2024-12-01 15:10:25 +08:00
|
|
|
#include "BulmaTheme.h"
|
|
|
|
#include "BoostLog.h"
|
|
|
|
#include <Wt/DomElement.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>
|
|
|
|
|
|
|
|
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 {
|
|
|
|
return "";
|
|
|
|
}
|
|
|
|
|
|
|
|
std::string BulmaTheme::activeClass() const {
|
|
|
|
return "";
|
|
|
|
}
|
|
|
|
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
default:
|
|
|
|
LOG(warning) << "elemnet[" << element.type() << "] need style.";
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
LOG(info) << "BulmaTheme::apply";
|
|
|
|
}
|
|
|
|
|
|
|
|
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;
|
|
|
|
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
|