mirror of
https://github.com/RGBCube/serenity
synced 2025-07-24 19:07:35 +00:00
LibWeb: Generate Element bindings from IDL :^)
Had to do a bunch more hacking on WrapperGenerator to support this. We now support attribute setters as well.
This commit is contained in:
parent
5eb39a5f61
commit
a64033e581
7 changed files with 103 additions and 289 deletions
|
@ -1,157 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright (c) 2020, Andreas Kling <kling@serenityos.org>
|
|
||||||
* All rights reserved.
|
|
||||||
*
|
|
||||||
* Redistribution and use in source and binary forms, with or without
|
|
||||||
* modification, are permitted provided that the following conditions are met:
|
|
||||||
*
|
|
||||||
* 1. Redistributions of source code must retain the above copyright notice, this
|
|
||||||
* list of conditions and the following disclaimer.
|
|
||||||
*
|
|
||||||
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
|
||||||
* this list of conditions and the following disclaimer in the documentation
|
|
||||||
* and/or other materials provided with the distribution.
|
|
||||||
*
|
|
||||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
|
||||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
|
||||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
|
||||||
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
|
||||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
|
||||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
|
||||||
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
|
||||||
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
|
||||||
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
|
||||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include <AK/FlyString.h>
|
|
||||||
#include <AK/Function.h>
|
|
||||||
#include <LibJS/Interpreter.h>
|
|
||||||
#include <LibJS/Runtime/Error.h>
|
|
||||||
#include <LibJS/Runtime/GlobalObject.h>
|
|
||||||
#include <LibJS/Runtime/PrimitiveString.h>
|
|
||||||
#include <LibJS/Runtime/Value.h>
|
|
||||||
#include <LibWeb/Bindings/ElementWrapper.h>
|
|
||||||
#include <LibWeb/DOM/AttributeNames.h>
|
|
||||||
#include <LibWeb/DOM/Element.h>
|
|
||||||
|
|
||||||
namespace Web {
|
|
||||||
namespace Bindings {
|
|
||||||
|
|
||||||
ElementWrapper::ElementWrapper(JS::GlobalObject& global_object, Element& element)
|
|
||||||
: NodeWrapper(global_object, element)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
void ElementWrapper::initialize(JS::Interpreter& interpreter, JS::GlobalObject& global_object)
|
|
||||||
{
|
|
||||||
NodeWrapper::initialize(interpreter, global_object);
|
|
||||||
|
|
||||||
define_native_property("innerHTML", inner_html_getter, inner_html_setter);
|
|
||||||
define_native_property("id", id_getter, id_setter);
|
|
||||||
|
|
||||||
u8 attributes = JS::Attribute::Configurable | JS::Attribute::Enumerable | JS::Attribute::Writable;
|
|
||||||
define_native_function("getAttribute", get_attribute, 1, attributes);
|
|
||||||
define_native_function("setAttribute", set_attribute, 2, attributes);
|
|
||||||
}
|
|
||||||
|
|
||||||
ElementWrapper::~ElementWrapper()
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
Element& ElementWrapper::node()
|
|
||||||
{
|
|
||||||
return static_cast<Element&>(NodeWrapper::impl());
|
|
||||||
}
|
|
||||||
|
|
||||||
const Element& ElementWrapper::node() const
|
|
||||||
{
|
|
||||||
return static_cast<const Element&>(NodeWrapper::impl());
|
|
||||||
}
|
|
||||||
|
|
||||||
static Element* impl_from(JS::Interpreter& interpreter, JS::GlobalObject& global_object)
|
|
||||||
{
|
|
||||||
auto* this_object = interpreter.this_value(global_object).to_object(interpreter, global_object);
|
|
||||||
if (!this_object)
|
|
||||||
return nullptr;
|
|
||||||
// FIXME: Verify that it's an ElementWrapper somehow!
|
|
||||||
return &static_cast<ElementWrapper*>(this_object)->node();
|
|
||||||
}
|
|
||||||
|
|
||||||
JS_DEFINE_NATIVE_FUNCTION(ElementWrapper::get_attribute)
|
|
||||||
{
|
|
||||||
auto* impl = impl_from(interpreter, global_object);
|
|
||||||
if (!impl)
|
|
||||||
return {};
|
|
||||||
|
|
||||||
if (interpreter.argument_count() < 1)
|
|
||||||
return interpreter.throw_exception<JS::TypeError>(JS::ErrorType::BadArgCountOne, "getAttribute");
|
|
||||||
|
|
||||||
auto attribute_name = interpreter.argument(0).to_string(interpreter);
|
|
||||||
if (interpreter.exception())
|
|
||||||
return {};
|
|
||||||
|
|
||||||
auto attribute_value = impl->attribute(attribute_name);
|
|
||||||
if (attribute_value.is_null())
|
|
||||||
return JS::js_null();
|
|
||||||
|
|
||||||
return JS::js_string(interpreter, attribute_value);
|
|
||||||
}
|
|
||||||
|
|
||||||
JS_DEFINE_NATIVE_FUNCTION(ElementWrapper::set_attribute)
|
|
||||||
{
|
|
||||||
auto* impl = impl_from(interpreter, global_object);
|
|
||||||
if (!impl)
|
|
||||||
return {};
|
|
||||||
|
|
||||||
if (interpreter.argument_count() < 2)
|
|
||||||
return interpreter.throw_exception<JS::TypeError>(JS::ErrorType::BadArgCountMany, "setAttribute", "two");
|
|
||||||
|
|
||||||
auto attribute_name = interpreter.argument(0).to_string(interpreter);
|
|
||||||
if (interpreter.exception())
|
|
||||||
return {};
|
|
||||||
|
|
||||||
auto attribute_value = interpreter.argument(1).to_string(interpreter);
|
|
||||||
if (interpreter.exception())
|
|
||||||
return {};
|
|
||||||
|
|
||||||
impl->set_attribute(attribute_name, attribute_value);
|
|
||||||
return JS::js_undefined();
|
|
||||||
}
|
|
||||||
|
|
||||||
JS_DEFINE_NATIVE_GETTER(ElementWrapper::inner_html_getter)
|
|
||||||
{
|
|
||||||
if (auto* impl = impl_from(interpreter, global_object))
|
|
||||||
return JS::js_string(interpreter, impl->inner_html());
|
|
||||||
return {};
|
|
||||||
}
|
|
||||||
|
|
||||||
JS_DEFINE_NATIVE_SETTER(ElementWrapper::inner_html_setter)
|
|
||||||
{
|
|
||||||
if (auto* impl = impl_from(interpreter, global_object)) {
|
|
||||||
auto string = value.to_string(interpreter);
|
|
||||||
if (interpreter.exception())
|
|
||||||
return;
|
|
||||||
impl->set_inner_html(string);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
JS_DEFINE_NATIVE_GETTER(ElementWrapper::id_getter)
|
|
||||||
{
|
|
||||||
if (auto* impl = impl_from(interpreter, global_object))
|
|
||||||
return JS::js_string(interpreter, impl->attribute(HTML::AttributeNames::id));
|
|
||||||
return {};
|
|
||||||
}
|
|
||||||
|
|
||||||
JS_DEFINE_NATIVE_SETTER(ElementWrapper::id_setter)
|
|
||||||
{
|
|
||||||
if (auto* impl = impl_from(interpreter, global_object)) {
|
|
||||||
auto string = value.to_string(interpreter);
|
|
||||||
if (interpreter.exception())
|
|
||||||
return;
|
|
||||||
impl->set_attribute(HTML::AttributeNames::id, string);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,57 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright (c) 2020, Andreas Kling <kling@serenityos.org>
|
|
||||||
* All rights reserved.
|
|
||||||
*
|
|
||||||
* Redistribution and use in source and binary forms, with or without
|
|
||||||
* modification, are permitted provided that the following conditions are met:
|
|
||||||
*
|
|
||||||
* 1. Redistributions of source code must retain the above copyright notice, this
|
|
||||||
* list of conditions and the following disclaimer.
|
|
||||||
*
|
|
||||||
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
|
||||||
* this list of conditions and the following disclaimer in the documentation
|
|
||||||
* and/or other materials provided with the distribution.
|
|
||||||
*
|
|
||||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
|
||||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
|
||||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
|
||||||
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
|
||||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
|
||||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
|
||||||
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
|
||||||
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
|
||||||
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
|
||||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#include <LibWeb/Bindings/NodeWrapper.h>
|
|
||||||
|
|
||||||
namespace Web {
|
|
||||||
namespace Bindings {
|
|
||||||
|
|
||||||
class ElementWrapper : public NodeWrapper {
|
|
||||||
public:
|
|
||||||
ElementWrapper(JS::GlobalObject&, Element&);
|
|
||||||
virtual void initialize(JS::Interpreter&, JS::GlobalObject&) override;
|
|
||||||
virtual ~ElementWrapper() override;
|
|
||||||
|
|
||||||
Element& node();
|
|
||||||
const Element& node() const;
|
|
||||||
|
|
||||||
private:
|
|
||||||
virtual const char* class_name() const override { return "ElementWrapper"; }
|
|
||||||
|
|
||||||
JS_DECLARE_NATIVE_GETTER(inner_html_getter);
|
|
||||||
JS_DECLARE_NATIVE_SETTER(inner_html_setter);
|
|
||||||
|
|
||||||
JS_DECLARE_NATIVE_GETTER(id_getter);
|
|
||||||
JS_DECLARE_NATIVE_SETTER(id_setter);
|
|
||||||
|
|
||||||
JS_DECLARE_NATIVE_FUNCTION(get_attribute);
|
|
||||||
JS_DECLARE_NATIVE_FUNCTION(set_attribute);
|
|
||||||
};
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -40,6 +40,7 @@ class Wrapper
|
||||||
public:
|
public:
|
||||||
virtual bool is_node_wrapper() const { return false; }
|
virtual bool is_node_wrapper() const { return false; }
|
||||||
virtual bool is_document_wrapper() const { return false; }
|
virtual bool is_document_wrapper() const { return false; }
|
||||||
|
virtual bool is_element_wrapper() const { return false; }
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
explicit Wrapper(Object& prototype)
|
explicit Wrapper(Object& prototype)
|
||||||
|
|
|
@ -3,6 +3,7 @@ set(SOURCES
|
||||||
Bindings/DocumentWrapper.cpp
|
Bindings/DocumentWrapper.cpp
|
||||||
Bindings/DocumentWrapper.h
|
Bindings/DocumentWrapper.h
|
||||||
Bindings/ElementWrapper.cpp
|
Bindings/ElementWrapper.cpp
|
||||||
|
Bindings/ElementWrapper.h
|
||||||
Bindings/EventListenerWrapper.cpp
|
Bindings/EventListenerWrapper.cpp
|
||||||
Bindings/EventTargetWrapper.cpp
|
Bindings/EventTargetWrapper.cpp
|
||||||
Bindings/EventWrapper.cpp
|
Bindings/EventWrapper.cpp
|
||||||
|
@ -126,45 +127,29 @@ set(GENERATED_SOURCES
|
||||||
../../Services/ProtocolServer/ProtocolServerEndpoint.h
|
../../Services/ProtocolServer/ProtocolServerEndpoint.h
|
||||||
)
|
)
|
||||||
|
|
||||||
add_custom_command(
|
function(libweb_js_wrapper class)
|
||||||
OUTPUT Bindings/NodeWrapper.h
|
add_custom_command(
|
||||||
COMMAND /bin/mkdir -p Bindings
|
OUTPUT Bindings/${class}Wrapper.h
|
||||||
COMMAND WrapperGenerator --header ${CMAKE_CURRENT_SOURCE_DIR}/DOM/Node.idl > Bindings/NodeWrapper.h
|
COMMAND /bin/mkdir -p Bindings
|
||||||
VERBATIM
|
COMMAND WrapperGenerator --header ${CMAKE_CURRENT_SOURCE_DIR}/DOM/${class}.idl > Bindings/${class}Wrapper.h
|
||||||
DEPENDS WrapperGenerator
|
VERBATIM
|
||||||
MAIN_DEPENDENCY DOM/Node.idl
|
DEPENDS WrapperGenerator
|
||||||
)
|
MAIN_DEPENDENCY DOM/${class}.idl
|
||||||
add_custom_target(generate_NodeWrapper.h DEPENDS Bindings/NodeWrapper.h)
|
)
|
||||||
|
add_custom_command(
|
||||||
|
OUTPUT Bindings/${class}Wrapper.cpp
|
||||||
|
COMMAND /bin/mkdir -p Bindings
|
||||||
|
COMMAND WrapperGenerator --implementation ${CMAKE_CURRENT_SOURCE_DIR}/DOM/${class}.idl > Bindings/${class}Wrapper.cpp
|
||||||
|
VERBATIM
|
||||||
|
DEPENDS WrapperGenerator
|
||||||
|
MAIN_DEPENDENCY DOM/${class}.idl
|
||||||
|
)
|
||||||
|
add_custom_target(generate_${class}Wrapper.h DEPENDS Bindings/${class}Wrapper.h)
|
||||||
|
endfunction()
|
||||||
|
|
||||||
add_custom_command(
|
libweb_js_wrapper(Node)
|
||||||
OUTPUT Bindings/NodeWrapper.cpp
|
libweb_js_wrapper(Document)
|
||||||
COMMAND /bin/mkdir -p Bindings
|
libweb_js_wrapper(Element)
|
||||||
COMMAND WrapperGenerator --implementation ${CMAKE_CURRENT_SOURCE_DIR}/DOM/Node.idl > Bindings/NodeWrapper.cpp
|
|
||||||
VERBATIM
|
|
||||||
DEPENDS WrapperGenerator
|
|
||||||
MAIN_DEPENDENCY DOM/Node.idl
|
|
||||||
)
|
|
||||||
add_custom_target(generate_NodeWrapper.cpp DEPENDS Bindings/NodeWrapper.cpp)
|
|
||||||
|
|
||||||
add_custom_command(
|
|
||||||
OUTPUT Bindings/DocumentWrapper.h
|
|
||||||
COMMAND /bin/mkdir -p Bindings
|
|
||||||
COMMAND WrapperGenerator --header ${CMAKE_CURRENT_SOURCE_DIR}/DOM/Document.idl > Bindings/DocumentWrapper.h
|
|
||||||
VERBATIM
|
|
||||||
DEPENDS WrapperGenerator
|
|
||||||
MAIN_DEPENDENCY DOM/Document.idl
|
|
||||||
)
|
|
||||||
add_custom_target(generate_DocumentWrapper.h DEPENDS Bindings/DocumentWrapper.h)
|
|
||||||
|
|
||||||
add_custom_command(
|
|
||||||
OUTPUT Bindings/DocumentWrapper.cpp
|
|
||||||
COMMAND /bin/mkdir -p Bindings
|
|
||||||
COMMAND WrapperGenerator --implementation ${CMAKE_CURRENT_SOURCE_DIR}/DOM/Document.idl > Bindings/DocumentWrapper.cpp
|
|
||||||
VERBATIM
|
|
||||||
DEPENDS WrapperGenerator
|
|
||||||
MAIN_DEPENDENCY DOM/Document.idl
|
|
||||||
)
|
|
||||||
add_custom_target(generate_DocumentWrapper.cpp DEPENDS Bindings/DocumentWrapper.cpp)
|
|
||||||
|
|
||||||
add_custom_command(
|
add_custom_command(
|
||||||
OUTPUT CSS/PropertyID.h
|
OUTPUT CSS/PropertyID.h
|
||||||
|
|
|
@ -34,15 +34,17 @@ static String snake_name(const StringView& title_name)
|
||||||
{
|
{
|
||||||
StringBuilder builder;
|
StringBuilder builder;
|
||||||
bool first = true;
|
bool first = true;
|
||||||
|
bool last_was_uppercase = false;
|
||||||
for (auto ch : title_name) {
|
for (auto ch : title_name) {
|
||||||
if (isupper(ch)) {
|
if (isupper(ch)) {
|
||||||
if (!first)
|
if (!first && !last_was_uppercase)
|
||||||
builder.append('_');
|
builder.append('_');
|
||||||
builder.append(tolower(ch));
|
builder.append(tolower(ch));
|
||||||
} else {
|
} else {
|
||||||
builder.append(ch);
|
builder.append(ch);
|
||||||
}
|
}
|
||||||
first = false;
|
first = false;
|
||||||
|
last_was_uppercase = isupper(ch);
|
||||||
}
|
}
|
||||||
return builder.to_string();
|
return builder.to_string();
|
||||||
}
|
}
|
||||||
|
@ -93,20 +95,6 @@ struct Interface {
|
||||||
String wrapper_base_class;
|
String wrapper_base_class;
|
||||||
};
|
};
|
||||||
|
|
||||||
static String snake_name(const StringView& camel_name)
|
|
||||||
{
|
|
||||||
StringBuilder builder;
|
|
||||||
for (auto ch : camel_name) {
|
|
||||||
if (isupper(ch)) {
|
|
||||||
builder.append('_');
|
|
||||||
builder.append(tolower(ch));
|
|
||||||
} else {
|
|
||||||
builder.append(ch);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return builder.to_string();
|
|
||||||
}
|
|
||||||
|
|
||||||
OwnPtr<Interface> parse_interface(const StringView& input)
|
OwnPtr<Interface> parse_interface(const StringView& input)
|
||||||
{
|
{
|
||||||
auto interface = make<Interface>();
|
auto interface = make<Interface>();
|
||||||
|
@ -422,9 +410,55 @@ void generate_implementation(const IDL::Interface& interface)
|
||||||
out() << " return &static_cast<" << wrapper_class << "*>(this_object)->impl();";
|
out() << " return &static_cast<" << wrapper_class << "*>(this_object)->impl();";
|
||||||
out() << "}";
|
out() << "}";
|
||||||
|
|
||||||
|
auto generate_to_cpp = [&](auto& parameter, auto& js_name, auto& js_suffix, auto cpp_name, bool return_void = false) {
|
||||||
|
auto generate_return = [&] {
|
||||||
|
if (return_void)
|
||||||
|
out() << " return;";
|
||||||
|
else
|
||||||
|
out() << " return {};";
|
||||||
|
};
|
||||||
|
if (parameter.type.name == "DOMString") {
|
||||||
|
out() << " auto " << cpp_name << " = " << js_name << js_suffix << ".to_string(interpreter);";
|
||||||
|
out() << " if (interpreter.exception())";
|
||||||
|
generate_return();
|
||||||
|
} else if (parameter.type.name == "Node") {
|
||||||
|
out() << " auto " << cpp_name << "_object = " << js_name << js_suffix << ".to_object(interpreter, global_object);";
|
||||||
|
out() << " if (interpreter.exception())";
|
||||||
|
generate_return();
|
||||||
|
auto is_foo_wrapper_name = snake_name(String::format("Is%sWrapper", parameter.type.name.characters()));
|
||||||
|
out() << " if (!" << cpp_name << "_object->is_web_wrapper() || !static_cast<Wrapper*>(" << cpp_name << "_object)->" << is_foo_wrapper_name << "()) {";
|
||||||
|
out() << " interpreter.throw_exception<JS::TypeError>(JS::ErrorType::NotA, \"" << parameter.type.name << "\");";
|
||||||
|
generate_return();
|
||||||
|
out() << " }";
|
||||||
|
out() << " auto& " << cpp_name << " = static_cast<" << parameter.type.name << "Wrapper*>(" << cpp_name << "_object)->impl();";
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
auto generate_arguments = [&](auto& parameters, auto& arguments_builder, bool return_void = false) {
|
||||||
|
Vector<String> parameter_names;
|
||||||
|
size_t argument_index = 0;
|
||||||
|
for (auto& parameter : parameters) {
|
||||||
|
parameter_names.append(snake_name(parameter.name));
|
||||||
|
out() << " auto arg" << argument_index << " = interpreter.argument(" << argument_index << ");";
|
||||||
|
generate_to_cpp(parameter, "arg", argument_index, snake_name(parameter.name), return_void);
|
||||||
|
++argument_index;
|
||||||
|
}
|
||||||
|
|
||||||
|
arguments_builder.join(", ", parameter_names);
|
||||||
|
};
|
||||||
|
|
||||||
auto generate_return_statement = [&](auto& return_type) {
|
auto generate_return_statement = [&](auto& return_type) {
|
||||||
|
if (return_type.name == "void") {
|
||||||
|
out() << " return JS::js_undefined();";
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (return_type.nullable) {
|
if (return_type.nullable) {
|
||||||
out() << " if (!retval)";
|
if (return_type.name == "DOMString") {
|
||||||
|
out() << " if (retval.is_null())";
|
||||||
|
} else {
|
||||||
|
out() << " if (!retval)";
|
||||||
|
}
|
||||||
out() << " return JS::js_null();";
|
out() << " return JS::js_null();";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -445,7 +479,7 @@ void generate_implementation(const IDL::Interface& interface)
|
||||||
|
|
||||||
// Implementation: Attributes
|
// Implementation: Attributes
|
||||||
for (auto& attribute : interface.attributes) {
|
for (auto& attribute : interface.attributes) {
|
||||||
out() << "JS_DEFINE_NATIVE_GETTER(" << wrapper_class << "::" << snake_name(attribute.name) << "_getter)";
|
out() << "JS_DEFINE_NATIVE_GETTER(" << wrapper_class << "::" << attribute.getter_callback_name << ")";
|
||||||
out() << "{";
|
out() << "{";
|
||||||
out() << " auto* impl = impl_from(interpreter, global_object);";
|
out() << " auto* impl = impl_from(interpreter, global_object);";
|
||||||
out() << " if (!impl)";
|
out() << " if (!impl)";
|
||||||
|
@ -453,6 +487,19 @@ void generate_implementation(const IDL::Interface& interface)
|
||||||
out() << " auto retval = impl->" << snake_name(attribute.name) << "();";
|
out() << " auto retval = impl->" << snake_name(attribute.name) << "();";
|
||||||
generate_return_statement(attribute.type);
|
generate_return_statement(attribute.type);
|
||||||
out() << "}";
|
out() << "}";
|
||||||
|
|
||||||
|
if (!attribute.readonly) {
|
||||||
|
out() << "JS_DEFINE_NATIVE_SETTER(" << wrapper_class << "::" << attribute.setter_callback_name << ")";
|
||||||
|
out() << "{";
|
||||||
|
out() << " auto* impl = impl_from(interpreter, global_object);";
|
||||||
|
out() << " if (!impl)";
|
||||||
|
out() << " return;";
|
||||||
|
|
||||||
|
generate_to_cpp(attribute, "value", "", "cpp_value", true);
|
||||||
|
|
||||||
|
out() << " impl->set_" << snake_name(attribute.name) << "(cpp_value);";
|
||||||
|
out() << "}";
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Implementation: Functions
|
// Implementation: Functions
|
||||||
|
@ -465,27 +512,8 @@ void generate_implementation(const IDL::Interface& interface)
|
||||||
out() << " if (interpreter.argument_count() < " << function.length() << ")";
|
out() << " if (interpreter.argument_count() < " << function.length() << ")";
|
||||||
out() << " return interpreter.throw_exception<JS::TypeError>(JS::ErrorType::BadArgCountMany, \"" << function.name << "\", \"" << function.length() << "\");";
|
out() << " return interpreter.throw_exception<JS::TypeError>(JS::ErrorType::BadArgCountMany, \"" << function.name << "\", \"" << function.length() << "\");";
|
||||||
|
|
||||||
Vector<String> parameter_names;
|
|
||||||
size_t argument_index = 0;
|
|
||||||
for (auto& parameter : function.parameters) {
|
|
||||||
parameter_names.append(snake_name(parameter.name));
|
|
||||||
if (parameter.type.name == "DOMString") {
|
|
||||||
out() << " auto " << snake_name(parameter.name) << " = interpreter.argument(" << argument_index << ").to_string(interpreter);";
|
|
||||||
out() << " if (interpreter.exception())";
|
|
||||||
out() << " return {};";
|
|
||||||
} else if (parameter.type.name == "Node") {
|
|
||||||
out() << " auto " << snake_name(parameter.name) << "_object = interpreter.argument(" << argument_index << ").to_object(interpreter, global_object);";
|
|
||||||
out() << " if (interpreter.exception())";
|
|
||||||
out() << " return {};";
|
|
||||||
out() << " if (!" << snake_name(parameter.name) << "_object->is_web_wrapper() || !static_cast<Wrapper*>(" << snake_name(parameter.name) << "_object)->is_node_wrapper())";
|
|
||||||
out() << " return interpreter.throw_exception<JS::TypeError>(JS::ErrorType::NotA, \"" << parameter.type.name << "\");";
|
|
||||||
out() << " auto& " << snake_name(parameter.name) << " = static_cast<" << wrapper_class << "*>(" << snake_name(parameter.name) << "_object)->impl();";
|
|
||||||
}
|
|
||||||
++argument_index;
|
|
||||||
}
|
|
||||||
|
|
||||||
StringBuilder arguments_builder;
|
StringBuilder arguments_builder;
|
||||||
arguments_builder.join(", ", parameter_names);
|
generate_arguments(function.parameters, arguments_builder);
|
||||||
|
|
||||||
if (function.return_type.name != "void") {
|
if (function.return_type.name != "void") {
|
||||||
out() << " auto retval = impl->" << snake_name(function.name) << "(" << arguments_builder.to_string() << ");";
|
out() << " auto retval = impl->" << snake_name(function.name) << "(" << arguments_builder.to_string() << ");";
|
||||||
|
|
|
@ -50,6 +50,7 @@ public:
|
||||||
|
|
||||||
bool has_attribute(const FlyString& name) const { return !attribute(name).is_null(); }
|
bool has_attribute(const FlyString& name) const { return !attribute(name).is_null(); }
|
||||||
String attribute(const FlyString& name) const;
|
String attribute(const FlyString& name) const;
|
||||||
|
String get_attribute(const FlyString& name) const { return attribute(name); }
|
||||||
void set_attribute(const FlyString& name, const String& value);
|
void set_attribute(const FlyString& name, const String& value);
|
||||||
|
|
||||||
void set_attributes(Vector<Attribute>&&);
|
void set_attributes(Vector<Attribute>&&);
|
||||||
|
@ -80,6 +81,9 @@ public:
|
||||||
String inner_html() const;
|
String inner_html() const;
|
||||||
void set_inner_html(StringView);
|
void set_inner_html(StringView);
|
||||||
|
|
||||||
|
String id() const { return attribute(HTML::AttributeNames::id); }
|
||||||
|
void set_id(const String& value) { set_attribute(HTML::AttributeNames::id, value); }
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
RefPtr<LayoutNode> create_layout_node(const StyleProperties* parent_style) const override;
|
RefPtr<LayoutNode> create_layout_node(const StyleProperties* parent_style) const override;
|
||||||
|
|
||||||
|
|
10
Libraries/LibWeb/DOM/Element.idl
Normal file
10
Libraries/LibWeb/DOM/Element.idl
Normal file
|
@ -0,0 +1,10 @@
|
||||||
|
interface Element : Node {
|
||||||
|
|
||||||
|
DOMString? getAttribute(DOMString qualifiedName);
|
||||||
|
void setAttribute(DOMString qualifiedName, DOMString value);
|
||||||
|
|
||||||
|
attribute DOMString innerHTML;
|
||||||
|
attribute DOMString id;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue