]> scripts.mit.edu Git - autoinstalls/mediawiki.git/blobdiff - vendor/wikimedia/remex-html/RemexHtml/TreeBuilder/SimpleStack.php
MediaWiki 1.30.2
[autoinstalls/mediawiki.git] / vendor / wikimedia / remex-html / RemexHtml / TreeBuilder / SimpleStack.php
diff --git a/vendor/wikimedia/remex-html/RemexHtml/TreeBuilder/SimpleStack.php b/vendor/wikimedia/remex-html/RemexHtml/TreeBuilder/SimpleStack.php
new file mode 100644 (file)
index 0000000..f6bec4a
--- /dev/null
@@ -0,0 +1,202 @@
+<?php
+namespace RemexHtml\TreeBuilder;
+use RemexHtml\HTMLData;
+
+/**
+ * An implementation of the "stack of open elements" which, unlike CachingStack,
+ * iterates through the stack in order to answer queries about which elements
+ * are in scope. This is presumably faster for best case input.
+ */
+class SimpleStack extends Stack {
+       private $elements;
+
+       /**
+        * A 2-d array giving the element types which break a scope region for the
+        * default scope, i.e. the one for phrases of the form "has an X element
+        * in scope".
+        * @var bool[string][string]
+        */
+       private static $defaultScope = [
+               HTMLData::NS_HTML => [
+                       'applet' => true,
+                       'caption' => true,
+                       'html' => true,
+                       'table' => true,
+                       'td' => true,
+                       'th' => true,
+                       'marquee' => true,
+                       'object' => true,
+                       'template' => true,
+               ],
+               HTMLData::NS_MATHML => [
+                       'mi' => true,
+                       'mo' => true,
+                       'mn' => true,
+                       'ms' => true,
+                       'mtext' => true,
+                       'annotation-xml' => true,
+               ],
+               HTMLData::NS_SVG => [
+                       'foreignObject' => true,
+                       'desc' => true,
+                       'title' => true,
+               ],
+       ];
+
+       /**
+        * The element types which break the table scope.
+        * @var bool[string][string]
+        */
+       private static $tableScope = [
+               HTMLData::NS_HTML => [
+                       'html' => true,
+                       'table' => true,
+                       'template' => true,
+               ]
+       ];
+
+       /**
+        * The element types which break the list scope. This is lazy-initialised.
+        * @var bool[string][string]
+        */
+       private static $listScope;
+
+       /**
+        * The element types which break the button scope. This is lazy-initialised.
+        * @var bool[string][string]
+        */
+       private static $buttonScope;
+
+       public function push( Element $elt ) {
+               $n = count( $this->elements );
+               $this->elements[$n] = $elt;
+               $this->current = $elt;
+               $elt->stackIndex = $n;
+       }
+
+       public function pop() {
+               $elt = array_pop( $this->elements );
+               $elt->stackIndex = null;
+               $n = count( $this->elements );
+               $this->current = $n ? $this->elements[$n - 1] : null;
+               return $elt;
+       }
+
+       public function replace( Element $oldElt, Element $elt ) {
+               $idx = $oldElt->stackIndex;
+               $this->elements[$idx] = $elt;
+               $oldElt->stackIndex = null;
+               $elt->stackIndex = $idx;
+               if ( $idx === count( $this->elements ) - 1 ) {
+                       $this->current = $elt;
+               }
+       }
+
+       public function remove( Element $elt ) {
+               $eltIndex = $elt->stackIndex;
+               $n = count( $this->elements );
+               for ( $i = $eltIndex + 1; $i < $n; $i++ ) {
+                       $this->elements[$i]->stackIndex --;
+               }
+               $elt->stackIndex = null;
+       }
+
+       public function isInScope( $name ) {
+               return $this->isInSpecificScope( $name, self::$defaultScope );
+       }
+
+       public function isElementInScope( Element $elt ) {
+               for ( $i = count( $this->elements ) - 1; $i >= 0; $i-- ) {
+                       $node = $this->elements[$i];
+                       if ( $node === $elt ) {
+                               return true;
+                       }
+                       if ( isset( self::$defaultScope[$node->namespace][$node->name] ) ) {
+                               return false;
+                       }
+               }
+               return false;
+       }
+
+       public function isOneOfSetInScope( $names ) {
+               for ( $i = count( $this->elements ) - 1; $i >= 0; $i-- ) {
+                       $node = $this->elements[$i];
+                       if ( $node->namespace === HTMLData::NS_HTML && isset( $names[$node->name] ) ) {
+                               return true;
+                       }
+                       if ( isset( self::$defaultScope[$node->namespace][$node->name] ) ) {
+                               return false;
+                       }
+               }
+               return false;
+       }
+
+       public function isInListScope( $name ) {
+               if ( self::$listScope === null ) {
+                       self::$listScope = self::$defaultScope;
+                       self::$listScope[HTMLData::NS_HTML] += [
+                               'ol' => true,
+                               'li' => true
+                       ];
+               }
+               return $this->isInSpecificScope( $name, self::$listScope );
+       }
+
+       public function isInButtonScope( $name ) {
+               if ( self::$buttonScope === null ) {
+                       self::$buttonScope = self::$defaultScope;
+                       self::$buttonScope[HTMLData::NS_HTML]['button'] = true;
+               }
+               return $this->isInSpecificScope( $name, self::$buttonScope );
+       }
+
+       public function isInTableScope( $name ) {
+               return $this->isInSpecificScope( $name, self::$tableScope );
+       }
+
+       public function isInSelectScope( $name ) {
+               for ( $i = count( $this->elements ) - 1; $i >= 0; $i-- ) {
+                       $node = $this->elements[$i];
+                       if ( $node->namespace === HTMLData::NS_HTML && $node->name === $name ) {
+                               return true;
+                       }
+                       if ( $node->namespace !== HTMLData::NS_HTML ) {
+                               return false;
+                       }
+                       if ( $node->name !== 'optgroup' && $node->name !== 'option' ) {
+                               return false;
+                       }
+               }
+               return false;
+       }
+
+       private function isInSpecificScope( $name, $set ) {
+               for ( $i = count( $this->elements ) - 1; $i >= 0; $i-- ) {
+                       $node = $this->elements[$i];
+                       if ( $node->namespace === HTMLData::NS_HTML && $node->name === $name ) {
+                               return true;
+                       }
+                       if ( isset( $set[$node->namespace][$node->name] ) ) {
+                               return false;
+                       }
+               }
+               return false;
+       }
+
+       public function item( $idx ) {
+               return $this->elements[$idx];
+       }
+
+       public function length() {
+               return count( $this->elements );
+       }
+
+       public function hasTemplate() {
+               foreach ( $this->elements as $elt ) {
+                       if ( $elt->namespace === HTMLData::NS_HTML && $elt->name === 'template' ) {
+                               return true;
+                       }
+               }
+               return false;
+       }
+}