diff --git a/.gitattributes b/.gitattributes
index fcadb2c..da1a09e 100644
--- a/.gitattributes
+++ b/.gitattributes
@@ -1 +1,7 @@
+* text=auto
* text eol=lf
+*.png binary
+*.otf binary
+*.ttf binary
+*.woff binary
+*.woff2 binary
diff --git a/assets/gitbook-fix.css b/assets/gitbook-fix.css
index 5b3922f..4559aba 100644
--- a/assets/gitbook-fix.css
+++ b/assets/gitbook-fix.css
@@ -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 {
max-height: 0;
@@ -54,8 +74,8 @@
top: 1px;
right: 20px;
padding: 0 5px 2px;
- background: rgba(0,0,0,.07);
- color: white;
+ background: var(--color-graystyle-background);
+ color: var(--color-icon-in-background);
border-bottom: 0;
border-radius: 0 0 5px 5px;
z-index: 1000;
@@ -72,9 +92,21 @@
.book .book-summary ul.summary li span.annotation {
padding: 0;
font-size: 0.2em;
- color: rgba(0, 0, 0, 0.2);
+ color: var(--color-graystyle);
}
.book .book-summary ul.summary li span.annotation:hover {
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;
+}
diff --git a/assets/gitbook-fix.js b/assets/gitbook-fix.js
index f7aa339..6f0bc45 100644
--- a/assets/gitbook-fix.js
+++ b/assets/gitbook-fix.js
@@ -1,6 +1,15 @@
const WITH_SUMMARY_CLASS = "with-summary"
+const DROPDOWN_OPEN_CLASS = "open";
+
let bookRoot;
+let pageContainer;
+let inBookNavContainer;
+
+let fontSettingDiv;
+
+let bookCurrentId;
+let pageCurrentId;
function summaryOnOrOff () {
@@ -15,6 +24,10 @@ function summaryOnOrOff () {
window.onload = function () {
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) {
bookRoot.classList.add(WITH_SUMMARY_CLASS);
@@ -22,16 +35,17 @@ window.onload = function () {
};
-for (let node of document.getElementsByClassName("fold")) {
- node.childNodes[0].addEventListener("click", function () {
- if (node.classList.contains("on")) {
- node.classList.remove("on");
- } else node.classList.add("on");
- });
-}
+function bindFolderClickEvent () {
+ for (let node of document.getElementsByClassName("fold")) {
+ node.childNodes[0].addEventListener("click", function () {
+ if (node.classList.contains("on")) {
+ node.classList.remove("on");
+ } else node.classList.add("on");
+ });
+ }
+} bindFolderClickEvent();
for (const node of document.getElementsByClassName("summary-container")) {
-
node.nextElementSibling.innerHTML = node.nextElementSibling.innerHTML + "";
node.nextElementSibling.getElementsByClassName("summary-container-icon")[0].addEventListener("click", function () {
if (node.classList.contains("on")) {
@@ -40,5 +54,139 @@ for (const node of document.getElementsByClassName("summary-container")) {
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();
diff --git a/assets/ref.css b/assets/ref.css
new file mode 100644
index 0000000..9b6ac88
--- /dev/null
+++ b/assets/ref.css
@@ -0,0 +1,6 @@
+ref {
+ display: block;
+ border: 2px solid var(--color-graystyle);
+ padding: 1em 2em;
+ margin: 1.7em 0
+}
\ No newline at end of file
diff --git a/assets/ref.js b/assets/ref.js
new file mode 100644
index 0000000..1e063ca
--- /dev/null
+++ b/assets/ref.js
@@ -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();
diff --git a/constant.php b/constant.php
index 083e9c7..3db37cd 100644
--- a/constant.php
+++ b/constant.php
@@ -2,7 +2,7 @@
const APP_NAME = "ph-Bookshelf";
-const VERSION = "0.1";
+const VERSION = "0.2";
const CHANNEL = "workshop-origin";
const BRANCH = "release";
diff --git a/index.php b/index.php
index 780e3d1..72b258b 100644
--- a/index.php
+++ b/index.php
@@ -3,12 +3,12 @@
require_once "./src/Data/SiteMeta.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/RequestNotExistException.php";
require_once "./constant.php";
-$parser = new Parsedown();
+$parser = new ParsedownExtend();
$parser->setMarkupEscaped(false);
$parser->setSafeMode(false);
@@ -17,6 +17,10 @@ try {
SiteMeta::load();
+ // 检查是否为 ajax 请求
+ $rawContent = $_GET['raw']=="true";
+ $rawWithNav = $_GET['nav']=="true";
+
// 格式化所给链接,并将链接转化为路径字符串数组
$req = $_GET['p'];
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";
?>
@@ -101,33 +111,34 @@ try {
-
+
+
@@ -136,6 +147,7 @@ try {
+
@@ -145,6 +157,8 @@ try {
require "./template/footer.php";
+ endif;
+
} catch (Exception $e) {
echo "ERROR
" . $e->getMessage() . "
";
diff --git a/lib/Parsedown/ParsedownExtra.php b/lib/Parsedown/ParsedownExtra.php
new file mode 100644
index 0000000..1592ad2
--- /dev/null
+++ b/lib/Parsedown/ParsedownExtra.php
@@ -0,0 +1,686 @@
+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+\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]+[ ]*)';
+}
\ No newline at end of file
diff --git a/src/Data/SiteMeta.php b/src/Data/SiteMeta.php
index de6d135..6f27882 100644
--- a/src/Data/SiteMeta.php
+++ b/src/Data/SiteMeta.php
@@ -29,7 +29,9 @@ class SiteMeta {
public static function getGitbookStylesheetsList (): array {
return array(
"/assets/gitbook/style.css",
+ "/assets/gitbook/gitbook-plugin-fontsettings/website.css",
"/assets/gitbook-fix.css",
+ "/assets/ref.css",
);
}
@@ -37,6 +39,8 @@ class SiteMeta {
return array(
"/assets/gitbook/gitbook.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");
}
+ 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";
+ }
+
}
diff --git a/src/Element/Book.php b/src/Element/Book.php
index 8601f76..65c5f25 100644
--- a/src/Element/Book.php
+++ b/src/Element/Book.php
@@ -54,7 +54,7 @@ class Book {
}
public function getHtml (): string {
- return "
getId()==$this->id?"":" href='/$this->id'") . ">$this->name";
+ return "getId()==$this->id?"":" href='/$this->id'") . ">$this->name";
}
/**
diff --git a/src/Element/BookContent/BookContented.php b/src/Element/BookContent/BookContented.php
index 6a3383b..187cf45 100644
--- a/src/Element/BookContent/BookContented.php
+++ b/src/Element/BookContent/BookContented.php
@@ -64,7 +64,7 @@ class BookContented {
}
public function getSummaryHtml (): string {
- return $this->childs->getSummaryHtml();
+ return "" . $this->childs->getSummaryHtml() . "
";
}
public function getPage (string $id): ?Page {
diff --git a/src/Element/BookContent/Page.php b/src/Element/BookContent/Page.php
index ddb739e..9e6f8dc 100644
--- a/src/Element/BookContent/Page.php
+++ b/src/Element/BookContent/Page.php
@@ -73,7 +73,7 @@ class Page {
public function getSummaryHtml (): string {
$str =
- "id' page-id='$this->id' class='page-contented chapter link-page " .
(PageMeta::$page->getId()==$this->id?" active":"") .
"'>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],
+ ),
+ ),
+
+ );
+ }
+ }
+
+}
diff --git a/template/footer.php b/template/footer.php
index c923dd1..c699f9c 100644
--- a/template/footer.php
+++ b/template/footer.php
@@ -11,7 +11,11 @@
}
?>
+