friendship ended with social-app. php is my new best friend
1<?php 2 3/* 4 * This file is part of the Symfony package. 5 * 6 * (c) Fabien Potencier <fabien@symfony.com> 7 * 8 * For the full copyright and license information, please view the LICENSE 9 * file that was distributed with this source code. 10 */ 11 12namespace Symfony\Component\CssSelector\XPath\Extension; 13 14use Symfony\Component\CssSelector\Exception\ExpressionErrorException; 15use Symfony\Component\CssSelector\Node\FunctionNode; 16use Symfony\Component\CssSelector\XPath\Translator; 17use Symfony\Component\CssSelector\XPath\XPathExpr; 18 19/** 20 * XPath expression translator HTML extension. 21 * 22 * This component is a port of the Python cssselect library, 23 * which is copyright Ian Bicking, @see https://github.com/SimonSapin/cssselect. 24 * 25 * @author Jean-François Simon <jeanfrancois.simon@sensiolabs.com> 26 * 27 * @internal 28 */ 29class HtmlExtension extends AbstractExtension 30{ 31 public function __construct(Translator $translator) 32 { 33 $translator 34 ->getExtension('node') 35 ->setFlag(NodeExtension::ELEMENT_NAME_IN_LOWER_CASE, true) 36 ->setFlag(NodeExtension::ATTRIBUTE_NAME_IN_LOWER_CASE, true); 37 } 38 39 public function getPseudoClassTranslators(): array 40 { 41 return [ 42 'checked' => $this->translateChecked(...), 43 'link' => $this->translateLink(...), 44 'disabled' => $this->translateDisabled(...), 45 'enabled' => $this->translateEnabled(...), 46 'selected' => $this->translateSelected(...), 47 'invalid' => $this->translateInvalid(...), 48 'hover' => $this->translateHover(...), 49 'visited' => $this->translateVisited(...), 50 ]; 51 } 52 53 public function getFunctionTranslators(): array 54 { 55 return [ 56 'lang' => $this->translateLang(...), 57 ]; 58 } 59 60 public function translateChecked(XPathExpr $xpath): XPathExpr 61 { 62 return $xpath->addCondition( 63 '(@checked ' 64 ."and (name(.) = 'input' or name(.) = 'command')" 65 ."and (@type = 'checkbox' or @type = 'radio'))" 66 ); 67 } 68 69 public function translateLink(XPathExpr $xpath): XPathExpr 70 { 71 return $xpath->addCondition("@href and (name(.) = 'a' or name(.) = 'link' or name(.) = 'area')"); 72 } 73 74 public function translateDisabled(XPathExpr $xpath): XPathExpr 75 { 76 return $xpath->addCondition( 77 '(' 78 .'@disabled and' 79 .'(' 80 ."(name(.) = 'input' and @type != 'hidden')" 81 ." or name(.) = 'button'" 82 ." or name(.) = 'select'" 83 ." or name(.) = 'textarea'" 84 ." or name(.) = 'command'" 85 ." or name(.) = 'fieldset'" 86 ." or name(.) = 'optgroup'" 87 ." or name(.) = 'option'" 88 .')' 89 .') or (' 90 ."(name(.) = 'input' and @type != 'hidden')" 91 ." or name(.) = 'button'" 92 ." or name(.) = 'select'" 93 ." or name(.) = 'textarea'" 94 .')' 95 .' and ancestor::fieldset[@disabled]' 96 ); 97 // todo: in the second half, add "and is not a descendant of that fieldset element's first legend element child, if any." 98 } 99 100 public function translateEnabled(XPathExpr $xpath): XPathExpr 101 { 102 return $xpath->addCondition( 103 '(' 104 .'@href and (' 105 ."name(.) = 'a'" 106 ." or name(.) = 'link'" 107 ." or name(.) = 'area'" 108 .')' 109 .') or (' 110 .'(' 111 ."name(.) = 'command'" 112 ." or name(.) = 'fieldset'" 113 ." or name(.) = 'optgroup'" 114 .')' 115 .' and not(@disabled)' 116 .') or (' 117 .'(' 118 ."(name(.) = 'input' and @type != 'hidden')" 119 ." or name(.) = 'button'" 120 ." or name(.) = 'select'" 121 ." or name(.) = 'textarea'" 122 ." or name(.) = 'keygen'" 123 .')' 124 .' and not (@disabled or ancestor::fieldset[@disabled])' 125 .') or (' 126 ."name(.) = 'option' and not(" 127 .'@disabled or ancestor::optgroup[@disabled]' 128 .')' 129 .')' 130 ); 131 } 132 133 /** 134 * @throws ExpressionErrorException 135 */ 136 public function translateLang(XPathExpr $xpath, FunctionNode $function): XPathExpr 137 { 138 $arguments = $function->getArguments(); 139 foreach ($arguments as $token) { 140 if (!($token->isString() || $token->isIdentifier())) { 141 throw new ExpressionErrorException('Expected a single string or identifier for :lang(), got '.implode(', ', $arguments)); 142 } 143 } 144 145 return $xpath->addCondition(\sprintf( 146 'ancestor-or-self::*[@lang][1][starts-with(concat(' 147 ."translate(@%s, 'ABCDEFGHIJKLMNOPQRSTUVWXYZ', 'abcdefghijklmnopqrstuvwxyz'), '-')" 148 .', %s)]', 149 'lang', 150 Translator::getXpathLiteral(strtolower($arguments[0]->getValue()).'-') 151 )); 152 } 153 154 public function translateSelected(XPathExpr $xpath): XPathExpr 155 { 156 return $xpath->addCondition("(@selected and name(.) = 'option')"); 157 } 158 159 public function translateInvalid(XPathExpr $xpath): XPathExpr 160 { 161 return $xpath->addCondition('0'); 162 } 163 164 public function translateHover(XPathExpr $xpath): XPathExpr 165 { 166 return $xpath->addCondition('0'); 167 } 168 169 public function translateVisited(XPathExpr $xpath): XPathExpr 170 { 171 return $xpath->addCondition('0'); 172 } 173 174 public function getName(): string 175 { 176 return 'html'; 177 } 178}