'Table of Contents', 'description' => 'When you insert {maketoc} into a wiki page, it will create a nested table of contents based on the headings in that page.', 'auto_activate' => true, 'plugin_type' => FILTER_PLUGIN, // filter functions 'presplit_function' => '\Bitweaver\Liberty\maketoc_presplitfilter', 'postparse_function' => '\Bitweaver\Liberty\maketoc_postparsefilter', // these settings are to get the plugin help working on content edit pages 'tag' => 'maketoc', 'help_page' => 'Maketoc Filter', 'help_function' => 'maketoc_help', 'syntax' => '{maketoc}', 'booticon' => '{biticon ipackage="icons" iname="view-list-text" iexplain="Page Table of Contents"}', 'taginsert' => '{maketoc}', ]; $gLibertySystem->registerPlugin( PLUGIN_GUID_FILTERMAKETOC, $pluginParams ); function maketoc_presplitfilter( &$pData, &$pFilterHash ) { // we remove the maketoc stuff when the data is split. this will simplify output and won't mess with the layout on the articles / blogs front page $pData = preg_replace( "/\{maketoc[^\}]*\}\s*\n?/i", "", $pData ); } function maketoc_postparsefilter( &$pData, &$pFilterHash ) { preg_match_all( "/\{maketoc(.*?)\}/i", $pData, $maketocs ); if( !empty( $maketocs[1] )) { // extract the parameters for maketoc foreach( $maketocs[1] as $string ) { $params[] = KernelTools::parse_xml_attributes( $string ); } // get all headers into an array preg_match_all( "/]*>(.*?)<\/h\d>/i", $pData, $headers ); // clumsy way of finding out if index is set. since we can't allow // duplicate settings of index in one page, we either index everything // or nothing. foreach( $params as $p ) { if( empty( $index )) { $index = in_array( 'index', array_keys( $p )); } } if( $index ) { $counter = []; foreach( array_keys( $headers[2] ) as $key ) { $level = $headers[1][$key]; if( empty( $counter[$level] )) { $counter[$level] = 1; } elseif( $level == $headers[1][$key - 1] ) { $counter[$level]++; } elseif( $level < $headers[1][$key - 1] ) { $counter[$level] += 1; } else { $counter[$level] = 1; } $index = ''; foreach( $counter as $k => $c ) { if( $k <= $level ) { $index .= "$c."; } } $headers[2][$key] = $index.' '.$headers[2][$key]; } } // remove any html tags from the output text and generate link ids foreach( $headers[2] as $output ) { $outputs[] = $id = preg_replace( "/<[^>]*>/", "", $output ); $id = preg_replace( "@parseprotect[[a-zA-Z0-9]{32}@", "", $id ); $id = substr( preg_replace( "/[^\w|\d]*/", "", $id ), 0, 40 ); $ids[] = !empty( $id ) ? $id : 'id'.microtime() * 1000000; } // insert the tags in the right places foreach( $headers[0] as $k => $header ) { $reconstructed = "{$headers[2][$k]}"; $pData = str_replace( $header, $reconstructed, $pData ); } if( !empty( $outputs ) ) { $tocHash = [ 'outputs' => $outputs, 'ids' => $ids, 'levels' => $headers[1], ]; // (){0,1} removes up to one occurance of
|
|
|
or similar variants $sections = preg_split( "/\{maketoc.*?\}(){0,1}/i", $pData ); // first section is before any {maketoc} entry, so we can ignore it $ret = ''; foreach( $sections as $k => $section ) { // count headers in each section that we know where to begin and where to stop preg_match_all( "!]*>.*?!i", $section, $hs ); $tocHash['header_count'][] = count( $hs[0] ); $ret .= $section; // the last section will create an error if we don't check for available params if( isset( $params[$k] )) { $ret .= maketoc_create_list( $tocHash, $params[$k] ); } } } } $pData = $ret ?? preg_replace( "/\{maketoc[^\}]*\}\s*(]*>)*/i", "", $pData ); } function maketoc_create_list( $pTocHash, $pParams ) { extract( $pTocHash , EXTR_SKIP); // previous level $prev = 0; // array that is populated with the items that have to be closed eventually $open = []; // contains the actual depth we're at $depth = 0; // maximum header level output uses $maxdepth = !empty( $pParams['maxdepth'] ) ? $pParams['maxdepth'] : 6; // work out what to print $ignore = 0; if( !isset( $pParams['include'] ) || $pParams['include'] != 'all' ) { for( $i = 0; $i < count( $header_count ); $i++ ) { $ignore += $header_count[$i]; } } $list = ''; // create a dropdown that will zap user to selection if( !empty( $pParams['type'] ) && $pParams['type'] == 'dropdown' ) { $list .= '
'; $list .= '"; $list .= '
'; } else { // start with the generation of the nested