1ad615f37SSungbin Jeon<?php 273971cfeSSungbin Jeon/* 373971cfeSSungbin Jeon * This file is part of the clockoon/dokuwiki-commonmark-plugin package. 473971cfeSSungbin Jeon * 573971cfeSSungbin Jeon * (c) Sungbin Jeon <clockoon@gmail.com> 673971cfeSSungbin Jeon * 773971cfeSSungbin Jeon * Original code based on the followings: 873971cfeSSungbin Jeon * - CommonMark JS reference parser (https://bitly.com/commonmark-js) (c) John MacFarlane 973971cfeSSungbin Jeon * - league/commonmark (https://github.com/thephpleague/commonmark) (c) Colin O'Dell <colinodell@gmail.com> 1073971cfeSSungbin Jeon * 1173971cfeSSungbin Jeon * For the full copyright and license information, please view the LICENSE 1273971cfeSSungbin Jeon * file that was distributed with this source code. 13ad615f37SSungbin Jeon */ 148ec9a8f2SSungbin Jeon 158ec9a8f2SSungbin Jeon require_once __DIR__.'/src/bootstrap.php'; 168ec9a8f2SSungbin Jeon 178ec9a8f2SSungbin Jeon use Dokuwiki\Plugin\Commonmark\Commonmark; 18*80734199SSungbin Jeon use Nette\Utils\Strings; 19ad615f37SSungbin Jeon 20ad615f37SSungbin Jeon if(!defined('DOKU_INC')) die(); 21ad615f37SSungbin Jeon 22ad615f37SSungbin Jeon class action_plugin_commonmark extends DokuWiki_Action_Plugin { 23*80734199SSungbin Jeon // array for heading positions 24*80734199SSungbin Jeon // [hid] => {[depth], [startline], [endline]} 25*80734199SSungbin Jeon public $headingInfo = []; 26*80734199SSungbin Jeon // positions of newline 27*80734199SSungbin Jeon public $linePosition = []; 28*80734199SSungbin Jeon // flag for checking first run only 29*80734199SSungbin Jeon public $firstRun = true; 30*80734199SSungbin Jeon 31ad615f37SSungbin Jeon /** 32ad615f37SSungbin Jeon * pass text to Commonmark parser before DW parser 33ad615f37SSungbin Jeon */ 34ad615f37SSungbin Jeon public function register(Doku_Event_Handler $controller) { 35ad615f37SSungbin Jeon $controller->register_hook('PARSER_WIKITEXT_PREPROCESS', 'BEFORE', $this, 36ad615f37SSungbin Jeon '_commonmarkparse'); 37*80734199SSungbin Jeon $controller->register_hook('HTML_SECEDIT_BUTTON', 'BEFORE', $this, 38*80734199SSungbin Jeon '_editbutton'); 39*80734199SSungbin Jeon } 40*80734199SSungbin Jeon 41*80734199SSungbin Jeon public function _editbutton(Doku_Event $event, $param) { 42*80734199SSungbin Jeon global $conf; 43*80734199SSungbin Jeon 44*80734199SSungbin Jeon // get hid 45*80734199SSungbin Jeon $hid = $event->data['hid']; 46*80734199SSungbin Jeon // fetch range on original md 47*80734199SSungbin Jeon // check hid match 48*80734199SSungbin Jeon $keys = array_keys($this->headingInfo); 49*80734199SSungbin Jeon if (array_key_exists($hid,$keys)) { 50*80734199SSungbin Jeon // get max section editing level config 51*80734199SSungbin Jeon $maxsec = $conf['maxseclevel']; 52*80734199SSungbin Jeon // set start position 53*80734199SSungbin Jeon // first, check whether first heading 54*80734199SSungbin Jeon if ($hid == $keys[0]) { 55*80734199SSungbin Jeon $start = 1; 56*80734199SSungbin Jeon } else { 57*80734199SSungbin Jeon $lineStart = $this->headingInfo[$hid]['startline']; 58*80734199SSungbin Jeon // since CommonMark library finds heading marks, we have to declare 59*80734199SSungbin Jeon $start = $this->linePosition[$lineStart]; 60*80734199SSungbin Jeon } 61*80734199SSungbin Jeon // find end key & location; proceed while max level or less arrived 62*80734199SSungbin Jeon $endlevel = 52; 63*80734199SSungbin Jeon $index = array_search($hid,$keys); 64*80734199SSungbin Jeon $end = 0; // 0 means end of document 65*80734199SSungbin Jeon $stop = false; 66*80734199SSungbin Jeon while($stop == false) { 67*80734199SSungbin Jeon if (isset($keys[$index+1])) { // check for non-last element 68*80734199SSungbin Jeon $endlevel = $this->headingInfo[$keys[$index+1]]['level']; 69*80734199SSungbin Jeon $lineEnd = $this->headingInfo[$keys[$index+1]]['startline'] - 1; // go one line up 70*80734199SSungbin Jeon $end = $this->linePosition[$lineEnd]; 71*80734199SSungbin Jeon if($maxsec<=$endlevel) { $stop = true; } 72*80734199SSungbin Jeon } else { 73*80734199SSungbin Jeon $end = 0; 74*80734199SSungbin Jeon $stop = true; 75*80734199SSungbin Jeon } 76*80734199SSungbin Jeon $index = $index + 1; 77*80734199SSungbin Jeon } 78*80734199SSungbin Jeon if($end == 0) { 79*80734199SSungbin Jeon $event->data['range'] = (string)$start.'-'; 80*80734199SSungbin Jeon } else { 81*80734199SSungbin Jeon $event->data['range'] = (string)$start.'-'.$end; 82*80734199SSungbin Jeon } 83*80734199SSungbin Jeon 84*80734199SSungbin Jeon } 85*80734199SSungbin Jeon // example: $event->data['range'] = '1-2'; 86ad615f37SSungbin Jeon } 87ad615f37SSungbin Jeon 88ad615f37SSungbin Jeon public function _commonmarkparse(Doku_Event $event, $param) { 89*80734199SSungbin Jeon $markdown = $event->data; 90532432a2SSungbin Jeon // check force_commonmark option; if 1, ignore doctype 91532432a2SSungbin Jeon if ($this->getConf('force_commonmark')) { 927569cca4SSungbin Jeon $markdown = ltrim($markdown); 93*80734199SSungbin Jeon $result = Commonmark::RendtoDW($markdown, $this->getConf('frontmatter_tag')); 94ad615f37SSungbin Jeon } 95*80734199SSungbin Jeon elseif (preg_match('/\A<!DOCTYPE markdown>/',$markdown)) { 96*80734199SSungbin Jeon $markdown = preg_replace('/\A<!DOCTYPE markdown>\n/','',$markdown); 97*80734199SSungbin Jeon $markdown = ltrim($markdown); 98*80734199SSungbin Jeon $result = Commonmark::RendtoDW($markdown, $this->getConf('frontmatter_tag')); 99*80734199SSungbin Jeon $event->data = $result['text']; 100*80734199SSungbin Jeon } 101*80734199SSungbin Jeon $event->data = $result['text']; 102*80734199SSungbin Jeon if ($this->firstRun == true) { 103*80734199SSungbin Jeon // get position of each line 104*80734199SSungbin Jeon $lastPos = 0; 105*80734199SSungbin Jeon while(($lastPos = strpos($markdown,'\n',$lastPos)) !== false){ 106*80734199SSungbin Jeon $linePosition[] = $lastPos; 107*80734199SSungbin Jeon $lastPos = $lastPos + strlen('\n'); 108*80734199SSungbin Jeon } 109*80734199SSungbin Jeon $this->headingInfo = $this->CleanHeadingInfo($result['heading']); 110*80734199SSungbin Jeon $this->firstRun = false; 111*80734199SSungbin Jeon } 112*80734199SSungbin Jeon } 113*80734199SSungbin Jeon 114*80734199SSungbin Jeon public function CleanHeadingInfo(array $input): array { 115*80734199SSungbin Jeon $keys = array_keys($input); 116*80734199SSungbin Jeon foreach($keys as $key) { 117*80734199SSungbin Jeon $new_key = sectionId($key, false); 118*80734199SSungbin Jeon if($new_key != $key) { 119*80734199SSungbin Jeon $input[$new_key] = $input[$key]; 120*80734199SSungbin Jeon unset($input[$key]); 121*80734199SSungbin Jeon } 122*80734199SSungbin Jeon } 123*80734199SSungbin Jeon return $input; 124ad615f37SSungbin Jeon } 125ad615f37SSungbin Jeon} 126