Last active
December 24, 2022 17:09
-
-
Save cw2k/02723601c1422e5fd15adf6fcb70161b to your computer and use it in GitHub Desktop.
Romeo Additions
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// ==UserScript== | |
// @name myRomeo Additions | |
// @name:de myRomeo Additions | |
// @namespace https://greasyfork.org/en/users/723211-ray/ | |
// @version 2.2.0 | |
// @description Allows to hide users, display their information on tiles, and enhances the Radar. | |
// @description:de Ermöglicht das Verstecken von Benutzern, die Anzeige ihrer Details auf Kacheln, und verbessert den Radar. | |
// @author -Ray-, Djamana | |
// @include *://*.romeo.com/* | |
// @grant GM_addStyle | |
// @require https://code.jquery.com/git/jquery-3.x-git.slim.min.js | |
// @license MIT | |
// ==/UserScript== | |
// ==== CSS ==== | |
GM_addStyle(` | |
#visits > .layer__container--wider { width:unset; max-width:1227px; } | |
.tile__bar { position:absolute; left:0; top:0; visibility:hidden; } | |
.tile__bar_action { background:rgba(0,0,0,0.4); backdrop-filter:blur(4px); display:inline-block; color:white; margin-right:1px; margin-bottom:1px; padding:0.5rem; } | |
.tile__bar_action:hover { background-color:#00A3E4; } | |
.tile__bar_action:active { background-color:#06648B; } | |
.tile:hover .tile__bar { visibility:visible; } | |
.js-romeo-badge { display:none; } /* hide Plus user icon (it is faked for enhanced tiles */ | |
div[data-testid='desktop-image'] { background-image: none; } /* hide models on login page */ | |
#visits div[class*='UnlockMoreVisitorsGrid'] { display: none; } /* hide PLUS message at bottom of visitor grid */ | |
#messenger div[class*='TruncateBlock__Content-sc-'] { -webkit-line-clamp: unset; } /* show full messages */ | |
`); | |
// ==== Script ==== | |
(function () { | |
'use strict'; | |
proxyXhr(); | |
})(); | |
// ---- Language ---- | |
const _strings = { | |
"display": { | |
"de": "Anzeige", | |
"en": "Display" | |
}, | |
"enhancedTiles": { | |
"de": "Erweiterte Kacheln", | |
"en": "Enhanced tiles" | |
}, | |
"enhancedTilesDesc": { | |
"de": "Zeigt alle Benutzerdetails auf den Kacheln. Im Radar wird dies Benutzer mit großen Kacheln darstellen.", | |
"en": "Shows all user details on tiles. The radar will display users with large tiles." | |
}, | |
"extensionTitle": { | |
"en": "Romeo Additions 2.2" | |
}, | |
"hiddenUsers": { | |
"de": "Ausgeblendete Benutzer", | |
"en": "Hidden users" | |
}, | |
"hideActivities": { | |
"de": "Auch Activities verstecken", | |
"en": "Also hide activities" | |
}, | |
"hideActivitiesDesc": { | |
"de": "Versteckt ausgeblendete Benutzer auch im Activity Stream.", | |
"en": "Removes hidden users even in the activity stream." | |
}, | |
"hideMessages": { | |
"de": "Auch Nachrichten verstecken", | |
"en": "Also hide messages" | |
}, | |
"hideMessagesDesc": { | |
"de": "Versteckt ausgeblendete Benutzer auch in der Nachrichtenliste.", | |
"en": "Removes hidden users even in the message list." | |
}, | |
"hideUser": { | |
"de": "Benutzer ausblenden (Nach Änderungen bitte die Seite Neuladen.)", | |
"en": "Hide user ( Please reload page manually to make changes take effect.)" | |
}, | |
"maxAge": { | |
"de": "Maximales Alter", | |
"en": "Maximal age" | |
}, | |
"minAge": { | |
"de": "Minimales Alter", | |
"en": "Minimal age" | |
}, | |
"sendEnter": { | |
"de": "Enter sendet Nachricht", | |
"en": "Enter sends message" | |
}, | |
"sendEnterDesc": { | |
"de": "Wenn deaktiviert, erzeugt Enter einen Absatz und Strg+Enter versendet die Nachricht.", | |
"en": "If disabled, Enter creates a new line instead, and Ctrl+Enter sends the message." | |
}, | |
"typingNotifications": { | |
"de": "Tippbenachrichtigungen", | |
"en": "Typing notifications" | |
}, | |
"typingNotificationsDesc": { | |
"de": "Wenn deaktiviert, können Empfänger nicht mehr sehen, dass eine Nachricht verfasst wird.", | |
"en": "If disabled, receivers can no longer see that a message is being composed." | |
}, | |
"viewFullImage": { | |
"de": "Bild vergrößern", | |
"en": "View full image" | |
}, | |
} | |
getFilename = (url) => url.split("/").at(-1) | |
getString = (key) => { | |
// Get current language | |
const lang = document.documentElement.getAttribute("lang") || "en" | |
// Select translation keyword | |
const translations = _strings[key] | |
// return translation - fallback#1 English translation | |
// fallback#2 example: %viewFullImage% | |
return !translations ? "%" + key + "% not in translationList" : | |
translations[lang] || | |
translations.en || | |
"%" + key + "% has no entries" | |
} | |
// ---- Settings ---- | |
const settingNs = "RA_SETTINGS:"; | |
nullIsTrue = expr => (expr === null) ? true : expr == "true" | |
nullIsFalse = expr => (expr === null) ? false : expr == "true" | |
getEnhancedTiles =() => nullIsTrue( localStorage.getItem(settingNs + "enhancedTiles") ) | |
getHiddenMaxAge =() => parseInt( localStorage.getItem(settingNs + "hiddenMaxAge")) || 99 | |
getHiddenMinAge =() => parseInt( localStorage.getItem(settingNs + "hiddenMinAge")) || 18 | |
getHiddenUsers =() => JSON.parse( localStorage.getItem(settingNs + "hiddenUsers")) || [] | |
getHideActivities =() => nullIsFalse( localStorage.getItem(settingNs + "hideActivities") ) | |
getHideMessages =() => nullIsFalse( localStorage.getItem(settingNs + "hideMessages") ) | |
getSendEnter =() => nullIsTrue( localStorage.getItem(settingNs + "sendEnter") ) | |
getTypingNotifications =() => nullIsTrue( localStorage.getItem(settingNs + "typingNotifications") ) | |
setEnhancedTiles = value => localStorage.setItem(settingNs + "enhancedTiles", value) | |
setHiddenMaxAge = value => localStorage.setItem(settingNs + "hiddenMaxAge", value) | |
setHiddenMinAge = value => localStorage.setItem(settingNs + "hiddenMinAge", value) | |
setHideActivities = value => localStorage.setItem(settingNs + "hideActivities", value) | |
setHideMessages = value => localStorage.setItem(settingNs + "hideMessages", value) | |
setSendEnter = value => localStorage.setItem(settingNs + "SendEnter", value) | |
setTypingNotifications = value => localStorage.setItem(settingNs + "typingNotifications", value) | |
setHiddenUsers = value => localStorage.setItem(settingNs + "hiddenUsers", JSON.stringify(value) ) | |
arrayRemove = (arr, value) => arr.filter(el => el != value) | |
function setUserHidden(username, hide) { | |
let hiddenUsers = getHiddenUsers(); | |
if (hide) { | |
// add item (no duplicates) | |
if ( hiddenUsers.includes(username) ) return // item already in list | |
hiddenUsers.push(username) | |
hiddenUsers.sort( (a, b) => | |
a.toLowerCase() | |
.localeCompare( | |
b.toLowerCase() | |
)); | |
} else { | |
// remove item | |
if ( !hiddenUsers.includes(username) ) return // item not in list | |
hiddenUsers = arrayRemove ( hiddenUsers, username ); | |
} | |
setHiddenUsers(hiddenUsers); | |
} | |
// ---- XHR ---- | |
filteredCount = 0 | |
filterUser = user => { | |
try { | |
// deleted User do not offer age | |
if (user.deletion_date) | |
isAgeOkay = true | |
else | |
isAgeOkay = | |
user.personal.age >= getHiddenMinAge() | |
&& user.personal.age <= getHiddenMaxAge() | |
} catch (e) { | |
console.log("[RA] filterUser failed: " + e) | |
isAgeOkay = true | |
} | |
isUserOkay = !getHiddenUsers().includes(user.name) | |
// console.log ( user.name + | |
// " isAgeOkay:" + isAgeOkay + | |
// " isUserOkay:" + isUserOkay ) | |
isOkay = isAgeOkay && isUserOkay | |
if (!isOkay) filteredCount +=1 | |
return isOkay | |
} | |
function getApiVerb(url) { | |
// Extract verb in "/api/v#/verb?" or "/api/+/verb?" . | |
const match = url.match( | |
new RegExp( "" | |
+ "(?<=/api/[\\w+]*/)" // match should starts with "/api/v#" ( positive lookbehind ) | |
+ "[\\w/-]*" // match a word and '-' and '/' | |
+ "(?=/?)" // match should end with "?" ( positive lookahead ) | |
) | |
); | |
if (match) | |
return match[0]; | |
return undefined; | |
} | |
// Sets Text on how many items where filtered as Tooltip ('Title') | |
function showFilterstatus( What, WhereToPut ) { | |
if ( !filteredCount ) return | |
var msg = getString("extensionTitle") + ": " + filteredCount + " " + What + " filtered." | |
console.log ("RA_"+ What +": " + msg ) | |
waitForKeyElements(WhereToPut, jNode => { | |
jNode[0].title = msg } ) | |
} | |
function proxyXhr() { | |
const realOpen = window.XMLHttpRequest.prototype.open; | |
window.XMLHttpRequest.prototype.open = function (method, url, async, user, password) { | |
this.addEventListener("load", () => { | |
// console.log("[RA] XHR reply: method=" + method + ", url=" + url); | |
try { | |
// Parse data. | |
const isString = typeof this.response === "string"; | |
if ( !isString ) return | |
if ( url.includes("/stream") ) return | |
const verb = getApiVerb(url); | |
if ( !verb ) return | |
let reply = JSON.parse(this.response); | |
console.log("[RA] XHR verb '" + verb + "' reply:\n", reply); | |
filteredCount = 0 | |
// Modify interesting data. | |
switch (verb) { | |
case "messages/conversations": | |
if (getHideMessages()) | |
xhrHideMessages( reply ) | |
showFilterstatus ( "conversations", "#messenger .refreshable" ) | |
break | |
case "notifications/activity-stream": | |
if (getHideActivities()) | |
reply = xhrHideActivities( reply ) | |
showFilterstatus ( "activities", ".stream" ) | |
break | |
case "session": | |
// Fake Plus to Romeo client to supress promoting plus | |
reply.is_plus = true | |
break | |
case "visitors": | |
xhrRestorePlusVisit( reply ) | |
xhrEnhanceUsers( reply ) | |
showFilterstatus ( "visitors", "#visits-received .refreshable" ) | |
break | |
case "profiles": | |
case "visits": | |
xhrEnhanceUsers( reply ) | |
showFilterstatus ( "visits", "#visits-made .refreshable" ) | |
break; | |
default: | |
return | |
} | |
// Write back possibly modified data. | |
Object.defineProperty(this, "responseText", { writable: true }); | |
this.responseText = JSON.stringify(reply); | |
} catch (e) { | |
console.log("[RA] XHR handler failed: " + e) | |
} | |
}); | |
// Forward to client. | |
return realOpen.apply(this, arguments); | |
} | |
} | |
xhrHideActivities = reply => | |
// Remove hidden users. | |
reply | |
.filter(x => filterUser( x.partner) ) | |
xhrHideMessages = reply => | |
// Remove hidden users. | |
reply.items = reply.items | |
.filter(x => filterUser( x.chat_partner ) ) | |
xhrEnhanceUsers = reply => { | |
// Remove hidden users. | |
reply.items = reply.items | |
.filter(x => filterUser( x ) ) | |
// Show as "large tiles" to display user details everywhere. | |
if ( getEnhancedTiles() ) | |
reply.items | |
.map( item => item.display.large_tile = true ) | |
} | |
xhrRestorePlusVisit = reply => | |
// Restore PLUS-visible visitors. | |
delete reply.items_limited | |
// ---- Tile UI ---- | |
waitForKeyElements(".tile > .reactView", jNode => { | |
const tile = jNode.parent(".tile")[0]; | |
// Ignore placeholder tiles. | |
var tileIsLoading = false | |
tile.classList.forEach( cls => | |
tileIsLoading |= cls.startsWith("tile--loading--") ) | |
if (tileIsLoading) return | |
// Extract user name from link. | |
// Example: 'https://www.romeo.com/profile/USERFooBar' | |
const userlink = tile.querySelector("a"); | |
const username = getFilename (userlink.href) ; | |
// Extract user avatar from link div. | |
// Example: 'url("https://www.romeo.com/assets/09114cba6c284f3a673d5f84300ab6b6.svg")' | |
const div = userlink.firstChild; | |
const divImg = window.getComputedStyle(div).getPropertyValue("background-image"); | |
const imgUrl = divImg.split('"')[1]; | |
// Add action bar. | |
const tileBar = $("<div class='tile__bar'></div>").appendTo(tile); | |
addHideUserAction( tileBar, tile, username); | |
addShowImageAction( tileBar, imgUrl); | |
}); | |
// Add showuserimage icon to tile | |
function addShowImageAction(tileBar, url) { | |
if (url.endsWith(".svg")) return; // ignore "no photo" placeholders | |
const origUrl = "/img/usr/original/0x0/" + getFilename( url ); | |
$("<a class='tile__bar_action' href='" + origUrl + "' title='" + | |
getString("viewFullImage") + "'><span class='icon icon-picture'></a>") | |
.on("click", e => { | |
debugger | |
//prevent open url | |
e.preventDefault(); | |
// Open image in div on top of the others ( z = 100) | |
$(`<div class='layer layer--spotlight' style='top:0;z-index:100;'> | |
<img src='` + origUrl + `'></img> | |
</div>`) | |
.on("click", e => e.currentTarget.remove() ) | |
.appendTo( $("#spotlight-container") ); | |
}) | |
.appendTo( tileBar ); | |
} | |
// Add hideuser icon to tile | |
function addHideUserAction(tileBar, tile, username) { | |
$("<a class='tile__bar_action' href='#' title='" + getString("hideUser") + | |
"'><span class='icon icon-hide-visit'></a>") | |
.on("click", e => { | |
e.preventDefault(); | |
setUserHidden(username, true); | |
//$(e.target).parent().parent().hide(); | |
$(tile).hide(); | |
}) | |
.appendTo(tileBar); | |
} | |
// ---- Messaging UI ---- | |
// Prevent site event handler from sending message or typing notifications. | |
waitForKeyElements(".js-send-region.layout-item > div", jNode => { | |
//TODO: Check is that is really working. | |
// before it was done via | |
// jNode[0].addEventListener("keydown", fnEnter, useCapture=true) | |
// useCapture: indicates whether events of this type will be dispatched to the registered | |
// listener before being dispatched to any EventTarget beneath it in the DOM tree. | |
// https://developer.mozilla.org/en-US/docs/Web/API/EventTarget/addEventListener?retiredLocale=de#parameters | |
jNode.on("keydown", e => { | |
const isEnter = e.key === 'Enter'; | |
const send = isEnter && ( getSendEnter() || e.ctrlKey ); | |
const allow = send || getTypingNotifications() && !isEnter; | |
if (!allow) { | |
e.stopPropagation(); | |
} | |
} ); | |
}); | |
// ---- Settings UI ---- | |
waitForKeyElements("li.js-settings > div.accordion > ul", jNode => { | |
// ^^- find Setting | |
// UL li:=Romeo= / li:About us / li:Help & Support | |
// SampleData: 'Item--2oX6- txt-truncate' | |
let itemClass = jNode.find("a").attr("class"); | |
// Make top menu item for Romeo Additions | |
$("<li><div><a class='" + itemClass + "'>" + getString("extensionTitle") + "</a></div></li>") | |
.on("click", e => { | |
// Force open the setting pane and clear any existing contents. | |
$("#offcanvas-nav > .js-layer-content").addClass("is-open"); | |
const pane = $(".js-side-content"); | |
pane.empty(); | |
// Add pane and list. | |
pane.append(` | |
<div class='layout layout--vertical layout--consume'> | |
<div class='layout-item layout-item--consume layout layout--vertical'> | |
<div class='layout-item settings__navigation p l-hidden-sm'> | |
<div class='js-title typo-section-navigation'>` + getString("extensionTitle") + `</div> | |
</div> | |
<div class='layout-item layout-item--consume'> | |
<div class='js-content js-scrollable fit scrollable'> | |
<div class="p"> | |
<div class="settings__key"> | |
<div class="layout layout--v-center"> | |
<div class="layout-item [ 6/12--sm ]"> | |
<span>` + getString("enhancedTiles") + `</span> | |
</div> | |
<div class="layout-item [ 6/12--sm ]"> | |
<div class="js-toggle-show-headlines pull-right"> | |
<div> | |
<span class="ui-toggle ui-toggle--default ui-toggle--right"> | |
<input class="ui-toggle__input" type="checkbox" id="ra_enhancedTiles"> | |
<label class="ui-toggle__label" for="ra_enhancedTiles" style="touch-action: pan-y; user-select: none; -webkit-user-drag: none; -webkit-tap-highlight-color: rgba(0, 0, 0, 0);"></label> | |
</span> | |
</div> | |
</div> | |
</div> | |
</div> | |
<div> | |
<div class="settings__description">` + getString("enhancedTilesDesc") + `</div> | |
</div> | |
<div class="layout layout--v-center"> | |
<div class="layout-item [ 6/12--sm ]"> | |
<span>` + getString("typingNotifications") + `</span> | |
</div> | |
<div class="layout-item [ 6/12--sm ]"> | |
<div class="js-toggle-show-headlines pull-right"> | |
<div> | |
<span class="ui-toggle ui-toggle--default ui-toggle--right"> | |
<input class="ui-toggle__input" type="checkbox" id="ra_typingNotifications"> | |
<label class="ui-toggle__label" for="ra_typingNotifications" style="touch-action: pan-y; user-select: none; -webkit-user-drag: none; -webkit-tap-highlight-color: rgba(0, 0, 0, 0);"></label> | |
</span> | |
</div> | |
</div> | |
</div> | |
</div> | |
<div> | |
<div class="settings__description">` + getString("typingNotificationsDesc") + `</div> | |
</div> | |
<div class="layout layout--v-center"> | |
<div class="layout-item [ 6/12--sm ]"> | |
<span>` + getString("sendEnter") + `</span> | |
</div> | |
<div class="layout-item [ 6/12--sm ]"> | |
<div class="js-toggle-show-headlines pull-right"> | |
<div> | |
<span class="ui-toggle ui-toggle--default ui-toggle--right"> | |
<input class="ui-toggle__input" type="checkbox" id="ra_sendEnter"> | |
<label class="ui-toggle__label" for="ra_sendEnter" style="touch-action: pan-y; user-select: none; -webkit-user-drag: none; -webkit-tap-highlight-color: rgba(0, 0, 0, 0);"></label> | |
</span> | |
</div> | |
</div> | |
</div> | |
</div> | |
<div> | |
<div class="settings__description">` + getString("sendEnterDesc") + `</div> | |
</div> | |
</div> | |
<div class="settings__key"> | |
<div> | |
<span>` + getString("hiddenUsers") + `</span> | |
</div> | |
<div class="separator separator--alt separator--narrow [ mb ] "></div> | |
<div class="layout layout--v-center"> | |
<div class="layout-item [ 6/12--sm ]"> | |
<span>` + getString("hideMessages") + `</span> | |
</div> | |
<div class="layout-item [ 6/12--sm ]"> | |
<div class="js-toggle-show-headlines pull-right"> | |
<div> | |
<span class="ui-toggle ui-toggle--default ui-toggle--right"> | |
<input class="ui-toggle__input" type="checkbox" id="ra_hideMessages"> | |
<label class="ui-toggle__label" for="ra_hideMessages" style="touch-action: pan-y; user-select: none; -webkit-user-drag: none; -webkit-tap-highlight-color: rgba(0, 0, 0, 0);"></label> | |
</span> | |
</div> | |
</div> | |
</div> | |
</div> | |
<div> | |
<div class="settings__description">` + getString("hideMessagesDesc") + `</div> | |
</div> | |
<div class="layout layout--v-center"> | |
<div class="layout-item [ 6/12--sm ]"> | |
<span>` + getString("hideActivities") + `</span> | |
</div> | |
<div class="layout-item [ 6/12--sm ]"> | |
<div class="js-toggle-show-headlines pull-right"> | |
<div> | |
<span class="ui-toggle ui-toggle--default ui-toggle--right"> | |
<input class="ui-toggle__input" type="checkbox" id="ra_hideActivities"> | |
<label class="ui-toggle__label" for="ra_hideActivities" style="touch-action: pan-y; user-select: none; -webkit-user-drag: none; -webkit-tap-highlight-color: rgba(0, 0, 0, 0);"></label> | |
</span> | |
</div> | |
</div> | |
</div> | |
</div> | |
<div> | |
<div class="settings__description">` + getString("hideActivitiesDesc") + `</div> | |
</div> | |
<div class="settings__key"> | |
<div class="layout layout--v-center"> | |
<div class="layout-item [ 6/12--sm ]"> | |
<span>` + getString("minAge") + `</span> | |
</div> | |
<div class="layout-item [ 6/12--sm ]"> | |
<input class="input input--block" id="ra_hiddenMinAge" type="number" min="18" max="99"/> | |
</div> | |
</div> | |
</div> | |
<div class="settings__key"> | |
<div class="layout layout--v-center"> | |
<div class="layout-item [ 6/12--sm ]"> | |
<span>` + getString("maxAge") + `</span> | |
</div> | |
<div class="layout-item [ 6/12--sm ]"> | |
<input class="input input--block" id="ra_hiddenMaxAge" type="number" min="18" max="99"/> | |
</div> | |
</div> | |
</div> | |
<div class="settings__key"> | |
<div class="js-grid-stats-selector"> | |
<div> | |
<ul class="js-list tags-list tags-list--centered" id="ra_hiddenUsers"/> | |
</div> | |
</div> | |
</div> | |
</div> | |
</div> | |
</div> | |
</div> | |
</div> | |
</div>`); | |
UI_addCheckBoxHandlers = (CssSelector, fnGetvalue, fnSetValue ) => | |
$( CssSelector ) | |
.prop("checked", fnGetvalue() ) | |
.on("change", e => | |
fnSetValue( e.target.checked ) | |
); | |
// Handle enhanced user tiles. | |
UI_addCheckBoxHandlers ( "#ra_enhancedTiles", getEnhancedTiles, setEnhancedTiles ); | |
// Handle typing notifications. | |
UI_addCheckBoxHandlers ( "#ra_typingNotifications", getTypingNotifications, setTypingNotifications ); | |
// Handle send enter. | |
UI_addCheckBoxHandlers ( "#ra_sendEnter", getSendEnter, setSendEnter ); | |
// Handle hidden interactions. | |
UI_addCheckBoxHandlers ( "#ra_hideMessages", getHideMessages, setHideMessages ); | |
UI_addCheckBoxHandlers ( "#ra_hideActivities", getHideActivities, setHideActivities ); | |
// Handle hidden age. | |
let minAge = getHiddenMinAge(); | |
let maxAge = getHiddenMaxAge(); | |
let inMinAge = $("#ra_hiddenMinAge") | |
.val(minAge) | |
.on("change", e => { | |
minAge = parseInt(e.target.value); | |
setHiddenMinAge(minAge); | |
// Handle min-max overlapse | |
if (minAge > maxAge) { | |
maxAge = minAge; | |
setHiddenMaxAge(maxAge); | |
inMaxAge.val(maxAge); | |
} | |
}); | |
let inMaxAge = $("#ra_hiddenMaxAge") | |
.val(maxAge) | |
.on("change", e => { | |
maxAge = parseInt(e.target.value); | |
setHiddenMaxAge(maxAge); | |
// Handle min-max overlapse | |
if (maxAge < minAge) { | |
minAge = maxAge; | |
setHiddenMinAge(minAge); | |
inMinAge.val(minAge); | |
} | |
}); | |
// Handle hidden user list. | |
const ul = $("#ra_hiddenUsers"); | |
getHiddenUsers().forEach( item => { | |
// Create new li > a > span | |
$("<li class='tags-list__item'/>" + | |
"<a class='js-tag ui-tag ui-tag--removable ui-tag--selected' href='#'>" + | |
"<span class='ui-tag__label'>" + item + "</span></a></li>") | |
.on("click", e => { | |
const username = $(e.target).text(); | |
setUserHidden( username , false); | |
// Remove in user list | |
// Note: 'currentTarget' is the element to which the event handler has been attached to | |
// => so here it's the li | |
$(e.currentTarget).hide(); | |
}) | |
.appendTo(ul); | |
}); //forEach | |
}) // on click | |
.appendTo(jNode); | |
}); | |
///////////////////////////// | |
// Additional library | |
// Copy and pasted from here; | |
// @-require https://greasyfork.org/scripts/383527-wait-for-key-elements/code/Wait_for_key_elements.js | |
// @-source https://www.torn.com/forums.php#/p=threads&f=67&t=16100245&b=0&a=0 | |
// since it also includes TinyMCE which is not needed | |
// ==/UserScript== | |
/*--- waitForKeyElements(): A utility function, for Greasemonkey scripts, | |
that detects and handles AJAXed content. | |
Usage example: | |
waitForKeyElements ( | |
"div.comments" | |
, commentCallbackFunction | |
); | |
//--- Page-specific function to do what we want when the node is found. | |
function commentCallbackFunction (jNode) { | |
jNode.text ("This comment changed by waitForKeyElements()."); | |
} | |
IMPORTANT: This function requires your script to have loaded jQuery. | |
*/ | |
function waitForKeyElements ( | |
selectorTxt, /* Required: The jQuery selector string that | |
specifies the desired element(s). | |
*/ | |
actionFunction, /* Required: The code to run when elements are | |
found. It is passed a jNode to the matched | |
element. | |
*/ | |
bWaitOnce, /* Optional: If false, will continue to scan for | |
new elements even after the first match is | |
found. | |
*/ | |
iframeSelector /* Optional: If set, identifies the iframe to | |
search. | |
*/ | |
) { | |
var targetNodes, btargetsFound; | |
if (typeof iframeSelector == "undefined") | |
targetNodes = $(selectorTxt); | |
else | |
targetNodes = $(iframeSelector).contents () | |
.find (selectorTxt); | |
if (targetNodes && targetNodes.length > 0) { | |
btargetsFound = true; | |
/*--- Found target node(s). Go through each and act if they | |
are new. | |
*/ | |
targetNodes.each ( function () { | |
var jThis = $(this); | |
var alreadyFound = jThis.data ('alreadyFound') || false; | |
if (!alreadyFound) { | |
//--- Call the payload function. | |
var cancelFound = actionFunction (jThis); | |
if (cancelFound) | |
btargetsFound = false; | |
else | |
jThis.data ('alreadyFound', true); | |
} | |
} ); | |
} | |
else { | |
btargetsFound = false; | |
} | |
//--- Get the timer-control variable for this selector. | |
var controlObj = waitForKeyElements.controlObj || {}; | |
var controlKey = selectorTxt.replace (/[^\w]/g, "_"); | |
var timeControl = controlObj [controlKey]; | |
//--- Now set or clear the timer as appropriate. | |
if (btargetsFound && bWaitOnce && timeControl) { | |
//--- The only condition where we need to clear the timer. | |
clearInterval (timeControl); | |
delete controlObj [controlKey] | |
} | |
else { | |
//--- Set a timer, if needed. | |
if ( ! timeControl) { | |
timeControl = setInterval ( function () { | |
waitForKeyElements ( selectorTxt, | |
actionFunction, | |
bWaitOnce, | |
iframeSelector | |
); | |
}, | |
300 | |
); | |
controlObj [controlKey] = timeControl; | |
} | |
} | |
waitForKeyElements.controlObj = controlObj; | |
} | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Based on version 2.15 of Romeo Additions I did applied a plenty refactoring and optimization.
You may try revisions to compare and see the changes.
As new functionality I add a status message when items got filtered.
It is shown via tooltip (title) when you hover over the concerning area.
Btw what is still missing is to show the version of Romeo Additions somewhere.