Skip to content

Commit

Permalink
Add raw, left as-is, block support
Browse files Browse the repository at this point in the history
Introduces Parser::setRawBlocks() and Parser::isRawBlocksEnabled(), that
control raw block mode. When enabled, blocks that start with HTML tags
are left as-is.
  • Loading branch information
gocom committed Nov 15, 2018
1 parent e6f7e03 commit 3503228
Show file tree
Hide file tree
Showing 3 changed files with 160 additions and 1 deletion.
1 change: 1 addition & 0 deletions CHANGELOG.textile
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ Here's a summary of changes in each release. The list doesn't include some small
h2. Version 3.7.0 - upcoming

* Add @Parser::setImagePrefix()@, @Parser::setLinkPrefix()@, @Parser::getImagePrefix()@ and @Parser::getLinkPrefix()@ (closes "#169":https://github.com/textile/php-textile/issues/169).
* Add @Parser::setRawBlocks()@ and @Parser::isRawBlocksEnabled()@.
* Deprecate @Parser::setRelativeImagePrefix()@ and @Parser::$relativeImagePrefix@ in favour of the new decoupled methods.

h2. "Version 3.6.1 - 2018/10/21":https://github.com/textile/php-textile/releases/tag/v3.6.1
Expand Down
94 changes: 93 additions & 1 deletion src/Netcarver/Textile/Parser.php
Original file line number Diff line number Diff line change
Expand Up @@ -462,6 +462,24 @@ class Parser

protected $blocktag_whitelist = array();

/**
* Whether raw blocks are enabled.
*
* @var bool
* @since 3.7.0
*/

protected $rawBlocksEnabled = false;

/**
* An array of patterns used for matching raw blocks.
*
* @var array
* @since 3.7.0
*/

protected $rawBlocks = array();

/**
* Whether block tags are enabled.
*
Expand Down Expand Up @@ -1298,6 +1316,55 @@ public function isRestrictedModeEnabled()
return (bool) $this->restricted;
}

/**
* Enables and disables raw blocks.
*
* When raw blocks are enabled, any paragraphs starting with a HTML tag, or
* as filtered by Parser::isRawBlock(), are left as is. What blocks are
* considered raw, can be changed by extending Parser::isRawBlock().
*
* bc. $parser = new \Netcarver\Textile\Parser();
* echo $parser
* ->setRawBlocks(true)
* ->parse('<div>A *raw* block.</div>');
*
* The above generates:
*
* bc. <div>A *raw* block.</div>
*
* @param bool $enabled TRUE to enable, FALSE to disable
* @return Parser
* @since 3.7.0
* @see Parser::isRawBlocksEnabled()
* @see Parser::isRawBlock()
* @api
*/

public function setRawBlocks($enabled)
{
$this->rawBlocksEnabled = (bool) $enabled;
return $this;
}

/**
* Whether raw blocks are enabled.
*
* bc. $parser = new \Netcarver\Textile\Parser();
* if ($parser->isRawBlocksEnabled() === true) {
* echo 'Raw blocks are enabled';
* }
*
* @return bool TRUE if enabled, FALSE otherwise
* @since 3.7.0
* @see Parser::setRawBlocks()
* @api
*/

public function isRawBlocksEnabled()
{
return (bool) $this->rawBlocksEnabled;
}

/**
* Enables and disables block-level tags and formatting features.
*
Expand Down Expand Up @@ -1675,6 +1742,9 @@ public function parse($text)
if ($this->isRestrictedModeEnabled()) {
// Escape any raw HTML.
$text = $this->encodeHTML($text, 0);
$this->rawBlocks = array('&lt;\w');
} else {
$this->rawBlocks = array('\<\w');
}

$text = $this->cleanWhiteSpace($text);
Expand Down Expand Up @@ -2902,7 +2972,9 @@ protected function blocks($text)
$block .= $c1;
}
} else {
if ($ext || strpos($block, ' ') !== 0) {
$rawBlock = $this->isRawBlocksEnabled() && $this->isRawBlock($block);

if ($ext || (strpos($block, ' ') !== 0 && !$rawBlock)) {
list($o1, $o2, $content, $c2, $c1, $eat) = $this->fBlock(array(
0,
$tag,
Expand All @@ -2918,6 +2990,10 @@ protected function blocks($text)
} else {
$block = $o2.$content.$c2;
}
} elseif ($rawBlock && $this->isRestrictedModeEnabled()) {
$block = $this->shelve($this->rEncodeHTML($block));
} elseif ($rawBlock) {
$block = $this->shelve($block);
} else {
$block = $this->graf($block);
}
Expand Down Expand Up @@ -3050,6 +3126,22 @@ protected function fBlock($m)
return array($o1, $o2, $content, $c2, $c1, $eat);
}

/**
* Whether the block is a raw document node.
*
* Raw blocks will be shelved and left as is.
*
* @param string $text Block to check
* @return bool TRUE if the block is raw, FALSE otherwise
* @see Parser::$rawBlocks
* @since 3.7.0
*/

protected function isRawBlock($text)
{
return !(!preg_match('/^(?:'.join('|', $this->rawBlocks).')/', $text));
}

/**
* Formats a footnote.
*
Expand Down
66 changes: 66 additions & 0 deletions test/fixtures/rawblocks.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
Paragraphs wrapped in HTML are skipped when raw blocks are enabled:
setup:
- setRawBlocks: true
input: |
<p>Paragraph *with* _some_ Textile-like syntax.</p>
<div>
<p>Multiple -- *multiple* -- lines.</p>
<p>...are supported by @Parser@</p>
</div>
But _normal_ paragraphs are still Textiled
*normally*.
&lt;p&gt;Escaped *tags* are not matched.&lt;p&gt;
<p>Paragraphs starting with a space *are* parsed...</p>
...and non-wrapped paragraphs work the *same* too.
bc.. Extended blocks...
<div>...and *code* are kept intact.</div>
expect: |
<p>Paragraph *with* _some_ Textile-like syntax.</p>
<div>
<p>Multiple -- *multiple* -- lines.</p>
<p>...are supported by @Parser@</p>
</div>
<p>But <em>normal</em> paragraphs are still Textiled<br />
<strong>normally</strong>.</p>
<p>&lt;p&gt;Escaped <strong>tags</strong> are not matched.&lt;p&gt;</p>
<p>Paragraphs starting with a space <strong>are</strong> parsed&#8230;</p>
&#8230;and non-wrapped paragraphs work the <strong>same</strong> too.
<pre><code>Extended blocks...
&lt;div&gt;...and *code* are kept intact.&lt;/div&gt;</code></pre>
Raw blocks are still escaped in restricted mode, but Textile is not parsed:
setup:
- setRawBlocks: true
- setRestricted: true
input: |
<p>Paragraph *with* _some_ Textile-like syntax<br />
is kept as is, but "escaped".</p>
&lt;p&gt;Escaped *tags* are not matched.&lt;p&gt;
<div>Wrapped *inlines* are parsed...</div>
...and inline *too*.
expect: |
&lt;p&gt;Paragraph *with* _some_ Textile-like syntax&lt;br /&gt;
is kept as is, but &quot;escaped&quot;.&lt;/p&gt;
<p>&amp;lt;p&amp;gt;Escaped <strong>tags</strong> are not matched.&amp;lt;p&amp;gt;</p>
&lt;div&gt;Wrapped <strong>inlines</strong> are parsed&#8230;&lt;/div&gt;
&#8230;and inline <strong>too</strong>.

0 comments on commit 3503228

Please sign in to comment.