Compatible with DokuWiki
No compatibility info given!
The missing download url means that this extension cannot be installed via the Extension Manager. Please see Publishing a Plugin on dokuwiki.org. Recommended are public repository hosts like GitHub, GitLab or Bitbucket.
This extension has not been updated in over 2 years. It may no longer be maintained or supported and may have compatibility issues.
Extension name contains underscore, will not generate popularity points.
Similar to wrap
This page provides a plugin with two related components: Shorthand Span and Shorthand Div.
(Before it where two separated plugins span shorthand
and div shorthand
.)
Shorthand Span is a shorthand syntax for embedding HTML spans:
%your_class{words}% ==> <span class="your_class">words</span>
Shorthand Div is a shorthand syntax for embedding HTML divs:
#your_class[words]# ==> <div class="your_class">words</div>
It's that simple. But there are some restrictions. Please read the comments at the beginning of each plugin so I'm not maintaining them in two places.
(Thank you Christopher Smith for providing a plugin tutorial that made the idea of writing a plugin less daunting.)
To install the Shorthand plugin, with two components:
/lib/plugins/shorthand
/lib/plugins/shorthand/plugin.info.txt
/lib/plugins/shorthand/syntax/span.php
/lib/plugins/shorthand/syntax/div.php
base shorthand author Joe Lapp email date 2007-06-05 name Shorthand Span and Div desc Shorthand for <span class="your_class">...</span> and <div class="your_class">...</div> url https://www.dokuwiki.org/plugin:div_span_shorthand
<?php /** * Shorthand Span Plugin: Shorthand for <span class="your_class">...</span>. * * syntax: %your_class{...}% * * You may embed any syntax between the shorthand opening and closing tags * that you can embed in (for example) the DokuWiki **...** bold syntax, * except that you can't nest a span shorthand within a span shorthand. If * anyone knows how to allow nesting, please let me know. * * @license GPL 2 (http://www.gnu.org/licenses/gpl.html) * @author Joe Lapp <http://www.spiderjoe.com> */ if(!defined('DOKU_INC')) die(); class syntax_plugin_shorthand_span extends DokuWiki_Syntax_Plugin { function getType() { return 'formatting'; } function getAllowedTypes() { return array('substition','protected','disabled','formatting'); } function getSort() { return 500; } // I'm not sure what's appropriate // override default accepts() method to allow nesting // - ie, to get the plugin accepts its own entry syntax function accepts($mode) { if ($mode == substr(get_class($this), 7)) return true; return parent::accepts($mode); } function connectTo($mode) { $this->Lexer->addEntryPattern('\%[a-zA-Z0-9_-]+\{(?=.*\x7D\x25)', $mode, 'plugin_shorthand_span'); } function postConnect() { $this->Lexer->addExitPattern('\}\%', 'plugin_shorthand_span'); } function handle($match, $state, $pos, Doku_Handler $handler) { switch($state) { case DOKU_LEXER_ENTER: return array($state, substr($match, 1, -1)); case DOKU_LEXER_UNMATCHED: return array($state, $match); case DOKU_LEXER_EXIT: return array($state, ''); } return array(); } function render($mode, Doku_Renderer $renderer, $data) { if($mode == 'xhtml') { list($state, $match) = $data; switch($state) { case DOKU_LEXER_ENTER: //toc is lost when we use $renderer->nest so we back it up here //$this->toc = $renderer->toc; $renderer->doc .= '<span class="'.$match.'">'; break; case DOKU_LEXER_UNMATCHED: $renderer->doc .= htmlspecialchars($match); // if you want to render instructions placed inside the tag : // $renderer->doc .= $renderer->nest(p_get_instructions($match)); break; case DOKU_LEXER_EXIT: $renderer->doc .= '</span>'; //toc restore //$renderer->toc = $this->toc; break; } return true; } return false; } } ?>
<?php /** * Shorthand Div Plugin: Shorthand for <div class="your_class">...</div>. * * syntax: #your_class[...]# * * The text you include between the shorthand opening and closing tags is not * parsed in any way. It's special characters are all escaped. I'd like to * allow embedded syntax, but paragraph generation behaves too strangely to * make this useful. For example, embedding the word "ain't" would produce * three separate paragraphs for each of "ain", "'", and "t". If you know * how to fix this, please let me know. * * @license GPL 2 (http://www.gnu.org/licenses/gpl.html) * @author Joe Lapp <http://www.spiderjoe.com> */ if(!defined('DOKU_INC')) die(); class syntax_plugin_shorthand_div extends DokuWiki_Syntax_Plugin { function getType() { return 'container'; } function getAllowedTypes() { // I'd like to allow all types, but the <p> autogen behavior makes them troublesome. return array(/*'container','substition','protected','disabled','formatting'*/); } function getPType() { return 'block'; } function getSort() { return 500; } // I'm not sure what's appropriate function connectTo($mode) { $this->Lexer->addEntryPattern('\#[a-zA-Z0-9_-]+\[(?=.*\x5D\x23)', $mode, 'plugin_shorthand_div'); } // override default accepts() method to allow nesting // - ie, to get the plugin accepts its own entry syntax function accepts($mode) { if ($mode == substr(get_class($this), 7)) return true; return parent::accepts($mode); } function postConnect() { $this->Lexer->addExitPattern('\]\#', 'plugin_shorthand_div'); } // function handle($match, $state, $pos, &$handler) function handle($match, $state, $pos, Doku_Handler $handler) { switch($state) { case DOKU_LEXER_ENTER: return array($state, substr($match, 1, -1)); case DOKU_LEXER_UNMATCHED: return array($state, $match); case DOKU_LEXER_EXIT: return array($state, ''); } return array(); } // function render($mode, &$renderer, $data) function render($mode, Doku_Renderer $renderer, $data) { if($mode == 'xhtml') { list($state, $match) = $data; switch($state) { case DOKU_LEXER_ENTER: //toc is lost when we use $renderer->nest so we back it up here //$this->toc = $renderer->toc; $renderer->doc .= '<div class="'.$match.'">'; break; case DOKU_LEXER_UNMATCHED: $renderer->doc .= htmlspecialchars($match); // if you want to render instructions placed inside the tag : // $renderer->doc .= $renderer->nest(p_get_instructions($match)); break; case DOKU_LEXER_EXIT: $renderer->doc .= '</div>'; //toc restore //$renderer->toc = $this->toc; break; } return true; } return false; } } ?>
Some points:
%%{{this is to show link syntax}}%%
— is legitimate DokuWiki syntax. However, %%
, has a getSort()
of 170 so everything should be fine. You may want to test it though, just to be certain shorthand/syntax/span.php
& shorthand/syntax/div.php
and classes syntax_plugin_shorthand_div
& syntax_plugin_shorthand_span
.Oh, I didn't know I could do that. I guess that would allow other people to create shorthand/ plugins as well, as might happen. I wonder if someone trying to follow the instructions on one of these plugins might think, “Oh well, I already have a plugin in that directory” and not load the plugin.
formatting
and control the opening and closing of paragraph tags yourself. You will need something like //on enter </p> <!-- close the currently open DokuWiki paragraph tag --> <div class='yourclass'> <!-- markup required for your plugin --> <p> <!-- open a new paragraph tag for DokuWiki --> // on exit </p> <!-- matching close for the paragraph you opened (although it may not be the same paragraph anymore) --> </div> <!-- closing markup required for your plugin --> <p> <!-- open paragraph to match the close you did initially -->
— Christopher Smith 2005-08-23 09:40
I played around with it a bit. Given that I'm using PType 'block', it seems that I don't need the initial </p> or final <p>.
It might actually be useful for people to put a paragraph inside the div, but what if someone doesn't want them? I was using this plugin to display a date right under my page title header, and because I have a “div.level1 p:first-child”, I'd end up acting on the <p> in the date div – not what I wanted. (I have since come up with another way to do dates, as you'll see in my next plugin.)
I was hoping someone would show me how to include arbitrary syntax inside the div, in which case I shouldn't need to add the <p> tags via the plugin. Maybe as an interim fix I can have the plugin implement a special token, say “##”, for wrapping text in paragraphs. That way you could have multiple paragraphs inside the div. For example:
#prettybox[ ## Paragraph 1. ## Paragraph 2. ## Etc. ]#
I'd have the handle() method take care of this – there would be no special substition plugin for it. What do you think?
BTW, I added a special thank you to the description for providing a plugin tutorial.
I thought of an even better way to embed paragraphs. If the content contains at least one blank line (whitespace only), then the entire content is partitioned into paragraphs delimited by blank lines. In particular, to get just one paragraph, you'd do this:
#prettybox[ This is the only paragraph. ]#
The blank line occurs on the same line as#prettybox[
, immediately following this opening tag.
But I'd really rather be able to embed any syntax. Is it possible to call the DokuWiki parser recursively?
Spider JoeYes, its possible, probably not wise.// where $text is a string containing DokuWiki markup to be rendered // and $info is an array to receive information from the renderer $xhtml_output = p_render('xhtml', p_get_instructions($text),$info=array());Its not very efficient. There is a large overhead in setting up the parser. If you use a type of
formatting
you can just embed about any syntax. — Christopher Smith 2005-08-23 23:49
Maybe a future rev of the parser could factor out the static configuration so that nested invocations could share that configuration without rebuilding it? You might also have to pass in an inheritable state. Dunno.
I tried changing Div Shorthand to use type formatting, allowing nesting types, but I ended up with the same problem as using type container and allowing nesting types – weird paragraph generation. It looks like the problem is with PType block – it's dictating what happens between a syntax mode's opening and closing tags.
BTW, how are you embedding the date/time in your responses? Is there an easy way to do this? I can't find it on the syntax page or the FAQ. Thanks!
Spider JoeDon't useblock
, usenormal
with the paragraph formatting I suggested. Withblock
the parser will open and close paragraphs before and after any nested formatting, withnormal
it doesn't do that.
If you are logged in, you will have a signature button amongst all the other editing buttons, you also get your login name added to the changes log. — Christopher Smith 2005-08-24 23:34
I'm unable to get the shorthand/syntax/span.php + syntax_plugin_shorthand_span directory organization to work. PHP isn't logging any error messages either. My next plugin sort of requires this directory structure because there are include files shared among the variations, and I'd like a logical home for those files. Any ideas? I'm using a recent devel version. Thanks! Spider Joe
Uh, never mind. It works. The problem was with my new plugin (yet to be posted). An error was causing the parser to bomb out no matter what I did. My plugin PHP errors don't seem to be making it to the PHP error log.
BTW, I think I'd like to leave div_shorthand and span_shorthand in different directories. Other people might come up with other shorthand, and I don't want to confuse people by already have the shorthand directory taken. Besides, the only thing shorthand plugins will have in common is the conceptual idea of being shorthand, not any logic. Spider Joe
Your comment about PHP not logging error messages. To error check your plugin, editinc/pluginutils.php
and remove the “@” from in front of the two includes in theplugin_load()
function. Note this will likely mean DokuWiki generates lots of warnings when it first attempts to load any plugins using subfolders viapluginname/syntax.php
. You could get around this by changing the error level to ignore warnings outside your plugin, and if you wish setting a tighter error level inside the plugin (remember to reset the error level before exiting).
The two plugins might not share any code, but conceptually they are two sides of the one coin, doing the same thing just at different places within the wiki page. I think it could be reasonably assumed that a user of one of the plugins would be a user of the other. Of course its up to you about the name and structure - but would you consider a name like “custom_class”?— Christopher Smith 2005-08-25 20:56
That's good to know about the error logging. Thanks. I wish I knew about that before starting the Command Plugin.
There seems to be four possible ways to use <div>:
Please note that
P
is a block element in (X)HTML that only allows inline data (see http://www.w3.org/TR/html401/struct/text.html#edef-P). So your first two points will cause invalid (X)HTML becauseDIV
is a block element as well that can not be nested within a paragraph. – The other way around, however, is completely valid (severalP
s inside aDIV
).
— Matthias Watermann 2005-08-28 14:42
You might want the div to be aligned relative to the paragraph, or even to be display:inline within the paragraph, and you might want that same div to itself contain multiple paragraphs. Or you might want the div to appear outside paragraphs, perhaps as one containing an image and a caption without any paragraphs. Or you might want the div to be something like a boxed note, external to paragraphs so that paragraphs wrap around it, yet it itself contains one or more paragraphs.
Right now the #
notation is implemented as (3), which is possibly the least likely use of the syntax. To implement (4) I'd need a fix for the problem that PType block creates inside of a container syntax, or I'd have to do your suggestion. But your suggestion requires that paragraph text precede and follow the div, since it begins with </p> and ends with <p>. If no inline text precedes or follows, you get <p></p> in that place. I don't know how to do (2) with the parser, unless I call it recursively. That leaves (1) as the most likely most doable solution.
What behavior would be most helpful to people? In any case, I prefer to allow syntax within the div, and this is not currently allowed.
BTW, if I end up creating yet another variant of this syntax, I'll probably throw it all into the same plugin. Maybe the potential should be enough to incline me to do so.
$renderer->document
is the whole output document up to that point. You can always look back at the characters immediately before the end to see if they are<p>
and remove them if they are. Though to be fair, it would make sense for the renderer to check for empty <p> tags as its probably a fairly frequently occurring issue. — Christopher Smith 2005-08-27 01:48
Hey, that's a clever hack.It does allows me to remove a preceding one, but not a following one. The best I can do with the following paragraph is to always give it an absolute position off screen via the HTML style attribute. This might keep people from putting text in the same paragraph, but it might incline some people to put sneaky text in there that a search engine or a filtering client might see, but that people browsing and maintaining the site would not.
Were I to go ahead with that solution, I'm thinking of having four syntaxes instead of two.%
and#
would indicate whether the contents goes into an outer paragraph or not, while curly-braces and square-brackets would signify the use of a span or div, respectively.
Inside a#
you would have the option of having paragraphs auto-generated. The plugin would put a special marker in$renderer->document
at the beginning of the content and it would monitor unmatched text. If ever a blank line appears — according to the unmatched text — then the entire content would be repartitioned into paragraphs. I'm thinking that I could leave the marker in there (as an HTML comment) if repartitioning is not required, to save a few clock cycles.
Ideally, a future version of the parser would encapsulate page concatenation and then write each contribution to an output buffer. You can do this by capturing the output buffer before parsing, parsing to collect a new output buffer, capturing the parser's output buffer, and then restoring the original output buffer. Buffered output would be far more efficient than string cat'ing, which requires creating huge numbers of objects, reallocating the heap and copying growing strings. Higher peak load, you know. You could do this without breaking existing plugins by monitoring$renderer->document
, which would then serve as just an output variable for old-style plugins. (Of course, this plugin, as proposed, would break. But it could be fixed.)
Anyway, can you think of a better way to deal with the paragraph that follows the#
-style shorthand? If I can monitor unmatched text as described, hidden text is the only thing keeping me from doing it. — Spider Joe
So here's what I'm thinking. I'm going to rewrite these two plugins and add a third:
%spanclass{words}%
produces a <span> embedded in a paragraph. %divclass[words]%
produces a <div> embedded in a paragraph. #divclass[words]#
produces a <div> not embedded in a paragraph.the second option creates invalid XHTML. Embedding of <div> inside of <p> is invalid…martin
In addition:
#divclass[words]#
I'll remove the preceding paragraph if it's empty (<p></p>) and I'll always give the following paragraph a relative position, so that it doesn't consume space on the page and yet it's presence and contents will be visible. This should keep people from putting text in the same paragraph.For number two. Can't it honor the entered wiki syntax. Wrap the div/span around whatever wiki syntax the user enters. Potentially the user could enter both <p>s as well as other HTML such as links, lists.
The syntax indicates that there should also be#divid[words]#
, attaching an id. As an alternative how about this#div?id=words&class=words#
…martin
I thought of adding another syntax for clearing empty paragraphs from the preceding portion of the page, but I didn't want to burden people by making them have to do this.
Please speak up if you can think of a better approach. Thanks! — Spider Joe
Is it possible to modify div plugin to put div class “your_class” into another class that's in main.php. That is:
my_class[words][container_class]
with second argument were optional (page is default)
useful for edit other divs outside div in which are tpl_content, editing the wiki.
Thanks, DXpublica ATTT telefonica.net
I liked the idea including such a flexible command – I used note in a modified version to display poems and so I knew, it was able to produce a valid xhtml-code (even if I use paragrafs). So I just mixed note and div_shorthand in order to have a flexible solution for my needs. Since I did it with try and error it may be not well done, but it works. It produces <div class="yourclass"><p>text</p></div> rendering all text normally
Here is the (mixed) Code:
<?php /** * Div Shorthand Plugin: Shorthand for <div class="your_class">...</div>. * * syntax: #your_class[...]# * * Modified Version of the DivShorthand-Plugin - text is parsed and there is no "ain't-Bug" * This version uses code of the Note-Plugin to enable rendering of the text * * @license GPL 2 (http://www.gnu.org/licenses/gpl.html) * @author Joe Lapp <http://www.spiderjoe.com> */ if(!defined('DOKU_INC')) define('DOKU_INC',realpath(dirname(__FILE__).'/../../').'/'); if(!defined('DOKU_PLUGIN')) define('DOKU_PLUGIN',DOKU_INC.'lib/plugins/'); require_once(DOKU_PLUGIN.'syntax.php'); class syntax_plugin_div_shorthand extends DokuWiki_Syntax_Plugin { function getInfo() { return array( 'author' => 'Joe Lapp, modified by Wolfgang Fricke', 'email' => '', 'date' => '2007-09-06', 'name' => 'Div Shorthand', 'desc' => 'Shorthand for <div class="your_class">...</div>', 'url' => 'http://www.dokuwiki.org/plugin:div_span_shorthand', ); } function getType() { return 'container'; } function getAllowedTypes() { // I'd like to allow all types, but the <p> autogen behavior makes them troublesome. return array('container','substition','protected','disabled','formatting','paragraphs'); } function getPType() { return 'normal'; } function getSort() { return 500; } // I'm not sure what's appropriate function connectTo($mode) { $this->Lexer->addEntryPattern('\#[a-zA-Z0-9_-]+\[(?=.*\x5D\x23)', $mode, 'plugin_div_shorthand'); } // override default accepts() method to allow nesting // - ie, to get the plugin accepts its own entry syntax function accepts($mode) { if ($mode == substr(get_class($this), 7)) return true; return parent::accepts($mode); } function postConnect() { $this->Lexer->addExitPattern('\]\#', 'plugin_div_shorthand'); } function handle($match, $state, $pos, &$handler) { switch($state) { case DOKU_LEXER_ENTER: return array($state, substr($match, 1, -1)); case DOKU_LEXER_UNMATCHED: return array($state, $match); default: return array($state); } } function render($mode, &$renderer, $indata) { if($mode == 'xhtml'){ list($state, $data) = $indata; switch ($state) { case DOKU_LEXER_ENTER : $renderer->doc .= "\n</p>\n"; $renderer->doc .= '<div class="'.$data.'"><p>'; break; case DOKU_LEXER_UNMATCHED : $renderer->doc .= $renderer->_xmlEntities($data); break; case DOKU_LEXER_EXIT : $renderer->doc .= "\n</p></div><p>"; break; } return true; } // unsupported $mode return false; } } //Setup VIM: ex: et ts=4 enc=utf-8 : ?>
— Wolfgang 2007/09/06
WCpedia's Monkhouse Hi; I posted to the plugin requests forum about a plugin for being able to have two columns, and someone replied sending me here. Unfortunately, I don't know what “div” and “span” do. In my days of html-ing they didn't exist. Would this plugin allow me to do that? If so, could you show me an example? This is the WCpedia index page; just a table of links. I'd like to put the second set on a second column. Thanks in advance.
— mikeY 2008-12-26
Something I was surprised not to find here is have multiple classes for a div element. All that is needed to enable this is to add a space in the regex entry pattern:
... function connectTo($mode) { $this->Lexer->addEntryPattern('\#[ a-zA-Z0-9_-]+\[(?=.*\x5D\x23)', $mode, 'plugin_div_shorthand'); } ...
Hi, I'm using this plugin for some time, and I've done several modifications. The most important ones are some of the ones suggested by martin (support for id
), Spider Joe (taking the plugin to a special directory), C. Smith (plugin renaming), the regex above to allow multiple classes, and the suggestion to try and merge the two syntaxes, package for the Plugin Manager, etc. The resulting code is still in beta status, and quite slow, but usable, and should work wonders alongside the txtconf
plugin if it can be made to edit the conf/userstyle.css
.
Can I ask for permission from the author to send patches and have the new code published, or, if development is currently not continued, to release a fork? — Luis Machuca B. 2009/02/01 03:28
Have try to fix the <p> problem for a div Plugin, it works in normal cases, but not in nested blocks. I thing with a Plugin i don't get enough control over the parser process to generate a correct XHTML (or has somebody a idea how to fix this in all cases?)
I would suggest to implement a span and div format type fix in to dokuwiki, with two standard CSS in the template folder. And the div type should by nestable and generate correct XHTML format. (<box a1><box a2>Text</box></box>)
This would give dokuwiki big formatting power in a simple way. Of course a 100% working Plugin solution would be ok too. (div is much more tricky then span, i would not merge the span and div!.)
A Format like this would be nice:
<spn>Text</spn> <spn cname>Text</spn> becomes: <span class="spn">Text</span> <span class="spn_cname">Text</span>
<box>Text</box> <box cname>Text</box> becomes: <div class="box">Text</div> <div class="box_cname">Text</div>
And a spn.css and box.css in the template folder
The plugin variation uses this code (in short!)
function getSort() { return 140; } function getType() { return 'container'; } function getAllowedTypes() { return array('container', 'formatting', 'substition', 'protected', 'disabled', 'paragraphs'); } function getPType() { return 'block'; } function connectTo($mode) { $this->Lexer->addEntryPattern('<'.PLUGIN_BOX_TAG.' ?[\w]*?>\n*(?=.*?</'.PLUGIN_BOX_TAG.'>)', $mode, 'plugin_box'); // maybe [\w]{0,32} instead of [\w]*? function postConnect() { $this->Lexer->addExitPattern('\n*</'.PLUGIN_BOX_TAG.'>', 'plugin_box'); function render($mode, &$renderer, $data) { ... $name = PLUGIN_BOX_TAG; if (!empty($dat)) $name .= '_'. $dat; $dat = '<'.PLUGIN_BOX_REPLACE.' class="'. $name .'">'; $renderer->doc .= $dat; $renderer->p_open(); // Opens the first <p>, next opens automatically // BUGFIX: It opens too if next Block is nested and generates so a XHTML-Error