dev_Top_Menu_Links2

User defined links in top menu

当前为 2023-05-02 提交的版本,查看 最新版本

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

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

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

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

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

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

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

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

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

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

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

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

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

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

// ==UserScript==
// @name         dev_Top_Menu_Links2
// @namespace    http://tampermonkey.net/
// @version      1.2
// @description  User defined links in top menu
// @author       Dediggefedde
// @match        *://*.deviantart.com/*
// @require      https://ajax.googleapis.com/ajax/libs/jquery/3.4.1/jquery.min.js
// @grant        GM.setValue
// @grant        GM.getValue
// @grant        GM.addStyle
// @noframes
// ==/UserScript==
/* globals $*/

/*
settings: new page "custom links"
options:
    image, (default none) TODO: find new list of icons / UTF8 icon list
    Text
    URL, TODO: suggestions for common targets
special: sortable by drag/drop, use jquery UI?
Also: think about design issures (long menu!, new menu?, drop-menu?, collapsible?)
*/

/*
role= is the new structure definind feature of eclipse. calss names changes on navigation, ids come sparse
header[role=banner] is top menu
div[role='dialog'] is user dropdown-menu
div[role='listbox'] is the list of entries in the dropdown-menu
div[role='group'] is group of links (only found in user dropdown so far
There is span[role=option], but only used once at top (not for each option)
Within options, I use tags since no further roles/hooks are used.

for information data- attributes can be used (data-hook for identifying elements)
*/


(function () {
	"use strict";
	// var iconlink = "https://st.deviantart.net/minish/gruzecontrol/icons-gruser.gif?37";
	var plusimg = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAUCAYAAACNiR0NAAAABHNCSVQICAgIfAhkiAAAAAlwSFlzAAAR2wAAEdsBLB24oQAAABl0RVh0U29mdHdhcmUAd3d3Lmlua3NjYXBlLm9yZ5vuPBoAAAIESURBVDiNnZS%2Fa1RBEMc%2FM7Pv0MhB8ET8QQpBaysLwUqwVcHCVDaCja2NtamtVOxFiGBjae8fYJUmhWJzFokSosbc252xePcu7%2FQumNtul5nPfOfHjkQEs871x%2F3np08u3Upm3r6pCNmLbn%2Ffe%2Fd%2BbefhLL80kwZUYoMHq5fP90%2F08AjCwSPY2d3nxeuPg3l%2Bc4FikHNQZ8c9xtAgZyeZznM7RGFS6lKoa8WDCTRnx0yODjSTfxS6Q12cahGFKRk5F0a1EhFTCqvDFN5eG7w0tVMCqAkCiEJxv%2BIe1LmMYRAeFA8cuXr%2F2cpbBAxAFWlibMm9p2eHN29cPOMBtEoAAXqVddKNsVL4PcqUEo19tMFg8%2FO3ryn1rPQqmxqNFjKqC9FpSAsVBFVwbwJLBCGQzEpKKn8VPmZCvBPsoKaNXYxt1YSkKtR1mRqN%2F4K09059TcfAUfZJlHmQ6ASbvE3dxwpFxHZ%2FjPAIiAYWEQRCUpmqqXsDyd3f04IDTMVSLr6%2Bsbk10Lb1Cori7tdWzvUvCNPQUoJfP%2BtPanwQbRxUQQUQ2ZZ52%2BbRq0vrg%2BVjd5E2XSbpFXjz5M7G6pF%2BSlUpuXjT8fFiaCegVy3y9UQ6tTqAEnB8qVoAWCn7dcHL9LiIsNhyMFPyXm7S7o6G6GLrq1IdLvd7XwgcAREQFDU0mQ3n%2Bf0Bhyn%2B7DYGIGsAAAAASUVORK5CYII%3D";
	var delimg = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAUCAYAAACNiR0NAAAABHNCSVQICAgIfAhkiAAAAAlwSFlzAAAS3gAAEt4BMgl5kwAAABl0RVh0U29mdHdhcmUAd3d3Lmlua3NjYXBlLm9yZ5vuPBoAAANsSURBVDiNfVTfbxRVFP7Onbnzc4e2Cws1qDEQY9S2u9WY2CglLSD0AUwI4cVITDRGkfoPoKENEn3RB2OoT7744D9gFB4Q6cbEF8JS%2F4ZqqaE%2FoN2lc38cH3ZmmZ0QT3Izufd8891zvvPNgJlRXEcrwdzxOFh8FYjKuXydBKL3wsriB0FlrpwTKMRbSTj%2FWurNnntUmdgfBTdOEUUoxSmiaE8Y%2F1bX3sSwdS5cCJP5Yp6YGQAwE4eXx7V%2F%2FqgKq5oYy8LoX7327c12%2B8h15m0AOEcUyzC%2BOaq98YiFq8H4R5j724IXvulsft4jPJGEX7yS%2Bh9Pq7BqiKEBGDBWhNFN2bmz02lPA8BAGN98SXuNkIWb4zQYm2TXlMDCl52Nz2imElxppP5HUzqo5gADQFP3%2BS8Z05I7LYLAi9ptBEyOoX6cBpCC1wTwvSstHXvBysE0q0oXwWBUIJwx7TcMAA9wFD0ZZwmDkumY89Sg%2Fulvi5madfZ5IMqrVNS9XQEgQIAgFLrVqEK7igBLbEMWLZPKKWJmnCWq%2BGF0a0KFjYRJ5C1pAEVNy1UZAhhsYxYtlcrDl3h1qzfls0SVJIwXR7VXj1iInMBkxLmmunAOwCYs7g6kcvI8r2712aZLureyJ%2Bw0Dxg5JpmEKVWZV6UzsgErlgaUPJSTAYBbNGUNgGt7t%2FdVZUrtChBcUNn3j7%2BU96mWSL%2FTHGZ3jJiEygaSZsKnyPbU3W%2BTFctCj2lpmj9QLen7Uj6l3buEr5o1dkZcQJTbK2tXlCFisnXjLcUKh9%2Fh%2Bw9oFtVdrq%2BaVXZGnIzsfwfyhMknTPYNFf61T9tJ55Av%2FxxiZ5Tyyoh7PlPZC06Xjx8JFpqy84IfH5KlFWH2PgP%2FhHCJftkBbypwV5%2BSVg7DPG3dpYPWWwpZGJVp2tM4wx007oZrcU181dm4KASuWmBdgZEiBzNchn7Wypav3ElHickR491NWOgujnu415W%2F9rIOFs6Y1Ys9H17xhy6n4E%2FWhR3SYARM%2Bjkr7wwpOfUur2wDwI80HBvX3PrD7dSXHeNqMN5UwdqI9q6eNquPf195fO0PzW%2BBZ9eFTZ438rZUwfSHvNwu%2Buxn2h9tOer3a157%2FIBxH9S1%2F93b5t6lPtsU41u5e84hHJEqOF4mK5IqR19nxo3T5t5cMfcf2%2F8%2BXPr5xm0AAAAASUVORK5CYII%3D";
	var upimg = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAUCAYAAACNiR0NAAAABHNCSVQICAgIfAhkiAAAAAlwSFlzAAANXAAADVwB7ig%2B4wAAABl0RVh0U29mdHdhcmUAd3d3Lmlua3NjYXBlLm9yZ5vuPBoAAAIvSURBVDiNjdI9UxNBGAfw%2F7P3kuQuOiCEg6BWgryon8DGUVKKNn4EP4RN2MbWj8FYEBjrII2thY0TCxxHRQljgLwdl%2BR2H4vEmLc72Gbv5nZ%2F9%2Fx3H2JmxA0pSdQ95y0BlC77L%2FJ51nHrKQ6UkkTVcwoP7rsbzEDpy0XR%2Bdl4HodGglKSaMw7hfV77sbiou1oDRwdtfzDr0HR%2FhaNTgSlJNFccHbW1t1cNms7WjO0BrQGyuW2%2F%2BN7q0iH9YnoGCglCT%2Fr7KyuubmF%2BUHs%2F1w5Df3fx%2B19Xao9G0WHQClJXCymCyurqQ3Ps5xRaHCuniv%2FtBLutz6fD6F9UEoSwc307vLd5BPPG44ZhTYbyq%2FV1Xv%2F0%2FnmP5SYuYe5e0vLqcfe3OSYUXMQsB%2B09EHt49nTfJ41bW1BBLfcd3eWUo%2FmMvExo76FIXzWfODVTzfN9u307tQ1I0cM6%2BSkA2bAdQ0YRnxcpRgqZDAAZjgkkKtMzxTMtsKbs6rarjUUAMAQlJ3NmK8ys9ZMHNgJuUKM1xD8yzS7BRBwPN4229dXbkyZH6amrZm4swOjYhE9fJn7Uxrcb442pg0A1I0UBxqCeouHxxgIGyAAKhwEx1EjMdGbVKENkEao4lvGBgGJq1SY6GZWo6BiaEb%2FmQAkrhI5YQNgQIXxDQ3q%2F%2F2SCtFd27nkUrrHc4UKbQAd6l0K96JOQKPEMdBKclNogm2ZRyCACDAIgCBQ750ISCWNpEloju7%2FC7GBED0wwi%2FRAAAAAElFTkSuQmCC";
	var downimg = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAUCAYAAACNiR0NAAAABHNCSVQICAgIfAhkiAAAAAlwSFlzAAANOgAADToBAyIehQAAABl0RVh0U29mdHdhcmUAd3d3Lmlua3NjYXBlLm9yZ5vuPBoAAAJPSURBVDiNjdQ%2FTxRBGMfx7zOze3u3Bxycika00ljYKI0FURP%2FhMJCgYSC1tqKN3C5wk5Lw6sgZ4x2CDHR%2BKcx0TdgNBIkhzSyELmZx2JZWdi9wJNsdrPZ%2Bcxvn9kdUVXy9fBxfD6q6udGw%2B6IAQFEBAQkO4Ak8dXtRMefzSc%2F8uMDDpUaV79wseYmJhpj3iuq4D1k1%2BrBq%2FL1y9b66ndXPzy%2BAAIIgnNaCmVnEaBSHFsAs2d6vXLIe8i6VOKVJKwAAt6VQ1ni4yeM0qY7pzlwH0phBQzgjpFwr1KwCGVJxUAUHSNhVIkQgZ4rh7IJ%2BlV5QgHnyqH%2FryxQKevh%2FELthhUZw1osUAn0rBDiXLbK2avnJ1AMYLD3nnSaV7FgASw%2Fg3ocPBoYsNMnT4UhCgrEscW7csj79FOqxWY0COQpgKK4nu6qSMcE3%2F7M7Wz7l85p0hgOaAxZrIWeSxfmwNHbv6cK1qaLoypbgnm1%2BfH3nKgq7bYYc6mxOHo6nBwasnEhUdbDvU8oa4N6cKpbgix132%2FMtFrqJdsc2m0xlcuNxWYznIzrEh8FeVVQEpCl7oeN6VZLPYDkd5t2W0x8ZXhxcMBOViKJ%2B0HpUBIbyNL6u32sAGbo4Phwp1azd60lPgx5VYxIEobyeu3txlQeKwUzdOTayHNrzB1E4zxojSRhZJbXbncftDiIQfpDFqrVUr%2F5aXMKWFZPkq4sGCtJVDUr%2FbC%2BCfNJz1xvvvi7yy0UqnWzsnqze78fdiQI0EbMuTcnOiLC4K%2FuzOysFreYXP0DXyvXcr82O8gAAAAASUVORK5CYII%3D";
	var defaultSet = "[{'text':'Custom Link Settings','url': 'https://www.deviantart.com/settings/browsing#TopMenuLinks', 'icon':''},{'text':'Cute cats!','url': 'https://www.deviantart.com/search?q=cute%20cats', 'icon':''}]";


	var settingTemplateHead = `
		<span class="topmenu_header">Title</span>
		<span class="topmenu_header">URL</span>
		<span class="topmenu_header">Options</span>`;
	var settingTemplateEntry = `
		<input type="text" role="text" />
		<input type="text" role="url" />
		<span role="buttons">
			<a class="push" role="addLink" onclick="return false;">
				<img src="${plusimg}" alt="add link" title="Add Link" class="pop plus"/></a>
			<a class="push" role="delLink" onclick="return false;">
				<img src="${delimg}" alt="delete link" title="Delete Link" class="pop del"/></a>
			<a class="push" role="upLink" onclick="return false;">
				<img src="${upimg}" alt="move up" title="Move Up" class="pop up"/></a>
			<a class="push" role="downLink" onclick="return false;">
				<img src="${downimg}" alt="move down" title="Move Down" class="pop down"/></a>
		</span>`;

	var topLinks = []; //[{title, url, icon}]

	function fillGrid() {
		var gridSets = $("#daTopMenuLink2_gridset").empty();
		gridSets.append(settingTemplateHead);
		topLinks.forEach((el, ind) => {
			var entr = $(settingTemplateEntry);
			entr.closest("input[role='text']").val(el.text);
			entr.closest("input[role='url']").val(el.url);
			entr.closest("a[role='icon']").attr("imgID", el.icon).data("index", ind);
			entr.attr("index", ind);
			gridSets.append(entr);
		});
		appendHandlers();
	}
	function appendHandlers() {

		var gridSets = $("#daTopMenuLink2_gridset");
		gridSets.find("a[role=addLink]").click(function () {
			var imgind = parseInt($(this).closest("span[index]").attr("index"));
			topLinks.splice(imgind + 1, 0, {
				text: "",
				url: "",
				img: ""
			});
			GM.setValue("topLinks", JSON.stringify(topLinks));
			fillGrid();
		});

		gridSets.find("a[role=delLink]").click(function () {
			var imgind = parseInt($(this).closest("span[index]").attr("index"));
			topLinks.splice(imgind, 1);
			GM.setValue("topLinks", JSON.stringify(topLinks));
			fillGrid();
		});

		gridSets.find("a[role=upLink]").click(function () {
			var imgind = parseInt($(this).closest("span[index]").attr("index"));
			if (imgind === 0) {return;}
			var el = topLinks[imgind];
			topLinks[imgind] = topLinks[imgind - 1];
			topLinks[imgind - 1] = el;
			GM.setValue("topLinks", JSON.stringify(topLinks));
			fillGrid();
		});

		gridSets.find("a[role=downLink]").click(function () {
			var imgind = parseInt($(this).closest("span[index]").attr("index"));
			if (imgind >= topLinks.length - 1) {return;}
			var el = topLinks[imgind];
			topLinks[imgind] = topLinks[imgind + 1];
			topLinks[imgind + 1] = el;
			GM.setValue("topLinks", JSON.stringify(topLinks));
			fillGrid();
		});

		gridSets.find("input[role=text]").change(function () {
			var imgind = parseInt($(this).attr("index"));
			topLinks[imgind].text = $(this).val();
			GM.setValue("topLinks", JSON.stringify(topLinks));
		});
		gridSets.find("input[role=url]").change(function () {
			var imgind = parseInt($(this).attr("index"));
			topLinks[imgind].url = $(this).val();
			GM.setValue("topLinks", JSON.stringify(topLinks));
		});
	}

	function insertSettingsPage() {
        if(document.getElementById("daTopMenuLink2_gridset")!=null)return;

		addSettingCss();
		var section = $("div.fooview.ch");
		var custSection = section.first().clone().insertAfter(section.last()).find("div.fooview-inner");
		custSection.empty();
		//custSection.find("h3").html("Custom Links");
		//custSection.find("div.rr").remove();
		custSection.append("<h3>Custom Links</h3><span>Add links to display in your username-top-menu.</span><div id='dev_top_menu_links2_icondiag'></div>");
		var gridSets = $("<div id='daTopMenuLink2_gridset'></div>").appendTo(custSection);
		gridSets.css({
			"display": "grid",
			"grid-template-columns": "auto auto auto",
			"grid-gap": "5px",
			"margin": "10px 0"
		});
		fillGrid();
		if (location.href.indexOf("#TopMenuLinks") !== -1) {custSection[0].scrollIntoView();}
	}

	function addSettingCss() {
		GM.addStyle(`
			#daTopMenuLink2_gridset span.topmenu_header{text-align:center;font-weight:bold;}
			#daTopMenuLink2_gridset span[role=buttons]{text-align:center;}
			#daTopMenuLink2_gridset span[role=buttons] img{margin: 0 5px;}
			#daTopMenuLink2_gridset a[role=icon] img{width:100%;height:100%;}
			#daTopMenuLink2_gridset img.pop{cursor:pointer;}
			#daTopMenuLink2_gridset img.pop:active{transform: scale(0.8);}
		`);
	}

	function addElements() {

        if (location.href.indexOf("deviantart.com/settings/browsing") !== 0) {
            insertSettingsPage();
        }

        var container = $("div[role=menu]:not([dev_top_menu_links2])");
        if(container.length!=0){
            container.attr("dev_top_menu_links2",1);

            let entry=container.find("a").last();
            topLinks.forEach(el => {
                entry =entry.clone();
                entry.attr("href",el.url);
                entry.attr("title","Custom Link inserted by dev_top_menu_links2.");
                entry.addClass("dev_top_menu_links2_link");
                entry.html(el.text+"<span class='dev_tml2_marker'></span>");
                container.append(entry);
            });
        }
    }

    GM.getValue("topLinks", defaultSet).then(function (data) {
	    topLinks = JSON.parse(data);
        GM.addStyle(".dev_tml2_marker{display: inline-block;border-radius: 5px;width: 5px;height: 5px;background-color: green;margin-top: -0.9em;}}");
	    setInterval(addElements,1000);
    });
})();