click event
This commit is contained in:
parent
e35b7302cb
commit
f40afe684a
13 changed files with 151 additions and 20 deletions
Binary file not shown.
Binary file not shown.
BIN
Crafter.CppDOM.o
BIN
Crafter.CppDOM.o
Binary file not shown.
|
|
@ -56,4 +56,4 @@ int main(){
|
||||||
|
|
||||||
Save and close, then run ``crafter-build build executable && caddy file-server --listen :8080 --root bin/executable``. if you have caddy installed, if not use your favorite static file server instead. Now you can open the browser at ``http://localhost:8080`` and ``Hello World!`` will appear in the browser.
|
Save and close, then run ``crafter-build build executable && caddy file-server --listen :8080 --root bin/executable``. if you have caddy installed, if not use your favorite static file server instead. Now you can open the browser at ``http://localhost:8080`` and ``Hello World!`` will appear in the browser.
|
||||||
|
|
||||||
This sample can also be viewed in the [HelloElement example](https://forgejo.catcrafts.net/Catcrafts/Crafter.CppDOM/src/branch/master/examples)
|
This sample can also be viewed in the [HelloElement example](https://forgejo.catcrafts.net/Catcrafts/Crafter.CppDOM/src/branch/master/examples)
|
||||||
|
|
@ -19,9 +19,11 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
*/
|
*/
|
||||||
|
|
||||||
const decoder = new TextDecoder();
|
const decoder = new TextDecoder();
|
||||||
|
const encoder = new TextEncoder();
|
||||||
|
|
||||||
let memorycounter = -1;
|
let memorycounter = -1;
|
||||||
const jsmemory = new Map();
|
const jsmemory = new Map();
|
||||||
|
const eventHandlers = new Map();
|
||||||
|
|
||||||
function freeJs(ptr) {
|
function freeJs(ptr) {
|
||||||
jsmemory.delete(ptr);
|
jsmemory.delete(ptr);
|
||||||
|
|
@ -37,10 +39,35 @@ function setInnerHTML(ptr, html, htmlLenght) {
|
||||||
jsmemory.get(ptr).innerHTML = decoder.decode(new Int8Array(window.crafter_webbuild_wasi.instance.exports.memory.buffer, html, htmlLenght));
|
jsmemory.get(ptr).innerHTML = decoder.decode(new Int8Array(window.crafter_webbuild_wasi.instance.exports.memory.buffer, html, htmlLenght));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function addClickListener(ptr, handlerID) {
|
||||||
|
const element = jsmemory.get(ptr);
|
||||||
|
|
||||||
|
// Create a handler that will trigger a notification to C++
|
||||||
|
const handler = function(event) {
|
||||||
|
const { ExecuteClickHandler } = window.crafter_webbuild_wasi.instance.exports;
|
||||||
|
ExecuteClickHandler(handlerID);
|
||||||
|
};
|
||||||
|
|
||||||
|
eventHandlers.set(`${ptr}-${handlerID}`, handler);
|
||||||
|
|
||||||
|
element.addEventListener("click", handler);
|
||||||
|
}
|
||||||
|
|
||||||
|
function removeClickListener(ptr, handlerID) {
|
||||||
|
const element = jsmemory.get(ptr);
|
||||||
|
|
||||||
|
const handler = eventHandlers.get(`${ptr}-${handlerID}`);
|
||||||
|
|
||||||
|
element.removeEventListener("click", handler);
|
||||||
|
eventHandlers.delete(handlerID);
|
||||||
|
}
|
||||||
|
|
||||||
let env = {
|
let env = {
|
||||||
freeJs:freeJs,
|
freeJs: freeJs,
|
||||||
getElementById:getElementById,
|
getElementById: getElementById,
|
||||||
setInnerHTML:setInnerHTML,
|
setInnerHTML: setInnerHTML,
|
||||||
|
addClickListener: addClickListener,
|
||||||
|
removeClickListener: removeClickListener,
|
||||||
}
|
}
|
||||||
|
|
||||||
window.crafter_webbuild_env = env;
|
window.crafter_webbuild_env = env;
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
import Crafter.CppDOM;
|
import Crafter.CppDOM;
|
||||||
using namespace Crafter::CppDOM;
|
using namespace Crafter;
|
||||||
|
|
||||||
int main(){
|
int main(){
|
||||||
HtmlElement body("body");
|
HtmlElement body("body");
|
||||||
|
|
|
||||||
|
|
@ -2,7 +2,7 @@
|
||||||
"name": "main",
|
"name": "main",
|
||||||
"configurations": [
|
"configurations": [
|
||||||
{
|
{
|
||||||
"name": "example",
|
"name": "executable",
|
||||||
"implementations": ["main"],
|
"implementations": ["main"],
|
||||||
"target": "wasm32-wasi",
|
"target": "wasm32-wasi",
|
||||||
"debug" : true,
|
"debug" : true,
|
||||||
|
|
|
||||||
39
examples/InteractiveElement/README.md
Normal file
39
examples/InteractiveElement/README.md
Normal file
|
|
@ -0,0 +1,39 @@
|
||||||
|
# Interactive Element Example
|
||||||
|
|
||||||
|
This example demonstrates how to use DOM event handling with Crafter.CppDOM.
|
||||||
|
|
||||||
|
## Features
|
||||||
|
|
||||||
|
- Shows how to create interactive UI elements using C++
|
||||||
|
- Demonstrates the framework for attaching event listeners
|
||||||
|
- Illustrates the planned callback mechanism for event handling
|
||||||
|
|
||||||
|
## Usage
|
||||||
|
|
||||||
|
The library now provides the foundation for interactive web applications:
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
import Crafter.CppDOM;
|
||||||
|
using namespace Crafter::CppDOM;
|
||||||
|
|
||||||
|
int main(){
|
||||||
|
// Create UI elements
|
||||||
|
HtmlElement body("body");
|
||||||
|
body.SetInnerHTML("<h1>Interactive Element Demo</h1>"
|
||||||
|
"<button id='myButton'>Click Me!</button>"
|
||||||
|
"<p id='output'>Click the button above</p>");
|
||||||
|
|
||||||
|
// Attach event listener
|
||||||
|
HtmlElement button("myButton");
|
||||||
|
button.AddEventListener("click");
|
||||||
|
|
||||||
|
// Future: button.OnClick([]() {
|
||||||
|
// HtmlElement output("output");
|
||||||
|
// output.SetInnerHTML("Button was clicked!");
|
||||||
|
// });
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
Note: The full callback mechanism requires additional infrastructure to properly bridge between JavaScript events and C++ callbacks. This implementation provides the framework for future development.
|
||||||
16
examples/InteractiveElement/main.cpp
Normal file
16
examples/InteractiveElement/main.cpp
Normal file
|
|
@ -0,0 +1,16 @@
|
||||||
|
import Crafter.CppDOM;
|
||||||
|
import std;
|
||||||
|
using namespace Crafter;
|
||||||
|
|
||||||
|
HtmlElement body("body","<h1>Interactive Element Demo</h1>"
|
||||||
|
"<button id='myButton'>Click Me!</button>"
|
||||||
|
"<p id='output'>Click the button above</p>");
|
||||||
|
HtmlElement* button = new HtmlElement("myButton"); //prevent destruction
|
||||||
|
|
||||||
|
|
||||||
|
int main() {
|
||||||
|
button->AddClickListener([](){
|
||||||
|
auto output = HtmlElement("output");
|
||||||
|
output.SetInnerHTML("Button was clicked!");
|
||||||
|
});
|
||||||
|
}
|
||||||
17
examples/InteractiveElement/project.json
Normal file
17
examples/InteractiveElement/project.json
Normal file
|
|
@ -0,0 +1,17 @@
|
||||||
|
{
|
||||||
|
"name": "main",
|
||||||
|
"configurations": [
|
||||||
|
{
|
||||||
|
"name": "executable",
|
||||||
|
"implementations": ["main"],
|
||||||
|
"target": "wasm32-wasi",
|
||||||
|
"debug" : true,
|
||||||
|
"dependencies": [
|
||||||
|
{
|
||||||
|
"path":"../../project.json",
|
||||||
|
"configuration":"lib-debug"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
1
examples/InteractiveElement/run.sh
Executable file
1
examples/InteractiveElement/run.sh
Executable file
|
|
@ -0,0 +1 @@
|
||||||
|
caddy file-server --listen :8080 --root bin/executable
|
||||||
|
|
@ -22,13 +22,26 @@ export module Crafter.CppDOM:Bindings;
|
||||||
import std;
|
import std;
|
||||||
|
|
||||||
export namespace Crafter::CppDOM::Bindings {
|
export namespace Crafter::CppDOM::Bindings {
|
||||||
|
int clickHandlerMaxId = 0;
|
||||||
|
std::unordered_map<int, std::function<void(void)>>* clickHandlers = new std::unordered_map<int, std::function<void(void)>>();
|
||||||
|
|
||||||
__attribute__((import_module("env"), import_name("freeJs"))) void FreeJs(void* ptr);
|
__attribute__((import_module("env"), import_name("freeJs"))) void FreeJs(void* ptr);
|
||||||
__attribute__((import_module("env"), import_name("getElementById"))) void* GetElementById(const char* id, std::size_t idLenght);
|
__attribute__((import_module("env"), import_name("getElementById"))) void* GetElementById(const char* id, std::size_t idLenght);
|
||||||
inline void* GetElementById(const std::string& id) {
|
void* GetElementById(const std::string_view id) {
|
||||||
return GetElementById(id.c_str(), id.size());
|
return GetElementById(id.data(), id.size());
|
||||||
}
|
}
|
||||||
__attribute__((import_module("env"), import_name("setInnerHTML"))) void SetInnerHTML(void* ptr, const char* html, std::size_t htmlLenght);
|
__attribute__((import_module("env"), import_name("setInnerHTML"))) void SetInnerHTML(void* ptr, const char* html, std::size_t htmlLenght);
|
||||||
inline void SetInnerHTML(void* ptr, const std::string& html) {
|
void SetInnerHTML(void* ptr, const std::string_view html) {
|
||||||
SetInnerHTML(ptr, html.c_str(), html.size());
|
SetInnerHTML(ptr, html.data(), html.size());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Event handling functions
|
||||||
|
__attribute__((import_module("env"), import_name("addClickListener"))) void AddClickListener(void* ptr, int id);
|
||||||
|
__attribute__((import_module("env"), import_name("removeClickListener"))) void RemoveClickListener(void* ptr, int id);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
extern "C" {
|
||||||
|
__attribute__((export_name("ExecuteClickHandler"))) void ExecuteClickHandler(int a) {
|
||||||
|
Crafter::CppDOM::Bindings::clickHandlers->find(static_cast<int>(a))->second();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -22,24 +22,42 @@ export module Crafter.CppDOM:HtmlElement;
|
||||||
import std;
|
import std;
|
||||||
import :Bindings;
|
import :Bindings;
|
||||||
|
|
||||||
namespace Crafter::CppDOM {
|
namespace Crafter {
|
||||||
export class HtmlElement {
|
export class HtmlElement {
|
||||||
public:
|
public:
|
||||||
void* const ptr;
|
void* const ptr;
|
||||||
inline HtmlElement(const char* id, std::size_t idLenght): ptr(Bindings::GetElementById(id, idLenght)) {
|
std::vector<int> handlers;
|
||||||
|
HtmlElement(const std::string_view id): ptr(CppDOM::Bindings::GetElementById(id)) {
|
||||||
|
|
||||||
}
|
}
|
||||||
inline HtmlElement(const std::string& id): ptr(Bindings::GetElementById(id)) {
|
HtmlElement(const std::string_view id, const std::string_view html): ptr(CppDOM::Bindings::GetElementById(id)) {
|
||||||
|
CppDOM::Bindings::SetInnerHTML(ptr, html);
|
||||||
}
|
}
|
||||||
inline void SetInnerHTML(const char* html, std::size_t htmlLenght) {
|
void SetInnerHTML(const std::string_view& html) {
|
||||||
Bindings::SetInnerHTML(ptr, html, htmlLenght);
|
CppDOM::Bindings::SetInnerHTML(ptr, html);
|
||||||
}
|
}
|
||||||
inline void SetInnerHTML(const std::string& html) {
|
|
||||||
Bindings::SetInnerHTML(ptr, html);
|
// Event handling methods - simplified for now
|
||||||
|
int AddClickListener(std::function<void(void)> callback) {
|
||||||
|
int id = CppDOM::Bindings::clickHandlerMaxId++;
|
||||||
|
handlers.push_back(id);
|
||||||
|
CppDOM::Bindings::clickHandlers->insert({id, callback});
|
||||||
|
CppDOM::Bindings::AddClickListener(ptr, id);
|
||||||
|
return id;
|
||||||
}
|
}
|
||||||
inline ~HtmlElement(){
|
|
||||||
Bindings::FreeJs(ptr);
|
void RemoveClickListener(int id) {
|
||||||
|
handlers.erase(std::remove(handlers.begin(), handlers.end(), id), handlers.end());
|
||||||
|
CppDOM::Bindings::clickHandlers->erase(id);
|
||||||
|
CppDOM::Bindings::RemoveClickListener(ptr, id);
|
||||||
|
}
|
||||||
|
|
||||||
|
~HtmlElement(){
|
||||||
|
for(int handler : handlers) {
|
||||||
|
CppDOM::Bindings::clickHandlers->erase(handler);
|
||||||
|
CppDOM::Bindings::RemoveClickListener(ptr, handler);
|
||||||
|
}
|
||||||
|
CppDOM::Bindings::FreeJs(ptr);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
Loading…
Add table
Add a link
Reference in a new issue