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

test

parent e63c553f
Loading
Loading
Loading
Loading
+59 −3
Changes for editor/src/htmlimport.cpp: 59 added lines, 3 removed lines.
Original line number Diff line number Diff line
@@ -1206,6 +1206,41 @@ std::string resolveSrcset(const std::string &baseUrl, const std::string &srcset)
    return out;
}

// Many real-world pages lazy-load images (lazysizes.js and similar
// libraries all use this same convention): the real image lives in
// data-src/data-srcset, while src/srcset hold a tiny placeholder (a blurred
// low-res preview or a 1x1 transparent pixel) so the browser doesn't fetch
// full-size images before they scroll into view. This importer never
// scrolls or runs JS, so without this it would silently capture only that
// placeholder -- prefer the data- variant whenever present. Unconditional
// (unlike rewriteRelativeUrls below): this has nothing to do with baseUrl
// resolution, so it applies the same whether the page was fetched from a
// URL or pasted/uploaded.
void preferLazyImageSrc(libhtmlpp::Element *node)
{
    while (node) {
        int type = node->getType();
        if (type == libhtmlpp::HtmlEl || type == libhtmlpp::SvgEL ||
            type == libhtmlpp::TextAreaEL) {
            auto *hel = static_cast<libhtmlpp::HtmlElement*>(node);
            std::string tag = hel->getTagname();
            std::transform(tag.begin(), tag.end(), tag.begin(),
                [](unsigned char c) { return std::tolower(c); });

            if (tag == "img" || tag == "source") {
                std::string dataSrc = hel->getAtributte("data-src");
                if (!dataSrc.empty()) hel->setAttribute("src", dataSrc);

                std::string dataSrcset = hel->getAtributte("data-srcset");
                if (!dataSrcset.empty()) hel->setAttribute("srcset", dataSrcset);
            }

            preferLazyImageSrc(hel->firstChild());
        }
        node = node->nextElement();
    }
}

// Walks the whole parsed document (unlike collectTopLevelElements, this
// includes <head> -- external stylesheets/scripts live there) and rewrites
// every document-relative resource/link/style reference to absolute, in
@@ -1612,6 +1647,13 @@ bool blogi::htmlimport::convertHtmlToWidgetXml(const std::string &html,
        if (sel.empty()) continue;

        bool isGlobal = false;
        // Only meaningful (and only set) when sel[0] == '@': the at-rule's
        // own "@media (...)"/"@supports (...)" wrapper and the selector
        // nested inside it. libhtmlpp::CSSStyleSheet flattens e.g.
        // "@media (max-width:768px) { :root { ... } }" into ONE CSSRule
        // whose getSelector() is the whole "@media (max-width:768px) :root"
        // string -- see the reconstruction below for why that matters.
        std::string atWrapper, innerSel;

        if (sel[0] == '@') {
            size_t parenDepth = 0;
@@ -1626,8 +1668,9 @@ bool blogi::htmlimport::convertHtmlToWidgetXml(const std::string &html,
            if (splitPos != std::string::npos && splitPos + 1 < sel.size()) {
                size_t innerStart = sel.find_first_not_of(" \t\n\r", splitPos);
                if (innerStart != std::string::npos) {
                    std::string inner = sel.substr(innerStart);
                    std::string innerLower = inner;
                    atWrapper = sel.substr(0, splitPos);
                    innerSel = sel.substr(innerStart);
                    std::string innerLower = innerSel;
                    std::transform(innerLower.begin(), innerLower.end(),
                        innerLower.begin(),
                        [](unsigned char c) { return std::tolower(c); });
@@ -1652,7 +1695,20 @@ bool blogi::htmlimport::convertHtmlToWidgetXml(const std::string &html,
            }
        }

        if (isGlobal) {
        if (isGlobal && sel[0] == '@' && !innerSel.empty()) {
            // rule.serialize() just wraps getSelector() in a single "{ }"
            // pair -- fine for a plain selector, but here getSelector() is
            // the FULL flattened "@media (...) :root" string, so that would
            // emit "@media (...) :root { decls }", which is invalid CSS (the
            // at-rule needs its own wrapping braces around the nested rule).
            // Reconstruct the proper nested form instead, the same way
            // mergeStylesheetRules does for per-element @media matches.
            globalCss += atWrapper + " {\n  " + innerSel + " {\n";
            for (const auto &prop : rule.getDeclaration().getProperties()) {
                globalCss += "    " + prop.getName() + ": " + prop.getValue() + ";\n";
            }
            globalCss += "  }\n}\n";
        } else if (isGlobal) {
            globalCss += rule.serialize(true);
            globalCss += "\n";
        }