mirror of
https://github.com/silverstripe/silverstripe-framework
synced 2024-09-28 20:29:15 +02:00
Merge pull request #6302 from jonom/shortcode-parse-extension-points
API Added extension points to ShortcodeParser
This commit is contained in:
commit
cfbfe1427c
@ -21,6 +21,13 @@ class ShortcodeParser extends Object {
|
|||||||
|
|
||||||
// --------------------------------------------------------------------------------------------------------------
|
// --------------------------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Registered shortcodes. Items follow this structure:
|
||||||
|
* [shortcode_name] => Array(
|
||||||
|
* [0] => class_containing_handler
|
||||||
|
* [1] => name_of_shortcode_handler_method
|
||||||
|
* )
|
||||||
|
*/
|
||||||
protected $shortcodes = array();
|
protected $shortcodes = array();
|
||||||
|
|
||||||
// --------------------------------------------------------------------------------------------------------------
|
// --------------------------------------------------------------------------------------------------------------
|
||||||
@ -96,6 +103,15 @@ class ShortcodeParser extends Object {
|
|||||||
if($this->registered($shortcode)) unset($this->shortcodes[$shortcode]);
|
if($this->registered($shortcode)) unset($this->shortcodes[$shortcode]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get an array containing information about registered shortcodes
|
||||||
|
*
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
public function getRegisteredShortcodes() {
|
||||||
|
return $this->shortcodes;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Remove all registered shortcodes.
|
* Remove all registered shortcodes.
|
||||||
*/
|
*/
|
||||||
@ -540,79 +556,90 @@ class ShortcodeParser extends Object {
|
|||||||
* @return string
|
* @return string
|
||||||
*/
|
*/
|
||||||
public function parse($content) {
|
public function parse($content) {
|
||||||
|
|
||||||
|
$this->extend('onBeforeParse', $content);
|
||||||
|
|
||||||
|
$continue = true;
|
||||||
|
|
||||||
// If no shortcodes defined, don't try and parse any
|
// If no shortcodes defined, don't try and parse any
|
||||||
if(!$this->shortcodes) return $content;
|
if(!$this->shortcodes) $continue = false;
|
||||||
|
|
||||||
// If no content, don't try and parse it
|
// If no content, don't try and parse it
|
||||||
if (!trim($content)) return $content;
|
else if (!trim($content)) $continue = false;
|
||||||
|
|
||||||
// If no shortcode tag, don't try and parse it
|
// If no shortcode tag, don't try and parse it
|
||||||
if (strpos($content, '[') === false) return $content;
|
else if (strpos($content, '[') === false) $continue = false;
|
||||||
|
|
||||||
// First we operate in text mode, replacing any shortcodes with marker elements so that later we can
|
if ($continue) {
|
||||||
// use a proper DOM
|
// First we operate in text mode, replacing any shortcodes with marker elements so that later we can
|
||||||
list($content, $tags) = $this->replaceElementTagsWithMarkers($content);
|
// use a proper DOM
|
||||||
|
list($content, $tags) = $this->replaceElementTagsWithMarkers($content);
|
||||||
|
|
||||||
$htmlvalue = Injector::inst()->create('HTMLValue', $content);
|
$htmlvalue = Injector::inst()->create('HTMLValue', $content);
|
||||||
|
|
||||||
// Now parse the result into a DOM
|
// Now parse the result into a DOM
|
||||||
if (!$htmlvalue->isValid()){
|
if (!$htmlvalue->isValid()){
|
||||||
if(self::$error_behavior == self::ERROR) {
|
if(self::$error_behavior == self::ERROR) {
|
||||||
user_error('Couldn\'t decode HTML when processing short codes', E_USER_ERRROR);
|
user_error('Couldn\'t decode HTML when processing short codes', E_USER_ERRROR);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
return $content;
|
$continue = false;
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// First, replace any shortcodes that are in attributes
|
|
||||||
$this->replaceAttributeTagsWithContent($htmlvalue);
|
|
||||||
|
|
||||||
// Find all the element scoped shortcode markers
|
|
||||||
$shortcodes = $htmlvalue->query('//img[@class="'.self::$marker_class.'"]');
|
|
||||||
|
|
||||||
// Find the parents. Do this before DOM modification, since SPLIT might cause parents to move otherwise
|
|
||||||
$parents = $this->findParentsForMarkers($shortcodes);
|
|
||||||
|
|
||||||
foreach($shortcodes as $shortcode) {
|
|
||||||
$tag = $tags[$shortcode->getAttribute('data-tagid')];
|
|
||||||
$parent = $parents[$shortcode->getAttribute('data-parentid')];
|
|
||||||
|
|
||||||
$class = null;
|
|
||||||
if(!empty($tag['attrs']['location'])) $class = $tag['attrs']['location'];
|
|
||||||
else if(!empty($tag['attrs']['class'])) $class = $tag['attrs']['class'];
|
|
||||||
|
|
||||||
$location = self::INLINE;
|
|
||||||
if($class == 'left' || $class == 'right') $location = self::BEFORE;
|
|
||||||
if($class == 'center' || $class == 'leftALone') $location = self::SPLIT;
|
|
||||||
|
|
||||||
if(!$parent) {
|
|
||||||
if($location !== self::INLINE) {
|
|
||||||
user_error("Parent block for shortcode couldn't be found, but location wasn't INLINE",
|
|
||||||
E_USER_ERROR);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else {
|
|
||||||
$this->moveMarkerToCompliantHome($shortcode, $parent, $location);
|
|
||||||
}
|
|
||||||
|
|
||||||
$this->replaceMarkerWithContent($shortcode, $tag);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
$content = $htmlvalue->getContent();
|
if ($continue) {
|
||||||
|
// First, replace any shortcodes that are in attributes
|
||||||
|
$this->replaceAttributeTagsWithContent($htmlvalue);
|
||||||
|
|
||||||
// Clean up any marker classes left over, for example, those injected into <script> tags
|
// Find all the element scoped shortcode markers
|
||||||
$parser = $this;
|
$shortcodes = $htmlvalue->query('//img[@class="'.self::$marker_class.'"]');
|
||||||
$content = preg_replace_callback(
|
|
||||||
// Not a general-case parser; assumes that the HTML generated in replaceElementTagsWithMarkers()
|
// Find the parents. Do this before DOM modification, since SPLIT might cause parents to move otherwise
|
||||||
// hasn't been heavily modified
|
$parents = $this->findParentsForMarkers($shortcodes);
|
||||||
'/<img[^>]+class="'.preg_quote(self::$marker_class).'"[^>]+data-tagid="([^"]+)"[^>]+>/i',
|
|
||||||
function ($matches) use ($tags, $parser) {
|
foreach($shortcodes as $shortcode) {
|
||||||
$tag = $tags[$matches[1]];
|
$tag = $tags[$shortcode->getAttribute('data-tagid')];
|
||||||
return $parser->getShortcodeReplacementText($tag);
|
$parent = $parents[$shortcode->getAttribute('data-parentid')];
|
||||||
},
|
|
||||||
$content
|
$class = null;
|
||||||
);
|
if(!empty($tag['attrs']['location'])) $class = $tag['attrs']['location'];
|
||||||
|
else if(!empty($tag['attrs']['class'])) $class = $tag['attrs']['class'];
|
||||||
|
|
||||||
|
$location = self::INLINE;
|
||||||
|
if($class == 'left' || $class == 'right') $location = self::BEFORE;
|
||||||
|
if($class == 'center' || $class == 'leftALone') $location = self::SPLIT;
|
||||||
|
|
||||||
|
if(!$parent) {
|
||||||
|
if($location !== self::INLINE) {
|
||||||
|
user_error("Parent block for shortcode couldn't be found, but location wasn't INLINE",
|
||||||
|
E_USER_ERROR);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
$this->moveMarkerToCompliantHome($shortcode, $parent, $location);
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->replaceMarkerWithContent($shortcode, $tag);
|
||||||
|
}
|
||||||
|
|
||||||
|
$content = $htmlvalue->getContent();
|
||||||
|
|
||||||
|
// Clean up any marker classes left over, for example, those injected into <script> tags
|
||||||
|
$parser = $this;
|
||||||
|
$content = preg_replace_callback(
|
||||||
|
// Not a general-case parser; assumes that the HTML generated in replaceElementTagsWithMarkers()
|
||||||
|
// hasn't been heavily modified
|
||||||
|
'/<img[^>]+class="'.preg_quote(self::$marker_class).'"[^>]+data-tagid="([^"]+)"[^>]+>/i',
|
||||||
|
function ($matches) use ($tags, $parser) {
|
||||||
|
$tag = $tags[$matches[1]];
|
||||||
|
return $parser->getShortcodeReplacementText($tag);
|
||||||
|
},
|
||||||
|
$content
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->extend('onAfterParse', $content);
|
||||||
|
|
||||||
return $content;
|
return $content;
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user