Skip to content

Instantly share code, notes, and snippets.

@Aran-Fey
Last active May 17, 2018 09:07
Show Gist options
  • Save Aran-Fey/d7f1776fbf00e9364411ecd60be569de to your computer and use it in GitHub Desktop.
Save Aran-Fey/d7f1776fbf00e9364411ecd60be569de to your computer and use it in GitHub Desktop.
// ==UserScript==
// @name SE reorder favorite tags
// @version 1.0.1
// @description Allows you to reorder your favorite tags with drag'n'drop
// @author Paul Pinterits
// @include *://*.stackexchange.com/questions/tagged/*
// @include *://meta.serverfault.com/questions/tagged/*
// @include *://meta.stackoverflow.com/questions/tagged/*
// @include *://meta.superuser.com/questions/tagged/*
// @include *://serverfault.com/questions/tagged/*
// @include *://stackoverflow.com/questions/tagged/*
// @include *://superuser.com/questions/tagged/*
// @grant GM_setValue
// @grant GM_getValue
// ==/UserScript==
"use strict;"
let tag_container = document.querySelector('.js-watched-tag-list');
function get_storage_key(){
return document.location.host + '_tag_order';
}
function load_order(){
let key = get_storage_key();
let order = GM_getValue(key, '');
if (order.length === 0)
return [];
return order.split(',');
}
function save_order(order){
let key = get_storage_key();
GM_setValue(key, order.join(','));
}
function find_tags(){
return tag_container.getElementsByClassName('post-tag');
}
function find_insert_position(x, y, elements){
let rects = elements.map(e => e.getBoundingClientRect());
var i = 0;
for (; i < rects.length; i++){
let rect = rects[i];
if (y <= rect.bottom)
break;
}
for (; i < rects.length; i++){
let rect = rects[i];
let center = (rect.x + rect.right) / 2;
if (x < center)
break;
}
return i;
}
function remove_tag(tag){
let parent = tag.parentElement;
parent.parentElement.removeChild(parent);
}
function on_drag_start(tag, event){
event.dataTransfer.setData("text", tag.textContent);
}
function make_draggable(tag){
tag.draggable = true;
tag.ondragstart = on_drag_start.bind(null, tag);
}
function on_drag_over(event){
event.preventDefault();
}
function on_drop(event){
let tag_name = event.dataTransfer.getData("text");
let tags = Array.from(find_tags());
let cur_index = tags.findIndex(t => t.textContent === tag_name);
let tag = tags[cur_index];
let new_index = find_insert_position(event.clientX, event.clientY, tags);
let parent = tag.parentElement.parentElement;
if (new_index !== cur_index){
remove_tag(tag);
if (new_index === tags.length)
parent.appendChild(tag.parentElement);
else
parent.insertBefore(tag.parentElement, tags[new_index].parentElement);
}
let order = Array.from(find_tags()).map(t => t.textContent);
save_order(order);
event.preventDefault();
}
function reorder_tags(tags){
let order = load_order();
let order_dict = {};
for (let i = 0; i < order.length; i++){
let tag = order[i];
order_dict[tag] = i;
}
let tags_array = Array.from(tags);
tags_array.sort((a, b) => (order_dict[a.textContent] - order_dict[b.textContent]) || -1);
let elements = tags_array.map(t => t.parentElement);
let parent = elements[0].parentElement;
for (let elem of elements)
parent.appendChild(elem);
}
function run(){
let tags = find_tags();
if (tags.length === 0)
return;
reorder_tags(tags);
for (let tag of tags)
make_draggable(tag);
tag_container.ondragover = on_drag_over;
tag_container.ondrop = on_drop;
// FIXME: react to tags being added or removed
}
run();
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment