summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorBigCoke233 <hi@guhub.cn>2020-05-30 14:30:38 +0800
committerBigCoke233 <hi@guhub.cn>2020-05-30 14:30:38 +0800
commitbd0a23b052dc750db72d2b98349044a56ede2419 (patch)
treee9b1b5540f639e438bd461bec1e8bf9e9a3f0038
parent33811859eb3438db65958e9a612918643786cdeb (diff)
✨ Add: 支持解析 details 短代码,并使用 js 垫片优化兼容性
-rw-r--r--README.md3
-rw-r--r--assets/css/main/post.css7
-rw-r--r--assets/js/details-element-polyfill.js194
-rw-r--r--includes/footer.php2
-rw-r--r--libs/Contents.php12
5 files changed, 214 insertions, 4 deletions
diff --git a/README.md b/README.md
index ca44ae6..7d070c8 100644
--- a/README.md
+++ b/README.md
@@ -137,7 +137,7 @@ $ git clone https://github.com/BigCoke233/miracles.git
- [ ] 新增:导航支持下拉面板
- [ ] 优化:页面/文章评论列表隐藏时,不显示评论数
- [ ] 优化:优化夜间模式的切换机制
-- [ ] 新增:支持快速写入`<details>`的短代码,并使用[垫片](https://github.com/javan/details-element-polyfill)优化兼容性
+- [x] 新增:支持快速写入`<details>`的短代码,并使用[垫片](https://github.com/javan/details-element-polyfill)优化兼容性
## 鸣谢
@@ -155,6 +155,7 @@ $ git clone https://github.com/BigCoke233/miracles.git
- [Normalize.css](http://necolas.github.io/normalize.css/) - 保证不同浏览器上各元素 css 默认效果相同
- [qrcode.js](https://github.com/davidshimjs/qrcodejs) - 生成文章二维码
- [gazeimg](https://github.com/ganxiaozhe/gazeimg) - 图片懒加载 & 灯箱
+- [details-element-polyfill](https://github.com/javan/details-element-polyfill) - 优化 details 标签兼容性
- ~~[LazyLoad](https://github.com/tuupola/lazyload) - 图片懒加载~~(开发版已用新的方案替换)
- ~~[FancyBox](https://github.com/fancyapps/fancybox) - 文章图片灯箱~~(开发版已用新的方案替换)
diff --git a/assets/css/main/post.css b/assets/css/main/post.css
index 6aaeff2..6a5728b 100644
--- a/assets/css/main/post.css
+++ b/assets/css/main/post.css
@@ -281,6 +281,13 @@
.post-content ol ul {
margin-top: 0;
}
+.post-content summary {
+ outline: none;
+ cursor: pointer;
+}
+.post-content summary:hover {
+ font-weight: bolder
+}
/* 加密文章 */
.post-content .protected {
display: flex;
diff --git a/assets/js/details-element-polyfill.js b/assets/js/details-element-polyfill.js
new file mode 100644
index 0000000..b651dfc
--- /dev/null
+++ b/assets/js/details-element-polyfill.js
@@ -0,0 +1,194 @@
+/*
+Details Element Polyfill 2.4.0
+Copyright © 2019 Javan Makhmali
+ */
+(function() {
+ "use strict";
+ var element = document.createElement("details");
+ var elementIsNative = typeof HTMLDetailsElement != "undefined" && element instanceof HTMLDetailsElement;
+ var support = {
+ open: "open" in element || elementIsNative,
+ toggle: "ontoggle" in element
+ };
+ var styles = '\ndetails, summary {\n display: block;\n}\ndetails:not([open]) > *:not(summary) {\n display: none;\n}\nsummary::before {\n content: "►";\n padding-right: 0.3rem;\n font-size: 0.6rem;\n cursor: default;\n}\n[open] > summary::before {\n content: "▼";\n}\n';
+ var _ref = [], forEach = _ref.forEach, slice = _ref.slice;
+ if (!support.open) {
+ polyfillStyles();
+ polyfillProperties();
+ polyfillToggle();
+ polyfillAccessibility();
+ }
+ if (support.open && !support.toggle) {
+ polyfillToggleEvent();
+ }
+ function polyfillStyles() {
+ document.head.insertAdjacentHTML("afterbegin", "<style>" + styles + "</style>");
+ }
+ function polyfillProperties() {
+ var prototype = document.createElement("details").constructor.prototype;
+ var setAttribute = prototype.setAttribute, removeAttribute = prototype.removeAttribute;
+ var open = Object.getOwnPropertyDescriptor(prototype, "open");
+ Object.defineProperties(prototype, {
+ open: {
+ get: function get() {
+ if (this.tagName == "DETAILS") {
+ return this.hasAttribute("open");
+ } else {
+ if (open && open.get) {
+ return open.get.call(this);
+ }
+ }
+ },
+ set: function set(value) {
+ if (this.tagName == "DETAILS") {
+ return value ? this.setAttribute("open", "") : this.removeAttribute("open");
+ } else {
+ if (open && open.set) {
+ return open.set.call(this, value);
+ }
+ }
+ }
+ },
+ setAttribute: {
+ value: function value(name, _value) {
+ var _this = this;
+ var call = function call() {
+ return setAttribute.call(_this, name, _value);
+ };
+ if (name == "open" && this.tagName == "DETAILS") {
+ var wasOpen = this.hasAttribute("open");
+ var result = call();
+ if (!wasOpen) {
+ var summary = this.querySelector("summary");
+ if (summary) summary.setAttribute("aria-expanded", true);
+ triggerToggle(this);
+ }
+ return result;
+ }
+ return call();
+ }
+ },
+ removeAttribute: {
+ value: function value(name) {
+ var _this2 = this;
+ var call = function call() {
+ return removeAttribute.call(_this2, name);
+ };
+ if (name == "open" && this.tagName == "DETAILS") {
+ var wasOpen = this.hasAttribute("open");
+ var result = call();
+ if (wasOpen) {
+ var summary = this.querySelector("summary");
+ if (summary) summary.setAttribute("aria-expanded", false);
+ triggerToggle(this);
+ }
+ return result;
+ }
+ return call();
+ }
+ }
+ });
+ }
+ function polyfillToggle() {
+ onTogglingTrigger(function(element) {
+ element.hasAttribute("open") ? element.removeAttribute("open") : element.setAttribute("open", "");
+ });
+ }
+ function polyfillToggleEvent() {
+ if (window.MutationObserver) {
+ new MutationObserver(function(mutations) {
+ forEach.call(mutations, function(mutation) {
+ var target = mutation.target, attributeName = mutation.attributeName;
+ if (target.tagName == "DETAILS" && attributeName == "open") {
+ triggerToggle(target);
+ }
+ });
+ }).observe(document.documentElement, {
+ attributes: true,
+ subtree: true
+ });
+ } else {
+ onTogglingTrigger(function(element) {
+ var wasOpen = element.getAttribute("open");
+ setTimeout(function() {
+ var isOpen = element.getAttribute("open");
+ if (wasOpen != isOpen) {
+ triggerToggle(element);
+ }
+ }, 1);
+ });
+ }
+ }
+ function polyfillAccessibility() {
+ setAccessibilityAttributes(document);
+ if (window.MutationObserver) {
+ new MutationObserver(function(mutations) {
+ forEach.call(mutations, function(mutation) {
+ forEach.call(mutation.addedNodes, setAccessibilityAttributes);
+ });
+ }).observe(document.documentElement, {
+ subtree: true,
+ childList: true
+ });
+ } else {
+ document.addEventListener("DOMNodeInserted", function(event) {
+ setAccessibilityAttributes(event.target);
+ });
+ }
+ }
+ function setAccessibilityAttributes(root) {
+ findElementsWithTagName(root, "SUMMARY").forEach(function(summary) {
+ var details = findClosestElementWithTagName(summary, "DETAILS");
+ summary.setAttribute("aria-expanded", details.hasAttribute("open"));
+ if (!summary.hasAttribute("tabindex")) summary.setAttribute("tabindex", "0");
+ if (!summary.hasAttribute("role")) summary.setAttribute("role", "button");
+ });
+ }
+ function eventIsSignificant(event) {
+ return !(event.defaultPrevented || event.ctrlKey || event.metaKey || event.shiftKey || event.target.isContentEditable);
+ }
+ function onTogglingTrigger(callback) {
+ addEventListener("click", function(event) {
+ if (eventIsSignificant(event)) {
+ if (event.which <= 1) {
+ var element = findClosestElementWithTagName(event.target, "SUMMARY");
+ if (element && element.parentNode && element.parentNode.tagName == "DETAILS") {
+ callback(element.parentNode);
+ }
+ }
+ }
+ }, false);
+ addEventListener("keydown", function(event) {
+ if (eventIsSignificant(event)) {
+ if (event.keyCode == 13 || event.keyCode == 32) {
+ var element = findClosestElementWithTagName(event.target, "SUMMARY");
+ if (element && element.parentNode && element.parentNode.tagName == "DETAILS") {
+ callback(element.parentNode);
+ event.preventDefault();
+ }
+ }
+ }
+ }, false);
+ }
+ function triggerToggle(element) {
+ var event = document.createEvent("Event");
+ event.initEvent("toggle", false, false);
+ element.dispatchEvent(event);
+ }
+ function findElementsWithTagName(root, tagName) {
+ return (root.tagName == tagName ? [ root ] : []).concat(typeof root.getElementsByTagName == "function" ? slice.call(root.getElementsByTagName(tagName)) : []);
+ }
+ function findClosestElementWithTagName(element, tagName) {
+ if (typeof element.closest == "function") {
+ return element.closest(tagName);
+ } else {
+ while (element) {
+ if (element.tagName == tagName) {
+ return element;
+ } else {
+ element = element.parentNode;
+ }
+ }
+ }
+ }
+ })(); \ No newline at end of file
diff --git a/includes/footer.php b/includes/footer.php
index d101499..1698bc2 100644
--- a/includes/footer.php
+++ b/includes/footer.php
@@ -22,7 +22,7 @@
</div>
<!-- JavaScript Require-->
<?php
- $js_files=array("jquery","pjax.jquery","gazeimg","nprogress","OwO.min","highlight","highlight-line-number","pangu","qrcode.min");
+ $js_files=array("jquery","pjax.jquery","gazeimg","nprogress","OwO.min","highlight","highlight-line-number","pangu","qrcode.min","details-element-polyfill");
if($this->options->customCDN): $custom=$this->options->customCDN; else: $custom=Helper::options()->themeUrl("","Miracles"); endif;
generate_require($js_files,"js",$this->options->CDN,$custom);
?>
diff --git a/libs/Contents.php b/libs/Contents.php
index 9547e95..055d4ce 100644
--- a/libs/Contents.php
+++ b/libs/Contents.php
@@ -13,7 +13,7 @@ class Contents
$text = empty($last) ? $data : $last;
if ($widget instanceof Widget_Archive) {
//ParseOther
- $text = Contents::parsePicShadow(Contents::parseNotice(Contents::parseKbd(Contents::parseCode(Contents::parseImages(Contents::parseHeadings(Contents::parseTextColor(Contents::parseRuby(Contents::parseTip($text)))))))));
+ $text = Contents::parseDetails(Contents::parsePicShadow(Contents::parseNotice(Contents::parseKbd(Contents::parseCode(Contents::parseImages(Contents::parseHeadings(Contents::parseTextColor(Contents::parseRuby(Contents::parseTip($text))))))))));
//LazyLoad
$text = preg_replace('/<img (.*?)src(.*?)(\/)?>/','<img $1src="/usr/themes/Miracles/images/loading/'.$load_image.'.gif" data-gisrc$2 data-gazeimg />',$text);
//owo
@@ -209,7 +209,15 @@ class Contents
static public function parseKbd($text) {
$text = preg_replace('/\[\[(.*?)\]\]/s','<kbd>${1}</kbd>',$text);
return $text;
- }
+ }
+
+ /**
+ * 解析 <details>
+ */
+ static public function parseDetails($text) {
+ $text = preg_replace('/\[details sum="(.*?)"\](.*?)\[\/details\]/s','<details><summary>${1}</summary>${2}</details>',$text);
+ return $text;
+ }
/**
* 解析章节链接