Skip to content

Instantly share code, notes, and snippets.

@shu8
Last active July 17, 2023 21:39
Show Gist options
  • Star 2 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save shu8/08d86eca16fc6146e5d2 to your computer and use it in GitHub Desktop.
Save shu8/08d86eca16fc6146e5d2 to your computer and use it in GitHub Desktop.
Userscript to allow you to tag favourites and add personal notes to them on StackExchange sites
// ==UserScript==
// @name Favourites enhancer
// @namespace http://stackexchange.com/users/4337810/%E1%94%95%E1%96%BA%E1%98%8E%E1%95%8A
// @version 1.1
// @description Allows you to tag favourites and add personal notes to them
// @author ᔕᖺᘎᕊ (http://stackexchange.com/users/4337810/%E1%94%95%E1%96%BA%E1%98%8E%E1%95%8A)
// @match *://*.stackexchange.com/*
// @match *://*.stackoverflow.com/*
// @match *://*.superuser.com/*
// @match *://*.serverfault.com/*
// @match *://*.askubuntu.com/*
// @match *://*.stackapps.com/*
// @match *://*.mathoverflow.net/*
// @require https://ajax.googleapis.com/ajax/libs/jquery/1.8/jquery.min.js
// @require https://ajax.googleapis.com/ajax/libs/jqueryui/1.8/jquery-ui.min.js
// @grant GM_setValue
// @grant GM_getValue
// @grant GM_deleteValue
// ==/UserScript==
var data = [],
tags = [
['goodResource', 'Good Resources'],
['checkEdits', 'Downvoted - check for edits'],
['commonDupes', 'Common Dupe Targets'],
['other', 'Other follow-up'],
['cleanUp', 'Clean up comments']
],
cssMainDiv = {
'position': 'absolute',
'top': '50%',
'left': '50%',
'margin-top': '-50px',
'margin-left': '-50px',
'width': '400px',
'height': '300px',
'background-color': 'whitesmoke',
'overflow': 'auto',
'border-radius': '10px',
'padding': '10px',
};
//(the main div that lets you select which tag to add favourite to):
$('body').append("<div id='favouritesEnhancerMain' style='background-color:whitesmoke; width:15%; display:none; font-size:100%; z-index:2;'> \
<span style='display:block; background-color:lightgray; text-align: center; font-weight: bold; padding: 5px'>Tags</span> \
</div>");
if (GM_getValue('favouritesEnhancer')) {
var data = JSON.parse(GM_getValue('favouritesEnhancer'));
} else {
GM_setValue('favouritesEnhancer', JSON.stringify(data));
}
if (GM_getValue('favouritesEnhancerTags')) {
var tags = JSON.parse(GM_getValue('favouritesEnhancerTags'));
} else {
GM_setValue('favouritesEnhancerTags', JSON.stringify(tags));
}
addStar(); //Add the favourite star if the question has already been favourited
//Add the main dialog to add a favourite:
$.each(tags, function () {
$('#favouritesEnhancerMain').append("<span id='" + $(this)[0] + "' style='cursor:pointer;padding:5px'>" + $(this)[1] + "</span><br /><hr style='margin:0.1em;'>");
});
//Show the main dialog when you click the favourite button
$('.js-bookmark-btn').click(function (event) {
$("#favouritesEnhancerMain").show(100);
$("#favouritesEnhancerMain").offset({
left: event.pageX,
top: event.pageY
});
//Hide the main dialog when you lose focus for 2 seconds:
$(this).blur(function () {
setTimeout(function () {
$('#favouritesEnhancerMain').hide();
}, 2000);
});
});
//Click handler for when you click on the tag you want to save the favourite to:
for (i = 0; i < tags.length; i++) {
$('#' + tags[i][0]).on('click', function () {
note = prompt('Add a note for this favourite:');
data.push([$('#question-header h1 a').text(), document.URL, $(this).attr('id'), note]); //Format = [title, url, short-name, note]
GM_setValue('favouritesEnhancer', JSON.stringify(data));
});
}
//Add an empty div on the bookmarks page:
$('#user-tab-bookmarks').append("<div id='favouritesEnhancerData'></div>");
update(); //Add stuff to that div
//Click handler for deleting a specific favourite from favourites page
$('#favouritesEnhancerData').on('click', 'input[value="Delete"]', function () {
data.splice($(this).attr('id'), 1);
GM_setValue('favouritesEnhancer', JSON.stringify(data));
update();
});
//Add div for viewing/creating/deleting tags on favourites page
$('body').append("<div id='newTagFavouritesEnhancer' style='display:none;'><span id='close' style='float:right;'>close</span><span id='reset' style='float:right;'>reset&nbsp;&nbsp;&nbsp;</span><table></table></div>");
$('#newTagFavouritesEnhancer').css(cssMainDiv).draggable();
//Click handler for closing that div
$('#newTagFavouritesEnhancer #close').css('cursor', 'pointer').click(function () {
$('#newTagFavouritesEnhancer').hide();
});
//Click handler for reset - delete all values!
$('#newTagFavouritesEnhancer #reset').css('cursor', 'pointer').click(function () {
if(confirm("Are you sure you want to reset everything? All your tags and favourites will be deleted!")) {
GM_deleteValue("favouritesEnhancer");
GM_deleteValue("favouritesEnhancerTags");
update();
$('#newTagFavouritesEnhancer').hide();
}
});
update();
//Filter click handler (on favourites page) - on click, hode all divs but the desired one
$('#favouritesEnhancerData #filter span').css('cursor', 'pointer').click(function () {
that = $(this);
if ($(this).attr('id') != 'all') {
$.each(tags, function () {
if (that.attr('id') == $(this)[0]) {
$('#favouritesEnhancerData div').not('#filter').hide();
$('#favouritesEnhancerData div[id*="' + $(this)[0] + '"]').show();
}
});
} else {
$('#favouritesEnhancerData div').show();
}
});
//Click handler for when you click "(add new tag)":
$('#favouritesEnhancerData #newTag').css('cursor', 'pointer').click(function () {
$('#newTagFavouritesEnhancer').show();
});
//Click handler for creating new tag
$('#newTagFavouritesEnhancer #addNewTag').click(function () {
//Add the fields needed
$(this).after("<div id='newTagFields'>Short Name: <input id='newTagShortName'> <br /> Actual Name: <input id='newTagActualName'> <br /> <input id='saveTag' type='button' value='Save tag'></div>");
$('#newTagFavouritesEnhancer input[id="saveTag"]').click(function () {
if ($('#newTagShortName').val().indexOf(' ') > 0) { //Make sure there are no spaces in short name - because we use this for the ID of the div and related things
alert('Please make sure there are no spaces in the "Short Name"!');
} else { //If there is no space, everything is valid, so add it to the array
tags.push([$('#newTagShortName').val(), $('#newTagActualName').val()]);
$('#newTagFields').remove();
GM_setValue('favouritesEnhancerTags', JSON.stringify(tags));
update();
}
});
});
//Delete click handler (for **a tag**)
$('#newTagFavouritesEnhancer input[value="Delete"]').click(function () {
var idToDelete = $(this).attr('id'),
shortNameToDelete = tags[idToDelete][0],
empty;
$.each(data, function () { //Make empty=false IF there is a favourite that has the unwanted tag in it
if ($(this)[2] == shortNameToDelete) {
empty = false;
}
});
if (empty == false) { //If there is a favourite that is tagged with this - alert user to remove this tag from all questions
alert('Please remove all favourites from the selected tag first!');
} else { //If not, delete it!
tags.splice(idToDelete, 1);
GM_setValue('favouritesEnhancerTags', JSON.stringify(tags));
update();
}
});
function update() { //Update (or add) everything
//Set up the data div (on favourites page):
$('#favouritesEnhancerData').html("<h2 style='padding:0; margin:0; padding-top:10px;'>Favourites Enhancer</h2><span id='newTag'>(add new tag)</span><div id='filter'><span id='all'>All</span>&nbsp;|&nbsp;</div>");
//Add headers to delete/create/delete div table:
$('#newTagFavouritesEnhancer table').html("<tr><th>Short Name</th><th>Actual Name</th><th>Delete?</th></tr>");
//Add a 'new tag' button if it doesn't already exist:
if (!$('#newTagFavouritesEnhancer #addNewTag').length) {
$('#newTagFavouritesEnhancer').append("<input id='addNewTag' type='button' value='Add a new tag' style='float:left;'>");
}
$.each(tags, function (i) {
//Add data to new/delete/view div table:
$('#newTagFavouritesEnhancer table').append("<tr><td>" + $(this)[0] + "</td><td>" + $(this)[1] + "</td><td><input type='button' value='Delete' id='" + i + "'></tr>");
//Add the filter options on the favourites page:
$('#favouritesEnhancerData #filter').append("<span id='" + $(this)[0] + "'>" + $(this)[1] + "</span>&nbsp;|&nbsp;");
//Add divs that will contain the tags' data:
$('#favouritesEnhancerData').append("<div id='" + $(this)[0] + "'><h3 style='padding:0; margin:0; padding-top:10px;'>" + $(this)[1] + "</h3><hr style='margin:0.1em;'></div>");
});
$.each(data, function (i) {
that = $(this);
//If there isn't a user-defined note, add '[no note]':
if (that[3] == '' || that[3] == null) {
var note = '[no note]';
} else {
var note = that[3];
}
//Add the actual favourites to their corresponding divs:
$.each(tags, function () {
if (that[2] == $(this)[0]) { //Decides whether to add it or not
$('#user-tab-bookmarks div[id="' + $(this)[0] + '"]').append("<span id='" + i + "'> <a href='" + that[1] + "'>" + that[0] + '</a> - ' + note + "&nbsp;<input type='button' value='Delete' id='" + i + "'></span><br />");
}
});
});
}
function addStar() { //Add star to question page if the question has been favourited:
$.each(data, function (i) {
that = $(this);
if (that[1] == document.URL) {
setTimeout(function () {
//title = note
$('.js-bookmark-btn').after(`<span style='color:orange;text-align:center;font-size:25px;cursor:pointer' title='${that[3].replace(/'/gi, '&apos;').replace(/"/gi, '&quot;')}' id='favouritesEnhancer-${i}'>☆</span>`);
}, 500);
} else {
$('span[id*="favouritesEnhancer"]').remove();
}
setTimeout(function () {
//Click handler for when you click the red star on an already favourited question (remove it):
$('span[id*="favouritesEnhancer"]').on('click', function () {
if ($(this).attr('id').split(/-(.+)?/)[1] == i) {
if (window.confirm('Are you sure you want to delete this favourite?')) {
data.splice($(this).attr('id').split(/-(.+)?/)[1], 1); //Delete the favourite
GM_setValue('favouritesEnhancer', JSON.stringify(data));
$(this).remove();
}
}
});
}, 600);
});
}
@shu8
Copy link
Author

shu8 commented Mar 13, 2015

More info at StackApps

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment