aboutsummaryrefslogtreecommitdiffstats
path: root/src/qml
diff options
context:
space:
mode:
authorMaximilian Goldstein <max.goldstein@qt.io>2020-04-09 13:34:01 +0200
committerMaximilian Goldstein <max.goldstein@qt.io>2020-05-06 10:45:48 +0200
commita714a3a446a47b3ac18de6cea1e6c4ca01535170 (patch)
tree2569eb6ec42f4b537bc18477b88d9a718f444012 /src/qml
parent22f9e5fb1ed643f284f50b9417bdbafdfb20566b (diff)
Implement URLSearchParams
Implements URLSearchParams (https://url.spec.whatwg.org/#urlsearchparams), completing our implementation of the URL object. Still needs the for..of iterator to get implemented. Change-Id: Iad33ed2f3fe0b2598ca2b0b21a4743f5f7dc19fd Reviewed-by: Ulf Hermann <ulf.hermann@qt.io>
Diffstat (limited to 'src/qml')
-rw-r--r--src/qml/jsruntime/qv4engine.cpp9
-rw-r--r--src/qml/jsruntime/qv4engine_p.h8
-rw-r--r--src/qml/jsruntime/qv4global_p.h1
-rw-r--r--src/qml/jsruntime/qv4managed.cpp3
-rw-r--r--src/qml/jsruntime/qv4managed_p.h1
-rw-r--r--src/qml/jsruntime/qv4urlobject.cpp760
-rw-r--r--src/qml/jsruntime/qv4urlobject_p.h103
7 files changed, 885 insertions, 0 deletions
diff --git a/src/qml/jsruntime/qv4engine.cpp b/src/qml/jsruntime/qv4engine.cpp
index fec1524667..6a583bf395 100644
--- a/src/qml/jsruntime/qv4engine.cpp
+++ b/src/qml/jsruntime/qv4engine.cpp
@@ -657,6 +657,8 @@ ExecutionEngine::ExecutionEngine(QJSEngine *jsEngine)
jsObjects[Url_Ctor] = memoryManager->allocate<UrlCtor>(global);
jsObjects[UrlProto] = memoryManager->allocate<UrlPrototype>();
+ jsObjects[UrlSearchParams_Ctor] = memoryManager->allocate<UrlSearchParamsCtor>(global);
+ jsObjects[UrlSearchParamsProto] = memoryManager->allocate<UrlSearchParamsPrototype>();
str = newString(QStringLiteral("get [Symbol.species]"));
jsObjects[GetSymbolSpecies] = FunctionObject::createBuiltinFunction(this, str, ArrayPrototype::method_get_species, 0);
@@ -680,6 +682,7 @@ ExecutionEngine::ExecutionEngine(QJSEngine *jsEngine)
static_cast<TypeErrorPrototype *>(typeErrorPrototype())->init(this, typeErrorCtor());
static_cast<URIErrorPrototype *>(uRIErrorPrototype())->init(this, uRIErrorCtor());
static_cast<UrlPrototype *>(urlPrototype())->init(this, urlCtor());
+ static_cast<UrlSearchParamsPrototype *>(urlSearchParamsPrototype())->init(this, urlSearchParamsCtor());
static_cast<IteratorPrototype *>(iteratorPrototype())->init(this);
static_cast<ForInIteratorPrototype *>(forInIteratorPrototype())->init(this);
@@ -770,6 +773,7 @@ ExecutionEngine::ExecutionEngine(QJSEngine *jsEngine)
globalObject->defineDefaultProperty(QStringLiteral("URIError"), *uRIErrorCtor());
globalObject->defineDefaultProperty(QStringLiteral("Promise"), *promiseCtor());
globalObject->defineDefaultProperty(QStringLiteral("URL"), *urlCtor());
+ globalObject->defineDefaultProperty(QStringLiteral("URLSearchParams"), *urlSearchParamsCtor());
globalObject->defineDefaultProperty(QStringLiteral("SharedArrayBuffer"), *sharedArrayBufferCtor());
globalObject->defineDefaultProperty(QStringLiteral("ArrayBuffer"), *arrayBufferCtor());
@@ -1064,6 +1068,11 @@ Heap::UrlObject *ExecutionEngine::newUrlObject()
return memoryManager->allocate<UrlObject>();
}
+Heap::UrlSearchParamsObject *ExecutionEngine::newUrlSearchParamsObject()
+{
+ return memoryManager->allocate<UrlSearchParamsObject>();
+}
+
Heap::Object *ExecutionEngine::newErrorObject(const Value &value)
{
return ErrorObject::create<ErrorObject>(this, value, errorCtor());
diff --git a/src/qml/jsruntime/qv4engine_p.h b/src/qml/jsruntime/qv4engine_p.h
index ebf2fcd55a..c555730838 100644
--- a/src/qml/jsruntime/qv4engine_p.h
+++ b/src/qml/jsruntime/qv4engine_p.h
@@ -241,6 +241,7 @@ public:
ArrayIteratorProto,
StringIteratorProto,
UrlProto,
+ UrlSearchParamsProto,
Object_Ctor,
String_Ctor,
@@ -269,6 +270,7 @@ public:
Map_Ctor,
IntrinsicTypedArray_Ctor,
Url_Ctor,
+ UrlSearchParams_Ctor,
GetSymbolSpecies,
@@ -313,6 +315,10 @@ public:
{
return reinterpret_cast<FunctionObject *>(jsObjects + Url_Ctor);
}
+ FunctionObject *urlSearchParamsCtor() const
+ {
+ return reinterpret_cast<FunctionObject *>(jsObjects + UrlSearchParams_Ctor);
+ }
FunctionObject *typedArrayCtors;
FunctionObject *getSymbolSpecies() const { return reinterpret_cast<FunctionObject *>(jsObjects + GetSymbolSpecies); }
@@ -361,6 +367,7 @@ public:
Object *arrayIteratorPrototype() const { return reinterpret_cast<Object *>(jsObjects + ArrayIteratorProto); }
Object *stringIteratorPrototype() const { return reinterpret_cast<Object *>(jsObjects + StringIteratorProto); }
Object *urlPrototype() const { return reinterpret_cast<Object *>(jsObjects + UrlProto); }
+ Object *urlSearchParamsPrototype() const { return reinterpret_cast<Object *>(jsObjects + UrlSearchParamsProto); }
EvalFunction *evalFunction() const { return reinterpret_cast<EvalFunction *>(jsObjects + Eval_Function); }
FunctionObject *getStackFunction() const { return reinterpret_cast<FunctionObject *>(jsObjects + GetStack_Function); }
@@ -591,6 +598,7 @@ public:
#endif
Heap::UrlObject *newUrlObject();
+ Heap::UrlSearchParamsObject *newUrlSearchParamsObject();
Heap::Object *newErrorObject(const Value &value);
Heap::Object *newErrorObject(const QString &message);
diff --git a/src/qml/jsruntime/qv4global_p.h b/src/qml/jsruntime/qv4global_p.h
index 7234a3456f..ace070c683 100644
--- a/src/qml/jsruntime/qv4global_p.h
+++ b/src/qml/jsruntime/qv4global_p.h
@@ -142,6 +142,7 @@ namespace Heap {
struct QObjectWrapper;
struct RegExpObject;
struct UrlObject;
+ struct UrlSearchParamsObject;
struct RegExp;
struct EvalFunction;
diff --git a/src/qml/jsruntime/qv4managed.cpp b/src/qml/jsruntime/qv4managed.cpp
index 8a0e5509c4..f090afe649 100644
--- a/src/qml/jsruntime/qv4managed.cpp
+++ b/src/qml/jsruntime/qv4managed.cpp
@@ -108,6 +108,9 @@ QString Managed::className() const
case Type_UrlObject:
s = "URL";
break;
+ case Type_UrlSearchParamsObject:
+ s = "URLSearchParams";
+ break;
case Type_ExecutionContext:
s = "__ExecutionContext";
diff --git a/src/qml/jsruntime/qv4managed_p.h b/src/qml/jsruntime/qv4managed_p.h
index 910eb3a5a1..96c47a9c41 100644
--- a/src/qml/jsruntime/qv4managed_p.h
+++ b/src/qml/jsruntime/qv4managed_p.h
@@ -145,6 +145,7 @@ public:
Type_MathObject,
Type_ProxyObject,
Type_UrlObject,
+ Type_UrlSearchParamsObject,
Type_ExecutionContext,
Type_InternalClass,
diff --git a/src/qml/jsruntime/qv4urlobject.cpp b/src/qml/jsruntime/qv4urlobject.cpp
index 15e827680e..73b1510d2e 100644
--- a/src/qml/jsruntime/qv4urlobject.cpp
+++ b/src/qml/jsruntime/qv4urlobject.cpp
@@ -37,15 +37,24 @@
**
****************************************************************************/
+#include "qv4arrayiterator_p.h"
#include "qv4urlobject_p.h"
+#include "qv4stringobject_p.h"
#include <QtCore/QUrl>
+#include <qv4jscall_p.h>
+#include <qv4objectiterator_p.h>
+
using namespace QV4;
DEFINE_OBJECT_VTABLE(UrlObject);
DEFINE_OBJECT_VTABLE(UrlCtor);
+DEFINE_OBJECT_VTABLE(UrlSearchParamsObject);
+DEFINE_OBJECT_VTABLE(UrlSearchParamsCtor);
+
+
void Heap::UrlCtor::init(QV4::ExecutionContext *scope)
{
Heap::FunctionObject::init(scope, QLatin1String("URL"));
@@ -71,6 +80,7 @@ void UrlPrototype::init(ExecutionEngine *engine, Object *ctor)
defineAccessorProperty(QLatin1String("port"), method_getPort, method_setPort);
defineAccessorProperty(QLatin1String("protocol"), method_getProtocol, method_setProtocol);
defineAccessorProperty(QLatin1String("search"), method_getSearch, method_setSearch);
+ defineAccessorProperty(QLatin1String("searchParams"), method_getSearchParams, nullptr);
defineAccessorProperty(QLatin1String("username"), method_getUsername, method_setUsername);
}
@@ -623,6 +633,21 @@ ReturnedValue UrlPrototype::method_setUsername(const FunctionObject *b, const Va
return Encode::undefined();
}
+ReturnedValue UrlPrototype::method_getSearchParams(const FunctionObject *b, const Value *thisObject,
+ const Value *, int)
+{
+ ExecutionEngine *v4 = b->engine();
+ Scope scope(v4);
+
+ Scoped<UrlObject> r(scope, thisObject->as<UrlObject>());
+
+ Scoped<UrlSearchParamsObject> usp(scope, v4->newUrlSearchParamsObject());
+
+ usp->initializeParams(r->search());
+
+ return usp->asReturnedValue();
+}
+
ReturnedValue UrlCtor::virtualCallAsConstructor(const FunctionObject *that, const Value *argv,
int argc, const Value *newTarget)
{
@@ -687,3 +712,738 @@ ReturnedValue UrlCtor::virtualCallAsConstructor(const FunctionObject *that, cons
return obj->asReturnedValue();
}
+
+
+void Heap::UrlSearchParamsCtor::init(QV4::ExecutionContext *scope)
+{
+ Heap::FunctionObject::init(scope, QLatin1String("URLSearchParams"));
+}
+
+void UrlSearchParamsPrototype::init(ExecutionEngine *engine, Object *ctor)
+{
+ Q_UNUSED(ctor)
+
+ Scope scope(engine);
+ ScopedObject o(scope);
+
+ defineDefaultProperty(QLatin1String("toString"), method_toString);
+ defineDefaultProperty(QLatin1String("sort"), method_sort);
+ defineDefaultProperty(QLatin1String("append"), method_append);
+ defineDefaultProperty(QLatin1String("delete"), method_delete);
+ defineDefaultProperty(QLatin1String("has"), method_has);
+ defineDefaultProperty(QLatin1String("set"), method_set);
+ defineDefaultProperty(QLatin1String("get"), method_get);
+ defineDefaultProperty(QLatin1String("getAll"), method_getAll);
+ defineDefaultProperty(QLatin1String("forEach"), method_forEach);
+ defineDefaultProperty(QLatin1String("entries"), method_entries);
+ defineDefaultProperty(QLatin1String("keys"), method_keys);
+ defineDefaultProperty(QLatin1String("values"), method_values);
+}
+
+ReturnedValue UrlSearchParamsCtor::virtualCallAsConstructor(const FunctionObject *that, const Value *argv,
+ int argc, const Value *newTarget)
+{
+ ExecutionEngine *v4 = that->engine();
+
+ if (argc > 1)
+ return v4->throwError(QLatin1String("Invalid amount of arguments"));
+
+ Scope scope(v4);
+
+ ScopedValue arg(scope, argv[0]);
+ ArrayObject *argArrayObject = arg->as<ArrayObject>();
+ Object *argObject = arg->as<Object>();
+
+ ReturnedValue o = Encode(v4->newUrlSearchParamsObject());
+
+ if (!newTarget)
+ return o;
+
+ ScopedObject obj(scope, o);
+ obj->setProtoFromNewTarget(newTarget);
+
+ UrlSearchParamsObject *urlSearchParamsObject = obj->as<UrlSearchParamsObject>();
+
+ if (argArrayObject != nullptr) {
+ ScopedArrayObject argArray(scope, argArrayObject);
+
+ uint len = argArray->getLength();
+
+ for (uint i = 0; i < len; i++) {
+ QV4::Value pair = argArray->get(i);
+ auto *pairArrayObject = pair.as<ArrayObject>();
+
+ if (pairArrayObject == nullptr) {
+ return v4->throwTypeError(
+ QLatin1String("element %1 is not a pair").arg(QString::number(i)));
+ }
+
+
+ ScopedArrayObject pairArray(scope, pairArrayObject);
+
+
+ uint pairLen = pairArray->getLength();
+
+
+ if (pairLen != 2) {
+ return v4->throwTypeError(QLatin1String("pair %1 has %2 elements instead of 2")
+ .arg(QString::number(i))
+ .arg(QString::number(pairLen)));
+ }
+ }
+
+ urlSearchParamsObject->initializeParams(argArray);
+ } else if (argObject != nullptr) {
+ ScopedObject scopedObject(scope, argObject);
+ urlSearchParamsObject->initializeParams(scopedObject);
+ } else {
+ QString value = argc > 0 ? arg->toQString() : QLatin1String("");
+ urlSearchParamsObject->initializeParams(value);
+ }
+
+ return obj->asReturnedValue();
+}
+
+void UrlSearchParamsObject::initializeParams()
+{
+ auto *arrayObject = engine()->newArrayObject(0);
+ auto *keys = engine()->newArrayObject(0);
+ auto *values = engine()->newArrayObject(0);
+
+ d()->params.set(engine(), arrayObject);
+ d()->keys.set(engine(), keys);
+ d()->values.set(engine(), values);
+}
+
+void UrlSearchParamsObject::initializeParams(QString value)
+{
+ Q_ASSERT(d()->params == nullptr);
+
+ initializeParams();
+
+ if (value.startsWith(QLatin1Char('?')))
+ value = value.mid(1);
+
+ const QStringList params = value.split(QLatin1Char('&'));
+
+ for (const QString& param : params) {
+ if (param.isEmpty())
+ continue;
+
+ QString key, value;
+
+ int equalsIndex = param.indexOf(QLatin1Char('='));
+ if (equalsIndex != -1) {
+ key = param.left(equalsIndex);
+ value = param.mid(equalsIndex+1);
+ } else {
+ key = param;
+ }
+
+ append(engine()->newString(key), engine()->newString(value));
+ }
+}
+
+void UrlSearchParamsObject::initializeParams(ScopedArrayObject& params)
+{
+ Q_ASSERT(d()->params == nullptr);
+
+ Scope scope(engine());
+
+ uint len = params->getLength();
+ auto *keys = engine()->newArrayObject(len);
+ auto *values = engine()->newArrayObject(len);
+
+ ScopedArrayObject scopedKeys(scope, keys);
+ ScopedArrayObject scopedValues(scope, values);
+
+ for (uint i = 0; i < len; i++)
+ {
+ QV4::Value pair = params->get(i);
+ auto *pairArrayObject = pair.as<ArrayObject>();
+
+ QV4::Value key = pairArrayObject->get(uint(0));
+ QV4::Value value = pairArrayObject->get(uint(1));
+
+ scopedKeys->put(i, key);
+ scopedValues->put(i, value);
+ }
+
+
+ d()->params.set(engine(), params->d());
+ d()->keys.set(engine(), keys);
+ d()->values.set(engine(), values);
+}
+
+void UrlSearchParamsObject::initializeParams(ScopedObject& params)
+{
+ Q_ASSERT(d()->params == nullptr);
+
+ initializeParams();
+
+ Scope scope(engine());
+ ObjectIterator it(scope, params, ObjectIterator::EnumerableOnly);
+
+ ScopedValue name(scope);
+ ScopedValue val(scope);
+
+ while (true) {
+ name = it.nextPropertyNameAsString(val);
+ if (name->isNull())
+ break;
+
+ Heap::String *nameStr = name->as<String>()->d();
+ Heap::String *valStr = val->toString(engine());
+
+ append(nameStr, valStr);
+ }
+}
+
+void UrlSearchParamsObject::setParams(QList<QStringList> params)
+{
+ auto *arrayObject = engine()->newArrayObject(0);
+ auto *keys = engine()->newArrayObject(0);
+ auto *values = engine()->newArrayObject(0);
+
+ Scope scope(engine());
+
+ ScopedArrayObject scopedArray(scope, arrayObject);
+
+ ScopedArrayObject scopedKeys(scope, keys);
+ ScopedArrayObject scopedValues(scope, values);
+
+ uint len = 0;
+
+ for (const QStringList& param : params) {
+
+ auto *valuePair = engine()->newArrayObject(2);
+
+ ScopedArrayObject valuePairObject(scope, valuePair);
+
+ ScopedValue key(scope, Value::fromHeapObject(engine()->newString(param[0])));
+ ScopedValue value(scope, Value::fromHeapObject(engine()->newString(param[1])));
+ valuePairObject->put(uint(0), key);
+ valuePairObject->put(uint(1), value);
+
+ scopedKeys->put(len, key);
+ scopedValues->put(len, value);
+
+ scopedArray->put(len, valuePairObject);
+ len++;
+ }
+
+ d()->params.set(engine(), arrayObject);
+ d()->keys.set(engine(), keys);
+ d()->values.set(engine(), values);
+}
+
+void UrlSearchParamsObject::append(Heap::String *name, Heap::String *value)
+{
+ Scope scope(engine());
+
+ ScopedArrayObject scopedArray(scope, d()->params);
+ ScopedArrayObject scopedKeys(scope, d()->keys);
+ ScopedArrayObject scopedValues(scope, d()->values);
+
+ auto *valuePair = engine()->newArrayObject(2);
+
+ ScopedArrayObject valuePairObject(scope, valuePair);
+
+ ScopedValue keyScoped(scope, Value::fromHeapObject(name));
+ ScopedValue valueScoped(scope, Value::fromHeapObject(value));
+ valuePairObject->put(uint(0), keyScoped);
+ valuePairObject->put(uint(1), valueScoped);
+
+ uint len = scopedArray->getLength();
+
+ scopedKeys->put(len, keyScoped);
+ scopedValues->put(len, valueScoped);
+
+ scopedArray->put(len, valuePairObject);
+}
+
+QList<QStringList> UrlSearchParamsObject::params() const
+{
+ auto *arrayObject = d()->params.get();
+ Scope scope(engine());
+ ScopedArrayObject scopedArray(scope, arrayObject);
+
+ QList<QStringList> result;
+
+ uint len = scopedArray->getLength();
+
+ for (uint i = 0; i < len; i++) {
+ QV4::Value pair = scopedArray->get(i);
+ auto *pairArrayObject = pair.as<ArrayObject>();
+
+ QV4::Value key = pairArrayObject->get(uint(0));
+ QV4::Value value = pairArrayObject->get(uint(1));
+
+ result << QStringList { key.toQString(), value.toQString() };
+ }
+
+ return result;
+}
+
+int UrlSearchParamsObject::length() const
+{
+ auto *arrayObject = d()->params.get();
+ Scope scope(engine());
+ ScopedArrayObject scopedArray(scope, arrayObject);
+
+ return scopedArray->getLength();
+}
+
+int UrlSearchParamsObject::indexOf(QString name, int last) const
+{
+ auto *arrayObject = d()->params.get();
+ Scope scope(engine());
+ ScopedArrayObject scopedArray(scope, arrayObject);
+
+ int len = scopedArray->getLength();
+
+ for (int i = last + 1; i < len; i++) {
+ QV4::Value pair = scopedArray->get(i);
+ auto *pairArrayObject = pair.as<ArrayObject>();
+
+ QV4::Value key = pairArrayObject->get(uint(0));
+
+ if (key.toQString() == name)
+ return i;
+ }
+
+ return -1;
+}
+
+QString UrlSearchParamsObject::stringAt(int index, int pairIndex) const
+{
+ auto *arrayObject = d()->params.get();
+ Scope scope(engine());
+ ScopedArrayObject scopedArray(scope, arrayObject);
+
+ if (index >= scopedArray->getLength())
+ return {};
+
+ QV4::Value pair = scopedArray->get(index);
+ auto *pairArrayObject = pair.as<ArrayObject>();
+
+ QV4::Value value = pairArrayObject->get(pairIndex);
+
+ return value.toQString();
+}
+
+QV4::Heap::String * UrlSearchParamsObject::stringAtRaw(int index, int pairIndex) const
+{
+ auto *arrayObject = d()->params.get();
+ Scope scope(engine());
+ ScopedArrayObject scopedArray(scope, arrayObject);
+
+ if (index >= scopedArray->getLength())
+ return nullptr;
+
+ QV4::Value pair = scopedArray->get(index);
+ auto *pairArrayObject = pair.as<ArrayObject>();
+
+ QV4::Value value = pairArrayObject->get(pairIndex);
+
+ return value.as<String>()->d();
+}
+
+QString UrlSearchParamsObject::nameAt(int index) const
+{
+ return stringAt(index, 0);
+}
+
+QV4::Heap::String * UrlSearchParamsObject::nameAtRaw(int index) const
+{
+ return stringAtRaw(index, 0);
+}
+
+
+QString UrlSearchParamsObject::valueAt(int index) const
+{
+ return stringAt(index, 1);
+}
+
+QV4::Heap::String * UrlSearchParamsObject::valueAtRaw(int index) const
+{
+ return stringAtRaw(index, 1);
+}
+
+
+struct UrlSearchParamsObjectOwnPropertyKeyIterator : ObjectOwnPropertyKeyIterator
+{
+ ~UrlSearchParamsObjectOwnPropertyKeyIterator() override = default;
+ PropertyKey next(const QV4::Object *o, Property *pd = nullptr,
+ PropertyAttributes *attrs = nullptr) override;
+};
+
+PropertyKey UrlSearchParamsObjectOwnPropertyKeyIterator::next(const QV4::Object *o, Property *pd,
+ PropertyAttributes *attrs)
+{
+ const UrlSearchParamsObject *usp = static_cast<const UrlSearchParamsObject *>(o);
+
+ Scope scope(usp);
+
+ uint len = usp->length();
+ if (arrayIndex < len) {
+ uint index = arrayIndex;
+ ++arrayIndex;
+ if (attrs)
+ *attrs = Attr_NotConfigurable | Attr_NotWritable;
+ if (pd)
+ pd->value = usp->engine()->newString(usp->nameAt(index));
+ return PropertyKey::fromArrayIndex(index);
+ }
+
+ return ObjectOwnPropertyKeyIterator::next(o, pd, attrs);
+}
+
+OwnPropertyKeyIterator *UrlSearchParamsObject::virtualOwnPropertyKeys(const Object *m,
+ Value *target)
+{
+ *target = *m;
+ return new UrlSearchParamsObjectOwnPropertyKeyIterator;
+}
+
+PropertyAttributes UrlSearchParamsObject::virtualGetOwnProperty(const Managed *m, PropertyKey id,
+ Property *p)
+{
+ PropertyAttributes attributes = Object::virtualGetOwnProperty(m, id, p);
+ if (attributes != Attr_Invalid)
+ return attributes;
+
+ if (id.isArrayIndex()) {
+ const int index = id.asArrayIndex();
+ const auto usp = static_cast<const UrlSearchParamsObject *>(m);
+ if (index < usp->length()) {
+ if (p)
+ p->value = usp->engine()->newString(usp->nameAt(index));
+ return Attr_NotConfigurable | Attr_NotWritable;
+ }
+ }
+
+ return Object::virtualGetOwnProperty(m, id, p);
+}
+
+ReturnedValue UrlSearchParamsPrototype::method_toString(const FunctionObject *b, const Value *thisObject,
+ const Value *, int)
+{
+ ExecutionEngine *v4 = b->engine();
+ Scope scope(v4);
+
+ Scoped<UrlSearchParamsObject> o(scope, thisObject->as<UrlSearchParamsObject>());
+
+ auto params = o->params();
+
+ QString value;
+
+ for (const QStringList &pair : params)
+ value += QLatin1String("%1=%2&").arg(QString::fromUtf8(QUrl::toPercentEncoding(pair[0])),
+ QString::fromUtf8(QUrl::toPercentEncoding(pair[1])));
+
+ value.chop(1);
+
+ return Encode(v4->newString(value));
+}
+
+ReturnedValue UrlSearchParamsPrototype::method_sort(const FunctionObject *b, const Value *thisObject,
+ const Value *, int)
+{
+ ExecutionEngine *v4 = b->engine();
+ Scope scope(v4);
+
+ Scoped<UrlSearchParamsObject> o(scope, thisObject->as<UrlSearchParamsObject>());
+
+ QList<QStringList> params = o->params();
+ std::stable_sort(params.begin(), params.end(), [](QStringList a, QStringList b) { return a[0] < b[0]; });
+
+ o->setParams(params);
+
+ return Encode::undefined();
+}
+
+ReturnedValue UrlSearchParamsPrototype::method_append(const FunctionObject *b, const Value *thisObject,
+ const Value *argv, int argc)
+{
+ ExecutionEngine *v4 = b->engine();
+ Scope scope(v4);
+
+ if (argc != 2)
+ return v4->throwError(QLatin1String("Bad amount of arguments"));
+
+ ScopedValue argName(scope, argv[0]);
+ ScopedValue argValue(scope, argv[1]);
+
+ String *argNameString = argName->stringValue();
+
+ if (argNameString == nullptr)
+ return v4->throwTypeError(QLatin1String("Invalid argument provided"));
+
+ ScopedString name(scope, argName->as<String>());
+ ScopedString value(scope, argValue->toString(v4));
+
+
+
+ Scoped<UrlSearchParamsObject> o(scope, thisObject->as<UrlSearchParamsObject>());
+
+ o->append(name->d(), value->d());
+
+ return Encode::undefined();
+}
+
+ReturnedValue UrlSearchParamsPrototype::method_delete(const FunctionObject *b, const Value *thisObject,
+ const Value *argv, int argc)
+{
+ ExecutionEngine *v4 = b->engine();
+ Scope scope(v4);
+
+ if (argc != 1)
+ return v4->throwError(QLatin1String("Bad amount of arguments"));
+
+ ScopedValue argName(scope, argv[0]);
+
+ String *argNameString = argName->stringValue();
+
+ if (argNameString == nullptr)
+ return v4->throwTypeError(QLatin1String("Invalid argument provided"));
+
+ QString name = argNameString->toQString();
+
+ Scoped<UrlSearchParamsObject> o(scope, thisObject->as<UrlSearchParamsObject>());
+
+ QList<QStringList> params = o->params();
+
+ auto to_remove = std::remove_if(params.begin(), params.end(), [&name](QStringList pair) {
+ return pair[0] == name;
+ });
+
+ params.erase(to_remove, params.end());
+
+ o->setParams(params);
+
+ return Encode::undefined();
+}
+
+ReturnedValue UrlSearchParamsPrototype::method_has(const FunctionObject *b, const Value *thisObject,
+ const Value *argv, int argc)
+{
+ ExecutionEngine *v4 = b->engine();
+ Scope scope(v4);
+
+ if (argc != 1)
+ return v4->throwError(QLatin1String("Bad amount of arguments"));
+
+ ScopedValue argName(scope, argv[0]);
+
+ String *argNameString = argName->stringValue();
+
+ if (argNameString == nullptr)
+ return v4->throwTypeError(QLatin1String("Invalid argument provided"));
+
+ Scoped<UrlSearchParamsObject> o(scope, thisObject->as<UrlSearchParamsObject>());
+
+ QString name = argNameString->toQString();
+
+ return Encode(o->indexOf(name) != -1);
+}
+
+ReturnedValue UrlSearchParamsPrototype::method_set(const FunctionObject *b, const Value *thisObject,
+ const Value *argv, int argc)
+{
+ ExecutionEngine *v4 = b->engine();
+ Scope scope(v4);
+
+ if (argc != 2)
+ return v4->throwError(QLatin1String("Bad amount of arguments"));
+
+ ScopedValue argName(scope, argv[0]);
+ ScopedValue argValue(scope, argv[1]);
+
+ String *argNameString = argName->stringValue();
+
+ if (argNameString == nullptr)
+ return v4->throwTypeError(QLatin1String("Invalid argument provided"));
+
+ Scoped<UrlSearchParamsObject> o(scope, thisObject->as<UrlSearchParamsObject>());
+
+ QString name = argNameString->toQString();
+ QString value = argValue->toQString();
+
+ auto params = o->params();
+
+ bool matched = false;
+
+ for (auto *it = params.begin(); it != params.end();) {
+ QStringList &param = *it;
+ if (param[0] == name) {
+ if (!matched) {
+ param[1] = value;
+ matched = true;
+ } else {
+ it = params.erase(it);
+ continue;
+ }
+ }
+ it++;
+ }
+
+ if (!matched)
+ params << QStringList { name, value };
+
+ o->setParams(params);
+
+ return Encode::undefined();
+}
+
+ReturnedValue UrlSearchParamsPrototype::method_get(const FunctionObject *b, const Value *thisObject,
+ const Value *argv, int argc)
+{
+ ExecutionEngine *v4 = b->engine();
+ Scope scope(v4);
+
+ if (argc != 1)
+ return v4->throwError(QLatin1String("Bad amount of arguments"));
+
+ ScopedValue argName(scope, argv[0]);
+
+ String *argNameString = argName->stringValue();
+
+ if (argNameString == nullptr)
+ return v4->throwTypeError(QLatin1String("Invalid argument provided"));
+
+ Scoped<UrlSearchParamsObject> o(scope, thisObject->as<UrlSearchParamsObject>());
+
+ QString name = argNameString->toQString();
+
+ int index = o->indexOf(name);
+
+ if (index == -1)
+ return Encode::null();
+
+ return Encode(o->valueAtRaw(index));
+}
+
+ReturnedValue UrlSearchParamsPrototype::method_getAll(const FunctionObject *b,
+ const Value *thisObject, const Value *argv,
+ int argc)
+{
+ ExecutionEngine *v4 = b->engine();
+ Scope scope(v4);
+
+ if (argc != 1)
+ return v4->throwError(QLatin1String("Bad amount of arguments"));
+
+ ScopedValue argName(scope, argv[0]);
+
+ String *argNameString = argName->stringValue();
+
+ if (argNameString == nullptr)
+ return v4->throwTypeError(QLatin1String("Invalid argument provided"));
+
+ Scoped<UrlSearchParamsObject> o(scope, thisObject->as<UrlSearchParamsObject>());
+
+ QString name = argNameString->toQString();
+
+ auto *arrayObject = v4->newArrayObject(0);
+ ScopedArrayObject result(scope, arrayObject);
+
+ int i = 0;
+ for (int index = o->indexOf(name); index != -1; index = o->indexOf(name, index)) {
+ ScopedValue value(scope, Value::fromHeapObject(o->valueAtRaw(index)));
+ result->put(i++, value);
+ }
+
+ return Encode(arrayObject);
+}
+
+ReturnedValue UrlSearchParamsPrototype::method_forEach(const FunctionObject *b,
+ const Value *thisObject, const Value *argv,
+ int argc)
+{
+ ExecutionEngine *v4 = b->engine();
+ Scope scope(v4);
+
+ if (argc != 1)
+ return v4->throwError(QLatin1String("Bad amount of arguments"));
+
+ ScopedValue argFunc(scope, argv[0]);
+
+ FunctionObject *func = argFunc->as<FunctionObject>();
+
+ if (func == nullptr)
+ return v4->throwTypeError(QLatin1String("Invalid argument: must be a function"));
+
+ Scoped<UrlSearchParamsObject> o(scope, thisObject->as<UrlSearchParamsObject>());
+
+ for (int i = 0; i < o->length(); i++) {
+ Scoped<String> name(scope, o->nameAtRaw(i));
+ Scoped<String> value(scope, o->valueAtRaw(i));
+
+ QV4::JSCallData calldata(scope, 2);
+
+ calldata->args[0] = value;
+ calldata->args[1] = name;
+
+ func->call(calldata);
+ }
+
+ return Encode::undefined();
+}
+
+ReturnedValue UrlSearchParamsPrototype::method_entries(const FunctionObject *b,
+ const Value *thisObject, const Value *,
+ int argc)
+{
+ ExecutionEngine *v4 = b->engine();
+ Scope scope(v4);
+
+ if (argc != 0)
+ return v4->throwError(QLatin1String("Bad amount of arguments"));
+
+ Scoped<UrlSearchParamsObject> o(scope, thisObject->as<UrlSearchParamsObject>());
+
+ ScopedObject params(scope, o->d()->params.get());
+
+ Scoped<ArrayIteratorObject> paramsIterator(scope, v4->newArrayIteratorObject(params));
+ paramsIterator->d()->iterationKind = IteratorKind::KeyValueIteratorKind;
+ return paramsIterator->asReturnedValue();
+}
+
+ReturnedValue UrlSearchParamsPrototype::method_keys(const FunctionObject *b,
+ const Value *thisObject, const Value *,
+ int argc)
+{
+ ExecutionEngine *v4 = b->engine();
+ Scope scope(v4);
+
+ if (argc != 0)
+ return v4->throwError(QLatin1String("Bad amount of arguments"));
+
+ Scoped<UrlSearchParamsObject> o(scope, thisObject->as<UrlSearchParamsObject>());
+
+ ScopedObject keys(scope, o->d()->keys.get());
+
+ Scoped<ArrayIteratorObject> keysIterator(scope, v4->newArrayIteratorObject(keys));
+ keysIterator->d()->iterationKind = IteratorKind::KeyValueIteratorKind;
+ return keysIterator->asReturnedValue();
+}
+
+ReturnedValue UrlSearchParamsPrototype::method_values(const FunctionObject *b,
+ const Value *thisObject, const Value *,
+ int argc)
+{
+ ExecutionEngine *v4 = b->engine();
+ Scope scope(v4);
+
+ if (argc != 0)
+ return v4->throwError(QLatin1String("Bad amount of arguments"));
+
+ Scoped<UrlSearchParamsObject> o(scope, thisObject->as<UrlSearchParamsObject>());
+
+ ScopedObject values(scope, o->d()->values.get());
+
+ Scoped<ArrayIteratorObject> valuesIterator(scope, v4->newArrayIteratorObject(values));
+ valuesIterator->d()->iterationKind = IteratorKind::KeyValueIteratorKind;
+ return valuesIterator->asReturnedValue();
+}
diff --git a/src/qml/jsruntime/qv4urlobject_p.h b/src/qml/jsruntime/qv4urlobject_p.h
index bc066818b6..aa0e7a062f 100644
--- a/src/qml/jsruntime/qv4urlobject_p.h
+++ b/src/qml/jsruntime/qv4urlobject_p.h
@@ -85,6 +85,24 @@ struct UrlCtor : FunctionObject
{
void init(QV4::ExecutionContext *scope);
};
+
+// clang-format on
+#define UrlSearchParamsObjectMembers(class, Member) \
+ Member(class, Pointer, ArrayObject *, params) \
+ Member(class, Pointer, ArrayObject *, keys) \
+ Member(class, Pointer, ArrayObject *, values)
+// clang-format off
+
+DECLARE_HEAP_OBJECT(UrlSearchParamsObject, Object)
+{
+ DECLARE_MARKOBJECTS(UrlSearchParamsObject);
+ void init() { Object::init(); }
+};
+
+struct UrlSearchParamsCtor : FunctionObject
+{
+ void init(QV4::ExecutionContext *scope);
+};
}
struct UrlObject : Object
@@ -205,6 +223,91 @@ struct UrlPrototype : Object
const Value *argv, int argc);
static ReturnedValue method_setUsername(const FunctionObject *, const Value *thisObject,
const Value *argv, int argc);
+
+ static ReturnedValue method_getSearchParams(const FunctionObject *, const Value *thisObject,
+ const Value *argv, int argc);
+};
+
+struct UrlSearchParamsObject : Object
+{
+ V4_OBJECT2(UrlSearchParamsObject, Object)
+ Q_MANAGED_TYPE(UrlSearchParamsObject)
+ V4_PROTOTYPE(urlSearchParamsPrototype)
+
+ void initializeParams();
+ void initializeParams(QString params);
+ void initializeParams(ScopedArrayObject& params);
+ void initializeParams(ScopedObject& params);
+
+ QList<QStringList> params() const;
+ void setParams(QList<QStringList> params);
+
+ QString nameAt(int index) const;
+ Heap::String * nameAtRaw(int index) const;
+ QString valueAt(int index) const;
+ Heap::String * valueAtRaw(int index) const;
+
+ void append(Heap::String *name, Heap::String *value);
+
+ int indexOf(QString name, int last = -1) const;
+ int length() const;
+
+ using Object::getOwnProperty;
+protected:
+ static OwnPropertyKeyIterator *virtualOwnPropertyKeys(const Object *m, Value *target);
+ static PropertyAttributes virtualGetOwnProperty(const Managed *m, PropertyKey id, Property *p);
+private:
+ QString stringAt(int index, int pairIndex) const;
+ Heap::String * stringAtRaw(int index, int pairIndex) const;
+};
+
+template<>
+inline const UrlSearchParamsObject *Value::as() const
+{
+ return isManaged() && m()->internalClass->vtable->type == Managed::Type_UrlSearchParamsObject
+ ? static_cast<const UrlSearchParamsObject *>(this)
+ : nullptr;
+}
+
+struct UrlSearchParamsCtor : FunctionObject
+{
+ V4_OBJECT2(UrlSearchParamsCtor, FunctionObject)
+
+ static ReturnedValue virtualCallAsConstructor(const FunctionObject *, const Value *argv,
+ int argc, const Value *);
+};
+
+struct UrlSearchParamsPrototype : Object
+{
+ V4_PROTOTYPE(objectPrototype)
+
+ void init(ExecutionEngine *engine, Object *ctor);
+
+ static ReturnedValue method_toString(const FunctionObject *, const Value *thisObject,
+ const Value *argv, int argc);
+ static ReturnedValue method_sort(const FunctionObject *, const Value *thisObject,
+ const Value *argv, int argc);
+ static ReturnedValue method_append(const FunctionObject *, const Value *thisObject,
+ const Value *argv, int argc);
+ static ReturnedValue method_delete(const FunctionObject *, const Value *thisObject,
+ const Value *argv, int argc);
+ static ReturnedValue method_has(const FunctionObject *, const Value *thisObject,
+ const Value *argv, int argc);
+ static ReturnedValue method_set(const FunctionObject *, const Value *thisObject,
+ const Value *argv, int argc);
+ static ReturnedValue method_get(const FunctionObject *, const Value *thisObject,
+ const Value *argv, int argc);
+ static ReturnedValue method_getAll(const FunctionObject *, const Value *thisObject,
+ const Value *argv, int argc);
+ static ReturnedValue method_forEach(const FunctionObject *, const Value *thisObject,
+ const Value *argv, int argc);
+ static ReturnedValue method_entries(const FunctionObject *, const Value *thisObject,
+ const Value *argv, int argc);
+ static ReturnedValue method_keys(const FunctionObject *, const Value *thisObject,
+ const Value *argv, int argc);
+ static ReturnedValue method_values(const FunctionObject *, const Value *thisObject,
+ const Value *argv, int argc);
+
};
}