Files

307 lines
11 KiB
JavaScript

/*
JWConfZoomHand
2021.08.28
(c) 2021 - JB
Some Parts from JWConf Signal 2018.04.29
(c) 2018 - Simon Lorenz - werbung@lorenzweb.net
*/
(function() {
// used locale
var requestedLocale = "de";
// switch enabled
var signalEnabled = true;
// remember testActive
var testActive = false;
// remember if zoom hand raised
var ZoomHandRaised = false;
var JWConfRaisings = 0;
// loop through table of attendees and call for observer subscription
/* function subscribeNewAttendees() {
if (signalEnabled === false) {
return;
}
var tableAttendees = document.getElementById("content").getElementsByTagName("table")[0];
if (typeof(tableAttendees) !== "undefined" && tableAttendees !== null) {
for (var i = 0, row; row = tableAttendees.rows[i]; i++) {
if (row.parentNode.localName !== "thead")
addObserver(row);
}
}
} */
function subscribeNewAttendees() {
if (signalEnabled === false) {
return;
}
var tablesAttendees = document.evaluate('//table[starts-with(@class,"listener-table")]', document, null, XPathResult.ORDERED_NODE_SNAPSHOT_TYPE, null );
var tableAttendees = null;
for ( var i=0; i < tablesAttendees.snapshotLength; i++ )
{
tableAttendees = tablesAttendees.snapshotItem(i)
for (var i = 0, row; row = tableAttendees.rows[i]; i++) {
if (row.parentNode.localName !== "thead") {
addObserver(row);
}
}
}
}
/*
wegen unten XPathResult.ORDERED_NODE_ITERATOR_TYPE durch XPathResult.ORDERED_NODE_SNAPSHOT_TYPE ersetzt (
siehe https://developer.mozilla.org/en-US/docs/Web/API/Document/evaluate
Results of NODE_SNAPSHOT types are snapshots, which are essentially lists of matched nodes. You can make changes to the document by altering snapshot nodes. Modifying the document doesn't invalidate the snapshot; however, if the document is changed, the snapshot may not correspond to the current state of the document, since nodes may have moved, been changed, added, or removed.
führt leider manchmal zu
jwconfsignal.js:46 Uncaught DOMException: Failed to execute 'iterateNext' on 'XPathResult': The document has mutated since the result was returned.
at subscribeNewAttendees (chrome-extension://hhcadpapjmemfpokloljohmahipbjhmb/jwconfsignal.js:46:42)
at chrome-extension://hhcadpapjmemfpokloljohmahipbjhmb/jwconfsignal.js:250:4 */
function updateJWConfRaisings() {
//JWConfRaisings = document.evaluate('count(//table[starts-with(@class,"listener-table")]//tr[@class="speechrequest detected"])', document, null, XPathResult.ANY_TYPE, null ).numberValue;
JWConfRaisings = document.evaluate('count(//table[starts-with(@class,"listener-table")]//tr[@class="detected speechrequest" or @class="speechrequest detected" or @style="background-color: rgb(23, 121, 186); color: rgb(254, 254, 254);" or @style="background-color: rgb(161, 184, 105); color: rgb(254, 254, 254);"])', document, null, XPathResult.ANY_TYPE, null ).numberValue;
}
function subscribeAttList() {
var x = new MutationObserver(function (e) {
if (e[0].removedNodes) {
updateJWConfRaisings();
decideZoomHand(false);
}
});
x.observe(document.getElementById("content"), { childList: true, subtree: true});
}
// add observer for any new attendee
function addObserver(addToElement) {
if (!addToElement.classList.contains('detected')) {
addToElement.classList.add('detected');
var observer = new MutationObserver(function(mutations) {
if (signalEnabled === false) {
return;
}
mutations.forEach(function(mutation) {
if (mutation.attributeName === "class") {
var attributeValue = $(mutation.target).prop(mutation.attributeName);
console.log("Class attribute", addToElement.children[0].innerText, "changed to:", attributeValue);
if (attributeValue === "detected speechrequest") {
decideZoomHand(true);
} else if (attributeValue === "detected") {
updateJWConfRaisings();
decideZoomHand(false);
}
}
});
});
observer.observe(addToElement, {
attributes: true
});
}
}
// send message to background script to raise hand in zoom if raised hand is active, else send message to lower hand
function decideZoomHand(actionRaise) {
contentElement = document.getElementById("content");
if (typeof(contentElement) !== "undefined" && contentElement !== null) {
if (actionRaise === true) {
if (ZoomHandRaised === false) {
//send message to background script which opens the ZoomRaiseHand Script
chrome.runtime.sendMessage({greeting: "raise"});
ZoomHandRaised = true;
}
} else {
// check if any other is still raising else all good, lower hand
if (JWConfRaisings > 0) {
console.log("There are some other raisings")
return;
}
if (ZoomHandRaised === true ) {
chrome.runtime.sendMessage({greeting: "raise"});
ZoomHandRaised = false;
}
}
}
}
// add on/off selector to "Live Monitor" headline
function addSelectorToMonitorHeadline() {
var headlineToFind = " Zuhörer";
var h4Elements = document.getElementsByTagName("h4");
if (typeof(h4Elements) !== "undefined" && h4Elements !== null) {
for (var i=0, h4Element; h4Element = h4Elements[i]; i++) {
if (typeof(h4Element.childNodes) !== "undefined" && h4Element.childNodes !== null) {
for (var ii=0, childNode; childNode = h4Element.childNodes[ii]; ii++) {
if (typeof(childNode.nodeValue) !== "undefined" && childNode.nodeValue !== null) {
if (childNode.nodeValue.startsWith(headlineToFind)) {
// add selector
var selectorElem = document.createElement("div");
selectorElem.style = "display: inline-block; margin-left: 10px;height: 22px;background-color: #c60f13;width: 49px;";
selectorElem.innerHTML = '<div id="switchSignalSelector" style="background-color: white; width: 18px; height: 14px; margin-top: 4px; margin-left: 27px;"></div>'
selectorElem.id = 'signalSelector';
selectorElem.addEventListener("click", function( e ) {
toggleSelectorSignal();
});
selectorElem.addEventListener("contextmenu", function( e ) {
openTestMenu();
e.preventDefault();
}, false);
h4Element.insertBefore(selectorElem, h4Element.childNodes[ii+1]);
// add test menu (originally color picker)
var testMenuElem = document.createElement("div");
testMenuElem.style = "position: absolute; top: 100px; left: 50px; display: none; background-color: #0a0a0a; color: #dadada; padding: 10px; font-size: 1rem; min-width:250px; min-height:170px; border: 2px solid #cacaca; -webkit-box-shadow: 10px 10px 20px 0px rgba(0,0,0,0.75); -moz-box-shadow: 10px 10px 20px 0px rgba(0,0,0,0.75); box-shadow: 10px 10px 20px 0px rgba(0,0,0,0.75); z-index: 1;";
testMenuElem.innerHTML = /*getMessage("configMenu_Language") + '&nbsp;&nbsp;<select id="languageSel" name="language" size="1" style="height: 1.5rem; font-size: 1.0rem; padding: .1rem .1rem .1rem .5rem; width: 150px;"><option>English</option><option>Deutsch</option><option>Ελληνική</option><option>Italiano</option><option>Français</option></select><br>' + */ '<input type="submit" id="btnTestJWConfSignal" style="color: black; float: left;"; value="' + getMessage("configMenu_Test") + '"/><input type="submit" id="btnCloseJWConfSignal" style="color: black; float: right;"; value="' + getMessage("configMenu_Close") + '"/>'
testMenuElem.id = 'testMenuDiv';
h4Element.insertBefore(testMenuElem, h4Element.childNodes[ii+2]);
// handle test
$('#btnTestJWConfSignal').click(function() {
if (testActive !== true) {
startTest();
}
});
// handle close
$('#btnCloseJWConfSignal').click(function() {
stopTest();
closeTestMenu();
});
return;
}
}
}
}
}
}
}
//open test menu
function openTestMenu() {
var testMenuDivElem = document.getElementById("testMenuDiv");
if (typeof(testMenuDivElem) !== "undefined" && testMenuDivElem !== null) {
testMenuDivElem.style.display = "block";
}
}
//close test menu
function closeTestMenu() {
var testMenuDivElem = document.getElementById("testMenuDiv");
if (typeof(testMenuDivElem) !== "undefined" && testMenuDivElem !== null) {
testMenuDivElem.style.display = "none";
}
}
function startTest() {
testActive = true;
decideZoomHand(true);
}
function stopTest() {
testActive = false;
decideZoomHand(false);
}
function setSubscriptions() {
subscribeNewAttendees();
}
function toggleSelectorSignal() {
if (signalEnabled === true) {
var signalElem = document.getElementById("signalSelector");
if (typeof(signalElem) !== "undefined" && signalElem !== null) {
signalElem.style.background = "#cacaca";
}
signalElem = document.getElementById("switchSignalSelector");
if (typeof(signalElem) !== "undefined" && signalElem !== null) {
signalElem.style.marginLeft = "5px";
}
signalEnabled = false;
} else {
var signalElem = document.getElementById("signalSelector");
if (typeof(signalElem) !== "undefined" && signalElem !== null) {
signalElem.style.background = "#c60f13";
}
signalElem = document.getElementById("switchSignalSelector");
if (typeof(signalElem) !== "undefined" && signalElem !== null) {
signalElem.style.marginLeft = "27px";
}
signalEnabled = true;
setSubscriptions();
}
}
function getMessage(msgName) {
var localMsg = requestedLocale+"_"+msgName;
return chrome.i18n.getMessage(localMsg);
}
function startNewAttendeesDetection() {
// check for new attendees every 15 sec
window.setInterval(function() {
subscribeNewAttendees();
}, 15000);
}
function detectedLiveMonitorHeadlineElement() {
var h4Elements = document.getElementsByTagName("h4");
if (typeof(h4Elements) !== "undefined" && h4Elements !== null) {
for (var i=0, h4Element; h4Element = h4Elements[i]; i++) {
if (typeof(h4Element.childNodes) !== "undefined" && h4Element.childNodes !== null) {
for (var ii=0, childNode; childNode = h4Element.childNodes[ii]; ii++) {
if (typeof(childNode.nodeValue) !== "undefined" && childNode.nodeValue !== null) {
if (childNode.nodeValue.startsWith(" Zuhörer")) {
return true
}
}
}
}
}
}
return false;
}
function waitForTelcoElements() {
if (detectedLiveMonitorHeadlineElement() === false) {
setTimeout(function () {
waitForTelcoElements();
}, 1000);
} else {
addSelectorToMonitorHeadline();
startNewAttendeesDetection();
subscribeAttList();
//die beiden // in der folgenden Zeile entfernen, wenn sich die Konferenz automatisch verbinden soll bzw. // davor setzen wenn sie manuell verbunden werden soll
//setTimeout(function(){ document.evaluate('//*[@id="left-column"]/div/div[2]/div[2]/button', document, null, XPathResult.FIRST_ORDERED_NODE_TYPE, null ).singleNodeValue.click(); }, 1000);
}
}
function startup() {
// runs ones when page is loaded, but telco attendees are added dynamically
waitForTelcoElements();
}
startup();
})();