Modifiers are texts like .(title)[class1 class2 #id]{color: red}>^ . starts with dot (...) title or alt modifier [...] classes or ID modifier {...} inner style modifier < > <> = horizontal align modifier ^ - _ vertical align modifier
Inheritance: use trait Strict
Exemplo n.º 1
0
 /**
  * Finish invocation.
  * @return Texy\HtmlElement|FALSE
  */
 public function solve(Texy\HandlerInvocation $invocation, Texy\Image $image, Texy\Link $link = NULL, $content, Texy\Modifier $mod)
 {
     $texy = $this->texy;
     $hAlign = $image->modifier->hAlign;
     $image->modifier->hAlign = NULL;
     $elImg = $texy->imageModule->solve(NULL, $image, $link);
     // returns Texy\HtmlElement or false!
     if (!$elImg) {
         return FALSE;
     }
     $el = new Texy\HtmlElement('div');
     if (!empty($image->width) && $this->widthDelta !== FALSE) {
         $el->attrs['style']['width'] = $image->width + $this->widthDelta . 'px';
     }
     $mod->decorate($texy, $el);
     $el[0] = $elImg;
     $el[1] = new Texy\HtmlElement('p');
     $el[1]->parseLine($texy, ltrim($content));
     $class = $this->class;
     if ($hAlign) {
         $var = $hAlign . 'Class';
         // leftClass, rightClass
         if (!empty($this->{$var})) {
             $class = $this->{$var};
         } elseif (empty($texy->alignClasses[$hAlign])) {
             $el->attrs['style']['float'] = $hAlign;
         } else {
             $class .= '-' . $texy->alignClasses[$hAlign];
         }
     }
     $el->attrs['class'][] = $class;
     return $el;
 }
Exemplo n.º 2
0
 /**
  * Finish invocation.
  * @return Texy\HtmlElement
  */
 public function solve(Texy\HandlerInvocation $invocation, $type, Texy\Modifier $modifier)
 {
     $el = new Texy\HtmlElement('hr');
     $modifier->decorate($invocation->getTexy(), $el);
     $class = $this->classes[$type[0]];
     if ($class && !isset($modifier->classes[$class])) {
         $el->attrs['class'][] = $class;
     }
     return $el;
 }
Exemplo n.º 3
0
 /**
  * Callback for:.
  *
  * > They went in single file, running like hounds on a strong scent,
  * and an eager light was in their eyes. Nearly due west the broad
  * swath of the marching Orcs tramped its ugly slot; the sweet grass
  * of Rohan had been bruised and blackened as they passed.
  * >:http://www.mycom.com/tolkien/twotowers.html
  *
  * @return Texy\HtmlElement|string|FALSE
  */
 public function pattern(Texy\BlockParser $parser, array $matches)
 {
     list(, $mMod, $mPrefix, $mContent) = $matches;
     // [1] => .(title)[class]{style}<>
     // [2] => spaces |
     // [3] => ... / LINK
     $texy = $this->texy;
     $el = new Texy\HtmlElement('blockquote');
     $mod = new Texy\Modifier($mMod);
     $mod->decorate($texy, $el);
     $content = '';
     $spaces = '';
     do {
         if ($mPrefix === ':') {
             $mod->cite = $texy->blockQuoteModule->citeLink($mContent);
             $content .= "\n";
         } else {
             if ($spaces === '') {
                 $spaces = max(1, strlen($mPrefix));
             }
             $content .= $mContent . "\n";
         }
         if (!$parser->next("#^>(?:|(\\ {1,{$spaces}}|:)(.*))()\$#mA", $matches)) {
             break;
         }
         /*
         			if ($mPrefix === '>') {
         				$content .= $mPrefix . $mContent . "\n";
         			} elseif ($mPrefix === ':') {
         				$mod->cite = $texy->blockQuoteModule->citeLink($mContent);
         				$content .= "\n";
         			} else {
         				if ($spaces === '') $spaces = max(1, strlen($mPrefix));
         				$content .= $mContent . "\n";
         			}
         			if (!$parser->next("#^\\>(?:(\\>|\\ {1,$spaces}|:)(.*))?()$#mA", $matches)) break;
         */
         list(, $mPrefix, $mContent) = $matches;
     } while (TRUE);
     $el->attrs['cite'] = $mod->cite;
     $el->parseBlock($texy, $content, $parser->isIndented());
     // no content?
     if (!$el->count()) {
         return FALSE;
     }
     // event listener
     $texy->invokeHandlers('afterBlockquote', [$parser, $el, $mod]);
     return $el;
 }
Exemplo n.º 4
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;
 }
Exemplo n.º 5
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;
 }
Exemplo n.º 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;
 }
Exemplo n.º 7
0
 /**
  * Callback for:.
  *
  * .(title)[class]{style}>
  * |------------------
  * | xxx | xxx | xxx | .(..){..}[..]
  * |------------------
  * | aa | bb | cc |
  *
  * @return HtmlElement|string|FALSE
  */
 public function patternTable(Texy\BlockParser $parser, array $matches)
 {
     if ($this->disableTables) {
         return FALSE;
     }
     list(, $mMod) = $matches;
     // [1] => .(title)[class]{style}<>_
     $texy = $this->texy;
     $el = new HtmlElement('table');
     $mod = new Modifier($mMod);
     $mod->decorate($texy, $el);
     $parser->moveBackward();
     if ($parser->next('#^\\|(\\#|\\=){2,}(?![|\\#=+])(.+)\\1*\\|? *' . Patterns::MODIFIER_H . '?()$#Um', $matches)) {
         list(, , $mContent, $mMod) = $matches;
         // [1] => # / =
         // [2] => ....
         // [3] => .(title)[class]{style}<>
         $caption = $el->create('caption');
         $mod = new Modifier($mMod);
         $mod->decorate($texy, $caption);
         $caption->parseLine($texy, $mContent);
     }
     $isHead = FALSE;
     $colModifier = [];
     $prevRow = [];
     // rowSpan building helper
     $rowCounter = 0;
     $colCounter = 0;
     $elPart = NULL;
     $lineMode = FALSE;
     // rows must be separated by lines
     while (TRUE) {
         if ($parser->next('#^\\|([=-])[+|=-]{2,}$#Um', $matches)) {
             // line
             if ($lineMode) {
                 if ($matches[1] === '=') {
                     $isHead = !$isHead;
                 }
             } else {
                 $isHead = !$isHead;
                 $lineMode = $matches[1] === '=';
             }
             $prevRow = [];
             continue;
         }
         if ($parser->next('#^\\|(.*)(?:|\\|\\ *' . Patterns::MODIFIER_HV . '?)()$#U', $matches)) {
             // smarter head detection
             if ($rowCounter === 0 && !$isHead && $parser->next('#^\\|[=-][+|=-]{2,}$#Um', $foo)) {
                 $isHead = TRUE;
                 $parser->moveBackward();
             }
             if ($elPart === NULL) {
                 $elPart = $el->create($isHead ? 'thead' : 'tbody');
             } elseif (!$isHead && $elPart->getName() === 'thead') {
                 $this->finishPart($elPart);
                 $elPart = $el->create('tbody');
             }
             // PARSE ROW
             list(, $mContent, $mMod) = $matches;
             // [1] => ....
             // [2] => .(title)[class]{style}<>_
             $elRow = new HtmlElement('tr');
             $mod = new Modifier($mMod);
             $mod->decorate($texy, $elRow);
             $rowClass = $rowCounter % 2 === 0 ? $this->oddClass : $this->evenClass;
             if ($rowClass && !isset($mod->classes[$this->oddClass]) && !isset($mod->classes[$this->evenClass])) {
                 $elRow->attrs['class'][] = $rowClass;
             }
             $col = 0;
             $elCell = NULL;
             // special escape sequence \|
             $mContent = str_replace('\\|', "", $mContent);
             $mContent = Regexp::replace($mContent, '#(\\[[^\\]]*)\\|#', "\$1");
             // HACK: support for [..|..]
             foreach (explode('|', $mContent) as $cell) {
                 $cell = strtr($cell, "", '|');
                 // rowSpan
                 if (isset($prevRow[$col]) && ($lineMode || ($matches = Regexp::match($cell, '#\\^\\ *$|\\*??(.*)\\ +\\^$#AU')))) {
                     $prevRow[$col]->rowSpan++;
                     if (!$lineMode) {
                         $cell = isset($matches[1]) ? $matches[1] : '';
                     }
                     $prevRow[$col]->text .= "\n" . $cell;
                     $col += $prevRow[$col]->colSpan;
                     $elCell = NULL;
                     continue;
                 }
                 // colSpan
                 if ($cell === '' && $elCell) {
                     $elCell->colSpan++;
                     unset($prevRow[$col]);
                     $col++;
                     continue;
                 }
                 // common cell
                 $matches = Regexp::match($cell, '#(\\*??)\\ *' . Patterns::MODIFIER_HV . '??(.*)' . Patterns::MODIFIER_HV . '?\\ *()$#AU');
                 if (!$matches) {
                     continue;
                 }
                 list(, $mHead, $mModCol, $mContent, $mMod) = $matches;
                 // [1] => * ^
                 // [2] => .(title)[class]{style}<>_
                 // [3] => ....
                 // [4] => .(title)[class]{style}<>_
                 if ($mModCol) {
                     $colModifier[$col] = new Modifier($mModCol);
                 }
                 if (isset($colModifier[$col])) {
                     $mod = clone $colModifier[$col];
                 } else {
                     $mod = new Modifier();
                 }
                 $mod->setProperties($mMod);
                 $elCell = new TableCellElement();
                 $elCell->setName($isHead || $mHead === '*' ? 'th' : 'td');
                 $mod->decorate($texy, $elCell);
                 $elCell->text = $mContent;
                 $elRow->add($elCell);
                 $prevRow[$col] = $elCell;
                 $col++;
             }
             // even up with empty cells
             while ($col < $colCounter) {
                 if (isset($prevRow[$col]) && $lineMode) {
                     $prevRow[$col]->rowSpan++;
                     $prevRow[$col]->text .= "\n";
                 } else {
                     $elCell = new TableCellElement();
                     $elCell->setName($isHead ? 'th' : 'td');
                     if (isset($colModifier[$col])) {
                         $colModifier[$col]->decorate($texy, $elCell);
                     }
                     $elRow->add($elCell);
                     $prevRow[$col] = $elCell;
                 }
                 $col++;
             }
             $colCounter = $col;
             if ($elRow->count()) {
                 $elPart->add($elRow);
                 $rowCounter++;
             } else {
                 // redundant row
                 foreach ($prevRow as $elCell) {
                     $elCell->rowSpan--;
                 }
             }
             continue;
         }
         break;
     }
     if ($elPart === NULL) {
         // invalid table
         return FALSE;
     }
     if ($elPart->getName() === 'thead') {
         // thead is optional, tbody is required
         $elPart->setName('tbody');
     }
     $this->finishPart($elPart);
     // event listener
     $texy->invokeHandlers('afterTable', [$parser, $el, $mod]);
     return $el;
 }
Exemplo n.º 8
0
 /**
  * Finish invocation.
  * @return Texy\HtmlElement
  */
 public function solve(Texy\HandlerInvocation $invocation, $level, $content, Modifier $mod, $isSurrounded)
 {
     // as fixed balancing, for block/texysource & correct decorating
     $el = new Texy\HtmlElement('h' . min(6, max(1, $level + $this->top)));
     $mod->decorate($this->texy, $el);
     $el->parseLine($this->texy, trim($content));
     $this->TOC[] = ['el' => $el, 'level' => $level, 'type' => $isSurrounded ? 'surrounded' : 'underlined'];
     return $el;
 }
Exemplo n.º 9
0
 /**
  * Callback for single list item.
  * @return HtmlElement|FALSE
  */
 public function patternItem(BlockParser $parser, $bullet, $indented, $tag)
 {
     $spacesBase = $indented ? '\\ {1,}' : '';
     $patternItem = "#^\n?({$spacesBase}){$bullet}\\ *(\\S.*)?" . Patterns::MODIFIER_H . '?()$#mAUu';
     // first line with bullet
     $matches = NULL;
     if (!$parser->next($patternItem, $matches)) {
         return FALSE;
     }
     list(, $mIndent, $mContent, $mMod) = $matches;
     // [1] => indent
     // [2] => ...
     // [3] => .(title)[class]{style}<>
     $elItem = new HtmlElement($tag);
     $mod = new Modifier($mMod);
     $mod->decorate($this->texy, $elItem);
     // next lines
     $spaces = '';
     $content = ' ' . $mContent;
     // trick
     while ($parser->next('#^(\\n*)' . $mIndent . '(\\ {1,' . $spaces . '})(.*)()$#Am', $matches)) {
         list(, $mBlank, $mSpaces, $mContent) = $matches;
         // [1] => blank line?
         // [2] => spaces
         // [3] => ...
         if ($spaces === '') {
             $spaces = strlen($mSpaces);
         }
         $content .= "\n" . $mBlank . $mContent;
     }
     // parse content
     $elItem->parseBlock($this->texy, $content, TRUE);
     if (isset($elItem[0]) && $elItem[0] instanceof HtmlElement) {
         $elItem[0]->setName(NULL);
     }
     return $elItem;
 }