Skip to content

Instantly share code, notes, and snippets.

@kui
Last active August 29, 2015 14:01
Show Gist options
  • Save kui/9c37177a61933158737f to your computer and use it in GitHub Desktop.
Save kui/9c37177a61933158737f to your computer and use it in GitHub Desktop.
Hipchat のブラウザクライアントで、右カラムのルーム一覧の中で、赤字のルームと選択中のルームを上に持ってくるやつ。
// ==UserScript==
// @name Hipchat Room Sort by Alert
// @include https://*.hipchat.com/chat
// ==/UserScript==
'use strict';
function main() {
console.log('# Hipchat Room Sort by Alert');
startAlertOserver();
}
// Callbacks which is called when the classes is added or removed
// to the "class" attr of the room node.
var CLASS_MUTATION_CALLBACKS = [
function(addedClassNames, removedClassNames, room) {
if (addedClassNames.indexOf('alert') < 0) return;
moveToAlerteds(room);
},
function(addedClassNames, removedClassNames, room) {
if (addedClassNames.indexOf('selected') < 0
&& removedClassNames.indexOf('alert') < 0) return;
moveToNonAlerteds(room);
}
];
function startAlertOserver() {
var observer = new MutationObserver(function (mutations) {
var isChild = haveChildNode.bind(null, tabs());
handleMutations(
mutations
.filter(function (m) { return m.type === 'attributes'; })
.filter(function (m) { return m.attributeName === 'class'; })
.filter(function (m) { return isChild(m.target); }));
});
function start() {
var t = tabs();
if (!t || !lobby()) retry(start);
observer.observe(
t,
{ attributes: true,
subtree: true,
attributeOldValue: true,
attributeFilter: ['class'] });
}
start();
}
function retry(f) {
console.log('retry: %o', f);
requestAnimationFrame(f);
}
function handleMutations(mutations) {
var map = {};
mutations.forEach(function(m) {
var name = m.target.getAttribute('name');
if (map.hasOwnProperty(name)) {
var o = map[name];
map[name] = { oldValue: o.oldValue, node: m.target };
} else {
map[name] = { oldValue: m.oldValue, node: m.target };
}
});
for (var p in map) {
if (!map.hasOwnProperty(p)) continue;
var a = map[p];
handleMutation(a.node, a.oldValue);
}
}
function handleMutation(node, oldValue) {
var newClassList = (node.classList) ? toArray(node.classList) : [];
var oldClassList = (oldValue) ? removeEmpties(oldValue.split(/\s+/)) : [];
if (newClassList.length === 0 && oldClassList.length === 0) return;
console.log('%o => %o', oldClassList, newClassList);
var addedClassList = [];
newClassList.forEach(function(c) {
if (oldClassList.indexOf(c) < 0) addedClassList.push(c);
});
var removedClassList = [];
oldClassList.forEach(function(c) {
if (newClassList.indexOf(c) < 0) removedClassList.push(c);
});
CLASS_MUTATION_CALLBACKS.forEach(function(f) {
f(addedClassList, removedClassList, node);
});
}
function removeEmpties(list) {
return list.filter(function(e) { return e.length != 0; });
}
function haveClass(node, className) {
if (!node || !node.classList) return false;
return node.classList.contains(className);
}
function moveToAlerteds(node) {
console.log('move to alerteds: %o', node);
insertAfter(lobby(), node);
}
function moveToNonAlerteds(node) {
console.log('move to non-alerteds: %o', node);
var headNonAlerted = find(toArray(rooms()), function(e) {
return node !== e && !haveClass(e, 'alert');
});
insertBefore(headNonAlerted, node);
}
function find(arr, condition) {
for (var i = 0; i < arr.length; i++) {
var e = arr[i];
if (condition(e))
return e;
}
}
function haveChildNode(parent, child) {
if (!parent || !child) return false;
var children = toArray(parent.childNodes);
if (!children || children.length === 0) return false;
return children.indexOf(child) >= 0;
}
function lobby() {
return querySelector('#tab_lobby');
}
function tabs() {
return querySelector('#tabs');
}
function rooms() {
return querySelectorAll('#tab_lobby ~ li');
}
var querySelector = document.querySelector.bind(document);
var querySelectorAll = document.querySelectorAll.bind(document);
function toArray(a) {
return Array.prototype.slice.call(a, 0);
}
function insertAfter(node, newNode) {
node.parentNode.insertBefore(newNode, node.nextSibling);
}
function insertBefore(node, newNode) {
node.parentNode.insertBefore(newNode, node);
}
main();
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment