Loading editor/src/htmlimport.cpp +48 −9 Original line number Diff line number Diff line Loading @@ -290,6 +290,21 @@ std::string neutralizeFixedStickyPosition(const std::string &css) return std::regex_replace(css, re, "position: static"); } // Splits a whitespace-separated `class` attribute value into its individual // tokens, for building this element's own libhtmlpp::AncestorFrame entry // (see htmlElementToWidgetXml's Frame::ancestorChain) -- getCSSRules/ // collectApproximateMatches do this same split internally for the *target* // element already, but an ancestor frame is built here, once per element, // to hand to its own children's matching later. std::vector<std::string> splitClassList(const std::string &cssClass) { std::vector<std::string> classes; std::istringstream iss(cssClass); std::string cls; while (iss >> cls) classes.push_back(cls); return classes; } // Best-effort extraction of just the color component from a `background` // shorthand value (e.g. "background: url(x.png) no-repeat center red;") -- // every widget's known-CSS mapping only ever looks for the longhand Loading Loading @@ -986,6 +1001,15 @@ void blogi::htmlimport::htmlElementToWidgetXml( tinyxml2::XMLElement *pXml; libhtmlpp::Element *stop = nullptr; std::map<std::string,std::string> customPropertyEnv = {}; // Outermost-ancestor-first, immediate-parent-last (see // libhtmlpp::AncestorFrame's own doc comment) -- passed to // getCSSRules below so a descendant selector like ".header .frame" // only matches an element that's actually inside something with // class "header", instead of leaking onto every ".frame" in the // document regardless of where it lives (the bautenschutz-wetzlar.de // bug: a header-only padding rule was silently zeroing out every // section's own padding because this chain didn't exist yet). std::vector<libhtmlpp::AncestorFrame> ancestorChain = {}; }; std::stack<Frame> workStack; workStack.push({htmlEl, parentXml, stopBefore, rootCustomProperties}); Loading Loading @@ -1039,8 +1063,11 @@ void blogi::htmlimport::htmlElementToWidgetXml( libhtmlpp::Element *child = el->firstChild(); if (child) { // No cssProps computed for these structural tags -- just // pass the inherited environment through unchanged. childFrames.push_back({child, pXml, nullptr, frame.customPropertyEnv}); // pass the inherited environment/ancestor chain through // unchanged (dropping the chain here would make every // element under <body> think it has no ancestors at all). childFrames.push_back( {child, pXml, nullptr, frame.customPropertyEnv, frame.ancestorChain}); } cur = cur->nextElement(); continue; Loading @@ -1056,8 +1083,12 @@ void blogi::htmlimport::htmlElementToWidgetXml( // Every matching rule for this element -- its own inline style, // every <style> block, and any externally fetched stylesheet // already folded into `sheet` below -- fully cascaded. auto cssRules = libhtmlpp::getCSSRules(*el, sheet, seenMediaBlocks); // already folded into `sheet` below -- fully cascaded, with // frame.ancestorChain (this element's OWN ancestors, not // including itself) verifying any descendant-combinator selector // instead of letting it match regardless of where the element // actually lives. auto cssRules = libhtmlpp::getCSSRules(*el, sheet, seenMediaBlocks, &frame.ancestorChain); auto cssProps = cssRules.properties; std::string mediaRules = cssRules.mediaRules; applyBackgroundColorShorthand(cssProps); Loading @@ -1065,6 +1096,13 @@ void blogi::htmlimport::htmlElementToWidgetXml( std::map<std::string,std::string> elementEnv = resolveCustomProperties(cssProps, frame.customPropertyEnv); // This element's own ancestor chain, for its children's matching // (see Frame::ancestorChain) -- appended once here and reused at // every childFrames.push_back below, rather than re-splitting // cssClass per push site. std::vector<libhtmlpp::AncestorFrame> childAncestorChain = frame.ancestorChain; childAncestorChain.push_back({tag, splitClassList(cssClass), elemId}); // ---- Map HTML tags to widget types ---- // Shared by "section" and the semantic wrapper tags below -- Loading Loading @@ -1119,7 +1157,7 @@ void blogi::htmlimport::htmlElementToWidgetXml( } pXml->InsertEndChild(w); libhtmlpp::Element *child = el->firstChild(); if (child) childFrames.push_back({child, w, nullptr, elementEnv}); if (child) childFrames.push_back({child, w, nullptr, elementEnv, childAncestorChain}); }; if (tag == "section") { Loading Loading @@ -1164,7 +1202,7 @@ void blogi::htmlimport::htmlElementToWidgetXml( } pXml->InsertEndChild(w); libhtmlpp::Element *child = el->firstChild(); if (child) childFrames.push_back({child, w, nullptr, elementEnv}); if (child) childFrames.push_back({child, w, nullptr, elementEnv, childAncestorChain}); } else if (tag == "div" || tag == "label" || tag == "figure" || tag == "figcaption" || tag == "picture" || tag == "li") { Loading Loading @@ -1262,7 +1300,7 @@ void blogi::htmlimport::htmlElementToWidgetXml( } pXml->InsertEndChild(w); libhtmlpp::Element *child = el->firstChild(); if (child) childFrames.push_back({child, w, nullptr, elementEnv}); if (child) childFrames.push_back({child, w, nullptr, elementEnv, childAncestorChain}); } else if (tag == "img") { tinyxml2::XMLElement *w = doc.NewElement("Image"); Loading Loading @@ -1530,7 +1568,8 @@ void blogi::htmlimport::htmlElementToWidgetXml( // the workStack would walk straight through // them too, reprocessing (and duplicating) // every later sibling <li>. childFrames.push_back({liEl, w, liEl->nextElement(), elementEnv}); childFrames.push_back( {liEl, w, liEl->nextElement(), elementEnv, childAncestorChain}); } } } Loading Loading @@ -1679,7 +1718,7 @@ void blogi::htmlimport::htmlElementToWidgetXml( } pXml->InsertEndChild(w); libhtmlpp::Element *child = el->firstChild(); if (child) childFrames.push_back({child, w, nullptr, elementEnv}); if (child) childFrames.push_back({child, w, nullptr, elementEnv, childAncestorChain}); } } else if (tag == "h1" || tag == "h2" || tag == "h3" || tag == "h4" || Loading Loading
editor/src/htmlimport.cpp +48 −9 Original line number Diff line number Diff line Loading @@ -290,6 +290,21 @@ std::string neutralizeFixedStickyPosition(const std::string &css) return std::regex_replace(css, re, "position: static"); } // Splits a whitespace-separated `class` attribute value into its individual // tokens, for building this element's own libhtmlpp::AncestorFrame entry // (see htmlElementToWidgetXml's Frame::ancestorChain) -- getCSSRules/ // collectApproximateMatches do this same split internally for the *target* // element already, but an ancestor frame is built here, once per element, // to hand to its own children's matching later. std::vector<std::string> splitClassList(const std::string &cssClass) { std::vector<std::string> classes; std::istringstream iss(cssClass); std::string cls; while (iss >> cls) classes.push_back(cls); return classes; } // Best-effort extraction of just the color component from a `background` // shorthand value (e.g. "background: url(x.png) no-repeat center red;") -- // every widget's known-CSS mapping only ever looks for the longhand Loading Loading @@ -986,6 +1001,15 @@ void blogi::htmlimport::htmlElementToWidgetXml( tinyxml2::XMLElement *pXml; libhtmlpp::Element *stop = nullptr; std::map<std::string,std::string> customPropertyEnv = {}; // Outermost-ancestor-first, immediate-parent-last (see // libhtmlpp::AncestorFrame's own doc comment) -- passed to // getCSSRules below so a descendant selector like ".header .frame" // only matches an element that's actually inside something with // class "header", instead of leaking onto every ".frame" in the // document regardless of where it lives (the bautenschutz-wetzlar.de // bug: a header-only padding rule was silently zeroing out every // section's own padding because this chain didn't exist yet). std::vector<libhtmlpp::AncestorFrame> ancestorChain = {}; }; std::stack<Frame> workStack; workStack.push({htmlEl, parentXml, stopBefore, rootCustomProperties}); Loading Loading @@ -1039,8 +1063,11 @@ void blogi::htmlimport::htmlElementToWidgetXml( libhtmlpp::Element *child = el->firstChild(); if (child) { // No cssProps computed for these structural tags -- just // pass the inherited environment through unchanged. childFrames.push_back({child, pXml, nullptr, frame.customPropertyEnv}); // pass the inherited environment/ancestor chain through // unchanged (dropping the chain here would make every // element under <body> think it has no ancestors at all). childFrames.push_back( {child, pXml, nullptr, frame.customPropertyEnv, frame.ancestorChain}); } cur = cur->nextElement(); continue; Loading @@ -1056,8 +1083,12 @@ void blogi::htmlimport::htmlElementToWidgetXml( // Every matching rule for this element -- its own inline style, // every <style> block, and any externally fetched stylesheet // already folded into `sheet` below -- fully cascaded. auto cssRules = libhtmlpp::getCSSRules(*el, sheet, seenMediaBlocks); // already folded into `sheet` below -- fully cascaded, with // frame.ancestorChain (this element's OWN ancestors, not // including itself) verifying any descendant-combinator selector // instead of letting it match regardless of where the element // actually lives. auto cssRules = libhtmlpp::getCSSRules(*el, sheet, seenMediaBlocks, &frame.ancestorChain); auto cssProps = cssRules.properties; std::string mediaRules = cssRules.mediaRules; applyBackgroundColorShorthand(cssProps); Loading @@ -1065,6 +1096,13 @@ void blogi::htmlimport::htmlElementToWidgetXml( std::map<std::string,std::string> elementEnv = resolveCustomProperties(cssProps, frame.customPropertyEnv); // This element's own ancestor chain, for its children's matching // (see Frame::ancestorChain) -- appended once here and reused at // every childFrames.push_back below, rather than re-splitting // cssClass per push site. std::vector<libhtmlpp::AncestorFrame> childAncestorChain = frame.ancestorChain; childAncestorChain.push_back({tag, splitClassList(cssClass), elemId}); // ---- Map HTML tags to widget types ---- // Shared by "section" and the semantic wrapper tags below -- Loading Loading @@ -1119,7 +1157,7 @@ void blogi::htmlimport::htmlElementToWidgetXml( } pXml->InsertEndChild(w); libhtmlpp::Element *child = el->firstChild(); if (child) childFrames.push_back({child, w, nullptr, elementEnv}); if (child) childFrames.push_back({child, w, nullptr, elementEnv, childAncestorChain}); }; if (tag == "section") { Loading Loading @@ -1164,7 +1202,7 @@ void blogi::htmlimport::htmlElementToWidgetXml( } pXml->InsertEndChild(w); libhtmlpp::Element *child = el->firstChild(); if (child) childFrames.push_back({child, w, nullptr, elementEnv}); if (child) childFrames.push_back({child, w, nullptr, elementEnv, childAncestorChain}); } else if (tag == "div" || tag == "label" || tag == "figure" || tag == "figcaption" || tag == "picture" || tag == "li") { Loading Loading @@ -1262,7 +1300,7 @@ void blogi::htmlimport::htmlElementToWidgetXml( } pXml->InsertEndChild(w); libhtmlpp::Element *child = el->firstChild(); if (child) childFrames.push_back({child, w, nullptr, elementEnv}); if (child) childFrames.push_back({child, w, nullptr, elementEnv, childAncestorChain}); } else if (tag == "img") { tinyxml2::XMLElement *w = doc.NewElement("Image"); Loading Loading @@ -1530,7 +1568,8 @@ void blogi::htmlimport::htmlElementToWidgetXml( // the workStack would walk straight through // them too, reprocessing (and duplicating) // every later sibling <li>. childFrames.push_back({liEl, w, liEl->nextElement(), elementEnv}); childFrames.push_back( {liEl, w, liEl->nextElement(), elementEnv, childAncestorChain}); } } } Loading Loading @@ -1679,7 +1718,7 @@ void blogi::htmlimport::htmlElementToWidgetXml( } pXml->InsertEndChild(w); libhtmlpp::Element *child = el->firstChild(); if (child) childFrames.push_back({child, w, nullptr, elementEnv}); if (child) childFrames.push_back({child, w, nullptr, elementEnv, childAncestorChain}); } } else if (tag == "h1" || tag == "h2" || tag == "h3" || tag == "h4" || Loading