<?php
define('HEAD', 'h3');
define('SUBHEAD', 'h4');
function t_head($text, $time, $opts = array()) {
$opts['time'] = $time;
return head_with_id(HEAD, $text, $opts);
}
function head($text, $opts = array()) {
return head_with_id(HEAD, $text, $opts);
}
function subhead($text, $opts = array()) {
return head_with_id(SUBHEAD, $text, $opts);
}
function head_with_id($tag, $text, $opts) {
global $headings;
$attrs = array();
$extras = array(
'modified' => false,
'essential' => false,
'optional' => false,
'extra' => false,
'time' => null
);
if (isset($opts['class'])) {
if (is_array($opts['class'])) {
$attrs['class'] = $opts['class'];
} else {
$attrs['class'] = array($opts['class']);
}
} else {
$attrs['class'] = array();
}
if (isset($opts['id'])) {
$id = $opts['id'];
} else {
$id = text2id($text);
}
$attrs['id'] = $id;
foreach ($extras as $key => $val) {
if (isset($opts[$key])) {
$extras[$key] = $opts[$key];
}
}
if ($extras['modified']) {
array_push($attrs['class'], 'ins');
}
if ($tag == HEAD) {
$header_classes = array();
foreach (array('essential', 'optional', 'extra') as $header_extra) {
if ($extras[$header_extra]) {
array_push($header_classes, $header_extra);
}
}
$header_attrs = count($header_classes) ? array('class' => $header_classes) : array();
}
switch ($tag) {
case HEAD:
$headings[$id] = array($text, $extras, null);
break;
case SUBHEAD:
$last = end(array_keys($headings));
list($h_text, $h_extras, $subs) = $headings[$last];
if (!is_array($subs)) {
$subs = array();
}
$subs[$id] = array($text, $extras);
$headings[$last] = array($h_text, $h_extras, $subs);
break;
}
$output = tag($tag, $text, $attrs) . ($extras['time'] ? tag('h4', "({$extras['time']} min)", array('class' => array('time'))) : '');
if ($tag == HEAD) {
$output = tag('header', $output, $header_attrs);
}
return $output;
}
function attributemap($attr, $value) {
return htmlspecialchars($attr) . '="' . htmlspecialchars($value) . '"';
}
function phplink($func, $label = '') {
if (!$label) $label = "$func()";
return tag('code', tag('a', $label, array('href' => "http://php.net/$func"), ''));
}
function tag($name, $content, $attributes = array()) {
$name = htmlspecialchars($name);
// $content = htmlspecialchars($content);
if (preg_match('/^(a|em|strong|code|var|samp|kbd|dfn|span|cite|ins|del|q|su[bp]|img|label|legend|textarea)$/', $name)) {
$ending = '';
} else {
$ending = "\n";
}
if (isset($attributes['class'])) {
$attributes['class'] = implode(' ', $attributes['class']);
}
$attributestr = implode(" ", array_map("attributemap", array_keys($attributes), array_values($attributes)));
if ($attributestr) {
return "<$name $attributestr>$content</$name>$ending";
} else {
return "<$name>$content</$name>$ending";
}
}
function text2id($text) {
$id = str_replace('&', 'and', $text);
$id = preg_replace('|</?[^>]+>|', '', $id);
$id = preg_replace("/['\"‘’“”]/", '', $id);
$id = preg_replace("/[\s ]+/", '-', $id);
$id = preg_replace("/[\-–—]+/", '-', $id);
$id = preg_replace("/\b\.\b/", '-', $id);
$id = preg_replace("/[^\w\-]/", '', $id);
return strtolower($id);
}
function toc() {
global $headings;
ob_start();
print_toc_list($headings);
return ob_get_clean();
}
function print_toc_list($headings) {
?>
<ol>
<?php
foreach ($headings as $headid => $parts) {
list($text, $extras, $subs) = @$parts;
$ins = $extras['modified'] ? ' class="ins"' : '';
$cls = array();
foreach (array('essential', 'optional', 'extra') as $c) {
if ($extras[$c]) {
$cls[] = $c;
}
}
$classes = count($cls) ? ' class="' . implode(' ', $cls) . '"' : '';
if (is_array($subs)) {
?>
<li<?= $classes ?>>
<p<?= $ins ?>>
<a href="#<?= $headid ?>"><?= $text ?></a>
<?php if ($extras['time']) { ?>
<span class="time">(<?= $extras['time'] ?> min)</span>
<?php } ?>
</p>
<?php print_toc_list($subs); ?>
</li>
<?php
} else {
?>
<li<?= $classes ?>>
<a <?= $ins ?> href="#<?= $headid ?>"><?= $text ?></a>
<?php if ($extras['time']) { ?>
<span class="time">(<?= $extras['time'] ?> min)</span>
<?php } ?>
</li>
<?php
}
}
?>
</ol>
<?php
}
function begin_structured_page() {
global $headings;
$headings = array();
ob_start();
}
function generate_structured_page() {
print str_replace('%%TOC%%', toc(), ob_get_clean());
}
?>