* * This Syntax plugin is inspired by the deprecated publistf Dokuwiki plugin, and * tries to recreate the same output using a BibBrowser * (https://github.com/monperrus/bibtexbrowser) Bibtex processing script. * * Templating is handled through the BB4DWTemplating class. */ /** * BibBrowser Configurations */ $_GET['library'] = 1; // cause BibBrowser to run in 'library' mode define('BIBTEXBROWSER_BIBTEX_LINKS', false); // disable links back to bibtex define('USE_FIRST_THEN_LAST', true); // ensure that author names are consistently ordered class syntax_plugin_bb4dw extends SyntaxPlugin { /** @inheritDoc */ public function getType() { return 'substition'; } /** @inheritDoc */ public function getPType() { return 'block'; } /** @inheritDoc */ public function getSort() { return 105; } /** @inheritDoc */ public function connectTo($mode) { $this->Lexer->addSpecialPattern('\[bb4dw\|.+?\]', $mode, 'plugin_bb4dw'); } /** @inheritDoc */ public function handle($match, $state, $pos, Doku_Handler $handler) { $data = [ 'error' => false, 'groups' => [], 'bibtex' => [], 'template' => [], 'raw' => [], 'config' => ['target' => 'dokuwiki', # XXX likely we won't be able to support anything else! 'usegroup' => true, 'groupby' => 'year', # call also be 'none', 'author', or 'title' 'order' => 'newest', 'globalkey' => 'all', 'filter' => []], # or 'descending' ]; // parse the bb4dw plugin pattern $matchs = []; $pattern = '/\[bb4dw(?:\|bibtex=(dokuwiki|url):(.+?))(?:\|template=(dokuwiki|url):(.+?))(?:\|(.+?(?:\|.+?)*))?\]/'; if (preg_match($pattern, $match, $matches) === 0) { msg('Not valid bb4dw syntax: '.$match, -1); $data['error'] = true; } else { // capture matches in config $data['bibtex'] = ['type' => $matches[1], 'ref' => $matches[2]]; $data['template'] = ['type' => $matches[3], 'ref' => $matches[4]]; if (!empty($matches[5])) { $matches = explode('|', $matches[5]); foreach ( $matches as $opt ) { $optparts = array(); if (preg_match('/(.+?)=(.+)/', $opt, $optparts) ) { $optparts[2] = explode(';', $optparts[2]); $option = array(); foreach ($optparts[2] as $single) { $single = explode(':', $single); if (count($single) == 1 && count($optparts[2]) == 1) { $option = $single[0]; } else { $option[$single[0]] = str_replace(',', '|', $single[1]); } } $data['config'][$optparts[1]] = $option; } } } // init BibBrowser library require_once(dirname(__FILE__).'/bibtexbrowser.php'); global $db; $db = new BibDataBase(); // Load Bibtex into db structure $db->load($this->retrieve_resource($data['bibtex']['type'], $data['bibtex']['ref'], true)); // get all entries and sort (internally the default is by year) $data['raw'] = $db->getEntries(); //uasort($data['raw'], 'compare_bib_entries'); foreach ($data['raw'] as $entry) { // we decouple the read in fields from the bibbrowser library // we format authors into consistent state $_tmp_entry = $entry->getFields(); $_tmp_entry['niceauthor'] = $entry->getFormattedAuthorsString(); $_tmp_entry['bibtex'] = $entry->getText(); $keep = true; foreach ($data['config']['filter'] as $field => $regexp) { if (!empty($_tmp_entry[$field])) { $val = $field === 'author' ? $_tmp_entry['niceauthor'] : $_tmp_entry[$field]; $keep = $keep && preg_match('/'.$regexp.'/i', $val); } else $keep = false; } if (!$keep) { unset($_tmp_entry); continue; } switch($data['config']['groupby']) { case 'none': $groupby = 'none'; break; case 'author': $_authors = $entry->getRawAuthors(); $groupby = mb_substr($entry->getLastName($_authors[0]), 0, 1); break; case 'title': $groupby = mb_substr($entry->getTitle(), 0, 1); break; case 'year': $groupby = $entry->getYear(); break; default: msg('Unknown groupby `'.$data['config']['groupby'].'` passed!', -1); $data['error'] = true; break 2; } // ensure that we don't append to null array if (empty($data['groups'][$groupby])) $data['groups'][$groupby] = [$_tmp_entry]; else $data['groups'][$groupby][] = $_tmp_entry; } // ensure that the groups are sorted and in the specified order ksort($data['groups']); if ($data['config']['order'] == 'newest' || $data['config']['order'] == 'descending') $data['groups'] = array_reverse($data['groups'], true); } return $data; } /** @inheritDoc */ public function render($mode, Doku_Renderer $renderer, $data) { if ($data['error']) return false; if ($mode !== 'xhtml') return false; // activate caching of results $renderer->info['cache'] = $this->getConf('cache'); $tpl = $this->retrieve_resource($data['template']['type'], $data['template']['ref']); require_once(dirname(__FILE__).'/templating.php'); $bb4dw_tpl_class = new BB4DWTemplating(); $proc_tpl = $bb4dw_tpl_class->process_template($tpl, $data); if ($data['config']['target'] == 'dokuwiki') { $proc_tpl = p_render($mode, p_get_instructions($proc_tpl), $info); } $renderer->doc .= $proc_tpl; return true; } /** * Retrieve resource from one of file, URL, or dokuwiki page. The result of this * function with either be the verbatim content of the resource, or an absolute path. * * @param string $type * @param string $ref * @param bool $path * @return string Content of or path to resource */ private function retrieve_resource(string $type, string $ref, bool $path = false): string { $res = ''; switch ($type) { case 'url': if ($path) $res = $ref; else $res = file_get_contents($ref); break; case 'dokuwiki': $resolver = new PageResolver($ID); $mid = $resolver->resolveId($ref); if(page_exists($mid)) { if ($path) $res = wikiFN($mid); else $res = rawWiki($mid); } break; default: msg('Unknown type '.$type.', unable to process!', -1); break; } return $res; } }