-
Notifications
You must be signed in to change notification settings - Fork 6
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #8 from CircuitVerse/fix/location
Embed Location Fix + Multiple Circuits Embed
- Loading branch information
Showing
2 changed files
with
193 additions
and
85 deletions.
There are no files selected for viewing
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
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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,76 +1,186 @@ | ||
chrome.extension.sendMessage({}, function(response) { | ||
var readyStateCheckInterval = setInterval(function() { | ||
if (document.readyState === "complete") { | ||
clearInterval(readyStateCheckInterval); | ||
|
||
// ---------------------------------------------------------- | ||
// This part of the script triggers when page is done loading | ||
console.log("Hello. This message was sent from scripts/inject.js"); | ||
// ---------------------------------------------------------- | ||
|
||
function getEmbedLocation() { | ||
return document.getElementsByClassName("punch-full-screen-element")[0]; | ||
} | ||
|
||
function embed(url) { | ||
var ifrm = document.createElement('iframe'); | ||
ifrm.setAttribute('id', 'circuitverse-iframe'); // assign an id | ||
ifrm.setAttribute('class', 'circuitverse-iframe'); // assign an id | ||
ifrm.setAttribute('style','width:100%;height:100%;position:fixed;top:0px;left:0px;z-index:100') | ||
|
||
var location = getEmbedLocation(); | ||
if(location == undefined) {return;} | ||
location.appendChild(ifrm); // to place at end of document | ||
|
||
// assign url | ||
ifrm.setAttribute('src', url); | ||
iframe_embedded = true; | ||
url_embedded = url; | ||
} | ||
|
||
function removeEmbed() { | ||
if(!iframe_embedded)return; | ||
iframe_embedded = false; | ||
var iframe = document.getElementById('circuitverse-iframe'); | ||
if(iframe) iframe.parentNode.removeChild(iframe); | ||
} | ||
|
||
var url_embedded = undefined; | ||
var iframe_embedded = false; | ||
|
||
function main() { | ||
var iframes = document.getElementsByClassName('punch-present-iframe'); | ||
if(iframes.length == 0) { | ||
removeEmbed(); | ||
return; | ||
} | ||
iframeDocument = iframes[0]; | ||
if(iframe_embedded) { | ||
document.getElementsByClassName("punch-present-iframe")[0].contentWindow.document.body.focus(); | ||
} | ||
|
||
var text = iframeDocument.contentWindow.document.body.innerHTML; | ||
|
||
var re = /xlink:href="([(http(s)?):\/\/(www\.)?a-zA-Z0-9@:%._\+~#=]{2,256}\.[a-z]{2,6}\b([-a-zA-Z0-9@:%_\+.~#?&//=]*))"/g; | ||
var m; | ||
do { | ||
m = re.exec(text); | ||
if (m) { | ||
var url = m[1]; | ||
if(url.includes("circuitverse.org")) { | ||
if(iframe_embedded && url_embedded == url) return; | ||
if(iframe_embedded && url_embedded != url) { | ||
removeEmbed(); | ||
} | ||
embed(url); | ||
return; | ||
} | ||
} | ||
} while (m); | ||
removeEmbed(); | ||
} | ||
|
||
setInterval(main, 1000); | ||
} | ||
}, 10); | ||
}); | ||
var readyStateCheckInterval = setInterval(function() { | ||
if (document.readyState === 'complete') { | ||
clearInterval(readyStateCheckInterval); | ||
|
||
// Specific location which allows the iframe embedded to be visible | ||
function getEmbedLocation() { | ||
return document.getElementsByClassName('punch-full-screen-element')[0]; | ||
} | ||
|
||
// Extract slide number from the presentation | ||
function getSlideNumber() { | ||
var labelElement = | ||
getSlideIframe().contentWindow.document.getElementsByClassName( | ||
'punch-viewer-svgpage-a11yelement')[0]; | ||
if (!labelElement) return -1; | ||
var label = labelElement.getAttribute('aria-label'); | ||
return parseInt(label.match(/Slide (\d*)/)[1]); | ||
} | ||
|
||
// Get the slide iframe | ||
function getSlideIframe() { | ||
return document.getElementsByClassName('punch-present-iframe')[0]; | ||
} | ||
|
||
// Get the slide dimensions in svg values | ||
function getSlideSvgViewDimensions() { | ||
var svgContainer = | ||
getSlideIframe().contentWindow.document.getElementsByClassName( | ||
'punch-viewer-svgpage-svgcontainer')[0]; | ||
var svg = svgContainer.children[0]; | ||
var viewBox = svg.getAttribute('viewBox').split(' '); | ||
|
||
return { | ||
slideW: parseFloat(viewBox[2]), slideH: parseFloat(viewBox[3]) | ||
} | ||
} | ||
|
||
// Extract position and size of embedded image in SVG | ||
// Needed for identifying exact location to embed the iframe | ||
function extractPositionFromPath(path) { | ||
var svgLinkPath = path.getAttribute('d'); | ||
var pathRegexExp = | ||
/M ([\S]*) ([\S]*) L ([\S]*) ([\S]*) ([\S]*) ([\S]*) ([\S]*) ([\S]*) Z/; | ||
var matches = svgLinkPath.match(pathRegexExp); | ||
var x1 = parseFloat(matches[1]); | ||
var y1 = parseFloat(matches[2]); | ||
var x2 = parseFloat(matches[3]); | ||
var y3 = parseFloat(matches[6]); | ||
var widthInSvg = x2 - x1; | ||
var heightInSvg = y3 - y1; | ||
return { | ||
svgX: x1, svgY: y1, svgW: widthInSvg, svgH: heightInSvg | ||
} | ||
} | ||
|
||
// Get slide dimensions and offsets in pixels | ||
function getSlideDimensions() { | ||
var slideDiv = | ||
getSlideIframe().contentWindow.document.getElementsByClassName( | ||
'punch-viewer-content')[0]; | ||
var metadata = { | ||
xOffsetPx: parseFloat(slideDiv.style.left), | ||
yOffsetPx: parseFloat(slideDiv.style.top), | ||
slideWidthPx: parseFloat(slideDiv.style.width), | ||
slideHeightPx: parseFloat(slideDiv.style.height), | ||
}; | ||
return metadata; | ||
} | ||
|
||
// Create circuitverse iframe from anchor tag | ||
// Calculates exact position and places the iframe | ||
function createEmbedIframe(anchorTag) { | ||
var url = | ||
anchorTag.getAttributeNS('http://www.w3.org/1999/xlink', 'href'); | ||
var {svgX, svgY, svgW, svgH} = | ||
extractPositionFromPath(anchorTag.children[0]); | ||
var {slideW, slideH} = getSlideSvgViewDimensions(); | ||
var {xOffsetPx, yOffsetPx, slideWidthPx, slideHeightPx} = | ||
getSlideDimensions(); | ||
|
||
var svg2px = slideWidthPx / slideW; | ||
|
||
var absoluteXoffSetPx = xOffsetPx + svgX * svg2px; | ||
var absoluteYoffSetPx = yOffsetPx + svgY * svg2px; | ||
var widthPx = svgW * svg2px; | ||
var heightPx = svgH * svg2px; | ||
absoluteXoffSetPx = Math.round(absoluteXoffSetPx); | ||
absoluteYoffSetPx = Math.round(absoluteYoffSetPx); | ||
widthPx = Math.round(widthPx); | ||
heightPx = Math.round(heightPx); | ||
|
||
var ifrm = document.createElement('iframe'); | ||
ifrm.classList.add('circuitverse-iframe'); // assign a class | ||
ifrm.setAttribute('style', `position:fixed;z-index:100; | ||
width:${widthPx}px; | ||
height:${heightPx}px; | ||
top:${absoluteYoffSetPx}px; | ||
left:${absoluteXoffSetPx}px`); | ||
// assign url | ||
ifrm.setAttribute('src', url); | ||
|
||
return ifrm; | ||
} | ||
|
||
// Embeds iframe given link | ||
function embed(anchorTag) { | ||
var iframe = createEmbedIframe(anchorTag); | ||
var url = | ||
anchorTag.getAttributeNS('http://www.w3.org/1999/xlink', 'href'); | ||
var location = getEmbedLocation(); | ||
if (location == undefined) { | ||
return; | ||
} | ||
location.appendChild(iframe); // to place at end of document | ||
|
||
iframe_embedded = true; | ||
url_embedded = url; | ||
} | ||
|
||
// Removes all embedded iframes | ||
function removeEmbed() { | ||
var iframes = document.getElementsByClassName('circuitverse-iframe'); | ||
while (iframes[0]) { | ||
iframes[0].parentNode.removeChild(iframes[0]); | ||
} | ||
} | ||
|
||
// Keeps track of current frame | ||
|
||
var slideNumber = -1; | ||
|
||
// Setting slideNumber = -1 will reset everything | ||
function reset() { | ||
slideNumber = -1; | ||
} | ||
|
||
// Driver logic | ||
function main() { | ||
var iframeDocument = getSlideIframe(); | ||
|
||
if (!iframeDocument) { | ||
slideNumber = -1; | ||
removeEmbed(); | ||
return; | ||
} | ||
|
||
// Bring slide into focus - necessary for slide transitions to work! | ||
if (slideNumber != -1) { | ||
iframeDocument.contentWindow.document.body.focus(); | ||
} | ||
|
||
if (slideNumber == getSlideNumber()) return; | ||
|
||
// New Slide | ||
removeEmbed(); // remove previous iframes | ||
slideNumber = getSlideNumber(); | ||
|
||
var anchorTags = | ||
iframeDocument.contentWindow.document.getElementsByTagName('a'); | ||
|
||
var prevUrl = undefined; | ||
for (var i = 0; i < anchorTags.length; i++) { | ||
var url = anchorTags[i].getAttributeNS( | ||
'http://www.w3.org/1999/xlink', 'href'); | ||
|
||
// Google Slides has 2 anchor tags for every link for some reason; | ||
// Hence ensuring no duplicate embeds! | ||
if (url != prevUrl && url.includes('circuitverse.org')) { | ||
prevUrl = url | ||
embed(anchorTags[i]); | ||
} | ||
} | ||
} | ||
|
||
// Call driver logic repeatedly | ||
setInterval(main, 300); | ||
|
||
// Force reset after 3 seconds - needed for window resizing | ||
// Also needed if first slide has circuit | ||
window.addEventListener('resize', () => { | ||
setTimeout(reset, 3000); | ||
}); | ||
} | ||
}, 10); | ||
}); |