").addClass(errClass).css("position", "absolute")
+ .css("top", el.offsetTop)
+ .css("left", el.offsetLeft)
+ // setting width can push out the page size, forcing otherwise
+ // unnecessary scrollbars to appear and making it impossible for
+ // the element to shrink; so use max-width instead
+ .css("maxWidth", el.offsetWidth)
+ .css("height", el.offsetHeight);
+ errorDiv.text(err.message);
+ $el.after(errorDiv);
+
+ // Really dumb way to keep the size/position of the error in sync with
+ // the parent element as the window is resized or whatever.
+ var intId = setInterval(function() {
+ if (!errorDiv[0].parentElement) {
+ clearInterval(intId);
+ return;
+ }
+ errorDiv
+ .css("top", el.offsetTop)
+ .css("left", el.offsetLeft)
+ .css("maxWidth", el.offsetWidth)
+ .css("height", el.offsetHeight);
+ }, 500);
+ }
+ }
+ },
+ clearError: function(el) {
+ var $el = $(el);
+ var display = $el.data("restore-display-mode");
+ $el.data("restore-display-mode", null);
+
+ if (display === "inline" || display === "inline-block") {
+ if (display)
+ $el.css("display", display);
+ $(el.nextSibling).filter(".htmlwidgets-error").remove();
+ } else if (display === "block"){
+ $el.css("visibility", "inherit");
+ $(el.nextSibling).filter(".htmlwidgets-error").remove();
+ }
+ },
+ sizing: {}
+ };
+
+ // Called by widget bindings to register a new type of widget. The definition
+ // object can contain the following properties:
+ // - name (required) - A string indicating the binding name, which will be
+ // used by default as the CSS classname to look for.
+ // - initialize (optional) - A function(el) that will be called once per
+ // widget element; if a value is returned, it will be passed as the third
+ // value to renderValue.
+ // - renderValue (required) - A function(el, data, initValue) that will be
+ // called with data. Static contexts will cause this to be called once per
+ // element; Shiny apps will cause this to be called multiple times per
+ // element, as the data changes.
+ window.HTMLWidgets.widget = function(definition) {
+ if (!definition.name) {
+ throw new Error("Widget must have a name");
+ }
+ if (!definition.type) {
+ throw new Error("Widget must have a type");
+ }
+ // Currently we only support output widgets
+ if (definition.type !== "output") {
+ throw new Error("Unrecognized widget type '" + definition.type + "'");
+ }
+ // TODO: Verify that .name is a valid CSS classname
+
+ // Support new-style instance-bound definitions. Old-style class-bound
+ // definitions have one widget "object" per widget per type/class of
+ // widget; the renderValue and resize methods on such widget objects
+ // take el and instance arguments, because the widget object can't
+ // store them. New-style instance-bound definitions have one widget
+ // object per widget instance; the definition that's passed in doesn't
+ // provide renderValue or resize methods at all, just the single method
+ // factory(el, width, height)
+ // which returns an object that has renderValue(x) and resize(w, h).
+ // This enables a far more natural programming style for the widget
+ // author, who can store per-instance state using either OO-style
+ // instance fields or functional-style closure variables (I guess this
+ // is in contrast to what can only be called C-style pseudo-OO which is
+ // what we required before).
+ if (definition.factory) {
+ definition = createLegacyDefinitionAdapter(definition);
+ }
+
+ if (!definition.renderValue) {
+ throw new Error("Widget must have a renderValue function");
+ }
+
+ // For static rendering (non-Shiny), use a simple widget registration
+ // scheme. We also use this scheme for Shiny apps/documents that also
+ // contain static widgets.
+ window.HTMLWidgets.widgets = window.HTMLWidgets.widgets || [];
+ // Merge defaults into the definition; don't mutate the original definition.
+ var staticBinding = extend({}, defaults, definition);
+ overrideMethod(staticBinding, "find", function(superfunc) {
+ return function(scope) {
+ var results = superfunc(scope);
+ // Filter out Shiny outputs, we only want the static kind
+ return filterByClass(results, "html-widget-output", false);
+ };
+ });
+ window.HTMLWidgets.widgets.push(staticBinding);
+
+ if (shinyMode) {
+ // Shiny is running. Register the definition with an output binding.
+ // The definition itself will not be the output binding, instead
+ // we will make an output binding object that delegates to the
+ // definition. This is because we foolishly used the same method
+ // name (renderValue) for htmlwidgets definition and Shiny bindings
+ // but they actually have quite different semantics (the Shiny
+ // bindings receive data that includes lots of metadata that it
+ // strips off before calling htmlwidgets renderValue). We can't
+ // just ignore the difference because in some widgets it's helpful
+ // to call this.renderValue() from inside of resize(), and if
+ // we're not delegating, then that call will go to the Shiny
+ // version instead of the htmlwidgets version.
+
+ // Merge defaults with definition, without mutating either.
+ var bindingDef = extend({}, defaults, definition);
+
+ // This object will be our actual Shiny binding.
+ var shinyBinding = new Shiny.OutputBinding();
+
+ // With a few exceptions, we'll want to simply use the bindingDef's
+ // version of methods if they are available, otherwise fall back to
+ // Shiny's defaults. NOTE: If Shiny's output bindings gain additional
+ // methods in the future, and we want them to be overrideable by
+ // HTMLWidget binding definitions, then we'll need to add them to this
+ // list.
+ delegateMethod(shinyBinding, bindingDef, "getId");
+ delegateMethod(shinyBinding, bindingDef, "onValueChange");
+ delegateMethod(shinyBinding, bindingDef, "onValueError");
+ delegateMethod(shinyBinding, bindingDef, "renderError");
+ delegateMethod(shinyBinding, bindingDef, "clearError");
+ delegateMethod(shinyBinding, bindingDef, "showProgress");
+
+ // The find, renderValue, and resize are handled differently, because we
+ // want to actually decorate the behavior of the bindingDef methods.
+
+ shinyBinding.find = function(scope) {
+ var results = bindingDef.find(scope);
+
+ // Only return elements that are Shiny outputs, not static ones
+ var dynamicResults = results.filter(".html-widget-output");
+
+ // It's possible that whatever caused Shiny to think there might be
+ // new dynamic outputs, also caused there to be new static outputs.
+ // Since there might be lots of different htmlwidgets bindings, we
+ // schedule execution for later--no need to staticRender multiple
+ // times.
+ if (results.length !== dynamicResults.length)
+ scheduleStaticRender();
+
+ return dynamicResults;
+ };
+
+ // Wrap renderValue to handle initialization, which unfortunately isn't
+ // supported natively by Shiny at the time of this writing.
+
+ shinyBinding.renderValue = function(el, data) {
+ Shiny.renderDependencies(data.deps);
+ // Resolve strings marked as javascript literals to objects
+ if (!(data.evals instanceof Array)) data.evals = [data.evals];
+ for (var i = 0; data.evals && i < data.evals.length; i++) {
+ window.HTMLWidgets.evaluateStringMember(data.x, data.evals[i]);
+ }
+ if (!bindingDef.renderOnNullValue) {
+ if (data.x === null) {
+ el.style.visibility = "hidden";
+ return;
+ } else {
+ el.style.visibility = "inherit";
+ }
+ }
+ if (!elementData(el, "initialized")) {
+ initSizing(el);
+
+ elementData(el, "initialized", true);
+ if (bindingDef.initialize) {
+ var result = bindingDef.initialize(el, el.offsetWidth,
+ el.offsetHeight);
+ elementData(el, "init_result", result);
+ }
+ }
+ bindingDef.renderValue(el, data.x, elementData(el, "init_result"));
+ evalAndRun(data.jsHooks.render, elementData(el, "init_result"), [el, data.x]);
+ };
+
+ // Only override resize if bindingDef implements it
+ if (bindingDef.resize) {
+ shinyBinding.resize = function(el, width, height) {
+ // Shiny can call resize before initialize/renderValue have been
+ // called, which doesn't make sense for widgets.
+ if (elementData(el, "initialized")) {
+ bindingDef.resize(el, width, height, elementData(el, "init_result"));
+ }
+ };
+ }
+
+ Shiny.outputBindings.register(shinyBinding, bindingDef.name);
+ }
+ };
+
+ var scheduleStaticRenderTimerId = null;
+ function scheduleStaticRender() {
+ if (!scheduleStaticRenderTimerId) {
+ scheduleStaticRenderTimerId = setTimeout(function() {
+ scheduleStaticRenderTimerId = null;
+ window.HTMLWidgets.staticRender();
+ }, 1);
+ }
+ }
+
+ // Render static widgets after the document finishes loading
+ // Statically render all elements that are of this widget's class
+ window.HTMLWidgets.staticRender = function() {
+ var bindings = window.HTMLWidgets.widgets || [];
+ forEach(bindings, function(binding) {
+ var matches = binding.find(document.documentElement);
+ forEach(matches, function(el) {
+ var sizeObj = initSizing(el, binding);
+
+ if (hasClass(el, "html-widget-static-bound"))
+ return;
+ el.className = el.className + " html-widget-static-bound";
+
+ var initResult;
+ if (binding.initialize) {
+ initResult = binding.initialize(el,
+ sizeObj ? sizeObj.getWidth() : el.offsetWidth,
+ sizeObj ? sizeObj.getHeight() : el.offsetHeight
+ );
+ elementData(el, "init_result", initResult);
+ }
+
+ if (binding.resize) {
+ var lastSize = {
+ w: sizeObj ? sizeObj.getWidth() : el.offsetWidth,
+ h: sizeObj ? sizeObj.getHeight() : el.offsetHeight
+ };
+ var resizeHandler = function(e) {
+ var size = {
+ w: sizeObj ? sizeObj.getWidth() : el.offsetWidth,
+ h: sizeObj ? sizeObj.getHeight() : el.offsetHeight
+ };
+ if (size.w === 0 && size.h === 0)
+ return;
+ if (size.w === lastSize.w && size.h === lastSize.h)
+ return;
+ lastSize = size;
+ binding.resize(el, size.w, size.h, initResult);
+ };
+
+ on(window, "resize", resizeHandler);
+
+ // This is needed for cases where we're running in a Shiny
+ // app, but the widget itself is not a Shiny output, but
+ // rather a simple static widget. One example of this is
+ // an rmarkdown document that has runtime:shiny and widget
+ // that isn't in a render function. Shiny only knows to
+ // call resize handlers for Shiny outputs, not for static
+ // widgets, so we do it ourselves.
+ if (window.jQuery) {
+ window.jQuery(document).on(
+ "shown.htmlwidgets shown.bs.tab.htmlwidgets shown.bs.collapse.htmlwidgets",
+ resizeHandler
+ );
+ window.jQuery(document).on(
+ "hidden.htmlwidgets hidden.bs.tab.htmlwidgets hidden.bs.collapse.htmlwidgets",
+ resizeHandler
+ );
+ }
+
+ // This is needed for the specific case of ioslides, which
+ // flips slides between display:none and display:block.
+ // Ideally we would not have to have ioslide-specific code
+ // here, but rather have ioslides raise a generic event,
+ // but the rmarkdown package just went to CRAN so the
+ // window to getting that fixed may be long.
+ if (window.addEventListener) {
+ // It's OK to limit this to window.addEventListener
+ // browsers because ioslides itself only supports
+ // such browsers.
+ on(document, "slideenter", resizeHandler);
+ on(document, "slideleave", resizeHandler);
+ }
+ }
+
+ var scriptData = document.querySelector("script[data-for='" + el.id + "'][type='application/json']");
+ if (scriptData) {
+ var data = JSON.parse(scriptData.textContent || scriptData.text);
+ // Resolve strings marked as javascript literals to objects
+ if (!(data.evals instanceof Array)) data.evals = [data.evals];
+ for (var k = 0; data.evals && k < data.evals.length; k++) {
+ window.HTMLWidgets.evaluateStringMember(data.x, data.evals[k]);
+ }
+ binding.renderValue(el, data.x, initResult);
+ evalAndRun(data.jsHooks.render, initResult, [el, data.x]);
+ }
+ });
+ });
+
+ invokePostRenderHandlers();
+ }
+
+
+ function has_jQuery3() {
+ if (!window.jQuery) {
+ return false;
+ }
+ var $version = window.jQuery.fn.jquery;
+ var $major_version = parseInt($version.split(".")[0]);
+ return $major_version >= 3;
+ }
+
+ /*
+ / Shiny 1.4 bumped jQuery from 1.x to 3.x which means jQuery's
+ / on-ready handler (i.e., $(fn)) is now asyncronous (i.e., it now
+ / really means $(setTimeout(fn)).
+ / https://jquery.com/upgrade-guide/3.0/#breaking-change-document-ready-handlers-are-now-asynchronous
+ /
+ / Since Shiny uses $() to schedule initShiny, shiny>=1.4 calls initShiny
+ / one tick later than it did before, which means staticRender() is
+ / called renderValue() earlier than (advanced) widget authors might be expecting.
+ / https://github.com/rstudio/shiny/issues/2630
+ /
+ / For a concrete example, leaflet has some methods (e.g., updateBounds)
+ / which reference Shiny methods registered in initShiny (e.g., setInputValue).
+ / Since leaflet is privy to this life-cycle, it knows to use setTimeout() to
+ / delay execution of those methods (until Shiny methods are ready)
+ / https://github.com/rstudio/leaflet/blob/18ec981/javascript/src/index.js#L266-L268
+ /
+ / Ideally widget authors wouldn't need to use this setTimeout() hack that
+ / leaflet uses to call Shiny methods on a staticRender(). In the long run,
+ / the logic initShiny should be broken up so that method registration happens
+ / right away, but binding happens later.
+ */
+ function maybeStaticRenderLater() {
+ if (shinyMode && has_jQuery3()) {
+ window.jQuery(window.HTMLWidgets.staticRender);
+ } else {
+ window.HTMLWidgets.staticRender();
+ }
+ }
+
+ if (document.addEventListener) {
+ document.addEventListener("DOMContentLoaded", function() {
+ document.removeEventListener("DOMContentLoaded", arguments.callee, false);
+ maybeStaticRenderLater();
+ }, false);
+ } else if (document.attachEvent) {
+ document.attachEvent("onreadystatechange", function() {
+ if (document.readyState === "complete") {
+ document.detachEvent("onreadystatechange", arguments.callee);
+ maybeStaticRenderLater();
+ }
+ });
+ }
+
+
+ window.HTMLWidgets.getAttachmentUrl = function(depname, key) {
+ // If no key, default to the first item
+ if (typeof(key) === "undefined")
+ key = 1;
+
+ var link = document.getElementById(depname + "-" + key + "-attachment");
+ if (!link) {
+ throw new Error("Attachment " + depname + "/" + key + " not found in document");
+ }
+ return link.getAttribute("href");
+ };
+
+ window.HTMLWidgets.dataframeToD3 = function(df) {
+ var names = [];
+ var length;
+ for (var name in df) {
+ if (df.hasOwnProperty(name))
+ names.push(name);
+ if (typeof(df[name]) !== "object" || typeof(df[name].length) === "undefined") {
+ throw new Error("All fields must be arrays");
+ } else if (typeof(length) !== "undefined" && length !== df[name].length) {
+ throw new Error("All fields must be arrays of the same length");
+ }
+ length = df[name].length;
+ }
+ var results = [];
+ var item;
+ for (var row = 0; row < length; row++) {
+ item = {};
+ for (var col = 0; col < names.length; col++) {
+ item[names[col]] = df[names[col]][row];
+ }
+ results.push(item);
+ }
+ return results;
+ };
+
+ window.HTMLWidgets.transposeArray2D = function(array) {
+ if (array.length === 0) return array;
+ var newArray = array[0].map(function(col, i) {
+ return array.map(function(row) {
+ return row[i]
+ })
+ });
+ return newArray;
+ };
+ // Split value at splitChar, but allow splitChar to be escaped
+ // using escapeChar. Any other characters escaped by escapeChar
+ // will be included as usual (including escapeChar itself).
+ function splitWithEscape(value, splitChar, escapeChar) {
+ var results = [];
+ var escapeMode = false;
+ var currentResult = "";
+ for (var pos = 0; pos < value.length; pos++) {
+ if (!escapeMode) {
+ if (value[pos] === splitChar) {
+ results.push(currentResult);
+ currentResult = "";
+ } else if (value[pos] === escapeChar) {
+ escapeMode = true;
+ } else {
+ currentResult += value[pos];
+ }
+ } else {
+ currentResult += value[pos];
+ escapeMode = false;
+ }
+ }
+ if (currentResult !== "") {
+ results.push(currentResult);
+ }
+ return results;
+ }
+ // Function authored by Yihui/JJ Allaire
+ window.HTMLWidgets.evaluateStringMember = function(o, member) {
+ var parts = splitWithEscape(member, '.', '\\');
+ for (var i = 0, l = parts.length; i < l; i++) {
+ var part = parts[i];
+ // part may be a character or 'numeric' member name
+ if (o !== null && typeof o === "object" && part in o) {
+ if (i == (l - 1)) { // if we are at the end of the line then evalulate
+ if (typeof o[part] === "string")
+ o[part] = tryEval(o[part]);
+ } else { // otherwise continue to next embedded object
+ o = o[part];
+ }
+ }
+ }
+ };
+
+ // Retrieve the HTMLWidget instance (i.e. the return value of an
+ // HTMLWidget binding's initialize() or factory() function)
+ // associated with an element, or null if none.
+ window.HTMLWidgets.getInstance = function(el) {
+ return elementData(el, "init_result");
+ };
+
+ // Finds the first element in the scope that matches the selector,
+ // and returns the HTMLWidget instance (i.e. the return value of
+ // an HTMLWidget binding's initialize() or factory() function)
+ // associated with that element, if any. If no element matches the
+ // selector, or the first matching element has no HTMLWidget
+ // instance associated with it, then null is returned.
+ //
+ // The scope argument is optional, and defaults to window.document.
+ window.HTMLWidgets.find = function(scope, selector) {
+ if (arguments.length == 1) {
+ selector = scope;
+ scope = document;
+ }
+
+ var el = scope.querySelector(selector);
+ if (el === null) {
+ return null;
+ } else {
+ return window.HTMLWidgets.getInstance(el);
+ }
+ };
+
+ // Finds all elements in the scope that match the selector, and
+ // returns the HTMLWidget instances (i.e. the return values of
+ // an HTMLWidget binding's initialize() or factory() function)
+ // associated with the elements, in an array. If elements that
+ // match the selector don't have an associated HTMLWidget
+ // instance, the returned array will contain nulls.
+ //
+ // The scope argument is optional, and defaults to window.document.
+ window.HTMLWidgets.findAll = function(scope, selector) {
+ if (arguments.length == 1) {
+ selector = scope;
+ scope = document;
+ }
+
+ var nodes = scope.querySelectorAll(selector);
+ var results = [];
+ for (var i = 0; i < nodes.length; i++) {
+ results.push(window.HTMLWidgets.getInstance(nodes[i]));
+ }
+ return results;
+ };
+
+ var postRenderHandlers = [];
+ function invokePostRenderHandlers() {
+ while (postRenderHandlers.length) {
+ var handler = postRenderHandlers.shift();
+ if (handler) {
+ handler();
+ }
+ }
+ }
+
+ // Register the given callback function to be invoked after the
+ // next time static widgets are rendered.
+ window.HTMLWidgets.addPostRenderHandler = function(callback) {
+ postRenderHandlers.push(callback);
+ };
+
+ // Takes a new-style instance-bound definition, and returns an
+ // old-style class-bound definition. This saves us from having
+ // to rewrite all the logic in this file to accomodate both
+ // types of definitions.
+ function createLegacyDefinitionAdapter(defn) {
+ var result = {
+ name: defn.name,
+ type: defn.type,
+ initialize: function(el, width, height) {
+ return defn.factory(el, width, height);
+ },
+ renderValue: function(el, x, instance) {
+ return instance.renderValue(x);
+ },
+ resize: function(el, width, height, instance) {
+ return instance.resize(width, height);
+ }
+ };
+
+ if (defn.find)
+ result.find = defn.find;
+ if (defn.renderError)
+ result.renderError = defn.renderError;
+ if (defn.clearError)
+ result.clearError = defn.clearError;
+
+ return result;
+ }
+})();
+
diff --git a/Practicals/Aleksandra Dacko/P5/pres_files/figure-html/widgets/visNetwork_libs/pymjs-1.3.2/pym.v1.js b/Practicals/Aleksandra Dacko/P5/pres_files/figure-html/widgets/visNetwork_libs/pymjs-1.3.2/pym.v1.js
new file mode 100644
index 0000000..c69c5e5
--- /dev/null
+++ b/Practicals/Aleksandra Dacko/P5/pres_files/figure-html/widgets/visNetwork_libs/pymjs-1.3.2/pym.v1.js
@@ -0,0 +1,1116 @@
+/*! pym.js - v1.3.1 - 2017-08-06 */
+/*
+* Pym.js is library that resizes an iframe based on the width of the parent and the resulting height of the child.
+* Check out the docs at http://blog.apps.npr.org/pym.js/ or the readme at README.md for usage.
+*/
+
+/** @module pym */
+(function(factory) {
+ if (typeof define === 'function' && define.amd) {
+ define(factory);
+ }
+ else if (typeof module !== 'undefined' && module.exports) {
+ module.exports = factory();
+ } else {
+ window.pym = factory.call(this);
+ }
+})(function() {
+ var MESSAGE_DELIMITER = 'xPYMx';
+
+ var lib = {};
+
+ /**
+ * Create and dispatch a custom pym event
+ *
+ * @method _raiseCustomEvent
+ * @inner
+ *
+ * @param {String} eventName
+ */
+ var _raiseCustomEvent = function(eventName) {
+ var event = document.createEvent('Event');
+ event.initEvent('pym:' + eventName, true, true);
+ document.dispatchEvent(event);
+ };
+
+ /**
+ * Generic function for parsing URL params.
+ * Via http://stackoverflow.com/questions/901115/how-can-i-get-query-string-values-in-javascript
+ *
+ * @method _getParameterByName
+ * @inner
+ *
+ * @param {String} name The name of the paramter to get from the URL.
+ */
+ var _getParameterByName = function(name) {
+ var regex = new RegExp("[\\?&]" + name.replace(/[\[]/, '\\[').replace(/[\]]/, '\\]') + '=([^]*)');
+ var results = regex.exec(location.search);
+
+ if (results === null) {
+ return '';
+ }
+
+ return decodeURIComponent(results[1].replace(/\+/g, " "));
+ };
+
+ /**
+ * Check the message to make sure it comes from an acceptable xdomain.
+ * Defaults to '*' but can be overriden in config.
+ *
+ * @method _isSafeMessage
+ * @inner
+ *
+ * @param {Event} e The message event.
+ * @param {Object} settings Configuration.
+ */
+ var _isSafeMessage = function(e, settings) {
+ if (settings.xdomain !== '*') {
+ // If origin doesn't match our xdomain, return.
+ if (!e.origin.match(new RegExp(settings.xdomain + '$'))) { return; }
+ }
+
+ // Ignore events that do not carry string data #151
+ if (typeof e.data !== 'string') { return; }
+
+ return true;
+ };
+
+ /**
+ * Construct a message to send between frames.
+ *
+ * NB: We use string-building here because JSON message passing is
+ * not supported in all browsers.
+ *
+ * @method _makeMessage
+ * @inner
+ *
+ * @param {String} id The unique id of the message recipient.
+ * @param {String} messageType The type of message to send.
+ * @param {String} message The message to send.
+ */
+ var _makeMessage = function(id, messageType, message) {
+ var bits = ['pym', id, messageType, message];
+
+ return bits.join(MESSAGE_DELIMITER);
+ };
+
+ /**
+ * Construct a regex to validate and parse messages.
+ *
+ * @method _makeMessageRegex
+ * @inner
+ *
+ * @param {String} id The unique id of the message recipient.
+ */
+ var _makeMessageRegex = function(id) {
+ var bits = ['pym', id, '(\\S+)', '(.*)'];
+
+ return new RegExp('^' + bits.join(MESSAGE_DELIMITER) + '$');
+ };
+
+ /**
+ * Underscore implementation of getNow
+ *
+ * @method _getNow
+ * @inner
+ *
+ */
+ var _getNow = Date.now || function() {
+ return new Date().getTime();
+ };
+
+ /**
+ * Underscore implementation of throttle
+ *
+ * @method _throttle
+ * @inner
+ *
+ * @param {function} func Throttled function
+ * @param {number} wait Throttle wait time
+ * @param {object} options Throttle settings
+ */
+
+ var _throttle = function(func, wait, options) {
+ var context, args, result;
+ var timeout = null;
+ var previous = 0;
+ if (!options) {options = {};}
+ var later = function() {
+ previous = options.leading === false ? 0 : _getNow();
+ timeout = null;
+ result = func.apply(context, args);
+ if (!timeout) {context = args = null;}
+ };
+ return function() {
+ var now = _getNow();
+ if (!previous && options.leading === false) {previous = now;}
+ var remaining = wait - (now - previous);
+ context = this;
+ args = arguments;
+ if (remaining <= 0 || remaining > wait) {
+ if (timeout) {
+ clearTimeout(timeout);
+ timeout = null;
+ }
+ previous = now;
+ result = func.apply(context, args);
+ if (!timeout) {context = args = null;}
+ } else if (!timeout && options.trailing !== false) {
+ timeout = setTimeout(later, remaining);
+ }
+ return result;
+ };
+ };
+
+ /**
+ * Clean autoInit Instances: those that point to contentless iframes
+ * @method _cleanAutoInitInstances
+ * @inner
+ */
+ var _cleanAutoInitInstances = function() {
+ var length = lib.autoInitInstances.length;
+
+ // Loop backwards to avoid index issues
+ for (var idx = length - 1; idx >= 0; idx--) {
+ var instance = lib.autoInitInstances[idx];
+ // If instance has been removed or is contentless then remove it
+ if (instance.el.getElementsByTagName('iframe').length &&
+ instance.el.getElementsByTagName('iframe')[0].contentWindow) {
+ continue;
+ }
+ else {
+ // Remove the reference to the removed or orphan instance
+ lib.autoInitInstances.splice(idx,1);
+ }
+ }
+ };
+
+ /**
+ * Store auto initialized Pym instances for further reference
+ * @name module:pym#autoInitInstances
+ * @type Array
+ * @default []
+ */
+ lib.autoInitInstances = [];
+
+ /**
+ * Initialize Pym for elements on page that have data-pym attributes.
+ * Expose autoinit in case we need to call it from the outside
+ * @instance
+ * @method autoInit
+ * @param {Boolean} doNotRaiseEvents flag to avoid sending custom events
+ */
+ lib.autoInit = function(doNotRaiseEvents) {
+ var elements = document.querySelectorAll('[data-pym-src]:not([data-pym-auto-initialized])');
+ var length = elements.length;
+
+ // Clean stored instances in case needed
+ _cleanAutoInitInstances();
+ for (var idx = 0; idx < length; ++idx) {
+ var element = elements[idx];
+ /*
+ * Mark automatically-initialized elements so they are not
+ * re-initialized if the user includes pym.js more than once in the
+ * same document.
+ */
+ element.setAttribute('data-pym-auto-initialized', '');
+
+ // Ensure elements have an id
+ if (element.id === '') {
+ element.id = 'pym-' + idx + "-" + Math.random().toString(36).substr(2,5);
+ }
+
+ var src = element.getAttribute('data-pym-src');
+
+ // List of data attributes to configure the component
+ // structure: {'attribute name': 'type'}
+ var settings = {'xdomain': 'string', 'title': 'string', 'name': 'string', 'id': 'string',
+ 'sandbox': 'string', 'allowfullscreen': 'boolean',
+ 'parenturlparam': 'string', 'parenturlvalue': 'string',
+ 'optionalparams': 'boolean', 'trackscroll': 'boolean',
+ 'scrollwait': 'number', 'lazyload': 'boolean'};
+
+ var config = {};
+
+ for (var attribute in settings) {
+ // via https://developer.mozilla.org/en-US/docs/Web/API/Element/getAttribute#Notes
+ if (element.getAttribute('data-pym-'+attribute) !== null) {
+ switch (settings[attribute]) {
+ case 'boolean':
+ config[attribute] = !(element.getAttribute('data-pym-'+attribute) === 'false'); // jshint ignore:line
+ break;
+ case 'string':
+ config[attribute] = element.getAttribute('data-pym-'+attribute);
+ break;
+ case 'number':
+ var n = Number(element.getAttribute('data-pym-'+attribute));
+ if (!isNaN(n)) {
+ config[attribute] = n;
+ }
+ break;
+ default:
+ console.err('unrecognized attribute type');
+ }
+ }
+ }
+
+ // Store references to autoinitialized pym instances
+ var parent = new lib.Parent(element.id, src, config);
+ lib.autoInitInstances.push(parent);
+ }
+
+ // Fire customEvent
+ if (!doNotRaiseEvents) {
+ _raiseCustomEvent("pym-initialized");
+ }
+ // Return stored autoinitalized pym instances
+ return lib.autoInitInstances;
+ };
+
+ /**
+ * The Parent half of a response iframe.
+ *
+ * @memberof module:pym
+ * @class Parent
+ * @param {String} id The id of the div into which the iframe will be rendered. sets {@link module:pym.Parent~id}
+ * @param {String} url The url of the iframe source. sets {@link module:pym.Parent~url}
+ * @param {Object} [config] Configuration for the parent instance. sets {@link module:pym.Parent~settings}
+ * @param {string} [config.xdomain='*'] - xdomain to validate messages received
+ * @param {string} [config.title] - if passed it will be assigned to the iframe title attribute
+ * @param {string} [config.name] - if passed it will be assigned to the iframe name attribute
+ * @param {string} [config.id] - if passed it will be assigned to the iframe id attribute
+ * @param {boolean} [config.allowfullscreen] - if passed and different than false it will be assigned to the iframe allowfullscreen attribute
+ * @param {string} [config.sandbox] - if passed it will be assigned to the iframe sandbox attribute (we do not validate the syntax so be careful!!)
+ * @param {string} [config.parenturlparam] - if passed it will be override the default parentUrl query string parameter name passed to the iframe src
+ * @param {string} [config.parenturlvalue] - if passed it will be override the default parentUrl query string parameter value passed to the iframe src
+ * @param {string} [config.optionalparams] - if passed and different than false it will strip the querystring params parentUrl and parentTitle passed to the iframe src
+ * @param {boolean} [config.trackscroll] - if passed it will activate scroll tracking on the parent
+ * @param {number} [config.scrollwait] - if passed it will set the throttle wait in order to fire scroll messaging. Defaults to 100 ms.
+ * @param {boolean} [config.lazyload] - if passed and different than false construct a iframe that can be lazy loaded along with {@link http://dinbror.dk/blog/blazy/?ref=github#iframe blazy-iframe}
+ * @see {@link https://developer.mozilla.org/en-US/docs/Web/HTML/Element/iframe iFrame}
+ */
+ lib.Parent = function(id, url, config) {
+ /**
+ * The id of the container element
+ *
+ * @memberof module:pym.Parent
+ * @member {string} id
+ * @inner
+ */
+ this.id = id;
+ /**
+ * The url that will be set as the iframe's src
+ *
+ * @memberof module:pym.Parent
+ * @member {String} url
+ * @inner
+ */
+ this.url = url;
+
+ /**
+ * The container DOM object
+ *
+ * @memberof module:pym.Parent
+ * @member {HTMLElement} el
+ * @inner
+ */
+ this.el = document.getElementById(id);
+ /**
+ * The contained child iframe
+ *
+ * @memberof module:pym.Parent
+ * @member {HTMLElement} iframe
+ * @inner
+ * @default null
+ */
+ this.iframe = null;
+ /**
+ * The parent instance settings, updated by the values passed in the config object
+ *
+ * @memberof module:pym.Parent
+ * @member {Object} settings
+ * @inner
+ */
+ this.settings = {
+ xdomain: '*',
+ optionalparams: true,
+ parenturlparam: 'parentUrl',
+ parenturlvalue: window.location.href,
+ trackscroll: false,
+ scrollwait: 100,
+ };
+ /**
+ * RegularExpression to validate the received messages
+ *
+ * @memberof module:pym.Parent
+ * @member {String} messageRegex
+ * @inner
+ */
+ this.messageRegex = _makeMessageRegex(this.id);
+ /**
+ * Stores the registered messageHandlers for each messageType
+ *
+ * @memberof module:pym.Parent
+ * @member {Object} messageHandlers
+ * @inner
+ */
+ this.messageHandlers = {};
+
+ // ensure a config object
+ config = (config || {});
+
+ /**
+ * Construct the iframe.
+ *
+ * @memberof module:pym.Parent
+ * @method _constructIframe
+ * @inner
+ */
+ this._constructIframe = function() {
+ // Calculate the width of this element.
+ var width = this.el.offsetWidth.toString();
+
+ // Create an iframe element attached to the document.
+ this.iframe = document.createElement('iframe');
+
+ // Save fragment id
+ var hash = '';
+ var hashIndex = this.url.indexOf('#');
+
+ if (hashIndex > -1) {
+ hash = this.url.substring(hashIndex, this.url.length);
+ this.url = this.url.substring(0, hashIndex);
+ }
+
+ // If the URL contains querystring bits, use them.
+ // Otherwise, just create a set of valid params.
+ if (this.url.indexOf('?') < 0) {
+ this.url += '?';
+ } else {
+ this.url += '&';
+ }
+
+ // Append the initial width as a querystring parameter
+ // and optional params if configured to do so
+ this.iframe.src = this.url + 'initialWidth=' + width +
+ '&childId=' + this.id;
+
+ if (this.settings.optionalparams) {
+ this.iframe.src += '&parentTitle=' + encodeURIComponent(document.title);
+ this.iframe.src += '&'+ this.settings.parenturlparam + '=' + encodeURIComponent(this.settings.parenturlvalue);
+ }
+ this.iframe.src +=hash;
+
+ if(this.settings.lazyload) {
+ this.iframe.setAttribute('data-src', this.iframe.src);
+ this.iframe.setAttribute('class', 'b-lazy');
+ this.iframe.src = 'about:blank';
+ }
+
+ // Set some attributes to this proto-iframe.
+ this.iframe.setAttribute('width', '100%');
+ this.iframe.setAttribute('scrolling', 'no');
+ this.iframe.setAttribute('marginheight', '0');
+ this.iframe.setAttribute('frameborder', '0');
+
+ if (this.settings.title) {
+ this.iframe.setAttribute('title', this.settings.title);
+ }
+
+ if (this.settings.allowfullscreen !== undefined && this.settings.allowfullscreen !== false) {
+ this.iframe.setAttribute('allowfullscreen','');
+ }
+
+ if (this.settings.sandbox !== undefined && typeof this.settings.sandbox === 'string') {
+ this.iframe.setAttribute('sandbox', this.settings.sandbox);
+ }
+
+ if (this.settings.id) {
+ if (!document.getElementById(this.settings.id)) {
+ this.iframe.setAttribute('id', this.settings.id);
+ }
+ }
+
+ if (this.settings.name) {
+ this.iframe.setAttribute('name', this.settings.name);
+ }
+
+ // Replace the child content if needed
+ // (some CMSs might strip out empty elements)
+ while(this.el.firstChild) { this.el.removeChild(this.el.firstChild); }
+ // Append the iframe to our element.
+ this.el.appendChild(this.iframe);
+
+ // Add an event listener that will handle redrawing the child on resize.
+ window.addEventListener('resize', this._onResize);
+
+ // Add an event listener that will send the child the viewport.
+ if (this.settings.trackscroll) {
+ window.addEventListener('scroll', this._throttleOnScroll);
+ }
+ };
+
+ /**
+ * Send width on resize.
+ *
+ * @memberof module:pym.Parent
+ * @method _onResize
+ * @inner
+ */
+ this._onResize = function() {
+ this.sendWidth();
+ if (this.settings.trackscroll) {
+ this.sendViewportAndIFramePosition();
+ }
+ }.bind(this);
+
+ /**
+ * Send viewport and iframe info on scroll.
+ *
+ * @memberof module:pym.Parent
+ * @method _onScroll
+ * @inner
+ */
+ this._onScroll = function() {
+ this.sendViewportAndIFramePosition();
+ }.bind(this);
+
+ /**
+ * Fire all event handlers for a given message type.
+ *
+ * @memberof module:pym.Parent
+ * @method _fire
+ * @inner
+ *
+ * @param {String} messageType The type of message.
+ * @param {String} message The message data.
+ */
+ this._fire = function(messageType, message) {
+ if (messageType in this.messageHandlers) {
+ for (var i = 0; i < this.messageHandlers[messageType].length; i++) {
+ this.messageHandlers[messageType][i].call(this, message);
+ }
+ }
+ };
+
+ /**
+ * Remove this parent from the page and unbind it's event handlers.
+ *
+ * @memberof module:pym.Parent
+ * @method remove
+ * @instance
+ */
+ this.remove = function() {
+ window.removeEventListener('message', this._processMessage);
+ window.removeEventListener('resize', this._onResize);
+
+ this.el.removeChild(this.iframe);
+ // _cleanAutoInitInstances in case this parent was autoInitialized
+ _cleanAutoInitInstances();
+ };
+
+ /**
+ * Process a new message from the child.
+ *
+ * @memberof module:pym.Parent
+ * @method _processMessage
+ * @inner
+ *
+ * @param {Event} e A message event.
+ */
+ this._processMessage = function(e) {
+ // First, punt if this isn't from an acceptable xdomain.
+ if (!_isSafeMessage(e, this.settings)) {
+ return;
+ }
+
+ // Discard object messages, we only care about strings
+ if (typeof e.data !== 'string') {
+ return;
+ }
+
+ // Grab the message from the child and parse it.
+ var match = e.data.match(this.messageRegex);
+
+ // If there's no match or too many matches in the message, punt.
+ if (!match || match.length !== 3) {
+ return false;
+ }
+
+ var messageType = match[1];
+ var message = match[2];
+
+ this._fire(messageType, message);
+ }.bind(this);
+
+ /**
+ * Resize iframe in response to new height message from child.
+ *
+ * @memberof module:pym.Parent
+ * @method _onHeightMessage
+ * @inner
+ *
+ * @param {String} message The new height.
+ */
+ this._onHeightMessage = function(message) {
+ /*
+ * Handle parent height message from child.
+ */
+ var height = parseInt(message);
+
+ this.iframe.setAttribute('height', height + 'px');
+ };
+
+ /**
+ * Navigate parent to a new url.
+ *
+ * @memberof module:pym.Parent
+ * @method _onNavigateToMessage
+ * @inner
+ *
+ * @param {String} message The url to navigate to.
+ */
+ this._onNavigateToMessage = function(message) {
+ /*
+ * Handle parent scroll message from child.
+ */
+ document.location.href = message;
+ };
+
+ /**
+ * Scroll parent to a given child position.
+ *
+ * @memberof module:pym.Parent
+ * @method _onScrollToChildPosMessage
+ * @inner
+ *
+ * @param {String} message The offset inside the child page.
+ */
+ this._onScrollToChildPosMessage = function(message) {
+ // Get the child container position using getBoundingClientRect + pageYOffset
+ // via https://developer.mozilla.org/en-US/docs/Web/API/Element/getBoundingClientRect
+ var iframePos = document.getElementById(this.id).getBoundingClientRect().top + window.pageYOffset;
+
+ var totalOffset = iframePos + parseInt(message);
+ window.scrollTo(0, totalOffset);
+ };
+
+ /**
+ * Bind a callback to a given messageType from the child.
+ *
+ * Reserved message names are: "height", "scrollTo" and "navigateTo".
+ *
+ * @memberof module:pym.Parent
+ * @method onMessage
+ * @instance
+ *
+ * @param {String} messageType The type of message being listened for.
+ * @param {module:pym.Parent~onMessageCallback} callback The callback to invoke when a message of the given type is received.
+ */
+ this.onMessage = function(messageType, callback) {
+ if (!(messageType in this.messageHandlers)) {
+ this.messageHandlers[messageType] = [];
+ }
+
+ this.messageHandlers[messageType].push(callback);
+ };
+
+ /**
+ * @callback module:pym.Parent~onMessageCallback
+ * @param {String} message The message data.
+ */
+
+ /**
+ * Send a message to the the child.
+ *
+ * @memberof module:pym.Parent
+ * @method sendMessage
+ * @instance
+ *
+ * @param {String} messageType The type of message to send.
+ * @param {String} message The message data to send.
+ */
+ this.sendMessage = function(messageType, message) {
+ // When used alongside with pjax some references are lost
+ if (this.el.getElementsByTagName('iframe').length) {
+ if (this.el.getElementsByTagName('iframe')[0].contentWindow) {
+ this.el.getElementsByTagName('iframe')[0].contentWindow
+ .postMessage(_makeMessage(this.id, messageType, message), '*');
+ }
+ else {
+ // Contentless child detected remove listeners and iframe
+ this.remove();
+ }
+ }
+ };
+
+ /**
+ * Transmit the current iframe width to the child.
+ *
+ * You shouldn't need to call this directly.
+ *
+ * @memberof module:pym.Parent
+ * @method sendWidth
+ * @instance
+ */
+ this.sendWidth = function() {
+ var width = this.el.offsetWidth.toString();
+ this.sendMessage('width', width);
+ };
+
+ /**
+ * Transmit the current viewport and iframe position to the child.
+ * Sends viewport width, viewport height
+ * and iframe bounding rect top-left-bottom-right
+ * all separated by spaces
+ *
+ * You shouldn't need to call this directly.
+ *
+ * @memberof module:pym.Parent
+ * @method sendViewportAndIFramePosition
+ * @instance
+ */
+ this.sendViewportAndIFramePosition = function() {
+ var iframeRect = this.iframe.getBoundingClientRect();
+ var vWidth = window.innerWidth || document.documentElement.clientWidth;
+ var vHeight = window.innerHeight || document.documentElement.clientHeight;
+ var payload = vWidth + ' ' + vHeight;
+ payload += ' ' + iframeRect.top + ' ' + iframeRect.left;
+ payload += ' ' + iframeRect.bottom + ' ' + iframeRect.right;
+ this.sendMessage('viewport-iframe-position', payload);
+ };
+
+ // Add any overrides to settings coming from config.
+ for (var key in config) {
+ this.settings[key] = config[key];
+ }
+
+ /**
+ * Throttled scroll function.
+ *
+ * @memberof module:pym.Parent
+ * @method _throttleOnScroll
+ * @inner
+ */
+ this._throttleOnScroll = _throttle(this._onScroll.bind(this), this.settings.scrollwait);
+
+ // Bind required message handlers
+ this.onMessage('height', this._onHeightMessage);
+ this.onMessage('navigateTo', this._onNavigateToMessage);
+ this.onMessage('scrollToChildPos', this._onScrollToChildPosMessage);
+ this.onMessage('parentPositionInfo', this.sendViewportAndIFramePosition);
+
+ // Add a listener for processing messages from the child.
+ window.addEventListener('message', this._processMessage, false);
+
+ // Construct the iframe in the container element.
+ this._constructIframe();
+
+ return this;
+ };
+
+ /**
+ * The Child half of a responsive iframe.
+ *
+ * @memberof module:pym
+ * @class Child
+ * @param {Object} [config] Configuration for the child instance. sets {@link module:pym.Child~settings}
+ * @param {function} [config.renderCallback=null] Callback invoked after receiving a resize event from the parent, sets {@link module:pym.Child#settings.renderCallback}
+ * @param {string} [config.xdomain='*'] - xdomain to validate messages received
+ * @param {number} [config.polling=0] - polling frequency in milliseconds to send height to parent
+ * @param {number} [config.id] - parent container id used when navigating the child iframe to a new page but we want to keep it responsive.
+ * @param {string} [config.parenturlparam] - if passed it will be override the default parentUrl query string parameter name expected on the iframe src
+ */
+ lib.Child = function(config) {
+ /**
+ * The initial width of the parent page
+ *
+ * @memberof module:pym.Child
+ * @member {string} parentWidth
+ * @inner
+ */
+ this.parentWidth = null;
+ /**
+ * The id of the parent container
+ *
+ * @memberof module:pym.Child
+ * @member {String} id
+ * @inner
+ */
+ this.id = null;
+ /**
+ * The title of the parent page from document.title.
+ *
+ * @memberof module:pym.Child
+ * @member {String} parentTitle
+ * @inner
+ */
+ this.parentTitle = null;
+ /**
+ * The URL of the parent page from window.location.href.
+ *
+ * @memberof module:pym.Child
+ * @member {String} parentUrl
+ * @inner
+ */
+ this.parentUrl = null;
+ /**
+ * The settings for the child instance. Can be overriden by passing a config object to the child constructor
+ * i.e.: var pymChild = new pym.Child({renderCallback: render, xdomain: "\\*\.npr\.org"})
+ *
+ * @memberof module:pym.Child.settings
+ * @member {Object} settings - default settings for the child instance
+ * @inner
+ */
+ this.settings = {
+ renderCallback: null,
+ xdomain: '*',
+ polling: 0,
+ parenturlparam: 'parentUrl'
+ };
+
+ /**
+ * The timerId in order to be able to stop when polling is enabled
+ *
+ * @memberof module:pym.Child
+ * @member {String} timerId
+ * @inner
+ */
+ this.timerId = null;
+ /**
+ * RegularExpression to validate the received messages
+ *
+ * @memberof module:pym.Child
+ * @member {String} messageRegex
+ * @inner
+ */
+ this.messageRegex = null;
+ /**
+ * Stores the registered messageHandlers for each messageType
+ *
+ * @memberof module:pym.Child
+ * @member {Object} messageHandlers
+ * @inner
+ */
+ this.messageHandlers = {};
+
+ // Ensure a config object
+ config = (config || {});
+
+ /**
+ * Bind a callback to a given messageType from the child.
+ *
+ * Reserved message names are: "width".
+ *
+ * @memberof module:pym.Child
+ * @method onMessage
+ * @instance
+ *
+ * @param {String} messageType The type of message being listened for.
+ * @param {module:pym.Child~onMessageCallback} callback The callback to invoke when a message of the given type is received.
+ */
+ this.onMessage = function(messageType, callback) {
+
+ if (!(messageType in this.messageHandlers)) {
+ this.messageHandlers[messageType] = [];
+ }
+
+ this.messageHandlers[messageType].push(callback);
+ };
+
+ /**
+ * @callback module:pym.Child~onMessageCallback
+ * @param {String} message The message data.
+ */
+
+
+ /**
+ * Fire all event handlers for a given message type.
+ *
+ * @memberof module:pym.Child
+ * @method _fire
+ * @inner
+ *
+ * @param {String} messageType The type of message.
+ * @param {String} message The message data.
+ */
+ this._fire = function(messageType, message) {
+ /*
+ * Fire all event handlers for a given message type.
+ */
+ if (messageType in this.messageHandlers) {
+ for (var i = 0; i < this.messageHandlers[messageType].length; i++) {
+ this.messageHandlers[messageType][i].call(this, message);
+ }
+ }
+ };
+
+ /**
+ * Process a new message from the parent.
+ *
+ * @memberof module:pym.Child
+ * @method _processMessage
+ * @inner
+ *
+ * @param {Event} e A message event.
+ */
+ this._processMessage = function(e) {
+ /*
+ * Process a new message from parent frame.
+ */
+ // First, punt if this isn't from an acceptable xdomain.
+ if (!_isSafeMessage(e, this.settings)) {
+ return;
+ }
+
+ // Discard object messages, we only care about strings
+ if (typeof e.data !== 'string') {
+ return;
+ }
+
+ // Get the message from the parent.
+ var match = e.data.match(this.messageRegex);
+
+ // If there's no match or it's a bad format, punt.
+ if (!match || match.length !== 3) { return; }
+
+ var messageType = match[1];
+ var message = match[2];
+
+ this._fire(messageType, message);
+ }.bind(this);
+
+ /**
+ * Resize iframe in response to new width message from parent.
+ *
+ * @memberof module:pym.Child
+ * @method _onWidthMessage
+ * @inner
+ *
+ * @param {String} message The new width.
+ */
+ this._onWidthMessage = function(message) {
+ /*
+ * Handle width message from the child.
+ */
+ var width = parseInt(message);
+
+ // Change the width if it's different.
+ if (width !== this.parentWidth) {
+ this.parentWidth = width;
+
+ // Call the callback function if it exists.
+ if (this.settings.renderCallback) {
+ this.settings.renderCallback(width);
+ }
+
+ // Send the height back to the parent.
+ this.sendHeight();
+ }
+ };
+
+ /**
+ * Send a message to the the Parent.
+ *
+ * @memberof module:pym.Child
+ * @method sendMessage
+ * @instance
+ *
+ * @param {String} messageType The type of message to send.
+ * @param {String} message The message data to send.
+ */
+ this.sendMessage = function(messageType, message) {
+ /*
+ * Send a message to the parent.
+ */
+ window.parent.postMessage(_makeMessage(this.id, messageType, message), '*');
+ };
+
+ /**
+ * Transmit the current iframe height to the parent.
+ *
+ * Call this directly in cases where you manually alter the height of the iframe contents.
+ *
+ * @memberof module:pym.Child
+ * @method sendHeight
+ * @instance
+ */
+ this.sendHeight = function() {
+ // Get the child's height.
+ var height = document.getElementsByTagName('body')[0].offsetHeight.toString();
+
+ // Send the height to the parent.
+ this.sendMessage('height', height);
+
+ return height;
+ }.bind(this);
+
+ /**
+ * Ask parent to send the current viewport and iframe position information
+ *
+ * @memberof module:pym.Child
+ * @method sendHeight
+ * @instance
+ */
+ this.getParentPositionInfo = function() {
+ // Send the height to the parent.
+ this.sendMessage('parentPositionInfo');
+ };
+
+ /**
+ * Scroll parent to a given element id.
+ *
+ * @memberof module:pym.Child
+ * @method scrollParentTo
+ * @instance
+ *
+ * @param {String} hash The id of the element to scroll to.
+ */
+ this.scrollParentTo = function(hash) {
+ this.sendMessage('navigateTo', '#' + hash);
+ };
+
+ /**
+ * Navigate parent to a given url.
+ *
+ * @memberof module:pym.Child
+ * @method navigateParentTo
+ * @instance
+ *
+ * @param {String} url The url to navigate to.
+ */
+ this.navigateParentTo = function(url) {
+ this.sendMessage('navigateTo', url);
+ };
+
+ /**
+ * Scroll parent to a given child element id.
+ *
+ * @memberof module:pym.Child
+ * @method scrollParentToChildEl
+ * @instance
+ *
+ * @param {String} id The id of the child element to scroll to.
+ */
+ this.scrollParentToChildEl = function(id) {
+ // Get the child element position using getBoundingClientRect + pageYOffset
+ // via https://developer.mozilla.org/en-US/docs/Web/API/Element/getBoundingClientRect
+ var topPos = document.getElementById(id).getBoundingClientRect().top + window.pageYOffset;
+ this.scrollParentToChildPos(topPos);
+ };
+
+ /**
+ * Scroll parent to a particular child offset.
+ *
+ * @memberof module:pym.Child
+ * @method scrollParentToChildPos
+ * @instance
+ *
+ * @param {Number} pos The offset of the child element to scroll to.
+ */
+ this.scrollParentToChildPos = function(pos) {
+ this.sendMessage('scrollToChildPos', pos.toString());
+ };
+
+ /**
+ * Mark Whether the child is embedded or not
+ * executes a callback in case it was passed to the config
+ *
+ * @memberof module:pym.Child
+ * @method _markWhetherEmbedded
+ * @inner
+ *
+ * @param {module:pym.Child~onMarkedEmbeddedStatus} The callback to execute after determining whether embedded or not.
+ */
+ var _markWhetherEmbedded = function(onMarkedEmbeddedStatus) {
+ var htmlElement = document.getElementsByTagName('html')[0],
+ newClassForHtml,
+ originalHtmlClasses = htmlElement.className;
+ try {
+ if(window.self !== window.top) {
+ newClassForHtml = "embedded";
+ }else{
+ newClassForHtml = "not-embedded";
+ }
+ }catch(e) {
+ newClassForHtml = "embedded";
+ }
+ if(originalHtmlClasses.indexOf(newClassForHtml) < 0) {
+ htmlElement.className = originalHtmlClasses ? originalHtmlClasses + ' ' + newClassForHtml : newClassForHtml;
+ if(onMarkedEmbeddedStatus){
+ onMarkedEmbeddedStatus(newClassForHtml);
+ }
+ _raiseCustomEvent("marked-embedded");
+ }
+ };
+
+ /**
+ * @callback module:pym.Child~onMarkedEmbeddedStatus
+ * @param {String} classname "embedded" or "not-embedded".
+ */
+
+ /**
+ * Unbind child event handlers and timers.
+ *
+ * @memberof module:pym.Child
+ * @method remove
+ * @instance
+ */
+ this.remove = function() {
+ window.removeEventListener('message', this._processMessage);
+ if (this.timerId) {
+ clearInterval(this.timerId);
+ }
+ };
+
+ // Initialize settings with overrides.
+ for (var key in config) {
+ this.settings[key] = config[key];
+ }
+
+ // Identify what ID the parent knows this child as.
+ this.id = _getParameterByName('childId') || config.id;
+ this.messageRegex = new RegExp('^pym' + MESSAGE_DELIMITER + this.id + MESSAGE_DELIMITER + '(\\S+)' + MESSAGE_DELIMITER + '(.*)$');
+
+ // Get the initial width from a URL parameter.
+ var width = parseInt(_getParameterByName('initialWidth'));
+
+ // Get the url of the parent frame
+ this.parentUrl = _getParameterByName(this.settings.parenturlparam);
+
+ // Get the title of the parent frame
+ this.parentTitle = _getParameterByName('parentTitle');
+
+ // Bind the required message handlers
+ this.onMessage('width', this._onWidthMessage);
+
+ // Set up a listener to handle any incoming messages.
+ window.addEventListener('message', this._processMessage, false);
+
+ // If there's a callback function, call it.
+ if (this.settings.renderCallback) {
+ this.settings.renderCallback(width);
+ }
+
+ // Send the initial height to the parent.
+ this.sendHeight();
+
+ // If we're configured to poll, create a setInterval to handle that.
+ if (this.settings.polling) {
+ this.timerId = window.setInterval(this.sendHeight, this.settings.polling);
+ }
+
+ _markWhetherEmbedded(config.onMarkedEmbeddedStatus);
+
+ return this;
+ };
+
+ // Initialize elements with pym data attributes
+ // if we are not in server configuration
+ if(typeof document !== "undefined") {
+ lib.autoInit(true);
+ }
+
+ return lib;
+});
+
diff --git a/Practicals/Aleksandra Dacko/P5/pres_files/figure-html/widgets/visNetwork_libs/pymjs-1.3.2/pym.v1.min.js b/Practicals/Aleksandra Dacko/P5/pres_files/figure-html/widgets/visNetwork_libs/pymjs-1.3.2/pym.v1.min.js
new file mode 100644
index 0000000..9b47a7e
--- /dev/null
+++ b/Practicals/Aleksandra Dacko/P5/pres_files/figure-html/widgets/visNetwork_libs/pymjs-1.3.2/pym.v1.min.js
@@ -0,0 +1,3 @@
+/*! pym.js - v1.3.1 - 2017-08-06 */
+
+!function(a){"function"==typeof define&&define.amd?define(a):"undefined"!=typeof module&&module.exports?module.exports=a():window.pym=a.call(this)}(function(){var a={},b=function(a){var b=document.createEvent("Event");b.initEvent("pym:"+a,!0,!0),document.dispatchEvent(b)},c=function(a){var b=new RegExp("[\\?&]"+a.replace(/[\[]/,"\\[").replace(/[\]]/,"\\]")+"=([^]*)"),c=b.exec(location.search);return null===c?"":decodeURIComponent(c[1].replace(/\+/g," "))},d=function(a,b){if(("*"===b.xdomain||a.origin.match(new RegExp(b.xdomain+"$")))&&"string"==typeof a.data)return!0},e=function(a,b,c){return["pym",a,b,c].join("xPYMx")},f=function(a){var b=["pym",a,"(\\S+)","(.*)"];return new RegExp("^"+b.join("xPYMx")+"$")},g=Date.now||function(){return(new Date).getTime()},h=function(a,b,c){var d,e,f,h=null,i=0;c||(c={});var j=function(){i=!1===c.leading?0:g(),h=null,f=a.apply(d,e),h||(d=e=null)};return function(){var k=g();i||!1!==c.leading||(i=k);var l=b-(k-i);return d=this,e=arguments,l<=0||l>b?(h&&(clearTimeout(h),h=null),i=k,f=a.apply(d,e),h||(d=e=null)):h||!1===c.trailing||(h=setTimeout(j,l)),f}},i=function(){for(var b=a.autoInitInstances.length,c=b-1;c>=0;c--){var d=a.autoInitInstances[c];d.el.getElementsByTagName("iframe").length&&d.el.getElementsByTagName("iframe")[0].contentWindow||a.autoInitInstances.splice(c,1)}};return a.autoInitInstances=[],a.autoInit=function(c){var d=document.querySelectorAll("[data-pym-src]:not([data-pym-auto-initialized])"),e=d.length;i();for(var f=0;f
-1&&(b=this.url.substring(c,this.url.length),this.url=this.url.substring(0,c)),this.url.indexOf("?")<0?this.url+="?":this.url+="&",this.iframe.src=this.url+"initialWidth="+a+"&childId="+this.id,this.settings.optionalparams&&(this.iframe.src+="&parentTitle="+encodeURIComponent(document.title),this.iframe.src+="&"+this.settings.parenturlparam+"="+encodeURIComponent(this.settings.parenturlvalue)),this.iframe.src+=b,this.settings.lazyload&&(this.iframe.setAttribute("data-src",this.iframe.src),this.iframe.setAttribute("class","b-lazy"),this.iframe.src="about:blank"),this.iframe.setAttribute("width","100%"),this.iframe.setAttribute("scrolling","no"),this.iframe.setAttribute("marginheight","0"),this.iframe.setAttribute("frameborder","0"),this.settings.title&&this.iframe.setAttribute("title",this.settings.title),void 0!==this.settings.allowfullscreen&&!1!==this.settings.allowfullscreen&&this.iframe.setAttribute("allowfullscreen",""),void 0!==this.settings.sandbox&&"string"==typeof this.settings.sandbox&&this.iframe.setAttribute("sandbox",this.settings.sandbox),this.settings.id&&(document.getElementById(this.settings.id)||this.iframe.setAttribute("id",this.settings.id)),this.settings.name&&this.iframe.setAttribute("name",this.settings.name);this.el.firstChild;)this.el.removeChild(this.el.firstChild);this.el.appendChild(this.iframe),window.addEventListener("resize",this._onResize),this.settings.trackscroll&&window.addEventListener("scroll",this._throttleOnScroll)},this._onResize=function(){this.sendWidth(),this.settings.trackscroll&&this.sendViewportAndIFramePosition()}.bind(this),this._onScroll=function(){this.sendViewportAndIFramePosition()}.bind(this),this._fire=function(a,b){if(a in this.messageHandlers)for(var c=0;c=74)&&(o=E.match(/Chrome\/(\d+)/))&&(r=o[1]);var M=r&&+r,P=!!Object.getOwnPropertySymbols&&!h((function(){var t=Symbol();return!String(t)||!(Object(t)instanceof Symbol)||!Symbol.sham&&M&&M<41})),D=P&&!Symbol.sham&&"symbol"==typeof Symbol.iterator,I=D?function(t){return"symbol"==typeof t}:function(t){var e=x("Symbol");return"function"==typeof e&&Object(t)instanceof e},B="__core-js_shared__",z=a[B]||function(t,e){try{Object.defineProperty(a,t,{value:e,configurable:!0,writable:!0})}catch(i){a[t]=e}return e}(B,{}),N=n((function(t){(t.exports=function(t,e){return z[t]||(z[t]=void 0!==e?e:{})})("versions",[]).push({version:"3.16.1",mode:"pure",copyright:"© 2021 Denis Pushkarev (zloirock.ru)"})})),A=function(t){return Object(m(t))},F={}.hasOwnProperty,j=Object.hasOwn||function(t,e){return F.call(A(t),e)},R=0,L=Math.random(),H=function(t){return"Symbol("+String(void 0===t?"":t)+")_"+(++R+L).toString(36)},W=N("wks"),q=a.Symbol,V=D?q:q&&q.withoutSetter||H,U=function(t){return j(W,t)&&(P||"string"==typeof W[t])||(P&&j(q,t)?W[t]=q[t]:W[t]=V("Symbol."+t)),W[t]},Y=U("toPrimitive"),X=function(t,e){if(!w(t)||I(t))return t;var i,n=t[Y];if(void 0!==n){if(void 0===e&&(e="default"),i=n.call(t,e),!w(i)||I(i))return i;throw TypeError("Can't convert object to primitive value")}return void 0===e&&(e="number"),function(t,e){var i,n;if("string"===e&&"function"==typeof(i=t.toString)&&!w(n=i.call(t)))return n;if("function"==typeof(i=t.valueOf)&&!w(n=i.call(t)))return n;if("string"!==e&&"function"==typeof(i=t.toString)&&!w(n=i.call(t)))return n;throw TypeError("Can't convert object to primitive value")}(t,e)},G=function(t){var e=X(t,"string");return I(e)?e:String(e)},K=a.document,$=w(K)&&w(K.createElement),Z=function(t){return $?K.createElement(t):{}},Q=!l&&!h((function(){return 7!=Object.defineProperty(Z("div"),"a",{get:function(){return 7}}).a})),J=Object.getOwnPropertyDescriptor,tt={f:l?J:function(t,e){if(t=b(t),e=G(e),Q)try{return J(t,e)}catch(t){}if(j(t,e))return f(!u.f.call(t,e),t[e])}},et=/#|\.prototype\./,it=function(t,e){var i=ot[nt(t)];return i==st||i!=rt&&("function"==typeof e?h(e):!!e)},nt=it.normalize=function(t){return String(t).replace(et,".").toLowerCase()},ot=it.data={},rt=it.NATIVE="N",st=it.POLYFILL="P",at=it,ht=function(t){if("function"!=typeof t)throw TypeError(String(t)+" is not a function");return t},lt=function(t,e,i){if(ht(t),void 0===e)return t;switch(i){case 0:return function(){return t.call(e)};case 1:return function(i){return t.call(e,i)};case 2:return function(i,n){return t.call(e,i,n)};case 3:return function(i,n,o){return t.call(e,i,n,o)}}return function(){return t.apply(e,arguments)}},dt=function(t){if(!w(t))throw TypeError(String(t)+" is not an object");return t},ct=Object.defineProperty,ut={f:l?ct:function(t,e,i){if(dt(t),e=G(e),dt(i),Q)try{return ct(t,e,i)}catch(t){}if("get"in i||"set"in i)throw TypeError("Accessors not supported");return"value"in i&&(t[e]=i.value),t}},ft=l?function(t,e,i){return ut.f(t,e,f(1,i))}:function(t,e,i){return t[e]=i,t},pt=tt.f,vt=function(t){var e=function(e,i,n){if(this instanceof t){switch(arguments.length){case 0:return new t;case 1:return new t(e);case 2:return new t(e,i)}return new t(e,i,n)}return t.apply(this,arguments)};return e.prototype=t.prototype,e},gt=function(t,e){var i,n,o,r,s,h,l,d,c=t.target,u=t.global,f=t.stat,p=t.proto,v=u?a:f?a[c]:(a[c]||{}).prototype,g=u?k:k[c]||(k[c]={}),y=g.prototype;for(o in e)i=!at(u?o:c+(f?".":"#")+o,t.forced)&&v&&j(v,o),s=g[o],i&&(h=t.noTargetGet?(d=pt(v,o))&&d.value:v[o]),r=i&&h?h:e[o],i&&typeof s==typeof r||(l=t.bind&&i?lt(r,a):t.wrap&&i?vt(r):p&&"function"==typeof r?lt(Function.call,r):r,(t.sham||r&&r.sham||s&&s.sham)&&ft(l,"sham",!0),g[o]=l,p&&(j(k,n=c+"Prototype")||ft(k,n,{}),k[n][o]=r,t.real&&y&&!y[o]&&ft(y,o,r)))},yt=Math.ceil,mt=Math.floor,bt=function(t){return isNaN(t=+t)?0:(t>0?mt:yt)(t)},wt=Math.min,kt=function(t){return t>0?wt(bt(t),9007199254740991):0},_t=Math.max,xt=Math.min,Et=function(t,e){var i=bt(t);return i<0?_t(i+e,0):xt(i,e)},Ot=function(t){return function(e,i,n){var o,r=b(e),s=kt(r.length),a=Et(n,s);if(t&&i!=i){for(;s>a;)if((o=r[a++])!=o)return!0}else for(;s>a;a++)if((t||a in r)&&r[a]===i)return t||a||0;return!t&&-1}},Ct={includes:Ot(!0),indexOf:Ot(!1)},St={},Tt=Ct.indexOf,Mt=function(t,e){var i,n=b(t),o=0,r=[];for(i in n)!j(St,i)&&j(n,i)&&r.push(i);for(;e.length>o;)j(n,i=e[o++])&&(~Tt(r,i)||r.push(i));return r},Pt=["constructor","hasOwnProperty","isPrototypeOf","propertyIsEnumerable","toLocaleString","toString","valueOf"],Dt=Object.keys||function(t){return Mt(t,Pt)},It={f:Object.getOwnPropertySymbols},Bt=Object.assign,zt=Object.defineProperty,Nt=!Bt||h((function(){if(l&&1!==Bt({b:1},Bt(zt({},"a",{enumerable:!0,get:function(){zt(this,"b",{value:3,enumerable:!1})}}),{b:2})).b)return!0;var t={},e={},i=Symbol(),n="abcdefghijklmnopqrst";return t[i]=7,n.split("").forEach((function(t){e[t]=t})),7!=Bt({},t)[i]||Dt(Bt({},e)).join("")!=n}))?function(t,e){for(var i=A(t),n=arguments.length,o=1,r=It.f,s=u.f;n>o;)for(var a,h=y(arguments[o++]),d=r?Dt(h).concat(r(h)):Dt(h),c=d.length,f=0;c>f;)a=d[f++],l&&!s.call(h,a)||(i[a]=h[a]);return i}:Bt;gt({target:"Object",stat:!0,forced:Object.assign!==Nt},{assign:Nt});var At=k.Object.assign,Ft=[].slice,jt={},Rt=function(t,e,i){if(!(e in jt)){for(var n=[],o=0;o=.1;)(p=+r[c++%s])>d&&(p=d),f=Math.sqrt(p*p/(1+l*l)),e+=f=a<0?-f:f,i+=l*f,!0===u?t.lineTo(e,i):t.moveTo(e,i),d-=p,u=!u}var $t={circle:Ut,dashedLine:Kt,database:Gt,diamond:function(t,e,i,n){t.beginPath(),t.lineTo(e,i+n),t.lineTo(e+n,i),t.lineTo(e,i-n),t.lineTo(e-n,i),t.closePath()},ellipse:Xt,ellipse_vis:Xt,hexagon:function(t,e,i,n){t.beginPath();var o=2*Math.PI/6;t.moveTo(e+n,i);for(var r=1;r<6;r++)t.lineTo(e+n*Math.cos(o*r),i+n*Math.sin(o*r));t.closePath()},roundRect:Yt,square:function(t,e,i,n){t.beginPath(),t.rect(e-n,i-n,2*n,2*n),t.closePath()},star:function(t,e,i,n){t.beginPath(),i+=.1*(n*=.82);for(var o=0;o<10;o++){var r=o%2==0?1.3*n:.5*n;t.lineTo(e+r*Math.sin(2*o*Math.PI/10),i-r*Math.cos(2*o*Math.PI/10))}t.closePath()},triangle:function(t,e,i,n){t.beginPath(),i+=.275*(n*=1.15);var o=2*n,r=o/2,s=Math.sqrt(3)/6*o,a=Math.sqrt(o*o-r*r);t.moveTo(e,i-(a-s)),t.lineTo(e+r,i+s),t.lineTo(e-r,i+s),t.lineTo(e,i-(a-s)),t.closePath()},triangleDown:function(t,e,i,n){t.beginPath(),i-=.275*(n*=1.15);var o=2*n,r=o/2,s=Math.sqrt(3)/6*o,a=Math.sqrt(o*o-r*r);t.moveTo(e,i+(a-s)),t.lineTo(e+r,i-s),t.lineTo(e-r,i-s),t.lineTo(e,i+(a-s)),t.closePath()}};var Zt=n((function(t){function e(t){if(t)return function(t){for(var i in e.prototype)t[i]=e.prototype[i];return t}(t)}t.exports=e,e.prototype.on=e.prototype.addEventListener=function(t,e){return this._callbacks=this._callbacks||{},(this._callbacks["$"+t]=this._callbacks["$"+t]||[]).push(e),this},e.prototype.once=function(t,e){function i(){this.off(t,i),e.apply(this,arguments)}return i.fn=e,this.on(t,i),this},e.prototype.off=e.prototype.removeListener=e.prototype.removeAllListeners=e.prototype.removeEventListener=function(t,e){if(this._callbacks=this._callbacks||{},0==arguments.length)return this._callbacks={},this;var i,n=this._callbacks["$"+t];if(!n)return this;if(1==arguments.length)return delete this._callbacks["$"+t],this;for(var o=0;o=a?t?"":void 0:(n=r.charCodeAt(s))<55296||n>56319||s+1===a||(o=r.charCodeAt(s+1))<56320||o>57343?t?r.charAt(s):n:t?r.slice(s,s+2):o-56320+(n-55296<<10)+65536}},te={codeAt:Jt(!1),charAt:Jt(!0)},ee=Function.toString;"function"!=typeof z.inspectSource&&(z.inspectSource=function(t){return ee.call(t)});var ie,ne,oe,re=z.inspectSource,se=a.WeakMap,ae="function"==typeof se&&/native code/.test(re(se)),he=N("keys"),le=function(t){return he[t]||(he[t]=H(t))},de="Object already initialized",ce=a.WeakMap;if(ae||z.state){var ue=z.state||(z.state=new ce),fe=ue.get,pe=ue.has,ve=ue.set;ie=function(t,e){if(pe.call(ue,t))throw new TypeError(de);return e.facade=t,ve.call(ue,t,e),e},ne=function(t){return fe.call(ue,t)||{}},oe=function(t){return pe.call(ue,t)}}else{var ge=le("state");St[ge]=!0,ie=function(t,e){if(j(t,ge))throw new TypeError(de);return e.facade=t,ft(t,ge,e),e},ne=function(t){return j(t,ge)?t[ge]:{}},oe=function(t){return j(t,ge)}}var ye,me,be,we={set:ie,get:ne,has:oe,enforce:function(t){return oe(t)?ne(t):ie(t,{})},getterFor:function(t){return function(e){var i;if(!w(e)||(i=ne(e)).type!==t)throw TypeError("Incompatible receiver, "+t+" required");return i}}},ke=!h((function(){function t(){}return t.prototype.constructor=null,Object.getPrototypeOf(new t)!==t.prototype})),_e=le("IE_PROTO"),xe=Object.prototype,Ee=ke?Object.getPrototypeOf:function(t){return t=A(t),j(t,_e)?t[_e]:"function"==typeof t.constructor&&t instanceof t.constructor?t.constructor.prototype:t instanceof Object?xe:null},Oe=U("iterator"),Ce=!1;[].keys&&("next"in(be=[].keys())?(me=Ee(Ee(be)))!==Object.prototype&&(ye=me):Ce=!0);var Se=null==ye||h((function(){var t={};return ye[Oe].call(t)!==t}));Se&&(ye={}),Se&&!j(ye,Oe)&&ft(ye,Oe,(function(){return this}));var Te,Me={IteratorPrototype:ye,BUGGY_SAFARI_ITERATORS:Ce},Pe=l?Object.defineProperties:function(t,e){dt(t);for(var i,n=Dt(e),o=n.length,r=0;o>r;)ut.f(t,i=n[r++],e[i]);return t},De=x("document","documentElement"),Ie=le("IE_PROTO"),Be=function(){},ze=function(t){return"
+
+
+
+
+ visNetwork
+
+
+
+
+
+
+