Loading editor/src/htmlimport.cpp +73 −0 Original line number Diff line number Diff line Loading @@ -661,6 +661,57 @@ void applyFlexLayoutAttributes(tinyxml2::XMLElement *w, } } // @p mediaRules (see extractCustomCss's parameter of the same name) is kept // as raw "@media(...) { <original-selector> { ... } }" text, verbatim from // libhtmlpp::getCSSRules -- including whatever selector the source // stylesheet actually used, e.g. ".con-kit-col[data-col-lg=\"6\"]". A class // in that selector still matches after import (see cssClass -> css_class), // but an attribute-selector condition like "[data-col-lg=\"6\"]" silently // stops matching: no widget's Render() re-emits arbitrary source `data-*` // attributes onto the element it produces, only class/style. Found on a // real page-builder site (bautenschutz-wetzlar.de) whose responsive column // widths are ONLY ever set inside such a media-query rule (no plain/base // declaration at all) -- every widget kept exactly the widget's default // (auto) width at every breakpoint instead, silently un-doing an intended // side-by-side layout. Scans @p mediaRules for every "[attrName...]" // condition and returns an HTML-attribute-serialized string // (`name="value"`, space-separated) for whichever of those names @p // elemAttrs (this element's own real attributes, see its declaration // above) actually has a value for -- so the caller can stash it on the // widget and have Render() re-apply just those specific attributes, // without a general (larger, riskier) passthrough of every source // attribute on every widget. Serialized as "name=value" pairs joined by // ";" -- deliberately not HTML/XML attribute syntax (no quoting) since the // values in play here (page-builder breakpoint/variant tokens like "6" or // "solid") never contain ";"/"=" themselves, and this keeps the widget-side // parser (see each widget's applyDataAttrs-style Render() code) trivial // instead of needing to un-escape a quoted sub-value out of an already // tinyxml2-escaped XML attribute. std::string extractReferencedDataAttrs(const std::string &mediaRules, const std::map<std::string,std::string> &elemAttrs) { std::string result; std::set<std::string> seen; size_t pos = 0; while (pos < mediaRules.size()) { size_t open = mediaRules.find('[', pos); if (open == std::string::npos) break; size_t close = mediaRules.find(']', open + 1); if (close == std::string::npos) break; size_t nameEnd = mediaRules.find_first_of("=~|^$*]", open + 1); if (nameEnd == std::string::npos || nameEnd > close) nameEnd = close; std::string name = mediaRules.substr(open + 1, nameEnd - (open + 1)); pos = close + 1; if (name.empty() || seen.count(name)) continue; seen.insert(name); auto it = elemAttrs.find(name); if (it == elemAttrs.end()) continue; if (!result.empty()) result += ";"; result += name + "=" + it->second; } return result; } // Merges this element's own --custom-property declarations onto the // inherited environment (own values override inherited -- innermost scope // wins, matching real CSS custom-property cascade/inheritance), resolves Loading Loading @@ -1161,6 +1212,8 @@ void blogi::htmlimport::htmlElementToWidgetXml( applyFlexLayoutAttributes(w, cssProps, knownCss); std::string newInstanceId; std::string custom = extractCustomCss(cssProps, knownCss, mediaRules, newInstanceId); std::string dataAttrs = extractReferencedDataAttrs(mediaRules, elemAttrs); if (!dataAttrs.empty()) w->SetAttribute("data_attrs", dataAttrs.c_str()); finalizeInstanceId(w, elemId, newInstanceId, idToInstanceId); if (!custom.empty()) { tinyxml2::XMLElement *ccEl = doc.NewElement("CustomCss"); Loading Loading @@ -1206,6 +1259,8 @@ void blogi::htmlimport::htmlElementToWidgetXml( applyFlexLayoutAttributes(w, cssProps, knownCss); std::string newInstanceId; std::string custom = extractCustomCss(cssProps, knownCss, mediaRules, newInstanceId); std::string dataAttrs = extractReferencedDataAttrs(mediaRules, elemAttrs); if (!dataAttrs.empty()) w->SetAttribute("data_attrs", dataAttrs.c_str()); finalizeInstanceId(w, elemId, newInstanceId, idToInstanceId); if (!custom.empty()) { tinyxml2::XMLElement *ccEl = doc.NewElement("CustomCss"); Loading Loading @@ -1283,6 +1338,8 @@ void blogi::htmlimport::htmlElementToWidgetXml( } std::string newInstanceId; std::string custom = extractCustomCss(cssProps, knownCss, mediaRules, newInstanceId); std::string dataAttrs = extractReferencedDataAttrs(mediaRules, elemAttrs); if (!dataAttrs.empty()) w->SetAttribute("data_attrs", dataAttrs.c_str()); finalizeInstanceId(w, elemId, newInstanceId, idToInstanceId); if (!custom.empty()) { tinyxml2::XMLElement *ccEl = doc.NewElement("CustomCss"); Loading @@ -1303,6 +1360,8 @@ void blogi::htmlimport::htmlElementToWidgetXml( applyFlexLayoutAttributes(w, cssProps, knownCss); std::string newInstanceId; std::string custom = extractCustomCss(cssProps, knownCss, mediaRules, newInstanceId); std::string dataAttrs = extractReferencedDataAttrs(mediaRules, elemAttrs); if (!dataAttrs.empty()) w->SetAttribute("data_attrs", dataAttrs.c_str()); finalizeInstanceId(w, elemId, newInstanceId, idToInstanceId); if (!custom.empty()) { tinyxml2::XMLElement *ccEl = doc.NewElement("CustomCss"); Loading Loading @@ -1338,6 +1397,8 @@ void blogi::htmlimport::htmlElementToWidgetXml( "display","visibility"}; std::string newInstanceId; std::string custom = extractCustomCss(cssProps, knownCss, mediaRules, newInstanceId); std::string dataAttrs = extractReferencedDataAttrs(mediaRules, elemAttrs); if (!dataAttrs.empty()) w->SetAttribute("data_attrs", dataAttrs.c_str()); finalizeInstanceId(w, elemId, newInstanceId, idToInstanceId); if (!custom.empty()) { tinyxml2::XMLElement *ccEl = doc.NewElement("CustomCss"); Loading @@ -1360,6 +1421,8 @@ void blogi::htmlimport::htmlElementToWidgetXml( std::vector<std::string> knownCss = {"width","height","display"}; std::string newInstanceId; std::string custom = extractCustomCss(cssProps, knownCss, mediaRules, newInstanceId); std::string dataAttrs = extractReferencedDataAttrs(mediaRules, elemAttrs); if (!dataAttrs.empty()) w->SetAttribute("data_attrs", dataAttrs.c_str()); finalizeInstanceId(w, elemId, newInstanceId, idToInstanceId); if (!custom.empty()) { tinyxml2::XMLElement *ccEl = doc.NewElement("CustomCss"); Loading Loading @@ -1505,6 +1568,8 @@ void blogi::htmlimport::htmlElementToWidgetXml( "display","visibility"}; std::string newInstanceId; std::string custom = extractCustomCss(cssProps, knownCss, mediaRules, newInstanceId); std::string dataAttrs = extractReferencedDataAttrs(mediaRules, elemAttrs); if (!dataAttrs.empty()) w->SetAttribute("data_attrs", dataAttrs.c_str()); finalizeInstanceId(w, elemId, newInstanceId, idToInstanceId); std::string structureCss = collectTableStructureCss(sheet, usedClasses); if (!structureCss.empty()) { Loading Loading @@ -1594,6 +1659,8 @@ void blogi::htmlimport::htmlElementToWidgetXml( applyFlexLayoutAttributes(w, cssProps, knownCss); std::string newInstanceId; std::string custom = extractCustomCss(cssProps, knownCss, mediaRules, newInstanceId); std::string dataAttrs = extractReferencedDataAttrs(mediaRules, elemAttrs); if (!dataAttrs.empty()) w->SetAttribute("data_attrs", dataAttrs.c_str()); finalizeInstanceId(w, elemId, newInstanceId, idToInstanceId); if (!custom.empty()) { tinyxml2::XMLElement *ccEl = doc.NewElement("CustomCss"); Loading Loading @@ -1660,6 +1727,8 @@ void blogi::htmlimport::htmlElementToWidgetXml( "visibility","text-decoration","cursor","text-align"}; std::string newInstanceId; std::string custom = extractCustomCss(cssProps, knownCss, mediaRules, newInstanceId); std::string dataAttrs = extractReferencedDataAttrs(mediaRules, elemAttrs); if (!dataAttrs.empty()) w->SetAttribute("data_attrs", dataAttrs.c_str()); finalizeInstanceId(w, elemId, newInstanceId, idToInstanceId); if (!custom.empty()) { tinyxml2::XMLElement *ccEl = doc.NewElement("CustomCss"); Loading Loading @@ -1722,6 +1791,8 @@ void blogi::htmlimport::htmlElementToWidgetXml( applyFlexLayoutAttributes(w, cssProps, knownCss); std::string newInstanceId; std::string custom = extractCustomCss(cssProps, knownCss, mediaRules, newInstanceId); std::string dataAttrs = extractReferencedDataAttrs(mediaRules, elemAttrs); if (!dataAttrs.empty()) w->SetAttribute("data_attrs", dataAttrs.c_str()); finalizeInstanceId(w, elemId, newInstanceId, idToInstanceId); if (!custom.empty()) { tinyxml2::XMLElement *ccEl = doc.NewElement("CustomCss"); Loading Loading @@ -1779,6 +1850,8 @@ void blogi::htmlimport::htmlElementToWidgetXml( "padding","margin","line-height"}; std::string newInstanceId; std::string custom = extractCustomCss(cssProps, knownCss, mediaRules, newInstanceId); std::string dataAttrs = extractReferencedDataAttrs(mediaRules, elemAttrs); if (!dataAttrs.empty()) w->SetAttribute("data_attrs", dataAttrs.c_str()); finalizeInstanceId(w, elemId, newInstanceId, idToInstanceId); if (!custom.empty()) { tinyxml2::XMLElement *ccEl = doc.NewElement("CustomCss"); Loading editor/widgets/article/article.cpp +13 −0 Original line number Diff line number Diff line Loading @@ -103,6 +103,13 @@ extern "C" { // Custom CSS std::string customCss = ""; // Source data-* attributes an imported element's leftover // @media-rule CSS still references by attribute selector (see // htmlimport.cpp's extractReferencedDataAttrs) -- re-applied // verbatim in Render() via applyDataAttrs, since that's the // only way such a rule keeps matching post-import. std::string dataAttrs = ""; public: Article() { Type = "58e70fdb-d4b4-45bf-8c59-e7a8ce2db735"; Loading Loading @@ -326,6 +333,8 @@ extern "C" { cssEl->SetText(customCss.c_str()); element->InsertEndChild(cssEl); } if (!dataAttrs.empty()) element->SetAttribute("data_attrs", dataAttrs.c_str()); if (!content.empty()) { element->SetText(content.c_str()); Loading Loading @@ -459,6 +468,9 @@ extern "C" { const char* cssVal = cssEl->GetText(); if (cssVal) customCss = cssVal; } const char* loaded_data_attrs = xml_data->Attribute("data_attrs"); if (loaded_data_attrs) dataAttrs = loaded_data_attrs; } std::optional<std::string> toLlmsBlock() const override { Loading Loading @@ -796,6 +808,7 @@ extern "C" { cls = cssClass + " " + responsiveClass; } art.setAttribute("class", cls.c_str()); if (!dataAttrs.empty()) applyDataAttrs(art, dataAttrs); // Mobile responsive overrides std::string mobileCSS; Loading editor/widgets/button/button.cpp +13 −0 Original line number Diff line number Diff line Loading @@ -114,6 +114,13 @@ extern "C" { // Custom CSS std::string customCss = ""; // Source data-* attributes an imported element's leftover // @media-rule CSS still references by attribute selector (see // htmlimport.cpp's extractReferencedDataAttrs) -- re-applied // verbatim in Render() via applyDataAttrs, since that's the // only way such a rule keeps matching post-import. std::string dataAttrs = ""; // Google Event Trigger bool gEventEnabled = false; std::string gEventName = ""; Loading Loading @@ -586,6 +593,8 @@ extern "C" { cssEl->SetText(customCss.c_str()); element->InsertEndChild(cssEl); } if (!dataAttrs.empty()) element->SetAttribute("data_attrs", dataAttrs.c_str()); return element; } Loading Loading @@ -723,6 +732,9 @@ extern "C" { const char* cssVal = cssEl->GetText(); if (cssVal) customCss = cssVal; } val = xml_data->Attribute("data_attrs"); if (val) dataAttrs = val; } // --- JSON Properties Helpers --- Loading Loading @@ -1133,6 +1145,7 @@ extern "C" { a.setAttribute("style", style.c_str()); a.setAttribute("class", responsiveClass.c_str()); if (!dataAttrs.empty()) applyDataAttrs(a, dataAttrs); if (hideLabel) { a.setAttribute("aria-label", label.c_str()); libhtmlpp::HtmlElement labelSpan("span"); Loading editor/widgets/container/container.cpp +13 −0 Original line number Diff line number Diff line Loading @@ -131,6 +131,13 @@ extern "C" { // Custom CSS std::string customCss = ""; // Source data-* attributes an imported element's leftover // @media-rule CSS still references by attribute selector (see // htmlimport.cpp's extractReferencedDataAttrs) -- re-applied // verbatim in Render() via applyDataAttrs, since that's the // only way such a rule keeps matching post-import. std::string dataAttrs = ""; public: Container() { // NOTE: The base EditPlugin constructor handles ID generation. Loading Loading @@ -509,6 +516,8 @@ extern "C" { cssEl->SetText(customCss.c_str()); element->InsertEndChild(cssEl); } if (!dataAttrs.empty()) element->SetAttribute("data_attrs", dataAttrs.c_str()); // Add content if (!content.empty()) { Loading Loading @@ -708,6 +717,9 @@ extern "C" { if (cssVal) customCss = cssVal; } const char* loaded_data_attrs = xml_data->Attribute("data_attrs"); if (loaded_data_attrs) dataAttrs = loaded_data_attrs; // NOTE: Loading children from XML requires an EditPluginFactory which is not available here. } Loading Loading @@ -1182,6 +1194,7 @@ extern "C" { cls = cssClass + " " + responsiveClass; } cnt.setAttribute("class", cls.c_str()); if (!dataAttrs.empty()) applyDataAttrs(cnt, dataAttrs); // Shape divider: a decorative wave/oval SVG pinned to the // container's top and/or bottom edge (see member field comment). Loading editor/widgets/grid/grid.cpp +13 −0 Original line number Diff line number Diff line Loading @@ -99,6 +99,13 @@ extern "C" { // Custom CSS std::string customCss = ""; // Source data-* attributes an imported element's leftover // @media-rule CSS still references by attribute selector (see // htmlimport.cpp's extractReferencedDataAttrs) -- re-applied // verbatim in Render() via applyDataAttrs, since that's the // only way such a rule keeps matching post-import. std::string dataAttrs = ""; public: Grid() { Type = "c44c9af1-2f65-4e3f-a4c6-9f56d1b656c4"; Loading Loading @@ -409,6 +416,8 @@ extern "C" { cssEl->SetText(customCss.c_str()); element->InsertEndChild(cssEl); } if (!dataAttrs.empty()) element->SetAttribute("data_attrs", dataAttrs.c_str()); // Serialize children const EditPlugin *cur = child; Loading Loading @@ -547,6 +556,9 @@ extern "C" { const char* cssVal = cssEl->GetText(); if (cssVal) customCss = cssVal; } val = xml_data->Attribute("data_attrs"); if (val) dataAttrs = val; } // --- JSON Properties Helpers --- Loading Loading @@ -822,6 +834,7 @@ extern "C" { cls = cssClass + " " + responsiveClass; } grid.setAttribute("class", cls.c_str()); if (!dataAttrs.empty()) applyDataAttrs(grid, dataAttrs); // Mobile responsive overrides via media query std::string mobileCSS; Loading Loading
editor/src/htmlimport.cpp +73 −0 Original line number Diff line number Diff line Loading @@ -661,6 +661,57 @@ void applyFlexLayoutAttributes(tinyxml2::XMLElement *w, } } // @p mediaRules (see extractCustomCss's parameter of the same name) is kept // as raw "@media(...) { <original-selector> { ... } }" text, verbatim from // libhtmlpp::getCSSRules -- including whatever selector the source // stylesheet actually used, e.g. ".con-kit-col[data-col-lg=\"6\"]". A class // in that selector still matches after import (see cssClass -> css_class), // but an attribute-selector condition like "[data-col-lg=\"6\"]" silently // stops matching: no widget's Render() re-emits arbitrary source `data-*` // attributes onto the element it produces, only class/style. Found on a // real page-builder site (bautenschutz-wetzlar.de) whose responsive column // widths are ONLY ever set inside such a media-query rule (no plain/base // declaration at all) -- every widget kept exactly the widget's default // (auto) width at every breakpoint instead, silently un-doing an intended // side-by-side layout. Scans @p mediaRules for every "[attrName...]" // condition and returns an HTML-attribute-serialized string // (`name="value"`, space-separated) for whichever of those names @p // elemAttrs (this element's own real attributes, see its declaration // above) actually has a value for -- so the caller can stash it on the // widget and have Render() re-apply just those specific attributes, // without a general (larger, riskier) passthrough of every source // attribute on every widget. Serialized as "name=value" pairs joined by // ";" -- deliberately not HTML/XML attribute syntax (no quoting) since the // values in play here (page-builder breakpoint/variant tokens like "6" or // "solid") never contain ";"/"=" themselves, and this keeps the widget-side // parser (see each widget's applyDataAttrs-style Render() code) trivial // instead of needing to un-escape a quoted sub-value out of an already // tinyxml2-escaped XML attribute. std::string extractReferencedDataAttrs(const std::string &mediaRules, const std::map<std::string,std::string> &elemAttrs) { std::string result; std::set<std::string> seen; size_t pos = 0; while (pos < mediaRules.size()) { size_t open = mediaRules.find('[', pos); if (open == std::string::npos) break; size_t close = mediaRules.find(']', open + 1); if (close == std::string::npos) break; size_t nameEnd = mediaRules.find_first_of("=~|^$*]", open + 1); if (nameEnd == std::string::npos || nameEnd > close) nameEnd = close; std::string name = mediaRules.substr(open + 1, nameEnd - (open + 1)); pos = close + 1; if (name.empty() || seen.count(name)) continue; seen.insert(name); auto it = elemAttrs.find(name); if (it == elemAttrs.end()) continue; if (!result.empty()) result += ";"; result += name + "=" + it->second; } return result; } // Merges this element's own --custom-property declarations onto the // inherited environment (own values override inherited -- innermost scope // wins, matching real CSS custom-property cascade/inheritance), resolves Loading Loading @@ -1161,6 +1212,8 @@ void blogi::htmlimport::htmlElementToWidgetXml( applyFlexLayoutAttributes(w, cssProps, knownCss); std::string newInstanceId; std::string custom = extractCustomCss(cssProps, knownCss, mediaRules, newInstanceId); std::string dataAttrs = extractReferencedDataAttrs(mediaRules, elemAttrs); if (!dataAttrs.empty()) w->SetAttribute("data_attrs", dataAttrs.c_str()); finalizeInstanceId(w, elemId, newInstanceId, idToInstanceId); if (!custom.empty()) { tinyxml2::XMLElement *ccEl = doc.NewElement("CustomCss"); Loading Loading @@ -1206,6 +1259,8 @@ void blogi::htmlimport::htmlElementToWidgetXml( applyFlexLayoutAttributes(w, cssProps, knownCss); std::string newInstanceId; std::string custom = extractCustomCss(cssProps, knownCss, mediaRules, newInstanceId); std::string dataAttrs = extractReferencedDataAttrs(mediaRules, elemAttrs); if (!dataAttrs.empty()) w->SetAttribute("data_attrs", dataAttrs.c_str()); finalizeInstanceId(w, elemId, newInstanceId, idToInstanceId); if (!custom.empty()) { tinyxml2::XMLElement *ccEl = doc.NewElement("CustomCss"); Loading Loading @@ -1283,6 +1338,8 @@ void blogi::htmlimport::htmlElementToWidgetXml( } std::string newInstanceId; std::string custom = extractCustomCss(cssProps, knownCss, mediaRules, newInstanceId); std::string dataAttrs = extractReferencedDataAttrs(mediaRules, elemAttrs); if (!dataAttrs.empty()) w->SetAttribute("data_attrs", dataAttrs.c_str()); finalizeInstanceId(w, elemId, newInstanceId, idToInstanceId); if (!custom.empty()) { tinyxml2::XMLElement *ccEl = doc.NewElement("CustomCss"); Loading @@ -1303,6 +1360,8 @@ void blogi::htmlimport::htmlElementToWidgetXml( applyFlexLayoutAttributes(w, cssProps, knownCss); std::string newInstanceId; std::string custom = extractCustomCss(cssProps, knownCss, mediaRules, newInstanceId); std::string dataAttrs = extractReferencedDataAttrs(mediaRules, elemAttrs); if (!dataAttrs.empty()) w->SetAttribute("data_attrs", dataAttrs.c_str()); finalizeInstanceId(w, elemId, newInstanceId, idToInstanceId); if (!custom.empty()) { tinyxml2::XMLElement *ccEl = doc.NewElement("CustomCss"); Loading Loading @@ -1338,6 +1397,8 @@ void blogi::htmlimport::htmlElementToWidgetXml( "display","visibility"}; std::string newInstanceId; std::string custom = extractCustomCss(cssProps, knownCss, mediaRules, newInstanceId); std::string dataAttrs = extractReferencedDataAttrs(mediaRules, elemAttrs); if (!dataAttrs.empty()) w->SetAttribute("data_attrs", dataAttrs.c_str()); finalizeInstanceId(w, elemId, newInstanceId, idToInstanceId); if (!custom.empty()) { tinyxml2::XMLElement *ccEl = doc.NewElement("CustomCss"); Loading @@ -1360,6 +1421,8 @@ void blogi::htmlimport::htmlElementToWidgetXml( std::vector<std::string> knownCss = {"width","height","display"}; std::string newInstanceId; std::string custom = extractCustomCss(cssProps, knownCss, mediaRules, newInstanceId); std::string dataAttrs = extractReferencedDataAttrs(mediaRules, elemAttrs); if (!dataAttrs.empty()) w->SetAttribute("data_attrs", dataAttrs.c_str()); finalizeInstanceId(w, elemId, newInstanceId, idToInstanceId); if (!custom.empty()) { tinyxml2::XMLElement *ccEl = doc.NewElement("CustomCss"); Loading Loading @@ -1505,6 +1568,8 @@ void blogi::htmlimport::htmlElementToWidgetXml( "display","visibility"}; std::string newInstanceId; std::string custom = extractCustomCss(cssProps, knownCss, mediaRules, newInstanceId); std::string dataAttrs = extractReferencedDataAttrs(mediaRules, elemAttrs); if (!dataAttrs.empty()) w->SetAttribute("data_attrs", dataAttrs.c_str()); finalizeInstanceId(w, elemId, newInstanceId, idToInstanceId); std::string structureCss = collectTableStructureCss(sheet, usedClasses); if (!structureCss.empty()) { Loading Loading @@ -1594,6 +1659,8 @@ void blogi::htmlimport::htmlElementToWidgetXml( applyFlexLayoutAttributes(w, cssProps, knownCss); std::string newInstanceId; std::string custom = extractCustomCss(cssProps, knownCss, mediaRules, newInstanceId); std::string dataAttrs = extractReferencedDataAttrs(mediaRules, elemAttrs); if (!dataAttrs.empty()) w->SetAttribute("data_attrs", dataAttrs.c_str()); finalizeInstanceId(w, elemId, newInstanceId, idToInstanceId); if (!custom.empty()) { tinyxml2::XMLElement *ccEl = doc.NewElement("CustomCss"); Loading Loading @@ -1660,6 +1727,8 @@ void blogi::htmlimport::htmlElementToWidgetXml( "visibility","text-decoration","cursor","text-align"}; std::string newInstanceId; std::string custom = extractCustomCss(cssProps, knownCss, mediaRules, newInstanceId); std::string dataAttrs = extractReferencedDataAttrs(mediaRules, elemAttrs); if (!dataAttrs.empty()) w->SetAttribute("data_attrs", dataAttrs.c_str()); finalizeInstanceId(w, elemId, newInstanceId, idToInstanceId); if (!custom.empty()) { tinyxml2::XMLElement *ccEl = doc.NewElement("CustomCss"); Loading Loading @@ -1722,6 +1791,8 @@ void blogi::htmlimport::htmlElementToWidgetXml( applyFlexLayoutAttributes(w, cssProps, knownCss); std::string newInstanceId; std::string custom = extractCustomCss(cssProps, knownCss, mediaRules, newInstanceId); std::string dataAttrs = extractReferencedDataAttrs(mediaRules, elemAttrs); if (!dataAttrs.empty()) w->SetAttribute("data_attrs", dataAttrs.c_str()); finalizeInstanceId(w, elemId, newInstanceId, idToInstanceId); if (!custom.empty()) { tinyxml2::XMLElement *ccEl = doc.NewElement("CustomCss"); Loading Loading @@ -1779,6 +1850,8 @@ void blogi::htmlimport::htmlElementToWidgetXml( "padding","margin","line-height"}; std::string newInstanceId; std::string custom = extractCustomCss(cssProps, knownCss, mediaRules, newInstanceId); std::string dataAttrs = extractReferencedDataAttrs(mediaRules, elemAttrs); if (!dataAttrs.empty()) w->SetAttribute("data_attrs", dataAttrs.c_str()); finalizeInstanceId(w, elemId, newInstanceId, idToInstanceId); if (!custom.empty()) { tinyxml2::XMLElement *ccEl = doc.NewElement("CustomCss"); Loading
editor/widgets/article/article.cpp +13 −0 Original line number Diff line number Diff line Loading @@ -103,6 +103,13 @@ extern "C" { // Custom CSS std::string customCss = ""; // Source data-* attributes an imported element's leftover // @media-rule CSS still references by attribute selector (see // htmlimport.cpp's extractReferencedDataAttrs) -- re-applied // verbatim in Render() via applyDataAttrs, since that's the // only way such a rule keeps matching post-import. std::string dataAttrs = ""; public: Article() { Type = "58e70fdb-d4b4-45bf-8c59-e7a8ce2db735"; Loading Loading @@ -326,6 +333,8 @@ extern "C" { cssEl->SetText(customCss.c_str()); element->InsertEndChild(cssEl); } if (!dataAttrs.empty()) element->SetAttribute("data_attrs", dataAttrs.c_str()); if (!content.empty()) { element->SetText(content.c_str()); Loading Loading @@ -459,6 +468,9 @@ extern "C" { const char* cssVal = cssEl->GetText(); if (cssVal) customCss = cssVal; } const char* loaded_data_attrs = xml_data->Attribute("data_attrs"); if (loaded_data_attrs) dataAttrs = loaded_data_attrs; } std::optional<std::string> toLlmsBlock() const override { Loading Loading @@ -796,6 +808,7 @@ extern "C" { cls = cssClass + " " + responsiveClass; } art.setAttribute("class", cls.c_str()); if (!dataAttrs.empty()) applyDataAttrs(art, dataAttrs); // Mobile responsive overrides std::string mobileCSS; Loading
editor/widgets/button/button.cpp +13 −0 Original line number Diff line number Diff line Loading @@ -114,6 +114,13 @@ extern "C" { // Custom CSS std::string customCss = ""; // Source data-* attributes an imported element's leftover // @media-rule CSS still references by attribute selector (see // htmlimport.cpp's extractReferencedDataAttrs) -- re-applied // verbatim in Render() via applyDataAttrs, since that's the // only way such a rule keeps matching post-import. std::string dataAttrs = ""; // Google Event Trigger bool gEventEnabled = false; std::string gEventName = ""; Loading Loading @@ -586,6 +593,8 @@ extern "C" { cssEl->SetText(customCss.c_str()); element->InsertEndChild(cssEl); } if (!dataAttrs.empty()) element->SetAttribute("data_attrs", dataAttrs.c_str()); return element; } Loading Loading @@ -723,6 +732,9 @@ extern "C" { const char* cssVal = cssEl->GetText(); if (cssVal) customCss = cssVal; } val = xml_data->Attribute("data_attrs"); if (val) dataAttrs = val; } // --- JSON Properties Helpers --- Loading Loading @@ -1133,6 +1145,7 @@ extern "C" { a.setAttribute("style", style.c_str()); a.setAttribute("class", responsiveClass.c_str()); if (!dataAttrs.empty()) applyDataAttrs(a, dataAttrs); if (hideLabel) { a.setAttribute("aria-label", label.c_str()); libhtmlpp::HtmlElement labelSpan("span"); Loading
editor/widgets/container/container.cpp +13 −0 Original line number Diff line number Diff line Loading @@ -131,6 +131,13 @@ extern "C" { // Custom CSS std::string customCss = ""; // Source data-* attributes an imported element's leftover // @media-rule CSS still references by attribute selector (see // htmlimport.cpp's extractReferencedDataAttrs) -- re-applied // verbatim in Render() via applyDataAttrs, since that's the // only way such a rule keeps matching post-import. std::string dataAttrs = ""; public: Container() { // NOTE: The base EditPlugin constructor handles ID generation. Loading Loading @@ -509,6 +516,8 @@ extern "C" { cssEl->SetText(customCss.c_str()); element->InsertEndChild(cssEl); } if (!dataAttrs.empty()) element->SetAttribute("data_attrs", dataAttrs.c_str()); // Add content if (!content.empty()) { Loading Loading @@ -708,6 +717,9 @@ extern "C" { if (cssVal) customCss = cssVal; } const char* loaded_data_attrs = xml_data->Attribute("data_attrs"); if (loaded_data_attrs) dataAttrs = loaded_data_attrs; // NOTE: Loading children from XML requires an EditPluginFactory which is not available here. } Loading Loading @@ -1182,6 +1194,7 @@ extern "C" { cls = cssClass + " " + responsiveClass; } cnt.setAttribute("class", cls.c_str()); if (!dataAttrs.empty()) applyDataAttrs(cnt, dataAttrs); // Shape divider: a decorative wave/oval SVG pinned to the // container's top and/or bottom edge (see member field comment). Loading
editor/widgets/grid/grid.cpp +13 −0 Original line number Diff line number Diff line Loading @@ -99,6 +99,13 @@ extern "C" { // Custom CSS std::string customCss = ""; // Source data-* attributes an imported element's leftover // @media-rule CSS still references by attribute selector (see // htmlimport.cpp's extractReferencedDataAttrs) -- re-applied // verbatim in Render() via applyDataAttrs, since that's the // only way such a rule keeps matching post-import. std::string dataAttrs = ""; public: Grid() { Type = "c44c9af1-2f65-4e3f-a4c6-9f56d1b656c4"; Loading Loading @@ -409,6 +416,8 @@ extern "C" { cssEl->SetText(customCss.c_str()); element->InsertEndChild(cssEl); } if (!dataAttrs.empty()) element->SetAttribute("data_attrs", dataAttrs.c_str()); // Serialize children const EditPlugin *cur = child; Loading Loading @@ -547,6 +556,9 @@ extern "C" { const char* cssVal = cssEl->GetText(); if (cssVal) customCss = cssVal; } val = xml_data->Attribute("data_attrs"); if (val) dataAttrs = val; } // --- JSON Properties Helpers --- Loading Loading @@ -822,6 +834,7 @@ extern "C" { cls = cssClass + " " + responsiveClass; } grid.setAttribute("class", cls.c_str()); if (!dataAttrs.empty()) applyDataAttrs(grid, dataAttrs); // Mobile responsive overrides via media query std::string mobileCSS; Loading