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

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

@ -858,21 +858,16 @@ namespace NLGUI
CFile::createDirectory( pathName ); 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) for(uint i = 0; i < links.size(); ++i)
{ {
std::string url = getAbsoluteUrl(links[i]); _StylesheetQueue.push_back(links[i]);
std::string local = localImageName(url); 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 // push to the front of the queue
Curls.push_front(CDataDownload(url, local, StylesheetType, NULL, "", "")); Curls.push_front(CDataDownload(url, localImageName(url), StylesheetType, NULL, "", ""));
}
} }
pumpCurlQueue(); pumpCurlQueue();
} }
@ -4184,19 +4179,28 @@ namespace NLGUI
// *************************************************************************** // ***************************************************************************
void CGroupHTML::cssDownloadFinished(const std::string &url, const std::string &local) void CGroupHTML::cssDownloadFinished(const std::string &url, const std::string &local)
{ {
// remove file from download queue for(std::vector<CHtmlParser::StyleLink>::iterator it = _StylesheetQueue.begin();
std::vector<std::string>::iterator it = std::find(_StylesheetQueue.begin(), _StylesheetQueue.end(), url); it != _StylesheetQueue.end(); ++it)
if (it != _StylesheetQueue.end())
{ {
_StylesheetQueue.erase(it); if (it->Url == url)
}
if (!CFile::fileExists(local))
{ {
return; // 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());
}
}
} }
parseStylesheetFile(local); _StylesheetQueue.erase(it);
break;
}
}
} }
void CGroupHTML::renderDocument() void CGroupHTML::renderDocument()
@ -4214,6 +4218,16 @@ namespace NLGUI
beginBuild(); beginBuild();
removeContent(); 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(); std::list<CHtmlElement>::iterator it = _HtmlDOM.Children.begin();
while(it != _HtmlDOM.Children.end()) while(it != _HtmlDOM.Children.end())
{ {
@ -4821,9 +4835,6 @@ namespace NLGUI
// *************************************************************************** // ***************************************************************************
bool CGroupHTML::parseHtml(const std::string &htmlString) bool CGroupHTML::parseHtml(const std::string &htmlString)
{ {
std::vector<std::string> links;
std::string styleString;
CHtmlElement *parsedDOM; CHtmlElement *parsedDOM;
if (_CurrentHTMLElement == NULL) if (_CurrentHTMLElement == NULL)
{ {
@ -4836,16 +4847,28 @@ namespace NLGUI
parsedDOM = _CurrentHTMLElement; parsedDOM = _CurrentHTMLElement;
} }
std::vector<CHtmlParser::StyleLink> links;
CHtmlParser parser; 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> // 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") 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) { if (_CurrentHTMLElement) {
std::list<CHtmlElement>::iterator it2 = it->Children.begin(); std::list<CHtmlElement>::iterator it2 = it->Children.begin();
while(it2 != it->Children.end()) while(it2 != it->Children.end())

@ -57,7 +57,7 @@ namespace NLGUI
// *************************************************************************** // ***************************************************************************
// recursive function to walk html document // 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 childIndex = 0;
uint element_number; uint element_number;
@ -145,7 +145,9 @@ namespace NLGUI
if (useStyle) if (useStyle)
{ {
parseStyle(node->children, styleString); std::string style;
parseStyle(node->children, style);
styles.push_back(style);
} }
// style tag is kept in dom // style tag is kept in dom
} }
@ -163,13 +165,14 @@ namespace NLGUI
if (useStyle) 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 // link tag is kept in dom
} }
else if (node->children) 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 // must cleanup nested tags that libxml2 does not fix
// dt without end tag: <dl><dt><dt></dl> // 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); htmlParserCtxtPtr parser = htmlCreatePushParserCtxt(NULL, NULL, NULL, 0, NULL, XML_CHAR_ENCODING_UTF8);
if (!parser) if (!parser)
@ -428,8 +431,7 @@ namespace NLGUI
xmlNode *root = xmlDocGetRootElement(parser->myDoc); xmlNode *root = xmlDocGetRootElement(parser->myDoc);
if (root) if (root)
{ {
styleString.clear(); parseNode(root, dom, styles, links);
parseNode(root, dom, styleString, links);
} }
else else
{ {

Loading…
Cancel
Save