diff options
author | Olivier Paroz <github@oparoz.com> | 2015-09-08 04:15:15 +0300 |
---|---|---|
committer | Olivier Paroz <github@oparoz.com> | 2015-09-24 11:23:50 +0300 |
commit | e3a80971d036eb9e9b01c7d503280c106fc3dfa6 (patch) | |
tree | b3535d178cb766d64ed7c13269a78918dfce0988 /js/vendor | |
parent | 011bf95bf03a7ea75672a399f8787df5d2aea37c (diff) |
Add DOMPurify and cleanup JS libraries
Diffstat (limited to 'js/vendor')
31 files changed, 694 insertions, 14549 deletions
diff --git a/js/vendor/bigshot/bigshot-2.0.zip b/js/vendor/bigshot/bigshot-2.0.zip Binary files differdeleted file mode 100644 index fdfc0408..00000000 --- a/js/vendor/bigshot/bigshot-2.0.zip +++ /dev/null diff --git a/js/vendor/bigshot/bigshot.js b/js/vendor/bigshot/bigshot.js deleted file mode 100644 index eee39bbe..00000000 --- a/js/vendor/bigshot/bigshot.js +++ /dev/null @@ -1,9717 +0,0 @@ -/* - * Copyright 2010 - 2012 Leo Sutic <leo.sutic@gmail.com> - * - * 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. - * - * <h3>Zoomable Images</h3> - * - * <p>The two classes that are needed for zoomable images are: - * - * <ul> - * <li>{@link bigshot.Image}: The main class for making zoomable images. See the class docs - * for a tutorial. - * <li>{@link bigshot.ImageParameters}: Parameters for zoomable images. - * <li>{@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. - * </ul> - * - * For hotspots, see: - * - * <ul> - * <li>{@link bigshot.HotspotLayer} - * <li>{@link bigshot.Hotspot} - * <li>{@link bigshot.LabeledHotspot} - * <li>{@link bigshot.LinkHotspot} - * </ul> - * - * <h3>VR Panoramas</h3> - * - * <p>The two classes that are needed for zoomable VR panoramas (requires WebGL) are: - * - * <ul> - * <li>{@link bigshot.VRPanorama}: The main class for making VR panoramas. See the class docs - * for a tutorial. - * <li>{@link bigshot.VRPanoramaParameters}: Parameters for VR panoramas. - * </ul> - * - * For hotspots, see: - * - * <ul> - * <li>{@link bigshot.VRHotspot} - * <li>{@link bigshot.VRRectangleHotspot} - * <li>{@link bigshot.VRPointHotspot} - * </ul> - */ - 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 <leo.sutic@gmail.com> - * - * 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 <leo.sutic@gmail.com> - * - * 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 <code>self</code>. - * - * @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 <leo.sutic@gmail.com> - * - * 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 <a href="https://developer.mozilla.org/en/DOM/element.addEventListener">element.addEventListener</a> - * 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 <code>width</code> - * set to <code>100px</code> occupies 50 physical pixels, the function will return - * <code>0.5</code>. - * @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 <code>setTimeout</code> 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 <leo.sutic@gmail.com> - * - * 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 <code>Array</code> 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 <leo.sutic@gmail.com> - * - * 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 <code>new Date ().getTime ()</code> - * @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 <leo.sutic@gmail.com> - * - * 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 <leo.sutic@gmail.com> - * - * 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 <leo.sutic@gmail.com> - * - * 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 <leo.sutic@gmail.com> - * - * 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 <code>requestFullScreen</code> - * API - as standard or as <code>moz</code>- or <code>webkit</code>- 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 <code>onClose</code> 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 <code>requestFullScreen</code> - * 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 <leo.sutic@gmail.com> - * - * 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 <leo.sutic@gmail.com> - * - * 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 <leo.sutic@gmail.com> - * - * 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 <leo.sutic@gmail.com> - * - * 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 <leo.sutic@gmail.com> - * - * 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 <leo.sutic@gmail.com> - * - * 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 <leo.sutic@gmail.com> - * - * 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 <leo.sutic@gmail.com> - * - * 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 <leo.sutic@gmail.com> - * - * 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 <leo.sutic@gmail.com> - * - * 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 <leo.sutic@gmail.com> - * - * 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 <leo.sutic@gmail.com> - * - * 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 <leo.sutic@gmail.com> - * - * 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. - * - * <p>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 <i>Optional</i> 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 <code>null</code>, which results in an all-black image - * @type String - * @public - */ - this.emptyImage = null; - - /** - * Suffix to append to the tile filenames. Typically <code>".jpg"</code> or - * <code>".png"</code>. - * - * @default <i>Optional</i> set by MakeImagePyramid and loaded from descriptor - * @type String - */ - this.suffix = null; - - /** - * The width of the full image; in pixels. - * - * @default <i>Optional</i> set by MakeImagePyramid and loaded from descriptor - * @type int - */ - this.width = 0; - - /** - * The height of the full image; in pixels. - * - * @default <i>Optional</i> set by MakeImagePyramid and loaded from descriptor - * @type int - */ - this.height = 0; - - /** - * For {@link bigshot.Image} and {@link bigshot.SimpleImage}, the <code>div</code> - * 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 - * 2<sup>n</sup> 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/2<sup>3</sup>) of the full size. - * - * @type number - * @default <i>Optional</i> set by MakeImagePyramid and loaded from descriptor - */ - this.minZoom = 0.0; - - /** - * The maximum zoom value. Zoom values are specified as a magnification; where - * 2<sup>n</sup> 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/2<sup>3</sup>) of the full size. - * - * @type number - * @default 0.0 - */ - this.maxZoom = 0.0; - - /** - * Size of one tile in pixels. - * - * @type int - * @default <i>Optional</i> set by MakeImagePyramid and loaded from descriptor - */ - this.tileSize = 0; - - /** - * Tile overlap. Not implemented. - * - * @type int - * @default <i>Optional</i> 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 <code>tileSize * 2^n</code>. 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 <code>tileSize * 2^n</code>. 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 - * - * <ul> - * <li><b>archive</b>= The basePath is <code>"<path>/bigshot.php?file=<path-to-bigshot-archive-relative-to-bigshot.php>"</code>; - * for example; <code>"/bigshot.php?file=images/bigshot-sample.bigshot"</code>. - * <li><b>folder</b>= The basePath is <code>"<path-to-image-folder>"</code>; - * for example; <code>"/images/bigshot-sample"</code>. - * </ul> - * - * @type String - */ - this.basePath = null; - - /** - * The file system type. Used to create a filesystem instance unless - * the fileSystem field is set. Possible values are <code>"archive"</code>, - * <code>"folder"</code> or <code>"dzi"</code>. - * - * @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: - * <p style="text-align:center"><img src="../images/touch-ui.png"/></p> - * - * <p>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. - * - * <p>As before, you can drag to pan anywhere. - * - * <p>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 <leo.sutic@gmail.com> - * - * 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 <code>false</code>. - */ - 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 2<sup>maxZoom</sup>. 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 2<sup>maxZoom</sup>. - * - * @public - * @type number - */ - getMaxZoom : function () { - return this.maxZoom; - }, - - /** - * Sets the minimum zoom value. The minimum magnification (of the full-size image) - * is 2<sup>minZoom</sup>, so a minZoom of <code>-3</code> 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 2<sup>minZoom</sup>, so a minZoom of <code>-3</code> 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 <code>current</code> and - * <code>centerOfZoom</code> 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 <code>gestureend</code> 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 <code>click</code> 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 = "<span style='display:inline-box; position:relative; vertical-align:middle; font-size: 20pt; top: 10pt; color:white'>ZOOM IN</span>"; - - 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 = "<span style='position:relative; font-size: 20pt; top: -25pt; color:white'>ZOOM OUT</span>"; - - 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. - * - * <p>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<i>-ier</i>. - * @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 = "<span style='border-radius: 16px; -moz-border-radius: 16px; padding: 16px; padding-left: 32px; padding-right: 32px; background:black'>Press Esc to exit full screen mode.</span>"; - - 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 <leo.sutic@gmail.com> - * - * 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: <code>basePath</code> and <code>container</code>. - * If you intend to use the archive filesystem, you need to set the <code>fileSystemType</code> to <code>"archive"</code> - * as well. - * @see bigshot.ImageBase#dispose - * @class A tiled, zoomable image viewer. - * - * <h3 id="creating-a-wrapping-image">Creating a Wrapping Image</h3> - * - * <p>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: - * - * <p>The way to figure out the proper input size is this: - * - * <ol> - * <li><p>Decide on a tile size and call this <i>tileSize</i>.</p></li> - * <li><p>Decide on a minimum integer zoom level, and call this <i>minZoom</i>.</p></li> - * <li><p>Compute <i>tileSize * 2<sup>-minZoom</sup></i>, call this <i>S</i>.</p></li> - * <li><p>The source image size along the wrapped axis must be evenly divisible by <i>S</i>.</p></li> - * </ol> - * - * <p>An example:</p> - * - * <ol> - * <li><p>I have an image that is 23148x3242 pixels.</p></li> - * <li><p>I chose 256x256 pixel tiles: <i>tileSize = 256</i>.</p></li> - * <li><p>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 <i>minZoom</i> of -3. A <i>minZoom</i> of -2 would only let me - * zoom out to 1/4 (2<sup>-2</sup>), or an image that is 810 pixels tall. A <i>minZoom</i> of -3, however lets me - * zoom out to 1/8 (2<sup>-3</sup>), or an image that is 405 pixels tall. Thus: <i>minZoom = -3</i></p></li> - * <li><p>Computing <i>S</i> gives: <i>S = 256 * 2<sup>3</sup> = 256 * 8 = 2048</i></p></li> - * <li><p>I want it to wrap along the X axis. Therefore I may have to adjust the width, - * currently 23148 pixels.</p></li> - * <li><p>Rounding 23148 down to the nearest multiple of 2048 gives 22528. (23148 divided by 2048 is 11.3, and 11 times 2048 is 22528.)</p></li> - * <li><p>I will shrink my source image to be 22528 pixels wide before building the image pyramid, - * and I will set the <code>minZoom</code> parameter to -3 in the {@link bigshot.ImageParameters} when creating - * the image. (I will also set <code>wrapX</code> to <code>true</code>.)</p></li> - * </ol> - * - * @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 <leo.sutic@gmail.com> - * - * 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 <leo.sutic@gmail.com> - * - * 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 <leo.sutic@gmail.com> - * - * 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: <code>container</code>. - * If the <code>imgElement</code> parameter is not given, then <code>basePath</code>, <code>width</code> and <code>height</code> are also required. The - * following parameters are not supported and should be left as defaults: <code>fileSystem</code>, <code>fileSystemType</code>, - * <code>maxTextureMagnification</code> and <code>tileSize</code>. <code>wrapX</code> and <code>wrapY</code> may only be used if the imgElement is <b>not</b> - * set. - * - * @param {HTMLImageElement} [imgElement] an img element to use. The element should have <code>style.position = "absolute"</code>. - * @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 <leo.sutic@gmail.com> - * - * 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 <leo.sutic@gmail.com> - * - * 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 <leo.sutic@gmail.com> - * - * 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 <leo.sutic@gmail.com> - * - * 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 <leo.sutic@gmail.com> - * - * 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 <code>.bigshot</code> 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 <leo.sutic@gmail.com> - * - * 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 <leo.sutic@gmail.com> - * - * 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 <leo.sutic@gmail.com> - * - * 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 <leo.sutic@gmail.com> - * - * 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 <leo.sutic@gmail.com> - * - * 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 <leo.sutic@gmail.com> - * - * 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 <leo.sutic@gmail.com> - * - * 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 <leo.sutic@gmail.com> - * - * 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 <leo.sutic@gmail.com> - * - * 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 <leo.sutic@gmail.com> - * - * 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 <leo.sutic@gmail.com> - * - * 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 <leo.sutic@gmail.com> - * - * 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 <leo.sutic@gmail.com> - * - * 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 <leo.sutic@gmail.com> - * - * 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 <leo.sutic@gmail.com> - * - * 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 <leo.sutic@gmail.com> - * - * 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 <leo.sutic@gmail.com> - * - * 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 <leo.sutic@gmail.com> - * - * 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. - * - * <p>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 <i>Optional</i> 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 <code>null</code>, which results in an all-black image - * @type String - * @public - */ - this.emptyImage = null; - - /** - * Suffix to append to the tile filenames. Typically <code>".jpg"</code> or - * <code>".png"</code>. - * - * @default <i>Optional</i> set by MakeImagePyramid and loaded from descriptor - * @type String - */ - this.suffix = null; - - /** - * The width of the full image; in pixels. - * - * @default <i>Optional</i> set by MakeImagePyramid and loaded from descriptor - * @type int - */ - this.width = 0; - - /** - * The height of the full image; in pixels. - * - * @default <i>Optional</i> 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 <i>Optional</i> set by MakeImagePyramid and loaded from descriptor - */ - this.maxTesselation = -1; - - /** - * Size of one tile in pixels. - * - * @type int - * @default <i>Optional</i> set by MakeImagePyramid and loaded from descriptor - */ - this.tileSize = 0; - - /** - * Tile overlap. Not implemented. - * - * @type int - * @default <i>Optional</i> 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 - * - * <ul> - * <li><b>archive</b>= The basePath is <code>"<path>/bigshot.php?file=<path-to-bigshot-archive-relative-to-bigshot.php>"</code>; - * for example; <code>"/bigshot.php?file=images/bigshot-sample.bigshot"</code>. - * <li><b>folder</b>= The basePath is <code>"<path-to-image-folder>"</code>; - * for example; <code>"/images/bigshot-sample"</code>. - * </ul> - * - * @type String - */ - this.basePath = null; - - /** - * The file system type. Used to create a filesystem instance unless - * the fileSystem field is set. Possible values are <code>"archive"</code>, - * <code>"folder"</code> or <code>"dzi"</code>. - * - * @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 <code>TEXTURE_MAG_FILTER</code>. - * <code>null</code> means <code>NEAREST</code>. - * - * @default null / NEAREST. - */ - this.textureMagFilter = null; - - /** - * The WebGL texture filter to use for supersampling (minifying) textures. - * Possible values are all values valid for <code>TEXTURE_MIN_FILTER</code>. - * <code>null</code> means <code>NEAREST</code>. - * - * @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 <leo.sutic@gmail.com> - * - * 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. <b>Requires WebGL or CSS3D support.</b> - * (Note: See {@link bigshot.VRPanorama#dispose} for important information.) - * - * <h3 id="creating-a-cubemap">Creating a Cube Map</h3> - * - * <p>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. - * - * <p>The MakeImagePyramid has some sensible defaults built-in. If you just use the - * command line: - * - * <code><pre> - * java -jar bigshot.jar input.jpg temp/dzi \ - * --preset dzi-cubemap \ - * --format folders - * </pre></code> - * - * <p>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 <code>overlap</code>, <code>face-size</code> - * and <code>tile-size</code> parameters. Let's take these one by one: - * - * <ul> - * <li><p><code>overlap</code>: Overlap defines how much tiles should overlap, just to avoid - * seams in the rendered results caused by finite numeric precision. The default is <b>2</b>, which - * I've found works great for me.</p></li> - * <li><p><code>tile-size</code>: 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, <code>tile-size</code> - * could be 127, 255, 511, or any 2<sup>n</sup>-1 value.</p></li> - * <li><p><code>face-size</code>: Finally, we decide on a size for the full cube face. This should be - * tile-size * 2<sup>n</sup>. 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*2<sup>3</sup> = 255*8 = <b>2040</b>.</p></li> - * </ul> - * - * <p>A command line for the hypothetical scenario above would be: - * - * <code><pre> - * java -jar bigshot.jar input.jpg temp/dzi \ - * --preset dzi-cubemap \ - * --overlap 1 \ - * --tile-size 255 \ - * --face-size 2040 \ - * --format folders - * </pre></code> - * - * <p>If your tile size numbers don't add up, you'll get a warning like: - * - * <code><pre> - * WARNING: Resulting image tile size (tile-size + overlap) is not a power of two: 255 - * </pre></code> - * - * <p>If your face size don't add up, you'll get another warning: - * - * <code><pre> - * WARNING: face-size is not an even multiple of tile-size: 2040 % 254 != 0 - * </pre></code> - * - * <h3 id="integration-with-saladoplayer">Integration With SaladoPlayer</h3> - * - * <p><a href="http://panozona.com/wiki/">SaladoPlayer</a> 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. - * - * <p>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. - * - * <h4>Serving DZI as Folders</h4> - * - * <p>This is an easy one. First, we generate the required DZIs: - * - * <code><pre> - * java -jar bigshot.jar input.jpg temp/dzi \ - * --preset dzi-cubemap \ - * --format folders - * </pre></code> - * - * <p>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: - * - * <code><pre> - * bvr = new bigshot.VRPanorama ( - * new bigshot.VRPanoramaParameters ({ - * container : document.getElementById ("canvas"), - * basePath : "temp/dzi", - * fileSystemType : "dzi" - * })); - * </pre></code> - * - * <p>SaladoPlayer uses an XML config file, which in this case will - * look something like this: - * - * <code><pre> - * <SaladoPlayer> - * <global debug="false" firstPanorama="pano"/> - * <panoramas> - * <panorama id="pano" path="temp/dzi/face_f.xml"/> - * </panoramas> - * </SaladoPlayer> - * </pre></code> - * - * <h4>Serving DZI as Archive</h4> - * - * <p>This one is a bit more difficult. First we create a DZI as a bigshot archive: - * - * <code><pre> - * java -jar bigshot.jar input.jpg temp/dzi.bigshot \ - * --preset dzi-cubemap \ - * --format archive - * </pre></code> - * - * <p>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: - * - * <code><pre> - * bvr = new bigshot.VRPanorama ( - * new bigshot.VRPanoramaParameters ({ - * container : document.getElementById ("canvas"), - * basePath : "/bigshot.php?file=temp/dzi.bigshot&entry=", - * fileSystemType : "dzi" - * })); - * </pre></code> - * - * <p>SaladoPlayer uses an XML config file, which in this case will - * look something like this: - * - * <code><pre> - * <SaladoPlayer> - * <global debug="false" firstPanorama="pano"/> - * <panoramas> - * <panorama id="pano" path="/bigshot.php?file=dzi.bigshot&amp;entry=face_f.xml"/> - * </panoramas> - * </SaladoPlayer> - * </pre></code> - * - * <h3>Usage example:</h3> - * @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. - * - * <p>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<i>-ier</i>. - * - * @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 = "<span style='border-radius: 16px; -moz-border-radius: 16px; padding: 16px; padding-left: 32px; padding-right: 32px; background:black'>Press Esc to exit full screen mode.</span>"; - - 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 <code>null</code> - * 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 <leo.sutic@gmail.com> - * - * 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 <code>frac</code> 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 <leo.sutic@gmail.com> - * - * 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 <code>style.top</code> and <code>style.left</code> - * 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 <leo.sutic@gmail.com> - * - * 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 <code>style.top</code> and <code>style.left</code> - * values, and resized by setting its <code>style.width</code> and <code>style.height</code> - * 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 <leo.sutic@gmail.com> - * - * 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 <i>1 / targetFps</i> 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 - * <i>target frame render time * (1.0 + tolerance)</i> or falls below - * <i>target frame render time / (1.0 + tolerance)</i>. - * - * @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 <leo.sutic@gmail.com> - * - * 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}. - * - * <p>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/dompurify/purify.js b/js/vendor/dompurify/purify.js new file mode 100644 index 00000000..552eaafe --- /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 <html>... 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(/</g, '<'); + } + + /* Execute a hook if present */ + _executeHook('afterSanitizeElements', currentNode, null); + + return false; + }; + + /** + * _sanitizeAttributes + * + * @protect attributes + * @protect nodeName + * @protect removeAttribute + * @protect setAttribute + * + * @param node to sanitize + * @return void + */ + var _sanitizeAttributes = function(currentNode) { + /* Execute a hook if present */ + _executeHook('beforeSanitizeAttributes', currentNode, null); + + var attributes = currentNode.attributes; + + /* Check if we have attributes; if not we might have a text node */ + if (!attributes) { return; } + + var hookEvent = { + attrName: '', + attrValue: '', + keepAttr: true + }, + l = attributes.length, + attr, name, value, lcName, idAttr; + + /* Go backwards over all attributes; safely remove bad ones */ + while (l--) { + attr = attributes[l]; + name = attr.name; + value = attr.value; + lcName = name.toLowerCase(); + + /* Execute a hook if present */ + hookEvent.attrName = lcName; + hookEvent.attrValue = value; + hookEvent.keepAttr = true; + _executeHook('uponSanitizeAttribute', currentNode, hookEvent ); + value = hookEvent.attrValue; + + /* Remove attribute */ + // Safari (iOS + Mac), last tested v8.0.5, crashes if you try to + // remove a "name" attribute from an <img> 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 86a5d3d5..00000000 --- a/js/vendor/eventsource-polyfill/.bower.json +++ /dev/null @@ -1,43 +0,0 @@ -{ - "name": "eventsource-polyfill", - "homepage": "https://github.com/amvtek/EventSource", - "authors": [ - "amvtek <devel@amvtek.com>" - ], - "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 62758d3f..00000000 --- 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 c949243e..00000000 --- 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 d2722f92..00000000 --- a/js/vendor/eventsource-polyfill/bower.json +++ /dev/null @@ -1,29 +0,0 @@ -{ - "name": "eventsource-polyfill", - "homepage": "https://github.com/amvtek/EventSource", - "authors": [ - "amvtek <devel@amvtek.com>" - ], - "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 76b9b4ad..00000000 --- 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 d3b563b3..00000000 --- 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 3e79de63..00000000 --- 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<i.length-1;c++){for(e="message",f=[],parts=i[c].split("\n"),d=0;d<parts.length;d++)g=this.trimWhiteSpace(parts[d]),0==g.indexOf("event")?e=g.replace(/event:?\s*/,""):0==g.indexOf("retry")?(h=parseInt(g.replace(/retry:?\s*/,"")),isNaN(h)||(this.interval=h)):0==g.indexOf("data")?f.push(g.replace(/data:?\s*/,"")):0==g.indexOf("id:")?this.lastEventId=g.replace(/id:?\s*/,""):0==g.indexOf("id")&&(this.lastEventId=null);if(f.length){var j=new b(e,f.join("\n"),window.location.origin,this.lastEventId);this.dispatchEvent(e,j)}}this.cache=i[i.length-1]},dispatchEvent:function(a,b){var c=this["_"+a+"Handlers"];if(c)for(var d=0;d<c.length;d++)c[d].call(this,b);this["on"+a]&&this["on"+a].call(this,b)},addEventListener:function(a,b){this["_"+a+"Handlers"]||(this["_"+a+"Handlers"]=[]),this["_"+a+"Handlers"].push(b)},removeEventListener:function(a,b){var c=this["_"+a+"Handlers"];if(c)for(var d=c.length-1;d>=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 bff2cb88..00000000 --- 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 6b164322..00000000 --- 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 5d9445ce..00000000 --- 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 654d0bfe..00000000 --- a/js/vendor/github-markdown-css/license +++ /dev/null @@ -1,21 +0,0 @@ -The MIT License (MIT) - -Copyright (c) Sindre Sorhus <sindresorhus@gmail.com> (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 a58fe348..00000000 --- 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 - -[<img src="https://cloud.githubusercontent.com/assets/170270/5219062/f22a978c-7685-11e4-8316-af25b6c89bc0.png" width="300">](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 -<link rel="stylesheet" href="github-markdown.css"> -<style> - .markdown-body { - min-width: 200px; - max-width: 790px; - margin: 0 auto; - padding: 30px; - } -</style> -<article class="markdown-body"> - <h1>Unicorns</h1> - <p>All the things</p> -</article> -``` - - -## 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 b3908ae8..00000000 --- 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 304ab691..00000000 --- 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 : - - <script src="jquery.js" type="text/javascript"></script> - <script src="image-scale.js" type="text/javascript"></script> - ------- - -## 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. - - <div class="image-container"> - <img class="scale" data-scale="best-fit-down" data-align="center" src="img/example.jpg"> - </div> - -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 3934d35c..00000000 --- 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 dc9c1bb0..00000000 --- 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 <chjjeffrey@gmail.com>" - ], - "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 a7b812ed..00000000 --- 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 d9349f07..00000000 --- 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 b9817cd4..00000000 --- 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: <p>I am using <strong>markdown</strong>.</p> -``` - -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 -<!doctype html> -<html> -<head> - <meta charset="utf-8"/> - <title>Marked in the browser</title> - <script src="lib/marked.js"></script> -</head> -<body> - <div id="content"></div> - <script> - document.getElementById('content').innerHTML = - marked('# Marked in browser\n\nRendered by **marked**.'); - </script> -</body> -</html> -``` - -## 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 '<h' + level + '><a name="' + - escapedText + - '" class="anchor" href="#' + - escapedText + - '"><span class="header-link"></span></a>' + - text + '</h' + level + '>'; -}, - -console.log(marked('# heading+', { renderer: renderer })); -``` -This code will output the following HTML: -```html -<h1> - <a name="heading-" class="anchor" href="#heading-"> - <span class="header-link"></span> - </a> - heading+ -</h1> -``` - -#### 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 -<p>hello world</p> -``` - -## 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. `</legalese>` - -## 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 64254fc3..00000000 --- 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 3eab3110..00000000 --- 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 <chjjeffrey@gmail.com>" - ], - "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 931cbedc..00000000 --- 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 7bfa49e8..00000000 --- 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 -<ul> -<li><p>item1</p> - -<ul> -<li>item2</li> -</ul> - -<p><p>text</p></li> -</ul></p> -``` - - -``` -$ marked - * item1 - - * item2 - - text -^D -<ul> -<li><p>item1</p> -<ul> -<li>item2</li> -</ul> -<p>text</p> -</li> -</ul> -``` - -Which looks correct to you? - -- - - - -``` -$ markdown.pl -* hello - > world -^D -<p><ul> -<li>hello</p> - -<blockquote> - <p>world</li> -</ul></p> -</blockquote> -``` - -``` -$ marked -* hello - > world -^D -<ul> -<li>hello<blockquote> -<p>world</p> -</blockquote> -</li> -</ul> -``` - -Again, which looks correct to you? - -- - - - -EXAMPLE: - -``` -$ markdown.pl -* hello - * world - * hi - code -^D -<ul> -<li>hello -<ul> -<li>world</li> -<li>hi - code</li> -</ul></li> -</ul> -``` - -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 -<ul> -<li>hello -<ul> -<li>world</li> -<li>hi - code</li> -</ul></li> -</ul> -``` - -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 -<ul> -<li><p>item1</p> - -<ul> -<li>item2</li> -</ul> - -<p><p>text</p></li> -</ul></p> -``` - -Misnested tags. - - -``` -$ marked - * item1 - - * item2 - - text -^D -<ul> -<li><p>item1</p> -<ul> -<li>item2</li> -</ul> -<p>text</p> -</li> -</ul> -``` - -Which looks correct to you? - -- - - - -``` -$ markdown.pl -* hello - > world -^D -<p><ul> -<li>hello</p> - -<blockquote> - <p>world</li> -</ul></p> -</blockquote> -``` - -More misnested tags. - - -``` -$ marked -* hello - > world -^D -<ul> -<li>hello<blockquote> -<p>world</p> -</blockquote> -</li> -</ul> -``` - -Again, which looks correct to you? - -- - - - -# Why quality matters - Part 2 - -``` bash -$ markdown.pl -* hello - > world -^D -<p><ul> -<li>hello</p> - -<blockquote> - <p>world</li> -</ul></p> -</blockquote> -``` - -``` bash -$ sundown # upskirt -* hello - > world -^D -<ul> -<li>hello -> world</li> -</ul> -``` - -``` bash -$ marked -* hello - > world -^D -<ul><li>hello <blockquote><p>world</p></blockquote></li></ul> -``` - -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 -<ul> -<li>hello -var a = 1;</li> -<li>world</li> -</ul> -``` - -``` bash -$ marked -* hello - var a = 1; -* world -^D -<ul><li>hello -<pre>code>var a = 1;</code></pre></li> -<li>world</li></ul> -``` - -Which looks more reasonable? Why shouldn't code blocks be able to appear in -list items in a sane way? - -- - - - -``` bash -$ markdown.js -<div>hello</div> - -<span>hello</span> -^D -<p><div>hello</div></p> - -<p><span>hello</span></p> -``` - -``` bash -$ marked -<div>hello</div> - -<span>hello</span> -^D -<div>hello</div> - - -<p><span>hello</span> -</p> -``` - -- - - - -See: https://github.com/evilstreak/markdown-js/issues/27 - -``` bash -$ markdown.js -[![an image](/image)](/link) -^D -<p><a href="/image)](/link">![an image</a></p> -``` - -``` bash -$ marked -[![an image](/image)](/link) -^D -<p><a href="/link"><img src="/image" alt="an image"></a> -</p> -``` - -- - - - -See: https://github.com/evilstreak/markdown-js/issues/24 - -``` bash -$ markdown.js -> a - -> b - -> c -^D -<blockquote><p>a</p><p>bundefined> c</p></blockquote> -``` - -``` bash -$ marked -> a - -> b - -> c -^D -<blockquote><p>a - -</p></blockquote> -<blockquote><p>b - -</p></blockquote> -<blockquote><p>c -</p></blockquote> -``` - -- - - - -``` bash -$ markdown.pl -* hello - * world - how - - are - you - - * today -* hi -^D -<ul> -<li><p>hello</p> - -<ul> -<li>world -how</li> -</ul> - -<p>are -you</p> - -<ul> -<li>today</li> -</ul></li> -<li>hi</li> -</ul> -``` - -``` bash -$ marked -* hello - * world - how - - are - you - - * today -* hi -^D -<ul> -<li><p>hello</p> -<ul> -<li><p>world -how</p> -<p>are -you</p> -</li> -<li><p>today</p> -</li> -</ul> -</li> -<li>hi</li> -</ul> -``` diff --git a/js/vendor/marked/doc/todo.md b/js/vendor/marked/doc/todo.md deleted file mode 100644 index 2e60b162..00000000 --- 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 a12f9056..00000000 --- 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 0b7180ff..00000000 --- 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: /^ *\[([^\]]+)\]: *<?([^\s>]+)>?(?: +["(]([^\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', /<!--[\s\S]*?-->/) - ('closed', /<(tag)[\s\S]+?<\/\1>/) - ('closing', /<tag(?:"[^"]*"|'[^']*'|[^'">])*?>/) - (/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: /^<!--[\s\S]*?-->|^<\/?\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]+?(?=[\\<!\[_*`]| {2,}\n|$)/ -}; - -inline._inside = /(?:\[[^\]]*\]|[^\[\]]|\](?=[^\[]*\]))*/; -inline._href = /\s*<?([\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 && /^<a /i.test(cap[0])) { - this.inLink = true; - } else if (this.inLink && /^<\/a>/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 '<pre><code>' - + (escaped ? code : escape(code, true)) - + '\n</code></pre>'; - } - - return '<pre><code class="' - + this.options.langPrefix - + escape(lang, true) - + '">' - + (escaped ? code : escape(code, true)) - + '\n</code></pre>\n'; -}; - -Renderer.prototype.blockquote = function(quote) { - return '<blockquote>\n' + quote + '</blockquote>\n'; -}; - -Renderer.prototype.html = function(html) { - return html; -}; - -Renderer.prototype.heading = function(text, level, raw) { - return '<h' - + level - + ' id="' - + this.options.headerPrefix - + raw.toLowerCase().replace(/[^\w]+/g, '-') - + '">' - + text - + '</h' - + level - + '>\n'; -}; - -Renderer.prototype.hr = function() { - return this.options.xhtml ? '<hr/>\n' : '<hr>\n'; -}; - -Renderer.prototype.list = function(body, ordered) { - var type = ordered ? 'ol' : 'ul'; - return '<' + type + '>\n' + body + '</' + type + '>\n'; -}; - -Renderer.prototype.listitem = function(text) { - return '<li>' + text + '</li>\n'; -}; - -Renderer.prototype.paragraph = function(text) { - return '<p>' + text + '</p>\n'; -}; - -Renderer.prototype.table = function(header, body) { - return '<table>\n' - + '<thead>\n' - + header - + '</thead>\n' - + '<tbody>\n' - + body - + '</tbody>\n' - + '</table>\n'; -}; - -Renderer.prototype.tablerow = function(content) { - return '<tr>\n' + content + '</tr>\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 + '</' + type + '>\n'; -}; - -// span level renderer -Renderer.prototype.strong = function(text) { - return '<strong>' + text + '</strong>'; -}; - -Renderer.prototype.em = function(text) { - return '<em>' + text + '</em>'; -}; - -Renderer.prototype.codespan = function(text) { - return '<code>' + text + '</code>'; -}; - -Renderer.prototype.br = function() { - return this.options.xhtml ? '<br/>' : '<br>'; -}; - -Renderer.prototype.del = function(text) { - return '<del>' + text + '</del>'; -}; - -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 = '<a href="' + href + '"'; - if (title) { - out += ' title="' + title + '"'; - } - out += '>' + text + '</a>'; - return out; -}; - -Renderer.prototype.image = function(href, title, text) { - var out = '<img src="' + href + '" alt="' + text + '"'; - if (title) { - out += ' title="' + title + '"'; - } - out += this.options.xhtml ? '/>' : '>'; - 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, '"') - .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 '<p>An error occured:</p><pre>' - + escape(e.message + '', true) - + '</pre>'; - } - 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 f89f1a7b..00000000 --- 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<output>\fP] [\-i \fI<input>\fP] [\-\-help] -[\-\-tokens] [\-\-pedantic] [\-\-gfm] -[\-\-breaks] [\-\-tables] [\-\-sanitize] -[\-\-smart\-lists] [\-\-lang\-prefix \fI<prefix>\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/package.json b/js/vendor/marked/package.json deleted file mode 100644 index eb1e28db..00000000 --- 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" } -} |