Commit e3d4a331 authored by Jan Köster's avatar Jan Köster
Browse files

better import

parent 475e8869
Loading
Loading
Loading
Loading
+42 −32
Changes for editor/src/htmlimport.cpp: 42 added lines, 32 removed lines.
Original line number Diff line number Diff line
@@ -43,6 +43,7 @@
#include <arpa/inet.h>

#include <zlib.h>
#include <uuidp.h>

using namespace blogi::htmlimport;

@@ -665,8 +666,7 @@ std::string blogi::htmlimport::extractCustomCss(
    std::map<std::string,std::string> &props,
    const std::vector<std::string> &knownKeys,
    const std::string &mediaRules,
    const std::string &cssClass,
    const std::string &elemId)
    std::string &outInstanceId)
{
    std::string plainDecls;
    std::vector<std::string> toRemove;
@@ -685,28 +685,18 @@ std::string blogi::htmlimport::extractCustomCss(

    std::string customCss;
    if (!plainDecls.empty()) {
        // The widgets that render CustomCss (Section/Container/Article/Grid)
        // emit this field's text verbatim inside a <style> tag, so it needs
        // its own selector -- bare declarations are invalid at stylesheet
        // top level and get silently dropped by the browser. The element's
        // own class/id (captured at import time) is also applied onto the
        // rendered widget alongside its generated "we-<uuid>" class (see
        // e.g. section.cpp's Render()), so scoping to it here reliably
        // matches. With neither class nor id there's no stable selector to
        // hang these declarations on, so they're dropped (same as before).
        std::string selector;
        if (!elemId.empty()) {
            selector = "#" + elemId;
        } else if (!cssClass.empty()) {
            std::istringstream iss(cssClass);
            std::string firstClass;
            iss >> firstClass;
            if (!firstClass.empty()) selector = "." + firstClass;
        }
        if (!selector.empty()) {
        // The widgets that render CustomCss emit this field's text verbatim
        // inside a <style> tag, so it needs its own selector -- bare
        // declarations are invalid at stylesheet top level and get silently
        // dropped by the browser. See this function's header doc comment
        // for why that selector is this element's own "we-<uuid>" auto-class
        // rather than its source class/id.
        uuid::uuid id;
        id.generate();
        outInstanceId = id.c_str();
        std::string selector = ".we-" + outInstanceId;
        customCss = selector + " { " + plainDecls + " }";
    }
    }

    if (!mediaRules.empty()) {
        if (!customCss.empty()) customCss += " ";
@@ -993,7 +983,9 @@ void blogi::htmlimport::htmlElementToWidgetXml(
                    }
                }
                applyFlexLayoutAttributes(w, cssProps, knownCss);
                std::string custom = extractCustomCss(cssProps, knownCss, mediaRules, cssClass, elemId);
                std::string newInstanceId;
                std::string custom = extractCustomCss(cssProps, knownCss, mediaRules, newInstanceId);
                if (!newInstanceId.empty()) w->SetAttribute("instance_id", newInstanceId.c_str());
                if (!custom.empty()) {
                    tinyxml2::XMLElement *ccEl = doc.NewElement("CustomCss");
                    ccEl->SetText(custom.c_str());
@@ -1036,7 +1028,9 @@ void blogi::htmlimport::htmlElementToWidgetXml(
                    }
                }
                applyFlexLayoutAttributes(w, cssProps, knownCss);
                std::string custom = extractCustomCss(cssProps, knownCss, mediaRules, cssClass, elemId);
                std::string newInstanceId;
                std::string custom = extractCustomCss(cssProps, knownCss, mediaRules, newInstanceId);
                if (!newInstanceId.empty()) w->SetAttribute("instance_id", newInstanceId.c_str());
                if (!custom.empty()) {
                    tinyxml2::XMLElement *ccEl = doc.NewElement("CustomCss");
                    ccEl->SetText(custom.c_str());
@@ -1089,7 +1083,9 @@ void blogi::htmlimport::htmlElementToWidgetXml(
                            knownCss.push_back("align-items");
                        }
                    }
                    std::string custom = extractCustomCss(cssProps, knownCss, mediaRules, cssClass, elemId);
                    std::string newInstanceId;
                    std::string custom = extractCustomCss(cssProps, knownCss, mediaRules, newInstanceId);
                    if (!newInstanceId.empty()) w->SetAttribute("instance_id", newInstanceId.c_str());
                    if (!custom.empty()) {
                        tinyxml2::XMLElement *ccEl = doc.NewElement("CustomCss");
                        ccEl->SetText(custom.c_str());
@@ -1107,7 +1103,9 @@ void blogi::htmlimport::htmlElementToWidgetXml(
                        }
                    }
                    applyFlexLayoutAttributes(w, cssProps, knownCss);
                    std::string custom = extractCustomCss(cssProps, knownCss, mediaRules, cssClass, elemId);
                    std::string newInstanceId;
                    std::string custom = extractCustomCss(cssProps, knownCss, mediaRules, newInstanceId);
                    if (!newInstanceId.empty()) w->SetAttribute("instance_id", newInstanceId.c_str());
                    if (!custom.empty()) {
                        tinyxml2::XMLElement *ccEl = doc.NewElement("CustomCss");
                        ccEl->SetText(custom.c_str());
@@ -1140,7 +1138,9 @@ void blogi::htmlimport::htmlElementToWidgetXml(
                std::vector<std::string> knownCss = {
                    "width","height","object-fit","border-radius","border",
                    "display","visibility"};
                std::string custom = extractCustomCss(cssProps, knownCss, mediaRules, cssClass, elemId);
                std::string newInstanceId;
                std::string custom = extractCustomCss(cssProps, knownCss, mediaRules, newInstanceId);
                if (!newInstanceId.empty()) w->SetAttribute("instance_id", newInstanceId.c_str());
                if (!custom.empty()) {
                    tinyxml2::XMLElement *ccEl = doc.NewElement("CustomCss");
                    ccEl->SetText(custom.c_str());
@@ -1160,7 +1160,9 @@ void blogi::htmlimport::htmlElementToWidgetXml(
                    w->SetAttribute("height", cssProps["height"].c_str());

                std::vector<std::string> knownCss = {"width","height","display"};
                std::string custom = extractCustomCss(cssProps, knownCss, mediaRules, cssClass, elemId);
                std::string newInstanceId;
                std::string custom = extractCustomCss(cssProps, knownCss, mediaRules, newInstanceId);
                if (!newInstanceId.empty()) w->SetAttribute("instance_id", newInstanceId.c_str());
                if (!custom.empty()) {
                    tinyxml2::XMLElement *ccEl = doc.NewElement("CustomCss");
                    ccEl->SetText(custom.c_str());
@@ -1303,7 +1305,9 @@ void blogi::htmlimport::htmlElementToWidgetXml(
                std::vector<std::string> knownCss = {
                    "border","background-color","border-collapse","width","height",
                    "display","visibility"};
                std::string custom = extractCustomCss(cssProps, knownCss, mediaRules, cssClass, elemId);
                std::string newInstanceId;
                std::string custom = extractCustomCss(cssProps, knownCss, mediaRules, newInstanceId);
                if (!newInstanceId.empty()) w->SetAttribute("instance_id", newInstanceId.c_str());
                std::string structureCss = collectTableStructureCss(sheet, usedClasses);
                if (!structureCss.empty()) {
                    if (!custom.empty()) custom += " ";
@@ -1353,7 +1357,9 @@ void blogi::htmlimport::htmlElementToWidgetXml(
                    "font-size","color","line-height","list-style-type",
                    "padding","margin","width","height","display","visibility","gap"};
                applyFlexLayoutAttributes(w, cssProps, knownCss);
                std::string custom = extractCustomCss(cssProps, knownCss, mediaRules, cssClass, elemId);
                std::string newInstanceId;
                std::string custom = extractCustomCss(cssProps, knownCss, mediaRules, newInstanceId);
                if (!newInstanceId.empty()) w->SetAttribute("instance_id", newInstanceId.c_str());
                if (!custom.empty()) {
                    tinyxml2::XMLElement *ccEl = doc.NewElement("CustomCss");
                    ccEl->SetText(custom.c_str());
@@ -1410,7 +1416,9 @@ void blogi::htmlimport::htmlElementToWidgetXml(
                        "background-color","color","font-size","padding",
                        "border-radius","border","width","height","display",
                        "visibility","text-decoration","cursor","text-align"};
                    std::string custom = extractCustomCss(cssProps, knownCss, mediaRules, cssClass, elemId);
                    std::string newInstanceId;
                    std::string custom = extractCustomCss(cssProps, knownCss, mediaRules, newInstanceId);
                    if (!newInstanceId.empty()) w->SetAttribute("instance_id", newInstanceId.c_str());
                    if (!custom.empty()) {
                        tinyxml2::XMLElement *ccEl = doc.NewElement("CustomCss");
                        ccEl->SetText(custom.c_str());
@@ -1469,7 +1477,9 @@ void blogi::htmlimport::htmlElementToWidgetXml(
                    "font-family","font-size","color","text-align",
                    "font-weight","font-style","width","height",
                    "padding","margin","line-height"};
                std::string custom = extractCustomCss(cssProps, knownCss, mediaRules, cssClass, elemId);
                std::string newInstanceId;
                std::string custom = extractCustomCss(cssProps, knownCss, mediaRules, newInstanceId);
                if (!newInstanceId.empty()) w->SetAttribute("instance_id", newInstanceId.c_str());
                if (!custom.empty()) {
                    tinyxml2::XMLElement *ccEl = doc.NewElement("CustomCss");
                    ccEl->SetText(custom.c_str());
+26 −2
Changes for editor/src/htmlimport.h: 26 added lines, 2 removed lines.
Original line number Diff line number Diff line
@@ -72,12 +72,36 @@ namespace htmlimport {
        int jsFailed = 0;
    };

    /** Pulls every property in @p props that isn't one of @p knownKeys
     *  (i.e. has no widget-attribute equivalent) out into a standalone CSS
     *  rule text, scoped to this element's own "we-<uuid>" auto-class --
     *  the same class every widget's Render() unconditionally applies to
     *  its rendered root node (see e.g. Section/Container/TextBox's own
     *  Render()), regardless of widget type. This is deliberate, not a
     *  fallback: only Section/Container/Article/Grid/Table ever forward an
     *  imported class/id onto the rendered element at all (see their own
     *  cssClass member/Render()); TextBox/List/Image/Video do not, so a
     *  selector built from the source element's class/id would silently
     *  never match on those and the "leftover" CSS extracted here would be
     *  dead weight. Scoping to we-<uuid> instead works uniformly.
     *  Since that class only exists once the widget XML this call is
     *  building is actually loaded into a widget instance -- which happens
     *  later, in a different function entirely (see loadChildrenFromXml /
     *  loadDocumentTreeFromXml in webedit_api.cpp) -- the uuid has to be
     *  picked here, at XML-generation time, and threaded through: if there
     *  is anything to scope, a fresh one is generated and written to
     *  @p outInstanceId (left untouched otherwise) for the caller to set
     *  as this XML element's own `instance_id` attribute. Every loader that
     *  honors `instance_id` (loadChildrenFromXml's preserveInstanceIds,
     *  loadDocumentTreeFromXml, and handleImportHtml's own top-level loop)
     *  assigns exactly this id to the resulting widget instance instead of
     *  generating a random one, which is what makes the selector chosen
     *  here still correct once rendered. */
    std::string extractCustomCss(
        std::map<std::string,std::string> &props,
        const std::vector<std::string> &knownKeys,
        const std::string &mediaRules,
        const std::string &cssClass,
        const std::string &elemId);
        std::string &outInstanceId);

    std::string serializeElement(const libhtmlpp::Element *el);
    std::string serializeInnerHtml(libhtmlpp::HtmlElement *el);
+8 −1
Changes for editor/src/webedit_api.cpp: 8 added lines, 1 removed line.
Original line number Diff line number Diff line
@@ -5509,6 +5509,13 @@ void webedit::Api::handleImportHtml(libhttppp::HttpRequest &curreq,
        if (!el) continue;

        el->fromXmlObject(child);
        // Honor the instance_id htmlimport.cpp assigned to this element (see
        // extractCustomCss's doc comment) -- without this, the widget gets a
        // fresh random id here and any CustomCss scoped to "we-<that uuid>"
        // silently never matches its rendered class.
        const char *instanceIdAttr = child->Attribute("instance_id");
        if (instanceIdAttr && instanceIdAttr[0])
            el->setInstanceId(instanceIdAttr);

        if (insertParent) {
            // Child mode: add as children of target element
@@ -5530,7 +5537,7 @@ void webedit::Api::handleImportHtml(libhttppp::HttpRequest &curreq,
        }
        lastTop = el;

        loadChildrenFromXml(child, el, doc);
        loadChildrenFromXml(child, el, doc, /*preserveInstanceIds=*/true);
    }

    json_object *resp = json_object_new_object();