diff options
author | Aaron Kennedy <aaron.kennedy@nokia.com> | 2009-09-01 03:38:08 (GMT) |
---|---|---|
committer | Aaron Kennedy <aaron.kennedy@nokia.com> | 2009-09-01 03:38:08 (GMT) |
commit | 49e4975e96ac9e2e8e6af1c58d3ed1453a130eb4 (patch) | |
tree | 30595ddf8401cdde3f0c7fdfb233e8ddcb600e70 | |
parent | 671c3ac47a258a876352a4c4d38937e0fb7034a7 (diff) | |
download | Qt-49e4975e96ac9e2e8e6af1c58d3ed1453a130eb4.zip Qt-49e4975e96ac9e2e8e6af1c58d3ed1453a130eb4.tar.gz Qt-49e4975e96ac9e2e8e6af1c58d3ed1453a130eb4.tar.bz2 |
Implement more of XMLHttpRequest
-rw-r--r-- | examples/declarative/xmlhttprequest/test.qml | 26 | ||||
-rw-r--r-- | examples/declarative/xmlhttprequest/test.xml | 5 | ||||
-rw-r--r-- | src/declarative/qml/qmlengine.cpp | 8 | ||||
-rw-r--r-- | src/declarative/qml/qmlengine_p.h | 7 | ||||
-rw-r--r-- | src/declarative/qml/qmlxmlhttprequest.cpp | 883 |
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); } |