diff --git a/js/bower.json b/js/bower.json index 1f67648e5e..9b8f9d96a6 100644 --- a/js/bower.json +++ b/js/bower.json @@ -2,7 +2,8 @@ "name": "gallery", "homepage": "https://github.com/owncloud/gallery", "authors": [ - "Olivier Paroz " + "Olivier Paroz ", + "Robin Appelman " ], "description": "Media gallery for ownCloud which includes previews for all media types supported by your ownCloud installation.", "license": "AGPL", @@ -16,7 +17,8 @@ ], "dependencies": { "eventsource-polyfill": "~0.*", - "marked": "~0.*", - "github-markdown-css": "~2.*" + "github-markdown-css": "~2.*", + "dompurify": "~0.6.5", + "commonmark": "~0.22.0" } } diff --git a/js/galleryinfobox.js b/js/galleryinfobox.js index 2a3b0608b4..7ce993cbd5 100644 --- a/js/galleryinfobox.js +++ b/js/galleryinfobox.js @@ -1,4 +1,4 @@ -/* global Gallery, marked */ +/* global Gallery, commonmark, DOMPurify */ (function ($, t, Gallery) { "use strict"; /** @@ -10,6 +10,9 @@ this.infoContentContainer = $('.album-info-container'); this.infoContentSpinner = this.infoContentContainer.children('.album-info-loader'); this.infoContentElement = this.infoContentContainer.children('.album-info-content'); + this.markdownReader = new commonmark.Parser(); + this.htmlWriter = new commonmark.HtmlRenderer(); + this._initCustomSanitizer(); }; InfoBox.prototype = { @@ -17,6 +20,9 @@ infoContentSpinner: null, infoContentElement: null, albumInfo: null, + markdownReader: null, + htmlWriter: null, + allowedTags: null, /** * Shows an information box to the user @@ -41,9 +47,9 @@ thisInfoBox._addContent(data); } ).fail(function () { - thisInfoBox._addContent(t('gallery', - 'Could not load the description')); - }); + thisInfoBox._addContent(t('gallery', + 'Could not load the description')); + }); } else { this._addContent(this.albumInfo.description); } @@ -63,7 +69,7 @@ */ _addContent: function (content) { try { - content = marked(content); + content = this._parseMarkdown(content); } catch (exception) { content = t('gallery', 'Could not load the description: ' + exception.message); @@ -74,6 +80,21 @@ this._adjustHeight(); }, + /** + * Parses markdown content and sanitizes the HTML + * + * @param {string} content + * @private + */ + _parseMarkdown: function (content) { + return DOMPurify.sanitize(this.htmlWriter.render(this.markdownReader.parse(content), { + smart: true, + safe: true + }), { + ALLOWED_TAGS: this.allowedTags + }); + }, + /** * Adjusts the height of the element to match the content * @private @@ -101,7 +122,7 @@ if (!$.isEmptyObject(this.albumInfo.copyright)) { try { - copyright = marked(this.albumInfo.copyright); + copyright = this._parseMarkdown(this.albumInfo.copyright); } catch (exception) { copyright = t('gallery', @@ -115,6 +136,7 @@ this._addCopyrightLink(copyright); } else { this.infoContentElement.append(copyright); + this.infoContentElement.find('a').attr("target", "_blank"); } } }, @@ -139,6 +161,54 @@ target: "_blank" }); this.infoContentElement.append(copyrightLink); + }, + + /** + * Adds custom tags and rules to DomPurify + * + * @link https://github.com/cure53/DOMPurify/blob/master/demos/hooks-scheme-whitelist.html + * @private + */ + _initCustomSanitizer: function () { + this.allowedTags = + ['p', 'b', 'em', 'i', 'pre', 'sup', 'sub', 'strong', 'strike', 'br', 'hr', + 'h1', 'h2', 'h3', 'li', 'ul', 'ol', 'a', 'img', 'blockquote', 'code' + ]; + + // allowed URI schemes + var whitelist = ['http', 'https']; + + // build fitting regex + var regex = new RegExp('^(' + whitelist.join('|') + '):', 'gim'); + + // Add a hook to enforce URI scheme whitelist + DOMPurify.addHook('afterSanitizeAttributes', function (node) { + + // build an anchor to map URLs to + var anchor = document.createElement('a'); + + // check all href attributes for validity + if (node.hasAttribute('href')) { + anchor.href = node.getAttribute('href'); + if (anchor.protocol && !anchor.protocol.match(regex)) { + node.removeAttribute('href'); + } + } + // check all action attributes for validity + if (node.hasAttribute('action')) { + anchor.href = node.getAttribute('action'); + if (anchor.protocol && !anchor.protocol.match(regex)) { + node.removeAttribute('action'); + } + } + // check all xlink:href attributes for validity + if (node.hasAttribute('xlink:href')) { + anchor.href = node.getAttribute('xlink:href'); + if (anchor.protocol && !anchor.protocol.match(regex)) { + node.removeAttribute('xlink:href'); + } + } + }); } }; diff --git a/js/vendor/bigshot/bigshot-2.0.zip b/js/vendor/bigshot/bigshot-2.0.zip deleted file mode 100644 index fdfc0408c4..0000000000 Binary files a/js/vendor/bigshot/bigshot-2.0.zip and /dev/null differ diff --git a/js/vendor/bigshot/bigshot.js b/js/vendor/bigshot/bigshot.js deleted file mode 100644 index eee39bbee9..0000000000 --- a/js/vendor/bigshot/bigshot.js +++ /dev/null @@ -1,9717 +0,0 @@ -/* - * Copyright 2010 - 2012 Leo Sutic - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -if (!self["bigshot"]) { - /** - * @namespace Bigshot namespace. - * - * Bigshot is a toolkit for zoomable images and VR panoramas. - * - *

Zoomable Images

- * - *

The two classes that are needed for zoomable images are: - * - *

    - *
  • {@link bigshot.Image}: The main class for making zoomable images. See the class docs - * for a tutorial. - *
  • {@link bigshot.ImageParameters}: Parameters for zoomable images. - *
  • {@link bigshot.SimpleImage}: A class for making simple zoomable images that don't - * require the generation of an image pyramid.. See the class docs for a tutorial. - *
- * - * For hotspots, see: - * - *
    - *
  • {@link bigshot.HotspotLayer} - *
  • {@link bigshot.Hotspot} - *
  • {@link bigshot.LabeledHotspot} - *
  • {@link bigshot.LinkHotspot} - *
- * - *

VR Panoramas

- * - *

The two classes that are needed for zoomable VR panoramas (requires WebGL) are: - * - *

    - *
  • {@link bigshot.VRPanorama}: The main class for making VR panoramas. See the class docs - * for a tutorial. - *
  • {@link bigshot.VRPanoramaParameters}: Parameters for VR panoramas. - *
- * - * For hotspots, see: - * - *
    - *
  • {@link bigshot.VRHotspot} - *
  • {@link bigshot.VRRectangleHotspot} - *
  • {@link bigshot.VRPointHotspot} - *
- */ - bigshot = {}; - - /* - * This is supposed to be processed using a minimalhttpd.IncludeProcessor - * during development. The files must be listed in dependency order. - */ -/* - * Copyright 2010 - 2012 Leo Sutic - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -/** - * This class has no constructor, it is created as an object literal. - * @name bigshot.HomogeneousPoint3D - * @class A 3d homogenous point. - * @property {number} x the x-coordinate - * @property {number} y the y-coordinate - * @property {number} z the z-coordinate - * @property {number} w the w-coordinate - */ - -/** - * This class has no constructor, it is created as an object literal. - * @name bigshot.Point3D - * @class A 3d point. - * @property {number} x the x-coordinate - * @property {number} y the y-coordinate - * @property {number} z the z-coordinate - */ - -/** - * This class has no constructor, it is created as an object literal. - * @name bigshot.Point2D - * @class A 2d point. - * @property {number} x the x-coordinate - * @property {number} y the y-coordinate - */ - -/** - * This class has no constructor, it is created as an object literal. - * @name bigshot.Rotation - * @class A rotation specified as a yaw-pitch-roll triplet. - * @property {number} y the rotation around the yaw (y) axis - * @property {number} p the rotation around the pitch (x) axis - * @property {number} r the rotation around the roll (z) axis - */ - - -/* - * Copyright 2010 - 2012 Leo Sutic - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -/** - * @class Object-oriented support functions, used to make JavaScript - * a bit more palatable to a Java-head. - */ -bigshot.Object = { - /** - * Extends a base class with a derived class. - * - * @param {Function} derived the derived-class - * @param {Function} base the base-class - */ - extend : function (derived, base) { - for (var k in base.prototype) { - if (derived.prototype[k]) { - derived.prototype[k]._super = base.prototype[k]; - } else { - derived.prototype[k] = base.prototype[k]; - } - } - }, - - /** - * Resolves a name relative to self. - * - * @param {String} name the name to resolve - * @type {Object} - */ - resolve : function (name) { - var c = name.split ("."); - var clazz = self; - for (var i = 0; i < c.length; ++i) { - clazz = clazz[c[i]]; - } - return clazz; - }, - - validate : function (clazzName, iface) { - }, - - /** - * Utility function to show an object's fields in a message box. - * - * @param {Object} o the object - */ - alertr : function (o) { - var sb = ""; - for (var k in o) { - sb += k + ":" + o[k] + "\n"; - } - alert (sb); - }, - - /** - * Utility function to show an object's fields in the console log. - * - * @param {Object} o the object - */ - logr : function (o) { - var sb = ""; - for (var k in o) { - sb += k + ":" + o[k] + "\n"; - } - if (console) { - console.log (sb); - } - } -}; -/* - * Copyright 2010 - 2012 Leo Sutic - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -/** - * Creates a new browser helper object. - * - * @class Encapsulates common browser functions for cross-browser portability - * and convenience. - */ -bigshot.Browser = function () { - this.requestAnimationFrameFunction = - window.requestAnimationFrame || - window.mozRequestAnimationFrame || - window.webkitRequestAnimationFrame || - window.msRequestAnimationFrame || - function (callback, element) { return setTimeout (callback, 0); }; -} - -bigshot.Browser.prototype = { - /** - * Removes all children from an element. - * - * @public - * @param {HTMLElement} element the element whose children are to be removed. - */ - removeAllChildren : function (element) { - element.innerHTML = ""; - /* - if (element.children.length > 0) { - for (var i = element.children.length - 1; i >= 0; --i) { - element.removeChild (element.children[i]); - } - } - */ - }, - - /** - * Thunk to implement a faked "mouseenter" event. - * @private - */ - mouseEnter : function (_fn) { - var isAChildOf = this.isAChildOf; - return function(_evt) - { - var relTarget = _evt.relatedTarget; - if (this === relTarget || isAChildOf (this, relTarget)) - { return; } - - _fn.call (this, _evt); - } - }, - - isAChildOf : function (_parent, _child) { - if (_parent === _child) { return false; } - while (_child && _child !== _parent) - { _child = _child.parentNode; } - - return _child === _parent; - }, - - /** - * Unregisters a listener from an element. - * - * @param {HTMLElement} elem the element - * @param {String} eventName the event name ("click", "mouseover", etc.) - * @param {function(e)} fn the callback function to detach - * @param {boolean} useCapture specifies if we should unregister a listener from the capture chain. - */ - unregisterListener : function (elem, eventName, fn, useCapture) { - if (typeof (elem.removeEventListener) != 'undefined') { - elem.removeEventListener (eventName, fn, useCapture); - } else if (typeof (elem.detachEvent) != 'undefined') { - elem.detachEvent('on' + eventName, fn); - } - }, - - /** - * Registers a listener to an element. - * - * @param {HTMLElement} elem the element - * @param {String} eventName the event name ("click", "mouseover", etc.) - * @param {function(e)} fn the callback function to attach - * @param {boolean} useCapture specifies if we want to initiate capture. - * See element.addEventListener - * on MDN for an explanation. - */ - registerListener : function (_elem, _evtName, _fn, _useCapture) { - if (typeof _elem.addEventListener != 'undefined') - { - if (_evtName === 'mouseenter') - { _elem.addEventListener('mouseover', this.mouseEnter(_fn), _useCapture); } - else if (_evtName === 'mouseleave') - { _elem.addEventListener('mouseout', this.mouseEnter(_fn), _useCapture); } - else - { _elem.addEventListener(_evtName, _fn, _useCapture); } - } - else if (typeof _elem.attachEvent != 'undefined') - { - _elem.attachEvent('on' + _evtName, _fn); - } - else - { - _elem['on' + _evtName] = _fn; - } - }, - - /** - * Stops an event from bubbling. - * - * @param {Event} eventObject the event object - */ - stopEventBubbling : function (eventObject) { - if (eventObject) { - if (eventObject.stopPropagation) { - eventObject.stopPropagation (); - } else { - eventObject.cancelBubble = true; - } - } - }, - - /** - * Creates a callback function that simply stops the event from bubbling. - * - * @example - * var browser = new bigshot.Browser (); - * browser.registerListener (element, - * "mousedown", - * browser.stopEventBubblingHandler (), - * false); - * @type function(event) - * @return a new function that can be used to stop an event from bubbling - */ - stopEventBubblingHandler : function () { - var that = this; - return function (event) { - that.stopEventBubbling (event); - return false; - }; - }, - - /** - * Stops bubbling for all mouse events on the element. - * - * @param {HTMLElement} element the element - */ - stopMouseEventBubbling : function (element) { - this.registerListener (element, "mousedown", this.stopEventBubblingHandler (), false); - this.registerListener (element, "mouseup", this.stopEventBubblingHandler (), false); - this.registerListener (element, "mousemove", this.stopEventBubblingHandler (), false); - }, - - /** - * Returns the size in pixels of the element - * - * @param {HTMLElement} obj the element - * @return a size object with two integer members, w and h, for width and height respectively. - */ - getElementSize : function (obj) { - var size = {}; - if (obj.clientWidth) { - size.w = obj.clientWidth; - } - if (obj.clientHeight) { - size.h = obj.clientHeight; - } - return size; - }, - - /** - * Returns true if the browser is scaling the window, such as on Mobile Safari. - * The method used here is far from perfect, but it catches the most important use case: - * If we are running on an iDevice and the page is zoomed out. - */ - browserIsViewporting : function () { - if (window.innerWidth <= screen.width) { - return false; - } else { - return true; - } - }, - - /** - * Returns the device pixel scale, which is equal to the number of device - * pixels each css pixel corresponds to. Used to render the proper level of detail - * on mobile devices, especially when zoomed out and more detailed textures are - * simply wasted. - * - * @returns The number of device pixels each css pixel corresponds to. - * For example, if the browser is zoomed out to 50% and a div with width - * set to 100px occupies 50 physical pixels, the function will return - * 0.5. - * @type number - */ - getDevicePixelScale : function () { - if (this.browserIsViewporting ()) { - return screen.width / window.innerWidth; - } else { - return 1.0; - } - }, - - /** - * Requests an animation frame, if the API is supported - * on the browser. If not, a setTimeout with - * a timeout of zero is used. - * - * @param {function()} callback the animation frame render function - * @param {HTMLElement} element the element to use when requesting an - * animation frame - */ - requestAnimationFrame : function (callback, element) { - var raff = this.requestAnimationFrameFunction; - raff (callback, element); - }, - - /** - * Returns the position in pixels of the element relative - * to the top left corner of the document. - * - * @param {HTMLElement} obj the element - * @return a position object with two integer members, x and y. - */ - getElementPosition : function (obj) { - var position = new Object(); - position.x = 0; - position.y = 0; - - var o = obj; - while (o) { - position.x += o.offsetLeft; - position.y += o.offsetTop; - if (o.clientLeft) { - position.x += o.clientLeft; - } - if (o.clientTop) { - position.y += o.clientTop; - } - - if (o.x) { - position.x += o.x; - } - if (o.y) { - position.y += o.y; - } - o = o.offsetParent; - } - return position; - }, - - /** - * Creates an XMLHttpRequest object. - * - * @type XMLHttpRequest - * @returns a XMLHttpRequest object. - */ - createXMLHttpRequest : function () { - try { - return new ActiveXObject("Msxml2.XMLHTTP"); - } catch (e) { - } - - try { - return new ActiveXObject("Microsoft.XMLHTTP"); - } catch (e) { - } - - try { - return new XMLHttpRequest(); - } catch(e) { - } - - alert("XMLHttpRequest not supported"); - - return null; - }, - - /** - * Creates an opacity transition from opaque to transparent. - * If CSS transitions aren't supported, the element is - * immediately made transparent without a transition. - * - * @param {HTMLElement} element the element to fade out - * @param {function()} onComplete function to call when - * the transition is complete. - */ - makeOpacityTransition : function (element, onComplete) { - if (element.style.WebkitTransitionProperty != undefined) { - element.style.opacity = 1.0; - element.style.WebkitTransitionProperty = "opacity"; - element.style.WebkitTransitionTimingFunction = "linear"; - element.style.WebkitTransitionDuration = "1s"; - setTimeout (function () { - element.addEventListener ("webkitTransitionEnd", function () { - onComplete (); - }); - element.style.opacity = 0.0; - }, 0); - } else { - element.style.opacity = 0.0; - onComplete (); - } - } -}; -/* - * Copyright 2010 - 2012 Leo Sutic - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -/** - * Creates an event dispatcher. - * - * @class Base class for objects that dispatch events. - */ -bigshot.EventDispatcher = function () { - /** - * The event listeners. Each key-value pair in the map is - * an event name and an Array of listeners. - * - * @type Object - */ - this.eventListeners = {}; -} - -bigshot.EventDispatcher.prototype = { - /** - * Adds an event listener to the specified event. - * - * @example - * image.addEventListener ("click", function (event) { ... }); - * - * @param {String} eventName the name of the event to add a listener for - * @param {Function} handler function that is invoked with an event object - * when the event is fired - */ - addEventListener : function (eventName, handler) { - if (this.eventListeners[eventName] == undefined) { - this.eventListeners[eventName] = new Array (); - } - this.eventListeners[eventName].push (handler); - }, - - /** - * Removes an event listener. - * @param {String} eventName the name of the event to remove a listener for - * @param {Function} handler the handler to remove - */ - removeEventListener : function (eventName, handler) { - if (this.eventListeners[eventName] != undefined) { - var el = this.eventListeners[eventName]; - for (var i = 0; i < el.length; ++i) { - if (el[i] === listener) { - el.splice (i, 1); - if (el.length == 0) { - delete this.eventListeners[eventName]; - } - break; - } - } - } - }, - - /** - * Fires an event. - * - * @param {String} eventName the name of the event to fire - * @param {bigshot.Event} eventObject the event object to pass to the handlers - */ - fireEvent : function (eventName, eventObject) { - if (this.eventListeners[eventName] != undefined) { - var el = this.eventListeners[eventName]; - for (var i = 0; i < el.length; ++i) { - el[i](eventObject); - } - } - } -}; -/* - * Copyright 2010 - 2012 Leo Sutic - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -/** - * Creates an event. - * - * @class Base class for events. The interface is supposed to be as similar to - * standard DOM events as possible. - * @param {Object} data a data object whose fields will be used to set the - * corresponding fields of the event object. - */ -bigshot.Event = function (data) { - - /** - * Indicates whether the event bubbles. - * @default false - * @type boolean - */ - this.bubbles = false; - - /** - * Indicates whether the event is cancelable. - * @default false - * @type boolean - */ - this.cancelable = false; - - /** - * The current target of the event - * @default null - */ - this.currentTarget = null; - - /** - * Set if the preventDefault method has been called. - * @default false - * @type boolean - */ - this.defaultPrevented = false; - - /** - * The target to which the event is dispatched. - * @default null - */ - this.target = null; - - /** - * The time the event was created, in milliseconds since the epoch. - * @default the current time, as given by new Date ().getTime () - * @type number - */ - this.timeStamp = new Date ().getTime (); - - /** - * The event type. - * @default null - * @type String - */ - this.type = null; - - /** - * Flag indicating origin of event. - * @default false - * @type boolean - */ - this.isTrusted = false; - - for (var k in data) { - this[k] = data[k]; - } -} - -bigshot.Event.prototype = { - /** - * Prevents default handling of the event. - */ - preventDefault : function () { - this.defaultPrevented = true; - } -}; -/* - * Copyright 2010 - 2012 Leo Sutic - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - - -/** - * Creates a new instance of the cached resource. May return - * null, in which case that value is cached. The function - * may be called multiple times, but a corresponding call to - * the dispose function will always occur inbetween. - * @name bigshot.TimedWeakReference.Create - * @function - */ - -/** - * Disposes a of the cached resource. - * @name bigshot.TimedWeakReference.Dispose - * @function - * @param {Object} resource the resource that was created - * by the create function - */ - -/** - * Creates a new instance. - * - * @class Caches a lazy-created resource for a given time before - * disposing it. - * - * @param {bigshot.TimedWeakReference.Create} create a function that creates the - * held resource. May be called multiple times, but not without a call to - * dispose inbetween. - * @param {bigshot.TimedWeakReference.Dispose} dispose a function that disposes the - * resource created by create. - * @param {int} interval the polling interval in milliseconds. If the last - * access time is further back than one interval, the held resource is - * disposed (and will be re-created - * on the next call to get). - */ -bigshot.TimedWeakReference = function (create, dispose, interval) { - this.object = null; - this.hasObject = false; - this.fnCreate = create; - this.fnDispose = dispose; - this.lastAccess = new Date ().getTime (); - this.hasTimer = false; - this.interval = interval; -}; - -bigshot.TimedWeakReference.prototype = { - /** - * Disposes of this instance. The resource is disposed. - */ - dispose : function () { - this.clear (); - }, - - /** - * Gets the resource. The resource is created if needed. - * The last access time is updated. - */ - get : function () { - if (!this.hasObject) { - this.hasObject = true; - this.object = this.fnCreate (); - this.startTimer (); - } - this.lastAccess = new Date ().getTime (); - return this.object; - }, - - /** - * Forcibly disposes the held resource, if any. - */ - clear : function () { - if (this.hasObject) { - this.hasObject = false; - this.fnDispose (this.object); - this.object = null; - this.stopTimer (); - } - }, - - /** - * Stops the polling timer if it is running. - * @private - */ - stopTimer : function () { - if (this.hasTimer) { - clearTimeout (this.timerId); - this.hasTimer = false; - } - }, - - /** - * Starts the polling timer if it isn't already running. - * @private - */ - startTimer : function () { - if (!this.hasTimer) { - var that = this; - this.hasTimer = true; - this.timerId = setTimeout (function () { - that.hasTimer = false; - that.update (); - }, this.interval); - } - }, - - /** - * Disposes of the held resource if it hasn't been - * accessed in {@link #interval} milliseconds. - * @private - */ - update : function () { - if (this.hasObject) { - var now = new Date ().getTime (); - if (now - this.lastAccess > this.interval) { - this.clear (); - } else { - this.startTimer (); - } - } - } -} - -/* - * Copyright 2010 - 2012 Leo Sutic - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -/** - * Creates an image event. - * - * @class Base class for events dispatched by bigshot.ImageBase. - * @param {Object} data a data object whose fields will be used to set the - * corresponding fields of the event object. - * @extends bigshot.Event - * @see bigshot.ImageBase - */ -bigshot.ImageEvent = function (data) { - bigshot.Event.call (this, data); -} - -/** - * The image X coordinate of the event, if any. - * - * @name bigshot.ImageEvent#imageX - * @field - * @type number - */ - -/** - * The image Y coordinate of the event, if any. - * - * @name bigshot.ImageEvent#imageY - * @field - * @type number - */ - -/** - * The client X coordinate of the event, if any. - * - * @name bigshot.ImageEvent#clientX - * @field - * @type number - */ - -/** - * The client Y coordinate of the event, if any. - * - * @name bigshot.ImageEvent#clientY - * @field - * @type number - */ - -/** - * The local X coordinate of the event, if any. - * - * @name bigshot.ImageEvent#localX - * @field - * @type number - */ - -/** - * The local Y coordinate of the event, if any. - * - * @name bigshot.ImageEvent#localY - * @field - * @type number - */ - - -bigshot.ImageEvent.prototype = { -}; - -bigshot.Object.extend (bigshot.ImageEvent, bigshot.Event); -/* - * Copyright 2010 - 2012 Leo Sutic - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -/** - * Creates an image event. - * - * @class Base class for events dispatched by bigshot.VRPanorama. - * @param {Object} data a data object whose fields will be used to set the - * corresponding fields of the event object. - * @extends bigshot.Event - * @see bigshot.VRPanorama - */ -bigshot.VREvent = function (data) { - bigshot.Event.call (this, data); -} - -/** - * The yaw coordinate of the event, if any. - * - * @name bigshot.VREvent#yaw - * @field - * @type number - */ - -/** - * The pitch coordinate of the event, if any. - * - * @name bigshot.VREvent#pitch - * @field - * @type number - */ - -/** - * The client X coordinate of the event, if any. - * - * @name bigshot.VREvent#clientX - * @field - * @type number - */ - -/** - * The client Y coordinate of the event, if any. - * - * @name bigshot.VREvent#clientY - * @field - * @type number - */ - -/** - * The local X coordinate of the event, if any. - * - * @name bigshot.VREvent#localX - * @field - * @type number - */ - -/** - * The local Y coordinate of the event, if any. - * - * @name bigshot.VREvent#localY - * @field - * @type number - */ - -/** - * A x,y,z triplet specifying a 3D ray from the viewer in the direction the - * event took place. The same as the yaw and pitch fields, but in Cartesian - * coordinates. - * - * @name bigshot.VREvent#ray - * @field - * @type xyz-triplet - */ - - -bigshot.VREvent.prototype = { -}; - -bigshot.Object.extend (bigshot.VREvent, bigshot.Event); -/* - * Copyright 2010 - 2012 Leo Sutic - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -/** - * Creates a new full-screen handler for an element. - * - * @class A utility class for making an element "full screen", or as close to that - * as browser security allows. If the browser supports the requestFullScreen - * API - as standard or as moz- or webkit- extensions, - * this will be used. - * - * @param {HTMLElement} container the element that is to be made full screen - */ -bigshot.FullScreen = function (container) { - this.container = container; - - this.isFullScreen = false; - this.savedBodyStyle = null; - this.savedParent = null; - this.savedSize = null; - this.expanderDiv = null; - this.restoreSize = false; - - this.onCloseHandlers = new Array (); - this.onResizeHandlers = new Array (); - - var findFunc = function (el, list) { - for (var i = 0; i < list.length; ++i) { - if (el[list[i]]) { - return list[i]; - } - } - return null; - }; - - this.requestFullScreen = findFunc (container, ["requestFullScreen", "mozRequestFullScreen", "webkitRequestFullscreen"]); - this.cancelFullScreen = findFunc (document, ["cancelFullScreen", "mozCancelFullScreen", "webkitCancelFullscreen"]); - - this.restoreSize = this.requestFullScreen != null; -} - -bigshot.FullScreen.prototype = { - browser : new bigshot.Browser (), - - getRootElement : function () { - return this.div; - }, - - /** - * Adds a function that will run when exiting full screen mode. - * - * @param {function()} onClose the function to call - */ - addOnClose : function (onClose) { - this.onCloseHandlers.push (onClose); - }, - - /** - * Notifies all onClose handlers. - * - * @private - */ - onClose : function () { - for (var i = 0; i < this.onCloseHandlers.length; ++i) { - this.onCloseHandlers[i] (); - } - }, - - /** - * Adds a function that will run when the element is resized. - * - * @param {function()} onResize the function to call - */ - addOnResize : function (onResize) { - this.onResizeHandlers.push (onResize); - }, - - /** - * Notifies all resize handlers. - * - * @private - */ - onResize : function () { - for (var i = 0; i < this.onResizeHandlers.length; ++i) { - this.onResizeHandlers[i] (); - } - }, - - /** - * Begins full screen mode. - */ - open : function () { - this.isFullScreen = true; - - if (this.requestFullScreen) { - return this.openRequestFullScreen (); - } else { - return this.openCompat (); - } - }, - - /** - * Makes the element really full screen using the requestFullScreen - * API. - * - * @private - */ - openRequestFullScreen : function () { - this.savedSize = { - width : this.container.style.width, - height : this.container.style.height - }; - - this.container.style.width = "100%"; - this.container.style.height = "100%"; - - var that = this; - - if (this.requestFullScreen == "mozRequestFullScreen") { - /** - * @private - */ - var errFun = function () { - that.container.removeEventListener ("mozfullscreenerror", errFun); - that.isFullScreen = false; - that.exitFullScreenHandler (); - that.onClose (); - }; - this.container.addEventListener ("mozfullscreenerror", errFun); - - /** - * @private - */ - var changeFun = function () { - if (document.mozFullScreenElement !== that.container) { - document.removeEventListener ("mozfullscreenchange", changeFun); - that.exitFullScreenHandler (); - } else { - that.onResize (); - } - }; - document.addEventListener ("mozfullscreenchange", changeFun); - } else { - /** - * @private - */ - var changeFun = function () { - if (document.webkitCurrentFullScreenElement !== that.container) { - that.container.removeEventListener ("webkitfullscreenchange", changeFun); - that.exitFullScreenHandler (); - } else { - that.onResize (); - } - }; - this.container.addEventListener ("webkitfullscreenchange", changeFun); - } - - this.exitFullScreenHandler = function () { - if (that.isFullScreen) { - that.isFullScreen = false; - document[that.cancelFullScreen](); - if (that.restoreSize) { - that.container.style.width = that.savedSize.width; - that.container.style.height = that.savedSize.height; - } - that.onResize (); - that.onClose (); - } - }; - this.container[this.requestFullScreen](Element.ALLOW_KEYBOARD_INPUT); - }, - - /** - * Makes the element "full screen" in older browsers by covering the browser's client area. - * - * @private - */ - openCompat : function () { - this.savedParent = this.container.parentNode; - - this.savedSize = { - width : this.container.style.width, - height : this.container.style.height - }; - this.savedBodyStyle = document.body.style.cssText; - - document.body.style.overflow = "hidden"; - - this.expanderDiv = document.createElement ("div"); - this.expanderDiv.style.position = "absolute"; - this.expanderDiv.style.top = "0px"; - this.expanderDiv.style.left = "0px"; - this.expanderDiv.style.width = Math.max (window.innerWidth, document.documentElement.clientWidth) + "px"; - this.expanderDiv.style.height = Math.max (window.innerHeight, document.documentElement.clientHeight) + "px"; - - document.body.appendChild (this.expanderDiv); - - this.div = document.createElement ("div"); - this.div.style.position = "fixed"; - this.div.style.top = window.pageYOffset + "px"; - this.div.style.left = window.pageXOffset + "px"; - - this.div.style.width = window.innerWidth + "px"; - this.div.style.height = window.innerHeight + "px"; - this.div.style.zIndex = 9998; - - this.div.appendChild (this.container); - - //this.container.style.width = window.innerWidth + "px"; - //this.container.style.height = window.innerHeight + "px"; - - document.body.appendChild (this.div); - - var that = this; - var resizeHandler = function (e) { - setTimeout (function () { - that.div.style.width = window.innerWidth + "px"; - that.div.style.height = window.innerHeight + "px"; - setTimeout (function () { - that.onResize (); - }, 1); - }, 1); - }; - - - var rotationHandler = function (e) { - that.expanderDiv.style.width = Math.max (window.innerWidth, document.documentElement.clientWidth) + "px"; - that.expanderDiv.style.height = Math.max (window.innerHeight, document.documentElement.clientHeight) + "px"; - setTimeout (function () { - that.div.style.top = window.pageYOffset + "px"; - that.div.style.left = window.pageXOffset + "px"; - that.div.style.width = window.innerWidth + "px"; - that.div.style.height = window.innerHeight + "px"; - setTimeout (function () { - that.onResize (); - }, 1); - }, 1); - }; - - var escHandler = function (e) { - if (e.keyCode == 27) { - that.exitFullScreenHandler (); - } - }; - - this.exitFullScreenHandler = function () { - that.isFullScreen = false; - that.browser.unregisterListener (document, "keydown", escHandler); - that.browser.unregisterListener (window, "resize", resizeHandler); - that.browser.unregisterListener (document.body, "orientationchange", rotationHandler); - if (that.restoreSize) { - that.container.style.width = that.savedSize.width; - that.container.style.height = that.savedSize.height; - } - - document.body.style.cssText = that.savedBodyStyle; - - that.savedParent.appendChild (that.container); - document.body.removeChild (that.div); - document.body.removeChild (that.expanderDiv); - - that.onResize (); - that.onClose (); - setTimeout (function () { - that.onResize (); - }, 1); - }; - - this.browser.registerListener (document, "keydown", escHandler, false); - this.browser.registerListener (window, "resize", resizeHandler, false); - this.browser.registerListener (document.body, "orientationchange", rotationHandler, false); - - this.onResize (); - - return this.exitFullScreenHandler; - }, - - /** - * Ends full screen mode. - */ - close : function () { - this.exitFullScreenHandler (); - } -}; - -/* - * Copyright 2010 - 2012 Leo Sutic - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -/** - * @class Loads image and XML data. - */ -bigshot.DataLoader = function () { -} - -bigshot.DataLoader.prototype = { - /** - * Loads an image. - * - * @param {String} url the url to load - * @param {function(success,img)} onloaded called on complete - */ - loadImage : function (url, onloaded) {}, - - /** - * Loads XML data. - * - * @param {String} url the url to load - * @param {boolean} async use async request - * @param {function(success,xml)} [onloaded] called on complete for async requests - * @return the xml for synchronous calls - */ - loadXml : function (url, async, onloaded) {} -} -/* - * Copyright 2010 - 2012 Leo Sutic - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -/** - * Creates a new data loader. - * - * @param {int} [maxRetries=0] the maximum number of times to retry requests - * @param {String} [crossOrigin] the CORS crossOrigin parameter to use when loading images - * @class Data loader using standard browser functions. - * @augments bigshot.DataLoader - */ -bigshot.DefaultDataLoader = function (maxRetries, crossOrigin) { - this.maxRetries = maxRetries; - this.crossOrigin = crossOrigin; - - if (!this.maxRetries) { - this.maxRetries = 0; - } -} - -bigshot.DefaultDataLoader.prototype = { - browser : new bigshot.Browser (), - - loadImage : function (url, onloaded) { - var tile = document.createElement ("img"); - tile.retries = 0; - if (this.crossOrigin != null) { - tile.crossOrigin = this.crossOrigin; - } - var that = this; - this.browser.registerListener (tile, "load", function () { - if (onloaded) { - onloaded (tile); - } - }, false); - this.browser.registerListener (tile, "error", function () { - tile.retries++; - if (tile.retries <= that.maxRetries) { - setTimeout (function () { - tile.src = url; - }, tile.retries * 1000); - } else { - if (onloaded) { - onloaded (null); - } - } - }, false); - tile.src = url; - return tile; - }, - - loadXml : function (url, synchronous, onloaded) { - for (var tries = 0; tries <= this.maxRetries; ++tries) { - var req = this.browser.createXMLHttpRequest (); - - req.open("GET", url, false); - req.send(null); - if(req.status == 200) { - var xml = req.responseXML; - if (xml != null) { - if (onloaded) { - onloaded (xml); - } - return xml; - } - } - - if (tries == that.maxRetries) { - if (onloaded) { - onloaded (null); - } - return null; - } - } - } -} - -bigshot.Object.validate ("bigshot.DefaultDataLoader", bigshot.DataLoader); -/* - * Copyright 2010 - 2012 Leo Sutic - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -/** - * @class Data loader using standard browser functions that maintains - * an in-memory cache of everything loaded. - * @augments bigshot.DataLoader - */ -bigshot.CachingDataLoader = function () { - this.cache = {}; - this.requested = {}; - this.requestedTiles = {}; -} - -bigshot.CachingDataLoader.prototype = { - - browser : new bigshot.Browser (), - - loadImage : function (url, onloaded) { - if (this.cache[url]) { - if (onloaded) { - onloaded (this.cache[url]); - } - return this.cache[url]; - } else if (this.requested[url]) { - if (onloaded) { - this.requested[url].push (onloaded); - } - return this.requestedTiles[url]; - } else { - var that = this; - this.requested[url] = new Array (); - if (onloaded) { - this.requested[url].push (onloaded); - } - - var tile = document.createElement ("img"); - this.requestedTiles[url] = tile; - this.browser.registerListener (tile, "load", function () { - var listeners = that.requested[url]; - delete that.requested[url]; - delete that.requestedTiles[url]; - that.cache[url] = tile; - - for (var i = 0; i < listeners.length; ++i) { - listeners[i] (tile); - } - }, false); - tile.src = url; - return tile; - } - }, - - loadXml : function (url, async, onloaded) { - if (this.cache[url]) { - if (onloaded) { - onloaded (this.cache[url]); - } - return this.cache[url]; - } else if (this.requested[url] && async) { - if (onloaded) { - this.requested[url].push (onloaded); - } - } else { - var req = this.browser.createXMLHttpRequest (); - - if (!this.requested[url]) { - this.requested[url] = new Array (); - } - - if (async) { - if (onloaded) { - this.requested[url].push (onloaded); - } - } - - var that = this; - var finishRequest = function () { - if (that.requested[url]) { - var xml = null; - if(req.status == 200) { - xml = req.responseXML; - } - var listeners = that.requested[url]; - delete that.requested[url]; - that.cache[url] = xml - - for (var i = 0; i < listeners.length; ++i) { - listeners[i](xml); - } - } - return xml; - }; - - if (async) { - req.onreadystatechange = function () { - if (req.readyState == 4) { - finishRequest (); - } - }; - req.open("GET", url, true); - req.send (); - } else { - req.open("GET", url, false); - req.send (); - return finishRequest (); - } - } - } -} - -bigshot.Object.validate ("bigshot.CachingDataLoader", bigshot.DataLoader); -/* - * Copyright 2010 - 2012 Leo Sutic - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -/** - * Creates a new hotspot instance. - * - * @class Base class for hotspots in a {@link bigshot.HotspotLayer}. See {@link bigshot.HotspotLayer} for - * examples. - * - * @param {number} x x-coordinate of the top-left corner, given in full image pixels - * @param {number} y y-coordinate of the top-left corner, given in full image pixels - * @param {number} w width of the hotspot, given in full image pixels - * @param {number} h height of the hotspot, given in full image pixels - * @see bigshot.HotspotLayer - * @see bigshot.LabeledHotspot - * @see bigshot.LinkHotspot - * @constructor - */ -bigshot.Hotspot = function (x, y, w, h) { - var element = document.createElement ("div"); - element.style.position = "absolute"; - element.style.overflow = "visible"; - - this.element = element; - this.x = x; - this.y = y; - this.w = w; - this.h = h; -} - -bigshot.Hotspot.prototype = { - - browser : new bigshot.Browser (), - - /** - * Lays out the hotspot in the viewport. - * - * @name bigshot.Hotspot#layout - * @param x0 x-coordinate of top-left corner of the full image in css pixels - * @param y0 y-coordinate of top-left corner of the full image in css pixels - * @param zoomFactor the zoom factor. - * @function - */ - layout : function (x0, y0, zoomFactor) { - var sx = this.x * zoomFactor + x0; - var sy = this.y * zoomFactor + y0; - var sw = this.w * zoomFactor; - var sh = this.h * zoomFactor; - this.element.style.top = sy + "px"; - this.element.style.left = sx + "px"; - this.element.style.width = sw + "px"; - this.element.style.height = sh + "px"; - }, - - /** - * Returns the HTMLDivElement used to show the hotspot. - * Clients can access this element in order to style it. - * - * @type HTMLDivElement - */ - getElement : function () { - return this.element; - } -}; -/* - * Copyright 2010 - 2012 Leo Sutic - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -/** - * Creates a new labeled hotspot instance. - * - * @class A point hotspot consisting of an image. - * - * @see bigshot.HotspotLayer - * @param {number} x x-coordinate of the center corner, given in full image pixels - * @param {number} y y-coordinate of the center corner, given in full image pixels - * @param {number} w width of the hotspot, given in screen pixels - * @param {number} h height of the hotspot, given in screen pixels - * @param {number} xo x-offset, given in screen pixels - * @param {number} yo y-offset, given in screen pixels - * @param {HTMLElement} element the HTML element to position - * @param {String} [imageUrl] the image to use as hotspot sprite - * @augments bigshot.Hotspot - */ -bigshot.PointHotspot = function (x, y, w, h, xo, yo, imageUrl) { - bigshot.Hotspot.call (this, x, y, w, h); - this.xo = xo; - this.yo = yo; - - if (imageUrl) { - var el = this.getElement (); - el.style.backgroundImage = "url('" + imageUrl + "')"; - el.style.backgroundRepeat = "no-repeat"; - } -} - -bigshot.PointHotspot.prototype = { - /** - * Returns the label element. - * - * @type HTMLDivElement - */ - getLabel : function () { - return this.label; - }, - - layout : function (x0, y0, zoomFactor) { - var sx = this.x * zoomFactor + x0 + this.xo; - var sy = this.y * zoomFactor + y0 + this.yo; - this.element.style.top = sy + "px"; - this.element.style.left = sx + "px"; - this.element.style.width = this.w + "px"; - this.element.style.height = this.h + "px"; - } -}; - -bigshot.Object.extend (bigshot.PointHotspot, bigshot.Hotspot); - -/* - * Copyright 2010 - 2012 Leo Sutic - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -/** - * Abstract interface description for a Layer. - * - * @class Abstract interface description for a layer. - */ -bigshot.Layer = function () { -} - -bigshot.Layer.prototype = { - /** - * Returns the layer container. - * - * @type HTMLDivElement - */ - getContainer : function () {}, - - /** - * Sets the maximum number of image tiles that will be visible in the image. - * - * @param {int} x the number of tiles horizontally - * @param {int} y the number of tiles vertically - */ - setMaxTiles : function (x, y) {}, - - /** - * Called when the image's viewport is resized. - * - * @param {int} w the new width of the viewport, in css pixels - * @param {int} h the new height of the viewport, in css pixels - */ - resize : function (w, h) {}, - - /** - * Lays out the layer. - * - * @param {number} zoom the zoom level, adjusted for texture stretching - * @param {number} x0 the x-coordinate of the top-left corner of the top-left tile in css pixels - * @param {number} y0 the y-coordinate of the top-left corner of the top-left tile in css pixels - * @param {number} tx0 column number (starting at zero) of the top-left tile - * @param {number} ty0 row number (starting at zero) of the top-left tile - * @param {number} size the {@link bigshot.ImageParameters#tileSize} - width of each - * image tile in pixels - of the image - * @param {number} stride offset (vertical and horizontal) from the top-left corner - * of a tile to the next tile's top-left corner. - * @param {number} opacity the opacity of the layer as a CSS opacity value. - */ - layout : function (zoom, x0, y0, tx0, ty0, size, stride, opacity) {} -}; -/* - * Copyright 2010 - 2012 Leo Sutic - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -/** - * Creates a new labeled hotspot instance. - * - * @class A hotspot with a label under it. The label element can be accessed using - * the getLabel method and styled as any HTMLElement. See {@link bigshot.HotspotLayer} for - * examples. - * - * @see bigshot.HotspotLayer - * @param {number} x x-coordinate of the top-left corner, given in full image pixels - * @param {number} y y-coordinate of the top-left corner, given in full image pixels - * @param {number} w width of the hotspot, given in full image pixels - * @param {number} h height of the hotspot, given in full image pixels - * @param {String} labelText text of the label - * @augments bigshot.Hotspot - */ -bigshot.LabeledHotspot = function (x, y, w, h, labelText) { - bigshot.Hotspot.call (this, x, y, w, h); - - this.label = document.createElement ("div"); - this.label.style.position = "relative"; - this.label.style.display = "inline-block"; - - this.getElement ().appendChild (this.label); - this.label.innerHTML = labelText; - this.labelSize = this.browser.getElementSize (this.label); -} - -bigshot.LabeledHotspot.prototype = { - /** - * Returns the label element. - * - * @type HTMLDivElement - */ - getLabel : function () { - return this.label; - }, - - layout : function (x0, y0, zoomFactor) { - this.layout._super.call (this, x0, y0, zoomFactor); - var sw = this.w * zoomFactor; - var sh = this.h * zoomFactor; - this.label.style.top = (sh + 4) + "px"; - this.label.style.left = ((sw - this.labelSize.w) / 2) + "px"; - } -}; - -bigshot.Object.extend (bigshot.LabeledHotspot, bigshot.Hotspot); - -/* - * Copyright 2010 - 2012 Leo Sutic - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -/** - * Creates a new link-hotspot instance. - * - * @class A labeled hotspot that takes the user to another - * location when it is clicked on. See {@link bigshot.HotspotLayer} for - * examples. - * - * @see bigshot.HotspotLayer - * @param {number} x x-coordinate of the top-left corner, given in full image pixels - * @param {number} y y-coordinate of the top-left corner, given in full image pixels - * @param {number} w width of the hotspot, given in full image pixels - * @param {number} h height of the hotspot, given in full image pixels - * @param {String} labelText text of the label - * @param {String} url url to go to on click - * @augments bigshot.LabeledHotspot - * @constructor - */ -bigshot.LinkHotspot = function (x, y, w, h, labelText, url) { - bigshot.LabeledHotspot.call (this, x, y, w, h, labelText); - this.browser.registerListener (this.getElement (), "click", function () { - document.location.href = url; - }); -}; - -bigshot.Object.extend (bigshot.LinkHotspot, bigshot.LabeledHotspot); -/* - * Copyright 2010 - 2012 Leo Sutic - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -/** - * Creates a new hotspot layer. The layer must be added to the image using - * {@link bigshot.ImageBase#addLayer}. - * - * @class A hotspot layer. - * @example - * var image = new bigshot.Image (...); - * var hotspotLayer = new bigshot.HotspotLayer (image); - * var hotspot = new bigshot.LinkHotspot (100, 100, 200, 100, - * "Bigshot on Google Code", - * "http://code.google.com/p/bigshot/"); - * - * // Style the hotspot a bit - * hotspot.getElement ().className = "hotspot"; - * hotspot.getLabel ().className = "label"; - * - * hotspotLayer.addHotspot (hotspot); - * - * image.addLayer (hotspotLayer); - * - * @param {bigshot.ImageBase} image the image this hotspot layer will be part of - * @augments bigshot.Layer - * @constructor - */ -bigshot.HotspotLayer = function (image) { - this.image = image; - this.hotspots = new Array (); - this.browser = new bigshot.Browser (); - this.container = image.createLayerContainer (); - this.parentContainer = image.getContainer (); - this.resize (0, 0); -} - -bigshot.HotspotLayer.prototype = { - - getContainer : function () { - return this.container; - }, - - resize : function (w, h) { - this.container.style.width = this.parentContainer.clientWidth + "px"; - this.container.style.height = this.parentContainer.clientHeight + "px"; - }, - - layout : function (zoom, x0, y0, tx0, ty0, size, stride, opacity) { - var zoomFactor = Math.pow (2, this.image.getZoom ()); - x0 -= stride * tx0; - y0 -= stride * ty0; - for (var i = 0; i < this.hotspots.length; ++i) { - this.hotspots[i].layout (x0, y0, zoomFactor); - } - }, - - setMaxTiles : function (mtx, mty) { - }, - - /** - * Adds a hotspot to the layer. - * - * @param {bigshot.Hotspot} hotspot the hotspot to add. - */ - addHotspot : function (hotspot) { - this.container.appendChild (hotspot.getElement ()); - this.hotspots.push (hotspot); - } -} - -bigshot.Object.validate ("bigshot.HotspotLayer", bigshot.Layer); -/* - * Copyright 2010 - 2012 Leo Sutic - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -/** - * Creates a new image layer. - * - * @param {bigshot.ImageBase} image the image that this layer is part of - * @param {bigshot.ImageParameters} parameters the associated image parameters - * @param {number} w the current width in css pixels of the viewport - * @param {number} h the current height in css pixels of the viewport - * @param {bigshot.ImageTileCache} itc the tile cache to use - * @class A tiled, zoomable image layer. - * @constructor - */ -bigshot.TileLayer = function (image, parameters, w, h, itc) { - this.rows = new Array (); - this.browser = new bigshot.Browser (); - this.container = image.createLayerContainer (); - this.parentContainer = image.getContainer (); - this.parameters = parameters; - this.w = w; - this.h = h; - this.imageTileCache = itc; - - this.resize (w, h); - return this; -} - -bigshot.TileLayer.prototype = { - getContainer : function () { - return this.container; - }, - - resize : function (w, h) { - this.container.style.width = this.parentContainer.clientWidth + "px"; - this.container.style.height = this.parentContainer.clientHeight + "px"; - this.pixelWidth = this.parentContainer.clientWidth; - this.pixelHeight = this.parentContainer.clientHeight; - this.w = w; - this.h = h; - this.rows = new Array (); - this.browser.removeAllChildren (this.container); - for (var r = 0; r < h; ++r) { - var row = new Array (); - for (var c = 0; c < w; ++c) { - var tileAnchor = document.createElement ("div"); - tileAnchor.style.position = "absolute"; - tileAnchor.style.overflow = "hidden"; - tileAnchor.style.width = this.container.clientWidth + "px"; - tileAnchor.style.height = this.container.clientHeight + "px"; - - var tile = document.createElement ("div"); - tile.style.position = "relative"; - tile.style.border = "hidden"; - tile.style.visibility = "hidden"; - tile.bigshotData = { - visible : false - }; - row.push (tile); - this.container.appendChild (tileAnchor); - tileAnchor.appendChild (tile); - } - this.rows.push (row); - } - }, - - layout : function (zoom, x0, y0, tx0, ty0, size, stride, opacity) { - zoom = Math.min (0, Math.ceil (zoom)); - - this.imageTileCache.resetUsed (); - var y = y0; - - var visible = 0; - for (var r = 0; r < this.h; ++r) { - var x = x0; - for (var c = 0; c < this.w; ++c) { - var tile = this.rows[r][c]; - var bigshotData = tile.bigshotData; - if (x + size < 0 || x > this.pixelWidth || y + size < 0 || y > this.pixelHeight) { - if (bigshotData.visible) { - bigshotData.visible = false; - tile.style.visibility = "hidden"; - } - } else { - visible++; - tile.style.left = x + "px"; - tile.style.top = y + "px"; - tile.style.width = size + "px"; - tile.style.height = size + "px"; - tile.style.opacity = opacity; - if (!bigshotData.visible) { - bigshotData.visible = true; - tile.style.visibility = "visible"; - } - var tx = c + tx0; - var ty = r + ty0; - if (this.parameters.wrapX) { - if (tx < 0 || tx >= this.imageTileCache.maxTileX) { - tx = (tx + this.imageTileCache.maxTileX) % this.imageTileCache.maxTileX; - } - } - - if (this.parameters.wrapY) { - if (ty < 0 || ty >= this.imageTileCache.maxTileY) { - ty = (ty + this.imageTileCache.maxTileY) % this.imageTileCache.maxTileY; - } - } - - var imageKey = tx + "_" + ty + "_" + zoom; - var isOutside = tx < 0 || tx >= this.imageTileCache.maxTileX || ty < 0 || ty >= this.imageTileCache.maxTileY; - if (isOutside) { - if (!bigshotData.isOutside) { - var image = this.imageTileCache.getImage (tx, ty, zoom); - - this.browser.removeAllChildren (tile); - tile.appendChild (image); - bigshotData.image = image; - } - bigshotData.isOutside = true; - bigshotData.imageKey = "EMPTY"; - bigshotData.image.style.width = size + "px"; - bigshotData.image.style.height = size + "px"; - } else { - var image = this.imageTileCache.getImage (tx, ty, zoom); - - bigshotData.isOutside = false; - - if (bigshotData.imageKey !== imageKey || bigshotData.isPartial) { - this.browser.removeAllChildren (tile); - tile.appendChild (image); - bigshotData.image = image; - bigshotData.imageKey = imageKey; - bigshotData.isPartial = image.isPartial; - } - bigshotData.image.style.width = size + "px"; - bigshotData.image.style.height = size + "px"; - - } - } - x += stride; - } - y += stride; - } - }, - - setMaxTiles : function (mtx, mty) { - this.imageTileCache.setMaxTiles (mtx, mty); - } -}; - -bigshot.Object.validate ("bigshot.TileLayer", bigshot.Layer); -/* - * Copyright 2010 - 2012 Leo Sutic - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -/** - * Creates a new, empty, LRUMap instance. - * - * @class Implementation of a Least-Recently-Used cache map. - * Used by the ImageTileCache to keep track of cache entries. - * @constructor - */ -bigshot.LRUMap = function () { - /** - * Key to last-accessed time mapping. - * - * @type Object - */ - this.keyToTime = {}; - - /** - * Current time counter. Incremented for each access of - * a key in the map. - * @type int - */ - this.counter = 0; - - /** - * Current size of the map. - * @type int - */ - this.size = 0; -} - -bigshot.LRUMap.prototype = { - /** - * Marks access to an item, represented by its key in the map. - * The key's last-accessed time is updated to the current time - * and the current time is incremented by one step. - * - * @param {String} key the key associated with the accessed item - */ - access : function (key) { - this.remove (key); - this.keyToTime[key] = this.counter; - ++this.counter; - ++this.size; - }, - - /** - * Removes a key from the map. - * - * @param {String} key the key to remove - * @returns true iff the key existed in the map. - * @type boolean - */ - remove : function (key) { - if (this.keyToTime[key]) { - delete this.keyToTime[key]; - --this.size; - return true; - } else { - return false; - } - }, - - /** - * Returns the current number of keys in the map. - * @type int - */ - getSize : function () { - return this.size; - }, - - /** - * Returns the key in the map with the lowest - * last-accessed time. This is done as a linear - * search through the map. It could be done much - * faster with a sorted map, but unless this becomes - * a bottleneck it is just not worth the effort. - * @type String - */ - leastUsed : function () { - var least = this.counter + 1; - var leastKey = null; - for (var k in this.keyToTime) { - if (this.keyToTime[k] < least) { - least = this.keyToTime[k]; - leastKey = k; - } - } - return leastKey; - } -}; -/* - * Copyright 2010 - 2012 Leo Sutic - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -/** - * Creates a new cache instance. - * - * @class Tile cache for the {@link bigshot.TileLayer}. - * @constructor - */ -bigshot.ImageTileCache = function (onLoaded, onCacheInit, parameters) { - var that = this; - - this.parameters = parameters; - - /** - * Reduced-resolution preview of the full image. - * Loaded from the "poster" image created by - * MakeImagePyramid - * - * @private - * @type HTMLImageElement - */ - this.fullImage = null; - parameters.dataLoader.loadImage (parameters.fileSystem.getPosterFilename (), function (tile) { - that.fullImage = tile; - if (onCacheInit) { - onCacheInit (); - } - }); - - /** - * Maximum number of tiles in the cache. - * @private - * @type int - */ - this.maxCacheSize = 512; - this.maxTileX = 0; - this.maxTileY = 0; - this.cachedImages = {}; - this.requestedImages = {}; - this.usedImages = {}; - this.lastOnLoadFiredAt = 0; - this.imageRequests = 0; - this.lruMap = new bigshot.LRUMap (); - this.onLoaded = onLoaded; - this.browser = new bigshot.Browser (); - this.partialImageSize = parameters.tileSize / 4; - this.POSTER_ZOOM_LEVEL = Math.log (parameters.posterSize / Math.max (parameters.width, parameters.height)) / Math.log (2); -} - -bigshot.ImageTileCache.prototype = { - resetUsed : function () { - this.usedImages = {}; - }, - - setMaxTiles : function (mtx, mty) { - this.maxTileX = mtx; - this.maxTileY = mty; - }, - - getPartialImage : function (tileX, tileY, zoomLevel) { - var img = this.getPartialImageFromDownsampled (tileX, tileY, zoomLevel, 0, 0, this.parameters.tileSize, this.parameters.tileSize); - if (img == null) { - img = this.getPartialImageFromPoster (tileX, tileY, zoomLevel); - } - return img; - }, - - getPartialImageFromPoster : function (tileX, tileY, zoomLevel) { - if (this.fullImage && this.fullImage.complete) { - var posterScale = this.fullImage.width / this.parameters.width; - var tileSizeAtZoom = posterScale * this.parameters.tileSize / Math.pow (2, zoomLevel); - - x0 = Math.floor (tileSizeAtZoom * tileX); - y0 = Math.floor (tileSizeAtZoom * tileY); - w = Math.floor (tileSizeAtZoom); - h = Math.floor (tileSizeAtZoom); - - return this.createPartialImage (this.fullImage, this.fullImage.width, x0, y0, w, h); - } else { - return null; - } - }, - - createPartialImage : function (sourceImage, expectedSourceImageSize, x0, y0, w, h) { - var canvas = document.createElement ("canvas"); - if (!canvas["width"]) { - return null; - } - canvas.width = this.partialImageSize; - canvas.height = this.partialImageSize; - var ctx = canvas.getContext('2d'); - - var scale = sourceImage.width / expectedSourceImageSize; - - var sx = Math.floor (x0 * scale); - var sy = Math.floor (y0 * scale); - var dw = this.partialImageSize; - var dh = this.partialImageSize; - - w *= scale; - if (sx + w >= sourceImage.width) { - var w0 = w; - w = sourceImage.width - sx; - dw *= w / w0; - } - - h *= scale; - if (sy + h >= sourceImage.height) { - var h0 = h; - h = sourceImage.height - sy; - dh *= h / h0; - } - - try { - ctx.drawImage (sourceImage, sx, sy, w, h, -0.1, -0.1, dw + 0.2, dh + 0.2); - } catch (e) { - // DOM INDEX error on iPad. - return null; - } - - return canvas; - }, - - getPartialImageFromDownsampled : function (tileX, tileY, zoomLevel, x0, y0, w, h) { - // Give up if the poster image has higher resolution. - if (zoomLevel < this.POSTER_ZOOM_LEVEL || zoomLevel < this.parameters.minZoom) { - return null; - } - - var key = this.getImageKey (tileX, tileY, zoomLevel); - var sourceImage = this.cachedImages[key]; - - if (sourceImage == null) { - this.requestImage (tileX, tileY, zoomLevel); - } - - if (sourceImage) { - return this.createPartialImage (sourceImage, this.parameters.tileSize, x0, y0, w, h); - } else { - w /= 2; - h /= 2; - x0 /= 2; - y0 /= 2; - if ((tileX % 2) == 1) { - x0 += this.parameters.tileSize / 2; - } - if ((tileY % 2) == 1) { - y0 += this.parameters.tileSize / 2; - } - tileX = Math.floor (tileX / 2); - tileY = Math.floor (tileY / 2); - --zoomLevel; - return this.getPartialImageFromDownsampled (tileX, tileY, zoomLevel, x0, y0, w, h); - } - }, - - getEmptyImage : function () { - var tile = document.createElement ("img"); - if (this.parameters.emptyImage) { - tile.src = this.parameters.emptyImage; - } else { - tile.src = "data:image/gif,GIF89a%01%00%01%00%80%00%00%00%00%00%FF%FF%FF!%F9%04%00%00%00%00%00%2C%00%00%00%00%01%00%01%00%00%02%02D%01%00%3B"; - } - return tile; - }, - - getImage : function (tileX, tileY, zoomLevel) { - if (tileX < 0 || tileY < 0 || tileX >= this.maxTileX || tileY >= this.maxTileY) { - return this.getEmptyImage (); - } - - var key = this.getImageKey (tileX, tileY, zoomLevel); - this.lruMap.access (key); - - if (this.cachedImages[key]) { - if (this.usedImages[key]) { - var tile = this.parameters.dataLoader.loadImage (this.getImageFilename (tileX, tileY, zoomLevel)); - tile.isPartial = false; - return tile; - } else { - this.usedImages[key] = true; - var img = this.cachedImages[key]; - return img; - } - } else { - this.requestImage (tileX, tileY, zoomLevel); - var img = this.getPartialImage (tileX, tileY, zoomLevel); - if (img != null) { - img.isPartial = true; - this.cachedImages[key] = img; - } else { - img = this.getEmptyImage (); - if (img != null) { - img.isPartial = true; - } - } - return img; - } - }, - - requestImage : function (tileX, tileY, zoomLevel) { - var key = this.getImageKey (tileX, tileY, zoomLevel); - if (!this.requestedImages[key]) { - this.imageRequests++; - var that = this; - this.requestedImages[key] = true; - this.parameters.dataLoader.loadImage (this.getImageFilename (tileX, tileY, zoomLevel), function (tile) { - delete that.requestedImages[key]; - that.imageRequests--; - tile.isPartial = false; - that.cachedImages[key] = tile; - that.fireOnLoad (); - }); - } - }, - - /** - * Fires the onload event, if it hasn't been fired for at least 50 ms - */ - fireOnLoad : function () { - var now = new Date(); - if (this.imageRequests == 0 || now.getTime () > (this.lastOnLoadFiredAt + 50)) { - this.purgeCache (); - this.lastOnLoadFiredAt = now.getTime (); - this.onLoaded (); - } - }, - - /** - * Removes the least-recently used objects from the cache, - * if the size of the cache exceeds the maximum cache size. - * A maximum of four objects will be removed per call. - * - * @private - */ - purgeCache : function () { - for (var i = 0; i < 4; ++i) { - if (this.lruMap.getSize () > this.maxCacheSize) { - var leastUsed = this.lruMap.leastUsed (); - this.lruMap.remove (leastUsed); - delete this.cachedImages[leastUsed]; - } - } - }, - - getImageKey : function (tileX, tileY, zoomLevel) { - return "I" + tileX + "_" + tileY + "_" + zoomLevel; - }, - - getImageFilename : function (tileX, tileY, zoomLevel) { - var f = this.parameters.fileSystem.getImageFilename (tileX, tileY, zoomLevel); - return f; - } -}; -/* - * Copyright 2010 - 2012 Leo Sutic - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -/** - * Creates a new image parameter object and populates it with default values for - * all values not explicitly given. - * - * @class ImageParameters parameter object. - * You need not set any fields that can be read from the image descriptor that - * MakeImagePyramid creates. See the {@link bigshot.Image} documentation for - * required parameters. - * - *

Usage: - * - * @example - * var bsi = new bigshot.Image ( - * new bigshot.ImageParameters ({ - * basePath : "/bigshot.php?file=myshot.bigshot", - * fileSystemType : "archive", - * container : document.getElementById ("bigshot_div") - * })); - * - * @param values named parameter map, see the fields below for parameter names and types. - * @see bigshot.Image - */ -bigshot.ImageParameters = function (values) { - /** - * Size of low resolution preview image along the longest image - * dimension. The preview is assumed to have the same aspect - * ratio as the full image (specified by width and height). - * - * @default Optional set by MakeImagePyramid and loaded from descriptor - * @type int - * @public - */ - this.posterSize = 0; - - /** - * Url for the image tile to show while the tile is loading and no - * low-resolution preview is available. - * - * @default null, which results in an all-black image - * @type String - * @public - */ - this.emptyImage = null; - - /** - * Suffix to append to the tile filenames. Typically ".jpg" or - * ".png". - * - * @default Optional set by MakeImagePyramid and loaded from descriptor - * @type String - */ - this.suffix = null; - - /** - * The width of the full image; in pixels. - * - * @default Optional set by MakeImagePyramid and loaded from descriptor - * @type int - */ - this.width = 0; - - /** - * The height of the full image; in pixels. - * - * @default Optional set by MakeImagePyramid and loaded from descriptor - * @type int - */ - this.height = 0; - - /** - * For {@link bigshot.Image} and {@link bigshot.SimpleImage}, the div - * to use as a container for the image. - * - * @type HTMLDivElement - */ - this.container = null; - - /** - * The minimum zoom value. Zoom values are specified as a magnification; where - * 2n is the magnification and n is the zoom value. So a zoom value of - * 2 means a 4x magnification of the full image. -3 means showing an image that - * is a eighth (1/8 or 1/23) of the full size. - * - * @type number - * @default Optional set by MakeImagePyramid and loaded from descriptor - */ - this.minZoom = 0.0; - - /** - * The maximum zoom value. Zoom values are specified as a magnification; where - * 2n is the magnification and n is the zoom value. So a zoom value of - * 2 means a 4x magnification of the full image. -3 means showing an image that - * is a eighth (1/8 or 1/23) of the full size. - * - * @type number - * @default 0.0 - */ - this.maxZoom = 0.0; - - /** - * Size of one tile in pixels. - * - * @type int - * @default Optional set by MakeImagePyramid and loaded from descriptor - */ - this.tileSize = 0; - - /** - * Tile overlap. Not implemented. - * - * @type int - * @default Optional set by MakeImagePyramid and loaded from descriptor - */ - this.overlap = 0; - - /** - * Flag indicating that the image should wrap horizontally. The image wraps on tile - * boundaries; so in order to get a seamless wrap at zoom level -n; the image width must - * be evenly divisible by tileSize * 2^n. Set the minZoom value appropriately. - * - * @type boolean - * @default false - */ - this.wrapX = false; - - /** - * Flag indicating that the image should wrap vertically. The image wraps on tile - * boundaries; so in order to get a seamless wrap at zoom level -n; the image height must - * be evenly divisible by tileSize * 2^n. Set the minZoom value appropriately. - * - * @type boolean - * @default false - */ - this.wrapY = false; - - /** - * Base path for the image. This is filesystem dependent; but for the two most common cases - * the following should be set - * - *

    - *
  • archive= The basePath is "<path>/bigshot.php?file=<path-to-bigshot-archive-relative-to-bigshot.php>"; - * for example; "/bigshot.php?file=images/bigshot-sample.bigshot". - *
  • folder= The basePath is "<path-to-image-folder>"; - * for example; "/images/bigshot-sample". - *
- * - * @type String - */ - this.basePath = null; - - /** - * The file system type. Used to create a filesystem instance unless - * the fileSystem field is set. Possible values are "archive", - * "folder" or "dzi". - * - * @type String - * @default "folder" - */ - this.fileSystemType = "folder"; - - /** - * A reference to a filesystem implementation. If set; it overrides the - * fileSystemType field. - * - * @default set depending on value of bigshot.ImageParameters.fileSystemType - * @type bigshot.FileSystem - */ - this.fileSystem = null; - - /** - * Object used to load data files. - * - * @default bigshot.DefaultDataLoader - * @type bigshot.DataLoader - */ - this.dataLoader = new bigshot.DefaultDataLoader (); - - /** - * Enable the touch-friendly ui. The touch-friendly UI splits the viewport into - * three click-sensitive regions: - *

- * - *

Clicking (or tapping with a finger) on the outer region causes the viewport to zoom out. - * Clicking anywhere within the middle, "pan", region centers the image on the spot clicked. - * Finally, clicking in the center hotspot will center the image on the spot clicked and zoom - * in half a zoom level. - * - *

As before, you can drag to pan anywhere. - * - *

If you have navigation tools for mouse users that hover over the image container, it - * is recommended that any click events on them are kept from bubbling, otherwise the click - * will propagate to the touch ui. One way is to use the - * {@link bigshot.Browser#stopMouseEventBubbling} method: - * - * @example - * var browser = new bigshot.Browser (); - * browser.stopMouseEventBubbling (document.getElementById ("myBigshotControlDiv")); - * - * @see bigshot.ImageBase#showTouchUI - * - * @type boolean - * @default true - * @deprecated Bigshot supports all common touch-gestures. - */ - this.touchUI = false; - - /** - * Lets you "fling" the image. - * - * @type boolean - * @default true - */ - this.fling = true; - - /** - * The maximum amount that a tile will be stretched until we try to show - * the next more detailed level. - * - * @type float - * @default 1.0 - */ - this.maxTextureMagnification = 1.0; - - if (values) { - for (var k in values) { - this[k] = values[k]; - } - } - - this.merge = function (values, overwrite) { - for (var k in values) { - if (overwrite || !this[k]) { - this[k] = values[k]; - } - } - } - return this; -}; -/* - * Copyright 2010 - 2012 Leo Sutic - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - - -/** - * Sets up base image functionality. - * - * @param {bigshot.ImageParameters} parameters the image parameters - * @class Base class for image viewers. - * @extends bigshot.EventDispatcher - */ -bigshot.ImageBase = function (parameters) { - // Base class init - bigshot.EventDispatcher.call (this); - - this.parameters = parameters; - this.flying = 0; - this.container = parameters.container; - this.x = parameters.width / 2.0; - this.y = parameters.height / 2.0; - this.zoom = 0.0; - this.width = parameters.width; - this.height = parameters.height; - this.minZoom = parameters.minZoom; - this.maxZoom = parameters.maxZoom; - this.tileSize = parameters.tileSize; - this.overlap = 0; - this.imageTileCache = null; - - this.dragStart = null; - this.dragged = false; - - this.layers = new Array (); - - this.fullScreenHandler = null; - this.currentGesture = null; - - var that = this; - this.onresizeHandler = function (e) { - that.onresize (); - } - - /** - * Helper function to consume events. - * @private - */ - var consumeEvent = function (event) { - if (event.preventDefault) { - event.preventDefault (); - } - return false; - }; - - /** - * Helper function to translate touch events to mouse-like events. - * @private - */ - var translateEvent = function (event) { - if (event.clientX) { - return event; - } else { - return { - clientX : event.changedTouches[0].clientX, - clientY : event.changedTouches[0].clientY, - changedTouches : event.changedTouches - }; - }; - }; - - this.setupLayers (); - - this.resize (); - - this.allListeners = { - "DOMMouseScroll" : function (e) { - that.mouseWheel (e); - return consumeEvent (e); - }, - "mousewheel" : function (e) { - that.mouseWheel (e); - return consumeEvent (e); - }, - "dblclick" : function (e) { - that.mouseDoubleClick (e); - return consumeEvent (e); - }, - "mousedown" : function (e) { - that.dragMouseDown (e); - return consumeEvent (e); - }, - "gesturestart" : function (e) { - that.gestureStart (e); - return consumeEvent (e); - }, - "gesturechange" : function (e) { - that.gestureChange (e); - return consumeEvent (e); - }, - "gestureend" : function (e) { - that.gestureEnd (e); - return consumeEvent (e); - }, - "touchstart" : function (e) { - that.dragMouseDown (translateEvent (e)); - return consumeEvent (e); - }, - "mouseup" : function (e) { - that.dragMouseUp (e); - return consumeEvent (e); - }, - "touchend" : function (e) { - that.dragMouseUp (translateEvent (e)); - return consumeEvent (e); - }, - "mousemove" : function (e) { - that.dragMouseMove (e); - return consumeEvent (e); - }, - "mouseout" : function (e) { - //that.dragMouseUp (e); - return consumeEvent (e); - }, - "touchmove" : function (e) { - that.dragMouseMove (translateEvent (e)); - return consumeEvent (e); - } - }; - - this.addEventListeners (); - this.browser.registerListener (window, 'resize', that.onresizeHandler, false); - this.zoomToFit (); -} - -bigshot.ImageBase.prototype = { - /** - * Browser helper and compatibility functions. - * - * @private - * @type bigshot.Browser - */ - browser : new bigshot.Browser (), - - /** - * Adds all event listeners to the container object. - * @private - */ - addEventListeners : function () { - for (var k in this.allListeners) { - this.browser.registerListener (this.container, k, this.allListeners[k], false); - } - }, - - /** - * Removes all event listeners from the container object. - * @private - */ - removeEventListeners : function () { - for (var k in this.allListeners) { - this.browser.unregisterListener (this.container, k, this.allListeners[k], false); - } - }, - - /** - * Sets up the initial layers of the image. Override in subclass. - */ - setupLayers : function () { - }, - - /** - * Returns the base 2 logarithm of the maximum texture stretching, allowing for device pixel scaling. - * @type number - * @private - */ - getTextureStretch : function () { - var ts = Math.log (this.parameters.maxTextureMagnification / this.browser.getDevicePixelScale ()) / Math.LN2; - return ts; - }, - - /** - * Constrains the x and y coordinates to allowed values - * @param {number} x the initial x coordinate - * @param {number} y the initial y coordinate - * @return {number} .x the constrained x coordinate - * @return {number} .y the constrained y coordinate - */ - clampXY : function (x, y) { - var viewportWidth = this.container.clientWidth; - var viewportHeight = this.container.clientHeight; - - var realZoomFactor = Math.pow (2, this.zoom); - /* - Constrain X and Y - */ - var viewportWidthInImagePixels = viewportWidth / realZoomFactor; - var viewportHeightInImagePixels = viewportHeight / realZoomFactor; - - var constrain = function (viewportSizeInImagePixels, imageSizeInImagePixels, p) { - var min = viewportSizeInImagePixels / 2; - min = Math.min (imageSizeInImagePixels / 2, min); - if (p < min) { - p = min; - } - - var max = imageSizeInImagePixels - viewportSizeInImagePixels / 2; - max = Math.max (imageSizeInImagePixels / 2, max); - if (p > max) { - p = max; - } - return p; - }; - - var o = {}; - if (x != null) { - o.x = constrain (viewportWidthInImagePixels, this.width, x); - } - - if (y != null) { - o.y = constrain (viewportHeightInImagePixels, this.height, y); - } - - return o; - }, - - /** - * Lays out all layers according to the current - * x, y and zoom values. - * - * @public - */ - layout : function () { - var viewportWidth = this.container.clientWidth; - var viewportHeight = this.container.clientHeight; - - var zoomWithStretch = Math.min (this.maxZoom, Math.max (this.zoom - this.getTextureStretch (), this.minZoom)); - - var zoomLevel = Math.min (0, Math.ceil (zoomWithStretch)); - var zoomFactor = Math.pow (2, zoomLevel); - - var clamped = this.clampXY (this.x, this.y); - - if (!this.parameters.wrapY) { - this.y = clamped.y; - } - - if (!this.parameters.wrapX) { - this.x = clamped.x; - } - - var tileWidthInRealPixels = this.tileSize / zoomFactor; - - var fractionalZoomFactor = Math.pow (2, this.zoom - zoomLevel); - var tileDisplayWidth = this.tileSize * fractionalZoomFactor; - - var widthInTiles = this.width / tileWidthInRealPixels; - var heightInTiles = this.height / tileWidthInRealPixels; - var centerInTilesX = this.x / tileWidthInRealPixels; - var centerInTilesY = this.y / tileWidthInRealPixels; - - var topLeftInTilesX = centerInTilesX - (viewportWidth / 2) / tileDisplayWidth; - var topLeftInTilesY = centerInTilesY - (viewportHeight / 2) / tileDisplayWidth; - - var topLeftTileX = Math.floor (topLeftInTilesX); - var topLeftTileY = Math.floor (topLeftInTilesY); - var topLeftTileXoffset = Math.round ((topLeftInTilesX - topLeftTileX) * tileDisplayWidth); - var topLeftTileYoffset = Math.round ((topLeftInTilesY - topLeftTileY) * tileDisplayWidth); - - for (var i = 0; i < this.layers.length; ++i) { - this.layers[i].layout ( - zoomWithStretch, - -topLeftTileXoffset - tileDisplayWidth, -topLeftTileYoffset - tileDisplayWidth, - topLeftTileX - 1, topLeftTileY - 1, - Math.ceil (tileDisplayWidth), Math.ceil (tileDisplayWidth), - 1.0); - } - }, - - /** - * Resizes the layers of this image. - * - * @public - */ - resize : function () { - var tilesW = Math.ceil (2 * this.container.clientWidth / this.tileSize) + 2; - var tilesH = Math.ceil (2 * this.container.clientHeight / this.tileSize) + 2; - for (var i = 0; i < this.layers.length; ++i) { - this.layers[i].resize (tilesW, tilesH); - } - }, - - /** - * Creates a HTML div container for a layer. This method - * is called by the layer's constructor to obtain a - * container. - * - * @public - * @type HTMLDivElement - */ - createLayerContainer : function () { - var layerContainer = document.createElement ("div"); - layerContainer.style.position = "absolute"; - layerContainer.style.overflow = "hidden"; - return layerContainer; - }, - - /** - * Returns the div element used as viewport. - * - * @public - * @type HTMLDivElement - */ - getContainer : function () { - return this.container; - }, - - /** - * Adds a new layer to the image. - * - * @public - * @see bigshot.HotspotLayer for usage example - * @param {bigshot.Layer} layer the layer to add. - */ - addLayer : function (layer) { - this.container.appendChild (layer.getContainer ()); - this.layers.push (layer); - }, - - /** - * Clamps the zoom value to be between minZoom and maxZoom. - * - * @param {number} zoom the zoom value - * @type number - */ - clampZoom : function (zoom) { - return Math.min (this.maxZoom, Math.max (zoom, this.minZoom)); - }, - - /** - * Sets the current zoom value. - * - * @private - * @param {number} zoom the zoom value. - * @param {boolean} [layout] trigger a viewport update after setting. Defaults to false. - */ - setZoom : function (zoom, updateViewport) { - this.zoom = this.clampZoom (zoom); - var zoomLevel = Math.ceil (this.zoom - this.getTextureStretch ()); - var zoomFactor = Math.pow (2, zoomLevel); - var maxTileX = Math.ceil (zoomFactor * this.width / this.tileSize); - var maxTileY = Math.ceil (zoomFactor * this.height / this.tileSize); - for (var i = 0; i < this.layers.length; ++i) { - this.layers[i].setMaxTiles (maxTileX, maxTileY); - } - if (updateViewport) { - this.layout (); - } - }, - - /** - * Sets the maximum zoom value. The maximum magnification (of the full-size image) - * is 2maxZoom. Set to 0.0 to avoid pixelation. - * - * @public - * @param {number} maxZoom the maximum zoom value - */ - setMaxZoom : function (maxZoom) { - this.maxZoom = maxZoom; - }, - - /** - * Gets the maximum zoom value. The maximum magnification (of the full-size image) - * is 2maxZoom. - * - * @public - * @type number - */ - getMaxZoom : function () { - return this.maxZoom; - }, - - /** - * Sets the minimum zoom value. The minimum magnification (of the full-size image) - * is 2minZoom, so a minZoom of -3 means that the smallest - * image shown will be one-eighth of the full-size image. - * - * @public - * @param {number} minZoom the minimum zoom value for this image - */ - setMinZoom : function (minZoom) { - this.minZoom = minZoom; - }, - - /** - * Gets the minimum zoom value. The minimum magnification (of the full-size image) - * is 2minZoom, so a minZoom of -3 means that the smallest - * image shown will be one-eighth of the full-size image. - * - * @public - * @type number - */ - getMinZoom : function () { - return this.minZoom; - }, - - /** - * Adjusts a coordinate so that the center of zoom - * remains constant during zooming operations. The - * method is intended to be called twice, once for x - * and once for y. The current and - * centerOfZoom values will be the current - * and the center for the x and y, respectively. - * - * @example - * this.x = this.adjustCoordinateForZoom (this.x, zoomCenterX, oldZoom, newZoom); - * this.y = this.adjustCoordinateForZoom (this.y, zoomCenterY, oldZoom, newZoom); - * - * @param {number} current the current value of the coordinate - * @param {number} centerOfZoom the center of zoom along the coordinate axis - * @param {number} oldZoom the old zoom value - * @param {number} oldZoom the new zoom value - * @type number - * @returns the new value for the coordinate - */ - adjustCoordinateForZoom : function (current, centerOfZoom, oldZoom, newZoom) { - var zoomRatio = Math.pow (2, oldZoom) / Math.pow (2, newZoom); - return centerOfZoom + (current - centerOfZoom) * zoomRatio; - }, - - /** - * Begins a potential drag event. - * - * @private - */ - gestureStart : function (event) { - this.currentGesture = { - startZoom : this.zoom, - scale : event.scale - }; - }, - - /** - * Ends a gesture. - * - * @param {Event} event the gestureend event - * @private - */ - gestureEnd : function (event) { - this.currentGesture = null; - if (this.dragStart) { - this.dragStart.hadGesture = true; - } - }, - - /** - * Adjusts the zoom level based on the scale property of the - * gesture. - * - * @private - */ - gestureChange : function (event) { - if (this.currentGesture) { - if (this.dragStart) { - this.dragStart.hadGesture = true; - } - - var newZoom = this.clampZoom (this.currentGesture.startZoom + Math.log (event.scale) / Math.log (2)); - var oldZoom = this.getZoom (); - if (this.currentGesture.clientX !== undefined && this.currentGesture.clientY !== undefined) { - var centerOfZoom = this.clientToImage (this.currentGesture.clientX, this.currentGesture.clientY); - - var nx = this.adjustCoordinateForZoom (this.x, centerOfZoom.x, oldZoom, newZoom); - var ny = this.adjustCoordinateForZoom (this.y, centerOfZoom.y, oldZoom, newZoom); - - this.moveTo (nx, ny, newZoom); - } else { - this.setZoom (newZoom); - this.layout (); - } - } - }, - - /** - * Begins a potential drag event. - * - * @private - */ - dragMouseDown : function (event) { - this.dragStart = { - x : event.clientX, - y : event.clientY - }; - this.dragLast = { - clientX : event.clientX, - clientY : event.clientY, - dx : 0, - dy : 0, - dt : 1000000, - time : new Date ().getTime () - }; - this.dragged = false; - }, - - /** - * Handles a mouse drag event by panning the image. - * Also sets the dragged flag to indicate that the - * following click event should be ignored. - * @private - */ - dragMouseMove : function (event) { - if (this.currentGesture != null && event.changedTouches != null && event.changedTouches.length > 0) { - var cx = 0; - var cy = 0; - for (var i = 0; i < event.changedTouches.length; ++i) { - cx += event.changedTouches[i].clientX; - cy += event.changedTouches[i].clientY; - } - this.currentGesture.clientX = cx / event.changedTouches.length; - this.currentGesture.clientY = cy / event.changedTouches.length; - } - - if (this.currentGesture == null && this.dragStart != null) { - var delta = { - x : event.clientX - this.dragStart.x, - y : event.clientY - this.dragStart.y - }; - if (delta.x != 0 || delta.y != 0) { - this.dragged = true; - } - var zoomFactor = Math.pow (2, this.zoom); - var realX = delta.x / zoomFactor; - var realY = delta.y / zoomFactor; - - this.dragStart = { - x : event.clientX, - y : event.clientY - }; - - var dt = new Date ().getTime () - this.dragLast.time; - if (dt > 20) { - this.dragLast = { - dx : this.dragLast.clientX - event.clientX, - dy : this.dragLast.clientY - event.clientY, - dt : dt, - clientX : event.clientX, - clientY : event.clientY, - time : new Date ().getTime () - }; - } - - this.moveTo (this.x - realX, this.y - realY); - } - }, - - /** - * Ends a drag event by freeing the associated structures. - * @private - */ - dragMouseUp : function (event) { - if (this.currentGesture == null && !this.dragStart.hadGesture && this.dragStart != null) { - this.dragStart = null; - if (!this.dragged) { - this.mouseClick (event); - } else { - var scale = Math.pow (2, this.zoom); - var dx = this.dragLast.dx / scale; - var dy = this.dragLast.dy / scale; - var ds = Math.sqrt (dx * dx + dy * dy); - var dt = this.dragLast.dt; - var dtb = new Date ().getTime () - this.dragLast.time; - this.dragLast = null; - - var v = dt > 0 ? (ds / dt) : 0; - if (v > 0.05 && dtb < 250 && dt > 20 && this.parameters.fling) { - var t0 = new Date ().getTime (); - - dx /= dt; - dy /= dt; - - this.flyTo (this.x + dx * 250, this.y + dy * 250, this.zoom); - } - } - } - }, - - /** - * Mouse double-click handler. Pans to the clicked point and - * zooms in half a zoom level (approx 40%). - * @private - */ - mouseDoubleClick : function (event) { - var eventData = this.createImageEventData ({ - type : "dblclick", - clientX : event.clientX, - clientY : event.clientY - }); - this.fireEvent ("dblclick", eventData); - if (!eventData.defaultPrevented) { - this.flyTo (eventData.imageX, eventData.imageY, this.zoom + 0.5); - } - }, - - /** - * Returns the current zoom level. - * - * @public - * @type number - */ - getZoom : function () { - return this.zoom; - }, - - /** - * Stops any current flyTo operation and sets the current position. - * - * @param [x] the new x-coordinate - * @param [y] the new y-coordinate - * @param [zoom] the new zoom level - * @param [updateViewport=true] updates the viewport - * @public - */ - moveTo : function (x, y, zoom, updateViewport) { - this.stopFlying (); - - if (x != null || y != null) { - this.setPosition (x, y, false); - } - if (zoom != null) { - this.setZoom (zoom, false); - } - if (updateViewport == undefined || updateViewport == true) { - this.layout (); - } - }, - - /** - * Sets the current position. - * - * @param [x] the new x-coordinate - * @param [y] the new y-coordinate - * @param [updateViewport=true] if the viewport should be updated - * @private - */ - setPosition : function (x, y, updateViewport) { - var clamped = this.clampXY (x, y); - - if (x != null) { - if (this.parameters.wrapX) { - if (x < 0 || x >= this.width) { - x = (x + this.width) % this.width; - } - } else { - x = clamped.x; - } - this.x = Math.max (0, Math.min (this.width, x)); - } - - if (y != null) { - if (this.parameters.wrapY) { - if (y < 0 || y >= this.height) { - y = (y + this.height) % this.height; - } - } else { - y = clamped.y; - } - this.y = Math.max (0, Math.min (this.height, y)); - } - - if (updateViewport != false) { - this.layout (); - } - }, - - /** - * Helper function for calculating zoom levels. - * - * @public - * @returns the zoom level at which the given number of full-image pixels - * occupy the given number of screen pixels. - * @param {number} imageDimension the image dimension in full-image pixels - * @param {number} containerDimension the container dimension in screen pixels - * @type number - */ - fitZoom : function (imageDimension, containerDimension) { - var scale = containerDimension / imageDimension; - return Math.log (scale) / Math.LN2; - }, - - /** - * Returns the maximum zoom level at which the full image - * is visible in the viewport. - * @public - * @type number - */ - getZoomToFitValue : function () { - return Math.min ( - this.fitZoom (this.parameters.width, this.container.clientWidth), - this.fitZoom (this.parameters.height, this.container.clientHeight)); - }, - - /** - * Returns the zoom level at which the image fills the whole - * viewport. - * @public - * @type number - */ - getZoomToFillValue : function () { - return Math.max ( - this.fitZoom (this.parameters.width, this.container.clientWidth), - this.fitZoom (this.parameters.height, this.container.clientHeight)); - }, - - /** - * Adjust the zoom level to fit the image in the viewport. - * @public - */ - zoomToFit : function () { - this.moveTo (null, null, this.getZoomToFitValue ()); - }, - - /** - * Adjust the zoom level to fit the image in the viewport. - * @public - */ - zoomToFill : function () { - this.moveTo (null, null, this.getZoomToFillValue ()); - }, - - /** - * Adjust the zoom level to fit the - * image height in the viewport. - * @public - */ - zoomToFitHeight : function () { - this.moveTo (null, null, this.fitZoom (this.parameters.height, this.container.clientHeight)); - }, - - /** - * Adjust the zoom level to fit the - * image width in the viewport. - * @public - */ - zoomToFitWidth : function () { - this.moveTo (null, null, this.fitZoom (this.parameters.width, this.container.clientWidth)); - }, - - /** - * Smoothly adjust the zoom level to fit the - * image height in the viewport. - * @public - */ - flyZoomToFitHeight : function () { - this.flyTo (null, this.parameters.height / 2, this.fitZoom (this.parameters.height, this.container.clientHeight)); - }, - - /** - * Smoothly adjust the zoom level to fit the - * image width in the viewport. - * @public - */ - flyZoomToFitWidth : function () { - this.flyTo (this.parameters.width / 2, null, this.fitZoom (this.parameters.width, this.container.clientWidth)); - }, - - /** - * Smoothly adjust the zoom level to fit the - * full image in the viewport. - * @public - */ - flyZoomToFit : function () { - this.flyTo (this.parameters.width / 2, this.parameters.height / 2, this.getZoomToFitValue ()); - }, - - /** - * Converts client-relative screen coordinates to image coordinates. - * - * @param {number} clientX the client x-coordinate - * @param {number} clientY the client y-coordinate - * - * @returns {number} .x the image x-coordinate - * @returns {number} .y the image y-coordinate - * @type Object - */ - clientToImage : function (clientX, clientY) { - var zoomFactor = Math.pow (2, this.zoom); - return { - x : (clientX - this.container.clientWidth / 2) / zoomFactor + this.x, - y : (clientY - this.container.clientHeight / 2) / zoomFactor + this.y - }; - }, - - /** - * Handles mouse wheel actions. - * @private - */ - mouseWheelHandler : function (delta, event) { - var zoomDelta = false; - if (delta > 0) { - zoomDelta = 0.5; - } else if (delta < 0) { - zoomDelta = -0.5; - } - - if (zoomDelta) { - var centerOfZoom = this.clientToImage (event.clientX, event.clientY); - var newZoom = Math.min (this.maxZoom, Math.max (this.getZoom () + zoomDelta, this.minZoom)); - - var nx = this.adjustCoordinateForZoom (this.x, centerOfZoom.x, this.getZoom (), newZoom); - var ny = this.adjustCoordinateForZoom (this.y, centerOfZoom.y, this.getZoom (), newZoom); - - this.flyTo (nx, ny, newZoom, true); - } - }, - - /** - * Translates mouse wheel events. - * @private - */ - mouseWheel : function (event){ - var delta = 0; - if (!event) /* For IE. */ - event = window.event; - if (event.wheelDelta) { /* IE/Opera. */ - delta = event.wheelDelta / 120; - /* - * In Opera 9, delta differs in sign as compared to IE. - */ - if (window.opera) - delta = -delta; - } else if (event.detail) { /* Mozilla case. */ - /* - * In Mozilla, sign of delta is different than in IE. - * Also, delta is multiple of 3. - */ - delta = -event.detail; - } - - /* - * If delta is nonzero, handle it. - * Basically, delta is now positive if wheel was scrolled up, - * and negative, if wheel was scrolled down. - */ - if (delta) { - this.mouseWheelHandler (delta, event); - } - - /* - * Prevent default actions caused by mouse wheel. - * That might be ugly, but we handle scrolls somehow - * anyway, so don't bother here.. - */ - if (event.preventDefault) { - event.preventDefault (); - } - event.returnValue = false; - }, - - /** - * Triggers a right-sizing of all layers. - * Called on window resize via the {@link bigshot.ImageBase#onresizeHandler} stub. - * @public - */ - onresize : function () { - this.resize (); - this.layout (); - }, - - /** - * Returns the current x-coordinate, which is the full-image x coordinate - * in the center of the viewport. - * @public - * @type number - */ - getX : function () { - return this.x; - }, - - /** - * Returns the current y-coordinate, which is the full-image x coordinate - * in the center of the viewport. - * @public - * @type number - */ - getY : function () { - return this.y; - }, - - /** - * Interrupts the current {@link #flyTo}, if one is active. - * @public - */ - stopFlying : function () { - this.flying++; - }, - - /** - * Smoothly flies to the specified position. - * - * @public - * @param {number} [x=current x] the new x-coordinate - * @param {number} [y=current y] the new y-coordinate - * @param {number} [zoom=current zoom] the new zoom level - * @param {boolean} [uniformApproach=false] if true, uses the same interpolation curve for x, y and zoom. - */ - flyTo : function (x, y, zoom, uniformApproach) { - var that = this; - - x = x != null ? x : this.x; - y = y != null ? y : this.y; - zoom = zoom != null ? zoom : this.zoom; - uniformApproach = uniformApproach != null ? uniformApproach : false; - - var startX = this.x; - var startY = this.y; - var startZoom = this.zoom; - - var clamped = this.clampXY (x, y); - var targetX = this.parameters.wrapX ? x : clamped.x; - var targetY = this.parameters.wrapY ? y : clamped.y; - var targetZoom = Math.min (this.maxZoom, Math.max (zoom, this.minZoom)); - - this.flying++; - var flyingAtStart = this.flying; - - var t0 = new Date ().getTime (); - - var approach = function (start, target, dt, step, linear) { - var delta = (target - start); - - var diff = - delta * Math.pow (2, -dt * step); - - var lin = dt * linear; - if (delta < 0) { - diff = Math.max (0, diff - lin); - } else { - diff = Math.min (0, diff + lin); - } - - return target + diff; - }; - - - var iter = function () { - if (that.flying == flyingAtStart) { - var dt = (new Date ().getTime () - t0) / 1000; - - var nx = approach (startX, targetX, dt, uniformApproach ? 10 : 4, uniformApproach ? 0.2 : 1.0); - var ny = approach (startY, targetY, dt, uniformApproach ? 10 : 4, uniformApproach ? 0.2 : 1.0); - var nz = approach (startZoom, targetZoom, dt, 10, 0.2); - var done = true; - - var zoomFactor = Math.min (Math.pow (2, that.getZoom ()), 1); - - if (Math.abs (nx - targetX) < (0.5 * zoomFactor)) { - nx = targetX; - } else { - done = false; - } - if (Math.abs (ny - targetY) < (0.5 * zoomFactor)) { - ny = targetY; - } else { - done = false; - } - if (Math.abs (nz - targetZoom) < 0.02) { - nz = targetZoom; - } else { - done = false; - } - that.setPosition (nx, ny, false); - that.setZoom (nz, false); - that.layout (); - if (!done) { - that.browser.requestAnimationFrame (iter, that.container); - } - }; - } - this.browser.requestAnimationFrame (iter, this.container); - }, - - /** - * Returns the maximum zoom level at which a rectangle with the given dimensions - * fit into the viewport. - * - * @public - * @param {number} w the width of the rectangle, given in full-image pixels - * @param {number} h the height of the rectangle, given in full-image pixels - * @type number - * @returns the zoom level that will precisely fit the given rectangle - */ - rectVisibleAtZoomLevel : function (w, h) { - return Math.min ( - this.fitZoom (w, this.container.clientWidth), - this.fitZoom (h, this.container.clientHeight)); - }, - - /** - * Returns the base size in screen pixels of the two zoom touch areas. - * The zoom out border will be getTouchAreaBaseSize() pixels wide, - * and the center zoom in hotspot will be 2*getTouchAreaBaseSize() pixels wide - * and tall. - * @deprecated - * @type number - * @public - */ - getTouchAreaBaseSize : function () { - var averageSize = ((this.container.clientWidth + this.container.clientHeight) / 2) * 0.2; - return Math.min (averageSize, Math.min (this.container.clientWidth, this.container.clientHeight) / 6); - }, - - /** - * Creates a new {@link bigshot.ImageEvent} using the supplied data object, - * transforming the client x- and y-coordinates to local and image coordinates. - * The returned event object will have the {@link bigshot.ImageEvent#localX}, - * {@link bigshot.ImageEvent#localY}, {@link bigshot.ImageEvent#imageX}, - * {@link bigshot.ImageEvent#imageY}, {@link bigshot.Event#target} and - * {@link bigshot.Event#currentTarget} fields set. - * - * @param {Object} data data object with initial values for the event object - * @param {number} data.clientX the clientX of the event - * @param {number} data.clientY the clientY of the event - * @returns the new event object - * @type bigshot.ImageEvent - */ - createImageEventData : function (data) { - var elementPos = this.browser.getElementPosition (this.container); - data.localX = data.clientX - elementPos.x; - data.localY = data.clientY - elementPos.y; - - var scale = Math.pow (2, this.zoom); - - data.imageX = (data.localX - this.container.clientWidth / 2) / scale + this.x; - data.imageY = (data.localY - this.container.clientHeight / 2) / scale + this.y; - - data.target = this; - data.currentTarget = this; - - return new bigshot.ImageEvent (data); - }, - - /** - * Handles mouse click events. If the touch UI is active, - * we'll pan and/or zoom, as appropriate. If not, we just ignore - * the event. - * @private - */ - mouseClick : function (event) { - var eventData = this.createImageEventData ({ - type : "click", - clientX : event.clientX, - clientY : event.clientY - }); - this.fireEvent ("click", eventData); - /* - if (!eventData.defaultPrevented) { - if (!this.parameters.touchUI) { - return; - } - if (this.dragged) { - return; - } - - var zoomOutBorderSize = this.getTouchAreaBaseSize (); - var zoomInHotspotSize = this.getTouchAreaBaseSize (); - - if (Math.abs (clickPos.x) > (this.container.clientWidth / 2 - zoomOutBorderSize) || Math.abs (clickPos.y) > (this.container.clientHeight / 2 - zoomOutBorderSize)) { - this.flyTo (this.x, this.y, this.zoom - 0.5); - } else { - var newZoom = this.zoom; - if (Math.abs (clickPos.x) < zoomInHotspotSize && Math.abs (clickPos.y) < zoomInHotspotSize) { - newZoom += 0.5; - } - var scale = Math.pow (2, this.zoom); - clickPos.x /= scale; - clickPos.y /= scale; - this.flyTo (this.x + clickPos.x, this.y + clickPos.y, newZoom); - } - } - */ - }, - - /** - * Briefly shows the touch ui zones. See the {@link bigshot.ImageParameters#touchUI} - * documentation for an explanation of the touch ui. - * - * @public - * @deprecated All common touch gestures are supported by default. - * @see bigshot.ImageParameters#touchUI - * @param {int} [delay] milliseconds before fading out - * @param {int} [fadeOut] milliseconds to fade out the zone overlays in - */ - showTouchUI : function (delay, fadeOut) { - if (!delay) { - delay = 2500; - } - if (!fadeOut) { - fadeOut = 1000; - } - - var zoomOutBorderSize = this.getTouchAreaBaseSize (); - var zoomInHotspotSize = this.getTouchAreaBaseSize (); - var centerX = this.container.clientWidth / 2; - var centerY = this.container.clientHeight / 2; - - var frameDiv = document.createElement ("div"); - frameDiv.style.position = "absolute"; - frameDiv.style.zIndex = "9999"; - frameDiv.style.opacity = 0.9; - frameDiv.style.width = this.container.clientWidth + "px"; - frameDiv.style.height = this.container.clientHeight + "px"; - - var centerSpotAnchor = document.createElement ("div"); - centerSpotAnchor.style.position = "absolute"; - - var centerSpot = document.createElement ("div"); - centerSpot.style.position = "relative"; - centerSpot.style.background = "black"; - centerSpot.style.textAlign = "center"; - centerSpot.style.top = (centerY - zoomInHotspotSize) + "px"; - centerSpot.style.left = (centerX - zoomInHotspotSize) + "px"; - centerSpot.style.width = (2 * zoomInHotspotSize) + "px"; - centerSpot.style.height = (2 * zoomInHotspotSize) + "px"; - - frameDiv.appendChild (centerSpotAnchor); - centerSpotAnchor.appendChild (centerSpot); - centerSpot.innerHTML = "ZOOM IN"; - - var zoomOutBorderAnchor = document.createElement ("div"); - zoomOutBorderAnchor.style.position = "absolute"; - - var zoomOutBorder = document.createElement ("div"); - zoomOutBorder.style.position = "relative"; - zoomOutBorder.style.border = zoomOutBorderSize + "px solid black"; - zoomOutBorder.style.top = "0px"; - zoomOutBorder.style.left = "0px"; - zoomOutBorder.style.textAlign = "center"; - zoomOutBorder.style.width = this.container.clientWidth + "px"; - zoomOutBorder.style.height = this.container.clientHeight + "px"; - zoomOutBorder.style.MozBoxSizing = - zoomOutBorder.style.boxSizing = - zoomOutBorder.style.WebkitBoxSizing = - "border-box"; - - zoomOutBorder.innerHTML = "ZOOM OUT"; - - zoomOutBorderAnchor.appendChild (zoomOutBorder); - frameDiv.appendChild (zoomOutBorderAnchor); - - this.container.appendChild (frameDiv); - - var that = this; - var opacity = 0.9; - var fadeOutSteps = fadeOut / 50; - if (fadeOutSteps < 1) { - fadeOutSteps = 1; - } - var iter = function () { - opacity = opacity - (0.9 / fadeOutSteps); - if (opacity < 0.0) { - that.container.removeChild (frameDiv); - } else { - frameDiv.style.opacity = opacity; - setTimeout (iter, 50); - } - }; - setTimeout (iter, delay); - }, - - /** - * Forces exit from full screen mode, if we're there. - * @public - */ - exitFullScreen : function () { - if (this.fullScreenHandler) { - this.removeEventListeners (); - this.fullScreenHandler.close (); - this.addEventListeners (); - this.fullScreenHandler = null; - return; - } - }, - - /** - * Maximizes the image to cover the browser viewport. - * The container div is removed from its parent node upon entering - * full screen mode. When leaving full screen mode, the container - * is appended to its old parent node. To avoid rearranging the - * nodes, wrap the container in an extra div. - * - *

For unknown reasons (probably security), browsers will - * not let you open a window that covers the entire screen. - * Even when specifying "fullscreen=yes", all you get is a window - * that has a title bar and only covers the desktop (not any task - * bars or the like). For now, this is the best that I can do, - * but should the situation change I'll update this to be - * full-screen-ier. - * @public - */ - fullScreen : function (onClose) { - if (this.fullScreenHandler) { - return; - } - - var message = document.createElement ("div"); - message.style.position = "absolute"; - message.style.fontSize = "16pt"; - message.style.top = "128px"; - message.style.width = "100%"; - message.style.color = "white"; - message.style.padding = "16px"; - message.style.zIndex = "9999"; - message.style.textAlign = "center"; - message.style.opacity = "0.75"; - message.innerHTML = "Press Esc to exit full screen mode."; - - var that = this; - - this.fullScreenHandler = new bigshot.FullScreen (this.container); - this.fullScreenHandler.restoreSize = true; - - this.fullScreenHandler.addOnResize (function () { - if (that.fullScreenHandler && that.fullScreenHandler.isFullScreen) { - that.container.style.width = window.innerWidth + "px"; - that.container.style.height = window.innerHeight + "px"; - } - that.onresize (); - }); - - this.fullScreenHandler.addOnClose (function () { - if (message.parentNode) { - try { - div.removeChild (message); - } catch (x) { - } - } - that.fullScreenHandler = null; - }); - - if (onClose) { - this.fullScreenHandler.addOnClose (function () { - onClose (); - }); - } - - this.removeEventListeners (); - this.fullScreenHandler.open (); - this.addEventListeners (); - if (this.fullScreenHandler.getRootElement ()) { - this.fullScreenHandler.getRootElement ().appendChild (message); - - setTimeout (function () { - var opacity = 0.75; - var iter = function () { - opacity -= 0.02; - if (message.parentNode) { - if (opacity <= 0) { - try { - div.removeChild (message); - } catch (x) {} - } else { - message.style.opacity = opacity; - setTimeout (iter, 20); - } - } - }; - setTimeout (iter, 20); - }, 3500); - } - - return function () { - that.fullScreenHandler.close (); - }; - }, - - /** - * Unregisters event handlers and other page-level hooks. The client need not call this - * method unless bigshot images are created and removed from the page - * dynamically. In that case, this method must be called when the client wishes to - * free the resources allocated by the image. Otherwise the browser will garbage-collect - * all resources automatically. - * @public - */ - dispose : function () { - this.browser.unregisterListener (window, "resize", this.onresizeHandler, false); - this.removeEventListeners (); - } -}; - -/** - * Fired when the user double-clicks on the image - * - * @name bigshot.ImageBase#dblclick - * @event - * @param {bigshot.ImageEvent} event the event object - */ - -/** - * Fired when the user clicks on (but does not drag) the image - * - * @name bigshot.ImageBase#click - * @event - * @param {bigshot.ImageEvent} event the event object - */ - -bigshot.Object.extend (bigshot.ImageBase, bigshot.EventDispatcher); -/* - * Copyright 2010 - 2012 Leo Sutic - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - - -/** - * Creates a new tiled image viewer. (Note: See {@link bigshot.ImageBase#dispose} for important information.) - * - * @example - * var bsi = new bigshot.Image ( - * new bigshot.ImageParameters ({ - * basePath : "/bigshot.php?file=myshot.bigshot", - * fileSystemType : "archive", - * container : document.getElementById ("bigshot_div") - * })); - * - * @param {bigshot.ImageParameters} parameters the image parameters. Required fields are: basePath and container. - * If you intend to use the archive filesystem, you need to set the fileSystemType to "archive" - * as well. - * @see bigshot.ImageBase#dispose - * @class A tiled, zoomable image viewer. - * - *

Creating a Wrapping Image

- * - *

If you have set the wrapX or wrapY parameters in the {@link bigshot.ImageParameters}, the - * image must be an integer multiple of the tile size at the desired minimum zoom level, otherwise - * there will be a gap at the wrap point: - * - *

The way to figure out the proper input size is this: - * - *

    - *
  1. Decide on a tile size and call this tileSize.

  2. - *
  3. Decide on a minimum integer zoom level, and call this minZoom.

  4. - *
  5. Compute tileSize * 2-minZoom, call this S.

  6. - *
  7. The source image size along the wrapped axis must be evenly divisible by S.

  8. - *
- * - *

An example:

- * - *
    - *
  1. I have an image that is 23148x3242 pixels.

  2. - *
  3. I chose 256x256 pixel tiles: tileSize = 256.

  4. - *
  5. When displaying the image, I want the user to be able to zoom out so that the - * whole image is less than or equal to 600 pixels tall. Since the image is 3242 pixels - * tall originally, I will need a minZoom of -3. A minZoom of -2 would only let me - * zoom out to 1/4 (2-2), or an image that is 810 pixels tall. A minZoom of -3, however lets me - * zoom out to 1/8 (2-3), or an image that is 405 pixels tall. Thus: minZoom = -3

  6. - *
  7. Computing S gives: S = 256 * 23 = 256 * 8 = 2048

  8. - *
  9. I want it to wrap along the X axis. Therefore I may have to adjust the width, - * currently 23148 pixels.

  10. - *
  11. Rounding 23148 down to the nearest multiple of 2048 gives 22528. (23148 divided by 2048 is 11.3, and 11 times 2048 is 22528.)

  12. - *
  13. I will shrink my source image to be 22528 pixels wide before building the image pyramid, - * and I will set the minZoom parameter to -3 in the {@link bigshot.ImageParameters} when creating - * the image. (I will also set wrapX to true.)

  14. - *
- * - * @augments bigshot.ImageBase - */ -bigshot.Image = function (parameters) { - bigshot.setupFileSystem (parameters); - parameters.merge (parameters.fileSystem.getDescriptor (), false); - - bigshot.ImageBase.call (this, parameters); -} - -bigshot.Image.prototype = { - setupLayers : function () { - var that = this; - this.thisTileCache = new bigshot.ImageTileCache (function () { - that.layout (); - }, null, this.parameters); - - this.addLayer ( - new bigshot.TileLayer (this, this.parameters, 0, 0, this.thisTileCache) - ); - } -}; - -bigshot.Object.extend (bigshot.Image, bigshot.ImageBase); - -/* - * Copyright 2010 - 2012 Leo Sutic - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -/** - * Creates a new HTML element layer. The layer must be added to the image using - * {@link bigshot.ImageBase#addLayer}. - * - * @class A layer consisting of a single HTML element that is moved and scaled to cover - * the layer. - * @example - * var image = new bigshot.Image (...); - * image.addLayer ( - * new bigshot.HTMLElementLayer (this, this.imgElement, this.parameters.width, this.parameters.height) - * ); - * @param {bigshot.ImageBase} image the image this hotspot layer will be part of - * @param {HTMLElement} element the element to present in this layer - * @param {int} width the width, in image pixels (display size at zoom level 0), of the HTML element - * @param {int} height the height, in image pixels (display size at zoom level 0), of the HTML element - * @augments bigshot.Layer - */ -bigshot.HTMLElementLayer = function (image, element, width, height) { - this.hotspots = new Array (); - this.browser = new bigshot.Browser (); - this.image = image; - this.container = image.createLayerContainer (); - this.parentContainer = image.getContainer (); - this.element = element; - this.parentContainer.appendChild (element); - this.w = width; - this.h = height; - this.resize (0, 0); -} - -bigshot.HTMLElementLayer.prototype = { - - getContainer : function () { - return this.container; - }, - - resize : function (w, h) { - this.container.style.width = this.parentContainer.clientWidth + "px"; - this.container.style.height = this.parentContainer.clientHeight + "px"; - }, - - layout : function (zoom, x0, y0, tx0, ty0, size, stride, opacity) { - var zoomFactor = Math.pow (2, this.image.getZoom ()); - x0 -= stride * tx0; - y0 -= stride * ty0; - - this.element.style.top = y0 + "px"; - this.element.style.left = x0 + "px"; - this.element.style.width = (this.w * zoomFactor) + "px"; - this.element.style.height = (this.h * zoomFactor) + "px"; - }, - - setMaxTiles : function (mtx, mty) { - } -} - -bigshot.Object.validate ("bigshot.HTMLElementLayer", bigshot.Layer); -/* - * Copyright 2010 - 2012 Leo Sutic - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -/** - * Creates a new HTML element layer. The layer must be added to the image using - * {@link bigshot.ImageBase#addLayer}. - * - * @class A layer consisting of a single HTML element that is moved and scaled to cover - * the layer. - * @example - * var image = new bigshot.Image (...); - * image.addLayer ( - * new bigshot.HTMLElementLayer (this, this.imgElement, this.parameters.width, this.parameters.height) - * ); - * @param {bigshot.ImageBase} image the image this hotspot layer will be part of - * @param {HTMLElement} element the element to present in this layer - * @param {int} width the width, in image pixels (display size at zoom level 0), of the HTML element - * @param {int} height the height, in image pixels (display size at zoom level 0), of the HTML element - * @augments bigshot.Layer - */ -bigshot.HTMLDivElementLayer = function (image, element, width, height, wrapX, wrapY) { - this.wrapX = wrapX; - this.wrapY = wrapY; - this.hotspots = new Array (); - this.browser = new bigshot.Browser (); - this.image = image; - this.container = image.createLayerContainer (); - this.parentContainer = image.getContainer (); - this.element = element; - this.parentContainer.appendChild (element); - this.w = width; - this.h = height; - this.resize (0, 0); -} - -bigshot.HTMLDivElementLayer.prototype = { - - getContainer : function () { - return this.container; - }, - - resize : function (w, h) { - this.container.style.width = this.parentContainer.clientWidth + "px"; - this.container.style.height = this.parentContainer.clientHeight + "px"; - }, - - layout : function (zoom, x0, y0, tx0, ty0, size, stride, opacity) { - var zoomFactor = Math.pow (2, this.image.getZoom ()); - x0 -= stride * tx0; - y0 -= stride * ty0; - - var imW = (this.w * zoomFactor); - var imH = (this.h * zoomFactor); - - this.element.style.backgroundSize = imW + "px " + imH + "px"; - - var bposX = "0px"; - var bposY = "0px"; - - if (this.wrapY) { - this.element.style.top = "0px"; - this.element.style.height = (this.parentContainer.clientHeight) + "px"; - bposY = y0 + "px"; - } else { - this.element.style.top = y0 + "px"; - this.element.style.height = imH + "px"; - } - - if (this.wrapX) { - this.element.style.left = "0px"; - this.element.style.width = (this.parentContainer.clientWidth) + "px"; - bposX = x0 + "px"; - } else { - this.element.style.left = x0 + "px"; - this.element.style.width = imW + "px"; - } - - this.element.style.backgroundPosition = bposX + " " + bposY; - }, - - setMaxTiles : function (mtx, mty) { - } -} - -bigshot.Object.validate ("bigshot.HTMLDivElementLayer", bigshot.Layer); -/* - * Copyright 2010 - 2012 Leo Sutic - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - - -/** - * Creates a new image viewer. (Note: See {@link bigshot.SimpleImage#dispose} for important information.) - * - * @example - * var bsi = new bigshot.SimpleImage ( - * new bigshot.ImageParameters ({ - * basePath : "myimage.jpg", - * width : 681, - * height : 1024, - * container : document.getElementById ("bigshot_div") - * })); - * - * @param {bigshot.ImageParameters} parameters the image parameters. Required fields are: container. - * If the imgElement parameter is not given, then basePath, width and height are also required. The - * following parameters are not supported and should be left as defaults: fileSystem, fileSystemType, - * maxTextureMagnification and tileSize. wrapX and wrapY may only be used if the imgElement is not - * set. - * - * @param {HTMLImageElement} [imgElement] an img element to use. The element should have style.position = "absolute". - * @see bigshot.ImageBase#dispose - * @class A zoomable image viewer. - * @augments bigshot.ImageBase - */ -bigshot.SimpleImage = function (parameters, imgElement) { - parameters.merge ({ - fileSystem : null, - fileSystemType : "simple", - maxTextureMagnification : 1.0, - tileSize : 1024 - }, true); - - if (imgElement) { - parameters.merge ({ - width : imgElement.width, - height : imgElement.height - }); - this.imgElement = imgElement; - } else { - if (parameters.width == 0 || parameters.height == 0) { - throw new Error ("No imgElement and missing width or height in ImageParameters"); - } - } - bigshot.setupFileSystem (parameters); - - bigshot.ImageBase.call (this, parameters); -} - -bigshot.SimpleImage.prototype = { - setupLayers : function () { - if (!this.imgElement) { - /* - this.imgElement = document.createElement ("img"); - this.imgElement.src = this.parameters.basePath; - this.imgElement.style.position = "absolute"; - */ - this.imgElement = document.createElement ("div"); - this.imgElement.style.backgroundImage = "url('" + this.parameters.basePath + "')"; - this.imgElement.style.position = "absolute"; - if (!this.parameters.wrapX && !this.parameters.wrapY) { - this.imgElement.style.backgroundRepeat = "no-repeat"; - } else if (this.parameters.wrapX && !this.parameters.wrapY) { - this.imgElement.style.backgroundRepeat = "repeat-x"; - } else if (!this.parameters.wrapX && this.parameters.wrapY) { - this.imgElement.style.backgroundRepeat = "repeat-y"; - } else if (this.parameters.wrapX && this.parameters.wrapY) { - this.imgElement.style.backgroundRepeat = "repeat"; - } - } - - this.addLayer ( - new bigshot.HTMLDivElementLayer (this, this.imgElement, this.parameters.width, this.parameters.height, this.parameters.wrapX, this.parameters.wrapY) - ); - } -}; - -bigshot.Object.extend (bigshot.SimpleImage, bigshot.ImageBase); - -/* - * Copyright 2010 - 2012 Leo Sutic - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -/** - * Abstract filesystem definition. - * - * @class Abstract filesystem definition. - */ -bigshot.FileSystem = function () { -} - -bigshot.FileSystem.prototype = { - /** - * Returns the URL filename for the given filesystem entry. - * - * @param {String} name the entry name - */ - getFilename : function (name) {}, - - /** - * Returns the entry filename for the given tile. - * - * @param {int} tileX the column of the tile - * @param {int} tileY the row of the tile - * @param {int} zoomLevel the zoom level - */ - getImageFilename : function (tileX, tileY, zoomLevel) {}, - - /** - * Sets an optional prefix that is prepended, along with a forward - * slash ("/"), to all names. - * - * @param {String} prefix the prefix - */ - setPrefix : function (prefix) {}, - - /** - * Returns an image descriptor object from the descriptor file. - * - * @return a descriptor object - */ - getDescriptor : function () {}, - - /** - * Returns the poster URL filename. For Bigshot images this is - * typically the URL corresponding to the entry "poster.jpg", - * but for other filesystems it can be different. - */ - getPosterFilename : function () {} -}; - -/** - * Sets up a filesystem instance in the given parameters object, if none exist. - * If the {@link bigshot.ImageParameters#fileSystem} member isn't set, the - * {@link bigshot.ImageParameters#fileSystemType} member is used to create a new - * {@link bigshot.FileSystem} instance and set it. - * - * @param {bigshot.ImageParameters or bigshot.VRPanoramaParameters or bigshot.ImageCarouselPanoramaParameters} parameters the parameters object to populate - */ -bigshot.setupFileSystem = function (parameters) { - if (!parameters.fileSystem) { - if (parameters.fileSystemType == "archive") { - parameters.fileSystem = new bigshot.ArchiveFileSystem (parameters); - } else if (parameters.fileSystemType == "dzi") { - parameters.fileSystem = new bigshot.DeepZoomImageFileSystem (parameters); - } else if (parameters.fileSystemType == "simple") { - parameters.fileSystem = new bigshot.SimpleFileSystem (parameters); - } else { - parameters.fileSystem = new bigshot.FolderFileSystem (parameters); - } - } -} -/* - * Copyright 2010 - 2012 Leo Sutic - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -/** - * Creates a new instance of a filesystem adapter for the SimpleImage class. - * - * @class Filesystem adapter for bigshot.SimpleImage. This class is not - * supposed to be used outside of the {@link bigshot.SimpleImage} class. - * @param {bigshot.ImageParameters} parameters the associated image parameters - * @augments bigshot.FileSystem - * @see bigshot.SimpleImage - */ -bigshot.SimpleFileSystem = function (parameters) { - this.parameters = parameters; -}; - - -bigshot.SimpleFileSystem.prototype = { - getDescriptor : function () { - return {}; - }, - - getPosterFilename : function () { - return null; - }, - - getFilename : function (name) { - return null; - }, - - getImageFilename : function (tileX, tileY, zoomLevel) { - return null; - }, - - getPrefix : function () { - return ""; - }, - - setPrefix : function (prefix) { - this.prefix = prefix; - } -} - -bigshot.Object.validate ("bigshot.SimpleFileSystem", bigshot.FileSystem); -/* - * Copyright 2010 - 2012 Leo Sutic - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -/** - * Creates a new instance of a folder-based filesystem adapter. - * - * @augments bigshot.FileSystem - * @class Folder-based filesystem. - * @param {bigshot.ImageParameters|bigshot.VRPanoramaParameters} parameters the associated image parameters - * @constructor - */ -bigshot.FolderFileSystem = function (parameters) { - this.prefix = null; - this.suffix = ""; - this.parameters = parameters; -} - - -bigshot.FolderFileSystem.prototype = { - getDescriptor : function () { - this.browser = new bigshot.Browser (); - var req = this.browser.createXMLHttpRequest (); - - req.open("GET", this.getFilename ("descriptor"), false); - req.send(null); - var descriptor = {}; - if(req.status == 200) { - var substrings = req.responseText.split (":"); - for (var i = 0; i < substrings.length; i += 2) { - if (substrings[i] == "suffix") { - descriptor[substrings[i]] = substrings[i + 1]; - } else { - descriptor[substrings[i]] = parseInt (substrings[i + 1]); - } - } - this.suffix = descriptor.suffix; - return descriptor; - } else { - throw new Error ("Unable to find descriptor."); - } - }, - - getPosterFilename : function () { - return this.getFilename ("poster" + this.suffix); - }, - - setPrefix : function (prefix) { - this.prefix = prefix; - }, - - getPrefix : function () { - if (this.prefix) { - return this.prefix + "/"; - } else { - return ""; - } - }, - - getFilename : function (name) { - return this.parameters.basePath + "/" + this.getPrefix () + name; - }, - - getImageFilename : function (tileX, tileY, zoomLevel) { - var key = (-zoomLevel) + "/" + tileX + "_" + tileY + this.suffix; - return this.getFilename (key); - } -}; - -bigshot.Object.validate ("bigshot.FolderFileSystem", bigshot.FileSystem); -/* - * Copyright 2010 - 2012 Leo Sutic - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -/** - * Creates a new instance of a Deep Zoom Image folder-based filesystem adapter. - * - * @augments bigshot.FileSystem - * @class A Deep Zoom Image filesystem. - * @param {bigshot.ImageParameters|bigshot.VRPanoramaParameters} parameters the associated image parameters - * @constructor - */ -bigshot.DeepZoomImageFileSystem = function (parameters) { - this.prefix = ""; - this.suffix = ""; - - this.DZ_NAMESPACE = "http://schemas.microsoft.com/deepzoom/2009"; - this.fullZoomLevel = 0; - this.posterName = ""; - this.parameters = parameters; -} - -bigshot.DeepZoomImageFileSystem.prototype = { - getDescriptor : function () { - var descriptor = {}; - - var xml = this.parameters.dataLoader.loadXml (this.parameters.basePath + this.prefix + ".xml", false); - var image = xml.getElementsByTagName ("Image")[0]; - var size = xml.getElementsByTagName ("Size")[0]; - descriptor.width = parseInt (size.getAttribute ("Width")); - descriptor.height = parseInt (size.getAttribute ("Height")); - descriptor.tileSize = parseInt (image.getAttribute ("TileSize")); - descriptor.overlap = parseInt (image.getAttribute ("Overlap")); - descriptor.suffix = "." + image.getAttribute ("Format") - descriptor.posterSize = descriptor.tileSize; - - this.suffix = descriptor.suffix; - this.fullZoomLevel = Math.ceil (Math.log (Math.max (descriptor.width, descriptor.height)) / Math.LN2); - - descriptor.minZoom = -this.fullZoomLevel; - var posterZoomLevel = Math.ceil (Math.log (descriptor.tileSize) / Math.LN2); - this.posterName = this.getImageFilename (0, 0, posterZoomLevel - this.fullZoomLevel); - return descriptor; - }, - - setPrefix : function (prefix) { - this.prefix = prefix; - }, - - getPosterFilename : function () { - return this.posterName; - }, - - getFilename : function (name) { - return this.parameters.basePath + this.prefix + "/" + name; - }, - - getImageFilename : function (tileX, tileY, zoomLevel) { - var dziZoomLevel = this.fullZoomLevel + zoomLevel; - var key = dziZoomLevel + "/" + tileX + "_" + tileY + this.suffix; - return this.getFilename (key); - } -}; -/* - * Copyright 2010 - 2012 Leo Sutic - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -/** - * Creates a new instance of a .bigshot archive filesystem adapter. - * - * @class Bigshot archive filesystem. - * @param {bigshot.ImageParameters|bigshot.VRPanoramaParameters} parameters the associated image parameters - * @augments bigshot.FileSystem - * @constructor - */ -bigshot.ArchiveFileSystem = function (parameters) { - this.indexSize = 0; - this.offset = 0; - this.index = {}; - this.prefix = ""; - this.suffix = ""; - this.parameters = parameters; - - var browser = new bigshot.Browser (); - var req = browser.createXMLHttpRequest (); - req.open("GET", this.parameters.basePath + "&start=0&length=24&type=text/plain", false); - req.send(null); - if(req.status == 200) { - if (req.responseText.substring (0, 7) != "BIGSHOT") { - alert ("\"" + this.parameters.basePath + "\" is not a valid bigshot file"); - return; - } - this.indexSize = parseInt (req.responseText.substring (8), 16); - this.offset = this.indexSize + 24; - - req.open("GET", this.parameters.basePath + "&type=text/plain&start=24&length=" + this.indexSize, false); - req.send(null); - if(req.status == 200) { - var substrings = req.responseText.split (":"); - for (var i = 0; i < substrings.length; i += 3) { - this.index[substrings[i]] = { - start : parseInt (substrings[i + 1]) + this.offset, - length : parseInt (substrings[i + 2]) - }; - } - } else { - alert ("The index of \"" + this.parameters.basePath + "\" could not be loaded: " + req.status); - } - } else { - alert ("The header of \"" + this.parameters.basePath + "\" could not be loaded: " + req.status); - } -}; - - -bigshot.ArchiveFileSystem.prototype = { - getDescriptor : function () { - this.browser = new bigshot.Browser (); - var req = this.browser.createXMLHttpRequest (); - - req.open("GET", this.getFilename ("descriptor"), false); - req.send(null); - var descriptor = {}; - if(req.status == 200) { - var substrings = req.responseText.split (":"); - for (var i = 0; i < substrings.length; i += 2) { - if (substrings[i] == "suffix") { - descriptor[substrings[i]] = substrings[i + 1]; - } else { - descriptor[substrings[i]] = parseInt (substrings[i + 1]); - } - } - this.suffix = descriptor.suffix; - return descriptor; - } else { - throw new Error ("Unable to find descriptor."); - } - }, - - getPosterFilename : function () { - return this.getFilename ("poster" + this.suffix); - }, - - getFilename : function (name) { - name = this.getPrefix () + name; - if (!this.index[name] && console) { - console.log ("Can't find " + name); - } - var f = this.parameters.basePath + "&start=" + this.index[name].start + "&length=" + this.index[name].length; - if (name.substring (name.length - 4) == ".jpg") { - f = f + "&type=image/jpeg"; - } else if (name.substring (name.length - 4) == ".png") { - f = f + "&type=image/png"; - } else { - f = f + "&type=text/plain"; - } - return f; - }, - - getImageFilename : function (tileX, tileY, zoomLevel) { - var key = (-zoomLevel) + "/" + tileX + "_" + tileY + this.suffix; - return this.getFilename (key); - }, - - getPrefix : function () { - if (this.prefix) { - return this.prefix + "/"; - } else { - return ""; - } - }, - - setPrefix : function (prefix) { - this.prefix = prefix; - } -} - -bigshot.Object.validate ("bigshot.ArchiveFileSystem", bigshot.FileSystem); -/* - * Copyright 2010 - 2012 Leo Sutic - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -/** - * @class Abstract base class. - */ -bigshot.VRTileCache = function () { -} - -bigshot.VRTileCache.prototype = { - /** - * Returns the texture object for the given tile-x, tile-y and zoom level. - * The return type is dependent on the renderer. The WebGL renderer, for example - * uses a tile cache that returns WebGL textures, while the CSS3D renderer - * returns HTML img or canvas elements. - */ - getTexture : function (tileX, tileY, zoomLevel) {}, - - /** - * Purges the cache of old entries. - * - * @type void - */ - purge : function () {}, - - /** - * Disposes the cache and all its entries. - * - * @type void - */ - dispose : function () {} -} -/* - * Copyright 2010 - 2012 Leo Sutic - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -/** - * @class A VR tile cache backed by a {@link bigshot.ImageTileCache}. - * @augments bigshot.VRTileCache - */ -bigshot.ImageVRTileCache = function (onloaded, onCacheInit, parameters) { - this.imageTileCache = new bigshot.ImageTileCache (onloaded, onCacheInit, parameters); - - // Keep the imageTileCache from wrapping around. - this.imageTileCache.setMaxTiles (999999, 999999); -} - -bigshot.ImageVRTileCache.prototype = { - getTexture : function (tileX, tileY, zoomLevel) { - var res = this.imageTileCache.getImage (tileX, tileY, zoomLevel); - return res; - }, - - purge : function () { - this.imageTileCache.resetUsed (); - }, - - dispose : function () { - - } -} - -bigshot.Object.validate ("bigshot.ImageVRTileCache", bigshot.VRTileCache); -/* - * Copyright 2010 - 2012 Leo Sutic - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -/** - * Creates a new cache instance. - * - * @class Tile texture cache for a {@link bigshot.VRFace}. - * @augments bigshot.VRTileCache - * @param {function()} onLoaded function that is called whenever a texture tile has been loaded - * @param {function()} onCacheInit function that is called when the texture cache is fully initialized - * @param {bigshot.VRPanoramaParameters} parameters image parameters - * @param {bigshot.WebGL} _webGl WebGL instance to use - */ -bigshot.TextureTileCache = function (onLoaded, onCacheInit, parameters, _webGl) { - this.parameters = parameters; - this.webGl = _webGl; - - /** - * Reduced-resolution preview of the full image. - * Loaded from the "poster" image created by - * MakeImagePyramid - * - * @private - * @type HTMLImageElement - */ - this.fullImage = parameters.dataLoader.loadImage (parameters.fileSystem.getPosterFilename (), onCacheInit); - - /** - * Maximum number of WebGL textures in the cache. This is the - * "L1" cache. - * - * @private - * @type int - */ - this.maxTextureCacheSize = 512; - - /** - * Maximum number of HTMLImageElement images in the cache. This is the - * "L2" cache. - * - * @private - * @type int - */ - this.maxImageCacheSize = 2048; - this.cachedTextures = {}; - this.cachedImages = {}; - this.requestedImages = {}; - this.lastOnLoadFiredAt = 0; - this.imageRequests = 0; - this.partialImageSize = parameters.tileSize / 8; - this.imageLruMap = new bigshot.LRUMap (); - this.textureLruMap = new bigshot.LRUMap (); - this.onLoaded = onLoaded; - this.browser = new bigshot.Browser (); - this.disposed = false; -} - -bigshot.TextureTileCache.prototype = { - - getPartialTexture : function (tileX, tileY, zoomLevel) { - if (this.fullImage.complete) { - var canvas = document.createElement ("canvas"); - if (!canvas["width"]) { - return null; - } - canvas.width = this.partialImageSize; - canvas.height = this.partialImageSize; - var ctx = canvas.getContext ("2d"); - - var posterScale = this.parameters.posterSize / Math.max (this.parameters.width, this.parameters.height); - - var posterWidth = Math.floor (posterScale * this.parameters.width); - var posterHeight = Math.floor (posterScale * this.parameters.height); - - var tileSizeAtZoom = posterScale * (this.parameters.tileSize - this.parameters.overlap) / Math.pow (2, zoomLevel); - var sx = Math.floor (tileSizeAtZoom * tileX); - var sy = Math.floor (tileSizeAtZoom * tileY); - var sw = Math.floor (tileSizeAtZoom); - var sh = Math.floor (tileSizeAtZoom); - var dw = this.partialImageSize + 2; - var dh = this.partialImageSize + 2; - - if (sx + sw > posterWidth) { - sw = posterWidth - sx; - dw = this.partialImageSize * (sw / Math.floor (tileSizeAtZoom)); - } - if (sy + sh > posterHeight) { - sh = posterHeight - sy; - dh = this.partialImageSize * (sh / Math.floor (tileSizeAtZoom)); - } - - ctx.drawImage (this.fullImage, sx, sy, sw, sh, -1, -1, dw, dh); - - return this.webGl.createImageTextureFromImage (canvas, this.parameters.textureMinFilter, this.parameters.textureMagFilter); - } else { - return null; - } - }, - - setCachedTexture : function (key, newTexture) { - if (this.cachedTextures[key] != null) { - this.webGl.deleteTexture (this.cachedTextures[key]); - } - this.cachedTextures[key] = newTexture; - }, - - getTexture : function (tileX, tileY, zoomLevel) { - var key = this.getImageKey (tileX, tileY, zoomLevel); - this.textureLruMap.access (key); - this.imageLruMap.access (key); - - if (this.cachedTextures[key]) { - return this.cachedTextures[key]; - } else if (this.cachedImages[key]) { - this.setCachedTexture (key, this.webGl.createImageTextureFromImage (this.cachedImages[key], this.parameters.textureMinFilter, this.parameters.textureMagFilter)); - return this.cachedTextures[key]; - } else { - this.requestImage (tileX, tileY, zoomLevel); - var partial = this.getPartialTexture (tileX, tileY, zoomLevel); - if (partial) { - this.setCachedTexture (key, partial); - } - return partial; - } - }, - - requestImage : function (tileX, tileY, zoomLevel) { - var key = this.getImageKey (tileX, tileY, zoomLevel); - if (!this.requestedImages[key]) { - this.imageRequests++; - var that = this; - this.parameters.dataLoader.loadImage (this.getImageFilename (tileX, tileY, zoomLevel), function (tile) { - if (that.disposed) { - return; - } - that.cachedImages[key] = tile; - that.setCachedTexture (key, that.webGl.createImageTextureFromImage (tile, that.parameters.textureMinFilter, that.parameters.textureMagFilter)); - delete that.requestedImages[key]; - that.imageRequests--; - var now = new Date(); - if (that.imageRequests == 0 || now.getTime () > (that.lastOnLoadFiredAt + 50)) { - that.lastOnLoadFiredAt = now.getTime (); - that.onLoaded (); - } - }); - this.requestedImages[key] = true; - } - }, - - purge : function () { - var that = this; - this.purgeCache (this.textureLruMap, this.cachedTextures, this.maxTextureCacheSize, function (leastUsedKey) { - that.webGl.deleteTexture (that.cachedTextures[leastUsedKey]); - }); - this.purgeCache (this.imageLruMap, this.cachedImages, this.maxImageCacheSize, function (leastUsedKey) { - }); - }, - - purgeCache : function (lruMap, cache, maxCacheSize, onEvict) { - for (var i = 0; i < 64; ++i) { - if (lruMap.getSize () > maxCacheSize) { - var leastUsed = lruMap.leastUsed (); - lruMap.remove (leastUsed); - if (onEvict) { - onEvict (leastUsed); - } - delete cache[leastUsed]; - } else { - break; - } - } - }, - - getImageKey : function (tileX, tileY, zoomLevel) { - return "I" + tileX + "_" + tileY + "_" + zoomLevel; - }, - - getImageFilename : function (tileX, tileY, zoomLevel) { - var f = this.parameters.fileSystem.getImageFilename (tileX, tileY, zoomLevel); - return f; - }, - - dispose : function () { - this.disposed = true; - for (var k in this.cachedTextures) { - this.webGl.deleteTexture (this.cachedTextures[k]); - } - } -}; - - -bigshot.Object.validate ("bigshot.TextureTileCache", bigshot.VRTileCache); -/* - * Copyright 2010 - 2012 Leo Sutic - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -/** - * Creates a new VR cube face. - * - * @class a VR cube face. The {@link bigshot.VRPanorama} instance holds - * six of these. - * - * @param {bigshot.VRPanorama} owner the VR panorama this face is part of. - * @param {String} key the identifier for the face. "f" is front, "b" is back, "u" is - * up, "d" is down, "l" is left and "r" is right. - * @param {bigshot.Point3D} topLeft_ the top-left corner of the quad. - * @param {number} width_ the length of the sides of the face, expressed in multiples of u and v. - * @param {bigshot.Point3D} u basis vector going from the top left corner along the top edge of the face - * @param {bigshot.Point3D} v basis vector going from the top left corner along the left edge of the face - */ -bigshot.VRFace = function (owner, key, topLeft_, width_, u, v, onLoaded) { - var that = this; - this.owner = owner; - this.key = key; - this.topLeft = topLeft_; - this.width = width_; - this.u = u; - this.v = v; - this.updated = false; - this.parameters = new Object (); - - for (var k in this.owner.getParameters ()) { - this.parameters[k] = this.owner.getParameters ()[k]; - } - - bigshot.setupFileSystem (this.parameters); - this.parameters.fileSystem.setPrefix ("face_" + key); - this.parameters.merge (this.parameters.fileSystem.getDescriptor (), false); - - - /** - * Texture cache. - * - * @private - */ - this.tileCache = owner.renderer.createTileCache (function () { - that.updated = true; - owner.renderUpdated (bigshot.VRPanorama.ONRENDER_TEXTURE_UPDATE); - }, onLoaded, this.parameters); - - this.fullSize = this.parameters.width; - this.overlap = this.parameters.overlap; - this.tileSize = this.parameters.tileSize; - - this.minDivisions = 0; - var fullZoom = Math.log (this.fullSize - this.overlap) / Math.LN2; - var singleTile = Math.log (this.tileSize - this.overlap) / Math.LN2; - this.maxDivisions = Math.floor (fullZoom - singleTile); - this.maxTesselation = this.parameters.maxTesselation >= 0 ? this.parameters.maxTesselation : this.maxDivisions; -} - -bigshot.VRFace.prototype = { - browser : new bigshot.Browser (), - - dispose : function () { - this.tileCache.dispose (); - }, - - /** - * Utility function to do a multiply-and-add of a 3d point. - * - * @private - * @param p {bigshot.Point3D} the point to multiply - * @param m {number} the number to multiply the elements of p with - * @param a {bigshot.Point3D} the point to add - * @return p * m + a - */ - pt3dMultAdd : function (p, m, a) { - return { - x : p.x * m + a.x, - y : p.y * m + a.y, - z : p.z * m + a.z - }; - }, - - /** - * Utility function to do an element-wise multiply of a 3d point. - * - * @private - * @param p {bigshot.Point3D} the point to multiply - * @param m {number} the number to multiply the elements of p with - * @return p * m - */ - pt3dMult : function (p, m) { - return { - x : p.x * m, - y : p.y * m, - z : p.z * m - }; - }, - - /** - * Creates a textured quad. - * - * @private - */ - generateFace : function (scene, topLeft, width, tx, ty, divisions) { - width *= this.tileSize / (this.tileSize - this.overlap); - var texture = this.tileCache.getTexture (tx, ty, -this.maxDivisions + divisions); - scene.addQuad (this.owner.renderer.createTexturedQuad ( - topLeft, - this.pt3dMult (this.u, width), - this.pt3dMult (this.v, width), - texture - ) - ); - }, - - VISIBLE_NONE : 0, - VISIBLE_SOME : 1, - VISIBLE_ALL : 2, - - /** - * Tests whether the point is in the axis-aligned rectangle. - * - * @private - * @param point the point - * @param min top left corner of the rectangle - * @param max bottom right corner of the rectangle - */ - pointInRect : function (point, min, max) { - return (point.x >= min.x && point.y >= min.y && point.x < max.x && point.y < max.y); - }, - - /** - * Intersects a quadrilateral with the view frustum. - * The test is a simple rectangle intersection of the AABB of - * the transformed quad with the viewport. - * - * @private - * @return VISIBLE_NONE, VISIBLE_SOME or VISIBLE_ALL - */ - intersectWithView : function intersectWithView (transformed) { - var numNull = 0; - var tf = []; - var tfl = transformed.length; - for (var i = 0; i < tfl; ++i) { - if (transformed[i] == null) { - numNull++; - } else { - tf.push (transformed[i]); - } - } - if (numNull == 4) { - return this.VISIBLE_NONE; - } - - var minX = tf[0].x; - var minY = tf[0].y; - - var maxX = minX; - var maxY = minY; - - var viewMinX = 0; - var viewMinY = 0; - - var viewMaxX = this.viewportWidth; - var viewMaxY = this.viewportHeight; - - var pointsInViewport = 0; - var tl = tf.length; - for (var i = 1; i < tl; ++i) { - var tix = tf[i].x; - var tiy = tf[i].y; - - minX = minX < tix ? minX : tix; - minY = minY < tiy ? minY : tiy; - - - maxX = maxX > tix ? maxX : tix; - maxY = maxY > tiy ? maxY : tiy; - } - - var iminX = minX > viewMinX ? minX : viewMinX; - var iminY = minY > viewMinY ? minY : viewMinY; - - var imaxX = maxX < viewMaxX ? maxX : viewMaxX; - var imaxY = maxY < viewMaxY ? maxY : viewMaxY; - - if (iminX <= imaxX && iminY <= imaxY) { - return this.VISIBLE_SOME; - } - - return this.VISIBLE_NONE; - }, - - /** - * Quick and dirty computation of the on-screen distance in pixels - * between two 2d points. We use the max of the x and y differences. - * In case a point is null (that is, it's not on the screen), we - * return an arbitrarily high number. - * - * @private - */ - screenDistance : function screenDistance (p0, p1) { - if (p0 == null || p1 == null) { - return 0; - } - return Math.max (Math.abs (p0.x - p1.x), Math.abs (p0.y - p1.y)); - }, - - transformToScreen : function transformToScreen (v) { - return this.owner.renderer.transformToScreen (v); - }, - - /** - * Optionally subdivides a quad into fourn new quads, depending on the - * position and on-screen size of the quad. - * - * @private - * @param {bigshot.WebGLTexturedQuadScene} scene the scene to add quads to - * @param {bigshot.Point3D} topLeft the top left corner of this quad - * @param {number} width the sides of the quad, expressed in multiples of u and v - * @param {int} divisions the current number of divisions done (increases by one for each - * split-in-four). - * @param {int} tx the tile column this face is in - * @param {int} ty the tile row this face is in - */ - generateSubdivisionFace : function generateSubdivisionFace (scene, topLeft, width, divisions, tx, ty, transformed) { - if (!transformed) { - transformed = new Array (4); - transformed[0] = this.transformToScreen (topLeft); - var topRight = this.pt3dMultAdd (this.u, width, topLeft); - transformed[1] = this.transformToScreen (topRight); - - var bottomLeft = this.pt3dMultAdd (this.v, width, topLeft); - transformed[3] = this.transformToScreen (bottomLeft); - - var bottomRight = this.pt3dMultAdd (this.v, width, topRight); - transformed[2] = this.transformToScreen (bottomRight); - }; - - var numVisible = this.intersectWithView (transformed); - - if (numVisible == this.VISIBLE_NONE) { - return; - } - - var dmax = 0; - for (var i = 0; i < transformed.length; ++i) { - var next = (i + 1) % 4; - dmax = Math.max (this.screenDistance (transformed[i], transformed[next]), dmax); - } - - // Convert the distance to physical pixels - dmax *= this.owner.browser.getDevicePixelScale (); - - if (divisions < this.minDivisions - || - ( - ( - dmax > this.owner.maxTextureMagnification * (this.tileSize - this.overlap) - ) && divisions < this.maxDivisions && divisions < this.maxTesselation - ) - ) { - var center = this.pt3dMultAdd ({x: this.u.x + this.v.x, y: this.u.y + this.v.y, z: this.u.z + this.v.z }, width / 2, topLeft); - var midTop = this.pt3dMultAdd (this.u, width / 2, topLeft); - var midLeft = this.pt3dMultAdd (this.v, width / 2, topLeft); - - var tCenter = this.transformToScreen (center); - var tMidLeft = this.transformToScreen (midLeft); - var tMidTop = this.transformToScreen (midTop); - var tMidRight = this.transformToScreen (this.pt3dMultAdd (this.u, width, midLeft)); - var tMidBottom = this.transformToScreen (this.pt3dMultAdd (this.v, width, midTop)); - - this.generateSubdivisionFace (scene, topLeft, width / 2, divisions + 1, tx * 2, ty * 2, [transformed[0], tMidTop, tCenter, tMidLeft]); - this.generateSubdivisionFace (scene, midTop, width / 2, divisions + 1, tx * 2 + 1, ty * 2, [tMidTop, transformed[1], tMidRight, tCenter]); - this.generateSubdivisionFace (scene, midLeft, width / 2, divisions + 1, tx * 2, ty * 2 + 1, [tMidLeft, tCenter, tMidBottom, transformed[3]]); - this.generateSubdivisionFace (scene, center, width / 2, divisions + 1, tx * 2 + 1, ty * 2 + 1, [tCenter, tMidRight, transformed[2], tMidBottom]); - } else { - this.generateFace (scene, topLeft, width, tx, ty, divisions); - } - }, - - /** - * Tests if the face has had any updated texture - * notifications from the tile cache. - * - * @public - */ - isUpdated : function () { - return this.updated; - }, - - /** - * Renders this face into a scene. - * - * @public - * @param {bigshot.WebGLTexturedQuadScene} scene the scene to render into - */ - render : function (scene) { - this.updated = false; - this.viewportWidth = this.owner.renderer.getViewportWidth (); - this.viewportHeight = this.owner.renderer.getViewportHeight (); - this.generateSubdivisionFace (scene, this.topLeft, this.width, 0, 0, 0); - }, - - /** - * Performs post-render cleanup. - */ - endRender : function () { - this.tileCache.purge (); - } -} -/* - * Copyright 2010 - 2012 Leo Sutic - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -/** - * @class WebGL utility functions. - */ -bigshot.WebGLUtil = { - /** - * Flag indicating whether we want to wrap the WebGL context in a - * WebGLDebugUtils.makeDebugContext. Defaults to false. - * - * @type boolean - * @public - */ - debug : false, - - /** - * List of context identifiers WebGL may be accessed via. - * - * @type String[] - * @private - */ - contextNames : ["webgl", "experimental-webgl"], - - /** - * Utility function for creating a context given a canvas and - * a context identifier. - * @type WebGLRenderingContext - * @private - */ - createContext0 : function (canvas, context) { - var gl = this.debug - ? - WebGLDebugUtils.makeDebugContext(canvas.getContext(context)) - : - canvas.getContext (context); - return gl; - }, - - /** - * Creates a WebGL context for the given canvas, if possible. - * - * @public - * @type WebGLRenderingContext - * @param {HTMLCanvasElement} canvas the canvas - * @return The WebGL context - * @throws {Error} If WebGL isn't supported. - */ - createContext : function (canvas) { - for (var i = 0; i < this.contextNames.length; ++i) { - try { - var gl = this.createContext0 (canvas, this.contextNames[i]); - if (gl) { - return gl; - } - } catch (e) { - } - } - throw new Error ("Could not initialize WebGL."); - }, - - /** - * Tests whether WebGL is supported. - * - * @type boolean - * @public - * @return true If WebGL is supported, false otherwise. - */ - isWebGLSupported : function () { - var canvas = document.createElement ("canvas"); - if (!canvas["width"]) { - // Not even canvas support - return false; - } - - try { - this.createContext (canvas); - return true; - } catch (e) { - // No WebGL support - return false; - } - } -} -/* - * Copyright 2010 - 2012 Leo Sutic - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -/** - * Creates a new transformation stack, initialized to the identity transform. - * - * @class A 3D transformation stack. - */ -bigshot.TransformStack = function () { - /** - * The current transform matrix. - * - * @type Matrix - */ - this.mvMatrix = null; - - /** - * The object-to-world transform matrix stack. - * - * @type Matrix[] - */ - this.mvMatrixStack = []; - - this.reset (); -} - -bigshot.TransformStack.prototype = { - /** - * Pushes the current world transform onto the stack - * and returns a new, identical one. - * - * @return the new world transform matrix - * @param {Matrix} [matrix] the new world transform. - * If omitted, the current is used - * @type Matrix - */ - push : function (matrix) { - if (matrix) { - this.mvMatrixStack.push (matrix.dup()); - this.mvMatrix = matrix.dup(); - return mvMatrix; - } else { - this.mvMatrixStack.push (this.mvMatrix.dup()); - return mvMatrix; - } - }, - - /** - * Pops the last-pushed world transform off the stack, thereby restoring it. - * - * @type Matrix - * @return the previously-pushed matrix - */ - pop : function () { - if (this.mvMatrixStack.length == 0) { - throw new Error ("Invalid popMatrix!"); - } - this.mvMatrix = this.mvMatrixStack.pop(); - return mvMatrix; - }, - - /** - * Resets the world transform to the identity transform. - */ - reset : function () { - this.mvMatrix = Matrix.I(4); - }, - - /** - * Multiplies the current world transform with a matrix. - * - * @param {Matrix} matrix the matrix to multiply with - */ - multiply : function (matrix) { - this.mvMatrix = matrix.x (this.mvMatrix); - }, - - /** - * Adds a translation to the world transform matrix. - * - * @param {bigshot.Point3D} vector the translation vector - */ - translate : function (vector) { - var m = Matrix.Translation($V([vector.x, vector.y, vector.z])).ensure4x4 (); - this.multiply (m); - }, - - /** - * Adds a rotation to the world transform matrix. - * - * @param {number} ang the angle in degrees to rotate - * @param {bigshot.Point3D} vector the rotation vector - */ - rotate : function (ang, vector) { - var arad = ang * Math.PI / 180.0; - var m = Matrix.Rotation(arad, $V([vector.x, vector.y, vector.z])).ensure4x4 (); - this.multiply (m); - }, - - /** - * Adds a rotation around the x-axis to the world transform matrix. - * - * @param {number} ang the angle in degrees to rotate - */ - rotateX : function (ang) { - this.rotate (ang, { x : 1, y : 0, z : 0 }); - }, - - /** - * Adds a rotation around the y-axis to the world transform matrix. - * - * @param {number} ang the angle in degrees to rotate - */ - rotateY : function (ang) { - this.rotate (ang, { x : 0, y : 1, z : 0 }); - }, - - /** - * Adds a rotation around the z-axis to the world transform matrix. - * - * @param {number} ang the angle in degrees to rotate - */ - rotateZ : function (ang) { - this.rotate (ang, { x : 0, y : 0, z : 1 }); - }, - - /** - * Multiplies the current matrix with a - * perspective transformation matrix. - * - * @param {number} fovy vertical field of view - * @param {number} aspect viewport aspect ratio - * @param {number} znear near image plane - * @param {number} zfar far image plane - */ - perspective : function (fovy, aspect, znear, zfar) { - var m = makePerspective (fovy, aspect, znear, zfar); - this.multiply (m); - }, - - matrix : function () { - return this.mvMatrix; - } -} -/* - * Copyright 2010 - 2012 Leo Sutic - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -/** - * Creates a new WebGL wrapper instance. - * - * @class WebGL wrapper for common {@link bigshot.VRPanorama} uses. - * @param {HTMLCanvasElement} canvas_ the canvas - * @see #onresize() - */ -bigshot.WebGL = function (canvas_) { - /** - * The html canvas element we'll be rendering in. - * - * @type HTMLCanvasElement - */ - this.canvas = canvas_; - - /** - * Our WebGL context. - * - * @type WebGLRenderingContext - */ - this.gl = bigshot.WebGLUtil.createContext (this.canvas); - - /** - * The current object-to-world transform matrix. - * - * @type bigshot.TransformStack - */ - this.mvMatrix = new bigshot.TransformStack (); - - /** - * The current perspective transform matrix. - * - * @type bigshot.TransformStack - */ - this.pMatrix = new bigshot.TransformStack (); - - /** - * The current shader program. - */ - this.shaderProgram = null; - - this.onresize (); -} - -bigshot.WebGL.prototype = { - /** - * Must be called when the canvas element is resized. - * - * @public - */ - onresize : function () { - this.gl.viewportWidth = this.canvas.width; - this.gl.viewportHeight = this.canvas.height; - }, - - /** - * Fragment shader. Taken from the "Learning WebGL" lessons: - * http://learningwebgl.com/blog/?p=571 - */ - fragmentShader : - "#ifdef GL_ES\n" + - " precision highp float;\n" + - "#endif\n" + - "\n" + - "varying vec2 vTextureCoord;\n" + - "\n" + - "uniform sampler2D uSampler;\n" + - "\n" + - "void main(void) {\n" + - " gl_FragColor = texture2D(uSampler, vec2(vTextureCoord.s, vTextureCoord.t));\n" + - "}\n", - - /** - * Vertex shader. Taken from the "Learning WebGL" lessons: - * http://learningwebgl.com/blog/?p=571 - */ - vertexShader : - "attribute vec3 aVertexPosition;\n" + - "attribute vec2 aTextureCoord;\n" + - "\n" + - "uniform mat4 uMVMatrix;\n" + - "uniform mat4 uPMatrix;\n" + - "\n" + - "varying vec2 vTextureCoord;\n" + - "\n" + - "void main(void) {\n" + - " gl_Position = uPMatrix * uMVMatrix * vec4(aVertexPosition, 1.0);\n" + - " vTextureCoord = aTextureCoord;\n" + - "}", - - /** - * Creates a new shader. - * - * @type WebGLShader - * @param {String} source the source code - * @param {int} type the shader type, one of WebGLRenderingContext.FRAGMENT_SHADER or - * WebGLRenderingContext.VERTEX_SHADER - */ - createShader : function (source, type) { - var shader = this.gl.createShader (type); - this.gl.shaderSource (shader, source); - this.gl.compileShader (shader); - - if (!this.gl.getShaderParameter (shader, this.gl.COMPILE_STATUS)) { - alert (this.gl.getShaderInfoLog (shader)); - return null; - } - - return shader; - }, - - /** - * Creates a new fragment shader. - * - * @type WebGLShader - * @param {String} source the source code - */ - createFragmentShader : function (source) { - return this.createShader (source, this.gl.FRAGMENT_SHADER); - }, - - /** - * Creates a new vertex shader. - * - * @type WebGLShader - * @param {String} source the source code - */ - createVertexShader : function (source) { - return this.createShader (source, this.gl.VERTEX_SHADER); - }, - - /** - * Initializes the shaders. - */ - initShaders : function () { - this.shaderProgram = this.gl.createProgram (); - this.gl.attachShader (this.shaderProgram, this.createVertexShader (this.vertexShader)); - this.gl.attachShader (this.shaderProgram, this.createFragmentShader (this.fragmentShader)); - this.gl.linkProgram (this.shaderProgram); - - if (!this.gl.getProgramParameter (this.shaderProgram, this.gl.LINK_STATUS)) { - throw new Error ("Could not initialise shaders"); - return; - } - - this.gl.useProgram (this.shaderProgram); - - this.shaderProgram.vertexPositionAttribute = this.gl.getAttribLocation (this.shaderProgram, "aVertexPosition"); - this.gl.enableVertexAttribArray (this.shaderProgram.vertexPositionAttribute); - - this.shaderProgram.textureCoordAttribute = this.gl.getAttribLocation (this.shaderProgram, "aTextureCoord"); - this.gl.enableVertexAttribArray (this.shaderProgram.textureCoordAttribute); - - this.shaderProgram.pMatrixUniform = this.gl.getUniformLocation(this.shaderProgram, "uPMatrix"); - this.shaderProgram.mvMatrixUniform = this.gl.getUniformLocation(this.shaderProgram, "uMVMatrix"); - this.shaderProgram.samplerUniform = this.gl.getUniformLocation(this.shaderProgram, "uSampler"); - }, - - - /** - * Sets the matrix parameters ("uniforms", since the variables are declared as uniform) in the shaders. - */ - setMatrixUniforms : function () { - this.gl.uniformMatrix4fv (this.shaderProgram.pMatrixUniform, false, new Float32Array(this.pMatrix.matrix().flatten())); - this.gl.uniformMatrix4fv (this.shaderProgram.mvMatrixUniform, false, new Float32Array(this.mvMatrix.matrix().flatten())); - }, - - /** - * Creates a texture from an image. - * - * @param {HTMLImageElement or HTMLCanvasElement} image the image - * @type WebGLTexture - * @return An initialized texture - */ - createImageTextureFromImage : function (image, minFilter, magFilter) { - var texture = this.gl.createTexture(); - this.handleImageTextureLoaded (this, texture, image, minFilter, magFilter); - return texture; - }, - - /** - * Creates a texture from a source url. - * - * @param {String} source the URL of the image - * @return WebGLTexture - */ - createImageTextureFromSource : function (source, minFilter, magFilter) { - var image = new Image(); - var texture = this.gl.createTexture(); - - var that = this; - image.onload = function () { - that.handleImageTextureLoaded (that, texture, image, minFilter, magFilter); - } - - image.src = source; - - return texture; - }, - - /** - * Uploads the image data to the texture memory. Called when the texture image - * has finished loading. - * - * @private - */ - handleImageTextureLoaded : function (that, texture, image, minFilter, magFilter) { - that.gl.bindTexture (that.gl.TEXTURE_2D, texture); - that.gl.texImage2D (that.gl.TEXTURE_2D, 0, that.gl.RGBA, that.gl.RGBA, that.gl.UNSIGNED_BYTE, image); - that.gl.texParameteri (that.gl.TEXTURE_2D, that.gl.TEXTURE_MAG_FILTER, magFilter ? magFilter : that.gl.NEAREST); - that.gl.texParameteri (that.gl.TEXTURE_2D, that.gl.TEXTURE_MIN_FILTER, minFilter ? minFilter : that.gl.NEAREST); - that.gl.texParameteri (that.gl.TEXTURE_2D, that.gl.TEXTURE_WRAP_S, that.gl.CLAMP_TO_EDGE); - that.gl.texParameteri (that.gl.TEXTURE_2D, that.gl.TEXTURE_WRAP_T, that.gl.CLAMP_TO_EDGE); - if (minFilter == that.gl.NEAREST_MIPMAP_NEAREST - || minFilter == that.gl.LINEAR_MIPMAP_NEAREST - || minFilter == that.gl.NEAREST_MIPMAP_LINEAR - || minFilter == that.gl.LINEAR_MIPMAP_LINEAR) { - that.gl.generateMipmap(that.gl.TEXTURE_2D); - } - - that.gl.bindTexture (that.gl.TEXTURE_2D, null); - }, - - deleteTexture : function (texture) { - this.gl.deleteTexture (texture); - }, - - dispose : function () { - delete this.canvas; - delete this.gl; - } -}; -/* - * Copyright 2010 - 2012 Leo Sutic - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -/** - * @class Abstract base for 3d rendering system. - */ -bigshot.VRRenderer = function () { -} - -bigshot.VRRenderer.prototype = { - /** - * Creates a new {@link bigshot.VRTileCache}, appropriate for the rendering system. - * - * @param {function()} onloaded function that is called whenever a texture tile has been loaded - * @param {function()} onCacheInit function that is called when the texture cache is fully initialized - * @param {bigshot.VRPanoramaParameters} parameters the parameters for the panorama - */ - createTileCache : function (onloaded, onCacheInit, parameters) {}, - - /** - * Creates a bigshot.TexturedQuadScene. - */ - createTexturedQuadScene : function () {}, - - /** - * Creates a bigshot.TexturedQuad. - * - * @param {bigshot.Point3D} p the top-left corner of the quad - * @param {bigshot.Point3D} u a vector going along the top edge of the quad - * @param {bigshot.Point3D} v a vector going down the left edge of the quad - * @param {Object} texture a texture to use for the quad. The texture type may vary among different - * VRRenderer implementations. The VRTileCache that is created using the createTileCache method will - * supply the correct type. - */ - createTexturedQuad : function (p, u, v, texture) {}, - - /** - * Returns the viewport width, in pixels. - * - * @type int - */ - getViewportWidth : function () {}, - - /** - * Returns the viewport height, in pixels. - * - * @type int - */ - getViewportHeight : function () {}, - - /** - * Transforms a vector to world coordinates. - * - * @param {bigshot.Point3D} v the view-space point to transform - */ - transformToWorld : function (v) {}, - - /** - * Transforms a world vector to screen coordinates. - * - * @param {bigshot.Point3D} worldVector the world-space point to transform - */ - transformWorldToScreen : function (worldVector) {}, - - /** - * Transforms a 3D vector to screen coordinates. - * - * @param {bigshot.Point3D} vector the vector to transform. - * If it is already in homogenous coordinates (4-element array) - * the transformation is faster. Otherwise it will be converted. - */ - transformToScreen : function (vector) {}, - - /** - * Disposes the renderer and associated resources. - */ - dispose : function () {}, - - /** - * Called to begin a render. - * - * @param {bigshot.Rotation} rotation the rotation of the viewer - * @param {number} fov the vertical field of view, in degrees - * @param {bigshot.Point3D} translation the position of the viewer in world space - * @param {bigshot.Rotation} rotationOffsets the rotation to apply to the VR cube - * before the viewer rotation is applied - */ - beginRender : function (rotation, fov, translation, rotationOffsets) {}, - - /** - * Called to end a render. - */ - endRender : function () {}, - - /** - * Called by client code to notify the renderer that the viewport has been resized. - */ - onresize : function () {}, - - /** - * Resizes the viewport. - * - * @param {int} w the new width of the viewport, in pixels - * @param {int} h the new height of the viewport, in pixels - */ - resize : function (w, h) {}, - - /** - * Gets the container element for the renderer. This is used - * when calling the requestAnimationFrame API. - */ - getElement : function () {} -} -/* - * Copyright 2010 - 2012 Leo Sutic - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -/** - * @class Abstract VR renderer base class. - */ -bigshot.AbstractVRRenderer = function () { -} - -bigshot.AbstractVRRenderer.prototype = { - /** - * Transforms a vector to world coordinates. - * - * @param {bigshot.Point3D} vector the vector to transform - */ - transformToWorld : function transformToWorld (vector) { - var world = this.mvMatrix.matrix ().xPoint3Dhom1 (vector); - - return world; - }, - - /** - * Transforms a world vector to screen coordinates. - * - * @param {bigshot.Point3D} world the world-vector to transform - */ - transformWorldToScreen : function transformWorldToScreen (world) { - if (world.z > 0) { - return null; - } - - var screen = this.pMatrix.matrix ().xPoint3Dhom (world); - if (Math.abs (screen.w) < Sylvester.precision) { - return null; - } - - var sx = screen.x; - var sy = screen.y; - var sz = screen.z; - var vw = this.getViewportWidth (); - var vh = this.getViewportHeight (); - - var r = { - x: (vw / 2) * sx / sz + vw / 2, - y: - (vh / 2) * sy / sz + vh / 2 - }; - return r; - }, - - /** - * Transforms a vector to screen coordinates. - * - * @param {bigshot.Point3D} vector the vector to transform - * @return the transformed vector, or null if the vector is nearer than the near-z plane. - */ - transformToScreen : function transformToScreen (vector) { - var sel = this.mvpMatrix.xPoint3Dhom (vector); - - if (sel.z < 0) { - return null; - } - - var sz = sel.w; - - if (Math.abs (sel.w) < Sylvester.precision) { - return null; - } - - var sx = sel.x; - var sy = sel.y; - var vw = this.getViewportWidth (); - var vh = this.getViewportHeight (); - - var r = { - x: (vw / 2) * sx / sz + vw / 2, - y: - (vh / 2) * sy / sz + vh / 2 - }; - - return r; - } -} -/* - * Copyright 2010 - 2012 Leo Sutic - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -/** - * @class CSS 3D Transform-based renderer. - * @param {HTMLElement} _container the HTML container element for the render viewport - * - * @augments bigshot.VRRenderer - */ -bigshot.CSS3DVRRenderer = function (_container) { - this.container = _container; - this.canvasOrigin = document.createElement ("div"); - - this.canvasOrigin.style.WebkitTransformOrigin = "0px 0px 0px"; - this.canvasOrigin.style.WebkitTransformStyle = "preserve-3d"; - this.canvasOrigin.style.WebkitPerspective= "600px"; - - this.canvasOrigin.style.position = "relative"; - this.canvasOrigin.style.left = "50%"; - this.canvasOrigin.style.top = "50%"; - - this.container.appendChild (this.canvasOrigin); - - this.viewport = document.createElement ("div"); - this.viewport.style.WebkitTransformOrigin = "0px 0px 0px"; - this.viewport.style.WebkitTransformStyle = "preserve-3d"; - this.canvasOrigin.appendChild (this.viewport); - - this.world = document.createElement ("div"); - this.world.style.WebkitTransformOrigin = "0px 0px 0px"; - this.world.style.WebkitTransformStyle = "preserve-3d"; - this.viewport.appendChild (this.world); - - this.browser.removeAllChildren (this.world); - - this.view = null; - - this.mvMatrix = new bigshot.TransformStack (); - - this.yaw = 0; - this.pitch = 0; - this.fov = 0; - this.pMatrix = new bigshot.TransformStack (); - - this.onresize = function () { - }; - - this.viewportSize = null; -}; - -bigshot.CSS3DVRRenderer.prototype = { - browser : new bigshot.Browser (), - - dispose : function () { - - }, - - createTileCache : function (onloaded, onCacheInit, parameters) { - return new bigshot.ImageVRTileCache (onloaded, onCacheInit, parameters); - }, - - createTexturedQuadScene : function () { - return new bigshot.CSS3DTexturedQuadScene (this.world, 128, this.view); - }, - - createTexturedQuad : function (p, u, v, texture) { - return new bigshot.CSS3DTexturedQuad (p, u, v, texture); - }, - - getElement : function () { - return this.container; - }, - - supportsUpdate : function () { - return false; - }, - - getViewportWidth : function () { - if (this.viewportSize) { - return this.viewportSize.w; - } - return this.browser.getElementSize (this.container).w; - }, - - getViewportHeight : function () { - if (this.viewportSize) { - return this.viewportSize.h; - } - return this.browser.getElementSize (this.container).h; - }, - - onresize : function () { - }, - - resize : function (w, h) { - if (this.container.style.width != "") { - this.container.style.width = w + "px"; - } - if (this.container.style.height != "") { - this.container.style.height = h + "px"; - } - }, - - beginRender : function (rotation, fov, translation, rotationOffsets) { - this.viewportSize = this.browser.getElementSize (this.container); - - this.yaw = rotation.y; - this.pitch = rotation.p; - this.fov = fov; - - var halfFovInRad = 0.5 * fov * Math.PI / 180; - var halfHeight = this.getViewportHeight () / 2; - var perspectiveDistance = halfHeight / Math.tan (halfFovInRad); - - this.mvMatrix.reset (); - - this.view = translation; - this.mvMatrix.translate (this.view); - - - this.mvMatrix.rotateZ (rotationOffsets.r); - this.mvMatrix.rotateX (rotationOffsets.p); - this.mvMatrix.rotateY (rotationOffsets.y); - - this.mvMatrix.rotateY (this.yaw); - this.mvMatrix.rotateX (this.pitch); - - - this.pMatrix.reset (); - this.pMatrix.perspective (this.fov, this.getViewportWidth () / this.getViewportHeight (), 0.1, 100.0); - - this.mvpMatrix = this.pMatrix.matrix ().multiply (this.mvMatrix.matrix ()); - - this.canvasOrigin.style.WebkitPerspective= perspectiveDistance + "px"; - - for (var i = this.world.children.length - 1; i >= 0; --i) { - this.world.children[i].inWorld = 1; - } - - this.world.style.WebkitTransform = - "rotate3d(1,0,0," + (-rotation.p) + "deg) " + - "rotate3d(0,1,0," + rotation.y + "deg) " + - "rotate3d(0,1,0," + (rotationOffsets.y) + "deg) " + - "rotate3d(1,0,0," + (-rotationOffsets.p) + "deg) " + - "rotate3d(0,0,1," + (-rotationOffsets.r) + "deg) "; - this.world.style.WebkitTransformStyle = "preserve-3d"; - this.world.style.WebKitBackfaceVisibility = "hidden"; - - this.viewport.style.WebkitTransform = - "translateZ(" + perspectiveDistance + "px)"; - }, - - endRender : function () { - for (var i = this.world.children.length - 1; i >= 0; --i) { - var child = this.world.children[i]; - if (!child.inWorld || child.inWorld != 2) { - delete child.inWorld; - this.world.removeChild (child); - } - } - - this.viewportSize = null; - } -}; - -bigshot.Object.extend (bigshot.CSS3DVRRenderer, bigshot.AbstractVRRenderer); -bigshot.Object.validate ("bigshot.CSS3DVRRenderer", bigshot.VRRenderer); -/* - * Copyright 2010 - 2012 Leo Sutic - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -/** - * Creates a textured quad object. - * - * @class An abstraction for textured quads. Used in the - * {@link bigshot.CSS3DTexturedQuadScene}. - * - * @param {bigshot.Point3D} p the top-left corner of the quad - * @param {bigshot.Point3D} u vector pointing from p along the top edge of the quad - * @param {bigshot.Point3D} v vector pointing from p along the left edge of the quad - * @param {HTMLImageElement} the image to use. - */ -bigshot.CSS3DTexturedQuad = function (p, u, v, image) { - this.p = p; - this.u = u; - this.v = v; - this.image = image; -} - -bigshot.CSS3DTexturedQuad.prototype = { - /** - * Computes the cross product of two vectors. - * - * @param {bigshot.Point3D} a the first vector - * @param {bigshot.Point3D} b the second vector - * @type bigshot.Point3D - * @return the cross product - */ - crossProduct : function crossProduct (a, b) { - return { - x : a.y*b.z-a.z*b.y, - y : a.z*b.x-a.x*b.z, - z : a.x*b.y-a.y*b.x - }; - }, - - /** - * Stringifies a vector as the x, y, and z components - * separated by commas. - * - * @param {bigshot.Point3D} u the vector - * @type String - * @return the stringified vector - */ - vecToStr : function vecToStr (u) { - return (u.x) + "," + (u.y) + "," + (u.z); - }, - - /** - * Creates a CSS3D matrix3d transform from - * an origin point and two basis vectors - * - * @param {bigshot.Point3D} tl the top left corner - * @param {bigshot.Point3D} u the vector pointing along the top edge - * @param {bigshot.Point3D} y the vector pointing down the left edge - * @type String - * @return the matrix3d statement - */ - quadTransform : function quadTransform (tl, u, v) { - var w = this.crossProduct (u, v); - var res = - "matrix3d(" + - this.vecToStr (u) + ",0," + - this.vecToStr (v) + ",0," + - this.vecToStr (w) + ",0," + - this.vecToStr (tl) + ",1)"; - return res; - }, - - /** - * Computes the norm of a vector. - * - * @param {bigshot.Point3D} vec the vector - */ - norm : function norm (vec) { - return Math.sqrt (vec.x * vec.x + vec.y * vec.y + vec.z * vec.z); - }, - - /** - * Renders the quad. - * - * @param {HTMLElement} world the world element - * @param {number} scale the scale factor to apply to world space to get CSS pixel distances - * @param {bigshot.Point3D} view the viewer position in world space - */ - render : function render (world, scale, view) { - var s = scale / (this.image.width - 1); - var ps = scale * 1.0; - var p = this.p; - var u = this.u; - var v = this.v; - - this.image.style.position = "absolute"; - if (!this.image.inWorld || this.image.inWorld != 1) { - world.appendChild (this.image); - } - this.image.inWorld = 2; - this.image.style.WebkitTransformOrigin = "0px 0px 0px"; - this.image.style.WebkitTransform = - this.quadTransform ({ - x : (p.x + view.x) * ps, - y : (-p.y + view.y) * ps, - z : (p.z + view.z) * ps - }, { - x : u.x * s, - y : -u.y * s, - z : u.z * s - }, { - x : v.x * s, - y : -v.y * s, - z : v.z * s - }); - } -} -/* - * Copyright 2010 - 2012 Leo Sutic - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -/** - * Creates a textured quad scene. - * - * @param {HTMLElement} world element used as container for - * the world coordinate system. - * @param {number} scale the scaling factor to use to avoid - * numeric errors. - * @param {bigshot.Point3D} view the 3d-coordinates of the viewer - * - * @class A scene consisting of a number of quads, all with - * a unique texture. Used by the {@link bigshot.VRPanorama} to render the VR cube. - * - * @see bigshot.CSS3DTexturedQuad - */ -bigshot.CSS3DTexturedQuadScene = function (world, scale, view) { - this.quads = new Array (); - this.world = world; - this.scale = scale; - this.view = view; -} - -bigshot.CSS3DTexturedQuadScene.prototype = { - /** - * Adds a new quad to the scene. - * - * @param {bigshot.TexturedQuad} quad the quad to add to the scene - */ - addQuad : function (quad) { - this.quads.push (quad); - }, - - /** - * Renders all quads. - */ - render : function () { - for (var i = 0; i < this.quads.length; ++i) { - this.quads[i].render (this.world, this.scale, this.view); - } - } -}; -/* - * Copyright 2010 - 2012 Leo Sutic - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -/** - * @class Abstract base for textured quad scenes. - */ -bigshot.TexturedQuadScene = function () { -} - -bigshot.TexturedQuadScene.prototype = { - /** - * Adds a quad to the scene. - */ - addQuad : function (quad) {}, - - /** - * Renders the scene. - */ - render : function () {} -}; -/* - * Copyright 2010 - 2012 Leo Sutic - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -/** - * @class WebGL renderer. - */ -bigshot.WebGLVRRenderer = function (container) { - this.container = container; - - this.canvas = document.createElement ("canvas"); - this.canvas.width = 480; - this.canvas.height = 480; - this.canvas.style.position = "absolute"; - this.container.appendChild (this.canvas); - - this.webGl = new bigshot.WebGL (this.canvas); - this.webGl.initShaders (); - this.webGl.gl.clearColor(0.0, 0.0, 0.0, 1.0); - this.webGl.gl.blendFunc (this.webGl.gl.ONE, this.webGl.gl.ZERO); - this.webGl.gl.enable (this.webGl.gl.BLEND); - this.webGl.gl.disable (this.webGl.gl.DEPTH_TEST); - this.webGl.gl.clearDepth (1.0); - - var that = this; - this.buffers = new bigshot.TimedWeakReference (function () { - return that.setupBuffers (); - }, function (heldObject) { - that.disposeBuffers (heldObject); - }, 1000); -} - -bigshot.WebGLVRRenderer.prototype = { - createTileCache : function (onloaded, onCacheInit, parameters) { - return new bigshot.TextureTileCache (onloaded, onCacheInit, parameters, this.webGl); - }, - - createTexturedQuadScene : function () { - return new bigshot.WebGLTexturedQuadScene (this.webGl, this.buffers); - }, - - setupBuffers : function () { - var vertexPositionBuffer = this.webGl.gl.createBuffer(); - - var textureCoordBuffer = this.webGl.gl.createBuffer(); - this.webGl.gl.bindBuffer(this.webGl.gl.ARRAY_BUFFER, textureCoordBuffer); - var textureCoords = [ - // Front face - 0.0, 0.0, - 1.0, 0.0, - 1.0, 1.0, - 0.0, 1.0 - ]; - this.webGl.gl.bufferData (this.webGl.gl.ARRAY_BUFFER, new Float32Array (textureCoords), this.webGl.gl.STATIC_DRAW); - - var vertexIndexBuffer = this.webGl.gl.createBuffer(); - this.webGl.gl.bindBuffer(this.webGl.gl.ELEMENT_ARRAY_BUFFER, vertexIndexBuffer); - var vertexIndexes = [ - 0, 2, 1, - 0, 3, 2 - ]; - this.webGl.gl.bufferData(this.webGl.gl.ELEMENT_ARRAY_BUFFER, new Uint16Array (vertexIndexes), this.webGl.gl.STATIC_DRAW); - - this.webGl.gl.bindBuffer(this.webGl.gl.ARRAY_BUFFER, textureCoordBuffer); - this.webGl.gl.vertexAttribPointer(this.webGl.shaderProgram.textureCoordAttribute, 2, this.webGl.gl.FLOAT, false, 0, 0); - - this.webGl.gl.bindBuffer(this.webGl.gl.ARRAY_BUFFER, vertexPositionBuffer); - this.webGl.gl.vertexAttribPointer(this.webGl.shaderProgram.vertexPositionAttribute, 3, this.webGl.gl.FLOAT, false, 0, 0); - - return { - vertexPositionBuffer : vertexPositionBuffer, - textureCoordBuffer : textureCoordBuffer, - vertexIndexBuffer : vertexIndexBuffer - }; - }, - - dispose : function () { - this.buffers.dispose (); - this.container.removeChild (this.canvas); - delete this.canvas; - this.webGl.dispose (); - delete this.webGl; - }, - - disposeBuffers : function (buffers) { - this.webGl.gl.deleteBuffer (buffers.vertexPositionBuffer); - this.webGl.gl.deleteBuffer (buffers.vertexIndexBuffer); - this.webGl.gl.deleteBuffer (buffers.textureCoordBuffer); - }, - - getElement : function () { - return this.canvas; - }, - - supportsUpdate : function () { - return false; - }, - - createTexturedQuad : function (p, u, v, texture) { - return new bigshot.WebGLTexturedQuad (p, u, v, texture); - }, - - getViewportWidth : function () { - return this.webGl.gl.viewportWidth; - }, - - getViewportHeight : function () { - return this.webGl.gl.viewportHeight; - }, - - beginRender : function (rotation, fov, translation, rotationOffsets) { - this.webGl.gl.viewport (0, 0, this.webGl.gl.viewportWidth, this.webGl.gl.viewportHeight); - - this.webGl.pMatrix.reset (); - this.webGl.pMatrix.perspective (fov, this.webGl.gl.viewportWidth / this.webGl.gl.viewportHeight, 0.1, 100.0); - - this.webGl.mvMatrix.reset (); - this.webGl.mvMatrix.translate (translation); - this.webGl.mvMatrix.rotateZ (rotationOffsets.r); - this.webGl.mvMatrix.rotateX (rotationOffsets.p); - this.webGl.mvMatrix.rotateY (rotationOffsets.y); - this.webGl.mvMatrix.rotateY (rotation.y); - this.webGl.mvMatrix.rotateX (rotation.p); - - this.mvMatrix = this.webGl.mvMatrix; - this.pMatrix = this.webGl.pMatrix; - this.mvpMatrix = this.pMatrix.matrix ().multiply (this.mvMatrix.matrix ()); - }, - - endRender : function () { - - }, - - resize : function (w, h) { - this.canvas.width = w; - this.canvas.height = h; - if (this.container.style.width != "") { - this.container.style.width = w + "px"; - } - if (this.container.style.height != "") { - this.container.style.height = h + "px"; - } - }, - - onresize : function () { - this.webGl.onresize (); - } -} - -bigshot.Object.extend (bigshot.WebGLVRRenderer, bigshot.AbstractVRRenderer); -bigshot.Object.validate ("bigshot.WebGLVRRenderer", bigshot.VRRenderer); -/* - * Copyright 2010 - 2012 Leo Sutic - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -/** - * @class Abstract base for textured quads. - */ -bigshot.TexturedQuad = function () { -}; -/* - * Copyright 2010 - 2012 Leo Sutic - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -/** - * Creates a textured quad object. - * - * @class An abstraction for textured quads. Used in the - * {@link bigshot.WebGLTexturedQuadScene}. - * - * @param {bigshot.Point3D} p the top-left corner of the quad - * @param {bigshot.Point3D} u vector pointing from p along the top edge of the quad - * @param {bigshot.Point3D} v vector pointing from p along the left edge of the quad - * @param {WebGLTexture} the texture to use. - */ -bigshot.WebGLTexturedQuad = function (p, u, v, texture) { - this.p = p; - this.u = u; - this.v = v; - this.texture = texture; -} - -bigshot.WebGLTexturedQuad.prototype = { - - /** - * Renders the quad using the given {@link bigshot.WebGL} instance. - * Currently creates, fills, draws with and then deletes three buffers - - * not very efficient, but works. - * - * @param {bigshot.WebGL} webGl the WebGL wrapper instance to use for rendering. - */ - render : function (webGl, vertexPositionBuffer, textureCoordBuffer, vertexIndexBuffer) { - webGl.gl.bindBuffer(webGl.gl.ARRAY_BUFFER, vertexPositionBuffer); - var vertices = [ - this.p.x, this.p.y, this.p.z, - this.p.x + this.u.x, this.p.y + this.u.y, this.p.z + this.u.z, - this.p.x + this.u.x + this.v.x, this.p.y + this.u.y + this.v.y, this.p.z + this.u.z + this.v.z, - this.p.x + this.v.x, this.p.y + this.v.y, this.p.z + this.v.z - ]; - webGl.gl.bufferData(webGl.gl.ARRAY_BUFFER, new Float32Array (vertices), webGl.gl.STATIC_DRAW); - - webGl.gl.activeTexture(webGl.gl.TEXTURE0); - webGl.gl.bindTexture(webGl.gl.TEXTURE_2D, this.texture); - webGl.gl.uniform1i(webGl.shaderProgram.samplerUniform, 0); - - webGl.gl.bindBuffer(webGl.gl.ELEMENT_ARRAY_BUFFER, vertexIndexBuffer); - webGl.gl.drawElements(webGl.gl.TRIANGLES, 6, webGl.gl.UNSIGNED_SHORT, 0); - - webGl.gl.bindTexture(webGl.gl.TEXTURE_2D, null); - } -} -/* - * Copyright 2010 - 2012 Leo Sutic - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -/** - * Creates a textured quad scene. - * - * @param {bigshot.WebGL} webGl the webGl instance to use for rendering. - * - * @class A "scene" consisting of a number of quads, all with - * a unique texture. Used by the {@link bigshot.VRPanorama} to render the VR cube. - * - * @see bigshot.WebGLTexturedQuad - */ -bigshot.WebGLTexturedQuadScene = function (webGl, buffers) { - this.quads = new Array (); - this.webGl = webGl; - this.buffers = buffers; -} - -bigshot.WebGLTexturedQuadScene.prototype = { - /** - * Adds a new quad to the scene. - */ - addQuad : function (quad) { - this.quads.push (quad); - }, - - /** - * Renders all quads. - */ - render : function () { - var b = this.buffers.get (); - var vertexPositionBuffer = b.vertexPositionBuffer; - var textureCoordBuffer = b.textureCoordBuffer; - var vertexIndexBuffer = b.vertexIndexBuffer; - - this.webGl.setMatrixUniforms(); - - for (var i = 0; i < this.quads.length; ++i) { - this.quads[i].render (this.webGl, vertexPositionBuffer, textureCoordBuffer, vertexIndexBuffer); - } - } -}; -/* - * Copyright 2010 - 2012 Leo Sutic - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -/** - * Creates a new VR panorama parameter object and populates it with default values for - * all values not explicitly given. - * - * @class VRPanoramaParameters parameter object. - * You need not set any fields that can be read from the image descriptor that - * MakeImagePyramid creates. See the {@link bigshot.VRPanorama} - * documentation for required parameters. - * - *

Usage: - * - * @example - * var bvr = new bigshot.VRPanorama ( - * new bigshot.VRPanoramaParameters ({ - * basePath : "/bigshot.php?file=myvr.bigshot", - * fileSystemType : "archive", - * container : document.getElementById ("bigshot_canvas") - * })); - * @param values named parameter map, see the fields below for parameter names and types. - * @see bigshot.VRPanorama - */ -bigshot.VRPanoramaParameters = function (values) { - /** - * Size of low resolution preview image along the longest image - * dimension. The preview is assumed to have the same aspect - * ratio as the full image (specified by width and height). - * - * @default Optional set by MakeImagePyramid and loaded from descriptor - * @type int - * @public - */ - this.posterSize = 0; - - /** - * Url for the image tile to show while the tile is loading and no - * low-resolution preview is available. - * - * @default null, which results in an all-black image - * @type String - * @public - */ - this.emptyImage = null; - - /** - * Suffix to append to the tile filenames. Typically ".jpg" or - * ".png". - * - * @default Optional set by MakeImagePyramid and loaded from descriptor - * @type String - */ - this.suffix = null; - - /** - * The width of the full image; in pixels. - * - * @default Optional set by MakeImagePyramid and loaded from descriptor - * @type int - */ - this.width = 0; - - /** - * The height of the full image; in pixels. - * - * @default Optional set by MakeImagePyramid and loaded from descriptor - * @type int - */ - this.height = 0; - - /** - * For {@link bigshot.VRPanorama}, the {@code div} to render into. - * - * @type HTMLDivElement - */ - this.container = null; - - /** - * The maximum number of times to split a cube face into four quads. - * - * @type int - * @default Optional set by MakeImagePyramid and loaded from descriptor - */ - this.maxTesselation = -1; - - /** - * Size of one tile in pixels. - * - * @type int - * @default Optional set by MakeImagePyramid and loaded from descriptor - */ - this.tileSize = 0; - - /** - * Tile overlap. Not implemented. - * - * @type int - * @default Optional set by MakeImagePyramid and loaded from descriptor - */ - this.overlap = 0; - - /** - * Base path for the image. This is filesystem dependent; but for the two most common cases - * the following should be set - * - *

    - *
  • archive= The basePath is "<path>/bigshot.php?file=<path-to-bigshot-archive-relative-to-bigshot.php>"; - * for example; "/bigshot.php?file=images/bigshot-sample.bigshot". - *
  • folder= The basePath is "<path-to-image-folder>"; - * for example; "/images/bigshot-sample". - *
- * - * @type String - */ - this.basePath = null; - - /** - * The file system type. Used to create a filesystem instance unless - * the fileSystem field is set. Possible values are "archive", - * "folder" or "dzi". - * - * @type String - * @default "folder" - */ - this.fileSystemType = "folder"; - - /** - * A reference to a filesystem implementation. If set; it overrides the - * fileSystemType field. - * - * @default set depending on value of bigshot.VRPanoramaParameters#fileSystemType - * @type bigshot.FileSystem - */ - this.fileSystem = null; - - /** - * Object used to load data files. - * - * @default bigshot.DefaultDataLoader - * @type bigshot.DataLoader - */ - this.dataLoader = new bigshot.DefaultDataLoader (); - - /** - * The maximum magnification for the texture tiles making up the VR cube. - * Used for level-of-detail tesselation. - * A value of 1.0 means that textures will never be stretched (one texture pixel will - * always be at most one screen pixel), unless there is no more detailed texture available. - * A value of 2.0 means that textures may be stretched at most 2x (one texture pixel - * will always be at most 2x2 screen pixels) - * The bigger the value, the less texture data is required, but quality suffers. - * - * @type number - * @default 1.0 - */ - this.maxTextureMagnification = 1.0; - - /** - * The WebGL texture filter to use for magnifying textures. - * Possible values are all values valid for TEXTURE_MAG_FILTER. - * null means NEAREST. - * - * @default null / NEAREST. - */ - this.textureMagFilter = null; - - /** - * The WebGL texture filter to use for supersampling (minifying) textures. - * Possible values are all values valid for TEXTURE_MIN_FILTER. - * null means NEAREST. - * - * @default null / NEAREST. - */ - this.textureMinFilter = null; - - /** - * Minimum vertical field of view in degrees. - * - * @default 2.0 - * @type number - */ - this.minFov = 2.0; - - /** - * Maximum vertical field of view in degrees. - * - * @default 90.0 - * @type number - */ - this.maxFov = 90; - - /** - * Minimum pitch in degrees. - * - * @default -90 - * @type number - */ - this.minPitch = -90; - - /** - * Maximum pitch in degrees. - * - * @default 90.0 - * @type number - */ - this.maxPitch = 90; - - /** - * Minimum yaw in degrees. The number is interpreted modulo 360. - * The default value, -360, is just to make sure that we won't accidentally - * trip it. If the number is set to something in the interval 0-360, - * the autoRotate function will pan back and forth. - * - * @default -360 - * @type number - */ - this.minYaw = -360; - - /** - * Maximum yaw in degrees. The number is interpreted modulo 360. - * The default value, 720, is just to make sure that we won't accidentally - * trip it. If the number is set to something in the interval 0-360, - * the autoRotate function will pan back and forth. - * - * @default 720.0 - * @type number - */ - this.maxYaw = 720; - - /** - * Transform offset for yaw. - * @default 0.0 - * @type number - */ - this.yawOffset = 0.0; - - /** - * Transform offset for pitch. - * @default 0.0 - * @type number - */ - this.pitchOffset = 0.0; - - /** - * Transform offset for roll. - * @default 0.0 - * @type number - */ - this.rollOffset = 0.0; - - /** - * Function to call when all six cube faces have loaded the base texture level - * and can be rendered. - * - * @type function() - * @default null - */ - this.onload = null; - - /** - * The rendering back end to use. - * Values are "css" and "webgl". - * - * @type String - * @default null - */ - this.renderer = null; - - /** - * Controls whether the panorama can be "flung" by quickly dragging and releasing. - * - * @type boolean - * @default true - */ - this.fling = true; - - /** - * Controls the decay of the "flinging" animation. The fling animation decays - * as 2^(-flingScale * t) where t is the time in milliseconds since the animation started. - * For the animation to decay to half-speed in X seconds, - * flingScale should then be set to 1 / (X*1000). - * - * @type float - * @default 0.004 - */ - this.flingScale = 0.004; - - if (values) { - for (var k in values) { - this[k] = values[k]; - } - } - - this.merge = function (values, overwrite) { - for (var k in values) { - if (overwrite || !this[k]) { - this[k] = values[k]; - } - } - } - return this; -}; -/* - * Copyright 2010 - 2012 Leo Sutic - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -/** - * Creates a new VR panorama in a canvas. Requires WebGL or CSS3D support. - * (Note: See {@link bigshot.VRPanorama#dispose} for important information.) - * - *

Creating a Cube Map

- * - *

The panorama consists of six image pyramids, one for each face of the VR cube. - * Due to restrictions in WebGL, each texture tile must have a power-of-two (POT) size - - * that is, 2, 4, ..., 128, 256, etc. Furthermore, due to the way the faces are tesselated - * the largest image must consist of POT x POT tiles. The final restriction is that the - * tiles must overlap for good seamless results. - * - *

The MakeImagePyramid has some sensible defaults built-in. If you just use the - * command line: - * - *

- * java -jar bigshot.jar input.jpg temp/dzi \
- *     --preset dzi-cubemap \ 
- *     --format folders
- * 
- * - *

You will get 2034 pixels per face, and a tile size of 256 pixels with 2 pixels - * overlap. If you don't like that, you can use the overlap, face-size - * and tile-size parameters. Let's take these one by one: - * - *

    - *
  • overlap: Overlap defines how much tiles should overlap, just to avoid - * seams in the rendered results caused by finite numeric precision. The default is 2, which - * I've found works great for me.

  • - *
  • tile-size: First you need to decide what POT size the output should be. - * Then subtract the overlap value. For example, if you set overlap to 1, tile-size - * could be 127, 255, 511, or any 2n-1 value.

  • - *
  • face-size: Finally, we decide on a size for the full cube face. This should be - * tile-size * 2n. Let's say we set n=3, which makes each face 8x8 tiles at the most zoomed-in - * level. For a tile-size of 255, then, face-size is 255*23 = 255*8 = 2040.

  • - *
- * - *

A command line for the hypothetical scenario above would be: - * - *

- * java -jar bigshot.jar input.jpg temp/dzi \
- *     --preset dzi-cubemap \ 
- *     --overlap 1 \
- *     --tile-size 255 \
- *     --face-size 2040 \
- *     --format folders
- * 
- * - *

If your tile size numbers don't add up, you'll get a warning like: - * - *

- * WARNING: Resulting image tile size (tile-size + overlap) is not a power of two: 255
- * 
- * - *

If your face size don't add up, you'll get another warning: - * - *

- * WARNING: face-size is not an even multiple of tile-size: 2040 % 254 != 0
- * 
- * - *

Integration With SaladoPlayer

- * - *

SaladoPlayer is a cool - * Flash-based VR panorama viewer that can display Deep Zoom Images. - * It can be used as a fallback for Bigshot for browsers that don't - * support WebGL. - * - *

Since Bigshot can use a Deep Zoom Image (DZI) via a {@link bigshot.DeepZoomImageFileSystem} - * adapter, the common file format is DZI. There are two cases: The first is - * when the DZI is served up as a folder structure, the second when - * we pack the DZI into a Bigshot archive and serve it using bigshot.php. - * - *

Serving DZI as Folders

- * - *

This is an easy one. First, we generate the required DZIs: - * - *

- * java -jar bigshot.jar input.jpg temp/dzi \
- *     --preset dzi-cubemap \ 
- *     --format folders
- * 
- * - *

We'll assume that we have the six DZI folders in "temp/dzi", and that - * they have "face_" as a common prefix (which is what Bigshot's MakeImagePyramid - * outputs). So we have, for example, "temp/dzi/face_f.xml" and the tiles for face_f - * in "temp/dzi/face_f/". Set up Bigshot like this: - * - *

- * bvr = new bigshot.VRPanorama (
- *     new bigshot.VRPanoramaParameters ({
- *             container : document.getElementById ("canvas"),
- *             basePath : "temp/dzi",
- *             fileSystemType : "dzi"
- *         }));
- * 
- * - *

SaladoPlayer uses an XML config file, which in this case will - * look something like this: - * - *

- * <SaladoPlayer>
- *     <global debug="false" firstPanorama="pano"/>
- *     <panoramas>
- *         <panorama id="pano" path="temp/dzi/face_f.xml"/>
- *     </panoramas>
- * </SaladoPlayer>
- * 
- * - *

Serving DZI as Archive

- * - *

This one is a bit more difficult. First we create a DZI as a bigshot archive: - * - *

- * java -jar bigshot.jar input.jpg temp/dzi.bigshot \
- *     --preset dzi-cubemap \ 
- *     --format archive
- * 
- * - *

We'll assume that we have our Bigshot archive at - * "temp/dzi.bigshot". For this we will use the "entry" parameter of bigshot.php - * to serve up the right files: - * - *

- * bvr = new bigshot.VRPanorama (
- *     new bigshot.VRPanoramaParameters ({
- *             container : document.getElementById ("canvas"),
- *             basePath : "/bigshot.php?file=temp/dzi.bigshot&entry=",
- *             fileSystemType : "dzi"
- *         }));
- * 
- * - *

SaladoPlayer uses an XML config file, which in this case will - * look something like this: - * - *

- * <SaladoPlayer>
- *     <global debug="false" firstPanorama="pano"/>
- *     <panoramas>
- *         <panorama id="pano" path="/bigshot.php?file=dzi.bigshot&amp;entry=face_f.xml"/>
- *     </panoramas>
- * </SaladoPlayer>
- * 
- * - *

Usage example:

- * @example - * var bvr = new bigshot.VRPanorama ( - * new bigshot.VRPanoramaParameters ({ - * basePath : "/bigshot.php?file=myvr.bigshot", - * fileSystemType : "archive", - * container : document.getElementById ("bigshot_canvas") - * })); - * @class A cube-map VR panorama. - * @extends bigshot.EventDispatcher - * - * @param {bigshot.VRPanoramaParameters} parameters the panorama parameters. - * - * @see bigshot.VRPanoramaParameters - */ -bigshot.VRPanorama = function (parameters) { - bigshot.EventDispatcher.call (this); - - var that = this; - - this.parameters = parameters; - this.maxTextureMagnification = parameters.maxTextureMagnification; - this.container = parameters.container; - this.browser = new bigshot.Browser (); - this.dragStart = null; - this.dragDistance = 0; - this.hotspots = []; - this.disposed = false; - - this.transformOffsets = { - y : parameters.yawOffset, - p : parameters.pitchOffset, - r : parameters.rollOffset - }; - - /** - * Current camera state. - * @private - */ - this.state = { - rotation : { - /** - * Pitch in degrees. - * @type float - * @private - */ - p : 0.0, - - /** - * Yaw in degrees. - * @type float - * @private - */ - y : 0.0, - - r : 0 - }, - - /** - * Field of view (vertical) in degrees. - * @type float - * @private - */ - fov : 45, - - translation : { - /** - * Translation along X-axis. - * @private - * @type float - */ - x : 0.0, - - /** - * Translation along Y-axis. - * @private - * @type float - */ - y : 0.0, - - /** - * Translation along Z-axis. - * @private - * @type float - */ - z : 0.0 - } - }; - - /** - * Renderer wrapper. - * @private - * @type bigshot.VRRenderer - */ - this.renderer = null; - if (this.parameters.renderer) { - if (this.parameters.renderer == "css") { - this.renderer = new bigshot.CSS3DVRRenderer (this.container); - } else if (this.parameters.renderer == "webgl") { - this.renderer = new bigshot.WebGLVRRenderer (this.container) - } else { - throw new Error ("Unknown renderer: " + this.parameters.renderer); - } - } else { - this.renderer = - bigshot.WebGLUtil.isWebGLSupported () ? - new bigshot.WebGLVRRenderer (this.container) - : - new bigshot.CSS3DVRRenderer (this.container); - } - - /** - * List of render listeners to call at the start and end of each render. - * - * @private - */ - this.renderListeners = new Array (); - - this.renderables = new Array (); - - /** - * Current value of the idle counter. - * - * @private - */ - this.idleCounter = 0; - - /** - * Maximum value of the idle counter before any idle events start, - * such as autorotation. - * - * @private - */ - this.maxIdleCounter = -1; - - - /** - * Integer acting as a "permit". When the smoothRotate function - * is called, the current value is incremented and saved. If the number changes - * that particular call to smoothRotate stops. This way we avoid - * having multiple smoothRotate rotations going in parallel. - * @private - * @type int - */ - this.smoothrotatePermit = 0; - - /** - * Helper function to consume events. - * @private - */ - var consumeEvent = function (event) { - if (event.preventDefault) { - event.preventDefault (); - } - return false; - }; - - /** - * Full screen handler. - * - * @private - */ - this.fullScreenHandler = null; - - this.renderAsapPermitTaken = false; - - /** - * An element to use as reference when resizing the canvas element. - * If non-null, any onresize() calls will result in the canvas being - * resized to the size of this element. - * - * @private - */ - this.sizeContainer = null; - - /** - * The six cube faces. - * - * @type bigshot.VRFace[] - * @private - */ - var facesInit = { - facesLeft : 6, - faceLoaded : function () { - this.facesLeft--; - if (this.facesLeft == 0) { - if (that.parameters.onload) { - that.parameters.onload (); - } - } - } - }; - var onFaceLoad = function () { - facesInit.faceLoaded () - }; - - this.vrFaces = new Array (); - this.vrFaces[0] = new bigshot.VRFace (this, "f", {x:-1, y:1, z:-1}, 2.0, {x:1, y:0, z:0}, {x:0, y:-1, z:0}, onFaceLoad); - this.vrFaces[1] = new bigshot.VRFace (this, "b", {x:1, y:1, z:1}, 2.0, {x:-1, y:0, z:0}, {x:0, y:-1, z:0}, onFaceLoad); - this.vrFaces[2] = new bigshot.VRFace (this, "l", {x:-1, y:1, z:1}, 2.0, {x:0, y:0, z:-1}, {x:0, y:-1, z:0}, onFaceLoad); - this.vrFaces[3] = new bigshot.VRFace (this, "r", {x:1, y:1, z:-1}, 2.0, {x:0, y:0, z:1}, {x:0, y:-1, z:0}, onFaceLoad); - this.vrFaces[4] = new bigshot.VRFace (this, "u", {x:-1, y:1, z:1}, 2.0, {x:1, y:0, z:0}, {x:0, y:0, z:-1}, onFaceLoad); - this.vrFaces[5] = new bigshot.VRFace (this, "d", {x:-1, y:-1, z:-1}, 2.0, {x:1, y:0, z:0}, {x:0, y:0, z:1}, onFaceLoad); - - /** - * Helper function to translate touch events to mouse-like events. - * @private - */ - var translateEvent = function (event) { - if (event.clientX) { - return event; - } else { - return { - clientX : event.changedTouches[0].clientX, - clientY : event.changedTouches[0].clientY - }; - }; - }; - - this.lastTouchStartAt = -1; - - this.allListeners = { - "mousedown" : function (e) { - that.smoothRotate (); - that.resetIdle (); - that.dragMouseDown (e); - return consumeEvent (e); - }, - "mouseup" : function (e) { - that.resetIdle (); - that.dragMouseUp (e); - return consumeEvent (e); - }, - "mousemove" : function (e) { - that.resetIdle (); - that.dragMouseMove (e); - return consumeEvent (e); - }, - "gesturestart" : function (e) { - that.gestureStart (e); - return consumeEvent (e); - }, - "gesturechange" : function (e) { - that.gestureChange (e); - return consumeEvent (e); - }, - "gestureend" : function (e) { - that.gestureEnd (e); - return consumeEvent (e); - }, - - "DOMMouseScroll" : function (e) { - that.resetIdle (); - that.mouseWheel (e); - return consumeEvent (e); - }, - "mousewheel" : function (e) { - that.resetIdle (); - that.mouseWheel (e); - return consumeEvent (e); - }, - "dblclick" : function (e) { - that.mouseDoubleClick (e); - return consumeEvent (e); - }, - - "touchstart" : function (e) { - that.smoothRotate (); - that.lastTouchStartAt = new Date ().getTime (); - that.resetIdle (); - that.dragMouseDown (translateEvent (e)); - return consumeEvent (e); - }, - "touchend" : function (e) { - that.resetIdle (); - var handled = that.dragMouseUp (translateEvent (e)); - if (!handled && (that.lastTouchStartAt > new Date().getTime() - 350)) { - that.mouseDoubleClick (translateEvent (e)); - } - that.lastTouchStartAt = -1; - return consumeEvent (e); - }, - "touchmove" : function (e) { - if (that.dragDistance > 24) { - that.lastTouchStartAt = -1; - } - that.resetIdle (); - that.dragMouseMove (translateEvent (e)); - return consumeEvent (e); - } - }; - this.addEventListeners (); - - /** - * Stub function to call onresize on this instance. - * - * @private - */ - this.onresizeHandler = function (e) { - that.onresize (); - }; - - this.browser.registerListener (window, 'resize', this.onresizeHandler, false); - this.browser.registerListener (document.body, 'orientationchange', this.onresizeHandler, false); - - this.setPitch (0.0); - this.setYaw (0.0); - this.setFov (45.0); -} - -/* - * Statics - */ - -/** - * When the mouse is pressed and dragged, the camera rotates - * proportionally to the length of the dragging. - * - * @constant - * @public - * @static - */ -bigshot.VRPanorama.DRAG_GRAB = "grab"; - -/** - * When the mouse is pressed and dragged, the camera continuously - * rotates with a speed that is proportional to the length of the - * dragging. - * - * @constant - * @public - * @static - */ -bigshot.VRPanorama.DRAG_PAN = "pan"; - -/** - * @name bigshot.VRPanorama.RenderState - * @class The state the renderer is in when a {@link bigshot.VRPanorama.RenderListener} is called. - * - * @see bigshot.VRPanorama.ONRENDER_BEGIN - * @see bigshot.VRPanorama.ONRENDER_END - */ - -/** - * A RenderListener state parameter value used at the start of each render. - * - * @constant - * @public - * @static - * @type bigshot.VRPanorama.RenderState - */ -bigshot.VRPanorama.ONRENDER_BEGIN = 0; - -/** - * A RenderListener state parameter value used at the end of each render. - * - * @constant - * @public - * @static - * @type bigshot.VRPanorama.RenderState - */ -bigshot.VRPanorama.ONRENDER_END = 1; - -/** - * A RenderListener cause parameter indicating that a previously requested - * texture has loaded and a render is forced. The data parameter is not used. - * - * @constant - * @public - * @static - * @param {bigshot.VRPanorama.RenderCause} - */ -bigshot.VRPanorama.ONRENDER_TEXTURE_UPDATE = 0; - -/** - * @name bigshot.VRPanorama.RenderCause - * @class The reason why the {@link bigshot.VRPanorama} is being rendered. - * Due to the events outside of the panorama, the VR panorama may be forced to - * re-render itself. When this happens, the {@link bigshot.VRPanorama.RenderListener}s - * receive a constant indicating the cause of the rendering. - * - * @see bigshot.VRPanorama.ONRENDER_TEXTURE_UPDATE - */ - -/** - * Specification for functions passed to {@link bigshot.VRPanorama#addRenderListener}. - * - * @name bigshot.VRPanorama.RenderListener - * @function - * @param {bigshot.VRPanorama.RenderState} state The state of the renderer. Can be {@link bigshot.VRPanorama.ONRENDER_BEGIN} or {@link bigshot.VRPanorama.ONRENDER_END} - * @param {bigshot.VRPanorama.RenderCause} [cause] The reason for rendering the scene. Can be undefined or {@link bigshot.VRPanorama.ONRENDER_TEXTURE_UPDATE} - * @param {Object} [data] An optional data object that is dependent on the cause. See the documentation - * for the different causes. - */ - -/** - * Specification for functions passed to {@link bigshot.VRPanorama#addRenderable}. - * - * @name bigshot.VRPanorama.Renderable - * @function - * @param {bigshot.VRRenderer} renderer The renderer object to use. - * @param {bigshot.TexturedQuadScene} scene The scene to render into. - */ - -/** */ -bigshot.VRPanorama.prototype = { - /** - * Adds a hotstpot. - * - * @param {bigshot.VRHotspot} hs the hotspot to add - */ - addHotspot : function (hs) { - this.hotspots.push (hs); - }, - - /** - * Returns the {@link bigshot.VRPanoramaParameters} object used by this instance. - * - * @type bigshot.VRPanoramaParameters - */ - getParameters : function () { - return this.parameters; - }, - - /** - * Sets the view translation. - * - * @param x translation of the viewer along the X axis - * @param y translation of the viewer along the Y axis - * @param z translation of the viewer along the Z axis - */ - setTranslation : function (x, y, z) { - this.state.translation.x = x; - this.state.translation.y = y; - this.state.translation.z = z; - }, - - /** - * Returns the current view translation as an x-y-z triplet. - * - * @returns {number} x translation of the viewer along the X axis - * @returns {number} y translation of the viewer along the Y axis - * @returns {number} z translation of the viewer along the Z axis - */ - getTranslation : function () { - return this.state.translation; - }, - - /** - * Sets the field of view. - * - * @param {number} fov the vertical field of view, in degrees - */ - setFov : function (fov) { - fov = Math.min (this.parameters.maxFov, fov); - fov = Math.max (this.parameters.minFov, fov); - this.state.fov = fov; - }, - - /** - * Gets the field of view. - * - * @return {number} the vertical field of view, in degrees - */ - getFov : function () { - return this.state.fov; - }, - - /** - * Returns the angle (yaw, pitch) for a given pixel coordinate. - * - * @param {number} x the x-coordinate of the pixel, measured in pixels - * from the left edge of the panorama. - * @param {number} y the y-coordinate of the pixel, measured in pixels - * from the top edge of the panorama. - * @return {number} .yaw the yaw angle of the pixel (0 <= yaw < 360) - * @return {number} .pitch the pitch angle of the pixel (-180 <= pitch <= 180) - * - * @example - * var container = ...; // an HTML element - * var pano = ...; // a bigshot.VRPanorama - * ... - * container.addEventListener ("click", function (e) { - * var clickX = e.clientX - container.offsetX; - * var clickY = e.clientY - container.offsetY; - * var polar = pano.screenToPolar (clickX, clickY); - * alert ("You clicked at: " + - * "Yaw: " + polar.yaw + - * " Pitch: " + polar.pitch); - * }); - */ - screenToPolar : function (x, y) { - var dray = this.screenToRayDelta (x, y); - var ray = $V([dray.x, dray.y, dray.z, 1.0]); - - ray = Matrix.RotationX (this.getPitch () * Math.PI / 180.0).ensure4x4 ().x (ray); - ray = Matrix.RotationY (-this.getYaw () * Math.PI / 180.0).ensure4x4 ().x (ray); - - var dx = ray.e(1); - var dy = ray.e(2); - var dz = ray.e(3); - - var dxz = Math.sqrt (dx * dx + dz * dz); - - var dyaw = Math.atan2 (dx, -dz) * 180 / Math.PI; - var dpitch = Math.atan2 (dy, dxz) * 180 / Math.PI; - - var res = {}; - res.yaw = (dyaw + 360) % 360.0; - res.pitch = dpitch; - - return res; - }, - - /** - * Restricts the pitch value to be between the minPitch and maxPitch parameters. - * - * @param {number} p the pitch value - * @returns the constrained pitch value. - */ - snapPitch : function (p) { - p = Math.min (this.parameters.maxPitch, p); - p = Math.max (this.parameters.minPitch, p); - return p; - }, - - /** - * Sets the current camera pitch. - * - * @param {number} p the pitch, in degrees - */ - setPitch : function (p) { - this.state.rotation.p = this.snapPitch (p); - }, - - /** - * Subtraction mod 360, sort of... - * - * @private - * @returns the angular distance with smallest magnitude to add to p0 to get to p1 % 360 - */ - circleDistance : function (p0, p1) { - if (p1 > p0) { - // p1 is somewhere clockwise to p0 - var d1 = (p1 - p0); // move clockwise - var d2 = ((p1 - 360) - p0); // move counterclockwise, first -p0 to get to 0, then p1 - 360. - return Math.abs (d1) < Math.abs (d2) ? d1 : d2; - } else { - // p1 is somewhere counterclockwise to p0 - var d1 = (p1 - p0); // move counterclockwise - var d2 = (360 - p0) + p1; // move clockwise, first (360-p= to get to 0, then another p1 degrees - return Math.abs (d1) < Math.abs (d2) ? d1 : d2; - } - }, - - /** - * Subtraction mod 360, sort of... - * - * @private - */ - circleSnapTo : function (p, p1, p2) { - var d1 = this.circleDistance (p, p1); - var d2 = this.circleDistance (p, p2); - return Math.abs (d1) < Math.abs (d2) ? p1 : p2; - }, - - /** - * Constrains a yaw value to the required minimum and maximum values. - * - * @private - */ - snapYaw : function (y) { - y %= 360; - if (y < 0) { - y += 360; - } - if (this.parameters.minYaw < this.parameters.maxYaw) { - if (y > this.parameters.maxYaw || y < this.parameters.minYaw) { - y = circleSnapTo (y, this.parameters.minYaw, this.parameters.maxYaw); - } - } else { - // The only time when minYaw > maxYaw is when the interval - // contains the 0 angle. - if (y > this.parameters.minYaw) { - // ok, we're somewhere between minYaw and 0.0 - } else if (y > this.parameters.maxYaw) { - // we're somewhere between maxYaw and minYaw - // (but on the wrong side). - // figure out the nearest point and snap to it - y = circleSnapTo (y, this.parameters.minYaw, this.parameters.maxYaw); - } else { - // ok, we're somewhere between 0.0 and maxYaw - } - } - return y; - }, - - /** - * Sets the current camera yaw. The yaw is normalized between - * 0 <= y < 360. - * - * @param {number} y the yaw, in degrees - */ - setYaw : function (y) { - this.state.rotation.y = this.snapYaw (y); - }, - - /** - * Gets the current camera yaw. - * - * @return {number} the yaw, in degrees - */ - getYaw : function () { - return this.state.rotation.y; - }, - - /** - * Gets the current camera pitch. - * - * @return {number} the pitch, in degrees - */ - getPitch : function () { - return this.state.rotation.p; - }, - - /** - * Unregisters event handlers and other page-level hooks. The client need not call this - * method unless bigshot images are created and removed from the page - * dynamically. In that case, this method must be called when the client wishes to - * free the resources allocated by the image. Otherwise the browser will garbage-collect - * all resources automatically. - * @public - */ - dispose : function () { - this.disposed = true; - this.browser.unregisterListener (window, "resize", this.onresizeHandler, false); - this.browser.unregisterListener (document.body, "orientationchange", this.onresizeHandler, false); - this.removeEventListeners (); - - for (var i = 0; i < this.vrFaces.length; ++i) { - this.vrFaces[i].dispose (); - } - this.renderer.dispose (); - }, - - /** - * Creates and initializes a {@link bigshot.VREvent} object. - * The {@link bigshot.VREvent#ray}, {@link bigshot.VREvent#yaw}, - * {@link bigshot.VREvent#pitch}, {@link bigshot.Event#target} and - * {@link bigshot.Event#currentTarget} fields are set. - * - * @param {Object} data the data object for the event - * @param {number} data.clientX the client x-coordinate of the event - * @param {number} data.clientY the client y-coordinate of the event - * @returns the new event object - * @type bigshot.VREvent - */ - createVREventData : function (data) { - var elementPos = this.browser.getElementPosition (this.container); - data.localX = data.clientX - elementPos.x; - data.localY = data.clientY - elementPos.y; - - data.ray = this.screenToRay (data.localX, data.localY); - - var polar = this.screenToPolar (data.localX, data.localY); - data.yaw = polar.yaw; - data.pitch = polar.pitch; - data.target = this; - data.currentTarget = this; - - return new bigshot.VREvent (data); - }, - - - /** - * Sets up transformation matrices etc. Calls all render listeners with a state parameter - * of {@link bigshot.VRPanorama.ONRENDER_BEGIN}. - * - * @private - * - * @param [cause] parameter for the {@link bigshot.VRPanorama.RenderListener}s. - * @param [data] parameter for the {@link bigshot.VRPanorama.RenderListener}s. - */ - beginRender : function (cause, data) { - this.onrender (bigshot.VRPanorama.ONRENDER_BEGIN, cause, data); - this.renderer.beginRender (this.state.rotation, this.state.fov, this.state.translation, this.transformOffsets); - }, - - - /** - * Add a function that will be called at various times during the render. - * - * @param {bigshot.VRPanorama.RenderListener} listener the listener function - */ - addRenderListener : function (listener) { - var rl = new Array (); - rl = rl.concat (this.renderListeners); - rl.push (listener); - this.renderListeners = rl; - }, - - /** - * Removes a function that will be called at various times during the render. - * - * @param {bigshot.VRPanorama.RenderListener} listener the listener function - */ - removeRenderListener : function (listener) { - var rl = new Array (); - rl = rl.concat (this.renderListeners); - for (var i = 0; i < rl.length; ++i) { - if (rl[i] === listener) { - rl.splice (i, 1); - break; - } - } - this.renderListeners = rl; - }, - - /** - * Called at the start and end of every render. - * - * @event - * @private - * @type function() - * @param {bigshot.VRPanorama.RenderState} state the current render state - */ - onrender : function (state, cause, data) { - var rl = this.renderListeners; - for (var i = 0; i < rl.length; ++i) { - rl[i](state, cause, data); - } - }, - - /** - * Performs per-render cleanup. Calls all render listeners with a state parameter - * of {@link bigshot.VRPanorama.ONRENDER_END}. - * - * @private - * - * @param [cause] parameter for the {@link bigshot.VRPanorama.RenderListener}s. - * @param [data] parameter for the {@link bigshot.VRPanorama.RenderListener}s. - */ - endRender : function (cause, data) { - for (var f in this.vrFaces) { - this.vrFaces[f].endRender (); - } - this.renderer.endRender (); - this.onrender (bigshot.VRPanorama.ONRENDER_END, cause, data); - }, - - /** - * Add a function that will be called to render any additional quads. - * - * @param {bigshot.VRPanorama.Renderable} renderable The renderable, a function responsible for - * rendering additional scene elements. - */ - addRenderable : function (renderable) { - var rl = new Array (); - rl.concat (this.renderables); - rl.push (renderable); - this.renderables = rl; - }, - - /** - * Removes a function that will be called to render any additional quads. - * - * @param {bigshot.VRPanorama.Renderable} renderable The renderable added using - * {@link bigshot.VRPanorama#addRenderable}. - */ - removeRenderable : function (renderable) { - var rl = new Array (); - rl.concat (this.renderables); - for (var i = 0; i < rl.length; ++i) { - if (rl[i] == listener) { - rl.splice (i, 1); - break; - } - } - this.renderables = rl; - }, - - /** - * Renders the VR cube. - * - * @param [cause] parameter for the {@link bigshot.VRPanorama.RenderListener}s. - * @param [data] parameter for the {@link bigshot.VRPanorama.RenderListener}s. - */ - render : function (cause, data) { - if (!this.disposed) { - this.beginRender (cause, data); - - var scene = this.renderer.createTexturedQuadScene (); - - for (var f in this.vrFaces) { - this.vrFaces[f].render (scene); - } - - for (var i = 0; i < this.renderables.length; ++i) { - this.renderables[i](this.renderer, scene); - } - - scene.render (); - - for (var i = 0; i < this.hotspots.length; ++i) { - this.hotspots[i].layout (); - } - - this.endRender (cause, data); - } - }, - - /** - * Render updated faces. Called as tiles are loaded from the server. - * - * @param [cause] parameter for the {@link bigshot.VRPanorama.RenderListener}s. - * @param [data] parameter for the {@link bigshot.VRPanorama.RenderListener}s. - */ - renderUpdated : function (cause, data) { - if (!this.disposed && this.renderer.supportsUpdate ()) { - this.beginRender (cause, data); - - var scene = this.renderer.createTexturedQuadScene (); - - for (var f in this.vrFaces) { - if (this.vrFaces[f].isUpdated ()) { - this.vrFaces[f].render (scene); - } - } - - scene.render (); - - for (var i = 0; i < this.hotspots.length; ++i) { - this.hotspots[i].layout (); - } - - this.endRender (cause, data); - } else { - this.render (cause, data); - } - }, - - /** - * The current drag mode. - * - * @private - */ - dragMode : bigshot.VRPanorama.DRAG_GRAB, - - /** - * Sets the mouse dragging mode. - * - * @param mode one of {@link bigshot.VRPanorama.DRAG_PAN} or {@link bigshot.VRPanorama.DRAG_GRAB}. - */ - setDragMode : function (mode) { - this.dragMode = mode; - }, - - addEventListeners : function () { - for (var k in this.allListeners) { - this.browser.registerListener (this.container, k, this.allListeners[k], false); - } - }, - - removeEventListeners : function () { - for (var k in this.allListeners) { - this.browser.unregisterListener (this.container, k, this.allListeners[k], false); - } - }, - - dragMouseDown : function (e) { - this.dragStart = { - clientX : e.clientX, - clientY : e.clientY - }; - this.dragLast = { - clientX : e.clientX, - clientY : e.clientY, - dx : 0, - dy : 0, - dt : 1000000, - time : new Date ().getTime () - }; - this.dragDistance = 0; - }, - - dragMouseUp : function (e) { - // In case we got a mouse up with out a previous mouse down, - // for example, double-click on title bar to maximize the - // window - if (this.dragStart == null || this.dragLast == null) { - this.dragStart = null; - this.dragLast = null; - return; - } - - this.dragStart = null; - var dx = this.dragLast.dx; - var dy = this.dragLast.dy; - var ds = Math.sqrt (dx * dx + dy * dy); - var dt = this.dragLast.dt; - var dtb = new Date ().getTime () - this.dragLast.time; - this.dragLast = null; - - var v = dt > 0 ? (ds / dt) : 0; - if (v > 0.05 && dtb < 250 && dt > 20 && this.parameters.fling) { - var scale = this.state.fov / this.renderer.getViewportHeight (); - - var t0 = new Date ().getTime (); - - var flingScale = this.parameters.flingScale; - - dx /= dt; - dy /= dt; - - this.smoothRotate (function (dat) { - var dt = new Date ().getTime () - t0; - var fact = Math.pow (2, -dt * flingScale); - var d = (dx * dat * scale) * fact; - return fact > 0.01 ? d : null; - }, function (dat) { - var dt = new Date ().getTime () - t0; - var fact = Math.pow (2, -dt * flingScale); - var d = (dy * dat * scale) * fact; - return fact > 0.01 ? d : null; - }, function () { - return null; - }); - return true; - } else { - this.smoothRotate (); - return false; - } - }, - - dragMouseMove : function (e) { - if (this.dragStart != null && this.currentGesture == null) { - if (this.dragMode == bigshot.VRPanorama.DRAG_GRAB) { - this.smoothRotate (); - var scale = this.state.fov / this.renderer.getViewportHeight (); - var dx = e.clientX - this.dragStart.clientX; - var dy = e.clientY - this.dragStart.clientY; - this.dragDistance += dx + dy; - this.setYaw (this.getYaw () - dx * scale); - this.setPitch (this.getPitch () - dy * scale); - this.renderAsap (); - this.dragStart = e; - var dt = new Date ().getTime () - this.dragLast.time; - if (dt > 20) { - this.dragLast = { - dx : this.dragLast.clientX - e.clientX, - dy : this.dragLast.clientY - e.clientY, - dt : dt, - clientX : e.clientX, - clientY : e.clientY, - time : new Date ().getTime () - }; - } - } else { - var scale = 0.1 * this.state.fov / this.renderer.getViewportHeight (); - var dx = e.clientX - this.dragStart.clientX; - var dy = e.clientY - this.dragStart.clientY; - this.dragDistance = dx + dy; - this.smoothRotate ( - function () { - return dx * scale; - }, - function () { - return dy * scale; - }); - } - } - }, - - onMouseDoubleClick : function (e, x, y) { - var eventData = this.createVREventData ({ - type : "dblclick", - clientX : e.clientX, - clientY : e.clientY - }); - this.fireEvent ("dblclick", eventData); - if (!eventData.defaultPrevented) { - this.smoothRotateToXY (x, y); - } - }, - - mouseDoubleClick : function (e) { - var pos = this.browser.getElementPosition (this.container); - this.onMouseDoubleClick (e, e.clientX - pos.x, e.clientY - pos.y); - }, - - /** - * Begins a potential drag event. - * - * @private - */ - gestureStart : function (event) { - this.currentGesture = { - startFov : this.getFov (), - scale : event.scale - }; - }, - - /** - * Begins a potential drag event. - * - * @private - */ - gestureEnd : function (event) { - this.currentGesture = null; - }, - - /** - * Begins a potential drag event. - * - * @private - */ - gestureChange : function (event) { - if (this.currentGesture) { - var newFov = this.currentGesture.startFov / event.scale; - this.setFov (newFov); - this.renderAsap (); - } - }, - - /** - * Sets the maximum texture magnification. - * - * @param {number} v the maximum texture magnification - * @see bigshot.VRPanoramaParameters#maxTextureMagnification - */ - setMaxTextureMagnification : function (v) { - this.maxTextureMagnification = v; - }, - - /** - * Gets the current maximum texture magnification. - * - * @type number - * @see bigshot.VRPanoramaParameters#maxTextureMagnification - */ - getMaxTextureMagnification : function () { - return this.maxTextureMagnification; - }, - - /** - * Computes the minimum field of view where the resulting image will not - * have to stretch the textures more than given by the - * {@link bigshot.VRPanoramaParameters#maxTextureMagnification} parameter. - * - * @type number - * @return the minimum FOV, below which it is necessary to stretch the - * vr cube texture more than the given {@link bigshot.VRPanoramaParameters#maxTextureMagnification} - */ - getMinFovFromViewportAndImage : function () { - var halfHeight = this.renderer.getViewportHeight () / 2; - - var minFaceHeight = this.vrFaces[0].parameters.height; - for (var i in this.vrFaces) { - minFaceHeight = Math.min (minFaceHeight, this.vrFaces[i].parameters.height); - } - - var edgeSizeY = this.maxTextureMagnification * minFaceHeight / 2; - - var wy = halfHeight / edgeSizeY; - - var mz = Math.atan (wy) * 180 / Math.PI; - - return mz * 2; - }, - - /** - * Transforms screen coordinates to a world-coordinate ray. - * @private - */ - screenToRay : function (x, y) { - var dray = this.screenToRayDelta (x, y); - var ray = this.renderer.transformToWorld (dray); - ray = Matrix.RotationY (-this.transformOffsets.y * Math.PI / 180.0).ensure4x4 ().xPoint3Dhom1 (ray); - ray = Matrix.RotationX (-this.transformOffsets.p * Math.PI / 180.0).ensure4x4 ().xPoint3Dhom1 (ray); - ray = Matrix.RotationZ (-this.transformOffsets.r * Math.PI / 180.0).ensure4x4 ().xPoint3Dhom1 (ray); - return ray; - }, - - /** - * @private - */ - screenToRayDelta : function (x, y) { - var halfHeight = this.renderer.getViewportHeight () / 2; - var halfWidth = this.renderer.getViewportWidth () / 2; - var x = (x - halfWidth); - var y = (y - halfHeight); - - var edgeSizeY = Math.tan ((this.state.fov / 2) * Math.PI / 180); - var edgeSizeX = edgeSizeY * this.renderer.getViewportWidth () / this.renderer.getViewportHeight (); - - var wx = x * edgeSizeX / halfWidth; - var wy = y * edgeSizeY / halfHeight; - var wz = -1.0; - - return { - x : wx, - y : wy, - z : wz - }; - }, - - /** - * Smoothly rotates the panorama so that the - * point given by x and y, in pixels relative to the top left corner - * of the panorama, ends up in the center of the viewport. - * - * @param {int} x the x-coordinate, in pixels from the left edge - * @param {int} y the y-coordinate, in pixels from the top edge - */ - smoothRotateToXY : function (x, y) { - var polar = this.screenToPolar (x, y); - - this.smoothRotateTo (this.snapYaw (polar.yaw), this.snapPitch (polar.pitch), this.getFov (), this.state.fov / 200); - }, - - /** - * Gives the step to take to slowly approach the - * target value. - * - * @example - * current = current + this.ease (current, target, 1.0); - * @private - */ - ease : function (current, target, speed, snapFrom) { - var easingFrom = speed * 40; - if (!snapFrom) { - snapFrom = speed / 5; - } - var ignoreFrom = speed / 1000; - - var distance = current - target; - if (distance > easingFrom) { - distance = -speed; - } else if (distance < -easingFrom) { - distance = speed; - } else if (Math.abs (distance) < snapFrom) { - distance = -distance; - } else if (Math.abs (distance) < ignoreFrom) { - distance = 0; - } else { - distance = - (speed * distance) / (easingFrom); - } - return distance; - }, - - /** - * Resets the "idle" clock. - * @private - */ - resetIdle : function () { - this.idleCounter = 0; - }, - - /** - * Idle clock. - * @private - */ - idleTick : function () { - if (this.maxIdleCounter < 0) { - return; - } - ++this.idleCounter; - if (this.idleCounter == this.maxIdleCounter) { - this.autoRotate (); - } - var that = this; - setTimeout (function () { - that.idleTick (); - }, 1000); - }, - - /** - * Sets the panorama to auto-rotate after a certain time has - * elapsed with no user interaction. Default is disabled. - * - * @param {int} delay the delay in seconds. Set to < 0 to disable - * auto-rotation when idle - */ - autoRotateWhenIdle : function (delay) { - this.maxIdleCounter = delay; - this.idleCounter = 0; - if (delay < 0) { - return; - } else if (this.maxIdleCounter > 0) { - var that = this; - setTimeout (function () { - that.idleTick (); - }, 1000); - } - }, - - /** - * Starts auto-rotation of the camera. If the yaw is constrained, - * will pan back and forth between the yaw endpoints. Call - * {@link #smoothRotate}() to stop the rotation. - */ - autoRotate : function () { - var that = this; - var scale = this.state.fov / 400; - - var speed = scale; - var dy = speed; - this.smoothRotate ( - function () { - var nextPos = that.getYaw () + dy; - if (that.parameters.minYaw < that.parameters.maxYaw) { - if (nextPos > that.parameters.maxYaw || nextPos < that.parameters.minYaw) { - dy = -dy; - } - } else { - // The only time when minYaw > maxYaw is when the interval - // contains the 0 angle. - if (nextPos > that.parameters.minYaw) { - // ok, we're somewhere between minYaw and 0.0 - } else if (nextPos > that.parameters.maxYaw) { - dy = -dy; - } else { - // ok, we're somewhere between 0.0 and maxYaw - } - } - return dy; - }, function () { - return that.ease (that.getPitch (), 0.0, speed); - }, function () { - return that.ease (that.getFov (), 45.0, 0.1); - }); - }, - - /** - * Smoothly rotates the panorama to the given state. - * - * @param {number} yaw the target yaw - * @param {number} pitch the target pitch - * @param {number} fov the target vertical field of view - * @param {number} the speed to rotate with - */ - smoothRotateTo : function (yaw, pitch, fov, speed) { - var that = this; - this.smoothRotate ( - function () { - var distance = that.circleDistance (yaw, that.getYaw ()); - var d = -that.ease (0, distance, speed); - return Math.abs (d) > 0.01 ? d : null; - }, function () { - var d = that.ease (that.getPitch (), pitch, speed); - return Math.abs (d) > 0.01 ? d : null; - }, function () { - var d = that.ease (that.getFov (), fov, speed); - return Math.abs (d) > 0.01 ? d : null; - } - ); - }, - - - /** - * Smoothly rotates the camera. If all of the dp, dy and df functions are null, stops - * any smooth rotation. - * - * @param {function()} [dy] function giving the yaw increment for the next frame - * or null if no further yaw movement is required - * @param {function()} [dp] function giving the pitch increment for the next frame - * or null if no further pitch movement is required - * @param {function()} [df] function giving the field of view (degrees) increment - * for the next frame or null if no further fov adjustment is required - */ - smoothRotate : function (dy, dp, df) { - ++this.smoothrotatePermit; - var savedPermit = this.smoothrotatePermit; - if (!dp && !dy && !df) { - return; - } - - var that = this; - var fs = { - dy : dy, - dp : dp, - df : df, - t : new Date ().getTime () - }; - var stepper = function () { - if (that.smoothrotatePermit == savedPermit) { - var now = new Date ().getTime (); - var dat = now - fs.t; - fs.t = now; - - var anyFunc = false; - if (fs.dy) { - var d = fs.dy(dat); - if (d != null) { - anyFunc = true; - that.setYaw (that.getYaw () + d); - } else { - fs.dy = null; - } - } - - if (fs.dp) { - var d = fs.dp(dat); - if (d != null) { - anyFunc = true; - that.setPitch (that.getPitch () + d); - } else { - fs.dp = null; - } - } - - if (fs.df) { - var d = fs.df(dat); - if (d != null) { - anyFunc = true; - that.setFov (that.getFov () + d); - } else { - fs.df = null; - } - } - that.render (); - if (anyFunc) { - that.browser.requestAnimationFrame (stepper, that.renderer.getElement ()); - } - } - }; - stepper (); - }, - - /** - * Translates mouse wheel events. - * @private - */ - mouseWheel : function (event){ - var delta = 0; - if (!event) /* For IE. */ - event = window.event; - if (event.wheelDelta) { /* IE/Opera. */ - delta = event.wheelDelta / 120; - /* - * In Opera 9, delta differs in sign as compared to IE. - */ - if (window.opera) - delta = -delta; - } else if (event.detail) { /* Mozilla case. */ - /* - * In Mozilla, sign of delta is different than in IE. - * Also, delta is multiple of 3. - */ - delta = -event.detail; - } - - /* - * If delta is nonzero, handle it. - * Basically, delta is now positive if wheel was scrolled up, - * and negative, if wheel was scrolled down. - */ - if (delta) { - this.mouseWheelHandler (delta); - } - - /* - * Prevent default actions caused by mouse wheel. - * That might be ugly, but we handle scrolls somehow - * anyway, so don't bother here.. - */ - if (event.preventDefault) { - event.preventDefault (); - } - event.returnValue = false; - }, - - /** - * Utility function to interpret mouse wheel events. - * @private - */ - mouseWheelHandler : function (delta) { - var that = this; - var target = null; - if (delta > 0) { - if (this.getFov () > this.parameters.minFov) { - target = this.getFov () * 0.9; - } - } - if (delta < 0) { - if (this.getFov () < this.parameters.maxFov) { - target = this.getFov () / 0.9; - } - } - if (target != null) { - this.smoothRotate (null, null, function () { - var df = (target - that.getFov ()) / 1.5; - return Math.abs (df) > 0.01 ? df : null; - }); - } - }, - - /** - * Maximizes the image to cover the browser viewport. - * The container div is removed from its parent node upon entering - * full screen mode. When leaving full screen mode, the container - * is appended to its old parent node. To avoid rearranging the - * nodes, wrap the container in an extra div. - * - *

For unknown reasons (probably security), browsers will - * not let you open a window that covers the entire screen. - * Even when specifying "fullscreen=yes", all you get is a window - * that has a title bar and only covers the desktop (not any task - * bars or the like). For now, this is the best that I can do, - * but should the situation change I'll update this to be - * full-screen-ier. - * - * @param {function()} [onClose] function that is called when the user - * exits full-screen mode - * @public - */ - fullScreen : function (onClose) { - if (this.fullScreenHandler) { - return; - } - - var message = document.createElement ("div"); - message.style.position = "absolute"; - message.style.fontSize = "16pt"; - message.style.top = "128px"; - message.style.width = "100%"; - message.style.color = "white"; - message.style.padding = "16px"; - message.style.zIndex = "9999"; - message.style.textAlign = "center"; - message.style.opacity = "0.75"; - message.innerHTML = "Press Esc to exit full screen mode."; - - var that = this; - - this.fullScreenHandler = new bigshot.FullScreen (this.container); - this.fullScreenHandler.restoreSize = this.sizeContainer == null; - - this.fullScreenHandler.addOnResize (function () { - that.onresize (); - }); - - this.fullScreenHandler.addOnClose (function () { - if (message.parentNode) { - try { - div.removeChild (message); - } catch (x) { - } - } - that.fullScreenHandler = null; - }); - - if (onClose) { - this.fullScreenHandler.addOnClose (function () { - onClose (); - }); - } - - this.removeEventListeners (); - this.fullScreenHandler.open (); - this.addEventListeners (); - // Safari compatibility - must update after entering fullscreen. - // 1s should be enough so we enter FS, but not enough for the - // user to wonder if something is wrong. - var r = function () { - that.render (); - }; - setTimeout (r, 1000); - setTimeout (r, 2000); - setTimeout (r, 3000); - - if (this.fullScreenHandler.getRootElement ()) { - this.fullScreenHandler.getRootElement ().appendChild (message); - - setTimeout (function () { - var opacity = 0.75; - var iter = function () { - opacity -= 0.02; - if (message.parentNode) { - if (opacity <= 0) { - message.style.display = "none"; - try { - div.removeChild (message); - } catch (x) {} - } else { - message.style.opacity = opacity; - setTimeout (iter, 20); - } - } - }; - setTimeout (iter, 20); - }, 3500); - } - - return function () { - that.removeEventListeners (); - that.fullScreenHandler.close (); - that.addEventListeners (); - }; - }, - - /** - * Right-sizes the canvas container. - * @private - */ - onresize : function () { - if (this.fullScreenHandler == null || !this.fullScreenHandler.isFullScreen) { - if (this.sizeContainer) { - var s = this.browser.getElementSize (this.sizeContainer); - this.renderer.resize (s.w, s.h); - } - } else { - this.container.style.width = window.innerWidth + "px"; - this.container.style.height = window.innerHeight + "px"; - var s = this.browser.getElementSize (this.container); - this.renderer.resize (s.w, s.h); - } - this.renderer.onresize (); - this.renderAsap (); - }, - - /** - * Posts a render() call via a timeout or the requestAnimationFrame API. - * Use when the render call must be done as soon as possible, but - * can't be done in the current call context. - */ - renderAsap : function () { - if (!this.renderAsapPermitTaken && !this.disposed) { - this.renderAsapPermitTaken = true; - var that = this; - this.browser.requestAnimationFrame (function () { - that.renderAsapPermitTaken = false; - that.render (); - }, this.renderer.getElement ()); - } - }, - - - /** - * Automatically resizes the canvas element to the size of the - * given element on resize. - * - * @param {HTMLElement} sizeContainer the element to use. Set to null - * to disable. - */ - autoResizeContainer : function (sizeContainer) { - this.sizeContainer = sizeContainer; - } -} - -/** - * Fired when the user double-clicks on the panorama. - * - * @name bigshot.VRPanorama#dblclick - * @event - * @param {bigshot.VREvent} event the event object - */ - -bigshot.Object.extend (bigshot.VRPanorama, bigshot.EventDispatcher); -/* - * Copyright 2010 - 2012 Leo Sutic - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -/** - * Abstract base class for panorama hotspots. - * - * @class Abstract base class for panorama hotspots. - * - * A Hotspot is simply an HTML element that is moved / hidden etc. - * to overlay a given position in the panorama. - * - * @param {bigshot.VRPanorama} panorama the panorama to attach this hotspot to - */ -bigshot.VRHotspot = function (panorama) { - this.panorama = panorama; - - /** - * The method to use for dealing with hotspots that extend outside the - * viewport. Note that {@link #CLIP_ADJUST} et al are functions, not constants. - * To set the value, you must call the function to get a clipping strategy: - * - * @example - * var hotspot = ...; - * // note the function call below ---------------v - * hotspot.clippingStrategy = hotspot.CLIP_ADJUST (); - * - * @see bigshot.VRHotspot#CLIP_ADJUST - * @see bigshot.VRHotspot#CLIP_CENTER - * @see bigshot.VRHotspot#CLIP_FRACTION - * @see bigshot.VRHotspot#CLIP_ZOOM - * @see bigshot.VRHotspot#CLIP_FADE - * @see bigshot.VRHotspot#clip - * @type function(clipData) - * @default bigshot.VRHotspot#CLIP_ADJUST - */ - this.clippingStrategy = bigshot.VRHotspot.CLIP_ADJUST (panorama); - -} - -/** - * Hides the hotspot if less than frac of its area is visible. - * - * @param {number} frac the fraction (0.0 - 1.0) of the hotspot that must be visible for - * it to be shown. - * @type function(clipData) - * @see bigshot.VRHotspot#clip - * @see bigshot.VRHotspot#clippingStrategy - */ -bigshot.VRHotspot.CLIP_FRACTION = function (panorama, frac) { - return function (clipData) { - var r = { - x0 : Math.max (clipData.x, 0), - y0 : Math.max (clipData.y, 0), - x1 : Math.min (clipData.x + clipData.w, panorama.renderer.getViewportWidth ()), - y1 : Math.min (clipData.y + clipData.h, panorama.renderer.getViewportHeight ()) - }; - var full = clipData.w * clipData.h; - var visibleWidth = (r.x1 - r.x0); - var visibleHeight = (r.y1 - r.y0); - if (visibleWidth > 0 && visibleHeight > 0) { - var visible = visibleWidth * visibleHeight; - - return (visible / full) >= frac; - } else { - return false; - } - } -}; - -/** - * Hides the hotspot if its center is outside the viewport. - * - * @type function(clipData) - * @see bigshot.VRHotspot#clip - * @see bigshot.VRHotspot#clippingStrategy - */ -bigshot.VRHotspot.CLIP_CENTER = function (panorama) { - return function (clipData) { - var c = { - x : clipData.x + clipData.w / 2, - y : clipData.y + clipData.h / 2 - }; - return c.x >= 0 && c.x < panorama.renderer.getViewportWidth () && - c.y >= 0 && c.y < panorama.renderer.getViewportHeight (); - } -} - -/** - * Resizes the hotspot to fit in the viewport. Hides the hotspot if - * it is completely outside the viewport. - * - * @type function(clipData) - * @see bigshot.VRHotspot#clip - * @see bigshot.VRHotspot#clippingStrategy - */ -bigshot.VRHotspot.CLIP_ADJUST = function (panorama) { - return function (clipData) { - if (clipData.x < 0) { - clipData.w -= -clipData.x; - clipData.x = 0; - } - if (clipData.y < 0) { - clipData.h -= -clipData.y; - clipData.y = 0; - } - if (clipData.x + clipData.w > panorama.renderer.getViewportWidth ()) { - clipData.w = panorama.renderer.getViewportWidth () - clipData.x - 1; - } - if (clipData.y + clipData.h > panorama.renderer.getViewportHeight ()) { - clipData.h = panorama.renderer.getViewportHeight () - clipData.y - 1; - } - - return clipData.w > 0 && clipData.h > 0; - } -} - -/** - * Shrinks the hotspot as it approaches the viewport edges. - * - * @param s The full size of the hotspot. - * @param s.w The full width of the hotspot, in pixels. - * @param s.h The full height of the hotspot, in pixels. - * @see bigshot.VRHotspot#clip - * @see bigshot.VRHotspot#clippingStrategy - */ -bigshot.VRHotspot.CLIP_ZOOM = function (panorama, s, maxDistanceInViewportHeights) { - return function (clipData) { - if (clipData.x >= 0 && clipData.y >= 0 && (clipData.x + s.w) < panorama.renderer.getViewportWidth () - && (clipData.y + s.h) < panorama.renderer.getViewportHeight ()) { - clipData.w = s.w; - clipData.h = s.h; - return true; - } - - var distance = 0; - if (clipData.x < 0) { - distance = Math.max (-clipData.x, distance); - } - if (clipData.y < 0) { - distance = Math.max (-clipData.y, distance); - } - if (clipData.x + s.w > panorama.renderer.getViewportWidth ()) { - distance = Math.max (clipData.x + s.w - panorama.renderer.getViewportWidth (), distance); - } - if (clipData.y + s.h > panorama.renderer.getViewportHeight ()) { - distance = Math.max (clipData.y + s.h - panorama.renderer.getViewportHeight (), distance); - } - - distance /= panorama.renderer.getViewportHeight (); - if (distance > maxDistanceInViewportHeights) { - return false; - } - - var scale = 1 / (1 + distance); - - clipData.w = s.w * scale; - clipData.h = s.w * scale; - if (clipData.x < 0) { - clipData.x = 0; - } - if (clipData.y < 0) { - clipData.y = 0; - } - if (clipData.x + clipData.w > panorama.renderer.getViewportWidth ()) { - clipData.x = panorama.renderer.getViewportWidth () - clipData.w; - } - if (clipData.y + clipData.h > panorama.renderer.getViewportHeight ()) { - clipData.y = panorama.renderer.getViewportHeight () - clipData.h; - } - - return true; - } -} - -/** - * Progressively fades the hotspot as it gets closer to the viewport edges. - * - * @param {number} borderSizeInPixels the distance from the edge, in pixels, - * where the hotspot is completely opaque. - * @see bigshot.VRHotspot#clip - * @see bigshot.VRHotspot#clippingStrategy - */ -bigshot.VRHotspot.CLIP_FADE = function (panorama, borderSizeInPixels) { - return function (clipData) { - var distance = Math.min ( - clipData.x, - clipData.y, - panorama.renderer.getViewportWidth () - (clipData.x + clipData.w), - panorama.renderer.getViewportHeight () - (clipData.y + clipData.h)); - - if (distance <= 0) { - return false; - } else if (distance <= borderSizeInPixels) { - clipData.opacity = (distance / borderSizeInPixels); - return true; - } else { - clipData.opacity = 1.0; - return true; - } - } -} - -bigshot.VRHotspot.prototype = { - - /** - * Layout and resize the hotspot. Called by the panorama. - */ - layout : function () {}, - - /** - * Helper function to rotate a point around an axis. - * - * @param {number} ang the angle - * @param {bigshot.Point3D} vector the vector to rotate around - * @param {Vector} point the point - * @type Vector - * @private - */ - rotate : function (ang, vector, point) { - var arad = ang * Math.PI / 180.0; - var m = Matrix.Rotation(arad, $V([vector.x, vector.y, vector.z])).ensure4x4 (); - return m.xPoint3Dhom1 (point); - }, - - /** - * Converts the polar coordinates to world coordinates. - * The distance is assumed to be 1.0. - * - * @param yaw the yaw, in degrees - * @param pitch the pitch, in degrees - * @type bigshot.Point3D - */ - toVector : function (yaw, pitch) { - var point = { x : 0, y : 0, z : -1 }; - point = this.rotate (-pitch, { x : 1, y : 0, z : 0 }, point); - point = this.rotate (-yaw, { x : 0, y : 1, z : 0 }, point); - return point; - }, - - /** - * Converts the world-coordinate point p to screen coordinates. - * - * @param {bigshot.Point3D} p the world-coordinate point - * @type point - */ - toScreen : function (p) { - var res = this.panorama.renderer.transformToScreen (p) - return res; - }, - - /** - * Clips the hotspot against the viewport. Both parameters - * are in/out. Clipping is done by adjusting the values of the - * parameters. - * - * @param clipData Information about the hotspot. - * @param {number} clipData.x the x-coordinate of the top-left corner of the hotspot, in pixels. - * @param {number} clipData.y the y-coordinate of the top-left corner of the hotspot, in pixels. - * @param {number} clipData.w the width of the hotspot, in pixels. - * @param {number} clipData.h the height of the hotspot, in pixels. - * @param {number} [clipData.opacity] the opacity of the hotspot, ranging from 0.0 (transparent) - * to 1.0 (opaque). If set, the opacity of the hotspot element is adjusted. - * @type boolean - * @return true if the hotspot is visible, false otherwise - */ - clip : function (clipData) { - return this.clippingStrategy (clipData); - } -} -/* - * Copyright 2010 - 2012 Leo Sutic - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -/** - * Creates a new point-hotspot and attaches it to a VR panorama. - * - * @class A VR panorama point-hotspot. - * - * A Hotspot is simply an HTML element that is moved / hidden etc. - * to overlay a given position in the panorama. The element is moved - * by setting its style.top and style.left - * values. - * - * @augments bigshot.VRHotspot - * @param {bigshot.VRPanorama} panorama the panorama to attach this hotspot to - * @param {number} yaw the yaw coordinate of the hotspot - * @param {number} pitch the pitch coordinate of the hotspot - * @param {HTMLElement} element the HTML element - * @param {number} offsetX the offset to add to the screen coordinate corresponding - * to the hotspot's polar coordinates. Use this to center the hotspot horizontally. - * @param {number} offsetY the offset to add to the screen coordinate corresponding - * to the hotspot's polar coordinates. Use this to center the hotspot vertically. - */ -bigshot.VRPointHotspot = function (panorama, yaw, pitch, element, offsetX, offsetY) { - bigshot.VRHotspot.call (this, panorama); - this.element = element; - this.offsetX = offsetX; - this.offsetY = offsetY; - this.point = this.toVector (yaw, pitch); -} - -bigshot.VRPointHotspot.prototype = { - layout : function () { - var p = this.toScreen (this.point); - - var visible = false; - if (p != null) { - var s = this.panorama.browser.getElementSize (this.element); - p.w = s.w; - p.h = s.h; - - p.x += this.offsetX; - p.y += this.offsetY; - - if (this.clip (p)) { - this.element.style.top = (p.y) + "px"; - this.element.style.left = (p.x) + "px"; - this.element.style.width = (p.w) + "px"; - this.element.style.height = (p.h) + "px"; - if (p.opacity) { - this.element.style.opacity = p.opacity; - } - this.element.style.visibility = "inherit"; - visible = true; - } - } - - if (!visible) { - this.element.style.visibility = "hidden"; - } - } -} - -bigshot.Object.extend (bigshot.VRPointHotspot, bigshot.VRHotspot); -bigshot.Object.validate ("bigshot.VRPointHotspot", bigshot.VRHotspot); -/* - * Copyright 2010 - 2012 Leo Sutic - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -/** - * Creates a new rectangular hotspot and attaches it to a VR panorama. - * - * @class A rectangular VR panorama hotspot. - * - * A rectangular hotspot is simply an HTML element that is moved / resized / hidden etc. - * to overlay a given rectangle in the panorama. The element is moved - * by setting its style.top and style.left - * values, and resized by setting its style.width and style.height - * values. - * - * @augments bigshot.VRHotspot - * @param {bigshot.VRPanorama} panorama the panorama to attach this hotspot to - * @param {number} yaw0 the yaw coordinate of the top-left corner of the hotspot - * @param {number} pitch0 the pitch coordinate of the top-left corner of the hotspot - * @param {number} yaw1 the yaw coordinate of the bottom-right corner of the hotspot - * @param {number} pitch1 the pitch coordinate of the bottom-right corner of the hotspot - * @param {HTMLElement} element the HTML element - */ -bigshot.VRRectangleHotspot = function (panorama, yaw0, pitch0, yaw1, pitch1, element) { - bigshot.VRHotspot.call (this, panorama); - - this.element = element; - this.point0 = this.toVector (yaw0, pitch0); - this.point1 = this.toVector (yaw1, pitch1); -} - -bigshot.VRRectangleHotspot.prototype = { - layout : function () { - var p = this.toScreen (this.point0); - var p1 = this.toScreen (this.point1); - - var visible = false; - if (p != null && p1 != null) { - var cd = { - x : p.x, - y : p.y, - opacity : 1.0, - w : p1.x - p.x, - h : p1.y - p.y - }; - - if (this.clip (cd)) { - this.element.style.top = (cd.y) + "px"; - this.element.style.left = (cd.x) + "px"; - this.element.style.width = (cd.w) + "px"; - this.element.style.height = (cd.h) + "px"; - this.element.style.visibility = "inherit"; - visible = true; - } - } - - if (!visible) { - this.element.style.visibility = "hidden"; - } - } -} - -bigshot.Object.extend (bigshot.VRRectangleHotspot, bigshot.VRHotspot); -bigshot.Object.validate ("bigshot.VRRectangleHotspot", bigshot.VRHotspot); -/* - * Copyright 2010 - 2012 Leo Sutic - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -/** - * Creates a new parameter block. - * - * @class Parameters for the adaptive LOD monitor. - */ -bigshot.AdaptiveLODMonitorParameters = function (values) { - - /** - * The VR panorama to adjust. - * - * @type bigshot.VRPanorama - */ - this.vrPanorama = null; - - /** - * The target framerate in frames per second. - * The monitor will try to achieve an average frame render time - * of 1 / targetFps seconds. - * - * @default 30 - * @type float - */ - this.targetFps = 30; - - /** - * The tolerance for the rendering time. The monitor will adjust the - * level of detail if the average frame render time rises above - * target frame render time * (1.0 + tolerance) or falls below - * target frame render time / (1.0 + tolerance). - * - * @default 0.3 - * @type float - */ - this.tolerance = 0.3; - - /** - * The rate at which the level of detail is adjusted. - * For detail increase, the detail is multiplied with (1.0 + rate), - * for decrease divided. - * - * @default 0.1 - * @type float - */ - this.rate = 0.1; - - /** - * Minimum texture magnification. - * - * @default 1.5 - * @type float - */ - this.minMag = 1.5; - - /** - * Maximum texture magnification. - * - * @default 16 - * @type float - */ - this.maxMag = 16; - - /** - * Texture magnification for HQ render passes. - * - * @default 1.5 - * @type float - */ - this.hqRenderMag = 1.5; - - /** - * Delay in milliseconds before executing - * a HQ render pass. - * - * @default 2000 - * @type int - */ - this.hqRenderDelay = 2000; - - /** - * Interval in milliseconds for the - * HQ render pass timer. - * - * @default 1000 - * @type int - */ - this.hqRenderInterval = 1000; - - if (values) { - for (var k in values) { - this[k] = values[k]; - } - } - - this.merge = function (values, overwrite) { - for (var k in values) { - if (overwrite || !this[k]) { - this[k] = values[k]; - } - } - } - return this; -}; -/* - * Copyright 2010 - 2012 Leo Sutic - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -/** - * Creates a new adaptive level-of-detail monitor. - * - * @class An adaptive LOD monitor that adjusts the level of detail of a VR panorama - * to achieve a desired frame rate. To connect it to a VR panorama, use the - * {@link bigshot.AdaptiveLODMonitor#getListener} method to get a render listener - * that can be passed to {@link bigshot.VRPanorama#addRenderListener}. - * - *

The monitor maintains two render modes - a high quality one with a fixed - * level of detail, and a low(er) quality one with variable level of detail. - * If the panorama is idle for more than a set interval, a high-quality render is - * performed. - * - * @param {bigshot.AdaptiveLODMonitorParameters} parameters parameters for the LOD monitor. - * - * @see bigshot.AdaptiveLODMonitorParameters for a list of parameters - * - * @example - * var bvr = new bigshot.VRPanorama ( ... ); - * var lodMonitor = new bigshot.AdaptiveLODMonitor ( - * new bigshot.AdaptiveLODMonitorParameters ({ - * vrPanorama : bvr, - * targetFps : 30, - * tolerance : 0.3, - * rate : 0.1, - * minMag : 1.5, - * maxMag : 16 - * })); - * bvr.addRenderListener (lodMonitor.getListener ()); - */ -bigshot.AdaptiveLODMonitor = function (parameters) { - this.setParameters (parameters); - - /** - * The current adaptive detail level. - * @type float - * @private - */ - this.currentAdaptiveMagnification = parameters.vrPanorama.getMaxTextureMagnification (); - - /** - * The number of frames that have been rendered. - * @type int - * @private - */ - this.frames = 0; - - /** - * The total number of times we have sampled the render time. - * @type int - * @private - */ - this.samples = 0; - - /** - * The sum of sample times from all samples of render time in milliseconds. - * @type int - * @private - */ - this.renderTimeTotal = 0; - - /** - * The sum of sample times from the recent sample pass in milliseconds. - * @type int - * @private - */ - this.renderTimeLast = 0; - - /** - * The number of samples currently done in the recent sample pass. - * @type int - * @private - */ - this.samplesLast = 0; - - /** - * The start time, in milliseconds, of the last sample. - * @type int - * @private - */ - this.startTime = 0; - - /** - * The time, in milliseconds, when the panorama was last rendered. - * @type int - * @private - */ - this.lastRender = 0; - - this.hqRender = false; - this.hqMode = false; - this.hqRenderWaiting = false; - - /** - * Flag to enable / disable the monitor. - * @type boolean - * @private - */ - this.enabled = true; - - var that = this; - this.listenerFunction = function (state, cause, data) { - that.listener (state, cause, data); - }; -}; - -bigshot.AdaptiveLODMonitor.prototype = { - averageRenderTime : function () { - if (this.samples > 0) { - return this.renderTimeTotal / this.samples; - } else { - return -1; - } - }, - - /** - * @param {bigshot.AdaptiveLODMonitorParameters} parameters - */ - setParameters : function (parameters) { - this.parameters = parameters; - this.targetTime = 1000 / this.parameters.targetFps; - - this.lowerTime = this.targetTime / (1.0 + this.parameters.tolerance); - this.upperTime = this.targetTime * (1.0 + this.parameters.tolerance); - }, - - setEnabled : function (enabled) { - this.enabled = enabled; - }, - - averageRenderTimeLast : function () { - if (this.samples > 0) { - return this.renderTimeLast / this.samplesLast; - } else { - return -1; - } - }, - - getListener : function () { - return this.listenerFunction; - }, - - increaseDetail : function () { - this.currentAdaptiveMagnification = Math.max (this.parameters.minMag, this.currentAdaptiveMagnification / (1.0 + this.parameters.rate)); - }, - - decreaseDetail : function () { - this.currentAdaptiveMagnification = Math.min (this.parameters.maxMag, this.currentAdaptiveMagnification * (1.0 + this.parameters.rate)); - }, - - sample : function () { - var deltat = new Date ().getTime () - this.startTime; - this.samples++; - this.renderTimeTotal += deltat; - - this.samplesLast++; - this.renderTimeLast += deltat; - - if (this.samplesLast > 4) { - var averageLast = this.renderTimeLast / this.samplesLast; - - if (averageLast < this.lowerTime) { - this.increaseDetail (); - } else if (averageLast > this.upperTime) { - this.decreaseDetail (); - } - - this.samplesLast = 0; - this.renderTimeLast = 0; - } - }, - - hqRenderTick : function () { - if (this.lastRender < new Date ().getTime () - this.parameters.hqRenderDelay) { - this.hqRender = true; - this.hqMode = true; - if (this.enabled) { - this.parameters.vrPanorama.setMaxTextureMagnification (this.parameters.hqRenderMag); - this.parameters.vrPanorama.render (); - } - - this.hqRender = false; - this.hqRenderWaiting = false; - } else { - var that = this; - setTimeout (function () { - that.hqRenderTick (); - }, this.parameters.hqRenderInterval); - } - }, - - listener : function (state, cause, data) { - if (!this.enabled) { - return; - } - - if (this.hqRender) { - return; - } - - if (this.hqMode && cause == bigshot.VRPanorama.ONRENDER_TEXTURE_UPDATE) { - this.parameters.vrPanorama.setMaxTextureMagnification (this.parameters.minMag); - return; - } else { - this.hqMode = false; - } - - this.parameters.vrPanorama.setMaxTextureMagnification (this.currentAdaptiveMagnification); - - this.frames++; - if ((this.frames < 20 || this.frames % 5 == 0) && state == bigshot.VRPanorama.ONRENDER_BEGIN) { - this.startTime = new Date ().getTime (); - this.lastRender = this.startTime; - var that = this; - setTimeout (function () { - that.sample (); - }, 1); - if (!this.hqRenderWaiting) { - this.hqRenderWaiting = true; - setTimeout (function () { - that.hqRenderTick (); - }, this.parameters.hqRenderInterval); - } - } - } -}; -} diff --git a/js/vendor/commonmark/dist/commonmark.min.js b/js/vendor/commonmark/dist/commonmark.min.js new file mode 100644 index 0000000000..e8c0e6e14e --- /dev/null +++ b/js/vendor/commonmark/dist/commonmark.min.js @@ -0,0 +1,4 @@ +/* commonmark 0.22 https://github.com/jgm/CommonMark @license BSD3 */ +!function(e){if("object"==typeof exports&&"undefined"!=typeof module)module.exports=e();else if("function"==typeof define&&define.amd)define([],e);else{var o;"undefined"!=typeof window?o=window:"undefined"!=typeof global?o=global:"undefined"!=typeof self&&(o=self),o.commonmark=e()}}(function(){return function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a="function"==typeof require&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);var f=new Error("Cannot find module '"+o+"'");throw f.code="MODULE_NOT_FOUND",f}var l=n[o]={exports:{}};t[o][0].call(l.exports,function(e){var n=t[o][1][e];return s(n?n:e)},l,l.exports,e,t,n,r)}return n[o].exports}for(var i="function"==typeof require&&require,o=0;r.length>o;o++)s(r[o]);return s}({1:[function(require,module,exports){"use strict";function Parser(options){return{doc:new Document,blocks:blocks,blockStarts:blockStarts,tip:this.doc,oldtip:this.doc,currentLine:"",lineNumber:0,offset:0,column:0,nextNonspace:0,nextNonspaceColumn:0,indent:0,indented:!1,blank:!1,allClosed:!0,lastMatchedContainer:this.doc,refmap:{},lastLineLength:0,inlineParser:new InlineParser(options),findNextNonspace:findNextNonspace,advanceOffset:advanceOffset,advanceNextNonspace:advanceNextNonspace,breakOutOfLists:breakOutOfLists,addLine:addLine,addChild:addChild,incorporateLine:incorporateLine,finalize:finalize,processInlines:processInlines,closeUnmatchedBlocks:closeUnmatchedBlocks,parse:parse,options:options||{}}}var Node=require("./node"),unescapeString=require("./common").unescapeString,OPENTAG=require("./common").OPENTAG,CLOSETAG=require("./common").CLOSETAG,CODE_INDENT=4,C_NEWLINE=10,C_GREATERTHAN=62,C_LESSTHAN=60,C_SPACE=32,C_OPEN_BRACKET=91,InlineParser=require("./inlines"),reHtmlBlockOpen=[/./,/^<(?:script|pre|style)(?:\s|>|$)/i,/^/,/\?>/,/>/,/\]\]>/],reHrule=/^(?:(?:\* *){3,}|(?:_ *){3,}|(?:- *){3,}) *$/,reMaybeSpecial=/^[#`~*+_=<>0-9-]/,reNonSpace=/[^ \t\f\v\r\n]/,reBulletListMarker=/^[*+-]( +|$)/,reOrderedListMarker=/^(\d{1,9})([.)])( +|$)/,reATXHeaderMarker=/^#{1,6}(?: +|$)/,reCodeFence=/^`{3,}(?!.*`)|^~{3,}(?!.*~)/,reClosingCodeFence=/^(?:`{3,}|~{3,})(?= *$)/,reSetextHeaderLine=/^(?:=+|-+) *$/,reLineEnding=/\r\n|\n|\r/,isBlank=function(s){return!reNonSpace.test(s)},peek=function(ln,pos){return ln.length>pos?ln.charCodeAt(pos):-1},endsWithBlankLine=function(block){for(;block;){if(block._lastLineBlank)return!0;var t=block.type;if("List"!==t&&"Item"!==t)break;block=block._lastChild}return!1},breakOutOfLists=function(block){var b=block,last_list=null;do"List"===b.type&&(last_list=b),b=b._parent;while(b);if(last_list){for(;block!==last_list;)this.finalize(block,this.lineNumber),block=block._parent;this.finalize(last_list,this.lineNumber),this.tip=last_list._parent}},addLine=function(){this.tip._string_content+=this.currentLine.slice(this.offset)+"\n"},addChild=function(tag,offset){for(;!this.blocks[this.tip.type].canContain(tag);)this.finalize(this.tip,this.lineNumber-1);var column_number=offset+1,newBlock=new Node(tag,[[this.lineNumber,column_number],[0,0]]);return newBlock._string_content="",this.tip.appendChild(newBlock),this.tip=newBlock,newBlock},parseListMarker=function(ln,offset,indent){var match,spaces_after_marker,rest=ln.slice(offset),data={type:null,tight:!0,bulletChar:null,start:null,delimiter:null,padding:null,markerOffset:indent};if(match=rest.match(reBulletListMarker))spaces_after_marker=match[1].length,data.type="Bullet",data.bulletChar=match[0][0];else{if(!(match=rest.match(reOrderedListMarker)))return null;spaces_after_marker=match[3].length,data.type="Ordered",data.start=parseInt(match[1]),data.delimiter=match[2]}var blank_item=match[0].length===rest.length;return data.padding=spaces_after_marker>=5||1>spaces_after_marker||blank_item?match[0].length-spaces_after_marker+1:match[0].length,data},listsMatch=function(list_data,item_data){return list_data.type===item_data.type&&list_data.delimiter===item_data.delimiter&&list_data.bulletChar===item_data.bulletChar},closeUnmatchedBlocks=function(){if(!this.allClosed){for(;this.oldtip!==this.lastMatchedContainer;){var parent=this.oldtip._parent;this.finalize(this.oldtip,this.lineNumber-1),this.oldtip=parent}this.allClosed=!0}},blocks={Document:{"continue":function(){return 0},finalize:function(){},canContain:function(t){return"Item"!==t},acceptsLines:!1},List:{"continue":function(){return 0},finalize:function(parser,block){for(var item=block._firstChild;item;){if(endsWithBlankLine(item)&&item._next){block._listData.tight=!1;break}for(var subitem=item._firstChild;subitem;){if(endsWithBlankLine(subitem)&&(item._next||subitem._next)){block._listData.tight=!1;break}subitem=subitem._next}item=item._next}},canContain:function(t){return"Item"===t},acceptsLines:!1},BlockQuote:{"continue":function(parser){var ln=parser.currentLine;return parser.indented||peek(ln,parser.nextNonspace)!==C_GREATERTHAN?1:(parser.advanceNextNonspace(),parser.advanceOffset(1,!1),peek(ln,parser.offset)===C_SPACE&&parser.offset++,0)},finalize:function(){},canContain:function(t){return"Item"!==t},acceptsLines:!1},Item:{"continue":function(parser,container){if(parser.blank&&null!==container._firstChild)parser.advanceNextNonspace();else{if(!(parser.indent>=container._listData.markerOffset+container._listData.padding))return 1;parser.advanceOffset(container._listData.markerOffset+container._listData.padding,!0)}return 0},finalize:function(){},canContain:function(t){return"Item"!==t},acceptsLines:!1},Header:{"continue":function(){return 1},finalize:function(){},canContain:function(){return!1},acceptsLines:!1},HorizontalRule:{"continue":function(){return 1},finalize:function(){},canContain:function(){return!1},acceptsLines:!1},CodeBlock:{"continue":function(parser,container){var ln=parser.currentLine,indent=parser.indent;if(container._isFenced){var match=3>=indent&&ln.charAt(parser.nextNonspace)===container._fenceChar&&ln.slice(parser.nextNonspace).match(reClosingCodeFence);if(match&&match[0].length>=container._fenceLength)return parser.finalize(container,parser.lineNumber),2;for(var i=container._fenceOffset;i>0&&peek(ln,parser.offset)===C_SPACE;)parser.advanceOffset(1,!1),i--}else if(indent>=CODE_INDENT)parser.advanceOffset(CODE_INDENT,!0);else{if(!parser.blank)return 1;parser.advanceNextNonspace()}return 0},finalize:function(parser,block){if(block._isFenced){var content=block._string_content,newlinePos=content.indexOf("\n"),firstLine=content.slice(0,newlinePos),rest=content.slice(newlinePos+1);block.info=unescapeString(firstLine.trim()),block._literal=rest}else block._literal=block._string_content.replace(/(\n *)+$/,"\n");block._string_content=null},canContain:function(){return!1},acceptsLines:!0},HtmlBlock:{"continue":function(parser,container){return!parser.blank||6!==container._htmlBlockType&&7!==container._htmlBlockType?0:1},finalize:function(parser,block){block._literal=block._string_content.replace(/(\n *)+$/,""),block._string_content=null},canContain:function(){return!1},acceptsLines:!0},Paragraph:{"continue":function(parser){return parser.blank?1:0},finalize:function(parser,block){for(var pos,hasReferenceDefs=!1;peek(block._string_content,0)===C_OPEN_BRACKET&&(pos=parser.inlineParser.parseReference(block._string_content,parser.refmap));)block._string_content=block._string_content.slice(pos),hasReferenceDefs=!0;hasReferenceDefs&&isBlank(block._string_content)&&block.unlink()},canContain:function(){return!1},acceptsLines:!0}},blockStarts=[function(parser){return parser.indented||peek(parser.currentLine,parser.nextNonspace)!==C_GREATERTHAN?0:(parser.advanceNextNonspace(),parser.advanceOffset(1,!1),peek(parser.currentLine,parser.offset)===C_SPACE&&parser.advanceOffset(1,!1),parser.closeUnmatchedBlocks(),parser.addChild("BlockQuote",parser.nextNonspace),1)},function(parser){var match;if(!parser.indented&&(match=parser.currentLine.slice(parser.nextNonspace).match(reATXHeaderMarker))){parser.advanceNextNonspace(),parser.advanceOffset(match[0].length,!1),parser.closeUnmatchedBlocks();var container=parser.addChild("Header",parser.nextNonspace);return container.level=match[0].trim().length,container._string_content=parser.currentLine.slice(parser.offset).replace(/^ *#+ *$/,"").replace(/ +#+ *$/,""),parser.advanceOffset(parser.currentLine.length-parser.offset),2}return 0},function(parser){var match;if(!parser.indented&&(match=parser.currentLine.slice(parser.nextNonspace).match(reCodeFence))){var fenceLength=match[0].length;parser.closeUnmatchedBlocks();var container=parser.addChild("CodeBlock",parser.nextNonspace);return container._isFenced=!0,container._fenceLength=fenceLength,container._fenceChar=match[0][0],container._fenceOffset=parser.indent,parser.advanceNextNonspace(),parser.advanceOffset(fenceLength,!1),2}return 0},function(parser,container){if(!parser.indented&&peek(parser.currentLine,parser.nextNonspace)===C_LESSTHAN){var blockType,s=parser.currentLine.slice(parser.nextNonspace);for(blockType=1;7>=blockType;blockType++)if(reHtmlBlockOpen[blockType].test(s)&&(7>blockType||"Paragraph"!==container.type)){parser.closeUnmatchedBlocks();var b=parser.addChild("HtmlBlock",parser.offset);return b._htmlBlockType=blockType,2}}return 0},function(parser,container){var match;if(!parser.indented&&"Paragraph"===container.type&&container._string_content.indexOf("\n")===container._string_content.length-1&&(match=parser.currentLine.slice(parser.nextNonspace).match(reSetextHeaderLine))){parser.closeUnmatchedBlocks();var header=new Node("Header",container.sourcepos);return header.level="="===match[0][0]?1:2,header._string_content=container._string_content,container.insertAfter(header),container.unlink(),parser.tip=header,parser.advanceOffset(parser.currentLine.length-parser.offset,!1),2}return 0},function(parser){return!parser.indented&&reHrule.test(parser.currentLine.slice(parser.nextNonspace))?(parser.closeUnmatchedBlocks(),parser.addChild("HorizontalRule",parser.nextNonspace),parser.advanceOffset(parser.currentLine.length-parser.offset,!1),2):0},function(parser,container){var data,i;return!(data=parseListMarker(parser.currentLine,parser.nextNonspace,parser.indent))||parser.indented&&"List"!==container.type?0:(parser.closeUnmatchedBlocks(),parser.advanceNextNonspace(),i=parser.column,parser.advanceOffset(data.padding,!1),data.padding=parser.column-i,"List"===parser.tip.type&&listsMatch(container._listData,data)||(container=parser.addChild("List",parser.nextNonspace),container._listData=data),container=parser.addChild("Item",parser.nextNonspace),container._listData=data,1)},function(parser){return parser.indented&&"Paragraph"!==parser.tip.type&&!parser.blank?(parser.advanceOffset(CODE_INDENT,!0),parser.closeUnmatchedBlocks(),parser.addChild("CodeBlock",parser.offset),2):0}],advanceOffset=function(count,columns){for(var i=0,cols=0,currentLine=this.currentLine;columns?count>cols:count>i;)cols+=" "===currentLine[this.offset+i]?4-(this.column+cols)%4:1,i++;this.offset+=i,this.column+=cols},advanceNextNonspace=function(){this.offset=this.nextNonspace,this.column=this.nextNonspaceColumn},findNextNonspace=function(){for(var c,currentLine=this.currentLine,i=this.offset,cols=this.column;""!==(c=currentLine.charAt(i));)if(" "===c)i++,cols++;else{if(" "!==c)break;i++,cols+=4-cols%4}this.blank="\n"===c||"\r"===c||""===c,this.nextNonspace=i,this.nextNonspaceColumn=cols,this.indent=this.nextNonspaceColumn-this.column,this.indented=this.indent>=CODE_INDENT},incorporateLine=function(ln){var t,all_matched=!0,container=this.doc;this.oldtip=this.tip,this.offset=0,this.lineNumber+=1,-1!==ln.indexOf("\x00")&&(ln=ln.replace(/\0/g,"�")),this.currentLine=ln;for(var lastChild;(lastChild=container._lastChild)&&lastChild._open;){switch(container=lastChild,this.findNextNonspace(),this.blocks[container.type]["continue"](this,container)){case 0:break;case 1:all_matched=!1;break;case 2:return void(this.lastLineLength=ln.length);default:throw"continue returned illegal value, must be 0, 1, or 2"}if(!all_matched){container=container._parent;break}}this.allClosed=container===this.oldtip,this.lastMatchedContainer=container,this.blank&&container._lastLineBlank&&this.breakOutOfLists(container);for(var matchedLeaf="Paragraph"!==container.type&&blocks[container.type].acceptsLines,starts=this.blockStarts,startsLen=starts.length;!matchedLeaf;){if(this.findNextNonspace(),!this.indented&&!reMaybeSpecial.test(ln.slice(this.nextNonspace))){this.advanceNextNonspace();break}for(var i=0;startsLen>i;){var res=starts[i](this,container);if(1===res){container=this.tip;break}if(2===res){container=this.tip,matchedLeaf=!0;break}i++}if(i===startsLen){this.advanceNextNonspace();break}}if(this.allClosed||this.blank||"Paragraph"!==this.tip.type){this.closeUnmatchedBlocks(),this.blank&&container.lastChild&&(container.lastChild._lastLineBlank=!0),t=container.type;for(var lastLineBlank=this.blank&&!("BlockQuote"===t||"CodeBlock"===t&&container._isFenced||"Item"===t&&!container._firstChild&&container.sourcepos[0][0]===this.lineNumber),cont=container;cont;)cont._lastLineBlank=lastLineBlank,cont=cont._parent;this.blocks[t].acceptsLines?(this.addLine(),"HtmlBlock"===t&&container._htmlBlockType>=1&&5>=container._htmlBlockType&&reHtmlBlockClose[container._htmlBlockType].test(this.currentLine.slice(this.offset))&&this.finalize(container,this.lineNumber)):ln.length>this.offset&&!this.blank&&(container=this.addChild("Paragraph",this.offset),this.advanceNextNonspace(),this.addLine())}else this.addLine();this.lastLineLength=ln.length},finalize=function(block,lineNumber){var above=block._parent;block._open=!1,block.sourcepos[1]=[lineNumber,this.lastLineLength],this.blocks[block.type].finalize(this,block),this.tip=above},processInlines=function(block){var node,event,t,walker=block.walker();for(this.inlineParser.refmap=this.refmap,this.inlineParser.options=this.options;event=walker.next();)node=event.node,t=node.type,event.entering||"Paragraph"!==t&&"Header"!==t||this.inlineParser.parse(node)},Document=function(){var doc=new Node("Document",[[1,1],[0,0]]);return doc},parse=function(input){this.doc=new Document,this.tip=this.doc,this.refmap={},this.lineNumber=0,this.lastLineLength=0,this.offset=0,this.column=0,this.lastMatchedContainer=this.doc,this.currentLine="",this.options.time&&console.time("preparing input");var lines=input.split(reLineEnding),len=lines.length;input.charCodeAt(input.length-1)===C_NEWLINE&&(len-=1),this.options.time&&console.timeEnd("preparing input"),this.options.time&&console.time("block parsing");for(var i=0;len>i;i++)this.incorporateLine(lines[i]);for(;this.tip;)this.finalize(this.tip,len);return this.options.time&&console.timeEnd("block parsing"),this.options.time&&console.time("inline parsing"),this.processInlines(this.doc),this.options.time&&console.timeEnd("inline parsing"),this.doc};module.exports=Parser},{"./common":2,"./inlines":6,"./node":7}],2:[function(require,module,exports){"use strict";var encode=require("mdurl/encode"),decode=require("mdurl/decode"),C_BACKSLASH=92,decodeHTML=require("entities").decodeHTML,ENTITY="&(?:#x[a-f0-9]{1,8}|#[0-9]{1,8}|[a-z][a-z0-9]{1,31});",TAGNAME="[A-Za-z][A-Za-z0-9-]*",ATTRIBUTENAME="[a-zA-Z_:][a-zA-Z0-9:._-]*",UNQUOTEDVALUE="[^\"'=<>`\\x00-\\x20]+",SINGLEQUOTEDVALUE="'[^']*'",DOUBLEQUOTEDVALUE='"[^"]*"',ATTRIBUTEVALUE="(?:"+UNQUOTEDVALUE+"|"+SINGLEQUOTEDVALUE+"|"+DOUBLEQUOTEDVALUE+")",ATTRIBUTEVALUESPEC="(?:\\s*=\\s*"+ATTRIBUTEVALUE+")",ATTRIBUTE="(?:\\s+"+ATTRIBUTENAME+ATTRIBUTEVALUESPEC+"?)",OPENTAG="<"+TAGNAME+ATTRIBUTE+"*\\s*/?>",CLOSETAG="]",HTMLCOMMENT="|",PROCESSINGINSTRUCTION="[<][?].*?[?][>]",DECLARATION="]*>",CDATA="",HTMLTAG="(?:"+OPENTAG+"|"+CLOSETAG+"|"+HTMLCOMMENT+"|"+PROCESSINGINSTRUCTION+"|"+DECLARATION+"|"+CDATA+")",reHtmlTag=new RegExp("^"+HTMLTAG,"i"),reBackslashOrAmp=/[\\&]/,ESCAPABLE="[!\"#$%&'()*+,./:;<=>?@[\\\\\\]^_`{|}~-]",reEntityOrEscapedChar=new RegExp("\\\\"+ESCAPABLE+"|"+ENTITY,"gi"),XMLSPECIAL='[&<>"]',reXmlSpecial=new RegExp(XMLSPECIAL,"g"),reXmlSpecialOrEntity=new RegExp(ENTITY+"|"+XMLSPECIAL,"gi"),unescapeChar=function(s){return s.charCodeAt(0)===C_BACKSLASH?s.charAt(1):decodeHTML(s)},unescapeString=function(s){return reBackslashOrAmp.test(s)?s.replace(reEntityOrEscapedChar,unescapeChar):s},normalizeURI=function(uri){try{return encode(decode(uri))}catch(err){return uri}},replaceUnsafeChar=function(s){switch(s){case"&":return"&";case"<":return"<";case">":return">";case'"':return""";default:return s}},escapeXml=function(s,preserve_entities){return reXmlSpecial.test(s)?preserve_entities?s.replace(reXmlSpecialOrEntity,replaceUnsafeChar):s.replace(reXmlSpecial,replaceUnsafeChar):s};module.exports={unescapeString:unescapeString,normalizeURI:normalizeURI,escapeXml:escapeXml,reHtmlTag:reHtmlTag,OPENTAG:OPENTAG,CLOSETAG:CLOSETAG,ENTITY:ENTITY,ESCAPABLE:ESCAPABLE}},{entities:10,"mdurl/decode":18,"mdurl/encode":19}],3:[function(require,module,exports){"use strict";if(String.fromCodePoint)module.exports=function(_){try{return String.fromCodePoint(_)}catch(e){if(e instanceof RangeError)return String.fromCharCode(65533);throw e}};else{var stringFromCharCode=String.fromCharCode,floor=Math.floor,fromCodePoint=function(){var highSurrogate,lowSurrogate,MAX_SIZE=16384,codeUnits=[],index=-1,length=arguments.length;if(!length)return"";for(var result="";++indexcodePoint||codePoint>1114111||floor(codePoint)!==codePoint)return String.fromCharCode(65533);65535>=codePoint?codeUnits.push(codePoint):(codePoint-=65536,highSurrogate=(codePoint>>10)+55296,lowSurrogate=codePoint%1024+56320,codeUnits.push(highSurrogate,lowSurrogate)),(index+1===length||codeUnits.length>MAX_SIZE)&&(result+=stringFromCharCode.apply(null,codeUnits),codeUnits.length=0)}return result};module.exports=fromCodePoint}},{}],4:[function(require,module,exports){"use strict";function HtmlRenderer(options){return{softbreak:"\n",escape:escapeXml,options:options||{},render:renderNodes}}var escapeXml=require("./common").escapeXml,tag=function(name,attrs,selfclosing){var result="<"+name;if(attrs&&attrs.length>0)for(var attrib,i=0;void 0!==(attrib=attrs[i]);)result+=" "+attrib[0]+'="'+attrib[1]+'"',i++;return selfclosing&&(result+=" /"),result+=">"},reHtmlTag=/\<[^>]*\>/,reUnsafeProtocol=/^javascript:|vbscript:|file:|data:/i,reSafeDataProtocol=/^data:image\/(?:png|gif|jpeg|webp)/i,potentiallyUnsafe=function(url){return reUnsafeProtocol.test(url)&&!reSafeDataProtocol.test(url)},renderNodes=function(block){var attrs,info_words,tagname,event,node,entering,grandparent,walker=block.walker(),buffer="",lastOut="\n",disableTags=0,out=function(s){buffer+=disableTags>0?s.replace(reHtmlTag,""):s,lastOut=s},esc=this.escape,cr=function(){"\n"!==lastOut&&(buffer+="\n",lastOut="\n")},options=this.options;for(options.time&&console.time("rendering");event=walker.next();){if(entering=event.entering,node=event.node,attrs=[],options.sourcepos){var pos=node.sourcepos;pos&&attrs.push(["data-sourcepos",String(pos[0][0])+":"+String(pos[0][1])+"-"+String(pos[1][0])+":"+String(pos[1][1])])}switch(node.type){case"Text":out(esc(node.literal,!1));break;case"Softbreak":out(this.softbreak);break;case"Hardbreak":out(tag("br",[],!0)),cr();break;case"Emph":out(tag(entering?"em":"/em"));break;case"Strong":out(tag(entering?"strong":"/strong"));break;case"Html":out(options.safe?"":node.literal);break;case"Link":entering?(options.safe&&potentiallyUnsafe(node.destination)||attrs.push(["href",esc(node.destination,!0)]),node.title&&attrs.push(["title",esc(node.title,!0)]),out(tag("a",attrs))):out(tag("/a"));break;case"Image":entering?(0===disableTags&&out(options.safe&&potentiallyUnsafe(node.destination)?'':'<img src=')));break;case"Code":out(tag("code")+esc(node.literal,!1)+tag("/code"));break;case"Document":break;case"Paragraph":if(grandparent=node.parent.parent,null!==grandparent&&"List"===grandparent.type&&grandparent.listTight)break;entering?(cr(),out(tag("p",attrs))):(out(tag("/p")),cr());break;case"BlockQuote":entering?(cr(),out(tag("blockquote",attrs)),cr()):(cr(),out(tag("/blockquote")),cr());break;case"Item":entering?out(tag("li",attrs)):(out(tag("/li")),cr());break;case"List":if(tagname="Bullet"===node.listType?"ul":"ol",entering){var start=node.listStart;null!==start&&1!==start&&attrs.push(["start",start.toString()]),cr(),out(tag(tagname,attrs)),cr()}else cr(),out(tag("/"+tagname)),cr();break;case"Header":tagname="h"+node.level,entering?(cr(),out(tag(tagname,attrs))):(out(tag("/"+tagname)),cr());break;case"CodeBlock":info_words=node.info?node.info.split(/\s+/):[],info_words.length>0&&info_words[0].length>0&&attrs.push(["class","language-"+esc(info_words[0],!0)]),cr(),out(tag("pre")+tag("code",attrs)),out(esc(node.literal,!1)),out(tag("/code")+tag("/pre")),cr();break;case"HtmlBlock":cr(),out(options.safe?"":node.literal),cr();break;case"HorizontalRule":cr(),out(tag("hr",attrs,!0)),cr();break;default:throw"Unknown node type "+node.type}}return options.time&&console.timeEnd("rendering"),buffer};module.exports=HtmlRenderer},{"./common":2}],5:[function(require,module,exports){"use strict";module.exports.Node=require("./node"),module.exports.Parser=require("./blocks"),module.exports.HtmlRenderer=require("./html"),module.exports.XmlRenderer=require("./xml")},{"./blocks":1,"./html":4,"./node":7,"./xml":9}],6:[function(require,module,exports){"use strict";function InlineParser(options){return{subject:"",delimiters:null,pos:0,refmap:{},match:match,peek:peek,spnl:spnl,parseBackticks:parseBackticks,parseBackslash:parseBackslash,parseAutolink:parseAutolink,parseHtmlTag:parseHtmlTag,scanDelims:scanDelims,handleDelim:handleDelim,parseLinkTitle:parseLinkTitle,parseLinkDestination:parseLinkDestination,parseLinkLabel:parseLinkLabel,parseOpenBracket:parseOpenBracket,parseCloseBracket:parseCloseBracket,parseBang:parseBang,parseEntity:parseEntity,parseString:parseString,parseNewline:parseNewline,parseReference:parseReference,parseInline:parseInline,processEmphasis:processEmphasis,removeDelimiter:removeDelimiter,options:options||{},parse:parseInlines}}var Node=require("./node"),common=require("./common"),normalizeReference=require("./normalize-reference"),normalizeURI=common.normalizeURI,unescapeString=common.unescapeString,fromCodePoint=require("./from-code-point.js"),decodeHTML=require("entities").decodeHTML;require("string.prototype.repeat");var C_NEWLINE=10,C_ASTERISK=42,C_UNDERSCORE=95,C_BACKTICK=96,C_OPEN_BRACKET=91,C_CLOSE_BRACKET=93,C_LESSTHAN=60,C_BANG=33,C_BACKSLASH=92,C_AMPERSAND=38,C_OPEN_PAREN=40,C_CLOSE_PAREN=41,C_COLON=58,C_SINGLEQUOTE=39,C_DOUBLEQUOTE=34,ESCAPABLE=common.ESCAPABLE,ESCAPED_CHAR="\\\\"+ESCAPABLE,REG_CHAR="[^\\\\()\\x00-\\x20]",IN_PARENS_NOSP="\\(("+REG_CHAR+"|"+ESCAPED_CHAR+"|\\\\)*\\)",ENTITY=common.ENTITY,reHtmlTag=common.reHtmlTag,rePunctuation=new RegExp(/^[\u2000-\u206F\u2E00-\u2E7F\\'!"#\$%&\(\)\*\+,\-\.\/:;<=>\?@\[\]\^_`\{\|\}~]/),reLinkTitle=new RegExp('^(?:"('+ESCAPED_CHAR+'|[^"\\x00])*"|\'('+ESCAPED_CHAR+"|[^'\\x00])*'|\\(("+ESCAPED_CHAR+"|[^)\\x00])*\\))"),reLinkDestinationBraces=new RegExp("^(?:[<](?:[^<>\\n\\\\\\x00]|"+ESCAPED_CHAR+"|\\\\)*[>])"),reLinkDestination=new RegExp("^(?:"+REG_CHAR+"+|"+ESCAPED_CHAR+"|\\\\|"+IN_PARENS_NOSP+")*"),reEscapable=new RegExp("^"+ESCAPABLE),reEntityHere=new RegExp("^"+ENTITY,"i"),reTicks=/`+/,reTicksHere=/^`+/,reEllipses=/\.\.\./g,reDash=/--+/g,reEmailAutolink=/^<([a-zA-Z0-9.!#$%&'*+\/=?^_`{|}~-]+@[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?(?:\.[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?)*)>/,reAutolink=/^<(?:coap|doi|javascript|aaa|aaas|about|acap|cap|cid|crid|data|dav|dict|dns|file|ftp|geo|go|gopher|h323|http|https|iax|icap|im|imap|info|ipp|iris|iris.beep|iris.xpc|iris.xpcs|iris.lwz|ldap|mailto|mid|msrp|msrps|mtqp|mupdate|news|nfs|ni|nih|nntp|opaquelocktoken|pop|pres|rtsp|service|session|shttp|sieve|sip|sips|sms|snmp|soap.beep|soap.beeps|tag|tel|telnet|tftp|thismessage|tn3270|tip|tv|urn|vemmi|ws|wss|xcon|xcon-userid|xmlrpc.beep|xmlrpc.beeps|xmpp|z39.50r|z39.50s|adiumxtra|afp|afs|aim|apt|attachment|aw|beshare|bitcoin|bolo|callto|chrome|chrome-extension|com-eventbrite-attendee|content|cvs|dlna-playsingle|dlna-playcontainer|dtn|dvb|ed2k|facetime|feed|finger|fish|gg|git|gizmoproject|gtalk|hcp|icon|ipn|irc|irc6|ircs|itms|jar|jms|keyparc|lastfm|ldaps|magnet|maps|market|message|mms|ms-help|msnim|mumble|mvn|notes|oid|palm|paparazzi|platform|proxy|psyc|query|res|resource|rmi|rsync|rtmp|secondlife|sftp|sgn|skype|smb|soldat|spotify|ssh|steam|svn|teamspeak|things|udp|unreal|ut2004|ventrilo|view-source|webcal|wtai|wyciwyg|xfire|xri|ymsgr):[^<>\x00-\x20]*>/i,reSpnl=/^ *(?:\n *)?/,reWhitespaceChar=/^\s/,reWhitespace=/\s+/g,reFinalSpace=/ *$/,reInitialSpace=/^ */,reSpaceAtEndOfLine=/^ *(?:\n|$)/,reLinkLabel=new RegExp("^\\[(?:[^\\\\\\[\\]]|"+ESCAPED_CHAR+"|\\\\){0,1000}\\]"),reMain=/^[^\n`\[\]\\!<&*_'"]+/m,text=function(s){var node=new Node("Text");return node._literal=s,node},match=function(re){var m=re.exec(this.subject.slice(this.pos));return null===m?null:(this.pos+=m.index+m[0].length,m[0])},peek=function(){return this.subject.length>this.pos?this.subject.charCodeAt(this.pos):-1},spnl=function(){return this.match(reSpnl),!0},parseBackticks=function(block){var ticks=this.match(reTicksHere);if(null===ticks)return!1;for(var matched,node,afterOpenTicks=this.pos;null!==(matched=this.match(reTicks));)if(matched===ticks)return node=new Node("Code"),node._literal=this.subject.slice(afterOpenTicks,this.pos-ticks.length).trim().replace(reWhitespace," "),block.appendChild(node),!0;return this.pos=afterOpenTicks,block.appendChild(text(ticks)),!0},parseBackslash=function(block){var node,subj=this.subject;return this.pos+=1,this.peek()===C_NEWLINE?(this.pos+=1,node=new Node("Hardbreak"),block.appendChild(node)):reEscapable.test(subj.charAt(this.pos))?(block.appendChild(text(subj.charAt(this.pos))),this.pos+=1):block.appendChild(text("\\")),!0},parseAutolink=function(block){var m,dest,node;return(m=this.match(reEmailAutolink))?(dest=m.slice(1,m.length-1),node=new Node("Link"),node._destination=normalizeURI("mailto:"+dest),node._title="",node.appendChild(text(dest)),block.appendChild(node),!0):(m=this.match(reAutolink))?(dest=m.slice(1,m.length-1),node=new Node("Link"),node._destination=normalizeURI(dest),node._title="",node.appendChild(text(dest)),block.appendChild(node),!0):!1},parseHtmlTag=function(block){var m=this.match(reHtmlTag);if(null===m)return!1;var node=new Node("Html");return node._literal=m,block.appendChild(node),!0},scanDelims=function(cc){var char_before,char_after,cc_after,left_flanking,right_flanking,can_open,can_close,after_is_whitespace,after_is_punctuation,before_is_whitespace,before_is_punctuation,numdelims=0,startpos=this.pos;if(cc===C_SINGLEQUOTE||cc===C_DOUBLEQUOTE)numdelims++,this.pos++;else for(;this.peek()===cc;)numdelims++,this.pos++;return 0===numdelims?null:(char_before=0===startpos?"\n":this.subject.charAt(startpos-1),cc_after=this.peek(),char_after=-1===cc_after?"\n":fromCodePoint(cc_after),after_is_whitespace=reWhitespaceChar.test(char_after),after_is_punctuation=rePunctuation.test(char_after),before_is_whitespace=reWhitespaceChar.test(char_before),before_is_punctuation=rePunctuation.test(char_before),left_flanking=!(after_is_whitespace||after_is_punctuation&&!before_is_whitespace&&!before_is_punctuation),right_flanking=!(before_is_whitespace||before_is_punctuation&&!after_is_whitespace&&!after_is_punctuation),cc===C_UNDERSCORE?(can_open=left_flanking&&(!right_flanking||before_is_punctuation),can_close=right_flanking&&(!left_flanking||after_is_punctuation)):cc===C_SINGLEQUOTE||cc===C_DOUBLEQUOTE?(can_open=left_flanking&&!right_flanking,can_close=right_flanking):(can_open=left_flanking,can_close=right_flanking),this.pos=startpos,{numdelims:numdelims,can_open:can_open,can_close:can_close})},handleDelim=function(cc,block){var res=this.scanDelims(cc);if(!res)return!1;var contents,numdelims=res.numdelims,startpos=this.pos;this.pos+=numdelims,contents=cc===C_SINGLEQUOTE?"’":cc===C_DOUBLEQUOTE?"“":this.subject.slice(startpos,this.pos);var node=text(contents);return block.appendChild(node),this.delimiters={cc:cc,numdelims:numdelims,node:node,previous:this.delimiters,next:null,can_open:res.can_open,can_close:res.can_close,active:!0},null!==this.delimiters.previous&&(this.delimiters.previous.next=this.delimiters),!0},removeDelimiter=function(delim){null!==delim.previous&&(delim.previous.next=delim.next),null===delim.next?this.delimiters=delim.previous:delim.next.previous=delim.previous},removeDelimitersBetween=function(bottom,top){bottom.next!==top&&(bottom.next=top,top.previous=bottom)},processEmphasis=function(stack_bottom){var opener,closer,old_closer,opener_inl,closer_inl,tempstack,use_delims,tmp,next,opener_found,openers_bottom=[];for(openers_bottom[C_UNDERSCORE]=stack_bottom,openers_bottom[C_ASTERISK]=stack_bottom,openers_bottom[C_SINGLEQUOTE]=stack_bottom,openers_bottom[C_DOUBLEQUOTE]=stack_bottom,closer=this.delimiters;null!==closer&&closer.previous!==stack_bottom;)closer=closer.previous;for(;null!==closer;){var closercc=closer.cc;if(!closer.can_close||closercc!==C_UNDERSCORE&&closercc!==C_ASTERISK&&closercc!==C_SINGLEQUOTE&&closercc!==C_DOUBLEQUOTE)closer=closer.next;else{for(opener=closer.previous,opener_found=!1;null!==opener&&opener!==stack_bottom&&opener!==openers_bottom[closercc];){if(opener.cc===closer.cc&&opener.can_open){opener_found=!0;break}opener=opener.previous}if(old_closer=closer,closercc===C_ASTERISK||closercc===C_UNDERSCORE)if(opener_found){use_delims=3>closer.numdelims||3>opener.numdelims?opener.numdelims>=closer.numdelims?closer.numdelims:opener.numdelims:closer.numdelims%2===0?2:1,opener_inl=opener.node,closer_inl=closer.node,opener.numdelims-=use_delims,closer.numdelims-=use_delims,opener_inl._literal=opener_inl._literal.slice(0,opener_inl._literal.length-use_delims),closer_inl._literal=closer_inl._literal.slice(0,closer_inl._literal.length-use_delims);var emph=new Node(1===use_delims?"Emph":"Strong");for(tmp=opener_inl._next;tmp&&tmp!==closer_inl;)next=tmp._next,tmp.unlink(),emph.appendChild(tmp),tmp=next;opener_inl.insertAfter(emph),removeDelimitersBetween(opener,closer),0===opener.numdelims&&(opener_inl.unlink(),this.removeDelimiter(opener)),0===closer.numdelims&&(closer_inl.unlink(),tempstack=closer.next,this.removeDelimiter(closer),closer=tempstack)}else closer=closer.next;else closercc===C_SINGLEQUOTE?(closer.node._literal="’",opener_found&&(opener.node._literal="‘"),closer=closer.next):closercc===C_DOUBLEQUOTE&&(closer.node._literal="”",opener_found&&(opener.node.literal="“"),closer=closer.next);opener_found||(openers_bottom[closercc]=old_closer.previous,old_closer.can_open||this.removeDelimiter(old_closer))}}for(;null!==this.delimiters&&this.delimiters!==stack_bottom;)this.removeDelimiter(this.delimiters)},parseLinkTitle=function(){var title=this.match(reLinkTitle);return null===title?null:unescapeString(title.substr(1,title.length-2))},parseLinkDestination=function(){var res=this.match(reLinkDestinationBraces);return null===res?(res=this.match(reLinkDestination),null===res?null:normalizeURI(unescapeString(res))):normalizeURI(unescapeString(res.substr(1,res.length-2)))},parseLinkLabel=function(){var m=this.match(reLinkLabel); +return null===m||m.length>1001?0:m.length},parseOpenBracket=function(block){var startpos=this.pos;this.pos+=1;var node=text("[");return block.appendChild(node),this.delimiters={cc:C_OPEN_BRACKET,numdelims:1,node:node,previous:this.delimiters,next:null,can_open:!0,can_close:!1,index:startpos,active:!0},null!==this.delimiters.previous&&(this.delimiters.previous.next=this.delimiters),!0},parseBang=function(block){var startpos=this.pos;if(this.pos+=1,this.peek()===C_OPEN_BRACKET){this.pos+=1;var node=text("![");block.appendChild(node),this.delimiters={cc:C_BANG,numdelims:1,node:node,previous:this.delimiters,next:null,can_open:!0,can_close:!1,index:startpos+1,active:!0},null!==this.delimiters.previous&&(this.delimiters.previous.next=this.delimiters)}else block.appendChild(text("!"));return!0},parseCloseBracket=function(block){var startpos,is_image,dest,title,reflabel,opener,matched=!1;for(this.pos+=1,startpos=this.pos,opener=this.delimiters;null!==opener&&opener.cc!==C_OPEN_BRACKET&&opener.cc!==C_BANG;)opener=opener.previous;if(null===opener)return block.appendChild(text("]")),!0;if(!opener.active)return block.appendChild(text("]")),this.removeDelimiter(opener),!0;if(is_image=opener.cc===C_BANG,this.peek()===C_OPEN_PAREN)this.pos++,this.spnl()&&null!==(dest=this.parseLinkDestination())&&this.spnl()&&this.spnl()&&this.peek()===C_CLOSE_PAREN&&(this.pos+=1,matched=!0);else{var savepos=this.pos;this.spnl();var beforelabel=this.pos,n=this.parseLinkLabel();reflabel=0===n||2===n?this.subject.slice(opener.index,startpos):this.subject.slice(beforelabel,beforelabel+n),0===n&&(this.pos=savepos);var link=this.refmap[normalizeReference(reflabel)];link&&(dest=link.destination,title=link.title,matched=!0)}if(matched){var node=new Node(is_image?"Image":"Link");node._destination=dest,node._title=title||"";var tmp,next;for(tmp=opener.node._next;tmp;)next=tmp._next,tmp.unlink(),node.appendChild(tmp),tmp=next;if(block.appendChild(node),this.processEmphasis(opener.previous),opener.node.unlink(),!is_image)for(opener=this.delimiters;null!==opener;)opener.cc===C_OPEN_BRACKET&&(opener.active=!1),opener=opener.previous;return!0}return this.removeDelimiter(opener),this.pos=startpos,block.appendChild(text("]")),!0},parseEntity=function(block){var m;return(m=this.match(reEntityHere))?(block.appendChild(text(decodeHTML(m))),!0):!1},parseString=function(block){var m;return(m=this.match(reMain))?(block.appendChild(text(this.options.smart?m.replace(reEllipses,"…").replace(reDash,function(chars){var enCount=0,emCount=0;return chars.length%3===0?emCount=chars.length/3:chars.length%2===0?enCount=chars.length/2:chars.length%3===2?(enCount=1,emCount=(chars.length-2)/3):(enCount=2,emCount=(chars.length-4)/3),"—".repeat(emCount)+"–".repeat(enCount)}):m)),!0):!1},parseNewline=function(block){this.pos+=1;var lastc=block._lastChild;if(lastc&&"Text"===lastc.type&&" "===lastc._literal[lastc._literal.length-1]){var hardbreak=" "===lastc._literal[lastc._literal.length-2];lastc._literal=lastc._literal.replace(reFinalSpace,""),block.appendChild(new Node(hardbreak?"Hardbreak":"Softbreak"))}else block.appendChild(new Node("Softbreak"));return this.match(reInitialSpace),!0},parseReference=function(s,refmap){this.subject=s,this.pos=0;var rawlabel,dest,title,matchChars,startpos=this.pos;if(matchChars=this.parseLinkLabel(),0===matchChars)return 0;if(rawlabel=this.subject.substr(0,matchChars),this.peek()!==C_COLON)return this.pos=startpos,0;if(this.pos++,this.spnl(),dest=this.parseLinkDestination(),null===dest||0===dest.length)return this.pos=startpos,0;var beforetitle=this.pos;this.spnl(),title=this.parseLinkTitle(),null===title&&(title="",this.pos=beforetitle);var atLineEnd=!0;if(null===this.match(reSpaceAtEndOfLine)&&(""===title?atLineEnd=!1:(title="",this.pos=beforetitle,atLineEnd=null!==this.match(reSpaceAtEndOfLine))),!atLineEnd)return this.pos=startpos,0;var normlabel=normalizeReference(rawlabel);return""===normlabel?(this.pos=startpos,0):(refmap[normlabel]||(refmap[normlabel]={destination:dest,title:title}),this.pos-startpos)},parseInline=function(block){var res=!1,c=this.peek();if(-1===c)return!1;switch(c){case C_NEWLINE:res=this.parseNewline(block);break;case C_BACKSLASH:res=this.parseBackslash(block);break;case C_BACKTICK:res=this.parseBackticks(block);break;case C_ASTERISK:case C_UNDERSCORE:res=this.handleDelim(c,block);break;case C_SINGLEQUOTE:case C_DOUBLEQUOTE:res=this.options.smart&&this.handleDelim(c,block);break;case C_OPEN_BRACKET:res=this.parseOpenBracket(block);break;case C_BANG:res=this.parseBang(block);break;case C_CLOSE_BRACKET:res=this.parseCloseBracket(block);break;case C_LESSTHAN:res=this.parseAutolink(block)||this.parseHtmlTag(block);break;case C_AMPERSAND:res=this.parseEntity(block);break;default:res=this.parseString(block)}return res||(this.pos+=1,block.appendChild(text(fromCodePoint(c)))),!0},parseInlines=function(block){for(this.subject=block._string_content.trim(),this.pos=0,this.delimiters=null;this.parseInline(block););block._string_content=null,this.processEmphasis(null)};module.exports=InlineParser},{"./common":2,"./from-code-point.js":3,"./node":7,"./normalize-reference":8,entities:10,"string.prototype.repeat":20}],7:[function(require,module,exports){"use strict";function isContainer(node){switch(node._type){case"Document":case"BlockQuote":case"List":case"Item":case"Paragraph":case"Header":case"Emph":case"Strong":case"Link":case"Image":return!0;default:return!1}}var resumeAt=function(node,entering){this.current=node,this.entering=entering===!0},next=function(){var cur=this.current,entering=this.entering;if(null===cur)return null;var container=isContainer(cur);return entering&&container?cur._firstChild?(this.current=cur._firstChild,this.entering=!0):this.entering=!1:cur===this.root?this.current=null:null===cur._next?(this.current=cur._parent,this.entering=!1):(this.current=cur._next,this.entering=!0),{entering:entering,node:cur}},NodeWalker=function(root){return{current:root,root:root,entering:!0,next:next,resumeAt:resumeAt}},Node=function(nodeType,sourcepos){this._type=nodeType,this._parent=null,this._firstChild=null,this._lastChild=null,this._prev=null,this._next=null,this._sourcepos=sourcepos,this._lastLineBlank=!1,this._open=!0,this._string_content=null,this._literal=null,this._listData=null,this._info=null,this._destination=null,this._title=null,this._isFenced=!1,this._fenceChar=null,this._fenceLength=0,this._fenceOffset=null,this._level=null},proto=Node.prototype;Object.defineProperty(proto,"isContainer",{get:function(){return isContainer(this)}}),Object.defineProperty(proto,"type",{get:function(){return this._type}}),Object.defineProperty(proto,"firstChild",{get:function(){return this._firstChild}}),Object.defineProperty(proto,"lastChild",{get:function(){return this._lastChild}}),Object.defineProperty(proto,"next",{get:function(){return this._next}}),Object.defineProperty(proto,"prev",{get:function(){return this._prev}}),Object.defineProperty(proto,"parent",{get:function(){return this._parent}}),Object.defineProperty(proto,"sourcepos",{get:function(){return this._sourcepos}}),Object.defineProperty(proto,"literal",{get:function(){return this._literal},set:function(s){this._literal=s}}),Object.defineProperty(proto,"destination",{get:function(){return this._destination},set:function(s){this._destination=s}}),Object.defineProperty(proto,"title",{get:function(){return this._title},set:function(s){this._title=s}}),Object.defineProperty(proto,"info",{get:function(){return this._info},set:function(s){this._info=s}}),Object.defineProperty(proto,"level",{get:function(){return this._level},set:function(s){this._level=s}}),Object.defineProperty(proto,"listType",{get:function(){return this._listData.type},set:function(t){this._listData.type=t}}),Object.defineProperty(proto,"listTight",{get:function(){return this._listData.tight},set:function(t){this._listData.tight=t}}),Object.defineProperty(proto,"listStart",{get:function(){return this._listData.start},set:function(n){this._listData.start=n}}),Object.defineProperty(proto,"listDelimiter",{get:function(){return this._listData.delimiter},set:function(delim){this._listData.delimiter=delim}}),Node.prototype.appendChild=function(child){child.unlink(),child._parent=this,this._lastChild?(this._lastChild._next=child,child._prev=this._lastChild,this._lastChild=child):(this._firstChild=child,this._lastChild=child)},Node.prototype.prependChild=function(child){child.unlink(),child._parent=this,this._firstChild?(this._firstChild._prev=child,child._next=this._firstChild,this._firstChild=child):(this._firstChild=child,this._lastChild=child)},Node.prototype.unlink=function(){this._prev?this._prev._next=this._next:this._parent&&(this._parent._firstChild=this._next),this._next?this._next._prev=this._prev:this._parent&&(this._parent._lastChild=this._prev),this._parent=null,this._next=null,this._prev=null},Node.prototype.insertAfter=function(sibling){sibling.unlink(),sibling._next=this._next,sibling._next&&(sibling._next._prev=sibling),sibling._prev=this,this._next=sibling,sibling._parent=this._parent,sibling._next||(sibling._parent._lastChild=sibling)},Node.prototype.insertBefore=function(sibling){sibling.unlink(),sibling._prev=this._prev,sibling._prev&&(sibling._prev._next=sibling),sibling._next=this,this._prev=sibling,sibling._parent=this._parent,sibling._prev||(sibling._parent._firstChild=sibling)},Node.prototype.walker=function(){var walker=new NodeWalker(this);return walker},module.exports=Node},{}],8:[function(require,module,exports){"use strict";var regex=/[ \t\r\n]+|[A-Z\xB5\xC0-\xD6\xD8-\xDF\u0100\u0102\u0104\u0106\u0108\u010A\u010C\u010E\u0110\u0112\u0114\u0116\u0118\u011A\u011C\u011E\u0120\u0122\u0124\u0126\u0128\u012A\u012C\u012E\u0130\u0132\u0134\u0136\u0139\u013B\u013D\u013F\u0141\u0143\u0145\u0147\u0149\u014A\u014C\u014E\u0150\u0152\u0154\u0156\u0158\u015A\u015C\u015E\u0160\u0162\u0164\u0166\u0168\u016A\u016C\u016E\u0170\u0172\u0174\u0176\u0178\u0179\u017B\u017D\u017F\u0181\u0182\u0184\u0186\u0187\u0189-\u018B\u018E-\u0191\u0193\u0194\u0196-\u0198\u019C\u019D\u019F\u01A0\u01A2\u01A4\u01A6\u01A7\u01A9\u01AC\u01AE\u01AF\u01B1-\u01B3\u01B5\u01B7\u01B8\u01BC\u01C4\u01C5\u01C7\u01C8\u01CA\u01CB\u01CD\u01CF\u01D1\u01D3\u01D5\u01D7\u01D9\u01DB\u01DE\u01E0\u01E2\u01E4\u01E6\u01E8\u01EA\u01EC\u01EE\u01F0-\u01F2\u01F4\u01F6-\u01F8\u01FA\u01FC\u01FE\u0200\u0202\u0204\u0206\u0208\u020A\u020C\u020E\u0210\u0212\u0214\u0216\u0218\u021A\u021C\u021E\u0220\u0222\u0224\u0226\u0228\u022A\u022C\u022E\u0230\u0232\u023A\u023B\u023D\u023E\u0241\u0243-\u0246\u0248\u024A\u024C\u024E\u0345\u0370\u0372\u0376\u037F\u0386\u0388-\u038A\u038C\u038E-\u03A1\u03A3-\u03AB\u03B0\u03C2\u03CF-\u03D1\u03D5\u03D6\u03D8\u03DA\u03DC\u03DE\u03E0\u03E2\u03E4\u03E6\u03E8\u03EA\u03EC\u03EE\u03F0\u03F1\u03F4\u03F5\u03F7\u03F9\u03FA\u03FD-\u042F\u0460\u0462\u0464\u0466\u0468\u046A\u046C\u046E\u0470\u0472\u0474\u0476\u0478\u047A\u047C\u047E\u0480\u048A\u048C\u048E\u0490\u0492\u0494\u0496\u0498\u049A\u049C\u049E\u04A0\u04A2\u04A4\u04A6\u04A8\u04AA\u04AC\u04AE\u04B0\u04B2\u04B4\u04B6\u04B8\u04BA\u04BC\u04BE\u04C0\u04C1\u04C3\u04C5\u04C7\u04C9\u04CB\u04CD\u04D0\u04D2\u04D4\u04D6\u04D8\u04DA\u04DC\u04DE\u04E0\u04E2\u04E4\u04E6\u04E8\u04EA\u04EC\u04EE\u04F0\u04F2\u04F4\u04F6\u04F8\u04FA\u04FC\u04FE\u0500\u0502\u0504\u0506\u0508\u050A\u050C\u050E\u0510\u0512\u0514\u0516\u0518\u051A\u051C\u051E\u0520\u0522\u0524\u0526\u0528\u052A\u052C\u052E\u0531-\u0556\u0587\u10A0-\u10C5\u10C7\u10CD\u1E00\u1E02\u1E04\u1E06\u1E08\u1E0A\u1E0C\u1E0E\u1E10\u1E12\u1E14\u1E16\u1E18\u1E1A\u1E1C\u1E1E\u1E20\u1E22\u1E24\u1E26\u1E28\u1E2A\u1E2C\u1E2E\u1E30\u1E32\u1E34\u1E36\u1E38\u1E3A\u1E3C\u1E3E\u1E40\u1E42\u1E44\u1E46\u1E48\u1E4A\u1E4C\u1E4E\u1E50\u1E52\u1E54\u1E56\u1E58\u1E5A\u1E5C\u1E5E\u1E60\u1E62\u1E64\u1E66\u1E68\u1E6A\u1E6C\u1E6E\u1E70\u1E72\u1E74\u1E76\u1E78\u1E7A\u1E7C\u1E7E\u1E80\u1E82\u1E84\u1E86\u1E88\u1E8A\u1E8C\u1E8E\u1E90\u1E92\u1E94\u1E96-\u1E9B\u1E9E\u1EA0\u1EA2\u1EA4\u1EA6\u1EA8\u1EAA\u1EAC\u1EAE\u1EB0\u1EB2\u1EB4\u1EB6\u1EB8\u1EBA\u1EBC\u1EBE\u1EC0\u1EC2\u1EC4\u1EC6\u1EC8\u1ECA\u1ECC\u1ECE\u1ED0\u1ED2\u1ED4\u1ED6\u1ED8\u1EDA\u1EDC\u1EDE\u1EE0\u1EE2\u1EE4\u1EE6\u1EE8\u1EEA\u1EEC\u1EEE\u1EF0\u1EF2\u1EF4\u1EF6\u1EF8\u1EFA\u1EFC\u1EFE\u1F08-\u1F0F\u1F18-\u1F1D\u1F28-\u1F2F\u1F38-\u1F3F\u1F48-\u1F4D\u1F50\u1F52\u1F54\u1F56\u1F59\u1F5B\u1F5D\u1F5F\u1F68-\u1F6F\u1F80-\u1FAF\u1FB2-\u1FB4\u1FB6-\u1FBC\u1FBE\u1FC2-\u1FC4\u1FC6-\u1FCC\u1FD2\u1FD3\u1FD6-\u1FDB\u1FE2-\u1FE4\u1FE6-\u1FEC\u1FF2-\u1FF4\u1FF6-\u1FFC\u2126\u212A\u212B\u2132\u2160-\u216F\u2183\u24B6-\u24CF\u2C00-\u2C2E\u2C60\u2C62-\u2C64\u2C67\u2C69\u2C6B\u2C6D-\u2C70\u2C72\u2C75\u2C7E-\u2C80\u2C82\u2C84\u2C86\u2C88\u2C8A\u2C8C\u2C8E\u2C90\u2C92\u2C94\u2C96\u2C98\u2C9A\u2C9C\u2C9E\u2CA0\u2CA2\u2CA4\u2CA6\u2CA8\u2CAA\u2CAC\u2CAE\u2CB0\u2CB2\u2CB4\u2CB6\u2CB8\u2CBA\u2CBC\u2CBE\u2CC0\u2CC2\u2CC4\u2CC6\u2CC8\u2CCA\u2CCC\u2CCE\u2CD0\u2CD2\u2CD4\u2CD6\u2CD8\u2CDA\u2CDC\u2CDE\u2CE0\u2CE2\u2CEB\u2CED\u2CF2\uA640\uA642\uA644\uA646\uA648\uA64A\uA64C\uA64E\uA650\uA652\uA654\uA656\uA658\uA65A\uA65C\uA65E\uA660\uA662\uA664\uA666\uA668\uA66A\uA66C\uA680\uA682\uA684\uA686\uA688\uA68A\uA68C\uA68E\uA690\uA692\uA694\uA696\uA698\uA69A\uA722\uA724\uA726\uA728\uA72A\uA72C\uA72E\uA732\uA734\uA736\uA738\uA73A\uA73C\uA73E\uA740\uA742\uA744\uA746\uA748\uA74A\uA74C\uA74E\uA750\uA752\uA754\uA756\uA758\uA75A\uA75C\uA75E\uA760\uA762\uA764\uA766\uA768\uA76A\uA76C\uA76E\uA779\uA77B\uA77D\uA77E\uA780\uA782\uA784\uA786\uA78B\uA78D\uA790\uA792\uA796\uA798\uA79A\uA79C\uA79E\uA7A0\uA7A2\uA7A4\uA7A6\uA7A8\uA7AA-\uA7AD\uA7B0\uA7B1\uFB00-\uFB06\uFB13-\uFB17\uFF21-\uFF3A]|\uD801[\uDC00-\uDC27]|\uD806[\uDCA0-\uDCBF]/g,map={A:"a",B:"b",C:"c",D:"d",E:"e",F:"f",G:"g",H:"h",I:"i",J:"j",K:"k",L:"l",M:"m",N:"n",O:"o",P:"p",Q:"q",R:"r",S:"s",T:"t",U:"u",V:"v",W:"w",X:"x",Y:"y",Z:"z","µ":"μ","À":"à","Á":"á","Â":"â","Ã":"ã","Ä":"ä","Å":"å","Æ":"æ","Ç":"ç","È":"è","É":"é","Ê":"ê","Ë":"ë","Ì":"ì","Í":"í","Î":"î","Ï":"ï","Ð":"ð","Ñ":"ñ","Ò":"ò","Ó":"ó","Ô":"ô","Õ":"õ","Ö":"ö","Ø":"ø","Ù":"ù","Ú":"ú","Û":"û","Ü":"ü","Ý":"ý","Þ":"þ","Ā":"ā","Ă":"ă","Ą":"ą","Ć":"ć","Ĉ":"ĉ","Ċ":"ċ","Č":"č","Ď":"ď","Đ":"đ","Ē":"ē","Ĕ":"ĕ","Ė":"ė","Ę":"ę","Ě":"ě","Ĝ":"ĝ","Ğ":"ğ","Ġ":"ġ","Ģ":"ģ","Ĥ":"ĥ","Ħ":"ħ","Ĩ":"ĩ","Ī":"ī","Ĭ":"ĭ","Į":"į","IJ":"ij","Ĵ":"ĵ","Ķ":"ķ","Ĺ":"ĺ","Ļ":"ļ","Ľ":"ľ","Ŀ":"ŀ","Ł":"ł","Ń":"ń","Ņ":"ņ","Ň":"ň","Ŋ":"ŋ","Ō":"ō","Ŏ":"ŏ","Ő":"ő","Œ":"œ","Ŕ":"ŕ","Ŗ":"ŗ","Ř":"ř","Ś":"ś","Ŝ":"ŝ","Ş":"ş","Š":"š","Ţ":"ţ","Ť":"ť","Ŧ":"ŧ","Ũ":"ũ","Ū":"ū","Ŭ":"ŭ","Ů":"ů","Ű":"ű","Ų":"ų","Ŵ":"ŵ","Ŷ":"ŷ","Ÿ":"ÿ","Ź":"ź","Ż":"ż","Ž":"ž","ſ":"s","Ɓ":"ɓ","Ƃ":"ƃ","Ƅ":"ƅ","Ɔ":"ɔ","Ƈ":"ƈ","Ɖ":"ɖ","Ɗ":"ɗ","Ƌ":"ƌ","Ǝ":"ǝ","Ə":"ə","Ɛ":"ɛ","Ƒ":"ƒ","Ɠ":"ɠ","Ɣ":"ɣ","Ɩ":"ɩ","Ɨ":"ɨ","Ƙ":"ƙ","Ɯ":"ɯ","Ɲ":"ɲ","Ɵ":"ɵ","Ơ":"ơ","Ƣ":"ƣ","Ƥ":"ƥ","Ʀ":"ʀ","Ƨ":"ƨ","Ʃ":"ʃ","Ƭ":"ƭ","Ʈ":"ʈ","Ư":"ư","Ʊ":"ʊ","Ʋ":"ʋ","Ƴ":"ƴ","Ƶ":"ƶ","Ʒ":"ʒ","Ƹ":"ƹ","Ƽ":"ƽ","DŽ":"dž","Dž":"dž","LJ":"lj","Lj":"lj","NJ":"nj","Nj":"nj","Ǎ":"ǎ","Ǐ":"ǐ","Ǒ":"ǒ","Ǔ":"ǔ","Ǖ":"ǖ","Ǘ":"ǘ","Ǚ":"ǚ","Ǜ":"ǜ","Ǟ":"ǟ","Ǡ":"ǡ","Ǣ":"ǣ","Ǥ":"ǥ","Ǧ":"ǧ","Ǩ":"ǩ","Ǫ":"ǫ","Ǭ":"ǭ","Ǯ":"ǯ","DZ":"dz","Dz":"dz","Ǵ":"ǵ","Ƕ":"ƕ","Ƿ":"ƿ","Ǹ":"ǹ","Ǻ":"ǻ","Ǽ":"ǽ","Ǿ":"ǿ","Ȁ":"ȁ","Ȃ":"ȃ","Ȅ":"ȅ","Ȇ":"ȇ","Ȉ":"ȉ","Ȋ":"ȋ","Ȍ":"ȍ","Ȏ":"ȏ","Ȑ":"ȑ","Ȓ":"ȓ","Ȕ":"ȕ","Ȗ":"ȗ","Ș":"ș","Ț":"ț","Ȝ":"ȝ","Ȟ":"ȟ","Ƞ":"ƞ","Ȣ":"ȣ","Ȥ":"ȥ","Ȧ":"ȧ","Ȩ":"ȩ","Ȫ":"ȫ","Ȭ":"ȭ","Ȯ":"ȯ","Ȱ":"ȱ","Ȳ":"ȳ","Ⱥ":"ⱥ","Ȼ":"ȼ","Ƚ":"ƚ","Ⱦ":"ⱦ","Ɂ":"ɂ","Ƀ":"ƀ","Ʉ":"ʉ","Ʌ":"ʌ","Ɇ":"ɇ","Ɉ":"ɉ","Ɋ":"ɋ","Ɍ":"ɍ","Ɏ":"ɏ","ͅ":"ι","Ͱ":"ͱ","Ͳ":"ͳ","Ͷ":"ͷ","Ϳ":"ϳ","Ά":"ά","Έ":"έ","Ή":"ή","Ί":"ί","Ό":"ό","Ύ":"ύ","Ώ":"ώ","Α":"α","Β":"β","Γ":"γ","Δ":"δ","Ε":"ε","Ζ":"ζ","Η":"η","Θ":"θ","Ι":"ι","Κ":"κ","Λ":"λ","Μ":"μ","Ν":"ν","Ξ":"ξ","Ο":"ο","Π":"π","Ρ":"ρ","Σ":"σ","Τ":"τ","Υ":"υ","Φ":"φ","Χ":"χ","Ψ":"ψ","Ω":"ω","Ϊ":"ϊ","Ϋ":"ϋ","ς":"σ","Ϗ":"ϗ","ϐ":"β","ϑ":"θ","ϕ":"φ","ϖ":"π","Ϙ":"ϙ","Ϛ":"ϛ","Ϝ":"ϝ","Ϟ":"ϟ","Ϡ":"ϡ","Ϣ":"ϣ","Ϥ":"ϥ","Ϧ":"ϧ","Ϩ":"ϩ","Ϫ":"ϫ","Ϭ":"ϭ","Ϯ":"ϯ","ϰ":"κ","ϱ":"ρ","ϴ":"θ","ϵ":"ε","Ϸ":"ϸ","Ϲ":"ϲ","Ϻ":"ϻ","Ͻ":"ͻ","Ͼ":"ͼ","Ͽ":"ͽ","Ѐ":"ѐ","Ё":"ё","Ђ":"ђ","Ѓ":"ѓ","Є":"є","Ѕ":"ѕ","І":"і","Ї":"ї","Ј":"ј","Љ":"љ","Њ":"њ","Ћ":"ћ","Ќ":"ќ","Ѝ":"ѝ","Ў":"ў","Џ":"џ","А":"а","Б":"б","В":"в","Г":"г","Д":"д","Е":"е","Ж":"ж","З":"з","И":"и","Й":"й","К":"к","Л":"л","М":"м","Н":"н","О":"о","П":"п","Р":"р","С":"с","Т":"т","У":"у","Ф":"ф","Х":"х","Ц":"ц","Ч":"ч","Ш":"ш","Щ":"щ","Ъ":"ъ","Ы":"ы","Ь":"ь","Э":"э","Ю":"ю","Я":"я","Ѡ":"ѡ","Ѣ":"ѣ","Ѥ":"ѥ","Ѧ":"ѧ","Ѩ":"ѩ","Ѫ":"ѫ","Ѭ":"ѭ","Ѯ":"ѯ","Ѱ":"ѱ","Ѳ":"ѳ","Ѵ":"ѵ","Ѷ":"ѷ","Ѹ":"ѹ","Ѻ":"ѻ","Ѽ":"ѽ","Ѿ":"ѿ","Ҁ":"ҁ","Ҋ":"ҋ","Ҍ":"ҍ","Ҏ":"ҏ","Ґ":"ґ","Ғ":"ғ","Ҕ":"ҕ","Җ":"җ","Ҙ":"ҙ","Қ":"қ","Ҝ":"ҝ","Ҟ":"ҟ","Ҡ":"ҡ","Ң":"ң","Ҥ":"ҥ","Ҧ":"ҧ","Ҩ":"ҩ","Ҫ":"ҫ","Ҭ":"ҭ","Ү":"ү","Ұ":"ұ","Ҳ":"ҳ","Ҵ":"ҵ","Ҷ":"ҷ","Ҹ":"ҹ","Һ":"һ","Ҽ":"ҽ","Ҿ":"ҿ","Ӏ":"ӏ","Ӂ":"ӂ","Ӄ":"ӄ","Ӆ":"ӆ","Ӈ":"ӈ","Ӊ":"ӊ","Ӌ":"ӌ","Ӎ":"ӎ","Ӑ":"ӑ","Ӓ":"ӓ","Ӕ":"ӕ","Ӗ":"ӗ","Ә":"ә","Ӛ":"ӛ","Ӝ":"ӝ","Ӟ":"ӟ","Ӡ":"ӡ","Ӣ":"ӣ","Ӥ":"ӥ","Ӧ":"ӧ","Ө":"ө","Ӫ":"ӫ","Ӭ":"ӭ","Ӯ":"ӯ","Ӱ":"ӱ","Ӳ":"ӳ","Ӵ":"ӵ","Ӷ":"ӷ","Ӹ":"ӹ","Ӻ":"ӻ","Ӽ":"ӽ","Ӿ":"ӿ","Ԁ":"ԁ","Ԃ":"ԃ","Ԅ":"ԅ","Ԇ":"ԇ","Ԉ":"ԉ","Ԋ":"ԋ","Ԍ":"ԍ","Ԏ":"ԏ","Ԑ":"ԑ","Ԓ":"ԓ","Ԕ":"ԕ","Ԗ":"ԗ","Ԙ":"ԙ","Ԛ":"ԛ","Ԝ":"ԝ","Ԟ":"ԟ","Ԡ":"ԡ","Ԣ":"ԣ","Ԥ":"ԥ","Ԧ":"ԧ","Ԩ":"ԩ","Ԫ":"ԫ","Ԭ":"ԭ","Ԯ":"ԯ","Ա":"ա","Բ":"բ","Գ":"գ","Դ":"դ","Ե":"ե","Զ":"զ","Է":"է","Ը":"ը","Թ":"թ","Ժ":"ժ","Ի":"ի","Լ":"լ","Խ":"խ","Ծ":"ծ","Կ":"կ","Հ":"հ","Ձ":"ձ","Ղ":"ղ","Ճ":"ճ","Մ":"մ","Յ":"յ","Ն":"ն","Շ":"շ","Ո":"ո","Չ":"չ","Պ":"պ","Ջ":"ջ","Ռ":"ռ","Ս":"ս","Վ":"վ","Տ":"տ","Ր":"ր","Ց":"ց","Ւ":"ւ","Փ":"փ","Ք":"ք","Օ":"օ","Ֆ":"ֆ","Ⴀ":"ⴀ","Ⴁ":"ⴁ","Ⴂ":"ⴂ","Ⴃ":"ⴃ","Ⴄ":"ⴄ","Ⴅ":"ⴅ","Ⴆ":"ⴆ","Ⴇ":"ⴇ","Ⴈ":"ⴈ","Ⴉ":"ⴉ","Ⴊ":"ⴊ","Ⴋ":"ⴋ","Ⴌ":"ⴌ","Ⴍ":"ⴍ","Ⴎ":"ⴎ","Ⴏ":"ⴏ","Ⴐ":"ⴐ","Ⴑ":"ⴑ","Ⴒ":"ⴒ","Ⴓ":"ⴓ","Ⴔ":"ⴔ","Ⴕ":"ⴕ","Ⴖ":"ⴖ","Ⴗ":"ⴗ","Ⴘ":"ⴘ","Ⴙ":"ⴙ","Ⴚ":"ⴚ","Ⴛ":"ⴛ","Ⴜ":"ⴜ","Ⴝ":"ⴝ","Ⴞ":"ⴞ","Ⴟ":"ⴟ","Ⴠ":"ⴠ","Ⴡ":"ⴡ","Ⴢ":"ⴢ","Ⴣ":"ⴣ","Ⴤ":"ⴤ","Ⴥ":"ⴥ","Ⴧ":"ⴧ","Ⴭ":"ⴭ","Ḁ":"ḁ","Ḃ":"ḃ","Ḅ":"ḅ","Ḇ":"ḇ","Ḉ":"ḉ","Ḋ":"ḋ","Ḍ":"ḍ","Ḏ":"ḏ","Ḑ":"ḑ","Ḓ":"ḓ","Ḕ":"ḕ","Ḗ":"ḗ","Ḙ":"ḙ","Ḛ":"ḛ","Ḝ":"ḝ","Ḟ":"ḟ","Ḡ":"ḡ","Ḣ":"ḣ","Ḥ":"ḥ","Ḧ":"ḧ","Ḩ":"ḩ","Ḫ":"ḫ","Ḭ":"ḭ","Ḯ":"ḯ","Ḱ":"ḱ","Ḳ":"ḳ","Ḵ":"ḵ","Ḷ":"ḷ","Ḹ":"ḹ","Ḻ":"ḻ","Ḽ":"ḽ","Ḿ":"ḿ","Ṁ":"ṁ","Ṃ":"ṃ","Ṅ":"ṅ","Ṇ":"ṇ","Ṉ":"ṉ","Ṋ":"ṋ","Ṍ":"ṍ","Ṏ":"ṏ","Ṑ":"ṑ","Ṓ":"ṓ","Ṕ":"ṕ","Ṗ":"ṗ","Ṙ":"ṙ","Ṛ":"ṛ","Ṝ":"ṝ","Ṟ":"ṟ","Ṡ":"ṡ","Ṣ":"ṣ","Ṥ":"ṥ","Ṧ":"ṧ","Ṩ":"ṩ","Ṫ":"ṫ","Ṭ":"ṭ","Ṯ":"ṯ","Ṱ":"ṱ","Ṳ":"ṳ","Ṵ":"ṵ","Ṷ":"ṷ","Ṹ":"ṹ","Ṻ":"ṻ","Ṽ":"ṽ","Ṿ":"ṿ","Ẁ":"ẁ","Ẃ":"ẃ","Ẅ":"ẅ","Ẇ":"ẇ","Ẉ":"ẉ","Ẋ":"ẋ","Ẍ":"ẍ","Ẏ":"ẏ","Ẑ":"ẑ","Ẓ":"ẓ","Ẕ":"ẕ","ẛ":"ṡ","Ạ":"ạ","Ả":"ả","Ấ":"ấ","Ầ":"ầ","Ẩ":"ẩ","Ẫ":"ẫ","Ậ":"ậ","Ắ":"ắ","Ằ":"ằ","Ẳ":"ẳ","Ẵ":"ẵ","Ặ":"ặ","Ẹ":"ẹ","Ẻ":"ẻ","Ẽ":"ẽ","Ế":"ế","Ề":"ề","Ể":"ể","Ễ":"ễ","Ệ":"ệ","Ỉ":"ỉ","Ị":"ị","Ọ":"ọ","Ỏ":"ỏ","Ố":"ố","Ồ":"ồ","Ổ":"ổ","Ỗ":"ỗ","Ộ":"ộ","Ớ":"ớ","Ờ":"ờ","Ở":"ở","Ỡ":"ỡ","Ợ":"ợ","Ụ":"ụ","Ủ":"ủ","Ứ":"ứ","Ừ":"ừ","Ử":"ử","Ữ":"ữ","Ự":"ự","Ỳ":"ỳ","Ỵ":"ỵ","Ỷ":"ỷ","Ỹ":"ỹ","Ỻ":"ỻ","Ỽ":"ỽ","Ỿ":"ỿ","Ἀ":"ἀ","Ἁ":"ἁ","Ἂ":"ἂ","Ἃ":"ἃ","Ἄ":"ἄ","Ἅ":"ἅ","Ἆ":"ἆ","Ἇ":"ἇ","Ἐ":"ἐ","Ἑ":"ἑ","Ἒ":"ἒ","Ἓ":"ἓ","Ἔ":"ἔ","Ἕ":"ἕ","Ἠ":"ἠ","Ἡ":"ἡ","Ἢ":"ἢ","Ἣ":"ἣ","Ἤ":"ἤ","Ἥ":"ἥ","Ἦ":"ἦ","Ἧ":"ἧ","Ἰ":"ἰ","Ἱ":"ἱ","Ἲ":"ἲ","Ἳ":"ἳ","Ἴ":"ἴ","Ἵ":"ἵ","Ἶ":"ἶ","Ἷ":"ἷ","Ὀ":"ὀ","Ὁ":"ὁ","Ὂ":"ὂ","Ὃ":"ὃ","Ὄ":"ὄ","Ὅ":"ὅ","Ὑ":"ὑ","Ὓ":"ὓ","Ὕ":"ὕ","Ὗ":"ὗ","Ὠ":"ὠ","Ὡ":"ὡ","Ὢ":"ὢ","Ὣ":"ὣ","Ὤ":"ὤ","Ὥ":"ὥ","Ὦ":"ὦ","Ὧ":"ὧ","Ᾰ":"ᾰ","Ᾱ":"ᾱ","Ὰ":"ὰ","Ά":"ά","ι":"ι","Ὲ":"ὲ","Έ":"έ","Ὴ":"ὴ","Ή":"ή","Ῐ":"ῐ","Ῑ":"ῑ","Ὶ":"ὶ","Ί":"ί","Ῠ":"ῠ","Ῡ":"ῡ","Ὺ":"ὺ","Ύ":"ύ","Ῥ":"ῥ","Ὸ":"ὸ","Ό":"ό","Ὼ":"ὼ","Ώ":"ώ","Ω":"ω","K":"k","Å":"å","Ⅎ":"ⅎ","Ⅰ":"ⅰ","Ⅱ":"ⅱ","Ⅲ":"ⅲ","Ⅳ":"ⅳ","Ⅴ":"ⅴ","Ⅵ":"ⅵ","Ⅶ":"ⅶ","Ⅷ":"ⅷ","Ⅸ":"ⅸ","Ⅹ":"ⅹ","Ⅺ":"ⅺ","Ⅻ":"ⅻ","Ⅼ":"ⅼ","Ⅽ":"ⅽ","Ⅾ":"ⅾ","Ⅿ":"ⅿ","Ↄ":"ↄ","Ⓐ":"ⓐ","Ⓑ":"ⓑ","Ⓒ":"ⓒ","Ⓓ":"ⓓ","Ⓔ":"ⓔ","Ⓕ":"ⓕ","Ⓖ":"ⓖ","Ⓗ":"ⓗ","Ⓘ":"ⓘ","Ⓙ":"ⓙ","Ⓚ":"ⓚ","Ⓛ":"ⓛ","Ⓜ":"ⓜ","Ⓝ":"ⓝ","Ⓞ":"ⓞ","Ⓟ":"ⓟ","Ⓠ":"ⓠ","Ⓡ":"ⓡ","Ⓢ":"ⓢ","Ⓣ":"ⓣ","Ⓤ":"ⓤ","Ⓥ":"ⓥ","Ⓦ":"ⓦ","Ⓧ":"ⓧ","Ⓨ":"ⓨ","Ⓩ":"ⓩ","Ⰰ":"ⰰ","Ⰱ":"ⰱ","Ⰲ":"ⰲ","Ⰳ":"ⰳ","Ⰴ":"ⰴ","Ⰵ":"ⰵ","Ⰶ":"ⰶ","Ⰷ":"ⰷ","Ⰸ":"ⰸ","Ⰹ":"ⰹ","Ⰺ":"ⰺ","Ⰻ":"ⰻ","Ⰼ":"ⰼ","Ⰽ":"ⰽ","Ⰾ":"ⰾ","Ⰿ":"ⰿ","Ⱀ":"ⱀ","Ⱁ":"ⱁ","Ⱂ":"ⱂ","Ⱃ":"ⱃ","Ⱄ":"ⱄ","Ⱅ":"ⱅ","Ⱆ":"ⱆ","Ⱇ":"ⱇ","Ⱈ":"ⱈ","Ⱉ":"ⱉ","Ⱊ":"ⱊ","Ⱋ":"ⱋ","Ⱌ":"ⱌ","Ⱍ":"ⱍ","Ⱎ":"ⱎ","Ⱏ":"ⱏ","Ⱐ":"ⱐ","Ⱑ":"ⱑ","Ⱒ":"ⱒ","Ⱓ":"ⱓ","Ⱔ":"ⱔ","Ⱕ":"ⱕ","Ⱖ":"ⱖ","Ⱗ":"ⱗ","Ⱘ":"ⱘ","Ⱙ":"ⱙ","Ⱚ":"ⱚ","Ⱛ":"ⱛ","Ⱜ":"ⱜ","Ⱝ":"ⱝ","Ⱞ":"ⱞ","Ⱡ":"ⱡ","Ɫ":"ɫ","Ᵽ":"ᵽ","Ɽ":"ɽ","Ⱨ":"ⱨ","Ⱪ":"ⱪ","Ⱬ":"ⱬ","Ɑ":"ɑ","Ɱ":"ɱ","Ɐ":"ɐ","Ɒ":"ɒ","Ⱳ":"ⱳ","Ⱶ":"ⱶ","Ȿ":"ȿ","Ɀ":"ɀ","Ⲁ":"ⲁ","Ⲃ":"ⲃ","Ⲅ":"ⲅ","Ⲇ":"ⲇ","Ⲉ":"ⲉ","Ⲋ":"ⲋ","Ⲍ":"ⲍ","Ⲏ":"ⲏ","Ⲑ":"ⲑ","Ⲓ":"ⲓ","Ⲕ":"ⲕ","Ⲗ":"ⲗ","Ⲙ":"ⲙ","Ⲛ":"ⲛ","Ⲝ":"ⲝ","Ⲟ":"ⲟ","Ⲡ":"ⲡ","Ⲣ":"ⲣ","Ⲥ":"ⲥ","Ⲧ":"ⲧ","Ⲩ":"ⲩ","Ⲫ":"ⲫ","Ⲭ":"ⲭ","Ⲯ":"ⲯ","Ⲱ":"ⲱ","Ⲳ":"ⲳ","Ⲵ":"ⲵ","Ⲷ":"ⲷ","Ⲹ":"ⲹ","Ⲻ":"ⲻ","Ⲽ":"ⲽ","Ⲿ":"ⲿ","Ⳁ":"ⳁ","Ⳃ":"ⳃ","Ⳅ":"ⳅ","Ⳇ":"ⳇ","Ⳉ":"ⳉ","Ⳋ":"ⳋ","Ⳍ":"ⳍ","Ⳏ":"ⳏ","Ⳑ":"ⳑ","Ⳓ":"ⳓ","Ⳕ":"ⳕ","Ⳗ":"ⳗ","Ⳙ":"ⳙ","Ⳛ":"ⳛ","Ⳝ":"ⳝ","Ⳟ":"ⳟ","Ⳡ":"ⳡ","Ⳣ":"ⳣ","Ⳬ":"ⳬ","Ⳮ":"ⳮ","Ⳳ":"ⳳ","Ꙁ":"ꙁ","Ꙃ":"ꙃ","Ꙅ":"ꙅ","Ꙇ":"ꙇ","Ꙉ":"ꙉ","Ꙋ":"ꙋ","Ꙍ":"ꙍ","Ꙏ":"ꙏ","Ꙑ":"ꙑ","Ꙓ":"ꙓ","Ꙕ":"ꙕ","Ꙗ":"ꙗ","Ꙙ":"ꙙ","Ꙛ":"ꙛ","Ꙝ":"ꙝ","Ꙟ":"ꙟ","Ꙡ":"ꙡ","Ꙣ":"ꙣ","Ꙥ":"ꙥ","Ꙧ":"ꙧ","Ꙩ":"ꙩ","Ꙫ":"ꙫ","Ꙭ":"ꙭ","Ꚁ":"ꚁ","Ꚃ":"ꚃ","Ꚅ":"ꚅ","Ꚇ":"ꚇ","Ꚉ":"ꚉ","Ꚋ":"ꚋ","Ꚍ":"ꚍ","Ꚏ":"ꚏ","Ꚑ":"ꚑ","Ꚓ":"ꚓ","Ꚕ":"ꚕ","Ꚗ":"ꚗ","Ꚙ":"ꚙ","Ꚛ":"ꚛ","Ꜣ":"ꜣ","Ꜥ":"ꜥ","Ꜧ":"ꜧ","Ꜩ":"ꜩ","Ꜫ":"ꜫ","Ꜭ":"ꜭ","Ꜯ":"ꜯ","Ꜳ":"ꜳ","Ꜵ":"ꜵ","Ꜷ":"ꜷ","Ꜹ":"ꜹ","Ꜻ":"ꜻ","Ꜽ":"ꜽ","Ꜿ":"ꜿ","Ꝁ":"ꝁ","Ꝃ":"ꝃ","Ꝅ":"ꝅ","Ꝇ":"ꝇ","Ꝉ":"ꝉ","Ꝋ":"ꝋ","Ꝍ":"ꝍ","Ꝏ":"ꝏ","Ꝑ":"ꝑ","Ꝓ":"ꝓ","Ꝕ":"ꝕ","Ꝗ":"ꝗ","Ꝙ":"ꝙ","Ꝛ":"ꝛ","Ꝝ":"ꝝ","Ꝟ":"ꝟ","Ꝡ":"ꝡ","Ꝣ":"ꝣ","Ꝥ":"ꝥ","Ꝧ":"ꝧ","Ꝩ":"ꝩ","Ꝫ":"ꝫ","Ꝭ":"ꝭ","Ꝯ":"ꝯ","Ꝺ":"ꝺ","Ꝼ":"ꝼ","Ᵹ":"ᵹ","Ꝿ":"ꝿ","Ꞁ":"ꞁ","Ꞃ":"ꞃ","Ꞅ":"ꞅ","Ꞇ":"ꞇ","Ꞌ":"ꞌ","Ɥ":"ɥ","Ꞑ":"ꞑ","Ꞓ":"ꞓ","Ꞗ":"ꞗ","Ꞙ":"ꞙ","Ꞛ":"ꞛ","Ꞝ":"ꞝ","Ꞟ":"ꞟ","Ꞡ":"ꞡ","Ꞣ":"ꞣ","Ꞥ":"ꞥ","Ꞧ":"ꞧ","Ꞩ":"ꞩ","Ɦ":"ɦ","Ɜ":"ɜ","Ɡ":"ɡ","Ɬ":"ɬ","Ʞ":"ʞ","Ʇ":"ʇ","A":"a","B":"b","C":"c","D":"d","E":"e","F":"f","G":"g","H":"h","I":"i","J":"j","K":"k","L":"l","M":"m","N":"n","O":"o","P":"p","Q":"q","R":"r","S":"s","T":"t","U":"u","V":"v","W":"w","X":"x","Y":"y","Z":"z","𐐀":"𐐨","𐐁":"𐐩","𐐂":"𐐪","𐐃":"𐐫","𐐄":"𐐬","𐐅":"𐐭","𐐆":"𐐮","𐐇":"𐐯","𐐈":"𐐰","𐐉":"𐐱","𐐊":"𐐲","𐐋":"𐐳","𐐌":"𐐴","𐐍":"𐐵","𐐎":"𐐶","𐐏":"𐐷","𐐐":"𐐸","𐐑":"𐐹","𐐒":"𐐺","𐐓":"𐐻","𐐔":"𐐼","𐐕":"𐐽","𐐖":"𐐾","𐐗":"𐐿","𐐘":"𐑀","𐐙":"𐑁","𐐚":"𐑂","𐐛":"𐑃","𐐜":"𐑄","𐐝":"𐑅","𐐞":"𐑆","𐐟":"𐑇","𐐠":"𐑈","𐐡":"𐑉","𐐢":"𐑊","𐐣":"𐑋","𐐤":"𐑌","𐐥":"𐑍","𐐦":"𐑎","𐐧":"𐑏","𑢠":"𑣀","𑢡":"𑣁","𑢢":"𑣂","𑢣":"𑣃","𑢤":"𑣄","𑢥":"𑣅","𑢦":"𑣆","𑢧":"𑣇","𑢨":"𑣈","𑢩":"𑣉","𑢪":"𑣊","𑢫":"𑣋","𑢬":"𑣌","𑢭":"𑣍","𑢮":"𑣎","𑢯":"𑣏","𑢰":"𑣐","𑢱":"𑣑","𑢲":"𑣒","𑢳":"𑣓","𑢴":"𑣔","𑢵":"𑣕","𑢶":"𑣖","𑢷":"𑣗","𑢸":"𑣘","𑢹":"𑣙","𑢺":"𑣚","𑢻":"𑣛","𑢼":"𑣜","𑢽":"𑣝","𑢾":"𑣞","𑢿":"𑣟","ß":"ss","İ":"i̇","ʼn":"ʼn","ǰ":"ǰ","ΐ":"ΐ","ΰ":"ΰ","և":"եւ","ẖ":"ẖ","ẗ":"ẗ","ẘ":"ẘ","ẙ":"ẙ","ẚ":"aʾ","ẞ":"ss","ὐ":"ὐ","ὒ":"ὒ","ὔ":"ὔ","ὖ":"ὖ","ᾀ":"ἀι","ᾁ":"ἁι","ᾂ":"ἂι","ᾃ":"ἃι","ᾄ":"ἄι","ᾅ":"ἅι","ᾆ":"ἆι","ᾇ":"ἇι","ᾈ":"ἀι","ᾉ":"ἁι","ᾊ":"ἂι","ᾋ":"ἃι","ᾌ":"ἄι","ᾍ":"ἅι","ᾎ":"ἆι","ᾏ":"ἇι","ᾐ":"ἠι","ᾑ":"ἡι","ᾒ":"ἢι","ᾓ":"ἣι","ᾔ":"ἤι","ᾕ":"ἥι","ᾖ":"ἦι","ᾗ":"ἧι","ᾘ":"ἠι","ᾙ":"ἡι","ᾚ":"ἢι","ᾛ":"ἣι","ᾜ":"ἤι","ᾝ":"ἥι","ᾞ":"ἦι","ᾟ":"ἧι","ᾠ":"ὠι","ᾡ":"ὡι","ᾢ":"ὢι","ᾣ":"ὣι","ᾤ":"ὤι","ᾥ":"ὥι","ᾦ":"ὦι","ᾧ":"ὧι","ᾨ":"ὠι","ᾩ":"ὡι","ᾪ":"ὢι","ᾫ":"ὣι","ᾬ":"ὤι","ᾭ":"ὥι","ᾮ":"ὦι","ᾯ":"ὧι","ᾲ":"ὰι","ᾳ":"αι","ᾴ":"άι","ᾶ":"ᾶ","ᾷ":"ᾶι","ᾼ":"αι","ῂ":"ὴι","ῃ":"ηι","ῄ":"ήι","ῆ":"ῆ","ῇ":"ῆι","ῌ":"ηι","ῒ":"ῒ","ΐ":"ΐ","ῖ":"ῖ","ῗ":"ῗ","ῢ":"ῢ","ΰ":"ΰ","ῤ":"ῤ","ῦ":"ῦ","ῧ":"ῧ","ῲ":"ὼι","ῳ":"ωι","ῴ":"ώι","ῶ":"ῶ","ῷ":"ῶι","ῼ":"ωι","ff":"ff","fi":"fi","fl":"fl","ffi":"ffi","ffl":"ffl","ſt":"st","st":"st","ﬓ":"մն","ﬔ":"մե","ﬕ":"մի","ﬖ":"վն","ﬗ":"մխ"};module.exports=function(string){return string.slice(1,string.length-1).trim().replace(regex,function($0){return map[$0]||" "})}},{}],9:[function(require,module,exports){"use strict";function XmlRenderer(options){return{softbreak:"\n",escape:escapeXml,options:options||{},render:renderNodes}}var escapeXml=require("./common").escapeXml,tag=function(name,attrs,selfclosing){var result="<"+name;if(attrs&&attrs.length>0)for(var attrib,i=0;void 0!==(attrib=attrs[i]);)result+=" "+attrib[0]+'="'+attrib[1]+'"',i++;return selfclosing&&(result+=" /"),result+=">"},reXMLTag=/\<[^>]*\>/,toTagName=function(s){return s.replace(/([a-z])([A-Z])/g,"$1_$2").toLowerCase()},renderNodes=function(block){var attrs,tagname,event,node,entering,unescapedContents,container,selfClosing,nodetype,walker=block.walker(),buffer="",lastOut="\n",disableTags=0,indentLevel=0,indent=" ",out=function(s){buffer+=disableTags>0?s.replace(reXMLTag,""):s,lastOut=s},esc=this.escape,cr=function(){if("\n"!==lastOut){buffer+="\n",lastOut="\n";for(var i=indentLevel;i>0;i--)buffer+=indent}},options=this.options;for(options.time&&console.time("rendering"),buffer+='\n',buffer+='\n';event=walker.next();)if(entering=event.entering,node=event.node,nodetype=node.type,container=node.isContainer,selfClosing="HorizontalRule"===nodetype||"Hardbreak"===nodetype||"Softbreak"===nodetype,unescapedContents="Html"===nodetype||"HtmlInline"===nodetype,tagname=toTagName(nodetype),entering){switch(attrs=[],nodetype){case"List":null!==node.listType&&attrs.push(["type",node.listType.toLowerCase()]),null!==node.listStart&&attrs.push(["start",String(node.listStart)]),null!==node.listTight&&attrs.push(["tight",node.listTight?"true":"false"]);var delim=node.listDelimiter;if(null!==delim){var delimword="";delimword="."===delim?"period":"paren",attrs.push(["delimiter",delimword])}break;case"CodeBlock":node.info&&attrs.push(["info",node.info]);break;case"Header":attrs.push(["level",String(node.level)]);break;case"Link":case"Image":attrs.push(["destination",node.destination]),attrs.push(["title",node.title])}if(options.sourcepos){var pos=node.sourcepos;pos&&attrs.push(["sourcepos",String(pos[0][0])+":"+String(pos[0][1])+"-"+String(pos[1][0])+":"+String(pos[1][1])])}if(cr(),out(tag(tagname,attrs,selfClosing)),container)indentLevel+=1;else if(!container&&!selfClosing){var lit=node.literal;lit&&out(unescapedContents?lit:esc(lit)),out(tag("/"+tagname))}}else indentLevel-=1,cr(),out(tag("/"+tagname));return options.time&&console.timeEnd("rendering"),buffer+="\n"};module.exports=XmlRenderer},{"./common":2}],10:[function(require,module,exports){var encode=require("./lib/encode.js"),decode=require("./lib/decode.js");exports.decode=function(data,level){return(!level||0>=level?decode.XML:decode.HTML)(data)},exports.decodeStrict=function(data,level){return(!level||0>=level?decode.XML:decode.HTMLStrict)(data)},exports.encode=function(data,level){return(!level||0>=level?encode.XML:encode.HTML)(data)},exports.encodeXML=encode.XML,exports.encodeHTML4=exports.encodeHTML5=exports.encodeHTML=encode.HTML,exports.decodeXML=exports.decodeXMLStrict=decode.XML,exports.decodeHTML4=exports.decodeHTML5=exports.decodeHTML=decode.HTML,exports.decodeHTML4Strict=exports.decodeHTML5Strict=exports.decodeHTMLStrict=decode.HTMLStrict,exports.escape=encode.escape},{"./lib/decode.js":11,"./lib/encode.js":13}],11:[function(require,module,exports){function getStrictDecoder(map){var keys=Object.keys(map).join("|"),replace=getReplacer(map);keys+="|#[xX][\\da-fA-F]+|#\\d+";var re=new RegExp("&(?:"+keys+");","g");return function(str){return String(str).replace(re,replace)}}function sorter(a,b){return b>a?1:-1}function getReplacer(map){return function(str){return"#"===str.charAt(1)?decodeCodePoint("X"===str.charAt(2)||"x"===str.charAt(2)?parseInt(str.substr(3),16):parseInt(str.substr(2),10)):map[str.slice(1,-1)]}}var entityMap=require("../maps/entities.json"),legacyMap=require("../maps/legacy.json"),xmlMap=require("../maps/xml.json"),decodeCodePoint=require("./decode_codepoint.js"),decodeXMLStrict=getStrictDecoder(xmlMap),decodeHTMLStrict=getStrictDecoder(entityMap),decodeHTML=function(){function replacer(str){return";"!==str.substr(-1)&&(str+=";"),replace(str)}for(var legacy=Object.keys(legacyMap).sort(sorter),keys=Object.keys(entityMap).sort(sorter),i=0,j=0;keys.length>i;i++)legacy[j]===keys[i]?(keys[i]+=";?",j++):keys[i]+=";";var re=new RegExp("&(?:"+keys.join("|")+"|#[xX][\\da-fA-F]+;?|#\\d+;?)","g"),replace=getReplacer(entityMap);return function(str){return String(str).replace(re,replacer)}}();module.exports={XML:decodeXMLStrict,HTML:decodeHTML,HTMLStrict:decodeHTMLStrict}},{"../maps/entities.json":15,"../maps/legacy.json":16,"../maps/xml.json":17,"./decode_codepoint.js":12}],12:[function(require,module,exports){function decodeCodePoint(codePoint){if(codePoint>=55296&&57343>=codePoint||codePoint>1114111)return"�";codePoint in decodeMap&&(codePoint=decodeMap[codePoint]);var output="";return codePoint>65535&&(codePoint-=65536,output+=String.fromCharCode(codePoint>>>10&1023|55296),codePoint=56320|1023&codePoint),output+=String.fromCharCode(codePoint)}var decodeMap=require("../maps/decode.json");module.exports=decodeCodePoint},{"../maps/decode.json":14}],13:[function(require,module,exports){function getInverseObj(obj){return Object.keys(obj).sort().reduce(function(inverse,name){return inverse[obj[name]]="&"+name+";",inverse},{})}function getInverseReplacer(inverse){var single=[],multiple=[];return Object.keys(inverse).forEach(function(k){1===k.length?single.push("\\"+k):multiple.push(k)}),multiple.unshift("["+single.join("")+"]"),new RegExp(multiple.join("|"),"g")}function singleCharReplacer(c){return"&#x"+c.charCodeAt(0).toString(16).toUpperCase()+";"}function astralReplacer(c){var high=c.charCodeAt(0),low=c.charCodeAt(1),codePoint=1024*(high-55296)+low-56320+65536;return"&#x"+codePoint.toString(16).toUpperCase()+";"}function getInverse(inverse,re){function func(name){return inverse[name]}return function(data){return data.replace(re,func).replace(re_astralSymbols,astralReplacer).replace(re_nonASCII,singleCharReplacer)}}function escapeXML(data){return data.replace(re_xmlChars,singleCharReplacer).replace(re_astralSymbols,astralReplacer).replace(re_nonASCII,singleCharReplacer)}var inverseXML=getInverseObj(require("../maps/xml.json")),xmlReplacer=getInverseReplacer(inverseXML);exports.XML=getInverse(inverseXML,xmlReplacer);var inverseHTML=getInverseObj(require("../maps/entities.json")),htmlReplacer=getInverseReplacer(inverseHTML);exports.HTML=getInverse(inverseHTML,htmlReplacer);var re_nonASCII=/[^\0-\x7F]/g,re_astralSymbols=/[\uD800-\uDBFF][\uDC00-\uDFFF]/g,re_xmlChars=getInverseReplacer(inverseXML);exports.escape=escapeXML},{"../maps/entities.json":15,"../maps/xml.json":17}],14:[function(require,module,exports){module.exports={0:65533,128:8364,130:8218,131:402,132:8222,133:8230,134:8224,135:8225,136:710,137:8240,138:352,139:8249,140:338,142:381,145:8216,146:8217,147:8220,148:8221,149:8226,150:8211,151:8212,152:732,153:8482,154:353,155:8250,156:339,158:382,159:376}},{}],15:[function(require,module,exports){module.exports={Aacute:"Á",aacute:"á",Abreve:"Ă",abreve:"ă",ac:"∾",acd:"∿",acE:"∾̳",Acirc:"Â",acirc:"â",acute:"´",Acy:"А",acy:"а",AElig:"Æ",aelig:"æ",af:"⁡",Afr:"𝔄",afr:"𝔞",Agrave:"À",agrave:"à",alefsym:"ℵ",aleph:"ℵ",Alpha:"Α",alpha:"α",Amacr:"Ā",amacr:"ā",amalg:"⨿",amp:"&",AMP:"&",andand:"⩕",And:"⩓",and:"∧",andd:"⩜",andslope:"⩘",andv:"⩚",ang:"∠",ange:"⦤",angle:"∠",angmsdaa:"⦨",angmsdab:"⦩",angmsdac:"⦪",angmsdad:"⦫",angmsdae:"⦬",angmsdaf:"⦭",angmsdag:"⦮",angmsdah:"⦯",angmsd:"∡",angrt:"∟",angrtvb:"⊾",angrtvbd:"⦝",angsph:"∢",angst:"Å",angzarr:"⍼",Aogon:"Ą",aogon:"ą",Aopf:"𝔸",aopf:"𝕒",apacir:"⩯",ap:"≈",apE:"⩰",ape:"≊",apid:"≋",apos:"'",ApplyFunction:"⁡",approx:"≈",approxeq:"≊",Aring:"Å",aring:"å",Ascr:"𝒜",ascr:"𝒶",Assign:"≔",ast:"*",asymp:"≈",asympeq:"≍",Atilde:"Ã",atilde:"ã",Auml:"Ä",auml:"ä",awconint:"∳",awint:"⨑",backcong:"≌",backepsilon:"϶",backprime:"‵",backsim:"∽",backsimeq:"⋍",Backslash:"∖",Barv:"⫧",barvee:"⊽",barwed:"⌅",Barwed:"⌆",barwedge:"⌅",bbrk:"⎵",bbrktbrk:"⎶",bcong:"≌",Bcy:"Б",bcy:"б",bdquo:"„",becaus:"∵",because:"∵",Because:"∵",bemptyv:"⦰",bepsi:"϶",bernou:"ℬ",Bernoullis:"ℬ",Beta:"Β",beta:"β",beth:"ℶ",between:"≬",Bfr:"𝔅",bfr:"𝔟",bigcap:"⋂",bigcirc:"◯",bigcup:"⋃",bigodot:"⨀",bigoplus:"⨁",bigotimes:"⨂",bigsqcup:"⨆",bigstar:"★",bigtriangledown:"▽",bigtriangleup:"△",biguplus:"⨄",bigvee:"⋁",bigwedge:"⋀",bkarow:"⤍",blacklozenge:"⧫",blacksquare:"▪",blacktriangle:"▴",blacktriangledown:"▾",blacktriangleleft:"◂",blacktriangleright:"▸",blank:"␣",blk12:"▒",blk14:"░",blk34:"▓",block:"█",bne:"=⃥",bnequiv:"≡⃥",bNot:"⫭",bnot:"⌐",Bopf:"𝔹",bopf:"𝕓",bot:"⊥",bottom:"⊥",bowtie:"⋈",boxbox:"⧉",boxdl:"┐",boxdL:"╕",boxDl:"╖",boxDL:"╗",boxdr:"┌",boxdR:"╒",boxDr:"╓",boxDR:"╔",boxh:"─",boxH:"═",boxhd:"┬",boxHd:"╤",boxhD:"╥",boxHD:"╦",boxhu:"┴",boxHu:"╧",boxhU:"╨",boxHU:"╩",boxminus:"⊟",boxplus:"⊞",boxtimes:"⊠",boxul:"┘",boxuL:"╛",boxUl:"╜",boxUL:"╝",boxur:"└",boxuR:"╘",boxUr:"╙",boxUR:"╚",boxv:"│",boxV:"║",boxvh:"┼",boxvH:"╪",boxVh:"╫",boxVH:"╬",boxvl:"┤",boxvL:"╡",boxVl:"╢",boxVL:"╣",boxvr:"├",boxvR:"╞",boxVr:"╟",boxVR:"╠",bprime:"‵",breve:"˘",Breve:"˘",brvbar:"¦",bscr:"𝒷",Bscr:"ℬ",bsemi:"⁏",bsim:"∽",bsime:"⋍",bsolb:"⧅",bsol:"\\",bsolhsub:"⟈",bull:"•",bullet:"•",bump:"≎",bumpE:"⪮",bumpe:"≏",Bumpeq:"≎",bumpeq:"≏",Cacute:"Ć",cacute:"ć",capand:"⩄",capbrcup:"⩉",capcap:"⩋",cap:"∩",Cap:"⋒",capcup:"⩇",capdot:"⩀",CapitalDifferentialD:"ⅅ",caps:"∩︀",caret:"⁁",caron:"ˇ",Cayleys:"ℭ",ccaps:"⩍",Ccaron:"Č",ccaron:"č",Ccedil:"Ç",ccedil:"ç",Ccirc:"Ĉ",ccirc:"ĉ",Cconint:"∰",ccups:"⩌",ccupssm:"⩐",Cdot:"Ċ",cdot:"ċ",cedil:"¸",Cedilla:"¸",cemptyv:"⦲",cent:"¢",centerdot:"·",CenterDot:"·",cfr:"𝔠",Cfr:"ℭ",CHcy:"Ч",chcy:"ч",check:"✓",checkmark:"✓",Chi:"Χ",chi:"χ",circ:"ˆ",circeq:"≗",circlearrowleft:"↺",circlearrowright:"↻",circledast:"⊛",circledcirc:"⊚",circleddash:"⊝",CircleDot:"⊙",circledR:"®",circledS:"Ⓢ",CircleMinus:"⊖",CirclePlus:"⊕",CircleTimes:"⊗",cir:"○",cirE:"⧃",cire:"≗",cirfnint:"⨐",cirmid:"⫯",cirscir:"⧂",ClockwiseContourIntegral:"∲",CloseCurlyDoubleQuote:"”",CloseCurlyQuote:"’",clubs:"♣",clubsuit:"♣",colon:":",Colon:"∷",Colone:"⩴",colone:"≔",coloneq:"≔",comma:",",commat:"@",comp:"∁",compfn:"∘",complement:"∁",complexes:"ℂ",cong:"≅",congdot:"⩭",Congruent:"≡",conint:"∮",Conint:"∯",ContourIntegral:"∮",copf:"𝕔",Copf:"ℂ",coprod:"∐",Coproduct:"∐",copy:"©",COPY:"©",copysr:"℗",CounterClockwiseContourIntegral:"∳",crarr:"↵",cross:"✗",Cross:"⨯",Cscr:"𝒞",cscr:"𝒸",csub:"⫏",csube:"⫑",csup:"⫐",csupe:"⫒",ctdot:"⋯",cudarrl:"⤸",cudarrr:"⤵",cuepr:"⋞",cuesc:"⋟",cularr:"↶",cularrp:"⤽",cupbrcap:"⩈",cupcap:"⩆",CupCap:"≍",cup:"∪",Cup:"⋓",cupcup:"⩊",cupdot:"⊍",cupor:"⩅",cups:"∪︀",curarr:"↷",curarrm:"⤼",curlyeqprec:"⋞",curlyeqsucc:"⋟",curlyvee:"⋎",curlywedge:"⋏",curren:"¤",curvearrowleft:"↶",curvearrowright:"↷",cuvee:"⋎",cuwed:"⋏",cwconint:"∲",cwint:"∱",cylcty:"⌭",dagger:"†",Dagger:"‡",daleth:"ℸ",darr:"↓",Darr:"↡",dArr:"⇓",dash:"‐",Dashv:"⫤",dashv:"⊣",dbkarow:"⤏",dblac:"˝",Dcaron:"Ď",dcaron:"ď",Dcy:"Д",dcy:"д",ddagger:"‡",ddarr:"⇊",DD:"ⅅ",dd:"ⅆ",DDotrahd:"⤑",ddotseq:"⩷",deg:"°",Del:"∇",Delta:"Δ",delta:"δ",demptyv:"⦱",dfisht:"⥿",Dfr:"𝔇",dfr:"𝔡",dHar:"⥥",dharl:"⇃",dharr:"⇂",DiacriticalAcute:"´",DiacriticalDot:"˙",DiacriticalDoubleAcute:"˝",DiacriticalGrave:"`",DiacriticalTilde:"˜",diam:"⋄",diamond:"⋄",Diamond:"⋄",diamondsuit:"♦",diams:"♦",die:"¨",DifferentialD:"ⅆ",digamma:"ϝ",disin:"⋲",div:"÷",divide:"÷",divideontimes:"⋇",divonx:"⋇",DJcy:"Ђ",djcy:"ђ",dlcorn:"⌞",dlcrop:"⌍",dollar:"$",Dopf:"𝔻",dopf:"𝕕",Dot:"¨",dot:"˙",DotDot:"⃜",doteq:"≐",doteqdot:"≑",DotEqual:"≐",dotminus:"∸",dotplus:"∔",dotsquare:"⊡",doublebarwedge:"⌆",DoubleContourIntegral:"∯",DoubleDot:"¨",DoubleDownArrow:"⇓",DoubleLeftArrow:"⇐",DoubleLeftRightArrow:"⇔",DoubleLeftTee:"⫤",DoubleLongLeftArrow:"⟸",DoubleLongLeftRightArrow:"⟺",DoubleLongRightArrow:"⟹",DoubleRightArrow:"⇒",DoubleRightTee:"⊨",DoubleUpArrow:"⇑",DoubleUpDownArrow:"⇕",DoubleVerticalBar:"∥",DownArrowBar:"⤓",downarrow:"↓",DownArrow:"↓",Downarrow:"⇓",DownArrowUpArrow:"⇵",DownBreve:"̑",downdownarrows:"⇊",downharpoonleft:"⇃",downharpoonright:"⇂",DownLeftRightVector:"⥐",DownLeftTeeVector:"⥞",DownLeftVectorBar:"⥖",DownLeftVector:"↽",DownRightTeeVector:"⥟",DownRightVectorBar:"⥗",DownRightVector:"⇁",DownTeeArrow:"↧",DownTee:"⊤",drbkarow:"⤐",drcorn:"⌟",drcrop:"⌌",Dscr:"𝒟",dscr:"𝒹",DScy:"Ѕ",dscy:"ѕ",dsol:"⧶",Dstrok:"Đ",dstrok:"đ",dtdot:"⋱",dtri:"▿",dtrif:"▾",duarr:"⇵",duhar:"⥯",dwangle:"⦦",DZcy:"Џ",dzcy:"џ",dzigrarr:"⟿",Eacute:"É",eacute:"é",easter:"⩮",Ecaron:"Ě",ecaron:"ě",Ecirc:"Ê",ecirc:"ê",ecir:"≖",ecolon:"≕",Ecy:"Э",ecy:"э",eDDot:"⩷",Edot:"Ė",edot:"ė",eDot:"≑",ee:"ⅇ",efDot:"≒",Efr:"𝔈",efr:"𝔢",eg:"⪚",Egrave:"È",egrave:"è",egs:"⪖",egsdot:"⪘",el:"⪙",Element:"∈",elinters:"⏧",ell:"ℓ",els:"⪕",elsdot:"⪗",Emacr:"Ē",emacr:"ē",empty:"∅",emptyset:"∅",EmptySmallSquare:"◻",emptyv:"∅",EmptyVerySmallSquare:"▫",emsp13:" ",emsp14:" ",emsp:" ",ENG:"Ŋ",eng:"ŋ",ensp:" ",Eogon:"Ę",eogon:"ę",Eopf:"𝔼",eopf:"𝕖",epar:"⋕",eparsl:"⧣",eplus:"⩱",epsi:"ε",Epsilon:"Ε",epsilon:"ε",epsiv:"ϵ",eqcirc:"≖",eqcolon:"≕",eqsim:"≂",eqslantgtr:"⪖",eqslantless:"⪕",Equal:"⩵",equals:"=",EqualTilde:"≂",equest:"≟",Equilibrium:"⇌",equiv:"≡",equivDD:"⩸",eqvparsl:"⧥",erarr:"⥱",erDot:"≓",escr:"ℯ",Escr:"ℰ",esdot:"≐",Esim:"⩳",esim:"≂",Eta:"Η",eta:"η",ETH:"Ð",eth:"ð",Euml:"Ë",euml:"ë",euro:"€",excl:"!",exist:"∃",Exists:"∃",expectation:"ℰ",exponentiale:"ⅇ",ExponentialE:"ⅇ",fallingdotseq:"≒",Fcy:"Ф",fcy:"ф",female:"♀",ffilig:"ffi",fflig:"ff",ffllig:"ffl",Ffr:"𝔉",ffr:"𝔣",filig:"fi",FilledSmallSquare:"◼",FilledVerySmallSquare:"▪",fjlig:"fj",flat:"♭",fllig:"fl",fltns:"▱",fnof:"ƒ",Fopf:"𝔽",fopf:"𝕗",forall:"∀",ForAll:"∀",fork:"⋔",forkv:"⫙",Fouriertrf:"ℱ",fpartint:"⨍",frac12:"½",frac13:"⅓",frac14:"¼",frac15:"⅕",frac16:"⅙",frac18:"⅛",frac23:"⅔",frac25:"⅖",frac34:"¾",frac35:"⅗",frac38:"⅜",frac45:"⅘",frac56:"⅚",frac58:"⅝",frac78:"⅞",frasl:"⁄",frown:"⌢",fscr:"𝒻",Fscr:"ℱ",gacute:"ǵ",Gamma:"Γ",gamma:"γ",Gammad:"Ϝ",gammad:"ϝ",gap:"⪆",Gbreve:"Ğ",gbreve:"ğ",Gcedil:"Ģ",Gcirc:"Ĝ",gcirc:"ĝ",Gcy:"Г",gcy:"г",Gdot:"Ġ",gdot:"ġ",ge:"≥",gE:"≧",gEl:"⪌",gel:"⋛",geq:"≥",geqq:"≧",geqslant:"⩾",gescc:"⪩",ges:"⩾",gesdot:"⪀",gesdoto:"⪂",gesdotol:"⪄",gesl:"⋛︀",gesles:"⪔",Gfr:"𝔊",gfr:"𝔤",gg:"≫",Gg:"⋙",ggg:"⋙",gimel:"ℷ",GJcy:"Ѓ",gjcy:"ѓ",gla:"⪥",gl:"≷",glE:"⪒",glj:"⪤",gnap:"⪊",gnapprox:"⪊",gne:"⪈",gnE:"≩",gneq:"⪈",gneqq:"≩",gnsim:"⋧",Gopf:"𝔾",gopf:"𝕘",grave:"`",GreaterEqual:"≥",GreaterEqualLess:"⋛",GreaterFullEqual:"≧",GreaterGreater:"⪢",GreaterLess:"≷",GreaterSlantEqual:"⩾",GreaterTilde:"≳",Gscr:"𝒢",gscr:"ℊ",gsim:"≳",gsime:"⪎",gsiml:"⪐",gtcc:"⪧",gtcir:"⩺",gt:">",GT:">",Gt:"≫",gtdot:"⋗",gtlPar:"⦕",gtquest:"⩼",gtrapprox:"⪆",gtrarr:"⥸",gtrdot:"⋗",gtreqless:"⋛",gtreqqless:"⪌",gtrless:"≷",gtrsim:"≳",gvertneqq:"≩︀",gvnE:"≩︀",Hacek:"ˇ",hairsp:" ",half:"½",hamilt:"ℋ",HARDcy:"Ъ",hardcy:"ъ",harrcir:"⥈",harr:"↔",hArr:"⇔",harrw:"↭",Hat:"^",hbar:"ℏ",Hcirc:"Ĥ",hcirc:"ĥ",hearts:"♥",heartsuit:"♥",hellip:"…",hercon:"⊹",hfr:"𝔥",Hfr:"ℌ",HilbertSpace:"ℋ",hksearow:"⤥",hkswarow:"⤦",hoarr:"⇿",homtht:"∻",hookleftarrow:"↩",hookrightarrow:"↪",hopf:"𝕙",Hopf:"ℍ",horbar:"―",HorizontalLine:"─",hscr:"𝒽",Hscr:"ℋ",hslash:"ℏ",Hstrok:"Ħ",hstrok:"ħ",HumpDownHump:"≎",HumpEqual:"≏",hybull:"⁃",hyphen:"‐",Iacute:"Í",iacute:"í",ic:"⁣",Icirc:"Î",icirc:"î",Icy:"И",icy:"и",Idot:"İ",IEcy:"Е",iecy:"е",iexcl:"¡",iff:"⇔",ifr:"𝔦",Ifr:"ℑ",Igrave:"Ì",igrave:"ì",ii:"ⅈ",iiiint:"⨌",iiint:"∭",iinfin:"⧜",iiota:"℩",IJlig:"IJ",ijlig:"ij",Imacr:"Ī",imacr:"ī",image:"ℑ",ImaginaryI:"ⅈ",imagline:"ℐ",imagpart:"ℑ",imath:"ı",Im:"ℑ",imof:"⊷",imped:"Ƶ",Implies:"⇒",incare:"℅","in":"∈",infin:"∞",infintie:"⧝",inodot:"ı",intcal:"⊺","int":"∫",Int:"∬",integers:"ℤ",Integral:"∫",intercal:"⊺",Intersection:"⋂",intlarhk:"⨗",intprod:"⨼",InvisibleComma:"⁣",InvisibleTimes:"⁢",IOcy:"Ё",iocy:"ё",Iogon:"Į",iogon:"į",Iopf:"𝕀",iopf:"𝕚",Iota:"Ι",iota:"ι",iprod:"⨼",iquest:"¿",iscr:"𝒾",Iscr:"ℐ",isin:"∈",isindot:"⋵",isinE:"⋹",isins:"⋴",isinsv:"⋳",isinv:"∈",it:"⁢",Itilde:"Ĩ",itilde:"ĩ",Iukcy:"І",iukcy:"і",Iuml:"Ï",iuml:"ï",Jcirc:"Ĵ",jcirc:"ĵ",Jcy:"Й",jcy:"й",Jfr:"𝔍",jfr:"𝔧",jmath:"ȷ",Jopf:"𝕁",jopf:"𝕛",Jscr:"𝒥",jscr:"𝒿",Jsercy:"Ј",jsercy:"ј",Jukcy:"Є",jukcy:"є",Kappa:"Κ",kappa:"κ",kappav:"ϰ",Kcedil:"Ķ",kcedil:"ķ",Kcy:"К",kcy:"к",Kfr:"𝔎",kfr:"𝔨",kgreen:"ĸ",KHcy:"Х",khcy:"х",KJcy:"Ќ",kjcy:"ќ",Kopf:"𝕂",kopf:"𝕜",Kscr:"𝒦",kscr:"𝓀",lAarr:"⇚",Lacute:"Ĺ",lacute:"ĺ",laemptyv:"⦴",lagran:"ℒ",Lambda:"Λ",lambda:"λ",lang:"⟨",Lang:"⟪",langd:"⦑",langle:"⟨",lap:"⪅",Laplacetrf:"ℒ",laquo:"«",larrb:"⇤",larrbfs:"⤟",larr:"←",Larr:"↞",lArr:"⇐",larrfs:"⤝",larrhk:"↩",larrlp:"↫",larrpl:"⤹",larrsim:"⥳",larrtl:"↢",latail:"⤙",lAtail:"⤛",lat:"⪫",late:"⪭",lates:"⪭︀",lbarr:"⤌",lBarr:"⤎",lbbrk:"❲",lbrace:"{",lbrack:"[",lbrke:"⦋",lbrksld:"⦏",lbrkslu:"⦍",Lcaron:"Ľ",lcaron:"ľ",Lcedil:"Ļ",lcedil:"ļ",lceil:"⌈",lcub:"{",Lcy:"Л",lcy:"л",ldca:"⤶",ldquo:"“",ldquor:"„",ldrdhar:"⥧",ldrushar:"⥋",ldsh:"↲",le:"≤",lE:"≦",LeftAngleBracket:"⟨",LeftArrowBar:"⇤",leftarrow:"←",LeftArrow:"←",Leftarrow:"⇐",LeftArrowRightArrow:"⇆",leftarrowtail:"↢",LeftCeiling:"⌈",LeftDoubleBracket:"⟦",LeftDownTeeVector:"⥡",LeftDownVectorBar:"⥙",LeftDownVector:"⇃",LeftFloor:"⌊",leftharpoondown:"↽",leftharpoonup:"↼",leftleftarrows:"⇇",leftrightarrow:"↔",LeftRightArrow:"↔",Leftrightarrow:"⇔",leftrightarrows:"⇆",leftrightharpoons:"⇋",leftrightsquigarrow:"↭",LeftRightVector:"⥎",LeftTeeArrow:"↤",LeftTee:"⊣",LeftTeeVector:"⥚",leftthreetimes:"⋋",LeftTriangleBar:"⧏",LeftTriangle:"⊲",LeftTriangleEqual:"⊴",LeftUpDownVector:"⥑",LeftUpTeeVector:"⥠",LeftUpVectorBar:"⥘",LeftUpVector:"↿",LeftVectorBar:"⥒",LeftVector:"↼",lEg:"⪋",leg:"⋚",leq:"≤",leqq:"≦",leqslant:"⩽",lescc:"⪨",les:"⩽",lesdot:"⩿",lesdoto:"⪁",lesdotor:"⪃",lesg:"⋚︀",lesges:"⪓",lessapprox:"⪅",lessdot:"⋖",lesseqgtr:"⋚",lesseqqgtr:"⪋",LessEqualGreater:"⋚",LessFullEqual:"≦",LessGreater:"≶",lessgtr:"≶",LessLess:"⪡",lesssim:"≲",LessSlantEqual:"⩽",LessTilde:"≲",lfisht:"⥼",lfloor:"⌊",Lfr:"𝔏",lfr:"𝔩",lg:"≶",lgE:"⪑",lHar:"⥢",lhard:"↽",lharu:"↼",lharul:"⥪",lhblk:"▄",LJcy:"Љ",ljcy:"љ",llarr:"⇇",ll:"≪",Ll:"⋘",llcorner:"⌞",Lleftarrow:"⇚",llhard:"⥫",lltri:"◺",Lmidot:"Ŀ",lmidot:"ŀ",lmoustache:"⎰",lmoust:"⎰",lnap:"⪉",lnapprox:"⪉",lne:"⪇",lnE:"≨",lneq:"⪇",lneqq:"≨",lnsim:"⋦",loang:"⟬",loarr:"⇽",lobrk:"⟦",longleftarrow:"⟵",LongLeftArrow:"⟵",Longleftarrow:"⟸",longleftrightarrow:"⟷",LongLeftRightArrow:"⟷",Longleftrightarrow:"⟺",longmapsto:"⟼",longrightarrow:"⟶",LongRightArrow:"⟶",Longrightarrow:"⟹",looparrowleft:"↫",looparrowright:"↬",lopar:"⦅",Lopf:"𝕃",lopf:"𝕝",loplus:"⨭",lotimes:"⨴",lowast:"∗",lowbar:"_",LowerLeftArrow:"↙",LowerRightArrow:"↘",loz:"◊",lozenge:"◊",lozf:"⧫",lpar:"(",lparlt:"⦓",lrarr:"⇆",lrcorner:"⌟",lrhar:"⇋",lrhard:"⥭",lrm:"‎",lrtri:"⊿",lsaquo:"‹",lscr:"𝓁",Lscr:"ℒ",lsh:"↰",Lsh:"↰",lsim:"≲",lsime:"⪍",lsimg:"⪏",lsqb:"[",lsquo:"‘",lsquor:"‚",Lstrok:"Ł",lstrok:"ł",ltcc:"⪦",ltcir:"⩹",lt:"<",LT:"<",Lt:"≪",ltdot:"⋖",lthree:"⋋",ltimes:"⋉",ltlarr:"⥶",ltquest:"⩻",ltri:"◃",ltrie:"⊴",ltrif:"◂",ltrPar:"⦖",lurdshar:"⥊",luruhar:"⥦",lvertneqq:"≨︀",lvnE:"≨︀",macr:"¯",male:"♂",malt:"✠",maltese:"✠",Map:"⤅",map:"↦",mapsto:"↦",mapstodown:"↧",mapstoleft:"↤",mapstoup:"↥",marker:"▮",mcomma:"⨩",Mcy:"М",mcy:"м",mdash:"—",mDDot:"∺",measuredangle:"∡",MediumSpace:" ",Mellintrf:"ℳ",Mfr:"𝔐",mfr:"𝔪",mho:"℧",micro:"µ",midast:"*",midcir:"⫰",mid:"∣",middot:"·",minusb:"⊟",minus:"−",minusd:"∸",minusdu:"⨪",MinusPlus:"∓",mlcp:"⫛",mldr:"…",mnplus:"∓",models:"⊧",Mopf:"𝕄",mopf:"𝕞",mp:"∓",mscr:"𝓂",Mscr:"ℳ",mstpos:"∾",Mu:"Μ",mu:"μ",multimap:"⊸",mumap:"⊸",nabla:"∇",Nacute:"Ń",nacute:"ń",nang:"∠⃒",nap:"≉",napE:"⩰̸",napid:"≋̸",napos:"ʼn",napprox:"≉",natural:"♮",naturals:"ℕ",natur:"♮",nbsp:" ",nbump:"≎̸",nbumpe:"≏̸",ncap:"⩃",Ncaron:"Ň",ncaron:"ň",Ncedil:"Ņ",ncedil:"ņ",ncong:"≇",ncongdot:"⩭̸",ncup:"⩂",Ncy:"Н",ncy:"н",ndash:"–",nearhk:"⤤",nearr:"↗",neArr:"⇗",nearrow:"↗",ne:"≠",nedot:"≐̸",NegativeMediumSpace:"​",NegativeThickSpace:"​",NegativeThinSpace:"​",NegativeVeryThinSpace:"​",nequiv:"≢",nesear:"⤨",nesim:"≂̸",NestedGreaterGreater:"≫",NestedLessLess:"≪",NewLine:"\n",nexist:"∄",nexists:"∄",Nfr:"𝔑",nfr:"𝔫",ngE:"≧̸",nge:"≱",ngeq:"≱",ngeqq:"≧̸",ngeqslant:"⩾̸",nges:"⩾̸",nGg:"⋙̸",ngsim:"≵",nGt:"≫⃒",ngt:"≯",ngtr:"≯",nGtv:"≫̸",nharr:"↮",nhArr:"⇎",nhpar:"⫲",ni:"∋",nis:"⋼",nisd:"⋺",niv:"∋",NJcy:"Њ",njcy:"њ",nlarr:"↚",nlArr:"⇍",nldr:"‥",nlE:"≦̸",nle:"≰",nleftarrow:"↚",nLeftarrow:"⇍",nleftrightarrow:"↮",nLeftrightarrow:"⇎",nleq:"≰",nleqq:"≦̸",nleqslant:"⩽̸",nles:"⩽̸",nless:"≮",nLl:"⋘̸",nlsim:"≴",nLt:"≪⃒",nlt:"≮",nltri:"⋪",nltrie:"⋬",nLtv:"≪̸",nmid:"∤",NoBreak:"⁠",NonBreakingSpace:" ",nopf:"𝕟",Nopf:"ℕ",Not:"⫬",not:"¬",NotCongruent:"≢",NotCupCap:"≭",NotDoubleVerticalBar:"∦",NotElement:"∉",NotEqual:"≠",NotEqualTilde:"≂̸",NotExists:"∄",NotGreater:"≯",NotGreaterEqual:"≱",NotGreaterFullEqual:"≧̸",NotGreaterGreater:"≫̸",NotGreaterLess:"≹",NotGreaterSlantEqual:"⩾̸",NotGreaterTilde:"≵",NotHumpDownHump:"≎̸",NotHumpEqual:"≏̸",notin:"∉",notindot:"⋵̸",notinE:"⋹̸",notinva:"∉",notinvb:"⋷",notinvc:"⋶",NotLeftTriangleBar:"⧏̸",NotLeftTriangle:"⋪",NotLeftTriangleEqual:"⋬",NotLess:"≮",NotLessEqual:"≰",NotLessGreater:"≸",NotLessLess:"≪̸",NotLessSlantEqual:"⩽̸",NotLessTilde:"≴",NotNestedGreaterGreater:"⪢̸",NotNestedLessLess:"⪡̸",notni:"∌",notniva:"∌",notnivb:"⋾",notnivc:"⋽",NotPrecedes:"⊀",NotPrecedesEqual:"⪯̸",NotPrecedesSlantEqual:"⋠",NotReverseElement:"∌",NotRightTriangleBar:"⧐̸",NotRightTriangle:"⋫",NotRightTriangleEqual:"⋭",NotSquareSubset:"⊏̸",NotSquareSubsetEqual:"⋢",NotSquareSuperset:"⊐̸",NotSquareSupersetEqual:"⋣",NotSubset:"⊂⃒",NotSubsetEqual:"⊈",NotSucceeds:"⊁",NotSucceedsEqual:"⪰̸",NotSucceedsSlantEqual:"⋡",NotSucceedsTilde:"≿̸",NotSuperset:"⊃⃒",NotSupersetEqual:"⊉",NotTilde:"≁",NotTildeEqual:"≄",NotTildeFullEqual:"≇",NotTildeTilde:"≉",NotVerticalBar:"∤",nparallel:"∦",npar:"∦",nparsl:"⫽⃥",npart:"∂̸",npolint:"⨔",npr:"⊀",nprcue:"⋠",nprec:"⊀",npreceq:"⪯̸",npre:"⪯̸",nrarrc:"⤳̸",nrarr:"↛",nrArr:"⇏",nrarrw:"↝̸",nrightarrow:"↛",nRightarrow:"⇏",nrtri:"⋫",nrtrie:"⋭",nsc:"⊁",nsccue:"⋡",nsce:"⪰̸",Nscr:"𝒩",nscr:"𝓃",nshortmid:"∤",nshortparallel:"∦",nsim:"≁",nsime:"≄",nsimeq:"≄",nsmid:"∤",nspar:"∦",nsqsube:"⋢",nsqsupe:"⋣",nsub:"⊄",nsubE:"⫅̸",nsube:"⊈",nsubset:"⊂⃒",nsubseteq:"⊈",nsubseteqq:"⫅̸",nsucc:"⊁",nsucceq:"⪰̸",nsup:"⊅",nsupE:"⫆̸",nsupe:"⊉",nsupset:"⊃⃒",nsupseteq:"⊉",nsupseteqq:"⫆̸",ntgl:"≹",Ntilde:"Ñ",ntilde:"ñ",ntlg:"≸",ntriangleleft:"⋪",ntrianglelefteq:"⋬",ntriangleright:"⋫",ntrianglerighteq:"⋭",Nu:"Ν",nu:"ν",num:"#",numero:"№",numsp:" ",nvap:"≍⃒",nvdash:"⊬",nvDash:"⊭",nVdash:"⊮",nVDash:"⊯",nvge:"≥⃒",nvgt:">⃒",nvHarr:"⤄",nvinfin:"⧞",nvlArr:"⤂",nvle:"≤⃒",nvlt:"<⃒",nvltrie:"⊴⃒",nvrArr:"⤃",nvrtrie:"⊵⃒",nvsim:"∼⃒",nwarhk:"⤣",nwarr:"↖",nwArr:"⇖",nwarrow:"↖",nwnear:"⤧",Oacute:"Ó",oacute:"ó",oast:"⊛",Ocirc:"Ô",ocirc:"ô",ocir:"⊚",Ocy:"О",ocy:"о",odash:"⊝",Odblac:"Ő",odblac:"ő",odiv:"⨸",odot:"⊙",odsold:"⦼",OElig:"Œ",oelig:"œ",ofcir:"⦿",Ofr:"𝔒",ofr:"𝔬",ogon:"˛",Ograve:"Ò",ograve:"ò",ogt:"⧁",ohbar:"⦵",ohm:"Ω",oint:"∮",olarr:"↺",olcir:"⦾",olcross:"⦻",oline:"‾",olt:"⧀",Omacr:"Ō",omacr:"ō",Omega:"Ω",omega:"ω",Omicron:"Ο",omicron:"ο",omid:"⦶",ominus:"⊖",Oopf:"𝕆",oopf:"𝕠",opar:"⦷",OpenCurlyDoubleQuote:"“",OpenCurlyQuote:"‘",operp:"⦹",oplus:"⊕",orarr:"↻",Or:"⩔",or:"∨",ord:"⩝",order:"ℴ",orderof:"ℴ",ordf:"ª",ordm:"º",origof:"⊶",oror:"⩖",orslope:"⩗",orv:"⩛",oS:"Ⓢ",Oscr:"𝒪",oscr:"ℴ",Oslash:"Ø",oslash:"ø",osol:"⊘",Otilde:"Õ",otilde:"õ",otimesas:"⨶",Otimes:"⨷",otimes:"⊗",Ouml:"Ö",ouml:"ö",ovbar:"⌽",OverBar:"‾",OverBrace:"⏞",OverBracket:"⎴",OverParenthesis:"⏜",para:"¶",parallel:"∥",par:"∥",parsim:"⫳",parsl:"⫽",part:"∂",PartialD:"∂",Pcy:"П",pcy:"п",percnt:"%",period:".",permil:"‰",perp:"⊥",pertenk:"‱",Pfr:"𝔓",pfr:"𝔭",Phi:"Φ",phi:"φ",phiv:"ϕ",phmmat:"ℳ",phone:"☎",Pi:"Π",pi:"π",pitchfork:"⋔",piv:"ϖ",planck:"ℏ",planckh:"ℎ",plankv:"ℏ",plusacir:"⨣",plusb:"⊞",pluscir:"⨢",plus:"+",plusdo:"∔",plusdu:"⨥",pluse:"⩲",PlusMinus:"±",plusmn:"±",plussim:"⨦",plustwo:"⨧",pm:"±",Poincareplane:"ℌ",pointint:"⨕",popf:"𝕡",Popf:"ℙ",pound:"£",prap:"⪷",Pr:"⪻",pr:"≺",prcue:"≼",precapprox:"⪷",prec:"≺",preccurlyeq:"≼",Precedes:"≺",PrecedesEqual:"⪯",PrecedesSlantEqual:"≼",PrecedesTilde:"≾",preceq:"⪯",precnapprox:"⪹",precneqq:"⪵",precnsim:"⋨",pre:"⪯",prE:"⪳",precsim:"≾",prime:"′",Prime:"″",primes:"ℙ",prnap:"⪹",prnE:"⪵",prnsim:"⋨",prod:"∏",Product:"∏",profalar:"⌮",profline:"⌒",profsurf:"⌓",prop:"∝",Proportional:"∝",Proportion:"∷",propto:"∝",prsim:"≾",prurel:"⊰",Pscr:"𝒫",pscr:"𝓅",Psi:"Ψ",psi:"ψ",puncsp:" ",Qfr:"𝔔",qfr:"𝔮",qint:"⨌",qopf:"𝕢",Qopf:"ℚ",qprime:"⁗",Qscr:"𝒬",qscr:"𝓆",quaternions:"ℍ",quatint:"⨖",quest:"?",questeq:"≟",quot:'"',QUOT:'"',rAarr:"⇛",race:"∽̱",Racute:"Ŕ",racute:"ŕ",radic:"√",raemptyv:"⦳",rang:"⟩",Rang:"⟫",rangd:"⦒",range:"⦥",rangle:"⟩",raquo:"»",rarrap:"⥵",rarrb:"⇥",rarrbfs:"⤠",rarrc:"⤳",rarr:"→",Rarr:"↠",rArr:"⇒",rarrfs:"⤞",rarrhk:"↪",rarrlp:"↬",rarrpl:"⥅",rarrsim:"⥴",Rarrtl:"⤖",rarrtl:"↣",rarrw:"↝",ratail:"⤚",rAtail:"⤜",ratio:"∶",rationals:"ℚ",rbarr:"⤍",rBarr:"⤏",RBarr:"⤐",rbbrk:"❳",rbrace:"}",rbrack:"]",rbrke:"⦌",rbrksld:"⦎",rbrkslu:"⦐",Rcaron:"Ř",rcaron:"ř",Rcedil:"Ŗ",rcedil:"ŗ",rceil:"⌉",rcub:"}",Rcy:"Р",rcy:"р",rdca:"⤷",rdldhar:"⥩",rdquo:"”",rdquor:"”",rdsh:"↳",real:"ℜ",realine:"ℛ",realpart:"ℜ",reals:"ℝ",Re:"ℜ",rect:"▭",reg:"®",REG:"®",ReverseElement:"∋",ReverseEquilibrium:"⇋",ReverseUpEquilibrium:"⥯",rfisht:"⥽",rfloor:"⌋",rfr:"𝔯",Rfr:"ℜ",rHar:"⥤",rhard:"⇁",rharu:"⇀",rharul:"⥬",Rho:"Ρ",rho:"ρ",rhov:"ϱ",RightAngleBracket:"⟩",RightArrowBar:"⇥",rightarrow:"→",RightArrow:"→",Rightarrow:"⇒",RightArrowLeftArrow:"⇄",rightarrowtail:"↣",RightCeiling:"⌉",RightDoubleBracket:"⟧",RightDownTeeVector:"⥝",RightDownVectorBar:"⥕",RightDownVector:"⇂",RightFloor:"⌋",rightharpoondown:"⇁",rightharpoonup:"⇀",rightleftarrows:"⇄",rightleftharpoons:"⇌",rightrightarrows:"⇉",rightsquigarrow:"↝",RightTeeArrow:"↦",RightTee:"⊢",RightTeeVector:"⥛",rightthreetimes:"⋌",RightTriangleBar:"⧐",RightTriangle:"⊳",RightTriangleEqual:"⊵",RightUpDownVector:"⥏",RightUpTeeVector:"⥜",RightUpVectorBar:"⥔",RightUpVector:"↾",RightVectorBar:"⥓",RightVector:"⇀",ring:"˚",risingdotseq:"≓",rlarr:"⇄",rlhar:"⇌",rlm:"‏",rmoustache:"⎱",rmoust:"⎱",rnmid:"⫮",roang:"⟭",roarr:"⇾",robrk:"⟧",ropar:"⦆",ropf:"𝕣",Ropf:"ℝ",roplus:"⨮",rotimes:"⨵",RoundImplies:"⥰",rpar:")",rpargt:"⦔",rppolint:"⨒",rrarr:"⇉",Rrightarrow:"⇛",rsaquo:"›",rscr:"𝓇",Rscr:"ℛ",rsh:"↱",Rsh:"↱",rsqb:"]",rsquo:"’",rsquor:"’",rthree:"⋌",rtimes:"⋊",rtri:"▹",rtrie:"⊵",rtrif:"▸",rtriltri:"⧎",RuleDelayed:"⧴",ruluhar:"⥨",rx:"℞",Sacute:"Ś",sacute:"ś",sbquo:"‚",scap:"⪸",Scaron:"Š",scaron:"š",Sc:"⪼",sc:"≻",sccue:"≽",sce:"⪰",scE:"⪴",Scedil:"Ş",scedil:"ş",Scirc:"Ŝ",scirc:"ŝ",scnap:"⪺",scnE:"⪶",scnsim:"⋩",scpolint:"⨓",scsim:"≿",Scy:"С",scy:"с",sdotb:"⊡",sdot:"⋅",sdote:"⩦",searhk:"⤥",searr:"↘",seArr:"⇘",searrow:"↘",sect:"§",semi:";",seswar:"⤩",setminus:"∖",setmn:"∖",sext:"✶",Sfr:"𝔖",sfr:"𝔰",sfrown:"⌢",sharp:"♯",SHCHcy:"Щ",shchcy:"щ",SHcy:"Ш",shcy:"ш",ShortDownArrow:"↓",ShortLeftArrow:"←",shortmid:"∣",shortparallel:"∥",ShortRightArrow:"→",ShortUpArrow:"↑",shy:"­",Sigma:"Σ",sigma:"σ",sigmaf:"ς",sigmav:"ς",sim:"∼",simdot:"⩪",sime:"≃",simeq:"≃",simg:"⪞",simgE:"⪠",siml:"⪝",simlE:"⪟",simne:"≆",simplus:"⨤",simrarr:"⥲",slarr:"←",SmallCircle:"∘",smallsetminus:"∖",smashp:"⨳",smeparsl:"⧤",smid:"∣",smile:"⌣",smt:"⪪",smte:"⪬",smtes:"⪬︀",SOFTcy:"Ь",softcy:"ь",solbar:"⌿",solb:"⧄",sol:"/",Sopf:"𝕊",sopf:"𝕤",spades:"♠",spadesuit:"♠",spar:"∥",sqcap:"⊓",sqcaps:"⊓︀",sqcup:"⊔",sqcups:"⊔︀",Sqrt:"√",sqsub:"⊏",sqsube:"⊑",sqsubset:"⊏",sqsubseteq:"⊑",sqsup:"⊐",sqsupe:"⊒",sqsupset:"⊐",sqsupseteq:"⊒",square:"□",Square:"□",SquareIntersection:"⊓",SquareSubset:"⊏",SquareSubsetEqual:"⊑",SquareSuperset:"⊐",SquareSupersetEqual:"⊒",SquareUnion:"⊔",squarf:"▪",squ:"□",squf:"▪",srarr:"→",Sscr:"𝒮",sscr:"𝓈",ssetmn:"∖",ssmile:"⌣",sstarf:"⋆",Star:"⋆",star:"☆",starf:"★",straightepsilon:"ϵ",straightphi:"ϕ",strns:"¯",sub:"⊂",Sub:"⋐",subdot:"⪽",subE:"⫅",sube:"⊆",subedot:"⫃",submult:"⫁",subnE:"⫋",subne:"⊊",subplus:"⪿",subrarr:"⥹",subset:"⊂",Subset:"⋐",subseteq:"⊆",subseteqq:"⫅",SubsetEqual:"⊆",subsetneq:"⊊",subsetneqq:"⫋",subsim:"⫇",subsub:"⫕",subsup:"⫓",succapprox:"⪸",succ:"≻",succcurlyeq:"≽",Succeeds:"≻",SucceedsEqual:"⪰",SucceedsSlantEqual:"≽",SucceedsTilde:"≿",succeq:"⪰",succnapprox:"⪺",succneqq:"⪶",succnsim:"⋩",succsim:"≿",SuchThat:"∋",sum:"∑",Sum:"∑",sung:"♪",sup1:"¹",sup2:"²",sup3:"³",sup:"⊃",Sup:"⋑",supdot:"⪾",supdsub:"⫘",supE:"⫆",supe:"⊇",supedot:"⫄",Superset:"⊃",SupersetEqual:"⊇",suphsol:"⟉",suphsub:"⫗",suplarr:"⥻",supmult:"⫂",supnE:"⫌",supne:"⊋",supplus:"⫀",supset:"⊃",Supset:"⋑",supseteq:"⊇",supseteqq:"⫆",supsetneq:"⊋",supsetneqq:"⫌",supsim:"⫈",supsub:"⫔",supsup:"⫖",swarhk:"⤦",swarr:"↙",swArr:"⇙",swarrow:"↙",swnwar:"⤪",szlig:"ß",Tab:" ",target:"⌖",Tau:"Τ",tau:"τ",tbrk:"⎴",Tcaron:"Ť",tcaron:"ť",Tcedil:"Ţ",tcedil:"ţ",Tcy:"Т",tcy:"т",tdot:"⃛",telrec:"⌕",Tfr:"𝔗",tfr:"𝔱",there4:"∴",therefore:"∴",Therefore:"∴",Theta:"Θ",theta:"θ",thetasym:"ϑ",thetav:"ϑ",thickapprox:"≈",thicksim:"∼",ThickSpace:"  ",ThinSpace:" ",thinsp:" ",thkap:"≈",thksim:"∼",THORN:"Þ",thorn:"þ",tilde:"˜",Tilde:"∼",TildeEqual:"≃",TildeFullEqual:"≅",TildeTilde:"≈",timesbar:"⨱",timesb:"⊠",times:"×",timesd:"⨰",tint:"∭",toea:"⤨",topbot:"⌶",topcir:"⫱",top:"⊤",Topf:"𝕋",topf:"𝕥",topfork:"⫚",tosa:"⤩",tprime:"‴",trade:"™",TRADE:"™",triangle:"▵",triangledown:"▿",triangleleft:"◃",trianglelefteq:"⊴",triangleq:"≜",triangleright:"▹",trianglerighteq:"⊵",tridot:"◬",trie:"≜",triminus:"⨺",TripleDot:"⃛",triplus:"⨹",trisb:"⧍",tritime:"⨻",trpezium:"⏢",Tscr:"𝒯",tscr:"𝓉",TScy:"Ц",tscy:"ц",TSHcy:"Ћ",tshcy:"ћ",Tstrok:"Ŧ",tstrok:"ŧ",twixt:"≬",twoheadleftarrow:"↞",twoheadrightarrow:"↠",Uacute:"Ú",uacute:"ú",uarr:"↑",Uarr:"↟",uArr:"⇑",Uarrocir:"⥉",Ubrcy:"Ў",ubrcy:"ў",Ubreve:"Ŭ",ubreve:"ŭ",Ucirc:"Û",ucirc:"û",Ucy:"У",ucy:"у",udarr:"⇅",Udblac:"Ű",udblac:"ű",udhar:"⥮",ufisht:"⥾",Ufr:"𝔘",ufr:"𝔲",Ugrave:"Ù",ugrave:"ù",uHar:"⥣",uharl:"↿",uharr:"↾",uhblk:"▀",ulcorn:"⌜",ulcorner:"⌜",ulcrop:"⌏",ultri:"◸",Umacr:"Ū",umacr:"ū",uml:"¨",UnderBar:"_",UnderBrace:"⏟",UnderBracket:"⎵",UnderParenthesis:"⏝",Union:"⋃",UnionPlus:"⊎",Uogon:"Ų",uogon:"ų",Uopf:"𝕌",uopf:"𝕦",UpArrowBar:"⤒",uparrow:"↑",UpArrow:"↑",Uparrow:"⇑",UpArrowDownArrow:"⇅",updownarrow:"↕",UpDownArrow:"↕",Updownarrow:"⇕",UpEquilibrium:"⥮",upharpoonleft:"↿",upharpoonright:"↾",uplus:"⊎",UpperLeftArrow:"↖",UpperRightArrow:"↗",upsi:"υ",Upsi:"ϒ",upsih:"ϒ",Upsilon:"Υ",upsilon:"υ",UpTeeArrow:"↥",UpTee:"⊥",upuparrows:"⇈",urcorn:"⌝",urcorner:"⌝",urcrop:"⌎",Uring:"Ů",uring:"ů",urtri:"◹",Uscr:"𝒰",uscr:"𝓊",utdot:"⋰",Utilde:"Ũ",utilde:"ũ",utri:"▵",utrif:"▴",uuarr:"⇈",Uuml:"Ü",uuml:"ü",uwangle:"⦧",vangrt:"⦜",varepsilon:"ϵ",varkappa:"ϰ",varnothing:"∅",varphi:"ϕ",varpi:"ϖ",varpropto:"∝",varr:"↕",vArr:"⇕",varrho:"ϱ",varsigma:"ς",varsubsetneq:"⊊︀",varsubsetneqq:"⫋︀",varsupsetneq:"⊋︀",varsupsetneqq:"⫌︀",vartheta:"ϑ",vartriangleleft:"⊲",vartriangleright:"⊳",vBar:"⫨",Vbar:"⫫",vBarv:"⫩",Vcy:"В",vcy:"в",vdash:"⊢",vDash:"⊨",Vdash:"⊩",VDash:"⊫",Vdashl:"⫦",veebar:"⊻",vee:"∨",Vee:"⋁",veeeq:"≚",vellip:"⋮",verbar:"|",Verbar:"‖",vert:"|",Vert:"‖",VerticalBar:"∣",VerticalLine:"|",VerticalSeparator:"❘",VerticalTilde:"≀",VeryThinSpace:" ",Vfr:"𝔙",vfr:"𝔳",vltri:"⊲",vnsub:"⊂⃒",vnsup:"⊃⃒",Vopf:"𝕍",vopf:"𝕧",vprop:"∝",vrtri:"⊳",Vscr:"𝒱",vscr:"𝓋",vsubnE:"⫋︀",vsubne:"⊊︀",vsupnE:"⫌︀",vsupne:"⊋︀",Vvdash:"⊪",vzigzag:"⦚",Wcirc:"Ŵ",wcirc:"ŵ",wedbar:"⩟",wedge:"∧",Wedge:"⋀",wedgeq:"≙",weierp:"℘",Wfr:"𝔚",wfr:"𝔴",Wopf:"𝕎",wopf:"𝕨",wp:"℘",wr:"≀",wreath:"≀",Wscr:"𝒲",wscr:"𝓌",xcap:"⋂",xcirc:"◯",xcup:"⋃",xdtri:"▽",Xfr:"𝔛",xfr:"𝔵",xharr:"⟷",xhArr:"⟺",Xi:"Ξ",xi:"ξ",xlarr:"⟵",xlArr:"⟸",xmap:"⟼",xnis:"⋻",xodot:"⨀",Xopf:"𝕏",xopf:"𝕩",xoplus:"⨁",xotime:"⨂",xrarr:"⟶",xrArr:"⟹",Xscr:"𝒳",xscr:"𝓍",xsqcup:"⨆",xuplus:"⨄",xutri:"△",xvee:"⋁",xwedge:"⋀",Yacute:"Ý",yacute:"ý",YAcy:"Я",yacy:"я",Ycirc:"Ŷ",ycirc:"ŷ",Ycy:"Ы",ycy:"ы",yen:"¥",Yfr:"𝔜",yfr:"𝔶",YIcy:"Ї",yicy:"ї",Yopf:"𝕐",yopf:"𝕪",Yscr:"𝒴",yscr:"𝓎",YUcy:"Ю",yucy:"ю",yuml:"ÿ",Yuml:"Ÿ",Zacute:"Ź",zacute:"ź",Zcaron:"Ž",zcaron:"ž",Zcy:"З",zcy:"з",Zdot:"Ż",zdot:"ż",zeetrf:"ℨ",ZeroWidthSpace:"​",Zeta:"Ζ",zeta:"ζ",zfr:"𝔷",Zfr:"ℨ",ZHcy:"Ж",zhcy:"ж",zigrarr:"⇝",zopf:"𝕫",Zopf:"ℤ",Zscr:"𝒵",zscr:"𝓏",zwj:"‍",zwnj:"‌"} +},{}],16:[function(require,module,exports){module.exports={Aacute:"Á",aacute:"á",Acirc:"Â",acirc:"â",acute:"´",AElig:"Æ",aelig:"æ",Agrave:"À",agrave:"à",amp:"&",AMP:"&",Aring:"Å",aring:"å",Atilde:"Ã",atilde:"ã",Auml:"Ä",auml:"ä",brvbar:"¦",Ccedil:"Ç",ccedil:"ç",cedil:"¸",cent:"¢",copy:"©",COPY:"©",curren:"¤",deg:"°",divide:"÷",Eacute:"É",eacute:"é",Ecirc:"Ê",ecirc:"ê",Egrave:"È",egrave:"è",ETH:"Ð",eth:"ð",Euml:"Ë",euml:"ë",frac12:"½",frac14:"¼",frac34:"¾",gt:">",GT:">",Iacute:"Í",iacute:"í",Icirc:"Î",icirc:"î",iexcl:"¡",Igrave:"Ì",igrave:"ì",iquest:"¿",Iuml:"Ï",iuml:"ï",laquo:"«",lt:"<",LT:"<",macr:"¯",micro:"µ",middot:"·",nbsp:" ",not:"¬",Ntilde:"Ñ",ntilde:"ñ",Oacute:"Ó",oacute:"ó",Ocirc:"Ô",ocirc:"ô",Ograve:"Ò",ograve:"ò",ordf:"ª",ordm:"º",Oslash:"Ø",oslash:"ø",Otilde:"Õ",otilde:"õ",Ouml:"Ö",ouml:"ö",para:"¶",plusmn:"±",pound:"£",quot:'"',QUOT:'"',raquo:"»",reg:"®",REG:"®",sect:"§",shy:"­",sup1:"¹",sup2:"²",sup3:"³",szlig:"ß",THORN:"Þ",thorn:"þ",times:"×",Uacute:"Ú",uacute:"ú",Ucirc:"Û",ucirc:"û",Ugrave:"Ù",ugrave:"ù",uml:"¨",Uuml:"Ü",uuml:"ü",Yacute:"Ý",yacute:"ý",yen:"¥",yuml:"ÿ"}},{}],17:[function(require,module,exports){module.exports={amp:"&",apos:"'",gt:">",lt:"<",quot:'"'}},{}],18:[function(require,module,exports){"use strict";function getDecodeCache(exclude){var i,ch,cache=decodeCache[exclude];if(cache)return cache;for(cache=decodeCache[exclude]=[],i=0;128>i;i++)ch=String.fromCharCode(i),cache.push(ch);for(i=0;exclude.length>i;i++)ch=exclude.charCodeAt(i),cache[ch]="%"+("0"+ch.toString(16).toUpperCase()).slice(-2);return cache}function decode(string,exclude){var cache;return"string"!=typeof exclude&&(exclude=decode.defaultChars),cache=getDecodeCache(exclude),string.replace(/(%[a-f0-9]{2})+/gi,function(seq){var i,l,b1,b2,b3,b4,char,result="";for(i=0,l=seq.length;l>i;i+=3)b1=parseInt(seq.slice(i+1,i+3),16),128>b1?result+=cache[b1]:192===(224&b1)&&l>i+3&&(b2=parseInt(seq.slice(i+4,i+6),16),128===(192&b2))?(char=b1<<6&1984|63&b2,result+=128>char?"��":String.fromCharCode(char),i+=3):224===(240&b1)&&l>i+6&&(b2=parseInt(seq.slice(i+4,i+6),16),b3=parseInt(seq.slice(i+7,i+9),16),128===(192&b2)&&128===(192&b3))?(char=b1<<12&61440|b2<<6&4032|63&b3,result+=2048>char||char>=55296&&57343>=char?"���":String.fromCharCode(char),i+=6):240===(248&b1)&&l>i+9&&(b2=parseInt(seq.slice(i+4,i+6),16),b3=parseInt(seq.slice(i+7,i+9),16),b4=parseInt(seq.slice(i+10,i+12),16),128===(192&b2)&&128===(192&b3)&&128===(192&b4))?(char=b1<<18&1835008|b2<<12&258048|b3<<6&4032|63&b4,65536>char||char>1114111?result+="����":(char-=65536,result+=String.fromCharCode(55296+(char>>10),56320+(1023&char))),i+=9):result+="�";return result})}var decodeCache={};decode.defaultChars=";/?:@&=+$,#",decode.componentChars="",module.exports=decode},{}],19:[function(require,module,exports){"use strict";function getEncodeCache(exclude){var i,ch,cache=encodeCache[exclude];if(cache)return cache;for(cache=encodeCache[exclude]=[],i=0;128>i;i++)ch=String.fromCharCode(i),cache.push(/^[0-9a-z]$/i.test(ch)?ch:"%"+("0"+i.toString(16).toUpperCase()).slice(-2));for(i=0;exclude.length>i;i++)cache[exclude.charCodeAt(i)]=exclude[i];return cache}function encode(string,exclude,keepEscaped){var i,l,code,nextCode,cache,result="";for("string"!=typeof exclude&&(keepEscaped=exclude,exclude=encode.defaultChars),"undefined"==typeof keepEscaped&&(keepEscaped=!0),cache=getEncodeCache(exclude),i=0,l=string.length;l>i;i++)if(code=string.charCodeAt(i),keepEscaped&&37===code&&l>i+2&&/^[0-9a-f]{2}$/i.test(string.slice(i+1,i+3)))result+=string.slice(i,i+3),i+=2;else if(128>code)result+=cache[code];else if(code>=55296&&57343>=code){if(code>=55296&&56319>=code&&l>i+1&&(nextCode=string.charCodeAt(i+1),nextCode>=56320&&57343>=nextCode)){result+=encodeURIComponent(string[i]+string[i+1]),i++;continue}result+="%EF%BF%BD"}else result+=encodeURIComponent(string[i]);return result}var encodeCache={};encode.defaultChars=";/?:@&=+$,-_.!~*'()#",encode.componentChars="-_.!~*'()",module.exports=encode},{}],20:[function(require,module,exports){String.prototype.repeat||!function(){"use strict";var defineProperty=function(){try{var object={},$defineProperty=Object.defineProperty,result=$defineProperty(object,object,object)&&$defineProperty}catch(error){}return result}(),repeat=function(count){if(null==this)throw TypeError();var string=String(this),n=count?Number(count):0;if(n!=n&&(n=0),0>n||1/0==n)throw RangeError();for(var result="";n;)n%2==1&&(result+=string),n>1&&(string+=string),n>>=1;return result};defineProperty?defineProperty(String.prototype,"repeat",{value:repeat,configurable:!0,writable:!0}):String.prototype.repeat=repeat}()},{}]},{},[5])(5)}); \ No newline at end of file diff --git a/js/vendor/dompurify/purify.js b/js/vendor/dompurify/purify.js new file mode 100644 index 0000000000..552eaafe33 --- /dev/null +++ b/js/vendor/dompurify/purify.js @@ -0,0 +1,694 @@ +;(function(factory) { + 'use strict'; + /* global window: false, define: false, module: false */ + var root = typeof window === 'undefined' ? null : window; + + if (typeof define === 'function' && define.amd) { + define(function(){ return factory(root); }); + } else if (typeof module !== 'undefined') { + module.exports = factory(root); + } else { + root.DOMPurify = factory(root); + } +}(function factory(window) { + 'use strict'; + + var DOMPurify = function(window) { + return factory(window); + }; + + /** + * Version label, exposed for easier checks + * if DOMPurify is up to date or not + */ + DOMPurify.version = '0.6.5'; + + if (!window || !window.document || window.document.nodeType !== 9) { + // not running in a browser, provide a factory function + // so that you can pass your own Window + DOMPurify.isSupported = false; + return DOMPurify; + } + + var document = window.document; + var originalDocument = document; + var DocumentFragment = window.DocumentFragment; + var HTMLTemplateElement = window.HTMLTemplateElement; + var NodeFilter = window.NodeFilter; + var NamedNodeMap = window.NamedNodeMap || window.MozNamedAttrMap; + var Text = window.Text; + var Comment = window.Comment; + + // As per issue #47, the web-components registry is inherited by a + // new document created via createHTMLDocument. As per the spec + // (http://w3c.github.io/webcomponents/spec/custom/#creating-and-passing-registries) + // a new empty registry is used when creating a template contents owner + // document, so we use that as our parent document to ensure nothing + // is inherited. + if (typeof HTMLTemplateElement === 'function') { + document = document.createElement('template').content.ownerDocument; + } + var implementation = document.implementation; + var createNodeIterator = document.createNodeIterator; + var getElementsByTagName = document.getElementsByTagName; + var createDocumentFragment = document.createDocumentFragment; + var importNode = originalDocument.importNode; + + var hooks = {}; + + /** + * Expose whether this browser supports running the full DOMPurify. + */ + DOMPurify.isSupported = + typeof implementation.createHTMLDocument !== 'undefined' && + document.documentMode !== 9; + + /* Add properties to a lookup table */ + var _addToSet = function(set, array) { + var l = array.length; + while (l--) { + set[array[l]] = true; + } + return set; + }; + + /* Shallow clone an object */ + var _cloneObj = function(object) { + var newObject = {}; + var property; + for (property in object) { + if (object.hasOwnProperty(property)) { + newObject[property] = object[property]; + } + } + return newObject; + }; + + /** + * We consider the elements and attributes below to be safe. Ideally + * don't add any new ones but feel free to remove unwanted ones. + */ + + /* allowed element names */ + var ALLOWED_TAGS = null; + var DEFAULT_ALLOWED_TAGS = _addToSet({}, [ + + // HTML + 'a','abbr','acronym','address','area','article','aside','audio','b', + 'bdi','bdo','big','blink','blockquote','body','br','button','canvas', + 'caption','center','cite','code','col','colgroup','content','data', + 'datalist','dd','decorator','del','details','dfn','dir','div','dl','dt', + 'element','em','fieldset','figcaption','figure','font','footer','form', + 'h1','h2','h3','h4','h5','h6','head','header','hgroup','hr','html','i', + 'img','input','ins','kbd','label','legend','li','main','map','mark', + 'marquee','menu','menuitem','meter','nav','nobr','ol','optgroup', + 'option','output','p','pre','progress','q','rp','rt','ruby','s','samp', + 'section','select','shadow','small','source','spacer','span','strike', + 'strong','style','sub','summary','sup','table','tbody','td','template', + 'textarea','tfoot','th','thead','time','tr','track','tt','u','ul','var', + 'video','wbr', + + // SVG + 'svg','altglyph','altglyphdef','altglyphitem','animatecolor', + 'animatemotion','animatetransform','circle','clippath','defs','desc', + 'ellipse','font','g','glyph','glyphref','hkern','image','line', + 'lineargradient','marker','mask','metadata','mpath','path','pattern', + 'polygon','polyline','radialgradient','rect','stop','switch','symbol', + 'text','textpath','title','tref','tspan','view','vkern', + + //MathML + 'math','menclose','merror','mfenced','mfrac','mglyph','mi','mlabeledtr', + 'mmuliscripts','mn','mo','mover','mpadded','mphantom','mroot','mrow', + 'ms','mpspace','msqrt','mystyle','msub','msup','msubsup','mtable','mtd', + 'mtext','mtr','munder','munderover', + + //Text + '#text' + ]); + + /* Allowed attribute names */ + var ALLOWED_ATTR = null; + var DEFAULT_ALLOWED_ATTR = _addToSet({}, [ + + // HTML + 'accept','action','align','alt','autocomplete','background','bgcolor', + 'border','cellpadding','cellspacing','checked','cite','class','clear','color', + 'cols','colspan','coords','datetime','default','dir','disabled', + 'download','enctype','face','for','headers','height','hidden','high','href', + 'hreflang','id','ismap','label','lang','list','loop', 'low','max', + 'maxlength','media','method','min','multiple','name','noshade','novalidate', + 'nowrap','open','optimum','pattern','placeholder','poster','preload','pubdate', + 'radiogroup','readonly','rel','required','rev','reversed','rows', + 'rowspan','spellcheck','scope','selected','shape','size','span', + 'srclang','start','src','step','style','summary','tabindex','title', + 'type','usemap','valign','value','width','xmlns', + + // SVG + 'accent-height','accumulate','additivive','alignment-baseline', + 'ascent','azimuth','baseline-shift','bias','clip','clip-path', + 'clip-rule','color','color-interpolation','color-interpolation-filters', + 'color-profile','color-rendering','cx','cy','d','dy','dy','direction', + 'display','divisor','dur','elevation','end','fill','fill-opacity', + 'fill-rule','filter','flood-color','flood-opacity','font-family', + 'font-size','font-size-adjust','font-stretch','font-style','font-variant', + 'font-weight','image-rendering','in','in2','k1','k2','k3','k4','kerning', + 'letter-spacing','lighting-color','local','marker-end','marker-mid', + 'marker-start','max','mask','mode','min','offset','operator','opacity', + 'order','overflow','paint-order','path','points','r','rx','ry','radius', + 'restart','scale','seed','shape-rendering','stop-color','stop-opacity', + 'stroke-dasharray','stroke-dashoffset','stroke-linecap','stroke-linejoin', + 'stroke-miterlimit','stroke-opacity','stroke','stroke-width','transform', + 'text-anchor','text-decoration','text-rendering','u1','u2','viewbox', + 'visibility','word-spacing','wrap','writing-mode','x','x1','x2','y', + 'y1','y2','z', + + // MathML + 'accent','accentunder','bevelled','close','columnsalign','columnlines', + 'columnspan','denomalign','depth','display','displaystyle','fence', + 'frame','largeop','length','linethickness','lspace','lquote', + 'mathbackground','mathcolor','mathsize','mathvariant','maxsize', + 'minsize','movablelimits','notation','numalign','open','rowalign', + 'rowlines','rowspacing','rowspan','rspace','rquote','scriptlevel', + 'scriptminsize','scriptsizemultiplier','selection','separator', + 'separators','stretchy','subscriptshift','supscriptshift','symmetric', + 'voffset', + + // XML + 'xlink:href','xml:id','xlink:title','xml:space' + ]); + + /* Explicitly forbidden tags (overrides ALLOWED_TAGS/ADD_TAGS) */ + var FORBID_TAGS = null; + + /* Explicitly forbidden attributes (overrides ALLOWED_ATTR/ADD_ATTR) */ + var FORBID_ATTR = null; + + /* Decide if custom data attributes are okay */ + var ALLOW_DATA_ATTR = true; + + /* Output should be safe for jQuery's $() factory? */ + var SAFE_FOR_JQUERY = false; + + /* Decide if document with ... should be returned */ + var WHOLE_DOCUMENT = false; + + /* Decide if a DOM `HTMLBodyElement` should be returned, instead of a html string. + * If `WHOLE_DOCUMENT` is enabled a `HTMLHtmlElement` will be returned instead + */ + var RETURN_DOM = false; + + /* Decide if a DOM `DocumentFragment` should be returned, instead of a html string */ + var RETURN_DOM_FRAGMENT = false; + + /* If `RETURN_DOM` or `RETURN_DOM_FRAGMENT` is enabled, decide if the returned DOM + * `Node` is imported into the current `Document`. If this flag is not enabled the + * `Node` will belong (its ownerDocument) to a fresh `HTMLDocument`, created by + * DOMPurify. */ + var RETURN_DOM_IMPORT = false; + + /* Output should be free from DOM clobbering attacks? */ + var SANITIZE_DOM = true; + + /* Keep element content when removing element? */ + var KEEP_CONTENT = true; + + /* Tags to ignore content of when KEEP_CONTENT is true */ + var FORBID_CONTENTS = _addToSet({}, [ + 'audio', 'head', 'math', 'script', 'style', 'svg', 'video' + ]); + + /* Keep a reference to config to pass to hooks */ + var CONFIG = null; + + /* Ideally, do not touch anything below this line */ + /* ______________________________________________ */ + + var formElement = document.createElement('form'); + + /** + * _parseConfig + * + * @param optional config literal + */ + var _parseConfig = function(cfg) { + /* Shield configuration object from tampering */ + if (typeof cfg !== 'object') { + cfg = {}; + } + + /* Set configuration parameters */ + ALLOWED_TAGS = 'ALLOWED_TAGS' in cfg ? + _addToSet({}, cfg.ALLOWED_TAGS) : DEFAULT_ALLOWED_TAGS; + ALLOWED_ATTR = 'ALLOWED_ATTR' in cfg ? + _addToSet({}, cfg.ALLOWED_ATTR) : DEFAULT_ALLOWED_ATTR; + FORBID_TAGS = 'FORBID_TAGS' in cfg ? + _addToSet({}, cfg.FORBID_TAGS) : {}; + FORBID_ATTR = 'FORBID_ATTR' in cfg ? + _addToSet({}, cfg.FORBID_ATTR) : {}; + ALLOW_DATA_ATTR = cfg.ALLOW_DATA_ATTR !== false; // Default true + SAFE_FOR_JQUERY = cfg.SAFE_FOR_JQUERY || false; // Default false + WHOLE_DOCUMENT = cfg.WHOLE_DOCUMENT || false; // Default false + RETURN_DOM = cfg.RETURN_DOM || false; // Default false + RETURN_DOM_FRAGMENT = cfg.RETURN_DOM_FRAGMENT || false; // Default false + RETURN_DOM_IMPORT = cfg.RETURN_DOM_IMPORT || false; // Default false + SANITIZE_DOM = cfg.SANITIZE_DOM !== false; // Default true + KEEP_CONTENT = cfg.KEEP_CONTENT !== false; // Default true + + if (RETURN_DOM_FRAGMENT) { + RETURN_DOM = true; + } + + /* Merge configuration parameters */ + if (cfg.ADD_TAGS) { + if (ALLOWED_TAGS === DEFAULT_ALLOWED_TAGS) { + ALLOWED_TAGS = _cloneObj(ALLOWED_TAGS); + } + _addToSet(ALLOWED_TAGS, cfg.ADD_TAGS); + } + if (cfg.ADD_ATTR) { + if (ALLOWED_ATTR === DEFAULT_ALLOWED_ATTR) { + ALLOWED_ATTR = _cloneObj(ALLOWED_ATTR); + } + _addToSet(ALLOWED_ATTR, cfg.ADD_ATTR); + } + + /* Add #text in case KEEP_CONTENT is set to true */ + if (KEEP_CONTENT) { ALLOWED_TAGS['#text'] = true; } + + // Prevent further manipulation of configuration. + // Not available in IE8, Safari 5, etc. + if (Object && 'freeze' in Object) { Object.freeze(cfg); } + + CONFIG = cfg; + }; + + /** + * _forceRemove + * + * @param a DOM node + */ + var _forceRemove = function(node) { + try { + node.parentNode.removeChild(node); + } catch (e) { + node.outerHTML = ''; + } + }; + + /** + * _initDocument + * + * @param a string of dirty markup + * @return a DOM, filled with the dirty markup + */ + var _initDocument = function(dirty) { + /* Create new document to parse markup to */ + var doc = implementation.createHTMLDocument(''); + + /* Set content */ + var body = doc.body; + body.parentNode.removeChild(body.parentNode.firstElementChild); + body.outerHTML = dirty; + + /* Work on whole document or just its body */ + return getElementsByTagName.call(doc, + WHOLE_DOCUMENT ? 'html' : 'body')[0]; + }; + + /** + * _createIterator + * + * @param document/fragment to create iterator for + * @return iterator instance + */ + var _createIterator = function(root) { + return createNodeIterator.call(root.ownerDocument || root, + root, + NodeFilter.SHOW_ELEMENT + | NodeFilter.SHOW_COMMENT + | NodeFilter.SHOW_TEXT, + function() { return NodeFilter.FILTER_ACCEPT; }, + false + ); + }; + + /** + * _isClobbered + * + * @param element to check for clobbering attacks + * @return true if clobbered, false if safe + */ + var _isClobbered = function(elm) { + if (elm instanceof Text || elm instanceof Comment) { + return false; + } + if ( typeof elm.nodeName !== 'string' + || typeof elm.textContent !== 'string' + || typeof elm.removeChild !== 'function' + || !(elm.attributes instanceof NamedNodeMap) + || typeof elm.removeAttribute !== 'function' + || typeof elm.setAttribute !== 'function' + ) { + return true; + } + return false; + }; + + /** + * _sanitizeElements + * + * @protect nodeName + * @protect textContent + * @protect removeChild + * + * @param node to check for permission to exist + * @return true if node was killed, false if left alive + */ + var _sanitizeElements = function(currentNode) { + /* Execute a hook if present */ + _executeHook('beforeSanitizeElements', currentNode, null); + + /* Check if element is clobbered or can clobber */ + if (_isClobbered(currentNode)) { + _forceRemove(currentNode); + return true; + } + + /* Now let's check the element's type and name */ + var tagName = currentNode.nodeName.toLowerCase(); + + /* Execute a hook if present */ + _executeHook('uponSanitizeElement', currentNode, { + tagName: tagName + }); + + /* Remove element if anything forbids its presence */ + if (!ALLOWED_TAGS[tagName] || FORBID_TAGS[tagName]) { + /* Keep content except for black-listed elements */ + if (KEEP_CONTENT && !FORBID_CONTENTS[tagName] + && typeof currentNode.insertAdjacentHTML === 'function') { + try { + currentNode.insertAdjacentHTML('AfterEnd', currentNode.innerHTML); + } catch (e) {} + } + _forceRemove(currentNode); + return true; + } + + /* Finally, convert markup to cover jQuery behavior */ + if (SAFE_FOR_JQUERY && !currentNode.firstElementChild) { + currentNode.innerHTML = currentNode.textContent.replace(/ tag that has an "id" + // attribute at the time. + if (lcName === 'name' && + currentNode.nodeName === 'IMG' && attributes.id) { + idAttr = attributes.id; + attributes = Array.prototype.slice.apply(attributes); + currentNode.removeAttribute('id'); + currentNode.removeAttribute(name); + if (attributes.indexOf(idAttr) > l) { + currentNode.setAttribute('id', idAttr.value); + } + } else { + currentNode.removeAttribute(name); + } + + /* Did the hooks approve of the attribute? */ + if (!hookEvent.keepAttr) { + continue; + } + + /* Make sure attribute cannot clobber */ + if (SANITIZE_DOM && + (lcName === 'id' || lcName === 'name') && + (value in window || value in document || value in formElement)) { + continue; + } + + if ( + /* Check the name is permitted */ + ( + (ALLOWED_ATTR[lcName] && !FORBID_ATTR[lcName]) || + /* Allow potentially valid data-* attributes + * At least one character after "-" (https://html.spec.whatwg.org/multipage/dom.html#embedding-custom-non-visible-data-with-the-data-*-attributes) + * XML-compatible (https://html.spec.whatwg.org/multipage/infrastructure.html#xml-compatible and http://www.w3.org/TR/xml/#d0e804) */ + (ALLOW_DATA_ATTR && DATA_ATTR.test(lcName)) + ) && + /* Get rid of script and data URIs */ + ( + !IS_SCRIPT_OR_DATA.test(value.replace(ATTR_WHITESPACE,'')) || + /* Keep image data URIs alive if src is allowed */ + (lcName === 'src' && value.indexOf('data:') === 0 && + currentNode.nodeName === 'IMG') + ) + ) { + /* Handle invalid data-* attribute set by try-catching it */ + try { + currentNode.setAttribute(name, value); + } catch (e) {} + } + } + + /* Execute a hook if present */ + _executeHook('afterSanitizeAttributes', currentNode, null); + }; + var DATA_ATTR = /^data-[\w.\u00B7-\uFFFF-]/; + var IS_SCRIPT_OR_DATA = /^(?:\w+script|data):/i; + /* This needs to be extensive thanks to Webkit/Blink's behavior */ + var ATTR_WHITESPACE = /[\x00-\x20\xA0\u1680\u180E\u2000-\u2029\u205f\u3000]/g; + + /** + * _sanitizeShadowDOM + * + * @param fragment to iterate over recursively + * @return void + */ + var _sanitizeShadowDOM = function(fragment) { + var shadowNode; + var shadowIterator = _createIterator(fragment); + + /* Execute a hook if present */ + _executeHook('beforeSanitizeShadowDOM', fragment, null); + + while ( (shadowNode = shadowIterator.nextNode()) ) { + /* Execute a hook if present */ + _executeHook('uponSanitizeShadowNode', shadowNode, null); + + /* Sanitize tags and elements */ + if (_sanitizeElements(shadowNode)) { + continue; + } + + /* Deep shadow DOM detected */ + if (shadowNode.content instanceof DocumentFragment) { + _sanitizeShadowDOM(shadowNode.content); + } + + /* Check attributes, sanitize if necessary */ + _sanitizeAttributes(shadowNode); + } + + /* Execute a hook if present */ + _executeHook('afterSanitizeShadowDOM', fragment, null); + }; + + /** + * _executeHook + * Execute user configurable hooks + * + * @param {String} entryPoint Name of the hook's entry point + * @param {Node} currentNode + */ + var _executeHook = function(entryPoint, currentNode, data) { + if (!hooks[entryPoint]) { return; } + + hooks[entryPoint].forEach(function(hook) { + hook.call(DOMPurify, currentNode, data, CONFIG); + }); + }; + + /** + * sanitize + * Public method providing core sanitation functionality + * + * @param {String} dirty string + * @param {Object} configuration object + */ + DOMPurify.sanitize = function(dirty, cfg) { + /* Check we can run. Otherwise fall back or ignore */ + if (!DOMPurify.isSupported) { + if (typeof window.toStaticHTML === 'function' && typeof dirty === 'string') { + return window.toStaticHTML(dirty); + } + return dirty; + } + + /* Assign config vars */ + _parseConfig(cfg); + + /* Exit directly if we have nothing to do */ + if (!RETURN_DOM && !WHOLE_DOCUMENT && dirty.indexOf('<') === -1) { + return dirty; + } + + /* Initialize the document to work on */ + var body = _initDocument(dirty); + + /* Check we have a DOM node from the data */ + if (!body) { + return RETURN_DOM ? null : ''; + } + + /* Get node iterator */ + var currentNode; + var nodeIterator = _createIterator(body); + + /* Now start iterating over the created document */ + while ( (currentNode = nodeIterator.nextNode()) ) { + /* Sanitize tags and elements */ + if (_sanitizeElements(currentNode)) { + continue; + } + + /* Shadow DOM detected, sanitize it */ + if (currentNode.content instanceof DocumentFragment) { + _sanitizeShadowDOM(currentNode.content); + } + + /* Check attributes, sanitize if necessary */ + _sanitizeAttributes(currentNode); + } + + /* Return sanitized string or DOM */ + var returnNode; + if (RETURN_DOM) { + + if (RETURN_DOM_FRAGMENT) { + returnNode = createDocumentFragment.call(body.ownerDocument); + + while (body.firstChild) { + returnNode.appendChild(body.firstChild); + } + } else { + returnNode = body; + } + + if (RETURN_DOM_IMPORT) { + /* adoptNode() is not used because internal state is not reset + (e.g. the past names map of a HTMLFormElement), this is safe + in theory but we would rather not risk another attack vector. + The state that is cloned by importNode() is explicitly defined + by the specs. */ + returnNode = importNode.call(originalDocument, returnNode, true); + } + + return returnNode; + } + + return WHOLE_DOCUMENT ? body.outerHTML : body.innerHTML; + }; + + /** + * addHook + * Public method to add DOMPurify hooks + * + * @param {String} entryPoint + * @param {Function} hookFunction + */ + DOMPurify.addHook = function(entryPoint, hookFunction) { + if (typeof hookFunction !== 'function') { return; } + hooks[entryPoint] = hooks[entryPoint] || []; + hooks[entryPoint].push(hookFunction); + }; + + /** + * removeHook + * Public method to remove a DOMPurify hook at a given entryPoint + * (pops it from the stack of hooks if more are present) + * + * @param {String} entryPoint + * @return void + */ + DOMPurify.removeHook = function(entryPoint) { + if (hooks[entryPoint]) { + hooks[entryPoint].pop(); + } + }; + + /** + * removeHooks + * Public method to remove all DOMPurify hooks at a given entryPoint + * + * @param {String} entryPoint + * @return void + */ + DOMPurify.removeHooks = function(entryPoint) { + if (hooks[entryPoint]) { + hooks[entryPoint] = []; + } + }; + + /** + * removeAllHooks + * Public method to remove all DOMPurify hooks + * + * @return void + */ + DOMPurify.removeAllHooks = function() { + hooks = []; + }; + + return DOMPurify; +})); diff --git a/js/vendor/eventsource-polyfill/.bower.json b/js/vendor/eventsource-polyfill/.bower.json deleted file mode 100644 index 86a5d3d5c9..0000000000 --- a/js/vendor/eventsource-polyfill/.bower.json +++ /dev/null @@ -1,43 +0,0 @@ -{ - "name": "eventsource-polyfill", - "homepage": "https://github.com/amvtek/EventSource", - "authors": [ - "amvtek " - ], - "description": "A polyfill for http://www.w3.org/TR/eventsource/", - "main": [ - "javascript/src/eventsource.js", - "eventsource.min.js", - "README.rst" - ], - "keywords": [ - "sse", - "server sent events", - "eventsource", - "event-source", - "polyfill" - ], - "license": "MIT", - "ignore": [ - "**/.*", - "javascript", - "test_server", - "Gruntfile.js", - "package.json", - "node_modules", - "bower_components", - "test", - "tests", - "docs" - ], - "version": "0.9.7", - "_release": "0.9.7", - "_resolution": { - "type": "version", - "tag": "v0.9.7", - "commit": "32c3cfc08b2a3a84a6533063fee823e62987000f" - }, - "_source": "git://github.com/amvtek/EventSource.git", - "_target": "~0.*", - "_originalSource": "eventsource-polyfill" -} \ No newline at end of file diff --git a/js/vendor/eventsource-polyfill/LICENSE b/js/vendor/eventsource-polyfill/LICENSE deleted file mode 100644 index 62758d3fcf..0000000000 --- a/js/vendor/eventsource-polyfill/LICENSE +++ /dev/null @@ -1,21 +0,0 @@ -The MIT License (MIT) - -Copyright (c) 2014 AmvTek - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. \ No newline at end of file diff --git a/js/vendor/eventsource-polyfill/README.md b/js/vendor/eventsource-polyfill/README.md deleted file mode 100644 index c949243e99..0000000000 --- a/js/vendor/eventsource-polyfill/README.md +++ /dev/null @@ -1,75 +0,0 @@ -EventSource Polyfill -==================== - -Provide polyfill to support EventSource in browser where it is not available. - -> - Used in production -> - Tested in Internet Explorer 8 + -> - Tested in Android browser 2.1 + -> - [Documented][] -> - Run the [Browser test suite][] - -Installing ----------- - -### from source - -Download suitable project archive (zip or tar.gz) from [release page][] - -Include in your html documents one of the following javascript file: - -> - *dist/eventsource.js* -> - *dist/eventsource.min.js* (minified version) - -### Using bower package manager - -To install package from **bower registry**, type : - - bower install eventsource-polyfill - -Include in your html documents one of the following javascript file: - -> - *bower\_components/eventsource-polyfill/dist/eventsource.js* -> - *bower\_components/eventsource-polyfill/dist/eventsource.min.js* (minified version) - -### Using npm package manager - -To install package from **npm registry**, type : - - npm install eventsource-polyfill - -Note that this package may only be used with in **browser application**. - -If you are using [browserify][] , you just have to require this package in your main module… - -``` sourceCode -// load (Polyfill) EventSource, in case browser does not support it... -require('eventsource-polyfill'); -``` - -Run the tests now ------------------ - -With your web browser visit this [test site][Browser test suite] - -Allow **sufficient time** ( ~ 5 minutes) for the full Test Suite to run… - -Project content ---------------- - -dist/ - built version of javascript modules - -javascript/ - Contains polyfill module and related unit tests - -test_server/ - python server which generates *easy to test* **event stream** - -docs/ - documentation wiki - - [Documented]: https://github.com/amvtek/EventSource/wiki - [Browser test suite]: http://testevs.amvtek.com/ - [release page]: https://github.com/amvtek/EventSource/releases/latest - [browserify]: http://browserify.org diff --git a/js/vendor/eventsource-polyfill/bower.json b/js/vendor/eventsource-polyfill/bower.json deleted file mode 100644 index d2722f9239..0000000000 --- a/js/vendor/eventsource-polyfill/bower.json +++ /dev/null @@ -1,29 +0,0 @@ -{ - "name": "eventsource-polyfill", - "homepage": "https://github.com/amvtek/EventSource", - "authors": [ - "amvtek " - ], - "description": "A polyfill for http://www.w3.org/TR/eventsource/", - "main": ["javascript/src/eventsource.js", "eventsource.min.js", "README.rst"], - "keywords": [ - "sse", - "server sent events", - "eventsource", - "event-source", - "polyfill" - ], - "license": "MIT", - "ignore": [ - "**/.*", - "javascript", - "test_server", - "Gruntfile.js", - "package.json", - "node_modules", - "bower_components", - "test", - "tests", - "docs" - ] -} diff --git a/js/vendor/eventsource-polyfill/dist/browserify-eventsource.js b/js/vendor/eventsource-polyfill/dist/browserify-eventsource.js deleted file mode 100644 index 76b9b4adda..0000000000 --- a/js/vendor/eventsource-polyfill/dist/browserify-eventsource.js +++ /dev/null @@ -1,23 +0,0 @@ -/* - * CommonJS module that exports EventSource polyfill version 0.9.7 - * This module is intended for browser side use - * ===================================================================== - * THIS IS A POLYFILL MODULE, SO IT HAS SIDE EFFECTS - * IT AUTOMATICALLY CHECKS IF window OBJECT DEFINES EventSource - * AND ADD THE EXPORTED ONE IN CASE IT IS UNDEFINED - * ===================================================================== - * Supported by sc AmvTek srl - * :email: devel@amvtek.com - */ - - -var PolyfillEventSource = require('./eventsource.js').EventSource; -module.exports = PolyfillEventSource; - -// Add EventSource to window if it is missing... -if (window && !window.EventSource){ - window.EventSource = PolyfillEventSource; - if (console){ - console.log("polyfill-eventsource added missing EventSource to window"); - } -} diff --git a/js/vendor/eventsource-polyfill/dist/eventsource.js b/js/vendor/eventsource-polyfill/dist/eventsource.js deleted file mode 100644 index d3b563b34c..0000000000 --- a/js/vendor/eventsource-polyfill/dist/eventsource.js +++ /dev/null @@ -1,621 +0,0 @@ -/* - * EventSource polyfill version 0.9.7 - * Supported by sc AmvTek srl - * :email: devel@amvtek.com - */ -;(function (global) { - - if (global.EventSource && !global._eventSourceImportPrefix){ - return; - } - - var evsImportName = (global._eventSourceImportPrefix||'')+"EventSource"; - - var EventSource = function (url, options) { - - if (!url || typeof url != 'string') { - throw new SyntaxError('Not enough arguments'); - } - - this.URL = url; - this.setOptions(options); - var evs = this; - setTimeout(function(){evs.poll()}, 0); - }; - - EventSource.prototype = { - - CONNECTING: 0, - - OPEN: 1, - - CLOSED: 2, - - defaultOptions: { - - loggingEnabled: false, - - loggingPrefix: "eventsource", - - interval: 500, // milliseconds - - bufferSizeLimit: 256*1024, // bytes - - silentTimeout: 300000, // milliseconds - - getArgs:{ - 'evs_buffer_size_limit': 256*1024 - }, - - xhrHeaders:{ - 'Accept': 'text/event-stream', - 'Cache-Control': 'no-cache', - 'X-Requested-With': 'XMLHttpRequest' - } - }, - - setOptions: function(options){ - - var defaults = this.defaultOptions; - var option; - - // set all default options... - for (option in defaults){ - - if ( defaults.hasOwnProperty(option) ){ - this[option] = defaults[option]; - } - } - - // override with what is in options - for (option in options){ - - if (option in defaults && options.hasOwnProperty(option)){ - this[option] = options[option]; - } - } - - // if getArgs option is enabled - // ensure evs_buffer_size_limit corresponds to bufferSizeLimit - if (this.getArgs && this.bufferSizeLimit) { - - this.getArgs['evs_buffer_size_limit'] = this.bufferSizeLimit; - } - - // if console is not available, force loggingEnabled to false - if (typeof console === "undefined" || typeof console.log === "undefined") { - - this.loggingEnabled = false; - } - }, - - log: function(message) { - - if (this.loggingEnabled) { - - console.log("[" + this.loggingPrefix +"]:" + message) - } - }, - - poll: function() { - - try { - - if (this.readyState == this.CLOSED) { - return; - } - - this.cleanup(); - this.readyState = this.CONNECTING; - this.cursor = 0; - this.cache = ''; - this._xhr = new this.XHR(this); - this.resetNoActivityTimer(); - - } - catch (e) { - - // in an attempt to silence the errors - this.log('There were errors inside the pool try-catch'); - this.dispatchEvent('error', { type: 'error', data: e.message }); - } - }, - - pollAgain: function (interval) { - - // schedule poll to be called after interval milliseconds - var evs = this; - evs.readyState = evs.CONNECTING; - evs.dispatchEvent('error', { - type: 'error', - data: "Reconnecting " - }); - this._pollTimer = setTimeout(function(){evs.poll()}, interval||0); - }, - - - cleanup: function() { - - this.log('evs cleaning up') - - if (this._pollTimer){ - clearInterval(this._pollTimer); - this._pollTimer = null; - } - - if (this._noActivityTimer){ - clearInterval(this._noActivityTimer); - this._noActivityTimer = null; - } - - if (this._xhr){ - this._xhr.abort(); - this._xhr = null; - } - }, - - resetNoActivityTimer: function(){ - - if (this.silentTimeout){ - - if (this._noActivityTimer){ - clearInterval(this._noActivityTimer); - } - var evs = this; - this._noActivityTimer = setTimeout( - function(){ evs.log('Timeout! silentTImeout:'+evs.silentTimeout); evs.pollAgain(); }, - this.silentTimeout - ); - } - }, - - close: function () { - - this.readyState = this.CLOSED; - this.log('Closing connection. readyState: '+this.readyState); - this.cleanup(); - }, - - _onxhrdata: function() { - - var request = this._xhr; - - if (request.isReady() && !request.hasError() ) { - // reset the timer, as we have activity - this.resetNoActivityTimer(); - - // move this EventSource to OPEN state... - if (this.readyState == this.CONNECTING) { - this.readyState = this.OPEN; - this.dispatchEvent('open', { type: 'open' }); - } - - var buffer = request.getBuffer(); - - if (buffer.length > this.bufferSizeLimit) { - this.log('buffer.length > this.bufferSizeLimit'); - this.pollAgain(); - } - - if (this.cursor == 0 && buffer.length > 0){ - - // skip byte order mark \uFEFF character if it starts the stream - if (buffer.substring(0,1) == '\uFEFF'){ - this.cursor = 1; - } - } - - var lastMessageIndex = this.lastMessageIndex(buffer); - if (lastMessageIndex[0] >= this.cursor){ - - var newcursor = lastMessageIndex[1]; - var toparse = buffer.substring(this.cursor, newcursor); - this.parseStream(toparse); - this.cursor = newcursor; - } - - // if request is finished, reopen the connection - if (request.isDone()) { - this.log('request.isDone(). reopening the connection'); - this.pollAgain(this.interval); - } - } - else if (this.readyState !== this.CLOSED) { - - this.log('this.readyState !== this.CLOSED'); - this.pollAgain(this.interval); - - //MV: Unsure why an error was previously dispatched - } - }, - - parseStream: function(chunk) { - - // normalize line separators (\r\n,\r,\n) to \n - // remove white spaces that may precede \n - chunk = this.cache + this.normalizeToLF(chunk); - - var events = chunk.split('\n\n'); - - var i, j, eventType, datas, line, retry; - - for (i=0; i < (events.length - 1); i++) { - - eventType = 'message'; - datas = []; - parts = events[i].split('\n'); - - for (j=0; j < parts.length; j++) { - - line = this.trimWhiteSpace(parts[j]); - - if (line.indexOf('event') == 0) { - - eventType = line.replace(/event:?\s*/, ''); - } - else if (line.indexOf('retry') == 0) { - - retry = parseInt(line.replace(/retry:?\s*/, '')); - if(!isNaN(retry)) { - this.interval = retry; - } - } - else if (line.indexOf('data') == 0) { - - datas.push(line.replace(/data:?\s*/, '')); - } - else if (line.indexOf('id:') == 0) { - - this.lastEventId = line.replace(/id:?\s*/, ''); - } - else if (line.indexOf('id') == 0) { // this resets the id - - this.lastEventId = null; - } - } - - if (datas.length) { - // dispatch a new event - var event = new MessageEvent(eventType, datas.join('\n'), window.location.origin, this.lastEventId); - this.dispatchEvent(eventType, event); - } - } - - this.cache = events[events.length - 1]; - }, - - dispatchEvent: function (type, event) { - var handlers = this['_' + type + 'Handlers']; - - if (handlers) { - - for (var i = 0; i < handlers.length; i++) { - handlers[i].call(this, event); - } - } - - if (this['on' + type]) { - this['on' + type].call(this, event); - } - - }, - - addEventListener: function (type, handler) { - if (!this['_' + type + 'Handlers']) { - this['_' + type + 'Handlers'] = []; - } - - this['_' + type + 'Handlers'].push(handler); - }, - - removeEventListener: function (type, handler) { - var handlers = this['_' + type + 'Handlers']; - if (!handlers) { - return; - } - for (var i = handlers.length - 1; i >= 0; --i) { - if (handlers[i] === handler) { - handlers.splice(i, 1); - break; - } - } - }, - - _pollTimer: null, - - _noactivityTimer: null, - - _xhr: null, - - lastEventId: null, - - cache: '', - - cursor: 0, - - onerror: null, - - onmessage: null, - - onopen: null, - - readyState: 0, - - // =================================================================== - // helpers functions - // those are attached to prototype to ease reuse and testing... - - urlWithParams: function (baseURL, params) { - - var encodedArgs = []; - - if (params){ - - var key, urlarg; - var urlize = encodeURIComponent; - - for (key in params){ - if (params.hasOwnProperty(key)) { - urlarg = urlize(key)+'='+urlize(params[key]); - encodedArgs.push(urlarg); - } - } - } - - if (encodedArgs.length > 0){ - - if (baseURL.indexOf('?') == -1) - return baseURL + '?' + encodedArgs.join('&'); - return baseURL + '&' + encodedArgs.join('&'); - } - return baseURL; - }, - - lastMessageIndex: function(text) { - - var ln2 =text.lastIndexOf('\n\n'); - var lr2 = text.lastIndexOf('\r\r'); - var lrln2 = text.lastIndexOf('\r\n\r\n'); - - if (lrln2 > Math.max(ln2, lr2)) { - return [lrln2, lrln2+4]; - } - return [Math.max(ln2, lr2), Math.max(ln2, lr2) + 2] - }, - - trimWhiteSpace: function(str) { - // to remove whitespaces left and right of string - - var reTrim = /^(\s|\u00A0)+|(\s|\u00A0)+$/g; - return str.replace(reTrim, ''); - }, - - normalizeToLF: function(str) { - - // replace \r and \r\n with \n - return str.replace(/\r\n|\r/g, '\n'); - } - - }; - - if (!isOldIE()){ - - EventSource.isPolyfill = "XHR"; - - // EventSource will send request using XMLHttpRequest - EventSource.prototype.XHR = function(evs) { - - request = new XMLHttpRequest(); - this._request = request; - evs._xhr = this; - - // set handlers - request.onreadystatechange = function(){ - if (request.readyState > 1 && evs.readyState != evs.CLOSED) { - if (request.status == 200 || (request.status>=300 && request.status<400)){ - evs._onxhrdata(); - } - else { - request._failed = true; - evs.readyState = evs.CLOSED; - evs.dispatchEvent('error', { - type: 'error', - data: "The server responded with "+request.status - }); - evs.close(); - } - } - }; - - request.onprogress = function () { - }; - - request.open('GET', evs.urlWithParams(evs.URL, evs.getArgs), true); - - var headers = evs.xhrHeaders; // maybe null - for (var header in headers) { - if (headers.hasOwnProperty(header)){ - request.setRequestHeader(header, headers[header]); - } - } - if (evs.lastEventId) { - request.setRequestHeader('Last-Event-Id', evs.lastEventId); - } - - request.send(); - }; - - EventSource.prototype.XHR.prototype = { - - useXDomainRequest: false, - - _request: null, - - _failed: false, // true if we have had errors... - - isReady: function() { - - - return this._request.readyState >= 2; - }, - - isDone: function() { - - return (this._request.readyState == 4); - }, - - hasError: function() { - - return (this._failed || (this._request.status >= 400)); - }, - - getBuffer: function() { - - var rv = ''; - try { - rv = this._request.responseText || ''; - } - catch (e){} - return rv; - }, - - abort: function() { - - if ( this._request ) { - this._request.abort(); - } - } - }; - } - else { - - EventSource.isPolyfill = "IE_8-9"; - - // patch EventSource defaultOptions - var defaults = EventSource.prototype.defaultOptions; - defaults.xhrHeaders = null; // no headers will be sent - defaults.getArgs['evs_preamble'] = 2048 + 8; - - // EventSource will send request using Internet Explorer XDomainRequest - EventSource.prototype.XHR = function(evs) { - - request = new XDomainRequest(); - this._request = request; - - // set handlers - request.onprogress = function(){ - request._ready = true; - evs._onxhrdata(); - }; - - request.onload = function(){ - this._loaded = true; - evs._onxhrdata(); - }; - - request.onerror = function(){ - this._failed = true; - evs.readyState = evs.CLOSED; - evs.dispatchEvent('error', { - type: 'error', - data: "XDomainRequest error" - }); - }; - - request.ontimeout = function(){ - this._failed = true; - evs.readyState = evs.CLOSED; - evs.dispatchEvent('error', { - type: 'error', - data: "XDomainRequest timed out" - }); - }; - - // XDomainRequest does not allow setting custom headers - // If EventSource has enabled the use of GET arguments - // we add parameters to URL so that server can adapt the stream... - var reqGetArgs = {}; - if (evs.getArgs) { - - // copy evs.getArgs in reqGetArgs - var defaultArgs = evs.getArgs; - for (var key in defaultArgs) { - if (defaultArgs.hasOwnProperty(key)){ - reqGetArgs[key] = defaultArgs[key]; - } - } - if (evs.lastEventId){ - reqGetArgs['evs_last_event_id'] = evs.lastEventId; - } - } - // send the request - - request.open('GET', evs.urlWithParams(evs.URL,reqGetArgs)); - request.send(); - }; - - EventSource.prototype.XHR.prototype = { - - useXDomainRequest: true, - - _request: null, - - _ready: false, // true when progress events are dispatched - - _loaded: false, // true when request has been loaded - - _failed: false, // true if when request is in error - - isReady: function() { - - return this._request._ready; - }, - - isDone: function() { - - return this._request._loaded; - }, - - hasError: function() { - - return this._request._failed; - }, - - getBuffer: function() { - - var rv = ''; - try { - rv = this._request.responseText || ''; - } - catch (e){} - return rv; - }, - - abort: function() { - - if ( this._request){ - this._request.abort(); - } - } - }; - } - - function MessageEvent(type, data, origin, lastEventId) { - - this.bubbles = false; - this.cancelBubble = false; - this.cancelable = false; - this.data = data || null; - this.origin = origin || ''; - this.lastEventId = lastEventId || ''; - this.type = type || 'message'; - } - - function isOldIE () { - - //return true if we are in IE8 or IE9 - return (window.XDomainRequest && (window.XMLHttpRequest && new XMLHttpRequest().responseType === undefined)) ? true : false; - } - - global[evsImportName] = EventSource; -})(this); diff --git a/js/vendor/eventsource-polyfill/dist/eventsource.min.js b/js/vendor/eventsource-polyfill/dist/eventsource.min.js deleted file mode 100644 index 3e79de6372..0000000000 --- a/js/vendor/eventsource-polyfill/dist/eventsource.min.js +++ /dev/null @@ -1 +0,0 @@ -!function(a){function b(a,b,c,d){this.bubbles=!1,this.cancelBubble=!1,this.cancelable=!1,this.data=b||null,this.origin=c||"",this.lastEventId=d||"",this.type=a||"message"}function c(){return window.XDomainRequest&&window.XMLHttpRequest&&void 0===(new XMLHttpRequest).responseType?!0:!1}if(!a.EventSource||a._eventSourceImportPrefix){var d=(a._eventSourceImportPrefix||"")+"EventSource",e=function(a,b){if(!a||"string"!=typeof a)throw new SyntaxError("Not enough arguments");this.URL=a,this.setOptions(b);var c=this;setTimeout(function(){c.poll()},0)};if(e.prototype={CONNECTING:0,OPEN:1,CLOSED:2,defaultOptions:{loggingEnabled:!1,loggingPrefix:"eventsource",interval:500,bufferSizeLimit:262144,silentTimeout:3e5,getArgs:{evs_buffer_size_limit:262144},xhrHeaders:{Accept:"text/event-stream","Cache-Control":"no-cache","X-Requested-With":"XMLHttpRequest"}},setOptions:function(a){var b,c=this.defaultOptions;for(b in c)c.hasOwnProperty(b)&&(this[b]=c[b]);for(b in a)b in c&&a.hasOwnProperty(b)&&(this[b]=a[b]);this.getArgs&&this.bufferSizeLimit&&(this.getArgs.evs_buffer_size_limit=this.bufferSizeLimit),("undefined"==typeof console||"undefined"==typeof console.log)&&(this.loggingEnabled=!1)},log:function(a){this.loggingEnabled&&console.log("["+this.loggingPrefix+"]:"+a)},poll:function(){try{if(this.readyState==this.CLOSED)return;this.cleanup(),this.readyState=this.CONNECTING,this.cursor=0,this.cache="",this._xhr=new this.XHR(this),this.resetNoActivityTimer()}catch(a){this.log("There were errors inside the pool try-catch"),this.dispatchEvent("error",{type:"error",data:a.message})}},pollAgain:function(a){var b=this;b.readyState=b.CONNECTING,b.dispatchEvent("error",{type:"error",data:"Reconnecting "}),this._pollTimer=setTimeout(function(){b.poll()},a||0)},cleanup:function(){this.log("evs cleaning up"),this._pollTimer&&(clearInterval(this._pollTimer),this._pollTimer=null),this._noActivityTimer&&(clearInterval(this._noActivityTimer),this._noActivityTimer=null),this._xhr&&(this._xhr.abort(),this._xhr=null)},resetNoActivityTimer:function(){if(this.silentTimeout){this._noActivityTimer&&clearInterval(this._noActivityTimer);var a=this;this._noActivityTimer=setTimeout(function(){a.log("Timeout! silentTImeout:"+a.silentTimeout),a.pollAgain()},this.silentTimeout)}},close:function(){this.readyState=this.CLOSED,this.log("Closing connection. readyState: "+this.readyState),this.cleanup()},_onxhrdata:function(){var a=this._xhr;if(a.isReady()&&!a.hasError()){this.resetNoActivityTimer(),this.readyState==this.CONNECTING&&(this.readyState=this.OPEN,this.dispatchEvent("open",{type:"open"}));var b=a.getBuffer();b.length>this.bufferSizeLimit&&(this.log("buffer.length > this.bufferSizeLimit"),this.pollAgain()),0==this.cursor&&b.length>0&&""==b.substring(0,1)&&(this.cursor=1);var c=this.lastMessageIndex(b);if(c[0]>=this.cursor){var d=c[1],e=b.substring(this.cursor,d);this.parseStream(e),this.cursor=d}a.isDone()&&(this.log("request.isDone(). reopening the connection"),this.pollAgain(this.interval))}else this.readyState!==this.CLOSED&&(this.log("this.readyState !== this.CLOSED"),this.pollAgain(this.interval))},parseStream:function(a){a=this.cache+this.normalizeToLF(a);var c,d,e,f,g,h,i=a.split("\n\n");for(c=0;c=0;--d)if(c[d]===b){c.splice(d,1);break}},_pollTimer:null,_noactivityTimer:null,_xhr:null,lastEventId:null,cache:"",cursor:0,onerror:null,onmessage:null,onopen:null,readyState:0,urlWithParams:function(a,b){var c=[];if(b){var d,e,f=encodeURIComponent;for(d in b)b.hasOwnProperty(d)&&(e=f(d)+"="+f(b[d]),c.push(e))}return c.length>0?-1==a.indexOf("?")?a+"?"+c.join("&"):a+"&"+c.join("&"):a},lastMessageIndex:function(a){var b=a.lastIndexOf("\n\n"),c=a.lastIndexOf("\r\r"),d=a.lastIndexOf("\r\n\r\n");return d>Math.max(b,c)?[d,d+4]:[Math.max(b,c),Math.max(b,c)+2]},trimWhiteSpace:function(a){var b=/^(\s|\u00A0)+|(\s|\u00A0)+$/g;return a.replace(b,"")},normalizeToLF:function(a){return a.replace(/\r\n|\r/g,"\n")}},c()){e.isPolyfill="IE_8-9";var f=e.prototype.defaultOptions;f.xhrHeaders=null,f.getArgs.evs_preamble=2056,e.prototype.XHR=function(a){request=new XDomainRequest,this._request=request,request.onprogress=function(){request._ready=!0,a._onxhrdata()},request.onload=function(){this._loaded=!0,a._onxhrdata()},request.onerror=function(){this._failed=!0,a.readyState=a.CLOSED,a.dispatchEvent("error",{type:"error",data:"XDomainRequest error"})},request.ontimeout=function(){this._failed=!0,a.readyState=a.CLOSED,a.dispatchEvent("error",{type:"error",data:"XDomainRequest timed out"})};var b={};if(a.getArgs){var c=a.getArgs;for(var d in c)c.hasOwnProperty(d)&&(b[d]=c[d]);a.lastEventId&&(b.evs_last_event_id=a.lastEventId)}request.open("GET",a.urlWithParams(a.URL,b)),request.send()},e.prototype.XHR.prototype={useXDomainRequest:!0,_request:null,_ready:!1,_loaded:!1,_failed:!1,isReady:function(){return this._request._ready},isDone:function(){return this._request._loaded},hasError:function(){return this._request._failed},getBuffer:function(){var a="";try{a=this._request.responseText||""}catch(b){}return a},abort:function(){this._request&&this._request.abort()}}}else e.isPolyfill="XHR",e.prototype.XHR=function(a){request=new XMLHttpRequest,this._request=request,a._xhr=this,request.onreadystatechange=function(){request.readyState>1&&a.readyState!=a.CLOSED&&(200==request.status||request.status>=300&&request.status<400?a._onxhrdata():(request._failed=!0,a.readyState=a.CLOSED,a.dispatchEvent("error",{type:"error",data:"The server responded with "+request.status}),a.close()))},request.onprogress=function(){},request.open("GET",a.urlWithParams(a.URL,a.getArgs),!0);var b=a.xhrHeaders;for(var c in b)b.hasOwnProperty(c)&&request.setRequestHeader(c,b[c]);a.lastEventId&&request.setRequestHeader("Last-Event-Id",a.lastEventId),request.send()},e.prototype.XHR.prototype={useXDomainRequest:!1,_request:null,_failed:!1,isReady:function(){return this._request.readyState>=2},isDone:function(){return 4==this._request.readyState},hasError:function(){return this._failed||this._request.status>=400},getBuffer:function(){var a="";try{a=this._request.responseText||""}catch(b){}return a},abort:function(){this._request&&this._request.abort()}};a[d]=e}}(this); \ No newline at end of file diff --git a/js/vendor/github-markdown-css/.bower.json b/js/vendor/github-markdown-css/.bower.json deleted file mode 100644 index bff2cb8829..0000000000 --- a/js/vendor/github-markdown-css/.bower.json +++ /dev/null @@ -1,30 +0,0 @@ -{ - "name": "github-markdown-css", - "description": "The minimal amount of CSS to replicate the GitHub Markdown style", - "license": "MIT", - "main": "github-markdown.css", - "keywords": [ - "github", - "markdown", - "md", - "css", - "style", - "stylesheet" - ], - "ignore": [ - "**/.*", - "package.json", - "index.html" - ], - "homepage": "https://github.com/sindresorhus/github-markdown-css", - "version": "2.0.9", - "_release": "2.0.9", - "_resolution": { - "type": "version", - "tag": "2.0.9", - "commit": "0d3c28edca0b172140af74c191f7a0c15703c10a" - }, - "_source": "git://github.com/sindresorhus/github-markdown-css.git", - "_target": "~2.*", - "_originalSource": "github-markdown-css" -} \ No newline at end of file diff --git a/js/vendor/github-markdown-css/bower.json b/js/vendor/github-markdown-css/bower.json deleted file mode 100644 index 6b16432272..0000000000 --- a/js/vendor/github-markdown-css/bower.json +++ /dev/null @@ -1,19 +0,0 @@ -{ - "name": "github-markdown-css", - "description": "The minimal amount of CSS to replicate the GitHub Markdown style", - "license": "MIT", - "main": "github-markdown.css", - "keywords": [ - "github", - "markdown", - "md", - "css", - "style", - "stylesheet" - ], - "ignore": [ - "**/.*", - "package.json", - "index.html" - ] -} diff --git a/js/vendor/github-markdown-css/github-markdown.css b/js/vendor/github-markdown-css/github-markdown.css deleted file mode 100644 index 5d9445ce18..0000000000 --- a/js/vendor/github-markdown-css/github-markdown.css +++ /dev/null @@ -1,649 +0,0 @@ -@font-face { - font-family: octicons-anchor; - src: url(data:font/woff;charset=utf-8;base64,d09GRgABAAAAAAYcAA0AAAAACjQAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAABGRlRNAAABMAAAABwAAAAca8vGTk9TLzIAAAFMAAAARAAAAFZG1VHVY21hcAAAAZAAAAA+AAABQgAP9AdjdnQgAAAB0AAAAAQAAAAEACICiGdhc3AAAAHUAAAACAAAAAj//wADZ2x5ZgAAAdwAAADRAAABEKyikaNoZWFkAAACsAAAAC0AAAA2AtXoA2hoZWEAAALgAAAAHAAAACQHngNFaG10eAAAAvwAAAAQAAAAEAwAACJsb2NhAAADDAAAAAoAAAAKALIAVG1heHAAAAMYAAAAHwAAACABEAB2bmFtZQAAAzgAAALBAAAFu3I9x/Nwb3N0AAAF/AAAAB0AAAAvaoFvbwAAAAEAAAAAzBdyYwAAAADP2IQvAAAAAM/bz7t4nGNgZGFgnMDAysDB1Ml0hoGBoR9CM75mMGLkYGBgYmBlZsAKAtJcUxgcPsR8iGF2+O/AEMPsznAYKMwIkgMA5REMOXicY2BgYGaAYBkGRgYQsAHyGMF8FgYFIM0ChED+h5j//yEk/3KoSgZGNgYYk4GRCUgwMaACRoZhDwCs7QgGAAAAIgKIAAAAAf//AAJ4nHWMMQrCQBBF/0zWrCCIKUQsTDCL2EXMohYGSSmorScInsRGL2DOYJe0Ntp7BK+gJ1BxF1stZvjz/v8DRghQzEc4kIgKwiAppcA9LtzKLSkdNhKFY3HF4lK69ExKslx7Xa+vPRVS43G98vG1DnkDMIBUgFN0MDXflU8tbaZOUkXUH0+U27RoRpOIyCKjbMCVejwypzJJG4jIwb43rfl6wbwanocrJm9XFYfskuVC5K/TPyczNU7b84CXcbxks1Un6H6tLH9vf2LRnn8Ax7A5WQAAAHicY2BkYGAA4teL1+yI57f5ysDNwgAC529f0kOmWRiYVgEpDgYmEA8AUzEKsQAAAHicY2BkYGB2+O/AEMPCAAJAkpEBFbAAADgKAe0EAAAiAAAAAAQAAAAEAAAAAAAAKgAqACoAiAAAeJxjYGRgYGBhsGFgYgABEMkFhAwM/xn0QAIAD6YBhwB4nI1Ty07cMBS9QwKlQapQW3VXySvEqDCZGbGaHULiIQ1FKgjWMxknMfLEke2A+IJu+wntrt/QbVf9gG75jK577Lg8K1qQPCfnnnt8fX1NRC/pmjrk/zprC+8D7tBy9DHgBXoWfQ44Av8t4Bj4Z8CLtBL9CniJluPXASf0Lm4CXqFX8Q84dOLnMB17N4c7tBo1AS/Qi+hTwBH4rwHHwN8DXqQ30XXAS7QaLwSc0Gn8NuAVWou/gFmnjLrEaEh9GmDdDGgL3B4JsrRPDU2hTOiMSuJUIdKQQayiAth69r6akSSFqIJuA19TrzCIaY8sIoxyrNIrL//pw7A2iMygkX5vDj+G+kuoLdX4GlGK/8Lnlz6/h9MpmoO9rafrz7ILXEHHaAx95s9lsI7AHNMBWEZHULnfAXwG9/ZqdzLI08iuwRloXE8kfhXYAvE23+23DU3t626rbs8/8adv+9DWknsHp3E17oCf+Z48rvEQNZ78paYM38qfk3v/u3l3u3GXN2Dmvmvpf1Srwk3pB/VSsp512bA/GG5i2WJ7wu430yQ5K3nFGiOqgtmSB5pJVSizwaacmUZzZhXLlZTq8qGGFY2YcSkqbth6aW1tRmlaCFs2016m5qn36SbJrqosG4uMV4aP2PHBmB3tjtmgN2izkGQyLWprekbIntJFing32a5rKWCN/SdSoga45EJykyQ7asZvHQ8PTm6cslIpwyeyjbVltNikc2HTR7YKh9LBl9DADC0U/jLcBZDKrMhUBfQBvXRzLtFtjU9eNHKin0x5InTqb8lNpfKv1s1xHzTXRqgKzek/mb7nB8RZTCDhGEX3kK/8Q75AmUM/eLkfA+0Hi908Kx4eNsMgudg5GLdRD7a84npi+YxNr5i5KIbW5izXas7cHXIMAau1OueZhfj+cOcP3P8MNIWLyYOBuxL6DRylJ4cAAAB4nGNgYoAALjDJyIAOWMCiTIxMLDmZedkABtIBygAAAA==) format('woff'); -} - -.markdown-body { - -webkit-text-size-adjust: 100%; - -ms-text-size-adjust: 100%; - text-size-adjust: 100%; - color: #333; - overflow: hidden; - font-family: "Helvetica Neue", Helvetica, "Segoe UI", Arial, freesans, sans-serif; - font-size: 16px; - line-height: 1.6; - word-wrap: break-word; -} - -.markdown-body a { - background-color: transparent; -} - -.markdown-body a:active, -.markdown-body a:hover { - outline: 0; -} - -.markdown-body strong { - font-weight: bold; -} - -.markdown-body h1 { - font-size: 2em; - margin: 0.67em 0; -} - -.markdown-body img { - border: 0; -} - -.markdown-body hr { - box-sizing: content-box; - height: 0; -} - -.markdown-body pre { - overflow: auto; -} - -.markdown-body code, -.markdown-body kbd, -.markdown-body pre { - font-family: monospace, monospace; - font-size: 1em; -} - -.markdown-body input { - color: inherit; - font: inherit; - margin: 0; -} - -.markdown-body html input[disabled] { - cursor: default; -} - -.markdown-body input { - line-height: normal; -} - -.markdown-body input[type="checkbox"] { - box-sizing: border-box; - padding: 0; -} - -.markdown-body table { - border-collapse: collapse; - border-spacing: 0; -} - -.markdown-body td, -.markdown-body th { - padding: 0; -} - -.markdown-body * { - box-sizing: border-box; -} - -.markdown-body input { - font: 13px/1.4 Helvetica, arial, nimbussansl, liberationsans, freesans, clean, sans-serif, "Segoe UI Emoji", "Segoe UI Symbol"; -} - -.markdown-body a { - color: #4078c0; - text-decoration: none; -} - -.markdown-body a:hover, -.markdown-body a:active { - text-decoration: underline; -} - -.markdown-body hr { - height: 0; - margin: 15px 0; - overflow: hidden; - background: transparent; - border: 0; - border-bottom: 1px solid #ddd; -} - -.markdown-body hr:before { - display: table; - content: ""; -} - -.markdown-body hr:after { - display: table; - clear: both; - content: ""; -} - -.markdown-body h1, -.markdown-body h2, -.markdown-body h3, -.markdown-body h4, -.markdown-body h5, -.markdown-body h6 { - margin-top: 15px; - margin-bottom: 15px; - line-height: 1.1; -} - -.markdown-body h1 { - font-size: 30px; -} - -.markdown-body h2 { - font-size: 21px; -} - -.markdown-body h3 { - font-size: 16px; -} - -.markdown-body h4 { - font-size: 14px; -} - -.markdown-body h5 { - font-size: 12px; -} - -.markdown-body h6 { - font-size: 11px; -} - -.markdown-body blockquote { - margin: 0; -} - -.markdown-body ul, -.markdown-body ol { - padding: 0; - margin-top: 0; - margin-bottom: 0; -} - -.markdown-body ol ol, -.markdown-body ul ol { - list-style-type: lower-roman; -} - -.markdown-body ul ul ol, -.markdown-body ul ol ol, -.markdown-body ol ul ol, -.markdown-body ol ol ol { - list-style-type: lower-alpha; -} - -.markdown-body dd { - margin-left: 0; -} - -.markdown-body code { - font-family: Consolas, "Liberation Mono", Menlo, Courier, monospace; - font-size: 12px; -} - -.markdown-body pre { - margin-top: 0; - margin-bottom: 0; - font: 12px Consolas, "Liberation Mono", Menlo, Courier, monospace; -} - -.markdown-body .octicon { - font: normal normal normal 16px/1 octicons-anchor; - display: inline-block; - text-decoration: none; - text-rendering: auto; - -webkit-font-smoothing: antialiased; - -moz-osx-font-smoothing: grayscale; - -webkit-user-select: none; - -moz-user-select: none; - -ms-user-select: none; - user-select: none; -} - -.markdown-body .octicon-link:before { - content: '\f05c'; -} - -.markdown-body>*:first-child { - margin-top: 0 !important; -} - -.markdown-body>*:last-child { - margin-bottom: 0 !important; -} - -.markdown-body a:not([href]) { - color: inherit; - text-decoration: none; -} - -.markdown-body .anchor { - position: absolute; - top: 0; - left: 0; - display: block; - padding-right: 6px; - padding-left: 30px; - margin-left: -30px; -} - -.markdown-body .anchor:focus { - outline: none; -} - -.markdown-body h1, -.markdown-body h2, -.markdown-body h3, -.markdown-body h4, -.markdown-body h5, -.markdown-body h6 { - position: relative; - margin-top: 1em; - margin-bottom: 16px; - font-weight: bold; - line-height: 1.4; -} - -.markdown-body h1 .octicon-link, -.markdown-body h2 .octicon-link, -.markdown-body h3 .octicon-link, -.markdown-body h4 .octicon-link, -.markdown-body h5 .octicon-link, -.markdown-body h6 .octicon-link { - display: none; - color: #000; - vertical-align: middle; -} - -.markdown-body h1:hover .anchor, -.markdown-body h2:hover .anchor, -.markdown-body h3:hover .anchor, -.markdown-body h4:hover .anchor, -.markdown-body h5:hover .anchor, -.markdown-body h6:hover .anchor { - padding-left: 8px; - margin-left: -30px; - text-decoration: none; -} - -.markdown-body h1:hover .anchor .octicon-link, -.markdown-body h2:hover .anchor .octicon-link, -.markdown-body h3:hover .anchor .octicon-link, -.markdown-body h4:hover .anchor .octicon-link, -.markdown-body h5:hover .anchor .octicon-link, -.markdown-body h6:hover .anchor .octicon-link { - display: inline-block; -} - -.markdown-body h1 { - padding-bottom: 0.3em; - font-size: 2.25em; - line-height: 1.2; - border-bottom: 1px solid #eee; -} - -.markdown-body h1 .anchor { - line-height: 1; -} - -.markdown-body h2 { - padding-bottom: 0.3em; - font-size: 1.75em; - line-height: 1.225; - border-bottom: 1px solid #eee; -} - -.markdown-body h2 .anchor { - line-height: 1; -} - -.markdown-body h3 { - font-size: 1.5em; - line-height: 1.43; -} - -.markdown-body h3 .anchor { - line-height: 1.2; -} - -.markdown-body h4 { - font-size: 1.25em; -} - -.markdown-body h4 .anchor { - line-height: 1.2; -} - -.markdown-body h5 { - font-size: 1em; -} - -.markdown-body h5 .anchor { - line-height: 1.1; -} - -.markdown-body h6 { - font-size: 1em; - color: #777; -} - -.markdown-body h6 .anchor { - line-height: 1.1; -} - -.markdown-body p, -.markdown-body blockquote, -.markdown-body ul, -.markdown-body ol, -.markdown-body dl, -.markdown-body table, -.markdown-body pre { - margin-top: 0; - margin-bottom: 16px; -} - -.markdown-body hr { - height: 4px; - padding: 0; - margin: 16px 0; - background-color: #e7e7e7; - border: 0 none; -} - -.markdown-body ul, -.markdown-body ol { - padding-left: 2em; -} - -.markdown-body ul ul, -.markdown-body ul ol, -.markdown-body ol ol, -.markdown-body ol ul { - margin-top: 0; - margin-bottom: 0; -} - -.markdown-body li>p { - margin-top: 16px; -} - -.markdown-body dl { - padding: 0; -} - -.markdown-body dl dt { - padding: 0; - margin-top: 16px; - font-size: 1em; - font-style: italic; - font-weight: bold; -} - -.markdown-body dl dd { - padding: 0 16px; - margin-bottom: 16px; -} - -.markdown-body blockquote { - padding: 0 15px; - color: #777; - border-left: 4px solid #ddd; -} - -.markdown-body blockquote>:first-child { - margin-top: 0; -} - -.markdown-body blockquote>:last-child { - margin-bottom: 0; -} - -.markdown-body table { - display: block; - width: 100%; - overflow: auto; - word-break: normal; - word-break: keep-all; -} - -.markdown-body table th { - font-weight: bold; -} - -.markdown-body table th, -.markdown-body table td { - padding: 6px 13px; - border: 1px solid #ddd; -} - -.markdown-body table tr { - background-color: #fff; - border-top: 1px solid #ccc; -} - -.markdown-body table tr:nth-child(2n) { - background-color: #f8f8f8; -} - -.markdown-body img { - max-width: 100%; - box-sizing: border-box; -} - -.markdown-body code { - padding: 0; - padding-top: 0.2em; - padding-bottom: 0.2em; - margin: 0; - font-size: 85%; - background-color: rgba(0,0,0,0.04); - border-radius: 3px; -} - -.markdown-body code:before, -.markdown-body code:after { - letter-spacing: -0.2em; - content: "\00a0"; -} - -.markdown-body pre>code { - padding: 0; - margin: 0; - font-size: 100%; - word-break: normal; - white-space: pre; - background: transparent; - border: 0; -} - -.markdown-body .highlight { - margin-bottom: 16px; -} - -.markdown-body .highlight pre, -.markdown-body pre { - padding: 16px; - overflow: auto; - font-size: 85%; - line-height: 1.45; - background-color: #f7f7f7; - border-radius: 3px; -} - -.markdown-body .highlight pre { - margin-bottom: 0; - word-break: normal; -} - -.markdown-body pre { - word-wrap: normal; -} - -.markdown-body pre code { - display: inline; - max-width: initial; - padding: 0; - margin: 0; - overflow: initial; - line-height: inherit; - word-wrap: normal; - background-color: transparent; - border: 0; -} - -.markdown-body pre code:before, -.markdown-body pre code:after { - content: normal; -} - -.markdown-body kbd { - display: inline-block; - padding: 3px 5px; - font-size: 11px; - line-height: 10px; - color: #555; - vertical-align: middle; - background-color: #fcfcfc; - border: solid 1px #ccc; - border-bottom-color: #bbb; - border-radius: 3px; - box-shadow: inset 0 -1px 0 #bbb; -} - -.markdown-body .pl-c { - color: #969896; -} - -.markdown-body .pl-c1, -.markdown-body .pl-s .pl-v { - color: #0086b3; -} - -.markdown-body .pl-e, -.markdown-body .pl-en { - color: #795da3; -} - -.markdown-body .pl-s .pl-s1, -.markdown-body .pl-smi { - color: #333; -} - -.markdown-body .pl-ent { - color: #63a35c; -} - -.markdown-body .pl-k { - color: #a71d5d; -} - -.markdown-body .pl-pds, -.markdown-body .pl-s, -.markdown-body .pl-s .pl-pse .pl-s1, -.markdown-body .pl-sr, -.markdown-body .pl-sr .pl-cce, -.markdown-body .pl-sr .pl-sra, -.markdown-body .pl-sr .pl-sre { - color: #183691; -} - -.markdown-body .pl-v { - color: #ed6a43; -} - -.markdown-body .pl-id { - color: #b52a1d; -} - -.markdown-body .pl-ii { - background-color: #b52a1d; - color: #f8f8f8; -} - -.markdown-body .pl-sr .pl-cce { - color: #63a35c; - font-weight: bold; -} - -.markdown-body .pl-ml { - color: #693a17; -} - -.markdown-body .pl-mh, -.markdown-body .pl-mh .pl-en, -.markdown-body .pl-ms { - color: #1d3e81; - font-weight: bold; -} - -.markdown-body .pl-mq { - color: #008080; -} - -.markdown-body .pl-mi { - color: #333; - font-style: italic; -} - -.markdown-body .pl-mb { - color: #333; - font-weight: bold; -} - -.markdown-body .pl-md { - background-color: #ffecec; - color: #bd2c00; -} - -.markdown-body .pl-mi1 { - background-color: #eaffea; - color: #55a532; -} - -.markdown-body .pl-mdr { - color: #795da3; - font-weight: bold; -} - -.markdown-body .pl-mo { - color: #1d3e81; -} - -.markdown-body kbd { - display: inline-block; - padding: 3px 5px; - font: 11px Consolas, "Liberation Mono", Menlo, Courier, monospace; - line-height: 10px; - color: #555; - vertical-align: middle; - background-color: #fcfcfc; - border: solid 1px #ccc; - border-bottom-color: #bbb; - border-radius: 3px; - box-shadow: inset 0 -1px 0 #bbb; -} - -.markdown-body .task-list-item { - list-style-type: none; -} - -.markdown-body .task-list-item+.task-list-item { - margin-top: 3px; -} - -.markdown-body .task-list-item input { - margin: 0 0.35em 0.25em -1.6em; - vertical-align: middle; -} - -.markdown-body :checked+.radio-label { - z-index: 1; - position: relative; - border-color: #4078c0; -} diff --git a/js/vendor/github-markdown-css/license b/js/vendor/github-markdown-css/license deleted file mode 100644 index 654d0bfe94..0000000000 --- a/js/vendor/github-markdown-css/license +++ /dev/null @@ -1,21 +0,0 @@ -The MIT License (MIT) - -Copyright (c) Sindre Sorhus (sindresorhus.com) - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in -all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -THE SOFTWARE. diff --git a/js/vendor/github-markdown-css/readme.md b/js/vendor/github-markdown-css/readme.md deleted file mode 100644 index a58fe348e0..0000000000 --- a/js/vendor/github-markdown-css/readme.md +++ /dev/null @@ -1,56 +0,0 @@ -# github-markdown-css - -> The minimal amount of CSS to replicate the GitHub Markdown style - -[](http://sindresorhus.com/github-markdown-css) - -## [Demo](http://sindresorhus.com/github-markdown-css) - - -## Install - -Download [manually](https://raw.githubusercontent.com/sindresorhus/github-markdown-css/gh-pages/github-markdown.css) or with a package-manager. - -```sh -$ npm install --save github-markdown-css -``` - -```sh -$ bower install --save github-markdown-css -``` - - -## Usage - -Import the `github-markdown.css` file and add a `markdown-body` class to the container of your rendered Markdown and set a width for it. GitHub uses `790px` width and `30px` padding. - -```html - - -

-

Unicorns

-

All the things

-
-``` - - -## How - -See [`generate-github-markdown-css`](https://github.com/sindresorhus/generate-github-markdown-css) for how it's generated and ability to generate your own. - - -## Dev - -Run `npm run generate` to update the CSS. - - -## License - -MIT © [Sindre Sorhus](http://sindresorhus.com) diff --git a/js/vendor/image-scale/LICENSE b/js/vendor/image-scale/LICENSE deleted file mode 100644 index b3908ae8d7..0000000000 --- a/js/vendor/image-scale/LICENSE +++ /dev/null @@ -1,20 +0,0 @@ -The MIT License (MIT) - -Copyright (c) 2013 GestiXi - -Permission is hereby granted, free of charge, to any person obtaining a copy of -this software and associated documentation files (the "Software"), to deal in -the Software without restriction, including without limitation the rights to -use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of -the Software, and to permit persons to whom the Software is furnished to do so, -subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS -FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR -COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER -IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN -CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. \ No newline at end of file diff --git a/js/vendor/image-scale/README.md b/js/vendor/image-scale/README.md deleted file mode 100644 index 304ab6912e..0000000000 --- a/js/vendor/image-scale/README.md +++ /dev/null @@ -1,210 +0,0 @@ -Image Scale -=========== - -**Scale images to fit or fill any target container via two simple properties: scale and align.** - -*This plugin is greatly inspired from Sproutcore SC.ImageView.* - ------- - -## Installation - -image-scale depends on jQuery. To use it, include this in your page : - - - - ------- - -## Usage - -If you want to identify the images that you want to scale, you can add a class to them. In this example we are adding a class call `scale`. - -You can also set the `data-scale` and `data-align` attributes directly to the images if you want to override the default setting. - -
- -
- -Now add this JavaScript code to your page : - - $(function() { - $("img.scale").imageScale(); - }); - -You're done. - ------- - -## Properties - - -### scale - -Determines how the image will scale to fit within its containing space. Possible values: - -* **fill** - stretches or compresses the source image to fill the target frame -* **best-fill** - fits the shortest side of the source image within the target frame while maintaining the original aspect ratio -* **best-fit** - fits the longest edge of the source image within the target frame while maintaining the original aspect ratio -* **best-fit-down** - same as *best-fit* but will not stretch the source if it is smaller than the target -* **none** - the source image is left unscaled - - - - Type: String - Default: best-fill - - -### align - -Align the image within its frame. Possible values: - -* **left** -* **right** -* **center** -* **top** -* **bottom** -* **top-left** -* **top-right** -* **bottom-left** -* **bottom-right** - - - - Type: String - Default: center - - -### parent - -A jQuery Object against which the image size will be calculated. -If null, the parent of the image will be used. - - Type: jQuery Object - Default: null - - -### hideParentOverflow - -A boolean determining if the parent should hide its overflow. - - Type: Boolean - Default: true - - -### fadeInDuration - -A duration in milliseconds determining how long the fadeIn animation -will run when your image is scale for the firstTime. - -Set it to 0 if you don't want any animation. - - Type: Number or String - Default: 0 - - -### rescaleOnResize - -A boolean indicating if the image size should be rescaled when the window is resized. - -The window size is checked using requestAnimationFrame for good performance. - - Type: Boolean - Default: false - - -### didScale - -A function that will be call each time the receiver is scaled. - -Example: - - $images.imageScale({ - didScale: function(firstTime, options) { - console.log('did scale img: ', this.element); - } - }); - - - - Type: Function - Parameters: - - firstTime {Boolean} true if the image was scale for the first time. - - options {Object} the options passed to the scale method. - - -### debug - -A number indicating the debug level : - -0. silent -1. error -2. error & warning -3. error & warning & notice - - - - Type: Number - Default: 0 - ------- - -## Methods - - -### scale - -Main method. Used to scale the images. - -When `rescaleOnResize` is set to true, this method is executed each time the -windows size changes. - -If `rescaleOnResize` is set to false, you may want to call it manually. Here is an -example on how you should do it: - - $image.imageScale('scale'); - - -### destroy - -Removes the data for the element. - -Here is an example on how you can call the destroy method: - - $image.imageScale('destroy'); - - ------- - -## Demo - -See it in action on our [home page](https://www.gestixi.com). - - -You can also check out the Sproutcore [Automatic Image Scaling demo](http://showcase.sproutcore.com/#demos/Automatic%20Image%20Scaling) to understand the difference between all the different options. - - ------- - -## Size - -Original Size: 3.91KB gzipped (13.99KB uncompressed) - -Compiled Size: **1.8KB gzipped** (4.42KB uncompressed) - - ------- - -## Author - -**Nicolas Badia** - -+ [https://twitter.com/@nicolas_badia](https://twitter.com/@nicolas_badia) -+ [https://github.com/nicolasbadia](https://github.com/nicolasbadia) - - ------- - -## Copyright and license - -Copyright 2013-2015 GestiXi under [The MIT License (MIT)](LICENSE). \ No newline at end of file diff --git a/js/vendor/image-scale/image-scale.js b/js/vendor/image-scale/image-scale.js deleted file mode 100644 index 3934d35c9a..0000000000 --- a/js/vendor/image-scale/image-scale.js +++ /dev/null @@ -1,512 +0,0 @@ -// ========================================================================== -// Project: Image Scale -// Description: Scale images to fit or fill any target size via two simple properties: scale and align. -// Copyright: ©2012-2015 GestiXi -// License: Licensed under the MIT license (see LICENCE) -// Version: 2.1 -// Author: Nicolas BADIA -// ========================================================================== - -! function($) { - "use strict"; - - // .......................................................... - // IMAGE SCALE PLUGIN DEFINITION - // - - $.fn.imageScale = function(options) { - - return this.each(function() { - var that = this, - $this = $(this), - data = $this.data('imageScale'), - $img = this.tagName === 'IMG' ? $this : $this.find("img"); - - if (!data) { - var didLoad = $img[0].complete, - formattedOpt = $.extend({}, $.fn.imageScale.defaults, typeof options == 'object' && options), - - loadFunc = function() { - $this.data('imageScale', (data = new ImageScale(that, formattedOpt))); - - data.scale(true, formattedOpt); - }; - - if (didLoad) { - loadFunc.apply($this[0]); - } else { - $img.on("load", loadFunc).attr("src", $img.attr("src")); - } - } else { - if (typeof options == 'string') data[options](); - else if (typeof options == 'object') { - var method = options.method || 'scale'; - data[method](false, options); - } else data.scale(); - } - }) - } - - $.fn.imageScale.defaults = { - /** - Determines how the image will scale to fit within its containing space. Possible values: - - * **fill** - stretches or compresses the source image to fill the target frame - * **best-fill** - fits the shortest side of the source image within the target frame while maintaining the original aspect ratio - * **best-fit** - fits the longest edge of the source image within the target frame while maintaining the original aspect ratio - * **best-fit-down** - same as *best-fit* but will not stretch the source if it is smaller than the target - * **none** - the source image is left unscaled - - @type String - @default best-fill - @since Version 1.2 - */ - scale: 'best-fill', - - /** - Align the image within its frame. Possible values: - - * **left** - * **right** - * **center** - * **top** - * **bottom** - * **top-left** - * **top-right** - * **bottom-left** - * **bottom-right** - - @type String - @default center - @since Version 1.2 - */ - align: 'center', - - /** - A jQuery Object against which the image size will be calculated. - If null, the parent of the image will be used. - - @type jQuery Object - @default null - @since Version 1.0 - */ - parent: null, - - /** - A boolean determining if the parent should hide its overflow. - - @type Boolean - @default true - @since Version 1.0 - */ - hideParentOverflow: true, - - /** - A duration in milliseconds determining how long the fadeIn animation will run when your image is scale for the firstTime. - - Set it to 0 if you don't want any animation. - - @type Number|String - @default 0 - @since Version 1.1 - */ - fadeInDuration: 0, - - /** - A boolean indicating if the image size should be rescaled when the window is resized. - - The window size is checked using requestAnimationFrame for good performance. - - @type Boolean - @default false - @since Version 1.0 - */ - rescaleOnResize: false, - - /** - A function that will be call each time the receiver is scaled. - - Example: - - $images.imageScale({ - didScale: function() { - console.log('did scale img: ', this.element); - } - }); - - @type Function - @param firstTime {Boolean} true if the image was scale for the first time. - @param options {Object} the options passed to the scale method. - @since Version 2.0 - */ - didScale: function(firstTime, options) {}, - - /** - A number indicating the log level : - - 0: silent - 1: error - 2: error & warning - 3: error & warning & notice - - @type Number - @default 0 - @since Version 1.0 - */ - logLevel: 0 - } - - // .......................................................... - // IMAGE SCALE PUBLIC CLASS DEFINITION - // - - var ImageScale = function(element, options) { - var that = this; - that.options = options; - that.element = element; - - var $element = that.$element = $(element), - $img = that.$img = element.tagName === 'IMG' ? $element : $element.find("img"), - img = that.img = $img[0]; - - that.src = $img.attr('src'); - - that.imgWidth = img.naturalWidth || img.width; - that.imgHeight = img.naturalHeight || img.height; - - var $parent = that.$parent = options.parent ? options.parent : $($element.parent()[0]); - that.parent = $parent[0]; - - // Fixes: https://github.com/gestixi/image-scale/issues/1 - if ($parent.css('position') === 'static') { - $parent.css('position', 'relative'); - } - - if (options.rescaleOnResize) { - $(window).resize(function(e) { - that.scheduleScale(); - }); - } - } - - $.fn.imageScale.Constructor = ImageScale; - - ImageScale.prototype = { - - NONE: "none", - FILL: "fill", - BEST_FILL: "best-fill", - BEST_FIT: "best-fit", - BEST_FIT_DOWN_ONLY: "best-fit-down", - - ALIGN_LEFT: 'left', - ALIGN_RIGHT: 'right', - ALIGN_CENTER: 'center', - ALIGN_TOP: 'top', - ALIGN_BOTTOM: 'bottom', - ALIGN_TOP_LEFT: 'top-left', - ALIGN_TOP_RIGHT: 'top-right', - ALIGN_BOTTOM_LEFT: 'bottom-left', - ALIGN_BOTTOM_RIGHT: 'bottom-right', - - constructor: ImageScale, - - /** - The initial element. - - @type DOM Element - */ - element: null, - - /** - The passed options. - - @type Object - */ - options: null, - - /** - Main method. Used to scale the images. - - When `rescaleOnResize` is set to true, this method is executed each time the - windows size changes. - - If `rescaleOnResize` is set to false, you may want to call it manually. Here is an - example on how you should do it: - - $image.imageScale('scale'); - - - @param {Boolean} firstTime - */ - scale: function(firstTime, opt) { - if (this._isDestroyed || this._canScale === false) return; - - var that = this, - options = this.options, - $parent = this.$parent, - element = this.element, - $element = this.$element, - img = this.img, - $img = this.$img; - - if (firstTime) { - if (options.hideParentOverflow) { - $parent.css({ - overflow: 'hidden' - }); - } - } else { - // If the source of the image has changed - if (this.src !== $img.attr('src')) { - this.destroy(); - $element.data('imageScale', null); - $element.imageScale(options); - return; - } - } - - this._didScheduleScale = false; - - if (options.rescaleOnResize && !opt) { - if (!this._needUpdate(this.parent)) return; - } - opt = opt ? opt : {}; - - var transition = opt.transition; - if (transition) { - this._canScale = false; - $element.css('transition', 'all ' + transition + 'ms'); - - setTimeout(function() { - that._canScale = null; - $element.css('transition', 'null'); - }, transition); - } - - var destWidth = opt.destWidth ? opt.destWidth : $parent.outerWidth(), - destHeight = opt.destHeight ? opt.destHeight : $parent.outerHeight(), - - destInnerWidth = opt.destWidth ? opt.destWidth : $parent.innerWidth(), - destInnerHeight = opt.destHeight ? opt.destHeight : $parent.innerHeight(), - - widthOffset = destWidth - destInnerWidth, - heightOffset = destHeight - destInnerHeight, - - scaleData = $element.attr('data-scale'), - alignData = $element.attr('data-align'), - - scale = scaleData ? scaleData : options.scale, - align = alignData ? alignData : options.align, - - fadeInDuration = options.fadeInDuration; - - if (!scale) { - if (options.logLevel > 2) { - console.log("imageScale - DEBUG NOTICE: The scale property is null.", element); - } - return; - } - - if (this._cacheDestWidth === destWidth && this._cacheDestHeight === destHeight) { - if (options.logLevel > 2) { - console.log("imageScale - DEBUG NOTICE: The parent size hasn't changed: dest width: '" + destWidth + "' - dest height: '" + destHeight + "'.", element); - } - } - - var sourceWidth = this.imgWidth, - sourceHeight = this.imgHeight; - - if (!(destWidth && destHeight && sourceWidth && sourceHeight)) { - if (options.logLevel > 0) { - console.error("imageScale - DEBUG ERROR: The dimensions are incorrect: source width: '" + sourceWidth + "' - source height: '" + sourceHeight + "' - dest width: '" + destWidth + "' - dest height: '" + destHeight + "'.", element); - } - return; - } - - this._cacheDestWidth = destWidth; - this._cacheDestHeight = destHeight; - - var layout = this._innerFrameForSize(scale, align, sourceWidth, sourceHeight, destWidth, destHeight); - - if (widthOffset) layout.x -= widthOffset / 2; - if (heightOffset) layout.y -= heightOffset / 2; - - $element.css({ - position: 'absolute', - top: layout.y + 'px', - left: layout.x + 'px', - width: layout.width + 'px', - height: layout.height + 'px', - 'max-width': 'none' - }); - - if (firstTime && fadeInDuration) { - $element.css({ - display: 'none' - }); - $element.fadeIn(fadeInDuration); - } - - options.didScale.call(this, firstTime, opt); - }, - - /** - Removes the data for the element. - - Here is an example on how you can call the destroy method: - - $image.imageScale('destroy'); - - */ - destroy: function() { - this._isDestroyed = true; - this.$element.removeData('imageScale'); - }, - - /** - @private - - Returns a frame (x, y, width, height) fitting the source size (sourceWidth & sourceHeight) within the - destination size (destWidth & destHeight) according to the align and scale properties. - - @param {String} scale - @param {String} align - @param {Number} sourceWidth - @param {Number} sourceHeight - @param {Number} destWidth - @param {Number} destHeight - @returns {Object} the inner frame with properties: { x: value, y: value, width: value, height: value } - */ - _innerFrameForSize: function(scale, align, sourceWidth, sourceHeight, destWidth, destHeight) { - var scaleX, - scaleY, - result; - - // Fast path - result = { - x: 0, - y: 0, - width: destWidth, - height: destHeight - }; - if (scale === this.FILL) return result; - - // Determine the appropriate scale - scaleX = destWidth / sourceWidth; - scaleY = destHeight / sourceHeight; - - switch (scale) { - case this.BEST_FIT_DOWN_ONLY: - if (scale !== this.BEST_FIT_DOWN_ONLY && this.options.logLevel > 1) { - console.warn("imageScale - DEBUG WARNING: The scale '" + scale + "' was not understood."); - } - - if ((sourceWidth > destWidth) || (sourceHeight > destHeight)) { - scale = scaleX < scaleY ? scaleX : scaleY; - } else { - scale = 1.0; - } - break; - case this.BEST_FIT: - scale = scaleX < scaleY ? scaleX : scaleY; - break; - case this.NONE: - scale = 1.0; - break; - //case this.BEST_FILL: - default: - scale = scaleX > scaleY ? scaleX : scaleY; - break; - } - - sourceWidth *= scale; - sourceHeight *= scale; - result.width = Math.round(sourceWidth); - result.height = Math.round(sourceHeight); - - // Align the image within its frame - switch (align) { - case this.ALIGN_LEFT: - result.x = 0; - result.y = (destHeight / 2) - (sourceHeight / 2); - break; - case this.ALIGN_RIGHT: - result.x = destWidth - sourceWidth; - result.y = (destHeight / 2) - (sourceHeight / 2); - break; - case this.ALIGN_TOP: - result.x = (destWidth / 2) - (sourceWidth / 2); - result.y = 0; - break; - case this.ALIGN_BOTTOM: - result.x = (destWidth / 2) - (sourceWidth / 2); - result.y = destHeight - sourceHeight; - break; - case this.ALIGN_TOP_LEFT: - result.x = 0; - result.y = 0; - break; - case this.ALIGN_TOP_RIGHT: - result.x = destWidth - sourceWidth; - result.y = 0; - break; - case this.ALIGN_BOTTOM_LEFT: - result.x = 0; - result.y = destHeight - sourceHeight; - break; - case this.ALIGN_BOTTOM_RIGHT: - result.x = destWidth - sourceWidth; - result.y = destHeight - sourceHeight; - break; - default: // this.ALIGN_CENTER - if (align !== this.ALIGN_CENTER && this.options.logLevel > 1) { - console.warn("imageScale - DEBUG WARNING: The align '" + align + "' was not understood."); - } - result.x = (destWidth / 2) - (sourceWidth / 2); - result.y = (destHeight / 2) - (sourceHeight / 2); - } - - return result; - }, - - /** - @private - - Determines if the windows size has changed since the last update. - - @returns {Boolean} - */ - _needUpdate: function(parent) { - var size = parent.clientHeight + ' ' + parent.clientWidth; - - if (this._lastParentSize !== size) { - this._lastParentSize = size; - return true; - } - return false; - }, - - /** - @private - - Schedule a scale update. - */ - scheduleScale: function() { - if (this._didScheduleScale) return; - - if (window.requestAnimationFrame) { - var that = this; - this._didScheduleScale = true; - // setTimeout important when resizing down if the scrollbar were visible - requestAnimationFrame(function() { - setTimeout(function() { - that.scale(); - }, 0); - }); - } else { - this.scale(); - } - } - } -}(window.jQuery); \ No newline at end of file diff --git a/js/vendor/marked/.bower.json b/js/vendor/marked/.bower.json deleted file mode 100644 index dc9c1bb0e6..0000000000 --- a/js/vendor/marked/.bower.json +++ /dev/null @@ -1,33 +0,0 @@ -{ - "name": "marked", - "version": "0.3.3", - "homepage": "https://github.com/chjj/marked", - "authors": [ - "Christopher Jeffrey " - ], - "description": "A markdown parser built for speed", - "keywords": [ - "markdown", - "markup", - "html" - ], - "main": "lib/marked.js", - "license": "MIT", - "ignore": [ - "**/.*", - "node_modules", - "bower_components", - "app/bower_components", - "test", - "tests" - ], - "_release": "0.3.3", - "_resolution": { - "type": "version", - "tag": "v0.3.3", - "commit": "2b5802f258c5e23e48366f2377fbb4c807f47658" - }, - "_source": "git://github.com/chjj/marked.git", - "_target": "~0.*", - "_originalSource": "marked" -} \ No newline at end of file diff --git a/js/vendor/marked/LICENSE b/js/vendor/marked/LICENSE deleted file mode 100644 index a7b812ed61..0000000000 --- a/js/vendor/marked/LICENSE +++ /dev/null @@ -1,19 +0,0 @@ -Copyright (c) 2011-2014, Christopher Jeffrey (https://github.com/chjj/) - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in -all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -THE SOFTWARE. diff --git a/js/vendor/marked/Makefile b/js/vendor/marked/Makefile deleted file mode 100644 index d9349f0799..0000000000 --- a/js/vendor/marked/Makefile +++ /dev/null @@ -1,12 +0,0 @@ -all: - @cp lib/marked.js marked.js - @uglifyjs --comments '/\*[^\0]+?Copyright[^\0]+?\*/' -o marked.min.js lib/marked.js - -clean: - @rm marked.js - @rm marked.min.js - -bench: - @node test --bench - -.PHONY: clean all diff --git a/js/vendor/marked/README.md b/js/vendor/marked/README.md deleted file mode 100644 index b9817cd4f7..0000000000 --- a/js/vendor/marked/README.md +++ /dev/null @@ -1,406 +0,0 @@ -# marked - -> A full-featured markdown parser and compiler, written in JavaScript. Built -> for speed. - -[![NPM version](https://badge.fury.io/js/marked.png)][badge] - -## Install - -``` bash -npm install marked --save -``` - -## Usage - -Minimal usage: - -```js -var marked = require('marked'); -console.log(marked('I am using __markdown__.')); -// Outputs:

I am using markdown.

-``` - -Example setting options with default values: - -```js -var marked = require('marked'); -marked.setOptions({ - renderer: new marked.Renderer(), - gfm: true, - tables: true, - breaks: false, - pedantic: false, - sanitize: true, - smartLists: true, - smartypants: false -}); - -console.log(marked('I am using __markdown__.')); -``` - -### Browser - -```html - - - - - Marked in the browser - - - -
- - - -``` - -## marked(markdownString [,options] [,callback]) - -### markdownString - -Type: `string` - -String of markdown source to be compiled. - -### options - -Type: `object` - -Hash of options. Can also be set using the `marked.setOptions` method as seen -above. - -### callback - -Type: `function` - -Function called when the `markdownString` has been fully parsed when using -async highlighting. If the `options` argument is omitted, this can be used as -the second argument. - -## Options - -### highlight - -Type: `function` - -A function to highlight code blocks. The first example below uses async highlighting with -[node-pygmentize-bundled][pygmentize], and the second is a synchronous example using -[highlight.js][highlight]: - -```js -var marked = require('marked'); - -var markdownString = '```js\n console.log("hello"); \n```'; - -// Async highlighting with pygmentize-bundled -marked.setOptions({ - highlight: function (code, lang, callback) { - require('pygmentize-bundled')({ lang: lang, format: 'html' }, code, function (err, result) { - callback(err, result.toString()); - }); - } -}); - -// Using async version of marked -marked(markdownString, function (err, content) { - if (err) throw err; - console.log(content); -}); - -// Synchronous highlighting with highlight.js -marked.setOptions({ - highlight: function (code) { - return require('highlight.js').highlightAuto(code).value; - } -}); - -console.log(marked(markdownString)); -``` - -#### highlight arguments - -`code` - -Type: `string` - -The section of code to pass to the highlighter. - -`lang` - -Type: `string` - -The programming language specified in the code block. - -`callback` - -Type: `function` - -The callback function to call when using an async highlighter. - -### renderer - -Type: `object` -Default: `new Renderer()` - -An object containing functions to render tokens to HTML. - -#### Overriding renderer methods - -The renderer option allows you to render tokens in a custom manor. Here is an -example of overriding the default heading token rendering by adding an embedded anchor tag like on GitHub: - -```javascript -var marked = require('marked'); -var renderer = new marked.Renderer(); - -renderer.heading = function (text, level) { - var escapedText = text.toLowerCase().replace(/[^\w]+/g, '-'); - - return '' + - text + ''; -}, - -console.log(marked('# heading+', { renderer: renderer })); -``` -This code will output the following HTML: -```html -

- - - - heading+ -

-``` - -#### Block level renderer methods - -- code(*string* code, *string* language) -- blockquote(*string* quote) -- html(*string* html) -- heading(*string* text, *number* level) -- hr() -- list(*string* body, *boolean* ordered) -- listitem(*string* text) -- paragraph(*string* text) -- table(*string* header, *string* body) -- tablerow(*string* content) -- tablecell(*string* content, *object* flags) - -`flags` has the following properties: - -```js -{ - header: true || false, - align: 'center' || 'left' || 'right' -} -``` - -#### Inline level renderer methods - -- strong(*string* text) -- em(*string* text) -- codespan(*string* code) -- br() -- del(*string* text) -- link(*string* href, *string* title, *string* text) -- image(*string* href, *string* title, *string* text) - -### gfm - -Type: `boolean` -Default: `true` - -Enable [GitHub flavored markdown][gfm]. - -### tables - -Type: `boolean` -Default: `true` - -Enable GFM [tables][tables]. -This option requires the `gfm` option to be true. - -### breaks - -Type: `boolean` -Default: `false` - -Enable GFM [line breaks][breaks]. -This option requires the `gfm` option to be true. - -### pedantic - -Type: `boolean` -Default: `false` - -Conform to obscure parts of `markdown.pl` as much as possible. Don't fix any of -the original markdown bugs or poor behavior. - -### sanitize - -Type: `boolean` -Default: `false` - -Sanitize the output. Ignore any HTML that has been input. - -### smartLists - -Type: `boolean` -Default: `true` - -Use smarter list behavior than the original markdown. May eventually be -default with the old behavior moved into `pedantic`. - -### smartypants - -Type: `boolean` -Default: `false` - -Use "smart" typograhic punctuation for things like quotes and dashes. - -## Access to lexer and parser - -You also have direct access to the lexer and parser if you so desire. - -``` js -var tokens = marked.lexer(text, options); -console.log(marked.parser(tokens)); -``` - -``` js -var lexer = new marked.Lexer(options); -var tokens = lexer.lex(text); -console.log(tokens); -console.log(lexer.rules); -``` - -## CLI - -``` bash -$ marked -o hello.html -hello world -^D -$ cat hello.html -

hello world

-``` - -## Philosophy behind marked - -The point of marked was to create a markdown compiler where it was possible to -frequently parse huge chunks of markdown without having to worry about -caching the compiled output somehow...or blocking for an unnecesarily long time. - -marked is very concise and still implements all markdown features. It is also -now fully compatible with the client-side. - -marked more or less passes the official markdown test suite in its -entirety. This is important because a surprising number of markdown compilers -cannot pass more than a few tests. It was very difficult to get marked as -compliant as it is. It could have cut corners in several areas for the sake -of performance, but did not in order to be exactly what you expect in terms -of a markdown rendering. In fact, this is why marked could be considered at a -disadvantage in the benchmarks above. - -Along with implementing every markdown feature, marked also implements [GFM -features][gfmf]. - -## Benchmarks - -node v0.8.x - -``` bash -$ node test --bench -marked completed in 3411ms. -marked (gfm) completed in 3727ms. -marked (pedantic) completed in 3201ms. -robotskirt completed in 808ms. -showdown (reuse converter) completed in 11954ms. -showdown (new converter) completed in 17774ms. -markdown-js completed in 17191ms. -``` - -__Marked is now faster than Discount, which is written in C.__ - -For those feeling skeptical: These benchmarks run the entire markdown test suite 1000 times. The test suite tests every feature. It doesn't cater to specific aspects. - -### Pro level - -You also have direct access to the lexer and parser if you so desire. - -``` js -var tokens = marked.lexer(text, options); -console.log(marked.parser(tokens)); -``` - -``` js -var lexer = new marked.Lexer(options); -var tokens = lexer.lex(text); -console.log(tokens); -console.log(lexer.rules); -``` - -``` bash -$ node -> require('marked').lexer('> i am using marked.') -[ { type: 'blockquote_start' }, - { type: 'paragraph', - text: 'i am using marked.' }, - { type: 'blockquote_end' }, - links: {} ] -``` - -## Running Tests & Contributing - -If you want to submit a pull request, make sure your changes pass the test -suite. If you're adding a new feature, be sure to add your own test. - -The marked test suite is set up slightly strangely: `test/new` is for all tests -that are not part of the original markdown.pl test suite (this is where your -test should go if you make one). `test/original` is only for the original -markdown.pl tests. `test/tests` houses both types of tests after they have been -combined and moved/generated by running `node test --fix` or `marked --test ---fix`. - -In other words, if you have a test to add, add it to `test/new/` and then -regenerate the tests with `node test --fix`. Commit the result. If your test -uses a certain feature, for example, maybe it assumes GFM is *not* enabled, you -can add `.nogfm` to the filename. So, `my-test.text` becomes -`my-test.nogfm.text`. You can do this with any marked option. Say you want -line breaks and smartypants enabled, your filename should be: -`my-test.breaks.smartypants.text`. - -To run the tests: - -``` bash -cd marked/ -node test -``` - -### Contribution and License Agreement - -If you contribute code to this project, you are implicitly allowing your code -to be distributed under the MIT license. You are also implicitly verifying that -all code is your original work. `` - -## License - -Copyright (c) 2011-2014, Christopher Jeffrey. (MIT License) - -See LICENSE for more info. - -[gfm]: https://help.github.com/articles/github-flavored-markdown -[gfmf]: http://github.github.com/github-flavored-markdown/ -[pygmentize]: https://github.com/rvagg/node-pygmentize-bundled -[highlight]: https://github.com/isagalaev/highlight.js -[badge]: http://badge.fury.io/js/marked -[tables]: https://github.com/adam-p/markdown-here/wiki/Markdown-Cheatsheet#wiki-tables -[breaks]: https://help.github.com/articles/github-flavored-markdown#newlines diff --git a/js/vendor/marked/bin/marked b/js/vendor/marked/bin/marked deleted file mode 100644 index 64254fc3eb..0000000000 --- a/js/vendor/marked/bin/marked +++ /dev/null @@ -1,187 +0,0 @@ -#!/usr/bin/env node - -/** - * Marked CLI - * Copyright (c) 2011-2013, Christopher Jeffrey (MIT License) - */ - -var fs = require('fs') - , util = require('util') - , marked = require('../'); - -/** - * Man Page - */ - -function help() { - var spawn = require('child_process').spawn; - - var options = { - cwd: process.cwd(), - env: process.env, - setsid: false, - customFds: [0, 1, 2] - }; - - spawn('man', - [__dirname + '/../man/marked.1'], - options); -} - -/** - * Main - */ - -function main(argv, callback) { - var files = [] - , options = {} - , input - , output - , arg - , tokens - , opt; - - function getarg() { - var arg = argv.shift(); - - if (arg.indexOf('--') === 0) { - // e.g. --opt - arg = arg.split('='); - if (arg.length > 1) { - // e.g. --opt=val - argv.unshift(arg.slice(1).join('=')); - } - arg = arg[0]; - } else if (arg[0] === '-') { - if (arg.length > 2) { - // e.g. -abc - argv = arg.substring(1).split('').map(function(ch) { - return '-' + ch; - }).concat(argv); - arg = argv.shift(); - } else { - // e.g. -a - } - } else { - // e.g. foo - } - - return arg; - } - - while (argv.length) { - arg = getarg(); - switch (arg) { - case '--test': - return require('../test').main(process.argv.slice()); - case '-o': - case '--output': - output = argv.shift(); - break; - case '-i': - case '--input': - input = argv.shift(); - break; - case '-t': - case '--tokens': - tokens = true; - break; - case '-h': - case '--help': - return help(); - default: - if (arg.indexOf('--') === 0) { - opt = camelize(arg.replace(/^--(no-)?/, '')); - if (!marked.defaults.hasOwnProperty(opt)) { - continue; - } - if (arg.indexOf('--no-') === 0) { - options[opt] = typeof marked.defaults[opt] !== 'boolean' - ? null - : false; - } else { - options[opt] = typeof marked.defaults[opt] !== 'boolean' - ? argv.shift() - : true; - } - } else { - files.push(arg); - } - break; - } - } - - function getData(callback) { - if (!input) { - if (files.length <= 2) { - return getStdin(callback); - } - input = files.pop(); - } - return fs.readFile(input, 'utf8', callback); - } - - return getData(function(err, data) { - if (err) return callback(err); - - data = tokens - ? JSON.stringify(marked.lexer(data, options), null, 2) - : marked(data, options); - - if (!output) { - process.stdout.write(data + '\n'); - return callback(); - } - - return fs.writeFile(output, data, callback); - }); -} - -/** - * Helpers - */ - -function getStdin(callback) { - var stdin = process.stdin - , buff = ''; - - stdin.setEncoding('utf8'); - - stdin.on('data', function(data) { - buff += data; - }); - - stdin.on('error', function(err) { - return callback(err); - }); - - stdin.on('end', function() { - return callback(null, buff); - }); - - try { - stdin.resume(); - } catch (e) { - callback(e); - } -} - -function camelize(text) { - return text.replace(/(\w)-(\w)/g, function(_, a, b) { - return a + b.toUpperCase(); - }); -} - -/** - * Expose / Entry Point - */ - -if (!module.parent) { - process.title = 'marked'; - main(process.argv.slice(), function(err, code) { - if (err) throw err; - return process.exit(code || 0); - }); -} else { - module.exports = main; -} diff --git a/js/vendor/marked/bower.json b/js/vendor/marked/bower.json deleted file mode 100644 index 3eab3110c6..0000000000 --- a/js/vendor/marked/bower.json +++ /dev/null @@ -1,24 +0,0 @@ -{ - "name": "marked", - "version": "0.3.2", - "homepage": "https://github.com/chjj/marked", - "authors": [ - "Christopher Jeffrey " - ], - "description": "A markdown parser built for speed", - "keywords": [ - "markdown", - "markup", - "html" - ], - "main": "lib/marked.js", - "license": "MIT", - "ignore": [ - "**/.*", - "node_modules", - "bower_components", - "app/bower_components", - "test", - "tests" - ] -} diff --git a/js/vendor/marked/component.json b/js/vendor/marked/component.json deleted file mode 100644 index 931cbedcdf..0000000000 --- a/js/vendor/marked/component.json +++ /dev/null @@ -1,10 +0,0 @@ -{ - "name": "marked", - "version": "0.3.2", - "repo": "chjj/marked", - "description": "A markdown parser built for speed", - "keywords": ["markdown", "markup", "html"], - "scripts": ["lib/marked.js"], - "main": "lib/marked.js", - "license": "MIT" -} diff --git a/js/vendor/marked/doc/broken.md b/js/vendor/marked/doc/broken.md deleted file mode 100644 index 7bfa49e8a9..0000000000 --- a/js/vendor/marked/doc/broken.md +++ /dev/null @@ -1,426 +0,0 @@ -# Markdown is broken - -I have a lot of scraps of markdown engine oddities that I've collected over the -years. What you see below is slightly messy, but it's what I've managed to -cobble together to illustrate the differences between markdown engines, and -why, if there ever is a markdown specification, it has to be absolutely -thorough. There are a lot more of these little differences I have documented -elsewhere. I know I will find them lingering on my disk one day, but until -then, I'll continue to add whatever strange nonsensical things I find. - -Some of these examples may only mention a particular engine compared to marked. -However, the examples with markdown.pl could easily be swapped out for -discount, upskirt, or markdown.js, and you would very easily see even more -inconsistencies. - -A lot of this was written when I was very unsatisfied with the inconsistencies -between markdown engines. Please excuse the frustration noticeable in my -writing. - -## Examples of markdown's "stupid" list parsing - -``` -$ markdown.pl - - * item1 - - * item2 - - text -^D -
    -
  • item1

    - -
      -
    • item2
    • -
    - -

    text

  • -

-``` - - -``` -$ marked - * item1 - - * item2 - - text -^D -
    -
  • item1

    -
      -
    • item2
    • -
    -

    text

    -
  • -
-``` - -Which looks correct to you? - -- - - - -``` -$ markdown.pl -* hello - > world -^D -

    -
  • hello

    - -
    -

    world

  • -

- -``` - -``` -$ marked -* hello - > world -^D -
    -
  • hello
    -

    world

    -
    -
  • -
-``` - -Again, which looks correct to you? - -- - - - -EXAMPLE: - -``` -$ markdown.pl -* hello - * world - * hi - code -^D -
    -
  • hello -
      -
    • world
    • -
    • hi - code
    • -
  • -
-``` - -The code isn't a code block even though it's after the bullet margin. I know, -lets give it two more spaces, effectively making it 8 spaces past the bullet. - -``` -$ markdown.pl -* hello - * world - * hi - code -^D -
    -
  • hello -
      -
    • world
    • -
    • hi - code
    • -
  • -
-``` - -And, it's still not a code block. Did you also notice that the 3rd item isn't -even its own list? Markdown screws that up too because of its indentation -unaware parsing. - -- - - - -Let's look at some more examples of markdown's list parsing: - -``` -$ markdown.pl - - * item1 - - * item2 - - text -^D -
    -
  • item1

    - -
      -
    • item2
    • -
    - -

    text

  • -

-``` - -Misnested tags. - - -``` -$ marked - * item1 - - * item2 - - text -^D -
    -
  • item1

    -
      -
    • item2
    • -
    -

    text

    -
  • -
-``` - -Which looks correct to you? - -- - - - -``` -$ markdown.pl -* hello - > world -^D -

    -
  • hello

    - -
    -

    world

  • -

- -``` - -More misnested tags. - - -``` -$ marked -* hello - > world -^D -
    -
  • hello
    -

    world

    -
    -
  • -
-``` - -Again, which looks correct to you? - -- - - - -# Why quality matters - Part 2 - -``` bash -$ markdown.pl -* hello - > world -^D -

    -
  • hello

    - -
    -

    world

  • -

- -``` - -``` bash -$ sundown # upskirt -* hello - > world -^D -
    -
  • hello -> world
  • -
-``` - -``` bash -$ marked -* hello - > world -^D -
  • hello

    world

-``` - -Which looks correct to you? - -- - - - -See: https://github.com/evilstreak/markdown-js/issues/23 - -``` bash -$ markdown.pl # upskirt/markdown.js/discount -* hello - var a = 1; -* world -^D -
    -
  • hello -var a = 1;
  • -
  • world
  • -
-``` - -``` bash -$ marked -* hello - var a = 1; -* world -^D -
  • hello -
    code>var a = 1;
  • -
  • world
-``` - -Which looks more reasonable? Why shouldn't code blocks be able to appear in -list items in a sane way? - -- - - - -``` bash -$ markdown.js -
hello
- -hello -^D -

<div>hello</div>

- -

<span>hello</span>

-``` - -``` bash -$ marked -
hello
- -hello -^D -
hello
- - -

hello -

-``` - -- - - - -See: https://github.com/evilstreak/markdown-js/issues/27 - -``` bash -$ markdown.js -[![an image](/image)](/link) -^D -

![an image

-``` - -``` bash -$ marked -[![an image](/image)](/link) -^D -

an image -

-``` - -- - - - -See: https://github.com/evilstreak/markdown-js/issues/24 - -``` bash -$ markdown.js -> a - -> b - -> c -^D -

a

bundefined> c

-``` - -``` bash -$ marked -> a - -> b - -> c -^D -

a - -

-

b - -

-

c -

-``` - -- - - - -``` bash -$ markdown.pl -* hello - * world - how - - are - you - - * today -* hi -^D -
    -
  • hello

    - -
      -
    • world -how
    • -
    - -

    are -you

    - -
      -
    • today
    • -
  • -
  • hi
  • -
-``` - -``` bash -$ marked -* hello - * world - how - - are - you - - * today -* hi -^D -
    -
  • hello

    -
      -
    • world -how

      -

      are -you

      -
    • -
    • today

      -
    • -
    -
  • -
  • hi
  • -
-``` diff --git a/js/vendor/marked/doc/todo.md b/js/vendor/marked/doc/todo.md deleted file mode 100644 index 2e60b162ae..0000000000 --- a/js/vendor/marked/doc/todo.md +++ /dev/null @@ -1,2 +0,0 @@ -# Todo - diff --git a/js/vendor/marked/index.js b/js/vendor/marked/index.js deleted file mode 100644 index a12f90569f..0000000000 --- a/js/vendor/marked/index.js +++ /dev/null @@ -1 +0,0 @@ -module.exports = require('./lib/marked'); diff --git a/js/vendor/marked/lib/marked.js b/js/vendor/marked/lib/marked.js deleted file mode 100644 index 0b7180ff62..0000000000 --- a/js/vendor/marked/lib/marked.js +++ /dev/null @@ -1,1272 +0,0 @@ -/** - * marked - a markdown parser - * Copyright (c) 2011-2014, Christopher Jeffrey. (MIT Licensed) - * https://github.com/chjj/marked - */ - -;(function() { - -/** - * Block-Level Grammar - */ - -var block = { - newline: /^\n+/, - code: /^( {4}[^\n]+\n*)+/, - fences: noop, - hr: /^( *[-*_]){3,} *(?:\n+|$)/, - heading: /^ *(#{1,6}) *([^\n]+?) *#* *(?:\n+|$)/, - nptable: noop, - lheading: /^([^\n]+)\n *(=|-){2,} *(?:\n+|$)/, - blockquote: /^( *>[^\n]+(\n(?!def)[^\n]+)*\n*)+/, - list: /^( *)(bull) [\s\S]+?(?:hr|def|\n{2,}(?! )(?!\1bull )\n*|\s*$)/, - html: /^ *(?:comment *(?:\n|\s*$)|closed *(?:\n{2,}|\s*$)|closing *(?:\n{2,}|\s*$))/, - def: /^ *\[([^\]]+)\]: *]+)>?(?: +["(]([^\n]+)[")])? *(?:\n+|$)/, - table: noop, - paragraph: /^((?:[^\n]+\n?(?!hr|heading|lheading|blockquote|tag|def))+)\n*/, - text: /^[^\n]+/ -}; - -block.bullet = /(?:[*+-]|\d+\.)/; -block.item = /^( *)(bull) [^\n]*(?:\n(?!\1bull )[^\n]*)*/; -block.item = replace(block.item, 'gm') - (/bull/g, block.bullet) - (); - -block.list = replace(block.list) - (/bull/g, block.bullet) - ('hr', '\\n+(?=\\1?(?:[-*_] *){3,}(?:\\n+|$))') - ('def', '\\n+(?=' + block.def.source + ')') - (); - -block.blockquote = replace(block.blockquote) - ('def', block.def) - (); - -block._tag = '(?!(?:' - + 'a|em|strong|small|s|cite|q|dfn|abbr|data|time|code' - + '|var|samp|kbd|sub|sup|i|b|u|mark|ruby|rt|rp|bdi|bdo' - + '|span|br|wbr|ins|del|img)\\b)\\w+(?!:/|[^\\w\\s@]*@)\\b'; - -block.html = replace(block.html) - ('comment', //) - ('closed', /<(tag)[\s\S]+?<\/\1>/) - ('closing', /])*?>/) - (/tag/g, block._tag) - (); - -block.paragraph = replace(block.paragraph) - ('hr', block.hr) - ('heading', block.heading) - ('lheading', block.lheading) - ('blockquote', block.blockquote) - ('tag', '<' + block._tag) - ('def', block.def) - (); - -/** - * Normal Block Grammar - */ - -block.normal = merge({}, block); - -/** - * GFM Block Grammar - */ - -block.gfm = merge({}, block.normal, { - fences: /^ *(`{3,}|~{3,}) *(\S+)? *\n([\s\S]+?)\s*\1 *(?:\n+|$)/, - paragraph: /^/ -}); - -block.gfm.paragraph = replace(block.paragraph) - ('(?!', '(?!' - + block.gfm.fences.source.replace('\\1', '\\2') + '|' - + block.list.source.replace('\\1', '\\3') + '|') - (); - -/** - * GFM + Tables Block Grammar - */ - -block.tables = merge({}, block.gfm, { - nptable: /^ *(\S.*\|.*)\n *([-:]+ *\|[-| :]*)\n((?:.*\|.*(?:\n|$))*)\n*/, - table: /^ *\|(.+)\n *\|( *[-:]+[-| :]*)\n((?: *\|.*(?:\n|$))*)\n*/ -}); - -/** - * Block Lexer - */ - -function Lexer(options) { - this.tokens = []; - this.tokens.links = {}; - this.options = options || marked.defaults; - this.rules = block.normal; - - if (this.options.gfm) { - if (this.options.tables) { - this.rules = block.tables; - } else { - this.rules = block.gfm; - } - } -} - -/** - * Expose Block Rules - */ - -Lexer.rules = block; - -/** - * Static Lex Method - */ - -Lexer.lex = function(src, options) { - var lexer = new Lexer(options); - return lexer.lex(src); -}; - -/** - * Preprocessing - */ - -Lexer.prototype.lex = function(src) { - src = src - .replace(/\r\n|\r/g, '\n') - .replace(/\t/g, ' ') - .replace(/\u00a0/g, ' ') - .replace(/\u2424/g, '\n'); - - return this.token(src, true); -}; - -/** - * Lexing - */ - -Lexer.prototype.token = function(src, top, bq) { - var src = src.replace(/^ +$/gm, '') - , next - , loose - , cap - , bull - , b - , item - , space - , i - , l; - - while (src) { - // newline - if (cap = this.rules.newline.exec(src)) { - src = src.substring(cap[0].length); - if (cap[0].length > 1) { - this.tokens.push({ - type: 'space' - }); - } - } - - // code - if (cap = this.rules.code.exec(src)) { - src = src.substring(cap[0].length); - cap = cap[0].replace(/^ {4}/gm, ''); - this.tokens.push({ - type: 'code', - text: !this.options.pedantic - ? cap.replace(/\n+$/, '') - : cap - }); - continue; - } - - // fences (gfm) - if (cap = this.rules.fences.exec(src)) { - src = src.substring(cap[0].length); - this.tokens.push({ - type: 'code', - lang: cap[2], - text: cap[3] - }); - continue; - } - - // heading - if (cap = this.rules.heading.exec(src)) { - src = src.substring(cap[0].length); - this.tokens.push({ - type: 'heading', - depth: cap[1].length, - text: cap[2] - }); - continue; - } - - // table no leading pipe (gfm) - if (top && (cap = this.rules.nptable.exec(src))) { - src = src.substring(cap[0].length); - - item = { - type: 'table', - header: cap[1].replace(/^ *| *\| *$/g, '').split(/ *\| */), - align: cap[2].replace(/^ *|\| *$/g, '').split(/ *\| */), - cells: cap[3].replace(/\n$/, '').split('\n') - }; - - for (i = 0; i < item.align.length; i++) { - if (/^ *-+: *$/.test(item.align[i])) { - item.align[i] = 'right'; - } else if (/^ *:-+: *$/.test(item.align[i])) { - item.align[i] = 'center'; - } else if (/^ *:-+ *$/.test(item.align[i])) { - item.align[i] = 'left'; - } else { - item.align[i] = null; - } - } - - for (i = 0; i < item.cells.length; i++) { - item.cells[i] = item.cells[i].split(/ *\| */); - } - - this.tokens.push(item); - - continue; - } - - // lheading - if (cap = this.rules.lheading.exec(src)) { - src = src.substring(cap[0].length); - this.tokens.push({ - type: 'heading', - depth: cap[2] === '=' ? 1 : 2, - text: cap[1] - }); - continue; - } - - // hr - if (cap = this.rules.hr.exec(src)) { - src = src.substring(cap[0].length); - this.tokens.push({ - type: 'hr' - }); - continue; - } - - // blockquote - if (cap = this.rules.blockquote.exec(src)) { - src = src.substring(cap[0].length); - - this.tokens.push({ - type: 'blockquote_start' - }); - - cap = cap[0].replace(/^ *> ?/gm, ''); - - // Pass `top` to keep the current - // "toplevel" state. This is exactly - // how markdown.pl works. - this.token(cap, top, true); - - this.tokens.push({ - type: 'blockquote_end' - }); - - continue; - } - - // list - if (cap = this.rules.list.exec(src)) { - src = src.substring(cap[0].length); - bull = cap[2]; - - this.tokens.push({ - type: 'list_start', - ordered: bull.length > 1 - }); - - // Get each top-level item. - cap = cap[0].match(this.rules.item); - - next = false; - l = cap.length; - i = 0; - - for (; i < l; i++) { - item = cap[i]; - - // Remove the list item's bullet - // so it is seen as the next token. - space = item.length; - item = item.replace(/^ *([*+-]|\d+\.) +/, ''); - - // Outdent whatever the - // list item contains. Hacky. - if (~item.indexOf('\n ')) { - space -= item.length; - item = !this.options.pedantic - ? item.replace(new RegExp('^ {1,' + space + '}', 'gm'), '') - : item.replace(/^ {1,4}/gm, ''); - } - - // Determine whether the next list item belongs here. - // Backpedal if it does not belong in this list. - if (this.options.smartLists && i !== l - 1) { - b = block.bullet.exec(cap[i + 1])[0]; - if (bull !== b && !(bull.length > 1 && b.length > 1)) { - src = cap.slice(i + 1).join('\n') + src; - i = l - 1; - } - } - - // Determine whether item is loose or not. - // Use: /(^|\n)(?! )[^\n]+\n\n(?!\s*$)/ - // for discount behavior. - loose = next || /\n\n(?!\s*$)/.test(item); - if (i !== l - 1) { - next = item.charAt(item.length - 1) === '\n'; - if (!loose) loose = next; - } - - this.tokens.push({ - type: loose - ? 'loose_item_start' - : 'list_item_start' - }); - - // Recurse. - this.token(item, false, bq); - - this.tokens.push({ - type: 'list_item_end' - }); - } - - this.tokens.push({ - type: 'list_end' - }); - - continue; - } - - // html - if (cap = this.rules.html.exec(src)) { - src = src.substring(cap[0].length); - this.tokens.push({ - type: this.options.sanitize - ? 'paragraph' - : 'html', - pre: cap[1] === 'pre' || cap[1] === 'script' || cap[1] === 'style', - text: cap[0] - }); - continue; - } - - // def - if ((!bq && top) && (cap = this.rules.def.exec(src))) { - src = src.substring(cap[0].length); - this.tokens.links[cap[1].toLowerCase()] = { - href: cap[2], - title: cap[3] - }; - continue; - } - - // table (gfm) - if (top && (cap = this.rules.table.exec(src))) { - src = src.substring(cap[0].length); - - item = { - type: 'table', - header: cap[1].replace(/^ *| *\| *$/g, '').split(/ *\| */), - align: cap[2].replace(/^ *|\| *$/g, '').split(/ *\| */), - cells: cap[3].replace(/(?: *\| *)?\n$/, '').split('\n') - }; - - for (i = 0; i < item.align.length; i++) { - if (/^ *-+: *$/.test(item.align[i])) { - item.align[i] = 'right'; - } else if (/^ *:-+: *$/.test(item.align[i])) { - item.align[i] = 'center'; - } else if (/^ *:-+ *$/.test(item.align[i])) { - item.align[i] = 'left'; - } else { - item.align[i] = null; - } - } - - for (i = 0; i < item.cells.length; i++) { - item.cells[i] = item.cells[i] - .replace(/^ *\| *| *\| *$/g, '') - .split(/ *\| */); - } - - this.tokens.push(item); - - continue; - } - - // top-level paragraph - if (top && (cap = this.rules.paragraph.exec(src))) { - src = src.substring(cap[0].length); - this.tokens.push({ - type: 'paragraph', - text: cap[1].charAt(cap[1].length - 1) === '\n' - ? cap[1].slice(0, -1) - : cap[1] - }); - continue; - } - - // text - if (cap = this.rules.text.exec(src)) { - // Top-level should never reach here. - src = src.substring(cap[0].length); - this.tokens.push({ - type: 'text', - text: cap[0] - }); - continue; - } - - if (src) { - throw new - Error('Infinite loop on byte: ' + src.charCodeAt(0)); - } - } - - return this.tokens; -}; - -/** - * Inline-Level Grammar - */ - -var inline = { - escape: /^\\([\\`*{}\[\]()#+\-.!_>])/, - autolink: /^<([^ >]+(@|:\/)[^ >]+)>/, - url: noop, - tag: /^|^<\/?\w+(?:"[^"]*"|'[^']*'|[^'">])*?>/, - link: /^!?\[(inside)\]\(href\)/, - reflink: /^!?\[(inside)\]\s*\[([^\]]*)\]/, - nolink: /^!?\[((?:\[[^\]]*\]|[^\[\]])*)\]/, - strong: /^__([\s\S]+?)__(?!_)|^\*\*([\s\S]+?)\*\*(?!\*)/, - em: /^\b_((?:__|[\s\S])+?)_\b|^\*((?:\*\*|[\s\S])+?)\*(?!\*)/, - code: /^(`+)\s*([\s\S]*?[^`])\s*\1(?!`)/, - br: /^ {2,}\n(?!\s*$)/, - del: noop, - text: /^[\s\S]+?(?=[\\?(?:\s+['"]([\s\S]*?)['"])?\s*/; - -inline.link = replace(inline.link) - ('inside', inline._inside) - ('href', inline._href) - (); - -inline.reflink = replace(inline.reflink) - ('inside', inline._inside) - (); - -/** - * Normal Inline Grammar - */ - -inline.normal = merge({}, inline); - -/** - * Pedantic Inline Grammar - */ - -inline.pedantic = merge({}, inline.normal, { - strong: /^__(?=\S)([\s\S]*?\S)__(?!_)|^\*\*(?=\S)([\s\S]*?\S)\*\*(?!\*)/, - em: /^_(?=\S)([\s\S]*?\S)_(?!_)|^\*(?=\S)([\s\S]*?\S)\*(?!\*)/ -}); - -/** - * GFM Inline Grammar - */ - -inline.gfm = merge({}, inline.normal, { - escape: replace(inline.escape)('])', '~|])')(), - url: /^(https?:\/\/[^\s<]+[^<.,:;"')\]\s])/, - del: /^~~(?=\S)([\s\S]*?\S)~~/, - text: replace(inline.text) - (']|', '~]|') - ('|', '|https?://|') - () -}); - -/** - * GFM + Line Breaks Inline Grammar - */ - -inline.breaks = merge({}, inline.gfm, { - br: replace(inline.br)('{2,}', '*')(), - text: replace(inline.gfm.text)('{2,}', '*')() -}); - -/** - * Inline Lexer & Compiler - */ - -function InlineLexer(links, options) { - this.options = options || marked.defaults; - this.links = links; - this.rules = inline.normal; - this.renderer = this.options.renderer || new Renderer; - this.renderer.options = this.options; - - if (!this.links) { - throw new - Error('Tokens array requires a `links` property.'); - } - - if (this.options.gfm) { - if (this.options.breaks) { - this.rules = inline.breaks; - } else { - this.rules = inline.gfm; - } - } else if (this.options.pedantic) { - this.rules = inline.pedantic; - } -} - -/** - * Expose Inline Rules - */ - -InlineLexer.rules = inline; - -/** - * Static Lexing/Compiling Method - */ - -InlineLexer.output = function(src, links, options) { - var inline = new InlineLexer(links, options); - return inline.output(src); -}; - -/** - * Lexing/Compiling - */ - -InlineLexer.prototype.output = function(src) { - var out = '' - , link - , text - , href - , cap; - - while (src) { - // escape - if (cap = this.rules.escape.exec(src)) { - src = src.substring(cap[0].length); - out += cap[1]; - continue; - } - - // autolink - if (cap = this.rules.autolink.exec(src)) { - src = src.substring(cap[0].length); - if (cap[2] === '@') { - text = cap[1].charAt(6) === ':' - ? this.mangle(cap[1].substring(7)) - : this.mangle(cap[1]); - href = this.mangle('mailto:') + text; - } else { - text = escape(cap[1]); - href = text; - } - out += this.renderer.link(href, null, text); - continue; - } - - // url (gfm) - if (!this.inLink && (cap = this.rules.url.exec(src))) { - src = src.substring(cap[0].length); - text = escape(cap[1]); - href = text; - out += this.renderer.link(href, null, text); - continue; - } - - // tag - if (cap = this.rules.tag.exec(src)) { - if (!this.inLink && /^/i.test(cap[0])) { - this.inLink = false; - } - src = src.substring(cap[0].length); - out += this.options.sanitize - ? escape(cap[0]) - : cap[0]; - continue; - } - - // link - if (cap = this.rules.link.exec(src)) { - src = src.substring(cap[0].length); - this.inLink = true; - out += this.outputLink(cap, { - href: cap[2], - title: cap[3] - }); - this.inLink = false; - continue; - } - - // reflink, nolink - if ((cap = this.rules.reflink.exec(src)) - || (cap = this.rules.nolink.exec(src))) { - src = src.substring(cap[0].length); - link = (cap[2] || cap[1]).replace(/\s+/g, ' '); - link = this.links[link.toLowerCase()]; - if (!link || !link.href) { - out += cap[0].charAt(0); - src = cap[0].substring(1) + src; - continue; - } - this.inLink = true; - out += this.outputLink(cap, link); - this.inLink = false; - continue; - } - - // strong - if (cap = this.rules.strong.exec(src)) { - src = src.substring(cap[0].length); - out += this.renderer.strong(this.output(cap[2] || cap[1])); - continue; - } - - // em - if (cap = this.rules.em.exec(src)) { - src = src.substring(cap[0].length); - out += this.renderer.em(this.output(cap[2] || cap[1])); - continue; - } - - // code - if (cap = this.rules.code.exec(src)) { - src = src.substring(cap[0].length); - out += this.renderer.codespan(escape(cap[2], true)); - continue; - } - - // br - if (cap = this.rules.br.exec(src)) { - src = src.substring(cap[0].length); - out += this.renderer.br(); - continue; - } - - // del (gfm) - if (cap = this.rules.del.exec(src)) { - src = src.substring(cap[0].length); - out += this.renderer.del(this.output(cap[1])); - continue; - } - - // text - if (cap = this.rules.text.exec(src)) { - src = src.substring(cap[0].length); - out += escape(this.smartypants(cap[0])); - continue; - } - - if (src) { - throw new - Error('Infinite loop on byte: ' + src.charCodeAt(0)); - } - } - - return out; -}; - -/** - * Compile Link - */ - -InlineLexer.prototype.outputLink = function(cap, link) { - var href = escape(link.href) - , title = link.title ? escape(link.title) : null; - - return cap[0].charAt(0) !== '!' - ? this.renderer.link(href, title, this.output(cap[1])) - : this.renderer.image(href, title, escape(cap[1])); -}; - -/** - * Smartypants Transformations - */ - -InlineLexer.prototype.smartypants = function(text) { - if (!this.options.smartypants) return text; - return text - // em-dashes - .replace(/--/g, '\u2014') - // opening singles - .replace(/(^|[-\u2014/(\[{"\s])'/g, '$1\u2018') - // closing singles & apostrophes - .replace(/'/g, '\u2019') - // opening doubles - .replace(/(^|[-\u2014/(\[{\u2018\s])"/g, '$1\u201c') - // closing doubles - .replace(/"/g, '\u201d') - // ellipses - .replace(/\.{3}/g, '\u2026'); -}; - -/** - * Mangle Links - */ - -InlineLexer.prototype.mangle = function(text) { - var out = '' - , l = text.length - , i = 0 - , ch; - - for (; i < l; i++) { - ch = text.charCodeAt(i); - if (Math.random() > 0.5) { - ch = 'x' + ch.toString(16); - } - out += '&#' + ch + ';'; - } - - return out; -}; - -/** - * Renderer - */ - -function Renderer(options) { - this.options = options || {}; -} - -Renderer.prototype.code = function(code, lang, escaped) { - if (this.options.highlight) { - var out = this.options.highlight(code, lang); - if (out != null && out !== code) { - escaped = true; - code = out; - } - } - - if (!lang) { - return '
'
-      + (escaped ? code : escape(code, true))
-      + '\n
'; - } - - return '
'
-    + (escaped ? code : escape(code, true))
-    + '\n
\n'; -}; - -Renderer.prototype.blockquote = function(quote) { - return '
\n' + quote + '
\n'; -}; - -Renderer.prototype.html = function(html) { - return html; -}; - -Renderer.prototype.heading = function(text, level, raw) { - return '' - + text - + '\n'; -}; - -Renderer.prototype.hr = function() { - return this.options.xhtml ? '
\n' : '
\n'; -}; - -Renderer.prototype.list = function(body, ordered) { - var type = ordered ? 'ol' : 'ul'; - return '<' + type + '>\n' + body + '\n'; -}; - -Renderer.prototype.listitem = function(text) { - return '
  • ' + text + '
  • \n'; -}; - -Renderer.prototype.paragraph = function(text) { - return '

    ' + text + '

    \n'; -}; - -Renderer.prototype.table = function(header, body) { - return '\n' - + '\n' - + header - + '\n' - + '\n' - + body - + '\n' - + '
    \n'; -}; - -Renderer.prototype.tablerow = function(content) { - return '\n' + content + '\n'; -}; - -Renderer.prototype.tablecell = function(content, flags) { - var type = flags.header ? 'th' : 'td'; - var tag = flags.align - ? '<' + type + ' style="text-align:' + flags.align + '">' - : '<' + type + '>'; - return tag + content + '\n'; -}; - -// span level renderer -Renderer.prototype.strong = function(text) { - return '' + text + ''; -}; - -Renderer.prototype.em = function(text) { - return '' + text + ''; -}; - -Renderer.prototype.codespan = function(text) { - return '' + text + ''; -}; - -Renderer.prototype.br = function() { - return this.options.xhtml ? '
    ' : '
    '; -}; - -Renderer.prototype.del = function(text) { - return '' + text + ''; -}; - -Renderer.prototype.link = function(href, title, text) { - if (this.options.sanitize) { - try { - var prot = decodeURIComponent(unescape(href)) - .replace(/[^\w:]/g, '') - .toLowerCase(); - } catch (e) { - return ''; - } - if (prot.indexOf('javascript:') === 0 || prot.indexOf('vbscript:') === 0) { - return ''; - } - } - var out = '
    '; - return out; -}; - -Renderer.prototype.image = function(href, title, text) { - var out = '' + text + '' : '>'; - return out; -}; - -/** - * Parsing & Compiling - */ - -function Parser(options) { - this.tokens = []; - this.token = null; - this.options = options || marked.defaults; - this.options.renderer = this.options.renderer || new Renderer; - this.renderer = this.options.renderer; - this.renderer.options = this.options; -} - -/** - * Static Parse Method - */ - -Parser.parse = function(src, options, renderer) { - var parser = new Parser(options, renderer); - return parser.parse(src); -}; - -/** - * Parse Loop - */ - -Parser.prototype.parse = function(src) { - this.inline = new InlineLexer(src.links, this.options, this.renderer); - this.tokens = src.reverse(); - - var out = ''; - while (this.next()) { - out += this.tok(); - } - - return out; -}; - -/** - * Next Token - */ - -Parser.prototype.next = function() { - return this.token = this.tokens.pop(); -}; - -/** - * Preview Next Token - */ - -Parser.prototype.peek = function() { - return this.tokens[this.tokens.length - 1] || 0; -}; - -/** - * Parse Text Tokens - */ - -Parser.prototype.parseText = function() { - var body = this.token.text; - - while (this.peek().type === 'text') { - body += '\n' + this.next().text; - } - - return this.inline.output(body); -}; - -/** - * Parse Current Token - */ - -Parser.prototype.tok = function() { - switch (this.token.type) { - case 'space': { - return ''; - } - case 'hr': { - return this.renderer.hr(); - } - case 'heading': { - return this.renderer.heading( - this.inline.output(this.token.text), - this.token.depth, - this.token.text); - } - case 'code': { - return this.renderer.code(this.token.text, - this.token.lang, - this.token.escaped); - } - case 'table': { - var header = '' - , body = '' - , i - , row - , cell - , flags - , j; - - // header - cell = ''; - for (i = 0; i < this.token.header.length; i++) { - flags = { header: true, align: this.token.align[i] }; - cell += this.renderer.tablecell( - this.inline.output(this.token.header[i]), - { header: true, align: this.token.align[i] } - ); - } - header += this.renderer.tablerow(cell); - - for (i = 0; i < this.token.cells.length; i++) { - row = this.token.cells[i]; - - cell = ''; - for (j = 0; j < row.length; j++) { - cell += this.renderer.tablecell( - this.inline.output(row[j]), - { header: false, align: this.token.align[j] } - ); - } - - body += this.renderer.tablerow(cell); - } - return this.renderer.table(header, body); - } - case 'blockquote_start': { - var body = ''; - - while (this.next().type !== 'blockquote_end') { - body += this.tok(); - } - - return this.renderer.blockquote(body); - } - case 'list_start': { - var body = '' - , ordered = this.token.ordered; - - while (this.next().type !== 'list_end') { - body += this.tok(); - } - - return this.renderer.list(body, ordered); - } - case 'list_item_start': { - var body = ''; - - while (this.next().type !== 'list_item_end') { - body += this.token.type === 'text' - ? this.parseText() - : this.tok(); - } - - return this.renderer.listitem(body); - } - case 'loose_item_start': { - var body = ''; - - while (this.next().type !== 'list_item_end') { - body += this.tok(); - } - - return this.renderer.listitem(body); - } - case 'html': { - var html = !this.token.pre && !this.options.pedantic - ? this.inline.output(this.token.text) - : this.token.text; - return this.renderer.html(html); - } - case 'paragraph': { - return this.renderer.paragraph(this.inline.output(this.token.text)); - } - case 'text': { - return this.renderer.paragraph(this.parseText()); - } - } -}; - -/** - * Helpers - */ - -function escape(html, encode) { - return html - .replace(!encode ? /&(?!#?\w+;)/g : /&/g, '&') - .replace(//g, '>') - .replace(/"/g, '"') - .replace(/'/g, '''); -} - -function unescape(html) { - return html.replace(/&([#\w]+);/g, function(_, n) { - n = n.toLowerCase(); - if (n === 'colon') return ':'; - if (n.charAt(0) === '#') { - return n.charAt(1) === 'x' - ? String.fromCharCode(parseInt(n.substring(2), 16)) - : String.fromCharCode(+n.substring(1)); - } - return ''; - }); -} - -function replace(regex, opt) { - regex = regex.source; - opt = opt || ''; - return function self(name, val) { - if (!name) return new RegExp(regex, opt); - val = val.source || val; - val = val.replace(/(^|[^\[])\^/g, '$1'); - regex = regex.replace(name, val); - return self; - }; -} - -function noop() {} -noop.exec = noop; - -function merge(obj) { - var i = 1 - , target - , key; - - for (; i < arguments.length; i++) { - target = arguments[i]; - for (key in target) { - if (Object.prototype.hasOwnProperty.call(target, key)) { - obj[key] = target[key]; - } - } - } - - return obj; -} - - -/** - * Marked - */ - -function marked(src, opt, callback) { - if (callback || typeof opt === 'function') { - if (!callback) { - callback = opt; - opt = null; - } - - opt = merge({}, marked.defaults, opt || {}); - - var highlight = opt.highlight - , tokens - , pending - , i = 0; - - try { - tokens = Lexer.lex(src, opt) - } catch (e) { - return callback(e); - } - - pending = tokens.length; - - var done = function(err) { - if (err) { - opt.highlight = highlight; - return callback(err); - } - - var out; - - try { - out = Parser.parse(tokens, opt); - } catch (e) { - err = e; - } - - opt.highlight = highlight; - - return err - ? callback(err) - : callback(null, out); - }; - - if (!highlight || highlight.length < 3) { - return done(); - } - - delete opt.highlight; - - if (!pending) return done(); - - for (; i < tokens.length; i++) { - (function(token) { - if (token.type !== 'code') { - return --pending || done(); - } - return highlight(token.text, token.lang, function(err, code) { - if (err) return done(err); - if (code == null || code === token.text) { - return --pending || done(); - } - token.text = code; - token.escaped = true; - --pending || done(); - }); - })(tokens[i]); - } - - return; - } - try { - if (opt) opt = merge({}, marked.defaults, opt); - return Parser.parse(Lexer.lex(src, opt), opt); - } catch (e) { - e.message += '\nPlease report this to https://github.com/chjj/marked.'; - if ((opt || marked.defaults).silent) { - return '

    An error occured:

    '
    -        + escape(e.message + '', true)
    -        + '
    '; - } - throw e; - } -} - -/** - * Options - */ - -marked.options = -marked.setOptions = function(opt) { - merge(marked.defaults, opt); - return marked; -}; - -marked.defaults = { - gfm: true, - tables: true, - breaks: false, - pedantic: false, - sanitize: false, - smartLists: false, - silent: false, - highlight: null, - langPrefix: 'lang-', - smartypants: false, - headerPrefix: '', - renderer: new Renderer, - xhtml: false -}; - -/** - * Expose - */ - -marked.Parser = Parser; -marked.parser = Parser.parse; - -marked.Renderer = Renderer; - -marked.Lexer = Lexer; -marked.lexer = Lexer.lex; - -marked.InlineLexer = InlineLexer; -marked.inlineLexer = InlineLexer.output; - -marked.parse = marked; - -if (typeof module !== 'undefined' && typeof exports === 'object') { - module.exports = marked; -} else if (typeof define === 'function' && define.amd) { - define(function() { return marked; }); -} else { - this.marked = marked; -} - -}).call(function() { - return this || (typeof window !== 'undefined' ? window : global); -}()); diff --git a/js/vendor/marked/man/marked.1 b/js/vendor/marked/man/marked.1 deleted file mode 100644 index f89f1a7b9a..0000000000 --- a/js/vendor/marked/man/marked.1 +++ /dev/null @@ -1,88 +0,0 @@ -.ds q \N'34' -.TH marked 1 "2014-01-31" "v0.3.1" "marked.js" - -.SH NAME -marked \- a javascript markdown parser - -.SH SYNOPSIS -.B marked -[\-o \fI\fP] [\-i \fI\fP] [\-\-help] -[\-\-tokens] [\-\-pedantic] [\-\-gfm] -[\-\-breaks] [\-\-tables] [\-\-sanitize] -[\-\-smart\-lists] [\-\-lang\-prefix \fI\fP] -[\-\-no\-etc...] [\-\-silent] [\fIfilename\fP] - -.SH DESCRIPTION -.B marked -is a full-featured javascript markdown parser, built for speed. It also includes -multiple GFM features. - -.SH EXAMPLES -.TP -cat in.md | marked > out.html -.TP -echo "hello *world*" | marked -.TP -marked \-o out.html in.md \-\-gfm -.TP -marked \-\-output="hello world.html" \-i in.md \-\-no-breaks - -.SH OPTIONS -.TP -.BI \-o,\ \-\-output\ [\fIoutput\fP] -Specify file output. If none is specified, write to stdout. -.TP -.BI \-i,\ \-\-input\ [\fIinput\fP] -Specify file input, otherwise use last argument as input file. If no input file -is specified, read from stdin. -.TP -.BI \-t,\ \-\-tokens -Output a token stream instead of html. -.TP -.BI \-\-pedantic -Conform to obscure parts of markdown.pl as much as possible. Don't fix original -markdown bugs. -.TP -.BI \-\-gfm -Enable github flavored markdown. -.TP -.BI \-\-breaks -Enable GFM line breaks. Only works with the gfm option. -.TP -.BI \-\-tables -Enable GFM tables. Only works with the gfm option. -.TP -.BI \-\-sanitize -Sanitize output. Ignore any HTML input. -.TP -.BI \-\-smart\-lists -Use smarter list behavior than the original markdown. -.TP -.BI \-\-lang\-prefix\ [\fIprefix\fP] -Set the prefix for code block classes. -.TP -.BI \-\-no\-sanitize,\ \-no-etc... -The inverse of any of the marked options above. -.TP -.BI \-\-silent -Silence error output. -.TP -.BI \-h,\ \-\-help -Display help information. - -.SH CONFIGURATION -For configuring and running programmatically. - -.B Example - - require('marked')('*foo*', { gfm: true }); - -.SH BUGS -Please report any bugs to https://github.com/chjj/marked. - -.SH LICENSE -Copyright (c) 2011-2014, Christopher Jeffrey (MIT License). - -.SH "SEE ALSO" -.BR markdown(1), -.BR node.js(1) diff --git a/js/vendor/marked/marked.min.js b/js/vendor/marked/marked.min.js deleted file mode 100644 index a5164c4da9..0000000000 --- a/js/vendor/marked/marked.min.js +++ /dev/null @@ -1,6 +0,0 @@ -/** - * marked - a markdown parser - * Copyright (c) 2011-2014, Christopher Jeffrey. (MIT Licensed) - * https://github.com/chjj/marked - */ -(function(){var block={newline:/^\n+/,code:/^( {4}[^\n]+\n*)+/,fences:noop,hr:/^( *[-*_]){3,} *(?:\n+|$)/,heading:/^ *(#{1,6}) *([^\n]+?) *#* *(?:\n+|$)/,nptable:noop,lheading:/^([^\n]+)\n *(=|-){2,} *(?:\n+|$)/,blockquote:/^( *>[^\n]+(\n(?!def)[^\n]+)*\n*)+/,list:/^( *)(bull) [\s\S]+?(?:hr|def|\n{2,}(?! )(?!\1bull )\n*|\s*$)/,html:/^ *(?:comment|closed|closing) *(?:\n{2,}|\s*$)/,def:/^ *\[([^\]]+)\]: *]+)>?(?: +["(]([^\n]+)[")])? *(?:\n+|$)/,table:noop,paragraph:/^((?:[^\n]+\n?(?!hr|heading|lheading|blockquote|tag|def))+)\n*/,text:/^[^\n]+/};block.bullet=/(?:[*+-]|\d+\.)/;block.item=/^( *)(bull) [^\n]*(?:\n(?!\1bull )[^\n]*)*/;block.item=replace(block.item,"gm")(/bull/g,block.bullet)();block.list=replace(block.list)(/bull/g,block.bullet)("hr","\\n+(?=\\1?(?:[-*_] *){3,}(?:\\n+|$))")("def","\\n+(?="+block.def.source+")")();block.blockquote=replace(block.blockquote)("def",block.def)();block._tag="(?!(?:"+"a|em|strong|small|s|cite|q|dfn|abbr|data|time|code"+"|var|samp|kbd|sub|sup|i|b|u|mark|ruby|rt|rp|bdi|bdo"+"|span|br|wbr|ins|del|img)\\b)\\w+(?!:/|[^\\w\\s@]*@)\\b";block.html=replace(block.html)("comment",//)("closed",/<(tag)[\s\S]+?<\/\1>/)("closing",/])*?>/)(/tag/g,block._tag)();block.paragraph=replace(block.paragraph)("hr",block.hr)("heading",block.heading)("lheading",block.lheading)("blockquote",block.blockquote)("tag","<"+block._tag)("def",block.def)();block.normal=merge({},block);block.gfm=merge({},block.normal,{fences:/^ *(`{3,}|~{3,}) *(\S+)? *\n([\s\S]+?)\s*\1 *(?:\n+|$)/,paragraph:/^/});block.gfm.paragraph=replace(block.paragraph)("(?!","(?!"+block.gfm.fences.source.replace("\\1","\\2")+"|"+block.list.source.replace("\\1","\\3")+"|")();block.tables=merge({},block.gfm,{nptable:/^ *(\S.*\|.*)\n *([-:]+ *\|[-| :]*)\n((?:.*\|.*(?:\n|$))*)\n*/,table:/^ *\|(.+)\n *\|( *[-:]+[-| :]*)\n((?: *\|.*(?:\n|$))*)\n*/});function Lexer(options){this.tokens=[];this.tokens.links={};this.options=options||marked.defaults;this.rules=block.normal;if(this.options.gfm){if(this.options.tables){this.rules=block.tables}else{this.rules=block.gfm}}}Lexer.rules=block;Lexer.lex=function(src,options){var lexer=new Lexer(options);return lexer.lex(src)};Lexer.prototype.lex=function(src){src=src.replace(/\r\n|\r/g,"\n").replace(/\t/g," ").replace(/\u00a0/g," ").replace(/\u2424/g,"\n");return this.token(src,true)};Lexer.prototype.token=function(src,top,bq){var src=src.replace(/^ +$/gm,""),next,loose,cap,bull,b,item,space,i,l;while(src){if(cap=this.rules.newline.exec(src)){src=src.substring(cap[0].length);if(cap[0].length>1){this.tokens.push({type:"space"})}}if(cap=this.rules.code.exec(src)){src=src.substring(cap[0].length);cap=cap[0].replace(/^ {4}/gm,"");this.tokens.push({type:"code",text:!this.options.pedantic?cap.replace(/\n+$/,""):cap});continue}if(cap=this.rules.fences.exec(src)){src=src.substring(cap[0].length);this.tokens.push({type:"code",lang:cap[2],text:cap[3]});continue}if(cap=this.rules.heading.exec(src)){src=src.substring(cap[0].length);this.tokens.push({type:"heading",depth:cap[1].length,text:cap[2]});continue}if(top&&(cap=this.rules.nptable.exec(src))){src=src.substring(cap[0].length);item={type:"table",header:cap[1].replace(/^ *| *\| *$/g,"").split(/ *\| */),align:cap[2].replace(/^ *|\| *$/g,"").split(/ *\| */),cells:cap[3].replace(/\n$/,"").split("\n")};for(i=0;i ?/gm,"");this.token(cap,top,true);this.tokens.push({type:"blockquote_end"});continue}if(cap=this.rules.list.exec(src)){src=src.substring(cap[0].length);bull=cap[2];this.tokens.push({type:"list_start",ordered:bull.length>1});cap=cap[0].match(this.rules.item);next=false;l=cap.length;i=0;for(;i1&&b.length>1)){src=cap.slice(i+1).join("\n")+src;i=l-1}}loose=next||/\n\n(?!\s*$)/.test(item);if(i!==l-1){next=item.charAt(item.length-1)==="\n";if(!loose)loose=next}this.tokens.push({type:loose?"loose_item_start":"list_item_start"});this.token(item,false,bq);this.tokens.push({type:"list_item_end"})}this.tokens.push({type:"list_end"});continue}if(cap=this.rules.html.exec(src)){src=src.substring(cap[0].length);this.tokens.push({type:this.options.sanitize?"paragraph":"html",pre:cap[1]==="pre"||cap[1]==="script"||cap[1]==="style",text:cap[0]});continue}if(!bq&&top&&(cap=this.rules.def.exec(src))){src=src.substring(cap[0].length);this.tokens.links[cap[1].toLowerCase()]={href:cap[2],title:cap[3]};continue}if(top&&(cap=this.rules.table.exec(src))){src=src.substring(cap[0].length);item={type:"table",header:cap[1].replace(/^ *| *\| *$/g,"").split(/ *\| */),align:cap[2].replace(/^ *|\| *$/g,"").split(/ *\| */),cells:cap[3].replace(/(?: *\| *)?\n$/,"").split("\n")};for(i=0;i])/,autolink:/^<([^ >]+(@|:\/)[^ >]+)>/,url:noop,tag:/^|^<\/?\w+(?:"[^"]*"|'[^']*'|[^'">])*?>/,link:/^!?\[(inside)\]\(href\)/,reflink:/^!?\[(inside)\]\s*\[([^\]]*)\]/,nolink:/^!?\[((?:\[[^\]]*\]|[^\[\]])*)\]/,strong:/^__([\s\S]+?)__(?!_)|^\*\*([\s\S]+?)\*\*(?!\*)/,em:/^\b_((?:__|[\s\S])+?)_\b|^\*((?:\*\*|[\s\S])+?)\*(?!\*)/,code:/^(`+)\s*([\s\S]*?[^`])\s*\1(?!`)/,br:/^ {2,}\n(?!\s*$)/,del:noop,text:/^[\s\S]+?(?=[\\?(?:\s+['"]([\s\S]*?)['"])?\s*/;inline.link=replace(inline.link)("inside",inline._inside)("href",inline._href)();inline.reflink=replace(inline.reflink)("inside",inline._inside)();inline.normal=merge({},inline);inline.pedantic=merge({},inline.normal,{strong:/^__(?=\S)([\s\S]*?\S)__(?!_)|^\*\*(?=\S)([\s\S]*?\S)\*\*(?!\*)/,em:/^_(?=\S)([\s\S]*?\S)_(?!_)|^\*(?=\S)([\s\S]*?\S)\*(?!\*)/});inline.gfm=merge({},inline.normal,{escape:replace(inline.escape)("])","~|])")(),url:/^(https?:\/\/[^\s<]+[^<.,:;"')\]\s])/,del:/^~~(?=\S)([\s\S]*?\S)~~/,text:replace(inline.text)("]|","~]|")("|","|https?://|")()});inline.breaks=merge({},inline.gfm,{br:replace(inline.br)("{2,}","*")(),text:replace(inline.gfm.text)("{2,}","*")()});function InlineLexer(links,options){this.options=options||marked.defaults;this.links=links;this.rules=inline.normal;this.renderer=this.options.renderer||new Renderer;this.renderer.options=this.options;if(!this.links){throw new Error("Tokens array requires a `links` property.")}if(this.options.gfm){if(this.options.breaks){this.rules=inline.breaks}else{this.rules=inline.gfm}}else if(this.options.pedantic){this.rules=inline.pedantic}}InlineLexer.rules=inline;InlineLexer.output=function(src,links,options){var inline=new InlineLexer(links,options);return inline.output(src)};InlineLexer.prototype.output=function(src){var out="",link,text,href,cap;while(src){if(cap=this.rules.escape.exec(src)){src=src.substring(cap[0].length);out+=cap[1];continue}if(cap=this.rules.autolink.exec(src)){src=src.substring(cap[0].length);if(cap[2]==="@"){text=cap[1].charAt(6)===":"?this.mangle(cap[1].substring(7)):this.mangle(cap[1]);href=this.mangle("mailto:")+text}else{text=escape(cap[1]);href=text}out+=this.renderer.link(href,null,text);continue}if(!this.inLink&&(cap=this.rules.url.exec(src))){src=src.substring(cap[0].length);text=escape(cap[1]);href=text;out+=this.renderer.link(href,null,text);continue}if(cap=this.rules.tag.exec(src)){if(!this.inLink&&/^
    /i.test(cap[0])){this.inLink=false}src=src.substring(cap[0].length);out+=this.options.sanitize?escape(cap[0]):cap[0];continue}if(cap=this.rules.link.exec(src)){src=src.substring(cap[0].length);this.inLink=true;out+=this.outputLink(cap,{href:cap[2],title:cap[3]});this.inLink=false;continue}if((cap=this.rules.reflink.exec(src))||(cap=this.rules.nolink.exec(src))){src=src.substring(cap[0].length);link=(cap[2]||cap[1]).replace(/\s+/g," ");link=this.links[link.toLowerCase()];if(!link||!link.href){out+=cap[0].charAt(0);src=cap[0].substring(1)+src;continue}this.inLink=true;out+=this.outputLink(cap,link);this.inLink=false;continue}if(cap=this.rules.strong.exec(src)){src=src.substring(cap[0].length);out+=this.renderer.strong(this.output(cap[2]||cap[1]));continue}if(cap=this.rules.em.exec(src)){src=src.substring(cap[0].length);out+=this.renderer.em(this.output(cap[2]||cap[1]));continue}if(cap=this.rules.code.exec(src)){src=src.substring(cap[0].length);out+=this.renderer.codespan(escape(cap[2],true));continue}if(cap=this.rules.br.exec(src)){src=src.substring(cap[0].length);out+=this.renderer.br();continue}if(cap=this.rules.del.exec(src)){src=src.substring(cap[0].length);out+=this.renderer.del(this.output(cap[1]));continue}if(cap=this.rules.text.exec(src)){src=src.substring(cap[0].length);out+=escape(this.smartypants(cap[0]));continue}if(src){throw new Error("Infinite loop on byte: "+src.charCodeAt(0))}}return out};InlineLexer.prototype.outputLink=function(cap,link){var href=escape(link.href),title=link.title?escape(link.title):null;return cap[0].charAt(0)!=="!"?this.renderer.link(href,title,this.output(cap[1])):this.renderer.image(href,title,escape(cap[1]))};InlineLexer.prototype.smartypants=function(text){if(!this.options.smartypants)return text;return text.replace(/--/g,"—").replace(/(^|[-\u2014/(\[{"\s])'/g,"$1‘").replace(/'/g,"’").replace(/(^|[-\u2014/(\[{\u2018\s])"/g,"$1“").replace(/"/g,"”").replace(/\.{3}/g,"…")};InlineLexer.prototype.mangle=function(text){var out="",l=text.length,i=0,ch;for(;i.5){ch="x"+ch.toString(16)}out+="&#"+ch+";"}return out};function Renderer(options){this.options=options||{}}Renderer.prototype.code=function(code,lang,escaped){if(this.options.highlight){var out=this.options.highlight(code,lang);if(out!=null&&out!==code){escaped=true;code=out}}if(!lang){return"
    "+(escaped?code:escape(code,true))+"\n
    "}return'
    '+(escaped?code:escape(code,true))+"\n
    \n"};Renderer.prototype.blockquote=function(quote){return"
    \n"+quote+"
    \n"};Renderer.prototype.html=function(html){return html};Renderer.prototype.heading=function(text,level,raw){return"'+text+"\n"};Renderer.prototype.hr=function(){return this.options.xhtml?"
    \n":"
    \n"};Renderer.prototype.list=function(body,ordered){var type=ordered?"ol":"ul";return"<"+type+">\n"+body+"\n"};Renderer.prototype.listitem=function(text){return"
  • "+text+"
  • \n"};Renderer.prototype.paragraph=function(text){return"

    "+text+"

    \n"};Renderer.prototype.table=function(header,body){return"\n"+"\n"+header+"\n"+"\n"+body+"\n"+"
    \n"};Renderer.prototype.tablerow=function(content){return"\n"+content+"\n"};Renderer.prototype.tablecell=function(content,flags){var type=flags.header?"th":"td";var tag=flags.align?"<"+type+' style="text-align:'+flags.align+'">':"<"+type+">";return tag+content+"\n"};Renderer.prototype.strong=function(text){return""+text+""};Renderer.prototype.em=function(text){return""+text+""};Renderer.prototype.codespan=function(text){return""+text+""};Renderer.prototype.br=function(){return this.options.xhtml?"
    ":"
    "};Renderer.prototype.del=function(text){return""+text+""};Renderer.prototype.link=function(href,title,text){if(this.options.sanitize){try{var prot=decodeURIComponent(unescape(href)).replace(/[^\w:]/g,"").toLowerCase()}catch(e){return""}if(prot.indexOf("javascript:")===0){return""}}var out='
    ";return out};Renderer.prototype.image=function(href,title,text){var out=''+text+'":">";return out};function Parser(options){this.tokens=[];this.token=null;this.options=options||marked.defaults;this.options.renderer=this.options.renderer||new Renderer;this.renderer=this.options.renderer;this.renderer.options=this.options}Parser.parse=function(src,options,renderer){var parser=new Parser(options,renderer);return parser.parse(src)};Parser.prototype.parse=function(src){this.inline=new InlineLexer(src.links,this.options,this.renderer);this.tokens=src.reverse();var out="";while(this.next()){out+=this.tok()}return out};Parser.prototype.next=function(){return this.token=this.tokens.pop()};Parser.prototype.peek=function(){return this.tokens[this.tokens.length-1]||0};Parser.prototype.parseText=function(){var body=this.token.text;while(this.peek().type==="text"){body+="\n"+this.next().text}return this.inline.output(body)};Parser.prototype.tok=function(){switch(this.token.type){case"space":{return""}case"hr":{return this.renderer.hr()}case"heading":{return this.renderer.heading(this.inline.output(this.token.text),this.token.depth,this.token.text)}case"code":{return this.renderer.code(this.token.text,this.token.lang,this.token.escaped)}case"table":{var header="",body="",i,row,cell,flags,j;cell="";for(i=0;i/g,">").replace(/"/g,""").replace(/'/g,"'")}function unescape(html){return html.replace(/&([#\w]+);/g,function(_,n){n=n.toLowerCase();if(n==="colon")return":";if(n.charAt(0)==="#"){return n.charAt(1)==="x"?String.fromCharCode(parseInt(n.substring(2),16)):String.fromCharCode(+n.substring(1))}return""})}function replace(regex,opt){regex=regex.source;opt=opt||"";return function self(name,val){if(!name)return new RegExp(regex,opt);val=val.source||val;val=val.replace(/(^|[^\[])\^/g,"$1");regex=regex.replace(name,val);return self}}function noop(){}noop.exec=noop;function merge(obj){var i=1,target,key;for(;iAn error occured:

    "+escape(e.message+"",true)+"
    "}throw e}}marked.options=marked.setOptions=function(opt){merge(marked.defaults,opt);return marked};marked.defaults={gfm:true,tables:true,breaks:false,pedantic:false,sanitize:false,smartLists:false,silent:false,highlight:null,langPrefix:"lang-",smartypants:false,headerPrefix:"",renderer:new Renderer,xhtml:false};marked.Parser=Parser;marked.parser=Parser.parse;marked.Renderer=Renderer;marked.Lexer=Lexer;marked.lexer=Lexer.lex;marked.InlineLexer=InlineLexer;marked.inlineLexer=InlineLexer.output;marked.parse=marked;if(typeof module!=="undefined"&&typeof exports==="object"){module.exports=marked}else if(typeof define==="function"&&define.amd){define(function(){return marked})}else{this.marked=marked}}).call(function(){return this||(typeof window!=="undefined"?window:global)}()); \ No newline at end of file diff --git a/js/vendor/marked/package.json b/js/vendor/marked/package.json deleted file mode 100644 index eb1e28db57..0000000000 --- a/js/vendor/marked/package.json +++ /dev/null @@ -1,22 +0,0 @@ -{ - "name": "marked", - "description": "A markdown parser built for speed", - "author": "Christopher Jeffrey", - "version": "0.3.3", - "main": "./lib/marked.js", - "bin": "./bin/marked", - "man": "./man/marked.1", - "preferGlobal": true, - "repository": "git://github.com/chjj/marked.git", - "homepage": "https://github.com/chjj/marked", - "bugs": { "url": "http://github.com/chjj/marked/issues" }, - "license": "MIT", - "keywords": ["markdown", "markup", "html"], - "tags": ["markdown", "markup", "html"], - "devDependencies": { - "markdown": "*", - "showdown": "*", - "robotskirt": "*" - }, - "scripts": { "test": "node test", "bench": "node test --bench" } -} diff --git a/templates/part.content.php b/templates/part.content.php index 7703712a29..5b829d2395 100644 --- a/templates/part.content.php +++ b/templates/part.content.php @@ -21,7 +21,8 @@ 'thumbnail', 'vendor/modified-eventsource-polyfill/eventsource-polyfill', 'eventsource', - 'vendor/marked/marked.min', + 'vendor/commonmark/dist/commonmark.min', + 'vendor/dompurify/purify', 'vendor/bigshot/bigshot-compressed', 'slideshow', 'slideshowcontrols', diff --git a/templates/public.php b/templates/public.php index 57fb4ca989..ea7e3d57a1 100644 --- a/templates/public.php +++ b/templates/public.php @@ -21,7 +21,8 @@ 'thumbnail', 'vendor/modified-eventsource-polyfill/eventsource-polyfill', 'eventsource', - 'vendor/marked/marked.min', + 'vendor/commonmark/dist/commonmark.min', + 'vendor/dompurify/purify', 'vendor/bigshot/bigshot-compressed', 'slideshow', 'slideshowcontrols',