mirror of
https://github.com/suk-ws/ph-Bookshelf.git
synced 2025-01-18 23:12:23 +08:00
pre-release 0.2 md语法附加,主题,pjax刷新(未完成的)
- 完成支持了 gitbook 的三个主题切换功能 - 同时支持 cookie 储存选择的主题(数据30天过期) - 支持了一半的 pjax 动态页面刷新 - 同时添加了 `?raw=true&nav=true` 的页面选项用于获取原始页面数据(html)数据 - markdown extra 语法支持(通过ParsedownExtra) - 添加了自定义的html元素 `<ref sorce="url">` 用于嵌入显示网络来源的 markdown 页面 - 同时也添加了自定义的 markdown 元素 `$(url)`
This commit is contained in:
commit
354365a6da
6
.gitattributes
vendored
6
.gitattributes
vendored
@ -1 +1,7 @@
|
|||||||
|
* text=auto
|
||||||
* text eol=lf
|
* text eol=lf
|
||||||
|
*.png binary
|
||||||
|
*.otf binary
|
||||||
|
*.ttf binary
|
||||||
|
*.woff binary
|
||||||
|
*.woff2 binary
|
||||||
|
@ -1,3 +1,23 @@
|
|||||||
|
:root {
|
||||||
|
--color-graystyle-background: rgba(0, 0, 0, 0.07);
|
||||||
|
--color-icon-in-background: white;
|
||||||
|
--color-graystyle: rgba(0, 0, 0, 0.2);
|
||||||
|
--color-nav-background-base: null;
|
||||||
|
}
|
||||||
|
|
||||||
|
.color-theme-1 {
|
||||||
|
--color-graystyle-background: rgba(255, 255, 255, 0.48);
|
||||||
|
--color-icon-in-background: black;
|
||||||
|
--color-graystyle: rgba(135, 127, 106, 0.5);
|
||||||
|
--color-nav-background-base: #1111111;
|
||||||
|
}
|
||||||
|
|
||||||
|
.color-theme-2 {
|
||||||
|
--color-graystyle-background: rgba(29, 34, 63, 0.6);
|
||||||
|
--color-icon-in-background: white;
|
||||||
|
--color-graystyle: rgba(193, 198, 215, 0.2);
|
||||||
|
--color-nav-background-base: #252737;
|
||||||
|
}
|
||||||
|
|
||||||
.fold > ul {
|
.fold > ul {
|
||||||
max-height: 0;
|
max-height: 0;
|
||||||
@ -54,8 +74,8 @@
|
|||||||
top: 1px;
|
top: 1px;
|
||||||
right: 20px;
|
right: 20px;
|
||||||
padding: 0 5px 2px;
|
padding: 0 5px 2px;
|
||||||
background: rgba(0,0,0,.07);
|
background: var(--color-graystyle-background);
|
||||||
color: white;
|
color: var(--color-icon-in-background);
|
||||||
border-bottom: 0;
|
border-bottom: 0;
|
||||||
border-radius: 0 0 5px 5px;
|
border-radius: 0 0 5px 5px;
|
||||||
z-index: 1000;
|
z-index: 1000;
|
||||||
@ -72,9 +92,21 @@
|
|||||||
.book .book-summary ul.summary li span.annotation {
|
.book .book-summary ul.summary li span.annotation {
|
||||||
padding: 0;
|
padding: 0;
|
||||||
font-size: 0.2em;
|
font-size: 0.2em;
|
||||||
color: rgba(0, 0, 0, 0.2);
|
color: var(--color-graystyle);
|
||||||
}
|
}
|
||||||
|
|
||||||
.book .book-summary ul.summary li span.annotation:hover {
|
.book .book-summary ul.summary li span.annotation:hover {
|
||||||
text-decoration: none !important;
|
text-decoration: none !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#book-search-input {
|
||||||
|
background-color: var(--color-nav-background-base);
|
||||||
|
}
|
||||||
|
|
||||||
|
#page-container {
|
||||||
|
transition-duration: 400ms;
|
||||||
|
}
|
||||||
|
|
||||||
|
#page-container.loading {
|
||||||
|
opacity: 0.2;
|
||||||
|
}
|
||||||
|
@ -1,6 +1,15 @@
|
|||||||
const WITH_SUMMARY_CLASS = "with-summary"
|
const WITH_SUMMARY_CLASS = "with-summary"
|
||||||
|
|
||||||
|
const DROPDOWN_OPEN_CLASS = "open";
|
||||||
|
|
||||||
let bookRoot;
|
let bookRoot;
|
||||||
|
let pageContainer;
|
||||||
|
let inBookNavContainer;
|
||||||
|
|
||||||
|
let fontSettingDiv;
|
||||||
|
|
||||||
|
let bookCurrentId;
|
||||||
|
let pageCurrentId;
|
||||||
|
|
||||||
function summaryOnOrOff () {
|
function summaryOnOrOff () {
|
||||||
|
|
||||||
@ -15,6 +24,10 @@ function summaryOnOrOff () {
|
|||||||
window.onload = function () {
|
window.onload = function () {
|
||||||
|
|
||||||
bookRoot = document.getElementsByClassName("book")[0];
|
bookRoot = document.getElementsByClassName("book")[0];
|
||||||
|
pageContainer = document.getElementById("page-container");
|
||||||
|
inBookNavContainer = document.getElementById("in-book-nav-container");
|
||||||
|
|
||||||
|
fontSettingDiv = document.getElementsByClassName("font-settings")[0].getElementsByClassName("dropdown-menu")[0];
|
||||||
|
|
||||||
if (window.innerWidth > 600) {
|
if (window.innerWidth > 600) {
|
||||||
bookRoot.classList.add(WITH_SUMMARY_CLASS);
|
bookRoot.classList.add(WITH_SUMMARY_CLASS);
|
||||||
@ -22,16 +35,17 @@ window.onload = function () {
|
|||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
for (let node of document.getElementsByClassName("fold")) {
|
function bindFolderClickEvent () {
|
||||||
node.childNodes[0].addEventListener("click", function () {
|
for (let node of document.getElementsByClassName("fold")) {
|
||||||
if (node.classList.contains("on")) {
|
node.childNodes[0].addEventListener("click", function () {
|
||||||
node.classList.remove("on");
|
if (node.classList.contains("on")) {
|
||||||
} else node.classList.add("on");
|
node.classList.remove("on");
|
||||||
});
|
} else node.classList.add("on");
|
||||||
}
|
});
|
||||||
|
}
|
||||||
|
} bindFolderClickEvent();
|
||||||
|
|
||||||
for (const node of document.getElementsByClassName("summary-container")) {
|
for (const node of document.getElementsByClassName("summary-container")) {
|
||||||
|
|
||||||
node.nextElementSibling.innerHTML = node.nextElementSibling.innerHTML + "<a class='summary-container-icon'><i class='fa'></i></a>";
|
node.nextElementSibling.innerHTML = node.nextElementSibling.innerHTML + "<a class='summary-container-icon'><i class='fa'></i></a>";
|
||||||
node.nextElementSibling.getElementsByClassName("summary-container-icon")[0].addEventListener("click", function () {
|
node.nextElementSibling.getElementsByClassName("summary-container-icon")[0].addEventListener("click", function () {
|
||||||
if (node.classList.contains("on")) {
|
if (node.classList.contains("on")) {
|
||||||
@ -40,5 +54,139 @@ for (const node of document.getElementsByClassName("summary-container")) {
|
|||||||
node.classList.add("on")
|
node.classList.add("on")
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
function openOrCloseFontSettings () {
|
||||||
|
if (fontSettingDiv.classList.contains(DROPDOWN_OPEN_CLASS)) {
|
||||||
|
fontSettingDiv.classList.remove(DROPDOWN_OPEN_CLASS);
|
||||||
|
} else {
|
||||||
|
fontSettingDiv.classList.add(DROPDOWN_OPEN_CLASS);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function getFontSize () {
|
||||||
|
return parseInt(
|
||||||
|
/ font-size-([0-9]+) /.exec(bookRoot.className)[1]
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
function setFontSize (size) {
|
||||||
|
if (size < 0) size = 0;
|
||||||
|
else if (size > 4) size = 4;
|
||||||
|
bookRoot.className = bookRoot.className.replace(/ font-size-[0-9]+ /, " font-size-"+size+" ");
|
||||||
|
setCookie("font-size", size);
|
||||||
|
}
|
||||||
|
|
||||||
|
function enlargeFontSize () {
|
||||||
|
setFontSize(getFontSize()+1);
|
||||||
|
}
|
||||||
|
|
||||||
|
function reduceFontSize () {
|
||||||
|
setFontSize(getFontSize()-1);
|
||||||
|
}
|
||||||
|
|
||||||
|
function setFontFamily (familyId) {
|
||||||
|
bookRoot.className = bookRoot.className.replace(/ font-family-[0-9]+ /, " font-family-"+familyId+" ");
|
||||||
|
setCookie("font-family", familyId);
|
||||||
|
}
|
||||||
|
|
||||||
|
function setFontFamilySerif () {
|
||||||
|
setFontFamily(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
function setFontFamilySans () {
|
||||||
|
setFontFamily(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
function setColorTheme (colorThemeId) {
|
||||||
|
bookRoot.className = bookRoot.className.replace(/ color-theme-[0-9]+ /, " color-theme-"+colorThemeId+" ");
|
||||||
|
setCookie("color-theme", colorThemeId);
|
||||||
|
}
|
||||||
|
|
||||||
|
function setColorThemeWhite () {
|
||||||
|
setColorTheme(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
function setColorThemeSepia () {
|
||||||
|
setColorTheme(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
function setColorThemeNight () {
|
||||||
|
setColorTheme(2);
|
||||||
|
}
|
||||||
|
|
||||||
|
function setCookie(name, value) {
|
||||||
|
const d = new Date()
|
||||||
|
d.setTime(d.getTime() + (30*24*60*60*1000));
|
||||||
|
const expires = "expires=" + d.toGMTString()
|
||||||
|
document.cookie = name + "=" + value + "; " + expires;
|
||||||
|
}
|
||||||
|
|
||||||
|
function updatePage (bookId, pageId = "") {
|
||||||
|
|
||||||
|
const isNavRefresh = bookId !== bookCurrentId;
|
||||||
|
const request = new XMLHttpRequest();
|
||||||
|
const url = (
|
||||||
|
"/" + bookId + "/" + pageId
|
||||||
|
);
|
||||||
|
const urlParam = (
|
||||||
|
"?raw=true" +
|
||||||
|
((isNavRefresh)?("&nav=true"):(""))
|
||||||
|
)
|
||||||
|
request.open("GET", url + urlParam, true);
|
||||||
|
console.log(url + urlParam);
|
||||||
|
request.onreadystatechange = function () {
|
||||||
|
if (request.readyState === 4 && request.status === 200) {
|
||||||
|
|
||||||
|
// data
|
||||||
|
const data = request.responseText.split("\n", 2);
|
||||||
|
const nav = isNavRefresh?data[0]:"";
|
||||||
|
const content = request.responseText.substr(nav.length);
|
||||||
|
console.log(nav);
|
||||||
|
console.log(content);
|
||||||
|
// content
|
||||||
|
pageContainer.innerHTML = content;
|
||||||
|
if (!isNavRefresh) document.getElementById("page/"+pageCurrentId).classList.remove("active");
|
||||||
|
if (!isNavRefresh) pageCurrentId = pageId;
|
||||||
|
if (!isNavRefresh) document.getElementById("page/"+pageId).classList.add("active");
|
||||||
|
// nav
|
||||||
|
if (isNavRefresh) {
|
||||||
|
inBookNavContainer.innerHTML = nav;
|
||||||
|
if (bookCurrentId !== "%root")
|
||||||
|
document.getElementById("book/"+bookCurrentId).classList.remove("active");
|
||||||
|
bookCurrentId = bookId;
|
||||||
|
pageCurrentId = inBookNavContainer.getElementsByClassName("active")[0].getAttribute("page-id");
|
||||||
|
document.getElementById("book/"+bookId).classList.add("active");
|
||||||
|
bindFolderClickEvent();
|
||||||
|
bindPageLinkClickEvent();
|
||||||
|
}
|
||||||
|
// history
|
||||||
|
window.history.pushState(document.documentElement.innerHTML, document.title, url);
|
||||||
|
pageContainer.classList.remove("loading");
|
||||||
|
// post-process
|
||||||
|
updateRef();
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
request.send();
|
||||||
|
pageContainer.classList.add("loading");
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function bindBookLinkClickEvent () {
|
||||||
|
for (let node of document.getElementsByClassName("link-book")) {
|
||||||
|
node.children[0].removeAttribute("href");
|
||||||
|
node.childNodes[0].addEventListener("click", function () {
|
||||||
|
updatePage(node.getAttribute("book-id"));
|
||||||
|
}, true);
|
||||||
|
}
|
||||||
|
} bindBookLinkClickEvent();
|
||||||
|
|
||||||
|
function bindPageLinkClickEvent () {
|
||||||
|
for (let node of document.getElementsByClassName("link-page")) {
|
||||||
|
node.children[0].removeAttribute("href");
|
||||||
|
node.childNodes[0].addEventListener("click", function () {
|
||||||
|
updatePage(bookCurrentId, node.getAttribute("page-id"));
|
||||||
|
}, true);
|
||||||
|
}
|
||||||
|
} bindPageLinkClickEvent();
|
||||||
|
6
assets/ref.css
Normal file
6
assets/ref.css
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
ref {
|
||||||
|
display: block;
|
||||||
|
border: 2px solid var(--color-graystyle);
|
||||||
|
padding: 1em 2em;
|
||||||
|
margin: 1.7em 0
|
||||||
|
}
|
15
assets/ref.js
Normal file
15
assets/ref.js
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
function updateRef () {
|
||||||
|
for (let node of document.getElementsByTagName("ref")) {
|
||||||
|
node.innerHTML = "...";
|
||||||
|
const request = new XMLHttpRequest();
|
||||||
|
request.open("GET", node.getAttribute("source"), true);
|
||||||
|
request.onreadystatechange = function () {
|
||||||
|
if (request.readyState === 4 && request.status === 200) {
|
||||||
|
node.innerHTML = marked(request.responseText);
|
||||||
|
} else if (request.readyState === 4) {
|
||||||
|
node.innerHTML = "ERROR "+ request.status;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
request.send();
|
||||||
|
}
|
||||||
|
} updateRef();
|
@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
const APP_NAME = "ph-Bookshelf";
|
const APP_NAME = "ph-Bookshelf";
|
||||||
|
|
||||||
const VERSION = "0.1";
|
const VERSION = "0.2";
|
||||||
const CHANNEL = "workshop-origin";
|
const CHANNEL = "workshop-origin";
|
||||||
const BRANCH = "release";
|
const BRANCH = "release";
|
||||||
|
|
||||||
|
38
index.php
38
index.php
@ -3,12 +3,12 @@
|
|||||||
|
|
||||||
require_once "./src/Data/SiteMeta.php";
|
require_once "./src/Data/SiteMeta.php";
|
||||||
require_once "./src/Data/PageMeta.php";
|
require_once "./src/Data/PageMeta.php";
|
||||||
require_once "./lib/Parsedown/Parsedown.php";
|
require_once "./src/Utils/ParsedownExtend.php";
|
||||||
require_once "./src/Utils/PageParse.php";
|
require_once "./src/Utils/PageParse.php";
|
||||||
require_once "./src/Utils/RequestNotExistException.php";
|
require_once "./src/Utils/RequestNotExistException.php";
|
||||||
require_once "./constant.php";
|
require_once "./constant.php";
|
||||||
|
|
||||||
$parser = new Parsedown();
|
$parser = new ParsedownExtend();
|
||||||
|
|
||||||
$parser->setMarkupEscaped(false);
|
$parser->setMarkupEscaped(false);
|
||||||
$parser->setSafeMode(false);
|
$parser->setSafeMode(false);
|
||||||
@ -17,6 +17,10 @@ try {
|
|||||||
|
|
||||||
SiteMeta::load();
|
SiteMeta::load();
|
||||||
|
|
||||||
|
// 检查是否为 ajax 请求
|
||||||
|
$rawContent = $_GET['raw']=="true";
|
||||||
|
$rawWithNav = $_GET['nav']=="true";
|
||||||
|
|
||||||
// 格式化所给链接,并将链接转化为路径字符串数组
|
// 格式化所给链接,并将链接转化为路径字符串数组
|
||||||
$req = $_GET['p'];
|
$req = $_GET['p'];
|
||||||
if (strlen($req) > 0 && $req[strlen($req) - 1] === '/')
|
if (strlen($req) > 0 && $req[strlen($req) - 1] === '/')
|
||||||
@ -66,6 +70,12 @@ try {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if ($rawContent && $rawWithNav) {
|
||||||
|
echo PageMeta::$book->getSummaryHtml() . "\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!$rawContent) :
|
||||||
|
|
||||||
require "./template/header.php";
|
require "./template/header.php";
|
||||||
|
|
||||||
?>
|
?>
|
||||||
@ -101,33 +111,34 @@ try {
|
|||||||
<!-- Title -->
|
<!-- Title -->
|
||||||
<a class="btn pull-left js-toolbar-action" aria-label="" href="#" onclick="summaryOnOrOff()"><i class="fa fa-align-justify"></i></a>
|
<a class="btn pull-left js-toolbar-action" aria-label="" href="#" onclick="summaryOnOrOff()"><i class="fa fa-align-justify"></i></a>
|
||||||
<div class="dropdown pull-left font-settings js-toolbar-action">
|
<div class="dropdown pull-left font-settings js-toolbar-action">
|
||||||
<a class="btn toggle-dropdown" aria-label="Font Settings" href="#"><i class="fa fa-font"></i></a>
|
<a class="btn toggle-dropdown" aria-label="Font Settings" onclick="openOrCloseFontSettings()"><i class="fa fa-font"></i></a>
|
||||||
<div class="dropdown-menu dropdown-right">
|
<div class="dropdown-menu dropdown-right">
|
||||||
<div class="dropdown-caret">
|
<div class="dropdown-caret">
|
||||||
<span class="caret-outer"></span>
|
<span class="caret-outer"></span>
|
||||||
<span class="caret-inner"></span>
|
<span class="caret-inner"></span>
|
||||||
</div>
|
</div>
|
||||||
<div class="buttons">
|
<div class="buttons">
|
||||||
<button class="button size-2 font-reduce">A</button>
|
<button class="button size-2 font-reduce" onclick="reduceFontSize()">A</button>
|
||||||
<button class="button size-2 font-enlarge">A</button>
|
<button class="button size-2 font-enlarge" onclick="enlargeFontSize()">A</button>
|
||||||
</div>
|
</div>
|
||||||
<div class="buttons">
|
<div class="buttons">
|
||||||
<button class="button size-2 ">Serif</button>
|
<button class="button size-2" onclick="setFontFamilySerif()">Serif</button>
|
||||||
<button class="button size-2 ">Sans</button>
|
<button class="button size-2" onclick="setFontFamilySans()">Sans</button>
|
||||||
</div><div class="buttons">
|
</div><div class="buttons">
|
||||||
<button class="button size-3 ">White</button>
|
<button class="button size-3" onclick="setColorThemeWhite()">White</button>
|
||||||
<button class="button size-3 ">Sepia</button>
|
<button class="button size-3" onclick="setColorThemeSepia()">Sepia</button>
|
||||||
<button class="button size-3 ">Night</button>
|
<button class="button size-3" onclick="setColorThemeNight()">Night</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<h1>
|
<h1>
|
||||||
<i class="fa fa-circle-o-notch fa-spin"></i>
|
<i class="fa fa-circle-o-notch fa-spin"></i>
|
||||||
<a><?= PageMeta::$book->getName() ?></a>
|
<a id="page-title"><?= PageMeta::$book->getName() ?></a>
|
||||||
</h1>
|
</h1>
|
||||||
</div>
|
</div>
|
||||||
<div class="page-wrapper" tabindex="-1" role="main">
|
<div class="page-wrapper" tabindex="-1" role="main">
|
||||||
<div class="page-inner">
|
<div id="page-container" class="page-inner">
|
||||||
|
<?php endif; ?>
|
||||||
<div id="book-search-results">
|
<div id="book-search-results">
|
||||||
<div class="search-noresults">
|
<div class="search-noresults">
|
||||||
<section class="normal markdown-section">
|
<section class="normal markdown-section">
|
||||||
@ -136,6 +147,7 @@ try {
|
|||||||
</section>
|
</section>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
<?php if (!$rawContent) : ?>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@ -145,6 +157,8 @@ try {
|
|||||||
|
|
||||||
require "./template/footer.php";
|
require "./template/footer.php";
|
||||||
|
|
||||||
|
endif;
|
||||||
|
|
||||||
} catch (Exception $e) {
|
} catch (Exception $e) {
|
||||||
|
|
||||||
echo "<h1>ERROR</h1><p>" . $e->getMessage() . "</p>";
|
echo "<h1>ERROR</h1><p>" . $e->getMessage() . "</p>";
|
||||||
|
686
lib/Parsedown/ParsedownExtra.php
Normal file
686
lib/Parsedown/ParsedownExtra.php
Normal file
@ -0,0 +1,686 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
#
|
||||||
|
#
|
||||||
|
# Parsedown Extra
|
||||||
|
# https://github.com/erusev/parsedown-extra
|
||||||
|
#
|
||||||
|
# (c) Emanuil Rusev
|
||||||
|
# http://erusev.com
|
||||||
|
#
|
||||||
|
# For the full license information, view the LICENSE file that was distributed
|
||||||
|
# with this source code.
|
||||||
|
#
|
||||||
|
#
|
||||||
|
|
||||||
|
class ParsedownExtra extends Parsedown
|
||||||
|
{
|
||||||
|
# ~
|
||||||
|
|
||||||
|
const version = '0.8.0';
|
||||||
|
|
||||||
|
# ~
|
||||||
|
|
||||||
|
function __construct()
|
||||||
|
{
|
||||||
|
if (version_compare(parent::version, '1.7.1') < 0)
|
||||||
|
{
|
||||||
|
throw new Exception('ParsedownExtra requires a later version of Parsedown');
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->BlockTypes[':'] []= 'DefinitionList';
|
||||||
|
$this->BlockTypes['*'] []= 'Abbreviation';
|
||||||
|
|
||||||
|
# identify footnote definitions before reference definitions
|
||||||
|
array_unshift($this->BlockTypes['['], 'Footnote');
|
||||||
|
|
||||||
|
# identify footnote markers before before links
|
||||||
|
array_unshift($this->InlineTypes['['], 'FootnoteMarker');
|
||||||
|
}
|
||||||
|
|
||||||
|
#
|
||||||
|
# ~
|
||||||
|
|
||||||
|
function text($text)
|
||||||
|
{
|
||||||
|
$Elements = $this->textElements($text);
|
||||||
|
|
||||||
|
# convert to markup
|
||||||
|
$markup = $this->elements($Elements);
|
||||||
|
|
||||||
|
# trim line breaks
|
||||||
|
$markup = trim($markup, "\n");
|
||||||
|
|
||||||
|
# merge consecutive dl elements
|
||||||
|
|
||||||
|
$markup = preg_replace('/<\/dl>\s+<dl>\s+/', '', $markup);
|
||||||
|
|
||||||
|
# add footnotes
|
||||||
|
|
||||||
|
if (isset($this->DefinitionData['Footnote']))
|
||||||
|
{
|
||||||
|
$Element = $this->buildFootnoteElement();
|
||||||
|
|
||||||
|
$markup .= "\n" . $this->element($Element);
|
||||||
|
}
|
||||||
|
|
||||||
|
return $markup;
|
||||||
|
}
|
||||||
|
|
||||||
|
#
|
||||||
|
# Blocks
|
||||||
|
#
|
||||||
|
|
||||||
|
#
|
||||||
|
# Abbreviation
|
||||||
|
|
||||||
|
protected function blockAbbreviation($Line)
|
||||||
|
{
|
||||||
|
if (preg_match('/^\*\[(.+?)\]:[ ]*(.+?)[ ]*$/', $Line['text'], $matches))
|
||||||
|
{
|
||||||
|
$this->DefinitionData['Abbreviation'][$matches[1]] = $matches[2];
|
||||||
|
|
||||||
|
$Block = array(
|
||||||
|
'hidden' => true,
|
||||||
|
);
|
||||||
|
|
||||||
|
return $Block;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#
|
||||||
|
# Footnote
|
||||||
|
|
||||||
|
protected function blockFootnote($Line)
|
||||||
|
{
|
||||||
|
if (preg_match('/^\[\^(.+?)\]:[ ]?(.*)$/', $Line['text'], $matches))
|
||||||
|
{
|
||||||
|
$Block = array(
|
||||||
|
'label' => $matches[1],
|
||||||
|
'text' => $matches[2],
|
||||||
|
'hidden' => true,
|
||||||
|
);
|
||||||
|
|
||||||
|
return $Block;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function blockFootnoteContinue($Line, $Block)
|
||||||
|
{
|
||||||
|
if ($Line['text'][0] === '[' and preg_match('/^\[\^(.+?)\]:/', $Line['text']))
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isset($Block['interrupted']))
|
||||||
|
{
|
||||||
|
if ($Line['indent'] >= 4)
|
||||||
|
{
|
||||||
|
$Block['text'] .= "\n\n" . $Line['text'];
|
||||||
|
|
||||||
|
return $Block;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
$Block['text'] .= "\n" . $Line['text'];
|
||||||
|
|
||||||
|
return $Block;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function blockFootnoteComplete($Block)
|
||||||
|
{
|
||||||
|
$this->DefinitionData['Footnote'][$Block['label']] = array(
|
||||||
|
'text' => $Block['text'],
|
||||||
|
'count' => null,
|
||||||
|
'number' => null,
|
||||||
|
);
|
||||||
|
|
||||||
|
return $Block;
|
||||||
|
}
|
||||||
|
|
||||||
|
#
|
||||||
|
# Definition List
|
||||||
|
|
||||||
|
protected function blockDefinitionList($Line, $Block)
|
||||||
|
{
|
||||||
|
if ( ! isset($Block) or $Block['type'] !== 'Paragraph')
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
$Element = array(
|
||||||
|
'name' => 'dl',
|
||||||
|
'elements' => array(),
|
||||||
|
);
|
||||||
|
|
||||||
|
$terms = explode("\n", $Block['element']['handler']['argument']);
|
||||||
|
|
||||||
|
foreach ($terms as $term)
|
||||||
|
{
|
||||||
|
$Element['elements'] []= array(
|
||||||
|
'name' => 'dt',
|
||||||
|
'handler' => array(
|
||||||
|
'function' => 'lineElements',
|
||||||
|
'argument' => $term,
|
||||||
|
'destination' => 'elements'
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
$Block['element'] = $Element;
|
||||||
|
|
||||||
|
$Block = $this->addDdElement($Line, $Block);
|
||||||
|
|
||||||
|
return $Block;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function blockDefinitionListContinue($Line, array $Block)
|
||||||
|
{
|
||||||
|
if ($Line['text'][0] === ':')
|
||||||
|
{
|
||||||
|
$Block = $this->addDdElement($Line, $Block);
|
||||||
|
|
||||||
|
return $Block;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (isset($Block['interrupted']) and $Line['indent'] === 0)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isset($Block['interrupted']))
|
||||||
|
{
|
||||||
|
$Block['dd']['handler']['function'] = 'textElements';
|
||||||
|
$Block['dd']['handler']['argument'] .= "\n\n";
|
||||||
|
|
||||||
|
$Block['dd']['handler']['destination'] = 'elements';
|
||||||
|
|
||||||
|
unset($Block['interrupted']);
|
||||||
|
}
|
||||||
|
|
||||||
|
$text = substr($Line['body'], min($Line['indent'], 4));
|
||||||
|
|
||||||
|
$Block['dd']['handler']['argument'] .= "\n" . $text;
|
||||||
|
|
||||||
|
return $Block;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#
|
||||||
|
# Header
|
||||||
|
|
||||||
|
protected function blockHeader($Line)
|
||||||
|
{
|
||||||
|
$Block = parent::blockHeader($Line);
|
||||||
|
|
||||||
|
if ($Block !== null && preg_match('/[ #]*{('.$this->regexAttribute.'+)}[ ]*$/', $Block['element']['handler']['argument'], $matches, PREG_OFFSET_CAPTURE))
|
||||||
|
{
|
||||||
|
$attributeString = $matches[1][0];
|
||||||
|
|
||||||
|
$Block['element']['attributes'] = $this->parseAttributeData($attributeString);
|
||||||
|
|
||||||
|
$Block['element']['handler']['argument'] = substr($Block['element']['handler']['argument'], 0, $matches[0][1]);
|
||||||
|
}
|
||||||
|
|
||||||
|
return $Block;
|
||||||
|
}
|
||||||
|
|
||||||
|
#
|
||||||
|
# Markup
|
||||||
|
|
||||||
|
protected function blockMarkup($Line)
|
||||||
|
{
|
||||||
|
if ($this->markupEscaped or $this->safeMode)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (preg_match('/^<(\w[\w-]*)(?:[ ]*'.$this->regexHtmlAttribute.')*[ ]*(\/)?>/', $Line['text'], $matches))
|
||||||
|
{
|
||||||
|
$element = strtolower($matches[1]);
|
||||||
|
|
||||||
|
if (in_array($element, $this->textLevelElements))
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
$Block = array(
|
||||||
|
'name' => $matches[1],
|
||||||
|
'depth' => 0,
|
||||||
|
'element' => array(
|
||||||
|
'rawHtml' => $Line['text'],
|
||||||
|
'autobreak' => true,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
|
||||||
|
$length = strlen($matches[0]);
|
||||||
|
$remainder = substr($Line['text'], $length);
|
||||||
|
|
||||||
|
if (trim($remainder) === '')
|
||||||
|
{
|
||||||
|
if (isset($matches[2]) or in_array($matches[1], $this->voidElements))
|
||||||
|
{
|
||||||
|
$Block['closed'] = true;
|
||||||
|
$Block['void'] = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (isset($matches[2]) or in_array($matches[1], $this->voidElements))
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (preg_match('/<\/'.$matches[1].'>[ ]*$/i', $remainder))
|
||||||
|
{
|
||||||
|
$Block['closed'] = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return $Block;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function blockMarkupContinue($Line, array $Block)
|
||||||
|
{
|
||||||
|
if (isset($Block['closed']))
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (preg_match('/^<'.$Block['name'].'(?:[ ]*'.$this->regexHtmlAttribute.')*[ ]*>/i', $Line['text'])) # open
|
||||||
|
{
|
||||||
|
$Block['depth'] ++;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (preg_match('/(.*?)<\/'.$Block['name'].'>[ ]*$/i', $Line['text'], $matches)) # close
|
||||||
|
{
|
||||||
|
if ($Block['depth'] > 0)
|
||||||
|
{
|
||||||
|
$Block['depth'] --;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
$Block['closed'] = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isset($Block['interrupted']))
|
||||||
|
{
|
||||||
|
$Block['element']['rawHtml'] .= "\n";
|
||||||
|
unset($Block['interrupted']);
|
||||||
|
}
|
||||||
|
|
||||||
|
$Block['element']['rawHtml'] .= "\n".$Line['body'];
|
||||||
|
|
||||||
|
return $Block;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function blockMarkupComplete($Block)
|
||||||
|
{
|
||||||
|
if ( ! isset($Block['void']))
|
||||||
|
{
|
||||||
|
$Block['element']['rawHtml'] = $this->processTag($Block['element']['rawHtml']);
|
||||||
|
}
|
||||||
|
|
||||||
|
return $Block;
|
||||||
|
}
|
||||||
|
|
||||||
|
#
|
||||||
|
# Setext
|
||||||
|
|
||||||
|
protected function blockSetextHeader($Line, array $Block = null)
|
||||||
|
{
|
||||||
|
$Block = parent::blockSetextHeader($Line, $Block);
|
||||||
|
|
||||||
|
if ($Block !== null && preg_match('/[ ]*{('.$this->regexAttribute.'+)}[ ]*$/', $Block['element']['handler']['argument'], $matches, PREG_OFFSET_CAPTURE))
|
||||||
|
{
|
||||||
|
$attributeString = $matches[1][0];
|
||||||
|
|
||||||
|
$Block['element']['attributes'] = $this->parseAttributeData($attributeString);
|
||||||
|
|
||||||
|
$Block['element']['handler']['argument'] = substr($Block['element']['handler']['argument'], 0, $matches[0][1]);
|
||||||
|
}
|
||||||
|
|
||||||
|
return $Block;
|
||||||
|
}
|
||||||
|
|
||||||
|
#
|
||||||
|
# Inline Elements
|
||||||
|
#
|
||||||
|
|
||||||
|
#
|
||||||
|
# Footnote Marker
|
||||||
|
|
||||||
|
protected function inlineFootnoteMarker($Excerpt)
|
||||||
|
{
|
||||||
|
if (preg_match('/^\[\^(.+?)\]/', $Excerpt['text'], $matches))
|
||||||
|
{
|
||||||
|
$name = $matches[1];
|
||||||
|
|
||||||
|
if ( ! isset($this->DefinitionData['Footnote'][$name]))
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->DefinitionData['Footnote'][$name]['count'] ++;
|
||||||
|
|
||||||
|
if ( ! isset($this->DefinitionData['Footnote'][$name]['number']))
|
||||||
|
{
|
||||||
|
$this->DefinitionData['Footnote'][$name]['number'] = ++ $this->footnoteCount; # » &
|
||||||
|
}
|
||||||
|
|
||||||
|
$Element = array(
|
||||||
|
'name' => 'sup',
|
||||||
|
'attributes' => array('id' => 'fnref'.$this->DefinitionData['Footnote'][$name]['count'].':'.$name),
|
||||||
|
'element' => array(
|
||||||
|
'name' => 'a',
|
||||||
|
'attributes' => array('href' => '#fn:'.$name, 'class' => 'footnote-ref'),
|
||||||
|
'text' => $this->DefinitionData['Footnote'][$name]['number'],
|
||||||
|
),
|
||||||
|
);
|
||||||
|
|
||||||
|
return array(
|
||||||
|
'extent' => strlen($matches[0]),
|
||||||
|
'element' => $Element,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private $footnoteCount = 0;
|
||||||
|
|
||||||
|
#
|
||||||
|
# Link
|
||||||
|
|
||||||
|
protected function inlineLink($Excerpt)
|
||||||
|
{
|
||||||
|
$Link = parent::inlineLink($Excerpt);
|
||||||
|
|
||||||
|
$remainder = $Link !== null ? substr($Excerpt['text'], $Link['extent']) : '';
|
||||||
|
|
||||||
|
if (preg_match('/^[ ]*{('.$this->regexAttribute.'+)}/', $remainder, $matches))
|
||||||
|
{
|
||||||
|
$Link['element']['attributes'] += $this->parseAttributeData($matches[1]);
|
||||||
|
|
||||||
|
$Link['extent'] += strlen($matches[0]);
|
||||||
|
}
|
||||||
|
|
||||||
|
return $Link;
|
||||||
|
}
|
||||||
|
|
||||||
|
#
|
||||||
|
# ~
|
||||||
|
#
|
||||||
|
|
||||||
|
private $currentAbreviation;
|
||||||
|
private $currentMeaning;
|
||||||
|
|
||||||
|
protected function insertAbreviation(array $Element)
|
||||||
|
{
|
||||||
|
if (isset($Element['text']))
|
||||||
|
{
|
||||||
|
$Element['elements'] = self::pregReplaceElements(
|
||||||
|
'/\b'.preg_quote($this->currentAbreviation, '/').'\b/',
|
||||||
|
array(
|
||||||
|
array(
|
||||||
|
'name' => 'abbr',
|
||||||
|
'attributes' => array(
|
||||||
|
'title' => $this->currentMeaning,
|
||||||
|
),
|
||||||
|
'text' => $this->currentAbreviation,
|
||||||
|
)
|
||||||
|
),
|
||||||
|
$Element['text']
|
||||||
|
);
|
||||||
|
|
||||||
|
unset($Element['text']);
|
||||||
|
}
|
||||||
|
|
||||||
|
return $Element;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function inlineText($text)
|
||||||
|
{
|
||||||
|
$Inline = parent::inlineText($text);
|
||||||
|
|
||||||
|
if (isset($this->DefinitionData['Abbreviation']))
|
||||||
|
{
|
||||||
|
foreach ($this->DefinitionData['Abbreviation'] as $abbreviation => $meaning)
|
||||||
|
{
|
||||||
|
$this->currentAbreviation = $abbreviation;
|
||||||
|
$this->currentMeaning = $meaning;
|
||||||
|
|
||||||
|
$Inline['element'] = $this->elementApplyRecursiveDepthFirst(
|
||||||
|
array($this, 'insertAbreviation'),
|
||||||
|
$Inline['element']
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return $Inline;
|
||||||
|
}
|
||||||
|
|
||||||
|
#
|
||||||
|
# Util Methods
|
||||||
|
#
|
||||||
|
|
||||||
|
protected function addDdElement(array $Line, array $Block)
|
||||||
|
{
|
||||||
|
$text = substr($Line['text'], 1);
|
||||||
|
$text = trim($text);
|
||||||
|
|
||||||
|
unset($Block['dd']);
|
||||||
|
|
||||||
|
$Block['dd'] = array(
|
||||||
|
'name' => 'dd',
|
||||||
|
'handler' => array(
|
||||||
|
'function' => 'lineElements',
|
||||||
|
'argument' => $text,
|
||||||
|
'destination' => 'elements'
|
||||||
|
),
|
||||||
|
);
|
||||||
|
|
||||||
|
if (isset($Block['interrupted']))
|
||||||
|
{
|
||||||
|
$Block['dd']['handler']['function'] = 'textElements';
|
||||||
|
|
||||||
|
unset($Block['interrupted']);
|
||||||
|
}
|
||||||
|
|
||||||
|
$Block['element']['elements'] []= & $Block['dd'];
|
||||||
|
|
||||||
|
return $Block;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function buildFootnoteElement()
|
||||||
|
{
|
||||||
|
$Element = array(
|
||||||
|
'name' => 'div',
|
||||||
|
'attributes' => array('class' => 'footnotes'),
|
||||||
|
'elements' => array(
|
||||||
|
array('name' => 'hr'),
|
||||||
|
array(
|
||||||
|
'name' => 'ol',
|
||||||
|
'elements' => array(),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
|
||||||
|
uasort($this->DefinitionData['Footnote'], 'self::sortFootnotes');
|
||||||
|
|
||||||
|
foreach ($this->DefinitionData['Footnote'] as $definitionId => $DefinitionData)
|
||||||
|
{
|
||||||
|
if ( ! isset($DefinitionData['number']))
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
$text = $DefinitionData['text'];
|
||||||
|
|
||||||
|
$textElements = parent::textElements($text);
|
||||||
|
|
||||||
|
$numbers = range(1, $DefinitionData['count']);
|
||||||
|
|
||||||
|
$backLinkElements = array();
|
||||||
|
|
||||||
|
foreach ($numbers as $number)
|
||||||
|
{
|
||||||
|
$backLinkElements[] = array('text' => ' ');
|
||||||
|
$backLinkElements[] = array(
|
||||||
|
'name' => 'a',
|
||||||
|
'attributes' => array(
|
||||||
|
'href' => "#fnref$number:$definitionId",
|
||||||
|
'rev' => 'footnote',
|
||||||
|
'class' => 'footnote-backref',
|
||||||
|
),
|
||||||
|
'rawHtml' => '↩',
|
||||||
|
'allowRawHtmlInSafeMode' => true,
|
||||||
|
'autobreak' => false,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
unset($backLinkElements[0]);
|
||||||
|
|
||||||
|
$n = count($textElements) -1;
|
||||||
|
|
||||||
|
if ($textElements[$n]['name'] === 'p')
|
||||||
|
{
|
||||||
|
$backLinkElements = array_merge(
|
||||||
|
array(
|
||||||
|
array(
|
||||||
|
'rawHtml' => ' ',
|
||||||
|
'allowRawHtmlInSafeMode' => true,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
$backLinkElements
|
||||||
|
);
|
||||||
|
|
||||||
|
unset($textElements[$n]['name']);
|
||||||
|
|
||||||
|
$textElements[$n] = array(
|
||||||
|
'name' => 'p',
|
||||||
|
'elements' => array_merge(
|
||||||
|
array($textElements[$n]),
|
||||||
|
$backLinkElements
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
$textElements[] = array(
|
||||||
|
'name' => 'p',
|
||||||
|
'elements' => $backLinkElements
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
$Element['elements'][1]['elements'] []= array(
|
||||||
|
'name' => 'li',
|
||||||
|
'attributes' => array('id' => 'fn:'.$definitionId),
|
||||||
|
'elements' => array_merge(
|
||||||
|
$textElements
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return $Element;
|
||||||
|
}
|
||||||
|
|
||||||
|
# ~
|
||||||
|
|
||||||
|
protected function parseAttributeData($attributeString)
|
||||||
|
{
|
||||||
|
$Data = array();
|
||||||
|
|
||||||
|
$attributes = preg_split('/[ ]+/', $attributeString, - 1, PREG_SPLIT_NO_EMPTY);
|
||||||
|
|
||||||
|
foreach ($attributes as $attribute)
|
||||||
|
{
|
||||||
|
if ($attribute[0] === '#')
|
||||||
|
{
|
||||||
|
$Data['id'] = substr($attribute, 1);
|
||||||
|
}
|
||||||
|
else # "."
|
||||||
|
{
|
||||||
|
$classes []= substr($attribute, 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isset($classes))
|
||||||
|
{
|
||||||
|
$Data['class'] = implode(' ', $classes);
|
||||||
|
}
|
||||||
|
|
||||||
|
return $Data;
|
||||||
|
}
|
||||||
|
|
||||||
|
# ~
|
||||||
|
|
||||||
|
protected function processTag($elementMarkup) # recursive
|
||||||
|
{
|
||||||
|
# http://stackoverflow.com/q/1148928/200145
|
||||||
|
libxml_use_internal_errors(true);
|
||||||
|
|
||||||
|
$DOMDocument = new DOMDocument;
|
||||||
|
|
||||||
|
# http://stackoverflow.com/q/11309194/200145
|
||||||
|
$elementMarkup = mb_convert_encoding($elementMarkup, 'HTML-ENTITIES', 'UTF-8');
|
||||||
|
|
||||||
|
# http://stackoverflow.com/q/4879946/200145
|
||||||
|
$DOMDocument->loadHTML($elementMarkup);
|
||||||
|
$DOMDocument->removeChild($DOMDocument->doctype);
|
||||||
|
$DOMDocument->replaceChild($DOMDocument->firstChild->firstChild->firstChild, $DOMDocument->firstChild);
|
||||||
|
|
||||||
|
$elementText = '';
|
||||||
|
|
||||||
|
if ($DOMDocument->documentElement->getAttribute('markdown') === '1')
|
||||||
|
{
|
||||||
|
foreach ($DOMDocument->documentElement->childNodes as $Node)
|
||||||
|
{
|
||||||
|
$elementText .= $DOMDocument->saveHTML($Node);
|
||||||
|
}
|
||||||
|
|
||||||
|
$DOMDocument->documentElement->removeAttribute('markdown');
|
||||||
|
|
||||||
|
$elementText = "\n".$this->text($elementText)."\n";
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
foreach ($DOMDocument->documentElement->childNodes as $Node)
|
||||||
|
{
|
||||||
|
$nodeMarkup = $DOMDocument->saveHTML($Node);
|
||||||
|
|
||||||
|
if ($Node instanceof DOMElement and ! in_array($Node->nodeName, $this->textLevelElements))
|
||||||
|
{
|
||||||
|
$elementText .= $this->processTag($nodeMarkup);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
$elementText .= $nodeMarkup;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
# because we don't want for markup to get encoded
|
||||||
|
$DOMDocument->documentElement->nodeValue = 'placeholder\x1A';
|
||||||
|
|
||||||
|
$markup = $DOMDocument->saveHTML($DOMDocument->documentElement);
|
||||||
|
$markup = str_replace('placeholder\x1A', $elementText, $markup);
|
||||||
|
|
||||||
|
return $markup;
|
||||||
|
}
|
||||||
|
|
||||||
|
# ~
|
||||||
|
|
||||||
|
protected function sortFootnotes($A, $B) # callback
|
||||||
|
{
|
||||||
|
return $A['number'] - $B['number'];
|
||||||
|
}
|
||||||
|
|
||||||
|
#
|
||||||
|
# Fields
|
||||||
|
#
|
||||||
|
|
||||||
|
protected $regexAttribute = '(?:[#.][-\w]+[ ]*)';
|
||||||
|
}
|
@ -29,7 +29,9 @@ class SiteMeta {
|
|||||||
public static function getGitbookStylesheetsList (): array {
|
public static function getGitbookStylesheetsList (): array {
|
||||||
return array(
|
return array(
|
||||||
"/assets/gitbook/style.css",
|
"/assets/gitbook/style.css",
|
||||||
|
"/assets/gitbook/gitbook-plugin-fontsettings/website.css",
|
||||||
"/assets/gitbook-fix.css",
|
"/assets/gitbook-fix.css",
|
||||||
|
"/assets/ref.css",
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -37,6 +39,8 @@ class SiteMeta {
|
|||||||
return array(
|
return array(
|
||||||
"/assets/gitbook/gitbook.js",
|
"/assets/gitbook/gitbook.js",
|
||||||
"/assets/gitbook-fix.js",
|
"/assets/gitbook-fix.js",
|
||||||
|
"https://cdn.jsdelivr.net/npm/marked/marked.min.js",
|
||||||
|
"/assets/ref.js",
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -48,4 +52,11 @@ class SiteMeta {
|
|||||||
return file_get_contents("./data/$id.js");
|
return file_get_contents("./data/$id.js");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static function getUserThemes (): string {
|
||||||
|
$fontSize = $_COOKIE['font-size'] ?? 2;
|
||||||
|
$fontFamily = $_COOKIE['font-family'] ?? 1;
|
||||||
|
$colorTheme = $_COOKIE['color-theme'] ?? 0;
|
||||||
|
return "font-size-$fontSize font-family-$fontFamily color-theme-$colorTheme";
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -54,7 +54,7 @@ class Book {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public function getHtml (): string {
|
public function getHtml (): string {
|
||||||
return "<li class='link" . (PageMeta::$book->getId()==$this->id?" active":"") . "'><a class='link' " . (PageMeta::$book->getId()==$this->id?"":" href='/$this->id'") . ">$this->name</a></li>";
|
return "<li id='book/$this->id' book-id='$this->id' class='link link-book" . (PageMeta::$book->getId()==$this->id?" active":"") . "'><a class='link' " . (PageMeta::$book->getId()==$this->id?"":" href='/$this->id'") . ">$this->name</a></li>";
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -64,7 +64,7 @@ class BookContented {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public function getSummaryHtml (): string {
|
public function getSummaryHtml (): string {
|
||||||
return $this->childs->getSummaryHtml();
|
return "<div id='in-book-nav-container'>" . $this->childs->getSummaryHtml() . "</div>";
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getPage (string $id): ?Page {
|
public function getPage (string $id): ?Page {
|
||||||
|
@ -73,7 +73,7 @@ class Page {
|
|||||||
|
|
||||||
public function getSummaryHtml (): string {
|
public function getSummaryHtml (): string {
|
||||||
$str =
|
$str =
|
||||||
"<li class='page-contented chapter" .
|
"<li id='page/$this->id' page-id='$this->id' class='page-contented chapter link-page " .
|
||||||
(PageMeta::$page->getId()==$this->id?" active":"") .
|
(PageMeta::$page->getId()==$this->id?" active":"") .
|
||||||
"'><a class='page-contented' " .
|
"'><a class='page-contented' " .
|
||||||
(
|
(
|
||||||
|
32
src/Utils/ParsedownExtend.php
Normal file
32
src/Utils/ParsedownExtend.php
Normal file
@ -0,0 +1,32 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
require_once "./lib/Parsedown/Parsedown.php";
|
||||||
|
require_once "./lib/Parsedown/ParsedownExtra.php";
|
||||||
|
|
||||||
|
class ParsedownExtend extends ParsedownExtra {
|
||||||
|
|
||||||
|
function __construct() {
|
||||||
|
|
||||||
|
$this->InlineTypes['$'][] = 'RefMarkdown';
|
||||||
|
|
||||||
|
$this->inlineMarkerList .= '$';
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function inlineRefMarkdown ($excerpt) {
|
||||||
|
if (preg_match('/^\$\(([\S ]*?)\)/', $excerpt['text'], $matches)) {
|
||||||
|
return array(
|
||||||
|
'extent' => strlen($matches[0]),
|
||||||
|
'element' => array(
|
||||||
|
'name' => 'ref',
|
||||||
|
'text' => '',
|
||||||
|
'attributes' => array(
|
||||||
|
'source' => $matches[1],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -11,7 +11,11 @@
|
|||||||
}
|
}
|
||||||
?>
|
?>
|
||||||
<script><?= SiteMeta::getCustomScriptContent("custom") ?></script>
|
<script><?= SiteMeta::getCustomScriptContent("custom") ?></script>
|
||||||
|
<script>
|
||||||
|
bookCurrentId = "<?= PageMeta::$book->getId() ?>";
|
||||||
|
pageCurrentId = "<?= PageMeta::$page->getId() ?>";
|
||||||
|
</script>
|
||||||
|
|
||||||
</body>
|
</body>
|
||||||
|
|
||||||
</html>
|
</html>
|
||||||
|
@ -27,5 +27,5 @@
|
|||||||
<style><?= SiteMeta::getCustomCssContent("custom") ?></style>
|
<style><?= SiteMeta::getCustomCssContent("custom") ?></style>
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<div class="book">
|
<div class="book <?= SiteMeta::getUserThemes() ?>">
|
||||||
|
|
Loading…
Reference in New Issue
Block a user