diff --git a/public/injection.js b/public/injection.js index d05d1fd..ae7eabf 100644 --- a/public/injection.js +++ b/public/injection.js @@ -1,3 +1,7 @@ +import {DEBUG as debug} from '../src/common.js'; + +const DEBUG = debug || true; + export function getInjection({sessionId}) { // Notes: // say() function @@ -8,7 +12,19 @@ export function getInjection({sessionId}) { // in future return ` { - if ( top === self ) { + const DEBUG = ${DEBUG}; + const MIN_CHECK_TEXT = 3000; // min time between checking documentElement.innerText + const MIN_NOTIFY = 5000; // min time between telling controller text maybe changed + const MAX_NOTIFICATIONS = 13; // max times we will tell controller text maybe changed + const OBSERVER_OPTS = { + subtree: true, + childList: true, + characterData: true + }; + const Top = globalThis.top; + let lastInnerText; + + if ( Top === globalThis ) { const ConsoleInfo = console.info.bind(console); const JSONStringify = JSON.stringify.bind(JSON); const TITLE_CHANGES = 10; @@ -16,6 +32,8 @@ export function getInjection({sessionId}) { const TIME_MULTIPLIER = Math.E; const sessionId = "${sessionId}"; const sleep = ms => new Promise(res => setTimeout(res, ms)); + const handler = throttle(handleFrameMessage, MIN_NOTIFY); + let count = 0; installTop(); @@ -25,7 +43,7 @@ export function getInjection({sessionId}) { say({install: { sessionId, startUrl }}); await sleep(500); beginTitleChecks(); - beginTextChecks(); + beginTextNotifications(); console.log("Installed."); } @@ -61,29 +79,72 @@ export function getInjection({sessionId}) { ConsoleInfo(JSONStringify(thing)); } - function beginTextChecks() { + function beginTextNotifications() { // listen for {textChanged:true} messages // throttle them // on leading throttle edge send message to controller with // console.info(JSON.stringify({textChanged:true})); - self.addEventListener('message', ({data, origin}) => { - try { - - } catch(e) { + self.addEventListener('message', messageParser); + console.log('Begun notifying of text changes.'); + + function messageParser({data, origin}) { + let source; + try { + ({source} = data.frameTextChangedNotification); + if ( count > MAX_NOTIFICATIONS ) { + self.removeEventListener('message', messageParser); + return; + } + count++; + handler({textChanged:{source}}); + } catch(e) { + DEBUG && console.warn('could not parse message', data, e); } - }); + } + } + + function handleFrameMessage({textChanged}) { + const {source} = textChanged; + console.log('Telling controller that text changed'); + say({textChanged:true, source, count}); } } - function beginDocumentMutationChecks() { + beginTextMutationChecks(); + + function beginTextMutationChecks() { // create mutation observer for text // throttle output - // on leading throttle edge send top.postMessage({textChanged:true}, '*'); + + const observer = new MutationObserver(check, /*throttle(check, MIN_CHECK_TEXT)*/); + observer.observe(document.documentElement || document, OBSERVER_OPTS); + + console.log('Begun observing text changes.'); + + function check() { + console.log('check'); + const textMutated = document.documentElement.innerText !== lastInnerText; + if ( textMutated ) { + DEBUG && console.log('Text changed'); + lastInnerText = document.documentElement.innerText; + Top.postMessage({frameTextChangedNotification:{source:location.href}}, '*'); + } + } } // javascript throttle function - + // source: https://stackoverflow.com/a/59378445 + function throttle(func, timeFrame) { + var lastTime = 0; + return function (...args) { + var now = new Date(); + if (now - lastTime >= timeFrame) { + func.apply(this, args); + lastTime = now; + } + }; + } } `; }