DOMTokenList: Add support and testing for this

We add both DOMTokenList and DOMSettableTokenList and introduce
polyfills for stringifying it until nsgenbind can do that.

We also bring in a test to demonstrate all that we have.

Note: This does not implement the extra methods that exist according
to MDN, we may need a polyfill to bring that up to snuff.

Signed-off-by: Daniel Silverstone <dsilvers@digital-scurf.org>
This commit is contained in:
Daniel Silverstone 2022-11-27 09:40:47 +00:00
parent 764fca4f3a
commit 7bcd4fd246
No known key found for this signature in database
GPG Key ID: C30DF439F2987D74
7 changed files with 278 additions and 0 deletions

View File

@ -0,0 +1,44 @@
/* DOMTokenList binding for browser using duktape and libdom
*
* Copyright 2015 Vincent Sanders <vince@netsurf-browser.org>
*
* This file is part of NetSurf, http://www.netsurf-browser.org/
*
* Released under the terms of the MIT License,
* http://www.opensource.org/licenses/mit-license
*/
class DOMSettableTokenList {
};
init DOMSettableTokenList(struct dom_tokenlist *tokens::tokens);
getter DOMSettableTokenList::value()
%{
dom_exception exc;
dom_string *value;
exc = dom_tokenlist_get_value(priv->parent.tokens, &value);
if (exc != DOM_NO_ERR) return 0; /* coerced to undefined */
duk_push_lstring(ctx, dom_string_data(value), dom_string_length(value));
dom_string_unref(value);
return 1;
%}
setter DOMSettableTokenList::value()
%{
dom_exception exc;
dom_string *value;
duk_size_t slen;
const char *s = duk_require_lstring(ctx, 0, &slen);
exc = dom_string_create_interned((const uint8_t *)s, slen, &value);
if (exc != DOM_NO_ERR) return 0;
exc = dom_tokenlist_set_value(priv->parent.tokens, value);
dom_string_unref(value);
return 0;
%}

View File

@ -0,0 +1,163 @@
/* DOMTokenList binding for browser using duktape and libdom
*
* Copyright 2015 Vincent Sanders <vince@netsurf-browser.org>
*
* This file is part of NetSurf, http://www.netsurf-browser.org/
*
* Released under the terms of the MIT License,
* http://www.opensource.org/licenses/mit-license
*/
class DOMTokenList {
private struct dom_tokenlist *tokens;
};
init DOMTokenList(struct dom_tokenlist *tokens)
%{
priv->tokens = tokens;
dom_tokenlist_ref(tokens);
%}
fini DOMTokenList()
%{
dom_tokenlist_unref(priv->tokens);
%}
getter DOMTokenList::length()
%{
dom_exception err;
uint32_t len;
err = dom_tokenlist_get_length(priv->tokens, &len);
if (err != DOM_NO_ERR) return 0; /* coerced to undefined */
duk_push_uint(ctx, (duk_uint_t)len);
return 1;
%}
method DOMTokenList::item()
%{
unsigned long i = duk_to_uint(ctx, 0);
dom_exception err;
dom_string *value;
err = dom_tokenlist_item(priv->tokens, i, &value);
if (err != DOM_NO_ERR) return 0; /* coerced to undefined */
if (value == NULL) {
duk_push_null(ctx);
return 1;
}
duk_push_lstring(ctx, dom_string_data(value), dom_string_length(value));
dom_string_unref(value);
return 1;
%}
method DOMTokenList::add()
%{
dom_exception exc;
dom_string *value;
duk_size_t slen;
const char *s;
duk_idx_t spos;
for (spos = 0; spos < duk_get_top(ctx); ++spos) {
s = duk_safe_to_lstring(ctx, spos, &slen);
duk_safe_to_lstring(ctx, 0, &slen);
exc = dom_string_create_interned((const uint8_t *)s, slen, &value);
if (exc != DOM_NO_ERR) return 0;
exc = dom_tokenlist_add(priv->tokens, value);
dom_string_unref(value);
}
return 0;
%}
method DOMTokenList::remove()
%{
dom_exception exc;
dom_string *value;
duk_size_t slen;
const char *s;
duk_idx_t spos;
for (spos = 0; spos < duk_get_top(ctx); ++spos) {
s = duk_safe_to_lstring(ctx, spos, &slen);
duk_safe_to_lstring(ctx, 0, &slen);
exc = dom_string_create_interned((const uint8_t *)s, slen, &value);
if (exc != DOM_NO_ERR) return 0;
exc = dom_tokenlist_remove(priv->tokens, value);
dom_string_unref(value);
}
return 0;
%}
method DOMTokenList::contains()
%{
dom_exception exc;
dom_string *value;
duk_size_t slen;
const char *s = duk_safe_to_lstring(ctx, 0, &slen);
bool present = false;
exc = dom_string_create_interned((const uint8_t *)s, slen, &value);
if (exc != DOM_NO_ERR) return 0;
exc = dom_tokenlist_contains(priv->tokens, value, &present);
dom_string_unref(value);
if (exc != DOM_NO_ERR) return 0;
duk_push_boolean(ctx, present);
return 1;
%}
method DOMTokenList::toggle()
%{
dom_exception exc;
dom_string *value;
duk_size_t slen;
const char *s = duk_require_lstring(ctx, 0, &slen);
bool toggle_set = duk_get_top(ctx) > 1;
bool toggle = duk_opt_boolean(ctx, 1, 0);
bool present;
exc = dom_string_create_interned((const uint8_t *)s, slen, &value);
if (exc != DOM_NO_ERR) return 0;
exc = dom_tokenlist_contains(priv->tokens, value, &present);
if (exc != DOM_NO_ERR) {
dom_string_unref(value);
return 0;
}
/* Decision matrix is based on present, toggle_set, and toggle */
if (toggle_set) {
if (toggle) {
exc = dom_tokenlist_add(priv->tokens, value);
} else {
exc = dom_tokenlist_remove(priv->tokens, value);
}
} else {
if (present) {
exc = dom_tokenlist_add(priv->tokens, value);
} else {
exc = dom_tokenlist_remove(priv->tokens, value);
}
}
dom_string_unref(value);
return 0;
%}

View File

@ -392,6 +392,27 @@ setter Element::className ()
return 0;
%}
getter Element::classList ()
%{
dom_exception exc;
dom_tokenlist *tokens;
exc = dom_tokenlist_create((dom_element *)priv->parent.node, corestring_dom_class, &tokens);
if (exc != DOM_NO_ERR) return 0; /* Coerced to undefined */
/* Create a settable tokenlist - While the IDL says this isn't settable, all browsers
* seem to make it settable, so we'll permit it too
*/
duk_push_pointer(ctx, tokens);
if (dukky_create_object(ctx, PROTO_NAME(DOMSETTABLETOKENLIST), 1) != DUK_EXEC_SUCCESS) {
dom_tokenlist_unref(tokens);
NSLOG(dukky, DEBUG, "Unable to create DOMSettableTokenList object");
return 0; /* Coerced to undefined */
}
dom_tokenlist_unref(tokens);
return 1;
%}
getter Element::innerHTML()
%{
duk_push_lstring(ctx, "", 0);

View File

@ -60,6 +60,8 @@ struct dom_html_br_element;
#include "Document.bnd"
#include "Node.bnd"
#include "NodeList.bnd"
#include "DOMTokenList.bnd"
#include "DOMSettableTokenList.bnd"
#include "NamedNodeMap.bnd"
#include "Element.bnd"
#include "HTMLCollection.bnd"

View File

@ -83,3 +83,21 @@ if (!Array.from) {
};
}());
}
// DOMTokenList formatter, in theory we can remove this if we do the stringifier IDL support
DOMTokenList.prototype.toString = function () {
if (this.length == 0) {
return "";
}
var ret = this.item(0);
for (var index = 1; index < this.length; index++) {
ret = ret + " " + this.item(index);
}
return ret;
}
// Inherit the same toString for settable lists
DOMSettableTokenList.prototype.toString = DOMTokenList.prototype.toString;

29
test/js/class-list.html Normal file
View File

@ -0,0 +1,29 @@
<html>
<head>
<title>Class List (and other token lists?)</title>
<style>
.bad { background-color: red; }
.ok { background-color: green; }
</style>
</head>
<body>
<h1>This is a set of demonstrators for the token list Element.classList</h1>
<h2>This first is taken from the MDN for DOMTokenList</h2>
<span id="demo1" class=" d d e f bad"></span>
<script>
var span = document.getElementById("demo1");
var classes = span.classList;
classes.add("x", "d", "g");
classes.remove("e", "g");
classes.toggle("d"); // Toggles d off
classes.toggle("q", false); // Forces q off (won't be present)
classes.toggle("d"); // Toggles d on
classes.toggle("d", true); // Forces d on (won't toggle it off again)
if (classes.contains("d")) {
classes.add("ok")
classes.remove("bad")
span.textContent = "span classList is \"" + classes + '"';
}
</script>
</body>
</html>

View File

@ -104,6 +104,7 @@
<li><a href="assorted-log-doc-write.html">console.log and document.write</a></li>
<li><a href="wikipedia-lcm.html">Example from wikipedia</a></li>
<li><a href="verify-instanceofness.html">Check instanceof behaviour</a></li>
<li><a href="class-list.html">Class list (and other token lists?)</a></li>
<li><a href="mandelbrot.html">Canvas/ImageData Mandelbrot ploter</a></li>
<li><a href="life.html">Game of Life</a></li>
</ul>