[med-svn] r18890 - in trunk/packages/orthanc-webviewer/trunk/debian: . JS JS/cornerstone-0.7.1 JS/js-url-1.8.6 JS/jsPanel-2.3.3 JS/jsPanel-2.3.3/fonts JS/jsPanel-2.3.3/images JS/pako-0.2.5 patches source
Sebastien Jodogne
jodogne-guest at moszumanska.debian.org
Mon Mar 2 09:59:00 UTC 2015
Author: jodogne-guest
Date: 2015-03-02 09:58:59 +0000 (Mon, 02 Mar 2015)
New Revision: 18890
Added:
trunk/packages/orthanc-webviewer/trunk/debian/JS/
trunk/packages/orthanc-webviewer/trunk/debian/JS/README
trunk/packages/orthanc-webviewer/trunk/debian/JS/cornerstone-0.7.1/
trunk/packages/orthanc-webviewer/trunk/debian/JS/cornerstone-0.7.1/LICENSE
trunk/packages/orthanc-webviewer/trunk/debian/JS/cornerstone-0.7.1/README.md
trunk/packages/orthanc-webviewer/trunk/debian/JS/cornerstone-0.7.1/cornerstone.css
trunk/packages/orthanc-webviewer/trunk/debian/JS/cornerstone-0.7.1/cornerstone.js
trunk/packages/orthanc-webviewer/trunk/debian/JS/js-url-1.8.6/
trunk/packages/orthanc-webviewer/trunk/debian/JS/js-url-1.8.6/README.md
trunk/packages/orthanc-webviewer/trunk/debian/JS/js-url-1.8.6/url.jquery.json
trunk/packages/orthanc-webviewer/trunk/debian/JS/js-url-1.8.6/url.js
trunk/packages/orthanc-webviewer/trunk/debian/JS/jsPanel-2.3.3/
trunk/packages/orthanc-webviewer/trunk/debian/JS/jsPanel-2.3.3/LICENSE.TXT
trunk/packages/orthanc-webviewer/trunk/debian/JS/jsPanel-2.3.3/fonts/
trunk/packages/orthanc-webviewer/trunk/debian/JS/jsPanel-2.3.3/fonts/jsglyph.eot
trunk/packages/orthanc-webviewer/trunk/debian/JS/jsPanel-2.3.3/fonts/jsglyph.svg
trunk/packages/orthanc-webviewer/trunk/debian/JS/jsPanel-2.3.3/fonts/jsglyph.ttf
trunk/packages/orthanc-webviewer/trunk/debian/JS/jsPanel-2.3.3/fonts/jsglyph.woff
trunk/packages/orthanc-webviewer/trunk/debian/JS/jsPanel-2.3.3/fonts/jsglyph.woff2
trunk/packages/orthanc-webviewer/trunk/debian/JS/jsPanel-2.3.3/images/
trunk/packages/orthanc-webviewer/trunk/debian/JS/jsPanel-2.3.3/images/close-20-333.png
trunk/packages/orthanc-webviewer/trunk/debian/JS/jsPanel-2.3.3/images/close-20.png
trunk/packages/orthanc-webviewer/trunk/debian/JS/jsPanel-2.3.3/images/icon-sprite-16x16.jpg
trunk/packages/orthanc-webviewer/trunk/debian/JS/jsPanel-2.3.3/images/icon-sprite-20x20.jpg
trunk/packages/orthanc-webviewer/trunk/debian/JS/jsPanel-2.3.3/images/icon-sprite-32x32.jpg
trunk/packages/orthanc-webviewer/trunk/debian/JS/jsPanel-2.3.3/images/resize-handle.png
trunk/packages/orthanc-webviewer/trunk/debian/JS/jsPanel-2.3.3/images/ui-icons_454545_256x240.png
trunk/packages/orthanc-webviewer/trunk/debian/JS/jsPanel-2.3.3/jquery.jspanel.css
trunk/packages/orthanc-webviewer/trunk/debian/JS/jsPanel-2.3.3/jquery.jspanel.js
trunk/packages/orthanc-webviewer/trunk/debian/JS/jsPanel-2.3.3/jquery.ui.touch-punch.js
trunk/packages/orthanc-webviewer/trunk/debian/JS/jsPanel-2.3.3/jsglyph.css
trunk/packages/orthanc-webviewer/trunk/debian/JS/jsPanel-2.3.3/mobile-detect.js
trunk/packages/orthanc-webviewer/trunk/debian/JS/pako-0.2.5/
trunk/packages/orthanc-webviewer/trunk/debian/JS/pako-0.2.5/HISTORY.md
trunk/packages/orthanc-webviewer/trunk/debian/JS/pako-0.2.5/LICENSE
trunk/packages/orthanc-webviewer/trunk/debian/JS/pako-0.2.5/README.md
trunk/packages/orthanc-webviewer/trunk/debian/JS/pako-0.2.5/pako_inflate.js
trunk/packages/orthanc-webviewer/trunk/debian/patches/javascript-libs
Removed:
trunk/packages/orthanc-webviewer/trunk/debian/ThirdPartyDownloads/
trunk/packages/orthanc-webviewer/trunk/debian/patches/debian-jquery-ui
Modified:
trunk/packages/orthanc-webviewer/trunk/debian/control
trunk/packages/orthanc-webviewer/trunk/debian/patches/series
trunk/packages/orthanc-webviewer/trunk/debian/rules
trunk/packages/orthanc-webviewer/trunk/debian/source/include-binaries
Log:
Ship only the sources of the JavaScript libs instead of whole ZIP archives
Added: trunk/packages/orthanc-webviewer/trunk/debian/JS/README
===================================================================
--- trunk/packages/orthanc-webviewer/trunk/debian/JS/README (rev 0)
+++ trunk/packages/orthanc-webviewer/trunk/debian/JS/README 2015-03-02 09:58:59 UTC (rev 18890)
@@ -0,0 +1,13 @@
+Source of the JavaScript libraries that are required for Orthanc Web Viewer:
+
+* Cornerstone by Chris Hafey (MIT license):
+ https://github.com/chafey/cornerstone
+
+* jsPanel by Stefan Sträßer (MIT license):
+ http://jspanel.de/
+
+* js-url by Websanova (MIT license):
+ https://github.com/websanova/js-url
+
+* pako by Andrey Tupitsin and Vitaly Puzrin (MIT license):
+ https://github.com/nodeca/pako
Added: trunk/packages/orthanc-webviewer/trunk/debian/JS/cornerstone-0.7.1/LICENSE
===================================================================
--- trunk/packages/orthanc-webviewer/trunk/debian/JS/cornerstone-0.7.1/LICENSE (rev 0)
+++ trunk/packages/orthanc-webviewer/trunk/debian/JS/cornerstone-0.7.1/LICENSE 2015-03-02 09:58:59 UTC (rev 18890)
@@ -0,0 +1,21 @@
+The MIT License (MIT)
+
+Copyright (c) 2014 Chris Hafey (chafey at gmail.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.
\ No newline at end of file
Added: trunk/packages/orthanc-webviewer/trunk/debian/JS/cornerstone-0.7.1/README.md
===================================================================
--- trunk/packages/orthanc-webviewer/trunk/debian/JS/cornerstone-0.7.1/README.md (rev 0)
+++ trunk/packages/orthanc-webviewer/trunk/debian/JS/cornerstone-0.7.1/README.md 2015-03-02 09:58:59 UTC (rev 18890)
@@ -0,0 +1,252 @@
+Cornerstone Core
+================
+
+Cornerstone is an open source project with a goal to deliver a complete web based medical imaging platform. This
+repository contains the Cornerstone Core component which is a lightweight JavaScript library for displaying
+medical images in modern web browsers that support the HTML5 canvas element.
+Cornerstone Core is not meant to be a complete application itself, but instead a component
+that can be used as part of larger more complex applications. See the
+[CornerstoneDemo](http://chafey.github.io/cornerstoneDemo/) for an example of using the various Cornerstone
+libraries to build a simple study viewer.
+
+Cornerstone Core is agnostic to the actual container used to store image pixels as well as the transport mechanism
+used to get the image data. In fact, Cornerstone Core itself has no ability to read/parse or load images and instead
+depends on one or more [ImageLoaders](https://github.com/chafey/cornerstone/wiki/ImageLoader) to function.
+The goal here is to avoid constraining developers to work within a single container and transport (e.g. DICOM) since
+images are stored in a variety of formats (including proprietary). By providing flexibility with respect to the
+container and transport, the highest performance image display may be obtained as no conversion to an alternate
+container or transport is required. It is hoped that developers feel empowered to load images from any type of image
+container using any kind of transport. See the
+[CornerstoneWADOImageLoader](https://github.com/chafey/cornerstoneWADOImageLoader) project for an example
+of a DICOM WADO based Image Loader.
+
+Cornerstone Core is agnostic to the exact interaction paradigm being used. It does not include any mouse, touch or
+keyboard bindings to manipulate the various image properties such as scale, translation or ww/wc. The goal here
+is to avoid constraining developers using this library to fit into a given ui paradigm. It is hoped that developers
+are empowered to create new paradigms possibly using new input mechanisms to interact with medical images (e.g.
+[Kinect](http://en.wikipedia.org/wiki/Kinect) or [Accelerometer](http://en.wikipedia.org/wiki/Accelerometer).
+Cornerstone does provide a set of API's allowing manipulation of the image properties via javascript.
+See the [CornerstoneTools](https://github.com/chafey/cornerstoneTools) library for an example of common tools built on top of
+Cornerstone.
+
+Community
+---------
+
+Have questions? Try posting on our [google groups forum](https://groups.google.com/forum/#!forum/cornerstone-platform).
+
+Live Examples
+---------------
+The best way to see the power of this library is to actually see it in use.
+
+[Click here for a list of examples of using the Cornerstone library.](https://rawgit.com/chafey/cornerstone/master/example/index.html)
+
+Install
+-------
+
+Get a packaged source file:
+
+* [cornerstone.js](https://raw.githubusercontent.com/chafey/cornerstone/master/dist/cornerstone.js)
+* [cornerstone.min.js](https://raw.githubusercontent.com/chafey/cornerstone/master/dist/cornerstone.min.js)
+
+Or install via [Bower](http://bower.io/):
+
+> bower install cornerstone
+
+
+Key Features
+------------
+
+ * HTML5/Javascript based library to easily add interactive medical images to web applications
+ * Serves as a foundation to build more complex medical imaging applications from - enterprise viewer, report viewer, etc.
+ * Supports all HTML5 based browsers including mobile, tablet and desktop
+ * Displays all common medical image formats (e.g. 8 bit grayscale, 16 bit grayscale, RGB color)
+ * High performance image display
+ * Retrieval of images from different systems with different protocols via Image Loader plugin design
+ * API support for changing viewport properties (e.g. ww/wc, zoom, pan, invert)
+
+Build System
+============
+
+This project uses grunt to build the software.
+
+Pre-requisites:
+---------------
+
+NodeJs - [click to visit web site for installation instructions](http://nodejs.org).
+
+grunt-cli
+
+> npm install -g grunt-cli
+
+bower
+
+> npm install -g bower
+
+Common Tasks
+------------
+
+Update dependencies (after each pull):
+> npm install
+
+> bower install
+
+Running the build:
+> grunt
+
+Automatically running the build and unit tests after each source change:
+> grunt watch
+
+Links
+=====
+
+[View the wiki for documentation on the concepts and APIs](https://github.com/chafey/cornerstone/wiki)
+
+[View Roadmap](docs/roadmap.md)
+
+[View Backlog](docs/backlog.md)
+
+[comp.protocols.dicom thread](https://groups.google.com/forum/#!topic/comp.protocols.dicom/_2fMh69GdAM)
+
+[Trello](https://trello.com/b/tGTDIyt4/cornerstone)
+
+[CornerstoneTools](https://github.com/chafey/cornerstoneTools) - A library of common tools that can be used with Cornerstone
+
+[CornerstoneWADOImageLoader ](https://github.com/chafey/cornerstoneWADOImageLoader) - A Cornerstone Image Loader that works with WADO
+
+[dicomParser ](https://github.com/chafey/dicomParser) - A JavaScript library designed to parse DICOM for web browsers
+
+Code Contributors
+=================
+
+I welcome pull requests, please see FAQ below for guidance on this.
+
+* @simonmd - CSS improvements in the cornerstoneDemo application
+* @doncharkowsky - The angle tool in cornerstoneTools
+* @prasath-rasterimages - Touch event bindings in cornerstoneTools
+* @jpamburn - Performance optimizations for signed data, fixes for image caching
+* @jmhmd - for getPixels() implementation
+* @devishree-raster - for flip and rotate implementation
+
+FAQ
+===
+
+_Why did you decide to license this library using the open source MIT license?_
+
+The main reason this library is released as [open source](http://en.wikipedia.org/wiki/Open_source) is
+that I believe that medical imaging in particular can do a lot more to improve patient outcomes
+but the cost of doing so is prohibitive. Making this library open source removes the cost barrier and will
+hopefully usher in a new set of medical imaging based applications.
+
+The old adage [a picture is worth a thousand words](http://en.wikipedia.org/wiki/A_picture_is_worth_a_thousand_words)
+is very true in medical imaging. When a patient is going through a disease process, they often face fear
+and confusion. Medical terminology amplifies these issues as it is hard to understand and therefore
+disempowering. Medical imaging allows a mysterious health issue to be visualized and therefore brings a
+level of understanding that just can't be accomplished via textual information found in lab or radiology
+reports. By helping a patient (and its supporting friends/family) connect with the disease visually through
+images, it is believed that fear, anxiety and confusion will all be reduced which
+will increase optimism and therefore patient outcomes.
+
+It is my hope that this library be used to build a variety of applications and experiences
+to deliver on this vision. The MIT license allows this library to be used in any type of application - personal,
+open source and commercial and is therefore appropriate to support this vision. If you are reading this,
+I hope you can join me in this mission as there is still a lot to be done.
+
+_Why doesn't Cornerstone natively support the display of DICOM images?_
+
+While DICOM has support for just about every type of medical image, there are many cases where medical images
+are not stored in DICOM format. In many cases, a PACS may receive DICOM images but store them in a proprietary
+format on disk. In this case, it can be faster to access images by having an image loader that works with
+a proprietary PACS interface that would not require conversion from the proprietary format into a standard format
+like DICOM. Another example of this is is dermatology where images are often taken using standard
+digital cameras and are stored as JPEG not DICOM.
+
+The main reason this library is not based around DICOM is that it wants to reach the widest possible adoption
+and that will be accomplished by supporting as many types of image containers and transports possible.
+Another side effect of this approach is that the code base is smaller and easier to understand since
+it is focused on doing exactly one thing. That being said, it is is expected that the majority of images
+displayed using this library will have originated as DICOM images. It is therefore important to make sure
+that there are no limitations with respect to displaying the different types of DICOM images and have robust
+supporting libraries for DICOM. Separate libraries to add DICOM specific support already exist, check out the
+[CornerstoneWADOImageLoader](https://github.com/chafey/cornerstoneWADOImageLoader) library and
+the (dicomParser)[https://github.com/chafey/dicomParser] library.
+
+_Why doesn't Cornerstone include basic tools like ww/wc using the mouse?_
+
+There is no standard for user interaction in medical imaging and a wide variety of interaction paradigms exist.
+For example, one medical imaging application may use the left mouse button to adjust ww/wc and another may use the
+right mouse button. The main reason this library does not include tools is that it wants to reach the widest possible
+adoption and that will only be accomplished by making any interaction paradigm possible. No tools
+are therefore provided with this library allowing users of the library to choose
+whatever interaction paradigm they like. It is also hoped that this approach will make it easier for developers
+to experiment with new user input mechanisms like [Kinect](http://en.wikipedia.org/wiki/Kinect) or
+[Accelerometer](http://en.wikipedia.org/wiki/Accelerometer). Another side effect of this
+approach is that the code base is smaller and easier to understand since it is focused on doing exactly one
+thing. Tools are provided using the separate [CornerstoneTools](https://github.com/chafey/cornerstoneTools)
+if desired.
+
+_Why does this library require HTML5 canvas when IE8 is the main browser used in healthcare?_
+
+The fact that IE8 is the most popular commonly used web browser in healthcare right now is a temporary
+situation. It is expected that 50% of the industry will have HTML5 based web browsers deployed by the end
+of 2015 and 90% by 2017. The library made a tradeoff to focus on the future platform to keep the code base
+simple and avoid compromises related to older browser technology. Note that it may be possible to get
+this library to work on IE8 using [excanvas](https://code.google.com/p/explorercanvas/) but I haven't tried
+it yet.
+
+_Why doesn't this library support stacks of images?_
+
+Images stack functionality such as a CT series or MRI series can actually be quite complex. Regardless of
+what stack functionality is desired, all stacks ultimately need to be able to display a single image and that
+is what this library is focused on doing. Stack functionality is therefore pushed up to a higher layer. The
+[CornerstoneTools](https://github.com/chafey/cornerstoneTools) contains stack functionality and is a good place
+to look to see how various stack related functionality is implemented.
+
+_How do you envision this library supporting 3D functionality such as MPR, MIP and VR?_
+
+This library would be responsible for displaying the rendered image to the user. The rendering of the
+3D image would be done by some other library - perhaps on the server side. This library is purely 2D and has
+no knowledge of 3D image space. It will probably make sense to have several layers on top of this library
+to provide 3D functionality. For example, one layer that has a 3D viewport with properties such as transformation
+matrix, slice thickness, transfer function/LUT, segmentation masks, etc. And another 3D tools layer that provides
+various tools on top of the 3d viewport (rotate, zoom, segment, scroll, etc). I do have a working 3D server that
+is integrated with cornerstone but am keeping the code closed for now (this may change in the future - TBD).
+
+_Why did you add jQuery as a dependency?_
+
+Primarily for its custom event handling.
+
+_I would like to contribute code - how do I do this?_
+
+Fork the repository, make your change and submit a pull request.
+
+_Any guidance on submitting changes?_
+
+While I do appreciate code contributions, I will not merge it unless it meets the following criteria:
+
+* Functionality is appropriate for the repository. Consider posting on the forum if you are not sure
+* Code quality is acceptable. I don't have coding standards defined, but make sure it passes jshint and looks like
+ the rest of the code in the repository.
+* Quality of design is acceptable. This is a bit subjective so you should consider posting on the forum for specific guidance
+
+I will provide feedback on your pull request if it fails to meet any of the above.
+
+Please consider separate pull requests for each feature as big pull requests are very time consuming to understand.
+It is highly probably that I will reject a large pull request due to the time it would take to comprehend.
+
+_Will you add feature XYZ for me?_
+
+If it is in the roadmap, I intend to implement it some day - probably when I actually need it. If you really need
+something now and want to pay for it, feel free to email me.
+
+_How mature is Cornerstone?_
+
+Each repository is at a different level of maturity. There are at least 15 image viewer projects using Cornerstone
+and the feedback has been consistently strong about the architecture, design and quality. The cornerstoneTools library
+is the least mature from a framework and breadth of functionality perspective - but the implemented features work well.
+
+Copyright
+=========
+
+Copyright 2014 Chris Hafey [chafey at gmail.com](mailto:chafey at gmail.com)
+
+
Added: trunk/packages/orthanc-webviewer/trunk/debian/JS/cornerstone-0.7.1/cornerstone.css
===================================================================
--- trunk/packages/orthanc-webviewer/trunk/debian/JS/cornerstone-0.7.1/cornerstone.css (rev 0)
+++ trunk/packages/orthanc-webviewer/trunk/debian/JS/cornerstone-0.7.1/cornerstone.css 2015-03-02 09:58:59 UTC (rev 18890)
@@ -0,0 +1,17 @@
+/*! cornerstone - v0.7.1 - 2015-02-24 | (c) 2014 Chris Hafey | https://github.com/chafey/cornerstone */
+.cornerstone-enabled-image {
+
+ /* prevent text selection from occurring when dragging the mouse on the div */
+ /* http://stackoverflow.com/questions/826782/css-rule-to-disable-text-selection-highlighting */
+ -webkit-touch-callout: none;
+ -webkit-user-select: none;
+ -khtml-user-select: none;
+ -moz-user-select: none;
+ -ms-user-select: none;
+ user-select: none;
+
+ /* force the cursor to always be the default arrow. This prevents it from changing to an ibar when it is
+ over HTML based text overlays (four corners */
+ cursor:default;
+}
+
Added: trunk/packages/orthanc-webviewer/trunk/debian/JS/cornerstone-0.7.1/cornerstone.js
===================================================================
--- trunk/packages/orthanc-webviewer/trunk/debian/JS/cornerstone-0.7.1/cornerstone.js (rev 0)
+++ trunk/packages/orthanc-webviewer/trunk/debian/JS/cornerstone-0.7.1/cornerstone.js 2015-03-02 09:58:59 UTC (rev 18890)
@@ -0,0 +1,1725 @@
+/*! cornerstone - v0.7.1 - 2015-02-24 | (c) 2014 Chris Hafey | https://github.com/chafey/cornerstone */
+var cornerstone = (function (cornerstone) {
+
+ "use strict";
+
+ if(cornerstone === undefined) {
+ cornerstone = {};
+ }
+
+ function disable(element) {
+ if(element === undefined) {
+ throw "disable: element element must not be undefined";
+ }
+
+ // Search for this element in this list of enabled elements
+ var enabledElements = cornerstone.getEnabledElements();
+ for(var i=0; i < enabledElements.length; i++) {
+ if(enabledElements[i].element === element) {
+ // We found it!
+
+ // Fire an event so dependencies can cleanup
+ var eventData = {
+ element : element
+ };
+ $(element).trigger("CornerstoneElementDisabled", eventData);
+
+ // remove the child dom elements that we created (e.g.canvas)
+ enabledElements[i].element.removeChild(enabledElements[i].canvas);
+
+ // remove this element from the list of enabled elements
+ enabledElements.splice(i, 1);
+ return;
+ }
+ }
+ }
+
+ // module/private exports
+ cornerstone.disable = disable;
+
+ return cornerstone;
+}(cornerstone));
+/**
+ * This module is responsible for enabling an element to display images with cornerstone
+ */
+var cornerstone = (function ($, cornerstone) {
+
+ "use strict";
+
+ if(cornerstone === undefined) {
+ cornerstone = {};
+ }
+
+ /**
+ * sets a new image object for a given element
+ * @param element
+ * @param image
+ */
+ function displayImage(element, image, viewport) {
+ if(element === undefined) {
+ throw "displayImage: parameter element cannot be undefined";
+ }
+ if(image === undefined) {
+ throw "displayImage: parameter image cannot be undefined";
+ }
+
+ var enabledElement = cornerstone.getEnabledElement(element);
+
+ enabledElement.image = image;
+
+ if(enabledElement.viewport === undefined) {
+ enabledElement.viewport = cornerstone.getDefaultViewport(enabledElement.canvas, image);
+ }
+
+ // merge viewport
+ if(viewport) {
+ for(var attrname in viewport)
+ {
+ if(viewport[attrname] !== null) {
+ enabledElement.viewport[attrname] = viewport[attrname];
+ }
+ }
+ }
+
+ var now = new Date();
+ var frameRate;
+ if(enabledElement.lastImageTimeStamp !== undefined) {
+ var timeSinceLastImage = now.getTime() - enabledElement.lastImageTimeStamp;
+ frameRate = (1000 / timeSinceLastImage).toFixed();
+ } else {
+ }
+ enabledElement.lastImageTimeStamp = now.getTime();
+
+ var newImageEventData = {
+ viewport : enabledElement.viewport,
+ element : enabledElement.element,
+ image : enabledElement.image,
+ enabledElement : enabledElement,
+ frameRate : frameRate
+ };
+
+ $(enabledElement.element).trigger("CornerstoneNewImage", newImageEventData);
+
+ cornerstone.updateImage(element);
+ }
+
+ // module/private exports
+ cornerstone.displayImage = displayImage;
+
+ return cornerstone;
+}($, cornerstone));
+/**
+ * This module is responsible for immediately drawing an enabled element
+ */
+
+var cornerstone = (function ($, cornerstone) {
+
+ "use strict";
+
+ if(cornerstone === undefined) {
+ cornerstone = {};
+ }
+
+ /**
+ * Immediately draws the enabled element
+ *
+ * @param element
+ */
+ function draw(element) {
+ var enabledElement = cornerstone.getEnabledElement(element);
+
+ if(enabledElement.image === undefined) {
+ throw "draw: image has not been loaded yet";
+ }
+
+ cornerstone.drawImage(enabledElement);
+ }
+
+ // Module exports
+ cornerstone.draw = draw;
+
+ return cornerstone;
+}($, cornerstone));
+/**
+ * This module is responsible for drawing an image to an enabled elements canvas element
+ */
+
+var cornerstone = (function ($, cornerstone) {
+
+ "use strict";
+
+ if(cornerstone === undefined) {
+ cornerstone = {};
+ }
+
+ /**
+ * Internal API function to draw an image to a given enabled element
+ * @param enabledElement
+ * @param invalidated - true if pixel data has been invalidated and cached rendering should not be used
+ */
+ function drawImage(enabledElement, invalidated) {
+
+ var start = new Date();
+
+ enabledElement.image.render(enabledElement, invalidated);
+
+ var context = enabledElement.canvas.getContext('2d');
+
+ var end = new Date();
+ var diff = end - start;
+ //console.log(diff + ' ms');
+
+ var eventData = {
+ viewport : enabledElement.viewport,
+ element : enabledElement.element,
+ image : enabledElement.image,
+ enabledElement : enabledElement,
+ canvasContext: context,
+ renderTimeInMs : diff
+ };
+
+ $(enabledElement.element).trigger("CornerstoneImageRendered", eventData);
+ enabledElement.invalid = false;
+ }
+
+ // Module exports
+ cornerstone.drawImage = drawImage;
+
+ return cornerstone;
+}($, cornerstone));
+/**
+ * This module is responsible for drawing invalidated enabled elements
+ */
+
+var cornerstone = (function ($, cornerstone) {
+
+ "use strict";
+
+ if(cornerstone === undefined) {
+ cornerstone = {};
+ }
+
+ /**
+ * Draws all invalidated enabled elements and clears the invalid flag after drawing it
+ */
+ function drawInvalidated()
+ {
+ var enabledElements = cornerstone.getEnabledElements();
+ for(var i=0;i < enabledElements.length; i++) {
+ var ee = enabledElements[i];
+ if(ee.invalid === true) {
+ cornerstone.drawImage(ee);
+ }
+ }
+ }
+
+ // Module exports
+ cornerstone.drawInvalidated = drawInvalidated;
+
+ return cornerstone;
+}($, cornerstone));
+/**
+ * This module is responsible for enabling an element to display images with cornerstone
+ */
+var cornerstone = (function (cornerstone) {
+
+ "use strict";
+
+ if(cornerstone === undefined) {
+ cornerstone = {};
+ }
+
+ function enable(element) {
+ if(element === undefined) {
+ throw "enable: parameter element cannot be undefined";
+ }
+
+ var canvas = document.createElement('canvas');
+ element.appendChild(canvas);
+
+ var el = {
+ element: element,
+ canvas: canvas,
+ image : undefined, // will be set once image is loaded
+ invalid: false, // true if image needs to be drawn, false if not
+ data : {}
+ };
+ cornerstone.addEnabledElement(el);
+
+ cornerstone.resize(element, true);
+
+ return element;
+ }
+
+ // module/private exports
+ cornerstone.enable = enable;
+
+ return cornerstone;
+}(cornerstone));
+var cornerstone = (function (cornerstone) {
+
+ "use strict";
+
+ if(cornerstone === undefined) {
+ cornerstone = {};
+ }
+
+ function getElementData(el, dataType) {
+ var ee = cornerstone.getEnabledElement(el);
+ if(ee.data.hasOwnProperty(dataType) === false)
+ {
+ ee.data[dataType] = {};
+ }
+ return ee.data[dataType];
+ }
+
+ function removeElementData(el, dataType) {
+ var ee = cornerstone.getEnabledElement(el);
+ delete ee.data[dataType];
+ }
+
+ // module/private exports
+ cornerstone.getElementData = getElementData;
+ cornerstone.removeElementData = removeElementData;
+
+ return cornerstone;
+}(cornerstone));
+var cornerstone = (function (cornerstone) {
+
+ "use strict";
+
+ if(cornerstone === undefined) {
+ cornerstone = {};
+ }
+
+ var enabledElements = [];
+
+ function getEnabledElement(element) {
+ if(element === undefined) {
+ throw "getEnabledElement: parameter element must not be undefined";
+ }
+ for(var i=0; i < enabledElements.length; i++) {
+ if(enabledElements[i].element == element) {
+ return enabledElements[i];
+ }
+ }
+
+ throw "element not enabled";
+ }
+
+ function addEnabledElement(enabledElement) {
+ if(enabledElement === undefined) {
+ throw "getEnabledElement: enabledElement element must not be undefined";
+ }
+
+ enabledElements.push(enabledElement);
+ }
+
+ function getEnabledElementsByImageId(imageId) {
+ var ees = [];
+ enabledElements.forEach(function(enabledElement) {
+ if(enabledElement.image && enabledElement.image.imageId === imageId) {
+ ees.push(enabledElement);
+ }
+ });
+ return ees;
+ }
+
+ function getEnabledElements() {
+ return enabledElements;
+ }
+
+ // module/private exports
+ cornerstone.getEnabledElement = getEnabledElement;
+ cornerstone.addEnabledElement = addEnabledElement;
+ cornerstone.getEnabledElementsByImageId = getEnabledElementsByImageId;
+ cornerstone.getEnabledElements = getEnabledElements;
+
+ return cornerstone;
+}(cornerstone));
+/**
+ * This module will fit an image to fit inside the canvas displaying it such that all pixels
+ * in the image are viewable
+ */
+var cornerstone = (function (cornerstone) {
+
+ "use strict";
+
+ if(cornerstone === undefined) {
+ cornerstone = {};
+ }
+
+ /**
+ * Adjusts an images scale and center so the image is centered and completely visible
+ * @param element
+ */
+ function fitToWindow(element)
+ {
+ var enabledElement = cornerstone.getEnabledElement(element);
+ var defaultViewport = cornerstone.getDefaultViewport(enabledElement.canvas, enabledElement.image);
+ enabledElement.viewport.scale = defaultViewport.scale;
+ enabledElement.viewport.translation.x = defaultViewport.translation.x;
+ enabledElement.viewport.translation.y = defaultViewport.translation.y;
+ enabledElement.viewport.rotation = defaultViewport.rotation;
+ enabledElement.viewport.hflip = defaultViewport.hflip;
+ enabledElement.viewport.vflip = defaultViewport.vflip;
+ cornerstone.updateImage(element);
+ }
+
+ cornerstone.fitToWindow = fitToWindow;
+
+ return cornerstone;
+}(cornerstone));
+
+/**
+ * This module generates a lut for an image
+ */
+
+var cornerstone = (function (cornerstone) {
+
+ "use strict";
+
+ if(cornerstone === undefined) {
+ cornerstone = {};
+ }
+
+ /**
+ * Creates a LUT used while rendering to convert stored pixel values to
+ * display pixels
+ *
+ * @param image
+ * @returns {Array}
+ */
+ function generateLut(image, windowWidth, windowCenter, invert)
+ {
+ if(image.lut === undefined) {
+ image.lut = new Int16Array(image.maxPixelValue - Math.min(image.minPixelValue,0)+1);
+ }
+ var lut = image.lut;
+
+ var maxPixelValue = image.maxPixelValue;
+ var minPixelValue = image.minPixelValue;
+ var slope = image.slope;
+ var intercept = image.intercept;
+ var localWindowWidth = windowWidth;
+ var localWindowCenter = windowCenter;
+
+ var modalityLutValue;
+ var voiLutValue;
+ var clampedValue;
+ var storedValue;
+
+ // NOTE: As of Nov 2014, most javascript engines have lower performance when indexing negative indexes.
+ // We improve performance by offsetting the pixel values for signed data to avoid negative indexes
+ // when generating the lut and then undo it in storedPixelDataToCanvasImagedata. Thanks to @jpambrun
+ // for this contibution!
+
+ if(invert === true) {
+ for(storedValue = image.minPixelValue; storedValue <= maxPixelValue; storedValue++)
+ {
+ modalityLutValue = storedValue * slope + intercept;
+ voiLutValue = (((modalityLutValue - (localWindowCenter)) / (localWindowWidth) + 0.5) * 255.0);
+ clampedValue = Math.min(Math.max(voiLutValue, 0), 255);
+ lut[storedValue + (-minPixelValue)] = Math.round(255 - clampedValue);
+ }
+ }
+ else {
+ for(storedValue = image.minPixelValue; storedValue <= maxPixelValue; storedValue++)
+ {
+ modalityLutValue = storedValue * slope + intercept;
+ voiLutValue = (((modalityLutValue - (localWindowCenter)) / (localWindowWidth) + 0.5) * 255.0);
+ clampedValue = Math.min(Math.max(voiLutValue, 0), 255);
+ lut[storedValue+ (-minPixelValue)] = Math.round(clampedValue);
+ }
+ }
+ }
+
+
+ // Module exports
+ cornerstone.generateLut = generateLut;
+
+ return cornerstone;
+}(cornerstone));
+
+/**
+ * This module contains a function to get a default viewport for an image given
+ * a canvas element to display it in
+ *
+ */
+var cornerstone = (function (cornerstone) {
+
+ "use strict";
+
+ if(cornerstone === undefined) {
+ cornerstone = {};
+ }
+
+ /**
+ * Creates a new viewport object containing default values for the image and canvas
+ * @param canvas
+ * @param image
+ * @returns viewport object
+ */
+ function getDefaultViewport(canvas, image) {
+ if(canvas === undefined) {
+ throw "getDefaultViewport: parameter canvas must not be undefined";
+ }
+ if(image === undefined) {
+ throw "getDefaultViewport: parameter image must not be undefined";
+ }
+ var viewport = {
+ scale : 1.0,
+ translation : {
+ x : 0,
+ y : 0
+ },
+ voi : {
+ windowWidth: image.windowWidth,
+ windowCenter: image.windowCenter,
+ },
+ invert: image.invert,
+ pixelReplication: false,
+ rotation: 0,
+ hflip: false,
+ vflip: false
+ };
+
+ // fit image to window
+ var verticalScale = canvas.height / image.rows;
+ var horizontalScale= canvas.width / image.columns;
+ if(horizontalScale < verticalScale) {
+ viewport.scale = horizontalScale;
+ }
+ else {
+ viewport.scale = verticalScale;
+ }
+ return viewport;
+ }
+
+ // module/private exports
+ cornerstone.getDefaultViewport = getDefaultViewport;
+
+ return cornerstone;
+}(cornerstone));
+
+/**
+ * This module returns a subset of the stored pixels of an image
+ */
+var cornerstone = (function (cornerstone) {
+
+ "use strict";
+
+ if(cornerstone === undefined) {
+ cornerstone = {};
+ }
+
+ /**
+ * Returns an array of stored pixels given a rectangle in the image
+ * @param element
+ * @param x
+ * @param y
+ * @param width
+ * @param height
+ * @returns {Array}
+ */
+ function getStoredPixels(element, x, y, width, height) {
+ if(element === undefined) {
+ throw "getStoredPixels: parameter element must not be undefined";
+ }
+
+ x = Math.round(x);
+ y = Math.round(y);
+ var ee = cornerstone.getEnabledElement(element);
+ var storedPixels = [];
+ var index = 0;
+ var pixelData = ee.image.getPixelData();
+ for(var row=0; row < height; row++) {
+ for(var column=0; column < width; column++) {
+ var spIndex = ((row + y) * ee.image.columns) + (column + x);
+ storedPixels[index++] = pixelData[spIndex];
+ }
+ }
+ return storedPixels;
+ }
+
+ /**
+ * Returns array of pixels with modality LUT transformation applied
+ */
+ function getPixels(element, x, y, width, height) {
+
+ var storedPixels = getStoredPixels(element, x, y, width, height);
+ var ee = cornerstone.getEnabledElement(element);
+ var slope = ee.image.slope;
+ var intercept = ee.image.intercept;
+
+ var modalityPixels = storedPixels.map(function(pixel){
+ return pixel * slope + intercept;
+ });
+
+ return modalityPixels;
+ }
+
+ // module exports
+ cornerstone.getStoredPixels = getStoredPixels;
+ cornerstone.getPixels = getPixels;
+
+ return cornerstone;
+}(cornerstone));
+/**
+ * This module deals with caching images
+ */
+
+var cornerstone = (function (cornerstone) {
+
+ "use strict";
+
+ if(cornerstone === undefined) {
+ cornerstone = {};
+ }
+
+ var imageCache = {
+ };
+
+ var cachedImages = [];
+
+ var maximumSizeInBytes = 1024 * 1024 * 1024; // 1 GB
+ var cacheSizeInBytes = 0;
+
+ function setMaximumSizeBytes(numBytes)
+ {
+ if(numBytes === undefined) {
+ throw "setMaximumSizeBytes: parameter numBytes must not be undefined";
+ }
+ if(numBytes.toFixed === undefined) {
+ throw "setMaximumSizeBytes: parameter numBytes must be a number";
+ }
+
+ maximumSizeInBytes = numBytes;
+ purgeCacheIfNecessary();
+ }
+
+ function purgeCacheIfNecessary()
+ {
+ // if max cache size has not been exceeded, do nothing
+ if(cacheSizeInBytes <= maximumSizeInBytes)
+ {
+ return;
+ }
+
+ // cache size has been exceeded, create list of images sorted by timeStamp
+ // so we can purge the least recently used image
+ function compare(a,b) {
+ if(a.timeStamp > b.timeStamp) {
+ return -1;
+ }
+ if(a.timeStamp < b.timeStamp) {
+ return 1;
+ }
+ return 0;
+ }
+ cachedImages.sort(compare);
+
+ // remove images as necessary
+ while(cacheSizeInBytes > maximumSizeInBytes)
+ {
+ var lastCachedImage = cachedImages[cachedImages.length - 1];
+ cacheSizeInBytes -= lastCachedImage.sizeInBytes;
+ delete imageCache[lastCachedImage.imageId];
+ lastCachedImage.imagePromise.reject();
+ cachedImages.pop();
+ }
+ }
+
+ function putImagePromise(imageId, imagePromise) {
+ if(imageId === undefined)
+ {
+ throw "getImagePromise: imageId must not be undefined";
+ }
+ if(imagePromise === undefined)
+ {
+ throw "getImagePromise: imagePromise must not be undefined";
+ }
+
+ if(imageCache.hasOwnProperty(imageId) === true) {
+ throw "putImagePromise: imageId already in cache";
+ }
+
+ var cachedImage = {
+ loaded : false,
+ imageId : imageId,
+ imagePromise : imagePromise,
+ timeStamp : new Date(),
+ sizeInBytes: 0
+ };
+
+ imageCache[imageId] = cachedImage;
+ cachedImages.push(cachedImage);
+
+ imagePromise.then(function(image) {
+ cachedImage.loaded = true;
+
+ if(image.sizeInBytes === undefined)
+ {
+ throw "putImagePromise: image does not have sizeInBytes property or";
+ }
+ if(image.sizeInBytes.toFixed === undefined) {
+ throw "putImagePromise: image.sizeInBytes is not a number";
+ }
+ cachedImage.sizeInBytes = image.sizeInBytes;
+ cacheSizeInBytes += cachedImage.sizeInBytes;
+ purgeCacheIfNecessary();
+ });
+ }
+
+ function getImagePromise(imageId) {
+ if(imageId === undefined)
+ {
+ throw "getImagePromise: imageId must not be undefined";
+ }
+ var cachedImage = imageCache[imageId];
+ if(cachedImage === undefined) {
+ return undefined;
+ }
+
+ // bump time stamp for cached image
+ cachedImage.timeStamp = new Date();
+ return cachedImage.imagePromise;
+ }
+
+ function removeImagePromise(imageId) {
+ if(imageId === undefined) {
+ throw "removeImagePromise: imageId must not be undefined";
+ }
+ var cachedImage = imageCache[imageId];
+ if(cachedImage === undefined) {
+ throw "removeImagePromise: imageId must not be undefined";
+ }
+ cachedImages.splice( cachedImages.indexOf(cachedImage), 1);
+ cacheSizeInBytes -= cachedImage.sizeInBytes;
+ delete imageCache[imageId];
+
+ return cachedImage.imagePromise;
+ }
+
+ function getCacheInfo() {
+ return {
+ maximumSizeInBytes : maximumSizeInBytes,
+ cacheSizeInBytes : cacheSizeInBytes,
+ numberOfImagesCached: cachedImages.length
+ };
+ }
+
+ function purgeCache() {
+ while (cachedImages.length > 0) {
+ var removedCachedImage = cachedImages.pop();
+ delete imageCache[removedCachedImage.imageId];
+ removedCachedImage.imagePromise.reject();
+ }
+ cacheSizeInBytes = 0;
+ }
+
+ // module exports
+
+ cornerstone.imageCache = {
+ putImagePromise : putImagePromise,
+ getImagePromise: getImagePromise,
+ removeImagePromise: removeImagePromise,
+ setMaximumSizeBytes: setMaximumSizeBytes,
+ getCacheInfo : getCacheInfo,
+ purgeCache: purgeCache
+ };
+
+ return cornerstone;
+}(cornerstone));
+
+/**
+ * This module deals with ImageLoaders, loading images and caching images
+ */
+
+var cornerstone = (function ($, cornerstone) {
+
+ "use strict";
+
+ if(cornerstone === undefined) {
+ cornerstone = {};
+ }
+
+ var imageLoaders = {};
+
+ var unknownImageLoader;
+
+ function loadImageFromImageLoader(imageId) {
+ var colonIndex = imageId.indexOf(":");
+ var scheme = imageId.substring(0, colonIndex);
+ var loader = imageLoaders[scheme];
+ var imagePromise;
+ if(loader === undefined || loader === null) {
+ if(unknownImageLoader !== undefined) {
+ imagePromise = unknownImageLoader(imageId);
+ return imagePromise;
+ }
+ else {
+ return undefined;
+ }
+ }
+ imagePromise = loader(imageId);
+
+ // broadcast an image loaded event once the image is loaded
+ // This is based on the idea here: http://stackoverflow.com/questions/3279809/global-custom-events-in-jquery
+ imagePromise.then(function(image) {
+ $(cornerstone).trigger('CornerstoneImageLoaded', {image: image});
+ });
+
+ return imagePromise;
+ }
+
+ // Loads an image given an imageId and returns a promise which will resolve
+ // to the loaded image object or fail if an error occurred. The loaded image
+ // is not stored in the cache
+ function loadImage(imageId) {
+ if(imageId === undefined) {
+ throw "loadImage: parameter imageId must not be undefined";
+ }
+
+ var imagePromise = cornerstone.imageCache.getImagePromise(imageId);
+ if(imagePromise !== undefined) {
+ return imagePromise;
+ }
+
+ imagePromise = loadImageFromImageLoader(imageId);
+ if(imagePromise === undefined) {
+ throw "loadImage: no image loader for imageId";
+ }
+
+ return imagePromise;
+ }
+
+ // Loads an image given an imageId and returns a promise which will resolve
+ // to the loaded image object or fail if an error occurred. The image is
+ // stored in the cache
+ function loadAndCacheImage(imageId) {
+ if(imageId === undefined) {
+ throw "loadAndCacheImage: parameter imageId must not be undefined";
+ }
+
+ var imagePromise = cornerstone.imageCache.getImagePromise(imageId);
+ if(imagePromise !== undefined) {
+ return imagePromise;
+ }
+
+ imagePromise = loadImageFromImageLoader(imageId);
+ if(imagePromise === undefined) {
+ throw "loadAndCacheImage: no image loader for imageId";
+ }
+
+ cornerstone.imageCache.putImagePromise(imageId, imagePromise);
+
+ return imagePromise;
+ }
+
+
+ // registers an imageLoader plugin with cornerstone for the specified scheme
+ function registerImageLoader(scheme, imageLoader) {
+ imageLoaders[scheme] = imageLoader;
+ }
+
+ // Registers a new unknownImageLoader and returns the previous one (if it exists)
+ function registerUnknownImageLoader(imageLoader) {
+ var oldImageLoader = unknownImageLoader;
+ unknownImageLoader = imageLoader;
+ return oldImageLoader;
+ }
+
+ // module exports
+
+ cornerstone.loadImage = loadImage;
+ cornerstone.loadAndCacheImage = loadAndCacheImage;
+ cornerstone.registerImageLoader = registerImageLoader;
+ cornerstone.registerUnknownImageLoader = registerUnknownImageLoader;
+
+ return cornerstone;
+}($, cornerstone));
+/**
+ * This module contains a function to make an image is invalid
+ */
+var cornerstone = (function (cornerstone) {
+
+ "use strict";
+
+ if(cornerstone === undefined) {
+ cornerstone = {};
+ }
+
+ /**
+ * Sets the invalid flag on the enabled element and fire an event
+ * @param element
+ */
+ function invalidate(element) {
+ var enabledElement = cornerstone.getEnabledElement(element);
+ enabledElement.invalid = true;
+ var eventData = {
+ element: element
+ };
+ $(enabledElement.element).trigger("CornerstoneInvalidated", eventData);
+ }
+
+ // module exports
+ cornerstone.invalidate = invalidate;
+
+ return cornerstone;
+}(cornerstone));
+/**
+ * This module contains a function to immediately invalidate an image
+ */
+var cornerstone = (function (cornerstone) {
+
+ "use strict";
+
+ if(cornerstone === undefined) {
+ cornerstone = {};
+ }
+
+ /**
+ * Forces the image to be updated/redrawn for the specified enabled element
+ * @param element
+ */
+ function invalidateImageId(imageId) {
+
+ var enabledElements = cornerstone.getEnabledElementsByImageId(imageId);
+ enabledElements.forEach(function(enabledElement) {
+ cornerstone.drawImage(enabledElement, true);
+ });
+ }
+
+ // module exports
+ cornerstone.invalidateImageId = invalidateImageId;
+
+ return cornerstone;
+}(cornerstone));
+/**
+ * This module contains a helper function to covert page coordinates to pixel coordinates
+ */
+var cornerstone = (function (cornerstone) {
+
+ "use strict";
+
+ if(cornerstone === undefined) {
+ cornerstone = {};
+ }
+
+ /**
+ * Converts a point in the page coordinate system to the pixel coordinate
+ * system
+ * @param element
+ * @param pageX
+ * @param pageY
+ * @returns {{x: number, y: number}}
+ */
+
+ function pageToPixel(element, pageX, pageY) {
+ var ee = cornerstone.getEnabledElement(element);
+
+ if(ee.image === undefined) {
+ throw "image has not been loaded yet";
+ }
+
+ // TODO: replace this with a transformation matrix
+
+ // convert the pageX and pageY to the canvas client coordinates
+ var rect = element.getBoundingClientRect();
+ var clientX = pageX - rect.left - window.pageXOffset;
+ var clientY = pageY - rect.top - window.pageYOffset;
+
+ // translate the client relative to the middle of the canvas
+ var middleX = clientX - rect.width / 2.0;
+ var middleY = clientY - rect.height / 2.0;
+
+ // scale to image coordinates middleX/middleY
+ var viewport = ee.viewport;
+
+ // apply the scale
+ var widthScale = ee.viewport.scale;
+ var heightScale = ee.viewport.scale;
+ if(ee.image.rowPixelSpacing < ee.image.columnPixelSpacing) {
+ widthScale = widthScale * (ee.image.columnPixelSpacing / ee.image.rowPixelSpacing);
+ }
+ else if(ee.image.columnPixelSpacing < ee.image.rowPixelSpacing) {
+ heightScale = heightScale * (ee.image.rowPixelSpacing / ee.image.columnPixelSpacing);
+ }
+
+ var scaledMiddleX = middleX / widthScale;
+ var scaledMiddleY = middleY / heightScale;
+
+ // apply pan offset
+ var imageX = scaledMiddleX - viewport.translation.x;
+ var imageY = scaledMiddleY - viewport.translation.y;
+
+ //Apply Flips
+ if(viewport.hflip) {
+ imageX*=-1;
+ }
+
+ if(viewport.vflip) {
+ imageY*=-1;
+ }
+
+ //Apply rotations
+ if(viewport.rotation!==0) {
+ var angle = viewport.rotation * Math.PI/180;
+
+ var cosA = Math.cos(angle);
+ var sinA = Math.sin(angle);
+
+ var newX = imageX * cosA - imageY * sinA;
+ var newY = imageX * sinA + imageY * cosA;
+
+ if(viewport.rotation===90 || viewport.rotation===270 || viewport.rotation===-90 || viewport.rotation===-270) {
+ newX*= -1;
+ newY*= -1;
+ }
+
+ imageX = newX;
+ imageY = newY;
+ }
+
+ // translate to image top left
+ imageX += ee.image.columns / 2;
+ imageY += ee.image.rows / 2;
+
+ return {
+ x: imageX,
+ y: imageY
+ };
+ }
+
+ // module/private exports
+ cornerstone.pageToPixel = pageToPixel;
+
+ return cornerstone;
+}(cornerstone));
+
+/**
+ * This module is responsible for drawing an image to an enabled elements canvas element
+ */
+
+var cornerstone = (function (cornerstone) {
+
+ "use strict";
+
+ if(cornerstone === undefined) {
+ cornerstone = {};
+ }
+
+ var colorRenderCanvas = document.createElement('canvas');
+ var colorRenderCanvasContext;
+ var colorRenderCanvasData;
+
+ var lastRenderedImageId;
+ var lastRenderedViewport = {};
+
+ function initializeColorRenderCanvas(image)
+ {
+ // Resize the canvas
+ colorRenderCanvas.width = image.width;
+ colorRenderCanvas.height = image.height;
+
+ // get the canvas data so we can write to it directly
+ colorRenderCanvasContext = colorRenderCanvas.getContext('2d');
+ colorRenderCanvasContext.fillStyle = 'white';
+ colorRenderCanvasContext.fillRect(0,0, colorRenderCanvas.width, colorRenderCanvas.height);
+ colorRenderCanvasData = colorRenderCanvasContext.getImageData(0,0,image.width, image.height);
+ }
+
+
+ function getLut(image, viewport)
+ {
+ // if we have a cached lut and it has the right values, return it immediately
+ if(image.lut !== undefined &&
+ image.lut.windowCenter === viewport.voi.windowCenter &&
+ image.lut.windowWidth === viewport.voi.windowWidth &&
+ image.lut.invert === viewport.invert) {
+ return image.lut;
+ }
+
+ // lut is invalid or not present, regenerate it and cache it
+ cornerstone.generateLut(image, viewport.voi.windowWidth, viewport.voi.windowCenter, viewport.invert);
+ image.lut.windowWidth = viewport.voi.windowWidth;
+ image.lut.windowCenter = viewport.voi.windowCenter;
+ image.lut.invert = viewport.invert;
+ return image.lut;
+ }
+
+ function doesImageNeedToBeRendered(enabledElement, image)
+ {
+ if(image.imageId !== lastRenderedImageId ||
+ lastRenderedViewport.windowCenter !== enabledElement.viewport.voi.windowCenter ||
+ lastRenderedViewport.windowWidth !== enabledElement.viewport.voi.windowWidth ||
+ lastRenderedViewport.invert !== enabledElement.viewport.invert ||
+ lastRenderedViewport.rotation !== enabledElement.viewport.rotation ||
+ lastRenderedViewport.hflip !== enabledElement.viewport.hflip ||
+ lastRenderedViewport.vflip !== enabledElement.viewport.vflip
+ )
+ {
+ return true;
+ }
+
+ return false;
+ }
+
+ function getRenderCanvas(enabledElement, image, invalidated)
+ {
+ // apply the lut to the stored pixel data onto the render canvas
+
+ if(enabledElement.viewport.voi.windowWidth === enabledElement.image.windowWidth &&
+ enabledElement.viewport.voi.windowCenter === enabledElement.image.windowCenter &&
+ enabledElement.viewport.invert === false)
+ {
+ // the color image voi/invert has not been modified, request the canvas that contains
+ // it so we can draw it directly to the display canvas
+ return image.getCanvas();
+ }
+ else
+ {
+ if(doesImageNeedToBeRendered(enabledElement, image) === false && invalidated !== true) {
+ return colorRenderCanvas;
+ }
+
+ // If our render canvas does not match the size of this image reset it
+ // NOTE: This might be inefficient if we are updating multiple images of different
+ // sizes frequently.
+ if(colorRenderCanvas.width !== image.width || colorRenderCanvas.height != image.height) {
+ initializeColorRenderCanvas(image);
+ }
+
+ // get the lut to use
+ var colorLut = getLut(image, enabledElement.viewport);
+
+ // the color image voi/invert has been modified - apply the lut to the underlying
+ // pixel data and put it into the renderCanvas
+ cornerstone.storedColorPixelDataToCanvasImageData(image, colorLut, colorRenderCanvasData.data);
+ colorRenderCanvasContext.putImageData(colorRenderCanvasData, 0, 0);
+ return colorRenderCanvas;
+ }
+ }
+
+ /**
+ * API function to render a color image to an enabled element
+ * @param enabledElement
+ * @param invalidated - true if pixel data has been invaldiated and cached rendering should not be used
+ */
+ function renderColorImage(enabledElement, invalidated) {
+
+ if(enabledElement === undefined) {
+ throw "drawImage: enabledElement parameter must not be undefined";
+ }
+ var image = enabledElement.image;
+ if(image === undefined) {
+ throw "drawImage: image must be loaded before it can be drawn";
+ }
+
+ // get the canvas context and reset the transform
+ var context = enabledElement.canvas.getContext('2d');
+ context.setTransform(1, 0, 0, 1, 0, 0);
+
+ // clear the canvas
+ context.fillStyle = 'black';
+ context.fillRect(0,0, enabledElement.canvas.width, enabledElement.canvas.height);
+
+ // turn off image smooth/interpolation if pixelReplication is set in the viewport
+ if(enabledElement.viewport.pixelReplication === true) {
+ context.imageSmoothingEnabled = false;
+ context.mozImageSmoothingEnabled = false; // firefox doesn't support imageSmoothingEnabled yet
+ }
+ else {
+ context.imageSmoothingEnabled = true;
+ context.mozImageSmoothingEnabled = true;
+ }
+
+ // save the canvas context state and apply the viewport properties
+ context.save();
+ cornerstone.setToPixelCoordinateSystem(enabledElement, context);
+
+ var renderCanvas = getRenderCanvas(enabledElement, image, invalidated);
+
+ context.drawImage(renderCanvas, 0,0, image.width, image.height, 0, 0, image.width, image.height);
+
+ context.restore();
+
+ lastRenderedImageId = image.imageId;
+ lastRenderedViewport.windowCenter = enabledElement.viewport.voi.windowCenter;
+ lastRenderedViewport.windowWidth = enabledElement.viewport.voi.windowWidth;
+ lastRenderedViewport.invert = enabledElement.viewport.invert;
+ lastRenderedViewport.rotation = enabledElement.viewport.rotation;
+ lastRenderedViewport.hflip = enabledElement.viewport.hflip;
+ lastRenderedViewport.vflip = enabledElement.viewport.vflip;
+ }
+
+ // Module exports
+ cornerstone.renderColorImage = renderColorImage;
+
+ return cornerstone;
+}(cornerstone));
+
+/**
+ * This module is responsible for drawing a grayscale imageß
+ */
+
+var cornerstone = (function (cornerstone) {
+
+ "use strict";
+
+ if(cornerstone === undefined) {
+ cornerstone = {};
+ }
+
+ var grayscaleRenderCanvas = document.createElement('canvas');
+ var grayscaleRenderCanvasContext;
+ var grayscaleRenderCanvasData;
+
+ var lastRenderedImageId;
+ var lastRenderedViewport = {};
+
+ function initializeGrayscaleRenderCanvas(image)
+ {
+ // Resize the canvas
+ grayscaleRenderCanvas.width = image.width;
+ grayscaleRenderCanvas.height = image.height;
+
+ // NOTE - we need to fill the render canvas with white pixels since we control the luminance
+ // using the alpha channel to improve rendering performance.
+ grayscaleRenderCanvasContext = grayscaleRenderCanvas.getContext('2d');
+ grayscaleRenderCanvasContext.fillStyle = 'white';
+ grayscaleRenderCanvasContext.fillRect(0,0, grayscaleRenderCanvas.width, grayscaleRenderCanvas.height);
+ grayscaleRenderCanvasData = grayscaleRenderCanvasContext.getImageData(0,0,image.width, image.height);
+ }
+
+ function getLut(image, viewport, invalidated)
+ {
+ // if we have a cached lut and it has the right values, return it immediately
+ if(image.lut !== undefined &&
+ image.lut.windowCenter === viewport.voi.windowCenter &&
+ image.lut.windowWidth === viewport.voi.windowWidth &&
+ image.lut.invert === viewport.invert &&
+ invalidated !== true) {
+ return image.lut;
+ }
+
+ // lut is invalid or not present, regenerate it and cache it
+ cornerstone.generateLut(image, viewport.voi.windowWidth, viewport.voi.windowCenter, viewport.invert);
+ image.lut.windowWidth = viewport.voi.windowWidth;
+ image.lut.windowCenter = viewport.voi.windowCenter;
+ image.lut.invert = viewport.invert;
+ return image.lut;
+ }
+
+ function doesImageNeedToBeRendered(enabledElement, image)
+ {
+ if(image.imageId !== lastRenderedImageId ||
+ lastRenderedViewport.windowCenter !== enabledElement.viewport.voi.windowCenter ||
+ lastRenderedViewport.windowWidth !== enabledElement.viewport.voi.windowWidth ||
+ lastRenderedViewport.invert !== enabledElement.viewport.invert ||
+ lastRenderedViewport.rotation !== enabledElement.viewport.rotation ||
+ lastRenderedViewport.hflip !== enabledElement.viewport.hflip ||
+ lastRenderedViewport.vflip !== enabledElement.viewport.vflip
+ )
+ {
+ return true;
+ }
+
+ return false;
+ }
+
+ function getRenderCanvas(enabledElement, image, invalidated)
+ {
+ // apply the lut to the stored pixel data onto the render canvas
+
+ if(doesImageNeedToBeRendered(enabledElement, image) === false && invalidated !== true) {
+ return grayscaleRenderCanvas;
+ }
+
+ // If our render canvas does not match the size of this image reset it
+ // NOTE: This might be inefficient if we are updating multiple images of different
+ // sizes frequently.
+ if(grayscaleRenderCanvas.width !== image.width || grayscaleRenderCanvas.height != image.height) {
+ initializeGrayscaleRenderCanvas(image);
+ }
+
+ // get the lut to use
+ var lut = getLut(image, enabledElement.viewport, invalidated);
+ // gray scale image - apply the lut and put the resulting image onto the render canvas
+ cornerstone.storedPixelDataToCanvasImageData(image, lut, grayscaleRenderCanvasData.data);
+ grayscaleRenderCanvasContext.putImageData(grayscaleRenderCanvasData, 0, 0);
+ return grayscaleRenderCanvas;
+ }
+
+ /**
+ * API function to draw a grayscale image to a given enabledElement
+ * @param enabledElement
+ * @param invalidated - true if pixel data has been invaldiated and cached rendering should not be used
+ */
+ function renderGrayscaleImage(enabledElement, invalidated) {
+
+ if(enabledElement === undefined) {
+ throw "drawImage: enabledElement parameter must not be undefined";
+ }
+ var image = enabledElement.image;
+ if(image === undefined) {
+ throw "drawImage: image must be loaded before it can be drawn";
+ }
+
+ // get the canvas context and reset the transform
+ var context = enabledElement.canvas.getContext('2d');
+ context.setTransform(1, 0, 0, 1, 0, 0);
+
+ // clear the canvas
+ context.fillStyle = 'black';
+ context.fillRect(0,0, enabledElement.canvas.width, enabledElement.canvas.height);
+
+ // turn off image smooth/interpolation if pixelReplication is set in the viewport
+ if(enabledElement.viewport.pixelReplication === true) {
+ context.imageSmoothingEnabled = false;
+ context.mozImageSmoothingEnabled = false; // firefox doesn't support imageSmoothingEnabled yet
+ }
+ else {
+ context.imageSmoothingEnabled = true;
+ context.mozImageSmoothingEnabled = true;
+ }
+
+ // save the canvas context state and apply the viewport properties
+ cornerstone.setToPixelCoordinateSystem(enabledElement, context);
+
+ var renderCanvas = getRenderCanvas(enabledElement, image, invalidated);
+
+ // Draw the render canvas half the image size (because we set origin to the middle of the canvas above)
+ context.drawImage(renderCanvas, 0,0, image.width, image.height, 0, 0, image.width, image.height);
+
+ lastRenderedImageId = image.imageId;
+ lastRenderedViewport.windowCenter = enabledElement.viewport.voi.windowCenter;
+ lastRenderedViewport.windowWidth = enabledElement.viewport.voi.windowWidth;
+ lastRenderedViewport.invert = enabledElement.viewport.invert;
+ lastRenderedViewport.rotation = enabledElement.viewport.rotation;
+ lastRenderedViewport.hflip = enabledElement.viewport.hflip;
+ lastRenderedViewport.vflip = enabledElement.viewport.vflip;
+ }
+
+ // Module exports
+ cornerstone.renderGrayscaleImage = renderGrayscaleImage;
+
+ return cornerstone;
+}(cornerstone));
+
+/**
+ * This module is responsible for drawing an image to an enabled elements canvas element
+ */
+
+var cornerstone = (function (cornerstone) {
+
+ "use strict";
+
+ if(cornerstone === undefined) {
+ cornerstone = {};
+ }
+
+ /**
+ * API function to draw a standard web image (PNG, JPG) to an enabledImage
+ *
+ * @param enabledElement
+ * @param invalidated - true if pixel data has been invaldiated and cached rendering should not be used
+ */
+ function renderWebImage(enabledElement, invalidated) {
+
+ if(enabledElement === undefined) {
+ throw "drawImage: enabledElement parameter must not be undefined";
+ }
+ var image = enabledElement.image;
+ if(image === undefined) {
+ throw "drawImage: image must be loaded before it can be drawn";
+ }
+
+ // get the canvas context and reset the transform
+ var context = enabledElement.canvas.getContext('2d');
+ context.setTransform(1, 0, 0, 1, 0, 0);
+
+ // clear the canvas
+ context.fillStyle = 'black';
+ context.fillRect(0,0, enabledElement.canvas.width, enabledElement.canvas.height);
+
+ // turn off image smooth/interpolation if pixelReplication is set in the viewport
+ if(enabledElement.viewport.pixelReplication === true) {
+ context.imageSmoothingEnabled = false;
+ context.mozImageSmoothingEnabled = false; // firefox doesn't support imageSmoothingEnabled yet
+ }
+ else {
+ context.imageSmoothingEnabled = true;
+ context.mozImageSmoothingEnabled = true;
+ }
+
+ // save the canvas context state and apply the viewport properties
+ cornerstone.setToPixelCoordinateSystem(enabledElement, context);
+
+ // if the viewport ww/wc and invert all match the initial state of the image, we can draw the image
+ // directly. If any of those are changed, we call renderColorImage() to apply the lut
+ if(enabledElement.viewport.voi.windowWidth === enabledElement.image.windowWidth &&
+ enabledElement.viewport.voi.windowCenter === enabledElement.image.windowCenter &&
+ enabledElement.viewport.invert === false)
+ {
+ context.drawImage(image.getImage(), 0, 0, image.width, image.height, 0, 0, image.width, image.height);
+ } else {
+ cornerstone.renderColorImage(enabledElement, invalidated);
+ }
+
+ }
+
+ // Module exports
+ cornerstone.renderWebImage = renderWebImage;
+
+ return cornerstone;
+}(cornerstone));
+/**
+ * This module is responsible for enabling an element to display images with cornerstone
+ */
+var cornerstone = (function (cornerstone) {
+
+ "use strict";
+
+ if(cornerstone === undefined) {
+ cornerstone = {};
+ }
+
+ function setCanvasSize(element, canvas)
+ {
+ // the device pixel ratio is 1.0 for normal displays and > 1.0
+ // for high DPI displays like Retina
+ /*
+
+ This functionality is disabled due to buggy behavior on systems with mixed DPI's. If the canvas
+ is created on a display with high DPI (e.g. 2.0) and then the browser window is dragged to
+ a different display with a different DPI (e.g. 1.0), the canvas is not recreated so the pageToPixel
+ produces incorrect results. I couldn't find any way to determine when the DPI changed other than
+ by polling which is not very clean. If anyone has any ideas here, please let me know, but for now
+ we will disable this functionality. We may want
+ to add a mechanism to optionally enable this functionality if we can determine it is safe to do
+ so (e.g. iPad or iPhone or perhaps enumerate the displays on the system. I am choosing
+ to be cautious here since I would rather not have bug reports or safety issues related to this
+ scenario.
+
+ var devicePixelRatio = window.devicePixelRatio;
+ if(devicePixelRatio === undefined) {
+ devicePixelRatio = 1.0;
+ }
+ */
+
+ canvas.width = element.clientWidth;
+ canvas.height = element.clientHeight;
+ canvas.style.width = element.clientWidth + "px";
+ canvas.style.height = element.clientHeight + "px";
+ }
+
+ /**
+ * resizes an enabled element and optionally fits the image to window
+ * @param element
+ * @param fitToWindow true to refit, false to leave viewport parameters as they are
+ */
+ function resize(element, fitToWindow) {
+
+ var enabledElement = cornerstone.getEnabledElement(element);
+
+ setCanvasSize(element, enabledElement.canvas);
+
+ if(enabledElement.image === undefined ) {
+ return;
+ }
+
+ if(fitToWindow === true) {
+ cornerstone.fitToWindow(element);
+ }
+ else {
+ cornerstone.updateImage(element);
+ }
+ }
+
+ // module/private exports
+ cornerstone.resize = resize;
+
+ return cornerstone;
+}(cornerstone));
+/**
+ * This module contains a function that will set the canvas context to the pixel coordinates system
+ * making it easy to draw geometry on the image
+ */
+
+var cornerstone = (function (cornerstone) {
+
+ "use strict";
+
+ if(cornerstone === undefined) {
+ cornerstone = {};
+ }
+
+ /**
+ * Sets the canvas context transformation matrix to the pixel coordinate system. This allows
+ * geometry to be driven using the canvas context using coordinates in the pixel coordinate system
+ * @param ee
+ * @param context
+ * @param scale optional scaler to apply
+ */
+ function setToPixelCoordinateSystem(enabledElement, context, scale)
+ {
+ if(enabledElement === undefined) {
+ throw "setToPixelCoordinateSystem: parameter enabledElement must not be undefined";
+ }
+ if(context === undefined) {
+ throw "setToPixelCoordinateSystem: parameter context must not be undefined";
+ }
+
+ // reset the transformation matrix
+ context.setTransform(1, 0, 0, 1, 0, 0);
+ // move origin to center of canvas
+ context.translate(enabledElement.canvas.width/2, enabledElement.canvas.height / 2);
+
+ // apply the scale
+ var widthScale = enabledElement.viewport.scale;
+ var heightScale = enabledElement.viewport.scale;
+ if(enabledElement.image.rowPixelSpacing < enabledElement.image.columnPixelSpacing) {
+ widthScale = widthScale * (enabledElement.image.columnPixelSpacing / enabledElement.image.rowPixelSpacing);
+ }
+ else if(enabledElement.image.columnPixelSpacing < enabledElement.image.rowPixelSpacing) {
+ heightScale = heightScale * (enabledElement.image.rowPixelSpacing / enabledElement.image.columnPixelSpacing);
+ }
+ context.scale(widthScale, heightScale);
+
+ // apply the pan offset
+ context.translate(enabledElement.viewport.translation.x, enabledElement.viewport.translation.y);
+
+ if(scale === undefined) {
+ scale = 1.0;
+ } else {
+ // apply the font scale
+ context.scale(scale, scale);
+ }
+
+ //Apply if rotation required
+ var angle = enabledElement.viewport.rotation;
+
+ if(angle!==0) {
+ context.rotate(angle*Math.PI/180);
+ }
+
+ //Apply Flip if required
+ if(enabledElement.viewport.hflip) {
+ context.translate(enabledElement.offsetWidth,0);
+ context.scale(-1,1);
+ }
+
+ if(enabledElement.viewport.vflip) {
+ context.translate(0, enabledElement.offsetHeight);
+ context.scale(1,-1);
+ }
+
+ // translate the origin back to the corner of the image so the event handlers can draw in image coordinate system
+ context.translate(-enabledElement.image.width / 2 / scale, -enabledElement.image.height/ 2 / scale);
+ }
+
+ // Module exports
+ cornerstone.setToPixelCoordinateSystem = setToPixelCoordinateSystem;
+
+ return cornerstone;
+}(cornerstone));
+
+/**
+ * This module contains a function to convert stored pixel values to display pixel values using a LUT
+ */
+var cornerstone = (function (cornerstone) {
+
+ "use strict";
+
+ if(cornerstone === undefined) {
+ cornerstone = {};
+ }
+
+ /**
+ * This function transforms stored pixel values into a canvas image data buffer
+ * by using a LUT. This is the most performance sensitive code in cornerstone and
+ * we use a special trick to make this go as fast as possible. Specifically we
+ * use the alpha channel only to control the luminance rather than the red, green and
+ * blue channels which makes it over 3x faster. The canvasImageDataData buffer needs
+ * to be previously filled with white pixels.
+ *
+ * NOTE: Attribution would be appreciated if you use this technique!
+ *
+ * @param pixelData the pixel data
+ * @param lut the lut
+ * @param canvasImageDataData a canvasImgageData.data buffer filled with white pixels
+ */
+ function storedPixelDataToCanvasImageData(image, lut, canvasImageDataData)
+ {
+ var pixelData = image.getPixelData();
+ var minPixelValue = image.minPixelValue;
+ var canvasImageDataIndex = 3;
+ var storedPixelDataIndex = 0;
+ var localNumPixels = pixelData.length;
+ var localPixelData = pixelData;
+ var localLut = lut;
+ var localCanvasImageDataData = canvasImageDataData;
+ // NOTE: As of Nov 2014, most javascript engines have lower performance when indexing negative indexes.
+ // We have a special code path for this case that improves performance. Thanks to @jpambrun for this enhancement
+ if(minPixelValue < 0){
+ while(storedPixelDataIndex < localNumPixels) {
+ localCanvasImageDataData[canvasImageDataIndex] = localLut[localPixelData[storedPixelDataIndex++] + (-minPixelValue)]; // alpha
+ canvasImageDataIndex += 4;
+ }
+ }else{
+ while(storedPixelDataIndex < localNumPixels) {
+ localCanvasImageDataData[canvasImageDataIndex] = localLut[localPixelData[storedPixelDataIndex++]]; // alpha
+ canvasImageDataIndex += 4;
+ }
+ }
+ }
+
+ function storedColorPixelDataToCanvasImageData(image, lut, canvasImageDataData)
+ {
+ var minPixelValue = image.minPixelValue;
+ var canvasImageDataIndex = 0;
+ var storedPixelDataIndex = 0;
+ var numPixels = image.width * image.height * 4;
+ var storedPixelData = image.getPixelData();
+ var localLut = lut;
+ var localCanvasImageDataData = canvasImageDataData;
+ // NOTE: As of Nov 2014, most javascript engines have lower performance when indexing negative indexes.
+ // We have a special code path for this case that improves performance. Thanks to @jpambrun for this enhancement
+ if(minPixelValue < 0){
+ while(storedPixelDataIndex < numPixels) {
+ localCanvasImageDataData[canvasImageDataIndex++] = localLut[storedPixelData[storedPixelDataIndex++] + (-minPixelValue)]; // red
+ localCanvasImageDataData[canvasImageDataIndex++] = localLut[storedPixelData[storedPixelDataIndex++] + (-minPixelValue)]; // green
+ localCanvasImageDataData[canvasImageDataIndex] = localLut[storedPixelData[storedPixelDataIndex] + (-minPixelValue)]; // blue
+ storedPixelDataIndex+=2;
+ canvasImageDataIndex+=2;
+ }
+ }else{
+ while(storedPixelDataIndex < numPixels) {
+ localCanvasImageDataData[canvasImageDataIndex++] = localLut[storedPixelData[storedPixelDataIndex++]]; // red
+ localCanvasImageDataData[canvasImageDataIndex++] = localLut[storedPixelData[storedPixelDataIndex++]]; // green
+ localCanvasImageDataData[canvasImageDataIndex] = localLut[storedPixelData[storedPixelDataIndex]]; // blue
+ storedPixelDataIndex+=2;
+ canvasImageDataIndex+=2;
+ }
+ }
+ }
+
+ // Module exports
+ cornerstone.storedPixelDataToCanvasImageData = storedPixelDataToCanvasImageData;
+ cornerstone.storedColorPixelDataToCanvasImageData = storedColorPixelDataToCanvasImageData;
+
+ return cornerstone;
+}(cornerstone));
+
+/**
+ * This module contains a function to immediately redraw an image
+ */
+var cornerstone = (function (cornerstone) {
+
+ "use strict";
+
+ if(cornerstone === undefined) {
+ cornerstone = {};
+ }
+
+ /**
+ * Forces the image to be updated/redrawn for the specified enabled element
+ * @param element
+ */
+ function updateImage(element, invalidated) {
+ var enabledElement = cornerstone.getEnabledElement(element);
+
+ if(enabledElement.image === undefined) {
+ throw "updateImage: image has not been loaded yet";
+ }
+
+ cornerstone.drawImage(enabledElement, invalidated);
+ }
+
+ // module exports
+ cornerstone.updateImage = updateImage;
+
+ return cornerstone;
+}(cornerstone));
+/**
+ * This module contains functions to deal with getting and setting the viewport for an enabled element
+ */
+var cornerstone = (function (cornerstone) {
+
+ "use strict";
+
+ if(cornerstone === undefined) {
+ cornerstone = {};
+ }
+
+ function setViewport(element, viewport) {
+
+ var enabledElement = cornerstone.getEnabledElement(element);
+
+ enabledElement.viewport.scale = viewport.scale;
+ enabledElement.viewport.translation.x = viewport.translation.x;
+ enabledElement.viewport.translation.y = viewport.translation.y;
+ enabledElement.viewport.voi.windowWidth = viewport.voi.windowWidth;
+ enabledElement.viewport.voi.windowCenter = viewport.voi.windowCenter;
+ enabledElement.viewport.invert = viewport.invert;
+ enabledElement.viewport.pixelReplication = viewport.pixelReplication;
+ enabledElement.viewport.rotation = viewport.rotation;
+ enabledElement.viewport.hflip = viewport.hflip;
+ enabledElement.viewport.vflip = viewport.vflip;
+
+ // prevent window width from being < 1
+ if(enabledElement.viewport.voi.windowWidth < 1) {
+ enabledElement.viewport.voi.windowWidth = 1;
+ }
+ // prevent scale from getting too small
+ if(enabledElement.viewport.scale < 0.0001) {
+ enabledElement.viewport.scale = 0.25;
+ }
+
+ if(enabledElement.viewport.rotation===360 || enabledElement.viewport.rotation===-360) {
+ enabledElement.viewport.rotation = 0;
+ }
+
+ // Force the image to be updated since the viewport has been modified
+ cornerstone.updateImage(element);
+ }
+
+ /**
+ * Returns the viewport for the specified enabled element
+ * @param element
+ * @returns {*}
+ */
+ function getViewport(element) {
+ var enabledElement = cornerstone.getEnabledElement(element);
+
+ var viewport = enabledElement.viewport;
+ if(viewport === undefined) {
+ return undefined;
+ }
+ return {
+ scale : viewport.scale,
+ translation : {
+ x : viewport.translation.x,
+ y : viewport.translation.y
+ },
+ voi : {
+ windowWidth: viewport.voi.windowWidth,
+ windowCenter : viewport.voi.windowCenter
+ },
+ invert : viewport.invert,
+ pixelReplication: viewport.pixelReplication,
+ rotation: viewport.rotation,
+ hflip: viewport.hflip,
+ vflip: viewport.vflip
+ };
+ }
+
+
+ // module/private exports
+ cornerstone.getViewport = getViewport;
+ cornerstone.setViewport=setViewport;
+
+ return cornerstone;
+}(cornerstone));
Added: trunk/packages/orthanc-webviewer/trunk/debian/JS/js-url-1.8.6/README.md
===================================================================
--- trunk/packages/orthanc-webviewer/trunk/debian/JS/js-url-1.8.6/README.md (rev 0)
+++ trunk/packages/orthanc-webviewer/trunk/debian/JS/js-url-1.8.6/README.md 2015-03-02 09:58:59 UTC (rev 18890)
@@ -0,0 +1,89 @@
+# url()
+
+A simple, lightweight url parser for JavaScript (~1.6 Kb minified, ~0.6Kb gzipped).
+
+* [View the url demo](http://url.websanova.com)
+* [Download the lastest version of url](https://github.com/websanova/url/tags)
+
+
+## Notes
+
+For path(1) and path(-1) will always act as if the path is in the form `/some/path/` regardless of whether the original path was `/some/path` or `/some/path/`.
+
+
+## Examples
+
+```html
+http://rob:abcd1234@www.example.com/path/index.html?query1=test&silly=willy#test=hash&chucky=cheese
+```
+
+```js
+url(); // http://rob:abcd1234@www.example.com/path/index.html?query1=test&silly=willy#test=hash&chucky=cheese
+url('domain'); // example.com
+url('hostname'); // www.example.com
+url('sub'); // www
+url('.0') // (an empty string)
+url('.1') // www
+url('.2') // example
+url('.-1') // com
+url('auth') // rob:abcd1234
+url('user') // rob
+url('pass') // abcd1234
+url('port'); // 80
+url('protocol'); // http
+url('path'); // /path/index.html
+url('file'); // index.html
+url('filename'); // index
+url('fileext'); // html
+url('1'); // path
+url('2'); // index.html
+url('3'); // (an empty string)
+url('-1'); // index.html
+url(1); // path
+url(2); // index.html
+url(-1); // index.html
+url('?'); // query1=test&silly=willy
+url('?silly'); // willy
+url('?poo'); // null
+url('#'); // test=hash&chucky=cheese
+url('#chucky'); // cheese
+url('#poo'); // null
+```
+
+We can also pass a url in and use all the same options on it:
+
+```js
+url('domain', 'test.www.example.com/path/here'); // example.com
+url('hostname', 'test.www.example.com/path/here'); // test.www.example.com
+url('sub', 'test.www.example.com/path/here'); // test.www
+url('protocol', 'www.example.com/path/here'); // http
+url('path', 'http://www.example.com:8080/some/path'); // /some/path
+url('port', 'http://www.example.com:8080/some/path'); // 8080
+url('protocol', 'https://www.example.com:8080/some/path'); // https
+etc...
+```
+
+
+## jQuery
+
+Also include is a jQuery version of the plugin that can be called via $.url() with all the same options. If you're already using jQuery it may be better to use the jQuery version to avoid namespacing issues.
+
+
+## Grunt.js
+
+If you want to use Grunt you will need to install the required plugins locally using `npm install` in the root folder of your project. If you need to setup Grunt on your system you can follow my [Setting up Grunt.js](http://www.websanova.com/blog/javascript/how-to-setup-grunt) guide.
+
+
+## Resources
+
+* [More jQuery plugins by Websanova](http://websanova.com/plugins)
+* [Websanova JavaScript Extensions Project](http://websanova.com/extensions)
+* [jQuery Plugin Development Boilerplate](http://wboiler.websanova.com)
+* [The Ultimate Guide to Writing jQuery Plugins](http://www.websanova.com/blog/jquery/the-ultimate-guide-to-writing-jquery-plugins)
+
+
+## License
+
+MIT licensed
+
+Copyright (C) 2011-2012 Websanova http://www.websanova.com
\ No newline at end of file
Added: trunk/packages/orthanc-webviewer/trunk/debian/JS/js-url-1.8.6/url.jquery.json
===================================================================
--- trunk/packages/orthanc-webviewer/trunk/debian/JS/js-url-1.8.6/url.jquery.json (rev 0)
+++ trunk/packages/orthanc-webviewer/trunk/debian/JS/js-url-1.8.6/url.jquery.json 2015-03-02 09:58:59 UTC (rev 18890)
@@ -0,0 +1,35 @@
+{
+ "name": "url",
+ "title": "url jQuery Plugin",
+ "description": "A simple, lightweight url parser for JavaScript (~1.6 Kb minified, ~0.6Kb gzipped).",
+ "keywords": [
+ "websanova",
+ "url"
+ ],
+ "version": "1.8.6",
+ "author": {
+ "name": "Websanova",
+ "email": "rob at websanova.com",
+ "url": "http://websanova.com"
+ },
+ "maintainers": [
+ {
+ "name": "Websanova",
+ "email": "rob at websanova.com",
+ "url": "http://websanova.com"
+ }
+ ],
+ "licenses": [
+ {
+ "type": "MIT",
+ "url": "https://github.com/websanova/js-url#license"
+ }
+ ],
+ "bugs": "https://github.com/websanova/js-url/issues",
+ "homepage": "http://url.websanova.com",
+ "docs": "https://github.com/websanova/js-url#url",
+ "download": "https://github.com/websanova/js-url/tags",
+ "dependencies": {
+ "jquery": ">=1.5"
+ }
+}
Added: trunk/packages/orthanc-webviewer/trunk/debian/JS/js-url-1.8.6/url.js
===================================================================
--- trunk/packages/orthanc-webviewer/trunk/debian/JS/js-url-1.8.6/url.js (rev 0)
+++ trunk/packages/orthanc-webviewer/trunk/debian/JS/js-url-1.8.6/url.js 2015-03-02 09:58:59 UTC (rev 18890)
@@ -0,0 +1,81 @@
+window.url = (function() {
+ function isNumeric(arg) {
+ return !isNaN(parseFloat(arg)) && isFinite(arg);
+ }
+
+ return function(arg, url) {
+ var _ls = url || window.location.toString();
+
+ if (!arg) { return _ls; }
+ else { arg = arg.toString(); }
+
+ if (_ls.substring(0,2) === '//') { _ls = 'http:' + _ls; }
+ else if (_ls.split('://').length === 1) { _ls = 'http://' + _ls; }
+
+ url = _ls.split('/');
+ var _l = {auth:''}, host = url[2].split('@');
+
+ if (host.length === 1) { host = host[0].split(':'); }
+ else { _l.auth = host[0]; host = host[1].split(':'); }
+
+ _l.protocol=url[0];
+ _l.hostname=host[0];
+ _l.port=(host[1] || ((_l.protocol.split(':')[0].toLowerCase() === 'https') ? '443' : '80'));
+ _l.pathname=( (url.length > 3 ? '/' : '') + url.slice(3, url.length).join('/').split('?')[0].split('#')[0]);
+ var _p = _l.pathname;
+
+ if (_p.charAt(_p.length-1) === '/') { _p=_p.substring(0, _p.length-1); }
+ var _h = _l.hostname, _hs = _h.split('.'), _ps = _p.split('/');
+
+ if (arg === 'hostname') { return _h; }
+ else if (arg === 'domain') {
+ if (/^(([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\.){3}([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])$/.test(_h)) { return _h; }
+ return _hs.slice(-2).join('.');
+ }
+ //else if (arg === 'tld') { return _hs.slice(-1).join('.'); }
+ else if (arg === 'sub') { return _hs.slice(0, _hs.length - 2).join('.'); }
+ else if (arg === 'port') { return _l.port; }
+ else if (arg === 'protocol') { return _l.protocol.split(':')[0]; }
+ else if (arg === 'auth') { return _l.auth; }
+ else if (arg === 'user') { return _l.auth.split(':')[0]; }
+ else if (arg === 'pass') { return _l.auth.split(':')[1] || ''; }
+ else if (arg === 'path') { return _l.pathname; }
+ else if (arg.charAt(0) === '.')
+ {
+ arg = arg.substring(1);
+ if(isNumeric(arg)) {arg = parseInt(arg, 10); return _hs[arg < 0 ? _hs.length + arg : arg-1] || ''; }
+ }
+ else if (isNumeric(arg)) { arg = parseInt(arg, 10); return _ps[arg < 0 ? _ps.length + arg : arg] || ''; }
+ else if (arg === 'file') { return _ps.slice(-1)[0]; }
+ else if (arg === 'filename') { return _ps.slice(-1)[0].split('.')[0]; }
+ else if (arg === 'fileext') { return _ps.slice(-1)[0].split('.')[1] || ''; }
+ else if (arg.charAt(0) === '?' || arg.charAt(0) === '#')
+ {
+ var params = _ls, param = null;
+
+ if(arg.charAt(0) === '?') { params = (params.split('?')[1] || '').split('#')[0]; }
+ else if(arg.charAt(0) === '#') { params = (params.split('#')[1] || ''); }
+
+ if(!arg.charAt(1)) { return params; }
+
+ arg = arg.substring(1);
+ params = params.split('&');
+
+ for(var i=0,ii=params.length; i<ii; i++)
+ {
+ param = params[i].split('=');
+ if(param[0] === arg) { return param[1] || ''; }
+ }
+
+ return null;
+ }
+
+ return '';
+ };
+})();
+
+if(typeof jQuery !== 'undefined') {
+ jQuery.extend({
+ url: function(arg, url) { return window.url(arg, url); }
+ });
+}
\ No newline at end of file
Added: trunk/packages/orthanc-webviewer/trunk/debian/JS/jsPanel-2.3.3/LICENSE.TXT
===================================================================
--- trunk/packages/orthanc-webviewer/trunk/debian/JS/jsPanel-2.3.3/LICENSE.TXT (rev 0)
+++ trunk/packages/orthanc-webviewer/trunk/debian/JS/jsPanel-2.3.3/LICENSE.TXT 2015-03-02 09:58:59 UTC (rev 18890)
@@ -0,0 +1,39 @@
+The MIT License (MIT)
+
+Copyright (c) 2014 Stefan Sträßer, http://stefanstraesser.eu/
+
+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.
+
+Hiermit wird unentgeltlich jeder Person, die eine Kopie der Software und der
+zugehörigen Dokumentationen (die "Software") erhält, die Erlaubnis erteilt,
+sie uneingeschränkt zu benutzen, inklusive und ohne Ausnahme dem Recht, sie
+zu verwenden, kopieren, ändern, fusionieren, verlegen, verbreiten, unterlizenzieren
+und/oder zu verkaufen, und Personen, die diese Software erhalten, diese Rechte zu
+geben, unter den folgenden Bedingungen:
+
+Der obige Urheberrechtsvermerk und dieser Erlaubnisvermerk sind in allen Kopien
+oder Teilkopien der Software beizulegen.
+
+DIE SOFTWARE WIRD OHNE JEDE AUSDRÜCKLICHE ODER IMPLIZIERTE GARANTIE BEREITGESTELLT,
+EINSCHLIESSLICH DER GARANTIE ZUR BENUTZUNG FÜR DEN VORGESEHENEN ODER EINEM BESTIMMTEN
+ZWECK SOWIE JEGLICHER RECHTSVERLETZUNG, JEDOCH NICHT DARAUF BESCHRÄNKT. IN KEINEM
+FALL SIND DIE AUTOREN ODER COPYRIGHTINHABER FÜR JEGLICHEN SCHADEN ODER SONSTIGE
+ANSPRÜCHE HAFTBAR ZU MACHEN, OB INFOLGE DER ERFÜLLUNG EINES VERTRAGES, EINES DELIKTES
+ODER ANDERS IM ZUSAMMENHANG MIT DER SOFTWARE ODER SONSTIGER VERWENDUNG DER SOFTWARE
+ENTSTANDEN.
\ No newline at end of file
Added: trunk/packages/orthanc-webviewer/trunk/debian/JS/jsPanel-2.3.3/fonts/jsglyph.eot
===================================================================
(Binary files differ)
Property changes on: trunk/packages/orthanc-webviewer/trunk/debian/JS/jsPanel-2.3.3/fonts/jsglyph.eot
___________________________________________________________________
Added: svn:mime-type
+ application/octet-stream
Added: trunk/packages/orthanc-webviewer/trunk/debian/JS/jsPanel-2.3.3/fonts/jsglyph.svg
===================================================================
--- trunk/packages/orthanc-webviewer/trunk/debian/JS/jsPanel-2.3.3/fonts/jsglyph.svg (rev 0)
+++ trunk/packages/orthanc-webviewer/trunk/debian/JS/jsPanel-2.3.3/fonts/jsglyph.svg 2015-03-02 09:58:59 UTC (rev 18890)
@@ -0,0 +1,57 @@
+<?xml version="1.0" standalone="no"?>
+<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd" >
+<svg xmlns="http://www.w3.org/2000/svg">
+<metadata></metadata>
+<defs>
+<font id="jsglyphregular" horiz-adv-x="2048" >
+<font-face units-per-em="2048" ascent="1638" descent="-410" />
+<missing-glyph horiz-adv-x="500" />
+<glyph unicode="
" />
+<glyph unicode="◼" horiz-adv-x="500" d="M0 0v0v0v0v0z" />
+<glyph unicode="" d="M1405 1739l-514 -811l-139 80l-107 -585l454 385l-139 80zM208 398q-20 0 -34 -14t-14 -34v-304q0 -20 14 -34t34 -14h1584q20 0 34 14t14 34v304q0 20 -14 34t-34 14h-1584z" />
+<glyph unicode="" d="M208 1678q-20 0 -34 -14t-14 -34v-232v-72v-1193v-90v-5q1 -17 14.5 -28.5t30.5 -11.5h1590q17 0 30.5 11.5t14.5 28.5v5v90v1193v72v232q0 20 -14 34t-34 14h-1584zM340 1278h1320v-1100h-1320v1100z" />
+<glyph unicode="" d="M994 1156q-35 -2 -64 -20l-708 -441q-27 -16 -45.5 -49t-18.5 -65q0 -55 38.5 -94t93.5 -39q40 0 73 22l637 397l637 -397q33 -22 73 -22q55 0 93.5 39t38.5 94q0 32 -18.5 65t-45.5 49l-708 441q-33 20 -70 20h-6z" />
+<glyph unicode="" d="M994 448q-35 2 -64 20l-708 441q-27 16 -45.5 49t-18.5 65q0 55 38.5 94t93.5 39q42 0 73 -21l637 -398l637 398q31 21 73 21q55 0 93.5 -39t38.5 -94q0 -32 -18.5 -65t-45.5 -49l-708 -441q-33 -20 -70 -20h-6z" />
+<glyph unicode="" d="M374 1563q-19 0 -32.5 -10.5t-13.5 -26.5v-150h115v56q0 16 13.5 27t32.5 11h1291q19 0 32.5 -11t13.5 -27v-1043q0 -16 -13.5 -26.5t-32.5 -10.5h-65v-94h183q17 0 29.5 9.5t13.5 22.5v3v70v926v56v181q0 16 -13.5 26.5t-32.5 10.5h-1521zM113 1349q-19 0 -32.5 -11 t-13.5 -27v-180v-56v-926v-70v-4q1 -13 13.5 -22t29.5 -9h1527q17 0 29.5 9t13.5 22v4v70v926v56v180q0 16 -13.5 27t-32.5 11h-1521zM240 1038h1267v-854h-1267v854z" />
+<glyph unicode="" d="M1658 1637h-2q-35 0 -72 -22t-54 -53l-654 -1132l-270 468q-17 30 -54 51t-72 21q-60 0 -102.5 -42.5t-42.5 -102.5q0 -37 20 -72l395 -685q17 -30 54 -51.5t72 -21.5t72 21.5t54 51.5l779 1349q20 35 20 75q0 59 -42 101.5t-101 43.5z" />
+<glyph unicode="" d="M291 1456q-18 -19 -30.5 -49.5t-12.5 -56.5q0 -27 13.5 -59t32.5 -51l491 -491l-491 -490q-19 -19 -32 -50.5t-13 -57.5q0 -63 45 -108t108 -45q26 0 57.5 13t50.5 32l491 490l490 -490q19 -19 50.5 -32t57.5 -13q63 0 108 45t45 108q0 26 -13 57.5t-32 50.5l-490 490 l490 491q19 19 32 50.5t13 57.5q0 63 -45 108t-108 45q-26 0 -57.5 -13t-50.5 -32l-490 -490l-491 490q-19 19 -50.5 32.5t-58.5 13.5t-59 -13.5t-51 -32.5z" />
+<glyph unicode="" d="M1354 896q-2 35 -20 64l-441 708q-16 27 -49 45.5t-65 18.5q-55 0 -94 -38.5t-39 -93.5q0 -42 21 -73l398 -637l-398 -637q-21 -31 -21 -72q0 -55 39 -94t94 -39q32 0 65 19t49 46l441 707q20 33 20 70v6z" />
+<glyph unicode="" d="M646 896q2 35 20 64l441 708q16 27 49 45.5t65 18.5q55 0 94 -38.5t39 -93.5q0 -42 -21 -73l-398 -637l398 -637q21 -32 21 -72q0 -55 -39 -94t-94 -39q-32 0 -65 19t-49 46l-441 707q-20 33 -20 70v6z" />
+<glyph unicode="" d="M998 1623q-53 -1 -90.5 -39t-37.5 -91v-2v-485h-485h-2q-54 0 -92 -38t-38 -92t38 -92t92 -38h2h485v-485v-2q0 -54 38 -92t92 -38t92 38t38 92v2v485h485h2q54 0 92 38t38 92t-38 92t-92 38h-2h-485v485v2q0 54 -38 92t-92 38h-2z" />
+<glyph unicode="" d="M385 1006h-2q-54 0 -92 -38t-38 -92t38 -92t92 -38h2h1230h2q54 0 92 38t38 92t-38 92t-92 38h-2h-1230z" />
+<glyph unicode="" d="M1000 1709q-77 0 -131.5 -19.5t-54.5 -46.5q0 -24 44 -42.5t109 -22.5l-224 -53l-258 -60h515h515l-258 60l-224 53q65 4 109 22.5t44 42.5q0 27 -54.5 46.5t-131.5 19.5zM485 1464v-62h1030v62h-1030zM493 1283l89 -1284h840l85 1284h-1014z" />
+<glyph unicode="" d="M992 210q-169 2 -312 86.5t-226 228.5t-83 314q0 128 50 244.5t134 200.5t200.5 134t244.5 50t244.5 -50t200.5 -134t134 -200.5t50 -244.5t-50 -244.5t-134 -200.5t-200.5 -134t-244.5 -50h-8zM900 334h200q8 0 14 6t6 14v640q0 8 -6 14t-14 6h-200q-8 0 -14 -6t-6 -14 v-640q0 -8 6 -14t14 -6zM902 1122h196q9 0 15.5 6.5t6.5 15.5v156q0 9 -6.5 15.5t-15.5 6.5h-196q-9 0 -15.5 -6.5t-6.5 -15.5v-156q0 -9 6.5 -15.5t15.5 -6.5zM280 1679q-50 0 -85 -35.5t-35 -84.5v-1440q0 -49 35 -84.5t85 -35.5h1440q50 0 85 35.5t35 84.5v1440 q0 49 -35 84.5t-85 35.5h-1440zM1000 1599q155 0 295.5 -60t242.5 -162t162 -242.5t60 -295.5t-60 -295.5t-162 -242.5t-242.5 -162t-295.5 -60t-295.5 60t-242.5 162t-162 242.5t-60 295.5t60 295.5t162 242.5t242.5 162t295.5 60z" />
+<glyph unicode="" d="M280 1679q-50 0 -85 -35.5t-35 -84.5v-1440q0 -49 35 -84.5t85 -35.5h1440q50 0 85 35.5t35 84.5v1440q0 49 -35 84.5t-85 35.5h-1440zM1000 1624v1v-1q17 0 34.5 -11t25.5 -26l707 -1412q7 -14 7 -31q0 -28 -20 -47.5t-48 -19.5h-1412q-28 0 -48 19.5t-20 47.5 q0 17 7 31l707 1412q8 15 25.5 26t34.5 11zM1000 1406l-597 -1194h1194zM933 1075h134q22 0 37.5 -15.5t15.5 -37.5v-426q0 -22 -15.5 -37.5t-37.5 -15.5h-134q-22 0 -37.5 15.5t-15.5 37.5v426q0 22 15.5 37.5t37.5 15.5zM920 459h160q16 0 28 -11.5t12 -28.5v-80 q0 -17 -12 -28.5t-28 -11.5h-160q-16 0 -28 11.5t-12 28.5v80q0 17 12 28.5t28 11.5z" />
+<glyph unicode="" d="M662 1305q-55 0 -93 -38l-184 -185q-38 -38 -38 -92t38 -92l246 -246l-246 -247q-38 -38 -38 -92t38 -92l184 -185q38 -38 92.5 -38t92.5 38l246 246l246 -246q38 -38 92.5 -38t92.5 38l184 185q38 38 38 92t-38 92l-246 247l246 246q38 38 38 92t-38 92l-184 185 q-38 38 -92.5 38t-92.5 -38l-246 -246l-246 246q-38 38 -92 38z" />
+<glyph unicode="" d="M160 1038v-1040h1680v1040h-1680zM322 975h2q24 0 40 -13l636 -505l636 505q16 13 40 13q26 0 45 -19t19 -45v-786v-64h-128v64v654l-572 -454q-18 -14 -40 -14t-40 14l-572 454v-654v-64h-128v64v786q0 26 18.5 44.5t43.5 19.5z" />
+<glyph unicode="" d="M227 1045l750 -643l750 643h-1500zM138 989v-894l501 465zM1816 989l-502 -429l502 -465v894zM715 494l-524 -487h1571l-524 487l-229 -196l-32 -28l-33 28zM138 12v-5h4zM1816 12l-4 -5h4v5z" />
+<glyph unicode="" d="M357 875v741l7 -4q14 -7 641.5 -370t629.5 -365l-15 -9q-14 -10 -41 -26t-58 -34q-528 -305 -630 -364q-121 -70 -254 -147t-200.5 -116t-69.5 -40l-10 -6v740z" />
+<glyph unicode="" d="M1000 871v740l4 -4q6 -8 280.5 -371t275.5 -364t-50 -69q-173 -228 -276 -364q-224 -294 -229 -302l-5 -7v741zM440 871v740l4 -4q6 -8 280.5 -371t275.5 -364t-50 -69q-173 -228 -276 -364q-224 -294 -229 -302l-5 -7v741z" />
+<glyph unicode="" d="M1000 871v740l-4 -4q-6 -8 -280.5 -371t-275.5 -364t50 -69q173 -228 276 -364q224 -294 229 -302l5 -7v741zM1560 871v740l-4 -4q-6 -8 -280.5 -371t-275.5 -364t50 -69q173 -228 276 -364q224 -294 229 -302l5 -7v741z" />
+<glyph unicode="" d="M620 1611v-741v-740l5 6q11 16 229 303q103 136 276 364q51 67 49 69q-1 1 -275.5 364t-280.5 371zM1180 1608v-1480h200v1480h-200z" />
+<glyph unicode="" d="M1380 1611v-741v-740l-5 6q-11 16 -229 303q-103 136 -276 364q-51 67 -49 69q1 1 275.5 364t280.5 371zM820 1608v-1480h-200v1480h200z" />
+<glyph unicode="" d="M337 1611v-741v-740l5 6q11 16 229 303q103 136 276 364q51 67 49 69q-1 1 -275.5 364t-280.5 371zM897 1611v-741v-740l5 6q11 16 229 303q103 136 276 364q51 67 49 69q-1 1 -275.5 364t-280.5 371zM1457 1608v-1480h206v1480h-206z" />
+<glyph unicode="" d="M1663 1611v-741v-740l-5 6q-11 16 -229 303q-103 136 -276 364q-51 67 -49 69q1 1 275.5 364t280.5 371zM1103 1611v-741v-740l-5 6q-11 16 -229 303q-103 136 -276 364q-51 67 -49 69q1 1 275.5 364t280.5 371zM543 1608v-1480h-206v1480h206z" />
+<glyph unicode="" d="M261 363h1480v200h-1480v-200zM259 676h740h740l-6 5q-1 1 -40.5 38.5t-115.5 109t-147 139.5q-136 129 -364 345q-67 64 -69 62q-2 -1 -365 -344t-370 -351z" />
+<glyph unicode="" d="M374 1502h1252v-1252h-1252v1252z" />
+<glyph unicode="" d="M680 1502v-1252h240v1252h-240zM1080 1502v-1252h240v1252h-240z" />
+<glyph unicode="" d="M1022 517v358v358l310 -179l310 -179l-310 -179zM358 1019h851v-288h-851v288z" />
+<glyph unicode="" d="M978 517v358v358l-310 -179l-310 -179l310 -179zM1642 1019h-851v-288h851v288z" />
+<glyph unicode="" d="M642 897h358h358l-179 310l-179 310l-179 -310zM1144 233v851h-288v-851h288z" />
+<glyph unicode="" d="M642 853h358h358l-179 -310l-179 -310l-179 310zM1144 1517v-851h-288v851h288z" />
+<glyph unicode="" d="M1001 1531l-37 -125l-110 -382l-397 14l-131 5l108 -73l330 -223l-137 -374l-44 -123l103 80l313 245l314 -245l102 -80l-44 122l-136 374l331 222l108 73l-131 -4l-397 -14l-110 383zM1000 1260l82 -285l8 -28l29 1l297 10l-193 -130h-446l-193 130l297 -10l29 -1l8 28z " />
+<glyph unicode="" d="M1416 251l-416 324l-415 -325l180 496l-438 294l528 -18l145 507l145 -506l528 18l-437 -295z" />
+<glyph unicode="" d="M1001 1531l-37 -125l-110 -382l-397 14l-131 5l108 -73l330 -223l-137 -374l-44 -123l102 81l314 244l314 -245l102 -81l-44 123l-136 374l330 222l109 73l-131 -4l-397 -14l-110 383zM1000 1260l82 -285l8 -28l29 1l297 10l-247 -166l-24 -17l10 -27l101 -279l-234 183 l-22 18l-24 -18l-234 -182l102 278l10 28l-24 16l-246 166l297 -10l29 -1l8 28z" />
+<glyph unicode="" d="M950 1373v-85v-190h-630h-50v-50v-320v-50h50h630v-190v-85l74 41l720 400l79 44l-79 44l-720 400zM1050 1203l567 -315l-567 -315v155v50h-50h-630v220h630h50v50v155z" />
+<glyph unicode="" d="M1143 1373v-85v-190h630h50v-50v-320v-50h-50h-630v-190v-85l-74 41l-720 400l-79 44l79 44l720 400zM1043 1203l-567 -315l567 -315v155v50h50h630v220h-630h-50v50v155z" />
+<glyph unicode="" d="M1485 792h-85h-190v-630v-50h-50h-320h-50v50v630h-190h-85l41 74l400 720l44 78l44 -78l400 -720zM1315 892l-315 567l-315 -567h155h50v-50v-630h220v630v50h50h155z" />
+<glyph unicode="" d="M1485 984h-85h-190v630v50h-50h-320h-50v-50v-630h-190h-85l41 -74l400 -720l44 -78l44 78l400 720zM1315 884l-315 -567l-315 567h155h50v50v630h220v-630v-50h50h155z" />
+<glyph unicode="" d="M1000 1468q-128 0 -244.5 -50t-200.5 -134t-134 -200.5t-50 -244.5t50 -244.5t134 -200.5t200.5 -134t244.5 -50t244.5 50t200.5 134t134 200.5t50 244.5t-50 244.5t-134 200.5t-200.5 134t-244.5 50zM831 1328h1h336q25 0 42.5 -17.5t17.5 -42.5v-303q0 -25 -17.5 -42.5 t-42.5 -17.5h-277v-185h277h1q25 0 42.5 -17t17.5 -42t-17.5 -42.5t-42.5 -17.5h-1h-336q-25 0 -42.5 17.5t-17.5 42.5v304q0 25 17.5 42t42.5 17h277v185h-277h-3q-25 0 -42 17t-17 42t17 42.5t42 17.5h2zM1000 524q46 0 78 -32t32 -78t-32 -78t-78 -32t-78 32t-32 78 t32 78t78 32zM280 1679q-50 0 -85 -35.5t-35 -84.5v-1440q0 -49 35 -84.5t85 -35.5h1440q50 0 85 35.5t35 84.5v1440q0 49 -35 84.5t-85 35.5h-1440zM1000 1599q155 0 295.5 -60t242.5 -162t162 -242.5t60 -295.5t-60 -295.5t-162 -242.5t-242.5 -162t-295.5 -60t-295.5 60 t-242.5 162t-162 242.5t-60 295.5t60 295.5t162 242.5t242.5 162t295.5 60z" />
+<glyph unicode="" d="M989 -1q-169 2 -322.5 69.5t-264.5 180t-176.5 267t-65.5 323.5q0 171 66.5 326.5t179 268t268 179t326.5 66.5t326.5 -66.5t268 -179t179 -268t66.5 -326.5t-66.5 -326.5t-179 -268t-268 -179t-326.5 -66.5h-11zM867 165h266q11 0 19 8t8 19v854q0 11 -8 19t-19 8h-266 q-11 0 -19 -8t-8 -19v-854q0 -11 8 -19t19 -8zM870 1217h260q12 0 21 9t9 21v207q0 12 -9 21t-21 9h-260q-12 0 -21 -9t-9 -21v-207q0 -12 9 -21t21 -9z" />
+<glyph unicode="" d="M989 1679q-169 -2 -322.5 -69.5t-264.5 -180t-176.5 -267t-65.5 -323.5q0 -171 66.5 -326.5t179 -268t268 -179t326.5 -66.5t326.5 66.5t268 179t179 268t66.5 326.5t-66.5 326.5t-179 268t-268 179t-326.5 66.5h-11zM867 1513h266q11 0 19 -8t8 -19v-854q0 -11 -8 -19 t-19 -8h-266q-11 0 -19 8t-8 19v854q0 11 8 19t19 8zM870 461h260q12 0 21 -9t9 -21v-207q0 -12 -9 -21t-21 -9h-260q-12 0 -21 9t-9 21v207q0 12 9 21t21 9z" />
+<glyph unicode="" d="M989 1679q-169 -2 -322.5 -69.5t-264.5 -180t-176.5 -267t-65.5 -323.5q0 -171 66.5 -326.5t179 -268t268 -179t326.5 -66.5t326.5 66.5t268 179t179 268t66.5 326.5t-66.5 326.5t-179 268t-268 179t-326.5 66.5h-11zM775 1511h450q33 0 56 -23.5t23 -56.5v-405 q0 -33 -23 -56t-56 -23h-370v-247h370h1q33 0 56 -23t23 -56t-23 -56.5t-56 -23.5h-1h-450q-33 0 -56 23.5t-23 56.5v405q0 33 23 56t56 23h370v247h-370h-1q-33 0 -56 23t-23 56t23 56.5t56 23.5h1zM1000 439q61 0 104 -43t43 -104t-43 -104t-104 -43t-104 43t-43 104 t43 104t104 43z" />
+<glyph unicode="" d="M1000 -2q-168 0 -321 65.5t-263.5 176t-176 263.5t-65.5 321t65.5 321t176 264t263.5 176.5t321 65.5t321 -65.5t263.5 -176.5t176 -264t65.5 -321t-65.5 -321t-176 -263.5t-263.5 -176t-321 -65.5zM1000 133q141 0 269 54.5t221 147t147.5 220.5t54.5 269 q0 188 -92.5 347.5t-252 252t-347.5 92.5t-347.5 -92.5t-252 -252t-92.5 -347.5q0 -141 54.5 -269t147.5 -220.5t221 -147t269 -54.5zM900 308q-8 0 -14 6t-6 14v640q0 8 6 14t14 6h200q8 0 14 -6t6 -14v-640q0 -8 -6 -14t-14 -6h-200zM902 1140q-9 0 -15.5 7t-6.5 16v155 q0 9 6.5 15.5t15.5 6.5h196q9 0 15.5 -6.5t6.5 -15.5v-155q0 -9 -6.5 -16t-15.5 -7h-196z" />
+<glyph unicode="" d="M1000 1651q-168 0 -321 -65.5t-263.5 -176.5t-176 -264t-65.5 -321t65.5 -321t176 -263.5t263.5 -176t321 -65.5t321 65.5t263.5 176t176 263.5t65.5 321t-65.5 321t-176 264t-263.5 176.5t-321 65.5zM1000 1516q188 0 347.5 -92.5t252 -252t92.5 -347.5 q0 -141 -54.5 -269t-147.5 -220.5t-221 -147t-269 -54.5t-269 54.5t-221 147t-147.5 220.5t-54.5 269q0 188 92.5 347.5t252 252t347.5 92.5zM900 1340q-8 0 -14 -6t-6 -14v-640q0 -8 6 -14t14 -6h200q8 0 14 6t6 14v640q0 8 -6 14t-14 6h-200zM902 508q-9 0 -15.5 -6.5 t-6.5 -15.5v-155q0 -9 6.5 -16t15.5 -7h196q9 0 15.5 7t6.5 16v155q0 9 -6.5 15.5t-15.5 6.5h-196z" />
+<glyph unicode="" d="M1110 391q0 -46 -32 -78.5t-78 -32.5t-78 32.5t-32 78.5t32 78t78 32t78 -32t32 -78zM832 1335h-1q-25 0 -42.5 -17t-17.5 -42t17.5 -42.5t42.5 -17.5h1h277v-184h-277q-25 0 -42.5 -17.5t-17.5 -42.5v-304q0 -25 17.5 -42t42.5 -17h336h3q25 0 42 17t17 42t-17 42.5 t-42 17.5h-3h-277v185h277q25 0 42.5 17t17.5 42v304q0 25 -17.5 42t-42.5 17h-336zM1000 1651q-168 0 -321 -65.5t-263.5 -176.5t-176 -264t-65.5 -321t65.5 -321t176 -263.5t263.5 -176t321 -65.5t321 65.5t263.5 176t176 263.5t65.5 321t-65.5 321t-176 264t-263.5 176.5 t-321 65.5zM1000 1516q141 0 269 -54.5t220.5 -147.5t147 -221t54.5 -269t-54.5 -269t-147 -220.5t-220.5 -147t-269 -54.5t-269 54.5t-220.5 147t-147 220.5t-54.5 269t54.5 269t147 221t220.5 147.5t269 54.5z" />
+</font>
+</defs></svg>
\ No newline at end of file
Added: trunk/packages/orthanc-webviewer/trunk/debian/JS/jsPanel-2.3.3/fonts/jsglyph.ttf
===================================================================
(Binary files differ)
Property changes on: trunk/packages/orthanc-webviewer/trunk/debian/JS/jsPanel-2.3.3/fonts/jsglyph.ttf
___________________________________________________________________
Added: svn:mime-type
+ application/octet-stream
Added: trunk/packages/orthanc-webviewer/trunk/debian/JS/jsPanel-2.3.3/fonts/jsglyph.woff
===================================================================
(Binary files differ)
Property changes on: trunk/packages/orthanc-webviewer/trunk/debian/JS/jsPanel-2.3.3/fonts/jsglyph.woff
___________________________________________________________________
Added: svn:mime-type
+ application/octet-stream
Added: trunk/packages/orthanc-webviewer/trunk/debian/JS/jsPanel-2.3.3/fonts/jsglyph.woff2
===================================================================
(Binary files differ)
Property changes on: trunk/packages/orthanc-webviewer/trunk/debian/JS/jsPanel-2.3.3/fonts/jsglyph.woff2
___________________________________________________________________
Added: svn:mime-type
+ application/octet-stream
Added: trunk/packages/orthanc-webviewer/trunk/debian/JS/jsPanel-2.3.3/images/close-20-333.png
===================================================================
(Binary files differ)
Property changes on: trunk/packages/orthanc-webviewer/trunk/debian/JS/jsPanel-2.3.3/images/close-20-333.png
___________________________________________________________________
Added: svn:mime-type
+ application/octet-stream
Added: trunk/packages/orthanc-webviewer/trunk/debian/JS/jsPanel-2.3.3/images/close-20.png
===================================================================
(Binary files differ)
Property changes on: trunk/packages/orthanc-webviewer/trunk/debian/JS/jsPanel-2.3.3/images/close-20.png
___________________________________________________________________
Added: svn:mime-type
+ application/octet-stream
Added: trunk/packages/orthanc-webviewer/trunk/debian/JS/jsPanel-2.3.3/images/icon-sprite-16x16.jpg
===================================================================
(Binary files differ)
Property changes on: trunk/packages/orthanc-webviewer/trunk/debian/JS/jsPanel-2.3.3/images/icon-sprite-16x16.jpg
___________________________________________________________________
Added: svn:mime-type
+ application/octet-stream
Added: trunk/packages/orthanc-webviewer/trunk/debian/JS/jsPanel-2.3.3/images/icon-sprite-20x20.jpg
===================================================================
(Binary files differ)
Property changes on: trunk/packages/orthanc-webviewer/trunk/debian/JS/jsPanel-2.3.3/images/icon-sprite-20x20.jpg
___________________________________________________________________
Added: svn:mime-type
+ application/octet-stream
Added: trunk/packages/orthanc-webviewer/trunk/debian/JS/jsPanel-2.3.3/images/icon-sprite-32x32.jpg
===================================================================
(Binary files differ)
Property changes on: trunk/packages/orthanc-webviewer/trunk/debian/JS/jsPanel-2.3.3/images/icon-sprite-32x32.jpg
___________________________________________________________________
Added: svn:mime-type
+ application/octet-stream
Added: trunk/packages/orthanc-webviewer/trunk/debian/JS/jsPanel-2.3.3/images/resize-handle.png
===================================================================
(Binary files differ)
Property changes on: trunk/packages/orthanc-webviewer/trunk/debian/JS/jsPanel-2.3.3/images/resize-handle.png
___________________________________________________________________
Added: svn:mime-type
+ application/octet-stream
Added: trunk/packages/orthanc-webviewer/trunk/debian/JS/jsPanel-2.3.3/images/ui-icons_454545_256x240.png
===================================================================
(Binary files differ)
Property changes on: trunk/packages/orthanc-webviewer/trunk/debian/JS/jsPanel-2.3.3/images/ui-icons_454545_256x240.png
___________________________________________________________________
Added: svn:mime-type
+ application/octet-stream
Added: trunk/packages/orthanc-webviewer/trunk/debian/JS/jsPanel-2.3.3/jquery.jspanel.css
===================================================================
--- trunk/packages/orthanc-webviewer/trunk/debian/JS/jsPanel-2.3.3/jquery.jspanel.css (rev 0)
+++ trunk/packages/orthanc-webviewer/trunk/debian/JS/jsPanel-2.3.3/jquery.jspanel.css 2015-03-02 09:58:59 UTC (rev 18890)
@@ -0,0 +1,524 @@
+/* jsPanel.css version 2.3.0 - 2014-12-17 09:22 */
+ at font-face {
+ font-family: 'jsglyphregular';
+ src: url('fonts/jsglyph.eot');
+ src: url('fonts/jsglyph.eot?#iefix') format('embedded-opentype'),
+ url('fonts/jsglyph.woff2') format('woff2'),
+ url('fonts/jsglyph.woff') format('woff'),
+ url('fonts/jsglyph.ttf') format('truetype'),
+ url('fonts/jsglyph.svg#jsglyphregular') format('svg');
+ font-weight: normal;
+ font-style: normal;
+}
+.jsglyph{ font-family: "jsglyphregular"; }
+
+.jsglyph-remove:before{ content: "\e007"; } /* unicode  */
+.jsglyph-minimize:before{ content: "\e001"; }
+.jsglyph-maximize:before{ content: "\e002"; }
+.jsglyph-chevron-up:before{ content: "\e003"; }
+.jsglyph-chevron-down:before{ content: "\e004"; }
+.jsglyph-normalize:before{ content: "\e005"; }
+.jsglyph-circle2-exclamationmark:before{ content:"\e02c"; color:red; font-size:14px; }
+
+.jsPanel, .jsPanel-hdr-r, .jsPanel-hdr-l, .jsPanel-hdr-r span img, .jsPanel-content{
+ margin: 0; padding: 0; border: 0; font-size: 100%; line-height: 1.5em; vertical-align: baseline;
+}
+.jsPanel{
+ display: none;
+ overflow: hidden;
+ position: absolute;
+ border-radius: 3px;
+}
+.jsPanel-hdr{
+ min-height: 26px;
+ padding: 2px 0 4px 2px;
+}
+.jsPanel-hdr *{
+ font-size: 16px;
+}
+.jsPanel-hdr-r{
+ position: absolute;
+ top: 0;
+ right: 0;
+}
+h3.jsPanel-title{
+ float: left;
+ width: calc(100% - 90px);
+ white-space: nowrap;
+ overflow: hidden;
+ text-align: left;
+ text-overflow: ellipsis;
+ margin: 0;
+ font-variant: small-caps;
+ font-weight: normal;
+ cursor: move;
+ min-height: 20px;
+ padding: 0 5px;
+}
+.jsPanel-hdr-r div{
+ float: right;
+ cursor: pointer;
+ margin-left: 1px;
+ width: auto;
+ height: auto;
+ min-width: 20px;
+ min-height: 20px;
+ overflow: hidden;
+}
+
+.jsPanel-btn-close{ background: url("images/icon-sprite-20x20.jpg") 20px 0 repeat no-repeat; }
+.jsPanel-btn-max{ background: url("images/icon-sprite-20x20.jpg") 40px 0 repeat no-repeat; }
+.jsPanel-btn-norm{ background: url("images/icon-sprite-20x20.jpg") 60px 0 repeat no-repeat; display: none; }
+.jsPanel-btn-min{ background: url("images/icon-sprite-20x20.jpg") 80px 0 repeat no-repeat; }
+.jsPanel-btn-small{ background: url("images/icon-sprite-20x20.jpg") 100px 0 repeat no-repeat; }
+.jsPanel-btn-smallrev{ background: url("images/icon-sprite-20x20.jpg") 120px 0 repeat no-repeat; display: none; }
+
+
+.jsPanel-hdr-toolbar {
+ clear: both;
+ font-size: 16px;
+ margin-top: 23px;
+ height: auto;
+ padding: 0 5px;
+ width: auto;
+}
+.jsPanel-hdr-toolbar img{
+ cursor: pointer;
+ margin-bottom: 4px;
+ margin-right: 5px;
+}
+.jsPanel-content {
+ font-size: 12px;
+ position: relative;
+ width: 100%;
+ overflow: hidden;
+}
+.jsPanel-ftr{
+ cursor: move;
+ display: none;
+ font-size: 12px;
+ height: auto;
+ padding: 0;
+ text-align: right;
+}
+.jsPanel-ftr button{
+ margin: 5px;
+}
+/* change the default jQuery-UI resize icon */
+.ui-icon, .ui-widget-content .ui-icon {
+ background-image: url("images/ui-icons_454545_256x240.png");
+}
+.ui-icon-gripsmall-diagonal-se {
+ background-position: -81px -224px;
+}
+
+/* clearfix */
+.jsPanel-clearfix:after {
+ content: ".";
+ display: block;
+ height: 0;
+ clear: both;
+ visibility: hidden;
+}
+
+/* container that takes the minified jsPanels */
+#jsPanel-min-container{
+ position:fixed;
+ left:0;
+ bottom:0;
+ width:auto;
+ height:28px;
+ background:transparent;
+ z-index:1000;
+}
+
+/* css for the modal backdrop --------------------------- */
+.jsPanel-backdrop{
+ position:absolute;
+ top:0;
+ left:0;
+ z-index:1001;
+ width:100%;
+ background:rgba(0,0,0,0.8);
+}
+.jsPanel-backdrop-inner{
+ position:absolute;
+ width:100%;
+}
+/* THEMES ------------------------------------------------------------------------- */
+
+/* default ------------------------------------------- */
+.jsPanel.jsPanel-theme-default{
+ background: none repeat scroll 0 0 #fff;
+ box-shadow: 0 0 6px rgba(0, 33, 50, 0.1), 0 7px 25px rgba(17, 38, 60, 0.4);
+}
+.jsPanel-hdr.jsPanel-theme-default{
+ color: #000;
+ font-family: tahoma,arial,verdana,sans-serif;
+ font-weight: normal;
+}
+.jsPanel-hdr.jsPanel-theme-default h3{
+ color: #000;
+}
+.jsPanel-hdr.jsPanel-theme-default h3 small{
+ color: #000;
+ font-size: 65%;
+}
+.jsPanel-content.jsPanel-theme-default{
+ background: none repeat scroll 0 0 #FFFFFF;
+ color: #000;
+ font-family: tahoma,arial,verdana,sans-serif;
+ outline: 1px solid #bbb;
+}
+.jsPanel-ftr.jsPanel-theme-default{
+ font-size: 12px;
+ height: auto;
+ max-height: 40px;
+ min-height: 3px;
+ padding-right: 25px;
+ text-align: right;
+}
+
+/* light ------------------------------------------- */
+.jsPanel.jsPanel-theme-light{ background: #f1f1f1; box-shadow: 0 0 6px rgba(0, 33, 50, 0.1), 0 7px 25px rgba(17, 38, 60, 0.4); }
+.jsPanel-hdr.jsPanel-theme-light{ color: #000; font-family: tahoma,arial,verdana,sans-serif; font-weight: normal; background: #f1f1f1; }
+.jsPanel-hdr.jsPanel-theme-light h3{ color: #000; }
+.jsPanel-hdr.jsPanel-theme-light h3 small{ color: #000; font-size: 65%; }
+.jsPanel-content.jsPanel-theme-light { background: none repeat scroll 0 0 #FFFFFF; color: #000; font-family: tahoma,arial,verdana,sans-serif; outline: 1px solid #bbb; }
+.jsPanel-ftr.jsPanel-theme-light{ color: #000; font-family: tahoma,arial,verdana,sans-serif; font-weight: normal; background: #f1f1f1; }
+
+/* medium -------------------------------------------- */
+.jsPanel.jsPanel-theme-medium{ background: #c2c2c2; box-shadow: 0 0 6px rgba(0, 33, 50, 0.1), 0 7px 25px rgba(17, 38, 60, 0.4); }
+.jsPanel-hdr.jsPanel-theme-medium{ color: #000; font-family: tahoma,arial,verdana,sans-serif; font-weight: normal; background: #c2c2c2; }
+.jsPanel-hdr.jsPanel-theme-medium h3{ color: #000; }
+.jsPanel-hdr.jsPanel-theme-medium h3 small{ color: #000; font-size: 65%; }
+.jsPanel-content.jsPanel-theme-medium { background: none repeat scroll 0 0 #fff; color: #000; font-family: tahoma,arial,verdana,sans-serif; outline: 1px solid #bbb; }
+.jsPanel-ftr.jsPanel-theme-medium{ color: #000; font-family: tahoma,arial,verdana,sans-serif; font-weight: normal; background: #c2c2c2; }
+
+/* dark ---------------------------------------------- */
+.jsPanel.jsPanel-theme-dark{ background: #828282; box-shadow: 0 0 6px rgba(0, 33, 50, 0.1), 0 7px 25px rgba(17, 38, 60, 0.4); }
+.jsPanel-hdr.jsPanel-theme-dark{ color: #fff; font-family: tahoma,arial,verdana,sans-serif; font-weight: normal; background: #828282; }
+.jsPanel-hdr.jsPanel-theme-dark h3{ color: #fff; }
+.jsPanel-hdr.jsPanel-theme-dark h3 small{ color: #fff; font-size: 65%; }
+.jsPanel-content.jsPanel-theme-dark { background: none repeat scroll 0 0 #fff; color: #000; font-family: tahoma,arial,verdana,sans-serif; outline: 1px solid #bbb; }
+.jsPanel-ftr.jsPanel-theme-dark{ color: #fff; font-family: tahoma,arial,verdana,sans-serif; font-weight: normal; background: #828282; }
+
+/* black ---------------------------------------------- */
+/* .jsPanel.jsPanel-theme-black{ background: -moz-linear-gradient(center top , #4a4a4a 0px, black 100%) repeat scroll 0 0 #4a4a4a; box-shadow: 0 0 3px #333; } */
+.jsPanel.jsPanel-theme-black{ background: linear-gradient(#4a4a4a 0px, black 100%) repeat scroll 0 0 #4a4a4a; background: -ms-linear-gradient(#4a4a4a 0px, black 100%) repeat scroll 0 0 #4a4a4a; box-shadow: 0 0 3px #333; }
+.jsPanel-hdr.jsPanel-theme-black{ color: #fff; font-family: tahoma,arial,verdana,sans-serif; font-weight: normal; background: transparent; }
+.jsPanel-hdr.jsPanel-theme-black h3{ color: #fff; }
+.jsPanel-hdr.jsPanel-theme-black h3 small{ color: #fff; font-size: 65%; }
+.jsPanel-content.jsPanel-theme-black { background: transparent; color: #c3c3c3; }
+.jsPanel-ftr.jsPanel-theme-black{ color: #fff; font-family: tahoma,arial,verdana,sans-serif; font-weight: normal; background: transparent; }
+
+/* primary ---------------------------------------------- */
+.jsPanel.jsPanel-theme-primary{ background: none repeat scroll 0 0 #fff; box-shadow: 0 0 6px rgba(0, 33, 50, 0.1), 0 7px 25px rgba(17, 38, 60, 0.4); }
+.jsPanel-hdr.jsPanel-theme-primary{ color: #ffffff; font-family: tahoma,arial,verdana,sans-serif; font-weight: normal; background: #2FA4E7; }
+.jsPanel-hdr.jsPanel-theme-primary h3{ color: #fff; }
+.jsPanel-hdr.jsPanel-theme-primary h3 small{ color: #fff; font-size: 65%; }
+.jsPanel-content.jsPanel-theme-primary { background: none repeat scroll 0 0 #ffffff; color: #000000; font-family: tahoma,arial,verdana,sans-serif; outline: 1px solid #bbb; }
+.jsPanel-ftr.jsPanel-theme-primary{}
+
+/* success --------------------------------------------- */
+.jsPanel.jsPanel-theme-success{ background: none repeat scroll 0 0 #fff; box-shadow: 0 0 6px rgba(0, 33, 50, 0.1), 0 7px 25px rgba(17, 38, 60, 0.4); }
+.jsPanel-hdr.jsPanel-theme-success{ color: #fff; font-family: tahoma,arial,verdana,sans-serif; font-weight: normal; background: #73A839; }
+.jsPanel-hdr.jsPanel-theme-success h3{ color: #fff; }
+.jsPanel-hdr.jsPanel-theme-success h3 small{ color: #fff; font-size: 65%; }
+.jsPanel-content.jsPanel-theme-success { background: none repeat scroll 0 0 #ffffff; color: #000000; font-family: tahoma,arial,verdana,sans-serif; outline: 1px solid #bbb; }
+.jsPanel-ftr.jsPanel-theme-success{}
+
+/* info ---------------------------------------------- */
+.jsPanel.jsPanel-theme-info{ background: none repeat scroll 0 0 #fff; box-shadow: 0 0 6px rgba(0, 33, 50, 0.1), 0 7px 25px rgba(17, 38, 60, 0.4); }
+.jsPanel-hdr.jsPanel-theme-info{ color: #fff; font-family: tahoma,arial,verdana,sans-serif; font-weight: normal; background: #033C73; }
+.jsPanel-hdr.jsPanel-theme-info h3{ color: #fff; }
+.jsPanel-hdr.jsPanel-theme-info h3 small{ color: #fff; font-size: 65%; }
+.jsPanel-content.jsPanel-theme-info { background: none repeat scroll 0 0 #ffffff; color: #000000; font-family: tahoma,arial,verdana,sans-serif; outline: 1px solid #bbb; }
+.jsPanel-ftr.jsPanel-theme-info{}
+
+/* warning ----------------------------------------------- */
+.jsPanel.jsPanel-theme-warning{ background: none repeat scroll 0 0 #fff; box-shadow: 0 0 6px rgba(0, 33, 50, 0.1), 0 7px 25px rgba(17, 38, 60, 0.4); }
+.jsPanel-hdr.jsPanel-theme-warning{ color: #fff; font-family: tahoma,arial,verdana,sans-serif; font-weight: normal; background: #DD5600; }
+.jsPanel-hdr.jsPanel-theme-warning h3{ color: #fff; }
+.jsPanel-hdr.jsPanel-theme-warning h3 small{ color: #fff; font-size: 65%; }
+.jsPanel-content.jsPanel-theme-warning { background: none repeat scroll 0 0 #fff; color: #000; font-family: tahoma,arial,verdana,sans-serif; outline: 1px solid #bbb; }
+.jsPanel-ftr.jsPanel-theme-warning{}
+
+/* danger ----------------------------------------------- */
+.jsPanel.jsPanel-theme-danger{ background: none repeat scroll 0 0 #fff; box-shadow: 0 0 6px rgba(0, 33, 50, 0.1), 0 7px 25px rgba(17, 38, 60, 0.4); }
+.jsPanel-hdr.jsPanel-theme-danger{ color: #fff; font-family: tahoma,arial,verdana,sans-serif; font-weight: normal; background: #C71C22; }
+.jsPanel-hdr.jsPanel-theme-danger h3{ color: #fff; }
+.jsPanel-hdr.jsPanel-theme-danger h3 small{ color: #fff; font-size: 65%; }
+.jsPanel-content.jsPanel-theme-danger { background: none repeat scroll 0 0 #ffffff; color: #000000; font-family: tahoma,arial,verdana,sans-serif; outline: 1px solid #bbb; }
+.jsPanel-ftr.jsPanel-theme-danger{}
+
+/* autumngreen ------------------------------------------- */
+.jsPanel.jsPanel-theme-autumngreen{ background: none repeat scroll 0 0 #eee; box-shadow: 0 0 6px rgba(0, 33, 50, 0.1), 0 7px 25px rgba(17, 38, 60, 0.4); }
+.jsPanel-hdr.jsPanel-theme-autumngreen{ color: rgb(196, 189, 142); font-family: tahoma,arial,verdana,sans-serif; font-weight: normal; background: rgb(125, 126, 81); }
+.jsPanel-hdr.jsPanel-theme-autumngreen h3{ color: rgb(196, 189, 142); }
+.jsPanel-hdr.jsPanel-theme-autumngreen h3 small{ color: #fff; font-size: 65%; }
+.jsPanel-content.jsPanel-theme-autumngreen { background: none repeat scroll 0 0 #FFFFFF; color: rgb(110, 100, 73); font-family: tahoma,arial,verdana,sans-serif; outline: 1px solid #bbb; }
+.jsPanel-ftr.jsPanel-theme-autumngreen{ background: linear-gradient(to bottom, rgba(125, 126, 81,0.65) 0%,rgba(0,0,0,0) 100%); background: -ms-linear-gradient(top, rgba(125, 126, 81,0.65) 0%,rgba(0,0,0,0) 100%); color: rgb(110, 100, 73); }
+
+/* autumnbrown ------------------------------------------- */
+.jsPanel.jsPanel-theme-autumnbrown{ background: none repeat scroll 0 0 #eee; box-shadow: 0 0 6px rgba(0, 33, 50, 0.1), 0 7px 25px rgba(17, 38, 60, 0.4); }
+.jsPanel-hdr.jsPanel-theme-autumnbrown{ color: rgb(233, 206, 135); font-family: tahoma,arial,verdana,sans-serif; font-weight: normal; background: rgb(138, 91, 51); }
+.jsPanel-hdr.jsPanel-theme-autumnbrown h3{ color: rgb(233, 206, 135); }
+.jsPanel-hdr.jsPanel-theme-autumnbrown h3 small{ color: #fff; font-size: 65%; }
+.jsPanel-content.jsPanel-theme-autumnbrown { background: none repeat scroll 0 0 #FFFFFF; color: rgb(110, 100, 73); font-family: tahoma,arial,verdana,sans-serif; outline: 1px solid #bbb; }
+.jsPanel-ftr.jsPanel-theme-autumnbrown{ background: linear-gradient(to bottom, rgba(138, 91, 51,0.65) 0%,rgba(0,0,0,0) 100%); background: -ms-linear-gradient(top, rgba(138, 91, 51,0.65) 0%,rgba(0,0,0,0) 100%); color: rgb(110, 100, 73); }
+
+/* autumnred ------------------------------------------- */
+.jsPanel.jsPanel-theme-autumnred{ background: none repeat scroll 0 0 #eee; box-shadow: 0 0 6px rgba(0, 33, 50, 0.1), 0 7px 25px rgba(17, 38, 60, 0.4); }
+.jsPanel-hdr.jsPanel-theme-autumnred{ color: rgb(233, 206, 135); font-family: tahoma,arial,verdana,sans-serif; font-weight: normal; background: rgb(198, 113, 10); }
+.jsPanel-hdr.jsPanel-theme-autumnred h3{ color: rgb(233, 206, 135); }
+.jsPanel-hdr.jsPanel-theme-autumnred h3 small{ color: #fff; font-size: 65%; }
+.jsPanel-content.jsPanel-theme-autumnred { background: none repeat scroll 0 0 #FFFFFF; color: rgb(110, 100, 73); font-family: tahoma,arial,verdana,sans-serif; outline: 1px solid #bbb; }
+.jsPanel-ftr.jsPanel-theme-autumnred{ background: linear-gradient(to bottom, rgba(198, 113, 10,0.65) 0%,rgba(0,0,0,0) 100%); background: -ms-linear-gradient(top, rgba(198, 113, 10,0.65) 0%,rgba(0,0,0,0) 100%); color: rgb(110, 100, 73); }
+
+/* bootstrap adjustments */
+.jsPanel.panel-default, .jsPanel.panel-primary, .jsPanel.panel-info, .jsPanel.panel-success, .jsPanel.panel-warning, .jsPanel.panel-danger{
+ box-shadow: 0 0 6px rgba(0, 33, 50, 0.1), 0 7px 25px rgba(17, 38, 60, 0.4);
+}
+
+/* css for the tooltip wrapper ---------------------------- */
+.jsPanel-tooltip-wrapper{
+ position: relative;
+ display: inline-block;
+ margin: 0;
+ padding: 0;
+ border: none;
+ background: transparent;
+}
+.jsPanel-tooltip-wrapper .jsPanel{
+ border-radius: 4px;
+}
+
+/* css for tooltip corners */
+.jsPanel-corner-top, .jsPanel-corner-right, .jsPanel-corner-bottom, .jsPanel-corner-left{
+ width: 0;
+ height: 0;
+ border: 12px solid transparent;
+ position: absolute;
+}
+.jsPanel-corner-top{
+ border-top-width: 10px;
+}
+.jsPanel-corner-right{
+ border-right-width: 10px;
+}
+.jsPanel-corner-bottom{
+ border-bottom-width: 10px;
+}
+.jsPanel-corner-left{
+ border-left-width: 10px;
+}
+
+
+
+
+/* css for the hints ----------------------------------------------------------- */
+.jsPanel-hint{
+ margin-bottom: 4px;
+}
+.jsPanel-hint-close-dark, .jsPanel-hint-close-white{
+ float:right;
+ margin:5px;
+ cursor: pointer;
+ width: 20px;
+ height: 20px;
+}
+.jsPanel-hint-close-dark{
+ background: url('images/close-20-333.png');
+}
+.jsPanel-hint-close-white{
+ background: url('images/close-20.png');
+}
+.jsPanel-hint-content.jsPanel-hint-default{
+ background: none repeat scroll 0 0 #fff;
+ color: #000;
+}
+.jsPanel-hint-content.jsPanel-hint-light{
+ background: linear-gradient(to bottom, rgba(0,0,0,0) 0%,rgba(250,250,250,0.65) 100%); background: -ms-linear-gradient(top, rgba(0,0,0,0) 0%,rgba(250,250,250,0.65) 100%);
+ color: #000;
+}
+.jsPanel-hint-content.jsPanel-hint-medium{
+ background: linear-gradient(to bottom, rgba(0, 0, 0, 0) 0%, rgba(130, 130, 130, 1) 100%); background: -ms-linear-gradient(top, rgba(0, 0, 0, 0) 0%, rgba(130, 130, 130, 1) 100%);
+ color: #fff;
+}
+.jsPanel-hint-content.jsPanel-hint-dark{
+ background: linear-gradient(to bottom, rgba(181,189,200,1) 0%,rgba(130,140,149,1) 36%,rgba(40,52,59,1) 100%); background: -ms-linear-gradient(top, rgba(181,189,200,1) 0%,rgba(130,140,149,1) 36%,rgba(40,52,59,1) 100%);
+ color: #fff;
+}
+.jsPanel-hint-content.jsPanel-hint-autumngreen{
+ background: linear-gradient(to bottom, rgba(125, 126, 81,0.65) 0%,rgba(0,0,0,0) 100%); background: -ms-linear-gradient(top, rgba(125, 126, 81,0.65) 0%,rgba(0,0,0,0) 100%);
+ color: #fff;
+}
+.jsPanel-hint-content.jsPanel-hint-autumnbrown{
+ background: linear-gradient(to bottom, rgba(138, 91, 51,0.65) 0%,rgba(0,0,0,0) 100%); background: -ms-linear-gradient(top, rgba(138, 91, 51,0.65) 0%,rgba(0,0,0,0) 100%);
+ color: #fff;
+}
+.jsPanel-hint-content.jsPanel-hint-autumnred{
+ background: linear-gradient(to bottom, rgba(198, 113, 10,0.65) 0%,rgba(0,0,0,0) 100%); background: -ms-linear-gradient(top, rgba(198, 113, 10,0.65) 0%,rgba(0,0,0,0) 100%);
+ color: #fff;
+}
+.jsPanel-hint-content.jsPanel-hint-primary{
+ background: none repeat scroll 0 0 #2FA4E7;
+ color: #fff;
+}
+.jsPanel-hint-content.jsPanel-hint-info{
+ background: none repeat scroll 0 0 #033C73;
+ color: #fff;
+}
+.jsPanel-hint-content.jsPanel-hint-success{
+ background: none repeat scroll 0 0 #73A839;
+ color: #fff;
+}
+.jsPanel-hint-content.jsPanel-hint-warning{
+ background: none repeat scroll 0 0 #DD5600;
+ color: #fff;
+}
+.jsPanel-hint-content.jsPanel-hint-danger{
+ background: none repeat scroll 0 0 #C71C22;
+ color: #fff;
+}
+
+/**
+ * CSS3 Tips v1.0.1
+ * A stylesheet for creating tooltips without using anything other than CSS3.
+ * created by c.bavota
+ * released under GPL v2
+ * March 21st, 2014
+ * HTML example code for the tooltip
+ * <a href="http://bavotasan.com" class="top-tip" data-tips="Go to bavotasan.com">bavotasan.com</a>
+*/
+[data-tips] {
+ position: relative;
+ text-decoration: none;
+}
+[data-tips]:after,
+[data-tips]:before {
+ position: absolute;
+ z-index: 100;
+ opacity: 0;
+}
+[data-tips]:after {
+ content: attr(data-tips);
+ height: 25px;
+ line-height: 25px;
+ padding: 0 10px;
+ font-size: 12px;
+ text-align: center;
+ color: #fff;
+ background: #3276B1;
+ border-radius: 4px;
+ /*text-shadow: 0 0 5px #000;*/
+ -moz-box-shadow: 0 0 5px rgba(0,0,0,0.3);
+ -webkit-box-shadow: 0 0 5px rgba(0,0,0,0.3);
+ box-shadow: 0 0 5px rgba(0,0,0,0.3);
+ white-space: nowrap;
+ -moz-box-sizing: border-box;
+ -webkit-box-sizing: border-box;
+ box-sizing: border-box;
+}
+[data-tips]:before {
+ content: "";
+ width: 0;
+ height: 0;
+ border-width: 6px;
+ border-style: solid;
+}
+
+[data-tips]:hover:after,
+[data-tips]:hover:before {
+ opacity: 1;
+}
+/* Top tips */
+[data-tips].top-tip:after,
+[data-tips].top-tip:before {
+ -webkit-transition: bottom 0.25s ease-in-out, opacity 0.25s ease-in-out;
+ -moz-transition: bottom 0.25s ease-in-out, opacity 0.25s ease-in-out;
+ transition: bottom 0.25s ease-in-out, opacity 0.25s ease-in-out;
+ bottom: 90%;
+ left: -9999px;
+ margin-bottom: 12px;
+}
+[data-tips].top-tip:before {
+ border-color: #3276B1 transparent transparent transparent;
+ margin-bottom: 0;
+}
+[data-tips].top-tip:hover:after,
+[data-tips].top-tip:hover:before {
+ bottom: 100%;
+ left: 0;
+}
+[data-tips].top-tip:hover:before {
+ left: 15px;
+}
+/* Bottom tip */
+[data-tips].bottom-tip:after,
+[data-tips].bottom-tip:before {
+ -webkit-transition: top 0.25s ease-in-out, opacity 0.25s ease-in-out;
+ -moz-transition: top 0.25s ease-in-out, opacity 0.25s ease-in-out;
+ transition: top 0.25s ease-in-out, opacity 0.25s ease-in-out;
+ top: 90%;
+ left: -9999px;
+ margin-top: 12px;
+}
+[data-tips].bottom-tip:before {
+ border-color: transparent transparent #3276B1 transparent;
+ margin-top: 0;
+}
+[data-tips].bottom-tip:hover:after,
+[data-tips].bottom-tip:hover:before {
+ top: 100%;
+ left: 0;
+}
+[data-tips].bottom-tip:hover:before {
+ left: 15px;
+}
+/* Right tip */
+[data-tips].right-tip:after,
+[data-tips].right-tip:before {
+ -webkit-transition: left 0.25s ease-in-out, opacity 0.25s ease-in-out;
+ -moz-transition: left 0.25s ease-in-out, opacity 0.25s ease-in-out;
+ transition: left 0.25s ease-in-out, opacity 0.25s ease-in-out;
+ top: -9999px;
+ left: 96%;
+ margin-left: 12px;
+}
+[data-tips].right-tip:before {
+ border-color: transparent #3276B1 transparent transparent;
+ margin-left: 0;
+}
+[data-tips].right-tip:hover:after,
+[data-tips].right-tip:hover:before {
+ left: 100%;
+ top: 0;
+}
+
+[data-tips].right-tip:hover:before {
+ top: 7px;
+}
+/* Left tip */
+[data-tips].left-tip:after,
+[data-tips].left-tip:before {
+ -webkit-transition: right 0.25s ease-in-out, opacity 0.25s ease-in-out;
+ -moz-transition: right 0.25s ease-in-out, opacity 0.25s ease-in-out;
+ transition: right 0.25s ease-in-out, opacity 0.25s ease-in-out;
+ top: -9999px;
+ right: 96%;
+ margin-right: 12px;
+}
+[data-tips].left-tip:before {
+ border-color: transparent transparent transparent #3276B1;
+ margin-right: 0;
+}
+[data-tips].left-tip:hover:after,
+[data-tips].left-tip:hover:before {
+ right: 100%;
+ top: 0;
+}
+[data-tips].left-tip:hover:before {
+ top: 7px;
+}
Added: trunk/packages/orthanc-webviewer/trunk/debian/JS/jsPanel-2.3.3/jquery.jspanel.js
===================================================================
--- trunk/packages/orthanc-webviewer/trunk/debian/JS/jsPanel-2.3.3/jquery.jspanel.js (rev 0)
+++ trunk/packages/orthanc-webviewer/trunk/debian/JS/jsPanel-2.3.3/jquery.jspanel.js 2015-03-02 09:58:59 UTC (rev 18890)
@@ -0,0 +1,3050 @@
+/* global console, MobileDetect */
+/* jQuery Plugin jsPanel
+ Dependencies:
+ jQuery library ( > 1.7.0 incl. 2.1.1 )
+ jQuery.UI library ( > 1.9.0 ) - (at least UI Core, Mouse, Widget, Draggable, Resizable)
+ mobile-detect.js for the responsive features <https://github.com/hgoebl/mobile-detect.js>
+ bootstrap (required only when using the bootstrap features)
+ HTML5/CSS3 compatible browser
+
+ Copyright (c) 2014 Stefan Sträßer, <http://stefanstraesser.eu/>
+
+ 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.
+
+ You should have received a copy of the MIT License along with this program. If not, see <http://opensource.org/licenses/MIT>.
+ */
+
+/*
+ ### changes in 2.3.3 ###
+ + bugfix in handling of z-index values
+ ### changes in 2.3.2 ###
+ + bugfix in handling of z-index values for modals
+ ### changes in 2.3.1 ###
+ + bugfix in handling of z-index values
+ ### changes in 2.3.0 ###
+ + new method .resize(width, height) to resize an exsisting jsPanel by code
+ + new jsPanel property "device" return NULL if device is not a mobile
+ + new jsPanel.getMargins() to calculate panel margins either relative to browser viewport or panel.parent
+ + functions to shift tooltips horizontally or vertically depending on position used
+ + rewriteOPaneltype slightly adjusted
+ + Tooltips: option.paneltype NEW property "shiftwithin" to set the element witin a tooltip is to be repositioned; default "body"
+ + jsPanel function calcPosTooltipLeft und calcPosTooltipTop improved to consider possible margins of tooltrip trigger
+*/
+
+var jsPanel;
+
+(function($){
+ "use strict";
+ jsPanel = {
+ version: '2.3.3 2015-02-06 09:17',
+ device: (function(){
+ try {
+ // requires "mobile-detect.js" to be loaded
+ var md = new MobileDetect(window.navigator.userAgent),
+ mobile = md.mobile(),
+ phone = md.phone(),
+ tablet = md.tablet(),
+ os = md.os(),
+ userAgent = md.userAgent();
+ return {mobile: mobile, tablet: tablet, phone: phone, os: os, userAgent: userAgent};
+ } catch (e) {
+ console.log(e + "; Seems like mobile-detect.js is not loaded");
+ return false;
+ }
+ })(),
+ ID: 0, // kind of a counter to add to automatically generated id attribute
+ widthForMinimized: 150, // default width of minimized panels
+ hintsTc: [], // arrays that log hints for option.position 'top center', 'top left' and 'top right'
+ hintsTl: [],
+ hintsTr: [],
+
+ template: '<div class="jsPanel jsPanel-theme-default">' +
+ '<div class="jsPanel-hdr jsPanel-theme-default">' +
+ '<h3 class="jsPanel-title"></h3>' +
+ '<div class="jsPanel-hdr-r">' +
+ '<div class="jsPanel-btn-close"><span class="jsglyph jsglyph-remove"></span></div>' +
+ '<div class="jsPanel-btn-max"><span class="jsglyph jsglyph-maximize"></span></div>' +
+ '<div class="jsPanel-btn-norm"><span class="jsglyph jsglyph-normalize"></span></div>' +
+ '<div class="jsPanel-btn-min"><span class="jsglyph jsglyph-minimize"></span></div>' +
+ '<div class="jsPanel-btn-small"><span class="jsglyph jsglyph-chevron-up"></span></div>' +
+ '<div class="jsPanel-btn-smallrev"><span class="jsglyph jsglyph-chevron-down"></span></div>' +
+ '</div>' +
+ '<div class="jsPanel-hdr-toolbar jsPanel-clearfix"></div>' +
+ '</div>' +
+ '<div class="jsPanel-content jsPanel-theme-default"></div>' +
+ '<div class="jsPanel-ftr jsPanel-theme-default jsPanel-clearfix"></div>' +
+ '</div>',
+
+ // add toolbar
+ addToolbar: function (panel, place, items) {
+
+ if (place === 'header') {
+
+ jsPanel.configToolbar(items, panel.header.toolbar, panel);
+
+ } else if (place === 'footer') {
+
+ panel.footer.css({
+ display: 'block',
+ padding: '5px 20px 5px 5px'
+ });
+
+ jsPanel.configToolbar(items, panel.footer, panel);
+
+ }
+
+ return panel;
+
+ },
+
+ // used in option.autoclose and checks prior use of .close() whether the panel is still there
+ autoclose: function (panel, id, optionAutoclose) {
+
+ window.setTimeout(function () {
+
+ var elmt = $('#' + id);
+
+ if (elmt.length > 0) {
+
+ elmt.fadeOut('slow', function () {
+
+ panel.close(); // elmt geht hier nicht weil .close() nicht für elmt definiert ist
+
+ });
+
+ }
+
+ }, optionAutoclose);
+
+ },
+
+ calcPos: function (prop, option, count, panel) {
+
+ if (option.position[prop] === 'auto') {
+
+ option.position[prop] = count * 30 + 'px';
+
+ } else if ($.isFunction(option.position[prop])) {
+
+ option.position[prop] = option.position[prop](panel);
+
+ } else if (option.position[prop] === 0) {
+
+ option.position[prop] = '0';
+
+ } else {
+
+ option.position[prop] = parseInt(option.position[prop], 10) + 'px';
+
+ }
+
+ // corrections if jsPanel is appended to the body element
+ if (option.selector === 'body') {
+
+ if (prop === 'top') {
+
+ option.position.top = parseInt(option.position.top, 10) + jsPanel.winscrollTop() + 'px';
+
+ }
+
+ if (prop === 'bottom') {
+
+ option.position.bottom = parseInt(option.position.bottom, 10) - jsPanel.winscrollTop() + 'px';
+
+ }
+
+ if (prop === 'left') {
+
+ option.position.left = parseInt(option.position.left, 10) + jsPanel.winscrollLeft() + 'px';
+
+ }
+
+ if (prop === 'right') {
+
+ option.position.right = parseInt(option.position.right, 10) - jsPanel.winscrollLeft() + 'px';
+
+ }
+ }
+
+ return option.position[prop];
+
+ },
+
+ // calculate position center for option.position == 'center'
+ calcPosCenter: function (option) {
+
+ var posL = ($(option.selector).outerWidth() / 2) - ((parseInt(option.size.width, 10) / 2)),
+ posT;
+
+ if (option.selector === 'body') {
+
+ posT = ($(window).outerHeight() / 2) - ((parseInt(option.size.height, 10) / 2) - jsPanel.winscrollTop());
+
+ } else {
+
+ posT = ($(option.selector).outerHeight() / 2) - ((parseInt(option.size.height, 10) / 2));
+
+ }
+
+ return {top: posT + 'px', left: posL + 'px'};
+
+ },
+
+ // calculate position for maximized panels using option.controls.maxtoScreen (for devmondo)
+ calcPosmaxtoScreen: function(panel) {
+
+ var offset = panel.offset(),
+ newPos = {
+ top: parseInt(panel.css('top')) - (offset.top - $(document).scrollTop()) + 5 + 'px',
+ left: parseInt(panel.css('left')) - (offset.left - $(document).scrollLeft()) + 5 + 'px'
+ };
+
+ return newPos;
+
+ },
+
+ // calculates css left for tooltips
+ calcPosTooltipLeft: function (pos, jsPparent, option) {
+
+ // width of element serving as trigger for the tooltip
+ var parW = jsPparent.outerWidth(),
+ // check possible margins of trigger
+ mL = parseInt(jsPparent.css('margin-left')),
+ // check whether offset is set
+ oX = option.offset.left || 0;
+
+ if (pos === 'top' || pos === 'bottom') {
+
+ return (parW - option.size.width) / 2 + mL + oX + 'px';
+
+ }
+
+ if (pos === 'left') {
+
+ return -(option.size.width) + mL + oX + 'px';
+
+ }
+
+ if (pos === 'right') {
+
+ return parW + mL + oX + 'px';
+
+ }
+
+ return false;
+
+ },
+
+ // calculates css top for tooltips
+ calcPosTooltipTop: function (pos, jsPparent, option) {
+
+ var parH = jsPparent.innerHeight(),
+ mT = parseInt(jsPparent.css('margin-top')),
+ oY = option.offset.top || 0;
+
+ if (pos === 'left' || pos === 'right') {
+
+ return -(option.size.height / 2) + (parH / 2) + mT + oY + 'px';
+
+ }
+
+ if (pos === 'top') {
+
+ return -(option.size.height + oY) + mT + 'px';
+
+ }
+
+ if (pos === 'bottom') {
+
+ return parH + mT + oY + 'px';
+
+ }
+
+ return false;
+
+ },
+
+ // calculate final tooltip position
+ calcToooltipPosition: function(jsPparent, option) {
+
+ if (option.paneltype.position === 'top') {
+
+ option.position = {
+ top: jsPanel.calcPosTooltipTop('top', jsPparent, option),
+ left: jsPanel.calcPosTooltipLeft('top', jsPparent, option)
+ };
+
+ } else if (option.paneltype.position === 'bottom') {
+
+ option.position = {
+ top: jsPanel.calcPosTooltipTop('bottom', jsPparent, option),
+ left: jsPanel.calcPosTooltipLeft('bottom', jsPparent, option)
+ };
+
+ } else if (option.paneltype.position === 'left') {
+
+ option.position = {
+ top: jsPanel.calcPosTooltipTop('left', jsPparent, option),
+ left: jsPanel.calcPosTooltipLeft('left', jsPparent, option)
+ };
+
+ } else if (option.paneltype.position === 'right') {
+
+ option.position = {
+ top: jsPanel.calcPosTooltipTop('right', jsPparent, option),
+ left: jsPanel.calcPosTooltipLeft('right', jsPparent, option)
+ };
+
+ }
+
+ return option.position;
+
+ },
+
+ calcVerticalOffset: function (panel) {
+
+ return panel.offset().top - jsPanel.winscrollTop();
+
+ },
+
+ // closes a jsPanel and removes it from the DOM
+ close: function (panel, optionPaneltypeType, jsPparentTagname) {
+
+ // get parent-element of jsPanel
+ var context = panel.parent(),
+ panelID = panel.attr('id'),
+ ind;
+
+ // delete childpanels ...
+ jsPanel.closeChildpanels(panel);
+
+ // if present remove tooltip wrapper
+ if (context.hasClass('jsPanel-tooltip-wrapper')) {
+
+ panel.unwrap();
+
+ }
+
+ // remove the jsPanel itself
+ panel.remove();
+
+ $('body').trigger('jspanelclosed', panelID);
+
+ // remove backdrop only when modal jsPanel is closed
+ if (optionPaneltypeType === 'modal') {
+
+ $('.jsPanel-backdrop').remove();
+
+ }
+ // reposition minimized panels
+ jsPanel.reposMinimized(jsPanel.widthForMinimized);
+
+ // update arrays with hints
+ if (optionPaneltypeType === 'hint') {
+
+ ind = jsPanel.hintsTc.indexOf(panelID);
+
+ if (ind !== -1) {
+
+ jsPanel.hintsTc.splice(ind, 1);
+ // reposition hints
+ jsPanel.reposHints(jsPanel.hintsTc, jsPparentTagname);
+
+ }
+
+ ind = jsPanel.hintsTl.indexOf(panelID);
+
+ if (ind !== -1) {
+
+ jsPanel.hintsTl.splice(ind, 1);
+ jsPanel.reposHints(jsPanel.hintsTl, jsPparentTagname);
+
+ }
+
+ ind = jsPanel.hintsTr.indexOf(panelID);
+
+ if (ind !== -1) {
+
+ jsPanel.hintsTr.splice(ind, 1);
+ jsPanel.reposHints(jsPanel.hintsTr, jsPparentTagname);
+
+ }
+
+ }
+
+ return context;
+
+ },
+
+ // close all tooltips
+ closeallTooltips: function () {
+
+ var pID;
+
+ $('.jsPanel-tt').each(function () {
+
+ pID = $(this).attr('id');
+ // if present remove tooltip wrapper and than remove tooltip
+ $('#' + pID).unwrap().remove();
+ $('body').trigger('jspanelclosed', pID);
+
+ });
+
+ },
+
+ // closes/removes all childpanels within the parent jsPanel
+ closeChildpanels: function (panel) {
+
+ var pID;
+
+ $('.jsPanel', panel).each(function () {
+
+ pID = $(this).attr('id');
+ $('#' + pID).remove();
+ $('body').trigger('jspanelclosed', pID);
+
+ });
+
+ return panel;
+
+ },
+
+ // configure controls
+ configControls: function(optionControls, panel) {
+
+ if (optionControls.buttons === 'closeonly') {
+
+ $(".jsPanel-btn-min, .jsPanel-btn-norm, .jsPanel-btn-max, .jsPanel-btn-small, .jsPanel-btn-smallrev", panel.header.controls).remove();
+ panel.header.title.css("width", "calc(100% - 30px)");
+
+ } else if (optionControls.buttons === 'none') {
+
+ $('*', panel.header.controls).remove();
+ panel.header.title.css("width", "100%");
+
+ }
+ // disable controls individually
+ if (optionControls.close) {panel.control('disable', 'close');}
+ if (optionControls.maximize) {panel.control('disable', 'maximize');}
+ if (optionControls.minimize) {panel.control('disable', 'minimize');}
+ if (optionControls.normalize) {panel.control('disable', 'normalize');}
+ if (optionControls.smallify) {panel.control('disable', 'smallify');}
+
+ },
+
+ // configure iconfonts
+ configIconfont: function(optionControlsIconfont, panel) {
+
+ // remove icon sprites
+ $('*', panel.header.controls).css('background-image', 'none');
+
+ if (optionControlsIconfont === 'bootstrap') {
+
+ $('.jsPanel-btn-close', panel.header.controls).empty().append('<span class="glyphicon glyphicon-remove"></span>');
+ $('.jsPanel-btn-max', panel.header.controls).empty().append('<span class="glyphicon glyphicon-fullscreen"></span>');
+ $('.jsPanel-btn-norm', panel.header.controls).empty().append('<span class="glyphicon glyphicon-resize-full"></span>');
+ $('.jsPanel-btn-min', panel.header.controls).empty().append('<span class="glyphicon glyphicon-minus"></span>');
+ $('.jsPanel-btn-small', panel.header.controls).empty().append('<span class="glyphicon glyphicon-chevron-up"></span>');
+ $('.jsPanel-btn-smallrev', panel.header.controls).empty().append('<span class="glyphicon glyphicon-chevron-down"></span>');
+
+ } else if (optionControlsIconfont === 'font-awesome') {
+
+ $('.jsPanel-btn-close', panel.header.controls).empty().append('<i class="fa fa-times"></i>');
+ $('.jsPanel-btn-max', panel.header.controls).empty().append('<i class="fa fa-arrows-alt"></i>');
+ $('.jsPanel-btn-norm', panel.header.controls).empty().append('<i class="fa fa-expand"></i>');
+ $('.jsPanel-btn-min', panel.header.controls).empty().append('<i class="fa fa-minus"></i>');
+ $('.jsPanel-btn-small', panel.header.controls).empty().append('<i class="fa fa-chevron-up"></i>');
+ $('.jsPanel-btn-smallrev', panel.header.controls).empty().append('<i class="fa fa-chevron-down"></i>');
+
+ }
+
+ },
+
+ // builds toolbar
+ configToolbar: function (toolbaritems, toolbarplace, panel) {
+
+ var i,
+ el,
+ type,
+ max = toolbaritems.length;
+
+ for (i = 0; i < max; i += 1) {
+
+ if (typeof toolbaritems[i] === 'object') {
+
+ el = $(toolbaritems[i].item);
+ type = el.prop('tagName').toLowerCase();
+
+ if (type === 'button') {
+
+ // set text of button
+ el.append(toolbaritems[i].btntext);
+
+ // add class to button
+ if (typeof toolbaritems[i].btnclass === 'string') {
+
+ el.addClass(toolbaritems[i].btnclass);
+
+ }
+
+ }
+
+ toolbarplace.append(el);
+
+ // bind handler to the item
+ if ($.isFunction(toolbaritems[i].callback)) {
+
+ el.on(toolbaritems[i].event, panel, toolbaritems[i].callback);
+ // jsP is accessible in the handler as "event.data"
+
+ }
+
+ }
+
+ }
+
+ },
+
+ // disable/enable individual controls
+ control: function (panel, action, btn) {
+
+ if (arguments.length === 3) {
+
+ if (arguments[1] === 'disable') {
+
+ if (btn === 'close') {
+
+ btn = $('.jsPanel-btn-close', panel.header.controls);
+
+ }
+
+ if (btn === 'maximize') {
+
+ btn = $('.jsPanel-btn-max', panel.header.controls);
+
+ }
+
+ if (btn === 'minimize') {
+
+
+ btn = $('.jsPanel-btn-min', panel.header.controls);
+ }
+
+ if (btn === 'normalize') {
+
+ btn = $('.jsPanel-btn-norm', panel.header.controls);
+
+ }
+
+ if (btn === 'smallify') {
+
+ btn = $('.jsPanel-btn-small', panel.header.controls);
+
+ }
+
+ // unbind handler and set styles
+ btn.off().css({opacity:0.5, cursor: 'default'});
+
+ } else if (arguments[1] === 'enable') {
+
+ var controlbtn;
+
+ if (btn === 'close') {
+
+ controlbtn = $('.jsPanel-btn-close', panel.header.controls);
+
+ }
+
+ if (btn === 'maximize') {
+
+ controlbtn = $('.jsPanel-btn-max', panel.header.controls);
+
+ }
+
+ if (btn === 'minimize') {
+
+ controlbtn = $('.jsPanel-btn-min', panel.header.controls);
+
+ }
+
+ if (btn === 'normalize') {
+
+ controlbtn = $('.jsPanel-btn-norm', panel.header.controls);
+
+ }
+
+ if (btn === 'smallify') {
+
+ controlbtn = $('.jsPanel-btn-small', panel.header.controls);
+
+ }
+
+ // enable control and reset styles
+ controlbtn.on('click', function (e) {
+
+ e.preventDefault();
+ panel[btn]();
+
+ }).css({opacity: 1, cursor: 'pointer'});
+ }
+
+ }
+
+ return panel;
+
+ },
+
+ // helper function for the doubleclick handlers (title, content, footer)
+ dblclickhelper: function (odcs, panel) {
+
+ if (typeof odcs === 'string') {
+
+ if (odcs === "maximize" || odcs === "normalize") {
+
+ if (panel.status !== "maximized") {
+
+ panel.maximize();
+
+ } else {
+
+ panel.normalize();
+
+ }
+
+ } else if (odcs === "minimize" || odcs === "smallify" || odcs === "close") {
+
+ panel[odcs]();
+
+ }
+
+ }
+
+ },
+
+ docOuterHeight: function () {
+
+ return $(document).outerHeight();
+
+ },
+
+ // maintains panel position relative to window on scroll of page
+ fixPosition: function (panel) {
+
+ var jspaneldiff = panel.offset().top - jsPanel.winscrollTop();
+
+ panel.jsPanelfixPos = function () {
+
+ panel.css('top', jsPanel.winscrollTop() + jspaneldiff + 'px');
+
+ };
+
+ $(window).on('scroll', panel.jsPanelfixPos);
+
+ },
+
+ // calculate panel margins
+ getMargins: function(panel, selector) {
+
+ var off, elmtOff, mR, mL, mB, mT;
+
+ if(!selector || selector === "body") {
+
+ // panel margins relative to browser viewport
+ off = panel.offset();
+ mR = jsPanel.winouterWidth() - off.left - panel.outerWidth() + jsPanel.winscrollLeft();
+ mL = jsPanel.winouterWidth() - panel.outerWidth() - mR;
+ mB = jsPanel.winouterHeight() - off.top - panel.outerHeight() + jsPanel.winscrollTop();
+ mT = jsPanel.winouterHeight() - panel.outerHeight() - mB;
+
+ } else {
+
+ // panel margins relative to element matching selector "selector"
+ elmtOff = $(selector).offset();
+ off = panel.offset();
+ mR = $(selector).outerWidth() - parseInt(panel.css('width')) - (off.left - elmtOff.left);
+ mL = off.left - elmtOff.left;
+ mB = $(selector).outerHeight() - (off.top - elmtOff.top) - parseInt(panel.css('height'));
+ mT = off.top - elmtOff.top;
+
+ }
+
+ return {marginTop: parseInt(mT), marginRight: parseInt(mR), marginBottom: parseInt(mB), marginLeft: parseInt(mL)};
+
+ },
+
+ // calculate max horizontal and vertical tooltip shift
+ getMaxpanelshift: function(panel) {
+
+ var horiz = parseInt( panel.outerWidth()/2 ) + parseInt( panel.parent().outerWidth()/2 ) - 20,
+ vert = parseInt( panel.outerHeight()/2 ) + parseInt( panel.parent().outerHeight()/2 ) - 20,
+ cornerHoriz = parseInt( panel.outerWidth()/2 ) - 16,
+ cornerVert = parseInt( panel.outerHeight()/2 ) - 16;
+
+ return {maxshiftH: horiz, maxshiftV: vert, maxCornerH: cornerHoriz, maxCornerV: cornerVert};
+
+ },
+
+ // shift tooltip left/right if it overflows window
+ // when using horizontal offsets of panel and/or corner result might be not as expected
+ shiftTooltipHorizontal: function(panel, optionPaneltypeshiftwithin){
+
+ var margins = jsPanel.getMargins(panel, optionPaneltypeshiftwithin),
+ leftShiftRequired = 0,
+ maxShift = jsPanel.getMaxpanelshift(panel),
+ maxLeftShift = maxShift.maxshiftH,
+ shift = 0,
+ maxCornerLeft = maxShift.maxCornerH,
+ cornerShift = 0,
+ newPanelLeft = 0,
+ newCornerLeft = 0;
+
+ if (margins.marginLeft < 0 && margins.marginRight > 0) {
+ // if panel overflows left window border
+ leftShiftRequired = Math.abs(margins.marginLeft) + 5;
+ shift = Math.min(leftShiftRequired, maxLeftShift);
+ cornerShift = Math.min(maxCornerLeft, shift);
+ newPanelLeft = parseInt(panel.css('left')) + shift + "px";
+ newCornerLeft = parseInt($('.jsPanel-corner', panel).css('left')) - cornerShift + "px";
+
+ } else if (margins.marginRight < 0 && margins.marginLeft > 0) {
+ // if panel overflows right window border
+ leftShiftRequired = Math.abs(margins.marginRight) + 5;
+ shift = Math.min(leftShiftRequired, maxLeftShift);
+ cornerShift = Math.min(maxCornerLeft, shift);
+ newPanelLeft = parseInt(panel.css('left')) - shift + "px";
+ newCornerLeft = parseInt($('.jsPanel-corner', panel).css('left')) + cornerShift + "px";
+
+ }
+
+ if ((margins.marginLeft < 0 && margins.marginRight > 0) || (margins.marginRight < 0 && margins.marginLeft > 0)) {
+ // shift panel
+ panel.animate({
+ "left": newPanelLeft
+ },{ queue: false /* to have both animation run simultaneously */ });
+
+ // shift corner if present
+ if ($('.jsPanel-corner', panel)) {
+ $('.jsPanel-corner', panel).animate({
+ "left": newCornerLeft
+ },{ queue: false /* to have both animation run simultaneously */ });
+ }
+ }
+
+ },
+
+ // shift tooltip up/down if it overflows window
+ // when using vertical offsets of panel and/or corner result might be not as expected
+ shiftTooltipVertical: function(panel, optionPaneltypeshiftwithin){
+
+ //console.log( parseInt($('*:first-child', panel.parent()).css('margin-left')) );
+
+ var margins = jsPanel.getMargins(panel, optionPaneltypeshiftwithin),
+ topShiftRequired = 0,
+ maxShift = jsPanel.getMaxpanelshift(panel),
+ maxTopShift = maxShift.maxshiftV,
+ shift = 0,
+ maxCornerTop = maxShift.maxCornerV,
+ cornerShift = 0,
+ newPanelTop = 0,
+ newCornerTop = 0;
+
+ if (margins.marginTop < 0 && margins.marginBottom > 0) {
+ // if panel overflows top window border
+ topShiftRequired = Math.abs(margins.marginTop) + 5;
+ shift = Math.min(topShiftRequired, maxTopShift);
+ cornerShift = Math.min(maxCornerTop, shift);
+ newPanelTop = parseInt(panel.css('top')) + shift + "px";
+ newCornerTop = parseInt($('.jsPanel-corner', panel).css('top')) - cornerShift + "px";
+
+ } else if (margins.marginBottom < 0 && margins.marginTop > 0) {
+ // if panel overflows bottom window border
+ topShiftRequired = Math.abs(margins.marginBottom) + 5;
+ shift = Math.min(topShiftRequired, maxTopShift);
+ cornerShift = Math.min(maxCornerTop, shift);
+ newPanelTop = parseInt(panel.css('top')) - shift + "px";
+ newCornerTop = parseInt($('.jsPanel-corner', panel).css('top')) + cornerShift + "px";
+
+ }
+
+ if ((margins.marginTop < 0 && margins.marginBottom > 0) || (margins.marginBottom < 0 && margins.marginTop > 0)) {
+ // shift panel
+ panel.animate({
+ "top": newPanelTop
+ },{ queue: false /* to have both animation run simultaneously */ });
+
+ // shift corner if present
+ if ($('.jsPanel-corner', panel)) {
+ $('.jsPanel-corner', panel).animate({
+ "top": newCornerTop
+ },{ queue: false /* to have both animation run simultaneously */ });
+ }
+ }
+
+ },
+
+ // get title text
+ getTitle: function (panel) {
+
+ return panel.header.title.html();
+
+ },
+
+ // hide controls specified by param "sel" of the jsPanel "panel"
+ hideControls: function (sel, panel) {
+
+ var controls = ".jsPanel-btn-close, .jsPanel-btn-norm, .jsPanel-btn-min, .jsPanel-btn-max, .jsPanel-btn-small, .jsPanel-btn-smallrev";
+
+ $(controls, panel.header.controls).css('display', 'block');
+
+ $(sel, panel.header.controls).css('display', 'none');
+
+ },
+
+ // calculates option.position for hints using 'top left', 'top center' or 'top right'
+ hintTop: function (hintGroup) {
+
+ var i,
+ hintH = 0,
+ max = hintGroup.length;
+
+ for (i = 0; i < max; i += 1) {
+
+ hintH += $('#' + hintGroup[i]).outerHeight(true);
+
+ }
+
+ if (hintGroup === jsPanel.hintsTr) {
+
+ return {top: hintH, right: 0};
+
+ }
+
+ if (hintGroup === jsPanel.hintsTl) {
+
+ return {top: hintH, left: 0};
+
+ }
+
+ if (hintGroup === jsPanel.hintsTc) {
+
+ return {top: hintH, left: 'center'};
+
+ }
+
+ return {top: 0, left: 0};
+
+ },
+
+ // append modal backdrop
+ insertModalBackdrop: function () {
+
+ var backdrop = '<div class="jsPanel-backdrop" style="height:' + jsPanel.docOuterHeight() + 'px;"></div>';
+
+ $('body').append(backdrop);
+
+ },
+
+ // check whether a bootstrap compatible theme is used
+ isBootstrapTheme: function(optionBootstrap) {
+
+ var arr = ["default", "primary", "info", "success", "warning", "danger"];
+
+ if ($.inArray(optionBootstrap, arr) > -1) {
+
+ return optionBootstrap;
+
+ } else {
+
+ return "default";
+
+ }
+
+ },
+
+ // check for positive integer
+ isPosInt: function(arg) {
+
+ var regex = /^\+?[1-9]\d*$/;
+
+ if (arg.toString().match(regex) !== null) {
+
+ return true;
+
+ } else {
+
+ return false;
+
+ }
+ },
+
+ // maximizes a panel within the body element
+ maxWithinBody: function (panel, option) {
+
+ if (panel.status !== "maximized" && option.paneltype.mode !== 'default') {
+
+ var newPos, newTop, newLeft;
+
+ // remove window.scroll handler, is added again later in this function
+ $(window).off('scroll', panel.jsPanelfixPos);
+
+ // restore minimized panel to initial container
+ jsPanel.restoreFromMinimized(panel, option);
+
+ // test to enable fullscreen maximize for panels in a parent other than body
+ if (option.controls.maxtoScreen === true) {
+
+ newPos = jsPanel.calcPosmaxtoScreen(panel);
+ newTop = newPos.top;
+ newLeft = newPos.left;
+
+ } else {
+
+ newTop = jsPanel.winscrollTop() + 5 + 'px';
+ newLeft = jsPanel.winscrollLeft() + 5 + 'px';
+
+ }
+ panel.animate({
+
+ top: newTop,
+ left: newLeft,
+ width: jsPanel.winouterWidth() - 10 + 'px',
+ height: jsPanel.winouterHeight() - 10 + 'px'
+
+ }, {
+ done: function () {
+
+ jsPanel.resizeContent(panel);
+ panel.animate({opacity: 1}, {duration: 150});
+
+ // hier kein fadeIn() einbauen, funktioniert nicht mit jsPanel.fixPosition(jsP)
+ jsPanel.hideControls(".jsPanel-btn-max, .jsPanel-btn-smallrev", panel);
+ panel.status = "maximized";
+ $(panel).trigger('jspanelmaximized', panel.attr('id'));
+ $(panel).trigger('jspanelstatechange', panel.attr('id'));
+
+ if (!option.controls.maxtoScreen || (option.controls.maxtoScreen && option.selector === 'body')) {
+
+ // test to enable fullscreen maximize for panels in a parent other than body
+ jsPanel.fixPosition(panel, option);
+
+ }
+
+ //jsPanel.fixPosition(panel);
+ jsPanel.resizeTitle(panel);
+
+ }
+ });
+
+ }
+
+ },
+
+ // maximizes a panel within an element other than body
+ maxWithinElement: function (panel, option) {
+
+ if (panel.status !== "maximized" && option.paneltype.mode !== 'default') {
+
+ var width,
+ height;
+
+ // restore minimized panel to initial container
+ jsPanel.restoreFromMinimized(panel, option);
+
+ width = parseInt(panel.parent().outerWidth(), 10) - 10 + 'px';
+ height = parseInt(panel.parent().outerHeight(), 10) - 10 + 'px';
+
+ panel.animate({
+
+ top: '5px',
+ left: '5px',
+ width: width,
+ height: height
+
+ }, {
+ done: function () {
+
+ jsPanel.resizeContent(panel);
+ panel.animate({opacity: 1}, {duration: 150});
+ jsPanel.hideControls(".jsPanel-btn-max, .jsPanel-btn-smallrev", panel);
+ panel.status = "maximized";
+
+ $(panel).trigger('jspanelmaximized', panel.attr('id'));
+ $(panel).trigger('jspanelstatechange', panel.attr('id'));
+
+ jsPanel.resizeTitle(panel);
+
+ }
+
+ });
+
+ }
+
+ },
+
+ // calls functions to maximize a jsPanel
+ maximize: function (panel, jsPparentTagname, option) {
+
+ // || option.controls.maxtoScreen === true - test to enable fullscreen maximize for panels in a parent other than body
+ if (jsPparentTagname === 'body' || option.controls.maxtoScreen === true) {
+
+ jsPanel.maxWithinBody(panel, option);
+
+ } else {
+
+ jsPanel.maxWithinElement(panel, option);
+
+ }
+
+ return panel;
+
+ },
+
+ // minimizes a jsPanel to the lower left corner of the browser viewport
+ minimize: function (panel, optionSize) {
+
+ // update panel size to have correct values when normalizing again
+ if (panel.status === "normalized") {
+
+ optionSize.width = panel.outerWidth() + 'px';
+ optionSize.height = panel.outerHeight() + 'px';
+
+ }
+ panel.animate({
+
+ opacity: 0
+
+ }, {
+ duration: 400, // fade out speed when minimizing
+ complete: function () {
+
+ panel.animate({
+
+ width: '150px',
+ height: '28px'
+
+ }, {
+ duration: 100,
+ complete: function () {
+
+ jsPanel.movetoMinified(panel);
+ jsPanel.resizeTitle(panel);
+ panel.css('opacity', 1);
+
+ }
+ });
+
+ }
+
+ });
+
+ return panel;
+
+ },
+
+ // moves a panel to the minimized container
+ movetoMinified: function (panel) {
+
+ var mincount = $('#jsPanel-min-container > .jsPanel').length;
+
+ // wenn der Container für die minimierten jsPanels noch nicht existiert -> erstellen
+ if ($('#jsPanel-min-container').length === 0) {
+
+ $('body').append('<div id="jsPanel-min-container"></div>');
+
+ }
+ if (panel.status !== "minimized") {
+
+ // jsPanel in vorgesehenen Container verschieben
+ panel.css({
+
+ left: (mincount * jsPanel.widthForMinimized) + 'px',
+ top: 0,
+ opacity: 1
+
+ })
+ .appendTo('#jsPanel-min-container')
+ .resizable({disabled: true})
+ .draggable({disabled: true});
+
+ // buttons show or hide
+ jsPanel.hideControls(".jsPanel-btn-min, .jsPanel-btn-small, .jsPanel-btn-smallrev", panel);
+
+ $(panel).trigger('jspanelminimized', panel.attr('id'));
+ $(panel).trigger('jspanelstatechange', panel.attr('id'));
+
+ panel.status = "minimized";
+
+ $(window).off('scroll', panel.jsPanelfixPos);
+
+ }
+
+ },
+
+ // restores a panel to its "normalized" (not minimized, maximized or smallified) position & size
+ normalize: function (panel, option, jsPparentTagname, verticalOffset) {
+
+ var panelTop;
+
+ // remove window.scroll handler, is added again later in this function
+ $(window).off('scroll', panel.jsPanelfixPos);
+
+ // restore minimized panel to initial container
+ jsPanel.restoreFromMinimized(panel, option);
+
+ // correction for panels maximized in body after page was scrolled
+ if (jsPparentTagname === 'body') {
+
+ panelTop = jsPanel.winscrollTop() + verticalOffset + 'px';
+
+ } else {
+
+ panelTop = option.position.top;
+
+ }
+
+ panel.animate({
+
+ width: option.size.width,
+ height: option.size.height,
+ top: panelTop,
+ left: option.position.left
+
+ }, {
+ done: function () {
+
+ // hier kein fadeIn() einbauen, funktioniert nicht mit jsPanel.fixPosition(jsP);
+ panel.animate({opacity: 1}, {duration: 150});
+
+ jsPanel.hideControls(".jsPanel-btn-norm, .jsPanel-btn-smallrev", panel);
+ jsPanel.resizeTitle(panel);
+
+ if (option.resizable !== 'disabled') {
+
+ panel.resizable("enable");
+
+ }
+
+ if (option.draggable !== 'disabled') {
+
+ panel.draggable("enable");
+
+ }
+
+ panel.status = "normalized";
+
+ $(panel).trigger('jspanelnormalized', panel.attr('id'));
+ $(panel).trigger('jspanelstatechange', panel.attr('id'));
+
+ if (jsPparentTagname === 'body') {
+
+ jsPanel.fixPosition(panel);
+
+ }
+
+ jsPanel.resizeContent(panel); // to get the scrollbars back
+
+ }
+
+ });
+
+ return panel;
+
+ },
+
+ // replace bottom/right values with corresponding top/left values if necessary and update option.position
+ replaceCSSBottomRight: function (panel, optionPosition) {
+
+ var panelPosition = panel.position(),
+ panelPosTop = parseInt(panelPosition.top, 10),
+ panelPosLeft = parseInt(panelPosition.left, 10);
+
+ if (panel.css('bottom')) {
+
+ panel.css({
+
+ 'top': parseInt(panelPosition.top, 10) + 'px',
+ 'bottom': ''
+
+ });
+
+ optionPosition.top = panelPosTop;
+
+ }
+ if (panel.css('right')) {
+
+ panel.css({
+
+ 'left': parseInt(panelPosition.left, 10) + 'px',
+ 'right': ''
+
+ });
+
+ optionPosition.left = panelPosLeft;
+
+ }
+
+ },
+
+ // reposition hint upon closing
+ reposHints: function (hintGroup, jsPtagname) {
+
+ var hintH,
+ el,
+ i,
+ max = hintGroup.length;
+
+ if (jsPtagname === 'body') {
+
+ hintH = jsPanel.winscrollTop();
+
+ } else {
+
+ hintH = 0;
+
+ }
+
+ for (i = 0; i < max; i += 1) {
+
+ el = $('#' + hintGroup[i]);
+
+ el.animate({
+
+ top: hintH + 'px'
+
+ });
+
+ hintH += el.outerHeight(true);
+
+ }
+
+ },
+
+ // reposition hints on window scroll
+ reposHintsScroll: function(panel) {
+
+ var dif = panel.offset().top - jsPanel.winscrollTop();
+
+ // with window.onscroll only the last added hint would stay in position
+ $(window).scroll(function () {
+
+ panel.css('top', jsPanel.winscrollTop() + dif + 'px');
+
+ });
+
+ },
+
+ // repositions minimized jsPanels
+ reposMinimized: function () {
+
+ var minimized = $('#jsPanel-min-container > .jsPanel'),
+ minimizedCount = minimized.length,
+ i;
+
+ for (i = 0; i < minimizedCount; i += 1) {
+
+ minimized.eq(i).animate({
+
+ left: (i * jsPanel.widthForMinimized) + 'px'
+
+ });
+
+ }
+
+ },
+
+ // reset dimensions of content section after resize and so on
+ resizeContent: function (panel) {
+
+ var hdrftr,
+ poh = panel.outerHeight();
+
+ if (panel.footer.css('display') === 'none') {
+
+ hdrftr = panel.header.outerHeight();
+
+ } else {
+
+ hdrftr = panel.header.outerHeight() + panel.footer.outerHeight();
+
+ }
+
+ panel.content.css({
+
+ height: (poh - hdrftr) + 'px',
+ width: '100%'
+
+ });
+
+ return panel;
+
+ },
+
+ // resize the title h3 to use full width minus controls width (and prevent being longer than panel)
+ resizeTitle: function(panel) {
+
+ var contWidth = $(panel.header.controls).outerWidth(),
+ panelWidth = $(panel).outerWidth(),
+ titleWidth = (panelWidth - contWidth - 15) + 'px';
+
+ panel.header.title.css('width', titleWidth);
+
+ },
+
+ // restores minimized panels to their initial container, reenables resizable and draggable, repositions minimized panels
+ restoreFromMinimized: function (panel, option) {
+
+ // restore minimized panel to initial container
+ if (panel.status === "minimized") {
+
+ // hier kein fadeOut() einbauen, funktioniert nicht mit jsPanel.fixPosition(jsP)
+ panel.animate({opacity: 0}, {duration: 50});
+ panel.appendTo(option.selector);
+
+ }
+
+ if (option.resizable !== 'disabled') {
+
+ panel.resizable("enable");
+
+ }
+
+ if (option.draggable !== 'disabled') {
+
+ panel.draggable("enable");
+
+ }
+
+ // reposition minimized panels
+ jsPanel.reposMinimized(jsPanel.widthForMinimized);
+
+ },
+
+ // rewrite option.paneltype strings to objects and set defaults for option.paneltype
+ rewriteOPaneltype: function (optionPaneltype) {
+
+ var op = optionPaneltype;
+
+ if (op === 'modal') {
+
+ return {type: 'modal', mode: 'default'};
+
+ } else if (op === 'tooltip') {
+
+ return {type: 'tooltip', position: 'top'};
+
+ } else if (op === 'hint') {
+
+ return {type: 'hint'};
+
+ } else if (op.type === 'modal') {
+
+ op.mode = op.mode || 'default';
+ return {type: 'modal', mode: op.mode};
+
+ } else if (op.type === 'tooltip') {
+
+ op.mode = op.mode || false;
+ op.position = op.position || false;
+ op.shiftwithin = op.shiftwithin || "body";
+ op.solo = op.solo || false;
+ op.cornerBG = op.cornerBG || false;
+ op.cornerOX = op.cornerOX || false;
+ op.cornerOY = op.cornerOY || false;
+
+ return {
+ type: 'tooltip',
+ mode: op.mode,
+ position: op.position,
+ shiftwithin: op.shiftwithin,
+ solo: op.solo,
+ cornerBG: op.cornerBG,
+ cornerOX: op.cornerOX,
+ cornerOY: op.cornerOY
+ };
+
+ } else {
+
+ return {paneltype: false};
+
+ }
+
+ },
+
+ // converts option.position string to object
+ rewriteOPosition: function (optionPosition) {
+
+ var op = optionPosition;
+
+ if (op === 'center') {
+
+ return {top: 'center', left: 'center'};
+
+
+ }
+ if (op === 'auto') {
+
+ return {top: 'auto', left: 'auto'};
+
+ }
+
+ if (op === 'top left') {
+
+ return {top: '0', left: '0'};
+
+ }
+
+
+ if (op === 'top center') {
+ return {top: '0', left: 'center'};
+
+ }
+
+ if (op === 'top right') {
+
+ return {top: '0', right: '0'};
+
+ }
+
+ if (op === 'center right') {
+
+ return {top: 'center', right: '0'};
+
+ }
+
+ if (op === 'bottom right') {
+
+ return {bottom: '0', right: '0'};
+
+ }
+
+ if (op === 'bottom center') {
+
+ return {bottom: '0', left: 'center'};
+
+ }
+
+ if (op === 'bottom left') {
+
+ return {bottom: '0', left: '0'};
+
+ }
+
+ if (op === 'center left') {
+
+ return {top: 'center', left: '0'};
+
+ }
+
+ return optionPosition;
+
+ },
+
+ // set default options for hints and add necessary classes
+ setHintDefaults: function(option, panel) {
+
+ option.resizable = false;
+ option.draggable = false;
+ option.removeHeader = true;
+ option.toolbarFooter = false;
+ option.show = 'fadeIn';
+
+ panel.addClass('jsPanel-hint');
+ panel.content.addClass('jsPanel-hint-content');
+
+ // autoclose default 8 sec | or -1 to deactivate
+ if (!option.autoclose) {
+
+ option.autoclose = 8000;
+
+ } else if (option.autoclose < 0) {
+
+ option.autoclose = false;
+
+ }
+ // add class according option.theme to color the hint background
+ panel.content.addClass('jsPanel-hint-' + option.theme);
+
+ // add class according option.theme to color the hint background
+ if (option.theme === 'default' || option.theme === 'light') {
+
+ panel.content.append('<div class="jsPanel-hint-close-dark"></div>');
+
+ } else {
+
+ panel.content.append('<div class="jsPanel-hint-close-white"></div>');
+
+ }
+
+ },
+
+ // set default options for standard modal
+ setModalDefaults: function (option, panel) {
+
+ option.selector = 'body';
+ option.show = 'fadeIn';
+ panel.addClass('jsPanel-modal');
+
+ if (option.paneltype.mode === 'default') {
+
+ option.resizable = false;
+ option.draggable = false;
+ option.removeHeader = false;
+ option.position = {top: 'center', left: 'center'};
+ option.offset = {top: 0, left: 0};
+ option.controls.buttons = 'closeonly'; //do not delete else "modal" with no close button possible
+
+ $(".jsPanel-btn-min, .jsPanel-btn-norm, .jsPanel-btn-max, .jsPanel-btn-small, .jsPanel-btn-smallrev", panel).remove();
+ $(panel.header, panel.header.title, panel.footer).css('cursor', 'default');
+ $('.jsPanel-title', panel).css('cursor', 'inherit');
+
+ }
+
+ },
+
+ // set panel id
+ setPanelId: function (panel, optionID) {
+
+ if (typeof optionID === 'string') {
+
+ // id doesn't exist yet -> use it
+ if ($('#' + optionID).length < 1) {
+
+ panel.attr('id', optionID);
+
+ } else {
+
+ jsPanel.ID += 1;
+ panel.attr('id', 'jsPanel-' + jsPanel.ID);
+
+ // write new id as notification in title
+ $('.jsPanel-title', panel).html($('.jsPanel-title', panel).text() + ' AUTO-ID: ' + panel.attr('id'));
+
+ }
+
+ } else if ($.isFunction(optionID)) {
+
+ panel.attr('id', optionID);
+
+ }
+
+ },
+
+ // set right-to-left text direction and language; set styles and reoorder controls for rtl
+ setRTL: function(panel, optionRtlLang) {
+
+ var elmts = [ panel.header.title, panel.content, panel.header.toolbar, panel.footer ],
+ i,
+ max = elmts.length;
+
+ for (i = 0; i < max; i += 1) {
+
+ elmts[i].prop('dir', 'rtl');
+
+ if (optionRtlLang) {
+
+ elmts[i].prop('lang', optionRtlLang);
+
+ }
+
+ }
+
+ panel.header.title.css('text-align', 'right');
+ $('.jsPanel-btn-close', panel.header.controls).insertAfter($('.jsPanel-btn-min', panel.header.controls));
+ $('.jsPanel-btn-max', panel.header.controls).insertAfter($('.jsPanel-btn-min', panel.header.controls));
+ $('.jsPanel-btn-small', panel.header.controls).insertBefore($('.jsPanel-btn-min', panel.header.controls));
+ $('.jsPanel-btn-smallrev', panel.header.controls).insertBefore($('.jsPanel-btn-min', panel.header.controls));
+ $('.jsPanel-hdr-r', panel).css({left: '0px', right: '', position: 'relative', 'float': 'left'});
+ $('.jsPanel-hint-close-dark, .jsPanel-hint-close-white', panel).css('float', 'left');
+ $('.jsPanel-title', panel).css('float', 'right');
+ $('.jsPanel-ftr', panel).append('<div style="clear:both;height:0;"></div>');
+ $('button', panel.footer).css('float', 'left');
+
+ },
+
+ // set title text
+ setTitle: function (panel, text) {
+
+ if (text && typeof text === "string") {
+
+ panel.header.title.html(text);
+
+ return panel;
+
+ }
+
+ return panel;
+
+ },
+
+ // set default options for tooltips
+ setTooltipDefaults: function(option) {
+
+ option.position = {};
+ option.resizable = false;
+ option.draggable = false;
+ option.show = 'fadeIn';
+ option.controls.buttons = 'closeonly';
+
+ },
+
+ setZi: function () {
+ var zi = 100, elmtzi;
+ $('.jsPanel').each(function () {
+ elmtzi = $(this).zIndex();
+ if (elmtzi >= zi) {
+ zi = elmtzi + 1;
+ }
+ });
+ return zi;
+ },
+
+ // toggles jsPanel height between header height and normalized/maximized height
+ smallify: function (panel) {
+
+ if (panel.status !== "smallified" && panel.status !== "smallifiedMax") {
+
+ var statusNew;
+
+ if (panel.status === "maximized") {
+
+ statusNew = "smallifiedMax";
+
+ } else {
+
+ statusNew = "smallified";
+
+ }
+
+ // store panel height in function property
+ panel.smallify.height = panel.outerHeight() + 'px';
+ panel.panelheaderheight = panel.header.outerHeight() - 2;
+ panel.panelfooterheight = panel.footer.outerHeight();
+ panel.panelcontentheight = panel.content.outerHeight();
+ panel.animate({
+
+ height: panel.panelheaderheight + 'px'
+
+ },
+ {
+ done: function () {
+
+ if (panel.status === 'maximized') {
+
+ jsPanel.hideControls(".jsPanel-btn-max, .jsPanel-btn-small", panel);
+
+ } else {
+
+ jsPanel.hideControls(".jsPanel-btn-norm, .jsPanel-btn-small", panel);
+
+ }
+
+ panel.status = statusNew;
+
+ $(panel).trigger('jspanelsmallified', panel.attr('id'));
+ $(panel).trigger('jspanelstatechange', panel.attr('id'));
+
+ }
+
+ });
+
+ } else {
+ panel.animate({
+
+ height: panel.smallify.height
+
+ },
+ {
+ done: function () {
+
+ if (panel.status === 'smallified') {
+
+ jsPanel.hideControls(".jsPanel-btn-norm, .jsPanel-btn-smallrev", panel);
+ panel.status = "normalized";
+ $(panel).trigger('jspanelnormalized', panel.attr('id'));
+ $(panel).trigger('jspanelstatechange', panel.attr('id'));
+
+ } else {
+
+ jsPanel.hideControls(".jsPanel-btn-max, .jsPanel-btn-smallrev", panel);
+ panel.status = "maximized";
+ $(panel).trigger('jspanelmaximized', panel.attr('id'));
+ $(panel).trigger('jspanelstatechange', panel.attr('id'));
+
+ }
+
+ }
+
+ }
+
+ );
+
+ }
+
+ return panel;
+
+ },
+
+ // updates option.position to hold actual values
+ updateOptionPosition: function(panel, optionPosition) {
+
+ optionPosition.top = panel.css('top');
+ optionPosition.left = panel.css('left');
+
+ },
+
+ // updates option.size to hold actual values
+ updateOptionSize: function(panel, optionSize) {
+
+ optionSize.width = panel.css('width');
+ optionSize.height = panel.css('height');
+
+ },
+
+ winouterHeight: function () {
+
+ return $(window).outerHeight();
+
+ },
+
+ winouterWidth: function () {
+
+ return $(window).outerWidth();
+
+ },
+
+ winscrollLeft: function () {
+
+ return $(window).scrollLeft();
+
+ },
+
+ winscrollTop: function () {
+
+ return $(window).scrollTop();
+
+ }
+
+ };
+
+}(jQuery));
+
+(function ($) {
+ "use strict";
+
+ $.jsPanel = function (config) {
+
+ var jsP = $(jsPanel.template),
+ // Extend our default config with those provided.
+ // Note that the first arg to extend is an empty object - this is to keep from overriding our "defaults" object.
+ option = $.extend(true, {}, $.jsPanel.defaults, config),
+ anim = option.show,
+ verticalOffset = 0,
+ jsPparent,
+ jsPparentTagname,
+ count;
+
+ try {
+
+ jsPparent = $(option.selector).first();
+ jsPparentTagname = jsPparent[0].tagName.toLowerCase();
+ count = jsPparent.children('.jsPanel').length;
+
+ } catch (e) {
+
+ console.log(e);
+ console.log('The element you want to append the jsPanel to does not exist!');
+ option.selector = 'body';
+ jsPparent = $('body');
+ jsPparentTagname = 'body';
+ count = jsPparent.children('.jsPanel').length;
+
+ }
+
+ jsP.status = "initialized";
+
+ jsP.header = $('.jsPanel-hdr', jsP);
+
+ jsP.header.title = $('.jsPanel-title', jsP.header);
+
+ jsP.header.controls = $('.jsPanel-hdr-r', jsP.header);
+
+ jsP.header.toolbar = $('.jsPanel-hdr-toolbar', jsP.header);
+
+ jsP.content = $('.jsPanel-content', jsP);
+
+ jsP.footer = $('.jsPanel-ftr', jsP);
+
+ jsP.normalize = function() {
+
+ jsPanel.normalize(jsP, option, jsPparentTagname, verticalOffset);
+ return jsP;
+
+ };
+
+ jsP.close = function () {
+
+ jsPanel.close(jsP, option.paneltype.type, jsPparentTagname);
+ // no need to return something
+
+ };
+
+ jsP.closeChildpanels = function () {
+
+ jsPanel.closeChildpanels(jsP);
+ return jsP;
+
+ };
+
+ jsP.minimize = function () {
+
+ jsPanel.minimize(jsP, option.size);
+ return jsP;
+
+ };
+
+ jsP.maximize = function () {
+
+ jsPanel.maximize(jsP, jsPparentTagname, option);
+ return jsP;
+
+ };
+
+ jsP.smallify = function () {
+
+ jsPanel.smallify(jsP);
+ return jsP;
+
+ };
+
+ jsP.front = function () {
+
+ jsP.css('z-index', jsPanel.setZi());
+ return jsP;
+
+ };
+
+ jsP.title = function (text) {
+
+ if (text && typeof text === "string") {
+
+ jsPanel.setTitle(jsP, text);
+ return jsP;
+
+ } else if (arguments.length === 0) {
+
+ return jsPanel.getTitle(jsP);
+
+ }
+
+ };
+
+ jsP.addToolbar = function (place, items) {
+
+ jsPanel.addToolbar(jsP, place, items);
+ return jsP;
+
+ };
+
+ jsP.control = function (action, btn) {
+
+ jsPanel.control(jsP, action, btn);
+ return jsP;
+
+ };
+
+ jsP.resize = function (width, height) {
+ // method resizes the full panel (not content section only)
+
+ if(width && width !== null) {
+ jsP.css("width", width);
+ } else {
+ jsP.css("width", jsP.content.css("width"));
+ }
+ if(height && height !== null) {
+ jsP.css("height", height);
+ }
+ jsPanel.resizeContent(jsP);
+ jsPanel.resizeTitle(jsP);
+ return jsP;
+
+ };
+
+ /*
+ * handlers for the controls -----------------------------------------------------------------------------------
+ */
+ // handler to move panel to foreground on
+ jsP.on('click', function () {
+
+ if (!jsP.hasClass("jsPanel-modal")) {
+ jsP.css('z-index', jsPanel.setZi());
+ }
+
+ });
+
+ // jsPanel close
+ $('.jsPanel-btn-close', jsP).on('click', function (e) {
+
+ e.preventDefault();
+ jsPanel.close(jsP, option.paneltype.type, jsPparentTagname);
+
+ });
+
+ // jsPanel minimize
+ $('.jsPanel-btn-min', jsP).on('click', function (e) {
+
+ e.preventDefault();
+ jsPanel.minimize(jsP, option.size);
+
+ });
+
+ // jsPanel maximize
+ $('.jsPanel-btn-max', jsP).on('click', function (e) {
+
+ e.preventDefault();
+ jsPanel.maximize(jsP, jsPparentTagname, option);
+
+ });
+
+ // jsPanel normalize
+ $('.jsPanel-btn-norm', jsP).on('click', function (e) {
+
+ e.preventDefault();
+ jsPanel.normalize(jsP, option, jsPparentTagname, verticalOffset);
+
+ });
+
+ // jsPanel smallify
+ $('.jsPanel-btn-small, .jsPanel-btn-smallrev', jsP).on('click', function (e) {
+
+ e.preventDefault();
+ jsPanel.smallify(jsP);
+
+ });
+
+ // rewrite option.paneltype strings to objects and set defaults for option.paneltype
+ option.paneltype = jsPanel.rewriteOPaneltype(option.paneltype);
+
+ // converts option.position string to object
+ option.position = jsPanel.rewriteOPosition(option.position);
+
+ /* option.id ------------------------------------------------------------------------------------------------ */
+ // wenn option.id -> string oder function?
+ jsPanel.setPanelId(jsP, option.id);
+
+ /* option.paneltype - override or set various settings depending on option.paneltype ------------------------ */
+ if (option.paneltype.type === 'modal') {
+
+ // set defaults for standard modal
+ jsPanel.setModalDefaults(option, jsP);
+
+ // insert backdrop
+ if ($('.jsPanel-backdrop').length < 1) {
+
+ jsPanel.insertModalBackdrop();
+
+ }
+
+ } else if (option.paneltype.type === 'tooltip') {
+
+ jsPanel.setTooltipDefaults(option);
+
+ // optionally remove all other tooltips
+ if (option.paneltype.solo) {
+
+ jsPanel.closeallTooltips();
+
+ }
+
+ // calc top & left for the various tooltip positions
+ option.position = jsPanel.calcToooltipPosition(jsPparent, option);
+
+ // position the tooltip & add tooltip class
+ jsP.css({
+ top: option.position.top,
+ left: option.position.left
+ }).addClass('jsPanel-tt');
+
+ if (!jsPparent.parent().hasClass('jsPanel-tooltip-wrapper')) {
+
+ // wrap element serving as trigger in a div - will take the tooltip
+ jsPparent.wrap('<div class="jsPanel-tooltip-wrapper">');
+
+ // append tooltip (jsPanel) to the wrapper div
+ jsPparent.parent().append(jsP);
+
+ if (option.paneltype.mode === 'semisticky') {
+
+ jsP.hover(
+ function () {
+ $.noop();
+ },
+ function () {
+ jsPanel.close(jsP, option.paneltype.type, jsPparentTagname);
+ }
+ );
+
+ } else if (option.paneltype.mode === 'sticky') {
+
+ $.noop();
+
+ } else {
+
+ option.controls.buttons = 'none';
+
+ // tooltip will be removed whenever mouse leaves trigger
+ jsPparent.off('mouseout'); // to prevent mouseout from firing several times
+ jsPparent.mouseout(function () {
+
+ jsPanel.close(jsP, option.paneltype.type, jsPparentTagname);
+
+ });
+
+ }
+ }
+
+ // corners
+ jsP.css('overflow', 'visible');
+
+ if (option.paneltype.cornerBG) {
+
+ var corner = $("<div></div>"),
+ cornerLoc = "jsPanel-corner-" + option.paneltype.position,
+ cornerPos,
+ cornerOX = parseInt(option.paneltype.cornerOX) || 0,
+ cornerOY = parseInt(option.paneltype.cornerOY) || 0,
+ cornerBG = option.paneltype.cornerBG;
+
+ if (option.paneltype.position !== "bottom") {
+
+ corner.addClass("jsPanel-corner " + cornerLoc).appendTo(jsP);
+
+ } else {
+
+ corner.addClass("jsPanel-corner " + cornerLoc).prependTo(jsP);
+
+ }
+
+ if (option.paneltype.position === "top") {
+
+ cornerPos = parseInt(option.size.width)/2 - 12 + (cornerOX) + "px";
+ corner.css({borderTopColor: cornerBG, left: cornerPos});
+
+ } else if (option.paneltype.position === "right") {
+
+ cornerPos = parseInt(option.size.height)/2 - 12 + (cornerOY) + "px";
+ corner.css({borderRightColor: cornerBG, left: "-22px", top: cornerPos});
+
+ } else if (option.paneltype.position === "bottom") {
+
+ cornerPos = parseInt(option.size.width)/2 - 12 + (cornerOX) + "px";
+ corner.css({borderBottomColor: cornerBG, left: cornerPos, top: "-22px"});
+
+ } else if (option.paneltype.position === "left") {
+
+ cornerPos = parseInt(option.size.height)/2 - 12 + (cornerOY) + "px";
+ corner.css({borderLeftColor: cornerBG, left: option.size.width, top: cornerPos});
+
+ }
+
+ }
+ } else if (option.paneltype.type === 'hint') {
+
+ jsPanel.setHintDefaults(option, jsP);
+
+ // bind callback for close button
+ $('.jsPanel-hint-close-dark, .jsPanel-hint-close-white', jsP).on('click', jsP, function (event) {
+
+ event.data.close(jsP, option.paneltype.type, jsPparentTagname);
+
+ });
+
+ // set option.position for hints using 'top left', 'top center' or 'top right'
+ if (option.position.top === '0' && option.position.left === 'center') {
+ // Schleife über alle hints in jsPanel.hintsTc, Höhen aufsummieren und als top für option.position verwenden
+ if (jsPanel.hintsTc.length > 0) {
+
+ option.position = jsPanel.hintTop(jsPanel.hintsTc);
+
+ }
+ // populate array with hints
+ jsPanel.hintsTc.push(jsP.attr('id'));
+
+ } else if (option.position.top === '0' && option.position.left === '0') {
+
+ if (jsPanel.hintsTl.length > 0) {
+
+ option.position = jsPanel.hintTop(jsPanel.hintsTl);
+
+ }
+ jsPanel.hintsTl.push(jsP.attr('id'));
+
+ } else if (option.position.top === '0' && option.position.right === '0') {
+
+ if (jsPanel.hintsTr.length > 0) {
+
+ option.position = jsPanel.hintTop(jsPanel.hintsTr);
+
+ }
+ jsPanel.hintsTr.push(jsP.attr('id'));
+
+ }
+ }
+
+ /* option.selector - append jsPanel only to the first object in selector ------------------------------------ */
+ if (option.paneltype.type !== 'tooltip') {
+
+ jsP.appendTo(jsPparent);
+
+ }
+ if (option.paneltype.type === 'modal') {
+
+ jsP.css('zIndex', '1100');
+
+ if (option.paneltype.mode === 'extended') {
+
+ $('.jsPanel-backdrop').css('z-index', '999');
+
+ }
+
+ } else {
+
+ if (!jsP.hasClass("jsPanel-modal")) {
+ jsP.css('z-index', jsPanel.setZi());
+ }
+
+ }
+
+ /* option.bootstrap & option.theme -------------------------------------------------------------------------- */
+ if (option.bootstrap) {
+
+ // check whether a bootstrap compatible theme is used and set option.theme accordingly
+ option.theme = jsPanel.isBootstrapTheme(option.bootstrap);
+ option.controls.iconfont = 'bootstrap';
+
+ jsP.alterClass('jsPanel-theme-*', 'panel panel-' + option.theme);
+ jsP.header.alterClass('jsPanel-theme-*', 'panel-heading');
+ jsP.header.title.addClass('panel-title');
+ jsP.content.alterClass('jsPanel-theme-*', 'panel-body');
+ jsP.footer.addClass('panel-footer');
+
+ // fix css problems for panels nested in other bootstrap panels
+ jsP.header.title.css('color', function () {
+
+ return jsP.header.css('color');
+
+ });
+ jsP.content.css('border-top-color', function () {
+
+ return jsP.header.css('border-top-color');
+ });
+
+ } else {
+
+ // activate normal non bootstrap themes
+ jsP.alterClass('jsPanel-theme-*', 'jsPanel-theme-' + option.theme);
+ jsP.header.alterClass('jsPanel-theme-*', 'jsPanel-theme-' + option.theme);
+ jsP.content.alterClass('jsPanel-theme-*', 'jsPanel-theme-' + option.theme);
+ jsP.footer.alterClass('jsPanel-theme-*', 'jsPanel-theme-' + option.theme);
+
+ }
+
+ /* option.removeHeader -------------------------------------------------------------------------------------- */
+ if (option.removeHeader) {
+
+ jsP.header.remove();
+
+ }
+
+ /* option.controls (buttons in header right) | default: object ---------------------------------------------- */
+ if (!option.removeHeader) {
+
+ jsPanel.configControls(option.controls, jsP);
+
+ }
+
+ /* insert iconfonts if option.iconfont set (default is "jsglyph") */
+ if (option.controls.iconfont) {
+
+ jsPanel.configIconfont(option.controls.iconfont, jsP);
+
+ }
+
+ // if option.controls.iconfont === false restore old icon sprite
+ if (!option.controls.iconfont) {
+
+ $('.jsPanel-btn-close, .jsPanel-btn-max, .jsPanel-btn-norm, .jsPanel-btn-min, .jsPanel-btn-small, .jsPanel-btn-smallrev', jsP.header.controls).empty();
+
+ }
+
+ /* option.toolbarHeader | default: false -------------------------------------------------------------------- */
+ if (option.toolbarHeader && option.removeHeader === false) {
+
+ if (typeof option.toolbarHeader === 'string') {
+
+ jsP.header.toolbar.append(option.toolbarHeader);
+
+ } else if ($.isFunction(option.toolbarHeader)) {
+
+ jsP.header.toolbar.append(option.toolbarHeader(jsP.header));
+
+ } else if ($.isArray(option.toolbarHeader)) {
+
+ jsPanel.configToolbar(option.toolbarHeader, jsP.header.toolbar, jsP);
+
+ }
+ }
+
+ /* option.toolbarFooter | default: false -------------------------------------------------------------------- */
+ if (option.toolbarFooter) {
+
+ jsP.footer.css({
+
+ display: 'block',
+ padding: '0 20px 0 5px'
+
+ });
+
+ if (typeof option.toolbarFooter === 'string') {
+
+ jsP.footer.append(option.toolbarFooter);
+
+ } else if ($.isFunction(option.toolbarFooter)) {
+
+ jsP.footer.append(option.toolbarFooter(jsP.footer));
+
+ } else if ($.isArray(option.toolbarFooter)) {
+
+ jsPanel.configToolbar(option.toolbarFooter, jsP.footer, jsP);
+
+ }
+ }
+
+ /* option.rtl | default: false ------------------------------------------------------------------------------ */
+ if (option.rtl.rtl === true) {
+
+ jsPanel.setRTL(jsP, option.rtl.lang);
+
+ }
+
+ /* option.overflow | default: 'hidden' --------------------------------------------------------------------- */
+ if (typeof option.overflow === 'string') {
+
+ jsP.content.css('overflow', option.overflow);
+
+ } else if ($.isPlainObject(option.overflow)) {
+
+ jsP.content.css({
+
+ 'overflow-y': option.overflow.vertical,
+ 'overflow-x': option.overflow.horizontal
+
+ });
+
+ }
+
+ /* option.draggable ----------------------------------------------------------------------------------------- */
+ if ($.isPlainObject(option.draggable)) {
+
+ // if jsPanel is childpanel
+ if (jsP.parent().hasClass('jsPanel-content')) {
+
+ option.draggable.containment = 'parent';
+
+ }
+
+ // merge draggable settings and apply
+ option.customdraggable = $.extend(true, {}, $.jsPanel.defaults.draggable, option.draggable);
+ jsP.draggable(option.customdraggable);
+
+ } else if (option.draggable === 'disabled') {
+
+ // reset cursor, draggable deactivated
+ $('.jsPanel-title', jsP).css('cursor', 'inherit');
+
+ // jquery ui draggable initialize disabled to allow to query status
+ jsP.draggable({ disabled: true });
+
+ }
+
+ /* option.resizable ----------------------------------------------------------------------------------------- */
+ if ($.isPlainObject(option.resizable)) {
+
+ option.customresizable = $.extend(true, {}, $.jsPanel.defaults.resizable, option.resizable);
+ jsP.resizable(option.customresizable);
+
+ } else if (option.resizable === 'disabled') {
+
+ // jquery ui resizable initialize disabled to allow to query status
+ jsP.resizable({ disabled: true });
+ $('.ui-icon-gripsmall-diagonal-se', jsP).css('background-image', 'none');
+
+ }
+
+ /* option.content ------------------------------------------------------------------------------------------- */
+ // option.content can be any valid argument for jQuery.append()
+ if (option.content) {
+
+ jsP.content.append(option.content);
+
+
+ }
+
+ /* option.load ---------------------------------------------------------------------------------------------- */
+ if ($.isPlainObject(option.load) && option.load.url) {
+
+ if (!option.load.data) {
+
+ option.load.data = undefined;
+
+ }
+
+ jsP.content.load(option.load.url, option.load.data, function (responseText, textStatus, jqXHR) {
+
+ if (option.load.complete) {
+ option.load.complete(responseText, textStatus, jqXHR, jsP);
+ }
+
+ // title h3 might be to small: load() is async!
+ jsPanel.resizeTitle(jsP);
+
+ // update option.size (content might come delayed)
+ jsPanel.updateOptionSize(jsP, option.size);
+
+ // fix for a bug in jQuery-UI draggable? that causes the jsPanel to reduce width when dragged beyond boundary of containing element and option.size.width is 'auto'
+ jsP.content.css('width', function () {
+
+ return jsP.content.outerWidth() + 'px';
+
+ });
+
+ });
+
+ }
+
+ /* option.ajax ---------------------------------------------------------------------------------------------- */
+ if ($.isPlainObject(option.ajax)) {
+
+ $.ajax(option.ajax)
+
+ .done(function (data, textStatus, jqXHR) {
+
+ jsP.content.empty().append(data);
+
+ if (option.ajax.done && $.isFunction(option.ajax.done)) {
+
+
+ option.ajax.done(data, textStatus, jqXHR, jsP);
+ }
+
+ })
+
+ .fail(function (jqXHR, textStatus, errorThrown) {
+
+ if (option.ajax.fail && $.isFunction(option.ajax.fail)) {
+
+ option.ajax.fail(jqXHR, textStatus, errorThrown, jsP);
+
+ }
+
+ })
+
+ .always(function (arg1, textStatus, arg3) {
+ //In response to a successful request, the function's arguments are the same as those of .done(): data(hier: arg1), textStatus, and the jqXHR object(hier: arg3)
+ //For failed requests the arguments are the same as those of .fail(): the jqXHR object(hier: arg1), textStatus, and errorThrown(hier: arg3)
+ // fix for a bug in jQuery-UI draggable? that causes the jsPanel to reduce width when dragged beyond boundary of containing element and option.size.width is 'auto'
+
+ jsP.content.css('width', function () {
+
+ return jsP.content.outerWidth() + 'px';
+
+ });
+
+ if (option.ajax.always && $.isFunction(option.ajax.always)) {
+
+ option.ajax.always(arg1, textStatus, arg3, jsP);
+
+ }
+
+ // title h3 might be to small: load() is async!
+ jsPanel.resizeTitle(jsP);
+
+ // update option.size (content might come delayed)
+ jsPanel.updateOptionSize(jsP, option.size);
+
+ })
+
+ .then(function (data, textStatus, jqXHR) {
+
+ if (option.ajax.then && $.isArray(option.ajax.then)) {
+
+ if (option.ajax.then[0] && $.isFunction(option.ajax.then[0])) {
+
+ option.ajax.then[0](data, textStatus, jqXHR, jsP);
+
+ }
+
+ // title h3 might be to small: load() is async!
+ jsPanel.resizeTitle(jsP);
+
+ // update option.size (content might come delayed)
+ jsPanel.updateOptionSize(jsP, option.size);
+
+ }
+ }, function (jqXHR, textStatus, errorThrown) {
+
+ if (option.ajax.then && $.isArray(option.ajax.then)) {
+
+ if (option.ajax.then[1] && $.isFunction(option.ajax.then[1])) {
+
+ option.ajax.then[1](jqXHR, textStatus, errorThrown, jsP);
+
+ }
+
+ // title h3 might be to small: load() is async!
+ jsPanel.resizeTitle(jsP);
+
+ }
+
+ }
+
+ );
+
+ }
+
+ /* option.size ---------------------------------------------------------------------------------------------- */
+ if (typeof option.size === 'string' && option.size === 'auto') {
+
+ option.size = {
+
+ width: 'auto',
+ height: 'auto'
+
+ };
+
+ } else if ($.isPlainObject(option.size)) {
+
+ if (!jsPanel.isPosInt(option.size.width)) {
+
+ if (typeof option.size.width === 'string' && option.size.width !== 'auto') {
+
+ option.size.width = parseInt(option.size.width, 10);
+
+ if (option.size.width < 1 || !$.isNumeric(option.size.width)) {
+
+ option.size.width = $.jsPanel.defaults.size.width;
+
+ }
+
+ } else if ($.isFunction(option.size.width)) {
+
+ option.size.width = parseInt(option.size.width(), 10);
+
+ } else if (option.size.width !== 'auto') {
+
+ option.size.width = $.jsPanel.defaults.size.width;
+
+ }
+
+ }
+
+ if (!jsPanel.isPosInt(option.size.height)) {
+
+ if (typeof option.size.height === 'string' && option.size.height !== 'auto') {
+
+ option.size.height = parseInt(option.size.height, 10);
+
+ if (option.size.height < 1 || !$.isNumeric(option.size.height)) {
+
+ option.size.height = $.jsPanel.defaults.size.height;
+
+ }
+
+ } else if ($.isFunction(option.size.height)) {
+
+ option.size.height = parseInt(option.size.height(), 10);
+
+ } else if (option.size.height !== 'auto') {
+
+ option.size.height = $.jsPanel.defaults.size.height;
+
+ }
+
+ }
+
+ }
+
+ jsP.content.css({
+
+ width: option.size.width + 'px',
+ height: option.size.height + 'px'
+
+ });
+
+ // Important! limit title width; final adjustment follows later; otherwise title might be longer than panel width
+ jsP.header.title.css('width', jsP.content.width()-90);
+
+ /* option.iframe -------------------------------------------------------------------------------------------- */
+ // implemented after option.size because option.size.width/height are either "auto" or pixel values already
+ if ($.isPlainObject(option.iframe) && (option.iframe.src || option.iframe.srcdoc)) {
+
+ var iFrame = $("<iframe></iframe>");
+
+ // iframe content
+ if (option.iframe.srcdoc) {
+
+ iFrame.prop("srcdoc", option.iframe.srcdoc);
+
+ }
+
+ if (option.iframe.src) {
+
+ iFrame.prop("src", option.iframe.src);
+
+ }
+
+ //iframe size
+ if (option.size.width !== "auto" && !option.iframe.width) {
+
+ iFrame.prop("width", option.size.width);
+
+ } else if (typeof option.iframe.width === 'string' && option.iframe.width.slice(-1) === '%') {
+
+ iFrame.prop("width", option.iframe.width);
+
+ } else {
+
+ iFrame.prop("width", parseInt(option.iframe.width) + 'px');
+
+ }
+
+ if (option.size.height !== "auto" && !option.iframe.height) {
+
+ iFrame.prop("height", option.size.height);
+
+ } else if (typeof option.iframe.height === 'string' && option.iframe.height.slice(-1) === '%') {
+
+ iFrame.prop("height", option.iframe.height);
+
+ } else {
+
+ iFrame.prop("height", parseInt(option.iframe.height) + 'px');
+
+ }
+
+ //iframe name
+ if (typeof option.iframe.name === 'string') {
+
+ iFrame.prop("name", option.iframe.name);
+
+ }
+
+ //iframe id
+ if (typeof option.iframe.id === 'string') {
+
+ iFrame.prop("id", option.iframe.id);
+
+ }
+
+ //iframe seamless (not yet supported by any browser)
+ if (option.iframe.seamless) {
+
+ iFrame.prop("seamless", "seamless");
+
+ }
+
+ //iframe sandbox
+ if (typeof option.iframe.sandbox === 'string') {
+
+ iFrame.prop("sandox", option.iframe.sandbox);
+
+ }
+
+ //iframe style
+ if ($.isPlainObject(option.iframe.style)) {
+
+ iFrame.css(option.iframe.style);
+
+ }
+
+ //iframe css classes
+ if (typeof option.iframe.classname === 'string') {
+
+ iFrame.addClass(option.iframe.classname);
+
+ } else if ($.isFunction(option.iframe.classname)) {
+
+ iFrame.addClass(option.iframe.classname());
+
+ }
+
+ jsP.content.append(iFrame);
+ }
+
+ /* option.position ------------------------------------------------------------------------------------------ */
+ if (option.paneltype.type !== 'tooltip') {
+ // when using option.size = 'auto' and option.position = 'center' consider use of option.ajax with
+ // async: false -> size will be known when position is calculated
+ // value "center" not allowed for option.position.bottom & option.position.right -> use top and/or left
+
+ jsP.calcPanelposition = function (jsP, selector) {
+
+ var panelpos = {};
+
+ // get px values for panel size in case option.size is 'auto' - results will be incorrect whenever content
+ // is not loaded yet ( e.g. option.load, option.ajax ) -> centering can't work correctly
+ option.size.width = $(jsP).outerWidth();
+ option.size.height = $(jsP).innerHeight();
+
+ // delete op.top and/or left if option.position.bottom and/or right
+ if (option.position.bottom) {
+
+ delete option.position.top;
+
+ }
+ if (option.position.right) {
+
+ delete option.position.left;
+
+ }
+
+ // calculate top | bottom values != center
+ // if not checked for 0 as well code would not be executed!
+ if (option.position.bottom || option.position.bottom === 0) {
+
+ delete option.position.top;
+ jsPanel.calcPos('bottom', option, count, jsP);
+
+ } else if (option.position.top || option.position.top === 0) {
+
+ if (option.position.top === 'center') {
+
+ option.position.top = jsPanel.calcPosCenter(option).top;
+
+ } else {
+
+ jsPanel.calcPos('top', option, count, jsP);
+
+ }
+ }
+
+ // calculate left | right values != center
+ if (option.position.right || option.position.right === 0) {
+
+ delete option.position.left;
+ jsPanel.calcPos('right', option, count, jsP);
+
+ } else if (option.position.left || option.position.left === 0) {
+
+ if (option.position.left === 'center') {
+
+ option.position.left = jsPanel.calcPosCenter(option).left;
+
+ } else {
+
+ jsPanel.calcPos('left', option, count, jsP);
+
+ }
+
+ }
+ if (option.position.top) {
+
+ panelpos.top = parseInt(option.position.top, 10) + option.offset.top + 'px';
+
+ } else {
+
+ panelpos.bottom = parseInt(option.position.bottom, 10) + option.offset.top + 'px';
+
+ }
+ if (option.position.left) {
+
+ panelpos.left = parseInt(option.position.left, 10) + option.offset.left + 'px';
+
+ } else {
+
+ panelpos.right = parseInt(option.position.right, 10) + option.offset.left + 'px';
+
+ }
+
+ jsP.css(panelpos);
+ option.position = {
+
+ top: jsP.css('top'),
+ left: jsP.css('left')
+
+ };
+ };
+
+ // finally calculate & position the jsPanel
+ jsP.calcPanelposition(jsP, option.selector);
+
+ }
+
+ /* option.addClass ------------------------------------------------------------------------------------------ */
+ if (typeof option.addClass.header === 'string') {
+
+ jsP.header.addClass(option.addClass.header);
+
+ }
+
+ if (typeof option.addClass.content === 'string') {
+
+ jsP.content.addClass(option.addClass.content);
+
+ }
+
+ if (typeof option.addClass.footer === 'string') {
+
+ jsP.footer.addClass(option.addClass.footer);
+
+ }
+
+ // handlers for doubleclicks -------------------------------------------------------------------------------- */
+ // dblclicks disabled for normal modals, hints and tooltips
+ if (option.paneltype.mode !== "default") {
+
+ if (option.dblclicks) {
+
+ if (option.dblclicks.title) {
+
+ jsP.header.title.on('dblclick', function (e) {
+
+ e.preventDefault();
+ jsPanel.dblclickhelper(option.dblclicks.title, jsP);
+
+ });
+
+ }
+
+ if (option.dblclicks.content) {
+
+ jsP.content.on('dblclick', function (e) {
+
+ e.preventDefault();
+ jsPanel.dblclickhelper(option.dblclicks.content, jsP);
+
+ });
+
+ }
+
+ if (option.dblclicks.footer) {
+
+ jsP.footer.on('dblclick', function (e) {
+
+ e.preventDefault();
+ jsPanel.dblclickhelper(option.dblclicks.footer, jsP);
+
+ });
+
+ }
+
+ }
+
+ }
+
+ /* option.show ---------------------------------------------------------------------------------------------- */
+ if (anim.indexOf(" ") === -1) {
+
+ // if no space is found in "anim" -> function anwenden
+ jsP[anim]({
+
+ done: function () {
+
+ jsP.status = "normalized";
+
+ // trigger custom event
+ $(jsP).trigger('jspanelloaded', jsP.attr('id'));
+ $(jsP).trigger('jspanelstatechange', jsP.attr('id'));
+
+ option.size = {
+
+ width: jsP.outerWidth() + 'px',
+ height: jsP.outerHeight() + 'px'
+
+ };
+
+ }
+
+ });
+
+ } else {
+
+ jsP.status = "normalized";
+
+ // does not work with certain combinations of type of animation and positioning
+ jsP.css({
+
+ display: 'block',
+ opacity: 1
+
+ })
+ .addClass(option.show)
+ .trigger('jspanelloaded', jsP.attr('id'))
+ .trigger('jspanelstatechange', jsP.attr('id'));
+
+ option.size = {
+
+ width: jsP.outerWidth() + 'px',
+ height: jsP.outerHeight() + 'px'
+
+ };
+
+ }
+
+ /* needed if a maximized panel in body is normalized again -------------------------------------------------- */
+ // don't put this under $('body').on('jspanelloaded', function () { ... }
+ verticalOffset = jsPanel.calcVerticalOffset(jsP);
+
+ /* replace bottom/right values with corresponding top/left values if necessary ------------------------------ */
+ jsPanel.replaceCSSBottomRight(jsP, option.position);
+
+ /* option.title | needs to be late in the file! ------------------------------------------------------------- */
+ jsP.header.title.prepend(option.title);
+ jsPanel.resizeTitle(jsP);
+
+ /* reposition hints while scrolling window, must be after normalization of position ------------------------- */
+ if (option.paneltype.type === 'hint') {
+
+ jsPanel.reposHintsScroll(jsP);
+
+ }
+
+ /* reposition jsPanel appended to body while scrolling window ----------------------------------------------- */
+ if (jsPparentTagname === 'body' && (option.paneltype.type !== 'tooltip' || option.paneltype.type !== 'hint')) {
+
+ jsPanel.fixPosition(jsP);
+
+ }
+
+ /* option.callback & option.autoclose and a jQuery-UI draggable bugfix -------------------------------------- */
+ /* resizestart & resizestop & dragstop callbacks ------------------------------------------------------------ */
+ // features activated for extended modals only for @genachka
+ if (!option.paneltype || option.paneltype.mode !== 'default') {
+ // not needed for modals, hints and tooltips
+
+ $(jsP).on("resize", function () {
+
+ jsPanel.resizeContent(jsP);
+ jsPanel.resizeTitle(jsP);
+
+ });
+
+ $(jsP).on("resizestop", function () {
+
+ option.size = {
+
+ width: jsP.outerWidth() + 'px',
+ height: jsP.outerHeight() + 'px'
+
+ };
+
+ jsP.status = "normalized";
+ $(jsP).trigger('jspanelnormalized', jsP.attr('id'));
+ $(jsP).trigger('jspanelstatechange', jsP.attr('id'));
+
+ // controls und title zurücksetzen
+ jsPanel.hideControls(".jsPanel-btn-norm, .jsPanel-btn-smallrev", jsP);
+
+ });
+
+ $(jsP).on("dragstart", function () {
+
+ // remove window.scroll handler, is added again on dragstop
+ $(window).off('scroll', jsP.jsPanelfixPos);
+
+ if (option.paneltype.mode === 'extended') {
+
+ jsP.css('z-index', '1100');
+
+ }
+
+ });
+
+ $(jsP).on("dragstop", function () {
+
+ option.position = {
+
+ top: jsP.css('top'),
+ left: jsP.css('left')
+
+ };
+
+ verticalOffset = jsPanel.calcVerticalOffset(jsP);
+
+ if (jsPparentTagname === 'body') {
+
+ jsPanel.fixPosition(jsP);
+
+ }
+
+ });
+ }
+
+ /* option.autoclose | default: false --------------------------------------- */
+ if (typeof option.autoclose === 'number' && option.autoclose > 0) {
+
+ jsPanel.autoclose(jsP, jsP.attr('id'), option.autoclose);
+
+ }
+
+ /* tooltip corrections ----------------------------------------------------- */
+ if (option.paneltype.type === "tooltip" && (option.paneltype.position === "top" || option.paneltype.position === "bottom")) {
+
+ jsPanel.shiftTooltipHorizontal(jsP, option.paneltype.shiftwithin);
+
+ } else if (option.paneltype.position === "left" || option.paneltype.position === "right") {
+
+ jsPanel.shiftTooltipVertical(jsP, option.paneltype.shiftwithin);
+
+ }
+
+ /* option.callback --------------------------------------------------------- */
+ if (option.callback && $.isFunction(option.callback)) {
+
+ option.callback(jsP);
+
+ } else if ($.isArray(option.callback)) {
+ var j,
+ max = option.callback.length;
+
+ for (j = 0; j < max; j += 1) {
+
+ if ($.isFunction(option.callback[j])) {
+
+ option.callback[j](jsP);
+
+ }
+ }
+
+ }
+
+ return jsP;
+ };
+
+ /* jsPanel.defaults */
+ $.jsPanel.defaults = {
+ "addClass": {
+ header: false,
+ content: false,
+ footer: false
+ },
+ "ajax": false,
+ "autoclose": false,
+ "bootstrap": false,
+ "callback": undefined,
+ "content": false,
+ "controls": {
+ buttons: true,
+ iconfont: 'jsglyph',
+ close: false,
+ maximize: false,
+ minimize: false,
+ normalize: false,
+ smallify: false,
+ maxtoScreen: false
+ },
+ "dblclicks": false,
+ "draggable": {
+ handle: 'div.jsPanel-hdr, div.jsPanel-ftr',
+ stack: '.jsPanel',
+ opacity: 0.7
+ },
+ "id": function () {
+ jsPanel.ID += 1;
+ return 'jsPanel-' + jsPanel.ID;
+ },
+ "iframe": false,
+ "load": false,
+ "offset": {
+ top: 0,
+ left: 0
+ },
+ "paneltype": false,
+ "overflow": 'hidden',
+ "position": 'auto',
+ "removeHeader": false,
+ "resizable": {
+ handles: 'e, s, w, se, sw',
+ autoHide: false,
+ minWidth: 150,
+ minHeight: 93
+ },
+ "rtl": false,
+ "selector": 'body',
+ "show": 'fadeIn',
+ "size": {
+ width: 400,
+ height: 222
+ },
+ "theme": 'default',
+ "title": 'jsPanel',
+ "toolbarFooter": false,
+ "toolbarHeader": false
+ };
+
+ /*
+ * jQuery alterClass plugin
+ * Remove element classes with wildcard matching. Optionally add classes:
+ * $( '#foo' ).alterClass( 'foo-* bar-*', 'foobar' )
+ * Copyright (c) 2011 Pete Boere (the-echoplex.net)
+ * Free under terms of the MIT license: http://www.opensource.org/licenses/mit-license.php
+ */
+ $.fn.alterClass = function (removals, additions) {
+ var self = this,
+ patt;
+ if (removals.indexOf('*') === -1) {
+ // Use native jQuery methods if there is no wildcard matching
+ self.removeClass(removals);
+ return !additions ? self : self.addClass(additions);
+ }
+ patt = new RegExp('\\s' +
+ removals.replace(/\*/g, '[A-Za-z0-9-_]+').split(' ').join('\\s|\\s') +
+ '\\s', 'g');
+
+ self.each(function (i, it) {
+ var cn = ' ' + it.className + ' ';
+ while (patt.test(cn)) {
+ cn = cn.replace(patt, ' ');
+ }
+ it.className = $.trim(cn);
+ });
+ return !additions ? self : self.addClass(additions);
+ };
+
+ /* body click handler: remove all tooltips on click in body except click is inside tooltip */
+ $('body').click(function (e) {
+ var pID,
+ isTT = $(e.target).closest('.jsPanel-tt' ).length;
+
+ if (isTT < 1) {
+
+ $('.jsPanel-tt').each(function () {
+
+ pID = $(this).attr('id');
+
+ // if present remove tooltip wrapper and than remove tooltip
+ $('#' + pID).unwrap().remove();
+ $('body').trigger('jspanelclosed', pID);
+
+ });
+
+ }
+
+ });
+
+}(jQuery));
Added: trunk/packages/orthanc-webviewer/trunk/debian/JS/jsPanel-2.3.3/jquery.ui.touch-punch.js
===================================================================
--- trunk/packages/orthanc-webviewer/trunk/debian/JS/jsPanel-2.3.3/jquery.ui.touch-punch.js (rev 0)
+++ trunk/packages/orthanc-webviewer/trunk/debian/JS/jsPanel-2.3.3/jquery.ui.touch-punch.js 2015-03-02 09:58:59 UTC (rev 18890)
@@ -0,0 +1,180 @@
+/*!
+ * jQuery UI Touch Punch 0.2.3
+ *
+ * Copyright 2011–2014, Dave Furfero
+ * Dual licensed under the MIT or GPL Version 2 licenses.
+ *
+ * Depends:
+ * jquery.ui.widget.js
+ * jquery.ui.mouse.js
+ */
+(function ($) {
+
+ // Detect touch support
+ $.support.touch = 'ontouchend' in document;
+
+ // Ignore browsers without touch support
+ if (!$.support.touch) {
+ return;
+ }
+
+ var mouseProto = $.ui.mouse.prototype,
+ _mouseInit = mouseProto._mouseInit,
+ _mouseDestroy = mouseProto._mouseDestroy,
+ touchHandled;
+
+ /**
+ * Simulate a mouse event based on a corresponding touch event
+ * @param {Object} event A touch event
+ * @param {String} simulatedType The corresponding mouse event
+ */
+ function simulateMouseEvent (event, simulatedType) {
+
+ // Ignore multi-touch events
+ if (event.originalEvent.touches.length > 1) {
+ return;
+ }
+
+ event.preventDefault();
+
+ var touch = event.originalEvent.changedTouches[0],
+ simulatedEvent = document.createEvent('MouseEvents');
+
+ // Initialize the simulated mouse event using the touch event's coordinates
+ simulatedEvent.initMouseEvent(
+ simulatedType, // type
+ true, // bubbles
+ true, // cancelable
+ window, // view
+ 1, // detail
+ touch.screenX, // screenX
+ touch.screenY, // screenY
+ touch.clientX, // clientX
+ touch.clientY, // clientY
+ false, // ctrlKey
+ false, // altKey
+ false, // shiftKey
+ false, // metaKey
+ 0, // button
+ null // relatedTarget
+ );
+
+ // Dispatch the simulated event to the target element
+ event.target.dispatchEvent(simulatedEvent);
+ }
+
+ /**
+ * Handle the jQuery UI widget's touchstart events
+ * @param {Object} event The widget element's touchstart event
+ */
+ mouseProto._touchStart = function (event) {
+
+ var self = this;
+
+ // Ignore the event if another widget is already being handled
+ if (touchHandled || !self._mouseCapture(event.originalEvent.changedTouches[0])) {
+ return;
+ }
+
+ // Set the flag to prevent other widgets from inheriting the touch event
+ touchHandled = true;
+
+ // Track movement to determine if interaction was a click
+ self._touchMoved = false;
+
+ // Simulate the mouseover event
+ simulateMouseEvent(event, 'mouseover');
+
+ // Simulate the mousemove event
+ simulateMouseEvent(event, 'mousemove');
+
+ // Simulate the mousedown event
+ simulateMouseEvent(event, 'mousedown');
+ };
+
+ /**
+ * Handle the jQuery UI widget's touchmove events
+ * @param {Object} event The document's touchmove event
+ */
+ mouseProto._touchMove = function (event) {
+
+ // Ignore event if not handled
+ if (!touchHandled) {
+ return;
+ }
+
+ // Interaction was not a click
+ this._touchMoved = true;
+
+ // Simulate the mousemove event
+ simulateMouseEvent(event, 'mousemove');
+ };
+
+ /**
+ * Handle the jQuery UI widget's touchend events
+ * @param {Object} event The document's touchend event
+ */
+ mouseProto._touchEnd = function (event) {
+
+ // Ignore event if not handled
+ if (!touchHandled) {
+ return;
+ }
+
+ // Simulate the mouseup event
+ simulateMouseEvent(event, 'mouseup');
+
+ // Simulate the mouseout event
+ simulateMouseEvent(event, 'mouseout');
+
+ // If the touch interaction did not move, it should trigger a click
+ if (!this._touchMoved) {
+
+ // Simulate the click event
+ simulateMouseEvent(event, 'click');
+ }
+
+ // Unset the flag to allow other widgets to inherit the touch event
+ touchHandled = false;
+ };
+
+ /**
+ * A duck punch of the $.ui.mouse _mouseInit method to support touch events.
+ * This method extends the widget with bound touch event handlers that
+ * translate touch events to mouse events and pass them to the widget's
+ * original mouse event handling methods.
+ */
+ mouseProto._mouseInit = function () {
+
+ var self = this;
+
+ // Delegate the touch handlers to the widget's element
+ self.element.bind({
+ touchstart: $.proxy(self, '_touchStart'),
+ touchmove: $.proxy(self, '_touchMove'),
+ touchend: $.proxy(self, '_touchEnd')
+ });
+
+ // Call the original $.ui.mouse init method
+ _mouseInit.call(self);
+ };
+
+ /**
+ * Remove the touch event handlers
+ */
+ mouseProto._mouseDestroy = function () {
+
+ var self = this;
+
+ // Delegate the touch handlers to the widget's element
+ self.element.unbind({
+ touchstart: $.proxy(self, '_touchStart'),
+ touchmove: $.proxy(self, '_touchMove'),
+ touchend: $.proxy(self, '_touchEnd')
+ });
+
+ // Call the original $.ui.mouse destroy method
+ _mouseDestroy.call(self);
+ };
+
+})(jQuery);
\ No newline at end of file
Added: trunk/packages/orthanc-webviewer/trunk/debian/JS/jsPanel-2.3.3/jsglyph.css
===================================================================
--- trunk/packages/orthanc-webviewer/trunk/debian/JS/jsPanel-2.3.3/jsglyph.css (rev 0)
+++ trunk/packages/orthanc-webviewer/trunk/debian/JS/jsPanel-2.3.3/jsglyph.css 2015-03-02 09:58:59 UTC (rev 18890)
@@ -0,0 +1,64 @@
+ at font-face {
+ font-family: 'jsglyphregular';
+ src: url('fonts/jsglyph.eot');
+ src: url('fonts/jsglyph.eot?#iefix') format('embedded-opentype'),
+ url('fonts/jsglyph.woff2') format('woff2'),
+ url('fonts/jsglyph.woff') format('woff'),
+ url('fonts/jsglyph.ttf') format('truetype'),
+ url('fonts/jsglyph.svg#jsglyphregular') format('svg');
+ font-weight: normal;
+ font-style: normal;
+}
+.jsglyph{ font-family: "jsglyphregular"; }
+
+.jsglyph-minimize:before{ content: "\e001"; } /* unicode  */
+.jsglyph-maximize:before{ content: "\e002"; }
+.jsglyph-chevron-up:before{ content: "\e003"; }
+.jsglyph-chevron-down:before{ content: "\e004"; }
+.jsglyph-normalize:before{ content: "\e005"; }
+.jsglyph-tick:before{ content: "\e006"; }
+.jsglyph-remove:before{ content: "\e007"; }
+.jsglyph-chevron-right:before{ content: "\e008"; }
+.jsglyph-chevron-left:before{ content: "\e009"; }
+.jsglyph-plus:before{ content: "\e00a"; }
+.jsglyph-minus:before{ content: "\e00b"; }
+.jsglyph-trashcan:before{ content: "\e00c"; }
+.jsglyph-square-info:before{ content: "\e00d"; }
+.jsglyph-square-exclamationmark:before{ content: "\e00e"; }
+.jsglyph-delete:before{ content: "\e00f"; }
+
+.jsglyph-mail:before{ content: "\e010"; }
+.jsglyph-envelope:before{ content: "\e011"; }
+.jsglyph-play:before{ content: "\e012"; }
+.jsglyph-forward:before{ content: "\e013"; }
+.jsglyph-backward:before{ content: "\e014"; }
+.jsglyph-step-forward:before{ content: "\e015"; }
+.jsglyph-step-backwardbefore{ content: "\e016"; }
+.jsglyph-fast-forward:before{ content: "\e017"; }
+.jsglyph-fast-backward:before{ content: "\e018"; }
+.jsglyph-eject:before{ content: "\e019"; }
+.jsglyph-stop:before{ content: "\e01a"; }
+.jsglyph-pause:before{ content: "\e01b"; }
+.jsglyph-arrow-right:before{ content: "\e01c"; }
+.jsglyph-arrow-left:before{ content: "\e01d"; }
+.jsglyph-arrow-up:before{ content: "\e01e"; }
+.jsglyph-arrow-down:before{ content: "\e01f"; }
+
+.jsglyph-star-halffull:before{ content: "\e020"; }
+.jsglyph-star:before{ content: "\e021"; }
+.jsglyph-star-empty:before{ content: "\e022"; }
+.jsglyph-arrow-right-hollow:before{ content: "\e023"; }
+.jsglyph-arrow-left-hollow:before{ content: "\e024"; }
+.jsglyph-arrow-up-hollow:before{ content: "\e025"; }
+.jsglyph-arrow-down-hollow:before{ content: "\e026"; }
+.jsglyph-square-questionmark:before{ content: "\e027"; }
+.jsglyph-circle-info:before{ content: "\e028"; }
+.jsglyph-circle-exclamationmark:before{ content: "\e029"; }
+.jsglyph-circle-qustionmark:before{ content: "\e02a"; }
+.jsglyph-circle2-info:before{ content: "\e02b"; }
+.jsglyph-circle2-exclamationmark:before{ content: "\e02c"; }
+.jsglyph-circle2-questionmark:before{ content: "\e02d"; }
+/*.jsglyph-:before{ content: "\e02e"; }*/
+/*.jsglyph-:before{ content: "\e02f"; }*/
+
+
Added: trunk/packages/orthanc-webviewer/trunk/debian/JS/jsPanel-2.3.3/mobile-detect.js
===================================================================
--- trunk/packages/orthanc-webviewer/trunk/debian/JS/jsPanel-2.3.3/mobile-detect.js (rev 0)
+++ trunk/packages/orthanc-webviewer/trunk/debian/JS/jsPanel-2.3.3/mobile-detect.js 2015-03-02 09:58:59 UTC (rev 18890)
@@ -0,0 +1,871 @@
+// THIS FILE IS GENERATED - DO NOT EDIT!
+/*global module:false, define:false*/
+
+(function (define, undefined) {
+define(function () {
+ 'use strict';
+
+ var mobileDetectRules = {
+ "phones": {
+ "iPhone": "\\biPhone\\b|\\biPod\\b",
+ "BlackBerry": "BlackBerry|\\bBB10\\b|rim[0-9]+",
+ "HTC": "HTC|HTC.*(Sensation|Evo|Vision|Explorer|6800|8100|8900|A7272|S510e|C110e|Legend|Desire|T8282)|APX515CKT|Qtek9090|APA9292KT|HD_mini|Sensation.*Z710e|PG86100|Z715e|Desire.*(A8181|HD)|ADR6200|ADR6400L|ADR6425|001HT|Inspire 4G|Android.*\\bEVO\\b|T-Mobile G1|Z520m",
+ "Nexus": "Nexus One|Nexus S|Galaxy.*Nexus|Android.*Nexus.*Mobile|Nexus 4|Nexus 5|Nexus 6",
+ "Dell": "Dell.*Streak|Dell.*Aero|Dell.*Venue|DELL.*Venue Pro|Dell Flash|Dell Smoke|Dell Mini 3iX|XCD28|XCD35|\\b001DL\\b|\\b101DL\\b|\\bGS01\\b",
+ "Motorola": "Motorola|DROIDX|DROID BIONIC|\\bDroid\\b.*Build|Android.*Xoom|HRI39|MOT-|A1260|A1680|A555|A853|A855|A953|A955|A956|Motorola.*ELECTRIFY|Motorola.*i1|i867|i940|MB200|MB300|MB501|MB502|MB508|MB511|MB520|MB525|MB526|MB611|MB612|MB632|MB810|MB855|MB860|MB861|MB865|MB870|ME501|ME502|ME511|ME525|ME600|ME632|ME722|ME811|ME860|ME863|ME865|MT620|MT710|MT716|MT720|MT810|MT870|MT917|Motorola.*TITANIUM|WX435|WX445|XT300|XT301|XT311|XT316|XT317|XT319|XT320|XT390|XT502|XT530|XT531|XT532|XT535|XT603|XT610|XT611|XT615|XT681|XT701|XT702|XT711|XT720|XT800|XT806|XT860|XT862|XT875|XT882|XT883|XT894|XT901|XT907|XT909|XT910|XT912|XT928|XT926|XT915|XT919|XT925",
+ "Samsung": "Samsung|SGH-I337|BGT-S5230|GT-B2100|GT-B2700|GT-B2710|GT-B3210|GT-B3310|GT-B3410|GT-B3730|GT-B3740|GT-B5510|GT-B5512|GT-B5722|GT-B6520|GT-B7300|GT-B7320|GT-B7330|GT-B7350|GT-B7510|GT-B7722|GT-B7800|GT-C3010|GT-C3011|GT-C3060|GT-C3200|GT-C3212|GT-C3212I|GT-C3262|GT-C3222|GT-C3300|GT-C3300K|GT-C3303|GT-C3303K|GT-C3310|GT-C3322|GT-C3330|GT-C3350|GT-C3500|GT-C3510|GT-C3530|GT-C3630|GT-C3780|GT-C5010|GT-C5212|GT-C6620|GT-C6625|GT-C6712|GT-E1050|GT-E1070|GT-E1075|GT-E1080|GT-E1081|GT-E1085|GT-E1087|GT-E1100|GT-E1107|GT-E1110|GT-E1120|GT-E1125|GT-E1130|GT-E1160|GT-E1170|GT-E1175|GT-E1180|GT-E1182|GT-E1200|GT-E1210|GT-E1225|GT-E1230|GT-E1390|GT-E2100|GT-E2120|GT-E2121|GT-E2152|GT-E2220|GT-E2222|GT-E2230|GT-E2232|GT-E2250|GT-E2370|GT-E2550|GT-E2652|GT-E3210|GT-E3213|GT-I5500|GT-I5503|GT-I5700|GT-I5800|GT-I5801|GT-I6410|GT-I6420|GT-I7110|GT-I7410|GT-I7500|GT-I8000|GT-I8150|GT-I8160|GT-I8190|GT-I8320|GT-I8330|GT-I8350|GT-I8530|GT-I8700|GT-I8703|GT-I8910|GT-I9000|GT-I9001|GT-I9003|GT-I9010|GT-I9020|GT-I9023|GT-I9070|GT-I9082|GT-I9100|GT-I9103|GT-I9220|GT-I9250|GT-I9300|GT-I9305|GT-I9500|GT-I9505|GT-M3510|GT-M5650|GT-M7500|GT-M7600|GT-M7603|GT-M8800|GT-M8910|GT-N7000|GT-S3110|GT-S3310|GT-S3350|GT-S3353|GT-S3370|GT-S3650|GT-S3653|GT-S3770|GT-S3850|GT-S5210|GT-S5220|GT-S5229|GT-S5230|GT-S5233|GT-S5250|GT-S5253|GT-S5260|GT-S5263|GT-S5270|GT-S5300|GT-S5330|GT-S5350|GT-S5360|GT-S5363|GT-S5369|GT-S5380|GT-S5380D|GT-S5560|GT-S5570|GT-S5600|GT-S5603|GT-S5610|GT-S5620|GT-S5660|GT-S5670|GT-S5690|GT-S5750|GT-S5780|GT-S5830|GT-S5839|GT-S6102|GT-S6500|GT-S7070|GT-S7200|GT-S7220|GT-S7230|GT-S7233|GT-S7250|GT-S7500|GT-S7530|GT-S7550|GT-S7562|GT-S7710|GT-S8000|GT-S8003|GT-S8500|GT-S8530|GT-S8600|SCH-A310|SCH-A530|SCH-A570|SCH-A610|SCH-A630|SCH-A650|SCH-A790|SCH-A795|SCH-A850|SCH-A870|SCH-A890|SCH-A930|SCH-A950|SCH-A970|SCH-A990|SCH-I100|SCH-I110|SCH-I400|SCH-I405|SCH-I500|SCH-I510|SCH-I515|SCH-I600|SCH-I730|SCH-I760|SCH-I770|SCH-I830|SCH-I910|SCH-I920|SCH-I959|SCH-LC11|SCH-N150|SCH-N300|SCH-R100|SCH-R300|SCH-R351|SCH-R400|SCH-R410|SCH-T300|SCH-U310|SCH-U320|SCH-U350|SCH-U360|SCH-U365|SCH-U370|SCH-U380|SCH-U410|SCH-U430|SCH-U450|SCH-U460|SCH-U470|SCH-U490|SCH-U540|SCH-U550|SCH-U620|SCH-U640|SCH-U650|SCH-U660|SCH-U700|SCH-U740|SCH-U750|SCH-U810|SCH-U820|SCH-U900|SCH-U940|SCH-U960|SCS-26UC|SGH-A107|SGH-A117|SGH-A127|SGH-A137|SGH-A157|SGH-A167|SGH-A177|SGH-A187|SGH-A197|SGH-A227|SGH-A237|SGH-A257|SGH-A437|SGH-A517|SGH-A597|SGH-A637|SGH-A657|SGH-A667|SGH-A687|SGH-A697|SGH-A707|SGH-A717|SGH-A727|SGH-A737|SGH-A747|SGH-A767|SGH-A777|SGH-A797|SGH-A817|SGH-A827|SGH-A837|SGH-A847|SGH-A867|SGH-A877|SGH-A887|SGH-A897|SGH-A927|SGH-B100|SGH-B130|SGH-B200|SGH-B220|SGH-C100|SGH-C110|SGH-C120|SGH-C130|SGH-C140|SGH-C160|SGH-C170|SGH-C180|SGH-C200|SGH-C207|SGH-C210|SGH-C225|SGH-C230|SGH-C417|SGH-C450|SGH-D307|SGH-D347|SGH-D357|SGH-D407|SGH-D415|SGH-D780|SGH-D807|SGH-D980|SGH-E105|SGH-E200|SGH-E315|SGH-E316|SGH-E317|SGH-E335|SGH-E590|SGH-E635|SGH-E715|SGH-E890|SGH-F300|SGH-F480|SGH-I200|SGH-I300|SGH-I320|SGH-I550|SGH-I577|SGH-I600|SGH-I607|SGH-I617|SGH-I627|SGH-I637|SGH-I677|SGH-I700|SGH-I717|SGH-I727|SGH-i747M|SGH-I777|SGH-I780|SGH-I827|SGH-I847|SGH-I857|SGH-I896|SGH-I897|SGH-I900|SGH-I907|SGH-I917|SGH-I927|SGH-I937|SGH-I997|SGH-J150|SGH-J200|SGH-L170|SGH-L700|SGH-M110|SGH-M150|SGH-M200|SGH-N105|SGH-N500|SGH-N600|SGH-N620|SGH-N625|SGH-N700|SGH-N710|SGH-P107|SGH-P207|SGH-P300|SGH-P310|SGH-P520|SGH-P735|SGH-P777|SGH-Q105|SGH-R210|SGH-R220|SGH-R225|SGH-S105|SGH-S307|SGH-T109|SGH-T119|SGH-T139|SGH-T209|SGH-T219|SGH-T229|SGH-T239|SGH-T249|SGH-T259|SGH-T309|SGH-T319|SGH-T329|SGH-T339|SGH-T349|SGH-T359|SGH-T369|SGH-T379|SGH-T409|SGH-T429|SGH-T439|SGH-T459|SGH-T469|SGH-T479|SGH-T499|SGH-T509|SGH-T519|SGH-T539|SGH-T559|SGH-T589|SGH-T609|SGH-T619|SGH-T629|SGH-T639|SGH-T659|SGH-T669|SGH-T679|SGH-T709|SGH-T719|SGH-T729|SGH-T739|SGH-T746|SGH-T749|SGH-T759|SGH-T769|SGH-T809|SGH-T819|SGH-T839|SGH-T919|SGH-T929|SGH-T939|SGH-T959|SGH-T989|SGH-U100|SGH-U200|SGH-U800|SGH-V205|SGH-V206|SGH-X100|SGH-X105|SGH-X120|SGH-X140|SGH-X426|SGH-X427|SGH-X475|SGH-X495|SGH-X497|SGH-X507|SGH-X600|SGH-X610|SGH-X620|SGH-X630|SGH-X700|SGH-X820|SGH-X890|SGH-Z130|SGH-Z150|SGH-Z170|SGH-ZX10|SGH-ZX20|SHW-M110|SPH-A120|SPH-A400|SPH-A420|SPH-A460|SPH-A500|SPH-A560|SPH-A600|SPH-A620|SPH-A660|SPH-A700|SPH-A740|SPH-A760|SPH-A790|SPH-A800|SPH-A820|SPH-A840|SPH-A880|SPH-A900|SPH-A940|SPH-A960|SPH-D600|SPH-D700|SPH-D710|SPH-D720|SPH-I300|SPH-I325|SPH-I330|SPH-I350|SPH-I500|SPH-I600|SPH-I700|SPH-L700|SPH-M100|SPH-M220|SPH-M240|SPH-M300|SPH-M305|SPH-M320|SPH-M330|SPH-M350|SPH-M360|SPH-M370|SPH-M380|SPH-M510|SPH-M540|SPH-M550|SPH-M560|SPH-M570|SPH-M580|SPH-M610|SPH-M620|SPH-M630|SPH-M800|SPH-M810|SPH-M850|SPH-M900|SPH-M910|SPH-M920|SPH-M930|SPH-N100|SPH-N200|SPH-N240|SPH-N300|SPH-N400|SPH-Z400|SWC-E100|SCH-i909|GT-N7100|GT-N7105|SCH-I535|SM-N900A|SGH-I317|SGH-T999L|GT-S5360B|GT-I8262|GT-S6802|GT-S6312|GT-S6310|GT-S5312|GT-S5310|GT-I9105|GT-I8510|GT-S6790N|SM-G7105|SM-N9005|GT-S5301|GT-I9295|GT-I9195|SM-C101|GT-S7392|GT-S7560|GT-B7610|GT-I5510|GT-S7582|GT-S7530E|GT-I8750",
+ "LG": "\\bLG\\b;|LG[- ]?(C800|C900|E400|E610|E900|E-900|F160|F180K|F180L|F180S|730|855|L160|LS740|LS840|LS970|LU6200|MS690|MS695|MS770|MS840|MS870|MS910|P500|P700|P705|VM696|AS680|AS695|AX840|C729|E970|GS505|272|C395|E739BK|E960|L55C|L75C|LS696|LS860|P769BK|P350|P500|P509|P870|UN272|US730|VS840|VS950|LN272|LN510|LS670|LS855|LW690|MN270|MN510|P509|P769|P930|UN200|UN270|UN510|UN610|US670|US740|US760|UX265|UX840|VN271|VN530|VS660|VS700|VS740|VS750|VS910|VS920|VS930|VX9200|VX11000|AX840A|LW770|P506|P925|P999|E612|D955|D802)",
+ "Sony": "SonyST|SonyLT|SonyEricsson|SonyEricssonLT15iv|LT18i|E10i|LT28h|LT26w|SonyEricssonMT27i|C5303|C6902|C6903|C6906|C6943|D2533",
+ "Asus": "Asus.*Galaxy|PadFone.*Mobile",
+ "Micromax": "Micromax.*\\b(A210|A92|A88|A72|A111|A110Q|A115|A116|A110|A90S|A26|A51|A35|A54|A25|A27|A89|A68|A65|A57|A90)\\b",
+ "Palm": "PalmSource|Palm",
+ "Vertu": "Vertu|Vertu.*Ltd|Vertu.*Ascent|Vertu.*Ayxta|Vertu.*Constellation(F|Quest)?|Vertu.*Monika|Vertu.*Signature",
+ "Pantech": "PANTECH|IM-A850S|IM-A840S|IM-A830L|IM-A830K|IM-A830S|IM-A820L|IM-A810K|IM-A810S|IM-A800S|IM-T100K|IM-A725L|IM-A780L|IM-A775C|IM-A770K|IM-A760S|IM-A750K|IM-A740S|IM-A730S|IM-A720L|IM-A710K|IM-A690L|IM-A690S|IM-A650S|IM-A630K|IM-A600S|VEGA PTL21|PT003|P8010|ADR910L|P6030|P6020|P9070|P4100|P9060|P5000|CDM8992|TXT8045|ADR8995|IS11PT|P2030|P6010|P8000|PT002|IS06|CDM8999|P9050|PT001|TXT8040|P2020|P9020|P2000|P7040|P7000|C790",
+ "Fly": "IQ230|IQ444|IQ450|IQ440|IQ442|IQ441|IQ245|IQ256|IQ236|IQ255|IQ235|IQ245|IQ275|IQ240|IQ285|IQ280|IQ270|IQ260|IQ250",
+ "iMobile": "i-mobile (IQ|i-STYLE|idea|ZAA|Hitz)",
+ "SimValley": "\\b(SP-80|XT-930|SX-340|XT-930|SX-310|SP-360|SP60|SPT-800|SP-120|SPT-800|SP-140|SPX-5|SPX-8|SP-100|SPX-8|SPX-12)\\b",
+ "Wolfgang": "AT-B24D|AT-AS50HD|AT-AS40W|AT-AS55HD|AT-AS45q2|AT-B26D|AT-AS50Q",
+ "Alcatel": "Alcatel",
+ "Nintendo": "Nintendo 3DS",
+ "Amoi": "Amoi",
+ "INQ": "INQ",
+ "GenericPhone": "Tapatalk|PDA;|SAGEM|\\bmmp\\b|pocket|\\bpsp\\b|symbian|Smartphone|smartfon|treo|up.browser|up.link|vodafone|\\bwap\\b|nokia|Series40|Series60|S60|SonyEricsson|N900|MAUI.*WAP.*Browser"
+ },
+ "tablets": {
+ "iPad": "iPad|iPad.*Mobile",
+ "NexusTablet": "Android.*Nexus[\\s]+(7|9|10)|^.*Android.*Nexus(?:(?!Mobile).)*$",
+ "SamsungTablet": "SAMSUNG.*Tablet|Galaxy.*Tab|SC-01C|GT-P1000|GT-P1003|GT-P1010|GT-P3105|GT-P6210|GT-P6800|GT-P6810|GT-P7100|GT-P7300|GT-P7310|GT-P7500|GT-P7510|SCH-I800|SCH-I815|SCH-I905|SGH-I957|SGH-I987|SGH-T849|SGH-T859|SGH-T869|SPH-P100|GT-P3100|GT-P3108|GT-P3110|GT-P5100|GT-P5110|GT-P6200|GT-P7320|GT-P7511|GT-N8000|GT-P8510|SGH-I497|SPH-P500|SGH-T779|SCH-I705|SCH-I915|GT-N8013|GT-P3113|GT-P5113|GT-P8110|GT-N8010|GT-N8005|GT-N8020|GT-P1013|GT-P6201|GT-P7501|GT-N5100|GT-N5105|GT-N5110|SHV-E140K|SHV-E140L|SHV-E140S|SHV-E150S|SHV-E230K|SHV-E230L|SHV-E230S|SHW-M180K|SHW-M180L|SHW-M180S|SHW-M180W|SHW-M300W|SHW-M305W|SHW-M380K|SHW-M380S|SHW-M380W|SHW-M430W|SHW-M480K|SHW-M480S|SHW-M480W|SHW-M485W|SHW-M486W|SHW-M500W|GT-I9228|SCH-P739|SCH-I925|GT-I9200|GT-I9205|GT-P5200|GT-P5210|GT-P5210X|SM-T311|SM-T310|SM-T310X|SM-T210|SM-T210R|SM-T211|SM-P600|SM-P601|SM-P605|SM-P900|SM-P901|SM-T217|SM-T217A|SM-T217S|SM-P6000|SM-T3100|SGH-I467|XE500|SM-T110|GT-P5220|GT-I9200X|GT-N5110X|GT-N5120|SM-P905|SM-T111|SM-T2105|SM-T315|SM-T320|SM-T320X|SM-T321|SM-T520|SM-T525|SM-T530NU|SM-T230NU|SM-T330NU|SM-T900|XE500T1C|SM-P605V|SM-P905V|SM-P600X|SM-P900X|SM-T210X|SM-T230|SM-T230X|SM-T325|GT-P7503|SM-T531|SM-T330|SM-T530|SM-T705C|SM-T535|SM-T331|SM-T800|SM-T700|SM-T537|SM-T807|SM-P907A|SM-T337A|SM-T707A|SM-T807A|SM-T237P|SM-T807P|SM-P607T|SM-T217T|SM-T337T",
+ "Kindle": "Kindle|Silk.*Accelerated|Android.*\\b(KFOT|KFTT|KFJWI|KFJWA|KFOTE|KFSOWI|KFTHWI|KFTHWA|KFAPWI|KFAPWA|WFJWAE|KFSAWA|KFSAWI|KFASWI)\\b",
+ "SurfaceTablet": "Windows NT [0-9.]+; ARM;.*(Tablet|ARMBJS)",
+ "HPTablet": "HP Slate (7|8|10)|HP ElitePad 900|hp-tablet|EliteBook.*Touch|HP 8|Slate 21|HP SlateBook 10",
+ "AsusTablet": "^.*PadFone((?!Mobile).)*$|Transformer|TF101|TF101G|TF300T|TF300TG|TF300TL|TF700T|TF700KL|TF701T|TF810C|ME171|ME301T|ME302C|ME371MG|ME370T|ME372MG|ME172V|ME173X|ME400C|Slider SL101|\\bK00F\\b|\\bK00C\\b|\\bK00E\\b|\\bK00L\\b|TX201LA|ME176C|ME102A|\\bM80TA\\b|ME372CL|ME560CG|ME372CG",
+ "BlackBerryTablet": "PlayBook|RIM Tablet",
+ "HTCtablet": "HTC_Flyer_P512|HTC Flyer|HTC Jetstream|HTC-P715a|HTC EVO View 4G|PG41200|PG09410",
+ "MotorolaTablet": "xoom|sholest|MZ615|MZ605|MZ505|MZ601|MZ602|MZ603|MZ604|MZ606|MZ607|MZ608|MZ609|MZ615|MZ616|MZ617",
+ "NookTablet": "Android.*Nook|NookColor|nook browser|BNRV200|BNRV200A|BNTV250|BNTV250A|BNTV400|BNTV600|LogicPD Zoom2",
+ "AcerTablet": "Android.*; \\b(A100|A101|A110|A200|A210|A211|A500|A501|A510|A511|A700|A701|W500|W500P|W501|W501P|W510|W511|W700|G100|G100W|B1-A71|B1-710|B1-711|A1-810|A1-811|A1-830)\\b|W3-810|\\bA3-A10\\b",
+ "ToshibaTablet": "Android.*(AT100|AT105|AT200|AT205|AT270|AT275|AT300|AT305|AT1S5|AT500|AT570|AT700|AT830)|TOSHIBA.*FOLIO",
+ "LGTablet": "\\bL-06C|LG-V909|LG-V900|LG-V700|LG-V510|LG-V500|LG-V410|LG-V400|LG-VK810\\b",
+ "FujitsuTablet": "Android.*\\b(F-01D|F-02F|F-05E|F-10D|M532|Q572)\\b",
+ "PrestigioTablet": "PMP3170B|PMP3270B|PMP3470B|PMP7170B|PMP3370B|PMP3570C|PMP5870C|PMP3670B|PMP5570C|PMP5770D|PMP3970B|PMP3870C|PMP5580C|PMP5880D|PMP5780D|PMP5588C|PMP7280C|PMP7280C3G|PMP7280|PMP7880D|PMP5597D|PMP5597|PMP7100D|PER3464|PER3274|PER3574|PER3884|PER5274|PER5474|PMP5097CPRO|PMP5097|PMP7380D|PMP5297C|PMP5297C_QUAD",
+ "LenovoTablet": "Idea(Tab|Pad)( A1|A10| K1|)|ThinkPad([ ]+)?Tablet|Lenovo.*(S2109|S2110|S5000|S6000|K3011|A3000|A3500|A1000|A2107|A2109|A1107|A5500|A7600|B6000|B8000|B8080)(-|)(FL|F|HV|H|)",
+ "DellTablet": "Venue 11|Venue 8|Venue 7|Dell Streak 10|Dell Streak 7",
+ "YarvikTablet": "Android.*\\b(TAB210|TAB211|TAB224|TAB250|TAB260|TAB264|TAB310|TAB360|TAB364|TAB410|TAB411|TAB420|TAB424|TAB450|TAB460|TAB461|TAB464|TAB465|TAB467|TAB468|TAB07-100|TAB07-101|TAB07-150|TAB07-151|TAB07-152|TAB07-200|TAB07-201-3G|TAB07-210|TAB07-211|TAB07-212|TAB07-214|TAB07-220|TAB07-400|TAB07-485|TAB08-150|TAB08-200|TAB08-201-3G|TAB08-201-30|TAB09-100|TAB09-211|TAB09-410|TAB10-150|TAB10-201|TAB10-211|TAB10-400|TAB10-410|TAB13-201|TAB274EUK|TAB275EUK|TAB374EUK|TAB462EUK|TAB474EUK|TAB9-200)\\b",
+ "MedionTablet": "Android.*\\bOYO\\b|LIFE.*(P9212|P9514|P9516|S9512)|LIFETAB",
+ "ArnovaTablet": "AN10G2|AN7bG3|AN7fG3|AN8G3|AN8cG3|AN7G3|AN9G3|AN7dG3|AN7dG3ST|AN7dG3ChildPad|AN10bG3|AN10bG3DT|AN9G2",
+ "IntensoTablet": "INM8002KP|INM1010FP|INM805ND|Intenso Tab|TAB1004",
+ "IRUTablet": "M702pro",
+ "MegafonTablet": "MegaFon V9|\\bZTE V9\\b|Android.*\\bMT7A\\b",
+ "EbodaTablet": "E-Boda (Supreme|Impresspeed|Izzycomm|Essential)",
+ "AllViewTablet": "Allview.*(Viva|Alldro|City|Speed|All TV|Frenzy|Quasar|Shine|TX1|AX1|AX2)",
+ "ArchosTablet": "\\b(101G9|80G9|A101IT)\\b|Qilive 97R|Archos5|\\bARCHOS (70|79|80|90|97|101|FAMILYPAD|)(b|)(G10| Cobalt| TITANIUM(HD|)| Xenon| Neon|XSK| 2| XS 2| PLATINUM| CARBON|GAMEPAD)\\b",
+ "AinolTablet": "NOVO7|NOVO8|NOVO10|Novo7Aurora|Novo7Basic|NOVO7PALADIN|novo9-Spark",
+ "SonyTablet": "Sony.*Tablet|Xperia Tablet|Sony Tablet S|SO-03E|SGPT12|SGPT13|SGPT114|SGPT121|SGPT122|SGPT123|SGPT111|SGPT112|SGPT113|SGPT131|SGPT132|SGPT133|SGPT211|SGPT212|SGPT213|SGP311|SGP312|SGP321|EBRD1101|EBRD1102|EBRD1201|SGP351|SGP341|SGP511|SGP512|SGP521|SGP541|SGP551",
+ "PhilipsTablet": "\\b(PI2010|PI3000|PI3100|PI3105|PI3110|PI3205|PI3210|PI3900|PI4010|PI7000|PI7100)\\b",
+ "CubeTablet": "Android.*(K8GT|U9GT|U10GT|U16GT|U17GT|U18GT|U19GT|U20GT|U23GT|U30GT)|CUBE U8GT",
+ "CobyTablet": "MID1042|MID1045|MID1125|MID1126|MID7012|MID7014|MID7015|MID7034|MID7035|MID7036|MID7042|MID7048|MID7127|MID8042|MID8048|MID8127|MID9042|MID9740|MID9742|MID7022|MID7010",
+ "MIDTablet": "M9701|M9000|M9100|M806|M1052|M806|T703|MID701|MID713|MID710|MID727|MID760|MID830|MID728|MID933|MID125|MID810|MID732|MID120|MID930|MID800|MID731|MID900|MID100|MID820|MID735|MID980|MID130|MID833|MID737|MID960|MID135|MID860|MID736|MID140|MID930|MID835|MID733",
+ "MSITablet": "MSI \\b(Primo 73K|Primo 73L|Primo 81L|Primo 77|Primo 93|Primo 75|Primo 76|Primo 73|Primo 81|Primo 91|Primo 90|Enjoy 71|Enjoy 7|Enjoy 10)\\b",
+ "SMiTTablet": "Android.*(\\bMID\\b|MID-560|MTV-T1200|MTV-PND531|MTV-P1101|MTV-PND530)",
+ "RockChipTablet": "Android.*(RK2818|RK2808A|RK2918|RK3066)|RK2738|RK2808A",
+ "FlyTablet": "IQ310|Fly Vision",
+ "bqTablet": "bq.*(Elcano|Curie|Edison|Maxwell|Kepler|Pascal|Tesla|Hypatia|Platon|Newton|Livingstone|Cervantes|Avant)|Maxwell.*Lite|Maxwell.*Plus",
+ "HuaweiTablet": "MediaPad|MediaPad 7 Youth|IDEOS S7|S7-201c|S7-202u|S7-101|S7-103|S7-104|S7-105|S7-106|S7-201|S7-Slim",
+ "NecTablet": "\\bN-06D|\\bN-08D",
+ "PantechTablet": "Pantech.*P4100",
+ "BronchoTablet": "Broncho.*(N701|N708|N802|a710)",
+ "VersusTablet": "TOUCHPAD.*[78910]|\\bTOUCHTAB\\b",
+ "ZyncTablet": "z1000|Z99 2G|z99|z930|z999|z990|z909|Z919|z900",
+ "PositivoTablet": "TB07STA|TB10STA|TB07FTA|TB10FTA",
+ "NabiTablet": "Android.*\\bNabi",
+ "KoboTablet": "Kobo Touch|\\bK080\\b|\\bVox\\b Build|\\bArc\\b Build",
+ "DanewTablet": "DSlide.*\\b(700|701R|702|703R|704|802|970|971|972|973|974|1010|1012)\\b",
+ "TexetTablet": "NaviPad|TB-772A|TM-7045|TM-7055|TM-9750|TM-7016|TM-7024|TM-7026|TM-7041|TM-7043|TM-7047|TM-8041|TM-9741|TM-9747|TM-9748|TM-9751|TM-7022|TM-7021|TM-7020|TM-7011|TM-7010|TM-7023|TM-7025|TM-7037W|TM-7038W|TM-7027W|TM-9720|TM-9725|TM-9737W|TM-1020|TM-9738W|TM-9740|TM-9743W|TB-807A|TB-771A|TB-727A|TB-725A|TB-719A|TB-823A|TB-805A|TB-723A|TB-715A|TB-707A|TB-705A|TB-709A|TB-711A|TB-890HD|TB-880HD|TB-790HD|TB-780HD|TB-770HD|TB-721HD|TB-710HD|TB-434HD|TB-860HD|TB-840HD|TB-760HD|TB-750HD|TB-740HD|TB-730HD|TB-722HD|TB-720HD|TB-700HD|TB-500HD|TB-470HD|TB-431HD|TB-430HD|TB-506|TB-504|TB-446|TB-436|TB-416|TB-146SE|TB-126SE",
+ "PlaystationTablet": "Playstation.*(Portable|Vita)",
+ "TrekstorTablet": "ST10416-1|VT10416-1|ST70408-1|ST702xx-1|ST702xx-2|ST80208|ST97216|ST70104-2|VT10416-2|ST10216-2A|SurfTab",
+ "PyleAudioTablet": "\\b(PTBL10CEU|PTBL10C|PTBL72BC|PTBL72BCEU|PTBL7CEU|PTBL7C|PTBL92BC|PTBL92BCEU|PTBL9CEU|PTBL9CUK|PTBL9C)\\b",
+ "AdvanTablet": "Android.* \\b(E3A|T3X|T5C|T5B|T3E|T3C|T3B|T1J|T1F|T2A|T1H|T1i|E1C|T1-E|T5-A|T4|E1-B|T2Ci|T1-B|T1-D|O1-A|E1-A|T1-A|T3A|T4i)\\b ",
+ "DanyTechTablet": "Genius Tab G3|Genius Tab S2|Genius Tab Q3|Genius Tab G4|Genius Tab Q4|Genius Tab G-II|Genius TAB GII|Genius TAB GIII|Genius Tab S1",
+ "GalapadTablet": "Android.*\\bG1\\b",
+ "MicromaxTablet": "Funbook|Micromax.*\\b(P250|P560|P360|P362|P600|P300|P350|P500|P275)\\b",
+ "KarbonnTablet": "Android.*\\b(A39|A37|A34|ST8|ST10|ST7|Smart Tab3|Smart Tab2)\\b",
+ "AllFineTablet": "Fine7 Genius|Fine7 Shine|Fine7 Air|Fine8 Style|Fine9 More|Fine10 Joy|Fine11 Wide",
+ "PROSCANTablet": "\\b(PEM63|PLT1023G|PLT1041|PLT1044|PLT1044G|PLT1091|PLT4311|PLT4311PL|PLT4315|PLT7030|PLT7033|PLT7033D|PLT7035|PLT7035D|PLT7044K|PLT7045K|PLT7045KB|PLT7071KG|PLT7072|PLT7223G|PLT7225G|PLT7777G|PLT7810K|PLT7849G|PLT7851G|PLT7852G|PLT8015|PLT8031|PLT8034|PLT8036|PLT8080K|PLT8082|PLT8088|PLT8223G|PLT8234G|PLT8235G|PLT8816K|PLT9011|PLT9045K|PLT9233G|PLT9735|PLT9760G|PLT9770G)\\b",
+ "YONESTablet": "BQ1078|BC1003|BC1077|RK9702|BC9730|BC9001|IT9001|BC7008|BC7010|BC708|BC728|BC7012|BC7030|BC7027|BC7026",
+ "ChangJiaTablet": "TPC7102|TPC7103|TPC7105|TPC7106|TPC7107|TPC7201|TPC7203|TPC7205|TPC7210|TPC7708|TPC7709|TPC7712|TPC7110|TPC8101|TPC8103|TPC8105|TPC8106|TPC8203|TPC8205|TPC8503|TPC9106|TPC9701|TPC97101|TPC97103|TPC97105|TPC97106|TPC97111|TPC97113|TPC97203|TPC97603|TPC97809|TPC97205|TPC10101|TPC10103|TPC10106|TPC10111|TPC10203|TPC10205|TPC10503",
+ "GUTablet": "TX-A1301|TX-M9002|Q702|kf026",
+ "PointOfViewTablet": "TAB-P506|TAB-navi-7-3G-M|TAB-P517|TAB-P-527|TAB-P701|TAB-P703|TAB-P721|TAB-P731N|TAB-P741|TAB-P825|TAB-P905|TAB-P925|TAB-PR945|TAB-PL1015|TAB-P1025|TAB-PI1045|TAB-P1325|TAB-PROTAB[0-9]+|TAB-PROTAB25|TAB-PROTAB26|TAB-PROTAB27|TAB-PROTAB26XL|TAB-PROTAB2-IPS9|TAB-PROTAB30-IPS9|TAB-PROTAB25XXL|TAB-PROTAB26-IPS10|TAB-PROTAB30-IPS10",
+ "OvermaxTablet": "OV-(SteelCore|NewBase|Basecore|Baseone|Exellen|Quattor|EduTab|Solution|ACTION|BasicTab|TeddyTab|MagicTab|Stream|TB-08|TB-09)",
+ "HCLTablet": "HCL.*Tablet|Connect-3G-2.0|Connect-2G-2.0|ME Tablet U1|ME Tablet U2|ME Tablet G1|ME Tablet X1|ME Tablet Y2|ME Tablet Sync",
+ "DPSTablet": "DPS Dream 9|DPS Dual 7",
+ "VistureTablet": "V97 HD|i75 3G|Visture V4( HD)?|Visture V5( HD)?|Visture V10",
+ "CrestaTablet": "CTP(-)?810|CTP(-)?818|CTP(-)?828|CTP(-)?838|CTP(-)?888|CTP(-)?978|CTP(-)?980|CTP(-)?987|CTP(-)?988|CTP(-)?989",
+ "MediatekTablet": "\\bMT8125|MT8389|MT8135|MT8377\\b",
+ "ConcordeTablet": "Concorde([ ]+)?Tab|ConCorde ReadMan",
+ "GoCleverTablet": "GOCLEVER TAB|A7GOCLEVER|M1042|M7841|M742|R1042BK|R1041|TAB A975|TAB A7842|TAB A741|TAB A741L|TAB M723G|TAB M721|TAB A1021|TAB I921|TAB R721|TAB I720|TAB T76|TAB R70|TAB R76.2|TAB R106|TAB R83.2|TAB M813G|TAB I721|GCTA722|TAB I70|TAB I71|TAB S73|TAB R73|TAB R74|TAB R93|TAB R75|TAB R76.1|TAB A73|TAB A93|TAB A93.2|TAB T72|TAB R83|TAB R974|TAB R973|TAB A101|TAB A103|TAB A104|TAB A104.2|R105BK|M713G|A972BK|TAB A971|TAB R974.2|TAB R104|TAB R83.3|TAB A1042",
+ "ModecomTablet": "FreeTAB 9000|FreeTAB 7.4|FreeTAB 7004|FreeTAB 7800|FreeTAB 2096|FreeTAB 7.5|FreeTAB 1014|FreeTAB 1001 |FreeTAB 8001|FreeTAB 9706|FreeTAB 9702|FreeTAB 7003|FreeTAB 7002|FreeTAB 1002|FreeTAB 7801|FreeTAB 1331|FreeTAB 1004|FreeTAB 8002|FreeTAB 8014|FreeTAB 9704|FreeTAB 1003",
+ "VoninoTablet": "\\b(Argus[ _]?S|Diamond[ _]?79HD|Emerald[ _]?78E|Luna[ _]?70C|Onyx[ _]?S|Onyx[ _]?Z|Orin[ _]?HD|Orin[ _]?S|Otis[ _]?S|SpeedStar[ _]?S|Magnet[ _]?M9|Primus[ _]?94[ _]?3G|Primus[ _]?94HD|Primus[ _]?QS|Android.*\\bQ8\\b|Sirius[ _]?EVO[ _]?QS|Sirius[ _]?QS|Spirit[ _]?S)\\b",
+ "ECSTablet": "V07OT2|TM105A|S10OT1|TR10CS1",
+ "StorexTablet": "eZee[_']?(Tab|Go)[0-9]+|TabLC7|Looney Tunes Tab",
+ "VodafoneTablet": "SmartTab([ ]+)?[0-9]+|SmartTabII10|SmartTabII7",
+ "EssentielBTablet": "Smart[ ']?TAB[ ]+?[0-9]+|Family[ ']?TAB2",
+ "RossMoorTablet": "RM-790|RM-997|RMD-878G|RMD-974R|RMT-705A|RMT-701|RME-601|RMT-501|RMT-711",
+ "iMobileTablet": "i-mobile i-note",
+ "TolinoTablet": "tolino tab [0-9.]+|tolino shine",
+ "AudioSonicTablet": "\\bC-22Q|T7-QC|T-17B|T-17P\\b",
+ "AMPETablet": "Android.* A78 ",
+ "SkkTablet": "Android.* (SKYPAD|PHOENIX|CYCLOPS)",
+ "TecnoTablet": "TECNO P9",
+ "JXDTablet": "Android.*\\b(F3000|A3300|JXD5000|JXD3000|JXD2000|JXD300B|JXD300|S5800|S7800|S602b|S5110b|S7300|S5300|S602|S603|S5100|S5110|S601|S7100a|P3000F|P3000s|P101|P200s|P1000m|P200m|P9100|P1000s|S6600b|S908|P1000|P300|S18|S6600|S9100)\\b",
+ "iJoyTablet": "Tablet (Spirit 7|Essentia|Galatea|Fusion|Onix 7|Landa|Titan|Scooby|Deox|Stella|Themis|Argon|Unique 7|Sygnus|Hexen|Finity 7|Cream|Cream X2|Jade|Neon 7|Neron 7|Kandy|Scape|Saphyr 7|Rebel|Biox|Rebel|Rebel 8GB|Myst|Draco 7|Myst|Tab7-004|Myst|Tadeo Jones|Tablet Boing|Arrow|Draco Dual Cam|Aurix|Mint|Amity|Revolution|Finity 9|Neon 9|T9w|Amity 4GB Dual Cam|Stone 4GB|Stone 8GB|Andromeda|Silken|X2|Andromeda II|Halley|Flame|Saphyr 9,7|Touch 8|Planet|Triton|Unique 10|Hexen 10|Memphis 4GB|Memphis 8GB|Onix 10)",
+ "FX2Tablet": "FX2 PAD7|FX2 PAD10",
+ "XoroTablet": "KidsPAD 701|PAD[ ]?712|PAD[ ]?714|PAD[ ]?716|PAD[ ]?717|PAD[ ]?718|PAD[ ]?720|PAD[ ]?721|PAD[ ]?722|PAD[ ]?790|PAD[ ]?792|PAD[ ]?900|PAD[ ]?9715D|PAD[ ]?9716DR|PAD[ ]?9718DR|PAD[ ]?9719QR|PAD[ ]?9720QR|TelePAD1030|Telepad1032|TelePAD730|TelePAD731|TelePAD732|TelePAD735Q|TelePAD830|TelePAD9730|TelePAD795|MegaPAD 1331|MegaPAD 1851|MegaPAD 2151",
+ "ViewsonicTablet": "ViewPad 10pi|ViewPad 10e|ViewPad 10s|ViewPad E72|ViewPad7|ViewPad E100|ViewPad 7e|ViewSonic VB733|VB100a",
+ "OdysTablet": "LOOX|XENO10|ODYS[ -](Space|EVO|Xpress|NOON)|\\bXELIO\\b|Xelio10Pro|XELIO7PHONETAB|XELIO10EXTREME|XELIOPT2|NEO_QUAD10",
+ "CaptivaTablet": "CAPTIVA PAD",
+ "IconbitTablet": "NetTAB|NT-3702|NT-3702S|NT-3702S|NT-3603P|NT-3603P|NT-0704S|NT-0704S|NT-3805C|NT-3805C|NT-0806C|NT-0806C|NT-0909T|NT-0909T|NT-0907S|NT-0907S|NT-0902S|NT-0902S",
+ "TeclastTablet": "T98 4G|\\bP80\\b|\\bX90HD\\b|X98 Air|X98 Air 3G|\\bX89\\b|P80 3G|\\bX80h\\b|P98 Air|\\bX89HD\\b|P98 3G|\\bP90HD\\b|P89 3G|X98 3G|\\bP70h\\b|P79HD 3G|G18d 3G|\\bP79HD\\b|\\bP89s\\b|\\bA88\\b|\\bP10HD\\b|\\bP19HD\\b|G18 3G|\\bP78HD\\b|\\bA78\\b|\\bP75\\b|G17s 3G|G17h 3G|\\bP85t\\b|\\bP90\\b|\\bP11\\b|\\bP98t\\b|\\bP98HD\\b|\\bG18d\\b|\\bP85s\\b|\\bP11HD\\b|\\bP88s\\b|\\bA80HD\\b|\\bA80se\\b|\\bA10h\\b|\\bP89\\b|\\bP78s\\b|\\bG18\\b|\\bP85\\b|\\bA70h\\b|\\bA70\\b|\\bG17\\b|\\bP18\\b|\\bA80s\\b|\\bA11s\\b|\\bP88HD\\b|\\bA80h\\b|\\bP76s\\b|\\bP76h\\b|\\bP98\\b|\\bA10HD\\b|\\bP78\\b|\\bP88\\b|\\bA11\\b|\\bA10t\\b|\\bP76a\\b|\\bP76t\\b|\\bP76e\\b|\\bP85HD\\b|\\bP85a\\b|\\bP86\\b|\\bP75HD\\b|\\bP76v\\b|\\bA12\\b|\\bP75a\\b|\\bA15\\b|\\bP76Ti\\b|\\bP81HD\\b|\\bA10\\b|\\bT760VE\\b|\\bT720HD\\b|\\bP76\\b|\\bP73\\b|\\bP71\\b|\\bP72\\b|\\bT720SE\\b|\\bC520Ti\\b|\\bT760\\b|\\bT720VE\\b|T720-3GE|T720-WiFi",
+ "JaytechTablet": "TPC-PA762",
+ "BlaupunktTablet": "Endeavour 800NG|Endeavour 1010",
+ "DigmaTablet": "\\b(iDx10|iDx9|iDx8|iDx7|iDxD7|iDxD8|iDsQ8|iDsQ7|iDsQ8|iDsD10|iDnD7|3TS804H|iDsQ11|iDj7|iDs10)\\b",
+ "EvolioTablet": "ARIA_Mini_wifi|Aria[ _]Mini|Evolio X10|Evolio X7|Evolio X8|\\bEvotab\\b|\\bNeura\\b",
+ "LavaTablet": "QPAD E704|\\bIvoryS\\b|E-TAB IVORY",
+ "CelkonTablet": "CT695|CT888|CT[\\s]?910|CT7 Tab|CT9 Tab|CT3 Tab|CT2 Tab|CT1 Tab|C820|C720|\\bCT-1\\b",
+ "MiTablet": "\\bMI PAD\\b|\\bHM NOTE 1W\\b",
+ "NibiruTablet": "Nibiru M1|Nibiru Jupiter One",
+ "NexoTablet": "NEXO NOVA|NEXO 10|NEXO AVIO|NEXO FREE|NEXO GO|NEXO EVO|NEXO 3G|NEXO SMART|NEXO KIDDO|NEXO MOBI",
+ "UbislateTablet": "UbiSlate[\\s]?7C",
+ "PocketBookTablet": "Pocketbook",
+ "Hudl": "Hudl HT7S3",
+ "TelstraTablet": "T-Hub2",
+ "GenericTablet": "Android.*\\b97D\\b|Tablet(?!.*PC)|BNTV250A|MID-WCDMA|LogicPD Zoom2|\\bA7EB\\b|CatNova8|A1_07|CT704|CT1002|\\bM721\\b|rk30sdk|\\bEVOTAB\\b|M758A|ET904|ALUMIUM10|Smartfren Tab|Endeavour 1010|Tablet-PC-4|Tagi Tab|\\bM6pro\\b|CT1020W|arc 10HD|\\bJolla\\b"
+ },
+ "oss": {
+ "AndroidOS": "Android",
+ "BlackBerryOS": "blackberry|\\bBB10\\b|rim tablet os",
+ "PalmOS": "PalmOS|avantgo|blazer|elaine|hiptop|palm|plucker|xiino",
+ "SymbianOS": "Symbian|SymbOS|Series60|Series40|SYB-[0-9]+|\\bS60\\b",
+ "WindowsMobileOS": "Windows CE.*(PPC|Smartphone|Mobile|[0-9]{3}x[0-9]{3})|Window Mobile|Windows Phone [0-9.]+|WCE;",
+ "WindowsPhoneOS": "Windows Phone 8.0|Windows Phone OS|XBLWP7|ZuneWP7|Windows NT 6.[23]; ARM;",
+ "iOS": "\\biPhone.*Mobile|\\biPod|\\biPad",
+ "MeeGoOS": "MeeGo",
+ "MaemoOS": "Maemo",
+ "JavaOS": "J2ME\/|\\bMIDP\\b|\\bCLDC\\b",
+ "webOS": "webOS|hpwOS",
+ "badaOS": "\\bBada\\b",
+ "BREWOS": "BREW"
+ },
+ "uas": {
+ "Chrome": "\\bCrMo\\b|CriOS|Android.*Chrome\/[.0-9]* (Mobile)?",
+ "Dolfin": "\\bDolfin\\b",
+ "Opera": "Opera.*Mini|Opera.*Mobi|Android.*Opera|Mobile.*OPR\/[0-9.]+|Coast\/[0-9.]+",
+ "Skyfire": "Skyfire",
+ "IE": "IEMobile|MSIEMobile",
+ "Firefox": "fennec|firefox.*maemo|(Mobile|Tablet).*Firefox|Firefox.*Mobile",
+ "Bolt": "bolt",
+ "TeaShark": "teashark",
+ "Blazer": "Blazer",
+ "Safari": "Version.*Mobile.*Safari|Safari.*Mobile|MobileSafari",
+ "Tizen": "Tizen",
+ "UCBrowser": "UC.*Browser|UCWEB",
+ "baiduboxapp": "baiduboxapp",
+ "baidubrowser": "baidubrowser",
+ "DiigoBrowser": "DiigoBrowser",
+ "Puffin": "Puffin",
+ "Mercury": "\\bMercury\\b",
+ "ObigoBrowser": "Obigo",
+ "NetFront": "NF-Browser",
+ "GenericBrowser": "NokiaBrowser|OviBrowser|OneBrowser|TwonkyBeamBrowser|SEMC.*Browser|FlyFlow|Minimo|NetFront|Novarra-Vision|MQQBrowser|MicroMessenger"
+ },
+ "props": {
+ "Mobile": "Mobile\/[VER]",
+ "Build": "Build\/[VER]",
+ "Version": "Version\/[VER]",
+ "VendorID": "VendorID\/[VER]",
+ "iPad": "iPad.*CPU[a-z ]+[VER]",
+ "iPhone": "iPhone.*CPU[a-z ]+[VER]",
+ "iPod": "iPod.*CPU[a-z ]+[VER]",
+ "Kindle": "Kindle\/[VER]",
+ "Chrome": [
+ "Chrome\/[VER]",
+ "CriOS\/[VER]",
+ "CrMo\/[VER]"
+ ],
+ "Coast": [
+ "Coast\/[VER]"
+ ],
+ "Dolfin": "Dolfin\/[VER]",
+ "Firefox": "Firefox\/[VER]",
+ "Fennec": "Fennec\/[VER]",
+ "IE": [
+ "IEMobile\/[VER];",
+ "IEMobile [VER]",
+ "MSIE [VER];"
+ ],
+ "NetFront": "NetFront\/[VER]",
+ "NokiaBrowser": "NokiaBrowser\/[VER]",
+ "Opera": [
+ " OPR\/[VER]",
+ "Opera Mini\/[VER]",
+ "Version\/[VER]"
+ ],
+ "Opera Mini": "Opera Mini\/[VER]",
+ "Opera Mobi": "Version\/[VER]",
+ "UC Browser": "UC Browser[VER]",
+ "MQQBrowser": "MQQBrowser\/[VER]",
+ "MicroMessenger": "MicroMessenger\/[VER]",
+ "baiduboxapp": "baiduboxapp\/[VER]",
+ "baidubrowser": "baidubrowser\/[VER]",
+ "Iron": "Iron\/[VER]",
+ "Safari": [
+ "Version\/[VER]",
+ "Safari\/[VER]"
+ ],
+ "Skyfire": "Skyfire\/[VER]",
+ "Tizen": "Tizen\/[VER]",
+ "Webkit": "webkit[ \/][VER]",
+ "Gecko": "Gecko\/[VER]",
+ "Trident": "Trident\/[VER]",
+ "Presto": "Presto\/[VER]",
+ "iOS": " \\bOS\\b [VER] ",
+ "Android": "Android [VER]",
+ "BlackBerry": [
+ "BlackBerry[\\w]+\/[VER]",
+ "BlackBerry.*Version\/[VER]",
+ "Version\/[VER]"
+ ],
+ "BREW": "BREW [VER]",
+ "Java": "Java\/[VER]",
+ "Windows Phone OS": [
+ "Windows Phone OS [VER]",
+ "Windows Phone [VER]"
+ ],
+ "Windows Phone": "Windows Phone [VER]",
+ "Windows CE": "Windows CE\/[VER]",
+ "Windows NT": "Windows NT [VER]",
+ "Symbian": [
+ "SymbianOS\/[VER]",
+ "Symbian\/[VER]"
+ ],
+ "webOS": [
+ "webOS\/[VER]",
+ "hpwOS\/[VER];"
+ ]
+ },
+ "utils": {
+ "DesktopMode": "WPDesktop",
+ "TV": "SonyDTV|HbbTV",
+ "WebKit": "(webkit)[ \/]([\\w.]+)",
+ "Bot": "Googlebot|YandexBot|bingbot|ia_archiver|AhrefsBot|Ezooms|GSLFbot|WBSearchBot|Twitterbot|TweetmemeBot|Twikle|PaperLiBot|Wotbox|UnwindFetchor|facebookexternalhit",
+ "MobileBot": "Googlebot-Mobile|YahooSeeker\/M1A1-R2D2",
+ "Console": "\\b(Nintendo|Nintendo WiiU|Nintendo 3DS|PLAYSTATION|Xbox)\\b",
+ "Watch": "SM-V700"
+ }
+};
+
+ // following patterns come from http://detectmobilebrowsers.com/
+ var detectMobileBrowsers = {
+ fullPattern: /(android|bb\d+|meego).+mobile|avantgo|bada\/|blackberry|blazer|compal|elaine|fennec|hiptop|iemobile|ip(hone|od)|iris|kindle|lge |maemo|midp|mmp|mobile.+firefox|netfront|opera m(ob|in)i|palm( os)?|phone|p(ixi|re)\/|plucker|pocket|psp|series(4|6)0|symbian|treo|up\.(browser|link)|vodafone|wap|windows (ce|phone)|xda|xiino/i,
+ shortPattern: /1207|6310|6590|3gso|4thp|50[1-6]i|770s|802s|a wa|abac|ac(er|oo|s\-)|ai(ko|rn)|al(av|ca|co)|amoi|an(ex|ny|yw)|aptu|ar(ch|go)|as(te|us)|attw|au(di|\-m|r |s )|avan|be(ck|ll|nq)|bi(lb|rd)|bl(ac|az)|br(e|v)w|bumb|bw\-(n|u)|c55\/|capi|ccwa|cdm\-|cell|chtm|cldc|cmd\-|co(mp|nd)|craw|da(it|ll|ng)|dbte|dc\-s|devi|dica|dmob|do(c|p)o|ds(12|\-d)|el(49|ai)|em(l2|ul)|er(ic|k0)|esl8|ez([4-7]0|os|wa|ze)|fetc|fly(\-|_)|g1 u|g560|gene|gf\-5|g\-mo|go(\.w|od)|gr(ad|un)|haie|hcit|hd\-(m|p|t)|hei\-|hi(pt|ta)|hp( i|ip)|hs\-c|ht(c(\-| |_|a|g|p|s|t)|tp)|hu(aw|tc)|i\-(20|go|ma)|i230|iac( |\-|\/)|ibro|idea|ig01|ikom|im1k|inno|ipaq|iris|ja(t|v)a|jbro|jemu|jigs|kddi|keji|kgt( |\/)|klon|kpt |kwc\-|kyo(c|k)|le(no|xi)|lg( g|\/(k|l|u)|50|54|\-[a-w])|libw|lynx|m1\-w|m3ga|m50\/|ma(te|ui|xo)|mc(01|21|ca)|m\-cr|me(rc|ri)|mi(o8|oa|ts)|mmef|mo(01|02|bi|de|do|t(\-| |o|v)|zz)|mt(50|p1|v )|mwbp|mywa|n10[0-2]|n20[2-3]|n30(0|2)|n50(0|2|5)|n7(0(0|1)|10)|ne((c|m)\-|on|tf|wf|wg|wt)|nok(6|i)|nzph|o2im|op(ti|wv)|oran|owg1|p800|pan(a|d|t)|pdxg|pg(13|\-([1-8]|c))|phil|pire|pl(ay|uc)|pn\-2|po(ck|rt|se)|prox|psio|pt\-g|qa\-a|qc(07|12|21|32|60|\-[2-7]|i\-)|qtek|r380|r600|raks|rim9|ro(ve|zo)|s55\/|sa(ge|ma|mm|ms|ny|va)|sc(01|h\-|oo|p\-)|sdk\/|se(c(\-|0|1)|47|mc|nd|ri)|sgh\-|shar|sie(\-|m)|sk\-0|sl(45|id)|sm(al|ar|b3|it|t5)|so(ft|ny)|sp(01|h\-|v\-|v )|sy(01|mb)|t2(18|50)|t6(00|10|18)|ta(gt|lk)|tcl\-|tdg\-|tel(i|m)|tim\-|t\-mo|to(pl|sh)|ts(70|m\-|m3|m5)|tx\-9|up(\.b|g1|si)|utst|v400|v750|veri|vi(rg|te)|vk(40|5[0-3]|\-v)|vm40|voda|vulc|vx(52|53|60|61|70|80|81|83|85|98)|w3c(\-| )|webc|whit|wi(g |nc|nw)|wmlb|wonu|x700|yas\-|your|zeto|zte\-/i
+ };
+
+ var hasOwnProp = Object.prototype.hasOwnProperty,
+ isArray,
+ FALLBACK_PHONE = 'UnknownPhone',
+ FALLBACK_TABLET = 'UnknownTablet',
+ FALLBACK_MOBILE = 'UnknownMobile';
+
+ isArray = ('isArray' in Array) ?
+ Array.isArray : function (value) { return Object.prototype.toString.call(value) === '[object Array]'; };
+
+ (function init() {
+ var key, values, value, i, len, verPos;
+ for (key in mobileDetectRules.props) {
+ if (hasOwnProp.call(mobileDetectRules.props, key)) {
+ values = mobileDetectRules.props[key];
+ if (!isArray(values)) {
+ values = [values];
+ }
+ len = values.length;
+ for (i = 0; i < len; ++i) {
+ value = values[i];
+ verPos = value.indexOf('[VER]');
+ if (verPos >= 0) {
+ value = value.substring(0, verPos) + '([\\w._\\+]+)' + value.substring(verPos + 5);
+ }
+ values[i] = new RegExp(value, 'i');
+ }
+ mobileDetectRules.props[key] = values;
+ }
+ }
+ convertPropsToRegExp(mobileDetectRules.oss);
+ convertPropsToRegExp(mobileDetectRules.phones);
+ convertPropsToRegExp(mobileDetectRules.tablets);
+ convertPropsToRegExp(mobileDetectRules.uas);
+ convertPropsToRegExp(mobileDetectRules.utils);
+
+ // copy some patterns to oss0 which are tested first (see issue#15)
+ mobileDetectRules.oss0 = {
+ WindowsPhoneOS: mobileDetectRules.oss.WindowsPhoneOS,
+ WindowsMobileOS: mobileDetectRules.oss.WindowsMobileOS
+ };
+ }());
+
+ function convertPropsToRegExp(object) {
+ for (var key in object) {
+ if (hasOwnProp.call(object, key)) {
+ object[key] = new RegExp(object[key], 'i');
+ }
+ }
+ }
+
+ /**
+ * Test userAgent string against a set of rules and find the matched key.
+ * @param {Object} rules (key is String, value is RegExp)
+ * @param {String} userAgent the navigator.userAgent (or HTTP-Header 'User-Agent').
+ * @returns {String|null} the matched key if found, otherwise <tt>null</tt>
+ * @private
+ */
+ function findMatch(rules, userAgent) {
+ for (var key in rules) {
+ if (hasOwnProp.call(rules, key)) {
+ if (rules[key].test(userAgent)) {
+ return key;
+ }
+ }
+ }
+ return null;
+ }
+
+ /**
+ * Check the version of the given property in the User-Agent.
+ *
+ * @param {String} propertyName
+ * @param {String} userAgent
+ * @return {String} version or <tt>null</tt> if version not found
+ * @private
+ */
+ function getVersionStr(propertyName, userAgent) {
+ var props = mobileDetectRules.props, patterns, i, len, match;
+ if (hasOwnProp.call(props, propertyName)) {
+ patterns = props[propertyName];
+ len = patterns.length;
+ for (i = 0; i < len; ++i) {
+ match = patterns[i].exec(userAgent);
+ if (match !== null) {
+ return match[1];
+ }
+ }
+ }
+ return null;
+ }
+
+ /**
+ * Check the version of the given property in the User-Agent.
+ * Will return a float number. (eg. 2_0 will return 2.0, 4.3.1 will return 4.31)
+ *
+ * @param {String} propertyName
+ * @param {String} userAgent
+ * @return {Number} version or <tt>NaN</tt> if version not found
+ * @private
+ */
+ function getVersion(propertyName, userAgent) {
+ var version = getVersionStr(propertyName, userAgent);
+ return version ? prepareVersionNo(version) : NaN;
+ }
+
+ /**
+ * Prepare the version number.
+ *
+ * @param {String} version
+ * @return {Number} the version number as a floating number
+ * @private
+ */
+ function prepareVersionNo(version) {
+ var numbers;
+
+ numbers = version.split(/[a-z._ \/\-]/i);
+ if (numbers.length === 1) {
+ version = numbers[0];
+ }
+ if (numbers.length > 1) {
+ version = numbers[0] + '.';
+ numbers.shift();
+ version += numbers.join('');
+ }
+ return Number(version);
+ }
+
+ function equalIC(a, b) {
+ return a != null && b != null && a.toLowerCase() === b.toLowerCase();
+ }
+
+ function isMobileFallback(userAgent) {
+ return detectMobileBrowsers.fullPattern.test(userAgent) ||
+ detectMobileBrowsers.shortPattern.test(userAgent.substr(0,4));
+ }
+
+ function prepareDetectionCache(cache, userAgent, maxPhoneWidth) {
+ if (cache.mobile !== undefined) {
+ return;
+ }
+ var phone, tablet, phoneSized;
+
+ // first check for stronger tablet rules, then phone (see issue#5)
+ tablet = findMatch(mobileDetectRules.tablets, userAgent);
+ if (tablet) {
+ cache.mobile = cache.tablet = tablet;
+ cache.phone = null;
+ return; // unambiguously identified as tablet
+ }
+
+ phone = findMatch(mobileDetectRules.phones, userAgent);
+ if (phone) {
+ cache.mobile = cache.phone = phone;
+ cache.tablet = null;
+ return; // unambiguously identified as phone
+ }
+
+ // our rules haven't found a match -> try more general fallback rules
+ if (isMobileFallback(userAgent)) {
+ phoneSized = MobileDetect.isPhoneSized(maxPhoneWidth);
+ if (phoneSized === undefined) {
+ cache.mobile = cache.tablet = cache.phone = FALLBACK_MOBILE;
+ } else if (phoneSized) {
+ cache.mobile = cache.phone = FALLBACK_PHONE;
+ cache.tablet = null;
+ } else {
+ cache.mobile = cache.tablet = FALLBACK_TABLET;
+ cache.phone = null;
+ }
+ } else {
+ // not mobile at all!
+ cache.mobile = cache.tablet = cache.phone = null;
+ }
+ }
+
+ // t is a reference to a MobileDetect instance
+ function mobileGrade(t) {
+ // impl note:
+ // To keep in sync w/ Mobile_Detect.php easily, the following code is tightly aligned to the PHP version.
+ // When changes are made in Mobile_Detect.php, copy this method and replace:
+ // $this-> / t.
+ // self::MOBILE_GRADE_(.) / '$1'
+ // , self::VERSION_TYPE_FLOAT / (nothing)
+ // isIOS() / os('iOS')
+ // [reg] / (nothing) <-- jsdelivr complaining about unescaped unicode character U+00AE
+ var $isMobile = t.mobile() !== null;
+
+ if (
+ // Apple iOS 3.2-5.1 - Tested on the original iPad (4.3 / 5.0), iPad 2 (4.3), iPad 3 (5.1), original iPhone (3.1), iPhone 3 (3.2), 3GS (4.3), 4 (4.3 / 5.0), and 4S (5.1)
+ t.os('iOS') && t.version('iPad')>=4.3 ||
+ t.os('iOS') && t.version('iPhone')>=3.1 ||
+ t.os('iOS') && t.version('iPod')>=3.1 ||
+
+ // Android 2.1-2.3 - Tested on the HTC Incredible (2.2), original Droid (2.2), HTC Aria (2.1), Google Nexus S (2.3). Functional on 1.5 & 1.6 but performance may be sluggish, tested on Google G1 (1.5)
+ // Android 3.1 (Honeycomb) - Tested on the Samsung Galaxy Tab 10.1 and Motorola XOOM
+ // Android 4.0 (ICS) - Tested on a Galaxy Nexus. Note: transition performance can be poor on upgraded devices
+ // Android 4.1 (Jelly Bean) - Tested on a Galaxy Nexus and Galaxy 7
+ ( t.version('Android')>2.1 && t.is('Webkit') ) ||
+
+ // Windows Phone 7-7.5 - Tested on the HTC Surround (7.0) HTC Trophy (7.5), LG-E900 (7.5), Nokia Lumia 800
+ t.version('Windows Phone OS')>=7.0 ||
+
+ // Blackberry 7 - Tested on BlackBerry Torch 9810
+ // Blackberry 6.0 - Tested on the Torch 9800 and Style 9670
+ t.is('BlackBerry') && t.version('BlackBerry')>=6.0 ||
+ // Blackberry Playbook (1.0-2.0) - Tested on PlayBook
+ t.match('Playbook.*Tablet') ||
+
+ // Palm WebOS (1.4-2.0) - Tested on the Palm Pixi (1.4), Pre (1.4), Pre 2 (2.0)
+ ( t.version('webOS')>=1.4 && t.match('Palm|Pre|Pixi') ) ||
+ // Palm WebOS 3.0 - Tested on HP TouchPad
+ t.match('hp.*TouchPad') ||
+
+ // Firefox Mobile (12 Beta) - Tested on Android 2.3 device
+ ( t.is('Firefox') && t.version('Firefox')>=12 ) ||
+
+ // Chrome for Android - Tested on Android 4.0, 4.1 device
+ ( t.is('Chrome') && t.is('AndroidOS') && t.version('Android')>=4.0 ) ||
+
+ // Skyfire 4.1 - Tested on Android 2.3 device
+ ( t.is('Skyfire') && t.version('Skyfire')>=4.1 && t.is('AndroidOS') && t.version('Android')>=2.3 ) ||
+
+ // Opera Mobile 11.5-12: Tested on Android 2.3
+ ( t.is('Opera') && t.version('Opera Mobi')>11 && t.is('AndroidOS') ) ||
+
+ // Meego 1.2 - Tested on Nokia 950 and N9
+ t.is('MeeGoOS') ||
+
+ // Tizen (pre-release) - Tested on early hardware
+ t.is('Tizen') ||
+
+ // Samsung Bada 2.0 - Tested on a Samsung Wave 3, Dolphin browser
+ // @todo: more tests here!
+ t.is('Dolfin') && t.version('Bada')>=2.0 ||
+
+ // UC Browser - Tested on Android 2.3 device
+ ( (t.is('UC Browser') || t.is('Dolfin')) && t.version('Android')>=2.3 ) ||
+
+ // Kindle 3 and Fire - Tested on the built-in WebKit browser for each
+ ( t.match('Kindle Fire') ||
+ t.is('Kindle') && t.version('Kindle')>=3.0 ) ||
+
+ // Nook Color 1.4.1 - Tested on original Nook Color, not Nook Tablet
+ t.is('AndroidOS') && t.is('NookTablet') ||
+
+ // Chrome Desktop 11-21 - Tested on OS X 10.7 and Windows 7
+ t.version('Chrome')>=11 && !$isMobile ||
+
+ // Safari Desktop 4-5 - Tested on OS X 10.7 and Windows 7
+ t.version('Safari')>=5.0 && !$isMobile ||
+
+ // Firefox Desktop 4-13 - Tested on OS X 10.7 and Windows 7
+ t.version('Firefox')>=4.0 && !$isMobile ||
+
+ // Internet Explorer 7-9 - Tested on Windows XP, Vista and 7
+ t.version('MSIE')>=7.0 && !$isMobile ||
+
+ // Opera Desktop 10-12 - Tested on OS X 10.7 and Windows 7
+ // @reference: http://my.opera.com/community/openweb/idopera/
+ t.version('Opera')>=10 && !$isMobile
+
+ ){
+ return 'A';
+ }
+
+ if (
+ t.os('iOS') && t.version('iPad')<4.3 ||
+ t.os('iOS') && t.version('iPhone')<3.1 ||
+ t.os('iOS') && t.version('iPod')<3.1 ||
+
+ // Blackberry 5.0: Tested on the Storm 2 9550, Bold 9770
+ t.is('Blackberry') && t.version('BlackBerry')>=5 && t.version('BlackBerry')<6 ||
+
+ //Opera Mini (5.0-6.5) - Tested on iOS 3.2/4.3 and Android 2.3
+ ( t.version('Opera Mini')>=5.0 && t.version('Opera Mini')<=6.5 &&
+ (t.version('Android')>=2.3 || t.is('iOS')) ) ||
+
+ // Nokia Symbian^3 - Tested on Nokia N8 (Symbian^3), C7 (Symbian^3), also works on N97 (Symbian^1)
+ t.match('NokiaN8|NokiaC7|N97.*Series60|Symbian/3') ||
+
+ // @todo: report this (tested on Nokia N71)
+ t.version('Opera Mobi')>=11 && t.is('SymbianOS')
+ ){
+ return 'B';
+ }
+
+ if (
+ // Blackberry 4.x - Tested on the Curve 8330
+ t.version('BlackBerry')<5.0 ||
+ // Windows Mobile - Tested on the HTC Leo (WinMo 5.2)
+ t.match('MSIEMobile|Windows CE.*Mobile') || t.version('Windows Mobile')<=5.2
+
+ ){
+ return 'C';
+ }
+
+ //All older smartphone platforms and featurephones - Any device that doesn't support media queries
+ //will receive the basic, C grade experience.
+ return 'C';
+ }
+
+ /**
+ * Constructor for MobileDetect object.
+ * <br>
+ * Such an object will keep a reference to the given user-agent string and cache most of the detect queries.<br>
+ * <div style="background-color: #d9edf7; border: 1px solid #bce8f1; color: #3a87ad; padding: 14px; border-radius: 2px; margin-top: 20px">
+ * <strong>Find information how to download and install:</strong>
+ * <a href="https://github.com/hgoebl/mobile-detect.js/">github.com/hgoebl/mobile-detect.js/</a>
+ * </div>
+ *
+ * @example <pre>
+ * var md = new MobileDetect(window.navigator.userAgent);
+ * if (md.mobile()) {
+ * location.href = (md.mobileGrade() === 'A') ? '/mobile/' : '/lynx/';
+ * }
+ * </pre>
+ *
+ * @param {string} userAgent typically taken from window.navigator.userAgent or http_header['User-Agent']
+ * @param {number} [maxPhoneWidth=650] <strong>only for browsers</strong> specify a value for the maximum
+ * width (in logical "CSS" pixels) until a device detected as mobile will be handled as phone.
+ * This is only used in cases where the device cannot be classified as phone or tablet.<br>
+ * See <a href="http://www.html5rocks.com/en/mobile/cross-device/">A non-responsive approach to
+ * building cross-device webapps</a>.<br>
+ * If you provide a value < 0, then this "fuzzy" check is disabled.
+ * @constructor
+ * @global
+ */
+ function MobileDetect(userAgent, maxPhoneWidth) {
+ this.ua = userAgent || '';
+ this._cache = {};
+ this.maxPhoneWidth = maxPhoneWidth || 650;
+ }
+
+ MobileDetect.prototype = {
+ constructor: MobileDetect,
+
+ /**
+ * Returns the detected phone or tablet type or <tt>null</tt> if it is not a mobile device.
+ * <br>
+ * For a list of possible return values see {@link MobileDetect#phone} and {@link MobileDetect#tablet}.<br>
+ * <br>
+ * If the device is not detected by the regular expressions from Mobile-Detect, a test is made against
+ * the patterns of <a href="http://detectmobilebrowsers.com/">detectmobilebrowsers.com</a>. If this test
+ * is positive, a value of <code>UnknownPhone</code>, <code>UnknownTablet</code> or
+ * <code>UnknownMobile</code> is returned.<br>
+ * When used in browser, the decision whether phone or tablet is made based on <code>screen.width</code>.<br>
+ * When used server-side (node.js), there is no way to tell the difference between <code>UnknownPhone</code>
+ * and <code>UnknownTablet</code>, so you will only get <code>UnknownMobile</code>.<br>
+ * <br>
+ * In most cases you will use the return value just as a boolean.
+ *
+ * @returns {String} the key for the phone family or tablet family, e.g. "Nexus".
+ * @function MobileDetect#mobile
+ */
+ mobile: function () {
+ prepareDetectionCache(this._cache, this.ua, this.maxPhoneWidth);
+ return this._cache.mobile;
+ },
+
+ /**
+ * Returns the detected phone type/family string or <tt>null</tt>.
+ * <br>
+ * The returned tablet (family or producer) is one of following keys:<br>
+ * <br><tt>iPhone, BlackBerry, HTC, Nexus, Dell, Motorola, Samsung, LG, Sony, Asus,
+ * Micromax, Palm, Vertu, Pantech, Fly, iMobile, SimValley, Wolfgang, Alcatel,
+ * Nintendo, Amoi, INQ, GenericPhone</tt><br>
+ * <br>
+ * If the device is not detected by the regular expressions from Mobile-Detect, a test is made against
+ * the patterns of <a href="http://detectmobilebrowsers.com/">detectmobilebrowsers.com</a>. If this test
+ * is positive, a value of <code>UnknownPhone</code> or <code>UnknownMobile</code> is returned.<br>
+ * When used in browser, the decision whether phone or tablet is made based on <code>screen.width</code>.<br>
+ * When used server-side (node.js), there is no way to tell the difference between <code>UnknownPhone</code>
+ * and <code>UnknownMobile</code>, so you will only get <code>UnknownMobile</code>.<br>
+ * <br>
+ * In most cases you will use the return value just as a boolean.
+ *
+ * @returns {String} the key of the phone family or producer, e.g. "iPhone"
+ * @function MobileDetect#phone
+ */
+ phone: function () {
+ prepareDetectionCache(this._cache, this.ua, this.maxPhoneWidth);
+ return this._cache.phone;
+ },
+
+ /**
+ * Returns the detected tablet type/family string or <tt>null</tt>.
+ * <br>
+ * The returned tablet (family or producer) is one of following keys:<br>
+ * <br><tt>iPad, NexusTablet, SamsungTablet, Kindle, SurfaceTablet, HPTablet, AsusTablet,
+ * BlackBerryTablet, HTCtablet, MotorolaTablet, NookTablet, AcerTablet,
+ * ToshibaTablet, LGTablet, FujitsuTablet, PrestigioTablet, LenovoTablet,
+ * DellTablet, YarvikTablet, MedionTablet, ArnovaTablet, IntensoTablet, IRUTablet,
+ * MegafonTablet, EbodaTablet, AllViewTablet, ArchosTablet, AinolTablet,
+ * SonyTablet, PhilipsTablet, CubeTablet, CobyTablet, MIDTablet, MSITablet,
+ * SMiTTablet, RockChipTablet, FlyTablet, bqTablet, HuaweiTablet, NecTablet,
+ * PantechTablet, BronchoTablet, VersusTablet, ZyncTablet, PositivoTablet,
+ * NabiTablet, KoboTablet, DanewTablet, TexetTablet, PlaystationTablet,
+ * TrekstorTablet, PyleAudioTablet, AdvanTablet, DanyTechTablet, GalapadTablet,
+ * MicromaxTablet, KarbonnTablet, AllFineTablet, PROSCANTablet, YONESTablet,
+ * ChangJiaTablet, GUTablet, PointOfViewTablet, OvermaxTablet, HCLTablet,
+ * DPSTablet, VistureTablet, CrestaTablet, MediatekTablet, ConcordeTablet,
+ * GoCleverTablet, ModecomTablet, VoninoTablet, ECSTablet, StorexTablet,
+ * VodafoneTablet, EssentielBTablet, RossMoorTablet, iMobileTablet, TolinoTablet,
+ * AudioSonicTablet, AMPETablet, SkkTablet, TecnoTablet, JXDTablet, iJoyTablet,
+ * FX2Tablet, XoroTablet, ViewsonicTablet, OdysTablet, CaptivaTablet,
+ * IconbitTablet, TeclastTablet, JaytechTablet, BlaupunktTablet, DigmaTablet,
+ * EvolioTablet, LavaTablet, CelkonTablet, MiTablet, NibiruTablet, NexoTablet,
+ * UbislateTablet, PocketBookTablet, Hudl, TelstraTablet, GenericTablet</tt><br>
+ * <br>
+ * If the device is not detected by the regular expressions from Mobile-Detect, a test is made against
+ * the patterns of <a href="http://detectmobilebrowsers.com/">detectmobilebrowsers.com</a>. If this test
+ * is positive, a value of <code>UnknownTablet</code> or <code>UnknownMobile</code> is returned.<br>
+ * When used in browser, the decision whether phone or tablet is made based on <code>screen.width</code>.<br>
+ * When used server-side (node.js), there is no way to tell the difference between <code>UnknownTablet</code>
+ * and <code>UnknownMobile</code>, so you will only get <code>UnknownMobile</code>.<br>
+ * <br>
+ * In most cases you will use the return value just as a boolean.
+ *
+ * @returns {String} the key of the tablet family or producer, e.g. "SamsungTablet"
+ * @function MobileDetect#tablet
+ */
+ tablet: function () {
+ prepareDetectionCache(this._cache, this.ua, this.maxPhoneWidth);
+ return this._cache.tablet;
+ },
+
+ /**
+ * Returns the detected user-agent string or <tt>null</tt>.
+ * <br>
+ * The returned user-agent is one of following keys:<br>
+ * <br><tt>Chrome, Dolfin, Opera, Skyfire, IE, Firefox, Bolt, TeaShark, Blazer, Safari,
+ * Tizen, UCBrowser, baiduboxapp, baidubrowser, DiigoBrowser, Puffin, Mercury,
+ * ObigoBrowser, NetFront, GenericBrowser</tt><br>
+ *
+ * @returns {String} the key for the detected user-agent or <tt>null</tt>
+ * @function MobileDetect#userAgent
+ */
+ userAgent: function () {
+ if (this._cache.userAgent === undefined) {
+ this._cache.userAgent = findMatch(mobileDetectRules.uas, this.ua);
+ }
+ return this._cache.userAgent;
+ },
+
+ /**
+ * Returns the detected operating system string or <tt>null</tt>.
+ * <br>
+ * The operating system is one of following keys:<br>
+ * <br><tt>AndroidOS, BlackBerryOS, PalmOS, SymbianOS, WindowsMobileOS, WindowsPhoneOS,
+ * iOS, MeeGoOS, MaemoOS, JavaOS, webOS, badaOS, BREWOS</tt><br>
+ *
+ * @returns {String} the key for the detected operating system.
+ * @function MobileDetect#os
+ */
+ os: function () {
+ if (this._cache.os === undefined) {
+ this._cache.os = findMatch(mobileDetectRules.oss0, this.ua) ||
+ findMatch(mobileDetectRules.oss, this.ua);
+ }
+ return this._cache.os;
+ },
+
+ /**
+ * Get the version (as Number) of the given property in the User-Agent.
+ * <br>
+ * Will return a float number. (eg. 2_0 will return 2.0, 4.3.1 will return 4.31)
+ *
+ * @param {String} key a key defining a thing which has a version.<br>
+ * You can use one of following keys:<br>
+ * <br><tt>Mobile, Build, Version, VendorID, iPad, iPhone, iPod, Kindle, Chrome, Coast,
+ * Dolfin, Firefox, Fennec, IE, NetFront, NokiaBrowser, Opera, Opera Mini, Opera
+ * Mobi, UC Browser, MQQBrowser, MicroMessenger, baiduboxapp, baidubrowser, Iron,
+ * Safari, Skyfire, Tizen, Webkit, Gecko, Trident, Presto, iOS, Android,
+ * BlackBerry, BREW, Java, Windows Phone OS, Windows Phone, Windows CE, Windows
+ * NT, Symbian, webOS</tt><br>
+ *
+ * @returns {Number} the version as float or <tt>NaN</tt> if User-Agent doesn't contain this version.
+ * Be careful when comparing this value with '==' operator!
+ * @function MobileDetect#version
+ */
+ version: function (key) {
+ return getVersion(key, this.ua);
+ },
+
+ /**
+ * Get the version (as String) of the given property in the User-Agent.
+ * <br>
+ *
+ * @param {String} key a key defining a thing which has a version.<br>
+ * You can use one of following keys:<br>
+ * <br><tt>Mobile, Build, Version, VendorID, iPad, iPhone, iPod, Kindle, Chrome, Coast,
+ * Dolfin, Firefox, Fennec, IE, NetFront, NokiaBrowser, Opera, Opera Mini, Opera
+ * Mobi, UC Browser, MQQBrowser, MicroMessenger, baiduboxapp, baidubrowser, Iron,
+ * Safari, Skyfire, Tizen, Webkit, Gecko, Trident, Presto, iOS, Android,
+ * BlackBerry, BREW, Java, Windows Phone OS, Windows Phone, Windows CE, Windows
+ * NT, Symbian, webOS</tt><br>
+ *
+ * @returns {String} the "raw" version as String or <tt>null</tt> if User-Agent doesn't contain this version.
+ *
+ * @function MobileDetect#versionStr
+ */
+ versionStr: function (key) {
+ return getVersionStr(key, this.ua);
+ },
+
+ /**
+ * Global test key against userAgent, os, phone, tablet and some other properties of userAgent string.
+ *
+ * @param {String} key the key (case-insensitive) of a userAgent, an operating system, phone or
+ * tablet family.<br>
+ * For a complete list of possible values, see {@link MobileDetect#userAgent},
+ * {@link MobileDetect#os}, {@link MobileDetect#phone}, {@link MobileDetect#tablet}.<br>
+ * Additionally you have following keys:<br>
+ * <br><tt>DesktopMode, TV, WebKit, Bot, MobileBot, Console, Watch</tt><br>
+ *
+ * @returns {boolean} <tt>true</tt> when the given key is one of the defined keys of userAgent, os, phone,
+ * tablet or one of the listed additional keys, otherwise <tt>false</tt>
+ * @function MobileDetect#is
+ */
+ is: function(key) {
+ return equalIC(key, this.userAgent()) ||
+ equalIC(key, this.os()) ||
+ equalIC(key, this.phone()) ||
+ equalIC(key, this.tablet()) ||
+ equalIC(key, findMatch(mobileDetectRules.utils, this.ua));
+ },
+
+ /**
+ * Do a quick test against navigator::userAgent.
+ *
+ * @param {String|RegExp} pattern the pattern, either as String or RegExp
+ * (a string will be converted to a case-insensitive RegExp).
+ * @returns {boolean} <tt>true</tt> when the pattern matches, otherwise <tt>false</tt>
+ * @function MobileDetect#match
+ */
+ match: function (pattern) {
+ if (!(pattern instanceof RegExp)) {
+ pattern = new RegExp(pattern, 'i');
+ }
+ return pattern.test(this.ua);
+ },
+
+ /**
+ * Checks whether the mobile device can be considered as phone regarding <code>screen.width</code>.
+ * <br>
+ * Obviously this method makes sense in browser environments only (not for Node.js)!
+ * @param {number} [maxPhoneWidth] the maximum logical pixels (aka. CSS-pixels) to be considered as phone.<br>
+ * The argument is optional and if not present or falsy, the value of the constructor is taken.
+ * @returns {boolean|undefined} <code>undefined</code> if screen size wasn't detectable, else <code>true</code>
+ * when screen.width is less or equal to maxPhoneWidth, otherwise <code>false</code>.<br>
+ * Will always return <code>undefined</code> server-side.
+ */
+ isPhoneSized: function (maxPhoneWidth) {
+ return MobileDetect.isPhoneSized(maxPhoneWidth || this.maxPhoneWidth);
+ },
+
+ /**
+ * Returns the mobile grade ('A', 'B', 'C').
+ *
+ * @returns {String} one of the mobile grades ('A', 'B', 'C').
+ * @function MobileDetect#mobileGrade
+ */
+ mobileGrade: function () {
+ if (this._cache.grade === undefined) {
+ this._cache.grade = mobileGrade(this);
+ }
+ return this._cache.grade;
+ }
+ };
+
+ // environment-dependent
+ if (typeof window !== 'undefined' && window.screen && window.screen.width) {
+ MobileDetect.isPhoneSized = function (maxPhoneWidth) {
+ if (maxPhoneWidth < 0) {
+ return undefined;
+ }
+ var physicalPixelWidth = window.screen.width,
+ pixelRatio = window.devicePixelRatio || 1,
+ cssPixelWidth = physicalPixelWidth / pixelRatio;
+
+ return cssPixelWidth <= maxPhoneWidth;
+ };
+ } else {
+ MobileDetect.isPhoneSized = function () {};
+ }
+
+ return MobileDetect;
+}); // end of call of define()
+})((function (undefined) {
+ if (typeof define === 'function' && define.amd) {
+ return define;
+ } else if (typeof module !== 'undefined' && module.exports) {
+ return function (factory) { module.exports = factory(); };
+ } else if (typeof window !== 'undefined') {
+ return function (factory) { window.MobileDetect = factory(); };
+ } else {
+ // please file a bug if you get this error!
+ throw new Error('unknown environment');
+ }
+})());
Added: trunk/packages/orthanc-webviewer/trunk/debian/JS/pako-0.2.5/HISTORY.md
===================================================================
--- trunk/packages/orthanc-webviewer/trunk/debian/JS/pako-0.2.5/HISTORY.md (rev 0)
+++ trunk/packages/orthanc-webviewer/trunk/debian/JS/pako-0.2.5/HISTORY.md 2015-03-02 09:58:59 UTC (rev 18890)
@@ -0,0 +1,50 @@
+0.2.5 / 2014-07-19
+------------------
+
+- Workaround for Chrome 38.0.2096.0 script parser bug, #30
+
+
+0.2.4 / 2014-07-07
+------------------
+
+- Fixed bug in inflate wrapper, #29
+
+
+0.2.3 / 2014-06-09
+------------------
+
+- Maintenance release, dependencies update.
+
+
+0.2.2 / 2014-06-04
+------------------
+
+- Fixed iOS 5.1 Safary issue with `apply(typed_array)`, #26.
+
+
+0.2.1 / 2014-05-01
+------------------
+
+- Fixed collision on switch dynamic/fixed tables.
+
+
+0.2.0 / 2014-04-18
+------------------
+
+- Added custom gzip headers support.
+- Added strings support.
+- Improved memory allocations for small chunks.
+- ZStream properties rename/cleanup.
+- More coverage tests.
+
+
+0.1.1 / 2014-03-20
+------------------
+
+- Bugfixes for inflate/deflate.
+
+
+0.1.0 / 2014-03-15
+------------------
+
+- First release.
Added: trunk/packages/orthanc-webviewer/trunk/debian/JS/pako-0.2.5/LICENSE
===================================================================
--- trunk/packages/orthanc-webviewer/trunk/debian/JS/pako-0.2.5/LICENSE (rev 0)
+++ trunk/packages/orthanc-webviewer/trunk/debian/JS/pako-0.2.5/LICENSE 2015-03-02 09:58:59 UTC (rev 18890)
@@ -0,0 +1,21 @@
+(The MIT License)
+
+Copyright (C) 2014 by Vitaly Puzrin
+
+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.
Added: trunk/packages/orthanc-webviewer/trunk/debian/JS/pako-0.2.5/README.md
===================================================================
--- trunk/packages/orthanc-webviewer/trunk/debian/JS/pako-0.2.5/README.md (rev 0)
+++ trunk/packages/orthanc-webviewer/trunk/debian/JS/pako-0.2.5/README.md 2015-03-02 09:58:59 UTC (rev 18890)
@@ -0,0 +1,172 @@
+pako - zlib port to javascript, very fast!
+==========================================
+
+[![Build Status](https://travis-ci.org/nodeca/pako.svg?branch=master)](https://travis-ci.org/nodeca/pako)
+[![NPM version](https://img.shields.io/npm/v/pako.svg)](https://www.npmjs.org/package/pako)
+
+__Why pako is cool:__
+
+- Almost as fast in modern JS engines as C implementation (see benchmarks).
+- Works in browsers, you can browserify any separate component.
+- Chunking support for big blobs.
+- Results are binary equal to well known [zlib](http://www.zlib.net/) (now v1.2.8 ported).
+
+This project was done to understand how fast JS can be and is it necessary to
+develop native C modules for CPU-intensive tasks. Enjoy the result!
+
+
+__Famous projects, using pako:__
+
+- [browserify](http://browserify.org/) (via [browserify-zlib](https://github.com/devongovett/browserify-zlib))
+- [JSZip](http://stuk.github.io/jszip/)
+- [mincer](https://github.com/nodeca/mincer)
+- [JS-Git](https://github.com/creationix/js-git) and
+ [Tedit](https://chrome.google.com/webstore/detail/tedit-development-environ/ooekdijbnbbjdfjocaiflnjgoohnblgf)
+ by [@creatronix](https://github.com/creationix)
+
+
+
+__Benchmarks:__
+
+```
+node v0.10.26, 1mb sample:
+
+ deflate-dankogai x 4.73 ops/sec ±0.82% (15 runs sampled)
+ deflate-gildas x 4.58 ops/sec ±2.33% (15 runs sampled)
+ deflate-imaya x 3.22 ops/sec ±3.95% (12 runs sampled)
+ ! deflate-pako x 6.99 ops/sec ±0.51% (21 runs sampled)
+ deflate-pako-string x 5.89 ops/sec ±0.77% (18 runs sampled)
+ deflate-pako-untyped x 4.39 ops/sec ±1.58% (14 runs sampled)
+ * deflate-zlib x 14.71 ops/sec ±4.23% (59 runs sampled)
+ inflate-dankogai x 32.16 ops/sec ±0.13% (56 runs sampled)
+ inflate-imaya x 30.35 ops/sec ±0.92% (53 runs sampled)
+ ! inflate-pako x 69.89 ops/sec ±1.46% (71 runs sampled)
+ inflate-pako-string x 19.22 ops/sec ±1.86% (49 runs sampled)
+ inflate-pako-untyped x 17.19 ops/sec ±0.85% (32 runs sampled)
+ * inflate-zlib x 70.03 ops/sec ±1.64% (81 runs sampled)
+
+node v0.11.12, 1mb sample:
+
+ deflate-dankogai x 5.60 ops/sec ±0.49% (17 runs sampled)
+ deflate-gildas x 5.06 ops/sec ±6.00% (16 runs sampled)
+ deflate-imaya x 3.52 ops/sec ±3.71% (13 runs sampled)
+ ! deflate-pako x 11.52 ops/sec ±0.22% (32 runs sampled)
+ deflate-pako-string x 9.53 ops/sec ±1.12% (27 runs sampled)
+ deflate-pako-untyped x 5.44 ops/sec ±0.72% (17 runs sampled)
+ * deflate-zlib x 14.05 ops/sec ±3.34% (63 runs sampled)
+ inflate-dankogai x 42.19 ops/sec ±0.09% (56 runs sampled)
+ inflate-imaya x 79.68 ops/sec ±1.07% (68 runs sampled)
+ ! inflate-pako x 97.52 ops/sec ±0.83% (80 runs sampled)
+ inflate-pako-string x 45.19 ops/sec ±1.69% (57 runs sampled)
+ inflate-pako-untyped x 24.35 ops/sec ±2.59% (40 runs sampled)
+ * inflate-zlib x 60.32 ops/sec ±1.36% (69 runs sampled)
+```
+
+zlib's test is partialy afferted by marshling (that make sense for inflate only).
+You can change deflate level to 0 in benchmark source, to investigate details.
+For deflate level 6 results can be considered as correct.
+
+__Install:__
+
+node.js:
+
+```
+npm install pako
+```
+
+browser:
+
+```
+bower install pako
+```
+
+
+Example & API
+-------------
+
+Full docs - http://nodeca.github.io/pako/
+
+```javascript
+var pako = require('pako');
+
+// Deflate
+//
+var input = new Uint8Array();
+//... fill input data here
+var output = pako.deflate(input);
+
+// Inflate (simple wrapper can throw exception on broken stream)
+//
+var compressed = new Uint8Array();
+//... fill data to uncompress here
+try {
+ var result = pako.inflate(compressed);
+catch (err) {
+ console.log(err);
+}
+
+//
+// Alternate interface for chunking & without exceptions
+//
+
+var inflator = new pako.Inflate();
+
+inflator.push(chunk1, false);
+inflator.push(chunk2, false);
+...
+inflator.push(chunkN, true); // true -> last chunk
+
+if (inflator.err) {
+ console.log(inflator.msg);
+}
+
+var output = inflator.result;
+
+```
+
+Sometime you can wish to work with strings. For example, to send
+big objects as json to server. Pako detects input data type. You can
+force output to be string with option `{ to: 'string' }`.
+
+```javascript
+var pako = require('pako');
+
+var test = { my: 'super', puper: [456, 567], awesome: 'pako' };
+
+var binaryString = pako.deflate(JSON.stringify(test), { to: 'string' });
+
+//
+// Here you can do base64 encode, make xhr requests and so on.
+//
+
+var restored = JSON.parse(pako.inflate(binaryString, { to: 'string' }));
+```
+
+
+Notes
+-----
+
+Pako does not contain some specific zlib functions:
+
+- __deflate__ - methods `deflateCopy`, `deflateBound`, `deflateParams`,
+ `deflatePending`, `deflatePrime`, `deflateSetDictionary`, `deflateTune`.
+- __inflate__ - `inflateGetDictionary`, `inflateCopy`, `inflateMark`,
+ `inflatePrime`, `inflateSetDictionary`, `inflateSync`, `inflateSyncPoint`,
+ `inflateUndermine`.
+
+
+Authors
+-------
+
+- Andrey Tupitsin [@anrd83](https://github.com/andr83)
+- Vitaly Puzrin [@puzrin](https://github.com/puzrin)
+
+Personal thanks to Vyacheslav Egorov ([@mraleph](https://github.com/mraleph))
+for his awesome tutoruals about optimising JS code for v8,
+[IRHydra](http://mrale.ph/irhydra/) tool and his advices.
+
+
+License
+-------
+
+MIT
Added: trunk/packages/orthanc-webviewer/trunk/debian/JS/pako-0.2.5/pako_inflate.js
===================================================================
--- trunk/packages/orthanc-webviewer/trunk/debian/JS/pako-0.2.5/pako_inflate.js (rev 0)
+++ trunk/packages/orthanc-webviewer/trunk/debian/JS/pako-0.2.5/pako_inflate.js 2015-03-02 09:58:59 UTC (rev 18890)
@@ -0,0 +1,3025 @@
+/* pako 0.2.5 nodeca/pako */!function(e){if("object"==typeof exports&&"undefined"!=typeof module)module.exports=e();else if("function"==typeof define&&define.amd)define([],e);else{var f;"undefined"!=typeof window?f=window:"undefined"!=typeof global?f=global:"undefined"!=typeof self&&(f=self),f.pako=e()}}(function(){var define,module,exports;return (function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);throw new Error("Cannot find module '"+o+"'")}var f=n[o]={exports:{}};t[o][0].call(f.exports,function(e){var n=t[o][1][e];return s(n?n:e)},f,f.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o<r.length;o++)s(r[o]);return s})({1:[function(_dereq_,module,exports){
+'use strict';
+
+
+var zlib_inflate = _dereq_('./zlib/inflate.js');
+var utils = _dereq_('./utils/common');
+var strings = _dereq_('./utils/strings');
+var c = _dereq_('./zlib/constants');
+var msg = _dereq_('./zlib/messages');
+var zstream = _dereq_('./zlib/zstream');
+var gzheader = _dereq_('./zlib/gzheader');
+
+
+/**
+ * class Inflate
+ *
+ * Generic JS-style wrapper for zlib calls. If you don't need
+ * streaming behaviour - use more simple functions: [[inflate]]
+ * and [[inflateRaw]].
+ **/
+
+/* internal
+ * inflate.chunks -> Array
+ *
+ * Chunks of output data, if [[Inflate#onData]] not overriden.
+ **/
+
+/**
+ * Inflate.result -> Uint8Array|Array|String
+ *
+ * Uncompressed result, generated by default [[Inflate#onData]]
+ * and [[Inflate#onEnd]] handlers. Filled after you push last chunk
+ * (call [[Inflate#push]] with `Z_FINISH` / `true` param).
+ **/
+
+/**
+ * Inflate.err -> Number
+ *
+ * Error code after inflate finished. 0 (Z_OK) on success.
+ * Should be checked if broken data possible.
+ **/
+
+/**
+ * Inflate.msg -> String
+ *
+ * Error message, if [[Inflate.err]] != 0
+ **/
+
+
+/**
+ * new Inflate(options)
+ * - options (Object): zlib inflate options.
+ *
+ * Creates new inflator instance with specified params. Throws exception
+ * on bad params. Supported options:
+ *
+ * - `windowBits`
+ *
+ * [http://zlib.net/manual.html#Advanced](http://zlib.net/manual.html#Advanced)
+ * for more information on these.
+ *
+ * Additional options, for internal needs:
+ *
+ * - `chunkSize` - size of generated data chunks (16K by default)
+ * - `raw` (Boolean) - do raw inflate
+ * - `to` (String) - if equal to 'string', then result will be converted
+ * from utf8 to utf16 (javascript) string. When string output requested,
+ * chunk length can differ from `chunkSize`, depending on content.
+ *
+ * By default, when no options set, autodetect deflate/gzip data format via
+ * wrapper header.
+ *
+ * ##### Example:
+ *
+ * ```javascript
+ * var pako = require('pako')
+ * , chunk1 = Uint8Array([1,2,3,4,5,6,7,8,9])
+ * , chunk2 = Uint8Array([10,11,12,13,14,15,16,17,18,19]);
+ *
+ * var inflate = new pako.Inflate({ level: 3});
+ *
+ * inflate.push(chunk1, false);
+ * inflate.push(chunk2, true); // true -> last chunk
+ *
+ * if (inflate.err) { throw new Error(inflate.err); }
+ *
+ * console.log(inflate.result);
+ * ```
+ **/
+var Inflate = function(options) {
+
+ this.options = utils.assign({
+ chunkSize: 16384,
+ windowBits: 0,
+ to: ''
+ }, options || {});
+
+ var opt = this.options;
+
+ // Force window size for `raw` data, if not set directly,
+ // because we have no header for autodetect.
+ if (opt.raw && (opt.windowBits >= 0) && (opt.windowBits < 16)) {
+ opt.windowBits = -opt.windowBits;
+ if (opt.windowBits === 0) { opt.windowBits = -15; }
+ }
+
+ // If `windowBits` not defined (and mode not raw) - set autodetect flag for gzip/deflate
+ if ((opt.windowBits >= 0) && (opt.windowBits < 16) &&
+ !(options && options.windowBits)) {
+ opt.windowBits += 32;
+ }
+
+ // Gzip header has no info about windows size, we can do autodetect only
+ // for deflate. So, if window size not set, force it to max when gzip possible
+ if ((opt.windowBits > 15) && (opt.windowBits < 48)) {
+ // bit 3 (16) -> gzipped data
+ // bit 4 (32) -> autodetect gzip/deflate
+ if ((opt.windowBits & 15) === 0) {
+ opt.windowBits |= 15;
+ }
+ }
+
+ this.err = 0; // error code, if happens (0 = Z_OK)
+ this.msg = ''; // error message
+ this.ended = false; // used to avoid multiple onEnd() calls
+ this.chunks = []; // chunks of compressed data
+
+ this.strm = new zstream();
+ this.strm.avail_out = 0;
+
+ var status = zlib_inflate.inflateInit2(
+ this.strm,
+ opt.windowBits
+ );
+
+ if (status !== c.Z_OK) {
+ throw new Error(msg[status]);
+ }
+
+ this.header = new gzheader();
+
+ zlib_inflate.inflateGetHeader(this.strm, this.header);
+};
+
+/**
+ * Inflate#push(data[, mode]) -> Boolean
+ * - data (Uint8Array|Array|String): input data
+ * - mode (Number|Boolean): 0..6 for corresponding Z_NO_FLUSH..Z_TREE modes.
+ * See constants. Skipped or `false` means Z_NO_FLUSH, `true` meansh Z_FINISH.
+ *
+ * Sends input data to inflate pipe, generating [[Inflate#onData]] calls with
+ * new output chunks. Returns `true` on success. The last data block must have
+ * mode Z_FINISH (or `true`). That flush internal pending buffers and call
+ * [[Inflate#onEnd]].
+ *
+ * On fail call [[Inflate#onEnd]] with error code and return false.
+ *
+ * We strongly recommend to use `Uint8Array` on input for best speed (output
+ * format is detected automatically). Also, don't skip last param and always
+ * use the same type in your code (boolean or number). That will improve JS speed.
+ *
+ * For regular `Array`-s make sure all elements are [0..255].
+ *
+ * ##### Example
+ *
+ * ```javascript
+ * push(chunk, false); // push one of data chunks
+ * ...
+ * push(chunk, true); // push last chunk
+ * ```
+ **/
+Inflate.prototype.push = function(data, mode) {
+ var strm = this.strm;
+ var chunkSize = this.options.chunkSize;
+ var status, _mode;
+ var next_out_utf8, tail, utf8str;
+
+ if (this.ended) { return false; }
+ _mode = (mode === ~~mode) ? mode : ((mode === true) ? c.Z_FINISH : c.Z_NO_FLUSH);
+
+ // Convert data if needed
+ if (typeof data === 'string') {
+ // Only binary strings can be decompressed on practice
+ strm.input = strings.binstring2buf(data);
+ } else {
+ strm.input = data;
+ }
+
+ strm.next_in = 0;
+ strm.avail_in = strm.input.length;
+
+ do {
+ if (strm.avail_out === 0) {
+ strm.output = new utils.Buf8(chunkSize);
+ strm.next_out = 0;
+ strm.avail_out = chunkSize;
+ }
+
+ status = zlib_inflate.inflate(strm, c.Z_NO_FLUSH); /* no bad return value */
+
+ if (status !== c.Z_STREAM_END && status !== c.Z_OK) {
+ this.onEnd(status);
+ this.ended = true;
+ return false;
+ }
+
+ if (strm.next_out) {
+ if (strm.avail_out === 0 || status === c.Z_STREAM_END || (strm.avail_in === 0 && _mode === c.Z_FINISH)) {
+
+ if (this.options.to === 'string') {
+
+ next_out_utf8 = strings.utf8border(strm.output, strm.next_out);
+
+ tail = strm.next_out - next_out_utf8;
+ utf8str = strings.buf2string(strm.output, next_out_utf8);
+
+ // move tail
+ strm.next_out = tail;
+ strm.avail_out = chunkSize - tail;
+ if (tail) { utils.arraySet(strm.output, strm.output, next_out_utf8, tail, 0); }
+
+ this.onData(utf8str);
+
+ } else {
+ this.onData(utils.shrinkBuf(strm.output, strm.next_out));
+ }
+ }
+ }
+ } while ((strm.avail_in > 0) && status !== c.Z_STREAM_END);
+
+ if (status === c.Z_STREAM_END) {
+ _mode = c.Z_FINISH;
+ }
+ // Finalize on the last chunk.
+ if (_mode === c.Z_FINISH) {
+ status = zlib_inflate.inflateEnd(this.strm);
+ this.onEnd(status);
+ this.ended = true;
+ return status === c.Z_OK;
+ }
+
+ return true;
+};
+
+
+/**
+ * Inflate#onData(chunk) -> Void
+ * - chunk (Uint8Array|Array|String): ouput data. Type of array depends
+ * on js engine support. When string output requested, each chunk
+ * will be string.
+ *
+ * By default, stores data blocks in `chunks[]` property and glue
+ * those in `onEnd`. Override this handler, if you need another behaviour.
+ **/
+Inflate.prototype.onData = function(chunk) {
+ this.chunks.push(chunk);
+};
+
+
+/**
+ * Inflate#onEnd(status) -> Void
+ * - status (Number): inflate status. 0 (Z_OK) on success,
+ * other if not.
+ *
+ * Called once after you tell inflate that input stream complete
+ * or error happenned. By default - join collected chunks,
+ * free memory and fill `results` / `err` properties.
+ **/
+Inflate.prototype.onEnd = function(status) {
+ // On success - join
+ if (status === c.Z_OK) {
+ if (this.options.to === 'string') {
+ // Glue & convert here, until we teach pako to send
+ // utf8 alligned strings to onData
+ this.result = this.chunks.join('');
+ } else {
+ this.result = utils.flattenChunks(this.chunks);
+ }
+ }
+ this.chunks = [];
+ this.err = status;
+ this.msg = this.strm.msg;
+};
+
+
+/**
+ * inflate(data[, options]) -> Uint8Array|Array|String
+ * - data (Uint8Array|Array|String): input data to decompress.
+ * - options (Object): zlib inflate options.
+ *
+ * Decompress `data` with inflate/ungzip and `options`. Autodetect
+ * format via wrapper header by default. That's why we don't provide
+ * separate `ungzip` method.
+ *
+ * Supported options are:
+ *
+ * - windowBits
+ *
+ * [http://zlib.net/manual.html#Advanced](http://zlib.net/manual.html#Advanced)
+ * for more information.
+ *
+ * Sugar (options):
+ *
+ * - `raw` (Boolean) - say that we work with raw stream, if you don't wish to specify
+ * negative windowBits implicitly.
+ * - `to` (String) - if equal to 'string', then result will be converted
+ * from utf8 to utf16 (javascript) string. When string output requested,
+ * chunk length can differ from `chunkSize`, depending on content.
+ *
+ *
+ * ##### Example:
+ *
+ * ```javascript
+ * var pako = require('pako')
+ * , input = pako.deflate([1,2,3,4,5,6,7,8,9])
+ * , output;
+ *
+ * try {
+ * output = pako.inflate(input);
+ * } catch (err)
+ * console.log(err);
+ * }
+ * ```
+ **/
+function inflate(input, options) {
+ var inflator = new Inflate(options);
+
+ inflator.push(input, true);
+
+ // That will never happens, if you don't cheat with options :)
+ if (inflator.err) { throw inflator.msg; }
+
+ return inflator.result;
+}
+
+
+/**
+ * inflateRaw(data[, options]) -> Uint8Array|Array|String
+ * - data (Uint8Array|Array|String): input data to decompress.
+ * - options (Object): zlib inflate options.
+ *
+ * The same as [[inflate]], but creates raw data, without wrapper
+ * (header and adler32 crc).
+ **/
+function inflateRaw(input, options) {
+ options = options || {};
+ options.raw = true;
+ return inflate(input, options);
+}
+
+
+/**
+ * ungzip(data[, options]) -> Uint8Array|Array|String
+ * - data (Uint8Array|Array|String): input data to decompress.
+ * - options (Object): zlib inflate options.
+ *
+ * Just shortcut to [[inflate]], because it autodetects format
+ * by header.content. Done for convenience.
+ **/
+
+
+exports.Inflate = Inflate;
+exports.inflate = inflate;
+exports.inflateRaw = inflateRaw;
+exports.ungzip = inflate;
+
+},{"./utils/common":2,"./utils/strings":3,"./zlib/constants":5,"./zlib/gzheader":7,"./zlib/inflate.js":9,"./zlib/messages":11,"./zlib/zstream":12}],2:[function(_dereq_,module,exports){
+'use strict';
+
+
+var TYPED_OK = (typeof Uint8Array !== 'undefined') &&
+ (typeof Uint16Array !== 'undefined') &&
+ (typeof Int32Array !== 'undefined');
+
+
+exports.assign = function (obj /*from1, from2, from3, ...*/) {
+ var sources = Array.prototype.slice.call(arguments, 1);
+ while (sources.length) {
+ var source = sources.shift();
+ if (!source) { continue; }
+
+ if (typeof(source) !== 'object') {
+ throw new TypeError(source + 'must be non-object');
+ }
+
+ for (var p in source) {
+ if (source.hasOwnProperty(p)) {
+ obj[p] = source[p];
+ }
+ }
+ }
+
+ return obj;
+};
+
+
+// reduce buffer size, avoiding mem copy
+exports.shrinkBuf = function (buf, size) {
+ if (buf.length === size) { return buf; }
+ if (buf.subarray) { return buf.subarray(0, size); }
+ buf.length = size;
+ return buf;
+};
+
+
+var fnTyped = {
+ arraySet: function (dest, src, src_offs, len, dest_offs) {
+ if (src.subarray && dest.subarray) {
+ dest.set(src.subarray(src_offs, src_offs+len), dest_offs);
+ return;
+ }
+ // Fallback to ordinary array
+ for(var i=0; i<len; i++) {
+ dest[dest_offs + i] = src[src_offs + i];
+ }
+ },
+ // Join array of chunks to single array.
+ flattenChunks: function(chunks) {
+ var i, l, len, pos, chunk, result;
+
+ // calculate data length
+ len = 0;
+ for (i=0, l=chunks.length; i<l; i++) {
+ len += chunks[i].length;
+ }
+
+ // join chunks
+ result = new Uint8Array(len);
+ pos = 0;
+ for (i=0, l=chunks.length; i<l; i++) {
+ chunk = chunks[i];
+ result.set(chunk, pos);
+ pos += chunk.length;
+ }
+
+ return result;
+ }
+};
+
+var fnUntyped = {
+ arraySet: function (dest, src, src_offs, len, dest_offs) {
+ for(var i=0; i<len; i++) {
+ dest[dest_offs + i] = src[src_offs + i];
+ }
+ },
+ // Join array of chunks to single array.
+ flattenChunks: function(chunks) {
+ return [].concat.apply([], chunks);
+ }
+};
+
+
+// Enable/Disable typed arrays use, for testing
+//
+exports.setTyped = function (on) {
+ if (on) {
+ exports.Buf8 = Uint8Array;
+ exports.Buf16 = Uint16Array;
+ exports.Buf32 = Int32Array;
+ exports.assign(exports, fnTyped);
+ } else {
+ exports.Buf8 = Array;
+ exports.Buf16 = Array;
+ exports.Buf32 = Array;
+ exports.assign(exports, fnUntyped);
+ }
+};
+
+exports.setTyped(TYPED_OK);
+},{}],3:[function(_dereq_,module,exports){
+// String encode/decode helpers
+'use strict';
+
+
+var utils = _dereq_('./common');
+
+
+// Quick check if we can use fast array to bin string conversion
+//
+// - apply(Array) can fail on Android 2.2
+// - apply(Uint8Array) can fail on iOS 5.1 Safary
+//
+var STR_APPLY_OK = true;
+var STR_APPLY_UIA_OK = true;
+
+try { String.fromCharCode.apply(null, [0]); } catch(__) { STR_APPLY_OK = false; }
+try { String.fromCharCode.apply(null, new Uint8Array(1)); } catch(__) { STR_APPLY_UIA_OK = false; }
+
+
+// Table with utf8 lengths (calculated by first byte of sequence)
+// Note, that 5 & 6-byte values and some 4-byte values can not be represented in JS,
+// because max possible codepoint is 0x10ffff
+var _utf8len = new utils.Buf8(256);
+for (var i=0; i<256; i++) {
+ _utf8len[i] = (i >= 252 ? 6 : i >= 248 ? 5 : i >= 240 ? 4 : i >= 224 ? 3 : i >= 192 ? 2 : 1);
+}
+_utf8len[254]=_utf8len[254]=1; // Invalid sequence start
+
+
+// convert string to array (typed, when possible)
+exports.string2buf = function (str) {
+ var buf, c, c2, m_pos, i, str_len = str.length, buf_len = 0;
+
+ // count binary size
+ for (m_pos = 0; m_pos < str_len; m_pos++) {
+ c = str.charCodeAt(m_pos);
+ if ((c & 0xfc00) === 0xd800 && (m_pos+1 < str_len)) {
+ c2 = str.charCodeAt(m_pos+1);
+ if ((c2 & 0xfc00) === 0xdc00) {
+ c = 0x10000 + ((c - 0xd800) << 10) + (c2 - 0xdc00);
+ m_pos++;
+ }
+ }
+ buf_len += c < 0x80 ? 1 : c < 0x800 ? 2 : c < 0x10000 ? 3 : 4;
+ }
+
+ // allocate buffer
+ buf = new utils.Buf8(buf_len);
+
+ // convert
+ for (i=0, m_pos = 0; i < buf_len; m_pos++) {
+ c = str.charCodeAt(m_pos);
+ if ((c & 0xfc00) === 0xd800 && (m_pos+1 < str_len)) {
+ c2 = str.charCodeAt(m_pos+1);
+ if ((c2 & 0xfc00) === 0xdc00) {
+ c = 0x10000 + ((c - 0xd800) << 10) + (c2 - 0xdc00);
+ m_pos++;
+ }
+ }
+ if (c < 0x80) {
+ /* one byte */
+ buf[i++] = c;
+ } else if (c < 0x800) {
+ /* two bytes */
+ buf[i++] = 0xC0 | (c >>> 6);
+ buf[i++] = 0x80 | (c & 0x3f);
+ } else if (c < 0x10000) {
+ /* three bytes */
+ buf[i++] = 0xE0 | (c >>> 12);
+ buf[i++] = 0x80 | (c >>> 6 & 0x3f);
+ buf[i++] = 0x80 | (c & 0x3f);
+ } else {
+ /* four bytes */
+ buf[i++] = 0xf0 | (c >>> 18);
+ buf[i++] = 0x80 | (c >>> 12 & 0x3f);
+ buf[i++] = 0x80 | (c >>> 6 & 0x3f);
+ buf[i++] = 0x80 | (c & 0x3f);
+ }
+ }
+
+ return buf;
+};
+
+// Helper (used in 2 places)
+function buf2binstring(buf, len) {
+ // use fallback for big arrays to avoid stack overflow
+ if (len < 65537) {
+ if ((buf.subarray && STR_APPLY_UIA_OK) || (!buf.subarray && STR_APPLY_OK)) {
+ return String.fromCharCode.apply(null, utils.shrinkBuf(buf, len));
+ }
+ }
+
+ var result = '';
+ for(var i=0; i < len; i++) {
+ result += String.fromCharCode(buf[i]);
+ }
+ return result;
+}
+
+
+// Convert byte array to binary string
+exports.buf2binstring = function(buf) {
+ return buf2binstring(buf, buf.length);
+};
+
+
+// Convert binary string (typed, when possible)
+exports.binstring2buf = function(str) {
+ var buf = new utils.Buf8(str.length);
+ for(var i=0, len=buf.length; i < len; i++) {
+ buf[i] = str.charCodeAt(i);
+ }
+ return buf;
+};
+
+
+// convert array to string
+exports.buf2string = function (buf, max) {
+ var i, out, c, c_len;
+ var len = max || buf.length;
+
+ // Reserve max possible length (2 words per char)
+ // NB: by unknown reasons, Array is significantly faster for
+ // String.fromCharCode.apply than Uint16Array.
+ var utf16buf = new Array(len*2);
+
+ for (out=0, i=0; i<len;) {
+ c = buf[i++];
+ // quick process ascii
+ if (c < 0x80) { utf16buf[out++] = c; continue; }
+
+ c_len = _utf8len[c];
+ // skip 5 & 6 byte codes
+ if (c_len > 4) { utf16buf[out++] = 0xfffd; i += c_len-1; continue; }
+
+ // apply mask on first byte
+ c &= c_len === 2 ? 0x1f : c_len === 3 ? 0x0f : 0x07;
+ // join the rest
+ while (c_len > 1 && i < len) {
+ c = (c << 6) | (buf[i++] & 0x3f);
+ c_len--;
+ }
+
+ // terminated by end of string?
+ if (c_len > 1) { utf16buf[out++] = 0xfffd; continue; }
+
+ if (c < 0x10000) {
+ utf16buf[out++] = c;
+ } else {
+ c -= 0x10000;
+ utf16buf[out++] = 0xd800 | ((c >> 10) & 0x3ff);
+ utf16buf[out++] = 0xdc00 | (c & 0x3ff);
+ }
+ }
+
+ return buf2binstring(utf16buf, out);
+};
+
+
+// Calculate max possible position in utf8 buffer,
+// that will not break sequence. If that's not possible
+// - (very small limits) return max size as is.
+//
+// buf[] - utf8 bytes array
+// max - length limit (mandatory);
+exports.utf8border = function(buf, max) {
+ var pos;
+
+ max = max || buf.length;
+ if (max > buf.length) { max = buf.length; }
+
+ // go back from last position, until start of sequence found
+ pos = max-1;
+ while (pos >= 0 && (buf[pos] & 0xC0) === 0x80) { pos--; }
+
+ // Fuckup - very small and broken sequence,
+ // return max, because we should return something anyway.
+ if (pos < 0) { return max; }
+
+ // If we came to start of buffer - that means vuffer is too small,
+ // return max too.
+ if (pos === 0) { return max; }
+
+ return (pos + _utf8len[buf[pos]] > max) ? pos : max;
+};
+
+},{"./common":2}],4:[function(_dereq_,module,exports){
+'use strict';
+
+// Note: adler32 takes 12% for level 0 and 2% for level 6.
+// It doesn't worth to make additional optimizationa as in original.
+// Small size is preferable.
+
+function adler32(adler, buf, len, pos) {
+ var s1 = (adler & 0xffff) |0
+ , s2 = ((adler >>> 16) & 0xffff) |0
+ , n = 0;
+
+ while (len !== 0) {
+ // Set limit ~ twice less than 5552, to keep
+ // s2 in 31-bits, because we force signed ints.
+ // in other case %= will fail.
+ n = len > 2000 ? 2000 : len;
+ len -= n;
+
+ do {
+ s1 = (s1 + buf[pos++]) |0;
+ s2 = (s2 + s1) |0;
+ } while (--n);
+
+ s1 %= 65521;
+ s2 %= 65521;
+ }
+
+ return (s1 | (s2 << 16)) |0;
+}
+
+
+module.exports = adler32;
+},{}],5:[function(_dereq_,module,exports){
+module.exports = {
+
+ /* Allowed flush values; see deflate() and inflate() below for details */
+ Z_NO_FLUSH: 0,
+ Z_PARTIAL_FLUSH: 1,
+ Z_SYNC_FLUSH: 2,
+ Z_FULL_FLUSH: 3,
+ Z_FINISH: 4,
+ Z_BLOCK: 5,
+ Z_TREES: 6,
+
+ /* Return codes for the compression/decompression functions. Negative values
+ * are errors, positive values are used for special but normal events.
+ */
+ Z_OK: 0,
+ Z_STREAM_END: 1,
+ Z_NEED_DICT: 2,
+ Z_ERRNO: -1,
+ Z_STREAM_ERROR: -2,
+ Z_DATA_ERROR: -3,
+ //Z_MEM_ERROR: -4,
+ Z_BUF_ERROR: -5,
+ //Z_VERSION_ERROR: -6,
+
+ /* compression levels */
+ Z_NO_COMPRESSION: 0,
+ Z_BEST_SPEED: 1,
+ Z_BEST_COMPRESSION: 9,
+ Z_DEFAULT_COMPRESSION: -1,
+
+
+ Z_FILTERED: 1,
+ Z_HUFFMAN_ONLY: 2,
+ Z_RLE: 3,
+ Z_FIXED: 4,
+ Z_DEFAULT_STRATEGY: 0,
+
+ /* Possible values of the data_type field (though see inflate()) */
+ Z_BINARY: 0,
+ Z_TEXT: 1,
+ //Z_ASCII: 1, // = Z_TEXT (deprecated)
+ Z_UNKNOWN: 2,
+
+ /* The deflate compression method */
+ Z_DEFLATED: 8
+ //Z_NULL: null // Use -1 or null inline, depending on var type
+};
+},{}],6:[function(_dereq_,module,exports){
+'use strict';
+
+// Note: we can't get significant speed boost here.
+// So write code to minimize size - no pregenerated tables
+// and array tools dependencies.
+
+
+// Use ordinary array, since untyped makes no boost here
+function makeTable() {
+ var c, table = [];
+
+ for(var n =0; n < 256; n++){
+ c = n;
+ for(var k =0; k < 8; k++){
+ c = ((c&1) ? (0xEDB88320 ^ (c >>> 1)) : (c >>> 1));
+ }
+ table[n] = c;
+ }
+
+ return table;
+}
+
+// Create table on load. Just 255 signed longs. Not a problem.
+var crcTable = makeTable();
+
+
+function crc32(crc, buf, len, pos) {
+ var t = crcTable
+ , end = pos + len;
+
+ crc = crc ^ (-1);
+
+ for (var i = pos; i < end; i++ ) {
+ crc = (crc >>> 8) ^ t[(crc ^ buf[i]) & 0xFF];
+ }
+
+ return (crc ^ (-1)); // >>> 0;
+}
+
+
+module.exports = crc32;
+},{}],7:[function(_dereq_,module,exports){
+'use strict';
+
+
+function GZheader() {
+ /* true if compressed data believed to be text */
+ this.text = 0;
+ /* modification time */
+ this.time = 0;
+ /* extra flags (not used when writing a gzip file) */
+ this.xflags = 0;
+ /* operating system */
+ this.os = 0;
+ /* pointer to extra field or Z_NULL if none */
+ this.extra = null;
+ /* extra field length (valid if extra != Z_NULL) */
+ this.extra_len = 0; // Actually, we don't need it in JS,
+ // but leave for few code modifications
+
+ //
+ // Setup limits is not necessary because in js we should not preallocate memory
+ // for inflate use constant limit in 65536 bytes
+ //
+
+ /* space at extra (only when reading header) */
+ // this.extra_max = 0;
+ /* pointer to zero-terminated file name or Z_NULL */
+ this.name = '';
+ /* space at name (only when reading header) */
+ // this.name_max = 0;
+ /* pointer to zero-terminated comment or Z_NULL */
+ this.comment = '';
+ /* space at comment (only when reading header) */
+ // this.comm_max = 0;
+ /* true if there was or will be a header crc */
+ this.hcrc = 0;
+ /* true when done reading gzip header (not used when writing a gzip file) */
+ this.done = false;
+}
+
+module.exports = GZheader;
+},{}],8:[function(_dereq_,module,exports){
+'use strict';
+
+// See state defs from inflate.js
+var BAD = 30; /* got a data error -- remain here until reset */
+var TYPE = 12; /* i: waiting for type bits, including last-flag bit */
+
+/*
+ Decode literal, length, and distance codes and write out the resulting
+ literal and match bytes until either not enough input or output is
+ available, an end-of-block is encountered, or a data error is encountered.
+ When large enough input and output buffers are supplied to inflate(), for
+ example, a 16K input buffer and a 64K output buffer, more than 95% of the
+ inflate execution time is spent in this routine.
+
+ Entry assumptions:
+
+ state.mode === LEN
+ strm.avail_in >= 6
+ strm.avail_out >= 258
+ start >= strm.avail_out
+ state.bits < 8
+
+ On return, state.mode is one of:
+
+ LEN -- ran out of enough output space or enough available input
+ TYPE -- reached end of block code, inflate() to interpret next block
+ BAD -- error in block data
+
+ Notes:
+
+ - The maximum input bits used by a length/distance pair is 15 bits for the
+ length code, 5 bits for the length extra, 15 bits for the distance code,
+ and 13 bits for the distance extra. This totals 48 bits, or six bytes.
+ Therefore if strm.avail_in >= 6, then there is enough input to avoid
+ checking for available input while decoding.
+
+ - The maximum bytes that a single length/distance pair can output is 258
+ bytes, which is the maximum length that can be coded. inflate_fast()
+ requires strm.avail_out >= 258 for each loop to avoid checking for
+ output space.
+ */
+module.exports = function inflate_fast(strm, start) {
+ var state;
+ var _in; /* local strm.input */
+ var last; /* have enough input while in < last */
+ var _out; /* local strm.output */
+ var beg; /* inflate()'s initial strm.output */
+ var end; /* while out < end, enough space available */
+//#ifdef INFLATE_STRICT
+ var dmax; /* maximum distance from zlib header */
+//#endif
+ var wsize; /* window size or zero if not using window */
+ var whave; /* valid bytes in the window */
+ var wnext; /* window write index */
+ var window; /* allocated sliding window, if wsize != 0 */
+ var hold; /* local strm.hold */
+ var bits; /* local strm.bits */
+ var lcode; /* local strm.lencode */
+ var dcode; /* local strm.distcode */
+ var lmask; /* mask for first level of length codes */
+ var dmask; /* mask for first level of distance codes */
+ var here; /* retrieved table entry */
+ var op; /* code bits, operation, extra bits, or */
+ /* window position, window bytes to copy */
+ var len; /* match length, unused bytes */
+ var dist; /* match distance */
+ var from; /* where to copy match from */
+ var from_source;
+
+
+ var input, output; // JS specific, because we have no pointers
+
+ /* copy state to local variables */
+ state = strm.state;
+ //here = state.here;
+ _in = strm.next_in;
+ input = strm.input;
+ last = _in + (strm.avail_in - 5);
+ _out = strm.next_out;
+ output = strm.output;
+ beg = _out - (start - strm.avail_out);
+ end = _out + (strm.avail_out - 257);
+//#ifdef INFLATE_STRICT
+ dmax = state.dmax;
+//#endif
+ wsize = state.wsize;
+ whave = state.whave;
+ wnext = state.wnext;
+ window = state.window;
+ hold = state.hold;
+ bits = state.bits;
+ lcode = state.lencode;
+ dcode = state.distcode;
+ lmask = (1 << state.lenbits) - 1;
+ dmask = (1 << state.distbits) - 1;
+
+
+ /* decode literals and length/distances until end-of-block or not enough
+ input data or output space */
+
+ top:
+ do {
+ if (bits < 15) {
+ hold += input[_in++] << bits;
+ bits += 8;
+ hold += input[_in++] << bits;
+ bits += 8;
+ }
+
+ here = lcode[hold & lmask];
+
+ dolen:
+ for (;;) { // Goto emulation
+ op = here >>> 24/*here.bits*/;
+ hold >>>= op;
+ bits -= op;
+ op = (here >>> 16) & 0xff/*here.op*/;
+ if (op === 0) { /* literal */
+ //Tracevv((stderr, here.val >= 0x20 && here.val < 0x7f ?
+ // "inflate: literal '%c'\n" :
+ // "inflate: literal 0x%02x\n", here.val));
+ output[_out++] = here & 0xffff/*here.val*/;
+ }
+ else if (op & 16) { /* length base */
+ len = here & 0xffff/*here.val*/;
+ op &= 15; /* number of extra bits */
+ if (op) {
+ if (bits < op) {
+ hold += input[_in++] << bits;
+ bits += 8;
+ }
+ len += hold & ((1 << op) - 1);
+ hold >>>= op;
+ bits -= op;
+ }
+ //Tracevv((stderr, "inflate: length %u\n", len));
+ if (bits < 15) {
+ hold += input[_in++] << bits;
+ bits += 8;
+ hold += input[_in++] << bits;
+ bits += 8;
+ }
+ here = dcode[hold & dmask];
+
+ dodist:
+ for (;;) { // goto emulation
+ op = here >>> 24/*here.bits*/;
+ hold >>>= op;
+ bits -= op;
+ op = (here >>> 16) & 0xff/*here.op*/;
+
+ if (op & 16) { /* distance base */
+ dist = here & 0xffff/*here.val*/;
+ op &= 15; /* number of extra bits */
+ if (bits < op) {
+ hold += input[_in++] << bits;
+ bits += 8;
+ if (bits < op) {
+ hold += input[_in++] << bits;
+ bits += 8;
+ }
+ }
+ dist += hold & ((1 << op) - 1);
+//#ifdef INFLATE_STRICT
+ if (dist > dmax) {
+ strm.msg = 'invalid distance too far back';
+ state.mode = BAD;
+ break top;
+ }
+//#endif
+ hold >>>= op;
+ bits -= op;
+ //Tracevv((stderr, "inflate: distance %u\n", dist));
+ op = _out - beg; /* max distance in output */
+ if (dist > op) { /* see if copy from window */
+ op = dist - op; /* distance back in window */
+ if (op > whave) {
+ if (state.sane) {
+ strm.msg = 'invalid distance too far back';
+ state.mode = BAD;
+ break top;
+ }
+
+// (!) This block is disabled in zlib defailts,
+// don't enable it for binary compatibility
+//#ifdef INFLATE_ALLOW_INVALID_DISTANCE_TOOFAR_ARRR
+// if (len <= op - whave) {
+// do {
+// output[_out++] = 0;
+// } while (--len);
+// continue top;
+// }
+// len -= op - whave;
+// do {
+// output[_out++] = 0;
+// } while (--op > whave);
+// if (op === 0) {
+// from = _out - dist;
+// do {
+// output[_out++] = output[from++];
+// } while (--len);
+// continue top;
+// }
+//#endif
+ }
+ from = 0; // window index
+ from_source = window;
+ if (wnext === 0) { /* very common case */
+ from += wsize - op;
+ if (op < len) { /* some from window */
+ len -= op;
+ do {
+ output[_out++] = window[from++];
+ } while (--op);
+ from = _out - dist; /* rest from output */
+ from_source = output;
+ }
+ }
+ else if (wnext < op) { /* wrap around window */
+ from += wsize + wnext - op;
+ op -= wnext;
+ if (op < len) { /* some from end of window */
+ len -= op;
+ do {
+ output[_out++] = window[from++];
+ } while (--op);
+ from = 0;
+ if (wnext < len) { /* some from start of window */
+ op = wnext;
+ len -= op;
+ do {
+ output[_out++] = window[from++];
+ } while (--op);
+ from = _out - dist; /* rest from output */
+ from_source = output;
+ }
+ }
+ }
+ else { /* contiguous in window */
+ from += wnext - op;
+ if (op < len) { /* some from window */
+ len -= op;
+ do {
+ output[_out++] = window[from++];
+ } while (--op);
+ from = _out - dist; /* rest from output */
+ from_source = output;
+ }
+ }
+ while (len > 2) {
+ output[_out++] = from_source[from++];
+ output[_out++] = from_source[from++];
+ output[_out++] = from_source[from++];
+ len -= 3;
+ }
+ if (len) {
+ output[_out++] = from_source[from++];
+ if (len > 1) {
+ output[_out++] = from_source[from++];
+ }
+ }
+ }
+ else {
+ from = _out - dist; /* copy direct from output */
+ do { /* minimum length is three */
+ output[_out++] = output[from++];
+ output[_out++] = output[from++];
+ output[_out++] = output[from++];
+ len -= 3;
+ } while (len > 2);
+ if (len) {
+ output[_out++] = output[from++];
+ if (len > 1) {
+ output[_out++] = output[from++];
+ }
+ }
+ }
+ }
+ else if ((op & 64) === 0) { /* 2nd level distance code */
+ here = dcode[(here & 0xffff)/*here.val*/ + (hold & ((1 << op) - 1))];
+ continue dodist;
+ }
+ else {
+ strm.msg = 'invalid distance code';
+ state.mode = BAD;
+ break top;
+ }
+
+ break; // need to emulate goto via "continue"
+ }
+ }
+ else if ((op & 64) === 0) { /* 2nd level length code */
+ here = lcode[(here & 0xffff)/*here.val*/ + (hold & ((1 << op) - 1))];
+ continue dolen;
+ }
+ else if (op & 32) { /* end-of-block */
+ //Tracevv((stderr, "inflate: end of block\n"));
+ state.mode = TYPE;
+ break top;
+ }
+ else {
+ strm.msg = 'invalid literal/length code';
+ state.mode = BAD;
+ break top;
+ }
+
+ break; // need to emulate goto via "continue"
+ }
+ } while (_in < last && _out < end);
+
+ /* return unused bytes (on entry, bits < 8, so in won't go too far back) */
+ len = bits >> 3;
+ _in -= len;
+ bits -= len << 3;
+ hold &= (1 << bits) - 1;
+
+ /* update state and return */
+ strm.next_in = _in;
+ strm.next_out = _out;
+ strm.avail_in = (_in < last ? 5 + (last - _in) : 5 - (_in - last));
+ strm.avail_out = (_out < end ? 257 + (end - _out) : 257 - (_out - end));
+ state.hold = hold;
+ state.bits = bits;
+ return;
+};
+
+},{}],9:[function(_dereq_,module,exports){
+'use strict';
+
+
+var utils = _dereq_('../utils/common');
+var adler32 = _dereq_('./adler32');
+var crc32 = _dereq_('./crc32');
+var inflate_fast = _dereq_('./inffast');
+var inflate_table = _dereq_('./inftrees');
+
+var CODES = 0;
+var LENS = 1;
+var DISTS = 2;
+
+/* Public constants ==========================================================*/
+/* ===========================================================================*/
+
+
+/* Allowed flush values; see deflate() and inflate() below for details */
+//var Z_NO_FLUSH = 0;
+//var Z_PARTIAL_FLUSH = 1;
+//var Z_SYNC_FLUSH = 2;
+//var Z_FULL_FLUSH = 3;
+var Z_FINISH = 4;
+var Z_BLOCK = 5;
+var Z_TREES = 6;
+
+
+/* Return codes for the compression/decompression functions. Negative values
+ * are errors, positive values are used for special but normal events.
+ */
+var Z_OK = 0;
+var Z_STREAM_END = 1;
+var Z_NEED_DICT = 2;
+//var Z_ERRNO = -1;
+var Z_STREAM_ERROR = -2;
+var Z_DATA_ERROR = -3;
+var Z_MEM_ERROR = -4;
+var Z_BUF_ERROR = -5;
+//var Z_VERSION_ERROR = -6;
+
+/* The deflate compression method */
+var Z_DEFLATED = 8;
+
+
+/* STATES ====================================================================*/
+/* ===========================================================================*/
+
+
+var HEAD = 1; /* i: waiting for magic header */
+var FLAGS = 2; /* i: waiting for method and flags (gzip) */
+var TIME = 3; /* i: waiting for modification time (gzip) */
+var OS = 4; /* i: waiting for extra flags and operating system (gzip) */
+var EXLEN = 5; /* i: waiting for extra length (gzip) */
+var EXTRA = 6; /* i: waiting for extra bytes (gzip) */
+var NAME = 7; /* i: waiting for end of file name (gzip) */
+var COMMENT = 8; /* i: waiting for end of comment (gzip) */
+var HCRC = 9; /* i: waiting for header crc (gzip) */
+var DICTID = 10; /* i: waiting for dictionary check value */
+var DICT = 11; /* waiting for inflateSetDictionary() call */
+var TYPE = 12; /* i: waiting for type bits, including last-flag bit */
+var TYPEDO = 13; /* i: same, but skip check to exit inflate on new block */
+var STORED = 14; /* i: waiting for stored size (length and complement) */
+var COPY_ = 15; /* i/o: same as COPY below, but only first time in */
+var COPY = 16; /* i/o: waiting for input or output to copy stored block */
+var TABLE = 17; /* i: waiting for dynamic block table lengths */
+var LENLENS = 18; /* i: waiting for code length code lengths */
+var CODELENS = 19; /* i: waiting for length/lit and distance code lengths */
+var LEN_ = 20; /* i: same as LEN below, but only first time in */
+var LEN = 21; /* i: waiting for length/lit/eob code */
+var LENEXT = 22; /* i: waiting for length extra bits */
+var DIST = 23; /* i: waiting for distance code */
+var DISTEXT = 24; /* i: waiting for distance extra bits */
+var MATCH = 25; /* o: waiting for output space to copy string */
+var LIT = 26; /* o: waiting for output space to write literal */
+var CHECK = 27; /* i: waiting for 32-bit check value */
+var LENGTH = 28; /* i: waiting for 32-bit length (gzip) */
+var DONE = 29; /* finished check, done -- remain here until reset */
+var BAD = 30; /* got a data error -- remain here until reset */
+var MEM = 31; /* got an inflate() memory error -- remain here until reset */
+var SYNC = 32; /* looking for synchronization bytes to restart inflate() */
+
+/* ===========================================================================*/
+
+
+
+var ENOUGH_LENS = 852;
+var ENOUGH_DISTS = 592;
+//var ENOUGH = (ENOUGH_LENS+ENOUGH_DISTS);
+
+var MAX_WBITS = 15;
+/* 32K LZ77 window */
+var DEF_WBITS = MAX_WBITS;
+
+
+function ZSWAP32(q) {
+ return (((q >>> 24) & 0xff) +
+ ((q >>> 8) & 0xff00) +
+ ((q & 0xff00) << 8) +
+ ((q & 0xff) << 24));
+}
+
+
+function InflateState() {
+ this.mode = 0; /* current inflate mode */
+ this.last = false; /* true if processing last block */
+ this.wrap = 0; /* bit 0 true for zlib, bit 1 true for gzip */
+ this.havedict = false; /* true if dictionary provided */
+ this.flags = 0; /* gzip header method and flags (0 if zlib) */
+ this.dmax = 0; /* zlib header max distance (INFLATE_STRICT) */
+ this.check = 0; /* protected copy of check value */
+ this.total = 0; /* protected copy of output count */
+ // TODO: may be {}
+ this.head = null; /* where to save gzip header information */
+
+ /* sliding window */
+ this.wbits = 0; /* log base 2 of requested window size */
+ this.wsize = 0; /* window size or zero if not using window */
+ this.whave = 0; /* valid bytes in the window */
+ this.wnext = 0; /* window write index */
+ this.window = null; /* allocated sliding window, if needed */
+
+ /* bit accumulator */
+ this.hold = 0; /* input bit accumulator */
+ this.bits = 0; /* number of bits in "in" */
+
+ /* for string and stored block copying */
+ this.length = 0; /* literal or length of data to copy */
+ this.offset = 0; /* distance back to copy string from */
+
+ /* for table and code decoding */
+ this.extra = 0; /* extra bits needed */
+
+ /* fixed and dynamic code tables */
+ this.lencode = null; /* starting table for length/literal codes */
+ this.distcode = null; /* starting table for distance codes */
+ this.lenbits = 0; /* index bits for lencode */
+ this.distbits = 0; /* index bits for distcode */
+
+ /* dynamic table building */
+ this.ncode = 0; /* number of code length code lengths */
+ this.nlen = 0; /* number of length code lengths */
+ this.ndist = 0; /* number of distance code lengths */
+ this.have = 0; /* number of code lengths in lens[] */
+ this.next = null; /* next available space in codes[] */
+
+ this.lens = new utils.Buf16(320); /* temporary storage for code lengths */
+ this.work = new utils.Buf16(288); /* work area for code table building */
+
+ /*
+ because we don't have pointers in js, we use lencode and distcode directly
+ as buffers so we don't need codes
+ */
+ //this.codes = new utils.Buf32(ENOUGH); /* space for code tables */
+ this.lendyn = null; /* dynamic table for length/literal codes (JS specific) */
+ this.distdyn = null; /* dynamic table for distance codes (JS specific) */
+ this.sane = 0; /* if false, allow invalid distance too far */
+ this.back = 0; /* bits back of last unprocessed length/lit */
+ this.was = 0; /* initial length of match */
+}
+
+function inflateResetKeep(strm) {
+ var state;
+
+ if (!strm || !strm.state) { return Z_STREAM_ERROR; }
+ state = strm.state;
+ strm.total_in = strm.total_out = state.total = 0;
+ strm.msg = ''; /*Z_NULL*/
+ if (state.wrap) { /* to support ill-conceived Java test suite */
+ strm.adler = state.wrap & 1;
+ }
+ state.mode = HEAD;
+ state.last = 0;
+ state.havedict = 0;
+ state.dmax = 32768;
+ state.head = null/*Z_NULL*/;
+ state.hold = 0;
+ state.bits = 0;
+ //state.lencode = state.distcode = state.next = state.codes;
+ state.lencode = state.lendyn = new utils.Buf32(ENOUGH_LENS);
+ state.distcode = state.distdyn = new utils.Buf32(ENOUGH_DISTS);
+
+ state.sane = 1;
+ state.back = -1;
+ //Tracev((stderr, "inflate: reset\n"));
+ return Z_OK;
+}
+
+function inflateReset(strm) {
+ var state;
+
+ if (!strm || !strm.state) { return Z_STREAM_ERROR; }
+ state = strm.state;
+ state.wsize = 0;
+ state.whave = 0;
+ state.wnext = 0;
+ return inflateResetKeep(strm);
+
+}
+
+function inflateReset2(strm, windowBits) {
+ var wrap;
+ var state;
+
+ /* get the state */
+ if (!strm || !strm.state) { return Z_STREAM_ERROR; }
+ state = strm.state;
+
+ /* extract wrap request from windowBits parameter */
+ if (windowBits < 0) {
+ wrap = 0;
+ windowBits = -windowBits;
+ }
+ else {
+ wrap = (windowBits >> 4) + 1;
+ if (windowBits < 48) {
+ windowBits &= 15;
+ }
+ }
+
+ /* set number of window bits, free window if different */
+ if (windowBits && (windowBits < 8 || windowBits > 15)) {
+ return Z_STREAM_ERROR;
+ }
+ if (state.window !== null && state.wbits !== windowBits) {
+ state.window = null;
+ }
+
+ /* update state and reset the rest of it */
+ state.wrap = wrap;
+ state.wbits = windowBits;
+ return inflateReset(strm);
+}
+
+function inflateInit2(strm, windowBits) {
+ var ret;
+ var state;
+
+ if (!strm) { return Z_STREAM_ERROR; }
+ //strm.msg = Z_NULL; /* in case we return an error */
+
+ state = new InflateState();
+
+ //if (state === Z_NULL) return Z_MEM_ERROR;
+ //Tracev((stderr, "inflate: allocated\n"));
+ strm.state = state;
+ state.window = null/*Z_NULL*/;
+ ret = inflateReset2(strm, windowBits);
+ if (ret !== Z_OK) {
+ strm.state = null/*Z_NULL*/;
+ }
+ return ret;
+}
+
+function inflateInit(strm) {
+ return inflateInit2(strm, DEF_WBITS);
+}
+
+
+/*
+ Return state with length and distance decoding tables and index sizes set to
+ fixed code decoding. Normally this returns fixed tables from inffixed.h.
+ If BUILDFIXED is defined, then instead this routine builds the tables the
+ first time it's called, and returns those tables the first time and
+ thereafter. This reduces the size of the code by about 2K bytes, in
+ exchange for a little execution time. However, BUILDFIXED should not be
+ used for threaded applications, since the rewriting of the tables and virgin
+ may not be thread-safe.
+ */
+var virgin = true;
+
+var lenfix, distfix; // We have no pointers in JS, so keep tables separate
+
+function fixedtables(state) {
+ /* build fixed huffman tables if first call (may not be thread safe) */
+ if (virgin) {
+ var sym;
+
+ lenfix = new utils.Buf32(512);
+ distfix = new utils.Buf32(32);
+
+ /* literal/length table */
+ sym = 0;
+ while (sym < 144) { state.lens[sym++] = 8; }
+ while (sym < 256) { state.lens[sym++] = 9; }
+ while (sym < 280) { state.lens[sym++] = 7; }
+ while (sym < 288) { state.lens[sym++] = 8; }
+
+ inflate_table(LENS, state.lens, 0, 288, lenfix, 0, state.work, {bits: 9});
+
+ /* distance table */
+ sym = 0;
+ while (sym < 32) { state.lens[sym++] = 5; }
+
+ inflate_table(DISTS, state.lens, 0, 32, distfix, 0, state.work, {bits: 5});
+
+ /* do this just once */
+ virgin = false;
+ }
+
+ state.lencode = lenfix;
+ state.lenbits = 9;
+ state.distcode = distfix;
+ state.distbits = 5;
+}
+
+
+/*
+ Update the window with the last wsize (normally 32K) bytes written before
+ returning. If window does not exist yet, create it. This is only called
+ when a window is already in use, or when output has been written during this
+ inflate call, but the end of the deflate stream has not been reached yet.
+ It is also called to create a window for dictionary data when a dictionary
+ is loaded.
+
+ Providing output buffers larger than 32K to inflate() should provide a speed
+ advantage, since only the last 32K of output is copied to the sliding window
+ upon return from inflate(), and since all distances after the first 32K of
+ output will fall in the output data, making match copies simpler and faster.
+ The advantage may be dependent on the size of the processor's data caches.
+ */
+function updatewindow(strm, src, end, copy) {
+ var dist;
+ var state = strm.state;
+
+ /* if it hasn't been done already, allocate space for the window */
+ if (state.window === null) {
+ state.wsize = 1 << state.wbits;
+ state.wnext = 0;
+ state.whave = 0;
+
+ state.window = new utils.Buf8(state.wsize);
+ }
+
+ /* copy state->wsize or less output bytes into the circular window */
+ if (copy >= state.wsize) {
+ utils.arraySet(state.window,src, end - state.wsize, state.wsize, 0);
+ state.wnext = 0;
+ state.whave = state.wsize;
+ }
+ else {
+ dist = state.wsize - state.wnext;
+ if (dist > copy) {
+ dist = copy;
+ }
+ //zmemcpy(state->window + state->wnext, end - copy, dist);
+ utils.arraySet(state.window,src, end - copy, dist, state.wnext);
+ copy -= dist;
+ if (copy) {
+ //zmemcpy(state->window, end - copy, copy);
+ utils.arraySet(state.window,src, end - copy, copy, 0);
+ state.wnext = copy;
+ state.whave = state.wsize;
+ }
+ else {
+ state.wnext += dist;
+ if (state.wnext === state.wsize) { state.wnext = 0; }
+ if (state.whave < state.wsize) { state.whave += dist; }
+ }
+ }
+ return 0;
+}
+
+function inflate(strm, flush) {
+ var state;
+ var input, output; // input/output buffers
+ var next; /* next input INDEX */
+ var put; /* next output INDEX */
+ var have, left; /* available input and output */
+ var hold; /* bit buffer */
+ var bits; /* bits in bit buffer */
+ var _in, _out; /* save starting available input and output */
+ var copy; /* number of stored or match bytes to copy */
+ var from; /* where to copy match bytes from */
+ var from_source;
+ var here = 0; /* current decoding table entry */
+ var here_bits, here_op, here_val; // paked "here" denormalized (JS specific)
+ //var last; /* parent table entry */
+ var last_bits, last_op, last_val; // paked "last" denormalized (JS specific)
+ var len; /* length to copy for repeats, bits to drop */
+ var ret; /* return code */
+ var hbuf = new utils.Buf8(4); /* buffer for gzip header crc calculation */
+ var opts;
+
+ var n; // temporary var for NEED_BITS
+
+ var order = /* permutation of code lengths */
+ [16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15];
+
+
+ if (!strm || !strm.state || !strm.output ||
+ (!strm.input && strm.avail_in !== 0)) {
+ return Z_STREAM_ERROR;
+ }
+
+ state = strm.state;
+ if (state.mode === TYPE) { state.mode = TYPEDO; } /* skip check */
+
+
+ //--- LOAD() ---
+ put = strm.next_out;
+ output = strm.output;
+ left = strm.avail_out;
+ next = strm.next_in;
+ input = strm.input;
+ have = strm.avail_in;
+ hold = state.hold;
+ bits = state.bits;
+ //---
+
+ _in = have;
+ _out = left;
+ ret = Z_OK;
+
+ inf_leave: // goto emulation
+ for (;;) {
+ switch (state.mode) {
+ case HEAD:
+ if (state.wrap === 0) {
+ state.mode = TYPEDO;
+ break;
+ }
+ //=== NEEDBITS(16);
+ while (bits < 16) {
+ if (have === 0) { break inf_leave; }
+ have--;
+ hold += input[next++] << bits;
+ bits += 8;
+ }
+ //===//
+ if ((state.wrap & 2) && hold === 0x8b1f) { /* gzip header */
+ state.check = 0/*crc32(0L, Z_NULL, 0)*/;
+ //=== CRC2(state.check, hold);
+ hbuf[0] = hold & 0xff;
+ hbuf[1] = (hold >>> 8) & 0xff;
+ state.check = crc32(state.check, hbuf, 2, 0);
+ //===//
+
+ //=== INITBITS();
+ hold = 0;
+ bits = 0;
+ //===//
+ state.mode = FLAGS;
+ break;
+ }
+ state.flags = 0; /* expect zlib header */
+ if (state.head) {
+ state.head.done = false;
+ }
+ if (!(state.wrap & 1) || /* check if zlib header allowed */
+ (((hold & 0xff)/*BITS(8)*/ << 8) + (hold >> 8)) % 31) {
+ strm.msg = 'incorrect header check';
+ state.mode = BAD;
+ break;
+ }
+ if ((hold & 0x0f)/*BITS(4)*/ !== Z_DEFLATED) {
+ strm.msg = 'unknown compression method';
+ state.mode = BAD;
+ break;
+ }
+ //--- DROPBITS(4) ---//
+ hold >>>= 4;
+ bits -= 4;
+ //---//
+ len = (hold & 0x0f)/*BITS(4)*/ + 8;
+ if (state.wbits === 0) {
+ state.wbits = len;
+ }
+ else if (len > state.wbits) {
+ strm.msg = 'invalid window size';
+ state.mode = BAD;
+ break;
+ }
+ state.dmax = 1 << len;
+ //Tracev((stderr, "inflate: zlib header ok\n"));
+ strm.adler = state.check = 1/*adler32(0L, Z_NULL, 0)*/;
+ state.mode = hold & 0x200 ? DICTID : TYPE;
+ //=== INITBITS();
+ hold = 0;
+ bits = 0;
+ //===//
+ break;
+ case FLAGS:
+ //=== NEEDBITS(16); */
+ while (bits < 16) {
+ if (have === 0) { break inf_leave; }
+ have--;
+ hold += input[next++] << bits;
+ bits += 8;
+ }
+ //===//
+ state.flags = hold;
+ if ((state.flags & 0xff) !== Z_DEFLATED) {
+ strm.msg = 'unknown compression method';
+ state.mode = BAD;
+ break;
+ }
+ if (state.flags & 0xe000) {
+ strm.msg = 'unknown header flags set';
+ state.mode = BAD;
+ break;
+ }
+ if (state.head) {
+ state.head.text = ((hold >> 8) & 1);
+ }
+ if (state.flags & 0x0200) {
+ //=== CRC2(state.check, hold);
+ hbuf[0] = hold & 0xff;
+ hbuf[1] = (hold >>> 8) & 0xff;
+ state.check = crc32(state.check, hbuf, 2, 0);
+ //===//
+ }
+ //=== INITBITS();
+ hold = 0;
+ bits = 0;
+ //===//
+ state.mode = TIME;
+ /* falls through */
+ case TIME:
+ //=== NEEDBITS(32); */
+ while (bits < 32) {
+ if (have === 0) { break inf_leave; }
+ have--;
+ hold += input[next++] << bits;
+ bits += 8;
+ }
+ //===//
+ if (state.head) {
+ state.head.time = hold;
+ }
+ if (state.flags & 0x0200) {
+ //=== CRC4(state.check, hold)
+ hbuf[0] = hold & 0xff;
+ hbuf[1] = (hold >>> 8) & 0xff;
+ hbuf[2] = (hold >>> 16) & 0xff;
+ hbuf[3] = (hold >>> 24) & 0xff;
+ state.check = crc32(state.check, hbuf, 4, 0);
+ //===
+ }
+ //=== INITBITS();
+ hold = 0;
+ bits = 0;
+ //===//
+ state.mode = OS;
+ /* falls through */
+ case OS:
+ //=== NEEDBITS(16); */
+ while (bits < 16) {
+ if (have === 0) { break inf_leave; }
+ have--;
+ hold += input[next++] << bits;
+ bits += 8;
+ }
+ //===//
+ if (state.head) {
+ state.head.xflags = (hold & 0xff);
+ state.head.os = (hold >> 8);
+ }
+ if (state.flags & 0x0200) {
+ //=== CRC2(state.check, hold);
+ hbuf[0] = hold & 0xff;
+ hbuf[1] = (hold >>> 8) & 0xff;
+ state.check = crc32(state.check, hbuf, 2, 0);
+ //===//
+ }
+ //=== INITBITS();
+ hold = 0;
+ bits = 0;
+ //===//
+ state.mode = EXLEN;
+ /* falls through */
+ case EXLEN:
+ if (state.flags & 0x0400) {
+ //=== NEEDBITS(16); */
+ while (bits < 16) {
+ if (have === 0) { break inf_leave; }
+ have--;
+ hold += input[next++] << bits;
+ bits += 8;
+ }
+ //===//
+ state.length = hold;
+ if (state.head) {
+ state.head.extra_len = hold;
+ }
+ if (state.flags & 0x0200) {
+ //=== CRC2(state.check, hold);
+ hbuf[0] = hold & 0xff;
+ hbuf[1] = (hold >>> 8) & 0xff;
+ state.check = crc32(state.check, hbuf, 2, 0);
+ //===//
+ }
+ //=== INITBITS();
+ hold = 0;
+ bits = 0;
+ //===//
+ }
+ else if (state.head) {
+ state.head.extra = null/*Z_NULL*/;
+ }
+ state.mode = EXTRA;
+ /* falls through */
+ case EXTRA:
+ if (state.flags & 0x0400) {
+ copy = state.length;
+ if (copy > have) { copy = have; }
+ if (copy) {
+ if (state.head) {
+ len = state.head.extra_len - state.length;
+ if (!state.head.extra) {
+ // Use untyped array for more conveniend processing later
+ state.head.extra = new Array(state.head.extra_len);
+ }
+ utils.arraySet(
+ state.head.extra,
+ input,
+ next,
+ // extra field is limited to 65536 bytes
+ // - no need for additional size check
+ copy,
+ /*len + copy > state.head.extra_max - len ? state.head.extra_max : copy,*/
+ len
+ );
+ //zmemcpy(state.head.extra + len, next,
+ // len + copy > state.head.extra_max ?
+ // state.head.extra_max - len : copy);
+ }
+ if (state.flags & 0x0200) {
+ state.check = crc32(state.check, input, copy, next);
+ }
+ have -= copy;
+ next += copy;
+ state.length -= copy;
+ }
+ if (state.length) { break inf_leave; }
+ }
+ state.length = 0;
+ state.mode = NAME;
+ /* falls through */
+ case NAME:
+ if (state.flags & 0x0800) {
+ if (have === 0) { break inf_leave; }
+ copy = 0;
+ do {
+ // TODO: 2 or 1 bytes?
+ len = input[next + copy++];
+ /* use constant limit because in js we should not preallocate memory */
+ if (state.head && len &&
+ (state.length < 65536 /*state.head.name_max*/)) {
+ state.head.name += String.fromCharCode(len);
+ }
+ } while (len && copy < have);
+
+ if (state.flags & 0x0200) {
+ state.check = crc32(state.check, input, copy, next);
+ }
+ have -= copy;
+ next += copy;
+ if (len) { break inf_leave; }
+ }
+ else if (state.head) {
+ state.head.name = null;
+ }
+ state.length = 0;
+ state.mode = COMMENT;
+ /* falls through */
+ case COMMENT:
+ if (state.flags & 0x1000) {
+ if (have === 0) { break inf_leave; }
+ copy = 0;
+ do {
+ len = input[next + copy++];
+ /* use constant limit because in js we should not preallocate memory */
+ if (state.head && len &&
+ (state.length < 65536 /*state.head.comm_max*/)) {
+ state.head.comment += String.fromCharCode(len);
+ }
+ } while (len && copy < have);
+ if (state.flags & 0x0200) {
+ state.check = crc32(state.check, input, copy, next);
+ }
+ have -= copy;
+ next += copy;
+ if (len) { break inf_leave; }
+ }
+ else if (state.head) {
+ state.head.comment = null;
+ }
+ state.mode = HCRC;
+ /* falls through */
+ case HCRC:
+ if (state.flags & 0x0200) {
+ //=== NEEDBITS(16); */
+ while (bits < 16) {
+ if (have === 0) { break inf_leave; }
+ have--;
+ hold += input[next++] << bits;
+ bits += 8;
+ }
+ //===//
+ if (hold !== (state.check & 0xffff)) {
+ strm.msg = 'header crc mismatch';
+ state.mode = BAD;
+ break;
+ }
+ //=== INITBITS();
+ hold = 0;
+ bits = 0;
+ //===//
+ }
+ if (state.head) {
+ state.head.hcrc = ((state.flags >> 9) & 1);
+ state.head.done = true;
+ }
+ strm.adler = state.check = 0 /*crc32(0L, Z_NULL, 0)*/;
+ state.mode = TYPE;
+ break;
+ case DICTID:
+ //=== NEEDBITS(32); */
+ while (bits < 32) {
+ if (have === 0) { break inf_leave; }
+ have--;
+ hold += input[next++] << bits;
+ bits += 8;
+ }
+ //===//
+ strm.adler = state.check = ZSWAP32(hold);
+ //=== INITBITS();
+ hold = 0;
+ bits = 0;
+ //===//
+ state.mode = DICT;
+ /* falls through */
+ case DICT:
+ if (state.havedict === 0) {
+ //--- RESTORE() ---
+ strm.next_out = put;
+ strm.avail_out = left;
+ strm.next_in = next;
+ strm.avail_in = have;
+ state.hold = hold;
+ state.bits = bits;
+ //---
+ return Z_NEED_DICT;
+ }
+ strm.adler = state.check = 1/*adler32(0L, Z_NULL, 0)*/;
+ state.mode = TYPE;
+ /* falls through */
+ case TYPE:
+ if (flush === Z_BLOCK || flush === Z_TREES) { break inf_leave; }
+ /* falls through */
+ case TYPEDO:
+ if (state.last) {
+ //--- BYTEBITS() ---//
+ hold >>>= bits & 7;
+ bits -= bits & 7;
+ //---//
+ state.mode = CHECK;
+ break;
+ }
+ //=== NEEDBITS(3); */
+ while (bits < 3) {
+ if (have === 0) { break inf_leave; }
+ have--;
+ hold += input[next++] << bits;
+ bits += 8;
+ }
+ //===//
+ state.last = (hold & 0x01)/*BITS(1)*/;
+ //--- DROPBITS(1) ---//
+ hold >>>= 1;
+ bits -= 1;
+ //---//
+
+ switch ((hold & 0x03)/*BITS(2)*/) {
+ case 0: /* stored block */
+ //Tracev((stderr, "inflate: stored block%s\n",
+ // state.last ? " (last)" : ""));
+ state.mode = STORED;
+ break;
+ case 1: /* fixed block */
+ fixedtables(state);
+ //Tracev((stderr, "inflate: fixed codes block%s\n",
+ // state.last ? " (last)" : ""));
+ state.mode = LEN_; /* decode codes */
+ if (flush === Z_TREES) {
+ //--- DROPBITS(2) ---//
+ hold >>>= 2;
+ bits -= 2;
+ //---//
+ break inf_leave;
+ }
+ break;
+ case 2: /* dynamic block */
+ //Tracev((stderr, "inflate: dynamic codes block%s\n",
+ // state.last ? " (last)" : ""));
+ state.mode = TABLE;
+ break;
+ case 3:
+ strm.msg = 'invalid block type';
+ state.mode = BAD;
+ }
+ //--- DROPBITS(2) ---//
+ hold >>>= 2;
+ bits -= 2;
+ //---//
+ break;
+ case STORED:
+ //--- BYTEBITS() ---// /* go to byte boundary */
+ hold >>>= bits & 7;
+ bits -= bits & 7;
+ //---//
+ //=== NEEDBITS(32); */
+ while (bits < 32) {
+ if (have === 0) { break inf_leave; }
+ have--;
+ hold += input[next++] << bits;
+ bits += 8;
+ }
+ //===//
+ if ((hold & 0xffff) !== ((hold >>> 16) ^ 0xffff)) {
+ strm.msg = 'invalid stored block lengths';
+ state.mode = BAD;
+ break;
+ }
+ state.length = hold & 0xffff;
+ //Tracev((stderr, "inflate: stored length %u\n",
+ // state.length));
+ //=== INITBITS();
+ hold = 0;
+ bits = 0;
+ //===//
+ state.mode = COPY_;
+ if (flush === Z_TREES) { break inf_leave; }
+ /* falls through */
+ case COPY_:
+ state.mode = COPY;
+ /* falls through */
+ case COPY:
+ copy = state.length;
+ if (copy) {
+ if (copy > have) { copy = have; }
+ if (copy > left) { copy = left; }
+ if (copy === 0) { break inf_leave; }
+ //--- zmemcpy(put, next, copy); ---
+ utils.arraySet(output, input, next, copy, put);
+ //---//
+ have -= copy;
+ next += copy;
+ left -= copy;
+ put += copy;
+ state.length -= copy;
+ break;
+ }
+ //Tracev((stderr, "inflate: stored end\n"));
+ state.mode = TYPE;
+ break;
+ case TABLE:
+ //=== NEEDBITS(14); */
+ while (bits < 14) {
+ if (have === 0) { break inf_leave; }
+ have--;
+ hold += input[next++] << bits;
+ bits += 8;
+ }
+ //===//
+ state.nlen = (hold & 0x1f)/*BITS(5)*/ + 257;
+ //--- DROPBITS(5) ---//
+ hold >>>= 5;
+ bits -= 5;
+ //---//
+ state.ndist = (hold & 0x1f)/*BITS(5)*/ + 1;
+ //--- DROPBITS(5) ---//
+ hold >>>= 5;
+ bits -= 5;
+ //---//
+ state.ncode = (hold & 0x0f)/*BITS(4)*/ + 4;
+ //--- DROPBITS(4) ---//
+ hold >>>= 4;
+ bits -= 4;
+ //---//
+//#ifndef PKZIP_BUG_WORKAROUND
+ if (state.nlen > 286 || state.ndist > 30) {
+ strm.msg = 'too many length or distance symbols';
+ state.mode = BAD;
+ break;
+ }
+//#endif
+ //Tracev((stderr, "inflate: table sizes ok\n"));
+ state.have = 0;
+ state.mode = LENLENS;
+ /* falls through */
+ case LENLENS:
+ while (state.have < state.ncode) {
+ //=== NEEDBITS(3);
+ while (bits < 3) {
+ if (have === 0) { break inf_leave; }
+ have--;
+ hold += input[next++] << bits;
+ bits += 8;
+ }
+ //===//
+ state.lens[order[state.have++]] = (hold & 0x07);//BITS(3);
+ //--- DROPBITS(3) ---//
+ hold >>>= 3;
+ bits -= 3;
+ //---//
+ }
+ while (state.have < 19) {
+ state.lens[order[state.have++]] = 0;
+ }
+ // We have separate tables & no pointers. 2 commented lines below not needed.
+ //state.next = state.codes;
+ //state.lencode = state.next;
+ // Switch to use dynamic table
+ state.lencode = state.lendyn;
+ state.lenbits = 7;
+
+ opts = {bits: state.lenbits};
+ ret = inflate_table(CODES, state.lens, 0, 19, state.lencode, 0, state.work, opts);
+ state.lenbits = opts.bits;
+
+ if (ret) {
+ strm.msg = 'invalid code lengths set';
+ state.mode = BAD;
+ break;
+ }
+ //Tracev((stderr, "inflate: code lengths ok\n"));
+ state.have = 0;
+ state.mode = CODELENS;
+ /* falls through */
+ case CODELENS:
+ while (state.have < state.nlen + state.ndist) {
+ for (;;) {
+ here = state.lencode[hold & ((1 << state.lenbits) - 1)];/*BITS(state.lenbits)*/
+ here_bits = here >>> 24;
+ here_op = (here >>> 16) & 0xff;
+ here_val = here & 0xffff;
+
+ if ((here_bits) <= bits) { break; }
+ //--- PULLBYTE() ---//
+ if (have === 0) { break inf_leave; }
+ have--;
+ hold += input[next++] << bits;
+ bits += 8;
+ //---//
+ }
+ if (here_val < 16) {
+ //--- DROPBITS(here.bits) ---//
+ hold >>>= here_bits;
+ bits -= here_bits;
+ //---//
+ state.lens[state.have++] = here_val;
+ }
+ else {
+ if (here_val === 16) {
+ //=== NEEDBITS(here.bits + 2);
+ n = here_bits + 2;
+ while (bits < n) {
+ if (have === 0) { break inf_leave; }
+ have--;
+ hold += input[next++] << bits;
+ bits += 8;
+ }
+ //===//
+ //--- DROPBITS(here.bits) ---//
+ hold >>>= here_bits;
+ bits -= here_bits;
+ //---//
+ if (state.have === 0) {
+ strm.msg = 'invalid bit length repeat';
+ state.mode = BAD;
+ break;
+ }
+ len = state.lens[state.have - 1];
+ copy = 3 + (hold & 0x03);//BITS(2);
+ //--- DROPBITS(2) ---//
+ hold >>>= 2;
+ bits -= 2;
+ //---//
+ }
+ else if (here_val === 17) {
+ //=== NEEDBITS(here.bits + 3);
+ n = here_bits + 3;
+ while (bits < n) {
+ if (have === 0) { break inf_leave; }
+ have--;
+ hold += input[next++] << bits;
+ bits += 8;
+ }
+ //===//
+ //--- DROPBITS(here.bits) ---//
+ hold >>>= here_bits;
+ bits -= here_bits;
+ //---//
+ len = 0;
+ copy = 3 + (hold & 0x07);//BITS(3);
+ //--- DROPBITS(3) ---//
+ hold >>>= 3;
+ bits -= 3;
+ //---//
+ }
+ else {
+ //=== NEEDBITS(here.bits + 7);
+ n = here_bits + 7;
+ while (bits < n) {
+ if (have === 0) { break inf_leave; }
+ have--;
+ hold += input[next++] << bits;
+ bits += 8;
+ }
+ //===//
+ //--- DROPBITS(here.bits) ---//
+ hold >>>= here_bits;
+ bits -= here_bits;
+ //---//
+ len = 0;
+ copy = 11 + (hold & 0x7f);//BITS(7);
+ //--- DROPBITS(7) ---//
+ hold >>>= 7;
+ bits -= 7;
+ //---//
+ }
+ if (state.have + copy > state.nlen + state.ndist) {
+ strm.msg = 'invalid bit length repeat';
+ state.mode = BAD;
+ break;
+ }
+ while (copy--) {
+ state.lens[state.have++] = len;
+ }
+ }
+ }
+
+ /* handle error breaks in while */
+ if (state.mode === BAD) { break; }
+
+ /* check for end-of-block code (better have one) */
+ if (state.lens[256] === 0) {
+ strm.msg = 'invalid code -- missing end-of-block';
+ state.mode = BAD;
+ break;
+ }
+
+ /* build code tables -- note: do not change the lenbits or distbits
+ values here (9 and 6) without reading the comments in inftrees.h
+ concerning the ENOUGH constants, which depend on those values */
+ state.lenbits = 9;
+
+ opts = {bits: state.lenbits};
+ ret = inflate_table(LENS, state.lens, 0, state.nlen, state.lencode, 0, state.work, opts);
+ // We have separate tables & no pointers. 2 commented lines below not needed.
+ // state.next_index = opts.table_index;
+ state.lenbits = opts.bits;
+ // state.lencode = state.next;
+
+ if (ret) {
+ strm.msg = 'invalid literal/lengths set';
+ state.mode = BAD;
+ break;
+ }
+
+ state.distbits = 6;
+ //state.distcode.copy(state.codes);
+ // Switch to use dynamic table
+ state.distcode = state.distdyn;
+ opts = {bits: state.distbits};
+ ret = inflate_table(DISTS, state.lens, state.nlen, state.ndist, state.distcode, 0, state.work, opts);
+ // We have separate tables & no pointers. 2 commented lines below not needed.
+ // state.next_index = opts.table_index;
+ state.distbits = opts.bits;
+ // state.distcode = state.next;
+
+ if (ret) {
+ strm.msg = 'invalid distances set';
+ state.mode = BAD;
+ break;
+ }
+ //Tracev((stderr, 'inflate: codes ok\n'));
+ state.mode = LEN_;
+ if (flush === Z_TREES) { break inf_leave; }
+ /* falls through */
+ case LEN_:
+ state.mode = LEN;
+ /* falls through */
+ case LEN:
+ if (have >= 6 && left >= 258) {
+ //--- RESTORE() ---
+ strm.next_out = put;
+ strm.avail_out = left;
+ strm.next_in = next;
+ strm.avail_in = have;
+ state.hold = hold;
+ state.bits = bits;
+ //---
+ inflate_fast(strm, _out);
+ //--- LOAD() ---
+ put = strm.next_out;
+ output = strm.output;
+ left = strm.avail_out;
+ next = strm.next_in;
+ input = strm.input;
+ have = strm.avail_in;
+ hold = state.hold;
+ bits = state.bits;
+ //---
+
+ if (state.mode === TYPE) {
+ state.back = -1;
+ }
+ break;
+ }
+ state.back = 0;
+ for (;;) {
+ here = state.lencode[hold & ((1 << state.lenbits) -1)]; /*BITS(state.lenbits)*/
+ here_bits = here >>> 24;
+ here_op = (here >>> 16) & 0xff;
+ here_val = here & 0xffff;
+
+ if (here_bits <= bits) { break; }
+ //--- PULLBYTE() ---//
+ if (have === 0) { break inf_leave; }
+ have--;
+ hold += input[next++] << bits;
+ bits += 8;
+ //---//
+ }
+ if (here_op && (here_op & 0xf0) === 0) {
+ last_bits = here_bits;
+ last_op = here_op;
+ last_val = here_val;
+ for (;;) {
+ here = state.lencode[last_val +
+ ((hold & ((1 << (last_bits + last_op)) -1))/*BITS(last.bits + last.op)*/ >> last_bits)];
+ here_bits = here >>> 24;
+ here_op = (here >>> 16) & 0xff;
+ here_val = here & 0xffff;
+
+ if ((last_bits + here_bits) <= bits) { break; }
+ //--- PULLBYTE() ---//
+ if (have === 0) { break inf_leave; }
+ have--;
+ hold += input[next++] << bits;
+ bits += 8;
+ //---//
+ }
+ //--- DROPBITS(last.bits) ---//
+ hold >>>= last_bits;
+ bits -= last_bits;
+ //---//
+ state.back += last_bits;
+ }
+ //--- DROPBITS(here.bits) ---//
+ hold >>>= here_bits;
+ bits -= here_bits;
+ //---//
+ state.back += here_bits;
+ state.length = here_val;
+ if (here_op === 0) {
+ //Tracevv((stderr, here.val >= 0x20 && here.val < 0x7f ?
+ // "inflate: literal '%c'\n" :
+ // "inflate: literal 0x%02x\n", here.val));
+ state.mode = LIT;
+ break;
+ }
+ if (here_op & 32) {
+ //Tracevv((stderr, "inflate: end of block\n"));
+ state.back = -1;
+ state.mode = TYPE;
+ break;
+ }
+ if (here_op & 64) {
+ strm.msg = 'invalid literal/length code';
+ state.mode = BAD;
+ break;
+ }
+ state.extra = here_op & 15;
+ state.mode = LENEXT;
+ /* falls through */
+ case LENEXT:
+ if (state.extra) {
+ //=== NEEDBITS(state.extra);
+ n = state.extra;
+ while (bits < n) {
+ if (have === 0) { break inf_leave; }
+ have--;
+ hold += input[next++] << bits;
+ bits += 8;
+ }
+ //===//
+ state.length += hold & ((1 << state.extra) -1)/*BITS(state.extra)*/;
+ //--- DROPBITS(state.extra) ---//
+ hold >>>= state.extra;
+ bits -= state.extra;
+ //---//
+ state.back += state.extra;
+ }
+ //Tracevv((stderr, "inflate: length %u\n", state.length));
+ state.was = state.length;
+ state.mode = DIST;
+ /* falls through */
+ case DIST:
+ for (;;) {
+ here = state.distcode[hold & ((1 << state.distbits) -1)];/*BITS(state.distbits)*/
+ here_bits = here >>> 24;
+ here_op = (here >>> 16) & 0xff;
+ here_val = here & 0xffff;
+
+ if ((here_bits) <= bits) { break; }
+ //--- PULLBYTE() ---//
+ if (have === 0) { break inf_leave; }
+ have--;
+ hold += input[next++] << bits;
+ bits += 8;
+ //---//
+ }
+ if ((here_op & 0xf0) === 0) {
+ last_bits = here_bits;
+ last_op = here_op;
+ last_val = here_val;
+ for (;;) {
+ here = state.distcode[last_val +
+ ((hold & ((1 << (last_bits + last_op)) -1))/*BITS(last.bits + last.op)*/ >> last_bits)];
+ here_bits = here >>> 24;
+ here_op = (here >>> 16) & 0xff;
+ here_val = here & 0xffff;
+
+ if ((last_bits + here_bits) <= bits) { break; }
+ //--- PULLBYTE() ---//
+ if (have === 0) { break inf_leave; }
+ have--;
+ hold += input[next++] << bits;
+ bits += 8;
+ //---//
+ }
+ //--- DROPBITS(last.bits) ---//
+ hold >>>= last_bits;
+ bits -= last_bits;
+ //---//
+ state.back += last_bits;
+ }
+ //--- DROPBITS(here.bits) ---//
+ hold >>>= here_bits;
+ bits -= here_bits;
+ //---//
+ state.back += here_bits;
+ if (here_op & 64) {
+ strm.msg = 'invalid distance code';
+ state.mode = BAD;
+ break;
+ }
+ state.offset = here_val;
+ state.extra = (here_op) & 15;
+ state.mode = DISTEXT;
+ /* falls through */
+ case DISTEXT:
+ if (state.extra) {
+ //=== NEEDBITS(state.extra);
+ n = state.extra;
+ while (bits < n) {
+ if (have === 0) { break inf_leave; }
+ have--;
+ hold += input[next++] << bits;
+ bits += 8;
+ }
+ //===//
+ state.offset += hold & ((1 << state.extra) -1)/*BITS(state.extra)*/;
+ //--- DROPBITS(state.extra) ---//
+ hold >>>= state.extra;
+ bits -= state.extra;
+ //---//
+ state.back += state.extra;
+ }
+//#ifdef INFLATE_STRICT
+ if (state.offset > state.dmax) {
+ strm.msg = 'invalid distance too far back';
+ state.mode = BAD;
+ break;
+ }
+//#endif
+ //Tracevv((stderr, "inflate: distance %u\n", state.offset));
+ state.mode = MATCH;
+ /* falls through */
+ case MATCH:
+ if (left === 0) { break inf_leave; }
+ copy = _out - left;
+ if (state.offset > copy) { /* copy from window */
+ copy = state.offset - copy;
+ if (copy > state.whave) {
+ if (state.sane) {
+ strm.msg = 'invalid distance too far back';
+ state.mode = BAD;
+ break;
+ }
+// (!) This block is disabled in zlib defailts,
+// don't enable it for binary compatibility
+//#ifdef INFLATE_ALLOW_INVALID_DISTANCE_TOOFAR_ARRR
+// Trace((stderr, "inflate.c too far\n"));
+// copy -= state.whave;
+// if (copy > state.length) { copy = state.length; }
+// if (copy > left) { copy = left; }
+// left -= copy;
+// state.length -= copy;
+// do {
+// output[put++] = 0;
+// } while (--copy);
+// if (state.length === 0) { state.mode = LEN; }
+// break;
+//#endif
+ }
+ if (copy > state.wnext) {
+ copy -= state.wnext;
+ from = state.wsize - copy;
+ }
+ else {
+ from = state.wnext - copy;
+ }
+ if (copy > state.length) { copy = state.length; }
+ from_source = state.window;
+ }
+ else { /* copy from output */
+ from_source = output;
+ from = put - state.offset;
+ copy = state.length;
+ }
+ if (copy > left) { copy = left; }
+ left -= copy;
+ state.length -= copy;
+ do {
+ output[put++] = from_source[from++];
+ } while (--copy);
+ if (state.length === 0) { state.mode = LEN; }
+ break;
+ case LIT:
+ if (left === 0) { break inf_leave; }
+ output[put++] = state.length;
+ left--;
+ state.mode = LEN;
+ break;
+ case CHECK:
+ if (state.wrap) {
+ //=== NEEDBITS(32);
+ while (bits < 32) {
+ if (have === 0) { break inf_leave; }
+ have--;
+ // Use '|' insdead of '+' to make sure that result is signed
+ hold |= input[next++] << bits;
+ bits += 8;
+ }
+ //===//
+ _out -= left;
+ strm.total_out += _out;
+ state.total += _out;
+ if (_out) {
+ strm.adler = state.check =
+ /*UPDATE(state.check, put - _out, _out);*/
+ (state.flags ? crc32(state.check, output, _out, put - _out) : adler32(state.check, output, _out, put - _out));
+
+ }
+ _out = left;
+ // NB: crc32 stored as signed 32-bit int, ZSWAP32 returns signed too
+ if ((state.flags ? hold : ZSWAP32(hold)) !== state.check) {
+ strm.msg = 'incorrect data check';
+ state.mode = BAD;
+ break;
+ }
+ //=== INITBITS();
+ hold = 0;
+ bits = 0;
+ //===//
+ //Tracev((stderr, "inflate: check matches trailer\n"));
+ }
+ state.mode = LENGTH;
+ /* falls through */
+ case LENGTH:
+ if (state.wrap && state.flags) {
+ //=== NEEDBITS(32);
+ while (bits < 32) {
+ if (have === 0) { break inf_leave; }
+ have--;
+ hold += input[next++] << bits;
+ bits += 8;
+ }
+ //===//
+ if (hold !== (state.total & 0xffffffff)) {
+ strm.msg = 'incorrect length check';
+ state.mode = BAD;
+ break;
+ }
+ //=== INITBITS();
+ hold = 0;
+ bits = 0;
+ //===//
+ //Tracev((stderr, "inflate: length matches trailer\n"));
+ }
+ state.mode = DONE;
+ /* falls through */
+ case DONE:
+ ret = Z_STREAM_END;
+ break inf_leave;
+ case BAD:
+ ret = Z_DATA_ERROR;
+ break inf_leave;
+ case MEM:
+ return Z_MEM_ERROR;
+ case SYNC:
+ /* falls through */
+ default:
+ return Z_STREAM_ERROR;
+ }
+ }
+
+ // inf_leave <- here is real place for "goto inf_leave", emulated via "break inf_leave"
+
+ /*
+ Return from inflate(), updating the total counts and the check value.
+ If there was no progress during the inflate() call, return a buffer
+ error. Call updatewindow() to create and/or update the window state.
+ Note: a memory error from inflate() is non-recoverable.
+ */
+
+ //--- RESTORE() ---
+ strm.next_out = put;
+ strm.avail_out = left;
+ strm.next_in = next;
+ strm.avail_in = have;
+ state.hold = hold;
+ state.bits = bits;
+ //---
+
+ if (state.wsize || (_out !== strm.avail_out && state.mode < BAD &&
+ (state.mode < CHECK || flush !== Z_FINISH))) {
+ if (updatewindow(strm, strm.output, strm.next_out, _out - strm.avail_out)) {
+ state.mode = MEM;
+ return Z_MEM_ERROR;
+ }
+ }
+ _in -= strm.avail_in;
+ _out -= strm.avail_out;
+ strm.total_in += _in;
+ strm.total_out += _out;
+ state.total += _out;
+ if (state.wrap && _out) {
+ strm.adler = state.check = /*UPDATE(state.check, strm.next_out - _out, _out);*/
+ (state.flags ? crc32(state.check, output, _out, strm.next_out - _out) : adler32(state.check, output, _out, strm.next_out - _out));
+ }
+ strm.data_type = state.bits + (state.last ? 64 : 0) +
+ (state.mode === TYPE ? 128 : 0) +
+ (state.mode === LEN_ || state.mode === COPY_ ? 256 : 0);
+ if (((_in === 0 && _out === 0) || flush === Z_FINISH) && ret === Z_OK) {
+ ret = Z_BUF_ERROR;
+ }
+ return ret;
+}
+
+function inflateEnd(strm) {
+
+ if (!strm || !strm.state /*|| strm->zfree == (free_func)0*/) {
+ return Z_STREAM_ERROR;
+ }
+
+ var state = strm.state;
+ if (state.window) {
+ state.window = null;
+ }
+ strm.state = null;
+ return Z_OK;
+}
+
+function inflateGetHeader(strm, head) {
+ var state;
+
+ /* check state */
+ if (!strm || !strm.state) { return Z_STREAM_ERROR; }
+ state = strm.state;
+ if ((state.wrap & 2) === 0) { return Z_STREAM_ERROR; }
+
+ /* save header structure */
+ state.head = head;
+ head.done = false;
+ return Z_OK;
+}
+
+
+exports.inflateReset = inflateReset;
+exports.inflateReset2 = inflateReset2;
+exports.inflateResetKeep = inflateResetKeep;
+exports.inflateInit = inflateInit;
+exports.inflateInit2 = inflateInit2;
+exports.inflate = inflate;
+exports.inflateEnd = inflateEnd;
+exports.inflateGetHeader = inflateGetHeader;
+exports.inflateInfo = 'pako inflate (from Nodeca project)';
+
+/* Not implemented
+exports.inflateCopy = inflateCopy;
+exports.inflateGetDictionary = inflateGetDictionary;
+exports.inflateMark = inflateMark;
+exports.inflatePrime = inflatePrime;
+exports.inflateSetDictionary = inflateSetDictionary;
+exports.inflateSync = inflateSync;
+exports.inflateSyncPoint = inflateSyncPoint;
+exports.inflateUndermine = inflateUndermine;
+*/
+},{"../utils/common":2,"./adler32":4,"./crc32":6,"./inffast":8,"./inftrees":10}],10:[function(_dereq_,module,exports){
+'use strict';
+
+
+var utils = _dereq_('../utils/common');
+
+var MAXBITS = 15;
+var ENOUGH_LENS = 852;
+var ENOUGH_DISTS = 592;
+//var ENOUGH = (ENOUGH_LENS+ENOUGH_DISTS);
+
+var CODES = 0;
+var LENS = 1;
+var DISTS = 2;
+
+var lbase = [ /* Length codes 257..285 base */
+ 3, 4, 5, 6, 7, 8, 9, 10, 11, 13, 15, 17, 19, 23, 27, 31,
+ 35, 43, 51, 59, 67, 83, 99, 115, 131, 163, 195, 227, 258, 0, 0
+];
+
+var lext = [ /* Length codes 257..285 extra */
+ 16, 16, 16, 16, 16, 16, 16, 16, 17, 17, 17, 17, 18, 18, 18, 18,
+ 19, 19, 19, 19, 20, 20, 20, 20, 21, 21, 21, 21, 16, 72, 78
+];
+
+var dbase = [ /* Distance codes 0..29 base */
+ 1, 2, 3, 4, 5, 7, 9, 13, 17, 25, 33, 49, 65, 97, 129, 193,
+ 257, 385, 513, 769, 1025, 1537, 2049, 3073, 4097, 6145,
+ 8193, 12289, 16385, 24577, 0, 0
+];
+
+var dext = [ /* Distance codes 0..29 extra */
+ 16, 16, 16, 16, 17, 17, 18, 18, 19, 19, 20, 20, 21, 21, 22, 22,
+ 23, 23, 24, 24, 25, 25, 26, 26, 27, 27,
+ 28, 28, 29, 29, 64, 64
+];
+
+module.exports = function inflate_table(type, lens, lens_index, codes, table, table_index, work, opts)
+{
+ var bits = opts.bits;
+ //here = opts.here; /* table entry for duplication */
+
+ var len = 0; /* a code's length in bits */
+ var sym = 0; /* index of code symbols */
+ var min = 0, max = 0; /* minimum and maximum code lengths */
+ var root = 0; /* number of index bits for root table */
+ var curr = 0; /* number of index bits for current table */
+ var drop = 0; /* code bits to drop for sub-table */
+ var left = 0; /* number of prefix codes available */
+ var used = 0; /* code entries in table used */
+ var huff = 0; /* Huffman code */
+ var incr; /* for incrementing code, index */
+ var fill; /* index for replicating entries */
+ var low; /* low bits for current root entry */
+ var mask; /* mask for low root bits */
+ var next; /* next available space in table */
+ var base = null; /* base value table to use */
+ var base_index = 0;
+// var shoextra; /* extra bits table to use */
+ var end; /* use base and extra for symbol > end */
+ var count = new utils.Buf16(MAXBITS+1); //[MAXBITS+1]; /* number of codes of each length */
+ var offs = new utils.Buf16(MAXBITS+1); //[MAXBITS+1]; /* offsets in table for each length */
+ var extra = null;
+ var extra_index = 0;
+
+ var here_bits, here_op, here_val;
+
+ /*
+ Process a set of code lengths to create a canonical Huffman code. The
+ code lengths are lens[0..codes-1]. Each length corresponds to the
+ symbols 0..codes-1. The Huffman code is generated by first sorting the
+ symbols by length from short to long, and retaining the symbol order
+ for codes with equal lengths. Then the code starts with all zero bits
+ for the first code of the shortest length, and the codes are integer
+ increments for the same length, and zeros are appended as the length
+ increases. For the deflate format, these bits are stored backwards
+ from their more natural integer increment ordering, and so when the
+ decoding tables are built in the large loop below, the integer codes
+ are incremented backwards.
+
+ This routine assumes, but does not check, that all of the entries in
+ lens[] are in the range 0..MAXBITS. The caller must assure this.
+ 1..MAXBITS is interpreted as that code length. zero means that that
+ symbol does not occur in this code.
+
+ The codes are sorted by computing a count of codes for each length,
+ creating from that a table of starting indices for each length in the
+ sorted table, and then entering the symbols in order in the sorted
+ table. The sorted table is work[], with that space being provided by
+ the caller.
+
+ The length counts are used for other purposes as well, i.e. finding
+ the minimum and maximum length codes, determining if there are any
+ codes at all, checking for a valid set of lengths, and looking ahead
+ at length counts to determine sub-table sizes when building the
+ decoding tables.
+ */
+
+ /* accumulate lengths for codes (assumes lens[] all in 0..MAXBITS) */
+ for (len = 0; len <= MAXBITS; len++) {
+ count[len] = 0;
+ }
+ for (sym = 0; sym < codes; sym++) {
+ count[lens[lens_index + sym]]++;
+ }
+
+ /* bound code lengths, force root to be within code lengths */
+ root = bits;
+ for (max = MAXBITS; max >= 1; max--) {
+ if (count[max] !== 0) { break; }
+ }
+ if (root > max) {
+ root = max;
+ }
+ if (max === 0) { /* no symbols to code at all */
+ //table.op[opts.table_index] = 64; //here.op = (var char)64; /* invalid code marker */
+ //table.bits[opts.table_index] = 1; //here.bits = (var char)1;
+ //table.val[opts.table_index++] = 0; //here.val = (var short)0;
+ table[table_index++] = (1 << 24) | (64 << 16) | 0;
+
+
+ //table.op[opts.table_index] = 64;
+ //table.bits[opts.table_index] = 1;
+ //table.val[opts.table_index++] = 0;
+ table[table_index++] = (1 << 24) | (64 << 16) | 0;
+
+ opts.bits = 1;
+ return 0; /* no symbols, but wait for decoding to report error */
+ }
+ for (min = 1; min < max; min++) {
+ if (count[min] !== 0) { break; }
+ }
+ if (root < min) {
+ root = min;
+ }
+
+ /* check for an over-subscribed or incomplete set of lengths */
+ left = 1;
+ for (len = 1; len <= MAXBITS; len++) {
+ left <<= 1;
+ left -= count[len];
+ if (left < 0) {
+ return -1;
+ } /* over-subscribed */
+ }
+ if (left > 0 && (type === CODES || max !== 1)) {
+ return -1; /* incomplete set */
+ }
+
+ /* generate offsets into symbol table for each length for sorting */
+ offs[1] = 0;
+ for (len = 1; len < MAXBITS; len++) {
+ offs[len + 1] = offs[len] + count[len];
+ }
+
+ /* sort symbols by length, by symbol order within each length */
+ for (sym = 0; sym < codes; sym++) {
+ if (lens[lens_index + sym] !== 0) {
+ work[offs[lens[lens_index + sym]]++] = sym;
+ }
+ }
+
+ /*
+ Create and fill in decoding tables. In this loop, the table being
+ filled is at next and has curr index bits. The code being used is huff
+ with length len. That code is converted to an index by dropping drop
+ bits off of the bottom. For codes where len is less than drop + curr,
+ those top drop + curr - len bits are incremented through all values to
+ fill the table with replicated entries.
+
+ root is the number of index bits for the root table. When len exceeds
+ root, sub-tables are created pointed to by the root entry with an index
+ of the low root bits of huff. This is saved in low to check for when a
+ new sub-table should be started. drop is zero when the root table is
+ being filled, and drop is root when sub-tables are being filled.
+
+ When a new sub-table is needed, it is necessary to look ahead in the
+ code lengths to determine what size sub-table is needed. The length
+ counts are used for this, and so count[] is decremented as codes are
+ entered in the tables.
+
+ used keeps track of how many table entries have been allocated from the
+ provided *table space. It is checked for LENS and DIST tables against
+ the constants ENOUGH_LENS and ENOUGH_DISTS to guard against changes in
+ the initial root table size constants. See the comments in inftrees.h
+ for more information.
+
+ sym increments through all symbols, and the loop terminates when
+ all codes of length max, i.e. all codes, have been processed. This
+ routine permits incomplete codes, so another loop after this one fills
+ in the rest of the decoding tables with invalid code markers.
+ */
+
+ /* set up for code type */
+ // poor man optimization - use if-else instead of switch,
+ // to avoid deopts in old v8
+ if (type === CODES) {
+ base = extra = work; /* dummy value--not used */
+ end = 19;
+ } else if (type === LENS) {
+ base = lbase;
+ base_index -= 257;
+ extra = lext;
+ extra_index -= 257;
+ end = 256;
+ } else { /* DISTS */
+ base = dbase;
+ extra = dext;
+ end = -1;
+ }
+
+ /* initialize opts for loop */
+ huff = 0; /* starting code */
+ sym = 0; /* starting code symbol */
+ len = min; /* starting code length */
+ next = table_index; /* current table to fill in */
+ curr = root; /* current table index bits */
+ drop = 0; /* current bits to drop from code for index */
+ low = -1; /* trigger new sub-table when len > root */
+ used = 1 << root; /* use root table entries */
+ mask = used - 1; /* mask for comparing low */
+
+ /* check available table space */
+ if ((type === LENS && used > ENOUGH_LENS) ||
+ (type === DISTS && used > ENOUGH_DISTS)) {
+ return 1;
+ }
+
+ var i=0;
+ /* process all codes and make table entries */
+ for (;;) {
+ i++;
+ /* create table entry */
+ here_bits = len - drop;
+ if (work[sym] < end) {
+ here_op = 0;
+ here_val = work[sym];
+ }
+ else if (work[sym] > end) {
+ here_op = extra[extra_index + work[sym]];
+ here_val = base[base_index + work[sym]];
+ }
+ else {
+ here_op = 32 + 64; /* end of block */
+ here_val = 0;
+ }
+
+ /* replicate for those indices with low len bits equal to huff */
+ incr = 1 << (len - drop);
+ fill = 1 << curr;
+ min = fill; /* save offset to next table */
+ do {
+ fill -= incr;
+ table[next + (huff >> drop) + fill] = (here_bits << 24) | (here_op << 16) | here_val |0;
+ } while (fill !== 0);
+
+ /* backwards increment the len-bit code huff */
+ incr = 1 << (len - 1);
+ while (huff & incr) {
+ incr >>= 1;
+ }
+ if (incr !== 0) {
+ huff &= incr - 1;
+ huff += incr;
+ } else {
+ huff = 0;
+ }
+
+ /* go to next symbol, update count, len */
+ sym++;
+ if (--count[len] === 0) {
+ if (len === max) { break; }
+ len = lens[lens_index + work[sym]];
+ }
+
+ /* create new sub-table if needed */
+ if (len > root && (huff & mask) !== low) {
+ /* if first time, transition to sub-tables */
+ if (drop === 0) {
+ drop = root;
+ }
+
+ /* increment past last table */
+ next += min; /* here min is 1 << curr */
+
+ /* determine length of next table */
+ curr = len - drop;
+ left = 1 << curr;
+ while (curr + drop < max) {
+ left -= count[curr + drop];
+ if (left <= 0) { break; }
+ curr++;
+ left <<= 1;
+ }
+
+ /* check for enough space */
+ used += 1 << curr;
+ if ((type === LENS && used > ENOUGH_LENS) ||
+ (type === DISTS && used > ENOUGH_DISTS)) {
+ return 1;
+ }
+
+ /* point entry in root table to sub-table */
+ low = huff & mask;
+ /*table.op[low] = curr;
+ table.bits[low] = root;
+ table.val[low] = next - opts.table_index;*/
+ table[low] = (root << 24) | (curr << 16) | (next - table_index) |0;
+ }
+ }
+
+ /* fill in remaining table entry if code is incomplete (guaranteed to have
+ at most one remaining entry, since if the code is incomplete, the
+ maximum code length that was allowed to get this far is one bit) */
+ if (huff !== 0) {
+ //table.op[next + huff] = 64; /* invalid code marker */
+ //table.bits[next + huff] = len - drop;
+ //table.val[next + huff] = 0;
+ table[next + huff] = ((len - drop) << 24) | (64 << 16) |0;
+ }
+
+ /* set return parameters */
+ //opts.table_index += used;
+ opts.bits = root;
+ return 0;
+};
+
+},{"../utils/common":2}],11:[function(_dereq_,module,exports){
+'use strict';
+
+module.exports = {
+ '2': 'need dictionary', /* Z_NEED_DICT 2 */
+ '1': 'stream end', /* Z_STREAM_END 1 */
+ '0': '', /* Z_OK 0 */
+ '-1': 'file error', /* Z_ERRNO (-1) */
+ '-2': 'stream error', /* Z_STREAM_ERROR (-2) */
+ '-3': 'data error', /* Z_DATA_ERROR (-3) */
+ '-4': 'insufficient memory', /* Z_MEM_ERROR (-4) */
+ '-5': 'buffer error', /* Z_BUF_ERROR (-5) */
+ '-6': 'incompatible version' /* Z_VERSION_ERROR (-6) */
+};
+},{}],12:[function(_dereq_,module,exports){
+'use strict';
+
+
+function ZStream() {
+ /* next input byte */
+ this.input = null; // JS specific, because we have no pointers
+ this.next_in = 0;
+ /* number of bytes available at input */
+ this.avail_in = 0;
+ /* total number of input bytes read so far */
+ this.total_in = 0;
+ /* next output byte should be put there */
+ this.output = null; // JS specific, because we have no pointers
+ this.next_out = 0;
+ /* remaining free space at output */
+ this.avail_out = 0;
+ /* total number of bytes output so far */
+ this.total_out = 0;
+ /* last error message, NULL if no error */
+ this.msg = ''/*Z_NULL*/;
+ /* not visible by applications */
+ this.state = null;
+ /* best guess about the data type: binary or text */
+ this.data_type = 2/*Z_UNKNOWN*/;
+ /* adler32 value of the uncompressed data */
+ this.adler = 0;
+}
+
+module.exports = ZStream;
+},{}]},{},[1])
+(1)
+});
\ No newline at end of file
Modified: trunk/packages/orthanc-webviewer/trunk/debian/control
===================================================================
--- trunk/packages/orthanc-webviewer/trunk/debian/control 2015-03-01 17:40:57 UTC (rev 18889)
+++ trunk/packages/orthanc-webviewer/trunk/debian/control 2015-03-02 09:58:59 UTC (rev 18890)
@@ -8,12 +8,13 @@
Build-Depends: cmake (>= 2.8),
debhelper (>= 9),
unzip,
+ yui-compressor,
libboost-all-dev (>= 1.54.0-5),
libgdcm2-dev,
libgtest-dev (>= 1.6.0),
+ libjpeg-dev,
libjs-jquery-ui,
libjs-jquery-ui-theme-base,
- libjpeg-dev,
libjsoncpp-dev,
liborthancclient-dev (>= 0.8.6),
libpng-dev,
Deleted: trunk/packages/orthanc-webviewer/trunk/debian/patches/debian-jquery-ui
===================================================================
--- trunk/packages/orthanc-webviewer/trunk/debian/patches/debian-jquery-ui 2015-03-01 17:40:57 UTC (rev 18889)
+++ trunk/packages/orthanc-webviewer/trunk/debian/patches/debian-jquery-ui 2015-03-02 09:58:59 UTC (rev 18890)
@@ -1,40 +0,0 @@
-Description: Patch to use the Debian version of jquery and jquery-ui
-Author: Sebastien Jodogne <s.jodogne at gmail.com>
----
-This patch header follows DEP-3: http://dep.debian.net/deps/dep3/
-Index: OrthancWebViewer-1.0/Resources/CMake/JavaScriptLibraries.cmake
-===================================================================
---- OrthancWebViewer-1.0.orig/Resources/CMake/JavaScriptLibraries.cmake 2015-02-26 17:25:35.000000000 +0100
-+++ OrthancWebViewer-1.0/Resources/CMake/JavaScriptLibraries.cmake 2015-02-27 10:37:31.358149479 +0100
-@@ -23,10 +23,10 @@
- "${BASE_URL}/cornerstone-0.7.1.zip"
- "cornerstone-0.7.1")
-
--DownloadPackage(
-- "cb943ac26be9ee755e8741ea232389e2"
-- "${BASE_URL}/jquery-ui-1.11.3.zip"
-- "jquery-ui-1.11.3")
-+#DownloadPackage(
-+# "cb943ac26be9ee755e8741ea232389e2"
-+# "${BASE_URL}/jquery-ui-1.11.3.zip"
-+# "jquery-ui-1.11.3")
-
- DownloadPackage(
- "8f27231a78218b959159e37daa3d86b3"
-@@ -50,11 +50,11 @@
- file(COPY
- ${CMAKE_CURRENT_BINARY_DIR}/cornerstone-0.7.1/dist/cornerstone.min.css
- ${CMAKE_CURRENT_BINARY_DIR}/cornerstone-0.7.1/dist/cornerstone.min.js
-- ${CMAKE_CURRENT_BINARY_DIR}/jquery-ui-1.11.3/external/jquery/jquery.js
-- ${CMAKE_CURRENT_BINARY_DIR}/jquery-ui-1.11.3/images
-- ${CMAKE_CURRENT_BINARY_DIR}/jquery-ui-1.11.3/jquery-ui.min.css
-- ${CMAKE_CURRENT_BINARY_DIR}/jquery-ui-1.11.3/jquery-ui.min.js
-- ${CMAKE_CURRENT_BINARY_DIR}/jquery-ui-1.11.3/jquery-ui.theme.min.css
-+# ${CMAKE_CURRENT_BINARY_DIR}/jquery-ui-1.11.3/external/jquery/jquery.js
-+# ${CMAKE_CURRENT_BINARY_DIR}/jquery-ui-1.11.3/images
-+# ${CMAKE_CURRENT_BINARY_DIR}/jquery-ui-1.11.3/jquery-ui.min.css
-+# ${CMAKE_CURRENT_BINARY_DIR}/jquery-ui-1.11.3/jquery-ui.min.js
-+# ${CMAKE_CURRENT_BINARY_DIR}/jquery-ui-1.11.3/jquery-ui.theme.min.css
- ${CMAKE_CURRENT_BINARY_DIR}/js-url-1.8.6/url.min.js
- ${CMAKE_CURRENT_BINARY_DIR}/jspanel/fonts
- ${CMAKE_CURRENT_BINARY_DIR}/jspanel/images
Added: trunk/packages/orthanc-webviewer/trunk/debian/patches/javascript-libs
===================================================================
--- trunk/packages/orthanc-webviewer/trunk/debian/patches/javascript-libs (rev 0)
+++ trunk/packages/orthanc-webviewer/trunk/debian/patches/javascript-libs 2015-03-02 09:58:59 UTC (rev 18890)
@@ -0,0 +1,18 @@
+Description: Patch to manually provide the JavaScript libraries
+Author: Sebastien Jodogne <s.jodogne at gmail.com>
+---
+This patch header follows DEP-3: http://dep.debian.net/deps/dep3/
+Index: OrthancWebViewer-1.0/CMakeLists.txt
+===================================================================
+--- OrthancWebViewer-1.0.orig/CMakeLists.txt 2015-02-27 12:59:40.000000000 +0100
++++ OrthancWebViewer-1.0/CMakeLists.txt 2015-03-02 10:55:22.463574790 +0100
+@@ -80,7 +80,8 @@
+ include(${CMAKE_SOURCE_DIR}/Resources/CMake/ZlibConfiguration.cmake)
+ include(${CMAKE_SOURCE_DIR}/Resources/CMake/SQLiteConfiguration.cmake)
+
+-include(${CMAKE_SOURCE_DIR}/Resources/CMake/JavaScriptLibraries.cmake)
++#include(${CMAKE_SOURCE_DIR}/Resources/CMake/JavaScriptLibraries.cmake)
++set(JAVASCRIPT_LIBS_DIR ${CMAKE_CURRENT_BINARY_DIR}/javascript-libs/)
+
+
+ # Check that the Orthanc SDK headers are available or download them
Modified: trunk/packages/orthanc-webviewer/trunk/debian/patches/series
===================================================================
--- trunk/packages/orthanc-webviewer/trunk/debian/patches/series 2015-03-01 17:40:57 UTC (rev 18889)
+++ trunk/packages/orthanc-webviewer/trunk/debian/patches/series 2015-03-02 09:58:59 UTC (rev 18890)
@@ -1,3 +1,3 @@
-debian-jquery-ui
+javascript-libs
jquery
shlibs
Modified: trunk/packages/orthanc-webviewer/trunk/debian/rules
===================================================================
--- trunk/packages/orthanc-webviewer/trunk/debian/rules 2015-03-01 17:40:57 UTC (rev 18889)
+++ trunk/packages/orthanc-webviewer/trunk/debian/rules 2015-03-02 09:58:59 UTC (rev 18890)
@@ -16,18 +16,40 @@
-DCMAKE_BUILD_TYPE="" # The build type must be left empty, see #711515
override_dh_auto_configure:
- # Put 3rd party packages where the cmake build system expects them
- mkdir -p ThirdPartyDownloads
- ( cd ThirdPartyDownloads; cp ../debian/ThirdPartyDownloads/* . )
+ mkdir -p ${JAVASCRIPT_LIBS}/fonts
+ mkdir -p ${JAVASCRIPT_LIBS}/images
# Place the jquery and jquery-ui libraries from Debian
- mkdir -p ${JAVASCRIPT_LIBS}/images
cp /usr/share/javascript/jquery/jquery.min.js ${JAVASCRIPT_LIBS}/jquery.js
cp /usr/share/javascript/jquery-ui/jquery-ui.min.js ${JAVASCRIPT_LIBS}
cp /usr/share/javascript/jquery-ui-themes/base/jquery-ui.min.css ${JAVASCRIPT_LIBS}
cp /usr/share/javascript/jquery-ui-themes/base/images/* ${JAVASCRIPT_LIBS}/images
touch ${JAVASCRIPT_LIBS}/jquery-ui.theme.min.css
+ # Place the third-party JavaScript libraries at the location
+ # expected by CMake
+ yui-compressor debian/JS/cornerstone-0.7.1/cornerstone.js > \
+ ${JAVASCRIPT_LIBS}/cornerstone.min.js
+ yui-compressor debian/JS/cornerstone-0.7.1/cornerstone.css > \
+ ${JAVASCRIPT_LIBS}/cornerstone.min.css
+
+ yui-compressor debian/JS/jsPanel-2.3.3/jquery.jspanel.js > \
+ ${JAVASCRIPT_LIBS}/jquery.jspanel.min.js
+ yui-compressor debian/JS/jsPanel-2.3.3/jquery.jspanel.css > \
+ ${JAVASCRIPT_LIBS}/jquery.jspanel.min.css
+ yui-compressor debian/JS/jsPanel-2.3.3/jquery.ui.touch-punch.js > \
+ ${JAVASCRIPT_LIBS}/jquery.ui.touch-punch.min.js
+ yui-compressor debian/JS/jsPanel-2.3.3/mobile-detect.js > \
+ ${JAVASCRIPT_LIBS}/mobile-detect.min.js
+ cp debian/JS/jsPanel-2.3.3/images/* ${JAVASCRIPT_LIBS}/images/
+ cp debian/JS/jsPanel-2.3.3/fonts/* ${JAVASCRIPT_LIBS}/fonts/
+
+ yui-compressor debian/JS/js-url-1.8.6/url.js > \
+ ${JAVASCRIPT_LIBS}/url.min.js
+
+ yui-compressor debian/JS/pako-0.2.5/pako_inflate.js > \
+ ${JAVASCRIPT_LIBS}/pako_inflate.min.js
+
# Launch the original CMake script
dh_auto_configure -- $(CMAKE_EXTRA_FLAGS)
Modified: trunk/packages/orthanc-webviewer/trunk/debian/source/include-binaries
===================================================================
--- trunk/packages/orthanc-webviewer/trunk/debian/source/include-binaries 2015-03-01 17:40:57 UTC (rev 18889)
+++ trunk/packages/orthanc-webviewer/trunk/debian/source/include-binaries 2015-03-02 09:58:59 UTC (rev 18890)
@@ -1,4 +1,11 @@
-debian/ThirdPartyDownloads/pako-0.2.5.zip
-debian/ThirdPartyDownloads/cornerstone-0.7.1.zip
-debian/ThirdPartyDownloads/js-url-1.8.6.zip
-debian/ThirdPartyDownloads/jsPanel-2.3.3.zip
+debian/JS/jsPanel-2.3.3/fonts/jsglyph.ttf
+debian/JS/jsPanel-2.3.3/fonts/jsglyph.eot
+debian/JS/jsPanel-2.3.3/fonts/jsglyph.woff2
+debian/JS/jsPanel-2.3.3/fonts/jsglyph.woff
+debian/JS/jsPanel-2.3.3/images/ui-icons_454545_256x240.png
+debian/JS/jsPanel-2.3.3/images/resize-handle.png
+debian/JS/jsPanel-2.3.3/images/close-20-333.png
+debian/JS/jsPanel-2.3.3/images/close-20.png
+debian/JS/jsPanel-2.3.3/images/icon-sprite-20x20.jpg
+debian/JS/jsPanel-2.3.3/images/icon-sprite-32x32.jpg
+debian/JS/jsPanel-2.3.3/images/icon-sprite-16x16.jpg
More information about the debian-med-commit
mailing list