Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- bool GUI::XHTMLDisplayer::doesSelectorMatch(const std::string& selector, XMLDocument::NodeID node) {
- // first case: if there is a comma in the selector, splitting it and calling doesSelectorMatch with each part
- // TODO:
- // second case: if the selector ends with ::something (eg. after, before, etc.), ie. pseudo elements
- // TODO:
- // third case: if the selector ends with :something (eg. last-child, empty, etc.), ie. structural pseudo-classes
- // calling doesSelectorMatch with the first part of the selector, then checking the thing on the right
- { static std::regex regex("^(.*):([^:]+)$");
- std::smatch matchResults;
- if (std::regex_match(selector, matchResults, regex)) {
- if (!doesSelectorMatch(matchResults[1].str(), node))
- return false;
- // now testing the structural pseudo-class
- const auto secondPart = matchResults[2].str();
- if (secondPart == "root") {
- return _xhtmlDocument.getParent(node) == _xhtmlDocument.getDocumentElement();
- } else if (secondPart == "first-child") {
- auto children = _xhtmlDocument.getChildren(_xhtmlDocument.getParent(node));
- for (auto i = children.begin(); i != children.end(); ++i)
- if (_xhtmlDocument.getNodeType(*i) == XMLDocument::NODETYPE_ELEMENT && *i != node)
- return false;
- return true;
- }
- // unknown structural pseudo-class
- return false;
- }
- }
- // fourth case: a class, like: E.warning
- // TODO:
- // fifth case: an ID, like: E#myid
- // TODO:
- // sixth case: an attribute selector, like E[attr] or E[attr="test"]
- // TODO:
- // seventh case: the selector is "A B" or "A ~ B" or "A + B" or "A > B"
- { static std::regex regex("^(.*)\\s*(~|\\+|\\>| )?\\s*[[:alnum:]-_\\.]+$");
- std::smatch matchResults;
- if (std::regex_match(selector, matchResults, regex)) {
- if (!doesSelectorMatch(matchResults[3].str(), node))
- return false;
- const auto firstPart = matchResults[1].str();
- const auto combinator = matchResults[2].matched ? matchResults[2].str().at(0) : ' ';
- // now dispatching depending on the combinator
- if (combinator == '>') {
- // the '>' combinator means the first part must be the parent of the second part
- return doesSelectorMatch(firstPart, _xhtmlDocument.getParent(node));
- } else if (combinator == '+') {
- // the '+' combinator means the first part must be THE previous element sibling of the second part
- for (auto i = _xhtmlDocument.getPreviousSibling(node); ; i = _xhtmlDocument.getPreviousSibling(i)) {
- if (_xhtmlDocument.getNodeType(i) == XMLDocument::NODETYPE_ELEMENT)
- return doesSelectorMatch(firstPart, i);
- if (!_xhtmlDocument.hasPreviousSibling(i))
- break;
- }
- return false;
- } else if (combinator == '~') {
- // the '~' combinator means the first part must be one of the previous siblings of the second part
- for (auto i = _xhtmlDocument.getPreviousSibling(node); ; i = _xhtmlDocument.getPreviousSibling(i)) {
- if (_xhtmlDocument.getNodeType(i) == XMLDocument::NODETYPE_ELEMENT && doesSelectorMatch(firstPart, i))
- return true;
- if (!_xhtmlDocument.hasPreviousSibling(i))
- break;
- }
- return false;
- } else if (combinator == ' ') {
- // the ' ' combinator means the first part must be an ancestor of the second part
- for (auto i = _xhtmlDocument.getParent(node); i != _xhtmlDocument.getDocumentElement(); i = _xhtmlDocument.getParent(i)) {
- if (doesSelectorMatch(firstPart, i))
- return true;
- }
- return false;
- } else {
- // unknown combinator
- return false;
- }
- }
- }
- // eight case: the selector is just a node name or a star
- { static std::regex regex("^\\s*(\\*|[[:alnum:]-_\\.]+)\\s*$");
- std::smatch matchResults;
- if (std::regex_match(selector, matchResults, regex)) {
- const auto name = matchResults[1].str();
- return name == _xhtmlDocument.getNodeName(node) || name == "*";
- }
- }
- // if everything failed, returning false
- return false;
- }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement