Merge branch 'dev' into feature/higher-order-sections
This commit is contained in:
+100
-35
@@ -14,9 +14,6 @@
|
||||
*/
|
||||
class Mustache {
|
||||
|
||||
public $_otag = '{{';
|
||||
public $_ctag = '}}';
|
||||
|
||||
/**
|
||||
* Should this Mustache throw exceptions when it finds unexpected tags?
|
||||
*
|
||||
@@ -85,6 +82,15 @@ class Mustache {
|
||||
*/
|
||||
const PRAGMA_UNESCAPED = 'UNESCAPED';
|
||||
|
||||
/**
|
||||
* Constants used for section and tag RegEx
|
||||
*/
|
||||
const SECTION_TYPES = '\^#\/';
|
||||
const TAG_TYPES = '#\^\/=!<>\\{&';
|
||||
|
||||
public $_otag = '{{';
|
||||
public $_ctag = '}}';
|
||||
|
||||
protected $_tagRegEx;
|
||||
|
||||
protected $_template = '';
|
||||
@@ -263,6 +269,23 @@ class Mustache {
|
||||
return $template;
|
||||
}
|
||||
|
||||
/**
|
||||
* Prepare a section RegEx string for the given opening/closing tags.
|
||||
*
|
||||
* @access protected
|
||||
* @param string $otag
|
||||
* @param string $ctag
|
||||
* @return string
|
||||
*/
|
||||
protected function _prepareSectionRegEx($otag, $ctag) {
|
||||
return sprintf(
|
||||
'/(?:(?<=\\n)[ \\t]*)?%s(?<type>[%s])(?<tag_name>.+?)%s\\n?/s',
|
||||
preg_quote($otag, '/'),
|
||||
self::SECTION_TYPES,
|
||||
preg_quote($ctag, '/')
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Extract a section from $template.
|
||||
*
|
||||
@@ -273,9 +296,7 @@ class Mustache {
|
||||
* @return array $section, $offset, $type, $tag_name and $content
|
||||
*/
|
||||
protected function _findSection($template) {
|
||||
$otag = preg_quote($this->_otag, '/');
|
||||
$ctag = preg_quote($this->_ctag, '/');
|
||||
$regex = '/' . $otag . '([\\^\\#\\/])\\s*(.+?)\\s*' . $ctag . '\\s*/ms';
|
||||
$regEx = $this->_prepareSectionRegEx($this->_otag, $this->_ctag);
|
||||
|
||||
$section_start = null;
|
||||
$section_type = null;
|
||||
@@ -285,12 +306,12 @@ class Mustache {
|
||||
|
||||
$section_stack = array();
|
||||
$matches = array();
|
||||
while (preg_match($regex, $template, $matches, PREG_OFFSET_CAPTURE, $search_offset)) {
|
||||
while (preg_match($regEx, $template, $matches, PREG_OFFSET_CAPTURE, $search_offset)) {
|
||||
|
||||
$match = $matches[0][0];
|
||||
$offset = $matches[0][1];
|
||||
$type = $matches[1][0];
|
||||
$tag_name = trim($matches[2][0]);
|
||||
$type = $matches['type'][0];
|
||||
$tag_name = trim($matches['tag_name'][0]);
|
||||
|
||||
$search_offset = $offset + strlen($match);
|
||||
|
||||
@@ -328,6 +349,22 @@ class Mustache {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Prepare a pragma RegEx for the given opening/closing tags.
|
||||
*
|
||||
* @access protected
|
||||
* @param string $otag
|
||||
* @param string $ctag
|
||||
* @return string
|
||||
*/
|
||||
protected function _preparePragmaRegEx($otag, $ctag) {
|
||||
return sprintf(
|
||||
'/%s%%\\s*(?<pragma_name>[\\w_-]+)(?<options_string>(?: [\\w]+=[\\w]+)*)\\s*%s\\n?/s',
|
||||
preg_quote($otag, '/'),
|
||||
preg_quote($ctag, '/')
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialize pragmas and remove all pragma tags.
|
||||
*
|
||||
@@ -343,10 +380,8 @@ class Mustache {
|
||||
return $template;
|
||||
}
|
||||
|
||||
$otag = preg_quote($this->_otag, '/');
|
||||
$ctag = preg_quote($this->_ctag, '/');
|
||||
$regex = '/' . $otag . '%\\s*([\\w_-]+)((?: [\\w]+=[\\w]+)*)\\s*' . $ctag . '\\n?/s';
|
||||
return preg_replace_callback($regex, array($this, '_renderPragma'), $template);
|
||||
$regEx = $this->_preparePragmaRegEx($this->_otag, $this->_ctag);
|
||||
return preg_replace_callback($regEx, array($this, '_renderPragma'), $template);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -359,8 +394,8 @@ class Mustache {
|
||||
*/
|
||||
protected function _renderPragma($matches) {
|
||||
$pragma = $matches[0];
|
||||
$pragma_name = $matches[1];
|
||||
$options_string = $matches[2];
|
||||
$pragma_name = $matches['pragma_name'];
|
||||
$options_string = $matches['options_string'];
|
||||
|
||||
if (!in_array($pragma_name, $this->_pragmasImplemented)) {
|
||||
throw new MustacheException('Unknown pragma: ' . $pragma_name, MustacheException::UNKNOWN_PRAGMA);
|
||||
@@ -369,7 +404,7 @@ class Mustache {
|
||||
$options = array();
|
||||
foreach (explode(' ', trim($options_string)) as $o) {
|
||||
if ($p = trim($o)) {
|
||||
$p = explode('=', trim($p));
|
||||
$p = explode('=', $p);
|
||||
$options[$p[0]] = $p[1];
|
||||
}
|
||||
}
|
||||
@@ -427,6 +462,23 @@ class Mustache {
|
||||
return (isset($this->_throwsExceptions[$exception]) && $this->_throwsExceptions[$exception]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Prepare a tag RegEx for the given opening/closing tags.
|
||||
*
|
||||
* @access protected
|
||||
* @param string $otag
|
||||
* @param string $ctag
|
||||
* @return string
|
||||
*/
|
||||
protected function _prepareTagRegEx($otag, $ctag) {
|
||||
return sprintf(
|
||||
'/(?<whitespace>(?<=\\n)[ \\t]*)?%s(?<type>[%s]?)(?<tag_name>.+?)(?:\\2|})?%s(?:\\s*(?=\\n))?/s',
|
||||
preg_quote($otag, '/'),
|
||||
self::TAG_TYPES,
|
||||
preg_quote($ctag, '/')
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Loop through and render individual Mustache tags.
|
||||
*
|
||||
@@ -442,22 +494,31 @@ class Mustache {
|
||||
$otag_orig = $this->_otag;
|
||||
$ctag_orig = $this->_ctag;
|
||||
|
||||
$otag = preg_quote($this->_otag, '/');
|
||||
$ctag = preg_quote($this->_ctag, '/');
|
||||
|
||||
$this->_tagRegEx = '/' . $otag . "([#\^\/=!<>\\{&])?(.+?)\\1?" . $ctag . "+/s";
|
||||
$this->_tagRegEx = $this->_prepareTagRegEx($this->_otag, $this->_ctag);
|
||||
|
||||
$html = '';
|
||||
$matches = array();
|
||||
while (preg_match($this->_tagRegEx, $template, $matches, PREG_OFFSET_CAPTURE)) {
|
||||
$tag = $matches[0][0];
|
||||
$offset = $matches[0][1];
|
||||
$modifier = $matches[1][0];
|
||||
$tag_name = trim($matches[2][0]);
|
||||
$modifier = $matches['type'][0];
|
||||
$tag_name = trim($matches['tag_name'][0]);
|
||||
|
||||
if (isset($matches['whitespace']) && $matches['whitespace'][1] > -1) {
|
||||
$whitespace = $matches['whitespace'][0];
|
||||
} else {
|
||||
$whitespace = null;
|
||||
}
|
||||
|
||||
$html .= substr($template, 0, $offset);
|
||||
$html .= $this->_renderTag($modifier, $tag_name);
|
||||
$template = substr($template, $offset + strlen($tag));
|
||||
|
||||
$next_offset = $offset + strlen($tag);
|
||||
if ((substr($html, -1) == "\n") && (substr($template, $next_offset, 1) == "\n")) {
|
||||
$next_offset++;
|
||||
}
|
||||
$template = substr($template, $next_offset);
|
||||
|
||||
$html .= $this->_renderTag($modifier, $tag_name, $whitespace);
|
||||
}
|
||||
|
||||
$this->_otag = $otag_orig;
|
||||
@@ -478,7 +539,7 @@ class Mustache {
|
||||
* @throws MustacheException Unmatched section tag encountered.
|
||||
* @return string
|
||||
*/
|
||||
protected function _renderTag($modifier, $tag_name) {
|
||||
protected function _renderTag($modifier, $tag_name, $whitespace) {
|
||||
switch ($modifier) {
|
||||
case '=':
|
||||
return $this->_changeDelimiter($tag_name);
|
||||
@@ -488,9 +549,13 @@ class Mustache {
|
||||
break;
|
||||
case '>':
|
||||
case '<':
|
||||
return $this->_renderPartial($tag_name);
|
||||
return $this->_renderPartial($tag_name, $whitespace);
|
||||
break;
|
||||
case '{':
|
||||
// strip the trailing } ...
|
||||
if ($tag_name[(strlen($tag_name) - 1)] == '}') {
|
||||
$tag_name = substr($tag_name, 0, -1);
|
||||
}
|
||||
case '&':
|
||||
if ($this->_hasPragma(self::PRAGMA_UNESCAPED)) {
|
||||
return $this->_renderEscaped($tag_name);
|
||||
@@ -553,9 +618,10 @@ class Mustache {
|
||||
* @param string $tag_name
|
||||
* @return string
|
||||
*/
|
||||
protected function _renderPartial($tag_name) {
|
||||
protected function _renderPartial($tag_name, $whitespace = '') {
|
||||
$view = clone($this);
|
||||
return $view->render($this->_getPartial($tag_name));
|
||||
|
||||
return $whitespace . preg_replace('/\n(?!$)/s', "\n" . $whitespace, $view->render($this->_getPartial($tag_name)));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -567,13 +633,12 @@ class Mustache {
|
||||
* @return string
|
||||
*/
|
||||
protected function _changeDelimiter($tag_name) {
|
||||
$tags = explode(' ', $tag_name);
|
||||
$this->_otag = $tags[0];
|
||||
$this->_ctag = $tags[1];
|
||||
list($otag, $ctag) = explode(' ', $tag_name);
|
||||
$this->_otag = $otag;
|
||||
$this->_ctag = $ctag;
|
||||
|
||||
$this->_tagRegEx = $this->_prepareTagRegEx($this->_otag, $this->_ctag);
|
||||
|
||||
$otag = preg_quote($this->_otag, '/');
|
||||
$ctag = preg_quote($this->_ctag, '/');
|
||||
$this->_tagRegEx = '/' . $otag . "([#\^\/=!<>\\{&])?(.+?)\\1?" . $ctag . "+/s";
|
||||
return '';
|
||||
}
|
||||
|
||||
@@ -625,7 +690,7 @@ class Mustache {
|
||||
* @return string
|
||||
*/
|
||||
protected function _getVariable($tag_name) {
|
||||
if ($this->_hasPragma(self::PRAGMA_DOT_NOTATION) && $tag_name != '.') {
|
||||
if ($tag_name != '.' && strpos($tag_name, '.') !== false && $this->_hasPragma(self::PRAGMA_DOT_NOTATION)) {
|
||||
$chunks = explode('.', $tag_name);
|
||||
$first = array_shift($chunks);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user