Merge pull request #1213 from silverstripe-rebelalliance/feature/shortcodes

FIX issues with new shortcode parser
This commit is contained in:
Sean Harvey 2013-02-19 14:12:28 -08:00
commit 8a70019e78
2 changed files with 55 additions and 15 deletions

View File

@ -456,6 +456,50 @@ class ShortcodeParser {
$this->removeNode($node);
}
protected function loadHTML($html) {
require_once(THIRDPARTY_PATH.'/html5lib/HTML5/Parser.php');
// Convert any errors to exceptions
set_error_handler(
function($no, $str){
throw new Exception("HTML Parse Error: ".$str);
},
error_reporting()
);
// Use HTML5lib to parse the HTML fragment
try {
$bases = HTML5_Parser::parseFragment(trim($html), 'div');
}
catch (Exception $e) {
$bases = null;
}
// Disable our error handler (restoring to previous value)
restore_error_handler();
return $bases;
}
protected function saveHTML($doc) {
if (version_compare(PHP_VERSION, '5.3.6', '>=')){
$res = '';
foreach($doc->firstChild->childNodes as $child) $res .= $doc->saveHTML($child);
}
else {
$res = preg_replace(
array(
'/^(.*?)<html>/is',
'/<\/html>(.*?)$/is',
),
'',
$doc->saveHTML()
);
}
return $res;
}
/**
* Parse a string, and replace any registered shortcodes within it with the result of the mapped callback.
*
@ -474,8 +518,7 @@ class ShortcodeParser {
list($content, $tags) = $this->replaceElementTagsWithMarkers($content);
// Now parse the result into a DOM
require_once(THIRDPARTY_PATH.'/html5lib/HTML5/Parser.php');
$bases = HTML5_Parser::parseFragment(trim($content), 'div');
$bases = $this->loadHTML($content);
// If we couldn't parse the HTML, error out
if (!$bases || !$bases->length) {
@ -487,9 +530,7 @@ class ShortcodeParser {
}
}
$res = '';
$html = $bases->item(0)->parentNode;
$doc = $html->ownerDocument;
$doc = $bases->item(0)->ownerDocument;
$xp = new DOMXPath($doc);
@ -526,9 +567,7 @@ class ShortcodeParser {
$this->replaceMarkerWithContent($shortcode, $tag);
}
foreach($html->childNodes as $child) $res .= $doc->saveHTML($child);
return $res;
return $this->saveHTML($doc);
}

View File

@ -36,6 +36,7 @@ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
class HTML5_TreeBuilder {
public $stack = array();
public $context;
public $content_model;
private $mode;
@ -3392,7 +3393,7 @@ class HTML5_TreeBuilder {
}
}
private function resetInsertionMode($context = null) {
private function resetInsertionMode() {
/* 1. Let last be false. */
$last = false;
$leng = count($this->stack);
@ -3406,7 +3407,7 @@ class HTML5_TreeBuilder {
* case) */
if($this->stack[0]->isSameNode($node)) {
$last = true;
$node = $context;
$node = $this->context;
}
/* 4. If node is a select element, then switch the insertion mode to
@ -3642,10 +3643,10 @@ class HTML5_TreeBuilder {
public function setupContext($context = null) {
$this->fragment = true;
if ($context) {
$context = $this->dom->createElementNS(self::NS_HTML, $context);
$this->context = $this->dom->createElementNS(self::NS_HTML, $context);
/* 4.1. Set the HTML parser's tokenization stage's content model
* flag according to the context element, as follows: */
switch ($context->tagName) {
switch ($this->context->tagName) {
case 'title': case 'textarea':
$this->content_model = HTML5_Tokenizer::RCDATA;
break;
@ -3670,12 +3671,12 @@ class HTML5_TreeBuilder {
* contains just the single element root. */
$this->stack = array($root);
/* 4.5 Reset the parser's insertion mode appropriately. */
$this->resetInsertionMode($context);
$this->resetInsertionMode();
/* 4.6 Set the parser's form element pointer to the nearest node
* to the context element that is a form element (going straight up
* the ancestor chain, and including the element itself, if it is a
* form element), or, if there is no such form element, to null. */
$node = $context;
$node = $this->context;
do {
if ($node->tagName === 'form') {
$this->form_pointer = $node;