1*21913ab3SNickeau<?php 2*21913ab3SNickeau 3*21913ab3SNickeau 4*21913ab3SNickeaurequire_once(__DIR__ . "/../class/Analytics.php"); 5*21913ab3SNickeaurequire_once(__DIR__ . "/../class/PluginUtility.php"); 6*21913ab3SNickeaurequire_once(__DIR__ . "/../class/LinkUtility.php"); 7*21913ab3SNickeaurequire_once(__DIR__ . "/../class/HtmlUtility.php"); 8*21913ab3SNickeau 9*21913ab3SNickeauuse ComboStrap\Analytics; 10*21913ab3SNickeauuse ComboStrap\Call; 11*21913ab3SNickeauuse ComboStrap\LogUtility; 12*21913ab3SNickeauuse ComboStrap\PluginUtility; 13*21913ab3SNickeauuse ComboStrap\Tag; 14*21913ab3SNickeauuse ComboStrap\TagAttributes; 15*21913ab3SNickeau 16*21913ab3SNickeauif (!defined('DOKU_INC')) die(); 17*21913ab3SNickeau 18*21913ab3SNickeau/** 19*21913ab3SNickeau * 20*21913ab3SNickeau * A paragraph syntax 21*21913ab3SNickeau * 22*21913ab3SNickeau * This syntax component is used dynamically while parsing (at the {@link DOKU_LEXER_END} of {@link \dokuwiki\Extension\SyntaxPlugin::handle()} 23*21913ab3SNickeau * with the function {@link \syntax_plugin_combo_para::fromEolToParagraphUntilEndOfStack()} 24*21913ab3SNickeau * 25*21913ab3SNickeau * 26*21913ab3SNickeau * !!!!! 27*21913ab3SNickeau * 28*21913ab3SNickeau * Info: The `eol` call are temporary created with {@link \dokuwiki\Parsing\ParserMode\Eol} 29*21913ab3SNickeau * and transformed to `p_open` and `p_close` via {@link \dokuwiki\Parsing\Handler\Block::process()} 30*21913ab3SNickeau * 31*21913ab3SNickeau * Note: p_open call may appears when the {@link \ComboStrap\Syntax::getPType()} is set to `block` or `stack` 32*21913ab3SNickeau * and the next call is not a block or a stack 33*21913ab3SNickeau * 34*21913ab3SNickeau * !!!!! 35*21913ab3SNickeau * 36*21913ab3SNickeau * 37*21913ab3SNickeau * Note on Typography 38*21913ab3SNickeau * TODO: https://github.com/typekit/webfontloader 39*21913ab3SNickeau * https://www.dokuwiki.org/plugin:typography 40*21913ab3SNickeau * https://stackoverflow.design/email/base/typography/ 41*21913ab3SNickeau * http://kyleamathews.github.io/typography.js/ 42*21913ab3SNickeau * https://docs.gitbook.com/features/advanced-branding (Roboto, Roboto Slab, Open Sans, Source Sans Pro, Lato, Ubuntu, Raleway, Merriweather) 43*21913ab3SNickeau * http://themenectar.com/docs/salient/theme-options/typography/ (Doc) 44*21913ab3SNickeau * https://www.modularscale.com/ - see the size of font 45*21913ab3SNickeau * 46*21913ab3SNickeau * See the fonts on your computer 47*21913ab3SNickeau * https://wordmark.it/ 48*21913ab3SNickeau * 49*21913ab3SNickeau * What's a type ? Type terminology 50*21913ab3SNickeau * https://www.supremo.co.uk/typeterms/ 51*21913ab3SNickeau * 52*21913ab3SNickeau * https://theprotoolbox.com/browse/font-tools/ 53*21913ab3SNickeau */ 54*21913ab3SNickeauclass syntax_plugin_combo_para extends DokuWiki_Syntax_Plugin 55*21913ab3SNickeau{ 56*21913ab3SNickeau 57*21913ab3SNickeau const TAG = 'para'; 58*21913ab3SNickeau const COMPONENT = "combo_para"; 59*21913ab3SNickeau 60*21913ab3SNickeau 61*21913ab3SNickeau /** 62*21913ab3SNickeau * Syntax Type. 63*21913ab3SNickeau * 64*21913ab3SNickeau * Needs to return one of the mode types defined in $PARSER_MODES in parser.php 65*21913ab3SNickeau * @see https://www.dokuwiki.org/devel:syntax_plugins#syntax_types 66*21913ab3SNickeau */ 67*21913ab3SNickeau function getType() 68*21913ab3SNickeau { 69*21913ab3SNickeau return 'paragraphs'; 70*21913ab3SNickeau } 71*21913ab3SNickeau 72*21913ab3SNickeau /** 73*21913ab3SNickeau * How Dokuwiki will add P element 74*21913ab3SNickeau * 75*21913ab3SNickeau * * 'normal' - The plugin can be used inside paragraphs 76*21913ab3SNickeau * * 'block' - Open paragraphs need to be closed before plugin output - block should not be inside paragraphs 77*21913ab3SNickeau * * 'stack' - Special case. Plugin wraps other paragraphs. - Stacks can contain paragraphs 78*21913ab3SNickeau * 79*21913ab3SNickeau * @see DokuWiki_Syntax_Plugin::getPType() 80*21913ab3SNickeau */ 81*21913ab3SNickeau function getPType() 82*21913ab3SNickeau { 83*21913ab3SNickeau /** 84*21913ab3SNickeau * !important! 85*21913ab3SNickeau * The {@link \dokuwiki\Parsing\Handler\Block::process()} 86*21913ab3SNickeau * will then not create an extra paragraph after it encounters a block 87*21913ab3SNickeau */ 88*21913ab3SNickeau return 'block'; 89*21913ab3SNickeau } 90*21913ab3SNickeau 91*21913ab3SNickeau /** 92*21913ab3SNickeau * @return array 93*21913ab3SNickeau * Allow which kind of plugin inside 94*21913ab3SNickeau * 95*21913ab3SNickeau * No one of array('container', 'baseonly', 'formatting', 'substition', 'protected', 'disabled', 'paragraphs') 96*21913ab3SNickeau * because we manage self the content and we call self the parser 97*21913ab3SNickeau */ 98*21913ab3SNickeau function getAllowedTypes() 99*21913ab3SNickeau { 100*21913ab3SNickeau /** 101*21913ab3SNickeau * Not needed as we don't have any {@link syntax_plugin_combo_para::connectTo()} 102*21913ab3SNickeau */ 103*21913ab3SNickeau return array(); 104*21913ab3SNickeau } 105*21913ab3SNickeau 106*21913ab3SNickeau 107*21913ab3SNickeau /** 108*21913ab3SNickeau * @see Doku_Parser_Mode::getSort() 109*21913ab3SNickeau * The mode with the lowest sort number will win out 110*21913ab3SNickeau * 111*21913ab3SNickeau */ 112*21913ab3SNickeau function getSort() 113*21913ab3SNickeau { 114*21913ab3SNickeau /** 115*21913ab3SNickeau * Not really needed as we don't have any {@link syntax_plugin_combo_para::connectTo()} 116*21913ab3SNickeau * 117*21913ab3SNickeau * Note: if we start to use it should be less than 370 118*21913ab3SNickeau * Ie Less than {@link \dokuwiki\Parsing\ParserMode\Eol::getSort()} 119*21913ab3SNickeau */ 120*21913ab3SNickeau return 369; 121*21913ab3SNickeau } 122*21913ab3SNickeau 123*21913ab3SNickeau 124*21913ab3SNickeau function connectTo($mode) 125*21913ab3SNickeau { 126*21913ab3SNickeau 127*21913ab3SNickeau /** 128*21913ab3SNickeau * No need to connect 129*21913ab3SNickeau * This syntax plugin is added dynamically with the {@link Tag::processEolToEndStack()} 130*21913ab3SNickeau * function 131*21913ab3SNickeau */ 132*21913ab3SNickeau 133*21913ab3SNickeau } 134*21913ab3SNickeau 135*21913ab3SNickeau 136*21913ab3SNickeau /** 137*21913ab3SNickeau * The handler for an internal link 138*21913ab3SNickeau * based on `internallink` in {@link Doku_Handler} 139*21913ab3SNickeau * The handler call the good renderer in {@link Doku_Renderer_xhtml} with 140*21913ab3SNickeau * the parameters (ie for instance internallink) 141*21913ab3SNickeau * @param string $match 142*21913ab3SNickeau * @param int $state 143*21913ab3SNickeau * @param int $pos 144*21913ab3SNickeau * @param Doku_Handler $handler 145*21913ab3SNickeau * @return array|bool 146*21913ab3SNickeau */ 147*21913ab3SNickeau function handle($match, $state, $pos, Doku_Handler $handler) 148*21913ab3SNickeau { 149*21913ab3SNickeau 150*21913ab3SNickeau /** 151*21913ab3SNickeau * No need to handle, 152*21913ab3SNickeau * there is no {@link syntax_plugin_combo_para::connectTo() connection} 153*21913ab3SNickeau */ 154*21913ab3SNickeau return true; 155*21913ab3SNickeau 156*21913ab3SNickeau 157*21913ab3SNickeau } 158*21913ab3SNickeau 159*21913ab3SNickeau /** 160*21913ab3SNickeau * Render the output 161*21913ab3SNickeau * @param string $format 162*21913ab3SNickeau * @param Doku_Renderer $renderer 163*21913ab3SNickeau * @param array $data - what the function handle() return'ed 164*21913ab3SNickeau * @return boolean - rendered correctly? (however, returned value is not used at the moment) 165*21913ab3SNickeau * @see DokuWiki_Syntax_Plugin::render() 166*21913ab3SNickeau * 167*21913ab3SNickeau * 168*21913ab3SNickeau */ 169*21913ab3SNickeau function render($format, Doku_Renderer $renderer, $data) 170*21913ab3SNickeau { 171*21913ab3SNickeau // The data 172*21913ab3SNickeau switch ($format) { 173*21913ab3SNickeau case 'xhtml': 174*21913ab3SNickeau 175*21913ab3SNickeau /** @var Doku_Renderer_xhtml $renderer */ 176*21913ab3SNickeau $state = $data[PluginUtility::STATE]; 177*21913ab3SNickeau switch ($state) { 178*21913ab3SNickeau case DOKU_LEXER_ENTER: 179*21913ab3SNickeau $tagAttributes = TagAttributes::createFromCallStackArray($data[PluginUtility::ATTRIBUTES]); 180*21913ab3SNickeau $renderer->doc .= $tagAttributes->toHtmlEnterTag("p"); 181*21913ab3SNickeau break; 182*21913ab3SNickeau case DOKU_LEXER_SPECIAL: 183*21913ab3SNickeau $tagAttributes = TagAttributes::createFromCallStackArray($data[PluginUtility::ATTRIBUTES]); 184*21913ab3SNickeau $renderer->doc .= $tagAttributes->toHtmlEnterTag("p"); 185*21913ab3SNickeau $renderer->doc .= "</p>"; 186*21913ab3SNickeau break; 187*21913ab3SNickeau case DOKU_LEXER_EXIT: 188*21913ab3SNickeau $renderer->doc .= "</p>"; 189*21913ab3SNickeau break; 190*21913ab3SNickeau } 191*21913ab3SNickeau return true; 192*21913ab3SNickeau 193*21913ab3SNickeau case 'metadata': 194*21913ab3SNickeau 195*21913ab3SNickeau /** @var Doku_Renderer_metadata $renderer */ 196*21913ab3SNickeau 197*21913ab3SNickeau 198*21913ab3SNickeau return true; 199*21913ab3SNickeau 200*21913ab3SNickeau 201*21913ab3SNickeau case Analytics::RENDERER_FORMAT: 202*21913ab3SNickeau 203*21913ab3SNickeau /** 204*21913ab3SNickeau * @var renderer_plugin_combo_analytics $renderer 205*21913ab3SNickeau */ 206*21913ab3SNickeau return true; 207*21913ab3SNickeau 208*21913ab3SNickeau } 209*21913ab3SNickeau // unsupported $mode 210*21913ab3SNickeau return false; 211*21913ab3SNickeau } 212*21913ab3SNickeau 213*21913ab3SNickeau /** 214*21913ab3SNickeau * 215*21913ab3SNickeau * Transform EOL into paragraph 216*21913ab3SNickeau * between the {@link CallStack::getActualCall()} and the {@link CallStack::isPointerAtEnd()} 217*21913ab3SNickeau * of the stack 218*21913ab3SNickeau * 219*21913ab3SNickeau * Info: Basically, you get an new paragraph with a blank line or `\\` : https://www.dokuwiki.org/faq:newlines 220*21913ab3SNickeau * 221*21913ab3SNickeau * It replaces the {@link \dokuwiki\Parsing\Handler\Block::process() eol to paragraph Dokuwiki process} 222*21913ab3SNickeau * that takes place at the end of parsing process on the whole stack 223*21913ab3SNickeau * 224*21913ab3SNickeau * Info: The `eol` call are temporary created with {@link \dokuwiki\Parsing\ParserMode\Eol} 225*21913ab3SNickeau * and transformed to `p_open` and `p_close` via {@link \dokuwiki\Parsing\Handler\Block::process()} 226*21913ab3SNickeau * 227*21913ab3SNickeau * @param \ComboStrap\CallStack $callstack 228*21913ab3SNickeau * @param $class 229*21913ab3SNickeau */ 230*21913ab3SNickeau public static function fromEolToParagraphUntilEndOfStack(&$callstack, $class) 231*21913ab3SNickeau { 232*21913ab3SNickeau /** 233*21913ab3SNickeau * The attributes passed to the paragraph 234*21913ab3SNickeau */ 235*21913ab3SNickeau $attributes = array("class" => $class); 236*21913ab3SNickeau 237*21913ab3SNickeau /** 238*21913ab3SNickeau * The syntax plugin that implements the paragraph 239*21913ab3SNickeau * ie {@link \syntax_plugin_combo_para} 240*21913ab3SNickeau * We will transform the eol with a call to this syntax plugin 241*21913ab3SNickeau * to create the paragraph 242*21913ab3SNickeau */ 243*21913ab3SNickeau $paragraphComponent = \syntax_plugin_combo_para::COMPONENT; 244*21913ab3SNickeau 245*21913ab3SNickeau /** 246*21913ab3SNickeau * The running variables 247*21913ab3SNickeau */ 248*21913ab3SNickeau $paragraphIsOpen = false; // A pointer to see if the paragraph is open 249*21913ab3SNickeau while ($callstack->next()) { 250*21913ab3SNickeau 251*21913ab3SNickeau $actualCall = $callstack->getActualCall(); 252*21913ab3SNickeau if ($actualCall->getTagName() === "eol") { 253*21913ab3SNickeau 254*21913ab3SNickeau /** 255*21913ab3SNickeau * Next Call 256*21913ab3SNickeau */ 257*21913ab3SNickeau $nextCall = $callstack->next(); 258*21913ab3SNickeau $callstack->prev(); 259*21913ab3SNickeau if ($nextCall === false) { 260*21913ab3SNickeau $nextDisplay = "last"; 261*21913ab3SNickeau $nextCall = null; 262*21913ab3SNickeau } else { 263*21913ab3SNickeau $nextDisplay = $nextCall->getDisplay(); 264*21913ab3SNickeau } 265*21913ab3SNickeau 266*21913ab3SNickeau 267*21913ab3SNickeau /** 268*21913ab3SNickeau * Processing 269*21913ab3SNickeau */ 270*21913ab3SNickeau if (!$paragraphIsOpen) { 271*21913ab3SNickeau 272*21913ab3SNickeau switch ($nextDisplay) { 273*21913ab3SNickeau case Call::BlOCK_DISPLAY: 274*21913ab3SNickeau case "last": 275*21913ab3SNickeau $callstack->deleteActualCallAndPrevious(); 276*21913ab3SNickeau break; 277*21913ab3SNickeau case Call::INLINE_DISPLAY: 278*21913ab3SNickeau $paragraphIsOpen = true; 279*21913ab3SNickeau $actualCall->updateToPluginComponent( 280*21913ab3SNickeau $paragraphComponent, 281*21913ab3SNickeau DOKU_LEXER_ENTER, 282*21913ab3SNickeau $attributes 283*21913ab3SNickeau ); 284*21913ab3SNickeau break; 285*21913ab3SNickeau case "eol": 286*21913ab3SNickeau /** 287*21913ab3SNickeau * Empty line 288*21913ab3SNickeau */ 289*21913ab3SNickeau $actualCall->updateToPluginComponent( 290*21913ab3SNickeau $paragraphComponent, 291*21913ab3SNickeau DOKU_LEXER_ENTER, 292*21913ab3SNickeau $attributes 293*21913ab3SNickeau ); 294*21913ab3SNickeau $nextCall->updateToPluginComponent( 295*21913ab3SNickeau $paragraphComponent, 296*21913ab3SNickeau DOKU_LEXER_EXIT 297*21913ab3SNickeau ); 298*21913ab3SNickeau $callstack->next(); 299*21913ab3SNickeau break; 300*21913ab3SNickeau default: 301*21913ab3SNickeau LogUtility::msg("The eol action for the combination enter / (" . $nextDisplay . ") of the call ( $nextCall ) was not implemented", LogUtility::LVL_MSG_ERROR); 302*21913ab3SNickeau break; 303*21913ab3SNickeau } 304*21913ab3SNickeau } else { 305*21913ab3SNickeau /** 306*21913ab3SNickeau * Paragraph is open 307*21913ab3SNickeau */ 308*21913ab3SNickeau switch ($nextDisplay) { 309*21913ab3SNickeau case "eol": 310*21913ab3SNickeau /** 311*21913ab3SNickeau * Empty line 312*21913ab3SNickeau */ 313*21913ab3SNickeau $actualCall->updateToPluginComponent( 314*21913ab3SNickeau $paragraphComponent, 315*21913ab3SNickeau DOKU_LEXER_EXIT 316*21913ab3SNickeau ); 317*21913ab3SNickeau $nextCall->updateToPluginComponent( 318*21913ab3SNickeau $paragraphComponent, 319*21913ab3SNickeau DOKU_LEXER_ENTER, 320*21913ab3SNickeau $attributes 321*21913ab3SNickeau ); 322*21913ab3SNickeau $callstack->next(); 323*21913ab3SNickeau break; 324*21913ab3SNickeau case Call::INLINE_DISPLAY: 325*21913ab3SNickeau // A space 326*21913ab3SNickeau $actualCall->updateEolToSpace(); 327*21913ab3SNickeau break; 328*21913ab3SNickeau case Call::BlOCK_DISPLAY: 329*21913ab3SNickeau case "last"; 330*21913ab3SNickeau $actualCall->updateToPluginComponent( 331*21913ab3SNickeau $paragraphComponent, 332*21913ab3SNickeau DOKU_LEXER_EXIT 333*21913ab3SNickeau ); 334*21913ab3SNickeau $paragraphIsOpen = false; 335*21913ab3SNickeau break; 336*21913ab3SNickeau default: 337*21913ab3SNickeau LogUtility::msg("The display for a open paragraph (" . $nextDisplay . ") is not implemented", LogUtility::LVL_MSG_ERROR); 338*21913ab3SNickeau break; 339*21913ab3SNickeau } 340*21913ab3SNickeau } 341*21913ab3SNickeau 342*21913ab3SNickeau } 343*21913ab3SNickeau } 344*21913ab3SNickeau 345*21913ab3SNickeau // if the paragraph is open close it 346*21913ab3SNickeau if ($paragraphIsOpen) { 347*21913ab3SNickeau $callstack->insertBefore( 348*21913ab3SNickeau Call::createComboCall( 349*21913ab3SNickeau \syntax_plugin_combo_para::TAG, 350*21913ab3SNickeau DOKU_LEXER_EXIT 351*21913ab3SNickeau ) 352*21913ab3SNickeau ); 353*21913ab3SNickeau } 354*21913ab3SNickeau } 355*21913ab3SNickeau 356*21913ab3SNickeau} 357*21913ab3SNickeau 358