diff options
author | Matt A. Tobin <mattatobin@localhost.localdomain> | 2018-02-02 04:16:08 -0500 |
---|---|---|
committer | Matt A. Tobin <mattatobin@localhost.localdomain> | 2018-02-02 04:16:08 -0500 |
commit | 5f8de423f190bbb79a62f804151bc24824fa32d8 (patch) | |
tree | 10027f336435511475e392454359edea8e25895d /dom/xul/templates | |
parent | 49ee0794b5d912db1f95dce6eb52d781dc210db5 (diff) | |
download | UXP-5f8de423f190bbb79a62f804151bc24824fa32d8.tar UXP-5f8de423f190bbb79a62f804151bc24824fa32d8.tar.gz UXP-5f8de423f190bbb79a62f804151bc24824fa32d8.tar.lz UXP-5f8de423f190bbb79a62f804151bc24824fa32d8.tar.xz UXP-5f8de423f190bbb79a62f804151bc24824fa32d8.zip |
Add m-esr52 at 52.6.0
Diffstat (limited to 'dom/xul/templates')
290 files changed, 37653 insertions, 0 deletions
diff --git a/dom/xul/templates/crashtests/257752-1-recursion.rdf b/dom/xul/templates/crashtests/257752-1-recursion.rdf new file mode 100644 index 000000000..a6eeb104b --- /dev/null +++ b/dom/xul/templates/crashtests/257752-1-recursion.rdf @@ -0,0 +1,13 @@ +<?xml version="1.0"?> +<rdf:RDF xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" + xmlns:m="urn:foo#"> + <rdf:Seq about="urn:x-rec:1"> + <rdf:li rdf:resource="urn:x-rec:2"/> + </rdf:Seq> + <rdf:Seq about="urn:x-rec:2"> + <rdf:li rdf:resource="urn:x-rec:3"/> + </rdf:Seq> + <rdf:Seq about="urn:x-rec:3"> + <rdf:li rdf:resource="urn:x-rec:1"/> + </rdf:Seq> +</rdf:RDF> diff --git a/dom/xul/templates/crashtests/257752-1-recursion.xul b/dom/xul/templates/crashtests/257752-1-recursion.xul new file mode 100644 index 000000000..fad5abfb6 --- /dev/null +++ b/dom/xul/templates/crashtests/257752-1-recursion.xul @@ -0,0 +1,28 @@ +<?xml version="1.0"?> + +<?xml-stylesheet href="chrome://global/skin/" type="text/css"?> + +<window id="child-iterate-recurse" + xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"> + +<vbox flex="1" style="overflow: auto;"> + +<vbox datasources="257752-1-recursion.rdf" ref="urn:x-rec:1"> + <template> + <rule> + <conditions> + <content uri="?uri"/> + <member container="?uri" child="?child"/> + </conditions> + <action> + <vbox uri="?child" style="border: 1px solid grey; margin: 1em;"> + <label value="hi"/> + </vbox> + </action> + </rule> + </template> +</vbox> + +</vbox> + +</window> diff --git a/dom/xul/templates/crashtests/329884-1.xul b/dom/xul/templates/crashtests/329884-1.xul new file mode 100644 index 000000000..8cc486e27 --- /dev/null +++ b/dom/xul/templates/crashtests/329884-1.xul @@ -0,0 +1,20 @@ +<?xml version="1.0"?> +<?xml-stylesheet href="chrome://global/skin" type="text/css"?> +<window xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"> + +<script> + +function rM(q1) { q1.parentNode.removeChild(q1); } + +function init2() +{ + rM(document.getElementById("t")); +} + +window.addEventListener("load", init2, false); + +</script> + +<foo id="t" datasources="1.rdf" /> + +</window> diff --git a/dom/xul/templates/crashtests/330012-1.rdf b/dom/xul/templates/crashtests/330012-1.rdf new file mode 100644 index 000000000..4bda7316a --- /dev/null +++ b/dom/xul/templates/crashtests/330012-1.rdf @@ -0,0 +1,13 @@ +<?xml version="1.0"?> +<rdf:RDF xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" + xmlns:s="urn:squarefree:a1:"> + <rdf:Description about="urn:root"> + <s:grapes> + <rdf:Bag> + <rdf:li> + <rdf:Description/> + </rdf:li> + </rdf:Bag> + </s:grapes> + </rdf:Description> +</rdf:RDF> diff --git a/dom/xul/templates/crashtests/330012-1.xul b/dom/xul/templates/crashtests/330012-1.xul new file mode 100644 index 000000000..ea797c2cf --- /dev/null +++ b/dom/xul/templates/crashtests/330012-1.xul @@ -0,0 +1,22 @@ +<?xml version="1.0"?> +<?xml-stylesheet href="chrome://global/skin" type="text/css"?> +<window xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"> + + <foo id="foo" datasources="330012-1.rdf" ref="urn:root"> + <template> + <rule> + <conditions> + <content uri="?root"/> + <triple subject="?root" + predicate="urn:squarefree:a1:grapes" + object="?lalala"/> + <member container="?grapes" child="?grape"/> + </conditions> + <action> + <bar uri="?grape"/> + </action> + </rule> + </template> + </foo> + +</window> diff --git a/dom/xul/templates/crashtests/404346-1.xul b/dom/xul/templates/crashtests/404346-1.xul new file mode 100644 index 000000000..e947960da --- /dev/null +++ b/dom/xul/templates/crashtests/404346-1.xul @@ -0,0 +1,7 @@ +<window xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"> +<box id="b"> +<box id="a" template="b"/> +<triple/> +</box> +<box datasources="" observes="a" ref="bbb"/> +</window>
\ No newline at end of file diff --git a/dom/xul/templates/crashtests/415019-1.xul b/dom/xul/templates/crashtests/415019-1.xul new file mode 100644 index 000000000..9fb9560f6 --- /dev/null +++ b/dom/xul/templates/crashtests/415019-1.xul @@ -0,0 +1,14 @@ +<window xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"> + <hbox datasources="nosuch.rdf" ref="urn:root"> + <template> + <rule> + <conditions> + <triple subject="?a"/> + </conditions> + <action> + <vbox uri="?b"/> + </action> + </rule> + </template> + </hbox> +</window> diff --git a/dom/xul/templates/crashtests/417840-1.xul b/dom/xul/templates/crashtests/417840-1.xul new file mode 100644 index 000000000..e41af81e9 --- /dev/null +++ b/dom/xul/templates/crashtests/417840-1.xul @@ -0,0 +1 @@ +<window xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul" onload="document.getElementById('foo').removeAttribute('ref');"><foo id="foo" datasources="nosuch.rdf" ref="urn:root"><template/></foo></window> diff --git a/dom/xul/templates/crashtests/424418-1.xul b/dom/xul/templates/crashtests/424418-1.xul new file mode 100644 index 000000000..d8565643a --- /dev/null +++ b/dom/xul/templates/crashtests/424418-1.xul @@ -0,0 +1 @@ +<window xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"><hbox datasources="u"/></window> diff --git a/dom/xul/templates/crashtests/crashtests.list b/dom/xul/templates/crashtests/crashtests.list new file mode 100644 index 000000000..ed99a3ae8 --- /dev/null +++ b/dom/xul/templates/crashtests/crashtests.list @@ -0,0 +1,7 @@ +load 257752-1-recursion.xul +load 329884-1.xul +skip-if(winWidget) load 330012-1.xul # bug 742455 +load 404346-1.xul +load 415019-1.xul +load 417840-1.xul +load 424418-1.xul diff --git a/dom/xul/templates/moz.build b/dom/xul/templates/moz.build new file mode 100644 index 000000000..3beb0b7e5 --- /dev/null +++ b/dom/xul/templates/moz.build @@ -0,0 +1,58 @@ +# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*- +# vim: set filetype=python: +# 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/. + +MOCHITEST_CHROME_MANIFESTS += ['tests/chrome/chrome.ini'] + +XPIDL_SOURCES += [ + 'nsIXULBuilderListener.idl', + 'nsIXULSortService.idl', + 'nsIXULTemplateBuilder.idl', + 'nsIXULTemplateQueryProcessor.idl', + 'nsIXULTemplateResult.idl', + 'nsIXULTemplateRuleFilter.idl', +] + +XPIDL_MODULE = 'xultmpl' + +UNIFIED_SOURCES += [ + 'nsContentSupportMap.cpp', + 'nsContentTestNode.cpp', + 'nsInstantiationNode.cpp', + 'nsRDFBinding.cpp', + 'nsRDFConInstanceTestNode.cpp', + 'nsRDFConMemberTestNode.cpp', + 'nsRDFPropertyTestNode.cpp', + 'nsRDFQuery.cpp', + 'nsResourceSet.cpp', + 'nsRuleNetwork.cpp', + 'nsTemplateMatch.cpp', + 'nsTemplateRule.cpp', + 'nsTreeRows.cpp', + 'nsXMLBinding.cpp', + 'nsXULContentBuilder.cpp', + 'nsXULContentUtils.cpp', + 'nsXULSortService.cpp', + 'nsXULTemplateBuilder.cpp', + 'nsXULTemplateQueryProcessorRDF.cpp', + 'nsXULTemplateQueryProcessorStorage.cpp', + 'nsXULTemplateQueryProcessorXML.cpp', + 'nsXULTemplateResultRDF.cpp', + 'nsXULTemplateResultSetRDF.cpp', + 'nsXULTemplateResultStorage.cpp', + 'nsXULTemplateResultXML.cpp', + 'nsXULTreeBuilder.cpp', +] + +LOCAL_INCLUDES += [ + '/dom/base', + '/dom/xul', + '/layout/xul/tree/', +] + +FINAL_LIBRARY = 'xul' + +if CONFIG['GNU_CXX']: + CXXFLAGS += ['-Wno-error=shadow'] diff --git a/dom/xul/templates/nsContentSupportMap.cpp b/dom/xul/templates/nsContentSupportMap.cpp new file mode 100644 index 000000000..ec10fde74 --- /dev/null +++ b/dom/xul/templates/nsContentSupportMap.cpp @@ -0,0 +1,18 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* 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 "nsContentSupportMap.h" +#include "nsXULElement.h" + +void +nsContentSupportMap::Remove(nsIContent* aElement) +{ + nsIContent* child = aElement; + do { + mMap.Remove(child); + child = child->GetNextNode(aElement); + } while(child); +} + diff --git a/dom/xul/templates/nsContentSupportMap.h b/dom/xul/templates/nsContentSupportMap.h new file mode 100644 index 000000000..aef7de83e --- /dev/null +++ b/dom/xul/templates/nsContentSupportMap.h @@ -0,0 +1,62 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* 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/. */ + +#ifndef nsContentSupportMap_h__ +#define nsContentSupportMap_h__ + +#include "PLDHashTable.h" +#include "nsTemplateMatch.h" + +/** + * The nsContentSupportMap maintains a mapping from a "resource element" + * in the content tree to the nsTemplateMatch that was used to instantiate it. This + * is necessary to allow the XUL content to be built lazily. Specifically, + * when building "resumes" on a partially-built content element, the builder + * will walk upwards in the content tree to find the first element with an + * 'id' attribute. This element is assumed to be the "resource element", + * and allows the content builder to access the nsTemplateMatch (variable assignments + * and rule information). + */ +class nsContentSupportMap { +public: + nsContentSupportMap() : mMap(PLDHashTable::StubOps(), sizeof(Entry)) { } + ~nsContentSupportMap() { } + + nsresult Put(nsIContent* aElement, nsTemplateMatch* aMatch) { + PLDHashEntryHdr* hdr = mMap.Add(aElement, mozilla::fallible); + if (!hdr) + return NS_ERROR_OUT_OF_MEMORY; + + Entry* entry = static_cast<Entry*>(hdr); + NS_ASSERTION(entry->mMatch == nullptr, "over-writing entry"); + entry->mContent = aElement; + entry->mMatch = aMatch; + return NS_OK; + } + + bool Get(nsIContent* aElement, nsTemplateMatch** aMatch) { + PLDHashEntryHdr* hdr = mMap.Search(aElement); + if (!hdr) + return false; + + Entry* entry = static_cast<Entry*>(hdr); + *aMatch = entry->mMatch; + return true; + } + + void Remove(nsIContent* aElement); + + void Clear() { mMap.Clear(); } + +protected: + PLDHashTable mMap; + + struct Entry : public PLDHashEntryHdr { + nsIContent* mContent; + nsTemplateMatch* mMatch; + }; +}; + +#endif diff --git a/dom/xul/templates/nsContentTestNode.cpp b/dom/xul/templates/nsContentTestNode.cpp new file mode 100644 index 000000000..53253a304 --- /dev/null +++ b/dom/xul/templates/nsContentTestNode.cpp @@ -0,0 +1,90 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* 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 "nsContentTestNode.h" +#include "nsIRDFResource.h" +#include "nsIAtom.h" +#include "nsIDOMElement.h" +#include "nsXULContentUtils.h" +#include "nsIXULTemplateResult.h" +#include "nsIXULTemplateBuilder.h" +#include "nsXULTemplateQueryProcessorRDF.h" + +#include "mozilla/Logging.h" + +using mozilla::LogLevel; + +extern mozilla::LazyLogModule gXULTemplateLog; + +nsContentTestNode::nsContentTestNode(nsXULTemplateQueryProcessorRDF* aProcessor, + nsIAtom* aRefVariable) + : TestNode(nullptr), + mProcessor(aProcessor), + mDocument(nullptr), + mRefVariable(aRefVariable), + mTag(nullptr) +{ + if (MOZ_LOG_TEST(gXULTemplateLog, LogLevel::Debug)) { + nsAutoString tag(NS_LITERAL_STRING("(none)")); + if (mTag) + mTag->ToString(tag); + + nsAutoString refvar(NS_LITERAL_STRING("(none)")); + if (aRefVariable) + aRefVariable->ToString(refvar); + + MOZ_LOG(gXULTemplateLog, LogLevel::Debug, + ("nsContentTestNode[%p]: ref-var=%s tag=%s", + this, NS_ConvertUTF16toUTF8(refvar).get(), + NS_ConvertUTF16toUTF8(tag).get())); + } +} + +nsresult +nsContentTestNode::FilterInstantiations(InstantiationSet& aInstantiations, + bool* aCantHandleYet) const + +{ + if (aCantHandleYet) + *aCantHandleYet = false; + return NS_OK; +} + +nsresult +nsContentTestNode::Constrain(InstantiationSet& aInstantiations) +{ + // contrain the matches to those that have matched in the template builder + + nsIXULTemplateBuilder* builder = mProcessor->GetBuilder(); + if (!builder) { + aInstantiations.Clear(); + return NS_OK; + } + + nsresult rv; + + InstantiationSet::Iterator last = aInstantiations.Last(); + for (InstantiationSet::Iterator inst = aInstantiations.First(); inst != last; ++inst) { + + nsCOMPtr<nsIRDFNode> refValue; + bool hasRefBinding = inst->mAssignments.GetAssignmentFor(mRefVariable, + getter_AddRefs(refValue)); + if (hasRefBinding) { + nsCOMPtr<nsIRDFResource> refResource = do_QueryInterface(refValue); + if (refResource) { + bool generated; + rv = builder->HasGeneratedContent(refResource, mTag, &generated); + if (NS_FAILED(rv)) return rv; + + if (generated) + continue; + } + } + + aInstantiations.Erase(inst--); + } + + return NS_OK; +} diff --git a/dom/xul/templates/nsContentTestNode.h b/dom/xul/templates/nsContentTestNode.h new file mode 100644 index 000000000..ebea5bcf6 --- /dev/null +++ b/dom/xul/templates/nsContentTestNode.h @@ -0,0 +1,48 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* 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/. */ + +#ifndef nsContentTestNode_h__ +#define nsContentTestNode_h__ + +#include "mozilla/Attributes.h" +#include "nscore.h" +#include "nsRuleNetwork.h" +#include "nsIAtom.h" +#include "nsIDOMDocument.h" + +class nsXULTemplateQueryProcessorRDF; + +/** + * The nsContentTestNode is always the top node in a query's rule network. It + * exists so that Constrain can filter out resources that aren't part of a + * result. + */ +class nsContentTestNode : public TestNode +{ +public: + nsContentTestNode(nsXULTemplateQueryProcessorRDF* aProcessor, + nsIAtom* aContentVariable); + + virtual nsresult FilterInstantiations(InstantiationSet& aInstantiations, + bool* aCantHandleYet) const override; + + nsresult + Constrain(InstantiationSet& aInstantiations) override; + + void SetTag(nsIAtom* aTag, nsIDOMDocument* aDocument) + { + mTag = aTag; + mDocument = aDocument; + } + +protected: + nsXULTemplateQueryProcessorRDF *mProcessor; + nsIDOMDocument* mDocument; + nsCOMPtr<nsIAtom> mRefVariable; + nsCOMPtr<nsIAtom> mTag; +}; + +#endif // nsContentTestNode_h__ + diff --git a/dom/xul/templates/nsIXULBuilderListener.idl b/dom/xul/templates/nsIXULBuilderListener.idl new file mode 100644 index 000000000..33ae2b3e8 --- /dev/null +++ b/dom/xul/templates/nsIXULBuilderListener.idl @@ -0,0 +1,28 @@ +/* -*- Mode: idl; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* 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 "nsISupports.idl" + +interface nsIXULTemplateBuilder; + +// An nsIXULBuilderListener object is a listener that will be notified +// when a template builder rebuilds its content. +[scriptable, uuid(ac46be8f-c863-4c23-84a2-d0fcc8dfa9f4)] +interface nsIXULBuilderListener: nsISupports { + + /** + * Called before a template builder rebuilds its content. + * @param aBuilder the template builder that rebuilds the content. + */ + void willRebuild(in nsIXULTemplateBuilder aBuilder); + + /** + * Called after a template builder has rebuilt its content. + * @param aBuilder the template builder that has rebuilt the content. + */ + void didRebuild(in nsIXULTemplateBuilder aBuilder); + +}; diff --git a/dom/xul/templates/nsIXULSortService.idl b/dom/xul/templates/nsIXULSortService.idl new file mode 100644 index 000000000..c8eb6a8bb --- /dev/null +++ b/dom/xul/templates/nsIXULSortService.idl @@ -0,0 +1,42 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* 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 "nsISupports.idl" + +interface nsIDOMNode; + +/** + * A service used to sort the contents of a XUL widget. + */ +[scriptable, uuid(F29270C8-3BE5-4046-9B57-945A84DFF132)] +interface nsIXULSortService : nsISupports +{ + const unsigned long SORT_COMPARECASE = 0x0001; + const unsigned long SORT_INTEGER = 0x0100; + + /** + * Sort the contents of the widget containing <code>aNode</code> + * using <code>aSortKey</code> as the comparison key, and + * <code>aSortDirection</code> as the direction. + * + * @param aNode A node in the XUL widget whose children are to be sorted. + * @param aSortKey The value to be used as the comparison key. + * @param aSortHints One or more hints as to how to sort: + * + * ascending: to sort the contents in ascending order + * descending: to sort the contents in descending order + * comparecase: perform case sensitive comparisons + * integer: treat values as integers, non-integers are compared as strings + * twostate: don't allow the natural (unordered state) + */ + void sort(in nsIDOMNode aNode, + in AString aSortKey, + in AString aSortHints); +}; + +%{C++ +nsresult +NS_NewXULSortService(nsIXULSortService **result); +%} diff --git a/dom/xul/templates/nsIXULTemplateBuilder.idl b/dom/xul/templates/nsIXULTemplateBuilder.idl new file mode 100644 index 000000000..755b57e57 --- /dev/null +++ b/dom/xul/templates/nsIXULTemplateBuilder.idl @@ -0,0 +1,409 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* 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 "domstubs.idl" + +interface nsIAtom; +interface nsIContent; +interface nsIXULBuilderListener; +interface nsIXULTemplateResult; +interface nsIXULTemplateRuleFilter; +interface nsIXULTemplateQueryProcessor; +interface nsIRDFResource; +interface nsIRDFCompositeDataSource; +interface nsIDOMDataTransfer; + +/** + * A template builder, given an input source of data, a template, and a + * reference point, generates a list of results from the input, and copies + * part of the template for each result. Templates may generate content + * recursively, using the same template, but with the previous iteration's + * results as the reference point. As an example, for an XML datasource the + * initial reference point would be a specific node in the DOM tree and a + * template might generate a list of all child nodes. For the next iteration, + * those children would be used to generate output for their child nodes and + * so forth. + * + * A template builder is attached to a single DOM node; this node is called + * the root node and is expected to contain a XUL template element as a direct + * child. Different template builders may be specialized in the manner in + * which they generate and display the resulting content from the template. + * + * The structure of a template is as follows: + * + * <rootnode datasources="" ref=""> + * <template> + * <queryset> + * <query> + * </query> + * <rule> + * <conditions>...</conditions> + * <bindings>...</bindings> + * <action>...</action> + * </rule> + * </queryset> + * </template> + * </rootnode> + * + * The datasources attribute on the root node is used to identify the source + * of data to be used. The ref attribute is used to specify the reference + * point for the query. Currently, the datasource will either be an + * nsIRDFDataSource or a DOM node. In the future, other datasource types may + * be used. + * + * The <queryset> element contains a single query and one or more <rule> + * elements. There may be more than one <queryset> if multiple queries are + * desired, and this element is optional if only one query is needed -- in + * that case the <query> and <rule>s are allowed to be children of the + * <template> node + * + * The contents of the query are processed by a separate component called a + * query processor. This query processor is expected to use this query to + * generate results when asked by the template builder. The template builder + * then generates output for each result based on the <rule> elements. + * + * This allows the query processor to be specific to a particular kind of + * input data or query syntax, while the template builder remains independent + * of the kind of data being used. Due to this, the query processor will be + * supplied with the datasource and query which the template builder handles + * in an opaque way, while the query processor handles these more + * specifically. + * + * Results implement the nsIXULTemplateResult interface and may be identified + * by an id which must be unique within a given set of query results. + * + * Each query may be accompanied by one or more <rule> elements. These rules + * are evaluated by the template builder for each result produced by the + * query. A rule consists of conditions that cause a rule to be either + * accepted or rejected. The condition syntax allows for common conditional + * handling; additional filtering may be applied by adding a custom filter + * to a rule with the builder's addRuleFilter method. + * + * If a result passes a rule's conditions, this is considered a match, and the + * content within the rule's <action> body is inserted as a sibling of the + * <template>, assuming the template builder creates real DOM content. Only + * one rule will match a result. For a tree builder, for example, the content + * within the action body is used to create the tree rows instead. A matching + * result must have its ruleMatched method called. When a result no longer + * matches, the result's hasBeenRemoved method must be called. + * + * Optionally, the rule may have a <bindings> section which may be used to + * define additional variables to be used within an action body. Each of these + * declared bindings must be supplied to the query processor via its + * addBinding method. The bindings are evaluated after a rule has matched. + * + * Templates may generate content recursively, using the previous iteration's + * results as reference point to invoke the same queries. Since the reference + * point is different, different output will typically be generated. + * + * The reference point nsIXULTemplateResult object for the first iteration is + * determined by calling the query processor's translateRef method using the + * value of the root node's ref attribute. This object may be retrieved later + * via the builder's rootResult property. + * + * For convenience, each reference point as well as all results implement the + * nsIXULTemplateResult interface, allowing the result objects from each + * iteration to be used directly as the reference points for the next + * iteration. + * + * When using multiple queries, each may generate results with the same id. + * More than one of these results may match one of the rules in their + * respective queries, however only the result for the earliest matching query + * in the template becomes the active match and generates output. The + * addResult, removeResult, replaceResult and resultBindingChanged methods may + * be called by the query processor to indicate that the set of valid results + * has changed, such that a different query may match. If a different match + * would become active, the content for the existing match is removed and the + * content for the new match is generated. A query processor is not required + * to provide any support for updating results after they have been generated. + * + * See http://wiki.mozilla.org/XUL:Templates_Plan for details about templates. + */ +[scriptable, uuid(A583B676-5B02-4F9C-A0C9-CB850CB99818)] +interface nsIXULTemplateBuilder : nsISupports +{ + /** + * The root node in the DOM to which this builder is attached. + */ + readonly attribute nsIDOMElement root; + + /** + * The opaque datasource object that is used for the template. This object + * is created by the getDataSource method of the query processor. May be + * null if the datasource has not been loaded yet. Set this attribute to + * use a different datasource and rebuild the template. + * + * For an RDF datasource, this will be the same as the database. For XML + * this will be the nsIDOMNode for the datasource document or node for + * an inline reference (such as #name). Other query processors may use + * other types for the datasource. + */ + attribute nsISupports datasource; + + /** + * The composite datasource that the template builder observes + * and uses to create content. This is used only for RDF queries and is + * maintained for backwards compatibility. It will be the same object as + * the datasource property. For non-RDF queries, it will always be null. + */ + readonly attribute nsIRDFCompositeDataSource database; + + /** + * The virtual result representing the starting reference point, + * determined by calling the query processor's translateRef method + * with the root node's ref attribute as an argument. + */ + readonly attribute nsIXULTemplateResult rootResult; + + /** + * The query processor used to generate results. + */ + [noscript] readonly attribute nsIXULTemplateQueryProcessor queryProcessor; + + /** + * Force the template builder to rebuild its content. All existing content + * will be removed first. The query processor's done() method will be + * invoked during cleanup, followed by its initializeForBuilding method + * when the content is to be regenerated. + * + */ + void rebuild(); + + /** + * Reload any of our RDF datasources that support nsIRDFRemoteDatasource. + * + * @note This is a temporary hack so that remote-XUL authors can + * reload remote datasources. When RDF becomes remote-scriptable, + * this will no longer be necessary. + */ + void refresh(); + + /** + * Inform the template builder that a new result is available. The builder + * will add this result to the set of results. The query node that the + * new result applies to must be specified using the aQueryNode parameter. + * + * The builder will apply the rules associated with the query to the new + * result, unless a result with the same id from an earlier query + * supersedes it, and the result's RuleMatched method will be called if it + * matches. + * + * @param aResult the result to add + * @param aQueryNode the query that the result applies to + * + * @throws NS_ERROR_NULL_POINTER if aResult or aQueryNode are null + */ + void addResult(in nsIXULTemplateResult aResult, in nsIDOMNode aQueryNode); + + /** + * Inform the template builder that a result no longer applies. The builder + * will call the remove content generated for the result, if any. If a different + * query would then match instead, it will become the active match. This + * method will have no effect if the result isn't known to the builder. + * + * @param aResult the result to remove + * + * @throws NS_ERROR_NULL_POINTER if aResult is null + */ + void removeResult(in nsIXULTemplateResult aResult); + + /** + * Inform the template builder that one result should be replaced with + * another. Both the old result (aOldResult) and the new result + * (aNewResult) must have the same id. The query node that the new result + * applies to must be specified using the aQueryNode parameter. + * + * This method is expected to have the same effect as calling both + * removeResult for the old result and addResult for the new result. + * + * @param aOldResult the old result + * @param aNewResult the new result + * @param aQueryNode the query that the new result applies to + * + * @throws NS_ERROR_NULL_POINTER if either argument is null, or + * NS_ERROR_INVALID_ARG if the ids don't match + */ + void replaceResult(in nsIXULTemplateResult aOldResult, + in nsIXULTemplateResult aNewResult, + in nsIDOMNode aQueryNode); + + /** + * Inform the template builder that one or more of the optional bindings + * for a result has changed. In this case, the rules are not reapplied as + * it is expected that the same rule will still apply. The builder will + * resynchronize any variables that are referenced in the action body. + * + * @param aResult the result to change + * + * @throws NS_ERROR_NULL_POINTER if aResult is null + */ + void resultBindingChanged(in nsIXULTemplateResult aResult); + + /** + * Return the result for a given id. Only one such result is returned and + * is always the result with that id associated with the active match. + * This method will return null is there is no result for the id. + * + * @param aId the id to return the result for + */ + nsIXULTemplateResult getResultForId(in AString aId); + + /** + * Retrieve the result corresponding to a generated element, or null is + * there isn't one. + * + * @param aContent element to result the result of + */ + nsIXULTemplateResult getResultForContent(in nsIDOMElement aElement); + + /** + * Returns true if the node has content generated for it. This method is + * intended to be called only by the RDF query processor. If aTag is set, + * the content must have a tag name that matches aTag. aTag may be ignored + * for builders that don't generate real DOM content. + * + * @param aNode node to check + * @param aTag tag that must match + */ + boolean hasGeneratedContent(in nsIRDFResource aNode, in nsIAtom aTag); + + /** + * Adds a rule filter for a given rule, which may be used for specialized + * rule filtering. Any existing filter on the rule is removed. The default + * conditions specified inside the <rule> tag are applied before the + * rule filter is applied, meaning that the filter may be used to further + * filter out results but not reaccept results that have already been + * rejected. + * + * @param aRule the rule to apply the filter to + * @param aFilter the filter to add + */ + void addRuleFilter(in nsIDOMNode aRule, in nsIXULTemplateRuleFilter aFilter); + + /** + * Called to initialize a XUL content builder on a particular root + * element. This element presumably has a ``datasources'' + * attribute, which the builder will parse to set up the template + * builder's datasources. + */ + [noscript] void init(in nsIContent aElement); + + /** + * Invoked lazily by a XUL element that needs its child content built. + * If aForceCreation is true, then the contents of an element will be + * generated even if it is closed. If false, the element will only + * generate its contents if it is open. This behaviour is used with menus. + */ + [noscript] void createContents(in nsIContent aElement, + in boolean aForceCreation); + + /** + * Add a listener to this template builder. The template builder + * holds a strong reference to the listener. + */ + void addListener(in nsIXULBuilderListener aListener); + + /** + * Remove a listener from this template builder. + */ + void removeListener(in nsIXULBuilderListener aListener); +}; + +/** + * nsIXULTreeBuilderObserver + * This interface allows clients of the XULTreeBuilder to define domain + * specific handling of specific nsITreeView methods that + * XULTreeBuilder does not implement. + */ +[scriptable, uuid(57CED9A7-EC0B-4A0E-8AEB-5DA32EBE951C)] +interface nsIXULTreeBuilderObserver : nsISupports +{ + const long DROP_BEFORE = -1; + const long DROP_ON = 0; + const long DROP_AFTER = 1; + /** + * Methods used by the drag feedback code to determine if a drag is allowable at + * the current location. To get the behavior where drops are only allowed on + * items, such as the mailNews folder pane, always return false whe + * the orientation is not DROP_ON. + */ + boolean canDrop(in long index, in long orientation, in nsIDOMDataTransfer dataTransfer); + + /** + * Called when the user drops something on this view. The |orientation| param + * specifies before/on/after the given |row|. + */ + void onDrop(in long row, in long orientation, in nsIDOMDataTransfer dataTransfer); + + /** + * Called when an item is opened or closed. + */ + void onToggleOpenState (in long index); + + /** + * Called when a header is clicked. + */ + void onCycleHeader(in wstring colID, in nsIDOMElement elt); + + /** + * Called when a cell in a non-selectable cycling column (e.g. + * unread/flag/etc.) is clicked. + */ + void onCycleCell(in long row, in wstring colID); + + /** + * Called when selection in the tree changes + */ + void onSelectionChanged(); + + /** + * A command API that can be used to invoke commands on the selection. + * The tree will automatically invoke this method when certain keys + * are pressed. For example, when the DEL key is pressed, performAction + * will be called with the "delete" string. + */ + void onPerformAction(in wstring action); + + /** + * A command API that can be used to invoke commands on a specific row. + */ + void onPerformActionOnRow(in wstring action, in long row); + + /** + * A command API that can be used to invoke commands on a specific cell. + */ + void onPerformActionOnCell(in wstring action, in long row, in wstring colID); +}; + +[scriptable, uuid(06b31b15-ebf5-4e74-a0e2-6bc0a18a3969)] +interface nsIXULTreeBuilder : nsISupports +{ + /** + * Retrieve the RDF resource associated with the specified row. + */ + nsIRDFResource getResourceAtIndex(in long aRowIndex); + + /** + * Retrieve the index associated with specified RDF resource. + */ + long getIndexOfResource(in nsIRDFResource resource); + + /** + * Add a Tree Builder Observer to handle Tree View + * methods that the base builder does not implement. + */ + void addObserver(in nsIXULTreeBuilderObserver aObserver); + + /** + * Remove an Tree Builder Observer. + */ + void removeObserver(in nsIXULTreeBuilderObserver aObserver); + + /** + * Sort the contents of the tree using the specified column. + */ + void sort(in nsIDOMElement aColumnElement); +}; + diff --git a/dom/xul/templates/nsIXULTemplateQueryProcessor.idl b/dom/xul/templates/nsIXULTemplateQueryProcessor.idl new file mode 100644 index 000000000..e064cf3b8 --- /dev/null +++ b/dom/xul/templates/nsIXULTemplateQueryProcessor.idl @@ -0,0 +1,276 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* 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 "domstubs.idl" + +interface nsIAtom; +interface nsIArray; +interface nsISimpleEnumerator; +interface nsIXULTemplateResult; +interface nsIXULTemplateRuleFilter; +interface nsIXULTemplateBuilder; + +/** + * A query processor takes a template query and generates results for it given + * a datasource and a reference point. There is a one-to-one relationship + * between a template builder and a query processor. The template builder + * creates the query processor, and there is no other means to retrieve it. + * + * A template query is the contents inside a <query> element within the + * template. The actual syntax is opaque to the template builder and defined + * by a query processor. The query is expected to consist of either text or + * DOM nodes that, when executed by a call to the generateResults method, will + * allow the generation of a list of results. + * + * The template builder will supply two variables, the reference variable and + * the member variable to further indicate what part of the datasource is to + * be examined in addition to the query itself. The reference is always + * a placeholder for the starting point and the member is always a placeholder + * for the end points (the results). + * + * The reference point is important when generating output recursively, as + * the query will be the same for each iteration, however, the reference point + * will differ. + * + * For instance, when examining an XML source, an XML query processor might + * begin at the node referred by the reference variable and end at a list of + * that node's children. + * + * Some queries may not need the reference variable if the syntax or the form + * of the data implies the value. For instance, a datasource that holds a + * table that can only produce one set of results. + * + * The reference variable may be specified in a template by setting the + * "container" attribute on the <template> element to the variable to use. The + * member variable may be specified in a similar way using the "member" + * attribute, or it may be specified in the first <action> body in the + * template as the value of a uri attribute on an element. A breadth-first + * search of the first action is performed to find this element. + * + * If unspecified, the default value of the reference variable is ?uri. + * + * For example, a query might have the following syntax: + * + * (?id, ?name, ?url) from Bookmarks where parentfolder = ?start + * + * This query might generate a result for each bookmark within a given folder. + * The variable ?start would be the reference variable, while the variable ?id + * would be the member variable, since it is the unique value that identifies + * a result. Each result will have the four variables referred to defined for + * it and the values may be retrieved using the result's getBindingFor and + * getBindingObjectFor methods. + * + * The template builder must call initializeForBuilding before the other + * methods, except for translateRef. The builder will then call compileQuery + * for each query in the template to compile the queries. When results need + * to be generated, the builder will call generateResults. The + * initializeForBuilding, compileQuery and addBinding methods may not be + * called after generateResults has been called until the builder indicates + * that the generated output is being removed by calling the done method. + * + * Currently, the datasource supplied to the methods will always be an + * nsIRDFDataSource or a DOM node, and will always be the same one in between + * calls to initializeForBuilding and done. + */ +[scriptable, uuid(C257573F-444F-468A-BA27-DE979DC55FE4)] +interface nsIXULTemplateQueryProcessor : nsISupports +{ + /** + * Retrieve the datasource to use for the query processor. The list of + * datasources in a template is specified using the datasources attribute as + * a space separated list of URIs. This list is processed by the builder and + * supplied to the query processor in the aDataSources array as a list of + * nsIURI objects or nsIDOMNode objects. This method may return an object + * corresponding to these URIs and the builder will supply this object to + * other query processor methods. For example, for an XML source, the + * datasource might be an nsIDOMNode. + * + * All of these URIs are checked by the builder so it is safe to use them, + * however note that a URI that redirects may still needs to be checked to + * ensure that the document containing aRootNode may access it. This is the + * responsibility of the query processor if it needs to load the content of + * the URI. + * + * If the query processor needs to load the datasource asynchronously, it + * may set the aShouldDelayBuilding returned parameter to true to delay + * building the template content, and call the builder's Rebuild method when + * the data is available. + * + * @param aDataSources the list of nsIURI objects and/or nsIDOMNode objects + * @param aRootNode the root node the builder is attached to + * @param aIsTrusted true if the template is in a trusted document + * @param aBuilder the template builder + * @param aShouldDelayBuilding [out] whether the builder should wait to + * build the content or not + * @returns a datasource object + */ + nsISupports getDatasource(in nsIArray aDataSources, + in nsIDOMNode aRootNode, + in boolean aIsTrusted, + in nsIXULTemplateBuilder aBuilder, + out boolean aShouldDelayBuilding); + + /** + * Initialize for query generation. This will be called before the rules are + * processed and whenever the template is rebuilt. This method must be + * called once before any of the other query processor methods except for + * translateRef. + * + * @param aDatasource datasource for the data + * @param aBuilder the template builder + * @param aRootNode the root node the builder is attached to + * + * @throws NS_ERROR_INVALID_ARG if the datasource is not supported or + * NS_ERROR_UNEXPECTED if generateResults has already been called. + */ + void initializeForBuilding(in nsISupports aDatasource, + in nsIXULTemplateBuilder aBuilder, + in nsIDOMNode aRootNode); + + /** + * Called when the template builder is being destroyed so that the query + * processor can clean up any state. The query processor should remove as + * much state as possible, such as results or references to the builder. + * This method will also be called when the template is going to be rebuilt. + */ + void done(); + + /** + * Compile a query from a node. The result of this function will later be + * passed to generateResults for result generation. If null is returned, + * the query will be ignored. + * + * The template builder will call this method once for each query within + * the template, before any results can be generated using generateResults, + * but after initializeForBuilding has been called. This method should not + * be called again for the same query unless the template is rebuilt. + * + * The reference variable may be used by the query processor as a + * placeholder for the reference point, or starting point in the query. + * + * The member variable is determined from the member attribute on the + * template, or from the uri in the first action's rule if that attribute is + * not present. A rule processor may use the member variable as a hint to + * indicate what variable is expected to contain the results. + * + * @param aBuilder the template builder + * @param aQuery <query> node to compile + * @param aRefVariable the reference variable + * @param aMemberVariable the member variable + * + * @returns a compiled query object + */ + nsISupports compileQuery(in nsIXULTemplateBuilder aBuilder, + in nsIDOMNode aQuery, + in nsIAtom aRefVariable, + in nsIAtom aMemberVariable); + + /** + * Generate the results of a query and return them in an enumerator. The + * enumerator must contain nsIXULTemplateResult objects. If there are no + * results, an empty enumerator must be returned. + * + * The datasource will be the same as the one passed to the earlier + * initializeForBuilding method. The context reference (aRef) is a reference + * point used when calculating results. + * + * The value of aQuery must be the result of a previous call to compileQuery + * from this query processor. This method may be called multiple times, + * typically with different values for aRef. + * + * @param aDatasource datasource for the data + * @param aRef context reference value used as a starting point + * @param aQuery the compiled query returned from query compilation + * + * @returns an enumerator of nsIXULTemplateResult objects as the results + * + * @throws NS_ERROR_INVALID_ARG if aQuery is invalid + */ + nsISimpleEnumerator generateResults(in nsISupports aDatasource, + in nsIXULTemplateResult aRef, + in nsISupports aQuery); + + /** + * Add a variable binding for a particular rule. A binding allows an + * additional variable to be set for a result, outside of those defined + * within the query. These bindings are always optional, in that they will + * never affect the results generated. + * + * This function will never be called after generateResults. Any bindings + * that were added should be applied to each result when the result's + * ruleMatched method is called, since the bindings are different for each + * rule. + * + * The reference aRef may be used to determine the reference when + * calculating the value for the binding, for example when a value should + * depend on the value of another variable. + * + * The syntax of the expression aExpr is defined by the query processor. If + * the syntax is invalid, the binding should be ignored. Only fatal errors + * should be thrown, or NS_ERROR_UNEXPECTED if generateResults has already + * been called. + * + * As an example, if the reference aRef is the variable '?count' which + * holds the value 5, and the expression aExpr is the string '+2', the value + * of the variable aVar would be 7, assuming the query processor considers + * the syntax '+2' to mean add two to the reference. + * + * @param aRuleNode rule to add the binding to + * @param aVar variable that will be bound + * @param aRef variable that holds reference value + * @param aExpr expression used to compute the value to assign + */ + void addBinding(in nsIDOMNode aRuleNode, + in nsIAtom aVar, + in nsIAtom aRef, + in AString aExpr); + + /** + * Translate a ref attribute string into a result. This is used as the + * reference point by the template builder when generating the first level + * of content. For recursive generation, the result from the parent + * generation phase will be used directly as the reference so a translation + * is not needed. This allows all levels to be generated using objects that + * all implement the nsIXULTemplateResult interface. + * + * This method may be called before initializeForBuilding, so the + * implementation may use the supplied datasource if it is needed to + * translate the reference. + * + * @param aDatasource datasource for the data + * @param aRefString the ref attribute string + * + * @return the translated ref + */ + nsIXULTemplateResult translateRef(in nsISupports aDatasource, + in AString aRefString); + + /** + * Compare two results to determine their order, used when sorting results. + * This method should return -1 when the left result is less than the right, + * 0 if both are equivalent, and 1 if the left is greater than the right. + * The comparison should only consider the values for the specified + * variable. + * + * If the comparison variable is null, the results may be + * sorted in a natural order, for instance, based on the order the data in + * stored in the datasource. + * + * The sort hints are the flags in nsIXULSortService. + * + * This method must only be called with results that were created by this + * query processor. + * + * @param aLeft the left result to compare + * @param aRight the right result to compare + * @param aVar variable to compare + * + * @param returns -1 if less, 0 if equal, or 1 if greater + */ + int32_t compareResults(in nsIXULTemplateResult aLeft, + in nsIXULTemplateResult aRight, + in nsIAtom aVar, + in unsigned long aSortHints); +}; diff --git a/dom/xul/templates/nsIXULTemplateResult.idl b/dom/xul/templates/nsIXULTemplateResult.idl new file mode 100644 index 000000000..6a8ac2439 --- /dev/null +++ b/dom/xul/templates/nsIXULTemplateResult.idl @@ -0,0 +1,116 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* 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 "nsISupports.idl" + +interface nsIAtom; +interface nsIDOMNode; +interface nsIRDFResource; + +/** + * A single result generated from a template query. Each result is identified + * by an id, which must be unique within the set of results produced from a + * query. The result may optionally be identified by an RDF resource. + * + * Generally, the result and its id will be able to uniquely identify a node + * in the source data, such as an RDF or XML node. In other contexts, such as + * a database query, a result would represent a particular record. + * + * A result is expected to only be created by a query processor. + * + * Each result also contains a set of variable bindings. The value for a + * particular variable may be retrieved using the getBindingFor and + * getBindingObjectFor methods. + */ +[scriptable, uuid(ebea0230-36fa-41b7-8e31-760806057965)] +interface nsIXULTemplateResult : nsISupports +{ + /** + * True if the result represents a container. + */ + readonly attribute boolean isContainer; + + /** + * True if the result represents an empty container. + */ + readonly attribute boolean isEmpty; + + /** + * True if the template builder may use this result as the reference point + * for additional recursive processing of the template. The template builder + * will reprocess the template using this result as the reference point and + * generate output content that is expected to be inserted as children of the + * output generated for this result. If false, child content is not + * processed. This property identifies only the default handling and may be + * overriden by syntax used in the template. + */ + readonly attribute boolean mayProcessChildren; + + /** + * ID of the result. The DOM element created for this result, if any, will + * have its id attribute set to this value. The id must be unique for a + * query. + */ + readonly attribute AString id; + + /** + * Resource for the result, which may be null. If set, the resource uri + * must be the same as the ID property. + */ + readonly attribute nsIRDFResource resource; + + /** + * The type of the object. The predefined value 'separator' may be used + * for separators. Other values may be used for application specific + * purposes. + */ + readonly attribute AString type; + + /** + * Get the string representation of the value of a variable for this + * result. This string will be used in the action body from a template as + * the replacement text. For instance, if the text ?name appears in an + * attribute within the action body, it will be replaced with the result + * of this method. The question mark is considered part of the variable + * name, thus aVar should be ?name and not simply name. + * + * @param aVar the variable to look up + * + * @return the value for the variable or a null string if it has no value + */ + AString getBindingFor(in nsIAtom aVar); + + /** + * Get an object value for a variable such as ?name for this result. + * + * This method may return null for a variable, even if getBindingFor returns + * a non-null value for the same variable. This method is provided as a + * convenience when sorting results. + * + * @param aVar the variable to look up + * + * @return the value for the variable or null if it has no value + */ + nsISupports getBindingObjectFor(in nsIAtom aVar); + + /** + * Indicate that a particular rule of a query has matched and that output + * will be generated for it. Both the query as compiled by the query + * processor's compileQuery method and the XUL <rule> element are supplied. + * The query must always be one that was compiled by the query processor + * that created this result. The <rule> element must always be a child of + * the <query> element that was used to compile the query. + * + * @param aQuery the query that matched + * @param aRuleNode the rule node that matched + */ + void ruleMatched(in nsISupports aQuery, in nsIDOMNode aRuleNode); + + /** + * Indicate that the output for a result has beeen removed and that the + * result is no longer being used by the builder. + */ + void hasBeenRemoved(); +}; diff --git a/dom/xul/templates/nsIXULTemplateRuleFilter.idl b/dom/xul/templates/nsIXULTemplateRuleFilter.idl new file mode 100644 index 000000000..59c88e072 --- /dev/null +++ b/dom/xul/templates/nsIXULTemplateRuleFilter.idl @@ -0,0 +1,36 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* 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 "domstubs.idl" + +interface nsISupports; +interface nsIXULTemplateResult; + +/** + * A rule filter may be used to add additional filtering of results to a rule. + * The filter is used to further reject results from matching the template's + * rules, beyond what the template syntax can do itself, thus allowing for + * more complex result filtering. The rule filter is applied after the rule + * syntax within the template. + * + * Only one filter may apply to each rule within the template and may be + * assigned using the template builder's addRuleFilter method. + */ +[scriptable, uuid(819cd1ed-8010-42e1-a8b9-778b726a1ff3)] +interface nsIXULTemplateRuleFilter : nsISupports +{ + /** + * Evaluate a result and return true if the result is accepted by this + * filter, or false if it is rejected. Accepted results will have output + * generated for them for the rule. Rejected results will not, but they + * may still match another rule. + * + * @param aRef the result to examine + * @param aRule the rule node + * + * @return true if the rule matches + */ + boolean match(in nsIXULTemplateResult aRef, in nsIDOMNode aRule); +}; diff --git a/dom/xul/templates/nsInstantiationNode.cpp b/dom/xul/templates/nsInstantiationNode.cpp new file mode 100644 index 000000000..9079d4189 --- /dev/null +++ b/dom/xul/templates/nsInstantiationNode.cpp @@ -0,0 +1,83 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* 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 "nsInstantiationNode.h" +#include "nsTemplateRule.h" +#include "nsXULTemplateQueryProcessorRDF.h" + +#include "mozilla/Logging.h" +extern mozilla::LazyLogModule gXULTemplateLog; + +nsInstantiationNode::nsInstantiationNode(nsXULTemplateQueryProcessorRDF* aProcessor, + nsRDFQuery* aQuery) + : mProcessor(aProcessor), + mQuery(aQuery) +{ + MOZ_LOG(gXULTemplateLog, LogLevel::Debug, + ("nsInstantiationNode[%p] query=%p", this, aQuery)); + + MOZ_COUNT_CTOR(nsInstantiationNode); +} + + +nsInstantiationNode::~nsInstantiationNode() +{ + MOZ_COUNT_DTOR(nsInstantiationNode); +} + +nsresult +nsInstantiationNode::Propagate(InstantiationSet& aInstantiations, + bool aIsUpdate, bool& aTakenInstantiations) +{ + // In update mode, iterate through the results and call the template + // builder to update them. In non-update mode, cache them in the processor + // to be used during processing. The results are cached in the processor + // so that the simple rules are only computed once. In this situation, all + // data for all queries are calculated at once. + nsresult rv = NS_OK; + + aTakenInstantiations = false; + + if (aIsUpdate) { + // Iterate through newly added keys to determine which rules fired. + // + // XXXwaterson Unfortunately, this could also lead to retractions; + // e.g., (container ?a ^empty false) could become "unmatched". How + // to track those? + nsCOMPtr<nsIDOMNode> querynode; + mQuery->GetQueryNode(getter_AddRefs(querynode)); + + InstantiationSet::ConstIterator last = aInstantiations.Last(); + for (InstantiationSet::ConstIterator inst = aInstantiations.First(); inst != last; ++inst) { + nsAssignmentSet assignments = inst->mAssignments; + + nsCOMPtr<nsIRDFNode> node; + assignments.GetAssignmentFor(mQuery->mMemberVariable, + getter_AddRefs(node)); + if (node) { + nsCOMPtr<nsIRDFResource> resource = do_QueryInterface(node); + if (resource) { + RefPtr<nsXULTemplateResultRDF> nextresult = + new nsXULTemplateResultRDF(mQuery, *inst, resource); + if (! nextresult) + return NS_ERROR_OUT_OF_MEMORY; + + rv = mProcessor->AddMemoryElements(*inst, nextresult); + if (NS_FAILED(rv)) + return rv; + + mProcessor->GetBuilder()->AddResult(nextresult, querynode); + } + } + } + } + else { + nsresult rv = mQuery->SetCachedResults(mProcessor, aInstantiations); + if (NS_SUCCEEDED(rv)) + aTakenInstantiations = true; + } + + return rv; +} diff --git a/dom/xul/templates/nsInstantiationNode.h b/dom/xul/templates/nsInstantiationNode.h new file mode 100644 index 000000000..5b9c7b9f1 --- /dev/null +++ b/dom/xul/templates/nsInstantiationNode.h @@ -0,0 +1,37 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* 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/. */ + +#ifndef nsInstantiationNode_h__ +#define nsInstantiationNode_h__ + +#include "mozilla/Attributes.h" +#include "nsRuleNetwork.h" +#include "nsRDFQuery.h" + +class nsXULTemplateQueryProcessorRDF; + +/** + * A leaf-level node in the rule network. If any instantiations + * propagate to this node, then we know we've matched a rule. + */ +class nsInstantiationNode : public ReteNode +{ +public: + nsInstantiationNode(nsXULTemplateQueryProcessorRDF* aProcessor, + nsRDFQuery* aRule); + + ~nsInstantiationNode(); + + // "downward" propagations + virtual nsresult Propagate(InstantiationSet& aInstantiations, + bool aIsUpdate, bool& aMatched) override; + +protected: + + nsXULTemplateQueryProcessorRDF* mProcessor; + nsRDFQuery* mQuery; +}; + +#endif // nsInstantiationNode_h__ diff --git a/dom/xul/templates/nsRDFBinding.cpp b/dom/xul/templates/nsRDFBinding.cpp new file mode 100644 index 000000000..120adfa79 --- /dev/null +++ b/dom/xul/templates/nsRDFBinding.cpp @@ -0,0 +1,265 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* 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 "nsXULTemplateQueryProcessorRDF.h" +#include "nsXULTemplateResultRDF.h" +#include "nsRDFBinding.h" + +#ifdef DEBUG +#include "nsXULContentUtils.h" +#endif + +RDFBindingSet::~RDFBindingSet() +{ + while (mFirst) { + RDFBinding* doomed = mFirst; + mFirst = mFirst->mNext; + delete doomed; + } + + MOZ_COUNT_DTOR(RDFBindingSet); +} + +nsresult +RDFBindingSet::AddBinding(nsIAtom* aVar, nsIAtom* aRef, nsIRDFResource* aPredicate) +{ + RDFBinding* newbinding = new RDFBinding(aRef, aPredicate, aVar); + if (mFirst) { + RDFBinding* binding = mFirst; + + while (binding) { + // the binding is dependant on the calculation of a previous binding + if (binding->mSubjectVariable == aVar) + newbinding->mHasDependency = true; + + // if the target variable is already used in a binding, ignore it + // since it won't be useful for anything + if (binding->mTargetVariable == aVar) { + delete newbinding; + return NS_OK; + } + + // add the binding at the end of the list + if (! binding->mNext) { + binding->mNext = newbinding; + break; + } + + binding = binding->mNext; + } + } + else { + mFirst = newbinding; + } + + mCount++; + + return NS_OK; +} + +bool +RDFBindingSet::SyncAssignments(nsIRDFResource* aSubject, + nsIRDFResource* aPredicate, + nsIRDFNode* aTarget, + nsIAtom* aMemberVariable, + nsXULTemplateResultRDF* aResult, + nsBindingValues& aBindingValues) +{ + NS_ASSERTION(aBindingValues.GetBindingSet() == this, + "nsBindingValues not for this RDFBindingSet"); + NS_PRECONDITION(aResult, "Must have result"); + + bool needSync = false; + nsCOMPtr<nsIRDFNode>* valuesArray = aBindingValues.ValuesArray(); + if (!valuesArray) + return false; + + RDFBinding* binding = mFirst; + int32_t count = 0; + + // QI for proper comparisons just to be safe + nsCOMPtr<nsIRDFNode> subjectnode = do_QueryInterface(aSubject); + + // iterate through the bindings looking for ones that would match the RDF + // nodes that were involved in a change + nsCOMPtr<nsIRDFNode> value; + while (binding) { + if (aPredicate == binding->mPredicate) { + // if the source of the binding is the member variable, optimize + if (binding->mSubjectVariable == aMemberVariable) { + valuesArray[count] = aTarget; + needSync = true; + } + else { + aResult->GetAssignment(binding->mSubjectVariable, getter_AddRefs(value)); + if (value == subjectnode) { + valuesArray[count] = aTarget; + needSync = true; + } + } + } + + binding = binding->mNext; + count++; + } + + return needSync; +} + +void +RDFBindingSet::AddDependencies(nsIRDFResource* aSubject, + nsXULTemplateResultRDF* aResult) +{ + NS_PRECONDITION(aResult, "Must have result"); + + // iterate through the bindings and add binding dependencies to the + // processor + + nsXULTemplateQueryProcessorRDF* processor = aResult->GetProcessor(); + if (! processor) + return; + + nsCOMPtr<nsIRDFNode> value; + + RDFBinding* binding = mFirst; + while (binding) { + aResult->GetAssignment(binding->mSubjectVariable, getter_AddRefs(value)); + + nsCOMPtr<nsIRDFResource> valueres = do_QueryInterface(value); + if (valueres) + processor->AddBindingDependency(aResult, valueres); + + binding = binding->mNext; + } +} + +void +RDFBindingSet::RemoveDependencies(nsIRDFResource* aSubject, + nsXULTemplateResultRDF* aResult) +{ + NS_PRECONDITION(aResult, "Must have result"); + + // iterate through the bindings and remove binding dependencies from the + // processor + + nsXULTemplateQueryProcessorRDF* processor = aResult->GetProcessor(); + if (! processor) + return; + + nsCOMPtr<nsIRDFNode> value; + + RDFBinding* binding = mFirst; + while (binding) { + aResult->GetAssignment(binding->mSubjectVariable, getter_AddRefs(value)); + + nsCOMPtr<nsIRDFResource> valueres = do_QueryInterface(value); + if (valueres) + processor->RemoveBindingDependency(aResult, valueres); + + binding = binding->mNext; + } +} + +int32_t +RDFBindingSet::LookupTargetIndex(nsIAtom* aTargetVariable, RDFBinding** aBinding) +{ + int32_t idx = 0; + RDFBinding* binding = mFirst; + + while (binding) { + if (binding->mTargetVariable == aTargetVariable) { + *aBinding = binding; + return idx; + } + idx++; + binding = binding->mNext; + } + + return -1; +} + +nsBindingValues::~nsBindingValues() +{ + ClearBindingSet(); + MOZ_COUNT_DTOR(nsBindingValues); +} + +void +nsBindingValues::ClearBindingSet() +{ + if (mBindings && mValues) { + delete [] mValues; + mValues = nullptr; + } + + mBindings = nullptr; +} + +nsresult +nsBindingValues::SetBindingSet(RDFBindingSet* aBindings) +{ + ClearBindingSet(); + + int32_t count = aBindings->Count(); + if (count) { + mValues = new nsCOMPtr<nsIRDFNode>[count]; + mBindings = aBindings; + } + else { + mValues = nullptr; + } + + return NS_OK; +} + +void +nsBindingValues::GetAssignmentFor(nsXULTemplateResultRDF* aResult, + nsIAtom* aVar, + nsIRDFNode** aValue) +{ + *aValue = nullptr; + + // assignments are calculated lazily when asked for. The only issue is + // when a binding has no value in the RDF graph, it will be checked again + // every time. + + if (mBindings && mValues) { + RDFBinding* binding; + int32_t idx = mBindings->LookupTargetIndex(aVar, &binding); + if (idx >= 0) { + *aValue = mValues[idx]; + if (*aValue) { + NS_ADDREF(*aValue); + } + else { + nsXULTemplateQueryProcessorRDF* processor = aResult->GetProcessor(); + if (! processor) + return; + + nsIRDFDataSource* ds = processor->GetDataSource(); + if (! ds) + return; + + nsCOMPtr<nsIRDFNode> subjectValue; + aResult->GetAssignment(binding->mSubjectVariable, + getter_AddRefs(subjectValue)); + if (subjectValue) { + nsCOMPtr<nsIRDFResource> subject = do_QueryInterface(subjectValue); + ds->GetTarget(subject, binding->mPredicate, true, aValue); + if (*aValue) + mValues[idx] = *aValue; + } + } + } + } +} + +void +nsBindingValues::RemoveDependencies(nsIRDFResource* aSubject, + nsXULTemplateResultRDF* aResult) +{ + if (mBindings) + mBindings->RemoveDependencies(aSubject, aResult); +} diff --git a/dom/xul/templates/nsRDFBinding.h b/dom/xul/templates/nsRDFBinding.h new file mode 100644 index 000000000..92c8b16ca --- /dev/null +++ b/dom/xul/templates/nsRDFBinding.h @@ -0,0 +1,216 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* 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/. */ + +#ifndef nsRDFBinding_h__ +#define nsRDFBinding_h__ + +#include "nsIAtom.h" +#include "nsIRDFResource.h" +#include "nsISupportsImpl.h" + +class nsXULTemplateResultRDF; +class nsBindingValues; + +/* + * Classes related to storing bindings for RDF handling. + */ + +/* + * a <binding> descriptors + */ +class RDFBinding { + +public: + + nsCOMPtr<nsIAtom> mSubjectVariable; + nsCOMPtr<nsIRDFResource> mPredicate; + nsCOMPtr<nsIAtom> mTargetVariable; + + // indicates whether a binding is dependant on the result from a + // previous binding + bool mHasDependency; + + RDFBinding* mNext; + +private: + + friend class RDFBindingSet; + + RDFBinding(nsIAtom* aSubjectVariable, + nsIRDFResource* aPredicate, + nsIAtom* aTargetVariable) + : mSubjectVariable(aSubjectVariable), + mPredicate(aPredicate), + mTargetVariable(aTargetVariable), + mHasDependency(false), + mNext(nullptr) + { + MOZ_COUNT_CTOR(RDFBinding); + } + + ~RDFBinding() + { + MOZ_COUNT_DTOR(RDFBinding); + } +}; + +/* + * a collection of <binding> descriptors. This object is refcounted by + * nsBindingValues objects and the query processor. + */ +class RDFBindingSet final +{ +private: + // Private destructor, to discourage deletion outside of Release(): + ~RDFBindingSet(); + + // the number of bindings + int32_t mCount; + + // pointer to the first binding in a linked list + RDFBinding* mFirst; + +public: + + RDFBindingSet() + : mCount(0), + mFirst(nullptr) + { + MOZ_COUNT_CTOR(RDFBindingSet); + } + + NS_INLINE_DECL_REFCOUNTING(RDFBindingSet) + + int32_t Count() const { return mCount; } + + /* + * Add a binding (aRef -> aPredicate -> aVar) to the set + */ + nsresult + AddBinding(nsIAtom* aVar, nsIAtom* aRef, nsIRDFResource* aPredicate); + + /* + * Return true if the binding set contains a binding which would cause + * the result to need resynchronizing for an RDF triple. The member + * variable may be supplied as an optimization since bindings most + * commonly use the member variable as the subject. If aMemberVariable + * is set, aSubject must be the value of the member variable for the + * result. The supplied binding values aBindingValues must be values + * using this binding set (that is aBindingValues->GetBindingSet() == this) + * + * @param aSubject subject of the RDF triple + * @param aPredicate predicate of the RDF triple + * @param aTarget target of the RDF triple + * @param aMemberVariable member variable for the query for the binding + * @param aResult result to synchronize + * @param aBindingValues the values for the bindings for the result + */ + bool + SyncAssignments(nsIRDFResource* aSubject, + nsIRDFResource* aPredicate, + nsIRDFNode* aTarget, + nsIAtom* aMemberVariable, + nsXULTemplateResultRDF* aResult, + nsBindingValues& aBindingValues); + + /* + * The query processor maintains a map of subjects to an array of results. + * This is used such that when a new assertion is added to the RDF graph, + * the results associated with the subject of that triple may be checked + * to see if their bindings have changed. The AddDependencies method adds + * these subject dependencies to the map. + */ + void + AddDependencies(nsIRDFResource* aSubject, + nsXULTemplateResultRDF* aResult); + + /* + * Remove the results from the dependencies map when results are deleted. + */ + void + RemoveDependencies(nsIRDFResource* aSubject, + nsXULTemplateResultRDF* aResult); + + /* + * The nsBindingValues classes stores an array of values, one for each + * target symbol that could be set by the bindings in the set. + * LookupTargetIndex determines the index into the array for a given + * target symbol. + */ + int32_t + LookupTargetIndex(nsIAtom* aTargetVariable, RDFBinding** aBinding); +}; + +/* + * A set of values of bindings. This object is used once per result. + * This stores a reference to the binding set and an array of node values. + * Since the binding set is used once per query and the values are + * used once per result, we reduce size by only storing the value array's + * length in the binding set. This is possible since the array is always + * a fixed length for a particular binding set. + * + * XXX ndeakin We may want to revisit this later since it makes the code + * more complicated. + */ +class nsBindingValues +{ +protected: + + // the binding set + RefPtr<RDFBindingSet> mBindings; + + /* + * A set of values for variable bindings. To look up a binding value, + * scan through the binding set in mBindings for the right target atom. + * Its index will correspond to the index in this array. The size of this + * array is determined by the RDFBindingSet's Count(). + */ + nsCOMPtr<nsIRDFNode>* mValues; + +public: + + nsBindingValues() + : mBindings(nullptr), + mValues(nullptr) + { + MOZ_COUNT_CTOR(nsBindingValues); + } + + ~nsBindingValues(); + + + /** + * Clear the binding set, to be called when the nsBindingValues is deleted + * or a new binding set is being set. + */ + void ClearBindingSet(); + + RDFBindingSet* GetBindingSet() { return mBindings; } + + /** + * Set the binding set to use. This needs to be called once a rule matches + * since it is then known which bindings will apply. + */ + nsresult SetBindingSet(RDFBindingSet* aBindings); + + nsCOMPtr<nsIRDFNode>* ValuesArray() { return mValues; } + + /* + * Retrieve the assignment for a particular variable + */ + void + GetAssignmentFor(nsXULTemplateResultRDF* aResult, + nsIAtom* aVar, + nsIRDFNode** aValue); + + /* + * Remove depenedencies the bindings have on particular resources + */ + void + RemoveDependencies(nsIRDFResource* aSubject, + nsXULTemplateResultRDF* aResult); +}; + +#endif // nsRDFBinding_h__ diff --git a/dom/xul/templates/nsRDFConInstanceTestNode.cpp b/dom/xul/templates/nsRDFConInstanceTestNode.cpp new file mode 100644 index 000000000..a96809743 --- /dev/null +++ b/dom/xul/templates/nsRDFConInstanceTestNode.cpp @@ -0,0 +1,281 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* 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 "nsIComponentManager.h" +#include "nsIRDFContainer.h" +#include "nsIRDFContainerUtils.h" +#include "nsIServiceManager.h" +#include "nsRDFCID.h" +#include "nsRDFConInstanceTestNode.h" +#include "nsResourceSet.h" + +#include "mozilla/Logging.h" +#include "nsXULContentUtils.h" + +using mozilla::LogLevel; + +extern mozilla::LazyLogModule gXULTemplateLog; + +static const char* +TestToString(nsRDFConInstanceTestNode::Test aTest) { + switch (aTest) { + case nsRDFConInstanceTestNode::eFalse: return "false"; + case nsRDFConInstanceTestNode::eTrue: return "true"; + case nsRDFConInstanceTestNode::eDontCare: return "dontcare"; + } + return "?"; +} + +nsRDFConInstanceTestNode::nsRDFConInstanceTestNode(TestNode* aParent, + nsXULTemplateQueryProcessorRDF* aProcessor, + nsIAtom* aContainerVariable, + Test aContainer, + Test aEmpty) + : nsRDFTestNode(aParent), + mProcessor(aProcessor), + mContainerVariable(aContainerVariable), + mContainer(aContainer), + mEmpty(aEmpty) +{ + if (MOZ_LOG_TEST(gXULTemplateLog, LogLevel::Debug)) { + nsAutoCString props; + + nsResourceSet& containmentProps = aProcessor->ContainmentProperties(); + nsResourceSet::ConstIterator last = containmentProps.Last(); + nsResourceSet::ConstIterator first = containmentProps.First(); + nsResourceSet::ConstIterator iter; + + for (iter = first; iter != last; ++iter) { + if (iter != first) + props += " "; + + const char* str; + iter->GetValueConst(&str); + + props += str; + } + + nsAutoString cvar(NS_LITERAL_STRING("(none)")); + if (mContainerVariable) + mContainerVariable->ToString(cvar); + + MOZ_LOG(gXULTemplateLog, LogLevel::Debug, + ("nsRDFConInstanceTestNode[%p]: parent=%p member-props=(%s) container-var=%s container=%s empty=%s", + this, + aParent, + props.get(), + NS_ConvertUTF16toUTF8(cvar).get(), + TestToString(aContainer), + TestToString(aEmpty))); + } +} + +nsresult +nsRDFConInstanceTestNode::FilterInstantiations(InstantiationSet& aInstantiations, + bool* aCantHandleYet) const +{ + nsresult rv; + + if (aCantHandleYet) + *aCantHandleYet = false; + + nsCOMPtr<nsIRDFContainerUtils> rdfc + = do_GetService("@mozilla.org/rdf/container-utils;1"); + + if (! rdfc) + return NS_ERROR_FAILURE; + + nsIRDFDataSource* ds = mProcessor->GetDataSource(); + + InstantiationSet::Iterator last = aInstantiations.Last(); + for (InstantiationSet::Iterator inst = aInstantiations.First(); inst != last; ++inst) { + nsCOMPtr<nsIRDFNode> value; + if (! inst->mAssignments.GetAssignmentFor(mContainerVariable, getter_AddRefs(value))) { + NS_ERROR("can't do unbounded container testing"); + return NS_ERROR_UNEXPECTED; + } + + nsCOMPtr<nsIRDFResource> valueres = do_QueryInterface(value); + if (! valueres) { + aInstantiations.Erase(inst--); + continue; + } + + if (MOZ_LOG_TEST(gXULTemplateLog, LogLevel::Debug)) { + const char* container = "(unbound)"; + valueres->GetValueConst(&container); + + MOZ_LOG(gXULTemplateLog, LogLevel::Debug, + ("nsRDFConInstanceTestNode[%p]::FilterInstantiations() container=[%s]", + this, container)); + } + + nsCOMPtr<nsIRDFContainer> rdfcontainer; + + bool isRDFContainer; + rv = rdfc->IsContainer(ds, valueres, &isRDFContainer); + if (NS_FAILED(rv)) return rv; + + if (mEmpty != eDontCare || mContainer != eDontCare) { + Test empty = eDontCare; + Test container = eDontCare; + + if (isRDFContainer) { + // It's an RDF container. Use the container utilities + // to deduce what's in it. + container = eTrue; + + // XXX should cache the factory + rdfcontainer = do_CreateInstance("@mozilla.org/rdf/container;1", &rv); + if (NS_FAILED(rv)) return rv; + + rv = rdfcontainer->Init(ds, valueres); + if (NS_FAILED(rv)) return rv; + + int32_t count; + rv = rdfcontainer->GetCount(&count); + if (NS_FAILED(rv)) return rv; + + empty = (count == 0) ? eTrue : eFalse; + } else { + empty = eTrue; + container = eFalse; + + // First do the simple check of finding some outward + // arcs; there should be only a few containment arcs, so this can + // save us time from dealing with an iterator later on + nsResourceSet& containmentProps = mProcessor->ContainmentProperties(); + for (nsResourceSet::ConstIterator property = containmentProps.First(); + property != containmentProps.Last(); + ++property) { + nsCOMPtr<nsIRDFNode> target; + rv = ds->GetTarget(valueres, *property, true, getter_AddRefs(target)); + if (NS_FAILED(rv)) return rv; + + if (target != nullptr) { + // bingo. we found one. + empty = eFalse; + container = eTrue; + break; + } + } + + // if we still don't think its a container, but we + // want to know for sure whether it is or not, we need + // to check ArcLabelsOut for potential container arcs. + if (container == eFalse && mContainer != eDontCare) { + nsCOMPtr<nsISimpleEnumerator> arcsout; + rv = ds->ArcLabelsOut(valueres, getter_AddRefs(arcsout)); + if (NS_FAILED(rv)) return rv; + + while (1) { + bool hasmore; + rv = arcsout->HasMoreElements(&hasmore); + if (NS_FAILED(rv)) return rv; + + if (! hasmore) + break; + + nsCOMPtr<nsISupports> isupports; + rv = arcsout->GetNext(getter_AddRefs(isupports)); + if (NS_FAILED(rv)) return rv; + + nsCOMPtr<nsIRDFResource> property = do_QueryInterface(isupports); + NS_ASSERTION(property != nullptr, "not a property"); + if (! property) + return NS_ERROR_UNEXPECTED; + + if (mProcessor->ContainmentProperties().Contains(property)) { + container = eTrue; + break; + } + } + } + } + + MOZ_LOG(gXULTemplateLog, LogLevel::Debug, + (" empty => %s", + (empty == mEmpty) ? "consistent" : "inconsistent")); + + MOZ_LOG(gXULTemplateLog, LogLevel::Debug, + (" container => %s", + (container == mContainer) ? "consistent" : "inconsistent")); + + if (((mEmpty == empty) && (mContainer == container)) || + ((mEmpty == eDontCare) && (mContainer == container)) || + ((mContainer == eDontCare) && (mEmpty == empty))) + { + Element* element = + new nsRDFConInstanceTestNode::Element(valueres, container, empty); + inst->AddSupportingElement(element); + } + else { + aInstantiations.Erase(inst--); + } + } + } + + return NS_OK; +} + +bool +nsRDFConInstanceTestNode::CanPropagate(nsIRDFResource* aSource, + nsIRDFResource* aProperty, + nsIRDFNode* aTarget, + Instantiation& aInitialBindings) const +{ + nsresult rv; + + bool canpropagate = false; + + nsCOMPtr<nsIRDFContainerUtils> rdfc + = do_GetService("@mozilla.org/rdf/container-utils;1"); + + if (! rdfc) + return false; + + // We can certainly propagate ordinal properties + rv = rdfc->IsOrdinalProperty(aProperty, &canpropagate); + if (NS_FAILED(rv)) return false; + + if (! canpropagate) { + canpropagate = mProcessor->ContainmentProperties().Contains(aProperty); + } + + if (MOZ_LOG_TEST(gXULTemplateLog, LogLevel::Debug)) { + const char* source; + aSource->GetValueConst(&source); + + const char* property; + aProperty->GetValueConst(&property); + + nsAutoString target; + nsXULContentUtils::GetTextForNode(aTarget, target); + + MOZ_LOG(gXULTemplateLog, LogLevel::Debug, + ("nsRDFConInstanceTestNode[%p]: CanPropagate([%s]==[%s]=>[%s]) => %s", + this, source, property, NS_ConvertUTF16toUTF8(target).get(), + canpropagate ? "true" : "false")); + } + + if (canpropagate) { + aInitialBindings.AddAssignment(mContainerVariable, aSource); + return true; + } + + return false; +} + +void +nsRDFConInstanceTestNode::Retract(nsIRDFResource* aSource, + nsIRDFResource* aProperty, + nsIRDFNode* aTarget) const +{ + // XXXwaterson oof. complicated. figure this out. + if (0) { + mProcessor->RetractElement(Element(aSource, mContainer, mEmpty)); + } +} + diff --git a/dom/xul/templates/nsRDFConInstanceTestNode.h b/dom/xul/templates/nsRDFConInstanceTestNode.h new file mode 100644 index 000000000..0ed96909e --- /dev/null +++ b/dom/xul/templates/nsRDFConInstanceTestNode.h @@ -0,0 +1,88 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* 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/. */ + +#ifndef nsRDFConInstanceTestNode_h__ +#define nsRDFConInstanceTestNode_h__ + +#include "mozilla/Attributes.h" +#include "nscore.h" +#include "nsRDFTestNode.h" +#include "nsIRDFResource.h" +#include "nsIRDFDataSource.h" +#include "nsXULTemplateQueryProcessorRDF.h" + +/** + * Rule network node that tests if a resource is an RDF container, or + * uses multi-attributes to ``contain'' other elements. + */ +class nsRDFConInstanceTestNode : public nsRDFTestNode +{ +public: + enum Test { eFalse, eTrue, eDontCare }; + + nsRDFConInstanceTestNode(TestNode* aParent, + nsXULTemplateQueryProcessorRDF* aProcessor, + nsIAtom* aContainerVariable, + Test aContainer, + Test aEmpty); + + virtual nsresult FilterInstantiations(InstantiationSet& aInstantiations, + bool* aCantHandleYet) const override; + + virtual bool + CanPropagate(nsIRDFResource* aSource, + nsIRDFResource* aProperty, + nsIRDFNode* aTarget, + Instantiation& aInitialBindings) const override; + + virtual void + Retract(nsIRDFResource* aSource, + nsIRDFResource* aProperty, + nsIRDFNode* aTarget) const override; + + + class Element : public MemoryElement { + public: + Element(nsIRDFResource* aContainer, + Test aContainerTest, + Test aEmptyTest) + : mContainer(aContainer), + mContainerTest(aContainerTest), + mEmptyTest(aEmptyTest) { + MOZ_COUNT_CTOR(nsRDFConInstanceTestNode::Element); } + + virtual ~Element() { MOZ_COUNT_DTOR(nsRDFConInstanceTestNode::Element); } + + virtual const char* Type() const override { + return "nsRDFConInstanceTestNode::Element"; } + + virtual PLHashNumber Hash() const override { + return mozilla::HashGeneric(mContainerTest, mEmptyTest, mContainer.get()); + } + + virtual bool Equals(const MemoryElement& aElement) const override { + if (aElement.Type() == Type()) { + const Element& element = static_cast<const Element&>(aElement); + return mContainer == element.mContainer + && mContainerTest == element.mContainerTest + && mEmptyTest == element.mEmptyTest; + } + return false; } + + protected: + nsCOMPtr<nsIRDFResource> mContainer; + Test mContainerTest; + Test mEmptyTest; + }; + +protected: + nsXULTemplateQueryProcessorRDF* mProcessor; + nsCOMPtr<nsIAtom> mContainerVariable; + Test mContainer; + Test mEmpty; +}; + +#endif // nsRDFConInstanceTestNode_h__ + diff --git a/dom/xul/templates/nsRDFConMemberTestNode.cpp b/dom/xul/templates/nsRDFConMemberTestNode.cpp new file mode 100644 index 000000000..0bb96a5b5 --- /dev/null +++ b/dom/xul/templates/nsRDFConMemberTestNode.cpp @@ -0,0 +1,510 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* 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 "nsRDFConMemberTestNode.h" +#include "nsIRDFContainer.h" +#include "nsIRDFContainerUtils.h" +#include "nsRDFCID.h" +#include "nsIServiceManager.h" +#include "nsResourceSet.h" +#include "nsString.h" +#include "nsXULContentUtils.h" + +#include "mozilla/Logging.h" + +using mozilla::LogLevel; + +extern mozilla::LazyLogModule gXULTemplateLog; + +nsRDFConMemberTestNode::nsRDFConMemberTestNode(TestNode* aParent, + nsXULTemplateQueryProcessorRDF* aProcessor, + nsIAtom *aContainerVariable, + nsIAtom *aMemberVariable) + : nsRDFTestNode(aParent), + mProcessor(aProcessor), + mContainerVariable(aContainerVariable), + mMemberVariable(aMemberVariable) +{ + if (MOZ_LOG_TEST(gXULTemplateLog, LogLevel::Debug)) { + nsAutoCString props; + + nsResourceSet& containmentProps = aProcessor->ContainmentProperties(); + nsResourceSet::ConstIterator last = containmentProps.Last(); + nsResourceSet::ConstIterator first = containmentProps.First(); + nsResourceSet::ConstIterator iter; + + for (iter = first; iter != last; ++iter) { + if (iter != first) + props += " "; + + const char* str; + iter->GetValueConst(&str); + + props += str; + } + + nsAutoString cvar(NS_LITERAL_STRING("(none)")); + if (mContainerVariable) + mContainerVariable->ToString(cvar); + + nsAutoString mvar(NS_LITERAL_STRING("(none)")); + if (mMemberVariable) + mMemberVariable->ToString(mvar); + + MOZ_LOG(gXULTemplateLog, LogLevel::Debug, + ("nsRDFConMemberTestNode[%p]: parent=%p member-props=(%s) container-var=%s member-var=%s", + this, + aParent, + props.get(), + NS_ConvertUTF16toUTF8(cvar).get(), + NS_ConvertUTF16toUTF8(mvar).get())); + } +} + +nsresult +nsRDFConMemberTestNode::FilterInstantiations(InstantiationSet& aInstantiations, + bool* aCantHandleYet) const +{ + // XXX Uh, factor me, please! + nsresult rv; + + if (aCantHandleYet) + *aCantHandleYet = false; + + nsCOMPtr<nsIRDFContainerUtils> rdfc = + do_GetService("@mozilla.org/rdf/container-utils;1"); + + if (! rdfc) + return NS_ERROR_FAILURE; + + nsIRDFDataSource* ds = mProcessor->GetDataSource(); + + InstantiationSet::Iterator last = aInstantiations.Last(); + for (InstantiationSet::Iterator inst = aInstantiations.First(); inst != last; ++inst) { + bool hasContainerBinding; + nsCOMPtr<nsIRDFNode> containerValue; + hasContainerBinding = inst->mAssignments.GetAssignmentFor(mContainerVariable, + getter_AddRefs(containerValue)); + + nsCOMPtr<nsIRDFResource> containerRes = do_QueryInterface(containerValue); + + nsCOMPtr<nsIRDFContainer> rdfcontainer; + + if (hasContainerBinding && containerRes) { + // If we have a container assignment, then see if the + // container is an RDF container (bag, seq, alt), and if + // so, wrap it. + bool isRDFContainer; + rv = rdfc->IsContainer(ds, containerRes, &isRDFContainer); + if (NS_FAILED(rv)) return rv; + + if (isRDFContainer) { + rdfcontainer = do_CreateInstance("@mozilla.org/rdf/container;1", &rv); + if (NS_FAILED(rv)) return rv; + + rv = rdfcontainer->Init(ds, containerRes); + if (NS_FAILED(rv)) return rv; + } + } + + bool hasMemberBinding; + nsCOMPtr<nsIRDFNode> memberValue; + hasMemberBinding = inst->mAssignments.GetAssignmentFor(mMemberVariable, + getter_AddRefs(memberValue)); + + if (MOZ_LOG_TEST(gXULTemplateLog, LogLevel::Debug)) { + const char* container = "(unbound)"; + if (hasContainerBinding) + containerRes->GetValueConst(&container); + + nsAutoString member(NS_LITERAL_STRING("(unbound)")); + if (hasMemberBinding) + nsXULContentUtils::GetTextForNode(memberValue, member); + + MOZ_LOG(gXULTemplateLog, LogLevel::Debug, + ("nsRDFConMemberTestNode[%p]: FilterInstantiations() container=[%s] member=[%s]", + this, container, NS_ConvertUTF16toUTF8(member).get())); + } + + if (hasContainerBinding && hasMemberBinding) { + // it's a consistency check. see if we have a assignment that is consistent + bool isconsistent = false; + + if (rdfcontainer) { + // RDF containers are easy. Just use the container API. + int32_t index; + rv = rdfcontainer->IndexOf(memberValue, &index); + if (NS_FAILED(rv)) return rv; + + if (index >= 0) + isconsistent = true; + } + + // XXXwaterson oof. if we *are* an RDF container, why do + // we still need to grovel through all the containment + // properties if the thing we're looking for wasn't there? + + if (! isconsistent) { + // Othewise, we'll need to grovel through the + // membership properties to see if we have an + // assertion that indicates membership. + nsResourceSet& containmentProps = mProcessor->ContainmentProperties(); + for (nsResourceSet::ConstIterator property = containmentProps.First(); + property != containmentProps.Last(); + ++property) { + bool hasAssertion; + rv = ds->HasAssertion(containerRes, + *property, + memberValue, + true, + &hasAssertion); + if (NS_FAILED(rv)) return rv; + + if (hasAssertion) { + // it's consistent. leave it in the set and we'll + // run it up to our parent. + isconsistent = true; + break; + } + } + } + + MOZ_LOG(gXULTemplateLog, LogLevel::Debug, + (" consistency check => %s", isconsistent ? "passed" : "failed")); + + if (isconsistent) { + // Add a memory element to our set-of-support. + Element* element = + new nsRDFConMemberTestNode::Element(containerRes, + memberValue); + inst->AddSupportingElement(element); + } + else { + // it's inconsistent. remove it. + aInstantiations.Erase(inst--); + } + + // We're done, go on to the next instantiation + continue; + } + + if (hasContainerBinding && rdfcontainer) { + // We've got a container assignment, and the container is + // bound to an RDF container. Add each member as a new + // instantiation. + nsCOMPtr<nsISimpleEnumerator> elements; + rv = rdfcontainer->GetElements(getter_AddRefs(elements)); + if (NS_FAILED(rv)) return rv; + + while (1) { + bool hasmore; + rv = elements->HasMoreElements(&hasmore); + if (NS_FAILED(rv)) return rv; + + if (! hasmore) + break; + + nsCOMPtr<nsISupports> isupports; + rv = elements->GetNext(getter_AddRefs(isupports)); + if (NS_FAILED(rv)) return rv; + + nsCOMPtr<nsIRDFNode> node = do_QueryInterface(isupports); + if (! node) + return NS_ERROR_UNEXPECTED; + + if (MOZ_LOG_TEST(gXULTemplateLog, LogLevel::Debug)) { + nsAutoString member; + nsXULContentUtils::GetTextForNode(node, member); + + MOZ_LOG(gXULTemplateLog, LogLevel::Debug, + (" member => %s", NS_ConvertUTF16toUTF8(member).get())); + } + + Instantiation newinst = *inst; + newinst.AddAssignment(mMemberVariable, node); + + Element* element = + new nsRDFConMemberTestNode::Element(containerRes, node); + newinst.AddSupportingElement(element); + aInstantiations.Insert(inst, newinst); + } + } + + if (hasMemberBinding) { + // Oh, this is so nasty. If we have a member assignment, then + // grovel through each one of our inbound arcs to see if + // any of them are ordinal properties (like an RDF + // container might have). If so, walk it backwards to get + // the container we're in. + nsCOMPtr<nsISimpleEnumerator> arcsin; + rv = ds->ArcLabelsIn(memberValue, getter_AddRefs(arcsin)); + if (NS_FAILED(rv)) return rv; + + while (1) { + nsCOMPtr<nsIRDFResource> property; + + { + bool hasmore; + rv = arcsin->HasMoreElements(&hasmore); + if (NS_FAILED(rv)) return rv; + + if (! hasmore) + break; + + nsCOMPtr<nsISupports> isupports; + rv = arcsin->GetNext(getter_AddRefs(isupports)); + if (NS_FAILED(rv)) return rv; + + property = do_QueryInterface(isupports); + if (! property) + return NS_ERROR_UNEXPECTED; + } + + // Ordinal properties automagically indicate container + // membership as far as we're concerned. Note that + // we're *only* concerned with ordinal properties + // here: the next block will worry about the other + // membership properties. + bool isordinal; + rv = rdfc->IsOrdinalProperty(property, &isordinal); + if (NS_FAILED(rv)) return rv; + + if (isordinal) { + // If we get here, we've found a property that + // indicates container membership leading *into* a + // member node. Find all the people that point to + // it, and call them containers. + nsCOMPtr<nsISimpleEnumerator> sources; + rv = ds->GetSources(property, memberValue, true, + getter_AddRefs(sources)); + if (NS_FAILED(rv)) return rv; + + while (1) { + bool hasmore; + rv = sources->HasMoreElements(&hasmore); + if (NS_FAILED(rv)) return rv; + + if (! hasmore) + break; + + nsCOMPtr<nsISupports> isupports; + rv = sources->GetNext(getter_AddRefs(isupports)); + if (NS_FAILED(rv)) return rv; + + nsCOMPtr<nsIRDFResource> source = do_QueryInterface(isupports); + if (! source) + return NS_ERROR_UNEXPECTED; + + if (MOZ_LOG_TEST(gXULTemplateLog, LogLevel::Debug)) { + const char* container; + source->GetValueConst(&container); + + MOZ_LOG(gXULTemplateLog, LogLevel::Debug, + (" container => %s", container)); + } + + // Add a new instantiation + Instantiation newinst = *inst; + newinst.AddAssignment(mContainerVariable, source); + + Element* element = + new nsRDFConMemberTestNode::Element(source, + memberValue); + newinst.AddSupportingElement(element); + + aInstantiations.Insert(inst, newinst); + } + } + } + } + + if ((hasContainerBinding && ! hasMemberBinding) || + (! hasContainerBinding && hasMemberBinding)) { + // it's an open ended query on the container or member. go + // through our containment properties to see if anything + // applies. + nsResourceSet& containmentProps = mProcessor->ContainmentProperties(); + for (nsResourceSet::ConstIterator property = containmentProps.First(); + property != containmentProps.Last(); + ++property) { + nsCOMPtr<nsISimpleEnumerator> results; + if (hasContainerBinding) { + rv = ds->GetTargets(containerRes, *property, true, + getter_AddRefs(results)); + } + else { + rv = ds->GetSources(*property, memberValue, true, + getter_AddRefs(results)); + } + if (NS_FAILED(rv)) return rv; + + while (1) { + bool hasmore; + rv = results->HasMoreElements(&hasmore); + if (NS_FAILED(rv)) return rv; + + if (! hasmore) + break; + + nsCOMPtr<nsISupports> isupports; + rv = results->GetNext(getter_AddRefs(isupports)); + if (NS_FAILED(rv)) return rv; + + nsIAtom* variable; + nsCOMPtr<nsIRDFNode> value; + nsCOMPtr<nsIRDFResource> valueRes; + + if (hasContainerBinding) { + variable = mMemberVariable; + + value = do_QueryInterface(isupports); + NS_ASSERTION(value != nullptr, "member is not an nsIRDFNode"); + if (! value) continue; + + if (MOZ_LOG_TEST(gXULTemplateLog, LogLevel::Debug)) { + nsAutoString s; + nsXULContentUtils::GetTextForNode(value, s); + + MOZ_LOG(gXULTemplateLog, LogLevel::Debug, + (" member => %s", NS_ConvertUTF16toUTF8(s).get())); + } + } + else { + variable = mContainerVariable; + + valueRes = do_QueryInterface(isupports); + NS_ASSERTION(valueRes != nullptr, "container is not an nsIRDFResource"); + if (! valueRes) continue; + + value = valueRes; + + if (MOZ_LOG_TEST(gXULTemplateLog, LogLevel::Debug)) { + const char* s; + valueRes->GetValueConst(&s); + + MOZ_LOG(gXULTemplateLog, LogLevel::Debug, + (" container => %s", s)); + } + } + + // Copy the original instantiation, and add it to the + // instantiation set with the new assignment that we've + // introduced. Ownership will be transferred to the + Instantiation newinst = *inst; + newinst.AddAssignment(variable, value); + + Element* element; + if (hasContainerBinding) { + element = + new nsRDFConMemberTestNode::Element(containerRes, value); + } + else { + element = + new nsRDFConMemberTestNode::Element(valueRes, memberValue); + } + + if (! element) + return NS_ERROR_OUT_OF_MEMORY; + + newinst.AddSupportingElement(element); + + aInstantiations.Insert(inst, newinst); + } + } + } + + if (! hasContainerBinding && ! hasMemberBinding) { + // Neither container nor member assignment! + if (!aCantHandleYet) { + nsXULContentUtils::LogTemplateError(ERROR_TEMPLATE_MEMBER_UNBOUND); + return NS_ERROR_UNEXPECTED; + } + + *aCantHandleYet = true; + return NS_OK; + } + + // finally, remove the "under specified" instantiation. + aInstantiations.Erase(inst--); + } + + return NS_OK; +} + +bool +nsRDFConMemberTestNode::CanPropagate(nsIRDFResource* aSource, + nsIRDFResource* aProperty, + nsIRDFNode* aTarget, + Instantiation& aInitialBindings) const +{ + nsresult rv; + + bool canpropagate = false; + + nsCOMPtr<nsIRDFContainerUtils> rdfc = + do_GetService("@mozilla.org/rdf/container-utils;1"); + + if (! rdfc) + return false; + + // We can certainly propagate ordinal properties + rv = rdfc->IsOrdinalProperty(aProperty, &canpropagate); + if (NS_FAILED(rv)) return false; + + if (! canpropagate) { + canpropagate = mProcessor->ContainmentProperties().Contains(aProperty); + } + + if (MOZ_LOG_TEST(gXULTemplateLog, LogLevel::Debug)) { + const char* source; + aSource->GetValueConst(&source); + + const char* property; + aProperty->GetValueConst(&property); + + nsAutoString target; + nsXULContentUtils::GetTextForNode(aTarget, target); + + MOZ_LOG(gXULTemplateLog, LogLevel::Debug, + ("nsRDFConMemberTestNode[%p]: CanPropagate([%s]==[%s]=>[%s]) => %s", + this, source, property, NS_ConvertUTF16toUTF8(target).get(), + canpropagate ? "true" : "false")); + } + + if (canpropagate) { + aInitialBindings.AddAssignment(mContainerVariable, aSource); + aInitialBindings.AddAssignment(mMemberVariable, aTarget); + return true; + } + + return false; +} + +void +nsRDFConMemberTestNode::Retract(nsIRDFResource* aSource, + nsIRDFResource* aProperty, + nsIRDFNode* aTarget) const +{ + bool canretract = false; + + nsCOMPtr<nsIRDFContainerUtils> rdfc = + do_GetService("@mozilla.org/rdf/container-utils;1"); + + if (! rdfc) + return; + + // We can certainly retract ordinal properties + nsresult rv; + rv = rdfc->IsOrdinalProperty(aProperty, &canretract); + if (NS_FAILED(rv)) return; + + if (! canretract) { + canretract = mProcessor->ContainmentProperties().Contains(aProperty); + } + + if (canretract) { + mProcessor->RetractElement(Element(aSource, aTarget)); + } +} diff --git a/dom/xul/templates/nsRDFConMemberTestNode.h b/dom/xul/templates/nsRDFConMemberTestNode.h new file mode 100644 index 000000000..4db2f8983 --- /dev/null +++ b/dom/xul/templates/nsRDFConMemberTestNode.h @@ -0,0 +1,77 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* 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/. */ + +#ifndef nsRDFConMemberTestNode_h__ +#define nsRDFConMemberTestNode_h__ + +#include "mozilla/Attributes.h" +#include "nscore.h" +#include "nsRDFTestNode.h" +#include "nsIRDFDataSource.h" +#include "nsXULTemplateQueryProcessorRDF.h" + +/** + * Rule network node that test if a resource is a member of an RDF + * container, or is ``contained'' by another resource that refers to + * it using a ``containment'' attribute. + */ +class nsRDFConMemberTestNode : public nsRDFTestNode +{ +public: + nsRDFConMemberTestNode(TestNode* aParent, + nsXULTemplateQueryProcessorRDF* aProcessor, + nsIAtom* aContainerVariable, + nsIAtom* aMemberVariable); + + virtual nsresult FilterInstantiations(InstantiationSet& aInstantiations, + bool* aCantHandleYet) const override; + + virtual bool + CanPropagate(nsIRDFResource* aSource, + nsIRDFResource* aProperty, + nsIRDFNode* aTarget, + Instantiation& aInitialBindings) const override; + + virtual void + Retract(nsIRDFResource* aSource, + nsIRDFResource* aProperty, + nsIRDFNode* aTarget) const override; + + class Element : public MemoryElement { + public: + Element(nsIRDFResource* aContainer, + nsIRDFNode* aMember) + : mContainer(aContainer), + mMember(aMember) { + MOZ_COUNT_CTOR(nsRDFConMemberTestNode::Element); } + + virtual ~Element() { MOZ_COUNT_DTOR(nsRDFConMemberTestNode::Element); } + + virtual const char* Type() const override { + return "nsRDFConMemberTestNode::Element"; } + + virtual PLHashNumber Hash() const override { + return PLHashNumber(NS_PTR_TO_INT32(mContainer.get())) ^ + (PLHashNumber(NS_PTR_TO_INT32(mMember.get())) >> 12); } + + virtual bool Equals(const MemoryElement& aElement) const override { + if (aElement.Type() == Type()) { + const Element& element = static_cast<const Element&>(aElement); + return mContainer == element.mContainer && mMember == element.mMember; + } + return false; } + + protected: + nsCOMPtr<nsIRDFResource> mContainer; + nsCOMPtr<nsIRDFNode> mMember; + }; + +protected: + nsXULTemplateQueryProcessorRDF* mProcessor; + nsCOMPtr<nsIAtom> mContainerVariable; + nsCOMPtr<nsIAtom> mMemberVariable; +}; + +#endif // nsRDFConMemberTestNode_h__ diff --git a/dom/xul/templates/nsRDFPropertyTestNode.cpp b/dom/xul/templates/nsRDFPropertyTestNode.cpp new file mode 100644 index 000000000..2fa08f2b8 --- /dev/null +++ b/dom/xul/templates/nsRDFPropertyTestNode.cpp @@ -0,0 +1,362 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* 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 "nsRDFPropertyTestNode.h" +#include "nsString.h" +#include "nsXULContentUtils.h" + +#include "mozilla/Logging.h" + +using mozilla::LogLevel; + +extern mozilla::LazyLogModule gXULTemplateLog; +#include "nsIRDFLiteral.h" + +nsRDFPropertyTestNode::nsRDFPropertyTestNode(TestNode* aParent, + nsXULTemplateQueryProcessorRDF* aProcessor, + nsIAtom* aSourceVariable, + nsIRDFResource* aProperty, + nsIAtom* aTargetVariable) + : nsRDFTestNode(aParent), + mProcessor(aProcessor), + mSourceVariable(aSourceVariable), + mSource(nullptr), + mProperty(aProperty), + mTargetVariable(aTargetVariable), + mTarget(nullptr) +{ + if (MOZ_LOG_TEST(gXULTemplateLog, LogLevel::Debug)) { + const char* prop = "(null)"; + if (aProperty) + aProperty->GetValueConst(&prop); + + nsAutoString svar(NS_LITERAL_STRING("(none)")); + if (mSourceVariable) + mSourceVariable->ToString(svar); + + nsAutoString tvar(NS_LITERAL_STRING("(none)")); + if (mTargetVariable) + mTargetVariable->ToString(tvar); + + MOZ_LOG(gXULTemplateLog, LogLevel::Debug, + ("nsRDFPropertyTestNode[%p]: parent=%p source=%s property=%s target=%s", + this, aParent, NS_ConvertUTF16toUTF8(svar).get(), prop, NS_ConvertUTF16toUTF8(tvar).get())); + } +} + + +nsRDFPropertyTestNode::nsRDFPropertyTestNode(TestNode* aParent, + nsXULTemplateQueryProcessorRDF* aProcessor, + nsIRDFResource* aSource, + nsIRDFResource* aProperty, + nsIAtom* aTargetVariable) + : nsRDFTestNode(aParent), + mProcessor(aProcessor), + mSourceVariable(nullptr), + mSource(aSource), + mProperty(aProperty), + mTargetVariable(aTargetVariable), + mTarget(nullptr) +{ + if (MOZ_LOG_TEST(gXULTemplateLog, LogLevel::Debug)) { + const char* source = "(null)"; + if (aSource) + aSource->GetValueConst(&source); + + const char* prop = "(null)"; + if (aProperty) + aProperty->GetValueConst(&prop); + + nsAutoString tvar(NS_LITERAL_STRING("(none)")); + if (mTargetVariable) + mTargetVariable->ToString(tvar); + + MOZ_LOG(gXULTemplateLog, LogLevel::Debug, + ("nsRDFPropertyTestNode[%p]: parent=%p source=%s property=%s target=%s", + this, aParent, source, prop, NS_ConvertUTF16toUTF8(tvar).get())); + } +} + + +nsRDFPropertyTestNode::nsRDFPropertyTestNode(TestNode* aParent, + nsXULTemplateQueryProcessorRDF* aProcessor, + nsIAtom* aSourceVariable, + nsIRDFResource* aProperty, + nsIRDFNode* aTarget) + : nsRDFTestNode(aParent), + mProcessor(aProcessor), + mSourceVariable(aSourceVariable), + mSource(nullptr), + mProperty(aProperty), + mTargetVariable(nullptr), + mTarget(aTarget) +{ + if (MOZ_LOG_TEST(gXULTemplateLog, LogLevel::Debug)) { + nsAutoString svar(NS_LITERAL_STRING("(none)")); + if (mSourceVariable) + mSourceVariable->ToString(svar); + + const char* prop = "(null)"; + if (aProperty) + aProperty->GetValueConst(&prop); + + nsAutoString target; + nsXULContentUtils::GetTextForNode(aTarget, target); + + MOZ_LOG(gXULTemplateLog, LogLevel::Debug, + ("nsRDFPropertyTestNode[%p]: parent=%p source=%s property=%s target=%s", + this, aParent, NS_ConvertUTF16toUTF8(svar).get(), prop, NS_ConvertUTF16toUTF8(target).get())); + } +} + + +nsresult +nsRDFPropertyTestNode::FilterInstantiations(InstantiationSet& aInstantiations, + bool* aCantHandleYet) const +{ + nsresult rv; + + if (aCantHandleYet) + *aCantHandleYet = false; + + nsIRDFDataSource* ds = mProcessor->GetDataSource(); + + InstantiationSet::Iterator last = aInstantiations.Last(); + for (InstantiationSet::Iterator inst = aInstantiations.First(); inst != last; ++inst) { + bool hasSourceBinding; + nsCOMPtr<nsIRDFResource> sourceRes; + + if (mSource) { + hasSourceBinding = true; + sourceRes = mSource; + } + else { + nsCOMPtr<nsIRDFNode> sourceValue; + hasSourceBinding = inst->mAssignments.GetAssignmentFor(mSourceVariable, + getter_AddRefs(sourceValue)); + sourceRes = do_QueryInterface(sourceValue); + } + + bool hasTargetBinding; + nsCOMPtr<nsIRDFNode> targetValue; + + if (mTarget) { + hasTargetBinding = true; + targetValue = mTarget; + } + else { + hasTargetBinding = inst->mAssignments.GetAssignmentFor(mTargetVariable, + getter_AddRefs(targetValue)); + } + + if (MOZ_LOG_TEST(gXULTemplateLog, LogLevel::Debug)) { + const char* source = "(unbound)"; + if (hasSourceBinding) + sourceRes->GetValueConst(&source); + + nsAutoString target(NS_LITERAL_STRING("(unbound)")); + if (hasTargetBinding) + nsXULContentUtils::GetTextForNode(targetValue, target); + + MOZ_LOG(gXULTemplateLog, LogLevel::Debug, + ("nsRDFPropertyTestNode[%p]: FilterInstantiations() source=[%s] target=[%s]", + this, source, NS_ConvertUTF16toUTF8(target).get())); + } + + if (hasSourceBinding && hasTargetBinding) { + // it's a consistency check. see if we have a assignment that is consistent + bool hasAssertion; + rv = ds->HasAssertion(sourceRes, mProperty, targetValue, + true, &hasAssertion); + if (NS_FAILED(rv)) return rv; + + MOZ_LOG(gXULTemplateLog, LogLevel::Debug, + (" consistency check => %s", hasAssertion ? "passed" : "failed")); + + if (hasAssertion) { + // it's consistent. + Element* element = + new nsRDFPropertyTestNode::Element(sourceRes, mProperty, + targetValue); + inst->AddSupportingElement(element); + } + else { + // it's inconsistent. remove it. + aInstantiations.Erase(inst--); + } + } + else if ((hasSourceBinding && ! hasTargetBinding) || + (! hasSourceBinding && hasTargetBinding)) { + // it's an open ended query on the source or + // target. figure out what matches and add as a + // cross-product. + nsCOMPtr<nsISimpleEnumerator> results; + if (hasSourceBinding) { + rv = ds->GetTargets(sourceRes, + mProperty, + true, + getter_AddRefs(results)); + } + else { + rv = ds->GetSources(mProperty, + targetValue, + true, + getter_AddRefs(results)); + if (NS_FAILED(rv)) return rv; + } + + while (1) { + bool hasMore; + rv = results->HasMoreElements(&hasMore); + if (NS_FAILED(rv)) return rv; + + if (! hasMore) + break; + + nsCOMPtr<nsISupports> isupports; + rv = results->GetNext(getter_AddRefs(isupports)); + if (NS_FAILED(rv)) return rv; + + nsIAtom* variable; + nsCOMPtr<nsIRDFNode> value; + + if (hasSourceBinding) { + variable = mTargetVariable; + + value = do_QueryInterface(isupports); + NS_ASSERTION(value != nullptr, "target is not an nsIRDFNode"); + + if (MOZ_LOG_TEST(gXULTemplateLog, LogLevel::Debug)) { + nsAutoString s(NS_LITERAL_STRING("(none found)")); + if (value) + nsXULContentUtils::GetTextForNode(value, s); + + MOZ_LOG(gXULTemplateLog, LogLevel::Debug, + (" target => %s", NS_ConvertUTF16toUTF8(s).get())); + } + + if (! value) continue; + + targetValue = value; + } + else { + variable = mSourceVariable; + + nsCOMPtr<nsIRDFResource> source = do_QueryInterface(isupports); + NS_ASSERTION(source != nullptr, "source is not an nsIRDFResource"); + + if (MOZ_LOG_TEST(gXULTemplateLog, LogLevel::Debug)) { + const char* s = "(none found)"; + if (source) + source->GetValueConst(&s); + + MOZ_LOG(gXULTemplateLog, LogLevel::Debug, + (" source => %s", s)); + } + + if (! source) continue; + + value = sourceRes = source; + } + + // Copy the original instantiation, and add it to the + // instantiation set with the new assignment that we've + // introduced. Ownership will be transferred to the + Instantiation newinst = *inst; + newinst.AddAssignment(variable, value); + + Element* element = + new nsRDFPropertyTestNode::Element(sourceRes, mProperty, + targetValue); + newinst.AddSupportingElement(element); + + aInstantiations.Insert(inst, newinst); + } + + // finally, remove the "under specified" instantiation. + aInstantiations.Erase(inst--); + } + else { + if (!aCantHandleYet) { + nsXULContentUtils::LogTemplateError(ERROR_TEMPLATE_TRIPLE_UNBOUND); + // Neither source nor target assignment! + return NS_ERROR_UNEXPECTED; + } + + *aCantHandleYet = true; + return NS_OK; + } + } + + return NS_OK; +} + +bool +nsRDFPropertyTestNode::CanPropagate(nsIRDFResource* aSource, + nsIRDFResource* aProperty, + nsIRDFNode* aTarget, + Instantiation& aInitialBindings) const +{ + bool result; + + if ((mProperty.get() != aProperty) || + (mSource && mSource.get() != aSource) || + (mTarget && mTarget.get() != aTarget)) { + result = false; + } + else { + if (mSourceVariable) + aInitialBindings.AddAssignment(mSourceVariable, aSource); + + if (mTargetVariable) + aInitialBindings.AddAssignment(mTargetVariable, aTarget); + + result = true; + } + + if (MOZ_LOG_TEST(gXULTemplateLog, LogLevel::Debug)) { + const char* source; + aSource->GetValueConst(&source); + + const char* property; + aProperty->GetValueConst(&property); + + nsAutoString target; + nsXULContentUtils::GetTextForNode(aTarget, target); + + MOZ_LOG(gXULTemplateLog, LogLevel::Debug, + ("nsRDFPropertyTestNode[%p]: CanPropagate([%s]==[%s]=>[%s]) => %s", + this, source, property, NS_ConvertUTF16toUTF8(target).get(), + result ? "true" : "false")); + } + + return result; +} + +void +nsRDFPropertyTestNode::Retract(nsIRDFResource* aSource, + nsIRDFResource* aProperty, + nsIRDFNode* aTarget) const +{ + if (aProperty == mProperty.get()) { + if (MOZ_LOG_TEST(gXULTemplateLog, LogLevel::Debug)) { + const char* source; + aSource->GetValueConst(&source); + + const char* property; + aProperty->GetValueConst(&property); + + nsAutoString target; + nsXULContentUtils::GetTextForNode(aTarget, target); + + MOZ_LOG(gXULTemplateLog, LogLevel::Debug, + ("nsRDFPropertyTestNode[%p]: Retract([%s]==[%s]=>[%s])", + this, source, property, NS_ConvertUTF16toUTF8(target).get())); + } + + mProcessor->RetractElement(Element(aSource, aProperty, aTarget)); + } +} + diff --git a/dom/xul/templates/nsRDFPropertyTestNode.h b/dom/xul/templates/nsRDFPropertyTestNode.h new file mode 100644 index 000000000..673552a26 --- /dev/null +++ b/dom/xul/templates/nsRDFPropertyTestNode.h @@ -0,0 +1,104 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* 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/. */ + +#ifndef nsRDFPropertyTestNode_h__ +#define nsRDFPropertyTestNode_h__ + +#include "mozilla/Attributes.h" +#include "nscore.h" +#include "nsRDFTestNode.h" +#include "nsIRDFDataSource.h" +#include "nsIRDFResource.h" +#include "nsXULTemplateQueryProcessorRDF.h" + +class nsRDFPropertyTestNode : public nsRDFTestNode +{ +public: + /** + * Both source and target unbound (?source ^property ?target) + */ + nsRDFPropertyTestNode(TestNode* aParent, + nsXULTemplateQueryProcessorRDF* aProcessor, + nsIAtom* aSourceVariable, + nsIRDFResource* aProperty, + nsIAtom* aTargetVariable); + + /** + * Source bound, target unbound (source ^property ?target) + */ + nsRDFPropertyTestNode(TestNode* aParent, + nsXULTemplateQueryProcessorRDF* aProcessor, + nsIRDFResource* aSource, + nsIRDFResource* aProperty, + nsIAtom* aTargetVariable); + + /** + * Source unbound, target bound (?source ^property target) + */ + nsRDFPropertyTestNode(TestNode* aParent, + nsXULTemplateQueryProcessorRDF* aProcessor, + nsIAtom* aSourceVariable, + nsIRDFResource* aProperty, + nsIRDFNode* aTarget); + + virtual nsresult FilterInstantiations(InstantiationSet& aInstantiations, + bool* aCantHandleYet) const override; + + virtual bool + CanPropagate(nsIRDFResource* aSource, + nsIRDFResource* aProperty, + nsIRDFNode* aTarget, + Instantiation& aInitialBindings) const override; + + virtual void + Retract(nsIRDFResource* aSource, + nsIRDFResource* aProperty, + nsIRDFNode* aTarget) const override; + + + class Element : public MemoryElement { + public: + Element(nsIRDFResource* aSource, + nsIRDFResource* aProperty, + nsIRDFNode* aTarget) + : mSource(aSource), + mProperty(aProperty), + mTarget(aTarget) { + MOZ_COUNT_CTOR(nsRDFPropertyTestNode::Element); } + + virtual ~Element() { MOZ_COUNT_DTOR(nsRDFPropertyTestNode::Element); } + + virtual const char* Type() const override { + return "nsRDFPropertyTestNode::Element"; } + + virtual PLHashNumber Hash() const override { + return mozilla::HashGeneric(mSource.get(), mProperty.get(), mTarget.get()); + } + + virtual bool Equals(const MemoryElement& aElement) const override { + if (aElement.Type() == Type()) { + const Element& element = static_cast<const Element&>(aElement); + return mSource == element.mSource + && mProperty == element.mProperty + && mTarget == element.mTarget; + } + return false; } + + protected: + nsCOMPtr<nsIRDFResource> mSource; + nsCOMPtr<nsIRDFResource> mProperty; + nsCOMPtr<nsIRDFNode> mTarget; + }; + +protected: + nsXULTemplateQueryProcessorRDF* mProcessor; + nsCOMPtr<nsIAtom> mSourceVariable; + nsCOMPtr<nsIRDFResource> mSource; + nsCOMPtr<nsIRDFResource> mProperty; + nsCOMPtr<nsIAtom> mTargetVariable; + nsCOMPtr<nsIRDFNode> mTarget; +}; + +#endif // nsRDFPropertyTestNode_h__ diff --git a/dom/xul/templates/nsRDFQuery.cpp b/dom/xul/templates/nsRDFQuery.cpp new file mode 100644 index 000000000..b4eb706ed --- /dev/null +++ b/dom/xul/templates/nsRDFQuery.cpp @@ -0,0 +1,47 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* 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 "nscore.h" +#include "nsCOMPtr.h" + +#include "nsXULTemplateQueryProcessorRDF.h" +#include "nsRDFQuery.h" + +NS_IMPL_CYCLE_COLLECTION(nsRDFQuery, mQueryNode) + +NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(nsRDFQuery) + NS_INTERFACE_MAP_ENTRY(nsITemplateRDFQuery) + NS_INTERFACE_MAP_ENTRY(nsISupports) +NS_INTERFACE_MAP_END + +NS_IMPL_CYCLE_COLLECTING_ADDREF(nsRDFQuery) +NS_IMPL_CYCLE_COLLECTING_RELEASE(nsRDFQuery) + +void +nsRDFQuery::Finish() +{ + // the template builder is going away and the query processor likely as + // well. Clear the reference to avoid calling it. + mProcessor = nullptr; + mCachedResults = nullptr; +} + +nsresult +nsRDFQuery::SetCachedResults(nsXULTemplateQueryProcessorRDF* aProcessor, + const InstantiationSet& aInstantiations) +{ + mCachedResults = new nsXULTemplateResultSetRDF(aProcessor, this, &aInstantiations); + return NS_OK; +} + + +void +nsRDFQuery::UseCachedResults(nsISimpleEnumerator** aResults) +{ + *aResults = mCachedResults; + NS_IF_ADDREF(*aResults); + + mCachedResults = nullptr; +} diff --git a/dom/xul/templates/nsRDFQuery.h b/dom/xul/templates/nsRDFQuery.h new file mode 100644 index 000000000..572cce4d3 --- /dev/null +++ b/dom/xul/templates/nsRDFQuery.h @@ -0,0 +1,130 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* 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/. */ + +#ifndef nsRDFQuery_h__ +#define nsRDFQuery_h__ + +#include "nsISimpleEnumerator.h" +#include "nsCycleCollectionParticipant.h" +#include "mozilla/Attributes.h" + +#define NS_ITEMPLATERDFQUERY_IID \ + {0x8929ff60, 0x1c9c, 0x4d87, \ + { 0xac, 0x02, 0x09, 0x14, 0x15, 0x3b, 0x48, 0xc4 }} + +class nsXULTemplateQueryProcessorRDF; + +/** + * A compiled query in the RDF query processor. This interface should not be + * used directly outside of the RDF query processor. + */ +class nsITemplateRDFQuery : public nsISupports +{ +public: + NS_DECLARE_STATIC_IID_ACCESSOR(NS_ITEMPLATERDFQUERY_IID) + + // return the processor the query was created from + virtual nsXULTemplateQueryProcessorRDF* Processor() = 0; // not addrefed + + // return the member variable for the query + virtual nsIAtom* GetMemberVariable() = 0; // not addrefed + + // return the <query> node the query was compiled from + virtual void GetQueryNode(nsIDOMNode** aQueryNode) = 0; + + // remove any results that are cached by the query + virtual void ClearCachedResults() = 0; +}; + +class nsRDFQuery final : public nsITemplateRDFQuery +{ + ~nsRDFQuery() { Finish(); } + +public: + + explicit nsRDFQuery(nsXULTemplateQueryProcessorRDF* aProcessor) + : mProcessor(aProcessor), + mSimple(false), + mRoot(nullptr), + mCachedResults(nullptr) + { } + + NS_DECL_CYCLE_COLLECTING_ISUPPORTS + NS_DECL_CYCLE_COLLECTION_CLASS(nsRDFQuery) + + /** + * Retrieve the root node in the rule network + * @return the root node in the rule network + */ + TestNode* GetRoot() { return mRoot; } + + void SetRoot(TestNode* aRoot) { mRoot = aRoot; } + + void GetQueryNode(nsIDOMNode** aQueryNode) override + { + *aQueryNode = mQueryNode; + NS_IF_ADDREF(*aQueryNode); + } + + void SetQueryNode(nsIDOMNode* aQueryNode) + { + mQueryNode = aQueryNode; + } + + // an optimization is used when several queries all use the simple query + // syntax. Since simple queries can only generate one possible set of + // results, they only need to be calculated once and reused for every + // simple query. The results may be cached in the query for this purpose. + // If successful, this method takes ownership of aInstantiations. + nsresult SetCachedResults(nsXULTemplateQueryProcessorRDF* aProcessor, + const InstantiationSet& aInstantiations); + + // grab the cached results, if any, causing the caller to take ownership + // of them. This also has the effect of setting the cached results in this + // nsRDFQuery to null. + void UseCachedResults(nsISimpleEnumerator** aResults); + + // clear the cached results + void ClearCachedResults() override + { + mCachedResults = nullptr; + } + + nsXULTemplateQueryProcessorRDF* Processor() override { return mProcessor; } + + nsIAtom* GetMemberVariable() override { return mMemberVariable; } + + bool IsSimple() { return mSimple; } + + void SetSimple() { mSimple = true; } + + // the reference and member variables for the query + nsCOMPtr<nsIAtom> mRefVariable; + nsCOMPtr<nsIAtom> mMemberVariable; + +protected: + + nsXULTemplateQueryProcessorRDF* mProcessor; + + // true if the query is a simple rule (one with a default query) + bool mSimple; + + /** + * The root node in the network for this query + */ + TestNode *mRoot; + + // the <query> node + nsCOMPtr<nsIDOMNode> mQueryNode; + + // used for simple rules since their results are all determined in one step + nsCOMPtr<nsISimpleEnumerator> mCachedResults; + + void Finish(); +}; + +NS_DEFINE_STATIC_IID_ACCESSOR(nsITemplateRDFQuery, NS_ITEMPLATERDFQUERY_IID) + +#endif // nsRDFQuery_h__ diff --git a/dom/xul/templates/nsRDFTestNode.h b/dom/xul/templates/nsRDFTestNode.h new file mode 100644 index 000000000..0e450fadf --- /dev/null +++ b/dom/xul/templates/nsRDFTestNode.h @@ -0,0 +1,49 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* 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/. */ + +#ifndef nsRDFTestNode_h__ +#define nsRDFTestNode_h__ + +#include "nsRuleNetwork.h" + +class nsIRDFResource; +class nsIRDFNode; + +/** + * An abstract base class for all of the RDF-related tests. This interface + * allows us to iterate over all of the RDF tests to find the one in the + * network that is apropos for a newly-added assertion. + */ +class nsRDFTestNode : public TestNode +{ +public: + explicit nsRDFTestNode(TestNode* aParent) + : TestNode(aParent) {} + + /** + * Determine whether the node can propagate an assertion + * with the specified source, property, and target. If the + * assertion can be propagated, aInitialBindings will be + * initialized with appropriate variable-to-value assignments + * to allow the rule network to start a constrain and propagate + * search from this node in the network. + * + * @return true if the node can propagate the specified + * assertion. + */ + virtual bool CanPropagate(nsIRDFResource* aSource, + nsIRDFResource* aProperty, + nsIRDFNode* aTarget, + Instantiation& aInitialBindings) const = 0; + + /** + * + */ + virtual void Retract(nsIRDFResource* aSource, + nsIRDFResource* aProperty, + nsIRDFNode* aTarget) const = 0; +}; + +#endif // nsRDFTestNode_h__ diff --git a/dom/xul/templates/nsResourceSet.cpp b/dom/xul/templates/nsResourceSet.cpp new file mode 100644 index 000000000..64f4aad19 --- /dev/null +++ b/dom/xul/templates/nsResourceSet.cpp @@ -0,0 +1,105 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* 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 "nsResourceSet.h" + +nsResourceSet::nsResourceSet(const nsResourceSet& aResourceSet) + : mResources(nullptr), + mCount(0), + mCapacity(0) +{ + ConstIterator last = aResourceSet.Last(); + for (ConstIterator resource = aResourceSet.First(); resource != last; ++resource) + Add(*resource); +} + + +nsResourceSet& +nsResourceSet::operator=(const nsResourceSet& aResourceSet) +{ + Clear(); + ConstIterator last = aResourceSet.Last(); + for (ConstIterator resource = aResourceSet.First(); resource != last; ++resource) + Add(*resource); + return *this; +} + +nsResourceSet::~nsResourceSet() +{ + MOZ_COUNT_DTOR(nsResourceSet); + Clear(); + delete[] mResources; +} + +nsresult +nsResourceSet::Clear() +{ + while (--mCount >= 0) { + NS_RELEASE(mResources[mCount]); + } + mCount = 0; + return NS_OK; +} + +nsresult +nsResourceSet::Add(nsIRDFResource* aResource) +{ + NS_PRECONDITION(aResource != nullptr, "null ptr"); + if (! aResource) + return NS_ERROR_NULL_POINTER; + + if (Contains(aResource)) + return NS_OK; + + if (mCount >= mCapacity) { + int32_t capacity = mCapacity + 4; + nsIRDFResource** resources = new nsIRDFResource*[capacity]; + for (int32_t i = mCount - 1; i >= 0; --i) + resources[i] = mResources[i]; + + delete[] mResources; + + mResources = resources; + mCapacity = capacity; + } + + mResources[mCount++] = aResource; + NS_ADDREF(aResource); + return NS_OK; +} + +void +nsResourceSet::Remove(nsIRDFResource* aProperty) +{ + bool found = false; + + nsIRDFResource** res = mResources; + nsIRDFResource** limit = mResources + mCount; + while (res < limit) { + if (found) { + *(res - 1) = *res; + } + else if (*res == aProperty) { + NS_RELEASE(*res); + found = true; + } + ++res; + } + + if (found) + --mCount; +} + +bool +nsResourceSet::Contains(nsIRDFResource* aResource) const +{ + for (int32_t i = mCount - 1; i >= 0; --i) { + if (mResources[i] == aResource) + return true; + } + + return false; +} + diff --git a/dom/xul/templates/nsResourceSet.h b/dom/xul/templates/nsResourceSet.h new file mode 100644 index 000000000..1f50538a8 --- /dev/null +++ b/dom/xul/templates/nsResourceSet.h @@ -0,0 +1,82 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* 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/. */ +#ifndef nsResourceSet_h__ +#define nsResourceSet_h__ + +#include "nsIRDFResource.h" + +class nsResourceSet +{ +public: + nsResourceSet() + : mResources(nullptr), + mCount(0), + mCapacity(0) { + MOZ_COUNT_CTOR(nsResourceSet); } + + nsResourceSet(const nsResourceSet& aResourceSet); + + nsResourceSet& operator=(const nsResourceSet& aResourceSet); + + ~nsResourceSet(); + + nsresult Clear(); + nsresult Add(nsIRDFResource* aProperty); + void Remove(nsIRDFResource* aProperty); + + bool Contains(nsIRDFResource* aProperty) const; + +protected: + nsIRDFResource** mResources; + int32_t mCount; + int32_t mCapacity; + +public: + class ConstIterator { + protected: + nsIRDFResource** mCurrent; + + public: + ConstIterator() : mCurrent(nullptr) {} + + ConstIterator(const ConstIterator& aConstIterator) + : mCurrent(aConstIterator.mCurrent) {} + + ConstIterator& operator=(const ConstIterator& aConstIterator) { + mCurrent = aConstIterator.mCurrent; + return *this; } + + ConstIterator& operator++() { + ++mCurrent; + return *this; } + + ConstIterator operator++(int) { + ConstIterator result(*this); + ++mCurrent; + return result; } + + /*const*/ nsIRDFResource* operator*() const { + return *mCurrent; } + + /*const*/ nsIRDFResource* operator->() const MOZ_NO_ADDREF_RELEASE_ON_RETURN { + return *mCurrent; } + + bool operator==(const ConstIterator& aConstIterator) const { + return mCurrent == aConstIterator.mCurrent; } + + bool operator!=(const ConstIterator& aConstIterator) const { + return mCurrent != aConstIterator.mCurrent; } + + protected: + explicit ConstIterator(nsIRDFResource** aProperty) : mCurrent(aProperty) {} + friend class nsResourceSet; + }; + + ConstIterator First() const { return ConstIterator(mResources); } + ConstIterator Last() const { return ConstIterator(mResources + mCount); } +}; + +#endif // nsResourceSet_h__ + diff --git a/dom/xul/templates/nsRuleNetwork.cpp b/dom/xul/templates/nsRuleNetwork.cpp new file mode 100644 index 000000000..c2cee5bbd --- /dev/null +++ b/dom/xul/templates/nsRuleNetwork.cpp @@ -0,0 +1,428 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* 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/. */ + +/* + + Implementations for the rule network classes. + + To Do. + + - Constrain() & Propagate() still feel like they are poorly named. + - As do Instantiation and InstantiationSet. + - Make InstantiationSet share and do copy-on-write. + - Make things iterative, instead of recursive. + + */ + +#include "nscore.h" +#include "nsCOMPtr.h" +#include "plhash.h" + +#include "mozilla/Logging.h" + +#include "nsString.h" +#include "nsUnicharUtils.h" +#include "nsXULContentUtils.h" + +#include "nsRuleNetwork.h" +#include "nsXULTemplateResultSetRDF.h" +#include "nsRDFConMemberTestNode.h" +#include "nsRDFPropertyTestNode.h" + +using namespace mozilla; +extern LazyLogModule gXULTemplateLog; + +//---------------------------------------------------------------------- +// +// nsRuleNetwork +// + +nsresult +MemoryElementSet::Add(MemoryElement* aElement) +{ + for (ConstIterator element = First(); element != Last(); ++element) { + if (*element == *aElement) { + // We've already got this element covered. Since Add() + // assumes ownership, and we aren't going to need this, + // just nuke it. + delete aElement; + return NS_OK; + } + } + + List* list = new List; + list->mElement = aElement; + list->mRefCnt = 1; + list->mNext = mElements; + + mElements = list; + + return NS_OK; +} + + +//---------------------------------------------------------------------- + +nsresult +nsAssignmentSet::Add(const nsAssignment& aAssignment) +{ + NS_PRECONDITION(! HasAssignmentFor(aAssignment.mVariable), "variable already bound"); + + // XXXndeakin should this just silently fail? + if (HasAssignmentFor(aAssignment.mVariable)) + return NS_ERROR_UNEXPECTED; + + List* list = new List(aAssignment); + list->mRefCnt = 1; + list->mNext = mAssignments; + + mAssignments = list; + + return NS_OK; +} + +int32_t +nsAssignmentSet::Count() const +{ + int32_t count = 0; + for (ConstIterator assignment = First(); assignment != Last(); ++assignment) + ++count; + + return count; +} + +bool +nsAssignmentSet::HasAssignment(nsIAtom* aVariable, nsIRDFNode* aValue) const +{ + for (ConstIterator assignment = First(); assignment != Last(); ++assignment) { + if (assignment->mVariable == aVariable && assignment->mValue == aValue) + return true; + } + + return false; +} + +bool +nsAssignmentSet::HasAssignmentFor(nsIAtom* aVariable) const +{ + for (ConstIterator assignment = First(); assignment != Last(); ++assignment) { + if (assignment->mVariable == aVariable) + return true; + } + + return false; +} + +bool +nsAssignmentSet::GetAssignmentFor(nsIAtom* aVariable, nsIRDFNode** aValue) const +{ + for (ConstIterator assignment = First(); assignment != Last(); ++assignment) { + if (assignment->mVariable == aVariable) { + *aValue = assignment->mValue; + NS_IF_ADDREF(*aValue); + return true; + } + } + + *aValue = nullptr; + return false; +} + +bool +nsAssignmentSet::Equals(const nsAssignmentSet& aSet) const +{ + if (aSet.mAssignments == mAssignments) + return true; + + // If they have a different number of assignments, then they're different. + if (Count() != aSet.Count()) + return false; + + // XXX O(n^2)! Ugh! + nsCOMPtr<nsIRDFNode> value; + for (ConstIterator assignment = First(); assignment != Last(); ++assignment) { + if (! aSet.GetAssignmentFor(assignment->mVariable, getter_AddRefs(value))) + return false; + + if (assignment->mValue != value) + return false; + } + + return true; +} + +//---------------------------------------------------------------------- + +PLHashNumber +Instantiation::Hash(const void* aKey) +{ + const Instantiation* inst = static_cast<const Instantiation*>(aKey); + + PLHashNumber result = 0; + + nsAssignmentSet::ConstIterator last = inst->mAssignments.Last(); + for (nsAssignmentSet::ConstIterator assignment = inst->mAssignments.First(); + assignment != last; ++assignment) + result ^= assignment->Hash(); + + return result; +} + + +int +Instantiation::Compare(const void* aLeft, const void* aRight) +{ + const Instantiation* left = static_cast<const Instantiation*>(aLeft); + const Instantiation* right = static_cast<const Instantiation*>(aRight); + + return *left == *right; +} + + +//---------------------------------------------------------------------- +// +// InstantiationSet +// + +InstantiationSet::InstantiationSet() +{ + mHead.mPrev = mHead.mNext = &mHead; + MOZ_COUNT_CTOR(InstantiationSet); +} + + +InstantiationSet::InstantiationSet(const InstantiationSet& aInstantiationSet) +{ + mHead.mPrev = mHead.mNext = &mHead; + + // XXX replace with copy-on-write foo + ConstIterator last = aInstantiationSet.Last(); + for (ConstIterator inst = aInstantiationSet.First(); inst != last; ++inst) + Append(*inst); + + MOZ_COUNT_CTOR(InstantiationSet); +} + +InstantiationSet& +InstantiationSet::operator=(const InstantiationSet& aInstantiationSet) +{ + // XXX replace with copy-on-write foo + Clear(); + + ConstIterator last = aInstantiationSet.Last(); + for (ConstIterator inst = aInstantiationSet.First(); inst != last; ++inst) + Append(*inst); + + return *this; +} + + +void +InstantiationSet::Clear() +{ + Iterator inst = First(); + while (inst != Last()) + Erase(inst++); +} + + +InstantiationSet::Iterator +InstantiationSet::Insert(Iterator aIterator, const Instantiation& aInstantiation) +{ + List* newelement = new List(); + if (newelement) { + newelement->mInstantiation = aInstantiation; + + aIterator.mCurrent->mPrev->mNext = newelement; + + newelement->mNext = aIterator.mCurrent; + newelement->mPrev = aIterator.mCurrent->mPrev; + + aIterator.mCurrent->mPrev = newelement; + } + return aIterator; +} + +InstantiationSet::Iterator +InstantiationSet::Erase(Iterator aIterator) +{ + Iterator result = aIterator; + ++result; + aIterator.mCurrent->mNext->mPrev = aIterator.mCurrent->mPrev; + aIterator.mCurrent->mPrev->mNext = aIterator.mCurrent->mNext; + delete aIterator.mCurrent; + return result; +} + + +bool +InstantiationSet::HasAssignmentFor(nsIAtom* aVariable) const +{ + return !Empty() ? First()->mAssignments.HasAssignmentFor(aVariable) : false; +} + +//---------------------------------------------------------------------- +// +// ReteNode +// +// The basic node in the network. +// + +//---------------------------------------------------------------------- +// +// TestNode +// +// to do: +// - FilterInstantiations() is poorly named +// + + +TestNode::TestNode(TestNode* aParent) + : mParent(aParent) +{ +} + +nsresult +TestNode::Propagate(InstantiationSet& aInstantiations, + bool aIsUpdate, bool& aTakenInstantiations) +{ + MOZ_LOG(gXULTemplateLog, LogLevel::Debug, + ("TestNode[%p]: Propagate() begin", this)); + + aTakenInstantiations = false; + + nsresult rv = FilterInstantiations(aInstantiations, nullptr); + if (NS_FAILED(rv)) + return rv; + + // if there is more than one child, each will need to be supplied with the + // original set of instantiations from this node, so create a copy in this + // case. If there is only one child, optimize and just pass the + // instantiations along to the child without copying + bool shouldCopy = (mKids.Count() > 1); + + // See the header file for details about how instantiation ownership works. + if (! aInstantiations.Empty()) { + ReteNodeSet::Iterator last = mKids.Last(); + for (ReteNodeSet::Iterator kid = mKids.First(); kid != last; ++kid) { + MOZ_LOG(gXULTemplateLog, LogLevel::Debug, + ("TestNode[%p]: Propagate() passing to child %p", this, kid.operator->())); + + // create a copy of the instantiations + if (shouldCopy) { + bool owned = false; + InstantiationSet* instantiations = + new InstantiationSet(aInstantiations); + rv = kid->Propagate(*instantiations, aIsUpdate, owned); + if (!owned) + delete instantiations; + if (NS_FAILED(rv)) + return rv; + } + else { + rv = kid->Propagate(aInstantiations, aIsUpdate, aTakenInstantiations); + if (NS_FAILED(rv)) + return rv; + } + } + } + + MOZ_LOG(gXULTemplateLog, LogLevel::Debug, + ("TestNode[%p]: Propagate() end", this)); + + return NS_OK; +} + + +nsresult +TestNode::Constrain(InstantiationSet& aInstantiations) +{ + nsresult rv; + + MOZ_LOG(gXULTemplateLog, LogLevel::Debug, + ("TestNode[%p]: Constrain() begin", this)); + + // if the cantHandleYet flag is set by FilterInstantiations, + // there isn't enough information yet available to fill in. + // For this, continue the constrain all the way to the top + // and then call FilterInstantiations again afterwards. This + // should fill in any missing information. + bool cantHandleYet = false; + rv = FilterInstantiations(aInstantiations, &cantHandleYet); + if (NS_FAILED(rv)) return rv; + + if (mParent && (!aInstantiations.Empty() || cantHandleYet)) { + // if we still have instantiations, or if the instantiations + // could not be filled in yet, then ride 'em on up to the + // parent to narrow them. + + MOZ_LOG(gXULTemplateLog, LogLevel::Debug, + ("TestNode[%p]: Constrain() passing to parent %p", this, mParent)); + + rv = mParent->Constrain(aInstantiations); + + if (NS_SUCCEEDED(rv) && cantHandleYet) + rv = FilterInstantiations(aInstantiations, nullptr); + } + else { + MOZ_LOG(gXULTemplateLog, LogLevel::Debug, + ("TestNode[%p]: Constrain() failed", this)); + + rv = NS_OK; + } + + MOZ_LOG(gXULTemplateLog, LogLevel::Debug, + ("TestNode[%p]: Constrain() end", this)); + + return rv; +} + + +//---------------------------------------------------------------------- + +ReteNodeSet::ReteNodeSet() + : mNodes(nullptr), mCount(0), mCapacity(0) +{ +} + +ReteNodeSet::~ReteNodeSet() +{ + Clear(); +} + +nsresult +ReteNodeSet::Add(ReteNode* aNode) +{ + NS_PRECONDITION(aNode != nullptr, "null ptr"); + if (! aNode) + return NS_ERROR_NULL_POINTER; + + if (mCount >= mCapacity) { + int32_t capacity = mCapacity + 4; + ReteNode** nodes = new ReteNode*[capacity]; + if (! nodes) + return NS_ERROR_OUT_OF_MEMORY; + + for (int32_t i = mCount - 1; i >= 0; --i) + nodes[i] = mNodes[i]; + + delete[] mNodes; + + mNodes = nodes; + mCapacity = capacity; + } + + mNodes[mCount++] = aNode; + return NS_OK; +} + +nsresult +ReteNodeSet::Clear() +{ + delete[] mNodes; + mNodes = nullptr; + mCount = mCapacity = 0; + return NS_OK; +} diff --git a/dom/xul/templates/nsRuleNetwork.h b/dom/xul/templates/nsRuleNetwork.h new file mode 100644 index 000000000..2b4402722 --- /dev/null +++ b/dom/xul/templates/nsRuleNetwork.h @@ -0,0 +1,861 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* 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/. */ + +/* + + A rule discrimination network implementation based on ideas from + RETE and TREAT. + + RETE is described in Charles Forgy, "Rete: A Fast Algorithm for the + Many Patterns/Many Objects Match Problem", Artificial Intelligence + 19(1): pp. 17-37, 1982. + + TREAT is described in Daniel P. Miranker, "TREAT: A Better Match + Algorithm for AI Production System Matching", AAAI 1987: pp. 42-47. + + -- + + TO DO: + + . nsAssignmentSet::List objects are allocated by the gallon. We + should make it so that these are always allocated from a pool, + maybe owned by the nsRuleNetwork? + + */ + +#ifndef nsRuleNetwork_h__ +#define nsRuleNetwork_h__ + +#include "mozilla/Attributes.h" +#include "nsCOMPtr.h" +#include "nsCOMArray.h" +#include "nsIAtom.h" +#include "nsIDOMNode.h" +#include "plhash.h" +#include "PLDHashTable.h" +#include "nsIRDFNode.h" + +class nsXULTemplateResultSetRDF; + +//---------------------------------------------------------------------- + +/** + * A memory element that supports an instantiation. A memory element holds a + * set of nodes involved in an RDF test such as <member> or <triple> test. A + * memory element is created when a specific test matches. The query processor + * maintains a map between the memory elements and the results they eventually + * matched. When an assertion is removed from the graph, this map is consulted + * to determine which results will no longer match. + */ +class MemoryElement { +protected: + MemoryElement() { MOZ_COUNT_CTOR(MemoryElement); } + +public: + virtual ~MemoryElement() { MOZ_COUNT_DTOR(MemoryElement); } + + virtual const char* Type() const = 0; + virtual PLHashNumber Hash() const = 0; + virtual bool Equals(const MemoryElement& aElement) const = 0; + + bool operator==(const MemoryElement& aMemoryElement) const { + return Equals(aMemoryElement); + } + + bool operator!=(const MemoryElement& aMemoryElement) const { + return !Equals(aMemoryElement); + } +}; + +//---------------------------------------------------------------------- + +/** + * A collection of memory elements + */ +class MemoryElementSet { +public: + class ConstIterator; + friend class ConstIterator; + +protected: + class List { + public: + List() { MOZ_COUNT_CTOR(MemoryElementSet::List); } + + protected: + ~List() { + MOZ_COUNT_DTOR(MemoryElementSet::List); + delete mElement; + NS_IF_RELEASE(mNext); } + + public: + int32_t AddRef() { return ++mRefCnt; } + + int32_t Release() { + int32_t refcnt = --mRefCnt; + if (refcnt == 0) delete this; + return refcnt; } + + MemoryElement* mElement; + int32_t mRefCnt; + List* mNext; + }; + + List* mElements; + +public: + MemoryElementSet() : mElements(nullptr) { + MOZ_COUNT_CTOR(MemoryElementSet); } + + MemoryElementSet(const MemoryElementSet& aSet) : mElements(aSet.mElements) { + MOZ_COUNT_CTOR(MemoryElementSet); + NS_IF_ADDREF(mElements); } + + MemoryElementSet& operator=(const MemoryElementSet& aSet) { + NS_IF_RELEASE(mElements); + mElements = aSet.mElements; + NS_IF_ADDREF(mElements); + return *this; } + + ~MemoryElementSet() { + MOZ_COUNT_DTOR(MemoryElementSet); + NS_IF_RELEASE(mElements); } + +public: + class ConstIterator { + public: + explicit ConstIterator(List* aElementList) : mCurrent(aElementList) { + NS_IF_ADDREF(mCurrent); } + + ConstIterator(const ConstIterator& aConstIterator) + : mCurrent(aConstIterator.mCurrent) { + NS_IF_ADDREF(mCurrent); } + + ConstIterator& operator=(const ConstIterator& aConstIterator) { + NS_IF_RELEASE(mCurrent); + mCurrent = aConstIterator.mCurrent; + NS_IF_ADDREF(mCurrent); + return *this; } + + ~ConstIterator() { NS_IF_RELEASE(mCurrent); } + + ConstIterator& operator++() { + List* next = mCurrent->mNext; + NS_RELEASE(mCurrent); + mCurrent = next; + NS_IF_ADDREF(mCurrent); + return *this; } + + ConstIterator operator++(int) { + ConstIterator result(*this); + List* next = mCurrent->mNext; + NS_RELEASE(mCurrent); + mCurrent = next; + NS_IF_ADDREF(mCurrent); + return result; } + + const MemoryElement& operator*() const { + return *mCurrent->mElement; } + + const MemoryElement* operator->() const { + return mCurrent->mElement; } + + bool operator==(const ConstIterator& aConstIterator) const { + return mCurrent == aConstIterator.mCurrent; } + + bool operator!=(const ConstIterator& aConstIterator) const { + return mCurrent != aConstIterator.mCurrent; } + + protected: + List* mCurrent; + }; + + ConstIterator First() const { return ConstIterator(mElements); } + ConstIterator Last() const { return ConstIterator(nullptr); } + + // N.B. that the set assumes ownership of the element + nsresult Add(MemoryElement* aElement); +}; + +//---------------------------------------------------------------------- + +/** + * An assignment of a value to a variable + */ +class nsAssignment { +public: + const nsCOMPtr<nsIAtom> mVariable; + nsCOMPtr<nsIRDFNode> mValue; + + nsAssignment(nsIAtom* aVariable, nsIRDFNode* aValue) + : mVariable(aVariable), + mValue(aValue) + { MOZ_COUNT_CTOR(nsAssignment); } + + nsAssignment(const nsAssignment& aAssignment) + : mVariable(aAssignment.mVariable), + mValue(aAssignment.mValue) + { MOZ_COUNT_CTOR(nsAssignment); } + + ~nsAssignment() { MOZ_COUNT_DTOR(nsAssignment); } + + bool operator==(const nsAssignment& aAssignment) const { + return mVariable == aAssignment.mVariable && mValue == aAssignment.mValue; } + + bool operator!=(const nsAssignment& aAssignment) const { + return mVariable != aAssignment.mVariable || mValue != aAssignment.mValue; } + + PLHashNumber Hash() const { + // XXX I have no idea if this hashing function is good or not // XXX change this + PLHashNumber temp = PLHashNumber(NS_PTR_TO_INT32(mValue.get())) >> 2; // strip alignment bits + return (temp & 0xffff) | NS_PTR_TO_INT32(mVariable.get()); } +}; + + +//---------------------------------------------------------------------- + +/** + * A collection of value-to-variable assignments that minimizes + * copying by sharing subsets when possible. + */ +class nsAssignmentSet { +public: + class ConstIterator; + friend class ConstIterator; + +protected: + class List { + public: + explicit List(const nsAssignment& aAssignment) : mAssignment(aAssignment) { + MOZ_COUNT_CTOR(nsAssignmentSet::List); } + + protected: + ~List() { + MOZ_COUNT_DTOR(nsAssignmentSet::List); + NS_IF_RELEASE(mNext); } + + public: + + int32_t AddRef() { return ++mRefCnt; } + + int32_t Release() { + int32_t refcnt = --mRefCnt; + if (refcnt == 0) delete this; + return refcnt; } + + nsAssignment mAssignment; + int32_t mRefCnt; + List* mNext; + }; + + List* mAssignments; + +public: + nsAssignmentSet() + : mAssignments(nullptr) + { MOZ_COUNT_CTOR(nsAssignmentSet); } + + nsAssignmentSet(const nsAssignmentSet& aSet) + : mAssignments(aSet.mAssignments) { + MOZ_COUNT_CTOR(nsAssignmentSet); + NS_IF_ADDREF(mAssignments); } + + nsAssignmentSet& operator=(const nsAssignmentSet& aSet) { + NS_IF_RELEASE(mAssignments); + mAssignments = aSet.mAssignments; + NS_IF_ADDREF(mAssignments); + return *this; } + + ~nsAssignmentSet() { + MOZ_COUNT_DTOR(nsAssignmentSet); + NS_IF_RELEASE(mAssignments); } + +public: + class ConstIterator { + public: + explicit ConstIterator(List* aAssignmentList) : mCurrent(aAssignmentList) { + NS_IF_ADDREF(mCurrent); } + + ConstIterator(const ConstIterator& aConstIterator) + : mCurrent(aConstIterator.mCurrent) { + NS_IF_ADDREF(mCurrent); } + + ConstIterator& operator=(const ConstIterator& aConstIterator) { + NS_IF_RELEASE(mCurrent); + mCurrent = aConstIterator.mCurrent; + NS_IF_ADDREF(mCurrent); + return *this; } + + ~ConstIterator() { NS_IF_RELEASE(mCurrent); } + + ConstIterator& operator++() { + List* next = mCurrent->mNext; + NS_RELEASE(mCurrent); + mCurrent = next; + NS_IF_ADDREF(mCurrent); + return *this; } + + ConstIterator operator++(int) { + ConstIterator result(*this); + List* next = mCurrent->mNext; + NS_RELEASE(mCurrent); + mCurrent = next; + NS_IF_ADDREF(mCurrent); + return result; } + + const nsAssignment& operator*() const { + return mCurrent->mAssignment; } + + const nsAssignment* operator->() const { + return &mCurrent->mAssignment; } + + bool operator==(const ConstIterator& aConstIterator) const { + return mCurrent == aConstIterator.mCurrent; } + + bool operator!=(const ConstIterator& aConstIterator) const { + return mCurrent != aConstIterator.mCurrent; } + + protected: + List* mCurrent; + }; + + ConstIterator First() const { return ConstIterator(mAssignments); } + ConstIterator Last() const { return ConstIterator(nullptr); } + +public: + /** + * Add an assignment to the set + * @param aElement the assigment to add + * @return NS_OK if all is well, NS_ERROR_OUT_OF_MEMORY if memory + * could not be allocated for the addition. + */ + nsresult Add(const nsAssignment& aElement); + + /** + * Determine if the assignment set contains the specified variable + * to value assignment. + * @param aVariable the variable for which to lookup the binding + * @param aValue the value to query + * @return true if aVariable is bound to aValue; false otherwise. + */ + bool HasAssignment(nsIAtom* aVariable, nsIRDFNode* aValue) const; + + /** + * Determine if the assignment set contains the specified assignment + * @param aAssignment the assignment to search for + * @return true if the set contains the assignment, false otherwise. + */ + bool HasAssignment(const nsAssignment& aAssignment) const { + return HasAssignment(aAssignment.mVariable, aAssignment.mValue); } + + /** + * Determine whether the assignment set has an assignment for the + * specified variable. + * @param aVariable the variable to query + * @return true if the assignment set has an assignment for the variable, + * false otherwise. + */ + bool HasAssignmentFor(nsIAtom* aVariable) const; + + /** + * Retrieve the assignment for the specified variable + * @param aVariable the variable to query + * @param aValue an out parameter that will receive the value assigned + * to the variable, if any. + * @return true if the variable has an assignment, false + * if there was no assignment for the variable. + */ + bool GetAssignmentFor(nsIAtom* aVariable, nsIRDFNode** aValue) const; + + /** + * Count the number of assignments in the set + * @return the number of assignments in the set + */ + int32_t Count() const; + + /** + * Determine if the set is empty + * @return true if the assignment set is empty, false otherwise. + */ + bool IsEmpty() const { return mAssignments == nullptr; } + + bool Equals(const nsAssignmentSet& aSet) const; + bool operator==(const nsAssignmentSet& aSet) const { return Equals(aSet); } + bool operator!=(const nsAssignmentSet& aSet) const { return !Equals(aSet); } +}; + + +//---------------------------------------------------------------------- + +/** + * A collection of variable-to-value bindings, with the memory elements + * that support those bindings. Essentially, an instantiation is the + * collection of variables and values assigned to those variables for a single + * result. For each RDF rule in the rule network, each instantiation is + * examined and either extended with additional bindings specified by the RDF + * rule, or removed if the rule doesn't apply (for instance if a node has no + * children). When an instantiation gets to the last node of the rule network, + * which is always an nsInstantiationNode, a result is created for it. + * + * An instantiation object is typically created by "extending" another + * instantiation object. That is, using the copy constructor, and + * adding bindings and support to the instantiation. + */ +class Instantiation +{ +public: + /** + * The variable-to-value bindings + */ + nsAssignmentSet mAssignments; + + /** + * The memory elements that support the bindings. + */ + MemoryElementSet mSupport; + + Instantiation() { MOZ_COUNT_CTOR(Instantiation); } + + Instantiation(const Instantiation& aInstantiation) + : mAssignments(aInstantiation.mAssignments), + mSupport(aInstantiation.mSupport) { + MOZ_COUNT_CTOR(Instantiation); } + + Instantiation& operator=(const Instantiation& aInstantiation) { + mAssignments = aInstantiation.mAssignments; + mSupport = aInstantiation.mSupport; + return *this; } + + ~Instantiation() { MOZ_COUNT_DTOR(Instantiation); } + + /** + * Add the specified variable-to-value assignment to the instantiation's + * set of assignments. + * @param aVariable the variable to which is being assigned + * @param aValue the value that is being assigned + * @return NS_OK if no errors, NS_ERROR_OUT_OF_MEMORY if there + * is not enough memory to perform the operation + */ + nsresult AddAssignment(nsIAtom* aVariable, nsIRDFNode* aValue) { + mAssignments.Add(nsAssignment(aVariable, aValue)); + return NS_OK; } + + /** + * Add a memory element to the set of memory elements that are + * supporting the instantiation + * @param aMemoryElement the memory element to add to the + * instantiation's set of support + * @return NS_OK if no errors occurred, NS_ERROR_OUT_OF_MEMORY + * if there is not enough memory to perform the operation. + */ + nsresult AddSupportingElement(MemoryElement* aMemoryElement) { + mSupport.Add(aMemoryElement); + return NS_OK; } + + bool Equals(const Instantiation& aInstantiation) const { + return mAssignments == aInstantiation.mAssignments; } + + bool operator==(const Instantiation& aInstantiation) const { + return Equals(aInstantiation); } + + bool operator!=(const Instantiation& aInstantiation) const { + return !Equals(aInstantiation); } + + static PLHashNumber Hash(const void* aKey); + static int Compare(const void* aLeft, const void* aRight); +}; + + +//---------------------------------------------------------------------- + +/** + * A collection of intantiations + */ +class InstantiationSet +{ +public: + InstantiationSet(); + InstantiationSet(const InstantiationSet& aInstantiationSet); + InstantiationSet& operator=(const InstantiationSet& aInstantiationSet); + + ~InstantiationSet() { + MOZ_COUNT_DTOR(InstantiationSet); + Clear(); } + + class ConstIterator; + friend class ConstIterator; + + class Iterator; + friend class Iterator; + + friend class nsXULTemplateResultSetRDF; // so it can get to the List + +protected: + class List { + public: + Instantiation mInstantiation; + List* mNext; + List* mPrev; + + List() { MOZ_COUNT_CTOR(InstantiationSet::List); } + ~List() { MOZ_COUNT_DTOR(InstantiationSet::List); } + }; + + List mHead; + +public: + class ConstIterator { + protected: + friend class Iterator; // XXXwaterson so broken. + List* mCurrent; + + public: + explicit ConstIterator(List* aList) : mCurrent(aList) {} + + ConstIterator(const ConstIterator& aConstIterator) + : mCurrent(aConstIterator.mCurrent) {} + + ConstIterator& operator=(const ConstIterator& aConstIterator) { + mCurrent = aConstIterator.mCurrent; + return *this; } + + ConstIterator& operator++() { + mCurrent = mCurrent->mNext; + return *this; } + + ConstIterator operator++(int) { + ConstIterator result(*this); + mCurrent = mCurrent->mNext; + return result; } + + ConstIterator& operator--() { + mCurrent = mCurrent->mPrev; + return *this; } + + ConstIterator operator--(int) { + ConstIterator result(*this); + mCurrent = mCurrent->mPrev; + return result; } + + const Instantiation& operator*() const { + return mCurrent->mInstantiation; } + + const Instantiation* operator->() const { + return &mCurrent->mInstantiation; } + + bool operator==(const ConstIterator& aConstIterator) const { + return mCurrent == aConstIterator.mCurrent; } + + bool operator!=(const ConstIterator& aConstIterator) const { + return mCurrent != aConstIterator.mCurrent; } + }; + + ConstIterator First() const { return ConstIterator(mHead.mNext); } + ConstIterator Last() const { return ConstIterator(const_cast<List*>(&mHead)); } + + class Iterator : public ConstIterator { + public: + explicit Iterator(List* aList) : ConstIterator(aList) {} + + Iterator& operator++() { + mCurrent = mCurrent->mNext; + return *this; } + + Iterator operator++(int) { + Iterator result(*this); + mCurrent = mCurrent->mNext; + return result; } + + Iterator& operator--() { + mCurrent = mCurrent->mPrev; + return *this; } + + Iterator operator--(int) { + Iterator result(*this); + mCurrent = mCurrent->mPrev; + return result; } + + Instantiation& operator*() const { + return mCurrent->mInstantiation; } + + Instantiation* operator->() const { + return &mCurrent->mInstantiation; } + + bool operator==(const ConstIterator& aConstIterator) const { + return mCurrent == aConstIterator.mCurrent; } + + bool operator!=(const ConstIterator& aConstIterator) const { + return mCurrent != aConstIterator.mCurrent; } + + friend class InstantiationSet; + }; + + Iterator First() { return Iterator(mHead.mNext); } + Iterator Last() { return Iterator(&mHead); } + + bool Empty() const { return First() == Last(); } + + Iterator Append(const Instantiation& aInstantiation) { + return Insert(Last(), aInstantiation); } + + Iterator Insert(Iterator aBefore, const Instantiation& aInstantiation); + + Iterator Erase(Iterator aElement); + + void Clear(); + + bool HasAssignmentFor(nsIAtom* aVariable) const; +}; + +//---------------------------------------------------------------------- + +/** + * A abstract base class for all nodes in the rule network + */ +class ReteNode +{ +public: + ReteNode() {} + virtual ~ReteNode() {} + + /** + * Propagate a set of instantiations "down" through the + * network. Each instantiation is a partial set of + * variable-to-value assignments, along with the memory elements + * that support it. + * + * The node must evaluate each instantiation, and either 1) + * extend it with additional assignments and memory-element + * support, or 2) remove it from the set because it is + * inconsistent with the constraints that this node applies. + * + * The node must then pass the resulting instantiation set along + * to any of its children in the network. (In other words, the + * node must recursively call Propagate() on its children. We + * should fix this to make the algorithm interruptable.) + * + * See TestNode::Propagate for details about instantiation set ownership + * + * @param aInstantiations the set of instantiations to propagate + * down through the network. + * @param aIsUpdate true if updating, false for first generation + * @param aTakenInstantiations true if the ownership over aInstantiations + * has been taken from the caller. If false, + * the caller owns it. + * @return NS_OK if no errors occurred. + */ + virtual nsresult Propagate(InstantiationSet& aInstantiations, + bool aIsUpdate, bool& aTakenInstantiations) = 0; +}; + +//---------------------------------------------------------------------- + +/** + * A collection of nodes in the rule network + */ +class ReteNodeSet +{ +public: + ReteNodeSet(); + ~ReteNodeSet(); + + nsresult Add(ReteNode* aNode); + nsresult Clear(); + + class Iterator; + + class ConstIterator { + public: + explicit ConstIterator(ReteNode** aNode) : mCurrent(aNode) {} + + ConstIterator(const ConstIterator& aConstIterator) + : mCurrent(aConstIterator.mCurrent) {} + + ConstIterator& operator=(const ConstIterator& aConstIterator) { + mCurrent = aConstIterator.mCurrent; + return *this; } + + ConstIterator& operator++() { + ++mCurrent; + return *this; } + + ConstIterator operator++(int) { + ConstIterator result(*this); + ++mCurrent; + return result; } + + const ReteNode* operator*() const { + return *mCurrent; } + + const ReteNode* operator->() const { + return *mCurrent; } + + bool operator==(const ConstIterator& aConstIterator) const { + return mCurrent == aConstIterator.mCurrent; } + + bool operator!=(const ConstIterator& aConstIterator) const { + return mCurrent != aConstIterator.mCurrent; } + + protected: + friend class Iterator; // XXXwaterson this is so wrong! + ReteNode** mCurrent; + }; + + ConstIterator First() const { return ConstIterator(mNodes); } + ConstIterator Last() const { return ConstIterator(mNodes + mCount); } + + class Iterator : public ConstIterator { + public: + explicit Iterator(ReteNode** aNode) : ConstIterator(aNode) {} + + Iterator& operator++() { + ++mCurrent; + return *this; } + + Iterator operator++(int) { + Iterator result(*this); + ++mCurrent; + return result; } + + ReteNode* operator*() const { + return *mCurrent; } + + ReteNode* operator->() const { + return *mCurrent; } + + bool operator==(const ConstIterator& aConstIterator) const { + return mCurrent == aConstIterator.mCurrent; } + + bool operator!=(const ConstIterator& aConstIterator) const { + return mCurrent != aConstIterator.mCurrent; } + }; + + Iterator First() { return Iterator(mNodes); } + Iterator Last() { return Iterator(mNodes + mCount); } + + int32_t Count() const { return mCount; } + +protected: + ReteNode** mNodes; + int32_t mCount; + int32_t mCapacity; +}; + +//---------------------------------------------------------------------- + +/** + * A node that applies a test condition to a set of instantiations. + * + * This class provides implementations of Propagate() and Constrain() + * in terms of one simple operation, FilterInstantiations(). A node + * that is a "simple test node" in a rule network should derive from + * this class, and need only implement FilterInstantiations(). + */ +class TestNode : public ReteNode +{ +public: + explicit TestNode(TestNode* aParent); + + /** + * Retrieve the test node's parent + * @return the test node's parent + */ + TestNode* GetParent() const { return mParent; } + + /** + * Calls FilterInstantiations() on the instantiation set, and if + * the resulting set isn't empty, propagates the new set down to + * each of the test node's children. + * + * Note that the caller of Propagate is responsible for deleting + * aInstantiations if necessary as described below. + * + * Propagate may be called in update or non-update mode as indicated + * by the aIsUpdate argument. Non-update mode is used when initially + * generating results, whereas update mode is used when the datasource + * changes and new results might be available. + * + * The last node in a chain of TestNodes is always an nsInstantiationNode. + * In non-update mode, this nsInstantiationNode will cache the results + * in the query using the SetCachedResults method. The query processor + * takes these cached results and creates a nsXULTemplateResultSetRDF + * which is the enumeration returned to the template builder. This + * nsXULTemplateResultSetRDF owns the instantiations and they will be + * deleted when the nsXULTemplateResultSetRDF goes away. + * + * In update mode, the nsInstantiationNode node will iterate over the + * instantiations itself and callback to the builder to update any matches + * and generated content. If no instantiations match, then the builder + * will never be called. + * + * Thus, the difference between update and non-update modes is that in + * update mode, the results and instantiations have been already handled + * whereas in non-update mode they are expected to be returned in an + * nsXULTemplateResultSetRDF for further processing by the builder. + * + * Regardless, aTakenInstantiations will be set to true if the + * ownership over aInstantiations has been transferred to a result set. + * If set to false, the caller is still responsible for aInstantiations. + * aTakenInstantiations will be set properly even if an error occurs. + */ + virtual nsresult Propagate(InstantiationSet& aInstantiations, + bool aIsUpdate, bool& aTakenInstantiations) override; + + /** + * This is called by a child node on its parent to allow the + * parent's constraints to apply to the set of instantiations. + * + * A node must iterate through the set of instantiations, and for + * each instantiation, either 1) extend the instantiation by + * adding variable-to-value assignments and memory element support + * for those assignments, or 2) remove the instantiation because + * it is inconsistent. + * + * The node must then pass the resulting set of instantiations up + * to its parent (by recursive call; we should make this iterative + * & interruptable at some point.) + * + * @param aInstantiations the set of instantiations that must + * be constrained + * @return NS_OK if no errors occurred + */ + virtual nsresult Constrain(InstantiationSet& aInstantiations); + + /** + * Given a set of instantiations, filter out any that are + * inconsistent with the test node's test, and append + * variable-to-value assignments and memory element support for + * those which do pass the test node's test. + * + * @param aInstantiations the set of instantiations to be + * filtered + * @param aCantHandleYet [out] true if the instantiations do not contain + * enough information to constrain the data. May be null if this + * isn't important to the caller. + * @return NS_OK if no errors occurred. + */ + virtual nsresult FilterInstantiations(InstantiationSet& aInstantiations, + bool* aCantHandleYet) const = 0; + //XXX probably better named "ApplyConstraints" or "Discrminiate" or something + + /** + * Add another node as a child of this node. + * @param aNode the node to add. + * @return NS_OK if no errors occur. + */ + nsresult AddChild(ReteNode* aNode) { return mKids.Add(aNode); } + + /** + * Remove all the children of this node + * @return NS_OK if no errors occur. + */ + nsresult RemoveAllChildren() { return mKids.Clear(); } + +protected: + TestNode* mParent; + ReteNodeSet mKids; +}; + +#endif // nsRuleNetwork_h__ diff --git a/dom/xul/templates/nsTemplateMap.h b/dom/xul/templates/nsTemplateMap.h new file mode 100644 index 000000000..cb828b093 --- /dev/null +++ b/dom/xul/templates/nsTemplateMap.h @@ -0,0 +1,64 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* 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/. */ + +#ifndef nsTemplateMap_h__ +#define nsTemplateMap_h__ + +#include "PLDHashTable.h" +#include "nsXULElement.h" + +class nsTemplateMap { +protected: + struct Entry : public PLDHashEntryHdr { + nsIContent* mContent; + nsIContent* mTemplate; + }; + + PLDHashTable mTable; + +public: + nsTemplateMap() : mTable(PLDHashTable::StubOps(), sizeof(Entry)) { } + + ~nsTemplateMap() { } + + void + Put(nsIContent* aContent, nsIContent* aTemplate) { + NS_ASSERTION(!mTable.Search(aContent), "aContent already in map"); + + auto entry = static_cast<Entry*>(mTable.Add(aContent, fallible)); + + if (entry) { + entry->mContent = aContent; + entry->mTemplate = aTemplate; + } + } + + void + Remove(nsIContent* aContent) { + mTable.Remove(aContent); + + for (nsIContent* child = aContent->GetFirstChild(); + child; + child = child->GetNextSibling()) { + Remove(child); + } + } + + + void + GetTemplateFor(nsIContent* aContent, nsIContent** aResult) { + auto entry = static_cast<Entry*>(mTable.Search(aContent)); + if (entry) + NS_IF_ADDREF(*aResult = entry->mTemplate); + else + *aResult = nullptr; + } + + void + Clear() { mTable.Clear(); } +}; + +#endif // nsTemplateMap_h__ + diff --git a/dom/xul/templates/nsTemplateMatch.cpp b/dom/xul/templates/nsTemplateMatch.cpp new file mode 100644 index 000000000..1ba1c9d87 --- /dev/null +++ b/dom/xul/templates/nsTemplateMatch.cpp @@ -0,0 +1,35 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* 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 "nsTemplateMatch.h" +#include "nsTemplateRule.h" + +// static +void +nsTemplateMatch::Destroy(nsTemplateMatch*& aMatch, bool aRemoveResult) +{ + if (aRemoveResult && aMatch->mResult) + aMatch->mResult->HasBeenRemoved(); + ::delete aMatch; + aMatch = nullptr; +} + +nsresult +nsTemplateMatch::RuleMatched(nsTemplateQuerySet* aQuerySet, + nsTemplateRule* aRule, + int16_t aRuleIndex, + nsIXULTemplateResult* aResult) +{ + // assign the rule index, used to indicate that a match is active, and + // so the tree builder can get the right action body to generate + mRuleIndex = aRuleIndex; + + nsCOMPtr<nsIDOMNode> rulenode; + aRule->GetRuleNode(getter_AddRefs(rulenode)); + if (rulenode) + return aResult->RuleMatched(aQuerySet->mCompiledQuery, rulenode); + + return NS_OK; +} diff --git a/dom/xul/templates/nsTemplateMatch.h b/dom/xul/templates/nsTemplateMatch.h new file mode 100644 index 000000000..ded2fe1ab --- /dev/null +++ b/dom/xul/templates/nsTemplateMatch.h @@ -0,0 +1,139 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* 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/. */ + +#ifndef nsTemplateMatch_h__ +#define nsTemplateMatch_h__ + +#include "mozilla/Attributes.h" +#include "nsIContent.h" +#include "nsIXULTemplateQueryProcessor.h" +#include "nsIXULTemplateResult.h" +#include "nsRuleNetwork.h" + +/** + * A match object, where each match object is associated with one result. + * There will be one match list for each unique id generated. However, since + * there are multiple querysets and each may generate results with the same + * id, they are all chained together in a linked list, ordered in the same + * order as the respective <queryset> elements they were generated from. + * A match can be identified by the container and id. The id is retrievable + * from the result. + * + * Only one match per container and id pair is active at a time, but which + * match is active may change as new results are added or removed. When a + * match is active, content is generated for that match. + * + * Matches are stored and owned by the mMatchToMap hash in the template + * builder. + */ + +class nsTemplateRule; +class nsTemplateQuerySet; + +class nsTemplateMatch { +private: + // Hide so that only Create() and Destroy() can be used to + // allocate and deallocate from the heap + void* operator new(size_t) CPP_THROW_NEW { MOZ_ASSERT(0); return nullptr; } + void operator delete(void*, size_t) { MOZ_ASSERT(0); } + +public: + nsTemplateMatch(uint16_t aQuerySetPriority, + nsIXULTemplateResult* aResult, + nsIContent* aContainer) + : mRuleIndex(-1), + mQuerySetPriority(aQuerySetPriority), + mContainer(aContainer), + mResult(aResult), + mNext(nullptr) + { + MOZ_COUNT_CTOR(nsTemplateMatch); + } + + ~nsTemplateMatch() + { + MOZ_COUNT_DTOR(nsTemplateMatch); + } + + static nsTemplateMatch* + Create(uint16_t aQuerySetPriority, + nsIXULTemplateResult* aResult, + nsIContent* aContainer) { + return ::new nsTemplateMatch(aQuerySetPriority, aResult, aContainer); + } + + static void Destroy(nsTemplateMatch*& aMatch, bool aRemoveResult); + + // return true if the the match is active, and has generated output + bool IsActive() { + return mRuleIndex >= 0; + } + + // indicate that a rule is no longer active, used when a query with a + // lower priority has overriden the match + void SetInactive() { + mRuleIndex = -1; + } + + // return matching rule index + int16_t RuleIndex() { + return mRuleIndex; + } + + // return priority of query set + uint16_t QuerySetPriority() { + return mQuerySetPriority; + } + + // return container, not addrefed. May be null. + nsIContent* GetContainer() { + return mContainer; + } + + nsresult RuleMatched(nsTemplateQuerySet* aQuerySet, + nsTemplateRule* aRule, + int16_t aRuleIndex, + nsIXULTemplateResult* aResult); + +private: + + /** + * The index of the rule that matched, or -1 if the match is not active. + */ + int16_t mRuleIndex; + + /** + * The priority of the queryset for this rule + */ + uint16_t mQuerySetPriority; + + /** + * The container the content generated for the match is inside. + */ + nsCOMPtr<nsIContent> mContainer; + +public: + + /** + * The result associated with this match + */ + nsCOMPtr<nsIXULTemplateResult> mResult; + + /** + * Matches are stored in a linked list, in priority order. This first + * match that has a rule set (mRule) is the active match and generates + * content. The next match is owned by the builder, which will delete + * template matches when needed. + */ + nsTemplateMatch *mNext; + +private: + + nsTemplateMatch(const nsTemplateMatch& aMatch) = delete; + void operator=(const nsTemplateMatch& aMatch) = delete; +}; + +#endif // nsTemplateMatch_h__ + diff --git a/dom/xul/templates/nsTemplateRule.cpp b/dom/xul/templates/nsTemplateRule.cpp new file mode 100644 index 000000000..6d82740e3 --- /dev/null +++ b/dom/xul/templates/nsTemplateRule.cpp @@ -0,0 +1,422 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* 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 "nsTemplateRule.h" +#include "nsTemplateMatch.h" +#include "nsXULContentUtils.h" +#include "nsUnicharUtils.h" +#include "nsReadableUtils.h" +#include "nsICollation.h" + +nsTemplateCondition::nsTemplateCondition(nsIAtom* aSourceVariable, + const nsAString& aRelation, + nsIAtom* aTargetVariable, + bool aIgnoreCase, + bool aNegate) + : mSourceVariable(aSourceVariable), + mTargetVariable(aTargetVariable), + mIgnoreCase(aIgnoreCase), + mNegate(aNegate), + mNext(nullptr) +{ + SetRelation(aRelation); + + MOZ_COUNT_CTOR(nsTemplateCondition); +} + +nsTemplateCondition::nsTemplateCondition(nsIAtom* aSourceVariable, + const nsAString& aRelation, + const nsAString& aTargets, + bool aIgnoreCase, + bool aNegate, + bool aIsMultiple) + : mSourceVariable(aSourceVariable), + mIgnoreCase(aIgnoreCase), + mNegate(aNegate), + mNext(nullptr) +{ + SetRelation(aRelation); + + if (aIsMultiple) { + int32_t start = 0, end = 0; + while ((end = aTargets.FindChar(',',start)) >= 0) { + if (end > start) { + mTargetList.AppendElement(Substring(aTargets, start, end - start)); + } + start = end + 1; + } + if (start < int32_t(aTargets.Length())) { + mTargetList.AppendElement(Substring(aTargets, start)); + } + } + else { + mTargetList.AppendElement(aTargets); + } + + MOZ_COUNT_CTOR(nsTemplateCondition); +} + +nsTemplateCondition::nsTemplateCondition(const nsAString& aSource, + const nsAString& aRelation, + nsIAtom* aTargetVariable, + bool aIgnoreCase, + bool aNegate) + : mSource(aSource), + mTargetVariable(aTargetVariable), + mIgnoreCase(aIgnoreCase), + mNegate(aNegate), + mNext(nullptr) +{ + SetRelation(aRelation); + + MOZ_COUNT_CTOR(nsTemplateCondition); +} + +void +nsTemplateCondition::SetRelation(const nsAString& aRelation) +{ + if (aRelation.EqualsLiteral("equals") || aRelation.IsEmpty()) + mRelation = eEquals; + else if (aRelation.EqualsLiteral("less")) + mRelation = eLess; + else if (aRelation.EqualsLiteral("greater")) + mRelation = eGreater; + else if (aRelation.EqualsLiteral("before")) + mRelation = eBefore; + else if (aRelation.EqualsLiteral("after")) + mRelation = eAfter; + else if (aRelation.EqualsLiteral("startswith")) + mRelation = eStartswith; + else if (aRelation.EqualsLiteral("endswith")) + mRelation = eEndswith; + else if (aRelation.EqualsLiteral("contains")) + mRelation = eContains; + else + mRelation = eUnknown; +} + +bool +nsTemplateCondition::CheckMatch(nsIXULTemplateResult* aResult) +{ + bool match = false; + + nsAutoString leftString; + if (mSourceVariable) + aResult->GetBindingFor(mSourceVariable, leftString); + else + leftString.Assign(mSource); + + if (mTargetVariable) { + nsAutoString rightString; + aResult->GetBindingFor(mTargetVariable, rightString); + + match = CheckMatchStrings(leftString, rightString); + } + else { + // iterate over the strings in the target and determine + // whether there is a match. + uint32_t length = mTargetList.Length(); + for (uint32_t t = 0; t < length; t++) { + match = CheckMatchStrings(leftString, mTargetList[t]); + + // stop once a match is found. In negate mode, stop once a + // target does not match. + if (match != mNegate) break; + } + } + + return match; +} + + +bool +nsTemplateCondition::CheckMatchStrings(const nsAString& aLeftString, + const nsAString& aRightString) +{ + bool match = false; + + if (aRightString.IsEmpty()) { + if ((mRelation == eEquals) && aLeftString.IsEmpty()) + match = true; + } + else { + switch (mRelation) { + case eEquals: + if (mIgnoreCase) + match = aLeftString.Equals(aRightString, + nsCaseInsensitiveStringComparator()); + else + match = aLeftString.Equals(aRightString); + break; + + case eLess: + case eGreater: + { + // non-numbers always compare false + nsresult err; + int32_t leftint = PromiseFlatString(aLeftString).ToInteger(&err); + if (NS_SUCCEEDED(err)) { + int32_t rightint = PromiseFlatString(aRightString).ToInteger(&err); + if (NS_SUCCEEDED(err)) { + match = (mRelation == eLess) ? (leftint < rightint) : + (leftint > rightint); + } + } + + break; + } + + case eBefore: + { + nsICollation* collation = nsXULContentUtils::GetCollation(); + if (collation) { + int32_t sortOrder; + collation->CompareString((mIgnoreCase ? + static_cast<int32_t>(nsICollation::kCollationCaseInSensitive) : + static_cast<int32_t>(nsICollation::kCollationCaseSensitive)), + aLeftString, + aRightString, + &sortOrder); + match = (sortOrder < 0); + } + else if (mIgnoreCase) { + match = (Compare(aLeftString, aRightString, + nsCaseInsensitiveStringComparator()) < 0); + } + else { + match = (Compare(aLeftString, aRightString) < 0); + } + break; + } + + case eAfter: + { + nsICollation* collation = nsXULContentUtils::GetCollation(); + if (collation) { + int32_t sortOrder; + collation->CompareString((mIgnoreCase ? + static_cast<int32_t>(nsICollation::kCollationCaseInSensitive) : + static_cast<int32_t>(nsICollation::kCollationCaseSensitive)), + aLeftString, + aRightString, + &sortOrder); + match = (sortOrder > 0); + } + else if (mIgnoreCase) { + match = (Compare(aLeftString, aRightString, + nsCaseInsensitiveStringComparator()) > 0); + } + else { + match = (Compare(aLeftString, aRightString) > 0); + } + break; + } + + case eStartswith: + if (mIgnoreCase) + match = (StringBeginsWith(aLeftString, aRightString, + nsCaseInsensitiveStringComparator())); + else + match = (StringBeginsWith(aLeftString, aRightString)); + break; + + case eEndswith: + if (mIgnoreCase) + match = (StringEndsWith(aLeftString, aRightString, + nsCaseInsensitiveStringComparator())); + else + match = (StringEndsWith(aLeftString, aRightString)); + break; + + case eContains: + { + nsAString::const_iterator start, end; + aLeftString.BeginReading(start); + aLeftString.EndReading(end); + if (mIgnoreCase) + match = CaseInsensitiveFindInReadable(aRightString, start, end); + else + match = FindInReadable(aRightString, start, end); + break; + } + + default: + break; + } + } + + if (mNegate) match = !match; + + return match; +} + +nsTemplateRule::nsTemplateRule(nsIContent* aRuleNode, + nsIContent* aAction, + nsTemplateQuerySet* aQuerySet) + : mQuerySet(aQuerySet), + mAction(aAction), + mBindings(nullptr), + mConditions(nullptr) +{ + MOZ_COUNT_CTOR(nsTemplateRule); + mRuleNode = do_QueryInterface(aRuleNode); +} + +nsTemplateRule::nsTemplateRule(const nsTemplateRule& aOtherRule) + : mQuerySet(aOtherRule.mQuerySet), + mRuleNode(aOtherRule.mRuleNode), + mAction(aOtherRule.mAction), + mBindings(nullptr), + mConditions(nullptr) +{ + MOZ_COUNT_CTOR(nsTemplateRule); +} + +nsTemplateRule::~nsTemplateRule() +{ + MOZ_COUNT_DTOR(nsTemplateRule); + + while (mBindings) { + Binding* doomed = mBindings; + mBindings = mBindings->mNext; + delete doomed; + } + + while (mConditions) { + nsTemplateCondition* cdel = mConditions; + mConditions = mConditions->GetNext(); + delete cdel; + } +} + +nsresult +nsTemplateRule::GetRuleNode(nsIDOMNode** aRuleNode) const +{ + *aRuleNode = mRuleNode; + NS_IF_ADDREF(*aRuleNode); + return NS_OK; +} + +void nsTemplateRule::SetCondition(nsTemplateCondition* aCondition) +{ + while (mConditions) { + nsTemplateCondition* cdel = mConditions; + mConditions = mConditions->GetNext(); + delete cdel; + } + + mConditions = aCondition; +} + +bool +nsTemplateRule::CheckMatch(nsIXULTemplateResult* aResult) const +{ + // check the conditions in the rule first + nsTemplateCondition* condition = mConditions; + while (condition) { + if (!condition->CheckMatch(aResult)) + return false; + + condition = condition->GetNext(); + } + + if (mRuleFilter) { + // if a rule filter was set, check it for a match. If an error occurs, + // assume that the match was acceptable + bool match; + nsresult rv = mRuleFilter->Match(aResult, mRuleNode, &match); + return NS_FAILED(rv) || match; + } + + return true; +} + +bool +nsTemplateRule::HasBinding(nsIAtom* aSourceVariable, + nsAString& aExpr, + nsIAtom* aTargetVariable) const +{ + for (Binding* binding = mBindings; binding != nullptr; binding = binding->mNext) { + if ((binding->mSourceVariable == aSourceVariable) && + (binding->mExpr.Equals(aExpr)) && + (binding->mTargetVariable == aTargetVariable)) + return true; + } + + return false; +} + +nsresult +nsTemplateRule::AddBinding(nsIAtom* aSourceVariable, + nsAString& aExpr, + nsIAtom* aTargetVariable) +{ + NS_PRECONDITION(aSourceVariable != 0, "no source variable!"); + if (! aSourceVariable) + return NS_ERROR_INVALID_ARG; + + NS_PRECONDITION(aTargetVariable != 0, "no target variable!"); + if (! aTargetVariable) + return NS_ERROR_INVALID_ARG; + + NS_ASSERTION(! HasBinding(aSourceVariable, aExpr, aTargetVariable), + "binding added twice"); + + Binding* newbinding = new Binding; + if (! newbinding) + return NS_ERROR_OUT_OF_MEMORY; + + newbinding->mSourceVariable = aSourceVariable; + newbinding->mTargetVariable = aTargetVariable; + newbinding->mParent = nullptr; + + newbinding->mExpr.Assign(aExpr); + + Binding* binding = mBindings; + Binding** link = &mBindings; + + // Insert it at the end, unless we detect that an existing + // binding's source is dependent on the newbinding's target. + // + // XXXwaterson this isn't enough to make sure that we get all of + // the dependencies worked out right, but it'll do for now. For + // example, if you have (ab, bc, cd), and insert them in the order + // (cd, ab, bc), you'll get (bc, cd, ab). The good news is, if the + // person uses a natural ordering when writing the XUL, it'll all + // work out ok. + while (binding) { + if (binding->mSourceVariable == newbinding->mTargetVariable) { + binding->mParent = newbinding; + break; + } + else if (binding->mTargetVariable == newbinding->mSourceVariable) { + newbinding->mParent = binding; + } + + link = &binding->mNext; + binding = binding->mNext; + } + + // Insert the newbinding + *link = newbinding; + newbinding->mNext = binding; + return NS_OK; +} + +nsresult +nsTemplateRule::AddBindingsToQueryProcessor(nsIXULTemplateQueryProcessor* aProcessor) +{ + Binding* binding = mBindings; + + while (binding) { + nsresult rv = aProcessor->AddBinding(mRuleNode, binding->mTargetVariable, + binding->mSourceVariable, binding->mExpr); + if (NS_FAILED(rv)) return rv; + + binding = binding->mNext; + } + + return NS_OK; +} diff --git a/dom/xul/templates/nsTemplateRule.h b/dom/xul/templates/nsTemplateRule.h new file mode 100644 index 000000000..d7821ba29 --- /dev/null +++ b/dom/xul/templates/nsTemplateRule.h @@ -0,0 +1,328 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* 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/. */ + +#ifndef nsTemplateRule_h__ +#define nsTemplateRule_h__ + +#include "nsCOMPtr.h" +#include "nsIAtom.h" +#include "nsIRDFDataSource.h" +#include "nsIRDFResource.h" +#include "nsIContent.h" +#include "nsIDOMNode.h" +#include "nsTArray.h" +#include "nsString.h" +#include "nsIXULTemplateRuleFilter.h" +#include "nsCycleCollectionParticipant.h" + +class nsIXULTemplateQueryProcessor; +class nsTemplateQuerySet; + +class nsTemplateCondition +{ +public: + // relations that may be used in a rule. They may be negated with the + // negate flag. Less and Greater are used for numeric comparisons and + // Before and After are used for string comparisons. For Less, Greater, + // Before, After, Startswith, Endswith, and Contains, the source is + // conceptually on the left of the relation and the target is on the + // right. For example, if the relation is Contains, that means Match if + // the source contains the target. + enum ConditionRelation { + eUnknown, + eEquals, + eLess, + eGreater, + eBefore, + eAfter, + eStartswith, + eEndswith, + eContains + }; + + nsTemplateCondition(nsIAtom* aSourceVariable, + const nsAString& aRelation, + nsIAtom* aTargetVariable, + bool mIgnoreCase, + bool mNegate); + + nsTemplateCondition(nsIAtom* aSourceVariable, + const nsAString& aRelation, + const nsAString& aTargets, + bool mIgnoreCase, + bool mNegate, + bool aIsMultiple); + + nsTemplateCondition(const nsAString& aSource, + const nsAString& aRelation, + nsIAtom* aTargetVariable, + bool mIgnoreCase, + bool mNegate); + + ~nsTemplateCondition() { MOZ_COUNT_DTOR(nsTemplateCondition); } + + nsTemplateCondition* GetNext() { return mNext; } + void SetNext(nsTemplateCondition* aNext) { mNext = aNext; } + + void SetRelation(const nsAString& aRelation); + + bool + CheckMatch(nsIXULTemplateResult* aResult); + + bool + CheckMatchStrings(const nsAString& aLeftString, + const nsAString& aRightString); +protected: + + nsCOMPtr<nsIAtom> mSourceVariable; + nsString mSource; + ConditionRelation mRelation; + nsCOMPtr<nsIAtom> mTargetVariable; + nsTArray<nsString> mTargetList; + bool mIgnoreCase; + bool mNegate; + + nsTemplateCondition* mNext; +}; + +/** + * A rule consists of: + * + * - Conditions, a set of unbound variables with consistency + * constraints that specify the values that each variable can + * assume. The conditions must be completely and consistently + * "bound" for the rule to be considered "matched". + * + * - Bindings, a set of unbound variables with consistency constraints + * that specify the values that each variable can assume. Unlike the + * conditions, the bindings need not be bound for the rule to be + * considered matched. + * + * - Content that should be constructed when the rule is "activated". + * + */ +class nsTemplateRule +{ +public: + nsTemplateRule(nsIContent* aRuleNode, + nsIContent* aAction, + nsTemplateQuerySet* aQuerySet); + /** + * The copy-constructor should only be called from nsTArray when appending + * a new rule, otherwise things break because the copy constructor expects + * mBindings and mConditions to be nullptr. + */ + nsTemplateRule(const nsTemplateRule& aOtherRule); + + ~nsTemplateRule(); + + /** + * Return the <action> node that this rule was constructed from, or its + * logical equivalent for shorthand syntaxes. That is, the parent node of + * the content that should be generated for this rule. + */ + nsIContent* GetAction() const { return mAction; } + + /** + * Return the <rule> content node that this rule was constructed from. + * @param aResult an out parameter, which will contain the rule node + * @return NS_OK if no errors occur. + */ + nsresult GetRuleNode(nsIDOMNode** aResult) const; + + void SetVars(nsIAtom* aRefVariable, nsIAtom* aMemberVariable) + { + mRefVariable = aRefVariable; + mMemberVariable = aMemberVariable; + } + + void SetRuleFilter(nsIXULTemplateRuleFilter* aRuleFilter) + { + mRuleFilter = aRuleFilter; + } + + nsIAtom* GetTag() { return mTag; } + void SetTag(nsIAtom* aTag) { mTag = aTag; } + + nsIAtom* GetMemberVariable() { return mMemberVariable; } + + /** + * Set the first condition for the rule. Other conditions are linked + * to it using the condition's SetNext method. + */ + void SetCondition(nsTemplateCondition* aConditions); + + /** + * Check if the result matches the rule by first looking at the conditions. + * If the results is accepted by the conditions, the rule filter, if any + * was set, is checked. If either check rejects a result, a match cannot + * occur for this rule and result. + */ + bool + CheckMatch(nsIXULTemplateResult* aResult) const; + + /** + * Determine if the rule has the specified binding + */ + bool + HasBinding(nsIAtom* aSourceVariable, + nsAString& aExpr, + nsIAtom* aTargetVariable) const; + + /** + * Add a binding to the rule. A binding consists of an already-bound + * source variable, and the RDF property that should be tested to + * generate a target value. The target value is bound to a target + * variable. + * + * @param aSourceVariable the source variable that will be used in + * the RDF query. + * @param aExpr the expression that will be used in the query. + * @param aTargetVariable the variable whose value will be bound + * to the RDF node that is returned when querying the binding + * @return NS_OK if no errors occur. + */ + nsresult AddBinding(nsIAtom* aSourceVariable, + nsAString& aExpr, + nsIAtom* aTargetVariable); + + /** + * Inform the query processor of the bindings that are set for a rule. + * This should be called after all the bindings for a rule are compiled. + */ + nsresult + AddBindingsToQueryProcessor(nsIXULTemplateQueryProcessor* aProcessor); + + void Traverse(nsCycleCollectionTraversalCallback &cb) const + { + cb.NoteXPCOMChild(mRuleNode); + cb.NoteXPCOMChild(mAction); + } + +protected: + + struct Binding { + nsCOMPtr<nsIAtom> mSourceVariable; + nsCOMPtr<nsIAtom> mTargetVariable; + nsString mExpr; + Binding* mNext; + Binding* mParent; + }; + + // backreference to the query set which owns this rule + nsTemplateQuerySet* mQuerySet; + + // the <rule> node, or the <template> node if there is no <rule> + nsCOMPtr<nsIDOMNode> mRuleNode; + + // the <action> node, or, if there is no <action>, the container node + // which contains the content to generate + nsCOMPtr<nsIContent> mAction; + + // the rule filter set by the builder's SetRuleFilter function + nsCOMPtr<nsIXULTemplateRuleFilter> mRuleFilter; + + // indicates that the rule will only match when generating content + // to be inserted into a container with this tag + nsCOMPtr<nsIAtom> mTag; + + // linked-list of the bindings for the rule, owned by the rule. + Binding* mBindings; + + nsCOMPtr<nsIAtom> mRefVariable; + nsCOMPtr<nsIAtom> mMemberVariable; + + nsTemplateCondition* mConditions; // owned by nsTemplateRule +}; + +/** nsTemplateQuerySet + * + * A single <queryset> which holds the query node and the rules for it. + * All builders have at least one queryset, which may be created with an + * explicit <queryset> tag or implied if the tag is not used. + * + * These queryset objects are created and owned by the builder in its + * mQuerySets array. + */ +class nsTemplateQuerySet +{ +protected: + nsTArray<nsTemplateRule> mRules; + + // a number which increments for each successive queryset. It is stored so + // it can be used as an optimization when updating results so that it is + // known where to insert them into a match. + int32_t mPriority; + +public: + + // <query> node + nsCOMPtr<nsIContent> mQueryNode; + + // compiled opaque query object returned by the query processor's + // CompileQuery call + nsCOMPtr<nsISupports> mCompiledQuery; + + // indicates that the query will only generate content to be inserted into + // a container with this tag + nsCOMPtr<nsIAtom> mTag; + + explicit nsTemplateQuerySet(int32_t aPriority) + : mPriority(aPriority) + { + MOZ_COUNT_CTOR(nsTemplateQuerySet); + } + + ~nsTemplateQuerySet() + { + MOZ_COUNT_DTOR(nsTemplateQuerySet); + } + + int32_t Priority() const + { + return mPriority; + } + + nsIAtom* GetTag() { return mTag; } + void SetTag(nsIAtom* aTag) { mTag = aTag; } + + nsTemplateRule* NewRule(nsIContent* aRuleNode, + nsIContent* aAction, + nsTemplateQuerySet* aQuerySet) + { + // nsTemplateMatch stores the index as a 16-bit value, + // so check to make sure for overflow + if (mRules.Length() == INT16_MAX) + return nullptr; + + return mRules.AppendElement(nsTemplateRule(aRuleNode, aAction, + aQuerySet)); + } + + void RemoveRule(nsTemplateRule *aRule) + { + mRules.RemoveElementAt(aRule - mRules.Elements()); + } + + int16_t RuleCount() const + { + return mRules.Length(); + } + + nsTemplateRule* GetRuleAt(int16_t aIndex) + { + if (uint32_t(aIndex) < mRules.Length()) { + return &mRules[aIndex]; + } + return nullptr; + } + + void Clear() + { + mRules.Clear(); + } +}; + +#endif // nsTemplateRule_h__ diff --git a/dom/xul/templates/nsTreeRows.cpp b/dom/xul/templates/nsTreeRows.cpp new file mode 100644 index 000000000..b77a97213 --- /dev/null +++ b/dom/xul/templates/nsTreeRows.cpp @@ -0,0 +1,482 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* 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 "nsString.h" +#include "nsTreeRows.h" +#include <algorithm> + +nsTreeRows::Subtree* +nsTreeRows::EnsureSubtreeFor(Subtree* aParent, + int32_t aChildIndex) +{ + Subtree* subtree = GetSubtreeFor(aParent, aChildIndex); + + if (! subtree) { + subtree = aParent->mRows[aChildIndex].mSubtree = new Subtree(aParent); + InvalidateCachedRow(); + } + + return subtree; +} + +nsTreeRows::Subtree* +nsTreeRows::GetSubtreeFor(const Subtree* aParent, + int32_t aChildIndex, + int32_t* aSubtreeSize) +{ + NS_PRECONDITION(aParent, "no parent"); + NS_PRECONDITION(aChildIndex >= 0, "bad child index"); + + Subtree* result = nullptr; + + if (aChildIndex < aParent->mCount) + result = aParent->mRows[aChildIndex].mSubtree; + + if (aSubtreeSize) + *aSubtreeSize = result ? result->mSubtreeSize : 0; + + return result; +} + +void +nsTreeRows::RemoveSubtreeFor(Subtree* aParent, int32_t aChildIndex) +{ + NS_PRECONDITION(aParent, "no parent"); + NS_PRECONDITION(aChildIndex >= 0 && aChildIndex < aParent->mCount, "bad child index"); + + Row& row = aParent->mRows[aChildIndex]; + + if (row.mSubtree) { + int32_t subtreeSize = row.mSubtree->GetSubtreeSize(); + + delete row.mSubtree; + row.mSubtree = nullptr; + + for (Subtree* subtree = aParent; subtree != nullptr; subtree = subtree->mParent) + subtree->mSubtreeSize -= subtreeSize; + } + + InvalidateCachedRow(); +} + +nsTreeRows::iterator +nsTreeRows::First() +{ + iterator result; + result.Append(&mRoot, 0); + result.SetRowIndex(0); + return result; +} + +nsTreeRows::iterator +nsTreeRows::Last() +{ + iterator result; + + // Build up a path along the rightmost edge of the tree + Subtree* current = &mRoot; + int32_t count = current->Count(); + do { + int32_t last = count - 1; + result.Append(current, last); + current = count ? GetSubtreeFor(current, last) : nullptr; + } while (current && ((count = current->Count()) != 0)); + + // Now, at the bottom rightmost leaf, advance us one off the end. + result.GetTop().mChildIndex++; + + // Our row index will be the size of the root subree, plus one. + result.SetRowIndex(mRoot.GetSubtreeSize() + 1); + + return result; +} + +nsTreeRows::iterator +nsTreeRows::operator[](int32_t aRow) +{ + // See if we're just lucky, and end up with something + // nearby. (This tends to happen a lot due to the way that we get + // asked for rows n' stuff.) + int32_t last = mLastRow.GetRowIndex(); + if (last != -1) { + if (aRow == last) + return mLastRow; + else if (last + 1 == aRow) + return ++mLastRow; + else if (last - 1 == aRow) + return --mLastRow; + } + + // Nope. Construct a path to the specified index. This is a little + // bit better than O(n), because we can skip over subtrees. (So it + // ends up being approximately linear in the subtree size, instead + // of the entire view size. But, most of the time, big views are + // flat. Oh well.) + iterator result; + Subtree* current = &mRoot; + + int32_t index = 0; + result.SetRowIndex(aRow); + + do { + int32_t subtreeSize; + Subtree* subtree = GetSubtreeFor(current, index, &subtreeSize); + + if (subtreeSize >= aRow) { + result.Append(current, index); + current = subtree; + index = 0; + --aRow; + } + else { + ++index; + aRow -= subtreeSize + 1; + } + } while (aRow >= 0); + + mLastRow = result; + return result; +} + +nsTreeRows::iterator +nsTreeRows::FindByResource(nsIRDFResource* aResource) +{ + // XXX Mmm, scan through the rows one-by-one... + iterator last = Last(); + iterator iter; + + nsresult rv; + nsAutoString resourceid; + bool stringmode = false; + + for (iter = First(); iter != last; ++iter) { + if (!stringmode) { + nsCOMPtr<nsIRDFResource> findres; + rv = iter->mMatch->mResult->GetResource(getter_AddRefs(findres)); + if (NS_FAILED(rv)) return last; + + if (findres == aResource) + break; + + if (! findres) { + const char *uri; + aResource->GetValueConst(&uri); + CopyUTF8toUTF16(uri, resourceid); + + // set stringmode and fall through + stringmode = true; + } + } + + // additional check because previous block could change stringmode + if (stringmode) { + nsAutoString findid; + rv = iter->mMatch->mResult->GetId(findid); + if (NS_FAILED(rv)) return last; + + if (resourceid.Equals(findid)) + break; + } + } + + return iter; +} + +nsTreeRows::iterator +nsTreeRows::Find(nsIXULTemplateResult *aResult) +{ + // XXX Mmm, scan through the rows one-by-one... + iterator last = Last(); + iterator iter; + + for (iter = First(); iter != last; ++iter) { + if (aResult == iter->mMatch->mResult) + break; + } + + return iter; +} + +void +nsTreeRows::Clear() +{ + mRoot.Clear(); + InvalidateCachedRow(); +} + +//---------------------------------------------------------------------- +// +// nsTreeRows::Subtree +// + +nsTreeRows::Subtree::~Subtree() +{ + Clear(); +} + +void +nsTreeRows::Subtree::Clear() +{ + for (int32_t i = mCount - 1; i >= 0; --i) + delete mRows[i].mSubtree; + + delete[] mRows; + + mRows = nullptr; + mCount = mCapacity = mSubtreeSize = 0; +} + +nsTreeRows::iterator +nsTreeRows::Subtree::InsertRowAt(nsTemplateMatch* aMatch, int32_t aIndex) +{ + if (mCount >= mCapacity || aIndex >= mCapacity) { + int32_t newCapacity = std::max(mCapacity * 2, aIndex + 1); + Row* newRows = new Row[newCapacity]; + if (! newRows) + return iterator(); + + for (int32_t i = mCount - 1; i >= 0; --i) + newRows[i] = mRows[i]; + + delete[] mRows; + + mRows = newRows; + mCapacity = newCapacity; + } + + for (int32_t i = mCount - 1; i >= aIndex; --i) + mRows[i + 1] = mRows[i]; + + mRows[aIndex].mMatch = aMatch; + mRows[aIndex].mContainerType = eContainerType_Unknown; + mRows[aIndex].mContainerState = eContainerState_Unknown; + mRows[aIndex].mContainerFill = eContainerFill_Unknown; + mRows[aIndex].mSubtree = nullptr; + ++mCount; + + // Now build an iterator that points to the newly inserted element. + int32_t rowIndex = 0; + iterator result; + result.Push(this, aIndex); + + for ( ; --aIndex >= 0; ++rowIndex) { + // Account for open subtrees in the absolute row index. + const Subtree *subtree = mRows[aIndex].mSubtree; + if (subtree) + rowIndex += subtree->mSubtreeSize; + } + + Subtree *subtree = this; + do { + // Note that the subtree's size has expanded. + ++subtree->mSubtreeSize; + + Subtree *parent = subtree->mParent; + if (! parent) + break; + + // Account for open subtrees in the absolute row index. + int32_t count = parent->Count(); + for (aIndex = 0; aIndex < count; ++aIndex, ++rowIndex) { + const Subtree *child = (*parent)[aIndex].mSubtree; + if (subtree == child) + break; + + if (child) + rowIndex += child->mSubtreeSize; + } + + NS_ASSERTION(aIndex < count, "couldn't find subtree in parent"); + + result.Push(parent, aIndex); + subtree = parent; + ++rowIndex; // One for the parent row. + } while (1); + + result.SetRowIndex(rowIndex); + return result; +} + +void +nsTreeRows::Subtree::RemoveRowAt(int32_t aIndex) +{ + NS_PRECONDITION(aIndex >= 0 && aIndex < Count(), "bad index"); + if (aIndex < 0 || aIndex >= Count()) + return; + + // How big is the subtree we're going to be removing? + int32_t subtreeSize = mRows[aIndex].mSubtree + ? mRows[aIndex].mSubtree->GetSubtreeSize() + : 0; + + ++subtreeSize; + + delete mRows[aIndex].mSubtree; + + for (int32_t i = aIndex + 1; i < mCount; ++i) + mRows[i - 1] = mRows[i]; + + --mCount; + + for (Subtree* subtree = this; subtree != nullptr; subtree = subtree->mParent) + subtree->mSubtreeSize -= subtreeSize; +} + +//---------------------------------------------------------------------- +// +// nsTreeRows::iterator +// + +nsTreeRows::iterator::iterator(const iterator& aIterator) + : mRowIndex(aIterator.mRowIndex), + mLink(aIterator.mLink) +{ +} + +nsTreeRows::iterator& +nsTreeRows::iterator::operator=(const iterator& aIterator) +{ + mRowIndex = aIterator.mRowIndex; + mLink = aIterator.mLink; + return *this; +} + +void +nsTreeRows::iterator::Append(Subtree* aParent, int32_t aChildIndex) +{ + Link *link = mLink.AppendElement(); + if (link) { + link->mParent = aParent; + link->mChildIndex = aChildIndex; + } + else + NS_ERROR("out of memory"); +} + +void +nsTreeRows::iterator::Push(Subtree *aParent, int32_t aChildIndex) +{ + Link *link = mLink.InsertElementAt(0); + if (link) { + link->mParent = aParent; + link->mChildIndex = aChildIndex; + } + else + NS_ERROR("out of memory"); +} + +bool +nsTreeRows::iterator::operator==(const iterator& aIterator) const +{ + if (GetDepth() != aIterator.GetDepth()) + return false; + + if (GetDepth() == 0) + return true; + + return GetTop() == aIterator.GetTop(); +} + +void +nsTreeRows::iterator::Next() +{ + NS_PRECONDITION(GetDepth() > 0, "cannot increment an uninitialized iterator"); + + // Increment the absolute row index + ++mRowIndex; + + Link& top = GetTop(); + + // Is there a child subtree? If so, descend into the child + // subtree. + Subtree* subtree = top.GetRow().mSubtree; + + if (subtree && subtree->Count()) { + Append(subtree, 0); + return; + } + + // Have we exhausted the current subtree? + if (top.mChildIndex >= top.mParent->Count() - 1) { + // Yep. See if we've just iterated path the last element in + // the tree, period. Walk back up the stack, looking for any + // unfinished subtrees. + int32_t unfinished; + for (unfinished = GetDepth() - 2; unfinished >= 0; --unfinished) { + const Link& link = mLink[unfinished]; + if (link.mChildIndex < link.mParent->Count() - 1) + break; + } + + // If there are no unfinished subtrees in the stack, then this + // iterator is exhausted. Leave it in the same state that + // Last() does. + if (unfinished < 0) { + top.mChildIndex++; + return; + } + + // Otherwise, we ran off the end of one of the inner + // subtrees. Pop up to the next unfinished level in the stack. + mLink.SetLength(unfinished + 1); + } + + // Advance to the next child in this subtree + ++(GetTop().mChildIndex); +} + +void +nsTreeRows::iterator::Prev() +{ + NS_PRECONDITION(GetDepth() > 0, "cannot increment an uninitialized iterator"); + + // Decrement the absolute row index + --mRowIndex; + + // Move to the previous child in this subtree + --(GetTop().mChildIndex); + + // Have we exhausted the current subtree? + if (GetTop().mChildIndex < 0) { + // Yep. See if we've just iterated back to the first element + // in the tree, period. Walk back up the stack, looking for + // any unfinished subtrees. + int32_t unfinished; + for (unfinished = GetDepth() - 2; unfinished >= 0; --unfinished) { + const Link& link = mLink[unfinished]; + if (link.mChildIndex >= 0) + break; + } + + // If there are no unfinished subtrees in the stack, then this + // iterator is exhausted. Leave it in the same state that + // First() does. + if (unfinished < 0) + return; + + // Otherwise, we ran off the end of one of the inner + // subtrees. Pop up to the next unfinished level in the stack. + mLink.SetLength(unfinished + 1); + return; + } + + // Is there a child subtree immediately prior to our current + // position? If so, descend into it, grovelling down to the + // deepest, rightmost left edge. + Subtree* parent = GetTop().GetParent(); + int32_t index = GetTop().GetChildIndex(); + + Subtree* subtree = (*parent)[index].mSubtree; + + if (subtree && subtree->Count()) { + do { + index = subtree->Count() - 1; + Append(subtree, index); + + parent = subtree; + subtree = (*parent)[index].mSubtree; + } while (subtree && subtree->Count()); + } +} diff --git a/dom/xul/templates/nsTreeRows.h b/dom/xul/templates/nsTreeRows.h new file mode 100644 index 000000000..801af0226 --- /dev/null +++ b/dom/xul/templates/nsTreeRows.h @@ -0,0 +1,437 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* 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/. */ + +#ifndef nsTreeRows_h__ +#define nsTreeRows_h__ + +#include "nsCOMPtr.h" +#include "nsTArray.h" +#include "PLDHashTable.h" +#include "nsIXULTemplateResult.h" +#include "nsTemplateMatch.h" +#include "nsIRDFResource.h" + + +/** + * This class maintains the state of the XUL tree builder's + * rows. It maps a row number to the nsTemplateMatch object that + * populates the row. + */ +class nsTreeRows +{ +public: + class iterator; + friend class iterator; + + enum Direction { eDirection_Forwards = +1, eDirection_Backwards = -1 }; + + enum ContainerType { + eContainerType_Unknown = 0, + eContainerType_Noncontainer = 1, + eContainerType_Container = 2 + }; + + enum ContainerState { + eContainerState_Unknown = 0, + eContainerState_Open = 1, + eContainerState_Closed = 2 + }; + + enum ContainerFill { + eContainerFill_Unknown = 0, + eContainerFill_Empty = 1, + eContainerFill_Nonempty = 2 + }; + + class Subtree; + + /** + * A row in the tree. Contains the match that the row + * corresponds to, and a pointer to the row's subtree, if there + * are any. + */ + struct Row { + nsTemplateMatch* mMatch; + ContainerType mContainerType : 4; + ContainerState mContainerState : 4; + ContainerFill mContainerFill : 4; + + Subtree* mSubtree; // XXX eventually move to hashtable + }; + + /** + * A subtree in the tree. A subtree contains rows, which may + * contain other subtrees. + */ + class Subtree { + protected: + friend class nsTreeRows; // so that it can access members, for now + + /** + * The parent subtree; null if we're the root + */ + Subtree* mParent; + + /** + * The number of immediate children in this subtree + */ + int32_t mCount; + + /** + * The capacity of the subtree + */ + int32_t mCapacity; + + /** + * The total number of rows in this subtree, recursively + * including child subtrees. + */ + int32_t mSubtreeSize; + + /** + * The array of rows in the subtree + */ + Row* mRows; + + public: + /** + * Creates a subtree with the specified parent. + */ + explicit Subtree(Subtree* aParent) + : mParent(aParent), + mCount(0), + mCapacity(0), + mSubtreeSize(0), + mRows(nullptr) {} + + ~Subtree(); + + /** + * Return the number of immediate child rows in the subtree + */ + int32_t Count() const { return mCount; } + + /** + * Return the number of rows in this subtree, as well as all + * the subtrees it contains. + */ + int32_t GetSubtreeSize() const { return mSubtreeSize; } + + /** + * Retrieve the immediate child row at the specified index. + */ + const Row& operator[](int32_t aIndex) const { + NS_PRECONDITION(aIndex >= 0 && aIndex < mCount, "bad index"); + return mRows[aIndex]; } + + /** + * Retrieve the immediate row at the specified index. + */ + Row& operator[](int32_t aIndex) { + NS_PRECONDITION(aIndex >= 0 && aIndex < mCount, "bad index"); + return mRows[aIndex]; } + + /** + * Remove all rows from the subtree. + */ + void Clear(); + + protected: + /** + * Insert an immediate child row at the specified index. + */ + iterator InsertRowAt(nsTemplateMatch* aMatch, int32_t aIndex); + + /** + * Remove an immediate child row from the specified index. + */ + void RemoveRowAt(int32_t aChildIndex); + }; + + friend class Subtree; + +protected: + /** + * A link in the path through the view's tree. + */ + struct Link { + Subtree* mParent; + int32_t mChildIndex; + + Link& + operator=(const Link& aLink) { + mParent = aLink.mParent; + mChildIndex = aLink.mChildIndex; + return *this; } + + bool + operator==(const Link& aLink) const { + return (mParent == aLink.mParent) + && (mChildIndex == aLink.mChildIndex); } + + Subtree* GetParent() { return mParent; } + const Subtree* GetParent() const { return mParent; } + + int32_t GetChildIndex() const { return mChildIndex; } + + Row& GetRow() { return (*mParent)[mChildIndex]; } + const Row& GetRow() const { return (*mParent)[mChildIndex]; } + }; + +public: + /** + * An iterator that can be used to traverse the tree view. + */ + class iterator { + protected: + int32_t mRowIndex; + AutoTArray<Link, 8> mLink; + + void Next(); + void Prev(); + + friend class Subtree; // so InsertRowAt can initialize us + friend class nsTreeRows; // so nsTreeRows can initialize us + + /** + * Used by operator[]() to initialize an iterator. + */ + void Append(Subtree* aParent, int32_t aChildIndex); + + /** + * Used by InsertRowAt() to initialize an iterator. + */ + void Push(Subtree *aParent, int32_t aChildIndex); + + /** + * Used by operator[]() and InsertRowAt() to initialize an iterator. + */ + void SetRowIndex(int32_t aRowIndex) { mRowIndex = aRowIndex; } + + /** + * Handy accessors to the top element. + */ + Link& GetTop() { return mLink[mLink.Length() - 1]; } + const Link& GetTop() const { return mLink[mLink.Length() - 1]; } + + public: + iterator() : mRowIndex(-1) {} + + iterator(const iterator& aIterator); + iterator& operator=(const iterator& aIterator); + + bool operator==(const iterator& aIterator) const; + + bool operator!=(const iterator& aIterator) const { + return !aIterator.operator==(*this); } + + const Row& operator*() const { return GetTop().GetRow(); } + Row& operator*() { return GetTop().GetRow(); } + + const Row* operator->() const { return &(GetTop().GetRow()); } + Row* operator->() { return &(GetTop().GetRow()); } + + iterator& operator++() { Next(); return *this; } + iterator operator++(int) { iterator temp(*this); Next(); return temp; } + iterator& operator--() { Prev(); return *this; } + iterator operator--(int) { iterator temp(*this); Prev(); return temp; } + + /** + * Return the current parent link + */ + Subtree* GetParent() { return GetTop().GetParent(); } + + const Subtree* GetParent() const { return GetTop().GetParent(); } + + /** + * Return the current child index + */ + int32_t GetChildIndex() const { return GetTop().GetChildIndex(); } + + /** + * Return the depth of the path the iterator is maintaining + * into the tree. + */ + int32_t GetDepth() const { return mLink.Length(); } + + /** + * Return the current row index of the iterator + */ + int32_t GetRowIndex() const { return mRowIndex; } + + /** + * Pop the iterator up a level. + */ + iterator& Pop() { mLink.SetLength(GetDepth() - 1); return *this; } + }; + + /** + * Retrieve the first element in the view + */ + iterator First(); + + /** + * Retrieve (one past) the last element in the view + */ + iterator Last(); + + /** + * Find the row that contains the given resource + */ + iterator FindByResource(nsIRDFResource* aResource); + + /** + * Find the row that contains the result + */ + iterator Find(nsIXULTemplateResult* aResult); + + /** + * Retrieve the ith element in the view + */ + iterator operator[](int32_t aIndex); + + nsTreeRows() : mRoot(nullptr) {} + ~nsTreeRows() {} + + /** + * Ensure that a child subtree exists within the specified parent + * at the specified child index within the parent. (In other + * words, create a subtree if one doesn't already exist.) + */ + Subtree* + EnsureSubtreeFor(Subtree* aParent, int32_t aChildIndex); + + /** + * Ensure that a child subtree exists at the iterator's position. + */ + Subtree* + EnsureSubtreeFor(iterator& aIterator) { + return EnsureSubtreeFor(aIterator.GetParent(), + aIterator.GetChildIndex()); } + + /** + * Get the child subtree for the specified parent at the specified + * child index. Optionally return the child subtree's size. Will + * return `null' if no subtree exists. + */ + Subtree* + GetSubtreeFor(const Subtree* aParent, + int32_t aChildIndex, + int32_t* aSubtreeSize = nullptr); + + /** + * Retrieve the size of the subtree within the specified parent. + */ + int32_t + GetSubtreeSizeFor(const Subtree* aParent, + int32_t aChildIndex) { + int32_t size; + GetSubtreeFor(aParent, aChildIndex, &size); + return size; } + + /** + * Retrieve the size of the subtree within the specified parent. + */ + int32_t + GetSubtreeSizeFor(const iterator& aIterator) { + int32_t size; + GetSubtreeFor(aIterator.GetParent(), aIterator.GetChildIndex(), &size); + return size; } + + /** + * Remove the specified subtree for a row, leaving the row itself + * intact. + */ + void + RemoveSubtreeFor(Subtree* aParent, int32_t aChildIndex); + + /** + * Remove the specified subtree for a row, leaving the row itself + * intact. + */ + void + RemoveSubtreeFor(iterator& aIterator) { + RemoveSubtreeFor(aIterator.GetParent(), aIterator.GetChildIndex()); } + + /** + * Remove the specified row from the view + */ + int32_t + RemoveRowAt(iterator& aIterator) { + iterator temp = aIterator--; + Subtree* parent = temp.GetParent(); + parent->RemoveRowAt(temp.GetChildIndex()); + InvalidateCachedRow(); + return parent->Count(); } + + /** + * Insert a new match into the view + */ + iterator + InsertRowAt(nsTemplateMatch* aMatch, Subtree* aSubtree, int32_t aChildIndex) { + InvalidateCachedRow(); + return aSubtree->InsertRowAt(aMatch, aChildIndex); } + + /** + * Raw access to the rows; e.g., for sorting. + */ + Row* + GetRowsFor(Subtree* aSubtree) { return aSubtree->mRows; } + + /** + * Remove all of the rows + */ + void Clear(); + + /** + * Return the total number of rows in the tree view. + */ + int32_t Count() const { return mRoot.GetSubtreeSize(); } + + /** + * Retrieve the root subtree + */ + Subtree* GetRoot() { return &mRoot; } + + /** + * Set the root resource for the view + */ + void SetRootResource(nsIRDFResource* aResource) { + mRootResource = aResource; } + + /** + * Retrieve the root resource for the view + */ + nsIRDFResource* GetRootResource() { + return mRootResource.get(); } + + /** + * Invalidate the cached row; e.g., because the view has changed + * in a way that would corrupt the iterator. + */ + void + InvalidateCachedRow() { mLastRow = iterator(); } + +protected: + /** + * The root subtree. + */ + Subtree mRoot; + + /** + * The root resource for the view + */ + nsCOMPtr<nsIRDFResource> mRootResource; + + /** + * The last row that was asked for by operator[]. By remembering + * this, we can usually avoid the O(n) search through the row + * array to find the row at the specified index. + */ + iterator mLastRow; +}; + + +#endif // nsTreeRows_h__ diff --git a/dom/xul/templates/nsXMLBinding.cpp b/dom/xul/templates/nsXMLBinding.cpp new file mode 100644 index 000000000..9c1965ce2 --- /dev/null +++ b/dom/xul/templates/nsXMLBinding.cpp @@ -0,0 +1,118 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* 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 "nsXULTemplateQueryProcessorXML.h" +#include "nsXULTemplateResultXML.h" +#include "nsXMLBinding.h" +#include "mozilla/ErrorResult.h" +#include "mozilla/dom/XPathResult.h" + +using namespace mozilla; +using namespace mozilla::dom; + +nsXMLBindingSet::~nsXMLBindingSet() +{} + +void +nsXMLBindingSet::AddBinding(nsIAtom* aVar, nsAutoPtr<XPathExpression>&& aExpr) +{ + nsAutoPtr<nsXMLBinding> newbinding(new nsXMLBinding(aVar, Move(aExpr))); + + if (mFirst) { + nsXMLBinding* binding = mFirst; + + while (binding) { + // if the target variable is already used in a binding, ignore it + // since it won't be useful for anything + if (binding->mVar == aVar) + return; + + // add the binding at the end of the list + if (!binding->mNext) { + binding->mNext = newbinding; + return; + } + + binding = binding->mNext; + } + } + else { + mFirst = newbinding; + } +} + +int32_t +nsXMLBindingSet::LookupTargetIndex(nsIAtom* aTargetVariable, + nsXMLBinding** aBinding) +{ + int32_t idx = 0; + nsXMLBinding* binding = mFirst; + + while (binding) { + if (binding->mVar == aTargetVariable) { + *aBinding = binding; + return idx; + } + idx++; + binding = binding->mNext; + } + + *aBinding = nullptr; + return -1; +} + +XPathResult* +nsXMLBindingValues::GetAssignmentFor(nsXULTemplateResultXML* aResult, + nsXMLBinding* aBinding, + int32_t aIndex, + uint16_t aType) +{ + XPathResult* value = mValues.SafeElementAt(aIndex); + if (value) { + return value; + } + + nsINode* contextNode = aResult->Node(); + if (!contextNode) { + return nullptr; + } + + mValues.EnsureLengthAtLeast(aIndex + 1); + + ErrorResult ignored; + mValues[aIndex] = aBinding->mExpr->Evaluate(*contextNode, aType, nullptr, + ignored); + + return mValues[aIndex]; +} + +nsINode* +nsXMLBindingValues::GetNodeAssignmentFor(nsXULTemplateResultXML* aResult, + nsXMLBinding* aBinding, + int32_t aIndex) +{ + XPathResult* result = GetAssignmentFor(aResult, aBinding, aIndex, + XPathResult::FIRST_ORDERED_NODE_TYPE); + + ErrorResult rv; + return result ? result->GetSingleNodeValue(rv) : nullptr; +} + +void +nsXMLBindingValues::GetStringAssignmentFor(nsXULTemplateResultXML* aResult, + nsXMLBinding* aBinding, + int32_t aIndex, + nsAString& aValue) +{ + XPathResult* result = GetAssignmentFor(aResult, aBinding, aIndex, + XPathResult::STRING_TYPE); + + if (result) { + ErrorResult rv; + result->GetStringValue(aValue, rv); + } else { + aValue.Truncate(); + } +} diff --git a/dom/xul/templates/nsXMLBinding.h b/dom/xul/templates/nsXMLBinding.h new file mode 100644 index 000000000..e72813598 --- /dev/null +++ b/dom/xul/templates/nsXMLBinding.h @@ -0,0 +1,137 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* 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/. */ + +#ifndef nsXMLBinding_h__ +#define nsXMLBinding_h__ + +#include "nsAutoPtr.h" +#include "nsIAtom.h" +#include "mozilla/Attributes.h" +#include "mozilla/dom/XPathExpression.h" + +class nsINode; +class nsXULTemplateResultXML; +class nsXMLBindingValues; +namespace mozilla { +namespace dom { +class XPathResult; +} // namespace dom +} // namespace mozilla + +/** + * Classes related to storing bindings for XML handling. + */ + +/** + * a <binding> description + */ +struct nsXMLBinding { + nsCOMPtr<nsIAtom> mVar; + nsAutoPtr<mozilla::dom::XPathExpression> mExpr; + + nsAutoPtr<nsXMLBinding> mNext; + + nsXMLBinding(nsIAtom* aVar, nsAutoPtr<mozilla::dom::XPathExpression>&& aExpr) + : mVar(aVar), mExpr(aExpr), mNext(nullptr) + { + MOZ_COUNT_CTOR(nsXMLBinding); + } + + ~nsXMLBinding() + { + MOZ_COUNT_DTOR(nsXMLBinding); + } +}; + +/** + * a collection of <binding> descriptors. This object is refcounted by + * nsXMLBindingValues objects and the query processor. + */ +class nsXMLBindingSet final +{ + ~nsXMLBindingSet(); + +public: + // pointer to the first binding in a linked list + nsAutoPtr<nsXMLBinding> mFirst; + + NS_INLINE_DECL_REFCOUNTING(nsXMLBindingSet); + + /** + * Add a binding to the set + */ + void + AddBinding(nsIAtom* aVar, nsAutoPtr<mozilla::dom::XPathExpression>&& aExpr); + + /** + * The nsXMLBindingValues class stores an array of values, one for each + * target symbol that could be set by the bindings in the set. + * LookupTargetIndex determines the index into the array for a given + * target symbol. + */ + int32_t + LookupTargetIndex(nsIAtom* aTargetVariable, nsXMLBinding** aBinding); +}; + +/** + * a set of values of bindings. This object is used once per result. + */ +class nsXMLBindingValues +{ +protected: + + // the binding set + RefPtr<nsXMLBindingSet> mBindings; + + /** + * A set of values for variable bindings. To look up a binding value, + * scan through the binding set in mBindings for the right target atom. + * Its index will correspond to the index in this array. + */ + nsTArray<RefPtr<mozilla::dom::XPathResult> > mValues; + +public: + + nsXMLBindingValues() { MOZ_COUNT_CTOR(nsXMLBindingValues); } + ~nsXMLBindingValues() { MOZ_COUNT_DTOR(nsXMLBindingValues); } + + nsXMLBindingSet* GetBindingSet() { return mBindings; } + + void SetBindingSet(nsXMLBindingSet* aBindings) { mBindings = aBindings; } + + int32_t + LookupTargetIndex(nsIAtom* aTargetVariable, nsXMLBinding** aBinding) + { + return mBindings ? + mBindings->LookupTargetIndex(aTargetVariable, aBinding) : -1; + } + + /** + * Retrieve the assignment for a particular variable + * + * aResult the result generated from the template + * aBinding the binding looked up using LookupTargetIndex + * aIndex the index of the assignment to retrieve + * aType the type of result expected + */ + mozilla::dom::XPathResult* + GetAssignmentFor(nsXULTemplateResultXML* aResult, + nsXMLBinding* aBinding, + int32_t idx, + uint16_t type); + + nsINode* + GetNodeAssignmentFor(nsXULTemplateResultXML* aResult, + nsXMLBinding* aBinding, + int32_t idx); + + void + GetStringAssignmentFor(nsXULTemplateResultXML* aResult, + nsXMLBinding* aBinding, + int32_t idx, + nsAString& aValue); +}; + +#endif // nsXMLBinding_h__ diff --git a/dom/xul/templates/nsXULContentBuilder.cpp b/dom/xul/templates/nsXULContentBuilder.cpp new file mode 100644 index 000000000..71c285cc4 --- /dev/null +++ b/dom/xul/templates/nsXULContentBuilder.cpp @@ -0,0 +1,1976 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* 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 "mozilla/ArrayUtils.h" + +#include "nsContentCID.h" +#include "nsIDocument.h" +#include "nsIDOMNodeList.h" +#include "nsIDOMXULDocument.h" +#include "mozilla/dom/NodeInfo.h" +#include "nsIServiceManager.h" +#include "nsIXULDocument.h" + +#include "nsContentSupportMap.h" +#include "nsRDFConMemberTestNode.h" +#include "nsRDFPropertyTestNode.h" +#include "nsXULSortService.h" +#include "nsTemplateRule.h" +#include "nsTemplateMap.h" +#include "nsTArray.h" +#include "nsXPIDLString.h" +#include "nsGkAtoms.h" +#include "nsXULContentUtils.h" +#include "nsXULElement.h" +#include "nsXULTemplateBuilder.h" +#include "nsNodeInfoManager.h" +#include "nsContentCreatorFunctions.h" +#include "nsContentUtils.h" +#include "nsAttrName.h" +#include "nsNodeUtils.h" +#include "mozAutoDocUpdate.h" +#include "nsTextNode.h" +#include "mozilla/dom/Element.h" + +#include "PLDHashTable.h" +#include "rdf.h" + +using namespace mozilla; +using namespace mozilla::dom; + +//---------------------------------------------------------------------- +// +// Return values for EnsureElementHasGenericChild() +// +#define NS_ELEMENT_GOT_CREATED NS_RDF_NO_VALUE +#define NS_ELEMENT_WAS_THERE NS_OK + +//---------------------------------------------------------------------- +// +// nsXULContentBuilder +// + +/** + * The content builder generates DOM nodes from a template. The actual content + * generation is done entirely inside BuildContentFromTemplate. + * + * Content generation is centered around the generation node (the node with + * uri="?member" on it). Nodes above the generation node are unique and + * generated only once. BuildContentFromTemplate will be passed the unique + * flag as an argument for content at this point and will recurse until it + * finds the generation node. + * + * Once the generation node has been found, the results for that content node + * are added to the content map, stored in mContentSupportMap. + * + * If recursion is allowed, generation continues, where the generation node + * becomes the container to insert into. + */ +class nsXULContentBuilder : public nsXULTemplateBuilder +{ +public: + // nsIXULTemplateBuilder interface + NS_IMETHOD CreateContents(nsIContent* aElement, bool aForceCreation) override; + + NS_IMETHOD HasGeneratedContent(nsIRDFResource* aResource, + nsIAtom* aTag, + bool* aGenerated) override; + + NS_IMETHOD GetResultForContent(nsIDOMElement* aContent, + nsIXULTemplateResult** aResult) override; + + // nsIMutationObserver interface + NS_DECL_NSIMUTATIONOBSERVER_ATTRIBUTECHANGED + NS_DECL_NSIMUTATIONOBSERVER_NODEWILLBEDESTROYED + +protected: + friend nsresult + NS_NewXULContentBuilder(nsISupports* aOuter, REFNSIID aIID, void** aResult); + + nsXULContentBuilder(); + + void Traverse(nsCycleCollectionTraversalCallback& aCb) const override + { + mSortState.Traverse(aCb); + } + + virtual void Uninit(bool aIsFinal) override; + + // Implementation methods + nsresult + OpenContainer(nsIContent* aElement); + + nsresult + CloseContainer(nsIContent* aElement); + + /** + * Build content from a template for a given result. This will be called + * recursively or on demand and will be called for every node in the + * generated content tree. + */ + nsresult + BuildContentFromTemplate(nsIContent *aTemplateNode, + nsIContent *aResourceNode, + nsIContent *aRealNode, + bool aIsUnique, + bool aIsSelfReference, + nsIXULTemplateResult* aChild, + bool aNotify, + nsTemplateMatch* aMatch, + nsIContent** aContainer, + int32_t* aNewIndexInContainer); + + /** + * Copy the attributes from the template node to the node generated + * from it, performing any substitutions. + * + * @param aTemplateNode node within template + * @param aRealNode generated node to set attibutes upon + * @param aResult result to look up variable->value bindings in + * @param aNotify true to notify of DOM changes + */ + nsresult + CopyAttributesToElement(nsIContent* aTemplateNode, + nsIContent* aRealNode, + nsIXULTemplateResult* aResult, + bool aNotify); + + /** + * Add any necessary persistent attributes (persist="...") from the + * local store to a generated node. + * + * @param aTemplateNode node within template + * @param aRealNode generated node to set persisted attibutes upon + * @param aResult result to look up variable->value bindings in + */ + nsresult + AddPersistentAttributes(Element* aTemplateNode, + nsIXULTemplateResult* aResult, + nsIContent* aRealNode); + + /** + * Recalculate any attributes that have variable references. This will + * be called when a binding has been changed to update the attributes. + * The attributes are copied from the node aTemplateNode in the template + * to the generated node aRealNode, using the values from the result + * aResult. This method will operate recursively. + * + * @param aTemplateNode node within template + * @param aRealNode generated node to set attibutes upon + * @param aResult result to look up variable->value bindings in + */ + nsresult + SynchronizeUsingTemplate(nsIContent *aTemplateNode, + nsIContent* aRealNode, + nsIXULTemplateResult* aResult); + + /** + * Remove the generated node aContent from the DOM and the hashtables + * used by the content builder. + */ + nsresult + RemoveMember(nsIContent* aContent); + + /** + * Create the appropriate generated content for aElement, by calling + * CreateContainerContents. + * + * @param aElement element to generate content inside + * @param aForceCreation true to force creation for closed items such as menus + */ + nsresult + CreateTemplateAndContainerContents(nsIContent* aElement, + bool aForceCreation); + + /** + * Generate the results for a template, by calling + * CreateContainerContentsForQuerySet for each queryset. + * + * @param aElement element to generate content inside + * @param aResult reference point for query + * @param aForceCreation true to force creation for closed items such as menus + * @param aNotify true to notify of DOM changes as each element is inserted + * @param aNotifyAtEnd notify at the end of all DOM changes + */ + nsresult + CreateContainerContents(nsIContent* aElement, + nsIXULTemplateResult* aResult, + bool aForceCreation, + bool aNotify, + bool aNotifyAtEnd); + + /** + * Generate the results for a query. + * + * @param aElement element to generate content inside + * @param aResult reference point for query + * @param aNotify true to notify of DOM changes + * @param aContainer container content was added inside + * @param aNewIndexInContainer index with container in which content was added + */ + nsresult + CreateContainerContentsForQuerySet(nsIContent* aElement, + nsIXULTemplateResult* aResult, + bool aNotify, + nsTemplateQuerySet* aQuerySet, + nsIContent** aContainer, + int32_t* aNewIndexInContainer); + + /** + * Check if an element with a particular tag exists with a container. + * If it is not present, append a new element with that tag into the + * container. + * + * @param aParent parent container + * @param aNameSpaceID namespace of tag to locate or create + * @param aTag tag to locate or create + * @param aNotify true to notify of DOM changes + * @param aResult set to the found or created node. + */ + nsresult + EnsureElementHasGenericChild(nsIContent* aParent, + int32_t aNameSpaceID, + nsIAtom* aTag, + bool aNotify, + nsIContent** aResult); + + bool + IsOpen(nsIContent* aElement); + + nsresult + RemoveGeneratedContent(nsIContent* aElement); + + nsresult + GetElementsForResult(nsIXULTemplateResult* aResult, + nsCOMArray<nsIContent>& aElements); + + nsresult + CreateElement(int32_t aNameSpaceID, + nsIAtom* aTag, + Element** aResult); + + /** + * Set the container and empty attributes on a node. If + * aIgnoreNonContainers is true, then the element is not changed + * for non-containers. Otherwise, the container attribute will be set to + * false. + * + * @param aElement element to set attributes on + * @param aResult result to use to determine state of attributes + * @param aIgnoreNonContainers true to not change for non-containers + * @param aNotify true to notify of DOM changes + */ + nsresult + SetContainerAttrs(nsIContent *aElement, + nsIXULTemplateResult* aResult, + bool aIgnoreNonContainers, + bool aNotify); + + virtual nsresult + RebuildAll() override; + + // GetInsertionLocations, ReplaceMatch and SynchronizeResult are inherited + // from nsXULTemplateBuilder + + /** + * Return true if the result can be inserted into the template as + * generated content. For the content builder, aLocations will be set + * to the list of containers where the content should be inserted. + */ + virtual bool + GetInsertionLocations(nsIXULTemplateResult* aOldResult, + nsCOMArray<nsIContent>** aLocations) override; + + /** + * Remove the content associated with aOldResult which no longer matches, + * and/or generate content for a new match. + */ + virtual nsresult + ReplaceMatch(nsIXULTemplateResult* aOldResult, + nsTemplateMatch* aNewMatch, + nsTemplateRule* aNewMatchRule, + void *aContext) override; + + /** + * Synchronize a result bindings with the generated content for that + * result. This will be called as a result of the template builder's + * ResultBindingChanged method. + */ + virtual nsresult + SynchronizeResult(nsIXULTemplateResult* aResult) override; + + /** + * Compare a result to a content node. If the generated content for the + * result should come before aContent, set aSortOrder to -1. If it should + * come after, set sortOrder to 1. If both are equal, set to 0. + */ + nsresult + CompareResultToNode(nsIXULTemplateResult* aResult, nsIContent* aContent, + int32_t* aSortOrder); + + /** + * Insert a generated node into the container where it should go according + * to the current sort. aNode is the generated content node and aResult is + * the result for the generated node. + */ + nsresult + InsertSortedNode(nsIContent* aContainer, + nsIContent* aNode, + nsIXULTemplateResult* aResult, + bool aNotify); + + /** + * Maintains a mapping between elements in the DOM and the matches + * that they support. + */ + nsContentSupportMap mContentSupportMap; + + /** + * Maintains a mapping from an element in the DOM to the template + * element that it was created from. + */ + nsTemplateMap mTemplateMap; + + /** + * Information about the currently active sort + */ + nsSortState mSortState; +}; + +nsresult +NS_NewXULContentBuilder(nsISupports* aOuter, REFNSIID aIID, void** aResult) +{ + NS_PRECONDITION(aOuter == nullptr, "no aggregation"); + if (aOuter) + return NS_ERROR_NO_AGGREGATION; + + nsresult rv; + nsXULContentBuilder* result = new nsXULContentBuilder(); + NS_ADDREF(result); // stabilize + + rv = result->InitGlobals(); + + if (NS_SUCCEEDED(rv)) + rv = result->QueryInterface(aIID, aResult); + + NS_RELEASE(result); + return rv; +} + +nsXULContentBuilder::nsXULContentBuilder() +{ + mSortState.initialized = false; +} + +void +nsXULContentBuilder::Uninit(bool aIsFinal) +{ + if (! aIsFinal && mRoot) { + nsresult rv = RemoveGeneratedContent(mRoot); + if (NS_FAILED(rv)) + return; + } + + // Nuke the content support map completely. + mContentSupportMap.Clear(); + mTemplateMap.Clear(); + + mSortState.initialized = false; + + nsXULTemplateBuilder::Uninit(aIsFinal); +} + +nsresult +nsXULContentBuilder::BuildContentFromTemplate(nsIContent *aTemplateNode, + nsIContent *aResourceNode, + nsIContent *aRealNode, + bool aIsUnique, + bool aIsSelfReference, + nsIXULTemplateResult* aChild, + bool aNotify, + nsTemplateMatch* aMatch, + nsIContent** aContainer, + int32_t* aNewIndexInContainer) +{ + // This is the mother lode. Here is where we grovel through an + // element in the template, copying children from the template + // into the "real" content tree, performing substitution as we go + // by looking stuff up using the results. + // + // |aTemplateNode| is the element in the "template tree", whose + // children we will duplicate and move into the "real" content + // tree. + // + // |aResourceNode| is the element in the "real" content tree that + // has the "id" attribute set to an result's id. This is + // not directly used here, but rather passed down to the XUL + // sort service to perform container-level sort. + // + // |aRealNode| is the element in the "real" content tree to which + // the new elements will be copied. + // + // |aIsUnique| is set to "true" so long as content has been + // "unique" (or "above" the resource element) so far in the + // template. + // + // |aIsSelfReference| should be set to "true" for cases where + // the reference and member variables are the same, indicating + // that the generated node is the same as the reference point, + // so generation should not recurse, or else an infinite loop + // would occur. + // + // |aChild| is the result for which we are building content. + // + // |aNotify| is set to "true" if content should be constructed + // "noisily"; that is, whether the document observers should be + // notified when new content is added to the content model. + // + // |aContainer| is an out parameter that will be set to the first + // container element in the "real" content tree to which content + // was appended. + // + // |aNewIndexInContainer| is an out parameter that will be set to + // the index in aContainer at which new content is first + // constructed. + // + // If |aNotify| is "false", then |aContainer| and + // |aNewIndexInContainer| are used to determine where in the + // content model new content is constructed. This allows a single + // notification to be propagated to document observers. + // + + nsresult rv; + + if (MOZ_LOG_TEST(gXULTemplateLog, LogLevel::Debug)) { + MOZ_LOG(gXULTemplateLog, LogLevel::Debug, + ("nsXULContentBuilder::BuildContentFromTemplate (is unique: %d)", + aIsUnique)); + + nsAutoString id; + aChild->GetId(id); + + MOZ_LOG(gXULTemplateLog, LogLevel::Debug, + ("Tags: [Template: %s Resource: %s Real: %s] for id %s", + nsAtomCString(aTemplateNode->NodeInfo()->NameAtom()).get(), + nsAtomCString(aResourceNode->NodeInfo()->NameAtom()).get(), + nsAtomCString(aRealNode->NodeInfo()->NameAtom()).get(), NS_ConvertUTF16toUTF8(id).get())); + } + + // Iterate through all of the template children, constructing + // "real" content model nodes for each "template" child. + for (nsIContent* tmplKid = aTemplateNode->GetFirstChild(); + tmplKid; + tmplKid = tmplKid->GetNextSibling()) { + + int32_t nameSpaceID = tmplKid->GetNameSpaceID(); + + // Check whether this element is the generation element. The generation + // element is the element that is cookie-cutter copied once for each + // different result specified by |aChild|. + // + // Nodes that appear -above- the generation element + // (that is, are ancestors of the generation element in the + // content model) are unique across all values of |aChild|, + // and are created only once. + // + // Nodes that appear -below- the generation element (that is, + // are descendants of the generation element in the content + // model), are cookie-cutter copied for each distinct value of + // |aChild|. + // + // For example, in a <tree> template: + // + // <tree> + // <template> + // <treechildren> [1] + // <treeitem uri="rdf:*"> [2] + // <treerow> [3] + // <treecell value="rdf:urn:foo" /> [4] + // <treecell value="rdf:urn:bar" /> [5] + // </treerow> + // </treeitem> + // </treechildren> + // </template> + // </tree> + // + // The <treeitem> element [2] is the generation element. This + // element, and all of its descendants ([3], [4], and [5]) + // will be duplicated for each different |aChild|. + // It's ancestor <treechildren> [1] is unique, and + // will only be created -once-, no matter how many <treeitem>s + // are created below it. + // + // isUnique will be true for nodes above the generation element, + // isGenerationElement will be true for the generation element, + // and both will be false for descendants + bool isGenerationElement = false; + bool isUnique = aIsUnique; + + // We identify the resource element by presence of a + // "uri='rdf:*'" attribute. (We also support the older + // "uri='...'" syntax.) + if (tmplKid->HasAttr(kNameSpaceID_None, nsGkAtoms::uri) && aMatch->IsActive()) { + isGenerationElement = true; + isUnique = false; + } + + MOZ_ASSERT_IF(isGenerationElement, tmplKid->IsElement()); + + nsIAtom *tag = tmplKid->NodeInfo()->NameAtom(); + + if (MOZ_LOG_TEST(gXULTemplateLog, LogLevel::Debug)) { + MOZ_LOG(gXULTemplateLog, LogLevel::Debug, + ("xultemplate[%p] building %s %s %s", + this, nsAtomCString(tag).get(), + (isGenerationElement ? "[resource]" : ""), + (isUnique ? "[unique]" : ""))); + } + + // Set to true if the child we're trying to create now + // already existed in the content model. + bool realKidAlreadyExisted = false; + + nsCOMPtr<nsIContent> realKid; + if (isUnique) { + // The content is "unique"; that is, we haven't descended + // far enough into the template to hit the generation + // element yet. |EnsureElementHasGenericChild()| will + // conditionally create the element iff it isn't there + // already. + rv = EnsureElementHasGenericChild(aRealNode, nameSpaceID, tag, aNotify, getter_AddRefs(realKid)); + if (NS_FAILED(rv)) + return rv; + + if (rv == NS_ELEMENT_WAS_THERE) { + realKidAlreadyExisted = true; + } + else { + // Potentially remember the index of this element as the first + // element that we've generated. Note that we remember + // this -before- we recurse! + if (aContainer && !*aContainer) { + *aContainer = aRealNode; + NS_ADDREF(*aContainer); + + uint32_t indx = aRealNode->GetChildCount(); + + // Since EnsureElementHasGenericChild() added us, make + // sure to subtract one for our real index. + *aNewIndexInContainer = indx - 1; + } + } + + // Recurse until we get to the resource element. Since + // -we're- unique, assume that our child will be + // unique. The check for the "resource" element at the top + // of the function will trip this to |false| as soon as we + // encounter it. + rv = BuildContentFromTemplate(tmplKid, aResourceNode, realKid, true, + aIsSelfReference, aChild, aNotify, aMatch, + aContainer, aNewIndexInContainer); + + if (NS_FAILED(rv)) + return rv; + } + else if (isGenerationElement) { + // It's the "resource" element. Create a new element using + // the namespace ID and tag from the template element. + nsCOMPtr<Element> element; + rv = CreateElement(nameSpaceID, tag, getter_AddRefs(element)); + if (NS_FAILED(rv)) + return rv; + realKid = element.forget(); + + // Add the resource element to the content support map so + // we can remove the match based on the content node later. + mContentSupportMap.Put(realKid, aMatch); + + // Assign the element an 'id' attribute using result's id + nsAutoString id; + rv = aChild->GetId(id); + if (NS_FAILED(rv)) + return rv; + + rv = realKid->SetAttr(kNameSpaceID_None, nsGkAtoms::id, id, false); + if (NS_FAILED(rv)) + return rv; + + // Set up the element's 'container' and 'empty' attributes. + SetContainerAttrs(realKid, aChild, true, false); + } + else if (tag == nsGkAtoms::textnode && + nameSpaceID == kNameSpaceID_XUL) { + // <xul:text value="..."> is replaced by text of the + // actual value of the 'rdf:resource' attribute for the + // given node. + // SynchronizeUsingTemplate contains code used to update textnodes, + // so make sure to modify both when changing this + char16_t attrbuf[128]; + nsFixedString attrValue(attrbuf, ArrayLength(attrbuf), 0); + tmplKid->GetAttr(kNameSpaceID_None, nsGkAtoms::value, attrValue); + if (!attrValue.IsEmpty()) { + nsAutoString value; + rv = SubstituteText(aChild, attrValue, value); + if (NS_FAILED(rv)) return rv; + + RefPtr<nsTextNode> content = + new nsTextNode(mRoot->NodeInfo()->NodeInfoManager()); + + content->SetText(value, false); + + rv = aRealNode->AppendChildTo(content, aNotify); + if (NS_FAILED(rv)) return rv; + + // XXX Don't bother remembering text nodes as the + // first element we've generated? + } + } + else if (tmplKid->IsNodeOfType(nsINode::eTEXT)) { + nsCOMPtr<nsIDOMNode> tmplTextNode = do_QueryInterface(tmplKid); + if (!tmplTextNode) { + NS_ERROR("textnode not implementing nsIDOMNode??"); + return NS_ERROR_FAILURE; + } + nsCOMPtr<nsIDOMNode> clonedNode; + tmplTextNode->CloneNode(false, 1, getter_AddRefs(clonedNode)); + nsCOMPtr<nsIContent> clonedContent = do_QueryInterface(clonedNode); + if (!clonedContent) { + NS_ERROR("failed to clone textnode"); + return NS_ERROR_FAILURE; + } + rv = aRealNode->AppendChildTo(clonedContent, aNotify); + if (NS_FAILED(rv)) return rv; + } + else { + // It's just a generic element. Create it! + nsCOMPtr<Element> element; + rv = CreateElement(nameSpaceID, tag, getter_AddRefs(element)); + if (NS_FAILED(rv)) return rv; + realKid = element.forget(); + } + + if (realKid && !realKidAlreadyExisted) { + // Potentially remember the index of this element as the + // first element that we've generated. + if (aContainer && !*aContainer) { + *aContainer = aRealNode; + NS_ADDREF(*aContainer); + + uint32_t indx = aRealNode->GetChildCount(); + + // Since we haven't inserted any content yet, our new + // index in the container will be the current count of + // elements in the container. + *aNewIndexInContainer = indx; + } + + // Remember the template kid from which we created the + // real kid. This allows us to sync back up with the + // template to incrementally build content. + mTemplateMap.Put(realKid, tmplKid); + + rv = CopyAttributesToElement(tmplKid, realKid, aChild, false); + if (NS_FAILED(rv)) return rv; + + // Add any persistent attributes + if (isGenerationElement) { + rv = AddPersistentAttributes(tmplKid->AsElement(), aChild, + realKid); + if (NS_FAILED(rv)) return rv; + } + + // the unique content recurses up above. Also, don't recurse if + // this is a self reference (a reference to the same resource) + // or we'll end up regenerating the same content. + if (!aIsSelfReference && !isUnique) { + // this call creates the content inside the generation node, + // for example the label below: + // <vbox uri="?"> + // <label value="?title"/> + // </vbox> + rv = BuildContentFromTemplate(tmplKid, aResourceNode, realKid, false, + false, aChild, false, aMatch, + nullptr /* don't care */, + nullptr /* don't care */); + if (NS_FAILED(rv)) return rv; + + if (isGenerationElement) { + // build the next level of children + rv = CreateContainerContents(realKid, aChild, false, + false, false); + if (NS_FAILED(rv)) return rv; + } + } + + // We'll _already_ have added the unique elements; but if + // it's -not- unique, then use the XUL sort service now to + // append the element to the content model. + if (! isUnique) { + rv = NS_ERROR_UNEXPECTED; + + if (isGenerationElement) + rv = InsertSortedNode(aRealNode, realKid, aChild, aNotify); + + if (NS_FAILED(rv)) { + rv = aRealNode->AppendChildTo(realKid, aNotify); + NS_ASSERTION(NS_SUCCEEDED(rv), "unable to insert element"); + } + } + } + } + + return NS_OK; +} + +nsresult +nsXULContentBuilder::CopyAttributesToElement(nsIContent* aTemplateNode, + nsIContent* aRealNode, + nsIXULTemplateResult* aResult, + bool aNotify) +{ + nsresult rv; + + // Copy all attributes from the template to the new element + uint32_t numAttribs = aTemplateNode->GetAttrCount(); + + for (uint32_t attr = 0; attr < numAttribs; attr++) { + const nsAttrName* name = aTemplateNode->GetAttrNameAt(attr); + int32_t attribNameSpaceID = name->NamespaceID(); + // Hold a strong reference here so that the atom doesn't go away + // during UnsetAttr. + nsCOMPtr<nsIAtom> attribName = name->LocalName(); + + // XXXndeakin ignore namespaces until bug 321182 is fixed + if (attribName != nsGkAtoms::id && attribName != nsGkAtoms::uri) { + // Create a buffer here, because there's a chance that an + // attribute in the template is going to be an RDF URI, which is + // usually longish. + char16_t attrbuf[128]; + nsFixedString attribValue(attrbuf, ArrayLength(attrbuf), 0); + aTemplateNode->GetAttr(attribNameSpaceID, attribName, attribValue); + if (!attribValue.IsEmpty()) { + nsAutoString value; + rv = SubstituteText(aResult, attribValue, value); + if (NS_FAILED(rv)) + return rv; + + // if the string is empty after substitutions, remove the + // attribute + if (!value.IsEmpty()) { + rv = aRealNode->SetAttr(attribNameSpaceID, + attribName, + name->GetPrefix(), + value, + aNotify); + } + else { + rv = aRealNode->UnsetAttr(attribNameSpaceID, + attribName, + aNotify); + } + + if (NS_FAILED(rv)) + return rv; + } + } + } + + return NS_OK; +} + +nsresult +nsXULContentBuilder::AddPersistentAttributes(Element* aTemplateNode, + nsIXULTemplateResult* aResult, + nsIContent* aRealNode) +{ + if (!mRoot) + return NS_OK; + + nsCOMPtr<nsIRDFResource> resource; + nsresult rv = GetResultResource(aResult, getter_AddRefs(resource)); + NS_ENSURE_SUCCESS(rv, rv); + + nsAutoString attribute, persist; + aTemplateNode->GetAttr(kNameSpaceID_None, nsGkAtoms::persist, persist); + + while (!persist.IsEmpty()) { + attribute.Truncate(); + + int32_t offset = persist.FindCharInSet(" ,"); + if (offset > 0) { + persist.Left(attribute, offset); + persist.Cut(0, offset + 1); + } + else { + attribute = persist; + persist.Truncate(); + } + + attribute.Trim(" "); + + if (attribute.IsEmpty()) + break; + + nsCOMPtr<nsIAtom> tag; + int32_t nameSpaceID; + + RefPtr<mozilla::dom::NodeInfo> ni = + aTemplateNode->GetExistingAttrNameFromQName(attribute); + if (ni) { + tag = ni->NameAtom(); + nameSpaceID = ni->NamespaceID(); + } + else { + tag = NS_Atomize(attribute); + NS_ENSURE_TRUE(tag, NS_ERROR_OUT_OF_MEMORY); + + nameSpaceID = kNameSpaceID_None; + } + + nsCOMPtr<nsIRDFResource> property; + rv = nsXULContentUtils::GetResource(nameSpaceID, tag, getter_AddRefs(property)); + NS_ENSURE_SUCCESS(rv, rv); + + nsCOMPtr<nsIRDFNode> target; + rv = mDB->GetTarget(resource, property, true, getter_AddRefs(target)); + NS_ENSURE_SUCCESS(rv, rv); + + if (! target) + continue; + + nsCOMPtr<nsIRDFLiteral> value = do_QueryInterface(target); + NS_ASSERTION(value != nullptr, "unable to stomach that sort of node"); + if (! value) + continue; + + const char16_t* valueStr; + rv = value->GetValueConst(&valueStr); + NS_ENSURE_SUCCESS(rv, rv); + + rv = aRealNode->SetAttr(nameSpaceID, tag, nsDependentString(valueStr), + false); + NS_ENSURE_SUCCESS(rv, rv); + } + + return NS_OK; +} + +nsresult +nsXULContentBuilder::SynchronizeUsingTemplate(nsIContent* aTemplateNode, + nsIContent* aRealElement, + nsIXULTemplateResult* aResult) +{ + // check all attributes on the template node; if they reference a resource, + // update the equivalent attribute on the content node + nsresult rv; + rv = CopyAttributesToElement(aTemplateNode, aRealElement, aResult, true); + if (NS_FAILED(rv)) + return rv; + + uint32_t count = aTemplateNode->GetChildCount(); + + for (uint32_t loop = 0; loop < count; ++loop) { + nsIContent *tmplKid = aTemplateNode->GetChildAt(loop); + + if (! tmplKid) + break; + + nsIContent *realKid = aRealElement->GetChildAt(loop); + if (! realKid) + break; + + // check for text nodes and update them accordingly. + // This code is similar to that in BuildContentFromTemplate + if (tmplKid->NodeInfo()->Equals(nsGkAtoms::textnode, + kNameSpaceID_XUL)) { + char16_t attrbuf[128]; + nsFixedString attrValue(attrbuf, ArrayLength(attrbuf), 0); + tmplKid->GetAttr(kNameSpaceID_None, nsGkAtoms::value, attrValue); + if (!attrValue.IsEmpty()) { + nsAutoString value; + rv = SubstituteText(aResult, attrValue, value); + if (NS_FAILED(rv)) return rv; + realKid->SetText(value, true); + } + } + + rv = SynchronizeUsingTemplate(tmplKid, realKid, aResult); + if (NS_FAILED(rv)) return rv; + } + + return NS_OK; +} + +nsresult +nsXULContentBuilder::RemoveMember(nsIContent* aContent) +{ + nsCOMPtr<nsIContent> parent = aContent->GetParent(); + if (parent) { + int32_t pos = parent->IndexOf(aContent); + + NS_ASSERTION(pos >= 0, "parent doesn't think this child has an index"); + if (pos < 0) return NS_OK; + + // Note: RemoveChildAt sets |child|'s document to null so that + // it'll get knocked out of the XUL doc's resource-to-element + // map. + parent->RemoveChildAt(pos, true); + } + + // Remove from the content support map. + mContentSupportMap.Remove(aContent); + + // Remove from the template map + mTemplateMap.Remove(aContent); + + return NS_OK; +} + +nsresult +nsXULContentBuilder::CreateTemplateAndContainerContents(nsIContent* aElement, + bool aForceCreation) +{ + // Generate both 1) the template content for the current element, + // and 2) recursive subcontent (if the current element refers to a + // container result). + + MOZ_LOG(gXULTemplateLog, LogLevel::Info, + ("nsXULContentBuilder::CreateTemplateAndContainerContents start - flags: %d", + mFlags)); + + if (! mQueryProcessor) + return NS_OK; + + // for the root element, get the ref attribute and generate content + if (aElement == mRoot) { + if (! mRootResult) { + nsAutoString ref; + mRoot->GetAttr(kNameSpaceID_None, nsGkAtoms::ref, ref); + + if (! ref.IsEmpty()) { + nsresult rv = mQueryProcessor->TranslateRef(mDataSource, ref, + getter_AddRefs(mRootResult)); + if (NS_FAILED(rv)) + return rv; + } + } + + if (mRootResult) { + CreateContainerContents(aElement, mRootResult, aForceCreation, + false, true); + } + } + else if (!(mFlags & eDontRecurse)) { + // The content map will contain the generation elements (the ones that + // are given ids) and only those elements, so get the reference point + // from the corresponding match. + nsTemplateMatch *match = nullptr; + if (mContentSupportMap.Get(aElement, &match)) + CreateContainerContents(aElement, match->mResult, aForceCreation, + false, true); + } + + MOZ_LOG(gXULTemplateLog, LogLevel::Info, + ("nsXULContentBuilder::CreateTemplateAndContainerContents end")); + + return NS_OK; +} + +nsresult +nsXULContentBuilder::CreateContainerContents(nsIContent* aElement, + nsIXULTemplateResult* aResult, + bool aForceCreation, + bool aNotify, + bool aNotifyAtEnd) +{ + if (!aForceCreation && !IsOpen(aElement)) + return NS_OK; + + // don't generate children if recursion or child processing isn't allowed + if (aResult != mRootResult) { + if (mFlags & eDontRecurse) + return NS_OK; + + bool mayProcessChildren; + nsresult rv = aResult->GetMayProcessChildren(&mayProcessChildren); + if (NS_FAILED(rv) || !mayProcessChildren) + return rv; + } + + nsCOMPtr<nsIRDFResource> refResource; + GetResultResource(aResult, getter_AddRefs(refResource)); + if (! refResource) + return NS_ERROR_FAILURE; + + // Avoid re-entrant builds for the same resource. + if (IsActivated(refResource)) + return NS_OK; + + ActivationEntry entry(refResource, &mTop); + + // Compile the rules now, if they haven't been already. + if (! mQueriesCompiled) { + nsresult rv = CompileQueries(); + if (NS_FAILED(rv)) + return rv; + } + + if (mQuerySets.Length() == 0) + return NS_OK; + + // See if the element's templates contents have been generated: + // this prevents a re-entrant call from triggering another + // generation. + nsXULElement *xulcontent = nsXULElement::FromContent(aElement); + if (xulcontent) { + if (xulcontent->GetTemplateGenerated()) + return NS_OK; + + // Now mark the element's contents as being generated so that + // any re-entrant calls don't trigger an infinite recursion. + xulcontent->SetTemplateGenerated(); + } + + int32_t newIndexInContainer = -1; + nsIContent* container = nullptr; + + int32_t querySetCount = mQuerySets.Length(); + + for (int32_t r = 0; r < querySetCount; r++) { + nsTemplateQuerySet* queryset = mQuerySets[r]; + + nsIAtom* tag = queryset->GetTag(); + if (tag && tag != aElement->NodeInfo()->NameAtom()) + continue; + + CreateContainerContentsForQuerySet(aElement, aResult, aNotify, queryset, + &container, &newIndexInContainer); + } + + if (aNotifyAtEnd && container) { + MOZ_AUTO_DOC_UPDATE(container->GetUncomposedDoc(), UPDATE_CONTENT_MODEL, + true); + nsNodeUtils::ContentAppended(container, + container->GetChildAt(newIndexInContainer), + newIndexInContainer); + } + + NS_IF_RELEASE(container); + + return NS_OK; +} + +nsresult +nsXULContentBuilder::CreateContainerContentsForQuerySet(nsIContent* aElement, + nsIXULTemplateResult* aResult, + bool aNotify, + nsTemplateQuerySet* aQuerySet, + nsIContent** aContainer, + int32_t* aNewIndexInContainer) +{ + if (MOZ_LOG_TEST(gXULTemplateLog, LogLevel::Debug)) { + nsAutoString id; + aResult->GetId(id); + MOZ_LOG(gXULTemplateLog, LogLevel::Debug, + ("nsXULContentBuilder::CreateContainerContentsForQuerySet start for ref %s\n", + NS_ConvertUTF16toUTF8(id).get())); + } + + if (! mQueryProcessor) + return NS_OK; + + nsCOMPtr<nsISimpleEnumerator> results; + nsresult rv = mQueryProcessor->GenerateResults(mDataSource, aResult, + aQuerySet->mCompiledQuery, + getter_AddRefs(results)); + if (NS_FAILED(rv) || !results) + return rv; + + bool hasMoreResults; + rv = results->HasMoreElements(&hasMoreResults); + + for (; NS_SUCCEEDED(rv) && hasMoreResults; + rv = results->HasMoreElements(&hasMoreResults)) { + nsCOMPtr<nsISupports> nr; + rv = results->GetNext(getter_AddRefs(nr)); + if (NS_FAILED(rv)) + return rv; + + nsCOMPtr<nsIXULTemplateResult> nextresult = do_QueryInterface(nr); + if (!nextresult) + return NS_ERROR_UNEXPECTED; + + nsCOMPtr<nsIRDFResource> resultid; + rv = GetResultResource(nextresult, getter_AddRefs(resultid)); + if (NS_FAILED(rv)) + return rv; + + if (!resultid) + continue; + + nsTemplateMatch *newmatch = + nsTemplateMatch::Create(aQuerySet->Priority(), + nextresult, aElement); + if (!newmatch) + return NS_ERROR_OUT_OF_MEMORY; + + // check if there is already an existing match. If so, a previous + // query already generated content so the match is just added to the + // end of the set of matches. + + bool generateContent = true; + + nsTemplateMatch* prevmatch = nullptr; + nsTemplateMatch* existingmatch = nullptr; + nsTemplateMatch* removematch = nullptr; + if (mMatchMap.Get(resultid, &existingmatch)){ + // check if there is an existing match that matched a rule + while (existingmatch) { + // break out once we've reached a query in the list with a + // higher priority, as the new match list is sorted by + // priority, and the new match should be inserted here + int32_t priority = existingmatch->QuerySetPriority(); + if (priority > aQuerySet->Priority()) + break; + + // skip over non-matching containers + if (existingmatch->GetContainer() == aElement) { + // if the same priority is already found, replace it. This can happen + // when a container is removed and readded + if (priority == aQuerySet->Priority()) { + removematch = existingmatch; + break; + } + + if (existingmatch->IsActive()) + generateContent = false; + } + + prevmatch = existingmatch; + existingmatch = existingmatch->mNext; + } + } + + if (removematch) { + // remove the generated content for the existing match + rv = ReplaceMatch(removematch->mResult, nullptr, nullptr, aElement); + if (NS_FAILED(rv)) + return rv; + + if (mFlags & eLoggingEnabled) + OutputMatchToLog(resultid, removematch, false); + } + + if (generateContent) { + // find the rule that matches. If none match, the content does not + // need to be generated + + int16_t ruleindex; + nsTemplateRule* matchedrule = nullptr; + rv = DetermineMatchedRule(aElement, nextresult, aQuerySet, + &matchedrule, &ruleindex); + if (NS_FAILED(rv)) { + nsTemplateMatch::Destroy(newmatch, false); + return rv; + } + + if (matchedrule) { + rv = newmatch->RuleMatched(aQuerySet, matchedrule, + ruleindex, nextresult); + if (NS_FAILED(rv)) { + nsTemplateMatch::Destroy(newmatch, false); + return rv; + } + + // Grab the template node + nsCOMPtr<nsIContent> action = matchedrule->GetAction(); + BuildContentFromTemplate(action, aElement, aElement, true, + mRefVariable == matchedrule->GetMemberVariable(), + nextresult, aNotify, newmatch, + aContainer, aNewIndexInContainer); + } + } + + if (mFlags & eLoggingEnabled) + OutputMatchToLog(resultid, newmatch, true); + + if (prevmatch) { + prevmatch->mNext = newmatch; + } + else { + mMatchMap.Put(resultid, newmatch); + } + + if (removematch) { + newmatch->mNext = removematch->mNext; + nsTemplateMatch::Destroy(removematch, true); + } + else { + newmatch->mNext = existingmatch; + } + } + + return rv; +} + +nsresult +nsXULContentBuilder::EnsureElementHasGenericChild(nsIContent* parent, + int32_t nameSpaceID, + nsIAtom* tag, + bool aNotify, + nsIContent** result) +{ + nsresult rv; + + rv = nsXULContentUtils::FindChildByTag(parent, nameSpaceID, tag, result); + if (NS_FAILED(rv)) + return rv; + + if (rv == NS_RDF_NO_VALUE) { + // we need to construct a new child element. + nsCOMPtr<Element> element; + + rv = CreateElement(nameSpaceID, tag, getter_AddRefs(element)); + if (NS_FAILED(rv)) + return rv; + + // XXX Note that the notification ensures we won't batch insertions! This could be bad! - Dave + rv = parent->AppendChildTo(element, aNotify); + if (NS_FAILED(rv)) + return rv; + + element.forget(result); + return NS_ELEMENT_GOT_CREATED; + } + else { + return NS_ELEMENT_WAS_THERE; + } +} + +bool +nsXULContentBuilder::IsOpen(nsIContent* aElement) +{ + // Determine if this is a <treeitem> or <menu> element + + // XXXhyatt Use the XBL service to obtain a base tag. + if (aElement->IsAnyOfXULElements(nsGkAtoms::menu, + nsGkAtoms::menubutton, + nsGkAtoms::toolbarbutton, + nsGkAtoms::button, + nsGkAtoms::treeitem)) + return aElement->AttrValueIs(kNameSpaceID_None, nsGkAtoms::open, + nsGkAtoms::_true, eCaseMatters); + return true; +} + +nsresult +nsXULContentBuilder::RemoveGeneratedContent(nsIContent* aElement) +{ + // Keep a queue of "ungenerated" elements that we have to probe + // for generated content. + AutoTArray<nsIContent*, 8> ungenerated; + if (ungenerated.AppendElement(aElement) == nullptr) + return NS_ERROR_OUT_OF_MEMORY; + + uint32_t count; + while (0 != (count = ungenerated.Length())) { + // Pull the next "ungenerated" element off the queue. + uint32_t last = count - 1; + nsCOMPtr<nsIContent> element = ungenerated[last]; + ungenerated.RemoveElementAt(last); + + uint32_t i = element->GetChildCount(); + + while (i-- > 0) { + nsCOMPtr<nsIContent> child = element->GetChildAt(i); + + // Optimize for the <template> element, because we *know* + // it won't have any generated content: there's no reason + // to even check this subtree. + // XXX should this check |child| rather than |element|? Otherwise + // it should be moved outside the inner loop. Bug 297290. + if (element->NodeInfo()->Equals(nsGkAtoms::_template, + kNameSpaceID_XUL) || + !element->IsElement()) + continue; + + // If the element is in the template map, then we + // assume it's been generated and nuke it. + nsCOMPtr<nsIContent> tmpl; + mTemplateMap.GetTemplateFor(child, getter_AddRefs(tmpl)); + + if (! tmpl) { + // No 'template' attribute, so this must not have been + // generated. We'll need to examine its kids. + if (ungenerated.AppendElement(child) == nullptr) + return NS_ERROR_OUT_OF_MEMORY; + continue; + } + + // If we get here, it's "generated". Bye bye! + element->RemoveChildAt(i, true); + + // Remove this and any children from the content support map. + mContentSupportMap.Remove(child); + + // Remove from the template map + mTemplateMap.Remove(child); + } + } + + return NS_OK; +} + +nsresult +nsXULContentBuilder::GetElementsForResult(nsIXULTemplateResult* aResult, + nsCOMArray<nsIContent>& aElements) +{ + // if the root has been removed from the document, just return + // since there won't be any generated content any more + nsCOMPtr<nsIXULDocument> xuldoc = do_QueryInterface(mRoot->GetComposedDoc()); + if (! xuldoc) + return NS_OK; + + nsAutoString id; + aResult->GetId(id); + + xuldoc->GetElementsForID(id, aElements); + + return NS_OK; +} + +nsresult +nsXULContentBuilder::CreateElement(int32_t aNameSpaceID, + nsIAtom* aTag, + Element** aResult) +{ + nsCOMPtr<nsIDocument> doc = mRoot->GetComposedDoc(); + NS_ASSERTION(doc != nullptr, "not initialized"); + if (! doc) + return NS_ERROR_NOT_INITIALIZED; + + RefPtr<mozilla::dom::NodeInfo> nodeInfo = + doc->NodeInfoManager()->GetNodeInfo(aTag, nullptr, aNameSpaceID, + nsIDOMNode::ELEMENT_NODE); + + return NS_NewElement(aResult, nodeInfo.forget(), NOT_FROM_PARSER); +} + +nsresult +nsXULContentBuilder::SetContainerAttrs(nsIContent *aElement, + nsIXULTemplateResult* aResult, + bool aIgnoreNonContainers, + bool aNotify) +{ + NS_PRECONDITION(aResult != nullptr, "null ptr"); + if (! aResult) + return NS_ERROR_NULL_POINTER; + + bool iscontainer; + aResult->GetIsContainer(&iscontainer); + + if (aIgnoreNonContainers && !iscontainer) + return NS_OK; + + NS_NAMED_LITERAL_STRING(true_, "true"); + NS_NAMED_LITERAL_STRING(false_, "false"); + + const nsAString& newcontainer = + iscontainer ? true_ : false_; + + aElement->SetAttr(kNameSpaceID_None, nsGkAtoms::container, + newcontainer, aNotify); + + if (iscontainer && !(mFlags & eDontTestEmpty)) { + bool isempty; + aResult->GetIsEmpty(&isempty); + + const nsAString& newempty = + (iscontainer && isempty) ? true_ : false_; + + aElement->SetAttr(kNameSpaceID_None, nsGkAtoms::empty, + newempty, aNotify); + } + + return NS_OK; +} + + +//---------------------------------------------------------------------- +// +// nsIXULTemplateBuilder methods +// + +NS_IMETHODIMP +nsXULContentBuilder::CreateContents(nsIContent* aElement, bool aForceCreation) +{ + NS_PRECONDITION(aElement != nullptr, "null ptr"); + if (! aElement) + return NS_ERROR_NULL_POINTER; + + // don't build contents for closed elements. aForceCreation will be true + // when a menu is about to be opened, so the content should be built anyway. + if (!aForceCreation && !IsOpen(aElement)) + return NS_OK; + + return CreateTemplateAndContainerContents(aElement, aForceCreation); +} + +NS_IMETHODIMP +nsXULContentBuilder::HasGeneratedContent(nsIRDFResource* aResource, + nsIAtom* aTag, + bool* aGenerated) +{ + *aGenerated = false; + NS_ENSURE_TRUE(mRoot, NS_ERROR_NOT_INITIALIZED); + NS_ENSURE_STATE(mRootResult); + + nsCOMPtr<nsIRDFResource> rootresource; + nsresult rv = mRootResult->GetResource(getter_AddRefs(rootresource)); + if (NS_FAILED(rv)) + return rv; + + // the root resource is always acceptable + if (aResource == rootresource) { + if (!aTag || mRoot->NodeInfo()->NameAtom() == aTag) + *aGenerated = true; + } + else { + const char* uri; + aResource->GetValueConst(&uri); + + NS_ConvertUTF8toUTF16 refID(uri); + + // just return if the node is no longer in a document + nsCOMPtr<nsIXULDocument> xuldoc = do_QueryInterface(mRoot->GetComposedDoc()); + if (! xuldoc) + return NS_OK; + + nsCOMArray<nsIContent> elements; + xuldoc->GetElementsForID(refID, elements); + + uint32_t cnt = elements.Count(); + + for (int32_t i = int32_t(cnt) - 1; i >= 0; --i) { + nsCOMPtr<nsIContent> content = elements.SafeObjectAt(i); + + do { + nsTemplateMatch* match; + if (content == mRoot || mContentSupportMap.Get(content, &match)) { + // If we've got a tag, check it to ensure we're consistent. + if (!aTag || content->NodeInfo()->NameAtom() == aTag) { + *aGenerated = true; + return NS_OK; + } + } + + content = content->GetParent(); + } while (content); + } + } + + return NS_OK; +} + +NS_IMETHODIMP +nsXULContentBuilder::GetResultForContent(nsIDOMElement* aElement, + nsIXULTemplateResult** aResult) +{ + NS_ENSURE_ARG_POINTER(aElement); + NS_ENSURE_ARG_POINTER(aResult); + + nsCOMPtr<nsIContent> content = do_QueryInterface(aElement); + if (content == mRoot) { + *aResult = mRootResult; + } + else { + nsTemplateMatch *match = nullptr; + if (mContentSupportMap.Get(content, &match)) + *aResult = match->mResult; + else + *aResult = nullptr; + } + + NS_IF_ADDREF(*aResult); + return NS_OK; +} + +//---------------------------------------------------------------------- +// +// nsIDocumentObserver methods +// + +void +nsXULContentBuilder::AttributeChanged(nsIDocument* aDocument, + Element* aElement, + int32_t aNameSpaceID, + nsIAtom* aAttribute, + int32_t aModType, + const nsAttrValue* aOldValue) +{ + nsCOMPtr<nsIMutationObserver> kungFuDeathGrip(this); + + // Handle "open" and "close" cases. We do this handling before + // we've notified the observer, so that content is already created + // for the frame system to walk. + if (aElement->GetNameSpaceID() == kNameSpaceID_XUL && + aAttribute == nsGkAtoms::open) { + // We're on a XUL tag, and an ``open'' attribute changed. + if (aElement->AttrValueIs(kNameSpaceID_None, nsGkAtoms::open, + nsGkAtoms::_true, eCaseMatters)) + OpenContainer(aElement); + else + CloseContainer(aElement); + } + + if ((aNameSpaceID == kNameSpaceID_XUL) && + ((aAttribute == nsGkAtoms::sort) || + (aAttribute == nsGkAtoms::sortDirection) || + (aAttribute == nsGkAtoms::sortResource) || + (aAttribute == nsGkAtoms::sortResource2))) + mSortState.initialized = false; + + // Pass along to the generic template builder. + nsXULTemplateBuilder::AttributeChanged(aDocument, aElement, aNameSpaceID, + aAttribute, aModType, aOldValue); +} + +void +nsXULContentBuilder::NodeWillBeDestroyed(const nsINode* aNode) +{ + nsCOMPtr<nsIMutationObserver> kungFuDeathGrip(this); + // Break circular references + mContentSupportMap.Clear(); + + nsXULTemplateBuilder::NodeWillBeDestroyed(aNode); +} + + +//---------------------------------------------------------------------- +// +// nsXULTemplateBuilder methods +// + +bool +nsXULContentBuilder::GetInsertionLocations(nsIXULTemplateResult* aResult, + nsCOMArray<nsIContent>** aLocations) +{ + *aLocations = nullptr; + + nsAutoString ref; + nsresult rv = aResult->GetBindingFor(mRefVariable, ref); + if (NS_FAILED(rv)) + return false; + + nsCOMPtr<nsIXULDocument> xuldoc = do_QueryInterface(mRoot->GetComposedDoc()); + if (! xuldoc) + return false; + + *aLocations = new nsCOMArray<nsIContent>; + NS_ENSURE_TRUE(*aLocations, false); + + xuldoc->GetElementsForID(ref, **aLocations); + uint32_t count = (*aLocations)->Count(); + + bool found = false; + + for (uint32_t t = 0; t < count; t++) { + nsCOMPtr<nsIContent> content = (*aLocations)->SafeObjectAt(t); + + nsTemplateMatch* refmatch; + if (content == mRoot || mContentSupportMap.Get(content, &refmatch)) { + // See if we've built the container contents for "content" + // yet. If not, we don't need to build any content. This + // happens, for example, if we receive an assertion on a + // closed folder in a tree widget or on a menu that hasn't + // yet been opened. + nsXULElement *xulcontent = nsXULElement::FromContent(content); + if (!xulcontent || xulcontent->GetTemplateGenerated()) { + found = true; + continue; + } + } + + // clear the item in the list since we don't want to insert there + (*aLocations)->ReplaceObjectAt(nullptr, t); + } + + return found; +} + +nsresult +nsXULContentBuilder::ReplaceMatch(nsIXULTemplateResult* aOldResult, + nsTemplateMatch* aNewMatch, + nsTemplateRule* aNewMatchRule, + void *aContext) + +{ + nsresult rv; + nsIContent* content = static_cast<nsIContent*>(aContext); + + // update the container attributes for the match + if (content) { + nsAutoString ref; + if (aNewMatch) + rv = aNewMatch->mResult->GetBindingFor(mRefVariable, ref); + else + rv = aOldResult->GetBindingFor(mRefVariable, ref); + if (NS_FAILED(rv)) + return rv; + + if (!ref.IsEmpty()) { + nsCOMPtr<nsIXULTemplateResult> refResult; + rv = GetResultForId(ref, getter_AddRefs(refResult)); + if (NS_FAILED(rv)) + return rv; + + if (refResult) + SetContainerAttrs(content, refResult, false, true); + } + } + + if (aOldResult) { + nsCOMArray<nsIContent> elements; + rv = GetElementsForResult(aOldResult, elements); + if (NS_FAILED(rv)) + return rv; + + uint32_t count = elements.Count(); + + for (int32_t e = int32_t(count) - 1; e >= 0; --e) { + nsCOMPtr<nsIContent> child = elements.SafeObjectAt(e); + + nsTemplateMatch* match; + if (mContentSupportMap.Get(child, &match)) { + if (content == match->GetContainer()) + RemoveMember(child); + } + } + } + + if (aNewMatch) { + nsCOMPtr<nsIContent> action = aNewMatchRule->GetAction(); + return BuildContentFromTemplate(action, content, content, true, + mRefVariable == aNewMatchRule->GetMemberVariable(), + aNewMatch->mResult, true, aNewMatch, + nullptr, nullptr); + } + + return NS_OK; +} + + +nsresult +nsXULContentBuilder::SynchronizeResult(nsIXULTemplateResult* aResult) +{ + nsCOMArray<nsIContent> elements; + GetElementsForResult(aResult, elements); + + uint32_t cnt = elements.Count(); + + for (int32_t i = int32_t(cnt) - 1; i >= 0; --i) { + nsCOMPtr<nsIContent> element = elements.SafeObjectAt(i); + + nsTemplateMatch* match; + if (! mContentSupportMap.Get(element, &match)) + continue; + + nsCOMPtr<nsIContent> templateNode; + mTemplateMap.GetTemplateFor(element, getter_AddRefs(templateNode)); + + NS_ASSERTION(templateNode, "couldn't find template node for element"); + if (! templateNode) + continue; + + // this node was created by a XUL template, so update it accordingly + SynchronizeUsingTemplate(templateNode, element, aResult); + } + + return NS_OK; +} + +//---------------------------------------------------------------------- +// +// Implementation methods +// + +nsresult +nsXULContentBuilder::OpenContainer(nsIContent* aElement) +{ + if (aElement != mRoot) { + if (mFlags & eDontRecurse) + return NS_OK; + + bool rightBuilder = false; + + nsCOMPtr<nsIXULDocument> xuldoc = do_QueryInterface(aElement->GetComposedDoc()); + if (! xuldoc) + return NS_OK; + + // See if we're responsible for this element + nsIContent* content = aElement; + do { + nsCOMPtr<nsIXULTemplateBuilder> builder; + xuldoc->GetTemplateBuilderFor(content, getter_AddRefs(builder)); + if (builder) { + if (builder == this) + rightBuilder = true; + break; + } + + content = content->GetParent(); + } while (content); + + if (! rightBuilder) + return NS_OK; + } + + CreateTemplateAndContainerContents(aElement, false); + + return NS_OK; +} + +nsresult +nsXULContentBuilder::CloseContainer(nsIContent* aElement) +{ + return NS_OK; +} + +nsresult +nsXULContentBuilder::RebuildAll() +{ + NS_ENSURE_TRUE(mRoot, NS_ERROR_NOT_INITIALIZED); + + // Bail out early if we are being torn down. + nsCOMPtr<nsIDocument> doc = mRoot->GetComposedDoc(); + if (!doc) + return NS_OK; + + if (mQueriesCompiled) + Uninit(false); + + nsresult rv = CompileQueries(); + if (NS_FAILED(rv)) + return rv; + + if (mQuerySets.Length() == 0) + return NS_OK; + + nsXULElement *xulcontent = nsXULElement::FromContent(mRoot); + if (xulcontent) + xulcontent->ClearTemplateGenerated(); + + // Now, regenerate both the template- and container-generated + // contents for the current element... + CreateTemplateAndContainerContents(mRoot, false); + + return NS_OK; +} + +/**** Sorting Methods ****/ + +nsresult +nsXULContentBuilder::CompareResultToNode(nsIXULTemplateResult* aResult, + nsIContent* aContent, + int32_t* aSortOrder) +{ + NS_ASSERTION(aSortOrder, "CompareResultToNode: null out param aSortOrder"); + + *aSortOrder = 0; + + nsTemplateMatch *match = nullptr; + if (!mContentSupportMap.Get(aContent, &match)) { + *aSortOrder = mSortState.sortStaticsLast ? -1 : 1; + return NS_OK; + } + + if (!mQueryProcessor) + return NS_OK; + + if (mSortState.direction == nsSortState_natural) { + // sort in natural order + nsresult rv = mQueryProcessor->CompareResults(aResult, match->mResult, + nullptr, mSortState.sortHints, + aSortOrder); + NS_ENSURE_SUCCESS(rv, rv); + } + else { + // iterate over each sort key and compare. If the nodes are equal, + // continue to compare using the next sort key. If not equal, stop. + int32_t length = mSortState.sortKeys.Count(); + for (int32_t t = 0; t < length; t++) { + nsresult rv = mQueryProcessor->CompareResults(aResult, match->mResult, + mSortState.sortKeys[t], + mSortState.sortHints, aSortOrder); + NS_ENSURE_SUCCESS(rv, rv); + + if (*aSortOrder) + break; + } + } + + // flip the sort order if performing a descending sorting + if (mSortState.direction == nsSortState_descending) + *aSortOrder = -*aSortOrder; + + return NS_OK; +} + +nsresult +nsXULContentBuilder::InsertSortedNode(nsIContent* aContainer, + nsIContent* aNode, + nsIXULTemplateResult* aResult, + bool aNotify) +{ + nsresult rv; + + if (!mSortState.initialized) { + nsAutoString sort, sortDirection, sortHints; + mRoot->GetAttr(kNameSpaceID_None, nsGkAtoms::sort, sort); + mRoot->GetAttr(kNameSpaceID_None, nsGkAtoms::sortDirection, sortDirection); + mRoot->GetAttr(kNameSpaceID_None, nsGkAtoms::sorthints, sortHints); + sortDirection += ' '; + sortDirection += sortHints; + rv = XULSortServiceImpl::InitializeSortState(mRoot, aContainer, + sort, sortDirection, &mSortState); + NS_ENSURE_SUCCESS(rv, rv); + } + + // when doing a natural sort, items will typically be sorted according to + // the order they appear in the datasource. For RDF, cache whether the + // reference parent is an RDF Seq. That way, the items can be sorted in the + // order they are in the Seq. + mSortState.isContainerRDFSeq = false; + if (mSortState.direction == nsSortState_natural) { + nsCOMPtr<nsISupports> ref; + nsresult rv = aResult->GetBindingObjectFor(mRefVariable, getter_AddRefs(ref)); + NS_ENSURE_SUCCESS(rv, rv); + + nsCOMPtr<nsIRDFResource> container = do_QueryInterface(ref); + + if (container) { + rv = gRDFContainerUtils->IsSeq(mDB, container, &mSortState.isContainerRDFSeq); + NS_ENSURE_SUCCESS(rv, rv); + } + } + + bool childAdded = false; + uint32_t numChildren = aContainer->GetChildCount(); + + if (mSortState.direction != nsSortState_natural || + (mSortState.direction == nsSortState_natural && mSortState.isContainerRDFSeq)) + { + // because numChildren gets modified + int32_t realNumChildren = numChildren; + nsIContent *child = nullptr; + + // rjc says: determine where static XUL ends and generated XUL/RDF begins + int32_t staticCount = 0; + + nsAutoString staticValue; + aContainer->GetAttr(kNameSpaceID_None, nsGkAtoms::staticHint, staticValue); + if (!staticValue.IsEmpty()) + { + // found "static" XUL element count hint + nsresult strErr = NS_OK; + staticCount = staticValue.ToInteger(&strErr); + if (NS_FAILED(strErr)) + staticCount = 0; + } else { + // compute the "static" XUL element count + for (nsIContent* child = aContainer->GetFirstChild(); + child; + child = child->GetNextSibling()) { + + if (nsContentUtils::HasNonEmptyAttr(child, kNameSpaceID_None, + nsGkAtoms::_template)) + break; + else + ++staticCount; + } + + if (mSortState.sortStaticsLast) { + // indicate that static XUL comes after RDF-generated content by + // making negative + staticCount = -staticCount; + } + + // save the "static" XUL element count hint + nsAutoString valueStr; + valueStr.AppendInt(staticCount); + aContainer->SetAttr(kNameSpaceID_None, nsGkAtoms::staticHint, valueStr, false); + } + + if (staticCount <= 0) { + numChildren += staticCount; + staticCount = 0; + } else if (staticCount > (int32_t)numChildren) { + staticCount = numChildren; + numChildren -= staticCount; + } + + // figure out where to insert the node when a sort order is being imposed + if (numChildren > 0) { + nsIContent *temp; + int32_t direction; + + // rjc says: The following is an implementation of a fairly optimal + // binary search insertion sort... with interpolation at either end-point. + + if (mSortState.lastWasFirst) { + child = aContainer->GetChildAt(staticCount); + temp = child; + rv = CompareResultToNode(aResult, temp, &direction); + if (direction < 0) { + aContainer->InsertChildAt(aNode, staticCount, aNotify); + childAdded = true; + } else + mSortState.lastWasFirst = false; + } else if (mSortState.lastWasLast) { + child = aContainer->GetChildAt(realNumChildren - 1); + temp = child; + rv = CompareResultToNode(aResult, temp, &direction); + if (direction > 0) { + aContainer->InsertChildAt(aNode, realNumChildren, aNotify); + childAdded = true; + } else + mSortState.lastWasLast = false; + } + + int32_t left = staticCount + 1, right = realNumChildren, x; + while (!childAdded && right >= left) { + x = (left + right) / 2; + child = aContainer->GetChildAt(x - 1); + temp = child; + + rv = CompareResultToNode(aResult, temp, &direction); + if ((x == left && direction < 0) || + (x == right && direction >= 0) || + left == right) + { + int32_t thePos = (direction > 0 ? x : x - 1); + aContainer->InsertChildAt(aNode, thePos, aNotify); + childAdded = true; + + mSortState.lastWasFirst = (thePos == staticCount); + mSortState.lastWasLast = (thePos >= realNumChildren); + + break; + } + if (direction < 0) + right = x - 1; + else + left = x + 1; + } + } + } + + // if the child hasn't been inserted yet, just add it at the end. Note + // that an append isn't done as there may be static content afterwards. + if (!childAdded) + aContainer->InsertChildAt(aNode, numChildren, aNotify); + + return NS_OK; +} diff --git a/dom/xul/templates/nsXULContentUtils.cpp b/dom/xul/templates/nsXULContentUtils.cpp new file mode 100644 index 000000000..5e128b42e --- /dev/null +++ b/dom/xul/templates/nsXULContentUtils.cpp @@ -0,0 +1,366 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * + * 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/. + * + * + * This Original Code has been modified by IBM Corporation. + * Modifications made by IBM described herein are + * Copyright (c) International Business Machines + * Corporation, 2000 + * + * Modifications to Mozilla code or documentation + * identified per MPL Section 3.3 + * + * Date Modified by Description of modification + * 03/27/2000 IBM Corp. Added PR_CALLBACK for Optlink + * use in OS2 + */ + + +/* + + A package of routines shared by the XUL content code. + + */ + +#include "mozilla/ArrayUtils.h" + +#include "nsCOMPtr.h" +#include "nsIContent.h" +#include "nsIDocument.h" +#include "nsIDOMElement.h" +#include "nsIDOMXULCommandDispatcher.h" +#include "nsIDOMXULDocument.h" +#include "nsIRDFNode.h" +#include "nsIRDFService.h" +#include "nsIServiceManager.h" +#include "nsIURL.h" +#include "nsXULContentUtils.h" +#include "nsLayoutCID.h" +#include "nsNameSpaceManager.h" +#include "nsRDFCID.h" +#include "nsString.h" +#include "nsXPIDLString.h" +#include "nsGkAtoms.h" +#include "mozilla/Logging.h" +#include "prtime.h" +#include "rdf.h" +#include "nsContentUtils.h" +#include "nsIDateTimeFormat.h" +#include "nsIScriptableDateFormat.h" +#include "nsICollation.h" +#include "nsCollationCID.h" +#include "nsILocale.h" +#include "nsILocaleService.h" +#include "nsIConsoleService.h" +#include "nsEscape.h" + +using namespace mozilla; + +//------------------------------------------------------------------------ + +nsIRDFService* nsXULContentUtils::gRDF; +nsIDateTimeFormat* nsXULContentUtils::gFormat; +nsICollation *nsXULContentUtils::gCollation; + +extern LazyLogModule gXULTemplateLog; + +#define XUL_RESOURCE(ident, uri) nsIRDFResource* nsXULContentUtils::ident +#define XUL_LITERAL(ident, val) nsIRDFLiteral* nsXULContentUtils::ident +#include "nsXULResourceList.h" +#undef XUL_RESOURCE +#undef XUL_LITERAL + +//------------------------------------------------------------------------ +// Constructors n' stuff +// + +nsresult +nsXULContentUtils::Init() +{ + static NS_DEFINE_CID(kRDFServiceCID, NS_RDFSERVICE_CID); + nsresult rv = CallGetService(kRDFServiceCID, &gRDF); + if (NS_FAILED(rv)) { + return rv; + } + +#define XUL_RESOURCE(ident, uri) \ + PR_BEGIN_MACRO \ + rv = gRDF->GetResource(NS_LITERAL_CSTRING(uri), &(ident)); \ + if (NS_FAILED(rv)) return rv; \ + PR_END_MACRO + +#define XUL_LITERAL(ident, val) \ + PR_BEGIN_MACRO \ + rv = gRDF->GetLiteral(val, &(ident)); \ + if (NS_FAILED(rv)) return rv; \ + PR_END_MACRO + +#include "nsXULResourceList.h" +#undef XUL_RESOURCE +#undef XUL_LITERAL + + gFormat = nsIDateTimeFormat::Create().take(); + if (!gFormat) { + return NS_ERROR_FAILURE; + } + + return NS_OK; +} + + +nsresult +nsXULContentUtils::Finish() +{ + NS_IF_RELEASE(gRDF); + +#define XUL_RESOURCE(ident, uri) NS_IF_RELEASE(ident) +#define XUL_LITERAL(ident, val) NS_IF_RELEASE(ident) +#include "nsXULResourceList.h" +#undef XUL_RESOURCE +#undef XUL_LITERAL + + NS_IF_RELEASE(gFormat); + NS_IF_RELEASE(gCollation); + + return NS_OK; +} + +nsICollation* +nsXULContentUtils::GetCollation() +{ + if (!gCollation) { + nsresult rv; + + // get a locale service + nsCOMPtr<nsILocaleService> localeService = + do_GetService(NS_LOCALESERVICE_CONTRACTID, &rv); + if (NS_SUCCEEDED(rv)) { + nsCOMPtr<nsILocale> locale; + rv = localeService->GetApplicationLocale(getter_AddRefs(locale)); + if (NS_SUCCEEDED(rv) && locale) { + nsCOMPtr<nsICollationFactory> colFactory = + do_CreateInstance(NS_COLLATIONFACTORY_CONTRACTID); + if (colFactory) { + rv = colFactory->CreateCollation(locale, &gCollation); + NS_ASSERTION(NS_SUCCEEDED(rv), + "couldn't create collation instance"); + } else + NS_ERROR("couldn't create instance of collation factory"); + } else + NS_ERROR("unable to get application locale"); + } else + NS_ERROR("couldn't get locale factory"); + } + + return gCollation; +} + +//------------------------------------------------------------------------ + +nsresult +nsXULContentUtils::FindChildByTag(nsIContent* aElement, + int32_t aNameSpaceID, + nsIAtom* aTag, + nsIContent** aResult) +{ + for (nsIContent* child = aElement->GetFirstChild(); + child; + child = child->GetNextSibling()) { + + if (child->NodeInfo()->Equals(aTag, aNameSpaceID)) { + NS_ADDREF(*aResult = child); + + return NS_OK; + } + } + + *aResult = nullptr; + return NS_RDF_NO_VALUE; // not found +} + + +/* + Note: this routine is similar, yet distinctly different from, nsBookmarksService::GetTextForNode +*/ + +nsresult +nsXULContentUtils::GetTextForNode(nsIRDFNode* aNode, nsAString& aResult) +{ + if (! aNode) { + aResult.Truncate(); + return NS_OK; + } + + nsresult rv; + + // Literals are the most common, so try these first. + nsCOMPtr<nsIRDFLiteral> literal = do_QueryInterface(aNode); + if (literal) { + const char16_t* p; + rv = literal->GetValueConst(&p); + if (NS_FAILED(rv)) return rv; + + aResult = p; + return NS_OK; + } + + nsCOMPtr<nsIRDFDate> dateLiteral = do_QueryInterface(aNode); + if (dateLiteral) { + PRTime value; + rv = dateLiteral->GetValue(&value); + if (NS_FAILED(rv)) return rv; + + nsAutoString str; + rv = gFormat->FormatPRTime(nullptr /* nsILocale* locale */, + kDateFormatShort, + kTimeFormatSeconds, + value, + str); + aResult.Assign(str); + + if (NS_FAILED(rv)) return rv; + + return NS_OK; + } + + nsCOMPtr<nsIRDFInt> intLiteral = do_QueryInterface(aNode); + if (intLiteral) { + int32_t value; + rv = intLiteral->GetValue(&value); + if (NS_FAILED(rv)) return rv; + + aResult.Truncate(); + nsAutoString intStr; + intStr.AppendInt(value, 10); + aResult.Append(intStr); + return NS_OK; + } + + + nsCOMPtr<nsIRDFResource> resource = do_QueryInterface(aNode); + if (resource) { + const char* p; + rv = resource->GetValueConst(&p); + if (NS_FAILED(rv)) return rv; + CopyUTF8toUTF16(p, aResult); + return NS_OK; + } + + NS_ERROR("not a resource or a literal"); + return NS_ERROR_UNEXPECTED; +} + +nsresult +nsXULContentUtils::GetResource(int32_t aNameSpaceID, nsIAtom* aAttribute, nsIRDFResource** aResult) +{ + // construct a fully-qualified URI from the namespace/tag pair. + NS_PRECONDITION(aAttribute != nullptr, "null ptr"); + if (! aAttribute) + return NS_ERROR_NULL_POINTER; + + return GetResource(aNameSpaceID, nsDependentAtomString(aAttribute), + aResult); +} + + +nsresult +nsXULContentUtils::GetResource(int32_t aNameSpaceID, const nsAString& aAttribute, nsIRDFResource** aResult) +{ + // construct a fully-qualified URI from the namespace/tag pair. + + // XXX should we allow nodes with no namespace??? + //NS_PRECONDITION(aNameSpaceID != kNameSpaceID_Unknown, "no namespace"); + //if (aNameSpaceID == kNameSpaceID_Unknown) + // return NS_ERROR_UNEXPECTED; + + nsresult rv; + + char16_t buf[256]; + nsFixedString uri(buf, ArrayLength(buf), 0); + if (aNameSpaceID != kNameSpaceID_Unknown && aNameSpaceID != kNameSpaceID_None) { + rv = nsContentUtils::NameSpaceManager()->GetNameSpaceURI(aNameSpaceID, uri); + // XXX ignore failure; treat as "no namespace" + } + + // XXX check to see if we need to insert a '/' or a '#'. Oy. + if (!uri.IsEmpty() && uri.Last() != '#' && uri.Last() != '/' && aAttribute.First() != '#') + uri.Append(char16_t('#')); + + uri.Append(aAttribute); + + rv = gRDF->GetUnicodeResource(uri, aResult); + NS_ASSERTION(NS_SUCCEEDED(rv), "unable to get resource"); + if (NS_FAILED(rv)) return rv; + + return NS_OK; +} + + +nsresult +nsXULContentUtils::SetCommandUpdater(nsIDocument* aDocument, nsIContent* aElement) +{ + // Deal with setting up a 'commandupdater'. Pulls the 'events' and + // 'targets' attributes off of aElement, and adds it to the + // document's command dispatcher. + NS_PRECONDITION(aDocument != nullptr, "null ptr"); + if (! aDocument) + return NS_ERROR_NULL_POINTER; + + NS_PRECONDITION(aElement != nullptr, "null ptr"); + if (! aElement) + return NS_ERROR_NULL_POINTER; + + nsresult rv; + + nsCOMPtr<nsIDOMXULDocument> xuldoc = do_QueryInterface(aDocument); + NS_ASSERTION(xuldoc != nullptr, "not a xul document"); + if (! xuldoc) + return NS_ERROR_UNEXPECTED; + + nsCOMPtr<nsIDOMXULCommandDispatcher> dispatcher; + rv = xuldoc->GetCommandDispatcher(getter_AddRefs(dispatcher)); + NS_ASSERTION(NS_SUCCEEDED(rv), "unable to get dispatcher"); + if (NS_FAILED(rv)) return rv; + + NS_ASSERTION(dispatcher != nullptr, "no dispatcher"); + if (! dispatcher) + return NS_ERROR_UNEXPECTED; + + nsAutoString events; + aElement->GetAttr(kNameSpaceID_None, nsGkAtoms::events, events); + if (events.IsEmpty()) + events.Assign('*'); + + nsAutoString targets; + aElement->GetAttr(kNameSpaceID_None, nsGkAtoms::targets, targets); + + if (targets.IsEmpty()) + targets.Assign('*'); + + nsCOMPtr<nsIDOMElement> domelement = do_QueryInterface(aElement); + NS_ASSERTION(domelement != nullptr, "not a DOM element"); + if (! domelement) + return NS_ERROR_UNEXPECTED; + + rv = dispatcher->AddCommandUpdater(domelement, events, targets); + if (NS_FAILED(rv)) return rv; + + return NS_OK; +} + +void +nsXULContentUtils::LogTemplateError(const char* aStr) +{ + nsAutoString message; + message.AssignLiteral("Error parsing template: "); + message.Append(NS_ConvertUTF8toUTF16(aStr).get()); + + nsCOMPtr<nsIConsoleService> cs = do_GetService(NS_CONSOLESERVICE_CONTRACTID); + if (cs) { + cs->LogStringMessage(message.get()); + MOZ_LOG(gXULTemplateLog, LogLevel::Info, ("Error parsing template: %s", aStr)); + } +} diff --git a/dom/xul/templates/nsXULContentUtils.h b/dom/xul/templates/nsXULContentUtils.h new file mode 100644 index 000000000..c106fd91e --- /dev/null +++ b/dom/xul/templates/nsXULContentUtils.h @@ -0,0 +1,149 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* 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/. */ + +/* + + A package of routines shared by the XUL content code. + + */ + +#ifndef nsXULContentUtils_h__ +#define nsXULContentUtils_h__ + +#include "nsISupports.h" + +class nsIAtom; +class nsIContent; +class nsIDocument; +class nsIRDFNode; +class nsIRDFResource; +class nsIRDFLiteral; +class nsIRDFService; +class nsIDateTimeFormat; +class nsICollation; + +// errors to pass to LogTemplateError +#define ERROR_TEMPLATE_INVALID_QUERYPROCESSOR \ + "querytype attribute doesn't specify a valid query processor" +#define ERROR_TEMPLATE_INVALID_QUERYSET \ + "unexpected <queryset> element" +#define ERROR_TEMPLATE_NO_MEMBERVAR \ + "no member variable found. Action body should have an element with uri attribute" +#define ERROR_TEMPLATE_WHERE_NO_SUBJECT \ + "<where> element is missing a subject attribute" +#define ERROR_TEMPLATE_WHERE_NO_RELATION \ + "<where> element is missing a rel attribute" +#define ERROR_TEMPLATE_WHERE_NO_VALUE \ + "<where> element is missing a value attribute" +#define ERROR_TEMPLATE_WHERE_NO_VAR \ + "<where> element must have at least one variable as a subject or value" +#define ERROR_TEMPLATE_BINDING_BAD_SUBJECT \ + "<binding> requires a variable for its subject attribute" +#define ERROR_TEMPLATE_BINDING_BAD_PREDICATE \ + "<binding> element is missing a predicate attribute" +#define ERROR_TEMPLATE_BINDING_BAD_OBJECT \ + "<binding> requires a variable for its object attribute" +#define ERROR_TEMPLATE_CONTENT_NOT_FIRST \ + "expected <content> to be first" +#define ERROR_TEMPLATE_MEMBER_NOCONTAINERVAR \ + "<member> requires a variable for its container attribute" +#define ERROR_TEMPLATE_MEMBER_NOCHILDVAR \ + "<member> requires a variable for its child attribute" +#define ERROR_TEMPLATE_TRIPLE_NO_VAR \ + "<triple> should have at least one variable as a subject or object" +#define ERROR_TEMPLATE_TRIPLE_BAD_SUBJECT \ + "<triple> requires a variable for its subject attribute" +#define ERROR_TEMPLATE_TRIPLE_BAD_PREDICATE \ + "<triple> should have a non-variable value as a predicate" +#define ERROR_TEMPLATE_TRIPLE_BAD_OBJECT \ + "<triple> requires a variable for its object attribute" +#define ERROR_TEMPLATE_MEMBER_UNBOUND \ + "neither container or child variables of <member> has a value" +#define ERROR_TEMPLATE_TRIPLE_UNBOUND \ + "neither subject or object variables of <triple> has a value" +#define ERROR_TEMPLATE_BAD_XPATH \ + "XPath expression in query could not be parsed" +#define ERROR_TEMPLATE_BAD_ASSIGN_XPATH \ + "XPath expression in <assign> could not be parsed" +#define ERROR_TEMPLATE_BAD_BINDING_XPATH \ + "XPath expression in <binding> could not be parsed" +#define ERROR_TEMPLATE_STORAGE_BAD_URI \ + "only profile: or file URI are allowed" +#define ERROR_TEMPLATE_STORAGE_CANNOT_OPEN_DATABASE \ + "cannot open given database" +#define ERROR_TEMPLATE_STORAGE_BAD_QUERY \ + "syntax error in the SQL query" +#define ERROR_TEMPLATE_STORAGE_UNKNOWN_QUERY_PARAMETER \ + "the given named parameter is unknown in the SQL query" +#define ERROR_TEMPLATE_STORAGE_WRONG_TYPE_QUERY_PARAMETER \ + "the type of a query parameter is wrong" +#define ERROR_TEMPLATE_STORAGE_QUERY_PARAMETER_NOT_BOUND \ + "a query parameter cannot be bound to the SQL query" + +class nsXULContentUtils +{ +protected: + static nsIRDFService* gRDF; + static nsIDateTimeFormat* gFormat; + static nsICollation *gCollation; + + static bool gDisableXULCache; + + static int + DisableXULCacheChangedCallback(const char* aPrefName, void* aClosure); + +public: + static nsresult + Init(); + + static nsresult + Finish(); + + static nsresult + FindChildByTag(nsIContent *aElement, + int32_t aNameSpaceID, + nsIAtom* aTag, + nsIContent **aResult); + + static nsresult + FindChildByResource(nsIContent* aElement, + nsIRDFResource* aResource, + nsIContent** aResult); + + static nsresult + GetTextForNode(nsIRDFNode* aNode, nsAString& aResult); + + static nsresult + GetResource(int32_t aNameSpaceID, nsIAtom* aAttribute, nsIRDFResource** aResult); + + static nsresult + GetResource(int32_t aNameSpaceID, const nsAString& aAttribute, nsIRDFResource** aResult); + + static nsresult + SetCommandUpdater(nsIDocument* aDocument, nsIContent* aElement); + + /** + * Log a message to the error console + */ + static void + LogTemplateError(const char* aMsg); + + static nsIRDFService* + RDFService() + { + return gRDF; + } + + static nsICollation* + GetCollation(); + +#define XUL_RESOURCE(ident, uri) static nsIRDFResource* ident +#define XUL_LITERAL(ident, val) static nsIRDFLiteral* ident +#include "nsXULResourceList.h" +#undef XUL_RESOURCE +#undef XUL_LITERAL +}; + +#endif // nsXULContentUtils_h__ diff --git a/dom/xul/templates/nsXULResourceList.h b/dom/xul/templates/nsXULResourceList.h new file mode 100644 index 000000000..eaea7e996 --- /dev/null +++ b/dom/xul/templates/nsXULResourceList.h @@ -0,0 +1,13 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* 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/. */ + +// N.B., no include guard! We'll include this multiple times in some +// files. + +XUL_RESOURCE(NC_child, NC_NAMESPACE_URI "child"); +XUL_RESOURCE(NC_Folder, NC_NAMESPACE_URI "Folder"); +XUL_RESOURCE(NC_open, NC_NAMESPACE_URI "open"); + +XUL_LITERAL(true_, u"true"); diff --git a/dom/xul/templates/nsXULSortService.cpp b/dom/xul/templates/nsXULSortService.cpp new file mode 100644 index 000000000..ab3e13461 --- /dev/null +++ b/dom/xul/templates/nsXULSortService.cpp @@ -0,0 +1,507 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* 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/. + * + * This Original Code has been modified by IBM Corporation. + * Modifications made by IBM described herein are + * Copyright (c) International Business Machines + * Corporation, 2000 + * + * Modifications to Mozilla code or documentation + * identified per MPL Section 3.3 + * + * Date Modified by Description of modification + * 03/27/2000 IBM Corp. Added PR_CALLBACK for Optlink + * use in OS2 + */ + +/* + This file provides the implementation for the sort service manager. + */ + +#include "nsCOMPtr.h" +#include "nsIContent.h" +#include "nsIDOMElement.h" +#include "nsIDOMNode.h" +#include "nsIServiceManager.h" +#include "nsGkAtoms.h" +#include "nsNameSpaceManager.h" +#include "nsXULContentUtils.h" +#include "nsString.h" +#include "nsQuickSort.h" +#include "nsWhitespaceTokenizer.h" +#include "nsXULSortService.h" +#include "nsIDOMXULElement.h" +#include "nsIXULTemplateBuilder.h" +#include "nsTemplateMatch.h" +#include "nsICollation.h" +#include "nsUnicharUtils.h" + +NS_IMPL_ISUPPORTS(XULSortServiceImpl, nsIXULSortService) + +void +XULSortServiceImpl::SetSortHints(nsIContent *aNode, nsSortState* aSortState) +{ + // set sort and sortDirection attributes when is sort is done + aNode->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"); + aNode->SetAttr(kNameSpaceID_None, nsGkAtoms::sortDirection, + direction, true); + + // for trees, also set the sort info on the currently sorted column + if (aNode->NodeInfo()->Equals(nsGkAtoms::tree, kNameSpaceID_XUL)) { + if (aSortState->sortKeys.Count() >= 1) { + nsAutoString sortkey; + aSortState->sortKeys[0]->ToString(sortkey); + SetSortColumnHints(aNode, sortkey, direction); + } + } +} + +void +XULSortServiceImpl::SetSortColumnHints(nsIContent *content, + const nsAString &sortResource, + const nsAString &sortDirection) +{ + // set sort info on current column. This ensures that the + // column header sort indicator is updated properly. + for (nsIContent* child = content->GetFirstChild(); + child; + child = child->GetNextSibling()) { + if (child->IsXULElement(nsGkAtoms::treecols)) { + SetSortColumnHints(child, sortResource, sortDirection); + } else if (child->IsXULElement(nsGkAtoms::treecol)) { + nsAutoString value; + child->GetAttr(kNameSpaceID_None, nsGkAtoms::sort, value); + // also check the resource attribute for older code + if (value.IsEmpty()) + child->GetAttr(kNameSpaceID_None, nsGkAtoms::resource, value); + if (value == sortResource) { + child->SetAttr(kNameSpaceID_None, nsGkAtoms::sortActive, + NS_LITERAL_STRING("true"), true); + child->SetAttr(kNameSpaceID_None, nsGkAtoms::sortDirection, + sortDirection, true); + // Note: don't break out of loop; want to set/unset + // attribs on ALL sort columns + } else if (!value.IsEmpty()) { + child->UnsetAttr(kNameSpaceID_None, nsGkAtoms::sortActive, + true); + child->UnsetAttr(kNameSpaceID_None, nsGkAtoms::sortDirection, + true); + } + } + } +} + +nsresult +XULSortServiceImpl::GetItemsToSort(nsIContent *aContainer, + nsSortState* aSortState, + nsTArray<contentSortInfo>& aSortItems) +{ + // if there is a template attached to the sort node, use the builder to get + // the items to be sorted + nsCOMPtr<nsIDOMXULElement> element = do_QueryInterface(aContainer); + if (element) { + nsCOMPtr<nsIXULTemplateBuilder> builder; + element->GetBuilder(getter_AddRefs(builder)); + + if (builder) { + nsresult rv = builder->GetQueryProcessor(getter_AddRefs(aSortState->processor)); + if (NS_FAILED(rv) || !aSortState->processor) + return rv; + + return GetTemplateItemsToSort(aContainer, builder, aSortState, aSortItems); + } + } + + // if there is no template builder, just get the children. For trees, + // get the treechildren element as use that as the parent + nsCOMPtr<nsIContent> treechildren; + if (aContainer->NodeInfo()->Equals(nsGkAtoms::tree, kNameSpaceID_XUL)) { + nsXULContentUtils::FindChildByTag(aContainer, + kNameSpaceID_XUL, + nsGkAtoms::treechildren, + getter_AddRefs(treechildren)); + if (!treechildren) + return NS_OK; + + aContainer = treechildren; + } + + for (nsIContent* child = aContainer->GetFirstChild(); + child; + child = child->GetNextSibling()) { + contentSortInfo* cinfo = aSortItems.AppendElement(); + if (!cinfo) + return NS_ERROR_OUT_OF_MEMORY; + + cinfo->content = child; + } + + return NS_OK; +} + + +nsresult +XULSortServiceImpl::GetTemplateItemsToSort(nsIContent* aContainer, + nsIXULTemplateBuilder* aBuilder, + nsSortState* aSortState, + nsTArray<contentSortInfo>& aSortItems) +{ + for (nsIContent* child = aContainer->GetFirstChild(); + child; + child = child->GetNextSibling()) { + + nsCOMPtr<nsIDOMElement> childnode = do_QueryInterface(child); + + nsCOMPtr<nsIXULTemplateResult> result; + nsresult rv = aBuilder->GetResultForContent(childnode, getter_AddRefs(result)); + NS_ENSURE_SUCCESS(rv, rv); + + if (result) { + contentSortInfo* cinfo = aSortItems.AppendElement(); + if (!cinfo) + return NS_ERROR_OUT_OF_MEMORY; + + cinfo->content = child; + cinfo->result = result; + } + else if (!aContainer->IsXULElement(nsGkAtoms::_template)) { + rv = GetTemplateItemsToSort(child, aBuilder, aSortState, aSortItems); + NS_ENSURE_SUCCESS(rv, rv); + } + } + + return NS_OK; +} + +int +testSortCallback(const void *data1, const void *data2, void *privateData) +{ + /// Note: testSortCallback is a small C callback stub for NS_QuickSort + contentSortInfo *left = (contentSortInfo *)data1; + contentSortInfo *right = (contentSortInfo *)data2; + nsSortState* sortState = (nsSortState *)privateData; + + int32_t sortOrder = 0; + + if (sortState->direction == nsSortState_natural && sortState->processor) { + // sort in natural order + sortState->processor->CompareResults(left->result, right->result, + nullptr, sortState->sortHints, &sortOrder); + } + else { + int32_t length = sortState->sortKeys.Count(); + for (int32_t t = 0; t < length; t++) { + // for templates, use the query processor to do sorting + if (sortState->processor) { + sortState->processor->CompareResults(left->result, right->result, + sortState->sortKeys[t], + sortState->sortHints, &sortOrder); + if (sortOrder) + break; + } + else { + // no template, so just compare attributes. Ignore namespaces for now. + nsAutoString leftstr, rightstr; + left->content->GetAttr(kNameSpaceID_None, sortState->sortKeys[t], leftstr); + right->content->GetAttr(kNameSpaceID_None, sortState->sortKeys[t], rightstr); + + sortOrder = XULSortServiceImpl::CompareValues(leftstr, rightstr, sortState->sortHints); + } + } + } + + if (sortState->direction == nsSortState_descending) + sortOrder = -sortOrder; + + return sortOrder; +} + +nsresult +XULSortServiceImpl::SortContainer(nsIContent *aContainer, nsSortState* aSortState) +{ + nsTArray<contentSortInfo> items; + nsresult rv = GetItemsToSort(aContainer, aSortState, items); + NS_ENSURE_SUCCESS(rv, rv); + + uint32_t numResults = items.Length(); + if (!numResults) + return NS_OK; + + uint32_t i; + + // inbetweenSeparatorSort sorts the items between separators independently + if (aSortState->inbetweenSeparatorSort) { + uint32_t startIndex = 0; + for (i = 0; i < numResults; i++) { + if (i > startIndex + 1) { + nsAutoString type; + items[i].result->GetType(type); + if (type.EqualsLiteral("separator")) { + if (aSortState->invertSort) + InvertSortInfo(items, startIndex, i - startIndex); + else + NS_QuickSort((void *)(items.Elements() + startIndex), i - startIndex, + sizeof(contentSortInfo), testSortCallback, (void*)aSortState); + + startIndex = i + 1; + } + } + } + + if (i > startIndex + 1) { + if (aSortState->invertSort) + InvertSortInfo(items, startIndex, i - startIndex); + else + NS_QuickSort((void *)(items.Elements() + startIndex), i - startIndex, + sizeof(contentSortInfo), testSortCallback, (void*)aSortState); + } + } else { + // 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); + } + + // first remove the items from the old positions + for (i = 0; i < numResults; i++) { + nsIContent* child = items[i].content; + 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. + items[i].parent = parent; + int32_t index = parent->IndexOf(child); + parent->RemoveChildAt(index, true); + } + } + + // now add the items back in sorted order + for (i = 0; i < numResults; i++) + { + nsIContent* child = items[i].content; + nsIContent* parent = items[i].parent; + if (parent) { + parent->AppendChildTo(child, true); + + // if it's a container in a tree or menu, find its children, + // and sort those also + if (!child->AttrValueIs(kNameSpaceID_None, nsGkAtoms::container, + nsGkAtoms::_true, eCaseMatters)) + continue; + + for (nsIContent* grandchild = child->GetFirstChild(); + grandchild; + grandchild = grandchild->GetNextSibling()) { + mozilla::dom::NodeInfo *ni = grandchild->NodeInfo(); + nsIAtom *localName = ni->NameAtom(); + if (ni->NamespaceID() == kNameSpaceID_XUL && + (localName == nsGkAtoms::treechildren || + localName == nsGkAtoms::menupopup)) { + SortContainer(grandchild, aSortState); + } + } + } + } + + return NS_OK; +} + +nsresult +XULSortServiceImpl::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; +} + +nsresult +XULSortServiceImpl::InitializeSortState(nsIContent* aRootElement, + nsIContent* aContainer, + const nsAString& aSortKey, + const nsAString& aSortHints, + nsSortState* aSortState) +{ + // used as an optimization for the content builder + if (aContainer != aSortState->lastContainer.get()) { + aSortState->lastContainer = aContainer; + aSortState->lastWasFirst = false; + aSortState->lastWasLast = false; + } + + // The attributes allowed are either: + // sort="key1 key2 ..." + // or sortResource="key1" sortResource2="key2" + // The latter is for backwards compatibility, and is equivalent to concatenating + // both values in the sort attribute + nsAutoString sort(aSortKey); + aSortState->sortKeys.Clear(); + if (sort.IsEmpty()) { + nsAutoString sortResource, sortResource2; + aRootElement->GetAttr(kNameSpaceID_None, nsGkAtoms::sortResource, sortResource); + if (!sortResource.IsEmpty()) { + nsCOMPtr<nsIAtom> sortkeyatom = NS_Atomize(sortResource); + aSortState->sortKeys.AppendObject(sortkeyatom); + sort.Append(sortResource); + + aRootElement->GetAttr(kNameSpaceID_None, nsGkAtoms::sortResource2, sortResource2); + if (!sortResource2.IsEmpty()) { + nsCOMPtr<nsIAtom> sortkeyatom2 = NS_Atomize(sortResource2); + aSortState->sortKeys.AppendObject(sortkeyatom2); + sort.Append(' '); + sort.Append(sortResource2); + } + } + } + else { + nsWhitespaceTokenizer tokenizer(sort); + while (tokenizer.hasMoreTokens()) { + nsCOMPtr<nsIAtom> keyatom = NS_Atomize(tokenizer.nextToken()); + NS_ENSURE_TRUE(keyatom, NS_ERROR_OUT_OF_MEMORY); + aSortState->sortKeys.AppendObject(keyatom); + } + } + + aSortState->sort.Assign(sort); + aSortState->direction = nsSortState_natural; + + bool noNaturalState = false; + nsWhitespaceTokenizer tokenizer(aSortHints); + while (tokenizer.hasMoreTokens()) { + const nsDependentSubstring& token(tokenizer.nextToken()); + if (token.EqualsLiteral("comparecase")) + aSortState->sortHints |= nsIXULSortService::SORT_COMPARECASE; + else if (token.EqualsLiteral("integer")) + aSortState->sortHints |= nsIXULSortService::SORT_INTEGER; + else if (token.EqualsLiteral("descending")) + aSortState->direction = nsSortState_descending; + else if (token.EqualsLiteral("ascending")) + aSortState->direction = nsSortState_ascending; + else if (token.EqualsLiteral("twostate")) + noNaturalState = true; + } + + // if the twostate flag was set, the natural order is skipped and only + // ascending and descending are allowed + if (aSortState->direction == nsSortState_natural && noNaturalState) { + aSortState->direction = nsSortState_ascending; + } + + // set up sort order info + aSortState->invertSort = false; + + nsAutoString existingsort; + aRootElement->GetAttr(kNameSpaceID_None, nsGkAtoms::sort, existingsort); + nsAutoString existingsortDirection; + aRootElement->GetAttr(kNameSpaceID_None, nsGkAtoms::sortDirection, existingsortDirection); + + // if just switching direction, set the invertSort flag + if (sort.Equals(existingsort)) { + if (aSortState->direction == nsSortState_descending) { + if (existingsortDirection.EqualsLiteral("ascending")) + aSortState->invertSort = true; + } + else if (aSortState->direction == nsSortState_ascending && + existingsortDirection.EqualsLiteral("descending")) { + aSortState->invertSort = true; + } + } + + // sort items between separators independently + aSortState->inbetweenSeparatorSort = + aRootElement->AttrValueIs(kNameSpaceID_None, nsGkAtoms::sortSeparators, + nsGkAtoms::_true, eCaseMatters); + + // sort static content (non template generated nodes) after generated content + aSortState->sortStaticsLast = aRootElement->AttrValueIs(kNameSpaceID_None, + nsGkAtoms::sortStaticsLast, + nsGkAtoms::_true, eCaseMatters); + + aSortState->initialized = true; + + return NS_OK; +} + +int32_t +XULSortServiceImpl::CompareValues(const nsAString& aLeft, + const nsAString& aRight, + uint32_t aSortHints) +{ + if (aSortHints & SORT_INTEGER) { + 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 + } + + if (aSortHints & SORT_COMPARECASE) { + 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()); +} + +NS_IMETHODIMP +XULSortServiceImpl::Sort(nsIDOMNode* aNode, + const nsAString& aSortKey, + const nsAString& aSortHints) +{ + // get root content node + nsCOMPtr<nsIContent> sortNode = do_QueryInterface(aNode); + if (!sortNode) + return NS_ERROR_FAILURE; + + nsSortState sortState; + nsresult rv = InitializeSortState(sortNode, sortNode, + aSortKey, aSortHints, &sortState); + NS_ENSURE_SUCCESS(rv, rv); + + // store sort info in attributes on content + SetSortHints(sortNode, &sortState); + rv = SortContainer(sortNode, &sortState); + + sortState.processor = nullptr; // don't hang on to this reference + return rv; +} + +nsresult +NS_NewXULSortService(nsIXULSortService** sortService) +{ + *sortService = new XULSortServiceImpl(); + NS_ADDREF(*sortService); + return NS_OK; +} diff --git a/dom/xul/templates/nsXULSortService.h b/dom/xul/templates/nsXULSortService.h new file mode 100644 index 000000000..306481e0d --- /dev/null +++ b/dom/xul/templates/nsXULSortService.h @@ -0,0 +1,187 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* 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/. + * + * This Original Code has been modified by IBM Corporation. + * Modifications made by IBM described herein are + * Copyright (c) International Business Machines + * Corporation, 2000 + * + * Modifications to Mozilla code or documentation + * identified per MPL Section 3.3 + * + * Date Modified by Description of modification + * 03/27/2000 IBM Corp. Added PR_CALLBACK for Optlink + * use in OS2 + */ + +/* + This sort service is used to sort template built content or content by attribute. + */ + +#ifndef nsXULTemplateResultSetRDF_h +#define nsXULTemplateResultSetRDF_h + +#include "nsCOMPtr.h" +#include "nsCOMArray.h" +#include "nsTArray.h" +#include "nsIContent.h" +#include "nsIXULTemplateResult.h" +#include "nsIXULTemplateQueryProcessor.h" +#include "nsIXULSortService.h" +#include "nsCycleCollectionParticipant.h" + +enum nsSortState_direction { + nsSortState_descending, + nsSortState_ascending, + nsSortState_natural +}; + +// the sort state holds info about the current sort +struct nsSortState +{ + bool initialized; + MOZ_INIT_OUTSIDE_CTOR bool invertSort; + MOZ_INIT_OUTSIDE_CTOR bool inbetweenSeparatorSort; + MOZ_INIT_OUTSIDE_CTOR bool sortStaticsLast; + MOZ_INIT_OUTSIDE_CTOR bool isContainerRDFSeq; + + uint32_t sortHints; + + MOZ_INIT_OUTSIDE_CTOR nsSortState_direction direction; + nsAutoString sort; + nsCOMArray<nsIAtom> sortKeys; + + nsCOMPtr<nsIXULTemplateQueryProcessor> processor; + nsCOMPtr<nsIContent> lastContainer; + MOZ_INIT_OUTSIDE_CTOR bool lastWasFirst, lastWasLast; + + nsSortState() + : initialized(false), + isContainerRDFSeq(false), + sortHints(0) + { + } + void Traverse(nsCycleCollectionTraversalCallback &cb) const + { + cb.NoteXPCOMChild(processor); + cb.NoteXPCOMChild(lastContainer); + } +}; + +// information about a particular item to be sorted +struct contentSortInfo { + nsCOMPtr<nsIContent> content; + nsCOMPtr<nsIContent> parent; + nsCOMPtr<nsIXULTemplateResult> result; + void swap(contentSortInfo& other) + { + content.swap(other.content); + parent.swap(other.parent); + result.swap(other.result); + } +}; + +//////////////////////////////////////////////////////////////////////// +// ServiceImpl +// +// This is the sort service. +// +class XULSortServiceImpl : public nsIXULSortService +{ +protected: + XULSortServiceImpl(void) {} + virtual ~XULSortServiceImpl(void) {} + + friend nsresult NS_NewXULSortService(nsIXULSortService** mgr); + +private: + +public: + // nsISupports + NS_DECL_ISUPPORTS + + // nsISortService + NS_DECL_NSIXULSORTSERVICE + + /** + * Set sort and sortDirection attributes when a sort is done. + */ + void + SetSortHints(nsIContent *aNode, nsSortState* aSortState); + + /** + * 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. + */ + void + SetSortColumnHints(nsIContent *content, + const nsAString &sortResource, + const nsAString &sortDirection); + + /** + * 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 + */ + nsresult + GetItemsToSort(nsIContent *aContainer, + nsSortState* aSortState, + nsTArray<contentSortInfo>& aSortItems); + + /** + * Get the list of items to sort for template built content + */ + nsresult + GetTemplateItemsToSort(nsIContent* aContainer, + nsIXULTemplateBuilder* aBuilder, + nsSortState* aSortState, + nsTArray<contentSortInfo>& aSortItems); + + /** + * Sort a container using the supplied sort state details. + */ + nsresult + SortContainer(nsIContent *aContainer, nsSortState* aSortState); + + /** + * Given a list of sortable items, reverse the list. This is done + * when simply changing the sort direction for the same key. + */ + nsresult + InvertSortInfo(nsTArray<contentSortInfo>& aData, + int32_t aStart, int32_t aNumItems); + + /** + * 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(nsIContent* aRootElement, + nsIContent* aContainer, + const nsAString& aSortKey, + const nsAString& aSortDirection, + nsSortState* aSortState); + + /** + * 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); +}; + +#endif diff --git a/dom/xul/templates/nsXULTemplateBuilder.cpp b/dom/xul/templates/nsXULTemplateBuilder.cpp new file mode 100644 index 000000000..49fb3335d --- /dev/null +++ b/dom/xul/templates/nsXULTemplateBuilder.cpp @@ -0,0 +1,2573 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* 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/. */ + +/* + + Builds content from a datasource using the XUL <template> tag. + + TO DO + + . Fix ContentTagTest's location in the network construction + + To turn on logging for this module, set: + + MOZ_LOG=nsXULTemplateBuilder:5 + + */ + +#include "nsAutoPtr.h" +#include "nsCOMPtr.h" +#include "nsCRT.h" +#include "nsIContent.h" +#include "nsIDOMElement.h" +#include "nsIDOMNode.h" +#include "nsIDOMDocument.h" +#include "nsIDOMXULElement.h" +#include "nsIDocument.h" +#include "nsBindingManager.h" +#include "nsIDOMNodeList.h" +#include "nsIObserverService.h" +#include "nsIRDFCompositeDataSource.h" +#include "nsIRDFInferDataSource.h" +#include "nsIRDFContainerUtils.h" +#include "nsIXULDocument.h" +#include "nsIXULTemplateBuilder.h" +#include "nsIXULBuilderListener.h" +#include "nsIRDFRemoteDataSource.h" +#include "nsIRDFService.h" +#include "nsIScriptContext.h" +#include "nsIScriptGlobalObject.h" +#include "nsIServiceManager.h" +#include "nsISimpleEnumerator.h" +#include "nsIMutableArray.h" +#include "nsIURL.h" +#include "nsIXPConnect.h" +#include "nsContentCID.h" +#include "nsNameSpaceManager.h" +#include "nsRDFCID.h" +#include "nsXULContentUtils.h" +#include "nsString.h" +#include "nsTArray.h" +#include "nsXPIDLString.h" +#include "nsWhitespaceTokenizer.h" +#include "nsGkAtoms.h" +#include "nsXULElement.h" +#include "jsapi.h" +#include "mozilla/Logging.h" +#include "rdf.h" +#include "PLDHashTable.h" +#include "plhash.h" +#include "nsDOMClassInfoID.h" +#include "nsPIDOMWindow.h" +#include "nsIConsoleService.h" +#include "nsNetUtil.h" +#include "nsXULTemplateBuilder.h" +#include "nsXULTemplateQueryProcessorRDF.h" +#include "nsXULTemplateQueryProcessorXML.h" +#include "nsXULTemplateQueryProcessorStorage.h" +#include "nsContentUtils.h" +#include "ChildIterator.h" +#include "mozilla/dom/ScriptSettings.h" +#include "nsGlobalWindow.h" + +using namespace mozilla::dom; +using namespace mozilla; + +//---------------------------------------------------------------------- +// +// nsXULTemplateBuilder +// + +nsrefcnt nsXULTemplateBuilder::gRefCnt = 0; +nsIRDFService* nsXULTemplateBuilder::gRDFService; +nsIRDFContainerUtils* nsXULTemplateBuilder::gRDFContainerUtils; +nsIScriptSecurityManager* nsXULTemplateBuilder::gScriptSecurityManager; +nsIPrincipal* nsXULTemplateBuilder::gSystemPrincipal; +nsIObserverService* nsXULTemplateBuilder::gObserverService; + +LazyLogModule gXULTemplateLog("nsXULTemplateBuilder"); + +#define NS_QUERY_PROCESSOR_CONTRACTID_PREFIX "@mozilla.org/xul/xul-query-processor;1?name=" + +//---------------------------------------------------------------------- +// +// nsXULTemplateBuilder methods +// + +nsXULTemplateBuilder::nsXULTemplateBuilder(void) + : mQueriesCompiled(false), + mFlags(0), + mTop(nullptr), + mObservedDocument(nullptr) +{ + MOZ_COUNT_CTOR(nsXULTemplateBuilder); +} + +void +nsXULTemplateBuilder::DestroyMatchMap() +{ + for (auto iter = mMatchMap.Iter(); !iter.Done(); iter.Next()) { + nsTemplateMatch*& match = iter.Data(); + // delete all the matches in the list + while (match) { + nsTemplateMatch* next = match->mNext; + nsTemplateMatch::Destroy(match, true); + match = next; + } + + iter.Remove(); + } +} + +nsXULTemplateBuilder::~nsXULTemplateBuilder(void) +{ + Uninit(true); + + if (--gRefCnt == 0) { + NS_IF_RELEASE(gRDFService); + NS_IF_RELEASE(gRDFContainerUtils); + NS_IF_RELEASE(gSystemPrincipal); + NS_IF_RELEASE(gScriptSecurityManager); + NS_IF_RELEASE(gObserverService); + } + + MOZ_COUNT_DTOR(nsXULTemplateBuilder); +} + + +nsresult +nsXULTemplateBuilder::InitGlobals() +{ + nsresult rv; + + if (gRefCnt++ == 0) { + // Initialize the global shared reference to the service + // manager and get some shared resource objects. + NS_DEFINE_CID(kRDFServiceCID, NS_RDFSERVICE_CID); + rv = CallGetService(kRDFServiceCID, &gRDFService); + if (NS_FAILED(rv)) + return rv; + + NS_DEFINE_CID(kRDFContainerUtilsCID, NS_RDFCONTAINERUTILS_CID); + rv = CallGetService(kRDFContainerUtilsCID, &gRDFContainerUtils); + if (NS_FAILED(rv)) + return rv; + + rv = CallGetService(NS_SCRIPTSECURITYMANAGER_CONTRACTID, + &gScriptSecurityManager); + if (NS_FAILED(rv)) + return rv; + + rv = gScriptSecurityManager->GetSystemPrincipal(&gSystemPrincipal); + if (NS_FAILED(rv)) + return rv; + + rv = CallGetService(NS_OBSERVERSERVICE_CONTRACTID, &gObserverService); + if (NS_FAILED(rv)) + return rv; + } + + return NS_OK; +} + +void +nsXULTemplateBuilder::StartObserving(nsIDocument* aDocument) +{ + aDocument->AddObserver(this); + mObservedDocument = aDocument; + gObserverService->AddObserver(this, DOM_WINDOW_DESTROYED_TOPIC, false); +} + +void +nsXULTemplateBuilder::StopObserving() +{ + MOZ_ASSERT(mObservedDocument); + mObservedDocument->RemoveObserver(this); + mObservedDocument = nullptr; + gObserverService->RemoveObserver(this, DOM_WINDOW_DESTROYED_TOPIC); +} + +void +nsXULTemplateBuilder::CleanUp(bool aIsFinal) +{ + for (int32_t q = mQuerySets.Length() - 1; q >= 0; q--) { + nsTemplateQuerySet* qs = mQuerySets[q]; + delete qs; + } + + mQuerySets.Clear(); + + DestroyMatchMap(); + + // Setting mQueryProcessor to null will close connections. This would be + // handled by the cycle collector, but we want to close them earlier. + if (aIsFinal) + mQueryProcessor = nullptr; +} + +void +nsXULTemplateBuilder::Uninit(bool aIsFinal) +{ + if (mObservedDocument && aIsFinal) { + StopObserving(); + } + + if (mQueryProcessor) + mQueryProcessor->Done(); + + CleanUp(aIsFinal); + + mRootResult = nullptr; + mRefVariable = nullptr; + mMemberVariable = nullptr; + + mQueriesCompiled = false; +} + +NS_IMPL_CYCLE_COLLECTION_CLASS(nsXULTemplateBuilder) + +NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(nsXULTemplateBuilder) + NS_IMPL_CYCLE_COLLECTION_UNLINK(mDataSource) + NS_IMPL_CYCLE_COLLECTION_UNLINK(mDB) + NS_IMPL_CYCLE_COLLECTION_UNLINK(mCompDB) + NS_IMPL_CYCLE_COLLECTION_UNLINK(mRoot) + NS_IMPL_CYCLE_COLLECTION_UNLINK(mRootResult) + NS_IMPL_CYCLE_COLLECTION_UNLINK(mListeners) + NS_IMPL_CYCLE_COLLECTION_UNLINK(mQueryProcessor) + tmp->DestroyMatchMap(); + for (uint32_t i = 0; i < tmp->mQuerySets.Length(); ++i) { + nsTemplateQuerySet* qs = tmp->mQuerySets[i]; + delete qs; + } + tmp->mQuerySets.Clear(); +NS_IMPL_CYCLE_COLLECTION_UNLINK_END +NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(nsXULTemplateBuilder) + if (tmp->mObservedDocument && !cb.WantAllTraces()) { + // The global observer service holds us alive. + return NS_SUCCESS_INTERRUPTED_TRAVERSE; + } + + NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mDataSource) + NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mDB) + NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mCompDB) + NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mRoot) + NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mRootResult) + NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mListeners) + NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mQueryProcessor) + + for (auto iter = tmp->mMatchMap.Iter(); !iter.Done(); iter.Next()) { + cb.NoteXPCOMChild(iter.Key()); + nsTemplateMatch* match = iter.UserData(); + while (match) { + cb.NoteXPCOMChild(match->GetContainer()); + cb.NoteXPCOMChild(match->mResult); + match = match->mNext; + } + } + + { + uint32_t i, count = tmp->mQuerySets.Length(); + for (i = 0; i < count; ++i) { + nsTemplateQuerySet *set = tmp->mQuerySets[i]; + cb.NoteXPCOMChild(set->mQueryNode); + cb.NoteXPCOMChild(set->mCompiledQuery); + uint16_t j, rulesCount = set->RuleCount(); + for (j = 0; j < rulesCount; ++j) { + set->GetRuleAt(j)->Traverse(cb); + } + } + } + tmp->Traverse(cb); +NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END + +NS_IMPL_CYCLE_COLLECTING_ADDREF(nsXULTemplateBuilder) +NS_IMPL_CYCLE_COLLECTING_RELEASE(nsXULTemplateBuilder) + +NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(nsXULTemplateBuilder) + NS_INTERFACE_MAP_ENTRY(nsIXULTemplateBuilder) + NS_INTERFACE_MAP_ENTRY(nsIDocumentObserver) + NS_INTERFACE_MAP_ENTRY(nsIMutationObserver) + NS_INTERFACE_MAP_ENTRY(nsIObserver) + NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIXULTemplateBuilder) + NS_DOM_INTERFACE_MAP_ENTRY_CLASSINFO(XULTemplateBuilder) +NS_INTERFACE_MAP_END + +//---------------------------------------------------------------------- +// +// nsIXULTemplateBuilder methods +// + +NS_IMETHODIMP +nsXULTemplateBuilder::GetRoot(nsIDOMElement** aResult) +{ + if (mRoot) { + return CallQueryInterface(mRoot, aResult); + } + *aResult = nullptr; + return NS_OK; +} + +NS_IMETHODIMP +nsXULTemplateBuilder::GetDatasource(nsISupports** aResult) +{ + if (mCompDB) + NS_ADDREF(*aResult = mCompDB); + else + NS_IF_ADDREF(*aResult = mDataSource); + return NS_OK; +} + +NS_IMETHODIMP +nsXULTemplateBuilder::SetDatasource(nsISupports* aResult) +{ + mDataSource = aResult; + mCompDB = do_QueryInterface(mDataSource); + + return Rebuild(); +} + +NS_IMETHODIMP +nsXULTemplateBuilder::GetDatabase(nsIRDFCompositeDataSource** aResult) +{ + NS_IF_ADDREF(*aResult = mCompDB); + return NS_OK; +} + +NS_IMETHODIMP +nsXULTemplateBuilder::GetQueryProcessor(nsIXULTemplateQueryProcessor** aResult) +{ + NS_IF_ADDREF(*aResult = mQueryProcessor.get()); + return NS_OK; +} + +NS_IMETHODIMP +nsXULTemplateBuilder::AddRuleFilter(nsIDOMNode* aRule, nsIXULTemplateRuleFilter* aFilter) +{ + if (!aRule || !aFilter) + return NS_ERROR_NULL_POINTER; + + // a custom rule filter may be added, one for each rule. If a new one is + // added, it replaces the old one. Look for the right rule and set its + // filter + + int32_t count = mQuerySets.Length(); + for (int32_t q = 0; q < count; q++) { + nsTemplateQuerySet* queryset = mQuerySets[q]; + + int16_t rulecount = queryset->RuleCount(); + for (int16_t r = 0; r < rulecount; r++) { + nsTemplateRule* rule = queryset->GetRuleAt(r); + + nsCOMPtr<nsIDOMNode> rulenode; + rule->GetRuleNode(getter_AddRefs(rulenode)); + if (aRule == rulenode) { + rule->SetRuleFilter(aFilter); + return NS_OK; + } + } + } + + return NS_OK; +} + +NS_IMETHODIMP +nsXULTemplateBuilder::Rebuild() +{ + int32_t i; + + for (i = mListeners.Count() - 1; i >= 0; --i) { + mListeners[i]->WillRebuild(this); + } + + nsresult rv = RebuildAll(); + + for (i = mListeners.Count() - 1; i >= 0; --i) { + mListeners[i]->DidRebuild(this); + } + + return rv; +} + +NS_IMETHODIMP +nsXULTemplateBuilder::Refresh() +{ + nsresult rv; + + if (!mCompDB) + return NS_ERROR_FAILURE; + + nsCOMPtr<nsISimpleEnumerator> dslist; + rv = mCompDB->GetDataSources(getter_AddRefs(dslist)); + NS_ENSURE_SUCCESS(rv, rv); + + bool hasMore; + nsCOMPtr<nsISupports> next; + nsCOMPtr<nsIRDFRemoteDataSource> rds; + + while(NS_SUCCEEDED(dslist->HasMoreElements(&hasMore)) && hasMore) { + dslist->GetNext(getter_AddRefs(next)); + if (next && (rds = do_QueryInterface(next))) { + rds->Refresh(false); + } + } + + // XXXbsmedberg: it would be kinda nice to install an async nsIRDFXMLSink + // observer and call rebuild() once the load is complete. See bug 254600. + + return NS_OK; +} + +NS_IMETHODIMP +nsXULTemplateBuilder::Init(nsIContent* aElement) +{ + NS_ENSURE_TRUE(aElement, NS_ERROR_NULL_POINTER); + mRoot = aElement; + + nsCOMPtr<nsIDocument> doc = mRoot->GetComposedDoc(); + NS_ASSERTION(doc, "element has no document"); + if (! doc) + return NS_ERROR_UNEXPECTED; + + bool shouldDelay; + nsresult rv = LoadDataSources(doc, &shouldDelay); + + if (NS_SUCCEEDED(rv)) { + StartObserving(doc); + } + + return rv; +} + +NS_IMETHODIMP +nsXULTemplateBuilder::CreateContents(nsIContent* aElement, bool aForceCreation) +{ + return NS_OK; +} + +NS_IMETHODIMP +nsXULTemplateBuilder::HasGeneratedContent(nsIRDFResource* aResource, + nsIAtom* aTag, + bool* aGenerated) +{ + *aGenerated = false; + return NS_OK; +} + +NS_IMETHODIMP +nsXULTemplateBuilder::AddResult(nsIXULTemplateResult* aResult, + nsIDOMNode* aQueryNode) +{ + NS_ENSURE_ARG_POINTER(aResult); + NS_ENSURE_ARG_POINTER(aQueryNode); + + return UpdateResult(nullptr, aResult, aQueryNode); +} + +NS_IMETHODIMP +nsXULTemplateBuilder::RemoveResult(nsIXULTemplateResult* aResult) +{ + NS_ENSURE_ARG_POINTER(aResult); + + return UpdateResult(aResult, nullptr, nullptr); +} + +NS_IMETHODIMP +nsXULTemplateBuilder::ReplaceResult(nsIXULTemplateResult* aOldResult, + nsIXULTemplateResult* aNewResult, + nsIDOMNode* aQueryNode) +{ + NS_ENSURE_ARG_POINTER(aOldResult); + NS_ENSURE_ARG_POINTER(aNewResult); + NS_ENSURE_ARG_POINTER(aQueryNode); + + // just remove the old result and then add a new result separately + + nsresult rv = UpdateResult(aOldResult, nullptr, nullptr); + if (NS_FAILED(rv)) + return rv; + + return UpdateResult(nullptr, aNewResult, aQueryNode); +} + +nsresult +nsXULTemplateBuilder::UpdateResult(nsIXULTemplateResult* aOldResult, + nsIXULTemplateResult* aNewResult, + nsIDOMNode* aQueryNode) +{ + MOZ_LOG(gXULTemplateLog, LogLevel::Info, + ("nsXULTemplateBuilder::UpdateResult %p %p %p", + aOldResult, aNewResult, aQueryNode)); + + if (!mRoot || !mQueriesCompiled) + return NS_OK; + + // get the containers where content may be inserted. If + // GetInsertionLocations returns false, no container has generated + // any content yet so new content should not be generated either. This + // will be false if the result applies to content that is in a closed menu + // or treeitem for example. + + nsAutoPtr<nsCOMArray<nsIContent> > insertionPoints; + bool mayReplace = GetInsertionLocations(aOldResult ? aOldResult : aNewResult, + getter_Transfers(insertionPoints)); + if (! mayReplace) + return NS_OK; + + nsresult rv = NS_OK; + + nsCOMPtr<nsIRDFResource> oldId, newId; + nsTemplateQuerySet* queryset = nullptr; + + if (aOldResult) { + rv = GetResultResource(aOldResult, getter_AddRefs(oldId)); + if (NS_FAILED(rv)) + return rv; + + // Ignore re-entrant builds for content that is currently in our + // activation stack. + if (IsActivated(oldId)) + return NS_OK; + } + + if (aNewResult) { + rv = GetResultResource(aNewResult, getter_AddRefs(newId)); + if (NS_FAILED(rv)) + return rv; + + // skip results that don't have ids + if (! newId) + return NS_OK; + + // Ignore re-entrant builds for content that is currently in our + // activation stack. + if (IsActivated(newId)) + return NS_OK; + + // look for the queryset associated with the supplied query node + nsCOMPtr<nsIContent> querycontent = do_QueryInterface(aQueryNode); + + int32_t count = mQuerySets.Length(); + for (int32_t q = 0; q < count; q++) { + nsTemplateQuerySet* qs = mQuerySets[q]; + if (qs->mQueryNode == querycontent) { + queryset = qs; + break; + } + } + + if (! queryset) + return NS_OK; + } + + if (insertionPoints) { + // iterate over each insertion point and add or remove the result from + // that container + uint32_t count = insertionPoints->Count(); + for (uint32_t t = 0; t < count; t++) { + nsCOMPtr<nsIContent> insertionPoint = insertionPoints->SafeObjectAt(t); + if (insertionPoint) { + rv = UpdateResultInContainer(aOldResult, aNewResult, queryset, + oldId, newId, insertionPoint); + if (NS_FAILED(rv)) + return rv; + } + } + } + else { + // The tree builder doesn't use insertion points, so no insertion + // points will be set. In this case, just update the one result. + rv = UpdateResultInContainer(aOldResult, aNewResult, queryset, + oldId, newId, nullptr); + } + + return NS_OK; +} + +nsresult +nsXULTemplateBuilder::UpdateResultInContainer(nsIXULTemplateResult* aOldResult, + nsIXULTemplateResult* aNewResult, + nsTemplateQuerySet* aQuerySet, + nsIRDFResource* aOldId, + nsIRDFResource* aNewId, + nsIContent* aInsertionPoint) +{ + // This method takes a result that no longer applies (aOldResult) and + // replaces it with a new result (aNewResult). Either may be null + // indicating to just remove a result or add a new one without replacing. + // + // Matches are stored in the hashtable mMatchMap, keyed by result id. If + // there is more than one query, or the same id is found in different + // containers, the values in the hashtable will be a linked list of all + // the matches for that id. The matches are sorted according to the + // queries they are associated with. Matches for earlier queries in the + // template take priority over matches from later queries. The priority + // for a match is determined from the match's QuerySetPriority method. + // The first query has a priority 0, and higher numbers are for later + // queries with successively higher priorities. Thus, a match takes + // precedence if it has a lower priority than another. If there is only + // one query or container, then the match doesn't have any linked items. + // + // Matches are nsTemplateMatch objects. They are wrappers around + // nsIXULTemplateResult result objects and are created with + // nsTemplateMatch::Create below. The aQuerySet argument specifies which + // query the match is associated with. + // + // When a result id exists in multiple containers, the match's mContainer + // field is set to the container it corresponds to. The aInsertionPoint + // argument specifies which container is being updated. Even though they + // are stored in the same linked list as other matches of the same id, the + // matches for different containers are treated separately. They are only + // stored in the same hashtable to avoid a more complex data structure, as + // the use of the same id in multiple containers isn't a common occurance. + // + // Only one match with a given id per container is active at a time. When + // a match is active, content is generated for it. When a match is + // inactive, content is not generated for it. A match becomes active if + // another match with the same id and container with a lower priority + // isn't already active, and the match has a rule or conditions clause + // which evaluates to true. The former is checked by comparing the value + // of the QuerySetPriority method of the match with earlier matches. The + // latter is checked with the DetermineMatchedRule method. + // + // Naturally, if a match with a lower priority is active, it overrides + // the new match, so the new match is hooked up into the match linked + // list as inactive, and no content is generated for it. If a match with a + // higher priority is active, and the new match's conditions evaluate + // to true, then this existing match with the higher priority needs to have + // its generated content removed and replaced with the new match's + // generated content. + // + // Similar situations apply when removing an existing match. If the match + // is active, the existing generated content will need to be removed, and + // a match of higher priority that is revealed may become active and need + // to have content generated. + // + // Content removal and generation is done by the ReplaceMatch method which + // is overridden for the content builder and tree builder to update the + // generated output for each type. + // + // The code below handles all of the various cases and ensures that the + // match lists are maintained properly. + + nsresult rv = NS_OK; + int16_t ruleindex; + nsTemplateRule* matchedrule = nullptr; + + // Indicates that the old match was active and must have its content + // removed + bool oldMatchWasActive = false; + + // acceptedmatch will be set to a new match that has to have new content + // generated for it. If a new match doesn't need to have content + // generated, (because for example, a match with a lower priority + // already applies), then acceptedmatch will be null, but the match will + // be still hooked up into the chain, since it may become active later + // as other results are updated. + nsTemplateMatch* acceptedmatch = nullptr; + + // When aOldResult is specified, removematch will be set to the + // corresponding match. This match needs to be deleted as it no longer + // applies. However, removedmatch will be null when aOldResult is null, or + // when no match was found corresponding to aOldResult. + nsTemplateMatch* removedmatch = nullptr; + + // These will be set when aNewResult is specified indicating to add a + // result, but will end up replacing an existing match. The former + // indicates a match being replaced that was active and had content + // generated for it, while the latter indicates a match that wasn't active + // and just needs to be deleted. Both may point to different matches. For + // example, if the new match becomes active, replacing an inactive match, + // the inactive match will need to be deleted. However, if another match + // with a higher priority is active, the new match will override it, so + // content will need to be generated for the new match and removed for + // this existing active match. + nsTemplateMatch* replacedmatch = nullptr; + nsTemplateMatch* replacedmatchtodelete = nullptr; + + if (aOldResult) { + nsTemplateMatch* firstmatch; + if (mMatchMap.Get(aOldId, &firstmatch)) { + nsTemplateMatch* oldmatch = firstmatch; + nsTemplateMatch* prevmatch = nullptr; + + // look for the right match if there was more than one + while (oldmatch && (oldmatch->mResult != aOldResult)) { + prevmatch = oldmatch; + oldmatch = oldmatch->mNext; + } + + if (oldmatch) { + nsTemplateMatch* findmatch = oldmatch->mNext; + + // Keep a reference so that linked list can be hooked up at + // the end in case an error occurs. + nsTemplateMatch* nextmatch = findmatch; + + if (oldmatch->IsActive()) { + // Indicate that the old match was active so its content + // will be removed later. + oldMatchWasActive = true; + + // The match being removed is the active match, so scan + // through the later matches to determine if one should + // now become the active match. + while (findmatch) { + // only other matches with the same container should + // now match, leave other containers alone + if (findmatch->GetContainer() == aInsertionPoint) { + nsTemplateQuerySet* qs = + mQuerySets[findmatch->QuerySetPriority()]; + + DetermineMatchedRule(aInsertionPoint, findmatch->mResult, + qs, &matchedrule, &ruleindex); + + if (matchedrule) { + rv = findmatch->RuleMatched(qs, + matchedrule, ruleindex, + findmatch->mResult); + if (NS_FAILED(rv)) + return rv; + + acceptedmatch = findmatch; + break; + } + } + + findmatch = findmatch->mNext; + } + } + + if (oldmatch == firstmatch) { + // the match to remove is at the beginning + if (oldmatch->mNext) { + mMatchMap.Put(aOldId, oldmatch->mNext); + } + else { + mMatchMap.Remove(aOldId); + } + } + + if (prevmatch) + prevmatch->mNext = nextmatch; + + removedmatch = oldmatch; + if (mFlags & eLoggingEnabled) + OutputMatchToLog(aOldId, removedmatch, false); + } + } + } + + nsTemplateMatch *newmatch = nullptr; + if (aNewResult) { + // only allow a result to be inserted into containers with a matching tag + nsIAtom* tag = aQuerySet->GetTag(); + if (aInsertionPoint && tag && + tag != aInsertionPoint->NodeInfo()->NameAtom()) + return NS_OK; + + int32_t findpriority = aQuerySet->Priority(); + + newmatch = nsTemplateMatch::Create(findpriority, + aNewResult, aInsertionPoint); + if (!newmatch) + return NS_ERROR_OUT_OF_MEMORY; + + nsTemplateMatch* firstmatch; + if (mMatchMap.Get(aNewId, &firstmatch)) { + bool hasEarlierActiveMatch = false; + + // Scan through the existing matches to find where the new one + // should be inserted. oldmatch will be set to the old match for + // the same query and prevmatch will be set to the match before it. + nsTemplateMatch* prevmatch = nullptr; + nsTemplateMatch* oldmatch = firstmatch; + while (oldmatch) { + // Break out once we've reached a query in the list with a + // lower priority. The new match will be inserted at this + // location so that the match list is sorted by priority. + int32_t priority = oldmatch->QuerySetPriority(); + if (priority > findpriority) { + oldmatch = nullptr; + break; + } + + // look for matches that belong in the same container + if (oldmatch->GetContainer() == aInsertionPoint) { + if (priority == findpriority) + break; + + // If a match with a lower priority is active, the new + // match can't replace it. + if (oldmatch->IsActive()) + hasEarlierActiveMatch = true; + } + + prevmatch = oldmatch; + oldmatch = oldmatch->mNext; + } + + // At this point, oldmatch will either be null, or set to a match + // with the same container and priority. If set, oldmatch will + // need to be replaced by newmatch. + + if (oldmatch) + newmatch->mNext = oldmatch->mNext; + else if (prevmatch) + newmatch->mNext = prevmatch->mNext; + else + newmatch->mNext = firstmatch; + + // hasEarlierActiveMatch will be set to true if a match with a + // lower priority was found. The new match won't replace it in + // this case. If hasEarlierActiveMatch is false, then the new match + // may be become active if it matches one of the rules, and will + // generate output. It's also possible however, that a match with + // the same priority already exists, which means that the new match + // will replace the old one. In this case, oldmatch will be set to + // the old match. The content for the old match must be removed and + // content for the new match generated in its place. + if (! hasEarlierActiveMatch) { + // If the old match was the active match, set replacedmatch to + // indicate that it needs its content removed. + if (oldmatch) { + if (oldmatch->IsActive()) + replacedmatch = oldmatch; + replacedmatchtodelete = oldmatch; + } + + // check if the new result matches the rules + rv = DetermineMatchedRule(aInsertionPoint, newmatch->mResult, + aQuerySet, &matchedrule, &ruleindex); + if (NS_FAILED(rv)) { + nsTemplateMatch::Destroy(newmatch, false); + return rv; + } + + if (matchedrule) { + rv = newmatch->RuleMatched(aQuerySet, + matchedrule, ruleindex, + newmatch->mResult); + if (NS_FAILED(rv)) { + nsTemplateMatch::Destroy(newmatch, false); + return rv; + } + + // acceptedmatch may have been set in the block handling + // aOldResult earlier. If so, we would only get here when + // that match has a higher priority than this new match. + // As only one match can have content generated for it, it + // is OK to set acceptedmatch here to the new match, + // ignoring the other one. + acceptedmatch = newmatch; + + // Clear the matched state of the later results for the + // same container. + nsTemplateMatch* clearmatch = newmatch->mNext; + while (clearmatch) { + if (clearmatch->GetContainer() == aInsertionPoint && + clearmatch->IsActive()) { + clearmatch->SetInactive(); + // Replacedmatch should be null here. If not, it + // means that two matches were active which isn't + // a valid state + NS_ASSERTION(!replacedmatch, + "replaced match already set"); + replacedmatch = clearmatch; + break; + } + clearmatch = clearmatch->mNext; + } + } + else if (oldmatch && oldmatch->IsActive()) { + // The result didn't match the rules, so look for a later + // one. However, only do this if the old match was the + // active match. + newmatch = newmatch->mNext; + while (newmatch) { + if (newmatch->GetContainer() == aInsertionPoint) { + rv = DetermineMatchedRule(aInsertionPoint, newmatch->mResult, + aQuerySet, &matchedrule, &ruleindex); + if (NS_FAILED(rv)) { + nsTemplateMatch::Destroy(newmatch, false); + return rv; + } + + if (matchedrule) { + rv = newmatch->RuleMatched(aQuerySet, + matchedrule, ruleindex, + newmatch->mResult); + if (NS_FAILED(rv)) { + nsTemplateMatch::Destroy(newmatch, false); + return rv; + } + + acceptedmatch = newmatch; + break; + } + } + + newmatch = newmatch->mNext; + } + } + + // put the match in the map if there isn't a previous match + if (! prevmatch) { + mMatchMap.Put(aNewId, newmatch); + } + } + + // hook up the match last in case an error occurs + if (prevmatch) + prevmatch->mNext = newmatch; + } + else { + // The id is not used in the hashtable yet so create a new match + // and add it to the hashtable. + rv = DetermineMatchedRule(aInsertionPoint, aNewResult, + aQuerySet, &matchedrule, &ruleindex); + if (NS_FAILED(rv)) { + nsTemplateMatch::Destroy(newmatch, false); + return rv; + } + + if (matchedrule) { + rv = newmatch->RuleMatched(aQuerySet, matchedrule, + ruleindex, aNewResult); + if (NS_FAILED(rv)) { + nsTemplateMatch::Destroy(newmatch, false); + return rv; + } + + acceptedmatch = newmatch; + } + + mMatchMap.Put(aNewId, newmatch); + } + } + + // The ReplaceMatch method is builder specific and removes the generated + // content for a match. + + // Remove the content for a match that was active and needs to be replaced. + if (replacedmatch) { + rv = ReplaceMatch(replacedmatch->mResult, nullptr, nullptr, + aInsertionPoint); + + if (mFlags & eLoggingEnabled) + OutputMatchToLog(aNewId, replacedmatch, false); + } + + // remove a match that needs to be deleted. + if (replacedmatchtodelete) + nsTemplateMatch::Destroy(replacedmatchtodelete, true); + + // If the old match was active, the content for it needs to be removed. + // If the old match was not active, it shouldn't have had any content, + // so just pass null to ReplaceMatch. If acceptedmatch was set, then + // content needs to be generated for a new match. + if (oldMatchWasActive || acceptedmatch) + rv = ReplaceMatch(oldMatchWasActive ? aOldResult : nullptr, + acceptedmatch, matchedrule, aInsertionPoint); + + // delete the old match that was replaced + if (removedmatch) + nsTemplateMatch::Destroy(removedmatch, true); + + if (mFlags & eLoggingEnabled && newmatch) + OutputMatchToLog(aNewId, newmatch, true); + + return rv; +} + +NS_IMETHODIMP +nsXULTemplateBuilder::ResultBindingChanged(nsIXULTemplateResult* aResult) +{ + // A binding update is used when only the values of the bindings have + // changed, so the same rule still applies. Just synchronize the content. + // The new result will have the new values. + NS_ENSURE_ARG_POINTER(aResult); + + if (!mRoot || !mQueriesCompiled) + return NS_OK; + + return SynchronizeResult(aResult); +} + +NS_IMETHODIMP +nsXULTemplateBuilder::GetRootResult(nsIXULTemplateResult** aResult) +{ + *aResult = mRootResult; + NS_IF_ADDREF(*aResult); + return NS_OK; +} + +NS_IMETHODIMP +nsXULTemplateBuilder::GetResultForId(const nsAString& aId, + nsIXULTemplateResult** aResult) +{ + if (aId.IsEmpty()) + return NS_ERROR_INVALID_ARG; + + nsCOMPtr<nsIRDFResource> resource; + gRDFService->GetUnicodeResource(aId, getter_AddRefs(resource)); + + *aResult = nullptr; + + nsTemplateMatch* match; + if (mMatchMap.Get(resource, &match)) { + // find the active match + while (match) { + if (match->IsActive()) { + *aResult = match->mResult; + NS_IF_ADDREF(*aResult); + break; + } + match = match->mNext; + } + } + + return NS_OK; +} + +NS_IMETHODIMP +nsXULTemplateBuilder::GetResultForContent(nsIDOMElement* aContent, + nsIXULTemplateResult** aResult) +{ + *aResult = nullptr; + return NS_OK; +} + +NS_IMETHODIMP +nsXULTemplateBuilder::AddListener(nsIXULBuilderListener* aListener) +{ + NS_ENSURE_ARG(aListener); + + if (!mListeners.AppendObject(aListener)) + return NS_ERROR_OUT_OF_MEMORY; + + return NS_OK; +} + +NS_IMETHODIMP +nsXULTemplateBuilder::RemoveListener(nsIXULBuilderListener* aListener) +{ + NS_ENSURE_ARG(aListener); + + mListeners.RemoveObject(aListener); + + return NS_OK; +} + +NS_IMETHODIMP +nsXULTemplateBuilder::Observe(nsISupports* aSubject, + const char* aTopic, + const char16_t* aData) +{ + // Uuuuber hack to clean up circular references that the cycle collector + // doesn't know about. See bug 394514. + if (!strcmp(aTopic, DOM_WINDOW_DESTROYED_TOPIC)) { + if (nsCOMPtr<mozIDOMWindow> window = do_QueryInterface(aSubject)) { + nsCOMPtr<nsIDocument> doc = + nsPIDOMWindowInner::From(window)->GetExtantDoc(); + if (doc && doc == mObservedDocument) + NodeWillBeDestroyed(doc); + } + } + return NS_OK; +} +//---------------------------------------------------------------------- +// +// nsIDocumentOberver interface +// + +void +nsXULTemplateBuilder::AttributeChanged(nsIDocument* aDocument, + Element* aElement, + int32_t aNameSpaceID, + nsIAtom* aAttribute, + int32_t aModType, + const nsAttrValue* aOldValue) +{ + if (aElement == mRoot && aNameSpaceID == kNameSpaceID_None) { + // Check for a change to the 'ref' attribute on an atom, in which + // case we may need to nuke and rebuild the entire content model + // beneath the element. + if (aAttribute == nsGkAtoms::ref) + nsContentUtils::AddScriptRunner( + NewRunnableMethod(this, &nsXULTemplateBuilder::RunnableRebuild)); + + // Check for a change to the 'datasources' attribute. If so, setup + // mDB by parsing the new value and rebuild. + else if (aAttribute == nsGkAtoms::datasources) { + nsContentUtils::AddScriptRunner( + NewRunnableMethod(this, &nsXULTemplateBuilder::RunnableLoadAndRebuild)); + } + } +} + +void +nsXULTemplateBuilder::ContentRemoved(nsIDocument* aDocument, + nsIContent* aContainer, + nsIContent* aChild, + int32_t aIndexInContainer, + nsIContent* aPreviousSibling) +{ + if (mRoot && nsContentUtils::ContentIsDescendantOf(mRoot, aChild)) { + RefPtr<nsXULTemplateBuilder> kungFuDeathGrip(this); + + if (mQueryProcessor) + mQueryProcessor->Done(); + + // Pass false to Uninit since content is going away anyway + nsContentUtils::AddScriptRunner( + NewRunnableMethod(this, &nsXULTemplateBuilder::UninitFalse)); + + MOZ_ASSERT(aDocument == mObservedDocument); + StopObserving(); + + nsCOMPtr<nsIXULDocument> xuldoc = do_QueryInterface(aDocument); + if (xuldoc) + xuldoc->SetTemplateBuilderFor(mRoot, nullptr); + + // clear the template state when removing content so that template + // content will be regenerated again if the content is reinserted + nsXULElement *xulcontent = nsXULElement::FromContent(mRoot); + if (xulcontent) + xulcontent->ClearTemplateGenerated(); + + CleanUp(true); + + mDB = nullptr; + mCompDB = nullptr; + mDataSource = nullptr; + } +} + +void +nsXULTemplateBuilder::NodeWillBeDestroyed(const nsINode* aNode) +{ + // The call to RemoveObserver could release the last reference to + // |this|, so hold another reference. + RefPtr<nsXULTemplateBuilder> kungFuDeathGrip(this); + + // Break circular references + if (mQueryProcessor) + mQueryProcessor->Done(); + + mDataSource = nullptr; + mDB = nullptr; + mCompDB = nullptr; + + nsContentUtils::AddScriptRunner( + NewRunnableMethod(this, &nsXULTemplateBuilder::UninitTrue)); +} + + + + +//---------------------------------------------------------------------- +// +// Implementation methods +// + +nsresult +nsXULTemplateBuilder::LoadDataSources(nsIDocument* aDocument, + bool* aShouldDelayBuilding) +{ + NS_PRECONDITION(mRoot != nullptr, "not initialized"); + + nsresult rv; + bool isRDFQuery = false; + + // we'll set these again later, after we create a new composite ds + mDB = nullptr; + mCompDB = nullptr; + mDataSource = nullptr; + + *aShouldDelayBuilding = false; + + nsAutoString datasources; + mRoot->GetAttr(kNameSpaceID_None, nsGkAtoms::datasources, datasources); + + nsAutoString querytype; + mRoot->GetAttr(kNameSpaceID_None, nsGkAtoms::querytype, querytype); + + // create the query processor. The querytype attribute on the root element + // may be used to create one of a specific type. + + // XXX should non-chrome be restricted to specific names? + if (querytype.IsEmpty()) + querytype.AssignLiteral("rdf"); + + if (querytype.EqualsLiteral("rdf")) { + isRDFQuery = true; + mQueryProcessor = new nsXULTemplateQueryProcessorRDF(); + } + else if (querytype.EqualsLiteral("xml")) { + mQueryProcessor = new nsXULTemplateQueryProcessorXML(); + } + else if (querytype.EqualsLiteral("storage")) { + mQueryProcessor = new nsXULTemplateQueryProcessorStorage(); + } + else { + nsAutoCString cid(NS_QUERY_PROCESSOR_CONTRACTID_PREFIX); + AppendUTF16toUTF8(querytype, cid); + mQueryProcessor = do_CreateInstance(cid.get(), &rv); + + if (!mQueryProcessor) { + nsXULContentUtils::LogTemplateError(ERROR_TEMPLATE_INVALID_QUERYPROCESSOR); + return rv; + } + } + + rv = LoadDataSourceUrls(aDocument, datasources, + isRDFQuery, aShouldDelayBuilding); + NS_ENSURE_SUCCESS(rv, rv); + + // Now set the database on the element, so that script writers can + // access it. + nsCOMPtr<nsIXULDocument> xuldoc = do_QueryInterface(aDocument); + if (xuldoc) + xuldoc->SetTemplateBuilderFor(mRoot, this); + + if (!mRoot->IsXULElement()) { + // Hmm. This must be an HTML element. Try to set it as a + // JS property "by hand". + InitHTMLTemplateRoot(); + } + + return NS_OK; +} + +nsresult +nsXULTemplateBuilder::LoadDataSourceUrls(nsIDocument* aDocument, + const nsAString& aDataSources, + bool aIsRDFQuery, + bool* aShouldDelayBuilding) +{ + // Grab the doc's principal... + nsIPrincipal *docPrincipal = aDocument->NodePrincipal(); + + NS_ASSERTION(docPrincipal == mRoot->NodePrincipal(), + "Principal mismatch? Which one to use?"); + + bool isTrusted = false; + nsresult rv = IsSystemPrincipal(docPrincipal, &isTrusted); + NS_ENSURE_SUCCESS(rv, rv); + + // Parse datasources: they are assumed to be a whitespace + // separated list of URIs; e.g., + // + // rdf:bookmarks rdf:history http://foo.bar.com/blah.cgi?baz=9 + // + nsIURI *docurl = aDocument->GetDocumentURI(); + + nsCOMPtr<nsIMutableArray> uriList = do_CreateInstance(NS_ARRAY_CONTRACTID); + if (!uriList) + return NS_ERROR_FAILURE; + + nsAutoString datasources(aDataSources); + uint32_t first = 0; + while (1) { + while (first < datasources.Length() && nsCRT::IsAsciiSpace(datasources.CharAt(first))) + ++first; + + if (first >= datasources.Length()) + break; + + uint32_t last = first; + while (last < datasources.Length() && !nsCRT::IsAsciiSpace(datasources.CharAt(last))) + ++last; + + nsAutoString uriStr; + datasources.Mid(uriStr, first, last - first); + first = last + 1; + + // A special 'dummy' datasource + if (uriStr.EqualsLiteral("rdf:null")) + continue; + + if (uriStr.CharAt(0) == '#') { + // ok, the datasource is certainly a node of the current document + nsCOMPtr<nsIDOMDocument> domdoc = do_QueryInterface(aDocument); + nsCOMPtr<nsIDOMElement> dsnode; + + domdoc->GetElementById(Substring(uriStr, 1), + getter_AddRefs(dsnode)); + + if (dsnode) + uriList->AppendElement(dsnode, false); + continue; + } + + // N.B. that `failure' (e.g., because it's an unknown + // protocol) leaves uriStr unaltered. + NS_MakeAbsoluteURI(uriStr, uriStr, docurl); + + nsCOMPtr<nsIURI> uri; + rv = NS_NewURI(getter_AddRefs(uri), uriStr); + if (NS_FAILED(rv) || !uri) + continue; // Necko will barf if our URI is weird + + // don't add the uri to the list if the document is not allowed to + // load it + if (!isTrusted && NS_FAILED(docPrincipal->CheckMayLoad(uri, true, false))) + continue; + + uriList->AppendElement(uri, false); + } + + nsCOMPtr<nsIDOMNode> rootNode = do_QueryInterface(mRoot); + rv = mQueryProcessor->GetDatasource(uriList, + rootNode, + isTrusted, + this, + aShouldDelayBuilding, + getter_AddRefs(mDataSource)); + NS_ENSURE_SUCCESS(rv, rv); + + if (aIsRDFQuery && mDataSource) { + // check if we were given an inference engine type + nsCOMPtr<nsIRDFInferDataSource> inferDB = do_QueryInterface(mDataSource); + if (inferDB) { + nsCOMPtr<nsIRDFDataSource> ds; + inferDB->GetBaseDataSource(getter_AddRefs(ds)); + if (ds) + mCompDB = do_QueryInterface(ds); + } + + if (!mCompDB) + mCompDB = do_QueryInterface(mDataSource); + + mDB = do_QueryInterface(mDataSource); + } + + if (!mDB && isTrusted) { + gRDFService->GetDataSource("rdf:local-store", getter_AddRefs(mDB)); + } + + return NS_OK; +} + +nsresult +nsXULTemplateBuilder::InitHTMLTemplateRoot() +{ + // Use XPConnect and the JS APIs to whack mDB and this as the + // 'database' and 'builder' properties onto aElement. + nsresult rv; + + nsCOMPtr<nsIDocument> doc = mRoot->GetComposedDoc(); + NS_ASSERTION(doc, "no document"); + if (! doc) + return NS_ERROR_UNEXPECTED; + + nsCOMPtr<nsIScriptGlobalObject> global = + do_QueryInterface(doc->GetWindow()); + if (! global) + return NS_ERROR_UNEXPECTED; + + nsCOMPtr<nsIGlobalObject> innerWin = + do_QueryInterface(doc->GetInnerWindow()); + + // We are going to run script via JS_SetProperty, so we need a script entry + // point, but as this is XUL related it does not appear in the HTML spec. + AutoEntryScript aes(innerWin, "nsXULTemplateBuilder creation", true); + JSContext* jscontext = aes.cx(); + + JS::Rooted<JS::Value> v(jscontext); + rv = nsContentUtils::WrapNative(jscontext, mRoot, mRoot, &v); + NS_ENSURE_SUCCESS(rv, rv); + + JS::Rooted<JSObject*> jselement(jscontext, v.toObjectOrNull()); + + if (mDB) { + // database + JS::Rooted<JS::Value> jsdatabase(jscontext); + rv = nsContentUtils::WrapNative(jscontext, mDB, + &NS_GET_IID(nsIRDFCompositeDataSource), + &jsdatabase); + NS_ENSURE_SUCCESS(rv, rv); + + bool ok = JS_SetProperty(jscontext, jselement, "database", jsdatabase); + NS_ASSERTION(ok, "unable to set database property"); + if (! ok) + return NS_ERROR_FAILURE; + } + + { + // builder + JS::Rooted<JS::Value> jsbuilder(jscontext); + rv = nsContentUtils::WrapNative(jscontext, + static_cast<nsIXULTemplateBuilder*>(this), + &NS_GET_IID(nsIXULTemplateBuilder), + &jsbuilder); + NS_ENSURE_SUCCESS(rv, rv); + + bool ok = JS_SetProperty(jscontext, jselement, "builder", jsbuilder); + if (! ok) + return NS_ERROR_FAILURE; + } + + return NS_OK; +} + +nsresult +nsXULTemplateBuilder::DetermineMatchedRule(nsIContent *aContainer, + nsIXULTemplateResult* aResult, + nsTemplateQuerySet* aQuerySet, + nsTemplateRule** aMatchedRule, + int16_t *aRuleIndex) +{ + // iterate through the rules and look for one that the result matches + int16_t count = aQuerySet->RuleCount(); + for (int16_t r = 0; r < count; r++) { + nsTemplateRule* rule = aQuerySet->GetRuleAt(r); + // If a tag was specified, it must match the tag of the container + // where content is being inserted. + nsIAtom* tag = rule->GetTag(); + if ((!aContainer || !tag || + tag == aContainer->NodeInfo()->NameAtom()) && + rule->CheckMatch(aResult)) { + *aMatchedRule = rule; + *aRuleIndex = r; + return NS_OK; + } + } + + *aRuleIndex = -1; + *aMatchedRule = nullptr; + return NS_OK; +} + +void +nsXULTemplateBuilder::ParseAttribute(const nsAString& aAttributeValue, + void (*aVariableCallback)(nsXULTemplateBuilder*, const nsAString&, void*), + void (*aTextCallback)(nsXULTemplateBuilder*, const nsAString&, void*), + void* aClosure) +{ + nsAString::const_iterator done_parsing; + aAttributeValue.EndReading(done_parsing); + + nsAString::const_iterator iter; + aAttributeValue.BeginReading(iter); + + nsAString::const_iterator mark(iter), backup(iter); + + for (; iter != done_parsing; backup = ++iter) { + // A variable is either prefixed with '?' (in the extended + // syntax) or "rdf:" (in the simple syntax). + bool isvar; + if (*iter == char16_t('?') && (++iter != done_parsing)) { + isvar = true; + } + else if ((*iter == char16_t('r') && (++iter != done_parsing)) && + (*iter == char16_t('d') && (++iter != done_parsing)) && + (*iter == char16_t('f') && (++iter != done_parsing)) && + (*iter == char16_t(':') && (++iter != done_parsing))) { + isvar = true; + } + else { + isvar = false; + } + + if (! isvar) { + // It's not a variable, or we ran off the end of the + // string after the initial variable prefix. Since we may + // have slurped down some characters before realizing that + // fact, back up to the point where we started. + iter = backup; + continue; + } + else if (backup != mark && aTextCallback) { + // Okay, we've found a variable, and there's some vanilla + // text that's been buffered up. Flush it. + (*aTextCallback)(this, Substring(mark, backup), aClosure); + } + + if (*iter == char16_t('?')) { + // Well, it was not really a variable, but "??". We use one + // question mark (the second one, actually) literally. + mark = iter; + continue; + } + + // Construct a substring that is the symbol we need to look up + // in the rule's symbol table. The symbol is terminated by a + // space character, a caret, or the end of the string, + // whichever comes first. + nsAString::const_iterator first(backup); + + char16_t c = 0; + while (iter != done_parsing) { + c = *iter; + if ((c == char16_t(' ')) || (c == char16_t('^'))) + break; + + ++iter; + } + + nsAString::const_iterator last(iter); + + // Back up so we don't consume the terminating character + // *unless* the terminating character was a caret: the caret + // means "concatenate with no space in between". + if (c != char16_t('^')) + --iter; + + (*aVariableCallback)(this, Substring(first, last), aClosure); + mark = iter; + ++mark; + } + + if (backup != mark && aTextCallback) { + // If there's any text left over, then fire the text callback + (*aTextCallback)(this, Substring(mark, backup), aClosure); + } +} + + +struct MOZ_STACK_CLASS SubstituteTextClosure { + SubstituteTextClosure(nsIXULTemplateResult* aResult, nsAString& aString) + : result(aResult), str(aString) {} + + // some datasources are lazily initialized or modified while values are + // being retrieved, causing results to be removed. Due to this, hold a + // strong reference to the result. + nsCOMPtr<nsIXULTemplateResult> result; + nsAString& str; +}; + +nsresult +nsXULTemplateBuilder::SubstituteText(nsIXULTemplateResult* aResult, + const nsAString& aAttributeValue, + nsAString& aString) +{ + // See if it's the special value "..." + if (aAttributeValue.EqualsLiteral("...")) { + aResult->GetId(aString); + return NS_OK; + } + + // Reasonable guess at how big it should be + aString.SetCapacity(aAttributeValue.Length()); + + SubstituteTextClosure closure(aResult, aString); + ParseAttribute(aAttributeValue, + SubstituteTextReplaceVariable, + SubstituteTextAppendText, + &closure); + + return NS_OK; +} + + +void +nsXULTemplateBuilder::SubstituteTextAppendText(nsXULTemplateBuilder* aThis, + const nsAString& aText, + void* aClosure) +{ + // Append aString to the closure's result + SubstituteTextClosure* c = static_cast<SubstituteTextClosure*>(aClosure); + c->str.Append(aText); +} + +void +nsXULTemplateBuilder::SubstituteTextReplaceVariable(nsXULTemplateBuilder* aThis, + const nsAString& aVariable, + void* aClosure) +{ + // Substitute the value for the variable and append to the + // closure's result. + SubstituteTextClosure* c = static_cast<SubstituteTextClosure*>(aClosure); + + nsAutoString replacementText; + + // The symbol "rdf:*" is special, and means "this guy's URI" + if (aVariable.EqualsLiteral("rdf:*")){ + c->result->GetId(replacementText); + } + else { + // Got a variable; get the value it's assigned to + nsCOMPtr<nsIAtom> var = NS_Atomize(aVariable); + c->result->GetBindingFor(var, replacementText); + } + + c->str += replacementText; +} + +bool +nsXULTemplateBuilder::IsTemplateElement(nsIContent* aContent) +{ + return aContent->NodeInfo()->Equals(nsGkAtoms::_template, + kNameSpaceID_XUL); +} + +nsresult +nsXULTemplateBuilder::GetTemplateRoot(nsIContent** aResult) +{ + NS_PRECONDITION(mRoot != nullptr, "not initialized"); + if (! mRoot) + return NS_ERROR_NOT_INITIALIZED; + + // First, check and see if the root has a template attribute. This + // allows a template to be specified "out of line"; e.g., + // + // <window> + // <foo template="MyTemplate">...</foo> + // <template id="MyTemplate">...</template> + // </window> + // + nsAutoString templateID; + mRoot->GetAttr(kNameSpaceID_None, nsGkAtoms::_template, templateID); + + if (! templateID.IsEmpty()) { + nsCOMPtr<nsIDOMDocument> domDoc = do_QueryInterface(mRoot->GetComposedDoc()); + if (! domDoc) + return NS_OK; + + nsCOMPtr<nsIDOMElement> domElement; + domDoc->GetElementById(templateID, getter_AddRefs(domElement)); + + if (domElement) { + nsCOMPtr<nsIContent> content = do_QueryInterface(domElement); + NS_ENSURE_STATE(content && + !nsContentUtils::ContentIsDescendantOf(mRoot, + content)); + content.forget(aResult); + return NS_OK; + } + } + + // If root node has no template attribute, then look for a child + // node which is a template tag. + for (nsIContent* child = mRoot->GetFirstChild(); + child; + child = child->GetNextSibling()) { + + if (IsTemplateElement(child)) { + NS_ADDREF(*aResult = child); + return NS_OK; + } + } + + // Look through the anonymous children as well. Although FlattenedChildIterator + // will find a template element that has been placed in an insertion point, many + // bindings do not have a specific insertion point for the template element, which + // would cause it to not be part of the flattened content tree. The check above to + // check the explicit children as well handles this case. + FlattenedChildIterator iter(mRoot); + for (nsIContent* child = iter.GetNextChild(); child; child = iter.GetNextChild()) { + if (IsTemplateElement(child)) { + NS_ADDREF(*aResult = child); + return NS_OK; + } + } + + *aResult = nullptr; + return NS_OK; +} + +nsresult +nsXULTemplateBuilder::CompileQueries() +{ + nsCOMPtr<nsIContent> tmpl; + GetTemplateRoot(getter_AddRefs(tmpl)); + if (! tmpl) + return NS_OK; + + if (! mRoot) + return NS_ERROR_NOT_INITIALIZED; + + // Determine if there are any special settings we need to observe + mFlags = 0; + + nsAutoString flags; + mRoot->GetAttr(kNameSpaceID_None, nsGkAtoms::flags, flags); + + // if the dont-test-empty flag is set, containers should not be checked to + // see if they are empty. If dont-recurse is set, then don't process the + // template recursively and only show one level of results. The logging + // flag logs errors and results to the console, which is useful when + // debugging templates. + nsWhitespaceTokenizer tokenizer(flags); + while (tokenizer.hasMoreTokens()) { + const nsDependentSubstring& token(tokenizer.nextToken()); + if (token.EqualsLiteral("dont-test-empty")) + mFlags |= eDontTestEmpty; + else if (token.EqualsLiteral("dont-recurse")) + mFlags |= eDontRecurse; + else if (token.EqualsLiteral("logging")) + mFlags |= eLoggingEnabled; + } + + // always enable logging if the debug setting is used + if (MOZ_LOG_TEST(gXULTemplateLog, LogLevel::Debug)) + mFlags |= eLoggingEnabled; + + nsCOMPtr<nsIDOMNode> rootnode = do_QueryInterface(mRoot); + nsresult rv = + mQueryProcessor->InitializeForBuilding(mDataSource, this, rootnode); + if (NS_FAILED(rv)) + return rv; + + // Set the "container" and "member" variables, if the user has specified + // them. The container variable may be specified with the container + // attribute on the <template> and the member variable may be specified + // using the member attribute or the value of the uri attribute inside the + // first action body in the template. If not specified, the container + // variable defaults to '?uri' and the member variable defaults to '?' or + // 'rdf:*' for simple queries. + + // For RDF queries, the container variable may also be set via the + // <content> tag. + + nsAutoString containervar; + tmpl->GetAttr(kNameSpaceID_None, nsGkAtoms::container, containervar); + + if (containervar.IsEmpty()) + mRefVariable = NS_Atomize("?uri"); + else + mRefVariable = NS_Atomize(containervar); + + nsAutoString membervar; + tmpl->GetAttr(kNameSpaceID_None, nsGkAtoms::member, membervar); + + if (membervar.IsEmpty()) + mMemberVariable = nullptr; + else + mMemberVariable = NS_Atomize(membervar); + + nsTemplateQuerySet* queryset = new nsTemplateQuerySet(0); + if (!mQuerySets.AppendElement(queryset)) { + delete queryset; + return NS_ERROR_OUT_OF_MEMORY; + } + + bool canUseTemplate = false; + int32_t priority = 0; + rv = CompileTemplate(tmpl, queryset, false, &priority, &canUseTemplate); + + if (NS_FAILED(rv) || !canUseTemplate) { + for (int32_t q = mQuerySets.Length() - 1; q >= 0; q--) { + nsTemplateQuerySet* qs = mQuerySets[q]; + delete qs; + } + mQuerySets.Clear(); + } + + mQueriesCompiled = true; + + return NS_OK; +} + +nsresult +nsXULTemplateBuilder::CompileTemplate(nsIContent* aTemplate, + nsTemplateQuerySet* aQuerySet, + bool aIsQuerySet, + int32_t* aPriority, + bool* aCanUseTemplate) +{ + NS_ASSERTION(aQuerySet, "No queryset supplied"); + + nsresult rv = NS_OK; + + bool isQuerySetMode = false; + bool hasQuerySet = false, hasRule = false, hasQuery = false; + + for (nsIContent* rulenode = aTemplate->GetFirstChild(); + rulenode; + rulenode = rulenode->GetNextSibling()) { + + mozilla::dom::NodeInfo *ni = rulenode->NodeInfo(); + + // don't allow more queries than can be supported + if (*aPriority == INT16_MAX) + return NS_ERROR_FAILURE; + + // XXXndeakin queryset isn't a good name for this tag since it only + // ever contains one query + if (!aIsQuerySet && ni->Equals(nsGkAtoms::queryset, kNameSpaceID_XUL)) { + if (hasRule || hasQuery) { + nsXULContentUtils::LogTemplateError(ERROR_TEMPLATE_INVALID_QUERYSET); + continue; + } + + isQuerySetMode = true; + + // only create a queryset for those after the first since the + // first one is always created by CompileQueries + if (hasQuerySet) { + aQuerySet = new nsTemplateQuerySet(++*aPriority); + + // once the queryset is appended to the mQuerySets list, it + // will be removed by CompileQueries if an error occurs + if (!mQuerySets.AppendElement(aQuerySet)) { + delete aQuerySet; + return NS_ERROR_OUT_OF_MEMORY; + } + } + + hasQuerySet = true; + + rv = CompileTemplate(rulenode, aQuerySet, true, aPriority, aCanUseTemplate); + if (NS_FAILED(rv)) + return rv; + } + + // once a queryset is used, everything must be a queryset + if (isQuerySetMode) + continue; + + if (ni->Equals(nsGkAtoms::rule, kNameSpaceID_XUL)) { + nsCOMPtr<nsIContent> action; + nsXULContentUtils::FindChildByTag(rulenode, + kNameSpaceID_XUL, + nsGkAtoms::action, + getter_AddRefs(action)); + + if (action){ + nsCOMPtr<nsIAtom> memberVariable = mMemberVariable; + if (!memberVariable) { + memberVariable = DetermineMemberVariable(action); + if (!memberVariable) { + nsXULContentUtils::LogTemplateError(ERROR_TEMPLATE_NO_MEMBERVAR); + continue; + } + } + + if (hasQuery) { + nsCOMPtr<nsIAtom> tag; + DetermineRDFQueryRef(aQuerySet->mQueryNode, + getter_AddRefs(tag)); + if (tag) + aQuerySet->SetTag(tag); + + if (! aQuerySet->mCompiledQuery) { + nsCOMPtr<nsIDOMNode> query(do_QueryInterface(aQuerySet->mQueryNode)); + + rv = mQueryProcessor->CompileQuery(this, query, + mRefVariable, memberVariable, + getter_AddRefs(aQuerySet->mCompiledQuery)); + if (NS_FAILED(rv)) + return rv; + } + + if (aQuerySet->mCompiledQuery) { + rv = CompileExtendedQuery(rulenode, action, memberVariable, + aQuerySet); + if (NS_FAILED(rv)) + return rv; + + *aCanUseTemplate = true; + } + } + else { + // backwards-compatible RDF template syntax where there is + // an <action> node but no <query> node. In this case, + // use the conditions as if it was the query. + + nsCOMPtr<nsIContent> conditions; + nsXULContentUtils::FindChildByTag(rulenode, + kNameSpaceID_XUL, + nsGkAtoms::conditions, + getter_AddRefs(conditions)); + + if (conditions) { + // create a new queryset if one hasn't been created already + if (hasQuerySet) { + aQuerySet = new nsTemplateQuerySet(++*aPriority); + if (!mQuerySets.AppendElement(aQuerySet)) { + delete aQuerySet; + return NS_ERROR_OUT_OF_MEMORY; + } + } + + nsCOMPtr<nsIAtom> tag; + DetermineRDFQueryRef(conditions, getter_AddRefs(tag)); + if (tag) + aQuerySet->SetTag(tag); + + hasQuerySet = true; + + nsCOMPtr<nsIDOMNode> conditionsnode(do_QueryInterface(conditions)); + + aQuerySet->mQueryNode = conditions; + rv = mQueryProcessor->CompileQuery(this, conditionsnode, + mRefVariable, + memberVariable, + getter_AddRefs(aQuerySet->mCompiledQuery)); + if (NS_FAILED(rv)) + return rv; + + if (aQuerySet->mCompiledQuery) { + rv = CompileExtendedQuery(rulenode, action, memberVariable, + aQuerySet); + if (NS_FAILED(rv)) + return rv; + + *aCanUseTemplate = true; + } + } + } + } + else { + if (hasQuery) + continue; + + // a new queryset must always be created in this case + if (hasQuerySet) { + aQuerySet = new nsTemplateQuerySet(++*aPriority); + if (!mQuerySets.AppendElement(aQuerySet)) { + delete aQuerySet; + return NS_ERROR_OUT_OF_MEMORY; + } + } + + hasQuerySet = true; + + rv = CompileSimpleQuery(rulenode, aQuerySet, aCanUseTemplate); + if (NS_FAILED(rv)) + return rv; + } + + hasRule = true; + } + else if (ni->Equals(nsGkAtoms::query, kNameSpaceID_XUL)) { + if (hasQuery) + continue; + + aQuerySet->mQueryNode = rulenode; + hasQuery = true; + } + else if (ni->Equals(nsGkAtoms::action, kNameSpaceID_XUL)) { + // the query must appear before the action + if (! hasQuery) + continue; + + nsCOMPtr<nsIAtom> tag; + DetermineRDFQueryRef(aQuerySet->mQueryNode, getter_AddRefs(tag)); + if (tag) + aQuerySet->SetTag(tag); + + nsCOMPtr<nsIAtom> memberVariable = mMemberVariable; + if (!memberVariable) { + memberVariable = DetermineMemberVariable(rulenode); + if (!memberVariable) { + nsXULContentUtils::LogTemplateError(ERROR_TEMPLATE_NO_MEMBERVAR); + continue; + } + } + + nsCOMPtr<nsIDOMNode> query(do_QueryInterface(aQuerySet->mQueryNode)); + + rv = mQueryProcessor->CompileQuery(this, query, + mRefVariable, memberVariable, + getter_AddRefs(aQuerySet->mCompiledQuery)); + + if (aQuerySet->mCompiledQuery) { + nsTemplateRule* rule = aQuerySet->NewRule(aTemplate, rulenode, aQuerySet); + if (! rule) + return NS_ERROR_OUT_OF_MEMORY; + + rule->SetVars(mRefVariable, memberVariable); + + *aCanUseTemplate = true; + + return NS_OK; + } + } + } + + if (! hasRule && ! hasQuery && ! hasQuerySet) { + // if no rules are specified in the template, then the contents of the + // <template> tag are the one-and-only template. + rv = CompileSimpleQuery(aTemplate, aQuerySet, aCanUseTemplate); + } + + return rv; +} + +nsresult +nsXULTemplateBuilder::CompileExtendedQuery(nsIContent* aRuleElement, + nsIContent* aActionElement, + nsIAtom* aMemberVariable, + nsTemplateQuerySet* aQuerySet) +{ + // Compile an "extended" <template> rule. An extended rule may have + // a <conditions> child, an <action> child, and a <bindings> child. + nsresult rv; + + nsTemplateRule* rule = aQuerySet->NewRule(aRuleElement, aActionElement, aQuerySet); + if (! rule) + return NS_ERROR_OUT_OF_MEMORY; + + nsCOMPtr<nsIContent> conditions; + nsXULContentUtils::FindChildByTag(aRuleElement, + kNameSpaceID_XUL, + nsGkAtoms::conditions, + getter_AddRefs(conditions)); + + // allow the conditions to be placed directly inside the rule + if (!conditions) + conditions = aRuleElement; + + rv = CompileConditions(rule, conditions); + // If the rule compilation failed, then we have to bail. + if (NS_FAILED(rv)) { + aQuerySet->RemoveRule(rule); + return rv; + } + + rule->SetVars(mRefVariable, aMemberVariable); + + // If we've got bindings, add 'em. + nsCOMPtr<nsIContent> bindings; + nsXULContentUtils::FindChildByTag(aRuleElement, + kNameSpaceID_XUL, + nsGkAtoms::bindings, + getter_AddRefs(bindings)); + + // allow bindings to be placed directly inside rule + if (!bindings) + bindings = aRuleElement; + + rv = CompileBindings(rule, bindings); + NS_ENSURE_SUCCESS(rv, rv); + + return NS_OK; +} + +already_AddRefed<nsIAtom> +nsXULTemplateBuilder::DetermineMemberVariable(nsIContent* aElement) +{ + // recursively iterate over the children looking for an element + // with uri="?..." + for (nsIContent* child = aElement->GetFirstChild(); + child; + child = child->GetNextSibling()) { + nsAutoString uri; + child->GetAttr(kNameSpaceID_None, nsGkAtoms::uri, uri); + if (!uri.IsEmpty() && uri[0] == char16_t('?')) { + return NS_Atomize(uri); + } + + nsCOMPtr<nsIAtom> result = DetermineMemberVariable(child); + if (result) { + return result.forget(); + } + } + + return nullptr; +} + +void +nsXULTemplateBuilder::DetermineRDFQueryRef(nsIContent* aQueryElement, nsIAtom** aTag) +{ + // check for a tag + nsCOMPtr<nsIContent> content; + nsXULContentUtils::FindChildByTag(aQueryElement, + kNameSpaceID_XUL, + nsGkAtoms::content, + getter_AddRefs(content)); + + if (! content) { + // look for older treeitem syntax as well + nsXULContentUtils::FindChildByTag(aQueryElement, + kNameSpaceID_XUL, + nsGkAtoms::treeitem, + getter_AddRefs(content)); + } + + if (content) { + nsAutoString uri; + content->GetAttr(kNameSpaceID_None, nsGkAtoms::uri, uri); + + if (!uri.IsEmpty()) + mRefVariable = NS_Atomize(uri); + + nsAutoString tag; + content->GetAttr(kNameSpaceID_None, nsGkAtoms::tag, tag); + + if (!tag.IsEmpty()) + *aTag = NS_Atomize(tag).take(); + } +} + +nsresult +nsXULTemplateBuilder::CompileSimpleQuery(nsIContent* aRuleElement, + nsTemplateQuerySet* aQuerySet, + bool* aCanUseTemplate) +{ + // compile a simple query, which is a query with no <query> or + // <conditions>. This means that a default query is used. + nsCOMPtr<nsIDOMNode> query(do_QueryInterface(aRuleElement)); + + nsCOMPtr<nsIAtom> memberVariable; + if (mMemberVariable) + memberVariable = mMemberVariable; + else + memberVariable = NS_Atomize("rdf:*"); + + // since there is no <query> node for a simple query, the query node will + // be either the <rule> node if multiple rules are used, or the <template> node. + aQuerySet->mQueryNode = aRuleElement; + nsresult rv = mQueryProcessor->CompileQuery(this, query, + mRefVariable, memberVariable, + getter_AddRefs(aQuerySet->mCompiledQuery)); + if (NS_FAILED(rv)) + return rv; + + if (! aQuerySet->mCompiledQuery) { + *aCanUseTemplate = false; + return NS_OK; + } + + nsTemplateRule* rule = aQuerySet->NewRule(aRuleElement, aRuleElement, aQuerySet); + if (! rule) + return NS_ERROR_OUT_OF_MEMORY; + + rule->SetVars(mRefVariable, memberVariable); + + nsAutoString tag; + aRuleElement->GetAttr(kNameSpaceID_None, nsGkAtoms::parent, tag); + + if (!tag.IsEmpty()) { + nsCOMPtr<nsIAtom> tagatom = NS_Atomize(tag); + aQuerySet->SetTag(tagatom); + } + + *aCanUseTemplate = true; + + return AddSimpleRuleBindings(rule, aRuleElement); +} + +nsresult +nsXULTemplateBuilder::CompileConditions(nsTemplateRule* aRule, + nsIContent* aCondition) +{ + nsAutoString tag; + aCondition->GetAttr(kNameSpaceID_None, nsGkAtoms::parent, tag); + + if (!tag.IsEmpty()) { + nsCOMPtr<nsIAtom> tagatom = NS_Atomize(tag); + aRule->SetTag(tagatom); + } + + nsTemplateCondition* currentCondition = nullptr; + + for (nsIContent* node = aCondition->GetFirstChild(); + node; + node = node->GetNextSibling()) { + + if (node->NodeInfo()->Equals(nsGkAtoms::where, kNameSpaceID_XUL)) { + nsresult rv = CompileWhereCondition(aRule, node, ¤tCondition); + if (NS_FAILED(rv)) + return rv; + } + } + + return NS_OK; +} + +nsresult +nsXULTemplateBuilder::CompileWhereCondition(nsTemplateRule* aRule, + nsIContent* aCondition, + nsTemplateCondition** aCurrentCondition) +{ + // Compile a <where> condition, which must be of the form: + // + // <where subject="?var1|string" rel="relation" value="?var2|string" /> + // + // The value of rel may be: + // equal - subject must be equal to object + // notequal - subject must not be equal to object + // less - subject must be less than object + // greater - subject must be greater than object + // startswith - subject must start with object + // endswith - subject must end with object + // contains - subject must contain object + // Comparisons are done as strings unless the subject is an integer. + + // subject + nsAutoString subject; + aCondition->GetAttr(kNameSpaceID_None, nsGkAtoms::subject, subject); + if (subject.IsEmpty()) { + nsXULContentUtils::LogTemplateError(ERROR_TEMPLATE_WHERE_NO_SUBJECT); + return NS_OK; + } + + nsCOMPtr<nsIAtom> svar; + if (subject[0] == char16_t('?')) + svar = NS_Atomize(subject); + + nsAutoString relstring; + aCondition->GetAttr(kNameSpaceID_None, nsGkAtoms::rel, relstring); + if (relstring.IsEmpty()) { + nsXULContentUtils::LogTemplateError(ERROR_TEMPLATE_WHERE_NO_RELATION); + return NS_OK; + } + + // object + nsAutoString value; + aCondition->GetAttr(kNameSpaceID_None, nsGkAtoms::value, value); + if (value.IsEmpty()) { + nsXULContentUtils::LogTemplateError(ERROR_TEMPLATE_WHERE_NO_VALUE); + return NS_OK; + } + + // multiple + bool shouldMultiple = + aCondition->AttrValueIs(kNameSpaceID_None, nsGkAtoms::multiple, + nsGkAtoms::_true, eCaseMatters); + + nsCOMPtr<nsIAtom> vvar; + if (!shouldMultiple && (value[0] == char16_t('?'))) { + vvar = NS_Atomize(value); + } + + // ignorecase + bool shouldIgnoreCase = + aCondition->AttrValueIs(kNameSpaceID_None, nsGkAtoms::ignorecase, + nsGkAtoms::_true, eCaseMatters); + + // negate + bool shouldNegate = + aCondition->AttrValueIs(kNameSpaceID_None, nsGkAtoms::negate, + nsGkAtoms::_true, eCaseMatters); + + nsTemplateCondition* condition; + + if (svar && vvar) { + condition = new nsTemplateCondition(svar, relstring, vvar, + shouldIgnoreCase, shouldNegate); + } + else if (svar && !value.IsEmpty()) { + condition = new nsTemplateCondition(svar, relstring, value, + shouldIgnoreCase, shouldNegate, shouldMultiple); + } + else if (vvar) { + condition = new nsTemplateCondition(subject, relstring, vvar, + shouldIgnoreCase, shouldNegate); + } + else { + nsXULContentUtils::LogTemplateError(ERROR_TEMPLATE_WHERE_NO_VAR); + return NS_OK; + } + + if (*aCurrentCondition) { + (*aCurrentCondition)->SetNext(condition); + } + else { + aRule->SetCondition(condition); + } + + *aCurrentCondition = condition; + + return NS_OK; +} + +nsresult +nsXULTemplateBuilder::CompileBindings(nsTemplateRule* aRule, nsIContent* aBindings) +{ + // Add an extended rule's bindings. + nsresult rv; + + for (nsIContent* binding = aBindings->GetFirstChild(); + binding; + binding = binding->GetNextSibling()) { + + if (binding->NodeInfo()->Equals(nsGkAtoms::binding, + kNameSpaceID_XUL)) { + rv = CompileBinding(aRule, binding); + if (NS_FAILED(rv)) + return rv; + } + } + + aRule->AddBindingsToQueryProcessor(mQueryProcessor); + + return NS_OK; +} + + +nsresult +nsXULTemplateBuilder::CompileBinding(nsTemplateRule* aRule, + nsIContent* aBinding) +{ + // Compile a <binding> "condition", which must be of the form: + // + // <binding subject="?var1" + // predicate="resource" + // object="?var2" /> + // + // XXXwaterson Some day it would be cool to allow the 'predicate' + // to be bound to a variable. + + // subject + nsAutoString subject; + aBinding->GetAttr(kNameSpaceID_None, nsGkAtoms::subject, subject); + if (subject.IsEmpty()) { + nsXULContentUtils::LogTemplateError(ERROR_TEMPLATE_BINDING_BAD_SUBJECT); + return NS_OK; + } + + nsCOMPtr<nsIAtom> svar; + if (subject[0] == char16_t('?')) { + svar = NS_Atomize(subject); + } + else { + nsXULContentUtils::LogTemplateError(ERROR_TEMPLATE_BINDING_BAD_SUBJECT); + return NS_OK; + } + + // predicate + nsAutoString predicate; + aBinding->GetAttr(kNameSpaceID_None, nsGkAtoms::predicate, predicate); + if (predicate.IsEmpty()) { + nsXULContentUtils::LogTemplateError(ERROR_TEMPLATE_BINDING_BAD_PREDICATE); + return NS_OK; + } + + // object + nsAutoString object; + aBinding->GetAttr(kNameSpaceID_None, nsGkAtoms::object, object); + + if (object.IsEmpty()) { + nsXULContentUtils::LogTemplateError(ERROR_TEMPLATE_BINDING_BAD_OBJECT); + return NS_OK; + } + + nsCOMPtr<nsIAtom> ovar; + if (object[0] == char16_t('?')) { + ovar = NS_Atomize(object); + } + else { + nsXULContentUtils::LogTemplateError(ERROR_TEMPLATE_BINDING_BAD_OBJECT); + return NS_OK; + } + + return aRule->AddBinding(svar, predicate, ovar); +} + +nsresult +nsXULTemplateBuilder::AddSimpleRuleBindings(nsTemplateRule* aRule, + nsIContent* aElement) +{ + // Crawl the content tree of a "simple" rule, adding a variable + // assignment for any attribute whose value is "rdf:". + + AutoTArray<nsIContent*, 8> elements; + + if (elements.AppendElement(aElement) == nullptr) + return NS_ERROR_OUT_OF_MEMORY; + + while (elements.Length()) { + // Pop the next element off the stack + uint32_t i = elements.Length() - 1; + nsIContent* element = elements[i]; + elements.RemoveElementAt(i); + + // Iterate through its attributes, looking for substitutions + // that we need to add as bindings. + uint32_t count = element->GetAttrCount(); + + for (i = 0; i < count; ++i) { + const nsAttrName* name = element->GetAttrNameAt(i); + + if (!name->Equals(nsGkAtoms::id, kNameSpaceID_None) && + !name->Equals(nsGkAtoms::uri, kNameSpaceID_None)) { + nsAutoString value; + element->GetAttr(name->NamespaceID(), name->LocalName(), value); + + // Scan the attribute for variables, adding a binding for + // each one. + ParseAttribute(value, AddBindingsFor, nullptr, aRule); + } + } + + // Push kids onto the stack, and search them next. + for (nsIContent* child = element->GetLastChild(); + child; + child = child->GetPreviousSibling()) { + + if (!elements.AppendElement(child)) + return NS_ERROR_OUT_OF_MEMORY; + } + } + + aRule->AddBindingsToQueryProcessor(mQueryProcessor); + + return NS_OK; +} + +void +nsXULTemplateBuilder::AddBindingsFor(nsXULTemplateBuilder* aThis, + const nsAString& aVariable, + void* aClosure) +{ + // We should *only* be recieving "rdf:"-style variables. Make + // sure... + if (!StringBeginsWith(aVariable, NS_LITERAL_STRING("rdf:"))) + return; + + nsTemplateRule* rule = static_cast<nsTemplateRule*>(aClosure); + + nsCOMPtr<nsIAtom> var = NS_Atomize(aVariable); + + // Strip it down to the raw RDF property by clobbering the "rdf:" + // prefix + nsAutoString property; + property.Assign(Substring(aVariable, uint32_t(4), aVariable.Length() - 4)); + + if (! rule->HasBinding(rule->GetMemberVariable(), property, var)) + // In the simple syntax, the binding is always from the + // member variable, through the property, to the target. + rule->AddBinding(rule->GetMemberVariable(), property, var); +} + + +nsresult +nsXULTemplateBuilder::IsSystemPrincipal(nsIPrincipal *principal, bool *result) +{ + if (!gSystemPrincipal) + return NS_ERROR_UNEXPECTED; + + *result = (principal == gSystemPrincipal); + return NS_OK; +} + +bool +nsXULTemplateBuilder::IsActivated(nsIRDFResource *aResource) +{ + for (ActivationEntry *entry = mTop; + entry != nullptr; + entry = entry->mPrevious) { + if (entry->mResource == aResource) + return true; + } + return false; +} + +nsresult +nsXULTemplateBuilder::GetResultResource(nsIXULTemplateResult* aResult, + nsIRDFResource** aResource) +{ + // get the resource for a result by checking its resource property. If it + // is not set, check the id. This allows non-chrome implementations to + // avoid having to use RDF. + nsresult rv = aResult->GetResource(aResource); + if (NS_FAILED(rv)) + return rv; + + if (! *aResource) { + nsAutoString id; + rv = aResult->GetId(id); + if (NS_FAILED(rv)) + return rv; + + return gRDFService->GetUnicodeResource(id, aResource); + } + + return rv; +} + + +void +nsXULTemplateBuilder::OutputMatchToLog(nsIRDFResource* aId, + nsTemplateMatch* aMatch, + bool aIsNew) +{ + int32_t priority = aMatch->QuerySetPriority() + 1; + int32_t activePriority = -1; + + nsAutoString msg; + + nsAutoString templateid; + mRoot->GetAttr(kNameSpaceID_None, nsGkAtoms::id, templateid); + msg.AppendLiteral("In template"); + if (!templateid.IsEmpty()) { + msg.AppendLiteral(" with id "); + msg.Append(templateid); + } + + nsAutoString refstring; + aMatch->mResult->GetBindingFor(mRefVariable, refstring); + if (!refstring.IsEmpty()) { + msg.AppendLiteral(" using ref "); + msg.Append(refstring); + } + + msg.AppendLiteral("\n "); + + nsTemplateMatch* match = nullptr; + if (mMatchMap.Get(aId, &match)){ + while (match) { + if (match == aMatch) + break; + if (match->IsActive() && + match->GetContainer() == aMatch->GetContainer()) { + activePriority = match->QuerySetPriority() + 1; + break; + } + match = match->mNext; + } + } + + if (aMatch->IsActive()) { + if (aIsNew) { + msg.AppendLiteral("New active result for query "); + msg.AppendInt(priority); + msg.AppendLiteral(" matching rule "); + msg.AppendInt(aMatch->RuleIndex() + 1); + } + else { + msg.AppendLiteral("Removed active result for query "); + msg.AppendInt(priority); + if (activePriority > 0) { + msg.AppendLiteral(" (new active query is "); + msg.AppendInt(activePriority); + msg.Append(')'); + } + else { + msg.AppendLiteral(" (no new active query)"); + } + } + } + else { + if (aIsNew) { + msg.AppendLiteral("New inactive result for query "); + msg.AppendInt(priority); + if (activePriority > 0) { + msg.AppendLiteral(" (overridden by query "); + msg.AppendInt(activePriority); + msg.Append(')'); + } + else { + msg.AppendLiteral(" (didn't match a rule)"); + } + } + else { + msg.AppendLiteral("Removed inactive result for query "); + msg.AppendInt(priority); + if (activePriority > 0) { + msg.AppendLiteral(" (active query is "); + msg.AppendInt(activePriority); + msg.Append(')'); + } + else { + msg.AppendLiteral(" (no active query)"); + } + } + } + + nsAutoString idstring; + nsXULContentUtils::GetTextForNode(aId, idstring); + msg.AppendLiteral(": "); + msg.Append(idstring); + + nsCOMPtr<nsIConsoleService> cs = do_GetService(NS_CONSOLESERVICE_CONTRACTID); + if (cs) + cs->LogStringMessage(msg.get()); +} diff --git a/dom/xul/templates/nsXULTemplateBuilder.h b/dom/xul/templates/nsXULTemplateBuilder.h new file mode 100644 index 000000000..7da8ffc98 --- /dev/null +++ b/dom/xul/templates/nsXULTemplateBuilder.h @@ -0,0 +1,502 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* 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/. */ + +#ifndef nsXULTemplateBuilder_h__ +#define nsXULTemplateBuilder_h__ + +#include "nsStubDocumentObserver.h" +#include "nsIScriptSecurityManager.h" +#include "nsIObserver.h" +#include "nsIRDFCompositeDataSource.h" +#include "nsIRDFContainer.h" +#include "nsIRDFContainerUtils.h" +#include "nsIRDFDataSource.h" +#include "nsIRDFObserver.h" +#include "nsIRDFService.h" +#include "nsIXULTemplateBuilder.h" + +#include "nsCOMArray.h" +#include "nsTArray.h" +#include "nsDataHashtable.h" +#include "nsTemplateRule.h" +#include "nsTemplateMatch.h" +#include "nsIXULTemplateQueryProcessor.h" +#include "nsCycleCollectionParticipant.h" + +#include "mozilla/Logging.h" +extern mozilla::LazyLogModule gXULTemplateLog; + +class nsIContent; +class nsIObserverService; +class nsIRDFCompositeDataSource; + +/** + * An object that translates an RDF graph into a presentation using a + * set of rules. + */ +class nsXULTemplateBuilder : public nsIXULTemplateBuilder, + public nsIObserver, + public nsStubDocumentObserver +{ + void CleanUp(bool aIsFinal); + void DestroyMatchMap(); + +public: + nsXULTemplateBuilder(); + + nsresult InitGlobals(); + + /** + * Clear the template builder structures. The aIsFinal flag is set to true + * when the template is going away. + */ + virtual void Uninit(bool aIsFinal); + + // nsISupports interface + NS_DECL_CYCLE_COLLECTING_ISUPPORTS + NS_DECL_CYCLE_COLLECTION_CLASS_AMBIGUOUS(nsXULTemplateBuilder, + nsIXULTemplateBuilder) + + // nsIXULTemplateBuilder interface + NS_DECL_NSIXULTEMPLATEBUILDER + + // nsIObserver Interface + NS_DECL_NSIOBSERVER + + // nsIMutationObserver + NS_DECL_NSIMUTATIONOBSERVER_ATTRIBUTECHANGED + NS_DECL_NSIMUTATIONOBSERVER_CONTENTREMOVED + NS_DECL_NSIMUTATIONOBSERVER_NODEWILLBEDESTROYED + + /** + * Remove an old result and/or add a new result. This method will retrieve + * the set of containers where the result could be inserted and either add + * the new result to those containers, or remove the result from those + * containers. UpdateResultInContainer is called for each container. + * + * @param aOldResult result to remove + * @param aNewResult result to add + * @param aQueryNode query node for new result + */ + nsresult + UpdateResult(nsIXULTemplateResult* aOldResult, + nsIXULTemplateResult* aNewResult, + nsIDOMNode* aQueryNode); + + /** + * Remove an old result and/or add a new result from a specific container. + * + * @param aOldResult result to remove + * @param aNewResult result to add + * @param aQueryNode queryset for the new result + * @param aOldId id of old result + * @param aNewId id of new result + * @param aInsertionPoint container to remove or add result inside + */ + nsresult + UpdateResultInContainer(nsIXULTemplateResult* aOldResult, + nsIXULTemplateResult* aNewResult, + nsTemplateQuerySet* aQuerySet, + nsIRDFResource* aOldId, + nsIRDFResource* aNewId, + nsIContent* aInsertionPoint); + + nsresult + ComputeContainmentProperties(); + + static bool + IsTemplateElement(nsIContent* aContent); + + virtual nsresult + RebuildAll() = 0; // must be implemented by subclasses + + void RunnableRebuild() { Rebuild(); } + void RunnableLoadAndRebuild() { + Uninit(false); // Reset results + + nsCOMPtr<nsIDocument> doc = mRoot ? mRoot->GetComposedDoc() : nullptr; + if (doc) { + bool shouldDelay; + LoadDataSources(doc, &shouldDelay); + if (!shouldDelay) { + Rebuild(); + } + } + } + + // mRoot should not be cleared until after Uninit is finished so that + // generated content can be removed during uninitialization. + void UninitFalse() { Uninit(false); mRoot = nullptr; } + void UninitTrue() { Uninit(true); mRoot = nullptr; } + + /** + * Find the <template> tag that applies for this builder + */ + nsresult + GetTemplateRoot(nsIContent** aResult); + + /** + * Compile the template's queries + */ + nsresult + CompileQueries(); + + /** + * Compile the template given a <template> in aTemplate. This function + * is called recursively to handle queries inside a queryset. For the + * outer pass, aIsQuerySet will be false, while the inner pass this will + * be true. + * + * aCanUseTemplate will be set to true if the template's queries could be + * compiled, and false otherwise. If false, the entire template is + * invalid. + * + * @param aTemplate <template> to compile + * @param aQuerySet first queryset + * @param aIsQuerySet true if + * @param aPriority the queryset index, incremented when a new one is added + * @param aCanUseTemplate true if template is valid + */ + nsresult + CompileTemplate(nsIContent* aTemplate, + nsTemplateQuerySet* aQuerySet, + bool aIsQuerySet, + int32_t* aPriority, + bool* aCanUseTemplate); + + /** + * Compile a query using the extended syntax. For backwards compatible RDF + * syntax where there is no <query>, the <conditions> becomes the query. + * + * @param aRuleElement <rule> element + * @param aActionElement <action> element + * @param aMemberVariable member variable for the query + * @param aQuerySet the queryset + */ + nsresult + CompileExtendedQuery(nsIContent* aRuleElement, + nsIContent* aActionElement, + nsIAtom* aMemberVariable, + nsTemplateQuerySet* aQuerySet); + + /** + * Determine the ref variable and tag from inside a RDF query. + */ + void DetermineRDFQueryRef(nsIContent* aQueryElement, nsIAtom** tag); + + /** + * Determine the member variable from inside an action body. It will be + * the value of the uri attribute on a node. + */ + already_AddRefed<nsIAtom> DetermineMemberVariable(nsIContent* aElement); + + /** + * Compile a simple query. A simple query is one that doesn't have a + * <query> and should use a default query which would normally just return + * a list of children of the reference point. + * + * @param aRuleElement the <rule> + * @param aQuerySet the query set + * @param aCanUseTemplate true if the query is valid + */ + nsresult + CompileSimpleQuery(nsIContent* aRuleElement, + nsTemplateQuerySet* aQuerySet, + bool* aCanUseTemplate); + + /** + * Compile the <conditions> tag in a rule + * + * @param aRule template rule + * @param aConditions <conditions> element + */ + nsresult + CompileConditions(nsTemplateRule* aRule, nsIContent* aConditions); + + /** + * Compile a <where> tag in a condition. The caller should set + * *aCurrentCondition to null for the first condition. This value will be + * updated to point to the new condition before returning. The conditions + * will be added to the rule aRule by this method. + * + * @param aRule template rule + * @param aCondition <where> element + * @param aCurrentCondition compiled condition + */ + nsresult + CompileWhereCondition(nsTemplateRule* aRule, + nsIContent* aCondition, + nsTemplateCondition** aCurrentCondition); + + /** + * Compile the <bindings> for an extended template syntax rule. + */ + nsresult + CompileBindings(nsTemplateRule* aRule, nsIContent* aBindings); + + /** + * Compile a single binding for an extended template syntax rule. + */ + nsresult + CompileBinding(nsTemplateRule* aRule, nsIContent* aBinding); + + /** + * Add automatic bindings for simple rules + */ + nsresult + AddSimpleRuleBindings(nsTemplateRule* aRule, nsIContent* aElement); + + static void + AddBindingsFor(nsXULTemplateBuilder* aSelf, + const nsAString& aVariable, + void* aClosure); + + /** + * Load the datasources for the template. shouldDelayBuilding is an out + * parameter which will be set to true to indicate that content building + * should not be performed yet as the datasource has not yet loaded. If + * false, the datasource has already loaded so building can proceed + * immediately. In the former case, the datasource or query processor + * should either rebuild the template or update results when the + * datasource is loaded as needed. + */ + nsresult + LoadDataSources(nsIDocument* aDoc, bool* shouldDelayBuilding); + + /** + * Called by LoadDataSources to load a datasource given a uri list + * in aDataSource. The list is a set of uris separated by spaces. + * If aIsRDFQuery is true, then this is for an RDF datasource which + * causes the method to check for additional flags specific to the + * RDF processor. + */ + nsresult + LoadDataSourceUrls(nsIDocument* aDocument, + const nsAString& aDataSources, + bool aIsRDFQuery, + bool* aShouldDelayBuilding); + + nsresult + InitHTMLTemplateRoot(); + + /** + * Determine which rule matches a given result. aContainer is used for + * tag matching and is optional for non-content generating builders. + * The returned matched rule is always one of the rules owned by the + * query set aQuerySet. + * + * @param aContainer parent where generated content will be inserted + * @param aResult result to match + * @param aQuerySet query set to examine the rules of + * @param aMatchedRule [out] rule that has matched, or null if any. + * @param aRuleIndex [out] index of the rule + */ + nsresult + DetermineMatchedRule(nsIContent* aContainer, + nsIXULTemplateResult* aResult, + nsTemplateQuerySet* aQuerySet, + nsTemplateRule** aMatchedRule, + int16_t *aRuleIndex); + + // XXX sigh, the string template foo doesn't mix with + // operator->*() on egcs-1.1.2, so we'll need to explicitly pass + // "this" and use good ol' fashioned static callbacks. + void + ParseAttribute(const nsAString& aAttributeValue, + void (*aVariableCallback)(nsXULTemplateBuilder* aThis, const nsAString&, void*), + void (*aTextCallback)(nsXULTemplateBuilder* aThis, const nsAString&, void*), + void* aClosure); + + nsresult + SubstituteText(nsIXULTemplateResult* aMatch, + const nsAString& aAttributeValue, + nsAString& aResult); + + static void + SubstituteTextAppendText(nsXULTemplateBuilder* aThis, const nsAString& aText, void* aClosure); + + static void + SubstituteTextReplaceVariable(nsXULTemplateBuilder* aThis, const nsAString& aVariable, void* aClosure); + + nsresult + IsSystemPrincipal(nsIPrincipal *principal, bool *result); + + /** + * Convenience method which gets a resource for a result. If a result + * doesn't have a resource set, it will create one from the result's id. + */ + nsresult GetResultResource(nsIXULTemplateResult* aResult, + nsIRDFResource** aResource); + +protected: + virtual ~nsXULTemplateBuilder(); + + nsCOMPtr<nsISupports> mDataSource; + nsCOMPtr<nsIRDFDataSource> mDB; + nsCOMPtr<nsIRDFCompositeDataSource> mCompDB; + + /** + * Circular reference, broken when the document is destroyed. + */ + nsCOMPtr<nsIContent> mRoot; + + /** + * The root result, translated from the root element's ref + */ + nsCOMPtr<nsIXULTemplateResult> mRootResult; + + nsCOMArray<nsIXULBuilderListener> mListeners; + + /** + * The query processor which generates results + */ + nsCOMPtr<nsIXULTemplateQueryProcessor> mQueryProcessor; + + /** + * The list of querysets + */ + nsTArray<nsTemplateQuerySet *> mQuerySets; + + /** + * Set to true if the rules have already been compiled + */ + bool mQueriesCompiled; + + /** + * The default reference and member variables. + */ + nsCOMPtr<nsIAtom> mRefVariable; + nsCOMPtr<nsIAtom> mMemberVariable; + + /** + * The match map contains nsTemplateMatch objects, one for each unique + * match found, keyed by the resource for that match. A particular match + * will contain a linked list of all of the matches for that unique result + * id. Only one is active at a time. When a match is retracted, look in + * the match map, remove it, and apply the next valid match in sequence to + * make active. + */ + nsDataHashtable<nsISupportsHashKey, nsTemplateMatch*> mMatchMap; + + // pseudo-constants + static nsrefcnt gRefCnt; + static nsIRDFService* gRDFService; + static nsIRDFContainerUtils* gRDFContainerUtils; + static nsIScriptSecurityManager* gScriptSecurityManager; + static nsIPrincipal* gSystemPrincipal; + static nsIObserverService* gObserverService; + + enum { + eDontTestEmpty = (1 << 0), + eDontRecurse = (1 << 1), + eLoggingEnabled = (1 << 2) + }; + + int32_t mFlags; + + /** + * Stack-based helper class to maintain a list of ``activated'' + * resources; i.e., resources for which we are currently building + * content. + */ + class ActivationEntry { + public: + nsIRDFResource *mResource; + ActivationEntry *mPrevious; + ActivationEntry **mLink; + + ActivationEntry(nsIRDFResource *aResource, ActivationEntry **aLink) + : mResource(aResource), + mPrevious(*aLink), + mLink(aLink) { *mLink = this; } + + ~ActivationEntry() { *mLink = mPrevious; } + }; + + /** + * The top of the stack of resources that we're currently building + * content for. + */ + ActivationEntry *mTop; + + /** + * Determine if a resource is currently on the activation stack. + */ + bool + IsActivated(nsIRDFResource *aResource); + + /** + * Returns true if content may be generated for a result, or false if it + * cannot, for example, if it would be created inside a closed container. + * Those results will be generated when the container is opened. + * If false is returned, no content should be generated. Possible + * insertion locations may optionally be set for new content, depending on + * the builder being used. Note that *aLocations or some items within + * aLocations may be null. + */ + virtual bool + GetInsertionLocations(nsIXULTemplateResult* aResult, + nsCOMArray<nsIContent>** aLocations) = 0; + + /** + * Must be implemented by subclasses. Handle removing the generated + * output for aOldMatch and adding new output for aNewMatch. Either + * aOldMatch or aNewMatch may be null. aContext is the location returned + * from the call to MayGenerateResult. + */ + virtual nsresult + ReplaceMatch(nsIXULTemplateResult* aOldResult, + nsTemplateMatch* aNewMatch, + nsTemplateRule* aNewMatchRule, + void *aContext) = 0; + + /** + * Must be implemented by subclasses. Handle change in bound + * variable values for aResult. aModifiedVars contains the set + * of variables that have changed. + * @param aResult the ersult for which variable bindings has changed. + * @param aModifiedVars the set of variables for which the bindings + * have changed. + */ + virtual nsresult + SynchronizeResult(nsIXULTemplateResult* aResult) = 0; + + /** + * Output a new match or removed match to the console. + * + * @param aId id of the result + * @param aMatch new or removed match + * @param aIsNew true for new matched, false for removed matches + */ + void + OutputMatchToLog(nsIRDFResource* aId, + nsTemplateMatch* aMatch, + bool aIsNew); + + virtual void Traverse(nsCycleCollectionTraversalCallback &cb) const + { + } + + /** + * Start observing events from the observer service and the given + * document. + * + * @param aDocument the document to observe + */ + void StartObserving(nsIDocument* aDocument); + + /** + * Stop observing events from the observer service and any associated + * document. + */ + void StopObserving(); + + /** + * Document that we're observing. Weak ref! + */ + nsIDocument* mObservedDocument; +}; + +#endif // nsXULTemplateBuilder_h__ diff --git a/dom/xul/templates/nsXULTemplateQueryProcessorRDF.cpp b/dom/xul/templates/nsXULTemplateQueryProcessorRDF.cpp new file mode 100644 index 000000000..732e545d0 --- /dev/null +++ b/dom/xul/templates/nsXULTemplateQueryProcessorRDF.cpp @@ -0,0 +1,1825 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* 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 "nsCOMPtr.h" +#include "nsICollation.h" +#include "nsIDOMNode.h" +#include "nsIRDFNode.h" +#include "nsIRDFObserver.h" +#include "nsIRDFRemoteDataSource.h" +#include "nsIRDFInferDataSource.h" +#include "nsIRDFService.h" +#include "nsRDFCID.h" +#include "nsIServiceManager.h" +#include "nsNameSpaceManager.h" +#include "nsGkAtoms.h" +#include "nsIDOMDocument.h" +#include "nsAttrName.h" +#include "rdf.h" +#include "nsArrayUtils.h" +#include "nsIURI.h" + +#include "nsContentTestNode.h" +#include "nsRDFConInstanceTestNode.h" +#include "nsRDFConMemberTestNode.h" +#include "nsRDFPropertyTestNode.h" +#include "nsInstantiationNode.h" +#include "nsRDFTestNode.h" +#include "nsXULContentUtils.h" +#include "nsXULTemplateBuilder.h" +#include "nsXULTemplateResultRDF.h" +#include "nsXULTemplateResultSetRDF.h" +#include "nsXULTemplateQueryProcessorRDF.h" +#include "nsXULSortService.h" +#include "nsIDocument.h" + +//---------------------------------------------------------------------- + +#define PARSE_TYPE_INTEGER "Integer" + +nsrefcnt nsXULTemplateQueryProcessorRDF::gRefCnt = 0; +nsIRDFService* nsXULTemplateQueryProcessorRDF::gRDFService; +nsIRDFContainerUtils* nsXULTemplateQueryProcessorRDF::gRDFContainerUtils; +nsIRDFResource* nsXULTemplateQueryProcessorRDF::kNC_BookmarkSeparator; +nsIRDFResource* nsXULTemplateQueryProcessorRDF::kRDF_type; + +NS_IMPL_CYCLE_COLLECTION_CLASS(nsXULTemplateQueryProcessorRDF) + +NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(nsXULTemplateQueryProcessorRDF) + tmp->Done(); +NS_IMPL_CYCLE_COLLECTION_UNLINK_END + +NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(nsXULTemplateQueryProcessorRDF) + NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mDB) + NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mLastRef) + + for (auto it = tmp->mBindingDependencies.Iter(); !it.Done(); it.Next()) { + nsXULTemplateQueryProcessorRDF::ResultArray* array = it.UserData(); + int32_t count = array->Length(); + for (int32_t i = 0; i < count; ++i) { + cb.NoteXPCOMChild(array->ElementAt(i)); + } + } + + for (auto it = tmp->mMemoryElementToResultMap.Iter(); + !it.Done(); + it.Next()) { + nsCOMArray<nsXULTemplateResultRDF>* array = it.UserData(); + int32_t count = array->Count(); + for (int32_t i = 0; i < count; ++i) { + cb.NoteXPCOMChild(array->ObjectAt(i)); + } + } + + for (auto it = tmp->mRuleToBindingsMap.Iter(); !it.Done(); it.Next()) { + cb.NoteXPCOMChild(it.Key()); + } + + NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mQueries) +NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END + +NS_IMPL_CYCLE_COLLECTING_ADDREF(nsXULTemplateQueryProcessorRDF) +NS_IMPL_CYCLE_COLLECTING_RELEASE(nsXULTemplateQueryProcessorRDF) +NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(nsXULTemplateQueryProcessorRDF) + NS_INTERFACE_MAP_ENTRY(nsIXULTemplateQueryProcessor) + NS_INTERFACE_MAP_ENTRY(nsIRDFObserver) + NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIXULTemplateQueryProcessor) +NS_INTERFACE_MAP_END + +nsXULTemplateQueryProcessorRDF::nsXULTemplateQueryProcessorRDF(void) + : mDB(nullptr), + mBuilder(nullptr), + mQueryProcessorRDFInited(false), + mGenerationStarted(false), + mUpdateBatchNest(0), + mSimpleRuleMemberTest(nullptr) +{ + gRefCnt++; +} + +nsXULTemplateQueryProcessorRDF::~nsXULTemplateQueryProcessorRDF(void) +{ + if (--gRefCnt == 0) { + NS_IF_RELEASE(gRDFService); + NS_IF_RELEASE(gRDFContainerUtils); + NS_IF_RELEASE(kNC_BookmarkSeparator); + NS_IF_RELEASE(kRDF_type); + } +} + +nsresult +nsXULTemplateQueryProcessorRDF::InitGlobals() +{ + nsresult rv; + + // Initialize the global shared reference to the service + // manager and get some shared resource objects. + if (!gRDFService) { + NS_DEFINE_CID(kRDFServiceCID, NS_RDFSERVICE_CID); + rv = CallGetService(kRDFServiceCID, &gRDFService); + if (NS_FAILED(rv)) + return rv; + } + + if (!gRDFContainerUtils) { + NS_DEFINE_CID(kRDFContainerUtilsCID, NS_RDFCONTAINERUTILS_CID); + rv = CallGetService(kRDFContainerUtilsCID, &gRDFContainerUtils); + if (NS_FAILED(rv)) + return rv; + } + + if (!kNC_BookmarkSeparator) { + gRDFService->GetResource( + NS_LITERAL_CSTRING(NC_NAMESPACE_URI "BookmarkSeparator"), + &kNC_BookmarkSeparator); + } + + if (!kRDF_type) { + gRDFService->GetResource( + NS_LITERAL_CSTRING(RDF_NAMESPACE_URI "type"), + &kRDF_type); + } + + return NS_OK; +} + +//---------------------------------------------------------------------- +// +// nsIXULTemplateQueryProcessor interface +// + +NS_IMETHODIMP +nsXULTemplateQueryProcessorRDF::GetDatasource(nsIArray* aDataSources, + nsIDOMNode* aRootNode, + bool aIsTrusted, + nsIXULTemplateBuilder* aBuilder, + bool* aShouldDelayBuilding, + nsISupports** aResult) +{ + nsCOMPtr<nsIRDFCompositeDataSource> compDB; + nsCOMPtr<nsIContent> root = do_QueryInterface(aRootNode); + nsresult rv; + + *aResult = nullptr; + *aShouldDelayBuilding = false; + + NS_ENSURE_TRUE(root, NS_ERROR_UNEXPECTED); + + // make sure the RDF service is set up + rv = InitGlobals(); + NS_ENSURE_SUCCESS(rv, rv); + + // create a database for the builder + compDB = do_CreateInstance(NS_RDF_DATASOURCE_CONTRACTID_PREFIX + "composite-datasource"); + if (!compDB) { + NS_ERROR("unable to construct new composite data source"); + return NS_ERROR_UNEXPECTED; + } + + // check for magical attributes. XXX move to ``flags''? + if (root->AttrValueIs(kNameSpaceID_None, + nsGkAtoms::coalesceduplicatearcs, + nsGkAtoms::_false, eCaseMatters)) + compDB->SetCoalesceDuplicateArcs(false); + + if (root->AttrValueIs(kNameSpaceID_None, + nsGkAtoms::allownegativeassertions, + nsGkAtoms::_false, eCaseMatters)) + compDB->SetAllowNegativeAssertions(false); + + if (aIsTrusted) { + // If we're a privileged (e.g., chrome) document, then add the + // local store as the first data source in the db. Note that + // we _might_ not be able to get a local store if we haven't + // got a profile to read from yet. + nsCOMPtr<nsIRDFDataSource> localstore; + rv = gRDFService->GetDataSource("rdf:local-store", + getter_AddRefs(localstore)); + NS_ENSURE_SUCCESS(rv, rv); + + rv = compDB->AddDataSource(localstore); + NS_ASSERTION(NS_SUCCEEDED(rv), "unable to add local store to db"); + NS_ENSURE_SUCCESS(rv, rv); + } + + uint32_t length, index; + rv = aDataSources->GetLength(&length); + NS_ENSURE_SUCCESS(rv,rv); + + for (index = 0; index < length; index++) { + + nsCOMPtr<nsIURI> uri = do_QueryElementAt(aDataSources, index); + if (!uri) // we ignore other datasources than uri + continue; + + nsCOMPtr<nsIRDFDataSource> ds; + nsAutoCString uristrC; + uri->GetSpec(uristrC); + + rv = gRDFService->GetDataSource(uristrC.get(), getter_AddRefs(ds)); + + if (NS_FAILED(rv)) { + // This is only a warning because the data source may not + // be accessible for any number of reasons, including + // security, a bad URL, etc. + #ifdef DEBUG + nsAutoCString msg; + msg.AppendLiteral("unable to load datasource '"); + msg.Append(uristrC); + msg.Append('\''); + NS_WARNING(msg.get()); + #endif + continue; + } + + compDB->AddDataSource(ds); + } + + + // check if we were given an inference engine type + nsAutoString infer; + nsCOMPtr<nsIRDFDataSource> db; + root->GetAttr(kNameSpaceID_None, nsGkAtoms::infer, infer); + if (!infer.IsEmpty()) { + nsCString inferCID(NS_RDF_INFER_DATASOURCE_CONTRACTID_PREFIX); + AppendUTF16toUTF8(infer, inferCID); + nsCOMPtr<nsIRDFInferDataSource> inferDB = + do_CreateInstance(inferCID.get()); + + if (inferDB) { + inferDB->SetBaseDataSource(compDB); + db = do_QueryInterface(inferDB); + } + else { + NS_WARNING("failed to construct inference engine specified on template"); + } + } + + if (!db) + db = compDB; + + return CallQueryInterface(db, aResult); +} + +NS_IMETHODIMP +nsXULTemplateQueryProcessorRDF::InitializeForBuilding(nsISupports* aDatasource, + nsIXULTemplateBuilder* aBuilder, + nsIDOMNode* aRootNode) +{ + if (!mQueryProcessorRDFInited) { + nsresult rv = InitGlobals(); + if (NS_FAILED(rv)) + return rv; + + mQueryProcessorRDFInited = true; + } + + // don't do anything if generation has already been done + if (mGenerationStarted) + return NS_ERROR_UNEXPECTED; + + mDB = do_QueryInterface(aDatasource); + mBuilder = aBuilder; + + ComputeContainmentProperties(aRootNode); + + // Add ourselves as a datasource observer + if (mDB) + mDB->AddObserver(this); + + return NS_OK; +} + +NS_IMETHODIMP +nsXULTemplateQueryProcessorRDF::Done() +{ + if (!mQueryProcessorRDFInited) + return NS_OK; + + if (mDB) + mDB->RemoveObserver(this); + + mDB = nullptr; + mBuilder = nullptr; + mRefVariable = nullptr; + mLastRef = nullptr; + + mGenerationStarted = false; + mUpdateBatchNest = 0; + + mContainmentProperties.Clear(); + + for (ReteNodeSet::Iterator node = mAllTests.First(); + node != mAllTests.Last(); ++node) + delete *node; + + mAllTests.Clear(); + mRDFTests.Clear(); + mQueries.Clear(); + + mSimpleRuleMemberTest = nullptr; + + mBindingDependencies.Clear(); + + mMemoryElementToResultMap.Clear(); + + mRuleToBindingsMap.Clear(); + + return NS_OK; +} + +NS_IMETHODIMP +nsXULTemplateQueryProcessorRDF::CompileQuery(nsIXULTemplateBuilder* aBuilder, + nsIDOMNode* aQueryNode, + nsIAtom* aRefVariable, + nsIAtom* aMemberVariable, + nsISupports** _retval) +{ + RefPtr<nsRDFQuery> query = new nsRDFQuery(this); + if (!query) + return NS_ERROR_OUT_OF_MEMORY; + + query->mRefVariable = aRefVariable; + if (!mRefVariable) + mRefVariable = aRefVariable; + + if (!aMemberVariable) + query->mMemberVariable = NS_Atomize("?"); + else + query->mMemberVariable = aMemberVariable; + + nsresult rv; + TestNode *lastnode = nullptr; + + nsCOMPtr<nsIContent> content = do_QueryInterface(aQueryNode); + + if (content->NodeInfo()->Equals(nsGkAtoms::_template, kNameSpaceID_XUL)) { + // simplified syntax with no rules + + query->SetSimple(); + NS_ASSERTION(!mSimpleRuleMemberTest, + "CompileQuery called twice with the same template"); + if (!mSimpleRuleMemberTest) + rv = CompileSimpleQuery(query, content, &lastnode); + else + rv = NS_ERROR_FAILURE; + } + else if (content->NodeInfo()->Equals(nsGkAtoms::rule, kNameSpaceID_XUL)) { + // simplified syntax with at least one rule + query->SetSimple(); + rv = CompileSimpleQuery(query, content, &lastnode); + } + else { + rv = CompileExtendedQuery(query, content, &lastnode); + } + + if (NS_FAILED(rv)) + return rv; + + query->SetQueryNode(aQueryNode); + + nsInstantiationNode* instnode = new nsInstantiationNode(this, query); + + // this and other functions always add nodes to mAllTests first. That + // way if something fails, the node will just sit harmlessly in mAllTests + // where it can be deleted later. + rv = mAllTests.Add(instnode); + if (NS_FAILED(rv)) { + delete instnode; + return rv; + } + + rv = lastnode->AddChild(instnode); + if (NS_FAILED(rv)) + return rv; + + mQueries.AppendElement(query); + + query.forget(_retval); + + return NS_OK; +} + +NS_IMETHODIMP +nsXULTemplateQueryProcessorRDF::GenerateResults(nsISupports* aDatasource, + nsIXULTemplateResult* aRef, + nsISupports* aQuery, + nsISimpleEnumerator** aResults) +{ + nsCOMPtr<nsITemplateRDFQuery> rdfquery = do_QueryInterface(aQuery); + if (! rdfquery) + return NS_ERROR_INVALID_ARG; + + mGenerationStarted = true; + + // should be safe to cast here since the query is a + // non-scriptable nsITemplateRDFQuery + nsRDFQuery* query = static_cast<nsRDFQuery *>(aQuery); + + *aResults = nullptr; + + nsCOMPtr<nsISimpleEnumerator> results; + + if (aRef) { + // make sure that cached results were generated for this ref, and if not, + // regenerate them. Otherwise, things will go wrong for templates bound to + // an HTML element as they are not generated lazily. + if (aRef == mLastRef) { + query->UseCachedResults(getter_AddRefs(results)); + } + else { + // clear the cached results + int32_t count = mQueries.Length(); + for (int32_t r = 0; r < count; r++) { + mQueries[r]->ClearCachedResults(); + } + } + + if (! results) { + if (! query->mRefVariable) + query->mRefVariable = NS_Atomize("?uri"); + + nsCOMPtr<nsIRDFResource> refResource; + aRef->GetResource(getter_AddRefs(refResource)); + if (! refResource) + return NS_ERROR_FAILURE; + + // Propagate the assignments through the network + TestNode* root = query->GetRoot(); + + if (query->IsSimple() && mSimpleRuleMemberTest) { + // get the top node in the simple rule tree + root = mSimpleRuleMemberTest->GetParent(); + mLastRef = aRef; + } + + if (MOZ_LOG_TEST(gXULTemplateLog, LogLevel::Debug)) { + nsAutoString id; + aRef->GetId(id); + + nsAutoString rvar; + query->mRefVariable->ToString(rvar); + nsAutoString mvar; + query->mMemberVariable->ToString(mvar); + + MOZ_LOG(gXULTemplateLog, LogLevel::Debug, + ("QueryProcessor::GenerateResults using ref %s and vars [ ref: %s member: %s]", + NS_ConvertUTF16toUTF8(id).get(), + NS_ConvertUTF16toUTF8(rvar).get(), + NS_ConvertUTF16toUTF8(mvar).get())); + } + + if (root) { + // the seed is the initial instantiation, which has a single + // assignment holding the reference point + Instantiation seed; + seed.AddAssignment(query->mRefVariable, refResource); + + InstantiationSet* instantiations = new InstantiationSet(); + instantiations->Append(seed); + + // if the propagation caused a match, then the results will be + // cached in the query, retrieved below by calling + // UseCachedResults. The matching result set owns the + // instantiations and will delete them when results have been + // iterated over. If the propagation did not match, the + // instantiations need to be deleted. + bool owned = false; + nsresult rv = root->Propagate(*instantiations, false, owned); + if (! owned) + delete instantiations; + if (NS_FAILED(rv)) + return rv; + + query->UseCachedResults(getter_AddRefs(results)); + } + } + } + + if (! results) { + // no results were found so create an empty set + results = new nsXULTemplateResultSetRDF(this, query, nullptr); + } + + results.swap(*aResults); + + return NS_OK; +} + +NS_IMETHODIMP +nsXULTemplateQueryProcessorRDF::AddBinding(nsIDOMNode* aRuleNode, + nsIAtom* aVar, + nsIAtom* aRef, + const nsAString& aExpr) +{ + // add a <binding> to a rule. When a result is matched, the bindings are + // examined to add additional variable assignments + + // bindings can't be added once result generation has started, otherwise + // the array sizes will get out of sync + if (mGenerationStarted) + return NS_ERROR_UNEXPECTED; + + nsCOMPtr<nsIRDFResource> property; + nsresult rv = gRDFService->GetUnicodeResource(aExpr, getter_AddRefs(property)); + if (NS_FAILED(rv)) + return rv; + + RefPtr<RDFBindingSet> bindings = mRuleToBindingsMap.GetWeak(aRuleNode); + if (!bindings) { + bindings = new RDFBindingSet(); + mRuleToBindingsMap.Put(aRuleNode, bindings); + } + + return bindings->AddBinding(aVar, aRef, property); +} + +NS_IMETHODIMP +nsXULTemplateQueryProcessorRDF::TranslateRef(nsISupports* aDatasource, + const nsAString& aRefString, + nsIXULTemplateResult** aRef) +{ + // make sure the RDF service is set up + nsresult rv = InitGlobals(); + if (NS_FAILED(rv)) + return rv; + + nsCOMPtr<nsIRDFResource> uri; + gRDFService->GetUnicodeResource(aRefString, getter_AddRefs(uri)); + + RefPtr<nsXULTemplateResultRDF> refresult = new nsXULTemplateResultRDF(uri); + if (! refresult) + return NS_ERROR_OUT_OF_MEMORY; + + refresult.forget(aRef); + + return NS_OK; +} + +NS_IMETHODIMP +nsXULTemplateQueryProcessorRDF::CompareResults(nsIXULTemplateResult* aLeft, + nsIXULTemplateResult* aRight, + nsIAtom* aVar, + uint32_t aSortHints, + int32_t* aResult) +{ + NS_ENSURE_ARG_POINTER(aLeft); + NS_ENSURE_ARG_POINTER(aRight); + + *aResult = 0; + + // for natural order sorting, use the index in the RDF container for the + // order. If there is no container, just sort them arbitrarily. + if (!aVar) { + // if a result has a negative index, just sort it first + int32_t leftindex = GetContainerIndexOf(aLeft); + int32_t rightindex = GetContainerIndexOf(aRight); + *aResult = leftindex == rightindex ? 0 : + leftindex > rightindex ? 1 : + -1; + return NS_OK; + } + + nsDependentAtomString sortkey(aVar); + + nsCOMPtr<nsISupports> leftNode, rightNode; + + if (!sortkey.IsEmpty() && sortkey[0] != '?' && + !StringBeginsWith(sortkey, NS_LITERAL_STRING("rdf:")) && + mDB) { + // if the sort key is not a template variable, it should be an RDF + // predicate. Get the targets and compare those instead. + nsCOMPtr<nsIRDFResource> predicate; + nsresult rv = gRDFService->GetUnicodeResource(sortkey, getter_AddRefs(predicate)); + NS_ENSURE_SUCCESS(rv, rv); + + // create a predicate with '?sort=true' appended. This special + // predicate may be used to have a different sort value than the + // displayed value + sortkey.AppendLiteral("?sort=true"); + + nsCOMPtr<nsIRDFResource> sortPredicate; + rv = gRDFService->GetUnicodeResource(sortkey, getter_AddRefs(sortPredicate)); + NS_ENSURE_SUCCESS(rv, rv); + + rv = GetSortValue(aLeft, predicate, sortPredicate, getter_AddRefs(leftNode)); + NS_ENSURE_SUCCESS(rv, rv); + + rv = GetSortValue(aRight, predicate, sortPredicate, getter_AddRefs(rightNode)); + NS_ENSURE_SUCCESS(rv, rv); + } + else { + // get the values for the sort key from the results + aLeft->GetBindingObjectFor(aVar, getter_AddRefs(leftNode)); + aRight->GetBindingObjectFor(aVar, getter_AddRefs(rightNode)); + } + + { + // Literals? + nsCOMPtr<nsIRDFLiteral> l = do_QueryInterface(leftNode); + if (l) { + nsCOMPtr<nsIRDFLiteral> r = do_QueryInterface(rightNode); + if (r) { + const char16_t *lstr, *rstr; + l->GetValueConst(&lstr); + r->GetValueConst(&rstr); + + *aResult = XULSortServiceImpl::CompareValues( + nsDependentString(lstr), + nsDependentString(rstr), aSortHints); + } + + return NS_OK; + } + } + + { + // Dates? + nsCOMPtr<nsIRDFDate> l = do_QueryInterface(leftNode); + if (l) { + nsCOMPtr<nsIRDFDate> r = do_QueryInterface(rightNode); + if (r) { + PRTime ldate, rdate; + l->GetValue(&ldate); + r->GetValue(&rdate); + + int64_t delta = ldate - rdate; + if (delta == 0) + *aResult = 0; + else if (delta >= 0) + *aResult = 1; + else + *aResult = -1; + } + + return NS_OK; + } + } + + { + // Integers? + nsCOMPtr<nsIRDFInt> l = do_QueryInterface(leftNode); + if (l) { + nsCOMPtr<nsIRDFInt> r = do_QueryInterface(rightNode); + if (r) { + int32_t lval, rval; + l->GetValue(&lval); + r->GetValue(&rval); + + *aResult = lval - rval; + } + + return NS_OK; + } + } + + nsICollation* collation = nsXULContentUtils::GetCollation(); + if (collation) { + // Blobs? (We can only compare these reasonably if we have a + // collation object.) + nsCOMPtr<nsIRDFBlob> l = do_QueryInterface(leftNode); + if (l) { + nsCOMPtr<nsIRDFBlob> r = do_QueryInterface(rightNode); + if (r) { + const uint8_t *lval, *rval; + int32_t llen, rlen; + l->GetValue(&lval); + l->GetLength(&llen); + r->GetValue(&rval); + r->GetLength(&rlen); + + collation->CompareRawSortKey(lval, llen, rval, rlen, aResult); + } + } + } + + // if the results are none of the above, just pretend that they are equal + return NS_OK; +} + +//---------------------------------------------------------------------- +// +// nsIRDFObserver interface +// + + +NS_IMETHODIMP +nsXULTemplateQueryProcessorRDF::OnAssert(nsIRDFDataSource* aDataSource, + nsIRDFResource* aSource, + nsIRDFResource* aProperty, + nsIRDFNode* aTarget) +{ + // Ignore updates if we're batching + if (mUpdateBatchNest) + return(NS_OK); + + if (! mBuilder) + return NS_OK; + + LOG("onassert", aSource, aProperty, aTarget); + + Propagate(aSource, aProperty, aTarget); + SynchronizeAll(aSource, aProperty, nullptr, aTarget); + return NS_OK; +} + + + +NS_IMETHODIMP +nsXULTemplateQueryProcessorRDF::OnUnassert(nsIRDFDataSource* aDataSource, + nsIRDFResource* aSource, + nsIRDFResource* aProperty, + nsIRDFNode* aTarget) +{ + // Ignore updates if we're batching + if (mUpdateBatchNest) + return NS_OK; + + if (! mBuilder) + return NS_OK; + + LOG("onunassert", aSource, aProperty, aTarget); + + Retract(aSource, aProperty, aTarget); + SynchronizeAll(aSource, aProperty, aTarget, nullptr); + return NS_OK; +} + + +NS_IMETHODIMP +nsXULTemplateQueryProcessorRDF::OnChange(nsIRDFDataSource* aDataSource, + nsIRDFResource* aSource, + nsIRDFResource* aProperty, + nsIRDFNode* aOldTarget, + nsIRDFNode* aNewTarget) +{ + // Ignore updates if we're batching + if (mUpdateBatchNest) + return NS_OK; + + if (! mBuilder) + return NS_OK; + + LOG("onchange", aSource, aProperty, aNewTarget); + + if (aOldTarget) { + // Pull any old results that were relying on aOldTarget + Retract(aSource, aProperty, aOldTarget); + } + + if (aNewTarget) { + // Fire any new results that are activated by aNewTarget + Propagate(aSource, aProperty, aNewTarget); + } + + // Synchronize any of the content model that may have changed. + SynchronizeAll(aSource, aProperty, aOldTarget, aNewTarget); + return NS_OK; +} + + +NS_IMETHODIMP +nsXULTemplateQueryProcessorRDF::OnMove(nsIRDFDataSource* aDataSource, + nsIRDFResource* aOldSource, + nsIRDFResource* aNewSource, + nsIRDFResource* aProperty, + nsIRDFNode* aTarget) +{ + // Ignore updates if we're batching + if (mUpdateBatchNest) + return NS_OK; + + NS_NOTYETIMPLEMENTED("write me"); + return NS_ERROR_NOT_IMPLEMENTED; +} + + +NS_IMETHODIMP +nsXULTemplateQueryProcessorRDF::OnBeginUpdateBatch(nsIRDFDataSource* aDataSource) +{ + mUpdateBatchNest++; + return NS_OK; +} + + +NS_IMETHODIMP +nsXULTemplateQueryProcessorRDF::OnEndUpdateBatch(nsIRDFDataSource* aDataSource) +{ + NS_ASSERTION(mUpdateBatchNest > 0, "badly nested update batch"); + if (--mUpdateBatchNest <= 0) { + mUpdateBatchNest = 0; + + if (mBuilder) + mBuilder->Rebuild(); + } + + return NS_OK; +} + +nsresult +nsXULTemplateQueryProcessorRDF::Propagate(nsIRDFResource* aSource, + nsIRDFResource* aProperty, + nsIRDFNode* aTarget) +{ + // When a new assertion is added to the graph, determine any new matches + // that must be added to the template builder. First, iterate through all + // the RDF tests (<member> and <triple> tests), and find the topmost test + // that would be affected by the new assertion. + nsresult rv; + + ReteNodeSet livenodes; + + if (MOZ_LOG_TEST(gXULTemplateLog, LogLevel::Debug)) { + const char* sourceStr; + aSource->GetValueConst(&sourceStr); + const char* propertyStr; + aProperty->GetValueConst(&propertyStr); + nsAutoString targetStr; + nsXULContentUtils::GetTextForNode(aTarget, targetStr); + + MOZ_LOG(gXULTemplateLog, LogLevel::Debug, + ("nsXULTemplateQueryProcessorRDF::Propagate: [%s] -> [%s] -> [%s]\n", + sourceStr, propertyStr, NS_ConvertUTF16toUTF8(targetStr).get())); + } + + { + ReteNodeSet::Iterator last = mRDFTests.Last(); + for (ReteNodeSet::Iterator i = mRDFTests.First(); i != last; ++i) { + nsRDFTestNode* rdftestnode = static_cast<nsRDFTestNode*>(*i); + + Instantiation seed; + if (rdftestnode->CanPropagate(aSource, aProperty, aTarget, seed)) { + rv = livenodes.Add(rdftestnode); + if (NS_FAILED(rv)) + return rv; + } + } + } + + // Now, we'll go through each, and any that aren't dominated by + // another live node will be used to propagate the assertion + // through the rule network + { + ReteNodeSet::Iterator last = livenodes.Last(); + for (ReteNodeSet::Iterator i = livenodes.First(); i != last; ++i) { + nsRDFTestNode* rdftestnode = static_cast<nsRDFTestNode*>(*i); + + // What happens here is we create an instantiation as if we were + // at the found test in the rule network. For example, if the + // found test was a member test (parent => child), the parent + // and child variables are assigned the values provided by the new + // RDF assertion in the graph. The Constrain call is used to go + // up to earlier RDF tests, filling in variables as it goes. + // Constrain will eventually get up to the top node, an + // nsContentTestNode, which takes the value of the reference + // variable and calls the template builder to see if a result has + // been generated already for the reference value. If it hasn't, + // the new assertion couldn't cause a new match. If the result + // exists, call Propagate to continue to the later RDF tests to + // fill in the rest of the variable assignments. + + // Bogus, to get the seed instantiation + Instantiation seed; + rdftestnode->CanPropagate(aSource, aProperty, aTarget, seed); + + InstantiationSet* instantiations = new InstantiationSet(); + instantiations->Append(seed); + + rv = rdftestnode->Constrain(*instantiations); + if (NS_FAILED(rv)) { + delete instantiations; + return rv; + } + + bool owned = false; + if (!instantiations->Empty()) + rv = rdftestnode->Propagate(*instantiations, true, owned); + + // owned should always be false in update mode, but check just + // to be sure + if (!owned) + delete instantiations; + if (NS_FAILED(rv)) + return rv; + } + } + + return NS_OK; +} + + +nsresult +nsXULTemplateQueryProcessorRDF::Retract(nsIRDFResource* aSource, + nsIRDFResource* aProperty, + nsIRDFNode* aTarget) +{ + + if (MOZ_LOG_TEST(gXULTemplateLog, LogLevel::Debug)) { + const char* sourceStr; + aSource->GetValueConst(&sourceStr); + const char* propertyStr; + aProperty->GetValueConst(&propertyStr); + nsAutoString targetStr; + nsXULContentUtils::GetTextForNode(aTarget, targetStr); + + MOZ_LOG(gXULTemplateLog, LogLevel::Debug, + ("nsXULTemplateQueryProcessorRDF::Retract: [%s] -> [%s] -> [%s]\n", + sourceStr, propertyStr, NS_ConvertUTF16toUTF8(targetStr).get())); + } + + // Retract any currently active rules that will no longer be matched. + ReteNodeSet::ConstIterator lastnode = mRDFTests.Last(); + for (ReteNodeSet::ConstIterator node = mRDFTests.First(); node != lastnode; ++node) { + const nsRDFTestNode* rdftestnode = static_cast<const nsRDFTestNode*>(*node); + + rdftestnode->Retract(aSource, aProperty, aTarget); + + // Now fire any newly revealed rules + // XXXwaterson yo. write me. + // The intent here is to handle any rules that might be + // "revealed" by the removal of an assertion from the datasource. + // Waterson doesn't think we support negated conditions in a rule. + // Nor is he sure that this is currently useful. + } + + return NS_OK; +} + +nsresult +nsXULTemplateQueryProcessorRDF::SynchronizeAll(nsIRDFResource* aSource, + nsIRDFResource* aProperty, + nsIRDFNode* aOldTarget, + nsIRDFNode* aNewTarget) +{ + // Update each match that contains <aSource, aProperty, aOldTarget>. + + // Get all the matches whose assignments are currently supported + // by aSource and aProperty: we'll need to recompute them. + ResultArray* results; + if (!mBindingDependencies.Get(aSource, &results) || !mBuilder) + return NS_OK; + + uint32_t length = results->Length(); + + for (uint32_t r = 0; r < length; r++) { + nsXULTemplateResultRDF* result = (*results)[r]; + if (result) { + // synchronize the result's bindings and then update the builder + // so that content can be updated + if (result->SyncAssignments(aSource, aProperty, aNewTarget)) { + nsITemplateRDFQuery* query = result->Query(); + if (query) { + nsCOMPtr<nsIDOMNode> querynode; + query->GetQueryNode(getter_AddRefs(querynode)); + + mBuilder->ResultBindingChanged(result); + } + } + } + } + + return NS_OK; +} + +nsresult +nsXULTemplateQueryProcessorRDF::Log(const char* aOperation, + nsIRDFResource* aSource, + nsIRDFResource* aProperty, + nsIRDFNode* aTarget) +{ + if (MOZ_LOG_TEST(gXULTemplateLog, LogLevel::Debug)) { + nsresult rv; + + const char* sourceStr; + rv = aSource->GetValueConst(&sourceStr); + if (NS_FAILED(rv)) + return rv; + + MOZ_LOG(gXULTemplateLog, LogLevel::Debug, + ("xultemplate[%p] %8s [%s]--", this, aOperation, sourceStr)); + + const char* propertyStr; + rv = aProperty->GetValueConst(&propertyStr); + if (NS_FAILED(rv)) + return rv; + + nsAutoString targetStr; + rv = nsXULContentUtils::GetTextForNode(aTarget, targetStr); + if (NS_FAILED(rv)) + return rv; + + nsAutoCString targetstrC; + targetstrC.AssignWithConversion(targetStr); + MOZ_LOG(gXULTemplateLog, LogLevel::Debug, + (" --[%s]-->[%s]", + propertyStr, + targetstrC.get())); + } + return NS_OK; +} + +nsresult +nsXULTemplateQueryProcessorRDF::CheckContainer(nsIRDFResource* aResource, + bool* aIsContainer) +{ + NS_ENSURE_ARG_POINTER(aIsContainer); + NS_ENSURE_STATE(mDB); + + // We have to look at all of the arcs extending out of the + // resource: if any of them are that "containment" property, then + // we know we'll have children. + bool isContainer = false; + + for (nsResourceSet::ConstIterator property = mContainmentProperties.First(); + property != mContainmentProperties.Last(); + property++) { + bool hasArc = false; + mDB->HasArcOut(aResource, *property, &hasArc); + + if (hasArc) { + // Well, it's a container... + isContainer = true; + break; + } + } + + // If we get here, and we're still not sure if it's a container, + // then see if it's an RDF container + if (! isContainer) { + gRDFContainerUtils->IsContainer(mDB, aResource, &isContainer); + } + + *aIsContainer = isContainer; + + return NS_OK; +} + +nsresult +nsXULTemplateQueryProcessorRDF::CheckEmpty(nsIRDFResource* aResource, + bool* aIsEmpty) +{ + NS_ENSURE_STATE(mDB); + *aIsEmpty = true; + + for (nsResourceSet::ConstIterator property = mContainmentProperties.First(); + property != mContainmentProperties.Last(); + property++) { + + nsCOMPtr<nsIRDFNode> dummy; + mDB->GetTarget(aResource, *property, true, getter_AddRefs(dummy)); + + if (dummy) { + *aIsEmpty = false; + break; + } + } + + if (*aIsEmpty){ + return nsXULTemplateQueryProcessorRDF::gRDFContainerUtils-> + IsEmpty(mDB, aResource, aIsEmpty); + } + + return NS_OK; +} + +nsresult +nsXULTemplateQueryProcessorRDF::CheckIsSeparator(nsIRDFResource* aResource, + bool* aIsSeparator) +{ + NS_ENSURE_STATE(mDB); + return mDB->HasAssertion(aResource, kRDF_type, kNC_BookmarkSeparator, + true, aIsSeparator); +} + +//---------------------------------------------------------------------- + +nsresult +nsXULTemplateQueryProcessorRDF::ComputeContainmentProperties(nsIDOMNode* aRootNode) +{ + // The 'containment' attribute on the root node is a + // whitespace-separated list that tells us which properties we + // should use to test for containment. + nsresult rv; + + mContainmentProperties.Clear(); + + nsCOMPtr<nsIContent> content = do_QueryInterface(aRootNode); + + nsAutoString containment; + content->GetAttr(kNameSpaceID_None, nsGkAtoms::containment, containment); + + uint32_t len = containment.Length(); + uint32_t offset = 0; + while (offset < len) { + while (offset < len && nsCRT::IsAsciiSpace(containment[offset])) + ++offset; + + if (offset >= len) + break; + + uint32_t end = offset; + while (end < len && !nsCRT::IsAsciiSpace(containment[end])) + ++end; + + nsAutoString propertyStr; + containment.Mid(propertyStr, offset, end - offset); + + nsCOMPtr<nsIRDFResource> property; + rv = gRDFService->GetUnicodeResource(propertyStr, getter_AddRefs(property)); + if (NS_FAILED(rv)) + return rv; + + rv = mContainmentProperties.Add(property); + if (NS_FAILED(rv)) + return rv; + + offset = end; + } + +#define TREE_PROPERTY_HACK 1 +#if defined(TREE_PROPERTY_HACK) + if (! len) { + // Some ever-present membership tests. + mContainmentProperties.Add(nsXULContentUtils::NC_child); + mContainmentProperties.Add(nsXULContentUtils::NC_Folder); + } +#endif + + return NS_OK; +} + +nsresult +nsXULTemplateQueryProcessorRDF::CompileExtendedQuery(nsRDFQuery* aQuery, + nsIContent* aConditions, + TestNode** aLastNode) +{ + // Compile an extended query's children + nsContentTestNode* idnode = + new nsContentTestNode(this, aQuery->mRefVariable); + + aQuery->SetRoot(idnode); + nsresult rv = mAllTests.Add(idnode); + if (NS_FAILED(rv)) { + delete idnode; + return rv; + } + + TestNode* prevnode = idnode; + + for (nsIContent* condition = aConditions->GetFirstChild(); + condition; + condition = condition->GetNextSibling()) { + + // the <content> condition should always be the first child + if (condition->IsXULElement(nsGkAtoms::content)) { + if (condition != aConditions->GetFirstChild()) { + nsXULContentUtils::LogTemplateError(ERROR_TEMPLATE_CONTENT_NOT_FIRST); + continue; + } + + // check for <content tag='tag'/> which indicates that matches + // should only be generated for items inside content with that tag + nsAutoString tagstr; + condition->GetAttr(kNameSpaceID_None, nsGkAtoms::tag, tagstr); + + nsCOMPtr<nsIAtom> tag; + if (! tagstr.IsEmpty()) { + tag = NS_Atomize(tagstr); + } + + nsCOMPtr<nsIDOMDocument> doc = do_QueryInterface(condition->GetComposedDoc()); + if (! doc) + return NS_ERROR_FAILURE; + + idnode->SetTag(tag, doc); + continue; + } + + TestNode* testnode = nullptr; + nsresult rv = CompileQueryChild(condition->NodeInfo()->NameAtom(), + aQuery, condition, prevnode, &testnode); + if (NS_FAILED(rv)) + return rv; + + if (testnode) { + rv = prevnode->AddChild(testnode); + if (NS_FAILED(rv)) + return rv; + + prevnode = testnode; + } + } + + *aLastNode = prevnode; + + return NS_OK; +} + +nsresult +nsXULTemplateQueryProcessorRDF::CompileQueryChild(nsIAtom* aTag, + nsRDFQuery* aQuery, + nsIContent* aCondition, + TestNode* aParentNode, + TestNode** aResult) +{ + nsresult rv = NS_OK; + + if (aTag == nsGkAtoms::triple) { + rv = CompileTripleCondition(aQuery, aCondition, aParentNode, aResult); + } + else if (aTag == nsGkAtoms::member) { + rv = CompileMemberCondition(aQuery, aCondition, aParentNode, aResult); + } + else if (MOZ_LOG_TEST(gXULTemplateLog, LogLevel::Info)) { + nsAutoString tagstr; + aTag->ToString(tagstr); + + nsAutoCString tagstrC; + tagstrC.AssignWithConversion(tagstr); + MOZ_LOG(gXULTemplateLog, LogLevel::Info, + ("xultemplate[%p] unrecognized condition test <%s>", + this, tagstrC.get())); + } + + return rv; +} + +nsresult +nsXULTemplateQueryProcessorRDF::ParseLiteral(const nsString& aParseType, + const nsString& aValue, + nsIRDFNode** aResult) +{ + nsresult rv = NS_OK; + *aResult = nullptr; + + if (aParseType.EqualsLiteral(PARSE_TYPE_INTEGER)) { + nsCOMPtr<nsIRDFInt> intLiteral; + nsresult errorCode; + int32_t intValue = aValue.ToInteger(&errorCode); + if (NS_FAILED(errorCode)) + return NS_ERROR_FAILURE; + rv = gRDFService->GetIntLiteral(intValue, getter_AddRefs(intLiteral)); + if (NS_FAILED(rv)) + return rv; + intLiteral.forget(aResult); + } + else { + nsCOMPtr<nsIRDFLiteral> literal; + rv = gRDFService->GetLiteral(aValue.get(), getter_AddRefs(literal)); + if (NS_FAILED(rv)) + return rv; + literal.forget(aResult); + } + return rv; +} + +nsresult +nsXULTemplateQueryProcessorRDF::CompileTripleCondition(nsRDFQuery* aQuery, + nsIContent* aCondition, + TestNode* aParentNode, + TestNode** aResult) +{ + // Compile a <triple> condition, which must be of the form: + // + // <triple subject="?var1|resource" + // predicate="resource" + // object="?var2|resource|literal" /> + // + // XXXwaterson Some day it would be cool to allow the 'predicate' + // to be bound to a variable. + + // subject + nsAutoString subject; + aCondition->GetAttr(kNameSpaceID_None, nsGkAtoms::subject, subject); + + nsCOMPtr<nsIAtom> svar; + nsCOMPtr<nsIRDFResource> sres; + if (subject.IsEmpty()) { + nsXULContentUtils::LogTemplateError(ERROR_TEMPLATE_TRIPLE_BAD_SUBJECT); + return NS_OK; + } + if (subject[0] == char16_t('?')) + svar = NS_Atomize(subject); + else + gRDFService->GetUnicodeResource(subject, getter_AddRefs(sres)); + + // predicate + nsAutoString predicate; + aCondition->GetAttr(kNameSpaceID_None, nsGkAtoms::predicate, predicate); + + nsCOMPtr<nsIRDFResource> pres; + if (predicate.IsEmpty() || predicate[0] == char16_t('?')) { + nsXULContentUtils::LogTemplateError(ERROR_TEMPLATE_TRIPLE_BAD_PREDICATE); + return NS_OK; + } + gRDFService->GetUnicodeResource(predicate, getter_AddRefs(pres)); + + // object + nsAutoString object; + aCondition->GetAttr(kNameSpaceID_None, nsGkAtoms::object, object); + + nsCOMPtr<nsIAtom> ovar; + nsCOMPtr<nsIRDFNode> onode; + if (object.IsEmpty()) { + nsXULContentUtils::LogTemplateError(ERROR_TEMPLATE_TRIPLE_BAD_OBJECT); + return NS_OK; + } + + if (object[0] == char16_t('?')) { + ovar = NS_Atomize(object); + } + else if (object.FindChar(':') != -1) { // XXXwaterson evil. + // treat as resource + nsCOMPtr<nsIRDFResource> resource; + gRDFService->GetUnicodeResource(object, getter_AddRefs(resource)); + onode = do_QueryInterface(resource); + } + else { + nsAutoString parseType; + aCondition->GetAttr(kNameSpaceID_None, nsGkAtoms::parsetype, parseType); + nsresult rv = ParseLiteral(parseType, object, getter_AddRefs(onode)); + if (NS_FAILED(rv)) + return rv; + } + + nsRDFPropertyTestNode* testnode = nullptr; + + if (svar && ovar) { + testnode = new nsRDFPropertyTestNode(aParentNode, this, svar, pres, ovar); + } + else if (svar) { + testnode = new nsRDFPropertyTestNode(aParentNode, this, svar, pres, onode); + } + else if (ovar) { + testnode = new nsRDFPropertyTestNode(aParentNode, this, sres, pres, ovar); + } + else { + nsXULContentUtils::LogTemplateError(ERROR_TEMPLATE_TRIPLE_NO_VAR); + return NS_OK; + } + + // add testnode to mAllTests first. If adding to mRDFTests fails, just + // leave it in the list so that it can be deleted later. + MOZ_ASSERT(testnode); + nsresult rv = mAllTests.Add(testnode); + if (NS_FAILED(rv)) { + delete testnode; + return rv; + } + + rv = mRDFTests.Add(testnode); + if (NS_FAILED(rv)) + return rv; + + *aResult = testnode; + return NS_OK; +} + +nsresult +nsXULTemplateQueryProcessorRDF::CompileMemberCondition(nsRDFQuery* aQuery, + nsIContent* aCondition, + TestNode* aParentNode, + TestNode** aResult) +{ + // Compile a <member> condition, which must be of the form: + // + // <member container="?var1" child="?var2" /> + // + + // container + nsAutoString container; + aCondition->GetAttr(kNameSpaceID_None, nsGkAtoms::container, container); + + if (!container.IsEmpty() && container[0] != char16_t('?')) { + nsXULContentUtils::LogTemplateError(ERROR_TEMPLATE_MEMBER_NOCONTAINERVAR); + return NS_OK; + } + + nsCOMPtr<nsIAtom> containervar = NS_Atomize(container); + + // child + nsAutoString child; + aCondition->GetAttr(kNameSpaceID_None, nsGkAtoms::child, child); + + if (!child.IsEmpty() && child[0] != char16_t('?')) { + nsXULContentUtils::LogTemplateError(ERROR_TEMPLATE_MEMBER_NOCHILDVAR); + return NS_OK; + } + + nsCOMPtr<nsIAtom> childvar = NS_Atomize(child); + + TestNode* testnode = + new nsRDFConMemberTestNode(aParentNode, + this, + containervar, + childvar); + + // add testnode to mAllTests first. If adding to mRDFTests fails, just + // leave it in the list so that it can be deleted later. + nsresult rv = mAllTests.Add(testnode); + if (NS_FAILED(rv)) { + delete testnode; + return rv; + } + + rv = mRDFTests.Add(testnode); + if (NS_FAILED(rv)) + return rv; + + *aResult = testnode; + return NS_OK; +} + +nsresult +nsXULTemplateQueryProcessorRDF::AddDefaultSimpleRules(nsRDFQuery* aQuery, + TestNode** aChildNode) +{ + // XXXndeakin should check for tag in query processor instead of builder? + nsContentTestNode* idnode = + new nsContentTestNode(this, + aQuery->mRefVariable); + + // Create (?container ^member ?member) + nsRDFConMemberTestNode* membernode = + new nsRDFConMemberTestNode(idnode, + this, + aQuery->mRefVariable, + aQuery->mMemberVariable); + + // add nodes to mAllTests first. If later calls fail, just leave them in + // the list so that they can be deleted later. + nsresult rv = mAllTests.Add(idnode); + if (NS_FAILED(rv)) { + delete idnode; + delete membernode; + return rv; + } + + rv = mAllTests.Add(membernode); + if (NS_FAILED(rv)) { + delete membernode; + return rv; + } + + rv = mRDFTests.Add(membernode); + if (NS_FAILED(rv)) + return rv; + + rv = idnode->AddChild(membernode); + if (NS_FAILED(rv)) + return rv; + + mSimpleRuleMemberTest = membernode; + *aChildNode = membernode; + + return NS_OK; +} + +nsresult +nsXULTemplateQueryProcessorRDF::CompileSimpleQuery(nsRDFQuery* aQuery, + nsIContent* aQueryElement, + TestNode** aLastNode) +{ + // Compile a "simple" (or old-school style) <template> query. + nsresult rv; + + TestNode* parentNode; + + if (! mSimpleRuleMemberTest) { + rv = AddDefaultSimpleRules(aQuery, &parentNode); + if (NS_FAILED(rv)) + return rv; + } + + bool hasContainerTest = false; + + TestNode* prevnode = mSimpleRuleMemberTest; + + // Add constraints for the LHS + const nsAttrName* name; + for (uint32_t i = 0; (name = aQueryElement->GetAttrNameAt(i)); ++i) { + // Note: some attributes must be skipped on XUL template query subtree + + // never compare against rdf:property, rdf:instanceOf, {}:id or {}:parsetype attribute + if (name->Equals(nsGkAtoms::property, kNameSpaceID_RDF) || + name->Equals(nsGkAtoms::instanceOf, kNameSpaceID_RDF) || + name->Equals(nsGkAtoms::id, kNameSpaceID_None) || + name->Equals(nsGkAtoms::parsetype, kNameSpaceID_None)) { + continue; + } + + int32_t attrNameSpaceID = name->NamespaceID(); + if (attrNameSpaceID == kNameSpaceID_XMLNS) + continue; + nsIAtom* attr = name->LocalName(); + + nsAutoString value; + aQueryElement->GetAttr(attrNameSpaceID, attr, value); + + TestNode* testnode = nullptr; + + if (name->Equals(nsGkAtoms::iscontainer, kNameSpaceID_None) || + name->Equals(nsGkAtoms::isempty, kNameSpaceID_None)) { + // Tests about containerhood and emptiness. These can be + // globbed together, mostly. Check to see if we've already + // added a container test: we only need one. + if (hasContainerTest) + continue; + + nsRDFConInstanceTestNode::Test iscontainer = + nsRDFConInstanceTestNode::eDontCare; + + static nsIContent::AttrValuesArray strings[] = + {&nsGkAtoms::_true, &nsGkAtoms::_false, nullptr}; + switch (aQueryElement->FindAttrValueIn(kNameSpaceID_None, + nsGkAtoms::iscontainer, + strings, eCaseMatters)) { + case 0: iscontainer = nsRDFConInstanceTestNode::eTrue; break; + case 1: iscontainer = nsRDFConInstanceTestNode::eFalse; break; + } + + nsRDFConInstanceTestNode::Test isempty = + nsRDFConInstanceTestNode::eDontCare; + + switch (aQueryElement->FindAttrValueIn(kNameSpaceID_None, + nsGkAtoms::isempty, + strings, eCaseMatters)) { + case 0: isempty = nsRDFConInstanceTestNode::eTrue; break; + case 1: isempty = nsRDFConInstanceTestNode::eFalse; break; + } + + testnode = new nsRDFConInstanceTestNode(prevnode, + this, + aQuery->mMemberVariable, + iscontainer, + isempty); + + rv = mAllTests.Add(testnode); + if (NS_FAILED(rv)) { + delete testnode; + return rv; + } + + rv = mRDFTests.Add(testnode); + if (NS_FAILED(rv)) + return rv; + } + else if (attrNameSpaceID != kNameSpaceID_None || attr != nsGkAtoms::parent) { + // It's a simple RDF test + nsCOMPtr<nsIRDFResource> property; + rv = nsXULContentUtils::GetResource(attrNameSpaceID, attr, getter_AddRefs(property)); + if (NS_FAILED(rv)) + return rv; + + // XXXwaterson this is so manky + nsCOMPtr<nsIRDFNode> target; + if (value.FindChar(':') != -1) { // XXXwaterson WRONG WRONG WRONG! + nsCOMPtr<nsIRDFResource> resource; + rv = gRDFService->GetUnicodeResource(value, getter_AddRefs(resource)); + if (NS_FAILED(rv)) + return rv; + + target = do_QueryInterface(resource); + } + else { + nsAutoString parseType; + aQueryElement->GetAttr(kNameSpaceID_None, nsGkAtoms::parsetype, parseType); + rv = ParseLiteral(parseType, value, getter_AddRefs(target)); + if (NS_FAILED(rv)) + return rv; + } + + testnode = new nsRDFPropertyTestNode(prevnode, this, + aQuery->mMemberVariable, property, target); + rv = mAllTests.Add(testnode); + if (NS_FAILED(rv)) { + delete testnode; + return rv; + } + + rv = mRDFTests.Add(testnode); + if (NS_FAILED(rv)) + return rv; + } + + if (testnode) { + if (prevnode) { + rv = prevnode->AddChild(testnode); + if (NS_FAILED(rv)) + return rv; + } + else { + aQuery->SetRoot(testnode); + } + + prevnode = testnode; + } + } + + *aLastNode = prevnode; + + return NS_OK; +} + +RDFBindingSet* +nsXULTemplateQueryProcessorRDF::GetBindingsForRule(nsIDOMNode* aRuleNode) +{ + return mRuleToBindingsMap.GetWeak(aRuleNode); +} + +void +nsXULTemplateQueryProcessorRDF::AddBindingDependency(nsXULTemplateResultRDF* aResult, + nsIRDFResource* aResource) +{ + ResultArray* arr; + if (!mBindingDependencies.Get(aResource, &arr)) { + arr = new ResultArray(); + + mBindingDependencies.Put(aResource, arr); + } + + int32_t index = arr->IndexOf(aResult); + if (index == -1) + arr->AppendElement(aResult); +} + +void +nsXULTemplateQueryProcessorRDF::RemoveBindingDependency(nsXULTemplateResultRDF* aResult, + nsIRDFResource* aResource) +{ + ResultArray* arr; + if (mBindingDependencies.Get(aResource, &arr)) { + int32_t index = arr->IndexOf(aResult); + if (index >= 0) + arr->RemoveElementAt(index); + } +} + + +nsresult +nsXULTemplateQueryProcessorRDF::AddMemoryElements(const Instantiation& aInst, + nsXULTemplateResultRDF* aResult) +{ + // Add the result to a table indexed by supporting MemoryElement + MemoryElementSet::ConstIterator last = aInst.mSupport.Last(); + for (MemoryElementSet::ConstIterator element = aInst.mSupport.First(); + element != last; ++element) { + + PLHashNumber hash = (element.operator->())->Hash(); + + nsCOMArray<nsXULTemplateResultRDF>* arr; + if (!mMemoryElementToResultMap.Get(hash, &arr)) { + arr = new nsCOMArray<nsXULTemplateResultRDF>(); + mMemoryElementToResultMap.Put(hash, arr); + } + + // results may be added more than once so they will all get deleted properly + arr->AppendObject(aResult); + } + + return NS_OK; +} + +nsresult +nsXULTemplateQueryProcessorRDF::RemoveMemoryElements(const Instantiation& aInst, + nsXULTemplateResultRDF* aResult) +{ + // Remove the results mapped by the supporting MemoryElement + MemoryElementSet::ConstIterator last = aInst.mSupport.Last(); + for (MemoryElementSet::ConstIterator element = aInst.mSupport.First(); + element != last; ++element) { + + PLHashNumber hash = (element.operator->())->Hash(); + + nsCOMArray<nsXULTemplateResultRDF>* arr; + if (mMemoryElementToResultMap.Get(hash, &arr)) { + int32_t index = arr->IndexOf(aResult); + if (index >= 0) + arr->RemoveObjectAt(index); + + uint32_t length = arr->Count(); + if (! length) + mMemoryElementToResultMap.Remove(hash); + } + } + + return NS_OK; +} + +void +nsXULTemplateQueryProcessorRDF::RetractElement(const MemoryElement& aMemoryElement) +{ + if (! mBuilder) + return; + + // when an assertion is removed, look through the memory elements and + // find results that are associated with them. Those results will need + // to be removed because they no longer match. + PLHashNumber hash = aMemoryElement.Hash(); + + nsCOMArray<nsXULTemplateResultRDF>* arr; + if (mMemoryElementToResultMap.Get(hash, &arr)) { + uint32_t length = arr->Count(); + + for (int32_t r = length - 1; r >= 0; r--) { + nsXULTemplateResultRDF* result = (*arr)[r]; + if (result) { + // because the memory elements are hashed by an integer, + // sometimes two different memory elements will have the same + // hash code. In this case we check the result to make sure + // and only remove those that refer to that memory element. + if (result->HasMemoryElement(aMemoryElement)) { + nsITemplateRDFQuery* query = result->Query(); + if (query) { + nsCOMPtr<nsIDOMNode> querynode; + query->GetQueryNode(getter_AddRefs(querynode)); + + mBuilder->RemoveResult(result); + } + + // a call to RemoveMemoryElements may have removed it + if (!mMemoryElementToResultMap.Get(hash, nullptr)) + return; + + // the array should have been reduced by one, but check + // just to make sure + uint32_t newlength = arr->Count(); + if (r > (int32_t)newlength) + r = newlength; + } + } + } + + // if there are no items left, remove the memory element from the hashtable + if (!arr->Count()) + mMemoryElementToResultMap.Remove(hash); + } +} + +int32_t +nsXULTemplateQueryProcessorRDF::GetContainerIndexOf(nsIXULTemplateResult* aResult) +{ + // get the reference variable and look up the container in the result + nsCOMPtr<nsISupports> ref; + nsresult rv = aResult->GetBindingObjectFor(mRefVariable, + getter_AddRefs(ref)); + if (NS_FAILED(rv) || !mDB) + return -1; + + nsCOMPtr<nsIRDFResource> container = do_QueryInterface(ref); + if (container) { + // if the container is an RDF Seq, return the index of the result + // in the container. + bool isSequence = false; + gRDFContainerUtils->IsSeq(mDB, container, &isSequence); + if (isSequence) { + nsCOMPtr<nsIRDFResource> resource; + aResult->GetResource(getter_AddRefs(resource)); + if (resource) { + int32_t index; + gRDFContainerUtils->IndexOf(mDB, container, resource, &index); + return index; + } + } + } + + // if the container isn't a Seq, or the result isn't in the container, + // return -1 indicating no index. + return -1; +} + +nsresult +nsXULTemplateQueryProcessorRDF::GetSortValue(nsIXULTemplateResult* aResult, + nsIRDFResource* aPredicate, + nsIRDFResource* aSortPredicate, + nsISupports** aResultNode) +{ + nsCOMPtr<nsIRDFResource> source; + nsresult rv = aResult->GetResource(getter_AddRefs(source)); + if (NS_FAILED(rv)) + return rv; + + nsCOMPtr<nsIRDFNode> value; + if (source && mDB) { + // first check predicate?sort=true so that datasources may use a + // custom value for sorting + rv = mDB->GetTarget(source, aSortPredicate, true, + getter_AddRefs(value)); + if (NS_FAILED(rv)) + return rv; + + if (!value) { + rv = mDB->GetTarget(source, aPredicate, true, + getter_AddRefs(value)); + if (NS_FAILED(rv)) + return rv; + } + } + + *aResultNode = value; + NS_IF_ADDREF(*aResultNode); + return NS_OK; +} diff --git a/dom/xul/templates/nsXULTemplateQueryProcessorRDF.h b/dom/xul/templates/nsXULTemplateQueryProcessorRDF.h new file mode 100644 index 000000000..30ac34d23 --- /dev/null +++ b/dom/xul/templates/nsXULTemplateQueryProcessorRDF.h @@ -0,0 +1,349 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* 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/. */ + + +#ifndef nsXULTemplateQueryProcessorRDF_h__ +#define nsXULTemplateQueryProcessorRDF_h__ + +#include "nsIRDFContainer.h" +#include "nsIRDFContainerUtils.h" +#include "nsIRDFDataSource.h" +#include "nsIRDFObserver.h" +#include "nsIRDFService.h" +#include "nsIXULTemplateBuilder.h" +#include "nsIXULTemplateQueryProcessor.h" +#include "nsCollationCID.h" + +#include "nsResourceSet.h" +#include "nsRuleNetwork.h" +#include "nsRDFQuery.h" +#include "nsRDFBinding.h" +#include "nsXULTemplateResultSetRDF.h" +#include "nsCOMArray.h" +#include "nsString.h" +#include "nsClassHashtable.h" +#include "nsRefPtrHashtable.h" +#include "nsCycleCollectionParticipant.h" +#include "mozilla/Attributes.h" + +#include "mozilla/Logging.h" +extern mozilla::LazyLogModule gXULTemplateLog; + +class nsIContent; +class nsXULTemplateResultRDF; + +/** + * An object that generates results from a query on an RDF graph + */ +class nsXULTemplateQueryProcessorRDF final : public nsIXULTemplateQueryProcessor, + public nsIRDFObserver +{ +public: + typedef nsTArray<RefPtr<nsXULTemplateResultRDF> > ResultArray; + + nsXULTemplateQueryProcessorRDF(); + + nsresult InitGlobals(); + + // nsISupports interface + NS_DECL_CYCLE_COLLECTING_ISUPPORTS + NS_DECL_CYCLE_COLLECTION_CLASS_AMBIGUOUS(nsXULTemplateQueryProcessorRDF, + nsIXULTemplateQueryProcessor) + + // nsIXULTemplateQueryProcessor interface + NS_DECL_NSIXULTEMPLATEQUERYPROCESSOR + + // nsIRDFObserver interface + NS_DECL_NSIRDFOBSERVER + + /* + * Propagate all changes through the rule network when an assertion is + * added to the graph, adding any new results. + */ + nsresult + Propagate(nsIRDFResource* aSource, + nsIRDFResource* aProperty, + nsIRDFNode* aTarget); + + /* + * Retract all changes through the rule network when an assertion is + * removed from the graph, removing any results that no longer match. + */ + nsresult + Retract(nsIRDFResource* aSource, + nsIRDFResource* aProperty, + nsIRDFNode* aTarget); + + /* + * Synchronize results when the graph changes, updating their bindings. + */ + nsresult + SynchronizeAll(nsIRDFResource* aSource, + nsIRDFResource* aProperty, + nsIRDFNode* aOldTarget, + nsIRDFNode* aNewTarget); + + /* + * Return true if a resource is a container + */ + nsresult + CheckContainer(nsIRDFResource* aTargetResource, + bool* aIsContainer); + + /* + * Check if a resource does not have any children + */ + nsresult + CheckEmpty(nsIRDFResource* aTargetResource, + bool* aIsEmpty); + + /** + * Check if a resource is a separator + */ + nsresult + CheckIsSeparator(nsIRDFResource* aResource, bool* aIsSeparator); + + /* + * Compute the containment properties which are additional arcs which + * indicate that a node is a container, in additional to the RDF container + * tests. The computed list is stored in mContainmentProperties + */ + nsresult + ComputeContainmentProperties(nsIDOMNode* aRootNode); + + /** + * Compile a query that uses the extended template syntax. The last + * compiled node of the query is returned as aLastNode. This node will + * have been added to mAllTests which owns the node. + */ + nsresult + CompileExtendedQuery(nsRDFQuery* aQuery, + nsIContent* aConditions, + TestNode** aLastNode); + + /** + * Compile a single query child and return the compiled node in aResult. + * This node will have been added to mAllTests which owns the node and + * set as a child of aParentNode. + */ + virtual nsresult + CompileQueryChild(nsIAtom* aTag, + nsRDFQuery* aQuery, + nsIContent* aConditions, + TestNode* aParentNode, + TestNode** aResult); + + /** + * Parse the value of a property test assertion for a condition or a simple + * rule based on the parseType attribute into the appropriate literal type. + */ + nsresult ParseLiteral(const nsString& aParseType, + const nsString& aValue, + nsIRDFNode** aResult); + + /** + * Compile a <triple> condition and return the compiled node in aResult. + * This node will have been added to mAllTests which owns the node and + * set as a child of aParentNode. + */ + nsresult + CompileTripleCondition(nsRDFQuery* aQuery, + nsIContent* aCondition, + TestNode* aParentNode, + TestNode** aResult); + + /** + * Compile a <member> condition and return the compiled node in aResult. + * This node will have been added to mAllTests which owns the node and + * set as a child of aParentNode. + */ + nsresult + CompileMemberCondition(nsRDFQuery* aQuery, + nsIContent* aCondition, + TestNode* aParentNode, + TestNode** aResult); + + /** + * Add the default rules shared by all simple queries. This creates + * the content start node followed by a member test. The member TestNode + * is returned in aChildNode. Both nodes will have been added to mAllTests + * which owns the nodes. + */ + nsresult + AddDefaultSimpleRules(nsRDFQuery* aQuery, + TestNode** aChildNode); + + /** + * Compile a query that's specified using the simple template + * syntax. Each TestNode is created in a chain, the last compiled node + * is returned as aLastNode. All nodes will have been added to mAllTests + * which owns the nodes. + */ + nsresult + CompileSimpleQuery(nsRDFQuery* aQuery, + nsIContent* aQueryElement, + TestNode** aLastNode); + + RDFBindingSet* + GetBindingsForRule(nsIDOMNode* aRule); + + /* + * Indicate that a result is dependant on a particular resource. When an + * assertion is added to or removed from the graph involving that + * resource, that result must be recalculated. + */ + void + AddBindingDependency(nsXULTemplateResultRDF* aResult, + nsIRDFResource* aResource); + + /** + * Remove a dependency a result has on a particular resource. + */ + void + RemoveBindingDependency(nsXULTemplateResultRDF* aResult, + nsIRDFResource* aResource); + + /** + * A memory element is a hash of an RDF triple. One exists for each triple + * that was involved in generating a result. This function adds this to a + * map, keyed by memory element, when the value is a list of results that + * depend on that memory element. When an RDF triple is removed from the + * datasource, RetractElement is called, and this map is examined to + * determine which results are no longer valid. + */ + nsresult + AddMemoryElements(const Instantiation& aInst, + nsXULTemplateResultRDF* aResult); + + /** + * Remove the memory elements associated with a result when the result is + * no longer being used. + */ + nsresult + RemoveMemoryElements(const Instantiation& aInst, + nsXULTemplateResultRDF* aResult); + + /** + * Remove the results associated with a memory element since the + * RDF triple the memory element is a hash of has been removed. + */ + void RetractElement(const MemoryElement& aMemoryElement); + + /** + * Return the index of a result's resource in its RDF container + */ + int32_t + GetContainerIndexOf(nsIXULTemplateResult* aResult); + + /** + * Given a result and a predicate to sort on, get the target value of + * the triple to use for sorting. The sort predicate is the predicate + * with '?sort=true' appended. + */ + nsresult + GetSortValue(nsIXULTemplateResult* aResult, + nsIRDFResource* aPredicate, + nsIRDFResource* aSortPredicate, + nsISupports** aResultNode); + + nsIRDFDataSource* GetDataSource() { return mDB; } + + nsIXULTemplateBuilder* GetBuilder() { return mBuilder; } + + nsResourceSet& ContainmentProperties() { return mContainmentProperties; } + + nsresult + Log(const char* aOperation, + nsIRDFResource* aSource, + nsIRDFResource* aProperty, + nsIRDFNode* aTarget); + +#define LOG(_op, _src, _prop, _targ) \ + Log(_op, _src, _prop, _targ) + +protected: + ~nsXULTemplateQueryProcessorRDF(); + + // We are an observer of the composite datasource. The cycle is + // broken when the document is destroyed. + nsCOMPtr<nsIRDFDataSource> mDB; + + // weak reference to the builder, cleared when the document is destroyed + nsIXULTemplateBuilder* mBuilder; + + // true if the query processor has been initialized + bool mQueryProcessorRDFInited; + + // true if results have been generated. Once set, bindings can no longer + // be added. If they were, the binding value arrays for results that have + // already been generated would be the wrong size + bool mGenerationStarted; + + // nesting level for RDF batch notifications + int32_t mUpdateBatchNest; + + // containment properties that are checked to determine if a resource is + // a container + nsResourceSet mContainmentProperties; + + // the end node of the default simple node hierarchy + TestNode* mSimpleRuleMemberTest; + + // the reference variable + nsCOMPtr<nsIAtom> mRefVariable; + + // the last ref that was calculated, used for simple rules + nsCOMPtr<nsIXULTemplateResult> mLastRef; + + /** + * A map between nsIRDFNodes that form the left-hand side (the subject) of + * a <binding> and an array of nsIXULTemplateResults. When a new assertion + * is added to the graph involving a particular rdf node, it is looked up + * in this binding map. If it exists, the corresponding results must then + * be synchronized. + */ + nsClassHashtable<nsISupportsHashKey, ResultArray> mBindingDependencies; + + /** + * A map between memory elements and an array of nsIXULTemplateResults. + * When a triple is unasserted from the graph, the corresponding results + * no longer match so they must be removed. + */ + nsClassHashtable<nsUint32HashKey, + nsCOMArray<nsXULTemplateResultRDF> > mMemoryElementToResultMap; + + // map of the rules to the bindings for those rules. + // XXXndeakin this might be better just as an array since there is usually + // ten or fewer rules + nsRefPtrHashtable<nsISupportsHashKey, RDFBindingSet> mRuleToBindingsMap; + + /** + * The queries + */ + nsTArray<nsCOMPtr<nsITemplateRDFQuery> > mQueries; + + /** + * All of the RDF tests in the rule network, which are checked when a new + * assertion is added to the graph. This is a subset of mAllTests, which + * also includes non-RDF tests. + */ + ReteNodeSet mRDFTests; + + /** + * All of the tests in the rule network, owned by this list + */ + ReteNodeSet mAllTests; + + // pseudo-constants + static nsrefcnt gRefCnt; + +public: + static nsIRDFService* gRDFService; + static nsIRDFContainerUtils* gRDFContainerUtils; + static nsIRDFResource* kNC_BookmarkSeparator; + static nsIRDFResource* kRDF_type; +}; + +#endif // nsXULTemplateQueryProcessorRDF_h__ diff --git a/dom/xul/templates/nsXULTemplateQueryProcessorStorage.cpp b/dom/xul/templates/nsXULTemplateQueryProcessorStorage.cpp new file mode 100644 index 000000000..a70307bf5 --- /dev/null +++ b/dom/xul/templates/nsXULTemplateQueryProcessorStorage.cpp @@ -0,0 +1,502 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* 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 "prprf.h" + +#include "nsIDOMNodeList.h" +#include "nsUnicharUtils.h" + +#include "nsArrayUtils.h" +#include "nsVariant.h" +#include "nsAppDirectoryServiceDefs.h" + +#include "nsIURI.h" +#include "nsIFileChannel.h" +#include "nsIFile.h" +#include "nsGkAtoms.h" +#include "nsContentUtils.h" + +#include "nsXULTemplateBuilder.h" +#include "nsXULTemplateResultStorage.h" +#include "nsXULContentUtils.h" +#include "nsXULSortService.h" + +#include "mozIStorageService.h" +#include "nsIChannel.h" +#include "nsIDocument.h" +#include "nsNetUtil.h" + +//---------------------------------------------------------------------- +// +// nsXULTemplateResultSetStorage +// + +NS_IMPL_ISUPPORTS(nsXULTemplateResultSetStorage, nsISimpleEnumerator) + + +nsXULTemplateResultSetStorage::nsXULTemplateResultSetStorage(mozIStorageStatement* aStatement) + : mStatement(aStatement) +{ + uint32_t count; + nsresult rv = aStatement->GetColumnCount(&count); + if (NS_FAILED(rv)) { + mStatement = nullptr; + return; + } + for (uint32_t c = 0; c < count; c++) { + nsAutoCString name; + rv = aStatement->GetColumnName(c, name); + if (NS_SUCCEEDED(rv)) { + nsCOMPtr<nsIAtom> columnName = NS_Atomize(NS_LITERAL_CSTRING("?") + name); + mColumnNames.AppendObject(columnName); + } + } +} + +NS_IMETHODIMP +nsXULTemplateResultSetStorage::HasMoreElements(bool *aResult) +{ + if (!mStatement) { + *aResult = false; + return NS_OK; + } + + nsresult rv = mStatement->ExecuteStep(aResult); + NS_ENSURE_SUCCESS(rv, rv); + // Because the nsXULTemplateResultSetStorage is owned by many nsXULTemplateResultStorage objects, + // it could live longer than it needed to get results. + // So we destroy the statement to free resources when all results are fetched + if (!*aResult) { + mStatement = nullptr; + } + return NS_OK; +} + +NS_IMETHODIMP +nsXULTemplateResultSetStorage::GetNext(nsISupports **aResult) +{ + nsXULTemplateResultStorage* result = + new nsXULTemplateResultStorage(this); + *aResult = result; + NS_ADDREF(result); + return NS_OK; +} + + +int32_t +nsXULTemplateResultSetStorage::GetColumnIndex(nsIAtom* aColumnName) +{ + int32_t count = mColumnNames.Count(); + for (int32_t c = 0; c < count; c++) { + if (mColumnNames[c] == aColumnName) + return c; + } + + return -1; +} + +void +nsXULTemplateResultSetStorage::FillColumnValues(nsCOMArray<nsIVariant>& aArray) +{ + if (!mStatement) + return; + + int32_t count = mColumnNames.Count(); + + for (int32_t c = 0; c < count; c++) { + RefPtr<nsVariant> value = new nsVariant(); + + int32_t type; + mStatement->GetTypeOfIndex(c, &type); + + if (type == mStatement->VALUE_TYPE_INTEGER) { + int64_t val = mStatement->AsInt64(c); + value->SetAsInt64(val); + } + else if (type == mStatement->VALUE_TYPE_FLOAT) { + double val = mStatement->AsDouble(c); + value->SetAsDouble(val); + } + else { + nsAutoString val; + nsresult rv = mStatement->GetString(c, val); + if (NS_FAILED(rv)) + value->SetAsAString(EmptyString()); + else + value->SetAsAString(val); + } + aArray.AppendObject(value); + } +} + + + +//---------------------------------------------------------------------- +// +// nsXULTemplateQueryProcessorStorage +// + +NS_IMPL_ISUPPORTS(nsXULTemplateQueryProcessorStorage, + nsIXULTemplateQueryProcessor) + + +nsXULTemplateQueryProcessorStorage::nsXULTemplateQueryProcessorStorage() + : mGenerationStarted(false) +{ +} + +NS_IMETHODIMP +nsXULTemplateQueryProcessorStorage::GetDatasource(nsIArray* aDataSources, + nsIDOMNode* aRootNode, + bool aIsTrusted, + nsIXULTemplateBuilder* aBuilder, + bool* aShouldDelayBuilding, + nsISupports** aReturn) +{ + *aReturn = nullptr; + *aShouldDelayBuilding = false; + + if (!aIsTrusted) { + return NS_OK; + } + + uint32_t length; + nsresult rv = aDataSources->GetLength(&length); + NS_ENSURE_SUCCESS(rv, rv); + + if (length == 0) { + return NS_OK; + } + + // We get only the first uri. This query processor supports + // only one database at a time. + nsCOMPtr<nsIURI> uri; + uri = do_QueryElementAt(aDataSources, 0); + + if (!uri) { + // No uri in the list of datasources + return NS_OK; + } + + nsCOMPtr<mozIStorageService> storage = + do_GetService("@mozilla.org/storage/service;1", &rv); + NS_ENSURE_SUCCESS(rv, rv); + + nsCOMPtr<nsIFile> databaseFile; + nsAutoCString scheme; + rv = uri->GetScheme(scheme); + NS_ENSURE_SUCCESS(rv, rv); + + if (scheme.EqualsLiteral("profile")) { + + nsAutoCString path; + rv = uri->GetPath(path); + NS_ENSURE_SUCCESS(rv, rv); + + if (path.IsEmpty()) { + return NS_ERROR_FAILURE; + } + + rv = NS_GetSpecialDirectory(NS_APP_USER_PROFILE_50_DIR, + getter_AddRefs(databaseFile)); + NS_ENSURE_SUCCESS(rv, rv); + + rv = databaseFile->AppendNative(path); + NS_ENSURE_SUCCESS(rv, rv); + } + else { + nsCOMPtr<nsIChannel> channel; + nsCOMPtr<nsINode> node = do_QueryInterface(aRootNode); + + // The following channel is never openend, so it does not matter what + // securityFlags we pass; let's follow the principle of least privilege. + rv = NS_NewChannel(getter_AddRefs(channel), + uri, + node, + nsILoadInfo::SEC_REQUIRE_SAME_ORIGIN_DATA_IS_BLOCKED, + nsIContentPolicy::TYPE_OTHER); + NS_ENSURE_SUCCESS(rv, rv); + + nsCOMPtr<nsIFileChannel> fileChannel = do_QueryInterface(channel, &rv); + if (NS_FAILED(rv)) { // if it fails, not a file url + nsXULContentUtils::LogTemplateError(ERROR_TEMPLATE_STORAGE_BAD_URI); + return rv; + } + + rv = fileChannel->GetFile(getter_AddRefs(databaseFile)); + NS_ENSURE_SUCCESS(rv, rv); + } + + // ok now we have an URI of a sqlite file + nsCOMPtr<mozIStorageConnection> connection; + rv = storage->OpenDatabase(databaseFile, getter_AddRefs(connection)); + if (NS_FAILED(rv)) { + nsXULContentUtils::LogTemplateError(ERROR_TEMPLATE_STORAGE_CANNOT_OPEN_DATABASE); + return rv; + } + + connection.forget(aReturn); + return NS_OK; +} + + + +NS_IMETHODIMP +nsXULTemplateQueryProcessorStorage::InitializeForBuilding(nsISupports* aDatasource, + nsIXULTemplateBuilder* aBuilder, + nsIDOMNode* aRootNode) +{ + NS_ENSURE_STATE(!mGenerationStarted); + + mStorageConnection = do_QueryInterface(aDatasource); + if (!mStorageConnection) + return NS_ERROR_INVALID_ARG; + + bool ready; + mStorageConnection->GetConnectionReady(&ready); + if (!ready) + return NS_ERROR_UNEXPECTED; + + return NS_OK; +} + +NS_IMETHODIMP +nsXULTemplateQueryProcessorStorage::Done() +{ + mGenerationStarted = false; + return NS_OK; +} + +NS_IMETHODIMP +nsXULTemplateQueryProcessorStorage::CompileQuery(nsIXULTemplateBuilder* aBuilder, + nsIDOMNode* aQueryNode, + nsIAtom* aRefVariable, + nsIAtom* aMemberVariable, + nsISupports** aReturn) +{ + nsCOMPtr<nsIDOMNodeList> childNodes; + aQueryNode->GetChildNodes(getter_AddRefs(childNodes)); + + uint32_t length; + childNodes->GetLength(&length); + + nsCOMPtr<mozIStorageStatement> statement; + nsCOMPtr<nsIContent> queryContent = do_QueryInterface(aQueryNode); + nsAutoString sqlQuery; + + // Let's get all text nodes (which should be the query) + if (!nsContentUtils::GetNodeTextContent(queryContent, false, sqlQuery, fallible)) { + return NS_ERROR_OUT_OF_MEMORY; + } + + nsresult rv = mStorageConnection->CreateStatement(NS_ConvertUTF16toUTF8(sqlQuery), + getter_AddRefs(statement)); + if (NS_FAILED(rv)) { + nsXULContentUtils::LogTemplateError(ERROR_TEMPLATE_STORAGE_BAD_QUERY); + return rv; + } + + uint32_t parameterCount = 0; + for (nsIContent* child = queryContent->GetFirstChild(); + child; + child = child->GetNextSibling()) { + + if (child->NodeInfo()->Equals(nsGkAtoms::param, kNameSpaceID_XUL)) { + nsAutoString value; + if (!nsContentUtils::GetNodeTextContent(child, false, value, fallible)) { + return NS_ERROR_OUT_OF_MEMORY; + } + + uint32_t index = parameterCount; + nsAutoString name, indexValue; + + if (child->GetAttr(kNameSpaceID_None, nsGkAtoms::name, name)) { + rv = statement->GetParameterIndex(NS_ConvertUTF16toUTF8(name), + &index); + if (NS_FAILED(rv)) { + nsXULContentUtils::LogTemplateError(ERROR_TEMPLATE_STORAGE_UNKNOWN_QUERY_PARAMETER); + return rv; + } + parameterCount++; + } + else if (child->GetAttr(kNameSpaceID_None, nsGkAtoms::index, indexValue)) { + PR_sscanf(NS_ConvertUTF16toUTF8(indexValue).get(),"%d",&index); + if (index > 0) + index--; + } + else { + parameterCount++; + } + + static nsIContent::AttrValuesArray sTypeValues[] = + { &nsGkAtoms::int32, &nsGkAtoms::integer, &nsGkAtoms::int64, + &nsGkAtoms::null, &nsGkAtoms::double_, &nsGkAtoms::string, nullptr }; + + int32_t typeError = 1; + int32_t typeValue = child->FindAttrValueIn(kNameSpaceID_None, nsGkAtoms::type, + sTypeValues, eCaseMatters); + rv = NS_ERROR_ILLEGAL_VALUE; + int32_t valInt32 = 0; + int64_t valInt64 = 0; + double valFloat = 0; + + switch (typeValue) { + case 0: + case 1: + typeError = PR_sscanf(NS_ConvertUTF16toUTF8(value).get(),"%d",&valInt32); + if (typeError > 0) + rv = statement->BindInt32ByIndex(index, valInt32); + break; + case 2: + typeError = PR_sscanf(NS_ConvertUTF16toUTF8(value).get(),"%lld",&valInt64); + if (typeError > 0) + rv = statement->BindInt64ByIndex(index, valInt64); + break; + case 3: + rv = statement->BindNullByIndex(index); + break; + case 4: + typeError = PR_sscanf(NS_ConvertUTF16toUTF8(value).get(),"%lf",&valFloat); + if (typeError > 0) + rv = statement->BindDoubleByIndex(index, valFloat); + break; + case 5: + case nsIContent::ATTR_MISSING: + rv = statement->BindStringByIndex(index, value); + break; + default: + typeError = 0; + } + + if (typeError <= 0) { + nsXULContentUtils::LogTemplateError(ERROR_TEMPLATE_STORAGE_WRONG_TYPE_QUERY_PARAMETER); + return rv; + } + + if (NS_FAILED(rv)) { + nsXULContentUtils::LogTemplateError(ERROR_TEMPLATE_STORAGE_QUERY_PARAMETER_NOT_BOUND); + return rv; + } + } + } + + *aReturn = statement; + NS_IF_ADDREF(*aReturn); + + return NS_OK; +} + +NS_IMETHODIMP +nsXULTemplateQueryProcessorStorage::GenerateResults(nsISupports* aDatasource, + nsIXULTemplateResult* aRef, + nsISupports* aQuery, + nsISimpleEnumerator** aResults) +{ + mGenerationStarted = true; + + nsCOMPtr<mozIStorageStatement> statement = do_QueryInterface(aQuery); + if (!statement) + return NS_ERROR_FAILURE; + + nsXULTemplateResultSetStorage* results = + new nsXULTemplateResultSetStorage(statement); + *aResults = results; + NS_ADDREF(*aResults); + + return NS_OK; +} + +NS_IMETHODIMP +nsXULTemplateQueryProcessorStorage::AddBinding(nsIDOMNode* aRuleNode, + nsIAtom* aVar, + nsIAtom* aRef, + const nsAString& aExpr) +{ + return NS_OK; +} + +NS_IMETHODIMP +nsXULTemplateQueryProcessorStorage::TranslateRef(nsISupports* aDatasource, + const nsAString& aRefString, + nsIXULTemplateResult** aRef) +{ + nsXULTemplateResultStorage* result = + new nsXULTemplateResultStorage(nullptr); + *aRef = result; + NS_ADDREF(*aRef); + return NS_OK; +} + + +NS_IMETHODIMP +nsXULTemplateQueryProcessorStorage::CompareResults(nsIXULTemplateResult* aLeft, + nsIXULTemplateResult* aRight, + nsIAtom* aVar, + uint32_t aSortHints, + int32_t* aResult) +{ + *aResult = 0; + if (!aVar) + return NS_OK; + + // We're going to see if values are integers or float, to perform + // a suitable comparison + nsCOMPtr<nsISupports> leftValue, rightValue; + if (aLeft) + aLeft->GetBindingObjectFor(aVar, getter_AddRefs(leftValue)); + if (aRight) + aRight->GetBindingObjectFor(aVar, getter_AddRefs(rightValue)); + + if (leftValue && rightValue) { + nsCOMPtr<nsIVariant> vLeftValue = do_QueryInterface(leftValue); + nsCOMPtr<nsIVariant> vRightValue = do_QueryInterface(rightValue); + + if (vLeftValue && vRightValue) { + nsresult rv1, rv2; + uint16_t vtypeL, vtypeR; + vLeftValue->GetDataType(&vtypeL); + vRightValue->GetDataType(&vtypeR); + + if (vtypeL == vtypeR) { + if (vtypeL == nsIDataType::VTYPE_INT64) { + int64_t leftValue, rightValue; + rv1 = vLeftValue->GetAsInt64(&leftValue); + rv2 = vRightValue->GetAsInt64(&rightValue); + if (NS_SUCCEEDED(rv1) && NS_SUCCEEDED(rv2)) { + if (leftValue > rightValue) + *aResult = 1; + else if (leftValue < rightValue) + *aResult = -1; + return NS_OK; + } + } + else if (vtypeL == nsIDataType::VTYPE_DOUBLE) { + double leftValue, rightValue; + rv1 = vLeftValue->GetAsDouble(&leftValue); + rv2 = vRightValue->GetAsDouble(&rightValue); + if (NS_SUCCEEDED(rv1) && NS_SUCCEEDED(rv2)) { + if (leftValue > rightValue) + *aResult = 1; + else if (leftValue < rightValue) + *aResult = -1; + return NS_OK; + } + } + } + } + } + + // Values are not integers or floats, so we just compare them as simple strings + nsAutoString leftVal; + if (aLeft) + aLeft->GetBindingFor(aVar, leftVal); + + nsAutoString rightVal; + if (aRight) + aRight->GetBindingFor(aVar, rightVal); + + *aResult = XULSortServiceImpl::CompareValues(leftVal, rightVal, aSortHints); + return NS_OK; +} diff --git a/dom/xul/templates/nsXULTemplateQueryProcessorStorage.h b/dom/xul/templates/nsXULTemplateQueryProcessorStorage.h new file mode 100644 index 000000000..8c52f139b --- /dev/null +++ b/dom/xul/templates/nsXULTemplateQueryProcessorStorage.h @@ -0,0 +1,69 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* 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/. */ + +#ifndef nsXULTemplateQueryProcessorStorage_h__ +#define nsXULTemplateQueryProcessorStorage_h__ + +#include "nsIXULTemplateBuilder.h" +#include "nsIXULTemplateQueryProcessor.h" + +#include "nsISimpleEnumerator.h" +#include "nsCOMArray.h" +#include "nsIVariant.h" + +#include "mozIStorageValueArray.h" +#include "mozIStorageStatement.h" +#include "mozIStorageConnection.h" +#include "mozilla/Attributes.h" + +class nsXULTemplateQueryProcessorStorage; + +class nsXULTemplateResultSetStorage final : public nsISimpleEnumerator +{ +private: + + nsCOMPtr<mozIStorageStatement> mStatement; + + nsCOMArray<nsIAtom> mColumnNames; + + ~nsXULTemplateResultSetStorage() {} + +public: + + // nsISupports interface + NS_DECL_ISUPPORTS + + // nsISimpleEnumerator interface + NS_DECL_NSISIMPLEENUMERATOR + + explicit nsXULTemplateResultSetStorage(mozIStorageStatement* aStatement); + + int32_t GetColumnIndex(nsIAtom* aColumnName); + + void FillColumnValues(nsCOMArray<nsIVariant>& aArray); + +}; + +class nsXULTemplateQueryProcessorStorage final : public nsIXULTemplateQueryProcessor +{ +public: + + nsXULTemplateQueryProcessorStorage(); + + // nsISupports interface + NS_DECL_ISUPPORTS + + // nsIXULTemplateQueryProcessor interface + NS_DECL_NSIXULTEMPLATEQUERYPROCESSOR + +private: + + ~nsXULTemplateQueryProcessorStorage() {} + + nsCOMPtr<mozIStorageConnection> mStorageConnection; + bool mGenerationStarted; +}; + +#endif // nsXULTemplateQueryProcessorStorage_h__ diff --git a/dom/xul/templates/nsXULTemplateQueryProcessorXML.cpp b/dom/xul/templates/nsXULTemplateQueryProcessorXML.cpp new file mode 100644 index 000000000..1c6fed252 --- /dev/null +++ b/dom/xul/templates/nsXULTemplateQueryProcessorXML.cpp @@ -0,0 +1,449 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* 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 "nsCOMPtr.h" +#include "nsAutoPtr.h" +#include "nsIDOMDocument.h" +#include "nsIDOMNode.h" +#include "nsIDOMElement.h" +#include "nsIDOMEvent.h" +#include "nsIDocument.h" +#include "nsIContent.h" +#include "nsComponentManagerUtils.h" +#include "nsGkAtoms.h" +#include "nsIURI.h" +#include "nsIArray.h" +#include "nsIScriptContext.h" +#include "nsArrayUtils.h" +#include "nsPIDOMWindow.h" +#include "nsXULContentUtils.h" +#include "mozilla/dom/XPathEvaluator.h" +#include "nsXULTemplateQueryProcessorXML.h" +#include "nsXULTemplateResultXML.h" +#include "nsXULSortService.h" +#include "mozilla/dom/Element.h" +#include "mozilla/dom/XMLHttpRequest.h" + +using namespace mozilla; +using namespace mozilla::dom; + +NS_IMPL_ISUPPORTS(nsXMLQuery, nsXMLQuery) + +//---------------------------------------------------------------------- +// +// nsXULTemplateResultSetXML +// + +NS_IMPL_ISUPPORTS(nsXULTemplateResultSetXML, nsISimpleEnumerator) + +NS_IMETHODIMP +nsXULTemplateResultSetXML::HasMoreElements(bool *aResult) +{ + // if GetSnapshotLength failed, then the return type was not a set of + // nodes, so just return false in this case. + ErrorResult rv; + uint32_t length = mResults->GetSnapshotLength(rv); + if (NS_WARN_IF(rv.Failed())) { + rv.SuppressException(); + *aResult = false; + return NS_OK; + } + + *aResult = mPosition < length; + return NS_OK; +} + +NS_IMETHODIMP +nsXULTemplateResultSetXML::GetNext(nsISupports **aResult) +{ + ErrorResult rv; + nsINode* node = mResults->SnapshotItem(mPosition, rv); + if (rv.Failed()) { + return rv.StealNSResult(); + } + + nsXULTemplateResultXML* result = + new nsXULTemplateResultXML(mQuery, node->AsContent(), mBindingSet); + + ++mPosition; + *aResult = result; + NS_ADDREF(result); + return NS_OK; +} + + +//---------------------------------------------------------------------- +// +// nsXULTemplateQueryProcessorXML +// + +NS_IMPL_CYCLE_COLLECTION_CLASS(nsXULTemplateQueryProcessorXML) + +NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(nsXULTemplateQueryProcessorXML) + tmp->mRuleToBindingsMap.Clear(); + NS_IMPL_CYCLE_COLLECTION_UNLINK(mRoot) + NS_IMPL_CYCLE_COLLECTION_UNLINK(mEvaluator) + NS_IMPL_CYCLE_COLLECTION_UNLINK(mTemplateBuilder) + NS_IMPL_CYCLE_COLLECTION_UNLINK(mRequest) +NS_IMPL_CYCLE_COLLECTION_UNLINK_END +NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(nsXULTemplateQueryProcessorXML) + for (auto it = tmp->mRuleToBindingsMap.Iter(); !it.Done(); it.Next()) { + NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(cb, "mRuleToBindingsMap key"); + cb.NoteXPCOMChild(it.Key()); + } + NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mRoot) + NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mEvaluator) + NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mTemplateBuilder) + NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mRequest) +NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END +NS_IMPL_CYCLE_COLLECTING_ADDREF(nsXULTemplateQueryProcessorXML) +NS_IMPL_CYCLE_COLLECTING_RELEASE(nsXULTemplateQueryProcessorXML) +NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(nsXULTemplateQueryProcessorXML) + NS_INTERFACE_MAP_ENTRY(nsIXULTemplateQueryProcessor) + NS_INTERFACE_MAP_ENTRY(nsIDOMEventListener) + NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIXULTemplateQueryProcessor) +NS_INTERFACE_MAP_END + +/* + * Only the first datasource in aDataSource is used, which should be either an + * nsIURI of an XML document, or a DOM node. If the former, GetDatasource will + * load the document asynchronously and return null in aResult. Once the + * document has loaded, the builder's datasource will be set to the XML + * document. If the datasource is a DOM node, the node will be returned in + * aResult. + */ +NS_IMETHODIMP +nsXULTemplateQueryProcessorXML::GetDatasource(nsIArray* aDataSources, + nsIDOMNode* aRootNode, + bool aIsTrusted, + nsIXULTemplateBuilder* aBuilder, + bool* aShouldDelayBuilding, + nsISupports** aResult) +{ + *aResult = nullptr; + *aShouldDelayBuilding = false; + + nsresult rv; + uint32_t length; + + aDataSources->GetLength(&length); + if (length == 0) + return NS_OK; + + // we get only the first item, because the query processor supports only + // one document as a datasource + + nsCOMPtr<nsIDOMNode> node = do_QueryElementAt(aDataSources, 0); + if (node) { + return CallQueryInterface(node, aResult); + } + + nsCOMPtr<nsIURI> uri = do_QueryElementAt(aDataSources, 0); + if (!uri) + return NS_ERROR_UNEXPECTED; + + nsAutoCString uriStr; + rv = uri->GetSpec(uriStr); + NS_ENSURE_SUCCESS(rv, rv); + + nsCOMPtr<nsIContent> root = do_QueryInterface(aRootNode); + if (!root) + return NS_ERROR_UNEXPECTED; + + nsCOMPtr<nsIDocument> doc = root->GetUncomposedDoc(); + if (!doc) + return NS_ERROR_UNEXPECTED; + + nsIPrincipal *docPrincipal = doc->NodePrincipal(); + + bool hasHadScriptObject = true; + nsIScriptGlobalObject* scriptObject = + doc->GetScriptHandlingObject(hasHadScriptObject); + NS_ENSURE_STATE(scriptObject); + + nsCOMPtr<nsIXMLHttpRequest> req = + do_CreateInstance(NS_XMLHTTPREQUEST_CONTRACTID, &rv); + NS_ENSURE_SUCCESS(rv, rv); + + rv = req->Init(docPrincipal, scriptObject, nullptr, nullptr); + NS_ENSURE_SUCCESS(rv, rv); + + rv = req->Open(NS_LITERAL_CSTRING("GET"), uriStr, true, + EmptyString(), EmptyString()); + NS_ENSURE_SUCCESS(rv, rv); + + nsCOMPtr<EventTarget> target(do_QueryInterface(req)); + rv = target->AddEventListener(NS_LITERAL_STRING("load"), this, false); + NS_ENSURE_SUCCESS(rv, rv); + + rv = target->AddEventListener(NS_LITERAL_STRING("error"), this, false); + NS_ENSURE_SUCCESS(rv, rv); + + rv = req->Send(nullptr); + NS_ENSURE_SUCCESS(rv, rv); + + mTemplateBuilder = aBuilder; + mRequest = req; + + *aShouldDelayBuilding = true; + return NS_OK; +} + +NS_IMETHODIMP +nsXULTemplateQueryProcessorXML::InitializeForBuilding(nsISupports* aDatasource, + nsIXULTemplateBuilder* aBuilder, + nsIDOMNode* aRootNode) +{ + if (mGenerationStarted) + return NS_ERROR_UNEXPECTED; + + // the datasource is either a document or a DOM element + nsCOMPtr<nsIDocument> doc = do_QueryInterface(aDatasource); + if (doc) + mRoot = doc->GetDocumentElement(); + else + mRoot = do_QueryInterface(aDatasource); + NS_ENSURE_STATE(mRoot); + + mEvaluator = new XPathEvaluator(); + + return NS_OK; +} + +NS_IMETHODIMP +nsXULTemplateQueryProcessorXML::Done() +{ + mGenerationStarted = false; + + mRuleToBindingsMap.Clear(); + + return NS_OK; +} + +NS_IMETHODIMP +nsXULTemplateQueryProcessorXML::CompileQuery(nsIXULTemplateBuilder* aBuilder, + nsIDOMNode* aQueryNode, + nsIAtom* aRefVariable, + nsIAtom* aMemberVariable, + nsISupports** _retval) +{ + *_retval = nullptr; + + nsCOMPtr<nsIContent> content = do_QueryInterface(aQueryNode); + + nsAutoString expr; + content->GetAttr(kNameSpaceID_None, nsGkAtoms::expr, expr); + + // if an expression is not specified, then the default is to + // just take all of the children + if (expr.IsEmpty()) + expr.Assign('*'); + + ErrorResult rv; + nsAutoPtr<XPathExpression> compiledexpr; + compiledexpr = CreateExpression(expr, content, rv); + if (rv.Failed()) { + nsXULContentUtils::LogTemplateError(ERROR_TEMPLATE_BAD_XPATH); + return rv.StealNSResult(); + } + + RefPtr<nsXMLQuery> query = + new nsXMLQuery(this, aMemberVariable, Move(compiledexpr)); + + for (nsIContent* condition = content->GetFirstChild(); + condition; + condition = condition->GetNextSibling()) { + + if (condition->NodeInfo()->Equals(nsGkAtoms::assign, + kNameSpaceID_XUL)) { + nsAutoString var; + condition->GetAttr(kNameSpaceID_None, nsGkAtoms::var, var); + + nsAutoString expr; + condition->GetAttr(kNameSpaceID_None, nsGkAtoms::expr, expr); + + // ignore assignments without a variable or an expression + if (!var.IsEmpty() && !expr.IsEmpty()) { + compiledexpr = CreateExpression(expr, condition, rv); + if (rv.Failed()) { + nsXULContentUtils::LogTemplateError(ERROR_TEMPLATE_BAD_ASSIGN_XPATH); + return rv.StealNSResult(); + } + + nsCOMPtr<nsIAtom> varatom = NS_Atomize(var); + + query->AddBinding(varatom, Move(compiledexpr)); + } + } + } + + query.forget(_retval); + + return NS_OK; +} + +NS_IMETHODIMP +nsXULTemplateQueryProcessorXML::GenerateResults(nsISupports* aDatasource, + nsIXULTemplateResult* aRef, + nsISupports* aQuery, + nsISimpleEnumerator** aResults) +{ + if (!aQuery) + return NS_ERROR_INVALID_ARG; + + mGenerationStarted = true; + + nsCOMPtr<nsXMLQuery> xmlquery = do_QueryInterface(aQuery); + if (!xmlquery) + return NS_ERROR_INVALID_ARG; + + nsCOMPtr<nsISupports> supports; + nsCOMPtr<nsINode> context; + if (aRef) + aRef->GetBindingObjectFor(xmlquery->GetMemberVariable(), + getter_AddRefs(supports)); + context = do_QueryInterface(supports); + if (!context) + context = mRoot; + + XPathExpression* expr = xmlquery->GetResultsExpression(); + if (!expr) + return NS_ERROR_FAILURE; + + ErrorResult rv; + RefPtr<XPathResult> exprresults = + expr->Evaluate(*context, XPathResult::ORDERED_NODE_SNAPSHOT_TYPE, + nullptr, rv); + if (rv.Failed()) { + return rv.StealNSResult(); + } + + RefPtr<nsXULTemplateResultSetXML> results = + new nsXULTemplateResultSetXML(xmlquery, exprresults.forget(), + xmlquery->GetBindingSet()); + + results.forget(aResults); + + return NS_OK; +} + +NS_IMETHODIMP +nsXULTemplateQueryProcessorXML::AddBinding(nsIDOMNode* aRuleNode, + nsIAtom* aVar, + nsIAtom* aRef, + const nsAString& aExpr) +{ + if (mGenerationStarted) + return NS_ERROR_FAILURE; + + RefPtr<nsXMLBindingSet> bindings = mRuleToBindingsMap.GetWeak(aRuleNode); + if (!bindings) { + bindings = new nsXMLBindingSet(); + mRuleToBindingsMap.Put(aRuleNode, bindings); + } + + nsCOMPtr<nsINode> ruleNode = do_QueryInterface(aRuleNode); + + ErrorResult rv; + nsAutoPtr<XPathExpression> compiledexpr; + compiledexpr = CreateExpression(aExpr, ruleNode, rv); + if (rv.Failed()) { + rv.SuppressException(); + nsXULContentUtils::LogTemplateError(ERROR_TEMPLATE_BAD_BINDING_XPATH); + return NS_OK; + } + + // aRef isn't currently used for XML query processors + bindings->AddBinding(aVar, Move(compiledexpr)); + return NS_OK; +} + +NS_IMETHODIMP +nsXULTemplateQueryProcessorXML::TranslateRef(nsISupports* aDatasource, + const nsAString& aRefString, + nsIXULTemplateResult** aRef) +{ + *aRef = nullptr; + + // the datasource is either a document or a DOM element + nsCOMPtr<Element> rootElement; + nsCOMPtr<nsIDocument> doc = do_QueryInterface(aDatasource); + if (doc) + rootElement = doc->GetRootElement(); + else + rootElement = do_QueryInterface(aDatasource); + + // if no root element, just return. The document may not have loaded yet + if (!rootElement) + return NS_OK; + + RefPtr<nsXULTemplateResultXML> result = new nsXULTemplateResultXML(nullptr, rootElement, nullptr); + result.forget(aRef); + + return NS_OK; +} + + +NS_IMETHODIMP +nsXULTemplateQueryProcessorXML::CompareResults(nsIXULTemplateResult* aLeft, + nsIXULTemplateResult* aRight, + nsIAtom* aVar, + uint32_t aSortHints, + int32_t* aResult) +{ + *aResult = 0; + if (!aVar) + return NS_OK; + + nsAutoString leftVal; + if (aLeft) + aLeft->GetBindingFor(aVar, leftVal); + + nsAutoString rightVal; + if (aRight) + aRight->GetBindingFor(aVar, rightVal); + + *aResult = XULSortServiceImpl::CompareValues(leftVal, rightVal, aSortHints); + return NS_OK; +} + +nsXMLBindingSet* +nsXULTemplateQueryProcessorXML::GetOptionalBindingsForRule(nsIDOMNode* aRuleNode) +{ + return mRuleToBindingsMap.GetWeak(aRuleNode); +} + +XPathExpression* +nsXULTemplateQueryProcessorXML::CreateExpression(const nsAString& aExpr, + nsINode* aNode, + ErrorResult& aRv) +{ + return mEvaluator->CreateExpression(aExpr, aNode, aRv); +} + +NS_IMETHODIMP +nsXULTemplateQueryProcessorXML::HandleEvent(nsIDOMEvent* aEvent) +{ + NS_PRECONDITION(aEvent, "aEvent null"); + nsAutoString eventType; + aEvent->GetType(eventType); + + if (eventType.EqualsLiteral("load") && mTemplateBuilder) { + NS_ASSERTION(mRequest, "request was not set"); + nsCOMPtr<nsIDOMDocument> doc; + if (NS_SUCCEEDED(mRequest->GetResponseXML(getter_AddRefs(doc)))) + mTemplateBuilder->SetDatasource(doc); + + // to avoid leak. we don't need it after... + mTemplateBuilder = nullptr; + mRequest = nullptr; + } + else if (eventType.EqualsLiteral("error")) { + mTemplateBuilder = nullptr; + mRequest = nullptr; + } + + return NS_OK; +} diff --git a/dom/xul/templates/nsXULTemplateQueryProcessorXML.h b/dom/xul/templates/nsXULTemplateQueryProcessorXML.h new file mode 100644 index 000000000..dec508415 --- /dev/null +++ b/dom/xul/templates/nsXULTemplateQueryProcessorXML.h @@ -0,0 +1,170 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* 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/. */ + +#ifndef nsXULTemplateQueryProcessorXML_h__ +#define nsXULTemplateQueryProcessorXML_h__ + +#include "nsIXULTemplateBuilder.h" +#include "nsIXULTemplateQueryProcessor.h" + +#include "nsAutoPtr.h" +#include "nsISimpleEnumerator.h" +#include "nsString.h" +#include "nsCOMArray.h" +#include "nsRefPtrHashtable.h" +#include "nsIDOMEventListener.h" +#include "nsIDOMXPathEvaluator.h" +#include "nsXMLBinding.h" +#include "nsCycleCollectionParticipant.h" +#include "nsIXMLHttpRequest.h" +#include "mozilla/Attributes.h" +#include "mozilla/dom/Element.h" +#include "mozilla/dom/XPathEvaluator.h" +#include "mozilla/dom/XPathResult.h" + +class nsXULTemplateQueryProcessorXML; + +#define NS_IXMLQUERY_IID \ + {0x0358d692, 0xccce, 0x4a97, \ + { 0xb2, 0x51, 0xba, 0x8f, 0x17, 0x0f, 0x3b, 0x6f }} + +class nsXMLQuery final : public nsISupports +{ + public: + NS_DECLARE_STATIC_IID_ACCESSOR(NS_IXMLQUERY_IID) + + NS_DECL_ISUPPORTS + + // return a weak reference to the processor the query was created from + nsXULTemplateQueryProcessorXML* Processor() { return mProcessor; } + + // return a weak reference t the member variable for the query + nsIAtom* GetMemberVariable() { return mMemberVariable; } + + // return a weak reference to the expression used to generate results + mozilla::dom::XPathExpression* GetResultsExpression() + { return mResultsExpr; } + + // return a weak reference to the additional required bindings + nsXMLBindingSet* GetBindingSet() { return mRequiredBindings; } + + // add a required binding for the query + void + AddBinding(nsIAtom* aVar, nsAutoPtr<mozilla::dom::XPathExpression>&& aExpr) + { + if (!mRequiredBindings) { + mRequiredBindings = new nsXMLBindingSet(); + } + + mRequiredBindings->AddBinding(aVar, mozilla::Move(aExpr)); + } + + nsXMLQuery(nsXULTemplateQueryProcessorXML* aProcessor, + nsIAtom* aMemberVariable, + nsAutoPtr<mozilla::dom::XPathExpression>&& aResultsExpr) + : mProcessor(aProcessor), + mMemberVariable(aMemberVariable), + mResultsExpr(aResultsExpr) + { } + + protected: + ~nsXMLQuery() {} + + nsXULTemplateQueryProcessorXML* mProcessor; + + nsCOMPtr<nsIAtom> mMemberVariable; + + nsAutoPtr<mozilla::dom::XPathExpression> mResultsExpr; + + RefPtr<nsXMLBindingSet> mRequiredBindings; +}; + +NS_DEFINE_STATIC_IID_ACCESSOR(nsXMLQuery, NS_IXMLQUERY_IID) + +class nsXULTemplateResultSetXML final : public nsISimpleEnumerator +{ +private: + + // reference back to the query + nsCOMPtr<nsXMLQuery> mQuery; + + // the binding set created from <assign> nodes + RefPtr<nsXMLBindingSet> mBindingSet; + + // set of results contained in this enumerator + RefPtr<mozilla::dom::XPathResult> mResults; + + // current position within the list of results + uint32_t mPosition; + + ~nsXULTemplateResultSetXML() {} + +public: + + // nsISupports interface + NS_DECL_ISUPPORTS + + // nsISimpleEnumerator interface + NS_DECL_NSISIMPLEENUMERATOR + + nsXULTemplateResultSetXML(nsXMLQuery* aQuery, + already_AddRefed<mozilla::dom::XPathResult> aResults, + nsXMLBindingSet* aBindingSet) + : mQuery(aQuery), + mBindingSet(aBindingSet), + mResults(aResults), + mPosition(0) + {} +}; + +class nsXULTemplateQueryProcessorXML final : public nsIXULTemplateQueryProcessor, + public nsIDOMEventListener +{ +public: + + nsXULTemplateQueryProcessorXML() + : mGenerationStarted(false) + {} + + // nsISupports interface + NS_DECL_CYCLE_COLLECTING_ISUPPORTS + NS_DECL_CYCLE_COLLECTION_CLASS_AMBIGUOUS(nsXULTemplateQueryProcessorXML, + nsIXULTemplateQueryProcessor) + + // nsIXULTemplateQueryProcessor interface + NS_DECL_NSIXULTEMPLATEQUERYPROCESSOR + + // nsIDOMEventListener interface + NS_DECL_NSIDOMEVENTLISTENER + + nsXMLBindingSet* + GetOptionalBindingsForRule(nsIDOMNode* aRuleNode); + + // create an XPath expression from aExpr, using aNode for + // resolving namespaces + mozilla::dom::XPathExpression* + CreateExpression(const nsAString& aExpr, + nsINode* aNode, + mozilla::ErrorResult& aRv); + +private: + + ~nsXULTemplateQueryProcessorXML() {} + + bool mGenerationStarted; + + nsRefPtrHashtable<nsISupportsHashKey, nsXMLBindingSet> mRuleToBindingsMap; + + nsCOMPtr<mozilla::dom::Element> mRoot; + + RefPtr<mozilla::dom::XPathEvaluator> mEvaluator; + + nsCOMPtr<nsIXULTemplateBuilder> mTemplateBuilder; + + nsCOMPtr<nsIXMLHttpRequest> mRequest; +}; + + +#endif // nsXULTemplateQueryProcessorXML_h__ diff --git a/dom/xul/templates/nsXULTemplateResultRDF.cpp b/dom/xul/templates/nsXULTemplateResultRDF.cpp new file mode 100644 index 000000000..9d53bab7d --- /dev/null +++ b/dom/xul/templates/nsXULTemplateResultRDF.cpp @@ -0,0 +1,208 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* 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 "nsXULTemplateResultRDF.h" +#include "nsXULContentUtils.h" + +// XXXndeakin for some reason, making this class have classinfo breaks trees. +//#include "nsIDOMClassInfo.h" + +NS_IMPL_CYCLE_COLLECTION(nsXULTemplateResultRDF, mQuery) + +NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(nsXULTemplateResultRDF) + NS_INTERFACE_MAP_ENTRY(nsIXULTemplateResult) + NS_INTERFACE_MAP_ENTRY(nsISupports) +NS_INTERFACE_MAP_END + +NS_IMPL_CYCLE_COLLECTING_ADDREF(nsXULTemplateResultRDF) +NS_IMPL_CYCLE_COLLECTING_RELEASE(nsXULTemplateResultRDF) + +nsXULTemplateResultRDF::nsXULTemplateResultRDF(nsIRDFResource* aNode) + : mQuery(nullptr), + mNode(aNode) +{ +} + +nsXULTemplateResultRDF::nsXULTemplateResultRDF(nsRDFQuery* aQuery, + const Instantiation& aInst, + nsIRDFResource *aNode) + : mQuery(aQuery), + mNode(aNode), + mInst(aInst) +{ +} + +nsXULTemplateResultRDF::~nsXULTemplateResultRDF() +{ +} + +NS_IMETHODIMP +nsXULTemplateResultRDF::GetIsContainer(bool* aIsContainer) +{ + *aIsContainer = false; + + if (mNode) { + nsXULTemplateQueryProcessorRDF* processor = GetProcessor(); + if (processor) + return processor->CheckContainer(mNode, aIsContainer); + } + + return NS_OK; +} + +NS_IMETHODIMP +nsXULTemplateResultRDF::GetIsEmpty(bool* aIsEmpty) +{ + *aIsEmpty = true; + + if (mNode) { + nsXULTemplateQueryProcessorRDF* processor = GetProcessor(); + if (processor) + return processor->CheckEmpty(mNode, aIsEmpty); + } + + return NS_OK; +} + +NS_IMETHODIMP +nsXULTemplateResultRDF::GetMayProcessChildren(bool* aMayProcessChildren) +{ + // RDF always allows recursion + *aMayProcessChildren = true; + return NS_OK; +} + +NS_IMETHODIMP +nsXULTemplateResultRDF::GetId(nsAString& aId) +{ + if (! mNode) + return NS_ERROR_FAILURE; + + const char* uri; + mNode->GetValueConst(&uri); + + CopyUTF8toUTF16(uri, aId); + + return NS_OK; +} + +NS_IMETHODIMP +nsXULTemplateResultRDF::GetResource(nsIRDFResource** aResource) +{ + *aResource = mNode; + NS_IF_ADDREF(*aResource); + return NS_OK; +} + +NS_IMETHODIMP +nsXULTemplateResultRDF::GetType(nsAString& aType) +{ + aType.Truncate(); + + nsresult rv = NS_OK; + + nsXULTemplateQueryProcessorRDF* processor = GetProcessor(); + if (processor) { + bool found; + rv = processor->CheckIsSeparator(mNode, &found); + if (NS_SUCCEEDED(rv) && found) + aType.AssignLiteral("separator"); + } + + return rv; +} + +NS_IMETHODIMP +nsXULTemplateResultRDF::GetBindingFor(nsIAtom* aVar, nsAString& aValue) +{ + nsCOMPtr<nsIRDFNode> val; + GetAssignment(aVar, getter_AddRefs(val)); + + return nsXULContentUtils::GetTextForNode(val, aValue); +} + +NS_IMETHODIMP +nsXULTemplateResultRDF::GetBindingObjectFor(nsIAtom* aVar, nsISupports** aValue) +{ + GetAssignment(aVar, (nsIRDFNode **)aValue); + + return NS_OK; +} + +NS_IMETHODIMP +nsXULTemplateResultRDF::RuleMatched(nsISupports* aQuery, nsIDOMNode* aRuleNode) +{ + // when a rule matches, set the bindings that must be used. + nsXULTemplateQueryProcessorRDF* processor = GetProcessor(); + if (processor) { + RDFBindingSet* bindings = processor->GetBindingsForRule(aRuleNode); + if (bindings) { + nsresult rv = mBindingValues.SetBindingSet(bindings); + if (NS_FAILED(rv)) + return rv; + + bindings->AddDependencies(mNode, this); + } + } + + return NS_OK; +} + +NS_IMETHODIMP +nsXULTemplateResultRDF::HasBeenRemoved() +{ + // when a result is no longer used, clean up the dependencies and + // memory elements that refer to it + mBindingValues.RemoveDependencies(mNode, this); + + nsXULTemplateQueryProcessorRDF* processor = GetProcessor(); + if (processor) + processor->RemoveMemoryElements(mInst, this); + + return NS_OK; +} + + +void +nsXULTemplateResultRDF::GetAssignment(nsIAtom* aVar, nsIRDFNode** aValue) +{ + // look up a variable in the assignments map + *aValue = nullptr; + mInst.mAssignments.GetAssignmentFor(aVar, aValue); + + // if not found, look up the variable in the bindings + if (! *aValue) + mBindingValues.GetAssignmentFor(this, aVar, aValue); +} + + +bool +nsXULTemplateResultRDF::SyncAssignments(nsIRDFResource* aSubject, + nsIRDFResource* aPredicate, + nsIRDFNode* aTarget) +{ + // synchronize the bindings when an assertion is added or removed + RDFBindingSet* bindingset = mBindingValues.GetBindingSet(); + if (bindingset) { + return bindingset->SyncAssignments(aSubject, aPredicate, aTarget, + (aSubject == mNode) ? mQuery->GetMemberVariable() : nullptr, + this, mBindingValues); + } + + return false; +} + +bool +nsXULTemplateResultRDF::HasMemoryElement(const MemoryElement& aMemoryElement) +{ + MemoryElementSet::ConstIterator last = mInst.mSupport.Last(); + for (MemoryElementSet::ConstIterator element = mInst.mSupport.First(); + element != last; ++element) { + if ((*element).Equals(aMemoryElement)) + return true; + } + + return false; +} diff --git a/dom/xul/templates/nsXULTemplateResultRDF.h b/dom/xul/templates/nsXULTemplateResultRDF.h new file mode 100644 index 000000000..cb5022420 --- /dev/null +++ b/dom/xul/templates/nsXULTemplateResultRDF.h @@ -0,0 +1,81 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* 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/. */ + +#ifndef nsXULTemplateResultRDF_h__ +#define nsXULTemplateResultRDF_h__ + +#include "nsCOMPtr.h" +#include "nsIRDFResource.h" +#include "nsXULTemplateQueryProcessorRDF.h" +#include "nsRDFQuery.h" +#include "nsRuleNetwork.h" +#include "nsIXULTemplateResult.h" +#include "nsRDFBinding.h" +#include "mozilla/Attributes.h" + +/** + * A single result of a query on an RDF graph + */ +class nsXULTemplateResultRDF final : public nsIXULTemplateResult +{ +public: + NS_DECL_CYCLE_COLLECTING_ISUPPORTS + NS_DECL_CYCLE_COLLECTION_CLASS(nsXULTemplateResultRDF) + + NS_DECL_NSIXULTEMPLATERESULT + + explicit nsXULTemplateResultRDF(nsIRDFResource* aNode); + + nsXULTemplateResultRDF(nsRDFQuery* aQuery, + const Instantiation& aInst, + nsIRDFResource* aNode); + + nsITemplateRDFQuery* Query() { return mQuery; } + + nsXULTemplateQueryProcessorRDF* GetProcessor() + { + return (mQuery ? mQuery->Processor() : nullptr); + } + + /** + * Get the value of a variable, first by looking in the assignments and + * then the bindings + */ + void + GetAssignment(nsIAtom* aVar, nsIRDFNode** aValue); + + /** + * Synchronize the bindings after a change in the RDF graph. Bindings that + * would be affected will be assigned appropriately based on the change. + */ + bool + SyncAssignments(nsIRDFResource* aSubject, + nsIRDFResource* aPredicate, + nsIRDFNode* aTarget); + + /** + * Return true if the result has an instantiation involving a particular + * memory element. + */ + bool + HasMemoryElement(const MemoryElement& aMemoryElement); + +protected: + ~nsXULTemplateResultRDF(); + + // query that generated the result + nsCOMPtr<nsITemplateRDFQuery> mQuery; + + // resource node + nsCOMPtr<nsIRDFResource> mNode; + + // data computed from query + Instantiation mInst; + + // extra assignments made by rules (<binding> tags) + nsBindingValues mBindingValues; +}; + +#endif // nsXULTemplateResultRDF_h__ diff --git a/dom/xul/templates/nsXULTemplateResultSetRDF.cpp b/dom/xul/templates/nsXULTemplateResultSetRDF.cpp new file mode 100644 index 000000000..1ab9a7959 --- /dev/null +++ b/dom/xul/templates/nsXULTemplateResultSetRDF.cpp @@ -0,0 +1,82 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* 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 "nsXULTemplateResultSetRDF.h" +#include "nsXULTemplateQueryProcessorRDF.h" + +NS_IMPL_ISUPPORTS(nsXULTemplateResultSetRDF, nsISimpleEnumerator) + +NS_IMETHODIMP +nsXULTemplateResultSetRDF::HasMoreElements(bool *aResult) +{ + *aResult = true; + + nsCOMPtr<nsIRDFNode> node; + + if (! mInstantiations || ! mQuery) { + *aResult = false; + return NS_OK; + } + + if (mCheckedNext) { + if (!mCurrent || mCurrent == &(mInstantiations->mHead)) + *aResult = false; + return NS_OK; + } + + mCheckedNext = true; + + do { + if (mCurrent) { + mCurrent = mCurrent->mNext; + if (mCurrent == &(mInstantiations->mHead)) { + *aResult = false; + return NS_OK; + } + } + else { + *aResult = ! mInstantiations->Empty(); + if (*aResult) + mCurrent = mInstantiations->mHead.mNext; + } + + // get the value of the member variable. If it is not set, skip + // the result and move on to the next result + if (mCurrent) { + mCurrent->mInstantiation.mAssignments. + GetAssignmentFor(mQuery->mMemberVariable, getter_AddRefs(node)); + } + + // only resources may be used as results + mResource = do_QueryInterface(node); + } while (! mResource); + + return NS_OK; +} + +NS_IMETHODIMP +nsXULTemplateResultSetRDF::GetNext(nsISupports **aResult) +{ + if (!aResult) + return NS_ERROR_NULL_POINTER; + + if (!mCurrent || !mCheckedNext) + return NS_ERROR_FAILURE; + + RefPtr<nsXULTemplateResultRDF> nextresult = + new nsXULTemplateResultRDF(mQuery, mCurrent->mInstantiation, mResource); + if (!nextresult) + return NS_ERROR_OUT_OF_MEMORY; + + // add the supporting memory elements to the processor's map. These are + // used to remove the results when an assertion is removed from the graph + mProcessor->AddMemoryElements(mCurrent->mInstantiation, nextresult); + + mCheckedNext = false; + + nextresult.forget(aResult); + + return NS_OK; +} diff --git a/dom/xul/templates/nsXULTemplateResultSetRDF.h b/dom/xul/templates/nsXULTemplateResultSetRDF.h new file mode 100644 index 000000000..76aa28774 --- /dev/null +++ b/dom/xul/templates/nsXULTemplateResultSetRDF.h @@ -0,0 +1,60 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* 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/. */ + +#ifndef nsXULTemplateResultSetRDF_h__ +#define nsXULTemplateResultSetRDF_h__ + +#include "nsISimpleEnumerator.h" +#include "nsRuleNetwork.h" +#include "nsRDFQuery.h" +#include "nsXULTemplateResultRDF.h" +#include "mozilla/Attributes.h" + +class nsXULTemplateQueryProcessorRDF; +class nsXULTemplateResultRDF; + +/** + * An enumerator used to iterate over a set of results. + */ +class nsXULTemplateResultSetRDF final : public nsISimpleEnumerator +{ +private: + nsXULTemplateQueryProcessorRDF* mProcessor; + + nsRDFQuery* mQuery; + + const InstantiationSet* mInstantiations; + + nsCOMPtr<nsIRDFResource> mResource; + + InstantiationSet::List *mCurrent; + + bool mCheckedNext; + + ~nsXULTemplateResultSetRDF() + { + delete mInstantiations; + } + +public: + + // nsISupports interface + NS_DECL_ISUPPORTS + + // nsISimpleEnumerator interface + NS_DECL_NSISIMPLEENUMERATOR + + nsXULTemplateResultSetRDF(nsXULTemplateQueryProcessorRDF *aProcessor, + nsRDFQuery* aQuery, + const InstantiationSet* aInstantiations) + : mProcessor(aProcessor), + mQuery(aQuery), + mInstantiations(aInstantiations), + mCurrent(nullptr), + mCheckedNext(false) + { } +}; + +#endif // nsXULTemplateResultSetRDF_h__ diff --git a/dom/xul/templates/nsXULTemplateResultStorage.cpp b/dom/xul/templates/nsXULTemplateResultStorage.cpp new file mode 100644 index 000000000..b840fc2c7 --- /dev/null +++ b/dom/xul/templates/nsXULTemplateResultStorage.cpp @@ -0,0 +1,126 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* 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 "nsIServiceManager.h" +#include "nsRDFCID.h" +#include "nsIRDFService.h" +#include "nsString.h" +#include "nsXULTemplateResultStorage.h" + +NS_IMPL_ISUPPORTS(nsXULTemplateResultStorage, nsIXULTemplateResult) + +nsXULTemplateResultStorage::nsXULTemplateResultStorage(nsXULTemplateResultSetStorage* aResultSet) +{ + static NS_DEFINE_CID(kRDFServiceCID, NS_RDFSERVICE_CID); + nsCOMPtr<nsIRDFService> rdfService = do_GetService(kRDFServiceCID); + rdfService->GetAnonymousResource(getter_AddRefs(mNode)); + mResultSet = aResultSet; + if (aResultSet) { + mResultSet->FillColumnValues(mValues); + } +} + +nsXULTemplateResultStorage::~nsXULTemplateResultStorage() +{ +} + +NS_IMETHODIMP +nsXULTemplateResultStorage::GetIsContainer(bool* aIsContainer) +{ + *aIsContainer = false; + return NS_OK; +} + +NS_IMETHODIMP +nsXULTemplateResultStorage::GetIsEmpty(bool* aIsEmpty) +{ + *aIsEmpty = true; + return NS_OK; +} + +NS_IMETHODIMP +nsXULTemplateResultStorage::GetMayProcessChildren(bool* aMayProcessChildren) +{ + *aMayProcessChildren = false; + return NS_OK; +} + +NS_IMETHODIMP +nsXULTemplateResultStorage::GetId(nsAString& aId) +{ + const char* uri = nullptr; + mNode->GetValueConst(&uri); + + aId.Assign(NS_ConvertUTF8toUTF16(uri)); + + return NS_OK; +} + +NS_IMETHODIMP +nsXULTemplateResultStorage::GetResource(nsIRDFResource** aResource) +{ + *aResource = mNode; + NS_IF_ADDREF(*aResource); + return NS_OK; +} + +NS_IMETHODIMP +nsXULTemplateResultStorage::GetType(nsAString& aType) +{ + aType.Truncate(); + return NS_OK; +} + + +NS_IMETHODIMP +nsXULTemplateResultStorage::GetBindingFor(nsIAtom* aVar, nsAString& aValue) +{ + NS_ENSURE_ARG_POINTER(aVar); + + aValue.Truncate(); + if (!mResultSet) { + return NS_OK; + } + + int32_t idx = mResultSet->GetColumnIndex(aVar); + if (idx < 0) { + return NS_OK; + } + + nsIVariant * value = mValues[idx]; + if (value) { + value->GetAsAString(aValue); + } + return NS_OK; +} + +NS_IMETHODIMP +nsXULTemplateResultStorage::GetBindingObjectFor(nsIAtom* aVar, nsISupports** aValue) +{ + NS_ENSURE_ARG_POINTER(aVar); + + if (mResultSet) { + int32_t idx = mResultSet->GetColumnIndex(aVar); + if (idx >= 0) { + *aValue = mValues[idx]; + NS_IF_ADDREF(*aValue); + return NS_OK; + } + } + *aValue = nullptr; + return NS_OK; +} + +NS_IMETHODIMP +nsXULTemplateResultStorage::RuleMatched(nsISupports* aQuery, nsIDOMNode* aRuleNode) +{ + return NS_OK; +} + +NS_IMETHODIMP +nsXULTemplateResultStorage::HasBeenRemoved() +{ + return NS_OK; +} diff --git a/dom/xul/templates/nsXULTemplateResultStorage.h b/dom/xul/templates/nsXULTemplateResultStorage.h new file mode 100644 index 000000000..75cf7b05a --- /dev/null +++ b/dom/xul/templates/nsXULTemplateResultStorage.h @@ -0,0 +1,37 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* 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/. */ + +#ifndef nsXULTemplateResultStorage_h__ +#define nsXULTemplateResultStorage_h__ + +#include "nsXULTemplateQueryProcessorStorage.h" +#include "nsIRDFResource.h" +#include "nsIXULTemplateResult.h" +#include "mozilla/Attributes.h" + +/** + * A single result of a query from mozstorage + */ +class nsXULTemplateResultStorage final : public nsIXULTemplateResult +{ +public: + NS_DECL_ISUPPORTS + + NS_DECL_NSIXULTEMPLATERESULT + + explicit nsXULTemplateResultStorage(nsXULTemplateResultSetStorage* aResultSet); + +protected: + + ~nsXULTemplateResultStorage(); + + RefPtr<nsXULTemplateResultSetStorage> mResultSet; + + nsCOMArray<nsIVariant> mValues; + + nsCOMPtr<nsIRDFResource> mNode; +}; + +#endif // nsXULTemplateResultStorage_h__ diff --git a/dom/xul/templates/nsXULTemplateResultXML.cpp b/dom/xul/templates/nsXULTemplateResultXML.cpp new file mode 100644 index 000000000..6ac4e6004 --- /dev/null +++ b/dom/xul/templates/nsXULTemplateResultXML.cpp @@ -0,0 +1,189 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* 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 "nsIServiceManager.h" +#include "nsIDOMNode.h" +#include "nsIDOMElement.h" +#include "nsIContent.h" + +#include "nsIRDFService.h" + +#include "nsXULTemplateResultXML.h" +#include "nsXMLBinding.h" + +static uint32_t sTemplateId = 0; + +NS_IMPL_ISUPPORTS(nsXULTemplateResultXML, nsIXULTemplateResult) + +nsXULTemplateResultXML::nsXULTemplateResultXML(nsXMLQuery* aQuery, + nsIContent* aNode, + nsXMLBindingSet* aBindings) + : mQuery(aQuery), mNode(aNode) +{ + // If the node has an id, create the uri from it. Otherwise, there isn't + // anything to identify the node with so just use a somewhat random number. + nsCOMPtr<nsIAtom> id = mNode->GetID(); + if (id) { + nsCOMPtr<nsIURI> uri = mNode->GetBaseURI(); + nsAutoCString spec; + uri->GetSpec(spec); + + mId = NS_ConvertUTF8toUTF16(spec); + + nsAutoString idstr; + id->ToString(idstr); + mId += NS_LITERAL_STRING("#") + idstr; + } + else { + nsAutoString rowid(NS_LITERAL_STRING("row")); + rowid.AppendInt(++sTemplateId); + mId.Assign(rowid); + } + + if (aBindings) + mRequiredValues.SetBindingSet(aBindings); +} + +NS_IMETHODIMP +nsXULTemplateResultXML::GetIsContainer(bool* aIsContainer) +{ + // a node is considered a container if it has children + *aIsContainer = mNode && mNode->HasChildNodes(); + return NS_OK; +} + +NS_IMETHODIMP +nsXULTemplateResultXML::GetIsEmpty(bool* aIsEmpty) +{ + // a node is considered empty if it has no elements as children + nsCOMPtr<nsIContent> content = do_QueryInterface(mNode); + if (content) { + for (nsIContent* child = content->GetFirstChild(); + child; + child = child->GetNextSibling()) { + if (child->IsElement()) { + *aIsEmpty = false; + return NS_OK; + } + } + } + + *aIsEmpty = true; + return NS_OK; +} + +NS_IMETHODIMP +nsXULTemplateResultXML::GetMayProcessChildren(bool* aMayProcessChildren) +{ + *aMayProcessChildren = true; + return NS_OK; +} + +NS_IMETHODIMP +nsXULTemplateResultXML::GetId(nsAString& aId) +{ + aId = mId; + return NS_OK; +} + +NS_IMETHODIMP +nsXULTemplateResultXML::GetResource(nsIRDFResource** aResource) +{ + *aResource = nullptr; + return NS_OK; +} + +NS_IMETHODIMP +nsXULTemplateResultXML::GetType(nsAString& aType) +{ + aType.Truncate(); + return NS_OK; +} + +NS_IMETHODIMP +nsXULTemplateResultXML::GetBindingFor(nsIAtom* aVar, nsAString& aValue) +{ + NS_ENSURE_ARG_POINTER(aVar); + + // get the position of the atom in the variables table + nsXMLBinding* binding; + + int32_t idx = mRequiredValues.LookupTargetIndex(aVar, &binding); + if (idx >= 0) { + mRequiredValues.GetStringAssignmentFor(this, binding, idx, aValue); + return NS_OK; + } + + idx = mOptionalValues.LookupTargetIndex(aVar, &binding); + if (idx >= 0) { + mOptionalValues.GetStringAssignmentFor(this, binding, idx, aValue); + return NS_OK; + } + + // if the variable is not bound, just use the variable name as the name of + // an attribute to retrieve + nsAutoString attr; + aVar->ToString(attr); + + if (attr.Length() > 1) { + nsCOMPtr<nsIDOMElement> element = do_QueryInterface(mNode); + if (element) + return element->GetAttribute(Substring(attr, 1), aValue); + } + + aValue.Truncate(); + return NS_OK; +} + +NS_IMETHODIMP +nsXULTemplateResultXML::GetBindingObjectFor(nsIAtom* aVar, nsISupports** aValue) +{ + NS_ENSURE_ARG_POINTER(aVar); + + nsXMLBinding* binding; + nsCOMPtr<nsISupports> node; + + if (mQuery && aVar == mQuery->GetMemberVariable()) { + node = mNode; + } + else { + int32_t idx = mRequiredValues.LookupTargetIndex(aVar, &binding); + if (idx > 0) { + node = mRequiredValues.GetNodeAssignmentFor(this, binding, idx); + } + else { + idx = mOptionalValues.LookupTargetIndex(aVar, &binding); + if (idx > 0) { + node = mOptionalValues.GetNodeAssignmentFor(this, binding, idx); + } + } + } + + node.forget(aValue); + return NS_OK; +} + +NS_IMETHODIMP +nsXULTemplateResultXML::RuleMatched(nsISupports* aQueryNode, + nsIDOMNode* aRuleNode) +{ + // when a rule matches, set the bindings that must be used. + nsXULTemplateQueryProcessorXML* processor = mQuery ? mQuery->Processor() : + nullptr; + if (processor) { + nsXMLBindingSet* bindings = + processor->GetOptionalBindingsForRule(aRuleNode); + if (bindings) + mOptionalValues.SetBindingSet(bindings); + } + + return NS_OK; +} + +NS_IMETHODIMP +nsXULTemplateResultXML::HasBeenRemoved() +{ + return NS_OK; +} diff --git a/dom/xul/templates/nsXULTemplateResultXML.h b/dom/xul/templates/nsXULTemplateResultXML.h new file mode 100644 index 000000000..3c42c0829 --- /dev/null +++ b/dom/xul/templates/nsXULTemplateResultXML.h @@ -0,0 +1,59 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* 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/. */ + +#ifndef nsXULTemplateResultXML_h__ +#define nsXULTemplateResultXML_h__ + +#include "nsCOMPtr.h" +#include "nsIContent.h" +#include "nsIURI.h" +#include "nsIRDFResource.h" +#include "nsXULTemplateQueryProcessorXML.h" +#include "nsIXULTemplateResult.h" +#include "mozilla/Attributes.h" + +/** + * An single result of an query + */ +class nsXULTemplateResultXML final : public nsIXULTemplateResult +{ +public: + NS_DECL_ISUPPORTS + + NS_DECL_NSIXULTEMPLATERESULT + + nsXULTemplateResultXML(nsXMLQuery* aQuery, + nsIContent* aNode, + nsXMLBindingSet* aBindings); + + nsIContent* Node() + { + return mNode; + } + +protected: + + ~nsXULTemplateResultXML() {} + + // ID used for persisting data. It is constructed using the mNode's + // base uri plus the node's id to form 'baseuri#id'. If the node has no + // id, then an id of the form 'row<some number>' is generated. In the + // latter case, persistence will not work as there won't be a unique id. + nsAutoString mId; + + // query that generated the result + nsCOMPtr<nsXMLQuery> mQuery; + + // context node in datasource + nsCOMPtr<nsIContent> mNode; + + // assignments in query + nsXMLBindingValues mRequiredValues; + + // extra assignments made by rules (<binding> tags) + nsXMLBindingValues mOptionalValues; +}; + +#endif // nsXULTemplateResultXML_h__ diff --git a/dom/xul/templates/nsXULTreeBuilder.cpp b/dom/xul/templates/nsXULTreeBuilder.cpp new file mode 100644 index 000000000..b42133484 --- /dev/null +++ b/dom/xul/templates/nsXULTreeBuilder.cpp @@ -0,0 +1,1881 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* 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 "nscore.h" +#include "nsError.h" +#include "nsIContent.h" +#include "mozilla/dom/NodeInfo.h" +#include "nsIDOMElement.h" +#include "nsIBoxObject.h" +#include "nsITreeBoxObject.h" +#include "nsITreeSelection.h" +#include "nsITreeColumns.h" +#include "nsITreeView.h" +#include "nsTreeUtils.h" +#include "nsIServiceManager.h" +#include "nsReadableUtils.h" +#include "nsQuickSort.h" +#include "nsTreeRows.h" +#include "nsTemplateRule.h" +#include "nsTemplateMatch.h" +#include "nsGkAtoms.h" +#include "nsXULContentUtils.h" +#include "nsXULTemplateBuilder.h" +#include "nsIXULSortService.h" +#include "nsTArray.h" +#include "nsUnicharUtils.h" +#include "nsNameSpaceManager.h" +#include "nsDOMClassInfoID.h" +#include "nsWhitespaceTokenizer.h" +#include "nsTreeContentView.h" +#include "nsIXULStore.h" +#include "mozilla/BinarySearch.h" + +// For security check +#include "nsIDocument.h" + +/** + * A XUL template builder that serves as an tree view, allowing + * (pretty much) arbitrary RDF to be presented in an tree. + */ +class nsXULTreeBuilder : public nsXULTemplateBuilder, + public nsIXULTreeBuilder, + public nsINativeTreeView +{ +public: + // nsISupports + NS_DECL_ISUPPORTS_INHERITED + NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(nsXULTreeBuilder, nsXULTemplateBuilder) + + // nsIXULTreeBuilder + NS_DECL_NSIXULTREEBUILDER + + // nsITreeView + NS_DECL_NSITREEVIEW + // nsINativeTreeView: Untrusted code can use us + NS_IMETHOD EnsureNative() override { return NS_OK; } + + // nsIMutationObserver + NS_DECL_NSIMUTATIONOBSERVER_NODEWILLBEDESTROYED + +protected: + friend nsresult + NS_NewXULTreeBuilder(nsISupports* aOuter, REFNSIID aIID, void** aResult); + + friend struct ResultComparator; + + nsXULTreeBuilder(); + ~nsXULTreeBuilder(); + + /** + * Uninitialize the template builder + */ + virtual void Uninit(bool aIsFinal) override; + + /** + * Get sort variables from the active <treecol> + */ + nsresult + EnsureSortVariables(); + + virtual nsresult + RebuildAll() override; + + /** + * Given a row, use the row's match to figure out the appropriate + * <treerow> in the rule's <action>. + */ + nsresult + GetTemplateActionRowFor(int32_t aRow, nsIContent** aResult); + + /** + * Given a row and a column ID, use the row's match to figure out + * the appropriate <treecell> in the rule's <action>. + */ + nsresult + GetTemplateActionCellFor(int32_t aRow, nsITreeColumn* aCol, nsIContent** aResult); + + /** + * Return the resource corresponding to a row in the tree. + */ + nsresult + GetResourceFor(int32_t aRow, nsIRDFResource** aResource); + + /** + * Open a container row, inserting the container's children into + * the view. + */ + nsresult + OpenContainer(int32_t aIndex, nsIXULTemplateResult* aResult); + + /** + * Helper for OpenContainer, recursively open subtrees, remembering + * persisted ``open'' state + */ + nsresult + OpenSubtreeOf(nsTreeRows::Subtree* aSubtree, + int32_t aIndex, + nsIXULTemplateResult *aResult, + int32_t* aDelta); + + nsresult + OpenSubtreeForQuerySet(nsTreeRows::Subtree* aSubtree, + int32_t aIndex, + nsIXULTemplateResult *aResult, + nsTemplateQuerySet* aQuerySet, + int32_t* aDelta, + nsTArray<int32_t>& open); + + /** + * Close a container row, removing the container's childrem from + * the view. + */ + nsresult + CloseContainer(int32_t aIndex); + + /** + * Remove the matches for the rows in a subtree + */ + nsresult + RemoveMatchesFor(nsTreeRows::Subtree& subtree); + + /** + * Helper method that determines if the specified container is open. + */ + bool + IsContainerOpen(nsIXULTemplateResult* aResource); + + /** + * A sorting callback for NS_QuickSort(). + */ + static int + Compare(const void* aLeft, const void* aRight, void* aClosure); + + /** + * The real sort routine + */ + int32_t + CompareResults(nsIXULTemplateResult* aLeft, nsIXULTemplateResult* aRight); + + /** + * Sort the specified subtree, and recursively sort any subtrees + * beneath it. + */ + nsresult + SortSubtree(nsTreeRows::Subtree* aSubtree); + + NS_IMETHOD + HasGeneratedContent(nsIRDFResource* aResource, + nsIAtom* aTag, + bool* aGenerated) override; + + // GetInsertionLocations, ReplaceMatch and SynchronizeResult are inherited + // from nsXULTemplateBuilder + + /** + * Return true if the result can be inserted into the template as a new + * row. + */ + bool + GetInsertionLocations(nsIXULTemplateResult* aResult, + nsCOMArray<nsIContent>** aLocations) override; + + /** + * Implement result replacement + */ + virtual nsresult + ReplaceMatch(nsIXULTemplateResult* aOldResult, + nsTemplateMatch* aNewMatch, + nsTemplateRule* aNewMatchRule, + void* aContext) override; + + /** + * Implement match synchronization + */ + virtual nsresult + SynchronizeResult(nsIXULTemplateResult* aResult) override; + + /** + * The tree's box object, used to communicate with the front-end. + */ + nsCOMPtr<nsITreeBoxObject> mBoxObject; + + /** + * The tree's selection object. + */ + nsCOMPtr<nsITreeSelection> mSelection; + + /** + * The datasource that's used to persist open folder information + */ + nsCOMPtr<nsIRDFDataSource> mPersistStateStore; + + /** + * The rows in the view + */ + nsTreeRows mRows; + + /** + * The currently active sort variable + */ + nsCOMPtr<nsIAtom> mSortVariable; + + enum Direction { + eDirection_Descending = -1, + eDirection_Natural = 0, + eDirection_Ascending = +1 + }; + + /** + * The currently active sort order + */ + Direction mSortDirection; + + /* + * Sort hints (compare case, etc) + */ + uint32_t mSortHints; + + /** + * The builder observers. + */ + nsCOMArray<nsIXULTreeBuilderObserver> mObservers; + + /* + * XUL store for holding open container state + */ + nsCOMPtr<nsIXULStore> mLocalStore; +}; + +//---------------------------------------------------------------------- + +nsresult +NS_NewXULTreeBuilder(nsISupports* aOuter, REFNSIID aIID, void** aResult) +{ + *aResult = nullptr; + + NS_PRECONDITION(aOuter == nullptr, "no aggregation"); + if (aOuter) + return NS_ERROR_NO_AGGREGATION; + + nsresult rv; + nsXULTreeBuilder* result = new nsXULTreeBuilder(); + NS_ADDREF(result); // stabilize + + rv = result->InitGlobals(); + + if (NS_SUCCEEDED(rv)) + rv = result->QueryInterface(aIID, aResult); + + NS_RELEASE(result); + return rv; +} + +NS_IMPL_ADDREF_INHERITED(nsXULTreeBuilder, nsXULTemplateBuilder) +NS_IMPL_RELEASE_INHERITED(nsXULTreeBuilder, nsXULTemplateBuilder) + +NS_IMPL_CYCLE_COLLECTION_INHERITED(nsXULTreeBuilder, nsXULTemplateBuilder, + mBoxObject, + mSelection, + mPersistStateStore, + mLocalStore, + mObservers) + +NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION_INHERITED(nsXULTreeBuilder) + NS_INTERFACE_MAP_ENTRY(nsIXULTreeBuilder) + NS_INTERFACE_MAP_ENTRY(nsITreeView) + NS_DOM_INTERFACE_MAP_ENTRY_CLASSINFO(XULTreeBuilder) +NS_INTERFACE_MAP_END_INHERITING(nsXULTemplateBuilder) + + +nsXULTreeBuilder::nsXULTreeBuilder() + : mSortDirection(eDirection_Natural), mSortHints(0) +{ +} + +nsXULTreeBuilder::~nsXULTreeBuilder() +{ +} + +void +nsXULTreeBuilder::Uninit(bool aIsFinal) +{ + int32_t count = mRows.Count(); + mRows.Clear(); + + if (mBoxObject) { + mBoxObject->BeginUpdateBatch(); + mBoxObject->RowCountChanged(0, -count); + if (mBoxObject) { + mBoxObject->EndUpdateBatch(); + } + } + + nsXULTemplateBuilder::Uninit(aIsFinal); +} + + +//---------------------------------------------------------------------- +// +// nsIXULTreeBuilder methods +// + +NS_IMETHODIMP +nsXULTreeBuilder::GetResourceAtIndex(int32_t aRowIndex, nsIRDFResource** aResult) +{ + if (aRowIndex < 0 || aRowIndex >= mRows.Count()) + return NS_ERROR_INVALID_ARG; + + return GetResourceFor(aRowIndex, aResult); +} + +NS_IMETHODIMP +nsXULTreeBuilder::GetIndexOfResource(nsIRDFResource* aResource, int32_t* aResult) +{ + NS_ENSURE_ARG_POINTER(aResource); + nsTreeRows::iterator iter = mRows.FindByResource(aResource); + if (iter == mRows.Last()) + *aResult = -1; + else + *aResult = iter.GetRowIndex(); + return NS_OK; +} + +NS_IMETHODIMP +nsXULTreeBuilder::AddObserver(nsIXULTreeBuilderObserver* aObserver) +{ + return mObservers.AppendObject(aObserver) ? NS_OK : NS_ERROR_FAILURE; +} + +NS_IMETHODIMP +nsXULTreeBuilder::RemoveObserver(nsIXULTreeBuilderObserver* aObserver) +{ + return mObservers.RemoveObject(aObserver) ? NS_OK : NS_ERROR_FAILURE; +} + +NS_IMETHODIMP +nsXULTreeBuilder::Sort(nsIDOMElement* aElement) +{ + nsCOMPtr<nsIContent> header = do_QueryInterface(aElement); + if (! header) + return NS_ERROR_FAILURE; + + if (header->AttrValueIs(kNameSpaceID_None, nsGkAtoms::sortLocked, + nsGkAtoms::_true, eCaseMatters)) + return NS_OK; + + nsAutoString sort; + header->GetAttr(kNameSpaceID_None, nsGkAtoms::sort, sort); + + if (sort.IsEmpty()) + return NS_OK; + + // Grab the new sort variable + mSortVariable = NS_Atomize(sort); + + nsAutoString hints; + header->GetAttr(kNameSpaceID_None, nsGkAtoms::sorthints, hints); + + bool hasNaturalState = true; + nsWhitespaceTokenizer tokenizer(hints); + while (tokenizer.hasMoreTokens()) { + const nsDependentSubstring& token(tokenizer.nextToken()); + if (token.EqualsLiteral("comparecase")) + mSortHints |= nsIXULSortService::SORT_COMPARECASE; + else if (token.EqualsLiteral("integer")) + mSortHints |= nsIXULSortService::SORT_INTEGER; + else if (token.EqualsLiteral("twostate")) + hasNaturalState = false; + } + + // Cycle the sort direction + nsAutoString dir; + header->GetAttr(kNameSpaceID_None, nsGkAtoms::sortDirection, dir); + + if (dir.EqualsLiteral("ascending")) { + dir.AssignLiteral("descending"); + mSortDirection = eDirection_Descending; + } + else if (hasNaturalState && dir.EqualsLiteral("descending")) { + dir.AssignLiteral("natural"); + mSortDirection = eDirection_Natural; + } + else { + dir.AssignLiteral("ascending"); + mSortDirection = eDirection_Ascending; + } + + // Sort it. + SortSubtree(mRows.GetRoot()); + mRows.InvalidateCachedRow(); + if (mBoxObject) + mBoxObject->Invalidate(); + + nsTreeUtils::UpdateSortIndicators(header, dir); + + return NS_OK; +} + +//---------------------------------------------------------------------- +// +// nsITreeView methods +// + +NS_IMETHODIMP +nsXULTreeBuilder::GetRowCount(int32_t* aRowCount) +{ + *aRowCount = mRows.Count(); + return NS_OK; +} + +NS_IMETHODIMP +nsXULTreeBuilder::GetSelection(nsITreeSelection** aSelection) +{ + NS_IF_ADDREF(*aSelection = mSelection.get()); + return NS_OK; +} + +NS_IMETHODIMP +nsXULTreeBuilder::SetSelection(nsITreeSelection* aSelection) +{ + NS_ENSURE_TRUE(!aSelection || + nsTreeContentView::CanTrustTreeSelection(aSelection), + NS_ERROR_DOM_SECURITY_ERR); + mSelection = aSelection; + return NS_OK; +} + +NS_IMETHODIMP +nsXULTreeBuilder::GetRowProperties(int32_t aIndex, nsAString& aProps) +{ + NS_PRECONDITION(aIndex >= 0 && aIndex < mRows.Count(), "bad row"); + if (aIndex < 0 || aIndex >= mRows.Count()) + return NS_ERROR_INVALID_ARG; + + nsCOMPtr<nsIContent> row; + GetTemplateActionRowFor(aIndex, getter_AddRefs(row)); + if (row) { + nsAutoString raw; + row->GetAttr(kNameSpaceID_None, nsGkAtoms::properties, raw); + + if (!raw.IsEmpty()) { + SubstituteText(mRows[aIndex]->mMatch->mResult, raw, aProps); + } + } + + return NS_OK; +} + +NS_IMETHODIMP +nsXULTreeBuilder::GetCellProperties(int32_t aRow, nsITreeColumn* aCol, + nsAString& aProps) +{ + NS_ENSURE_ARG_POINTER(aCol); + NS_PRECONDITION(aRow >= 0 && aRow < mRows.Count(), "bad row"); + if (aRow < 0 || aRow >= mRows.Count()) + return NS_ERROR_INVALID_ARG; + + nsCOMPtr<nsIContent> cell; + GetTemplateActionCellFor(aRow, aCol, getter_AddRefs(cell)); + if (cell) { + nsAutoString raw; + cell->GetAttr(kNameSpaceID_None, nsGkAtoms::properties, raw); + + if (!raw.IsEmpty()) { + SubstituteText(mRows[aRow]->mMatch->mResult, raw, aProps); + } + } + + return NS_OK; +} + +NS_IMETHODIMP +nsXULTreeBuilder::GetColumnProperties(nsITreeColumn* aCol, nsAString& aProps) +{ + NS_ENSURE_ARG_POINTER(aCol); + // XXX sortactive fu + return NS_OK; +} + +NS_IMETHODIMP +nsXULTreeBuilder::IsContainer(int32_t aIndex, bool* aResult) +{ + NS_PRECONDITION(aIndex >= 0 && aIndex < mRows.Count(), "bad row"); + if (aIndex < 0 || aIndex >= mRows.Count()) + return NS_ERROR_INVALID_ARG; + + nsTreeRows::iterator iter = mRows[aIndex]; + + bool isContainer; + iter->mMatch->mResult->GetIsContainer(&isContainer); + + iter->mContainerType = isContainer + ? nsTreeRows::eContainerType_Container + : nsTreeRows::eContainerType_Noncontainer; + + *aResult = (iter->mContainerType == nsTreeRows::eContainerType_Container); + return NS_OK; +} + +NS_IMETHODIMP +nsXULTreeBuilder::IsContainerOpen(int32_t aIndex, bool* aOpen) +{ + NS_PRECONDITION(aIndex >= 0 && aIndex < mRows.Count(), "bad row"); + if (aIndex < 0 || aIndex >= mRows.Count()) + return NS_ERROR_INVALID_ARG; + + nsTreeRows::iterator iter = mRows[aIndex]; + + if (iter->mContainerState == nsTreeRows::eContainerState_Unknown) { + bool isOpen = IsContainerOpen(iter->mMatch->mResult); + + iter->mContainerState = isOpen + ? nsTreeRows::eContainerState_Open + : nsTreeRows::eContainerState_Closed; + } + + *aOpen = (iter->mContainerState == nsTreeRows::eContainerState_Open); + return NS_OK; +} + +NS_IMETHODIMP +nsXULTreeBuilder::IsContainerEmpty(int32_t aIndex, bool* aResult) +{ + NS_PRECONDITION(aIndex >= 0 && aIndex < mRows.Count(), "bad row"); + if (aIndex < 0 || aIndex >= mRows.Count()) + return NS_ERROR_INVALID_ARG; + + nsTreeRows::iterator iter = mRows[aIndex]; + NS_ASSERTION(iter->mContainerType == nsTreeRows::eContainerType_Container, + "asking for empty state on non-container"); + + // if recursion is disabled, pretend that the container is empty. This + // ensures that folders are still displayed as such, yet won't display + // their children + if ((mFlags & eDontRecurse) && (iter->mMatch->mResult != mRootResult)) { + *aResult = true; + return NS_OK; + } + + if (iter->mContainerFill == nsTreeRows::eContainerFill_Unknown) { + bool isEmpty; + iter->mMatch->mResult->GetIsEmpty(&isEmpty); + + iter->mContainerFill = isEmpty + ? nsTreeRows::eContainerFill_Empty + : nsTreeRows::eContainerFill_Nonempty; + } + + *aResult = (iter->mContainerFill == nsTreeRows::eContainerFill_Empty); + return NS_OK; +} + +NS_IMETHODIMP +nsXULTreeBuilder::IsSeparator(int32_t aIndex, bool* aResult) +{ + NS_PRECONDITION(aIndex >= 0 && aIndex < mRows.Count(), "bad row"); + if (aIndex < 0 || aIndex >= mRows.Count()) + return NS_ERROR_INVALID_ARG; + + nsAutoString type; + nsTreeRows::Row& row = *(mRows[aIndex]); + row.mMatch->mResult->GetType(type); + + *aResult = type.EqualsLiteral("separator"); + + return NS_OK; +} + +NS_IMETHODIMP +nsXULTreeBuilder::GetParentIndex(int32_t aRowIndex, int32_t* aResult) +{ + NS_PRECONDITION(aRowIndex >= 0 && aRowIndex < mRows.Count(), "bad row"); + if (aRowIndex < 0 || aRowIndex >= mRows.Count()) + return NS_ERROR_INVALID_ARG; + + // Construct a path to the row + nsTreeRows::iterator iter = mRows[aRowIndex]; + + // The parent of the row will be at the top of the path + nsTreeRows::Subtree* parent = iter.GetParent(); + + // Now walk through our previous siblings, subtracting off each + // one's subtree size + int32_t index = iter.GetChildIndex(); + while (--index >= 0) + aRowIndex -= mRows.GetSubtreeSizeFor(parent, index) + 1; + + // Now the parent's index will be the first row's index, less one. + *aResult = aRowIndex - 1; + return NS_OK; +} + +NS_IMETHODIMP +nsXULTreeBuilder::HasNextSibling(int32_t aRowIndex, int32_t aAfterIndex, bool* aResult) +{ + NS_PRECONDITION(aRowIndex >= 0 && aRowIndex < mRows.Count(), "bad row"); + if (aRowIndex < 0 || aRowIndex >= mRows.Count()) + return NS_ERROR_INVALID_ARG; + + // Construct a path to the row + nsTreeRows::iterator iter = mRows[aRowIndex]; + + // The parent of the row will be at the top of the path + nsTreeRows::Subtree* parent = iter.GetParent(); + + // We have a next sibling if the child is not the last in the + // subtree. + *aResult = iter.GetChildIndex() != parent->Count() - 1; + return NS_OK; +} + +NS_IMETHODIMP +nsXULTreeBuilder::GetLevel(int32_t aRowIndex, int32_t* aResult) +{ + NS_PRECONDITION(aRowIndex >= 0 && aRowIndex < mRows.Count(), "bad row"); + if (aRowIndex < 0 || aRowIndex >= mRows.Count()) + return NS_ERROR_INVALID_ARG; + + // Construct a path to the row; the ``level'' is the path length + // less one. + nsTreeRows::iterator iter = mRows[aRowIndex]; + *aResult = iter.GetDepth() - 1; + return NS_OK; +} + +NS_IMETHODIMP +nsXULTreeBuilder::GetImageSrc(int32_t aRow, nsITreeColumn* aCol, nsAString& aResult) +{ + NS_ENSURE_ARG_POINTER(aCol); + NS_PRECONDITION(aRow >= 0 && aRow < mRows.Count(), "bad index"); + if (aRow < 0 || aRow >= mRows.Count()) + return NS_ERROR_INVALID_ARG; + + // Find the <cell> that corresponds to the column we want. + nsCOMPtr<nsIContent> cell; + GetTemplateActionCellFor(aRow, aCol, getter_AddRefs(cell)); + if (cell) { + nsAutoString raw; + cell->GetAttr(kNameSpaceID_None, nsGkAtoms::src, raw); + + SubstituteText(mRows[aRow]->mMatch->mResult, raw, aResult); + } + else + aResult.Truncate(); + + return NS_OK; +} + + +NS_IMETHODIMP +nsXULTreeBuilder::GetProgressMode(int32_t aRow, nsITreeColumn* aCol, int32_t* aResult) +{ + NS_ENSURE_ARG_POINTER(aCol); + NS_PRECONDITION(aRow >= 0 && aRow < mRows.Count(), "bad index"); + if (aRow < 0 || aRow >= mRows.Count()) + return NS_ERROR_INVALID_ARG; + + *aResult = nsITreeView::PROGRESS_NONE; + + // Find the <cell> that corresponds to the column we want. + nsCOMPtr<nsIContent> cell; + GetTemplateActionCellFor(aRow, aCol, getter_AddRefs(cell)); + if (cell) { + nsAutoString raw; + cell->GetAttr(kNameSpaceID_None, nsGkAtoms::mode, raw); + + nsAutoString mode; + SubstituteText(mRows[aRow]->mMatch->mResult, raw, mode); + + if (mode.EqualsLiteral("normal")) + *aResult = nsITreeView::PROGRESS_NORMAL; + else if (mode.EqualsLiteral("undetermined")) + *aResult = nsITreeView::PROGRESS_UNDETERMINED; + } + + return NS_OK; +} + +NS_IMETHODIMP +nsXULTreeBuilder::GetCellValue(int32_t aRow, nsITreeColumn* aCol, nsAString& aResult) +{ + NS_ENSURE_ARG_POINTER(aCol); + NS_PRECONDITION(aRow >= 0 && aRow < mRows.Count(), "bad index"); + if (aRow < 0 || aRow >= mRows.Count()) + return NS_ERROR_INVALID_ARG; + + // Find the <cell> that corresponds to the column we want. + nsCOMPtr<nsIContent> cell; + GetTemplateActionCellFor(aRow, aCol, getter_AddRefs(cell)); + if (cell) { + nsAutoString raw; + cell->GetAttr(kNameSpaceID_None, nsGkAtoms::value, raw); + + SubstituteText(mRows[aRow]->mMatch->mResult, raw, aResult); + } + else + aResult.Truncate(); + + return NS_OK; +} + +NS_IMETHODIMP +nsXULTreeBuilder::GetCellText(int32_t aRow, nsITreeColumn* aCol, nsAString& aResult) +{ + NS_ENSURE_ARG_POINTER(aCol); + NS_PRECONDITION(aRow >= 0 && aRow < mRows.Count(), "bad index"); + if (aRow < 0 || aRow >= mRows.Count()) + return NS_ERROR_INVALID_ARG; + + // Find the <cell> that corresponds to the column we want. + nsCOMPtr<nsIContent> cell; + GetTemplateActionCellFor(aRow, aCol, getter_AddRefs(cell)); + if (cell) { + nsAutoString raw; + cell->GetAttr(kNameSpaceID_None, nsGkAtoms::label, raw); + + SubstituteText(mRows[aRow]->mMatch->mResult, raw, aResult); + + } + else + aResult.Truncate(); + + return NS_OK; +} + +NS_IMETHODIMP +nsXULTreeBuilder::SetTree(nsITreeBoxObject* aTree) +{ + mBoxObject = aTree; + + // If this is teardown time, then we're done. + if (!mBoxObject) { + Uninit(false); + return NS_OK; + } + NS_ENSURE_TRUE(mRoot, NS_ERROR_NOT_INITIALIZED); + + // Only use the XUL store if the root's principal is trusted. + bool isTrusted = false; + nsresult rv = IsSystemPrincipal(mRoot->NodePrincipal(), &isTrusted); + if (NS_SUCCEEDED(rv) && isTrusted) { + mLocalStore = do_GetService("@mozilla.org/xul/xulstore;1"); + if(NS_WARN_IF(!mLocalStore)){ + return NS_ERROR_NOT_INITIALIZED; + } + } + + Rebuild(); + + EnsureSortVariables(); + if (mSortVariable) + SortSubtree(mRows.GetRoot()); + + return NS_OK; +} + +NS_IMETHODIMP +nsXULTreeBuilder::ToggleOpenState(int32_t aIndex) +{ + if (aIndex < 0 || aIndex >= mRows.Count()) + return NS_ERROR_INVALID_ARG; + + nsIXULTemplateResult* result = mRows[aIndex]->mMatch->mResult; + if (! result) + return NS_ERROR_FAILURE; + + if (mFlags & eDontRecurse) + return NS_OK; + + if (result && result != mRootResult) { + // don't open containers if child processing isn't allowed + bool mayProcessChildren; + nsresult rv = result->GetMayProcessChildren(&mayProcessChildren); + if (NS_FAILED(rv) || !mayProcessChildren) + return rv; + } + + uint32_t count = mObservers.Count(); + for (uint32_t i = 0; i < count; ++i) { + nsCOMPtr<nsIXULTreeBuilderObserver> observer = mObservers.SafeObjectAt(i); + if (observer) + observer->OnToggleOpenState(aIndex); + } + + if (mLocalStore && mRoot) { + bool isOpen; + IsContainerOpen(aIndex, &isOpen); + + nsIDocument* doc = mRoot->GetComposedDoc(); + if (!doc) { + return NS_ERROR_FAILURE; + } + + nsIURI* docURI = doc->GetDocumentURI(); + nsTreeRows::Row& row = *(mRows[aIndex]); + nsAutoString nodeid; + nsresult rv = row.mMatch->mResult->GetId(nodeid); + if (NS_FAILED(rv)) { + return rv; + } + + nsAutoCString utf8uri; + rv = docURI->GetSpec(utf8uri); + if (NS_WARN_IF(NS_FAILED(rv))) { + return rv; + } + NS_ConvertUTF8toUTF16 uri(utf8uri); + + if (isOpen) { + mLocalStore->RemoveValue(uri, nodeid, NS_LITERAL_STRING("open")); + CloseContainer(aIndex); + } else { + mLocalStore->SetValue(uri, nodeid, NS_LITERAL_STRING("open"), + NS_LITERAL_STRING("true")); + + OpenContainer(aIndex, result); + } + } + + return NS_OK; +} + +NS_IMETHODIMP +nsXULTreeBuilder::CycleHeader(nsITreeColumn* aCol) +{ + NS_ENSURE_ARG_POINTER(aCol); + nsCOMPtr<nsIDOMElement> element; + aCol->GetElement(getter_AddRefs(element)); + + nsAutoString id; + aCol->GetId(id); + + uint32_t count = mObservers.Count(); + for (uint32_t i = 0; i < count; ++i) { + nsCOMPtr<nsIXULTreeBuilderObserver> observer = mObservers.SafeObjectAt(i); + if (observer) + observer->OnCycleHeader(id.get(), element); + } + + return Sort(element); +} + +NS_IMETHODIMP +nsXULTreeBuilder::SelectionChanged() +{ + uint32_t count = mObservers.Count(); + for (uint32_t i = 0; i < count; ++i) { + nsCOMPtr<nsIXULTreeBuilderObserver> observer = mObservers.SafeObjectAt(i); + if (observer) + observer->OnSelectionChanged(); + } + + return NS_OK; +} + +NS_IMETHODIMP +nsXULTreeBuilder::CycleCell(int32_t aRow, nsITreeColumn* aCol) +{ + NS_ENSURE_ARG_POINTER(aCol); + + nsAutoString id; + aCol->GetId(id); + + uint32_t count = mObservers.Count(); + for (uint32_t i = 0; i < count; ++i) { + nsCOMPtr<nsIXULTreeBuilderObserver> observer = mObservers.SafeObjectAt(i); + if (observer) + observer->OnCycleCell(aRow, id.get()); + } + + return NS_OK; +} + +NS_IMETHODIMP +nsXULTreeBuilder::IsEditable(int32_t aRow, nsITreeColumn* aCol, bool* _retval) +{ + *_retval = true; + NS_ENSURE_ARG_POINTER(aCol); + NS_PRECONDITION(aRow >= 0 && aRow < mRows.Count(), "bad index"); + if (aRow < 0 || aRow >= mRows.Count()) + return NS_ERROR_INVALID_ARG; + + // Find the <cell> that corresponds to the column we want. + nsCOMPtr<nsIContent> cell; + GetTemplateActionCellFor(aRow, aCol, getter_AddRefs(cell)); + if (cell) { + nsAutoString raw; + cell->GetAttr(kNameSpaceID_None, nsGkAtoms::editable, raw); + + nsAutoString editable; + SubstituteText(mRows[aRow]->mMatch->mResult, raw, editable); + + if (editable.EqualsLiteral("false")) + *_retval = false; + } + + return NS_OK; +} + +NS_IMETHODIMP +nsXULTreeBuilder::IsSelectable(int32_t aRow, nsITreeColumn* aCol, bool* _retval) +{ + NS_PRECONDITION(aRow >= 0 && aRow < mRows.Count(), "bad index"); + if (aRow < 0 || aRow >= mRows.Count()) + return NS_ERROR_INVALID_ARG; + + *_retval = true; + + // Find the <cell> that corresponds to the column we want. + nsCOMPtr<nsIContent> cell; + GetTemplateActionCellFor(aRow, aCol, getter_AddRefs(cell)); + if (cell) { + nsAutoString raw; + cell->GetAttr(kNameSpaceID_None, nsGkAtoms::selectable, raw); + + nsAutoString selectable; + SubstituteText(mRows[aRow]->mMatch->mResult, raw, selectable); + + if (selectable.EqualsLiteral("false")) + *_retval = false; + } + + return NS_OK; +} + +NS_IMETHODIMP +nsXULTreeBuilder::SetCellValue(int32_t aRow, nsITreeColumn* aCol, const nsAString& aValue) +{ + NS_ENSURE_ARG_POINTER(aCol); + return NS_OK; +} + +NS_IMETHODIMP +nsXULTreeBuilder::SetCellText(int32_t aRow, nsITreeColumn* aCol, const nsAString& aValue) +{ + NS_ENSURE_ARG_POINTER(aCol); + return NS_OK; +} + +NS_IMETHODIMP +nsXULTreeBuilder::PerformAction(const char16_t* aAction) +{ + uint32_t count = mObservers.Count(); + for (uint32_t i = 0; i < count; ++i) { + nsCOMPtr<nsIXULTreeBuilderObserver> observer = mObservers.SafeObjectAt(i); + if (observer) + observer->OnPerformAction(aAction); + } + + return NS_OK; +} + +NS_IMETHODIMP +nsXULTreeBuilder::PerformActionOnRow(const char16_t* aAction, int32_t aRow) +{ + uint32_t count = mObservers.Count(); + for (uint32_t i = 0; i < count; ++i) { + nsCOMPtr<nsIXULTreeBuilderObserver> observer = mObservers.SafeObjectAt(i); + if (observer) + observer->OnPerformActionOnRow(aAction, aRow); + } + + return NS_OK; +} + +NS_IMETHODIMP +nsXULTreeBuilder::PerformActionOnCell(const char16_t* aAction, int32_t aRow, nsITreeColumn* aCol) +{ + NS_ENSURE_ARG_POINTER(aCol); + nsAutoString id; + aCol->GetId(id); + + uint32_t count = mObservers.Count(); + for (uint32_t i = 0; i < count; ++i) { + nsCOMPtr<nsIXULTreeBuilderObserver> observer = mObservers.SafeObjectAt(i); + if (observer) + observer->OnPerformActionOnCell(aAction, aRow, id.get()); + } + + return NS_OK; +} + + +void +nsXULTreeBuilder::NodeWillBeDestroyed(const nsINode* aNode) +{ + nsCOMPtr<nsIMutationObserver> kungFuDeathGrip(this); + mObservers.Clear(); + + nsXULTemplateBuilder::NodeWillBeDestroyed(aNode); +} + +NS_IMETHODIMP +nsXULTreeBuilder::HasGeneratedContent(nsIRDFResource* aResource, + nsIAtom* aTag, + bool* aGenerated) +{ + *aGenerated = false; + NS_ENSURE_ARG_POINTER(aResource); + + if (!mRootResult) + return NS_OK; + + nsCOMPtr<nsIRDFResource> rootresource; + nsresult rv = mRootResult->GetResource(getter_AddRefs(rootresource)); + if (NS_FAILED(rv)) + return rv; + + if (aResource == rootresource || + mRows.FindByResource(aResource) != mRows.Last()) + *aGenerated = true; + + return NS_OK; +} + +bool +nsXULTreeBuilder::GetInsertionLocations(nsIXULTemplateResult* aResult, + nsCOMArray<nsIContent>** aLocations) +{ + *aLocations = nullptr; + + // Get the reference point and check if it is an open container. Rows + // should not be generated otherwise. + + nsAutoString ref; + nsresult rv = aResult->GetBindingFor(mRefVariable, ref); + if (NS_FAILED(rv) || ref.IsEmpty()) + return false; + + nsCOMPtr<nsIRDFResource> container; + rv = gRDFService->GetUnicodeResource(ref, getter_AddRefs(container)); + if (NS_FAILED(rv)) + return false; + + // Can always insert into the root resource + if (container == mRows.GetRootResource()) + return true; + + nsTreeRows::iterator iter = mRows.FindByResource(container); + if (iter == mRows.Last()) + return false; + + return (iter->mContainerState == nsTreeRows::eContainerState_Open); +} + +struct ResultComparator +{ + nsXULTreeBuilder* const mTreebuilder; + nsIXULTemplateResult* const mResult; + ResultComparator(nsXULTreeBuilder* aTreebuilder, nsIXULTemplateResult* aResult) + : mTreebuilder(aTreebuilder), mResult(aResult) {} + int operator()(const nsTreeRows::Row& aSubtree) const { + return mTreebuilder->CompareResults(mResult, aSubtree.mMatch->mResult); + } +}; + +nsresult +nsXULTreeBuilder::ReplaceMatch(nsIXULTemplateResult* aOldResult, + nsTemplateMatch* aNewMatch, + nsTemplateRule* aNewMatchRule, + void *aLocation) +{ + if (! mBoxObject) + return NS_OK; + + if (aOldResult) { + // Grovel through the rows looking for oldresult. + nsTreeRows::iterator iter = mRows.Find(aOldResult); + + NS_ASSERTION(iter != mRows.Last(), "couldn't find row"); + if (iter == mRows.Last()) + return NS_ERROR_FAILURE; + + // Remove the rows from the view + int32_t row = iter.GetRowIndex(); + + // If the row contains children, remove the matches from the + // children so that they can be regenerated again if the element + // gets added back. + int32_t delta = mRows.GetSubtreeSizeFor(iter); + if (delta) + RemoveMatchesFor(*(iter->mSubtree)); + + if (mRows.RemoveRowAt(iter) == 0 && iter.GetRowIndex() >= 0) { + + // In this case iter now points to its parent + // Invalidate the row's cached fill state + iter->mContainerFill = nsTreeRows::eContainerFill_Unknown; + + nsCOMPtr<nsITreeColumns> cols; + mBoxObject->GetColumns(getter_AddRefs(cols)); + if (cols) { + nsCOMPtr<nsITreeColumn> primaryCol; + cols->GetPrimaryColumn(getter_AddRefs(primaryCol)); + if (primaryCol) + mBoxObject->InvalidateCell(iter.GetRowIndex(), primaryCol); + } + } + + // Notify the box object + mBoxObject->RowCountChanged(row, -delta - 1); + } + + if (aNewMatch && aNewMatch->mResult) { + // Insertion. + int32_t row = -1; + nsTreeRows::Subtree* parent = nullptr; + nsIXULTemplateResult* result = aNewMatch->mResult; + + nsAutoString ref; + nsresult rv = result->GetBindingFor(mRefVariable, ref); + if (NS_FAILED(rv) || ref.IsEmpty()) + return rv; + + nsCOMPtr<nsIRDFResource> container; + rv = gRDFService->GetUnicodeResource(ref, getter_AddRefs(container)); + if (NS_FAILED(rv)) + return rv; + + if (container != mRows.GetRootResource()) { + nsTreeRows::iterator iter = mRows.FindByResource(container); + row = iter.GetRowIndex(); + + NS_ASSERTION(iter != mRows.Last(), "couldn't find container row"); + if (iter == mRows.Last()) + return NS_ERROR_FAILURE; + + // Use the persist store to remember if the container + // is open or closed. + bool open = false; + IsContainerOpen(row, &open); + + // If it's open, make sure that we've got a subtree structure ready. + if (open) + parent = mRows.EnsureSubtreeFor(iter); + + // We know something has just been inserted into the + // container, so whether its open or closed, make sure + // that we've got our tree row's state correct. + if ((iter->mContainerType != nsTreeRows::eContainerType_Container) || + (iter->mContainerFill != nsTreeRows::eContainerFill_Nonempty)) { + iter->mContainerType = nsTreeRows::eContainerType_Container; + iter->mContainerFill = nsTreeRows::eContainerFill_Nonempty; + mBoxObject->InvalidateRow(iter.GetRowIndex()); + } + } + else { + parent = mRows.GetRoot(); + } + + if (parent) { + // If we get here, then we're inserting into an open + // container. By default, place the new element at the + // end of the container + size_t index = parent->Count(); + + if (mSortVariable) { + // Figure out where to put the new element through + // binary search. + mozilla::BinarySearchIf(*parent, 0, parent->Count(), + ResultComparator(this, result), &index); + } + + nsTreeRows::iterator iter = + mRows.InsertRowAt(aNewMatch, parent, index); + + mBoxObject->RowCountChanged(iter.GetRowIndex(), +1); + + // See if this newly added row is open; in which case, + // recursively add its children to the tree, too. + + if (mFlags & eDontRecurse) + return NS_OK; + + if (result != mRootResult) { + // don't open containers if child processing isn't allowed + bool mayProcessChildren; + nsresult rv = result->GetMayProcessChildren(&mayProcessChildren); + if (NS_FAILED(rv) || ! mayProcessChildren) return NS_OK; + } + + if (IsContainerOpen(result)) { + OpenContainer(iter.GetRowIndex(), result); + } + } + } + + return NS_OK; +} + +nsresult +nsXULTreeBuilder::SynchronizeResult(nsIXULTemplateResult* aResult) +{ + if (mBoxObject) { + // XXX we could be more conservative and just invalidate the cells + // that got whacked... + + nsTreeRows::iterator iter = mRows.Find(aResult); + + NS_ASSERTION(iter != mRows.Last(), "couldn't find row"); + if (iter == mRows.Last()) + return NS_ERROR_FAILURE; + + int32_t row = iter.GetRowIndex(); + if (row >= 0) + mBoxObject->InvalidateRow(row); + + MOZ_LOG(gXULTemplateLog, LogLevel::Debug, + ("xultemplate[%p] => row %d", this, row)); + } + + return NS_OK; +} + +//---------------------------------------------------------------------- + +nsresult +nsXULTreeBuilder::EnsureSortVariables() +{ + // Grovel through <treecols> kids to find the <treecol> + // with the sort attributes. + nsCOMPtr<nsIContent> treecols; + + nsXULContentUtils::FindChildByTag(mRoot, kNameSpaceID_XUL, + nsGkAtoms::treecols, + getter_AddRefs(treecols)); + + if (!treecols) + return NS_OK; + + for (nsIContent* child = treecols->GetFirstChild(); + child; + child = child->GetNextSibling()) { + + if (child->NodeInfo()->Equals(nsGkAtoms::treecol, + kNameSpaceID_XUL)) { + if (child->AttrValueIs(kNameSpaceID_None, nsGkAtoms::sortActive, + nsGkAtoms::_true, eCaseMatters)) { + nsAutoString sort; + child->GetAttr(kNameSpaceID_None, nsGkAtoms::sort, sort); + if (! sort.IsEmpty()) { + mSortVariable = NS_Atomize(sort); + + static nsIContent::AttrValuesArray strings[] = + {&nsGkAtoms::ascending, &nsGkAtoms::descending, nullptr}; + switch (child->FindAttrValueIn(kNameSpaceID_None, + nsGkAtoms::sortDirection, + strings, eCaseMatters)) { + case 0: mSortDirection = eDirection_Ascending; break; + case 1: mSortDirection = eDirection_Descending; break; + default: mSortDirection = eDirection_Natural; break; + } + } + break; + } + } + } + + return NS_OK; +} + +nsresult +nsXULTreeBuilder::RebuildAll() +{ + NS_ENSURE_TRUE(mRoot, NS_ERROR_NOT_INITIALIZED); + + nsCOMPtr<nsIDocument> doc = mRoot->GetComposedDoc(); + + // Bail out early if we are being torn down. + if (!doc) + return NS_OK; + + if (! mQueryProcessor) + return NS_OK; + + if (mBoxObject) { + mBoxObject->BeginUpdateBatch(); + } + + if (mQueriesCompiled) { + Uninit(false); + } + else if (mBoxObject) { + int32_t count = mRows.Count(); + mRows.Clear(); + mBoxObject->RowCountChanged(0, -count); + } + + nsresult rv = CompileQueries(); + if (NS_SUCCEEDED(rv) && mQuerySets.Length() > 0) { + // Seed the rule network with assignments for the tree row variable + nsAutoString ref; + mRoot->GetAttr(kNameSpaceID_None, nsGkAtoms::ref, ref); + if (!ref.IsEmpty()) { + rv = mQueryProcessor->TranslateRef(mDataSource, ref, + getter_AddRefs(mRootResult)); + if (NS_SUCCEEDED(rv) && mRootResult) { + OpenContainer(-1, mRootResult); + + nsCOMPtr<nsIRDFResource> rootResource; + GetResultResource(mRootResult, getter_AddRefs(rootResource)); + + mRows.SetRootResource(rootResource); + } + } + } + + if (mBoxObject) { + mBoxObject->EndUpdateBatch(); + } + + return rv; +} + +nsresult +nsXULTreeBuilder::GetTemplateActionRowFor(int32_t aRow, nsIContent** aResult) +{ + // Get the template in the DOM from which we're supposed to + // generate text + nsTreeRows::Row& row = *(mRows[aRow]); + + // The match stores the indices of the rule and query to use. Use these + // to look up the right nsTemplateRule and use that rule's action to get + // the treerow in the template. + int16_t ruleindex = row.mMatch->RuleIndex(); + if (ruleindex >= 0) { + nsTemplateQuerySet* qs = mQuerySets[row.mMatch->QuerySetPriority()]; + nsTemplateRule* rule = qs->GetRuleAt(ruleindex); + if (rule) { + nsCOMPtr<nsIContent> children; + nsXULContentUtils::FindChildByTag(rule->GetAction(), kNameSpaceID_XUL, + nsGkAtoms::treechildren, + getter_AddRefs(children)); + if (children) { + nsCOMPtr<nsIContent> item; + nsXULContentUtils::FindChildByTag(children, kNameSpaceID_XUL, + nsGkAtoms::treeitem, + getter_AddRefs(item)); + if (item) + return nsXULContentUtils::FindChildByTag(item, + kNameSpaceID_XUL, + nsGkAtoms::treerow, + aResult); + } + } + } + + *aResult = nullptr; + return NS_OK; +} + +nsresult +nsXULTreeBuilder::GetTemplateActionCellFor(int32_t aRow, + nsITreeColumn* aCol, + nsIContent** aResult) +{ + *aResult = nullptr; + + if (!aCol) return NS_ERROR_INVALID_ARG; + + nsCOMPtr<nsIContent> row; + GetTemplateActionRowFor(aRow, getter_AddRefs(row)); + if (row) { + nsCOMPtr<nsIAtom> colAtom; + int32_t colIndex; + aCol->GetAtom(getter_AddRefs(colAtom)); + aCol->GetIndex(&colIndex); + + uint32_t j = 0; + for (nsIContent* child = row->GetFirstChild(); + child; + child = child->GetNextSibling()) { + + if (child->NodeInfo()->Equals(nsGkAtoms::treecell, + kNameSpaceID_XUL)) { + if (colAtom && + child->AttrValueIs(kNameSpaceID_None, nsGkAtoms::ref, + colAtom, eCaseMatters)) { + *aResult = child; + break; + } + else if (j == (uint32_t)colIndex) + *aResult = child; + j++; + } + } + } + NS_IF_ADDREF(*aResult); + + return NS_OK; +} + +nsresult +nsXULTreeBuilder::GetResourceFor(int32_t aRow, nsIRDFResource** aResource) +{ + nsTreeRows::Row& row = *(mRows[aRow]); + return GetResultResource(row.mMatch->mResult, aResource); +} + +nsresult +nsXULTreeBuilder::OpenContainer(int32_t aIndex, nsIXULTemplateResult* aResult) +{ + // A row index of -1 in this case means ``open tree body'' + NS_ASSERTION(aIndex >= -1 && aIndex < mRows.Count(), "bad row"); + if (aIndex < -1 || aIndex >= mRows.Count()) + return NS_ERROR_INVALID_ARG; + + nsTreeRows::Subtree* container; + + if (aIndex >= 0) { + nsTreeRows::iterator iter = mRows[aIndex]; + container = mRows.EnsureSubtreeFor(iter.GetParent(), + iter.GetChildIndex()); + + iter->mContainerState = nsTreeRows::eContainerState_Open; + } + else + container = mRows.GetRoot(); + + if (! container) + return NS_ERROR_OUT_OF_MEMORY; + + int32_t count; + OpenSubtreeOf(container, aIndex, aResult, &count); + + // Notify the box object + if (mBoxObject) { + if (aIndex >= 0) + mBoxObject->InvalidateRow(aIndex); + + if (count) + mBoxObject->RowCountChanged(aIndex + 1, count); + } + + return NS_OK; +} + +nsresult +nsXULTreeBuilder::OpenSubtreeOf(nsTreeRows::Subtree* aSubtree, + int32_t aIndex, + nsIXULTemplateResult *aResult, + int32_t* aDelta) +{ + AutoTArray<int32_t, 8> open; + int32_t count = 0; + + int32_t rulecount = mQuerySets.Length(); + + for (int32_t r = 0; r < rulecount; r++) { + nsTemplateQuerySet* queryset = mQuerySets[r]; + OpenSubtreeForQuerySet(aSubtree, aIndex, aResult, queryset, &count, open); + } + + // Now recursively deal with any open sub-containers that just got + // inserted. We need to do this back-to-front to avoid skewing offsets. + for (int32_t i = open.Length() - 1; i >= 0; --i) { + int32_t index = open[i]; + + nsTreeRows::Subtree* child = + mRows.EnsureSubtreeFor(aSubtree, index); + + nsIXULTemplateResult* result = (*aSubtree)[index].mMatch->mResult; + + int32_t delta; + OpenSubtreeOf(child, aIndex + index, result, &delta); + count += delta; + } + + // Sort the container. + if (mSortVariable) { + NS_QuickSort(mRows.GetRowsFor(aSubtree), + aSubtree->Count(), + sizeof(nsTreeRows::Row), + Compare, + this); + } + + *aDelta = count; + return NS_OK; +} + +nsresult +nsXULTreeBuilder::OpenSubtreeForQuerySet(nsTreeRows::Subtree* aSubtree, + int32_t aIndex, + nsIXULTemplateResult* aResult, + nsTemplateQuerySet* aQuerySet, + int32_t* aDelta, + nsTArray<int32_t>& open) +{ + int32_t count = *aDelta; + + nsCOMPtr<nsISimpleEnumerator> results; + nsresult rv = mQueryProcessor->GenerateResults(mDataSource, aResult, + aQuerySet->mCompiledQuery, + getter_AddRefs(results)); + if (NS_FAILED(rv)) + return rv; + + bool hasMoreResults; + rv = results->HasMoreElements(&hasMoreResults); + + for (; NS_SUCCEEDED(rv) && hasMoreResults; + rv = results->HasMoreElements(&hasMoreResults)) { + nsCOMPtr<nsISupports> nr; + rv = results->GetNext(getter_AddRefs(nr)); + if (NS_FAILED(rv)) + return rv; + + nsCOMPtr<nsIXULTemplateResult> nextresult = do_QueryInterface(nr); + if (!nextresult) + return NS_ERROR_UNEXPECTED; + + nsCOMPtr<nsIRDFResource> resultid; + rv = GetResultResource(nextresult, getter_AddRefs(resultid)); + if (NS_FAILED(rv)) + return rv; + + if (! resultid) + continue; + + // check if there is already an existing match. If so, a previous + // query already generated content so the match is just added to the + // end of the set of matches. + + bool generateContent = true; + + nsTemplateMatch* prevmatch = nullptr; + nsTemplateMatch* existingmatch = nullptr; + if (mMatchMap.Get(resultid, &existingmatch)){ + // check if there is an existing match that matched a rule + while (existingmatch) { + if (existingmatch->IsActive()) + generateContent = false; + prevmatch = existingmatch; + existingmatch = existingmatch->mNext; + } + } + + nsTemplateMatch *newmatch = + nsTemplateMatch::Create(aQuerySet->Priority(), nextresult, nullptr); + if (!newmatch) + return NS_ERROR_OUT_OF_MEMORY; + + if (generateContent) { + // Don't allow cyclic graphs to get our knickers in a knot. + bool cyclic = false; + + if (aIndex >= 0) { + for (nsTreeRows::iterator iter = mRows[aIndex]; iter.GetDepth() > 0; iter.Pop()) { + nsCOMPtr<nsIRDFResource> parentid; + rv = GetResultResource(iter->mMatch->mResult, getter_AddRefs(parentid)); + if (NS_FAILED(rv)) { + nsTemplateMatch::Destroy(newmatch, false); + return rv; + } + + if (resultid == parentid) { + cyclic = true; + break; + } + } + } + + if (cyclic) { + NS_WARNING("tree cannot handle cyclic graphs"); + nsTemplateMatch::Destroy(newmatch, false); + continue; + } + + int16_t ruleindex; + nsTemplateRule* matchedrule = nullptr; + rv = DetermineMatchedRule(nullptr, nextresult, aQuerySet, + &matchedrule, &ruleindex); + if (NS_FAILED(rv)) { + nsTemplateMatch::Destroy(newmatch, false); + return rv; + } + + if (matchedrule) { + rv = newmatch->RuleMatched(aQuerySet, matchedrule, ruleindex, + nextresult); + if (NS_FAILED(rv)) { + nsTemplateMatch::Destroy(newmatch, false); + return rv; + } + + // Remember that this match applied to this row + mRows.InsertRowAt(newmatch, aSubtree, count); + + // If this is open, then remember it so we can recursively add + // *its* rows to the tree. + if (IsContainerOpen(nextresult)) { + if (open.AppendElement(count) == nullptr) + return NS_ERROR_OUT_OF_MEMORY; + } + + ++count; + } + + if (mFlags & eLoggingEnabled) + OutputMatchToLog(resultid, newmatch, true); + + } + + if (prevmatch) { + prevmatch->mNext = newmatch; + } + else { + mMatchMap.Put(resultid, newmatch); + } + } + + *aDelta = count; + return rv; +} + +nsresult +nsXULTreeBuilder::CloseContainer(int32_t aIndex) +{ + NS_ASSERTION(aIndex >= 0 && aIndex < mRows.Count(), "bad row"); + if (aIndex < 0 || aIndex >= mRows.Count()) + return NS_ERROR_INVALID_ARG; + + nsTreeRows::iterator iter = mRows[aIndex]; + + if (iter->mSubtree) + RemoveMatchesFor(*iter->mSubtree); + + + int32_t count = mRows.GetSubtreeSizeFor(iter); + mRows.RemoveSubtreeFor(iter); + + iter->mContainerState = nsTreeRows::eContainerState_Closed; + + if (mBoxObject) { + mBoxObject->InvalidateRow(aIndex); + + if (count) + mBoxObject->RowCountChanged(aIndex + 1, -count); + } + + return NS_OK; +} + +nsresult +nsXULTreeBuilder::RemoveMatchesFor(nsTreeRows::Subtree& subtree) +{ + for (int32_t i = subtree.Count() - 1; i >= 0; --i) { + nsTreeRows::Row& row = subtree[i]; + + nsTemplateMatch* match = row.mMatch; + + nsCOMPtr<nsIRDFResource> id; + nsresult rv = GetResultResource(match->mResult, getter_AddRefs(id)); + if (NS_FAILED(rv)) + return rv; + + nsTemplateMatch* existingmatch; + if (mMatchMap.Get(id, &existingmatch)) { + while (existingmatch) { + nsTemplateMatch* nextmatch = existingmatch->mNext; + nsTemplateMatch::Destroy(existingmatch, true); + existingmatch = nextmatch; + } + + mMatchMap.Remove(id); + } + + if ((row.mContainerState == nsTreeRows::eContainerState_Open) && row.mSubtree) + RemoveMatchesFor(*(row.mSubtree)); + } + + return NS_OK; +} + + +bool +nsXULTreeBuilder::IsContainerOpen(nsIXULTemplateResult *aResult) +{ + // items are never open if recursion is disabled + if ((mFlags & eDontRecurse) && aResult != mRootResult) { + return false; + } + + if (!mLocalStore) { + return false; + } + + nsIDocument* doc = mRoot->GetComposedDoc(); + if (!doc) { + return false; + } + + nsIURI* docURI = doc->GetDocumentURI(); + + nsAutoString nodeid; + nsresult rv = aResult->GetId(nodeid); + if (NS_FAILED(rv)) { + return false; + } + + nsAutoCString utf8uri; + rv = docURI->GetSpec(utf8uri); + if (NS_WARN_IF(NS_FAILED(rv))) { + return false; + } + NS_ConvertUTF8toUTF16 uri(utf8uri); + + nsAutoString val; + mLocalStore->GetValue(uri, nodeid, NS_LITERAL_STRING("open"), val); + return val.EqualsLiteral("true"); +} + +int +nsXULTreeBuilder::Compare(const void* aLeft, const void* aRight, void* aClosure) +{ + nsXULTreeBuilder* self = static_cast<nsXULTreeBuilder*>(aClosure); + + nsTreeRows::Row* left = static_cast<nsTreeRows::Row*> + (const_cast<void*>(aLeft)); + + nsTreeRows::Row* right = static_cast<nsTreeRows::Row*> + (const_cast<void*>(aRight)); + + return self->CompareResults(left->mMatch->mResult, right->mMatch->mResult); +} + +int32_t +nsXULTreeBuilder::CompareResults(nsIXULTemplateResult* aLeft, nsIXULTemplateResult* aRight) +{ + // this is an extra check done for RDF queries such that results appear in + // the order they appear in their containing Seq + if (mSortDirection == eDirection_Natural && mDB) { + // If the sort order is ``natural'', then see if the container + // is an RDF sequence. If so, we'll try to use the ordinal + // properties to determine order. + // + // XXX the problem with this is, it doesn't always get the + // *real* container; e.g., + // + // <treerow uri="?uri" /> + // + // <triple subject="?uri" + // predicate="http://home.netscape.com/NC-rdf#subheadings" + // object="?subheadings" /> + // + // <member container="?subheadings" child="?subheading" /> + // + // In this case mRefVariable is bound to ?uri, not + // ?subheadings. (The ``container'' in the template sense != + // container in the RDF sense.) + + nsCOMPtr<nsISupports> ref; + nsresult rv = aLeft->GetBindingObjectFor(mRefVariable, getter_AddRefs(ref)); + if (NS_FAILED(rv)) + return 0; + + nsCOMPtr<nsIRDFResource> container = do_QueryInterface(ref); + if (container) { + bool isSequence = false; + gRDFContainerUtils->IsSeq(mDB, container, &isSequence); + if (isSequence) { + // Determine the indices of the left and right elements + // in the container. + int32_t lindex = 0, rindex = 0; + + nsCOMPtr<nsIRDFResource> leftitem; + aLeft->GetResource(getter_AddRefs(leftitem)); + if (leftitem) { + gRDFContainerUtils->IndexOf(mDB, container, leftitem, &lindex); + if (lindex < 0) + return 0; + } + + nsCOMPtr<nsIRDFResource> rightitem; + aRight->GetResource(getter_AddRefs(rightitem)); + if (rightitem) { + gRDFContainerUtils->IndexOf(mDB, container, rightitem, &rindex); + if (rindex < 0) + return 0; + } + + return lindex - rindex; + } + } + } + + int32_t sortorder; + if (!mQueryProcessor) + return 0; + + mQueryProcessor->CompareResults(aLeft, aRight, mSortVariable, mSortHints, &sortorder); + + if (sortorder) + sortorder = sortorder * mSortDirection; + return sortorder; +} + +nsresult +nsXULTreeBuilder::SortSubtree(nsTreeRows::Subtree* aSubtree) +{ + NS_QuickSort(mRows.GetRowsFor(aSubtree), + aSubtree->Count(), + sizeof(nsTreeRows::Row), + Compare, + this); + + for (int32_t i = aSubtree->Count() - 1; i >= 0; --i) { + nsTreeRows::Subtree* child = (*aSubtree)[i].mSubtree; + if (child) + SortSubtree(child); + } + + return NS_OK; +} + + +NS_IMETHODIMP +nsXULTreeBuilder::CanDrop(int32_t index, int32_t orientation, + nsIDOMDataTransfer* dataTransfer, bool *_retval) +{ + *_retval = false; + uint32_t count = mObservers.Count(); + for (uint32_t i = 0; i < count; ++i) { + nsCOMPtr<nsIXULTreeBuilderObserver> observer = mObservers.SafeObjectAt(i); + if (observer) { + observer->CanDrop(index, orientation, dataTransfer, _retval); + if (*_retval) + break; + } + } + + return NS_OK; +} + +NS_IMETHODIMP +nsXULTreeBuilder::Drop(int32_t row, int32_t orient, nsIDOMDataTransfer* dataTransfer) +{ + uint32_t count = mObservers.Count(); + for (uint32_t i = 0; i < count; ++i) { + nsCOMPtr<nsIXULTreeBuilderObserver> observer = mObservers.SafeObjectAt(i); + if (observer) { + bool canDrop = false; + observer->CanDrop(row, orient, dataTransfer, &canDrop); + if (canDrop) + observer->OnDrop(row, orient, dataTransfer); + } + } + + return NS_OK; +} + +NS_IMETHODIMP +nsXULTreeBuilder::IsSorted(bool *_retval) +{ + *_retval = (mSortVariable != nullptr); + return NS_OK; +} + diff --git a/dom/xul/templates/tests/chrome/animals.rdf b/dom/xul/templates/tests/chrome/animals.rdf new file mode 100644 index 000000000..06fee7ac5 --- /dev/null +++ b/dom/xul/templates/tests/chrome/animals.rdf @@ -0,0 +1,224 @@ +<?xml version="1.0"?> + +<RDF:RDF xmlns:RDF="http://www.w3.org/1999/02/22-rdf-syntax-ns#" + xmlns:NC="http://home.netscape.com/NC-rdf#" + xmlns:ANIMALS="http://www.some-fictitious-zoo.com/rdf#"> + + <ANIMALS:Class RDF:about="http://www.some-fictitious-zoo.com/arachnids"> + <ANIMALS:name>Arachnids</ANIMALS:name> + </ANIMALS:Class> + + <RDF:Description RDF:about="http://www.some-fictitious-zoo.com/arachnids/tarantula" ANIMALS:specimens="3"> + <ANIMALS:name>Tarantula</ANIMALS:name> + <ANIMALS:species>Avicularia avicularia</ANIMALS:species> + </RDF:Description> + + <ANIMALS:Class RDF:about="http://www.some-fictitious-zoo.com/birds"> + <ANIMALS:name>Birds</ANIMALS:name> + <ANIMALS:keeper resource="http://www.some-fictitious-zoo.com/humans/sarah"/> + </ANIMALS:Class> + + <RDF:Description RDF:about="http://www.some-fictitious-zoo.com/birds/emu" ANIMALS:specimens="12"> + <ANIMALS:name>Emu</ANIMALS:name> + <ANIMALS:species>Dromaius novaehollandiae</ANIMALS:species> + </RDF:Description> + + <RDF:Description RDF:about="http://www.some-fictitious-zoo.com/birds/barnowl" ANIMALS:specimens="4"> + <ANIMALS:name>Barn Owl</ANIMALS:name> + <ANIMALS:species>Tyto alba</ANIMALS:species> + </RDF:Description> + + <RDF:Description RDF:about="http://www.some-fictitious-zoo.com/birds/raven" ANIMALS:specimens="0"> + <ANIMALS:name>Raven</ANIMALS:name> + <ANIMALS:species>Corvus corax</ANIMALS:species> + </RDF:Description> + + <ANIMALS:Class RDF:about="http://www.some-fictitious-zoo.com/crustaceans"> + <ANIMALS:name>Crustaceans</ANIMALS:name> + <ANIMALS:keeper resource="http://www.some-fictitious-zoo.com/humans/robert"/> + </ANIMALS:Class> + + <ANIMALS:Class RDF:about="http://www.some-fictitious-zoo.com/fish"> + <ANIMALS:name>Fish</ANIMALS:name> + </ANIMALS:Class> + + <RDF:Description RDF:about="http://www.some-fictitious-zoo.com/fish/cod" ANIMALS:specimens="0"> + <ANIMALS:name>Cod</ANIMALS:name> + <ANIMALS:species>Gadus morhua</ANIMALS:species> + </RDF:Description> + + <RDF:Description RDF:about="http://www.some-fictitious-zoo.com/fish/swordfish" ANIMALS:specimens="3"> + <ANIMALS:name>Swordfish</ANIMALS:name> + <ANIMALS:species>Xiphias gladius</ANIMALS:species> + </RDF:Description> + + <ANIMALS:Class RDF:about="http://www.some-fictitious-zoo.com/mammals"> + <ANIMALS:name>Mammals</ANIMALS:name> + </ANIMALS:Class> + + <RDF:Description RDF:about="http://www.some-fictitious-zoo.com/mammals/lion"> + <ANIMALS:name>Lion</ANIMALS:name> + <ANIMALS:species>Panthera leo</ANIMALS:species> + <ANIMALS:specimens NC:parseType="Integer">4</ANIMALS:specimens> + <ANIMALS:specimensAsString>4</ANIMALS:specimensAsString> + </RDF:Description> + + <RDF:Description RDF:about="http://www.some-fictitious-zoo.com/mammals/hippopotamus"> + <ANIMALS:name>HIPPOPOTAMUS</ANIMALS:name> + <ANIMALS:species>Hippopotamus amphibius</ANIMALS:species> + <ANIMALS:specimens NC:parseType="Integer">2</ANIMALS:specimens> + <ANIMALS:specimensAsString>2</ANIMALS:specimensAsString> + </RDF:Description> + + <RDF:Description RDF:about="http://www.some-fictitious-zoo.com/mammals/africanelephant"> + <ANIMALS:name>African Elephant</ANIMALS:name> + <ANIMALS:species>Loxodonta africana</ANIMALS:species> + <ANIMALS:specimens NC:parseType="Integer">14</ANIMALS:specimens> + <ANIMALS:specimensAsString>14</ANIMALS:specimensAsString> + </RDF:Description> + + <RDF:Description RDF:about="http://www.some-fictitious-zoo.com/mammals/llama"> + <ANIMALS:name>LLAMA</ANIMALS:name> + <ANIMALS:species>Lama glama</ANIMALS:species> + <ANIMALS:specimens NC:parseType="Integer">5</ANIMALS:specimens> + <ANIMALS:specimensAsString>5</ANIMALS:specimensAsString> + </RDF:Description> + + <RDF:Description RDF:about="http://www.some-fictitious-zoo.com/mammals/polarbear"> + <ANIMALS:name>Polar Bear</ANIMALS:name> + <ANIMALS:species>Thalarctos maritimus</ANIMALS:species> + <ANIMALS:specimens NC:parseType="Integer">20</ANIMALS:specimens> + <ANIMALS:specimensAsString>20</ANIMALS:specimensAsString> + </RDF:Description> + + <RDF:Description RDF:about="http://www.some-fictitious-zoo.com/mammals/aardvark"> + <ANIMALS:name>aardvark</ANIMALS:name> + <ANIMALS:species>Orycteropus afer</ANIMALS:species> + <ANIMALS:specimens NC:parseType="Integer">2</ANIMALS:specimens> + <ANIMALS:specimensAsString>2</ANIMALS:specimensAsString> + </RDF:Description> + + <RDF:Description RDF:about="http://www.some-fictitious-zoo.com/mammals/ninebandedarmadillo"> + <ANIMALS:name>Nine-banded Armadillo</ANIMALS:name> + <ANIMALS:species>Dasypus novemcinctus</ANIMALS:species> + <ANIMALS:specimens NC:parseType="Integer">1</ANIMALS:specimens> + <ANIMALS:specimensAsString>1</ANIMALS:specimensAsString> + </RDF:Description> + + <RDF:Description RDF:about="http://www.some-fictitious-zoo.com/mammals/gorilla"> + <ANIMALS:name>Gorilla</ANIMALS:name> + <ANIMALS:species>Gorilla gorilla</ANIMALS:species> + <ANIMALS:specimens NC:parseType="Integer">7</ANIMALS:specimens> + <ANIMALS:specimensAsString>7</ANIMALS:specimensAsString> + </RDF:Description> + + <ANIMALS:Class RDF:about="http://www.some-fictitious-zoo.com/reptiles"> + <ANIMALS:name>Reptiles</ANIMALS:name> + <ANIMALS:keeper resource="http://www.some-fictitious-zoo.com/humans/robert"/> + </ANIMALS:Class> + + <RDF:Description RDF:about="http://www.some-fictitious-zoo.com/reptiles/anaconda" ANIMALS:specimens="1"> + <ANIMALS:name>Anaconda</ANIMALS:name> + <ANIMALS:species>Eunectes murinus</ANIMALS:species> + </RDF:Description> + + <RDF:Description RDF:about="http://www.some-fictitious-zoo.com/reptiles/chameleon" ANIMALS:specimens="2"> + <ANIMALS:name>Chameleon</ANIMALS:name> + <ANIMALS:species>Chamaeleo chamaelon</ANIMALS:species> + </RDF:Description> + + <RDF:Seq RDF:about="http://www.some-fictitious-zoo.com/some-animals" ANIMALS:name="Zoo Animals"> + <RDF:li RDF:resource="http://www.some-fictitious-zoo.com/arachnids"/> + <RDF:li RDF:resource="http://www.some-fictitious-zoo.com/birds"/> + </RDF:Seq> + + <RDF:Seq RDF:about="http://www.some-fictitious-zoo.com/all-animals" ANIMALS:name="Zoo Animals"> + <RDF:li> + <RDF:Seq RDF:about="http://www.some-fictitious-zoo.com/arachnids"> + <RDF:li RDF:resource="http://www.some-fictitious-zoo.com/arachnids/tarantula"/> + </RDF:Seq> + </RDF:li> + <RDF:li> + <RDF:Seq RDF:about="http://www.some-fictitious-zoo.com/birds"> + <RDF:li RDF:resource="http://www.some-fictitious-zoo.com/birds/emu"/> + <RDF:li RDF:resource="http://www.some-fictitious-zoo.com/birds/barnowl"/> + <RDF:li RDF:resource="http://www.some-fictitious-zoo.com/birds/raven"/> + </RDF:Seq> + </RDF:li> + <RDF:li> + <RDF:Seq RDF:about="http://www.some-fictitious-zoo.com/crustaceans"/> + </RDF:li> + <RDF:li> + <RDF:Seq RDF:about="http://www.some-fictitious-zoo.com/fish"> + <RDF:li RDF:resource="http://www.some-fictitious-zoo.com/fish/cod"/> + <RDF:li RDF:resource="http://www.some-fictitious-zoo.com/fish/swordfish"/> + </RDF:Seq> + </RDF:li> + <RDF:li> + <RDF:Seq RDF:about="http://www.some-fictitious-zoo.com/mammals"> + <RDF:li RDF:resource="http://www.some-fictitious-zoo.com/mammals/lion"/> + <RDF:li RDF:resource="http://www.some-fictitious-zoo.com/mammals/hippopotamus"/> + <RDF:li RDF:resource="http://www.some-fictitious-zoo.com/mammals/africanelephant"/> + <RDF:li RDF:resource="http://www.some-fictitious-zoo.com/mammals/llama"/> + <RDF:li RDF:resource="http://www.some-fictitious-zoo.com/mammals/polarbear"/> + <RDF:li RDF:resource="http://www.some-fictitious-zoo.com/mammals/aardvark"/> + <RDF:li RDF:resource="http://www.some-fictitious-zoo.com/mammals/ninebandedarmadillo"/> + <RDF:li RDF:resource="http://www.some-fictitious-zoo.com/mammals/gorilla"/> + </RDF:Seq> + </RDF:li> + <RDF:li> + <RDF:Seq RDF:about="http://www.some-fictitious-zoo.com/reptiles"> + <RDF:li RDF:resource="http://www.some-fictitious-zoo.com/reptiles/anaconda"/> + <RDF:li RDF:resource="http://www.some-fictitious-zoo.com/reptiles/chameleon"/> + </RDF:Seq> + </RDF:li> + </RDF:Seq> + + <RDF:Seq RDF:about="http://www.some-fictitious-zoo.com/humans" ANIMALS:name="Humans"> + <RDF:li RDF:resource="http://www.some-fictitious-zoo.com/humans/sarah"/> + <RDF:li RDF:resource="http://www.some-fictitious-zoo.com/humans/robert"/> + </RDF:Seq> + + <RDF:Seq RDF:about="http://www.some-fictitious-zoo.com/sarahs-pets" ANIMALS:name="Sarah's Pets"> + <RDF:li RDF:resource="http://www.some-fictitious-zoo.com/birds/emu"/> + <RDF:li RDF:resource="http://www.some-fictitious-zoo.com/arachnids/tarantula"/> + </RDF:Seq> + + <RDF:Seq RDF:about="http://www.some-fictitious-zoo.com/roberts-pets" ANIMALS:name="Robert's Pets"> + <RDF:li RDF:resource="http://www.some-fictitious-zoo.com/reptiles/chameleon"/> + <RDF:li RDF:resource="http://www.some-fictitious-zoo.com/arachnids/tarantula"/> + <RDF:li RDF:resource="http://www.some-fictitious-zoo.com/mammals/llama"/> + </RDF:Seq> + + <RDF:Description RDF:about="http://www.some-fictitious-zoo.com/humans/sarah" ANIMALS:name="Sarah"> + <ANIMALS:pets resource="http://www.some-fictitious-zoo.com/sarahs-pets"/> + <ANIMALS:favoriteAnimal resource="http://www.some-fictitious-zoo.com/birds/emu"/> + <ANIMALS:favoriteAnimal resource="http://www.some-fictitious-zoo.com/mammals/polarbear"/> + <ANIMALS:favoriteAnimal resource="http://www.some-fictitious-zoo.com/arachnids/tarantula"/> + <ANIMALS:description> + Sarah became caretaker of the Fictitious Zoo's emu exhibit in 2001. With so + many emus living there, she has a lot to do! + </ANIMALS:description> + </RDF:Description> + + <RDF:Description RDF:about="http://www.some-fictitious-zoo.com/humans/robert" ANIMALS:name="Robert"> + <ANIMALS:pets resource="http://www.some-fictitious-zoo.com/roberts-pets"/> + <ANIMALS:favoriteAnimal resource="http://www.some-fictitious-zoo.com/arachnids/tarantula"/> + <ANIMALS:favoriteAnimal resource="http://www.some-fictitious-zoo.com/reptiles/anaconda"/> + <ANIMALS:favoriteAnimal resource="http://www.some-fictitious-zoo.com/reptiles/chameleon"/> + <ANIMALS:favoriteAnimal resource="http://www.some-fictitious-zoo.com/mammals/africanelephant"/> + <ANIMALS:description> + Robert helps visitors to the Fictitious Zoo's reptile pavilion learn + more about some of the more unusual creatures that live there. + </ANIMALS:description> + <ANIMALS:lastName>Sanderson</ANIMALS:lastName> + </RDF:Description> + + <RDF:Seq RDF:about="http://www.some-fictitious-zoo.com/marked" ANIMALS:name="Marked"> + <RDF:li RDF:resource="http://www.some-fictitious-zoo.com/humans/sarah"/> + <RDF:li RDF:resource="http://www.some-fictitious-zoo.com/mammals"/> + <RDF:li RDF:resource="http://www.some-fictitious-zoo.com/crustaceans"/> + <RDF:li RDF:resource="http://www.some-fictitious-zoo.com/birds/emu"/> + </RDF:Seq> + +</RDF:RDF> diff --git a/dom/xul/templates/tests/chrome/animals.sqlite b/dom/xul/templates/tests/chrome/animals.sqlite Binary files differnew file mode 100644 index 000000000..7ba88ff74 --- /dev/null +++ b/dom/xul/templates/tests/chrome/animals.sqlite diff --git a/dom/xul/templates/tests/chrome/animals.xml b/dom/xul/templates/tests/chrome/animals.xml new file mode 100644 index 000000000..f73ec718b --- /dev/null +++ b/dom/xul/templates/tests/chrome/animals.xml @@ -0,0 +1,19 @@ +<?xml version="1.0"?> + +<!DOCTYPE zoo [ + <!ATTLIST species id ID #REQUIRED> +]> + +<zoo> + <class> + <name>Reptiles</name> + <species id="Chamaeleo-chamaelon" name="Chameleon" specimens="2"/> + </class> + <class> + <name>Birds</name> + <species id="Dromaius-novaehollandiae" name="Emu" specimens="12"/> + <species id="Tyto-alba" name="Barn Owl" specimens="4"/> + <species id="Corvus-corax" name="Raven" specimens="0"/> + <location>Aviary</location> + </class> +</zoo> diff --git a/dom/xul/templates/tests/chrome/bug441785-1.rdf b/dom/xul/templates/tests/chrome/bug441785-1.rdf new file mode 100644 index 000000000..4be55657f --- /dev/null +++ b/dom/xul/templates/tests/chrome/bug441785-1.rdf @@ -0,0 +1,263 @@ +<?xml version="1.0" encoding="utf-8"?> +<RDF:RDF xmlns:RDF="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns:row="http://dummy/rdf#" xmlns:NC="http://home.netscape.com/NC-rdf#"> + <RDF:Bag about="urn:data:row"> + <RDF:li> + <RDF:Description> + <row:id NC:parseType="Integer">111110</row:id> + <row:title>FILE 1 -- A</row:title> + </RDF:Description> + </RDF:li> + <RDF:li> + <RDF:Description> + <row:id NC:parseType="Integer">111111</row:id> + <row:title>FILE 1 -- B</row:title> + </RDF:Description> + </RDF:li> + <RDF:li> + <RDF:Description> + <row:id NC:parseType="Integer">111110</row:id> + <row:title>FILE 1 -- C</row:title> + </RDF:Description> + </RDF:li> + <RDF:li> + <RDF:Description> + <row:id NC:parseType="Integer">111111</row:id> + <row:title>FILE 1 -- D</row:title> + </RDF:Description> + </RDF:li> + <RDF:li> + <RDF:Description> + <row:id NC:parseType="Integer">111112</row:id> + <row:title>FILE 1 -- E</row:title> + </RDF:Description> + </RDF:li> + <RDF:li> + <RDF:Description> + <row:id NC:parseType="Integer">111110</row:id> + <row:title>FILE 1 -- F</row:title> + </RDF:Description> + </RDF:li> + <RDF:li> + <RDF:Description> + <row:id NC:parseType="Integer">111114</row:id> + <row:title>FILE 1 -- G</row:title> + </RDF:Description> + </RDF:li> + <RDF:li> + <RDF:Description> + <row:id NC:parseType="Integer">111111</row:id> + <row:title>FILE 1 -- H</row:title> + </RDF:Description> + </RDF:li> + <RDF:li> + <RDF:Description> + <row:id NC:parseType="Integer">111118</row:id> + <row:title>FILE 1 -- I</row:title> + </RDF:Description> + </RDF:li> + <RDF:li> + <RDF:Description> + <row:id NC:parseType="Integer">111116</row:id> + <row:title>FILE 1 -- J</row:title> + </RDF:Description> + </RDF:li> + <RDF:li> + <RDF:Description> + <row:id NC:parseType="Integer">111110</row:id> + <row:title>FILE 1 -- K</row:title> + </RDF:Description> + </RDF:li> + <RDF:li> + <RDF:Description> + <row:id NC:parseType="Integer">111119</row:id> + <row:title>FILE 1 -- L</row:title> + </RDF:Description> + </RDF:li> + <RDF:li> + <RDF:Description> + <row:id NC:parseType="Integer">111116</row:id> + <row:title>FILE 1 -- M</row:title> + </RDF:Description> + </RDF:li> + <RDF:li> + <RDF:Description> + <row:id NC:parseType="Integer">1111111</row:id> + <row:title>FILE 1 -- N</row:title> + </RDF:Description> + </RDF:li> + <RDF:li> + <RDF:Description> + <row:id NC:parseType="Integer">111113</row:id> + <row:title>FILE 1 -- O</row:title> + </RDF:Description> + </RDF:li> + <RDF:li> + <RDF:Description> + <row:id NC:parseType="Integer">111111</row:id> + <row:title>FILE 1 -- P</row:title> + </RDF:Description> + </RDF:li> + <RDF:li> + <RDF:Description> + <row:id NC:parseType="Integer">111117</row:id> + <row:title>FILE 1 -- Q</row:title> + </RDF:Description> + </RDF:li> + <RDF:li> + <RDF:Description> + <row:id NC:parseType="Integer">1111110</row:id> + <row:title>FILE 1 -- R</row:title> + </RDF:Description> + </RDF:li> + <RDF:li> + <RDF:Description> + <row:id NC:parseType="Integer">111113</row:id> + <row:title>FILE 1 -- S</row:title> + </RDF:Description> + </RDF:li> + <RDF:li> + <RDF:Description> + <row:id NC:parseType="Integer">1111112</row:id> + <row:title>FILE 1 -- T</row:title> + </RDF:Description> + </RDF:li> + <RDF:li> + <RDF:Description> + <row:id NC:parseType="Integer">111116</row:id> + <row:title>FILE 1 -- U</row:title> + </RDF:Description> + </RDF:li> + <RDF:li> + <RDF:Description> + <row:id NC:parseType="Integer">1111111</row:id> + <row:title>FILE 1 -- V</row:title> + </RDF:Description> + </RDF:li> + <RDF:li> + <RDF:Description> + <row:id NC:parseType="Integer">1111121</row:id> + <row:title>FILE 1 -- W</row:title> + </RDF:Description> + </RDF:li> + <RDF:li> + <RDF:Description> + <row:id NC:parseType="Integer">111114</row:id> + <row:title>FILE 1 -- X</row:title> + </RDF:Description> + </RDF:li> + <RDF:li> + <RDF:Description> + <row:id NC:parseType="Integer">1111122</row:id> + <row:title>FILE 1 -- Y</row:title> + </RDF:Description> + </RDF:li> + <RDF:li> + <RDF:Description> + <row:id NC:parseType="Integer">1111113</row:id> + <row:title>FILE 1 -- Z</row:title> + </RDF:Description> + </RDF:li> + <RDF:li> + <RDF:Description> + <row:id NC:parseType="Integer">1111119</row:id> + <row:title>FILE 1 -- AA</row:title> + </RDF:Description> + </RDF:li> + <RDF:li> + <RDF:Description> + <row:id NC:parseType="Integer">1111117</row:id> + <row:title>FILE 1 -- BB</row:title> + </RDF:Description> + </RDF:li> + <RDF:li> + <RDF:Description> + <row:id NC:parseType="Integer">111117</row:id> + <row:title>FILE 1 -- CC</row:title> + </RDF:Description> + </RDF:li> + <RDF:li> + <RDF:Description> + <row:id NC:parseType="Integer">111117</row:id> + <row:title>FILE 1 -- DD</row:title> + </RDF:Description> + </RDF:li> + <RDF:li> + <RDF:Description> + <row:id NC:parseType="Integer">111116</row:id> + <row:title>FILE 1 -- EE</row:title> + </RDF:Description> + </RDF:li> + <RDF:li> + <RDF:Description> + <row:id NC:parseType="Integer">1111124</row:id> + <row:title>FILE 1 -- FF</row:title> + </RDF:Description> + </RDF:li> + <RDF:li> + <RDF:Description> + <row:id NC:parseType="Integer">111118</row:id> + <row:title>FILE 1 -- GG</row:title> + </RDF:Description> + </RDF:li> + <RDF:li> + <RDF:Description> + <row:id NC:parseType="Integer">1111117</row:id> + <row:title>FILE 1 -- HH</row:title> + </RDF:Description> + </RDF:li> + <RDF:li> + <RDF:Description> + <row:id NC:parseType="Integer">111118</row:id> + <row:title>FILE 1 -- II</row:title> + </RDF:Description> + </RDF:li> + <RDF:li> + <RDF:Description> + <row:id NC:parseType="Integer">1111125</row:id> + <row:title>FILE 1 -- JJ</row:title> + </RDF:Description> + </RDF:li> + <RDF:li> + <RDF:Description> + <row:id NC:parseType="Integer">1111124</row:id> + <row:title>FILE 1 -- KK</row:title> + </RDF:Description> + </RDF:li> + <RDF:li> + <RDF:Description> + <row:id NC:parseType="Integer">1111132</row:id> + <row:title>FILE 1 -- LL</row:title> + </RDF:Description> + </RDF:li> + <RDF:li> + <RDF:Description> + <row:id NC:parseType="Integer">1111136</row:id> + <row:title>FILE 1 -- MM</row:title> + </RDF:Description> + </RDF:li> + <RDF:li> + <RDF:Description> + <row:id NC:parseType="Integer">1111123</row:id> + <row:title>FILE 1 -- NN</row:title> + </RDF:Description> + </RDF:li> + <RDF:li> + <RDF:Description> + <row:id NC:parseType="Integer">1111122</row:id> + <row:title>FILE 1 -- OO</row:title> + </RDF:Description> + </RDF:li> + <RDF:li> + <RDF:Description> + <row:id NC:parseType="Integer">111110</row:id> + <row:title>FILE 1 -- PP</row:title> + </RDF:Description> + </RDF:li> + <RDF:li> + <RDF:Description> + <row:id NC:parseType="Integer">1111116</row:id> + <row:title>FILE 1 -- QQ</row:title> + </RDF:Description> + </RDF:li> + </RDF:Bag> +</RDF:RDF> diff --git a/dom/xul/templates/tests/chrome/bug441785-2.rdf b/dom/xul/templates/tests/chrome/bug441785-2.rdf new file mode 100644 index 000000000..dca97ba78 --- /dev/null +++ b/dom/xul/templates/tests/chrome/bug441785-2.rdf @@ -0,0 +1,11 @@ +<?xml version="1.0" encoding="utf-8"?> +<RDF:RDF xmlns:RDF="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns:row="http://dummy/rdf#" xmlns:NC="http://home.netscape.com/NC-rdf#"> + <RDF:Bag about="urn:data:row"> + <RDF:li> + <RDF:Description> + <row:id NC:parseType="Integer">222220</row:id> + <row:title>FILE 2 -- A</row:title> + </RDF:Description> + </RDF:li> + </RDF:Bag> +</RDF:RDF> diff --git a/dom/xul/templates/tests/chrome/chrome.ini b/dom/xul/templates/tests/chrome/chrome.ini new file mode 100644 index 000000000..97989723c --- /dev/null +++ b/dom/xul/templates/tests/chrome/chrome.ini @@ -0,0 +1,225 @@ +[DEFAULT] +skip-if = os == 'android' +support-files = + animals.rdf + animals.sqlite + animals.xml + bug441785-1.rdf + bug441785-2.rdf + templates_shared.js + +[test_bug329335.xul] +[test_bug330010.xul] +skip-if = os == "win" +support-files = file_bug330010.rdf +[test_bug397148.xul] +skip-if = true # Bug 879531 +[test_bug441785.xul] +[test_bug476634.xul] +[test_sortservice.xul] +[test_tmpl_bindingsextendedsyntax.xul] +[test_tmpl_bindingsmultiple.xul] +[test_tmpl_bindingsquerysyntax.xul] +[test_tmpl_bindingsreversed.xul] +[test_tmpl_bindingssameastriple.xul] +[test_tmpl_containerandmembervariablechanged.xul] +[test_tmpl_containervariablechanged.xul] +[test_tmpl_containmentattribute.xul] +[test_tmpl_defaultcontainervariableisuri.xul] +[test_tmpl_errors.xul] +[test_tmpl_extendedsyntax.xul] +[test_tmpl_extendedsyntaxemptyconditions.xul] +[test_tmpl_extendedsyntaxotherrefvariable.xul] +[test_tmpl_extendedsyntaxremoveunmatched.xul] +[test_tmpl_extendedsyntaxsimplevariablesubstitution.xul] +[test_tmpl_extendedsyntaxtworulesrecurse.xul] +[test_tmpl_extendedsyntaxusinganinterveningcontainer.xul] +[test_tmpl_extendedvariablesubstitution.xul] +[test_tmpl_gridelement.xul] +[test_tmpl_htmlelementextendedsyntaxwithbinding.xul] +[test_tmpl_htmlelementquerysyntaxrecursive.xul] +[test_tmpl_htmlelementquerysyntaxwithmultiplerules.xul] +[test_tmpl_htmlelementsimplesyntax.xul] +[test_tmpl_htmlelementsimplesyntaxusingatextnode.xul] +[test_tmpl_invalidqp.xul] +[test_tmpl_listboxelement.xul] +[test_tmpl_literalasmember.xul] +[test_tmpl_membervariablechanged.xul] +[test_tmpl_membervariablesubstitution.xul] +[test_tmpl_menuelement.xul] +[test_tmpl_menuelementrecursive.xul] +[test_tmpl_menulistelement.xul] +[test_tmpl_mixedsyntaxiscontainer.xul] +[test_tmpl_mixedsyntaxiscontainerisempty.xul] +[test_tmpl_mixedsyntaxisempty.xul] +[test_tmpl_noaction.xul] +[test_tmpl_noactionuriattribute.xul] +[test_tmpl_parentconditions.xul] +[test_tmpl_parentcontenttag.xul] +[test_tmpl_parentsimplesyntax.xul] +[test_tmpl_query3triples.xul] +[test_tmpl_query3tripleswherecontains.xul] +[test_tmpl_querymember3tripleswhereequals.xul] +[test_tmpl_querymemberandtwotriples.xul] +[test_tmpl_querymembertriplemembertriple.xul] +[test_tmpl_queryresourcematch.xul] +[test_tmpl_queryreversetriple.xul] +[test_tmpl_queryselfwithtriple.xul] +[test_tmpl_querysetone.xul] +[test_tmpl_querysettwo.xul] +[test_tmpl_querysettwowithcondition.xul] +[test_tmpl_querysyntax.xul] +[test_tmpl_querysyntaxmultiplerules.xul] +[test_tmpl_querysyntaxmultiplerulesfirstconditionall.xul] +[test_tmpl_querysyntaxmultiplerulestwoconditions.xul] +[test_tmpl_querytripleandmembermerge.xul] +[test_tmpl_querytripleobjecttosubject.xul] +[test_tmpl_querytwomembers.xul] +[test_tmpl_querytwomembersfiltered.xul] +[test_tmpl_querytwotriples.xul] +[test_tmpl_queryupwardsmember.xul] +[test_tmpl_queryupwardsmembertripleandfilteringtriple.xul] +[test_tmpl_querywithemptyconditions.xul] +[test_tmpl_referenceasmember.xul] +[test_tmpl_regenerate.xul] +[test_tmpl_selfgenerationextendedsyntax.xul] +[test_tmpl_selfgenerationsimplesyntax.xul] +[test_tmpl_simplesyntaxenclosedinacontainer.xul] +[test_tmpl_simplesyntaxenclosedinacontainerwitharule.xul] +[test_tmpl_simplesyntaxfilter.xul] +[test_tmpl_simplesyntaxfilterwithmultiplerules.xul] +[test_tmpl_simplesyntaxfilterwithrule.xul] +[test_tmpl_simplesyntaxiteratingoverasinglevalue.xul] +[test_tmpl_simplesyntaxusinganinterveningcontainer.xul] +[test_tmpl_simplesyntaxusingatextnode.xul] +[test_tmpl_simplesyntaxusingcontainerasthegenerationelement.xul] +[test_tmpl_simplesyntaxusingdontrecurse.xul] +[test_tmpl_simplesyntaxusingrecursivegeneration.xul] +[test_tmpl_simplesyntaxusingrecursivegenerationagain.xul] +[test_tmpl_simplesyntaxwithtwovariablesused.xul] +[test_tmpl_simplevariablesubstitutioncaretsatbeginningandend.xul] +[test_tmpl_simplevariablesubstitutioncaretsubstitution.xul] +[test_tmpl_simplevariablesubstitutionnovariable.xul] +[test_tmpl_simplevariablesubstitutionquestionmarkaspartofvariable.xul] +[test_tmpl_simplevariablesubstitutionquestionmarksubstitution.xul] +[test_tmpl_simplevariablesubstitutiontextandvariable.xul] +[test_tmpl_simplevariablesubstitutionvariableandtextconcatenated.xul] +[test_tmpl_simplevariablesubstitutionvariablesconcatenated.xul] +[test_tmpl_sortascendinginteger.xul] +[test_tmpl_sortascendingquerysyntax.xul] +[test_tmpl_sortascendingtworulesquerysyntax.xul] +[test_tmpl_sortascendingtworuleswithcontainerquerysyntax.xul] +[test_tmpl_sortascendingtworuleswithdifferentcontainerquerysyntax.xul] +[test_tmpl_sortdescendingquerysyntax.xul] +[test_tmpl_sortquerymemberandtwotriples.xul] +[test_tmpl_sortresource2descendingsimplesyntax.xul] +[test_tmpl_sortresource2settopredicateascendingquerysyntax.xul] +[test_tmpl_sortresource2settopredicatedescendingquerysyntax.xul] +[test_tmpl_sortresourceascendingquerysyntax.xul] +[test_tmpl_sortresourcedescendingquerysyntax.xul] +[test_tmpl_sortresourcesettopredicateascendingquerysyntax.xul] +[test_tmpl_sortresourcesettopredicatedescendingquerysyntax.xul] +[test_tmpl_sorttworesourcesasstringsettopredicatedescendingquerysyntax.xul] +[test_tmpl_sorttworesourcessettopredicateascendingquerysyntax.xul] +[test_tmpl_sorttwovariablesascendingquerysyntax.xul] +[test_tmpl_sorttwovariablesascendingsimplesyntax.xul] +[test_tmpl_sorttwovariablesdescendingquerysyntax.xul] +[test_tmpl_sortunknownascendingquerysyntax.xul] +[test_tmpl_storage_bad_parameters.xul] +[test_tmpl_storage_bad_parameters_2.xul] +[test_tmpl_storage_bad_parameters_3.xul] +[test_tmpl_storage_baddatasource.xul] +[test_tmpl_storage_badquery.xul] +[test_tmpl_storage_dynamicparameters.xul] +[test_tmpl_storage_listbox.xul] +[test_tmpl_storage_multiqueries.xul] +[test_tmpl_storage_parameters.xul] +[test_tmpl_storage_rule.xul] +[test_tmpl_storage_simple.xul] +[test_tmpl_storage_sortintegerasc.xul] +[test_tmpl_storage_sortintegerdesc.xul] +[test_tmpl_storage_sortstringasc.xul] +[test_tmpl_storage_sortstringdesc.xul] +[test_tmpl_storage_tree.xul] +[test_tmpl_treeelementquerysyntax.xul] +[test_tmpl_treeelementquerysyntaxnotrecursive.xul] +[test_tmpl_treeelementquerysyntaxnotrecursivetreebuilder.xul] +[test_tmpl_treeelementquerysyntaxrecursive.xul] +[test_tmpl_treeelementquerysyntaxrecursivemultiplerules.xul] +[test_tmpl_treeelementquerysyntaxrecursivemultiplerulestreebuilder.xul] +[test_tmpl_treeelementquerysyntaxrecursivetreebuilder.xul] +[test_tmpl_treeelementquerysyntaxtreebuilder.xul] +[test_tmpl_treeelementsimplesyntaxnotrecursive.xul] +[test_tmpl_treeelementsimplesyntaxnotrecursivetreebuilder.xul] +[test_tmpl_treeelementsimplesyntaxrecursive.xul] +[test_tmpl_treeelementsimplesyntaxrecursivetreebuilder.xul] +[test_tmpl_treeelementtreecell.xul] +[test_tmpl_treeelementtreecellsortascending.xul] +[test_tmpl_treeelementtreecellsortascendingtreebuilder.xul] +[test_tmpl_treeelementtreecelltreebuilder.xul] +[test_tmpl_treeelementtreeitemonly.xul] +[test_tmpl_treeelementtreeitemsortascending.xul] +[test_tmpl_twogenerationnodes.xul] +[test_tmpl_whereafterignorecase.xul] +[test_tmpl_whereafterlowercase.xul] +[test_tmpl_whereafternegation.xul] +[test_tmpl_whereafteruppercase.xul] +[test_tmpl_wherebeforeignorecase.xul] +[test_tmpl_wherebeforelowercase.xul] +[test_tmpl_wherebeforenegation.xul] +[test_tmpl_wherebeforeuppercase.xul] +[test_tmpl_wherecontains.xul] +[test_tmpl_wherecontainsignorecase.xul] +[test_tmpl_wherecontainsnegation.xul] +[test_tmpl_wherecontainsnumber.xul] +[test_tmpl_wherecontainsnumberstring.xul] +[test_tmpl_wherecontainsresource.xul] +[test_tmpl_wherecontainstwo.xul] +[test_tmpl_whereendswith.xul] +[test_tmpl_whereendswithignorecase.xul] +[test_tmpl_whereendswithnegation.xul] +[test_tmpl_whereequals.xul] +[test_tmpl_whereequalsignorecase.xul] +[test_tmpl_whereequalsmultiple.xul] +[test_tmpl_whereequalsmultiplenegation.xul] +[test_tmpl_whereequalsmultiplenegationignorecase.xul] +[test_tmpl_whereequalsnegation.xul] +[test_tmpl_whereequalsnegationignorecase.xul] +[test_tmpl_whereequalsnegationwrongcase.xul] +[test_tmpl_whereequalsnumber.xul] +[test_tmpl_whereequalsothervariable.xul] +[test_tmpl_whereequalsresource.xul] +[test_tmpl_whereequalssamevariable.xul] +[test_tmpl_whereequalswrongcase.xul] +[test_tmpl_wheregreater.xul] +[test_tmpl_wheregreaternegation.xul] +[test_tmpl_wheregreaternegationstring.xul] +[test_tmpl_wheregreaterstring.xul] +[test_tmpl_whereless.xul] +[test_tmpl_wherelessnegation.xul] +[test_tmpl_wherelessnegationstring.xul] +[test_tmpl_wherelessstring.xul] +[test_tmpl_wherenorel.xul] +[test_tmpl_wherenosubject.xul] +[test_tmpl_wherenovalue.xul] +[test_tmpl_wherestartswith.xul] +[test_tmpl_wherestartswithignorecase.xul] +[test_tmpl_wherestartswithmultiple.xul] +[test_tmpl_wherestartswithnegation.xul] +[test_tmpl_wherestartswithunknownvariable.xul] +[test_tmpl_wherestartswithvariable.xul] +[test_tmpl_wheresubjectequalsvariable.xul] +[test_tmpl_wheresubjectstartswithvariable.xul] +[test_tmpl_xmlquerysimple.xul] +[test_tmpl_xmlquerywithassign.xul] +[test_tmpl_xmlquerywithassignmentandcondition.xul] +[test_tmpl_xmlquerywithassignmentandconditiondontrecurse.xul] +[test_tmpl_xmlquerywithbindinginbindings.xul] +[test_tmpl_xmlquerywithbindinginrule.xul] +[test_tmpl_xmlquerywithdifferentmember.xul] +[test_tmpl_xmlquerywithinlinedata.xul] +[test_tmpl_xmlquerywithinlinedatawithmultiplequeries.xul] +[test_tmpl_xmlquerywithmultiplequeries.xul] +[test_tmpl_xmlquerywithothertypes.xul] +[test_tmpl_xmlquerywithsort.xul] +[test_tmpl_xmlquerywithsortotherfield.xul] diff --git a/dom/xul/templates/tests/chrome/file_bug330010.rdf b/dom/xul/templates/tests/chrome/file_bug330010.rdf new file mode 100644 index 000000000..428f1045f --- /dev/null +++ b/dom/xul/templates/tests/chrome/file_bug330010.rdf @@ -0,0 +1,13 @@ +<?xml version="1.0"?> +<rdf:RDF xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" + xmlns:s="urn:croczilla:xulsvg1:"> + <rdf:Description about="urn:root"> + <s:shapes> + <rdf:Bag> + <rdf:li> + <rdf:Description /> + </rdf:li> + </rdf:Bag> + </s:shapes> + </rdf:Description> +</rdf:RDF> diff --git a/dom/xul/templates/tests/chrome/templates_shared.js b/dom/xul/templates/tests/chrome/templates_shared.js new file mode 100644 index 000000000..85c49e52e --- /dev/null +++ b/dom/xul/templates/tests/chrome/templates_shared.js @@ -0,0 +1,488 @@ +/** + * This script is used for testing XUL templates. Call test_template within + * a load event handler. + * + * A test should have a root node with the datasources attribute with the + * id 'root', and a few global variables defined in the test's XUL file: + * + * testid: the testid, used when outputting test results + * expectedOutput: e4x data containing the expected output. It can optionally + * be enclosed in an <output> element as most tests generate + * more than one node of output. + * isTreeBuilder: true for dont-build-content trees, false otherwise + * queryType: 'rdf', 'xml', etc. + * needsOpen: true for menu tests where the root menu must be opened before + * comparing results + * notWorkingYet: true if this test isn't working yet, outputs todo results + * notWorkingYetDynamic: true if the dynamic changes portion of the test + * isn't working yet, outputs todo results + * changes: an array of functions to perform in sequence to test dynamic changes + * to the datasource. + * + * If the <output> element has an unordered attribute set to true, the + * children within it must all appear to match, but may appear in any order. + * If the unordered attribute is not set, the children must appear in the same + * order. + * + * If the 'changes' array is used, it should be an array of functions. Each + * function will be called in order and a comparison of the output will be + * performed. This allows changes to be made to the datasource to ensure that + * the generated template output has been updated. Within the expected output + * XML, the step attribute may be set to a number on an element to indicate + * that an element only applies before or after a particular change. If step + * is set to a positive number, that element will only exist after that step in + * the list of changes made. If step is set to a negative number, that element + * will only exist until that step. Steps are numbered starting at 1. For + * example: + * <label value="Cat"/> + * <label step="2" value="Dog"/> + * <label step="-5" value="Mouse"/> + * The first element will always exist. The second element will only appear + * after the second change is made. The third element will only appear until + * the fifth change and it will no longer be present at later steps. + * + * If the anyid attribute is set to true on an element in the expected output, + * then the value of the id attribute on that element is not compared for a + * match. This is used, for example, for xml datasources, where the ids set on + * the generated output are pseudo-random. + */ + +const ZOO_NS = "http://www.some-fictitious-zoo.com/"; +const XUL_NS = "http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"; +const debug = false; + +var expectedConsoleMessages = []; +var expectLoggedMessages = null; + +function get_RDF() { + try { + return Components.classes["@mozilla.org/rdf/rdf-service;1"]. + getService(Components.interfaces.nsIRDFService); + } catch (ex) { } +} + +function get_ContainerUtils() +{ + try { + return Components.classes["@mozilla.org/rdf/container-utils;1"]. + getService(Components.interfaces.nsIRDFContainerUtils); + } catch(ex) { } +} + +const RDF = get_RDF(); +const ContainerUtils = get_ContainerUtils(); + +var xmlDoc; + +function test_template() +{ + var root = document.getElementById("root"); + + var ds; + if (queryType == "rdf" && RDF) { + var ioService = Components.classes["@mozilla.org/network/io-service;1"]. + getService(Components.interfaces.nsIIOService); + + var src = window.location.href.replace(/test_tmpl.*xul/, "animals.rdf"); + ds = RDF.GetDataSourceBlocking(src); + + if (expectLoggedMessages) { + Components.classes["@mozilla.org/consoleservice;1"]. + getService(Components.interfaces.nsIConsoleService).reset(); + } + + if (root.getAttribute("datasources") == "rdf:null") + root.setAttribute("datasources", "animals.rdf"); + } + else if (queryType == "xml") { + var src = window.location.href.replace(/test_tmpl.*xul/, "animals.xml"); + xmlDoc = new XMLHttpRequest(); + xmlDoc.open("get", src, false); + xmlDoc.send(null); + } + + // open menus if necessary + if (needsOpen) + root.open = true; + + if (expectLoggedMessages) + expectLoggedMessages(); + + checkResults(root, 0); + + if (changes.length) { + var usedds = ds; + // within these chrome tests, RDF datasources won't be modifiable unless + // an in-memory datasource is used instead. Call copyRDFDataSource to + // copy the datasource. + if (queryType == "rdf") + usedds = copyRDFDataSource(root, ds); + if (needsOpen) + root.open = true; + setTimeout(iterateChanged, 0, root, usedds); + } + else { + if (needsOpen) + root.open = false; + if (expectedConsoleMessages.length) + compareConsoleMessages(); + SimpleTest.finish(); + } +} + +function iterateChanged(root, ds) +{ + Components.classes["@mozilla.org/consoleservice;1"]. + getService(Components.interfaces.nsIConsoleService).reset(); + + for (var c = 0; c < changes.length; c++) { + changes[c](ds, root); + checkResults(root, c + 1); + } + + if (needsOpen) + root.open = false; + if (expectedConsoleMessages.length) + compareConsoleMessages(); + SimpleTest.finish(); +} + +function checkResults(root, step) +{ + var output = expectedOutput.cloneNode(true); + setForCurrentStep(output, step); + + var error; + var actualoutput = root; + if (isTreeBuilder) { + // convert the tree's view data into the equivalent DOM structure + // for easier comparison + actualoutput = treeViewToDOM(root); + var treechildrenElements = [...output.children].filter((e) => e.localName === "treechildren"); + error = compareOutput(actualoutput, treechildrenElements[0], false); + } + else { + error = compareOutput(actualoutput, output, true); + } + + var adjtestid = testid; + if (step > 0) + adjtestid += " dynamic step " + step; + + var stilltodo = ((step == 0 && notWorkingYet) || (step > 0 && notWorkingYetDynamic)); + if (stilltodo) + todo(false, adjtestid); + else + ok(!error, adjtestid); + + if ((!stilltodo && error) || debug) { + // for debugging, serialize the XML output + var serializedXML = ""; + var rootNodes = actualoutput.childNodes; + for (var n = 0; n < rootNodes.length; n++) { + var node = rootNodes[n]; + if (node.localName != "template") + serializedXML += ((new XMLSerializer()).serializeToString(node)); + } + + // remove the XUL namespace declarations to make the output more readable + const nsrepl = new RegExp("xmlns=\"" + XUL_NS + "\" ", "g"); + serializedXML = serializedXML.replace(nsrepl, ""); + if (debug) + dump("-------- " + adjtestid + " " + error + ":\n" + serializedXML + "\n"); + if (!stilltodo && error) + is(serializedXML, "Same", "Error is: " + error); + } +} + +/** + * Adjust the expected output to acccount for any step attributes. + */ +function setForCurrentStep(content, currentStep) +{ + var todelete = []; + for (var child of content.childNodes) { + if (child.nodeType === Node.ELEMENT_NODE) { + var stepstr = child.getAttribute("step") || ""; + var stepsarr = stepstr.split(","); + for (var s = 0; s < stepsarr.length; s++) { + var step = parseInt(stepsarr[s]); + if ((step > 0 && step > currentStep) || + (step < 0 && -step <= currentStep)) { + todelete.push(child); + } + } + } else if (child.nodeType === Node.TEXT_NODE) { + // Drop empty text nodes. + if (child.nodeValue.trim() === "") + todelete.push(child); + } + } + + for (var e of todelete) + content.removeChild(e); + + for (var child of content.children) { + child.removeAttribute("step"); + setForCurrentStep(child, currentStep); + } +} + +/** + * Compares the 'actual' DOM output with the 'expected' output. This function + * is called recursively, with isroot true if actual refers to the root of the + * template. Returns a null string if they are equal and an error string if + * they are not equal. This function is called recursively as it iterates + * through each node in the DOM tree. + */ +function compareOutput(actual, expected, isroot) +{ + if (isroot && expected.localName != "data") + return "expected must be a <data> element"; + + var t; + + // compare text nodes + if (expected.nodeType == Node.TEXT_NODE) { + if (actual.nodeValue !== expected.nodeValue.trim()) + return "Text " + actual.nodeValue + " doesn't match " + expected.nodeValue; + return ""; + } + + if (!isroot) { + var anyid = false; + // make sure that the tags match + if (actual.localName != expected.localName) + return "Tag name " + expected.localName + " not found"; + + // loop through the attributes in the expected node and compare their + // values with the corresponding attribute on the actual node + + var expectedAttrs = expected.attributes; + for (var a = 0; a < expectedAttrs.length; a++) { + var attr = expectedAttrs[a]; + var expectval = attr.value; + // skip checking the id when anyid="true", however make sure to + // ensure that the id is actually present. + if (attr.name == "anyid" && expectval == "true") { + anyid = true; + if (!actual.hasAttribute("id")) + return "expected id attribute"; + } + else if (actual.getAttribute(attr.name) != expectval) { + return "attribute " + attr.name + " is '" + + actual.getAttribute(attr.name) + "' instead of '" + expectval + "'"; + } + } + + // now loop through the actual attributes and make sure that there aren't + // any extra attributes that weren't expected + var length = actual.attributes.length; + for (t = 0; t < length; t++) { + var aattr = actual.attributes[t]; + var expectval = expected.getAttribute(aattr.name); + // ignore some attributes that don't matter + if (expectval != actual.getAttribute(aattr.name) && + aattr.name != "staticHint" && aattr.name != "xmlns" && + (aattr.name != "id" || !anyid)) + return "extra attribute " + aattr.name; + } + } + + // ensure that the node has the right number of children. Subtract one for + // the root node to account for the <template> node. + length = actual.childNodes.length - (isroot ? 1 : 0); + if (length != expected.childNodes.length) + return "incorrect child node count of " + actual.localName + " " + length + + " expected " + expected.childNodes.length; + + // if <data unordered="true"> is used, then the child nodes may be in any order + var unordered = (expected.localName == "data" && expected.getAttribute("unordered") == "true"); + + // next, loop over the children and call compareOutput recursively on each one + var adj = 0; + for (t = 0; t < actual.childNodes.length; t++) { + var actualnode = actual.childNodes[t]; + // skip the <template> element, and add one to the indices when looking + // at the later nodes to account for it + if (isroot && actualnode.localName == "template") { + adj++; + } + else { + var output = "unexpected"; + if (unordered) { + var expectedChildren = expected.childNodes; + for (var e = 0; e < expectedChildren.length; e++) { + output = compareOutput(actualnode, expectedChildren[e], false); + if (!output) + break; + } + } + else { + output = compareOutput(actualnode, expected.childNodes[t - adj], false); + } + + // an error was returned, so return early + if (output) + return output; + } + } + + return ""; +} + +/* + * copy the datasource into an in-memory datasource so that it can be modified + */ +function copyRDFDataSource(root, sourceds) +{ + var dsourcesArr = []; + var composite = root.database; + var dsources = composite.GetDataSources(); + while (dsources.hasMoreElements()) { + sourceds = dsources.getNext().QueryInterface(Components.interfaces.nsIRDFDataSource); + dsourcesArr.push(sourceds); + } + + for (var d = 0; d < dsourcesArr.length; d++) + composite.RemoveDataSource(dsourcesArr[d]); + + var newds = Components.classes["@mozilla.org/rdf/datasource;1?name=in-memory-datasource"]. + createInstance(Components.interfaces.nsIRDFDataSource); + + var sourcelist = sourceds.GetAllResources(); + while (sourcelist.hasMoreElements()) { + var source = sourcelist.getNext(); + var props = sourceds.ArcLabelsOut(source); + while (props.hasMoreElements()) { + var prop = props.getNext(); + if (prop instanceof Components.interfaces.nsIRDFResource) { + var targets = sourceds.GetTargets(source, prop, true); + while (targets.hasMoreElements()) + newds.Assert(source, prop, targets.getNext(), true); + } + } + } + + composite.AddDataSource(newds); + root.builder.rebuild(); + + return newds; +} + +/** + * Converts a tree view (nsITreeView) into the equivalent DOM tree. + * Returns the treechildren + */ +function treeViewToDOM(tree) +{ + var treechildren = document.createElement("treechildren"); + + if (tree.view) + treeViewToDOMInner(tree.columns, treechildren, tree.view, tree.builder, 0, 0); + + return treechildren; +} + +function treeViewToDOMInner(columns, treechildren, view, builder, start, level) +{ + var end = view.rowCount; + + for (var i = start; i < end; i++) { + if (view.getLevel(i) < level) + return i - 1; + + var id = builder ? builder.getResourceAtIndex(i).Value : "id" + i; + var item = document.createElement("treeitem"); + item.setAttribute("id", id); + treechildren.appendChild(item); + + var row = document.createElement("treerow"); + item.appendChild(row); + + for (var c = 0; c < columns.length; c++) { + var cell = document.createElement("treecell"); + var label = view.getCellText(i, columns[c]); + if (label) + cell.setAttribute("label", label); + row.appendChild(cell); + } + + if (view.isContainer(i)) { + item.setAttribute("container", "true"); + item.setAttribute("empty", view.isContainerEmpty(i) ? "true" : "false"); + + if (!view.isContainerEmpty(i) && view.isContainerOpen(i)) { + item.setAttribute("open", "true"); + + var innertreechildren = document.createElement("treechildren"); + item.appendChild(innertreechildren); + + i = treeViewToDOMInner(columns, innertreechildren, view, builder, i + 1, level + 1); + } + } + } + + return i; +} + +function expectConsoleMessage(ref, id, isNew, isActive, extra) +{ + var message = "In template with id root" + + (ref ? " using ref " + ref : "") + "\n " + + (isNew ? "New " : "Removed ") + (isActive ? "active" : "inactive") + + " result for query " + extra + ": " + id; + expectedConsoleMessages.push(message); +} + +function compareConsoleMessages() +{ + var consoleService = Components.classes["@mozilla.org/consoleservice;1"]. + getService(Components.interfaces.nsIConsoleService); + var messages = consoleService.getMessageArray() || []; + messages = messages.map(m => m.message); + // Copy to avoid modifying expectedConsoleMessages + var expect = expectedConsoleMessages.concat(); + for (var m = 0; m < messages.length; m++) { + if (messages[m] == expect[0]) { + ok(true, "found message " + expect.shift()); + } + } + if (expect.length != 0) { + ok(false, "failed to find expected console messages: " + expect); + } +} + +function copyToProfile(filename) +{ + if (Cc === undefined) { + var Cc = Components.classes; + var Ci = Components.interfaces; + } + + var loader = Cc["@mozilla.org/moz/jssubscript-loader;1"] + .getService(Ci.mozIJSSubScriptLoader); + loader.loadSubScript("chrome://mochikit/content/chrome-harness.js"); + + var file = Cc["@mozilla.org/file/directory_service;1"] + .getService(Ci.nsIProperties) + .get("ProfD", Ci.nsIFile); + file.append(filename); + + var parentURI = getResolvedURI(getRootDirectory(window.location.href)); + if (parentURI.JARFile) { + parentURI = extractJarToTmp(parentURI); + } else { + var fileHandler = Cc["@mozilla.org/network/protocol;1?name=file"]. + getService(Ci.nsIFileProtocolHandler); + parentURI = fileHandler.getFileFromURLSpec(parentURI.spec); + } + + parentURI = parentURI.QueryInterface(Ci.nsILocalFile); + parentURI.append(filename); + try { + var retVal = parentURI.copyToFollowingLinks(file.parent, filename); + } catch (ex) { + //ignore this error as the file could exist already + } +} diff --git a/dom/xul/templates/tests/chrome/test_bug329335.xul b/dom/xul/templates/tests/chrome/test_bug329335.xul new file mode 100644 index 000000000..75190c17b --- /dev/null +++ b/dom/xul/templates/tests/chrome/test_bug329335.xul @@ -0,0 +1,28 @@ +<?xml version="1.0"?> +<?xml-stylesheet href="chrome://global/skin" type="text/css"?> +<?xml-stylesheet type="text/css" href="chrome://mochikit/content/tests/SimpleTest/test.css"?> + +<window xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul" + xmlns:svg="http://www.w3.org/2000/svg"> + + <script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"/> + <script> + + SimpleTest.waitForExplicitFinish(); + + function init() + { + document.documentElement.appendChild(document.getElementById("svg")); + ok(true, "Didn't crash"); + SimpleTest.finish(); + } + + window.addEventListener("load", init, false); + + </script> + + + <svg:svg datasources="" id="svg"/> + + +</window> diff --git a/dom/xul/templates/tests/chrome/test_bug330010.xul b/dom/xul/templates/tests/chrome/test_bug330010.xul new file mode 100644 index 000000000..67cc81931 --- /dev/null +++ b/dom/xul/templates/tests/chrome/test_bug330010.xul @@ -0,0 +1,51 @@ +<?xml version="1.0"?> +<?xml-stylesheet href="chrome://global/skin" type="text/css"?> +<?xml-stylesheet type="text/css" href="chrome://mochikit/content/tests/SimpleTest/test.css"?> +<window xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul" + xmlns:svg="http://www.w3.org/2000/svg" + xmlns:html="http://www.w3.org/1999/xhtml" + onload="boom();"> +<script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"/> +<script type="text/javascript"> +<![CDATA[ + +SimpleTest.waitForExplicitFinish(); +function boom() +{ + const RDF = Components.classes["@mozilla.org/rdf/rdf-service;1"]. + getService(Components.interfaces.nsIRDFService); + var src = window.location.href.replace(/test_bug330010.xul/, "file_bug330010.rdf"); + + var ds = RDF.GetDataSourceBlocking(src); + + var s = document.getElementById("s"); + s.setAttribute("datasources", "file_bug330010.rdf"); + + var x = document.createElementNS("http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul", "hbox"); + var generatedShape = s.childNodes[3]; + generatedShape.appendChild(x); + document.documentElement.removeChild(document.getElementById("s")); + ok(true, "Didn't crash"); + SimpleTest.finish(); +} + +]]> +</script> + + <html:div datasources="rdf:null" ref="urn:root" flex="1" id="s"> + <template> + <rule> + <conditions> + <content uri="?root"/> + <triple subject="?root" + predicate="urn:croczilla:xulsvg1:shapes" + object="?shapes"/> + <member container="?shapes" child="?shape" id="m"/> + </conditions> + <action> + <hbox id="p" uri="?shape" /> + </action> + </rule> + </template> + </html:div> +</window> diff --git a/dom/xul/templates/tests/chrome/test_bug397148.xul b/dom/xul/templates/tests/chrome/test_bug397148.xul new file mode 100644 index 000000000..0f15cfa29 --- /dev/null +++ b/dom/xul/templates/tests/chrome/test_bug397148.xul @@ -0,0 +1,19 @@ +<?xml version="1.0"?> +<?xml-stylesheet href="chrome://global/skin" type="text/css"?> +<?xml-stylesheet type="text/css" href="chrome://mochikit/content/tests/SimpleTest/test.css"?> +<window xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul" xmlns:html="http://www.w3.org/1999/xhtml" onload="boom();"> +<script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"/> + +<script type="text/javascript"> +SimpleTest.waitForExplicitFinish(); + +function boom() { + ok(true, "Didn't crash"); + SimpleTest.finish(); +} +</script> + + +<html:span datasources="0" /> + +</window> diff --git a/dom/xul/templates/tests/chrome/test_bug441785.xul b/dom/xul/templates/tests/chrome/test_bug441785.xul new file mode 100644 index 000000000..7be6df198 --- /dev/null +++ b/dom/xul/templates/tests/chrome/test_bug441785.xul @@ -0,0 +1,148 @@ +<?xml version="1.0" ?> +<?xml-stylesheet href="chrome://global/skin" type="text/css"?> +<?xml-stylesheet href="chrome://mochikit/content/tests/SimpleTest/test.css" type="text/css"?> + +<window xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"> + <tree flex="20" id="t" ref="urn:data:row" datasources="rdf:null" seltype="single"> + <treecols> + <treecol flex="1" id="id" label="id" sort="rdf:http://dummy/rdf#id" /> + <splitter class="tree-splitter"/> + <treecol flex="1" id="title" label="title" sort="rdf:http://dummy/rdf#title" sortActive="true" sortDirection="ascending" /><splitter class="tree-splitter"/> + </treecols> + <template> + <treechildren> + <treeitem uri="rdf:*" seltype="single"> + <treerow > + <treecell label="rdf:http://dummy/rdf#id"/> + <treecell label="rdf:http://dummy/rdf#title"/> + </treerow> + </treeitem> + </treechildren> + </template> + </tree> + <tree flex="20" id="tc" ref="urn:data:row" datasources="rdf:null" seltype="single" flags="dont-build-content"> + <treecols> + <treecol flex="1" id="idc" label="id" sort="rdf:http://dummy/rdf#id" /> + <splitter class="tree-splitter"/> + <treecol flex="1" id="titlec" label="title" sort="rdf:http://dummy/rdf#title" sortActive="true" sortDirection="ascending" /><splitter class="tree-splitter"/> + </treecols> + <template> + <treechildren> + <treeitem uri="rdf:*" seltype="single"> + <treerow > + <treecell label="rdf:http://dummy/rdf#id"/> + <treecell label="rdf:http://dummy/rdf#title"/> + </treerow> + </treeitem> + </treechildren> + </template> + </tree> + +<body xmlns="http://www.w3.org/1999/xhtml" style="height: 300px; overflow: auto;"/> + +<script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script> + +<script type="application/x-javascript"> +<![CDATA[ + +var buildCount = 0; + +SimpleTest.waitForExplicitFinish(); + +var TemplateBuilderListener = { + willRebuild: function(aBuilder) { + }, + + didRebuild: function(aBuilder) { + ++buildCount; + var remove = false; + if (buildCount == 2) { + remove =true; + setTimeout(nextDataSource, 0); + } else if (buildCount == 4) { + remove = true; + setTimeout(continueTest, 0); + } + if (remove) { + var tree = document.getElementById('t'); + var treec = document.getElementById('tc'); + tree.builder.removeListener(TemplateBuilderListener); + treec.builder.removeListener(TemplateBuilderListener); + } + }, + + QueryInterface: function (aIID) + { + if (!aIID.equals(Components.interfaces.nsIXULBuilderListener) && + !aIID.equals(Components.interfaces.nsISupports)) + throw Components.results.NS_ERROR_NO_INTERFACE; + return this; + } +}; + +function runTest() { + var tree = document.getElementById('t'); + var treec = document.getElementById('tc'); + + try { + var rdfService = Components.classes["@mozilla.org/rdf/rdf-service;1"]. + getService(Components.interfaces.nsIRDFService); + + var s1 = window.location.href.replace(/test_bug441785.xul/, "bug441785-1.rdf"); + var ds1 = rdfService.GetDataSourceBlocking(s1); + + var s2 = window.location.href.replace(/test_bug441785.xul/, "bug441785-2.rdf"); + var ds2 = rdfService.GetDataSourceBlocking(s2); + } catch (ex) { } + + tree.builder.addListener(TemplateBuilderListener); + treec.builder.addListener(TemplateBuilderListener); + tree.setAttribute('datasources', 'bug441785-1.rdf'); + treec.setAttribute('datasources', 'bug441785-1.rdf'); +} + +var oldtreefirstrow, oldtreecfirstrow; + +function nextDataSource() +{ + var tree = document.getElementById('t'); + var treec = document.getElementById('tc'); + tree.treeBoxObject.scrollToRow(10); + treec.treeBoxObject.scrollToRow(10); + + is(tree.treeBoxObject.getFirstVisibleRow(), 10, "first tree row count datasource 1"); + is(treec.treeBoxObject.getFirstVisibleRow(), 10, "second tree row count datasource 1"); + + tree.builder.addListener(TemplateBuilderListener); + treec.builder.addListener(TemplateBuilderListener); + tree.setAttribute('datasources', 'bug441785-2.rdf'); + treec.setAttribute('datasources', 'bug441785-2.rdf'); +} + +function continueTest() { + var tree = document.getElementById('t'); + var treec = document.getElementById('tc'); + + is(tree.treeBoxObject.getFirstVisibleRow(), 0, "first tree row count datasource 2"); + is(treec.treeBoxObject.getFirstVisibleRow(), 0, "second tree row count datasource 2"); + + try { + window.QueryInterface(Components.interfaces.nsIInterfaceRequestor) + .getInterface(Components.interfaces.nsIDOMWindowUtils) + .garbageCollect(); + } + catch (e) { } + + // Hit the bug, crash + // (not exactly the same kind of crash as 441785, but from the same cause) + tree.parentNode.removeChild(tree); + treec.parentNode.removeChild(treec); + + SimpleTest.finish(); +} + +window.addEventListener("load", runTest, false); + +]]> +</script> +</window> diff --git a/dom/xul/templates/tests/chrome/test_bug476634.xul b/dom/xul/templates/tests/chrome/test_bug476634.xul new file mode 100644 index 000000000..cee01d41a --- /dev/null +++ b/dom/xul/templates/tests/chrome/test_bug476634.xul @@ -0,0 +1,76 @@ +<?xml version="1.0"?> +<?xml-stylesheet href="chrome://global/skin" type="text/css"?> +<?xml-stylesheet + href="chrome://mochikit/content/tests/SimpleTest/test.css" + type="text/css"?> +<!-- +https://bugzilla.mozilla.org/show_bug.cgi?id=476634 +--> +<window title="Mozilla Bug 476634" onload="startup()" + xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"> + + <script type="application/javascript" + src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script> + +<body xmlns="http://www.w3.org/1999/xhtml"> +<a target="_blank" + href="https://bugzilla.mozilla.org/show_bug.cgi?id=304188">Mozilla Bug 476634</a> +<p id="display"></p> +<div id="content" style="display: none"> +</div> +<pre id="test"> +</pre> +</body> +<template id="test-template"> + <query>SELECT id,value FROM test</query> + <action> + <label uri="?" id="?id" value="?value"/> + </action> +</template> +<vbox id="results-list" datasources="rdf:null" querytype="storage" ref="*" + template="test-template"/> + +<script class="testbody" type="application/javascript"> +<![CDATA[ +function startup() { + var ss = Components.classes["@mozilla.org/storage/service;1"] + .getService(Components.interfaces.mozIStorageService); + var db = ss.openSpecialDatabase("memory"); + + db.createTable("test", "id TEXT, value INTEGER"); + var stmt = db.createStatement("INSERT INTO test (id, value) VALUES (?,?)"); + stmt.bindByIndex(0, "test1"); + stmt.bindByIndex(1, 0); + stmt.execute(); + stmt.bindByIndex(0, "test2"); + stmt.bindByIndex(1, 2147483647); + stmt.execute(); + stmt.bindByIndex(0, "test3"); + stmt.bindByIndex(1, -2147483648); + stmt.execute(); + stmt.bindByIndex(0, "test4"); + stmt.bindByIndex(1, 0); + stmt.execute(); + stmt.bindByIndex(0, "test5"); + stmt.bindByIndex(1, 3147483647); + stmt.execute(); + stmt.bindByIndex(0, "test6"); + stmt.bindByIndex(1, -3147483648); + stmt.execute(); + stmt.finalize(); + + var list = document.getElementById("results-list"); + list.builder.datasource = db; + + is(list.childNodes.length, 6, "Should be 6 generated elements"); + is(list.childNodes[0].value, "0", "Should have seen the correct value"); + is(list.childNodes[1].value, "2147483647", "Should have seen the correct value"); + is(list.childNodes[2].value, "-2147483648", "Should have seen the correct value"); + is(list.childNodes[3].value, "0", "Should have seen the correct value"); + is(list.childNodes[4].value, "3147483647", "Should have seen the correct value"); + is(list.childNodes[5].value, "-3147483648", "Should have seen the correct value"); +} +]]> +</script> + +</window> diff --git a/dom/xul/templates/tests/chrome/test_sortservice.xul b/dom/xul/templates/tests/chrome/test_sortservice.xul new file mode 100644 index 000000000..af1de3f0e --- /dev/null +++ b/dom/xul/templates/tests/chrome/test_sortservice.xul @@ -0,0 +1,70 @@ +<?xml version="1.0" ?> +<?xml-stylesheet href="chrome://global/skin" type="text/css"?> +<?xml-stylesheet href="chrome://mochikit/content/tests/SimpleTest/test.css" type="text/css"?> + +<window xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"> + +<vbox id="box"/> + +<body xmlns="http://www.w3.org/1999/xhtml" style="height: 300px; overflow: auto;"/> + +<script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script> + +<script type="application/x-javascript"> +<![CDATA[ + +var tests = [ + [["One", "Two", "Three", "Four"], "", "Four One Three Two"], + [["One", "Two", "Three", "Four"], "integer", "Four One Three Two"], + [["One", "Two", "Three", "Four"], "descending", "Two Three One Four"], + [["One", "Two", "Three", "Four"], "descending integer", "Two Three One Four"], + [["One", "Two", "Three", "Four"], "integer cat descending", "Two Three One Four"], + [["1", "13", "2", "7", "12", "240", "2", "170", "222", "98"], "", "1 12 13 170 2 2 222 240 7 98"], + [["1", "13", "2", "7", "12", "240", "2", "170", "222", "98"], "integer", "1 2 2 7 12 13 98 170 222 240"], + [["1", "13", "2", "7", "12", "240", "2", "170", "222", "98"], "ascending integer", "1 2 2 7 12 13 98 170 222 240"], + [["1", "13", "2", "7", "12", "240", "2", "170", "222", "98"], "integer descending", "240 222 170 98 13 12 7 2 2 1"], + [["Cat", "cat", "Candy", "candy"], "comparecase", "Candy Cat candy cat"], + [["1", "102", "22", "One", "40", "Two"], "integer", "1 22 40 102 One Two"], +]; + +SimpleTest.waitForExplicitFinish(); + +function doTests() +{ + var box = document.getElementById("box"); + + const sortService = Components.classes["@mozilla.org/xul/xul-sort-service;1"]. + getService(Components.interfaces.nsIXULSortService); + + for (let t = 0; t < tests.length; t++) { + var test = tests[t]; + + for (let e = 0; e < test[0].length; e++) { + var label = document.createElement("label"); + label.setAttribute("value", test[0][e]); + box.appendChild(label); + } + + sortService.sort(box, "value", test[1]); + + var actual = ""; + for (let e = 0; e < box.childNodes.length; e++) { + if (actual) + actual += " "; + actual += box.childNodes[e].getAttribute("value"); + } + is(actual, test[2], "sorted step " + (t + 1)); + + while(box.hasChildNodes()) + box.removeChild(box.firstChild); + box.removeAttribute("sortDirection"); + } + + SimpleTest.finish(); +} + +window.addEventListener("load", doTests, false); + +]]> +</script> +</window> diff --git a/dom/xul/templates/tests/chrome/test_tmpl_bindingsextendedsyntax.xul b/dom/xul/templates/tests/chrome/test_tmpl_bindingsextendedsyntax.xul new file mode 100644 index 000000000..42e9a1633 --- /dev/null +++ b/dom/xul/templates/tests/chrome/test_tmpl_bindingsextendedsyntax.xul @@ -0,0 +1,73 @@ +<?xml version="1.0"?> +<?xml-stylesheet href="chrome://global/skin" type="text/css"?> +<?xml-stylesheet href="chrome://mochikit/content/tests/SimpleTest/test.css" type="text/css"?> + +<!-- + bindings - extended syntax +--> + +<window title="XUL Template Tests" width="500" height="600" + onload="test_template();" + xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"> + <script type="application/javascript" + src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script> + + <body xmlns="http://www.w3.org/1999/xhtml" style="height: 300px; overflow: auto;"/> + + <data id="output"> + <label step="-2" id="http://www.some-fictitious-zoo.com/humans/sarah" value="Sarah "/> + <label step="2" id="http://www.some-fictitious-zoo.com/humans/sarah" value="Sarah Yarmouth"/> + <label step="-1" id="http://www.some-fictitious-zoo.com/humans/robert" value="Robert Sanderson"/> + <label step="1" id="http://www.some-fictitious-zoo.com/humans/robert" value="Robert "/> + </data> + +<script src="templates_shared.js"/> + +<script> +<![CDATA[ +SimpleTest.waitForExplicitFinish(); + +var testid ="bindings - extended syntax"; +var queryType = "rdf"; +var isTreeBuilder = false; +var needsOpen = false; +var notWorkingYet = false; +var notWorkingYetDynamic = false; +var expectedOutput = document.getElementById("output"); + +var changes = [ + // step 1 + function(targetds, root) { + targetds.Unassert(RDF.GetResource(ZOO_NS + 'humans/robert'), + RDF.GetResource(ZOO_NS + 'rdf#lastName'), + RDF.GetLiteral('Sanderson'), true); + }, + // step 2 + function(targetds, root) { + targetds.Assert(RDF.GetResource(ZOO_NS + 'humans/sarah'), + RDF.GetResource(ZOO_NS + 'rdf#lastName'), + RDF.GetLiteral('Yarmouth'), true); + } +]; +]]> +</script> + +<vbox xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul" id="root" datasources="rdf:null" ref="http://www.some-fictitious-zoo.com/humans"> +<template id="template"> +<rule> +<conditions> +<content uri="?uri"/> +<member container="?uri" child="?child"/> +<triple subject="?child" predicate="http://www.some-fictitious-zoo.com/rdf#name" object="?name"/> +</conditions> +<bindings> +<binding subject="?child" predicate="http://www.some-fictitious-zoo.com/rdf#lastName" object="?lastname"/> +</bindings> +<action> +<label uri="?child" value="?name ?lastname"/> +</action> +</rule> +</template> +</vbox> + +</window> diff --git a/dom/xul/templates/tests/chrome/test_tmpl_bindingsmultiple.xul b/dom/xul/templates/tests/chrome/test_tmpl_bindingsmultiple.xul new file mode 100644 index 000000000..2af4f89aa --- /dev/null +++ b/dom/xul/templates/tests/chrome/test_tmpl_bindingsmultiple.xul @@ -0,0 +1,80 @@ +<?xml version="1.0"?> +<?xml-stylesheet href="chrome://global/skin" type="text/css"?> +<?xml-stylesheet href="chrome://mochikit/content/tests/SimpleTest/test.css" type="text/css"?> + +<!-- + bindings - multiple +--> + +<window title="XUL Template Tests" width="500" height="600" + onload="test_template();" + xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"> + <script type="application/javascript" + src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script> + + <body xmlns="http://www.w3.org/1999/xhtml" style="height: 300px; overflow: auto;"/> + + <data id="output"> + <button id="http://www.some-fictitious-zoo.com/arachnids" container="true" empty="false" label="Arachnids "/> + <button step="-2" id="http://www.some-fictitious-zoo.com/birds" container="true" empty="false" label="Birds Sarah "/> + <button step="2" id="http://www.some-fictitious-zoo.com/birds" container="true" empty="false" label="Birds Sarah Yarmouth"/> + <button step="-1" id="http://www.some-fictitious-zoo.com/crustaceans" container="true" empty="true" label="Crustaceans Robert Sanderson"/> + <button step="1" id="http://www.some-fictitious-zoo.com/crustaceans" container="true" empty="true" label="Crustaceans Robert "/> + <button id="http://www.some-fictitious-zoo.com/fish" container="true" empty="false" label="Fish "/> + <button id="http://www.some-fictitious-zoo.com/mammals" container="true" empty="false" label="Mammals "/> + <button step="-1" id="http://www.some-fictitious-zoo.com/reptiles" container="true" empty="false" label="Reptiles Robert Sanderson"/> + <button step="1" id="http://www.some-fictitious-zoo.com/reptiles" container="true" empty="false" label="Reptiles Robert "/> + </data> + +<script src="templates_shared.js"/> + +<script> +<![CDATA[ +SimpleTest.waitForExplicitFinish(); + +var testid ="bindings - multiple"; +var queryType = "rdf"; +var isTreeBuilder = false; +var needsOpen = false; +var notWorkingYet = false; +var notWorkingYetDynamic = false; +var expectedOutput = document.getElementById("output"); + +var changes = [ + // step 1 + function(targetds, root) { + targetds.Unassert(RDF.GetResource(ZOO_NS + 'humans/robert'), + RDF.GetResource(ZOO_NS + 'rdf#lastName'), + RDF.GetLiteral('Sanderson'), true); + }, + // step 2 + function(targetds, root) { + targetds.Assert(RDF.GetResource(ZOO_NS + 'humans/sarah'), + RDF.GetResource(ZOO_NS + 'rdf#lastName'), + RDF.GetLiteral('Yarmouth'), true); + } +]; +]]> +</script> + +<vbox xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul" id="root" datasources="rdf:null" ref="http://www.some-fictitious-zoo.com/all-animals"> +<template> +<query> +<content uri="?uri"/> +<member container="?uri" child="?child"/> +</query> +<rule> +<bindings> +<binding subject="?child" predicate="http://www.some-fictitious-zoo.com/rdf#keeper" object="?keeper"/> +<binding subject="?keeper" predicate="http://www.some-fictitious-zoo.com/rdf#name" object="?keepername"/> +<binding subject="?keeper" predicate="http://www.some-fictitious-zoo.com/rdf#lastName" object="?lastname"/> +<binding subject="?child" predicate="http://www.some-fictitious-zoo.com/rdf#name" object="?name"/> +</bindings> +<action> +<button uri="?child" label="?name ?keepername ?lastname"/> +</action> +</rule> +</template> +</vbox> + +</window> diff --git a/dom/xul/templates/tests/chrome/test_tmpl_bindingsquerysyntax.xul b/dom/xul/templates/tests/chrome/test_tmpl_bindingsquerysyntax.xul new file mode 100644 index 000000000..d8b6110be --- /dev/null +++ b/dom/xul/templates/tests/chrome/test_tmpl_bindingsquerysyntax.xul @@ -0,0 +1,73 @@ +<?xml version="1.0"?> +<?xml-stylesheet href="chrome://global/skin" type="text/css"?> +<?xml-stylesheet href="chrome://mochikit/content/tests/SimpleTest/test.css" type="text/css"?> + +<!-- + bindings - query syntax +--> + +<window title="XUL Template Tests" width="500" height="600" + onload="test_template();" + xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"> + <script type="application/javascript" + src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script> + + <body xmlns="http://www.w3.org/1999/xhtml" style="height: 300px; overflow: auto;"/> + + <data id="output"> + <label step="-2" id="http://www.some-fictitious-zoo.com/humans/sarah" value="First Name: Sarah Last Name: "/> + <label step="2" id="http://www.some-fictitious-zoo.com/humans/sarah" value="First Name: Sarah Last Name: Yarmouth"/> + <label step="-1" id="http://www.some-fictitious-zoo.com/humans/robert" value="First Name: Robert Last Name: Sanderson"/> + <label step="1" id="http://www.some-fictitious-zoo.com/humans/robert" value="First Name: Robert Last Name: "/> + </data> + +<script src="templates_shared.js"/> + +<script> +<![CDATA[ +SimpleTest.waitForExplicitFinish(); + +var testid ="bindings - query syntax"; +var queryType = "rdf"; +var isTreeBuilder = false; +var needsOpen = false; +var notWorkingYet = false; +var notWorkingYetDynamic = false; +var expectedOutput = document.getElementById("output"); + +var changes = [ + // step 1 + function(targetds, root) { + targetds.Unassert(RDF.GetResource(ZOO_NS + 'humans/robert'), + RDF.GetResource(ZOO_NS + 'rdf#lastName'), + RDF.GetLiteral('Sanderson'), true); + }, + // step 2 + function(targetds, root) { + targetds.Assert(RDF.GetResource(ZOO_NS + 'humans/sarah'), + RDF.GetResource(ZOO_NS + 'rdf#lastName'), + RDF.GetLiteral('Yarmouth'), true); + } +]; +]]> +</script> + +<vbox xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul" id="root" datasources="rdf:null" ref="http://www.some-fictitious-zoo.com/humans"> +<template id="template"> +<query> +<content uri="?uri"/> +<member container="?uri" child="?child"/> +<triple subject="?child" predicate="http://www.some-fictitious-zoo.com/rdf#name" object="?name"/> +</query> +<rule id="rule"> +<bindings id="bindings"> +<binding subject="?child" predicate="http://www.some-fictitious-zoo.com/rdf#lastName" object="?lastname"/> +</bindings> +<action> +<label uri="?child" value="First Name: ?name Last Name: ?lastname"/> +</action> +</rule> +</template> +</vbox> + +</window> diff --git a/dom/xul/templates/tests/chrome/test_tmpl_bindingsreversed.xul b/dom/xul/templates/tests/chrome/test_tmpl_bindingsreversed.xul new file mode 100644 index 000000000..a7bd190a7 --- /dev/null +++ b/dom/xul/templates/tests/chrome/test_tmpl_bindingsreversed.xul @@ -0,0 +1,58 @@ +<?xml version="1.0"?> +<?xml-stylesheet href="chrome://global/skin" type="text/css"?> +<?xml-stylesheet href="chrome://mochikit/content/tests/SimpleTest/test.css" type="text/css"?> + +<!-- + bindings - reversed +--> + +<window title="XUL Template Tests" width="500" height="600" + onload="test_template();" + xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"> + <script type="application/javascript" + src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script> + + <body xmlns="http://www.w3.org/1999/xhtml" style="height: 300px; overflow: auto;"/> + + <data id="output"> + <label id="http://www.some-fictitious-zoo.com/humans/sarah" value="First Name: Sarah Last Name: "/> + <label id="http://www.some-fictitious-zoo.com/humans/robert" value="First Name: Robert Last Name: "/> + </data> + +<script src="templates_shared.js"/> + +<script> +<![CDATA[ +SimpleTest.waitForExplicitFinish(); + +var testid ="bindings - reversed"; +var queryType = "rdf"; +var isTreeBuilder = false; +var needsOpen = false; +var notWorkingYet = false; +var notWorkingYetDynamic = false; +var expectedOutput = document.getElementById("output"); + +var changes = []; +]]> +</script> + +<vbox xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul" id="root" datasources="rdf:null" ref="http://www.some-fictitious-zoo.com/humans"> +<template id="template"> +<query> +<content uri="?uri"/> +<member container="?uri" child="?child"/> +<triple subject="?child" predicate="http://www.some-fictitious-zoo.com/rdf#name" object="?name"/> +</query> +<rule id="rule"> +<bindings id="bindings"> +<binding subject="?lastname" predicate="http://www.some-fictitious-zoo.com/rdf#lastName" object="?child"/> +</bindings> +<action> +<label uri="?child" value="First Name: ?name Last Name: ?lastname"/> +</action> +</rule> +</template> +</vbox> + +</window> diff --git a/dom/xul/templates/tests/chrome/test_tmpl_bindingssameastriple.xul b/dom/xul/templates/tests/chrome/test_tmpl_bindingssameastriple.xul new file mode 100644 index 000000000..514979d59 --- /dev/null +++ b/dom/xul/templates/tests/chrome/test_tmpl_bindingssameastriple.xul @@ -0,0 +1,58 @@ +<?xml version="1.0"?> +<?xml-stylesheet href="chrome://global/skin" type="text/css"?> +<?xml-stylesheet href="chrome://mochikit/content/tests/SimpleTest/test.css" type="text/css"?> + +<!-- + bindings - same as triple +--> + +<window title="XUL Template Tests" width="500" height="600" + onload="test_template();" + xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"> + <script type="application/javascript" + src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script> + + <body xmlns="http://www.w3.org/1999/xhtml" style="height: 300px; overflow: auto;"/> + + <data id="output"> + <label id="http://www.some-fictitious-zoo.com/humans/sarah" value="First Name: Sarah Last Name: "/> + <label id="http://www.some-fictitious-zoo.com/humans/robert" value="First Name: Robert Last Name: "/> + </data> + +<script src="templates_shared.js"/> + +<script> +<![CDATA[ +SimpleTest.waitForExplicitFinish(); + +var testid ="bindings - same as triple"; +var queryType = "rdf"; +var isTreeBuilder = false; +var needsOpen = false; +var notWorkingYet = false; +var notWorkingYetDynamic = false; +var expectedOutput = document.getElementById("output"); + +var changes = []; +]]> +</script> + +<vbox xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul" id="root" datasources="rdf:null" ref="http://www.some-fictitious-zoo.com/humans"> +<template id="template"> +<query> +<content uri="?uri"/> +<member container="?uri" child="?child"/> +<triple subject="?child" predicate="http://www.some-fictitious-zoo.com/rdf#name" object="?name"/> +</query> +<rule id="rule"> +<bindings id="bindings"> +<binding subject="?child" predicate="http://www.some-fictitious-zoo.com/rdf#name" object="?name"/> +</bindings> +<action> +<label uri="?child" value="First Name: ?name Last Name: ?lastname"/> +</action> +</rule> +</template> +</vbox> + +</window> diff --git a/dom/xul/templates/tests/chrome/test_tmpl_containerandmembervariablechanged.xul b/dom/xul/templates/tests/chrome/test_tmpl_containerandmembervariablechanged.xul new file mode 100644 index 000000000..7b90d64b1 --- /dev/null +++ b/dom/xul/templates/tests/chrome/test_tmpl_containerandmembervariablechanged.xul @@ -0,0 +1,88 @@ +<?xml version="1.0"?> +<?xml-stylesheet href="chrome://global/skin" type="text/css"?> +<?xml-stylesheet href="chrome://mochikit/content/tests/SimpleTest/test.css" type="text/css"?> + +<!-- + container and member variable changed +--> + +<window title="XUL Template Tests" width="500" height="600" + onload="test_template();" + xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"> + <script type="application/javascript" + src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script> + + <body xmlns="http://www.w3.org/1999/xhtml" style="height: 300px; overflow: auto;"/> + + <data id="output"> + <button step="3" id="http://www.some-fictitious-zoo.com/birds/wren" label="http://www.some-fictitious-zoo.com/birds http://www.some-fictitious-zoo.com/birds/wren"/> + <button id="http://www.some-fictitious-zoo.com/birds/emu" label="http://www.some-fictitious-zoo.com/birds http://www.some-fictitious-zoo.com/birds/emu"/> + <button step="-4" id="http://www.some-fictitious-zoo.com/birds/barnowl" label="http://www.some-fictitious-zoo.com/birds http://www.some-fictitious-zoo.com/birds/barnowl"/> + <button id="http://www.some-fictitious-zoo.com/birds/raven" label="http://www.some-fictitious-zoo.com/birds http://www.some-fictitious-zoo.com/birds/raven"/> + <button step="2" id="http://www.some-fictitious-zoo.com/birds/archaeopteryx" label="http://www.some-fictitious-zoo.com/birds http://www.some-fictitious-zoo.com/birds/archaeopteryx"/> + <button step="1" id="http://www.some-fictitious-zoo.com/birds/emperorpenguin" label="http://www.some-fictitious-zoo.com/birds http://www.some-fictitious-zoo.com/birds/emperorpenguin"/> + </data> + +<script src="templates_shared.js"/> + +<script> +<![CDATA[ +SimpleTest.waitForExplicitFinish(); + +var testid ="container and member variable changed"; +var queryType = "rdf"; +var isTreeBuilder = false; +var needsOpen = false; +var notWorkingYet = false; +var notWorkingYetDynamic = false; +var expectedOutput = document.getElementById("output"); + +var changes = [ + // step 1 + function(targetds, root) { + var newnode = RDF.GetResource(ZOO_NS + 'birds/emperorpenguin'); + targetds.Assert(newnode, RDF.GetResource(ZOO_NS + 'rdf#name'), + RDF.GetLiteral('Emperor Penguin'), true); + var container = ContainerUtils.MakeSeq(targetds, + RDF.GetResource(ZOO_NS + 'birds')); + container.AppendElement(newnode); + }, + // step 2 + function(targetds, root) { + var newnode = RDF.GetResource(ZOO_NS + 'birds/archaeopteryx'); + targetds.Assert(newnode, RDF.GetResource(ZOO_NS + 'rdf#name'), + RDF.GetLiteral('Archaeopteryx'), true); + var container = ContainerUtils.MakeSeq(targetds, + RDF.GetResource(ZOO_NS + 'birds')); + container.InsertElementAt(newnode, '4', true); + }, + // step 3 + function(targetds, root) { + var newnode = RDF.GetResource(ZOO_NS + 'birds/wren'); + targetds.Assert(newnode, RDF.GetResource(ZOO_NS + 'rdf#name'), + RDF.GetLiteral('Wren'), true); + var container = ContainerUtils.MakeSeq(targetds, + RDF.GetResource(ZOO_NS + 'birds')); + container.InsertElementAt(newnode, '1', true); + }, + // step 4 + function(targetds, root) { + var container = ContainerUtils.MakeSeq(targetds, + RDF.GetResource(ZOO_NS + 'birds')); + var removednode = container.RemoveElementAt('3', true); + targetds.Unassert(removednode, RDF.GetResource(ZOO_NS + 'rdf#name'), + RDF.GetLiteral('Barn Owl'), true); + } +]; +]]> +</script> + +<vbox xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul" id="root" datasources="rdf:null" ref="http://www.some-fictitious-zoo.com/birds"> +<template container="?parent" member="?child"> +<rule> +<button uri="?" label="?parent ?child"/> +</rule> +</template> +</vbox> + +</window> diff --git a/dom/xul/templates/tests/chrome/test_tmpl_containervariablechanged.xul b/dom/xul/templates/tests/chrome/test_tmpl_containervariablechanged.xul new file mode 100644 index 000000000..f9100047f --- /dev/null +++ b/dom/xul/templates/tests/chrome/test_tmpl_containervariablechanged.xul @@ -0,0 +1,49 @@ +<?xml version="1.0"?> +<?xml-stylesheet href="chrome://global/skin" type="text/css"?> +<?xml-stylesheet href="chrome://mochikit/content/tests/SimpleTest/test.css" type="text/css"?> + +<!-- + container variable changed +--> + +<window title="XUL Template Tests" width="500" height="600" + onload="test_template();" + xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"> + <script type="application/javascript" + src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script> + + <body xmlns="http://www.w3.org/1999/xhtml" style="height: 300px; overflow: auto;"/> + + <data id="output"> + <button id="http://www.some-fictitious-zoo.com/birds/emu" label="http://www.some-fictitious-zoo.com/birds "/> + <button id="http://www.some-fictitious-zoo.com/birds/barnowl" label="http://www.some-fictitious-zoo.com/birds "/> + <button id="http://www.some-fictitious-zoo.com/birds/raven" label="http://www.some-fictitious-zoo.com/birds "/> + </data> + +<script src="templates_shared.js"/> + +<script> +<![CDATA[ +SimpleTest.waitForExplicitFinish(); + +var testid ="container variable changed"; +var queryType = "rdf"; +var isTreeBuilder = false; +var needsOpen = false; +var notWorkingYet = false; +var notWorkingYetDynamic = false; +var expectedOutput = document.getElementById("output"); + +var changes = []; +]]> +</script> + +<vbox xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul" id="root" datasources="rdf:null" ref="http://www.some-fictitious-zoo.com/birds"> +<template container="?parent"> +<rule> +<button uri="?" label="?parent ?child"/> +</rule> +</template> +</vbox> + +</window> diff --git a/dom/xul/templates/tests/chrome/test_tmpl_containmentattribute.xul b/dom/xul/templates/tests/chrome/test_tmpl_containmentattribute.xul new file mode 100644 index 000000000..909a05e34 --- /dev/null +++ b/dom/xul/templates/tests/chrome/test_tmpl_containmentattribute.xul @@ -0,0 +1,71 @@ +<?xml version="1.0"?> +<?xml-stylesheet href="chrome://global/skin" type="text/css"?> +<?xml-stylesheet href="chrome://mochikit/content/tests/SimpleTest/test.css" type="text/css"?> + +<!-- + containment attribute +--> + +<window title="XUL Template Tests" width="500" height="600" + onload="test_template();" + xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"> + <script type="application/javascript" + src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script> + + <body xmlns="http://www.w3.org/1999/xhtml" style="height: 300px; overflow: auto;"/> + + <data id="output" unordered="true"> + <checkbox step="-1" id="http://www.some-fictitious-zoo.com/arachnids/tarantula" label="Tarantula"/> + <checkbox step="2" id="http://www.some-fictitious-zoo.com/mammals/lion" label="Lion"/> + <checkbox id="http://www.some-fictitious-zoo.com/reptiles/anaconda" label="Anaconda"/> + <checkbox id="http://www.some-fictitious-zoo.com/reptiles/chameleon" label="Chameleon"/> + <checkbox id="http://www.some-fictitious-zoo.com/mammals/africanelephant" label="African Elephant"/> + </data> + +<script src="templates_shared.js"/> + +<script> +<![CDATA[ +SimpleTest.waitForExplicitFinish(); + +var testid ="containment attribute"; +var queryType = "rdf"; +var isTreeBuilder = false; +var needsOpen = false; +var notWorkingYet = false; +var notWorkingYetDynamic = false; +var expectedOutput = document.getElementById("output"); + +var changes = [ + // step 1 + function(targetds, root) { + targetds.Unassert(RDF.GetResource(ZOO_NS + 'humans/robert'), + RDF.GetResource(ZOO_NS + 'rdf#favoriteAnimal'), + RDF.GetResource(ZOO_NS + 'arachnids/tarantula'), true); + }, + // step 2 + function(targetds, root) { + targetds.Assert(RDF.GetResource(ZOO_NS + 'humans/robert'), + RDF.GetResource(ZOO_NS + 'rdf#favoriteAnimal'), + RDF.GetResource(ZOO_NS + 'mammals/lion'), true); + } +]; +]]> +</script> + +<vbox xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul" id="root" datasources="rdf:null" ref="http://www.some-fictitious-zoo.com/humans/robert" containment="http://www.some-fictitious-zoo.com/rdf#favoriteAnimal"> +<template id="template"> +<rule id="rule"> +<conditions> +<content uri="?uri"/> +<member container="?uri" child="?child"/> +<triple subject="?child" predicate="http://www.some-fictitious-zoo.com/rdf#name" object="?name"/> +</conditions> +<action> +<checkbox uri="?child" label="?name"/> +</action> +</rule> +</template> +</vbox> + +</window> diff --git a/dom/xul/templates/tests/chrome/test_tmpl_defaultcontainervariableisuri.xul b/dom/xul/templates/tests/chrome/test_tmpl_defaultcontainervariableisuri.xul new file mode 100644 index 000000000..933c51bc0 --- /dev/null +++ b/dom/xul/templates/tests/chrome/test_tmpl_defaultcontainervariableisuri.xul @@ -0,0 +1,49 @@ +<?xml version="1.0"?> +<?xml-stylesheet href="chrome://global/skin" type="text/css"?> +<?xml-stylesheet href="chrome://mochikit/content/tests/SimpleTest/test.css" type="text/css"?> + +<!-- + default container variable is ?uri +--> + +<window title="XUL Template Tests" width="500" height="600" + onload="test_template();" + xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"> + <script type="application/javascript" + src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script> + + <body xmlns="http://www.w3.org/1999/xhtml" style="height: 300px; overflow: auto;"/> + + <data id="output"> + <button id="http://www.some-fictitious-zoo.com/birds/emu" label="http://www.some-fictitious-zoo.com/birds"/> + <button id="http://www.some-fictitious-zoo.com/birds/barnowl" label="http://www.some-fictitious-zoo.com/birds"/> + <button id="http://www.some-fictitious-zoo.com/birds/raven" label="http://www.some-fictitious-zoo.com/birds"/> + </data> + +<script src="templates_shared.js"/> + +<script> +<![CDATA[ +SimpleTest.waitForExplicitFinish(); + +var testid ="default container variable is ?uri"; +var queryType = "rdf"; +var isTreeBuilder = false; +var needsOpen = false; +var notWorkingYet = false; +var notWorkingYetDynamic = false; +var expectedOutput = document.getElementById("output"); + +var changes = []; +]]> +</script> + +<vbox xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul" id="root" datasources="rdf:null" ref="http://www.some-fictitious-zoo.com/birds"> +<template> +<rule> +<button uri="?uri" label="?uri"/> +</rule> +</template> +</vbox> + +</window> diff --git a/dom/xul/templates/tests/chrome/test_tmpl_errors.xul b/dom/xul/templates/tests/chrome/test_tmpl_errors.xul new file mode 100644 index 000000000..f3b58502d --- /dev/null +++ b/dom/xul/templates/tests/chrome/test_tmpl_errors.xul @@ -0,0 +1,280 @@ +<?xml version="1.0"?> +<?xml-stylesheet href="chrome://global/skin" type="text/css"?> +<?xml-stylesheet href="chrome://mochikit/content/tests/SimpleTest/test.css" type="text/css"?> + +<!-- + tests for templates with invalid syntax +--> + +<window title="XUL Invalid Template Tests" width="500" height="600" + onload="runTest();" + xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"> + <script type="application/javascript" + src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script> + + <body xmlns="http://www.w3.org/1999/xhtml" style="height: 300px; overflow: auto;"/> + +<script> +<![CDATA[ +SimpleTest.waitForExplicitFinish(); + +var consoleService = Components.classes["@mozilla.org/consoleservice;1"]. + getService(Components.interfaces.nsIConsoleService); + +function checkConsole(expectedError) +{ + var message = consoleService.getMessageArray()[0].message; + is(message, expectedError, "logged message " + expectedError); +} + +// each test consists of a pre function executed before the template build, an +// expected error message, and a post function executed after the template build +var tests = [ + +// <queryset> used in invalid location +{ + pre: template => template.insertBefore(document.createElement("queryset"), template.lastChild), + error: "Error parsing template: unexpected <queryset> element", + post: queryset => queryset.parentNode.removeChild(queryset) +}, + +// no member variable found +{ + pre: template => $("action").firstChild.removeAttribute("uri"), + error: "Error parsing template: no member variable found. Action body should have an element with uri attribute", + post: () => $("action").firstChild.setAttribute("uri", "?child") +}, + +// bad binding subject +{ + pre: template => $("binding").removeAttribute("subject"), + error: "Error parsing template: <binding> requires a variable for its subject attribute", + post: () => $("binding").setAttribute("subject", "?child"), +}, + +// bad binding predicate +{ + pre: template => $("binding").removeAttribute("predicate"), + error: "Error parsing template: <binding> element is missing a predicate attribute", + post: () => $("binding").setAttribute("predicate", "http://www.some-fictitious-zoo.com/rdf#name"), +}, + +// bad binding object +{ + pre: template => $("binding").setAttribute("object", "blah"), + error: "Error parsing template: <binding> requires a variable for its object attribute", + post: () => $("binding").setAttribute("object", "?name"), +}, + +// where condition missing a subject +{ + pre: function(template) { var rule = $("rule"); + var where = document.createElement("where"); + where.setAttribute("subject", ""); + where.setAttribute("rel", "equals"); + where.setAttribute("value", "Raven"); + rule.appendChild(where); + return where; }, + error: "Error parsing template: <where> element is missing a subject attribute", + post: function(where) { where.parentNode.removeChild(where); } +}, + +// where condition missing a rel +{ + pre: function(template) { var rule = $("rule"); + var where = document.createElement("where"); + where.setAttribute("subject", "?name"); + where.setAttribute("rel", ""); + where.setAttribute("value", "Raven"); + rule.appendChild(where); + return where; }, + error: "Error parsing template: <where> element is missing a rel attribute", + post: function(where) { where.parentNode.removeChild(where); } +}, + +// where condition missing a value +{ + pre: function(template) { var rule = $("rule"); + var where = document.createElement("where"); + where.setAttribute("subject", "?name"); + where.setAttribute("rel", "equals"); + where.setAttribute("value", ""); + rule.appendChild(where); + return where; }, + error: "Error parsing template: <where> element is missing a value attribute", + post: function(where) { where.parentNode.removeChild(where); } +}, + +// where condition missing a variable +{ + pre: function(template) { var rule = $("rule"); + var where = document.createElement("where"); + where.setAttribute("subject", "name"); + where.setAttribute("rel", "equals"); + where.setAttribute("value", "Raven"); + rule.appendChild(where); + return where; }, + error: "Error parsing template: <where> element must have at least one variable as a subject or value", + post: function(where) { where.parentNode.removeChild(where); } +}, + +// bad member container +{ + pre: template => $("member").setAttribute("container", "blah"), + error: "Error parsing template: <member> requires a variable for its container attribute", + post: () => $("member").setAttribute("container", "?uri"), +}, + +// bad member child +{ + pre: template => $("member").setAttribute("child", "blah"), + error: "Error parsing template: <member> requires a variable for its child attribute", + post: () => $("member").setAttribute("child", "?child"), +}, + +// bad triple subject +{ + pre: template => $("triple").removeAttribute("subject"), + error: "Error parsing template: <triple> requires a variable for its subject attribute", + post: () => $("triple").setAttribute("subject", "?child"), +}, + +// missing triple predicate +{ + pre: template => $("triple").removeAttribute("predicate"), + error: "Error parsing template: <triple> should have a non-variable value as a predicate", + post: () => $("triple").setAttribute("predicate", "http://www.some-fictitious-zoo.com/rdf#name"), +}, + +// bad triple predicate +{ + pre: template => $("triple").setAttribute("predicate", "?predicate"), + error: "Error parsing template: <triple> should have a non-variable value as a predicate", + post: () => $("triple").setAttribute("predicate", "http://www.some-fictitious-zoo.com/rdf#name"), +}, + +// bad triple object +{ + pre: template => $("triple").removeAttribute("object"), + error: "Error parsing template: <triple> requires a variable for its object attribute", + post: () => $("triple").setAttribute("object", "?name"), +}, + +// content not first element in query +{ + pre: function(template) { var content = $("content"); content.parentNode.appendChild(content); return content; }, + error: "Error parsing template: expected <content> to be first", + post: content => content.parentNode.insertBefore(content, content.parentNode.firstChild), +}, + +// member container variable not bound +{ + pre: template => $("member").removeAttribute("container"), + error: "Error parsing template: neither container or child variables of <member> has a value", + post: () => $("member").setAttribute("container", "?uri"), +}, + +// neither triple subject or object variable are bound +{ + pre: template => $("triple").setAttribute("subject", "?blah"), + error: "Error parsing template: neither subject or object variables of <triple> has a value", + post: () => $("triple").setAttribute("subject", "?child"), +}, + +// neither triple subject or object variable are bound +{ + pre: function(template) { var triple = $("triple"); triple.setAttribute("subject", "blah"); + triple.setAttribute("object", "blah"); }, + error: "Error parsing template: <triple> should have at least one variable as a subject or object", + post: function() { var triple = $("triple"); triple.setAttribute("subject", "?uri"); + triple.setAttribute("object", "?uri") } +}, + +// could not parse xml query expression +{ + firstXMLTest: true, + pre: function(template) { $("query").setAttribute("expr", "something()"); }, + error: "Error parsing template: XPath expression in query could not be parsed", + post: function() { } +}, + +// could not parse xml assign expression +{ + pre: function(template) { var query = $("query"); + query.setAttribute("expr", "*"); + var assign = document.createElement("assign"); + assign.setAttribute("var", "?name"); + assign.setAttribute("expr", "something()"); + query.appendChild(assign); + return assign; }, + error: "Error parsing template: XPath expression in <assign> could not be parsed", + post: function(assign) { assign.parentNode.removeChild(assign); } +}, + +// could not parse xml binding expression +{ + pre: function(template) { $("binding").setAttribute("predicate", "something()"); }, + error: "Error parsing template: XPath expression in <binding> could not be parsed", + post: function() { $("binding").setAttribute("predicate", "[name]"); }, +}, + +]; + +function runTest() +{ + var root = $("root"); + var template = $("template"); + while (test = tests.shift()) { + consoleService.reset(); + var context = test.pre(template); + root.builder.rebuild(); + checkConsole(test.error); + test.post(context); + + // preload and set up for the xml datasource query error tests + if (tests.length && tests[0].firstXMLTest) { + var src = window.location.href.replace(/test_tmpl.*xul/, "animals.xml"); + xmlDoc = new XMLHttpRequest(); + xmlDoc.open("get", src, false); + xmlDoc.send(null); + + var root = $("root"); + root.setAttribute("querytype", "xml"); + root.setAttribute("datasources", "animals.xml"); + $("binding").setAttribute("predicate", "[name]"); + + function waitForDatasource() { + // wait for the datasource to be available before continuing the test + if (root.builder.datasource instanceof XMLDocument) + runTest(); + else + setTimeout(waitForDatasource, 100); + } + + setTimeout(waitForDatasource, 0); + return; + } + } + SimpleTest.finish(); +} + +]]> +</script> + +<vbox id="root" datasources="animals.rdf" ref="http://www.some-fictitious-zoo.com/birds"> +<template id="template"> + <query id="query"> + <content id="content" uri="?uri"/> + <member id="member" container="?uri" child="?child"/> + <triple id="triple" subject="?child" predicate="http://www.some-fictitious-zoo.com/rdf#name" object="?name"/> + </query> + <rule id="rule"> + <binding id="binding" subject="?child" predicate="http://www.some-fictitious-zoo.com/rdf#name" object="?name"/> + <action id="action"> + <label uri="?child" value="?name"/> + </action> + </rule> +</template> +</vbox> + +</window> diff --git a/dom/xul/templates/tests/chrome/test_tmpl_extendedsyntax.xul b/dom/xul/templates/tests/chrome/test_tmpl_extendedsyntax.xul new file mode 100644 index 000000000..1bd31525e --- /dev/null +++ b/dom/xul/templates/tests/chrome/test_tmpl_extendedsyntax.xul @@ -0,0 +1,95 @@ +<?xml version="1.0"?> +<?xml-stylesheet href="chrome://global/skin" type="text/css"?> +<?xml-stylesheet href="chrome://mochikit/content/tests/SimpleTest/test.css" type="text/css"?> + +<!-- + extended syntax +--> + +<window title="XUL Template Tests" width="500" height="600" + onload="test_template();" + xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"> + <script type="application/javascript" + src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script> + + <body xmlns="http://www.w3.org/1999/xhtml" style="height: 300px; overflow: auto;"/> + + <data id="output"> + <label step="3" id="http://www.some-fictitious-zoo.com/birds/wren" value="Wren"/> + <label id="http://www.some-fictitious-zoo.com/birds/emu" value="Emu"/> + <label step="-4" id="http://www.some-fictitious-zoo.com/birds/barnowl" value="Barn Owl"/> + <label id="http://www.some-fictitious-zoo.com/birds/raven" value="Raven"/> + <label step="2" id="http://www.some-fictitious-zoo.com/birds/archaeopteryx" value="Archaeopteryx"/> + <label step="1" id="http://www.some-fictitious-zoo.com/birds/emperorpenguin" value="Emperor Penguin"/> + </data> + +<script src="templates_shared.js"/> + +<script> +<![CDATA[ +SimpleTest.waitForExplicitFinish(); + +var testid ="extended syntax"; +var queryType = "rdf"; +var isTreeBuilder = false; +var needsOpen = false; +var notWorkingYet = false; +var notWorkingYetDynamic = false; +var expectedOutput = document.getElementById("output"); + +var changes = [ + // step 1 + function(targetds, root) { + var newnode = RDF.GetResource(ZOO_NS + 'birds/emperorpenguin'); + targetds.Assert(newnode, RDF.GetResource(ZOO_NS + 'rdf#name'), + RDF.GetLiteral('Emperor Penguin'), true); + var container = ContainerUtils.MakeSeq(targetds, + RDF.GetResource(ZOO_NS + 'birds')); + container.AppendElement(newnode); + }, + // step 2 + function(targetds, root) { + var newnode = RDF.GetResource(ZOO_NS + 'birds/archaeopteryx'); + targetds.Assert(newnode, RDF.GetResource(ZOO_NS + 'rdf#name'), + RDF.GetLiteral('Archaeopteryx'), true); + var container = ContainerUtils.MakeSeq(targetds, + RDF.GetResource(ZOO_NS + 'birds')); + container.InsertElementAt(newnode, '4', true); + }, + // step 3 + function(targetds, root) { + var newnode = RDF.GetResource(ZOO_NS + 'birds/wren'); + targetds.Assert(newnode, RDF.GetResource(ZOO_NS + 'rdf#name'), + RDF.GetLiteral('Wren'), true); + var container = ContainerUtils.MakeSeq(targetds, + RDF.GetResource(ZOO_NS + 'birds')); + container.InsertElementAt(newnode, '1', true); + }, + // step 4 + function(targetds, root) { + var container = ContainerUtils.MakeSeq(targetds, + RDF.GetResource(ZOO_NS + 'birds')); + var removednode = container.RemoveElementAt('3', true); + targetds.Unassert(removednode, RDF.GetResource(ZOO_NS + 'rdf#name'), + RDF.GetLiteral('Barn Owl'), true); + } +]; +]]> +</script> + +<vbox xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul" id="root" datasources="rdf:null" ref="http://www.some-fictitious-zoo.com/birds"> +<template id="template"> +<rule id="rule"> +<conditions id="conditions"> +<content uri="?uri"/> +<member container="?uri" child="?animal"/> +<triple subject="?animal" predicate="http://www.some-fictitious-zoo.com/rdf#name" object="?name"/> +</conditions> +<action id="action"> +<label uri="?animal" value="?name"/> +</action> +</rule> +</template> +</vbox> + +</window> diff --git a/dom/xul/templates/tests/chrome/test_tmpl_extendedsyntaxemptyconditions.xul b/dom/xul/templates/tests/chrome/test_tmpl_extendedsyntaxemptyconditions.xul new file mode 100644 index 000000000..8e0e37c3a --- /dev/null +++ b/dom/xul/templates/tests/chrome/test_tmpl_extendedsyntaxemptyconditions.xul @@ -0,0 +1,48 @@ +<?xml version="1.0"?> +<?xml-stylesheet href="chrome://global/skin" type="text/css"?> +<?xml-stylesheet href="chrome://mochikit/content/tests/SimpleTest/test.css" type="text/css"?> + +<!-- + extended syntax - empty conditions +--> + +<window title="XUL Template Tests" width="500" height="600" + onload="test_template();" + xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"> + <script type="application/javascript" + src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script> + + <body xmlns="http://www.w3.org/1999/xhtml" style="height: 300px; overflow: auto;"/> + + <data id="output"/> + +<script src="templates_shared.js"/> + +<script> +<![CDATA[ +SimpleTest.waitForExplicitFinish(); + +var testid ="extended syntax - empty conditions"; +var queryType = "rdf"; +var isTreeBuilder = false; +var needsOpen = false; +var notWorkingYet = false; +var notWorkingYetDynamic = false; +var expectedOutput = document.getElementById("output"); + +var changes = []; +]]> +</script> + +<vbox xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul" id="root" datasources="rdf:null" ref="http://www.some-fictitious-zoo.com/birds"> +<template id="template"> +<rule id="rule"> +<conditions id="conditions"/> +<action id="action"> +<label uri="?animal" value="?name"/> +</action> +</rule> +</template> +</vbox> + +</window> diff --git a/dom/xul/templates/tests/chrome/test_tmpl_extendedsyntaxotherrefvariable.xul b/dom/xul/templates/tests/chrome/test_tmpl_extendedsyntaxotherrefvariable.xul new file mode 100644 index 000000000..6895034f2 --- /dev/null +++ b/dom/xul/templates/tests/chrome/test_tmpl_extendedsyntaxotherrefvariable.xul @@ -0,0 +1,95 @@ +<?xml version="1.0"?> +<?xml-stylesheet href="chrome://global/skin" type="text/css"?> +<?xml-stylesheet href="chrome://mochikit/content/tests/SimpleTest/test.css" type="text/css"?> + +<!-- + extended syntax - other ref variable +--> + +<window title="XUL Template Tests" width="500" height="600" + onload="test_template();" + xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"> + <script type="application/javascript" + src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script> + + <body xmlns="http://www.w3.org/1999/xhtml" style="height: 300px; overflow: auto;"/> + + <data id="output"> + <label step="3" id="http://www.some-fictitious-zoo.com/birds/wren" value="Wren"/> + <label id="http://www.some-fictitious-zoo.com/birds/emu" value="Emu"/> + <label step="-4" id="http://www.some-fictitious-zoo.com/birds/barnowl" value="Barn Owl"/> + <label id="http://www.some-fictitious-zoo.com/birds/raven" value="Raven"/> + <label step="2" id="http://www.some-fictitious-zoo.com/birds/archaeopteryx" value="Archaeopteryx"/> + <label step="1" id="http://www.some-fictitious-zoo.com/birds/emperorpenguin" value="Emperor Penguin"/> + </data> + +<script src="templates_shared.js"/> + +<script> +<![CDATA[ +SimpleTest.waitForExplicitFinish(); + +var testid ="extended syntax - other ref variable"; +var queryType = "rdf"; +var isTreeBuilder = false; +var needsOpen = false; +var notWorkingYet = false; +var notWorkingYetDynamic = false; +var expectedOutput = document.getElementById("output"); + +var changes = [ + // step 1 + function(targetds, root) { + var newnode = RDF.GetResource(ZOO_NS + 'birds/emperorpenguin'); + targetds.Assert(newnode, RDF.GetResource(ZOO_NS + 'rdf#name'), + RDF.GetLiteral('Emperor Penguin'), true); + var container = ContainerUtils.MakeSeq(targetds, + RDF.GetResource(ZOO_NS + 'birds')); + container.AppendElement(newnode); + }, + // step 2 + function(targetds, root) { + var newnode = RDF.GetResource(ZOO_NS + 'birds/archaeopteryx'); + targetds.Assert(newnode, RDF.GetResource(ZOO_NS + 'rdf#name'), + RDF.GetLiteral('Archaeopteryx'), true); + var container = ContainerUtils.MakeSeq(targetds, + RDF.GetResource(ZOO_NS + 'birds')); + container.InsertElementAt(newnode, '4', true); + }, + // step 3 + function(targetds, root) { + var newnode = RDF.GetResource(ZOO_NS + 'birds/wren'); + targetds.Assert(newnode, RDF.GetResource(ZOO_NS + 'rdf#name'), + RDF.GetLiteral('Wren'), true); + var container = ContainerUtils.MakeSeq(targetds, + RDF.GetResource(ZOO_NS + 'birds')); + container.InsertElementAt(newnode, '1', true); + }, + // step 4 + function(targetds, root) { + var container = ContainerUtils.MakeSeq(targetds, + RDF.GetResource(ZOO_NS + 'birds')); + var removednode = container.RemoveElementAt('3', true); + targetds.Unassert(removednode, RDF.GetResource(ZOO_NS + 'rdf#name'), + RDF.GetLiteral('Barn Owl'), true); + } +]; +]]> +</script> + +<vbox xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul" id="root" datasources="rdf:null" ref="http://www.some-fictitious-zoo.com/birds"> +<template id="template"> +<rule id="rule"> +<conditions id="conditions"> +<content uri="?start"/> +<member container="?start" child="?animal"/> +<triple subject="?animal" predicate="http://www.some-fictitious-zoo.com/rdf#name" object="?name"/> +</conditions> +<action id="action"> +<label uri="?animal" value="?name"/> +</action> +</rule> +</template> +</vbox> + +</window> diff --git a/dom/xul/templates/tests/chrome/test_tmpl_extendedsyntaxremoveunmatched.xul b/dom/xul/templates/tests/chrome/test_tmpl_extendedsyntaxremoveunmatched.xul new file mode 100644 index 000000000..b2ef77d9e --- /dev/null +++ b/dom/xul/templates/tests/chrome/test_tmpl_extendedsyntaxremoveunmatched.xul @@ -0,0 +1,55 @@ +<?xml version="1.0"?> +<?xml-stylesheet href="chrome://global/skin" type="text/css"?> +<?xml-stylesheet href="chrome://mochikit/content/tests/SimpleTest/test.css" type="text/css"?> + +<!-- + extended syntax, remove unmatched +--> + +<window title="XUL Template Tests" width="500" height="600" + onload="test_template();" + xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"> + <script type="application/javascript" + src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script> + + <body xmlns="http://www.w3.org/1999/xhtml" style="height: 300px; overflow: auto;"/> + + <data id="output"> + <label id="http://www.some-fictitious-zoo.com/humans/robert" value="Robert Sanderson"/> + </data> + +<script src="templates_shared.js"/> + +<script> +<![CDATA[ +SimpleTest.waitForExplicitFinish(); + +var testid ="extended syntax, remove unmatched"; +var queryType = "rdf"; +var isTreeBuilder = false; +var needsOpen = false; +var notWorkingYet = false; +var notWorkingYetDynamic = false; +var expectedOutput = document.getElementById("output"); + +var changes = []; +]]> +</script> + +<vbox xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul" id="root" datasources="rdf:null" ref="http://www.some-fictitious-zoo.com/humans"> +<template id="template"> +<rule> +<conditions> +<content uri="?uri"/> +<member container="?uri" child="?human"/> +<triple subject="?human" predicate="http://www.some-fictitious-zoo.com/rdf#name" object="?name"/> +<triple subject="?human" predicate="http://www.some-fictitious-zoo.com/rdf#lastName" object="?lastname"/> +</conditions> +<action id="action"> +<label uri="?human" value="?name ?lastname"/> +</action> +</rule> +</template> +</vbox> + +</window> diff --git a/dom/xul/templates/tests/chrome/test_tmpl_extendedsyntaxsimplevariablesubstitution.xul b/dom/xul/templates/tests/chrome/test_tmpl_extendedsyntaxsimplevariablesubstitution.xul new file mode 100644 index 000000000..d38bd96c0 --- /dev/null +++ b/dom/xul/templates/tests/chrome/test_tmpl_extendedsyntaxsimplevariablesubstitution.xul @@ -0,0 +1,54 @@ +<?xml version="1.0"?> +<?xml-stylesheet href="chrome://global/skin" type="text/css"?> +<?xml-stylesheet href="chrome://mochikit/content/tests/SimpleTest/test.css" type="text/css"?> + +<!-- + extended syntax - simple variable substitution +--> + +<window title="XUL Template Tests" width="500" height="600" + onload="test_template();" + xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"> + <script type="application/javascript" + src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script> + + <body xmlns="http://www.w3.org/1999/xhtml" style="height: 300px; overflow: auto;"/> + + <data id="output"> + <label id="http://www.some-fictitious-zoo.com/arachnids/tarantula" value=""/> + </data> + +<script src="templates_shared.js"/> + +<script> +<![CDATA[ +SimpleTest.waitForExplicitFinish(); + +var testid ="extended syntax - simple variable substitution"; +var queryType = "rdf"; +var isTreeBuilder = false; +var needsOpen = false; +var notWorkingYet = false; +var notWorkingYetDynamic = false; +var expectedOutput = document.getElementById("output"); + +var changes = []; +]]> +</script> + +<vbox xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul" id="root" datasources="rdf:null" ref="http://www.some-fictitious-zoo.com/arachnids"> +<template id="template"> +<rule id="rule"> +<conditions id="conditions"> +<content uri="?start"/> +<member container="?start" child="?animal"/> +<triple subject="?animal" predicate="http://www.some-fictitious-zoo.com/rdf#name" object="?name"/> +</conditions> +<action id="action"> +<label uri="?animal" value="rdf:http://www.some-fictitious-zoo.com/rdf#name"/> +</action> +</rule> +</template> +</vbox> + +</window> diff --git a/dom/xul/templates/tests/chrome/test_tmpl_extendedsyntaxtworulesrecurse.xul b/dom/xul/templates/tests/chrome/test_tmpl_extendedsyntaxtworulesrecurse.xul new file mode 100644 index 000000000..d0e4faadf --- /dev/null +++ b/dom/xul/templates/tests/chrome/test_tmpl_extendedsyntaxtworulesrecurse.xul @@ -0,0 +1,81 @@ +<?xml version="1.0"?> +<?xml-stylesheet href="chrome://global/skin" type="text/css"?> +<?xml-stylesheet href="chrome://mochikit/content/tests/SimpleTest/test.css" type="text/css"?> + +<!-- + extended syntax - two rules recurse +--> + +<window title="XUL Template Tests" width="500" height="600" + onload="test_template();" + xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"> + <script type="application/javascript" + src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script> + + <body xmlns="http://www.w3.org/1999/xhtml" style="height: 300px; overflow: auto;"/> + + <data id="output"> + <vbox id="http://www.some-fictitious-zoo.com/humans/sarah"> + <label value="The favorite animals of Sarah"/> + <label id="http://www.some-fictitious-zoo.com/birds/emu" class="indent" value="Emu which belongs to the class Birds"/> + <label id="http://www.some-fictitious-zoo.com/mammals/polarbear" class="indent" value="Polar Bear which belongs to the class Mammals"/> + <label id="http://www.some-fictitious-zoo.com/arachnids/tarantula" class="indent" value="Tarantula which belongs to the class Arachnids"/> + </vbox> + <vbox id="http://www.some-fictitious-zoo.com/humans/robert"> + <label value="The favorite animals of Robert"/> + <label id="http://www.some-fictitious-zoo.com/arachnids/tarantula" class="indent" value="Tarantula which belongs to the class Arachnids"/> + <label id="http://www.some-fictitious-zoo.com/reptiles/anaconda" class="indent" value="Anaconda which belongs to the class Reptiles"/> + <label id="http://www.some-fictitious-zoo.com/reptiles/chameleon" class="indent" value="Chameleon which belongs to the class Reptiles"/> + <label id="http://www.some-fictitious-zoo.com/mammals/africanelephant" class="indent" value="African Elephant which belongs to the class Mammals"/> + </vbox> + </data> + +<script src="templates_shared.js"/> + +<script> +<![CDATA[ +SimpleTest.waitForExplicitFinish(); + +var testid ="extended syntax - two rules recurse"; +var queryType = "rdf"; +var isTreeBuilder = false; +var needsOpen = false; +var notWorkingYet = false; +var notWorkingYetDynamic = false; +var expectedOutput = document.getElementById("output"); + +var changes = []; +]]> +</script> + +<vbox xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul" id="root" datasources="rdf:null" ref="http://www.some-fictitious-zoo.com/humans"> +<template> +<rule> +<conditions> +<content uri="?uri"/> +<member container="?uri" child="?child"/> +<triple subject="?child" predicate="http://www.some-fictitious-zoo.com/rdf#name" object="?name"/> +</conditions> +<action> +<vbox uri="?child"> +<label value="The favorite animals of ?name"/> +</vbox> +</action> +</rule> +<rule> +<conditions> +<content uri="?uri"/> +<triple subject="?uri" predicate="http://www.some-fictitious-zoo.com/rdf#favoriteAnimal" object="?child"/> +<member container="?animalClass" child="?child"/> +<triple subject="?animalClass" predicate="http://www.w3.org/1999/02/22-rdf-syntax-ns#type" object="http://www.some-fictitious-zoo.com/rdf#Class"/> +<triple subject="?child" predicate="http://www.some-fictitious-zoo.com/rdf#name" object="?name"/> +<triple subject="?animalClass" predicate="http://www.some-fictitious-zoo.com/rdf#name" object="?animalClassName"/> +</conditions> +<action> +<label uri="?child" class="indent" value="?name which belongs to the class ?animalClassName"/> +</action> +</rule> +</template> +</vbox> + +</window> diff --git a/dom/xul/templates/tests/chrome/test_tmpl_extendedsyntaxusinganinterveningcontainer.xul b/dom/xul/templates/tests/chrome/test_tmpl_extendedsyntaxusinganinterveningcontainer.xul new file mode 100644 index 000000000..2e9ce8a2f --- /dev/null +++ b/dom/xul/templates/tests/chrome/test_tmpl_extendedsyntaxusinganinterveningcontainer.xul @@ -0,0 +1,60 @@ +<?xml version="1.0"?> +<?xml-stylesheet href="chrome://global/skin" type="text/css"?> +<?xml-stylesheet href="chrome://mochikit/content/tests/SimpleTest/test.css" type="text/css"?> + +<!-- + extended syntax using an intervening container +--> + +<window title="XUL Template Tests" width="500" height="600" + onload="test_template();" + xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"> + <script type="application/javascript" + src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script> + + <body xmlns="http://www.w3.org/1999/xhtml" style="height: 300px; overflow: auto;"/> + + <data id="output"> + <groupbox> + <label id="http://www.some-fictitious-zoo.com/birds/emu" value="Emu"/> + <label id="http://www.some-fictitious-zoo.com/birds/barnowl" value="Barn Owl"/> + <label id="http://www.some-fictitious-zoo.com/birds/raven" value="Raven"/> + </groupbox> + </data> + +<script src="templates_shared.js"/> + +<script> +<![CDATA[ +SimpleTest.waitForExplicitFinish(); + +var testid ="extended syntax using an intervening container"; +var queryType = "rdf"; +var isTreeBuilder = false; +var needsOpen = false; +var notWorkingYet = false; +var notWorkingYetDynamic = false; +var expectedOutput = document.getElementById("output"); + +var changes = []; +]]> +</script> + +<vbox xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul" id="root" datasources="rdf:null" ref="http://www.some-fictitious-zoo.com/birds"> +<template id="template"> +<rule id="rule"> +<conditions id="conditions"> +<content uri="?start"/> +<member container="?start" child="?animal"/> +<triple subject="?animal" predicate="http://www.some-fictitious-zoo.com/rdf#name" object="?name"/> +</conditions> +<action id="action"> +<groupbox> +<label uri="?animal" value="?name"/> +</groupbox> +</action> +</rule> +</template> +</vbox> + +</window> diff --git a/dom/xul/templates/tests/chrome/test_tmpl_extendedvariablesubstitution.xul b/dom/xul/templates/tests/chrome/test_tmpl_extendedvariablesubstitution.xul new file mode 100644 index 000000000..deee822dd --- /dev/null +++ b/dom/xul/templates/tests/chrome/test_tmpl_extendedvariablesubstitution.xul @@ -0,0 +1,54 @@ +<?xml version="1.0"?> +<?xml-stylesheet href="chrome://global/skin" type="text/css"?> +<?xml-stylesheet href="chrome://mochikit/content/tests/SimpleTest/test.css" type="text/css"?> + +<!-- + extended variable substitution +--> + +<window title="XUL Template Tests" width="500" height="600" + onload="test_template();" + xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"> + <script type="application/javascript" + src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script> + + <body xmlns="http://www.w3.org/1999/xhtml" style="height: 300px; overflow: auto;"/> + + <data id="output"> + <label id="http://www.some-fictitious-zoo.com/arachnids/tarantula" value="Tarantula? - TarantulaTarantula^ Test"/> + </data> + +<script src="templates_shared.js"/> + +<script> +<![CDATA[ +SimpleTest.waitForExplicitFinish(); + +var testid ="extended variable substitution"; +var queryType = "rdf"; +var isTreeBuilder = false; +var needsOpen = false; +var notWorkingYet = false; +var notWorkingYetDynamic = false; +var expectedOutput = document.getElementById("output"); + +var changes = []; +]]> +</script> + +<vbox xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul" id="root" datasources="rdf:null" ref="http://www.some-fictitious-zoo.com/arachnids"> +<template id="template"> +<rule id="rule"> +<conditions id="conditions"> +<content uri="?start"/> +<member container="?start" child="?animal"/> +<triple subject="?animal" predicate="http://www.some-fictitious-zoo.com/rdf#name" object="?name"/> +</conditions> +<action id="action"> +<label uri="?animal" value="?name^?? ?name?name - ?name^?name^^ Test"/> +</action> +</rule> +</template> +</vbox> + +</window> diff --git a/dom/xul/templates/tests/chrome/test_tmpl_gridelement.xul b/dom/xul/templates/tests/chrome/test_tmpl_gridelement.xul new file mode 100644 index 000000000..12575c6b8 --- /dev/null +++ b/dom/xul/templates/tests/chrome/test_tmpl_gridelement.xul @@ -0,0 +1,131 @@ +<?xml version="1.0"?> +<?xml-stylesheet href="chrome://global/skin" type="text/css"?> +<?xml-stylesheet href="chrome://mochikit/content/tests/SimpleTest/test.css" type="text/css"?> + +<!-- + grid element +--> + +<window title="XUL Template Tests" width="500" height="600" + onload="test_template();" + xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"> + <script type="application/javascript" + src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script> + + <body xmlns="http://www.w3.org/1999/xhtml" style="height: 300px; overflow: auto;"/> + + <data id="output"> + <columns> + <column/> + <column/> + </columns> + <rows> + <label step="3" id="http://www.some-fictitious-zoo.com/birds/wren" value="The coolest animal is: Wren"/> + <row id="http://www.some-fictitious-zoo.com/birds/emu"> + <label value="Emu"/> + <label value="Birds"/> + </row> + <label step="-4" id="http://www.some-fictitious-zoo.com/birds/barnowl" value="The coolest animal is: Barn Owl"/> + <row id="http://www.some-fictitious-zoo.com/birds/raven"> + <label value="Raven"/> + <label value="Birds"/> + </row> + <row step="2" id="http://www.some-fictitious-zoo.com/birds/archaeopteryx"> + <label value="Archaeopteryx"/> + <label value="Birds"/> + </row> + <label step="1" id="http://www.some-fictitious-zoo.com/birds/emperorpenguin" value="The coolest animal is: Emperor Penguin"/> + </rows> + </data> + +<script src="templates_shared.js"/> + +<script> +<![CDATA[ +SimpleTest.waitForExplicitFinish(); + +var testid ="grid element"; +var queryType = "rdf"; +var isTreeBuilder = false; +var needsOpen = false; +var notWorkingYet = false; +var notWorkingYetDynamic = false; +var expectedOutput = document.getElementById("output"); + +var changes = [ + // step 1 + function(targetds, root) { + var newnode = RDF.GetResource(ZOO_NS + 'birds/emperorpenguin'); + targetds.Assert(newnode, RDF.GetResource(ZOO_NS + 'rdf#name'), + RDF.GetLiteral('Emperor Penguin'), true); + var container = ContainerUtils.MakeSeq(targetds, + RDF.GetResource(ZOO_NS + 'birds')); + container.AppendElement(newnode); + }, + // step 2 + function(targetds, root) { + var newnode = RDF.GetResource(ZOO_NS + 'birds/archaeopteryx'); + targetds.Assert(newnode, RDF.GetResource(ZOO_NS + 'rdf#name'), + RDF.GetLiteral('Archaeopteryx'), true); + var container = ContainerUtils.MakeSeq(targetds, + RDF.GetResource(ZOO_NS + 'birds')); + container.InsertElementAt(newnode, '4', true); + }, + // step 3 + function(targetds, root) { + var newnode = RDF.GetResource(ZOO_NS + 'birds/wren'); + targetds.Assert(newnode, RDF.GetResource(ZOO_NS + 'rdf#name'), + RDF.GetLiteral('Wren'), true); + var container = ContainerUtils.MakeSeq(targetds, + RDF.GetResource(ZOO_NS + 'birds')); + container.InsertElementAt(newnode, '1', true); + }, + // step 4 + function(targetds, root) { + var container = ContainerUtils.MakeSeq(targetds, + RDF.GetResource(ZOO_NS + 'birds')); + var removednode = container.RemoveElementAt('3', true); + targetds.Unassert(removednode, RDF.GetResource(ZOO_NS + 'rdf#name'), + RDF.GetLiteral('Barn Owl'), true); + } +]; +]]> +</script> + +<grid xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul" id="root" datasources="rdf:null" ref="http://www.some-fictitious-zoo.com/birds"> +<columns> +<column/> +<column/> +</columns> +<template> +<query> +<content uri="?uri"/> +<member container="?uri" child="?child"/> +<triple subject="?uri" predicate="http://www.some-fictitious-zoo.com/rdf#name" object="?classname"/> +<triple subject="?child" predicate="http://www.some-fictitious-zoo.com/rdf#name" object="?name"/> +</query> +<rule> +<conditions> +<where subject="?name" rel="equals" value="Raven" negate="true"/> +<where subject="?name" rel="contains" value="n"/> +</conditions> +<action> +<rows> +<label uri="?child" value="The coolest animal is: ?name"/> +</rows> +</action> +</rule> +<rule> +<action> +<rows> +<row uri="?child"> +<label value="?name"/> +<label value="?classname"/> +</row> +</rows> +</action> +</rule> +</template> +</grid> + +</window> diff --git a/dom/xul/templates/tests/chrome/test_tmpl_htmlelementextendedsyntaxwithbinding.xul b/dom/xul/templates/tests/chrome/test_tmpl_htmlelementextendedsyntaxwithbinding.xul new file mode 100644 index 000000000..a9a14e00a --- /dev/null +++ b/dom/xul/templates/tests/chrome/test_tmpl_htmlelementextendedsyntaxwithbinding.xul @@ -0,0 +1,114 @@ +<?xml version="1.0"?> +<?xml-stylesheet href="chrome://global/skin" type="text/css"?> +<?xml-stylesheet href="chrome://mochikit/content/tests/SimpleTest/test.css" type="text/css"?> + +<!-- + html element - extended syntax with binding +--> + +<window title="XUL Template Tests" width="500" height="600" + onload="test_template();" + xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"> + <script type="application/javascript" + src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script> + + <body xmlns="http://www.w3.org/1999/xhtml" style="height: 300px; overflow: auto;"/> + + <data id="output" xmlns:html="http://www.w3.org/1999/xhtml"> + <html:div id="http://www.some-fictitious-zoo.com/mammals/lion" title="Lion"> + <html:em step="-2">4</html:em> + <html:em step="2">9</html:em> + </html:div> + <html:div id="http://www.some-fictitious-zoo.com/mammals/hippopotamus" title="HIPPOPOTAMUS"> + <html:em>2</html:em> + </html:div> + <html:p id="http://www.some-fictitious-zoo.com/mammals/africanelephant"> + African Elephant + <html:span title="14"/> + </html:p> + <html:p step="4" id="http://www.some-fictitious-zoo.com/mammals/chimpanzee"> + Chimpanzee + <html:span step="-5"/> + <html:span step="5" title="3"/> + </html:p> + <html:div id="http://www.some-fictitious-zoo.com/mammals/llama" title="LLAMA"> + <html:em>5</html:em> + </html:div> + <html:div id="http://www.some-fictitious-zoo.com/mammals/polarbear" title="Polar Bear"> + <html:em step="-1">20</html:em> + <html:em step="1">5</html:em> + </html:div> + <html:div id="http://www.some-fictitious-zoo.com/mammals/aardvark" title="aardvark"> + <html:em>2</html:em> + </html:div> + <html:p step="-3" id="http://www.some-fictitious-zoo.com/mammals/ninebandedarmadillo"> + Nine-banded Armadillo + <html:span title="1"/> + </html:p> + <html:div id="http://www.some-fictitious-zoo.com/mammals/gorilla" title="Gorilla"> + <html:em>7</html:em> + </html:div> + </data> + +<script src="templates_shared.js"/> + +<script> +<![CDATA[ +SimpleTest.waitForExplicitFinish(); + +var testid ="html element - extended syntax with binding"; +var queryType = "rdf"; +var isTreeBuilder = false; +var needsOpen = false; +var notWorkingYet = false; +var notWorkingYetDynamic = false; +var expectedOutput = document.getElementById("output"); + +var changes = [ + // step 1 + function(targetds, root) { + var subject = RDF.GetResource(ZOO_NS + 'mammals/polarbear'); + var predicate = RDF.GetResource(ZOO_NS + 'rdf#specimens'); + var oldval = targetds.GetTarget(subject, predicate, true); + targetds.Change(RDF.GetResource(ZOO_NS + 'mammals/polarbear'), + RDF.GetResource(ZOO_NS + 'rdf#specimens'), + oldval, RDF.GetLiteral('5')); + }, + // step 2 + function(targetds, root) { + var subject = RDF.GetResource(ZOO_NS + 'mammals/lion'); + var predicate = RDF.GetResource(ZOO_NS + 'rdf#specimens'); + var oldval = targetds.GetTarget(subject, predicate, true); + targetds.Change(RDF.GetResource(ZOO_NS + 'mammals/lion'), + RDF.GetResource(ZOO_NS + 'rdf#specimens'), + oldval, RDF.GetLiteral('9')); + }, + // step 3 + function(targetds, root) { + var container = ContainerUtils.MakeSeq(targetds, + RDF.GetResource(ZOO_NS + 'mammals')); + var removednode = container.RemoveElementAt('7', true); + targetds.Unassert(removednode, RDF.GetResource(ZOO_NS + 'rdf#name'), + RDF.GetLiteral('Nine-banded Armadillo'), true); + }, + // step 4 + function(targetds, root) { + var newnode = RDF.GetResource(ZOO_NS + 'mammals/chimpanzee'); + targetds.Assert(newnode, RDF.GetResource(ZOO_NS + 'rdf#name'), + RDF.GetLiteral('Chimpanzee'), true); + var container = ContainerUtils.MakeSeq(targetds, + RDF.GetResource(ZOO_NS + 'mammals')); + container.InsertElementAt(newnode, '4', true); + }, + // step 5 + function(targetds, root) { + targetds.Assert(RDF.GetResource(ZOO_NS + 'mammals/chimpanzee'), + RDF.GetResource(ZOO_NS + 'rdf#specimens'), + RDF.GetLiteral('3'), true); + } +]; +]]> +</script> + +<div xmlns="http://www.w3.org/1999/xhtml" id="root" datasources="rdf:null" ref="http://www.some-fictitious-zoo.com/mammals"><template xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul" id="template"><rule><conditions><content uri="?uri"/><member container="?uri" child="?animal"/><triple subject="?animal" predicate="http://www.some-fictitious-zoo.com/rdf#name" object="?name"/><where subject="?name" rel="contains" value="an"/></conditions><bindings><binding subject="?animal" predicate="http://www.some-fictitious-zoo.com/rdf#specimens" object="?specimens"/></bindings><action><p xmlns="http://www.w3.org/1999/xhtml" uri="?animal"><textnode xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul" value="?name"/><span title="?specimens"/></p></action></rule><rule><conditions><content uri="?uri"/><member container="?uri" child="?animal"/><triple subject="?animal" predicate="http://www.some-fictitious-zoo.com/rdf#name" object="?name"/></conditions><bindings><binding subject="?animal" predicate="http://www.some-fictitious-zoo.com/rdf#specimens" object="?specimens"/></bindings><action><div xmlns="http://www.w3.org/1999/xhtml" uri="?animal" title="?name"><em><textnode xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul" value="?specimens"/></em></div></action></rule></template></div> +</window> diff --git a/dom/xul/templates/tests/chrome/test_tmpl_htmlelementquerysyntaxrecursive.xul b/dom/xul/templates/tests/chrome/test_tmpl_htmlelementquerysyntaxrecursive.xul new file mode 100644 index 000000000..b03f20ce2 --- /dev/null +++ b/dom/xul/templates/tests/chrome/test_tmpl_htmlelementquerysyntaxrecursive.xul @@ -0,0 +1,81 @@ +<?xml version="1.0"?> +<?xml-stylesheet href="chrome://global/skin" type="text/css"?> +<?xml-stylesheet href="chrome://mochikit/content/tests/SimpleTest/test.css" type="text/css"?> + +<!-- + html element - query syntax recursive +--> + +<window title="XUL Template Tests" width="500" height="600" + onload="test_template();" + xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"> + <script type="application/javascript" + src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script> + + <body xmlns="http://www.w3.org/1999/xhtml" style="height: 300px; overflow: auto;"/> + + <data id="output" xmlns:html="http://www.w3.org/1999/xhtml"> + <html:strong id="http://www.some-fictitious-zoo.com/arachnids" container="true" empty="false">Arachnids</html:strong> + <html:strong step="-3" id="http://www.some-fictitious-zoo.com/birds" container="true" empty="false"> + Birds + <html:span id="http://www.some-fictitious-zoo.com/birds/barnowl">Barn Owl</html:span> + </html:strong> + <html:strong step="1" id="http://www.some-fictitious-zoo.com/insects">Insects</html:strong> + <html:strong id="http://www.some-fictitious-zoo.com/mammals" container="true" empty="false"> + Mammals + <html:span id="http://www.some-fictitious-zoo.com/mammals/lion">Lion</html:span> + <html:span id="http://www.some-fictitious-zoo.com/mammals/hippopotamus">HIPPOPOTAMUS</html:span> + <html:span step="2" id="http://www.some-fictitious-zoo.com/mammals/koala">Koala</html:span> + <html:span id="http://www.some-fictitious-zoo.com/mammals/polarbear">Polar Bear</html:span> + <html:span id="http://www.some-fictitious-zoo.com/mammals/ninebandedarmadillo">Nine-banded Armadillo</html:span> + <html:span id="http://www.some-fictitious-zoo.com/mammals/gorilla">Gorilla</html:span> + </html:strong> + </data> + +<script src="templates_shared.js"/> + +<script> +<![CDATA[ +SimpleTest.waitForExplicitFinish(); + +var testid ="html element - query syntax recursive"; +var queryType = "rdf"; +var isTreeBuilder = false; +var needsOpen = false; +var notWorkingYet = false; +var notWorkingYetDynamic = false; +var expectedOutput = document.getElementById("output"); + +var changes = [ + // step 1 + function(targetds, root) { + var newnode = RDF.GetResource(ZOO_NS + 'insects'); + targetds.Assert(newnode, RDF.GetResource(ZOO_NS + 'rdf#name'), + RDF.GetLiteral('Insects'), true); + var container = ContainerUtils.MakeSeq(targetds, + RDF.GetResource(ZOO_NS + 'all-animals')); + container.InsertElementAt(newnode, '3', true); + }, + // step 2 + function(targetds, root) { + var newnode = RDF.GetResource(ZOO_NS + 'mammals/koala'); + targetds.Assert(newnode, RDF.GetResource(ZOO_NS + 'rdf#name'), + RDF.GetLiteral('Koala'), true); + var container = ContainerUtils.MakeSeq(targetds, + RDF.GetResource(ZOO_NS + 'mammals')); + container.InsertElementAt(newnode, '4', true); + }, + // step 3 + function(targetds, root) { + var container = ContainerUtils.MakeSeq(targetds, + RDF.GetResource(ZOO_NS + 'all-animals')); + var removednode = container.RemoveElementAt('2', true); + targetds.Unassert(removednode, RDF.GetResource(ZOO_NS + 'rdf#name'), + RDF.GetLiteral('Birds'), true); + } +]; +]]> +</script> + +<div xmlns="http://www.w3.org/1999/xhtml" id="root" datasources="rdf:null" ref="http://www.some-fictitious-zoo.com/all-animals"><template xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul" id="template"><query><content uri="?uri"/><member container="?uri" child="?child"/><triple subject="?child" predicate="http://www.some-fictitious-zoo.com/rdf#name" object="?name"/></query><rule><conditions><where subject="?name" rel="endswith" multiple="true" value="mals,ects,nids,irds"/></conditions><action><strong xmlns="http://www.w3.org/1999/xhtml" uri="?child"><textnode xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul" value="?name"/></strong></action></rule><rule><conditions><where subject="?uri" rel="equals" negate="true" value="http://www.some-fictitious-zoo.com/all-animals"/><where subject="?name" rel="contains" ignorecase="true" value="o"/></conditions><action><span xmlns="http://www.w3.org/1999/xhtml" uri="?child"><textnode xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul" value="?name"/></span></action></rule></template></div> +</window> diff --git a/dom/xul/templates/tests/chrome/test_tmpl_htmlelementquerysyntaxwithmultiplerules.xul b/dom/xul/templates/tests/chrome/test_tmpl_htmlelementquerysyntaxwithmultiplerules.xul new file mode 100644 index 000000000..e0ef6a732 --- /dev/null +++ b/dom/xul/templates/tests/chrome/test_tmpl_htmlelementquerysyntaxwithmultiplerules.xul @@ -0,0 +1,102 @@ +<?xml version="1.0"?> +<?xml-stylesheet href="chrome://global/skin" type="text/css"?> +<?xml-stylesheet href="chrome://mochikit/content/tests/SimpleTest/test.css" type="text/css"?> + +<!-- + html element - query syntax with multiple rules +--> + +<window title="XUL Template Tests" width="500" height="600" + onload="test_template();" + xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"> + <script type="application/javascript" + src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script> + + <body xmlns="http://www.w3.org/1999/xhtml" style="height: 300px; overflow: auto;"/> + + <data id="output" xmlns:html="http://www.w3.org/1999/xhtml"> + <html:span step="-2" id="http://www.some-fictitious-zoo.com/mammals/lion">Lion</html:span> + <html:span id="http://www.some-fictitious-zoo.com/mammals/hippopotamus">HIPPOPOTAMUS</html:span> + <vbox> + <html:p step="2" id="http://www.some-fictitious-zoo.com/mammals/lion"> + <html:span title="Lion"/> + </html:p> + <html:p id="http://www.some-fictitious-zoo.com/mammals/africanelephant"> + <html:span title="African Elephant"/> + </html:p> + <html:p step="-1" id="http://www.some-fictitious-zoo.com/mammals/polarbear"> + <html:span title="Polar Bear"/> + </html:p> + <html:p id="http://www.some-fictitious-zoo.com/mammals/gorilla"> + <html:span title="Gorilla"/> + </html:p> + </vbox> + <html:span step="5" id="http://www.some-fictitious-zoo.com/mammals/chimpanzee">Chimpanzee</html:span> + <html:span id="http://www.some-fictitious-zoo.com/mammals/llama">LLAMA</html:span> + <html:span step="1" id="http://www.some-fictitious-zoo.com/mammals/polarbear">Polar Bear</html:span> + <html:span id="http://www.some-fictitious-zoo.com/mammals/aardvark">aardvark</html:span> + <html:span step="-3" id="http://www.some-fictitious-zoo.com/mammals/ninebandedarmadillo">Nine-banded Armadillo</html:span> + </data> + +<script src="templates_shared.js"/> + +<script> +<![CDATA[ +SimpleTest.waitForExplicitFinish(); + +var testid ="html element - query syntax with multiple rules"; +var queryType = "rdf"; +var isTreeBuilder = false; +var needsOpen = false; +var notWorkingYet = true; +var notWorkingYetDynamic = true; +var expectedOutput = document.getElementById("output"); + +var changes = [ + // step 1 + function(targetds, root) { + var subject = RDF.GetResource(ZOO_NS + 'mammals/polarbear'); + var predicate = RDF.GetResource(ZOO_NS + 'rdf#specimens'); + var oldval = targetds.GetTarget(subject, predicate, true); + targetds.Change(RDF.GetResource(ZOO_NS + 'mammals/polarbear'), + RDF.GetResource(ZOO_NS + 'rdf#specimens'), + oldval, RDF.GetLiteral('5')); + }, + // step 2 + function(targetds, root) { + var subject = RDF.GetResource(ZOO_NS + 'mammals/lion'); + var predicate = RDF.GetResource(ZOO_NS + 'rdf#specimens'); + var oldval = targetds.GetTarget(subject, predicate, true); + targetds.Change(RDF.GetResource(ZOO_NS + 'mammals/lion'), + RDF.GetResource(ZOO_NS + 'rdf#specimens'), + oldval, RDF.GetLiteral('9')); + }, + // step 3 + function(targetds, root) { + var container = ContainerUtils.MakeSeq(targetds, + RDF.GetResource(ZOO_NS + 'mammals')); + var removednode = container.RemoveElementAt('7', true); + targetds.Unassert(removednode, RDF.GetResource(ZOO_NS + 'rdf#name'), + RDF.GetLiteral('Nine-banded Armadillo'), true); + }, + // step 4 + function(targetds, root) { + var newnode = RDF.GetResource(ZOO_NS + 'mammals/chimpanzee'); + targetds.Assert(newnode, RDF.GetResource(ZOO_NS + 'rdf#name'), + RDF.GetLiteral('Chimpanzee'), true); + var container = ContainerUtils.MakeSeq(targetds, + RDF.GetResource(ZOO_NS + 'mammals')); + container.InsertElementAt(newnode, '4', true); + }, + // step 5 + function(targetds, root) { + targetds.Assert(RDF.GetResource(ZOO_NS + 'mammals/chimpanzee'), + RDF.GetResource(ZOO_NS + 'rdf#specimens'), + RDF.GetLiteral('3'), true); + } +]; +]]> +</script> + +<div xmlns="http://www.w3.org/1999/xhtml" id="root" datasources="rdf:null" ref="http://www.some-fictitious-zoo.com/mammals"><template xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul" id="template"><query><content uri="?uri"/><member container="?uri" child="?animal"/><triple subject="?animal" predicate="http://www.some-fictitious-zoo.com/rdf#name" object="?name"/><triple subject="?animal" predicate="http://www.some-fictitious-zoo.com/rdf#specimens" object="?specimens"/></query><rule><conditions id="conditions"><where subject="?specimens" rel="greater" value="6"/></conditions><action><vbox><p xmlns="http://www.w3.org/1999/xhtml" uri="?animal"><span title="?name"/></p></vbox></action></rule><rule><action><span xmlns="http://www.w3.org/1999/xhtml" uri="?animal"><textnode xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul" value="?name"/></span></action></rule></template></div> +</window> diff --git a/dom/xul/templates/tests/chrome/test_tmpl_htmlelementsimplesyntax.xul b/dom/xul/templates/tests/chrome/test_tmpl_htmlelementsimplesyntax.xul new file mode 100644 index 000000000..95c016fe8 --- /dev/null +++ b/dom/xul/templates/tests/chrome/test_tmpl_htmlelementsimplesyntax.xul @@ -0,0 +1,81 @@ +<?xml version="1.0"?> +<?xml-stylesheet href="chrome://global/skin" type="text/css"?> +<?xml-stylesheet href="chrome://mochikit/content/tests/SimpleTest/test.css" type="text/css"?> + +<!-- + html element - simple syntax +--> + +<window title="XUL Template Tests" width="500" height="600" + onload="test_template();" + xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"> + <script type="application/javascript" + src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script> + + <body xmlns="http://www.w3.org/1999/xhtml" style="height: 300px; overflow: auto;"/> + + <data id="output" xmlns:html="http://www.w3.org/1999/xhtml"> + <html:p step="3" id="http://www.some-fictitious-zoo.com/birds/wren" title="Wren"/> + <html:p id="http://www.some-fictitious-zoo.com/birds/emu" title="Emu"/> + <html:p step="-4" id="http://www.some-fictitious-zoo.com/birds/barnowl" title="Barn Owl"/> + <html:p id="http://www.some-fictitious-zoo.com/birds/raven" title="Raven"/> + <html:p step="2" id="http://www.some-fictitious-zoo.com/birds/archaeopteryx" title="Archaeopteryx"/> + <html:p step="1" id="http://www.some-fictitious-zoo.com/birds/emperorpenguin" title="Emperor Penguin"/> + </data> + +<script src="templates_shared.js"/> + +<script> +<![CDATA[ +SimpleTest.waitForExplicitFinish(); + +var testid ="html element - simple syntax"; +var queryType = "rdf"; +var isTreeBuilder = false; +var needsOpen = false; +var notWorkingYet = false; +var notWorkingYetDynamic = false; +var expectedOutput = document.getElementById("output"); + +var changes = [ + // step 1 + function(targetds, root) { + var newnode = RDF.GetResource(ZOO_NS + 'birds/emperorpenguin'); + targetds.Assert(newnode, RDF.GetResource(ZOO_NS + 'rdf#name'), + RDF.GetLiteral('Emperor Penguin'), true); + var container = ContainerUtils.MakeSeq(targetds, + RDF.GetResource(ZOO_NS + 'birds')); + container.AppendElement(newnode); + }, + // step 2 + function(targetds, root) { + var newnode = RDF.GetResource(ZOO_NS + 'birds/archaeopteryx'); + targetds.Assert(newnode, RDF.GetResource(ZOO_NS + 'rdf#name'), + RDF.GetLiteral('Archaeopteryx'), true); + var container = ContainerUtils.MakeSeq(targetds, + RDF.GetResource(ZOO_NS + 'birds')); + container.InsertElementAt(newnode, '4', true); + }, + // step 3 + function(targetds, root) { + var newnode = RDF.GetResource(ZOO_NS + 'birds/wren'); + targetds.Assert(newnode, RDF.GetResource(ZOO_NS + 'rdf#name'), + RDF.GetLiteral('Wren'), true); + var container = ContainerUtils.MakeSeq(targetds, + RDF.GetResource(ZOO_NS + 'birds')); + container.InsertElementAt(newnode, '1', true); + }, + // step 4 + function(targetds, root) { + var container = ContainerUtils.MakeSeq(targetds, + RDF.GetResource(ZOO_NS + 'birds')); + var removednode = container.RemoveElementAt('3', true); + targetds.Unassert(removednode, RDF.GetResource(ZOO_NS + 'rdf#name'), + RDF.GetLiteral('Barn Owl'), true); + } +]; +]]> +</script> + +<div xmlns="http://www.w3.org/1999/xhtml" id="root" datasources="rdf:null" ref="http://www.some-fictitious-zoo.com/birds"><template xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"><p xmlns="http://www.w3.org/1999/xhtml" uri="rdf:*" title="rdf:http://www.some-fictitious-zoo.com/rdf#name"/></template></div> +</window> diff --git a/dom/xul/templates/tests/chrome/test_tmpl_htmlelementsimplesyntaxusingatextnode.xul b/dom/xul/templates/tests/chrome/test_tmpl_htmlelementsimplesyntaxusingatextnode.xul new file mode 100644 index 000000000..14d8bab38 --- /dev/null +++ b/dom/xul/templates/tests/chrome/test_tmpl_htmlelementsimplesyntaxusingatextnode.xul @@ -0,0 +1,81 @@ +<?xml version="1.0"?> +<?xml-stylesheet href="chrome://global/skin" type="text/css"?> +<?xml-stylesheet href="chrome://mochikit/content/tests/SimpleTest/test.css" type="text/css"?> + +<!-- + html element - simple syntax using a textnode +--> + +<window title="XUL Template Tests" width="500" height="600" + onload="test_template();" + xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"> + <script type="application/javascript" + src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script> + + <body xmlns="http://www.w3.org/1999/xhtml" style="height: 300px; overflow: auto;"/> + + <data id="output" xmlns:html="http://www.w3.org/1999/xhtml"> + <html:p step="3" id="http://www.some-fictitious-zoo.com/birds/wren">Wren</html:p> + <html:p id="http://www.some-fictitious-zoo.com/birds/emu">Emu</html:p> + <html:p step="-4" id="http://www.some-fictitious-zoo.com/birds/barnowl">Barn Owl</html:p> + <html:p id="http://www.some-fictitious-zoo.com/birds/raven">Raven</html:p> + <html:p step="2" id="http://www.some-fictitious-zoo.com/birds/archaeopteryx">Archaeopteryx</html:p> + <html:p step="1" id="http://www.some-fictitious-zoo.com/birds/emperorpenguin">Emperor Penguin</html:p> + </data> + +<script src="templates_shared.js"/> + +<script> +<![CDATA[ +SimpleTest.waitForExplicitFinish(); + +var testid ="html element - simple syntax using a textnode"; +var queryType = "rdf"; +var isTreeBuilder = false; +var needsOpen = false; +var notWorkingYet = false; +var notWorkingYetDynamic = false; +var expectedOutput = document.getElementById("output"); + +var changes = [ + // step 1 + function(targetds, root) { + var newnode = RDF.GetResource(ZOO_NS + 'birds/emperorpenguin'); + targetds.Assert(newnode, RDF.GetResource(ZOO_NS + 'rdf#name'), + RDF.GetLiteral('Emperor Penguin'), true); + var container = ContainerUtils.MakeSeq(targetds, + RDF.GetResource(ZOO_NS + 'birds')); + container.AppendElement(newnode); + }, + // step 2 + function(targetds, root) { + var newnode = RDF.GetResource(ZOO_NS + 'birds/archaeopteryx'); + targetds.Assert(newnode, RDF.GetResource(ZOO_NS + 'rdf#name'), + RDF.GetLiteral('Archaeopteryx'), true); + var container = ContainerUtils.MakeSeq(targetds, + RDF.GetResource(ZOO_NS + 'birds')); + container.InsertElementAt(newnode, '4', true); + }, + // step 3 + function(targetds, root) { + var newnode = RDF.GetResource(ZOO_NS + 'birds/wren'); + targetds.Assert(newnode, RDF.GetResource(ZOO_NS + 'rdf#name'), + RDF.GetLiteral('Wren'), true); + var container = ContainerUtils.MakeSeq(targetds, + RDF.GetResource(ZOO_NS + 'birds')); + container.InsertElementAt(newnode, '1', true); + }, + // step 4 + function(targetds, root) { + var container = ContainerUtils.MakeSeq(targetds, + RDF.GetResource(ZOO_NS + 'birds')); + var removednode = container.RemoveElementAt('3', true); + targetds.Unassert(removednode, RDF.GetResource(ZOO_NS + 'rdf#name'), + RDF.GetLiteral('Barn Owl'), true); + } +]; +]]> +</script> + +<div xmlns="http://www.w3.org/1999/xhtml" id="root" datasources="rdf:null" ref="http://www.some-fictitious-zoo.com/birds"><template xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"><p xmlns="http://www.w3.org/1999/xhtml" uri="rdf:*"><textnode xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul" value="rdf:http://www.some-fictitious-zoo.com/rdf#name"/></p></template></div> +</window> diff --git a/dom/xul/templates/tests/chrome/test_tmpl_invalidqp.xul b/dom/xul/templates/tests/chrome/test_tmpl_invalidqp.xul new file mode 100644 index 000000000..2231f2067 --- /dev/null +++ b/dom/xul/templates/tests/chrome/test_tmpl_invalidqp.xul @@ -0,0 +1,48 @@ +<?xml version="1.0"?> +<?xml-stylesheet href="chrome://global/skin" type="text/css"?> +<?xml-stylesheet href="chrome://mochikit/content/tests/SimpleTest/test.css" type="text/css"?> + +<!-- + invalid syntax - querytype="blah" +--> + +<window title="XUL Template Tests" width="500" height="600" + onload="test_template();" + xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"> + <script type="application/javascript" + src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script> + + <body xmlns="http://www.w3.org/1999/xhtml" style="height: 300px; overflow: auto;"/> + + <data id="output"/> + +<script src="templates_shared.js"/> + +<script> +<![CDATA[ +SimpleTest.waitForExplicitFinish(); + +var testid ="invalid syntax"; +var queryType = "rdf"; +var isTreeBuilder = false; +var needsOpen = false; +var notWorkingYet = false; +var notWorkingYetDynamic = false; +var expectedOutput = document.getElementById("output"); + +Components.classes["@mozilla.org/consoleservice;1"]. + getService(Components.interfaces.nsIConsoleService).reset(); +expectedConsoleMessages.push("Error parsing template: querytype attribute doesn't specify a valid query processor"); + +var changes = []; +]]> +</script> + +<vbox xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul" id="root" datasources="rdf:null" + ref="http://www.some-fictitious-zoo.com/birds" querytype="blah"> +<template zoo:name="Barn Owl" xmlns:zoo="http://www.some-fictitious-zoo.com/rdf#"> +<label uri="rdf:*" value="rdf:http://www.some-fictitious-zoo.com/rdf#name"/> +</template> +</vbox> + +</window> diff --git a/dom/xul/templates/tests/chrome/test_tmpl_listboxelement.xul b/dom/xul/templates/tests/chrome/test_tmpl_listboxelement.xul new file mode 100644 index 000000000..e754b1542 --- /dev/null +++ b/dom/xul/templates/tests/chrome/test_tmpl_listboxelement.xul @@ -0,0 +1,117 @@ +<?xml version="1.0"?> +<?xml-stylesheet href="chrome://global/skin" type="text/css"?> +<?xml-stylesheet href="chrome://mochikit/content/tests/SimpleTest/test.css" type="text/css"?> + +<!-- + listbox element +--> + +<window title="XUL Template Tests" width="500" height="600" + onload="test_template();" + xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"> + <script type="application/javascript" + src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script> + + <body xmlns="http://www.w3.org/1999/xhtml" style="height: 300px; overflow: auto;"/> + + <data id="output"> + <listcols> + <listcol flex="1"/> + <listcol flex="1"/> + </listcols> + <listitem step="3" id="http://www.some-fictitious-zoo.com/birds/wren"> + <listcell label="Wren"/> + <listcell label=""/> + </listitem> + <listitem id="http://www.some-fictitious-zoo.com/birds/emu"> + <listcell label="Emu"/> + <listcell label="Dromaius novaehollandiae"/> + </listitem> + <listitem step="-4" id="http://www.some-fictitious-zoo.com/birds/barnowl"> + <listcell label="Barn Owl"/> + <listcell label="Tyto alba"/> + </listitem> + <listitem id="http://www.some-fictitious-zoo.com/birds/raven"> + <listcell label="Raven"/> + <listcell label="Corvus corax"/> + </listitem> + <listitem step="2" id="http://www.some-fictitious-zoo.com/birds/archaeopteryx"> + <listcell label="Archaeopteryx"/> + <listcell label=""/> + </listitem> + <listitem step="1" id="http://www.some-fictitious-zoo.com/birds/emperorpenguin"> + <listcell label="Emperor Penguin"/> + <listcell label=""/> + </listitem> + </data> + +<script src="templates_shared.js"/> + +<script> +<![CDATA[ +SimpleTest.expectAssertions(4); + +SimpleTest.waitForExplicitFinish(); + +var testid ="listbox element"; +var queryType = "rdf"; +var isTreeBuilder = false; +var needsOpen = false; +var notWorkingYet = false; +var notWorkingYetDynamic = false; +var expectedOutput = document.getElementById("output"); + +var changes = [ + // step 1 + function(targetds, root) { + var newnode = RDF.GetResource(ZOO_NS + 'birds/emperorpenguin'); + targetds.Assert(newnode, RDF.GetResource(ZOO_NS + 'rdf#name'), + RDF.GetLiteral('Emperor Penguin'), true); + var container = ContainerUtils.MakeSeq(targetds, + RDF.GetResource(ZOO_NS + 'birds')); + container.AppendElement(newnode); + }, + // step 2 + function(targetds, root) { + var newnode = RDF.GetResource(ZOO_NS + 'birds/archaeopteryx'); + targetds.Assert(newnode, RDF.GetResource(ZOO_NS + 'rdf#name'), + RDF.GetLiteral('Archaeopteryx'), true); + var container = ContainerUtils.MakeSeq(targetds, + RDF.GetResource(ZOO_NS + 'birds')); + container.InsertElementAt(newnode, '4', true); + }, + // step 3 + function(targetds, root) { + var newnode = RDF.GetResource(ZOO_NS + 'birds/wren'); + targetds.Assert(newnode, RDF.GetResource(ZOO_NS + 'rdf#name'), + RDF.GetLiteral('Wren'), true); + var container = ContainerUtils.MakeSeq(targetds, + RDF.GetResource(ZOO_NS + 'birds')); + container.InsertElementAt(newnode, '1', true); + }, + // step 4 + function(targetds, root) { + var container = ContainerUtils.MakeSeq(targetds, + RDF.GetResource(ZOO_NS + 'birds')); + var removednode = container.RemoveElementAt('3', true); + targetds.Unassert(removednode, RDF.GetResource(ZOO_NS + 'rdf#name'), + RDF.GetLiteral('Barn Owl'), true); + } +]; +]]> +</script> + +<listbox xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul" id="root" datasources="rdf:null" ref="http://www.some-fictitious-zoo.com/birds"> +<listcols> +<listcol flex="1"/> +<listcol flex="1"/> +</listcols> +<template> +<listitem uri="rdf:*"> +<listcell label="rdf:http://www.some-fictitious-zoo.com/rdf#name"/> +<listcell label="rdf:http://www.some-fictitious-zoo.com/rdf#species"/> +</listitem> +</template> +</listbox> + +</window> diff --git a/dom/xul/templates/tests/chrome/test_tmpl_literalasmember.xul b/dom/xul/templates/tests/chrome/test_tmpl_literalasmember.xul new file mode 100644 index 000000000..5e2ffe326 --- /dev/null +++ b/dom/xul/templates/tests/chrome/test_tmpl_literalasmember.xul @@ -0,0 +1,52 @@ +<?xml version="1.0"?> +<?xml-stylesheet href="chrome://global/skin" type="text/css"?> +<?xml-stylesheet href="chrome://mochikit/content/tests/SimpleTest/test.css" type="text/css"?> + +<!-- + literal as member +--> + +<window title="XUL Template Tests" width="500" height="600" + onload="test_template();" + xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"> + <script type="application/javascript" + src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script> + + <body xmlns="http://www.w3.org/1999/xhtml" style="height: 300px; overflow: auto;"/> + + <data id="output"/> + +<script src="templates_shared.js"/> + +<script> +<![CDATA[ +SimpleTest.waitForExplicitFinish(); + +var testid ="literal as member"; +var queryType = "rdf"; +var isTreeBuilder = false; +var needsOpen = false; +var notWorkingYet = false; +var notWorkingYetDynamic = false; +var expectedOutput = document.getElementById("output"); + +var changes = []; +]]> +</script> + +<vbox xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul" id="root" datasources="rdf:null" ref="http://www.some-fictitious-zoo.com/arachnids"> +<template id="template"> +<rule id="rule"> +<conditions id="conditions"> +<content uri="?start"/> +<member container="?start" child="?animal"/> +<triple subject="?animal" predicate="http://www.some-fictitious-zoo.com/rdf#name" object="?name"/> +</conditions> +<action id="action"> +<label uri="?name" value="?name"/> +</action> +</rule> +</template> +</vbox> + +</window> diff --git a/dom/xul/templates/tests/chrome/test_tmpl_membervariablechanged.xul b/dom/xul/templates/tests/chrome/test_tmpl_membervariablechanged.xul new file mode 100644 index 000000000..c231b8670 --- /dev/null +++ b/dom/xul/templates/tests/chrome/test_tmpl_membervariablechanged.xul @@ -0,0 +1,49 @@ +<?xml version="1.0"?> +<?xml-stylesheet href="chrome://global/skin" type="text/css"?> +<?xml-stylesheet href="chrome://mochikit/content/tests/SimpleTest/test.css" type="text/css"?> + +<!-- + member variable changed +--> + +<window title="XUL Template Tests" width="500" height="600" + onload="test_template();" + xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"> + <script type="application/javascript" + src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script> + + <body xmlns="http://www.w3.org/1999/xhtml" style="height: 300px; overflow: auto;"/> + + <data id="output"> + <button id="http://www.some-fictitious-zoo.com/birds/emu" label="http://www.some-fictitious-zoo.com/birds/emu Emu"/> + <button id="http://www.some-fictitious-zoo.com/birds/barnowl" label="http://www.some-fictitious-zoo.com/birds/barnowl Barn Owl"/> + <button id="http://www.some-fictitious-zoo.com/birds/raven" label="http://www.some-fictitious-zoo.com/birds/raven Raven"/> + </data> + +<script src="templates_shared.js"/> + +<script> +<![CDATA[ +SimpleTest.waitForExplicitFinish(); + +var testid ="member variable changed"; +var queryType = "rdf"; +var isTreeBuilder = false; +var needsOpen = false; +var notWorkingYet = false; +var notWorkingYetDynamic = false; +var expectedOutput = document.getElementById("output"); + +var changes = []; +]]> +</script> + +<vbox xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul" id="root" datasources="rdf:null" ref="http://www.some-fictitious-zoo.com/birds"> +<template member="?child"> +<rule> +<button uri="?child" label="?child rdf:http://www.some-fictitious-zoo.com/rdf#name"/> +</rule> +</template> +</vbox> + +</window> diff --git a/dom/xul/templates/tests/chrome/test_tmpl_membervariablesubstitution.xul b/dom/xul/templates/tests/chrome/test_tmpl_membervariablesubstitution.xul new file mode 100644 index 000000000..512717934 --- /dev/null +++ b/dom/xul/templates/tests/chrome/test_tmpl_membervariablesubstitution.xul @@ -0,0 +1,54 @@ +<?xml version="1.0"?> +<?xml-stylesheet href="chrome://global/skin" type="text/css"?> +<?xml-stylesheet href="chrome://mochikit/content/tests/SimpleTest/test.css" type="text/css"?> + +<!-- + member variable substitution +--> + +<window title="XUL Template Tests" width="500" height="600" + onload="test_template();" + xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"> + <script type="application/javascript" + src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script> + + <body xmlns="http://www.w3.org/1999/xhtml" style="height: 300px; overflow: auto;"/> + + <data id="output"> + <label id="http://www.some-fictitious-zoo.com/arachnids/tarantula" value="http://www.some-fictitious-zoo.com/arachnids/tarantula"/> + </data> + +<script src="templates_shared.js"/> + +<script> +<![CDATA[ +SimpleTest.waitForExplicitFinish(); + +var testid ="member variable substitution"; +var queryType = "rdf"; +var isTreeBuilder = false; +var needsOpen = false; +var notWorkingYet = false; +var notWorkingYetDynamic = false; +var expectedOutput = document.getElementById("output"); + +var changes = []; +]]> +</script> + +<vbox xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul" id="root" datasources="rdf:null" ref="http://www.some-fictitious-zoo.com/arachnids"> +<template id="template"> +<rule id="rule"> +<conditions id="conditions"> +<content uri="?start"/> +<member container="?start" child="?animal"/> +<triple subject="?animal" predicate="http://www.some-fictitious-zoo.com/rdf#name" object="?name"/> +</conditions> +<action id="action"> +<label uri="?animal" value="?animal"/> +</action> +</rule> +</template> +</vbox> + +</window> diff --git a/dom/xul/templates/tests/chrome/test_tmpl_menuelement.xul b/dom/xul/templates/tests/chrome/test_tmpl_menuelement.xul new file mode 100644 index 000000000..eecb6a7ed --- /dev/null +++ b/dom/xul/templates/tests/chrome/test_tmpl_menuelement.xul @@ -0,0 +1,90 @@ +<?xml version="1.0"?> +<?xml-stylesheet href="chrome://global/skin" type="text/css"?> +<?xml-stylesheet href="chrome://mochikit/content/tests/SimpleTest/test.css" type="text/css"?> + +<!-- + menu element +--> + +<window title="XUL Template Tests" width="500" height="600" + onload="test_template();" + xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"> + <script type="application/javascript" + src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script> + + <body xmlns="http://www.w3.org/1999/xhtml" style="height: 300px; overflow: auto;"/> + + <data id="output"> + <menupopup> + <menuitem step="3" id="http://www.some-fictitious-zoo.com/birds/wren" label="Wren"/> + <menuitem id="http://www.some-fictitious-zoo.com/birds/emu" label="Emu"/> + <menuitem step="-4" id="http://www.some-fictitious-zoo.com/birds/barnowl" label="Barn Owl"/> + <menuitem id="http://www.some-fictitious-zoo.com/birds/raven" label="Raven"/> + <menuitem step="2" id="http://www.some-fictitious-zoo.com/birds/archaeopteryx" label="Archaeopteryx"/> + <menuitem step="1" id="http://www.some-fictitious-zoo.com/birds/emperorpenguin" label="Emperor Penguin"/> + </menupopup> + </data> + +<script src="templates_shared.js"/> + +<script> +<![CDATA[ +SimpleTest.waitForExplicitFinish(); + +var testid ="menu element"; +var queryType = "rdf"; +var isTreeBuilder = false; +var needsOpen = true; +var notWorkingYet = false; +var notWorkingYetDynamic = false; +var expectedOutput = document.getElementById("output"); + +var changes = [ + // step 1 + function(targetds, root) { + var newnode = RDF.GetResource(ZOO_NS + 'birds/emperorpenguin'); + targetds.Assert(newnode, RDF.GetResource(ZOO_NS + 'rdf#name'), + RDF.GetLiteral('Emperor Penguin'), true); + var container = ContainerUtils.MakeSeq(targetds, + RDF.GetResource(ZOO_NS + 'birds')); + container.AppendElement(newnode); + }, + // step 2 + function(targetds, root) { + var newnode = RDF.GetResource(ZOO_NS + 'birds/archaeopteryx'); + targetds.Assert(newnode, RDF.GetResource(ZOO_NS + 'rdf#name'), + RDF.GetLiteral('Archaeopteryx'), true); + var container = ContainerUtils.MakeSeq(targetds, + RDF.GetResource(ZOO_NS + 'birds')); + container.InsertElementAt(newnode, '4', true); + }, + // step 3 + function(targetds, root) { + var newnode = RDF.GetResource(ZOO_NS + 'birds/wren'); + targetds.Assert(newnode, RDF.GetResource(ZOO_NS + 'rdf#name'), + RDF.GetLiteral('Wren'), true); + var container = ContainerUtils.MakeSeq(targetds, + RDF.GetResource(ZOO_NS + 'birds')); + container.InsertElementAt(newnode, '1', true); + }, + // step 4 + function(targetds, root) { + var container = ContainerUtils.MakeSeq(targetds, + RDF.GetResource(ZOO_NS + 'birds')); + var removednode = container.RemoveElementAt('3', true); + targetds.Unassert(removednode, RDF.GetResource(ZOO_NS + 'rdf#name'), + RDF.GetLiteral('Barn Owl'), true); + } +]; +]]> +</script> + +<button xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul" type="menu" id="root" datasources="rdf:null" ref="http://www.some-fictitious-zoo.com/birds"> +<template> +<menupopup> +<menuitem uri="rdf:*" label="rdf:http://www.some-fictitious-zoo.com/rdf#name"/> +</menupopup> +</template> +</button> + +</window> diff --git a/dom/xul/templates/tests/chrome/test_tmpl_menuelementrecursive.xul b/dom/xul/templates/tests/chrome/test_tmpl_menuelementrecursive.xul new file mode 100644 index 000000000..1597e3164 --- /dev/null +++ b/dom/xul/templates/tests/chrome/test_tmpl_menuelementrecursive.xul @@ -0,0 +1,121 @@ +<?xml version="1.0"?> +<?xml-stylesheet href="chrome://global/skin" type="text/css"?> +<?xml-stylesheet href="chrome://mochikit/content/tests/SimpleTest/test.css" type="text/css"?> + +<!-- + menu element recursive +--> + +<window title="XUL Template Tests" width="500" height="600" + onload="test_template()" + xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"> + <script type="application/javascript" + src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script> + + <body xmlns="http://www.w3.org/1999/xhtml" style="height: 300px; overflow: auto;"/> + + <data id="output"> + <menupopup> + <menuitem id="http://www.some-fictitious-zoo.com/arachnids" label="Arachnids" container="true" empty="false"/> + <menu step="-2" id="http://www.some-fictitious-zoo.com/birds" label="Birds" container="true" empty="false"/> + <menu step="2" id="http://www.some-fictitious-zoo.com/birds" label="Birds" container="true" empty="false" open="true"> + <menupopup> + <menuitem step="4" id="http://www.some-fictitious-zoo.com/birds/wren" label="Wren"/> + <menuitem id="http://www.some-fictitious-zoo.com/birds/emu" label="Emu"/> + <menuitem step="-5" id="http://www.some-fictitious-zoo.com/birds/barnowl" label="Barn Owl"/> + <menuitem id="http://www.some-fictitious-zoo.com/birds/raven" label="Raven"/> + <menuitem step="3" id="http://www.some-fictitious-zoo.com/birds/archaeopteryx" label="Archaeopteryx"/> + <menuitem id="http://www.some-fictitious-zoo.com/birds/emperorpenguin" label="Emperor Penguin"/> + </menupopup> + </menu> + <menuitem id="http://www.some-fictitious-zoo.com/crustaceans" label="Crustaceans" container="true" empty="true"/> + <menuitem id="http://www.some-fictitious-zoo.com/fish" label="Fish" container="true" empty="false"/> + <menuitem id="http://www.some-fictitious-zoo.com/mammals" label="Mammals" container="true" empty="false"/> + <menuitem id="http://www.some-fictitious-zoo.com/reptiles" label="Reptiles" container="true" empty="false"/> + </menupopup> + </data> + +<script src="templates_shared.js"/> + +<script> +<![CDATA[ +SimpleTest.waitForExplicitFinish(); + +var testid ="menu element recursive"; +var queryType = "rdf"; +var isTreeBuilder = false; +var needsOpen = true; +var notWorkingYet = false; +var notWorkingYetDynamic = false; +var expectedOutput = document.getElementById("output"); + +var changes = [ + // step 1 + function(targetds, root) { + // nothing should change at this step as the submenu is not open + var newnode = RDF.GetResource(ZOO_NS + 'birds/emperorpenguin'); + targetds.Assert(newnode, RDF.GetResource(ZOO_NS + 'rdf#name'), + RDF.GetLiteral('Emperor Penguin'), true); + var container = ContainerUtils.MakeSeq(targetds, + RDF.GetResource(ZOO_NS + 'birds')); + container.AppendElement(newnode); + }, + // step 2 + function(targetds, root) { + // open the submenu + root.lastChild.firstChild.nextSibling.open = true; + }, + // step 3 + function(targetds, root) { + var newnode = RDF.GetResource(ZOO_NS + 'birds/archaeopteryx'); + targetds.Assert(newnode, RDF.GetResource(ZOO_NS + 'rdf#name'), + RDF.GetLiteral('Archaeopteryx'), true); + var container = ContainerUtils.MakeSeq(targetds, + RDF.GetResource(ZOO_NS + 'birds')); + container.InsertElementAt(newnode, '4', true); + root.lastChild.firstChild.nextSibling.open = true; + }, + // step 4 + function(targetds, root) { + var newnode = RDF.GetResource(ZOO_NS + 'birds/wren'); + targetds.Assert(newnode, RDF.GetResource(ZOO_NS + 'rdf#name'), + RDF.GetLiteral('Wren'), true); + var container = ContainerUtils.MakeSeq(targetds, + RDF.GetResource(ZOO_NS + 'birds')); + container.InsertElementAt(newnode, '1', true); + root.lastChild.firstChild.nextSibling.open = true; + }, + // step 5 + function(targetds, root) { + var container = ContainerUtils.MakeSeq(targetds, + RDF.GetResource(ZOO_NS + 'birds')); + var removednode = container.RemoveElementAt('3', true); + targetds.Unassert(removednode, RDF.GetResource(ZOO_NS + 'rdf#name'), + RDF.GetLiteral('Barn Owl'), true); + root.lastChild.firstChild.nextSibling.open = true; + } +]; +]]> +</script> + +<button xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul" type="menu" id="root" datasources="rdf:null" ref="http://www.some-fictitious-zoo.com/all-animals"> +<template> +<rule iscontainer="true" zoo:name="Birds" xmlns:zoo="http://www.some-fictitious-zoo.com/rdf#"> +<menupopup> +<menu uri="rdf:*" label="rdf:http://www.some-fictitious-zoo.com/rdf#name"/> +</menupopup> +</rule> +<rule parent="button"> +<menupopup> +<menuitem uri="rdf:*" label="rdf:http://www.some-fictitious-zoo.com/rdf#name"/> +</menupopup> +</rule> +<rule parent="menu"> +<menupopup> +<menuitem uri="rdf:*" label="rdf:http://www.some-fictitious-zoo.com/rdf#name"/> +</menupopup> +</rule> +</template> +</button> + +</window> diff --git a/dom/xul/templates/tests/chrome/test_tmpl_menulistelement.xul b/dom/xul/templates/tests/chrome/test_tmpl_menulistelement.xul new file mode 100644 index 000000000..bebc7b970 --- /dev/null +++ b/dom/xul/templates/tests/chrome/test_tmpl_menulistelement.xul @@ -0,0 +1,90 @@ +<?xml version="1.0"?> +<?xml-stylesheet href="chrome://global/skin" type="text/css"?> +<?xml-stylesheet href="chrome://mochikit/content/tests/SimpleTest/test.css" type="text/css"?> + +<!-- + menulist element +--> + +<window title="XUL Template Tests" width="500" height="600" + onload="$('root').selectedItem = null; test_template();" + xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"> + <script type="application/javascript" + src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script> + + <body xmlns="http://www.w3.org/1999/xhtml" style="height: 300px; overflow: auto;"/> + + <data id="output"> + <menupopup> + <menuitem step="3" id="http://www.some-fictitious-zoo.com/birds/wren" label="Wren"/> + <menuitem id="http://www.some-fictitious-zoo.com/birds/emu" label="Emu"/> + <menuitem step="-4" id="http://www.some-fictitious-zoo.com/birds/barnowl" label="Barn Owl"/> + <menuitem id="http://www.some-fictitious-zoo.com/birds/raven" label="Raven"/> + <menuitem step="2" id="http://www.some-fictitious-zoo.com/birds/archaeopteryx" label="Archaeopteryx"/> + <menuitem step="1" id="http://www.some-fictitious-zoo.com/birds/emperorpenguin" label="Emperor Penguin"/> + </menupopup> + </data> + +<script src="templates_shared.js"/> + +<script> +<![CDATA[ +SimpleTest.waitForExplicitFinish(); + +var testid ="menulist element"; +var queryType = "rdf"; +var isTreeBuilder = false; +var needsOpen = false; +var notWorkingYet = false; +var notWorkingYetDynamic = false; +var expectedOutput = document.getElementById("output"); + +var changes = [ + // step 1 + function(targetds, root) { + var newnode = RDF.GetResource(ZOO_NS + 'birds/emperorpenguin'); + targetds.Assert(newnode, RDF.GetResource(ZOO_NS + 'rdf#name'), + RDF.GetLiteral('Emperor Penguin'), true); + var container = ContainerUtils.MakeSeq(targetds, + RDF.GetResource(ZOO_NS + 'birds')); + container.AppendElement(newnode); + }, + // step 2 + function(targetds, root) { + var newnode = RDF.GetResource(ZOO_NS + 'birds/archaeopteryx'); + targetds.Assert(newnode, RDF.GetResource(ZOO_NS + 'rdf#name'), + RDF.GetLiteral('Archaeopteryx'), true); + var container = ContainerUtils.MakeSeq(targetds, + RDF.GetResource(ZOO_NS + 'birds')); + container.InsertElementAt(newnode, '4', true); + }, + // step 3 + function(targetds, root) { + var newnode = RDF.GetResource(ZOO_NS + 'birds/wren'); + targetds.Assert(newnode, RDF.GetResource(ZOO_NS + 'rdf#name'), + RDF.GetLiteral('Wren'), true); + var container = ContainerUtils.MakeSeq(targetds, + RDF.GetResource(ZOO_NS + 'birds')); + container.InsertElementAt(newnode, '1', true); + }, + // step 4 + function(targetds, root) { + var container = ContainerUtils.MakeSeq(targetds, + RDF.GetResource(ZOO_NS + 'birds')); + var removednode = container.RemoveElementAt('3', true); + targetds.Unassert(removednode, RDF.GetResource(ZOO_NS + 'rdf#name'), + RDF.GetLiteral('Barn Owl'), true); + } +]; +]]> +</script> + +<menulist xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul" id="root" datasources="rdf:null" ref="http://www.some-fictitious-zoo.com/birds"> +<template> +<menupopup> +<menuitem uri="rdf:*" label="rdf:http://www.some-fictitious-zoo.com/rdf#name"/> +</menupopup> +</template> +</menulist> + +</window> diff --git a/dom/xul/templates/tests/chrome/test_tmpl_mixedsyntaxiscontainer.xul b/dom/xul/templates/tests/chrome/test_tmpl_mixedsyntaxiscontainer.xul new file mode 100644 index 000000000..446fa77ec --- /dev/null +++ b/dom/xul/templates/tests/chrome/test_tmpl_mixedsyntaxiscontainer.xul @@ -0,0 +1,67 @@ +<?xml version="1.0"?> +<?xml-stylesheet href="chrome://global/skin" type="text/css"?> +<?xml-stylesheet href="chrome://mochikit/content/tests/SimpleTest/test.css" type="text/css"?> + +<!-- + mixed syntax - iscontainer +--> + +<window title="XUL Template Tests" width="500" height="600" + onload="test_template();" + xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"> + <script type="application/javascript" + src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script> + + <body xmlns="http://www.w3.org/1999/xhtml" style="height: 300px; overflow: auto;"/> + + <data id="output"> + <checkbox id="http://www.some-fictitious-zoo.com/humans/sarah" label="Sarah"/> + <button id="http://www.some-fictitious-zoo.com/mammals" container="true" empty="false" label="Mammals"/> + <button id="http://www.some-fictitious-zoo.com/crustaceans" container="true" empty="true" label="Crustaceans"/> + <checkbox id="http://www.some-fictitious-zoo.com/birds/emu" label="Emu"/> + </data> + +<script src="templates_shared.js"/> + +<script> +<![CDATA[ +SimpleTest.waitForExplicitFinish(); + +var testid ="mixed syntax - iscontainer"; +var queryType = "rdf"; +var isTreeBuilder = false; +var needsOpen = false; +var notWorkingYet = false; +var notWorkingYetDynamic = false; +var expectedOutput = document.getElementById("output"); + +var changes = [ + // step 1 + function(targetds, root) { + targetds.Unassert(RDF.GetResource(ZOO_NS + 'humans/sarah'), + RDF.GetResource(ZOO_NS + 'rdf#pets'), + RDF.GetResource(ZOO_NS + 'sarahs-pets'), true); + } +]; +]]> +</script> + +<vbox xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul" id="root" datasources="rdf:null" ref="http://www.some-fictitious-zoo.com/marked" flags="dont-recurse"> +<template id="template"> +<rule id="rule1" iscontainer="true"> +<button uri="rdf:*" label="rdf:http://www.some-fictitious-zoo.com/rdf#name"/> +</rule> +<rule> +<conditions> +<content uri="?uri"/> +<member container="?uri" child="?child"/> +<triple subject="?child" predicate="http://www.some-fictitious-zoo.com/rdf#name" object="?name"/> +</conditions> +<action> +<checkbox uri="?child" label="?name"/> +</action> +</rule> +</template> +</vbox> + +</window> diff --git a/dom/xul/templates/tests/chrome/test_tmpl_mixedsyntaxiscontainerisempty.xul b/dom/xul/templates/tests/chrome/test_tmpl_mixedsyntaxiscontainerisempty.xul new file mode 100644 index 000000000..2c3a3e23c --- /dev/null +++ b/dom/xul/templates/tests/chrome/test_tmpl_mixedsyntaxiscontainerisempty.xul @@ -0,0 +1,60 @@ +<?xml version="1.0"?> +<?xml-stylesheet href="chrome://global/skin" type="text/css"?> +<?xml-stylesheet href="chrome://mochikit/content/tests/SimpleTest/test.css" type="text/css"?> + +<!-- + mixed syntax - iscontainer isempty +--> + +<window title="XUL Template Tests" width="500" height="600" + onload="test_template();" + xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"> + <script type="application/javascript" + src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script> + + <body xmlns="http://www.w3.org/1999/xhtml" style="height: 300px; overflow: auto;"/> + + <data id="output"> + <checkbox id="http://www.some-fictitious-zoo.com/humans/sarah" label="Sarah"/> + <checkbox id="http://www.some-fictitious-zoo.com/mammals" container="true" empty="false" label="Mammals"/> + <label id="http://www.some-fictitious-zoo.com/crustaceans" container="true" empty="true" value="Crustaceans"/> + <checkbox id="http://www.some-fictitious-zoo.com/birds/emu" label="Emu"/> + </data> + +<script src="templates_shared.js"/> + +<script> +<![CDATA[ +SimpleTest.waitForExplicitFinish(); + +var testid ="mixed syntax - iscontainer isempty"; +var queryType = "rdf"; +var isTreeBuilder = false; +var needsOpen = false; +var notWorkingYet = false; +var notWorkingYetDynamic = false; +var expectedOutput = document.getElementById("output"); + +var changes = []; +]]> +</script> + +<vbox xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul" id="root" datasources="rdf:null" ref="http://www.some-fictitious-zoo.com/marked" flags="dont-recurse"> +<template id="template"> +<rule id="rule1" iscontainer="true" isempty="true"> +<label uri="rdf:*" value="rdf:http://www.some-fictitious-zoo.com/rdf#name"/> +</rule> +<rule> +<conditions> +<content uri="?uri"/> +<member container="?uri" child="?child"/> +<triple subject="?child" predicate="http://www.some-fictitious-zoo.com/rdf#name" object="?name"/> +</conditions> +<action> +<checkbox uri="?child" label="?name"/> +</action> +</rule> +</template> +</vbox> + +</window> diff --git a/dom/xul/templates/tests/chrome/test_tmpl_mixedsyntaxisempty.xul b/dom/xul/templates/tests/chrome/test_tmpl_mixedsyntaxisempty.xul new file mode 100644 index 000000000..25b5d59a0 --- /dev/null +++ b/dom/xul/templates/tests/chrome/test_tmpl_mixedsyntaxisempty.xul @@ -0,0 +1,60 @@ +<?xml version="1.0"?> +<?xml-stylesheet href="chrome://global/skin" type="text/css"?> +<?xml-stylesheet href="chrome://mochikit/content/tests/SimpleTest/test.css" type="text/css"?> + +<!-- + mixed syntax - isempty +--> + +<window title="XUL Template Tests" width="500" height="600" + onload="test_template();" + xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"> + <script type="application/javascript" + src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script> + + <body xmlns="http://www.w3.org/1999/xhtml" style="height: 300px; overflow: auto;"/> + + <data id="output"> + <label id="http://www.some-fictitious-zoo.com/humans/sarah" value="Sarah"/> + <checkbox id="http://www.some-fictitious-zoo.com/mammals" container="true" empty="false" label="Mammals"/> + <label id="http://www.some-fictitious-zoo.com/crustaceans" container="true" empty="true" value="Crustaceans"/> + <label id="http://www.some-fictitious-zoo.com/birds/emu" value="Emu"/> + </data> + +<script src="templates_shared.js"/> + +<script> +<![CDATA[ +SimpleTest.waitForExplicitFinish(); + +var testid ="mixed syntax - isempty"; +var queryType = "rdf"; +var isTreeBuilder = false; +var needsOpen = false; +var notWorkingYet = false; +var notWorkingYetDynamic = false; +var expectedOutput = document.getElementById("output"); + +var changes = []; +]]> +</script> + +<vbox xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul" id="root" datasources="rdf:null" ref="http://www.some-fictitious-zoo.com/marked" flags="dont-recurse"> +<template id="template"> +<rule id="rule1" isempty="true"> +<label uri="rdf:*" value="rdf:http://www.some-fictitious-zoo.com/rdf#name"/> +</rule> +<rule> +<conditions> +<content uri="?uri"/> +<member container="?uri" child="?child"/> +<triple subject="?child" predicate="http://www.some-fictitious-zoo.com/rdf#name" object="?name"/> +</conditions> +<action> +<checkbox uri="?child" label="?name"/> +</action> +</rule> +</template> +</vbox> + +</window> diff --git a/dom/xul/templates/tests/chrome/test_tmpl_noaction.xul b/dom/xul/templates/tests/chrome/test_tmpl_noaction.xul new file mode 100644 index 000000000..f03623e09 --- /dev/null +++ b/dom/xul/templates/tests/chrome/test_tmpl_noaction.xul @@ -0,0 +1,48 @@ +<?xml version="1.0"?> +<?xml-stylesheet href="chrome://global/skin" type="text/css"?> +<?xml-stylesheet href="chrome://mochikit/content/tests/SimpleTest/test.css" type="text/css"?> + +<!-- + no action +--> + +<window title="XUL Template Tests" width="500" height="600" + onload="test_template();" + xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"> + <script type="application/javascript" + src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script> + + <body xmlns="http://www.w3.org/1999/xhtml" style="height: 300px; overflow: auto;"/> + + <data id="output"/> + +<script src="templates_shared.js"/> + +<script> +<![CDATA[ +SimpleTest.waitForExplicitFinish(); + +var testid ="no action"; +var queryType = "rdf"; +var isTreeBuilder = false; +var needsOpen = false; +var notWorkingYet = false; +var notWorkingYetDynamic = false; +var expectedOutput = document.getElementById("output"); + +var changes = []; +]]> +</script> + +<vbox xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul" id="root" datasources="rdf:null" ref="http://www.some-fictitious-zoo.com/birds"> +<template> +<query> +<content uri="?uri"/> +<member container="?uri" child="?child"/> +<triple subject="?child" predicate="http://www.some-fictitious-zoo.com/rdf#name" object="?name"/> +</query> +<button uri="?child" label="?name"/> +</template> +</vbox> + +</window> diff --git a/dom/xul/templates/tests/chrome/test_tmpl_noactionuriattribute.xul b/dom/xul/templates/tests/chrome/test_tmpl_noactionuriattribute.xul new file mode 100644 index 000000000..bd14bee1f --- /dev/null +++ b/dom/xul/templates/tests/chrome/test_tmpl_noactionuriattribute.xul @@ -0,0 +1,55 @@ +<?xml version="1.0"?> +<?xml-stylesheet href="chrome://global/skin" type="text/css"?> +<?xml-stylesheet href="chrome://mochikit/content/tests/SimpleTest/test.css" type="text/css"?> + +<!-- + no action uri attribute +--> + +<window title="XUL Template Tests" width="500" height="600" + onload="test_template();" + xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"> + <script type="application/javascript" + src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script> + + <body xmlns="http://www.w3.org/1999/xhtml" style="height: 300px; overflow: auto;"/> + + <data id="output"> + <label value="Tarantula"/> + </data> + +<script src="templates_shared.js"/> + +<script> +<![CDATA[ +SimpleTest.waitForExplicitFinish(); + +var testid ="no action uri attribute"; +var queryType = "rdf"; +var isTreeBuilder = false; +var needsOpen = false; +var notWorkingYet = false; +var notWorkingYetDynamic = false; +var expectedOutput = document.getElementById("output"); + +var changes = [ + // step 1 + function(targetds, root) { + var subject = RDF.GetResource(ZOO_NS + 'arachnids/tarantula'); + var predicate = RDF.GetResource(ZOO_NS + 'rdf#name'); + var oldval = targetds.GetTarget(subject, predicate, true); + targetds.Change(RDF.GetResource(ZOO_NS + 'arachnids/tarantula'), + RDF.GetResource(ZOO_NS + 'rdf#name'), + oldval, RDF.GetLiteral('Hairy Spider')); + } +]; +]]> +</script> + +<vbox xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul" id="root" datasources="rdf:null" ref="http://www.some-fictitious-zoo.com/arachnids"> +<template id="template"> +<label value="rdf:http://www.some-fictitious-zoo.com/rdf#name"/> +</template> +</vbox> + +</window> diff --git a/dom/xul/templates/tests/chrome/test_tmpl_parentconditions.xul b/dom/xul/templates/tests/chrome/test_tmpl_parentconditions.xul new file mode 100644 index 000000000..dae20a830 --- /dev/null +++ b/dom/xul/templates/tests/chrome/test_tmpl_parentconditions.xul @@ -0,0 +1,113 @@ +<?xml version="1.0"?> +<?xml-stylesheet href="chrome://global/skin" type="text/css"?> +<?xml-stylesheet href="chrome://mochikit/content/tests/SimpleTest/test.css" type="text/css"?> + +<!-- + parent - conditions +--> + +<window title="XUL Template Tests" width="500" height="600" + onload="test_template();" + xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"> + <script type="application/javascript" + src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script> + + <body xmlns="http://www.w3.org/1999/xhtml" style="height: 300px; overflow: auto;"/> + + <data id="output"> + <box step="-3" id="http://www.some-fictitious-zoo.com/birds" container="true" empty="false"> + <label value="Birds"/> + <button id="http://www.some-fictitious-zoo.com/birds/barnowl" label="Barn Owl"/> + <button id="http://www.some-fictitious-zoo.com/birds/raven" label="Raven"/> + </box> + <box step="1" id="http://www.some-fictitious-zoo.com/insects"> + <label value="Insects"/> + </box> + <box id="http://www.some-fictitious-zoo.com/crustaceans" container="true" empty="true"> + <label value="Crustaceans"/> + </box> + <box id="http://www.some-fictitious-zoo.com/mammals" container="true" empty="false"> + <label value="Mammals"/> + <button id="http://www.some-fictitious-zoo.com/mammals/africanelephant" label="African Elephant"/> + <button step="2" id="http://www.some-fictitious-zoo.com/mammals/koala" label="Koala"/> + <button id="http://www.some-fictitious-zoo.com/mammals/polarbear" label="Polar Bear"/> + <button id="http://www.some-fictitious-zoo.com/mammals/aardvark" label="aardvark"/> + <button id="http://www.some-fictitious-zoo.com/mammals/ninebandedarmadillo" label="Nine-banded Armadillo"/> + <button id="http://www.some-fictitious-zoo.com/mammals/gorilla" label="Gorilla"/> + </box> + </data> + +<script src="templates_shared.js"/> + +<script> +<![CDATA[ +SimpleTest.waitForExplicitFinish(); + +var testid ="parent - conditions"; +var queryType = "rdf"; +var isTreeBuilder = false; +var needsOpen = false; +var notWorkingYet = false; +var notWorkingYetDynamic = false; +var expectedOutput = document.getElementById("output"); + +var changes = [ + // step 1 + function(targetds, root) { + var newnode = RDF.GetResource(ZOO_NS + 'insects'); + targetds.Assert(newnode, RDF.GetResource(ZOO_NS + 'rdf#name'), + RDF.GetLiteral('Insects'), true); + var container = ContainerUtils.MakeSeq(targetds, + RDF.GetResource(ZOO_NS + 'all-animals')); + container.InsertElementAt(newnode, '3', true); + }, + // step 2 + function(targetds, root) { + var newnode = RDF.GetResource(ZOO_NS + 'mammals/koala'); + targetds.Assert(newnode, RDF.GetResource(ZOO_NS + 'rdf#name'), + RDF.GetLiteral('Koala'), true); + var container = ContainerUtils.MakeSeq(targetds, + RDF.GetResource(ZOO_NS + 'mammals')); + container.InsertElementAt(newnode, '4', true); + }, + // step 3 + function(targetds, root) { + var container = ContainerUtils.MakeSeq(targetds, + RDF.GetResource(ZOO_NS + 'all-animals')); + var removednode = container.RemoveElementAt('2', true); + targetds.Unassert(removednode, RDF.GetResource(ZOO_NS + 'rdf#name'), + RDF.GetLiteral('Birds'), true); + } +]; +]]> +</script> + +<vbox xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul" id="root" datasources="rdf:null" ref="http://www.some-fictitious-zoo.com/all-animals"> +<template> +<query> +<content uri="?uri"/> +<member container="?uri" child="?parent"/> +<triple subject="?parent" predicate="http://www.some-fictitious-zoo.com/rdf#name" object="?name"/> +</query> +<rule> +<conditions parent="box"> +<where subject="?name" rel="contains" value="a"/> +</conditions> +<action> +<button uri="?parent" label="?name"/> +</action> +</rule> +<rule> +<conditions> +<where subject="?name" rel="equals" multiple="true" value="Mammals,Crustaceans,Birds,Insects"/> +</conditions> +<action> +<box uri="?parent"> +<label value="?name"/> +</box> +</action> +</rule> +</template> +</vbox> + +</window> diff --git a/dom/xul/templates/tests/chrome/test_tmpl_parentcontenttag.xul b/dom/xul/templates/tests/chrome/test_tmpl_parentcontenttag.xul new file mode 100644 index 000000000..afcb1d34a --- /dev/null +++ b/dom/xul/templates/tests/chrome/test_tmpl_parentcontenttag.xul @@ -0,0 +1,114 @@ +<?xml version="1.0"?> +<?xml-stylesheet href="chrome://global/skin" type="text/css"?> +<?xml-stylesheet href="chrome://mochikit/content/tests/SimpleTest/test.css" type="text/css"?> + +<!-- + parent - content tag +--> + +<window title="XUL Template Tests" width="500" height="600" + onload="test_template();" + xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"> + <script type="application/javascript" + src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script> + + <body xmlns="http://www.w3.org/1999/xhtml" style="height: 300px; overflow: auto;"/> + + <data id="output"> + <groupbox step="-3" id="http://www.some-fictitious-zoo.com/birds" container="true" empty="false"> + <caption value="Birds"/> + <checkbox id="http://www.some-fictitious-zoo.com/birds/barnowl" label="Barn Owl"/> + <checkbox id="http://www.some-fictitious-zoo.com/birds/raven" label="Raven"/> + </groupbox> + <groupbox step="1" id="http://www.some-fictitious-zoo.com/insects"> + <caption value="Insects"/> + </groupbox> + <groupbox id="http://www.some-fictitious-zoo.com/crustaceans" container="true" empty="true"> + <caption value="Crustaceans"/> + </groupbox> + <groupbox id="http://www.some-fictitious-zoo.com/mammals" container="true" empty="false"> + <caption value="Mammals"/> + <checkbox id="http://www.some-fictitious-zoo.com/mammals/africanelephant" label="African Elephant"/> + <checkbox step="2" id="http://www.some-fictitious-zoo.com/mammals/koala" label="Koala"/> + <checkbox id="http://www.some-fictitious-zoo.com/mammals/polarbear" label="Polar Bear"/> + <checkbox id="http://www.some-fictitious-zoo.com/mammals/aardvark" label="aardvark"/> + <checkbox id="http://www.some-fictitious-zoo.com/mammals/ninebandedarmadillo" label="Nine-banded Armadillo"/> + <checkbox id="http://www.some-fictitious-zoo.com/mammals/gorilla" label="Gorilla"/> + </groupbox> + </data> + +<script src="templates_shared.js"/> + +<script> +<![CDATA[ +SimpleTest.waitForExplicitFinish(); + +var testid ="parent - content tag"; +var queryType = "rdf"; +var isTreeBuilder = false; +var needsOpen = false; +var notWorkingYet = false; +var notWorkingYetDynamic = false; +var expectedOutput = document.getElementById("output"); + +var changes = [ + // step 1 + function(targetds, root) { + var newnode = RDF.GetResource(ZOO_NS + 'insects'); + targetds.Assert(newnode, RDF.GetResource(ZOO_NS + 'rdf#name'), + RDF.GetLiteral('Insects'), true); + var container = ContainerUtils.MakeSeq(targetds, + RDF.GetResource(ZOO_NS + 'all-animals')); + container.InsertElementAt(newnode, '3', true); + }, + // step 2 + function(targetds, root) { + var newnode = RDF.GetResource(ZOO_NS + 'mammals/koala'); + targetds.Assert(newnode, RDF.GetResource(ZOO_NS + 'rdf#name'), + RDF.GetLiteral('Koala'), true); + var container = ContainerUtils.MakeSeq(targetds, + RDF.GetResource(ZOO_NS + 'mammals')); + container.InsertElementAt(newnode, '4', true); + }, + // step 3 + function(targetds, root) { + var container = ContainerUtils.MakeSeq(targetds, + RDF.GetResource(ZOO_NS + 'all-animals')); + var removednode = container.RemoveElementAt('2', true); + targetds.Unassert(removednode, RDF.GetResource(ZOO_NS + 'rdf#name'), + RDF.GetLiteral('Birds'), true); + } +]; +]]> +</script> + +<vbox xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul" id="root" datasources="rdf:null" ref="http://www.some-fictitious-zoo.com/all-animals"> +<template> +<rule> +<conditions> +<content uri="?uri" tag="groupbox"/> +<member container="?uri" child="?parent"/> +<triple subject="?parent" predicate="http://www.some-fictitious-zoo.com/rdf#name" object="?name"/> +<where subject="?name" rel="contains" value="a"/> +</conditions> +<action> +<checkbox uri="?parent" label="?name"/> +</action> +</rule> +<rule> +<conditions> +<content uri="?uri"/> +<member container="?uri" child="?parent"/> +<triple subject="?parent" predicate="http://www.some-fictitious-zoo.com/rdf#name" object="?name"/> +<where subject="?name" rel="equals" multiple="true" value="Mammals,Crustaceans,Birds,Insects"/> +</conditions> +<action> +<groupbox uri="?parent"> +<caption value="?name"/> +</groupbox> +</action> +</rule> +</template> +</vbox> + +</window> diff --git a/dom/xul/templates/tests/chrome/test_tmpl_parentsimplesyntax.xul b/dom/xul/templates/tests/chrome/test_tmpl_parentsimplesyntax.xul new file mode 100644 index 000000000..c5d94e0e2 --- /dev/null +++ b/dom/xul/templates/tests/chrome/test_tmpl_parentsimplesyntax.xul @@ -0,0 +1,110 @@ +<?xml version="1.0"?> +<?xml-stylesheet href="chrome://global/skin" type="text/css"?> +<?xml-stylesheet href="chrome://mochikit/content/tests/SimpleTest/test.css" type="text/css"?> + +<!-- + parent - simple syntax +--> + +<window title="XUL Template Tests" width="500" height="600" + onload="test_template();" + xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"> + <script type="application/javascript" + src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script> + + <body xmlns="http://www.w3.org/1999/xhtml" style="height: 300px; overflow: auto;"/> + + <data id="output"> + <hbox step="-3" id="http://www.some-fictitious-zoo.com/birds" container="true" empty="false"> + <label value="Birds"/> + <button id="http://www.some-fictitious-zoo.com/birds/emu" label="Emu"/> + <button id="http://www.some-fictitious-zoo.com/birds/barnowl" label="Barn Owl"/> + <button id="http://www.some-fictitious-zoo.com/birds/raven" label="Raven"/> + </hbox> + <hbox step="1" id="http://www.some-fictitious-zoo.com/insects"> + <label value="Insects"/> + </hbox> + <hbox id="http://www.some-fictitious-zoo.com/crustaceans" container="true" empty="true"> + <label value="Crustaceans"/> + </hbox> + <hbox id="http://www.some-fictitious-zoo.com/mammals" container="true" empty="false"> + <label value="Mammals"/> + <button id="http://www.some-fictitious-zoo.com/mammals/lion" label="Lion"/> + <button id="http://www.some-fictitious-zoo.com/mammals/hippopotamus" label="HIPPOPOTAMUS"/> + <button id="http://www.some-fictitious-zoo.com/mammals/africanelephant" label="African Elephant"/> + <button step="2" id="http://www.some-fictitious-zoo.com/mammals/koala" label="Koala"/> + <button id="http://www.some-fictitious-zoo.com/mammals/llama" label="LLAMA"/> + <button id="http://www.some-fictitious-zoo.com/mammals/polarbear" label="Polar Bear"/> + <button id="http://www.some-fictitious-zoo.com/mammals/aardvark" label="aardvark"/> + <button id="http://www.some-fictitious-zoo.com/mammals/ninebandedarmadillo" label="Nine-banded Armadillo"/> + <button id="http://www.some-fictitious-zoo.com/mammals/gorilla" label="Gorilla"/> + </hbox> + </data> + +<script src="templates_shared.js"/> + +<script> +<![CDATA[ +SimpleTest.waitForExplicitFinish(); + +var testid ="parent - simple syntax"; +var queryType = "rdf"; +var isTreeBuilder = false; +var needsOpen = false; +var notWorkingYet = false; +var notWorkingYetDynamic = false; +var expectedOutput = document.getElementById("output"); + +var changes = [ + // step 1 + function(targetds, root) { + var newnode = RDF.GetResource(ZOO_NS + 'insects'); + targetds.Assert(newnode, RDF.GetResource(ZOO_NS + 'rdf#name'), + RDF.GetLiteral('Insects'), true); + var container = ContainerUtils.MakeSeq(targetds, + RDF.GetResource(ZOO_NS + 'all-animals')); + container.InsertElementAt(newnode, '3', true); + }, + // step 2 + function(targetds, root) { + var newnode = RDF.GetResource(ZOO_NS + 'mammals/koala'); + targetds.Assert(newnode, RDF.GetResource(ZOO_NS + 'rdf#name'), + RDF.GetLiteral('Koala'), true); + var container = ContainerUtils.MakeSeq(targetds, + RDF.GetResource(ZOO_NS + 'mammals')); + container.InsertElementAt(newnode, '4', true); + }, + // step 3 + function(targetds, root) { + var container = ContainerUtils.MakeSeq(targetds, + RDF.GetResource(ZOO_NS + 'all-animals')); + var removednode = container.RemoveElementAt('2', true); + targetds.Unassert(removednode, RDF.GetResource(ZOO_NS + 'rdf#name'), + RDF.GetLiteral('Birds'), true); + } +]; +]]> +</script> + +<vbox xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul" id="root" datasources="rdf:null" ref="http://www.some-fictitious-zoo.com/all-animals"> +<template member="?parent"> +<rule parent="hbox"> +<button uri="?parent" label="rdf:http://www.some-fictitious-zoo.com/rdf#name"/> +</rule> +<rule> +<conditions> +<content uri="?uri"/> +<member container="?uri" child="?parent"/> +<triple subject="?parent" predicate="http://www.some-fictitious-zoo.com/rdf#name" object="?name"/> +<where subject="?name" rel="equals" multiple="true" value="Mammals,Crustaceans,Birds,Insects"/> +</conditions> +<action> +<hbox uri="?parent"> +<label value="?name"/> +</hbox> +</action> +</rule> +</template> +</vbox> + +</window> diff --git a/dom/xul/templates/tests/chrome/test_tmpl_query3triples.xul b/dom/xul/templates/tests/chrome/test_tmpl_query3triples.xul new file mode 100644 index 000000000..c0114effe --- /dev/null +++ b/dom/xul/templates/tests/chrome/test_tmpl_query3triples.xul @@ -0,0 +1,59 @@ +<?xml version="1.0"?> +<?xml-stylesheet href="chrome://global/skin" type="text/css"?> +<?xml-stylesheet href="chrome://mochikit/content/tests/SimpleTest/test.css" type="text/css"?> + +<!-- + query - 3 triples +--> + +<window title="XUL Template Tests" width="500" height="600" + onload="test_template();" + xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"> + <script type="application/javascript" + src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script> + + <body xmlns="http://www.w3.org/1999/xhtml" style="height: 300px; overflow: auto;"/> + + <data id="output" unordered="true"> + <label id="http://www.some-fictitious-zoo.com/arachnids/tarantula" value="Robert likes Tarantulas"/> + <label id="http://www.some-fictitious-zoo.com/reptiles/anaconda" value="Robert likes Anacondas"/> + <label id="http://www.some-fictitious-zoo.com/reptiles/chameleon" value="Robert likes Chameleons"/> + <label id="http://www.some-fictitious-zoo.com/mammals/africanelephant" value="Robert likes African Elephants"/> + </data> + +<script src="templates_shared.js"/> + +<script> +<![CDATA[ +SimpleTest.waitForExplicitFinish(); + +var testid ="query - 3 triples"; +var queryType = "rdf"; +var isTreeBuilder = false; +var needsOpen = false; +var notWorkingYet = false; +var notWorkingYetDynamic = false; +var expectedOutput = document.getElementById("output"); + +var changes = []; +]]> +</script> + +<vbox xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul" id="root" datasources="rdf:null" ref="http://www.some-fictitious-zoo.com/humans/robert"> +<template id="template"> +<query id="query"> +<content uri="?uri"/> +<triple subject="?uri" predicate="http://www.some-fictitious-zoo.com/rdf#name" object="?humanname"/> +<triple subject="?uri" predicate="http://www.some-fictitious-zoo.com/rdf#favoriteAnimal" object="?favoriteAnimal"/> +<triple subject="?favoriteAnimal" predicate="http://www.some-fictitious-zoo.com/rdf#name" object="?animalname"/> +</query> +<rule> +<conditions id="conditions"/> +<action> +<label uri="?favoriteAnimal" value="?humanname likes ?animalname^s"/> +</action> +</rule> +</template> +</vbox> + +</window> diff --git a/dom/xul/templates/tests/chrome/test_tmpl_query3tripleswherecontains.xul b/dom/xul/templates/tests/chrome/test_tmpl_query3tripleswherecontains.xul new file mode 100644 index 000000000..98006fc0d --- /dev/null +++ b/dom/xul/templates/tests/chrome/test_tmpl_query3tripleswherecontains.xul @@ -0,0 +1,111 @@ +<?xml version="1.0"?> +<?xml-stylesheet href="chrome://global/skin" type="text/css"?> +<?xml-stylesheet href="chrome://mochikit/content/tests/SimpleTest/test.css" type="text/css"?> + +<!-- + query - 3 triples - where contains +--> + +<window title="XUL Template Tests" width="500" height="600" + onload="test_template();" + xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"> + <script type="application/javascript" + src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script> + + <body xmlns="http://www.w3.org/1999/xhtml" style="height: 300px; overflow: auto;"/> + + <data id="output"> + <label id="http://www.some-fictitious-zoo.com/arachnids/tarantula" value="Robert likes Tarantulas"/> + <label step="-4" id="http://www.some-fictitious-zoo.com/mammals/africanelephant" value="Robert likes African Elephants"/> + <label step="5" id="http://www.some-fictitious-zoo.com/mammals/africanelephant" value="Robert likes African Elephants"/> + </data> + +<script src="templates_shared.js"/> + +<script> +<![CDATA[ +SimpleTest.waitForExplicitFinish(); + +var testid ="query - 3 triples - where contains"; +var queryType = "rdf"; +var isTreeBuilder = false; +var needsOpen = false; +var notWorkingYet = false; +var notWorkingYetDynamic = false; +var expectedOutput = document.getElementById("output"); + +var changes = [ + // step 1 + function(targetds, root) { + var newnode = RDF.GetResource(ZOO_NS + 'mammals/arctichare'); + targetds.Assert(newnode, RDF.GetResource(ZOO_NS + 'rdf#name'), + RDF.GetLiteral('Arctic Hare'), true); + var container = ContainerUtils.MakeSeq(targetds, + RDF.GetResource(ZOO_NS + 'mammals')); + container.AppendElement(newnode); + }, + // step 2 + function(targetds, root) { + var newnode = RDF.GetResource(ZOO_NS + 'mammals/koala'); + targetds.Assert(newnode, RDF.GetResource(ZOO_NS + 'rdf#name'), + RDF.GetLiteral('Koala'), true); + var container = ContainerUtils.MakeSeq(targetds, + RDF.GetResource(ZOO_NS + 'mammals')); + container.InsertElementAt(newnode, '4', true); + }, + // step 3 + function(targetds, root) { + var newnode = RDF.GetResource(ZOO_NS + 'mammals/zebra'); + targetds.Assert(newnode, RDF.GetResource(ZOO_NS + 'rdf#name'), + RDF.GetLiteral('Zebra'), true); + var container = ContainerUtils.MakeSeq(targetds, + RDF.GetResource(ZOO_NS + 'mammals')); + container.InsertElementAt(newnode, '1', true); + }, + // step 4 + function(targetds, root) { + var container = ContainerUtils.MakeSeq(targetds, + RDF.GetResource(ZOO_NS + 'mammals')); + var removednode = container.RemoveElementAt('4', true); + targetds.Unassert(removednode, RDF.GetResource(ZOO_NS + 'rdf#name'), + RDF.GetLiteral('African Elephant'), true); + }, + // step 5 + function(targetds, root) { + var newnode = RDF.GetResource(ZOO_NS + 'mammals/africanelephant'); + targetds.Assert(newnode, RDF.GetResource(ZOO_NS + 'rdf#name'), + RDF.GetLiteral('African Elephant'), true); + var container = ContainerUtils.MakeSeq(targetds, + RDF.GetResource(ZOO_NS + 'mammals')); + container.AppendElement(newnode); + }, + // step 6 + function(targetds, root) { + targetds.Assert(RDF.GetResource(ZOO_NS + 'mammals/koala'), + RDF.GetResource(ZOO_NS + 'rdf#specimensAsString'), + RDF.GetLiteral('8'), true); + } +]; +]]> +</script> + +<vbox xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul" id="root" datasources="rdf:null" ref="http://www.some-fictitious-zoo.com/humans/robert"> +<template id="template"> +<query id="query"> +<content uri="?uri"/> +<triple subject="?uri" predicate="http://www.some-fictitious-zoo.com/rdf#name" object="?humanname"/> +<triple subject="?uri" predicate="http://www.some-fictitious-zoo.com/rdf#favoriteAnimal" object="?favoriteAnimal"/> +<triple subject="?favoriteAnimal" predicate="http://www.some-fictitious-zoo.com/rdf#name" object="?animalname"/> +</query> +<rule> +<conditions id="conditions"> +<where subject="?favoriteAnimal" rel="contains" value="ant"/> +</conditions> +<action> +<label uri="?favoriteAnimal" value="?humanname likes ?animalname^s"/> +</action> +</rule> +</template> +</vbox> + +</window> diff --git a/dom/xul/templates/tests/chrome/test_tmpl_querymember3tripleswhereequals.xul b/dom/xul/templates/tests/chrome/test_tmpl_querymember3tripleswhereequals.xul new file mode 100644 index 000000000..8604a1321 --- /dev/null +++ b/dom/xul/templates/tests/chrome/test_tmpl_querymember3tripleswhereequals.xul @@ -0,0 +1,60 @@ +<?xml version="1.0"?> +<?xml-stylesheet href="chrome://global/skin" type="text/css"?> +<?xml-stylesheet href="chrome://mochikit/content/tests/SimpleTest/test.css" type="text/css"?> + +<!-- + query - member, 3 triples - where equals +--> + +<window title="XUL Template Tests" width="500" height="600" + onload="test_template();" + xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"> + <script type="application/javascript" + src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script> + + <body xmlns="http://www.w3.org/1999/xhtml" style="height: 300px; overflow: auto;"/> + + <data id="output" unordered="true"> + <label id="http://www.some-fictitious-zoo.com/birds/emu" value="Sarah likes Emus"/> + <label id="http://www.some-fictitious-zoo.com/mammals/polarbear" value="Sarah likes Polar Bears"/> + </data> + +<script src="templates_shared.js"/> + +<script> +<![CDATA[ +SimpleTest.waitForExplicitFinish(); + +var testid ="query - member, 3 triples - where equals"; +var queryType = "rdf"; +var isTreeBuilder = false; +var needsOpen = false; +var notWorkingYet = false; +var notWorkingYetDynamic = false; +var expectedOutput = document.getElementById("output"); + +var changes = []; +]]> +</script> + +<vbox xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul" id="root" datasources="rdf:null" ref="http://www.some-fictitious-zoo.com/humans"> +<template id="template"> +<query id="query"> +<content uri="?uri"/> +<member container="?uri" child="?human"/> +<triple subject="?human" predicate="http://www.some-fictitious-zoo.com/rdf#name" object="?humanname"/> +<triple subject="?human" predicate="http://www.some-fictitious-zoo.com/rdf#favoriteAnimal" object="?favoriteAnimal"/> +<triple subject="?favoriteAnimal" predicate="http://www.some-fictitious-zoo.com/rdf#name" object="?animalname"/> +</query> +<rule> +<conditions id="conditions"> +<where subject="?humanname" rel="equals" value="Sarah"/> +</conditions> +<action> +<label uri="?favoriteAnimal" value="?humanname likes ?animalname^s"/> +</action> +</rule> +</template> +</vbox> + +</window> diff --git a/dom/xul/templates/tests/chrome/test_tmpl_querymemberandtwotriples.xul b/dom/xul/templates/tests/chrome/test_tmpl_querymemberandtwotriples.xul new file mode 100644 index 000000000..9f3f36288 --- /dev/null +++ b/dom/xul/templates/tests/chrome/test_tmpl_querymemberandtwotriples.xul @@ -0,0 +1,58 @@ +<?xml version="1.0"?> +<?xml-stylesheet href="chrome://global/skin" type="text/css"?> +<?xml-stylesheet href="chrome://mochikit/content/tests/SimpleTest/test.css" type="text/css"?> + +<!-- + query - member and two triples +--> + +<window title="XUL Template Tests" width="500" height="600" + onload="test_template();" + xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"> + <script type="application/javascript" + src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script> + + <body xmlns="http://www.w3.org/1999/xhtml" style="height: 300px; overflow: auto;"/> + + <data id="output" unordered="true"> + <label id="http://www.some-fictitious-zoo.com/arachnids/tarantula" value="Tarantula"/> + <label id="http://www.some-fictitious-zoo.com/reptiles/anaconda" value="Anaconda"/> + <label id="http://www.some-fictitious-zoo.com/reptiles/chameleon" value="Chameleon"/> + <label id="http://www.some-fictitious-zoo.com/mammals/africanelephant" value="African Elephant"/> + <label id="http://www.some-fictitious-zoo.com/birds/emu" value="Emu"/> + <label id="http://www.some-fictitious-zoo.com/mammals/polarbear" value="Polar Bear"/> + </data> + +<script src="templates_shared.js"/> + +<script> +<![CDATA[ +SimpleTest.waitForExplicitFinish(); + +var testid ="query - member and two triples"; +var queryType = "rdf"; +var isTreeBuilder = false; +var needsOpen = false; +var notWorkingYet = false; +var notWorkingYetDynamic = false; +var expectedOutput = document.getElementById("output"); + +var changes = []; +]]> +</script> + +<vbox xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul" id="root" datasources="rdf:null" ref="http://www.some-fictitious-zoo.com/humans"> +<template id="template"> +<query id="query"> +<content uri="?uri"/> +<member container="?uri" child="?human"/> +<triple subject="?human" predicate="http://www.some-fictitious-zoo.com/rdf#favoriteAnimal" object="?child"/> +<triple subject="?child" predicate="http://www.some-fictitious-zoo.com/rdf#name" object="?name"/> +</query> +,<action> +<label uri="?child" value="?name"/> +</action> +</template> +</vbox> + +</window> diff --git a/dom/xul/templates/tests/chrome/test_tmpl_querymembertriplemembertriple.xul b/dom/xul/templates/tests/chrome/test_tmpl_querymembertriplemembertriple.xul new file mode 100644 index 000000000..b5b3acf79 --- /dev/null +++ b/dom/xul/templates/tests/chrome/test_tmpl_querymembertriplemembertriple.xul @@ -0,0 +1,64 @@ +<?xml version="1.0"?> +<?xml-stylesheet href="chrome://global/skin" type="text/css"?> +<?xml-stylesheet href="chrome://mochikit/content/tests/SimpleTest/test.css" type="text/css"?> + +<!-- + query - member, triple, member, triple +--> + +<window title="XUL Template Tests" width="500" height="600" + onload="test_template();" + xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"> + <script type="application/javascript" + src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script> + + <body xmlns="http://www.w3.org/1999/xhtml" style="height: 300px; overflow: auto;"/> + + <data id="output" unordered="true"> + <label id="http://www.some-fictitious-zoo.com/arachnids/tarantula" value="Tarantula"/> + <label id="http://www.some-fictitious-zoo.com/reptiles/chameleon" value="Chameleon"/> + <label id="http://www.some-fictitious-zoo.com/mammals/llama" value="LLAMA"/> + <label step="-1" id="http://www.some-fictitious-zoo.com/birds/emu" value="Emu"/> + </data> + +<script src="templates_shared.js"/> + +<script> +<![CDATA[ +SimpleTest.waitForExplicitFinish(); + +var testid ="query - member, triple, member, triple"; +var queryType = "rdf"; +var isTreeBuilder = false; +var needsOpen = false; +var notWorkingYet = false; +var notWorkingYetDynamic = false; +var expectedOutput = document.getElementById("output"); + +var changes = [ + // step 1 + function(targetds, root) { + targetds.Unassert(RDF.GetResource(ZOO_NS + 'humans/sarah'), + RDF.GetResource(ZOO_NS + 'rdf#pets'), + RDF.GetResource(ZOO_NS + 'sarahs-pets'), true); + } +]; +]]> +</script> + +<vbox xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul" id="root" datasources="rdf:null" ref="http://www.some-fictitious-zoo.com/humans"> +<template id="template"> +<query id="query"> +<content uri="?uri"/> +<member container="?uri" child="?human"/> +<triple subject="?human" predicate="http://www.some-fictitious-zoo.com/rdf#pets" object="?pets"/> +<member container="?pets" child="?child"/> +<triple subject="?child" predicate="http://www.some-fictitious-zoo.com/rdf#name" object="?name"/> +</query> +,<action> +<label uri="?child" value="?name"/> +</action> +</template> +</vbox> + +</window> diff --git a/dom/xul/templates/tests/chrome/test_tmpl_queryresourcematch.xul b/dom/xul/templates/tests/chrome/test_tmpl_queryresourcematch.xul new file mode 100644 index 000000000..b13ccdb7f --- /dev/null +++ b/dom/xul/templates/tests/chrome/test_tmpl_queryresourcematch.xul @@ -0,0 +1,58 @@ +<?xml version="1.0"?> +<?xml-stylesheet href="chrome://global/skin" type="text/css"?> +<?xml-stylesheet href="chrome://mochikit/content/tests/SimpleTest/test.css" type="text/css"?> + +<!-- + query - resource match +--> + +<window title="XUL Template Tests" width="500" height="600" + onload="test_template();" + xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"> + <script type="application/javascript" + src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script> + + <body xmlns="http://www.w3.org/1999/xhtml" style="height: 300px; overflow: auto;"/> + + <data id="output"> + <label id="http://www.some-fictitious-zoo.com/arachnids" container="true" empty="false" value="Arachnids"/> + <label id="http://www.some-fictitious-zoo.com/birds" container="true" empty="false" value="Birds"/> + <label id="http://www.some-fictitious-zoo.com/crustaceans" container="true" empty="true" value="Crustaceans"/> + <label id="http://www.some-fictitious-zoo.com/fish" container="true" empty="false" value="Fish"/> + <label id="http://www.some-fictitious-zoo.com/mammals" container="true" empty="false" value="Mammals"/> + <label id="http://www.some-fictitious-zoo.com/reptiles" container="true" empty="false" value="Reptiles"/> + </data> + +<script src="templates_shared.js"/> + +<script> +<![CDATA[ +SimpleTest.waitForExplicitFinish(); + +var testid ="query - resource match"; +var queryType = "rdf"; +var isTreeBuilder = false; +var needsOpen = false; +var notWorkingYet = false; +var notWorkingYetDynamic = false; +var expectedOutput = document.getElementById("output"); + +var changes = []; +]]> +</script> + +<vbox xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul" id="root" datasources="rdf:null" ref="http://www.some-fictitious-zoo.com/all-animals"> +<template id="template"> +<query id="query"> +<content uri="?uri"/> +<member container="?uri" child="?child"/> +<triple subject="?child" predicate="http://www.w3.org/1999/02/22-rdf-syntax-ns#type" object="http://www.some-fictitious-zoo.com/rdf#Class"/> +<triple subject="?child" predicate="http://www.some-fictitious-zoo.com/rdf#name" object="?name"/> +</query> +,<action> +<label uri="?child" value="?name"/> +</action> +</template> +</vbox> + +</window> diff --git a/dom/xul/templates/tests/chrome/test_tmpl_queryreversetriple.xul b/dom/xul/templates/tests/chrome/test_tmpl_queryreversetriple.xul new file mode 100644 index 000000000..633df8834 --- /dev/null +++ b/dom/xul/templates/tests/chrome/test_tmpl_queryreversetriple.xul @@ -0,0 +1,53 @@ +<?xml version="1.0"?> +<?xml-stylesheet href="chrome://global/skin" type="text/css"?> +<?xml-stylesheet href="chrome://mochikit/content/tests/SimpleTest/test.css" type="text/css"?> + +<!-- + query - reverse triple +--> + +<window title="XUL Template Tests" width="500" height="600" + onload="test_template();" + xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"> + <script type="application/javascript" + src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script> + + <body xmlns="http://www.w3.org/1999/xhtml" style="height: 300px; overflow: auto;"/> + + <data id="output"> + <label id="http://www.some-fictitious-zoo.com/reptiles" container="true" empty="false" value="Reptiles"/> + <label id="http://www.some-fictitious-zoo.com/crustaceans" container="true" empty="true" value="Crustaceans"/> + </data> + +<script src="templates_shared.js"/> + +<script> +<![CDATA[ +SimpleTest.waitForExplicitFinish(); + +var testid ="query - reverse triple"; +var queryType = "rdf"; +var isTreeBuilder = false; +var needsOpen = false; +var notWorkingYet = false; +var notWorkingYetDynamic = false; +var expectedOutput = document.getElementById("output"); + +var changes = []; +]]> +</script> + +<vbox xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul" id="root" datasources="rdf:null" ref="http://www.some-fictitious-zoo.com/humans/robert"> +<template id="template"> +<query id="query"> +<content uri="?uri"/> +<triple subject="?child" predicate="http://www.some-fictitious-zoo.com/rdf#keeper" object="?uri"/> +<triple subject="?child" predicate="http://www.some-fictitious-zoo.com/rdf#name" object="?name"/> +</query> +,<action> +<label uri="?child" value="?name"/> +</action> +</template> +</vbox> + +</window> diff --git a/dom/xul/templates/tests/chrome/test_tmpl_queryselfwithtriple.xul b/dom/xul/templates/tests/chrome/test_tmpl_queryselfwithtriple.xul new file mode 100644 index 000000000..bd10d0d1f --- /dev/null +++ b/dom/xul/templates/tests/chrome/test_tmpl_queryselfwithtriple.xul @@ -0,0 +1,51 @@ +<?xml version="1.0"?> +<?xml-stylesheet href="chrome://global/skin" type="text/css"?> +<?xml-stylesheet href="chrome://mochikit/content/tests/SimpleTest/test.css" type="text/css"?> + +<!-- + query - self with triple +--> + +<window title="XUL Template Tests" width="500" height="600" + onload="test_template();" + xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"> + <script type="application/javascript" + src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script> + + <body xmlns="http://www.w3.org/1999/xhtml" style="height: 300px; overflow: auto;"/> + + <data id="output"> + <label id="http://www.some-fictitious-zoo.com/mammals" container="true" empty="false" value="Mammals"/> + </data> + +<script src="templates_shared.js"/> + +<script> +<![CDATA[ +SimpleTest.waitForExplicitFinish(); + +var testid ="query - self with triple"; +var queryType = "rdf"; +var isTreeBuilder = false; +var needsOpen = false; +var notWorkingYet = false; +var notWorkingYetDynamic = false; +var expectedOutput = document.getElementById("output"); + +var changes = []; +]]> +</script> + +<vbox xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul" id="root" datasources="rdf:null" ref="http://www.some-fictitious-zoo.com/mammals"> +<template> +<query id="query"> +<content uri="?uri"/> +<triple subject="?uri" predicate="http://www.some-fictitious-zoo.com/rdf#name" object="?name"/> +</query> +<action> +<label uri="?uri" value="?name"/> +</action> +</template> +</vbox> + +</window> diff --git a/dom/xul/templates/tests/chrome/test_tmpl_querysetone.xul b/dom/xul/templates/tests/chrome/test_tmpl_querysetone.xul new file mode 100644 index 000000000..ed9c93843 --- /dev/null +++ b/dom/xul/templates/tests/chrome/test_tmpl_querysetone.xul @@ -0,0 +1,95 @@ +<?xml version="1.0"?> +<?xml-stylesheet href="chrome://global/skin" type="text/css"?> +<?xml-stylesheet href="chrome://mochikit/content/tests/SimpleTest/test.css" type="text/css"?> + +<!-- + queryset - one +--> + +<window title="XUL Template Tests" width="500" height="600" + onload="test_template();" + xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"> + <script type="application/javascript" + src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script> + + <body xmlns="http://www.w3.org/1999/xhtml" style="height: 300px; overflow: auto;"/> + + <data id="output"> + <button step="3" id="http://www.some-fictitious-zoo.com/birds/wren" label="Wren"/> + <button id="http://www.some-fictitious-zoo.com/birds/emu" label="Emu"/> + <button step="-4" id="http://www.some-fictitious-zoo.com/birds/barnowl" label="Barn Owl"/> + <button id="http://www.some-fictitious-zoo.com/birds/raven" label="Raven"/> + <button step="2" id="http://www.some-fictitious-zoo.com/birds/archaeopteryx" label="Archaeopteryx"/> + <button step="1" id="http://www.some-fictitious-zoo.com/birds/emperorpenguin" label="Emperor Penguin"/> + </data> + +<script src="templates_shared.js"/> + +<script> +<![CDATA[ +SimpleTest.waitForExplicitFinish(); + +var testid ="queryset - one"; +var queryType = "rdf"; +var isTreeBuilder = false; +var needsOpen = false; +var notWorkingYet = false; +var notWorkingYetDynamic = false; +var expectedOutput = document.getElementById("output"); + +var changes = [ + // step 1 + function(targetds, root) { + var newnode = RDF.GetResource(ZOO_NS + 'birds/emperorpenguin'); + targetds.Assert(newnode, RDF.GetResource(ZOO_NS + 'rdf#name'), + RDF.GetLiteral('Emperor Penguin'), true); + var container = ContainerUtils.MakeSeq(targetds, + RDF.GetResource(ZOO_NS + 'birds')); + container.AppendElement(newnode); + }, + // step 2 + function(targetds, root) { + var newnode = RDF.GetResource(ZOO_NS + 'birds/archaeopteryx'); + targetds.Assert(newnode, RDF.GetResource(ZOO_NS + 'rdf#name'), + RDF.GetLiteral('Archaeopteryx'), true); + var container = ContainerUtils.MakeSeq(targetds, + RDF.GetResource(ZOO_NS + 'birds')); + container.InsertElementAt(newnode, '4', true); + }, + // step 3 + function(targetds, root) { + var newnode = RDF.GetResource(ZOO_NS + 'birds/wren'); + targetds.Assert(newnode, RDF.GetResource(ZOO_NS + 'rdf#name'), + RDF.GetLiteral('Wren'), true); + var container = ContainerUtils.MakeSeq(targetds, + RDF.GetResource(ZOO_NS + 'birds')); + container.InsertElementAt(newnode, '1', true); + }, + // step 4 + function(targetds, root) { + var container = ContainerUtils.MakeSeq(targetds, + RDF.GetResource(ZOO_NS + 'birds')); + var removednode = container.RemoveElementAt('3', true); + targetds.Unassert(removednode, RDF.GetResource(ZOO_NS + 'rdf#name'), + RDF.GetLiteral('Barn Owl'), true); + } +]; +]]> +</script> + +<vbox xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul" id="root" datasources="rdf:null" ref="http://www.some-fictitious-zoo.com/birds"> +<template id="template"> +<queryset> +<query> +<content uri="?uri"/> +<member container="?uri" child="?animal"/> +<triple subject="?animal" predicate="http://www.some-fictitious-zoo.com/rdf#name" object="?name"/> +</query> +<action> +<button uri="?animal" label="?name"/> +</action> +</queryset> +</template> +</vbox> + +</window> diff --git a/dom/xul/templates/tests/chrome/test_tmpl_querysettwo.xul b/dom/xul/templates/tests/chrome/test_tmpl_querysettwo.xul new file mode 100644 index 000000000..1f6627931 --- /dev/null +++ b/dom/xul/templates/tests/chrome/test_tmpl_querysettwo.xul @@ -0,0 +1,117 @@ +<?xml version="1.0"?> +<?xml-stylesheet href="chrome://global/skin" type="text/css"?> +<?xml-stylesheet href="chrome://mochikit/content/tests/SimpleTest/test.css" type="text/css"?> + +<!-- + queryset - two +--> + +<window title="XUL Template Tests" width="500" height="600" + onload="test_template();" + xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"> + <script type="application/javascript" + src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script> + + <body xmlns="http://www.w3.org/1999/xhtml" style="height: 300px; overflow: auto;"/> + + <data id="output"> + <button step="3" id="http://www.some-fictitious-zoo.com/birds/wren" label="Wren"/> + <button id="http://www.some-fictitious-zoo.com/birds/emu" label="Emu"/> + <checkbox step="-4" id="http://www.some-fictitious-zoo.com/birds/barnowl" label="Barn Owl"/> + <button id="http://www.some-fictitious-zoo.com/birds/raven" label="Raven"/> + <button step="2" id="http://www.some-fictitious-zoo.com/birds/archaeopteryx" label="Archaeopteryx"/> + <button step="1" id="http://www.some-fictitious-zoo.com/birds/emperorpenguin" label="Emperor Penguin"/> + </data> + +<script src="templates_shared.js"/> + +<script> +<![CDATA[ +SimpleTest.waitForExplicitFinish(); + +var testid ="queryset - two"; +var queryType = "rdf"; +var isTreeBuilder = false; +var needsOpen = false; +var notWorkingYet = false; +var notWorkingYetDynamic = false; +var expectedOutput = document.getElementById("output"); + +var changes = [ + // step 1 + function(targetds, root) { + var newnode = RDF.GetResource(ZOO_NS + 'birds/emperorpenguin'); + targetds.Assert(newnode, RDF.GetResource(ZOO_NS + 'rdf#name'), + RDF.GetLiteral('Emperor Penguin'), true); + var container = ContainerUtils.MakeSeq(targetds, + RDF.GetResource(ZOO_NS + 'birds')); + container.AppendElement(newnode); + expectConsoleMessage(ZOO_NS + 'birds', ZOO_NS + 'birds/emperorpenguin', true, true, + '2 matching rule 1'); + }, + // step 2 + function(targetds, root) { + var newnode = RDF.GetResource(ZOO_NS + 'birds/archaeopteryx'); + targetds.Assert(newnode, RDF.GetResource(ZOO_NS + 'rdf#name'), + RDF.GetLiteral('Archaeopteryx'), true); + var container = ContainerUtils.MakeSeq(targetds, + RDF.GetResource(ZOO_NS + 'birds')); + container.InsertElementAt(newnode, '4', true); + expectConsoleMessage(ZOO_NS + 'birds', ZOO_NS + 'birds/archaeopteryx', true, true, + '2 matching rule 1'); + }, + // step 3 + function(targetds, root) { + var newnode = RDF.GetResource(ZOO_NS + 'birds/wren'); + targetds.Assert(newnode, RDF.GetResource(ZOO_NS + 'rdf#name'), + RDF.GetLiteral('Wren'), true); + var container = ContainerUtils.MakeSeq(targetds, + RDF.GetResource(ZOO_NS + 'birds')); + container.InsertElementAt(newnode, '1', true); + expectConsoleMessage(ZOO_NS + 'birds', ZOO_NS + 'birds/wren', true, true, + '2 matching rule 1'); + }, + // step 4 + function(targetds, root) { + var container = ContainerUtils.MakeSeq(targetds, + RDF.GetResource(ZOO_NS + 'birds')); + var removednode = container.RemoveElementAt('3', true); + targetds.Unassert(removednode, RDF.GetResource(ZOO_NS + 'rdf#name'), + RDF.GetLiteral('Barn Owl'), true); + expectConsoleMessage(ZOO_NS + 'birds', ZOO_NS + 'birds/barnowl', false, false, + '2 (active query is 1)'); + expectConsoleMessage(ZOO_NS + 'birds', ZOO_NS + 'birds/barnowl', false, true, + '1 (no new active query)'); + } +]; +]]> +</script> + +<vbox xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul" id="root" flags="logging" + datasources="rdf:null" ref="http://www.some-fictitious-zoo.com/birds"> +<template> +<queryset> +<query> +<content uri="?uri"/> +<member container="?uri" child="?animal"/> +<triple subject="?animal" predicate="http://www.some-fictitious-zoo.com/rdf#name" object="Barn Owl"/> +<triple subject="?animal" predicate="http://www.some-fictitious-zoo.com/rdf#name" object="?name"/> +</query> +<action> +<checkbox uri="?animal" label="?name"/> +</action> +</queryset> +<queryset> +<query> +<content uri="?uri"/> +<member container="?uri" child="?animal"/> +<triple subject="?animal" predicate="http://www.some-fictitious-zoo.com/rdf#name" object="?name"/> +</query> +<action> +<button uri="?animal" label="?name"/> +</action> +</queryset> +</template> +</vbox> + +</window> diff --git a/dom/xul/templates/tests/chrome/test_tmpl_querysettwowithcondition.xul b/dom/xul/templates/tests/chrome/test_tmpl_querysettwowithcondition.xul new file mode 100644 index 000000000..29b19f984 --- /dev/null +++ b/dom/xul/templates/tests/chrome/test_tmpl_querysettwowithcondition.xul @@ -0,0 +1,149 @@ +<?xml version="1.0"?> +<?xml-stylesheet href="chrome://global/skin" type="text/css"?> +<?xml-stylesheet href="chrome://mochikit/content/tests/SimpleTest/test.css" type="text/css"?> + +<!-- + queryset - two with condition +--> + +<window title="XUL Template Tests" width="500" height="600" + onload="test_template();" + xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"> + <script type="application/javascript" + src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script> + + <body xmlns="http://www.w3.org/1999/xhtml" style="height: 300px; overflow: auto;"/> + + <data id="output"> + <hbox step="-6" id="http://www.some-fictitious-zoo.com/birds/emu"> + <label value="Emu"/> + <label value="Dromaius novaehollandiae"/> + </hbox> + <button step="6" id="http://www.some-fictitious-zoo.com/birds/emu" label="No Emus Currently"/> + <hbox step="3" id="http://www.some-fictitious-zoo.com/birds/archaeopteryx"> + <label value="Archaeopteryx"/> + <label value="Archaeopteryx lithographica"/> + </hbox> + <hbox step="-2" id="http://www.some-fictitious-zoo.com/birds/barnowl"> + <label value="Barn Owl"/> + <label value="Tyto alba"/> + </hbox> + <button step="-5" id="http://www.some-fictitious-zoo.com/birds/raven" label="No Ravens Currently"/> + <hbox step="5" id="http://www.some-fictitious-zoo.com/birds/raven"> + <label step="-7" value="Raven"/> + <label step="7" value="Crow"/> + <label value="Corvus corax"/> + </hbox> + </data> + +<script src="templates_shared.js"/> + +<script> +<![CDATA[ +SimpleTest.waitForExplicitFinish(); + +var testid ="queryset - two with condition"; +var queryType = "rdf"; +var isTreeBuilder = false; +var needsOpen = false; +var notWorkingYet = false; +var notWorkingYetDynamic = false; +var expectedOutput = document.getElementById("output"); + +var changes = [ + // step 1 + function(targetds, root) { + var newnode = RDF.GetResource(ZOO_NS + 'birds/archaeopteryx'); + targetds.Assert(newnode, RDF.GetResource(ZOO_NS + 'rdf#name'), + RDF.GetLiteral('Archaeopteryx'), true); + var container = ContainerUtils.MakeSeq(targetds, + RDF.GetResource(ZOO_NS + 'birds')); + container.InsertElementAt(newnode, '2', true); + }, + // step 2 + function(targetds, root) { + var container = ContainerUtils.MakeSeq(targetds, + RDF.GetResource(ZOO_NS + 'birds')); + var removednode = container.RemoveElementAt('3', true); + targetds.Unassert(removednode, RDF.GetResource(ZOO_NS + 'rdf#name'), + RDF.GetLiteral('Barn Owl'), true); + }, + // step 3 + function(targetds, root) { + targetds.Assert(RDF.GetResource(ZOO_NS + 'birds/archaeopteryx'), + RDF.GetResource(ZOO_NS + 'rdf#species'), + RDF.GetLiteral('Archaeopteryx lithographica'), true); + }, + // step 4 + function(targetds, root) { + targetds.Assert(RDF.GetResource(ZOO_NS + 'birds/archaeopteryx'), + RDF.GetResource(ZOO_NS + 'rdf#specimens'), + RDF.GetLiteral('5'), true); + }, + // step 5 + function(targetds, root) { + var subject = RDF.GetResource(ZOO_NS + 'birds/raven'); + var predicate = RDF.GetResource(ZOO_NS + 'rdf#specimens'); + var oldval = targetds.GetTarget(subject, predicate, true); + targetds.Change(RDF.GetResource(ZOO_NS + 'birds/raven'), + RDF.GetResource(ZOO_NS + 'rdf#specimens'), + oldval, RDF.GetLiteral('2')); + }, + // step 6 + function(targetds, root) { + var subject = RDF.GetResource(ZOO_NS + 'birds/emu'); + var predicate = RDF.GetResource(ZOO_NS + 'rdf#specimens'); + var oldval = targetds.GetTarget(subject, predicate, true); + targetds.Change(RDF.GetResource(ZOO_NS + 'birds/emu'), + RDF.GetResource(ZOO_NS + 'rdf#specimens'), + oldval, RDF.GetLiteral('0')); + }, + // step 7 + function(targetds, root) { + var subject = RDF.GetResource(ZOO_NS + 'birds/raven'); + var predicate = RDF.GetResource(ZOO_NS + 'rdf#name'); + var oldval = targetds.GetTarget(subject, predicate, true); + targetds.Change(RDF.GetResource(ZOO_NS + 'birds/raven'), + RDF.GetResource(ZOO_NS + 'rdf#name'), + oldval, RDF.GetLiteral('Crow')); + } +]; +]]> +</script> + +<vbox xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul" id="root" datasources="rdf:null" ref="http://www.some-fictitious-zoo.com/birds"> +<template> +<queryset> +<query> +<content uri="?uri"/> +<member container="?uri" child="?child"/> +<triple subject="?child" predicate="http://www.some-fictitious-zoo.com/rdf#name" object="?name"/> +<triple subject="?child" predicate="http://www.some-fictitious-zoo.com/rdf#specimens" object="?specimens"/> +</query> +<rule> +<conditions> +<where subject="?specimens" rel="equals" value="0"/> +</conditions> +<action> +<button uri="?child" label="No ?name^s Currently"/> +</action> +</rule> +</queryset> +<queryset> +<query> +<content uri="?uri"/> +<member container="?uri" child="?child"/> +<triple subject="?child" predicate="http://www.some-fictitious-zoo.com/rdf#name" object="?name"/> +<triple subject="?child" predicate="http://www.some-fictitious-zoo.com/rdf#species" object="?species"/> +</query> +<action> +<hbox uri="?child"> +<label value="?name^?unknown"/> +<label value="?species^?specimens"/> +</hbox> +</action> +</queryset> +</template> +</vbox> + +</window> diff --git a/dom/xul/templates/tests/chrome/test_tmpl_querysyntax.xul b/dom/xul/templates/tests/chrome/test_tmpl_querysyntax.xul new file mode 100644 index 000000000..713cb371c --- /dev/null +++ b/dom/xul/templates/tests/chrome/test_tmpl_querysyntax.xul @@ -0,0 +1,63 @@ +<?xml version="1.0"?> +<?xml-stylesheet href="chrome://global/skin" type="text/css"?> +<?xml-stylesheet href="chrome://mochikit/content/tests/SimpleTest/test.css" type="text/css"?> + +<!-- + query syntax +--> + +<window title="XUL Template Tests" width="500" height="600" + onload="test_template();" + xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"> + <script type="application/javascript" + src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script> + + <body xmlns="http://www.w3.org/1999/xhtml" style="height: 300px; overflow: auto;"/> + + <data id="output"> + <label step="-1" id="http://www.some-fictitious-zoo.com/arachnids/tarantula" value="Tarantula"/> + <label step="1" id="http://www.some-fictitious-zoo.com/arachnids/tarantula" value="Hairy Spider"/> + </data> + +<script src="templates_shared.js"/> + +<script> +<![CDATA[ +SimpleTest.waitForExplicitFinish(); + +var testid ="query syntax"; +var queryType = "rdf"; +var isTreeBuilder = false; +var needsOpen = false; +var notWorkingYet = false; +var notWorkingYetDynamic = false; +var expectedOutput = document.getElementById("output"); + +var changes = [ + // step 1 + function(targetds, root) { + var subject = RDF.GetResource(ZOO_NS + 'arachnids/tarantula'); + var predicate = RDF.GetResource(ZOO_NS + 'rdf#name'); + var oldval = targetds.GetTarget(subject, predicate, true); + targetds.Change(RDF.GetResource(ZOO_NS + 'arachnids/tarantula'), + RDF.GetResource(ZOO_NS + 'rdf#name'), + oldval, RDF.GetLiteral('Hairy Spider')); + } +]; +]]> +</script> + +<vbox xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul" id="root" datasources="rdf:null" ref="http://www.some-fictitious-zoo.com/arachnids"> +<template id="template"> +<query id="query"> +<content uri="?uri"/> +<member container="?uri" child="?animal"/> +<triple subject="?animal" predicate="http://www.some-fictitious-zoo.com/rdf#name" object="?name"/> +</query> +<action id="action"> +<label uri="?animal" value="?name"/> +</action> +</template> +</vbox> + +</window> diff --git a/dom/xul/templates/tests/chrome/test_tmpl_querysyntaxmultiplerules.xul b/dom/xul/templates/tests/chrome/test_tmpl_querysyntaxmultiplerules.xul new file mode 100644 index 000000000..e1ac87c72 --- /dev/null +++ b/dom/xul/templates/tests/chrome/test_tmpl_querysyntaxmultiplerules.xul @@ -0,0 +1,115 @@ +<?xml version="1.0"?> +<?xml-stylesheet href="chrome://global/skin" type="text/css"?> +<?xml-stylesheet href="chrome://mochikit/content/tests/SimpleTest/test.css" type="text/css"?> + +<!-- + query syntax - multiple rules +--> + +<window title="XUL Template Tests" width="500" height="600" + onload="test_template();" + xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"> + <script type="application/javascript" + src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script> + + <body xmlns="http://www.w3.org/1999/xhtml" style="height: 300px; overflow: auto;"/> + + <data id="output"> + <label step="-2" id="http://www.some-fictitious-zoo.com/mammals/lion" value="Lion"/> + <checkbox step="2" id="http://www.some-fictitious-zoo.com/mammals/lion" label="Lion"/> + <label id="http://www.some-fictitious-zoo.com/mammals/hippopotamus" value="HIPPOPOTAMUS"/> + <checkbox id="http://www.some-fictitious-zoo.com/mammals/africanelephant" label="African Elephant"/> + <label step="5" id="http://www.some-fictitious-zoo.com/mammals/chimpanzee" value="Chimpanzee"/> + <label id="http://www.some-fictitious-zoo.com/mammals/llama" value="LLAMA"/> + <checkbox step="-1" id="http://www.some-fictitious-zoo.com/mammals/polarbear" label="Polar Bear"/> + <label step="1" id="http://www.some-fictitious-zoo.com/mammals/polarbear" value="Polar Bear"/> + <label id="http://www.some-fictitious-zoo.com/mammals/aardvark" value="aardvark"/> + <label step="-3" id="http://www.some-fictitious-zoo.com/mammals/ninebandedarmadillo" value="Nine-banded Armadillo"/> + <checkbox id="http://www.some-fictitious-zoo.com/mammals/gorilla" label="Gorilla"/> + </data> + +<script src="templates_shared.js"/> + +<script> +<![CDATA[ +SimpleTest.waitForExplicitFinish(); + +var testid ="query syntax - multiple rules"; +var queryType = "rdf"; +var isTreeBuilder = false; +var needsOpen = false; +var notWorkingYet = false; +var notWorkingYetDynamic = false; +var expectedOutput = document.getElementById("output"); + +var changes = [ + // step 1 + function(targetds, root) { + var subject = RDF.GetResource(ZOO_NS + 'mammals/polarbear'); + var predicate = RDF.GetResource(ZOO_NS + 'rdf#specimens'); + var oldval = targetds.GetTarget(subject, predicate, true); + targetds.Change(RDF.GetResource(ZOO_NS + 'mammals/polarbear'), + RDF.GetResource(ZOO_NS + 'rdf#specimens'), + oldval, RDF.GetLiteral('5')); + }, + // step 2 + function(targetds, root) { + var subject = RDF.GetResource(ZOO_NS + 'mammals/lion'); + var predicate = RDF.GetResource(ZOO_NS + 'rdf#specimens'); + var oldval = targetds.GetTarget(subject, predicate, true); + targetds.Change(RDF.GetResource(ZOO_NS + 'mammals/lion'), + RDF.GetResource(ZOO_NS + 'rdf#specimens'), + oldval, RDF.GetLiteral('9')); + }, + // step 3 + function(targetds, root) { + var container = ContainerUtils.MakeSeq(targetds, + RDF.GetResource(ZOO_NS + 'mammals')); + var removednode = container.RemoveElementAt('7', true); + targetds.Unassert(removednode, RDF.GetResource(ZOO_NS + 'rdf#name'), + RDF.GetLiteral('Nine-banded Armadillo'), true); + }, + // step 4 + function(targetds, root) { + var newnode = RDF.GetResource(ZOO_NS + 'mammals/chimpanzee'); + targetds.Assert(newnode, RDF.GetResource(ZOO_NS + 'rdf#name'), + RDF.GetLiteral('Chimpanzee'), true); + var container = ContainerUtils.MakeSeq(targetds, + RDF.GetResource(ZOO_NS + 'mammals')); + container.InsertElementAt(newnode, '4', true); + }, + // step 5 + function(targetds, root) { + targetds.Assert(RDF.GetResource(ZOO_NS + 'mammals/chimpanzee'), + RDF.GetResource(ZOO_NS + 'rdf#specimens'), + RDF.GetLiteral('3'), true); + } +]; +]]> +</script> + +<vbox xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul" id="root" datasources="rdf:null" ref="http://www.some-fictitious-zoo.com/mammals"> +<template id="template"> +<query> +<content uri="?uri"/> +<member container="?uri" child="?animal"/> +<triple subject="?animal" predicate="http://www.some-fictitious-zoo.com/rdf#name" object="?name"/> +<triple subject="?animal" predicate="http://www.some-fictitious-zoo.com/rdf#specimens" object="?specimens"/> +</query> +<rule> +<conditions id="conditions"> +<where subject="?specimens" rel="greater" value="6"/> +</conditions> +<action> +<checkbox uri="?animal" label="?name"/> +</action> +</rule> +<rule id="rule2"> +<action> +<label uri="?animal" value="?name"/> +</action> +</rule> +</template> +</vbox> + +</window> diff --git a/dom/xul/templates/tests/chrome/test_tmpl_querysyntaxmultiplerulesfirstconditionall.xul b/dom/xul/templates/tests/chrome/test_tmpl_querysyntaxmultiplerulesfirstconditionall.xul new file mode 100644 index 000000000..4509c1018 --- /dev/null +++ b/dom/xul/templates/tests/chrome/test_tmpl_querysyntaxmultiplerulesfirstconditionall.xul @@ -0,0 +1,71 @@ +<?xml version="1.0"?> +<?xml-stylesheet href="chrome://global/skin" type="text/css"?> +<?xml-stylesheet href="chrome://mochikit/content/tests/SimpleTest/test.css" type="text/css"?> + +<!-- + query syntax - multiple rules first condition all +--> + +<window title="XUL Template Tests" width="500" height="600" + onload="test_template();" + xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"> + <script type="application/javascript" + src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script> + + <body xmlns="http://www.w3.org/1999/xhtml" style="height: 300px; overflow: auto;"/> + + <data id="output"> + <checkbox id="http://www.some-fictitious-zoo.com/mammals/lion" label="Lion"/> + <checkbox id="http://www.some-fictitious-zoo.com/mammals/hippopotamus" label="HIPPOPOTAMUS"/> + <checkbox id="http://www.some-fictitious-zoo.com/mammals/africanelephant" label="African Elephant"/> + <checkbox id="http://www.some-fictitious-zoo.com/mammals/llama" label="LLAMA"/> + <checkbox id="http://www.some-fictitious-zoo.com/mammals/polarbear" label="Polar Bear"/> + <checkbox id="http://www.some-fictitious-zoo.com/mammals/aardvark" label="aardvark"/> + <checkbox id="http://www.some-fictitious-zoo.com/mammals/ninebandedarmadillo" label="Nine-banded Armadillo"/> + <checkbox id="http://www.some-fictitious-zoo.com/mammals/gorilla" label="Gorilla"/> + </data> + +<script src="templates_shared.js"/> + +<script> +<![CDATA[ +SimpleTest.waitForExplicitFinish(); + +var testid ="query syntax - multiple rules first condition all"; +var queryType = "rdf"; +var isTreeBuilder = false; +var needsOpen = false; +var notWorkingYet = false; +var notWorkingYetDynamic = false; +var expectedOutput = document.getElementById("output"); + +var changes = []; +]]> +</script> + +<vbox xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul" id="root" datasources="rdf:null" ref="http://www.some-fictitious-zoo.com/mammals"> +<template id="template"> +<query> +<content uri="?uri"/> +<member container="?uri" child="?animal"/> +<triple subject="?animal" predicate="http://www.some-fictitious-zoo.com/rdf#name" object="?name"/> +<triple subject="?animal" predicate="http://www.some-fictitious-zoo.com/rdf#specimens" object="?specimens"/> +</query> +<rule> +<where subject="?animal" rel="contains" value="zoo"/> +<action> +<checkbox uri="?animal" label="?name"/> +</action> +</rule> +<rule id="rule2"> +<conditions> +<where subject="?name" rel="contains" value="an"/> +</conditions> +<action> +<label uri="?animal" value="?name"/> +</action> +</rule> +</template> +</vbox> + +</window> diff --git a/dom/xul/templates/tests/chrome/test_tmpl_querysyntaxmultiplerulestwoconditions.xul b/dom/xul/templates/tests/chrome/test_tmpl_querysyntaxmultiplerulestwoconditions.xul new file mode 100644 index 000000000..68060c6b4 --- /dev/null +++ b/dom/xul/templates/tests/chrome/test_tmpl_querysyntaxmultiplerulestwoconditions.xul @@ -0,0 +1,113 @@ +<?xml version="1.0"?> +<?xml-stylesheet href="chrome://global/skin" type="text/css"?> +<?xml-stylesheet href="chrome://mochikit/content/tests/SimpleTest/test.css" type="text/css"?> + +<!-- + query syntax - multiple rules two conditions +--> + +<window title="XUL Template Tests" width="500" height="600" + onload="test_template();" + xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"> + <script type="application/javascript" + src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script> + + <body xmlns="http://www.w3.org/1999/xhtml" style="height: 300px; overflow: auto;"/> + + <data id="output"> + <checkbox step="2" id="http://www.some-fictitious-zoo.com/mammals/lion" label="Lion"/> + <checkbox id="http://www.some-fictitious-zoo.com/mammals/africanelephant" label="African Elephant"/> + <label step="5" id="http://www.some-fictitious-zoo.com/mammals/chimpanzee" value="Chimpanzee"/> + <checkbox step="-1" id="http://www.some-fictitious-zoo.com/mammals/polarbear" label="Polar Bear"/> + <label step="-3" id="http://www.some-fictitious-zoo.com/mammals/ninebandedarmadillo" value="Nine-banded Armadillo"/> + <checkbox id="http://www.some-fictitious-zoo.com/mammals/gorilla" label="Gorilla"/> + </data> + +<script src="templates_shared.js"/> + +<script> +<![CDATA[ +SimpleTest.waitForExplicitFinish(); + +var testid ="query syntax - multiple rules two conditions"; +var queryType = "rdf"; +var isTreeBuilder = false; +var needsOpen = false; +var notWorkingYet = false; +var notWorkingYetDynamic = false; +var expectedOutput = document.getElementById("output"); + +var changes = [ + // step 1 + function(targetds, root) { + var subject = RDF.GetResource(ZOO_NS + 'mammals/polarbear'); + var predicate = RDF.GetResource(ZOO_NS + 'rdf#specimens'); + var oldval = targetds.GetTarget(subject, predicate, true); + targetds.Change(RDF.GetResource(ZOO_NS + 'mammals/polarbear'), + RDF.GetResource(ZOO_NS + 'rdf#specimens'), + oldval, RDF.GetLiteral('5')); + }, + // step 2 + function(targetds, root) { + var subject = RDF.GetResource(ZOO_NS + 'mammals/lion'); + var predicate = RDF.GetResource(ZOO_NS + 'rdf#specimens'); + var oldval = targetds.GetTarget(subject, predicate, true); + targetds.Change(RDF.GetResource(ZOO_NS + 'mammals/lion'), + RDF.GetResource(ZOO_NS + 'rdf#specimens'), + oldval, RDF.GetLiteral('9')); + }, + // step 3 + function(targetds, root) { + var container = ContainerUtils.MakeSeq(targetds, + RDF.GetResource(ZOO_NS + 'mammals')); + var removednode = container.RemoveElementAt('7', true); + targetds.Unassert(removednode, RDF.GetResource(ZOO_NS + 'rdf#name'), + RDF.GetLiteral('Nine-banded Armadillo'), true); + }, + // step 4 + function(targetds, root) { + var newnode = RDF.GetResource(ZOO_NS + 'mammals/chimpanzee'); + targetds.Assert(newnode, RDF.GetResource(ZOO_NS + 'rdf#name'), + RDF.GetLiteral('Chimpanzee'), true); + var container = ContainerUtils.MakeSeq(targetds, + RDF.GetResource(ZOO_NS + 'mammals')); + container.InsertElementAt(newnode, '4', true); + }, + // step 5 + function(targetds, root) { + targetds.Assert(RDF.GetResource(ZOO_NS + 'mammals/chimpanzee'), + RDF.GetResource(ZOO_NS + 'rdf#specimens'), + RDF.GetLiteral('3'), true); + } +]; +]]> +</script> + +<vbox xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul" id="root" datasources="rdf:null" ref="http://www.some-fictitious-zoo.com/mammals"> +<template id="template"> +<query> +<content uri="?uri"/> +<member container="?uri" child="?animal"/> +<triple subject="?animal" predicate="http://www.some-fictitious-zoo.com/rdf#name" object="?name"/> +<triple subject="?animal" predicate="http://www.some-fictitious-zoo.com/rdf#specimens" object="?specimens"/> +</query> +<rule> +<conditions id="conditions"> +<where subject="?specimens" rel="greater" value="6"/> +</conditions> +<action> +<checkbox uri="?animal" label="?name"/> +</action> +</rule> +<rule id="rule2"> +<conditions> +<where subject="?name" rel="contains" value="an"/> +</conditions> +<action> +<label uri="?animal" value="?name"/> +</action> +</rule> +</template> +</vbox> + +</window> diff --git a/dom/xul/templates/tests/chrome/test_tmpl_querytripleandmembermerge.xul b/dom/xul/templates/tests/chrome/test_tmpl_querytripleandmembermerge.xul new file mode 100644 index 000000000..7abb67e1c --- /dev/null +++ b/dom/xul/templates/tests/chrome/test_tmpl_querytripleandmembermerge.xul @@ -0,0 +1,55 @@ +<?xml version="1.0"?> +<?xml-stylesheet href="chrome://global/skin" type="text/css"?> +<?xml-stylesheet href="chrome://mochikit/content/tests/SimpleTest/test.css" type="text/css"?> + +<!-- + query - triple and member merge +--> + +<window title="XUL Template Tests" width="500" height="600" + onload="test_template();" + xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"> + <script type="application/javascript" + src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script> + + <body xmlns="http://www.w3.org/1999/xhtml" style="height: 300px; overflow: auto;"/> + + <data id="output" unordered="true"> + <label id="http://www.some-fictitious-zoo.com/reptiles/chameleon" value="Chameleon"/> + <label id="http://www.some-fictitious-zoo.com/arachnids/tarantula" value="Tarantula"/> + </data> + +<script src="templates_shared.js"/> + +<script> +<![CDATA[ +SimpleTest.waitForExplicitFinish(); + +var testid ="query - triple and member merge"; +var queryType = "rdf"; +var isTreeBuilder = false; +var needsOpen = false; +var notWorkingYet = false; +var notWorkingYetDynamic = false; +var expectedOutput = document.getElementById("output"); + +var changes = []; +]]> +</script> + +<vbox xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul" id="root" datasources="rdf:null" ref="http://www.some-fictitious-zoo.com/humans/robert"> +<template id="template"> +<query id="query"> +<content uri="?uri"/> +<triple subject="?uri" predicate="http://www.some-fictitious-zoo.com/rdf#favoriteAnimal" object="?child"/> +<triple subject="?uri" predicate="http://www.some-fictitious-zoo.com/rdf#pets" object="?pets"/> +<member container="?pets" child="?child"/> +<triple subject="?child" predicate="http://www.some-fictitious-zoo.com/rdf#name" object="?name"/> +</query> +,<action> +<label uri="?child" value="?name"/> +</action> +</template> +</vbox> + +</window> diff --git a/dom/xul/templates/tests/chrome/test_tmpl_querytripleobjecttosubject.xul b/dom/xul/templates/tests/chrome/test_tmpl_querytripleobjecttosubject.xul new file mode 100644 index 000000000..3998f1796 --- /dev/null +++ b/dom/xul/templates/tests/chrome/test_tmpl_querytripleobjecttosubject.xul @@ -0,0 +1,67 @@ +<?xml version="1.0"?> +<?xml-stylesheet href="chrome://global/skin" type="text/css"?> +<?xml-stylesheet href="chrome://mochikit/content/tests/SimpleTest/test.css" type="text/css"?> + +<!-- + query - triple object to subject +--> + +<window title="XUL Template Tests" width="500" height="600" + onload="test_template();" + xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"> + <script type="application/javascript" + src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script> + + <body xmlns="http://www.w3.org/1999/xhtml" style="height: 300px; overflow: auto;"/> + + <data id="output"> + <label step="-1" id="http://www.some-fictitious-zoo.com/humans/robert" value="Robert"/> + <label step="2" id="http://www.some-fictitious-zoo.com/humans/robert" value="Robert"/> + <label id="http://www.some-fictitious-zoo.com/humans/sarah" value="Sarah"/> + </data> + +<script src="templates_shared.js"/> + +<script> +<![CDATA[ +SimpleTest.waitForExplicitFinish(); + +var testid ="query - triple object to subject"; +var queryType = "rdf"; +var isTreeBuilder = false; +var needsOpen = false; +var notWorkingYet = false; +var notWorkingYetDynamic = true; +var expectedOutput = document.getElementById("output"); + +var changes = [ + // step 1 + function(targetds, root) { + targetds.Unassert(RDF.GetResource(ZOO_NS + 'humans/robert'), + RDF.GetResource(ZOO_NS + 'rdf#favoriteAnimal'), + RDF.GetResource(ZOO_NS + 'arachnids/tarantula'), true); + }, + // step 2 + function(targetds, root) { + targetds.Assert(RDF.GetResource(ZOO_NS + 'humans/robert'), + RDF.GetResource(ZOO_NS + 'rdf#favoriteAnimal'), + RDF.GetResource(ZOO_NS + 'mammals/lion'), true); + } +]; +]]> +</script> + +<vbox xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul" id="root" datasources="rdf:null" ref="http://www.some-fictitious-zoo.com/arachnids/tarantula"> +<template id="template"> +<query> +<content uri="?uri"/> +<triple subject="?human" predicate="http://www.some-fictitious-zoo.com/rdf#favoriteAnimal" object="?uri"/> +<triple subject="?human" predicate="http://www.some-fictitious-zoo.com/rdf#name" object="?humanname"/> +</query> +<action> +<label uri="?human" value="?humanname"/> +</action> +</template> +</vbox> + +</window> diff --git a/dom/xul/templates/tests/chrome/test_tmpl_querytwomembers.xul b/dom/xul/templates/tests/chrome/test_tmpl_querytwomembers.xul new file mode 100644 index 000000000..df487a26f --- /dev/null +++ b/dom/xul/templates/tests/chrome/test_tmpl_querytwomembers.xul @@ -0,0 +1,107 @@ +<?xml version="1.0"?> +<?xml-stylesheet href="chrome://global/skin" type="text/css"?> +<?xml-stylesheet href="chrome://mochikit/content/tests/SimpleTest/test.css" type="text/css"?> + +<!-- + query - two members +--> + +<window title="XUL Template Tests" width="500" height="600" + onload="test_template();" + xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"> + <script type="application/javascript" + src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script> + + <body xmlns="http://www.w3.org/1999/xhtml" style="height: 300px; overflow: auto;"/> + + <data id="output" unordered="true"> + <label id="http://www.some-fictitious-zoo.com/arachnids/tarantula" value="Tarantula"/> + <label step="3" id="http://www.some-fictitious-zoo.com/birds/wren" value="Wren"/> + <label id="http://www.some-fictitious-zoo.com/birds/emu" value="Emu"/> + <label step="-4" id="http://www.some-fictitious-zoo.com/birds/barnowl" value="Barn Owl"/> + <label id="http://www.some-fictitious-zoo.com/birds/raven" value="Raven"/> + <label step="2" id="http://www.some-fictitious-zoo.com/birds/archaeopteryx" value="Archaeopteryx"/> + <label step="1" id="http://www.some-fictitious-zoo.com/birds/emperorpenguin" value="Emperor Penguin"/> + <label id="http://www.some-fictitious-zoo.com/fish/cod" value="Cod"/> + <label id="http://www.some-fictitious-zoo.com/fish/swordfish" value="Swordfish"/> + <label id="http://www.some-fictitious-zoo.com/mammals/lion" value="Lion"/> + <label id="http://www.some-fictitious-zoo.com/mammals/hippopotamus" value="HIPPOPOTAMUS"/> + <label id="http://www.some-fictitious-zoo.com/mammals/africanelephant" value="African Elephant"/> + <label id="http://www.some-fictitious-zoo.com/mammals/llama" value="LLAMA"/> + <label id="http://www.some-fictitious-zoo.com/mammals/polarbear" value="Polar Bear"/> + <label id="http://www.some-fictitious-zoo.com/mammals/aardvark" value="aardvark"/> + <label id="http://www.some-fictitious-zoo.com/mammals/ninebandedarmadillo" value="Nine-banded Armadillo"/> + <label id="http://www.some-fictitious-zoo.com/mammals/gorilla" value="Gorilla"/> + <label id="http://www.some-fictitious-zoo.com/reptiles/anaconda" value="Anaconda"/> + <label id="http://www.some-fictitious-zoo.com/reptiles/chameleon" value="Chameleon"/> + </data> + +<script src="templates_shared.js"/> + +<script> +<![CDATA[ +SimpleTest.waitForExplicitFinish(); + +var testid ="query - two members"; +var queryType = "rdf"; +var isTreeBuilder = false; +var needsOpen = false; +var notWorkingYet = false; +var notWorkingYetDynamic = false; +var expectedOutput = document.getElementById("output"); + +var changes = [ + // step 1 + function(targetds, root) { + var newnode = RDF.GetResource(ZOO_NS + 'birds/emperorpenguin'); + targetds.Assert(newnode, RDF.GetResource(ZOO_NS + 'rdf#name'), + RDF.GetLiteral('Emperor Penguin'), true); + var container = ContainerUtils.MakeSeq(targetds, + RDF.GetResource(ZOO_NS + 'birds')); + container.AppendElement(newnode); + }, + // step 2 + function(targetds, root) { + var newnode = RDF.GetResource(ZOO_NS + 'birds/archaeopteryx'); + targetds.Assert(newnode, RDF.GetResource(ZOO_NS + 'rdf#name'), + RDF.GetLiteral('Archaeopteryx'), true); + var container = ContainerUtils.MakeSeq(targetds, + RDF.GetResource(ZOO_NS + 'birds')); + container.InsertElementAt(newnode, '4', true); + }, + // step 3 + function(targetds, root) { + var newnode = RDF.GetResource(ZOO_NS + 'birds/wren'); + targetds.Assert(newnode, RDF.GetResource(ZOO_NS + 'rdf#name'), + RDF.GetLiteral('Wren'), true); + var container = ContainerUtils.MakeSeq(targetds, + RDF.GetResource(ZOO_NS + 'birds')); + container.InsertElementAt(newnode, '1', true); + }, + // step 4 + function(targetds, root) { + var container = ContainerUtils.MakeSeq(targetds, + RDF.GetResource(ZOO_NS + 'birds')); + var removednode = container.RemoveElementAt('3', true); + targetds.Unassert(removednode, RDF.GetResource(ZOO_NS + 'rdf#name'), + RDF.GetLiteral('Barn Owl'), true); + } +]; +]]> +</script> + +<vbox xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul" id="root" datasources="rdf:null" ref="http://www.some-fictitious-zoo.com/all-animals"> +<template id="template"> +<query id="query"> +<content uri="?uri"/> +<member container="?uri" child="?childone"/> +<member container="?childone" child="?child"/> +<triple subject="?child" predicate="http://www.some-fictitious-zoo.com/rdf#name" object="?name"/> +</query> +,<action> +<label uri="?child" value="?name"/> +</action> +</template> +</vbox> + +</window> diff --git a/dom/xul/templates/tests/chrome/test_tmpl_querytwomembersfiltered.xul b/dom/xul/templates/tests/chrome/test_tmpl_querytwomembersfiltered.xul new file mode 100644 index 000000000..fdd1efb20 --- /dev/null +++ b/dom/xul/templates/tests/chrome/test_tmpl_querytwomembersfiltered.xul @@ -0,0 +1,54 @@ +<?xml version="1.0"?> +<?xml-stylesheet href="chrome://global/skin" type="text/css"?> +<?xml-stylesheet href="chrome://mochikit/content/tests/SimpleTest/test.css" type="text/css"?> + +<!-- + query - two members filtered +--> + +<window title="XUL Template Tests" width="500" height="600" + onload="test_template();" + xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"> + <script type="application/javascript" + src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script> + + <body xmlns="http://www.w3.org/1999/xhtml" style="height: 300px; overflow: auto;"/> + + <data id="output"> + <label id="http://www.some-fictitious-zoo.com/mammals/llama" value="Mammals"/> + </data> + +<script src="templates_shared.js"/> + +<script> +<![CDATA[ +SimpleTest.waitForExplicitFinish(); + +var testid ="query - two members filtered"; +var queryType = "rdf"; +var isTreeBuilder = false; +var needsOpen = false; +var notWorkingYet = false; +var notWorkingYetDynamic = false; +var expectedOutput = document.getElementById("output"); + +var changes = []; +]]> +</script> + +<vbox xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul" id="root" datasources="rdf:null" ref="http://www.some-fictitious-zoo.com/all-animals"> +<template id="template"> +<query id="query"> +<content uri="?uri"/> +<member container="?uri" child="?childone"/> +<triple subject="?childone" predicate="http://www.some-fictitious-zoo.com/rdf#name" object="?name"/> +<member container="?childone" child="?child"/> +<triple subject="?child" predicate="http://www.some-fictitious-zoo.com/rdf#name" object="LLAMA"/> +</query> +,<action> +<label uri="?child" value="?name"/> +</action> +</template> +</vbox> + +</window> diff --git a/dom/xul/templates/tests/chrome/test_tmpl_querytwotriples.xul b/dom/xul/templates/tests/chrome/test_tmpl_querytwotriples.xul new file mode 100644 index 000000000..83887358f --- /dev/null +++ b/dom/xul/templates/tests/chrome/test_tmpl_querytwotriples.xul @@ -0,0 +1,55 @@ +<?xml version="1.0"?> +<?xml-stylesheet href="chrome://global/skin" type="text/css"?> +<?xml-stylesheet href="chrome://mochikit/content/tests/SimpleTest/test.css" type="text/css"?> + +<!-- + query - two triples +--> + +<window title="XUL Template Tests" width="500" height="600" + onload="test_template();" + xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"> + <script type="application/javascript" + src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script> + + <body xmlns="http://www.w3.org/1999/xhtml" style="height: 300px; overflow: auto;"/> + + <data id="output" unordered="true"> + <label id="http://www.some-fictitious-zoo.com/arachnids/tarantula" value="Tarantula"/> + <label id="http://www.some-fictitious-zoo.com/reptiles/anaconda" value="Anaconda"/> + <label id="http://www.some-fictitious-zoo.com/reptiles/chameleon" value="Chameleon"/> + <label id="http://www.some-fictitious-zoo.com/mammals/africanelephant" value="African Elephant"/> + </data> + +<script src="templates_shared.js"/> + +<script> +<![CDATA[ +SimpleTest.waitForExplicitFinish(); + +var testid ="query - two triples"; +var queryType = "rdf"; +var isTreeBuilder = false; +var needsOpen = false; +var notWorkingYet = false; +var notWorkingYetDynamic = false; +var expectedOutput = document.getElementById("output"); + +var changes = []; +]]> +</script> + +<vbox xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul" id="root" datasources="rdf:null" ref="http://www.some-fictitious-zoo.com/humans/robert"> +<template id="template"> +<query id="query"> +<content uri="?uri"/> +<triple subject="?uri" predicate="http://www.some-fictitious-zoo.com/rdf#favoriteAnimal" object="?child"/> +<triple subject="?child" predicate="http://www.some-fictitious-zoo.com/rdf#name" object="?name"/> +</query> +,<action> +<label uri="?child" value="?name"/> +</action> +</template> +</vbox> + +</window> diff --git a/dom/xul/templates/tests/chrome/test_tmpl_queryupwardsmember.xul b/dom/xul/templates/tests/chrome/test_tmpl_queryupwardsmember.xul new file mode 100644 index 000000000..5d3658535 --- /dev/null +++ b/dom/xul/templates/tests/chrome/test_tmpl_queryupwardsmember.xul @@ -0,0 +1,54 @@ +<?xml version="1.0"?> +<?xml-stylesheet href="chrome://global/skin" type="text/css"?> +<?xml-stylesheet href="chrome://mochikit/content/tests/SimpleTest/test.css" type="text/css"?> + +<!-- + query - upwards member +--> + +<window title="XUL Template Tests" width="500" height="600" + onload="test_template();" + xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"> + <script type="application/javascript" + src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script> + + <body xmlns="http://www.w3.org/1999/xhtml" style="height: 300px; overflow: auto;"/> + + <data id="output" unordered="true"> + <label id="http://www.some-fictitious-zoo.com/marked" container="true" empty="false" value="Marked"/> + <label id="http://www.some-fictitious-zoo.com/birds" container="true" empty="false" value="Birds"/> + <label id="http://www.some-fictitious-zoo.com/sarahs-pets" container="true" empty="false" value="Sarah's Pets"/> + </data> + +<script src="templates_shared.js"/> + +<script> +<![CDATA[ +SimpleTest.waitForExplicitFinish(); + +var testid ="query - upwards member"; +var queryType = "rdf"; +var isTreeBuilder = false; +var needsOpen = false; +var notWorkingYet = false; +var notWorkingYetDynamic = false; +var expectedOutput = document.getElementById("output"); + +var changes = []; +]]> +</script> + +<vbox xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul" id="root" datasources="rdf:null" ref="http://www.some-fictitious-zoo.com/birds/emu" flags="dont-recurse"> +<template id="template"> +<query id="query"> +<content uri="?uri"/> +<member container="?child" child="?uri"/> +<triple subject="?child" predicate="http://www.some-fictitious-zoo.com/rdf#name" object="?name"/> +</query> +,<action> +<label uri="?child" value="?name"/> +</action> +</template> +</vbox> + +</window> diff --git a/dom/xul/templates/tests/chrome/test_tmpl_queryupwardsmembertripleandfilteringtriple.xul b/dom/xul/templates/tests/chrome/test_tmpl_queryupwardsmembertripleandfilteringtriple.xul new file mode 100644 index 000000000..1cfb689b0 --- /dev/null +++ b/dom/xul/templates/tests/chrome/test_tmpl_queryupwardsmembertripleandfilteringtriple.xul @@ -0,0 +1,55 @@ +<?xml version="1.0"?> +<?xml-stylesheet href="chrome://global/skin" type="text/css"?> +<?xml-stylesheet href="chrome://mochikit/content/tests/SimpleTest/test.css" type="text/css"?> + +<!-- + query - upwards member, triple and filtering triple +--> + +<window title="XUL Template Tests" width="500" height="600" + onload="test_template();" + xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"> + <script type="application/javascript" + src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script> + + <body xmlns="http://www.w3.org/1999/xhtml" style="height: 300px; overflow: auto;"/> + + <data id="output" unordered="true"> + <label id="http://www.some-fictitious-zoo.com/reptiles/anaconda" value="Anaconda"/> + <label id="http://www.some-fictitious-zoo.com/reptiles/chameleon" value="Chameleon"/> + </data> + +<script src="templates_shared.js"/> + +<script> +<![CDATA[ +SimpleTest.waitForExplicitFinish(); + +var testid ="query - upwards member, triple and filtering triple"; +var queryType = "rdf"; +var isTreeBuilder = false; +var needsOpen = false; +var notWorkingYet = false; +var notWorkingYetDynamic = false; +var expectedOutput = document.getElementById("output"); + +var changes = []; +]]> +</script> + +<vbox xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul" id="root" datasources="rdf:null" ref="http://www.some-fictitious-zoo.com/humans/robert"> +<template id="template"> +<query id="query"> +<content uri="?uri"/> +<triple subject="?uri" predicate="http://www.some-fictitious-zoo.com/rdf#favoriteAnimal" object="?child"/> +<member container="?reptiles" child="?child"/> +<triple subject="?child" predicate="http://www.some-fictitious-zoo.com/rdf#name" object="?name"/> +<triple subject="?reptiles" predicate="http://www.some-fictitious-zoo.com/rdf#name" object="Reptiles"/> +</query> +,<action> +<label uri="?child" value="?name"/> +</action> +</template> +</vbox> + +</window> diff --git a/dom/xul/templates/tests/chrome/test_tmpl_querywithemptyconditions.xul b/dom/xul/templates/tests/chrome/test_tmpl_querywithemptyconditions.xul new file mode 100644 index 000000000..265a5bb14 --- /dev/null +++ b/dom/xul/templates/tests/chrome/test_tmpl_querywithemptyconditions.xul @@ -0,0 +1,117 @@ +<?xml version="1.0"?> +<?xml-stylesheet href="chrome://global/skin" type="text/css"?> +<?xml-stylesheet href="chrome://mochikit/content/tests/SimpleTest/test.css" type="text/css"?> + +<!-- + query with empty conditions +--> + +<window title="XUL Template Tests" width="500" height="600" + onload="test_template();" + xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"> + <script type="application/javascript" + src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script> + + <body xmlns="http://www.w3.org/1999/xhtml" style="height: 300px; overflow: auto;"/> + + <data id="output"> + <label step="3" id="http://www.some-fictitious-zoo.com/mammals/zebra" value="Zebra"/> + <label id="http://www.some-fictitious-zoo.com/mammals/lion" value="Lion"/> + <label id="http://www.some-fictitious-zoo.com/mammals/hippopotamus" value="HIPPOPOTAMUS"/> + <label step="-4" id="http://www.some-fictitious-zoo.com/mammals/africanelephant" value="African Elephant"/> + <label step="2" id="http://www.some-fictitious-zoo.com/mammals/koala" value="Koala"/> + <label id="http://www.some-fictitious-zoo.com/mammals/llama" value="LLAMA"/> + <label id="http://www.some-fictitious-zoo.com/mammals/polarbear" value="Polar Bear"/> + <label id="http://www.some-fictitious-zoo.com/mammals/aardvark" value="aardvark"/> + <label id="http://www.some-fictitious-zoo.com/mammals/ninebandedarmadillo" value="Nine-banded Armadillo"/> + <label id="http://www.some-fictitious-zoo.com/mammals/gorilla" value="Gorilla"/> + <label step="1" id="http://www.some-fictitious-zoo.com/mammals/arctichare" value="Arctic Hare"/> + <label step="5" id="http://www.some-fictitious-zoo.com/mammals/africanelephant" value="African Elephant"/> + </data> + +<script src="templates_shared.js"/> + +<script> +<![CDATA[ +SimpleTest.waitForExplicitFinish(); + +var testid ="query with empty conditions"; +var queryType = "rdf"; +var isTreeBuilder = false; +var needsOpen = false; +var notWorkingYet = false; +var notWorkingYetDynamic = false; +var expectedOutput = document.getElementById("output"); + +var changes = [ + // step 1 + function(targetds, root) { + var newnode = RDF.GetResource(ZOO_NS + 'mammals/arctichare'); + targetds.Assert(newnode, RDF.GetResource(ZOO_NS + 'rdf#name'), + RDF.GetLiteral('Arctic Hare'), true); + var container = ContainerUtils.MakeSeq(targetds, + RDF.GetResource(ZOO_NS + 'mammals')); + container.AppendElement(newnode); + }, + // step 2 + function(targetds, root) { + var newnode = RDF.GetResource(ZOO_NS + 'mammals/koala'); + targetds.Assert(newnode, RDF.GetResource(ZOO_NS + 'rdf#name'), + RDF.GetLiteral('Koala'), true); + var container = ContainerUtils.MakeSeq(targetds, + RDF.GetResource(ZOO_NS + 'mammals')); + container.InsertElementAt(newnode, '4', true); + }, + // step 3 + function(targetds, root) { + var newnode = RDF.GetResource(ZOO_NS + 'mammals/zebra'); + targetds.Assert(newnode, RDF.GetResource(ZOO_NS + 'rdf#name'), + RDF.GetLiteral('Zebra'), true); + var container = ContainerUtils.MakeSeq(targetds, + RDF.GetResource(ZOO_NS + 'mammals')); + container.InsertElementAt(newnode, '1', true); + }, + // step 4 + function(targetds, root) { + var container = ContainerUtils.MakeSeq(targetds, + RDF.GetResource(ZOO_NS + 'mammals')); + var removednode = container.RemoveElementAt('4', true); + targetds.Unassert(removednode, RDF.GetResource(ZOO_NS + 'rdf#name'), + RDF.GetLiteral('African Elephant'), true); + }, + // step 5 + function(targetds, root) { + var newnode = RDF.GetResource(ZOO_NS + 'mammals/africanelephant'); + targetds.Assert(newnode, RDF.GetResource(ZOO_NS + 'rdf#name'), + RDF.GetLiteral('African Elephant'), true); + var container = ContainerUtils.MakeSeq(targetds, + RDF.GetResource(ZOO_NS + 'mammals')); + container.AppendElement(newnode); + }, + // step 6 + function(targetds, root) { + targetds.Assert(RDF.GetResource(ZOO_NS + 'mammals/koala'), + RDF.GetResource(ZOO_NS + 'rdf#specimensAsString'), + RDF.GetLiteral('8'), true); + } +]; +]]> +</script> + +<vbox xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul" id="root" datasources="rdf:null" ref="http://www.some-fictitious-zoo.com/mammals"> +<template id="template"> +<query id="query"> +<content uri="?uri"/> +<member container="?uri" child="?animal"/> +<triple subject="?animal" predicate="http://www.some-fictitious-zoo.com/rdf#name" object="?name"/> +</query> +<rule> +<conditions id="conditions"/> +<action id="action"> +<label uri="?animal" value="?name"/> +</action> +</rule> +</template> +</vbox> + +</window> diff --git a/dom/xul/templates/tests/chrome/test_tmpl_referenceasmember.xul b/dom/xul/templates/tests/chrome/test_tmpl_referenceasmember.xul new file mode 100644 index 000000000..bf67ebf9d --- /dev/null +++ b/dom/xul/templates/tests/chrome/test_tmpl_referenceasmember.xul @@ -0,0 +1,65 @@ +<?xml version="1.0"?> +<?xml-stylesheet href="chrome://global/skin" type="text/css"?> +<?xml-stylesheet href="chrome://mochikit/content/tests/SimpleTest/test.css" type="text/css"?> + +<!-- + reference as member +--> + +<window title="XUL Template Tests" width="500" height="600" + onload="test_template();" + xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"> + <script type="application/javascript" + src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script> + + <body xmlns="http://www.w3.org/1999/xhtml" style="height: 300px; overflow: auto;"/> + + <data id="output"> + <label step="-1" id="http://www.some-fictitious-zoo.com/arachnids" container="true" empty="false" value="Tarantula"/> + <label step="1" id="http://www.some-fictitious-zoo.com/arachnids" container="true" empty="false" value="Hairy Spider"/> + </data> + +<script src="templates_shared.js"/> + +<script> +<![CDATA[ +SimpleTest.waitForExplicitFinish(); + +var testid ="reference as member"; +var queryType = "rdf"; +var isTreeBuilder = false; +var needsOpen = false; +var notWorkingYet = false; +var notWorkingYetDynamic = false; +var expectedOutput = document.getElementById("output"); + +var changes = [ + // step 1 + function(targetds, root) { + var subject = RDF.GetResource(ZOO_NS + 'arachnids/tarantula'); + var predicate = RDF.GetResource(ZOO_NS + 'rdf#name'); + var oldval = targetds.GetTarget(subject, predicate, true); + targetds.Change(RDF.GetResource(ZOO_NS + 'arachnids/tarantula'), + RDF.GetResource(ZOO_NS + 'rdf#name'), + oldval, RDF.GetLiteral('Hairy Spider')); + } +]; +]]> +</script> + +<vbox xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul" id="root" datasources="rdf:null" ref="http://www.some-fictitious-zoo.com/arachnids"> +<template id="template"> +<rule id="rule"> +<conditions id="conditions"> +<content uri="?start"/> +<member container="?start" child="?animal"/> +<triple subject="?animal" predicate="http://www.some-fictitious-zoo.com/rdf#name" object="?name"/> +</conditions> +<action id="action"> +<label uri="?start" value="?name"/> +</action> +</rule> +</template> +</vbox> + +</window> diff --git a/dom/xul/templates/tests/chrome/test_tmpl_regenerate.xul b/dom/xul/templates/tests/chrome/test_tmpl_regenerate.xul new file mode 100644 index 000000000..2c9aedc7b --- /dev/null +++ b/dom/xul/templates/tests/chrome/test_tmpl_regenerate.xul @@ -0,0 +1,49 @@ +<?xml version="1.0"?> +<?xml-stylesheet href="chrome://global/skin" type="text/css"?> +<?xml-stylesheet href="chrome://mochikit/content/tests/SimpleTest/test.css" type="text/css"?> + +<!-- + Regenerate template by removing and appending elements +--> + +<window title="XUL Template Tests" width="500" height="600" + onload="test_regenerate()" + xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"> + <script type="application/javascript" + src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script> + + <body xmlns="http://www.w3.org/1999/xhtml" style="height: 300px; overflow: auto;"/> + +<script> +<![CDATA[ +SimpleTest.waitForExplicitFinish(); + +function test_regenerate() +{ + var container = document.getElementById("container"); + var node = container.firstChild; + + if (node.childNodes.length != 2) { + setTimeout(test_regenerate, 50); + return; + } + + container.removeChild(node); + is(node.childNodes.length, 1, "childNodes after removeChild"); + container.appendChild(node); + is(node.childNodes.length, 2, "childNodes after appendChild"); + SimpleTest.finish(); +} + +]]> +</script> + +<vbox id="container"> +<vbox xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul" id="root" datasources="animals.rdf" ref="http://www.some-fictitious-zoo.com/birds"> +<template zoo:name="Barn Owl" xmlns:zoo="http://www.some-fictitious-zoo.com/rdf#"> +<label uri="rdf:*" value="rdf:http://www.some-fictitious-zoo.com/rdf#name"/> +</template> +</vbox> +</vbox> + +</window> diff --git a/dom/xul/templates/tests/chrome/test_tmpl_selfgenerationextendedsyntax.xul b/dom/xul/templates/tests/chrome/test_tmpl_selfgenerationextendedsyntax.xul new file mode 100644 index 000000000..712cd4a44 --- /dev/null +++ b/dom/xul/templates/tests/chrome/test_tmpl_selfgenerationextendedsyntax.xul @@ -0,0 +1,66 @@ +<?xml version="1.0"?> +<?xml-stylesheet href="chrome://global/skin" type="text/css"?> +<?xml-stylesheet href="chrome://mochikit/content/tests/SimpleTest/test.css" type="text/css"?> + +<!-- + self generation - extended syntax +--> + +<window title="XUL Template Tests" width="500" height="600" + onload="test_template();" + xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"> + <script type="application/javascript" + src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script> + + <body xmlns="http://www.w3.org/1999/xhtml" style="height: 300px; overflow: auto;"/> + + <data id="output"> + <label step="-1" id="http://www.some-fictitious-zoo.com/arachnids/tarantula" value="Tarantula"/> + <label step="1" id="http://www.some-fictitious-zoo.com/arachnids/tarantula" value="Hairy Spider"/> + </data> + +<script src="templates_shared.js"/> + +<script> +<![CDATA[ +SimpleTest.waitForExplicitFinish(); + +var testid ="self generation - extended syntax"; +var queryType = "rdf"; +var isTreeBuilder = false; +var needsOpen = false; +var notWorkingYet = false; +var notWorkingYetDynamic = false; +var expectedOutput = document.getElementById("output"); + +var changes = [ + // step 1 + function(targetds, root) { + var subject = RDF.GetResource(ZOO_NS + 'arachnids/tarantula'); + var predicate = RDF.GetResource(ZOO_NS + 'rdf#name'); + var oldval = targetds.GetTarget(subject, predicate, true); + targetds.Change(RDF.GetResource(ZOO_NS + 'arachnids/tarantula'), + RDF.GetResource(ZOO_NS + 'rdf#name'), + oldval, RDF.GetLiteral('Hairy Spider')); + } +]; +]]> +</script> + +<vbox xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul" id="root" datasources="rdf:null" ref="http://www.some-fictitious-zoo.com/arachnids/tarantula"> +<template id="template"> +<query> +<content uri="?uri"/> +</query> +<rule> +<bindings> +<binding subject="?uri" predicate="http://www.some-fictitious-zoo.com/rdf#name" object="?name"/> +</bindings> +<action> +<label uri="?uri" value="?name"/> +</action> +</rule> +</template> +</vbox> + +</window> diff --git a/dom/xul/templates/tests/chrome/test_tmpl_selfgenerationsimplesyntax.xul b/dom/xul/templates/tests/chrome/test_tmpl_selfgenerationsimplesyntax.xul new file mode 100644 index 000000000..e644d16ac --- /dev/null +++ b/dom/xul/templates/tests/chrome/test_tmpl_selfgenerationsimplesyntax.xul @@ -0,0 +1,53 @@ +<?xml version="1.0"?> +<?xml-stylesheet href="chrome://global/skin" type="text/css"?> +<?xml-stylesheet href="chrome://mochikit/content/tests/SimpleTest/test.css" type="text/css"?> + +<!-- + self generation - simple syntax +--> + +<window title="XUL Template Tests" width="500" height="600" + onload="test_template();" + xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"> + <script type="application/javascript" + src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script> + + <body xmlns="http://www.w3.org/1999/xhtml" style="height: 300px; overflow: auto;"/> + + <data id="output"/> + +<script src="templates_shared.js"/> + +<script> +<![CDATA[ +SimpleTest.waitForExplicitFinish(); + +var testid ="self generation - simple syntax"; +var queryType = "rdf"; +var isTreeBuilder = false; +var needsOpen = false; +var notWorkingYet = false; +var notWorkingYetDynamic = false; +var expectedOutput = document.getElementById("output"); + +var changes = [ + // step 1 + function(targetds, root) { + var subject = RDF.GetResource(ZOO_NS + 'arachnids/tarantula'); + var predicate = RDF.GetResource(ZOO_NS + 'rdf#name'); + var oldval = targetds.GetTarget(subject, predicate, true); + targetds.Change(RDF.GetResource(ZOO_NS + 'arachnids/tarantula'), + RDF.GetResource(ZOO_NS + 'rdf#name'), + oldval, RDF.GetLiteral('Hairy Spider')); + } +]; +]]> +</script> + +<vbox xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul" id="root" datasources="rdf:null" ref="http://www.some-fictitious-zoo.com/arachnids/tarantula"> +<template id="template"> +<button uri="?" label="rdf:http://www.some-fictitious-zoo.com/rdf#name"/> +</template> +</vbox> + +</window> diff --git a/dom/xul/templates/tests/chrome/test_tmpl_simplesyntaxenclosedinacontainer.xul b/dom/xul/templates/tests/chrome/test_tmpl_simplesyntaxenclosedinacontainer.xul new file mode 100644 index 000000000..18e8b72a9 --- /dev/null +++ b/dom/xul/templates/tests/chrome/test_tmpl_simplesyntaxenclosedinacontainer.xul @@ -0,0 +1,90 @@ +<?xml version="1.0"?> +<?xml-stylesheet href="chrome://global/skin" type="text/css"?> +<?xml-stylesheet href="chrome://mochikit/content/tests/SimpleTest/test.css" type="text/css"?> + +<!-- + simple syntax enclosed in a container +--> + +<window title="XUL Template Tests" width="500" height="600" + onload="test_template();" + xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"> + <script type="application/javascript" + src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script> + + <body xmlns="http://www.w3.org/1999/xhtml" style="height: 300px; overflow: auto;"/> + + <data id="output"> + <hbox> + <label step="3" id="http://www.some-fictitious-zoo.com/birds/wren" value="Wren"/> + <label id="http://www.some-fictitious-zoo.com/birds/emu" value="Emu"/> + <label step="-4" id="http://www.some-fictitious-zoo.com/birds/barnowl" value="Barn Owl"/> + <label id="http://www.some-fictitious-zoo.com/birds/raven" value="Raven"/> + <label step="2" id="http://www.some-fictitious-zoo.com/birds/archaeopteryx" value="Archaeopteryx"/> + <label step="1" id="http://www.some-fictitious-zoo.com/birds/emperorpenguin" value="Emperor Penguin"/> + </hbox> + </data> + +<script src="templates_shared.js"/> + +<script> +<![CDATA[ +SimpleTest.waitForExplicitFinish(); + +var testid ="simple syntax enclosed in a container"; +var queryType = "rdf"; +var isTreeBuilder = false; +var needsOpen = false; +var notWorkingYet = false; +var notWorkingYetDynamic = false; +var expectedOutput = document.getElementById("output"); + +var changes = [ + // step 1 + function(targetds, root) { + var newnode = RDF.GetResource(ZOO_NS + 'birds/emperorpenguin'); + targetds.Assert(newnode, RDF.GetResource(ZOO_NS + 'rdf#name'), + RDF.GetLiteral('Emperor Penguin'), true); + var container = ContainerUtils.MakeSeq(targetds, + RDF.GetResource(ZOO_NS + 'birds')); + container.AppendElement(newnode); + }, + // step 2 + function(targetds, root) { + var newnode = RDF.GetResource(ZOO_NS + 'birds/archaeopteryx'); + targetds.Assert(newnode, RDF.GetResource(ZOO_NS + 'rdf#name'), + RDF.GetLiteral('Archaeopteryx'), true); + var container = ContainerUtils.MakeSeq(targetds, + RDF.GetResource(ZOO_NS + 'birds')); + container.InsertElementAt(newnode, '4', true); + }, + // step 3 + function(targetds, root) { + var newnode = RDF.GetResource(ZOO_NS + 'birds/wren'); + targetds.Assert(newnode, RDF.GetResource(ZOO_NS + 'rdf#name'), + RDF.GetLiteral('Wren'), true); + var container = ContainerUtils.MakeSeq(targetds, + RDF.GetResource(ZOO_NS + 'birds')); + container.InsertElementAt(newnode, '1', true); + }, + // step 4 + function(targetds, root) { + var container = ContainerUtils.MakeSeq(targetds, + RDF.GetResource(ZOO_NS + 'birds')); + var removednode = container.RemoveElementAt('3', true); + targetds.Unassert(removednode, RDF.GetResource(ZOO_NS + 'rdf#name'), + RDF.GetLiteral('Barn Owl'), true); + } +]; +]]> +</script> + +<vbox xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul" id="root" datasources="rdf:null" ref="http://www.some-fictitious-zoo.com/birds"> +<template id="template"> +<hbox> +<label uri="rdf:*" value="rdf:http://www.some-fictitious-zoo.com/rdf#name"/> +</hbox> +</template> +</vbox> + +</window> diff --git a/dom/xul/templates/tests/chrome/test_tmpl_simplesyntaxenclosedinacontainerwitharule.xul b/dom/xul/templates/tests/chrome/test_tmpl_simplesyntaxenclosedinacontainerwitharule.xul new file mode 100644 index 000000000..5582e4845 --- /dev/null +++ b/dom/xul/templates/tests/chrome/test_tmpl_simplesyntaxenclosedinacontainerwitharule.xul @@ -0,0 +1,58 @@ +<?xml version="1.0"?> +<?xml-stylesheet href="chrome://global/skin" type="text/css"?> +<?xml-stylesheet href="chrome://mochikit/content/tests/SimpleTest/test.css" type="text/css"?> + +<!-- + simple syntax enclosed in a container with a rule +--> + +<window title="XUL Template Tests" width="500" height="600" + onload="test_template();" + xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"> + <script type="application/javascript" + src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script> + + <body xmlns="http://www.w3.org/1999/xhtml" style="height: 300px; overflow: auto;"/> + + <data id="output"> + <hbox id="http://www.some-fictitious-zoo.com/birds/emu"> + <label value="Emu"/> + </hbox> + <hbox id="http://www.some-fictitious-zoo.com/birds/barnowl"> + <label value="Barn Owl"/> + </hbox> + <hbox id="http://www.some-fictitious-zoo.com/birds/raven"> + <label value="Raven"/> + </hbox> + <label step="2" id="http://www.some-fictitious-zoo.com/birds/emperorpenguin" value="Emperor Penguin"/> + </data> + +<script src="templates_shared.js"/> + +<script> +<![CDATA[ +SimpleTest.waitForExplicitFinish(); + +var testid ="simple syntax enclosed in a container with a rule"; +var queryType = "rdf"; +var isTreeBuilder = false; +var needsOpen = false; +var notWorkingYet = false; +var notWorkingYetDynamic = false; +var expectedOutput = document.getElementById("output"); + +var changes = []; +]]> +</script> + +<vbox xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul" id="root" datasources="rdf:null" ref="http://www.some-fictitious-zoo.com/birds"> +<template id="template"> +<rule> +<hbox uri="rdf:*"> +<label value="rdf:http://www.some-fictitious-zoo.com/rdf#name"/> +</hbox> +</rule> +</template> +</vbox> + +</window> diff --git a/dom/xul/templates/tests/chrome/test_tmpl_simplesyntaxfilter.xul b/dom/xul/templates/tests/chrome/test_tmpl_simplesyntaxfilter.xul new file mode 100644 index 000000000..8715d3cc1 --- /dev/null +++ b/dom/xul/templates/tests/chrome/test_tmpl_simplesyntaxfilter.xul @@ -0,0 +1,45 @@ +<?xml version="1.0"?> +<?xml-stylesheet href="chrome://global/skin" type="text/css"?> +<?xml-stylesheet href="chrome://mochikit/content/tests/SimpleTest/test.css" type="text/css"?> + +<!-- + simple syntax - filter +--> + +<window title="XUL Template Tests" width="500" height="600" + onload="test_template();" + xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"> + <script type="application/javascript" + src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script> + + <body xmlns="http://www.w3.org/1999/xhtml" style="height: 300px; overflow: auto;"/> + + <data id="output"> + <label id="http://www.some-fictitious-zoo.com/birds/barnowl" value="Barn Owl"/> + </data> + +<script src="templates_shared.js"/> + +<script> +<![CDATA[ +SimpleTest.waitForExplicitFinish(); + +var testid ="simple syntax - filter"; +var queryType = "rdf"; +var isTreeBuilder = false; +var needsOpen = false; +var notWorkingYet = false; +var notWorkingYetDynamic = false; +var expectedOutput = document.getElementById("output"); + +var changes = []; +]]> +</script> + +<vbox xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul" id="root" datasources="rdf:null" ref="http://www.some-fictitious-zoo.com/birds"> +<template zoo:name="Barn Owl" xmlns:zoo="http://www.some-fictitious-zoo.com/rdf#"> +<label uri="rdf:*" value="rdf:http://www.some-fictitious-zoo.com/rdf#name"/> +</template> +</vbox> + +</window> diff --git a/dom/xul/templates/tests/chrome/test_tmpl_simplesyntaxfilterwithmultiplerules.xul b/dom/xul/templates/tests/chrome/test_tmpl_simplesyntaxfilterwithmultiplerules.xul new file mode 100644 index 000000000..ba8591f60 --- /dev/null +++ b/dom/xul/templates/tests/chrome/test_tmpl_simplesyntaxfilterwithmultiplerules.xul @@ -0,0 +1,97 @@ +<?xml version="1.0"?> +<?xml-stylesheet href="chrome://global/skin" type="text/css"?> +<?xml-stylesheet href="chrome://mochikit/content/tests/SimpleTest/test.css" type="text/css"?> + +<!-- + simple syntax - filter with multiple rules +--> + +<window title="XUL Template Tests" width="500" height="600" + onload="test_template();" + xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"> + <script type="application/javascript" + src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script> + + <body xmlns="http://www.w3.org/1999/xhtml" style="height: 300px; overflow: auto;"/> + + <data id="output"> + <button id="http://www.some-fictitious-zoo.com/birds/emu" label="Emu"/> + <label step="-1" id="http://www.some-fictitious-zoo.com/birds/barnowl" value="Barn Owl"/> + <button step="4,-5" id="http://www.some-fictitious-zoo.com/birds/barnowl" label="Spooky Bird"/> + <label step="5" id="http://www.some-fictitious-zoo.com/birds/barnowl" value="Barn Owl"/> + <button step="1,-3" id="http://www.some-fictitious-zoo.com/birds/barnowl" label="Spooky Bird"/> + <button id="http://www.some-fictitious-zoo.com/birds/raven" label="Raven"/> + <label step="2" id="http://www.some-fictitious-zoo.com/birds/syntheticbarnowl" value="Barn Owl"/> + </data> + +<script src="templates_shared.js"/> + +<script> +<![CDATA[ +SimpleTest.waitForExplicitFinish(); + +var testid ="simple syntax - filter with multiple rules"; +var queryType = "rdf"; +var isTreeBuilder = false; +var needsOpen = false; +var notWorkingYet = false; +var notWorkingYetDynamic = false; +var expectedOutput = document.getElementById("output"); + +var changes = [ + // step 1 + function(targetds, root) { + var subject = RDF.GetResource(ZOO_NS + 'birds/barnowl'); + var predicate = RDF.GetResource(ZOO_NS + 'rdf#name'); + var oldval = targetds.GetTarget(subject, predicate, true); + targetds.Change(RDF.GetResource(ZOO_NS + 'birds/barnowl'), + RDF.GetResource(ZOO_NS + 'rdf#name'), + oldval, RDF.GetLiteral('Spooky Bird')); + }, + // step 2 + function(targetds, root) { + var newnode = RDF.GetResource(ZOO_NS + 'birds/syntheticbarnowl'); + targetds.Assert(newnode, RDF.GetResource(ZOO_NS + 'rdf#name'), + RDF.GetLiteral('Barn Owl'), true); + var container = ContainerUtils.MakeSeq(targetds, + RDF.GetResource(ZOO_NS + 'birds')); + container.AppendElement(newnode); + }, + // step 3 + function(targetds, root) { + var container = ContainerUtils.MakeSeq(targetds, + RDF.GetResource(ZOO_NS + 'birds')); + var removednode = container.RemoveElementAt('2', true); + }, + // step 4 + function(targetds, root) { + var newnode = RDF.GetResource(ZOO_NS + 'birds/barnowl'); + var container = ContainerUtils.MakeSeq(targetds, + RDF.GetResource(ZOO_NS + 'birds')); + container.InsertElementAt(newnode, '2', true); + }, + // step 5 + function(targetds, root) { + var subject = RDF.GetResource(ZOO_NS + 'birds/barnowl'); + var predicate = RDF.GetResource(ZOO_NS + 'rdf#name'); + var oldval = targetds.GetTarget(subject, predicate, true); + targetds.Change(RDF.GetResource(ZOO_NS + 'birds/barnowl'), + RDF.GetResource(ZOO_NS + 'rdf#name'), + oldval, RDF.GetLiteral('Barn Owl')); + } +]; +]]> +</script> + +<vbox xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul" id="root" datasources="rdf:null" ref="http://www.some-fictitious-zoo.com/birds"> +<template> +<rule zoo:name="Barn Owl" xmlns:zoo="http://www.some-fictitious-zoo.com/rdf#"> +<label uri="rdf:*" value="rdf:http://www.some-fictitious-zoo.com/rdf#name"/> +</rule> +<rule> +<button uri="rdf:*" label="rdf:http://www.some-fictitious-zoo.com/rdf#name"/> +</rule> +</template> +</vbox> + +</window> diff --git a/dom/xul/templates/tests/chrome/test_tmpl_simplesyntaxfilterwithrule.xul b/dom/xul/templates/tests/chrome/test_tmpl_simplesyntaxfilterwithrule.xul new file mode 100644 index 000000000..a2a3eb55e --- /dev/null +++ b/dom/xul/templates/tests/chrome/test_tmpl_simplesyntaxfilterwithrule.xul @@ -0,0 +1,98 @@ +<?xml version="1.0"?> +<?xml-stylesheet href="chrome://global/skin" type="text/css"?> +<?xml-stylesheet href="chrome://mochikit/content/tests/SimpleTest/test.css" type="text/css"?> + +<!-- + simple syntax - filter with rule +--> + +<window title="XUL Template Tests" width="500" height="600" + onload="test_template();" + xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"> + <script type="application/javascript" + src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script> + + <body xmlns="http://www.w3.org/1999/xhtml" style="height: 300px; overflow: auto;"/> + + <data id="output"> + <hbox step="-1" id="http://www.some-fictitious-zoo.com/birds/barnowl"> + <label value="Barn Owl"/> + </hbox> + <hbox step="5" id="http://www.some-fictitious-zoo.com/birds/barnowl"> + <label value="Barn Owl"/> + </hbox> + <hbox step="2" id="http://www.some-fictitious-zoo.com/birds/syntheticbarnowl"> + <label value="Barn Owl"/> + </hbox> + </data> + +<script src="templates_shared.js"/> + +<script> +<![CDATA[ +SimpleTest.waitForExplicitFinish(); + +var testid ="simple syntax - filter with rule"; +var queryType = "rdf"; +var isTreeBuilder = false; +var needsOpen = false; +var notWorkingYet = false; +var notWorkingYetDynamic = false; +var expectedOutput = document.getElementById("output"); + +var changes = [ + // step 1 + function(targetds, root) { + var subject = RDF.GetResource(ZOO_NS + 'birds/barnowl'); + var predicate = RDF.GetResource(ZOO_NS + 'rdf#name'); + var oldval = targetds.GetTarget(subject, predicate, true); + targetds.Change(RDF.GetResource(ZOO_NS + 'birds/barnowl'), + RDF.GetResource(ZOO_NS + 'rdf#name'), + oldval, RDF.GetLiteral('Spooky Bird')); + }, + // step 2 + function(targetds, root) { + var newnode = RDF.GetResource(ZOO_NS + 'birds/syntheticbarnowl'); + targetds.Assert(newnode, RDF.GetResource(ZOO_NS + 'rdf#name'), + RDF.GetLiteral('Barn Owl'), true); + var container = ContainerUtils.MakeSeq(targetds, + RDF.GetResource(ZOO_NS + 'birds')); + container.AppendElement(newnode); + }, + // step 3 + function(targetds, root) { + var container = ContainerUtils.MakeSeq(targetds, + RDF.GetResource(ZOO_NS + 'birds')); + var removednode = container.RemoveElementAt('2', true); + }, + // step 4 + function(targetds, root) { + var newnode = RDF.GetResource(ZOO_NS + 'birds/barnowl'); + var container = ContainerUtils.MakeSeq(targetds, + RDF.GetResource(ZOO_NS + 'birds')); + container.InsertElementAt(newnode, '2', true); + }, + // step 5 + function(targetds, root) { + var subject = RDF.GetResource(ZOO_NS + 'birds/barnowl'); + var predicate = RDF.GetResource(ZOO_NS + 'rdf#name'); + var oldval = targetds.GetTarget(subject, predicate, true); + targetds.Change(RDF.GetResource(ZOO_NS + 'birds/barnowl'), + RDF.GetResource(ZOO_NS + 'rdf#name'), + oldval, RDF.GetLiteral('Barn Owl')); + } +]; +]]> +</script> + +<vbox xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul" id="root" datasources="rdf:null" ref="http://www.some-fictitious-zoo.com/birds"> +<template> +<rule zoo:name="Barn Owl" xmlns:zoo="http://www.some-fictitious-zoo.com/rdf#"> +<hbox uri="rdf:*"> +<label value="rdf:http://www.some-fictitious-zoo.com/rdf#name"/> +</hbox> +</rule> +</template> +</vbox> + +</window> diff --git a/dom/xul/templates/tests/chrome/test_tmpl_simplesyntaxiteratingoverasinglevalue.xul b/dom/xul/templates/tests/chrome/test_tmpl_simplesyntaxiteratingoverasinglevalue.xul new file mode 100644 index 000000000..e8e05acf2 --- /dev/null +++ b/dom/xul/templates/tests/chrome/test_tmpl_simplesyntaxiteratingoverasinglevalue.xul @@ -0,0 +1,86 @@ +<?xml version="1.0"?> +<?xml-stylesheet href="chrome://global/skin" type="text/css"?> +<?xml-stylesheet href="chrome://mochikit/content/tests/SimpleTest/test.css" type="text/css"?> + +<!-- + simple syntax iterating over a single value +--> + +<window title="XUL Template Tests" width="500" height="600" + onload="test_template();" + xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"> + <script type="application/javascript" + src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script> + + <body xmlns="http://www.w3.org/1999/xhtml" style="height: 300px; overflow: auto;"/> + + <data id="output"> + <label step="3" id="http://www.some-fictitious-zoo.com/birds/wren" value="Wren"/> + <label id="http://www.some-fictitious-zoo.com/birds/emu" value="Emu"/> + <label step="-4" id="http://www.some-fictitious-zoo.com/birds/barnowl" value="Barn Owl"/> + <label id="http://www.some-fictitious-zoo.com/birds/raven" value="Raven"/> + <label step="2" id="http://www.some-fictitious-zoo.com/birds/archaeopteryx" value="Archaeopteryx"/> + <label step="1" id="http://www.some-fictitious-zoo.com/birds/emperorpenguin" value="Emperor Penguin"/> + </data> + +<script src="templates_shared.js"/> + +<script> +<![CDATA[ +SimpleTest.waitForExplicitFinish(); + +var testid ="simple syntax iterating over a single value"; +var queryType = "rdf"; +var isTreeBuilder = false; +var needsOpen = false; +var notWorkingYet = false; +var notWorkingYetDynamic = false; +var expectedOutput = document.getElementById("output"); + +var changes = [ + // step 1 + function(targetds, root) { + var newnode = RDF.GetResource(ZOO_NS + 'birds/emperorpenguin'); + targetds.Assert(newnode, RDF.GetResource(ZOO_NS + 'rdf#name'), + RDF.GetLiteral('Emperor Penguin'), true); + var container = ContainerUtils.MakeSeq(targetds, + RDF.GetResource(ZOO_NS + 'birds')); + container.AppendElement(newnode); + }, + // step 2 + function(targetds, root) { + var newnode = RDF.GetResource(ZOO_NS + 'birds/archaeopteryx'); + targetds.Assert(newnode, RDF.GetResource(ZOO_NS + 'rdf#name'), + RDF.GetLiteral('Archaeopteryx'), true); + var container = ContainerUtils.MakeSeq(targetds, + RDF.GetResource(ZOO_NS + 'birds')); + container.InsertElementAt(newnode, '4', true); + }, + // step 3 + function(targetds, root) { + var newnode = RDF.GetResource(ZOO_NS + 'birds/wren'); + targetds.Assert(newnode, RDF.GetResource(ZOO_NS + 'rdf#name'), + RDF.GetLiteral('Wren'), true); + var container = ContainerUtils.MakeSeq(targetds, + RDF.GetResource(ZOO_NS + 'birds')); + container.InsertElementAt(newnode, '1', true); + }, + // step 4 + function(targetds, root) { + var container = ContainerUtils.MakeSeq(targetds, + RDF.GetResource(ZOO_NS + 'birds')); + var removednode = container.RemoveElementAt('3', true); + targetds.Unassert(removednode, RDF.GetResource(ZOO_NS + 'rdf#name'), + RDF.GetLiteral('Barn Owl'), true); + } +]; +]]> +</script> + +<vbox xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul" id="root" datasources="rdf:null" ref="http://www.some-fictitious-zoo.com/birds"> +<template id="template"> +<label uri="rdf:*" value="rdf:http://www.some-fictitious-zoo.com/rdf#name"/> +</template> +</vbox> + +</window> diff --git a/dom/xul/templates/tests/chrome/test_tmpl_simplesyntaxusinganinterveningcontainer.xul b/dom/xul/templates/tests/chrome/test_tmpl_simplesyntaxusinganinterveningcontainer.xul new file mode 100644 index 000000000..5aa5172c9 --- /dev/null +++ b/dom/xul/templates/tests/chrome/test_tmpl_simplesyntaxusinganinterveningcontainer.xul @@ -0,0 +1,90 @@ +<?xml version="1.0"?> +<?xml-stylesheet href="chrome://global/skin" type="text/css"?> +<?xml-stylesheet href="chrome://mochikit/content/tests/SimpleTest/test.css" type="text/css"?> + +<!-- + simple syntax using an intervening container +--> + +<window title="XUL Template Tests" width="500" height="600" + onload="test_template();" + xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"> + <script type="application/javascript" + src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script> + + <body xmlns="http://www.w3.org/1999/xhtml" style="height: 300px; overflow: auto;"/> + + <data id="output"> + <groupbox> + <label step="3" id="http://www.some-fictitious-zoo.com/birds/wren" value="Wren"/> + <label id="http://www.some-fictitious-zoo.com/birds/emu" value="Emu"/> + <label step="-4" id="http://www.some-fictitious-zoo.com/birds/barnowl" value="Barn Owl"/> + <label id="http://www.some-fictitious-zoo.com/birds/raven" value="Raven"/> + <label step="2" id="http://www.some-fictitious-zoo.com/birds/archaeopteryx" value="Archaeopteryx"/> + <label step="1" id="http://www.some-fictitious-zoo.com/birds/emperorpenguin" value="Emperor Penguin"/> + </groupbox> + </data> + +<script src="templates_shared.js"/> + +<script> +<![CDATA[ +SimpleTest.waitForExplicitFinish(); + +var testid ="simple syntax using an intervening container"; +var queryType = "rdf"; +var isTreeBuilder = false; +var needsOpen = false; +var notWorkingYet = false; +var notWorkingYetDynamic = false; +var expectedOutput = document.getElementById("output"); + +var changes = [ + // step 1 + function(targetds, root) { + var newnode = RDF.GetResource(ZOO_NS + 'birds/emperorpenguin'); + targetds.Assert(newnode, RDF.GetResource(ZOO_NS + 'rdf#name'), + RDF.GetLiteral('Emperor Penguin'), true); + var container = ContainerUtils.MakeSeq(targetds, + RDF.GetResource(ZOO_NS + 'birds')); + container.AppendElement(newnode); + }, + // step 2 + function(targetds, root) { + var newnode = RDF.GetResource(ZOO_NS + 'birds/archaeopteryx'); + targetds.Assert(newnode, RDF.GetResource(ZOO_NS + 'rdf#name'), + RDF.GetLiteral('Archaeopteryx'), true); + var container = ContainerUtils.MakeSeq(targetds, + RDF.GetResource(ZOO_NS + 'birds')); + container.InsertElementAt(newnode, '4', true); + }, + // step 3 + function(targetds, root) { + var newnode = RDF.GetResource(ZOO_NS + 'birds/wren'); + targetds.Assert(newnode, RDF.GetResource(ZOO_NS + 'rdf#name'), + RDF.GetLiteral('Wren'), true); + var container = ContainerUtils.MakeSeq(targetds, + RDF.GetResource(ZOO_NS + 'birds')); + container.InsertElementAt(newnode, '1', true); + }, + // step 4 + function(targetds, root) { + var container = ContainerUtils.MakeSeq(targetds, + RDF.GetResource(ZOO_NS + 'birds')); + var removednode = container.RemoveElementAt('3', true); + targetds.Unassert(removednode, RDF.GetResource(ZOO_NS + 'rdf#name'), + RDF.GetLiteral('Barn Owl'), true); + } +]; +]]> +</script> + +<vbox xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul" id="root" datasources="rdf:null" ref="http://www.some-fictitious-zoo.com/birds"> +<template id="template"> +<groupbox> +<label uri="rdf:*" value="rdf:http://www.some-fictitious-zoo.com/rdf#name"/> +</groupbox> +</template> +</vbox> + +</window> diff --git a/dom/xul/templates/tests/chrome/test_tmpl_simplesyntaxusingatextnode.xul b/dom/xul/templates/tests/chrome/test_tmpl_simplesyntaxusingatextnode.xul new file mode 100644 index 000000000..3fb1fdfa0 --- /dev/null +++ b/dom/xul/templates/tests/chrome/test_tmpl_simplesyntaxusingatextnode.xul @@ -0,0 +1,50 @@ +<?xml version="1.0"?> +<?xml-stylesheet href="chrome://global/skin" type="text/css"?> +<?xml-stylesheet href="chrome://mochikit/content/tests/SimpleTest/test.css" type="text/css"?> + +<!-- + simple syntax using a textnode +--> + +<window title="XUL Template Tests" width="500" height="600" + onload="test_template();" + xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"> + <script type="application/javascript" + src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script> + + <body xmlns="http://www.w3.org/1999/xhtml" style="height: 300px; overflow: auto;"/> + + <data id="output"> + <description step="3" id="http://www.some-fictitious-zoo.com/birds/wren">Wren</description> + <description id="http://www.some-fictitious-zoo.com/birds/emu">Emu</description> + <description step="-4" id="http://www.some-fictitious-zoo.com/birds/barnowl">Barn Owl</description> + <description id="http://www.some-fictitious-zoo.com/birds/raven">Raven</description> + <description step="2" id="http://www.some-fictitious-zoo.com/birds/archaeopteryx">Archaeopteryx</description> + <description step="1" id="http://www.some-fictitious-zoo.com/birds/emperorpenguin">Emperor Penguin</description> + </data> + +<script src="templates_shared.js"/> + +<script> +<![CDATA[ +SimpleTest.waitForExplicitFinish(); + +var testid ="simple syntax using a textnode"; +var queryType = "rdf"; +var isTreeBuilder = false; +var needsOpen = false; +var notWorkingYet = false; +var notWorkingYetDynamic = false; +var expectedOutput = document.getElementById("output"); + +var changes = []; +]]> +</script> + +<vbox xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul" id="root" datasources="rdf:null" ref="http://www.some-fictitious-zoo.com/birds"> +<template id="template"> +<description uri="rdf:*"><textnode value="rdf:http://www.some-fictitious-zoo.com/rdf#name"/></description> +</template> +</vbox> + +</window> diff --git a/dom/xul/templates/tests/chrome/test_tmpl_simplesyntaxusingcontainerasthegenerationelement.xul b/dom/xul/templates/tests/chrome/test_tmpl_simplesyntaxusingcontainerasthegenerationelement.xul new file mode 100644 index 000000000..238540fb4 --- /dev/null +++ b/dom/xul/templates/tests/chrome/test_tmpl_simplesyntaxusingcontainerasthegenerationelement.xul @@ -0,0 +1,100 @@ +<?xml version="1.0"?> +<?xml-stylesheet href="chrome://global/skin" type="text/css"?> +<?xml-stylesheet href="chrome://mochikit/content/tests/SimpleTest/test.css" type="text/css"?> + +<!-- + simple syntax using container as the generation element +--> + +<window title="XUL Template Tests" width="500" height="600" + onload="test_template();" + xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"> + <script type="application/javascript" + src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script> + + <body xmlns="http://www.w3.org/1999/xhtml" style="height: 300px; overflow: auto;"/> + + <data id="output"> + <hbox step="3" id="http://www.some-fictitious-zoo.com/birds/wren"> + <label value="Wren"/> + </hbox> + <hbox id="http://www.some-fictitious-zoo.com/birds/emu"> + <label value="Emu"/> + </hbox> + <hbox step="-4" id="http://www.some-fictitious-zoo.com/birds/barnowl"> + <label value="Barn Owl"/> + </hbox> + <hbox id="http://www.some-fictitious-zoo.com/birds/raven"> + <label value="Raven"/> + </hbox> + <hbox step="2" id="http://www.some-fictitious-zoo.com/birds/archaeopteryx"> + <label value="Archaeopteryx"/> + </hbox> + <hbox step="1" id="http://www.some-fictitious-zoo.com/birds/emperorpenguin"> + <label value="Emperor Penguin"/> + </hbox> + </data> + +<script src="templates_shared.js"/> + +<script> +<![CDATA[ +SimpleTest.waitForExplicitFinish(); + +var testid ="simple syntax using container as the generation element"; +var queryType = "rdf"; +var isTreeBuilder = false; +var needsOpen = false; +var notWorkingYet = false; +var notWorkingYetDynamic = false; +var expectedOutput = document.getElementById("output"); + +var changes = [ + // step 1 + function(targetds, root) { + var newnode = RDF.GetResource(ZOO_NS + 'birds/emperorpenguin'); + targetds.Assert(newnode, RDF.GetResource(ZOO_NS + 'rdf#name'), + RDF.GetLiteral('Emperor Penguin'), true); + var container = ContainerUtils.MakeSeq(targetds, + RDF.GetResource(ZOO_NS + 'birds')); + container.AppendElement(newnode); + }, + // step 2 + function(targetds, root) { + var newnode = RDF.GetResource(ZOO_NS + 'birds/archaeopteryx'); + targetds.Assert(newnode, RDF.GetResource(ZOO_NS + 'rdf#name'), + RDF.GetLiteral('Archaeopteryx'), true); + var container = ContainerUtils.MakeSeq(targetds, + RDF.GetResource(ZOO_NS + 'birds')); + container.InsertElementAt(newnode, '4', true); + }, + // step 3 + function(targetds, root) { + var newnode = RDF.GetResource(ZOO_NS + 'birds/wren'); + targetds.Assert(newnode, RDF.GetResource(ZOO_NS + 'rdf#name'), + RDF.GetLiteral('Wren'), true); + var container = ContainerUtils.MakeSeq(targetds, + RDF.GetResource(ZOO_NS + 'birds')); + container.InsertElementAt(newnode, '1', true); + }, + // step 4 + function(targetds, root) { + var container = ContainerUtils.MakeSeq(targetds, + RDF.GetResource(ZOO_NS + 'birds')); + var removednode = container.RemoveElementAt('3', true); + targetds.Unassert(removednode, RDF.GetResource(ZOO_NS + 'rdf#name'), + RDF.GetLiteral('Barn Owl'), true); + } +]; +]]> +</script> + +<vbox xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul" id="root" datasources="rdf:null" ref="http://www.some-fictitious-zoo.com/birds"> +<template id="template"> +<hbox uri="rdf:*"> +<label value="rdf:http://www.some-fictitious-zoo.com/rdf#name"/> +</hbox> +</template> +</vbox> + +</window> diff --git a/dom/xul/templates/tests/chrome/test_tmpl_simplesyntaxusingdontrecurse.xul b/dom/xul/templates/tests/chrome/test_tmpl_simplesyntaxusingdontrecurse.xul new file mode 100644 index 000000000..31aa9c404 --- /dev/null +++ b/dom/xul/templates/tests/chrome/test_tmpl_simplesyntaxusingdontrecurse.xul @@ -0,0 +1,52 @@ +<?xml version="1.0"?> +<?xml-stylesheet href="chrome://global/skin" type="text/css"?> +<?xml-stylesheet href="chrome://mochikit/content/tests/SimpleTest/test.css" type="text/css"?> + +<!-- + simple syntax using dont-recurse +--> + +<window title="XUL Template Tests" width="500" height="600" + onload="test_template();" + xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"> + <script type="application/javascript" + src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script> + + <body xmlns="http://www.w3.org/1999/xhtml" style="height: 300px; overflow: auto;"/> + + <data id="output"> + <hbox id="http://www.some-fictitious-zoo.com/arachnids" container="true" empty="false"> + <label value="Arachnids"/> + </hbox> + <hbox id="http://www.some-fictitious-zoo.com/birds" container="true" empty="false"> + <label value="Birds"/> + </hbox> + </data> + +<script src="templates_shared.js"/> + +<script> +<![CDATA[ +SimpleTest.waitForExplicitFinish(); + +var testid ="simple syntax using dont-recurse"; +var queryType = "rdf"; +var isTreeBuilder = false; +var needsOpen = false; +var notWorkingYet = false; +var notWorkingYetDynamic = false; +var expectedOutput = document.getElementById("output"); + +var changes = []; +]]> +</script> + +<vbox xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul" id="root" datasources="rdf:null" ref="http://www.some-fictitious-zoo.com/some-animals" flags="dont-recurse"> +<template id="template"> +<hbox uri="rdf:*"> +<label value="rdf:http://www.some-fictitious-zoo.com/rdf#name"/> +</hbox> +</template> +</vbox> + +</window> diff --git a/dom/xul/templates/tests/chrome/test_tmpl_simplesyntaxusingrecursivegeneration.xul b/dom/xul/templates/tests/chrome/test_tmpl_simplesyntaxusingrecursivegeneration.xul new file mode 100644 index 000000000..3ef3b1d3d --- /dev/null +++ b/dom/xul/templates/tests/chrome/test_tmpl_simplesyntaxusingrecursivegeneration.xul @@ -0,0 +1,109 @@ +<?xml version="1.0"?> +<?xml-stylesheet href="chrome://global/skin" type="text/css"?> +<?xml-stylesheet href="chrome://mochikit/content/tests/SimpleTest/test.css" type="text/css"?> + +<!-- + simple syntax using recursive generation +--> + +<window title="XUL Template Tests" width="500" height="600" + onload="test_template();" + xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"> + <script type="application/javascript" + src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script> + + <body xmlns="http://www.w3.org/1999/xhtml" style="height: 300px; overflow: auto;"/> + + <data id="output"> + <hbox id="http://www.some-fictitious-zoo.com/arachnids" container="true" empty="false"> + <label value="Arachnids"/> + <hbox id="http://www.some-fictitious-zoo.com/arachnids/tarantula"> + <label value="Tarantula"/> + </hbox> + </hbox> + <hbox id="http://www.some-fictitious-zoo.com/birds" container="true" empty="false"> + <label value="Birds"/> + <hbox step="3" id="http://www.some-fictitious-zoo.com/birds/wren"> + <label value="Wren"/> + </hbox> + <hbox id="http://www.some-fictitious-zoo.com/birds/emu"> + <label value="Emu"/> + </hbox> + <hbox step="-4" id="http://www.some-fictitious-zoo.com/birds/barnowl"> + <label value="Barn Owl"/> + </hbox> + <hbox id="http://www.some-fictitious-zoo.com/birds/raven"> + <label value="Raven"/> + </hbox> + <hbox step="2" id="http://www.some-fictitious-zoo.com/birds/archaeopteryx"> + <label value="Archaeopteryx"/> + </hbox> + <hbox step="1" id="http://www.some-fictitious-zoo.com/birds/emperorpenguin"> + <label value="Emperor Penguin"/> + </hbox> + </hbox> + </data> + +<script src="templates_shared.js"/> + +<script> +<![CDATA[ +SimpleTest.waitForExplicitFinish(); + +var testid ="simple syntax using recursive generation"; +var queryType = "rdf"; +var isTreeBuilder = false; +var needsOpen = false; +var notWorkingYet = false; +var notWorkingYetDynamic = false; +var expectedOutput = document.getElementById("output"); + +var changes = [ + // step 1 + function(targetds, root) { + var newnode = RDF.GetResource(ZOO_NS + 'birds/emperorpenguin'); + targetds.Assert(newnode, RDF.GetResource(ZOO_NS + 'rdf#name'), + RDF.GetLiteral('Emperor Penguin'), true); + var container = ContainerUtils.MakeSeq(targetds, + RDF.GetResource(ZOO_NS + 'birds')); + container.AppendElement(newnode); + }, + // step 2 + function(targetds, root) { + var newnode = RDF.GetResource(ZOO_NS + 'birds/archaeopteryx'); + targetds.Assert(newnode, RDF.GetResource(ZOO_NS + 'rdf#name'), + RDF.GetLiteral('Archaeopteryx'), true); + var container = ContainerUtils.MakeSeq(targetds, + RDF.GetResource(ZOO_NS + 'birds')); + container.InsertElementAt(newnode, '4', true); + }, + // step 3 + function(targetds, root) { + var newnode = RDF.GetResource(ZOO_NS + 'birds/wren'); + targetds.Assert(newnode, RDF.GetResource(ZOO_NS + 'rdf#name'), + RDF.GetLiteral('Wren'), true); + var container = ContainerUtils.MakeSeq(targetds, + RDF.GetResource(ZOO_NS + 'birds')); + container.InsertElementAt(newnode, '1', true); + }, + // step 4 + function(targetds, root) { + var container = ContainerUtils.MakeSeq(targetds, + RDF.GetResource(ZOO_NS + 'birds')); + var removednode = container.RemoveElementAt('3', true); + targetds.Unassert(removednode, RDF.GetResource(ZOO_NS + 'rdf#name'), + RDF.GetLiteral('Barn Owl'), true); + } +]; +]]> +</script> + +<vbox xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul" id="root" datasources="rdf:null" ref="http://www.some-fictitious-zoo.com/some-animals"> +<template id="template"> +<hbox uri="rdf:*"> +<label value="rdf:http://www.some-fictitious-zoo.com/rdf#name"/> +</hbox> +</template> +</vbox> + +</window> diff --git a/dom/xul/templates/tests/chrome/test_tmpl_simplesyntaxusingrecursivegenerationagain.xul b/dom/xul/templates/tests/chrome/test_tmpl_simplesyntaxusingrecursivegenerationagain.xul new file mode 100644 index 000000000..73d7f742e --- /dev/null +++ b/dom/xul/templates/tests/chrome/test_tmpl_simplesyntaxusingrecursivegenerationagain.xul @@ -0,0 +1,64 @@ +<?xml version="1.0"?> +<?xml-stylesheet href="chrome://global/skin" type="text/css"?> +<?xml-stylesheet href="chrome://mochikit/content/tests/SimpleTest/test.css" type="text/css"?> + +<!-- + simple syntax using recursive generation again +--> + +<window title="XUL Template Tests" width="500" height="600" + onload="test_template();" + xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"> + <script type="application/javascript" + src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script> + + <body xmlns="http://www.w3.org/1999/xhtml" style="height: 300px; overflow: auto;"/> + + <data id="output"> + <hbox id="http://www.some-fictitious-zoo.com/arachnids" container="true" empty="false"> + <label value="Arachnids"/> + <hbox id="http://www.some-fictitious-zoo.com/arachnids/tarantula"> + <label value="Tarantula"/> + </hbox> + </hbox> + <hbox id="http://www.some-fictitious-zoo.com/birds" container="true" empty="false"> + <label value="Birds"/> + <hbox id="http://www.some-fictitious-zoo.com/birds/emu"> + <label value="Emu"/> + </hbox> + <hbox id="http://www.some-fictitious-zoo.com/birds/barnowl"> + <label value="Barn Owl"/> + </hbox> + <hbox id="http://www.some-fictitious-zoo.com/birds/raven"> + <label value="Raven"/> + </hbox> + </hbox> + </data> + +<script src="templates_shared.js"/> + +<script> +<![CDATA[ +SimpleTest.waitForExplicitFinish(); + +var testid ="simple syntax using recursive generation again"; +var queryType = "rdf"; +var isTreeBuilder = false; +var needsOpen = false; +var notWorkingYet = false; +var notWorkingYetDynamic = false; +var expectedOutput = document.getElementById("output"); + +var changes = []; +]]> +</script> + +<vbox xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul" id="root" datasources="rdf:null" ref="http://www.some-fictitious-zoo.com/some-animals"> +<template id="template"> +<hbox uri="rdf:*"> +<label value="rdf:http://www.some-fictitious-zoo.com/rdf#name"/> +</hbox> +</template> +</vbox> + +</window> diff --git a/dom/xul/templates/tests/chrome/test_tmpl_simplesyntaxwithtwovariablesused.xul b/dom/xul/templates/tests/chrome/test_tmpl_simplesyntaxwithtwovariablesused.xul new file mode 100644 index 000000000..fccee70ce --- /dev/null +++ b/dom/xul/templates/tests/chrome/test_tmpl_simplesyntaxwithtwovariablesused.xul @@ -0,0 +1,59 @@ +<?xml version="1.0"?> +<?xml-stylesheet href="chrome://global/skin" type="text/css"?> +<?xml-stylesheet href="chrome://mochikit/content/tests/SimpleTest/test.css" type="text/css"?> + +<!-- + simple syntax with two variables used +--> + +<window title="XUL Template Tests" width="500" height="600" + onload="test_template();" + xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"> + <script type="application/javascript" + src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script> + + <body xmlns="http://www.w3.org/1999/xhtml" style="height: 300px; overflow: auto;"/> + + <data id="output"> + <hbox id="http://www.some-fictitious-zoo.com/birds/emu"> + <label value="Emu"/> + <label value="12"/> + </hbox> + <hbox id="http://www.some-fictitious-zoo.com/birds/barnowl"> + <label value="Barn Owl"/> + <label value="4"/> + </hbox> + <hbox id="http://www.some-fictitious-zoo.com/birds/raven"> + <label value="Raven"/> + <label value="0"/> + </hbox> + </data> + +<script src="templates_shared.js"/> + +<script> +<![CDATA[ +SimpleTest.waitForExplicitFinish(); + +var testid ="simple syntax with two variables used"; +var queryType = "rdf"; +var isTreeBuilder = false; +var needsOpen = false; +var notWorkingYet = false; +var notWorkingYetDynamic = false; +var expectedOutput = document.getElementById("output"); + +var changes = []; +]]> +</script> + +<vbox xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul" id="root" datasources="rdf:null" ref="http://www.some-fictitious-zoo.com/birds"> +<template id="template"> +<hbox uri="rdf:*"> +<label value="rdf:http://www.some-fictitious-zoo.com/rdf#name"/> +<label value="rdf:http://www.some-fictitious-zoo.com/rdf#specimens"/> +</hbox> +</template> +</vbox> + +</window> diff --git a/dom/xul/templates/tests/chrome/test_tmpl_simplevariablesubstitutioncaretsatbeginningandend.xul b/dom/xul/templates/tests/chrome/test_tmpl_simplevariablesubstitutioncaretsatbeginningandend.xul new file mode 100644 index 000000000..2ca63da19 --- /dev/null +++ b/dom/xul/templates/tests/chrome/test_tmpl_simplevariablesubstitutioncaretsatbeginningandend.xul @@ -0,0 +1,45 @@ +<?xml version="1.0"?> +<?xml-stylesheet href="chrome://global/skin" type="text/css"?> +<?xml-stylesheet href="chrome://mochikit/content/tests/SimpleTest/test.css" type="text/css"?> + +<!-- + simple variable substitution - carets at beginning and end +--> + +<window title="XUL Template Tests" width="500" height="600" + onload="test_template();" + xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"> + <script type="application/javascript" + src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script> + + <body xmlns="http://www.w3.org/1999/xhtml" style="height: 300px; overflow: auto;"/> + + <data id="output"> + <label id="http://www.some-fictitious-zoo.com/arachnids/tarantula" value="^^Before Tarantula^"/> + </data> + +<script src="templates_shared.js"/> + +<script> +<![CDATA[ +SimpleTest.waitForExplicitFinish(); + +var testid ="simple variable substitution - carets at beginning and end"; +var queryType = "rdf"; +var isTreeBuilder = false; +var needsOpen = false; +var notWorkingYet = false; +var notWorkingYetDynamic = false; +var expectedOutput = document.getElementById("output"); + +var changes = []; +]]> +</script> + +<vbox xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul" id="root" datasources="rdf:null" ref="http://www.some-fictitious-zoo.com/arachnids"> +<template id="template"> +<label uri="rdf:*" value="^^Before rdf:http://www.some-fictitious-zoo.com/rdf#name^^"/> +</template> +</vbox> + +</window> diff --git a/dom/xul/templates/tests/chrome/test_tmpl_simplevariablesubstitutioncaretsubstitution.xul b/dom/xul/templates/tests/chrome/test_tmpl_simplevariablesubstitutioncaretsubstitution.xul new file mode 100644 index 000000000..abc28ff0f --- /dev/null +++ b/dom/xul/templates/tests/chrome/test_tmpl_simplevariablesubstitutioncaretsubstitution.xul @@ -0,0 +1,45 @@ +<?xml version="1.0"?> +<?xml-stylesheet href="chrome://global/skin" type="text/css"?> +<?xml-stylesheet href="chrome://mochikit/content/tests/SimpleTest/test.css" type="text/css"?> + +<!-- + simple variable substitution - caret substitution +--> + +<window title="XUL Template Tests" width="500" height="600" + onload="test_template();" + xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"> + <script type="application/javascript" + src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script> + + <body xmlns="http://www.w3.org/1999/xhtml" style="height: 300px; overflow: auto;"/> + + <data id="output"> + <label id="http://www.some-fictitious-zoo.com/arachnids/tarantula" value="Tarantula^ and^^ lots ^ more"/> + </data> + +<script src="templates_shared.js"/> + +<script> +<![CDATA[ +SimpleTest.waitForExplicitFinish(); + +var testid ="simple variable substitution - caret substitution"; +var queryType = "rdf"; +var isTreeBuilder = false; +var needsOpen = false; +var notWorkingYet = false; +var notWorkingYetDynamic = false; +var expectedOutput = document.getElementById("output"); + +var changes = []; +]]> +</script> + +<vbox xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul" id="root" datasources="rdf:null" ref="http://www.some-fictitious-zoo.com/arachnids"> +<template id="template"> +<label uri="rdf:*" value="rdf:http://www.some-fictitious-zoo.com/rdf#name^^ and^^ lots ^ more"/> +</template> +</vbox> + +</window> diff --git a/dom/xul/templates/tests/chrome/test_tmpl_simplevariablesubstitutionnovariable.xul b/dom/xul/templates/tests/chrome/test_tmpl_simplevariablesubstitutionnovariable.xul new file mode 100644 index 000000000..4d2404aca --- /dev/null +++ b/dom/xul/templates/tests/chrome/test_tmpl_simplevariablesubstitutionnovariable.xul @@ -0,0 +1,45 @@ +<?xml version="1.0"?> +<?xml-stylesheet href="chrome://global/skin" type="text/css"?> +<?xml-stylesheet href="chrome://mochikit/content/tests/SimpleTest/test.css" type="text/css"?> + +<!-- + simple variable substitution - no variable +--> + +<window title="XUL Template Tests" width="500" height="600" + onload="test_template();" + xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"> + <script type="application/javascript" + src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script> + + <body xmlns="http://www.w3.org/1999/xhtml" style="height: 300px; overflow: auto;"/> + + <data id="output"> + <label id="http://www.some-fictitious-zoo.com/arachnids/tarantula" value="Name"/> + </data> + +<script src="templates_shared.js"/> + +<script> +<![CDATA[ +SimpleTest.waitForExplicitFinish(); + +var testid ="simple variable substitution - no variable"; +var queryType = "rdf"; +var isTreeBuilder = false; +var needsOpen = false; +var notWorkingYet = false; +var notWorkingYetDynamic = false; +var expectedOutput = document.getElementById("output"); + +var changes = []; +]]> +</script> + +<vbox xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul" id="root" datasources="rdf:null" ref="http://www.some-fictitious-zoo.com/arachnids"> +<template id="template"> +<label uri="rdf:*" value="Name"/> +</template> +</vbox> + +</window> diff --git a/dom/xul/templates/tests/chrome/test_tmpl_simplevariablesubstitutionquestionmarkaspartofvariable.xul b/dom/xul/templates/tests/chrome/test_tmpl_simplevariablesubstitutionquestionmarkaspartofvariable.xul new file mode 100644 index 000000000..0dd1a7ccf --- /dev/null +++ b/dom/xul/templates/tests/chrome/test_tmpl_simplevariablesubstitutionquestionmarkaspartofvariable.xul @@ -0,0 +1,45 @@ +<?xml version="1.0"?> +<?xml-stylesheet href="chrome://global/skin" type="text/css"?> +<?xml-stylesheet href="chrome://mochikit/content/tests/SimpleTest/test.css" type="text/css"?> + +<!-- + simple variable substitution - question mark as part of variable +--> + +<window title="XUL Template Tests" width="500" height="600" + onload="test_template();" + xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"> + <script type="application/javascript" + src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script> + + <body xmlns="http://www.w3.org/1999/xhtml" style="height: 300px; overflow: auto;"/> + + <data id="output"> + <label id="http://www.some-fictitious-zoo.com/arachnids/tarantula" value="Name is "/> + </data> + +<script src="templates_shared.js"/> + +<script> +<![CDATA[ +SimpleTest.waitForExplicitFinish(); + +var testid ="simple variable substitution - question mark as part of variable"; +var queryType = "rdf"; +var isTreeBuilder = false; +var needsOpen = false; +var notWorkingYet = false; +var notWorkingYetDynamic = false; +var expectedOutput = document.getElementById("output"); + +var changes = []; +]]> +</script> + +<vbox xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul" id="root" datasources="rdf:null" ref="http://www.some-fictitious-zoo.com/arachnids"> +<template id="template"> +<label uri="rdf:*" value="Name is rdf:http://www.some-fictitious-zoo.com/rdf#name?"/> +</template> +</vbox> + +</window> diff --git a/dom/xul/templates/tests/chrome/test_tmpl_simplevariablesubstitutionquestionmarksubstitution.xul b/dom/xul/templates/tests/chrome/test_tmpl_simplevariablesubstitutionquestionmarksubstitution.xul new file mode 100644 index 000000000..c31401dd4 --- /dev/null +++ b/dom/xul/templates/tests/chrome/test_tmpl_simplevariablesubstitutionquestionmarksubstitution.xul @@ -0,0 +1,56 @@ +<?xml version="1.0"?> +<?xml-stylesheet href="chrome://global/skin" type="text/css"?> +<?xml-stylesheet href="chrome://mochikit/content/tests/SimpleTest/test.css" type="text/css"?> + +<!-- + simple variable substitution - question mark substitution +--> + +<window title="XUL Template Tests" width="500" height="600" + onload="test_template();" + xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"> + <script type="application/javascript" + src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script> + + <body xmlns="http://www.w3.org/1999/xhtml" style="height: 300px; overflow: auto;"/> + + <data id="output"> + <label step="-1" id="http://www.some-fictitious-zoo.com/arachnids/tarantula" value="Are you a Tarantula ?"/> + <label step="1" id="http://www.some-fictitious-zoo.com/arachnids/tarantula" value="Are you a Hairy Spider ?"/> + </data> + +<script src="templates_shared.js"/> + +<script> +<![CDATA[ +SimpleTest.waitForExplicitFinish(); + +var testid ="simple variable substitution - question mark substitution"; +var queryType = "rdf"; +var isTreeBuilder = false; +var needsOpen = false; +var notWorkingYet = false; +var notWorkingYetDynamic = false; +var expectedOutput = document.getElementById("output"); + +var changes = [ + // step 1 + function(targetds, root) { + var subject = RDF.GetResource(ZOO_NS + 'arachnids/tarantula'); + var predicate = RDF.GetResource(ZOO_NS + 'rdf#name'); + var oldval = targetds.GetTarget(subject, predicate, true); + targetds.Change(RDF.GetResource(ZOO_NS + 'arachnids/tarantula'), + RDF.GetResource(ZOO_NS + 'rdf#name'), + oldval, RDF.GetLiteral('Hairy Spider')); + } +]; +]]> +</script> + +<vbox xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul" id="root" datasources="rdf:null" ref="http://www.some-fictitious-zoo.com/arachnids"> +<template id="template"> +<label uri="rdf:*" value="Are you a rdf:http://www.some-fictitious-zoo.com/rdf#name ?sample ??"/> +</template> +</vbox> + +</window> diff --git a/dom/xul/templates/tests/chrome/test_tmpl_simplevariablesubstitutiontextandvariable.xul b/dom/xul/templates/tests/chrome/test_tmpl_simplevariablesubstitutiontextandvariable.xul new file mode 100644 index 000000000..6d2bc806b --- /dev/null +++ b/dom/xul/templates/tests/chrome/test_tmpl_simplevariablesubstitutiontextandvariable.xul @@ -0,0 +1,56 @@ +<?xml version="1.0"?> +<?xml-stylesheet href="chrome://global/skin" type="text/css"?> +<?xml-stylesheet href="chrome://mochikit/content/tests/SimpleTest/test.css" type="text/css"?> + +<!-- + simple variable substitution - text and variable +--> + +<window title="XUL Template Tests" width="500" height="600" + onload="test_template();" + xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"> + <script type="application/javascript" + src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script> + + <body xmlns="http://www.w3.org/1999/xhtml" style="height: 300px; overflow: auto;"/> + + <data id="output"> + <label step="-1" id="http://www.some-fictitious-zoo.com/arachnids/tarantula" value="Name is Tarantula the Spider"/> + <label step="1" id="http://www.some-fictitious-zoo.com/arachnids/tarantula" value="Name is Hairy Spider the Spider"/> + </data> + +<script src="templates_shared.js"/> + +<script> +<![CDATA[ +SimpleTest.waitForExplicitFinish(); + +var testid ="simple variable substitution - text and variable"; +var queryType = "rdf"; +var isTreeBuilder = false; +var needsOpen = false; +var notWorkingYet = false; +var notWorkingYetDynamic = false; +var expectedOutput = document.getElementById("output"); + +var changes = [ + // step 1 + function(targetds, root) { + var subject = RDF.GetResource(ZOO_NS + 'arachnids/tarantula'); + var predicate = RDF.GetResource(ZOO_NS + 'rdf#name'); + var oldval = targetds.GetTarget(subject, predicate, true); + targetds.Change(RDF.GetResource(ZOO_NS + 'arachnids/tarantula'), + RDF.GetResource(ZOO_NS + 'rdf#name'), + oldval, RDF.GetLiteral('Hairy Spider')); + } +]; +]]> +</script> + +<vbox xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul" id="root" datasources="rdf:null" ref="http://www.some-fictitious-zoo.com/arachnids"> +<template id="template"> +<label uri="rdf:*" value="Name is rdf:http://www.some-fictitious-zoo.com/rdf#name the Spider"/> +</template> +</vbox> + +</window> diff --git a/dom/xul/templates/tests/chrome/test_tmpl_simplevariablesubstitutionvariableandtextconcatenated.xul b/dom/xul/templates/tests/chrome/test_tmpl_simplevariablesubstitutionvariableandtextconcatenated.xul new file mode 100644 index 000000000..41df3d4d8 --- /dev/null +++ b/dom/xul/templates/tests/chrome/test_tmpl_simplevariablesubstitutionvariableandtextconcatenated.xul @@ -0,0 +1,45 @@ +<?xml version="1.0"?> +<?xml-stylesheet href="chrome://global/skin" type="text/css"?> +<?xml-stylesheet href="chrome://mochikit/content/tests/SimpleTest/test.css" type="text/css"?> + +<!-- + simple variable substitution - variable and text concatenated +--> + +<window title="XUL Template Tests" width="500" height="600" + onload="test_template();" + xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"> + <script type="application/javascript" + src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script> + + <body xmlns="http://www.w3.org/1999/xhtml" style="height: 300px; overflow: auto;"/> + + <data id="output"> + <label id="http://www.some-fictitious-zoo.com/arachnids/tarantula" value="The Tarantula's Nest"/> + </data> + +<script src="templates_shared.js"/> + +<script> +<![CDATA[ +SimpleTest.waitForExplicitFinish(); + +var testid ="simple variable substitution - variable and text concatenated"; +var queryType = "rdf"; +var isTreeBuilder = false; +var needsOpen = false; +var notWorkingYet = false; +var notWorkingYetDynamic = false; +var expectedOutput = document.getElementById("output"); + +var changes = []; +]]> +</script> + +<vbox xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul" id="root" datasources="rdf:null" ref="http://www.some-fictitious-zoo.com/arachnids"> +<template id="template"> +<label uri="rdf:*" value="The rdf:http://www.some-fictitious-zoo.com/rdf#name^'s Nest"/> +</template> +</vbox> + +</window> diff --git a/dom/xul/templates/tests/chrome/test_tmpl_simplevariablesubstitutionvariablesconcatenated.xul b/dom/xul/templates/tests/chrome/test_tmpl_simplevariablesubstitutionvariablesconcatenated.xul new file mode 100644 index 000000000..b8864c3b3 --- /dev/null +++ b/dom/xul/templates/tests/chrome/test_tmpl_simplevariablesubstitutionvariablesconcatenated.xul @@ -0,0 +1,45 @@ +<?xml version="1.0"?> +<?xml-stylesheet href="chrome://global/skin" type="text/css"?> +<?xml-stylesheet href="chrome://mochikit/content/tests/SimpleTest/test.css" type="text/css"?> + +<!-- + simple variable substitution - variables concatenated +--> + +<window title="XUL Template Tests" width="500" height="600" + onload="test_template();" + xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"> + <script type="application/javascript" + src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script> + + <body xmlns="http://www.w3.org/1999/xhtml" style="height: 300px; overflow: auto;"/> + + <data id="output"> + <label id="http://www.some-fictitious-zoo.com/arachnids/tarantula" value="Tarantula3"/> + </data> + +<script src="templates_shared.js"/> + +<script> +<![CDATA[ +SimpleTest.waitForExplicitFinish(); + +var testid ="simple variable substitution - variables concatenated"; +var queryType = "rdf"; +var isTreeBuilder = false; +var needsOpen = false; +var notWorkingYet = false; +var notWorkingYetDynamic = false; +var expectedOutput = document.getElementById("output"); + +var changes = []; +]]> +</script> + +<vbox xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul" id="root" datasources="rdf:null" ref="http://www.some-fictitious-zoo.com/arachnids"> +<template id="template"> +<label uri="rdf:*" value="rdf:http://www.some-fictitious-zoo.com/rdf#name^rdf:http://www.some-fictitious-zoo.com/rdf#specimens"/> +</template> +</vbox> + +</window> diff --git a/dom/xul/templates/tests/chrome/test_tmpl_sortascendinginteger.xul b/dom/xul/templates/tests/chrome/test_tmpl_sortascendinginteger.xul new file mode 100644 index 000000000..2d30ced27 --- /dev/null +++ b/dom/xul/templates/tests/chrome/test_tmpl_sortascendinginteger.xul @@ -0,0 +1,70 @@ +<?xml version="1.0"?> +<?xml-stylesheet href="chrome://global/skin" type="text/css"?> +<?xml-stylesheet href="chrome://mochikit/content/tests/SimpleTest/test.css" type="text/css"?> + +<!-- + sort ascending - integers +--> + +<window title="XUL Template Tests" width="500" height="600" + onload="test_template();" + xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"> + <script type="application/javascript" + src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script> + + <body xmlns="http://www.w3.org/1999/xhtml" style="height: 300px; overflow: auto;"/> + + <data id="output"> + <label id="http://www.some-fictitious-zoo.com/mammals/ninebandedarmadillo" value="Nine-banded Armadillo"/> + <label id="http://www.some-fictitious-zoo.com/mammals/aardvark" value="aardvark"/> + <label id="http://www.some-fictitious-zoo.com/mammals/hippopotamus" value="HIPPOPOTAMUS"/> + <label id="http://www.some-fictitious-zoo.com/mammals/lion" value="Lion"/> + <label step="-1" id="http://www.some-fictitious-zoo.com/mammals/llama" value="LLAMA"/> + <label id="http://www.some-fictitious-zoo.com/mammals/gorilla" value="Gorilla"/> + <label step="1" id="http://www.some-fictitious-zoo.com/mammals/llama" value="LLAMA"/> + <label id="http://www.some-fictitious-zoo.com/mammals/africanelephant" value="African Elephant"/> + <label id="http://www.some-fictitious-zoo.com/mammals/polarbear" value="Polar Bear"/> + </data> + +<script src="templates_shared.js"/> + +<script> +<![CDATA[ +SimpleTest.waitForExplicitFinish(); + +var testid ="sort ascending - integers"; +var queryType = "rdf"; +var isTreeBuilder = false; +var needsOpen = false; +var notWorkingYet = false; +var notWorkingYetDynamic = false; +var expectedOutput = document.getElementById("output"); + +var changes = [ + // step 1 + function(targetds, root) { + var subject = RDF.GetResource(ZOO_NS + 'mammals/llama'); + var predicate = RDF.GetResource(ZOO_NS + 'rdf#specimensAsString'); + var oldval = targetds.GetTarget(subject, predicate, true); + targetds.Change(subject, predicate, oldval, RDF.GetLiteral('12'), true); + } +]; +]]> +</script> + +<vbox xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul" id="root" datasources="rdf:null" + ref="http://www.some-fictitious-zoo.com/mammals" sort="?specimens ?name" sortDirection="ascending" sorthints="integer"> +<template id="template"> +<query id="query"> +<content uri="?uri"/> +<member container="?uri" child="?animal"/> +<triple subject="?animal" predicate="http://www.some-fictitious-zoo.com/rdf#name" object="?name"/> +<triple subject="?animal" predicate="http://www.some-fictitious-zoo.com/rdf#specimensAsString" object="?specimens"/> +</query> +<action id="action"> +<label uri="?animal" value="?name"/> +</action> +</template> +</vbox> + +</window> diff --git a/dom/xul/templates/tests/chrome/test_tmpl_sortascendingquerysyntax.xul b/dom/xul/templates/tests/chrome/test_tmpl_sortascendingquerysyntax.xul new file mode 100644 index 000000000..5f90a8334 --- /dev/null +++ b/dom/xul/templates/tests/chrome/test_tmpl_sortascendingquerysyntax.xul @@ -0,0 +1,114 @@ +<?xml version="1.0"?> +<?xml-stylesheet href="chrome://global/skin" type="text/css"?> +<?xml-stylesheet href="chrome://mochikit/content/tests/SimpleTest/test.css" type="text/css"?> + +<!-- + sort ascending - query syntax +--> + +<window title="XUL Template Tests" width="500" height="600" + onload="test_template();" + xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"> + <script type="application/javascript" + src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script> + + <body xmlns="http://www.w3.org/1999/xhtml" style="height: 300px; overflow: auto;"/> + + <data id="output"> + <label id="http://www.some-fictitious-zoo.com/mammals/aardvark" value="aardvark"/> + <label step="-4" id="http://www.some-fictitious-zoo.com/mammals/africanelephant" value="African Elephant"/> + <label step="5" id="http://www.some-fictitious-zoo.com/mammals/africanelephant" value="African Elephant"/> + <label step="1" id="http://www.some-fictitious-zoo.com/mammals/arctichare" value="Arctic Hare"/> + <label id="http://www.some-fictitious-zoo.com/mammals/gorilla" value="Gorilla"/> + <label id="http://www.some-fictitious-zoo.com/mammals/hippopotamus" value="HIPPOPOTAMUS"/> + <label step="2" id="http://www.some-fictitious-zoo.com/mammals/koala" value="Koala"/> + <label id="http://www.some-fictitious-zoo.com/mammals/lion" value="Lion"/> + <label id="http://www.some-fictitious-zoo.com/mammals/llama" value="LLAMA"/> + <label id="http://www.some-fictitious-zoo.com/mammals/ninebandedarmadillo" value="Nine-banded Armadillo"/> + <label id="http://www.some-fictitious-zoo.com/mammals/polarbear" value="Polar Bear"/> + <label step="3" id="http://www.some-fictitious-zoo.com/mammals/zebra" value="Zebra"/> + </data> + +<script src="templates_shared.js"/> + +<script> +<![CDATA[ +SimpleTest.waitForExplicitFinish(); + +var testid ="sort ascending - query syntax"; +var queryType = "rdf"; +var isTreeBuilder = false; +var needsOpen = false; +var notWorkingYet = false; +var notWorkingYetDynamic = false; +var expectedOutput = document.getElementById("output"); + +var changes = [ + // step 1 + function(targetds, root) { + var newnode = RDF.GetResource(ZOO_NS + 'mammals/arctichare'); + targetds.Assert(newnode, RDF.GetResource(ZOO_NS + 'rdf#name'), + RDF.GetLiteral('Arctic Hare'), true); + var container = ContainerUtils.MakeSeq(targetds, + RDF.GetResource(ZOO_NS + 'mammals')); + container.AppendElement(newnode); + }, + // step 2 + function(targetds, root) { + var newnode = RDF.GetResource(ZOO_NS + 'mammals/koala'); + targetds.Assert(newnode, RDF.GetResource(ZOO_NS + 'rdf#name'), + RDF.GetLiteral('Koala'), true); + var container = ContainerUtils.MakeSeq(targetds, + RDF.GetResource(ZOO_NS + 'mammals')); + container.InsertElementAt(newnode, '4', true); + }, + // step 3 + function(targetds, root) { + var newnode = RDF.GetResource(ZOO_NS + 'mammals/zebra'); + targetds.Assert(newnode, RDF.GetResource(ZOO_NS + 'rdf#name'), + RDF.GetLiteral('Zebra'), true); + var container = ContainerUtils.MakeSeq(targetds, + RDF.GetResource(ZOO_NS + 'mammals')); + container.InsertElementAt(newnode, '1', true); + }, + // step 4 + function(targetds, root) { + var container = ContainerUtils.MakeSeq(targetds, + RDF.GetResource(ZOO_NS + 'mammals')); + var removednode = container.RemoveElementAt('4', true); + targetds.Unassert(removednode, RDF.GetResource(ZOO_NS + 'rdf#name'), + RDF.GetLiteral('African Elephant'), true); + }, + // step 5 + function(targetds, root) { + var newnode = RDF.GetResource(ZOO_NS + 'mammals/africanelephant'); + targetds.Assert(newnode, RDF.GetResource(ZOO_NS + 'rdf#name'), + RDF.GetLiteral('African Elephant'), true); + var container = ContainerUtils.MakeSeq(targetds, + RDF.GetResource(ZOO_NS + 'mammals')); + container.AppendElement(newnode); + }, + // step 6 + function(targetds, root) { + targetds.Assert(RDF.GetResource(ZOO_NS + 'mammals/koala'), + RDF.GetResource(ZOO_NS + 'rdf#specimensAsString'), + RDF.GetLiteral('8'), true); + } +]; +]]> +</script> + +<vbox xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul" id="root" datasources="rdf:null" ref="http://www.some-fictitious-zoo.com/mammals" sort="?name" sortDirection="ascending"> +<template id="template"> +<query id="query"> +<content uri="?uri"/> +<member container="?uri" child="?animal"/> +<triple subject="?animal" predicate="http://www.some-fictitious-zoo.com/rdf#name" object="?name"/> +</query> +<action id="action"> +<label uri="?animal" value="?name"/> +</action> +</template> +</vbox> + +</window> diff --git a/dom/xul/templates/tests/chrome/test_tmpl_sortascendingtworulesquerysyntax.xul b/dom/xul/templates/tests/chrome/test_tmpl_sortascendingtworulesquerysyntax.xul new file mode 100644 index 000000000..612a50fc6 --- /dev/null +++ b/dom/xul/templates/tests/chrome/test_tmpl_sortascendingtworulesquerysyntax.xul @@ -0,0 +1,70 @@ +<?xml version="1.0"?> +<?xml-stylesheet href="chrome://global/skin" type="text/css"?> +<?xml-stylesheet href="chrome://mochikit/content/tests/SimpleTest/test.css" type="text/css"?> + +<!-- + sort ascending two rules - query syntax +--> + +<window title="XUL Template Tests" width="500" height="600" + onload="test_template();" + xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"> + <script type="application/javascript" + src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script> + + <body xmlns="http://www.w3.org/1999/xhtml" style="height: 300px; overflow: auto;"/> + + <data id="output"> + <label id="http://www.some-fictitious-zoo.com/mammals/ninebandedarmadillo" value="Nine-banded Armadillo"/> + <button id="http://www.some-fictitious-zoo.com/mammals/aardvark" label="aardvark"/> + <button id="http://www.some-fictitious-zoo.com/mammals/hippopotamus" label="HIPPOPOTAMUS"/> + <label id="http://www.some-fictitious-zoo.com/mammals/lion" value="Lion"/> + <button id="http://www.some-fictitious-zoo.com/mammals/llama" label="LLAMA"/> + <label id="http://www.some-fictitious-zoo.com/mammals/gorilla" value="Gorilla"/> + <button id="http://www.some-fictitious-zoo.com/mammals/africanelephant" label="African Elephant"/> + <label id="http://www.some-fictitious-zoo.com/mammals/polarbear" value="Polar Bear"/> + </data> + +<script src="templates_shared.js"/> + +<script> +<![CDATA[ +SimpleTest.waitForExplicitFinish(); + +var testid ="sort ascending two rules - query syntax"; +var queryType = "rdf"; +var isTreeBuilder = false; +var needsOpen = false; +var notWorkingYet = false; +var notWorkingYetDynamic = false; +var expectedOutput = document.getElementById("output"); + +var changes = []; +]]> +</script> + +<vbox xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul" id="root" datasources="rdf:null" ref="http://www.some-fictitious-zoo.com/mammals" sortDirection="ascending" sort="?specimens ?name" sortResource="http://www.some-fictitious-zoo.com/rdf#specimens" sortResource2="http://www.some-fictitious-zoo.com/rdf#name"> +<template id="template"> +<query id="query"> +<content uri="?uri"/> +<member container="?uri" child="?animal"/> +<triple subject="?animal" predicate="http://www.some-fictitious-zoo.com/rdf#name" object="?name"/> +<triple subject="?animal" predicate="http://www.some-fictitious-zoo.com/rdf#specimens" object="?specimens"/> +</query> +<rule> +<conditions> +<where subject="?name" rel="contains" value="o"/> +</conditions> +<action id="action"> +<label uri="?animal" value="?name"/> +</action> +</rule> +<rule> +<action> +<button uri="?animal" label="?name"/> +</action> +</rule> +</template> +</vbox> + +</window> diff --git a/dom/xul/templates/tests/chrome/test_tmpl_sortascendingtworuleswithcontainerquerysyntax.xul b/dom/xul/templates/tests/chrome/test_tmpl_sortascendingtworuleswithcontainerquerysyntax.xul new file mode 100644 index 000000000..e3fb2e37b --- /dev/null +++ b/dom/xul/templates/tests/chrome/test_tmpl_sortascendingtworuleswithcontainerquerysyntax.xul @@ -0,0 +1,80 @@ +<?xml version="1.0"?> +<?xml-stylesheet href="chrome://global/skin" type="text/css"?> +<?xml-stylesheet href="chrome://mochikit/content/tests/SimpleTest/test.css" type="text/css"?> + +<!-- + sort ascending two rules with container - query syntax +--> + +<window title="XUL Template Tests" width="500" height="600" + onload="test_template();" + xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"> + <script type="application/javascript" + src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script> + + <body xmlns="http://www.w3.org/1999/xhtml" style="height: 300px; overflow: auto;"/> + + <data id="output"> + <hbox id="http://www.some-fictitious-zoo.com/mammals/ninebandedarmadillo"> + <label value="Nine-banded Armadillo"/> + </hbox> + <button id="http://www.some-fictitious-zoo.com/mammals/aardvark" label="aardvark"/> + <button id="http://www.some-fictitious-zoo.com/mammals/hippopotamus" label="HIPPOPOTAMUS"/> + <hbox id="http://www.some-fictitious-zoo.com/mammals/lion"> + <label value="Lion"/> + </hbox> + <button id="http://www.some-fictitious-zoo.com/mammals/llama" label="LLAMA"/> + <hbox id="http://www.some-fictitious-zoo.com/mammals/gorilla"> + <label value="Gorilla"/> + </hbox> + <button id="http://www.some-fictitious-zoo.com/mammals/africanelephant" label="African Elephant"/> + <hbox id="http://www.some-fictitious-zoo.com/mammals/polarbear"> + <label value="Polar Bear"/> + </hbox> + </data> + +<script src="templates_shared.js"/> + +<script> +<![CDATA[ +SimpleTest.waitForExplicitFinish(); + +var testid ="sort ascending two rules with container - query syntax"; +var queryType = "rdf"; +var isTreeBuilder = false; +var needsOpen = false; +var notWorkingYet = false; +var notWorkingYetDynamic = false; +var expectedOutput = document.getElementById("output"); + +var changes = []; +]]> +</script> + +<vbox xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul" id="root" datasources="rdf:null" ref="http://www.some-fictitious-zoo.com/mammals" sortDirection="ascending" sort="?specimens ?name" sortResource="http://www.some-fictitious-zoo.com/rdf#specimens" sortResource2="http://www.some-fictitious-zoo.com/rdf#name"> +<template id="template"> +<query id="query"> +<content uri="?uri"/> +<member container="?uri" child="?animal"/> +<triple subject="?animal" predicate="http://www.some-fictitious-zoo.com/rdf#name" object="?name"/> +<triple subject="?animal" predicate="http://www.some-fictitious-zoo.com/rdf#specimens" object="?specimens"/> +</query> +<rule> +<conditions> +<where subject="?name" rel="contains" value="o"/> +</conditions> +<action id="action"> +<hbox uri="?animal"> +<label value="?name"/> +</hbox> +</action> +</rule> +<rule> +<action> +<button uri="?animal" label="?name"/> +</action> +</rule> +</template> +</vbox> + +</window> diff --git a/dom/xul/templates/tests/chrome/test_tmpl_sortascendingtworuleswithdifferentcontainerquerysyntax.xul b/dom/xul/templates/tests/chrome/test_tmpl_sortascendingtworuleswithdifferentcontainerquerysyntax.xul new file mode 100644 index 000000000..fdab29054 --- /dev/null +++ b/dom/xul/templates/tests/chrome/test_tmpl_sortascendingtworuleswithdifferentcontainerquerysyntax.xul @@ -0,0 +1,84 @@ +<?xml version="1.0"?> +<?xml-stylesheet href="chrome://global/skin" type="text/css"?> +<?xml-stylesheet href="chrome://mochikit/content/tests/SimpleTest/test.css" type="text/css"?> + +<!-- + sort ascending two rules with different container - query syntax +--> + +<window title="XUL Template Tests" width="500" height="600" + onload="test_template();" + xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"> + <script type="application/javascript" + src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script> + + <body xmlns="http://www.w3.org/1999/xhtml" style="height: 300px; overflow: auto;"/> + + <data id="output"> + <vbox> + <hbox id="http://www.some-fictitious-zoo.com/mammals/ninebandedarmadillo"> + <label value="Nine-banded Armadillo"/> + </hbox> + <hbox id="http://www.some-fictitious-zoo.com/mammals/lion"> + <label value="Lion"/> + </hbox> + <hbox id="http://www.some-fictitious-zoo.com/mammals/gorilla"> + <label value="Gorilla"/> + </hbox> + <hbox id="http://www.some-fictitious-zoo.com/mammals/polarbear"> + <label value="Polar Bear"/> + </hbox> + </vbox> + <button id="http://www.some-fictitious-zoo.com/mammals/aardvark" label="aardvark"/> + <button id="http://www.some-fictitious-zoo.com/mammals/hippopotamus" label="HIPPOPOTAMUS"/> + <button id="http://www.some-fictitious-zoo.com/mammals/llama" label="LLAMA"/> + <button id="http://www.some-fictitious-zoo.com/mammals/africanelephant" label="African Elephant"/> + </data> + +<script src="templates_shared.js"/> + +<script> +<![CDATA[ +SimpleTest.waitForExplicitFinish(); + +var testid ="sort ascending two rules with different container - query syntax"; +var queryType = "rdf"; +var isTreeBuilder = false; +var needsOpen = false; +var notWorkingYet = false; +var notWorkingYetDynamic = false; +var expectedOutput = document.getElementById("output"); + +var changes = []; +]]> +</script> + +<vbox xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul" id="root" datasources="rdf:null" ref="http://www.some-fictitious-zoo.com/mammals" sortDirection="ascending" sort="?specimens ?name" sortResource="http://www.some-fictitious-zoo.com/rdf#specimens" sortResource2="http://www.some-fictitious-zoo.com/rdf#name"> +<template id="template"> +<query id="query"> +<content uri="?uri"/> +<member container="?uri" child="?animal"/> +<triple subject="?animal" predicate="http://www.some-fictitious-zoo.com/rdf#name" object="?name"/> +<triple subject="?animal" predicate="http://www.some-fictitious-zoo.com/rdf#specimens" object="?specimens"/> +</query> +<rule> +<conditions> +<where subject="?name" rel="contains" value="o"/> +</conditions> +<action id="action"> +<vbox> +<hbox uri="?animal"> +<label value="?name"/> +</hbox> +</vbox> +</action> +</rule> +<rule> +<action> +<button uri="?animal" label="?name"/> +</action> +</rule> +</template> +</vbox> + +</window> diff --git a/dom/xul/templates/tests/chrome/test_tmpl_sortdescendingquerysyntax.xul b/dom/xul/templates/tests/chrome/test_tmpl_sortdescendingquerysyntax.xul new file mode 100644 index 000000000..1979fdb98 --- /dev/null +++ b/dom/xul/templates/tests/chrome/test_tmpl_sortdescendingquerysyntax.xul @@ -0,0 +1,114 @@ +<?xml version="1.0"?> +<?xml-stylesheet href="chrome://global/skin" type="text/css"?> +<?xml-stylesheet href="chrome://mochikit/content/tests/SimpleTest/test.css" type="text/css"?> + +<!-- + sort descending - query syntax +--> + +<window title="XUL Template Tests" width="500" height="600" + onload="test_template();" + xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"> + <script type="application/javascript" + src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script> + + <body xmlns="http://www.w3.org/1999/xhtml" style="height: 300px; overflow: auto;"/> + + <data id="output"> + <label step="3" id="http://www.some-fictitious-zoo.com/mammals/zebra" value="Zebra"/> + <label id="http://www.some-fictitious-zoo.com/mammals/polarbear" value="Polar Bear"/> + <label id="http://www.some-fictitious-zoo.com/mammals/ninebandedarmadillo" value="Nine-banded Armadillo"/> + <label id="http://www.some-fictitious-zoo.com/mammals/llama" value="LLAMA"/> + <label id="http://www.some-fictitious-zoo.com/mammals/lion" value="Lion"/> + <label step="2" id="http://www.some-fictitious-zoo.com/mammals/koala" value="Koala"/> + <label id="http://www.some-fictitious-zoo.com/mammals/hippopotamus" value="HIPPOPOTAMUS"/> + <label id="http://www.some-fictitious-zoo.com/mammals/gorilla" value="Gorilla"/> + <label step="1" id="http://www.some-fictitious-zoo.com/mammals/arctichare" value="Arctic Hare"/> + <label step="5" id="http://www.some-fictitious-zoo.com/mammals/africanelephant" value="African Elephant"/> + <label step="-4" id="http://www.some-fictitious-zoo.com/mammals/africanelephant" value="African Elephant"/> + <label id="http://www.some-fictitious-zoo.com/mammals/aardvark" value="aardvark"/> + </data> + +<script src="templates_shared.js"/> + +<script> +<![CDATA[ +SimpleTest.waitForExplicitFinish(); + +var testid ="sort descending - query syntax"; +var queryType = "rdf"; +var isTreeBuilder = false; +var needsOpen = false; +var notWorkingYet = false; +var notWorkingYetDynamic = false; +var expectedOutput = document.getElementById("output"); + +var changes = [ + // step 1 + function(targetds, root) { + var newnode = RDF.GetResource(ZOO_NS + 'mammals/arctichare'); + targetds.Assert(newnode, RDF.GetResource(ZOO_NS + 'rdf#name'), + RDF.GetLiteral('Arctic Hare'), true); + var container = ContainerUtils.MakeSeq(targetds, + RDF.GetResource(ZOO_NS + 'mammals')); + container.AppendElement(newnode); + }, + // step 2 + function(targetds, root) { + var newnode = RDF.GetResource(ZOO_NS + 'mammals/koala'); + targetds.Assert(newnode, RDF.GetResource(ZOO_NS + 'rdf#name'), + RDF.GetLiteral('Koala'), true); + var container = ContainerUtils.MakeSeq(targetds, + RDF.GetResource(ZOO_NS + 'mammals')); + container.InsertElementAt(newnode, '4', true); + }, + // step 3 + function(targetds, root) { + var newnode = RDF.GetResource(ZOO_NS + 'mammals/zebra'); + targetds.Assert(newnode, RDF.GetResource(ZOO_NS + 'rdf#name'), + RDF.GetLiteral('Zebra'), true); + var container = ContainerUtils.MakeSeq(targetds, + RDF.GetResource(ZOO_NS + 'mammals')); + container.InsertElementAt(newnode, '1', true); + }, + // step 4 + function(targetds, root) { + var container = ContainerUtils.MakeSeq(targetds, + RDF.GetResource(ZOO_NS + 'mammals')); + var removednode = container.RemoveElementAt('4', true); + targetds.Unassert(removednode, RDF.GetResource(ZOO_NS + 'rdf#name'), + RDF.GetLiteral('African Elephant'), true); + }, + // step 5 + function(targetds, root) { + var newnode = RDF.GetResource(ZOO_NS + 'mammals/africanelephant'); + targetds.Assert(newnode, RDF.GetResource(ZOO_NS + 'rdf#name'), + RDF.GetLiteral('African Elephant'), true); + var container = ContainerUtils.MakeSeq(targetds, + RDF.GetResource(ZOO_NS + 'mammals')); + container.AppendElement(newnode); + }, + // step 6 + function(targetds, root) { + targetds.Assert(RDF.GetResource(ZOO_NS + 'mammals/koala'), + RDF.GetResource(ZOO_NS + 'rdf#specimensAsString'), + RDF.GetLiteral('8'), true); + } +]; +]]> +</script> + +<vbox xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul" id="root" datasources="rdf:null" ref="http://www.some-fictitious-zoo.com/mammals" sort="?name" sortDirection="descending"> +<template id="template"> +<query id="query"> +<content uri="?uri"/> +<member container="?uri" child="?animal"/> +<triple subject="?animal" predicate="http://www.some-fictitious-zoo.com/rdf#name" object="?name"/> +</query> +<action id="action"> +<label uri="?animal" value="?name"/> +</action> +</template> +</vbox> + +</window> diff --git a/dom/xul/templates/tests/chrome/test_tmpl_sortquerymemberandtwotriples.xul b/dom/xul/templates/tests/chrome/test_tmpl_sortquerymemberandtwotriples.xul new file mode 100644 index 000000000..8176553e4 --- /dev/null +++ b/dom/xul/templates/tests/chrome/test_tmpl_sortquerymemberandtwotriples.xul @@ -0,0 +1,58 @@ +<?xml version="1.0"?> +<?xml-stylesheet href="chrome://global/skin" type="text/css"?> +<?xml-stylesheet href="chrome://mochikit/content/tests/SimpleTest/test.css" type="text/css"?> + +<!-- + sort query - member and two triples +--> + +<window title="XUL Template Tests" width="500" height="600" + onload="test_template();" + xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"> + <script type="application/javascript" + src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script> + + <body xmlns="http://www.w3.org/1999/xhtml" style="height: 300px; overflow: auto;"/> + + <data id="output"> + <label id="http://www.some-fictitious-zoo.com/mammals/africanelephant" value="African Elephant"/> + <label id="http://www.some-fictitious-zoo.com/reptiles/anaconda" value="Anaconda"/> + <label id="http://www.some-fictitious-zoo.com/reptiles/chameleon" value="Chameleon"/> + <label id="http://www.some-fictitious-zoo.com/birds/emu" value="Emu"/> + <label id="http://www.some-fictitious-zoo.com/mammals/polarbear" value="Polar Bear"/> + <label id="http://www.some-fictitious-zoo.com/arachnids/tarantula" value="Tarantula"/> + </data> + +<script src="templates_shared.js"/> + +<script> +<![CDATA[ +SimpleTest.waitForExplicitFinish(); + +var testid ="sort query - member and two triples"; +var queryType = "rdf"; +var isTreeBuilder = false; +var needsOpen = false; +var notWorkingYet = false; +var notWorkingYetDynamic = false; +var expectedOutput = document.getElementById("output"); + +var changes = []; +]]> +</script> + +<vbox xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul" id="root" datasources="rdf:null" ref="http://www.some-fictitious-zoo.com/humans" sortDirection="ascending" sort="?name" sortResource="http://www.some-fictitious-zoo.com/rdf#specimens" sortResource2="http://www.some-fictitious-zoo.com/rdf#name"> +<template id="template"> +<query id="query"> +<content uri="?uri"/> +<member container="?uri" child="?human"/> +<triple subject="?human" predicate="http://www.some-fictitious-zoo.com/rdf#favoriteAnimal" object="?child"/> +<triple subject="?child" predicate="http://www.some-fictitious-zoo.com/rdf#name" object="?name"/> +</query> +<action> +<label uri="?child" value="?name"/> +</action> +</template> +</vbox> + +</window> diff --git a/dom/xul/templates/tests/chrome/test_tmpl_sortresource2descendingsimplesyntax.xul b/dom/xul/templates/tests/chrome/test_tmpl_sortresource2descendingsimplesyntax.xul new file mode 100644 index 000000000..d328d81b2 --- /dev/null +++ b/dom/xul/templates/tests/chrome/test_tmpl_sortresource2descendingsimplesyntax.xul @@ -0,0 +1,52 @@ +<?xml version="1.0"?> +<?xml-stylesheet href="chrome://global/skin" type="text/css"?> +<?xml-stylesheet href="chrome://mochikit/content/tests/SimpleTest/test.css" type="text/css"?> + +<!-- + sortResource2 descending - simple syntax +--> + +<window title="XUL Template Tests" width="500" height="600" + onload="test_template();" + xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"> + <script type="application/javascript" + src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script> + + <body xmlns="http://www.w3.org/1999/xhtml" style="height: 300px; overflow: auto;"/> + + <data id="output"> + <label id="http://www.some-fictitious-zoo.com/mammals/polarbear" value="Polar Bear"/> + <label id="http://www.some-fictitious-zoo.com/mammals/africanelephant" value="African Elephant"/> + <label id="http://www.some-fictitious-zoo.com/mammals/gorilla" value="Gorilla"/> + <label id="http://www.some-fictitious-zoo.com/mammals/llama" value="LLAMA"/> + <label id="http://www.some-fictitious-zoo.com/mammals/lion" value="Lion"/> + <label id="http://www.some-fictitious-zoo.com/mammals/hippopotamus" value="HIPPOPOTAMUS"/> + <label id="http://www.some-fictitious-zoo.com/mammals/aardvark" value="aardvark"/> + <label id="http://www.some-fictitious-zoo.com/mammals/ninebandedarmadillo" value="Nine-banded Armadillo"/> + </data> + +<script src="templates_shared.js"/> + +<script> +<![CDATA[ +SimpleTest.waitForExplicitFinish(); + +var testid ="sortResource2 descending - simple syntax"; +var queryType = "rdf"; +var isTreeBuilder = false; +var needsOpen = false; +var notWorkingYet = false; +var notWorkingYetDynamic = false; +var expectedOutput = document.getElementById("output"); + +var changes = []; +]]> +</script> + +<vbox xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul" id="root" datasources="rdf:null" ref="http://www.some-fictitious-zoo.com/mammals" sortDirection="descending" sort="http://www.some-fictitious-zoo.com/rdf#specimens http://www.some-fictitious-zoo.com/rdf#name" sortResource="http://www.some-fictitious-zoo.com/rdf#specimens" sortResource2="http://www.some-fictitious-zoo.com/rdf#name"> +<template id="template"> +<label uri="rdf:*" value="rdf:http://www.some-fictitious-zoo.com/rdf#name"/> +</template> +</vbox> + +</window> diff --git a/dom/xul/templates/tests/chrome/test_tmpl_sortresource2settopredicateascendingquerysyntax.xul b/dom/xul/templates/tests/chrome/test_tmpl_sortresource2settopredicateascendingquerysyntax.xul new file mode 100644 index 000000000..653584c52 --- /dev/null +++ b/dom/xul/templates/tests/chrome/test_tmpl_sortresource2settopredicateascendingquerysyntax.xul @@ -0,0 +1,59 @@ +<?xml version="1.0"?> +<?xml-stylesheet href="chrome://global/skin" type="text/css"?> +<?xml-stylesheet href="chrome://mochikit/content/tests/SimpleTest/test.css" type="text/css"?> + +<!-- + sortResource2 set to predicate ascending - query syntax +--> + +<window title="XUL Template Tests" width="500" height="600" + onload="test_template();" + xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"> + <script type="application/javascript" + src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script> + + <body xmlns="http://www.w3.org/1999/xhtml" style="height: 300px; overflow: auto;"/> + + <data id="output"> + <label id="http://www.some-fictitious-zoo.com/mammals/ninebandedarmadillo" value="Nine-banded Armadillo"/> + <label id="http://www.some-fictitious-zoo.com/mammals/aardvark" value="aardvark"/> + <label id="http://www.some-fictitious-zoo.com/mammals/hippopotamus" value="HIPPOPOTAMUS"/> + <label id="http://www.some-fictitious-zoo.com/mammals/lion" value="Lion"/> + <label id="http://www.some-fictitious-zoo.com/mammals/llama" value="LLAMA"/> + <label id="http://www.some-fictitious-zoo.com/mammals/gorilla" value="Gorilla"/> + <label id="http://www.some-fictitious-zoo.com/mammals/africanelephant" value="African Elephant"/> + <label id="http://www.some-fictitious-zoo.com/mammals/polarbear" value="Polar Bear"/> + </data> + +<script src="templates_shared.js"/> + +<script> +<![CDATA[ +SimpleTest.waitForExplicitFinish(); + +var testid ="sortResource2 set to predicate ascending - query syntax"; +var queryType = "rdf"; +var isTreeBuilder = false; +var needsOpen = false; +var notWorkingYet = false; +var notWorkingYetDynamic = false; +var expectedOutput = document.getElementById("output"); + +var changes = []; +]]> +</script> + +<vbox xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul" id="root" datasources="rdf:null" ref="http://www.some-fictitious-zoo.com/mammals" sortResource="http://www.some-fictitious-zoo.com/rdf#specimens" sortDirection="ascending" sortResource2="http://www.some-fictitious-zoo.com/rdf#name"> +<template id="template"> +<query id="query"> +<content uri="?uri"/> +<member container="?uri" child="?animal"/> +<triple subject="?animal" predicate="http://www.some-fictitious-zoo.com/rdf#name" object="?name"/> +</query> +<action id="action"> +<label uri="?animal" value="?name"/> +</action> +</template> +</vbox> + +</window> diff --git a/dom/xul/templates/tests/chrome/test_tmpl_sortresource2settopredicatedescendingquerysyntax.xul b/dom/xul/templates/tests/chrome/test_tmpl_sortresource2settopredicatedescendingquerysyntax.xul new file mode 100644 index 000000000..8fcb569a7 --- /dev/null +++ b/dom/xul/templates/tests/chrome/test_tmpl_sortresource2settopredicatedescendingquerysyntax.xul @@ -0,0 +1,59 @@ +<?xml version="1.0"?> +<?xml-stylesheet href="chrome://global/skin" type="text/css"?> +<?xml-stylesheet href="chrome://mochikit/content/tests/SimpleTest/test.css" type="text/css"?> + +<!-- + sortResource2 set to predicate descending - query syntax +--> + +<window title="XUL Template Tests" width="500" height="600" + onload="test_template();" + xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"> + <script type="application/javascript" + src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script> + + <body xmlns="http://www.w3.org/1999/xhtml" style="height: 300px; overflow: auto;"/> + + <data id="output"> + <label id="http://www.some-fictitious-zoo.com/mammals/polarbear" value="Polar Bear"/> + <label id="http://www.some-fictitious-zoo.com/mammals/africanelephant" value="African Elephant"/> + <label id="http://www.some-fictitious-zoo.com/mammals/gorilla" value="Gorilla"/> + <label id="http://www.some-fictitious-zoo.com/mammals/llama" value="LLAMA"/> + <label id="http://www.some-fictitious-zoo.com/mammals/lion" value="Lion"/> + <label id="http://www.some-fictitious-zoo.com/mammals/hippopotamus" value="HIPPOPOTAMUS"/> + <label id="http://www.some-fictitious-zoo.com/mammals/aardvark" value="aardvark"/> + <label id="http://www.some-fictitious-zoo.com/mammals/ninebandedarmadillo" value="Nine-banded Armadillo"/> + </data> + +<script src="templates_shared.js"/> + +<script> +<![CDATA[ +SimpleTest.waitForExplicitFinish(); + +var testid ="sortResource2 set to predicate descending - query syntax"; +var queryType = "rdf"; +var isTreeBuilder = false; +var needsOpen = false; +var notWorkingYet = false; +var notWorkingYetDynamic = false; +var expectedOutput = document.getElementById("output"); + +var changes = []; +]]> +</script> + +<vbox xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul" id="root" datasources="rdf:null" ref="http://www.some-fictitious-zoo.com/mammals" sortResource="http://www.some-fictitious-zoo.com/rdf#specimens" sortDirection="descending" sortResource2="http://www.some-fictitious-zoo.com/rdf#name"> +<template id="template"> +<query id="query"> +<content uri="?uri"/> +<member container="?uri" child="?animal"/> +<triple subject="?animal" predicate="http://www.some-fictitious-zoo.com/rdf#name" object="?name"/> +</query> +<action id="action"> +<label uri="?animal" value="?name"/> +</action> +</template> +</vbox> + +</window> diff --git a/dom/xul/templates/tests/chrome/test_tmpl_sortresourceascendingquerysyntax.xul b/dom/xul/templates/tests/chrome/test_tmpl_sortresourceascendingquerysyntax.xul new file mode 100644 index 000000000..346a988a5 --- /dev/null +++ b/dom/xul/templates/tests/chrome/test_tmpl_sortresourceascendingquerysyntax.xul @@ -0,0 +1,59 @@ +<?xml version="1.0"?> +<?xml-stylesheet href="chrome://global/skin" type="text/css"?> +<?xml-stylesheet href="chrome://mochikit/content/tests/SimpleTest/test.css" type="text/css"?> + +<!-- + sortResource ascending - query syntax +--> + +<window title="XUL Template Tests" width="500" height="600" + onload="test_template();" + xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"> + <script type="application/javascript" + src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script> + + <body xmlns="http://www.w3.org/1999/xhtml" style="height: 300px; overflow: auto;"/> + + <data id="output"> + <label id="http://www.some-fictitious-zoo.com/mammals/aardvark" value="aardvark"/> + <label id="http://www.some-fictitious-zoo.com/mammals/africanelephant" value="African Elephant"/> + <label id="http://www.some-fictitious-zoo.com/mammals/gorilla" value="Gorilla"/> + <label id="http://www.some-fictitious-zoo.com/mammals/hippopotamus" value="HIPPOPOTAMUS"/> + <label id="http://www.some-fictitious-zoo.com/mammals/lion" value="Lion"/> + <label id="http://www.some-fictitious-zoo.com/mammals/llama" value="LLAMA"/> + <label id="http://www.some-fictitious-zoo.com/mammals/ninebandedarmadillo" value="Nine-banded Armadillo"/> + <label id="http://www.some-fictitious-zoo.com/mammals/polarbear" value="Polar Bear"/> + </data> + +<script src="templates_shared.js"/> + +<script> +<![CDATA[ +SimpleTest.waitForExplicitFinish(); + +var testid ="sortResource ascending - query syntax"; +var queryType = "rdf"; +var isTreeBuilder = false; +var needsOpen = false; +var notWorkingYet = false; +var notWorkingYetDynamic = false; +var expectedOutput = document.getElementById("output"); + +var changes = []; +]]> +</script> + +<vbox xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul" id="root" datasources="rdf:null" ref="http://www.some-fictitious-zoo.com/mammals" sortResource="?name" sortDirection="ascending"> +<template id="template"> +<query id="query"> +<content uri="?uri"/> +<member container="?uri" child="?animal"/> +<triple subject="?animal" predicate="http://www.some-fictitious-zoo.com/rdf#name" object="?name"/> +</query> +<action id="action"> +<label uri="?animal" value="?name"/> +</action> +</template> +</vbox> + +</window> diff --git a/dom/xul/templates/tests/chrome/test_tmpl_sortresourcedescendingquerysyntax.xul b/dom/xul/templates/tests/chrome/test_tmpl_sortresourcedescendingquerysyntax.xul new file mode 100644 index 000000000..7281eb6ef --- /dev/null +++ b/dom/xul/templates/tests/chrome/test_tmpl_sortresourcedescendingquerysyntax.xul @@ -0,0 +1,59 @@ +<?xml version="1.0"?> +<?xml-stylesheet href="chrome://global/skin" type="text/css"?> +<?xml-stylesheet href="chrome://mochikit/content/tests/SimpleTest/test.css" type="text/css"?> + +<!-- + sortResource descending - query syntax +--> + +<window title="XUL Template Tests" width="500" height="600" + onload="test_template();" + xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"> + <script type="application/javascript" + src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script> + + <body xmlns="http://www.w3.org/1999/xhtml" style="height: 300px; overflow: auto;"/> + + <data id="output"> + <label id="http://www.some-fictitious-zoo.com/mammals/polarbear" value="Polar Bear"/> + <label id="http://www.some-fictitious-zoo.com/mammals/ninebandedarmadillo" value="Nine-banded Armadillo"/> + <label id="http://www.some-fictitious-zoo.com/mammals/llama" value="LLAMA"/> + <label id="http://www.some-fictitious-zoo.com/mammals/lion" value="Lion"/> + <label id="http://www.some-fictitious-zoo.com/mammals/hippopotamus" value="HIPPOPOTAMUS"/> + <label id="http://www.some-fictitious-zoo.com/mammals/gorilla" value="Gorilla"/> + <label id="http://www.some-fictitious-zoo.com/mammals/africanelephant" value="African Elephant"/> + <label id="http://www.some-fictitious-zoo.com/mammals/aardvark" value="aardvark"/> + </data> + +<script src="templates_shared.js"/> + +<script> +<![CDATA[ +SimpleTest.waitForExplicitFinish(); + +var testid ="sortResource descending - query syntax"; +var queryType = "rdf"; +var isTreeBuilder = false; +var needsOpen = false; +var notWorkingYet = false; +var notWorkingYetDynamic = false; +var expectedOutput = document.getElementById("output"); + +var changes = []; +]]> +</script> + +<vbox xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul" id="root" datasources="rdf:null" ref="http://www.some-fictitious-zoo.com/mammals" sortResource="?name" sortDirection="descending"> +<template id="template"> +<query id="query"> +<content uri="?uri"/> +<member container="?uri" child="?animal"/> +<triple subject="?animal" predicate="http://www.some-fictitious-zoo.com/rdf#name" object="?name"/> +</query> +<action id="action"> +<label uri="?animal" value="?name"/> +</action> +</template> +</vbox> + +</window> diff --git a/dom/xul/templates/tests/chrome/test_tmpl_sortresourcesettopredicateascendingquerysyntax.xul b/dom/xul/templates/tests/chrome/test_tmpl_sortresourcesettopredicateascendingquerysyntax.xul new file mode 100644 index 000000000..151c5d5ae --- /dev/null +++ b/dom/xul/templates/tests/chrome/test_tmpl_sortresourcesettopredicateascendingquerysyntax.xul @@ -0,0 +1,59 @@ +<?xml version="1.0"?> +<?xml-stylesheet href="chrome://global/skin" type="text/css"?> +<?xml-stylesheet href="chrome://mochikit/content/tests/SimpleTest/test.css" type="text/css"?> + +<!-- + sortResource set to predicate ascending - query syntax +--> + +<window title="XUL Template Tests" width="500" height="600" + onload="test_template();" + xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"> + <script type="application/javascript" + src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script> + + <body xmlns="http://www.w3.org/1999/xhtml" style="height: 300px; overflow: auto;"/> + + <data id="output"> + <label id="http://www.some-fictitious-zoo.com/mammals/ninebandedarmadillo" value="Nine-banded Armadillo"/> + <label id="http://www.some-fictitious-zoo.com/mammals/hippopotamus" value="HIPPOPOTAMUS"/> + <label id="http://www.some-fictitious-zoo.com/mammals/aardvark" value="aardvark"/> + <label id="http://www.some-fictitious-zoo.com/mammals/lion" value="Lion"/> + <label id="http://www.some-fictitious-zoo.com/mammals/llama" value="LLAMA"/> + <label id="http://www.some-fictitious-zoo.com/mammals/gorilla" value="Gorilla"/> + <label id="http://www.some-fictitious-zoo.com/mammals/africanelephant" value="African Elephant"/> + <label id="http://www.some-fictitious-zoo.com/mammals/polarbear" value="Polar Bear"/> + </data> + +<script src="templates_shared.js"/> + +<script> +<![CDATA[ +SimpleTest.waitForExplicitFinish(); + +var testid ="sortResource set to predicate ascending - query syntax"; +var queryType = "rdf"; +var isTreeBuilder = false; +var needsOpen = false; +var notWorkingYet = false; +var notWorkingYetDynamic = false; +var expectedOutput = document.getElementById("output"); + +var changes = []; +]]> +</script> + +<vbox xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul" id="root" datasources="rdf:null" ref="http://www.some-fictitious-zoo.com/mammals" sortResource="http://www.some-fictitious-zoo.com/rdf#specimens" sortDirection="ascending"> +<template id="template"> +<query id="query"> +<content uri="?uri"/> +<member container="?uri" child="?animal"/> +<triple subject="?animal" predicate="http://www.some-fictitious-zoo.com/rdf#name" object="?name"/> +</query> +<action id="action"> +<label uri="?animal" value="?name"/> +</action> +</template> +</vbox> + +</window> diff --git a/dom/xul/templates/tests/chrome/test_tmpl_sortresourcesettopredicatedescendingquerysyntax.xul b/dom/xul/templates/tests/chrome/test_tmpl_sortresourcesettopredicatedescendingquerysyntax.xul new file mode 100644 index 000000000..893f056b8 --- /dev/null +++ b/dom/xul/templates/tests/chrome/test_tmpl_sortresourcesettopredicatedescendingquerysyntax.xul @@ -0,0 +1,59 @@ +<?xml version="1.0"?> +<?xml-stylesheet href="chrome://global/skin" type="text/css"?> +<?xml-stylesheet href="chrome://mochikit/content/tests/SimpleTest/test.css" type="text/css"?> + +<!-- + sortResource set to predicate descending - query syntax +--> + +<window title="XUL Template Tests" width="500" height="600" + onload="test_template();" + xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"> + <script type="application/javascript" + src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script> + + <body xmlns="http://www.w3.org/1999/xhtml" style="height: 300px; overflow: auto;"/> + + <data id="output"> + <label id="http://www.some-fictitious-zoo.com/mammals/polarbear" value="Polar Bear"/> + <label id="http://www.some-fictitious-zoo.com/mammals/africanelephant" value="African Elephant"/> + <label id="http://www.some-fictitious-zoo.com/mammals/gorilla" value="Gorilla"/> + <label id="http://www.some-fictitious-zoo.com/mammals/llama" value="LLAMA"/> + <label id="http://www.some-fictitious-zoo.com/mammals/lion" value="Lion"/> + <label id="http://www.some-fictitious-zoo.com/mammals/aardvark" value="aardvark"/> + <label id="http://www.some-fictitious-zoo.com/mammals/hippopotamus" value="HIPPOPOTAMUS"/> + <label id="http://www.some-fictitious-zoo.com/mammals/ninebandedarmadillo" value="Nine-banded Armadillo"/> + </data> + +<script src="templates_shared.js"/> + +<script> +<![CDATA[ +SimpleTest.waitForExplicitFinish(); + +var testid ="sortResource set to predicate descending - query syntax"; +var queryType = "rdf"; +var isTreeBuilder = false; +var needsOpen = false; +var notWorkingYet = false; +var notWorkingYetDynamic = false; +var expectedOutput = document.getElementById("output"); + +var changes = []; +]]> +</script> + +<vbox xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul" id="root" datasources="rdf:null" ref="http://www.some-fictitious-zoo.com/mammals" sortResource="http://www.some-fictitious-zoo.com/rdf#specimens" sortDirection="descending"> +<template id="template"> +<query id="query"> +<content uri="?uri"/> +<member container="?uri" child="?animal"/> +<triple subject="?animal" predicate="http://www.some-fictitious-zoo.com/rdf#name" object="?name"/> +</query> +<action id="action"> +<label uri="?animal" value="?name"/> +</action> +</template> +</vbox> + +</window> diff --git a/dom/xul/templates/tests/chrome/test_tmpl_sorttworesourcesasstringsettopredicatedescendingquerysyntax.xul b/dom/xul/templates/tests/chrome/test_tmpl_sorttworesourcesasstringsettopredicatedescendingquerysyntax.xul new file mode 100644 index 000000000..1daf2dab9 --- /dev/null +++ b/dom/xul/templates/tests/chrome/test_tmpl_sorttworesourcesasstringsettopredicatedescendingquerysyntax.xul @@ -0,0 +1,59 @@ +<?xml version="1.0"?> +<?xml-stylesheet href="chrome://global/skin" type="text/css"?> +<?xml-stylesheet href="chrome://mochikit/content/tests/SimpleTest/test.css" type="text/css"?> + +<!-- + sort two resources as string set to predicate descending - query syntax +--> + +<window title="XUL Template Tests" width="500" height="600" + onload="test_template();" + xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"> + <script type="application/javascript" + src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script> + + <body xmlns="http://www.w3.org/1999/xhtml" style="height: 300px; overflow: auto;"/> + + <data id="output"> + <label id="http://www.some-fictitious-zoo.com/mammals/gorilla" value="Gorilla"/> + <label id="http://www.some-fictitious-zoo.com/mammals/llama" value="LLAMA"/> + <label id="http://www.some-fictitious-zoo.com/mammals/lion" value="Lion"/> + <label id="http://www.some-fictitious-zoo.com/mammals/polarbear" value="Polar Bear"/> + <label id="http://www.some-fictitious-zoo.com/mammals/hippopotamus" value="HIPPOPOTAMUS"/> + <label id="http://www.some-fictitious-zoo.com/mammals/aardvark" value="aardvark"/> + <label id="http://www.some-fictitious-zoo.com/mammals/africanelephant" value="African Elephant"/> + <label id="http://www.some-fictitious-zoo.com/mammals/ninebandedarmadillo" value="Nine-banded Armadillo"/> + </data> + +<script src="templates_shared.js"/> + +<script> +<![CDATA[ +SimpleTest.waitForExplicitFinish(); + +var testid ="sort two resources as string set to predicate descending - query syntax"; +var queryType = "rdf"; +var isTreeBuilder = false; +var needsOpen = false; +var notWorkingYet = false; +var notWorkingYetDynamic = false; +var expectedOutput = document.getElementById("output"); + +var changes = []; +]]> +</script> + +<vbox xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul" id="root" datasources="rdf:null" ref="http://www.some-fictitious-zoo.com/mammals" sortDirection="descending" sort="http://www.some-fictitious-zoo.com/rdf#specimensAsString http://www.some-fictitious-zoo.com/rdf#name"> +<template id="template"> +<query id="query"> +<content uri="?uri"/> +<member container="?uri" child="?animal"/> +<triple subject="?animal" predicate="http://www.some-fictitious-zoo.com/rdf#name" object="?name"/> +</query> +<action id="action"> +<label uri="?animal" value="?name"/> +</action> +</template> +</vbox> + +</window> diff --git a/dom/xul/templates/tests/chrome/test_tmpl_sorttworesourcessettopredicateascendingquerysyntax.xul b/dom/xul/templates/tests/chrome/test_tmpl_sorttworesourcessettopredicateascendingquerysyntax.xul new file mode 100644 index 000000000..8d9137ffa --- /dev/null +++ b/dom/xul/templates/tests/chrome/test_tmpl_sorttworesourcessettopredicateascendingquerysyntax.xul @@ -0,0 +1,59 @@ +<?xml version="1.0"?> +<?xml-stylesheet href="chrome://global/skin" type="text/css"?> +<?xml-stylesheet href="chrome://mochikit/content/tests/SimpleTest/test.css" type="text/css"?> + +<!-- + sort two resources set to predicate ascending - query syntax +--> + +<window title="XUL Template Tests" width="500" height="600" + onload="test_template();" + xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"> + <script type="application/javascript" + src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script> + + <body xmlns="http://www.w3.org/1999/xhtml" style="height: 300px; overflow: auto;"/> + + <data id="output"> + <label id="http://www.some-fictitious-zoo.com/mammals/ninebandedarmadillo" value="Nine-banded Armadillo"/> + <label id="http://www.some-fictitious-zoo.com/mammals/aardvark" value="aardvark"/> + <label id="http://www.some-fictitious-zoo.com/mammals/hippopotamus" value="HIPPOPOTAMUS"/> + <label id="http://www.some-fictitious-zoo.com/mammals/lion" value="Lion"/> + <label id="http://www.some-fictitious-zoo.com/mammals/llama" value="LLAMA"/> + <label id="http://www.some-fictitious-zoo.com/mammals/gorilla" value="Gorilla"/> + <label id="http://www.some-fictitious-zoo.com/mammals/africanelephant" value="African Elephant"/> + <label id="http://www.some-fictitious-zoo.com/mammals/polarbear" value="Polar Bear"/> + </data> + +<script src="templates_shared.js"/> + +<script> +<![CDATA[ +SimpleTest.waitForExplicitFinish(); + +var testid ="sort two resources set to predicate ascending - query syntax"; +var queryType = "rdf"; +var isTreeBuilder = false; +var needsOpen = false; +var notWorkingYet = false; +var notWorkingYetDynamic = false; +var expectedOutput = document.getElementById("output"); + +var changes = []; +]]> +</script> + +<vbox xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul" id="root" datasources="rdf:null" ref="http://www.some-fictitious-zoo.com/mammals" sortDirection="ascending" sort="http://www.some-fictitious-zoo.com/rdf#specimens http://www.some-fictitious-zoo.com/rdf#name"> +<template id="template"> +<query id="query"> +<content uri="?uri"/> +<member container="?uri" child="?animal"/> +<triple subject="?animal" predicate="http://www.some-fictitious-zoo.com/rdf#name" object="?name"/> +</query> +<action id="action"> +<label uri="?animal" value="?name"/> +</action> +</template> +</vbox> + +</window> diff --git a/dom/xul/templates/tests/chrome/test_tmpl_sorttwovariablesascendingquerysyntax.xul b/dom/xul/templates/tests/chrome/test_tmpl_sorttwovariablesascendingquerysyntax.xul new file mode 100644 index 000000000..6a396d3b9 --- /dev/null +++ b/dom/xul/templates/tests/chrome/test_tmpl_sorttwovariablesascendingquerysyntax.xul @@ -0,0 +1,119 @@ +<?xml version="1.0"?> +<?xml-stylesheet href="chrome://global/skin" type="text/css"?> +<?xml-stylesheet href="chrome://mochikit/content/tests/SimpleTest/test.css" type="text/css"?> + +<!-- + sort two variables ascending - query syntax +--> + +<window title="XUL Template Tests" width="500" height="600" + onload="test_template();" + xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"> + <script type="application/javascript" + src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script> + + <body xmlns="http://www.w3.org/1999/xhtml" style="height: 300px; overflow: auto;"/> + + <data id="output"> + <label id="http://www.some-fictitious-zoo.com/mammals/ninebandedarmadillo" value="Nine-banded Armadillo"/> + <label id="http://www.some-fictitious-zoo.com/mammals/aardvark" value="aardvark"/> + <label id="http://www.some-fictitious-zoo.com/mammals/hippopotamus" value="HIPPOPOTAMUS"/> + <label id="http://www.some-fictitious-zoo.com/mammals/lion" value="Lion"/> + <label id="http://www.some-fictitious-zoo.com/mammals/llama" value="LLAMA"/> + <label id="http://www.some-fictitious-zoo.com/mammals/gorilla" value="Gorilla"/> + <label step="5" id="http://www.some-fictitious-zoo.com/mammals/africanelephant" value="African Elephant"/> + <label step="-4" id="http://www.some-fictitious-zoo.com/mammals/africanelephant" value="African Elephant"/> + <label id="http://www.some-fictitious-zoo.com/mammals/polarbear" value="Polar Bear"/> + <label step="1" id="http://www.some-fictitious-zoo.com/mammals/arctichare" value="Arctic Hare"/> + <label step="2" id="http://www.some-fictitious-zoo.com/mammals/koala" value="Koala"/> + <label step="3" id="http://www.some-fictitious-zoo.com/mammals/zebra" value="Zebra"/> + </data> + +<script src="templates_shared.js"/> + +<script> +<![CDATA[ +SimpleTest.waitForExplicitFinish(); + +var testid ="sort two variables ascending - query syntax"; +var queryType = "rdf"; +var isTreeBuilder = false; +var needsOpen = false; +var notWorkingYet = false; +var notWorkingYetDynamic = true; +var expectedOutput = document.getElementById("output"); + +var changes = [ + // step 1 + function(targetds, root) { + var newnode = RDF.GetResource(ZOO_NS + 'mammals/arctichare'); + targetds.Assert(newnode, RDF.GetResource(ZOO_NS + 'rdf#name'), + RDF.GetLiteral('Arctic Hare'), true); + var container = ContainerUtils.MakeSeq(targetds, + RDF.GetResource(ZOO_NS + 'mammals')); + container.AppendElement(newnode); + }, + // step 2 + function(targetds, root) { + var newnode = RDF.GetResource(ZOO_NS + 'mammals/koala'); + targetds.Assert(newnode, RDF.GetResource(ZOO_NS + 'rdf#name'), + RDF.GetLiteral('Koala'), true); + var container = ContainerUtils.MakeSeq(targetds, + RDF.GetResource(ZOO_NS + 'mammals')); + container.InsertElementAt(newnode, '4', true); + }, + // step 3 + function(targetds, root) { + var newnode = RDF.GetResource(ZOO_NS + 'mammals/zebra'); + targetds.Assert(newnode, RDF.GetResource(ZOO_NS + 'rdf#name'), + RDF.GetLiteral('Zebra'), true); + var container = ContainerUtils.MakeSeq(targetds, + RDF.GetResource(ZOO_NS + 'mammals')); + container.InsertElementAt(newnode, '1', true); + }, + // step 4 + function(targetds, root) { + var container = ContainerUtils.MakeSeq(targetds, + RDF.GetResource(ZOO_NS + 'mammals')); + var removednode = container.RemoveElementAt('4', true); + targetds.Unassert(removednode, RDF.GetResource(ZOO_NS + 'rdf#name'), + RDF.GetLiteral('African Elephant'), true); + }, + // step 5 + function(targetds, root) { + var newnode = RDF.GetResource(ZOO_NS + 'mammals/africanelephant'); + targetds.Assert(newnode, RDF.GetResource(ZOO_NS + 'rdf#name'), + RDF.GetLiteral('African Elephant'), true); + var container = ContainerUtils.MakeSeq(targetds, + RDF.GetResource(ZOO_NS + 'mammals')); + container.AppendElement(newnode); + }, + // step 6 + function(targetds, root) { + targetds.Assert(RDF.GetResource(ZOO_NS + 'mammals/koala'), + RDF.GetResource(ZOO_NS + 'rdf#specimensAsString'), + RDF.GetLiteral('8'), true); + } +]; +]]> +</script> + +<vbox xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul" id="root" datasources="rdf:null" ref="http://www.some-fictitious-zoo.com/mammals" sortDirection="ascending" sort="?specimens ?name"> +<template id="template"> +<query id="query"> +<content uri="?uri"/> +<member container="?uri" child="?animal"/> +<triple subject="?animal" predicate="http://www.some-fictitious-zoo.com/rdf#name" object="?name"/> +</query> +<rule> +<bindings> +<binding subject="?animal" predicate="http://www.some-fictitious-zoo.com/rdf#specimens" object="?specimens"/> +</bindings> +<action id="action"> +<label uri="?animal" value="?name"/> +</action> +</rule> +</template> +</vbox> + +</window> diff --git a/dom/xul/templates/tests/chrome/test_tmpl_sorttwovariablesascendingsimplesyntax.xul b/dom/xul/templates/tests/chrome/test_tmpl_sorttwovariablesascendingsimplesyntax.xul new file mode 100644 index 000000000..fd8200a66 --- /dev/null +++ b/dom/xul/templates/tests/chrome/test_tmpl_sorttwovariablesascendingsimplesyntax.xul @@ -0,0 +1,52 @@ +<?xml version="1.0"?> +<?xml-stylesheet href="chrome://global/skin" type="text/css"?> +<?xml-stylesheet href="chrome://mochikit/content/tests/SimpleTest/test.css" type="text/css"?> + +<!-- + sort two variables ascending - simple syntax +--> + +<window title="XUL Template Tests" width="500" height="600" + onload="test_template();" + xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"> + <script type="application/javascript" + src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script> + + <body xmlns="http://www.w3.org/1999/xhtml" style="height: 300px; overflow: auto;"/> + + <data id="output"> + <label id="http://www.some-fictitious-zoo.com/mammals/ninebandedarmadillo" value="Nine-banded Armadillo"/> + <label id="http://www.some-fictitious-zoo.com/mammals/aardvark" value="aardvark"/> + <label id="http://www.some-fictitious-zoo.com/mammals/hippopotamus" value="HIPPOPOTAMUS"/> + <label id="http://www.some-fictitious-zoo.com/mammals/lion" value="Lion"/> + <label id="http://www.some-fictitious-zoo.com/mammals/llama" value="LLAMA"/> + <label id="http://www.some-fictitious-zoo.com/mammals/gorilla" value="Gorilla"/> + <label id="http://www.some-fictitious-zoo.com/mammals/africanelephant" value="African Elephant"/> + <label id="http://www.some-fictitious-zoo.com/mammals/polarbear" value="Polar Bear"/> + </data> + +<script src="templates_shared.js"/> + +<script> +<![CDATA[ +SimpleTest.waitForExplicitFinish(); + +var testid ="sort two variables ascending - simple syntax"; +var queryType = "rdf"; +var isTreeBuilder = false; +var needsOpen = false; +var notWorkingYet = false; +var notWorkingYetDynamic = false; +var expectedOutput = document.getElementById("output"); + +var changes = []; +]]> +</script> + +<vbox xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul" id="root" datasources="rdf:null" ref="http://www.some-fictitious-zoo.com/mammals" sortDirection="ascending" sort="http://www.some-fictitious-zoo.com/rdf#specimens http://www.some-fictitious-zoo.com/rdf#name"> +<template id="template"> +<label uri="rdf:*" value="rdf:http://www.some-fictitious-zoo.com/rdf#name"/> +</template> +</vbox> + +</window> diff --git a/dom/xul/templates/tests/chrome/test_tmpl_sorttwovariablesdescendingquerysyntax.xul b/dom/xul/templates/tests/chrome/test_tmpl_sorttwovariablesdescendingquerysyntax.xul new file mode 100644 index 000000000..f2fb6ca9d --- /dev/null +++ b/dom/xul/templates/tests/chrome/test_tmpl_sorttwovariablesdescendingquerysyntax.xul @@ -0,0 +1,64 @@ +<?xml version="1.0"?> +<?xml-stylesheet href="chrome://global/skin" type="text/css"?> +<?xml-stylesheet href="chrome://mochikit/content/tests/SimpleTest/test.css" type="text/css"?> + +<!-- + sort two variables descending - query syntax +--> + +<window title="XUL Template Tests" width="500" height="600" + onload="test_template();" + xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"> + <script type="application/javascript" + src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script> + + <body xmlns="http://www.w3.org/1999/xhtml" style="height: 300px; overflow: auto;"/> + + <data id="output"> + <label id="http://www.some-fictitious-zoo.com/mammals/polarbear" value="Polar Bear"/> + <label id="http://www.some-fictitious-zoo.com/mammals/africanelephant" value="African Elephant"/> + <label id="http://www.some-fictitious-zoo.com/mammals/gorilla" value="Gorilla"/> + <label id="http://www.some-fictitious-zoo.com/mammals/llama" value="LLAMA"/> + <label id="http://www.some-fictitious-zoo.com/mammals/lion" value="Lion"/> + <label id="http://www.some-fictitious-zoo.com/mammals/hippopotamus" value="HIPPOPOTAMUS"/> + <label id="http://www.some-fictitious-zoo.com/mammals/aardvark" value="aardvark"/> + <label id="http://www.some-fictitious-zoo.com/mammals/ninebandedarmadillo" value="Nine-banded Armadillo"/> + </data> + +<script src="templates_shared.js"/> + +<script> +<![CDATA[ +SimpleTest.waitForExplicitFinish(); + +var testid ="sort two variables descending - query syntax"; +var queryType = "rdf"; +var isTreeBuilder = false; +var needsOpen = false; +var notWorkingYet = false; +var notWorkingYetDynamic = false; +var expectedOutput = document.getElementById("output"); + +var changes = []; +]]> +</script> + +<vbox xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul" id="root" datasources="rdf:null" ref="http://www.some-fictitious-zoo.com/mammals" sortDirection="descending" sort="?specimens ?name"> +<template id="template"> +<query id="query"> +<content uri="?uri"/> +<member container="?uri" child="?animal"/> +<triple subject="?animal" predicate="http://www.some-fictitious-zoo.com/rdf#name" object="?name"/> +</query> +<rule> +<bindings> +<binding subject="?animal" predicate="http://www.some-fictitious-zoo.com/rdf#specimens" object="?specimens"/> +</bindings> +<action id="action"> +<label uri="?animal" value="?name"/> +</action> +</rule> +</template> +</vbox> + +</window> diff --git a/dom/xul/templates/tests/chrome/test_tmpl_sortunknownascendingquerysyntax.xul b/dom/xul/templates/tests/chrome/test_tmpl_sortunknownascendingquerysyntax.xul new file mode 100644 index 000000000..d995c4c1c --- /dev/null +++ b/dom/xul/templates/tests/chrome/test_tmpl_sortunknownascendingquerysyntax.xul @@ -0,0 +1,59 @@ +<?xml version="1.0"?> +<?xml-stylesheet href="chrome://global/skin" type="text/css"?> +<?xml-stylesheet href="chrome://mochikit/content/tests/SimpleTest/test.css" type="text/css"?> + +<!-- + sort unknown ascending - query syntax +--> + +<window title="XUL Template Tests" width="500" height="600" + onload="test_template();" + xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"> + <script type="application/javascript" + src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script> + + <body xmlns="http://www.w3.org/1999/xhtml" style="height: 300px; overflow: auto;"/> + + <data id="output"> + <label id="http://www.some-fictitious-zoo.com/mammals/lion" value="Lion"/> + <label id="http://www.some-fictitious-zoo.com/mammals/hippopotamus" value="HIPPOPOTAMUS"/> + <label id="http://www.some-fictitious-zoo.com/mammals/africanelephant" value="African Elephant"/> + <label id="http://www.some-fictitious-zoo.com/mammals/llama" value="LLAMA"/> + <label id="http://www.some-fictitious-zoo.com/mammals/polarbear" value="Polar Bear"/> + <label id="http://www.some-fictitious-zoo.com/mammals/aardvark" value="aardvark"/> + <label id="http://www.some-fictitious-zoo.com/mammals/ninebandedarmadillo" value="Nine-banded Armadillo"/> + <label id="http://www.some-fictitious-zoo.com/mammals/gorilla" value="Gorilla"/> + </data> + +<script src="templates_shared.js"/> + +<script> +<![CDATA[ +SimpleTest.waitForExplicitFinish(); + +var testid ="sort unknown ascending - query syntax"; +var queryType = "rdf"; +var isTreeBuilder = false; +var needsOpen = false; +var notWorkingYet = false; +var notWorkingYetDynamic = false; +var expectedOutput = document.getElementById("output"); + +var changes = []; +]]> +</script> + +<vbox xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul" id="root" datasources="rdf:null" ref="http://www.some-fictitious-zoo.com/mammals" sort="?other"> +<template id="template"> +<query id="query"> +<content uri="?uri"/> +<member container="?uri" child="?animal"/> +<triple subject="?animal" predicate="http://www.some-fictitious-zoo.com/rdf#name" object="?name"/> +</query> +<action id="action"> +<label uri="?animal" value="?name"/> +</action> +</template> +</vbox> + +</window> diff --git a/dom/xul/templates/tests/chrome/test_tmpl_storage_bad_parameters.xul b/dom/xul/templates/tests/chrome/test_tmpl_storage_bad_parameters.xul new file mode 100644 index 000000000..b11367e28 --- /dev/null +++ b/dom/xul/templates/tests/chrome/test_tmpl_storage_bad_parameters.xul @@ -0,0 +1,58 @@ +<?xml version="1.0"?> +<?xml-stylesheet href="chrome://global/skin" type="text/css"?> +<?xml-stylesheet href="chrome://mochikit/content/tests/SimpleTest/test.css" type="text/css"?> + +<!-- + storage listbox with bad query parameters +--> + +<window title="XUL Template Tests" width="500" height="600" + onload="test_template();" + xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"> + <script type="application/javascript" + src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script> + + <body xmlns="http://www.w3.org/1999/xhtml" style="height: 300px; overflow: auto;"/> + + <data id="output"/> + +<script src="templates_shared.js"/> + +<script> +<![CDATA[ +SimpleTest.waitForExplicitFinish(); + +var testid ="storage listbox with bad query parameters"; +var queryType = "storage"; +var isTreeBuilder = false; +var needsOpen = false; +var notWorkingYet = false; +var notWorkingYetDynamic = false; +var expectedOutput = document.getElementById("output"); + + +Components.classes["@mozilla.org/consoleservice;1"] + .getService(Components.interfaces.nsIConsoleService) + .reset(); + +copyToProfile('animals.sqlite'); +expectedConsoleMessages.push("Error parsing template: the given named parameter is unknown in the SQL query"); + +var changes = []; +]]> +</script> + +<listbox xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul" id="root" + flex="1" datasources="profile:animals.sqlite" ref="." querytype="storage"> + <template> + <query> + SELECT * FROM animals WHERE species_id = ? ORDER BY name + <param name="bar">2</param> + </query> + <action> + <listitem uri="?" label="?name"/> + </action> + </template> +</listbox> + +</window> diff --git a/dom/xul/templates/tests/chrome/test_tmpl_storage_bad_parameters_2.xul b/dom/xul/templates/tests/chrome/test_tmpl_storage_bad_parameters_2.xul new file mode 100644 index 000000000..81517d2df --- /dev/null +++ b/dom/xul/templates/tests/chrome/test_tmpl_storage_bad_parameters_2.xul @@ -0,0 +1,59 @@ +<?xml version="1.0"?> +<?xml-stylesheet href="chrome://global/skin" type="text/css"?> +<?xml-stylesheet href="chrome://mochikit/content/tests/SimpleTest/test.css" type="text/css"?> + +<!-- + storage listbox with bad query parameters +--> + +<window title="XUL Template Tests" width="500" height="600" + onload="test_template();" + xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"> + <script type="application/javascript" + src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script> + + <body xmlns="http://www.w3.org/1999/xhtml" style="height: 300px; overflow: auto;"/> + + <data id="output"/> + +<script src="templates_shared.js"/> + +<script> +<![CDATA[ +SimpleTest.waitForExplicitFinish(); + +var testid ="storage listbox with bad query parameters"; +var queryType = "storage"; +var isTreeBuilder = false; +var needsOpen = false; +var notWorkingYet = false; +var notWorkingYetDynamic = false; +var expectedOutput = document.getElementById("output"); + + +Components.classes["@mozilla.org/consoleservice;1"] + .getService(Components.interfaces.nsIConsoleService) + .reset(); + +copyToProfile('animals.sqlite'); + +expectedConsoleMessages.push("Error parsing template: the type of a query parameter is wrong"); + +var changes = []; +]]> +</script> + +<listbox xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul" id="root" + flex="1" datasources="profile:animals.sqlite" ref="." querytype="storage"> + <template> + <query> + SELECT * FROM animals WHERE species_id = ? ORDER BY name + <param type="mysupertype">2</param> + </query> + <action> + <listitem uri="?" label="?name"/> + </action> + </template> +</listbox> + +</window> diff --git a/dom/xul/templates/tests/chrome/test_tmpl_storage_bad_parameters_3.xul b/dom/xul/templates/tests/chrome/test_tmpl_storage_bad_parameters_3.xul new file mode 100644 index 000000000..22be02c28 --- /dev/null +++ b/dom/xul/templates/tests/chrome/test_tmpl_storage_bad_parameters_3.xul @@ -0,0 +1,60 @@ +<?xml version="1.0"?> +<?xml-stylesheet href="chrome://global/skin" type="text/css"?> +<?xml-stylesheet href="chrome://mochikit/content/tests/SimpleTest/test.css" type="text/css"?> + +<!-- + storage listbox with bad query parameters +--> + +<window title="XUL Template Tests" width="500" height="600" + onload="test_template();" + xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"> + <script type="application/javascript" + src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script> + + <body xmlns="http://www.w3.org/1999/xhtml" style="height: 300px; overflow: auto;"/> + + <data id="output"/> + +<script src="templates_shared.js"/> + +<script> +<![CDATA[ +SimpleTest.waitForExplicitFinish(); + +var testid ="storage listbox with bad query parameters"; +var queryType = "storage"; +var isTreeBuilder = false; +var needsOpen = false; +var notWorkingYet = false; +var notWorkingYetDynamic = false; +var expectedOutput = document.getElementById("output"); + + +Components.classes["@mozilla.org/consoleservice;1"] + .getService(Components.interfaces.nsIConsoleService) + .reset(); + +copyToProfile('animals.sqlite'); + +expectedConsoleMessages.push("Error parsing template: a query parameter cannot be bound to the SQL query"); + +var changes = []; +]]> +</script> + +<listbox xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul" id="root" + flex="1" datasources="profile:animals.sqlite" ref="." querytype="storage"> + <template> + <query> + SELECT * FROM animals WHERE species_id = :spec ORDER BY name + <param name="spec" type="int32">5</param> + <param>L%</param> + </query> + <action> + <listitem uri="?" label="?name"/> + </action> + </template> +</listbox> + +</window> diff --git a/dom/xul/templates/tests/chrome/test_tmpl_storage_baddatasource.xul b/dom/xul/templates/tests/chrome/test_tmpl_storage_baddatasource.xul new file mode 100644 index 000000000..da9c83d0c --- /dev/null +++ b/dom/xul/templates/tests/chrome/test_tmpl_storage_baddatasource.xul @@ -0,0 +1,56 @@ +<?xml version="1.0"?> +<?xml-stylesheet href="chrome://global/skin" type="text/css"?> +<?xml-stylesheet href="chrome://mochikit/content/tests/SimpleTest/test.css" type="text/css"?> + +<!-- + storage bad datasource +--> + +<window title="XUL Template Tests" width="500" height="600" + onload="test_template();" + xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"> + <script type="application/javascript" + src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script> + + <body xmlns="http://www.w3.org/1999/xhtml" style="height: 300px; overflow: auto;"/> + + <data id="output"/> + +<script src="templates_shared.js"/> + +<script> +<![CDATA[ +SimpleTest.waitForExplicitFinish(); + +var testid ="storage bad datasource"; +var queryType = "storage"; +var isTreeBuilder = false; +var needsOpen = false; +var notWorkingYet = false; +var notWorkingYetDynamic = false; +var expectedOutput = document.getElementById("output"); + +Components.classes["@mozilla.org/consoleservice;1"] + .getService(Components.interfaces.nsIConsoleService) + .reset(); + +expectedConsoleMessages.push("Error parsing template: only profile: or file URI are allowed"); + + +var changes = []; +]]> +</script> + +<listbox xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul" id="root" + flex="1" rows="8" + datasources="http://foo.local/animals.sqlite" ref="." querytype="storage"> + <template> + <query> + SELECT * FROM animals WHERE species_id = 2 ORDER BY name + </query> + <action> + <listitem uri="?" label="?name" /> + </action> + </template> +</listbox> +</window> diff --git a/dom/xul/templates/tests/chrome/test_tmpl_storage_badquery.xul b/dom/xul/templates/tests/chrome/test_tmpl_storage_badquery.xul new file mode 100644 index 000000000..39df0edac --- /dev/null +++ b/dom/xul/templates/tests/chrome/test_tmpl_storage_badquery.xul @@ -0,0 +1,58 @@ +<?xml version="1.0"?> +<?xml-stylesheet href="chrome://global/skin" type="text/css"?> +<?xml-stylesheet href="chrome://mochikit/content/tests/SimpleTest/test.css" type="text/css"?> + +<!-- + storage bad query +--> + +<window title="XUL Template Tests" width="500" height="600" + onload="test_template();" + xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"> + <script type="application/javascript" + src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script> + + <body xmlns="http://www.w3.org/1999/xhtml" style="height: 300px; overflow: auto;"/> + + <data id="output"/> + +<script src="templates_shared.js"/> + +<script> +<![CDATA[ +SimpleTest.waitForExplicitFinish(); + +var testid ="storage bad query"; +var queryType = "storage"; +var isTreeBuilder = false; +var needsOpen = false; +var notWorkingYet = false; +var notWorkingYetDynamic = false; +var expectedOutput = document.getElementById("output"); + +Components.classes["@mozilla.org/consoleservice;1"] + .getService(Components.interfaces.nsIConsoleService) + .reset(); + +copyToProfile('animals.sqlite'); + +expectedConsoleMessages.push("Error parsing template: syntax error in the SQL query"); + + +var changes = []; +]]> +</script> + +<listbox xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul" id="root" + flex="1" rows="8" + datasources="profile:animals.sqlite" ref="." querytype="storage"> + <template> + <query> + SELECT * FROM animalssssssss WHERE species_id = 2 ORDER BY + </query> + <action> + <listitem uri="?" label="?name" /> + </action> + </template> +</listbox> +</window> diff --git a/dom/xul/templates/tests/chrome/test_tmpl_storage_dynamicparameters.xul b/dom/xul/templates/tests/chrome/test_tmpl_storage_dynamicparameters.xul new file mode 100644 index 000000000..c791c6acd --- /dev/null +++ b/dom/xul/templates/tests/chrome/test_tmpl_storage_dynamicparameters.xul @@ -0,0 +1,84 @@ +<?xml version="1.0"?> +<?xml-stylesheet href="chrome://global/skin" type="text/css"?> +<?xml-stylesheet href="chrome://mochikit/content/tests/SimpleTest/test.css" type="text/css"?> + +<!-- + storage listbox with dynamic query parameters +--> + +<window title="XUL Template Tests" width="500" height="600" + onload="test_storage_template();" + xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"> + <script type="application/javascript" + src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script> + + <body xmlns="http://www.w3.org/1999/xhtml" style="height: 300px; overflow: auto;"/> + + <data id="output"/> + + <data id="rebuilt-output"> + <listitem anyid="true" label="Barn Owl"/> + <listitem anyid="true" label="Emu"/> + <listitem anyid="true" label="Raven"/> + </data> + +<script src="templates_shared.js"/> + +<script> +<![CDATA[ +SimpleTest.waitForExplicitFinish(); + +copyToProfile('animals.sqlite'); + +function test_storage_template() +{ + var root = document.getElementById("root"); + expectedOutput = document.getElementById("output"); + checkResults(root, 0); + + document.getElementById("species-id").textContent = '2'; + root.builder.addListener(myBuilderListener); + root.builder.rebuild(); +} + +var myBuilderListener = { + + willRebuild: function(aBuilder) { + + }, + didRebuild: function (aBuilder) { + var root = document.getElementById("root"); + expectedOutput = document.getElementById("rebuilt-output"); + checkResults(root, 0); + SimpleTest.finish(); + } +} + +var testid ="storage listbox with dynamic query parameters"; +var queryType = "storage"; +var isTreeBuilder = false; +var needsOpen = false; +var notWorkingYet = false; +var notWorkingYetDynamic = false; +var expectedOutput = document.getElementById("output"); + +var changes = []; +]]> +</script> + +<listbox xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul" id="root" + flex="1" datasources="profile:animals.sqlite" ref="." querytype="storage"> + <template> + <query> + SELECT * FROM animals WHERE species_id = :spec ORDER BY name + <param id="species-id" name="spec" type="int32" /> + </query> + <action> + <listitem uri="?" label="?name"/> + </action> + </template> +</listbox> + + + +</window> diff --git a/dom/xul/templates/tests/chrome/test_tmpl_storage_listbox.xul b/dom/xul/templates/tests/chrome/test_tmpl_storage_listbox.xul new file mode 100644 index 000000000..43661c417 --- /dev/null +++ b/dom/xul/templates/tests/chrome/test_tmpl_storage_listbox.xul @@ -0,0 +1,55 @@ +<?xml version="1.0"?> +<?xml-stylesheet href="chrome://global/skin" type="text/css"?> +<?xml-stylesheet href="chrome://mochikit/content/tests/SimpleTest/test.css" type="text/css"?> + +<!-- + storage simple with listbox +--> + +<window title="XUL Template Tests" width="500" height="600" + onload="test_template();" + xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"> + <script type="application/javascript" + src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script> + + <body xmlns="http://www.w3.org/1999/xhtml" style="height: 300px; overflow: auto;"/> + + <data id="output"> + <listitem anyid="true" label="Barn Owl"/> + <listitem anyid="true" label="Emu"/> + <listitem anyid="true" label="Raven"/> + </data> + +<script src="templates_shared.js"/> + +<script> +<![CDATA[ +SimpleTest.waitForExplicitFinish(); + +copyToProfile('animals.sqlite'); + +var testid ="storage simple listbox"; +var queryType = "storage"; +var isTreeBuilder = false; +var needsOpen = false; +var notWorkingYet = false; +var notWorkingYetDynamic = false; +var expectedOutput = document.getElementById("output"); + +var changes = []; +]]> +</script> + +<listbox xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul" id="root" + flex="1" rows="8" + datasources="profile:animals.sqlite" ref="." querytype="storage"> + <template> + <query> + SELECT * FROM animals WHERE species_id = 2 ORDER BY name + </query> + <action> + <listitem uri="?" label="?name" /> + </action> + </template> +</listbox> +</window> diff --git a/dom/xul/templates/tests/chrome/test_tmpl_storage_multiqueries.xul b/dom/xul/templates/tests/chrome/test_tmpl_storage_multiqueries.xul new file mode 100644 index 000000000..28dcaa926 --- /dev/null +++ b/dom/xul/templates/tests/chrome/test_tmpl_storage_multiqueries.xul @@ -0,0 +1,86 @@ +<?xml version="1.0"?> +<?xml-stylesheet href="chrome://global/skin" type="text/css"?> +<?xml-stylesheet href="chrome://mochikit/content/tests/SimpleTest/test.css" type="text/css"?> + +<!-- + storage listbox with multiqueries +--> + +<window title="XUL Template Tests" width="500" height="600" + onload="test_template();" + xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"> + <script type="application/javascript" + src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script> + + <body xmlns="http://www.w3.org/1999/xhtml" style="height: 300px; overflow: auto;"/> + + <data id="output"> + <listitem anyid="true" label="Mammal: African Elephant"/> + <listitem anyid="true" label="Mammal: Gorilla" style="font-weight:bold"/> + <listitem anyid="true" label="Mammal: HIPPOPOTAMUS"/> + <listitem anyid="true" label="Mammal: LAMA"/> + <listitem anyid="true" label="Mammal: Lion"/> + <listitem anyid="true" label="Mammal: Nine-banded Armadillo" style="font-weight:bold"/> + <listitem anyid="true" label="Mammal: Polar Bear"/> + <listitem anyid="true" label="Mammal: aardvark"/> + <listitem anyid="true" label="Bird: Barn Owl" style="font-style:italic"/> + <listitem anyid="true" label="Bird: Emu"/> + <listitem anyid="true" label="Bird: Raven"/> + </data> + +<script src="templates_shared.js"/> + +<script> +<![CDATA[ +SimpleTest.waitForExplicitFinish(); + +copyToProfile('animals.sqlite'); + +var testid ="storage listbox with multiqueries"; +var queryType = "storage"; +var isTreeBuilder = false; +var needsOpen = false; +var notWorkingYet = false; +var notWorkingYetDynamic = false; +var expectedOutput = document.getElementById("output"); + +var changes = []; +]]> +</script> + +<listbox xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul" id="root" + flex="1" datasources="profile:animals.sqlite" ref="." querytype="storage"> + <template> + <queryset> + <query>SELECT * FROM animals WHERE species_id = 5 ORDER BY name</query> + <rule> + <where subject="?id" rel="greater" value="12"/> + <action> + <listitem uri="?" label="Mammal: ?name" style="font-weight:bold"/> + </action> + </rule> + <rule> + <action> + <listitem uri="?" label="Mammal: ?name"/> + </action> + </rule> + </queryset> + <queryset> + <!-- we use aliases on columns just to have different "column names" in the result set + to "similate" a result set from another table for example --> + <query>SELECT * FROM animals WHERE species_id = 2 ORDER BY name</query> + <rule> + <where subject="?id" rel="equals" value="3"/> + <action> + <listitem uri="?" label="Bird: ?name" style="font-style:italic"/> + </action> + </rule> + <rule> + <action> + <listitem uri="?" label="Bird: ?name"/> + </action> + </rule> + </queryset> + </template> +</listbox> +</window> diff --git a/dom/xul/templates/tests/chrome/test_tmpl_storage_parameters.xul b/dom/xul/templates/tests/chrome/test_tmpl_storage_parameters.xul new file mode 100644 index 000000000..0df561884 --- /dev/null +++ b/dom/xul/templates/tests/chrome/test_tmpl_storage_parameters.xul @@ -0,0 +1,160 @@ +<?xml version="1.0"?> +<?xml-stylesheet href="chrome://global/skin" type="text/css"?> +<?xml-stylesheet href="chrome://mochikit/content/tests/SimpleTest/test.css" type="text/css"?> + +<!-- + storage listbox with query parameters +--> + +<window title="XUL Template Tests" width="500" height="600" + onload="test_storage_template();" + xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"> + <script type="application/javascript" + src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script> + + <body xmlns="http://www.w3.org/1999/xhtml" style="height: 300px; overflow: auto;"/> + + <data id="output-birds"> + <listitem anyid="true" label="Barn Owl"/> + <listitem anyid="true" label="Emu"/> + <listitem anyid="true" label="Raven"/> + </data> + + <data id="output-L"> + <listitem anyid="true" label="LAMA"/> + <listitem anyid="true" label="Lion"/> + </data> + +<script src="templates_shared.js"/> + +<script> +<![CDATA[ + +copyToProfile('animals.sqlite'); +SimpleTest.waitForExplicitFinish(); + + +function test_storage_template() +{ + var root = document.getElementById("root1"); + expectedOutput = document.getElementById("output-birds"); + checkResults(root, 0); + +root = document.getElementById("root2"); +checkResults(root, 0); + +root = document.getElementById("root6"); +checkResults(root, 0); + +root = document.getElementById("root3"); +expectedOutput = document.getElementById("output-L"); +checkResults(root, 0); + +root = document.getElementById("root4"); +checkResults(root, 0); + +root = document.getElementById("root5"); +checkResults(root, 0); + +SimpleTest.finish(); +} + + +var testid ="storage listbox with query parameters"; +var queryType = "storage"; +var isTreeBuilder = false; +var needsOpen = false; +var notWorkingYet = false; +var notWorkingYetDynamic = false; +var expectedOutput; + +var changes = []; +]]> +</script> + +<listbox xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul" id="root1" + flex="1" datasources="profile:animals.sqlite" ref="." querytype="storage"> + <template> + <query> + SELECT * FROM animals WHERE species_id = ? ORDER BY name + <param>2</param> + </query> + <action> + <listitem uri="?" label="?name"/> + </action> + </template> +</listbox> + + +<listbox xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul" id="root2" + flex="1" datasources="profile:animals.sqlite" ref="." querytype="storage"> + <template> + <query> + SELECT * FROM animals WHERE species_id = ? ORDER BY name + <param type="int32">2</param> + </query> + <action> + <listitem uri="?" label="?name"/> + </action> + </template> +</listbox> + + +<listbox xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul" id="root3" + flex="1" datasources="profile:animals.sqlite" ref="." querytype="storage"> + <template> + <query> + SELECT * FROM animals WHERE species_id = :spec AND name like ? ORDER BY name + <param name="spec" type="int32">5</param> + <param>L%</param> + </query> + <action> + <listitem uri="?" label="?name"/> + </action> + </template> +</listbox> + +<listbox xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul" id="root4" + flex="1" datasources="profile:animals.sqlite" ref="." querytype="storage"> + <template> + <query> + SELECT * FROM animals WHERE species_id = ?3 AND name like ?1 ORDER BY name + <param index="3" type="int32">5</param> + <param index="1">L%</param> + </query> + <action> + <listitem uri="?" label="?name"/> + </action> + </template> +</listbox> + +<listbox xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul" id="root5" + flex="1" datasources="profile:animals.sqlite" ref="." querytype="storage"> + <template> + <query> + SELECT * FROM animals WHERE species_id = ?3 AND name like :pattern ORDER BY name + <param name="pattern">L%</param> + <param index="3" type="int32">5</param> + </query> + <action> + <listitem uri="?" label="?name"/> + </action> + </template> +</listbox> + +<listbox xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul" id="root6" + flex="1" datasources="profile:animals.sqlite" ref="." querytype="storage"> + <template> + <query> + SELECT * FROM animals WHERE species_id = ? ORDER BY name + <param type="int32">2qsdqsd</param> + </query> + <action> + <listitem uri="?" label="?name"/> + </action> + </template> +</listbox> + + + +</window> diff --git a/dom/xul/templates/tests/chrome/test_tmpl_storage_rule.xul b/dom/xul/templates/tests/chrome/test_tmpl_storage_rule.xul new file mode 100644 index 000000000..003682750 --- /dev/null +++ b/dom/xul/templates/tests/chrome/test_tmpl_storage_rule.xul @@ -0,0 +1,59 @@ +<?xml version="1.0"?> +<?xml-stylesheet href="chrome://global/skin" type="text/css"?> +<?xml-stylesheet href="chrome://mochikit/content/tests/SimpleTest/test.css" type="text/css"?> + +<!-- + storage listbox with rule +--> + +<window title="XUL Template Tests" width="500" height="600" + onload="test_template();" + xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"> + <script type="application/javascript" + src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script> + + <body xmlns="http://www.w3.org/1999/xhtml" style="height: 300px; overflow: auto;"/> + + <data id="output"> + <listitem anyid="true" label="Gorilla"/> + <listitem anyid="true" label="Nine-banded Armadillo"/> + <listitem anyid="true" label="Polar Bear"/> + <listitem anyid="true" label="aardvark"/> + </data> + +<script src="templates_shared.js"/> + +<script> +<![CDATA[ + +SimpleTest.waitForExplicitFinish(); +copyToProfile('animals.sqlite'); + +var testid ="storage listbox with rule"; +var queryType = "storage"; +var isTreeBuilder = false; +var needsOpen = false; +var notWorkingYet = false; +var notWorkingYetDynamic = false; +var expectedOutput = document.getElementById("output"); + +var changes = []; +]]> +</script> + +<listbox xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul" id="root" + flex="1" rows="8" + datasources="profile:animals.sqlite" ref="." querytype="storage"> + <template> + <query> + SELECT * FROM animals WHERE species_id = 5 ORDER BY name + </query> + <rule> + <where subject="?id" rel="greater" value="10"/> + <action> + <listitem uri="?" label="?name" /> + </action> + </rule> + </template> +</listbox> +</window> diff --git a/dom/xul/templates/tests/chrome/test_tmpl_storage_simple.xul b/dom/xul/templates/tests/chrome/test_tmpl_storage_simple.xul new file mode 100644 index 000000000..0ac6d3857 --- /dev/null +++ b/dom/xul/templates/tests/chrome/test_tmpl_storage_simple.xul @@ -0,0 +1,52 @@ +<?xml version="1.0"?> +<?xml-stylesheet href="chrome://global/skin" type="text/css"?> +<?xml-stylesheet href="chrome://mochikit/content/tests/SimpleTest/test.css" type="text/css"?> + +<!-- + storage simple +--> + +<window title="XUL Template Tests" width="500" height="600" + onload="test_template();" + xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"> + <script type="application/javascript" + src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script> + + <body xmlns="http://www.w3.org/1999/xhtml" style="height: 300px; overflow: auto;"/> + + <data id="output"> + <button anyid="true" label="Barn Owl / Tyto alba"/> + <button anyid="true" label="Emu / Dromaius novaehollandiae"/> + <button anyid="true" label="Raven / Corvus corax"/> + </data> + +<script src="templates_shared.js"/> + +<script> +<![CDATA[ +copyToProfile('animals.sqlite'); +SimpleTest.waitForExplicitFinish(); + +var testid ="storage simple"; +var queryType = "storage"; +var isTreeBuilder = false; +var needsOpen = false; +var notWorkingYet = false; +var notWorkingYetDynamic = false; +var expectedOutput = document.getElementById("output"); + +var changes = []; +]]> +</script> + +<vbox xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul" id="root" + datasources="profile:animals.sqlite" querytype="storage" ref="."> +<template> + <query>SELECT * FROM animals WHERE species_id = 2 ORDER BY name</query> + <action> + <button uri="?" label="?name / ?specimen"/> + </action> +</template> +</vbox> + +</window> diff --git a/dom/xul/templates/tests/chrome/test_tmpl_storage_sortintegerasc.xul b/dom/xul/templates/tests/chrome/test_tmpl_storage_sortintegerasc.xul new file mode 100644 index 000000000..376cee25c --- /dev/null +++ b/dom/xul/templates/tests/chrome/test_tmpl_storage_sortintegerasc.xul @@ -0,0 +1,75 @@ +<?xml version="1.0"?> +<?xml-stylesheet href="chrome://global/skin" type="text/css"?> +<?xml-stylesheet href="chrome://mochikit/content/tests/SimpleTest/test.css" type="text/css"?> + +<!-- + storage sort integer asc +--> + +<window title="XUL Template Tests" width="500" height="600" + onload="test_template();" + xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"> + <script type="application/javascript" + src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script> + + <body xmlns="http://www.w3.org/1999/xhtml" style="height: 300px; overflow: auto;"/> + + <data id="output"> + <row anyid="true"> <label value="1"/> <label value="Tarantula"/> </row> + <row anyid="true"> <label value="2"/> <label value="Emu"/> </row> + <row anyid="true"> <label value="3"/> <label value="Barn Owl"/> </row> + <row anyid="true"> <label value="4"/> <label value="Raven"/> </row> + <row anyid="true"> <label value="5"/> <label value="Cod"/> </row> + <row anyid="true"> <label value="6"/> <label value="Swordfish"/> </row> + <row anyid="true"> <label value="7"/> <label value="Lion"/> </row> + <row anyid="true"> <label value="8"/> <label value="HIPPOPOTAMUS"/> </row> + <row anyid="true"> <label value="9"/> <label value="African Elephant"/> </row> + <row anyid="true"> <label value="10"/> <label value="LAMA"/> </row> + <row anyid="true"> <label value="11"/> <label value="Polar Bear"/> </row> + <row anyid="true"> <label value="12"/> <label value="aardvark"/> </row> + <row anyid="true"> <label value="13"/> <label value="Nine-banded Armadillo"/> </row> + <row anyid="true"> <label value="14"/> <label value="Gorilla"/> </row> + <row anyid="true"> <label value="15"/> <label value="Anaconda"/> </row> + <row anyid="true"> <label value="16"/> <label value="Chameleon"/> </row> + </data> + +<script src="templates_shared.js"/> + +<script> +<![CDATA[ +SimpleTest.waitForExplicitFinish(); + +copyToProfile('animals.sqlite'); + +var testid ="storage sort integer asc"; +var queryType = "storage"; +var isTreeBuilder = false; +var needsOpen = false; +var notWorkingYet = false; +var notWorkingYetDynamic = false; +var expectedOutput = document.getElementById("output"); + +var changes = []; +]]> +</script> + +<grid xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul" > + <columns> + <column flex="1"/> + <column flex="3"/> + </columns> + <rows id="root" datasources="profile:animals.sqlite" querytype="storage" ref="." + sort="?id" sortDirection="ascending"> + <template> + <query>SELECT id, name FROM animals</query> + <action> + <row uri="?"> + <label value="?id"/> + <label value="?name"/> + </row> + </action> + </template> + </rows> +</grid> + +</window> diff --git a/dom/xul/templates/tests/chrome/test_tmpl_storage_sortintegerdesc.xul b/dom/xul/templates/tests/chrome/test_tmpl_storage_sortintegerdesc.xul new file mode 100644 index 000000000..3ab75fcf4 --- /dev/null +++ b/dom/xul/templates/tests/chrome/test_tmpl_storage_sortintegerdesc.xul @@ -0,0 +1,78 @@ +<?xml version="1.0"?> +<?xml-stylesheet href="chrome://global/skin" type="text/css"?> +<?xml-stylesheet href="chrome://mochikit/content/tests/SimpleTest/test.css" type="text/css"?> + +<!-- + storage sort integer desc +--> + +<window title="XUL Template Tests" width="500" height="600" + onload="test_template();" + xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"> + <script type="application/javascript" + src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script> + + <body xmlns="http://www.w3.org/1999/xhtml" style="height: 300px; overflow: auto;"/> + + <data id="output"> + <row anyid="true"> <label value="16"/> <label value="Chameleon"/> </row> + <row anyid="true"> <label value="15"/> <label value="Anaconda"/> </row> + <row anyid="true"> <label value="14"/> <label value="Gorilla"/> </row> + <row anyid="true"> <label value="13"/> <label value="Nine-banded Armadillo"/> </row> + <row anyid="true"> <label value="12"/> <label value="aardvark"/> </row> + <row anyid="true"> <label value="11"/> <label value="Polar Bear"/> </row> + <row anyid="true"> <label value="10"/> <label value="LAMA"/> </row> + <row anyid="true"> <label value="9"/> <label value="African Elephant"/> </row> + <row anyid="true"> <label value="8"/> <label value="HIPPOPOTAMUS"/> </row> + <row anyid="true"> <label value="7"/> <label value="Lion"/> </row> + <row anyid="true"> <label value="6"/> <label value="Swordfish"/> </row> + <row anyid="true"> <label value="5"/> <label value="Cod"/> </row> + <row anyid="true"> <label value="4"/> <label value="Raven"/> </row> + <row anyid="true"> <label value="3"/> <label value="Barn Owl"/> </row> + <row anyid="true"> <label value="2"/> <label value="Emu"/> </row> + <row anyid="true"> <label value="1"/> <label value="Tarantula"/> </row> + </data> + +<script src="templates_shared.js"/> + +<script> +<![CDATA[ +SimpleTest.waitForExplicitFinish(); + +copyToProfile('animals.sqlite'); + +var testid ="storage sort integer desc"; +var queryType = "storage"; +var isTreeBuilder = false; +var needsOpen = false; +var notWorkingYet = false; +var notWorkingYetDynamic = false; +var expectedOutput = document.getElementById("output"); + +var changes = []; +]]> +</script> + +<grid xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul" > + <columns> + <column flex="1"/> + <column flex="3"/> + </columns> + <rows id="root" datasources="profile:animals.sqlite" querytype="storage" ref="." + sort="?id" sortDirection="descending"> + <template> + <query>SELECT id, name FROM animals</query> + <action> + <row uri="?"> + <label value="?id"/> + <label value="?name"/> + </row> + </action> + </template> + </rows> +</grid> + + + + +</window> diff --git a/dom/xul/templates/tests/chrome/test_tmpl_storage_sortstringasc.xul b/dom/xul/templates/tests/chrome/test_tmpl_storage_sortstringasc.xul new file mode 100644 index 000000000..600db67c4 --- /dev/null +++ b/dom/xul/templates/tests/chrome/test_tmpl_storage_sortstringasc.xul @@ -0,0 +1,75 @@ +<?xml version="1.0"?> +<?xml-stylesheet href="chrome://global/skin" type="text/css"?> +<?xml-stylesheet href="chrome://mochikit/content/tests/SimpleTest/test.css" type="text/css"?> + +<!-- + storage sort string asc +--> + +<window title="XUL Template Tests" width="500" height="600" + onload="test_template();" + xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"> + <script type="application/javascript" + src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script> + + <body xmlns="http://www.w3.org/1999/xhtml" style="height: 300px; overflow: auto;"/> + + <data id="output"> + <row anyid="true"> <label value="12"/> <label value="aardvark"/> </row> + <row anyid="true"> <label value="9"/> <label value="African Elephant"/> </row> + <row anyid="true"> <label value="15"/> <label value="Anaconda"/> </row> + <row anyid="true"> <label value="3"/> <label value="Barn Owl"/> </row> + <row anyid="true"> <label value="16"/> <label value="Chameleon"/> </row> + <row anyid="true"> <label value="5"/> <label value="Cod"/> </row> + <row anyid="true"> <label value="2"/> <label value="Emu"/> </row> + <row anyid="true"> <label value="14"/> <label value="Gorilla"/> </row> + <row anyid="true"> <label value="8"/> <label value="HIPPOPOTAMUS"/> </row> + <row anyid="true"> <label value="10"/> <label value="LAMA"/> </row> + <row anyid="true"> <label value="7"/> <label value="Lion"/> </row> + <row anyid="true"> <label value="13"/> <label value="Nine-banded Armadillo"/> </row> + <row anyid="true"> <label value="11"/> <label value="Polar Bear"/> </row> + <row anyid="true"> <label value="4"/> <label value="Raven"/> </row> + <row anyid="true"> <label value="6"/> <label value="Swordfish"/> </row> + <row anyid="true"> <label value="1"/> <label value="Tarantula"/> </row> + </data> + +<script src="templates_shared.js"/> + +<script> +<![CDATA[ +SimpleTest.waitForExplicitFinish(); + +copyToProfile('animals.sqlite'); + +var testid ="storage sort string asc"; +var queryType = "storage"; +var isTreeBuilder = false; +var needsOpen = false; +var notWorkingYet = false; +var notWorkingYetDynamic = false; +var expectedOutput = document.getElementById("output"); + +var changes = []; +]]> +</script> + +<grid xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul" > + <columns> + <column flex="1"/> + <column flex="3"/> + </columns> + <rows id="root" datasources="profile:animals.sqlite" querytype="storage" ref="." + sort="?name" sortDirection="ascending"> + <template> + <query>SELECT id, name FROM animals</query> + <action> + <row uri="?"> + <label value="?id"/> + <label value="?name"/> + </row> + </action> + </template> + </rows> +</grid> + +</window> diff --git a/dom/xul/templates/tests/chrome/test_tmpl_storage_sortstringdesc.xul b/dom/xul/templates/tests/chrome/test_tmpl_storage_sortstringdesc.xul new file mode 100644 index 000000000..b99c849e7 --- /dev/null +++ b/dom/xul/templates/tests/chrome/test_tmpl_storage_sortstringdesc.xul @@ -0,0 +1,75 @@ +<?xml version="1.0"?> +<?xml-stylesheet href="chrome://global/skin" type="text/css"?> +<?xml-stylesheet href="chrome://mochikit/content/tests/SimpleTest/test.css" type="text/css"?> + +<!-- + storage sort string desc +--> + +<window title="XUL Template Tests" width="500" height="600" + onload="test_template();" + xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"> + <script type="application/javascript" + src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script> + + <body xmlns="http://www.w3.org/1999/xhtml" style="height: 300px; overflow: auto;"/> + + <data id="output"> + <row anyid="true"> <label value="1"/> <label value="Tarantula"/> </row> + <row anyid="true"> <label value="6"/> <label value="Swordfish"/> </row> + <row anyid="true"> <label value="4"/> <label value="Raven"/> </row> + <row anyid="true"> <label value="11"/> <label value="Polar Bear"/> </row> + <row anyid="true"> <label value="13"/> <label value="Nine-banded Armadillo"/> </row> + <row anyid="true"> <label value="7"/> <label value="Lion"/> </row> + <row anyid="true"> <label value="10"/> <label value="LAMA"/> </row> + <row anyid="true"> <label value="8"/> <label value="HIPPOPOTAMUS"/> </row> + <row anyid="true"> <label value="14"/> <label value="Gorilla"/> </row> + <row anyid="true"> <label value="2"/> <label value="Emu"/> </row> + <row anyid="true"> <label value="5"/> <label value="Cod"/> </row> + <row anyid="true"> <label value="16"/> <label value="Chameleon"/> </row> + <row anyid="true"> <label value="3"/> <label value="Barn Owl"/> </row> + <row anyid="true"> <label value="15"/> <label value="Anaconda"/> </row> + <row anyid="true"> <label value="9"/> <label value="African Elephant"/> </row> + <row anyid="true"> <label value="12"/> <label value="aardvark"/> </row> + </data> + +<script src="templates_shared.js"/> + +<script> +<![CDATA[ +SimpleTest.waitForExplicitFinish(); + +copyToProfile('animals.sqlite'); + +var testid ="storage sort string desc"; +var queryType = "storage"; +var isTreeBuilder = false; +var needsOpen = false; +var notWorkingYet = false; +var notWorkingYetDynamic = false; +var expectedOutput = document.getElementById("output"); + +var changes = []; +]]> +</script> + +<grid xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul" > + <columns> + <column flex="1"/> + <column flex="3"/> + </columns> + <rows id="root" datasources="profile:animals.sqlite" querytype="storage" ref="." + sort="?name" sortDirection="descending"> + <template> + <query>SELECT id, name FROM animals</query> + <action> + <row uri="?"> + <label value="?id"/> + <label value="?name"/> + </row> + </action> + </template> + </rows> +</grid> + +</window> diff --git a/dom/xul/templates/tests/chrome/test_tmpl_storage_tree.xul b/dom/xul/templates/tests/chrome/test_tmpl_storage_tree.xul new file mode 100644 index 000000000..9ca042713 --- /dev/null +++ b/dom/xul/templates/tests/chrome/test_tmpl_storage_tree.xul @@ -0,0 +1,122 @@ +<?xml version="1.0"?> +<?xml-stylesheet href="chrome://global/skin" type="text/css"?> +<?xml-stylesheet href="chrome://mochikit/content/tests/SimpleTest/test.css" type="text/css"?> + +<!-- + storage tree +--> + +<window title="XUL Template Tests" width="500" height="600" + onload="test_template();" + xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"> + <script type="application/javascript" + src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script> + + <body xmlns="http://www.w3.org/1999/xhtml" style="height: 300px; overflow: auto;"/> + + <data id="output"> + <treecols orient="horizontal"> + <treecol id="species" primary="true" label="Species" flex="2" ordinal="1"/> + <treecol id="name" label="Common name" flex="2" ordinal="3"/> + <treecol id="specimen" label="Specimen" flex="3" ordinal="5"/> + <treecol id="id" label="id" flex="1" ordinal="7"/> + </treecols> + <treechildren> + <treeitem anyid="true"> <treerow> + <treecell label="arachnids" /> <treecell label="Tarantula"/> <treecell label="Avicularia avicularia" /> <treecell label="1"/> + </treerow> </treeitem> + <treeitem anyid="true"> <treerow> + <treecell label="birds" /> <treecell label="Barn Owl"/> <treecell label="Tyto alba" /> <treecell label="3"/> + </treerow> </treeitem> + <treeitem anyid="true"> <treerow> + <treecell label="birds" /> <treecell label="Emu"/> <treecell label="Dromaius novaehollandiae" /> <treecell label="2"/> + </treerow> </treeitem> + <treeitem anyid="true"> <treerow> + <treecell label="birds" /> <treecell label="Raven"/> <treecell label="Corvus corax" /> <treecell label="4"/> + </treerow> </treeitem> + <treeitem anyid="true"> <treerow> + <treecell label="fish" /> <treecell label="Cod"/> <treecell label="Gadus morhua" /> <treecell label="5"/> + </treerow> </treeitem> + <treeitem anyid="true"> <treerow> + <treecell label="fish" /> <treecell label="Swordfish"/> <treecell label="Xiphias gladius" /> <treecell label="6"/> + </treerow> </treeitem> + <treeitem anyid="true"> <treerow> + <treecell label="mammals" /> <treecell label="African Elephant"/> <treecell label="Loxodonta africana" /> <treecell label="9"/> + </treerow> </treeitem> + <treeitem anyid="true"> <treerow> + <treecell label="mammals" /> <treecell label="Gorilla"/> <treecell label="Gorilla gorilla" /> <treecell label="14"/> + </treerow> </treeitem> + <treeitem anyid="true"> <treerow> + <treecell label="mammals" /> <treecell label="HIPPOPOTAMUS"/> <treecell label="Hippopotamus amphibius" /> <treecell label="8"/> + </treerow> </treeitem> + <treeitem anyid="true"> <treerow> + <treecell label="mammals" /> <treecell label="LAMA"/> <treecell label="Lama glama" /> <treecell label="10"/> + </treerow> </treeitem> + <treeitem anyid="true"> <treerow> + <treecell label="mammals" /> <treecell label="Lion"/> <treecell label="Panthera leo" /> <treecell label="7"/> + </treerow> </treeitem> + <treeitem anyid="true"> <treerow> + <treecell label="mammals" /> <treecell label="Nine-banded Armadillo"/> <treecell label="Dasypus novemcinctus" /> <treecell label="13"/> + </treerow> </treeitem> + <treeitem anyid="true"> <treerow> + <treecell label="mammals" /> <treecell label="Polar Bear"/> <treecell label="Thalarctos maritimus" /> <treecell label="11"/> + </treerow> </treeitem> + <treeitem anyid="true"> <treerow> + <treecell label="mammals" /> <treecell label="aardvark"/> <treecell label="Orycteropus afer" /> <treecell label="12"/> + </treerow> </treeitem> + <treeitem anyid="true"> <treerow> + <treecell label="reptiles" /> <treecell label="Anaconda"/> <treecell label="Eunectes murinus" /> <treecell label="15"/> + </treerow> </treeitem> + <treeitem anyid="true"> <treerow> + <treecell label="reptiles" /> <treecell label="Chameleon"/> <treecell label="Chamaeleo chamaelon" /> <treecell label="16"/> + </treerow> </treeitem> + </treechildren> + </data> + +<script src="templates_shared.js"/> + +<script> +<![CDATA[ +SimpleTest.waitForExplicitFinish(); + +copyToProfile('animals.sqlite'); + +var testid ="storage tree"; +var queryType = "storage"; +var isTreeBuilder = true; +var needsOpen = false; +var notWorkingYet = false; +var notWorkingYetDynamic = false; +var expectedOutput = document.getElementById("output"); + +var changes = []; +]]> +</script> + +<tree xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul" id="root" + flex="1" datasources="profile:animals.sqlite" ref="*" querytype="storage" flags="dont-build-content"> + <treecols> + <treecol id="species" primary="true" label="Species" flex="2"/> + <treecol id="name" label="Common name" flex="2"/> + <treecol id="specimen" label="Specimen" flex="3"/> + <treecol id="id" label="id" flex="1"/> + </treecols> + <template> + <query> + SELECT a.id, a.name, a.specimen, s.name as species FROM animals a, species s + WHERE a.species_id = s.id ORDER BY species, a.name</query> + <action> + <treechildren> + <treeitem uri="?"> + <treerow> + <treecell label="?species"/> + <treecell label="?name"/> + <treecell label="?specimen"/> + <treecell label="?id"/> + </treerow> + </treeitem> + </treechildren> + </action> + </template> + </tree> +</window> diff --git a/dom/xul/templates/tests/chrome/test_tmpl_treeelementquerysyntax.xul b/dom/xul/templates/tests/chrome/test_tmpl_treeelementquerysyntax.xul new file mode 100644 index 000000000..bfb494c79 --- /dev/null +++ b/dom/xul/templates/tests/chrome/test_tmpl_treeelementquerysyntax.xul @@ -0,0 +1,158 @@ +<?xml version="1.0"?> +<?xml-stylesheet href="chrome://global/skin" type="text/css"?> +<?xml-stylesheet href="chrome://mochikit/content/tests/SimpleTest/test.css" type="text/css"?> + +<!-- + tree element - query syntax +--> + +<window title="XUL Template Tests" width="500" height="600" + onload="test_template();" + xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"> + <script type="application/javascript" + src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script> + + <body xmlns="http://www.w3.org/1999/xhtml" style="height: 300px; overflow: auto;"/> + + <data id="output"> + <treecols id="treecols" orient="horizontal"> + <treecol id="treecol" primary="true" label="Name" ordinal="1"/> + <treecol label="Species" ordinal="3"/> + </treecols> + <treechildren> + <treeitem id="http://www.some-fictitious-zoo.com/birds/emu"> + <treerow> + <treecell label="Emu"/> + <treecell step="-6" label="12"/> + <treecell step="6" label="0"/> + </treerow> + </treeitem> + <treeitem step="1" id="http://www.some-fictitious-zoo.com/birds/archaeopteryx"> + <treerow> + <treecell label="Archaeopteryx"/> + <treecell step="-4"/> + <treecell step="4" label="5"/> + </treerow> + </treeitem> + <treeitem step="-2" id="http://www.some-fictitious-zoo.com/birds/barnowl"> + <treerow> + <treecell label="Barn Owl"/> + <treecell label="4"/> + </treerow> + </treeitem> + <treeitem id="http://www.some-fictitious-zoo.com/birds/raven"> + <treerow> + <treecell step="-7" label="Raven"/> + <treecell step="7" label="Crow"/> + <treecell step="-5" label="0"/> + <treecell step="5" label="2"/> + </treerow> + </treeitem> + </treechildren> + </data> + +<script src="templates_shared.js"/> + +<script> +<![CDATA[ +SimpleTest.waitForExplicitFinish(); + +var testid ="tree element - query syntax"; +var queryType = "rdf"; +var isTreeBuilder = false; +var needsOpen = false; +var notWorkingYet = false; +var notWorkingYetDynamic = false; +var expectedOutput = document.getElementById("output"); + +var changes = [ + // step 1 + function(targetds, root) { + var newnode = RDF.GetResource(ZOO_NS + 'birds/archaeopteryx'); + targetds.Assert(newnode, RDF.GetResource(ZOO_NS + 'rdf#name'), + RDF.GetLiteral('Archaeopteryx'), true); + var container = ContainerUtils.MakeSeq(targetds, + RDF.GetResource(ZOO_NS + 'birds')); + container.InsertElementAt(newnode, '2', true); + }, + // step 2 + function(targetds, root) { + var container = ContainerUtils.MakeSeq(targetds, + RDF.GetResource(ZOO_NS + 'birds')); + var removednode = container.RemoveElementAt('3', true); + targetds.Unassert(removednode, RDF.GetResource(ZOO_NS + 'rdf#name'), + RDF.GetLiteral('Barn Owl'), true); + }, + // step 3 + function(targetds, root) { + targetds.Assert(RDF.GetResource(ZOO_NS + 'birds/archaeopteryx'), + RDF.GetResource(ZOO_NS + 'rdf#species'), + RDF.GetLiteral('Archaeopteryx lithographica'), true); + }, + // step 4 + function(targetds, root) { + targetds.Assert(RDF.GetResource(ZOO_NS + 'birds/archaeopteryx'), + RDF.GetResource(ZOO_NS + 'rdf#specimens'), + RDF.GetLiteral('5'), true); + }, + // step 5 + function(targetds, root) { + var subject = RDF.GetResource(ZOO_NS + 'birds/raven'); + var predicate = RDF.GetResource(ZOO_NS + 'rdf#specimens'); + var oldval = targetds.GetTarget(subject, predicate, true); + targetds.Change(RDF.GetResource(ZOO_NS + 'birds/raven'), + RDF.GetResource(ZOO_NS + 'rdf#specimens'), + oldval, RDF.GetLiteral('2')); + }, + // step 6 + function(targetds, root) { + var subject = RDF.GetResource(ZOO_NS + 'birds/emu'); + var predicate = RDF.GetResource(ZOO_NS + 'rdf#specimens'); + var oldval = targetds.GetTarget(subject, predicate, true); + targetds.Change(RDF.GetResource(ZOO_NS + 'birds/emu'), + RDF.GetResource(ZOO_NS + 'rdf#specimens'), + oldval, RDF.GetLiteral('0')); + }, + // step 7 + function(targetds, root) { + var subject = RDF.GetResource(ZOO_NS + 'birds/raven'); + var predicate = RDF.GetResource(ZOO_NS + 'rdf#name'); + var oldval = targetds.GetTarget(subject, predicate, true); + targetds.Change(RDF.GetResource(ZOO_NS + 'birds/raven'), + RDF.GetResource(ZOO_NS + 'rdf#name'), + oldval, RDF.GetLiteral('Crow')); + } +]; +]]> +</script> + +<tree xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul" hidevscroll="true" hidehscroll="true" datasources="rdf:null" flags="" id="root" ref="http://www.some-fictitious-zoo.com/birds"> +<treecols orient="horizontal" id="treecols"> +<treecol id="treecol" primary="true" label="Name"/> +<treecol label="Species"/> +</treecols> +<template id="template"> +<query> +<content uri="?uri"/> +<member container="?uri" child="?child"/> +<triple subject="?child" predicate="http://www.some-fictitious-zoo.com/rdf#name" object="?name"/> +</query> +<rule> +<bindings> +<binding subject="?child" predicate="http://www.some-fictitious-zoo.com/rdf#specimens" object="?specimens"/> +</bindings> +<action> +<treechildren> +<treeitem uri="?child"> +<treerow> +<treecell label="?name"/> +<treecell label="?specimens"/> +</treerow> +</treeitem> +</treechildren> +</action> +</rule> +</template> +</tree> + +</window> diff --git a/dom/xul/templates/tests/chrome/test_tmpl_treeelementquerysyntaxnotrecursive.xul b/dom/xul/templates/tests/chrome/test_tmpl_treeelementquerysyntaxnotrecursive.xul new file mode 100644 index 000000000..9a07372fe --- /dev/null +++ b/dom/xul/templates/tests/chrome/test_tmpl_treeelementquerysyntaxnotrecursive.xul @@ -0,0 +1,145 @@ +<?xml version="1.0"?> +<?xml-stylesheet href="chrome://global/skin" type="text/css"?> +<?xml-stylesheet href="chrome://mochikit/content/tests/SimpleTest/test.css" type="text/css"?> + +<!-- + tree element - query syntax not recursive +--> + +<window title="XUL Template Tests" width="500" height="600" + onload="test_template();" + xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"> + <script type="application/javascript" + src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script> + + <body xmlns="http://www.w3.org/1999/xhtml" style="height: 300px; overflow: auto;"/> + + <data id="output"> + <treecols id="treecols" orient="horizontal"> + <treecol id="treecol" primary="true" label="Name" ordinal="1"/> + <treecol label="Species" ordinal="3"/> + </treecols> + <treechildren> + <treeitem id="http://www.some-fictitious-zoo.com/humans/sarah"> + <treerow> + <treecell label="Sarah"/> + <treecell/> + </treerow> + </treeitem> + <treeitem step="-1" id="http://www.some-fictitious-zoo.com/mammals" container="true" empty="false"> + <treerow> + <treecell label="Mammals"/> + <treecell/> + </treerow> + </treeitem> + <treeitem step="1" id="http://www.some-fictitious-zoo.com/mammals" container="true" empty="false" open="true"> + <treerow> + <treecell label="Mammals"/> + <treecell/> + </treerow> + </treeitem> + <treeitem step="-4" id="http://www.some-fictitious-zoo.com/crustaceans" container="true" empty="true"> + <treerow> + <treecell label="Crustaceans"/> + <treecell/> + </treerow> + </treeitem> + <treeitem step="4" id="http://www.some-fictitious-zoo.com/crustaceans" container="true" empty="true"> + <treerow> + <treecell label="Crustaceans"/> + <treecell/> + </treerow> + </treeitem> + <treeitem id="http://www.some-fictitious-zoo.com/birds/emu"> + <treerow> + <treecell label="Emu"/> + <treecell/> + </treerow> + </treeitem> + </treechildren> + </data> + +<script src="templates_shared.js"/> + +<script> +<![CDATA[ +SimpleTest.waitForExplicitFinish(); + +var testid ="tree element - query syntax not recursive"; +var queryType = "rdf"; +var isTreeBuilder = false; +var needsOpen = false; +var notWorkingYet = false; +var notWorkingYetDynamic = true; +var expectedOutput = document.getElementById("output"); + +var changes = [ + // step 1 + function(targetds, root) { + if (root.view && 1 < root.view.rowCount && root.view.isContainer(1)) + root.view.toggleOpenState(1); + }, + // step 2 + function(targetds, root) { + var newnode = RDF.GetResource(ZOO_NS + 'mammals/koala'); + targetds.Assert(newnode, RDF.GetResource(ZOO_NS + 'rdf#name'), + RDF.GetLiteral('Koala'), true); + var container = ContainerUtils.MakeSeq(targetds, + RDF.GetResource(ZOO_NS + 'mammals')); + container.InsertElementAt(newnode, '4', true); + }, + // step 3 + function(targetds, root) { + var newnode = RDF.GetResource(ZOO_NS + 'crustaceans/lobster'); + targetds.Assert(newnode, RDF.GetResource(ZOO_NS + 'rdf#name'), + RDF.GetLiteral('Lobster'), true); + var container = ContainerUtils.MakeSeq(targetds, + RDF.GetResource(ZOO_NS + 'crustaceans')); + container.AppendElement(newnode); + }, + // step 4 + function(targetds, root) { + if (root.view && 11 < root.view.rowCount && root.view.isContainer(11)) + root.view.toggleOpenState(11); + }, + // step 5 + function(targetds, root) { + if (root.view && 11 < root.view.rowCount && root.view.isContainer(11)) + root.view.toggleOpenState(11); + }, + // step 6 + function(targetds, root) { + if (root.view && 1 < root.view.rowCount && root.view.isContainer(1)) + root.view.toggleOpenState(1); + } +]; +]]> +</script> + +<tree xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul" hidevscroll="true" hidehscroll="true" datasources="rdf:null" ref="http://www.some-fictitious-zoo.com/marked" flags="dont-recurse" id="root"> +<treecols orient="horizontal" id="treecols"> +<treecol id="treecol" primary="true" label="Name"/> +<treecol label="Species"/> +</treecols> +<template id="template"> +<query> +<content uri="?uri"/> +<member container="?uri" child="?child"/> +<triple subject="?child" predicate="http://www.some-fictitious-zoo.com/rdf#name" object="?name"/> +</query> +<rule> +<action> +<treechildren> +<treeitem uri="?child"> +<treerow> +<treecell label="?name"/> +<treecell/> +</treerow> +</treeitem> +</treechildren> +</action> +</rule> +</template> +</tree> + +</window> diff --git a/dom/xul/templates/tests/chrome/test_tmpl_treeelementquerysyntaxnotrecursivetreebuilder.xul b/dom/xul/templates/tests/chrome/test_tmpl_treeelementquerysyntaxnotrecursivetreebuilder.xul new file mode 100644 index 000000000..106d4d7cd --- /dev/null +++ b/dom/xul/templates/tests/chrome/test_tmpl_treeelementquerysyntaxnotrecursivetreebuilder.xul @@ -0,0 +1,145 @@ +<?xml version="1.0"?> +<?xml-stylesheet href="chrome://global/skin" type="text/css"?> +<?xml-stylesheet href="chrome://mochikit/content/tests/SimpleTest/test.css" type="text/css"?> + +<!-- + tree element - query syntax not recursive tree builder +--> + +<window title="XUL Template Tests" width="500" height="600" + onload="test_template();" + xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"> + <script type="application/javascript" + src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script> + + <body xmlns="http://www.w3.org/1999/xhtml" style="height: 300px; overflow: auto;"/> + + <data id="output"> + <treecols id="treecols" orient="horizontal"> + <treecol id="treecol" primary="true" label="Name" ordinal="1"/> + <treecol label="Species" ordinal="3"/> + </treecols> + <treechildren> + <treeitem id="http://www.some-fictitious-zoo.com/humans/sarah"> + <treerow> + <treecell label="Sarah"/> + <treecell/> + </treerow> + </treeitem> + <treeitem step="-1" id="http://www.some-fictitious-zoo.com/mammals" container="true" empty="true"> + <treerow> + <treecell label="Mammals"/> + <treecell/> + </treerow> + </treeitem> + <treeitem step="1" id="http://www.some-fictitious-zoo.com/mammals" container="true" empty="true" open=""> + <treerow> + <treecell label="Mammals"/> + <treecell/> + </treerow> + </treeitem> + <treeitem step="-4" id="http://www.some-fictitious-zoo.com/crustaceans" container="true" empty="true"> + <treerow> + <treecell label="Crustaceans"/> + <treecell/> + </treerow> + </treeitem> + <treeitem step="4" id="http://www.some-fictitious-zoo.com/crustaceans" container="true" empty="true"> + <treerow> + <treecell label="Crustaceans"/> + <treecell/> + </treerow> + </treeitem> + <treeitem id="http://www.some-fictitious-zoo.com/birds/emu"> + <treerow> + <treecell label="Emu"/> + <treecell/> + </treerow> + </treeitem> + </treechildren> + </data> + +<script src="templates_shared.js"/> + +<script> +<![CDATA[ +SimpleTest.waitForExplicitFinish(); + +var testid ="tree element - query syntax not recursive tree builder"; +var queryType = "rdf"; +var isTreeBuilder = true; +var needsOpen = false; +var notWorkingYet = false; +var notWorkingYetDynamic = false; +var expectedOutput = document.getElementById("output"); + +var changes = [ + // step 1 + function(targetds, root) { + if (root.view && 1 < root.view.rowCount && root.view.isContainer(1)) + root.view.toggleOpenState(1); + }, + // step 2 + function(targetds, root) { + var newnode = RDF.GetResource(ZOO_NS + 'mammals/koala'); + targetds.Assert(newnode, RDF.GetResource(ZOO_NS + 'rdf#name'), + RDF.GetLiteral('Koala'), true); + var container = ContainerUtils.MakeSeq(targetds, + RDF.GetResource(ZOO_NS + 'mammals')); + container.InsertElementAt(newnode, '4', true); + }, + // step 3 + function(targetds, root) { + var newnode = RDF.GetResource(ZOO_NS + 'crustaceans/lobster'); + targetds.Assert(newnode, RDF.GetResource(ZOO_NS + 'rdf#name'), + RDF.GetLiteral('Lobster'), true); + var container = ContainerUtils.MakeSeq(targetds, + RDF.GetResource(ZOO_NS + 'crustaceans')); + container.AppendElement(newnode); + }, + // step 4 + function(targetds, root) { + if (root.view && 11 < root.view.rowCount && root.view.isContainer(11)) + root.view.toggleOpenState(11); + }, + // step 5 + function(targetds, root) { + if (root.view && 11 < root.view.rowCount && root.view.isContainer(11)) + root.view.toggleOpenState(11); + }, + // step 6 + function(targetds, root) { + if (root.view && 1 < root.view.rowCount && root.view.isContainer(1)) + root.view.toggleOpenState(1); + } +]; +]]> +</script> + +<tree xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul" hidevscroll="true" hidehscroll="true" datasources="rdf:null" ref="http://www.some-fictitious-zoo.com/marked" flags="dont-recurse dont-build-content" id="root"> +<treecols orient="horizontal" id="treecols"> +<treecol id="treecol" primary="true" label="Name"/> +<treecol label="Species"/> +</treecols> +<template id="template"> +<query> +<content uri="?uri"/> +<member container="?uri" child="?child"/> +<triple subject="?child" predicate="http://www.some-fictitious-zoo.com/rdf#name" object="?name"/> +</query> +<rule> +<action> +<treechildren> +<treeitem uri="?child"> +<treerow> +<treecell label="?name"/> +<treecell/> +</treerow> +</treeitem> +</treechildren> +</action> +</rule> +</template> +</tree> + +</window> diff --git a/dom/xul/templates/tests/chrome/test_tmpl_treeelementquerysyntaxrecursive.xul b/dom/xul/templates/tests/chrome/test_tmpl_treeelementquerysyntaxrecursive.xul new file mode 100644 index 000000000..1002cd00c --- /dev/null +++ b/dom/xul/templates/tests/chrome/test_tmpl_treeelementquerysyntaxrecursive.xul @@ -0,0 +1,215 @@ +<?xml version="1.0"?> +<?xml-stylesheet href="chrome://global/skin" type="text/css"?> +<?xml-stylesheet href="chrome://mochikit/content/tests/SimpleTest/test.css" type="text/css"?> + +<!-- + tree element - query syntax recursive +--> + +<window title="XUL Template Tests" width="500" height="600" + onload="test_template();" + xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"> + <script type="application/javascript" + src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script> + + <body xmlns="http://www.w3.org/1999/xhtml" style="height: 300px; overflow: auto;"/> + + <data id="output"> + <treecols id="treecols" orient="horizontal"> + <treecol id="treecol" primary="true" label="Name" ordinal="1"/> + <treecol label="Species" ordinal="3"/> + </treecols> + <treechildren> + <treeitem id="http://www.some-fictitious-zoo.com/humans/sarah"> + <treerow> + <treecell label="Sarah"/> + <treecell/> + </treerow> + </treeitem> + <treeitem step="-1" id="http://www.some-fictitious-zoo.com/mammals" container="true" empty="false"> + <treerow> + <treecell label="Mammals"/> + <treecell/> + </treerow> + </treeitem> + <treeitem step="1" id="http://www.some-fictitious-zoo.com/mammals" container="true" empty="false" open="true"> + <treerow> + <treecell label="Mammals"/> + <treecell/> + </treerow> + <treechildren> + <treeitem id="http://www.some-fictitious-zoo.com/mammals/lion"> + <treerow> + <treecell label="Lion"/> + <treecell/> + </treerow> + </treeitem> + <treeitem id="http://www.some-fictitious-zoo.com/mammals/hippopotamus"> + <treerow> + <treecell label="HIPPOPOTAMUS"/> + <treecell/> + </treerow> + </treeitem> + <treeitem id="http://www.some-fictitious-zoo.com/mammals/africanelephant"> + <treerow> + <treecell label="African Elephant"/> + <treecell/> + </treerow> + </treeitem> + <treeitem step="2" id="http://www.some-fictitious-zoo.com/mammals/koala"> + <treerow> + <treecell label="Koala"/> + <treecell/> + </treerow> + </treeitem> + <treeitem id="http://www.some-fictitious-zoo.com/mammals/llama"> + <treerow> + <treecell label="LLAMA"/> + <treecell/> + </treerow> + </treeitem> + <treeitem id="http://www.some-fictitious-zoo.com/mammals/polarbear"> + <treerow> + <treecell label="Polar Bear"/> + <treecell/> + </treerow> + </treeitem> + <treeitem id="http://www.some-fictitious-zoo.com/mammals/aardvark"> + <treerow> + <treecell label="aardvark"/> + <treecell/> + </treerow> + </treeitem> + <treeitem id="http://www.some-fictitious-zoo.com/mammals/ninebandedarmadillo"> + <treerow> + <treecell label="Nine-banded Armadillo"/> + <treecell/> + </treerow> + </treeitem> + <treeitem id="http://www.some-fictitious-zoo.com/mammals/gorilla"> + <treerow> + <treecell label="Gorilla"/> + <treecell/> + </treerow> + </treeitem> + </treechildren> + </treeitem> + <treeitem step="-3" id="http://www.some-fictitious-zoo.com/crustaceans" container="true" empty="true"> + <treerow> + <treecell label="Crustaceans"/> + <treecell/> + </treerow> + </treeitem> + <treeitem step="3,-4" id="http://www.some-fictitious-zoo.com/crustaceans" container="true" empty="false"> + <treerow> + <treecell label="Crustaceans"/> + <treecell/> + </treerow> + </treeitem> + <treeitem step="4" id="http://www.some-fictitious-zoo.com/crustaceans" container="true" empty="false" open="true"> + <treerow> + <treecell label="Crustaceans"/> + <treecell/> + </treerow> + <treechildren> + <treeitem id="http://www.some-fictitious-zoo.com/crustaceans/lobster"> + <treerow> + <treecell label="Lobster"/> + <treecell/> + </treerow> + </treeitem> + </treechildren> + </treeitem> + <treeitem id="http://www.some-fictitious-zoo.com/birds/emu"> + <treerow> + <treecell label="Emu"/> + <treecell/> + </treerow> + </treeitem> + </treechildren> + </data> + +<script src="templates_shared.js"/> + +<script> +<![CDATA[ +SimpleTest.waitForExplicitFinish(); + +var testid ="tree element - query syntax recursive"; +var queryType = "rdf"; +var isTreeBuilder = false; +var needsOpen = false; +var notWorkingYet = false; +var notWorkingYetDynamic = true; +var expectedOutput = document.getElementById("output"); + +var changes = [ + // step 1 + function(targetds, root) { + if (root.view && 1 < root.view.rowCount && root.view.isContainer(1)) + root.view.toggleOpenState(1); + }, + // step 2 + function(targetds, root) { + var newnode = RDF.GetResource(ZOO_NS + 'mammals/koala'); + targetds.Assert(newnode, RDF.GetResource(ZOO_NS + 'rdf#name'), + RDF.GetLiteral('Koala'), true); + var container = ContainerUtils.MakeSeq(targetds, + RDF.GetResource(ZOO_NS + 'mammals')); + container.InsertElementAt(newnode, '4', true); + }, + // step 3 + function(targetds, root) { + var newnode = RDF.GetResource(ZOO_NS + 'crustaceans/lobster'); + targetds.Assert(newnode, RDF.GetResource(ZOO_NS + 'rdf#name'), + RDF.GetLiteral('Lobster'), true); + var container = ContainerUtils.MakeSeq(targetds, + RDF.GetResource(ZOO_NS + 'crustaceans')); + container.AppendElement(newnode); + }, + // step 4 + function(targetds, root) { + if (root.view && 11 < root.view.rowCount && root.view.isContainer(11)) + root.view.toggleOpenState(11); + }, + // step 5 + function(targetds, root) { + if (root.view && 11 < root.view.rowCount && root.view.isContainer(11)) + root.view.toggleOpenState(11); + }, + // step 6 + function(targetds, root) { + if (root.view && 1 < root.view.rowCount && root.view.isContainer(1)) + root.view.toggleOpenState(1); + } +]; +]]> +</script> + +<tree xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul" hidevscroll="true" hidehscroll="true" datasources="rdf:null" ref="http://www.some-fictitious-zoo.com/marked" id="root"> +<treecols orient="horizontal" id="treecols"> +<treecol id="treecol" primary="true" label="Name"/> +<treecol label="Species"/> +</treecols> +<template id="template"> +<query> +<content uri="?uri"/> +<member container="?uri" child="?child"/> +<triple subject="?child" predicate="http://www.some-fictitious-zoo.com/rdf#name" object="?name"/> +</query> +<rule> +<action> +<treechildren> +<treeitem uri="?child"> +<treerow> +<treecell label="?name"/> +<treecell/> +</treerow> +</treeitem> +</treechildren> +</action> +</rule> +</template> +</tree> + +</window> diff --git a/dom/xul/templates/tests/chrome/test_tmpl_treeelementquerysyntaxrecursivemultiplerules.xul b/dom/xul/templates/tests/chrome/test_tmpl_treeelementquerysyntaxrecursivemultiplerules.xul new file mode 100644 index 000000000..282beb69d --- /dev/null +++ b/dom/xul/templates/tests/chrome/test_tmpl_treeelementquerysyntaxrecursivemultiplerules.xul @@ -0,0 +1,268 @@ +<?xml version="1.0"?> +<?xml-stylesheet href="chrome://global/skin" type="text/css"?> +<?xml-stylesheet href="chrome://mochikit/content/tests/SimpleTest/test.css" type="text/css"?> + +<!-- + tree element - query syntax recursive multiple rules +--> + +<window title="XUL Template Tests" width="500" height="600" + onload="test_template();" + xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"> + <script type="application/javascript" + src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script> + + <body xmlns="http://www.w3.org/1999/xhtml" style="height: 300px; overflow: auto;"/> + + <data id="output"> + <treecols id="treecols" orient="horizontal"> + <treecol id="treecol" primary="true" label="Name" ordinal="1"/> + <treecol label="Species" ordinal="3"/> + </treecols> + <treechildren> + <treeitem id="http://www.some-fictitious-zoo.com/humans/sarah"> + <treerow> + <treecell label="Sarah"/> + <treecell/> + </treerow> + </treeitem> + <treeitem step="-1" id="http://www.some-fictitious-zoo.com/mammals" container="true" empty="false"> + <treerow> + <treecell/> + <treecell label="Is this cool: Mammals?"/> + </treerow> + </treeitem> + <treeitem step="1" id="http://www.some-fictitious-zoo.com/mammals" container="true" empty="false" open="true"> + <treerow> + <treecell/> + <treecell label="Is this cool: Mammals?"/> + </treerow> + <treechildren> + <treeitem id="http://www.some-fictitious-zoo.com/mammals/lion"> + <treerow> + <treecell/> + <treecell label="Is this cool: Lion?"/> + </treerow> + </treeitem> + <treeitem id="http://www.some-fictitious-zoo.com/mammals/hippopotamus"> + <treerow> + <treecell label="HIPPOPOTAMUS"/> + <treecell/> + </treerow> + </treeitem> + <treeitem id="http://www.some-fictitious-zoo.com/mammals/africanelephant"> + <treerow> + <treecell/> + <treecell label="Is this cool: African Elephant?"/> + </treerow> + </treeitem> + <treeitem step="2" id="http://www.some-fictitious-zoo.com/mammals/koala"> + <treerow> + <treecell/> + <treecell label="Is this cool: Koala?"/> + </treerow> + </treeitem> + <treeitem id="http://www.some-fictitious-zoo.com/mammals/llama"> + <treerow> + <treecell/> + <treecell label="Is this cool: LLAMA?"/> + </treerow> + </treeitem> + <treeitem id="http://www.some-fictitious-zoo.com/mammals/polarbear"> + <treerow> + <treecell/> + <treecell label="Is this cool: Polar Bear?"/> + </treerow> + </treeitem> + <treeitem id="http://www.some-fictitious-zoo.com/mammals/aardvark"> + <treerow> + <treecell label="aardvark"/> + <treecell/> + </treerow> + </treeitem> + <treeitem id="http://www.some-fictitious-zoo.com/mammals/ninebandedarmadillo"> + <treerow> + <treecell/> + <treecell label="Is this cool: Nine-banded Armadillo?"/> + </treerow> + </treeitem> + <treeitem id="http://www.some-fictitious-zoo.com/mammals/gorilla"> + <treerow> + <treecell/> + <treecell label="Is this cool: Gorilla?"/> + </treerow> + </treeitem> + </treechildren> + </treeitem> + <treeitem step="-3" id="http://www.some-fictitious-zoo.com/crustaceans" container="true" empty="true"> + <treerow> + <treecell label="Crustaceans"/> + <treecell/> + </treerow> + </treeitem> + <treeitem step="3,-4" id="http://www.some-fictitious-zoo.com/crustaceans" container="true" empty="false"> + <treerow> + <treecell label="Crustaceans"/> + <treecell/> + </treerow> + </treeitem> + <treeitem step="5" id="http://www.some-fictitious-zoo.com/crustaceans" container="true" empty="false" open="true"> + <treerow> + <treecell label="Crustaceans"/> + <treecell/> + </treerow> + <treechildren> + <treeitem id="http://www.some-fictitious-zoo.com/crustaceans/lobster"> + <treerow> + <treecell/> + <treecell label="Is this cool: Lobster?"/> + </treerow> + </treeitem> + <treeitem id="http://www.some-fictitious-zoo.com/crustaceans/crayfish"> + <treerow> + <treecell label="Crayfish"/> + <treecell/> + </treerow> + </treeitem> + </treechildren> + </treeitem> + <treeitem id="http://www.some-fictitious-zoo.com/birds/emu"> + <treerow> + <treecell label="Emu"/> + <treecell/> + </treerow> + </treeitem> + </treechildren> + </data> + +<script src="templates_shared.js"/> + +<script> +<![CDATA[ +SimpleTest.waitForExplicitFinish(); + +var testid ="tree element - query syntax recursive multiple rules"; +var queryType = "rdf"; +var isTreeBuilder = false; +var needsOpen = false; +var notWorkingYet = false; +var notWorkingYetDynamic = true; +var expectedOutput = document.getElementById("output"); + +var changes = [ + // step 1 + function(targetds, root) { + if (root.view && 1 < root.view.rowCount && root.view.isContainer(1)) + root.view.toggleOpenState(1); + expectConsoleMessage(ZOO_NS + 'mammals', ZOO_NS + 'mammals/lion', true, true, + '1 matching rule 1'); + expectConsoleMessage(ZOO_NS + 'mammals', ZOO_NS + 'mammals/hippopotamus', true, true, + '1 matching rule 2'); + expectConsoleMessage(ZOO_NS + 'mammals', ZOO_NS + 'mammals/africanelephant', true, true, + '1 matching rule 1'); + expectConsoleMessage(ZOO_NS + 'mammals', ZOO_NS + 'mammals/llama', true, true, + '1 matching rule 1'); + expectConsoleMessage(ZOO_NS + 'mammals', ZOO_NS + 'mammals/polarbear', true, true, + '1 matching rule 1'); + expectConsoleMessage(ZOO_NS + 'mammals', ZOO_NS + 'mammals/aardvark', true, true, + '1 matching rule 2'); + expectConsoleMessage(ZOO_NS + 'mammals', ZOO_NS + 'mammals/ninebandedarmadillo', true, true, + '1 matching rule 1'); + expectConsoleMessage(ZOO_NS + 'mammals', ZOO_NS + 'mammals/gorilla', true, true, + '1 matching rule 1'); + }, + // step 2 + function(targetds, root) { + var newnode = RDF.GetResource(ZOO_NS + 'mammals/koala'); + targetds.Assert(newnode, RDF.GetResource(ZOO_NS + 'rdf#name'), + RDF.GetLiteral('Koala'), true); + var container = ContainerUtils.MakeSeq(targetds, + RDF.GetResource(ZOO_NS + 'mammals')); + container.InsertElementAt(newnode, '4', true); + expectConsoleMessage(ZOO_NS + 'mammals', ZOO_NS + 'mammals/koala', true, true, + '1 matching rule 1'); + }, + // step 3 + function(targetds, root) { + var newnode = RDF.GetResource(ZOO_NS + 'crustaceans/lobster'); + targetds.Assert(newnode, RDF.GetResource(ZOO_NS + 'rdf#name'), + RDF.GetLiteral('Lobster'), true); + var container = ContainerUtils.MakeSeq(targetds, + RDF.GetResource(ZOO_NS + 'crustaceans')); + container.AppendElement(newnode); + }, + // step 4 + function(targetds, root) { + var newnode = RDF.GetResource(ZOO_NS + 'crustaceans/crayfish'); + targetds.Assert(newnode, RDF.GetResource(ZOO_NS + 'rdf#name'), + RDF.GetLiteral('Crayfish'), true); + var container = ContainerUtils.MakeSeq(targetds, + RDF.GetResource(ZOO_NS + 'crustaceans')); + container.AppendElement(newnode); + }, + // step 5 + function(targetds, root) { + if (root.view && 11 < root.view.rowCount && root.view.isContainer(11)) + root.view.toggleOpenState(11); + expectConsoleMessage(ZOO_NS + 'crustaceans', ZOO_NS + 'crustaceans/lobster', true, true, + '1 matching rule 1'); + expectConsoleMessage(ZOO_NS + 'crustaceans', ZOO_NS + 'crustaceans/crayfish', true, true, + '1 matching rule 2'); + }, + // step 6 + function(targetds, root) { + if (root.view && 11 < root.view.rowCount && root.view.isContainer(11)) + root.view.toggleOpenState(11); + }, + // step 7 + function(targetds, root) { + if (root.view && 1 < root.view.rowCount && root.view.isContainer(1)) + root.view.toggleOpenState(1); + } +]; +]]> +</script> + +<tree xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul" hidevscroll="true" hidehscroll="true" + flags="logging" datasources="rdf:null" ref="http://www.some-fictitious-zoo.com/marked" id="root"> +<treecols orient="horizontal" id="treecols"> +<treecol id="treecol" primary="true" label="Name"/> +<treecol label="Species"/> +</treecols> +<template id="template"> +<query> +<content uri="?uri"/> +<member container="?uri" child="?child"/> +<triple subject="?child" predicate="http://www.some-fictitious-zoo.com/rdf#name" object="?name"/> +</query> +<rule> +<conditions> +<where subject="?name" rel="contains" value="l" ignorecase="true"/> +</conditions> +<action> +<treechildren> +<treeitem uri="?child"> +<treerow> +<treecell/> +<treecell label="Is this cool: ?name^??"/> +</treerow> +</treeitem> +</treechildren> +</action> +</rule> +<rule> +<action> +<treechildren> +<treeitem uri="?child"> +<treerow> +<treecell label="?name"/> +<treecell/> +</treerow> +</treeitem> +</treechildren> +</action> +</rule> +</template> +</tree> + +</window> diff --git a/dom/xul/templates/tests/chrome/test_tmpl_treeelementquerysyntaxrecursivemultiplerulestreebuilder.xul b/dom/xul/templates/tests/chrome/test_tmpl_treeelementquerysyntaxrecursivemultiplerulestreebuilder.xul new file mode 100644 index 000000000..8c9e5c012 --- /dev/null +++ b/dom/xul/templates/tests/chrome/test_tmpl_treeelementquerysyntaxrecursivemultiplerulestreebuilder.xul @@ -0,0 +1,230 @@ +<?xml version="1.0"?> +<?xml-stylesheet href="chrome://global/skin" type="text/css"?> +<?xml-stylesheet href="chrome://mochikit/content/tests/SimpleTest/test.css" type="text/css"?> + +<!-- + tree element - query syntax recursive multiple rules tree builder +--> + +<window title="XUL Template Tests" width="500" height="600" + onload="test_template();" + xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"> + <script type="application/javascript" + src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script> + + <body xmlns="http://www.w3.org/1999/xhtml" style="height: 300px; overflow: auto;"/> + + <data id="output"> + <treecols id="treecols" orient="horizontal"> + <treecol id="treecol" primary="true" label="Name" ordinal="1"/> + <treecol label="Species" ordinal="3"/> + </treecols> + <treechildren> + <treeitem id="http://www.some-fictitious-zoo.com/humans/sarah"> + <treerow> + <treecell label="Sarah"/> + <treecell/> + </treerow> + </treeitem> + <treeitem step="-1" id="http://www.some-fictitious-zoo.com/mammals" container="true" empty="false"> + <treerow> + <treecell/> + <treecell label="Is this cool: Mammals?"/> + </treerow> + </treeitem> + <treeitem step="1" id="http://www.some-fictitious-zoo.com/mammals" container="true" empty="false" open="true"> + <treerow> + <treecell/> + <treecell label="Is this cool: Mammals?"/> + </treerow> + <treechildren> + <treeitem id="http://www.some-fictitious-zoo.com/mammals/lion"> + <treerow> + <treecell/> + <treecell label="Is this cool: Lion?"/> + </treerow> + </treeitem> + <treeitem id="http://www.some-fictitious-zoo.com/mammals/hippopotamus"> + <treerow> + <treecell label="HIPPOPOTAMUS"/> + <treecell/> + </treerow> + </treeitem> + <treeitem id="http://www.some-fictitious-zoo.com/mammals/africanelephant"> + <treerow> + <treecell/> + <treecell label="Is this cool: African Elephant?"/> + </treerow> + </treeitem> + <treeitem step="2" id="http://www.some-fictitious-zoo.com/mammals/koala"> + <treerow> + <treecell/> + <treecell label="Is this cool: Koala?"/> + </treerow> + </treeitem> + <treeitem id="http://www.some-fictitious-zoo.com/mammals/llama"> + <treerow> + <treecell/> + <treecell label="Is this cool: LLAMA?"/> + </treerow> + </treeitem> + <treeitem id="http://www.some-fictitious-zoo.com/mammals/polarbear"> + <treerow> + <treecell/> + <treecell label="Is this cool: Polar Bear?"/> + </treerow> + </treeitem> + <treeitem id="http://www.some-fictitious-zoo.com/mammals/aardvark"> + <treerow> + <treecell label="aardvark"/> + <treecell/> + </treerow> + </treeitem> + <treeitem id="http://www.some-fictitious-zoo.com/mammals/ninebandedarmadillo"> + <treerow> + <treecell/> + <treecell label="Is this cool: Nine-banded Armadillo?"/> + </treerow> + </treeitem> + <treeitem id="http://www.some-fictitious-zoo.com/mammals/gorilla"> + <treerow> + <treecell/> + <treecell label="Is this cool: Gorilla?"/> + </treerow> + </treeitem> + </treechildren> + </treeitem> + <treeitem step="-3" id="http://www.some-fictitious-zoo.com/crustaceans" container="true" empty="true"> + <treerow> + <treecell label="Crustaceans"/> + <treecell/> + </treerow> + </treeitem> + <treeitem step="3,-4" id="http://www.some-fictitious-zoo.com/crustaceans" container="true" empty="false"> + <treerow> + <treecell label="Crustaceans"/> + <treecell/> + </treerow> + </treeitem> + <treeitem step="4" id="http://www.some-fictitious-zoo.com/crustaceans" container="true" empty="false" open="true"> + <treerow> + <treecell label="Crustaceans"/> + <treecell/> + </treerow> + <treechildren> + <treeitem id="http://www.some-fictitious-zoo.com/crustaceans/lobster"> + <treerow> + <treecell/> + <treecell label="Is this cool: Lobster?"/> + </treerow> + </treeitem> + </treechildren> + </treeitem> + <treeitem id="http://www.some-fictitious-zoo.com/birds/emu"> + <treerow> + <treecell label="Emu"/> + <treecell/> + </treerow> + </treeitem> + </treechildren> + </data> + +<script src="templates_shared.js"/> + +<script> +<![CDATA[ +SimpleTest.waitForExplicitFinish(); + +var testid ="tree element - query syntax recursive multiple rules tree builder"; +var queryType = "rdf"; +var isTreeBuilder = true; +var needsOpen = false; +var notWorkingYet = false; +var notWorkingYetDynamic = true; +var expectedOutput = document.getElementById("output"); + +var changes = [ + // step 1 + function(targetds, root) { + if (root.view && 1 < root.view.rowCount && root.view.isContainer(1)) + root.view.toggleOpenState(1); + }, + // step 2 + function(targetds, root) { + var newnode = RDF.GetResource(ZOO_NS + 'mammals/koala'); + targetds.Assert(newnode, RDF.GetResource(ZOO_NS + 'rdf#name'), + RDF.GetLiteral('Koala'), true); + var container = ContainerUtils.MakeSeq(targetds, + RDF.GetResource(ZOO_NS + 'mammals')); + container.InsertElementAt(newnode, '4', true); + }, + // step 3 + function(targetds, root) { + var newnode = RDF.GetResource(ZOO_NS + 'crustaceans/lobster'); + targetds.Assert(newnode, RDF.GetResource(ZOO_NS + 'rdf#name'), + RDF.GetLiteral('Lobster'), true); + var container = ContainerUtils.MakeSeq(targetds, + RDF.GetResource(ZOO_NS + 'crustaceans')); + container.AppendElement(newnode); + }, + // step 4 + function(targetds, root) { + if (root.view && 11 < root.view.rowCount && root.view.isContainer(11)) + root.view.toggleOpenState(11); + }, + // step 5 + function(targetds, root) { + if (root.view && 11 < root.view.rowCount && root.view.isContainer(11)) + root.view.toggleOpenState(11); + }, + // step 6 + function(targetds, root) { + if (root.view && 1 < root.view.rowCount && root.view.isContainer(1)) + root.view.toggleOpenState(1); + } +]; +]]> +</script> + +<tree xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul" hidevscroll="true" hidehscroll="true" datasources="rdf:null" ref="http://www.some-fictitious-zoo.com/marked" flags=" dont-build-content" id="root"> +<treecols orient="horizontal" id="treecols"> +<treecol id="treecol" primary="true" label="Name"/> +<treecol label="Species"/> +</treecols> +<template id="template"> +<query> +<content uri="?uri"/> +<member container="?uri" child="?child"/> +<triple subject="?child" predicate="http://www.some-fictitious-zoo.com/rdf#name" object="?name"/> +</query> +<rule> +<conditions> +<where subject="?name" rel="contains" value="l" ignorecase="true"/> +</conditions> +<action> +<treechildren> +<treeitem uri="?child"> +<treerow> +<treecell/> +<treecell label="Is this cool: ?name^??"/> +</treerow> +</treeitem> +</treechildren> +</action> +</rule> +<rule> +<action> +<treechildren> +<treeitem uri="?child"> +<treerow> +<treecell label="?name"/> +<treecell/> +</treerow> +</treeitem> +</treechildren> +</action> +</rule> +</template> +</tree> + +</window> diff --git a/dom/xul/templates/tests/chrome/test_tmpl_treeelementquerysyntaxrecursivetreebuilder.xul b/dom/xul/templates/tests/chrome/test_tmpl_treeelementquerysyntaxrecursivetreebuilder.xul new file mode 100644 index 000000000..387279240 --- /dev/null +++ b/dom/xul/templates/tests/chrome/test_tmpl_treeelementquerysyntaxrecursivetreebuilder.xul @@ -0,0 +1,215 @@ +<?xml version="1.0"?> +<?xml-stylesheet href="chrome://global/skin" type="text/css"?> +<?xml-stylesheet href="chrome://mochikit/content/tests/SimpleTest/test.css" type="text/css"?> + +<!-- + tree element - query syntax recursive tree builder +--> + +<window title="XUL Template Tests" width="500" height="600" + onload="test_template();" + xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"> + <script type="application/javascript" + src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script> + + <body xmlns="http://www.w3.org/1999/xhtml" style="height: 300px; overflow: auto;"/> + + <data id="output"> + <treecols id="treecols" orient="horizontal"> + <treecol id="treecol" primary="true" label="Name" ordinal="1"/> + <treecol label="Species" ordinal="3"/> + </treecols> + <treechildren> + <treeitem id="http://www.some-fictitious-zoo.com/humans/sarah"> + <treerow> + <treecell label="Sarah"/> + <treecell/> + </treerow> + </treeitem> + <treeitem step="-1" id="http://www.some-fictitious-zoo.com/mammals" container="true" empty="false"> + <treerow> + <treecell label="Mammals"/> + <treecell/> + </treerow> + </treeitem> + <treeitem step="1" id="http://www.some-fictitious-zoo.com/mammals" container="true" empty="false" open="true"> + <treerow> + <treecell label="Mammals"/> + <treecell/> + </treerow> + <treechildren> + <treeitem id="http://www.some-fictitious-zoo.com/mammals/lion"> + <treerow> + <treecell label="Lion"/> + <treecell/> + </treerow> + </treeitem> + <treeitem id="http://www.some-fictitious-zoo.com/mammals/hippopotamus"> + <treerow> + <treecell label="HIPPOPOTAMUS"/> + <treecell/> + </treerow> + </treeitem> + <treeitem id="http://www.some-fictitious-zoo.com/mammals/africanelephant"> + <treerow> + <treecell label="African Elephant"/> + <treecell/> + </treerow> + </treeitem> + <treeitem step="2" id="http://www.some-fictitious-zoo.com/mammals/koala"> + <treerow> + <treecell label="Koala"/> + <treecell/> + </treerow> + </treeitem> + <treeitem id="http://www.some-fictitious-zoo.com/mammals/llama"> + <treerow> + <treecell label="LLAMA"/> + <treecell/> + </treerow> + </treeitem> + <treeitem id="http://www.some-fictitious-zoo.com/mammals/polarbear"> + <treerow> + <treecell label="Polar Bear"/> + <treecell/> + </treerow> + </treeitem> + <treeitem id="http://www.some-fictitious-zoo.com/mammals/aardvark"> + <treerow> + <treecell label="aardvark"/> + <treecell/> + </treerow> + </treeitem> + <treeitem id="http://www.some-fictitious-zoo.com/mammals/ninebandedarmadillo"> + <treerow> + <treecell label="Nine-banded Armadillo"/> + <treecell/> + </treerow> + </treeitem> + <treeitem id="http://www.some-fictitious-zoo.com/mammals/gorilla"> + <treerow> + <treecell label="Gorilla"/> + <treecell/> + </treerow> + </treeitem> + </treechildren> + </treeitem> + <treeitem step="-3" id="http://www.some-fictitious-zoo.com/crustaceans" container="true" empty="true"> + <treerow> + <treecell label="Crustaceans"/> + <treecell/> + </treerow> + </treeitem> + <treeitem step="3,-4" id="http://www.some-fictitious-zoo.com/crustaceans" container="true" empty="false"> + <treerow> + <treecell label="Crustaceans"/> + <treecell/> + </treerow> + </treeitem> + <treeitem step="4" id="http://www.some-fictitious-zoo.com/crustaceans" container="true" empty="false" open="true"> + <treerow> + <treecell label="Crustaceans"/> + <treecell/> + </treerow> + <treechildren> + <treeitem id="http://www.some-fictitious-zoo.com/crustaceans/lobster"> + <treerow> + <treecell label="Lobster"/> + <treecell/> + </treerow> + </treeitem> + </treechildren> + </treeitem> + <treeitem id="http://www.some-fictitious-zoo.com/birds/emu"> + <treerow> + <treecell label="Emu"/> + <treecell/> + </treerow> + </treeitem> + </treechildren> + </data> + +<script src="templates_shared.js"/> + +<script> +<![CDATA[ +SimpleTest.waitForExplicitFinish(); + +var testid ="tree element - query syntax recursive tree builder"; +var queryType = "rdf"; +var isTreeBuilder = true; +var needsOpen = false; +var notWorkingYet = false; +var notWorkingYetDynamic = true; +var expectedOutput = document.getElementById("output"); + +var changes = [ + // step 1 + function(targetds, root) { + if (root.view && 1 < root.view.rowCount && root.view.isContainer(1)) + root.view.toggleOpenState(1); + }, + // step 2 + function(targetds, root) { + var newnode = RDF.GetResource(ZOO_NS + 'mammals/koala'); + targetds.Assert(newnode, RDF.GetResource(ZOO_NS + 'rdf#name'), + RDF.GetLiteral('Koala'), true); + var container = ContainerUtils.MakeSeq(targetds, + RDF.GetResource(ZOO_NS + 'mammals')); + container.InsertElementAt(newnode, '4', true); + }, + // step 3 + function(targetds, root) { + var newnode = RDF.GetResource(ZOO_NS + 'crustaceans/lobster'); + targetds.Assert(newnode, RDF.GetResource(ZOO_NS + 'rdf#name'), + RDF.GetLiteral('Lobster'), true); + var container = ContainerUtils.MakeSeq(targetds, + RDF.GetResource(ZOO_NS + 'crustaceans')); + container.AppendElement(newnode); + }, + // step 4 + function(targetds, root) { + if (root.view && 11 < root.view.rowCount && root.view.isContainer(11)) + root.view.toggleOpenState(11); + }, + // step 5 + function(targetds, root) { + if (root.view && 11 < root.view.rowCount && root.view.isContainer(11)) + root.view.toggleOpenState(11); + }, + // step 6 + function(targetds, root) { + if (root.view && 1 < root.view.rowCount && root.view.isContainer(1)) + root.view.toggleOpenState(1); + } +]; +]]> +</script> + +<tree xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul" hidevscroll="true" hidehscroll="true" datasources="rdf:null" ref="http://www.some-fictitious-zoo.com/marked" flags=" dont-build-content" id="root"> +<treecols orient="horizontal" id="treecols"> +<treecol id="treecol" primary="true" label="Name"/> +<treecol label="Species"/> +</treecols> +<template id="template"> +<query> +<content uri="?uri"/> +<member container="?uri" child="?child"/> +<triple subject="?child" predicate="http://www.some-fictitious-zoo.com/rdf#name" object="?name"/> +</query> +<rule> +<action> +<treechildren> +<treeitem uri="?child"> +<treerow> +<treecell label="?name"/> +<treecell/> +</treerow> +</treeitem> +</treechildren> +</action> +</rule> +</template> +</tree> + +</window> diff --git a/dom/xul/templates/tests/chrome/test_tmpl_treeelementquerysyntaxtreebuilder.xul b/dom/xul/templates/tests/chrome/test_tmpl_treeelementquerysyntaxtreebuilder.xul new file mode 100644 index 000000000..e857c8e0e --- /dev/null +++ b/dom/xul/templates/tests/chrome/test_tmpl_treeelementquerysyntaxtreebuilder.xul @@ -0,0 +1,158 @@ +<?xml version="1.0"?> +<?xml-stylesheet href="chrome://global/skin" type="text/css"?> +<?xml-stylesheet href="chrome://mochikit/content/tests/SimpleTest/test.css" type="text/css"?> + +<!-- + tree element - query syntax tree builder +--> + +<window title="XUL Template Tests" width="500" height="600" + onload="test_template();" + xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"> + <script type="application/javascript" + src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script> + + <body xmlns="http://www.w3.org/1999/xhtml" style="height: 300px; overflow: auto;"/> + + <data id="output"> + <treecols id="treecols" orient="horizontal"> + <treecol id="treecol" primary="true" label="Name" ordinal="1"/> + <treecol label="Species" ordinal="3"/> + </treecols> + <treechildren> + <treeitem id="http://www.some-fictitious-zoo.com/birds/emu"> + <treerow> + <treecell label="Emu"/> + <treecell step="-6" label="12"/> + <treecell step="6" label="0"/> + </treerow> + </treeitem> + <treeitem step="1" id="http://www.some-fictitious-zoo.com/birds/archaeopteryx"> + <treerow> + <treecell label="Archaeopteryx"/> + <treecell step="-4"/> + <treecell step="4" label="5"/> + </treerow> + </treeitem> + <treeitem step="-2" id="http://www.some-fictitious-zoo.com/birds/barnowl"> + <treerow> + <treecell label="Barn Owl"/> + <treecell label="4"/> + </treerow> + </treeitem> + <treeitem id="http://www.some-fictitious-zoo.com/birds/raven"> + <treerow> + <treecell step="-7" label="Raven"/> + <treecell step="7" label="Crow"/> + <treecell step="-5" label="0"/> + <treecell step="5" label="2"/> + </treerow> + </treeitem> + </treechildren> + </data> + +<script src="templates_shared.js"/> + +<script> +<![CDATA[ +SimpleTest.waitForExplicitFinish(); + +var testid ="tree element - query syntax tree builder"; +var queryType = "rdf"; +var isTreeBuilder = true; +var needsOpen = false; +var notWorkingYet = false; +var notWorkingYetDynamic = true; +var expectedOutput = document.getElementById("output"); + +var changes = [ + // step 1 + function(targetds, root) { + var newnode = RDF.GetResource(ZOO_NS + 'birds/archaeopteryx'); + targetds.Assert(newnode, RDF.GetResource(ZOO_NS + 'rdf#name'), + RDF.GetLiteral('Archaeopteryx'), true); + var container = ContainerUtils.MakeSeq(targetds, + RDF.GetResource(ZOO_NS + 'birds')); + container.InsertElementAt(newnode, '2', true); + }, + // step 2 + function(targetds, root) { + var container = ContainerUtils.MakeSeq(targetds, + RDF.GetResource(ZOO_NS + 'birds')); + var removednode = container.RemoveElementAt('3', true); + targetds.Unassert(removednode, RDF.GetResource(ZOO_NS + 'rdf#name'), + RDF.GetLiteral('Barn Owl'), true); + }, + // step 3 + function(targetds, root) { + targetds.Assert(RDF.GetResource(ZOO_NS + 'birds/archaeopteryx'), + RDF.GetResource(ZOO_NS + 'rdf#species'), + RDF.GetLiteral('Archaeopteryx lithographica'), true); + }, + // step 4 + function(targetds, root) { + targetds.Assert(RDF.GetResource(ZOO_NS + 'birds/archaeopteryx'), + RDF.GetResource(ZOO_NS + 'rdf#specimens'), + RDF.GetLiteral('5'), true); + }, + // step 5 + function(targetds, root) { + var subject = RDF.GetResource(ZOO_NS + 'birds/raven'); + var predicate = RDF.GetResource(ZOO_NS + 'rdf#specimens'); + var oldval = targetds.GetTarget(subject, predicate, true); + targetds.Change(RDF.GetResource(ZOO_NS + 'birds/raven'), + RDF.GetResource(ZOO_NS + 'rdf#specimens'), + oldval, RDF.GetLiteral('2')); + }, + // step 6 + function(targetds, root) { + var subject = RDF.GetResource(ZOO_NS + 'birds/emu'); + var predicate = RDF.GetResource(ZOO_NS + 'rdf#specimens'); + var oldval = targetds.GetTarget(subject, predicate, true); + targetds.Change(RDF.GetResource(ZOO_NS + 'birds/emu'), + RDF.GetResource(ZOO_NS + 'rdf#specimens'), + oldval, RDF.GetLiteral('0')); + }, + // step 7 + function(targetds, root) { + var subject = RDF.GetResource(ZOO_NS + 'birds/raven'); + var predicate = RDF.GetResource(ZOO_NS + 'rdf#name'); + var oldval = targetds.GetTarget(subject, predicate, true); + targetds.Change(RDF.GetResource(ZOO_NS + 'birds/raven'), + RDF.GetResource(ZOO_NS + 'rdf#name'), + oldval, RDF.GetLiteral('Crow')); + } +]; +]]> +</script> + +<tree xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul" hidevscroll="true" hidehscroll="true" datasources="rdf:null" flags="dont-build-content" id="root" ref="http://www.some-fictitious-zoo.com/birds"> +<treecols orient="horizontal" id="treecols"> +<treecol id="treecol" primary="true" label="Name"/> +<treecol label="Species"/> +</treecols> +<template id="template"> +<query> +<content uri="?uri"/> +<member container="?uri" child="?child"/> +<triple subject="?child" predicate="http://www.some-fictitious-zoo.com/rdf#name" object="?name"/> +</query> +<rule> +<bindings> +<binding subject="?child" predicate="http://www.some-fictitious-zoo.com/rdf#specimens" object="?specimens"/> +</bindings> +<action> +<treechildren> +<treeitem uri="?child"> +<treerow> +<treecell label="?name"/> +<treecell label="?specimens"/> +</treerow> +</treeitem> +</treechildren> +</action> +</rule> +</template> +</tree> + +</window> diff --git a/dom/xul/templates/tests/chrome/test_tmpl_treeelementsimplesyntaxnotrecursive.xul b/dom/xul/templates/tests/chrome/test_tmpl_treeelementsimplesyntaxnotrecursive.xul new file mode 100644 index 000000000..ff447916e --- /dev/null +++ b/dom/xul/templates/tests/chrome/test_tmpl_treeelementsimplesyntaxnotrecursive.xul @@ -0,0 +1,136 @@ +<?xml version="1.0"?> +<?xml-stylesheet href="chrome://global/skin" type="text/css"?> +<?xml-stylesheet href="chrome://mochikit/content/tests/SimpleTest/test.css" type="text/css"?> + +<!-- + tree element - simple syntax not recursive +--> + +<window title="XUL Template Tests" width="500" height="600" + onload="test_template();" + xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"> + <script type="application/javascript" + src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script> + + <body xmlns="http://www.w3.org/1999/xhtml" style="height: 300px; overflow: auto;"/> + + <data id="output"> + <treecols id="treecols" orient="horizontal"> + <treecol id="treecol" primary="true" label="Name" ordinal="1"/> + <treecol label="Species" ordinal="3"/> + </treecols> + <treechildren> + <treeitem id="http://www.some-fictitious-zoo.com/humans/sarah"> + <treerow> + <treecell label="Sarah"/> + <treecell/> + </treerow> + </treeitem> + <treeitem step="-1" id="http://www.some-fictitious-zoo.com/mammals" container="true" empty="false"> + <treerow> + <treecell label="Mammals"/> + <treecell/> + </treerow> + </treeitem> + <treeitem step="1" id="http://www.some-fictitious-zoo.com/mammals" container="true" empty="false" open="true"> + <treerow> + <treecell label="Mammals"/> + <treecell/> + </treerow> + </treeitem> + <treeitem step="-4" id="http://www.some-fictitious-zoo.com/crustaceans" container="true" empty="true"> + <treerow> + <treecell label="Crustaceans"/> + <treecell/> + </treerow> + </treeitem> + <treeitem step="4" id="http://www.some-fictitious-zoo.com/crustaceans" container="true" empty="true"> + <treerow> + <treecell label="Crustaceans"/> + <treecell/> + </treerow> + </treeitem> + <treeitem id="http://www.some-fictitious-zoo.com/birds/emu"> + <treerow> + <treecell label="Emu"/> + <treecell/> + </treerow> + </treeitem> + </treechildren> + </data> + +<script src="templates_shared.js"/> + +<script> +<![CDATA[ +SimpleTest.waitForExplicitFinish(); + +var testid ="tree element - simple syntax not recursive"; +var queryType = "rdf"; +var isTreeBuilder = false; +var needsOpen = false; +var notWorkingYet = false; +var notWorkingYetDynamic = true; +var expectedOutput = document.getElementById("output"); + +var changes = [ + // step 1 + function(targetds, root) { + if (root.view && 1 < root.view.rowCount && root.view.isContainer(1)) + root.view.toggleOpenState(1); + }, + // step 2 + function(targetds, root) { + var newnode = RDF.GetResource(ZOO_NS + 'mammals/koala'); + targetds.Assert(newnode, RDF.GetResource(ZOO_NS + 'rdf#name'), + RDF.GetLiteral('Koala'), true); + var container = ContainerUtils.MakeSeq(targetds, + RDF.GetResource(ZOO_NS + 'mammals')); + container.InsertElementAt(newnode, '4', true); + }, + // step 3 + function(targetds, root) { + var newnode = RDF.GetResource(ZOO_NS + 'crustaceans/lobster'); + targetds.Assert(newnode, RDF.GetResource(ZOO_NS + 'rdf#name'), + RDF.GetLiteral('Lobster'), true); + var container = ContainerUtils.MakeSeq(targetds, + RDF.GetResource(ZOO_NS + 'crustaceans')); + container.AppendElement(newnode); + }, + // step 4 + function(targetds, root) { + if (root.view && 11 < root.view.rowCount && root.view.isContainer(11)) + root.view.toggleOpenState(11); + }, + // step 5 + function(targetds, root) { + if (root.view && 11 < root.view.rowCount && root.view.isContainer(11)) + root.view.toggleOpenState(11); + }, + // step 6 + function(targetds, root) { + if (root.view && 1 < root.view.rowCount && root.view.isContainer(1)) + root.view.toggleOpenState(1); + } +]; +]]> +</script> + +<tree xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul" hidevscroll="true" hidehscroll="true" datasources="rdf:null" flags="dont-recurse" ref="http://www.some-fictitious-zoo.com/marked" id="root"> +<treecols orient="horizontal" id="treecols"> +<treecol id="treecol" primary="true" label="Name"/> +<treecol label="Species"/> +</treecols> +<template id="template"> +<treechildren> +<treeitem uri="rdf:*"> +<treerow> +<treecell label="rdf:http://www.some-fictitious-zoo.com/rdf#name"/> +<treecell/> +</treerow> +</treeitem> +</treechildren> +</template> +</tree> + +</window> diff --git a/dom/xul/templates/tests/chrome/test_tmpl_treeelementsimplesyntaxnotrecursivetreebuilder.xul b/dom/xul/templates/tests/chrome/test_tmpl_treeelementsimplesyntaxnotrecursivetreebuilder.xul new file mode 100644 index 000000000..793506143 --- /dev/null +++ b/dom/xul/templates/tests/chrome/test_tmpl_treeelementsimplesyntaxnotrecursivetreebuilder.xul @@ -0,0 +1,136 @@ +<?xml version="1.0"?> +<?xml-stylesheet href="chrome://global/skin" type="text/css"?> +<?xml-stylesheet href="chrome://mochikit/content/tests/SimpleTest/test.css" type="text/css"?> + +<!-- + tree element - simple syntax not recursive tree builder +--> + +<window title="XUL Template Tests" width="500" height="600" + onload="test_template();" + xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"> + <script type="application/javascript" + src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script> + + <body xmlns="http://www.w3.org/1999/xhtml" style="height: 300px; overflow: auto;"/> + + <data id="output"> + <treecols id="treecols" orient="horizontal"> + <treecol id="treecol" primary="true" label="Name" ordinal="1"/> + <treecol label="Species" ordinal="3"/> + </treecols> + <treechildren> + <treeitem id="http://www.some-fictitious-zoo.com/humans/sarah"> + <treerow> + <treecell label="Sarah"/> + <treecell/> + </treerow> + </treeitem> + <treeitem step="-1" id="http://www.some-fictitious-zoo.com/mammals" container="true" empty="true"> + <treerow> + <treecell label="Mammals"/> + <treecell/> + </treerow> + </treeitem> + <treeitem step="1" id="http://www.some-fictitious-zoo.com/mammals" container="true" empty="true" open=""> + <treerow> + <treecell label="Mammals"/> + <treecell/> + </treerow> + </treeitem> + <treeitem step="-4" id="http://www.some-fictitious-zoo.com/crustaceans" container="true" empty="true"> + <treerow> + <treecell label="Crustaceans"/> + <treecell/> + </treerow> + </treeitem> + <treeitem step="4" id="http://www.some-fictitious-zoo.com/crustaceans" container="true" empty="true"> + <treerow> + <treecell label="Crustaceans"/> + <treecell/> + </treerow> + </treeitem> + <treeitem id="http://www.some-fictitious-zoo.com/birds/emu"> + <treerow> + <treecell label="Emu"/> + <treecell/> + </treerow> + </treeitem> + </treechildren> + </data> + +<script src="templates_shared.js"/> + +<script> +<![CDATA[ +SimpleTest.waitForExplicitFinish(); + +var testid ="tree element - simple syntax not recursive tree builder"; +var queryType = "rdf"; +var isTreeBuilder = true; +var needsOpen = false; +var notWorkingYet = false; +var notWorkingYetDynamic = false; +var expectedOutput = document.getElementById("output"); + +var changes = [ + // step 1 + function(targetds, root) { + if (root.view && 1 < root.view.rowCount && root.view.isContainer(1)) + root.view.toggleOpenState(1); + }, + // step 2 + function(targetds, root) { + var newnode = RDF.GetResource(ZOO_NS + 'mammals/koala'); + targetds.Assert(newnode, RDF.GetResource(ZOO_NS + 'rdf#name'), + RDF.GetLiteral('Koala'), true); + var container = ContainerUtils.MakeSeq(targetds, + RDF.GetResource(ZOO_NS + 'mammals')); + container.InsertElementAt(newnode, '4', true); + }, + // step 3 + function(targetds, root) { + var newnode = RDF.GetResource(ZOO_NS + 'crustaceans/lobster'); + targetds.Assert(newnode, RDF.GetResource(ZOO_NS + 'rdf#name'), + RDF.GetLiteral('Lobster'), true); + var container = ContainerUtils.MakeSeq(targetds, + RDF.GetResource(ZOO_NS + 'crustaceans')); + container.AppendElement(newnode); + }, + // step 4 + function(targetds, root) { + if (root.view && 11 < root.view.rowCount && root.view.isContainer(11)) + root.view.toggleOpenState(11); + }, + // step 5 + function(targetds, root) { + if (root.view && 11 < root.view.rowCount && root.view.isContainer(11)) + root.view.toggleOpenState(11); + }, + // step 6 + function(targetds, root) { + if (root.view && 1 < root.view.rowCount && root.view.isContainer(1)) + root.view.toggleOpenState(1); + } +]; +]]> +</script> + +<tree xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul" hidevscroll="true" hidehscroll="true" datasources="rdf:null" flags="dont-recurse dont-build-content" ref="http://www.some-fictitious-zoo.com/marked" id="root"> +<treecols orient="horizontal" id="treecols"> +<treecol id="treecol" primary="true" label="Name"/> +<treecol label="Species"/> +</treecols> +<template id="template"> +<treechildren> +<treeitem uri="rdf:*"> +<treerow> +<treecell label="rdf:http://www.some-fictitious-zoo.com/rdf#name"/> +<treecell/> +</treerow> +</treeitem> +</treechildren> +</template> +</tree> + +</window> diff --git a/dom/xul/templates/tests/chrome/test_tmpl_treeelementsimplesyntaxrecursive.xul b/dom/xul/templates/tests/chrome/test_tmpl_treeelementsimplesyntaxrecursive.xul new file mode 100644 index 000000000..009dd1367 --- /dev/null +++ b/dom/xul/templates/tests/chrome/test_tmpl_treeelementsimplesyntaxrecursive.xul @@ -0,0 +1,206 @@ +<?xml version="1.0"?> +<?xml-stylesheet href="chrome://global/skin" type="text/css"?> +<?xml-stylesheet href="chrome://mochikit/content/tests/SimpleTest/test.css" type="text/css"?> + +<!-- + tree element - simple syntax recursive +--> + +<window title="XUL Template Tests" width="500" height="600" + onload="test_template();" + xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"> + <script type="application/javascript" + src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script> + + <body xmlns="http://www.w3.org/1999/xhtml" style="height: 300px; overflow: auto;"/> + + <data id="output"> + <treecols id="treecols" orient="horizontal"> + <treecol id="treecol" primary="true" label="Name" ordinal="1"/> + <treecol label="Species" ordinal="3"/> + </treecols> + <treechildren> + <treeitem id="http://www.some-fictitious-zoo.com/humans/sarah"> + <treerow> + <treecell label="Sarah"/> + <treecell/> + </treerow> + </treeitem> + <treeitem step="-1" id="http://www.some-fictitious-zoo.com/mammals" container="true" empty="false"> + <treerow> + <treecell label="Mammals"/> + <treecell/> + </treerow> + </treeitem> + <treeitem step="1" id="http://www.some-fictitious-zoo.com/mammals" container="true" empty="false" open="true"> + <treerow> + <treecell label="Mammals"/> + <treecell/> + </treerow> + <treechildren> + <treeitem id="http://www.some-fictitious-zoo.com/mammals/lion"> + <treerow> + <treecell label="Lion"/> + <treecell/> + </treerow> + </treeitem> + <treeitem id="http://www.some-fictitious-zoo.com/mammals/hippopotamus"> + <treerow> + <treecell label="HIPPOPOTAMUS"/> + <treecell/> + </treerow> + </treeitem> + <treeitem id="http://www.some-fictitious-zoo.com/mammals/africanelephant"> + <treerow> + <treecell label="African Elephant"/> + <treecell/> + </treerow> + </treeitem> + <treeitem step="2" id="http://www.some-fictitious-zoo.com/mammals/koala"> + <treerow> + <treecell label="Koala"/> + <treecell/> + </treerow> + </treeitem> + <treeitem id="http://www.some-fictitious-zoo.com/mammals/llama"> + <treerow> + <treecell label="LLAMA"/> + <treecell/> + </treerow> + </treeitem> + <treeitem id="http://www.some-fictitious-zoo.com/mammals/polarbear"> + <treerow> + <treecell label="Polar Bear"/> + <treecell/> + </treerow> + </treeitem> + <treeitem id="http://www.some-fictitious-zoo.com/mammals/aardvark"> + <treerow> + <treecell label="aardvark"/> + <treecell/> + </treerow> + </treeitem> + <treeitem id="http://www.some-fictitious-zoo.com/mammals/ninebandedarmadillo"> + <treerow> + <treecell label="Nine-banded Armadillo"/> + <treecell/> + </treerow> + </treeitem> + <treeitem id="http://www.some-fictitious-zoo.com/mammals/gorilla"> + <treerow> + <treecell label="Gorilla"/> + <treecell/> + </treerow> + </treeitem> + </treechildren> + </treeitem> + <treeitem step="-3" id="http://www.some-fictitious-zoo.com/crustaceans" container="true" empty="true"> + <treerow> + <treecell label="Crustaceans"/> + <treecell/> + </treerow> + </treeitem> + <treeitem step="3,-4" id="http://www.some-fictitious-zoo.com/crustaceans" container="true" empty="false"> + <treerow> + <treecell label="Crustaceans"/> + <treecell/> + </treerow> + </treeitem> + <treeitem step="4" id="http://www.some-fictitious-zoo.com/crustaceans" container="true" empty="false" open="true"> + <treerow> + <treecell label="Crustaceans"/> + <treecell/> + </treerow> + <treechildren> + <treeitem id="http://www.some-fictitious-zoo.com/crustaceans/lobster"> + <treerow> + <treecell label="Lobster"/> + <treecell/> + </treerow> + </treeitem> + </treechildren> + </treeitem> + <treeitem id="http://www.some-fictitious-zoo.com/birds/emu"> + <treerow> + <treecell label="Emu"/> + <treecell/> + </treerow> + </treeitem> + </treechildren> + </data> + +<script src="templates_shared.js"/> + +<script> +<![CDATA[ +SimpleTest.waitForExplicitFinish(); + +var testid ="tree element - simple syntax recursive"; +var queryType = "rdf"; +var isTreeBuilder = false; +var needsOpen = false; +var notWorkingYet = false; +var notWorkingYetDynamic = true; +var expectedOutput = document.getElementById("output"); + +var changes = [ + // step 1 + function(targetds, root) { + if (root.view && 1 < root.view.rowCount && root.view.isContainer(1)) + root.view.toggleOpenState(1); + }, + // step 2 + function(targetds, root) { + var newnode = RDF.GetResource(ZOO_NS + 'mammals/koala'); + targetds.Assert(newnode, RDF.GetResource(ZOO_NS + 'rdf#name'), + RDF.GetLiteral('Koala'), true); + var container = ContainerUtils.MakeSeq(targetds, + RDF.GetResource(ZOO_NS + 'mammals')); + container.InsertElementAt(newnode, '4', true); + }, + // step 3 + function(targetds, root) { + var newnode = RDF.GetResource(ZOO_NS + 'crustaceans/lobster'); + targetds.Assert(newnode, RDF.GetResource(ZOO_NS + 'rdf#name'), + RDF.GetLiteral('Lobster'), true); + var container = ContainerUtils.MakeSeq(targetds, + RDF.GetResource(ZOO_NS + 'crustaceans')); + container.AppendElement(newnode); + }, + // step 4 + function(targetds, root) { + if (root.view && 11 < root.view.rowCount && root.view.isContainer(11)) + root.view.toggleOpenState(11); + }, + // step 5 + function(targetds, root) { + if (root.view && 11 < root.view.rowCount && root.view.isContainer(11)) + root.view.toggleOpenState(11); + }, + // step 6 + function(targetds, root) { + if (root.view && 1 < root.view.rowCount && root.view.isContainer(1)) + root.view.toggleOpenState(1); + } +]; +]]> +</script> + +<tree xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul" hidevscroll="true" hidehscroll="true" datasources="rdf:null" flags="" ref="http://www.some-fictitious-zoo.com/marked" id="root"> +<treecols orient="horizontal" id="treecols"> +<treecol id="treecol" primary="true" label="Name"/> +<treecol label="Species"/> +</treecols> +<template id="template"> +<treechildren> +<treeitem uri="rdf:*"> +<treerow> +<treecell label="rdf:http://www.some-fictitious-zoo.com/rdf#name"/> +<treecell/> +</treerow> +</treeitem> +</treechildren> +</template> +</tree> + +</window> diff --git a/dom/xul/templates/tests/chrome/test_tmpl_treeelementsimplesyntaxrecursivetreebuilder.xul b/dom/xul/templates/tests/chrome/test_tmpl_treeelementsimplesyntaxrecursivetreebuilder.xul new file mode 100644 index 000000000..3cd7a8f07 --- /dev/null +++ b/dom/xul/templates/tests/chrome/test_tmpl_treeelementsimplesyntaxrecursivetreebuilder.xul @@ -0,0 +1,206 @@ +<?xml version="1.0"?> +<?xml-stylesheet href="chrome://global/skin" type="text/css"?> +<?xml-stylesheet href="chrome://mochikit/content/tests/SimpleTest/test.css" type="text/css"?> + +<!-- + tree element - simple syntax recursive tree builder +--> + +<window title="XUL Template Tests" width="500" height="600" + onload="test_template();" + xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"> + <script type="application/javascript" + src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script> + + <body xmlns="http://www.w3.org/1999/xhtml" style="height: 300px; overflow: auto;"/> + + <data id="output"> + <treecols id="treecols" orient="horizontal"> + <treecol id="treecol" primary="true" label="Name" ordinal="1"/> + <treecol label="Species" ordinal="3"/> + </treecols> + <treechildren> + <treeitem id="http://www.some-fictitious-zoo.com/humans/sarah"> + <treerow> + <treecell label="Sarah"/> + <treecell/> + </treerow> + </treeitem> + <treeitem step="-1" id="http://www.some-fictitious-zoo.com/mammals" container="true" empty="false"> + <treerow> + <treecell label="Mammals"/> + <treecell/> + </treerow> + </treeitem> + <treeitem step="1" id="http://www.some-fictitious-zoo.com/mammals" container="true" empty="false" open="true"> + <treerow> + <treecell label="Mammals"/> + <treecell/> + </treerow> + <treechildren> + <treeitem id="http://www.some-fictitious-zoo.com/mammals/lion"> + <treerow> + <treecell label="Lion"/> + <treecell/> + </treerow> + </treeitem> + <treeitem id="http://www.some-fictitious-zoo.com/mammals/hippopotamus"> + <treerow> + <treecell label="HIPPOPOTAMUS"/> + <treecell/> + </treerow> + </treeitem> + <treeitem id="http://www.some-fictitious-zoo.com/mammals/africanelephant"> + <treerow> + <treecell label="African Elephant"/> + <treecell/> + </treerow> + </treeitem> + <treeitem step="2" id="http://www.some-fictitious-zoo.com/mammals/koala"> + <treerow> + <treecell label="Koala"/> + <treecell/> + </treerow> + </treeitem> + <treeitem id="http://www.some-fictitious-zoo.com/mammals/llama"> + <treerow> + <treecell label="LLAMA"/> + <treecell/> + </treerow> + </treeitem> + <treeitem id="http://www.some-fictitious-zoo.com/mammals/polarbear"> + <treerow> + <treecell label="Polar Bear"/> + <treecell/> + </treerow> + </treeitem> + <treeitem id="http://www.some-fictitious-zoo.com/mammals/aardvark"> + <treerow> + <treecell label="aardvark"/> + <treecell/> + </treerow> + </treeitem> + <treeitem id="http://www.some-fictitious-zoo.com/mammals/ninebandedarmadillo"> + <treerow> + <treecell label="Nine-banded Armadillo"/> + <treecell/> + </treerow> + </treeitem> + <treeitem id="http://www.some-fictitious-zoo.com/mammals/gorilla"> + <treerow> + <treecell label="Gorilla"/> + <treecell/> + </treerow> + </treeitem> + </treechildren> + </treeitem> + <treeitem step="-3" id="http://www.some-fictitious-zoo.com/crustaceans" container="true" empty="true"> + <treerow> + <treecell label="Crustaceans"/> + <treecell/> + </treerow> + </treeitem> + <treeitem step="3,-4" id="http://www.some-fictitious-zoo.com/crustaceans" container="true" empty="false"> + <treerow> + <treecell label="Crustaceans"/> + <treecell/> + </treerow> + </treeitem> + <treeitem step="4" id="http://www.some-fictitious-zoo.com/crustaceans" container="true" empty="false" open="true"> + <treerow> + <treecell label="Crustaceans"/> + <treecell/> + </treerow> + <treechildren> + <treeitem id="http://www.some-fictitious-zoo.com/crustaceans/lobster"> + <treerow> + <treecell label="Lobster"/> + <treecell/> + </treerow> + </treeitem> + </treechildren> + </treeitem> + <treeitem id="http://www.some-fictitious-zoo.com/birds/emu"> + <treerow> + <treecell label="Emu"/> + <treecell/> + </treerow> + </treeitem> + </treechildren> + </data> + +<script src="templates_shared.js"/> + +<script> +<![CDATA[ +SimpleTest.waitForExplicitFinish(); + +var testid ="tree element - simple syntax recursive tree builder"; +var queryType = "rdf"; +var isTreeBuilder = true; +var needsOpen = false; +var notWorkingYet = false; +var notWorkingYetDynamic = true; +var expectedOutput = document.getElementById("output"); + +var changes = [ + // step 1 + function(targetds, root) { + if (root.view && 1 < root.view.rowCount && root.view.isContainer(1)) + root.view.toggleOpenState(1); + }, + // step 2 + function(targetds, root) { + var newnode = RDF.GetResource(ZOO_NS + 'mammals/koala'); + targetds.Assert(newnode, RDF.GetResource(ZOO_NS + 'rdf#name'), + RDF.GetLiteral('Koala'), true); + var container = ContainerUtils.MakeSeq(targetds, + RDF.GetResource(ZOO_NS + 'mammals')); + container.InsertElementAt(newnode, '4', true); + }, + // step 3 + function(targetds, root) { + var newnode = RDF.GetResource(ZOO_NS + 'crustaceans/lobster'); + targetds.Assert(newnode, RDF.GetResource(ZOO_NS + 'rdf#name'), + RDF.GetLiteral('Lobster'), true); + var container = ContainerUtils.MakeSeq(targetds, + RDF.GetResource(ZOO_NS + 'crustaceans')); + container.AppendElement(newnode); + }, + // step 4 + function(targetds, root) { + if (root.view && 11 < root.view.rowCount && root.view.isContainer(11)) + root.view.toggleOpenState(11); + }, + // step 5 + function(targetds, root) { + if (root.view && 11 < root.view.rowCount && root.view.isContainer(11)) + root.view.toggleOpenState(11); + }, + // step 6 + function(targetds, root) { + if (root.view && 1 < root.view.rowCount && root.view.isContainer(1)) + root.view.toggleOpenState(1); + } +]; +]]> +</script> + +<tree xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul" hidevscroll="true" hidehscroll="true" datasources="rdf:null" flags="dont-build-content" ref="http://www.some-fictitious-zoo.com/marked" id="root"> +<treecols orient="horizontal" id="treecols"> +<treecol id="treecol" primary="true" label="Name"/> +<treecol label="Species"/> +</treecols> +<template id="template"> +<treechildren> +<treeitem uri="rdf:*"> +<treerow> +<treecell label="rdf:http://www.some-fictitious-zoo.com/rdf#name"/> +<treecell/> +</treerow> +</treeitem> +</treechildren> +</template> +</tree> + +</window> diff --git a/dom/xul/templates/tests/chrome/test_tmpl_treeelementtreecell.xul b/dom/xul/templates/tests/chrome/test_tmpl_treeelementtreecell.xul new file mode 100644 index 000000000..43c926ec8 --- /dev/null +++ b/dom/xul/templates/tests/chrome/test_tmpl_treeelementtreecell.xul @@ -0,0 +1,133 @@ +<?xml version="1.0"?> +<?xml-stylesheet href="chrome://global/skin" type="text/css"?> +<?xml-stylesheet href="chrome://mochikit/content/tests/SimpleTest/test.css" type="text/css"?> + +<!-- + tree element - treecell +--> + +<window title="XUL Template Tests" width="500" height="600" + onload="test_template();" + xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"> + <script type="application/javascript" + src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script> + + <body xmlns="http://www.w3.org/1999/xhtml" style="height: 300px; overflow: auto;"/> + + <data id="output"> + <treecols id="treecols" orient="horizontal"> + <treecol id="treecol" primary="true" label="Name" ordinal="1"/> + <treecol label="Species" ordinal="3"/> + </treecols> + <treechildren> + <treeitem step="3" id="http://www.some-fictitious-zoo.com/birds/wren"> + <treerow> + <treecell label="Wren"/> + <treecell/> + </treerow> + </treeitem> + <treeitem id="http://www.some-fictitious-zoo.com/birds/emu"> + <treerow> + <treecell label="Emu"/> + <treecell label="Dromaius novaehollandiae"/> + </treerow> + </treeitem> + <treeitem step="-4" id="http://www.some-fictitious-zoo.com/birds/barnowl"> + <treerow> + <treecell label="Barn Owl"/> + <treecell label="Tyto alba"/> + </treerow> + </treeitem> + <treeitem id="http://www.some-fictitious-zoo.com/birds/raven"> + <treerow> + <treecell label="Raven"/> + <treecell label="Corvus corax"/> + </treerow> + </treeitem> + <treeitem step="2" id="http://www.some-fictitious-zoo.com/birds/archaeopteryx"> + <treerow> + <treecell label="Archaeopteryx"/> + <treecell/> + </treerow> + </treeitem> + <treeitem step="1" id="http://www.some-fictitious-zoo.com/birds/emperorpenguin"> + <treerow> + <treecell label="Emperor Penguin"/> + <treecell/> + </treerow> + </treeitem> + </treechildren> + </data> + +<script src="templates_shared.js"/> + +<script> +<![CDATA[ +SimpleTest.waitForExplicitFinish(); + +var testid ="tree element - treecell"; +var queryType = "rdf"; +var isTreeBuilder = false; +var needsOpen = false; +var notWorkingYet = false; +var notWorkingYetDynamic = false; +var expectedOutput = document.getElementById("output"); + +var changes = [ + // step 1 + function(targetds, root) { + var newnode = RDF.GetResource(ZOO_NS + 'birds/emperorpenguin'); + targetds.Assert(newnode, RDF.GetResource(ZOO_NS + 'rdf#name'), + RDF.GetLiteral('Emperor Penguin'), true); + var container = ContainerUtils.MakeSeq(targetds, + RDF.GetResource(ZOO_NS + 'birds')); + container.AppendElement(newnode); + }, + // step 2 + function(targetds, root) { + var newnode = RDF.GetResource(ZOO_NS + 'birds/archaeopteryx'); + targetds.Assert(newnode, RDF.GetResource(ZOO_NS + 'rdf#name'), + RDF.GetLiteral('Archaeopteryx'), true); + var container = ContainerUtils.MakeSeq(targetds, + RDF.GetResource(ZOO_NS + 'birds')); + container.InsertElementAt(newnode, '4', true); + }, + // step 3 + function(targetds, root) { + var newnode = RDF.GetResource(ZOO_NS + 'birds/wren'); + targetds.Assert(newnode, RDF.GetResource(ZOO_NS + 'rdf#name'), + RDF.GetLiteral('Wren'), true); + var container = ContainerUtils.MakeSeq(targetds, + RDF.GetResource(ZOO_NS + 'birds')); + container.InsertElementAt(newnode, '1', true); + }, + // step 4 + function(targetds, root) { + var container = ContainerUtils.MakeSeq(targetds, + RDF.GetResource(ZOO_NS + 'birds')); + var removednode = container.RemoveElementAt('3', true); + targetds.Unassert(removednode, RDF.GetResource(ZOO_NS + 'rdf#name'), + RDF.GetLiteral('Barn Owl'), true); + } +]; +]]> +</script> + +<tree xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul" id="root" datasources="rdf:null" ref="http://www.some-fictitious-zoo.com/birds" hidevscroll="true" hidehscroll="true"> +<treecols orient="horizontal" id="treecols"> +<treecol id="treecol" primary="true" label="Name" ordinal="1"/> +<treecol label="Species" ordinal="3"/> +</treecols> +<template id="template"> +<treechildren id="treechildren"> +<treeitem uri="rdf:*"> +<treerow> +<treecell label="rdf:http://www.some-fictitious-zoo.com/rdf#name"/> +<treecell label="rdf:http://www.some-fictitious-zoo.com/rdf#species"/> +</treerow> +</treeitem> +</treechildren> +</template> +</tree> + +</window> diff --git a/dom/xul/templates/tests/chrome/test_tmpl_treeelementtreecellsortascending.xul b/dom/xul/templates/tests/chrome/test_tmpl_treeelementtreecellsortascending.xul new file mode 100644 index 000000000..da6c52507 --- /dev/null +++ b/dom/xul/templates/tests/chrome/test_tmpl_treeelementtreecellsortascending.xul @@ -0,0 +1,133 @@ +<?xml version="1.0"?> +<?xml-stylesheet href="chrome://global/skin" type="text/css"?> +<?xml-stylesheet href="chrome://mochikit/content/tests/SimpleTest/test.css" type="text/css"?> + +<!-- + tree element - treecell sort ascending +--> + +<window title="XUL Template Tests" width="500" height="600" + onload="test_template();" + xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"> + <script type="application/javascript" + src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script> + + <body xmlns="http://www.w3.org/1999/xhtml" style="height: 300px; overflow: auto;"/> + + <data id="output"> + <treecols id="treecols" orient="horizontal"> + <treecol id="treecol" primary="true" label="Name" ordinal="1" sort="rdf:http://www.some-fictitious-zoo.com/rdf#name" sortDirection="ascending" sortActive="true"/> + <treecol label="Species" ordinal="3"/> + </treecols> + <treechildren> + <treeitem step="2" id="http://www.some-fictitious-zoo.com/birds/archaeopteryx"> + <treerow> + <treecell label="Archaeopteryx"/> + <treecell/> + </treerow> + </treeitem> + <treeitem step="-4" id="http://www.some-fictitious-zoo.com/birds/barnowl"> + <treerow> + <treecell label="Barn Owl"/> + <treecell label="Tyto alba"/> + </treerow> + </treeitem> + <treeitem step="1" id="http://www.some-fictitious-zoo.com/birds/emperorpenguin"> + <treerow> + <treecell label="Emperor Penguin"/> + <treecell/> + </treerow> + </treeitem> + <treeitem id="http://www.some-fictitious-zoo.com/birds/emu"> + <treerow> + <treecell label="Emu"/> + <treecell label="Dromaius novaehollandiae"/> + </treerow> + </treeitem> + <treeitem id="http://www.some-fictitious-zoo.com/birds/raven"> + <treerow> + <treecell label="Raven"/> + <treecell label="Corvus corax"/> + </treerow> + </treeitem> + <treeitem step="3" id="http://www.some-fictitious-zoo.com/birds/wren"> + <treerow> + <treecell label="Wren"/> + <treecell/> + </treerow> + </treeitem> + </treechildren> + </data> + +<script src="templates_shared.js"/> + +<script> +<![CDATA[ +SimpleTest.waitForExplicitFinish(); + +var testid ="tree element - treecell sort ascending"; +var queryType = "rdf"; +var isTreeBuilder = false; +var needsOpen = false; +var notWorkingYet = false; +var notWorkingYetDynamic = false; +var expectedOutput = document.getElementById("output"); + +var changes = [ + // step 1 + function(targetds, root) { + var newnode = RDF.GetResource(ZOO_NS + 'birds/emperorpenguin'); + targetds.Assert(newnode, RDF.GetResource(ZOO_NS + 'rdf#name'), + RDF.GetLiteral('Emperor Penguin'), true); + var container = ContainerUtils.MakeSeq(targetds, + RDF.GetResource(ZOO_NS + 'birds')); + container.AppendElement(newnode); + }, + // step 2 + function(targetds, root) { + var newnode = RDF.GetResource(ZOO_NS + 'birds/archaeopteryx'); + targetds.Assert(newnode, RDF.GetResource(ZOO_NS + 'rdf#name'), + RDF.GetLiteral('Archaeopteryx'), true); + var container = ContainerUtils.MakeSeq(targetds, + RDF.GetResource(ZOO_NS + 'birds')); + container.InsertElementAt(newnode, '4', true); + }, + // step 3 + function(targetds, root) { + var newnode = RDF.GetResource(ZOO_NS + 'birds/wren'); + targetds.Assert(newnode, RDF.GetResource(ZOO_NS + 'rdf#name'), + RDF.GetLiteral('Wren'), true); + var container = ContainerUtils.MakeSeq(targetds, + RDF.GetResource(ZOO_NS + 'birds')); + container.InsertElementAt(newnode, '1', true); + }, + // step 4 + function(targetds, root) { + var container = ContainerUtils.MakeSeq(targetds, + RDF.GetResource(ZOO_NS + 'birds')); + var removednode = container.RemoveElementAt('3', true); + targetds.Unassert(removednode, RDF.GetResource(ZOO_NS + 'rdf#name'), + RDF.GetLiteral('Barn Owl'), true); + } +]; +]]> +</script> + +<tree xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul" hidevscroll="true" hidehscroll="true" datasources="rdf:null" flags="" sort="rdf:http://www.some-fictitious-zoo.com/rdf#name" sortDirection="ascending" id="root" ref="http://www.some-fictitious-zoo.com/birds"> +<treecols orient="horizontal" id="treecols"> +<treecol id="treecol" primary="true" label="Name" ordinal="1" sort="rdf:http://www.some-fictitious-zoo.com/rdf#name" sortDirection="ascending" sortActive="true"/> +<treecol label="Species" ordinal="3"/> +</treecols> +<template id="template"> +<treechildren id="treechildren"> +<treeitem uri="rdf:*"> +<treerow> +<treecell label="rdf:http://www.some-fictitious-zoo.com/rdf#name"/> +<treecell label="rdf:http://www.some-fictitious-zoo.com/rdf#species"/> +</treerow> +</treeitem> +</treechildren> +</template> +</tree> + +</window> diff --git a/dom/xul/templates/tests/chrome/test_tmpl_treeelementtreecellsortascendingtreebuilder.xul b/dom/xul/templates/tests/chrome/test_tmpl_treeelementtreecellsortascendingtreebuilder.xul new file mode 100644 index 000000000..a4f0e2417 --- /dev/null +++ b/dom/xul/templates/tests/chrome/test_tmpl_treeelementtreecellsortascendingtreebuilder.xul @@ -0,0 +1,133 @@ +<?xml version="1.0"?> +<?xml-stylesheet href="chrome://global/skin" type="text/css"?> +<?xml-stylesheet href="chrome://mochikit/content/tests/SimpleTest/test.css" type="text/css"?> + +<!-- + tree element - treecell sort ascending tree builder +--> + +<window title="XUL Template Tests" width="500" height="600" + onload="test_template();" + xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"> + <script type="application/javascript" + src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script> + + <body xmlns="http://www.w3.org/1999/xhtml" style="height: 300px; overflow: auto;"/> + + <data id="output"> + <treecols id="treecols" orient="horizontal"> + <treecol id="treecol" primary="true" label="Name" ordinal="1" sort="rdf:http://www.some-fictitious-zoo.com/rdf#name" sortDirection="ascending" sortActive="true"/> + <treecol label="Species" ordinal="3"/> + </treecols> + <treechildren> + <treeitem step="2" id="http://www.some-fictitious-zoo.com/birds/archaeopteryx"> + <treerow> + <treecell label="Archaeopteryx"/> + <treecell/> + </treerow> + </treeitem> + <treeitem step="-4" id="http://www.some-fictitious-zoo.com/birds/barnowl"> + <treerow> + <treecell label="Barn Owl"/> + <treecell label="Tyto alba"/> + </treerow> + </treeitem> + <treeitem step="1" id="http://www.some-fictitious-zoo.com/birds/emperorpenguin"> + <treerow> + <treecell label="Emperor Penguin"/> + <treecell/> + </treerow> + </treeitem> + <treeitem id="http://www.some-fictitious-zoo.com/birds/emu"> + <treerow> + <treecell label="Emu"/> + <treecell label="Dromaius novaehollandiae"/> + </treerow> + </treeitem> + <treeitem id="http://www.some-fictitious-zoo.com/birds/raven"> + <treerow> + <treecell label="Raven"/> + <treecell label="Corvus corax"/> + </treerow> + </treeitem> + <treeitem step="3" id="http://www.some-fictitious-zoo.com/birds/wren"> + <treerow> + <treecell label="Wren"/> + <treecell/> + </treerow> + </treeitem> + </treechildren> + </data> + +<script src="templates_shared.js"/> + +<script> +<![CDATA[ +SimpleTest.waitForExplicitFinish(); + +var testid ="tree element - treecell sort ascending tree builder"; +var queryType = "rdf"; +var isTreeBuilder = true; +var needsOpen = false; +var notWorkingYet = false; +var notWorkingYetDynamic = false; +var expectedOutput = document.getElementById("output"); + +var changes = [ + // step 1 + function(targetds, root) { + var newnode = RDF.GetResource(ZOO_NS + 'birds/emperorpenguin'); + targetds.Assert(newnode, RDF.GetResource(ZOO_NS + 'rdf#name'), + RDF.GetLiteral('Emperor Penguin'), true); + var container = ContainerUtils.MakeSeq(targetds, + RDF.GetResource(ZOO_NS + 'birds')); + container.AppendElement(newnode); + }, + // step 2 + function(targetds, root) { + var newnode = RDF.GetResource(ZOO_NS + 'birds/archaeopteryx'); + targetds.Assert(newnode, RDF.GetResource(ZOO_NS + 'rdf#name'), + RDF.GetLiteral('Archaeopteryx'), true); + var container = ContainerUtils.MakeSeq(targetds, + RDF.GetResource(ZOO_NS + 'birds')); + container.InsertElementAt(newnode, '4', true); + }, + // step 3 + function(targetds, root) { + var newnode = RDF.GetResource(ZOO_NS + 'birds/wren'); + targetds.Assert(newnode, RDF.GetResource(ZOO_NS + 'rdf#name'), + RDF.GetLiteral('Wren'), true); + var container = ContainerUtils.MakeSeq(targetds, + RDF.GetResource(ZOO_NS + 'birds')); + container.InsertElementAt(newnode, '1', true); + }, + // step 4 + function(targetds, root) { + var container = ContainerUtils.MakeSeq(targetds, + RDF.GetResource(ZOO_NS + 'birds')); + var removednode = container.RemoveElementAt('3', true); + targetds.Unassert(removednode, RDF.GetResource(ZOO_NS + 'rdf#name'), + RDF.GetLiteral('Barn Owl'), true); + } +]; +]]> +</script> + +<tree xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul" hidevscroll="true" hidehscroll="true" datasources="rdf:null" flags="dont-build-content" sort="rdf:http://www.some-fictitious-zoo.com/rdf#name" sortDirection="ascending" id="root" ref="http://www.some-fictitious-zoo.com/birds"> +<treecols orient="horizontal" id="treecols"> +<treecol id="treecol" primary="true" label="Name" ordinal="1" sort="rdf:http://www.some-fictitious-zoo.com/rdf#name" sortDirection="ascending" sortActive="true"/> +<treecol label="Species" ordinal="3"/> +</treecols> +<template id="template"> +<treechildren id="treechildren"> +<treeitem uri="rdf:*"> +<treerow> +<treecell label="rdf:http://www.some-fictitious-zoo.com/rdf#name"/> +<treecell label="rdf:http://www.some-fictitious-zoo.com/rdf#species"/> +</treerow> +</treeitem> +</treechildren> +</template> +</tree> + +</window> diff --git a/dom/xul/templates/tests/chrome/test_tmpl_treeelementtreecelltreebuilder.xul b/dom/xul/templates/tests/chrome/test_tmpl_treeelementtreecelltreebuilder.xul new file mode 100644 index 000000000..dcc14e0bb --- /dev/null +++ b/dom/xul/templates/tests/chrome/test_tmpl_treeelementtreecelltreebuilder.xul @@ -0,0 +1,133 @@ +<?xml version="1.0"?> +<?xml-stylesheet href="chrome://global/skin" type="text/css"?> +<?xml-stylesheet href="chrome://mochikit/content/tests/SimpleTest/test.css" type="text/css"?> + +<!-- + tree element - treecell tree builder +--> + +<window title="XUL Template Tests" width="500" height="600" + onload="test_template();" + xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"> + <script type="application/javascript" + src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script> + + <body xmlns="http://www.w3.org/1999/xhtml" style="height: 300px; overflow: auto;"/> + + <data id="output"> + <treecols id="treecols" orient="horizontal"> + <treecol id="treecol" primary="true" label="Name" ordinal="1"/> + <treecol label="Species" ordinal="3"/> + </treecols> + <treechildren> + <treeitem step="3" id="http://www.some-fictitious-zoo.com/birds/wren"> + <treerow> + <treecell label="Wren"/> + <treecell/> + </treerow> + </treeitem> + <treeitem id="http://www.some-fictitious-zoo.com/birds/emu"> + <treerow> + <treecell label="Emu"/> + <treecell label="Dromaius novaehollandiae"/> + </treerow> + </treeitem> + <treeitem step="-4" id="http://www.some-fictitious-zoo.com/birds/barnowl"> + <treerow> + <treecell label="Barn Owl"/> + <treecell label="Tyto alba"/> + </treerow> + </treeitem> + <treeitem id="http://www.some-fictitious-zoo.com/birds/raven"> + <treerow> + <treecell label="Raven"/> + <treecell label="Corvus corax"/> + </treerow> + </treeitem> + <treeitem step="2" id="http://www.some-fictitious-zoo.com/birds/archaeopteryx"> + <treerow> + <treecell label="Archaeopteryx"/> + <treecell/> + </treerow> + </treeitem> + <treeitem step="1" id="http://www.some-fictitious-zoo.com/birds/emperorpenguin"> + <treerow> + <treecell label="Emperor Penguin"/> + <treecell/> + </treerow> + </treeitem> + </treechildren> + </data> + +<script src="templates_shared.js"/> + +<script> +<![CDATA[ +SimpleTest.waitForExplicitFinish(); + +var testid ="tree element - treecell tree builder"; +var queryType = "rdf"; +var isTreeBuilder = true; +var needsOpen = false; +var notWorkingYet = false; +var notWorkingYetDynamic = true; +var expectedOutput = document.getElementById("output"); + +var changes = [ + // step 1 + function(targetds, root) { + var newnode = RDF.GetResource(ZOO_NS + 'birds/emperorpenguin'); + targetds.Assert(newnode, RDF.GetResource(ZOO_NS + 'rdf#name'), + RDF.GetLiteral('Emperor Penguin'), true); + var container = ContainerUtils.MakeSeq(targetds, + RDF.GetResource(ZOO_NS + 'birds')); + container.AppendElement(newnode); + }, + // step 2 + function(targetds, root) { + var newnode = RDF.GetResource(ZOO_NS + 'birds/archaeopteryx'); + targetds.Assert(newnode, RDF.GetResource(ZOO_NS + 'rdf#name'), + RDF.GetLiteral('Archaeopteryx'), true); + var container = ContainerUtils.MakeSeq(targetds, + RDF.GetResource(ZOO_NS + 'birds')); + container.InsertElementAt(newnode, '4', true); + }, + // step 3 + function(targetds, root) { + var newnode = RDF.GetResource(ZOO_NS + 'birds/wren'); + targetds.Assert(newnode, RDF.GetResource(ZOO_NS + 'rdf#name'), + RDF.GetLiteral('Wren'), true); + var container = ContainerUtils.MakeSeq(targetds, + RDF.GetResource(ZOO_NS + 'birds')); + container.InsertElementAt(newnode, '1', true); + }, + // step 4 + function(targetds, root) { + var container = ContainerUtils.MakeSeq(targetds, + RDF.GetResource(ZOO_NS + 'birds')); + var removednode = container.RemoveElementAt('3', true); + targetds.Unassert(removednode, RDF.GetResource(ZOO_NS + 'rdf#name'), + RDF.GetLiteral('Barn Owl'), true); + } +]; +]]> +</script> + +<tree xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul" hidevscroll="true" hidehscroll="true" datasources="rdf:null" flags="dont-build-content" id="root" ref="http://www.some-fictitious-zoo.com/birds"> +<treecols orient="horizontal" id="treecols"> +<treecol id="treecol" primary="true" label="Name" ordinal="1"/> +<treecol label="Species" ordinal="3"/> +</treecols> +<template id="template"> +<treechildren id="treechildren"> +<treeitem uri="rdf:*"> +<treerow> +<treecell label="rdf:http://www.some-fictitious-zoo.com/rdf#name"/> +<treecell label="rdf:http://www.some-fictitious-zoo.com/rdf#species"/> +</treerow> +</treeitem> +</treechildren> +</template> +</tree> + +</window> diff --git a/dom/xul/templates/tests/chrome/test_tmpl_treeelementtreeitemonly.xul b/dom/xul/templates/tests/chrome/test_tmpl_treeelementtreeitemonly.xul new file mode 100644 index 000000000..fb94cbdad --- /dev/null +++ b/dom/xul/templates/tests/chrome/test_tmpl_treeelementtreeitemonly.xul @@ -0,0 +1,96 @@ +<?xml version="1.0"?> +<?xml-stylesheet href="chrome://global/skin" type="text/css"?> +<?xml-stylesheet href="chrome://mochikit/content/tests/SimpleTest/test.css" type="text/css"?> + +<!-- + tree element - treeitem only +--> + +<window title="XUL Template Tests" width="500" height="600" + onload="test_template();" + xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"> + <script type="application/javascript" + src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script> + + <body xmlns="http://www.w3.org/1999/xhtml" style="height: 300px; overflow: auto;"/> + + <data id="output"> + <treecols id="treecols" orient="horizontal"> + <treecol id="treecol" primary="true" label="Name" ordinal="1"/> + </treecols> + <treechildren> + <treeitem step="3" id="http://www.some-fictitious-zoo.com/birds/wren" label="Wren"/> + <treeitem id="http://www.some-fictitious-zoo.com/birds/emu" label="Emu"/> + <treeitem step="-4" id="http://www.some-fictitious-zoo.com/birds/barnowl" label="Barn Owl"/> + <treeitem id="http://www.some-fictitious-zoo.com/birds/raven" label="Raven"/> + <treeitem step="2" id="http://www.some-fictitious-zoo.com/birds/archaeopteryx" label="Archaeopteryx"/> + <treeitem step="1" id="http://www.some-fictitious-zoo.com/birds/emperorpenguin" label="Emperor Penguin"/> + </treechildren> + </data> + +<script src="templates_shared.js"/> + +<script> +<![CDATA[ +SimpleTest.waitForExplicitFinish(); + +var testid ="tree element - treeitem only"; +var queryType = "rdf"; +var isTreeBuilder = false; +var needsOpen = false; +var notWorkingYet = false; +var notWorkingYetDynamic = false; +var expectedOutput = document.getElementById("output"); + +var changes = [ + // step 1 + function(targetds, root) { + var newnode = RDF.GetResource(ZOO_NS + 'birds/emperorpenguin'); + targetds.Assert(newnode, RDF.GetResource(ZOO_NS + 'rdf#name'), + RDF.GetLiteral('Emperor Penguin'), true); + var container = ContainerUtils.MakeSeq(targetds, + RDF.GetResource(ZOO_NS + 'birds')); + container.AppendElement(newnode); + }, + // step 2 + function(targetds, root) { + var newnode = RDF.GetResource(ZOO_NS + 'birds/archaeopteryx'); + targetds.Assert(newnode, RDF.GetResource(ZOO_NS + 'rdf#name'), + RDF.GetLiteral('Archaeopteryx'), true); + var container = ContainerUtils.MakeSeq(targetds, + RDF.GetResource(ZOO_NS + 'birds')); + container.InsertElementAt(newnode, '4', true); + }, + // step 3 + function(targetds, root) { + var newnode = RDF.GetResource(ZOO_NS + 'birds/wren'); + targetds.Assert(newnode, RDF.GetResource(ZOO_NS + 'rdf#name'), + RDF.GetLiteral('Wren'), true); + var container = ContainerUtils.MakeSeq(targetds, + RDF.GetResource(ZOO_NS + 'birds')); + container.InsertElementAt(newnode, '1', true); + }, + // step 4 + function(targetds, root) { + var container = ContainerUtils.MakeSeq(targetds, + RDF.GetResource(ZOO_NS + 'birds')); + var removednode = container.RemoveElementAt('3', true); + targetds.Unassert(removednode, RDF.GetResource(ZOO_NS + 'rdf#name'), + RDF.GetLiteral('Barn Owl'), true); + } +]; +]]> +</script> + +<tree xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul" id="root" datasources="rdf:null" ref="http://www.some-fictitious-zoo.com/birds" hidevscroll="true" hidehscroll="true"> +<treecols orient="horizontal" id="treecols"> +<treecol id="treecol" primary="true" label="Name"/> +</treecols> +<template id="template"> +<treechildren id="treechildren"> +<treeitem uri="rdf:*" label="rdf:http://www.some-fictitious-zoo.com/rdf#name"/> +</treechildren> +</template> +</tree> + +</window> diff --git a/dom/xul/templates/tests/chrome/test_tmpl_treeelementtreeitemsortascending.xul b/dom/xul/templates/tests/chrome/test_tmpl_treeelementtreeitemsortascending.xul new file mode 100644 index 000000000..654e79e1c --- /dev/null +++ b/dom/xul/templates/tests/chrome/test_tmpl_treeelementtreeitemsortascending.xul @@ -0,0 +1,96 @@ +<?xml version="1.0"?> +<?xml-stylesheet href="chrome://global/skin" type="text/css"?> +<?xml-stylesheet href="chrome://mochikit/content/tests/SimpleTest/test.css" type="text/css"?> + +<!-- + tree element - treeitem sort ascending +--> + +<window title="XUL Template Tests" width="500" height="600" + onload="test_template();" + xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"> + <script type="application/javascript" + src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script> + + <body xmlns="http://www.w3.org/1999/xhtml" style="height: 300px; overflow: auto;"/> + + <data id="output"> + <treecols id="treecols" orient="horizontal"> + <treecol id="treecol" primary="true" label="Name" ordinal="1" sort="rdf:http://www.some-fictitious-zoo.com/rdf#name" sortDirection="ascending" sortActive="true"/> + </treecols> + <treechildren> + <treeitem step="2" id="http://www.some-fictitious-zoo.com/birds/archaeopteryx" label="Archaeopteryx"/> + <treeitem step="-4" id="http://www.some-fictitious-zoo.com/birds/barnowl" label="Barn Owl"/> + <treeitem step="1" id="http://www.some-fictitious-zoo.com/birds/emperorpenguin" label="Emperor Penguin"/> + <treeitem id="http://www.some-fictitious-zoo.com/birds/emu" label="Emu"/> + <treeitem id="http://www.some-fictitious-zoo.com/birds/raven" label="Raven"/> + <treeitem step="3" id="http://www.some-fictitious-zoo.com/birds/wren" label="Wren"/> + </treechildren> + </data> + +<script src="templates_shared.js"/> + +<script> +<![CDATA[ +SimpleTest.waitForExplicitFinish(); + +var testid ="tree element - treeitem sort ascending"; +var queryType = "rdf"; +var isTreeBuilder = false; +var needsOpen = false; +var notWorkingYet = false; +var notWorkingYetDynamic = false; +var expectedOutput = document.getElementById("output"); + +var changes = [ + // step 1 + function(targetds, root) { + var newnode = RDF.GetResource(ZOO_NS + 'birds/emperorpenguin'); + targetds.Assert(newnode, RDF.GetResource(ZOO_NS + 'rdf#name'), + RDF.GetLiteral('Emperor Penguin'), true); + var container = ContainerUtils.MakeSeq(targetds, + RDF.GetResource(ZOO_NS + 'birds')); + container.AppendElement(newnode); + }, + // step 2 + function(targetds, root) { + var newnode = RDF.GetResource(ZOO_NS + 'birds/archaeopteryx'); + targetds.Assert(newnode, RDF.GetResource(ZOO_NS + 'rdf#name'), + RDF.GetLiteral('Archaeopteryx'), true); + var container = ContainerUtils.MakeSeq(targetds, + RDF.GetResource(ZOO_NS + 'birds')); + container.InsertElementAt(newnode, '4', true); + }, + // step 3 + function(targetds, root) { + var newnode = RDF.GetResource(ZOO_NS + 'birds/wren'); + targetds.Assert(newnode, RDF.GetResource(ZOO_NS + 'rdf#name'), + RDF.GetLiteral('Wren'), true); + var container = ContainerUtils.MakeSeq(targetds, + RDF.GetResource(ZOO_NS + 'birds')); + container.InsertElementAt(newnode, '1', true); + }, + // step 4 + function(targetds, root) { + var container = ContainerUtils.MakeSeq(targetds, + RDF.GetResource(ZOO_NS + 'birds')); + var removednode = container.RemoveElementAt('3', true); + targetds.Unassert(removednode, RDF.GetResource(ZOO_NS + 'rdf#name'), + RDF.GetLiteral('Barn Owl'), true); + } +]; +]]> +</script> + +<tree xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul" hidevscroll="true" hidehscroll="true" datasources="rdf:null" sort="rdf:http://www.some-fictitious-zoo.com/rdf#name" sortDirection="ascending" id="root" ref="http://www.some-fictitious-zoo.com/birds"> +<treecols orient="horizontal" id="treecols"> +<treecol id="treecol" primary="true" label="Name" ordinal="1" sort="rdf:http://www.some-fictitious-zoo.com/rdf#name" sortDirection="ascending" sortActive="true"/> +</treecols> +<template id="template"> +<treechildren id="treechildren"> +<treeitem uri="rdf:*" label="rdf:http://www.some-fictitious-zoo.com/rdf#name"/> +</treechildren> +</template> +</tree> + +</window> diff --git a/dom/xul/templates/tests/chrome/test_tmpl_twogenerationnodes.xul b/dom/xul/templates/tests/chrome/test_tmpl_twogenerationnodes.xul new file mode 100644 index 000000000..17528d34b --- /dev/null +++ b/dom/xul/templates/tests/chrome/test_tmpl_twogenerationnodes.xul @@ -0,0 +1,100 @@ +<?xml version="1.0"?> +<?xml-stylesheet href="chrome://global/skin" type="text/css"?> +<?xml-stylesheet href="chrome://mochikit/content/tests/SimpleTest/test.css" type="text/css"?> + +<!-- + two generation nodes +--> + +<window title="XUL Template Tests" width="500" height="600" + onload="test_template();" + xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"> + <script type="application/javascript" + src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script> + + <body xmlns="http://www.w3.org/1999/xhtml" style="height: 300px; overflow: auto;"/> + + <data id="output"> + <button step="3" id="http://www.some-fictitious-zoo.com/birds/wren" label="Wren"/> + <button step="3" id="http://www.some-fictitious-zoo.com/birds/wren" label="Wren"/> + <button id="http://www.some-fictitious-zoo.com/birds/emu" label="Emu"/> + <button id="http://www.some-fictitious-zoo.com/birds/emu" label="Emu"/> + <button step="-4" id="http://www.some-fictitious-zoo.com/birds/barnowl" label="Barn Owl"/> + <button step="-4" id="http://www.some-fictitious-zoo.com/birds/barnowl" label="Barn Owl"/> + <button id="http://www.some-fictitious-zoo.com/birds/raven" label="Raven"/> + <button id="http://www.some-fictitious-zoo.com/birds/raven" label="Raven"/> + <button step="2" id="http://www.some-fictitious-zoo.com/birds/archaeopteryx" label="Archaeopteryx"/> + <button step="2" id="http://www.some-fictitious-zoo.com/birds/archaeopteryx" label="Archaeopteryx"/> + <button step="1" id="http://www.some-fictitious-zoo.com/birds/emperorpenguin" label="Emperor Penguin"/> + <button step="1" id="http://www.some-fictitious-zoo.com/birds/emperorpenguin" label="Emperor Penguin"/> + </data> + +<script src="templates_shared.js"/> + +<script> +<![CDATA[ +SimpleTest.waitForExplicitFinish(); + +var testid ="two generation nodes"; +var queryType = "rdf"; +var isTreeBuilder = false; +var needsOpen = false; +var notWorkingYet = false; +var notWorkingYetDynamic = false; +var expectedOutput = document.getElementById("output"); + +var changes = [ + // step 1 + function(targetds, root) { + var newnode = RDF.GetResource(ZOO_NS + 'birds/emperorpenguin'); + targetds.Assert(newnode, RDF.GetResource(ZOO_NS + 'rdf#name'), + RDF.GetLiteral('Emperor Penguin'), true); + var container = ContainerUtils.MakeSeq(targetds, + RDF.GetResource(ZOO_NS + 'birds')); + container.AppendElement(newnode); + }, + // step 2 + function(targetds, root) { + var newnode = RDF.GetResource(ZOO_NS + 'birds/archaeopteryx'); + targetds.Assert(newnode, RDF.GetResource(ZOO_NS + 'rdf#name'), + RDF.GetLiteral('Archaeopteryx'), true); + var container = ContainerUtils.MakeSeq(targetds, + RDF.GetResource(ZOO_NS + 'birds')); + container.InsertElementAt(newnode, '4', true); + }, + // step 3 + function(targetds, root) { + var newnode = RDF.GetResource(ZOO_NS + 'birds/wren'); + targetds.Assert(newnode, RDF.GetResource(ZOO_NS + 'rdf#name'), + RDF.GetLiteral('Wren'), true); + var container = ContainerUtils.MakeSeq(targetds, + RDF.GetResource(ZOO_NS + 'birds')); + container.InsertElementAt(newnode, '1', true); + }, + // step 4 + function(targetds, root) { + var container = ContainerUtils.MakeSeq(targetds, + RDF.GetResource(ZOO_NS + 'birds')); + var removednode = container.RemoveElementAt('3', true); + targetds.Unassert(removednode, RDF.GetResource(ZOO_NS + 'rdf#name'), + RDF.GetLiteral('Barn Owl'), true); + } +]; +]]> +</script> + +<vbox xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul" id="root" datasources="rdf:null" ref="http://www.some-fictitious-zoo.com/birds"> +<template> +<query> +<content uri="?uri"/> +<member container="?uri" child="?child"/> +<triple subject="?child" predicate="http://www.some-fictitious-zoo.com/rdf#name" object="?name"/> +</query> +<action> +<button uri="?child" label="?name"/> +<button uri="?child" label="?name"/> +</action> +</template> +</vbox> + +</window> diff --git a/dom/xul/templates/tests/chrome/test_tmpl_whereafterignorecase.xul b/dom/xul/templates/tests/chrome/test_tmpl_whereafterignorecase.xul new file mode 100644 index 000000000..1fda7ec75 --- /dev/null +++ b/dom/xul/templates/tests/chrome/test_tmpl_whereafterignorecase.xul @@ -0,0 +1,60 @@ +<?xml version="1.0"?> +<?xml-stylesheet href="chrome://global/skin" type="text/css"?> +<?xml-stylesheet href="chrome://mochikit/content/tests/SimpleTest/test.css" type="text/css"?> + +<!-- + where - after ignore case +--> + +<window title="XUL Template Tests" width="500" height="600" + onload="test_template();" + xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"> + <script type="application/javascript" + src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script> + + <body xmlns="http://www.w3.org/1999/xhtml" style="height: 300px; overflow: auto;"/> + + <data id="output"> + <label id="http://www.some-fictitious-zoo.com/mammals/lion" value="Lion"/> + <label id="http://www.some-fictitious-zoo.com/mammals/llama" value="LLAMA"/> + <label id="http://www.some-fictitious-zoo.com/mammals/polarbear" value="Polar Bear"/> + <label id="http://www.some-fictitious-zoo.com/mammals/ninebandedarmadillo" value="Nine-banded Armadillo"/> + </data> + +<script src="templates_shared.js"/> + +<script> +<![CDATA[ +SimpleTest.waitForExplicitFinish(); + +var testid ="where - after ignore case"; +var queryType = "rdf"; +var isTreeBuilder = false; +var needsOpen = false; +var notWorkingYet = false; +var notWorkingYetDynamic = false; +var expectedOutput = document.getElementById("output"); + +var changes = []; +]]> +</script> + +<vbox xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul" id="root" datasources="rdf:null" ref="http://www.some-fictitious-zoo.com/mammals"> +<template id="template"> +<query id="query"> +<content uri="?uri"/> +<member container="?uri" child="?animal"/> +<triple subject="?animal" predicate="http://www.some-fictitious-zoo.com/rdf#name" object="?name"/> +</query> +<rule> +<conditions id="conditions"> +<where subject="?name" rel="after" ignorecase="true" value="l"/> +</conditions> +<action id="action"> +<label uri="?animal" value="?name"/> +</action> +</rule> +</template> +</vbox> + +</window> diff --git a/dom/xul/templates/tests/chrome/test_tmpl_whereafterlowercase.xul b/dom/xul/templates/tests/chrome/test_tmpl_whereafterlowercase.xul new file mode 100644 index 000000000..987c9a468 --- /dev/null +++ b/dom/xul/templates/tests/chrome/test_tmpl_whereafterlowercase.xul @@ -0,0 +1,63 @@ +<?xml version="1.0"?> +<?xml-stylesheet href="chrome://global/skin" type="text/css"?> +<?xml-stylesheet href="chrome://mochikit/content/tests/SimpleTest/test.css" type="text/css"?> + +<!-- + where - after lowercase +--> + +<window title="XUL Template Tests" width="500" height="600" + onload="test_template();" + xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"> + <script type="application/javascript" + src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script> + + <body xmlns="http://www.w3.org/1999/xhtml" style="height: 300px; overflow: auto;"/> + + <data id="output"> + <label id="http://www.some-fictitious-zoo.com/mammals/lion" value="Lion"/> + <label id="http://www.some-fictitious-zoo.com/mammals/hippopotamus" value="HIPPOPOTAMUS"/> + <label id="http://www.some-fictitious-zoo.com/mammals/africanelephant" value="African Elephant"/> + <label id="http://www.some-fictitious-zoo.com/mammals/llama" value="LLAMA"/> + <label id="http://www.some-fictitious-zoo.com/mammals/polarbear" value="Polar Bear"/> + <label id="http://www.some-fictitious-zoo.com/mammals/ninebandedarmadillo" value="Nine-banded Armadillo"/> + <label id="http://www.some-fictitious-zoo.com/mammals/gorilla" value="Gorilla"/> + </data> + +<script src="templates_shared.js"/> + +<script> +<![CDATA[ +SimpleTest.waitForExplicitFinish(); + +var testid ="where - after lowercase"; +var queryType = "rdf"; +var isTreeBuilder = false; +var needsOpen = false; +var notWorkingYet = true; +var notWorkingYetDynamic = false; +var expectedOutput = document.getElementById("output"); + +var changes = []; +]]> +</script> + +<vbox xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul" id="root" datasources="rdf:null" ref="http://www.some-fictitious-zoo.com/mammals"> +<template id="template"> +<query id="query"> +<content uri="?uri"/> +<member container="?uri" child="?animal"/> +<triple subject="?animal" predicate="http://www.some-fictitious-zoo.com/rdf#name" object="?name"/> +</query> +<rule> +<conditions id="conditions"> +<where subject="?name" rel="after" value="l"/> +</conditions> +<action id="action"> +<label uri="?animal" value="?name"/> +</action> +</rule> +</template> +</vbox> + +</window> diff --git a/dom/xul/templates/tests/chrome/test_tmpl_whereafternegation.xul b/dom/xul/templates/tests/chrome/test_tmpl_whereafternegation.xul new file mode 100644 index 000000000..4ae159991 --- /dev/null +++ b/dom/xul/templates/tests/chrome/test_tmpl_whereafternegation.xul @@ -0,0 +1,59 @@ +<?xml version="1.0"?> +<?xml-stylesheet href="chrome://global/skin" type="text/css"?> +<?xml-stylesheet href="chrome://mochikit/content/tests/SimpleTest/test.css" type="text/css"?> + +<!-- + where - after negation +--> + +<window title="XUL Template Tests" width="500" height="600" + onload="test_template();" + xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"> + <script type="application/javascript" + src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script> + + <body xmlns="http://www.w3.org/1999/xhtml" style="height: 300px; overflow: auto;"/> + + <data id="output"> + <label id="http://www.some-fictitious-zoo.com/mammals/africanelephant" value="African Elephant"/> + <label id="http://www.some-fictitious-zoo.com/mammals/aardvark" value="aardvark"/> + <label id="http://www.some-fictitious-zoo.com/mammals/gorilla" value="Gorilla"/> + </data> + +<script src="templates_shared.js"/> + +<script> +<![CDATA[ +SimpleTest.waitForExplicitFinish(); + +var testid ="where - after negation"; +var queryType = "rdf"; +var isTreeBuilder = false; +var needsOpen = false; +var notWorkingYet = false; +var notWorkingYetDynamic = false; +var expectedOutput = document.getElementById("output"); + +var changes = []; +]]> +</script> + +<vbox xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul" id="root" datasources="rdf:null" ref="http://www.some-fictitious-zoo.com/mammals"> +<template id="template"> +<query id="query"> +<content uri="?uri"/> +<member container="?uri" child="?animal"/> +<triple subject="?animal" predicate="http://www.some-fictitious-zoo.com/rdf#name" object="?name"/> +</query> +<rule> +<conditions id="conditions"> +<where subject="?name" rel="after" negate="true" value="H"/> +</conditions> +<action id="action"> +<label uri="?animal" value="?name"/> +</action> +</rule> +</template> +</vbox> + +</window> diff --git a/dom/xul/templates/tests/chrome/test_tmpl_whereafteruppercase.xul b/dom/xul/templates/tests/chrome/test_tmpl_whereafteruppercase.xul new file mode 100644 index 000000000..4f11a3de3 --- /dev/null +++ b/dom/xul/templates/tests/chrome/test_tmpl_whereafteruppercase.xul @@ -0,0 +1,60 @@ +<?xml version="1.0"?> +<?xml-stylesheet href="chrome://global/skin" type="text/css"?> +<?xml-stylesheet href="chrome://mochikit/content/tests/SimpleTest/test.css" type="text/css"?> + +<!-- + where - after uppercase +--> + +<window title="XUL Template Tests" width="500" height="600" + onload="test_template();" + xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"> + <script type="application/javascript" + src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script> + + <body xmlns="http://www.w3.org/1999/xhtml" style="height: 300px; overflow: auto;"/> + + <data id="output"> + <label id="http://www.some-fictitious-zoo.com/mammals/lion" value="Lion"/> + <label id="http://www.some-fictitious-zoo.com/mammals/llama" value="LLAMA"/> + <label id="http://www.some-fictitious-zoo.com/mammals/polarbear" value="Polar Bear"/> + <label id="http://www.some-fictitious-zoo.com/mammals/ninebandedarmadillo" value="Nine-banded Armadillo"/> + </data> + +<script src="templates_shared.js"/> + +<script> +<![CDATA[ +SimpleTest.waitForExplicitFinish(); + +var testid ="where - after uppercase"; +var queryType = "rdf"; +var isTreeBuilder = false; +var needsOpen = false; +var notWorkingYet = false; +var notWorkingYetDynamic = false; +var expectedOutput = document.getElementById("output"); + +var changes = []; +]]> +</script> + +<vbox xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul" id="root" datasources="rdf:null" ref="http://www.some-fictitious-zoo.com/mammals"> +<template id="template"> +<query id="query"> +<content uri="?uri"/> +<member container="?uri" child="?animal"/> +<triple subject="?animal" predicate="http://www.some-fictitious-zoo.com/rdf#name" object="?name"/> +</query> +<rule> +<conditions id="conditions"> +<where subject="?name" rel="after" value="L"/> +</conditions> +<action id="action"> +<label uri="?animal" value="?name"/> +</action> +</rule> +</template> +</vbox> + +</window> diff --git a/dom/xul/templates/tests/chrome/test_tmpl_wherebeforeignorecase.xul b/dom/xul/templates/tests/chrome/test_tmpl_wherebeforeignorecase.xul new file mode 100644 index 000000000..130f3ee76 --- /dev/null +++ b/dom/xul/templates/tests/chrome/test_tmpl_wherebeforeignorecase.xul @@ -0,0 +1,60 @@ +<?xml version="1.0"?> +<?xml-stylesheet href="chrome://global/skin" type="text/css"?> +<?xml-stylesheet href="chrome://mochikit/content/tests/SimpleTest/test.css" type="text/css"?> + +<!-- + where - before ignore case +--> + +<window title="XUL Template Tests" width="500" height="600" + onload="test_template();" + xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"> + <script type="application/javascript" + src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script> + + <body xmlns="http://www.w3.org/1999/xhtml" style="height: 300px; overflow: auto;"/> + + <data id="output"> + <label id="http://www.some-fictitious-zoo.com/mammals/hippopotamus" value="HIPPOPOTAMUS"/> + <label id="http://www.some-fictitious-zoo.com/mammals/africanelephant" value="African Elephant"/> + <label id="http://www.some-fictitious-zoo.com/mammals/aardvark" value="aardvark"/> + <label id="http://www.some-fictitious-zoo.com/mammals/gorilla" value="Gorilla"/> + </data> + +<script src="templates_shared.js"/> + +<script> +<![CDATA[ +SimpleTest.waitForExplicitFinish(); + +var testid ="where - before ignore case"; +var queryType = "rdf"; +var isTreeBuilder = false; +var needsOpen = false; +var notWorkingYet = true; +var notWorkingYetDynamic = false; +var expectedOutput = document.getElementById("output"); + +var changes = []; +]]> +</script> + +<vbox xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul" id="root" datasources="rdf:null" ref="http://www.some-fictitious-zoo.com/mammals"> +<template id="template"> +<query id="query"> +<content uri="?uri"/> +<member container="?uri" child="?animal"/> +<triple subject="?animal" predicate="http://www.some-fictitious-zoo.com/rdf#name" object="?name"/> +</query> +<rule> +<conditions id="conditions"> +<where subject="?name" rel="before" ignorecase="true" value="h"/> +</conditions> +<action id="action"> +<label uri="?animal" value="?name"/> +</action> +</rule> +</template> +</vbox> + +</window> diff --git a/dom/xul/templates/tests/chrome/test_tmpl_wherebeforelowercase.xul b/dom/xul/templates/tests/chrome/test_tmpl_wherebeforelowercase.xul new file mode 100644 index 000000000..b6a6a1de3 --- /dev/null +++ b/dom/xul/templates/tests/chrome/test_tmpl_wherebeforelowercase.xul @@ -0,0 +1,64 @@ +<?xml version="1.0"?> +<?xml-stylesheet href="chrome://global/skin" type="text/css"?> +<?xml-stylesheet href="chrome://mochikit/content/tests/SimpleTest/test.css" type="text/css"?> + +<!-- + where - before lowercase +--> + +<window title="XUL Template Tests" width="500" height="600" + onload="test_template();" + xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"> + <script type="application/javascript" + src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script> + + <body xmlns="http://www.w3.org/1999/xhtml" style="height: 300px; overflow: auto;"/> + + <data id="output"> + <label id="http://www.some-fictitious-zoo.com/mammals/lion" value="Lion"/> + <label id="http://www.some-fictitious-zoo.com/mammals/hippopotamus" value="HIPPOPOTAMUS"/> + <label id="http://www.some-fictitious-zoo.com/mammals/africanelephant" value="African Elephant"/> + <label id="http://www.some-fictitious-zoo.com/mammals/llama" value="LLAMA"/> + <label id="http://www.some-fictitious-zoo.com/mammals/polarbear" value="Polar Bear"/> + <label id="http://www.some-fictitious-zoo.com/mammals/aardvark" value="aardvark"/> + <label id="http://www.some-fictitious-zoo.com/mammals/ninebandedarmadillo" value="Nine-banded Armadillo"/> + <label id="http://www.some-fictitious-zoo.com/mammals/gorilla" value="Gorilla"/> + </data> + +<script src="templates_shared.js"/> + +<script> +<![CDATA[ +SimpleTest.waitForExplicitFinish(); + +var testid ="where - before lowercase"; +var queryType = "rdf"; +var isTreeBuilder = false; +var needsOpen = false; +var notWorkingYet = true; +var notWorkingYetDynamic = false; +var expectedOutput = document.getElementById("output"); + +var changes = []; +]]> +</script> + +<vbox xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul" id="root" datasources="rdf:null" ref="http://www.some-fictitious-zoo.com/mammals"> +<template id="template"> +<query id="query"> +<content uri="?uri"/> +<member container="?uri" child="?animal"/> +<triple subject="?animal" predicate="http://www.some-fictitious-zoo.com/rdf#name" object="?name"/> +</query> +<rule> +<conditions id="conditions"> +<where subject="?name" rel="before" value="l"/> +</conditions> +<action id="action"> +<label uri="?animal" value="?name"/> +</action> +</rule> +</template> +</vbox> + +</window> diff --git a/dom/xul/templates/tests/chrome/test_tmpl_wherebeforenegation.xul b/dom/xul/templates/tests/chrome/test_tmpl_wherebeforenegation.xul new file mode 100644 index 000000000..9885dbfce --- /dev/null +++ b/dom/xul/templates/tests/chrome/test_tmpl_wherebeforenegation.xul @@ -0,0 +1,58 @@ +<?xml version="1.0"?> +<?xml-stylesheet href="chrome://global/skin" type="text/css"?> +<?xml-stylesheet href="chrome://mochikit/content/tests/SimpleTest/test.css" type="text/css"?> + +<!-- + where - before negation +--> + +<window title="XUL Template Tests" width="500" height="600" + onload="test_template();" + xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"> + <script type="application/javascript" + src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script> + + <body xmlns="http://www.w3.org/1999/xhtml" style="height: 300px; overflow: auto;"/> + + <data id="output"> + <label id="http://www.some-fictitious-zoo.com/mammals/polarbear" value="Polar Bear"/> + <label id="http://www.some-fictitious-zoo.com/mammals/ninebandedarmadillo" value="Nine-banded Armadillo"/> + </data> + +<script src="templates_shared.js"/> + +<script> +<![CDATA[ +SimpleTest.waitForExplicitFinish(); + +var testid ="where - before negation"; +var queryType = "rdf"; +var isTreeBuilder = false; +var needsOpen = false; +var notWorkingYet = false; +var notWorkingYetDynamic = false; +var expectedOutput = document.getElementById("output"); + +var changes = []; +]]> +</script> + +<vbox xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul" id="root" datasources="rdf:null" ref="http://www.some-fictitious-zoo.com/mammals"> +<template id="template"> +<query id="query"> +<content uri="?uri"/> +<member container="?uri" child="?animal"/> +<triple subject="?animal" predicate="http://www.some-fictitious-zoo.com/rdf#name" object="?name"/> +</query> +<rule> +<conditions id="conditions"> +<where subject="?name" rel="before" negate="true" value="N"/> +</conditions> +<action id="action"> +<label uri="?animal" value="?name"/> +</action> +</rule> +</template> +</vbox> + +</window> diff --git a/dom/xul/templates/tests/chrome/test_tmpl_wherebeforeuppercase.xul b/dom/xul/templates/tests/chrome/test_tmpl_wherebeforeuppercase.xul new file mode 100644 index 000000000..40cd73854 --- /dev/null +++ b/dom/xul/templates/tests/chrome/test_tmpl_wherebeforeuppercase.xul @@ -0,0 +1,59 @@ +<?xml version="1.0"?> +<?xml-stylesheet href="chrome://global/skin" type="text/css"?> +<?xml-stylesheet href="chrome://mochikit/content/tests/SimpleTest/test.css" type="text/css"?> + +<!-- + where - before uppercase +--> + +<window title="XUL Template Tests" width="500" height="600" + onload="test_template();" + xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"> + <script type="application/javascript" + src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script> + + <body xmlns="http://www.w3.org/1999/xhtml" style="height: 300px; overflow: auto;"/> + + <data id="output"> + <label id="http://www.some-fictitious-zoo.com/mammals/africanelephant" value="African Elephant"/> + <label id="http://www.some-fictitious-zoo.com/mammals/aardvark" value="aardvark"/> + <label id="http://www.some-fictitious-zoo.com/mammals/gorilla" value="Gorilla"/> + </data> + +<script src="templates_shared.js"/> + +<script> +<![CDATA[ +SimpleTest.waitForExplicitFinish(); + +var testid ="where - before uppercase"; +var queryType = "rdf"; +var isTreeBuilder = false; +var needsOpen = false; +var notWorkingYet = false; +var notWorkingYetDynamic = false; +var expectedOutput = document.getElementById("output"); + +var changes = []; +]]> +</script> + +<vbox xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul" id="root" datasources="rdf:null" ref="http://www.some-fictitious-zoo.com/mammals"> +<template id="template"> +<query id="query"> +<content uri="?uri"/> +<member container="?uri" child="?animal"/> +<triple subject="?animal" predicate="http://www.some-fictitious-zoo.com/rdf#name" object="?name"/> +</query> +<rule> +<conditions id="conditions"> +<where subject="?name" rel="before" value="H"/> +</conditions> +<action id="action"> +<label uri="?animal" value="?name"/> +</action> +</rule> +</template> +</vbox> + +</window> diff --git a/dom/xul/templates/tests/chrome/test_tmpl_wherecontains.xul b/dom/xul/templates/tests/chrome/test_tmpl_wherecontains.xul new file mode 100644 index 000000000..09818b1e1 --- /dev/null +++ b/dom/xul/templates/tests/chrome/test_tmpl_wherecontains.xul @@ -0,0 +1,113 @@ +<?xml version="1.0"?> +<?xml-stylesheet href="chrome://global/skin" type="text/css"?> +<?xml-stylesheet href="chrome://mochikit/content/tests/SimpleTest/test.css" type="text/css"?> + +<!-- + where - contains +--> + +<window title="XUL Template Tests" width="500" height="600" + onload="test_template();" + xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"> + <script type="application/javascript" + src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script> + + <body xmlns="http://www.w3.org/1999/xhtml" style="height: 300px; overflow: auto;"/> + + <data id="output"> + <label step="3" id="http://www.some-fictitious-zoo.com/mammals/zebra" value="Zebra"/> + <label step="-4" id="http://www.some-fictitious-zoo.com/mammals/africanelephant" value="African Elephant"/> + <label id="http://www.some-fictitious-zoo.com/mammals/polarbear" value="Polar Bear"/> + <label id="http://www.some-fictitious-zoo.com/mammals/ninebandedarmadillo" value="Nine-banded Armadillo"/> + <label step="1" id="http://www.some-fictitious-zoo.com/mammals/arctichare" value="Arctic Hare"/> + <label step="5" id="http://www.some-fictitious-zoo.com/mammals/africanelephant" value="African Elephant"/> + </data> + +<script src="templates_shared.js"/> + +<script> +<![CDATA[ +SimpleTest.waitForExplicitFinish(); + +var testid ="where - contains"; +var queryType = "rdf"; +var isTreeBuilder = false; +var needsOpen = false; +var notWorkingYet = false; +var notWorkingYetDynamic = false; +var expectedOutput = document.getElementById("output"); + +var changes = [ + // step 1 + function(targetds, root) { + var newnode = RDF.GetResource(ZOO_NS + 'mammals/arctichare'); + targetds.Assert(newnode, RDF.GetResource(ZOO_NS + 'rdf#name'), + RDF.GetLiteral('Arctic Hare'), true); + var container = ContainerUtils.MakeSeq(targetds, + RDF.GetResource(ZOO_NS + 'mammals')); + container.AppendElement(newnode); + }, + // step 2 + function(targetds, root) { + var newnode = RDF.GetResource(ZOO_NS + 'mammals/koala'); + targetds.Assert(newnode, RDF.GetResource(ZOO_NS + 'rdf#name'), + RDF.GetLiteral('Koala'), true); + var container = ContainerUtils.MakeSeq(targetds, + RDF.GetResource(ZOO_NS + 'mammals')); + container.InsertElementAt(newnode, '4', true); + }, + // step 3 + function(targetds, root) { + var newnode = RDF.GetResource(ZOO_NS + 'mammals/zebra'); + targetds.Assert(newnode, RDF.GetResource(ZOO_NS + 'rdf#name'), + RDF.GetLiteral('Zebra'), true); + var container = ContainerUtils.MakeSeq(targetds, + RDF.GetResource(ZOO_NS + 'mammals')); + container.InsertElementAt(newnode, '1', true); + }, + // step 4 + function(targetds, root) { + var container = ContainerUtils.MakeSeq(targetds, + RDF.GetResource(ZOO_NS + 'mammals')); + var removednode = container.RemoveElementAt('4', true); + targetds.Unassert(removednode, RDF.GetResource(ZOO_NS + 'rdf#name'), + RDF.GetLiteral('African Elephant'), true); + }, + // step 5 + function(targetds, root) { + var newnode = RDF.GetResource(ZOO_NS + 'mammals/africanelephant'); + targetds.Assert(newnode, RDF.GetResource(ZOO_NS + 'rdf#name'), + RDF.GetLiteral('African Elephant'), true); + var container = ContainerUtils.MakeSeq(targetds, + RDF.GetResource(ZOO_NS + 'mammals')); + container.AppendElement(newnode); + }, + // step 6 + function(targetds, root) { + targetds.Assert(RDF.GetResource(ZOO_NS + 'mammals/koala'), + RDF.GetResource(ZOO_NS + 'rdf#specimensAsString'), + RDF.GetLiteral('8'), true); + } +]; +]]> +</script> + +<vbox xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul" id="root" datasources="rdf:null" ref="http://www.some-fictitious-zoo.com/mammals"> +<template id="template"> +<query id="query"> +<content uri="?uri"/> +<member container="?uri" child="?animal"/> +<triple subject="?animal" predicate="http://www.some-fictitious-zoo.com/rdf#name" object="?name"/> +</query> +<rule> +<conditions id="conditions"> +<where subject="?name" rel="contains" value="e"/> +</conditions> +<action id="action"> +<label uri="?animal" value="?name"/> +</action> +</rule> +</template> +</vbox> + +</window> diff --git a/dom/xul/templates/tests/chrome/test_tmpl_wherecontainsignorecase.xul b/dom/xul/templates/tests/chrome/test_tmpl_wherecontainsignorecase.xul new file mode 100644 index 000000000..ecec06997 --- /dev/null +++ b/dom/xul/templates/tests/chrome/test_tmpl_wherecontainsignorecase.xul @@ -0,0 +1,59 @@ +<?xml version="1.0"?> +<?xml-stylesheet href="chrome://global/skin" type="text/css"?> +<?xml-stylesheet href="chrome://mochikit/content/tests/SimpleTest/test.css" type="text/css"?> + +<!-- + where - contains ignore case +--> + +<window title="XUL Template Tests" width="500" height="600" + onload="test_template();" + xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"> + <script type="application/javascript" + src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script> + + <body xmlns="http://www.w3.org/1999/xhtml" style="height: 300px; overflow: auto;"/> + + <data id="output"> + <label id="http://www.some-fictitious-zoo.com/mammals/hippopotamus" value="HIPPOPOTAMUS"/> + <label id="http://www.some-fictitious-zoo.com/mammals/africanelephant" value="African Elephant"/> + <label id="http://www.some-fictitious-zoo.com/mammals/polarbear" value="Polar Bear"/> + </data> + +<script src="templates_shared.js"/> + +<script> +<![CDATA[ +SimpleTest.waitForExplicitFinish(); + +var testid ="where - contains ignore case"; +var queryType = "rdf"; +var isTreeBuilder = false; +var needsOpen = false; +var notWorkingYet = false; +var notWorkingYetDynamic = false; +var expectedOutput = document.getElementById("output"); + +var changes = []; +]]> +</script> + +<vbox xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul" id="root" datasources="rdf:null" ref="http://www.some-fictitious-zoo.com/mammals"> +<template id="template"> +<query id="query"> +<content uri="?uri"/> +<member container="?uri" child="?animal"/> +<triple subject="?animal" predicate="http://www.some-fictitious-zoo.com/rdf#name" object="?name"/> +</query> +<rule> +<conditions id="conditions"> +<where subject="?name" rel="contains" ignorecase="true" value="P"/> +</conditions> +<action id="action"> +<label uri="?animal" value="?name"/> +</action> +</rule> +</template> +</vbox> + +</window> diff --git a/dom/xul/templates/tests/chrome/test_tmpl_wherecontainsnegation.xul b/dom/xul/templates/tests/chrome/test_tmpl_wherecontainsnegation.xul new file mode 100644 index 000000000..07a421ef0 --- /dev/null +++ b/dom/xul/templates/tests/chrome/test_tmpl_wherecontainsnegation.xul @@ -0,0 +1,59 @@ +<?xml version="1.0"?> +<?xml-stylesheet href="chrome://global/skin" type="text/css"?> +<?xml-stylesheet href="chrome://mochikit/content/tests/SimpleTest/test.css" type="text/css"?> + +<!-- + where - contains negation +--> + +<window title="XUL Template Tests" width="500" height="600" + onload="test_template();" + xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"> + <script type="application/javascript" + src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script> + + <body xmlns="http://www.w3.org/1999/xhtml" style="height: 300px; overflow: auto;"/> + + <data id="output"> + <label id="http://www.some-fictitious-zoo.com/mammals/lion" value="Lion"/> + <label id="http://www.some-fictitious-zoo.com/mammals/hippopotamus" value="HIPPOPOTAMUS"/> + <label id="http://www.some-fictitious-zoo.com/mammals/llama" value="LLAMA"/> + </data> + +<script src="templates_shared.js"/> + +<script> +<![CDATA[ +SimpleTest.waitForExplicitFinish(); + +var testid ="where - contains negation"; +var queryType = "rdf"; +var isTreeBuilder = false; +var needsOpen = false; +var notWorkingYet = false; +var notWorkingYetDynamic = false; +var expectedOutput = document.getElementById("output"); + +var changes = []; +]]> +</script> + +<vbox xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul" id="root" datasources="rdf:null" ref="http://www.some-fictitious-zoo.com/mammals"> +<template id="template"> +<query id="query"> +<content uri="?uri"/> +<member container="?uri" child="?animal"/> +<triple subject="?animal" predicate="http://www.some-fictitious-zoo.com/rdf#name" object="?name"/> +</query> +<rule> +<conditions id="conditions"> +<where subject="?name" rel="contains" negate="true" value="a"/> +</conditions> +<action id="action"> +<label uri="?animal" value="?name"/> +</action> +</rule> +</template> +</vbox> + +</window> diff --git a/dom/xul/templates/tests/chrome/test_tmpl_wherecontainsnumber.xul b/dom/xul/templates/tests/chrome/test_tmpl_wherecontainsnumber.xul new file mode 100644 index 000000000..b1934edca --- /dev/null +++ b/dom/xul/templates/tests/chrome/test_tmpl_wherecontainsnumber.xul @@ -0,0 +1,59 @@ +<?xml version="1.0"?> +<?xml-stylesheet href="chrome://global/skin" type="text/css"?> +<?xml-stylesheet href="chrome://mochikit/content/tests/SimpleTest/test.css" type="text/css"?> + +<!-- + where - contains number +--> + +<window title="XUL Template Tests" width="500" height="600" + onload="test_template();" + xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"> + <script type="application/javascript" + src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script> + + <body xmlns="http://www.w3.org/1999/xhtml" style="height: 300px; overflow: auto;"/> + + <data id="output"> + <label id="http://www.some-fictitious-zoo.com/mammals/hippopotamus" value="2"/> + <label id="http://www.some-fictitious-zoo.com/mammals/polarbear" value="20"/> + <label id="http://www.some-fictitious-zoo.com/mammals/aardvark" value="2"/> + </data> + +<script src="templates_shared.js"/> + +<script> +<![CDATA[ +SimpleTest.waitForExplicitFinish(); + +var testid ="where - contains number"; +var queryType = "rdf"; +var isTreeBuilder = false; +var needsOpen = false; +var notWorkingYet = false; +var notWorkingYetDynamic = false; +var expectedOutput = document.getElementById("output"); + +var changes = []; +]]> +</script> + +<vbox xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul" id="root" datasources="rdf:null" ref="http://www.some-fictitious-zoo.com/mammals"> +<template id="template"> +<query id="query"> +<content uri="?uri"/> +<member container="?uri" child="?animal"/> +<triple subject="?animal" predicate="http://www.some-fictitious-zoo.com/rdf#specimens" object="?specimens"/> +</query> +<rule> +<conditions id="conditions"> +<where subject="?specimens" rel="contains" value="2"/> +</conditions> +<action id="action"> +<label uri="?animal" value="?specimens"/> +</action> +</rule> +</template> +</vbox> + +</window> diff --git a/dom/xul/templates/tests/chrome/test_tmpl_wherecontainsnumberstring.xul b/dom/xul/templates/tests/chrome/test_tmpl_wherecontainsnumberstring.xul new file mode 100644 index 000000000..033c87506 --- /dev/null +++ b/dom/xul/templates/tests/chrome/test_tmpl_wherecontainsnumberstring.xul @@ -0,0 +1,59 @@ +<?xml version="1.0"?> +<?xml-stylesheet href="chrome://global/skin" type="text/css"?> +<?xml-stylesheet href="chrome://mochikit/content/tests/SimpleTest/test.css" type="text/css"?> + +<!-- + where - contains number string +--> + +<window title="XUL Template Tests" width="500" height="600" + onload="test_template();" + xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"> + <script type="application/javascript" + src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script> + + <body xmlns="http://www.w3.org/1999/xhtml" style="height: 300px; overflow: auto;"/> + + <data id="output"> + <label id="http://www.some-fictitious-zoo.com/mammals/hippopotamus" value="2"/> + <label id="http://www.some-fictitious-zoo.com/mammals/polarbear" value="20"/> + <label id="http://www.some-fictitious-zoo.com/mammals/aardvark" value="2"/> + </data> + +<script src="templates_shared.js"/> + +<script> +<![CDATA[ +SimpleTest.waitForExplicitFinish(); + +var testid ="where - contains number string"; +var queryType = "rdf"; +var isTreeBuilder = false; +var needsOpen = false; +var notWorkingYet = false; +var notWorkingYetDynamic = false; +var expectedOutput = document.getElementById("output"); + +var changes = []; +]]> +</script> + +<vbox xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul" id="root" datasources="rdf:null" ref="http://www.some-fictitious-zoo.com/mammals"> +<template id="template"> +<query id="query"> +<content uri="?uri"/> +<member container="?uri" child="?animal"/> +<triple subject="?animal" predicate="http://www.some-fictitious-zoo.com/rdf#specimensAsString" object="?specimens"/> +</query> +<rule> +<conditions id="conditions"> +<where subject="?specimens" rel="contains" value="2"/> +</conditions> +<action id="action"> +<label uri="?animal" value="?specimens"/> +</action> +</rule> +</template> +</vbox> + +</window> diff --git a/dom/xul/templates/tests/chrome/test_tmpl_wherecontainsresource.xul b/dom/xul/templates/tests/chrome/test_tmpl_wherecontainsresource.xul new file mode 100644 index 000000000..45569d41e --- /dev/null +++ b/dom/xul/templates/tests/chrome/test_tmpl_wherecontainsresource.xul @@ -0,0 +1,57 @@ +<?xml version="1.0"?> +<?xml-stylesheet href="chrome://global/skin" type="text/css"?> +<?xml-stylesheet href="chrome://mochikit/content/tests/SimpleTest/test.css" type="text/css"?> + +<!-- + where - contains resource +--> + +<window title="XUL Template Tests" width="500" height="600" + onload="test_template();" + xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"> + <script type="application/javascript" + src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script> + + <body xmlns="http://www.w3.org/1999/xhtml" style="height: 300px; overflow: auto;"/> + + <data id="output"> + <label id="http://www.some-fictitious-zoo.com/mammals/llama" value="LLAMA"/> + </data> + +<script src="templates_shared.js"/> + +<script> +<![CDATA[ +SimpleTest.waitForExplicitFinish(); + +var testid ="where - contains resource"; +var queryType = "rdf"; +var isTreeBuilder = false; +var needsOpen = false; +var notWorkingYet = false; +var notWorkingYetDynamic = false; +var expectedOutput = document.getElementById("output"); + +var changes = []; +]]> +</script> + +<vbox xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul" id="root" datasources="rdf:null" ref="http://www.some-fictitious-zoo.com/mammals"> +<template id="template"> +<query id="query"> +<content uri="?uri"/> +<member container="?uri" child="?animal"/> +<triple subject="?animal" predicate="http://www.some-fictitious-zoo.com/rdf#name" object="?name"/> +</query> +<rule> +<conditions id="conditions"> +<where subject="?animal" rel="contains" value="/llama"/> +</conditions> +<action id="action"> +<label uri="?animal" value="?name"/> +</action> +</rule> +</template> +</vbox> + +</window> diff --git a/dom/xul/templates/tests/chrome/test_tmpl_wherecontainstwo.xul b/dom/xul/templates/tests/chrome/test_tmpl_wherecontainstwo.xul new file mode 100644 index 000000000..1519862fa --- /dev/null +++ b/dom/xul/templates/tests/chrome/test_tmpl_wherecontainstwo.xul @@ -0,0 +1,113 @@ +<?xml version="1.0"?> +<?xml-stylesheet href="chrome://global/skin" type="text/css"?> +<?xml-stylesheet href="chrome://mochikit/content/tests/SimpleTest/test.css" type="text/css"?> + +<!-- + where - contains two +--> + +<window title="XUL Template Tests" width="500" height="600" + onload="test_template();" + xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"> + <script type="application/javascript" + src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script> + + <body xmlns="http://www.w3.org/1999/xhtml" style="height: 300px; overflow: auto;"/> + + <data id="output"> + <label step="-4" id="http://www.some-fictitious-zoo.com/mammals/africanelephant" value="African Elephant"/> + <label id="http://www.some-fictitious-zoo.com/mammals/ninebandedarmadillo" value="Nine-banded Armadillo"/> + <label id="http://www.some-fictitious-zoo.com/mammals/gorilla" value="Gorilla"/> + <label step="1" id="http://www.some-fictitious-zoo.com/mammals/arctichare" value="Arctic Hare"/> + <label step="5" id="http://www.some-fictitious-zoo.com/mammals/africanelephant" value="African Elephant"/> + </data> + +<script src="templates_shared.js"/> + +<script> +<![CDATA[ +SimpleTest.waitForExplicitFinish(); + +var testid ="where - contains two"; +var queryType = "rdf"; +var isTreeBuilder = false; +var needsOpen = false; +var notWorkingYet = false; +var notWorkingYetDynamic = false; +var expectedOutput = document.getElementById("output"); + +var changes = [ + // step 1 + function(targetds, root) { + var newnode = RDF.GetResource(ZOO_NS + 'mammals/arctichare'); + targetds.Assert(newnode, RDF.GetResource(ZOO_NS + 'rdf#name'), + RDF.GetLiteral('Arctic Hare'), true); + var container = ContainerUtils.MakeSeq(targetds, + RDF.GetResource(ZOO_NS + 'mammals')); + container.AppendElement(newnode); + }, + // step 2 + function(targetds, root) { + var newnode = RDF.GetResource(ZOO_NS + 'mammals/koala'); + targetds.Assert(newnode, RDF.GetResource(ZOO_NS + 'rdf#name'), + RDF.GetLiteral('Koala'), true); + var container = ContainerUtils.MakeSeq(targetds, + RDF.GetResource(ZOO_NS + 'mammals')); + container.InsertElementAt(newnode, '4', true); + }, + // step 3 + function(targetds, root) { + var newnode = RDF.GetResource(ZOO_NS + 'mammals/zebra'); + targetds.Assert(newnode, RDF.GetResource(ZOO_NS + 'rdf#name'), + RDF.GetLiteral('Zebra'), true); + var container = ContainerUtils.MakeSeq(targetds, + RDF.GetResource(ZOO_NS + 'mammals')); + container.InsertElementAt(newnode, '1', true); + }, + // step 4 + function(targetds, root) { + var container = ContainerUtils.MakeSeq(targetds, + RDF.GetResource(ZOO_NS + 'mammals')); + var removednode = container.RemoveElementAt('4', true); + targetds.Unassert(removednode, RDF.GetResource(ZOO_NS + 'rdf#name'), + RDF.GetLiteral('African Elephant'), true); + }, + // step 5 + function(targetds, root) { + var newnode = RDF.GetResource(ZOO_NS + 'mammals/africanelephant'); + targetds.Assert(newnode, RDF.GetResource(ZOO_NS + 'rdf#name'), + RDF.GetLiteral('African Elephant'), true); + var container = ContainerUtils.MakeSeq(targetds, + RDF.GetResource(ZOO_NS + 'mammals')); + container.AppendElement(newnode); + }, + // step 6 + function(targetds, root) { + targetds.Assert(RDF.GetResource(ZOO_NS + 'mammals/koala'), + RDF.GetResource(ZOO_NS + 'rdf#specimensAsString'), + RDF.GetLiteral('8'), true); + } +]; +]]> +</script> + +<vbox xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul" id="root" datasources="rdf:null" ref="http://www.some-fictitious-zoo.com/mammals"> +<template id="template"> +<query id="query"> +<content uri="?uri"/> +<member container="?uri" child="?animal"/> +<triple subject="?animal" predicate="http://www.some-fictitious-zoo.com/rdf#name" object="?name"/> +</query> +<rule> +<conditions id="conditions"> +<where subject="?name" rel="contains" value="i"/> +<where subject="?name" rel="contains" value="r"/> +</conditions> +<action id="action"> +<label uri="?animal" value="?name"/> +</action> +</rule> +</template> +</vbox> + +</window> diff --git a/dom/xul/templates/tests/chrome/test_tmpl_whereendswith.xul b/dom/xul/templates/tests/chrome/test_tmpl_whereendswith.xul new file mode 100644 index 000000000..69a6d68fc --- /dev/null +++ b/dom/xul/templates/tests/chrome/test_tmpl_whereendswith.xul @@ -0,0 +1,57 @@ +<?xml version="1.0"?> +<?xml-stylesheet href="chrome://global/skin" type="text/css"?> +<?xml-stylesheet href="chrome://mochikit/content/tests/SimpleTest/test.css" type="text/css"?> + +<!-- + where - endswith +--> + +<window title="XUL Template Tests" width="500" height="600" + onload="test_template();" + xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"> + <script type="application/javascript" + src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script> + + <body xmlns="http://www.w3.org/1999/xhtml" style="height: 300px; overflow: auto;"/> + + <data id="output"> + <label id="http://www.some-fictitious-zoo.com/mammals/gorilla" value="Gorilla"/> + </data> + +<script src="templates_shared.js"/> + +<script> +<![CDATA[ +SimpleTest.waitForExplicitFinish(); + +var testid ="where - endswith"; +var queryType = "rdf"; +var isTreeBuilder = false; +var needsOpen = false; +var notWorkingYet = false; +var notWorkingYetDynamic = false; +var expectedOutput = document.getElementById("output"); + +var changes = []; +]]> +</script> + +<vbox xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul" id="root" datasources="rdf:null" ref="http://www.some-fictitious-zoo.com/mammals"> +<template id="template"> +<query id="query"> +<content uri="?uri"/> +<member container="?uri" child="?animal"/> +<triple subject="?animal" predicate="http://www.some-fictitious-zoo.com/rdf#name" object="?name"/> +</query> +<rule> +<conditions id="conditions"> +<where subject="?name" rel="endswith" value="a"/> +</conditions> +<action id="action"> +<label uri="?animal" value="?name"/> +</action> +</rule> +</template> +</vbox> + +</window> diff --git a/dom/xul/templates/tests/chrome/test_tmpl_whereendswithignorecase.xul b/dom/xul/templates/tests/chrome/test_tmpl_whereendswithignorecase.xul new file mode 100644 index 000000000..34794c51a --- /dev/null +++ b/dom/xul/templates/tests/chrome/test_tmpl_whereendswithignorecase.xul @@ -0,0 +1,58 @@ +<?xml version="1.0"?> +<?xml-stylesheet href="chrome://global/skin" type="text/css"?> +<?xml-stylesheet href="chrome://mochikit/content/tests/SimpleTest/test.css" type="text/css"?> + +<!-- + where - endswith ignore case +--> + +<window title="XUL Template Tests" width="500" height="600" + onload="test_template();" + xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"> + <script type="application/javascript" + src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script> + + <body xmlns="http://www.w3.org/1999/xhtml" style="height: 300px; overflow: auto;"/> + + <data id="output"> + <label id="http://www.some-fictitious-zoo.com/mammals/llama" value="LLAMA"/> + <label id="http://www.some-fictitious-zoo.com/mammals/gorilla" value="Gorilla"/> + </data> + +<script src="templates_shared.js"/> + +<script> +<![CDATA[ +SimpleTest.waitForExplicitFinish(); + +var testid ="where - endswith ignore case"; +var queryType = "rdf"; +var isTreeBuilder = false; +var needsOpen = false; +var notWorkingYet = false; +var notWorkingYetDynamic = false; +var expectedOutput = document.getElementById("output"); + +var changes = []; +]]> +</script> + +<vbox xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul" id="root" datasources="rdf:null" ref="http://www.some-fictitious-zoo.com/mammals"> +<template id="template"> +<query id="query"> +<content uri="?uri"/> +<member container="?uri" child="?animal"/> +<triple subject="?animal" predicate="http://www.some-fictitious-zoo.com/rdf#name" object="?name"/> +</query> +<rule> +<conditions id="conditions"> +<where subject="?name" rel="endswith" ignorecase="true" value="A"/> +</conditions> +<action id="action"> +<label uri="?animal" value="?name"/> +</action> +</rule> +</template> +</vbox> + +</window> diff --git a/dom/xul/templates/tests/chrome/test_tmpl_whereendswithnegation.xul b/dom/xul/templates/tests/chrome/test_tmpl_whereendswithnegation.xul new file mode 100644 index 000000000..8d3d0c575 --- /dev/null +++ b/dom/xul/templates/tests/chrome/test_tmpl_whereendswithnegation.xul @@ -0,0 +1,63 @@ +<?xml version="1.0"?> +<?xml-stylesheet href="chrome://global/skin" type="text/css"?> +<?xml-stylesheet href="chrome://mochikit/content/tests/SimpleTest/test.css" type="text/css"?> + +<!-- + where - endswith negation +--> + +<window title="XUL Template Tests" width="500" height="600" + onload="test_template();" + xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"> + <script type="application/javascript" + src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script> + + <body xmlns="http://www.w3.org/1999/xhtml" style="height: 300px; overflow: auto;"/> + + <data id="output"> + <label id="http://www.some-fictitious-zoo.com/mammals/lion" value="Lion"/> + <label id="http://www.some-fictitious-zoo.com/mammals/hippopotamus" value="HIPPOPOTAMUS"/> + <label id="http://www.some-fictitious-zoo.com/mammals/africanelephant" value="African Elephant"/> + <label id="http://www.some-fictitious-zoo.com/mammals/llama" value="LLAMA"/> + <label id="http://www.some-fictitious-zoo.com/mammals/polarbear" value="Polar Bear"/> + <label id="http://www.some-fictitious-zoo.com/mammals/ninebandedarmadillo" value="Nine-banded Armadillo"/> + <label id="http://www.some-fictitious-zoo.com/mammals/gorilla" value="Gorilla"/> + </data> + +<script src="templates_shared.js"/> + +<script> +<![CDATA[ +SimpleTest.waitForExplicitFinish(); + +var testid ="where - endswith negation"; +var queryType = "rdf"; +var isTreeBuilder = false; +var needsOpen = false; +var notWorkingYet = false; +var notWorkingYetDynamic = false; +var expectedOutput = document.getElementById("output"); + +var changes = []; +]]> +</script> + +<vbox xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul" id="root" datasources="rdf:null" ref="http://www.some-fictitious-zoo.com/mammals"> +<template id="template"> +<query id="query"> +<content uri="?uri"/> +<member container="?uri" child="?animal"/> +<triple subject="?animal" predicate="http://www.some-fictitious-zoo.com/rdf#name" object="?name"/> +</query> +<rule> +<conditions id="conditions"> +<where subject="?name" rel="endswith" negate="true" value="k"/> +</conditions> +<action id="action"> +<label uri="?animal" value="?name"/> +</action> +</rule> +</template> +</vbox> + +</window> diff --git a/dom/xul/templates/tests/chrome/test_tmpl_whereequals.xul b/dom/xul/templates/tests/chrome/test_tmpl_whereequals.xul new file mode 100644 index 000000000..2679c607e --- /dev/null +++ b/dom/xul/templates/tests/chrome/test_tmpl_whereequals.xul @@ -0,0 +1,109 @@ +<?xml version="1.0"?> +<?xml-stylesheet href="chrome://global/skin" type="text/css"?> +<?xml-stylesheet href="chrome://mochikit/content/tests/SimpleTest/test.css" type="text/css"?> + +<!-- + where - equals +--> + +<window title="XUL Template Tests" width="500" height="600" + onload="test_template();" + xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"> + <script type="application/javascript" + src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script> + + <body xmlns="http://www.w3.org/1999/xhtml" style="height: 300px; overflow: auto;"/> + + <data id="output"> + <label step="-4" id="http://www.some-fictitious-zoo.com/mammals/africanelephant" value="African Elephant"/> + <label step="5" id="http://www.some-fictitious-zoo.com/mammals/africanelephant" value="African Elephant"/> + </data> + +<script src="templates_shared.js"/> + +<script> +<![CDATA[ +SimpleTest.waitForExplicitFinish(); + +var testid ="where - equals"; +var queryType = "rdf"; +var isTreeBuilder = false; +var needsOpen = false; +var notWorkingYet = false; +var notWorkingYetDynamic = false; +var expectedOutput = document.getElementById("output"); + +var changes = [ + // step 1 + function(targetds, root) { + var newnode = RDF.GetResource(ZOO_NS + 'mammals/arctichare'); + targetds.Assert(newnode, RDF.GetResource(ZOO_NS + 'rdf#name'), + RDF.GetLiteral('Arctic Hare'), true); + var container = ContainerUtils.MakeSeq(targetds, + RDF.GetResource(ZOO_NS + 'mammals')); + container.AppendElement(newnode); + }, + // step 2 + function(targetds, root) { + var newnode = RDF.GetResource(ZOO_NS + 'mammals/koala'); + targetds.Assert(newnode, RDF.GetResource(ZOO_NS + 'rdf#name'), + RDF.GetLiteral('Koala'), true); + var container = ContainerUtils.MakeSeq(targetds, + RDF.GetResource(ZOO_NS + 'mammals')); + container.InsertElementAt(newnode, '4', true); + }, + // step 3 + function(targetds, root) { + var newnode = RDF.GetResource(ZOO_NS + 'mammals/zebra'); + targetds.Assert(newnode, RDF.GetResource(ZOO_NS + 'rdf#name'), + RDF.GetLiteral('Zebra'), true); + var container = ContainerUtils.MakeSeq(targetds, + RDF.GetResource(ZOO_NS + 'mammals')); + container.InsertElementAt(newnode, '1', true); + }, + // step 4 + function(targetds, root) { + var container = ContainerUtils.MakeSeq(targetds, + RDF.GetResource(ZOO_NS + 'mammals')); + var removednode = container.RemoveElementAt('4', true); + targetds.Unassert(removednode, RDF.GetResource(ZOO_NS + 'rdf#name'), + RDF.GetLiteral('African Elephant'), true); + }, + // step 5 + function(targetds, root) { + var newnode = RDF.GetResource(ZOO_NS + 'mammals/africanelephant'); + targetds.Assert(newnode, RDF.GetResource(ZOO_NS + 'rdf#name'), + RDF.GetLiteral('African Elephant'), true); + var container = ContainerUtils.MakeSeq(targetds, + RDF.GetResource(ZOO_NS + 'mammals')); + container.AppendElement(newnode); + }, + // step 6 + function(targetds, root) { + targetds.Assert(RDF.GetResource(ZOO_NS + 'mammals/koala'), + RDF.GetResource(ZOO_NS + 'rdf#specimensAsString'), + RDF.GetLiteral('8'), true); + } +]; +]]> +</script> + +<vbox xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul" id="root" datasources="rdf:null" ref="http://www.some-fictitious-zoo.com/mammals"> +<template id="template"> +<query id="query"> +<content uri="?uri"/> +<member container="?uri" child="?animal"/> +<triple subject="?animal" predicate="http://www.some-fictitious-zoo.com/rdf#name" object="?name"/> +</query> +<rule> +<conditions id="conditions"> +<where subject="?name" rel="equals" value="African Elephant"/> +</conditions> +<action id="action"> +<label uri="?animal" value="?name"/> +</action> +</rule> +</template> +</vbox> + +</window> diff --git a/dom/xul/templates/tests/chrome/test_tmpl_whereequalsignorecase.xul b/dom/xul/templates/tests/chrome/test_tmpl_whereequalsignorecase.xul new file mode 100644 index 000000000..e26be898b --- /dev/null +++ b/dom/xul/templates/tests/chrome/test_tmpl_whereequalsignorecase.xul @@ -0,0 +1,57 @@ +<?xml version="1.0"?> +<?xml-stylesheet href="chrome://global/skin" type="text/css"?> +<?xml-stylesheet href="chrome://mochikit/content/tests/SimpleTest/test.css" type="text/css"?> + +<!-- + where - equals ignore case +--> + +<window title="XUL Template Tests" width="500" height="600" + onload="test_template();" + xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"> + <script type="application/javascript" + src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script> + + <body xmlns="http://www.w3.org/1999/xhtml" style="height: 300px; overflow: auto;"/> + + <data id="output"> + <label id="http://www.some-fictitious-zoo.com/mammals/gorilla" value="Gorilla"/> + </data> + +<script src="templates_shared.js"/> + +<script> +<![CDATA[ +SimpleTest.waitForExplicitFinish(); + +var testid ="where - equals ignore case"; +var queryType = "rdf"; +var isTreeBuilder = false; +var needsOpen = false; +var notWorkingYet = false; +var notWorkingYetDynamic = false; +var expectedOutput = document.getElementById("output"); + +var changes = []; +]]> +</script> + +<vbox xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul" id="root" datasources="rdf:null" ref="http://www.some-fictitious-zoo.com/mammals"> +<template id="template"> +<query id="query"> +<content uri="?uri"/> +<member container="?uri" child="?animal"/> +<triple subject="?animal" predicate="http://www.some-fictitious-zoo.com/rdf#name" object="?name"/> +</query> +<rule> +<conditions id="conditions"> +<where subject="?name" rel="equals" ignorecase="true" value="GoriLLA"/> +</conditions> +<action id="action"> +<label uri="?animal" value="?name"/> +</action> +</rule> +</template> +</vbox> + +</window> diff --git a/dom/xul/templates/tests/chrome/test_tmpl_whereequalsmultiple.xul b/dom/xul/templates/tests/chrome/test_tmpl_whereequalsmultiple.xul new file mode 100644 index 000000000..00558388d --- /dev/null +++ b/dom/xul/templates/tests/chrome/test_tmpl_whereequalsmultiple.xul @@ -0,0 +1,58 @@ +<?xml version="1.0"?> +<?xml-stylesheet href="chrome://global/skin" type="text/css"?> +<?xml-stylesheet href="chrome://mochikit/content/tests/SimpleTest/test.css" type="text/css"?> + +<!-- + where - equals multiple +--> + +<window title="XUL Template Tests" width="500" height="600" + onload="test_template();" + xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"> + <script type="application/javascript" + src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script> + + <body xmlns="http://www.w3.org/1999/xhtml" style="height: 300px; overflow: auto;"/> + + <data id="output"> + <label id="http://www.some-fictitious-zoo.com/mammals/lion" value="Lion"/> + <label id="http://www.some-fictitious-zoo.com/mammals/gorilla" value="Gorilla"/> + </data> + +<script src="templates_shared.js"/> + +<script> +<![CDATA[ +SimpleTest.waitForExplicitFinish(); + +var testid ="where - equals multiple"; +var queryType = "rdf"; +var isTreeBuilder = false; +var needsOpen = false; +var notWorkingYet = false; +var notWorkingYetDynamic = false; +var expectedOutput = document.getElementById("output"); + +var changes = []; +]]> +</script> + +<vbox xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul" id="root" datasources="rdf:null" ref="http://www.some-fictitious-zoo.com/mammals"> +<template id="template"> +<query id="query"> +<content uri="?uri"/> +<member container="?uri" child="?animal"/> +<triple subject="?animal" predicate="http://www.some-fictitious-zoo.com/rdf#name" object="?name"/> +</query> +<rule> +<conditions id="conditions"> +<where subject="?name" rel="equals" multiple="true" value="Lion,Gorilla"/> +</conditions> +<action id="action"> +<label uri="?animal" value="?name"/> +</action> +</rule> +</template> +</vbox> + +</window> diff --git a/dom/xul/templates/tests/chrome/test_tmpl_whereequalsmultiplenegation.xul b/dom/xul/templates/tests/chrome/test_tmpl_whereequalsmultiplenegation.xul new file mode 100644 index 000000000..a66792dd7 --- /dev/null +++ b/dom/xul/templates/tests/chrome/test_tmpl_whereequalsmultiplenegation.xul @@ -0,0 +1,125 @@ +<?xml version="1.0"?> +<?xml-stylesheet href="chrome://global/skin" type="text/css"?> +<?xml-stylesheet href="chrome://mochikit/content/tests/SimpleTest/test.css" type="text/css"?> + +<!-- + where - equals multiple negation +--> + +<window title="XUL Template Tests" width="500" height="600" + onload="test_template();" + xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"> + <script type="application/javascript" + src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script> + + <body xmlns="http://www.w3.org/1999/xhtml" style="height: 300px; overflow: auto;"/> + + <data id="output"> + <label step="3" id="http://www.some-fictitious-zoo.com/mammals/zebra" value="Zebra"/> + <label id="http://www.some-fictitious-zoo.com/mammals/hippopotamus" value="HIPPOPOTAMUS"/> + <label step="-4" id="http://www.some-fictitious-zoo.com/mammals/africanelephant" value="African Elephant"/> + <label id="http://www.some-fictitious-zoo.com/mammals/polarbear" value="Polar Bear"/> + <label id="http://www.some-fictitious-zoo.com/mammals/ninebandedarmadillo" value="Nine-banded Armadillo"/> + <label step="1" id="http://www.some-fictitious-zoo.com/mammals/arctichare" value="Arctic Hare"/> + <label step="5" id="http://www.some-fictitious-zoo.com/mammals/africanelephant" value="African Elephant"/> + </data> + +<script src="templates_shared.js"/> + +<script> +<![CDATA[ +SimpleTest.waitForExplicitFinish(); + +var testid ="where - equals multiple negation"; +var queryType = "rdf"; +var isTreeBuilder = false; +var needsOpen = false; +var notWorkingYet = false; +var notWorkingYetDynamic = false; +var expectedOutput = document.getElementById("output"); + +var changes = [ + // step 1 + function(targetds, root) { + var newnode = RDF.GetResource(ZOO_NS + 'mammals/arctichare'); + targetds.Assert(newnode, RDF.GetResource(ZOO_NS + 'rdf#name'), + RDF.GetLiteral('Arctic Hare'), true); + var container = ContainerUtils.MakeSeq(targetds, + RDF.GetResource(ZOO_NS + 'mammals')); + container.AppendElement(newnode); + expectConsoleMessage(ZOO_NS + 'mammals', ZOO_NS + 'mammals/arctichare', true, true, + '1 matching rule 1'); + }, + // step 2 + function(targetds, root) { + var newnode = RDF.GetResource(ZOO_NS + 'mammals/koala'); + targetds.Assert(newnode, RDF.GetResource(ZOO_NS + 'rdf#name'), + RDF.GetLiteral('Koala'), true); + var container = ContainerUtils.MakeSeq(targetds, + RDF.GetResource(ZOO_NS + 'mammals')); + container.InsertElementAt(newnode, '4', true); + expectConsoleMessage(ZOO_NS + 'mammals', ZOO_NS + 'mammals/koala', true, false, + '1 (didn\'t match a rule)'); + }, + // step 3 + function(targetds, root) { + var newnode = RDF.GetResource(ZOO_NS + 'mammals/zebra'); + targetds.Assert(newnode, RDF.GetResource(ZOO_NS + 'rdf#name'), + RDF.GetLiteral('Zebra'), true); + var container = ContainerUtils.MakeSeq(targetds, + RDF.GetResource(ZOO_NS + 'mammals')); + container.InsertElementAt(newnode, '1', true); + expectConsoleMessage(ZOO_NS + 'mammals', ZOO_NS + 'mammals/zebra', true, true, + '1 matching rule 1'); + }, + // step 4 + function(targetds, root) { + var container = ContainerUtils.MakeSeq(targetds, + RDF.GetResource(ZOO_NS + 'mammals')); + var removednode = container.RemoveElementAt('4', true); + targetds.Unassert(removednode, RDF.GetResource(ZOO_NS + 'rdf#name'), + RDF.GetLiteral('African Elephant'), true); + expectConsoleMessage(ZOO_NS + 'mammals', ZOO_NS + 'mammals/africanelephant', false, true, + '1 (no new active query)'); + }, + // step 5 + function(targetds, root) { + var newnode = RDF.GetResource(ZOO_NS + 'mammals/africanelephant'); + targetds.Assert(newnode, RDF.GetResource(ZOO_NS + 'rdf#name'), + RDF.GetLiteral('African Elephant'), true); + var container = ContainerUtils.MakeSeq(targetds, + RDF.GetResource(ZOO_NS + 'mammals')); + container.AppendElement(newnode); + expectConsoleMessage(ZOO_NS + 'mammals', ZOO_NS + 'mammals/africanelephant', true, true, + '1 matching rule 1'); + }, + // step 6 + function(targetds, root) { + targetds.Assert(RDF.GetResource(ZOO_NS + 'mammals/koala'), + RDF.GetResource(ZOO_NS + 'rdf#specimensAsString'), + RDF.GetLiteral('8'), true); + } +]; +]]> +</script> + +<vbox xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul" id="root" flags="logging" + datasources="rdf:null" ref="http://www.some-fictitious-zoo.com/mammals"> +<template id="template"> +<query id="query"> +<content uri="?uri"/> +<member container="?uri" child="?animal"/> +<triple subject="?animal" predicate="http://www.some-fictitious-zoo.com/rdf#name" object="?name"/> +</query> +<rule> +<conditions id="conditions"> +<where subject="?name" rel="equals" multiple="true" negate="true" value="Lion,aardvark,LLAMA,Gorilla,Koala"/> +</conditions> +<action id="action"> +<label uri="?animal" value="?name"/> +</action> +</rule> +</template> +</vbox> + +</window> diff --git a/dom/xul/templates/tests/chrome/test_tmpl_whereequalsmultiplenegationignorecase.xul b/dom/xul/templates/tests/chrome/test_tmpl_whereequalsmultiplenegationignorecase.xul new file mode 100644 index 000000000..67b3f2fcf --- /dev/null +++ b/dom/xul/templates/tests/chrome/test_tmpl_whereequalsmultiplenegationignorecase.xul @@ -0,0 +1,60 @@ +<?xml version="1.0"?> +<?xml-stylesheet href="chrome://global/skin" type="text/css"?> +<?xml-stylesheet href="chrome://mochikit/content/tests/SimpleTest/test.css" type="text/css"?> + +<!-- + where - equals multiple negation ignore case +--> + +<window title="XUL Template Tests" width="500" height="600" + onload="test_template();" + xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"> + <script type="application/javascript" + src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script> + + <body xmlns="http://www.w3.org/1999/xhtml" style="height: 300px; overflow: auto;"/> + + <data id="output"> + <label id="http://www.some-fictitious-zoo.com/mammals/hippopotamus" value="HIPPOPOTAMUS"/> + <label id="http://www.some-fictitious-zoo.com/mammals/africanelephant" value="African Elephant"/> + <label id="http://www.some-fictitious-zoo.com/mammals/ninebandedarmadillo" value="Nine-banded Armadillo"/> + <label id="http://www.some-fictitious-zoo.com/mammals/gorilla" value="Gorilla"/> + </data> + +<script src="templates_shared.js"/> + +<script> +<![CDATA[ +SimpleTest.waitForExplicitFinish(); + +var testid ="where - equals multiple negation ignore case"; +var queryType = "rdf"; +var isTreeBuilder = false; +var needsOpen = false; +var notWorkingYet = false; +var notWorkingYetDynamic = false; +var expectedOutput = document.getElementById("output"); + +var changes = []; +]]> +</script> + +<vbox xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul" id="root" datasources="rdf:null" ref="http://www.some-fictitious-zoo.com/mammals"> +<template id="template"> +<query id="query"> +<content uri="?uri"/> +<member container="?uri" child="?animal"/> +<triple subject="?animal" predicate="http://www.some-fictitious-zoo.com/rdf#name" object="?name"/> +</query> +<rule> +<conditions id="conditions"> +<where subject="?name" rel="equals" multiple="true" ignorecase="true" negate="true" value="Lion,Aardvark,llama,Polar BEAR"/> +</conditions> +<action id="action"> +<label uri="?animal" value="?name"/> +</action> +</rule> +</template> +</vbox> + +</window> diff --git a/dom/xul/templates/tests/chrome/test_tmpl_whereequalsnegation.xul b/dom/xul/templates/tests/chrome/test_tmpl_whereequalsnegation.xul new file mode 100644 index 000000000..edcac5542 --- /dev/null +++ b/dom/xul/templates/tests/chrome/test_tmpl_whereequalsnegation.xul @@ -0,0 +1,63 @@ +<?xml version="1.0"?> +<?xml-stylesheet href="chrome://global/skin" type="text/css"?> +<?xml-stylesheet href="chrome://mochikit/content/tests/SimpleTest/test.css" type="text/css"?> + +<!-- + where - equals negation +--> + +<window title="XUL Template Tests" width="500" height="600" + onload="test_template();" + xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"> + <script type="application/javascript" + src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script> + + <body xmlns="http://www.w3.org/1999/xhtml" style="height: 300px; overflow: auto;"/> + + <data id="output"> + <label id="http://www.some-fictitious-zoo.com/mammals/lion" value="Lion"/> + <label id="http://www.some-fictitious-zoo.com/mammals/hippopotamus" value="HIPPOPOTAMUS"/> + <label id="http://www.some-fictitious-zoo.com/mammals/africanelephant" value="African Elephant"/> + <label id="http://www.some-fictitious-zoo.com/mammals/llama" value="LLAMA"/> + <label id="http://www.some-fictitious-zoo.com/mammals/aardvark" value="aardvark"/> + <label id="http://www.some-fictitious-zoo.com/mammals/ninebandedarmadillo" value="Nine-banded Armadillo"/> + <label id="http://www.some-fictitious-zoo.com/mammals/gorilla" value="Gorilla"/> + </data> + +<script src="templates_shared.js"/> + +<script> +<![CDATA[ +SimpleTest.waitForExplicitFinish(); + +var testid ="where - equals negation"; +var queryType = "rdf"; +var isTreeBuilder = false; +var needsOpen = false; +var notWorkingYet = false; +var notWorkingYetDynamic = false; +var expectedOutput = document.getElementById("output"); + +var changes = []; +]]> +</script> + +<vbox xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul" id="root" datasources="rdf:null" ref="http://www.some-fictitious-zoo.com/mammals"> +<template id="template"> +<query id="query"> +<content uri="?uri"/> +<member container="?uri" child="?animal"/> +<triple subject="?animal" predicate="http://www.some-fictitious-zoo.com/rdf#name" object="?name"/> +</query> +<rule> +<conditions id="conditions"> +<where subject="?name" rel="equals" negate="true" value="Polar Bear"/> +</conditions> +<action id="action"> +<label uri="?animal" value="?name"/> +</action> +</rule> +</template> +</vbox> + +</window> diff --git a/dom/xul/templates/tests/chrome/test_tmpl_whereequalsnegationignorecase.xul b/dom/xul/templates/tests/chrome/test_tmpl_whereequalsnegationignorecase.xul new file mode 100644 index 000000000..cd877f1ce --- /dev/null +++ b/dom/xul/templates/tests/chrome/test_tmpl_whereequalsnegationignorecase.xul @@ -0,0 +1,63 @@ +<?xml version="1.0"?> +<?xml-stylesheet href="chrome://global/skin" type="text/css"?> +<?xml-stylesheet href="chrome://mochikit/content/tests/SimpleTest/test.css" type="text/css"?> + +<!-- + where - equals negation ignore case +--> + +<window title="XUL Template Tests" width="500" height="600" + onload="test_template();" + xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"> + <script type="application/javascript" + src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script> + + <body xmlns="http://www.w3.org/1999/xhtml" style="height: 300px; overflow: auto;"/> + + <data id="output"> + <label id="http://www.some-fictitious-zoo.com/mammals/lion" value="Lion"/> + <label id="http://www.some-fictitious-zoo.com/mammals/hippopotamus" value="HIPPOPOTAMUS"/> + <label id="http://www.some-fictitious-zoo.com/mammals/llama" value="LLAMA"/> + <label id="http://www.some-fictitious-zoo.com/mammals/polarbear" value="Polar Bear"/> + <label id="http://www.some-fictitious-zoo.com/mammals/aardvark" value="aardvark"/> + <label id="http://www.some-fictitious-zoo.com/mammals/ninebandedarmadillo" value="Nine-banded Armadillo"/> + <label id="http://www.some-fictitious-zoo.com/mammals/gorilla" value="Gorilla"/> + </data> + +<script src="templates_shared.js"/> + +<script> +<![CDATA[ +SimpleTest.waitForExplicitFinish(); + +var testid ="where - equals negation ignore case"; +var queryType = "rdf"; +var isTreeBuilder = false; +var needsOpen = false; +var notWorkingYet = false; +var notWorkingYetDynamic = false; +var expectedOutput = document.getElementById("output"); + +var changes = []; +]]> +</script> + +<vbox xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul" id="root" datasources="rdf:null" ref="http://www.some-fictitious-zoo.com/mammals"> +<template id="template"> +<query id="query"> +<content uri="?uri"/> +<member container="?uri" child="?animal"/> +<triple subject="?animal" predicate="http://www.some-fictitious-zoo.com/rdf#name" object="?name"/> +</query> +<rule> +<conditions id="conditions"> +<where subject="?name" rel="equals" negate="true" ignorecase="true" value="AFRICAN Elephant"/> +</conditions> +<action id="action"> +<label uri="?animal" value="?name"/> +</action> +</rule> +</template> +</vbox> + +</window> diff --git a/dom/xul/templates/tests/chrome/test_tmpl_whereequalsnegationwrongcase.xul b/dom/xul/templates/tests/chrome/test_tmpl_whereequalsnegationwrongcase.xul new file mode 100644 index 000000000..16eca331e --- /dev/null +++ b/dom/xul/templates/tests/chrome/test_tmpl_whereequalsnegationwrongcase.xul @@ -0,0 +1,64 @@ +<?xml version="1.0"?> +<?xml-stylesheet href="chrome://global/skin" type="text/css"?> +<?xml-stylesheet href="chrome://mochikit/content/tests/SimpleTest/test.css" type="text/css"?> + +<!-- + where - equals negation wrong case +--> + +<window title="XUL Template Tests" width="500" height="600" + onload="test_template();" + xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"> + <script type="application/javascript" + src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script> + + <body xmlns="http://www.w3.org/1999/xhtml" style="height: 300px; overflow: auto;"/> + + <data id="output"> + <label id="http://www.some-fictitious-zoo.com/mammals/lion" value="Lion"/> + <label id="http://www.some-fictitious-zoo.com/mammals/hippopotamus" value="HIPPOPOTAMUS"/> + <label id="http://www.some-fictitious-zoo.com/mammals/africanelephant" value="African Elephant"/> + <label id="http://www.some-fictitious-zoo.com/mammals/llama" value="LLAMA"/> + <label id="http://www.some-fictitious-zoo.com/mammals/polarbear" value="Polar Bear"/> + <label id="http://www.some-fictitious-zoo.com/mammals/aardvark" value="aardvark"/> + <label id="http://www.some-fictitious-zoo.com/mammals/ninebandedarmadillo" value="Nine-banded Armadillo"/> + <label id="http://www.some-fictitious-zoo.com/mammals/gorilla" value="Gorilla"/> + </data> + +<script src="templates_shared.js"/> + +<script> +<![CDATA[ +SimpleTest.waitForExplicitFinish(); + +var testid ="where - equals negation wrong case"; +var queryType = "rdf"; +var isTreeBuilder = false; +var needsOpen = false; +var notWorkingYet = false; +var notWorkingYetDynamic = false; +var expectedOutput = document.getElementById("output"); + +var changes = []; +]]> +</script> + +<vbox xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul" id="root" datasources="rdf:null" ref="http://www.some-fictitious-zoo.com/mammals"> +<template id="template"> +<query id="query"> +<content uri="?uri"/> +<member container="?uri" child="?animal"/> +<triple subject="?animal" predicate="http://www.some-fictitious-zoo.com/rdf#name" object="?name"/> +</query> +<rule> +<conditions id="conditions"> +<where subject="?name" rel="equals" negate="true" value="Llama"/> +</conditions> +<action id="action"> +<label uri="?animal" value="?name"/> +</action> +</rule> +</template> +</vbox> + +</window> diff --git a/dom/xul/templates/tests/chrome/test_tmpl_whereequalsnumber.xul b/dom/xul/templates/tests/chrome/test_tmpl_whereequalsnumber.xul new file mode 100644 index 000000000..c036a3c6a --- /dev/null +++ b/dom/xul/templates/tests/chrome/test_tmpl_whereequalsnumber.xul @@ -0,0 +1,58 @@ +<?xml version="1.0"?> +<?xml-stylesheet href="chrome://global/skin" type="text/css"?> +<?xml-stylesheet href="chrome://mochikit/content/tests/SimpleTest/test.css" type="text/css"?> + +<!-- + where - equals number +--> + +<window title="XUL Template Tests" width="500" height="600" + onload="test_template();" + xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"> + <script type="application/javascript" + src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script> + + <body xmlns="http://www.w3.org/1999/xhtml" style="height: 300px; overflow: auto;"/> + + <data id="output"> + <label id="http://www.some-fictitious-zoo.com/mammals/hippopotamus" value="2"/> + <label id="http://www.some-fictitious-zoo.com/mammals/aardvark" value="2"/> + </data> + +<script src="templates_shared.js"/> + +<script> +<![CDATA[ +SimpleTest.waitForExplicitFinish(); + +var testid ="where - equals number"; +var queryType = "rdf"; +var isTreeBuilder = false; +var needsOpen = false; +var notWorkingYet = false; +var notWorkingYetDynamic = false; +var expectedOutput = document.getElementById("output"); + +var changes = []; +]]> +</script> + +<vbox xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul" id="root" datasources="rdf:null" ref="http://www.some-fictitious-zoo.com/mammals"> +<template id="template"> +<query id="query"> +<content uri="?uri"/> +<member container="?uri" child="?animal"/> +<triple subject="?animal" predicate="http://www.some-fictitious-zoo.com/rdf#specimens" object="?specimens"/> +</query> +<rule> +<conditions id="conditions"> +<where subject="?specimens" rel="equals" value="2"/> +</conditions> +<action id="action"> +<label uri="?animal" value="?specimens"/> +</action> +</rule> +</template> +</vbox> + +</window> diff --git a/dom/xul/templates/tests/chrome/test_tmpl_whereequalsothervariable.xul b/dom/xul/templates/tests/chrome/test_tmpl_whereequalsothervariable.xul new file mode 100644 index 000000000..a6ae12135 --- /dev/null +++ b/dom/xul/templates/tests/chrome/test_tmpl_whereequalsothervariable.xul @@ -0,0 +1,65 @@ +<?xml version="1.0"?> +<?xml-stylesheet href="chrome://global/skin" type="text/css"?> +<?xml-stylesheet href="chrome://mochikit/content/tests/SimpleTest/test.css" type="text/css"?> + +<!-- + where - equals other variable +--> + +<window title="XUL Template Tests" width="500" height="600" + onload="test_template();" + xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"> + <script type="application/javascript" + src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script> + + <body xmlns="http://www.w3.org/1999/xhtml" style="height: 300px; overflow: auto;"/> + + <data id="output"> + <label id="http://www.some-fictitious-zoo.com/mammals/lion" value="Lion"/> + <label id="http://www.some-fictitious-zoo.com/mammals/hippopotamus" value="HIPPOPOTAMUS"/> + <label id="http://www.some-fictitious-zoo.com/mammals/africanelephant" value="African Elephant"/> + <label id="http://www.some-fictitious-zoo.com/mammals/llama" value="LLAMA"/> + <label id="http://www.some-fictitious-zoo.com/mammals/polarbear" value="Polar Bear"/> + <label id="http://www.some-fictitious-zoo.com/mammals/aardvark" value="aardvark"/> + <label id="http://www.some-fictitious-zoo.com/mammals/ninebandedarmadillo" value="Nine-banded Armadillo"/> + <label id="http://www.some-fictitious-zoo.com/mammals/gorilla" value="Gorilla"/> + </data> + +<script src="templates_shared.js"/> + +<script> +<![CDATA[ +SimpleTest.waitForExplicitFinish(); + +var testid ="where - equals other variable"; +var queryType = "rdf"; +var isTreeBuilder = false; +var needsOpen = false; +var notWorkingYet = false; +var notWorkingYetDynamic = false; +var expectedOutput = document.getElementById("output"); + +var changes = []; +]]> +</script> + +<vbox xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul" id="root" datasources="rdf:null" ref="http://www.some-fictitious-zoo.com/mammals"> +<template id="template"> +<query id="query"> +<content uri="?uri"/> +<member container="?uri" child="?animal"/> +<triple subject="?animal" predicate="http://www.some-fictitious-zoo.com/rdf#name" object="?name"/> +<triple subject="?animal" predicate="http://www.some-fictitious-zoo.com/rdf#name" object="?othername"/> +</query> +<rule id="rule"> +<conditions id="conditions"> +<where subject="?name" rel="equals" value="?othername"/> +</conditions> +<action id="action"> +<label uri="?animal" value="?name"/> +</action> +</rule> +</template> +</vbox> + +</window> diff --git a/dom/xul/templates/tests/chrome/test_tmpl_whereequalsresource.xul b/dom/xul/templates/tests/chrome/test_tmpl_whereequalsresource.xul new file mode 100644 index 000000000..d2779a20f --- /dev/null +++ b/dom/xul/templates/tests/chrome/test_tmpl_whereequalsresource.xul @@ -0,0 +1,57 @@ +<?xml version="1.0"?> +<?xml-stylesheet href="chrome://global/skin" type="text/css"?> +<?xml-stylesheet href="chrome://mochikit/content/tests/SimpleTest/test.css" type="text/css"?> + +<!-- + where - equals resource +--> + +<window title="XUL Template Tests" width="500" height="600" + onload="test_template();" + xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"> + <script type="application/javascript" + src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script> + + <body xmlns="http://www.w3.org/1999/xhtml" style="height: 300px; overflow: auto;"/> + + <data id="output"> + <label id="http://www.some-fictitious-zoo.com/mammals/polarbear" value="Polar Bear"/> + </data> + +<script src="templates_shared.js"/> + +<script> +<![CDATA[ +SimpleTest.waitForExplicitFinish(); + +var testid ="where - equals resource"; +var queryType = "rdf"; +var isTreeBuilder = false; +var needsOpen = false; +var notWorkingYet = false; +var notWorkingYetDynamic = false; +var expectedOutput = document.getElementById("output"); + +var changes = []; +]]> +</script> + +<vbox xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul" id="root" datasources="rdf:null" ref="http://www.some-fictitious-zoo.com/mammals"> +<template id="template"> +<query id="query"> +<content uri="?uri"/> +<member container="?uri" child="?animal"/> +<triple subject="?animal" predicate="http://www.some-fictitious-zoo.com/rdf#name" object="?name"/> +</query> +<rule> +<conditions id="conditions"> +<where subject="?animal" rel="equals" value="http://www.some-fictitious-zoo.com/mammals/polarbear"/> +</conditions> +<action id="action"> +<label uri="?animal" value="?name"/> +</action> +</rule> +</template> +</vbox> + +</window> diff --git a/dom/xul/templates/tests/chrome/test_tmpl_whereequalssamevariable.xul b/dom/xul/templates/tests/chrome/test_tmpl_whereequalssamevariable.xul new file mode 100644 index 000000000..455fd147f --- /dev/null +++ b/dom/xul/templates/tests/chrome/test_tmpl_whereequalssamevariable.xul @@ -0,0 +1,64 @@ +<?xml version="1.0"?> +<?xml-stylesheet href="chrome://global/skin" type="text/css"?> +<?xml-stylesheet href="chrome://mochikit/content/tests/SimpleTest/test.css" type="text/css"?> + +<!-- + where - equals same variable +--> + +<window title="XUL Template Tests" width="500" height="600" + onload="test_template();" + xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"> + <script type="application/javascript" + src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script> + + <body xmlns="http://www.w3.org/1999/xhtml" style="height: 300px; overflow: auto;"/> + + <data id="output"> + <label id="http://www.some-fictitious-zoo.com/mammals/lion" value="Lion"/> + <label id="http://www.some-fictitious-zoo.com/mammals/hippopotamus" value="HIPPOPOTAMUS"/> + <label id="http://www.some-fictitious-zoo.com/mammals/africanelephant" value="African Elephant"/> + <label id="http://www.some-fictitious-zoo.com/mammals/llama" value="LLAMA"/> + <label id="http://www.some-fictitious-zoo.com/mammals/polarbear" value="Polar Bear"/> + <label id="http://www.some-fictitious-zoo.com/mammals/aardvark" value="aardvark"/> + <label id="http://www.some-fictitious-zoo.com/mammals/ninebandedarmadillo" value="Nine-banded Armadillo"/> + <label id="http://www.some-fictitious-zoo.com/mammals/gorilla" value="Gorilla"/> + </data> + +<script src="templates_shared.js"/> + +<script> +<![CDATA[ +SimpleTest.waitForExplicitFinish(); + +var testid ="where - equals same variable"; +var queryType = "rdf"; +var isTreeBuilder = false; +var needsOpen = false; +var notWorkingYet = false; +var notWorkingYetDynamic = false; +var expectedOutput = document.getElementById("output"); + +var changes = []; +]]> +</script> + +<vbox xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul" id="root" datasources="rdf:null" ref="http://www.some-fictitious-zoo.com/mammals"> +<template id="template"> +<query id="query"> +<content uri="?uri"/> +<member container="?uri" child="?animal"/> +<triple subject="?animal" predicate="http://www.some-fictitious-zoo.com/rdf#name" object="?name"/> +</query> +<rule> +<conditions id="conditions"> +<where subject="?name" rel="equals" value="?name"/> +</conditions> +<action id="action"> +<label uri="?animal" value="?name"/> +</action> +</rule> +</template> +</vbox> + +</window> diff --git a/dom/xul/templates/tests/chrome/test_tmpl_whereequalswrongcase.xul b/dom/xul/templates/tests/chrome/test_tmpl_whereequalswrongcase.xul new file mode 100644 index 000000000..b67200b57 --- /dev/null +++ b/dom/xul/templates/tests/chrome/test_tmpl_whereequalswrongcase.xul @@ -0,0 +1,55 @@ +<?xml version="1.0"?> +<?xml-stylesheet href="chrome://global/skin" type="text/css"?> +<?xml-stylesheet href="chrome://mochikit/content/tests/SimpleTest/test.css" type="text/css"?> + +<!-- + where - equals wrong case +--> + +<window title="XUL Template Tests" width="500" height="600" + onload="test_template();" + xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"> + <script type="application/javascript" + src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script> + + <body xmlns="http://www.w3.org/1999/xhtml" style="height: 300px; overflow: auto;"/> + + <data id="output"/> + +<script src="templates_shared.js"/> + +<script> +<![CDATA[ +SimpleTest.waitForExplicitFinish(); + +var testid ="where - equals wrong case"; +var queryType = "rdf"; +var isTreeBuilder = false; +var needsOpen = false; +var notWorkingYet = false; +var notWorkingYetDynamic = false; +var expectedOutput = document.getElementById("output"); + +var changes = []; +]]> +</script> + +<vbox xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul" id="root" datasources="rdf:null" ref="http://www.some-fictitious-zoo.com/mammals"> +<template id="template"> +<query id="query"> +<content uri="?uri"/> +<member container="?uri" child="?animal"/> +<triple subject="?animal" predicate="http://www.some-fictitious-zoo.com/rdf#name" object="?name"/> +</query> +<rule> +<conditions id="conditions"> +<where subject="?name" rel="equals" value="Llama"/> +</conditions> +<action id="action"> +<label uri="?animal" value="?name"/> +</action> +</rule> +</template> +</vbox> + +</window> diff --git a/dom/xul/templates/tests/chrome/test_tmpl_wheregreater.xul b/dom/xul/templates/tests/chrome/test_tmpl_wheregreater.xul new file mode 100644 index 000000000..5276fb598 --- /dev/null +++ b/dom/xul/templates/tests/chrome/test_tmpl_wheregreater.xul @@ -0,0 +1,60 @@ +<?xml version="1.0"?> +<?xml-stylesheet href="chrome://global/skin" type="text/css"?> +<?xml-stylesheet href="chrome://mochikit/content/tests/SimpleTest/test.css" type="text/css"?> + +<!-- + where - greater +--> + +<window title="XUL Template Tests" width="500" height="600" + onload="test_template();" + xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"> + <script type="application/javascript" + src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script> + + <body xmlns="http://www.w3.org/1999/xhtml" style="height: 300px; overflow: auto;"/> + + <data id="output"> + <label id="http://www.some-fictitious-zoo.com/mammals/africanelephant" value="14"/> + <label id="http://www.some-fictitious-zoo.com/mammals/llama" value="5"/> + <label id="http://www.some-fictitious-zoo.com/mammals/polarbear" value="20"/> + <label id="http://www.some-fictitious-zoo.com/mammals/gorilla" value="7"/> + </data> + +<script src="templates_shared.js"/> + +<script> +<![CDATA[ +SimpleTest.waitForExplicitFinish(); + +var testid ="where - greater"; +var queryType = "rdf"; +var isTreeBuilder = false; +var needsOpen = false; +var notWorkingYet = false; +var notWorkingYetDynamic = false; +var expectedOutput = document.getElementById("output"); + +var changes = []; +]]> +</script> + +<vbox xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul" id="root" datasources="rdf:null" ref="http://www.some-fictitious-zoo.com/mammals"> +<template id="template"> +<query id="query"> +<content uri="?uri"/> +<member container="?uri" child="?animal"/> +<triple subject="?animal" predicate="http://www.some-fictitious-zoo.com/rdf#specimens" object="?specimens"/> +</query> +<rule> +<conditions id="conditions"> +<where subject="?specimens" rel="greater" value="4"/> +</conditions> +<action id="action"> +<label uri="?animal" value="?specimens"/> +</action> +</rule> +</template> +</vbox> + +</window> diff --git a/dom/xul/templates/tests/chrome/test_tmpl_wheregreaternegation.xul b/dom/xul/templates/tests/chrome/test_tmpl_wheregreaternegation.xul new file mode 100644 index 000000000..7daa0a7cc --- /dev/null +++ b/dom/xul/templates/tests/chrome/test_tmpl_wheregreaternegation.xul @@ -0,0 +1,60 @@ +<?xml version="1.0"?> +<?xml-stylesheet href="chrome://global/skin" type="text/css"?> +<?xml-stylesheet href="chrome://mochikit/content/tests/SimpleTest/test.css" type="text/css"?> + +<!-- + where - greater negation +--> + +<window title="XUL Template Tests" width="500" height="600" + onload="test_template();" + xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"> + <script type="application/javascript" + src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script> + + <body xmlns="http://www.w3.org/1999/xhtml" style="height: 300px; overflow: auto;"/> + + <data id="output"> + <label id="http://www.some-fictitious-zoo.com/mammals/lion" value="4"/> + <label id="http://www.some-fictitious-zoo.com/mammals/hippopotamus" value="2"/> + <label id="http://www.some-fictitious-zoo.com/mammals/aardvark" value="2"/> + <label id="http://www.some-fictitious-zoo.com/mammals/ninebandedarmadillo" value="1"/> + </data> + +<script src="templates_shared.js"/> + +<script> +<![CDATA[ +SimpleTest.waitForExplicitFinish(); + +var testid ="where - greater negation"; +var queryType = "rdf"; +var isTreeBuilder = false; +var needsOpen = false; +var notWorkingYet = false; +var notWorkingYetDynamic = false; +var expectedOutput = document.getElementById("output"); + +var changes = []; +]]> +</script> + +<vbox xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul" id="root" datasources="rdf:null" ref="http://www.some-fictitious-zoo.com/mammals"> +<template id="template"> +<query id="query"> +<content uri="?uri"/> +<member container="?uri" child="?animal"/> +<triple subject="?animal" predicate="http://www.some-fictitious-zoo.com/rdf#specimens" object="?specimens"/> +</query> +<rule> +<conditions id="conditions"> +<where subject="?specimens" rel="greater" negate="true" value="4"/> +</conditions> +<action id="action"> +<label uri="?animal" value="?specimens"/> +</action> +</rule> +</template> +</vbox> + +</window> diff --git a/dom/xul/templates/tests/chrome/test_tmpl_wheregreaternegationstring.xul b/dom/xul/templates/tests/chrome/test_tmpl_wheregreaternegationstring.xul new file mode 100644 index 000000000..22f351547 --- /dev/null +++ b/dom/xul/templates/tests/chrome/test_tmpl_wheregreaternegationstring.xul @@ -0,0 +1,60 @@ +<?xml version="1.0"?> +<?xml-stylesheet href="chrome://global/skin" type="text/css"?> +<?xml-stylesheet href="chrome://mochikit/content/tests/SimpleTest/test.css" type="text/css"?> + +<!-- + where - greater negation string +--> + +<window title="XUL Template Tests" width="500" height="600" + onload="test_template();" + xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"> + <script type="application/javascript" + src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script> + + <body xmlns="http://www.w3.org/1999/xhtml" style="height: 300px; overflow: auto;"/> + + <data id="output"> + <label id="http://www.some-fictitious-zoo.com/mammals/lion" value="4"/> + <label id="http://www.some-fictitious-zoo.com/mammals/hippopotamus" value="2"/> + <label id="http://www.some-fictitious-zoo.com/mammals/aardvark" value="2"/> + <label id="http://www.some-fictitious-zoo.com/mammals/ninebandedarmadillo" value="1"/> + </data> + +<script src="templates_shared.js"/> + +<script> +<![CDATA[ +SimpleTest.waitForExplicitFinish(); + +var testid ="where - greater negation string"; +var queryType = "rdf"; +var isTreeBuilder = false; +var needsOpen = false; +var notWorkingYet = false; +var notWorkingYetDynamic = false; +var expectedOutput = document.getElementById("output"); + +var changes = []; +]]> +</script> + +<vbox xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul" id="root" datasources="rdf:null" ref="http://www.some-fictitious-zoo.com/mammals"> +<template id="template"> +<query id="query"> +<content uri="?uri"/> +<member container="?uri" child="?animal"/> +<triple subject="?animal" predicate="http://www.some-fictitious-zoo.com/rdf#specimensAsString" object="?specimens"/> +</query> +<rule> +<conditions id="conditions"> +<where subject="?specimens" rel="greater" negate="true" value="4"/> +</conditions> +<action id="action"> +<label uri="?animal" value="?specimens"/> +</action> +</rule> +</template> +</vbox> + +</window> diff --git a/dom/xul/templates/tests/chrome/test_tmpl_wheregreaterstring.xul b/dom/xul/templates/tests/chrome/test_tmpl_wheregreaterstring.xul new file mode 100644 index 000000000..f7c1e4b11 --- /dev/null +++ b/dom/xul/templates/tests/chrome/test_tmpl_wheregreaterstring.xul @@ -0,0 +1,113 @@ +<?xml version="1.0"?> +<?xml-stylesheet href="chrome://global/skin" type="text/css"?> +<?xml-stylesheet href="chrome://mochikit/content/tests/SimpleTest/test.css" type="text/css"?> + +<!-- + where - greater string +--> + +<window title="XUL Template Tests" width="500" height="600" + onload="test_template();" + xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"> + <script type="application/javascript" + src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script> + + <body xmlns="http://www.w3.org/1999/xhtml" style="height: 300px; overflow: auto;"/> + + <data id="output"> + <label step="-4" id="http://www.some-fictitious-zoo.com/mammals/africanelephant" value="14"/> + <label step="6" id="http://www.some-fictitious-zoo.com/mammals/koala" value="8"/> + <label id="http://www.some-fictitious-zoo.com/mammals/llama" value="5"/> + <label id="http://www.some-fictitious-zoo.com/mammals/polarbear" value="20"/> + <label id="http://www.some-fictitious-zoo.com/mammals/gorilla" value="7"/> + <label step="5" id="http://www.some-fictitious-zoo.com/mammals/africanelephant" value="14"/> + </data> + +<script src="templates_shared.js"/> + +<script> +<![CDATA[ +SimpleTest.waitForExplicitFinish(); + +var testid ="where - greater string"; +var queryType = "rdf"; +var isTreeBuilder = false; +var needsOpen = false; +var notWorkingYet = false; +var notWorkingYetDynamic = false; +var expectedOutput = document.getElementById("output"); + +var changes = [ + // step 1 + function(targetds, root) { + var newnode = RDF.GetResource(ZOO_NS + 'mammals/arctichare'); + targetds.Assert(newnode, RDF.GetResource(ZOO_NS + 'rdf#name'), + RDF.GetLiteral('Arctic Hare'), true); + var container = ContainerUtils.MakeSeq(targetds, + RDF.GetResource(ZOO_NS + 'mammals')); + container.AppendElement(newnode); + }, + // step 2 + function(targetds, root) { + var newnode = RDF.GetResource(ZOO_NS + 'mammals/koala'); + targetds.Assert(newnode, RDF.GetResource(ZOO_NS + 'rdf#name'), + RDF.GetLiteral('Koala'), true); + var container = ContainerUtils.MakeSeq(targetds, + RDF.GetResource(ZOO_NS + 'mammals')); + container.InsertElementAt(newnode, '4', true); + }, + // step 3 + function(targetds, root) { + var newnode = RDF.GetResource(ZOO_NS + 'mammals/zebra'); + targetds.Assert(newnode, RDF.GetResource(ZOO_NS + 'rdf#name'), + RDF.GetLiteral('Zebra'), true); + var container = ContainerUtils.MakeSeq(targetds, + RDF.GetResource(ZOO_NS + 'mammals')); + container.InsertElementAt(newnode, '1', true); + }, + // step 4 + function(targetds, root) { + var container = ContainerUtils.MakeSeq(targetds, + RDF.GetResource(ZOO_NS + 'mammals')); + var removednode = container.RemoveElementAt('4', true); + targetds.Unassert(removednode, RDF.GetResource(ZOO_NS + 'rdf#name'), + RDF.GetLiteral('African Elephant'), true); + }, + // step 5 + function(targetds, root) { + var newnode = RDF.GetResource(ZOO_NS + 'mammals/africanelephant'); + targetds.Assert(newnode, RDF.GetResource(ZOO_NS + 'rdf#name'), + RDF.GetLiteral('African Elephant'), true); + var container = ContainerUtils.MakeSeq(targetds, + RDF.GetResource(ZOO_NS + 'mammals')); + container.AppendElement(newnode); + }, + // step 6 + function(targetds, root) { + targetds.Assert(RDF.GetResource(ZOO_NS + 'mammals/koala'), + RDF.GetResource(ZOO_NS + 'rdf#specimensAsString'), + RDF.GetLiteral('8'), true); + } +]; +]]> +</script> + +<vbox xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul" id="root" datasources="rdf:null" ref="http://www.some-fictitious-zoo.com/mammals"> +<template id="template"> +<query id="query"> +<content uri="?uri"/> +<member container="?uri" child="?animal"/> +<triple subject="?animal" predicate="http://www.some-fictitious-zoo.com/rdf#specimensAsString" object="?specimens"/> +</query> +<rule> +<conditions id="conditions"> +<where subject="?specimens" rel="greater" value="4"/> +</conditions> +<action id="action"> +<label uri="?animal" value="?specimens"/> +</action> +</rule> +</template> +</vbox> + +</window> diff --git a/dom/xul/templates/tests/chrome/test_tmpl_whereless.xul b/dom/xul/templates/tests/chrome/test_tmpl_whereless.xul new file mode 100644 index 000000000..4c42f54e2 --- /dev/null +++ b/dom/xul/templates/tests/chrome/test_tmpl_whereless.xul @@ -0,0 +1,62 @@ +<?xml version="1.0"?> +<?xml-stylesheet href="chrome://global/skin" type="text/css"?> +<?xml-stylesheet href="chrome://mochikit/content/tests/SimpleTest/test.css" type="text/css"?> + +<!-- + where - less +--> + +<window title="XUL Template Tests" width="500" height="600" + onload="test_template();" + xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"> + <script type="application/javascript" + src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script> + + <body xmlns="http://www.w3.org/1999/xhtml" style="height: 300px; overflow: auto;"/> + + <data id="output"> + <label id="http://www.some-fictitious-zoo.com/mammals/lion" value="4"/> + <label id="http://www.some-fictitious-zoo.com/mammals/hippopotamus" value="2"/> + <label id="http://www.some-fictitious-zoo.com/mammals/llama" value="5"/> + <label id="http://www.some-fictitious-zoo.com/mammals/aardvark" value="2"/> + <label id="http://www.some-fictitious-zoo.com/mammals/ninebandedarmadillo" value="1"/> + <label id="http://www.some-fictitious-zoo.com/mammals/gorilla" value="7"/> + </data> + +<script src="templates_shared.js"/> + +<script> +<![CDATA[ +SimpleTest.waitForExplicitFinish(); + +var testid ="where - less"; +var queryType = "rdf"; +var isTreeBuilder = false; +var needsOpen = false; +var notWorkingYet = false; +var notWorkingYetDynamic = false; +var expectedOutput = document.getElementById("output"); + +var changes = []; +]]> +</script> + +<vbox xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul" id="root" datasources="rdf:null" ref="http://www.some-fictitious-zoo.com/mammals"> +<template id="template"> +<query id="query"> +<content uri="?uri"/> +<member container="?uri" child="?animal"/> +<triple subject="?animal" predicate="http://www.some-fictitious-zoo.com/rdf#specimens" object="?specimens"/> +</query> +<rule> +<conditions id="conditions"> +<where subject="?specimens" rel="less" value="14"/> +</conditions> +<action id="action"> +<label uri="?animal" value="?specimens"/> +</action> +</rule> +</template> +</vbox> + +</window> diff --git a/dom/xul/templates/tests/chrome/test_tmpl_wherelessnegation.xul b/dom/xul/templates/tests/chrome/test_tmpl_wherelessnegation.xul new file mode 100644 index 000000000..46e9d7819 --- /dev/null +++ b/dom/xul/templates/tests/chrome/test_tmpl_wherelessnegation.xul @@ -0,0 +1,61 @@ +<?xml version="1.0"?> +<?xml-stylesheet href="chrome://global/skin" type="text/css"?> +<?xml-stylesheet href="chrome://mochikit/content/tests/SimpleTest/test.css" type="text/css"?> + +<!-- + where - less negation +--> + +<window title="XUL Template Tests" width="500" height="600" + onload="test_template();" + xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"> + <script type="application/javascript" + src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script> + + <body xmlns="http://www.w3.org/1999/xhtml" style="height: 300px; overflow: auto;"/> + + <data id="output"> + <label id="http://www.some-fictitious-zoo.com/mammals/lion" value="4"/> + <label id="http://www.some-fictitious-zoo.com/mammals/africanelephant" value="14"/> + <label id="http://www.some-fictitious-zoo.com/mammals/llama" value="5"/> + <label id="http://www.some-fictitious-zoo.com/mammals/polarbear" value="20"/> + <label id="http://www.some-fictitious-zoo.com/mammals/gorilla" value="7"/> + </data> + +<script src="templates_shared.js"/> + +<script> +<![CDATA[ +SimpleTest.waitForExplicitFinish(); + +var testid ="where - less negation"; +var queryType = "rdf"; +var isTreeBuilder = false; +var needsOpen = false; +var notWorkingYet = false; +var notWorkingYetDynamic = false; +var expectedOutput = document.getElementById("output"); + +var changes = []; +]]> +</script> + +<vbox xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul" id="root" datasources="rdf:null" ref="http://www.some-fictitious-zoo.com/mammals"> +<template id="template"> +<query id="query"> +<content uri="?uri"/> +<member container="?uri" child="?animal"/> +<triple subject="?animal" predicate="http://www.some-fictitious-zoo.com/rdf#specimens" object="?specimens"/> +</query> +<rule> +<conditions id="conditions"> +<where subject="?specimens" rel="less" negate="true" value="4"/> +</conditions> +<action id="action"> +<label uri="?animal" value="?specimens"/> +</action> +</rule> +</template> +</vbox> + +</window> diff --git a/dom/xul/templates/tests/chrome/test_tmpl_wherelessnegationstring.xul b/dom/xul/templates/tests/chrome/test_tmpl_wherelessnegationstring.xul new file mode 100644 index 000000000..728e7ae3d --- /dev/null +++ b/dom/xul/templates/tests/chrome/test_tmpl_wherelessnegationstring.xul @@ -0,0 +1,61 @@ +<?xml version="1.0"?> +<?xml-stylesheet href="chrome://global/skin" type="text/css"?> +<?xml-stylesheet href="chrome://mochikit/content/tests/SimpleTest/test.css" type="text/css"?> + +<!-- + where - less negation string +--> + +<window title="XUL Template Tests" width="500" height="600" + onload="test_template();" + xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"> + <script type="application/javascript" + src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script> + + <body xmlns="http://www.w3.org/1999/xhtml" style="height: 300px; overflow: auto;"/> + + <data id="output"> + <label id="http://www.some-fictitious-zoo.com/mammals/lion" value="4"/> + <label id="http://www.some-fictitious-zoo.com/mammals/africanelephant" value="14"/> + <label id="http://www.some-fictitious-zoo.com/mammals/llama" value="5"/> + <label id="http://www.some-fictitious-zoo.com/mammals/polarbear" value="20"/> + <label id="http://www.some-fictitious-zoo.com/mammals/gorilla" value="7"/> + </data> + +<script src="templates_shared.js"/> + +<script> +<![CDATA[ +SimpleTest.waitForExplicitFinish(); + +var testid ="where - less negation string"; +var queryType = "rdf"; +var isTreeBuilder = false; +var needsOpen = false; +var notWorkingYet = false; +var notWorkingYetDynamic = false; +var expectedOutput = document.getElementById("output"); + +var changes = []; +]]> +</script> + +<vbox xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul" id="root" datasources="rdf:null" ref="http://www.some-fictitious-zoo.com/mammals"> +<template id="template"> +<query id="query"> +<content uri="?uri"/> +<member container="?uri" child="?animal"/> +<triple subject="?animal" predicate="http://www.some-fictitious-zoo.com/rdf#specimensAsString" object="?specimens"/> +</query> +<rule> +<conditions id="conditions"> +<where subject="?specimens" rel="less" negate="true" value="4"/> +</conditions> +<action id="action"> +<label uri="?animal" value="?specimens"/> +</action> +</rule> +</template> +</vbox> + +</window> diff --git a/dom/xul/templates/tests/chrome/test_tmpl_wherelessstring.xul b/dom/xul/templates/tests/chrome/test_tmpl_wherelessstring.xul new file mode 100644 index 000000000..445f5efa1 --- /dev/null +++ b/dom/xul/templates/tests/chrome/test_tmpl_wherelessstring.xul @@ -0,0 +1,62 @@ +<?xml version="1.0"?> +<?xml-stylesheet href="chrome://global/skin" type="text/css"?> +<?xml-stylesheet href="chrome://mochikit/content/tests/SimpleTest/test.css" type="text/css"?> + +<!-- + where - less string +--> + +<window title="XUL Template Tests" width="500" height="600" + onload="test_template();" + xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"> + <script type="application/javascript" + src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script> + + <body xmlns="http://www.w3.org/1999/xhtml" style="height: 300px; overflow: auto;"/> + + <data id="output"> + <label id="http://www.some-fictitious-zoo.com/mammals/lion" value="4"/> + <label id="http://www.some-fictitious-zoo.com/mammals/hippopotamus" value="2"/> + <label id="http://www.some-fictitious-zoo.com/mammals/llama" value="5"/> + <label id="http://www.some-fictitious-zoo.com/mammals/aardvark" value="2"/> + <label id="http://www.some-fictitious-zoo.com/mammals/ninebandedarmadillo" value="1"/> + <label id="http://www.some-fictitious-zoo.com/mammals/gorilla" value="7"/> + </data> + +<script src="templates_shared.js"/> + +<script> +<![CDATA[ +SimpleTest.waitForExplicitFinish(); + +var testid ="where - less string"; +var queryType = "rdf"; +var isTreeBuilder = false; +var needsOpen = false; +var notWorkingYet = false; +var notWorkingYetDynamic = false; +var expectedOutput = document.getElementById("output"); + +var changes = []; +]]> +</script> + +<vbox xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul" id="root" datasources="rdf:null" ref="http://www.some-fictitious-zoo.com/mammals"> +<template id="template"> +<query id="query"> +<content uri="?uri"/> +<member container="?uri" child="?animal"/> +<triple subject="?animal" predicate="http://www.some-fictitious-zoo.com/rdf#specimensAsString" object="?specimens"/> +</query> +<rule> +<conditions id="conditions"> +<where subject="?specimens" rel="less" value="14"/> +</conditions> +<action id="action"> +<label uri="?animal" value="?specimens"/> +</action> +</rule> +</template> +</vbox> + +</window> diff --git a/dom/xul/templates/tests/chrome/test_tmpl_wherenorel.xul b/dom/xul/templates/tests/chrome/test_tmpl_wherenorel.xul new file mode 100644 index 000000000..b7e79ba18 --- /dev/null +++ b/dom/xul/templates/tests/chrome/test_tmpl_wherenorel.xul @@ -0,0 +1,69 @@ +<?xml version="1.0"?> +<?xml-stylesheet href="chrome://global/skin" type="text/css"?> +<?xml-stylesheet href="chrome://mochikit/content/tests/SimpleTest/test.css" type="text/css"?> + +<!-- + where - no rel +--> + +<window title="XUL Template Tests" width="500" height="600" + onload="test_template();" + xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"> + <script type="application/javascript" + src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script> + + <body xmlns="http://www.w3.org/1999/xhtml" style="height: 300px; overflow: auto;"/> + + <data id="output"> + <label id="http://www.some-fictitious-zoo.com/mammals/lion" value="Lion"/> + <label id="http://www.some-fictitious-zoo.com/mammals/hippopotamus" value="HIPPOPOTAMUS"/> + <label id="http://www.some-fictitious-zoo.com/mammals/africanelephant" value="African Elephant"/> + <label id="http://www.some-fictitious-zoo.com/mammals/llama" value="LLAMA"/> + <label id="http://www.some-fictitious-zoo.com/mammals/polarbear" value="Polar Bear"/> + <label id="http://www.some-fictitious-zoo.com/mammals/aardvark" value="aardvark"/> + <label id="http://www.some-fictitious-zoo.com/mammals/ninebandedarmadillo" value="Nine-banded Armadillo"/> + <label id="http://www.some-fictitious-zoo.com/mammals/gorilla" value="Gorilla"/> + </data> + +<script src="templates_shared.js"/> + +<script> +<![CDATA[ +SimpleTest.waitForExplicitFinish(); + +expectLoggedMessages = function() +{ + expectedConsoleMessages.push("Error parsing template: <where> element is missing a rel attribute"); +} + +var testid ="where - no rel"; +var queryType = "rdf"; +var isTreeBuilder = false; +var needsOpen = false; +var notWorkingYet = false; +var notWorkingYetDynamic = false; +var expectedOutput = document.getElementById("output"); + +var changes = []; +]]> +</script> + +<vbox xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul" id="root" datasources="rdf:null" ref="http://www.some-fictitious-zoo.com/mammals"> +<template id="template"> +<query id="query"> +<content uri="?uri"/> +<member container="?uri" child="?animal"/> +<triple subject="?animal" predicate="http://www.some-fictitious-zoo.com/rdf#name" object="?name"/> +</query> +<rule> +<conditions id="conditions"> +<where subject="?name" value="Lion"/> +</conditions> +<action id="action"> +<label uri="?animal" value="?name"/> +</action> +</rule> +</template> +</vbox> + +</window> diff --git a/dom/xul/templates/tests/chrome/test_tmpl_wherenosubject.xul b/dom/xul/templates/tests/chrome/test_tmpl_wherenosubject.xul new file mode 100644 index 000000000..c6b566fbe --- /dev/null +++ b/dom/xul/templates/tests/chrome/test_tmpl_wherenosubject.xul @@ -0,0 +1,69 @@ +<?xml version="1.0"?> +<?xml-stylesheet href="chrome://global/skin" type="text/css"?> +<?xml-stylesheet href="chrome://mochikit/content/tests/SimpleTest/test.css" type="text/css"?> + +<!-- + where - no subject +--> + +<window title="XUL Template Tests" width="500" height="600" + onload="test_template();" + xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"> + <script type="application/javascript" + src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script> + + <body xmlns="http://www.w3.org/1999/xhtml" style="height: 300px; overflow: auto;"/> + + <data id="output"> + <label id="http://www.some-fictitious-zoo.com/mammals/lion" value="Lion"/> + <label id="http://www.some-fictitious-zoo.com/mammals/hippopotamus" value="HIPPOPOTAMUS"/> + <label id="http://www.some-fictitious-zoo.com/mammals/africanelephant" value="African Elephant"/> + <label id="http://www.some-fictitious-zoo.com/mammals/llama" value="LLAMA"/> + <label id="http://www.some-fictitious-zoo.com/mammals/polarbear" value="Polar Bear"/> + <label id="http://www.some-fictitious-zoo.com/mammals/aardvark" value="aardvark"/> + <label id="http://www.some-fictitious-zoo.com/mammals/ninebandedarmadillo" value="Nine-banded Armadillo"/> + <label id="http://www.some-fictitious-zoo.com/mammals/gorilla" value="Gorilla"/> + </data> + +<script src="templates_shared.js"/> + +<script> +<![CDATA[ +SimpleTest.waitForExplicitFinish(); + +expectLoggedMessages = function() +{ + expectedConsoleMessages.push("Error parsing template: <where> element is missing a subject attribute"); +} + +var testid ="where - no subject"; +var queryType = "rdf"; +var isTreeBuilder = false; +var needsOpen = false; +var notWorkingYet = false; +var notWorkingYetDynamic = false; +var expectedOutput = document.getElementById("output"); + +var changes = []; +]]> +</script> + +<vbox xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul" id="root" datasources="rdf:null" ref="http://www.some-fictitious-zoo.com/mammals"> +<template id="template"> +<query id="query"> +<content uri="?uri"/> +<member container="?uri" child="?animal"/> +<triple subject="?animal" predicate="http://www.some-fictitious-zoo.com/rdf#name" object="?name"/> +</query> +<rule> +<conditions id="conditions"> +<where rel="startswith" value="d"/> +</conditions> +<action id="action"> +<label uri="?animal" value="?name"/> +</action> +</rule> +</template> +</vbox> + +</window> diff --git a/dom/xul/templates/tests/chrome/test_tmpl_wherenovalue.xul b/dom/xul/templates/tests/chrome/test_tmpl_wherenovalue.xul new file mode 100644 index 000000000..53507b0a3 --- /dev/null +++ b/dom/xul/templates/tests/chrome/test_tmpl_wherenovalue.xul @@ -0,0 +1,69 @@ +<?xml version="1.0"?> +<?xml-stylesheet href="chrome://global/skin" type="text/css"?> +<?xml-stylesheet href="chrome://mochikit/content/tests/SimpleTest/test.css" type="text/css"?> + +<!-- + where - no value +--> + +<window title="XUL Template Tests" width="500" height="600" + onload="test_template();" + xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"> + <script type="application/javascript" + src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script> + + <body xmlns="http://www.w3.org/1999/xhtml" style="height: 300px; overflow: auto;"/> + + <data id="output"> + <label id="http://www.some-fictitious-zoo.com/mammals/lion" value="Lion"/> + <label id="http://www.some-fictitious-zoo.com/mammals/hippopotamus" value="HIPPOPOTAMUS"/> + <label id="http://www.some-fictitious-zoo.com/mammals/africanelephant" value="African Elephant"/> + <label id="http://www.some-fictitious-zoo.com/mammals/llama" value="LLAMA"/> + <label id="http://www.some-fictitious-zoo.com/mammals/polarbear" value="Polar Bear"/> + <label id="http://www.some-fictitious-zoo.com/mammals/aardvark" value="aardvark"/> + <label id="http://www.some-fictitious-zoo.com/mammals/ninebandedarmadillo" value="Nine-banded Armadillo"/> + <label id="http://www.some-fictitious-zoo.com/mammals/gorilla" value="Gorilla"/> + </data> + +<script src="templates_shared.js"/> + +<script> +<![CDATA[ +SimpleTest.waitForExplicitFinish(); + +expectLoggedMessages = function() +{ + expectedConsoleMessages.push("Error parsing template: <where> element is missing a value attribute"); +} + +var testid ="where - no value"; +var queryType = "rdf"; +var isTreeBuilder = false; +var needsOpen = false; +var notWorkingYet = false; +var notWorkingYetDynamic = false; +var expectedOutput = document.getElementById("output"); + +var changes = []; +]]> +</script> + +<vbox xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul" id="root" datasources="rdf:null" ref="http://www.some-fictitious-zoo.com/mammals"> +<template id="template"> +<query id="query"> +<content uri="?uri"/> +<member container="?uri" child="?animal"/> +<triple subject="?animal" predicate="http://www.some-fictitious-zoo.com/rdf#name" object="?name"/> +</query> +<rule> +<conditions id="conditions"> +<where subject="?name" rel="startswith"/> +</conditions> +<action id="action"> +<label uri="?animal" value="?name"/> +</action> +</rule> +</template> +</vbox> + +</window> diff --git a/dom/xul/templates/tests/chrome/test_tmpl_wherestartswith.xul b/dom/xul/templates/tests/chrome/test_tmpl_wherestartswith.xul new file mode 100644 index 000000000..6e86c981d --- /dev/null +++ b/dom/xul/templates/tests/chrome/test_tmpl_wherestartswith.xul @@ -0,0 +1,108 @@ +<?xml version="1.0"?> +<?xml-stylesheet href="chrome://global/skin" type="text/css"?> +<?xml-stylesheet href="chrome://mochikit/content/tests/SimpleTest/test.css" type="text/css"?> + +<!-- + where - startswith +--> + +<window title="XUL Template Tests" width="500" height="600" + onload="test_template();" + xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"> + <script type="application/javascript" + src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script> + + <body xmlns="http://www.w3.org/1999/xhtml" style="height: 300px; overflow: auto;"/> + + <data id="output"> + <label id="http://www.some-fictitious-zoo.com/mammals/aardvark" value="aardvark"/> + </data> + +<script src="templates_shared.js"/> + +<script> +<![CDATA[ +SimpleTest.waitForExplicitFinish(); + +var testid ="where - startswith"; +var queryType = "rdf"; +var isTreeBuilder = false; +var needsOpen = false; +var notWorkingYet = false; +var notWorkingYetDynamic = false; +var expectedOutput = document.getElementById("output"); + +var changes = [ + // step 1 + function(targetds, root) { + var newnode = RDF.GetResource(ZOO_NS + 'mammals/arctichare'); + targetds.Assert(newnode, RDF.GetResource(ZOO_NS + 'rdf#name'), + RDF.GetLiteral('Arctic Hare'), true); + var container = ContainerUtils.MakeSeq(targetds, + RDF.GetResource(ZOO_NS + 'mammals')); + container.AppendElement(newnode); + }, + // step 2 + function(targetds, root) { + var newnode = RDF.GetResource(ZOO_NS + 'mammals/koala'); + targetds.Assert(newnode, RDF.GetResource(ZOO_NS + 'rdf#name'), + RDF.GetLiteral('Koala'), true); + var container = ContainerUtils.MakeSeq(targetds, + RDF.GetResource(ZOO_NS + 'mammals')); + container.InsertElementAt(newnode, '4', true); + }, + // step 3 + function(targetds, root) { + var newnode = RDF.GetResource(ZOO_NS + 'mammals/zebra'); + targetds.Assert(newnode, RDF.GetResource(ZOO_NS + 'rdf#name'), + RDF.GetLiteral('Zebra'), true); + var container = ContainerUtils.MakeSeq(targetds, + RDF.GetResource(ZOO_NS + 'mammals')); + container.InsertElementAt(newnode, '1', true); + }, + // step 4 + function(targetds, root) { + var container = ContainerUtils.MakeSeq(targetds, + RDF.GetResource(ZOO_NS + 'mammals')); + var removednode = container.RemoveElementAt('4', true); + targetds.Unassert(removednode, RDF.GetResource(ZOO_NS + 'rdf#name'), + RDF.GetLiteral('African Elephant'), true); + }, + // step 5 + function(targetds, root) { + var newnode = RDF.GetResource(ZOO_NS + 'mammals/africanelephant'); + targetds.Assert(newnode, RDF.GetResource(ZOO_NS + 'rdf#name'), + RDF.GetLiteral('African Elephant'), true); + var container = ContainerUtils.MakeSeq(targetds, + RDF.GetResource(ZOO_NS + 'mammals')); + container.AppendElement(newnode); + }, + // step 6 + function(targetds, root) { + targetds.Assert(RDF.GetResource(ZOO_NS + 'mammals/koala'), + RDF.GetResource(ZOO_NS + 'rdf#specimensAsString'), + RDF.GetLiteral('8'), true); + } +]; +]]> +</script> + +<vbox xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul" id="root" datasources="rdf:null" ref="http://www.some-fictitious-zoo.com/mammals"> +<template id="template"> +<query id="query"> +<content uri="?uri"/> +<member container="?uri" child="?animal"/> +<triple subject="?animal" predicate="http://www.some-fictitious-zoo.com/rdf#name" object="?name"/> +</query> +<rule> +<conditions id="conditions"> +<where subject="?name" rel="startswith" value="a"/> +</conditions> +<action id="action"> +<label uri="?animal" value="?name"/> +</action> +</rule> +</template> +</vbox> + +</window> diff --git a/dom/xul/templates/tests/chrome/test_tmpl_wherestartswithignorecase.xul b/dom/xul/templates/tests/chrome/test_tmpl_wherestartswithignorecase.xul new file mode 100644 index 000000000..434ba40c4 --- /dev/null +++ b/dom/xul/templates/tests/chrome/test_tmpl_wherestartswithignorecase.xul @@ -0,0 +1,58 @@ +<?xml version="1.0"?> +<?xml-stylesheet href="chrome://global/skin" type="text/css"?> +<?xml-stylesheet href="chrome://mochikit/content/tests/SimpleTest/test.css" type="text/css"?> + +<!-- + where - startswith ignore case +--> + +<window title="XUL Template Tests" width="500" height="600" + onload="test_template();" + xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"> + <script type="application/javascript" + src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script> + + <body xmlns="http://www.w3.org/1999/xhtml" style="height: 300px; overflow: auto;"/> + + <data id="output"> + <label id="http://www.some-fictitious-zoo.com/mammals/africanelephant" value="African Elephant"/> + <label id="http://www.some-fictitious-zoo.com/mammals/aardvark" value="aardvark"/> + </data> + +<script src="templates_shared.js"/> + +<script> +<![CDATA[ +SimpleTest.waitForExplicitFinish(); + +var testid ="where - startswith ignore case"; +var queryType = "rdf"; +var isTreeBuilder = false; +var needsOpen = false; +var notWorkingYet = false; +var notWorkingYetDynamic = false; +var expectedOutput = document.getElementById("output"); + +var changes = []; +]]> +</script> + +<vbox xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul" id="root" datasources="rdf:null" ref="http://www.some-fictitious-zoo.com/mammals"> +<template id="template"> +<query id="query"> +<content uri="?uri"/> +<member container="?uri" child="?animal"/> +<triple subject="?animal" predicate="http://www.some-fictitious-zoo.com/rdf#name" object="?name"/> +</query> +<rule> +<conditions id="conditions"> +<where subject="?name" rel="startswith" ignorecase="true" value="a"/> +</conditions> +<action id="action"> +<label uri="?animal" value="?name"/> +</action> +</rule> +</template> +</vbox> + +</window> diff --git a/dom/xul/templates/tests/chrome/test_tmpl_wherestartswithmultiple.xul b/dom/xul/templates/tests/chrome/test_tmpl_wherestartswithmultiple.xul new file mode 100644 index 000000000..4876ed383 --- /dev/null +++ b/dom/xul/templates/tests/chrome/test_tmpl_wherestartswithmultiple.xul @@ -0,0 +1,59 @@ +<?xml version="1.0"?> +<?xml-stylesheet href="chrome://global/skin" type="text/css"?> +<?xml-stylesheet href="chrome://mochikit/content/tests/SimpleTest/test.css" type="text/css"?> + +<!-- + where - startswith multiple +--> + +<window title="XUL Template Tests" width="500" height="600" + onload="test_template();" + xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"> + <script type="application/javascript" + src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script> + + <body xmlns="http://www.w3.org/1999/xhtml" style="height: 300px; overflow: auto;"/> + + <data id="output"> + <label id="http://www.some-fictitious-zoo.com/mammals/lion" value="Lion"/> + <label id="http://www.some-fictitious-zoo.com/mammals/africanelephant" value="African Elephant"/> + <label id="http://www.some-fictitious-zoo.com/mammals/llama" value="LLAMA"/> + </data> + +<script src="templates_shared.js"/> + +<script> +<![CDATA[ +SimpleTest.waitForExplicitFinish(); + +var testid ="where - startswith multiple"; +var queryType = "rdf"; +var isTreeBuilder = false; +var needsOpen = false; +var notWorkingYet = false; +var notWorkingYetDynamic = false; +var expectedOutput = document.getElementById("output"); + +var changes = []; +]]> +</script> + +<vbox xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul" id="root" datasources="rdf:null" ref="http://www.some-fictitious-zoo.com/mammals"> +<template id="template"> +<query id="query"> +<content uri="?uri"/> +<member container="?uri" child="?animal"/> +<triple subject="?animal" predicate="http://www.some-fictitious-zoo.com/rdf#name" object="?name"/> +</query> +<rule> +<conditions id="conditions"> +<where subject="?name" rel="startswith" multiple="true" value="L,A"/> +</conditions> +<action id="action"> +<label uri="?animal" value="?name"/> +</action> +</rule> +</template> +</vbox> + +</window> diff --git a/dom/xul/templates/tests/chrome/test_tmpl_wherestartswithnegation.xul b/dom/xul/templates/tests/chrome/test_tmpl_wherestartswithnegation.xul new file mode 100644 index 000000000..4ab12c74d --- /dev/null +++ b/dom/xul/templates/tests/chrome/test_tmpl_wherestartswithnegation.xul @@ -0,0 +1,62 @@ +<?xml version="1.0"?> +<?xml-stylesheet href="chrome://global/skin" type="text/css"?> +<?xml-stylesheet href="chrome://mochikit/content/tests/SimpleTest/test.css" type="text/css"?> + +<!-- + where - startswith negation +--> + +<window title="XUL Template Tests" width="500" height="600" + onload="test_template();" + xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"> + <script type="application/javascript" + src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script> + + <body xmlns="http://www.w3.org/1999/xhtml" style="height: 300px; overflow: auto;"/> + + <data id="output"> + <label id="http://www.some-fictitious-zoo.com/mammals/hippopotamus" value="HIPPOPOTAMUS"/> + <label id="http://www.some-fictitious-zoo.com/mammals/africanelephant" value="African Elephant"/> + <label id="http://www.some-fictitious-zoo.com/mammals/polarbear" value="Polar Bear"/> + <label id="http://www.some-fictitious-zoo.com/mammals/aardvark" value="aardvark"/> + <label id="http://www.some-fictitious-zoo.com/mammals/ninebandedarmadillo" value="Nine-banded Armadillo"/> + <label id="http://www.some-fictitious-zoo.com/mammals/gorilla" value="Gorilla"/> + </data> + +<script src="templates_shared.js"/> + +<script> +<![CDATA[ +SimpleTest.waitForExplicitFinish(); + +var testid ="where - startswith negation"; +var queryType = "rdf"; +var isTreeBuilder = false; +var needsOpen = false; +var notWorkingYet = false; +var notWorkingYetDynamic = false; +var expectedOutput = document.getElementById("output"); + +var changes = []; +]]> +</script> + +<vbox xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul" id="root" datasources="rdf:null" ref="http://www.some-fictitious-zoo.com/mammals"> +<template id="template"> +<query id="query"> +<content uri="?uri"/> +<member container="?uri" child="?animal"/> +<triple subject="?animal" predicate="http://www.some-fictitious-zoo.com/rdf#name" object="?name"/> +</query> +<rule> +<conditions id="conditions"> +<where subject="?name" rel="startswith" negate="true" value="L"/> +</conditions> +<action id="action"> +<label uri="?animal" value="?name"/> +</action> +</rule> +</template> +</vbox> + +</window> diff --git a/dom/xul/templates/tests/chrome/test_tmpl_wherestartswithunknownvariable.xul b/dom/xul/templates/tests/chrome/test_tmpl_wherestartswithunknownvariable.xul new file mode 100644 index 000000000..9fd794b92 --- /dev/null +++ b/dom/xul/templates/tests/chrome/test_tmpl_wherestartswithunknownvariable.xul @@ -0,0 +1,55 @@ +<?xml version="1.0"?> +<?xml-stylesheet href="chrome://global/skin" type="text/css"?> +<?xml-stylesheet href="chrome://mochikit/content/tests/SimpleTest/test.css" type="text/css"?> + +<!-- + where - startswith unknown variable +--> + +<window title="XUL Template Tests" width="500" height="600" + onload="test_template();" + xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"> + <script type="application/javascript" + src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script> + + <body xmlns="http://www.w3.org/1999/xhtml" style="height: 300px; overflow: auto;"/> + + <data id="output"/> + +<script src="templates_shared.js"/> + +<script> +<![CDATA[ +SimpleTest.waitForExplicitFinish(); + +var testid ="where - startswith unknown variable"; +var queryType = "rdf"; +var isTreeBuilder = false; +var needsOpen = false; +var notWorkingYet = false; +var notWorkingYetDynamic = false; +var expectedOutput = document.getElementById("output"); + +var changes = []; +]]> +</script> + +<vbox xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul" id="root" datasources="rdf:null" ref="http://www.some-fictitious-zoo.com/mammals"> +<template id="template"> +<query id="query"> +<content uri="?uri"/> +<member container="?uri" child="?animal"/> +<triple subject="?animal" predicate="http://www.some-fictitious-zoo.com/rdf#name" object="?name"/> +</query> +<rule> +<conditions id="conditions"> +<where subject="?name" rel="startswith" value="?unknown"/> +</conditions> +<action id="action"> +<label uri="?animal" value="?name"/> +</action> +</rule> +</template> +</vbox> + +</window> diff --git a/dom/xul/templates/tests/chrome/test_tmpl_wherestartswithvariable.xul b/dom/xul/templates/tests/chrome/test_tmpl_wherestartswithvariable.xul new file mode 100644 index 000000000..41e2be959 --- /dev/null +++ b/dom/xul/templates/tests/chrome/test_tmpl_wherestartswithvariable.xul @@ -0,0 +1,64 @@ +<?xml version="1.0"?> +<?xml-stylesheet href="chrome://global/skin" type="text/css"?> +<?xml-stylesheet href="chrome://mochikit/content/tests/SimpleTest/test.css" type="text/css"?> + +<!-- + where - startswith variable +--> + +<window title="XUL Template Tests" width="500" height="600" + onload="test_template();" + xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"> + <script type="application/javascript" + src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script> + + <body xmlns="http://www.w3.org/1999/xhtml" style="height: 300px; overflow: auto;"/> + + <data id="output"> + <label id="http://www.some-fictitious-zoo.com/mammals/lion" value="Lion"/> + <label id="http://www.some-fictitious-zoo.com/mammals/hippopotamus" value="HIPPOPOTAMUS"/> + <label id="http://www.some-fictitious-zoo.com/mammals/africanelephant" value="African Elephant"/> + <label id="http://www.some-fictitious-zoo.com/mammals/llama" value="LLAMA"/> + <label id="http://www.some-fictitious-zoo.com/mammals/polarbear" value="Polar Bear"/> + <label id="http://www.some-fictitious-zoo.com/mammals/aardvark" value="aardvark"/> + <label id="http://www.some-fictitious-zoo.com/mammals/ninebandedarmadillo" value="Nine-banded Armadillo"/> + <label id="http://www.some-fictitious-zoo.com/mammals/gorilla" value="Gorilla"/> + </data> + +<script src="templates_shared.js"/> + +<script> +<![CDATA[ +SimpleTest.waitForExplicitFinish(); + +var testid ="where - startswith variable"; +var queryType = "rdf"; +var isTreeBuilder = false; +var needsOpen = false; +var notWorkingYet = false; +var notWorkingYetDynamic = false; +var expectedOutput = document.getElementById("output"); + +var changes = []; +]]> +</script> + +<vbox xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul" id="root" datasources="rdf:null" ref="http://www.some-fictitious-zoo.com/mammals"> +<template id="template"> +<query id="query"> +<content uri="?uri"/> +<member container="?uri" child="?animal"/> +<triple subject="?animal" predicate="http://www.some-fictitious-zoo.com/rdf#name" object="?name"/> +</query> +<rule> +<conditions id="conditions"> +<where subject="?name" rel="startswith" value="?name"/> +</conditions> +<action id="action"> +<label uri="?animal" value="?name"/> +</action> +</rule> +</template> +</vbox> + +</window> diff --git a/dom/xul/templates/tests/chrome/test_tmpl_wheresubjectequalsvariable.xul b/dom/xul/templates/tests/chrome/test_tmpl_wheresubjectequalsvariable.xul new file mode 100644 index 000000000..14c03898c --- /dev/null +++ b/dom/xul/templates/tests/chrome/test_tmpl_wheresubjectequalsvariable.xul @@ -0,0 +1,57 @@ +<?xml version="1.0"?> +<?xml-stylesheet href="chrome://global/skin" type="text/css"?> +<?xml-stylesheet href="chrome://mochikit/content/tests/SimpleTest/test.css" type="text/css"?> + +<!-- + where - subject equals variable +--> + +<window title="XUL Template Tests" width="500" height="600" + onload="test_template();" + xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"> + <script type="application/javascript" + src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script> + + <body xmlns="http://www.w3.org/1999/xhtml" style="height: 300px; overflow: auto;"/> + + <data id="output"> + <label id="http://www.some-fictitious-zoo.com/mammals/africanelephant" value="African Elephant"/> + </data> + +<script src="templates_shared.js"/> + +<script> +<![CDATA[ +SimpleTest.waitForExplicitFinish(); + +var testid ="where - subject equals variable"; +var queryType = "rdf"; +var isTreeBuilder = false; +var needsOpen = false; +var notWorkingYet = false; +var notWorkingYetDynamic = false; +var expectedOutput = document.getElementById("output"); + +var changes = []; +]]> +</script> + +<vbox xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul" id="root" datasources="rdf:null" ref="http://www.some-fictitious-zoo.com/mammals"> +<template id="template"> +<query id="query"> +<content uri="?uri"/> +<member container="?uri" child="?animal"/> +<triple subject="?animal" predicate="http://www.some-fictitious-zoo.com/rdf#name" object="?name"/> +</query> +<rule> +<conditions id="conditions"> +<where subject="African Elephant" rel="equals" value="?name"/> +</conditions> +<action id="action"> +<label uri="?animal" value="?name"/> +</action> +</rule> +</template> +</vbox> + +</window> diff --git a/dom/xul/templates/tests/chrome/test_tmpl_wheresubjectstartswithvariable.xul b/dom/xul/templates/tests/chrome/test_tmpl_wheresubjectstartswithvariable.xul new file mode 100644 index 000000000..dd93aa285 --- /dev/null +++ b/dom/xul/templates/tests/chrome/test_tmpl_wheresubjectstartswithvariable.xul @@ -0,0 +1,57 @@ +<?xml version="1.0"?> +<?xml-stylesheet href="chrome://global/skin" type="text/css"?> +<?xml-stylesheet href="chrome://mochikit/content/tests/SimpleTest/test.css" type="text/css"?> + +<!-- + where - subject startswith variable +--> + +<window title="XUL Template Tests" width="500" height="600" + onload="test_template();" + xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"> + <script type="application/javascript" + src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script> + + <body xmlns="http://www.w3.org/1999/xhtml" style="height: 300px; overflow: auto;"/> + + <data id="output"> + <label id="http://www.some-fictitious-zoo.com/mammals/africanelephant" value="African Elephant"/> + </data> + +<script src="templates_shared.js"/> + +<script> +<![CDATA[ +SimpleTest.waitForExplicitFinish(); + +var testid ="where - subject startswith variable"; +var queryType = "rdf"; +var isTreeBuilder = false; +var needsOpen = false; +var notWorkingYet = false; +var notWorkingYetDynamic = false; +var expectedOutput = document.getElementById("output"); + +var changes = []; +]]> +</script> + +<vbox xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul" id="root" datasources="rdf:null" ref="http://www.some-fictitious-zoo.com/mammals"> +<template id="template"> +<query id="query"> +<content uri="?uri"/> +<member container="?uri" child="?animal"/> +<triple subject="?animal" predicate="http://www.some-fictitious-zoo.com/rdf#name" object="?name"/> +</query> +<rule> +<conditions id="conditions"> +<where subject="African Elephantitis" rel="startswith" value="?name"/> +</conditions> +<action id="action"> +<label uri="?animal" value="?name"/> +</action> +</rule> +</template> +</vbox> + +</window> diff --git a/dom/xul/templates/tests/chrome/test_tmpl_xmlquerysimple.xul b/dom/xul/templates/tests/chrome/test_tmpl_xmlquerysimple.xul new file mode 100644 index 000000000..9a576e370 --- /dev/null +++ b/dom/xul/templates/tests/chrome/test_tmpl_xmlquerysimple.xul @@ -0,0 +1,48 @@ +<?xml version="1.0"?> +<?xml-stylesheet href="chrome://global/skin" type="text/css"?> +<?xml-stylesheet href="chrome://mochikit/content/tests/SimpleTest/test.css" type="text/css"?> + +<!-- + xml query simple +--> + +<window title="XUL Template Tests" width="500" height="600" + onload="test_template();" + xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"> + <script type="application/javascript" + src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script> + + <body xmlns="http://www.w3.org/1999/xhtml" style="height: 300px; overflow: auto;"/> + + <data id="output"> + <button id="chrome://mochitests/content/chrome/dom/xul/templates/tests/chrome/animals.xml#Chamaeleo-chamaelon" label="Chameleon 2"/> + <button id="chrome://mochitests/content/chrome/dom/xul/templates/tests/chrome/animals.xml#Dromaius-novaehollandiae" label="Emu 12"/> + <button id="chrome://mochitests/content/chrome/dom/xul/templates/tests/chrome/animals.xml#Tyto-alba" label="Barn Owl 4"/> + <button id="chrome://mochitests/content/chrome/dom/xul/templates/tests/chrome/animals.xml#Corvus-corax" label="Raven 0"/> + </data> + +<script src="templates_shared.js"/> + +<script> +<![CDATA[ +SimpleTest.waitForExplicitFinish(); + +var testid ="xml query simple"; +var queryType = "xml"; +var isTreeBuilder = false; +var needsOpen = false; +var notWorkingYet = false; +var notWorkingYetDynamic = false; +var expectedOutput = document.getElementById("output"); + +var changes = []; +]]> +</script> + +<vbox xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul" id="root" datasources="animals.xml" querytype="xml" ref="."> +<template expr="class/species"> +<button uri="?" label="?name ?specimens"/> +</template> +</vbox> + +</window> diff --git a/dom/xul/templates/tests/chrome/test_tmpl_xmlquerywithassign.xul b/dom/xul/templates/tests/chrome/test_tmpl_xmlquerywithassign.xul new file mode 100644 index 000000000..39992b43e --- /dev/null +++ b/dom/xul/templates/tests/chrome/test_tmpl_xmlquerywithassign.xul @@ -0,0 +1,68 @@ +<?xml version="1.0"?> +<?xml-stylesheet href="chrome://global/skin" type="text/css"?> +<?xml-stylesheet href="chrome://mochikit/content/tests/SimpleTest/test.css" type="text/css"?> + +<!-- + xml query with assign +--> + +<window title="XUL Template Tests" width="500" height="600" + onload="test_template();" + xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"> + <script type="application/javascript" + src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script> + + <body xmlns="http://www.w3.org/1999/xhtml" style="height: 300px; overflow: auto;"/> + + <data id="output"> + <hbox id="chrome://mochitests/content/chrome/dom/xul/templates/tests/chrome/animals.xml#Chamaeleo-chamaelon"> + <button label="Chameleon"/> + <label value="9"/> + </hbox> + <hbox id="chrome://mochitests/content/chrome/dom/xul/templates/tests/chrome/animals.xml#Dromaius-novaehollandiae"> + <button label="Emu"/> + <label value="3"/> + </hbox> + <hbox id="chrome://mochitests/content/chrome/dom/xul/templates/tests/chrome/animals.xml#Tyto-alba"> + <button label="Barn Owl"/> + <label value="8"/> + </hbox> + <hbox id="chrome://mochitests/content/chrome/dom/xul/templates/tests/chrome/animals.xml#Corvus-corax"> + <button label="Raven"/> + <label value="5"/> + </hbox> + </data> + +<script src="templates_shared.js"/> + +<script> +<![CDATA[ +SimpleTest.waitForExplicitFinish(); + +var testid ="xml query with assign"; +var queryType = "xml"; +var isTreeBuilder = false; +var needsOpen = false; +var notWorkingYet = false; +var notWorkingYetDynamic = false; +var expectedOutput = document.getElementById("output"); + +var changes = []; +]]> +</script> + +<vbox xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul" id="root" datasources="animals.xml" querytype="xml" ref="."> +<template> +<query expr="class/species"> +<assign var="?length" expr="string-length(@name)"/> +</query> +<action> +<hbox uri="?"> +<button label="?name"/> +<label value="?length"/> +</hbox> +</action> +</template> +</vbox> + +</window> diff --git a/dom/xul/templates/tests/chrome/test_tmpl_xmlquerywithassignmentandcondition.xul b/dom/xul/templates/tests/chrome/test_tmpl_xmlquerywithassignmentandcondition.xul new file mode 100644 index 000000000..fdbbed321 --- /dev/null +++ b/dom/xul/templates/tests/chrome/test_tmpl_xmlquerywithassignmentandcondition.xul @@ -0,0 +1,69 @@ +<?xml version="1.0"?> +<?xml-stylesheet href="chrome://global/skin" type="text/css"?> +<?xml-stylesheet href="chrome://mochikit/content/tests/SimpleTest/test.css" type="text/css"?> + +<!-- + xml query with assignment and condition +--> + +<window title="XUL Template Tests" width="500" height="600" + onload="test_template();" + xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"> + <script type="application/javascript" + src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script> + + <body xmlns="http://www.w3.org/1999/xhtml" style="height: 300px; overflow: auto;"/> + + <data id="output"> + <hbox anyid="true" container="true" empty="false"> + <label value="class"/> + <hbox anyid="true" container="true" empty="true"> + <label value="name"/> + </hbox> + </hbox> + <hbox anyid="true" container="true" empty="false"> + <label value="class"/> + <hbox anyid="true" container="true" empty="true"> + <label value="name"/> + </hbox> + <hbox anyid="true" container="true" empty="true"> + <label value="location"/> + </hbox> + </hbox> + </data> + +<script src="templates_shared.js"/> + +<script> +<![CDATA[ +SimpleTest.waitForExplicitFinish(); + +var testid ="xml query with assignment and condition"; +var queryType = "xml"; +var isTreeBuilder = false; +var needsOpen = false; +var notWorkingYet = false; +var notWorkingYetDynamic = false; +var expectedOutput = document.getElementById("output"); + +var changes = []; +]]> +</script> + +<vbox xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul" id="root" datasources="animals.xml" querytype="xml" ref="."> +<template> +<query> +<assign var="?name" expr="name()"/> +</query> +<rule> +<where subject="?name" rel="equals" negate="true" value="species"/> +<action> +<hbox uri="?"> +<label value="?name"/> +</hbox> +</action> +</rule> +</template> +</vbox> + +</window> diff --git a/dom/xul/templates/tests/chrome/test_tmpl_xmlquerywithassignmentandconditiondontrecurse.xul b/dom/xul/templates/tests/chrome/test_tmpl_xmlquerywithassignmentandconditiondontrecurse.xul new file mode 100644 index 000000000..8f7e747c3 --- /dev/null +++ b/dom/xul/templates/tests/chrome/test_tmpl_xmlquerywithassignmentandconditiondontrecurse.xul @@ -0,0 +1,60 @@ +<?xml version="1.0"?> +<?xml-stylesheet href="chrome://global/skin" type="text/css"?> +<?xml-stylesheet href="chrome://mochikit/content/tests/SimpleTest/test.css" type="text/css"?> + +<!-- + xml query with assignment and condition dont-recurse +--> + +<window title="XUL Template Tests" width="500" height="600" + onload="test_template();" + xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"> + <script type="application/javascript" + src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script> + + <body xmlns="http://www.w3.org/1999/xhtml" style="height: 300px; overflow: auto;"/> + + <data id="output"> + <hbox anyid="true" container="true" empty="false"> + <label value="class"/> + </hbox> + <hbox anyid="true" container="true" empty="false"> + <label value="class"/> + </hbox> + </data> + +<script src="templates_shared.js"/> + +<script> +<![CDATA[ +SimpleTest.waitForExplicitFinish(); + +var testid ="xml query with assignment and condition dont-recurse"; +var queryType = "xml"; +var isTreeBuilder = false; +var needsOpen = false; +var notWorkingYet = false; +var notWorkingYetDynamic = false; +var expectedOutput = document.getElementById("output"); + +var changes = []; +]]> +</script> + +<vbox xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul" id="root" datasources="animals.xml" querytype="xml" ref="." flags="dont-recurse"> +<template> +<query> +<assign var="?name" expr="name()"/> +</query> +<rule> +<where subject="?name" rel="equals" negate="true" value="species"/> +<action> +<hbox uri="?"> +<label value="?name"/> +</hbox> +</action> +</rule> +</template> +</vbox> + +</window> diff --git a/dom/xul/templates/tests/chrome/test_tmpl_xmlquerywithbindinginbindings.xul b/dom/xul/templates/tests/chrome/test_tmpl_xmlquerywithbindinginbindings.xul new file mode 100644 index 000000000..90372f62c --- /dev/null +++ b/dom/xul/templates/tests/chrome/test_tmpl_xmlquerywithbindinginbindings.xul @@ -0,0 +1,54 @@ +<?xml version="1.0"?> +<?xml-stylesheet href="chrome://global/skin" type="text/css"?> +<?xml-stylesheet href="chrome://mochikit/content/tests/SimpleTest/test.css" type="text/css"?> + +<!-- + xml query with binding in bindings +--> + +<window title="XUL Template Tests" width="500" height="600" + onload="test_template();" + xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"> + <script type="application/javascript" + src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script> + + <body xmlns="http://www.w3.org/1999/xhtml" style="height: 300px; overflow: auto;"/> + + <data id="output"> + <checkbox anyid="true" container="true" empty="true" label="Reptiles"/> + <checkbox anyid="true" container="true" empty="true" label="Birds"/> + </data> + +<script src="templates_shared.js"/> + +<script> +<![CDATA[ +SimpleTest.waitForExplicitFinish(); + +var testid ="xml query with binding in bindings"; +var queryType = "xml"; +var isTreeBuilder = false; +var needsOpen = false; +var notWorkingYet = false; +var notWorkingYetDynamic = false; +var expectedOutput = document.getElementById("output"); + +var changes = []; +]]> +</script> + +<vbox xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul" id="root" datasources="animals.xml" querytype="xml" ref="."> +<template> +<query expr="class/name"/> +<rule id="rule"> +<bindings> +<binding subject="?" predicate="text()" object="?nm"/> +</bindings> +<action> +<checkbox uri="?" label="?nm"/> +</action> +</rule> +</template> +</vbox> + +</window> diff --git a/dom/xul/templates/tests/chrome/test_tmpl_xmlquerywithbindinginrule.xul b/dom/xul/templates/tests/chrome/test_tmpl_xmlquerywithbindinginrule.xul new file mode 100644 index 000000000..57ca2d838 --- /dev/null +++ b/dom/xul/templates/tests/chrome/test_tmpl_xmlquerywithbindinginrule.xul @@ -0,0 +1,64 @@ +<?xml version="1.0"?> +<?xml-stylesheet href="chrome://global/skin" type="text/css"?> +<?xml-stylesheet href="chrome://mochikit/content/tests/SimpleTest/test.css" type="text/css"?> + +<!-- + xml query with binding in rule +--> + +<window title="XUL Template Tests" width="500" height="600" + onload="test_template();" + xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"> + <script type="application/javascript" + src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script> + + <body xmlns="http://www.w3.org/1999/xhtml" style="height: 300px; overflow: auto;"/> + + <data id="output"> + <label anyid="true" container="true" empty="true" value="Class Reptiles"/> + <label anyid="true" container="true" empty="true" value="Class Birds"/> + </data> + +<script src="templates_shared.js"/> + +<script> +<![CDATA[ +SimpleTest.waitForExplicitFinish(); + +var testid ="xml query with binding in rule"; +var queryType = "xml"; +var isTreeBuilder = false; +var needsOpen = false; +var notWorkingYet = false; +var notWorkingYetDynamic = false; +var expectedOutput = document.getElementById("output"); + +Components.classes["@mozilla.org/consoleservice;1"]. + getService(Components.interfaces.nsIConsoleService).reset(); + +expectLoggedMessages = function() +{ + // check log to ensure that two rows have been added + var initialNumber = Number(document.getElementById("root").firstChild.nextSibling.id.substring(3)); + expectConsoleMessage('', 'row' + initialNumber, true, true, '1 matching rule 1'); + expectConsoleMessage('', 'row' + (initialNumber + 1), true, true, '1 matching rule 1'); +} + +var changes = []; +]]> +</script> + +<vbox xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul" id="root" + flags="logging" datasources="animals.xml" querytype="xml" ref="."> +<template> +<query expr="class/name"/> +<rule id="rule"> +<binding subject="?" predicate="concat('Class ', text())" object="?text"/> +<action> +<label uri="?" value="?text"/> +</action> +</rule> +</template> +</vbox> + +</window> diff --git a/dom/xul/templates/tests/chrome/test_tmpl_xmlquerywithdifferentmember.xul b/dom/xul/templates/tests/chrome/test_tmpl_xmlquerywithdifferentmember.xul new file mode 100644 index 000000000..160d4bddb --- /dev/null +++ b/dom/xul/templates/tests/chrome/test_tmpl_xmlquerywithdifferentmember.xul @@ -0,0 +1,48 @@ +<?xml version="1.0"?> +<?xml-stylesheet href="chrome://global/skin" type="text/css"?> +<?xml-stylesheet href="chrome://mochikit/content/tests/SimpleTest/test.css" type="text/css"?> + +<!-- + xml query with different member +--> + +<window title="XUL Template Tests" width="500" height="600" + onload="test_template();" + xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"> + <script type="application/javascript" + src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script> + + <body xmlns="http://www.w3.org/1999/xhtml" style="height: 300px; overflow: auto;"/> + + <data id="output"> + <button id="chrome://mochitests/content/chrome/dom/xul/templates/tests/chrome/animals.xml#Chamaeleo-chamaelon" label="Chameleon 2"/> + <button id="chrome://mochitests/content/chrome/dom/xul/templates/tests/chrome/animals.xml#Dromaius-novaehollandiae" label="Emu 12"/> + <button id="chrome://mochitests/content/chrome/dom/xul/templates/tests/chrome/animals.xml#Tyto-alba" label="Barn Owl 4"/> + <button id="chrome://mochitests/content/chrome/dom/xul/templates/tests/chrome/animals.xml#Corvus-corax" label="Raven 0"/> + </data> + +<script src="templates_shared.js"/> + +<script> +<![CDATA[ +SimpleTest.waitForExplicitFinish(); + +var testid ="xml query with different member"; +var queryType = "xml"; +var isTreeBuilder = false; +var needsOpen = false; +var notWorkingYet = false; +var notWorkingYetDynamic = false; +var expectedOutput = document.getElementById("output"); + +var changes = []; +]]> +</script> + +<vbox xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul" id="root" datasources="animals.xml" querytype="xml" ref="."> +<template expr="class/species"> +<button uri="?memb" label="?name ?specimens"/> +</template> +</vbox> + +</window> diff --git a/dom/xul/templates/tests/chrome/test_tmpl_xmlquerywithinlinedata.xul b/dom/xul/templates/tests/chrome/test_tmpl_xmlquerywithinlinedata.xul new file mode 100644 index 000000000..010a6ba49 --- /dev/null +++ b/dom/xul/templates/tests/chrome/test_tmpl_xmlquerywithinlinedata.xul @@ -0,0 +1,54 @@ +<?xml version="1.0"?> +<?xml-stylesheet href="chrome://global/skin" type="text/css"?> +<?xml-stylesheet href="chrome://mochikit/content/tests/SimpleTest/test.css" type="text/css"?> + +<!-- + xml query with inline data +--> + +<window title="XUL Template Tests" width="500" height="600" + onload="test_template();" + xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"> + <script type="application/javascript" + src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script> + + <body xmlns="http://www.w3.org/1999/xhtml" style="height: 300px; overflow: auto;"/> + + <data id="output"> + <button anyid="true" label="Nathan"/> + <button anyid="true" label="Marie"/> + </data> + +<script src="templates_shared.js"/> + +<script> +<![CDATA[ +SimpleTest.waitForExplicitFinish(); + +var testid ="xml query with inline data"; +var queryType = "xml"; +var isTreeBuilder = false; +var needsOpen = false; +var notWorkingYet = false; +var notWorkingYetDynamic = false; +var expectedOutput = document.getElementById("output"); + +var changes = []; +]]> +</script> + +<people id="data" xmlns:test="http://www.mozilla.com/test"> +<test:person name="Nathan"/> +<person name="Luke"/> +<xt:person xmlns:xt="http://www.mozilla.com/test" name="Marie"/> +</people> + +<vbox xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul" id="root" datasources="#data" querytype="xml" ref="."> +<template expr="test:person"> +<button uri="?" label="?name"/> +</template> +<button id="row6" label="Nathan"/> +<button id="row7" label="Marie"/> +</vbox> + +</window> diff --git a/dom/xul/templates/tests/chrome/test_tmpl_xmlquerywithinlinedatawithmultiplequeries.xul b/dom/xul/templates/tests/chrome/test_tmpl_xmlquerywithinlinedatawithmultiplequeries.xul new file mode 100644 index 000000000..d9640fbde --- /dev/null +++ b/dom/xul/templates/tests/chrome/test_tmpl_xmlquerywithinlinedatawithmultiplequeries.xul @@ -0,0 +1,71 @@ +<?xml version="1.0"?> +<?xml-stylesheet href="chrome://global/skin" type="text/css"?> +<?xml-stylesheet href="chrome://mochikit/content/tests/SimpleTest/test.css" type="text/css"?> + +<!-- + xml query with inline data with multiple queries +--> + +<window title="XUL Template Tests" width="500" height="600" + onload="test_template();" + xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"> + <script type="application/javascript" + src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script> + + <body xmlns="http://www.w3.org/1999/xhtml" style="height: 300px; overflow: auto;"/> + + <data id="output"> + <button anyid="true" label="Nathan"/> + <button anyid="true" label="Marie"/> + <checkbox anyid="true" label="Nathan"/> + <checkbox anyid="true" label="Luke"/> + <checkbox anyid="true" label="Marie"/> + </data> + +<script src="templates_shared.js"/> + +<script> +<![CDATA[ +SimpleTest.waitForExplicitFinish(); + +var testid ="xml query with inline data with multiple queries"; +var queryType = "xml"; +var isTreeBuilder = false; +var needsOpen = false; +var notWorkingYet = false; +var notWorkingYetDynamic = false; +var expectedOutput = document.getElementById("output"); + +var changes = []; +]]> +</script> + +<people id="data" xmlns:test="http://www.mozilla.com/test"> +<test:person name="Nathan"/> +<person name="Luke"/> +<xt:person xmlns:xt="http://www.mozilla.com/test" name="Marie"/> +</people> + +<vbox xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul" id="root" datasources="#data" querytype="xml" ref="."> +<template> +<queryset> +<query expr="test:person"/> +<action> +<button uri="?" label="?name"/> +</action> +</queryset> +<queryset> +<query/> +<action> +<checkbox uri="?" label="?name"/> +</action> +</queryset> +</template> +<button id="row9" label="Nathan"/> +<button id="row10" label="Marie"/> +<checkbox id="row11" label="Nathan"/> +<checkbox id="row12" label="Luke"/> +<checkbox id="row13" label="Marie"/> +</vbox> + +</window> diff --git a/dom/xul/templates/tests/chrome/test_tmpl_xmlquerywithmultiplequeries.xul b/dom/xul/templates/tests/chrome/test_tmpl_xmlquerywithmultiplequeries.xul new file mode 100644 index 000000000..075d2c453 --- /dev/null +++ b/dom/xul/templates/tests/chrome/test_tmpl_xmlquerywithmultiplequeries.xul @@ -0,0 +1,70 @@ +<?xml version="1.0"?> +<?xml-stylesheet href="chrome://global/skin" type="text/css"?> +<?xml-stylesheet href="chrome://mochikit/content/tests/SimpleTest/test.css" type="text/css"?> + +<!-- + xml query with multiple queries +--> + +<window title="XUL Template Tests" width="500" height="600" + onload="test_template();" + xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"> + <script type="application/javascript" + src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script> + + <body xmlns="http://www.w3.org/1999/xhtml" style="height: 300px; overflow: auto;"/> + + <data id="output"> + <button id="chrome://mochitests/content/chrome/dom/xul/templates/tests/chrome/animals.xml#Dromaius-novaehollandiae" label="(Dromaius-novaehollandiae) is a large bird"/> + <button id="chrome://mochitests/content/chrome/dom/xul/templates/tests/chrome/animals.xml#Tyto-alba" label="(Tyto-alba) Barn Owl"/> + <button id="chrome://mochitests/content/chrome/dom/xul/templates/tests/chrome/animals.xml#Corvus-corax" label="(Corvus-corax) Raven"/> + <label id="chrome://mochitests/content/chrome/dom/xul/templates/tests/chrome/animals.xml#Chamaeleo-chamaelon" value="Chameleon"/> + </data> + +<script src="templates_shared.js"/> + +<script> +<![CDATA[ +SimpleTest.waitForExplicitFinish(); + +var testid ="xml query with multiple queries"; +var queryType = "xml"; +var isTreeBuilder = false; +var needsOpen = false; +var notWorkingYet = false; +var notWorkingYetDynamic = false; +var expectedOutput = document.getElementById("output"); + +var changes = []; +]]> +</script> + +<vbox xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul" id="root" datasources="animals.xml" querytype="xml" ref="."> +<template> +<queryset> +<query expr="class[position()>1]/species"> +<assign var="?id" expr="concat('(', @id, ')')"/> +</query> +<rule> +<where subject="?id" rel="equals" value="(Dromaius-novaehollandiae)"/> +<action> +<button uri="?" label="?id is a large bird"/> +</action> +</rule> +<rule> +<binding subject="?" predicate="@name" object="?name"/> +<action> +<button uri="?" label="?id ?name"/> +</action> +</rule> +</queryset> +<queryset> +<query expr="class[name/text()='Reptiles']/species"/> +<action> +<label uri="?" value="?name"/> +</action> +</queryset> +</template> +</vbox> + +</window> diff --git a/dom/xul/templates/tests/chrome/test_tmpl_xmlquerywithothertypes.xul b/dom/xul/templates/tests/chrome/test_tmpl_xmlquerywithothertypes.xul new file mode 100644 index 000000000..ce728b2b1 --- /dev/null +++ b/dom/xul/templates/tests/chrome/test_tmpl_xmlquerywithothertypes.xul @@ -0,0 +1,75 @@ +<?xml version="1.0"?> +<?xml-stylesheet href="chrome://global/skin" type="text/css"?> +<?xml-stylesheet href="chrome://mochikit/content/tests/SimpleTest/test.css" type="text/css"?> + +<!-- + xml query with other types +--> + +<window title="XUL Template Tests" width="500" height="600" + onload="test_template();" + xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"> + <script type="application/javascript" + src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script> + + <body xmlns="http://www.w3.org/1999/xhtml" style="height: 300px; overflow: auto;"/> + + <data id="output"> + <groupbox anyid="true" container="true" empty="false"> + <caption label="Reptiles false"/> + <label id="chrome://mochitests/content/chrome/dom/xul/templates/tests/chrome/animals.xml#Chamaeleo-chamaelon" value="Chameleon"/> + </groupbox> + <groupbox anyid="true" container="true" empty="false"> + <caption label="Birds true"/> + <label id="chrome://mochitests/content/chrome/dom/xul/templates/tests/chrome/animals.xml#Dromaius-novaehollandiae" value="Emu"/> + <label id="chrome://mochitests/content/chrome/dom/xul/templates/tests/chrome/animals.xml#Tyto-alba" value="Barn Owl"/> + <label id="chrome://mochitests/content/chrome/dom/xul/templates/tests/chrome/animals.xml#Corvus-corax" value="Raven"/> + </groupbox> + </data> + +<script src="templates_shared.js"/> + +<script> +<![CDATA[ +SimpleTest.waitForExplicitFinish(); + +var testid ="xml query with other types"; +var queryType = "xml"; +var isTreeBuilder = false; +var needsOpen = false; +var notWorkingYet = false; +var notWorkingYetDynamic = false; +var expectedOutput = document.getElementById("output"); + +var changes = []; +]]> +</script> + +<vbox xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul" id="root" datasources="animals.xml" querytype="xml" ref="."> +<template> +<queryset> +<query expr="species"> +<assign var="?haschild" expr="boolean(location)"/> +<assign var="?name" expr="@name"/> +</query> +<action> +<label uri="?" value="?name"/> +</action> +</queryset> +<queryset> +<query> +<assign var="?name" expr="name/text()"/> +<assign var="?isbirds" expr="name/text() = 'Birds'"/> +</query> +<rule parent="vbox"> +<action> +<groupbox uri="?"> +<caption label="?name ?isbirds"/> +</groupbox> +</action> +</rule> +</queryset> +</template> +</vbox> + +</window> diff --git a/dom/xul/templates/tests/chrome/test_tmpl_xmlquerywithsort.xul b/dom/xul/templates/tests/chrome/test_tmpl_xmlquerywithsort.xul new file mode 100644 index 000000000..b83fc3595 --- /dev/null +++ b/dom/xul/templates/tests/chrome/test_tmpl_xmlquerywithsort.xul @@ -0,0 +1,51 @@ +<?xml version="1.0"?> +<?xml-stylesheet href="chrome://global/skin" type="text/css"?> +<?xml-stylesheet href="chrome://mochikit/content/tests/SimpleTest/test.css" type="text/css"?> + +<!-- + xml query with sort +--> + +<window title="XUL Template Tests" width="500" height="600" + onload="test_template();" + xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"> + <script type="application/javascript" + src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script> + + <body xmlns="http://www.w3.org/1999/xhtml" style="height: 300px; overflow: auto;"/> + + <data id="output"> + <button id="chrome://mochitests/content/chrome/dom/xul/templates/tests/chrome/animals.xml#Tyto-alba" label="Barn Owl"/> + <button id="chrome://mochitests/content/chrome/dom/xul/templates/tests/chrome/animals.xml#Chamaeleo-chamaelon" label="Chameleon"/> + <button id="chrome://mochitests/content/chrome/dom/xul/templates/tests/chrome/animals.xml#Dromaius-novaehollandiae" label="Emu"/> + <button id="chrome://mochitests/content/chrome/dom/xul/templates/tests/chrome/animals.xml#Corvus-corax" label="Raven"/> + </data> + +<script src="templates_shared.js"/> + +<script> +<![CDATA[ +SimpleTest.waitForExplicitFinish(); + +var testid ="xml query with sort"; +var queryType = "xml"; +var isTreeBuilder = false; +var needsOpen = false; +var notWorkingYet = false; +var notWorkingYetDynamic = false; +var expectedOutput = document.getElementById("output"); + +var changes = []; +]]> +</script> + +<vbox xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul" id="root" datasources="animals.xml" querytype="xml" ref="." sort="?name" sortDirection="ascending"> +<template> +<query expr="class/species"/> +<action> +<button uri="?" label="?name"/> +</action> +</template> +</vbox> + +</window> diff --git a/dom/xul/templates/tests/chrome/test_tmpl_xmlquerywithsortotherfield.xul b/dom/xul/templates/tests/chrome/test_tmpl_xmlquerywithsortotherfield.xul new file mode 100644 index 000000000..ad1829d0d --- /dev/null +++ b/dom/xul/templates/tests/chrome/test_tmpl_xmlquerywithsortotherfield.xul @@ -0,0 +1,51 @@ +<?xml version="1.0"?> +<?xml-stylesheet href="chrome://global/skin" type="text/css"?> +<?xml-stylesheet href="chrome://mochikit/content/tests/SimpleTest/test.css" type="text/css"?> + +<!-- + xml query with sort other field +--> + +<window title="XUL Template Tests" width="500" height="600" + onload="test_template();" + xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"> + <script type="application/javascript" + src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script> + + <body xmlns="http://www.w3.org/1999/xhtml" style="height: 300px; overflow: auto;"/> + + <data id="output"> + <button id="chrome://mochitests/content/chrome/dom/xul/templates/tests/chrome/animals.xml#Tyto-alba" label="Barn Owl"/> + <button id="chrome://mochitests/content/chrome/dom/xul/templates/tests/chrome/animals.xml#Dromaius-novaehollandiae" label="Emu"/> + <button id="chrome://mochitests/content/chrome/dom/xul/templates/tests/chrome/animals.xml#Corvus-corax" label="Raven"/> + <button id="chrome://mochitests/content/chrome/dom/xul/templates/tests/chrome/animals.xml#Chamaeleo-chamaelon" label="Chameleon"/> + </data> + +<script src="templates_shared.js"/> + +<script> +<![CDATA[ +SimpleTest.waitForExplicitFinish(); + +var testid ="xml query with sort other field"; +var queryType = "xml"; +var isTreeBuilder = false; +var needsOpen = false; +var notWorkingYet = false; +var notWorkingYetDynamic = false; +var expectedOutput = document.getElementById("output"); + +var changes = []; +]]> +</script> + +<vbox xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul" id="root" datasources="animals.xml" querytype="xml" ref="." sort="?id" sortDirection="descending"> +<template> +<query expr="class/species"/> +<action> +<button uri="?" label="?name"/> +</action> +</template> +</vbox> + +</window> |