1*9337a630SNickeau<?php 2*9337a630SNickeau 3*9337a630SNickeau 4*9337a630SNickeauuse ComboStrap\Call; 5*9337a630SNickeauuse ComboStrap\CallStack; 6*9337a630SNickeauuse ComboStrap\PluginUtility; 7*9337a630SNickeauuse ComboStrap\StyleUtility; 8*9337a630SNickeauuse ComboStrap\TagAttributes; 9*9337a630SNickeau 10*9337a630SNickeaurequire_once(__DIR__ . '/../class/StyleUtility.php'); 11*9337a630SNickeaurequire_once(__DIR__ . '/../class/SnippetManager.php'); 12*9337a630SNickeau 13*9337a630SNickeau 14*9337a630SNickeau/** 15*9337a630SNickeau * Class syntax_plugin_combo_list 16*9337a630SNickeau * Implementation of a list 17*9337a630SNickeau * 18*9337a630SNickeau * Content list is a list implementation that permits to 19*9337a630SNickeau * create simple and complex list such as media list 20*9337a630SNickeau * 21*9337a630SNickeau * https://getbootstrap.com/docs/4.0/layout/media-object/#media-list - Bootstrap media list 22*9337a630SNickeau * https://getbootstrap.com/docs/5.0/utilities/flex/#media-object 23*9337a630SNickeau * https://github.com/material-components/material-components-web/tree/master/packages/mdc-list - mdc list 24*9337a630SNickeau * 25*9337a630SNickeau * It's implemented on the basis of: 26*9337a630SNickeau * * bootstrap list-group 27*9337a630SNickeau * * flex utility on the list-group-item 28*9337a630SNickeau * * with the row/cell (grid) adjusted in order to add automatically a space between col (cell) 29*9337a630SNickeau * 30*9337a630SNickeau * Note: 31*9337a630SNickeau * * The cell inside a row are centered vertically automatically 32*9337a630SNickeau * * The illustrative image does not get any [[ui:image#link|link]] 33*9337a630SNickeau * 34*9337a630SNickeau * Documentation: 35*9337a630SNickeau * https://getbootstrap.com/docs/4.1/components/list-group/ 36*9337a630SNickeau * https://getbootstrap.com/docs/5.0/components/list-group/ 37*9337a630SNickeau * 38*9337a630SNickeau * https://getbootstrap.com/docs/5.0/utilities/flex/ 39*9337a630SNickeau * https://getbootstrap.com/docs/5.0/utilities/flex/#media-object 40*9337a630SNickeau * 41*9337a630SNickeau */ 42*9337a630SNickeauclass syntax_plugin_combo_contentlist extends DokuWiki_Syntax_Plugin 43*9337a630SNickeau{ 44*9337a630SNickeau 45*9337a630SNickeau const DOKU_TAG = "contentlist"; 46*9337a630SNickeau 47*9337a630SNickeau /** 48*9337a630SNickeau * To allow a minus 49*9337a630SNickeau */ 50*9337a630SNickeau const MARKI_TAG = "content-list"; 51*9337a630SNickeau const COMBO_TAG_OLD = "list"; 52*9337a630SNickeau const COMBO_TAGS = [self::MARKI_TAG, self::COMBO_TAG_OLD]; 53*9337a630SNickeau 54*9337a630SNickeau 55*9337a630SNickeau /** 56*9337a630SNickeau * Syntax Type. 57*9337a630SNickeau * 58*9337a630SNickeau * Needs to return one of the mode types defined in $PARSER_MODES in parser.php 59*9337a630SNickeau * @see https://www.dokuwiki.org/devel:syntax_plugins#syntax_types 60*9337a630SNickeau * @see DokuWiki_Syntax_Plugin::getType() 61*9337a630SNickeau */ 62*9337a630SNickeau function getType() 63*9337a630SNickeau { 64*9337a630SNickeau return 'container'; 65*9337a630SNickeau } 66*9337a630SNickeau 67*9337a630SNickeau /** 68*9337a630SNickeau * How Dokuwiki will add P element 69*9337a630SNickeau * 70*9337a630SNickeau * * 'normal' - The plugin can be used inside paragraphs (inline or inside) 71*9337a630SNickeau * * 'block' - Open paragraphs need to be closed before plugin output (box) - block should not be inside paragraphs 72*9337a630SNickeau * * 'stack' - Special case. Plugin wraps other paragraphs. - Stacks can contain paragraphs 73*9337a630SNickeau * 74*9337a630SNickeau * @see DokuWiki_Syntax_Plugin::getPType() 75*9337a630SNickeau * @see https://www.dokuwiki.org/devel:syntax_plugins#ptype 76*9337a630SNickeau */ 77*9337a630SNickeau function getPType() 78*9337a630SNickeau { 79*9337a630SNickeau return 'block'; 80*9337a630SNickeau } 81*9337a630SNickeau 82*9337a630SNickeau /** 83*9337a630SNickeau * @return array 84*9337a630SNickeau * Allow which kind of plugin inside 85*9337a630SNickeau * 86*9337a630SNickeau * No one of array('baseonly','container', 'formatting', 'substition', 'protected', 'disabled', 'paragraphs') 87*9337a630SNickeau * because we manage self the content and we call self the parser 88*9337a630SNickeau * 89*9337a630SNickeau * Return an array of one or more of the mode types {@link $PARSER_MODES} in Parser.php 90*9337a630SNickeau */ 91*9337a630SNickeau function getAllowedTypes() 92*9337a630SNickeau { 93*9337a630SNickeau return array('container', 'formatting', 'substition', 'protected', 'disabled', 'paragraphs'); 94*9337a630SNickeau } 95*9337a630SNickeau 96*9337a630SNickeau public function accepts($mode) 97*9337a630SNickeau { 98*9337a630SNickeau 99*9337a630SNickeau return syntax_plugin_combo_preformatted::disablePreformatted($mode); 100*9337a630SNickeau 101*9337a630SNickeau } 102*9337a630SNickeau 103*9337a630SNickeau 104*9337a630SNickeau function getSort() 105*9337a630SNickeau { 106*9337a630SNickeau return 15; 107*9337a630SNickeau } 108*9337a630SNickeau 109*9337a630SNickeau 110*9337a630SNickeau function connectTo($mode) 111*9337a630SNickeau { 112*9337a630SNickeau 113*9337a630SNickeau foreach (self::COMBO_TAGS as $tag) { 114*9337a630SNickeau $pattern = PluginUtility::getContainerTagPattern($tag); 115*9337a630SNickeau $this->Lexer->addEntryPattern($pattern, $mode, PluginUtility::getModeFromTag($this->getPluginComponent())); 116*9337a630SNickeau } 117*9337a630SNickeau 118*9337a630SNickeau } 119*9337a630SNickeau 120*9337a630SNickeau public function postConnect() 121*9337a630SNickeau { 122*9337a630SNickeau foreach (self::COMBO_TAGS as $tag) { 123*9337a630SNickeau $this->Lexer->addExitPattern('</' . $tag . '>', PluginUtility::getModeFromTag($this->getPluginComponent())); 124*9337a630SNickeau } 125*9337a630SNickeau 126*9337a630SNickeau } 127*9337a630SNickeau 128*9337a630SNickeau 129*9337a630SNickeau /** 130*9337a630SNickeau * 131*9337a630SNickeau * The handle function goal is to parse the matched syntax through the pattern function 132*9337a630SNickeau * and to return the result for use in the renderer 133*9337a630SNickeau * This result is always cached until the page is modified. 134*9337a630SNickeau * @param string $match 135*9337a630SNickeau * @param int $state 136*9337a630SNickeau * @param int $pos - byte position in the original source file 137*9337a630SNickeau * @param Doku_Handler $handler 138*9337a630SNickeau * @return array|bool 139*9337a630SNickeau * @see DokuWiki_Syntax_Plugin::handle() 140*9337a630SNickeau * 141*9337a630SNickeau */ 142*9337a630SNickeau function handle($match, $state, $pos, Doku_Handler $handler) 143*9337a630SNickeau { 144*9337a630SNickeau 145*9337a630SNickeau switch ($state) { 146*9337a630SNickeau 147*9337a630SNickeau case DOKU_LEXER_ENTER : 148*9337a630SNickeau 149*9337a630SNickeau $attributes = TagAttributes::createFromTagMatch($match); 150*9337a630SNickeau 151*9337a630SNickeau if ($attributes->hasComponentAttribute(TagAttributes::TYPE_KEY)) { 152*9337a630SNickeau $type = trim(strtolower($attributes->getType())); 153*9337a630SNickeau if ($type == "flush") { 154*9337a630SNickeau // https://getbootstrap.com/docs/5.0/components/list-group/#flush 155*9337a630SNickeau // https://getbootstrap.com/docs/4.1/components/list-group/#flush 156*9337a630SNickeau $attributes->addClassName("list-group-flush"); 157*9337a630SNickeau } 158*9337a630SNickeau } 159*9337a630SNickeau return array( 160*9337a630SNickeau PluginUtility::STATE => $state, 161*9337a630SNickeau PluginUtility::ATTRIBUTES => $attributes->toCallStackArray() 162*9337a630SNickeau ); 163*9337a630SNickeau 164*9337a630SNickeau case DOKU_LEXER_UNMATCHED : 165*9337a630SNickeau 166*9337a630SNickeau return PluginUtility::handleAndReturnUnmatchedData(self::MARKI_TAG, $match, $handler); 167*9337a630SNickeau 168*9337a630SNickeau case DOKU_LEXER_EXIT : 169*9337a630SNickeau 170*9337a630SNickeau /** 171*9337a630SNickeau * Add to all row the list-group-item 172*9337a630SNickeau */ 173*9337a630SNickeau $callStack = CallStack::createFromHandler($handler); 174*9337a630SNickeau $callStack->moveToPreviousCorrespondingOpeningCall(); 175*9337a630SNickeau while ($actualCall = $callStack->next()) { 176*9337a630SNickeau if($actualCall->getTagName()==syntax_plugin_combo_contentlistitem::DOKU_TAG){ 177*9337a630SNickeau // List item were added by the user 178*9337a630SNickeau break; 179*9337a630SNickeau } 180*9337a630SNickeau if ($actualCall->getTagName() == syntax_plugin_combo_row::TAG) { 181*9337a630SNickeau $actualState = $actualCall->getState(); 182*9337a630SNickeau switch ($actualState) { 183*9337a630SNickeau case DOKU_LEXER_ENTER: 184*9337a630SNickeau $callStack->insertBefore(Call::createComboCall( 185*9337a630SNickeau syntax_plugin_combo_contentlistitem::DOKU_TAG, 186*9337a630SNickeau DOKU_LEXER_ENTER 187*9337a630SNickeau )); 188*9337a630SNickeau break; 189*9337a630SNickeau case DOKU_LEXER_EXIT: 190*9337a630SNickeau $callStack->insertAfter(Call::createComboCall( 191*9337a630SNickeau syntax_plugin_combo_contentlistitem::DOKU_TAG, 192*9337a630SNickeau DOKU_LEXER_EXIT 193*9337a630SNickeau )); 194*9337a630SNickeau $callStack->next(); 195*9337a630SNickeau break; 196*9337a630SNickeau } 197*9337a630SNickeau 198*9337a630SNickeau } 199*9337a630SNickeau } 200*9337a630SNickeau 201*9337a630SNickeau 202*9337a630SNickeau return array(PluginUtility::STATE => $state); 203*9337a630SNickeau 204*9337a630SNickeau 205*9337a630SNickeau } 206*9337a630SNickeau return array(); 207*9337a630SNickeau 208*9337a630SNickeau } 209*9337a630SNickeau 210*9337a630SNickeau /** 211*9337a630SNickeau * Render the output 212*9337a630SNickeau * @param string $format 213*9337a630SNickeau * @param Doku_Renderer $renderer 214*9337a630SNickeau * @param array $data - what the function handle() return'ed 215*9337a630SNickeau * @return boolean - rendered correctly? (however, returned value is not used at the moment) 216*9337a630SNickeau * @see DokuWiki_Syntax_Plugin::render() 217*9337a630SNickeau * 218*9337a630SNickeau * 219*9337a630SNickeau */ 220*9337a630SNickeau function render($format, Doku_Renderer $renderer, $data) 221*9337a630SNickeau { 222*9337a630SNickeau if ($format == 'xhtml') { 223*9337a630SNickeau 224*9337a630SNickeau /** @var Doku_Renderer_xhtml $renderer */ 225*9337a630SNickeau $state = $data[PluginUtility::STATE]; 226*9337a630SNickeau switch ($state) { 227*9337a630SNickeau case DOKU_LEXER_ENTER : 228*9337a630SNickeau 229*9337a630SNickeau PluginUtility::getSnippetManager()->attachCssSnippetForBar(self::MARKI_TAG); 230*9337a630SNickeau $tagAttributes = TagAttributes::createFromCallStackArray($data[PluginUtility::ATTRIBUTES], self::MARKI_TAG); 231*9337a630SNickeau $tagAttributes->addClassName("list-group"); 232*9337a630SNickeau $renderer->doc .= $tagAttributes->toHtmlEnterTag("ul") . DOKU_LF; 233*9337a630SNickeau 234*9337a630SNickeau break; 235*9337a630SNickeau case DOKU_LEXER_EXIT : 236*9337a630SNickeau $renderer->doc .= "</ul>" . DOKU_LF; 237*9337a630SNickeau break; 238*9337a630SNickeau case DOKU_LEXER_UNMATCHED : 239*9337a630SNickeau $renderer->doc .= PluginUtility::renderUnmatched($data); 240*9337a630SNickeau break; 241*9337a630SNickeau } 242*9337a630SNickeau return true; 243*9337a630SNickeau } 244*9337a630SNickeau 245*9337a630SNickeau // unsupported $mode 246*9337a630SNickeau return false; 247*9337a630SNickeau } 248*9337a630SNickeau 249*9337a630SNickeau 250*9337a630SNickeau} 251*9337a630SNickeau 252