您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
make old apollo better
当前为
// ==UserScript== // @name apollo-enhance // @namespace apollo-enhance // @version 0.8.5 // @description make old apollo better // @homepage https://github.com/xyz327/old-apollo-portal-enhance // @website https://github.com/xyz327/old-apollo-portal-enhance // @source https://github.com/xyz327/old-apollo-portal-enhance // @author xizhou // @match *://*/config.html* // @resource highlight_xcode_css https://lf3-cdn-tos.bytecdntp.com/cdn/expire-1-M/highlight.js/9.18.5/styles/xcode.min.css // @require https://lf9-cdn-tos.bytecdntp.com/cdn/expire-1-M/diff_match_patch/20121119/diff_match_patch_uncompressed.js // @require https://lf3-cdn-tos.bytecdntp.com/cdn/expire-1-M/highlight.js/9.18.5/highlight.min.js // @require https://lf6-cdn-tos.bytecdntp.com/cdn/expire-1-M/highlight.js/9.18.5/languages/json.min.js // @resource text_different_css https://cdn.jsdelivr.net/npm/[email protected]/build/style/text-different.min.css // @require https://cdn.jsdelivr.net/combine/npm/[email protected]/build/text-different.min.js,npm/[email protected]/build/text-different-for-html.min.js // @noframes // @grant GM_getResourceText // @grant GM_addStyle // @grant GM_addElement // ==/UserScript== (function () { 'use strict'; var enhanceNavId = "apollo-enhance-nav"; var featureId = "apollo-enhance-feature"; function appendNavBar(child) { $(`#${enhanceNavId}`).append(child); } loadFeature("nav", false, function () { var $navBar = $("#bs-example-navbar-collapse-1"); $navBar.append(` <ul id="${enhanceNavId}" class="nav navbar-nav navbar-right"> </ul> `); return true; }); (function () { initFeatureId(); initDiffModal(); $("[data-copy]").on("click", function (e) { copy($(e.currentTarget).attr("data-copy-value")).then(function () { var $icon = $(e.target).parent().find(".glyphicon"); $icon.removeClass("glyphicon-duplicate").addClass("glyphicon-ok"); setTimeout(function () { $icon.addClass("glyphicon-duplicate").removeClass("glyphicon-ok"); }, 2000); }); }); // 加载 layer 依赖 $ GM_addElement('script', { src: 'https://cdn.jsdelivr.net/npm/[email protected]/src/layer.js', type: 'text/javascript' }); })(); loadFeature("onNamesacpeLoaded", true, function () { var $namespaces = $(".namespace-name"); if ($namespaces.length == 0) { return false; } console.log('trigger namespaceLoaded'); $("body").trigger("namespaceLoaded"); }); function getAppId() { let hash = location.hash; if (hash) { hash = hash.substring(2); const url = new URL("http://localhost?" + hash); return url.searchParams.get("appid"); } } function loadFeature(name, reloadOnHashChange, feature) { loadFeature0(name, feature, false); if (reloadOnHashChange) { $(window).on("hashchange", function (e) { loadFeature0(name, feature, true); }); } } function showDiffModal(key, newVal, oldVal) { const tdfh = new TextDifferentForHtml( $("#diff-container")[0], // The dom used to render the display code "json" // Type of code ); $("#diff-detail-title").html(`${key}`); $("#copyOld").attr("data-copy-value", oldVal); $("#copyNew").attr("data-copy-value", newVal); tdfh.render({ oldCode: toPerttyJson(oldVal), // Old code newCode: toPerttyJson(newVal), // New code hasLineNumber: false, // Whether to display the line number }); $("#diffModal").modal(); } function copy(content) { return new Promise(function (res, rej) { let copy = function (e) { try { e.preventDefault(); e.clipboardData.setData("text/plain", content); document.removeEventListener("copy", copy); console.log("copy value:", content); res(); } catch (e) { rej(); } }; document.addEventListener("copy", copy); document.execCommand("Copy"); }); } function toPerttyJson(val) { try { return JSON.stringify(JSON.parse(val), null, 2); } catch (e) { return val; } } function loadFeature0(name, feature, isReloadByHash) { try { if ($("#feature-" + name).length !== 0) { // 已经加载过了 console.log(`loadFeature: ${name} has loaded`); return; } var clear = setInterval(function () { if (feature(isReloadByHash) !== false) { console.log(`loadFeature: ${name} finished`); $(`${"#" + featureId}`).append(`<div id="feature-${name}"></div>`); clearInterval(clear); } }, 1000); } catch (e) { console.error(`load feature failed :${name}`, e.message); } } function initFeatureId() { $("body").prepend(`<div id="${featureId}" class="hidden"></div>`); } function initDiffModal() { $("body").append(` <!-- Modal --> <div class="modal fade" id="diffModal" tabindex="-1" role="dialog" aria-labelledby="myModalLabel"> <div class="modal-dialog modal-lg" role="document"> <div class="modal-content"> <div class="modal-header"> <button type="button" class="close" data-dismiss="modal" aria-label="Close"><span aria-hidden="true">×</span></button> <h4 class="modal-title"><span class="text-danger" id="diff-detail-title"></span> 差异对比</h4> </div> <div class="modal-body" > <div class="row"> <div class="col-xs-6 text-center"> <span data-tooltip="tooltip" title="点击复制" id="copyOld" data-copy="copy" data-copy-value="" class="label label-default">旧值 <label class="glyphicon glyphicon-duplicate"></label> </span> </div> <div class="col-xs-6 text-center"> <span data-tooltip="tooltip" title="点击复制" id="copyNew" data-copy="copy" data-copy-value="" class="label label-success">新值 <label class="glyphicon glyphicon-duplicate"></label> </span> </div> </div> <div id="diff-container" style="display:flex"></div> </div> </div> </div> </div> `); } loadFeature("fixNiceScroll", false, function () { $(document).ready(function () { // 放在初始化之后执行 setTimeout(function () { $("html").css("overflow", ""); }, 200); }); return true; }); loadFeature("fixEnvTab", true, function (isReloadByHash) { var $tab = $(".J_appFound"); if ($tab.length == 0) { return false; } const infoVal = sessionStorage[getAppId()]; const infoObj = JSON.parse(infoVal); const cluster = infoObj.cluster; const env = infoObj.env; var $panelHeader = $tab.find(".panel-heading:first"); var $curEnvInfo = $panelHeader.find("#curEnvInfo"); if ($curEnvInfo.length == 0) { $tab.find(".panel-heading>span").after(` <button type="button" class="slideBtn btn btn-primary btn-xs">(点击展开/收缩)</button> `); $panelHeader.append(`<div id="curEnvInfo"></div>`); $curEnvInfo = $panelHeader.find("#curEnvInfo"); } $curEnvInfo.html(` <span class="label label-success">${env}</span> - <span class="label label-info">${cluster}</span> `); if (!isReloadByHash) { // 不是通过 hash change reload 的才需要绑定事件 $tab.find(".panel-heading .slideBtn").on("click", function (e) { const $header = $(e.target).parent(".panel-heading"); $header.next("div").slideToggle("normal", function () {}); }); $tab = $tab.parent(); $tab.on("affixed.bs.affix", function (e) { $tab.css({ position: "fixed" }); $tab .find(".panel-heading") .next("div") .slideUp("normal", function () {}); }); $tab.on("affixed-top.bs.affix ", function (e) { $tab.css({ position: "" }); $tab .find(".panel-heading") .next("div") .slideDown("normal", function () {}); }); $tab.affix({ offset: { top: 50, }, }); } return true; }); loadFeature("disableScrollOnModal", false, function () { $("body") .on("show.bs.modal", function () { $("html").css("overflow", "hidden"); }) .on("hide.bs.modal", function () { $("html").css("overflow", ""); }); return true; }); loadFeature("gotoNamespace", true, () => { var $namespaces = $(".namespace-name"); if ($namespaces.length == 0) { return false; } goToNamespace0(); return true; }); function goToNamespace0() { if ($("#affixPlaceholder").length == 0) { $("body>nav.navbar").width("100%").css({ "z-index": 999 }).affix({ top: 0, }); $("body>nav.navbar").after('<div id="affixPlaceholder"></div>'); var $affixPlaceholder = $("#affixPlaceholder"); $("body>nav.navbar").on("affix.bs.affix", function (event) { $affixPlaceholder.css("height", "50px"); }); $("body>nav.navbar").on("affix-top.bs.affix", function (event) { $affixPlaceholder.css("height", "0px"); }); } const observer = new MutationObserver(() => { console.log('rebuild gotoNamesapce'); // 重新加载 namespace selector 的修改状态 buildGotoNamespace(); }); $.each($(".config-item-container"), (index, el) => { observer.observe(el, { childList: true }); }); buildGotoNamespace(); } function buildGotoNamespace() { $("#goToNamespace").remove(); var $namespaces = $(".namespace-name"); $namespaces.attr("data-namespace", function(){ return this.innerHTML.replace('.', "-") }); var list = ""; var namespaceOffsets = []; var lastNamespaceId = "application"; for (const namespace of $namespaces) { var $namespace = $(namespace); var namespaceVal = $namespace.text(); var namespaceId = namespaceVal; //$namespace.text().replaceAll(".", "-"); namespaceOffsets.push({ top: $namespace.offset().top, id: lastNamespaceId, }); lastNamespaceId = namespaceId; var changed = $(namespace).parent().parent().find(".modify-tip.ng-hide").length === 0; //$namespace.parents('header.panel-heading').after(`<a href="#${namespaceId}" id="${namespaceId}"></a>`); list += `<option value="${namespaceId}" ${changed?'data-change="1"':''}>${namespaceVal}</option>`; } appendNavBar(` <li id="goToNamespace" style="margin-top: 10px;"> <select id="namespaceSelecter">${list}</select> </li> `); var $select = $("#namespaceSelecter"); // init changed $select.select2({ placeholder: "跳转到 Namespace", templateResult: function (state) { var changed = $(state.element).attr("data-change"); if (changed) { return $( `<label>${state.text} <span class="label label-warning ">改</span></label>` ); } return `${state.text}`; }, }); $select.on("select2:open", function (e) { $("#select2-namespaceSelecter-results").css({ "max-height": "600px" }); }); var selectedVal; var triggerBySelect = false; var htmlScroll = $("html").getNiceScroll(0); htmlScroll.scrollend(function (e) { if (triggerBySelect) { triggerBySelect = false; return; } var offsetY = e.end.y; var curNamespace = namespaceOffsets.find((val) => val.top > offsetY); if (curNamespace && selectedVal != curNamespace.id) { //TODO selectedVal = curNamespace.id; $select.val(selectedVal).trigger("change"); } }); $select.on("select2:select", function (e) { var namespaceId = $select.val(); var namespaceEl = $(".namespace-name") .toArray() .find((el) => el.innerHTML == namespaceId); triggerBySelect = true; htmlScroll.doScrollTop($(namespaceEl).offset().top - 100, 1000); }); } var DiffMatch = new diff_match_patch(); loadFeature("releaseDiff", false, function () { var releaseModalNode = document.querySelector("#releaseModal"); if (releaseModalNode == null) { return false; } bindDiffInfo(releaseModalNode); return true; }); function bindDiffInfo(node) { initDiifLib(); var observer = new MutationObserver(function () { initChangeInfoHeader(); // 每次都需要隐藏 initChangeInfoDetail(); var $cols = $("#releaseModal table tr.ng-scope"); var kvInfo = {}; for (const col of $cols) { var $col = $(col); var tds = $(col).find("td"); kvInfo = { key: tds[0].title, oldVal: tds[1].title, newVal: tds[2].title, }; buildDiffHtml( $col.find("td.diff-text"), kvInfo.key, kvInfo.oldVal, kvInfo.newVal ); } }); observer.observe(node, { attributeFilter: ["style"], }); } function toggleDiff() { $(".change-diff").toggle(); var needShow = $(".change-diff").is(":hidden"); if (needShow) { $(".change-detail").show(); } else { $(".change-detail").hide(); } } function initChangeInfoDetail() { $(".change-detail").hide(); var $cols = $("#releaseModal table tr.ng-scope"); for (var col of $cols) { var $col = $(col); if ($col.hasClass("diff-info-inited")) { return; } initChageCol(); $col.addClass("diff-info-inited"); } } function initChageCol() { var bodyRows = $("#releaseModal table tr.ng-scope"); for (var row of bodyRows) { var $row = $(row); if ($row.find("td.change-diff").length == 0) { $row.find("td:gt(0)").addClass("change-detail x-detail").hide(); $row.append( '<td class="change-diff diff-text" data-toggle="tooltip" data-placement="top" title="点击查看详细差异对比"></td>' ); } } $(".change-diff.diff-text").tooltip(); } function initChangeInfoHeader() { if ($("#releaseModal table thead tr>th").length == 0) { return; } if ($("#toggleDiff").length != 0) { return; } // 隐藏原有信息 $("#releaseModal table thead tr>th:gt(0)").addClass("change-detail").hide(); // 增加差异信息展示 var headCol = $("#releaseModal table thead tr"); headCol.append('<th class="change-diff">差异(点击查看新旧值对比)</th>'); $("#releaseModal table thead tr>th:eq(0)").append( '<button id="toggleDiff">切换显示</button>' ); $("#toggleDiff").click(function () { toggleDiff(); return false; }); } function initDiifLib() { const highlight_xcode_css = GM_getResourceText("highlight_xcode_css"); const text_different_css = GM_getResourceText("text_different_css"); GM_addStyle(highlight_xcode_css); GM_addStyle(text_different_css); } function buildDiffHtml($node, key, oldVal, newVal) { // 新增或删除 var diff = DiffMatch.diff_main(oldVal, newVal); DiffMatch.diff_cleanupSemantic(diff); var html = DiffMatch.diff_prettyHtml(diff); $node.html(html); var errorJson = isErrorJson(newVal); if (errorJson) { var $td = $node.parent().find("td:first"); var errorJsonLabelId = `${key}-errorJson`; if ($(`#${errorJsonLabelId}`).length == 0) { $td.append( `<span id="${errorJsonLabelId}" class="label label-danger">错误的json</span>` ); $td.addClass("alert alert-danger"); } } $node.on("click", function () { showDiffModal(key, newVal, oldVal); }); } function isErrorJson(val) { val = val.trim(); if (val.startsWith("{") || val.startsWith("[")) { try { JSON.parse(val); return false; } catch (e) { return true; } } return false; } loadFeature("releaseModal", true, function () { $('#releaseModal div.modal-header .modal-title:not(".ng-hide")') .append(`<span id="goReleaseMoadlBottom" class="glyphicon glyphicon-circle-arrow-down" data-tooltip="tooltip" data-placement="top" title="定位到发布按钮"></span>`); $('#releaseModal div.modal-footer') .prepend(` <span id="goReleaseMoadlTop" class="pull-left glyphicon glyphicon-circle-arrow-up" data-tooltip="tooltip" data-placement="top" title="回到顶部"></span>`); // for scroll var nicesocre = $('#releaseModal').niceScroll({cursoropacitymax: 0}); $('#goReleaseMoadlBottom').on('click',function(){ nicesocre.doScrollTop($('#goReleaseMoadlTop').offset().top, 1000); }); $('#goReleaseMoadlTop').on('click',function(){ nicesocre.doScrollTop($('#goReleaseMoadlBottom').offset().top, 1000); }); return true; }); loadFeature("showText", true, function () { var $namespaces = $(".namespace-view-table"); if ($namespaces.length == 0) { return false; } var currItem; $("#showTextModal .modal-body") .tooltip({ title: "点击查看差异对比", }) .on("click", function () { if (!currItem) { return; } if (currItem.isModified) { console.log(currItem); showDiffModal(currItem.item.key, currItem.newValue, currItem.oldValue); } }); $(".namespace-view-table div.ng-scope:not(.no-config-panel)") .filter(function (idx) { currItem = null; var $el = $(this); if ($el.hasClass("panel")) { // 关联 namespace 的覆盖配置 return true; } var ngIf = $el.attr("ng-if"); if (ngIf === "!namespace.isLinkedNamespace") { // 私有 namespace 的配置 return true; } // 关联 namespace 的配置 return false; }) .find("tbody>tr") .find("td:eq(2)") .filter(".cursor-pointer") .on("click", function (e) { var $td = $(e.currentTarget); var key = $td.prev("td").find('span:eq(0)').text().trim(); var namespace = $td .parents("section.master-panel-body.ng-scope") .find("b.namespace-name.ng-binding") .text() .trim(); var namespaceScope = $( 'div[ng-controller="ConfigNamespaceController"]' ).scope(); var namesapce = namespaceScope.namespaces.find( (e) => e.baseInfo.namespaceName === namespace ); currItem = namesapce.items.find((e) => e.item.key === key); }); }); loadFeature("help", false, function () { helpInfo(); return true; }); function helpInfo() { initFeatureInfoModal(); appendNavBar(` <li> <a href="javascript:void(0);" id="showFeatureInfo"> <span class="glyphicon glyphicon-question-sign"></span> </a> </li> `); $("#showFeatureInfo").on("click", showFeatureInfo); } function showFeatureInfo() { var data = [ { title: "json格式校验", img: "https://raw.githubusercontent.com/xyz327/old-apollo-portal-enhance/main/doc/change-diff-1.png", }, { title: "namespace跳转", img: "https://raw.githubusercontent.com/xyz327/old-apollo-portal-enhance/main/doc/gotoNamespace.png", }, ]; var content = ""; for (const val of data) { content += ` <div class="panel panel-default"> <div class="panel-heading"> <h3 class="panel-title">${val.title}</h3> </div> <div class="panel-body"> <img class="img-responsive" src="${val.img}"/> </div> </div> `; } $("#featureModalBody").html(content); $("#featureModal").modal(); } function initFeatureInfoModal() { $("body").append(` <!-- Modal --> <div class="modal fade" id="featureModal" tabindex="-1" role="dialog" aria-labelledby="myModalLabel"> <div class="modal-dialog modal-lg" role="document"> <div class="modal-content"> <div class="modal-header"> <button type="button" class="close" data-dismiss="modal" aria-label="Close"><span aria-hidden="true">×</span></button> <h4 class="modal-title">apollo-enhance 功能说明</h4> </div> <div class="modal-body" id="featureModalBody"> </div> </div> </div> </div> `); } })();