usage: $anchor = (new HtmlElement('a'))->href($link)->setText('Texy'); $el->class = 'myclass'; echo $el->startTag(), $el->endTag();
Inheritance: implements ArrayAccess, implements IteratorAggregate, use trait Strict
Example #1
0
 /**
  * Finish invocation.
  * @return Texy\HtmlElement|FALSE
  */
 public function solve(Texy\HandlerInvocation $invocation, $content, Texy\Modifier $mod = NULL)
 {
     $texy = $this->texy;
     // find hard linebreaks
     if ($texy->mergeLines) {
         // ....
         // ... => \r means break line
         $content = Regexp::replace($content, '#\\n +(?=\\S)#', "\r");
     } else {
         $content = Regexp::replace($content, '#\\n#', "\r");
     }
     $el = new Texy\HtmlElement('p');
     $el->parseLine($texy, $content);
     $content = $el->getText();
     // string
     // check content type
     // block contains block tag
     if (strpos($content, $texy::CONTENT_BLOCK) !== FALSE) {
         $el->setName(NULL);
         // ignores modifier!
         // block contains text (protected)
     } elseif (strpos($content, $texy::CONTENT_TEXTUAL) !== FALSE) {
         // leave element p
         // block contains text
     } elseif (preg_match('#[^\\s' . Texy\Patterns::MARK . ']#u', $content)) {
         // leave element p
         // block contains only replaced element
     } elseif (strpos($content, $texy::CONTENT_REPLACED) !== FALSE) {
         $el->setName($texy->nontextParagraph);
         // block contains only markup tags or spaces or nothing
     } else {
         // if {ignoreEmptyStuff} return FALSE;
         if (!$mod) {
             $el->setName(NULL);
         }
     }
     if ($el->getName()) {
         // apply modifier
         if ($mod) {
             $mod->decorate($texy, $el);
         }
         // add <br />
         if (strpos($content, "\r") !== FALSE) {
             $key = $texy->protect('<br />', $texy::CONTENT_REPLACED);
             $content = str_replace("\r", $key, $content);
         }
     }
     $content = strtr($content, "\r\n", '  ');
     $el->setText($content);
     return $el;
 }
Example #2
0
 /**
  * Callback for:.
  *
  * 1) .... .(title)[class]{style}>
  * 2) ....
  *   + ...
  *   + ...
  * 3) ....
  *
  * @return HtmlElement|FALSE
  */
 public function patternList(BlockParser $parser, array $matches)
 {
     list(, $mMod, $mBullet) = $matches;
     // [1] => .(title)[class]{style}<>
     // [2] => bullet * + - 1) a) A) IV)
     $el = new HtmlElement();
     $bullet = $min = NULL;
     foreach ($this->bullets as $type => $desc) {
         if (preg_match('#' . $desc[0] . '#Au', $mBullet)) {
             $bullet = isset($desc[3]) ? $desc[3] : $desc[0];
             $min = isset($desc[3]) ? 2 : 1;
             $el->setName($desc[1] ? 'ol' : 'ul');
             $el->attrs['style']['list-style-type'] = $desc[2];
             if ($desc[1]) {
                 // ol
                 if ($type[0] === '1' && (int) $mBullet > 1) {
                     $el->attrs['start'] = (int) $mBullet;
                 } elseif ($type[0] === 'a' && $mBullet[0] > 'a') {
                     $el->attrs['start'] = ord($mBullet[0]) - 96;
                 } elseif ($type[0] === 'A' && $mBullet[0] > 'A') {
                     $el->attrs['start'] = ord($mBullet[0]) - 64;
                 }
             }
             break;
         }
     }
     $mod = new Modifier($mMod);
     $mod->decorate($this->texy, $el);
     $parser->moveBackward(1);
     while ($elItem = $this->patternItem($parser, $bullet, FALSE, 'li')) {
         $el->add($elItem);
     }
     if ($el->count() < $min) {
         return FALSE;
     }
     // event listener
     $this->texy->invokeHandlers('afterList', [$parser, $el, $mod]);
     return $el;
 }
Example #3
0
 /**
  * Callback for: [ref].
  * @return Texy\HtmlElement|string|FALSE
  */
 public function patternReference(LineParser $parser, array $matches)
 {
     list(, $mRef) = $matches;
     // [1] => [ref]
     $texy = $this->texy;
     $name = substr($mRef, 1, -1);
     $link = $this->getReference($name);
     if (!$link) {
         return $texy->invokeAroundHandlers('newReference', $parser, [$name]);
     }
     $link->type = $link::BRACKET;
     if ($link->label != '') {
         // NULL or ''
         // prevent circular references
         if (isset(self::$livelock[$link->name])) {
             $content = $link->label;
         } else {
             self::$livelock[$link->name] = TRUE;
             $el = new Texy\HtmlElement();
             $lineParser = new LineParser($texy, $el);
             $lineParser->parse($link->label);
             $content = $el->toString($texy);
             unset(self::$livelock[$link->name]);
         }
     } else {
         $content = $this->textualUrl($link);
         $content = $this->texy->protect($content, $texy::CONTENT_TEXTUAL);
     }
     return $texy->invokeAroundHandlers('linkReference', $parser, [$link, $content]);
 }
Example #4
0
 /**
  * Finish invocation.
  * @return Texy\HtmlElement
  */
 public function solve(Texy\HandlerInvocation $invocation, $phrase, $content, Modifier $mod, Texy\Link $link = NULL)
 {
     $texy = $this->texy;
     $tag = isset($this->tags[$phrase]) ? $this->tags[$phrase] : NULL;
     if ($tag === 'a') {
         $tag = $link && $this->linksAllowed ? NULL : 'span';
     }
     if ($phrase === 'phrase/code') {
         $content = $texy->protect(htmlspecialchars($content, ENT_NOQUOTES, 'UTF-8'), $texy::CONTENT_TEXTUAL);
     }
     if ($phrase === 'phrase/strong+em') {
         $el = new Texy\HtmlElement($this->tags['phrase/strong']);
         $el->create($this->tags['phrase/em'], $content);
         $mod->decorate($texy, $el);
     } elseif ($tag) {
         $el = new Texy\HtmlElement($tag, $content);
         $mod->decorate($texy, $el);
         if ($tag === 'q') {
             $el->attrs['cite'] = $mod->cite;
         }
     } else {
         $el = $content;
         // trick
     }
     if ($link && $this->linksAllowed) {
         return $texy->linkModule->solve(NULL, $link, $el);
     }
     return $el;
 }
Example #5
0
 /**
  * Finish invocation.
  * @return HtmlElement|string|FALSE
  */
 public function solveTag(Texy\HandlerInvocation $invocation, HtmlElement $el, $isStart, $forceEmpty = NULL)
 {
     $texy = $this->texy;
     // tag & attibutes
     $allowedTags = $texy->allowedTags;
     // speed-up
     if (!$allowedTags) {
         return FALSE;
         // all tags are disabled
     }
     // convert case
     $name = $el->getName();
     $lower = strtolower($name);
     if (isset($texy->dtd[$lower]) || $name === strtoupper($name)) {
         // complete UPPER convert to lower
         $name = $lower;
         $el->setName($name);
     }
     if (is_array($allowedTags)) {
         if (!isset($allowedTags[$name])) {
             return FALSE;
         }
         $allowedAttrs = $allowedTags[$name];
         // allowed attrs
     } else {
         // allowedTags === Texy\Texy::ALL
         if ($forceEmpty) {
             $el->setName($name, TRUE);
         }
         $allowedAttrs = $texy::ALL;
         // all attrs are allowed
     }
     // end tag? we are finished
     if (!$isStart) {
         return $el;
     }
     $elAttrs =& $el->attrs;
     // process attributes
     if (!$allowedAttrs) {
         $elAttrs = [];
     } elseif (is_array($allowedAttrs)) {
         // skip disabled
         $allowedAttrs = array_flip($allowedAttrs);
         foreach ($elAttrs as $key => $foo) {
             if (!isset($allowedAttrs[$key])) {
                 unset($elAttrs[$key]);
             }
         }
     }
     // apply allowedClasses
     $tmp = $texy->_classes;
     // speed-up
     if (isset($elAttrs['class'])) {
         if (is_array($tmp)) {
             $elAttrs['class'] = explode(' ', $elAttrs['class']);
             foreach ($elAttrs['class'] as $key => $value) {
                 if (!isset($tmp[$value])) {
                     unset($elAttrs['class'][$key]);
                     // id & class are case-sensitive
                 }
             }
         } elseif ($tmp !== $texy::ALL) {
             $elAttrs['class'] = NULL;
         }
     }
     // apply allowedClasses for ID
     if (isset($elAttrs['id'])) {
         if (is_array($tmp)) {
             if (!isset($tmp['#' . $elAttrs['id']])) {
                 $elAttrs['id'] = NULL;
             }
         } elseif ($tmp !== $texy::ALL) {
             $elAttrs['id'] = NULL;
         }
     }
     // apply allowedStyles
     if (isset($elAttrs['style'])) {
         $tmp = $texy->_styles;
         // speed-up
         if (is_array($tmp)) {
             $styles = explode(';', $elAttrs['style']);
             $elAttrs['style'] = NULL;
             foreach ($styles as $value) {
                 $pair = explode(':', $value, 2);
                 $prop = trim($pair[0]);
                 if (isset($pair[1]) && isset($tmp[strtolower($prop)])) {
                     // CSS is case-insensitive
                     $elAttrs['style'][$prop] = $pair[1];
                 }
             }
         } elseif ($tmp !== $texy::ALL) {
             $elAttrs['style'] = NULL;
         }
     }
     foreach (['src', 'href', 'name', 'id'] as $attr) {
         if (isset($elAttrs[$attr])) {
             $elAttrs[$attr] = is_string($elAttrs[$attr]) ? trim($elAttrs[$attr]) : '';
             if ($elAttrs[$attr] === '') {
                 unset($elAttrs[$attr]);
             }
         }
     }
     if ($name === 'img') {
         if (!isset($elAttrs['src']) || !$texy->checkURL($elAttrs['src'], $texy::FILTER_IMAGE)) {
             return FALSE;
         }
         $texy->summary['images'][] = $elAttrs['src'];
     } elseif ($name === 'a') {
         if (!isset($elAttrs['href']) && !isset($elAttrs['name']) && !isset($elAttrs['id'])) {
             return FALSE;
         }
         if (isset($elAttrs['href'])) {
             if ($texy->linkModule->forceNoFollow && strpos($elAttrs['href'], '//') !== FALSE) {
                 if (isset($elAttrs['rel'])) {
                     $elAttrs['rel'] = (array) $elAttrs['rel'];
                 }
                 $elAttrs['rel'][] = 'nofollow';
             }
             if (!$texy->checkURL($elAttrs['href'], $texy::FILTER_ANCHOR)) {
                 return FALSE;
             }
             $texy->summary['links'][] = $elAttrs['href'];
         }
     } elseif (preg_match('#^h[1-6]#i', $name)) {
         $texy->headingModule->TOC[] = ['el' => $el, 'level' => (int) substr($name, 1), 'type' => 'html'];
     }
     $el->validateAttrs($texy->dtd);
     return $el;
 }
Example #6
0
 /**
  * Finish invocation.
  * @return HtmlElement|string|FALSE
  */
 public function solve(Texy\HandlerInvocation $invocation, $blocktype, $s, $param, Texy\Modifier $mod)
 {
     $texy = $this->texy;
     $parser = $invocation->getParser();
     if ($blocktype === 'block/texy') {
         $el = new HtmlElement();
         $el->parseBlock($texy, $s, $parser->isIndented());
         return $el;
     }
     if (empty($texy->allowed[$blocktype])) {
         return FALSE;
     }
     if ($blocktype === 'block/texysource') {
         $s = Helpers::outdent($s);
         if ($s === '') {
             return "\n";
         }
         $el = new HtmlElement();
         if ($param === 'line') {
             $el->parseLine($texy, $s);
         } else {
             $el->parseBlock($texy, $s);
         }
         $s = $el->toHtml($texy);
         $blocktype = 'block/code';
         $param = 'html';
         // to be continue (as block/code)
     }
     if ($blocktype === 'block/code') {
         $s = Helpers::outdent($s);
         if ($s === '') {
             return "\n";
         }
         $s = htmlspecialchars($s, ENT_NOQUOTES, 'UTF-8');
         $s = $texy->protect($s, $texy::CONTENT_BLOCK);
         $el = new HtmlElement('pre');
         $mod->decorate($texy, $el);
         $el->attrs['class'][] = $param;
         // lang
         $el->create('code', $s);
         return $el;
     }
     if ($blocktype === 'block/default') {
         $s = Helpers::outdent($s);
         if ($s === '') {
             return "\n";
         }
         $el = new HtmlElement('pre');
         $mod->decorate($texy, $el);
         $el->attrs['class'][] = $param;
         // lang
         $s = htmlspecialchars($s, ENT_NOQUOTES, 'UTF-8');
         $s = $texy->protect($s, $texy::CONTENT_BLOCK);
         $el->setText($s);
         return $el;
     }
     if ($blocktype === 'block/pre') {
         $s = Helpers::outdent($s);
         if ($s === '') {
             return "\n";
         }
         $el = new HtmlElement('pre');
         $mod->decorate($texy, $el);
         $lineParser = new Texy\LineParser($texy, $el);
         // special mode - parse only html tags
         $tmp = $lineParser->patterns;
         $lineParser->patterns = [];
         if (isset($tmp['html/tag'])) {
             $lineParser->patterns['html/tag'] = $tmp['html/tag'];
         }
         if (isset($tmp['html/comment'])) {
             $lineParser->patterns['html/comment'] = $tmp['html/comment'];
         }
         unset($tmp);
         $lineParser->parse($s);
         $s = $el->getText();
         $s = html_entity_decode($s, ENT_QUOTES, 'UTF-8');
         $s = htmlspecialchars($s, ENT_NOQUOTES, 'UTF-8');
         $s = $texy->unprotect($s);
         $s = $texy->protect($s, $texy::CONTENT_BLOCK);
         $el->setText($s);
         return $el;
     }
     if ($blocktype === 'block/html') {
         $s = trim($s, "\n");
         if ($s === '') {
             return "\n";
         }
         $el = new HtmlElement();
         $lineParser = new Texy\LineParser($texy, $el);
         // special mode - parse only html tags
         $tmp = $lineParser->patterns;
         $lineParser->patterns = [];
         if (isset($tmp['html/tag'])) {
             $lineParser->patterns['html/tag'] = $tmp['html/tag'];
         }
         if (isset($tmp['html/comment'])) {
             $lineParser->patterns['html/comment'] = $tmp['html/comment'];
         }
         unset($tmp);
         $lineParser->parse($s);
         $s = $el->getText();
         $s = html_entity_decode($s, ENT_QUOTES, 'UTF-8');
         $s = htmlspecialchars($s, ENT_NOQUOTES, 'UTF-8');
         $s = $texy->unprotect($s);
         return $texy->protect($s, $texy::CONTENT_BLOCK) . "\n";
     }
     if ($blocktype === 'block/text') {
         $s = trim($s, "\n");
         if ($s === '') {
             return "\n";
         }
         $s = htmlspecialchars($s, ENT_NOQUOTES, 'UTF-8');
         $s = str_replace("\n", (new HtmlElement('br'))->startTag(), $s);
         // nl2br
         return $texy->protect($s, $texy::CONTENT_BLOCK) . "\n";
     }
     if ($blocktype === 'block/comment') {
         return "\n";
     }
     if ($blocktype === 'block/div') {
         $s = Helpers::outdent($s, TRUE);
         if ($s === '') {
             return "\n";
         }
         $el = new HtmlElement('div');
         $mod->decorate($texy, $el);
         $el->parseBlock($texy, $s, $parser->isIndented());
         // TODO: INDENT or NORMAL ?
         return $el;
     }
     return FALSE;
 }
Example #7
0
 /**
  * Parse text in all cells.
  * @return void
  */
 private function finishPart(HtmlElement $elPart)
 {
     foreach ($elPart->getChildren() as $elRow) {
         foreach ($elRow->getChildren() as $elCell) {
             if ($elCell->colSpan > 1) {
                 $elCell->attrs['colspan'] = $elCell->colSpan;
             }
             if ($elCell->rowSpan > 1) {
                 $elCell->attrs['rowspan'] = $elCell->rowSpan;
             }
             $text = rtrim($elCell->text);
             if (strpos($text, "\n") !== FALSE) {
                 // multiline parse as block
                 // HACK: disable tables
                 $this->disableTables = TRUE;
                 $elCell->parseBlock($this->texy, Texy\Helpers::outdent($text));
                 $this->disableTables = FALSE;
             } else {
                 $elCell->parseLine($this->texy, ltrim($text));
             }
             if ($elCell->getText() === '') {
                 $elCell->setText(" ");
                 // &nbsp;
             }
         }
     }
 }
Example #8
0
 public function blockHandler($invocation, $blocktype, $content, $lang, $modifier)
 {
     if ($blocktype !== 'block/code') {
         return $invocation->proceed();
         //vstup se nebude zpracovavat
     }
     $highlighter = new \FSHL\Highlighter(new \FSHL\Output\Html(), \FSHL\Highlighter::OPTION_TAB_INDENT);
     $texy = $invocation->getTexy();
     $content = \Texy\Texy::outdent($content);
     //Set correct lexer:
     $lang = $lang ?: '';
     switch (strtoupper($lang)) {
         case 'C':
         case 'CPP':
             $lexer = new \FSHL\Lexer\Cpp();
             break;
         case 'CSS':
             $lexer = new \FSHL\Lexer\Css();
             break;
         case 'HTML':
             $lexer = new \FSHL\Lexer\Html();
             break;
             //HtmlOnly lexer
         //HtmlOnly lexer
         case 'JAVA':
             $lexer = new \FSHL\Lexer\Java();
             break;
         case 'JS':
         case 'JAVASCRIPT':
             $lexer = new \FSHL\Lexer\Javascript();
             break;
         case 'NEON':
             $lexer = new \FSHL\Lexer\Neon();
             break;
         case 'PHP':
             $lexer = new \FSHL\Lexer\Php();
             break;
         case 'PYTHON':
             $lexer = new \FSHL\Lexer\Python();
             break;
         case 'SQL':
             $lexer = new \FSHL\Lexer\Sql();
             break;
         case 'TEX':
             $lexer = new \App\Texy\Tex();
             break;
         case 'TEXY':
             $lexer = new \FSHL\Lexer\Texy();
             break;
         default:
             $lexer = new \FSHL\Lexer\Minimal();
     }
     $content = $highlighter->highlight($content, $lexer);
     $content = $texy->protect($content, \Texy\Texy::CONTENT_BLOCK);
     $elPre = \Texy\HtmlElement::el('pre');
     if ($modifier) {
         $modifier->decorate($texy, $elPre);
     }
     $elPre->attrs['class'] = strtolower($lang);
     $elPre->create('code', $content);
     return $elPre;
 }