Skip to content

Commit

Permalink
Merge pull request #8 from CircuitVerse/fix/location
Browse files Browse the repository at this point in the history
Embed Location Fix +  Multiple Circuits Embed
  • Loading branch information
satu0king authored Oct 3, 2020
2 parents 45bc061 + 317d443 commit c3b8c11
Show file tree
Hide file tree
Showing 2 changed files with 193 additions and 85 deletions.
18 changes: 8 additions & 10 deletions Chrome Extension/src/bg/background.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,15 +5,13 @@
// });


//example of using a message handler from the inject scripts
chrome.extension.onMessage.addListener(
function(request, sender, sendResponse) {
chrome.pageAction.show(sender.tab.id);
sendResponse();
});
// example of using a message handler from the inject scripts

chrome.runtime.onInstalled.addListener(function (object) {
chrome.tabs.create({url: "views/instructions.html"}, function (tab) {
console.log("New tab launched with http://yoursite.com/");
});
// chrome.extension.onMessage.addListener(function(request, sender, sendResponse) {
// chrome.pageAction.show(sender.tab.id);
// sendResponse();
// });

chrome.runtime.onInstalled.addListener(function(object) {
chrome.tabs.create({url: 'views/instructions.html'});
});
260 changes: 185 additions & 75 deletions Chrome Extension/src/inject/inject.js
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);
});

0 comments on commit c3b8c11

Please sign in to comment.