Older/WebApplication/BulmaTheme.cpp

334 lines
8.9 KiB
C++
Raw Normal View History

2024-12-01 15:10:25 +08:00
#include "BulmaTheme.h"
#include "BoostLog.h"
#include <Wt/DomElement.h>
2025-01-17 21:47:26 +08:00
#include <Wt/WAbstractSpinBox.h>
2024-12-02 01:18:57 +08:00
#include <Wt/WApplication.h>
2024-12-01 15:10:25 +08:00
#include <Wt/WDialog.h>
#include <Wt/WLinkedCssStyleSheet.h>
#include <Wt/WPopupWidget.h>
#include <Wt/WPushButton.h>
#include <format>
2025-01-17 21:47:26 +08:00
#include "js/BulmaThemeValidate.js"
2024-12-01 15:10:25 +08:00
namespace std {
std::ostream &operator<<(std::ostream &os, Wt::DomElementType type);
}
2024-12-02 01:18:57 +08:00
void BulmaTheme::init(Wt::WApplication *app) const {
Wt::WString v = app->metaHeader(Wt::MetaHeaderType::Meta, "viewport");
if (v.empty()) {
// app->addMetaHeader("viewport", "width=device-width, initial-scale=1");
app->doJavaScript(R"(
var meta = document.createElement('meta');
meta.name = 'viewport';
meta.content = 'width=device-width, initial-scale=1';
document.getElementsByTagName('head')[0].appendChild(meta);
)");
}
}
2024-12-01 15:10:25 +08:00
std::string BulmaTheme::disabledClass() const {
2024-12-25 22:07:00 +08:00
return "bulma-is-disabled"; // bulma 没有这个类
2024-12-01 15:10:25 +08:00
}
std::string BulmaTheme::activeClass() const {
2024-12-25 22:07:00 +08:00
return "bulma-is-active";
2024-12-01 15:10:25 +08:00
}
std::string BulmaTheme::utilityCssClass(int utilityCssClassRole) const {
return "";
}
std::vector<Wt::WLinkedCssStyleSheet> BulmaTheme::styleSheets() const {
std::vector<Wt::WLinkedCssStyleSheet> result;
std::string themeDir = resourcesUrl();
if (m_global) {
result.push_back(Wt::WLinkedCssStyleSheet(Wt::WLink(std::format("{}base.css", themeDir))));
}
result.push_back(Wt::WLinkedCssStyleSheet(Wt::WLink(std::format("{}prefixed.css", themeDir))));
return result;
}
bool BulmaTheme::canStyleAnchorAsButton() const {
return true;
}
void BulmaTheme::apply(Wt::WWidget *widget, Wt::WWidget *child, int widgetRole) const {
2024-12-02 01:18:57 +08:00
using namespace Wt;
if (!widget->isThemeStyleEnabled()) return;
switch (widgetRole) {
case DialogContent: {
child->addStyleClass("bulma-modal-content");
break;
}
case DialogCoverWidget: {
child->addStyleClass("bulma-modal-backdrop");
break;
}
case DialogTitleBar: {
child->addStyleClass("bulma-modal-card-head");
child->setAttributeValue("style", "justify-content: space-between");
break;
}
case DialogBody: {
child->addStyleClass("bulma-modal-card-body");
break;
}
case DialogFooter: {
child->addStyleClass("bulma-modal-card-foot bulma-buttons");
break;
}
case DialogCloseIcon: {
auto parent = dynamic_cast<WContainerWidget *>(child->parent());
auto self = parent->removeWidget(child);
parent->addWidget(std::move(self));
child->addStyleClass("bulma-delete");
break;
}
2024-12-18 23:35:26 +08:00
case NavbarBtn: {
child->addStyleClass("bulma-navbar-burger");
child->setAttributeValue("aria-label", "menu");
child->setAttributeValue("aria-expanded", "false");
break;
}
case NavBrand: {
child->addStyleClass("bulma-navbar-brand");
break;
}
2024-12-02 01:18:57 +08:00
default:
break;
}
2024-12-01 15:10:25 +08:00
}
void BulmaTheme::apply(Wt::WWidget *widget, Wt::DomElement &element, int elementRole) const {
bool creating = element.mode() == Wt::DomElement::Mode::Create;
if (!widget->isThemeStyleEnabled()) return;
{
Wt::WPopupWidget *popup = dynamic_cast<Wt::WPopupWidget *>(widget);
if (popup) element.addPropertyWord(Wt::Property::Class, "Wt-outset");
}
switch (element.type()) {
case Wt::DomElementType::BUTTON: {
if (creating) {
element.addPropertyWord(Wt::Property::Class, "bulma-button");
}
break;
}
case Wt::DomElementType::DIV: {
2024-12-02 01:18:57 +08:00
if (Wt::WDialog *dialog = dynamic_cast<Wt::WDialog *>(widget); dialog != nullptr) {
element.addPropertyWord(Wt::Property::Class, "bulma-modal bulma-is-active");
return;
} else if (auto text = dynamic_cast<Wt::WText *>(widget); text != nullptr) {
element.addPropertyWord(Wt::Property::Class, "is-size-6");
2024-12-01 15:10:25 +08:00
return;
}
break;
}
2025-01-17 21:47:26 +08:00
case Wt::DomElementType::INPUT: {
auto spinBox = dynamic_cast<Wt::WAbstractSpinBox *>(widget);
if (spinBox) {
element.addPropertyWord(Wt::Property::Class, "bulma-spinbox");
return;
}
break;
}
2024-12-01 15:10:25 +08:00
default:
2025-01-03 23:51:45 +08:00
// LOG(warning) << "elemnet[" << element.type() << "] need style.";
2024-12-01 15:10:25 +08:00
break;
}
}
void BulmaTheme::applyValidationStyle(Wt::WWidget *widget, const Wt::WValidator::Result &validation,
Wt::WFlags<Wt::ValidationStyleFlag> flags) const {
2024-12-13 19:11:44 +08:00
using namespace Wt;
2025-01-17 21:47:26 +08:00
WApplication *app = WApplication::instance();
LOAD_JAVASCRIPT(app, "js/BulmaThemeValidate.js", "validate", wtjs1);
LOAD_JAVASCRIPT(app, "js/BulmaThemeValidate.js", "setValidationState", wtjs2);
2024-12-13 19:11:44 +08:00
if (flags.test(ValidationStyleFlag::InvalidStyle)) {
widget->addStyleClass("bulma-is-danger");
}
2024-12-01 15:10:25 +08:00
}
bool BulmaTheme::canBorderBoxElement(const Wt::DomElement &element) const {
return true;
}
std::string BulmaTheme::name() const {
return m_name;
}
BulmaTheme::BulmaTheme(const std::string &name, bool global) : m_name(name), m_global(global) {
}
namespace std {
std::ostream &operator<<(std::ostream &os, Wt::DomElementType type) {
using namespace Wt;
switch (type) {
case DomElementType::A:
os << "A";
break;
case DomElementType::BR:
os << "BR";
break;
case DomElementType::BUTTON:
os << "BUTTON";
break;
case DomElementType::COL:
os << "COL";
break;
case DomElementType::COLGROUP:
os << "COLGROUP";
break;
case DomElementType::DIV:
os << "DIV";
break;
case DomElementType::FIELDSET:
os << "FIELDSET";
break;
case DomElementType::FORM:
os << "FORM";
break;
case DomElementType::H1:
os << "H1";
break;
case DomElementType::H2:
os << "H2";
break;
case DomElementType::H3:
os << "H3";
break;
case DomElementType::H4:
os << "H4";
break;
case DomElementType::H5:
os << "H5";
break;
case DomElementType::H6:
os << "H6";
break;
case DomElementType::IFRAME:
os << "IFRAME";
break;
case DomElementType::IMG:
os << "IMG";
break;
case DomElementType::INPUT:
os << "INPUT";
break;
case DomElementType::LABEL:
os << "LABEL";
break;
case DomElementType::LEGEND:
os << "LEGEND";
break;
case DomElementType::LI:
os << "LI";
break;
case DomElementType::OL:
os << "OL";
break;
case DomElementType::OPTION:
os << "OPTION";
break;
case DomElementType::UL:
os << "UL";
break;
case DomElementType::SCRIPT:
os << "SCRIPT";
break;
case DomElementType::SELECT:
os << "SELECT";
break;
case DomElementType::SPAN:
os << "SPAN";
break;
case DomElementType::TABLE:
os << "TABLE";
break;
case DomElementType::TBODY:
os << "TBODY";
break;
case DomElementType::THEAD:
os << "THEAD";
break;
case DomElementType::TFOOT:
os << "TFOOT";
break;
case DomElementType::TH:
os << "TH";
break;
case DomElementType::TD:
os << "TD";
break;
case DomElementType::TEXTAREA:
os << "TEXTAREA";
break;
case DomElementType::OPTGROUP:
os << "OPTGROUP";
break;
case DomElementType::TR:
os << "TR";
break;
case DomElementType::P:
os << "P";
break;
case DomElementType::CANVAS:
os << "CANVAS";
break;
case DomElementType::MAP:
os << "MAP";
break;
case DomElementType::AREA:
os << "AREA";
break;
case DomElementType::STYLE:
os << "STYLE";
break;
case DomElementType::OBJECT:
os << "OBJECT";
break;
case DomElementType::PARAM:
os << "PARAM";
break;
case DomElementType::AUDIO:
os << "AUDIO";
break;
case DomElementType::VIDEO:
os << "VIDEO";
break;
case DomElementType::SOURCE:
os << "SOURCE";
break;
case DomElementType::B:
os << "B";
break;
case DomElementType::STRONG:
os << "STRONG";
break;
case DomElementType::EM:
os << "EM";
break;
case DomElementType::I:
os << "I";
break;
case DomElementType::HR:
os << "HR";
break;
case DomElementType::DATALIST:
os << "DATALIST";
break;
case DomElementType::UNKNOWN:
os << "UNKNOWN";
break;
case DomElementType::OTHER:
os << "OTHER";
break;
default:
os << "UNKNOWN";
break;
}
return os;
}
} // namespace std