apollo-enhance

make old apollo better

Ajankohdalta 3.8.2022. Katso uusin versio.

// ==UserScript==
// @name         apollo-enhance
// @namespace    apollo-enhance
// @version      0.8.1
// @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       xizhouxi
// @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

// ==/UserScript==

(function () {
  "use strict";
  console.log("===start");
  //var jq = $.noConflict();
  var DiffMatch = new diff_match_patch();

  $ = unsafeWindow.$;
  var namespaceLoaded = false;
  function getAppId() {
    let hash = location.hash;
    if (hash) {
      hash = hash.substring(2);
      const url = new URL("http://localhost?" + hash);
      return url.searchParams.get("appid");
    }
  }

  loadFeature("diff", false, function () {
    var releaseModalNode = document.querySelector("#releaseModal");
    if (releaseModalNode == null) {
      return false;
    }
    bindDiffInfo(releaseModalNode);
    return true;
  });
  loadFeature("fixNiceScroll", false, function () {
    $(document).ready(function () {
      // 放在初始化之后执行
      setTimeout(function () {
        $("html").css("overflow", "");
      }, 200);
    });
    return true;
  });

  loadFeature("gotoNamespace", true, function () {
    var $namespaces = $(".namespace-name");
    if ($namespaces.length == 0) {
      return false;
    }
    goToNamespace($namespaces);
    namespaceLoaded = true;
    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;
  });

  function loadFeature(name, reloadOnHashChange, feature) {
    loadFeature0(name, feature, false);
    if (reloadOnHashChange) {
      $(window).on("hashchange", function (e) {
        loadFeature0(name, feature, true);
      });
    }
  }

  function loadFeature0(name, feature, isReloadByHash) {
    try {
      var clear = setInterval(function () {
        if (feature(isReloadByHash)) {
          console.log(`loadFeature: ${name} finished`);
          clearInterval(clear);
        }
      }, 1000);
    } catch (e) {
      console.error(`load feature failed :${name}`, e.message);
    }
  }

  // ===== goToNamespace ...

  function goToNamespace($namespaces) {
    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");
      });
    }

    $("#goToNamespace").remove();
    var list = "";
    var namespaceOffsets = [];
    var lastNamespaceId = "application";
    for (const namespace of $namespaces) {
      var $namespace = $(namespace);
      var namespaceVal = $namespace.text();
      var namespaceId = $namespace.text().replaceAll(".", "-");
      namespaceOffsets.push({
        top: $namespace.offset().top,
        id: lastNamespaceId,
      });
      lastNamespaceId = namespaceId;
      $namespace.after(`<a href="#${namespaceId}" id="${namespaceId}"></a>`);
      list += `<option value="${namespaceId}">${namespaceVal}</option>`;
    }

    var $navBar = $("#bs-example-navbar-collapse-1");
    $navBar.append(`
        <div id="goToNamespace" class="nav navbar-nav navbar-right" style="margin-top: 10px;">
        <select id="namespaceSelecter">${list}</select>
        </div>
        `);

    var $select = $("#namespaceSelecter");
    $select.select2({
      placeholder: "跳转到 Namespace",
    });
    $select.on("select2:open", function (e) {
      $("#select2-namespaceSelecter-results").css({ "max-height": "400px" });
    });
    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 $namespaceNode = $(`#${namespaceId}`);
      triggerBySelect = true;
      htmlScroll.doScrollTop($namespaceNode.offset().top - 100, 1000);
    });
  }

  // =========== diff code

  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);
    initDiffModal();
  }
  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);

    $node.on("click", function () {
      const tdfh = new TextDifferentForHtml(
        $("#diff-container")[0], // The dom used to render the display code
        "json" // Type of code
      );
      $("#diff-detail-title").html(`${key}`);
      tdfh.render({
        oldCode: toPerttyJson(oldVal), // Old code
        newCode: toPerttyJson(newVal), // New code
        hasLineNumber: false, // Whether to display the line number
      });
      $("#diffModal").modal();
    });
  }

  function toPerttyJson(val) {
    try {
      return JSON.stringify(JSON.parse(val), null, 2);
    } catch (e) {
      return val;
    }
  }
  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">&times;</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 class="label label-default">旧值</span></div>
                <div class="col-xs-6 text-center"><span class="label label-success">新值</span></div>
              </div>
              <div id="diff-container" style="display:flex"></div>
          </div>
        </div>
      </div>
    </div>
    `);
  }
  // libs
})();