API: Pass extra context information to shortcode handlers.

This allows shortcodes to perform more complex actions on the element
which contains them. For example, the element reference can be used
to add extra classes or attributes to links which provide additional
metadata.
This commit is contained in:
Andrew Short 2013-10-09 15:02:36 +11:00
parent f0ccdeb9fc
commit a339687493
3 changed files with 24 additions and 9 deletions

View File

@ -64,7 +64,10 @@ These parameters are passed to the callback:
will not have been parsed, and can optionally be fed back into the parser.
- The ShortcodeParser instance used to parse the content.
- The shortcode tag name that was matched within the parsed content.
- An associative array of extra information about the shortcode being parsed. For example, if the shortcode is
is inside an attribute, the `element` key contains a reference to the parent `DOMElement`, and the `node`
key the attribute's `DOMNode`.
## Example: Google Maps Iframe by Address
To demonstrate how easy it is to build custom shortcodes, we'll build one to display

View File

@ -68,6 +68,7 @@ class ShortcodeParser {
* this will not have been parsed, and can optionally be fed back into the parser.
* - The {@link ShortcodeParser} instance used to parse the content.
* - The shortcode tag name that was matched within the parsed content.
* - An associative array of extra information about the shortcode being parsed.
*
* @param string $shortcode The shortcode tag to map to the callback - normally in lowercase_underscore format.
* @param callback $callback The callback to replace the shortcode with.
@ -102,9 +103,9 @@ class ShortcodeParser {
$this->shortcodes = array();
}
public function callShortcode($tag, $attributes, $content) {
public function callShortcode($tag, $attributes, $content, $extra = array()) {
if (!isset($this->shortcodes[$tag])) return false;
return call_user_func($this->shortcodes[$tag], $attributes, $content, $this, $tag);
return call_user_func($this->shortcodes[$tag], $attributes, $content, $this, $tag, $extra);
}
// --------------------------------------------------------------------------------------------------------------
@ -332,11 +333,12 @@ class ShortcodeParser {
for($i = 0; $i < $attributes->length; $i++) {
$node = $attributes->item($i);
$tags = $this->extractTags($node->nodeValue);
$extra = array('node' => $node, 'element' => $node->ownerElement);
if($tags) {
$node->nodeValue = $this->replaceTagsWithText($node->nodeValue, $tags,
function($idx, $tag) use ($parser){
$content = $parser->callShortcode($tag['open'], $tag['attrs'], $tag['content']);
function($idx, $tag) use ($parser, $extra){
$content = $parser->callShortcode($tag['open'], $tag['attrs'], $tag['content'], $extra);
if ($content === false) {
if(ShortcodeParser::$error_behavior == ShortcodeParser::ERROR) {

View File

@ -6,6 +6,7 @@
class ShortcodeParserTest extends SapphireTest {
protected $arguments, $contents, $tagName, $parser;
protected $extra = array();
public function setUp() {
ShortcodeParser::get('test')->register('test_shortcode', array($this, 'shortcodeSaver'));
@ -210,16 +211,25 @@ class ShortcodeParserTest extends SapphireTest {
);
}
public function testExtraContext() {
$this->parser->parse('<a href="[test_shortcode]">Test</a>');
$this->assertInstanceOf('DOMNode', $this->extra['node']);
$this->assertInstanceOf('DOMElement', $this->extra['element']);
$this->assertEquals($this->extra['element']->tagName, 'a');
}
// -----------------------------------------------------------------------------------------------------------------
/**
* Stores the result of a shortcode parse in object properties for easy testing access.
*/
public function shortcodeSaver($arguments, $content = null, $parser, $tagName = null) {
public function shortcodeSaver($arguments, $content, $parser, $tagName, $extra) {
$this->arguments = $arguments;
$this->contents = $content;
$this->tagName = $tagName;
$this->contents = $content;
$this->tagName = $tagName;
$this->extra = $extra;
return $content;
}