diff --git a/README.md b/README.md index 20a4f00..096032f 100644 --- a/README.md +++ b/README.md @@ -4,6 +4,28 @@ 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 Please view the examples folder, this is a snippit from the HelloElement example: @@ -12,7 +34,7 @@ import Crafter.CppDOM; using namespace Crafter::CppDOM; int main(){ - HtmlElement body("body"); + HtmlElementView body("body"); body.SetInnerHTML("Hello World!"); } ``` @@ -49,7 +71,7 @@ import Crafter.CppDOM; using namespace Crafter::CppDOM; int main(){ - HtmlElement body("body"); + HtmlElementView body("body"); body.SetInnerHTML("Hello World!"); } ``` diff --git a/additional/env.js b/additional/env.js index a379805..c5645c5 100644 --- a/additional/env.js +++ b/additional/env.js @@ -624,6 +624,12 @@ let env = { const cls = decoder.decode(new Int8Array(window.crafter_webbuild_wasi.instance.exports.memory.buffer, className, classNameLength)); 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, removeClickListener: removeClickListener, addMouseOverListener: addMouseOverListener, diff --git a/examples/AllEventHandling/main.cpp b/examples/AllEventHandling/main.cpp index b477bc7..584caf5 100644 --- a/examples/AllEventHandling/main.cpp +++ b/examples/AllEventHandling/main.cpp @@ -8,7 +8,7 @@ using namespace Crafter; import std; // Create the main container element -HtmlElement* body = new HtmlElement("body", "
" +HtmlElementView* body = new HtmlElementView("body", "
" "

Enhanced Event Handling Demo

" "
" "
" @@ -58,22 +58,22 @@ HtmlElement* body = new HtmlElement("body", "
" "
"); // Get references to elements -HtmlElement* mouseButton = new HtmlElement("mouseButton"); -HtmlElement* mouseOutput = new HtmlElement("mouseOutput"); -HtmlElement* keyInput = new HtmlElement("keyInput"); -HtmlElement* keyOutput = new HtmlElement("keyOutput"); -HtmlElement* focusInput = new HtmlElement("focusInput"); -HtmlElement* focusOutput = new HtmlElement("focusOutput"); -HtmlElement* formInput = new HtmlElement("formInput"); -HtmlElement* formSelect = new HtmlElement("formSelect"); -HtmlElement* formElement = new HtmlElement("formElement"); -HtmlElement* formOutput = new HtmlElement("formOutput"); -HtmlElement* windowOutput = new HtmlElement("windowOutput"); -HtmlElement* dragSource = new HtmlElement("dragSource"); -HtmlElement* dropTarget = new HtmlElement("dropTarget"); -HtmlElement* dragOutput = new HtmlElement("dragOutput"); -HtmlElement* wheelContainer = new HtmlElement("wheelContainer"); -HtmlElement* wheelOutput = new HtmlElement("wheelOutput"); +HtmlElementView* mouseButton = new HtmlElementView("mouseButton"); +HtmlElementView* mouseOutput = new HtmlElementView("mouseOutput"); +HtmlElementView* keyInput = new HtmlElementView("keyInput"); +HtmlElementView* keyOutput = new HtmlElementView("keyOutput"); +HtmlElementView* focusInput = new HtmlElementView("focusInput"); +HtmlElementView* focusOutput = new HtmlElementView("focusOutput"); +HtmlElementView* formInput = new HtmlElementView("formInput"); +HtmlElementView* formSelect = new HtmlElementView("formSelect"); +HtmlElementView* formElement = new HtmlElementView("formElement"); +HtmlElementView* formOutput = new HtmlElementView("formOutput"); +HtmlElementView* windowOutput = new HtmlElementView("windowOutput"); +HtmlElementView* dragSource = new HtmlElementView("dragSource"); +HtmlElementView* dropTarget = new HtmlElementView("dropTarget"); +HtmlElementView* dragOutput = new HtmlElementView("dragOutput"); +HtmlElementView* wheelContainer = new HtmlElementView("wheelContainer"); +HtmlElementView* wheelOutput = new HtmlElementView("wheelOutput"); int main() { // Mouse Events diff --git a/examples/HelloElement/README.md b/examples/HelloElement/README.md index 52b9dde..1a4ec5a 100644 --- a/examples/HelloElement/README.md +++ b/examples/HelloElement/README.md @@ -15,7 +15,7 @@ import Crafter.CppDOM; using namespace Crafter::CppDOM; int main(){ - HtmlElement body("body"); + HtmlElementView body("body"); body.SetInnerHTML("Hello World!"); } ``` diff --git a/examples/HelloElement/main.cpp b/examples/HelloElement/main.cpp index fce4639..366f298 100644 --- a/examples/HelloElement/main.cpp +++ b/examples/HelloElement/main.cpp @@ -2,7 +2,7 @@ import Crafter.CppDOM; using namespace Crafter; int main(){ - HtmlElement body("body"); + HtmlElementView body("body"); 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. } \ No newline at end of file diff --git a/examples/InteractiveElement/main.cpp b/examples/InteractiveElement/main.cpp index 371ca9b..9a7691f 100644 --- a/examples/InteractiveElement/main.cpp +++ b/examples/InteractiveElement/main.cpp @@ -2,15 +2,15 @@ import Crafter.CppDOM; import std; using namespace Crafter; -HtmlElement body("body","

Interactive Element Demo

" +HtmlElementView body("body","

Interactive Element Demo

" "" "

Click the button above

"); -HtmlElement* button = new HtmlElement("myButton"); //prevent destruction +HtmlElementView* button = new HtmlElement("myButton"); //prevent destruction int main() { 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) + ")!"); }); } \ No newline at end of file diff --git a/examples/StyleExample/main.cpp b/examples/StyleExample/main.cpp index 251fe24..5fa2db2 100644 --- a/examples/StyleExample/main.cpp +++ b/examples/StyleExample/main.cpp @@ -2,9 +2,9 @@ import Crafter.CppDOM; using namespace Crafter; int main(){ - HtmlElement body("body","
"); + HtmlElementView body("body","
"); // Create a div element - HtmlElement div("myDiv"); + HtmlElementView div("myDiv"); // Set some initial content div.SetInnerHTML("

This is a styled paragraph

"); diff --git a/implementations/Crafter.CppDOM-HtmlElement.cpp b/implementations/Crafter.CppDOM-HtmlElement.cpp index 199f157..921f277 100644 --- a/implementations/Crafter.CppDOM-HtmlElement.cpp +++ b/implementations/Crafter.CppDOM-HtmlElement.cpp @@ -507,8 +507,7 @@ namespace Crafter { } HtmlElement::~HtmlElement() { - + CppDOMBindings::DeleteElement(ptr); } - } diff --git a/interfaces/Crafter.CppDOM-BindingsExport.cppm b/interfaces/Crafter.CppDOM-BindingsExport.cppm index f6647da..02d45f2 100644 --- a/interfaces/Crafter.CppDOM-BindingsExport.cppm +++ b/interfaces/Crafter.CppDOM-BindingsExport.cppm @@ -105,6 +105,10 @@ extern "C" { 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) { Crafter::CppDOMBindings::clickHandlers->find(handlerID)->second(Crafter::MouseEvent(clientX, clientY, screenX, screenY, button, buttons, altKey, ctrlKey, shiftKey, metaKey)); } diff --git a/interfaces/Crafter.CppDOM-BindingsImport.cppm b/interfaces/Crafter.CppDOM-BindingsImport.cppm index 56db1fb..07d5efb 100644 --- a/interfaces/Crafter.CppDOM-BindingsImport.cppm +++ b/interfaces/Crafter.CppDOM-BindingsImport.cppm @@ -136,4 +136,6 @@ export namespace Crafter::CppDOMBindings { bool HasClass(void* ptr, const std::string_view className) { return HasClass(ptr, className.data(), className.size()); } + + __attribute__((import_module("env"), import_name("deleteElement"))) void DeleteElement(void* ptr); } \ No newline at end of file diff --git a/interfaces/Crafter.CppDOM-HtmlElement.cppm b/interfaces/Crafter.CppDOM-HtmlElement.cppm index ebd5288..71b64d0 100644 --- a/interfaces/Crafter.CppDOM-HtmlElement.cppm +++ b/interfaces/Crafter.CppDOM-HtmlElement.cppm @@ -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 */ -export module Crafter.CppDOM:HtmlElementView; +export module Crafter.CppDOM:HtmlElement; import std; import :BindingsExport; import :BindingsImport; @@ -139,8 +139,9 @@ namespace Crafter { }; export class HtmlElement : public HtmlElementView { - HtmlElementView(const std::string_view id); - HtmlElementView(const std::string_view id, const std::string_view html); - ~HtmlElementView(); - } + public: + HtmlElement(const std::string_view id); + HtmlElement(const std::string_view id, const std::string_view html); + ~HtmlElement(); + }; } \ No newline at end of file