您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
小白社区开发者实用工具,快速在issue中插入申请开发/变更deadline等操作
// ==UserScript== // @name Sibbay Github Quick Reply // @namespace https://github.com/sibbay-ai/public // @version 0.13 // @description 小白社区开发者实用工具,快速在issue中插入申请开发/变更deadline等操作 // @author github.com/Yidadaa // @include https://github.com* // @run-at document-end // @grant GM_getValue // @grant GM_setValue // ==/UserScript== (function() { 'use strict'; // 由于github使用pjax加载页面,需要对github全站进行匹配,然后排除掉不需要运行脚本的页面 let days = GM_getValue('days') || 14 let size = GM_getValue('size') || 0.1 // 工具函数 const $$ = s => Array.from(document.querySelectorAll(s)) const $ = s => document.querySelector(s) function tree2node (root) { // 生成dom节点 const node = document.createElement(root.type) // 映射标签属性 root.attrs && Object.keys(root.attrs).forEach(key => { node.setAttribute(key, root.attrs[key]) }) // 映射节点属性 root.props && Object.keys(root.props).forEach(key => { node[key] = root.props[key] }) // 生成子节点 root.children && root.children.forEach(child => { node.appendChild(tree2node(child)) }) return node } // 检查是否已经标记过ddl const checkDDL = () => { return $$('.timeline-comment-group .edit-comment-hide').some(node => { return /申请开发\ deadline/.test(node.innerText) }) } // 生成n天后的时间 const nDaysLater = (n) => { const date = new Date() const nDaysLaterTime = new Date(date.getTime() + n * 24 * 3600 * 1000) return `${nDaysLaterTime.getFullYear()}-${nDaysLaterTime.getMonth() + 1}-${nDaysLaterTime.getDate()}` } // 生成模板 const generateText = () => { const hasDDL = checkDDL() let text = `申请开发 deadline: ${nDaysLater(days)} size: ${size}` if (hasDDL) text = `变更 deadline: ${nDaysLater(days)}` return text } // 更新文字 const updateText = () => { $('#sibbay-text').innerText = generateText() $('#sibbay-time').innerText = ` - will finish in ${days} days` $('#sibbay-size').innerText = ` - ${size} size` } // 确认提交文字 const confirmText = () => { $('#new_comment_field').value = generateText() GM_setValue('days', days) GM_setValue('size', size) } const buttonWithMenu = { type: "span", attrs: { class: "js-pages-source select-menu js-menu-container js-select-menu js-transitionable", style: "float: right;" }, children: [ { type: "button", attrs: { class: "btn mr-1 select-menu-button js-menu-target", type: 'button', 'aria-haspopup': true, 'aria-expanded': false }, children: [{ type: 'span', attrs: { class: 'js-select-button js-pages-source-btn-text', style: 'margin-right: 5px;' }, props: { innerText: checkDDL() ? 'Change deadline' : 'Wanna develop' } }] }, { type: 'div', attrs: { class: 'select-menu-modal-holder', style: 'margin-top: 35px;' }, children: [{ type: 'div', attrs: { class: 'select-menu-modal js-menu-content', 'aria-expanded': false }, children: [{ type: 'div', attrs: { class: 'select-menu-list js-navigation-container', role: 'menu' }, children: [{ type: 'div', attrs: { class: 'select-menu-header js-navigation-enable' }, children: [{ type: 'span', props: { innerText: 'Select a time' } }, { type: 'span', attrs: { id: 'sibbay-time' }, props: { innerText: ` - will finish in ${days} days` } }] }, { type: 'div', attrs: { class: 'width-full', style: 'padding: 10px;' }, children: [{ type: 'input', attrs: { class: 'width-full', type: 'range', min: '1', max: '30', value: days, style: 'cursor: pointer' }, props: { oninput: e => { days = e.target.value updateText() } } }] }, { type: 'div', attrs: { class: 'select-menu-header js-navigation-enable', style: `display: ${checkDDL() ? 'none' : 'block'}` }, children: [{ type: 'span', props: { innerText: 'Select a size' } }, { type: 'span', attrs: { id: 'sibbay-size' }, props: { innerText: ` - ${size} size` } }] }, { type: 'div', attrs: { class: 'width-full', style: `padding: 10px; display: ${checkDDL() ? 'none' : 'block'}` }, children: [{ type: 'input', attrs: { class: 'width-full', type: 'range', min: '0.1', max: '3', step: '0.1', value: size, style: 'cursor: pointer' }, props: { oninput: e => { size = e.target.value updateText() } } }] }, { type: 'div', attrs: { style: 'padding: 10px; border-top: 1px solid #eee; display: flex; align-items: center;' }, children: [{ type: 'div', attrs: { class: 'width-full', id: 'sibbay-text', style: 'font-weight: bold;' }, props: { innerText: generateText() } }, { type: 'div', attrs: { class: 'btn btn-sm btn-primary js-menu-close' }, props: { innerText: 'OK', onclick: confirmText } }] }] }] }] } ] } let applyBtn = tree2node(buttonWithMenu) const appendBtn = () => { if (!location.href.includes('sibbay-ai')) return const buttons = document.getElementById('partial-new-comment-form-actions') if (!buttons) { return } buttons.appendChild(applyBtn) } document.addEventListener('pjax:complete', appendBtn) appendBtn() })();