EVOLUTION-MANAGER
Edit File: shiny-showcase.js
/*jshint browser:true, jquery:true, strict:false, curly:false, indent:2*/ (function() { var animateMs = 400; // Given a DOM node and a column (count of characters), walk recursively // through the node's siblings counting characters until the given number // of characters have been found. // // If the given count is bigger than the number of characters contained by // the node and its siblings, returns a null node and the number of // characters found. function findTextColPoint(node, col) { var cols = 0; if (node.nodeType === 3) { var nchar = node.nodeValue.replace(/\n/g, "").length; if (nchar >= col) { return { element: node, offset: col }; } else { cols += nchar; } } else if (node.nodeType === 1 && node.firstChild) { var ret = findTextColPoint(node.firstChild, col); if (ret.element !== null) { return ret; } else { cols += ret.offset; } } if (node.nextSibling) return findTextColPoint(node.nextSibling, col - cols); else return { element: null, offset: cols }; } // Returns an object indicating the element containing the given line and // column of text, and the offset into that element where the text was found. // // If the given line and column are not found, returns a null element and // the number of lines found. function findTextPoint(el, line, col) { var newlines = 0; for (var childId = 0; childId < el.childNodes.length; childId++) { var child = el.childNodes[childId]; // If this is a text node, count the number of newlines it contains. if (child.nodeType === 3) { // TEXT_NODE var newlinere = /\n/g; var match; while ((match = newlinere.exec(child.nodeValue)) !== null) { newlines++; // Found the desired line, now find the column. if (newlines === line) { return findTextColPoint(child, match.index + col + 1); } } } // If this is not a text node, descend recursively to see how many // lines it contains. else if (child.nodeType === 1) { // ELEMENT_NODE var ret = findTextPoint(child, line - newlines, col); if (ret.element !== null) return ret; else newlines += ret.offset; } } return { element: null, offset: newlines }; } // Draw a highlight effect for the given source ref. srcref is assumed to be // an integer array of length 6, following the standard R format for source // refs. function highlightSrcref (srcref, srcfile) { // Check to see if the browser supports text ranges (IE8 doesn't) if (!document.createRange) return; // Check to see if we already have a marker for this source ref var el = document.getElementById("srcref_" + srcref); if (!el) { // We don't have a marker, create one el = document.createElement("span"); el.id = "srcref_" + srcref; var ref = srcref; var code = document.getElementById(srcfile.replace(/\./g, "_") + "_code"); // if there is no code file (might be a shiny file), quit early if (!code) return; var start = findTextPoint(code, ref[0], ref[4]); var end = findTextPoint(code, ref[2], ref[5]); // If the insertion point can't be found, bail out now if (start.element === null || end.element === null) return; var range = document.createRange(); // If the text points are inside different <SPAN>s, we may not be able to // surround them without breaking apart the elements to keep the DOM tree // intact. Just move the selection points to encompass the contents of // the SPANs. if (start.element.parentNode.nodeName === "SPAN" && start.element !== end.element) { range.setStartBefore(start.element.parentNode); } else { range.setStart(start.element, start.offset); } if (end.element.parentNode.nodeName === "SPAN" && start.element !== end.element) { range.setEndAfter(end.element.parentNode); } else { range.setEnd(end.element, end.offset); } range.surroundContents(el); } // End any previous highlight before starting this one jQuery(el) .stop(true, true) .effect("highlight", null, 1600); } // If this is the main Shiny window, wire up our custom message handler. if (window.Shiny) { Shiny.addCustomMessageHandler('showcase-src', function(message) { if (message.srcref && message.srcfile) { highlightSrcref(message.srcref, message.srcfile); } }); } var isCodeAbove = false; var setCodePosition = function(above, animate) { var animateCodeMs = animate ? animateMs : 1; // set the source and targets for the tab move var newHostElement = above ? document.getElementById("showcase-sxs-code") : document.getElementById("showcase-code-inline"); var currentHostElement = above ? document.getElementById("showcase-code-inline") : document.getElementById("showcase-sxs-code"); var metadataElement = document.getElementById("showcase-app-metadata"); if (metadataElement === null) { // if there's no app metadata, show and hide the entire well container // when the code changes position var wellElement = $("#showcase-well"); if (above) { wellElement.fadeOut(animateCodeMs); } else { wellElement.fadeIn(animateCodeMs); } } // hide the new element before doing anything to it $(newHostElement).hide(); $(currentHostElement).fadeOut(animateCodeMs, function() { var tabs = document.getElementById("showcase-code-tabs"); currentHostElement.removeChild(tabs); newHostElement.appendChild(tabs); // remove or set the height of the code if (above) { setCodeHeightFromDocHeight(); } else { document.getElementById("showcase-code-content").removeAttribute("style"); } $(newHostElement).fadeIn(animateCodeMs); if (!above) { // remove the applied width and zoom on the app container, and // scroll smoothly down to the code's new home document.getElementById("showcase-app-container").removeAttribute("style"); if (animate) $(document.body).animate({ scrollTop: $(newHostElement).offset().top }); } // if there's a readme, move it either alongside the code or beneath // the app var readme = document.getElementById("readme-md"); if (readme !== null) { readme.parentElement.removeChild(readme); if (above) { currentHostElement.appendChild(readme); $(currentHostElement).fadeIn(animateCodeMs); } else document.getElementById("showcase-app-metadata").appendChild(readme); } // change the text on the toggle button to reflect the new state document.getElementById("showcase-code-position-toggle").innerHTML = above ? '<i class="fa fa-level-down"></i> show below' : '<i class="fa fa-level-up"></i> show with app'; }); if (above) { $(document.body).animate({ scrollTop: 0 }, animateCodeMs); } isCodeAbove = above; setAppCodeSxsWidths(above && animate); $(window).trigger("resize"); }; var setAppCodeSxsWidths = function(animate) { var appTargetWidth = 960; var appWidth = appTargetWidth; var zoom = 1.0; var totalWidth = document.getElementById("showcase-app-code").offsetWidth; if (totalWidth / 2 > appTargetWidth) { // If the app can use only half the available space and still meet its // target, take half the available space. appWidth = totalWidth / 2; } else if (totalWidth * 0.66 > appTargetWidth) { // If the app can meet its target by taking up more space (up to 66% // of its container), take up more space. appWidth = 960; } else { // The space is too narrow for the app and code to live side-by-side // in a friendly way. Keep the app at 2/3 of the space but scale it. appWidth = totalWidth * 0.66; zoom = appWidth/appTargetWidth; } var app = document.getElementById("showcase-app-container"); $(app).animate({ width: appWidth + "px", zoom: (zoom*100) + "%" }, animate ? animateMs : 0); }; var toggleCodePosition = function() { setCodePosition(!isCodeAbove, true); }; // if the browser is sized to wider than 1350px, show the code next to the // app by default var setInitialCodePosition = function() { if (document.body.offsetWidth > 1350) { setCodePosition(true, false); } }; // make the code scrollable to about the height of the browser, less space // for the tabs var setCodeHeightFromDocHeight = function() { document.getElementById("showcase-code-content").style.height = $(window).height() + "px"; }; // if there's a block of markdown content, render it to HTML var renderMarkdown = function() { var mdContent = document.getElementById("showcase-markdown-content"); if (mdContent !== null) { // IE8 puts the content of <script> tags into innerHTML but // not innerText var content = mdContent.innerText || mdContent.innerHTML; document.getElementById("readme-md").innerHTML = (new Showdown.converter()).makeHtml(content) } } $(window).resize(function() { if (isCodeAbove) { setAppCodeSxsWidths(false); setCodeHeightFromDocHeight(); } }); window.toggleCodePosition = toggleCodePosition; $(window).on("load", setInitialCodePosition); $(window).on("load", renderMarkdown); if (window.hljs) hljs.initHighlightingOnLoad(); })();