// ==UserScript== // @name github、码云 md文件目录化 // @name:en Github, code cloud md file directory // @namespace github、码云 md文件目录化 // @version 1.0 // @description github、码云项目README.md增加目录侧栏导航,悬浮按钮 // @description:en Github,code cloud project README.md add directory sidebar navigation,Floating button // @author lecoler // @supportURL https://github.com/lecoler/md-list // @icon https://raw.githubusercontent.com/lecoler/readme.md-list/master/static/icon.png // @match *://gitee.com/*/* // @match *://www.gitee.com/*/* // @match *://github.com/*/* // @match *://www.github.com/*/* // @note 2019.10.28-V1.0 优化逻辑,追加判断目录内容是否存在 // @note 2019.10.25-V0.9 重构项目,移除jq,改用原生开发,新增悬浮按钮 // @note 2019.10.14-V0.9 修复bug // @note 2019.9.18-V0.8 修改样式,新增可手动拉伸 // @note 2019.9.11-V0.7 新增点击跳转前判断是否能跳,不能将回到主页执行跳转 // @note 2019.8.11-V0.6 优化代码,修改样式 // @note 2019.7.25-V0.5 美化界面 // @note 2019.7.25-V0.4 新增支持github // @note 2019.7.25-V0.2 修复bug,优化运行速度,新增按序获取 // @home-url https://greasyfork.org/zh-CN/scripts/387834 // @homepageURL https://github.com/lecoler/md-list // @grant GM_addStyle // @run-at document-end // @downloadURL none // ==/UserScript== (function () { 'use strict'; // 初始化 let initStatus = false; let $menu = null; let lastPathName = ''; let moveStatus = false; function init() { style(); const $div = document.createElement('div'); const $button = document.createElement('div'); $menu = document.createElement('ul'); $menu.className = 'hidden'; $button.setAttribute('class', 'le-md-btn'); $button.innerHTML = `目录`; // 添加点击事件 $button.addEventListener('click', e => { //判断是否在移动 if (moveStatus) { moveStatus = false; return false; } if ($menu.className.match(/hidden/)) { // 判断路径是否改变,menu是否重载 if (lastPathName !== window.location.pathname) { start(); } // 判断menu位置 const winWidth = document.documentElement.clientWidth; const winHeight = document.documentElement.clientHeight; const x = e.clientX; const y = e.clientY; const classname1 = winWidth / 2 - x > 0 ? 'le-md-right' : 'le-md-left'; const classname2 = winHeight / 2 - y > 0 ? 'le-md-bottom' : 'le-md-top'; $menu.className = `${classname1} ${classname2}`; } else { $menu.className += ' hidden'; } }); $div.appendChild($button); $div.appendChild($menu); $div.setAttribute('class', 'le-md'); dragEle($button); document.body.appendChild($div); initStatus = true; } // 插入样式表 function style() { const style = document.createElement('style'); style.innerHTML = ` .le-md { position: fixed; top: 12%; left: 90%; z-index: 999; } .le-md-btn { font-size: 14px; text-transform: uppercase; width: 60px; height: 60px; box-sizing: border-box; border-radius: 50%; color: #fff; text-shadow: -1px -1px 1px rgba(0, 0, 0, 0.8); border: 0; background: hsla(230, 50%, 50%, 0.6); animation: pulse 1s infinite alternate; transition: background 0.4s, margin 0.2s; text-align: center; line-height: 60px; user-select: none; cursor: move; } .le-md-btn:after { background: rgba(0, 0, 0, 0.05); border-radius: 50%; bottom: -22.5px; content: ""; display: block; height: 0; margin: 0 auto; left: 0; position: absolute; right: 0; width: 40px; -webkit-transition: height 0.5s ease-in-out, width 0.5s ease-in-out; -moz-transition: height 0.5s ease-in-out, width 0.5s ease-in-out; -ms-transition: height 0.5s ease-in-out, width 0.5s ease-in-out; transition: height 0.5s ease-in-out, width 0.5s ease-in-out; animation: shadow 1s infinite alternate; } .le-md-btn:hover { background: hsla(220, 50%, 47%, 1); margin-top: -1px; animation: none; box-shadow: inset -5px -10px 1px hsla(220, 50%, 42%, 1); } .le-md-btn:hover:after { animation: none; height: 10px; } .hidden { max-height: 0 !important; } .le-md-left { right: 0; margin-right: 100px; } .le-md-right { left: 0; margin-left: 100px; } .le-md-top { bottom: 0; } .le-md-bottom { top: 0; } .le-md > ul { max-width: 200px; min-width: 80px; text-align: left; cursor: pointer; list-style: none; position: absolute; overflow-y: auto; transition: all 0.4s; max-height: 600px; resize: both; } .le-md > ul::-webkit-scrollbar { display: none; } .le-md > ul > li { margin-top: 0.25em; border-bottom: 0.5em solid #eee; padding: 5px 10px; transition: 0.4s all; border-left: 0.5em groove #e2e2e2; border-right: 1px solid #e2e2e2; border-top: 1px solid #e2e2e2; background: #fff; box-shadow: 0 1px 4px rgba(0, 0, 0, 0.3); border-radius: 0 0 5px 5px; } .le-md > ul > li:hover { background: #99CCFF; border-left: 1em groove #0099CC !important; } .le-md > ul a { text-decoration: none; font-size: 1em; color: #333; text-shadow: 0 1px 0 rgba(0, 0, 0, 0.2); display: block; white-space: nowrap; text-overflow: ellipsis; overflow: hidden; width: 100%; } @keyframes pulse { 0% { margin-top: 0; } 100% { margin-top: 6px; box-shadow: inset -5px -10px 1px hsla(230, 50%, 55%, 0.6), 0 0 25px hsla(230, 50%, 50%, 1); } } @keyframes shadow { to { height: 16px; } } `; document.head.appendChild(style); } // 拖动事件 function dragEle(ele) { ele.onmousedown = event => { let eleX = event.offsetX; let eleY = event.offsetY; let count = 0; window.document.onmousemove = e => { //防止误触移动 if (count > 9) { moveStatus = true; } let winX = e.clientX; let winY = e.clientY; ele.parentNode.style.left = winX - eleX + 'px'; ele.parentNode.style.top = winY - eleY + 'px'; count++; }; }; ele.onmouseup = () => { window.document.onmousemove = null; }; ele.onmouseout = () => { window.document.onmousemove = null; }; } // 执行 function start() { // 获取链接 const host = window.location.host; lastPathName = window.location.pathname; // 获取相应的容器dom let $content = null; let list = []; if (host === 'github.com') { //github home const $parent = document.getElementById('readme'); $content = $parent && $parent.getElementsByClassName('markdown-body')[0]; } else if (host === 'gitee.com') { //码云 home const $parent = document.getElementById('tree-content-holder'); $content = $parent && $parent.getElementsByClassName('markdown-body')[0]; } // 获取子级 const $children = $content ? $content.children : []; for (let $dom of $children) { const tagName = $dom.tagName; const lastCharAt = +tagName.charAt(tagName.length - 1); // 获取Tag h0-h9 if (tagName.length === 2 && tagName.startsWith('H') && !isNaN(lastCharAt)) { // 获取value const value = $dom.innerText.trim(); // 获取锚点 const href = $dom.getElementsByTagName('a')[0].getAttribute('href'); list.push({type: lastCharAt, value, href}); } } // 清空容器 if ($menu) { const list = [...$menu.childNodes]; list.forEach(i => $menu.removeChild(i)); } //是否初始化 if (!initStatus) { init(); } //是否存在 if (list.length) { // 生成菜单 for (let i of list) { const li = document.createElement('li'); li.innerHTML = `${i.value}`; li.setAttribute('style', `margin-left: ${i.type * 0.4}em;border-left: 0.5em groove hsla(200, 80%, ${45 + i.type * 10}%, 0.8);`); $menu.appendChild(li); } } else if (initStatus) { const li = document.createElement('li'); li.innerHTML = `未找到目录内容`; $menu.appendChild(li); } } start(); })();