Commit dbe87278 authored by jan.koester's avatar jan.koester
Browse files

data attr will be imported

parent ae422427
Loading
Loading
Loading
Loading
+73 −0
Original line number Diff line number Diff line
@@ -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
@@ -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");
@@ -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");
@@ -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");
@@ -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");
@@ -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");
@@ -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");
@@ -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()) {
@@ -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");
@@ -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");
@@ -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");
@@ -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");
+13 −0
Original line number Diff line number Diff line
@@ -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";
@@ -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());
@@ -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 {
@@ -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;
+13 −0
Original line number Diff line number Diff line
@@ -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     = "";
@@ -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;
            }

@@ -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 ---
@@ -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");
+13 −0
Original line number Diff line number Diff line
@@ -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.
@@ -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()) {
@@ -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.
            }

@@ -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).
+13 −0
Original line number Diff line number Diff line
@@ -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";
@@ -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;
@@ -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 ---
@@ -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