// ==UserScript==
// @name Xhamster Middle Click Search v.2
// @namespace https://greasyfork.org/fr/users/7434-janvier56
// @version 2.0.1
// @description Middle clicking the search on Xhamster search icon opens the results in a new tab. (fork of "Youtube Middle Click Search" by Adrien Pyke)
// @icon https://external-content.duckduckgo.com/ip3/fr.xhamster.com.ico
// @author janvier57
// @author Adrien Pyke
// @include https://xhamster.com/*
// @license unlicense
// @grant GM_openInTab
// ==/UserScript==
/**
The old require is INVALID (server error 500) https://gitcdn.link/repo/fuzetsu/userscripts/b38eabf72c20fa3cf7da84ecd2cefe0d4a2116be/wait-for-elements/wait-for-elements.js
* @param obj - {
* sel: 'a', // the selector you want to wait for (optional)
* context: document.body, // scope of search for selector or mutations (optional, default document.body)
* stop: true, // stop waiting after first result (optional, default false)
* mode: 'M', // M to use mutation observer, S to use setInterval (optional, default M)
* onchange: func, // if using mode 'M' this function will be called whenever mutation handler triggers
* onmatch: func, // if selector is specified function will be called for each match with element as parameter
* config: { attributes: true } // if using mode 'M' this object will override settings passed to mutation observer
* }
*/
function waitForElems(obj) {
var tick;
var id = 'fke' + Math.floor(Math.random() * 12345);
var type = window.MutationObserver ? (obj.mode || 'M') : 'S';
var lastMutation = Date.now();
var lastCall = Date.now();
var context = obj.context;
var sel = obj.sel;
var config = obj.config || {
subtree: true,
childList: true
};
var onChange = obj.onchange;
var queuedCall;
var domLoaded = document && document.readyState !== 'loading';
function throttle(func) {
var now = Date.now();
clearTimeout(queuedCall);
// less than 100ms since last mutation
if (now - lastMutation < 100) {
// 500ms or more since last query
if (now - lastCall >= 500) {
func();
} else {
queuedCall = setTimeout(func, 100);
}
} else {
func();
}
lastMutation = now;
}
function findElem(sel) {
lastCall = Date.now();
var found = [].filter.call(context.querySelectorAll(sel), function(elem) {
return elem.dataset[id] !== 'y';
});
if (found.length > 0) {
if (obj.stop) {
type === 'M' ? tick.disconnect() : clearInterval(tick);
}
found.forEach(function(elem) {
elem.dataset[id] = 'y';
obj.onmatch(elem);
});
}
}
function connect() {
context = context || document.body;
if (type === 'M') {
tick = new MutationObserver(function() {
if (sel) throttle.call(null, findElem.bind(null, sel));
if (onChange) onChange.apply(this, arguments);
});
tick.observe(context, config);
} else {
tick = setInterval(findElem.bind(null, sel), 300);
}
if (sel) findElem(sel);
}
if(domLoaded) {
connect();
} else {
window.addEventListener('DOMContentLoaded', connect);
}
return {
type: type,
stop: function() {
if (type === 'M') {
tick.disconnect();
} else {
clearInterval(tick);
}
},
resume: connect
};
}
/**
* @param regex - should match the site you're waiting for
* @param action - the callback that will be executed when a matching url is visited
* @param stopLooking - if true the function will stop waiting for another url match after the first match
*/
function waitForUrl(regex, action, stopLooking) {
function checkUrl(urlTest) {
var url = window.location.href;
if (url !== lastUrl && urlTest(url)) {
if (stopLooking) {
clearInterval(tick);
}
lastUrl = url;
action();
}
lastUrl = url;
}
var urlTest = (typeof regex === 'function' ? regex : regex.test.bind(regex)),
tick = setInterval(checkUrl.bind(null, urlTest), 300),
lastUrl;
checkUrl(urlTest);
return tick;
}
// YOUR OWN CODE
(function () {
'use strict';
const SCRIPT_NAME = 'YMCS';
const Util = {
log(...args) {
args.unshift(`%c${SCRIPT_NAME}:`, 'font-weight: bold;color: #233c7b;');
console.log(...args);
},
q(query, context = document) {
return context.querySelector(query);
},
qq(query, context = document) {
return Array.from(context.querySelectorAll(query));
},
getQueryParameter(name, url = window.location.href) {
name = name.replace(/[[\]]/gu, '\\$&');
const regex = new RegExp(`[?&]${name}(=([^&#]*)|&|#|$)`, 'u'),
results = regex.exec(url);
if (!results) return null;
if (!results[2]) return '';
return decodeURIComponent(results[2].replace(/\+/gu, ' '));
},
encodeURIWithPlus(string) {
return encodeURIComponent(string).replace(/%20/gu, '+');
}
};
waitForElems({
// sel: '#search-icon-legacy',
//XHAM
sel: '.search-submit',
stop: true,
onmatch(btn) {
btn.onmousedown = function (e) {
if (e.button === 1) {
e.preventDefault();
}
};
btn.onclick = function (e) {
e.preventDefault();
e.stopImmediatePropagation();
// const input = Util.q('input#search').value.trim();
// XHAM
const input = Util.q('input.search-text').value.trim();
if (!input) return false;
// const url = `${location.origin}/results?search_query=${Util.encodeURIWithPlus(input)}`;
// XHAM
const url = `${location.origin}/search/${Util.encodeURIWithPlus(input)}`;
if (e.button === 1) {
GM_openInTab(url, true);
} else if (e.button === 0) {
window.location.href = url;
}
return false;
};
btn.onauxclick = btn.onclick;
}
});
waitForElems({
sel: '.sbsb_c',
onmatch(result) {
result.onclick = function (e) {
if (!e.target.classList.contains('sbsb_i')) {
const search = Util.q('.sbpqs_a, .sbqs_c', result).textContent;
const url = `${location.origin}/search/${Util.encodeURIWithPlus(search)}`;
if (e.button === 1) {
GM_openInTab(url, true);
} else if (e.button === 0) {
window.location.href = url;
}
} else if (e.button === 1) {
// prevent opening in new tab if they middle click the remove button
e.preventDefault();
e.stopImmediatePropagation();
}
};
result.onauxclick = result.onclick;
}
});
})();