added view

This commit is contained in:
Jorijn van der Graaf 2025-11-10 22:46:05 +01:00
commit 580e53d3bc
11 changed files with 68 additions and 34 deletions

View file

@ -4,6 +4,28 @@
Crafter.CppDOM is a C++ library that exposes the browser DOM api's to C++ WebAssembly. Crafter.CppDOM is a C++ library that exposes the browser DOM api's to C++ WebAssembly.
# HtmlElement vs HtmlElementView
The library provides two main classes for working with HTML elements:
## HtmlElementView
`HtmlElementView` is a base class that provides read and write access to HTML element properties and methods, but does **not** own the underlying DOM element. It's designed to be used when you want to interact with existing elements in the DOM without managing their lifecycle.
Key characteristics:
- Provides access to element properties and methods like `SetInnerHTML`, `SetStyle`, `AddClass`, etc.
- Supports event handling through various `Add*Listener` methods
- Does not delete the underlying DOM element when destroyed
- Used when you're working with elements that already exist in the DOM
## HtmlElement
`HtmlElement` is a derived class from `HtmlElementView` that adds ownership semantics. It creates a new DOM element when instantiated and properly manages its lifecycle.
Key characteristics:
- Inherits all functionality from `HtmlElementView`
- Creates and owns a new DOM element when constructed
- Automatically deletes the DOM element when the `HtmlElement` object is destroyed
- Used when you want to create new elements programmatically
# How to use # How to use
Please view the examples folder, this is a snippit from the HelloElement example: Please view the examples folder, this is a snippit from the HelloElement example:
@ -12,7 +34,7 @@ import Crafter.CppDOM;
using namespace Crafter::CppDOM; using namespace Crafter::CppDOM;
int main(){ int main(){
HtmlElement body("body"); HtmlElementView body("body");
body.SetInnerHTML("Hello World!"); body.SetInnerHTML("Hello World!");
} }
``` ```
@ -49,7 +71,7 @@ import Crafter.CppDOM;
using namespace Crafter::CppDOM; using namespace Crafter::CppDOM;
int main(){ int main(){
HtmlElement body("body"); HtmlElementView body("body");
body.SetInnerHTML("Hello World!"); body.SetInnerHTML("Hello World!");
} }
``` ```

View file

@ -624,6 +624,12 @@ let env = {
const cls = decoder.decode(new Int8Array(window.crafter_webbuild_wasi.instance.exports.memory.buffer, className, classNameLength)); const cls = decoder.decode(new Int8Array(window.crafter_webbuild_wasi.instance.exports.memory.buffer, className, classNameLength));
return jsmemory.get(ptr).classList.contains(cls); return jsmemory.get(ptr).classList.contains(cls);
}, },
deleteElement: function(ptr) {
const element = jsmemory.get(ptr);
if(element && element.parentNode) {
element.parentNode.removeChild(element);
}
},
addClickListener: addClickListener, addClickListener: addClickListener,
removeClickListener: removeClickListener, removeClickListener: removeClickListener,
addMouseOverListener: addMouseOverListener, addMouseOverListener: addMouseOverListener,

View file

@ -8,7 +8,7 @@ using namespace Crafter;
import std; import std;
// Create the main container element // Create the main container element
HtmlElement* body = new HtmlElement("body", "<div id='container'>" HtmlElementView* body = new HtmlElementView("body", "<div id='container'>"
"<h1>Enhanced Event Handling Demo</h1>" "<h1>Enhanced Event Handling Demo</h1>"
"<div id='events-container'>" "<div id='events-container'>"
"<div class='event-section'>" "<div class='event-section'>"
@ -58,22 +58,22 @@ HtmlElement* body = new HtmlElement("body", "<div id='container'>"
"</div>"); "</div>");
// Get references to elements // Get references to elements
HtmlElement* mouseButton = new HtmlElement("mouseButton"); HtmlElementView* mouseButton = new HtmlElementView("mouseButton");
HtmlElement* mouseOutput = new HtmlElement("mouseOutput"); HtmlElementView* mouseOutput = new HtmlElementView("mouseOutput");
HtmlElement* keyInput = new HtmlElement("keyInput"); HtmlElementView* keyInput = new HtmlElementView("keyInput");
HtmlElement* keyOutput = new HtmlElement("keyOutput"); HtmlElementView* keyOutput = new HtmlElementView("keyOutput");
HtmlElement* focusInput = new HtmlElement("focusInput"); HtmlElementView* focusInput = new HtmlElementView("focusInput");
HtmlElement* focusOutput = new HtmlElement("focusOutput"); HtmlElementView* focusOutput = new HtmlElementView("focusOutput");
HtmlElement* formInput = new HtmlElement("formInput"); HtmlElementView* formInput = new HtmlElementView("formInput");
HtmlElement* formSelect = new HtmlElement("formSelect"); HtmlElementView* formSelect = new HtmlElementView("formSelect");
HtmlElement* formElement = new HtmlElement("formElement"); HtmlElementView* formElement = new HtmlElementView("formElement");
HtmlElement* formOutput = new HtmlElement("formOutput"); HtmlElementView* formOutput = new HtmlElementView("formOutput");
HtmlElement* windowOutput = new HtmlElement("windowOutput"); HtmlElementView* windowOutput = new HtmlElementView("windowOutput");
HtmlElement* dragSource = new HtmlElement("dragSource"); HtmlElementView* dragSource = new HtmlElementView("dragSource");
HtmlElement* dropTarget = new HtmlElement("dropTarget"); HtmlElementView* dropTarget = new HtmlElementView("dropTarget");
HtmlElement* dragOutput = new HtmlElement("dragOutput"); HtmlElementView* dragOutput = new HtmlElementView("dragOutput");
HtmlElement* wheelContainer = new HtmlElement("wheelContainer"); HtmlElementView* wheelContainer = new HtmlElementView("wheelContainer");
HtmlElement* wheelOutput = new HtmlElement("wheelOutput"); HtmlElementView* wheelOutput = new HtmlElementView("wheelOutput");
int main() { int main() {
// Mouse Events // Mouse Events

View file

@ -15,7 +15,7 @@ import Crafter.CppDOM;
using namespace Crafter::CppDOM; using namespace Crafter::CppDOM;
int main(){ int main(){
HtmlElement body("body"); HtmlElementView body("body");
body.SetInnerHTML("Hello World!"); body.SetInnerHTML("Hello World!");
} }
``` ```

View file

@ -2,7 +2,7 @@ import Crafter.CppDOM;
using namespace Crafter; using namespace Crafter;
int main(){ int main(){
HtmlElement body("body"); HtmlElementView body("body");
body.SetInnerHTML("Hello World!"); body.SetInnerHTML("Hello World!");
//No need to call FreeJs, this is done in the destructor of HtmlElement. //No need to call FreeJs, this is done in the destructor of HtmlElementView.
} }

View file

@ -2,15 +2,15 @@ import Crafter.CppDOM;
import std; import std;
using namespace Crafter; using namespace Crafter;
HtmlElement body("body","<h1>Interactive Element Demo</h1>" HtmlElementView body("body","<h1>Interactive Element Demo</h1>"
"<button id='myButton'>Click Me!</button>" "<button id='myButton'>Click Me!</button>"
"<p id='output'>Click the button above</p>"); "<p id='output'>Click the button above</p>");
HtmlElement* button = new HtmlElement("myButton"); //prevent destruction HtmlElementView* button = new HtmlElement("myButton"); //prevent destruction
int main() { int main() {
button->AddClickListener([](Crafter::MouseEvent event){ button->AddClickListener([](Crafter::MouseEvent event){
auto output = HtmlElement("output"); auto output = HtmlElementView("output");
output.SetInnerHTML("Button was clicked at (" + std::to_string(event.clientX) + ", " + std::to_string(event.clientY) + ")!"); output.SetInnerHTML("Button was clicked at (" + std::to_string(event.clientX) + ", " + std::to_string(event.clientY) + ")!");
}); });
} }

View file

@ -2,9 +2,9 @@ import Crafter.CppDOM;
using namespace Crafter; using namespace Crafter;
int main(){ int main(){
HtmlElement body("body","<div id=\"myDiv\"></div>"); HtmlElementView body("body","<div id=\"myDiv\"></div>");
// Create a div element // Create a div element
HtmlElement div("myDiv"); HtmlElementView div("myDiv");
// Set some initial content // Set some initial content
div.SetInnerHTML("<p>This is a styled paragraph</p>"); div.SetInnerHTML("<p>This is a styled paragraph</p>");

View file

@ -507,8 +507,7 @@ namespace Crafter {
} }
HtmlElement::~HtmlElement() { HtmlElement::~HtmlElement() {
CppDOMBindings::DeleteElement(ptr);
} }
} }

View file

@ -105,6 +105,10 @@ extern "C" {
std::free(ptr); std::free(ptr);
} }
__attribute__((export_name("deleteElement"))) void DeleteElement(void* ptr) {
// This will be implemented in JavaScript
}
__attribute__((export_name("ExecuteClickHandler"))) void ExecuteClickHandler(std::int32_t handlerID, double clientX, double clientY, double screenX, double screenY, std::int32_t button, std::int32_t buttons, bool altKey, bool ctrlKey, bool shiftKey, bool metaKey) { __attribute__((export_name("ExecuteClickHandler"))) void ExecuteClickHandler(std::int32_t handlerID, double clientX, double clientY, double screenX, double screenY, std::int32_t button, std::int32_t buttons, bool altKey, bool ctrlKey, bool shiftKey, bool metaKey) {
Crafter::CppDOMBindings::clickHandlers->find(handlerID)->second(Crafter::MouseEvent(clientX, clientY, screenX, screenY, button, buttons, altKey, ctrlKey, shiftKey, metaKey)); Crafter::CppDOMBindings::clickHandlers->find(handlerID)->second(Crafter::MouseEvent(clientX, clientY, screenX, screenY, button, buttons, altKey, ctrlKey, shiftKey, metaKey));
} }

View file

@ -136,4 +136,6 @@ export namespace Crafter::CppDOMBindings {
bool HasClass(void* ptr, const std::string_view className) { bool HasClass(void* ptr, const std::string_view className) {
return HasClass(ptr, className.data(), className.size()); return HasClass(ptr, className.data(), className.size());
} }
__attribute__((import_module("env"), import_name("deleteElement"))) void DeleteElement(void* ptr);
} }

View file

@ -18,7 +18,7 @@ License along with this library; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/ */
export module Crafter.CppDOM:HtmlElementView; export module Crafter.CppDOM:HtmlElement;
import std; import std;
import :BindingsExport; import :BindingsExport;
import :BindingsImport; import :BindingsImport;
@ -139,8 +139,9 @@ namespace Crafter {
}; };
export class HtmlElement : public HtmlElementView { export class HtmlElement : public HtmlElementView {
HtmlElementView(const std::string_view id); public:
HtmlElementView(const std::string_view id, const std::string_view html); HtmlElement(const std::string_view id);
~HtmlElementView(); HtmlElement(const std::string_view id, const std::string_view html);
} ~HtmlElement();
};
} }