2025-01-12 00:52:51 +08:00

149 lines
4.5 KiB
JavaScript

/*jshint browser:true, strict:false, curly:false, indent:3*/
(function(){
// returns the origin we should post messages to (if on same host), or null if
// no suitable origin is found
var getOrigin = function() {
var origin = null;
// if an origin is supplied by RStudio, use it directly.
var rstudio_origin_meta = $('meta[name="rstudio_origin"]');
if (rstudio_origin_meta.length > 0) {
var rstudio_origin = rstudio_origin_meta.attr('content');
return window.location.protocol + "//" + rstudio_origin;
}
// function to normalize hostnames
var normalize = function(hostname) {
if (hostname == "127.0.0.1")
return "localhost";
else
return hostname;
};
// construct the parent origin if the hostnames match
var parentUrl = (parent !== window) ? document.referrer : null;
if (parentUrl) {
// parse the parent href
var a = document.createElement('a');
a.href = parentUrl;
if (normalize(a.hostname) == normalize(window.location.hostname)) {
var protocol = a.protocol.replace(':',''); // browser compatability
origin = protocol + '://' + a.hostname;
if (a.port)
origin = origin + ':' + a.port;
}
}
return origin;
};
// property application ------------------------------------------------------
// sets the location hash
var setHash = function(hash) {
// special case for ioslides: if the hash is numeric and we have a slide
// controller, use it to change the slides (ioslides doesn't respond to
// onhashchange)
if (/[0-9]+/.test(hash) && window.slidedeck) {
window.slidedeck.loadSlide(parseInt(hash));
} else {
location.hash = hash;
}
};
// sets the document scroll position. this could be called before that part of
// the document has loaded, so if the position specified is not yet available,
// wait a few ms and try again.
var setScrollPos = function(pos) {
if (pos > document.body.scrollHeight) {
window.setTimeout(function() { setScrollPos(pos); }, 100);
} else {
document.body.scrollTop = pos;
}
};
// cross-domain communication ------------------------------------------------
// obtain and validate the origin
var origin = getOrigin();
if (origin === null)
return;
// set up cross-domain send/receive
var send = function(data) {
data.type = "ShinyFrameEvent";
// only send the message if we have a parent
if (parent && (parent !== window))
parent.postMessage(data, origin);
};
var recv = function(evt) {
// validate that message is from expected origin (i.e. our parent)
if (evt.origin !== origin)
return;
switch (evt.data.method) {
case "rs_set_scroll_pos":
setScrollPos(evt.data.arg);
break;
case "rs_set_hash":
setHash(evt.data.arg);
break;
}
};
window.addEventListener("message", recv, false);
// document event handlers ---------------------------------------------------
// notify parent when scroll stops changing for ~0.25 s (don't spam during
// continuous/smooth scrolling)
var scrollTimer = 0;
var onScroll = function(pos) {
if (scrollTimer !== 0)
window.clearTimeout(scrollTimer);
scrollTimer = window.setTimeout(function() {
send({ event: "doc_scroll_change", data: document.body.scrollTop });
}, 250);
};
// test the href for changes every 100ms, and notify parent if it has changed.
// ordinarily we'd hook an event handler to 'hashchange' here, but in some
// cases (e.g. ioslides) the document can change the hash without triggering
// a hashchange event.
var currentHref = location.href;
var testHrefChange = function() {
if (currentHref !== location.href) {
currentHref = location.href;
send({ event: "doc_hash_change", data: location.href });
}
};
window.setInterval(testHrefChange, 100);
window.addEventListener("scroll", onScroll, false);
// let parent know we're ready once the event loop finishes
window.setTimeout(function() {
send({ event: "doc_ready", data: null });
}, 0);
// mathjax setup -------------------------------------------------------------
// if this is a Qt-based browser on Windows, inject the MathJax configuration
// data. at the time this runs it's not possible to know whether the document
// uses MathJax or not.
if (window.navigator.userAgent.indexOf(" Qt/") > 0 &&
window.navigator.userAgent.indexOf("Windows") > 0) {
var s = document.createElement("script");
s.type = "text/x-mathjax-config";
s.textContent =
'MathJax.Hub.Config({' +
' "HTML-CSS": { minScaleAdjust: 125, availableFonts: [] } ' +
'});';
document.head.appendChild(s);
}
})();