// ==UserScript==
// @name Title manager
// @namespace grom
// @description Manage page titles per (sub)domain. Shift-T-M for options.
// @include http*
// @grant GM_getValue
// @grant GM_setValue
// @grant GM_deleteValue
// @version 1.0.20140314
// @run-at document-end
// ==/UserScript==
if ( GM_getValue === 'undefined' || GM_setValue === 'undefined' ) {
alert('=== Title Manager ===\n\nUnable to load or store values.\
\nPlease use supported script managers:\nGreasemonkey, Tampermonkey...');
}
var domains = GM_getValue('domains-deletable-buffer', '') || GM_getValue('domains', '').replace(/\./g, '\\.'),
match = window.location.host.toLowerCase().match(domains),
t = document.getElementsByTagName('title')[0],
tOriginal = '';
if (match) {
var _find = GM_getValue(match[0] + '-find', '');
if (_find.match(/^regex:/)) {
var _find = _find.replace(/^regex:/, '');
var _find = new RegExp(_find, 'i');
}
var _with = GM_getValue(match[0] + '-with', '');
}
if (t) {
var tOriginal = t.innerHTML;
if (_find) t.innerHTML = t.innerHTML.replace(_find, _with);
}
function tm_add(StrReg, escape, isItImport, _domain, _find, _with) {
// StrReg: is "Search for" string or regex - 'str' or 'reg'
// escape: escape dollar signs or not - 'escape' or 'noescape'
var d = document,
_domainCheck = /^[a-z0-9_\.-]+$/,
tm_error = d.getElementById('tm-error-notifier');
if (!isItImport) {
var _domain = d.getElementById('tm-domain').value.toLowerCase();
var _find = d.getElementById('tm-find').value;
var _with = d.getElementById('tm-with').value;
}
if (!_domain.match(_domainCheck)) {
tm_error.innerHTML = 'Domain invalid. Please use letters a-z, numbers 0-9, underscore _, minus - or dot .';
return;
}
// if "Search for" is regex, make sure it starts with "regex:"
if (StrReg == 'reg') {
if (!_find.match(/^regex:/)) _find = _find.replace(/^/, 'regex:');
}
// store values, if "domain" and "Search for" are valid
if (_find) { // we don't need to check for _domain, we passed _domainCheck
var domains = GM_getValue('domains', '');
if (!domains) {
GM_setValue('domains', _domain);
}
else {
var match = _domain.replace(/\./g, '\\.');
var match = new RegExp('(^|\\|)' + match + '($|\\|)');
if (!domains.match(match)) {
var domains = domains + '|' + _domain;
GM_setValue('domains', domains);
}
}
GM_setValue(_domain + '-find', _find);
if (_with) {
// if not adding as regex, escape dollar signs
if (escape == 'escape') var _with = _with.replace(/\$/g, '$$$$');
GM_setValue(_domain + '-with', _with);
}
else if (GM_getValue(_domain + '-with', '')) GM_deleteValue(_domain + '-with');
// if not in importing loop, create buffer for domains
if (!isItImport) {
var domainsDeletableBuffer = GM_getValue('domains', '').replace(/\./g, '\\.');
GM_setValue('domains-deletable-buffer', domainsDeletableBuffer);
tm_error.innerHTML = 'Success! Rule added.';
}
}
}
function tm_manage() {
var d = document;
d.documentElement.innerHTML = '';
var domains = GM_getValue('domains', '');
if (domains) {
var domains = domains.split('|');
for(var i = 0, j = domains.length; i < j; i++) {
var _find = GM_getValue(domains[i] + '-find', '');
var _with = GM_getValue(domains[i] + '-with', '');
var box = d.createElement('pre');
box.className = 'item';
box.innerHTML = '<span>' + domains[i] + '</span><br /><span>' + _find + '</span>\
<br /><span>' + _with + '</span><br /><button>Remove</button><br /><span>========</span>';
if (d.body) d.body.appendChild(box);
else d.documentElement.appendChild(box);
box.getElementsByTagName('button')[0].addEventListener('click', tm_remove);
}
}
// import
var impList = d.createElement('textarea');
impList.id = 'tm-import-list';
d.documentElement.appendChild(impList);
var imp = d.createElement('input');
imp.type = 'submit'; imp.id = 'tm-import'; imp.value = 'Import';
d.documentElement.appendChild(imp);
imp.addEventListener('click', tm_import);
// sort button if 2 or more domains
if (domains.length>1) {
var sor = d.createElement('input');
sor.type = 'submit'; sor.id = 'tm-sort'; sor.value = 'Sort';
d.documentElement.appendChild(sor);
sor.addEventListener('click', tm_sort);
}
}
function tm_remove() {
var item = this.parentNode;
var _domain = item.getElementsByTagName('span')[0].innerHTML;
GM_deleteValue(_domain + '-find');
GM_deleteValue(_domain + '-with');
var domains = GM_getValue('domains', '');
var match = _domain.replace(/\./g, '\\.');
// match: (^ or |) + single/current domain + ($ or |)
var match = new RegExp('(^|\\|)' + match + '($|\\|)');
// replace: matched single domain with ^ or |; replace: || with | or remove |$
var domains = domains.replace(match, '$1').replace(/(\|)\||\|$/g, '$1');
GM_setValue('domains', domains);
item.parentNode.removeChild(item);
}
function tm_import() {
var d = document,
list = d.getElementById('tm-import-list').value;
var list = list.match(/.+/g).join('--------').replace(/(--------)+========$/, '').split('========--------');
for(var i = 0, j = list.length; i < j; i++) {
var listB = list[i].split('--------');
if (listB[0] && listB[1]) tm_add('str', 'noescape', 'true', listB[0], listB[1], listB[2]);
}
// create buffer for domains, refresh page
var domainsDeletableBuffer = GM_getValue('domains', '').replace(/\./g, '\\.');
GM_setValue('domains-deletable-buffer', domainsDeletableBuffer);
tm_manage();
}
function tm_sort() {
GM_setValue('domains', GM_getValue('domains', '').split('|').sort().join('|'));
GM_setValue('domains-deletable-buffer', GM_getValue('domains', '').replace(/\./g, '\\.'));
tm_manage();
}
function tm_QuickMenu() {
var d = document,
box = d.createElement('div'),
isThere = d.getElementById('grom-TitleManager');
if (isThere) {
isThere.parentNode.removeChild(isThere);
return;
}
box.style = 'text-align:center!important;';
box.id = 'grom-TitleManager';
box.innerHTML = '<br /><hr><h1 style="margin:initial!important;">Title Manager</h1><p>Full title: "<strong>' + tOriginal + '</strong>"</p>\
<p id="tm-error-notifier">Regex supported only in "Search for"; use single backslash <strong>\\</strong> for escaping characters.</p>\
<p>Domain: <input type="text" id="tm-domain" value="' + window.location.host.toLowerCase() + '" /></p>\
<p>Search for: <input type="text" id="tm-find" value="' + tOriginal + '" /></p>\
<p>Replace with: <input type="text" id="tm-with" value="" /></p>\
<p><input type="submit" id="tm-add" value="Add" /> or <input type="submit" id="tm-add-regex" value="Add as regex" /></p>\
<p><input type="submit" id="tm-manage" value="View and manage all title rules" /></p><br /><br />';
if (d.body) d.body.appendChild(box);
else d.documentElement.appendChild(box);
box.scrollIntoView();
d.getElementById('tm-add').addEventListener('click', function() { tm_add('str','escape') });
d.getElementById('tm-add-regex').addEventListener('click', function() { tm_add('reg','noescape') });
d.getElementById('tm-manage').addEventListener('click', tm_manage);
}
// trigger for QuickMenu: Shift+T+M
var kbd = [];
onkeydown = onkeyup = function(e) {
kbd[e.keyCode] = e.type == 'keydown';
if (kbd[16] && kbd[84] && kbd[77]) {
tm_QuickMenu();
kbd = [];
return false;
}
}