Ejemplo n.º 1
0
 /**
  * Callback function: <tag> | </tag> | ....
  * @return string
  * @internal
  */
 public function cb($matches)
 {
     // html tag
     list(, $mText, $mComment, $mEnd, $mTag, $mAttr, $mEmpty) = $matches;
     // [1] => text
     // [1] => !-- comment --
     // [2] => /
     // [3] => TAG
     // [4] => ... (attributes)
     // [5] => / (empty)
     $s = '';
     // phase #1 - stuff between tags
     if ($mText !== '') {
         $item = reset($this->tagStack);
         if ($item && !isset($item['dtdContent']['%DATA'])) {
             // text not allowed?
         } elseif (array_intersect(array_keys($this->tagUsed, TRUE), $this->preserveSpaces)) {
             // inside pre & textarea preserve spaces
             $s = Texy\Helpers::freezeSpaces($mText);
         } else {
             $s = Regexp::replace($mText, '#[ \\n]+#', ' ');
             // otherwise shrink multiple spaces
         }
     }
     // phase #2 - HTML comment
     if ($mComment) {
         return $s . '<' . Texy\Helpers::freezeSpaces($mComment) . '>';
     }
     // phase #3 - HTML tag
     $mEmpty = $mEmpty || isset(HtmlElement::$emptyElements[$mTag]);
     if ($mEmpty && $mEnd) {
         return $s;
         // bad tag; /end/
     }
     if ($mEnd) {
         // end tag
         // has start tag?
         if (empty($this->tagUsed[$mTag])) {
             return $s;
         }
         // autoclose tags
         $tmp = [];
         $back = TRUE;
         foreach ($this->tagStack as $i => $item) {
             $tag = $item['tag'];
             $s .= $item['close'];
             $this->space -= $item['indent'];
             $this->tagUsed[$tag]--;
             $back = $back && isset(HtmlElement::$inlineElements[$tag]);
             unset($this->tagStack[$i]);
             if ($tag === $mTag) {
                 break;
             }
             array_unshift($tmp, $item);
         }
         if (!$back || !$tmp) {
             return $s;
         }
         // allowed-check (nejspis neni ani potreba)
         $item = reset($this->tagStack);
         $dtdContent = $item ? $item['dtdContent'] : $this->baseDTD;
         if (!isset($dtdContent[$tmp[0]['tag']])) {
             return $s;
         }
         // autoopen tags
         foreach ($tmp as $item) {
             $s .= $item['open'];
             $this->space += $item['indent'];
             $this->tagUsed[$item['tag']]++;
             array_unshift($this->tagStack, $item);
         }
     } else {
         // start tag
         $dtdContent = $this->baseDTD;
         if (!isset($this->texy->dtd[$mTag])) {
             // unknown (non-html) tag
             $allowed = TRUE;
             $item = reset($this->tagStack);
             if ($item) {
                 $dtdContent = $item['dtdContent'];
             }
         } else {
             // optional end tag closing
             foreach ($this->tagStack as $i => $item) {
                 // is tag allowed here?
                 $dtdContent = $item['dtdContent'];
                 if (isset($dtdContent[$mTag])) {
                     break;
                 }
                 $tag = $item['tag'];
                 // auto-close hidden, optional and inline tags
                 if ($item['close'] && (!isset(HtmlElement::$optionalEnds[$tag]) && !isset(HtmlElement::$inlineElements[$tag]))) {
                     break;
                 }
                 // close it
                 $s .= $item['close'];
                 $this->space -= $item['indent'];
                 $this->tagUsed[$tag]--;
                 unset($this->tagStack[$i]);
                 $dtdContent = $this->baseDTD;
             }
             // is tag allowed in this content?
             $allowed = isset($dtdContent[$mTag]);
             // check deep element prohibitions
             if ($allowed && isset(HtmlElement::$prohibits[$mTag])) {
                 foreach (HtmlElement::$prohibits[$mTag] as $pTag) {
                     if (!empty($this->tagUsed[$pTag])) {
                         $allowed = FALSE;
                         break;
                     }
                 }
             }
         }
         // empty elements se neukladaji do zasobniku
         if ($mEmpty) {
             if (!$allowed) {
                 return $s;
             }
             if ($this->xml) {
                 $mAttr .= ' /';
             }
             $indent = $this->indent && !array_intersect(array_keys($this->tagUsed, TRUE), $this->preserveSpaces);
             if ($indent && $mTag === 'br') {
                 // formatting exception
                 return rtrim($s) . '<' . $mTag . $mAttr . ">\n" . str_repeat("\t", max(0, $this->space - 1)) . "";
             } elseif ($indent && !isset(HtmlElement::$inlineElements[$mTag])) {
                 $space = "\r" . str_repeat("\t", $this->space);
                 return $s . $space . '<' . $mTag . $mAttr . '>' . $space;
             } else {
                 return $s . '<' . $mTag . $mAttr . '>';
             }
         }
         $open = NULL;
         $close = NULL;
         $indent = 0;
         /*
         if (!isset(Texy\HtmlElement::$inlineElements[$mTag])) {
         	// block tags always decorate with \n
         	$s .= "\n";
         	$close = "\n";
         }
         */
         if ($allowed) {
             $open = '<' . $mTag . $mAttr . '>';
             // receive new content (ins & del are special cases)
             if (!empty($this->texy->dtd[$mTag][1])) {
                 $dtdContent = $this->texy->dtd[$mTag][1];
             }
             // format output
             if ($this->indent && !isset(HtmlElement::$inlineElements[$mTag])) {
                 $close = "" . '</' . $mTag . '>' . "\n" . str_repeat("\t", $this->space);
                 $s .= "\n" . str_repeat("\t", $this->space++) . $open . "";
                 $indent = 1;
             } else {
                 $close = '</' . $mTag . '>';
                 $s .= $open;
             }
             // TODO: problematic formatting of select / options, object / params
         }
         // open tag, put to stack, increase counter
         $item = ['tag' => $mTag, 'open' => $open, 'close' => $close, 'dtdContent' => $dtdContent, 'indent' => $indent];
         array_unshift($this->tagStack, $item);
         $tmp =& $this->tagUsed[$mTag];
         $tmp++;
     }
     return $s;
 }