diff options
| -rw-r--r-- | README.md | 3 | ||||
| -rw-r--r-- | assets/css/main/post.css | 7 | ||||
| -rw-r--r-- | assets/js/details-element-polyfill.js | 194 | ||||
| -rw-r--r-- | includes/footer.php | 2 | ||||
| -rw-r--r-- | libs/Contents.php | 12 |
5 files changed, 214 insertions, 4 deletions
@@ -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; + } /** * 解析章节链接 |
