From 7bcd4fd2465631f4a17e1920594e9c2536b6f057 Mon Sep 17 00:00:00 2001 From: Daniel Silverstone Date: Sun, 27 Nov 2022 09:40:47 +0000 Subject: 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 --- .../javascript/duktape/DOMSettableTokenList.bnd | 44 ++++++ .../handlers/javascript/duktape/DOMTokenList.bnd | 163 +++++++++++++++++++++ content/handlers/javascript/duktape/Element.bnd | 21 +++ content/handlers/javascript/duktape/netsurf.bnd | 2 + content/handlers/javascript/duktape/polyfill.js | 18 +++ test/js/class-list.html | 29 ++++ test/js/index.html | 1 + 7 files changed, 278 insertions(+) create mode 100644 content/handlers/javascript/duktape/DOMSettableTokenList.bnd create mode 100644 content/handlers/javascript/duktape/DOMTokenList.bnd create mode 100644 test/js/class-list.html diff --git a/content/handlers/javascript/duktape/DOMSettableTokenList.bnd b/content/handlers/javascript/duktape/DOMSettableTokenList.bnd new file mode 100644 index 000000000..ac5c7062a --- /dev/null +++ b/content/handlers/javascript/duktape/DOMSettableTokenList.bnd @@ -0,0 +1,44 @@ +/* DOMTokenList binding for browser using duktape and libdom + * + * Copyright 2015 Vincent Sanders + * + * 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; +%} \ No newline at end of file diff --git a/content/handlers/javascript/duktape/DOMTokenList.bnd b/content/handlers/javascript/duktape/DOMTokenList.bnd new file mode 100644 index 000000000..928d9ef35 --- /dev/null +++ b/content/handlers/javascript/duktape/DOMTokenList.bnd @@ -0,0 +1,163 @@ +/* DOMTokenList binding for browser using duktape and libdom + * + * Copyright 2015 Vincent Sanders + * + * 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; +%} \ No newline at end of file diff --git a/content/handlers/javascript/duktape/Element.bnd b/content/handlers/javascript/duktape/Element.bnd index a965a6ceb..677a9578e 100644 --- a/content/handlers/javascript/duktape/Element.bnd +++ b/content/handlers/javascript/duktape/Element.bnd @@ -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); diff --git a/content/handlers/javascript/duktape/netsurf.bnd b/content/handlers/javascript/duktape/netsurf.bnd index 651c2fdfa..483f3471f 100644 --- a/content/handlers/javascript/duktape/netsurf.bnd +++ b/content/handlers/javascript/duktape/netsurf.bnd @@ -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" diff --git a/content/handlers/javascript/duktape/polyfill.js b/content/handlers/javascript/duktape/polyfill.js index 5f0215618..6c85ce1a0 100644 --- a/content/handlers/javascript/duktape/polyfill.js +++ b/content/handlers/javascript/duktape/polyfill.js @@ -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; \ No newline at end of file diff --git a/test/js/class-list.html b/test/js/class-list.html new file mode 100644 index 000000000..4c73283e5 --- /dev/null +++ b/test/js/class-list.html @@ -0,0 +1,29 @@ + + + Class List (and other token lists?) + + + +

This is a set of demonstrators for the token list Element.classList

+

This first is taken from the MDN for DOMTokenList

+ + + + diff --git a/test/js/index.html b/test/js/index.html index 032946726..6d2c6541e 100644 --- a/test/js/index.html +++ b/test/js/index.html @@ -104,6 +104,7 @@
  • console.log and document.write
  • Example from wikipedia
  • Check instanceof behaviour
  • +
  • Class list (and other token lists?)
  • Canvas/ImageData Mandelbrot ploter
  • Game of Life
  • -- cgit v1.2.1