Fix css style order when using external css files

develop
Nimetu 4 years ago
parent 779f87d6e7
commit d9d9c6e1e6

@ -28,6 +28,7 @@
#include "nel/gui/ctrl_button.h"
#include "nel/gui/group_table.h"
#include "nel/gui/html_element.h"
#include "nel/gui/html_parser.h"
#include "nel/gui/css_style.h"
// forward declaration
@ -376,7 +377,9 @@ namespace NLGUI
// true if renderer is waiting for css files to finish downloading (link rel=stylesheet)
bool _WaitingForStylesheet;
// list of css file urls that are queued up for download
std::vector<std::string> _StylesheetQueue;
std::vector<CHtmlParser::StyleLink> _StylesheetQueue;
// <style> and downloaded <link rel=stylesheet> elements
std::vector<std::string> _HtmlStyles;
// Valid base href was found
bool _IgnoreBaseUrlTag;
@ -890,7 +893,7 @@ namespace NLGUI
std::string localBnpName(const std::string &url);
// add css file from <link href=".." rel="stylesheet"> to download queue
void addStylesheetDownload(std::vector<std::string> links);
void addStylesheetDownload(std::vector<CHtmlParser::StyleLink> links);
// stop all curl downalods (html and data)
void releaseDownloads();

@ -31,14 +31,23 @@ namespace NLGUI
class CHtmlParser
{
public:
// <link rel=stylesheet>
struct StyleLink
{
uint Index;
std::string Url;
StyleLink(uint i, const std::string &url) : Index(i), Url(url)
{ }
};
bool parseHtml(std::string htmlString) const;
// parse html string into DOM, extract <style> tags into styleString, <link stylesheet> urls into links
void getDOM(std::string htmlString, CHtmlElement &parent, std::string &styleString, std::vector<std::string> &links) const;
// parse html string into DOM, extract <style> and <link stylesheet> urls
void getDOM(std::string htmlString, CHtmlElement &parent, std::vector<std::string> &styles, std::vector<StyleLink> &links) const;
private:
// iterate over libxml html tree, build DOM, and join all <style> tags together
void parseNode(xmlNode *a_node, CHtmlElement &parent, std::string &styleString, std::vector<std::string> &links) const;
// iterate over libxml html tree, build DOM
void parseNode(xmlNode *a_node, CHtmlElement &parent, std::vector<std::string> &styles, std::vector<StyleLink> &links) const;
// read <style> tag and add its content to styleString
void parseStyle(xmlNode *a_node, std::string &styleString) const;

@ -858,21 +858,16 @@ namespace NLGUI
CFile::createDirectory( pathName );
}
void CGroupHTML::addStylesheetDownload(std::vector<std::string> links)
void CGroupHTML::addStylesheetDownload(const std::vector<CHtmlParser::StyleLink> links)
{
for(uint i = 0; i < links.size(); ++i)
{
std::string url = getAbsoluteUrl(links[i]);
std::string local = localImageName(url);
_StylesheetQueue.push_back(links[i]);
std::string url = getAbsoluteUrl(links[i].Url);
_StylesheetQueue.back().Url = url;
// insert only if url not already downloading
std::vector<std::string>::const_iterator it = std::find(_StylesheetQueue.begin(), _StylesheetQueue.end(), url);
if (it == _StylesheetQueue.end())
{
_StylesheetQueue.push_back(url);
// push to the front of the queue
Curls.push_front(CDataDownload(url, local, StylesheetType, NULL, "", ""));
}
// push to the front of the queue
Curls.push_front(CDataDownload(url, localImageName(url), StylesheetType, NULL, "", ""));
}
pumpCurlQueue();
}
@ -4184,19 +4179,28 @@ namespace NLGUI
// ***************************************************************************
void CGroupHTML::cssDownloadFinished(const std::string &url, const std::string &local)
{
// remove file from download queue
std::vector<std::string>::iterator it = std::find(_StylesheetQueue.begin(), _StylesheetQueue.end(), url);
if (it != _StylesheetQueue.end())
for(std::vector<CHtmlParser::StyleLink>::iterator it = _StylesheetQueue.begin();
it != _StylesheetQueue.end(); ++it)
{
_StylesheetQueue.erase(it);
}
if (it->Url == url)
{
// read downloaded file into HtmlStyles
if (CFile::fileExists(local) && it->Index < _HtmlStyles.size())
{
CIFile in;
if (in.open(local))
{
if (!in.readAll(_HtmlStyles[it->Index]))
{
nlwarning("Failed to read downloaded css file(%s), url(%s)", local.c_str(), url.c_str());
}
}
}
if (!CFile::fileExists(local))
{
return;
_StylesheetQueue.erase(it);
break;
}
}
parseStylesheetFile(local);
}
void CGroupHTML::renderDocument()
@ -4214,6 +4218,16 @@ namespace NLGUI
beginBuild();
removeContent();
// process all <style> and <link rel=stylesheet> elements
for(uint i = 0; i < _HtmlStyles.size(); ++i)
{
if (!_HtmlStyles[i].empty())
{
_Style.parseStylesheet(_HtmlStyles[i]);
}
}
_HtmlStyles.clear();
std::list<CHtmlElement>::iterator it = _HtmlDOM.Children.begin();
while(it != _HtmlDOM.Children.end())
{
@ -4821,9 +4835,6 @@ namespace NLGUI
// ***************************************************************************
bool CGroupHTML::parseHtml(const std::string &htmlString)
{
std::vector<std::string> links;
std::string styleString;
CHtmlElement *parsedDOM;
if (_CurrentHTMLElement == NULL)
{
@ -4836,16 +4847,28 @@ namespace NLGUI
parsedDOM = _CurrentHTMLElement;
}
std::vector<CHtmlParser::StyleLink> links;
CHtmlParser parser;
parser.getDOM(htmlString, *parsedDOM, styleString, links);
parser.getDOM(htmlString, *parsedDOM, _HtmlStyles, links);
if (!styleString.empty())
// <link> elements inserted from lua::parseHtml are ignored
if (_CurrentHTMLElement == NULL && !links.empty())
{
_Style.parseStylesheet(styleString);
addStylesheetDownload(links);
}
if (!links.empty())
else if (_CurrentHTMLElement != NULL)
{
addStylesheetDownload(links);
// Called from active element (lua)
// <style> order is not preserved as document is already being rendered
for(uint i = 0; i < _HtmlStyles.size(); ++i)
{
if (!_HtmlStyles[i].empty())
{
_Style.parseStylesheet(_HtmlStyles[i]);
}
}
_HtmlStyles.clear();
}
// this should rarely fail as first element should be <html>
@ -4856,7 +4879,7 @@ namespace NLGUI
{
if (it->Type == CHtmlElement::ELEMENT_NODE && it->Value == "html")
{
// more newly parsed childs from <body> into siblings
// move newly parsed childs from <body> into siblings
if (_CurrentHTMLElement) {
std::list<CHtmlElement>::iterator it2 = it->Children.begin();
while(it2 != it->Children.end())

@ -57,7 +57,7 @@ namespace NLGUI
// ***************************************************************************
// recursive function to walk html document
void CHtmlParser::parseNode(xmlNode *a_node, CHtmlElement &parent, std::string &styleString, std::vector<std::string> &links) const
void CHtmlParser::parseNode(xmlNode *a_node, CHtmlElement &parent, std::vector<std::string> &styles, std::vector<StyleLink> &links) const
{
uint childIndex = 0;
uint element_number;
@ -145,7 +145,9 @@ namespace NLGUI
if (useStyle)
{
parseStyle(node->children, styleString);
std::string style;
parseStyle(node->children, style);
styles.push_back(style);
}
// style tag is kept in dom
}
@ -163,13 +165,14 @@ namespace NLGUI
if (useStyle)
{
links.push_back(elm.getAttribute("href"));
styles.push_back("");
links.push_back(StyleLink(styles.size()-1, elm.getAttribute("href")));
}
// link tag is kept in dom
}
else if (node->children)
{
parseNode(node->children, elm, styleString, links);
parseNode(node->children, elm, styles, links);
// must cleanup nested tags that libxml2 does not fix
// dt without end tag: <dl><dt><dt></dl>
@ -406,7 +409,7 @@ namespace NLGUI
}
// ***************************************************************************
void CHtmlParser::getDOM(std::string htmlString, CHtmlElement &dom, std::string &styleString, std::vector<std::string> &links) const
void CHtmlParser::getDOM(std::string htmlString, CHtmlElement &dom, std::vector<std::string> &styles, std::vector<StyleLink> &links) const
{
htmlParserCtxtPtr parser = htmlCreatePushParserCtxt(NULL, NULL, NULL, 0, NULL, XML_CHAR_ENCODING_UTF8);
if (!parser)
@ -428,8 +431,7 @@ namespace NLGUI
xmlNode *root = xmlDocGetRootElement(parser->myDoc);
if (root)
{
styleString.clear();
parseNode(root, dom, styleString, links);
parseNode(root, dom, styles, links);
}
else
{

Loading…
Cancel
Save