style
This commit is contained in:
parent
528e434c16
commit
224dc563e9
9 changed files with 200 additions and 46 deletions
86
README.md
86
README.md
|
|
@ -1,59 +1,53 @@
|
||||||
# About
|
# Crafter.CppDOM
|
||||||
|
|
||||||

|
A C++ DOM library for web applications that allows you to manipulate HTML elements directly from C++.
|
||||||
|
|
||||||
Crafter.CppDOM is a C++ library that exposes the browser DOM api's to C++ WebAssembly.
|
## New Styling Features
|
||||||
|
|
||||||
# How to use
|
This library now supports comprehensive styling capabilities beyond just inline HTML:
|
||||||
Please view the examples folder, this is a snippit from the HelloElement example:
|
|
||||||
|
### Style Methods
|
||||||
|
|
||||||
|
- `SetStyle(const std::string_view style)` - Sets multiple CSS properties at once
|
||||||
|
- `SetProperty(const std::string_view property, const std::string_view value)` - Sets a single CSS property
|
||||||
|
- `AddClass(const std::string_view className)` - Adds a CSS class to the element
|
||||||
|
- `RemoveClass(const std::string_view className)` - Removes a CSS class from the element
|
||||||
|
- `ToggleClass(const std::string_view className)` - Toggles a CSS class on the element
|
||||||
|
- `HasClass(const std::string_view className)` - Checks if the element has a specific CSS class
|
||||||
|
|
||||||
|
### Example Usage
|
||||||
|
|
||||||
```cpp
|
```cpp
|
||||||
import Crafter.CppDOM;
|
HtmlElement div("myDiv");
|
||||||
using namespace Crafter::CppDOM;
|
|
||||||
|
|
||||||
int main(){
|
// Set multiple styles at once
|
||||||
HtmlElement body("body");
|
div.SetStyle("color: blue; font-size: 20px; background-color: lightgray;");
|
||||||
body.SetInnerHTML("Hello World!");
|
|
||||||
}
|
|
||||||
```
|
|
||||||
You can also view the wiki for more detailed information.
|
|
||||||
|
|
||||||
It is highly recommended to use this with [Crafter.Build](https://forgejo.catcrafts.net/Catcrafts/Crafter.Build), but it is not strictly required if the same way of injecting the env is followed. The following instructions will be for Crafter.Build.
|
// Set individual properties
|
||||||
|
div.SetProperty("border", "2px solid red");
|
||||||
|
div.SetProperty("padding", "10px");
|
||||||
|
|
||||||
## Quickstart
|
// Work with CSS classes
|
||||||
create a ``project.json`` in an empty folder, open it in your preferred text editor.
|
div.AddClass("highlight");
|
||||||
Create a basic project file, that describes your web project.
|
div.AddClass("container");
|
||||||
```JSON
|
div.ToggleClass("active");
|
||||||
{
|
bool isActive = div.HasClass("active");
|
||||||
"name": "main",
|
div.RemoveClass("highlight");
|
||||||
"configurations": [
|
|
||||||
{
|
|
||||||
"name": "executable",
|
|
||||||
"implementations": ["main"],
|
|
||||||
"target": "wasm32-wasi",
|
|
||||||
"debug" : true,
|
|
||||||
"dependencies": [
|
|
||||||
{
|
|
||||||
"path":"https://forgejo.catcrafts.net/Catcrafts/Crafter.CppDOM.git",
|
|
||||||
"configuration":"lib-debug"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
```
|
```
|
||||||
|
|
||||||
Save and close the file, create a ``main.cpp``
|
### Benefits
|
||||||
```cpp
|
|
||||||
import Crafter.CppDOM;
|
|
||||||
using namespace Crafter::CppDOM;
|
|
||||||
|
|
||||||
int main(){
|
1. **Type Safety**: Compile-time checking of method names and parameters
|
||||||
HtmlElement body("body");
|
2. **Performance**: More efficient than constructing HTML strings
|
||||||
body.SetInnerHTML("Hello World!");
|
3. **Maintainability**: Clear separation between content and styling logic
|
||||||
}
|
4. **Flexibility**: Support for both inline styles and CSS classes
|
||||||
```
|
5. **Developer Experience**: Intuitive API similar to JavaScript DOM
|
||||||
|
|
||||||
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.
|
## Examples
|
||||||
|
|
||||||
This sample can also be viewed in the [HelloElement example](https://forgejo.catcrafts.net/Catcrafts/Crafter.CppDOM/src/branch/master/examples)
|
Check the examples directory for usage demonstrations:
|
||||||
|
- `HelloWorld` - Basic usage
|
||||||
|
- `HelloElement` - Creating and manipulating elements
|
||||||
|
- `InteractiveElement` - Interactive elements with event handling
|
||||||
|
- `AllEventHandling` - Complete event handling example
|
||||||
|
- `StyleExample` - Demonstrates new styling features
|
||||||
|
|
@ -600,6 +600,30 @@ let env = {
|
||||||
freeJs: freeJs,
|
freeJs: freeJs,
|
||||||
getElementById: getElementById,
|
getElementById: getElementById,
|
||||||
setInnerHTML: setInnerHTML,
|
setInnerHTML: setInnerHTML,
|
||||||
|
setStyle: function(ptr, style, styleLength) {
|
||||||
|
jsmemory.get(ptr).style.cssText = decoder.decode(new Int8Array(window.crafter_webbuild_wasi.instance.exports.memory.buffer, style, styleLength));
|
||||||
|
},
|
||||||
|
setProperty: function(ptr, property, propertyLength, value, valueLength) {
|
||||||
|
const prop = decoder.decode(new Int8Array(window.crafter_webbuild_wasi.instance.exports.memory.buffer, property, propertyLength));
|
||||||
|
const val = decoder.decode(new Int8Array(window.crafter_webbuild_wasi.instance.exports.memory.buffer, value, valueLength));
|
||||||
|
jsmemory.get(ptr).style.setProperty(prop, val);
|
||||||
|
},
|
||||||
|
addClass: function(ptr, className, classNameLength) {
|
||||||
|
const cls = decoder.decode(new Int8Array(window.crafter_webbuild_wasi.instance.exports.memory.buffer, className, classNameLength));
|
||||||
|
jsmemory.get(ptr).classList.add(cls);
|
||||||
|
},
|
||||||
|
removeClass: function(ptr, className, classNameLength) {
|
||||||
|
const cls = decoder.decode(new Int8Array(window.crafter_webbuild_wasi.instance.exports.memory.buffer, className, classNameLength));
|
||||||
|
jsmemory.get(ptr).classList.remove(cls);
|
||||||
|
},
|
||||||
|
toggleClass: function(ptr, className, classNameLength) {
|
||||||
|
const cls = decoder.decode(new Int8Array(window.crafter_webbuild_wasi.instance.exports.memory.buffer, className, classNameLength));
|
||||||
|
jsmemory.get(ptr).classList.toggle(cls);
|
||||||
|
},
|
||||||
|
hasClass: function(ptr, 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);
|
||||||
|
},
|
||||||
addClickListener: addClickListener,
|
addClickListener: addClickListener,
|
||||||
removeClickListener: removeClickListener,
|
removeClickListener: removeClickListener,
|
||||||
addMouseOverListener: addMouseOverListener,
|
addMouseOverListener: addMouseOverListener,
|
||||||
|
|
|
||||||
31
examples/StyleExample/main.cpp
Normal file
31
examples/StyleExample/main.cpp
Normal file
|
|
@ -0,0 +1,31 @@
|
||||||
|
import Crafter.CppDOM;
|
||||||
|
using namespace Crafter;
|
||||||
|
|
||||||
|
int main(){
|
||||||
|
HtmlElement body("body","<div id=\"myDiv\"></div>");
|
||||||
|
// Create a div element
|
||||||
|
HtmlElement div("myDiv");
|
||||||
|
|
||||||
|
// Set some initial content
|
||||||
|
div.SetInnerHTML("<p>This is a styled paragraph</p>");
|
||||||
|
|
||||||
|
// Apply styles using different methods
|
||||||
|
div.SetStyle("color: blue; font-size: 20px; background-color: lightgray;");
|
||||||
|
|
||||||
|
// Or apply individual properties
|
||||||
|
div.SetProperty("border", "2px solid red");
|
||||||
|
div.SetProperty("padding", "10px");
|
||||||
|
|
||||||
|
// Add CSS classes
|
||||||
|
div.AddClass("highlight");
|
||||||
|
div.AddClass("container");
|
||||||
|
|
||||||
|
// Demonstrate class toggling
|
||||||
|
div.ToggleClass("active");
|
||||||
|
|
||||||
|
// Check if class exists
|
||||||
|
bool hasActiveClass = div.HasClass("active");
|
||||||
|
|
||||||
|
// Remove a class
|
||||||
|
div.RemoveClass("highlight");
|
||||||
|
}
|
||||||
17
examples/StyleExample/project.json
Normal file
17
examples/StyleExample/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/StyleExample/run.sh
Executable file
1
examples/StyleExample/run.sh
Executable file
|
|
@ -0,0 +1 @@
|
||||||
|
caddy file-server --listen :8080 --root bin/executable
|
||||||
|
|
@ -38,6 +38,30 @@ namespace Crafter {
|
||||||
CppDOMBindings::SetInnerHTML(ptr, html);
|
CppDOMBindings::SetInnerHTML(ptr, html);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void HtmlElement::SetStyle(const std::string_view style) {
|
||||||
|
CppDOMBindings::SetStyle(ptr, style);
|
||||||
|
}
|
||||||
|
|
||||||
|
void HtmlElement::SetProperty(const std::string_view property, const std::string_view value) {
|
||||||
|
CppDOMBindings::SetProperty(ptr, property, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
void HtmlElement::AddClass(const std::string_view className) {
|
||||||
|
CppDOMBindings::AddClass(ptr, className);
|
||||||
|
}
|
||||||
|
|
||||||
|
void HtmlElement::RemoveClass(const std::string_view className) {
|
||||||
|
CppDOMBindings::RemoveClass(ptr, className);
|
||||||
|
}
|
||||||
|
|
||||||
|
void HtmlElement::ToggleClass(const std::string_view className) {
|
||||||
|
CppDOMBindings::ToggleClass(ptr, className);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool HtmlElement::HasClass(const std::string_view className) {
|
||||||
|
return CppDOMBindings::HasClass(ptr, className);
|
||||||
|
}
|
||||||
|
|
||||||
std::int32_t HtmlElement::AddClickListener(std::function<void(Crafter::MouseEvent)> callback) {
|
std::int32_t HtmlElement::AddClickListener(std::function<void(Crafter::MouseEvent)> callback) {
|
||||||
std::int32_t id = CppDOMBindings::clickHandlerMaxId++;
|
std::int32_t id = CppDOMBindings::clickHandlerMaxId++;
|
||||||
clickHandlers.push_back(id);
|
clickHandlers.push_back(id);
|
||||||
|
|
|
||||||
|
|
@ -200,4 +200,30 @@ extern "C" {
|
||||||
__attribute__((export_name("ExecuteDragLeaveHandler"))) void ExecuteDragLeaveHandler(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("ExecuteDragLeaveHandler"))) void ExecuteDragLeaveHandler(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::dragLeaveHandlers->find(handlerID)->second(Crafter::MouseEvent(clientX, clientY, screenX, screenY, button, buttons, altKey, ctrlKey, shiftKey, metaKey));
|
Crafter::CppDOMBindings::dragLeaveHandlers->find(handlerID)->second(Crafter::MouseEvent(clientX, clientY, screenX, screenY, button, buttons, altKey, ctrlKey, shiftKey, metaKey));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Style functions
|
||||||
|
__attribute__((export_name("setStyle"))) void SetStyle(void* ptr, const char* style, std::size_t styleLength) {
|
||||||
|
// This will be implemented in JavaScript
|
||||||
|
}
|
||||||
|
|
||||||
|
__attribute__((export_name("setProperty"))) void SetProperty(void* ptr, const char* property, std::size_t propertyLength, const char* value, std::size_t valueLength) {
|
||||||
|
// This will be implemented in JavaScript
|
||||||
|
}
|
||||||
|
|
||||||
|
__attribute__((export_name("addClass"))) void AddClass(void* ptr, const char* className, std::size_t classNameLength) {
|
||||||
|
// This will be implemented in JavaScript
|
||||||
|
}
|
||||||
|
|
||||||
|
__attribute__((export_name("removeClass"))) void RemoveClass(void* ptr, const char* className, std::size_t classNameLength) {
|
||||||
|
// This will be implemented in JavaScript
|
||||||
|
}
|
||||||
|
|
||||||
|
__attribute__((export_name("toggleClass"))) void ToggleClass(void* ptr, const char* className, std::size_t classNameLength) {
|
||||||
|
// This will be implemented in JavaScript
|
||||||
|
}
|
||||||
|
|
||||||
|
__attribute__((export_name("hasClass"))) bool HasClass(void* ptr, const char* className, std::size_t classNameLength) {
|
||||||
|
// This will be implemented in JavaScript
|
||||||
|
return false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -105,4 +105,35 @@ export namespace Crafter::CppDOMBindings {
|
||||||
|
|
||||||
__attribute__((import_module("env"), import_name("addDragLeaveListener"))) void AddDragLeaveListener(void* ptr, int id);
|
__attribute__((import_module("env"), import_name("addDragLeaveListener"))) void AddDragLeaveListener(void* ptr, int id);
|
||||||
__attribute__((import_module("env"), import_name("removeDragLeaveListener"))) void RemoveDragLeaveListener(void* ptr, int id);
|
__attribute__((import_module("env"), import_name("removeDragLeaveListener"))) void RemoveDragLeaveListener(void* ptr, int id);
|
||||||
|
|
||||||
|
// Style functions
|
||||||
|
__attribute__((import_module("env"), import_name("setStyle"))) void SetStyle(void* ptr, const char* style, std::size_t styleLength);
|
||||||
|
void SetStyle(void* ptr, const std::string_view style) {
|
||||||
|
SetStyle(ptr, style.data(), style.size());
|
||||||
|
}
|
||||||
|
|
||||||
|
__attribute__((import_module("env"), import_name("setProperty"))) void SetProperty(void* ptr, const char* property, std::size_t propertyLength, const char* value, std::size_t valueLength);
|
||||||
|
void SetProperty(void* ptr, const std::string_view property, const std::string_view value) {
|
||||||
|
SetProperty(ptr, property.data(), property.size(), value.data(), value.size());
|
||||||
|
}
|
||||||
|
|
||||||
|
__attribute__((import_module("env"), import_name("addClass"))) void AddClass(void* ptr, const char* className, std::size_t classNameLength);
|
||||||
|
void AddClass(void* ptr, const std::string_view className) {
|
||||||
|
AddClass(ptr, className.data(), className.size());
|
||||||
|
}
|
||||||
|
|
||||||
|
__attribute__((import_module("env"), import_name("removeClass"))) void RemoveClass(void* ptr, const char* className, std::size_t classNameLength);
|
||||||
|
void RemoveClass(void* ptr, const std::string_view className) {
|
||||||
|
RemoveClass(ptr, className.data(), className.size());
|
||||||
|
}
|
||||||
|
|
||||||
|
__attribute__((import_module("env"), import_name("toggleClass"))) void ToggleClass(void* ptr, const char* className, std::size_t classNameLength);
|
||||||
|
void ToggleClass(void* ptr, const std::string_view className) {
|
||||||
|
ToggleClass(ptr, className.data(), className.size());
|
||||||
|
}
|
||||||
|
|
||||||
|
__attribute__((import_module("env"), import_name("hasClass"))) bool HasClass(void* ptr, const char* className, std::size_t classNameLength);
|
||||||
|
bool HasClass(void* ptr, const std::string_view className) {
|
||||||
|
return HasClass(ptr, className.data(), className.size());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -56,6 +56,12 @@ namespace Crafter {
|
||||||
HtmlElement(const std::string_view id);
|
HtmlElement(const std::string_view id);
|
||||||
HtmlElement(const std::string_view id, const std::string_view html);
|
HtmlElement(const std::string_view id, const std::string_view html);
|
||||||
void SetInnerHTML(const std::string_view html);
|
void SetInnerHTML(const std::string_view html);
|
||||||
|
void SetStyle(const std::string_view style);
|
||||||
|
void SetProperty(const std::string_view property, const std::string_view value);
|
||||||
|
void AddClass(const std::string_view className);
|
||||||
|
void RemoveClass(const std::string_view className);
|
||||||
|
void ToggleClass(const std::string_view className);
|
||||||
|
bool HasClass(const std::string_view className);
|
||||||
|
|
||||||
std::int32_t AddClickListener(std::function<void(Crafter::MouseEvent)> callback);
|
std::int32_t AddClickListener(std::function<void(Crafter::MouseEvent)> callback);
|
||||||
void RemoveClickListener(std::int32_t id);
|
void RemoveClickListener(std::int32_t id);
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue