summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAaron Kennedy <aaron.kennedy@nokia.com>2009-09-01 03:38:08 (GMT)
committerAaron Kennedy <aaron.kennedy@nokia.com>2009-09-01 03:38:08 (GMT)
commit49e4975e96ac9e2e8e6af1c58d3ed1453a130eb4 (patch)
tree30595ddf8401cdde3f0c7fdfb233e8ddcb600e70
parent671c3ac47a258a876352a4c4d38937e0fb7034a7 (diff)
downloadQt-49e4975e96ac9e2e8e6af1c58d3ed1453a130eb4.zip
Qt-49e4975e96ac9e2e8e6af1c58d3ed1453a130eb4.tar.gz
Qt-49e4975e96ac9e2e8e6af1c58d3ed1453a130eb4.tar.bz2
Implement more of XMLHttpRequest
-rw-r--r--examples/declarative/xmlhttprequest/test.qml26
-rw-r--r--examples/declarative/xmlhttprequest/test.xml5
-rw-r--r--src/declarative/qml/qmlengine.cpp8
-rw-r--r--src/declarative/qml/qmlengine_p.h7
-rw-r--r--src/declarative/qml/qmlxmlhttprequest.cpp883
5 files changed, 910 insertions, 19 deletions
diff --git a/examples/declarative/xmlhttprequest/test.qml b/examples/declarative/xmlhttprequest/test.qml
new file mode 100644
index 0000000..56366d6
--- /dev/null
+++ b/examples/declarative/xmlhttprequest/test.qml
@@ -0,0 +1,26 @@
+import Qt 4.6
+
+Rectangle {
+ width: 800; height: 600
+
+ MouseRegion {
+ anchors.fill: parent
+ onClicked: {
+
+ var doc = new XMLHttpRequest();
+ doc.onreadystatechange = function() {
+ if (doc.readyState == XMLHttpRequest.DONE) {
+
+ var a = doc.responseXML.documentElement;
+ for (var ii = 0; ii < a.childNodes.length; ++ii) {
+ print (a.childNodes[ii].nodeName);
+ }
+
+ }
+ }
+
+ doc.open("GET", "test.xml");
+ doc.send();
+ }
+ }
+}
diff --git a/examples/declarative/xmlhttprequest/test.xml b/examples/declarative/xmlhttprequest/test.xml
new file mode 100644
index 0000000..8b7f1e1
--- /dev/null
+++ b/examples/declarative/xmlhttprequest/test.xml
@@ -0,0 +1,5 @@
+<data>
+ <element1 />
+ <element2 />
+</data>
+
diff --git a/src/declarative/qml/qmlengine.cpp b/src/declarative/qml/qmlengine.cpp
index d06376a..cc0d4c5 100644
--- a/src/declarative/qml/qmlengine.cpp
+++ b/src/declarative/qml/qmlengine.cpp
@@ -109,8 +109,8 @@ QScriptValue desktopOpenUrl(QScriptContext *ctxt, QScriptEngine *e)
QmlEnginePrivate::QmlEnginePrivate(QmlEngine *e)
: rootContext(0), currentBindContext(0), currentExpression(0),
isDebugging(false), contextClass(0), objectClass(0), valueTypeClass(0),
- scriptEngine(this), rootComponent(0), networkAccessManager(0), typeManager(e),
- uniqueId(1)
+ nodeListClass(0), namedNodeMapClass(0), scriptEngine(this), rootComponent(0),
+ networkAccessManager(0), typeManager(e), uniqueId(1)
{
QScriptValue qtObject =
scriptEngine.newQMetaObject(StaticQtMetaObject::get());
@@ -139,6 +139,10 @@ QmlEnginePrivate::~QmlEnginePrivate()
objectClass = 0;
delete networkAccessManager;
networkAccessManager = 0;
+ delete nodeListClass;
+ nodeListClass = 0;
+ delete namedNodeMapClass;
+ namedNodeMapClass = 0;
for(int ii = 0; ii < bindValues.count(); ++ii)
clear(bindValues[ii]);
diff --git a/src/declarative/qml/qmlengine_p.h b/src/declarative/qml/qmlengine_p.h
index aeee355..b3c6279 100644
--- a/src/declarative/qml/qmlengine_p.h
+++ b/src/declarative/qml/qmlengine_p.h
@@ -114,7 +114,7 @@ public:
QPODVector<CapturedProperty> capturedProperties;
QmlContext *rootContext;
- QmlContext *currentBindContext;
+ QmlContext *currentBindContext; // ### Remove me
QmlExpression *currentExpression;
bool isDebugging;
#ifdef QT_SCRIPTTOOLS_LIB
@@ -124,9 +124,12 @@ public:
QmlContextScriptClass *contextClass;
QmlObjectScriptClass *objectClass;
QmlValueTypeScriptClass *valueTypeClass;
+ // Used by DOM Core 3 API
+ QScriptClass *nodeListClass;
+ QScriptClass *namedNodeMapClass;
QmlContext *setCurrentBindContext(QmlContext *);
- QStack<QmlContext *> activeContexts;
+ QStack<QmlContext *> activeContexts; // ### Remove me
struct QmlScriptEngine : public QScriptEngine
{
diff --git a/src/declarative/qml/qmlxmlhttprequest.cpp b/src/declarative/qml/qmlxmlhttprequest.cpp
index fb92c54..0cfd794 100644
--- a/src/declarative/qml/qmlxmlhttprequest.cpp
+++ b/src/declarative/qml/qmlxmlhttprequest.cpp
@@ -46,6 +46,10 @@
#include <QtScript/qscriptcontext.h>
#include <QtScript/qscriptengine.h>
#include <QtNetwork/qnetworkreply.h>
+#include <QtCore/qxmlstream.h>
+#include <private/qmlrefcount_p.h>
+#include <private/qmlengine_p.h>
+#include <QtCore/qstack.h>
#include "qmlxmlhttprequest_p.h"
#include <QtCore/qdebug.h>
@@ -53,6 +57,840 @@
// ### Find real values
#define INVALID_STATE_ERR ((QScriptContext::Error)15)
+#define D(arg) (arg)->release()
+#define A(arg) (arg)->addref()
+
+namespace {
+
+class NodeImpl : public QmlRefCount
+{
+public:
+ NodeImpl() : type(Element), parent(0) {}
+ virtual ~NodeImpl() {
+ if (parent) D(parent);
+ for (int ii = 0; ii < children.count(); ++ii)
+ D(children.at(ii));
+ for (int ii = 0; ii < attributes.count(); ++ii)
+ D(attributes.at(ii));
+ }
+
+ // These numbers are copied from the Node IDL definition
+ enum Type {
+ Attr = 2,
+ CDATA = 4,
+ Comment = 8,
+ Document = 9,
+ DocumentFragment = 11,
+ DocumentType = 10,
+ Element = 1,
+ Entity = 6,
+ EntityReference = 5,
+ Notation = 12,
+ ProcessingInstruction = 7,
+ Text = 3
+ };
+ Type type;
+
+ QString namespaceUri;
+ QString name;
+
+ QString data;
+
+ NodeImpl *parent;
+
+ QList<NodeImpl *> children;
+ QList<NodeImpl *> attributes;
+};
+
+class DocumentImpl : public QmlRefCount
+{
+public:
+ DocumentImpl() : root(0) {}
+ virtual ~DocumentImpl() {
+ if (root) D(root);
+ }
+
+ QString version;
+ QString encoding;
+ bool isStandalone;
+
+ NodeImpl *root;
+};
+
+class NamedNodeMap
+{
+public:
+ // JS API
+ static QScriptValue length(QScriptContext *context, QScriptEngine *engine);
+
+ // C++ API
+ static QScriptValue prototype(QScriptEngine *);
+ static QScriptValue create(QScriptEngine *, NodeImpl *, QList<NodeImpl *> *);
+
+ NamedNodeMap();
+ NamedNodeMap(const NamedNodeMap &);
+ NamedNodeMap &operator=(const NamedNodeMap &);
+ ~NamedNodeMap();
+ bool isNull();
+
+ NodeImpl *d;
+ QList<NodeImpl *> *list;
+};
+
+class NamedNodeMapClass : public QScriptClass
+{
+public:
+ NamedNodeMapClass(QScriptEngine *engine) : QScriptClass(engine) {}
+
+ virtual QueryFlags queryProperty(const QScriptValue &object, const QScriptString &name, QueryFlags flags, uint *id);
+ virtual QScriptValue property(const QScriptValue &object, const QScriptString &name, uint id);
+};
+
+class NodeList
+{
+public:
+ // JS API
+ static QScriptValue length(QScriptContext *context, QScriptEngine *engine);
+ static QScriptValue item(QScriptContext *context, QScriptEngine *engine);
+
+ // C++ API
+ static QScriptValue prototype(QScriptEngine *);
+ static QScriptValue create(QScriptEngine *, NodeImpl *);
+
+ NodeList();
+ NodeList(const NodeList &);
+ NodeList &operator=(const NodeList &);
+ ~NodeList();
+ bool isNull();
+
+ NodeImpl *d;
+};
+
+class NodeListClass : public QScriptClass
+{
+public:
+ NodeListClass(QScriptEngine *engine) : QScriptClass(engine) {}
+ virtual QueryFlags queryProperty(const QScriptValue &object, const QScriptString &name, QueryFlags flags, uint *id);
+ virtual QScriptValue property(const QScriptValue &object, const QScriptString &name, uint id);
+};
+
+class Node
+{
+public:
+ // JS API
+ static QScriptValue nodeName(QScriptContext *context, QScriptEngine *engine);
+ static QScriptValue nodeValue(QScriptContext *context, QScriptEngine *engine);
+ static QScriptValue nodeType(QScriptContext *context, QScriptEngine *engine);
+
+ static QScriptValue parentNode(QScriptContext *context, QScriptEngine *engine);
+ static QScriptValue childNodes(QScriptContext *context, QScriptEngine *engine);
+ static QScriptValue firstChild(QScriptContext *context, QScriptEngine *engine);
+ static QScriptValue lastChild(QScriptContext *context, QScriptEngine *engine);
+ static QScriptValue previousSibling(QScriptContext *context, QScriptEngine *engine);
+ static QScriptValue nextSibling(QScriptContext *context, QScriptEngine *engine);
+ static QScriptValue attributes(QScriptContext *context, QScriptEngine *engine);
+
+ //static QScriptValue ownerDocument(QScriptContext *context, QScriptEngine *engine);
+ //static QScriptValue namespaceURI(QScriptContext *context, QScriptEngine *engine);
+ //static QScriptValue prefix(QScriptContext *context, QScriptEngine *engine);
+ //static QScriptValue localName(QScriptContext *context, QScriptEngine *engine);
+ //static QScriptValue baseURI(QScriptContext *context, QScriptEngine *engine);
+ //static QScriptValue textContent(QScriptContext *context, QScriptEngine *engine);
+
+ // C++ API
+ static QScriptValue prototype(QScriptEngine *);
+ static QScriptValue create(QScriptEngine *, NodeImpl *);
+
+ Node();
+ Node(const Node &o);
+ Node &operator=(const Node &);
+ ~Node();
+ bool isNull() const;
+
+ NodeImpl *d;
+};
+
+class Element : public Node
+{
+public:
+ static QScriptValue prototype(QScriptEngine *);
+};
+
+class CharacterData : public Node
+{
+public:
+ // JS API
+ static QScriptValue length(QScriptContext *context, QScriptEngine *engine);
+
+ // C++ API
+ static QScriptValue prototype(QScriptEngine *);
+};
+
+class Text : public CharacterData
+{
+public:
+ // JS API
+ static QScriptValue isElementContentWhitespace(QScriptContext *context, QScriptEngine *engine);
+ static QScriptValue wholeText(QScriptContext *context, QScriptEngine *engine);
+
+ // C++ API
+ static QScriptValue prototype(QScriptEngine *);
+};
+
+class CDATA : public Text
+{
+public:
+ // C++ API
+ static QScriptValue prototype(QScriptEngine *);
+};
+
+class Document : public Node
+{
+public:
+ // JS API
+ static QScriptValue xmlVersion(QScriptContext *context, QScriptEngine *engine);
+ static QScriptValue xmlEncoding(QScriptContext *context, QScriptEngine *engine);
+ static QScriptValue xmlStandalone(QScriptContext *context, QScriptEngine *engine);
+ static QScriptValue documentElement(QScriptContext *context, QScriptEngine *engine);
+
+ // C++ API
+ static QScriptValue prototype(QScriptEngine *);
+ static QScriptValue load(QScriptEngine *engine, const QString &data);
+
+ Document();
+ Document(const Document &);
+ Document &operator=(const Document &);
+ ~Document();
+ bool isNull() const;
+
+ DocumentImpl *d;
+private:
+ Document(DocumentImpl *);
+};
+
+};
+
+Q_DECLARE_METATYPE(Node);
+Q_DECLARE_METATYPE(NodeList);
+Q_DECLARE_METATYPE(NamedNodeMap);
+Q_DECLARE_METATYPE(Document);
+
+QScriptValue Node::nodeName(QScriptContext *context, QScriptEngine *engine)
+{
+ Node node = qscriptvalue_cast<Node>(context->thisObject());
+ if (node.isNull()) return engine->undefinedValue();
+ return QScriptValue(node.d->name);
+}
+
+QScriptValue Node::nodeValue(QScriptContext *context, QScriptEngine *engine)
+{
+ Node node = qscriptvalue_cast<Node>(context->thisObject());
+ if (node.isNull()) return engine->undefinedValue();
+
+ return QScriptValue(node.d->data);
+}
+
+QScriptValue Node::nodeType(QScriptContext *context, QScriptEngine *engine)
+{
+ Node node = qscriptvalue_cast<Node>(context->thisObject());
+ if (node.isNull()) return engine->undefinedValue();
+ return QScriptValue(node.d->type);
+}
+
+QScriptValue Node::parentNode(QScriptContext *context, QScriptEngine *engine)
+{
+ Node node = qscriptvalue_cast<Node>(context->thisObject());
+ if (node.isNull()) return engine->undefinedValue();
+
+ if (node.d->parent) return Node::create(engine, node.d->parent);
+ else return engine->nullValue();
+}
+
+QScriptValue Node::childNodes(QScriptContext *context, QScriptEngine *engine)
+{
+ Node node = qscriptvalue_cast<Node>(context->thisObject());
+ if (node.isNull()) return engine->undefinedValue();
+
+ return NodeList::create(engine, node.d);
+}
+
+QScriptValue Node::firstChild(QScriptContext *context, QScriptEngine *engine)
+{
+ Node node = qscriptvalue_cast<Node>(context->thisObject());
+ if (node.isNull()) return engine->undefinedValue();
+
+ if (node.d->children.isEmpty()) return engine->nullValue();
+ else return Node::create(engine, node.d->children.first());
+}
+
+QScriptValue Node::lastChild(QScriptContext *context, QScriptEngine *engine)
+{
+ Node node = qscriptvalue_cast<Node>(context->thisObject());
+ if (node.isNull()) return engine->undefinedValue();
+
+ if (node.d->children.isEmpty()) return engine->nullValue();
+ else return Node::create(engine, node.d->children.last());
+}
+
+QScriptValue Node::previousSibling(QScriptContext *context, QScriptEngine *engine)
+{
+ Node node = qscriptvalue_cast<Node>(context->thisObject());
+ if (node.isNull()) return engine->undefinedValue();
+
+ if (!node.d->parent) return engine->nullValue();
+
+ for (int ii = 0; ii < node.d->parent->children.count(); ++ii) {
+ if (node.d->parent->children.at(ii) == node.d) {
+ if (ii == 0) return engine->nullValue();
+ else return Node::create(engine, node.d->parent->children.at(ii - 1));
+ }
+ }
+
+ return engine->nullValue();
+}
+
+QScriptValue Node::nextSibling(QScriptContext *context, QScriptEngine *engine)
+{
+ Node node = qscriptvalue_cast<Node>(context->thisObject());
+ if (node.isNull()) return engine->undefinedValue();
+
+ if (!node.d->parent) return engine->nullValue();
+
+ for (int ii = 0; ii < node.d->parent->children.count(); ++ii) {
+ if (node.d->parent->children.at(ii) == node.d) {
+ if ((ii + 1) == node.d->parent->children.count()) return engine->nullValue();
+ else return Node::create(engine, node.d->parent->children.at(ii + 1));
+ }
+ }
+
+ return engine->nullValue();
+}
+
+QScriptValue Node::attributes(QScriptContext *context, QScriptEngine *engine)
+{
+ Node node = qscriptvalue_cast<Node>(context->thisObject());
+ if (node.isNull()) return engine->undefinedValue();
+
+ if (node.d->type != NodeImpl::Element)
+ return engine->nullValue();
+ else
+ return NamedNodeMap::create(engine, node.d, &node.d->attributes);
+}
+
+QScriptValue Node::prototype(QScriptEngine *engine)
+{
+ QScriptValue proto = engine->newObject();
+
+ proto.setProperty(QLatin1String("nodeName"), engine->newFunction(nodeName), QScriptValue::ReadOnly | QScriptValue::PropertyGetter);
+ proto.setProperty(QLatin1String("nodeValue"), engine->newFunction(nodeValue), QScriptValue::ReadOnly | QScriptValue::PropertyGetter | QScriptValue::PropertySetter);
+ proto.setProperty(QLatin1String("nodeType"), engine->newFunction(nodeType), QScriptValue::ReadOnly | QScriptValue::PropertyGetter);
+ proto.setProperty(QLatin1String("parentNode"), engine->newFunction(parentNode), QScriptValue::ReadOnly | QScriptValue::PropertyGetter);
+ proto.setProperty(QLatin1String("childNodes"), engine->newFunction(childNodes), QScriptValue::ReadOnly | QScriptValue::PropertyGetter);
+ proto.setProperty(QLatin1String("firstChild"), engine->newFunction(firstChild), QScriptValue::ReadOnly | QScriptValue::PropertyGetter);
+ proto.setProperty(QLatin1String("lastChild"), engine->newFunction(lastChild), QScriptValue::ReadOnly | QScriptValue::PropertyGetter);
+ proto.setProperty(QLatin1String("previousSibling"), engine->newFunction(previousSibling), QScriptValue::ReadOnly | QScriptValue::PropertyGetter);
+ proto.setProperty(QLatin1String("nextSibling"), engine->newFunction(nextSibling), QScriptValue::ReadOnly | QScriptValue::PropertyGetter);
+ proto.setProperty(QLatin1String("attributes"), engine->newFunction(attributes), QScriptValue::ReadOnly | QScriptValue::PropertyGetter);
+
+ return proto;
+}
+
+QScriptValue Node::create(QScriptEngine *engine, NodeImpl *data)
+{
+ QScriptValue instance = engine->newObject();
+
+ switch (data->type) {
+ case NodeImpl::Attr:
+ case NodeImpl::Comment:
+ case NodeImpl::Document:
+ case NodeImpl::DocumentFragment:
+ case NodeImpl::DocumentType:
+ case NodeImpl::Entity:
+ case NodeImpl::EntityReference:
+ case NodeImpl::Notation:
+ case NodeImpl::CDATA:
+ instance.setPrototype(CDATA::prototype(engine));
+ break;
+ case NodeImpl::ProcessingInstruction:
+ instance.setPrototype(Node::prototype(engine));
+ break;
+ case NodeImpl::Text:
+ instance.setPrototype(Text::prototype(engine));
+ break;
+ case NodeImpl::Element:
+ instance.setPrototype(Element::prototype(engine));
+ break;
+ }
+
+ Node node;
+ node.d = data;
+ if (data) A(data);
+
+ return engine->newVariant(instance, qVariantFromValue(node));
+}
+
+QScriptValue Element::prototype(QScriptEngine *engine)
+{
+ QScriptValue proto = engine->newObject();
+ proto.setPrototype(Node::prototype(engine));
+
+ proto.setProperty(QLatin1String("tagName"), engine->newFunction(nodeName), QScriptValue::ReadOnly | QScriptValue::PropertyGetter);
+
+ return proto;
+}
+
+QScriptValue CharacterData::length(QScriptContext *context, QScriptEngine *engine)
+{
+ Node node = qscriptvalue_cast<Node>(context->thisObject());
+ if (node.isNull()) return engine->undefinedValue();
+
+ return QScriptValue(node.d->data.length());
+}
+
+QScriptValue CharacterData::prototype(QScriptEngine *engine)
+{
+ QScriptValue proto = engine->newObject();
+ proto.setPrototype(Node::prototype(engine));
+
+ proto.setProperty(QLatin1String("data"), engine->newFunction(nodeValue), QScriptValue::ReadOnly | QScriptValue::PropertyGetter | QScriptValue::PropertySetter);
+ proto.setProperty(QLatin1String("length"), engine->newFunction(length), QScriptValue::ReadOnly | QScriptValue::PropertyGetter);
+
+ return proto;
+}
+
+QScriptValue Text::isElementContentWhitespace(QScriptContext *context, QScriptEngine *engine)
+{
+ Node node = qscriptvalue_cast<Node>(context->thisObject());
+ if (node.isNull()) return engine->undefinedValue();
+
+ // ### implement
+ return QScriptValue(false);
+}
+
+QScriptValue Text::wholeText(QScriptContext *context, QScriptEngine *engine)
+{
+ Node node = qscriptvalue_cast<Node>(context->thisObject());
+ if (node.isNull()) return engine->undefinedValue();
+
+ // ### implement
+ return QScriptValue(QString());
+}
+
+QScriptValue Text::prototype(QScriptEngine *engine)
+{
+ QScriptValue proto = engine->newObject();
+ proto.setPrototype(CharacterData::prototype(engine));
+
+ proto.setProperty(QLatin1String("isElementContentWhitespace"), engine->newFunction(isElementContentWhitespace), QScriptValue::ReadOnly | QScriptValue::PropertyGetter);
+ proto.setProperty(QLatin1String("wholeText"), engine->newFunction(wholeText), QScriptValue::ReadOnly | QScriptValue::PropertyGetter);
+
+ return proto;
+}
+
+QScriptValue CDATA::prototype(QScriptEngine *engine)
+{
+ QScriptValue proto = engine->newObject();
+ proto.setPrototype(Text::prototype(engine));
+ return proto;
+}
+
+QScriptValue Document::prototype(QScriptEngine *engine)
+{
+ QScriptValue proto = engine->newObject();
+ proto.setPrototype(Node::prototype(engine));
+
+ proto.setProperty(QLatin1String("xmlVersion"), engine->newFunction(xmlVersion), QScriptValue::ReadOnly | QScriptValue::PropertyGetter | QScriptValue::PropertySetter);
+ proto.setProperty(QLatin1String("xmlEncoding"), engine->newFunction(xmlEncoding), QScriptValue::ReadOnly | QScriptValue::PropertyGetter | QScriptValue::PropertySetter);
+ proto.setProperty(QLatin1String("xmlStandalone"), engine->newFunction(xmlStandalone), QScriptValue::ReadOnly | QScriptValue::PropertyGetter | QScriptValue::PropertySetter);
+ proto.setProperty(QLatin1String("documentElement"), engine->newFunction(documentElement), QScriptValue::ReadOnly | QScriptValue::PropertyGetter);
+
+ return proto;
+}
+
+QScriptValue Document::load(QScriptEngine *engine, const QString &data)
+{
+ Q_ASSERT(engine);
+
+ DocumentImpl *document = 0;
+ QStack<NodeImpl *> nodeStack;
+
+ QXmlStreamReader reader(data);
+
+ while (!reader.atEnd()) {
+ switch (reader.readNext()) {
+ case QXmlStreamReader::NoToken:
+ break;
+ case QXmlStreamReader::Invalid:
+ break;
+ case QXmlStreamReader::StartDocument:
+ Q_ASSERT(!document);
+ document = new DocumentImpl;
+ document->version = reader.documentVersion().toString();
+ document->encoding = reader.documentEncoding().toString();
+ document->isStandalone = reader.isStandaloneDocument();
+ break;
+ case QXmlStreamReader::EndDocument:
+ break;
+ case QXmlStreamReader::StartElement:
+ {
+ Q_ASSERT(document);
+ NodeImpl *node = new NodeImpl;
+ node->namespaceUri = reader.namespaceUri().toString();
+ node->name = reader.name().toString();
+ if (nodeStack.isEmpty()) {
+ document->root = node;
+ } else {
+ node->parent = nodeStack.top();
+ A(node->parent);
+ node->parent->children.append(node);
+ }
+ nodeStack.append(node);
+
+ foreach (const QXmlStreamAttribute &a, reader.attributes()) {
+ NodeImpl *attr = new NodeImpl;
+ attr->type = NodeImpl::Attr;
+ attr->namespaceUri = a.namespaceUri().toString();
+ attr->name = a.name().toString();
+ attr->data = a.value().toString();
+ node->attributes.append(attr);
+ }
+ }
+ break;
+ case QXmlStreamReader::EndElement:
+ nodeStack.pop();
+ break;
+ case QXmlStreamReader::Characters:
+ {
+ NodeImpl *node = new NodeImpl;
+ node->type = reader.isCDATA()?NodeImpl::CDATA:NodeImpl::Text;
+ node->parent = nodeStack.top();
+ A(node->parent);
+ node->parent->children.append(node);
+ node->data = reader.text().toString();
+ }
+ break;
+ case QXmlStreamReader::Comment:
+ break;
+ case QXmlStreamReader::DTD:
+ break;
+ case QXmlStreamReader::EntityReference:
+ break;
+ case QXmlStreamReader::ProcessingInstruction:
+ break;
+ }
+ }
+
+ if (!document || reader.hasError()) {
+ if (document) D(document);
+ return engine->nullValue();
+ }
+
+ QScriptValue instance = engine->newObject();
+ instance.setPrototype(Document::prototype(engine));
+ return engine->newVariant(instance, qVariantFromValue(Document(document)));
+}
+
+Node::Node()
+: d(0)
+{
+}
+
+Node::Node(const Node &o)
+: d(o.d)
+{
+ if (d) A(d);
+}
+
+Node &Node::operator=(const Node &o)
+{
+ if (o.d) A(o.d);
+ if (d) D(d);
+ d = o.d;
+ return *this;
+}
+
+Node::~Node()
+{
+ if (d) D(d);
+}
+
+bool Node::isNull() const
+{
+ return d == 0;
+}
+
+QScriptValue NamedNodeMap::length(QScriptContext *context, QScriptEngine *engine)
+{
+ NamedNodeMap map = qscriptvalue_cast<NamedNodeMap>(context->thisObject().data());
+ if (map.isNull()) return engine->undefinedValue();
+
+ return QScriptValue(map.list->count());
+}
+
+QScriptValue NamedNodeMap::prototype(QScriptEngine *engine)
+{
+ QScriptValue proto = engine->newObject();
+
+ proto.setProperty(QLatin1String("length"), engine->newFunction(length), QScriptValue::ReadOnly | QScriptValue::PropertyGetter);
+
+ return proto;
+}
+
+QScriptValue NamedNodeMap::create(QScriptEngine *engine, NodeImpl *data, QList<NodeImpl *> *list)
+{
+ QScriptValue instance = engine->newObject();
+ instance.setPrototype(NamedNodeMap::prototype(engine));
+
+ NamedNodeMap map;
+ map.d = data;
+ map.list = list;
+ if (data) A(data);
+
+ instance.setData(engine->newVariant(qVariantFromValue(map)));
+
+ if (!QmlEnginePrivate::get(engine)->namedNodeMapClass)
+ QmlEnginePrivate::get(engine)->namedNodeMapClass= new NamedNodeMapClass(engine);
+
+ instance.setScriptClass(QmlEnginePrivate::get(engine)->namedNodeMapClass);
+
+ return instance;
+}
+
+NamedNodeMap::NamedNodeMap()
+: d(0), list(0)
+{
+}
+
+NamedNodeMap::NamedNodeMap(const NamedNodeMap &o)
+: d(o.d), list(o.list)
+{
+ if (d) A(d);
+}
+
+NamedNodeMap &NamedNodeMap::operator=(const NamedNodeMap &o)
+{
+ if (o.d) A(o.d);
+ if (d) D(d);
+ d = o.d;
+ list = o.list;
+ return *this;
+}
+
+NamedNodeMap::~NamedNodeMap()
+{
+ if (d) D(d);
+}
+
+bool NamedNodeMap::isNull()
+{
+ return d == 0;
+}
+
+QScriptValue NodeList::item(QScriptContext *context, QScriptEngine *engine)
+{
+ NodeList list = qscriptvalue_cast<NodeList>(context->thisObject().data());
+ if (list.isNull() || context->argumentCount() != 1)
+ return engine->undefinedValue();
+
+ qint32 index = context->argument(0).toInt32();
+
+ if (index >= list.d->children.count())
+ return engine->undefinedValue(); // ### Exception
+ else
+ return Node::create(engine, list.d->children.at(index));
+}
+
+QScriptValue NodeList::length(QScriptContext *context, QScriptEngine *engine)
+{
+ NodeList list = qscriptvalue_cast<NodeList>(context->thisObject().data());
+ if (list.isNull()) return engine->undefinedValue();
+
+ return QScriptValue(list.d->children.count());
+}
+
+QScriptValue NodeList::prototype(QScriptEngine *engine)
+{
+ QScriptValue proto = engine->newObject();
+
+ proto.setProperty(QLatin1String("length"), engine->newFunction(length), QScriptValue::ReadOnly | QScriptValue::PropertyGetter);
+ proto.setProperty(QLatin1String("item"), engine->newFunction(item, 1), QScriptValue::ReadOnly);
+
+ return proto;
+}
+
+QScriptValue NodeList::create(QScriptEngine *engine, NodeImpl *data)
+{
+ QScriptValue instance = engine->newObject();
+ instance.setPrototype(NodeList::prototype(engine));
+
+ NodeList list;
+ list.d = data;
+ if (data) A(data);
+
+ instance.setData(engine->newVariant(qVariantFromValue(list)));
+
+ if (!QmlEnginePrivate::get(engine)->nodeListClass)
+ QmlEnginePrivate::get(engine)->nodeListClass= new NodeListClass(engine);
+
+ instance.setScriptClass(QmlEnginePrivate::get(engine)->nodeListClass);
+
+ return instance;
+}
+
+NodeList::NodeList()
+: d(0)
+{
+}
+
+NodeList::NodeList(const NodeList &o)
+: d(o.d)
+{
+ if (d) A(d);
+}
+
+NodeList &NodeList::operator=(const NodeList &o)
+{
+ if (o.d) A(o.d);
+ if (d) D(d);
+ d = o.d;
+ return *this;
+}
+
+NodeList::~NodeList()
+{
+ if (d) D(d);
+}
+
+bool NodeList::isNull()
+{
+ return d == 0;
+}
+
+NamedNodeMapClass::QueryFlags NamedNodeMapClass::queryProperty(const QScriptValue &object, const QScriptString &name, QueryFlags flags, uint *id)
+{
+ if (!(flags & HandlesReadAccess))
+ return 0;
+
+ bool ok = false;
+ uint index = name.toString().toUInt(&ok);
+ if (!ok)
+ return 0;
+
+ NamedNodeMap map = qscriptvalue_cast<NamedNodeMap>(object.data());
+ if (map.isNull() || (uint)map.list->count() <= index)
+ return 0; // ### I think we're meant to raise an exception
+
+ *id = index;
+ return HandlesReadAccess;
+}
+
+QScriptValue NamedNodeMapClass::property(const QScriptValue &object, const QScriptString &, uint id)
+{
+ NamedNodeMap map = qscriptvalue_cast<NamedNodeMap>(object.data());
+ return Node::create(engine(), map.list->at(id));
+}
+
+NodeListClass::QueryFlags NodeListClass::queryProperty(const QScriptValue &object, const QScriptString &name, QueryFlags flags, uint *id)
+{
+ if (!(flags & HandlesReadAccess))
+ return 0;
+
+ bool ok = false;
+ uint index = name.toString().toUInt(&ok);
+ if (!ok)
+ return 0;
+
+ NodeList list = qscriptvalue_cast<NodeList>(object.data());
+ if (list.isNull() || (uint)list.d->children.count() <= index)
+ return 0; // ### I think we're meant to raise an exception
+
+ *id = index;
+ return HandlesReadAccess;
+}
+
+QScriptValue NodeListClass::property(const QScriptValue &object, const QScriptString &, uint id)
+{
+ NodeList list = qscriptvalue_cast<NodeList>(object.data());
+ return Node::create(engine(), list.d->children.at(id));
+}
+
+Document::Document()
+: d(0)
+{
+}
+
+Document::Document(DocumentImpl *data)
+: d(data)
+{
+}
+
+Document::Document(const Document &o)
+: Node(o), d(o.d)
+{
+ if (d) A(d);
+}
+
+Document &Document::operator=(const Document &o)
+{
+ if (o.d) A(o.d);
+ if (d) D(d);
+ d = o.d;
+ return *this;
+}
+
+Document::~Document()
+{
+ if (d) D(d);
+}
+
+bool Document::isNull() const
+{
+ return d == 0;
+}
+
+QScriptValue Document::documentElement(QScriptContext *context, QScriptEngine *engine)
+{
+ Document document = qscriptvalue_cast<Document>(context->thisObject());
+ if (document.isNull()) return engine->undefinedValue();
+
+ if (!document.d->root) return engine->nullValue();
+
+ return Node::create(engine, document.d->root);
+}
+
+QScriptValue Document::xmlStandalone(QScriptContext *context, QScriptEngine *engine)
+{
+ Document document = qscriptvalue_cast<Document>(context->thisObject());
+ if (document.isNull()) return engine->undefinedValue();
+
+ if (context->argumentCount())
+ document.d->isStandalone = context->argument(0).toBool();
+
+ return QScriptValue(document.d->isStandalone);
+}
+
+QScriptValue Document::xmlVersion(QScriptContext *context, QScriptEngine *engine)
+{
+ Document document = qscriptvalue_cast<Document>(context->thisObject());
+ if (document.isNull()) return engine->undefinedValue();
+
+ if (context->argumentCount())
+ document.d->version = context->argument(0).toString();
+
+ return QScriptValue(document.d->version);
+}
+
+QScriptValue Document::xmlEncoding(QScriptContext *context, QScriptEngine *engine)
+{
+ Document document = qscriptvalue_cast<Document>(context->thisObject());
+ if (document.isNull()) return engine->undefinedValue();
+
+ if (context->argumentCount())
+ document.d->encoding = context->argument(0).toString();
+
+ return QScriptValue(document.d->encoding);
+}
+
class QmlXMLHttpRequest : public QObject
{
Q_OBJECT
@@ -311,8 +1149,13 @@ static QScriptValue qmlxmlhttprequest_open(QScriptContext *context, QScriptEngin
// Argument 1 - URL
QUrl url(context->argument(1).toString()); // ### Need to resolve correctly
- if (url.isRelative()) // ### Fix me
- return context->throwError(QScriptContext::SyntaxError, "Relative URLs not supported");
+ if (url.isRelative()) {
+ QmlContext *ctxt = QmlEnginePrivate::get(engine)->currentExpression?QmlEnginePrivate::get(engine)->currentExpression->context():0;
+ if (ctxt)
+ url = ctxt->resolvedUrl(url);
+ else
+ return context->throwError(QScriptContext::SyntaxError, "Relative URLs not supported");
+ }
// Argument 2 - async (optional)
if (context->argumentCount() > 2 && !context->argument(2).toBoolean())
@@ -480,6 +1323,18 @@ static QScriptValue qmlxmlhttprequest_responseText(QScriptContext *context, QScr
return QScriptValue(request->responseBody());
}
+static QScriptValue qmlxmlhttprequest_responseXML(QScriptContext *context, QScriptEngine *engine)
+{
+ QmlXMLHttpRequest *request = qobject_cast<QmlXMLHttpRequest *>(context->thisObject().data().toQObject());
+ if (!request) return context->throwError(QScriptContext::ReferenceError, QLatin1String("Not an XMLHttpRequest object"));
+
+ if (request->readyState() != QmlXMLHttpRequest::Loading &&
+ request->readyState() != QmlXMLHttpRequest::Done)
+ return engine->nullValue();
+ else
+ return Document::load(engine, request->responseBody());
+}
+
static QScriptValue qmlxmlhttprequest_onreadystatechange(QScriptContext *context, QScriptEngine *engine)
{
QmlXMLHttpRequest *request = qobject_cast<QmlXMLHttpRequest *>(context->thisObject().data().toQObject());
@@ -494,23 +1349,16 @@ static QScriptValue qmlxmlhttprequest_onreadystatechange(QScriptContext *context
// Constructor
static QScriptValue qmlxmlhttprequest_new(QScriptContext *context, QScriptEngine *engine)
{
- QScriptValue rv = engine->newObject();
- rv.setPrototype(context->callee().data());
- rv.setData(engine->newQObject(new QmlXMLHttpRequest(QmlEnginePrivate::getEngine(engine)), QScriptEngine::ScriptOwnership));
- return rv;
+ if (context->isCalledAsConstructor()) {
+ context->thisObject().setData(engine->newQObject(new QmlXMLHttpRequest(QmlEnginePrivate::getEngine(engine)), QScriptEngine::ScriptOwnership));
+ }
+ return engine->undefinedValue();
}
void qt_add_qmlxmlhttprequest(QScriptEngine *engine)
{
QScriptValue prototype = engine->newObject();
- // Constants
- prototype.setProperty(QLatin1String("UNSENT"), 0, QScriptValue::ReadOnly | QScriptValue::Undeletable | QScriptValue::SkipInEnumeration);
- prototype.setProperty(QLatin1String("OPENED"), 1, QScriptValue::ReadOnly | QScriptValue::Undeletable | QScriptValue::SkipInEnumeration);
- prototype.setProperty(QLatin1String("HEADERS_RECEIVED"), 2, QScriptValue::ReadOnly | QScriptValue::Undeletable | QScriptValue::SkipInEnumeration);
- prototype.setProperty(QLatin1String("LOADING"), 3, QScriptValue::ReadOnly | QScriptValue::Undeletable | QScriptValue::SkipInEnumeration);
- prototype.setProperty(QLatin1String("DONE"), 4, QScriptValue::ReadOnly | QScriptValue::Undeletable | QScriptValue::SkipInEnumeration);
-
// Methods
prototype.setProperty(QLatin1String("open"), engine->newFunction(qmlxmlhttprequest_open, 2));
prototype.setProperty(QLatin1String("setRequestHeader"), engine->newFunction(qmlxmlhttprequest_setRequestHeader, 2));
@@ -524,11 +1372,16 @@ void qt_add_qmlxmlhttprequest(QScriptEngine *engine)
prototype.setProperty(QLatin1String("status"), engine->newFunction(qmlxmlhttprequest_status), QScriptValue::ReadOnly | QScriptValue::PropertyGetter);
prototype.setProperty(QLatin1String("statusText"), engine->newFunction(qmlxmlhttprequest_statusText), QScriptValue::ReadOnly | QScriptValue::PropertyGetter);
prototype.setProperty(QLatin1String("responseText"), engine->newFunction(qmlxmlhttprequest_responseText), QScriptValue::ReadOnly | QScriptValue::PropertyGetter);
+ prototype.setProperty(QLatin1String("responseXML"), engine->newFunction(qmlxmlhttprequest_responseXML), QScriptValue::ReadOnly | QScriptValue::PropertyGetter);
prototype.setProperty(QLatin1String("onreadystatechange"), engine->newFunction(qmlxmlhttprequest_onreadystatechange), QScriptValue::PropertyGetter | QScriptValue::PropertySetter);
// Constructor
- QScriptValue constructor = engine->newFunction(qmlxmlhttprequest_new);
- constructor.setData(prototype);
+ QScriptValue constructor = engine->newFunction(qmlxmlhttprequest_new, prototype);
+ constructor.setProperty(QLatin1String("UNSENT"), 0, QScriptValue::ReadOnly | QScriptValue::Undeletable | QScriptValue::SkipInEnumeration);
+ constructor.setProperty(QLatin1String("OPENED"), 1, QScriptValue::ReadOnly | QScriptValue::Undeletable | QScriptValue::SkipInEnumeration);
+ constructor.setProperty(QLatin1String("HEADERS_RECEIVED"), 2, QScriptValue::ReadOnly | QScriptValue::Undeletable | QScriptValue::SkipInEnumeration);
+ constructor.setProperty(QLatin1String("LOADING"), 3, QScriptValue::ReadOnly | QScriptValue::Undeletable | QScriptValue::SkipInEnumeration);
+ constructor.setProperty(QLatin1String("DONE"), 4, QScriptValue::ReadOnly | QScriptValue::Undeletable | QScriptValue::SkipInEnumeration);
engine->globalObject().setProperty(QLatin1String("XMLHttpRequest"), constructor);
}