Skip to content

Instantly share code, notes, and snippets.

@JaneOri
Created July 11, 2018 03:29
Show Gist options
  • Save JaneOri/da84cc2bb6087db5f041387b0a586e6c to your computer and use it in GitHub Desktop.
Save JaneOri/da84cc2bb6087db5f041387b0a586e6c to your computer and use it in GitHub Desktop.
inserted and removed callbacks for given selectors. Useful for user scripts or other hacks when you don't have source access.
// Given parent container selector and child selector, call inserted and removed for elements that match the selector.
// Inserted and removed callbacks are called with an array of the relevant matching dom nodes.
// Intention is to use this for User Scripts or other cases when you don't have access to source
//## Begin Selector Observation Code
var selectors = [];
(new MutationObserver(
function (mutationsList) {
var s, selector, nodeMatches
var slen = selectors.length
for (s = 0; s < slen; s++) {
selector = selectors[s]
nodeMatches = node => node.nodeType === 1 && node.matches(selector.childSelector)
mutationsList.forEach(mu => {
if (mu.type === "childList" && mu.target.matches(selector.parentSelector)) {
var addedMatches = Array.prototype.filter.call(mu.addedNodes, nodeMatches)
var removedMatches = Array.prototype.filter.call(mu.removedNodes, nodeMatches)
addedMatches.length && selector.inserted.call(null, addedMatches)
removedMatches.length && selector.removed.call(null, removedMatches)
}
})
}
}
)).observe(document.documentElement, {
childList: true,
subtree: true
})
// watch the parentSelector for the specific children to be added or removed,
// call inserted as that parentSelector > children are added and they match childSelector
// call removed as that parentSelector > children are removed and they match childSelector (note they won't be in the dom any more)
// inserted and removed callbacks are called with the matching elements passed in as the only parameter (is an array)
var onParentChildSelectors = function (opts) {
var nullFn = () => {}
selectors.push(Object.assign({
parentSelector: "",
childSelector: "",
inserted: nullFn,
removed: nullFn
}, opts))
}
// remove all watch selectors:
// offSelector({ parentSelector }) -> matching that selector
// offSelector({ parentSelector, childSelector }) -> matching that selector
// offSelector({ parentSelector, inserted }) -> matching that parentSelector && matching that inserted function
// offSelector({ parentSelector, childSelector, inserted }) -> matching that selector && matching that inserted function
// offSelector({ parentSelector, childSelector, removed }) -> matching that selector && matching that removed function
// offSelector({ parentSelector, childSelector, inserted, removed }) -> matching that selector, inserted function, and removed function
var offSelector = function (opts) {
for (let s = 0; s < selectors.length; s++) {
let selectorObj = selectors[s]
let comp = Object.assign({}, selectorObj, opts)
let matchingProps = ["parentSelector", "childSelector", "inserted", "removed"].filter(prop => selectorObj[prop] === comp[prop])
if (matchingProps.length === 4) {
selectors.splice(s, 1)
s--
}
}
}
//## End Selector Observation Code
var handleNewChat = function (chatEl) {
var escapedId = chatEl.id.replace(/%/g, "\\%")
var user = chatEl.querySelector("#author-name").textContent.trim()
var messageEl = chatEl.querySelector("#message")
var message = messageEl.textContent.trim()
userInfo[user] = {
user,
userNameRx: new RegExp("@" + escapeRegExp(user) + "\\b", "gi"),
lastId: chatEl.id,
escapedId,
lastMessage: message
}
decorateMessage(messageEl)
}
onParentChildSelectors({
parentSelector: "yt-live-chat-renderer #chat #items",
childSelector: "yt-live-chat-text-message-renderer, yt-live-chat-paid-message-renderer",
inserted: addedChatEls => addedChatEls.forEach(handleNewChat)
// removed
})
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment