Greasy Fork

Greasy Fork is available in English.

MiGerritPlus

some extention for miui gerrit

当前为 2022-08-03 提交的版本,查看 最新版本

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴Greasemonkey 油猴子Violentmonkey 暴力猴,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴Violentmonkey 暴力猴,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴Userscripts ,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展后才能安装此脚本。

(我已经安装了用户脚本管理器,让我安装!)

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

(我已经安装了用户样式管理器,让我安装!)

// ==UserScript==
// @name         MiGerritPlus
// @namespace    thbeliefNameSpace
// @icon         https://cnbj1.fds.api.xiaomi.com/info-app-webfile/common-resource/ico/favicon.ico
// @version      1.3.0
// @description  some extention for miui gerrit
// @author       thbelief
// @match        *://gerrit.pt.mioffice.cn/*
// @require      https://apps.bdimg.com/libs/jquery/2.1.4/jquery.min.js
// @grant        GM_setValue
// @grant        GM_getValue
// @grant        GM_registerMenuCommand
// @grant        GM_deleteValue
// @grant        GM_xmlhttpRequest
// @grant        GM_notification
// @grant        GM_setClipboard
// @grant        GM.setValue
// @grant        GM.getValue
// @grant        GM.registerMenuCommand
// @grant        GM.deleteValue
// @grant        GM.xmlHttpRequest
// @grant        GM.notification
// @grant        GM.setClipboard
// @grant        unsafeWindow
// @run-at       document-end
// @license      AGPL
// ==/UserScript==
(function () {
    'use strict'

    // code region start

    /**
     * some config
     */
    var TAG = "MiGerritPlus"
    // control is print log
    var isDebug = true
    var dashBoardSelf = "https://gerrit.pt.mioffice.cn/dashboard/self"
    var intervalTime = 150
    var checkboxInsertIndex = 3
    // need hide group array
    var hideGroupArray = new Array("Your Turn", "Incoming reviews", "CCed on", "Recently closed")


    print("origin start")
    $(document).ready(function () { main() })
    // cur url
    var curHerf = window.location.href
    // reload because not success sometimes
    var isNeedReloadMain = false
    // save checkbox and change
    var selectChangeMap = new Map()
    // copyButton
    var copyButton = createClipIcon()

    /**
     * History and window.hashchange is not role
     * so use interval
     */
    setInterval(function () {
        if (curHerf != window.location.href || isNeedReloadMain) {
            isNeedReloadMain = false;
            curHerf = window.location.href
            print("cur url = " + curHerf)
            if (curHerf != dashBoardSelf) {
                copyButton.remove()
                print("Not dashBoardSelf.Remove copy button")
            }
            if (curHerf === dashBoardSelf) {
                main()
            }
        }
    }, intervalTime);

    function print(content) {
        if (!isDebug) {
            return;
        }
        console.log(TAG + ": " + content)
    }
    function main() {
        print("main")
        var rootDom = document.body.querySelector("gr-app").shadowRoot.getElementById("app-element").shadowRoot.getRootNode();
        var mainHeader = rootDom.querySelector("gr-main-header").shadowRoot.getRootNode()
        // insert copy button
        insertClipIcon(mainHeader.querySelector(".links"))
        // remove footer
        var footerDom = rootDom.querySelector("footer")
        if (footerDom != null) {
            print("remove footer")
            footerDom.remove()
        }
        var mainDom = rootDom.querySelector("main")
        if (mainDom === null) {
            print("main is null")
            return
        }
        var changeDom = mainDom.querySelector("gr-dashboard-view")
        if (changeDom === null) {
            isNeedReloadMain = true
            return
        }
        var changeList = changeDom.shadowRoot.getRootNode().querySelector("gr-change-list").shadowRoot.getRootNode().querySelectorAll("gr-change-list-section")
        // cardArray is per change card
        var cardArray = new Array()
        for (var i = 0; i < changeList.length; i++) {
            cardArray[i] = changeList[i].shadowRoot.getRootNode()
        }
        if (cardArray.length === 0) {
            isNeedReloadMain = true
        }
        print("cardArray = " + cardArray)
        for (var i = 0; i < cardArray.length; i++) {
            var curGroupDom = cardArray[i].querySelector(".section-name")
            var groupHeaderDom = cardArray[i].querySelector(".groupHeader")
            // hide which need to hide group
            if (curGroupDom != null && hideGroupArray.includes(curGroupDom.innerText)) {
                print("remove " + curGroupDom.innerText)
                if (groupHeaderDom !== null) {
                    groupHeaderDom.remove()
                }
                var groupContentDom = cardArray[i].querySelector(".groupContent")
                if (groupContentDom !== null) {
                    groupContentDom.remove()
                }
                // remove noChanges item
                var noChangesDom = cardArray[i].querySelector(".noChanges")
                if (noChangesDom !== null) {
                    noChangesDom.remove()
                }
                // remove group title
                if (i != 0) {
                    var groupTitleDom = cardArray[i].querySelector(".groupTitle")
                    if (groupTitleDom !== null) {
                        groupTitleDom.remove()
                    }
                }
            }
            var groupContentDom = cardArray[i].querySelector(".groupContent")
            if (groupContentDom !== null) {
                var groupTitleDom = groupContentDom.querySelector(".groupTitle")
                if(groupTitleDom.querySelectorAll(".subject").length <= 1){
                    insertCheckBoxTitle(groupTitleDom)
                    var list = groupContentDom.querySelectorAll("gr-change-list-item")
                    insertCheckBox(list)
                }
            }
        }
    }
    /**
     * insert checkbox title
     * @param list 
     */
    function insertCheckBoxTitle(groupTitle) {
        var tdList = groupTitle.querySelectorAll("td")
        groupTitle.insertBefore(createCheckBoxTitle(), tdList[checkboxInsertIndex])
    }
    /**
     * create checkbox title
     * @returns 
     */
    function createCheckBoxTitle() {
        var td = document.createElement("td")
        td.className = "subject"
        td.innerText = "Select"
        return td
    }
    /**
     * insert checkbox to every change
     * @param {*} list 
     */
    function insertCheckBox(list) {
        for (var i = 0; i < list.length; i++) {
            var tdList = list[i].shadowRoot.getRootNode().querySelectorAll("td")
            var cellNumberNode = list[i].shadowRoot.getRootNode().querySelector(".number")
            var titleNode = list[i].shadowRoot.getRootNode().querySelector(".content")
            var repoNode = list[i].shadowRoot.getRootNode().querySelector(".fullRepo")
            var branchNode = list[i].shadowRoot.getRootNode().querySelector(".branch")
            const change = new Change(cellNumberNode.querySelector("a").innerText, titleNode.innerText, cellNumberNode.querySelector("a").href, repoNode.innerText, branchNode.querySelector("a").innerText)
            list[i].shadowRoot.getRootNode().insertBefore(createCheckBox(change), tdList[checkboxInsertIndex])
        }
    }
    /**
     * create checkbox
     * @param {*} change 
     * @returns 
     */
    function createCheckBox(change) {
        var td = document.createElement("td")
        var input = document.createElement("input")
        input.type = "checkbox"
        input.setAttribute("style", "width:20px;height:20px;")
        input.onclick = function () {
            selectChangeMap.get(this).setIsChecked(this.checked)
            //console.log(selectChangeMap.get(this))
        }
        td.setAttribute("display", "table-cell")
        td.setAttribute("vertical-align", "middle")
        td.setAttribute("white-space", "nowrap")
        td.appendChild(input)
        selectChangeMap.set(input, change)
        return td
    }
    /**
     * insert copy button
     * @param {*} links 
     */
    function insertClipIcon(links) {
        if (links == null) {
            return
        }
        var button = links.querySelector(".copyToClipboard")
        // just need one
        if (button == null) {
            links.appendChild(copyButton)
        }
    }
    /**
     * get changes which checked by myselef
     * @returns 
     */
    function getCheckedChange() {
        var changes = new Array()
        var index = 0
        selectChangeMap.forEach(function (value, key) {
            if (value.isChecked()) {
                key.checked = false
                changes[index++] = value
            }
        })
        return changes
    }
    /**
     * create copy button
     * @returns 
     */
    function createClipIcon() {
        /**
         * <gr-button id="copy-clipboard-button" link="" class="copyToClipboard" aria-label="Click to copy to clipboard" role="button" tabindex="0" aria-disabled="false">
         * <iron-icon id="icon" icon="gr-icons:content-copy">
         * <svg viewBox="0 0 24 24" preserveAspectRatio="xMidYMid meet" focusable="false" style="pointer-events: none; display: block; width: 100%; height: 100%;">
         * <g>
         * <path d="M16 1H4c-1.1 0-2 .9-2 2v14h2V3h12V1zm3 4H8c-1.1 0-2 .9-2 2v14c0 1.1.9 2 2 2h11c1.1 0 2-.9 2-2V7c0-1.1-.9-2-2-2zm0 16H8V7h11v14z">
         * </path>
         * </g>
         * </svg>
         * </iron-icon>
         * </gr-button>
         */
        var path = document.createElement("path")
        path.setAttribute("d", "M16 1H4c-1.1 0-2 .9-2 2v14h2V3h12V1zm3 4H8c-1.1 0-2 .9-2 2v14c0 1.1.9 2 2 2h11c1.1 0 2-.9 2-2V7c0-1.1-.9-2-2-2zm0 16H8V7h11v14z")
        var g = document.createElement("g")
        g.appendChild(path)
        var svg = document.createElement('svg');
        svg.setAttribute("viewBox", "0 0 24 24")
        svg.setAttribute("preserveAspectRatio", "xMidYMid meet")
        svg.setAttribute("focusable", "false")
        svg.setAttribute("style", "pointer-events: none; display: block; width: 100%; height: 100%;")
        svg.appendChild(g)
        var icon = document.createElement("iron-icon")
        icon.setAttribute("icon", "gr-icons:content-copy")
        icon.appendChild(svg)
        var button = document.createElement("gr-button")
        button.setAttribute("class", "copyToClipboard")
        button.setAttribute("role", "button")
        button.setAttribute("aria-disabled", "false")
        button.appendChild(icon)
        button.onclick = function () {
            var array = getCheckedChange()
            if (array.length == 0) {
                print("not select any change")
                return
            }
            var result = "";
            for (var i = 0; i < array.length; i++) {
                var extra = ""
                if (i != 0) {
                    extra += "\n"
                }
                extra += "index = " + i + "\n"
                result += extra + array[i].getString()
                if (i != array.length - 1) {
                    result += "\n"
                }
            }
            print("copy \n" + result)
            GM_setClipboard(result)
        }
        var li = document.createElement("li")
        li.appendChild(button)
        return li;
    }
    /**
     * change class 
     * save information about change
     */
    class Change {
        constructor(id, title, url, repo, branch) {
            this.id = id.trim()
            this.title = title.trim()
            this.url = url.trim()
            this.repo = repo.trim()
            this.branch = branch.trim()
            this.ischecked = false
        }

        isChecked() {
            return this.ischecked
        }

        setIsChecked(ischecked) {
            this.ischecked = ischecked
        }

        getString() {
            var result = "ChangeId: " + this.id + "\nTitle: " + this.title + "\nRepo: " + this.repo + "\nBranch: " + this.branch + "\nUrl: " + this.url
            return result
        }
    }

    // code region end
})();