summaryrefslogtreecommitdiffstats
path: root/debian/missing-sources
diff options
context:
space:
mode:
Diffstat (limited to 'debian/missing-sources')
-rw-r--r--debian/missing-sources/README98
-rw-r--r--debian/missing-sources/backbone.js1571
-rw-r--r--debian/missing-sources/iris.js1507
-rw-r--r--debian/missing-sources/jquery-ui/jquery-ui.js15003
-rw-r--r--debian/missing-sources/jquery-ui/jquery.ui.accordion.js572
-rw-r--r--debian/missing-sources/jquery-ui/jquery.ui.autocomplete.js610
-rw-r--r--debian/missing-sources/jquery-ui/jquery.ui.button.js419
-rw-r--r--debian/missing-sources/jquery-ui/jquery.ui.core.js320
-rw-r--r--debian/missing-sources/jquery-ui/jquery.ui.datepicker.js2038
-rw-r--r--debian/missing-sources/jquery-ui/jquery.ui.dialog.js808
-rw-r--r--debian/missing-sources/jquery-ui/jquery.ui.draggable.js958
-rw-r--r--debian/missing-sources/jquery-ui/jquery.ui.droppable.js372
-rw-r--r--debian/missing-sources/jquery-ui/jquery.ui.effect-blind.js82
-rw-r--r--debian/missing-sources/jquery-ui/jquery.ui.effect-bounce.js113
-rw-r--r--debian/missing-sources/jquery-ui/jquery.ui.effect-clip.js67
-rw-r--r--debian/missing-sources/jquery-ui/jquery.ui.effect-drop.js65
-rw-r--r--debian/missing-sources/jquery-ui/jquery.ui.effect-explode.js97
-rw-r--r--debian/missing-sources/jquery-ui/jquery.ui.effect-fade.js30
-rw-r--r--debian/missing-sources/jquery-ui/jquery.ui.effect-fold.js76
-rw-r--r--debian/missing-sources/jquery-ui/jquery.ui.effect-highlight.js50
-rw-r--r--debian/missing-sources/jquery-ui/jquery.ui.effect-pulsate.js63
-rw-r--r--debian/missing-sources/jquery-ui/jquery.ui.effect-scale.js318
-rw-r--r--debian/missing-sources/jquery-ui/jquery.ui.effect-shake.js74
-rw-r--r--debian/missing-sources/jquery-ui/jquery.ui.effect-slide.js64
-rw-r--r--debian/missing-sources/jquery-ui/jquery.ui.effect-transfer.js47
-rw-r--r--debian/missing-sources/jquery-ui/jquery.ui.effect.js1289
-rw-r--r--debian/missing-sources/jquery-ui/jquery.ui.menu.js621
-rw-r--r--debian/missing-sources/jquery-ui/jquery.ui.mouse.js169
-rw-r--r--debian/missing-sources/jquery-ui/jquery.ui.position.js497
-rw-r--r--debian/missing-sources/jquery-ui/jquery.ui.progressbar.js145
-rw-r--r--debian/missing-sources/jquery-ui/jquery.ui.resizable.js968
-rw-r--r--debian/missing-sources/jquery-ui/jquery.ui.selectable.js277
-rw-r--r--debian/missing-sources/jquery-ui/jquery.ui.slider.js672
-rw-r--r--debian/missing-sources/jquery-ui/jquery.ui.sortable.js1285
-rw-r--r--debian/missing-sources/jquery-ui/jquery.ui.spinner.js493
-rw-r--r--debian/missing-sources/jquery-ui/jquery.ui.tabs.js846
-rw-r--r--debian/missing-sources/jquery-ui/jquery.ui.tooltip.js402
-rw-r--r--debian/missing-sources/jquery-ui/jquery.ui.widget.js521
-rw-r--r--debian/missing-sources/jquery.color.js663
-rw-r--r--debian/missing-sources/jquery.js9789
-rw-r--r--debian/missing-sources/jquery.masonry.js499
-rw-r--r--debian/missing-sources/jquery.query.js224
-rw-r--r--debian/missing-sources/jquery.schedule.js708
-rw-r--r--debian/missing-sources/jquery.ui.touch-punch.js160
-rw-r--r--debian/missing-sources/jsCropperUI-1.2.0.tar.gzbin0 -> 171710 bytes
-rw-r--r--debian/missing-sources/mediaelement/README.md681
-rw-r--r--debian/missing-sources/mediaelement/src/FlashMediaElement.as1080
-rw-r--r--debian/missing-sources/mediaelement/src/FlashMediaElement.flabin0 -> 26182 bytes
-rw-r--r--debian/missing-sources/mediaelement/src/HtmlMediaEvent.as29
-rw-r--r--debian/missing-sources/mediaelement/src/htmlelements/AudioElement.as332
-rw-r--r--debian/missing-sources/mediaelement/src/htmlelements/IMediaElement.as35
-rw-r--r--debian/missing-sources/mediaelement/src/htmlelements/VideoElement.as1
-rw-r--r--debian/missing-sources/mediaelement/src/htmlelements/YouTubeElement.as403
-rw-r--r--debian/missing-sources/mediaelement/test/Spec-CreateRemove.js45
-rw-r--r--debian/missing-sources/mediaelement/test/Spec-Player.js90
-rw-r--r--debian/missing-sources/mediaelement/test/SpecRunner-CreateRemove.html78
-rw-r--r--debian/missing-sources/mediaelement/test/SpecRunner-Player.html78
-rw-r--r--debian/missing-sources/mediaelement/test/lib/jasmine-1.3.1/MIT.LICENSE20
-rw-r--r--debian/missing-sources/mediaelement/test/lib/jasmine-1.3.1/jasmine-html.js681
-rw-r--r--debian/missing-sources/mediaelement/test/lib/jasmine-1.3.1/jasmine.css82
-rw-r--r--debian/missing-sources/mediaelement/test/lib/jasmine-1.3.1/jasmine.js2600
-rw-r--r--debian/missing-sources/mediaelement/test/test.html237
-rw-r--r--debian/missing-sources/plupload/csharp/Plupload/App.xaml8
-rw-r--r--debian/missing-sources/plupload/csharp/Plupload/App.xaml.cs45
-rw-r--r--debian/missing-sources/plupload/csharp/Plupload/FJCore/DCT.cs222
-rw-r--r--debian/missing-sources/plupload/csharp/Plupload/FJCore/DecodedJpeg.cs121
-rw-r--r--debian/missing-sources/plupload/csharp/Plupload/FJCore/Decoder/HuffmanTable.cs487
-rw-r--r--debian/missing-sources/plupload/csharp/Plupload/FJCore/Decoder/JpegComponent.cs702
-rw-r--r--debian/missing-sources/plupload/csharp/Plupload/FJCore/Decoder/JpegDecoder.cs614
-rw-r--r--debian/missing-sources/plupload/csharp/Plupload/FJCore/Decoder/JpegFrame.cs283
-rw-r--r--debian/missing-sources/plupload/csharp/Plupload/FJCore/Decoder/JpegHuffmanTable.cs183
-rw-r--r--debian/missing-sources/plupload/csharp/Plupload/FJCore/Decoder/JpegQuantizationTable.cs116
-rw-r--r--debian/missing-sources/plupload/csharp/Plupload/FJCore/Decoder/JpegScan.cs37
-rw-r--r--debian/missing-sources/plupload/csharp/Plupload/FJCore/Encoder/JpegEncoder.cs327
-rw-r--r--debian/missing-sources/plupload/csharp/Plupload/FJCore/FDCT.cs201
-rw-r--r--debian/missing-sources/plupload/csharp/Plupload/FJCore/Filter/Convolution.cs404
-rw-r--r--debian/missing-sources/plupload/csharp/Plupload/FJCore/Filter/FilterBase.cs47
-rw-r--r--debian/missing-sources/plupload/csharp/Plupload/FJCore/Filter/FilterLowpassResize.cs44
-rw-r--r--debian/missing-sources/plupload/csharp/Plupload/FJCore/Filter/FilterNNResize.cs47
-rw-r--r--debian/missing-sources/plupload/csharp/Plupload/FJCore/Filter/GrayImage.cs77
-rw-r--r--debian/missing-sources/plupload/csharp/Plupload/FJCore/IJG.txt90
-rw-r--r--debian/missing-sources/plupload/csharp/Plupload/FJCore/IO/BinaryReader.cs46
-rw-r--r--debian/missing-sources/plupload/csharp/Plupload/FJCore/IO/BinaryWriter.cs45
-rw-r--r--debian/missing-sources/plupload/csharp/Plupload/FJCore/IO/JpegBinaryReader.cs117
-rw-r--r--debian/missing-sources/plupload/csharp/Plupload/FJCore/Image.cs183
-rw-r--r--debian/missing-sources/plupload/csharp/Plupload/FJCore/JAI.txt40
-rw-r--r--debian/missing-sources/plupload/csharp/Plupload/FJCore/JpegMarker.cs128
-rw-r--r--debian/missing-sources/plupload/csharp/Plupload/FJCore/License.txt24
-rw-r--r--debian/missing-sources/plupload/csharp/Plupload/FJCore/README.txt30
-rw-r--r--debian/missing-sources/plupload/csharp/Plupload/FJCore/Resize/ImageResizer.cs98
-rw-r--r--debian/missing-sources/plupload/csharp/Plupload/FJCore/YCbCr.cs59
-rw-r--r--debian/missing-sources/plupload/csharp/Plupload/FJCore/ZigZag.cs65
-rw-r--r--debian/missing-sources/plupload/csharp/Plupload/FileReference.cs721
-rw-r--r--debian/missing-sources/plupload/csharp/Plupload/Page.xaml7
-rw-r--r--debian/missing-sources/plupload/csharp/Plupload/Page.xaml.cs230
-rw-r--r--debian/missing-sources/plupload/csharp/Plupload/Plupload.csproj222
-rw-r--r--debian/missing-sources/plupload/csharp/Plupload/Plupload.sln20
-rw-r--r--debian/missing-sources/plupload/csharp/Plupload/PngEncoder/Adler32.cs216
-rw-r--r--debian/missing-sources/plupload/csharp/Plupload/PngEncoder/CRC32.cs213
-rw-r--r--debian/missing-sources/plupload/csharp/Plupload/PngEncoder/Deflater.cs543
-rw-r--r--debian/missing-sources/plupload/csharp/Plupload/PngEncoder/DeflaterConstants.cs184
-rw-r--r--debian/missing-sources/plupload/csharp/Plupload/PngEncoder/DeflaterEngine.cs832
-rw-r--r--debian/missing-sources/plupload/csharp/Plupload/PngEncoder/DeflaterHuffman.cs881
-rw-r--r--debian/missing-sources/plupload/csharp/Plupload/PngEncoder/DeflaterOutputStream.cs469
-rw-r--r--debian/missing-sources/plupload/csharp/Plupload/PngEncoder/DeflaterPending.cs55
-rw-r--r--debian/missing-sources/plupload/csharp/Plupload/PngEncoder/IChecksum.cs90
-rw-r--r--debian/missing-sources/plupload/csharp/Plupload/PngEncoder/PendingBuffer.cs281
-rw-r--r--debian/missing-sources/plupload/csharp/Plupload/PngEncoder/PngEncoder.cs467
-rw-r--r--debian/missing-sources/plupload/csharp/Plupload/Properties/AppManifest.xml6
-rw-r--r--debian/missing-sources/plupload/csharp/Plupload/Properties/AssemblyInfo.cs45
-rw-r--r--debian/missing-sources/plupload/csharp/Plupload/Utils/JsonReader.cs486
-rw-r--r--debian/missing-sources/plupload/flash/plupload/Plupload.as3proj85
-rwxr-xr-xdebian/missing-sources/plupload/flash/plupload/build.sh21
-rw-r--r--debian/missing-sources/plupload/flash/plupload/build.vbs83
-rw-r--r--debian/missing-sources/plupload/flash/plupload/exec.bat13
-rw-r--r--debian/missing-sources/plupload/flash/plupload/src/com/formatlos/BitmapDataUnlimited.as254
-rw-r--r--debian/missing-sources/plupload/flash/plupload/src/com/formatlos/Gif.as197
-rw-r--r--debian/missing-sources/plupload/flash/plupload/src/com/formatlos/events/BitmapDataUnlimitedEvent.as1
-rw-r--r--debian/missing-sources/plupload/flash/plupload/src/com/mxi/BinaryReader.as92
-rw-r--r--debian/missing-sources/plupload/flash/plupload/src/com/mxi/CleanEventDispatcher.as42
-rw-r--r--debian/missing-sources/plupload/flash/plupload/src/com/mxi/image/ExifParser.as417
-rw-r--r--debian/missing-sources/plupload/flash/plupload/src/com/mxi/image/Image.as216
-rw-r--r--debian/missing-sources/plupload/flash/plupload/src/com/mxi/image/JPEG.as186
-rw-r--r--debian/missing-sources/plupload/flash/plupload/src/com/mxi/image/PNG.as77
-rw-r--r--debian/missing-sources/plupload/flash/plupload/src/com/mxi/image/events/ExifParserEvent.as29
-rw-r--r--debian/missing-sources/plupload/flash/plupload/src/com/mxi/image/events/ImageEvent.as36
-rw-r--r--debian/missing-sources/plupload/flash/plupload/src/com/plupload/File.as499
-rw-r--r--debian/missing-sources/plupload/flash/plupload/src/com/plupload/Plupload.as413
-rw-r--r--debian/missing-sources/plupload/flash/plupload/src/com/plupload/UploadChunkEvent.as56
-rw-r--r--debian/missing-sources/plupload/javascript/i18n/cs.js14
-rw-r--r--debian/missing-sources/plupload/javascript/i18n/da.js12
-rw-r--r--debian/missing-sources/plupload/javascript/i18n/de.js24
-rw-r--r--debian/missing-sources/plupload/javascript/i18n/el.js14
-rw-r--r--debian/missing-sources/plupload/javascript/i18n/es.js25
-rw-r--r--debian/missing-sources/plupload/javascript/i18n/et.js33
-rw-r--r--debian/missing-sources/plupload/javascript/i18n/fa.js37
-rw-r--r--debian/missing-sources/plupload/javascript/i18n/fi.js33
-rw-r--r--debian/missing-sources/plupload/javascript/i18n/fr-ca.js35
-rw-r--r--debian/missing-sources/plupload/javascript/i18n/fr.js25
-rw-r--r--debian/missing-sources/plupload/javascript/i18n/hr.js25
-rw-r--r--debian/missing-sources/plupload/javascript/i18n/hu.js33
-rw-r--r--debian/missing-sources/plupload/javascript/i18n/it.js24
-rw-r--r--debian/missing-sources/plupload/javascript/i18n/ja.js37
-rw-r--r--debian/missing-sources/plupload/javascript/i18n/ko.js36
-rw-r--r--debian/missing-sources/plupload/javascript/i18n/lv.js33
-rw-r--r--debian/missing-sources/plupload/javascript/i18n/nl.js21
-rw-r--r--debian/missing-sources/plupload/javascript/i18n/pl.js24
-rw-r--r--debian/missing-sources/plupload/javascript/i18n/pt-br.js35
-rw-r--r--debian/missing-sources/plupload/javascript/i18n/ro.js24
-rw-r--r--debian/missing-sources/plupload/javascript/i18n/ru.js21
-rw-r--r--debian/missing-sources/plupload/javascript/i18n/sk.js25
-rw-r--r--debian/missing-sources/plupload/javascript/i18n/sr.js14
-rw-r--r--debian/missing-sources/plupload/javascript/i18n/sv.js12
-rw-r--r--debian/missing-sources/plupload/javascript/jquery.plupload.queue/css/jquery.plupload.queue.css177
-rw-r--r--debian/missing-sources/plupload/javascript/jquery.plupload.queue/img/backgrounds.gifbin0 -> 2977 bytes
-rw-r--r--debian/missing-sources/plupload/javascript/jquery.plupload.queue/img/buttons-disabled.pngbin0 -> 1292 bytes
-rw-r--r--debian/missing-sources/plupload/javascript/jquery.plupload.queue/img/buttons.pngbin0 -> 1439 bytes
-rw-r--r--debian/missing-sources/plupload/javascript/jquery.plupload.queue/img/delete.gifbin0 -> 180 bytes
-rw-r--r--debian/missing-sources/plupload/javascript/jquery.plupload.queue/img/done.gifbin0 -> 1024 bytes
-rw-r--r--debian/missing-sources/plupload/javascript/jquery.plupload.queue/img/error.gifbin0 -> 994 bytes
-rw-r--r--debian/missing-sources/plupload/javascript/jquery.plupload.queue/img/throbber.gifbin0 -> 1922 bytes
-rw-r--r--debian/missing-sources/plupload/javascript/jquery.plupload.queue/img/transp50.pngbin0 -> 399 bytes
-rw-r--r--debian/missing-sources/plupload/javascript/jquery.plupload.queue/jquery.plupload.queue.js336
-rw-r--r--debian/missing-sources/plupload/javascript/jquery.ui.plupload/css/jquery.ui.plupload.css147
-rw-r--r--debian/missing-sources/plupload/javascript/jquery.ui.plupload/img/plupload-bw.pngbin0 -> 2105 bytes
-rw-r--r--debian/missing-sources/plupload/javascript/jquery.ui.plupload/img/plupload.pngbin0 -> 3641 bytes
-rw-r--r--debian/missing-sources/plupload/javascript/jquery.ui.plupload/jquery.ui.plupload.js754
-rw-r--r--debian/missing-sources/plupload/javascript/plupload.browserplus.js361
-rw-r--r--debian/missing-sources/plupload/javascript/plupload.flash.js431
-rw-r--r--debian/missing-sources/plupload/javascript/plupload.gears.js446
-rw-r--r--debian/missing-sources/plupload/javascript/plupload.html4.js430
-rw-r--r--debian/missing-sources/plupload/javascript/plupload.html5.js1525
-rw-r--r--debian/missing-sources/plupload/javascript/plupload.js1774
-rw-r--r--debian/missing-sources/plupload/javascript/plupload.silverlight.js447
-rw-r--r--debian/missing-sources/revisions-js-dev.php159
-rw-r--r--debian/missing-sources/swfobject.js777
-rw-r--r--debian/missing-sources/swfupload/Core Changelog.txt283
-rw-r--r--debian/missing-sources/swfupload/Documentation/index.html1181
-rw-r--r--debian/missing-sources/swfupload/Flash/ExternalCall.as121
-rw-r--r--debian/missing-sources/swfupload/Flash/FileItem.as112
-rw-r--r--debian/missing-sources/swfupload/Flash/SWFUpload v2.as3proj79
-rw-r--r--debian/missing-sources/swfupload/Flash/SWFUpload.as1519
-rw-r--r--debian/missing-sources/swfupload/Flash/deploy.bat3
-rw-r--r--debian/missing-sources/swfupload/Flash/obj/SWFUpload-v2Config.old22
-rw-r--r--debian/missing-sources/swfupload/Flash/obj/SWFUpload-v2Config.xml22
-rw-r--r--debian/missing-sources/swfupload/Flash/swfupload.swfbin0 -> 12787 bytes
-rw-r--r--debian/missing-sources/swfupload/plugins/SWFObject License.txt4
-rw-r--r--debian/missing-sources/swfupload/plugins/swfupload.cookies.js53
-rw-r--r--debian/missing-sources/swfupload/plugins/swfupload.queue.js98
-rw-r--r--debian/missing-sources/swfupload/plugins/swfupload.speed.js342
-rw-r--r--debian/missing-sources/swfupload/plugins/swfupload.swfobject.js111
-rw-r--r--debian/missing-sources/swfupload/swfupload license.txt12
-rw-r--r--debian/missing-sources/swfupload/swfupload.js980
-rw-r--r--debian/missing-sources/tinymce-4.3.10.tar.gzbin0 -> 919374 bytes
-rw-r--r--debian/missing-sources/underscore.js1226
195 files changed, 80245 insertions, 0 deletions
diff --git a/debian/missing-sources/README b/debian/missing-sources/README
new file mode 100644
index 0000000..82c38fc
--- /dev/null
+++ b/debian/missing-sources/README
@@ -0,0 +1,98 @@
+Missing source files
+--------------------
+
+WordPress ships a tar.gz ready to use that embeds many minified javascript
+libraries as well as several compiled Flash files. The GPL requires you
+to provide the corresponding source code. WordPress complies to this
+through the page at http://wordpress.org/download/source/.
+
+For Debian this is not really acceptable so instead we bundle all the
+missing source files in this directory. They have been grabbed from the
+above page (when it was up-to-date) or directly from the various upstream
+projects.
+
+Last synchronization was made with SVN revision 304 of
+http://code.trac.wordpress.org/browser/wordpress-sources
+
+Files: wp-admin/js/iris.min.js
+Project: Iris v1.0.4
+Source: https://raw.githubusercontent.com/Automattic/Iris/1.0.4/dist/iris.js
+
+Files: wp-includes/js/crop/cropper.js
+Project: Cropper-UI 1.2.0
+Comment: The minified file has been patched in changeset 4768 so it's
+ really its own source in truth.
+ http://core.trac.wordpress.org/changeset/4768/trunk/wp-includes/js/crop/cropper.js
+URL: http://www.defusion.org.uk/downloads/code/jsCropperUI-1.2.0.tar.gz
+Source: jsCropperUI-1.2.0.tar.gz
+
+Files: wp-includes/js/swfupload/swfupload.swf
+Project: SWFUpload 2.2.0
+URL: http://code.svn.wordpress.org/wordpress-sources/swfupload/swfupload-2.2.0.1/
+Source: swfupload-2.2.0.1
+
+Files: wp-includes/js/swfobject.js
+Project: SWFObject 2.2
+URL: http://code.svn.wordpress.org/wordpress-sources/swfobject/swfobject-2.2-r402.js
+Source: swfobject-2.2-r402.js
+
+Files: wp-includes/js/jquery/jquery.js
+Project: jQuery 1.10.2
+URL: http://code.svn.wordpress.org/wordpress-sources/jquery/jquery-1.10.2.js
+Source: jquery-1.10.2.js
+
+Files: wp-includes/js/jquery/jquery.color.min.js
+Project: jQuery Color Animations v2.1.1
+URL: http://code.svn.wordpress.org/wordpress-sources/jquery-plugins/jquery.color-2.1.1.js
+Source: jquery.color.js
+
+Files: wp-includes/js/jquery/jquery.query.js
+Project: jQuery.jquery 2.1.7
+URL: http://code.svn.wordpress.org/wordpress-sources/jquery-plugins/jquery.query.js
+Source: jquery.query.js
+
+Files: wp-includes/js/jquery/jquery.schedule.js
+URL: http://code.svn.wordpress.org/wordpress-sources/jquery-plugins/jquery.schedule.js
+Source: jquery.schedule.js
+
+Files: wp-includes/js/jquery/jquery.masonry.min.js
+URL: http://code.svn.wordpress.org/wordpress-sources/jquery-plugins/jquery.masonry-2.1.05.js
+Source: jquery.masonry.js
+
+Files: wp-includes/js/jquery/jquery.ui.touch-punch.js
+URL: http://code.svn.wordpress.org/wordpress-sources/jquery-plugins/jquery.ui.touch-punch.js
+Source: jquery.ui.touch-punch.js
+
+Files: wp-includes/js/jquery/ui/*.js
+Project: jQuery UI 1.10.3
+URL: http://code.svn.wordpress.org/wordpress-sources/jquery-ui/1.10.3/
+Source: jquery-ui-1.10.3
+
+Files: wp-includes/js/plupload/*
+Project: plupload 1.5.7
+URL: http://code.svn.wordpress.org/wordpress-sources/plupload/1.5.7/
+Source: plupload-1.5.7
+
+Files: wp-includes/js/tinymce/*
+Project: TinyMCE 4.3.10
+URL: https://github.com/tinymce/tinymce/archive/4.3.10.tar.gz
+Source: tinymce-4.3.10.tar.gz
+
+Files: wp-includes/js/backbone.min.js
+Project: Backbone.js 1.0
+URL: http://code.svn.wordpress.org/wordpress-sources/backbone/backbone-1.0.js
+Source: backbone-1.0.js
+
+Files: wp-includes/js/underscore.min.js
+Project: Underscore.js 1.4.4
+URL: http://code.svn.wordpress.org/wordpress-sources/backbone/underscore-1.4.4.js
+Source: underscore-1.4.4.js
+
+File: wp-admin/js/revisions-js.php
+URL: http://wordpress.org/download/source/revisions-js-dev.php.txt
+Source: revisions-js-dev.php
+
+File: wp-includes/js/mediaelement/flashmediaelement.swf
+Project: mediaelement 2.13.0
+URL: https://github.com/johndyer/mediaelement/tree/2.13.0
+Source: mediaelement-2.13.0/*
diff --git a/debian/missing-sources/backbone.js b/debian/missing-sources/backbone.js
new file mode 100644
index 0000000..3512d42
--- /dev/null
+++ b/debian/missing-sources/backbone.js
@@ -0,0 +1,1571 @@
+// Backbone.js 1.0.0
+
+// (c) 2010-2013 Jeremy Ashkenas, DocumentCloud Inc.
+// Backbone may be freely distributed under the MIT license.
+// For all details and documentation:
+// http://backbonejs.org
+
+(function(){
+
+ // Initial Setup
+ // -------------
+
+ // Save a reference to the global object (`window` in the browser, `exports`
+ // on the server).
+ var root = this;
+
+ // Save the previous value of the `Backbone` variable, so that it can be
+ // restored later on, if `noConflict` is used.
+ var previousBackbone = root.Backbone;
+
+ // Create local references to array methods we'll want to use later.
+ var array = [];
+ var push = array.push;
+ var slice = array.slice;
+ var splice = array.splice;
+
+ // The top-level namespace. All public Backbone classes and modules will
+ // be attached to this. Exported for both the browser and the server.
+ var Backbone;
+ if (typeof exports !== 'undefined') {
+ Backbone = exports;
+ } else {
+ Backbone = root.Backbone = {};
+ }
+
+ // Current version of the library. Keep in sync with `package.json`.
+ Backbone.VERSION = '1.0.0';
+
+ // Require Underscore, if we're on the server, and it's not already present.
+ var _ = root._;
+ if (!_ && (typeof require !== 'undefined')) _ = require('underscore');
+
+ // For Backbone's purposes, jQuery, Zepto, Ender, or My Library (kidding) owns
+ // the `$` variable.
+ Backbone.$ = root.jQuery || root.Zepto || root.ender || root.$;
+
+ // Runs Backbone.js in *noConflict* mode, returning the `Backbone` variable
+ // to its previous owner. Returns a reference to this Backbone object.
+ Backbone.noConflict = function() {
+ root.Backbone = previousBackbone;
+ return this;
+ };
+
+ // Turn on `emulateHTTP` to support legacy HTTP servers. Setting this option
+ // will fake `"PUT"` and `"DELETE"` requests via the `_method` parameter and
+ // set a `X-Http-Method-Override` header.
+ Backbone.emulateHTTP = false;
+
+ // Turn on `emulateJSON` to support legacy servers that can't deal with direct
+ // `application/json` requests ... will encode the body as
+ // `application/x-www-form-urlencoded` instead and will send the model in a
+ // form param named `model`.
+ Backbone.emulateJSON = false;
+
+ // Backbone.Events
+ // ---------------
+
+ // A module that can be mixed in to *any object* in order to provide it with
+ // custom events. You may bind with `on` or remove with `off` callback
+ // functions to an event; `trigger`-ing an event fires all callbacks in
+ // succession.
+ //
+ // var object = {};
+ // _.extend(object, Backbone.Events);
+ // object.on('expand', function(){ alert('expanded'); });
+ // object.trigger('expand');
+ //
+ var Events = Backbone.Events = {
+
+ // Bind an event to a `callback` function. Passing `"all"` will bind
+ // the callback to all events fired.
+ on: function(name, callback, context) {
+ if (!eventsApi(this, 'on', name, [callback, context]) || !callback) return this;
+ this._events || (this._events = {});
+ var events = this._events[name] || (this._events[name] = []);
+ events.push({callback: callback, context: context, ctx: context || this});
+ return this;
+ },
+
+ // Bind an event to only be triggered a single time. After the first time
+ // the callback is invoked, it will be removed.
+ once: function(name, callback, context) {
+ if (!eventsApi(this, 'once', name, [callback, context]) || !callback) return this;
+ var self = this;
+ var once = _.once(function() {
+ self.off(name, once);
+ callback.apply(this, arguments);
+ });
+ once._callback = callback;
+ return this.on(name, once, context);
+ },
+
+ // Remove one or many callbacks. If `context` is null, removes all
+ // callbacks with that function. If `callback` is null, removes all
+ // callbacks for the event. If `name` is null, removes all bound
+ // callbacks for all events.
+ off: function(name, callback, context) {
+ var retain, ev, events, names, i, l, j, k;
+ if (!this._events || !eventsApi(this, 'off', name, [callback, context])) return this;
+ if (!name && !callback && !context) {
+ this._events = {};
+ return this;
+ }
+
+ names = name ? [name] : _.keys(this._events);
+ for (i = 0, l = names.length; i < l; i++) {
+ name = names[i];
+ if (events = this._events[name]) {
+ this._events[name] = retain = [];
+ if (callback || context) {
+ for (j = 0, k = events.length; j < k; j++) {
+ ev = events[j];
+ if ((callback && callback !== ev.callback && callback !== ev.callback._callback) ||
+ (context && context !== ev.context)) {
+ retain.push(ev);
+ }
+ }
+ }
+ if (!retain.length) delete this._events[name];
+ }
+ }
+
+ return this;
+ },
+
+ // Trigger one or many events, firing all bound callbacks. Callbacks are
+ // passed the same arguments as `trigger` is, apart from the event name
+ // (unless you're listening on `"all"`, which will cause your callback to
+ // receive the true name of the event as the first argument).
+ trigger: function(name) {
+ if (!this._events) return this;
+ var args = slice.call(arguments, 1);
+ if (!eventsApi(this, 'trigger', name, args)) return this;
+ var events = this._events[name];
+ var allEvents = this._events.all;
+ if (events) triggerEvents(events, args);
+ if (allEvents) triggerEvents(allEvents, arguments);
+ return this;
+ },
+
+ // Tell this object to stop listening to either specific events ... or
+ // to every object it's currently listening to.
+ stopListening: function(obj, name, callback) {
+ var listeners = this._listeners;
+ if (!listeners) return this;
+ var deleteListener = !name && !callback;
+ if (typeof name === 'object') callback = this;
+ if (obj) (listeners = {})[obj._listenerId] = obj;
+ for (var id in listeners) {
+ listeners[id].off(name, callback, this);
+ if (deleteListener) delete this._listeners[id];
+ }
+ return this;
+ }
+
+ };
+
+ // Regular expression used to split event strings.
+ var eventSplitter = /\s+/;
+
+ // Implement fancy features of the Events API such as multiple event
+ // names `"change blur"` and jQuery-style event maps `{change: action}`
+ // in terms of the existing API.
+ var eventsApi = function(obj, action, name, rest) {
+ if (!name) return true;
+
+ // Handle event maps.
+ if (typeof name === 'object') {
+ for (var key in name) {
+ obj[action].apply(obj, [key, name[key]].concat(rest));
+ }
+ return false;
+ }
+
+ // Handle space separated event names.
+ if (eventSplitter.test(name)) {
+ var names = name.split(eventSplitter);
+ for (var i = 0, l = names.length; i < l; i++) {
+ obj[action].apply(obj, [names[i]].concat(rest));
+ }
+ return false;
+ }
+
+ return true;
+ };
+
+ // A difficult-to-believe, but optimized internal dispatch function for
+ // triggering events. Tries to keep the usual cases speedy (most internal
+ // Backbone events have 3 arguments).
+ var triggerEvents = function(events, args) {
+ var ev, i = -1, l = events.length, a1 = args[0], a2 = args[1], a3 = args[2];
+ switch (args.length) {
+ case 0: while (++i < l) (ev = events[i]).callback.call(ev.ctx); return;
+ case 1: while (++i < l) (ev = events[i]).callback.call(ev.ctx, a1); return;
+ case 2: while (++i < l) (ev = events[i]).callback.call(ev.ctx, a1, a2); return;
+ case 3: while (++i < l) (ev = events[i]).callback.call(ev.ctx, a1, a2, a3); return;
+ default: while (++i < l) (ev = events[i]).callback.apply(ev.ctx, args);
+ }
+ };
+
+ var listenMethods = {listenTo: 'on', listenToOnce: 'once'};
+
+ // Inversion-of-control versions of `on` and `once`. Tell *this* object to
+ // listen to an event in another object ... keeping track of what it's
+ // listening to.
+ _.each(listenMethods, function(implementation, method) {
+ Events[method] = function(obj, name, callback) {
+ var listeners = this._listeners || (this._listeners = {});
+ var id = obj._listenerId || (obj._listenerId = _.uniqueId('l'));
+ listeners[id] = obj;
+ if (typeof name === 'object') callback = this;
+ obj[implementation](name, callback, this);
+ return this;
+ };
+ });
+
+ // Aliases for backwards compatibility.
+ Events.bind = Events.on;
+ Events.unbind = Events.off;
+
+ // Allow the `Backbone` object to serve as a global event bus, for folks who
+ // want global "pubsub" in a convenient place.
+ _.extend(Backbone, Events);
+
+ // Backbone.Model
+ // --------------
+
+ // Backbone **Models** are the basic data object in the framework --
+ // frequently representing a row in a table in a database on your server.
+ // A discrete chunk of data and a bunch of useful, related methods for
+ // performing computations and transformations on that data.
+
+ // Create a new model with the specified attributes. A client id (`cid`)
+ // is automatically generated and assigned for you.
+ var Model = Backbone.Model = function(attributes, options) {
+ var defaults;
+ var attrs = attributes || {};
+ options || (options = {});
+ this.cid = _.uniqueId('c');
+ this.attributes = {};
+ _.extend(this, _.pick(options, modelOptions));
+ if (options.parse) attrs = this.parse(attrs, options) || {};
+ if (defaults = _.result(this, 'defaults')) {
+ attrs = _.defaults({}, attrs, defaults);
+ }
+ this.set(attrs, options);
+ this.changed = {};
+ this.initialize.apply(this, arguments);
+ };
+
+ // A list of options to be attached directly to the model, if provided.
+ var modelOptions = ['url', 'urlRoot', 'collection'];
+
+ // Attach all inheritable methods to the Model prototype.
+ _.extend(Model.prototype, Events, {
+
+ // A hash of attributes whose current and previous value differ.
+ changed: null,
+
+ // The value returned during the last failed validation.
+ validationError: null,
+
+ // The default name for the JSON `id` attribute is `"id"`. MongoDB and
+ // CouchDB users may want to set this to `"_id"`.
+ idAttribute: 'id',
+
+ // Initialize is an empty function by default. Override it with your own
+ // initialization logic.
+ initialize: function(){},
+
+ // Return a copy of the model's `attributes` object.
+ toJSON: function(options) {
+ return _.clone(this.attributes);
+ },
+
+ // Proxy `Backbone.sync` by default -- but override this if you need
+ // custom syncing semantics for *this* particular model.
+ sync: function() {
+ return Backbone.sync.apply(this, arguments);
+ },
+
+ // Get the value of an attribute.
+ get: function(attr) {
+ return this.attributes[attr];
+ },
+
+ // Get the HTML-escaped value of an attribute.
+ escape: function(attr) {
+ return _.escape(this.get(attr));
+ },
+
+ // Returns `true` if the attribute contains a value that is not null
+ // or undefined.
+ has: function(attr) {
+ return this.get(attr) != null;
+ },
+
+ // Set a hash of model attributes on the object, firing `"change"`. This is
+ // the core primitive operation of a model, updating the data and notifying
+ // anyone who needs to know about the change in state. The heart of the beast.
+ set: function(key, val, options) {
+ var attr, attrs, unset, changes, silent, changing, prev, current;
+ if (key == null) return this;
+
+ // Handle both `"key", value` and `{key: value}` -style arguments.
+ if (typeof key === 'object') {
+ attrs = key;
+ options = val;
+ } else {
+ (attrs = {})[key] = val;
+ }
+
+ options || (options = {});
+
+ // Run validation.
+ if (!this._validate(attrs, options)) return false;
+
+ // Extract attributes and options.
+ unset = options.unset;
+ silent = options.silent;
+ changes = [];
+ changing = this._changing;
+ this._changing = true;
+
+ if (!changing) {
+ this._previousAttributes = _.clone(this.attributes);
+ this.changed = {};
+ }
+ current = this.attributes, prev = this._previousAttributes;
+
+ // Check for changes of `id`.
+ if (this.idAttribute in attrs) this.id = attrs[this.idAttribute];
+
+ // For each `set` attribute, update or delete the current value.
+ for (attr in attrs) {
+ val = attrs[attr];
+ if (!_.isEqual(current[attr], val)) changes.push(attr);
+ if (!_.isEqual(prev[attr], val)) {
+ this.changed[attr] = val;
+ } else {
+ delete this.changed[attr];
+ }
+ unset ? delete current[attr] : current[attr] = val;
+ }
+
+ // Trigger all relevant attribute changes.
+ if (!silent) {
+ if (changes.length) this._pending = true;
+ for (var i = 0, l = changes.length; i < l; i++) {
+ this.trigger('change:' + changes[i], this, current[changes[i]], options);
+ }
+ }
+
+ // You might be wondering why there's a `while` loop here. Changes can
+ // be recursively nested within `"change"` events.
+ if (changing) return this;
+ if (!silent) {
+ while (this._pending) {
+ this._pending = false;
+ this.trigger('change', this, options);
+ }
+ }
+ this._pending = false;
+ this._changing = false;
+ return this;
+ },
+
+ // Remove an attribute from the model, firing `"change"`. `unset` is a noop
+ // if the attribute doesn't exist.
+ unset: function(attr, options) {
+ return this.set(attr, void 0, _.extend({}, options, {unset: true}));
+ },
+
+ // Clear all attributes on the model, firing `"change"`.
+ clear: function(options) {
+ var attrs = {};
+ for (var key in this.attributes) attrs[key] = void 0;
+ return this.set(attrs, _.extend({}, options, {unset: true}));
+ },
+
+ // Determine if the model has changed since the last `"change"` event.
+ // If you specify an attribute name, determine if that attribute has changed.
+ hasChanged: function(attr) {
+ if (attr == null) return !_.isEmpty(this.changed);
+ return _.has(this.changed, attr);
+ },
+
+ // Return an object containing all the attributes that have changed, or
+ // false if there are no changed attributes. Useful for determining what
+ // parts of a view need to be updated and/or what attributes need to be
+ // persisted to the server. Unset attributes will be set to undefined.
+ // You can also pass an attributes object to diff against the model,
+ // determining if there *would be* a change.
+ changedAttributes: function(diff) {
+ if (!diff) return this.hasChanged() ? _.clone(this.changed) : false;
+ var val, changed = false;
+ var old = this._changing ? this._previousAttributes : this.attributes;
+ for (var attr in diff) {
+ if (_.isEqual(old[attr], (val = diff[attr]))) continue;
+ (changed || (changed = {}))[attr] = val;
+ }
+ return changed;
+ },
+
+ // Get the previous value of an attribute, recorded at the time the last
+ // `"change"` event was fired.
+ previous: function(attr) {
+ if (attr == null || !this._previousAttributes) return null;
+ return this._previousAttributes[attr];
+ },
+
+ // Get all of the attributes of the model at the time of the previous
+ // `"change"` event.
+ previousAttributes: function() {
+ return _.clone(this._previousAttributes);
+ },
+
+ // Fetch the model from the server. If the server's representation of the
+ // model differs from its current attributes, they will be overridden,
+ // triggering a `"change"` event.
+ fetch: function(options) {
+ options = options ? _.clone(options) : {};
+ if (options.parse === void 0) options.parse = true;
+ var model = this;
+ var success = options.success;
+ options.success = function(resp) {
+ if (!model.set(model.parse(resp, options), options)) return false;
+ if (success) success(model, resp, options);
+ model.trigger('sync', model, resp, options);
+ };
+ wrapError(this, options);
+ return this.sync('read', this, options);
+ },
+
+ // Set a hash of model attributes, and sync the model to the server.
+ // If the server returns an attributes hash that differs, the model's
+ // state will be `set` again.
+ save: function(key, val, options) {
+ var attrs, method, xhr, attributes = this.attributes;
+
+ // Handle both `"key", value` and `{key: value}` -style arguments.
+ if (key == null || typeof key === 'object') {
+ attrs = key;
+ options = val;
+ } else {
+ (attrs = {})[key] = val;
+ }
+
+ // If we're not waiting and attributes exist, save acts as `set(attr).save(null, opts)`.
+ if (attrs && (!options || !options.wait) && !this.set(attrs, options)) return false;
+
+ options = _.extend({validate: true}, options);
+
+ // Do not persist invalid models.
+ if (!this._validate(attrs, options)) return false;
+
+ // Set temporary attributes if `{wait: true}`.
+ if (attrs && options.wait) {
+ this.attributes = _.extend({}, attributes, attrs);
+ }
+
+ // After a successful server-side save, the client is (optionally)
+ // updated with the server-side state.
+ if (options.parse === void 0) options.parse = true;
+ var model = this;
+ var success = options.success;
+ options.success = function(resp) {
+ // Ensure attributes are restored during synchronous saves.
+ model.attributes = attributes;
+ var serverAttrs = model.parse(resp, options);
+ if (options.wait) serverAttrs = _.extend(attrs || {}, serverAttrs);
+ if (_.isObject(serverAttrs) && !model.set(serverAttrs, options)) {
+ return false;
+ }
+ if (success) success(model, resp, options);
+ model.trigger('sync', model, resp, options);
+ };
+ wrapError(this, options);
+
+ method = this.isNew() ? 'create' : (options.patch ? 'patch' : 'update');
+ if (method === 'patch') options.attrs = attrs;
+ xhr = this.sync(method, this, options);
+
+ // Restore attributes.
+ if (attrs && options.wait) this.attributes = attributes;
+
+ return xhr;
+ },
+
+ // Destroy this model on the server if it was already persisted.
+ // Optimistically removes the model from its collection, if it has one.
+ // If `wait: true` is passed, waits for the server to respond before removal.
+ destroy: function(options) {
+ options = options ? _.clone(options) : {};
+ var model = this;
+ var success = options.success;
+
+ var destroy = function() {
+ model.trigger('destroy', model, model.collection, options);
+ };
+
+ options.success = function(resp) {
+ if (options.wait || model.isNew()) destroy();
+ if (success) success(model, resp, options);
+ if (!model.isNew()) model.trigger('sync', model, resp, options);
+ };
+
+ if (this.isNew()) {
+ options.success();
+ return false;
+ }
+ wrapError(this, options);
+
+ var xhr = this.sync('delete', this, options);
+ if (!options.wait) destroy();
+ return xhr;
+ },
+
+ // Default URL for the model's representation on the server -- if you're
+ // using Backbone's restful methods, override this to change the endpoint
+ // that will be called.
+ url: function() {
+ var base = _.result(this, 'urlRoot') || _.result(this.collection, 'url') || urlError();
+ if (this.isNew()) return base;
+ return base + (base.charAt(base.length - 1) === '/' ? '' : '/') + encodeURIComponent(this.id);
+ },
+
+ // **parse** converts a response into the hash of attributes to be `set` on
+ // the model. The default implementation is just to pass the response along.
+ parse: function(resp, options) {
+ return resp;
+ },
+
+ // Create a new model with identical attributes to this one.
+ clone: function() {
+ return new this.constructor(this.attributes);
+ },
+
+ // A model is new if it has never been saved to the server, and lacks an id.
+ isNew: function() {
+ return this.id == null;
+ },
+
+ // Check if the model is currently in a valid state.
+ isValid: function(options) {
+ return this._validate({}, _.extend(options || {}, { validate: true }));
+ },
+
+ // Run validation against the next complete set of model attributes,
+ // returning `true` if all is well. Otherwise, fire an `"invalid"` event.
+ _validate: function(attrs, options) {
+ if (!options.validate || !this.validate) return true;
+ attrs = _.extend({}, this.attributes, attrs);
+ var error = this.validationError = this.validate(attrs, options) || null;
+ if (!error) return true;
+ this.trigger('invalid', this, error, _.extend(options || {}, {validationError: error}));
+ return false;
+ }
+
+ });
+
+ // Underscore methods that we want to implement on the Model.
+ var modelMethods = ['keys', 'values', 'pairs', 'invert', 'pick', 'omit'];
+
+ // Mix in each Underscore method as a proxy to `Model#attributes`.
+ _.each(modelMethods, function(method) {
+ Model.prototype[method] = function() {
+ var args = slice.call(arguments);
+ args.unshift(this.attributes);
+ return _[method].apply(_, args);
+ };
+ });
+
+ // Backbone.Collection
+ // -------------------
+
+ // If models tend to represent a single row of data, a Backbone Collection is
+ // more analagous to a table full of data ... or a small slice or page of that
+ // table, or a collection of rows that belong together for a particular reason
+ // -- all of the messages in this particular folder, all of the documents
+ // belonging to this particular author, and so on. Collections maintain
+ // indexes of their models, both in order, and for lookup by `id`.
+
+ // Create a new **Collection**, perhaps to contain a specific type of `model`.
+ // If a `comparator` is specified, the Collection will maintain
+ // its models in sort order, as they're added and removed.
+ var Collection = Backbone.Collection = function(models, options) {
+ options || (options = {});
+ if (options.url) this.url = options.url;
+ if (options.model) this.model = options.model;
+ if (options.comparator !== void 0) this.comparator = options.comparator;
+ this._reset();
+ this.initialize.apply(this, arguments);
+ if (models) this.reset(models, _.extend({silent: true}, options));
+ };
+
+ // Default options for `Collection#set`.
+ var setOptions = {add: true, remove: true, merge: true};
+ var addOptions = {add: true, merge: false, remove: false};
+
+ // Define the Collection's inheritable methods.
+ _.extend(Collection.prototype, Events, {
+
+ // The default model for a collection is just a **Backbone.Model**.
+ // This should be overridden in most cases.
+ model: Model,
+
+ // Initialize is an empty function by default. Override it with your own
+ // initialization logic.
+ initialize: function(){},
+
+ // The JSON representation of a Collection is an array of the
+ // models' attributes.
+ toJSON: function(options) {
+ return this.map(function(model){ return model.toJSON(options); });
+ },
+
+ // Proxy `Backbone.sync` by default.
+ sync: function() {
+ return Backbone.sync.apply(this, arguments);
+ },
+
+ // Add a model, or list of models to the set.
+ add: function(models, options) {
+ return this.set(models, _.defaults(options || {}, addOptions));
+ },
+
+ // Remove a model, or a list of models from the set.
+ remove: function(models, options) {
+ models = _.isArray(models) ? models.slice() : [models];
+ options || (options = {});
+ var i, l, index, model;
+ for (i = 0, l = models.length; i < l; i++) {
+ model = this.get(models[i]);
+ if (!model) continue;
+ delete this._byId[model.id];
+ delete this._byId[model.cid];
+ index = this.indexOf(model);
+ this.models.splice(index, 1);
+ this.length--;
+ if (!options.silent) {
+ options.index = index;
+ model.trigger('remove', model, this, options);
+ }
+ this._removeReference(model);
+ }
+ return this;
+ },
+
+ // Update a collection by `set`-ing a new list of models, adding new ones,
+ // removing models that are no longer present, and merging models that
+ // already exist in the collection, as necessary. Similar to **Model#set**,
+ // the core operation for updating the data contained by the collection.
+ set: function(models, options) {
+ options = _.defaults(options || {}, setOptions);
+ if (options.parse) models = this.parse(models, options);
+ if (!_.isArray(models)) models = models ? [models] : [];
+ var i, l, model, attrs, existing, sort;
+ var at = options.at;
+ var sortable = this.comparator && (at == null) && options.sort !== false;
+ var sortAttr = _.isString(this.comparator) ? this.comparator : null;
+ var toAdd = [], toRemove = [], modelMap = {};
+
+ // Turn bare objects into model references, and prevent invalid models
+ // from being added.
+ for (i = 0, l = models.length; i < l; i++) {
+ if (!(model = this._prepareModel(models[i], options))) continue;
+
+ // If a duplicate is found, prevent it from being added and
+ // optionally merge it into the existing model.
+ if (existing = this.get(model)) {
+ if (options.remove) modelMap[existing.cid] = true;
+ if (options.merge) {
+ existing.set(model.attributes, options);
+ if (sortable && !sort && existing.hasChanged(sortAttr)) sort = true;
+ }
+
+ // This is a new model, push it to the `toAdd` list.
+ } else if (options.add) {
+ toAdd.push(model);
+
+ // Listen to added models' events, and index models for lookup by
+ // `id` and by `cid`.
+ model.on('all', this._onModelEvent, this);
+ this._byId[model.cid] = model;
+ if (model.id != null) this._byId[model.id] = model;
+ }
+ }
+
+ // Remove nonexistent models if appropriate.
+ if (options.remove) {
+ for (i = 0, l = this.length; i < l; ++i) {
+ if (!modelMap[(model = this.models[i]).cid]) toRemove.push(model);
+ }
+ if (toRemove.length) this.remove(toRemove, options);
+ }
+
+ // See if sorting is needed, update `length` and splice in new models.
+ if (toAdd.length) {
+ if (sortable) sort = true;
+ this.length += toAdd.length;
+ if (at != null) {
+ splice.apply(this.models, [at, 0].concat(toAdd));
+ } else {
+ push.apply(this.models, toAdd);
+ }
+ }
+
+ // Silently sort the collection if appropriate.
+ if (sort) this.sort({silent: true});
+
+ if (options.silent) return this;
+
+ // Trigger `add` events.
+ for (i = 0, l = toAdd.length; i < l; i++) {
+ (model = toAdd[i]).trigger('add', model, this, options);
+ }
+
+ // Trigger `sort` if the collection was sorted.
+ if (sort) this.trigger('sort', this, options);
+ return this;
+ },
+
+ // When you have more items than you want to add or remove individually,
+ // you can reset the entire set with a new list of models, without firing
+ // any granular `add` or `remove` events. Fires `reset` when finished.
+ // Useful for bulk operations and optimizations.
+ reset: function(models, options) {
+ options || (options = {});
+ for (var i = 0, l = this.models.length; i < l; i++) {
+ this._removeReference(this.models[i]);
+ }
+ options.previousModels = this.models;
+ this._reset();
+ this.add(models, _.extend({silent: true}, options));
+ if (!options.silent) this.trigger('reset', this, options);
+ return this;
+ },
+
+ // Add a model to the end of the collection.
+ push: function(model, options) {
+ model = this._prepareModel(model, options);
+ this.add(model, _.extend({at: this.length}, options));
+ return model;
+ },
+
+ // Remove a model from the end of the collection.
+ pop: function(options) {
+ var model = this.at(this.length - 1);
+ this.remove(model, options);
+ return model;
+ },
+
+ // Add a model to the beginning of the collection.
+ unshift: function(model, options) {
+ model = this._prepareModel(model, options);
+ this.add(model, _.extend({at: 0}, options));
+ return model;
+ },
+
+ // Remove a model from the beginning of the collection.
+ shift: function(options) {
+ var model = this.at(0);
+ this.remove(model, options);
+ return model;
+ },
+
+ // Slice out a sub-array of models from the collection.
+ slice: function(begin, end) {
+ return this.models.slice(begin, end);
+ },
+
+ // Get a model from the set by id.
+ get: function(obj) {
+ if (obj == null) return void 0;
+ return this._byId[obj.id != null ? obj.id : obj.cid || obj];
+ },
+
+ // Get the model at the given index.
+ at: function(index) {
+ return this.models[index];
+ },
+
+ // Return models with matching attributes. Useful for simple cases of
+ // `filter`.
+ where: function(attrs, first) {
+ if (_.isEmpty(attrs)) return first ? void 0 : [];
+ return this[first ? 'find' : 'filter'](function(model) {
+ for (var key in attrs) {
+ if (attrs[key] !== model.get(key)) return false;
+ }
+ return true;
+ });
+ },
+
+ // Return the first model with matching attributes. Useful for simple cases
+ // of `find`.
+ findWhere: function(attrs) {
+ return this.where(attrs, true);
+ },
+
+ // Force the collection to re-sort itself. You don't need to call this under
+ // normal circumstances, as the set will maintain sort order as each item
+ // is added.
+ sort: function(options) {
+ if (!this.comparator) throw new Error('Cannot sort a set without a comparator');
+ options || (options = {});
+
+ // Run sort based on type of `comparator`.
+ if (_.isString(this.comparator) || this.comparator.length === 1) {
+ this.models = this.sortBy(this.comparator, this);
+ } else {
+ this.models.sort(_.bind(this.comparator, this));
+ }
+
+ if (!options.silent) this.trigger('sort', this, options);
+ return this;
+ },
+
+ // Figure out the smallest index at which a model should be inserted so as
+ // to maintain order.
+ sortedIndex: function(model, value, context) {
+ value || (value = this.comparator);
+ var iterator = _.isFunction(value) ? value : function(model) {
+ return model.get(value);
+ };
+ return _.sortedIndex(this.models, model, iterator, context);
+ },
+
+ // Pluck an attribute from each model in the collection.
+ pluck: function(attr) {
+ return _.invoke(this.models, 'get', attr);
+ },
+
+ // Fetch the default set of models for this collection, resetting the
+ // collection when they arrive. If `reset: true` is passed, the response
+ // data will be passed through the `reset` method instead of `set`.
+ fetch: function(options) {
+ options = options ? _.clone(options) : {};
+ if (options.parse === void 0) options.parse = true;
+ var success = options.success;
+ var collection = this;
+ options.success = function(resp) {
+ var method = options.reset ? 'reset' : 'set';
+ collection[method](resp, options);
+ if (success) success(collection, resp, options);
+ collection.trigger('sync', collection, resp, options);
+ };
+ wrapError(this, options);
+ return this.sync('read', this, options);
+ },
+
+ // Create a new instance of a model in this collection. Add the model to the
+ // collection immediately, unless `wait: true` is passed, in which case we
+ // wait for the server to agree.
+ create: function(model, options) {
+ options = options ? _.clone(options) : {};
+ if (!(model = this._prepareModel(model, options))) return false;
+ if (!options.wait) this.add(model, options);
+ var collection = this;
+ var success = options.success;
+ options.success = function(resp) {
+ if (options.wait) collection.add(model, options);
+ if (success) success(model, resp, options);
+ };
+ model.save(null, options);
+ return model;
+ },
+
+ // **parse** converts a response into a list of models to be added to the
+ // collection. The default implementation is just to pass it through.
+ parse: function(resp, options) {
+ return resp;
+ },
+
+ // Create a new collection with an identical list of models as this one.
+ clone: function() {
+ return new this.constructor(this.models);
+ },
+
+ // Private method to reset all internal state. Called when the collection
+ // is first initialized or reset.
+ _reset: function() {
+ this.length = 0;
+ this.models = [];
+ this._byId = {};
+ },
+
+ // Prepare a hash of attributes (or other model) to be added to this
+ // collection.
+ _prepareModel: function(attrs, options) {
+ if (attrs instanceof Model) {
+ if (!attrs.collection) attrs.collection = this;
+ return attrs;
+ }
+ options || (options = {});
+ options.collection = this;
+ var model = new this.model(attrs, options);
+ if (!model._validate(attrs, options)) {
+ this.trigger('invalid', this, attrs, options);
+ return false;
+ }
+ return model;
+ },
+
+ // Internal method to sever a model's ties to a collection.
+ _removeReference: function(model) {
+ if (this === model.collection) delete model.collection;
+ model.off('all', this._onModelEvent, this);
+ },
+
+ // Internal method called every time a model in the set fires an event.
+ // Sets need to update their indexes when models change ids. All other
+ // events simply proxy through. "add" and "remove" events that originate
+ // in other collections are ignored.
+ _onModelEvent: function(event, model, collection, options) {
+ if ((event === 'add' || event === 'remove') && collection !== this) return;
+ if (event === 'destroy') this.remove(model, options);
+ if (model && event === 'change:' + model.idAttribute) {
+ delete this._byId[model.previous(model.idAttribute)];
+ if (model.id != null) this._byId[model.id] = model;
+ }
+ this.trigger.apply(this, arguments);
+ }
+
+ });
+
+ // Underscore methods that we want to implement on the Collection.
+ // 90% of the core usefulness of Backbone Collections is actually implemented
+ // right here:
+ var methods = ['forEach', 'each', 'map', 'collect', 'reduce', 'foldl',
+ 'inject', 'reduceRight', 'foldr', 'find', 'detect', 'filter', 'select',
+ 'reject', 'every', 'all', 'some', 'any', 'include', 'contains', 'invoke',
+ 'max', 'min', 'toArray', 'size', 'first', 'head', 'take', 'initial', 'rest',
+ 'tail', 'drop', 'last', 'without', 'indexOf', 'shuffle', 'lastIndexOf',
+ 'isEmpty', 'chain'];
+
+ // Mix in each Underscore method as a proxy to `Collection#models`.
+ _.each(methods, function(method) {
+ Collection.prototype[method] = function() {
+ var args = slice.call(arguments);
+ args.unshift(this.models);
+ return _[method].apply(_, args);
+ };
+ });
+
+ // Underscore methods that take a property name as an argument.
+ var attributeMethods = ['groupBy', 'countBy', 'sortBy'];
+
+ // Use attributes instead of properties.
+ _.each(attributeMethods, function(method) {
+ Collection.prototype[method] = function(value, context) {
+ var iterator = _.isFunction(value) ? value : function(model) {
+ return model.get(value);
+ };
+ return _[method](this.models, iterator, context);
+ };
+ });
+
+ // Backbone.View
+ // -------------
+
+ // Backbone Views are almost more convention than they are actual code. A View
+ // is simply a JavaScript object that represents a logical chunk of UI in the
+ // DOM. This might be a single item, an entire list, a sidebar or panel, or
+ // even the surrounding frame which wraps your whole app. Defining a chunk of
+ // UI as a **View** allows you to define your DOM events declaratively, without
+ // having to worry about render order ... and makes it easy for the view to
+ // react to specific changes in the state of your models.
+
+ // Creating a Backbone.View creates its initial element outside of the DOM,
+ // if an existing element is not provided...
+ var View = Backbone.View = function(options) {
+ this.cid = _.uniqueId('view');
+ this._configure(options || {});
+ this._ensureElement();
+ this.initialize.apply(this, arguments);
+ this.delegateEvents();
+ };
+
+ // Cached regex to split keys for `delegate`.
+ var delegateEventSplitter = /^(\S+)\s*(.*)$/;
+
+ // List of view options to be merged as properties.
+ var viewOptions = ['model', 'collection', 'el', 'id', 'attributes', 'className', 'tagName', 'events'];
+
+ // Set up all inheritable **Backbone.View** properties and methods.
+ _.extend(View.prototype, Events, {
+
+ // The default `tagName` of a View's element is `"div"`.
+ tagName: 'div',
+
+ // jQuery delegate for element lookup, scoped to DOM elements within the
+ // current view. This should be prefered to global lookups where possible.
+ $: function(selector) {
+ return this.$el.find(selector);
+ },
+
+ // Initialize is an empty function by default. Override it with your own
+ // initialization logic.
+ initialize: function(){},
+
+ // **render** is the core function that your view should override, in order
+ // to populate its element (`this.el`), with the appropriate HTML. The
+ // convention is for **render** to always return `this`.
+ render: function() {
+ return this;
+ },
+
+ // Remove this view by taking the element out of the DOM, and removing any
+ // applicable Backbone.Events listeners.
+ remove: function() {
+ this.$el.remove();
+ this.stopListening();
+ return this;
+ },
+
+ // Change the view's element (`this.el` property), including event
+ // re-delegation.
+ setElement: function(element, delegate) {
+ if (this.$el) this.undelegateEvents();
+ this.$el = element instanceof Backbone.$ ? element : Backbone.$(element);
+ this.el = this.$el[0];
+ if (delegate !== false) this.delegateEvents();
+ return this;
+ },
+
+ // Set callbacks, where `this.events` is a hash of
+ //
+ // *{"event selector": "callback"}*
+ //
+ // {
+ // 'mousedown .title': 'edit',
+ // 'click .button': 'save'
+ // 'click .open': function(e) { ... }
+ // }
+ //
+ // pairs. Callbacks will be bound to the view, with `this` set properly.
+ // Uses event delegation for efficiency.
+ // Omitting the selector binds the event to `this.el`.
+ // This only works for delegate-able events: not `focus`, `blur`, and
+ // not `change`, `submit`, and `reset` in Internet Explorer.
+ delegateEvents: function(events) {
+ if (!(events || (events = _.result(this, 'events')))) return this;
+ this.undelegateEvents();
+ for (var key in events) {
+ var method = events[key];
+ if (!_.isFunction(method)) method = this[events[key]];
+ if (!method) continue;
+
+ var match = key.match(delegateEventSplitter);
+ var eventName = match[1], selector = match[2];
+ method = _.bind(method, this);
+ eventName += '.delegateEvents' + this.cid;
+ if (selector === '') {
+ this.$el.on(eventName, method);
+ } else {
+ this.$el.on(eventName, selector, method);
+ }
+ }
+ return this;
+ },
+
+ // Clears all callbacks previously bound to the view with `delegateEvents`.
+ // You usually don't need to use this, but may wish to if you have multiple
+ // Backbone views attached to the same DOM element.
+ undelegateEvents: function() {
+ this.$el.off('.delegateEvents' + this.cid);
+ return this;
+ },
+
+ // Performs the initial configuration of a View with a set of options.
+ // Keys with special meaning *(e.g. model, collection, id, className)* are
+ // attached directly to the view. See `viewOptions` for an exhaustive
+ // list.
+ _configure: function(options) {
+ if (this.options) options = _.extend({}, _.result(this, 'options'), options);
+ _.extend(this, _.pick(options, viewOptions));
+ this.options = options;
+ },
+
+ // Ensure that the View has a DOM element to render into.
+ // If `this.el` is a string, pass it through `$()`, take the first
+ // matching element, and re-assign it to `el`. Otherwise, create
+ // an element from the `id`, `className` and `tagName` properties.
+ _ensureElement: function() {
+ if (!this.el) {
+ var attrs = _.extend({}, _.result(this, 'attributes'));
+ if (this.id) attrs.id = _.result(this, 'id');
+ if (this.className) attrs['class'] = _.result(this, 'className');
+ var $el = Backbone.$('<' + _.result(this, 'tagName') + '>').attr(attrs);
+ this.setElement($el, false);
+ } else {
+ this.setElement(_.result(this, 'el'), false);
+ }
+ }
+
+ });
+
+ // Backbone.sync
+ // -------------
+
+ // Override this function to change the manner in which Backbone persists
+ // models to the server. You will be passed the type of request, and the
+ // model in question. By default, makes a RESTful Ajax request
+ // to the model's `url()`. Some possible customizations could be:
+ //
+ // * Use `setTimeout` to batch rapid-fire updates into a single request.
+ // * Send up the models as XML instead of JSON.
+ // * Persist models via WebSockets instead of Ajax.
+ //
+ // Turn on `Backbone.emulateHTTP` in order to send `PUT` and `DELETE` requests
+ // as `POST`, with a `_method` parameter containing the true HTTP method,
+ // as well as all requests with the body as `application/x-www-form-urlencoded`
+ // instead of `application/json` with the model in a param named `model`.
+ // Useful when interfacing with server-side languages like **PHP** that make
+ // it difficult to read the body of `PUT` requests.
+ Backbone.sync = function(method, model, options) {
+ var type = methodMap[method];
+
+ // Default options, unless specified.
+ _.defaults(options || (options = {}), {
+ emulateHTTP: Backbone.emulateHTTP,
+ emulateJSON: Backbone.emulateJSON
+ });
+
+ // Default JSON-request options.
+ var params = {type: type, dataType: 'json'};
+
+ // Ensure that we have a URL.
+ if (!options.url) {
+ params.url = _.result(model, 'url') || urlError();
+ }
+
+ // Ensure that we have the appropriate request data.
+ if (options.data == null && model && (method === 'create' || method === 'update' || method === 'patch')) {
+ params.contentType = 'application/json';
+ params.data = JSON.stringify(options.attrs || model.toJSON(options));
+ }
+
+ // For older servers, emulate JSON by encoding the request into an HTML-form.
+ if (options.emulateJSON) {
+ params.contentType = 'application/x-www-form-urlencoded';
+ params.data = params.data ? {model: params.data} : {};
+ }
+
+ // For older servers, emulate HTTP by mimicking the HTTP method with `_method`
+ // And an `X-HTTP-Method-Override` header.
+ if (options.emulateHTTP && (type === 'PUT' || type === 'DELETE' || type === 'PATCH')) {
+ params.type = 'POST';
+ if (options.emulateJSON) params.data._method = type;
+ var beforeSend = options.beforeSend;
+ options.beforeSend = function(xhr) {
+ xhr.setRequestHeader('X-HTTP-Method-Override', type);
+ if (beforeSend) return beforeSend.apply(this, arguments);
+ };
+ }
+
+ // Don't process data on a non-GET request.
+ if (params.type !== 'GET' && !options.emulateJSON) {
+ params.processData = false;
+ }
+
+ // If we're sending a `PATCH` request, and we're in an old Internet Explorer
+ // that still has ActiveX enabled by default, override jQuery to use that
+ // for XHR instead. Remove this line when jQuery supports `PATCH` on IE8.
+ if (params.type === 'PATCH' && window.ActiveXObject &&
+ !(window.external && window.external.msActiveXFilteringEnabled)) {
+ params.xhr = function() {
+ return new ActiveXObject("Microsoft.XMLHTTP");
+ };
+ }
+
+ // Make the request, allowing the user to override any Ajax options.
+ var xhr = options.xhr = Backbone.ajax(_.extend(params, options));
+ model.trigger('request', model, xhr, options);
+ return xhr;
+ };
+
+ // Map from CRUD to HTTP for our default `Backbone.sync` implementation.
+ var methodMap = {
+ 'create': 'POST',
+ 'update': 'PUT',
+ 'patch': 'PATCH',
+ 'delete': 'DELETE',
+ 'read': 'GET'
+ };
+
+ // Set the default implementation of `Backbone.ajax` to proxy through to `$`.
+ // Override this if you'd like to use a different library.
+ Backbone.ajax = function() {
+ return Backbone.$.ajax.apply(Backbone.$, arguments);
+ };
+
+ // Backbone.Router
+ // ---------------
+
+ // Routers map faux-URLs to actions, and fire events when routes are
+ // matched. Creating a new one sets its `routes` hash, if not set statically.
+ var Router = Backbone.Router = function(options) {
+ options || (options = {});
+ if (options.routes) this.routes = options.routes;
+ this._bindRoutes();
+ this.initialize.apply(this, arguments);
+ };
+
+ // Cached regular expressions for matching named param parts and splatted
+ // parts of route strings.
+ var optionalParam = /\((.*?)\)/g;
+ var namedParam = /(\(\?)?:\w+/g;
+ var splatParam = /\*\w+/g;
+ var escapeRegExp = /[\-{}\[\]+?.,\\\^$|#\s]/g;
+
+ // Set up all inheritable **Backbone.Router** properties and methods.
+ _.extend(Router.prototype, Events, {
+
+ // Initialize is an empty function by default. Override it with your own
+ // initialization logic.
+ initialize: function(){},
+
+ // Manually bind a single named route to a callback. For example:
+ //
+ // this.route('search/:query/p:num', 'search', function(query, num) {
+ // ...
+ // });
+ //
+ route: function(route, name, callback) {
+ if (!_.isRegExp(route)) route = this._routeToRegExp(route);
+ if (_.isFunction(name)) {
+ callback = name;
+ name = '';
+ }
+ if (!callback) callback = this[name];
+ var router = this;
+ Backbone.history.route(route, function(fragment) {
+ var args = router._extractParameters(route, fragment);
+ callback && callback.apply(router, args);
+ router.trigger.apply(router, ['route:' + name].concat(args));
+ router.trigger('route', name, args);
+ Backbone.history.trigger('route', router, name, args);
+ });
+ return this;
+ },
+
+ // Simple proxy to `Backbone.history` to save a fragment into the history.
+ navigate: function(fragment, options) {
+ Backbone.history.navigate(fragment, options);
+ return this;
+ },
+
+ // Bind all defined routes to `Backbone.history`. We have to reverse the
+ // order of the routes here to support behavior where the most general
+ // routes can be defined at the bottom of the route map.
+ _bindRoutes: function() {
+ if (!this.routes) return;
+ this.routes = _.result(this, 'routes');
+ var route, routes = _.keys(this.routes);
+ while ((route = routes.pop()) != null) {
+ this.route(route, this.routes[route]);
+ }
+ },
+
+ // Convert a route string into a regular expression, suitable for matching
+ // against the current location hash.
+ _routeToRegExp: function(route) {
+ route = route.replace(escapeRegExp, '\\$&')
+ .replace(optionalParam, '(?:$1)?')
+ .replace(namedParam, function(match, optional){
+ return optional ? match : '([^\/]+)';
+ })
+ .replace(splatParam, '(.*?)');
+ return new RegExp('^' + route + '$');
+ },
+
+ // Given a route, and a URL fragment that it matches, return the array of
+ // extracted decoded parameters. Empty or unmatched parameters will be
+ // treated as `null` to normalize cross-browser behavior.
+ _extractParameters: function(route, fragment) {
+ var params = route.exec(fragment).slice(1);
+ return _.map(params, function(param) {
+ return param ? decodeURIComponent(param) : null;
+ });
+ }
+
+ });
+
+ // Backbone.History
+ // ----------------
+
+ // Handles cross-browser history management, based on either
+ // [pushState](http://diveintohtml5.info/history.html) and real URLs, or
+ // [onhashchange](https://developer.mozilla.org/en-US/docs/DOM/window.onhashchange)
+ // and URL fragments. If the browser supports neither (old IE, natch),
+ // falls back to polling.
+ var History = Backbone.History = function() {
+ this.handlers = [];
+ _.bindAll(this, 'checkUrl');
+
+ // Ensure that `History` can be used outside of the browser.
+ if (typeof window !== 'undefined') {
+ this.location = window.location;
+ this.history = window.history;
+ }
+ };
+
+ // Cached regex for stripping a leading hash/slash and trailing space.
+ var routeStripper = /^[#\/]|\s+$/g;
+
+ // Cached regex for stripping leading and trailing slashes.
+ var rootStripper = /^\/+|\/+$/g;
+
+ // Cached regex for detecting MSIE.
+ var isExplorer = /msie [\w.]+/;
+
+ // Cached regex for removing a trailing slash.
+ var trailingSlash = /\/$/;
+
+ // Has the history handling already been started?
+ History.started = false;
+
+ // Set up all inheritable **Backbone.History** properties and methods.
+ _.extend(History.prototype, Events, {
+
+ // The default interval to poll for hash changes, if necessary, is
+ // twenty times a second.
+ interval: 50,
+
+ // Gets the true hash value. Cannot use location.hash directly due to bug
+ // in Firefox where location.hash will always be decoded.
+ getHash: function(window) {
+ var match = (window || this).location.href.match(/#(.*)$/);
+ return match ? match[1] : '';
+ },
+
+ // Get the cross-browser normalized URL fragment, either from the URL,
+ // the hash, or the override.
+ getFragment: function(fragment, forcePushState) {
+ if (fragment == null) {
+ if (this._hasPushState || !this._wantsHashChange || forcePushState) {
+ fragment = this.location.pathname;
+ var root = this.root.replace(trailingSlash, '');
+ if (!fragment.indexOf(root)) fragment = fragment.substr(root.length);
+ } else {
+ fragment = this.getHash();
+ }
+ }
+ return fragment.replace(routeStripper, '');
+ },
+
+ // Start the hash change handling, returning `true` if the current URL matches
+ // an existing route, and `false` otherwise.
+ start: function(options) {
+ if (History.started) throw new Error("Backbone.history has already been started");
+ History.started = true;
+
+ // Figure out the initial configuration. Do we need an iframe?
+ // Is pushState desired ... is it available?
+ this.options = _.extend({}, {root: '/'}, this.options, options);
+ this.root = this.options.root;
+ this._wantsHashChange = this.options.hashChange !== false;
+ this._wantsPushState = !!this.options.pushState;
+ this._hasPushState = !!(this.options.pushState && this.history && this.history.pushState);
+ var fragment = this.getFragment();
+ var docMode = document.documentMode;
+ var oldIE = (isExplorer.exec(navigator.userAgent.toLowerCase()) && (!docMode || docMode <= 7));
+
+ // Normalize root to always include a leading and trailing slash.
+ this.root = ('/' + this.root + '/').replace(rootStripper, '/');
+
+ if (oldIE && this._wantsHashChange) {
+ this.iframe = Backbone.$('<iframe src="javascript:0" tabindex="-1" />').hide().appendTo('body')[0].contentWindow;
+ this.navigate(fragment);
+ }
+
+ // Depending on whether we're using pushState or hashes, and whether
+ // 'onhashchange' is supported, determine how we check the URL state.
+ if (this._hasPushState) {
+ Backbone.$(window).on('popstate', this.checkUrl);
+ } else if (this._wantsHashChange && ('onhashchange' in window) && !oldIE) {
+ Backbone.$(window).on('hashchange', this.checkUrl);
+ } else if (this._wantsHashChange) {
+ this._checkUrlInterval = setInterval(this.checkUrl, this.interval);
+ }
+
+ // Determine if we need to change the base url, for a pushState link
+ // opened by a non-pushState browser.
+ this.fragment = fragment;
+ var loc = this.location;
+ var atRoot = loc.pathname.replace(/[^\/]$/, '$&/') === this.root;
+
+ // If we've started off with a route from a `pushState`-enabled browser,
+ // but we're currently in a browser that doesn't support it...
+ if (this._wantsHashChange && this._wantsPushState && !this._hasPushState && !atRoot) {
+ this.fragment = this.getFragment(null, true);
+ this.location.replace(this.root + this.location.search + '#' + this.fragment);
+ // Return immediately as browser will do redirect to new url
+ return true;
+
+ // Or if we've started out with a hash-based route, but we're currently
+ // in a browser where it could be `pushState`-based instead...
+ } else if (this._wantsPushState && this._hasPushState && atRoot && loc.hash) {
+ this.fragment = this.getHash().replace(routeStripper, '');
+ this.history.replaceState({}, document.title, this.root + this.fragment + loc.search);
+ }
+
+ if (!this.options.silent) return this.loadUrl();
+ },
+
+ // Disable Backbone.history, perhaps temporarily. Not useful in a real app,
+ // but possibly useful for unit testing Routers.
+ stop: function() {
+ Backbone.$(window).off('popstate', this.checkUrl).off('hashchange', this.checkUrl);
+ clearInterval(this._checkUrlInterval);
+ History.started = false;
+ },
+
+ // Add a route to be tested when the fragment changes. Routes added later
+ // may override previous routes.
+ route: function(route, callback) {
+ this.handlers.unshift({route: route, callback: callback});
+ },
+
+ // Checks the current URL to see if it has changed, and if it has,
+ // calls `loadUrl`, normalizing across the hidden iframe.
+ checkUrl: function(e) {
+ var current = this.getFragment();
+ if (current === this.fragment && this.iframe) {
+ current = this.getFragment(this.getHash(this.iframe));
+ }
+ if (current === this.fragment) return false;
+ if (this.iframe) this.navigate(current);
+ this.loadUrl() || this.loadUrl(this.getHash());
+ },
+
+ // Attempt to load the current URL fragment. If a route succeeds with a
+ // match, returns `true`. If no defined routes matches the fragment,
+ // returns `false`.
+ loadUrl: function(fragmentOverride) {
+ var fragment = this.fragment = this.getFragment(fragmentOverride);
+ var matched = _.any(this.handlers, function(handler) {
+ if (handler.route.test(fragment)) {
+ handler.callback(fragment);
+ return true;
+ }
+ });
+ return matched;
+ },
+
+ // Save a fragment into the hash history, or replace the URL state if the
+ // 'replace' option is passed. You are responsible for properly URL-encoding
+ // the fragment in advance.
+ //
+ // The options object can contain `trigger: true` if you wish to have the
+ // route callback be fired (not usually desirable), or `replace: true`, if
+ // you wish to modify the current URL without adding an entry to the history.
+ navigate: function(fragment, options) {
+ if (!History.started) return false;
+ if (!options || options === true) options = {trigger: options};
+ fragment = this.getFragment(fragment || '');
+ if (this.fragment === fragment) return;
+ this.fragment = fragment;
+ var url = this.root + fragment;
+
+ // If pushState is available, we use it to set the fragment as a real URL.
+ if (this._hasPushState) {
+ this.history[options.replace ? 'replaceState' : 'pushState']({}, document.title, url);
+
+ // If hash changes haven't been explicitly disabled, update the hash
+ // fragment to store history.
+ } else if (this._wantsHashChange) {
+ this._updateHash(this.location, fragment, options.replace);
+ if (this.iframe && (fragment !== this.getFragment(this.getHash(this.iframe)))) {
+ // Opening and closing the iframe tricks IE7 and earlier to push a
+ // history entry on hash-tag change. When replace is true, we don't
+ // want this.
+ if(!options.replace) this.iframe.document.open().close();
+ this._updateHash(this.iframe.location, fragment, options.replace);
+ }
+
+ // If you've told us that you explicitly don't want fallback hashchange-
+ // based history, then `navigate` becomes a page refresh.
+ } else {
+ return this.location.assign(url);
+ }
+ if (options.trigger) this.loadUrl(fragment);
+ },
+
+ // Update the hash location, either replacing the current entry, or adding
+ // a new one to the browser history.
+ _updateHash: function(location, fragment, replace) {
+ if (replace) {
+ var href = location.href.replace(/(javascript:|#).*$/, '');
+ location.replace(href + '#' + fragment);
+ } else {
+ // Some browsers require that `hash` contains a leading #.
+ location.hash = '#' + fragment;
+ }
+ }
+
+ });
+
+ // Create the default Backbone.history.
+ Backbone.history = new History;
+
+ // Helpers
+ // -------
+
+ // Helper function to correctly set up the prototype chain, for subclasses.
+ // Similar to `goog.inherits`, but uses a hash of prototype properties and
+ // class properties to be extended.
+ var extend = function(protoProps, staticProps) {
+ var parent = this;
+ var child;
+
+ // The constructor function for the new subclass is either defined by you
+ // (the "constructor" property in your `extend` definition), or defaulted
+ // by us to simply call the parent's constructor.
+ if (protoProps && _.has(protoProps, 'constructor')) {
+ child = protoProps.constructor;
+ } else {
+ child = function(){ return parent.apply(this, arguments); };
+ }
+
+ // Add static properties to the constructor function, if supplied.
+ _.extend(child, parent, staticProps);
+
+ // Set the prototype chain to inherit from `parent`, without calling
+ // `parent`'s constructor function.
+ var Surrogate = function(){ this.constructor = child; };
+ Surrogate.prototype = parent.prototype;
+ child.prototype = new Surrogate;
+
+ // Add prototype properties (instance properties) to the subclass,
+ // if supplied.
+ if (protoProps) _.extend(child.prototype, protoProps);
+
+ // Set a convenience property in case the parent's prototype is needed
+ // later.
+ child.__super__ = parent.prototype;
+
+ return child;
+ };
+
+ // Set up inheritance for the model, collection, router, view and history.
+ Model.extend = Collection.extend = Router.extend = View.extend = History.extend = extend;
+
+ // Throw an error when a URL is needed, and none is supplied.
+ var urlError = function() {
+ throw new Error('A "url" property or function must be specified');
+ };
+
+ // Wrap an optional error callback with a fallback error event.
+ var wrapError = function (model, options) {
+ var error = options.error;
+ options.error = function(resp) {
+ if (error) error(model, resp, options);
+ model.trigger('error', model, resp, options);
+ };
+ };
+
+}).call(this);
diff --git a/debian/missing-sources/iris.js b/debian/missing-sources/iris.js
new file mode 100644
index 0000000..d894c90
--- /dev/null
+++ b/debian/missing-sources/iris.js
@@ -0,0 +1,1507 @@
+/*! Iris Color Picker - v1.0.4 - 2013-11-18
+* https://github.com/Automattic/Iris
+* Copyright (c) 2013 Matt Wiebe; Licensed GPLv2 */
+(function( $, undef ){
+ var _html, nonGradientIE, gradientType, vendorPrefixes, _css, Iris, UA, isIE, IEVersion;
+
+ _html = '<div class="iris-picker"><div class="iris-picker-inner"><div class="iris-square"><a class="iris-square-value" href="#"><span class="iris-square-handle ui-slider-handle"></span></a><div class="iris-square-inner iris-square-horiz"></div><div class="iris-square-inner iris-square-vert"></div></div><div class="iris-slider iris-strip"><div class="iris-slider-offset"></div></div></div></div>';
+ // Even IE9 dosen't support gradients. Elaborate sigh.
+ UA = navigator.userAgent.toLowerCase();
+ isIE = navigator.appName === 'Microsoft Internet Explorer';
+ IEVersion = isIE ? parseFloat( UA.match( /msie ([0-9]{1,}[\.0-9]{0,})/ )[1] ) : 0;
+ nonGradientIE = ( isIE && IEVersion < 10 );
+ gradientType = false;
+ // we don't bother with an unprefixed version, as it has a different syntax
+ vendorPrefixes = [ '-moz-', '-webkit-', '-o-', '-ms-' ];
+ // This is manually copied from iris.min.css until I can figure out how to do it without
+ _css = '.iris-picker{display:block;position:relative}.iris-picker,.iris-picker *{-moz-box-sizing:content-box;-webkit-box-sizing:content-box;box-sizing:content-box}input+.iris-picker{margin-top:4px}.iris-error{background-color:#ffafaf}.iris-border{border-radius:3px;border:1px solid #aaa;width:200px;background-color:#fff}.iris-picker-inner{position:absolute;top:0;right:0;left:0;bottom:0}.iris-border .iris-picker-inner{top:10px;right:10px;left:10px;bottom:10px}.iris-picker .iris-square-inner{position:absolute;left:0;right:0;top:0;bottom:0}.iris-picker .iris-square,.iris-picker .iris-slider,.iris-picker .iris-square-inner,.iris-picker .iris-palette{border-radius:3px;box-shadow:inset 0 0 5px rgba(0,0,0,.4);height:100%;width:12.5%;float:left;margin-right:5%}.iris-picker .iris-square{width:76%;margin-right:10%;position:relative}.iris-picker .iris-square-inner{width:auto;margin:0}.iris-ie-9 .iris-square,.iris-ie-9 .iris-slider,.iris-ie-9 .iris-square-inner,.iris-ie-9 .iris-palette{box-shadow:none;border-radius:0}.iris-ie-9 .iris-square,.iris-ie-9 .iris-slider,.iris-ie-9 .iris-palette{outline:1px solid rgba(0,0,0,.1)}.iris-ie-lt9 .iris-square,.iris-ie-lt9 .iris-slider,.iris-ie-lt9 .iris-square-inner,.iris-ie-lt9 .iris-palette{outline:1px solid #aaa}.iris-ie-lt9 .iris-square .ui-slider-handle{outline:1px solid #aaa;background-color:#fff;-ms-filter:"alpha(Opacity=30)"}.iris-ie-lt9 .iris-square .iris-square-handle{background:0;border:3px solid #fff;-ms-filter:"alpha(Opacity=50)"}.iris-picker .iris-strip{margin-right:0;position:relative}.iris-picker .iris-strip .ui-slider-handle{position:absolute;background:0;margin:0;right:-3px;left:-3px;border:4px solid #aaa;border-width:4px 3px;width:auto;height:6px;border-radius:4px;box-shadow:0 1px 2px rgba(0,0,0,.2);opacity:.9;z-index:5;cursor:ns-resize}.iris-strip .ui-slider-handle:before{content:" ";position:absolute;left:-2px;right:-2px;top:-3px;bottom:-3px;border:2px solid #fff;border-radius:3px}.iris-picker .iris-slider-offset{position:absolute;top:11px;left:0;right:0;bottom:-3px;width:auto;height:auto;background:transparent;border:0;top:none;border-radius:0}.iris-picker .iris-square-handle{background:transparent;border:5px solid #aaa;border-radius:50%;border-color:rgba(128,128,128,.5);box-shadow:none;width:12px;height:12px;position:absolute;left:-10px;top:-10px;cursor:move;opacity:1;z-index:10}.iris-picker .ui-state-focus .iris-square-handle{opacity:.8}.iris-picker .iris-square-handle:hover{border-color:#999}.iris-picker .iris-square-value:focus .iris-square-handle{box-shadow:0 0 2px rgba(0,0,0,.75);opacity:.8}.iris-picker .iris-square-handle:hover::after{border-color:#fff}.iris-picker .iris-square-handle::after{position:absolute;bottom:-4px;right:-4px;left:-4px;top:-4px;border:3px solid #f9f9f9;border-color:rgba(255,255,255,.8);border-radius:50%;content:" "}.iris-picker .iris-square-value{width:8px;height:8px;position:absolute}.iris-ie-lt9 .iris-square-value,.iris-mozilla .iris-square-value{width:1px;height:1px}.iris-palette-container{position:absolute;bottom:0;left:0;margin:0;padding:0}.iris-border .iris-palette-container{left:10px;bottom:10px}.iris-picker .iris-palette{margin:0;cursor:pointer}';
+ // Bail for IE <= 7
+ if ( nonGradientIE && IEVersion <= 7 ) {
+ $.fn.iris = $.noop;
+ $.support.iris = false;
+ return;
+ }
+
+ $.support.iris = true;
+
+ function testGradientType() {
+ var el, base;
+
+ if ( nonGradientIE ) {
+ gradientType = 'filter';
+ }
+ else {
+ el = $( '<div id="iris-gradtest" />' );
+ base = 'linear-gradient(top,#fff,#000)';
+ $.each( vendorPrefixes, function( i, val ){
+ el.css( 'backgroundImage', val + base );
+ if ( el.css( 'backgroundImage').match( 'gradient' ) ) {
+ gradientType = i;
+ return false;
+ }
+ });
+ // check for legacy webkit gradient syntax
+ if ( gradientType === false ) {
+ el.css( 'background', '-webkit-gradient(linear,0% 0%,0% 100%,from(#fff),to(#000))' );
+ if ( el.css( 'backgroundImage').match( 'gradient' ) ) {
+ gradientType = 'webkit';
+ }
+ }
+ el.remove();
+ }
+
+ }
+
+ /**
+ * Only for CSS3 gradients. oldIE will use a separate function.
+ *
+ * Accepts as many color stops as necessary from 2nd arg on, or 2nd
+ * arg can be an array of color stops
+ *
+ * @param {string} origin Gradient origin - top or left, defaults to left.
+ * @return {string} Appropriate CSS3 gradient string for use in
+ */
+ function createGradient( origin, stops ) {
+ origin = ( origin === 'top' ) ? 'top' : 'left';
+ stops = $.isArray( stops ) ? stops : Array.prototype.slice.call( arguments, 1 );
+ if ( gradientType === 'webkit' ) {
+ return legacyWebkitGradient( origin, stops );
+ } else {
+ return vendorPrefixes[ gradientType ] + 'linear-gradient(' + origin + ', ' + stops.join(', ') + ')';
+ }
+ }
+
+ /**
+ * Stupid gradients for a stupid browser.
+ */
+ function stupidIEGradient( origin, stops ) {
+ var type, self, lastIndex, filter, startPosProp, endPosProp, dimensionProp, template, html;
+
+ origin = ( origin === 'top' ) ? 'top' : 'left';
+ stops = $.isArray( stops ) ? stops : Array.prototype.slice.call( arguments, 1 );
+ // 8 hex: AARRGGBB
+ // GradientType: 0 vertical, 1 horizontal
+ type = ( origin === 'top' ) ? 0 : 1;
+ self = $( this );
+ lastIndex = stops.length - 1;
+ filter = 'filter';
+ startPosProp = ( type === 1 ) ? 'left' : 'top';
+ endPosProp = ( type === 1 ) ? 'right' : 'bottom';
+ dimensionProp = ( type === 1 ) ? 'height' : 'width';
+ template = '<div class="iris-ie-gradient-shim" style="position:absolute;' + dimensionProp + ':100%;' + startPosProp + ':%start%;' + endPosProp + ':%end%;' + filter + ':%filter%;" data-color:"%color%"></div>';
+ html = '';
+ // need a positioning context
+ if ( self.css('position') === 'static' ) {
+ self.css( {position: 'relative' } );
+ }
+
+ stops = fillColorStops( stops );
+ $.each(stops, function( i, startColor ) {
+ var endColor, endStop, filterVal;
+
+ // we want two at a time. if we're on the last pair, bail.
+ if ( i === lastIndex ) {
+ return false;
+ }
+
+ endColor = stops[ i + 1 ];
+ //if our pairs are at the same color stop, moving along.
+ if ( startColor.stop === endColor.stop ) {
+ return;
+ }
+
+ endStop = 100 - parseFloat( endColor.stop ) + '%';
+ startColor.octoHex = new Color( startColor.color ).toIEOctoHex();
+ endColor.octoHex = new Color( endColor.color ).toIEOctoHex();
+
+ filterVal = 'progid:DXImageTransform.Microsoft.Gradient(GradientType=' + type + ', StartColorStr=\'' + startColor.octoHex + '\', EndColorStr=\'' + endColor.octoHex + '\')';
+ html += template.replace( '%start%', startColor.stop ).replace( '%end%', endStop ).replace( '%filter%', filterVal );
+ });
+ self.find( '.iris-ie-gradient-shim' ).remove();
+ $( html ).prependTo( self );
+ }
+
+ function legacyWebkitGradient( origin, colorList ) {
+ var stops = [];
+ origin = ( origin === 'top' ) ? '0% 0%,0% 100%,' : '0% 100%,100% 100%,';
+ colorList = fillColorStops( colorList );
+ $.each( colorList, function( i, val ){
+ stops.push( 'color-stop(' + ( parseFloat( val.stop ) / 100 ) + ', ' + val.color + ')' );
+ });
+ return '-webkit-gradient(linear,' + origin + stops.join(',') + ')';
+ }
+
+ function fillColorStops( colorList ) {
+ var colors = [],
+ percs = [],
+ newColorList = [],
+ lastIndex = colorList.length - 1;
+
+ $.each( colorList, function( index, val ) {
+ var color = val,
+ perc = false,
+ match = val.match( /1?[0-9]{1,2}%$/ );
+
+ if ( match ) {
+ color = val.replace( /\s?1?[0-9]{1,2}%$/, '' );
+ perc = match.shift();
+ }
+ colors.push( color );
+ percs.push( perc );
+ });
+
+ // back fill first and last
+ if ( percs[0] === false ) {
+ percs[0] = '0%';
+ }
+
+ if ( percs[lastIndex] === false ) {
+ percs[lastIndex] = '100%';
+ }
+
+ percs = backFillColorStops( percs );
+
+ $.each( percs, function( i ){
+ newColorList[i] = { color: colors[i], stop: percs[i] };
+ });
+ return newColorList;
+ }
+
+ function backFillColorStops( stops ) {
+ var first = 0,
+ last = stops.length - 1,
+ i = 0,
+ foundFirst = false,
+ incr,
+ steps,
+ step,
+ firstVal;
+
+ if ( stops.length <= 2 || $.inArray( false, stops ) < 0 ) {
+ return stops;
+ }
+ while ( i < stops.length - 1 ) {
+ if ( ! foundFirst && stops[i] === false ) {
+ first = i - 1;
+ foundFirst = true;
+ } else if ( foundFirst && stops[i] !== false ) {
+ last = i;
+ i = stops.length;
+ }
+ i++;
+ }
+ steps = last - first;
+ firstVal = parseInt( stops[first].replace('%'), 10 );
+ incr = ( parseFloat( stops[last].replace('%') ) - firstVal ) / steps;
+ i = first + 1;
+ step = 1;
+ while ( i < last ) {
+ stops[i] = ( firstVal + ( step * incr ) ) + '%';
+ step++;
+ i++;
+ }
+ return backFillColorStops( stops );
+ }
+
+ $.fn.gradient = function() {
+ var args = arguments;
+ return this.each( function() {
+ // this'll be oldishIE
+ if ( nonGradientIE ) {
+ stupidIEGradient.apply( this, args );
+ } else {
+ // new hotness
+ $( this ).css( 'backgroundImage', createGradient.apply( this, args ) );
+ }
+ });
+ };
+
+ $.fn.raninbowGradient = function( origin, args ) {
+ var opts, template, i, steps;
+
+ origin = origin || 'top';
+ opts = $.extend( {}, { s: 100, l: 50 }, args );
+ template = 'hsl(%h%,' + opts.s + '%,' + opts.l + '%)';
+ i = 0;
+ steps = [];
+ while ( i <= 360 ) {
+ steps.push( template.replace('%h%', i) );
+ i += 30;
+ }
+ return this.each(function() {
+ $(this).gradient( origin, steps );
+ });
+ };
+
+ // the colorpicker widget def.
+ Iris = {
+ options: {
+ color: false,
+ mode: 'hsl',
+ controls: {
+ horiz: 's', // horizontal defaults to saturation
+ vert: 'l', // vertical defaults to lightness
+ strip: 'h' // right strip defaults to hue
+ },
+ hide: true, // hide the color picker by default
+ border: true, // draw a border around the collection of UI elements
+ target: false, // a DOM element / jQuery selector that the element will be appended within. Only used when called on an input.
+ width: 200, // the width of the collection of UI elements
+ palettes: false // show a palette of basic colors beneath the square.
+ },
+ _color: '',
+ _palettes: [ '#000', '#fff', '#d33', '#d93', '#ee2', '#81d742', '#1e73be', '#8224e3' ],
+ _inited: false,
+ _defaultHSLControls: {
+ horiz: 's',
+ vert: 'l',
+ strip: 'h'
+ },
+ _defaultHSVControls: {
+ horiz: 'h',
+ vert: 'v',
+ strip: 's'
+ },
+ _scale: {
+ h: 360,
+ s: 100,
+ l: 100,
+ v: 100
+ },
+ _create: function() {
+ var self = this,
+ el = self.element,
+ color = self.options.color || el.val();
+
+ if ( gradientType === false ) {
+ testGradientType();
+ }
+
+ if ( el.is( 'input' ) ) {
+ if ( self.options.target ) {
+ self.picker = $( _html ).appendTo( self.options.target );
+ } else {
+ self.picker = $( _html ).insertAfter( el );
+ }
+
+ self._addInputListeners( el );
+ } else {
+ el.append( _html );
+ self.picker = el.find( '.iris-picker' );
+ }
+
+ // Browsers / Versions
+ // Feature detection doesn't work for these, and $.browser is deprecated
+ if ( isIE ) {
+ if ( IEVersion === 9 ) {
+ self.picker.addClass( 'iris-ie-9' );
+ } else if ( IEVersion <= 8 ) {
+ self.picker.addClass( 'iris-ie-lt9' );
+ }
+ } else if ( UA.indexOf('compatible') < 0 && UA.indexOf('khtml') < 0 && UA.match( /mozilla/ ) ) {
+ self.picker.addClass( 'iris-mozilla' );
+ }
+
+ if ( self.options.palettes ) {
+ self._addPalettes();
+ }
+
+ self._color = new Color( color ).setHSpace( self.options.mode );
+ self.options.color = self._color.toString();
+
+ // prep 'em for re-use
+ self.controls = {
+ square: self.picker.find( '.iris-square' ),
+ squareDrag: self.picker.find( '.iris-square-value' ),
+ horiz: self.picker.find( '.iris-square-horiz' ),
+ vert: self.picker.find( '.iris-square-vert' ),
+ strip: self.picker.find( '.iris-strip' ),
+ stripSlider: self.picker.find( '.iris-strip .iris-slider-offset' )
+ };
+
+ // small sanity check - if we chose hsv, change default controls away from hsl
+ if ( self.options.mode === 'hsv' && self._has('l', self.options.controls) ) {
+ self.options.controls = self._defaultHSVControls;
+ } else if ( self.options.mode === 'hsl' && self._has('v', self.options.controls) ) {
+ self.options.controls = self._defaultHSLControls;
+ }
+
+ // store it. HSL gets squirrely
+ self.hue = self._color.h();
+
+ if ( self.options.hide ) {
+ self.picker.hide();
+ }
+
+ if ( self.options.border ) {
+ self.picker.addClass( 'iris-border' );
+ }
+
+ self._initControls();
+ self.active = 'external';
+ self._dimensions();
+ self._change();
+ },
+ _has: function(needle, haystack) {
+ var ret = false;
+ $.each(haystack, function(i,v){
+ if ( needle === v ) {
+ ret = true;
+ // exit the loop
+ return false;
+ }
+ });
+ return ret;
+ },
+ _addPalettes: function () {
+ var container = $( '<div class="iris-palette-container" />' ),
+ palette = $( '<a class="iris-palette" tabindex="0" />' ),
+ colors = $.isArray( this.options.palettes ) ? this.options.palettes : this._palettes;
+
+ // do we have an existing container? Empty and reuse it.
+ if ( this.picker.find( '.iris-palette-container' ).length ) {
+ container = this.picker.find( '.iris-palette-container' ).detach().html( '' );
+ }
+
+ $.each(colors, function(index, val) {
+ palette.clone().data( 'color', val )
+ .css( 'backgroundColor', val ).appendTo( container )
+ .height( 10 ).width( 10 );
+ });
+
+ this.picker.append(container);
+ },
+ _paint: function() {
+ var self = this;
+ self._paintDimension( 'top', 'strip' );
+ self._paintDimension( 'top', 'vert' );
+ self._paintDimension( 'left', 'horiz' );
+ },
+ _paintDimension: function( origin, control ) {
+ var self = this,
+ c = self._color,
+ mode = self.options.mode,
+ color = self._getHSpaceColor(),
+ target = self.controls[ control ],
+ controlOpts = self.options.controls,
+ stops;
+
+ // don't paint the active control
+ if ( control === self.active || ( self.active === 'square' && control !== 'strip' ) ) {
+ return;
+ }
+
+ switch ( controlOpts[ control ] ) {
+ case 'h':
+ if ( mode === 'hsv' ) {
+ color = c.clone();
+ switch ( control ) {
+ case 'horiz':
+ color[controlOpts.vert](100);
+ break;
+ case 'vert':
+ color[controlOpts.horiz](100);
+ break;
+ case 'strip':
+ color.setHSpace('hsl');
+ break;
+ }
+ stops = color.toHsl();
+ } else {
+ if ( control === 'strip' ) {
+ stops = { s: color.s, l: color.l };
+ } else {
+ stops = { s: 100, l: color.l };
+ }
+ }
+
+ target.raninbowGradient( origin, stops );
+ break;
+ case 's':
+ if ( mode === 'hsv' ) {
+ if ( control === 'vert' ) {
+ stops = [ c.clone().a(0).s(0).toCSS('rgba'), c.clone().a(1).s(0).toCSS('rgba') ];
+ } else if ( control === 'strip' ) {
+ stops = [ c.clone().s(100).toCSS('hsl'), c.clone().s(0).toCSS('hsl') ];
+ } else if ( control === 'horiz' ) {
+ stops = [ '#fff', 'hsl(' + color.h + ',100%,50%)' ];
+ }
+ } else { // implicit mode === 'hsl'
+ if ( control === 'vert' && self.options.controls.horiz === 'h' ) {
+ stops = ['hsla(0, 0%, ' + color.l + '%, 0)', 'hsla(0, 0%, ' + color.l + '%, 1)'];
+ } else {
+ stops = ['hsl('+ color.h +',0%,50%)', 'hsl(' + color.h + ',100%,50%)'];
+ }
+ }
+
+
+ target.gradient( origin, stops );
+ break;
+ case 'l':
+ if ( control === 'strip' ) {
+ stops = ['hsl(' + color.h + ',100%,100%)', 'hsl(' + color.h + ', ' + color.s + '%,50%)', 'hsl('+ color.h +',100%,0%)'];
+ } else {
+ stops = ['#fff', 'rgba(255,255,255,0) 50%', 'rgba(0,0,0,0) 50%', 'rgba(0,0,0,1)'];
+ }
+ target.gradient( origin, stops );
+ break;
+ case 'v':
+ if ( control === 'strip' ) {
+ stops = [ c.clone().v(100).toCSS(), c.clone().v(0).toCSS() ];
+ } else {
+ stops = ['rgba(0,0,0,0)', '#000'];
+ }
+ target.gradient( origin, stops );
+ break;
+ default:
+ break;
+ }
+ },
+
+ _getHSpaceColor: function() {
+ return ( this.options.mode === 'hsv' ) ? this._color.toHsv() : this._color.toHsl();
+ },
+
+ _dimensions: function( reset ) {
+ // whatever size
+ var self = this,
+ opts = self.options,
+ controls = self.controls,
+ square = controls.square,
+ strip = self.picker.find( '.iris-strip' ),
+ squareWidth = '77.5%',
+ stripWidth = '12%',
+ totalPadding = 20,
+ innerWidth = opts.border ? opts.width - totalPadding : opts.width,
+ controlsHeight,
+ paletteCount = $.isArray( opts.palettes ) ? opts.palettes.length : self._palettes.length,
+ paletteMargin, paletteWidth, paletteContainerWidth;
+
+ if ( reset ) {
+ square.css( 'width', '' );
+ strip.css( 'width', '' );
+ self.picker.css( {width: '', height: ''} );
+ }
+
+ squareWidth = innerWidth * ( parseFloat( squareWidth ) / 100 );
+ stripWidth = innerWidth * ( parseFloat( stripWidth ) / 100 );
+ controlsHeight = opts.border ? squareWidth + totalPadding : squareWidth;
+
+ square.width( squareWidth ).height( squareWidth );
+ strip.height( squareWidth ).width( stripWidth );
+ self.picker.css( { width: opts.width, height: controlsHeight } );
+
+ if ( ! opts.palettes ) {
+ return self.picker.css( 'paddingBottom', '' );
+ }
+
+ // single margin at 2%
+ paletteMargin = squareWidth * 2 / 100;
+ paletteContainerWidth = squareWidth - ( ( paletteCount - 1 ) * paletteMargin );
+ paletteWidth = paletteContainerWidth / paletteCount;
+ self.picker.find('.iris-palette').each( function( i ) {
+ var margin = i === 0 ? 0 : paletteMargin;
+ $( this ).css({
+ width: paletteWidth,
+ height: paletteWidth,
+ marginLeft: margin
+ });
+ });
+ self.picker.css( 'paddingBottom', paletteWidth + paletteMargin );
+ strip.height( paletteWidth + paletteMargin + squareWidth );
+ },
+
+ _addInputListeners: function( input ) {
+ var self = this,
+ debounceTimeout = 100,
+ callback = function( event ){
+ var color = new Color( input.val() ),
+ val = input.val().replace( /^#/, '' );
+
+ input.removeClass( 'iris-error' );
+ // we gave a bad color
+ if ( color.error ) {
+ // don't error on an empty input - we want those allowed
+ if ( val !== '' ) {
+ input.addClass( 'iris-error' );
+ }
+ } else {
+ if ( color.toString() !== self._color.toString() ) {
+ // let's not do this on keyup for hex shortcodes
+ if ( ! ( event.type === 'keyup' && val.match( /^[0-9a-fA-F]{3}$/ ) ) ) {
+ self._setOption( 'color', color.toString() );
+ }
+ }
+ }
+ };
+
+ input.on( 'change', callback ).on( 'keyup', self._debounce( callback, debounceTimeout ) );
+
+ // If we initialized hidden, show on first focus. The rest is up to you.
+ if ( self.options.hide ) {
+ input.one( 'focus', function() {
+ self.show();
+ });
+ }
+ },
+
+ _initControls: function() {
+ var self = this,
+ controls = self.controls,
+ square = controls.square,
+ controlOpts = self.options.controls,
+ stripScale = self._scale[controlOpts.strip];
+
+ controls.stripSlider.slider({
+ orientation: 'vertical',
+ max: stripScale,
+ slide: function( event, ui ) {
+ self.active = 'strip';
+ // "reverse" for hue.
+ if ( controlOpts.strip === 'h' ) {
+ ui.value = stripScale - ui.value;
+ }
+
+ self._color[controlOpts.strip]( ui.value );
+ self._change.apply( self, arguments );
+ }
+ });
+
+ controls.squareDrag.draggable({
+ containment: 'parent',
+ zIndex: 1000,
+ cursor: 'move',
+ drag: function( event, ui ) {
+ self._squareDrag( event, ui );
+ },
+ start: function() {
+ square.addClass( 'iris-dragging' );
+ $(this).addClass( 'ui-state-focus' );
+ },
+ stop: function() {
+ square.removeClass( 'iris-dragging' );
+ $(this).removeClass( 'ui-state-focus' );
+ }
+ }).on( 'mousedown mouseup', function( event ) {
+ var focusClass = 'ui-state-focus';
+ event.preventDefault();
+ if (event.type === 'mousedown' ) {
+ self.picker.find( '.' + focusClass ).removeClass( focusClass ).blur();
+ $(this).addClass( focusClass ).focus();
+ } else {
+ $(this).removeClass( focusClass );
+ }
+ }).on( 'keydown', function( event ) {
+ var container = controls.square,
+ draggable = controls.squareDrag,
+ position = draggable.position(),
+ distance = self.options.width / 100; // Distance in pixels the draggable should be moved: 1 "stop"
+
+ // make alt key go "10"
+ if ( event.altKey ) {
+ distance *= 10;
+ }
+
+ // Reposition if one of the directional keys is pressed
+ switch ( event.keyCode ) {
+ case 37: position.left -= distance; break; // Left
+ case 38: position.top -= distance; break; // Up
+ case 39: position.left += distance; break; // Right
+ case 40: position.top += distance; break; // Down
+ default: return true; // Exit and bubble
+ }
+
+ // Keep draggable within container
+ position.left = Math.max( 0, Math.min( position.left, container.width() ) );
+ position.top = Math.max( 0, Math.min( position.top, container.height() ) );
+
+ draggable.css(position);
+ self._squareDrag( event, { position: position });
+ event.preventDefault();
+ });
+
+ // allow clicking on the square to move there and keep dragging
+ square.mousedown( function( event ) {
+ var squareOffset, pos;
+ // only left click
+ if ( event.which !== 1 ) {
+ return;
+ }
+
+ // prevent bubbling from the handle: no infinite loops
+ if ( ! $( event.target ).is( 'div' ) ) {
+ return;
+ }
+
+ squareOffset = self.controls.square.offset();
+ pos = {
+ top: event.pageY - squareOffset.top,
+ left: event.pageX - squareOffset.left
+ };
+ event.preventDefault();
+ self._squareDrag( event, { position: pos } );
+ event.target = self.controls.squareDrag.get(0);
+ self.controls.squareDrag.css( pos ).trigger( event );
+ });
+
+ // palettes
+ if ( self.options.palettes ) {
+ self._paletteListeners();
+ }
+ },
+
+ _paletteListeners: function() {
+ var self = this;
+ self.picker.find('.iris-palette-container').on('click.palette', '.iris-palette', function() {
+ self._color.fromCSS( $(this).data('color') );
+ self.active = 'external';
+ self._change();
+ }).on( 'keydown.palette', '.iris-palette', function( event ) {
+ if ( ! ( event.keyCode === 13 || event.keyCode === 32 ) ) {
+ return true;
+ }
+ event.stopPropagation();
+ $( this ).click();
+ });
+ },
+
+ _squareDrag: function( event, ui ) {
+ var self = this,
+ controlOpts = self.options.controls,
+ dimensions = self._squareDimensions(),
+ vertVal = Math.round( ( dimensions.h - ui.position.top ) / dimensions.h * self._scale[controlOpts.vert] ),
+ horizVal = self._scale[controlOpts.horiz] - Math.round( ( dimensions.w - ui.position.left ) / dimensions.w * self._scale[controlOpts.horiz] );
+
+ self._color[controlOpts.horiz]( horizVal )[controlOpts.vert]( vertVal );
+
+ self.active = 'square';
+ self._change.apply( self, arguments );
+ },
+
+ _setOption: function( key, value ) {
+ var self = this,
+ oldValue = self.options[key],
+ doDimensions = false,
+ hexLessColor,
+ newColor,
+ method;
+
+ // ensure the new value is set. We can reset to oldValue if some check wasn't met.
+ self.options[key] = value;
+
+ switch(key) {
+ case 'color':
+ // cast to string in case we have a number
+ value = '' + value;
+ hexLessColor = value.replace( /^#/, '' );
+ newColor = new Color( value ).setHSpace( self.options.mode );
+ if ( newColor.error ) {
+ self.options[key] = oldValue;
+ } else {
+ self._color = newColor;
+ self.options.color = self.options[key] = self._color.toString();
+ self.active = 'external';
+ self._change();
+ }
+ break;
+ case 'palettes':
+ doDimensions = true;
+
+ if ( value ) {
+ self._addPalettes();
+ } else {
+ self.picker.find('.iris-palette-container').remove();
+ }
+
+ // do we need to add events?
+ if ( ! oldValue ) {
+ self._paletteListeners();
+ }
+ break;
+ case 'width':
+ doDimensions = true;
+ break;
+ case 'border':
+ doDimensions = true;
+ method = value ? 'addClass' : 'removeClass';
+ self.picker[method]('iris-border');
+ break;
+ case 'mode':
+ case 'controls':
+ // if nothing's changed, let's bail, since this causes re-rendering the whole widget
+ if ( oldValue === value ) {
+ return;
+ }
+
+ // we're using these poorly named variables because they're already scoped.
+ // method is the element that Iris was called on. oldValue will be the options
+ method = self.element;
+ oldValue = self.options;
+ oldValue.hide = ! self.picker.is( ':visible' );
+ self.destroy();
+ self.picker.remove();
+ return $(self.element).iris(oldValue);
+ }
+
+ // Do we need to recalc dimensions?
+ if ( doDimensions ) {
+ self._dimensions(true);
+ }
+ },
+
+ _squareDimensions: function( forceRefresh ) {
+ var square = this.controls.square,
+ dimensions,
+ control;
+
+ if ( forceRefresh !== undef && square.data('dimensions') ) {
+ return square.data('dimensions');
+ }
+
+ control = this.controls.squareDrag;
+ dimensions = {
+ w: square.width(),
+ h: square.height()
+ };
+ square.data( 'dimensions', dimensions );
+ return dimensions;
+ },
+
+ _isNonHueControl: function( active, type ) {
+ if ( active === 'square' && this.options.controls.strip === 'h' ) {
+ return true;
+ } else if ( type === 'external' || ( type === 'h' && active === 'strip' ) ) {
+ return false;
+ }
+
+ return true;
+ },
+
+ _change: function() {
+ var self = this,
+ controls = self.controls,
+ color = self._getHSpaceColor(),
+ actions = [ 'square', 'strip' ],
+ controlOpts = self.options.controls,
+ type = controlOpts[self.active] || 'external',
+ oldHue = self.hue;
+
+ if ( self.active === 'strip' ) {
+ // take no action on any of the square sliders if we adjusted the strip
+ actions = [];
+ } else if ( self.active !== 'external' ) {
+ // for non-strip, non-external, strip should never change
+ actions.pop(); // conveniently the last item
+ }
+
+ $.each( actions, function(index, item) {
+ var value, dimensions, cssObj;
+ if ( item !== self.active ) {
+ switch ( item ) {
+ case 'strip':
+ // reverse for hue
+ value = ( controlOpts.strip === 'h' ) ? self._scale[controlOpts.strip] - color[controlOpts.strip] : color[controlOpts.strip];
+ controls.stripSlider.slider( 'value', value );
+ break;
+ case 'square':
+ dimensions = self._squareDimensions();
+ cssObj = {
+ left: color[controlOpts.horiz] / self._scale[controlOpts.horiz] * dimensions.w,
+ top: dimensions.h - ( color[controlOpts.vert] / self._scale[controlOpts.vert] * dimensions.h )
+ };
+
+ self.controls.squareDrag.css( cssObj );
+ break;
+ }
+ }
+ });
+
+ // Ensure that we don't change hue if we triggered a hue reset
+ if ( color.h !== oldHue && self._isNonHueControl( self.active, type ) ) {
+ self._color.h(oldHue);
+ }
+
+ // store hue for repeating above check next time
+ self.hue = self._color.h();
+
+ self.options.color = self._color.toString();
+
+ // only run after the first time
+ if ( self._inited ) {
+ self._trigger( 'change', { type: self.active }, { color: self._color } );
+ }
+
+ if ( self.element.is( ':input' ) && ! self._color.error ) {
+ self.element.removeClass( 'iris-error' );
+ if ( self.element.val() !== self._color.toString() ) {
+ self.element.val( self._color.toString() );
+ }
+ }
+
+ self._paint();
+ self._inited = true;
+ self.active = false;
+ },
+ // taken from underscore.js _.debounce method
+ _debounce: function( func, wait, immediate ) {
+ var timeout, result;
+ return function() {
+ var context = this,
+ args = arguments,
+ later,
+ callNow;
+
+ later = function() {
+ timeout = null;
+ if ( ! immediate) {
+ result = func.apply( context, args );
+ }
+ };
+
+ callNow = immediate && !timeout;
+ clearTimeout( timeout );
+ timeout = setTimeout( later, wait );
+ if ( callNow ) {
+ result = func.apply( context, args );
+ }
+ return result;
+ };
+ },
+ show: function() {
+ this.picker.show();
+ },
+ hide: function() {
+ this.picker.hide();
+ },
+ toggle: function() {
+ this.picker.toggle();
+ },
+ color: function(newColor) {
+ if ( newColor === true ) {
+ return this._color.clone();
+ } else if ( newColor === undef ) {
+ return this._color.toString();
+ }
+ this.option('color', newColor);
+ }
+ };
+ // initialize the widget
+ $.widget( 'a8c.iris', Iris );
+ // add CSS
+ $( '<style id="iris-css">' + _css + '</style>' ).appendTo( 'head' );
+
+}( jQuery ));
+/*! Color.js - v0.9.9 - 2012-11-20
+* https://github.com/Automattic/Color.js
+* Copyright (c) 2012 Matt Wiebe; Licensed GPL v2 */
+
+(function(exports, undef) {
+
+ var Color = function( color, type ) {
+ if ( ! ( this instanceof Color ) )
+ return new Color( color, type );
+
+ return this._init( color, type );
+ };
+
+ Color.fn = Color.prototype = {
+ _color: 0,
+ _alpha: 1,
+ error: false,
+ // for preserving hue/sat in fromHsl().toHsl() flows
+ _hsl: { h: 0, s: 0, l: 0 },
+ // for preserving hue/sat in fromHsv().toHsv() flows
+ _hsv: { h: 0, s: 0, v: 0 },
+ // for setting hsl or hsv space - needed for .h() & .s() functions to function properly
+ _hSpace: 'hsl',
+ _init: function( color ) {
+ var func = 'noop';
+ switch ( typeof color ) {
+ case 'object':
+ // alpha?
+ if ( color.a !== undef )
+ this.a( color.a );
+ func = ( color.r !== undef ) ? 'fromRgb' :
+ ( color.l !== undef ) ? 'fromHsl' :
+ ( color.v !== undef ) ? 'fromHsv' : func;
+ return this[func]( color );
+ case 'string':
+ return this.fromCSS( color );
+ case 'number':
+ return this.fromInt( parseInt( color, 10 ) );
+ }
+ return this;
+ },
+
+ _error: function() {
+ this.error = true;
+ return this;
+ },
+
+ clone: function() {
+ var newColor = new Color( this.toInt() ),
+ copy = ['_alpha', '_hSpace', '_hsl', '_hsv', 'error'];
+ for ( var i = copy.length - 1; i >= 0; i-- ) {
+ newColor[ copy[i] ] = this[ copy[i] ];
+ }
+ return newColor;
+ },
+
+ setHSpace: function( space ) {
+ this._hSpace = ( space === 'hsv' ) ? space : 'hsl';
+ return this;
+ },
+
+ noop: function() {
+ return this;
+ },
+
+ fromCSS: function( color ) {
+ var nums, list,
+ leadingRE = /^(rgb|hs(l|v))a?\(/;
+ this.error = false;
+
+ // whitespace and semicolon trim
+ color = color.replace(/^\s+/, '').replace(/\s+$/, '').replace(/;$/, '');
+
+ if ( color.match(leadingRE) && color.match(/\)$/) ) {
+ list = color.replace(/(\s|%)/g, '').replace(leadingRE, '').replace(/,?\);?$/, '').split(',');
+
+ if ( list.length < 3 )
+ return this._error();
+
+ if ( list.length === 4 ) {
+ this.a( parseFloat( list.pop() ) );
+ // error state has been set to true in .a() if we passed NaN
+ if ( this.error )
+ return this;
+ }
+
+ for (var i = list.length - 1; i >= 0; i--) {
+ list[i] = parseInt(list[i], 10);
+ if ( isNaN( list[i] ) )
+ return this._error();
+ }
+
+ if ( color.match(/^rgb/) ) {
+ return this.fromRgb( {
+ r: list[0],
+ g: list[1],
+ b: list[2]
+ } );
+ } else if ( color.match(/^hsv/) ) {
+ return this.fromHsv( {
+ h: list[0],
+ s: list[1],
+ v: list[2]
+ } );
+ } else {
+ return this.fromHsl( {
+ h: list[0],
+ s: list[1],
+ l: list[2]
+ } );
+ }
+ } else {
+ // must be hex amirite?
+ return this.fromHex( color );
+ }
+ },
+
+ fromRgb: function( rgb, preserve ) {
+ if ( typeof rgb !== 'object' || rgb.r === undef || rgb.g === undef || rgb.b === undef )
+ return this._error();
+
+ this.error = false;
+ return this.fromInt( parseInt( ( rgb.r << 16 ) + ( rgb.g << 8 ) + rgb.b, 10 ), preserve );
+ },
+
+ fromHex: function( color ) {
+ color = color.replace(/^#/, '').replace(/^0x/, '');
+ if ( color.length === 3 ) {
+ color = color[0] + color[0] + color[1] + color[1] + color[2] + color[2];
+ }
+
+ // rough error checking - this is where things go squirrely the most
+ this.error = ! /^[0-9A-F]{6}$/i.test( color );
+ return this.fromInt( parseInt( color, 16 ) );
+ },
+
+ fromHsl: function( hsl ) {
+ var r, g, b, q, p, h, s, l;
+
+ if ( typeof hsl !== 'object' || hsl.h === undef || hsl.s === undef || hsl.l === undef )
+ return this._error();
+
+ this._hsl = hsl; // store it
+ this._hSpace = 'hsl'; // implicit
+ h = hsl.h / 360; s = hsl.s / 100; l = hsl.l / 100;
+ if ( s === 0 ) {
+ r = g = b = l; // achromatic
+ }
+ else {
+ q = l < 0.5 ? l * ( 1 + s ) : l + s - l * s;
+ p = 2 * l - q;
+ r = this.hue2rgb( p, q, h + 1/3 );
+ g = this.hue2rgb( p, q, h );
+ b = this.hue2rgb( p, q, h - 1/3 );
+ }
+ return this.fromRgb( {
+ r: r * 255,
+ g: g * 255,
+ b: b * 255
+ }, true ); // true preserves hue/sat
+ },
+
+ fromHsv: function( hsv ) {
+ var h, s, v, r, g, b, i, f, p, q, t;
+ if ( typeof hsv !== 'object' || hsv.h === undef || hsv.s === undef || hsv.v === undef )
+ return this._error();
+
+ this._hsv = hsv; // store it
+ this._hSpace = 'hsv'; // implicit
+
+ h = hsv.h / 360; s = hsv.s / 100; v = hsv.v / 100;
+ i = Math.floor( h * 6 );
+ f = h * 6 - i;
+ p = v * ( 1 - s );
+ q = v * ( 1 - f * s );
+ t = v * ( 1 - ( 1 - f ) * s );
+
+ switch( i % 6 ) {
+ case 0:
+ r = v; g = t; b = p;
+ break;
+ case 1:
+ r = q; g = v; b = p;
+ break;
+ case 2:
+ r = p; g = v; b = t;
+ break;
+ case 3:
+ r = p; g = q; b = v;
+ break;
+ case 4:
+ r = t; g = p; b = v;
+ break;
+ case 5:
+ r = v; g = p; b = q;
+ break;
+ }
+
+ return this.fromRgb( {
+ r: r * 255,
+ g: g * 255,
+ b: b * 255
+ }, true ); // true preserves hue/sat
+
+ },
+ // everything comes down to fromInt
+ fromInt: function( color, preserve ) {
+ this._color = parseInt( color, 10 );
+
+ if ( isNaN( this._color ) )
+ this._color = 0;
+
+ // let's coerce things
+ if ( this._color > 16777215 )
+ this._color = 16777215;
+ else if ( this._color < 0 )
+ this._color = 0;
+
+ // let's not do weird things
+ if ( preserve === undef ) {
+ this._hsv.h = this._hsv.s = this._hsl.h = this._hsl.s = 0;
+ }
+ // EVENT GOES HERE
+ return this;
+ },
+
+ hue2rgb: function( p, q, t ) {
+ if ( t < 0 ) {
+ t += 1;
+ }
+ if ( t > 1 ) {
+ t -= 1;
+ }
+ if ( t < 1/6 ) {
+ return p + ( q - p ) * 6 * t;
+ }
+ if ( t < 1/2 ) {
+ return q;
+ }
+ if ( t < 2/3 ) {
+ return p + ( q - p ) * ( 2/3 - t ) * 6;
+ }
+ return p;
+ },
+
+ toString: function() {
+ var hex = parseInt( this._color, 10 ).toString( 16 );
+ if ( this.error )
+ return '';
+ // maybe left pad it
+ if ( hex.length < 6 ) {
+ for (var i = 6 - hex.length - 1; i >= 0; i--) {
+ hex = '0' + hex;
+ }
+ }
+ return '#' + hex;
+ },
+
+ toCSS: function( type, alpha ) {
+ type = type || 'hex';
+ alpha = parseFloat( alpha || this._alpha );
+ switch ( type ) {
+ case 'rgb':
+ case 'rgba':
+ var rgb = this.toRgb();
+ if ( alpha < 1 ) {
+ return "rgba( " + rgb.r + ", " + rgb.g + ", " + rgb.b + ", " + alpha + " )";
+ }
+ else {
+ return "rgb( " + rgb.r + ", " + rgb.g + ", " + rgb.b + " )";
+ }
+ break;
+ case 'hsl':
+ case 'hsla':
+ var hsl = this.toHsl();
+ if ( alpha < 1 ) {
+ return "hsla( " + hsl.h + ", " + hsl.s + "%, " + hsl.l + "%, " + alpha + " )";
+ }
+ else {
+ return "hsl( " + hsl.h + ", " + hsl.s + "%, " + hsl.l + "% )";
+ }
+ break;
+ default:
+ return this.toString();
+ }
+ },
+
+ toRgb: function() {
+ return {
+ r: 255 & ( this._color >> 16 ),
+ g: 255 & ( this._color >> 8 ),
+ b: 255 & ( this._color )
+ };
+ },
+
+ toHsl: function() {
+ var rgb = this.toRgb();
+ var r = rgb.r / 255, g = rgb.g / 255, b = rgb.b / 255;
+ var max = Math.max( r, g, b ), min = Math.min( r, g, b );
+ var h, s, l = ( max + min ) / 2;
+
+ if ( max === min ) {
+ h = s = 0; // achromatic
+ } else {
+ var d = max - min;
+ s = l > 0.5 ? d / ( 2 - max - min ) : d / ( max + min );
+ switch ( max ) {
+ case r: h = ( g - b ) / d + ( g < b ? 6 : 0 );
+ break;
+ case g: h = ( b - r ) / d + 2;
+ break;
+ case b: h = ( r - g ) / d + 4;
+ break;
+ }
+ h /= 6;
+ }
+
+ // maintain hue & sat if we've been manipulating things in the HSL space.
+ h = Math.round( h * 360 );
+ if ( h === 0 && this._hsl.h !== h ) {
+ h = this._hsl.h;
+ }
+ s = Math.round( s * 100 );
+ if ( s === 0 && this._hsl.s ) {
+ s = this._hsl.s;
+ }
+
+ return {
+ h: h,
+ s: s,
+ l: Math.round( l * 100 )
+ };
+
+ },
+
+ toHsv: function() {
+ var rgb = this.toRgb();
+ var r = rgb.r / 255, g = rgb.g / 255, b = rgb.b / 255;
+ var max = Math.max( r, g, b ), min = Math.min( r, g, b );
+ var h, s, v = max;
+ var d = max - min;
+ s = max === 0 ? 0 : d / max;
+
+ if ( max === min ) {
+ h = s = 0; // achromatic
+ } else {
+ switch( max ){
+ case r:
+ h = ( g - b ) / d + ( g < b ? 6 : 0 );
+ break;
+ case g:
+ h = ( b - r ) / d + 2;
+ break;
+ case b:
+ h = ( r - g ) / d + 4;
+ break;
+ }
+ h /= 6;
+ }
+
+ // maintain hue & sat if we've been manipulating things in the HSV space.
+ h = Math.round( h * 360 );
+ if ( h === 0 && this._hsv.h !== h ) {
+ h = this._hsv.h;
+ }
+ s = Math.round( s * 100 );
+ if ( s === 0 && this._hsv.s ) {
+ s = this._hsv.s;
+ }
+
+ return {
+ h: h,
+ s: s,
+ v: Math.round( v * 100 )
+ };
+ },
+
+ toInt: function() {
+ return this._color;
+ },
+
+ toIEOctoHex: function() {
+ // AARRBBGG
+ var hex = this.toString();
+ var AA = parseInt( 255 * this._alpha, 10 ).toString(16);
+ if ( AA.length === 1 ) {
+ AA = '0' + AA;
+ }
+ return '#' + AA + hex.replace(/^#/, '' );
+ },
+
+ toLuminosity: function() {
+ var rgb = this.toRgb();
+ return 0.2126 * Math.pow( rgb.r / 255, 2.2 ) + 0.7152 * Math.pow( rgb.g / 255, 2.2 ) + 0.0722 * Math.pow( rgb.b / 255, 2.2);
+ },
+
+ getDistanceLuminosityFrom: function( color ) {
+ if ( ! ( color instanceof Color ) ) {
+ throw 'getDistanceLuminosityFrom requires a Color object';
+ }
+ var lum1 = this.toLuminosity();
+ var lum2 = color.toLuminosity();
+ if ( lum1 > lum2 ) {
+ return ( lum1 + 0.05 ) / ( lum2 + 0.05 );
+ }
+ else {
+ return ( lum2 + 0.05 ) / ( lum1 + 0.05 );
+ }
+ },
+
+ getMaxContrastColor: function() {
+ var lum = this.toLuminosity();
+ var hex = ( lum >= 0.5 ) ? '000000' : 'ffffff';
+ return new Color( hex );
+ },
+
+ getGrayscaleContrastingColor: function( contrast ) {
+ if ( ! contrast ) {
+ return this.getMaxContrastColor();
+ }
+
+ // don't allow less than 5
+ var target_contrast = ( contrast < 5 ) ? 5 : contrast;
+ var color = this.getMaxContrastColor();
+ contrast = color.getDistanceLuminosityFrom( this );
+
+ // if current max contrast is less than the target contrast, we had wishful thinking.
+ if ( contrast <= target_contrast ) {
+ return color;
+ }
+
+ var incr = ( 0 === color.toInt() ) ? 1 : -1;
+
+ while ( contrast > target_contrast ) {
+ color = color.incrementLightness( incr );
+ contrast = color.getDistanceLuminosityFrom( this );
+ }
+
+ return color;
+ },
+
+ getReadableContrastingColor: function( bgColor, minContrast ) {
+ if ( ! bgColor instanceof Color ) {
+ return this;
+ }
+
+ // you shouldn't use less than 5, but you might want to.
+ var targetContrast = ( minContrast === undef ) ? 5 : minContrast;
+ // working things
+ var contrast = bgColor.getDistanceLuminosityFrom( this );
+ var maxContrastColor = bgColor.getMaxContrastColor();
+ var maxContrast = maxContrastColor.getDistanceLuminosityFrom( bgColor );
+
+ // if current max contrast is less than the target contrast, we had wishful thinking.
+ // still, go max
+ if ( maxContrast <= targetContrast ) {
+ return maxContrastColor;
+ }
+ // or, we might already have sufficient contrast
+ else if ( contrast >= targetContrast ) {
+ return this;
+ }
+
+ var incr = ( 0 === maxContrastColor.toInt() ) ? -1 : 1;
+ while ( contrast < targetContrast ) {
+ this.incrementLightness( incr );
+ contrast = this.getDistanceLuminosityFrom( bgColor );
+ // infininite loop prevention: you never know.
+ if ( this._color === 0 || this._color === 16777215 ) {
+ break;
+ }
+ }
+
+ return this;
+
+ },
+
+ a: function( val ) {
+ if ( val === undef )
+ return this._alpha;
+
+ var a = parseFloat( val );
+
+ if ( isNaN( a ) )
+ return this._error();
+
+ this._alpha = a;
+ return this;
+ },
+
+ // TRANSFORMS
+
+ darken: function( amount ) {
+ amount = amount || 5;
+ return this.l( - amount, true );
+ },
+
+ lighten: function( amount ) {
+ amount = amount || 5;
+ return this.l( amount, true );
+ },
+
+ saturate: function( amount ) {
+ amount = amount || 15;
+ return this.s( amount, true );
+ },
+
+ desaturate: function( amount ) {
+ amount = amount || 15;
+ return this.s( - amount, true );
+ },
+
+ toGrayscale: function() {
+ return this.setHSpace('hsl').s( 0 );
+ },
+
+ getComplement: function() {
+ return this.h( 180, true );
+ },
+
+ getSplitComplement: function( step ) {
+ step = step || 1;
+ var incr = 180 + ( step * 30 );
+ return this.h( incr, true );
+ },
+
+ getAnalog: function( step ) {
+ step = step || 1;
+ var incr = step * 30;
+ return this.h( incr, true );
+ },
+
+ getTetrad: function( step ) {
+ step = step || 1;
+ var incr = step * 60;
+ return this.h( incr, true );
+ },
+
+ getTriad: function( step ) {
+ step = step || 1;
+ var incr = step * 120;
+ return this.h( incr, true );
+ },
+
+ _partial: function( key ) {
+ var prop = shortProps[key];
+ return function( val, incr ) {
+ var color = this._spaceFunc('to', prop.space);
+
+ // GETTER
+ if ( val === undef )
+ return color[key];
+
+ // INCREMENT
+ if ( incr === true )
+ val = color[key] + val;
+
+ // MOD & RANGE
+ if ( prop.mod )
+ val = val % prop.mod;
+ if ( prop.range )
+ val = ( val < prop.range[0] ) ? prop.range[0] : ( val > prop.range[1] ) ? prop.range[1] : val;
+
+ // NEW VALUE
+ color[key] = val;
+
+ return this._spaceFunc('from', prop.space, color);
+ };
+ },
+
+ _spaceFunc: function( dir, s, val ) {
+ var space = s || this._hSpace,
+ funcName = dir + space.charAt(0).toUpperCase() + space.substr(1);
+ return this[funcName](val);
+ }
+ };
+
+ var shortProps = {
+ h: {
+ mod: 360
+ },
+ s: {
+ range: [0,100]
+ },
+ l: {
+ space: 'hsl',
+ range: [0,100]
+ },
+ v: {
+ space: 'hsv',
+ range: [0,100]
+ },
+ r: {
+ space: 'rgb',
+ range: [0,255]
+ },
+ g: {
+ space: 'rgb',
+ range: [0,255]
+ },
+ b: {
+ space: 'rgb',
+ range: [0,255]
+ }
+ };
+
+ for ( var key in shortProps ) {
+ if ( shortProps.hasOwnProperty( key ) )
+ Color.fn[key] = Color.fn._partial(key);
+ }
+
+ exports.Color = Color;
+
+}(typeof exports === 'object' && exports || this));
diff --git a/debian/missing-sources/jquery-ui/jquery-ui.js b/debian/missing-sources/jquery-ui/jquery-ui.js
new file mode 100644
index 0000000..7b727e7
--- /dev/null
+++ b/debian/missing-sources/jquery-ui/jquery-ui.js
@@ -0,0 +1,15003 @@
+/*! jQuery UI - v1.10.3 - 2013-05-03
+* http://jqueryui.com
+* Includes: jquery.ui.core.js, jquery.ui.widget.js, jquery.ui.mouse.js, jquery.ui.draggable.js, jquery.ui.droppable.js, jquery.ui.resizable.js, jquery.ui.selectable.js, jquery.ui.sortable.js, jquery.ui.effect.js, jquery.ui.accordion.js, jquery.ui.autocomplete.js, jquery.ui.button.js, jquery.ui.datepicker.js, jquery.ui.dialog.js, jquery.ui.effect-blind.js, jquery.ui.effect-bounce.js, jquery.ui.effect-clip.js, jquery.ui.effect-drop.js, jquery.ui.effect-explode.js, jquery.ui.effect-fade.js, jquery.ui.effect-fold.js, jquery.ui.effect-highlight.js, jquery.ui.effect-pulsate.js, jquery.ui.effect-scale.js, jquery.ui.effect-shake.js, jquery.ui.effect-slide.js, jquery.ui.effect-transfer.js, jquery.ui.menu.js, jquery.ui.position.js, jquery.ui.progressbar.js, jquery.ui.slider.js, jquery.ui.spinner.js, jquery.ui.tabs.js, jquery.ui.tooltip.js
+* Copyright 2013 jQuery Foundation and other contributors; Licensed MIT */
+(function( $, undefined ) {
+
+var uuid = 0,
+ runiqueId = /^ui-id-\d+$/;
+
+// $.ui might exist from components with no dependencies, e.g., $.ui.position
+$.ui = $.ui || {};
+
+$.extend( $.ui, {
+ version: "1.10.3",
+
+ keyCode: {
+ BACKSPACE: 8,
+ COMMA: 188,
+ DELETE: 46,
+ DOWN: 40,
+ END: 35,
+ ENTER: 13,
+ ESCAPE: 27,
+ HOME: 36,
+ LEFT: 37,
+ NUMPAD_ADD: 107,
+ NUMPAD_DECIMAL: 110,
+ NUMPAD_DIVIDE: 111,
+ NUMPAD_ENTER: 108,
+ NUMPAD_MULTIPLY: 106,
+ NUMPAD_SUBTRACT: 109,
+ PAGE_DOWN: 34,
+ PAGE_UP: 33,
+ PERIOD: 190,
+ RIGHT: 39,
+ SPACE: 32,
+ TAB: 9,
+ UP: 38
+ }
+});
+
+// plugins
+$.fn.extend({
+ focus: (function( orig ) {
+ return function( delay, fn ) {
+ return typeof delay === "number" ?
+ this.each(function() {
+ var elem = this;
+ setTimeout(function() {
+ $( elem ).focus();
+ if ( fn ) {
+ fn.call( elem );
+ }
+ }, delay );
+ }) :
+ orig.apply( this, arguments );
+ };
+ })( $.fn.focus ),
+
+ scrollParent: function() {
+ var scrollParent;
+ if (($.ui.ie && (/(static|relative)/).test(this.css("position"))) || (/absolute/).test(this.css("position"))) {
+ scrollParent = this.parents().filter(function() {
+ return (/(relative|absolute|fixed)/).test($.css(this,"position")) && (/(auto|scroll)/).test($.css(this,"overflow")+$.css(this,"overflow-y")+$.css(this,"overflow-x"));
+ }).eq(0);
+ } else {
+ scrollParent = this.parents().filter(function() {
+ return (/(auto|scroll)/).test($.css(this,"overflow")+$.css(this,"overflow-y")+$.css(this,"overflow-x"));
+ }).eq(0);
+ }
+
+ return (/fixed/).test(this.css("position")) || !scrollParent.length ? $(document) : scrollParent;
+ },
+
+ zIndex: function( zIndex ) {
+ if ( zIndex !== undefined ) {
+ return this.css( "zIndex", zIndex );
+ }
+
+ if ( this.length ) {
+ var elem = $( this[ 0 ] ), position, value;
+ while ( elem.length && elem[ 0 ] !== document ) {
+ // Ignore z-index if position is set to a value where z-index is ignored by the browser
+ // This makes behavior of this function consistent across browsers
+ // WebKit always returns auto if the element is positioned
+ position = elem.css( "position" );
+ if ( position === "absolute" || position === "relative" || position === "fixed" ) {
+ // IE returns 0 when zIndex is not specified
+ // other browsers return a string
+ // we ignore the case of nested elements with an explicit value of 0
+ // <div style="z-index: -10;"><div style="z-index: 0;"></div></div>
+ value = parseInt( elem.css( "zIndex" ), 10 );
+ if ( !isNaN( value ) && value !== 0 ) {
+ return value;
+ }
+ }
+ elem = elem.parent();
+ }
+ }
+
+ return 0;
+ },
+
+ uniqueId: function() {
+ return this.each(function() {
+ if ( !this.id ) {
+ this.id = "ui-id-" + (++uuid);
+ }
+ });
+ },
+
+ removeUniqueId: function() {
+ return this.each(function() {
+ if ( runiqueId.test( this.id ) ) {
+ $( this ).removeAttr( "id" );
+ }
+ });
+ }
+});
+
+// selectors
+function focusable( element, isTabIndexNotNaN ) {
+ var map, mapName, img,
+ nodeName = element.nodeName.toLowerCase();
+ if ( "area" === nodeName ) {
+ map = element.parentNode;
+ mapName = map.name;
+ if ( !element.href || !mapName || map.nodeName.toLowerCase() !== "map" ) {
+ return false;
+ }
+ img = $( "img[usemap=#" + mapName + "]" )[0];
+ return !!img && visible( img );
+ }
+ return ( /input|select|textarea|button|object/.test( nodeName ) ?
+ !element.disabled :
+ "a" === nodeName ?
+ element.href || isTabIndexNotNaN :
+ isTabIndexNotNaN) &&
+ // the element and all of its ancestors must be visible
+ visible( element );
+}
+
+function visible( element ) {
+ return $.expr.filters.visible( element ) &&
+ !$( element ).parents().addBack().filter(function() {
+ return $.css( this, "visibility" ) === "hidden";
+ }).length;
+}
+
+$.extend( $.expr[ ":" ], {
+ data: $.expr.createPseudo ?
+ $.expr.createPseudo(function( dataName ) {
+ return function( elem ) {
+ return !!$.data( elem, dataName );
+ };
+ }) :
+ // support: jQuery <1.8
+ function( elem, i, match ) {
+ return !!$.data( elem, match[ 3 ] );
+ },
+
+ focusable: function( element ) {
+ return focusable( element, !isNaN( $.attr( element, "tabindex" ) ) );
+ },
+
+ tabbable: function( element ) {
+ var tabIndex = $.attr( element, "tabindex" ),
+ isTabIndexNaN = isNaN( tabIndex );
+ return ( isTabIndexNaN || tabIndex >= 0 ) && focusable( element, !isTabIndexNaN );
+ }
+});
+
+// support: jQuery <1.8
+if ( !$( "<a>" ).outerWidth( 1 ).jquery ) {
+ $.each( [ "Width", "Height" ], function( i, name ) {
+ var side = name === "Width" ? [ "Left", "Right" ] : [ "Top", "Bottom" ],
+ type = name.toLowerCase(),
+ orig = {
+ innerWidth: $.fn.innerWidth,
+ innerHeight: $.fn.innerHeight,
+ outerWidth: $.fn.outerWidth,
+ outerHeight: $.fn.outerHeight
+ };
+
+ function reduce( elem, size, border, margin ) {
+ $.each( side, function() {
+ size -= parseFloat( $.css( elem, "padding" + this ) ) || 0;
+ if ( border ) {
+ size -= parseFloat( $.css( elem, "border" + this + "Width" ) ) || 0;
+ }
+ if ( margin ) {
+ size -= parseFloat( $.css( elem, "margin" + this ) ) || 0;
+ }
+ });
+ return size;
+ }
+
+ $.fn[ "inner" + name ] = function( size ) {
+ if ( size === undefined ) {
+ return orig[ "inner" + name ].call( this );
+ }
+
+ return this.each(function() {
+ $( this ).css( type, reduce( this, size ) + "px" );
+ });
+ };
+
+ $.fn[ "outer" + name] = function( size, margin ) {
+ if ( typeof size !== "number" ) {
+ return orig[ "outer" + name ].call( this, size );
+ }
+
+ return this.each(function() {
+ $( this).css( type, reduce( this, size, true, margin ) + "px" );
+ });
+ };
+ });
+}
+
+// support: jQuery <1.8
+if ( !$.fn.addBack ) {
+ $.fn.addBack = function( selector ) {
+ return this.add( selector == null ?
+ this.prevObject : this.prevObject.filter( selector )
+ );
+ };
+}
+
+// support: jQuery 1.6.1, 1.6.2 (http://bugs.jquery.com/ticket/9413)
+if ( $( "<a>" ).data( "a-b", "a" ).removeData( "a-b" ).data( "a-b" ) ) {
+ $.fn.removeData = (function( removeData ) {
+ return function( key ) {
+ if ( arguments.length ) {
+ return removeData.call( this, $.camelCase( key ) );
+ } else {
+ return removeData.call( this );
+ }
+ };
+ })( $.fn.removeData );
+}
+
+
+
+
+
+// deprecated
+$.ui.ie = !!/msie [\w.]+/.exec( navigator.userAgent.toLowerCase() );
+
+$.support.selectstart = "onselectstart" in document.createElement( "div" );
+$.fn.extend({
+ disableSelection: function() {
+ return this.bind( ( $.support.selectstart ? "selectstart" : "mousedown" ) +
+ ".ui-disableSelection", function( event ) {
+ event.preventDefault();
+ });
+ },
+
+ enableSelection: function() {
+ return this.unbind( ".ui-disableSelection" );
+ }
+});
+
+$.extend( $.ui, {
+ // $.ui.plugin is deprecated. Use $.widget() extensions instead.
+ plugin: {
+ add: function( module, option, set ) {
+ var i,
+ proto = $.ui[ module ].prototype;
+ for ( i in set ) {
+ proto.plugins[ i ] = proto.plugins[ i ] || [];
+ proto.plugins[ i ].push( [ option, set[ i ] ] );
+ }
+ },
+ call: function( instance, name, args ) {
+ var i,
+ set = instance.plugins[ name ];
+ if ( !set || !instance.element[ 0 ].parentNode || instance.element[ 0 ].parentNode.nodeType === 11 ) {
+ return;
+ }
+
+ for ( i = 0; i < set.length; i++ ) {
+ if ( instance.options[ set[ i ][ 0 ] ] ) {
+ set[ i ][ 1 ].apply( instance.element, args );
+ }
+ }
+ }
+ },
+
+ // only used by resizable
+ hasScroll: function( el, a ) {
+
+ //If overflow is hidden, the element might have extra content, but the user wants to hide it
+ if ( $( el ).css( "overflow" ) === "hidden") {
+ return false;
+ }
+
+ var scroll = ( a && a === "left" ) ? "scrollLeft" : "scrollTop",
+ has = false;
+
+ if ( el[ scroll ] > 0 ) {
+ return true;
+ }
+
+ // TODO: determine which cases actually cause this to happen
+ // if the element doesn't have the scroll set, see if it's possible to
+ // set the scroll
+ el[ scroll ] = 1;
+ has = ( el[ scroll ] > 0 );
+ el[ scroll ] = 0;
+ return has;
+ }
+});
+
+})( jQuery );
+
+(function( $, undefined ) {
+
+var uuid = 0,
+ slice = Array.prototype.slice,
+ _cleanData = $.cleanData;
+$.cleanData = function( elems ) {
+ for ( var i = 0, elem; (elem = elems[i]) != null; i++ ) {
+ try {
+ $( elem ).triggerHandler( "remove" );
+ // http://bugs.jquery.com/ticket/8235
+ } catch( e ) {}
+ }
+ _cleanData( elems );
+};
+
+$.widget = function( name, base, prototype ) {
+ var fullName, existingConstructor, constructor, basePrototype,
+ // proxiedPrototype allows the provided prototype to remain unmodified
+ // so that it can be used as a mixin for multiple widgets (#8876)
+ proxiedPrototype = {},
+ namespace = name.split( "." )[ 0 ];
+
+ name = name.split( "." )[ 1 ];
+ fullName = namespace + "-" + name;
+
+ if ( !prototype ) {
+ prototype = base;
+ base = $.Widget;
+ }
+
+ // create selector for plugin
+ $.expr[ ":" ][ fullName.toLowerCase() ] = function( elem ) {
+ return !!$.data( elem, fullName );
+ };
+
+ $[ namespace ] = $[ namespace ] || {};
+ existingConstructor = $[ namespace ][ name ];
+ constructor = $[ namespace ][ name ] = function( options, element ) {
+ // allow instantiation without "new" keyword
+ if ( !this._createWidget ) {
+ return new constructor( options, element );
+ }
+
+ // allow instantiation without initializing for simple inheritance
+ // must use "new" keyword (the code above always passes args)
+ if ( arguments.length ) {
+ this._createWidget( options, element );
+ }
+ };
+ // extend with the existing constructor to carry over any static properties
+ $.extend( constructor, existingConstructor, {
+ version: prototype.version,
+ // copy the object used to create the prototype in case we need to
+ // redefine the widget later
+ _proto: $.extend( {}, prototype ),
+ // track widgets that inherit from this widget in case this widget is
+ // redefined after a widget inherits from it
+ _childConstructors: []
+ });
+
+ basePrototype = new base();
+ // we need to make the options hash a property directly on the new instance
+ // otherwise we'll modify the options hash on the prototype that we're
+ // inheriting from
+ basePrototype.options = $.widget.extend( {}, basePrototype.options );
+ $.each( prototype, function( prop, value ) {
+ if ( !$.isFunction( value ) ) {
+ proxiedPrototype[ prop ] = value;
+ return;
+ }
+ proxiedPrototype[ prop ] = (function() {
+ var _super = function() {
+ return base.prototype[ prop ].apply( this, arguments );
+ },
+ _superApply = function( args ) {
+ return base.prototype[ prop ].apply( this, args );
+ };
+ return function() {
+ var __super = this._super,
+ __superApply = this._superApply,
+ returnValue;
+
+ this._super = _super;
+ this._superApply = _superApply;
+
+ returnValue = value.apply( this, arguments );
+
+ this._super = __super;
+ this._superApply = __superApply;
+
+ return returnValue;
+ };
+ })();
+ });
+ constructor.prototype = $.widget.extend( basePrototype, {
+ // TODO: remove support for widgetEventPrefix
+ // always use the name + a colon as the prefix, e.g., draggable:start
+ // don't prefix for widgets that aren't DOM-based
+ widgetEventPrefix: existingConstructor ? basePrototype.widgetEventPrefix : name
+ }, proxiedPrototype, {
+ constructor: constructor,
+ namespace: namespace,
+ widgetName: name,
+ widgetFullName: fullName
+ });
+
+ // If this widget is being redefined then we need to find all widgets that
+ // are inheriting from it and redefine all of them so that they inherit from
+ // the new version of this widget. We're essentially trying to replace one
+ // level in the prototype chain.
+ if ( existingConstructor ) {
+ $.each( existingConstructor._childConstructors, function( i, child ) {
+ var childPrototype = child.prototype;
+
+ // redefine the child widget using the same prototype that was
+ // originally used, but inherit from the new version of the base
+ $.widget( childPrototype.namespace + "." + childPrototype.widgetName, constructor, child._proto );
+ });
+ // remove the list of existing child constructors from the old constructor
+ // so the old child constructors can be garbage collected
+ delete existingConstructor._childConstructors;
+ } else {
+ base._childConstructors.push( constructor );
+ }
+
+ $.widget.bridge( name, constructor );
+};
+
+$.widget.extend = function( target ) {
+ var input = slice.call( arguments, 1 ),
+ inputIndex = 0,
+ inputLength = input.length,
+ key,
+ value;
+ for ( ; inputIndex < inputLength; inputIndex++ ) {
+ for ( key in input[ inputIndex ] ) {
+ value = input[ inputIndex ][ key ];
+ if ( input[ inputIndex ].hasOwnProperty( key ) && value !== undefined ) {
+ // Clone objects
+ if ( $.isPlainObject( value ) ) {
+ target[ key ] = $.isPlainObject( target[ key ] ) ?
+ $.widget.extend( {}, target[ key ], value ) :
+ // Don't extend strings, arrays, etc. with objects
+ $.widget.extend( {}, value );
+ // Copy everything else by reference
+ } else {
+ target[ key ] = value;
+ }
+ }
+ }
+ }
+ return target;
+};
+
+$.widget.bridge = function( name, object ) {
+ var fullName = object.prototype.widgetFullName || name;
+ $.fn[ name ] = function( options ) {
+ var isMethodCall = typeof options === "string",
+ args = slice.call( arguments, 1 ),
+ returnValue = this;
+
+ // allow multiple hashes to be passed on init
+ options = !isMethodCall && args.length ?
+ $.widget.extend.apply( null, [ options ].concat(args) ) :
+ options;
+
+ if ( isMethodCall ) {
+ this.each(function() {
+ var methodValue,
+ instance = $.data( this, fullName );
+ if ( !instance ) {
+ return $.error( "cannot call methods on " + name + " prior to initialization; " +
+ "attempted to call method '" + options + "'" );
+ }
+ if ( !$.isFunction( instance[options] ) || options.charAt( 0 ) === "_" ) {
+ return $.error( "no such method '" + options + "' for " + name + " widget instance" );
+ }
+ methodValue = instance[ options ].apply( instance, args );
+ if ( methodValue !== instance && methodValue !== undefined ) {
+ returnValue = methodValue && methodValue.jquery ?
+ returnValue.pushStack( methodValue.get() ) :
+ methodValue;
+ return false;
+ }
+ });
+ } else {
+ this.each(function() {
+ var instance = $.data( this, fullName );
+ if ( instance ) {
+ instance.option( options || {} )._init();
+ } else {
+ $.data( this, fullName, new object( options, this ) );
+ }
+ });
+ }
+
+ return returnValue;
+ };
+};
+
+$.Widget = function( /* options, element */ ) {};
+$.Widget._childConstructors = [];
+
+$.Widget.prototype = {
+ widgetName: "widget",
+ widgetEventPrefix: "",
+ defaultElement: "<div>",
+ options: {
+ disabled: false,
+
+ // callbacks
+ create: null
+ },
+ _createWidget: function( options, element ) {
+ element = $( element || this.defaultElement || this )[ 0 ];
+ this.element = $( element );
+ this.uuid = uuid++;
+ this.eventNamespace = "." + this.widgetName + this.uuid;
+ this.options = $.widget.extend( {},
+ this.options,
+ this._getCreateOptions(),
+ options );
+
+ this.bindings = $();
+ this.hoverable = $();
+ this.focusable = $();
+
+ if ( element !== this ) {
+ $.data( element, this.widgetFullName, this );
+ this._on( true, this.element, {
+ remove: function( event ) {
+ if ( event.target === element ) {
+ this.destroy();
+ }
+ }
+ });
+ this.document = $( element.style ?
+ // element within the document
+ element.ownerDocument :
+ // element is window or document
+ element.document || element );
+ this.window = $( this.document[0].defaultView || this.document[0].parentWindow );
+ }
+
+ this._create();
+ this._trigger( "create", null, this._getCreateEventData() );
+ this._init();
+ },
+ _getCreateOptions: $.noop,
+ _getCreateEventData: $.noop,
+ _create: $.noop,
+ _init: $.noop,
+
+ destroy: function() {
+ this._destroy();
+ // we can probably remove the unbind calls in 2.0
+ // all event bindings should go through this._on()
+ this.element
+ .unbind( this.eventNamespace )
+ // 1.9 BC for #7810
+ // TODO remove dual storage
+ .removeData( this.widgetName )
+ .removeData( this.widgetFullName )
+ // support: jquery <1.6.3
+ // http://bugs.jquery.com/ticket/9413
+ .removeData( $.camelCase( this.widgetFullName ) );
+ this.widget()
+ .unbind( this.eventNamespace )
+ .removeAttr( "aria-disabled" )
+ .removeClass(
+ this.widgetFullName + "-disabled " +
+ "ui-state-disabled" );
+
+ // clean up events and states
+ this.bindings.unbind( this.eventNamespace );
+ this.hoverable.removeClass( "ui-state-hover" );
+ this.focusable.removeClass( "ui-state-focus" );
+ },
+ _destroy: $.noop,
+
+ widget: function() {
+ return this.element;
+ },
+
+ option: function( key, value ) {
+ var options = key,
+ parts,
+ curOption,
+ i;
+
+ if ( arguments.length === 0 ) {
+ // don't return a reference to the internal hash
+ return $.widget.extend( {}, this.options );
+ }
+
+ if ( typeof key === "string" ) {
+ // handle nested keys, e.g., "foo.bar" => { foo: { bar: ___ } }
+ options = {};
+ parts = key.split( "." );
+ key = parts.shift();
+ if ( parts.length ) {
+ curOption = options[ key ] = $.widget.extend( {}, this.options[ key ] );
+ for ( i = 0; i < parts.length - 1; i++ ) {
+ curOption[ parts[ i ] ] = curOption[ parts[ i ] ] || {};
+ curOption = curOption[ parts[ i ] ];
+ }
+ key = parts.pop();
+ if ( value === undefined ) {
+ return curOption[ key ] === undefined ? null : curOption[ key ];
+ }
+ curOption[ key ] = value;
+ } else {
+ if ( value === undefined ) {
+ return this.options[ key ] === undefined ? null : this.options[ key ];
+ }
+ options[ key ] = value;
+ }
+ }
+
+ this._setOptions( options );
+
+ return this;
+ },
+ _setOptions: function( options ) {
+ var key;
+
+ for ( key in options ) {
+ this._setOption( key, options[ key ] );
+ }
+
+ return this;
+ },
+ _setOption: function( key, value ) {
+ this.options[ key ] = value;
+
+ if ( key === "disabled" ) {
+ this.widget()
+ .toggleClass( this.widgetFullName + "-disabled ui-state-disabled", !!value )
+ .attr( "aria-disabled", value );
+ this.hoverable.removeClass( "ui-state-hover" );
+ this.focusable.removeClass( "ui-state-focus" );
+ }
+
+ return this;
+ },
+
+ enable: function() {
+ return this._setOption( "disabled", false );
+ },
+ disable: function() {
+ return this._setOption( "disabled", true );
+ },
+
+ _on: function( suppressDisabledCheck, element, handlers ) {
+ var delegateElement,
+ instance = this;
+
+ // no suppressDisabledCheck flag, shuffle arguments
+ if ( typeof suppressDisabledCheck !== "boolean" ) {
+ handlers = element;
+ element = suppressDisabledCheck;
+ suppressDisabledCheck = false;
+ }
+
+ // no element argument, shuffle and use this.element
+ if ( !handlers ) {
+ handlers = element;
+ element = this.element;
+ delegateElement = this.widget();
+ } else {
+ // accept selectors, DOM elements
+ element = delegateElement = $( element );
+ this.bindings = this.bindings.add( element );
+ }
+
+ $.each( handlers, function( event, handler ) {
+ function handlerProxy() {
+ // allow widgets to customize the disabled handling
+ // - disabled as an array instead of boolean
+ // - disabled class as method for disabling individual parts
+ if ( !suppressDisabledCheck &&
+ ( instance.options.disabled === true ||
+ $( this ).hasClass( "ui-state-disabled" ) ) ) {
+ return;
+ }
+ return ( typeof handler === "string" ? instance[ handler ] : handler )
+ .apply( instance, arguments );
+ }
+
+ // copy the guid so direct unbinding works
+ if ( typeof handler !== "string" ) {
+ handlerProxy.guid = handler.guid =
+ handler.guid || handlerProxy.guid || $.guid++;
+ }
+
+ var match = event.match( /^(\w+)\s*(.*)$/ ),
+ eventName = match[1] + instance.eventNamespace,
+ selector = match[2];
+ if ( selector ) {
+ delegateElement.delegate( selector, eventName, handlerProxy );
+ } else {
+ element.bind( eventName, handlerProxy );
+ }
+ });
+ },
+
+ _off: function( element, eventName ) {
+ eventName = (eventName || "").split( " " ).join( this.eventNamespace + " " ) + this.eventNamespace;
+ element.unbind( eventName ).undelegate( eventName );
+ },
+
+ _delay: function( handler, delay ) {
+ function handlerProxy() {
+ return ( typeof handler === "string" ? instance[ handler ] : handler )
+ .apply( instance, arguments );
+ }
+ var instance = this;
+ return setTimeout( handlerProxy, delay || 0 );
+ },
+
+ _hoverable: function( element ) {
+ this.hoverable = this.hoverable.add( element );
+ this._on( element, {
+ mouseenter: function( event ) {
+ $( event.currentTarget ).addClass( "ui-state-hover" );
+ },
+ mouseleave: function( event ) {
+ $( event.currentTarget ).removeClass( "ui-state-hover" );
+ }
+ });
+ },
+
+ _focusable: function( element ) {
+ this.focusable = this.focusable.add( element );
+ this._on( element, {
+ focusin: function( event ) {
+ $( event.currentTarget ).addClass( "ui-state-focus" );
+ },
+ focusout: function( event ) {
+ $( event.currentTarget ).removeClass( "ui-state-focus" );
+ }
+ });
+ },
+
+ _trigger: function( type, event, data ) {
+ var prop, orig,
+ callback = this.options[ type ];
+
+ data = data || {};
+ event = $.Event( event );
+ event.type = ( type === this.widgetEventPrefix ?
+ type :
+ this.widgetEventPrefix + type ).toLowerCase();
+ // the original event may come from any element
+ // so we need to reset the target on the new event
+ event.target = this.element[ 0 ];
+
+ // copy original event properties over to the new event
+ orig = event.originalEvent;
+ if ( orig ) {
+ for ( prop in orig ) {
+ if ( !( prop in event ) ) {
+ event[ prop ] = orig[ prop ];
+ }
+ }
+ }
+
+ this.element.trigger( event, data );
+ return !( $.isFunction( callback ) &&
+ callback.apply( this.element[0], [ event ].concat( data ) ) === false ||
+ event.isDefaultPrevented() );
+ }
+};
+
+$.each( { show: "fadeIn", hide: "fadeOut" }, function( method, defaultEffect ) {
+ $.Widget.prototype[ "_" + method ] = function( element, options, callback ) {
+ if ( typeof options === "string" ) {
+ options = { effect: options };
+ }
+ var hasOptions,
+ effectName = !options ?
+ method :
+ options === true || typeof options === "number" ?
+ defaultEffect :
+ options.effect || defaultEffect;
+ options = options || {};
+ if ( typeof options === "number" ) {
+ options = { duration: options };
+ }
+ hasOptions = !$.isEmptyObject( options );
+ options.complete = callback;
+ if ( options.delay ) {
+ element.delay( options.delay );
+ }
+ if ( hasOptions && $.effects && $.effects.effect[ effectName ] ) {
+ element[ method ]( options );
+ } else if ( effectName !== method && element[ effectName ] ) {
+ element[ effectName ]( options.duration, options.easing, callback );
+ } else {
+ element.queue(function( next ) {
+ $( this )[ method ]();
+ if ( callback ) {
+ callback.call( element[ 0 ] );
+ }
+ next();
+ });
+ }
+ };
+});
+
+})( jQuery );
+
+(function( $, undefined ) {
+
+var mouseHandled = false;
+$( document ).mouseup( function() {
+ mouseHandled = false;
+});
+
+$.widget("ui.mouse", {
+ version: "1.10.3",
+ options: {
+ cancel: "input,textarea,button,select,option",
+ distance: 1,
+ delay: 0
+ },
+ _mouseInit: function() {
+ var that = this;
+
+ this.element
+ .bind("mousedown."+this.widgetName, function(event) {
+ return that._mouseDown(event);
+ })
+ .bind("click."+this.widgetName, function(event) {
+ if (true === $.data(event.target, that.widgetName + ".preventClickEvent")) {
+ $.removeData(event.target, that.widgetName + ".preventClickEvent");
+ event.stopImmediatePropagation();
+ return false;
+ }
+ });
+
+ this.started = false;
+ },
+
+ // TODO: make sure destroying one instance of mouse doesn't mess with
+ // other instances of mouse
+ _mouseDestroy: function() {
+ this.element.unbind("."+this.widgetName);
+ if ( this._mouseMoveDelegate ) {
+ $(document)
+ .unbind("mousemove."+this.widgetName, this._mouseMoveDelegate)
+ .unbind("mouseup."+this.widgetName, this._mouseUpDelegate);
+ }
+ },
+
+ _mouseDown: function(event) {
+ // don't let more than one widget handle mouseStart
+ if( mouseHandled ) { return; }
+
+ // we may have missed mouseup (out of window)
+ (this._mouseStarted && this._mouseUp(event));
+
+ this._mouseDownEvent = event;
+
+ var that = this,
+ btnIsLeft = (event.which === 1),
+ // event.target.nodeName works around a bug in IE 8 with
+ // disabled inputs (#7620)
+ elIsCancel = (typeof this.options.cancel === "string" && event.target.nodeName ? $(event.target).closest(this.options.cancel).length : false);
+ if (!btnIsLeft || elIsCancel || !this._mouseCapture(event)) {
+ return true;
+ }
+
+ this.mouseDelayMet = !this.options.delay;
+ if (!this.mouseDelayMet) {
+ this._mouseDelayTimer = setTimeout(function() {
+ that.mouseDelayMet = true;
+ }, this.options.delay);
+ }
+
+ if (this._mouseDistanceMet(event) && this._mouseDelayMet(event)) {
+ this._mouseStarted = (this._mouseStart(event) !== false);
+ if (!this._mouseStarted) {
+ event.preventDefault();
+ return true;
+ }
+ }
+
+ // Click event may never have fired (Gecko & Opera)
+ if (true === $.data(event.target, this.widgetName + ".preventClickEvent")) {
+ $.removeData(event.target, this.widgetName + ".preventClickEvent");
+ }
+
+ // these delegates are required to keep context
+ this._mouseMoveDelegate = function(event) {
+ return that._mouseMove(event);
+ };
+ this._mouseUpDelegate = function(event) {
+ return that._mouseUp(event);
+ };
+ $(document)
+ .bind("mousemove."+this.widgetName, this._mouseMoveDelegate)
+ .bind("mouseup."+this.widgetName, this._mouseUpDelegate);
+
+ event.preventDefault();
+
+ mouseHandled = true;
+ return true;
+ },
+
+ _mouseMove: function(event) {
+ // IE mouseup check - mouseup happened when mouse was out of window
+ if ($.ui.ie && ( !document.documentMode || document.documentMode < 9 ) && !event.button) {
+ return this._mouseUp(event);
+ }
+
+ if (this._mouseStarted) {
+ this._mouseDrag(event);
+ return event.preventDefault();
+ }
+
+ if (this._mouseDistanceMet(event) && this._mouseDelayMet(event)) {
+ this._mouseStarted =
+ (this._mouseStart(this._mouseDownEvent, event) !== false);
+ (this._mouseStarted ? this._mouseDrag(event) : this._mouseUp(event));
+ }
+
+ return !this._mouseStarted;
+ },
+
+ _mouseUp: function(event) {
+ $(document)
+ .unbind("mousemove."+this.widgetName, this._mouseMoveDelegate)
+ .unbind("mouseup."+this.widgetName, this._mouseUpDelegate);
+
+ if (this._mouseStarted) {
+ this._mouseStarted = false;
+
+ if (event.target === this._mouseDownEvent.target) {
+ $.data(event.target, this.widgetName + ".preventClickEvent", true);
+ }
+
+ this._mouseStop(event);
+ }
+
+ return false;
+ },
+
+ _mouseDistanceMet: function(event) {
+ return (Math.max(
+ Math.abs(this._mouseDownEvent.pageX - event.pageX),
+ Math.abs(this._mouseDownEvent.pageY - event.pageY)
+ ) >= this.options.distance
+ );
+ },
+
+ _mouseDelayMet: function(/* event */) {
+ return this.mouseDelayMet;
+ },
+
+ // These are placeholder methods, to be overriden by extending plugin
+ _mouseStart: function(/* event */) {},
+ _mouseDrag: function(/* event */) {},
+ _mouseStop: function(/* event */) {},
+ _mouseCapture: function(/* event */) { return true; }
+});
+
+})(jQuery);
+
+(function( $, undefined ) {
+
+$.widget("ui.draggable", $.ui.mouse, {
+ version: "1.10.3",
+ widgetEventPrefix: "drag",
+ options: {
+ addClasses: true,
+ appendTo: "parent",
+ axis: false,
+ connectToSortable: false,
+ containment: false,
+ cursor: "auto",
+ cursorAt: false,
+ grid: false,
+ handle: false,
+ helper: "original",
+ iframeFix: false,
+ opacity: false,
+ refreshPositions: false,
+ revert: false,
+ revertDuration: 500,
+ scope: "default",
+ scroll: true,
+ scrollSensitivity: 20,
+ scrollSpeed: 20,
+ snap: false,
+ snapMode: "both",
+ snapTolerance: 20,
+ stack: false,
+ zIndex: false,
+
+ // callbacks
+ drag: null,
+ start: null,
+ stop: null
+ },
+ _create: function() {
+
+ if (this.options.helper === "original" && !(/^(?:r|a|f)/).test(this.element.css("position"))) {
+ this.element[0].style.position = "relative";
+ }
+ if (this.options.addClasses){
+ this.element.addClass("ui-draggable");
+ }
+ if (this.options.disabled){
+ this.element.addClass("ui-draggable-disabled");
+ }
+
+ this._mouseInit();
+
+ },
+
+ _destroy: function() {
+ this.element.removeClass( "ui-draggable ui-draggable-dragging ui-draggable-disabled" );
+ this._mouseDestroy();
+ },
+
+ _mouseCapture: function(event) {
+
+ var o = this.options;
+
+ // among others, prevent a drag on a resizable-handle
+ if (this.helper || o.disabled || $(event.target).closest(".ui-resizable-handle").length > 0) {
+ return false;
+ }
+
+ //Quit if we're not on a valid handle
+ this.handle = this._getHandle(event);
+ if (!this.handle) {
+ return false;
+ }
+
+ $(o.iframeFix === true ? "iframe" : o.iframeFix).each(function() {
+ $("<div class='ui-draggable-iframeFix' style='background: #fff;'></div>")
+ .css({
+ width: this.offsetWidth+"px", height: this.offsetHeight+"px",
+ position: "absolute", opacity: "0.001", zIndex: 1000
+ })
+ .css($(this).offset())
+ .appendTo("body");
+ });
+
+ return true;
+
+ },
+
+ _mouseStart: function(event) {
+
+ var o = this.options;
+
+ //Create and append the visible helper
+ this.helper = this._createHelper(event);
+
+ this.helper.addClass("ui-draggable-dragging");
+
+ //Cache the helper size
+ this._cacheHelperProportions();
+
+ //If ddmanager is used for droppables, set the global draggable
+ if($.ui.ddmanager) {
+ $.ui.ddmanager.current = this;
+ }
+
+ /*
+ * - Position generation -
+ * This block generates everything position related - it's the core of draggables.
+ */
+
+ //Cache the margins of the original element
+ this._cacheMargins();
+
+ //Store the helper's css position
+ this.cssPosition = this.helper.css( "position" );
+ this.scrollParent = this.helper.scrollParent();
+ this.offsetParent = this.helper.offsetParent();
+ this.offsetParentCssPosition = this.offsetParent.css( "position" );
+
+ //The element's absolute position on the page minus margins
+ this.offset = this.positionAbs = this.element.offset();
+ this.offset = {
+ top: this.offset.top - this.margins.top,
+ left: this.offset.left - this.margins.left
+ };
+
+ //Reset scroll cache
+ this.offset.scroll = false;
+
+ $.extend(this.offset, {
+ click: { //Where the click happened, relative to the element
+ left: event.pageX - this.offset.left,
+ top: event.pageY - this.offset.top
+ },
+ parent: this._getParentOffset(),
+ relative: this._getRelativeOffset() //This is a relative to absolute position minus the actual position calculation - only used for relative positioned helper
+ });
+
+ //Generate the original position
+ this.originalPosition = this.position = this._generatePosition(event);
+ this.originalPageX = event.pageX;
+ this.originalPageY = event.pageY;
+
+ //Adjust the mouse offset relative to the helper if "cursorAt" is supplied
+ (o.cursorAt && this._adjustOffsetFromHelper(o.cursorAt));
+
+ //Set a containment if given in the options
+ this._setContainment();
+
+ //Trigger event + callbacks
+ if(this._trigger("start", event) === false) {
+ this._clear();
+ return false;
+ }
+
+ //Recache the helper size
+ this._cacheHelperProportions();
+
+ //Prepare the droppable offsets
+ if ($.ui.ddmanager && !o.dropBehaviour) {
+ $.ui.ddmanager.prepareOffsets(this, event);
+ }
+
+
+ this._mouseDrag(event, true); //Execute the drag once - this causes the helper not to be visible before getting its correct position
+
+ //If the ddmanager is used for droppables, inform the manager that dragging has started (see #5003)
+ if ( $.ui.ddmanager ) {
+ $.ui.ddmanager.dragStart(this, event);
+ }
+
+ return true;
+ },
+
+ _mouseDrag: function(event, noPropagation) {
+ // reset any necessary cached properties (see #5009)
+ if ( this.offsetParentCssPosition === "fixed" ) {
+ this.offset.parent = this._getParentOffset();
+ }
+
+ //Compute the helpers position
+ this.position = this._generatePosition(event);
+ this.positionAbs = this._convertPositionTo("absolute");
+
+ //Call plugins and callbacks and use the resulting position if something is returned
+ if (!noPropagation) {
+ var ui = this._uiHash();
+ if(this._trigger("drag", event, ui) === false) {
+ this._mouseUp({});
+ return false;
+ }
+ this.position = ui.position;
+ }
+
+ if(!this.options.axis || this.options.axis !== "y") {
+ this.helper[0].style.left = this.position.left+"px";
+ }
+ if(!this.options.axis || this.options.axis !== "x") {
+ this.helper[0].style.top = this.position.top+"px";
+ }
+ if($.ui.ddmanager) {
+ $.ui.ddmanager.drag(this, event);
+ }
+
+ return false;
+ },
+
+ _mouseStop: function(event) {
+
+ //If we are using droppables, inform the manager about the drop
+ var that = this,
+ dropped = false;
+ if ($.ui.ddmanager && !this.options.dropBehaviour) {
+ dropped = $.ui.ddmanager.drop(this, event);
+ }
+
+ //if a drop comes from outside (a sortable)
+ if(this.dropped) {
+ dropped = this.dropped;
+ this.dropped = false;
+ }
+
+ //if the original element is no longer in the DOM don't bother to continue (see #8269)
+ if ( this.options.helper === "original" && !$.contains( this.element[ 0 ].ownerDocument, this.element[ 0 ] ) ) {
+ return false;
+ }
+
+ if((this.options.revert === "invalid" && !dropped) || (this.options.revert === "valid" && dropped) || this.options.revert === true || ($.isFunction(this.options.revert) && this.options.revert.call(this.element, dropped))) {
+ $(this.helper).animate(this.originalPosition, parseInt(this.options.revertDuration, 10), function() {
+ if(that._trigger("stop", event) !== false) {
+ that._clear();
+ }
+ });
+ } else {
+ if(this._trigger("stop", event) !== false) {
+ this._clear();
+ }
+ }
+
+ return false;
+ },
+
+ _mouseUp: function(event) {
+ //Remove frame helpers
+ $("div.ui-draggable-iframeFix").each(function() {
+ this.parentNode.removeChild(this);
+ });
+
+ //If the ddmanager is used for droppables, inform the manager that dragging has stopped (see #5003)
+ if( $.ui.ddmanager ) {
+ $.ui.ddmanager.dragStop(this, event);
+ }
+
+ return $.ui.mouse.prototype._mouseUp.call(this, event);
+ },
+
+ cancel: function() {
+
+ if(this.helper.is(".ui-draggable-dragging")) {
+ this._mouseUp({});
+ } else {
+ this._clear();
+ }
+
+ return this;
+
+ },
+
+ _getHandle: function(event) {
+ return this.options.handle ?
+ !!$( event.target ).closest( this.element.find( this.options.handle ) ).length :
+ true;
+ },
+
+ _createHelper: function(event) {
+
+ var o = this.options,
+ helper = $.isFunction(o.helper) ? $(o.helper.apply(this.element[0], [event])) : (o.helper === "clone" ? this.element.clone().removeAttr("id") : this.element);
+
+ if(!helper.parents("body").length) {
+ helper.appendTo((o.appendTo === "parent" ? this.element[0].parentNode : o.appendTo));
+ }
+
+ if(helper[0] !== this.element[0] && !(/(fixed|absolute)/).test(helper.css("position"))) {
+ helper.css("position", "absolute");
+ }
+
+ return helper;
+
+ },
+
+ _adjustOffsetFromHelper: function(obj) {
+ if (typeof obj === "string") {
+ obj = obj.split(" ");
+ }
+ if ($.isArray(obj)) {
+ obj = {left: +obj[0], top: +obj[1] || 0};
+ }
+ if ("left" in obj) {
+ this.offset.click.left = obj.left + this.margins.left;
+ }
+ if ("right" in obj) {
+ this.offset.click.left = this.helperProportions.width - obj.right + this.margins.left;
+ }
+ if ("top" in obj) {
+ this.offset.click.top = obj.top + this.margins.top;
+ }
+ if ("bottom" in obj) {
+ this.offset.click.top = this.helperProportions.height - obj.bottom + this.margins.top;
+ }
+ },
+
+ _getParentOffset: function() {
+
+ //Get the offsetParent and cache its position
+ var po = this.offsetParent.offset();
+
+ // This is a special case where we need to modify a offset calculated on start, since the following happened:
+ // 1. The position of the helper is absolute, so it's position is calculated based on the next positioned parent
+ // 2. The actual offset parent is a child of the scroll parent, and the scroll parent isn't the document, which means that
+ // the scroll is included in the initial calculation of the offset of the parent, and never recalculated upon drag
+ if(this.cssPosition === "absolute" && this.scrollParent[0] !== document && $.contains(this.scrollParent[0], this.offsetParent[0])) {
+ po.left += this.scrollParent.scrollLeft();
+ po.top += this.scrollParent.scrollTop();
+ }
+
+ //This needs to be actually done for all browsers, since pageX/pageY includes this information
+ //Ugly IE fix
+ if((this.offsetParent[0] === document.body) ||
+ (this.offsetParent[0].tagName && this.offsetParent[0].tagName.toLowerCase() === "html" && $.ui.ie)) {
+ po = { top: 0, left: 0 };
+ }
+
+ return {
+ top: po.top + (parseInt(this.offsetParent.css("borderTopWidth"),10) || 0),
+ left: po.left + (parseInt(this.offsetParent.css("borderLeftWidth"),10) || 0)
+ };
+
+ },
+
+ _getRelativeOffset: function() {
+
+ if(this.cssPosition === "relative") {
+ var p = this.element.position();
+ return {
+ top: p.top - (parseInt(this.helper.css("top"),10) || 0) + this.scrollParent.scrollTop(),
+ left: p.left - (parseInt(this.helper.css("left"),10) || 0) + this.scrollParent.scrollLeft()
+ };
+ } else {
+ return { top: 0, left: 0 };
+ }
+
+ },
+
+ _cacheMargins: function() {
+ this.margins = {
+ left: (parseInt(this.element.css("marginLeft"),10) || 0),
+ top: (parseInt(this.element.css("marginTop"),10) || 0),
+ right: (parseInt(this.element.css("marginRight"),10) || 0),
+ bottom: (parseInt(this.element.css("marginBottom"),10) || 0)
+ };
+ },
+
+ _cacheHelperProportions: function() {
+ this.helperProportions = {
+ width: this.helper.outerWidth(),
+ height: this.helper.outerHeight()
+ };
+ },
+
+ _setContainment: function() {
+
+ var over, c, ce,
+ o = this.options;
+
+ if ( !o.containment ) {
+ this.containment = null;
+ return;
+ }
+
+ if ( o.containment === "window" ) {
+ this.containment = [
+ $( window ).scrollLeft() - this.offset.relative.left - this.offset.parent.left,
+ $( window ).scrollTop() - this.offset.relative.top - this.offset.parent.top,
+ $( window ).scrollLeft() + $( window ).width() - this.helperProportions.width - this.margins.left,
+ $( window ).scrollTop() + ( $( window ).height() || document.body.parentNode.scrollHeight ) - this.helperProportions.height - this.margins.top
+ ];
+ return;
+ }
+
+ if ( o.containment === "document") {
+ this.containment = [
+ 0,
+ 0,
+ $( document ).width() - this.helperProportions.width - this.margins.left,
+ ( $( document ).height() || document.body.parentNode.scrollHeight ) - this.helperProportions.height - this.margins.top
+ ];
+ return;
+ }
+
+ if ( o.containment.constructor === Array ) {
+ this.containment = o.containment;
+ return;
+ }
+
+ if ( o.containment === "parent" ) {
+ o.containment = this.helper[ 0 ].parentNode;
+ }
+
+ c = $( o.containment );
+ ce = c[ 0 ];
+
+ if( !ce ) {
+ return;
+ }
+
+ over = c.css( "overflow" ) !== "hidden";
+
+ this.containment = [
+ ( parseInt( c.css( "borderLeftWidth" ), 10 ) || 0 ) + ( parseInt( c.css( "paddingLeft" ), 10 ) || 0 ),
+ ( parseInt( c.css( "borderTopWidth" ), 10 ) || 0 ) + ( parseInt( c.css( "paddingTop" ), 10 ) || 0 ) ,
+ ( over ? Math.max( ce.scrollWidth, ce.offsetWidth ) : ce.offsetWidth ) - ( parseInt( c.css( "borderRightWidth" ), 10 ) || 0 ) - ( parseInt( c.css( "paddingRight" ), 10 ) || 0 ) - this.helperProportions.width - this.margins.left - this.margins.right,
+ ( over ? Math.max( ce.scrollHeight, ce.offsetHeight ) : ce.offsetHeight ) - ( parseInt( c.css( "borderBottomWidth" ), 10 ) || 0 ) - ( parseInt( c.css( "paddingBottom" ), 10 ) || 0 ) - this.helperProportions.height - this.margins.top - this.margins.bottom
+ ];
+ this.relative_container = c;
+ },
+
+ _convertPositionTo: function(d, pos) {
+
+ if(!pos) {
+ pos = this.position;
+ }
+
+ var mod = d === "absolute" ? 1 : -1,
+ scroll = this.cssPosition === "absolute" && !( this.scrollParent[ 0 ] !== document && $.contains( this.scrollParent[ 0 ], this.offsetParent[ 0 ] ) ) ? this.offsetParent : this.scrollParent;
+
+ //Cache the scroll
+ if (!this.offset.scroll) {
+ this.offset.scroll = {top : scroll.scrollTop(), left : scroll.scrollLeft()};
+ }
+
+ return {
+ top: (
+ pos.top + // The absolute mouse position
+ this.offset.relative.top * mod + // Only for relative positioned nodes: Relative offset from element to offset parent
+ this.offset.parent.top * mod - // The offsetParent's offset without borders (offset + border)
+ ( ( this.cssPosition === "fixed" ? -this.scrollParent.scrollTop() : this.offset.scroll.top ) * mod )
+ ),
+ left: (
+ pos.left + // The absolute mouse position
+ this.offset.relative.left * mod + // Only for relative positioned nodes: Relative offset from element to offset parent
+ this.offset.parent.left * mod - // The offsetParent's offset without borders (offset + border)
+ ( ( this.cssPosition === "fixed" ? -this.scrollParent.scrollLeft() : this.offset.scroll.left ) * mod )
+ )
+ };
+
+ },
+
+ _generatePosition: function(event) {
+
+ var containment, co, top, left,
+ o = this.options,
+ scroll = this.cssPosition === "absolute" && !( this.scrollParent[ 0 ] !== document && $.contains( this.scrollParent[ 0 ], this.offsetParent[ 0 ] ) ) ? this.offsetParent : this.scrollParent,
+ pageX = event.pageX,
+ pageY = event.pageY;
+
+ //Cache the scroll
+ if (!this.offset.scroll) {
+ this.offset.scroll = {top : scroll.scrollTop(), left : scroll.scrollLeft()};
+ }
+
+ /*
+ * - Position constraining -
+ * Constrain the position to a mix of grid, containment.
+ */
+
+ // If we are not dragging yet, we won't check for options
+ if ( this.originalPosition ) {
+ if ( this.containment ) {
+ if ( this.relative_container ){
+ co = this.relative_container.offset();
+ containment = [
+ this.containment[ 0 ] + co.left,
+ this.containment[ 1 ] + co.top,
+ this.containment[ 2 ] + co.left,
+ this.containment[ 3 ] + co.top
+ ];
+ }
+ else {
+ containment = this.containment;
+ }
+
+ if(event.pageX - this.offset.click.left < containment[0]) {
+ pageX = containment[0] + this.offset.click.left;
+ }
+ if(event.pageY - this.offset.click.top < containment[1]) {
+ pageY = containment[1] + this.offset.click.top;
+ }
+ if(event.pageX - this.offset.click.left > containment[2]) {
+ pageX = containment[2] + this.offset.click.left;
+ }
+ if(event.pageY - this.offset.click.top > containment[3]) {
+ pageY = containment[3] + this.offset.click.top;
+ }
+ }
+
+ if(o.grid) {
+ //Check for grid elements set to 0 to prevent divide by 0 error causing invalid argument errors in IE (see ticket #6950)
+ top = o.grid[1] ? this.originalPageY + Math.round((pageY - this.originalPageY) / o.grid[1]) * o.grid[1] : this.originalPageY;
+ pageY = containment ? ((top - this.offset.click.top >= containment[1] || top - this.offset.click.top > containment[3]) ? top : ((top - this.offset.click.top >= containment[1]) ? top - o.grid[1] : top + o.grid[1])) : top;
+
+ left = o.grid[0] ? this.originalPageX + Math.round((pageX - this.originalPageX) / o.grid[0]) * o.grid[0] : this.originalPageX;
+ pageX = containment ? ((left - this.offset.click.left >= containment[0] || left - this.offset.click.left > containment[2]) ? left : ((left - this.offset.click.left >= containment[0]) ? left - o.grid[0] : left + o.grid[0])) : left;
+ }
+
+ }
+
+ return {
+ top: (
+ pageY - // The absolute mouse position
+ this.offset.click.top - // Click offset (relative to the element)
+ this.offset.relative.top - // Only for relative positioned nodes: Relative offset from element to offset parent
+ this.offset.parent.top + // The offsetParent's offset without borders (offset + border)
+ ( this.cssPosition === "fixed" ? -this.scrollParent.scrollTop() : this.offset.scroll.top )
+ ),
+ left: (
+ pageX - // The absolute mouse position
+ this.offset.click.left - // Click offset (relative to the element)
+ this.offset.relative.left - // Only for relative positioned nodes: Relative offset from element to offset parent
+ this.offset.parent.left + // The offsetParent's offset without borders (offset + border)
+ ( this.cssPosition === "fixed" ? -this.scrollParent.scrollLeft() : this.offset.scroll.left )
+ )
+ };
+
+ },
+
+ _clear: function() {
+ this.helper.removeClass("ui-draggable-dragging");
+ if(this.helper[0] !== this.element[0] && !this.cancelHelperRemoval) {
+ this.helper.remove();
+ }
+ this.helper = null;
+ this.cancelHelperRemoval = false;
+ },
+
+ // From now on bulk stuff - mainly helpers
+
+ _trigger: function(type, event, ui) {
+ ui = ui || this._uiHash();
+ $.ui.plugin.call(this, type, [event, ui]);
+ //The absolute position has to be recalculated after plugins
+ if(type === "drag") {
+ this.positionAbs = this._convertPositionTo("absolute");
+ }
+ return $.Widget.prototype._trigger.call(this, type, event, ui);
+ },
+
+ plugins: {},
+
+ _uiHash: function() {
+ return {
+ helper: this.helper,
+ position: this.position,
+ originalPosition: this.originalPosition,
+ offset: this.positionAbs
+ };
+ }
+
+});
+
+$.ui.plugin.add("draggable", "connectToSortable", {
+ start: function(event, ui) {
+
+ var inst = $(this).data("ui-draggable"), o = inst.options,
+ uiSortable = $.extend({}, ui, { item: inst.element });
+ inst.sortables = [];
+ $(o.connectToSortable).each(function() {
+ var sortable = $.data(this, "ui-sortable");
+ if (sortable && !sortable.options.disabled) {
+ inst.sortables.push({
+ instance: sortable,
+ shouldRevert: sortable.options.revert
+ });
+ sortable.refreshPositions(); // Call the sortable's refreshPositions at drag start to refresh the containerCache since the sortable container cache is used in drag and needs to be up to date (this will ensure it's initialised as well as being kept in step with any changes that might have happened on the page).
+ sortable._trigger("activate", event, uiSortable);
+ }
+ });
+
+ },
+ stop: function(event, ui) {
+
+ //If we are still over the sortable, we fake the stop event of the sortable, but also remove helper
+ var inst = $(this).data("ui-draggable"),
+ uiSortable = $.extend({}, ui, { item: inst.element });
+
+ $.each(inst.sortables, function() {
+ if(this.instance.isOver) {
+
+ this.instance.isOver = 0;
+
+ inst.cancelHelperRemoval = true; //Don't remove the helper in the draggable instance
+ this.instance.cancelHelperRemoval = false; //Remove it in the sortable instance (so sortable plugins like revert still work)
+
+ //The sortable revert is supported, and we have to set a temporary dropped variable on the draggable to support revert: "valid/invalid"
+ if(this.shouldRevert) {
+ this.instance.options.revert = this.shouldRevert;
+ }
+
+ //Trigger the stop of the sortable
+ this.instance._mouseStop(event);
+
+ this.instance.options.helper = this.instance.options._helper;
+
+ //If the helper has been the original item, restore properties in the sortable
+ if(inst.options.helper === "original") {
+ this.instance.currentItem.css({ top: "auto", left: "auto" });
+ }
+
+ } else {
+ this.instance.cancelHelperRemoval = false; //Remove the helper in the sortable instance
+ this.instance._trigger("deactivate", event, uiSortable);
+ }
+
+ });
+
+ },
+ drag: function(event, ui) {
+
+ var inst = $(this).data("ui-draggable"), that = this;
+
+ $.each(inst.sortables, function() {
+
+ var innermostIntersecting = false,
+ thisSortable = this;
+
+ //Copy over some variables to allow calling the sortable's native _intersectsWith
+ this.instance.positionAbs = inst.positionAbs;
+ this.instance.helperProportions = inst.helperProportions;
+ this.instance.offset.click = inst.offset.click;
+
+ if(this.instance._intersectsWith(this.instance.containerCache)) {
+ innermostIntersecting = true;
+ $.each(inst.sortables, function () {
+ this.instance.positionAbs = inst.positionAbs;
+ this.instance.helperProportions = inst.helperProportions;
+ this.instance.offset.click = inst.offset.click;
+ if (this !== thisSortable &&
+ this.instance._intersectsWith(this.instance.containerCache) &&
+ $.contains(thisSortable.instance.element[0], this.instance.element[0])
+ ) {
+ innermostIntersecting = false;
+ }
+ return innermostIntersecting;
+ });
+ }
+
+
+ if(innermostIntersecting) {
+ //If it intersects, we use a little isOver variable and set it once, so our move-in stuff gets fired only once
+ if(!this.instance.isOver) {
+
+ this.instance.isOver = 1;
+ //Now we fake the start of dragging for the sortable instance,
+ //by cloning the list group item, appending it to the sortable and using it as inst.currentItem
+ //We can then fire the start event of the sortable with our passed browser event, and our own helper (so it doesn't create a new one)
+ this.instance.currentItem = $(that).clone().removeAttr("id").appendTo(this.instance.element).data("ui-sortable-item", true);
+ this.instance.options._helper = this.instance.options.helper; //Store helper option to later restore it
+ this.instance.options.helper = function() { return ui.helper[0]; };
+
+ event.target = this.instance.currentItem[0];
+ this.instance._mouseCapture(event, true);
+ this.instance._mouseStart(event, true, true);
+
+ //Because the browser event is way off the new appended portlet, we modify a couple of variables to reflect the changes
+ this.instance.offset.click.top = inst.offset.click.top;
+ this.instance.offset.click.left = inst.offset.click.left;
+ this.instance.offset.parent.left -= inst.offset.parent.left - this.instance.offset.parent.left;
+ this.instance.offset.parent.top -= inst.offset.parent.top - this.instance.offset.parent.top;
+
+ inst._trigger("toSortable", event);
+ inst.dropped = this.instance.element; //draggable revert needs that
+ //hack so receive/update callbacks work (mostly)
+ inst.currentItem = inst.element;
+ this.instance.fromOutside = inst;
+
+ }
+
+ //Provided we did all the previous steps, we can fire the drag event of the sortable on every draggable drag, when it intersects with the sortable
+ if(this.instance.currentItem) {
+ this.instance._mouseDrag(event);
+ }
+
+ } else {
+
+ //If it doesn't intersect with the sortable, and it intersected before,
+ //we fake the drag stop of the sortable, but make sure it doesn't remove the helper by using cancelHelperRemoval
+ if(this.instance.isOver) {
+
+ this.instance.isOver = 0;
+ this.instance.cancelHelperRemoval = true;
+
+ //Prevent reverting on this forced stop
+ this.instance.options.revert = false;
+
+ // The out event needs to be triggered independently
+ this.instance._trigger("out", event, this.instance._uiHash(this.instance));
+
+ this.instance._mouseStop(event, true);
+ this.instance.options.helper = this.instance.options._helper;
+
+ //Now we remove our currentItem, the list group clone again, and the placeholder, and animate the helper back to it's original size
+ this.instance.currentItem.remove();
+ if(this.instance.placeholder) {
+ this.instance.placeholder.remove();
+ }
+
+ inst._trigger("fromSortable", event);
+ inst.dropped = false; //draggable revert needs that
+ }
+
+ }
+
+ });
+
+ }
+});
+
+$.ui.plugin.add("draggable", "cursor", {
+ start: function() {
+ var t = $("body"), o = $(this).data("ui-draggable").options;
+ if (t.css("cursor")) {
+ o._cursor = t.css("cursor");
+ }
+ t.css("cursor", o.cursor);
+ },
+ stop: function() {
+ var o = $(this).data("ui-draggable").options;
+ if (o._cursor) {
+ $("body").css("cursor", o._cursor);
+ }
+ }
+});
+
+$.ui.plugin.add("draggable", "opacity", {
+ start: function(event, ui) {
+ var t = $(ui.helper), o = $(this).data("ui-draggable").options;
+ if(t.css("opacity")) {
+ o._opacity = t.css("opacity");
+ }
+ t.css("opacity", o.opacity);
+ },
+ stop: function(event, ui) {
+ var o = $(this).data("ui-draggable").options;
+ if(o._opacity) {
+ $(ui.helper).css("opacity", o._opacity);
+ }
+ }
+});
+
+$.ui.plugin.add("draggable", "scroll", {
+ start: function() {
+ var i = $(this).data("ui-draggable");
+ if(i.scrollParent[0] !== document && i.scrollParent[0].tagName !== "HTML") {
+ i.overflowOffset = i.scrollParent.offset();
+ }
+ },
+ drag: function( event ) {
+
+ var i = $(this).data("ui-draggable"), o = i.options, scrolled = false;
+
+ if(i.scrollParent[0] !== document && i.scrollParent[0].tagName !== "HTML") {
+
+ if(!o.axis || o.axis !== "x") {
+ if((i.overflowOffset.top + i.scrollParent[0].offsetHeight) - event.pageY < o.scrollSensitivity) {
+ i.scrollParent[0].scrollTop = scrolled = i.scrollParent[0].scrollTop + o.scrollSpeed;
+ } else if(event.pageY - i.overflowOffset.top < o.scrollSensitivity) {
+ i.scrollParent[0].scrollTop = scrolled = i.scrollParent[0].scrollTop - o.scrollSpeed;
+ }
+ }
+
+ if(!o.axis || o.axis !== "y") {
+ if((i.overflowOffset.left + i.scrollParent[0].offsetWidth) - event.pageX < o.scrollSensitivity) {
+ i.scrollParent[0].scrollLeft = scrolled = i.scrollParent[0].scrollLeft + o.scrollSpeed;
+ } else if(event.pageX - i.overflowOffset.left < o.scrollSensitivity) {
+ i.scrollParent[0].scrollLeft = scrolled = i.scrollParent[0].scrollLeft - o.scrollSpeed;
+ }
+ }
+
+ } else {
+
+ if(!o.axis || o.axis !== "x") {
+ if(event.pageY - $(document).scrollTop() < o.scrollSensitivity) {
+ scrolled = $(document).scrollTop($(document).scrollTop() - o.scrollSpeed);
+ } else if($(window).height() - (event.pageY - $(document).scrollTop()) < o.scrollSensitivity) {
+ scrolled = $(document).scrollTop($(document).scrollTop() + o.scrollSpeed);
+ }
+ }
+
+ if(!o.axis || o.axis !== "y") {
+ if(event.pageX - $(document).scrollLeft() < o.scrollSensitivity) {
+ scrolled = $(document).scrollLeft($(document).scrollLeft() - o.scrollSpeed);
+ } else if($(window).width() - (event.pageX - $(document).scrollLeft()) < o.scrollSensitivity) {
+ scrolled = $(document).scrollLeft($(document).scrollLeft() + o.scrollSpeed);
+ }
+ }
+
+ }
+
+ if(scrolled !== false && $.ui.ddmanager && !o.dropBehaviour) {
+ $.ui.ddmanager.prepareOffsets(i, event);
+ }
+
+ }
+});
+
+$.ui.plugin.add("draggable", "snap", {
+ start: function() {
+
+ var i = $(this).data("ui-draggable"),
+ o = i.options;
+
+ i.snapElements = [];
+
+ $(o.snap.constructor !== String ? ( o.snap.items || ":data(ui-draggable)" ) : o.snap).each(function() {
+ var $t = $(this),
+ $o = $t.offset();
+ if(this !== i.element[0]) {
+ i.snapElements.push({
+ item: this,
+ width: $t.outerWidth(), height: $t.outerHeight(),
+ top: $o.top, left: $o.left
+ });
+ }
+ });
+
+ },
+ drag: function(event, ui) {
+
+ var ts, bs, ls, rs, l, r, t, b, i, first,
+ inst = $(this).data("ui-draggable"),
+ o = inst.options,
+ d = o.snapTolerance,
+ x1 = ui.offset.left, x2 = x1 + inst.helperProportions.width,
+ y1 = ui.offset.top, y2 = y1 + inst.helperProportions.height;
+
+ for (i = inst.snapElements.length - 1; i >= 0; i--){
+
+ l = inst.snapElements[i].left;
+ r = l + inst.snapElements[i].width;
+ t = inst.snapElements[i].top;
+ b = t + inst.snapElements[i].height;
+
+ if ( x2 < l - d || x1 > r + d || y2 < t - d || y1 > b + d || !$.contains( inst.snapElements[ i ].item.ownerDocument, inst.snapElements[ i ].item ) ) {
+ if(inst.snapElements[i].snapping) {
+ (inst.options.snap.release && inst.options.snap.release.call(inst.element, event, $.extend(inst._uiHash(), { snapItem: inst.snapElements[i].item })));
+ }
+ inst.snapElements[i].snapping = false;
+ continue;
+ }
+
+ if(o.snapMode !== "inner") {
+ ts = Math.abs(t - y2) <= d;
+ bs = Math.abs(b - y1) <= d;
+ ls = Math.abs(l - x2) <= d;
+ rs = Math.abs(r - x1) <= d;
+ if(ts) {
+ ui.position.top = inst._convertPositionTo("relative", { top: t - inst.helperProportions.height, left: 0 }).top - inst.margins.top;
+ }
+ if(bs) {
+ ui.position.top = inst._convertPositionTo("relative", { top: b, left: 0 }).top - inst.margins.top;
+ }
+ if(ls) {
+ ui.position.left = inst._convertPositionTo("relative", { top: 0, left: l - inst.helperProportions.width }).left - inst.margins.left;
+ }
+ if(rs) {
+ ui.position.left = inst._convertPositionTo("relative", { top: 0, left: r }).left - inst.margins.left;
+ }
+ }
+
+ first = (ts || bs || ls || rs);
+
+ if(o.snapMode !== "outer") {
+ ts = Math.abs(t - y1) <= d;
+ bs = Math.abs(b - y2) <= d;
+ ls = Math.abs(l - x1) <= d;
+ rs = Math.abs(r - x2) <= d;
+ if(ts) {
+ ui.position.top = inst._convertPositionTo("relative", { top: t, left: 0 }).top - inst.margins.top;
+ }
+ if(bs) {
+ ui.position.top = inst._convertPositionTo("relative", { top: b - inst.helperProportions.height, left: 0 }).top - inst.margins.top;
+ }
+ if(ls) {
+ ui.position.left = inst._convertPositionTo("relative", { top: 0, left: l }).left - inst.margins.left;
+ }
+ if(rs) {
+ ui.position.left = inst._convertPositionTo("relative", { top: 0, left: r - inst.helperProportions.width }).left - inst.margins.left;
+ }
+ }
+
+ if(!inst.snapElements[i].snapping && (ts || bs || ls || rs || first)) {
+ (inst.options.snap.snap && inst.options.snap.snap.call(inst.element, event, $.extend(inst._uiHash(), { snapItem: inst.snapElements[i].item })));
+ }
+ inst.snapElements[i].snapping = (ts || bs || ls || rs || first);
+
+ }
+
+ }
+});
+
+$.ui.plugin.add("draggable", "stack", {
+ start: function() {
+ var min,
+ o = this.data("ui-draggable").options,
+ group = $.makeArray($(o.stack)).sort(function(a,b) {
+ return (parseInt($(a).css("zIndex"),10) || 0) - (parseInt($(b).css("zIndex"),10) || 0);
+ });
+
+ if (!group.length) { return; }
+
+ min = parseInt($(group[0]).css("zIndex"), 10) || 0;
+ $(group).each(function(i) {
+ $(this).css("zIndex", min + i);
+ });
+ this.css("zIndex", (min + group.length));
+ }
+});
+
+$.ui.plugin.add("draggable", "zIndex", {
+ start: function(event, ui) {
+ var t = $(ui.helper), o = $(this).data("ui-draggable").options;
+ if(t.css("zIndex")) {
+ o._zIndex = t.css("zIndex");
+ }
+ t.css("zIndex", o.zIndex);
+ },
+ stop: function(event, ui) {
+ var o = $(this).data("ui-draggable").options;
+ if(o._zIndex) {
+ $(ui.helper).css("zIndex", o._zIndex);
+ }
+ }
+});
+
+})(jQuery);
+
+(function( $, undefined ) {
+
+function isOverAxis( x, reference, size ) {
+ return ( x > reference ) && ( x < ( reference + size ) );
+}
+
+$.widget("ui.droppable", {
+ version: "1.10.3",
+ widgetEventPrefix: "drop",
+ options: {
+ accept: "*",
+ activeClass: false,
+ addClasses: true,
+ greedy: false,
+ hoverClass: false,
+ scope: "default",
+ tolerance: "intersect",
+
+ // callbacks
+ activate: null,
+ deactivate: null,
+ drop: null,
+ out: null,
+ over: null
+ },
+ _create: function() {
+
+ var o = this.options,
+ accept = o.accept;
+
+ this.isover = false;
+ this.isout = true;
+
+ this.accept = $.isFunction(accept) ? accept : function(d) {
+ return d.is(accept);
+ };
+
+ //Store the droppable's proportions
+ this.proportions = { width: this.element[0].offsetWidth, height: this.element[0].offsetHeight };
+
+ // Add the reference and positions to the manager
+ $.ui.ddmanager.droppables[o.scope] = $.ui.ddmanager.droppables[o.scope] || [];
+ $.ui.ddmanager.droppables[o.scope].push(this);
+
+ (o.addClasses && this.element.addClass("ui-droppable"));
+
+ },
+
+ _destroy: function() {
+ var i = 0,
+ drop = $.ui.ddmanager.droppables[this.options.scope];
+
+ for ( ; i < drop.length; i++ ) {
+ if ( drop[i] === this ) {
+ drop.splice(i, 1);
+ }
+ }
+
+ this.element.removeClass("ui-droppable ui-droppable-disabled");
+ },
+
+ _setOption: function(key, value) {
+
+ if(key === "accept") {
+ this.accept = $.isFunction(value) ? value : function(d) {
+ return d.is(value);
+ };
+ }
+ $.Widget.prototype._setOption.apply(this, arguments);
+ },
+
+ _activate: function(event) {
+ var draggable = $.ui.ddmanager.current;
+ if(this.options.activeClass) {
+ this.element.addClass(this.options.activeClass);
+ }
+ if(draggable){
+ this._trigger("activate", event, this.ui(draggable));
+ }
+ },
+
+ _deactivate: function(event) {
+ var draggable = $.ui.ddmanager.current;
+ if(this.options.activeClass) {
+ this.element.removeClass(this.options.activeClass);
+ }
+ if(draggable){
+ this._trigger("deactivate", event, this.ui(draggable));
+ }
+ },
+
+ _over: function(event) {
+
+ var draggable = $.ui.ddmanager.current;
+
+ // Bail if draggable and droppable are same element
+ if (!draggable || (draggable.currentItem || draggable.element)[0] === this.element[0]) {
+ return;
+ }
+
+ if (this.accept.call(this.element[0],(draggable.currentItem || draggable.element))) {
+ if(this.options.hoverClass) {
+ this.element.addClass(this.options.hoverClass);
+ }
+ this._trigger("over", event, this.ui(draggable));
+ }
+
+ },
+
+ _out: function(event) {
+
+ var draggable = $.ui.ddmanager.current;
+
+ // Bail if draggable and droppable are same element
+ if (!draggable || (draggable.currentItem || draggable.element)[0] === this.element[0]) {
+ return;
+ }
+
+ if (this.accept.call(this.element[0],(draggable.currentItem || draggable.element))) {
+ if(this.options.hoverClass) {
+ this.element.removeClass(this.options.hoverClass);
+ }
+ this._trigger("out", event, this.ui(draggable));
+ }
+
+ },
+
+ _drop: function(event,custom) {
+
+ var draggable = custom || $.ui.ddmanager.current,
+ childrenIntersection = false;
+
+ // Bail if draggable and droppable are same element
+ if (!draggable || (draggable.currentItem || draggable.element)[0] === this.element[0]) {
+ return false;
+ }
+
+ this.element.find(":data(ui-droppable)").not(".ui-draggable-dragging").each(function() {
+ var inst = $.data(this, "ui-droppable");
+ if(
+ inst.options.greedy &&
+ !inst.options.disabled &&
+ inst.options.scope === draggable.options.scope &&
+ inst.accept.call(inst.element[0], (draggable.currentItem || draggable.element)) &&
+ $.ui.intersect(draggable, $.extend(inst, { offset: inst.element.offset() }), inst.options.tolerance)
+ ) { childrenIntersection = true; return false; }
+ });
+ if(childrenIntersection) {
+ return false;
+ }
+
+ if(this.accept.call(this.element[0],(draggable.currentItem || draggable.element))) {
+ if(this.options.activeClass) {
+ this.element.removeClass(this.options.activeClass);
+ }
+ if(this.options.hoverClass) {
+ this.element.removeClass(this.options.hoverClass);
+ }
+ this._trigger("drop", event, this.ui(draggable));
+ return this.element;
+ }
+
+ return false;
+
+ },
+
+ ui: function(c) {
+ return {
+ draggable: (c.currentItem || c.element),
+ helper: c.helper,
+ position: c.position,
+ offset: c.positionAbs
+ };
+ }
+
+});
+
+$.ui.intersect = function(draggable, droppable, toleranceMode) {
+
+ if (!droppable.offset) {
+ return false;
+ }
+
+ var draggableLeft, draggableTop,
+ x1 = (draggable.positionAbs || draggable.position.absolute).left, x2 = x1 + draggable.helperProportions.width,
+ y1 = (draggable.positionAbs || draggable.position.absolute).top, y2 = y1 + draggable.helperProportions.height,
+ l = droppable.offset.left, r = l + droppable.proportions.width,
+ t = droppable.offset.top, b = t + droppable.proportions.height;
+
+ switch (toleranceMode) {
+ case "fit":
+ return (l <= x1 && x2 <= r && t <= y1 && y2 <= b);
+ case "intersect":
+ return (l < x1 + (draggable.helperProportions.width / 2) && // Right Half
+ x2 - (draggable.helperProportions.width / 2) < r && // Left Half
+ t < y1 + (draggable.helperProportions.height / 2) && // Bottom Half
+ y2 - (draggable.helperProportions.height / 2) < b ); // Top Half
+ case "pointer":
+ draggableLeft = ((draggable.positionAbs || draggable.position.absolute).left + (draggable.clickOffset || draggable.offset.click).left);
+ draggableTop = ((draggable.positionAbs || draggable.position.absolute).top + (draggable.clickOffset || draggable.offset.click).top);
+ return isOverAxis( draggableTop, t, droppable.proportions.height ) && isOverAxis( draggableLeft, l, droppable.proportions.width );
+ case "touch":
+ return (
+ (y1 >= t && y1 <= b) || // Top edge touching
+ (y2 >= t && y2 <= b) || // Bottom edge touching
+ (y1 < t && y2 > b) // Surrounded vertically
+ ) && (
+ (x1 >= l && x1 <= r) || // Left edge touching
+ (x2 >= l && x2 <= r) || // Right edge touching
+ (x1 < l && x2 > r) // Surrounded horizontally
+ );
+ default:
+ return false;
+ }
+
+};
+
+/*
+ This manager tracks offsets of draggables and droppables
+*/
+$.ui.ddmanager = {
+ current: null,
+ droppables: { "default": [] },
+ prepareOffsets: function(t, event) {
+
+ var i, j,
+ m = $.ui.ddmanager.droppables[t.options.scope] || [],
+ type = event ? event.type : null, // workaround for #2317
+ list = (t.currentItem || t.element).find(":data(ui-droppable)").addBack();
+
+ droppablesLoop: for (i = 0; i < m.length; i++) {
+
+ //No disabled and non-accepted
+ if(m[i].options.disabled || (t && !m[i].accept.call(m[i].element[0],(t.currentItem || t.element)))) {
+ continue;
+ }
+
+ // Filter out elements in the current dragged item
+ for (j=0; j < list.length; j++) {
+ if(list[j] === m[i].element[0]) {
+ m[i].proportions.height = 0;
+ continue droppablesLoop;
+ }
+ }
+
+ m[i].visible = m[i].element.css("display") !== "none";
+ if(!m[i].visible) {
+ continue;
+ }
+
+ //Activate the droppable if used directly from draggables
+ if(type === "mousedown") {
+ m[i]._activate.call(m[i], event);
+ }
+
+ m[i].offset = m[i].element.offset();
+ m[i].proportions = { width: m[i].element[0].offsetWidth, height: m[i].element[0].offsetHeight };
+
+ }
+
+ },
+ drop: function(draggable, event) {
+
+ var dropped = false;
+ // Create a copy of the droppables in case the list changes during the drop (#9116)
+ $.each(($.ui.ddmanager.droppables[draggable.options.scope] || []).slice(), function() {
+
+ if(!this.options) {
+ return;
+ }
+ if (!this.options.disabled && this.visible && $.ui.intersect(draggable, this, this.options.tolerance)) {
+ dropped = this._drop.call(this, event) || dropped;
+ }
+
+ if (!this.options.disabled && this.visible && this.accept.call(this.element[0],(draggable.currentItem || draggable.element))) {
+ this.isout = true;
+ this.isover = false;
+ this._deactivate.call(this, event);
+ }
+
+ });
+ return dropped;
+
+ },
+ dragStart: function( draggable, event ) {
+ //Listen for scrolling so that if the dragging causes scrolling the position of the droppables can be recalculated (see #5003)
+ draggable.element.parentsUntil( "body" ).bind( "scroll.droppable", function() {
+ if( !draggable.options.refreshPositions ) {
+ $.ui.ddmanager.prepareOffsets( draggable, event );
+ }
+ });
+ },
+ drag: function(draggable, event) {
+
+ //If you have a highly dynamic page, you might try this option. It renders positions every time you move the mouse.
+ if(draggable.options.refreshPositions) {
+ $.ui.ddmanager.prepareOffsets(draggable, event);
+ }
+
+ //Run through all droppables and check their positions based on specific tolerance options
+ $.each($.ui.ddmanager.droppables[draggable.options.scope] || [], function() {
+
+ if(this.options.disabled || this.greedyChild || !this.visible) {
+ return;
+ }
+
+ var parentInstance, scope, parent,
+ intersects = $.ui.intersect(draggable, this, this.options.tolerance),
+ c = !intersects && this.isover ? "isout" : (intersects && !this.isover ? "isover" : null);
+ if(!c) {
+ return;
+ }
+
+ if (this.options.greedy) {
+ // find droppable parents with same scope
+ scope = this.options.scope;
+ parent = this.element.parents(":data(ui-droppable)").filter(function () {
+ return $.data(this, "ui-droppable").options.scope === scope;
+ });
+
+ if (parent.length) {
+ parentInstance = $.data(parent[0], "ui-droppable");
+ parentInstance.greedyChild = (c === "isover");
+ }
+ }
+
+ // we just moved into a greedy child
+ if (parentInstance && c === "isover") {
+ parentInstance.isover = false;
+ parentInstance.isout = true;
+ parentInstance._out.call(parentInstance, event);
+ }
+
+ this[c] = true;
+ this[c === "isout" ? "isover" : "isout"] = false;
+ this[c === "isover" ? "_over" : "_out"].call(this, event);
+
+ // we just moved out of a greedy child
+ if (parentInstance && c === "isout") {
+ parentInstance.isout = false;
+ parentInstance.isover = true;
+ parentInstance._over.call(parentInstance, event);
+ }
+ });
+
+ },
+ dragStop: function( draggable, event ) {
+ draggable.element.parentsUntil( "body" ).unbind( "scroll.droppable" );
+ //Call prepareOffsets one final time since IE does not fire return scroll events when overflow was caused by drag (see #5003)
+ if( !draggable.options.refreshPositions ) {
+ $.ui.ddmanager.prepareOffsets( draggable, event );
+ }
+ }
+};
+
+})(jQuery);
+
+(function( $, undefined ) {
+
+function num(v) {
+ return parseInt(v, 10) || 0;
+}
+
+function isNumber(value) {
+ return !isNaN(parseInt(value, 10));
+}
+
+$.widget("ui.resizable", $.ui.mouse, {
+ version: "1.10.3",
+ widgetEventPrefix: "resize",
+ options: {
+ alsoResize: false,
+ animate: false,
+ animateDuration: "slow",
+ animateEasing: "swing",
+ aspectRatio: false,
+ autoHide: false,
+ containment: false,
+ ghost: false,
+ grid: false,
+ handles: "e,s,se",
+ helper: false,
+ maxHeight: null,
+ maxWidth: null,
+ minHeight: 10,
+ minWidth: 10,
+ // See #7960
+ zIndex: 90,
+
+ // callbacks
+ resize: null,
+ start: null,
+ stop: null
+ },
+ _create: function() {
+
+ var n, i, handle, axis, hname,
+ that = this,
+ o = this.options;
+ this.element.addClass("ui-resizable");
+
+ $.extend(this, {
+ _aspectRatio: !!(o.aspectRatio),
+ aspectRatio: o.aspectRatio,
+ originalElement: this.element,
+ _proportionallyResizeElements: [],
+ _helper: o.helper || o.ghost || o.animate ? o.helper || "ui-resizable-helper" : null
+ });
+
+ //Wrap the element if it cannot hold child nodes
+ if(this.element[0].nodeName.match(/canvas|textarea|input|select|button|img/i)) {
+
+ //Create a wrapper element and set the wrapper to the new current internal element
+ this.element.wrap(
+ $("<div class='ui-wrapper' style='overflow: hidden;'></div>").css({
+ position: this.element.css("position"),
+ width: this.element.outerWidth(),
+ height: this.element.outerHeight(),
+ top: this.element.css("top"),
+ left: this.element.css("left")
+ })
+ );
+
+ //Overwrite the original this.element
+ this.element = this.element.parent().data(
+ "ui-resizable", this.element.data("ui-resizable")
+ );
+
+ this.elementIsWrapper = true;
+
+ //Move margins to the wrapper
+ this.element.css({ marginLeft: this.originalElement.css("marginLeft"), marginTop: this.originalElement.css("marginTop"), marginRight: this.originalElement.css("marginRight"), marginBottom: this.originalElement.css("marginBottom") });
+ this.originalElement.css({ marginLeft: 0, marginTop: 0, marginRight: 0, marginBottom: 0});
+
+ //Prevent Safari textarea resize
+ this.originalResizeStyle = this.originalElement.css("resize");
+ this.originalElement.css("resize", "none");
+
+ //Push the actual element to our proportionallyResize internal array
+ this._proportionallyResizeElements.push(this.originalElement.css({ position: "static", zoom: 1, display: "block" }));
+
+ // avoid IE jump (hard set the margin)
+ this.originalElement.css({ margin: this.originalElement.css("margin") });
+
+ // fix handlers offset
+ this._proportionallyResize();
+
+ }
+
+ this.handles = o.handles || (!$(".ui-resizable-handle", this.element).length ? "e,s,se" : { n: ".ui-resizable-n", e: ".ui-resizable-e", s: ".ui-resizable-s", w: ".ui-resizable-w", se: ".ui-resizable-se", sw: ".ui-resizable-sw", ne: ".ui-resizable-ne", nw: ".ui-resizable-nw" });
+ if(this.handles.constructor === String) {
+
+ if ( this.handles === "all") {
+ this.handles = "n,e,s,w,se,sw,ne,nw";
+ }
+
+ n = this.handles.split(",");
+ this.handles = {};
+
+ for(i = 0; i < n.length; i++) {
+
+ handle = $.trim(n[i]);
+ hname = "ui-resizable-"+handle;
+ axis = $("<div class='ui-resizable-handle " + hname + "'></div>");
+
+ // Apply zIndex to all handles - see #7960
+ axis.css({ zIndex: o.zIndex });
+
+ //TODO : What's going on here?
+ if ("se" === handle) {
+ axis.addClass("ui-icon ui-icon-gripsmall-diagonal-se");
+ }
+
+ //Insert into internal handles object and append to element
+ this.handles[handle] = ".ui-resizable-"+handle;
+ this.element.append(axis);
+ }
+
+ }
+
+ this._renderAxis = function(target) {
+
+ var i, axis, padPos, padWrapper;
+
+ target = target || this.element;
+
+ for(i in this.handles) {
+
+ if(this.handles[i].constructor === String) {
+ this.handles[i] = $(this.handles[i], this.element).show();
+ }
+
+ //Apply pad to wrapper element, needed to fix axis position (textarea, inputs, scrolls)
+ if (this.elementIsWrapper && this.originalElement[0].nodeName.match(/textarea|input|select|button/i)) {
+
+ axis = $(this.handles[i], this.element);
+
+ //Checking the correct pad and border
+ padWrapper = /sw|ne|nw|se|n|s/.test(i) ? axis.outerHeight() : axis.outerWidth();
+
+ //The padding type i have to apply...
+ padPos = [ "padding",
+ /ne|nw|n/.test(i) ? "Top" :
+ /se|sw|s/.test(i) ? "Bottom" :
+ /^e$/.test(i) ? "Right" : "Left" ].join("");
+
+ target.css(padPos, padWrapper);
+
+ this._proportionallyResize();
+
+ }
+
+ //TODO: What's that good for? There's not anything to be executed left
+ if(!$(this.handles[i]).length) {
+ continue;
+ }
+ }
+ };
+
+ //TODO: make renderAxis a prototype function
+ this._renderAxis(this.element);
+
+ this._handles = $(".ui-resizable-handle", this.element)
+ .disableSelection();
+
+ //Matching axis name
+ this._handles.mouseover(function() {
+ if (!that.resizing) {
+ if (this.className) {
+ axis = this.className.match(/ui-resizable-(se|sw|ne|nw|n|e|s|w)/i);
+ }
+ //Axis, default = se
+ that.axis = axis && axis[1] ? axis[1] : "se";
+ }
+ });
+
+ //If we want to auto hide the elements
+ if (o.autoHide) {
+ this._handles.hide();
+ $(this.element)
+ .addClass("ui-resizable-autohide")
+ .mouseenter(function() {
+ if (o.disabled) {
+ return;
+ }
+ $(this).removeClass("ui-resizable-autohide");
+ that._handles.show();
+ })
+ .mouseleave(function(){
+ if (o.disabled) {
+ return;
+ }
+ if (!that.resizing) {
+ $(this).addClass("ui-resizable-autohide");
+ that._handles.hide();
+ }
+ });
+ }
+
+ //Initialize the mouse interaction
+ this._mouseInit();
+
+ },
+
+ _destroy: function() {
+
+ this._mouseDestroy();
+
+ var wrapper,
+ _destroy = function(exp) {
+ $(exp).removeClass("ui-resizable ui-resizable-disabled ui-resizable-resizing")
+ .removeData("resizable").removeData("ui-resizable").unbind(".resizable").find(".ui-resizable-handle").remove();
+ };
+
+ //TODO: Unwrap at same DOM position
+ if (this.elementIsWrapper) {
+ _destroy(this.element);
+ wrapper = this.element;
+ this.originalElement.css({
+ position: wrapper.css("position"),
+ width: wrapper.outerWidth(),
+ height: wrapper.outerHeight(),
+ top: wrapper.css("top"),
+ left: wrapper.css("left")
+ }).insertAfter( wrapper );
+ wrapper.remove();
+ }
+
+ this.originalElement.css("resize", this.originalResizeStyle);
+ _destroy(this.originalElement);
+
+ return this;
+ },
+
+ _mouseCapture: function(event) {
+ var i, handle,
+ capture = false;
+
+ for (i in this.handles) {
+ handle = $(this.handles[i])[0];
+ if (handle === event.target || $.contains(handle, event.target)) {
+ capture = true;
+ }
+ }
+
+ return !this.options.disabled && capture;
+ },
+
+ _mouseStart: function(event) {
+
+ var curleft, curtop, cursor,
+ o = this.options,
+ iniPos = this.element.position(),
+ el = this.element;
+
+ this.resizing = true;
+
+ // bugfix for http://dev.jquery.com/ticket/1749
+ if ( (/absolute/).test( el.css("position") ) ) {
+ el.css({ position: "absolute", top: el.css("top"), left: el.css("left") });
+ } else if (el.is(".ui-draggable")) {
+ el.css({ position: "absolute", top: iniPos.top, left: iniPos.left });
+ }
+
+ this._renderProxy();
+
+ curleft = num(this.helper.css("left"));
+ curtop = num(this.helper.css("top"));
+
+ if (o.containment) {
+ curleft += $(o.containment).scrollLeft() || 0;
+ curtop += $(o.containment).scrollTop() || 0;
+ }
+
+ //Store needed variables
+ this.offset = this.helper.offset();
+ this.position = { left: curleft, top: curtop };
+ this.size = this._helper ? { width: el.outerWidth(), height: el.outerHeight() } : { width: el.width(), height: el.height() };
+ this.originalSize = this._helper ? { width: el.outerWidth(), height: el.outerHeight() } : { width: el.width(), height: el.height() };
+ this.originalPosition = { left: curleft, top: curtop };
+ this.sizeDiff = { width: el.outerWidth() - el.width(), height: el.outerHeight() - el.height() };
+ this.originalMousePosition = { left: event.pageX, top: event.pageY };
+
+ //Aspect Ratio
+ this.aspectRatio = (typeof o.aspectRatio === "number") ? o.aspectRatio : ((this.originalSize.width / this.originalSize.height) || 1);
+
+ cursor = $(".ui-resizable-" + this.axis).css("cursor");
+ $("body").css("cursor", cursor === "auto" ? this.axis + "-resize" : cursor);
+
+ el.addClass("ui-resizable-resizing");
+ this._propagate("start", event);
+ return true;
+ },
+
+ _mouseDrag: function(event) {
+
+ //Increase performance, avoid regex
+ var data,
+ el = this.helper, props = {},
+ smp = this.originalMousePosition,
+ a = this.axis,
+ prevTop = this.position.top,
+ prevLeft = this.position.left,
+ prevWidth = this.size.width,
+ prevHeight = this.size.height,
+ dx = (event.pageX-smp.left)||0,
+ dy = (event.pageY-smp.top)||0,
+ trigger = this._change[a];
+
+ if (!trigger) {
+ return false;
+ }
+
+ // Calculate the attrs that will be change
+ data = trigger.apply(this, [event, dx, dy]);
+
+ // Put this in the mouseDrag handler since the user can start pressing shift while resizing
+ this._updateVirtualBoundaries(event.shiftKey);
+ if (this._aspectRatio || event.shiftKey) {
+ data = this._updateRatio(data, event);
+ }
+
+ data = this._respectSize(data, event);
+
+ this._updateCache(data);
+
+ // plugins callbacks need to be called first
+ this._propagate("resize", event);
+
+ if (this.position.top !== prevTop) {
+ props.top = this.position.top + "px";
+ }
+ if (this.position.left !== prevLeft) {
+ props.left = this.position.left + "px";
+ }
+ if (this.size.width !== prevWidth) {
+ props.width = this.size.width + "px";
+ }
+ if (this.size.height !== prevHeight) {
+ props.height = this.size.height + "px";
+ }
+ el.css(props);
+
+ if (!this._helper && this._proportionallyResizeElements.length) {
+ this._proportionallyResize();
+ }
+
+ // Call the user callback if the element was resized
+ if ( ! $.isEmptyObject(props) ) {
+ this._trigger("resize", event, this.ui());
+ }
+
+ return false;
+ },
+
+ _mouseStop: function(event) {
+
+ this.resizing = false;
+ var pr, ista, soffseth, soffsetw, s, left, top,
+ o = this.options, that = this;
+
+ if(this._helper) {
+
+ pr = this._proportionallyResizeElements;
+ ista = pr.length && (/textarea/i).test(pr[0].nodeName);
+ soffseth = ista && $.ui.hasScroll(pr[0], "left") /* TODO - jump height */ ? 0 : that.sizeDiff.height;
+ soffsetw = ista ? 0 : that.sizeDiff.width;
+
+ s = { width: (that.helper.width() - soffsetw), height: (that.helper.height() - soffseth) };
+ left = (parseInt(that.element.css("left"), 10) + (that.position.left - that.originalPosition.left)) || null;
+ top = (parseInt(that.element.css("top"), 10) + (that.position.top - that.originalPosition.top)) || null;
+
+ if (!o.animate) {
+ this.element.css($.extend(s, { top: top, left: left }));
+ }
+
+ that.helper.height(that.size.height);
+ that.helper.width(that.size.width);
+
+ if (this._helper && !o.animate) {
+ this._proportionallyResize();
+ }
+ }
+
+ $("body").css("cursor", "auto");
+
+ this.element.removeClass("ui-resizable-resizing");
+
+ this._propagate("stop", event);
+
+ if (this._helper) {
+ this.helper.remove();
+ }
+
+ return false;
+
+ },
+
+ _updateVirtualBoundaries: function(forceAspectRatio) {
+ var pMinWidth, pMaxWidth, pMinHeight, pMaxHeight, b,
+ o = this.options;
+
+ b = {
+ minWidth: isNumber(o.minWidth) ? o.minWidth : 0,
+ maxWidth: isNumber(o.maxWidth) ? o.maxWidth : Infinity,
+ minHeight: isNumber(o.minHeight) ? o.minHeight : 0,
+ maxHeight: isNumber(o.maxHeight) ? o.maxHeight : Infinity
+ };
+
+ if(this._aspectRatio || forceAspectRatio) {
+ // We want to create an enclosing box whose aspect ration is the requested one
+ // First, compute the "projected" size for each dimension based on the aspect ratio and other dimension
+ pMinWidth = b.minHeight * this.aspectRatio;
+ pMinHeight = b.minWidth / this.aspectRatio;
+ pMaxWidth = b.maxHeight * this.aspectRatio;
+ pMaxHeight = b.maxWidth / this.aspectRatio;
+
+ if(pMinWidth > b.minWidth) {
+ b.minWidth = pMinWidth;
+ }
+ if(pMinHeight > b.minHeight) {
+ b.minHeight = pMinHeight;
+ }
+ if(pMaxWidth < b.maxWidth) {
+ b.maxWidth = pMaxWidth;
+ }
+ if(pMaxHeight < b.maxHeight) {
+ b.maxHeight = pMaxHeight;
+ }
+ }
+ this._vBoundaries = b;
+ },
+
+ _updateCache: function(data) {
+ this.offset = this.helper.offset();
+ if (isNumber(data.left)) {
+ this.position.left = data.left;
+ }
+ if (isNumber(data.top)) {
+ this.position.top = data.top;
+ }
+ if (isNumber(data.height)) {
+ this.size.height = data.height;
+ }
+ if (isNumber(data.width)) {
+ this.size.width = data.width;
+ }
+ },
+
+ _updateRatio: function( data ) {
+
+ var cpos = this.position,
+ csize = this.size,
+ a = this.axis;
+
+ if (isNumber(data.height)) {
+ data.width = (data.height * this.aspectRatio);
+ } else if (isNumber(data.width)) {
+ data.height = (data.width / this.aspectRatio);
+ }
+
+ if (a === "sw") {
+ data.left = cpos.left + (csize.width - data.width);
+ data.top = null;
+ }
+ if (a === "nw") {
+ data.top = cpos.top + (csize.height - data.height);
+ data.left = cpos.left + (csize.width - data.width);
+ }
+
+ return data;
+ },
+
+ _respectSize: function( data ) {
+
+ var o = this._vBoundaries,
+ a = this.axis,
+ ismaxw = isNumber(data.width) && o.maxWidth && (o.maxWidth < data.width), ismaxh = isNumber(data.height) && o.maxHeight && (o.maxHeight < data.height),
+ isminw = isNumber(data.width) && o.minWidth && (o.minWidth > data.width), isminh = isNumber(data.height) && o.minHeight && (o.minHeight > data.height),
+ dw = this.originalPosition.left + this.originalSize.width,
+ dh = this.position.top + this.size.height,
+ cw = /sw|nw|w/.test(a), ch = /nw|ne|n/.test(a);
+ if (isminw) {
+ data.width = o.minWidth;
+ }
+ if (isminh) {
+ data.height = o.minHeight;
+ }
+ if (ismaxw) {
+ data.width = o.maxWidth;
+ }
+ if (ismaxh) {
+ data.height = o.maxHeight;
+ }
+
+ if (isminw && cw) {
+ data.left = dw - o.minWidth;
+ }
+ if (ismaxw && cw) {
+ data.left = dw - o.maxWidth;
+ }
+ if (isminh && ch) {
+ data.top = dh - o.minHeight;
+ }
+ if (ismaxh && ch) {
+ data.top = dh - o.maxHeight;
+ }
+
+ // fixing jump error on top/left - bug #2330
+ if (!data.width && !data.height && !data.left && data.top) {
+ data.top = null;
+ } else if (!data.width && !data.height && !data.top && data.left) {
+ data.left = null;
+ }
+
+ return data;
+ },
+
+ _proportionallyResize: function() {
+
+ if (!this._proportionallyResizeElements.length) {
+ return;
+ }
+
+ var i, j, borders, paddings, prel,
+ element = this.helper || this.element;
+
+ for ( i=0; i < this._proportionallyResizeElements.length; i++) {
+
+ prel = this._proportionallyResizeElements[i];
+
+ if (!this.borderDif) {
+ this.borderDif = [];
+ borders = [prel.css("borderTopWidth"), prel.css("borderRightWidth"), prel.css("borderBottomWidth"), prel.css("borderLeftWidth")];
+ paddings = [prel.css("paddingTop"), prel.css("paddingRight"), prel.css("paddingBottom"), prel.css("paddingLeft")];
+
+ for ( j = 0; j < borders.length; j++ ) {
+ this.borderDif[ j ] = ( parseInt( borders[ j ], 10 ) || 0 ) + ( parseInt( paddings[ j ], 10 ) || 0 );
+ }
+ }
+
+ prel.css({
+ height: (element.height() - this.borderDif[0] - this.borderDif[2]) || 0,
+ width: (element.width() - this.borderDif[1] - this.borderDif[3]) || 0
+ });
+
+ }
+
+ },
+
+ _renderProxy: function() {
+
+ var el = this.element, o = this.options;
+ this.elementOffset = el.offset();
+
+ if(this._helper) {
+
+ this.helper = this.helper || $("<div style='overflow:hidden;'></div>");
+
+ this.helper.addClass(this._helper).css({
+ width: this.element.outerWidth() - 1,
+ height: this.element.outerHeight() - 1,
+ position: "absolute",
+ left: this.elementOffset.left +"px",
+ top: this.elementOffset.top +"px",
+ zIndex: ++o.zIndex //TODO: Don't modify option
+ });
+
+ this.helper
+ .appendTo("body")
+ .disableSelection();
+
+ } else {
+ this.helper = this.element;
+ }
+
+ },
+
+ _change: {
+ e: function(event, dx) {
+ return { width: this.originalSize.width + dx };
+ },
+ w: function(event, dx) {
+ var cs = this.originalSize, sp = this.originalPosition;
+ return { left: sp.left + dx, width: cs.width - dx };
+ },
+ n: function(event, dx, dy) {
+ var cs = this.originalSize, sp = this.originalPosition;
+ return { top: sp.top + dy, height: cs.height - dy };
+ },
+ s: function(event, dx, dy) {
+ return { height: this.originalSize.height + dy };
+ },
+ se: function(event, dx, dy) {
+ return $.extend(this._change.s.apply(this, arguments), this._change.e.apply(this, [event, dx, dy]));
+ },
+ sw: function(event, dx, dy) {
+ return $.extend(this._change.s.apply(this, arguments), this._change.w.apply(this, [event, dx, dy]));
+ },
+ ne: function(event, dx, dy) {
+ return $.extend(this._change.n.apply(this, arguments), this._change.e.apply(this, [event, dx, dy]));
+ },
+ nw: function(event, dx, dy) {
+ return $.extend(this._change.n.apply(this, arguments), this._change.w.apply(this, [event, dx, dy]));
+ }
+ },
+
+ _propagate: function(n, event) {
+ $.ui.plugin.call(this, n, [event, this.ui()]);
+ (n !== "resize" && this._trigger(n, event, this.ui()));
+ },
+
+ plugins: {},
+
+ ui: function() {
+ return {
+ originalElement: this.originalElement,
+ element: this.element,
+ helper: this.helper,
+ position: this.position,
+ size: this.size,
+ originalSize: this.originalSize,
+ originalPosition: this.originalPosition
+ };
+ }
+
+});
+
+/*
+ * Resizable Extensions
+ */
+
+$.ui.plugin.add("resizable", "animate", {
+
+ stop: function( event ) {
+ var that = $(this).data("ui-resizable"),
+ o = that.options,
+ pr = that._proportionallyResizeElements,
+ ista = pr.length && (/textarea/i).test(pr[0].nodeName),
+ soffseth = ista && $.ui.hasScroll(pr[0], "left") /* TODO - jump height */ ? 0 : that.sizeDiff.height,
+ soffsetw = ista ? 0 : that.sizeDiff.width,
+ style = { width: (that.size.width - soffsetw), height: (that.size.height - soffseth) },
+ left = (parseInt(that.element.css("left"), 10) + (that.position.left - that.originalPosition.left)) || null,
+ top = (parseInt(that.element.css("top"), 10) + (that.position.top - that.originalPosition.top)) || null;
+
+ that.element.animate(
+ $.extend(style, top && left ? { top: top, left: left } : {}), {
+ duration: o.animateDuration,
+ easing: o.animateEasing,
+ step: function() {
+
+ var data = {
+ width: parseInt(that.element.css("width"), 10),
+ height: parseInt(that.element.css("height"), 10),
+ top: parseInt(that.element.css("top"), 10),
+ left: parseInt(that.element.css("left"), 10)
+ };
+
+ if (pr && pr.length) {
+ $(pr[0]).css({ width: data.width, height: data.height });
+ }
+
+ // propagating resize, and updating values for each animation step
+ that._updateCache(data);
+ that._propagate("resize", event);
+
+ }
+ }
+ );
+ }
+
+});
+
+$.ui.plugin.add("resizable", "containment", {
+
+ start: function() {
+ var element, p, co, ch, cw, width, height,
+ that = $(this).data("ui-resizable"),
+ o = that.options,
+ el = that.element,
+ oc = o.containment,
+ ce = (oc instanceof $) ? oc.get(0) : (/parent/.test(oc)) ? el.parent().get(0) : oc;
+
+ if (!ce) {
+ return;
+ }
+
+ that.containerElement = $(ce);
+
+ if (/document/.test(oc) || oc === document) {
+ that.containerOffset = { left: 0, top: 0 };
+ that.containerPosition = { left: 0, top: 0 };
+
+ that.parentData = {
+ element: $(document), left: 0, top: 0,
+ width: $(document).width(), height: $(document).height() || document.body.parentNode.scrollHeight
+ };
+ }
+
+ // i'm a node, so compute top, left, right, bottom
+ else {
+ element = $(ce);
+ p = [];
+ $([ "Top", "Right", "Left", "Bottom" ]).each(function(i, name) { p[i] = num(element.css("padding" + name)); });
+
+ that.containerOffset = element.offset();
+ that.containerPosition = element.position();
+ that.containerSize = { height: (element.innerHeight() - p[3]), width: (element.innerWidth() - p[1]) };
+
+ co = that.containerOffset;
+ ch = that.containerSize.height;
+ cw = that.containerSize.width;
+ width = ($.ui.hasScroll(ce, "left") ? ce.scrollWidth : cw );
+ height = ($.ui.hasScroll(ce) ? ce.scrollHeight : ch);
+
+ that.parentData = {
+ element: ce, left: co.left, top: co.top, width: width, height: height
+ };
+ }
+ },
+
+ resize: function( event ) {
+ var woset, hoset, isParent, isOffsetRelative,
+ that = $(this).data("ui-resizable"),
+ o = that.options,
+ co = that.containerOffset, cp = that.position,
+ pRatio = that._aspectRatio || event.shiftKey,
+ cop = { top:0, left:0 }, ce = that.containerElement;
+
+ if (ce[0] !== document && (/static/).test(ce.css("position"))) {
+ cop = co;
+ }
+
+ if (cp.left < (that._helper ? co.left : 0)) {
+ that.size.width = that.size.width + (that._helper ? (that.position.left - co.left) : (that.position.left - cop.left));
+ if (pRatio) {
+ that.size.height = that.size.width / that.aspectRatio;
+ }
+ that.position.left = o.helper ? co.left : 0;
+ }
+
+ if (cp.top < (that._helper ? co.top : 0)) {
+ that.size.height = that.size.height + (that._helper ? (that.position.top - co.top) : that.position.top);
+ if (pRatio) {
+ that.size.width = that.size.height * that.aspectRatio;
+ }
+ that.position.top = that._helper ? co.top : 0;
+ }
+
+ that.offset.left = that.parentData.left+that.position.left;
+ that.offset.top = that.parentData.top+that.position.top;
+
+ woset = Math.abs( (that._helper ? that.offset.left - cop.left : (that.offset.left - cop.left)) + that.sizeDiff.width );
+ hoset = Math.abs( (that._helper ? that.offset.top - cop.top : (that.offset.top - co.top)) + that.sizeDiff.height );
+
+ isParent = that.containerElement.get(0) === that.element.parent().get(0);
+ isOffsetRelative = /relative|absolute/.test(that.containerElement.css("position"));
+
+ if(isParent && isOffsetRelative) {
+ woset -= that.parentData.left;
+ }
+
+ if (woset + that.size.width >= that.parentData.width) {
+ that.size.width = that.parentData.width - woset;
+ if (pRatio) {
+ that.size.height = that.size.width / that.aspectRatio;
+ }
+ }
+
+ if (hoset + that.size.height >= that.parentData.height) {
+ that.size.height = that.parentData.height - hoset;
+ if (pRatio) {
+ that.size.width = that.size.height * that.aspectRatio;
+ }
+ }
+ },
+
+ stop: function(){
+ var that = $(this).data("ui-resizable"),
+ o = that.options,
+ co = that.containerOffset,
+ cop = that.containerPosition,
+ ce = that.containerElement,
+ helper = $(that.helper),
+ ho = helper.offset(),
+ w = helper.outerWidth() - that.sizeDiff.width,
+ h = helper.outerHeight() - that.sizeDiff.height;
+
+ if (that._helper && !o.animate && (/relative/).test(ce.css("position"))) {
+ $(this).css({ left: ho.left - cop.left - co.left, width: w, height: h });
+ }
+
+ if (that._helper && !o.animate && (/static/).test(ce.css("position"))) {
+ $(this).css({ left: ho.left - cop.left - co.left, width: w, height: h });
+ }
+
+ }
+});
+
+$.ui.plugin.add("resizable", "alsoResize", {
+
+ start: function () {
+ var that = $(this).data("ui-resizable"),
+ o = that.options,
+ _store = function (exp) {
+ $(exp).each(function() {
+ var el = $(this);
+ el.data("ui-resizable-alsoresize", {
+ width: parseInt(el.width(), 10), height: parseInt(el.height(), 10),
+ left: parseInt(el.css("left"), 10), top: parseInt(el.css("top"), 10)
+ });
+ });
+ };
+
+ if (typeof(o.alsoResize) === "object" && !o.alsoResize.parentNode) {
+ if (o.alsoResize.length) { o.alsoResize = o.alsoResize[0]; _store(o.alsoResize); }
+ else { $.each(o.alsoResize, function (exp) { _store(exp); }); }
+ }else{
+ _store(o.alsoResize);
+ }
+ },
+
+ resize: function (event, ui) {
+ var that = $(this).data("ui-resizable"),
+ o = that.options,
+ os = that.originalSize,
+ op = that.originalPosition,
+ delta = {
+ height: (that.size.height - os.height) || 0, width: (that.size.width - os.width) || 0,
+ top: (that.position.top - op.top) || 0, left: (that.position.left - op.left) || 0
+ },
+
+ _alsoResize = function (exp, c) {
+ $(exp).each(function() {
+ var el = $(this), start = $(this).data("ui-resizable-alsoresize"), style = {},
+ css = c && c.length ? c : el.parents(ui.originalElement[0]).length ? ["width", "height"] : ["width", "height", "top", "left"];
+
+ $.each(css, function (i, prop) {
+ var sum = (start[prop]||0) + (delta[prop]||0);
+ if (sum && sum >= 0) {
+ style[prop] = sum || null;
+ }
+ });
+
+ el.css(style);
+ });
+ };
+
+ if (typeof(o.alsoResize) === "object" && !o.alsoResize.nodeType) {
+ $.each(o.alsoResize, function (exp, c) { _alsoResize(exp, c); });
+ }else{
+ _alsoResize(o.alsoResize);
+ }
+ },
+
+ stop: function () {
+ $(this).removeData("resizable-alsoresize");
+ }
+});
+
+$.ui.plugin.add("resizable", "ghost", {
+
+ start: function() {
+
+ var that = $(this).data("ui-resizable"), o = that.options, cs = that.size;
+
+ that.ghost = that.originalElement.clone();
+ that.ghost
+ .css({ opacity: 0.25, display: "block", position: "relative", height: cs.height, width: cs.width, margin: 0, left: 0, top: 0 })
+ .addClass("ui-resizable-ghost")
+ .addClass(typeof o.ghost === "string" ? o.ghost : "");
+
+ that.ghost.appendTo(that.helper);
+
+ },
+
+ resize: function(){
+ var that = $(this).data("ui-resizable");
+ if (that.ghost) {
+ that.ghost.css({ position: "relative", height: that.size.height, width: that.size.width });
+ }
+ },
+
+ stop: function() {
+ var that = $(this).data("ui-resizable");
+ if (that.ghost && that.helper) {
+ that.helper.get(0).removeChild(that.ghost.get(0));
+ }
+ }
+
+});
+
+$.ui.plugin.add("resizable", "grid", {
+
+ resize: function() {
+ var that = $(this).data("ui-resizable"),
+ o = that.options,
+ cs = that.size,
+ os = that.originalSize,
+ op = that.originalPosition,
+ a = that.axis,
+ grid = typeof o.grid === "number" ? [o.grid, o.grid] : o.grid,
+ gridX = (grid[0]||1),
+ gridY = (grid[1]||1),
+ ox = Math.round((cs.width - os.width) / gridX) * gridX,
+ oy = Math.round((cs.height - os.height) / gridY) * gridY,
+ newWidth = os.width + ox,
+ newHeight = os.height + oy,
+ isMaxWidth = o.maxWidth && (o.maxWidth < newWidth),
+ isMaxHeight = o.maxHeight && (o.maxHeight < newHeight),
+ isMinWidth = o.minWidth && (o.minWidth > newWidth),
+ isMinHeight = o.minHeight && (o.minHeight > newHeight);
+
+ o.grid = grid;
+
+ if (isMinWidth) {
+ newWidth = newWidth + gridX;
+ }
+ if (isMinHeight) {
+ newHeight = newHeight + gridY;
+ }
+ if (isMaxWidth) {
+ newWidth = newWidth - gridX;
+ }
+ if (isMaxHeight) {
+ newHeight = newHeight - gridY;
+ }
+
+ if (/^(se|s|e)$/.test(a)) {
+ that.size.width = newWidth;
+ that.size.height = newHeight;
+ } else if (/^(ne)$/.test(a)) {
+ that.size.width = newWidth;
+ that.size.height = newHeight;
+ that.position.top = op.top - oy;
+ } else if (/^(sw)$/.test(a)) {
+ that.size.width = newWidth;
+ that.size.height = newHeight;
+ that.position.left = op.left - ox;
+ } else {
+ that.size.width = newWidth;
+ that.size.height = newHeight;
+ that.position.top = op.top - oy;
+ that.position.left = op.left - ox;
+ }
+ }
+
+});
+
+})(jQuery);
+
+(function( $, undefined ) {
+
+$.widget("ui.selectable", $.ui.mouse, {
+ version: "1.10.3",
+ options: {
+ appendTo: "body",
+ autoRefresh: true,
+ distance: 0,
+ filter: "*",
+ tolerance: "touch",
+
+ // callbacks
+ selected: null,
+ selecting: null,
+ start: null,
+ stop: null,
+ unselected: null,
+ unselecting: null
+ },
+ _create: function() {
+ var selectees,
+ that = this;
+
+ this.element.addClass("ui-selectable");
+
+ this.dragged = false;
+
+ // cache selectee children based on filter
+ this.refresh = function() {
+ selectees = $(that.options.filter, that.element[0]);
+ selectees.addClass("ui-selectee");
+ selectees.each(function() {
+ var $this = $(this),
+ pos = $this.offset();
+ $.data(this, "selectable-item", {
+ element: this,
+ $element: $this,
+ left: pos.left,
+ top: pos.top,
+ right: pos.left + $this.outerWidth(),
+ bottom: pos.top + $this.outerHeight(),
+ startselected: false,
+ selected: $this.hasClass("ui-selected"),
+ selecting: $this.hasClass("ui-selecting"),
+ unselecting: $this.hasClass("ui-unselecting")
+ });
+ });
+ };
+ this.refresh();
+
+ this.selectees = selectees.addClass("ui-selectee");
+
+ this._mouseInit();
+
+ this.helper = $("<div class='ui-selectable-helper'></div>");
+ },
+
+ _destroy: function() {
+ this.selectees
+ .removeClass("ui-selectee")
+ .removeData("selectable-item");
+ this.element
+ .removeClass("ui-selectable ui-selectable-disabled");
+ this._mouseDestroy();
+ },
+
+ _mouseStart: function(event) {
+ var that = this,
+ options = this.options;
+
+ this.opos = [event.pageX, event.pageY];
+
+ if (this.options.disabled) {
+ return;
+ }
+
+ this.selectees = $(options.filter, this.element[0]);
+
+ this._trigger("start", event);
+
+ $(options.appendTo).append(this.helper);
+ // position helper (lasso)
+ this.helper.css({
+ "left": event.pageX,
+ "top": event.pageY,
+ "width": 0,
+ "height": 0
+ });
+
+ if (options.autoRefresh) {
+ this.refresh();
+ }
+
+ this.selectees.filter(".ui-selected").each(function() {
+ var selectee = $.data(this, "selectable-item");
+ selectee.startselected = true;
+ if (!event.metaKey && !event.ctrlKey) {
+ selectee.$element.removeClass("ui-selected");
+ selectee.selected = false;
+ selectee.$element.addClass("ui-unselecting");
+ selectee.unselecting = true;
+ // selectable UNSELECTING callback
+ that._trigger("unselecting", event, {
+ unselecting: selectee.element
+ });
+ }
+ });
+
+ $(event.target).parents().addBack().each(function() {
+ var doSelect,
+ selectee = $.data(this, "selectable-item");
+ if (selectee) {
+ doSelect = (!event.metaKey && !event.ctrlKey) || !selectee.$element.hasClass("ui-selected");
+ selectee.$element
+ .removeClass(doSelect ? "ui-unselecting" : "ui-selected")
+ .addClass(doSelect ? "ui-selecting" : "ui-unselecting");
+ selectee.unselecting = !doSelect;
+ selectee.selecting = doSelect;
+ selectee.selected = doSelect;
+ // selectable (UN)SELECTING callback
+ if (doSelect) {
+ that._trigger("selecting", event, {
+ selecting: selectee.element
+ });
+ } else {
+ that._trigger("unselecting", event, {
+ unselecting: selectee.element
+ });
+ }
+ return false;
+ }
+ });
+
+ },
+
+ _mouseDrag: function(event) {
+
+ this.dragged = true;
+
+ if (this.options.disabled) {
+ return;
+ }
+
+ var tmp,
+ that = this,
+ options = this.options,
+ x1 = this.opos[0],
+ y1 = this.opos[1],
+ x2 = event.pageX,
+ y2 = event.pageY;
+
+ if (x1 > x2) { tmp = x2; x2 = x1; x1 = tmp; }
+ if (y1 > y2) { tmp = y2; y2 = y1; y1 = tmp; }
+ this.helper.css({left: x1, top: y1, width: x2-x1, height: y2-y1});
+
+ this.selectees.each(function() {
+ var selectee = $.data(this, "selectable-item"),
+ hit = false;
+
+ //prevent helper from being selected if appendTo: selectable
+ if (!selectee || selectee.element === that.element[0]) {
+ return;
+ }
+
+ if (options.tolerance === "touch") {
+ hit = ( !(selectee.left > x2 || selectee.right < x1 || selectee.top > y2 || selectee.bottom < y1) );
+ } else if (options.tolerance === "fit") {
+ hit = (selectee.left > x1 && selectee.right < x2 && selectee.top > y1 && selectee.bottom < y2);
+ }
+
+ if (hit) {
+ // SELECT
+ if (selectee.selected) {
+ selectee.$element.removeClass("ui-selected");
+ selectee.selected = false;
+ }
+ if (selectee.unselecting) {
+ selectee.$element.removeClass("ui-unselecting");
+ selectee.unselecting = false;
+ }
+ if (!selectee.selecting) {
+ selectee.$element.addClass("ui-selecting");
+ selectee.selecting = true;
+ // selectable SELECTING callback
+ that._trigger("selecting", event, {
+ selecting: selectee.element
+ });
+ }
+ } else {
+ // UNSELECT
+ if (selectee.selecting) {
+ if ((event.metaKey || event.ctrlKey) && selectee.startselected) {
+ selectee.$element.removeClass("ui-selecting");
+ selectee.selecting = false;
+ selectee.$element.addClass("ui-selected");
+ selectee.selected = true;
+ } else {
+ selectee.$element.removeClass("ui-selecting");
+ selectee.selecting = false;
+ if (selectee.startselected) {
+ selectee.$element.addClass("ui-unselecting");
+ selectee.unselecting = true;
+ }
+ // selectable UNSELECTING callback
+ that._trigger("unselecting", event, {
+ unselecting: selectee.element
+ });
+ }
+ }
+ if (selectee.selected) {
+ if (!event.metaKey && !event.ctrlKey && !selectee.startselected) {
+ selectee.$element.removeClass("ui-selected");
+ selectee.selected = false;
+
+ selectee.$element.addClass("ui-unselecting");
+ selectee.unselecting = true;
+ // selectable UNSELECTING callback
+ that._trigger("unselecting", event, {
+ unselecting: selectee.element
+ });
+ }
+ }
+ }
+ });
+
+ return false;
+ },
+
+ _mouseStop: function(event) {
+ var that = this;
+
+ this.dragged = false;
+
+ $(".ui-unselecting", this.element[0]).each(function() {
+ var selectee = $.data(this, "selectable-item");
+ selectee.$element.removeClass("ui-unselecting");
+ selectee.unselecting = false;
+ selectee.startselected = false;
+ that._trigger("unselected", event, {
+ unselected: selectee.element
+ });
+ });
+ $(".ui-selecting", this.element[0]).each(function() {
+ var selectee = $.data(this, "selectable-item");
+ selectee.$element.removeClass("ui-selecting").addClass("ui-selected");
+ selectee.selecting = false;
+ selectee.selected = true;
+ selectee.startselected = true;
+ that._trigger("selected", event, {
+ selected: selectee.element
+ });
+ });
+ this._trigger("stop", event);
+
+ this.helper.remove();
+
+ return false;
+ }
+
+});
+
+})(jQuery);
+
+(function( $, undefined ) {
+
+/*jshint loopfunc: true */
+
+function isOverAxis( x, reference, size ) {
+ return ( x > reference ) && ( x < ( reference + size ) );
+}
+
+function isFloating(item) {
+ return (/left|right/).test(item.css("float")) || (/inline|table-cell/).test(item.css("display"));
+}
+
+$.widget("ui.sortable", $.ui.mouse, {
+ version: "1.10.3",
+ widgetEventPrefix: "sort",
+ ready: false,
+ options: {
+ appendTo: "parent",
+ axis: false,
+ connectWith: false,
+ containment: false,
+ cursor: "auto",
+ cursorAt: false,
+ dropOnEmpty: true,
+ forcePlaceholderSize: false,
+ forceHelperSize: false,
+ grid: false,
+ handle: false,
+ helper: "original",
+ items: "> *",
+ opacity: false,
+ placeholder: false,
+ revert: false,
+ scroll: true,
+ scrollSensitivity: 20,
+ scrollSpeed: 20,
+ scope: "default",
+ tolerance: "intersect",
+ zIndex: 1000,
+
+ // callbacks
+ activate: null,
+ beforeStop: null,
+ change: null,
+ deactivate: null,
+ out: null,
+ over: null,
+ receive: null,
+ remove: null,
+ sort: null,
+ start: null,
+ stop: null,
+ update: null
+ },
+ _create: function() {
+
+ var o = this.options;
+ this.containerCache = {};
+ this.element.addClass("ui-sortable");
+
+ //Get the items
+ this.refresh();
+
+ //Let's determine if the items are being displayed horizontally
+ this.floating = this.items.length ? o.axis === "x" || isFloating(this.items[0].item) : false;
+
+ //Let's determine the parent's offset
+ this.offset = this.element.offset();
+
+ //Initialize mouse events for interaction
+ this._mouseInit();
+
+ //We're ready to go
+ this.ready = true;
+
+ },
+
+ _destroy: function() {
+ this.element
+ .removeClass("ui-sortable ui-sortable-disabled");
+ this._mouseDestroy();
+
+ for ( var i = this.items.length - 1; i >= 0; i-- ) {
+ this.items[i].item.removeData(this.widgetName + "-item");
+ }
+
+ return this;
+ },
+
+ _setOption: function(key, value){
+ if ( key === "disabled" ) {
+ this.options[ key ] = value;
+
+ this.widget().toggleClass( "ui-sortable-disabled", !!value );
+ } else {
+ // Don't call widget base _setOption for disable as it adds ui-state-disabled class
+ $.Widget.prototype._setOption.apply(this, arguments);
+ }
+ },
+
+ _mouseCapture: function(event, overrideHandle) {
+ var currentItem = null,
+ validHandle = false,
+ that = this;
+
+ if (this.reverting) {
+ return false;
+ }
+
+ if(this.options.disabled || this.options.type === "static") {
+ return false;
+ }
+
+ //We have to refresh the items data once first
+ this._refreshItems(event);
+
+ //Find out if the clicked node (or one of its parents) is a actual item in this.items
+ $(event.target).parents().each(function() {
+ if($.data(this, that.widgetName + "-item") === that) {
+ currentItem = $(this);
+ return false;
+ }
+ });
+ if($.data(event.target, that.widgetName + "-item") === that) {
+ currentItem = $(event.target);
+ }
+
+ if(!currentItem) {
+ return false;
+ }
+ if(this.options.handle && !overrideHandle) {
+ $(this.options.handle, currentItem).find("*").addBack().each(function() {
+ if(this === event.target) {
+ validHandle = true;
+ }
+ });
+ if(!validHandle) {
+ return false;
+ }
+ }
+
+ this.currentItem = currentItem;
+ this._removeCurrentsFromItems();
+ return true;
+
+ },
+
+ _mouseStart: function(event, overrideHandle, noActivation) {
+
+ var i, body,
+ o = this.options;
+
+ this.currentContainer = this;
+
+ //We only need to call refreshPositions, because the refreshItems call has been moved to mouseCapture
+ this.refreshPositions();
+
+ //Create and append the visible helper
+ this.helper = this._createHelper(event);
+
+ //Cache the helper size
+ this._cacheHelperProportions();
+
+ /*
+ * - Position generation -
+ * This block generates everything position related - it's the core of draggables.
+ */
+
+ //Cache the margins of the original element
+ this._cacheMargins();
+
+ //Get the next scrolling parent
+ this.scrollParent = this.helper.scrollParent();
+
+ //The element's absolute position on the page minus margins
+ this.offset = this.currentItem.offset();
+ this.offset = {
+ top: this.offset.top - this.margins.top,
+ left: this.offset.left - this.margins.left
+ };
+
+ $.extend(this.offset, {
+ click: { //Where the click happened, relative to the element
+ left: event.pageX - this.offset.left,
+ top: event.pageY - this.offset.top
+ },
+ parent: this._getParentOffset(),
+ relative: this._getRelativeOffset() //This is a relative to absolute position minus the actual position calculation - only used for relative positioned helper
+ });
+
+ // Only after we got the offset, we can change the helper's position to absolute
+ // TODO: Still need to figure out a way to make relative sorting possible
+ this.helper.css("position", "absolute");
+ this.cssPosition = this.helper.css("position");
+
+ //Generate the original position
+ this.originalPosition = this._generatePosition(event);
+ this.originalPageX = event.pageX;
+ this.originalPageY = event.pageY;
+
+ //Adjust the mouse offset relative to the helper if "cursorAt" is supplied
+ (o.cursorAt && this._adjustOffsetFromHelper(o.cursorAt));
+
+ //Cache the former DOM position
+ this.domPosition = { prev: this.currentItem.prev()[0], parent: this.currentItem.parent()[0] };
+
+ //If the helper is not the original, hide the original so it's not playing any role during the drag, won't cause anything bad this way
+ if(this.helper[0] !== this.currentItem[0]) {
+ this.currentItem.hide();
+ }
+
+ //Create the placeholder
+ this._createPlaceholder();
+
+ //Set a containment if given in the options
+ if(o.containment) {
+ this._setContainment();
+ }
+
+ if( o.cursor && o.cursor !== "auto" ) { // cursor option
+ body = this.document.find( "body" );
+
+ // support: IE
+ this.storedCursor = body.css( "cursor" );
+ body.css( "cursor", o.cursor );
+
+ this.storedStylesheet = $( "<style>*{ cursor: "+o.cursor+" !important; }</style>" ).appendTo( body );
+ }
+
+ if(o.opacity) { // opacity option
+ if (this.helper.css("opacity")) {
+ this._storedOpacity = this.helper.css("opacity");
+ }
+ this.helper.css("opacity", o.opacity);
+ }
+
+ if(o.zIndex) { // zIndex option
+ if (this.helper.css("zIndex")) {
+ this._storedZIndex = this.helper.css("zIndex");
+ }
+ this.helper.css("zIndex", o.zIndex);
+ }
+
+ //Prepare scrolling
+ if(this.scrollParent[0] !== document && this.scrollParent[0].tagName !== "HTML") {
+ this.overflowOffset = this.scrollParent.offset();
+ }
+
+ //Call callbacks
+ this._trigger("start", event, this._uiHash());
+
+ //Recache the helper size
+ if(!this._preserveHelperProportions) {
+ this._cacheHelperProportions();
+ }
+
+
+ //Post "activate" events to possible containers
+ if( !noActivation ) {
+ for ( i = this.containers.length - 1; i >= 0; i-- ) {
+ this.containers[ i ]._trigger( "activate", event, this._uiHash( this ) );
+ }
+ }
+
+ //Prepare possible droppables
+ if($.ui.ddmanager) {
+ $.ui.ddmanager.current = this;
+ }
+
+ if ($.ui.ddmanager && !o.dropBehaviour) {
+ $.ui.ddmanager.prepareOffsets(this, event);
+ }
+
+ this.dragging = true;
+
+ this.helper.addClass("ui-sortable-helper");
+ this._mouseDrag(event); //Execute the drag once - this causes the helper not to be visible before getting its correct position
+ return true;
+
+ },
+
+ _mouseDrag: function(event) {
+ var i, item, itemElement, intersection,
+ o = this.options,
+ scrolled = false;
+
+ //Compute the helpers position
+ this.position = this._generatePosition(event);
+ this.positionAbs = this._convertPositionTo("absolute");
+
+ if (!this.lastPositionAbs) {
+ this.lastPositionAbs = this.positionAbs;
+ }
+
+ //Do scrolling
+ if(this.options.scroll) {
+ if(this.scrollParent[0] !== document && this.scrollParent[0].tagName !== "HTML") {
+
+ if((this.overflowOffset.top + this.scrollParent[0].offsetHeight) - event.pageY < o.scrollSensitivity) {
+ this.scrollParent[0].scrollTop = scrolled = this.scrollParent[0].scrollTop + o.scrollSpeed;
+ } else if(event.pageY - this.overflowOffset.top < o.scrollSensitivity) {
+ this.scrollParent[0].scrollTop = scrolled = this.scrollParent[0].scrollTop - o.scrollSpeed;
+ }
+
+ if((this.overflowOffset.left + this.scrollParent[0].offsetWidth) - event.pageX < o.scrollSensitivity) {
+ this.scrollParent[0].scrollLeft = scrolled = this.scrollParent[0].scrollLeft + o.scrollSpeed;
+ } else if(event.pageX - this.overflowOffset.left < o.scrollSensitivity) {
+ this.scrollParent[0].scrollLeft = scrolled = this.scrollParent[0].scrollLeft - o.scrollSpeed;
+ }
+
+ } else {
+
+ if(event.pageY - $(document).scrollTop() < o.scrollSensitivity) {
+ scrolled = $(document).scrollTop($(document).scrollTop() - o.scrollSpeed);
+ } else if($(window).height() - (event.pageY - $(document).scrollTop()) < o.scrollSensitivity) {
+ scrolled = $(document).scrollTop($(document).scrollTop() + o.scrollSpeed);
+ }
+
+ if(event.pageX - $(document).scrollLeft() < o.scrollSensitivity) {
+ scrolled = $(document).scrollLeft($(document).scrollLeft() - o.scrollSpeed);
+ } else if($(window).width() - (event.pageX - $(document).scrollLeft()) < o.scrollSensitivity) {
+ scrolled = $(document).scrollLeft($(document).scrollLeft() + o.scrollSpeed);
+ }
+
+ }
+
+ if(scrolled !== false && $.ui.ddmanager && !o.dropBehaviour) {
+ $.ui.ddmanager.prepareOffsets(this, event);
+ }
+ }
+
+ //Regenerate the absolute position used for position checks
+ this.positionAbs = this._convertPositionTo("absolute");
+
+ //Set the helper position
+ if(!this.options.axis || this.options.axis !== "y") {
+ this.helper[0].style.left = this.position.left+"px";
+ }
+ if(!this.options.axis || this.options.axis !== "x") {
+ this.helper[0].style.top = this.position.top+"px";
+ }
+
+ //Rearrange
+ for (i = this.items.length - 1; i >= 0; i--) {
+
+ //Cache variables and intersection, continue if no intersection
+ item = this.items[i];
+ itemElement = item.item[0];
+ intersection = this._intersectsWithPointer(item);
+ if (!intersection) {
+ continue;
+ }
+
+ // Only put the placeholder inside the current Container, skip all
+ // items form other containers. This works because when moving
+ // an item from one container to another the
+ // currentContainer is switched before the placeholder is moved.
+ //
+ // Without this moving items in "sub-sortables" can cause the placeholder to jitter
+ // beetween the outer and inner container.
+ if (item.instance !== this.currentContainer) {
+ continue;
+ }
+
+ // cannot intersect with itself
+ // no useless actions that have been done before
+ // no action if the item moved is the parent of the item checked
+ if (itemElement !== this.currentItem[0] &&
+ this.placeholder[intersection === 1 ? "next" : "prev"]()[0] !== itemElement &&
+ !$.contains(this.placeholder[0], itemElement) &&
+ (this.options.type === "semi-dynamic" ? !$.contains(this.element[0], itemElement) : true)
+ ) {
+
+ this.direction = intersection === 1 ? "down" : "up";
+
+ if (this.options.tolerance === "pointer" || this._intersectsWithSides(item)) {
+ this._rearrange(event, item);
+ } else {
+ break;
+ }
+
+ this._trigger("change", event, this._uiHash());
+ break;
+ }
+ }
+
+ //Post events to containers
+ this._contactContainers(event);
+
+ //Interconnect with droppables
+ if($.ui.ddmanager) {
+ $.ui.ddmanager.drag(this, event);
+ }
+
+ //Call callbacks
+ this._trigger("sort", event, this._uiHash());
+
+ this.lastPositionAbs = this.positionAbs;
+ return false;
+
+ },
+
+ _mouseStop: function(event, noPropagation) {
+
+ if(!event) {
+ return;
+ }
+
+ //If we are using droppables, inform the manager about the drop
+ if ($.ui.ddmanager && !this.options.dropBehaviour) {
+ $.ui.ddmanager.drop(this, event);
+ }
+
+ if(this.options.revert) {
+ var that = this,
+ cur = this.placeholder.offset(),
+ axis = this.options.axis,
+ animation = {};
+
+ if ( !axis || axis === "x" ) {
+ animation.left = cur.left - this.offset.parent.left - this.margins.left + (this.offsetParent[0] === document.body ? 0 : this.offsetParent[0].scrollLeft);
+ }
+ if ( !axis || axis === "y" ) {
+ animation.top = cur.top - this.offset.parent.top - this.margins.top + (this.offsetParent[0] === document.body ? 0 : this.offsetParent[0].scrollTop);
+ }
+ this.reverting = true;
+ $(this.helper).animate( animation, parseInt(this.options.revert, 10) || 500, function() {
+ that._clear(event);
+ });
+ } else {
+ this._clear(event, noPropagation);
+ }
+
+ return false;
+
+ },
+
+ cancel: function() {
+
+ if(this.dragging) {
+
+ this._mouseUp({ target: null });
+
+ if(this.options.helper === "original") {
+ this.currentItem.css(this._storedCSS).removeClass("ui-sortable-helper");
+ } else {
+ this.currentItem.show();
+ }
+
+ //Post deactivating events to containers
+ for (var i = this.containers.length - 1; i >= 0; i--){
+ this.containers[i]._trigger("deactivate", null, this._uiHash(this));
+ if(this.containers[i].containerCache.over) {
+ this.containers[i]._trigger("out", null, this._uiHash(this));
+ this.containers[i].containerCache.over = 0;
+ }
+ }
+
+ }
+
+ if (this.placeholder) {
+ //$(this.placeholder[0]).remove(); would have been the jQuery way - unfortunately, it unbinds ALL events from the original node!
+ if(this.placeholder[0].parentNode) {
+ this.placeholder[0].parentNode.removeChild(this.placeholder[0]);
+ }
+ if(this.options.helper !== "original" && this.helper && this.helper[0].parentNode) {
+ this.helper.remove();
+ }
+
+ $.extend(this, {
+ helper: null,
+ dragging: false,
+ reverting: false,
+ _noFinalSort: null
+ });
+
+ if(this.domPosition.prev) {
+ $(this.domPosition.prev).after(this.currentItem);
+ } else {
+ $(this.domPosition.parent).prepend(this.currentItem);
+ }
+ }
+
+ return this;
+
+ },
+
+ serialize: function(o) {
+
+ var items = this._getItemsAsjQuery(o && o.connected),
+ str = [];
+ o = o || {};
+
+ $(items).each(function() {
+ var res = ($(o.item || this).attr(o.attribute || "id") || "").match(o.expression || (/(.+)[\-=_](.+)/));
+ if (res) {
+ str.push((o.key || res[1]+"[]")+"="+(o.key && o.expression ? res[1] : res[2]));
+ }
+ });
+
+ if(!str.length && o.key) {
+ str.push(o.key + "=");
+ }
+
+ return str.join("&");
+
+ },
+
+ toArray: function(o) {
+
+ var items = this._getItemsAsjQuery(o && o.connected),
+ ret = [];
+
+ o = o || {};
+
+ items.each(function() { ret.push($(o.item || this).attr(o.attribute || "id") || ""); });
+ return ret;
+
+ },
+
+ /* Be careful with the following core functions */
+ _intersectsWith: function(item) {
+
+ var x1 = this.positionAbs.left,
+ x2 = x1 + this.helperProportions.width,
+ y1 = this.positionAbs.top,
+ y2 = y1 + this.helperProportions.height,
+ l = item.left,
+ r = l + item.width,
+ t = item.top,
+ b = t + item.height,
+ dyClick = this.offset.click.top,
+ dxClick = this.offset.click.left,
+ isOverElementHeight = ( this.options.axis === "x" ) || ( ( y1 + dyClick ) > t && ( y1 + dyClick ) < b ),
+ isOverElementWidth = ( this.options.axis === "y" ) || ( ( x1 + dxClick ) > l && ( x1 + dxClick ) < r ),
+ isOverElement = isOverElementHeight && isOverElementWidth;
+
+ if ( this.options.tolerance === "pointer" ||
+ this.options.forcePointerForContainers ||
+ (this.options.tolerance !== "pointer" && this.helperProportions[this.floating ? "width" : "height"] > item[this.floating ? "width" : "height"])
+ ) {
+ return isOverElement;
+ } else {
+
+ return (l < x1 + (this.helperProportions.width / 2) && // Right Half
+ x2 - (this.helperProportions.width / 2) < r && // Left Half
+ t < y1 + (this.helperProportions.height / 2) && // Bottom Half
+ y2 - (this.helperProportions.height / 2) < b ); // Top Half
+
+ }
+ },
+
+ _intersectsWithPointer: function(item) {
+
+ var isOverElementHeight = (this.options.axis === "x") || isOverAxis(this.positionAbs.top + this.offset.click.top, item.top, item.height),
+ isOverElementWidth = (this.options.axis === "y") || isOverAxis(this.positionAbs.left + this.offset.click.left, item.left, item.width),
+ isOverElement = isOverElementHeight && isOverElementWidth,
+ verticalDirection = this._getDragVerticalDirection(),
+ horizontalDirection = this._getDragHorizontalDirection();
+
+ if (!isOverElement) {
+ return false;
+ }
+
+ return this.floating ?
+ ( ((horizontalDirection && horizontalDirection === "right") || verticalDirection === "down") ? 2 : 1 )
+ : ( verticalDirection && (verticalDirection === "down" ? 2 : 1) );
+
+ },
+
+ _intersectsWithSides: function(item) {
+
+ var isOverBottomHalf = isOverAxis(this.positionAbs.top + this.offset.click.top, item.top + (item.height/2), item.height),
+ isOverRightHalf = isOverAxis(this.positionAbs.left + this.offset.click.left, item.left + (item.width/2), item.width),
+ verticalDirection = this._getDragVerticalDirection(),
+ horizontalDirection = this._getDragHorizontalDirection();
+
+ if (this.floating && horizontalDirection) {
+ return ((horizontalDirection === "right" && isOverRightHalf) || (horizontalDirection === "left" && !isOverRightHalf));
+ } else {
+ return verticalDirection && ((verticalDirection === "down" && isOverBottomHalf) || (verticalDirection === "up" && !isOverBottomHalf));
+ }
+
+ },
+
+ _getDragVerticalDirection: function() {
+ var delta = this.positionAbs.top - this.lastPositionAbs.top;
+ return delta !== 0 && (delta > 0 ? "down" : "up");
+ },
+
+ _getDragHorizontalDirection: function() {
+ var delta = this.positionAbs.left - this.lastPositionAbs.left;
+ return delta !== 0 && (delta > 0 ? "right" : "left");
+ },
+
+ refresh: function(event) {
+ this._refreshItems(event);
+ this.refreshPositions();
+ return this;
+ },
+
+ _connectWith: function() {
+ var options = this.options;
+ return options.connectWith.constructor === String ? [options.connectWith] : options.connectWith;
+ },
+
+ _getItemsAsjQuery: function(connected) {
+
+ var i, j, cur, inst,
+ items = [],
+ queries = [],
+ connectWith = this._connectWith();
+
+ if(connectWith && connected) {
+ for (i = connectWith.length - 1; i >= 0; i--){
+ cur = $(connectWith[i]);
+ for ( j = cur.length - 1; j >= 0; j--){
+ inst = $.data(cur[j], this.widgetFullName);
+ if(inst && inst !== this && !inst.options.disabled) {
+ queries.push([$.isFunction(inst.options.items) ? inst.options.items.call(inst.element) : $(inst.options.items, inst.element).not(".ui-sortable-helper").not(".ui-sortable-placeholder"), inst]);
+ }
+ }
+ }
+ }
+
+ queries.push([$.isFunction(this.options.items) ? this.options.items.call(this.element, null, { options: this.options, item: this.currentItem }) : $(this.options.items, this.element).not(".ui-sortable-helper").not(".ui-sortable-placeholder"), this]);
+
+ for (i = queries.length - 1; i >= 0; i--){
+ queries[i][0].each(function() {
+ items.push(this);
+ });
+ }
+
+ return $(items);
+
+ },
+
+ _removeCurrentsFromItems: function() {
+
+ var list = this.currentItem.find(":data(" + this.widgetName + "-item)");
+
+ this.items = $.grep(this.items, function (item) {
+ for (var j=0; j < list.length; j++) {
+ if(list[j] === item.item[0]) {
+ return false;
+ }
+ }
+ return true;
+ });
+
+ },
+
+ _refreshItems: function(event) {
+
+ this.items = [];
+ this.containers = [this];
+
+ var i, j, cur, inst, targetData, _queries, item, queriesLength,
+ items = this.items,
+ queries = [[$.isFunction(this.options.items) ? this.options.items.call(this.element[0], event, { item: this.currentItem }) : $(this.options.items, this.element), this]],
+ connectWith = this._connectWith();
+
+ if(connectWith && this.ready) { //Shouldn't be run the first time through due to massive slow-down
+ for (i = connectWith.length - 1; i >= 0; i--){
+ cur = $(connectWith[i]);
+ for (j = cur.length - 1; j >= 0; j--){
+ inst = $.data(cur[j], this.widgetFullName);
+ if(inst && inst !== this && !inst.options.disabled) {
+ queries.push([$.isFunction(inst.options.items) ? inst.options.items.call(inst.element[0], event, { item: this.currentItem }) : $(inst.options.items, inst.element), inst]);
+ this.containers.push(inst);
+ }
+ }
+ }
+ }
+
+ for (i = queries.length - 1; i >= 0; i--) {
+ targetData = queries[i][1];
+ _queries = queries[i][0];
+
+ for (j=0, queriesLength = _queries.length; j < queriesLength; j++) {
+ item = $(_queries[j]);
+
+ item.data(this.widgetName + "-item", targetData); // Data for target checking (mouse manager)
+
+ items.push({
+ item: item,
+ instance: targetData,
+ width: 0, height: 0,
+ left: 0, top: 0
+ });
+ }
+ }
+
+ },
+
+ refreshPositions: function(fast) {
+
+ //This has to be redone because due to the item being moved out/into the offsetParent, the offsetParent's position will change
+ if(this.offsetParent && this.helper) {
+ this.offset.parent = this._getParentOffset();
+ }
+
+ var i, item, t, p;
+
+ for (i = this.items.length - 1; i >= 0; i--){
+ item = this.items[i];
+
+ //We ignore calculating positions of all connected containers when we're not over them
+ if(item.instance !== this.currentContainer && this.currentContainer && item.item[0] !== this.currentItem[0]) {
+ continue;
+ }
+
+ t = this.options.toleranceElement ? $(this.options.toleranceElement, item.item) : item.item;
+
+ if (!fast) {
+ item.width = t.outerWidth();
+ item.height = t.outerHeight();
+ }
+
+ p = t.offset();
+ item.left = p.left;
+ item.top = p.top;
+ }
+
+ if(this.options.custom && this.options.custom.refreshContainers) {
+ this.options.custom.refreshContainers.call(this);
+ } else {
+ for (i = this.containers.length - 1; i >= 0; i--){
+ p = this.containers[i].element.offset();
+ this.containers[i].containerCache.left = p.left;
+ this.containers[i].containerCache.top = p.top;
+ this.containers[i].containerCache.width = this.containers[i].element.outerWidth();
+ this.containers[i].containerCache.height = this.containers[i].element.outerHeight();
+ }
+ }
+
+ return this;
+ },
+
+ _createPlaceholder: function(that) {
+ that = that || this;
+ var className,
+ o = that.options;
+
+ if(!o.placeholder || o.placeholder.constructor === String) {
+ className = o.placeholder;
+ o.placeholder = {
+ element: function() {
+
+ var nodeName = that.currentItem[0].nodeName.toLowerCase(),
+ element = $( "<" + nodeName + ">", that.document[0] )
+ .addClass(className || that.currentItem[0].className+" ui-sortable-placeholder")
+ .removeClass("ui-sortable-helper");
+
+ if ( nodeName === "tr" ) {
+ that.currentItem.children().each(function() {
+ $( "<td>&#160;</td>", that.document[0] )
+ .attr( "colspan", $( this ).attr( "colspan" ) || 1 )
+ .appendTo( element );
+ });
+ } else if ( nodeName === "img" ) {
+ element.attr( "src", that.currentItem.attr( "src" ) );
+ }
+
+ if ( !className ) {
+ element.css( "visibility", "hidden" );
+ }
+
+ return element;
+ },
+ update: function(container, p) {
+
+ // 1. If a className is set as 'placeholder option, we don't force sizes - the class is responsible for that
+ // 2. The option 'forcePlaceholderSize can be enabled to force it even if a class name is specified
+ if(className && !o.forcePlaceholderSize) {
+ return;
+ }
+
+ //If the element doesn't have a actual height by itself (without styles coming from a stylesheet), it receives the inline height from the dragged item
+ if(!p.height()) { p.height(that.currentItem.innerHeight() - parseInt(that.currentItem.css("paddingTop")||0, 10) - parseInt(that.currentItem.css("paddingBottom")||0, 10)); }
+ if(!p.width()) { p.width(that.currentItem.innerWidth() - parseInt(that.currentItem.css("paddingLeft")||0, 10) - parseInt(that.currentItem.css("paddingRight")||0, 10)); }
+ }
+ };
+ }
+
+ //Create the placeholder
+ that.placeholder = $(o.placeholder.element.call(that.element, that.currentItem));
+
+ //Append it after the actual current item
+ that.currentItem.after(that.placeholder);
+
+ //Update the size of the placeholder (TODO: Logic to fuzzy, see line 316/317)
+ o.placeholder.update(that, that.placeholder);
+
+ },
+
+ _contactContainers: function(event) {
+ var i, j, dist, itemWithLeastDistance, posProperty, sizeProperty, base, cur, nearBottom, floating,
+ innermostContainer = null,
+ innermostIndex = null;
+
+ // get innermost container that intersects with item
+ for (i = this.containers.length - 1; i >= 0; i--) {
+
+ // never consider a container that's located within the item itself
+ if($.contains(this.currentItem[0], this.containers[i].element[0])) {
+ continue;
+ }
+
+ if(this._intersectsWith(this.containers[i].containerCache)) {
+
+ // if we've already found a container and it's more "inner" than this, then continue
+ if(innermostContainer && $.contains(this.containers[i].element[0], innermostContainer.element[0])) {
+ continue;
+ }
+
+ innermostContainer = this.containers[i];
+ innermostIndex = i;
+
+ } else {
+ // container doesn't intersect. trigger "out" event if necessary
+ if(this.containers[i].containerCache.over) {
+ this.containers[i]._trigger("out", event, this._uiHash(this));
+ this.containers[i].containerCache.over = 0;
+ }
+ }
+
+ }
+
+ // if no intersecting containers found, return
+ if(!innermostContainer) {
+ return;
+ }
+
+ // move the item into the container if it's not there already
+ if(this.containers.length === 1) {
+ if (!this.containers[innermostIndex].containerCache.over) {
+ this.containers[innermostIndex]._trigger("over", event, this._uiHash(this));
+ this.containers[innermostIndex].containerCache.over = 1;
+ }
+ } else {
+
+ //When entering a new container, we will find the item with the least distance and append our item near it
+ dist = 10000;
+ itemWithLeastDistance = null;
+ floating = innermostContainer.floating || isFloating(this.currentItem);
+ posProperty = floating ? "left" : "top";
+ sizeProperty = floating ? "width" : "height";
+ base = this.positionAbs[posProperty] + this.offset.click[posProperty];
+ for (j = this.items.length - 1; j >= 0; j--) {
+ if(!$.contains(this.containers[innermostIndex].element[0], this.items[j].item[0])) {
+ continue;
+ }
+ if(this.items[j].item[0] === this.currentItem[0]) {
+ continue;
+ }
+ if (floating && !isOverAxis(this.positionAbs.top + this.offset.click.top, this.items[j].top, this.items[j].height)) {
+ continue;
+ }
+ cur = this.items[j].item.offset()[posProperty];
+ nearBottom = false;
+ if(Math.abs(cur - base) > Math.abs(cur + this.items[j][sizeProperty] - base)){
+ nearBottom = true;
+ cur += this.items[j][sizeProperty];
+ }
+
+ if(Math.abs(cur - base) < dist) {
+ dist = Math.abs(cur - base); itemWithLeastDistance = this.items[j];
+ this.direction = nearBottom ? "up": "down";
+ }
+ }
+
+ //Check if dropOnEmpty is enabled
+ if(!itemWithLeastDistance && !this.options.dropOnEmpty) {
+ return;
+ }
+
+ if(this.currentContainer === this.containers[innermostIndex]) {
+ return;
+ }
+
+ itemWithLeastDistance ? this._rearrange(event, itemWithLeastDistance, null, true) : this._rearrange(event, null, this.containers[innermostIndex].element, true);
+ this._trigger("change", event, this._uiHash());
+ this.containers[innermostIndex]._trigger("change", event, this._uiHash(this));
+ this.currentContainer = this.containers[innermostIndex];
+
+ //Update the placeholder
+ this.options.placeholder.update(this.currentContainer, this.placeholder);
+
+ this.containers[innermostIndex]._trigger("over", event, this._uiHash(this));
+ this.containers[innermostIndex].containerCache.over = 1;
+ }
+
+
+ },
+
+ _createHelper: function(event) {
+
+ var o = this.options,
+ helper = $.isFunction(o.helper) ? $(o.helper.apply(this.element[0], [event, this.currentItem])) : (o.helper === "clone" ? this.currentItem.clone() : this.currentItem);
+
+ //Add the helper to the DOM if that didn't happen already
+ if(!helper.parents("body").length) {
+ $(o.appendTo !== "parent" ? o.appendTo : this.currentItem[0].parentNode)[0].appendChild(helper[0]);
+ }
+
+ if(helper[0] === this.currentItem[0]) {
+ this._storedCSS = { width: this.currentItem[0].style.width, height: this.currentItem[0].style.height, position: this.currentItem.css("position"), top: this.currentItem.css("top"), left: this.currentItem.css("left") };
+ }
+
+ if(!helper[0].style.width || o.forceHelperSize) {
+ helper.width(this.currentItem.width());
+ }
+ if(!helper[0].style.height || o.forceHelperSize) {
+ helper.height(this.currentItem.height());
+ }
+
+ return helper;
+
+ },
+
+ _adjustOffsetFromHelper: function(obj) {
+ if (typeof obj === "string") {
+ obj = obj.split(" ");
+ }
+ if ($.isArray(obj)) {
+ obj = {left: +obj[0], top: +obj[1] || 0};
+ }
+ if ("left" in obj) {
+ this.offset.click.left = obj.left + this.margins.left;
+ }
+ if ("right" in obj) {
+ this.offset.click.left = this.helperProportions.width - obj.right + this.margins.left;
+ }
+ if ("top" in obj) {
+ this.offset.click.top = obj.top + this.margins.top;
+ }
+ if ("bottom" in obj) {
+ this.offset.click.top = this.helperProportions.height - obj.bottom + this.margins.top;
+ }
+ },
+
+ _getParentOffset: function() {
+
+
+ //Get the offsetParent and cache its position
+ this.offsetParent = this.helper.offsetParent();
+ var po = this.offsetParent.offset();
+
+ // This is a special case where we need to modify a offset calculated on start, since the following happened:
+ // 1. The position of the helper is absolute, so it's position is calculated based on the next positioned parent
+ // 2. The actual offset parent is a child of the scroll parent, and the scroll parent isn't the document, which means that
+ // the scroll is included in the initial calculation of the offset of the parent, and never recalculated upon drag
+ if(this.cssPosition === "absolute" && this.scrollParent[0] !== document && $.contains(this.scrollParent[0], this.offsetParent[0])) {
+ po.left += this.scrollParent.scrollLeft();
+ po.top += this.scrollParent.scrollTop();
+ }
+
+ // This needs to be actually done for all browsers, since pageX/pageY includes this information
+ // with an ugly IE fix
+ if( this.offsetParent[0] === document.body || (this.offsetParent[0].tagName && this.offsetParent[0].tagName.toLowerCase() === "html" && $.ui.ie)) {
+ po = { top: 0, left: 0 };
+ }
+
+ return {
+ top: po.top + (parseInt(this.offsetParent.css("borderTopWidth"),10) || 0),
+ left: po.left + (parseInt(this.offsetParent.css("borderLeftWidth"),10) || 0)
+ };
+
+ },
+
+ _getRelativeOffset: function() {
+
+ if(this.cssPosition === "relative") {
+ var p = this.currentItem.position();
+ return {
+ top: p.top - (parseInt(this.helper.css("top"),10) || 0) + this.scrollParent.scrollTop(),
+ left: p.left - (parseInt(this.helper.css("left"),10) || 0) + this.scrollParent.scrollLeft()
+ };
+ } else {
+ return { top: 0, left: 0 };
+ }
+
+ },
+
+ _cacheMargins: function() {
+ this.margins = {
+ left: (parseInt(this.currentItem.css("marginLeft"),10) || 0),
+ top: (parseInt(this.currentItem.css("marginTop"),10) || 0)
+ };
+ },
+
+ _cacheHelperProportions: function() {
+ this.helperProportions = {
+ width: this.helper.outerWidth(),
+ height: this.helper.outerHeight()
+ };
+ },
+
+ _setContainment: function() {
+
+ var ce, co, over,
+ o = this.options;
+ if(o.containment === "parent") {
+ o.containment = this.helper[0].parentNode;
+ }
+ if(o.containment === "document" || o.containment === "window") {
+ this.containment = [
+ 0 - this.offset.relative.left - this.offset.parent.left,
+ 0 - this.offset.relative.top - this.offset.parent.top,
+ $(o.containment === "document" ? document : window).width() - this.helperProportions.width - this.margins.left,
+ ($(o.containment === "document" ? document : window).height() || document.body.parentNode.scrollHeight) - this.helperProportions.height - this.margins.top
+ ];
+ }
+
+ if(!(/^(document|window|parent)$/).test(o.containment)) {
+ ce = $(o.containment)[0];
+ co = $(o.containment).offset();
+ over = ($(ce).css("overflow") !== "hidden");
+
+ this.containment = [
+ co.left + (parseInt($(ce).css("borderLeftWidth"),10) || 0) + (parseInt($(ce).css("paddingLeft"),10) || 0) - this.margins.left,
+ co.top + (parseInt($(ce).css("borderTopWidth"),10) || 0) + (parseInt($(ce).css("paddingTop"),10) || 0) - this.margins.top,
+ co.left+(over ? Math.max(ce.scrollWidth,ce.offsetWidth) : ce.offsetWidth) - (parseInt($(ce).css("borderLeftWidth"),10) || 0) - (parseInt($(ce).css("paddingRight"),10) || 0) - this.helperProportions.width - this.margins.left,
+ co.top+(over ? Math.max(ce.scrollHeight,ce.offsetHeight) : ce.offsetHeight) - (parseInt($(ce).css("borderTopWidth"),10) || 0) - (parseInt($(ce).css("paddingBottom"),10) || 0) - this.helperProportions.height - this.margins.top
+ ];
+ }
+
+ },
+
+ _convertPositionTo: function(d, pos) {
+
+ if(!pos) {
+ pos = this.position;
+ }
+ var mod = d === "absolute" ? 1 : -1,
+ scroll = this.cssPosition === "absolute" && !(this.scrollParent[0] !== document && $.contains(this.scrollParent[0], this.offsetParent[0])) ? this.offsetParent : this.scrollParent,
+ scrollIsRootNode = (/(html|body)/i).test(scroll[0].tagName);
+
+ return {
+ top: (
+ pos.top + // The absolute mouse position
+ this.offset.relative.top * mod + // Only for relative positioned nodes: Relative offset from element to offset parent
+ this.offset.parent.top * mod - // The offsetParent's offset without borders (offset + border)
+ ( ( this.cssPosition === "fixed" ? -this.scrollParent.scrollTop() : ( scrollIsRootNode ? 0 : scroll.scrollTop() ) ) * mod)
+ ),
+ left: (
+ pos.left + // The absolute mouse position
+ this.offset.relative.left * mod + // Only for relative positioned nodes: Relative offset from element to offset parent
+ this.offset.parent.left * mod - // The offsetParent's offset without borders (offset + border)
+ ( ( this.cssPosition === "fixed" ? -this.scrollParent.scrollLeft() : scrollIsRootNode ? 0 : scroll.scrollLeft() ) * mod)
+ )
+ };
+
+ },
+
+ _generatePosition: function(event) {
+
+ var top, left,
+ o = this.options,
+ pageX = event.pageX,
+ pageY = event.pageY,
+ scroll = this.cssPosition === "absolute" && !(this.scrollParent[0] !== document && $.contains(this.scrollParent[0], this.offsetParent[0])) ? this.offsetParent : this.scrollParent, scrollIsRootNode = (/(html|body)/i).test(scroll[0].tagName);
+
+ // This is another very weird special case that only happens for relative elements:
+ // 1. If the css position is relative
+ // 2. and the scroll parent is the document or similar to the offset parent
+ // we have to refresh the relative offset during the scroll so there are no jumps
+ if(this.cssPosition === "relative" && !(this.scrollParent[0] !== document && this.scrollParent[0] !== this.offsetParent[0])) {
+ this.offset.relative = this._getRelativeOffset();
+ }
+
+ /*
+ * - Position constraining -
+ * Constrain the position to a mix of grid, containment.
+ */
+
+ if(this.originalPosition) { //If we are not dragging yet, we won't check for options
+
+ if(this.containment) {
+ if(event.pageX - this.offset.click.left < this.containment[0]) {
+ pageX = this.containment[0] + this.offset.click.left;
+ }
+ if(event.pageY - this.offset.click.top < this.containment[1]) {
+ pageY = this.containment[1] + this.offset.click.top;
+ }
+ if(event.pageX - this.offset.click.left > this.containment[2]) {
+ pageX = this.containment[2] + this.offset.click.left;
+ }
+ if(event.pageY - this.offset.click.top > this.containment[3]) {
+ pageY = this.containment[3] + this.offset.click.top;
+ }
+ }
+
+ if(o.grid) {
+ top = this.originalPageY + Math.round((pageY - this.originalPageY) / o.grid[1]) * o.grid[1];
+ pageY = this.containment ? ( (top - this.offset.click.top >= this.containment[1] && top - this.offset.click.top <= this.containment[3]) ? top : ((top - this.offset.click.top >= this.containment[1]) ? top - o.grid[1] : top + o.grid[1])) : top;
+
+ left = this.originalPageX + Math.round((pageX - this.originalPageX) / o.grid[0]) * o.grid[0];
+ pageX = this.containment ? ( (left - this.offset.click.left >= this.containment[0] && left - this.offset.click.left <= this.containment[2]) ? left : ((left - this.offset.click.left >= this.containment[0]) ? left - o.grid[0] : left + o.grid[0])) : left;
+ }
+
+ }
+
+ return {
+ top: (
+ pageY - // The absolute mouse position
+ this.offset.click.top - // Click offset (relative to the element)
+ this.offset.relative.top - // Only for relative positioned nodes: Relative offset from element to offset parent
+ this.offset.parent.top + // The offsetParent's offset without borders (offset + border)
+ ( ( this.cssPosition === "fixed" ? -this.scrollParent.scrollTop() : ( scrollIsRootNode ? 0 : scroll.scrollTop() ) ))
+ ),
+ left: (
+ pageX - // The absolute mouse position
+ this.offset.click.left - // Click offset (relative to the element)
+ this.offset.relative.left - // Only for relative positioned nodes: Relative offset from element to offset parent
+ this.offset.parent.left + // The offsetParent's offset without borders (offset + border)
+ ( ( this.cssPosition === "fixed" ? -this.scrollParent.scrollLeft() : scrollIsRootNode ? 0 : scroll.scrollLeft() ))
+ )
+ };
+
+ },
+
+ _rearrange: function(event, i, a, hardRefresh) {
+
+ a ? a[0].appendChild(this.placeholder[0]) : i.item[0].parentNode.insertBefore(this.placeholder[0], (this.direction === "down" ? i.item[0] : i.item[0].nextSibling));
+
+ //Various things done here to improve the performance:
+ // 1. we create a setTimeout, that calls refreshPositions
+ // 2. on the instance, we have a counter variable, that get's higher after every append
+ // 3. on the local scope, we copy the counter variable, and check in the timeout, if it's still the same
+ // 4. this lets only the last addition to the timeout stack through
+ this.counter = this.counter ? ++this.counter : 1;
+ var counter = this.counter;
+
+ this._delay(function() {
+ if(counter === this.counter) {
+ this.refreshPositions(!hardRefresh); //Precompute after each DOM insertion, NOT on mousemove
+ }
+ });
+
+ },
+
+ _clear: function(event, noPropagation) {
+
+ this.reverting = false;
+ // We delay all events that have to be triggered to after the point where the placeholder has been removed and
+ // everything else normalized again
+ var i,
+ delayedTriggers = [];
+
+ // We first have to update the dom position of the actual currentItem
+ // Note: don't do it if the current item is already removed (by a user), or it gets reappended (see #4088)
+ if(!this._noFinalSort && this.currentItem.parent().length) {
+ this.placeholder.before(this.currentItem);
+ }
+ this._noFinalSort = null;
+
+ if(this.helper[0] === this.currentItem[0]) {
+ for(i in this._storedCSS) {
+ if(this._storedCSS[i] === "auto" || this._storedCSS[i] === "static") {
+ this._storedCSS[i] = "";
+ }
+ }
+ this.currentItem.css(this._storedCSS).removeClass("ui-sortable-helper");
+ } else {
+ this.currentItem.show();
+ }
+
+ if(this.fromOutside && !noPropagation) {
+ delayedTriggers.push(function(event) { this._trigger("receive", event, this._uiHash(this.fromOutside)); });
+ }
+ if((this.fromOutside || this.domPosition.prev !== this.currentItem.prev().not(".ui-sortable-helper")[0] || this.domPosition.parent !== this.currentItem.parent()[0]) && !noPropagation) {
+ delayedTriggers.push(function(event) { this._trigger("update", event, this._uiHash()); }); //Trigger update callback if the DOM position has changed
+ }
+
+ // Check if the items Container has Changed and trigger appropriate
+ // events.
+ if (this !== this.currentContainer) {
+ if(!noPropagation) {
+ delayedTriggers.push(function(event) { this._trigger("remove", event, this._uiHash()); });
+ delayedTriggers.push((function(c) { return function(event) { c._trigger("receive", event, this._uiHash(this)); }; }).call(this, this.currentContainer));
+ delayedTriggers.push((function(c) { return function(event) { c._trigger("update", event, this._uiHash(this)); }; }).call(this, this.currentContainer));
+ }
+ }
+
+
+ //Post events to containers
+ for (i = this.containers.length - 1; i >= 0; i--){
+ if(!noPropagation) {
+ delayedTriggers.push((function(c) { return function(event) { c._trigger("deactivate", event, this._uiHash(this)); }; }).call(this, this.containers[i]));
+ }
+ if(this.containers[i].containerCache.over) {
+ delayedTriggers.push((function(c) { return function(event) { c._trigger("out", event, this._uiHash(this)); }; }).call(this, this.containers[i]));
+ this.containers[i].containerCache.over = 0;
+ }
+ }
+
+ //Do what was originally in plugins
+ if ( this.storedCursor ) {
+ this.document.find( "body" ).css( "cursor", this.storedCursor );
+ this.storedStylesheet.remove();
+ }
+ if(this._storedOpacity) {
+ this.helper.css("opacity", this._storedOpacity);
+ }
+ if(this._storedZIndex) {
+ this.helper.css("zIndex", this._storedZIndex === "auto" ? "" : this._storedZIndex);
+ }
+
+ this.dragging = false;
+ if(this.cancelHelperRemoval) {
+ if(!noPropagation) {
+ this._trigger("beforeStop", event, this._uiHash());
+ for (i=0; i < delayedTriggers.length; i++) {
+ delayedTriggers[i].call(this, event);
+ } //Trigger all delayed events
+ this._trigger("stop", event, this._uiHash());
+ }
+
+ this.fromOutside = false;
+ return false;
+ }
+
+ if(!noPropagation) {
+ this._trigger("beforeStop", event, this._uiHash());
+ }
+
+ //$(this.placeholder[0]).remove(); would have been the jQuery way - unfortunately, it unbinds ALL events from the original node!
+ this.placeholder[0].parentNode.removeChild(this.placeholder[0]);
+
+ if(this.helper[0] !== this.currentItem[0]) {
+ this.helper.remove();
+ }
+ this.helper = null;
+
+ if(!noPropagation) {
+ for (i=0; i < delayedTriggers.length; i++) {
+ delayedTriggers[i].call(this, event);
+ } //Trigger all delayed events
+ this._trigger("stop", event, this._uiHash());
+ }
+
+ this.fromOutside = false;
+ return true;
+
+ },
+
+ _trigger: function() {
+ if ($.Widget.prototype._trigger.apply(this, arguments) === false) {
+ this.cancel();
+ }
+ },
+
+ _uiHash: function(_inst) {
+ var inst = _inst || this;
+ return {
+ helper: inst.helper,
+ placeholder: inst.placeholder || $([]),
+ position: inst.position,
+ originalPosition: inst.originalPosition,
+ offset: inst.positionAbs,
+ item: inst.currentItem,
+ sender: _inst ? _inst.element : null
+ };
+ }
+
+});
+
+})(jQuery);
+
+(function($, undefined) {
+
+var dataSpace = "ui-effects-";
+
+$.effects = {
+ effect: {}
+};
+
+/*!
+ * jQuery Color Animations v2.1.2
+ * https://github.com/jquery/jquery-color
+ *
+ * Copyright 2013 jQuery Foundation and other contributors
+ * Released under the MIT license.
+ * http://jquery.org/license
+ *
+ * Date: Wed Jan 16 08:47:09 2013 -0600
+ */
+(function( jQuery, undefined ) {
+
+ var stepHooks = "backgroundColor borderBottomColor borderLeftColor borderRightColor borderTopColor color columnRuleColor outlineColor textDecorationColor textEmphasisColor",
+
+ // plusequals test for += 100 -= 100
+ rplusequals = /^([\-+])=\s*(\d+\.?\d*)/,
+ // a set of RE's that can match strings and generate color tuples.
+ stringParsers = [{
+ re: /rgba?\(\s*(\d{1,3})\s*,\s*(\d{1,3})\s*,\s*(\d{1,3})\s*(?:,\s*(\d?(?:\.\d+)?)\s*)?\)/,
+ parse: function( execResult ) {
+ return [
+ execResult[ 1 ],
+ execResult[ 2 ],
+ execResult[ 3 ],
+ execResult[ 4 ]
+ ];
+ }
+ }, {
+ re: /rgba?\(\s*(\d+(?:\.\d+)?)\%\s*,\s*(\d+(?:\.\d+)?)\%\s*,\s*(\d+(?:\.\d+)?)\%\s*(?:,\s*(\d?(?:\.\d+)?)\s*)?\)/,
+ parse: function( execResult ) {
+ return [
+ execResult[ 1 ] * 2.55,
+ execResult[ 2 ] * 2.55,
+ execResult[ 3 ] * 2.55,
+ execResult[ 4 ]
+ ];
+ }
+ }, {
+ // this regex ignores A-F because it's compared against an already lowercased string
+ re: /#([a-f0-9]{2})([a-f0-9]{2})([a-f0-9]{2})/,
+ parse: function( execResult ) {
+ return [
+ parseInt( execResult[ 1 ], 16 ),
+ parseInt( execResult[ 2 ], 16 ),
+ parseInt( execResult[ 3 ], 16 )
+ ];
+ }
+ }, {
+ // this regex ignores A-F because it's compared against an already lowercased string
+ re: /#([a-f0-9])([a-f0-9])([a-f0-9])/,
+ parse: function( execResult ) {
+ return [
+ parseInt( execResult[ 1 ] + execResult[ 1 ], 16 ),
+ parseInt( execResult[ 2 ] + execResult[ 2 ], 16 ),
+ parseInt( execResult[ 3 ] + execResult[ 3 ], 16 )
+ ];
+ }
+ }, {
+ re: /hsla?\(\s*(\d+(?:\.\d+)?)\s*,\s*(\d+(?:\.\d+)?)\%\s*,\s*(\d+(?:\.\d+)?)\%\s*(?:,\s*(\d?(?:\.\d+)?)\s*)?\)/,
+ space: "hsla",
+ parse: function( execResult ) {
+ return [
+ execResult[ 1 ],
+ execResult[ 2 ] / 100,
+ execResult[ 3 ] / 100,
+ execResult[ 4 ]
+ ];
+ }
+ }],
+
+ // jQuery.Color( )
+ color = jQuery.Color = function( color, green, blue, alpha ) {
+ return new jQuery.Color.fn.parse( color, green, blue, alpha );
+ },
+ spaces = {
+ rgba: {
+ props: {
+ red: {
+ idx: 0,
+ type: "byte"
+ },
+ green: {
+ idx: 1,
+ type: "byte"
+ },
+ blue: {
+ idx: 2,
+ type: "byte"
+ }
+ }
+ },
+
+ hsla: {
+ props: {
+ hue: {
+ idx: 0,
+ type: "degrees"
+ },
+ saturation: {
+ idx: 1,
+ type: "percent"
+ },
+ lightness: {
+ idx: 2,
+ type: "percent"
+ }
+ }
+ }
+ },
+ propTypes = {
+ "byte": {
+ floor: true,
+ max: 255
+ },
+ "percent": {
+ max: 1
+ },
+ "degrees": {
+ mod: 360,
+ floor: true
+ }
+ },
+ support = color.support = {},
+
+ // element for support tests
+ supportElem = jQuery( "<p>" )[ 0 ],
+
+ // colors = jQuery.Color.names
+ colors,
+
+ // local aliases of functions called often
+ each = jQuery.each;
+
+// determine rgba support immediately
+supportElem.style.cssText = "background-color:rgba(1,1,1,.5)";
+support.rgba = supportElem.style.backgroundColor.indexOf( "rgba" ) > -1;
+
+// define cache name and alpha properties
+// for rgba and hsla spaces
+each( spaces, function( spaceName, space ) {
+ space.cache = "_" + spaceName;
+ space.props.alpha = {
+ idx: 3,
+ type: "percent",
+ def: 1
+ };
+});
+
+function clamp( value, prop, allowEmpty ) {
+ var type = propTypes[ prop.type ] || {};
+
+ if ( value == null ) {
+ return (allowEmpty || !prop.def) ? null : prop.def;
+ }
+
+ // ~~ is an short way of doing floor for positive numbers
+ value = type.floor ? ~~value : parseFloat( value );
+
+ // IE will pass in empty strings as value for alpha,
+ // which will hit this case
+ if ( isNaN( value ) ) {
+ return prop.def;
+ }
+
+ if ( type.mod ) {
+ // we add mod before modding to make sure that negatives values
+ // get converted properly: -10 -> 350
+ return (value + type.mod) % type.mod;
+ }
+
+ // for now all property types without mod have min and max
+ return 0 > value ? 0 : type.max < value ? type.max : value;
+}
+
+function stringParse( string ) {
+ var inst = color(),
+ rgba = inst._rgba = [];
+
+ string = string.toLowerCase();
+
+ each( stringParsers, function( i, parser ) {
+ var parsed,
+ match = parser.re.exec( string ),
+ values = match && parser.parse( match ),
+ spaceName = parser.space || "rgba";
+
+ if ( values ) {
+ parsed = inst[ spaceName ]( values );
+
+ // if this was an rgba parse the assignment might happen twice
+ // oh well....
+ inst[ spaces[ spaceName ].cache ] = parsed[ spaces[ spaceName ].cache ];
+ rgba = inst._rgba = parsed._rgba;
+
+ // exit each( stringParsers ) here because we matched
+ return false;
+ }
+ });
+
+ // Found a stringParser that handled it
+ if ( rgba.length ) {
+
+ // if this came from a parsed string, force "transparent" when alpha is 0
+ // chrome, (and maybe others) return "transparent" as rgba(0,0,0,0)
+ if ( rgba.join() === "0,0,0,0" ) {
+ jQuery.extend( rgba, colors.transparent );
+ }
+ return inst;
+ }
+
+ // named colors
+ return colors[ string ];
+}
+
+color.fn = jQuery.extend( color.prototype, {
+ parse: function( red, green, blue, alpha ) {
+ if ( red === undefined ) {
+ this._rgba = [ null, null, null, null ];
+ return this;
+ }
+ if ( red.jquery || red.nodeType ) {
+ red = jQuery( red ).css( green );
+ green = undefined;
+ }
+
+ var inst = this,
+ type = jQuery.type( red ),
+ rgba = this._rgba = [];
+
+ // more than 1 argument specified - assume ( red, green, blue, alpha )
+ if ( green !== undefined ) {
+ red = [ red, green, blue, alpha ];
+ type = "array";
+ }
+
+ if ( type === "string" ) {
+ return this.parse( stringParse( red ) || colors._default );
+ }
+
+ if ( type === "array" ) {
+ each( spaces.rgba.props, function( key, prop ) {
+ rgba[ prop.idx ] = clamp( red[ prop.idx ], prop );
+ });
+ return this;
+ }
+
+ if ( type === "object" ) {
+ if ( red instanceof color ) {
+ each( spaces, function( spaceName, space ) {
+ if ( red[ space.cache ] ) {
+ inst[ space.cache ] = red[ space.cache ].slice();
+ }
+ });
+ } else {
+ each( spaces, function( spaceName, space ) {
+ var cache = space.cache;
+ each( space.props, function( key, prop ) {
+
+ // if the cache doesn't exist, and we know how to convert
+ if ( !inst[ cache ] && space.to ) {
+
+ // if the value was null, we don't need to copy it
+ // if the key was alpha, we don't need to copy it either
+ if ( key === "alpha" || red[ key ] == null ) {
+ return;
+ }
+ inst[ cache ] = space.to( inst._rgba );
+ }
+
+ // this is the only case where we allow nulls for ALL properties.
+ // call clamp with alwaysAllowEmpty
+ inst[ cache ][ prop.idx ] = clamp( red[ key ], prop, true );
+ });
+
+ // everything defined but alpha?
+ if ( inst[ cache ] && jQuery.inArray( null, inst[ cache ].slice( 0, 3 ) ) < 0 ) {
+ // use the default of 1
+ inst[ cache ][ 3 ] = 1;
+ if ( space.from ) {
+ inst._rgba = space.from( inst[ cache ] );
+ }
+ }
+ });
+ }
+ return this;
+ }
+ },
+ is: function( compare ) {
+ var is = color( compare ),
+ same = true,
+ inst = this;
+
+ each( spaces, function( _, space ) {
+ var localCache,
+ isCache = is[ space.cache ];
+ if (isCache) {
+ localCache = inst[ space.cache ] || space.to && space.to( inst._rgba ) || [];
+ each( space.props, function( _, prop ) {
+ if ( isCache[ prop.idx ] != null ) {
+ same = ( isCache[ prop.idx ] === localCache[ prop.idx ] );
+ return same;
+ }
+ });
+ }
+ return same;
+ });
+ return same;
+ },
+ _space: function() {
+ var used = [],
+ inst = this;
+ each( spaces, function( spaceName, space ) {
+ if ( inst[ space.cache ] ) {
+ used.push( spaceName );
+ }
+ });
+ return used.pop();
+ },
+ transition: function( other, distance ) {
+ var end = color( other ),
+ spaceName = end._space(),
+ space = spaces[ spaceName ],
+ startColor = this.alpha() === 0 ? color( "transparent" ) : this,
+ start = startColor[ space.cache ] || space.to( startColor._rgba ),
+ result = start.slice();
+
+ end = end[ space.cache ];
+ each( space.props, function( key, prop ) {
+ var index = prop.idx,
+ startValue = start[ index ],
+ endValue = end[ index ],
+ type = propTypes[ prop.type ] || {};
+
+ // if null, don't override start value
+ if ( endValue === null ) {
+ return;
+ }
+ // if null - use end
+ if ( startValue === null ) {
+ result[ index ] = endValue;
+ } else {
+ if ( type.mod ) {
+ if ( endValue - startValue > type.mod / 2 ) {
+ startValue += type.mod;
+ } else if ( startValue - endValue > type.mod / 2 ) {
+ startValue -= type.mod;
+ }
+ }
+ result[ index ] = clamp( ( endValue - startValue ) * distance + startValue, prop );
+ }
+ });
+ return this[ spaceName ]( result );
+ },
+ blend: function( opaque ) {
+ // if we are already opaque - return ourself
+ if ( this._rgba[ 3 ] === 1 ) {
+ return this;
+ }
+
+ var rgb = this._rgba.slice(),
+ a = rgb.pop(),
+ blend = color( opaque )._rgba;
+
+ return color( jQuery.map( rgb, function( v, i ) {
+ return ( 1 - a ) * blend[ i ] + a * v;
+ }));
+ },
+ toRgbaString: function() {
+ var prefix = "rgba(",
+ rgba = jQuery.map( this._rgba, function( v, i ) {
+ return v == null ? ( i > 2 ? 1 : 0 ) : v;
+ });
+
+ if ( rgba[ 3 ] === 1 ) {
+ rgba.pop();
+ prefix = "rgb(";
+ }
+
+ return prefix + rgba.join() + ")";
+ },
+ toHslaString: function() {
+ var prefix = "hsla(",
+ hsla = jQuery.map( this.hsla(), function( v, i ) {
+ if ( v == null ) {
+ v = i > 2 ? 1 : 0;
+ }
+
+ // catch 1 and 2
+ if ( i && i < 3 ) {
+ v = Math.round( v * 100 ) + "%";
+ }
+ return v;
+ });
+
+ if ( hsla[ 3 ] === 1 ) {
+ hsla.pop();
+ prefix = "hsl(";
+ }
+ return prefix + hsla.join() + ")";
+ },
+ toHexString: function( includeAlpha ) {
+ var rgba = this._rgba.slice(),
+ alpha = rgba.pop();
+
+ if ( includeAlpha ) {
+ rgba.push( ~~( alpha * 255 ) );
+ }
+
+ return "#" + jQuery.map( rgba, function( v ) {
+
+ // default to 0 when nulls exist
+ v = ( v || 0 ).toString( 16 );
+ return v.length === 1 ? "0" + v : v;
+ }).join("");
+ },
+ toString: function() {
+ return this._rgba[ 3 ] === 0 ? "transparent" : this.toRgbaString();
+ }
+});
+color.fn.parse.prototype = color.fn;
+
+// hsla conversions adapted from:
+// https://code.google.com/p/maashaack/source/browse/packages/graphics/trunk/src/graphics/colors/HUE2RGB.as?r=5021
+
+function hue2rgb( p, q, h ) {
+ h = ( h + 1 ) % 1;
+ if ( h * 6 < 1 ) {
+ return p + (q - p) * h * 6;
+ }
+ if ( h * 2 < 1) {
+ return q;
+ }
+ if ( h * 3 < 2 ) {
+ return p + (q - p) * ((2/3) - h) * 6;
+ }
+ return p;
+}
+
+spaces.hsla.to = function ( rgba ) {
+ if ( rgba[ 0 ] == null || rgba[ 1 ] == null || rgba[ 2 ] == null ) {
+ return [ null, null, null, rgba[ 3 ] ];
+ }
+ var r = rgba[ 0 ] / 255,
+ g = rgba[ 1 ] / 255,
+ b = rgba[ 2 ] / 255,
+ a = rgba[ 3 ],
+ max = Math.max( r, g, b ),
+ min = Math.min( r, g, b ),
+ diff = max - min,
+ add = max + min,
+ l = add * 0.5,
+ h, s;
+
+ if ( min === max ) {
+ h = 0;
+ } else if ( r === max ) {
+ h = ( 60 * ( g - b ) / diff ) + 360;
+ } else if ( g === max ) {
+ h = ( 60 * ( b - r ) / diff ) + 120;
+ } else {
+ h = ( 60 * ( r - g ) / diff ) + 240;
+ }
+
+ // chroma (diff) == 0 means greyscale which, by definition, saturation = 0%
+ // otherwise, saturation is based on the ratio of chroma (diff) to lightness (add)
+ if ( diff === 0 ) {
+ s = 0;
+ } else if ( l <= 0.5 ) {
+ s = diff / add;
+ } else {
+ s = diff / ( 2 - add );
+ }
+ return [ Math.round(h) % 360, s, l, a == null ? 1 : a ];
+};
+
+spaces.hsla.from = function ( hsla ) {
+ if ( hsla[ 0 ] == null || hsla[ 1 ] == null || hsla[ 2 ] == null ) {
+ return [ null, null, null, hsla[ 3 ] ];
+ }
+ var h = hsla[ 0 ] / 360,
+ s = hsla[ 1 ],
+ l = hsla[ 2 ],
+ a = hsla[ 3 ],
+ q = l <= 0.5 ? l * ( 1 + s ) : l + s - l * s,
+ p = 2 * l - q;
+
+ return [
+ Math.round( hue2rgb( p, q, h + ( 1 / 3 ) ) * 255 ),
+ Math.round( hue2rgb( p, q, h ) * 255 ),
+ Math.round( hue2rgb( p, q, h - ( 1 / 3 ) ) * 255 ),
+ a
+ ];
+};
+
+
+each( spaces, function( spaceName, space ) {
+ var props = space.props,
+ cache = space.cache,
+ to = space.to,
+ from = space.from;
+
+ // makes rgba() and hsla()
+ color.fn[ spaceName ] = function( value ) {
+
+ // generate a cache for this space if it doesn't exist
+ if ( to && !this[ cache ] ) {
+ this[ cache ] = to( this._rgba );
+ }
+ if ( value === undefined ) {
+ return this[ cache ].slice();
+ }
+
+ var ret,
+ type = jQuery.type( value ),
+ arr = ( type === "array" || type === "object" ) ? value : arguments,
+ local = this[ cache ].slice();
+
+ each( props, function( key, prop ) {
+ var val = arr[ type === "object" ? key : prop.idx ];
+ if ( val == null ) {
+ val = local[ prop.idx ];
+ }
+ local[ prop.idx ] = clamp( val, prop );
+ });
+
+ if ( from ) {
+ ret = color( from( local ) );
+ ret[ cache ] = local;
+ return ret;
+ } else {
+ return color( local );
+ }
+ };
+
+ // makes red() green() blue() alpha() hue() saturation() lightness()
+ each( props, function( key, prop ) {
+ // alpha is included in more than one space
+ if ( color.fn[ key ] ) {
+ return;
+ }
+ color.fn[ key ] = function( value ) {
+ var vtype = jQuery.type( value ),
+ fn = ( key === "alpha" ? ( this._hsla ? "hsla" : "rgba" ) : spaceName ),
+ local = this[ fn ](),
+ cur = local[ prop.idx ],
+ match;
+
+ if ( vtype === "undefined" ) {
+ return cur;
+ }
+
+ if ( vtype === "function" ) {
+ value = value.call( this, cur );
+ vtype = jQuery.type( value );
+ }
+ if ( value == null && prop.empty ) {
+ return this;
+ }
+ if ( vtype === "string" ) {
+ match = rplusequals.exec( value );
+ if ( match ) {
+ value = cur + parseFloat( match[ 2 ] ) * ( match[ 1 ] === "+" ? 1 : -1 );
+ }
+ }
+ local[ prop.idx ] = value;
+ return this[ fn ]( local );
+ };
+ });
+});
+
+// add cssHook and .fx.step function for each named hook.
+// accept a space separated string of properties
+color.hook = function( hook ) {
+ var hooks = hook.split( " " );
+ each( hooks, function( i, hook ) {
+ jQuery.cssHooks[ hook ] = {
+ set: function( elem, value ) {
+ var parsed, curElem,
+ backgroundColor = "";
+
+ if ( value !== "transparent" && ( jQuery.type( value ) !== "string" || ( parsed = stringParse( value ) ) ) ) {
+ value = color( parsed || value );
+ if ( !support.rgba && value._rgba[ 3 ] !== 1 ) {
+ curElem = hook === "backgroundColor" ? elem.parentNode : elem;
+ while (
+ (backgroundColor === "" || backgroundColor === "transparent") &&
+ curElem && curElem.style
+ ) {
+ try {
+ backgroundColor = jQuery.css( curElem, "backgroundColor" );
+ curElem = curElem.parentNode;
+ } catch ( e ) {
+ }
+ }
+
+ value = value.blend( backgroundColor && backgroundColor !== "transparent" ?
+ backgroundColor :
+ "_default" );
+ }
+
+ value = value.toRgbaString();
+ }
+ try {
+ elem.style[ hook ] = value;
+ } catch( e ) {
+ // wrapped to prevent IE from throwing errors on "invalid" values like 'auto' or 'inherit'
+ }
+ }
+ };
+ jQuery.fx.step[ hook ] = function( fx ) {
+ if ( !fx.colorInit ) {
+ fx.start = color( fx.elem, hook );
+ fx.end = color( fx.end );
+ fx.colorInit = true;
+ }
+ jQuery.cssHooks[ hook ].set( fx.elem, fx.start.transition( fx.end, fx.pos ) );
+ };
+ });
+
+};
+
+color.hook( stepHooks );
+
+jQuery.cssHooks.borderColor = {
+ expand: function( value ) {
+ var expanded = {};
+
+ each( [ "Top", "Right", "Bottom", "Left" ], function( i, part ) {
+ expanded[ "border" + part + "Color" ] = value;
+ });
+ return expanded;
+ }
+};
+
+// Basic color names only.
+// Usage of any of the other color names requires adding yourself or including
+// jquery.color.svg-names.js.
+colors = jQuery.Color.names = {
+ // 4.1. Basic color keywords
+ aqua: "#00ffff",
+ black: "#000000",
+ blue: "#0000ff",
+ fuchsia: "#ff00ff",
+ gray: "#808080",
+ green: "#008000",
+ lime: "#00ff00",
+ maroon: "#800000",
+ navy: "#000080",
+ olive: "#808000",
+ purple: "#800080",
+ red: "#ff0000",
+ silver: "#c0c0c0",
+ teal: "#008080",
+ white: "#ffffff",
+ yellow: "#ffff00",
+
+ // 4.2.3. "transparent" color keyword
+ transparent: [ null, null, null, 0 ],
+
+ _default: "#ffffff"
+};
+
+})( jQuery );
+
+
+/******************************************************************************/
+/****************************** CLASS ANIMATIONS ******************************/
+/******************************************************************************/
+(function() {
+
+var classAnimationActions = [ "add", "remove", "toggle" ],
+ shorthandStyles = {
+ border: 1,
+ borderBottom: 1,
+ borderColor: 1,
+ borderLeft: 1,
+ borderRight: 1,
+ borderTop: 1,
+ borderWidth: 1,
+ margin: 1,
+ padding: 1
+ };
+
+$.each([ "borderLeftStyle", "borderRightStyle", "borderBottomStyle", "borderTopStyle" ], function( _, prop ) {
+ $.fx.step[ prop ] = function( fx ) {
+ if ( fx.end !== "none" && !fx.setAttr || fx.pos === 1 && !fx.setAttr ) {
+ jQuery.style( fx.elem, prop, fx.end );
+ fx.setAttr = true;
+ }
+ };
+});
+
+function getElementStyles( elem ) {
+ var key, len,
+ style = elem.ownerDocument.defaultView ?
+ elem.ownerDocument.defaultView.getComputedStyle( elem, null ) :
+ elem.currentStyle,
+ styles = {};
+
+ if ( style && style.length && style[ 0 ] && style[ style[ 0 ] ] ) {
+ len = style.length;
+ while ( len-- ) {
+ key = style[ len ];
+ if ( typeof style[ key ] === "string" ) {
+ styles[ $.camelCase( key ) ] = style[ key ];
+ }
+ }
+ // support: Opera, IE <9
+ } else {
+ for ( key in style ) {
+ if ( typeof style[ key ] === "string" ) {
+ styles[ key ] = style[ key ];
+ }
+ }
+ }
+
+ return styles;
+}
+
+
+function styleDifference( oldStyle, newStyle ) {
+ var diff = {},
+ name, value;
+
+ for ( name in newStyle ) {
+ value = newStyle[ name ];
+ if ( oldStyle[ name ] !== value ) {
+ if ( !shorthandStyles[ name ] ) {
+ if ( $.fx.step[ name ] || !isNaN( parseFloat( value ) ) ) {
+ diff[ name ] = value;
+ }
+ }
+ }
+ }
+
+ return diff;
+}
+
+// support: jQuery <1.8
+if ( !$.fn.addBack ) {
+ $.fn.addBack = function( selector ) {
+ return this.add( selector == null ?
+ this.prevObject : this.prevObject.filter( selector )
+ );
+ };
+}
+
+$.effects.animateClass = function( value, duration, easing, callback ) {
+ var o = $.speed( duration, easing, callback );
+
+ return this.queue( function() {
+ var animated = $( this ),
+ baseClass = animated.attr( "class" ) || "",
+ applyClassChange,
+ allAnimations = o.children ? animated.find( "*" ).addBack() : animated;
+
+ // map the animated objects to store the original styles.
+ allAnimations = allAnimations.map(function() {
+ var el = $( this );
+ return {
+ el: el,
+ start: getElementStyles( this )
+ };
+ });
+
+ // apply class change
+ applyClassChange = function() {
+ $.each( classAnimationActions, function(i, action) {
+ if ( value[ action ] ) {
+ animated[ action + "Class" ]( value[ action ] );
+ }
+ });
+ };
+ applyClassChange();
+
+ // map all animated objects again - calculate new styles and diff
+ allAnimations = allAnimations.map(function() {
+ this.end = getElementStyles( this.el[ 0 ] );
+ this.diff = styleDifference( this.start, this.end );
+ return this;
+ });
+
+ // apply original class
+ animated.attr( "class", baseClass );
+
+ // map all animated objects again - this time collecting a promise
+ allAnimations = allAnimations.map(function() {
+ var styleInfo = this,
+ dfd = $.Deferred(),
+ opts = $.extend({}, o, {
+ queue: false,
+ complete: function() {
+ dfd.resolve( styleInfo );
+ }
+ });
+
+ this.el.animate( this.diff, opts );
+ return dfd.promise();
+ });
+
+ // once all animations have completed:
+ $.when.apply( $, allAnimations.get() ).done(function() {
+
+ // set the final class
+ applyClassChange();
+
+ // for each animated element,
+ // clear all css properties that were animated
+ $.each( arguments, function() {
+ var el = this.el;
+ $.each( this.diff, function(key) {
+ el.css( key, "" );
+ });
+ });
+
+ // this is guarnteed to be there if you use jQuery.speed()
+ // it also handles dequeuing the next anim...
+ o.complete.call( animated[ 0 ] );
+ });
+ });
+};
+
+$.fn.extend({
+ addClass: (function( orig ) {
+ return function( classNames, speed, easing, callback ) {
+ return speed ?
+ $.effects.animateClass.call( this,
+ { add: classNames }, speed, easing, callback ) :
+ orig.apply( this, arguments );
+ };
+ })( $.fn.addClass ),
+
+ removeClass: (function( orig ) {
+ return function( classNames, speed, easing, callback ) {
+ return arguments.length > 1 ?
+ $.effects.animateClass.call( this,
+ { remove: classNames }, speed, easing, callback ) :
+ orig.apply( this, arguments );
+ };
+ })( $.fn.removeClass ),
+
+ toggleClass: (function( orig ) {
+ return function( classNames, force, speed, easing, callback ) {
+ if ( typeof force === "boolean" || force === undefined ) {
+ if ( !speed ) {
+ // without speed parameter
+ return orig.apply( this, arguments );
+ } else {
+ return $.effects.animateClass.call( this,
+ (force ? { add: classNames } : { remove: classNames }),
+ speed, easing, callback );
+ }
+ } else {
+ // without force parameter
+ return $.effects.animateClass.call( this,
+ { toggle: classNames }, force, speed, easing );
+ }
+ };
+ })( $.fn.toggleClass ),
+
+ switchClass: function( remove, add, speed, easing, callback) {
+ return $.effects.animateClass.call( this, {
+ add: add,
+ remove: remove
+ }, speed, easing, callback );
+ }
+});
+
+})();
+
+/******************************************************************************/
+/*********************************** EFFECTS **********************************/
+/******************************************************************************/
+
+(function() {
+
+$.extend( $.effects, {
+ version: "1.10.3",
+
+ // Saves a set of properties in a data storage
+ save: function( element, set ) {
+ for( var i=0; i < set.length; i++ ) {
+ if ( set[ i ] !== null ) {
+ element.data( dataSpace + set[ i ], element[ 0 ].style[ set[ i ] ] );
+ }
+ }
+ },
+
+ // Restores a set of previously saved properties from a data storage
+ restore: function( element, set ) {
+ var val, i;
+ for( i=0; i < set.length; i++ ) {
+ if ( set[ i ] !== null ) {
+ val = element.data( dataSpace + set[ i ] );
+ // support: jQuery 1.6.2
+ // http://bugs.jquery.com/ticket/9917
+ // jQuery 1.6.2 incorrectly returns undefined for any falsy value.
+ // We can't differentiate between "" and 0 here, so we just assume
+ // empty string since it's likely to be a more common value...
+ if ( val === undefined ) {
+ val = "";
+ }
+ element.css( set[ i ], val );
+ }
+ }
+ },
+
+ setMode: function( el, mode ) {
+ if (mode === "toggle") {
+ mode = el.is( ":hidden" ) ? "show" : "hide";
+ }
+ return mode;
+ },
+
+ // Translates a [top,left] array into a baseline value
+ // this should be a little more flexible in the future to handle a string & hash
+ getBaseline: function( origin, original ) {
+ var y, x;
+ switch ( origin[ 0 ] ) {
+ case "top": y = 0; break;
+ case "middle": y = 0.5; break;
+ case "bottom": y = 1; break;
+ default: y = origin[ 0 ] / original.height;
+ }
+ switch ( origin[ 1 ] ) {
+ case "left": x = 0; break;
+ case "center": x = 0.5; break;
+ case "right": x = 1; break;
+ default: x = origin[ 1 ] / original.width;
+ }
+ return {
+ x: x,
+ y: y
+ };
+ },
+
+ // Wraps the element around a wrapper that copies position properties
+ createWrapper: function( element ) {
+
+ // if the element is already wrapped, return it
+ if ( element.parent().is( ".ui-effects-wrapper" )) {
+ return element.parent();
+ }
+
+ // wrap the element
+ var props = {
+ width: element.outerWidth(true),
+ height: element.outerHeight(true),
+ "float": element.css( "float" )
+ },
+ wrapper = $( "<div></div>" )
+ .addClass( "ui-effects-wrapper" )
+ .css({
+ fontSize: "100%",
+ background: "transparent",
+ border: "none",
+ margin: 0,
+ padding: 0
+ }),
+ // Store the size in case width/height are defined in % - Fixes #5245
+ size = {
+ width: element.width(),
+ height: element.height()
+ },
+ active = document.activeElement;
+
+ // support: Firefox
+ // Firefox incorrectly exposes anonymous content
+ // https://bugzilla.mozilla.org/show_bug.cgi?id=561664
+ try {
+ active.id;
+ } catch( e ) {
+ active = document.body;
+ }
+
+ element.wrap( wrapper );
+
+ // Fixes #7595 - Elements lose focus when wrapped.
+ if ( element[ 0 ] === active || $.contains( element[ 0 ], active ) ) {
+ $( active ).focus();
+ }
+
+ wrapper = element.parent(); //Hotfix for jQuery 1.4 since some change in wrap() seems to actually lose the reference to the wrapped element
+
+ // transfer positioning properties to the wrapper
+ if ( element.css( "position" ) === "static" ) {
+ wrapper.css({ position: "relative" });
+ element.css({ position: "relative" });
+ } else {
+ $.extend( props, {
+ position: element.css( "position" ),
+ zIndex: element.css( "z-index" )
+ });
+ $.each([ "top", "left", "bottom", "right" ], function(i, pos) {
+ props[ pos ] = element.css( pos );
+ if ( isNaN( parseInt( props[ pos ], 10 ) ) ) {
+ props[ pos ] = "auto";
+ }
+ });
+ element.css({
+ position: "relative",
+ top: 0,
+ left: 0,
+ right: "auto",
+ bottom: "auto"
+ });
+ }
+ element.css(size);
+
+ return wrapper.css( props ).show();
+ },
+
+ removeWrapper: function( element ) {
+ var active = document.activeElement;
+
+ if ( element.parent().is( ".ui-effects-wrapper" ) ) {
+ element.parent().replaceWith( element );
+
+ // Fixes #7595 - Elements lose focus when wrapped.
+ if ( element[ 0 ] === active || $.contains( element[ 0 ], active ) ) {
+ $( active ).focus();
+ }
+ }
+
+
+ return element;
+ },
+
+ setTransition: function( element, list, factor, value ) {
+ value = value || {};
+ $.each( list, function( i, x ) {
+ var unit = element.cssUnit( x );
+ if ( unit[ 0 ] > 0 ) {
+ value[ x ] = unit[ 0 ] * factor + unit[ 1 ];
+ }
+ });
+ return value;
+ }
+});
+
+// return an effect options object for the given parameters:
+function _normalizeArguments( effect, options, speed, callback ) {
+
+ // allow passing all options as the first parameter
+ if ( $.isPlainObject( effect ) ) {
+ options = effect;
+ effect = effect.effect;
+ }
+
+ // convert to an object
+ effect = { effect: effect };
+
+ // catch (effect, null, ...)
+ if ( options == null ) {
+ options = {};
+ }
+
+ // catch (effect, callback)
+ if ( $.isFunction( options ) ) {
+ callback = options;
+ speed = null;
+ options = {};
+ }
+
+ // catch (effect, speed, ?)
+ if ( typeof options === "number" || $.fx.speeds[ options ] ) {
+ callback = speed;
+ speed = options;
+ options = {};
+ }
+
+ // catch (effect, options, callback)
+ if ( $.isFunction( speed ) ) {
+ callback = speed;
+ speed = null;
+ }
+
+ // add options to effect
+ if ( options ) {
+ $.extend( effect, options );
+ }
+
+ speed = speed || options.duration;
+ effect.duration = $.fx.off ? 0 :
+ typeof speed === "number" ? speed :
+ speed in $.fx.speeds ? $.fx.speeds[ speed ] :
+ $.fx.speeds._default;
+
+ effect.complete = callback || options.complete;
+
+ return effect;
+}
+
+function standardAnimationOption( option ) {
+ // Valid standard speeds (nothing, number, named speed)
+ if ( !option || typeof option === "number" || $.fx.speeds[ option ] ) {
+ return true;
+ }
+
+ // Invalid strings - treat as "normal" speed
+ if ( typeof option === "string" && !$.effects.effect[ option ] ) {
+ return true;
+ }
+
+ // Complete callback
+ if ( $.isFunction( option ) ) {
+ return true;
+ }
+
+ // Options hash (but not naming an effect)
+ if ( typeof option === "object" && !option.effect ) {
+ return true;
+ }
+
+ // Didn't match any standard API
+ return false;
+}
+
+$.fn.extend({
+ effect: function( /* effect, options, speed, callback */ ) {
+ var args = _normalizeArguments.apply( this, arguments ),
+ mode = args.mode,
+ queue = args.queue,
+ effectMethod = $.effects.effect[ args.effect ];
+
+ if ( $.fx.off || !effectMethod ) {
+ // delegate to the original method (e.g., .show()) if possible
+ if ( mode ) {
+ return this[ mode ]( args.duration, args.complete );
+ } else {
+ return this.each( function() {
+ if ( args.complete ) {
+ args.complete.call( this );
+ }
+ });
+ }
+ }
+
+ function run( next ) {
+ var elem = $( this ),
+ complete = args.complete,
+ mode = args.mode;
+
+ function done() {
+ if ( $.isFunction( complete ) ) {
+ complete.call( elem[0] );
+ }
+ if ( $.isFunction( next ) ) {
+ next();
+ }
+ }
+
+ // If the element already has the correct final state, delegate to
+ // the core methods so the internal tracking of "olddisplay" works.
+ if ( elem.is( ":hidden" ) ? mode === "hide" : mode === "show" ) {
+ elem[ mode ]();
+ done();
+ } else {
+ effectMethod.call( elem[0], args, done );
+ }
+ }
+
+ return queue === false ? this.each( run ) : this.queue( queue || "fx", run );
+ },
+
+ show: (function( orig ) {
+ return function( option ) {
+ if ( standardAnimationOption( option ) ) {
+ return orig.apply( this, arguments );
+ } else {
+ var args = _normalizeArguments.apply( this, arguments );
+ args.mode = "show";
+ return this.effect.call( this, args );
+ }
+ };
+ })( $.fn.show ),
+
+ hide: (function( orig ) {
+ return function( option ) {
+ if ( standardAnimationOption( option ) ) {
+ return orig.apply( this, arguments );
+ } else {
+ var args = _normalizeArguments.apply( this, arguments );
+ args.mode = "hide";
+ return this.effect.call( this, args );
+ }
+ };
+ })( $.fn.hide ),
+
+ toggle: (function( orig ) {
+ return function( option ) {
+ if ( standardAnimationOption( option ) || typeof option === "boolean" ) {
+ return orig.apply( this, arguments );
+ } else {
+ var args = _normalizeArguments.apply( this, arguments );
+ args.mode = "toggle";
+ return this.effect.call( this, args );
+ }
+ };
+ })( $.fn.toggle ),
+
+ // helper functions
+ cssUnit: function(key) {
+ var style = this.css( key ),
+ val = [];
+
+ $.each( [ "em", "px", "%", "pt" ], function( i, unit ) {
+ if ( style.indexOf( unit ) > 0 ) {
+ val = [ parseFloat( style ), unit ];
+ }
+ });
+ return val;
+ }
+});
+
+})();
+
+/******************************************************************************/
+/*********************************** EASING ***********************************/
+/******************************************************************************/
+
+(function() {
+
+// based on easing equations from Robert Penner (http://www.robertpenner.com/easing)
+
+var baseEasings = {};
+
+$.each( [ "Quad", "Cubic", "Quart", "Quint", "Expo" ], function( i, name ) {
+ baseEasings[ name ] = function( p ) {
+ return Math.pow( p, i + 2 );
+ };
+});
+
+$.extend( baseEasings, {
+ Sine: function ( p ) {
+ return 1 - Math.cos( p * Math.PI / 2 );
+ },
+ Circ: function ( p ) {
+ return 1 - Math.sqrt( 1 - p * p );
+ },
+ Elastic: function( p ) {
+ return p === 0 || p === 1 ? p :
+ -Math.pow( 2, 8 * (p - 1) ) * Math.sin( ( (p - 1) * 80 - 7.5 ) * Math.PI / 15 );
+ },
+ Back: function( p ) {
+ return p * p * ( 3 * p - 2 );
+ },
+ Bounce: function ( p ) {
+ var pow2,
+ bounce = 4;
+
+ while ( p < ( ( pow2 = Math.pow( 2, --bounce ) ) - 1 ) / 11 ) {}
+ return 1 / Math.pow( 4, 3 - bounce ) - 7.5625 * Math.pow( ( pow2 * 3 - 2 ) / 22 - p, 2 );
+ }
+});
+
+$.each( baseEasings, function( name, easeIn ) {
+ $.easing[ "easeIn" + name ] = easeIn;
+ $.easing[ "easeOut" + name ] = function( p ) {
+ return 1 - easeIn( 1 - p );
+ };
+ $.easing[ "easeInOut" + name ] = function( p ) {
+ return p < 0.5 ?
+ easeIn( p * 2 ) / 2 :
+ 1 - easeIn( p * -2 + 2 ) / 2;
+ };
+});
+
+})();
+
+})(jQuery);
+
+(function( $, undefined ) {
+
+var uid = 0,
+ hideProps = {},
+ showProps = {};
+
+hideProps.height = hideProps.paddingTop = hideProps.paddingBottom =
+ hideProps.borderTopWidth = hideProps.borderBottomWidth = "hide";
+showProps.height = showProps.paddingTop = showProps.paddingBottom =
+ showProps.borderTopWidth = showProps.borderBottomWidth = "show";
+
+$.widget( "ui.accordion", {
+ version: "1.10.3",
+ options: {
+ active: 0,
+ animate: {},
+ collapsible: false,
+ event: "click",
+ header: "> li > :first-child,> :not(li):even",
+ heightStyle: "auto",
+ icons: {
+ activeHeader: "ui-icon-triangle-1-s",
+ header: "ui-icon-triangle-1-e"
+ },
+
+ // callbacks
+ activate: null,
+ beforeActivate: null
+ },
+
+ _create: function() {
+ var options = this.options;
+ this.prevShow = this.prevHide = $();
+ this.element.addClass( "ui-accordion ui-widget ui-helper-reset" )
+ // ARIA
+ .attr( "role", "tablist" );
+
+ // don't allow collapsible: false and active: false / null
+ if ( !options.collapsible && (options.active === false || options.active == null) ) {
+ options.active = 0;
+ }
+
+ this._processPanels();
+ // handle negative values
+ if ( options.active < 0 ) {
+ options.active += this.headers.length;
+ }
+ this._refresh();
+ },
+
+ _getCreateEventData: function() {
+ return {
+ header: this.active,
+ panel: !this.active.length ? $() : this.active.next(),
+ content: !this.active.length ? $() : this.active.next()
+ };
+ },
+
+ _createIcons: function() {
+ var icons = this.options.icons;
+ if ( icons ) {
+ $( "<span>" )
+ .addClass( "ui-accordion-header-icon ui-icon " + icons.header )
+ .prependTo( this.headers );
+ this.active.children( ".ui-accordion-header-icon" )
+ .removeClass( icons.header )
+ .addClass( icons.activeHeader );
+ this.headers.addClass( "ui-accordion-icons" );
+ }
+ },
+
+ _destroyIcons: function() {
+ this.headers
+ .removeClass( "ui-accordion-icons" )
+ .children( ".ui-accordion-header-icon" )
+ .remove();
+ },
+
+ _destroy: function() {
+ var contents;
+
+ // clean up main element
+ this.element
+ .removeClass( "ui-accordion ui-widget ui-helper-reset" )
+ .removeAttr( "role" );
+
+ // clean up headers
+ this.headers
+ .removeClass( "ui-accordion-header ui-accordion-header-active ui-helper-reset ui-state-default ui-corner-all ui-state-active ui-state-disabled ui-corner-top" )
+ .removeAttr( "role" )
+ .removeAttr( "aria-selected" )
+ .removeAttr( "aria-controls" )
+ .removeAttr( "tabIndex" )
+ .each(function() {
+ if ( /^ui-accordion/.test( this.id ) ) {
+ this.removeAttribute( "id" );
+ }
+ });
+ this._destroyIcons();
+
+ // clean up content panels
+ contents = this.headers.next()
+ .css( "display", "" )
+ .removeAttr( "role" )
+ .removeAttr( "aria-expanded" )
+ .removeAttr( "aria-hidden" )
+ .removeAttr( "aria-labelledby" )
+ .removeClass( "ui-helper-reset ui-widget-content ui-corner-bottom ui-accordion-content ui-accordion-content-active ui-state-disabled" )
+ .each(function() {
+ if ( /^ui-accordion/.test( this.id ) ) {
+ this.removeAttribute( "id" );
+ }
+ });
+ if ( this.options.heightStyle !== "content" ) {
+ contents.css( "height", "" );
+ }
+ },
+
+ _setOption: function( key, value ) {
+ if ( key === "active" ) {
+ // _activate() will handle invalid values and update this.options
+ this._activate( value );
+ return;
+ }
+
+ if ( key === "event" ) {
+ if ( this.options.event ) {
+ this._off( this.headers, this.options.event );
+ }
+ this._setupEvents( value );
+ }
+
+ this._super( key, value );
+
+ // setting collapsible: false while collapsed; open first panel
+ if ( key === "collapsible" && !value && this.options.active === false ) {
+ this._activate( 0 );
+ }
+
+ if ( key === "icons" ) {
+ this._destroyIcons();
+ if ( value ) {
+ this._createIcons();
+ }
+ }
+
+ // #5332 - opacity doesn't cascade to positioned elements in IE
+ // so we need to add the disabled class to the headers and panels
+ if ( key === "disabled" ) {
+ this.headers.add( this.headers.next() )
+ .toggleClass( "ui-state-disabled", !!value );
+ }
+ },
+
+ _keydown: function( event ) {
+ /*jshint maxcomplexity:15*/
+ if ( event.altKey || event.ctrlKey ) {
+ return;
+ }
+
+ var keyCode = $.ui.keyCode,
+ length = this.headers.length,
+ currentIndex = this.headers.index( event.target ),
+ toFocus = false;
+
+ switch ( event.keyCode ) {
+ case keyCode.RIGHT:
+ case keyCode.DOWN:
+ toFocus = this.headers[ ( currentIndex + 1 ) % length ];
+ break;
+ case keyCode.LEFT:
+ case keyCode.UP:
+ toFocus = this.headers[ ( currentIndex - 1 + length ) % length ];
+ break;
+ case keyCode.SPACE:
+ case keyCode.ENTER:
+ this._eventHandler( event );
+ break;
+ case keyCode.HOME:
+ toFocus = this.headers[ 0 ];
+ break;
+ case keyCode.END:
+ toFocus = this.headers[ length - 1 ];
+ break;
+ }
+
+ if ( toFocus ) {
+ $( event.target ).attr( "tabIndex", -1 );
+ $( toFocus ).attr( "tabIndex", 0 );
+ toFocus.focus();
+ event.preventDefault();
+ }
+ },
+
+ _panelKeyDown : function( event ) {
+ if ( event.keyCode === $.ui.keyCode.UP && event.ctrlKey ) {
+ $( event.currentTarget ).prev().focus();
+ }
+ },
+
+ refresh: function() {
+ var options = this.options;
+ this._processPanels();
+
+ // was collapsed or no panel
+ if ( ( options.active === false && options.collapsible === true ) || !this.headers.length ) {
+ options.active = false;
+ this.active = $();
+ // active false only when collapsible is true
+ } else if ( options.active === false ) {
+ this._activate( 0 );
+ // was active, but active panel is gone
+ } else if ( this.active.length && !$.contains( this.element[ 0 ], this.active[ 0 ] ) ) {
+ // all remaining panel are disabled
+ if ( this.headers.length === this.headers.find(".ui-state-disabled").length ) {
+ options.active = false;
+ this.active = $();
+ // activate previous panel
+ } else {
+ this._activate( Math.max( 0, options.active - 1 ) );
+ }
+ // was active, active panel still exists
+ } else {
+ // make sure active index is correct
+ options.active = this.headers.index( this.active );
+ }
+
+ this._destroyIcons();
+
+ this._refresh();
+ },
+
+ _processPanels: function() {
+ this.headers = this.element.find( this.options.header )
+ .addClass( "ui-accordion-header ui-helper-reset ui-state-default ui-corner-all" );
+
+ this.headers.next()
+ .addClass( "ui-accordion-content ui-helper-reset ui-widget-content ui-corner-bottom" )
+ .filter(":not(.ui-accordion-content-active)")
+ .hide();
+ },
+
+ _refresh: function() {
+ var maxHeight,
+ options = this.options,
+ heightStyle = options.heightStyle,
+ parent = this.element.parent(),
+ accordionId = this.accordionId = "ui-accordion-" +
+ (this.element.attr( "id" ) || ++uid);
+
+ this.active = this._findActive( options.active )
+ .addClass( "ui-accordion-header-active ui-state-active ui-corner-top" )
+ .removeClass( "ui-corner-all" );
+ this.active.next()
+ .addClass( "ui-accordion-content-active" )
+ .show();
+
+ this.headers
+ .attr( "role", "tab" )
+ .each(function( i ) {
+ var header = $( this ),
+ headerId = header.attr( "id" ),
+ panel = header.next(),
+ panelId = panel.attr( "id" );
+ if ( !headerId ) {
+ headerId = accordionId + "-header-" + i;
+ header.attr( "id", headerId );
+ }
+ if ( !panelId ) {
+ panelId = accordionId + "-panel-" + i;
+ panel.attr( "id", panelId );
+ }
+ header.attr( "aria-controls", panelId );
+ panel.attr( "aria-labelledby", headerId );
+ })
+ .next()
+ .attr( "role", "tabpanel" );
+
+ this.headers
+ .not( this.active )
+ .attr({
+ "aria-selected": "false",
+ tabIndex: -1
+ })
+ .next()
+ .attr({
+ "aria-expanded": "false",
+ "aria-hidden": "true"
+ })
+ .hide();
+
+ // make sure at least one header is in the tab order
+ if ( !this.active.length ) {
+ this.headers.eq( 0 ).attr( "tabIndex", 0 );
+ } else {
+ this.active.attr({
+ "aria-selected": "true",
+ tabIndex: 0
+ })
+ .next()
+ .attr({
+ "aria-expanded": "true",
+ "aria-hidden": "false"
+ });
+ }
+
+ this._createIcons();
+
+ this._setupEvents( options.event );
+
+ if ( heightStyle === "fill" ) {
+ maxHeight = parent.height();
+ this.element.siblings( ":visible" ).each(function() {
+ var elem = $( this ),
+ position = elem.css( "position" );
+
+ if ( position === "absolute" || position === "fixed" ) {
+ return;
+ }
+ maxHeight -= elem.outerHeight( true );
+ });
+
+ this.headers.each(function() {
+ maxHeight -= $( this ).outerHeight( true );
+ });
+
+ this.headers.next()
+ .each(function() {
+ $( this ).height( Math.max( 0, maxHeight -
+ $( this ).innerHeight() + $( this ).height() ) );
+ })
+ .css( "overflow", "auto" );
+ } else if ( heightStyle === "auto" ) {
+ maxHeight = 0;
+ this.headers.next()
+ .each(function() {
+ maxHeight = Math.max( maxHeight, $( this ).css( "height", "" ).height() );
+ })
+ .height( maxHeight );
+ }
+ },
+
+ _activate: function( index ) {
+ var active = this._findActive( index )[ 0 ];
+
+ // trying to activate the already active panel
+ if ( active === this.active[ 0 ] ) {
+ return;
+ }
+
+ // trying to collapse, simulate a click on the currently active header
+ active = active || this.active[ 0 ];
+
+ this._eventHandler({
+ target: active,
+ currentTarget: active,
+ preventDefault: $.noop
+ });
+ },
+
+ _findActive: function( selector ) {
+ return typeof selector === "number" ? this.headers.eq( selector ) : $();
+ },
+
+ _setupEvents: function( event ) {
+ var events = {
+ keydown: "_keydown"
+ };
+ if ( event ) {
+ $.each( event.split(" "), function( index, eventName ) {
+ events[ eventName ] = "_eventHandler";
+ });
+ }
+
+ this._off( this.headers.add( this.headers.next() ) );
+ this._on( this.headers, events );
+ this._on( this.headers.next(), { keydown: "_panelKeyDown" });
+ this._hoverable( this.headers );
+ this._focusable( this.headers );
+ },
+
+ _eventHandler: function( event ) {
+ var options = this.options,
+ active = this.active,
+ clicked = $( event.currentTarget ),
+ clickedIsActive = clicked[ 0 ] === active[ 0 ],
+ collapsing = clickedIsActive && options.collapsible,
+ toShow = collapsing ? $() : clicked.next(),
+ toHide = active.next(),
+ eventData = {
+ oldHeader: active,
+ oldPanel: toHide,
+ newHeader: collapsing ? $() : clicked,
+ newPanel: toShow
+ };
+
+ event.preventDefault();
+
+ if (
+ // click on active header, but not collapsible
+ ( clickedIsActive && !options.collapsible ) ||
+ // allow canceling activation
+ ( this._trigger( "beforeActivate", event, eventData ) === false ) ) {
+ return;
+ }
+
+ options.active = collapsing ? false : this.headers.index( clicked );
+
+ // when the call to ._toggle() comes after the class changes
+ // it causes a very odd bug in IE 8 (see #6720)
+ this.active = clickedIsActive ? $() : clicked;
+ this._toggle( eventData );
+
+ // switch classes
+ // corner classes on the previously active header stay after the animation
+ active.removeClass( "ui-accordion-header-active ui-state-active" );
+ if ( options.icons ) {
+ active.children( ".ui-accordion-header-icon" )
+ .removeClass( options.icons.activeHeader )
+ .addClass( options.icons.header );
+ }
+
+ if ( !clickedIsActive ) {
+ clicked
+ .removeClass( "ui-corner-all" )
+ .addClass( "ui-accordion-header-active ui-state-active ui-corner-top" );
+ if ( options.icons ) {
+ clicked.children( ".ui-accordion-header-icon" )
+ .removeClass( options.icons.header )
+ .addClass( options.icons.activeHeader );
+ }
+
+ clicked
+ .next()
+ .addClass( "ui-accordion-content-active" );
+ }
+ },
+
+ _toggle: function( data ) {
+ var toShow = data.newPanel,
+ toHide = this.prevShow.length ? this.prevShow : data.oldPanel;
+
+ // handle activating a panel during the animation for another activation
+ this.prevShow.add( this.prevHide ).stop( true, true );
+ this.prevShow = toShow;
+ this.prevHide = toHide;
+
+ if ( this.options.animate ) {
+ this._animate( toShow, toHide, data );
+ } else {
+ toHide.hide();
+ toShow.show();
+ this._toggleComplete( data );
+ }
+
+ toHide.attr({
+ "aria-expanded": "false",
+ "aria-hidden": "true"
+ });
+ toHide.prev().attr( "aria-selected", "false" );
+ // if we're switching panels, remove the old header from the tab order
+ // if we're opening from collapsed state, remove the previous header from the tab order
+ // if we're collapsing, then keep the collapsing header in the tab order
+ if ( toShow.length && toHide.length ) {
+ toHide.prev().attr( "tabIndex", -1 );
+ } else if ( toShow.length ) {
+ this.headers.filter(function() {
+ return $( this ).attr( "tabIndex" ) === 0;
+ })
+ .attr( "tabIndex", -1 );
+ }
+
+ toShow
+ .attr({
+ "aria-expanded": "true",
+ "aria-hidden": "false"
+ })
+ .prev()
+ .attr({
+ "aria-selected": "true",
+ tabIndex: 0
+ });
+ },
+
+ _animate: function( toShow, toHide, data ) {
+ var total, easing, duration,
+ that = this,
+ adjust = 0,
+ down = toShow.length &&
+ ( !toHide.length || ( toShow.index() < toHide.index() ) ),
+ animate = this.options.animate || {},
+ options = down && animate.down || animate,
+ complete = function() {
+ that._toggleComplete( data );
+ };
+
+ if ( typeof options === "number" ) {
+ duration = options;
+ }
+ if ( typeof options === "string" ) {
+ easing = options;
+ }
+ // fall back from options to animation in case of partial down settings
+ easing = easing || options.easing || animate.easing;
+ duration = duration || options.duration || animate.duration;
+
+ if ( !toHide.length ) {
+ return toShow.animate( showProps, duration, easing, complete );
+ }
+ if ( !toShow.length ) {
+ return toHide.animate( hideProps, duration, easing, complete );
+ }
+
+ total = toShow.show().outerHeight();
+ toHide.animate( hideProps, {
+ duration: duration,
+ easing: easing,
+ step: function( now, fx ) {
+ fx.now = Math.round( now );
+ }
+ });
+ toShow
+ .hide()
+ .animate( showProps, {
+ duration: duration,
+ easing: easing,
+ complete: complete,
+ step: function( now, fx ) {
+ fx.now = Math.round( now );
+ if ( fx.prop !== "height" ) {
+ adjust += fx.now;
+ } else if ( that.options.heightStyle !== "content" ) {
+ fx.now = Math.round( total - toHide.outerHeight() - adjust );
+ adjust = 0;
+ }
+ }
+ });
+ },
+
+ _toggleComplete: function( data ) {
+ var toHide = data.oldPanel;
+
+ toHide
+ .removeClass( "ui-accordion-content-active" )
+ .prev()
+ .removeClass( "ui-corner-top" )
+ .addClass( "ui-corner-all" );
+
+ // Work around for rendering bug in IE (#5421)
+ if ( toHide.length ) {
+ toHide.parent()[0].className = toHide.parent()[0].className;
+ }
+
+ this._trigger( "activate", null, data );
+ }
+});
+
+})( jQuery );
+
+(function( $, undefined ) {
+
+// used to prevent race conditions with remote data sources
+var requestIndex = 0;
+
+$.widget( "ui.autocomplete", {
+ version: "1.10.3",
+ defaultElement: "<input>",
+ options: {
+ appendTo: null,
+ autoFocus: false,
+ delay: 300,
+ minLength: 1,
+ position: {
+ my: "left top",
+ at: "left bottom",
+ collision: "none"
+ },
+ source: null,
+
+ // callbacks
+ change: null,
+ close: null,
+ focus: null,
+ open: null,
+ response: null,
+ search: null,
+ select: null
+ },
+
+ pending: 0,
+
+ _create: function() {
+ // Some browsers only repeat keydown events, not keypress events,
+ // so we use the suppressKeyPress flag to determine if we've already
+ // handled the keydown event. #7269
+ // Unfortunately the code for & in keypress is the same as the up arrow,
+ // so we use the suppressKeyPressRepeat flag to avoid handling keypress
+ // events when we know the keydown event was used to modify the
+ // search term. #7799
+ var suppressKeyPress, suppressKeyPressRepeat, suppressInput,
+ nodeName = this.element[0].nodeName.toLowerCase(),
+ isTextarea = nodeName === "textarea",
+ isInput = nodeName === "input";
+
+ this.isMultiLine =
+ // Textareas are always multi-line
+ isTextarea ? true :
+ // Inputs are always single-line, even if inside a contentEditable element
+ // IE also treats inputs as contentEditable
+ isInput ? false :
+ // All other element types are determined by whether or not they're contentEditable
+ this.element.prop( "isContentEditable" );
+
+ this.valueMethod = this.element[ isTextarea || isInput ? "val" : "text" ];
+ this.isNewMenu = true;
+
+ this.element
+ .addClass( "ui-autocomplete-input" )
+ .attr( "autocomplete", "off" );
+
+ this._on( this.element, {
+ keydown: function( event ) {
+ /*jshint maxcomplexity:15*/
+ if ( this.element.prop( "readOnly" ) ) {
+ suppressKeyPress = true;
+ suppressInput = true;
+ suppressKeyPressRepeat = true;
+ return;
+ }
+
+ suppressKeyPress = false;
+ suppressInput = false;
+ suppressKeyPressRepeat = false;
+ var keyCode = $.ui.keyCode;
+ switch( event.keyCode ) {
+ case keyCode.PAGE_UP:
+ suppressKeyPress = true;
+ this._move( "previousPage", event );
+ break;
+ case keyCode.PAGE_DOWN:
+ suppressKeyPress = true;
+ this._move( "nextPage", event );
+ break;
+ case keyCode.UP:
+ suppressKeyPress = true;
+ this._keyEvent( "previous", event );
+ break;
+ case keyCode.DOWN:
+ suppressKeyPress = true;
+ this._keyEvent( "next", event );
+ break;
+ case keyCode.ENTER:
+ case keyCode.NUMPAD_ENTER:
+ // when menu is open and has focus
+ if ( this.menu.active ) {
+ // #6055 - Opera still allows the keypress to occur
+ // which causes forms to submit
+ suppressKeyPress = true;
+ event.preventDefault();
+ this.menu.select( event );
+ }
+ break;
+ case keyCode.TAB:
+ if ( this.menu.active ) {
+ this.menu.select( event );
+ }
+ break;
+ case keyCode.ESCAPE:
+ if ( this.menu.element.is( ":visible" ) ) {
+ this._value( this.term );
+ this.close( event );
+ // Different browsers have different default behavior for escape
+ // Single press can mean undo or clear
+ // Double press in IE means clear the whole form
+ event.preventDefault();
+ }
+ break;
+ default:
+ suppressKeyPressRepeat = true;
+ // search timeout should be triggered before the input value is changed
+ this._searchTimeout( event );
+ break;
+ }
+ },
+ keypress: function( event ) {
+ if ( suppressKeyPress ) {
+ suppressKeyPress = false;
+ if ( !this.isMultiLine || this.menu.element.is( ":visible" ) ) {
+ event.preventDefault();
+ }
+ return;
+ }
+ if ( suppressKeyPressRepeat ) {
+ return;
+ }
+
+ // replicate some key handlers to allow them to repeat in Firefox and Opera
+ var keyCode = $.ui.keyCode;
+ switch( event.keyCode ) {
+ case keyCode.PAGE_UP:
+ this._move( "previousPage", event );
+ break;
+ case keyCode.PAGE_DOWN:
+ this._move( "nextPage", event );
+ break;
+ case keyCode.UP:
+ this._keyEvent( "previous", event );
+ break;
+ case keyCode.DOWN:
+ this._keyEvent( "next", event );
+ break;
+ }
+ },
+ input: function( event ) {
+ if ( suppressInput ) {
+ suppressInput = false;
+ event.preventDefault();
+ return;
+ }
+ this._searchTimeout( event );
+ },
+ focus: function() {
+ this.selectedItem = null;
+ this.previous = this._value();
+ },
+ blur: function( event ) {
+ if ( this.cancelBlur ) {
+ delete this.cancelBlur;
+ return;
+ }
+
+ clearTimeout( this.searching );
+ this.close( event );
+ this._change( event );
+ }
+ });
+
+ this._initSource();
+ this.menu = $( "<ul>" )
+ .addClass( "ui-autocomplete ui-front" )
+ .appendTo( this._appendTo() )
+ .menu({
+ // disable ARIA support, the live region takes care of that
+ role: null
+ })
+ .hide()
+ .data( "ui-menu" );
+
+ this._on( this.menu.element, {
+ mousedown: function( event ) {
+ // prevent moving focus out of the text field
+ event.preventDefault();
+
+ // IE doesn't prevent moving focus even with event.preventDefault()
+ // so we set a flag to know when we should ignore the blur event
+ this.cancelBlur = true;
+ this._delay(function() {
+ delete this.cancelBlur;
+ });
+
+ // clicking on the scrollbar causes focus to shift to the body
+ // but we can't detect a mouseup or a click immediately afterward
+ // so we have to track the next mousedown and close the menu if
+ // the user clicks somewhere outside of the autocomplete
+ var menuElement = this.menu.element[ 0 ];
+ if ( !$( event.target ).closest( ".ui-menu-item" ).length ) {
+ this._delay(function() {
+ var that = this;
+ this.document.one( "mousedown", function( event ) {
+ if ( event.target !== that.element[ 0 ] &&
+ event.target !== menuElement &&
+ !$.contains( menuElement, event.target ) ) {
+ that.close();
+ }
+ });
+ });
+ }
+ },
+ menufocus: function( event, ui ) {
+ // support: Firefox
+ // Prevent accidental activation of menu items in Firefox (#7024 #9118)
+ if ( this.isNewMenu ) {
+ this.isNewMenu = false;
+ if ( event.originalEvent && /^mouse/.test( event.originalEvent.type ) ) {
+ this.menu.blur();
+
+ this.document.one( "mousemove", function() {
+ $( event.target ).trigger( event.originalEvent );
+ });
+
+ return;
+ }
+ }
+
+ var item = ui.item.data( "ui-autocomplete-item" );
+ if ( false !== this._trigger( "focus", event, { item: item } ) ) {
+ // use value to match what will end up in the input, if it was a key event
+ if ( event.originalEvent && /^key/.test( event.originalEvent.type ) ) {
+ this._value( item.value );
+ }
+ } else {
+ // Normally the input is populated with the item's value as the
+ // menu is navigated, causing screen readers to notice a change and
+ // announce the item. Since the focus event was canceled, this doesn't
+ // happen, so we update the live region so that screen readers can
+ // still notice the change and announce it.
+ this.liveRegion.text( item.value );
+ }
+ },
+ menuselect: function( event, ui ) {
+ var item = ui.item.data( "ui-autocomplete-item" ),
+ previous = this.previous;
+
+ // only trigger when focus was lost (click on menu)
+ if ( this.element[0] !== this.document[0].activeElement ) {
+ this.element.focus();
+ this.previous = previous;
+ // #6109 - IE triggers two focus events and the second
+ // is asynchronous, so we need to reset the previous
+ // term synchronously and asynchronously :-(
+ this._delay(function() {
+ this.previous = previous;
+ this.selectedItem = item;
+ });
+ }
+
+ if ( false !== this._trigger( "select", event, { item: item } ) ) {
+ this._value( item.value );
+ }
+ // reset the term after the select event
+ // this allows custom select handling to work properly
+ this.term = this._value();
+
+ this.close( event );
+ this.selectedItem = item;
+ }
+ });
+
+ this.liveRegion = $( "<span>", {
+ role: "status",
+ "aria-live": "polite"
+ })
+ .addClass( "ui-helper-hidden-accessible" )
+ .insertBefore( this.element );
+
+ // turning off autocomplete prevents the browser from remembering the
+ // value when navigating through history, so we re-enable autocomplete
+ // if the page is unloaded before the widget is destroyed. #7790
+ this._on( this.window, {
+ beforeunload: function() {
+ this.element.removeAttr( "autocomplete" );
+ }
+ });
+ },
+
+ _destroy: function() {
+ clearTimeout( this.searching );
+ this.element
+ .removeClass( "ui-autocomplete-input" )
+ .removeAttr( "autocomplete" );
+ this.menu.element.remove();
+ this.liveRegion.remove();
+ },
+
+ _setOption: function( key, value ) {
+ this._super( key, value );
+ if ( key === "source" ) {
+ this._initSource();
+ }
+ if ( key === "appendTo" ) {
+ this.menu.element.appendTo( this._appendTo() );
+ }
+ if ( key === "disabled" && value && this.xhr ) {
+ this.xhr.abort();
+ }
+ },
+
+ _appendTo: function() {
+ var element = this.options.appendTo;
+
+ if ( element ) {
+ element = element.jquery || element.nodeType ?
+ $( element ) :
+ this.document.find( element ).eq( 0 );
+ }
+
+ if ( !element ) {
+ element = this.element.closest( ".ui-front" );
+ }
+
+ if ( !element.length ) {
+ element = this.document[0].body;
+ }
+
+ return element;
+ },
+
+ _initSource: function() {
+ var array, url,
+ that = this;
+ if ( $.isArray(this.options.source) ) {
+ array = this.options.source;
+ this.source = function( request, response ) {
+ response( $.ui.autocomplete.filter( array, request.term ) );
+ };
+ } else if ( typeof this.options.source === "string" ) {
+ url = this.options.source;
+ this.source = function( request, response ) {
+ if ( that.xhr ) {
+ that.xhr.abort();
+ }
+ that.xhr = $.ajax({
+ url: url,
+ data: request,
+ dataType: "json",
+ success: function( data ) {
+ response( data );
+ },
+ error: function() {
+ response( [] );
+ }
+ });
+ };
+ } else {
+ this.source = this.options.source;
+ }
+ },
+
+ _searchTimeout: function( event ) {
+ clearTimeout( this.searching );
+ this.searching = this._delay(function() {
+ // only search if the value has changed
+ if ( this.term !== this._value() ) {
+ this.selectedItem = null;
+ this.search( null, event );
+ }
+ }, this.options.delay );
+ },
+
+ search: function( value, event ) {
+ value = value != null ? value : this._value();
+
+ // always save the actual value, not the one passed as an argument
+ this.term = this._value();
+
+ if ( value.length < this.options.minLength ) {
+ return this.close( event );
+ }
+
+ if ( this._trigger( "search", event ) === false ) {
+ return;
+ }
+
+ return this._search( value );
+ },
+
+ _search: function( value ) {
+ this.pending++;
+ this.element.addClass( "ui-autocomplete-loading" );
+ this.cancelSearch = false;
+
+ this.source( { term: value }, this._response() );
+ },
+
+ _response: function() {
+ var that = this,
+ index = ++requestIndex;
+
+ return function( content ) {
+ if ( index === requestIndex ) {
+ that.__response( content );
+ }
+
+ that.pending--;
+ if ( !that.pending ) {
+ that.element.removeClass( "ui-autocomplete-loading" );
+ }
+ };
+ },
+
+ __response: function( content ) {
+ if ( content ) {
+ content = this._normalize( content );
+ }
+ this._trigger( "response", null, { content: content } );
+ if ( !this.options.disabled && content && content.length && !this.cancelSearch ) {
+ this._suggest( content );
+ this._trigger( "open" );
+ } else {
+ // use ._close() instead of .close() so we don't cancel future searches
+ this._close();
+ }
+ },
+
+ close: function( event ) {
+ this.cancelSearch = true;
+ this._close( event );
+ },
+
+ _close: function( event ) {
+ if ( this.menu.element.is( ":visible" ) ) {
+ this.menu.element.hide();
+ this.menu.blur();
+ this.isNewMenu = true;
+ this._trigger( "close", event );
+ }
+ },
+
+ _change: function( event ) {
+ if ( this.previous !== this._value() ) {
+ this._trigger( "change", event, { item: this.selectedItem } );
+ }
+ },
+
+ _normalize: function( items ) {
+ // assume all items have the right format when the first item is complete
+ if ( items.length && items[0].label && items[0].value ) {
+ return items;
+ }
+ return $.map( items, function( item ) {
+ if ( typeof item === "string" ) {
+ return {
+ label: item,
+ value: item
+ };
+ }
+ return $.extend({
+ label: item.label || item.value,
+ value: item.value || item.label
+ }, item );
+ });
+ },
+
+ _suggest: function( items ) {
+ var ul = this.menu.element.empty();
+ this._renderMenu( ul, items );
+ this.isNewMenu = true;
+ this.menu.refresh();
+
+ // size and position menu
+ ul.show();
+ this._resizeMenu();
+ ul.position( $.extend({
+ of: this.element
+ }, this.options.position ));
+
+ if ( this.options.autoFocus ) {
+ this.menu.next();
+ }
+ },
+
+ _resizeMenu: function() {
+ var ul = this.menu.element;
+ ul.outerWidth( Math.max(
+ // Firefox wraps long text (possibly a rounding bug)
+ // so we add 1px to avoid the wrapping (#7513)
+ ul.width( "" ).outerWidth() + 1,
+ this.element.outerWidth()
+ ) );
+ },
+
+ _renderMenu: function( ul, items ) {
+ var that = this;
+ $.each( items, function( index, item ) {
+ that._renderItemData( ul, item );
+ });
+ },
+
+ _renderItemData: function( ul, item ) {
+ return this._renderItem( ul, item ).data( "ui-autocomplete-item", item );
+ },
+
+ _renderItem: function( ul, item ) {
+ return $( "<li>" )
+ .append( $( "<a>" ).text( item.label ) )
+ .appendTo( ul );
+ },
+
+ _move: function( direction, event ) {
+ if ( !this.menu.element.is( ":visible" ) ) {
+ this.search( null, event );
+ return;
+ }
+ if ( this.menu.isFirstItem() && /^previous/.test( direction ) ||
+ this.menu.isLastItem() && /^next/.test( direction ) ) {
+ this._value( this.term );
+ this.menu.blur();
+ return;
+ }
+ this.menu[ direction ]( event );
+ },
+
+ widget: function() {
+ return this.menu.element;
+ },
+
+ _value: function() {
+ return this.valueMethod.apply( this.element, arguments );
+ },
+
+ _keyEvent: function( keyEvent, event ) {
+ if ( !this.isMultiLine || this.menu.element.is( ":visible" ) ) {
+ this._move( keyEvent, event );
+
+ // prevents moving cursor to beginning/end of the text field in some browsers
+ event.preventDefault();
+ }
+ }
+});
+
+$.extend( $.ui.autocomplete, {
+ escapeRegex: function( value ) {
+ return value.replace(/[\-\[\]{}()*+?.,\\\^$|#\s]/g, "\\$&");
+ },
+ filter: function(array, term) {
+ var matcher = new RegExp( $.ui.autocomplete.escapeRegex(term), "i" );
+ return $.grep( array, function(value) {
+ return matcher.test( value.label || value.value || value );
+ });
+ }
+});
+
+
+// live region extension, adding a `messages` option
+// NOTE: This is an experimental API. We are still investigating
+// a full solution for string manipulation and internationalization.
+$.widget( "ui.autocomplete", $.ui.autocomplete, {
+ options: {
+ messages: {
+ noResults: "No search results.",
+ results: function( amount ) {
+ return amount + ( amount > 1 ? " results are" : " result is" ) +
+ " available, use up and down arrow keys to navigate.";
+ }
+ }
+ },
+
+ __response: function( content ) {
+ var message;
+ this._superApply( arguments );
+ if ( this.options.disabled || this.cancelSearch ) {
+ return;
+ }
+ if ( content && content.length ) {
+ message = this.options.messages.results( content.length );
+ } else {
+ message = this.options.messages.noResults;
+ }
+ this.liveRegion.text( message );
+ }
+});
+
+}( jQuery ));
+
+(function( $, undefined ) {
+
+var lastActive, startXPos, startYPos, clickDragged,
+ baseClasses = "ui-button ui-widget ui-state-default ui-corner-all",
+ stateClasses = "ui-state-hover ui-state-active ",
+ typeClasses = "ui-button-icons-only ui-button-icon-only ui-button-text-icons ui-button-text-icon-primary ui-button-text-icon-secondary ui-button-text-only",
+ formResetHandler = function() {
+ var form = $( this );
+ setTimeout(function() {
+ form.find( ":ui-button" ).button( "refresh" );
+ }, 1 );
+ },
+ radioGroup = function( radio ) {
+ var name = radio.name,
+ form = radio.form,
+ radios = $( [] );
+ if ( name ) {
+ name = name.replace( /'/g, "\\'" );
+ if ( form ) {
+ radios = $( form ).find( "[name='" + name + "']" );
+ } else {
+ radios = $( "[name='" + name + "']", radio.ownerDocument )
+ .filter(function() {
+ return !this.form;
+ });
+ }
+ }
+ return radios;
+ };
+
+$.widget( "ui.button", {
+ version: "1.10.3",
+ defaultElement: "<button>",
+ options: {
+ disabled: null,
+ text: true,
+ label: null,
+ icons: {
+ primary: null,
+ secondary: null
+ }
+ },
+ _create: function() {
+ this.element.closest( "form" )
+ .unbind( "reset" + this.eventNamespace )
+ .bind( "reset" + this.eventNamespace, formResetHandler );
+
+ if ( typeof this.options.disabled !== "boolean" ) {
+ this.options.disabled = !!this.element.prop( "disabled" );
+ } else {
+ this.element.prop( "disabled", this.options.disabled );
+ }
+
+ this._determineButtonType();
+ this.hasTitle = !!this.buttonElement.attr( "title" );
+
+ var that = this,
+ options = this.options,
+ toggleButton = this.type === "checkbox" || this.type === "radio",
+ activeClass = !toggleButton ? "ui-state-active" : "",
+ focusClass = "ui-state-focus";
+
+ if ( options.label === null ) {
+ options.label = (this.type === "input" ? this.buttonElement.val() : this.buttonElement.html());
+ }
+
+ this._hoverable( this.buttonElement );
+
+ this.buttonElement
+ .addClass( baseClasses )
+ .attr( "role", "button" )
+ .bind( "mouseenter" + this.eventNamespace, function() {
+ if ( options.disabled ) {
+ return;
+ }
+ if ( this === lastActive ) {
+ $( this ).addClass( "ui-state-active" );
+ }
+ })
+ .bind( "mouseleave" + this.eventNamespace, function() {
+ if ( options.disabled ) {
+ return;
+ }
+ $( this ).removeClass( activeClass );
+ })
+ .bind( "click" + this.eventNamespace, function( event ) {
+ if ( options.disabled ) {
+ event.preventDefault();
+ event.stopImmediatePropagation();
+ }
+ });
+
+ this.element
+ .bind( "focus" + this.eventNamespace, function() {
+ // no need to check disabled, focus won't be triggered anyway
+ that.buttonElement.addClass( focusClass );
+ })
+ .bind( "blur" + this.eventNamespace, function() {
+ that.buttonElement.removeClass( focusClass );
+ });
+
+ if ( toggleButton ) {
+ this.element.bind( "change" + this.eventNamespace, function() {
+ if ( clickDragged ) {
+ return;
+ }
+ that.refresh();
+ });
+ // if mouse moves between mousedown and mouseup (drag) set clickDragged flag
+ // prevents issue where button state changes but checkbox/radio checked state
+ // does not in Firefox (see ticket #6970)
+ this.buttonElement
+ .bind( "mousedown" + this.eventNamespace, function( event ) {
+ if ( options.disabled ) {
+ return;
+ }
+ clickDragged = false;
+ startXPos = event.pageX;
+ startYPos = event.pageY;
+ })
+ .bind( "mouseup" + this.eventNamespace, function( event ) {
+ if ( options.disabled ) {
+ return;
+ }
+ if ( startXPos !== event.pageX || startYPos !== event.pageY ) {
+ clickDragged = true;
+ }
+ });
+ }
+
+ if ( this.type === "checkbox" ) {
+ this.buttonElement.bind( "click" + this.eventNamespace, function() {
+ if ( options.disabled || clickDragged ) {
+ return false;
+ }
+ });
+ } else if ( this.type === "radio" ) {
+ this.buttonElement.bind( "click" + this.eventNamespace, function() {
+ if ( options.disabled || clickDragged ) {
+ return false;
+ }
+ $( this ).addClass( "ui-state-active" );
+ that.buttonElement.attr( "aria-pressed", "true" );
+
+ var radio = that.element[ 0 ];
+ radioGroup( radio )
+ .not( radio )
+ .map(function() {
+ return $( this ).button( "widget" )[ 0 ];
+ })
+ .removeClass( "ui-state-active" )
+ .attr( "aria-pressed", "false" );
+ });
+ } else {
+ this.buttonElement
+ .bind( "mousedown" + this.eventNamespace, function() {
+ if ( options.disabled ) {
+ return false;
+ }
+ $( this ).addClass( "ui-state-active" );
+ lastActive = this;
+ that.document.one( "mouseup", function() {
+ lastActive = null;
+ });
+ })
+ .bind( "mouseup" + this.eventNamespace, function() {
+ if ( options.disabled ) {
+ return false;
+ }
+ $( this ).removeClass( "ui-state-active" );
+ })
+ .bind( "keydown" + this.eventNamespace, function(event) {
+ if ( options.disabled ) {
+ return false;
+ }
+ if ( event.keyCode === $.ui.keyCode.SPACE || event.keyCode === $.ui.keyCode.ENTER ) {
+ $( this ).addClass( "ui-state-active" );
+ }
+ })
+ // see #8559, we bind to blur here in case the button element loses
+ // focus between keydown and keyup, it would be left in an "active" state
+ .bind( "keyup" + this.eventNamespace + " blur" + this.eventNamespace, function() {
+ $( this ).removeClass( "ui-state-active" );
+ });
+
+ if ( this.buttonElement.is("a") ) {
+ this.buttonElement.keyup(function(event) {
+ if ( event.keyCode === $.ui.keyCode.SPACE ) {
+ // TODO pass through original event correctly (just as 2nd argument doesn't work)
+ $( this ).click();
+ }
+ });
+ }
+ }
+
+ // TODO: pull out $.Widget's handling for the disabled option into
+ // $.Widget.prototype._setOptionDisabled so it's easy to proxy and can
+ // be overridden by individual plugins
+ this._setOption( "disabled", options.disabled );
+ this._resetButton();
+ },
+
+ _determineButtonType: function() {
+ var ancestor, labelSelector, checked;
+
+ if ( this.element.is("[type=checkbox]") ) {
+ this.type = "checkbox";
+ } else if ( this.element.is("[type=radio]") ) {
+ this.type = "radio";
+ } else if ( this.element.is("input") ) {
+ this.type = "input";
+ } else {
+ this.type = "button";
+ }
+
+ if ( this.type === "checkbox" || this.type === "radio" ) {
+ // we don't search against the document in case the element
+ // is disconnected from the DOM
+ ancestor = this.element.parents().last();
+ labelSelector = "label[for='" + this.element.attr("id") + "']";
+ this.buttonElement = ancestor.find( labelSelector );
+ if ( !this.buttonElement.length ) {
+ ancestor = ancestor.length ? ancestor.siblings() : this.element.siblings();
+ this.buttonElement = ancestor.filter( labelSelector );
+ if ( !this.buttonElement.length ) {
+ this.buttonElement = ancestor.find( labelSelector );
+ }
+ }
+ this.element.addClass( "ui-helper-hidden-accessible" );
+
+ checked = this.element.is( ":checked" );
+ if ( checked ) {
+ this.buttonElement.addClass( "ui-state-active" );
+ }
+ this.buttonElement.prop( "aria-pressed", checked );
+ } else {
+ this.buttonElement = this.element;
+ }
+ },
+
+ widget: function() {
+ return this.buttonElement;
+ },
+
+ _destroy: function() {
+ this.element
+ .removeClass( "ui-helper-hidden-accessible" );
+ this.buttonElement
+ .removeClass( baseClasses + " " + stateClasses + " " + typeClasses )
+ .removeAttr( "role" )
+ .removeAttr( "aria-pressed" )
+ .html( this.buttonElement.find(".ui-button-text").html() );
+
+ if ( !this.hasTitle ) {
+ this.buttonElement.removeAttr( "title" );
+ }
+ },
+
+ _setOption: function( key, value ) {
+ this._super( key, value );
+ if ( key === "disabled" ) {
+ if ( value ) {
+ this.element.prop( "disabled", true );
+ } else {
+ this.element.prop( "disabled", false );
+ }
+ return;
+ }
+ this._resetButton();
+ },
+
+ refresh: function() {
+ //See #8237 & #8828
+ var isDisabled = this.element.is( "input, button" ) ? this.element.is( ":disabled" ) : this.element.hasClass( "ui-button-disabled" );
+
+ if ( isDisabled !== this.options.disabled ) {
+ this._setOption( "disabled", isDisabled );
+ }
+ if ( this.type === "radio" ) {
+ radioGroup( this.element[0] ).each(function() {
+ if ( $( this ).is( ":checked" ) ) {
+ $( this ).button( "widget" )
+ .addClass( "ui-state-active" )
+ .attr( "aria-pressed", "true" );
+ } else {
+ $( this ).button( "widget" )
+ .removeClass( "ui-state-active" )
+ .attr( "aria-pressed", "false" );
+ }
+ });
+ } else if ( this.type === "checkbox" ) {
+ if ( this.element.is( ":checked" ) ) {
+ this.buttonElement
+ .addClass( "ui-state-active" )
+ .attr( "aria-pressed", "true" );
+ } else {
+ this.buttonElement
+ .removeClass( "ui-state-active" )
+ .attr( "aria-pressed", "false" );
+ }
+ }
+ },
+
+ _resetButton: function() {
+ if ( this.type === "input" ) {
+ if ( this.options.label ) {
+ this.element.val( this.options.label );
+ }
+ return;
+ }
+ var buttonElement = this.buttonElement.removeClass( typeClasses ),
+ buttonText = $( "<span></span>", this.document[0] )
+ .addClass( "ui-button-text" )
+ .html( this.options.label )
+ .appendTo( buttonElement.empty() )
+ .text(),
+ icons = this.options.icons,
+ multipleIcons = icons.primary && icons.secondary,
+ buttonClasses = [];
+
+ if ( icons.primary || icons.secondary ) {
+ if ( this.options.text ) {
+ buttonClasses.push( "ui-button-text-icon" + ( multipleIcons ? "s" : ( icons.primary ? "-primary" : "-secondary" ) ) );
+ }
+
+ if ( icons.primary ) {
+ buttonElement.prepend( "<span class='ui-button-icon-primary ui-icon " + icons.primary + "'></span>" );
+ }
+
+ if ( icons.secondary ) {
+ buttonElement.append( "<span class='ui-button-icon-secondary ui-icon " + icons.secondary + "'></span>" );
+ }
+
+ if ( !this.options.text ) {
+ buttonClasses.push( multipleIcons ? "ui-button-icons-only" : "ui-button-icon-only" );
+
+ if ( !this.hasTitle ) {
+ buttonElement.attr( "title", $.trim( buttonText ) );
+ }
+ }
+ } else {
+ buttonClasses.push( "ui-button-text-only" );
+ }
+ buttonElement.addClass( buttonClasses.join( " " ) );
+ }
+});
+
+$.widget( "ui.buttonset", {
+ version: "1.10.3",
+ options: {
+ items: "button, input[type=button], input[type=submit], input[type=reset], input[type=checkbox], input[type=radio], a, :data(ui-button)"
+ },
+
+ _create: function() {
+ this.element.addClass( "ui-buttonset" );
+ },
+
+ _init: function() {
+ this.refresh();
+ },
+
+ _setOption: function( key, value ) {
+ if ( key === "disabled" ) {
+ this.buttons.button( "option", key, value );
+ }
+
+ this._super( key, value );
+ },
+
+ refresh: function() {
+ var rtl = this.element.css( "direction" ) === "rtl";
+
+ this.buttons = this.element.find( this.options.items )
+ .filter( ":ui-button" )
+ .button( "refresh" )
+ .end()
+ .not( ":ui-button" )
+ .button()
+ .end()
+ .map(function() {
+ return $( this ).button( "widget" )[ 0 ];
+ })
+ .removeClass( "ui-corner-all ui-corner-left ui-corner-right" )
+ .filter( ":first" )
+ .addClass( rtl ? "ui-corner-right" : "ui-corner-left" )
+ .end()
+ .filter( ":last" )
+ .addClass( rtl ? "ui-corner-left" : "ui-corner-right" )
+ .end()
+ .end();
+ },
+
+ _destroy: function() {
+ this.element.removeClass( "ui-buttonset" );
+ this.buttons
+ .map(function() {
+ return $( this ).button( "widget" )[ 0 ];
+ })
+ .removeClass( "ui-corner-left ui-corner-right" )
+ .end()
+ .button( "destroy" );
+ }
+});
+
+}( jQuery ) );
+
+(function( $, undefined ) {
+
+$.extend($.ui, { datepicker: { version: "1.10.3" } });
+
+var PROP_NAME = "datepicker",
+ instActive;
+
+/* Date picker manager.
+ Use the singleton instance of this class, $.datepicker, to interact with the date picker.
+ Settings for (groups of) date pickers are maintained in an instance object,
+ allowing multiple different settings on the same page. */
+
+function Datepicker() {
+ this._curInst = null; // The current instance in use
+ this._keyEvent = false; // If the last event was a key event
+ this._disabledInputs = []; // List of date picker inputs that have been disabled
+ this._datepickerShowing = false; // True if the popup picker is showing , false if not
+ this._inDialog = false; // True if showing within a "dialog", false if not
+ this._mainDivId = "ui-datepicker-div"; // The ID of the main datepicker division
+ this._inlineClass = "ui-datepicker-inline"; // The name of the inline marker class
+ this._appendClass = "ui-datepicker-append"; // The name of the append marker class
+ this._triggerClass = "ui-datepicker-trigger"; // The name of the trigger marker class
+ this._dialogClass = "ui-datepicker-dialog"; // The name of the dialog marker class
+ this._disableClass = "ui-datepicker-disabled"; // The name of the disabled covering marker class
+ this._unselectableClass = "ui-datepicker-unselectable"; // The name of the unselectable cell marker class
+ this._currentClass = "ui-datepicker-current-day"; // The name of the current day marker class
+ this._dayOverClass = "ui-datepicker-days-cell-over"; // The name of the day hover marker class
+ this.regional = []; // Available regional settings, indexed by language code
+ this.regional[""] = { // Default regional settings
+ closeText: "Done", // Display text for close link
+ prevText: "Prev", // Display text for previous month link
+ nextText: "Next", // Display text for next month link
+ currentText: "Today", // Display text for current month link
+ monthNames: ["January","February","March","April","May","June",
+ "July","August","September","October","November","December"], // Names of months for drop-down and formatting
+ monthNamesShort: ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"], // For formatting
+ dayNames: ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"], // For formatting
+ dayNamesShort: ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"], // For formatting
+ dayNamesMin: ["Su","Mo","Tu","We","Th","Fr","Sa"], // Column headings for days starting at Sunday
+ weekHeader: "Wk", // Column header for week of the year
+ dateFormat: "mm/dd/yy", // See format options on parseDate
+ firstDay: 0, // The first day of the week, Sun = 0, Mon = 1, ...
+ isRTL: false, // True if right-to-left language, false if left-to-right
+ showMonthAfterYear: false, // True if the year select precedes month, false for month then year
+ yearSuffix: "" // Additional text to append to the year in the month headers
+ };
+ this._defaults = { // Global defaults for all the date picker instances
+ showOn: "focus", // "focus" for popup on focus,
+ // "button" for trigger button, or "both" for either
+ showAnim: "fadeIn", // Name of jQuery animation for popup
+ showOptions: {}, // Options for enhanced animations
+ defaultDate: null, // Used when field is blank: actual date,
+ // +/-number for offset from today, null for today
+ appendText: "", // Display text following the input box, e.g. showing the format
+ buttonText: "...", // Text for trigger button
+ buttonImage: "", // URL for trigger button image
+ buttonImageOnly: false, // True if the image appears alone, false if it appears on a button
+ hideIfNoPrevNext: false, // True to hide next/previous month links
+ // if not applicable, false to just disable them
+ navigationAsDateFormat: false, // True if date formatting applied to prev/today/next links
+ gotoCurrent: false, // True if today link goes back to current selection instead
+ changeMonth: false, // True if month can be selected directly, false if only prev/next
+ changeYear: false, // True if year can be selected directly, false if only prev/next
+ yearRange: "c-10:c+10", // Range of years to display in drop-down,
+ // either relative to today's year (-nn:+nn), relative to currently displayed year
+ // (c-nn:c+nn), absolute (nnnn:nnnn), or a combination of the above (nnnn:-n)
+ showOtherMonths: false, // True to show dates in other months, false to leave blank
+ selectOtherMonths: false, // True to allow selection of dates in other months, false for unselectable
+ showWeek: false, // True to show week of the year, false to not show it
+ calculateWeek: this.iso8601Week, // How to calculate the week of the year,
+ // takes a Date and returns the number of the week for it
+ shortYearCutoff: "+10", // Short year values < this are in the current century,
+ // > this are in the previous century,
+ // string value starting with "+" for current year + value
+ minDate: null, // The earliest selectable date, or null for no limit
+ maxDate: null, // The latest selectable date, or null for no limit
+ duration: "fast", // Duration of display/closure
+ beforeShowDay: null, // Function that takes a date and returns an array with
+ // [0] = true if selectable, false if not, [1] = custom CSS class name(s) or "",
+ // [2] = cell title (optional), e.g. $.datepicker.noWeekends
+ beforeShow: null, // Function that takes an input field and
+ // returns a set of custom settings for the date picker
+ onSelect: null, // Define a callback function when a date is selected
+ onChangeMonthYear: null, // Define a callback function when the month or year is changed
+ onClose: null, // Define a callback function when the datepicker is closed
+ numberOfMonths: 1, // Number of months to show at a time
+ showCurrentAtPos: 0, // The position in multipe months at which to show the current month (starting at 0)
+ stepMonths: 1, // Number of months to step back/forward
+ stepBigMonths: 12, // Number of months to step back/forward for the big links
+ altField: "", // Selector for an alternate field to store selected dates into
+ altFormat: "", // The date format to use for the alternate field
+ constrainInput: true, // The input is constrained by the current date format
+ showButtonPanel: false, // True to show button panel, false to not show it
+ autoSize: false, // True to size the input for the date format, false to leave as is
+ disabled: false // The initial disabled state
+ };
+ $.extend(this._defaults, this.regional[""]);
+ this.dpDiv = bindHover($("<div id='" + this._mainDivId + "' class='ui-datepicker ui-widget ui-widget-content ui-helper-clearfix ui-corner-all'></div>"));
+}
+
+$.extend(Datepicker.prototype, {
+ /* Class name added to elements to indicate already configured with a date picker. */
+ markerClassName: "hasDatepicker",
+
+ //Keep track of the maximum number of rows displayed (see #7043)
+ maxRows: 4,
+
+ // TODO rename to "widget" when switching to widget factory
+ _widgetDatepicker: function() {
+ return this.dpDiv;
+ },
+
+ /* Override the default settings for all instances of the date picker.
+ * @param settings object - the new settings to use as defaults (anonymous object)
+ * @return the manager object
+ */
+ setDefaults: function(settings) {
+ extendRemove(this._defaults, settings || {});
+ return this;
+ },
+
+ /* Attach the date picker to a jQuery selection.
+ * @param target element - the target input field or division or span
+ * @param settings object - the new settings to use for this date picker instance (anonymous)
+ */
+ _attachDatepicker: function(target, settings) {
+ var nodeName, inline, inst;
+ nodeName = target.nodeName.toLowerCase();
+ inline = (nodeName === "div" || nodeName === "span");
+ if (!target.id) {
+ this.uuid += 1;
+ target.id = "dp" + this.uuid;
+ }
+ inst = this._newInst($(target), inline);
+ inst.settings = $.extend({}, settings || {});
+ if (nodeName === "input") {
+ this._connectDatepicker(target, inst);
+ } else if (inline) {
+ this._inlineDatepicker(target, inst);
+ }
+ },
+
+ /* Create a new instance object. */
+ _newInst: function(target, inline) {
+ var id = target[0].id.replace(/([^A-Za-z0-9_\-])/g, "\\\\$1"); // escape jQuery meta chars
+ return {id: id, input: target, // associated target
+ selectedDay: 0, selectedMonth: 0, selectedYear: 0, // current selection
+ drawMonth: 0, drawYear: 0, // month being drawn
+ inline: inline, // is datepicker inline or not
+ dpDiv: (!inline ? this.dpDiv : // presentation div
+ bindHover($("<div class='" + this._inlineClass + " ui-datepicker ui-widget ui-widget-content ui-helper-clearfix ui-corner-all'></div>")))};
+ },
+
+ /* Attach the date picker to an input field. */
+ _connectDatepicker: function(target, inst) {
+ var input = $(target);
+ inst.append = $([]);
+ inst.trigger = $([]);
+ if (input.hasClass(this.markerClassName)) {
+ return;
+ }
+ this._attachments(input, inst);
+ input.addClass(this.markerClassName).keydown(this._doKeyDown).
+ keypress(this._doKeyPress).keyup(this._doKeyUp);
+ this._autoSize(inst);
+ $.data(target, PROP_NAME, inst);
+ //If disabled option is true, disable the datepicker once it has been attached to the input (see ticket #5665)
+ if( inst.settings.disabled ) {
+ this._disableDatepicker( target );
+ }
+ },
+
+ /* Make attachments based on settings. */
+ _attachments: function(input, inst) {
+ var showOn, buttonText, buttonImage,
+ appendText = this._get(inst, "appendText"),
+ isRTL = this._get(inst, "isRTL");
+
+ if (inst.append) {
+ inst.append.remove();
+ }
+ if (appendText) {
+ inst.append = $("<span class='" + this._appendClass + "'>" + appendText + "</span>");
+ input[isRTL ? "before" : "after"](inst.append);
+ }
+
+ input.unbind("focus", this._showDatepicker);
+
+ if (inst.trigger) {
+ inst.trigger.remove();
+ }
+
+ showOn = this._get(inst, "showOn");
+ if (showOn === "focus" || showOn === "both") { // pop-up date picker when in the marked field
+ input.focus(this._showDatepicker);
+ }
+ if (showOn === "button" || showOn === "both") { // pop-up date picker when button clicked
+ buttonText = this._get(inst, "buttonText");
+ buttonImage = this._get(inst, "buttonImage");
+ inst.trigger = $(this._get(inst, "buttonImageOnly") ?
+ $("<img/>").addClass(this._triggerClass).
+ attr({ src: buttonImage, alt: buttonText, title: buttonText }) :
+ $("<button type='button'></button>").addClass(this._triggerClass).
+ html(!buttonImage ? buttonText : $("<img/>").attr(
+ { src:buttonImage, alt:buttonText, title:buttonText })));
+ input[isRTL ? "before" : "after"](inst.trigger);
+ inst.trigger.click(function() {
+ if ($.datepicker._datepickerShowing && $.datepicker._lastInput === input[0]) {
+ $.datepicker._hideDatepicker();
+ } else if ($.datepicker._datepickerShowing && $.datepicker._lastInput !== input[0]) {
+ $.datepicker._hideDatepicker();
+ $.datepicker._showDatepicker(input[0]);
+ } else {
+ $.datepicker._showDatepicker(input[0]);
+ }
+ return false;
+ });
+ }
+ },
+
+ /* Apply the maximum length for the date format. */
+ _autoSize: function(inst) {
+ if (this._get(inst, "autoSize") && !inst.inline) {
+ var findMax, max, maxI, i,
+ date = new Date(2009, 12 - 1, 20), // Ensure double digits
+ dateFormat = this._get(inst, "dateFormat");
+
+ if (dateFormat.match(/[DM]/)) {
+ findMax = function(names) {
+ max = 0;
+ maxI = 0;
+ for (i = 0; i < names.length; i++) {
+ if (names[i].length > max) {
+ max = names[i].length;
+ maxI = i;
+ }
+ }
+ return maxI;
+ };
+ date.setMonth(findMax(this._get(inst, (dateFormat.match(/MM/) ?
+ "monthNames" : "monthNamesShort"))));
+ date.setDate(findMax(this._get(inst, (dateFormat.match(/DD/) ?
+ "dayNames" : "dayNamesShort"))) + 20 - date.getDay());
+ }
+ inst.input.attr("size", this._formatDate(inst, date).length);
+ }
+ },
+
+ /* Attach an inline date picker to a div. */
+ _inlineDatepicker: function(target, inst) {
+ var divSpan = $(target);
+ if (divSpan.hasClass(this.markerClassName)) {
+ return;
+ }
+ divSpan.addClass(this.markerClassName).append(inst.dpDiv);
+ $.data(target, PROP_NAME, inst);
+ this._setDate(inst, this._getDefaultDate(inst), true);
+ this._updateDatepicker(inst);
+ this._updateAlternate(inst);
+ //If disabled option is true, disable the datepicker before showing it (see ticket #5665)
+ if( inst.settings.disabled ) {
+ this._disableDatepicker( target );
+ }
+ // Set display:block in place of inst.dpDiv.show() which won't work on disconnected elements
+ // http://bugs.jqueryui.com/ticket/7552 - A Datepicker created on a detached div has zero height
+ inst.dpDiv.css( "display", "block" );
+ },
+
+ /* Pop-up the date picker in a "dialog" box.
+ * @param input element - ignored
+ * @param date string or Date - the initial date to display
+ * @param onSelect function - the function to call when a date is selected
+ * @param settings object - update the dialog date picker instance's settings (anonymous object)
+ * @param pos int[2] - coordinates for the dialog's position within the screen or
+ * event - with x/y coordinates or
+ * leave empty for default (screen centre)
+ * @return the manager object
+ */
+ _dialogDatepicker: function(input, date, onSelect, settings, pos) {
+ var id, browserWidth, browserHeight, scrollX, scrollY,
+ inst = this._dialogInst; // internal instance
+
+ if (!inst) {
+ this.uuid += 1;
+ id = "dp" + this.uuid;
+ this._dialogInput = $("<input type='text' id='" + id +
+ "' style='position: absolute; top: -100px; width: 0px;'/>");
+ this._dialogInput.keydown(this._doKeyDown);
+ $("body").append(this._dialogInput);
+ inst = this._dialogInst = this._newInst(this._dialogInput, false);
+ inst.settings = {};
+ $.data(this._dialogInput[0], PROP_NAME, inst);
+ }
+ extendRemove(inst.settings, settings || {});
+ date = (date && date.constructor === Date ? this._formatDate(inst, date) : date);
+ this._dialogInput.val(date);
+
+ this._pos = (pos ? (pos.length ? pos : [pos.pageX, pos.pageY]) : null);
+ if (!this._pos) {
+ browserWidth = document.documentElement.clientWidth;
+ browserHeight = document.documentElement.clientHeight;
+ scrollX = document.documentElement.scrollLeft || document.body.scrollLeft;
+ scrollY = document.documentElement.scrollTop || document.body.scrollTop;
+ this._pos = // should use actual width/height below
+ [(browserWidth / 2) - 100 + scrollX, (browserHeight / 2) - 150 + scrollY];
+ }
+
+ // move input on screen for focus, but hidden behind dialog
+ this._dialogInput.css("left", (this._pos[0] + 20) + "px").css("top", this._pos[1] + "px");
+ inst.settings.onSelect = onSelect;
+ this._inDialog = true;
+ this.dpDiv.addClass(this._dialogClass);
+ this._showDatepicker(this._dialogInput[0]);
+ if ($.blockUI) {
+ $.blockUI(this.dpDiv);
+ }
+ $.data(this._dialogInput[0], PROP_NAME, inst);
+ return this;
+ },
+
+ /* Detach a datepicker from its control.
+ * @param target element - the target input field or division or span
+ */
+ _destroyDatepicker: function(target) {
+ var nodeName,
+ $target = $(target),
+ inst = $.data(target, PROP_NAME);
+
+ if (!$target.hasClass(this.markerClassName)) {
+ return;
+ }
+
+ nodeName = target.nodeName.toLowerCase();
+ $.removeData(target, PROP_NAME);
+ if (nodeName === "input") {
+ inst.append.remove();
+ inst.trigger.remove();
+ $target.removeClass(this.markerClassName).
+ unbind("focus", this._showDatepicker).
+ unbind("keydown", this._doKeyDown).
+ unbind("keypress", this._doKeyPress).
+ unbind("keyup", this._doKeyUp);
+ } else if (nodeName === "div" || nodeName === "span") {
+ $target.removeClass(this.markerClassName).empty();
+ }
+ },
+
+ /* Enable the date picker to a jQuery selection.
+ * @param target element - the target input field or division or span
+ */
+ _enableDatepicker: function(target) {
+ var nodeName, inline,
+ $target = $(target),
+ inst = $.data(target, PROP_NAME);
+
+ if (!$target.hasClass(this.markerClassName)) {
+ return;
+ }
+
+ nodeName = target.nodeName.toLowerCase();
+ if (nodeName === "input") {
+ target.disabled = false;
+ inst.trigger.filter("button").
+ each(function() { this.disabled = false; }).end().
+ filter("img").css({opacity: "1.0", cursor: ""});
+ } else if (nodeName === "div" || nodeName === "span") {
+ inline = $target.children("." + this._inlineClass);
+ inline.children().removeClass("ui-state-disabled");
+ inline.find("select.ui-datepicker-month, select.ui-datepicker-year").
+ prop("disabled", false);
+ }
+ this._disabledInputs = $.map(this._disabledInputs,
+ function(value) { return (value === target ? null : value); }); // delete entry
+ },
+
+ /* Disable the date picker to a jQuery selection.
+ * @param target element - the target input field or division or span
+ */
+ _disableDatepicker: function(target) {
+ var nodeName, inline,
+ $target = $(target),
+ inst = $.data(target, PROP_NAME);
+
+ if (!$target.hasClass(this.markerClassName)) {
+ return;
+ }
+
+ nodeName = target.nodeName.toLowerCase();
+ if (nodeName === "input") {
+ target.disabled = true;
+ inst.trigger.filter("button").
+ each(function() { this.disabled = true; }).end().
+ filter("img").css({opacity: "0.5", cursor: "default"});
+ } else if (nodeName === "div" || nodeName === "span") {
+ inline = $target.children("." + this._inlineClass);
+ inline.children().addClass("ui-state-disabled");
+ inline.find("select.ui-datepicker-month, select.ui-datepicker-year").
+ prop("disabled", true);
+ }
+ this._disabledInputs = $.map(this._disabledInputs,
+ function(value) { return (value === target ? null : value); }); // delete entry
+ this._disabledInputs[this._disabledInputs.length] = target;
+ },
+
+ /* Is the first field in a jQuery collection disabled as a datepicker?
+ * @param target element - the target input field or division or span
+ * @return boolean - true if disabled, false if enabled
+ */
+ _isDisabledDatepicker: function(target) {
+ if (!target) {
+ return false;
+ }
+ for (var i = 0; i < this._disabledInputs.length; i++) {
+ if (this._disabledInputs[i] === target) {
+ return true;
+ }
+ }
+ return false;
+ },
+
+ /* Retrieve the instance data for the target control.
+ * @param target element - the target input field or division or span
+ * @return object - the associated instance data
+ * @throws error if a jQuery problem getting data
+ */
+ _getInst: function(target) {
+ try {
+ return $.data(target, PROP_NAME);
+ }
+ catch (err) {
+ throw "Missing instance data for this datepicker";
+ }
+ },
+
+ /* Update or retrieve the settings for a date picker attached to an input field or division.
+ * @param target element - the target input field or division or span
+ * @param name object - the new settings to update or
+ * string - the name of the setting to change or retrieve,
+ * when retrieving also "all" for all instance settings or
+ * "defaults" for all global defaults
+ * @param value any - the new value for the setting
+ * (omit if above is an object or to retrieve a value)
+ */
+ _optionDatepicker: function(target, name, value) {
+ var settings, date, minDate, maxDate,
+ inst = this._getInst(target);
+
+ if (arguments.length === 2 && typeof name === "string") {
+ return (name === "defaults" ? $.extend({}, $.datepicker._defaults) :
+ (inst ? (name === "all" ? $.extend({}, inst.settings) :
+ this._get(inst, name)) : null));
+ }
+
+ settings = name || {};
+ if (typeof name === "string") {
+ settings = {};
+ settings[name] = value;
+ }
+
+ if (inst) {
+ if (this._curInst === inst) {
+ this._hideDatepicker();
+ }
+
+ date = this._getDateDatepicker(target, true);
+ minDate = this._getMinMaxDate(inst, "min");
+ maxDate = this._getMinMaxDate(inst, "max");
+ extendRemove(inst.settings, settings);
+ // reformat the old minDate/maxDate values if dateFormat changes and a new minDate/maxDate isn't provided
+ if (minDate !== null && settings.dateFormat !== undefined && settings.minDate === undefined) {
+ inst.settings.minDate = this._formatDate(inst, minDate);
+ }
+ if (maxDate !== null && settings.dateFormat !== undefined && settings.maxDate === undefined) {
+ inst.settings.maxDate = this._formatDate(inst, maxDate);
+ }
+ if ( "disabled" in settings ) {
+ if ( settings.disabled ) {
+ this._disableDatepicker(target);
+ } else {
+ this._enableDatepicker(target);
+ }
+ }
+ this._attachments($(target), inst);
+ this._autoSize(inst);
+ this._setDate(inst, date);
+ this._updateAlternate(inst);
+ this._updateDatepicker(inst);
+ }
+ },
+
+ // change method deprecated
+ _changeDatepicker: function(target, name, value) {
+ this._optionDatepicker(target, name, value);
+ },
+
+ /* Redraw the date picker attached to an input field or division.
+ * @param target element - the target input field or division or span
+ */
+ _refreshDatepicker: function(target) {
+ var inst = this._getInst(target);
+ if (inst) {
+ this._updateDatepicker(inst);
+ }
+ },
+
+ /* Set the dates for a jQuery selection.
+ * @param target element - the target input field or division or span
+ * @param date Date - the new date
+ */
+ _setDateDatepicker: function(target, date) {
+ var inst = this._getInst(target);
+ if (inst) {
+ this._setDate(inst, date);
+ this._updateDatepicker(inst);
+ this._updateAlternate(inst);
+ }
+ },
+
+ /* Get the date(s) for the first entry in a jQuery selection.
+ * @param target element - the target input field or division or span
+ * @param noDefault boolean - true if no default date is to be used
+ * @return Date - the current date
+ */
+ _getDateDatepicker: function(target, noDefault) {
+ var inst = this._getInst(target);
+ if (inst && !inst.inline) {
+ this._setDateFromField(inst, noDefault);
+ }
+ return (inst ? this._getDate(inst) : null);
+ },
+
+ /* Handle keystrokes. */
+ _doKeyDown: function(event) {
+ var onSelect, dateStr, sel,
+ inst = $.datepicker._getInst(event.target),
+ handled = true,
+ isRTL = inst.dpDiv.is(".ui-datepicker-rtl");
+
+ inst._keyEvent = true;
+ if ($.datepicker._datepickerShowing) {
+ switch (event.keyCode) {
+ case 9: $.datepicker._hideDatepicker();
+ handled = false;
+ break; // hide on tab out
+ case 13: sel = $("td." + $.datepicker._dayOverClass + ":not(." +
+ $.datepicker._currentClass + ")", inst.dpDiv);
+ if (sel[0]) {
+ $.datepicker._selectDay(event.target, inst.selectedMonth, inst.selectedYear, sel[0]);
+ }
+
+ onSelect = $.datepicker._get(inst, "onSelect");
+ if (onSelect) {
+ dateStr = $.datepicker._formatDate(inst);
+
+ // trigger custom callback
+ onSelect.apply((inst.input ? inst.input[0] : null), [dateStr, inst]);
+ } else {
+ $.datepicker._hideDatepicker();
+ }
+
+ return false; // don't submit the form
+ case 27: $.datepicker._hideDatepicker();
+ break; // hide on escape
+ case 33: $.datepicker._adjustDate(event.target, (event.ctrlKey ?
+ -$.datepicker._get(inst, "stepBigMonths") :
+ -$.datepicker._get(inst, "stepMonths")), "M");
+ break; // previous month/year on page up/+ ctrl
+ case 34: $.datepicker._adjustDate(event.target, (event.ctrlKey ?
+ +$.datepicker._get(inst, "stepBigMonths") :
+ +$.datepicker._get(inst, "stepMonths")), "M");
+ break; // next month/year on page down/+ ctrl
+ case 35: if (event.ctrlKey || event.metaKey) {
+ $.datepicker._clearDate(event.target);
+ }
+ handled = event.ctrlKey || event.metaKey;
+ break; // clear on ctrl or command +end
+ case 36: if (event.ctrlKey || event.metaKey) {
+ $.datepicker._gotoToday(event.target);
+ }
+ handled = event.ctrlKey || event.metaKey;
+ break; // current on ctrl or command +home
+ case 37: if (event.ctrlKey || event.metaKey) {
+ $.datepicker._adjustDate(event.target, (isRTL ? +1 : -1), "D");
+ }
+ handled = event.ctrlKey || event.metaKey;
+ // -1 day on ctrl or command +left
+ if (event.originalEvent.altKey) {
+ $.datepicker._adjustDate(event.target, (event.ctrlKey ?
+ -$.datepicker._get(inst, "stepBigMonths") :
+ -$.datepicker._get(inst, "stepMonths")), "M");
+ }
+ // next month/year on alt +left on Mac
+ break;
+ case 38: if (event.ctrlKey || event.metaKey) {
+ $.datepicker._adjustDate(event.target, -7, "D");
+ }
+ handled = event.ctrlKey || event.metaKey;
+ break; // -1 week on ctrl or command +up
+ case 39: if (event.ctrlKey || event.metaKey) {
+ $.datepicker._adjustDate(event.target, (isRTL ? -1 : +1), "D");
+ }
+ handled = event.ctrlKey || event.metaKey;
+ // +1 day on ctrl or command +right
+ if (event.originalEvent.altKey) {
+ $.datepicker._adjustDate(event.target, (event.ctrlKey ?
+ +$.datepicker._get(inst, "stepBigMonths") :
+ +$.datepicker._get(inst, "stepMonths")), "M");
+ }
+ // next month/year on alt +right
+ break;
+ case 40: if (event.ctrlKey || event.metaKey) {
+ $.datepicker._adjustDate(event.target, +7, "D");
+ }
+ handled = event.ctrlKey || event.metaKey;
+ break; // +1 week on ctrl or command +down
+ default: handled = false;
+ }
+ } else if (event.keyCode === 36 && event.ctrlKey) { // display the date picker on ctrl+home
+ $.datepicker._showDatepicker(this);
+ } else {
+ handled = false;
+ }
+
+ if (handled) {
+ event.preventDefault();
+ event.stopPropagation();
+ }
+ },
+
+ /* Filter entered characters - based on date format. */
+ _doKeyPress: function(event) {
+ var chars, chr,
+ inst = $.datepicker._getInst(event.target);
+
+ if ($.datepicker._get(inst, "constrainInput")) {
+ chars = $.datepicker._possibleChars($.datepicker._get(inst, "dateFormat"));
+ chr = String.fromCharCode(event.charCode == null ? event.keyCode : event.charCode);
+ return event.ctrlKey || event.metaKey || (chr < " " || !chars || chars.indexOf(chr) > -1);
+ }
+ },
+
+ /* Synchronise manual entry and field/alternate field. */
+ _doKeyUp: function(event) {
+ var date,
+ inst = $.datepicker._getInst(event.target);
+
+ if (inst.input.val() !== inst.lastVal) {
+ try {
+ date = $.datepicker.parseDate($.datepicker._get(inst, "dateFormat"),
+ (inst.input ? inst.input.val() : null),
+ $.datepicker._getFormatConfig(inst));
+
+ if (date) { // only if valid
+ $.datepicker._setDateFromField(inst);
+ $.datepicker._updateAlternate(inst);
+ $.datepicker._updateDatepicker(inst);
+ }
+ }
+ catch (err) {
+ }
+ }
+ return true;
+ },
+
+ /* Pop-up the date picker for a given input field.
+ * If false returned from beforeShow event handler do not show.
+ * @param input element - the input field attached to the date picker or
+ * event - if triggered by focus
+ */
+ _showDatepicker: function(input) {
+ input = input.target || input;
+ if (input.nodeName.toLowerCase() !== "input") { // find from button/image trigger
+ input = $("input", input.parentNode)[0];
+ }
+
+ if ($.datepicker._isDisabledDatepicker(input) || $.datepicker._lastInput === input) { // already here
+ return;
+ }
+
+ var inst, beforeShow, beforeShowSettings, isFixed,
+ offset, showAnim, duration;
+
+ inst = $.datepicker._getInst(input);
+ if ($.datepicker._curInst && $.datepicker._curInst !== inst) {
+ $.datepicker._curInst.dpDiv.stop(true, true);
+ if ( inst && $.datepicker._datepickerShowing ) {
+ $.datepicker._hideDatepicker( $.datepicker._curInst.input[0] );
+ }
+ }
+
+ beforeShow = $.datepicker._get(inst, "beforeShow");
+ beforeShowSettings = beforeShow ? beforeShow.apply(input, [input, inst]) : {};
+ if(beforeShowSettings === false){
+ return;
+ }
+ extendRemove(inst.settings, beforeShowSettings);
+
+ inst.lastVal = null;
+ $.datepicker._lastInput = input;
+ $.datepicker._setDateFromField(inst);
+
+ if ($.datepicker._inDialog) { // hide cursor
+ input.value = "";
+ }
+ if (!$.datepicker._pos) { // position below input
+ $.datepicker._pos = $.datepicker._findPos(input);
+ $.datepicker._pos[1] += input.offsetHeight; // add the height
+ }
+
+ isFixed = false;
+ $(input).parents().each(function() {
+ isFixed |= $(this).css("position") === "fixed";
+ return !isFixed;
+ });
+
+ offset = {left: $.datepicker._pos[0], top: $.datepicker._pos[1]};
+ $.datepicker._pos = null;
+ //to avoid flashes on Firefox
+ inst.dpDiv.empty();
+ // determine sizing offscreen
+ inst.dpDiv.css({position: "absolute", display: "block", top: "-1000px"});
+ $.datepicker._updateDatepicker(inst);
+ // fix width for dynamic number of date pickers
+ // and adjust position before showing
+ offset = $.datepicker._checkOffset(inst, offset, isFixed);
+ inst.dpDiv.css({position: ($.datepicker._inDialog && $.blockUI ?
+ "static" : (isFixed ? "fixed" : "absolute")), display: "none",
+ left: offset.left + "px", top: offset.top + "px"});
+
+ if (!inst.inline) {
+ showAnim = $.datepicker._get(inst, "showAnim");
+ duration = $.datepicker._get(inst, "duration");
+ inst.dpDiv.zIndex($(input).zIndex()+1);
+ $.datepicker._datepickerShowing = true;
+
+ if ( $.effects && $.effects.effect[ showAnim ] ) {
+ inst.dpDiv.show(showAnim, $.datepicker._get(inst, "showOptions"), duration);
+ } else {
+ inst.dpDiv[showAnim || "show"](showAnim ? duration : null);
+ }
+
+ if ( $.datepicker._shouldFocusInput( inst ) ) {
+ inst.input.focus();
+ }
+
+ $.datepicker._curInst = inst;
+ }
+ },
+
+ /* Generate the date picker content. */
+ _updateDatepicker: function(inst) {
+ this.maxRows = 4; //Reset the max number of rows being displayed (see #7043)
+ instActive = inst; // for delegate hover events
+ inst.dpDiv.empty().append(this._generateHTML(inst));
+ this._attachHandlers(inst);
+ inst.dpDiv.find("." + this._dayOverClass + " a").mouseover();
+
+ var origyearshtml,
+ numMonths = this._getNumberOfMonths(inst),
+ cols = numMonths[1],
+ width = 17;
+
+ inst.dpDiv.removeClass("ui-datepicker-multi-2 ui-datepicker-multi-3 ui-datepicker-multi-4").width("");
+ if (cols > 1) {
+ inst.dpDiv.addClass("ui-datepicker-multi-" + cols).css("width", (width * cols) + "em");
+ }
+ inst.dpDiv[(numMonths[0] !== 1 || numMonths[1] !== 1 ? "add" : "remove") +
+ "Class"]("ui-datepicker-multi");
+ inst.dpDiv[(this._get(inst, "isRTL") ? "add" : "remove") +
+ "Class"]("ui-datepicker-rtl");
+
+ if (inst === $.datepicker._curInst && $.datepicker._datepickerShowing && $.datepicker._shouldFocusInput( inst ) ) {
+ inst.input.focus();
+ }
+
+ // deffered render of the years select (to avoid flashes on Firefox)
+ if( inst.yearshtml ){
+ origyearshtml = inst.yearshtml;
+ setTimeout(function(){
+ //assure that inst.yearshtml didn't change.
+ if( origyearshtml === inst.yearshtml && inst.yearshtml ){
+ inst.dpDiv.find("select.ui-datepicker-year:first").replaceWith(inst.yearshtml);
+ }
+ origyearshtml = inst.yearshtml = null;
+ }, 0);
+ }
+ },
+
+ // #6694 - don't focus the input if it's already focused
+ // this breaks the change event in IE
+ // Support: IE and jQuery <1.9
+ _shouldFocusInput: function( inst ) {
+ return inst.input && inst.input.is( ":visible" ) && !inst.input.is( ":disabled" ) && !inst.input.is( ":focus" );
+ },
+
+ /* Check positioning to remain on screen. */
+ _checkOffset: function(inst, offset, isFixed) {
+ var dpWidth = inst.dpDiv.outerWidth(),
+ dpHeight = inst.dpDiv.outerHeight(),
+ inputWidth = inst.input ? inst.input.outerWidth() : 0,
+ inputHeight = inst.input ? inst.input.outerHeight() : 0,
+ viewWidth = document.documentElement.clientWidth + (isFixed ? 0 : $(document).scrollLeft()),
+ viewHeight = document.documentElement.clientHeight + (isFixed ? 0 : $(document).scrollTop());
+
+ offset.left -= (this._get(inst, "isRTL") ? (dpWidth - inputWidth) : 0);
+ offset.left -= (isFixed && offset.left === inst.input.offset().left) ? $(document).scrollLeft() : 0;
+ offset.top -= (isFixed && offset.top === (inst.input.offset().top + inputHeight)) ? $(document).scrollTop() : 0;
+
+ // now check if datepicker is showing outside window viewport - move to a better place if so.
+ offset.left -= Math.min(offset.left, (offset.left + dpWidth > viewWidth && viewWidth > dpWidth) ?
+ Math.abs(offset.left + dpWidth - viewWidth) : 0);
+ offset.top -= Math.min(offset.top, (offset.top + dpHeight > viewHeight && viewHeight > dpHeight) ?
+ Math.abs(dpHeight + inputHeight) : 0);
+
+ return offset;
+ },
+
+ /* Find an object's position on the screen. */
+ _findPos: function(obj) {
+ var position,
+ inst = this._getInst(obj),
+ isRTL = this._get(inst, "isRTL");
+
+ while (obj && (obj.type === "hidden" || obj.nodeType !== 1 || $.expr.filters.hidden(obj))) {
+ obj = obj[isRTL ? "previousSibling" : "nextSibling"];
+ }
+
+ position = $(obj).offset();
+ return [position.left, position.top];
+ },
+
+ /* Hide the date picker from view.
+ * @param input element - the input field attached to the date picker
+ */
+ _hideDatepicker: function(input) {
+ var showAnim, duration, postProcess, onClose,
+ inst = this._curInst;
+
+ if (!inst || (input && inst !== $.data(input, PROP_NAME))) {
+ return;
+ }
+
+ if (this._datepickerShowing) {
+ showAnim = this._get(inst, "showAnim");
+ duration = this._get(inst, "duration");
+ postProcess = function() {
+ $.datepicker._tidyDialog(inst);
+ };
+
+ // DEPRECATED: after BC for 1.8.x $.effects[ showAnim ] is not needed
+ if ( $.effects && ( $.effects.effect[ showAnim ] || $.effects[ showAnim ] ) ) {
+ inst.dpDiv.hide(showAnim, $.datepicker._get(inst, "showOptions"), duration, postProcess);
+ } else {
+ inst.dpDiv[(showAnim === "slideDown" ? "slideUp" :
+ (showAnim === "fadeIn" ? "fadeOut" : "hide"))]((showAnim ? duration : null), postProcess);
+ }
+
+ if (!showAnim) {
+ postProcess();
+ }
+ this._datepickerShowing = false;
+
+ onClose = this._get(inst, "onClose");
+ if (onClose) {
+ onClose.apply((inst.input ? inst.input[0] : null), [(inst.input ? inst.input.val() : ""), inst]);
+ }
+
+ this._lastInput = null;
+ if (this._inDialog) {
+ this._dialogInput.css({ position: "absolute", left: "0", top: "-100px" });
+ if ($.blockUI) {
+ $.unblockUI();
+ $("body").append(this.dpDiv);
+ }
+ }
+ this._inDialog = false;
+ }
+ },
+
+ /* Tidy up after a dialog display. */
+ _tidyDialog: function(inst) {
+ inst.dpDiv.removeClass(this._dialogClass).unbind(".ui-datepicker-calendar");
+ },
+
+ /* Close date picker if clicked elsewhere. */
+ _checkExternalClick: function(event) {
+ if (!$.datepicker._curInst) {
+ return;
+ }
+
+ var $target = $(event.target),
+ inst = $.datepicker._getInst($target[0]);
+
+ if ( ( ( $target[0].id !== $.datepicker._mainDivId &&
+ $target.parents("#" + $.datepicker._mainDivId).length === 0 &&
+ !$target.hasClass($.datepicker.markerClassName) &&
+ !$target.closest("." + $.datepicker._triggerClass).length &&
+ $.datepicker._datepickerShowing && !($.datepicker._inDialog && $.blockUI) ) ) ||
+ ( $target.hasClass($.datepicker.markerClassName) && $.datepicker._curInst !== inst ) ) {
+ $.datepicker._hideDatepicker();
+ }
+ },
+
+ /* Adjust one of the date sub-fields. */
+ _adjustDate: function(id, offset, period) {
+ var target = $(id),
+ inst = this._getInst(target[0]);
+
+ if (this._isDisabledDatepicker(target[0])) {
+ return;
+ }
+ this._adjustInstDate(inst, offset +
+ (period === "M" ? this._get(inst, "showCurrentAtPos") : 0), // undo positioning
+ period);
+ this._updateDatepicker(inst);
+ },
+
+ /* Action for current link. */
+ _gotoToday: function(id) {
+ var date,
+ target = $(id),
+ inst = this._getInst(target[0]);
+
+ if (this._get(inst, "gotoCurrent") && inst.currentDay) {
+ inst.selectedDay = inst.currentDay;
+ inst.drawMonth = inst.selectedMonth = inst.currentMonth;
+ inst.drawYear = inst.selectedYear = inst.currentYear;
+ } else {
+ date = new Date();
+ inst.selectedDay = date.getDate();
+ inst.drawMonth = inst.selectedMonth = date.getMonth();
+ inst.drawYear = inst.selectedYear = date.getFullYear();
+ }
+ this._notifyChange(inst);
+ this._adjustDate(target);
+ },
+
+ /* Action for selecting a new month/year. */
+ _selectMonthYear: function(id, select, period) {
+ var target = $(id),
+ inst = this._getInst(target[0]);
+
+ inst["selected" + (period === "M" ? "Month" : "Year")] =
+ inst["draw" + (period === "M" ? "Month" : "Year")] =
+ parseInt(select.options[select.selectedIndex].value,10);
+
+ this._notifyChange(inst);
+ this._adjustDate(target);
+ },
+
+ /* Action for selecting a day. */
+ _selectDay: function(id, month, year, td) {
+ var inst,
+ target = $(id);
+
+ if ($(td).hasClass(this._unselectableClass) || this._isDisabledDatepicker(target[0])) {
+ return;
+ }
+
+ inst = this._getInst(target[0]);
+ inst.selectedDay = inst.currentDay = $("a", td).html();
+ inst.selectedMonth = inst.currentMonth = month;
+ inst.selectedYear = inst.currentYear = year;
+ this._selectDate(id, this._formatDate(inst,
+ inst.currentDay, inst.currentMonth, inst.currentYear));
+ },
+
+ /* Erase the input field and hide the date picker. */
+ _clearDate: function(id) {
+ var target = $(id);
+ this._selectDate(target, "");
+ },
+
+ /* Update the input field with the selected date. */
+ _selectDate: function(id, dateStr) {
+ var onSelect,
+ target = $(id),
+ inst = this._getInst(target[0]);
+
+ dateStr = (dateStr != null ? dateStr : this._formatDate(inst));
+ if (inst.input) {
+ inst.input.val(dateStr);
+ }
+ this._updateAlternate(inst);
+
+ onSelect = this._get(inst, "onSelect");
+ if (onSelect) {
+ onSelect.apply((inst.input ? inst.input[0] : null), [dateStr, inst]); // trigger custom callback
+ } else if (inst.input) {
+ inst.input.trigger("change"); // fire the change event
+ }
+
+ if (inst.inline){
+ this._updateDatepicker(inst);
+ } else {
+ this._hideDatepicker();
+ this._lastInput = inst.input[0];
+ if (typeof(inst.input[0]) !== "object") {
+ inst.input.focus(); // restore focus
+ }
+ this._lastInput = null;
+ }
+ },
+
+ /* Update any alternate field to synchronise with the main field. */
+ _updateAlternate: function(inst) {
+ var altFormat, date, dateStr,
+ altField = this._get(inst, "altField");
+
+ if (altField) { // update alternate field too
+ altFormat = this._get(inst, "altFormat") || this._get(inst, "dateFormat");
+ date = this._getDate(inst);
+ dateStr = this.formatDate(altFormat, date, this._getFormatConfig(inst));
+ $(altField).each(function() { $(this).val(dateStr); });
+ }
+ },
+
+ /* Set as beforeShowDay function to prevent selection of weekends.
+ * @param date Date - the date to customise
+ * @return [boolean, string] - is this date selectable?, what is its CSS class?
+ */
+ noWeekends: function(date) {
+ var day = date.getDay();
+ return [(day > 0 && day < 6), ""];
+ },
+
+ /* Set as calculateWeek to determine the week of the year based on the ISO 8601 definition.
+ * @param date Date - the date to get the week for
+ * @return number - the number of the week within the year that contains this date
+ */
+ iso8601Week: function(date) {
+ var time,
+ checkDate = new Date(date.getTime());
+
+ // Find Thursday of this week starting on Monday
+ checkDate.setDate(checkDate.getDate() + 4 - (checkDate.getDay() || 7));
+
+ time = checkDate.getTime();
+ checkDate.setMonth(0); // Compare with Jan 1
+ checkDate.setDate(1);
+ return Math.floor(Math.round((time - checkDate) / 86400000) / 7) + 1;
+ },
+
+ /* Parse a string value into a date object.
+ * See formatDate below for the possible formats.
+ *
+ * @param format string - the expected format of the date
+ * @param value string - the date in the above format
+ * @param settings Object - attributes include:
+ * shortYearCutoff number - the cutoff year for determining the century (optional)
+ * dayNamesShort string[7] - abbreviated names of the days from Sunday (optional)
+ * dayNames string[7] - names of the days from Sunday (optional)
+ * monthNamesShort string[12] - abbreviated names of the months (optional)
+ * monthNames string[12] - names of the months (optional)
+ * @return Date - the extracted date value or null if value is blank
+ */
+ parseDate: function (format, value, settings) {
+ if (format == null || value == null) {
+ throw "Invalid arguments";
+ }
+
+ value = (typeof value === "object" ? value.toString() : value + "");
+ if (value === "") {
+ return null;
+ }
+
+ var iFormat, dim, extra,
+ iValue = 0,
+ shortYearCutoffTemp = (settings ? settings.shortYearCutoff : null) || this._defaults.shortYearCutoff,
+ shortYearCutoff = (typeof shortYearCutoffTemp !== "string" ? shortYearCutoffTemp :
+ new Date().getFullYear() % 100 + parseInt(shortYearCutoffTemp, 10)),
+ dayNamesShort = (settings ? settings.dayNamesShort : null) || this._defaults.dayNamesShort,
+ dayNames = (settings ? settings.dayNames : null) || this._defaults.dayNames,
+ monthNamesShort = (settings ? settings.monthNamesShort : null) || this._defaults.monthNamesShort,
+ monthNames = (settings ? settings.monthNames : null) || this._defaults.monthNames,
+ year = -1,
+ month = -1,
+ day = -1,
+ doy = -1,
+ literal = false,
+ date,
+ // Check whether a format character is doubled
+ lookAhead = function(match) {
+ var matches = (iFormat + 1 < format.length && format.charAt(iFormat + 1) === match);
+ if (matches) {
+ iFormat++;
+ }
+ return matches;
+ },
+ // Extract a number from the string value
+ getNumber = function(match) {
+ var isDoubled = lookAhead(match),
+ size = (match === "@" ? 14 : (match === "!" ? 20 :
+ (match === "y" && isDoubled ? 4 : (match === "o" ? 3 : 2)))),
+ digits = new RegExp("^\\d{1," + size + "}"),
+ num = value.substring(iValue).match(digits);
+ if (!num) {
+ throw "Missing number at position " + iValue;
+ }
+ iValue += num[0].length;
+ return parseInt(num[0], 10);
+ },
+ // Extract a name from the string value and convert to an index
+ getName = function(match, shortNames, longNames) {
+ var index = -1,
+ names = $.map(lookAhead(match) ? longNames : shortNames, function (v, k) {
+ return [ [k, v] ];
+ }).sort(function (a, b) {
+ return -(a[1].length - b[1].length);
+ });
+
+ $.each(names, function (i, pair) {
+ var name = pair[1];
+ if (value.substr(iValue, name.length).toLowerCase() === name.toLowerCase()) {
+ index = pair[0];
+ iValue += name.length;
+ return false;
+ }
+ });
+ if (index !== -1) {
+ return index + 1;
+ } else {
+ throw "Unknown name at position " + iValue;
+ }
+ },
+ // Confirm that a literal character matches the string value
+ checkLiteral = function() {
+ if (value.charAt(iValue) !== format.charAt(iFormat)) {
+ throw "Unexpected literal at position " + iValue;
+ }
+ iValue++;
+ };
+
+ for (iFormat = 0; iFormat < format.length; iFormat++) {
+ if (literal) {
+ if (format.charAt(iFormat) === "'" && !lookAhead("'")) {
+ literal = false;
+ } else {
+ checkLiteral();
+ }
+ } else {
+ switch (format.charAt(iFormat)) {
+ case "d":
+ day = getNumber("d");
+ break;
+ case "D":
+ getName("D", dayNamesShort, dayNames);
+ break;
+ case "o":
+ doy = getNumber("o");
+ break;
+ case "m":
+ month = getNumber("m");
+ break;
+ case "M":
+ month = getName("M", monthNamesShort, monthNames);
+ break;
+ case "y":
+ year = getNumber("y");
+ break;
+ case "@":
+ date = new Date(getNumber("@"));
+ year = date.getFullYear();
+ month = date.getMonth() + 1;
+ day = date.getDate();
+ break;
+ case "!":
+ date = new Date((getNumber("!") - this._ticksTo1970) / 10000);
+ year = date.getFullYear();
+ month = date.getMonth() + 1;
+ day = date.getDate();
+ break;
+ case "'":
+ if (lookAhead("'")){
+ checkLiteral();
+ } else {
+ literal = true;
+ }
+ break;
+ default:
+ checkLiteral();
+ }
+ }
+ }
+
+ if (iValue < value.length){
+ extra = value.substr(iValue);
+ if (!/^\s+/.test(extra)) {
+ throw "Extra/unparsed characters found in date: " + extra;
+ }
+ }
+
+ if (year === -1) {
+ year = new Date().getFullYear();
+ } else if (year < 100) {
+ year += new Date().getFullYear() - new Date().getFullYear() % 100 +
+ (year <= shortYearCutoff ? 0 : -100);
+ }
+
+ if (doy > -1) {
+ month = 1;
+ day = doy;
+ do {
+ dim = this._getDaysInMonth(year, month - 1);
+ if (day <= dim) {
+ break;
+ }
+ month++;
+ day -= dim;
+ } while (true);
+ }
+
+ date = this._daylightSavingAdjust(new Date(year, month - 1, day));
+ if (date.getFullYear() !== year || date.getMonth() + 1 !== month || date.getDate() !== day) {
+ throw "Invalid date"; // E.g. 31/02/00
+ }
+ return date;
+ },
+
+ /* Standard date formats. */
+ ATOM: "yy-mm-dd", // RFC 3339 (ISO 8601)
+ COOKIE: "D, dd M yy",
+ ISO_8601: "yy-mm-dd",
+ RFC_822: "D, d M y",
+ RFC_850: "DD, dd-M-y",
+ RFC_1036: "D, d M y",
+ RFC_1123: "D, d M yy",
+ RFC_2822: "D, d M yy",
+ RSS: "D, d M y", // RFC 822
+ TICKS: "!",
+ TIMESTAMP: "@",
+ W3C: "yy-mm-dd", // ISO 8601
+
+ _ticksTo1970: (((1970 - 1) * 365 + Math.floor(1970 / 4) - Math.floor(1970 / 100) +
+ Math.floor(1970 / 400)) * 24 * 60 * 60 * 10000000),
+
+ /* Format a date object into a string value.
+ * The format can be combinations of the following:
+ * d - day of month (no leading zero)
+ * dd - day of month (two digit)
+ * o - day of year (no leading zeros)
+ * oo - day of year (three digit)
+ * D - day name short
+ * DD - day name long
+ * m - month of year (no leading zero)
+ * mm - month of year (two digit)
+ * M - month name short
+ * MM - month name long
+ * y - year (two digit)
+ * yy - year (four digit)
+ * @ - Unix timestamp (ms since 01/01/1970)
+ * ! - Windows ticks (100ns since 01/01/0001)
+ * "..." - literal text
+ * '' - single quote
+ *
+ * @param format string - the desired format of the date
+ * @param date Date - the date value to format
+ * @param settings Object - attributes include:
+ * dayNamesShort string[7] - abbreviated names of the days from Sunday (optional)
+ * dayNames string[7] - names of the days from Sunday (optional)
+ * monthNamesShort string[12] - abbreviated names of the months (optional)
+ * monthNames string[12] - names of the months (optional)
+ * @return string - the date in the above format
+ */
+ formatDate: function (format, date, settings) {
+ if (!date) {
+ return "";
+ }
+
+ var iFormat,
+ dayNamesShort = (settings ? settings.dayNamesShort : null) || this._defaults.dayNamesShort,
+ dayNames = (settings ? settings.dayNames : null) || this._defaults.dayNames,
+ monthNamesShort = (settings ? settings.monthNamesShort : null) || this._defaults.monthNamesShort,
+ monthNames = (settings ? settings.monthNames : null) || this._defaults.monthNames,
+ // Check whether a format character is doubled
+ lookAhead = function(match) {
+ var matches = (iFormat + 1 < format.length && format.charAt(iFormat + 1) === match);
+ if (matches) {
+ iFormat++;
+ }
+ return matches;
+ },
+ // Format a number, with leading zero if necessary
+ formatNumber = function(match, value, len) {
+ var num = "" + value;
+ if (lookAhead(match)) {
+ while (num.length < len) {
+ num = "0" + num;
+ }
+ }
+ return num;
+ },
+ // Format a name, short or long as requested
+ formatName = function(match, value, shortNames, longNames) {
+ return (lookAhead(match) ? longNames[value] : shortNames[value]);
+ },
+ output = "",
+ literal = false;
+
+ if (date) {
+ for (iFormat = 0; iFormat < format.length; iFormat++) {
+ if (literal) {
+ if (format.charAt(iFormat) === "'" && !lookAhead("'")) {
+ literal = false;
+ } else {
+ output += format.charAt(iFormat);
+ }
+ } else {
+ switch (format.charAt(iFormat)) {
+ case "d":
+ output += formatNumber("d", date.getDate(), 2);
+ break;
+ case "D":
+ output += formatName("D", date.getDay(), dayNamesShort, dayNames);
+ break;
+ case "o":
+ output += formatNumber("o",
+ Math.round((new Date(date.getFullYear(), date.getMonth(), date.getDate()).getTime() - new Date(date.getFullYear(), 0, 0).getTime()) / 86400000), 3);
+ break;
+ case "m":
+ output += formatNumber("m", date.getMonth() + 1, 2);
+ break;
+ case "M":
+ output += formatName("M", date.getMonth(), monthNamesShort, monthNames);
+ break;
+ case "y":
+ output += (lookAhead("y") ? date.getFullYear() :
+ (date.getYear() % 100 < 10 ? "0" : "") + date.getYear() % 100);
+ break;
+ case "@":
+ output += date.getTime();
+ break;
+ case "!":
+ output += date.getTime() * 10000 + this._ticksTo1970;
+ break;
+ case "'":
+ if (lookAhead("'")) {
+ output += "'";
+ } else {
+ literal = true;
+ }
+ break;
+ default:
+ output += format.charAt(iFormat);
+ }
+ }
+ }
+ }
+ return output;
+ },
+
+ /* Extract all possible characters from the date format. */
+ _possibleChars: function (format) {
+ var iFormat,
+ chars = "",
+ literal = false,
+ // Check whether a format character is doubled
+ lookAhead = function(match) {
+ var matches = (iFormat + 1 < format.length && format.charAt(iFormat + 1) === match);
+ if (matches) {
+ iFormat++;
+ }
+ return matches;
+ };
+
+ for (iFormat = 0; iFormat < format.length; iFormat++) {
+ if (literal) {
+ if (format.charAt(iFormat) === "'" && !lookAhead("'")) {
+ literal = false;
+ } else {
+ chars += format.charAt(iFormat);
+ }
+ } else {
+ switch (format.charAt(iFormat)) {
+ case "d": case "m": case "y": case "@":
+ chars += "0123456789";
+ break;
+ case "D": case "M":
+ return null; // Accept anything
+ case "'":
+ if (lookAhead("'")) {
+ chars += "'";
+ } else {
+ literal = true;
+ }
+ break;
+ default:
+ chars += format.charAt(iFormat);
+ }
+ }
+ }
+ return chars;
+ },
+
+ /* Get a setting value, defaulting if necessary. */
+ _get: function(inst, name) {
+ return inst.settings[name] !== undefined ?
+ inst.settings[name] : this._defaults[name];
+ },
+
+ /* Parse existing date and initialise date picker. */
+ _setDateFromField: function(inst, noDefault) {
+ if (inst.input.val() === inst.lastVal) {
+ return;
+ }
+
+ var dateFormat = this._get(inst, "dateFormat"),
+ dates = inst.lastVal = inst.input ? inst.input.val() : null,
+ defaultDate = this._getDefaultDate(inst),
+ date = defaultDate,
+ settings = this._getFormatConfig(inst);
+
+ try {
+ date = this.parseDate(dateFormat, dates, settings) || defaultDate;
+ } catch (event) {
+ dates = (noDefault ? "" : dates);
+ }
+ inst.selectedDay = date.getDate();
+ inst.drawMonth = inst.selectedMonth = date.getMonth();
+ inst.drawYear = inst.selectedYear = date.getFullYear();
+ inst.currentDay = (dates ? date.getDate() : 0);
+ inst.currentMonth = (dates ? date.getMonth() : 0);
+ inst.currentYear = (dates ? date.getFullYear() : 0);
+ this._adjustInstDate(inst);
+ },
+
+ /* Retrieve the default date shown on opening. */
+ _getDefaultDate: function(inst) {
+ return this._restrictMinMax(inst,
+ this._determineDate(inst, this._get(inst, "defaultDate"), new Date()));
+ },
+
+ /* A date may be specified as an exact value or a relative one. */
+ _determineDate: function(inst, date, defaultDate) {
+ var offsetNumeric = function(offset) {
+ var date = new Date();
+ date.setDate(date.getDate() + offset);
+ return date;
+ },
+ offsetString = function(offset) {
+ try {
+ return $.datepicker.parseDate($.datepicker._get(inst, "dateFormat"),
+ offset, $.datepicker._getFormatConfig(inst));
+ }
+ catch (e) {
+ // Ignore
+ }
+
+ var date = (offset.toLowerCase().match(/^c/) ?
+ $.datepicker._getDate(inst) : null) || new Date(),
+ year = date.getFullYear(),
+ month = date.getMonth(),
+ day = date.getDate(),
+ pattern = /([+\-]?[0-9]+)\s*(d|D|w|W|m|M|y|Y)?/g,
+ matches = pattern.exec(offset);
+
+ while (matches) {
+ switch (matches[2] || "d") {
+ case "d" : case "D" :
+ day += parseInt(matches[1],10); break;
+ case "w" : case "W" :
+ day += parseInt(matches[1],10) * 7; break;
+ case "m" : case "M" :
+ month += parseInt(matches[1],10);
+ day = Math.min(day, $.datepicker._getDaysInMonth(year, month));
+ break;
+ case "y": case "Y" :
+ year += parseInt(matches[1],10);
+ day = Math.min(day, $.datepicker._getDaysInMonth(year, month));
+ break;
+ }
+ matches = pattern.exec(offset);
+ }
+ return new Date(year, month, day);
+ },
+ newDate = (date == null || date === "" ? defaultDate : (typeof date === "string" ? offsetString(date) :
+ (typeof date === "number" ? (isNaN(date) ? defaultDate : offsetNumeric(date)) : new Date(date.getTime()))));
+
+ newDate = (newDate && newDate.toString() === "Invalid Date" ? defaultDate : newDate);
+ if (newDate) {
+ newDate.setHours(0);
+ newDate.setMinutes(0);
+ newDate.setSeconds(0);
+ newDate.setMilliseconds(0);
+ }
+ return this._daylightSavingAdjust(newDate);
+ },
+
+ /* Handle switch to/from daylight saving.
+ * Hours may be non-zero on daylight saving cut-over:
+ * > 12 when midnight changeover, but then cannot generate
+ * midnight datetime, so jump to 1AM, otherwise reset.
+ * @param date (Date) the date to check
+ * @return (Date) the corrected date
+ */
+ _daylightSavingAdjust: function(date) {
+ if (!date) {
+ return null;
+ }
+ date.setHours(date.getHours() > 12 ? date.getHours() + 2 : 0);
+ return date;
+ },
+
+ /* Set the date(s) directly. */
+ _setDate: function(inst, date, noChange) {
+ var clear = !date,
+ origMonth = inst.selectedMonth,
+ origYear = inst.selectedYear,
+ newDate = this._restrictMinMax(inst, this._determineDate(inst, date, new Date()));
+
+ inst.selectedDay = inst.currentDay = newDate.getDate();
+ inst.drawMonth = inst.selectedMonth = inst.currentMonth = newDate.getMonth();
+ inst.drawYear = inst.selectedYear = inst.currentYear = newDate.getFullYear();
+ if ((origMonth !== inst.selectedMonth || origYear !== inst.selectedYear) && !noChange) {
+ this._notifyChange(inst);
+ }
+ this._adjustInstDate(inst);
+ if (inst.input) {
+ inst.input.val(clear ? "" : this._formatDate(inst));
+ }
+ },
+
+ /* Retrieve the date(s) directly. */
+ _getDate: function(inst) {
+ var startDate = (!inst.currentYear || (inst.input && inst.input.val() === "") ? null :
+ this._daylightSavingAdjust(new Date(
+ inst.currentYear, inst.currentMonth, inst.currentDay)));
+ return startDate;
+ },
+
+ /* Attach the onxxx handlers. These are declared statically so
+ * they work with static code transformers like Caja.
+ */
+ _attachHandlers: function(inst) {
+ var stepMonths = this._get(inst, "stepMonths"),
+ id = "#" + inst.id.replace( /\\\\/g, "\\" );
+ inst.dpDiv.find("[data-handler]").map(function () {
+ var handler = {
+ prev: function () {
+ $.datepicker._adjustDate(id, -stepMonths, "M");
+ },
+ next: function () {
+ $.datepicker._adjustDate(id, +stepMonths, "M");
+ },
+ hide: function () {
+ $.datepicker._hideDatepicker();
+ },
+ today: function () {
+ $.datepicker._gotoToday(id);
+ },
+ selectDay: function () {
+ $.datepicker._selectDay(id, +this.getAttribute("data-month"), +this.getAttribute("data-year"), this);
+ return false;
+ },
+ selectMonth: function () {
+ $.datepicker._selectMonthYear(id, this, "M");
+ return false;
+ },
+ selectYear: function () {
+ $.datepicker._selectMonthYear(id, this, "Y");
+ return false;
+ }
+ };
+ $(this).bind(this.getAttribute("data-event"), handler[this.getAttribute("data-handler")]);
+ });
+ },
+
+ /* Generate the HTML for the current state of the date picker. */
+ _generateHTML: function(inst) {
+ var maxDraw, prevText, prev, nextText, next, currentText, gotoDate,
+ controls, buttonPanel, firstDay, showWeek, dayNames, dayNamesMin,
+ monthNames, monthNamesShort, beforeShowDay, showOtherMonths,
+ selectOtherMonths, defaultDate, html, dow, row, group, col, selectedDate,
+ cornerClass, calender, thead, day, daysInMonth, leadDays, curRows, numRows,
+ printDate, dRow, tbody, daySettings, otherMonth, unselectable,
+ tempDate = new Date(),
+ today = this._daylightSavingAdjust(
+ new Date(tempDate.getFullYear(), tempDate.getMonth(), tempDate.getDate())), // clear time
+ isRTL = this._get(inst, "isRTL"),
+ showButtonPanel = this._get(inst, "showButtonPanel"),
+ hideIfNoPrevNext = this._get(inst, "hideIfNoPrevNext"),
+ navigationAsDateFormat = this._get(inst, "navigationAsDateFormat"),
+ numMonths = this._getNumberOfMonths(inst),
+ showCurrentAtPos = this._get(inst, "showCurrentAtPos"),
+ stepMonths = this._get(inst, "stepMonths"),
+ isMultiMonth = (numMonths[0] !== 1 || numMonths[1] !== 1),
+ currentDate = this._daylightSavingAdjust((!inst.currentDay ? new Date(9999, 9, 9) :
+ new Date(inst.currentYear, inst.currentMonth, inst.currentDay))),
+ minDate = this._getMinMaxDate(inst, "min"),
+ maxDate = this._getMinMaxDate(inst, "max"),
+ drawMonth = inst.drawMonth - showCurrentAtPos,
+ drawYear = inst.drawYear;
+
+ if (drawMonth < 0) {
+ drawMonth += 12;
+ drawYear--;
+ }
+ if (maxDate) {
+ maxDraw = this._daylightSavingAdjust(new Date(maxDate.getFullYear(),
+ maxDate.getMonth() - (numMonths[0] * numMonths[1]) + 1, maxDate.getDate()));
+ maxDraw = (minDate && maxDraw < minDate ? minDate : maxDraw);
+ while (this._daylightSavingAdjust(new Date(drawYear, drawMonth, 1)) > maxDraw) {
+ drawMonth--;
+ if (drawMonth < 0) {
+ drawMonth = 11;
+ drawYear--;
+ }
+ }
+ }
+ inst.drawMonth = drawMonth;
+ inst.drawYear = drawYear;
+
+ prevText = this._get(inst, "prevText");
+ prevText = (!navigationAsDateFormat ? prevText : this.formatDate(prevText,
+ this._daylightSavingAdjust(new Date(drawYear, drawMonth - stepMonths, 1)),
+ this._getFormatConfig(inst)));
+
+ prev = (this._canAdjustMonth(inst, -1, drawYear, drawMonth) ?
+ "<a class='ui-datepicker-prev ui-corner-all' data-handler='prev' data-event='click'" +
+ " title='" + prevText + "'><span class='ui-icon ui-icon-circle-triangle-" + ( isRTL ? "e" : "w") + "'>" + prevText + "</span></a>" :
+ (hideIfNoPrevNext ? "" : "<a class='ui-datepicker-prev ui-corner-all ui-state-disabled' title='"+ prevText +"'><span class='ui-icon ui-icon-circle-triangle-" + ( isRTL ? "e" : "w") + "'>" + prevText + "</span></a>"));
+
+ nextText = this._get(inst, "nextText");
+ nextText = (!navigationAsDateFormat ? nextText : this.formatDate(nextText,
+ this._daylightSavingAdjust(new Date(drawYear, drawMonth + stepMonths, 1)),
+ this._getFormatConfig(inst)));
+
+ next = (this._canAdjustMonth(inst, +1, drawYear, drawMonth) ?
+ "<a class='ui-datepicker-next ui-corner-all' data-handler='next' data-event='click'" +
+ " title='" + nextText + "'><span class='ui-icon ui-icon-circle-triangle-" + ( isRTL ? "w" : "e") + "'>" + nextText + "</span></a>" :
+ (hideIfNoPrevNext ? "" : "<a class='ui-datepicker-next ui-corner-all ui-state-disabled' title='"+ nextText + "'><span class='ui-icon ui-icon-circle-triangle-" + ( isRTL ? "w" : "e") + "'>" + nextText + "</span></a>"));
+
+ currentText = this._get(inst, "currentText");
+ gotoDate = (this._get(inst, "gotoCurrent") && inst.currentDay ? currentDate : today);
+ currentText = (!navigationAsDateFormat ? currentText :
+ this.formatDate(currentText, gotoDate, this._getFormatConfig(inst)));
+
+ controls = (!inst.inline ? "<button type='button' class='ui-datepicker-close ui-state-default ui-priority-primary ui-corner-all' data-handler='hide' data-event='click'>" +
+ this._get(inst, "closeText") + "</button>" : "");
+
+ buttonPanel = (showButtonPanel) ? "<div class='ui-datepicker-buttonpane ui-widget-content'>" + (isRTL ? controls : "") +
+ (this._isInRange(inst, gotoDate) ? "<button type='button' class='ui-datepicker-current ui-state-default ui-priority-secondary ui-corner-all' data-handler='today' data-event='click'" +
+ ">" + currentText + "</button>" : "") + (isRTL ? "" : controls) + "</div>" : "";
+
+ firstDay = parseInt(this._get(inst, "firstDay"),10);
+ firstDay = (isNaN(firstDay) ? 0 : firstDay);
+
+ showWeek = this._get(inst, "showWeek");
+ dayNames = this._get(inst, "dayNames");
+ dayNamesMin = this._get(inst, "dayNamesMin");
+ monthNames = this._get(inst, "monthNames");
+ monthNamesShort = this._get(inst, "monthNamesShort");
+ beforeShowDay = this._get(inst, "beforeShowDay");
+ showOtherMonths = this._get(inst, "showOtherMonths");
+ selectOtherMonths = this._get(inst, "selectOtherMonths");
+ defaultDate = this._getDefaultDate(inst);
+ html = "";
+ dow;
+ for (row = 0; row < numMonths[0]; row++) {
+ group = "";
+ this.maxRows = 4;
+ for (col = 0; col < numMonths[1]; col++) {
+ selectedDate = this._daylightSavingAdjust(new Date(drawYear, drawMonth, inst.selectedDay));
+ cornerClass = " ui-corner-all";
+ calender = "";
+ if (isMultiMonth) {
+ calender += "<div class='ui-datepicker-group";
+ if (numMonths[1] > 1) {
+ switch (col) {
+ case 0: calender += " ui-datepicker-group-first";
+ cornerClass = " ui-corner-" + (isRTL ? "right" : "left"); break;
+ case numMonths[1]-1: calender += " ui-datepicker-group-last";
+ cornerClass = " ui-corner-" + (isRTL ? "left" : "right"); break;
+ default: calender += " ui-datepicker-group-middle"; cornerClass = ""; break;
+ }
+ }
+ calender += "'>";
+ }
+ calender += "<div class='ui-datepicker-header ui-widget-header ui-helper-clearfix" + cornerClass + "'>" +
+ (/all|left/.test(cornerClass) && row === 0 ? (isRTL ? next : prev) : "") +
+ (/all|right/.test(cornerClass) && row === 0 ? (isRTL ? prev : next) : "") +
+ this._generateMonthYearHeader(inst, drawMonth, drawYear, minDate, maxDate,
+ row > 0 || col > 0, monthNames, monthNamesShort) + // draw month headers
+ "</div><table class='ui-datepicker-calendar'><thead>" +
+ "<tr>";
+ thead = (showWeek ? "<th class='ui-datepicker-week-col'>" + this._get(inst, "weekHeader") + "</th>" : "");
+ for (dow = 0; dow < 7; dow++) { // days of the week
+ day = (dow + firstDay) % 7;
+ thead += "<th" + ((dow + firstDay + 6) % 7 >= 5 ? " class='ui-datepicker-week-end'" : "") + ">" +
+ "<span title='" + dayNames[day] + "'>" + dayNamesMin[day] + "</span></th>";
+ }
+ calender += thead + "</tr></thead><tbody>";
+ daysInMonth = this._getDaysInMonth(drawYear, drawMonth);
+ if (drawYear === inst.selectedYear && drawMonth === inst.selectedMonth) {
+ inst.selectedDay = Math.min(inst.selectedDay, daysInMonth);
+ }
+ leadDays = (this._getFirstDayOfMonth(drawYear, drawMonth) - firstDay + 7) % 7;
+ curRows = Math.ceil((leadDays + daysInMonth) / 7); // calculate the number of rows to generate
+ numRows = (isMultiMonth ? this.maxRows > curRows ? this.maxRows : curRows : curRows); //If multiple months, use the higher number of rows (see #7043)
+ this.maxRows = numRows;
+ printDate = this._daylightSavingAdjust(new Date(drawYear, drawMonth, 1 - leadDays));
+ for (dRow = 0; dRow < numRows; dRow++) { // create date picker rows
+ calender += "<tr>";
+ tbody = (!showWeek ? "" : "<td class='ui-datepicker-week-col'>" +
+ this._get(inst, "calculateWeek")(printDate) + "</td>");
+ for (dow = 0; dow < 7; dow++) { // create date picker days
+ daySettings = (beforeShowDay ?
+ beforeShowDay.apply((inst.input ? inst.input[0] : null), [printDate]) : [true, ""]);
+ otherMonth = (printDate.getMonth() !== drawMonth);
+ unselectable = (otherMonth && !selectOtherMonths) || !daySettings[0] ||
+ (minDate && printDate < minDate) || (maxDate && printDate > maxDate);
+ tbody += "<td class='" +
+ ((dow + firstDay + 6) % 7 >= 5 ? " ui-datepicker-week-end" : "") + // highlight weekends
+ (otherMonth ? " ui-datepicker-other-month" : "") + // highlight days from other months
+ ((printDate.getTime() === selectedDate.getTime() && drawMonth === inst.selectedMonth && inst._keyEvent) || // user pressed key
+ (defaultDate.getTime() === printDate.getTime() && defaultDate.getTime() === selectedDate.getTime()) ?
+ // or defaultDate is current printedDate and defaultDate is selectedDate
+ " " + this._dayOverClass : "") + // highlight selected day
+ (unselectable ? " " + this._unselectableClass + " ui-state-disabled": "") + // highlight unselectable days
+ (otherMonth && !showOtherMonths ? "" : " " + daySettings[1] + // highlight custom dates
+ (printDate.getTime() === currentDate.getTime() ? " " + this._currentClass : "") + // highlight selected day
+ (printDate.getTime() === today.getTime() ? " ui-datepicker-today" : "")) + "'" + // highlight today (if different)
+ ((!otherMonth || showOtherMonths) && daySettings[2] ? " title='" + daySettings[2].replace(/'/g, "&#39;") + "'" : "") + // cell title
+ (unselectable ? "" : " data-handler='selectDay' data-event='click' data-month='" + printDate.getMonth() + "' data-year='" + printDate.getFullYear() + "'") + ">" + // actions
+ (otherMonth && !showOtherMonths ? "&#xa0;" : // display for other months
+ (unselectable ? "<span class='ui-state-default'>" + printDate.getDate() + "</span>" : "<a class='ui-state-default" +
+ (printDate.getTime() === today.getTime() ? " ui-state-highlight" : "") +
+ (printDate.getTime() === currentDate.getTime() ? " ui-state-active" : "") + // highlight selected day
+ (otherMonth ? " ui-priority-secondary" : "") + // distinguish dates from other months
+ "' href='#'>" + printDate.getDate() + "</a>")) + "</td>"; // display selectable date
+ printDate.setDate(printDate.getDate() + 1);
+ printDate = this._daylightSavingAdjust(printDate);
+ }
+ calender += tbody + "</tr>";
+ }
+ drawMonth++;
+ if (drawMonth > 11) {
+ drawMonth = 0;
+ drawYear++;
+ }
+ calender += "</tbody></table>" + (isMultiMonth ? "</div>" +
+ ((numMonths[0] > 0 && col === numMonths[1]-1) ? "<div class='ui-datepicker-row-break'></div>" : "") : "");
+ group += calender;
+ }
+ html += group;
+ }
+ html += buttonPanel;
+ inst._keyEvent = false;
+ return html;
+ },
+
+ /* Generate the month and year header. */
+ _generateMonthYearHeader: function(inst, drawMonth, drawYear, minDate, maxDate,
+ secondary, monthNames, monthNamesShort) {
+
+ var inMinYear, inMaxYear, month, years, thisYear, determineYear, year, endYear,
+ changeMonth = this._get(inst, "changeMonth"),
+ changeYear = this._get(inst, "changeYear"),
+ showMonthAfterYear = this._get(inst, "showMonthAfterYear"),
+ html = "<div class='ui-datepicker-title'>",
+ monthHtml = "";
+
+ // month selection
+ if (secondary || !changeMonth) {
+ monthHtml += "<span class='ui-datepicker-month'>" + monthNames[drawMonth] + "</span>";
+ } else {
+ inMinYear = (minDate && minDate.getFullYear() === drawYear);
+ inMaxYear = (maxDate && maxDate.getFullYear() === drawYear);
+ monthHtml += "<select class='ui-datepicker-month' data-handler='selectMonth' data-event='change'>";
+ for ( month = 0; month < 12; month++) {
+ if ((!inMinYear || month >= minDate.getMonth()) && (!inMaxYear || month <= maxDate.getMonth())) {
+ monthHtml += "<option value='" + month + "'" +
+ (month === drawMonth ? " selected='selected'" : "") +
+ ">" + monthNamesShort[month] + "</option>";
+ }
+ }
+ monthHtml += "</select>";
+ }
+
+ if (!showMonthAfterYear) {
+ html += monthHtml + (secondary || !(changeMonth && changeYear) ? "&#xa0;" : "");
+ }
+
+ // year selection
+ if ( !inst.yearshtml ) {
+ inst.yearshtml = "";
+ if (secondary || !changeYear) {
+ html += "<span class='ui-datepicker-year'>" + drawYear + "</span>";
+ } else {
+ // determine range of years to display
+ years = this._get(inst, "yearRange").split(":");
+ thisYear = new Date().getFullYear();
+ determineYear = function(value) {
+ var year = (value.match(/c[+\-].*/) ? drawYear + parseInt(value.substring(1), 10) :
+ (value.match(/[+\-].*/) ? thisYear + parseInt(value, 10) :
+ parseInt(value, 10)));
+ return (isNaN(year) ? thisYear : year);
+ };
+ year = determineYear(years[0]);
+ endYear = Math.max(year, determineYear(years[1] || ""));
+ year = (minDate ? Math.max(year, minDate.getFullYear()) : year);
+ endYear = (maxDate ? Math.min(endYear, maxDate.getFullYear()) : endYear);
+ inst.yearshtml += "<select class='ui-datepicker-year' data-handler='selectYear' data-event='change'>";
+ for (; year <= endYear; year++) {
+ inst.yearshtml += "<option value='" + year + "'" +
+ (year === drawYear ? " selected='selected'" : "") +
+ ">" + year + "</option>";
+ }
+ inst.yearshtml += "</select>";
+
+ html += inst.yearshtml;
+ inst.yearshtml = null;
+ }
+ }
+
+ html += this._get(inst, "yearSuffix");
+ if (showMonthAfterYear) {
+ html += (secondary || !(changeMonth && changeYear) ? "&#xa0;" : "") + monthHtml;
+ }
+ html += "</div>"; // Close datepicker_header
+ return html;
+ },
+
+ /* Adjust one of the date sub-fields. */
+ _adjustInstDate: function(inst, offset, period) {
+ var year = inst.drawYear + (period === "Y" ? offset : 0),
+ month = inst.drawMonth + (period === "M" ? offset : 0),
+ day = Math.min(inst.selectedDay, this._getDaysInMonth(year, month)) + (period === "D" ? offset : 0),
+ date = this._restrictMinMax(inst, this._daylightSavingAdjust(new Date(year, month, day)));
+
+ inst.selectedDay = date.getDate();
+ inst.drawMonth = inst.selectedMonth = date.getMonth();
+ inst.drawYear = inst.selectedYear = date.getFullYear();
+ if (period === "M" || period === "Y") {
+ this._notifyChange(inst);
+ }
+ },
+
+ /* Ensure a date is within any min/max bounds. */
+ _restrictMinMax: function(inst, date) {
+ var minDate = this._getMinMaxDate(inst, "min"),
+ maxDate = this._getMinMaxDate(inst, "max"),
+ newDate = (minDate && date < minDate ? minDate : date);
+ return (maxDate && newDate > maxDate ? maxDate : newDate);
+ },
+
+ /* Notify change of month/year. */
+ _notifyChange: function(inst) {
+ var onChange = this._get(inst, "onChangeMonthYear");
+ if (onChange) {
+ onChange.apply((inst.input ? inst.input[0] : null),
+ [inst.selectedYear, inst.selectedMonth + 1, inst]);
+ }
+ },
+
+ /* Determine the number of months to show. */
+ _getNumberOfMonths: function(inst) {
+ var numMonths = this._get(inst, "numberOfMonths");
+ return (numMonths == null ? [1, 1] : (typeof numMonths === "number" ? [1, numMonths] : numMonths));
+ },
+
+ /* Determine the current maximum date - ensure no time components are set. */
+ _getMinMaxDate: function(inst, minMax) {
+ return this._determineDate(inst, this._get(inst, minMax + "Date"), null);
+ },
+
+ /* Find the number of days in a given month. */
+ _getDaysInMonth: function(year, month) {
+ return 32 - this._daylightSavingAdjust(new Date(year, month, 32)).getDate();
+ },
+
+ /* Find the day of the week of the first of a month. */
+ _getFirstDayOfMonth: function(year, month) {
+ return new Date(year, month, 1).getDay();
+ },
+
+ /* Determines if we should allow a "next/prev" month display change. */
+ _canAdjustMonth: function(inst, offset, curYear, curMonth) {
+ var numMonths = this._getNumberOfMonths(inst),
+ date = this._daylightSavingAdjust(new Date(curYear,
+ curMonth + (offset < 0 ? offset : numMonths[0] * numMonths[1]), 1));
+
+ if (offset < 0) {
+ date.setDate(this._getDaysInMonth(date.getFullYear(), date.getMonth()));
+ }
+ return this._isInRange(inst, date);
+ },
+
+ /* Is the given date in the accepted range? */
+ _isInRange: function(inst, date) {
+ var yearSplit, currentYear,
+ minDate = this._getMinMaxDate(inst, "min"),
+ maxDate = this._getMinMaxDate(inst, "max"),
+ minYear = null,
+ maxYear = null,
+ years = this._get(inst, "yearRange");
+ if (years){
+ yearSplit = years.split(":");
+ currentYear = new Date().getFullYear();
+ minYear = parseInt(yearSplit[0], 10);
+ maxYear = parseInt(yearSplit[1], 10);
+ if ( yearSplit[0].match(/[+\-].*/) ) {
+ minYear += currentYear;
+ }
+ if ( yearSplit[1].match(/[+\-].*/) ) {
+ maxYear += currentYear;
+ }
+ }
+
+ return ((!minDate || date.getTime() >= minDate.getTime()) &&
+ (!maxDate || date.getTime() <= maxDate.getTime()) &&
+ (!minYear || date.getFullYear() >= minYear) &&
+ (!maxYear || date.getFullYear() <= maxYear));
+ },
+
+ /* Provide the configuration settings for formatting/parsing. */
+ _getFormatConfig: function(inst) {
+ var shortYearCutoff = this._get(inst, "shortYearCutoff");
+ shortYearCutoff = (typeof shortYearCutoff !== "string" ? shortYearCutoff :
+ new Date().getFullYear() % 100 + parseInt(shortYearCutoff, 10));
+ return {shortYearCutoff: shortYearCutoff,
+ dayNamesShort: this._get(inst, "dayNamesShort"), dayNames: this._get(inst, "dayNames"),
+ monthNamesShort: this._get(inst, "monthNamesShort"), monthNames: this._get(inst, "monthNames")};
+ },
+
+ /* Format the given date for display. */
+ _formatDate: function(inst, day, month, year) {
+ if (!day) {
+ inst.currentDay = inst.selectedDay;
+ inst.currentMonth = inst.selectedMonth;
+ inst.currentYear = inst.selectedYear;
+ }
+ var date = (day ? (typeof day === "object" ? day :
+ this._daylightSavingAdjust(new Date(year, month, day))) :
+ this._daylightSavingAdjust(new Date(inst.currentYear, inst.currentMonth, inst.currentDay)));
+ return this.formatDate(this._get(inst, "dateFormat"), date, this._getFormatConfig(inst));
+ }
+});
+
+/*
+ * Bind hover events for datepicker elements.
+ * Done via delegate so the binding only occurs once in the lifetime of the parent div.
+ * Global instActive, set by _updateDatepicker allows the handlers to find their way back to the active picker.
+ */
+function bindHover(dpDiv) {
+ var selector = "button, .ui-datepicker-prev, .ui-datepicker-next, .ui-datepicker-calendar td a";
+ return dpDiv.delegate(selector, "mouseout", function() {
+ $(this).removeClass("ui-state-hover");
+ if (this.className.indexOf("ui-datepicker-prev") !== -1) {
+ $(this).removeClass("ui-datepicker-prev-hover");
+ }
+ if (this.className.indexOf("ui-datepicker-next") !== -1) {
+ $(this).removeClass("ui-datepicker-next-hover");
+ }
+ })
+ .delegate(selector, "mouseover", function(){
+ if (!$.datepicker._isDisabledDatepicker( instActive.inline ? dpDiv.parent()[0] : instActive.input[0])) {
+ $(this).parents(".ui-datepicker-calendar").find("a").removeClass("ui-state-hover");
+ $(this).addClass("ui-state-hover");
+ if (this.className.indexOf("ui-datepicker-prev") !== -1) {
+ $(this).addClass("ui-datepicker-prev-hover");
+ }
+ if (this.className.indexOf("ui-datepicker-next") !== -1) {
+ $(this).addClass("ui-datepicker-next-hover");
+ }
+ }
+ });
+}
+
+/* jQuery extend now ignores nulls! */
+function extendRemove(target, props) {
+ $.extend(target, props);
+ for (var name in props) {
+ if (props[name] == null) {
+ target[name] = props[name];
+ }
+ }
+ return target;
+}
+
+/* Invoke the datepicker functionality.
+ @param options string - a command, optionally followed by additional parameters or
+ Object - settings for attaching new datepicker functionality
+ @return jQuery object */
+$.fn.datepicker = function(options){
+
+ /* Verify an empty collection wasn't passed - Fixes #6976 */
+ if ( !this.length ) {
+ return this;
+ }
+
+ /* Initialise the date picker. */
+ if (!$.datepicker.initialized) {
+ $(document).mousedown($.datepicker._checkExternalClick);
+ $.datepicker.initialized = true;
+ }
+
+ /* Append datepicker main container to body if not exist. */
+ if ($("#"+$.datepicker._mainDivId).length === 0) {
+ $("body").append($.datepicker.dpDiv);
+ }
+
+ var otherArgs = Array.prototype.slice.call(arguments, 1);
+ if (typeof options === "string" && (options === "isDisabled" || options === "getDate" || options === "widget")) {
+ return $.datepicker["_" + options + "Datepicker"].
+ apply($.datepicker, [this[0]].concat(otherArgs));
+ }
+ if (options === "option" && arguments.length === 2 && typeof arguments[1] === "string") {
+ return $.datepicker["_" + options + "Datepicker"].
+ apply($.datepicker, [this[0]].concat(otherArgs));
+ }
+ return this.each(function() {
+ typeof options === "string" ?
+ $.datepicker["_" + options + "Datepicker"].
+ apply($.datepicker, [this].concat(otherArgs)) :
+ $.datepicker._attachDatepicker(this, options);
+ });
+};
+
+$.datepicker = new Datepicker(); // singleton instance
+$.datepicker.initialized = false;
+$.datepicker.uuid = new Date().getTime();
+$.datepicker.version = "1.10.3";
+
+})(jQuery);
+
+(function( $, undefined ) {
+
+var sizeRelatedOptions = {
+ buttons: true,
+ height: true,
+ maxHeight: true,
+ maxWidth: true,
+ minHeight: true,
+ minWidth: true,
+ width: true
+ },
+ resizableRelatedOptions = {
+ maxHeight: true,
+ maxWidth: true,
+ minHeight: true,
+ minWidth: true
+ };
+
+$.widget( "ui.dialog", {
+ version: "1.10.3",
+ options: {
+ appendTo: "body",
+ autoOpen: true,
+ buttons: [],
+ closeOnEscape: true,
+ closeText: "close",
+ dialogClass: "",
+ draggable: true,
+ hide: null,
+ height: "auto",
+ maxHeight: null,
+ maxWidth: null,
+ minHeight: 150,
+ minWidth: 150,
+ modal: false,
+ position: {
+ my: "center",
+ at: "center",
+ of: window,
+ collision: "fit",
+ // Ensure the titlebar is always visible
+ using: function( pos ) {
+ var topOffset = $( this ).css( pos ).offset().top;
+ if ( topOffset < 0 ) {
+ $( this ).css( "top", pos.top - topOffset );
+ }
+ }
+ },
+ resizable: true,
+ show: null,
+ title: null,
+ width: 300,
+
+ // callbacks
+ beforeClose: null,
+ close: null,
+ drag: null,
+ dragStart: null,
+ dragStop: null,
+ focus: null,
+ open: null,
+ resize: null,
+ resizeStart: null,
+ resizeStop: null
+ },
+
+ _create: function() {
+ this.originalCss = {
+ display: this.element[0].style.display,
+ width: this.element[0].style.width,
+ minHeight: this.element[0].style.minHeight,
+ maxHeight: this.element[0].style.maxHeight,
+ height: this.element[0].style.height
+ };
+ this.originalPosition = {
+ parent: this.element.parent(),
+ index: this.element.parent().children().index( this.element )
+ };
+ this.originalTitle = this.element.attr("title");
+ this.options.title = this.options.title || this.originalTitle;
+
+ this._createWrapper();
+
+ this.element
+ .show()
+ .removeAttr("title")
+ .addClass("ui-dialog-content ui-widget-content")
+ .appendTo( this.uiDialog );
+
+ this._createTitlebar();
+ this._createButtonPane();
+
+ if ( this.options.draggable && $.fn.draggable ) {
+ this._makeDraggable();
+ }
+ if ( this.options.resizable && $.fn.resizable ) {
+ this._makeResizable();
+ }
+
+ this._isOpen = false;
+ },
+
+ _init: function() {
+ if ( this.options.autoOpen ) {
+ this.open();
+ }
+ },
+
+ _appendTo: function() {
+ var element = this.options.appendTo;
+ if ( element && (element.jquery || element.nodeType) ) {
+ return $( element );
+ }
+ return this.document.find( element || "body" ).eq( 0 );
+ },
+
+ _destroy: function() {
+ var next,
+ originalPosition = this.originalPosition;
+
+ this._destroyOverlay();
+
+ this.element
+ .removeUniqueId()
+ .removeClass("ui-dialog-content ui-widget-content")
+ .css( this.originalCss )
+ // Without detaching first, the following becomes really slow
+ .detach();
+
+ this.uiDialog.stop( true, true ).remove();
+
+ if ( this.originalTitle ) {
+ this.element.attr( "title", this.originalTitle );
+ }
+
+ next = originalPosition.parent.children().eq( originalPosition.index );
+ // Don't try to place the dialog next to itself (#8613)
+ if ( next.length && next[0] !== this.element[0] ) {
+ next.before( this.element );
+ } else {
+ originalPosition.parent.append( this.element );
+ }
+ },
+
+ widget: function() {
+ return this.uiDialog;
+ },
+
+ disable: $.noop,
+ enable: $.noop,
+
+ close: function( event ) {
+ var that = this;
+
+ if ( !this._isOpen || this._trigger( "beforeClose", event ) === false ) {
+ return;
+ }
+
+ this._isOpen = false;
+ this._destroyOverlay();
+
+ if ( !this.opener.filter(":focusable").focus().length ) {
+ // Hiding a focused element doesn't trigger blur in WebKit
+ // so in case we have nothing to focus on, explicitly blur the active element
+ // https://bugs.webkit.org/show_bug.cgi?id=47182
+ $( this.document[0].activeElement ).blur();
+ }
+
+ this._hide( this.uiDialog, this.options.hide, function() {
+ that._trigger( "close", event );
+ });
+ },
+
+ isOpen: function() {
+ return this._isOpen;
+ },
+
+ moveToTop: function() {
+ this._moveToTop();
+ },
+
+ _moveToTop: function( event, silent ) {
+ var moved = !!this.uiDialog.nextAll(":visible").insertBefore( this.uiDialog ).length;
+ if ( moved && !silent ) {
+ this._trigger( "focus", event );
+ }
+ return moved;
+ },
+
+ open: function() {
+ var that = this;
+ if ( this._isOpen ) {
+ if ( this._moveToTop() ) {
+ this._focusTabbable();
+ }
+ return;
+ }
+
+ this._isOpen = true;
+ this.opener = $( this.document[0].activeElement );
+
+ this._size();
+ this._position();
+ this._createOverlay();
+ this._moveToTop( null, true );
+ this._show( this.uiDialog, this.options.show, function() {
+ that._focusTabbable();
+ that._trigger("focus");
+ });
+
+ this._trigger("open");
+ },
+
+ _focusTabbable: function() {
+ // Set focus to the first match:
+ // 1. First element inside the dialog matching [autofocus]
+ // 2. Tabbable element inside the content element
+ // 3. Tabbable element inside the buttonpane
+ // 4. The close button
+ // 5. The dialog itself
+ var hasFocus = this.element.find("[autofocus]");
+ if ( !hasFocus.length ) {
+ hasFocus = this.element.find(":tabbable");
+ }
+ if ( !hasFocus.length ) {
+ hasFocus = this.uiDialogButtonPane.find(":tabbable");
+ }
+ if ( !hasFocus.length ) {
+ hasFocus = this.uiDialogTitlebarClose.filter(":tabbable");
+ }
+ if ( !hasFocus.length ) {
+ hasFocus = this.uiDialog;
+ }
+ hasFocus.eq( 0 ).focus();
+ },
+
+ _keepFocus: function( event ) {
+ function checkFocus() {
+ var activeElement = this.document[0].activeElement,
+ isActive = this.uiDialog[0] === activeElement ||
+ $.contains( this.uiDialog[0], activeElement );
+ if ( !isActive ) {
+ this._focusTabbable();
+ }
+ }
+ event.preventDefault();
+ checkFocus.call( this );
+ // support: IE
+ // IE <= 8 doesn't prevent moving focus even with event.preventDefault()
+ // so we check again later
+ this._delay( checkFocus );
+ },
+
+ _createWrapper: function() {
+ this.uiDialog = $("<div>")
+ .addClass( "ui-dialog ui-widget ui-widget-content ui-corner-all ui-front " +
+ this.options.dialogClass )
+ .hide()
+ .attr({
+ // Setting tabIndex makes the div focusable
+ tabIndex: -1,
+ role: "dialog"
+ })
+ .appendTo( this._appendTo() );
+
+ this._on( this.uiDialog, {
+ keydown: function( event ) {
+ if ( this.options.closeOnEscape && !event.isDefaultPrevented() && event.keyCode &&
+ event.keyCode === $.ui.keyCode.ESCAPE ) {
+ event.preventDefault();
+ this.close( event );
+ return;
+ }
+
+ // prevent tabbing out of dialogs
+ if ( event.keyCode !== $.ui.keyCode.TAB ) {
+ return;
+ }
+ var tabbables = this.uiDialog.find(":tabbable"),
+ first = tabbables.filter(":first"),
+ last = tabbables.filter(":last");
+
+ if ( ( event.target === last[0] || event.target === this.uiDialog[0] ) && !event.shiftKey ) {
+ first.focus( 1 );
+ event.preventDefault();
+ } else if ( ( event.target === first[0] || event.target === this.uiDialog[0] ) && event.shiftKey ) {
+ last.focus( 1 );
+ event.preventDefault();
+ }
+ },
+ mousedown: function( event ) {
+ if ( this._moveToTop( event ) ) {
+ this._focusTabbable();
+ }
+ }
+ });
+
+ // We assume that any existing aria-describedby attribute means
+ // that the dialog content is marked up properly
+ // otherwise we brute force the content as the description
+ if ( !this.element.find("[aria-describedby]").length ) {
+ this.uiDialog.attr({
+ "aria-describedby": this.element.uniqueId().attr("id")
+ });
+ }
+ },
+
+ _createTitlebar: function() {
+ var uiDialogTitle;
+
+ this.uiDialogTitlebar = $("<div>")
+ .addClass("ui-dialog-titlebar ui-widget-header ui-corner-all ui-helper-clearfix")
+ .prependTo( this.uiDialog );
+ this._on( this.uiDialogTitlebar, {
+ mousedown: function( event ) {
+ // Don't prevent click on close button (#8838)
+ // Focusing a dialog that is partially scrolled out of view
+ // causes the browser to scroll it into view, preventing the click event
+ if ( !$( event.target ).closest(".ui-dialog-titlebar-close") ) {
+ // Dialog isn't getting focus when dragging (#8063)
+ this.uiDialog.focus();
+ }
+ }
+ });
+
+ this.uiDialogTitlebarClose = $("<button></button>")
+ .button({
+ label: this.options.closeText,
+ icons: {
+ primary: "ui-icon-closethick"
+ },
+ text: false
+ })
+ .addClass("ui-dialog-titlebar-close")
+ .appendTo( this.uiDialogTitlebar );
+ this._on( this.uiDialogTitlebarClose, {
+ click: function( event ) {
+ event.preventDefault();
+ this.close( event );
+ }
+ });
+
+ uiDialogTitle = $("<span>")
+ .uniqueId()
+ .addClass("ui-dialog-title")
+ .prependTo( this.uiDialogTitlebar );
+ this._title( uiDialogTitle );
+
+ this.uiDialog.attr({
+ "aria-labelledby": uiDialogTitle.attr("id")
+ });
+ },
+
+ _title: function( title ) {
+ if ( !this.options.title ) {
+ title.html("&#160;");
+ }
+ title.text( this.options.title );
+ },
+
+ _createButtonPane: function() {
+ this.uiDialogButtonPane = $("<div>")
+ .addClass("ui-dialog-buttonpane ui-widget-content ui-helper-clearfix");
+
+ this.uiButtonSet = $("<div>")
+ .addClass("ui-dialog-buttonset")
+ .appendTo( this.uiDialogButtonPane );
+
+ this._createButtons();
+ },
+
+ _createButtons: function() {
+ var that = this,
+ buttons = this.options.buttons;
+
+ // if we already have a button pane, remove it
+ this.uiDialogButtonPane.remove();
+ this.uiButtonSet.empty();
+
+ if ( $.isEmptyObject( buttons ) || ($.isArray( buttons ) && !buttons.length) ) {
+ this.uiDialog.removeClass("ui-dialog-buttons");
+ return;
+ }
+
+ $.each( buttons, function( name, props ) {
+ var click, buttonOptions;
+ props = $.isFunction( props ) ?
+ { click: props, text: name } :
+ props;
+ // Default to a non-submitting button
+ props = $.extend( { type: "button" }, props );
+ // Change the context for the click callback to be the main element
+ click = props.click;
+ props.click = function() {
+ click.apply( that.element[0], arguments );
+ };
+ buttonOptions = {
+ icons: props.icons,
+ text: props.showText
+ };
+ delete props.icons;
+ delete props.showText;
+ $( "<button></button>", props )
+ .button( buttonOptions )
+ .appendTo( that.uiButtonSet );
+ });
+ this.uiDialog.addClass("ui-dialog-buttons");
+ this.uiDialogButtonPane.appendTo( this.uiDialog );
+ },
+
+ _makeDraggable: function() {
+ var that = this,
+ options = this.options;
+
+ function filteredUi( ui ) {
+ return {
+ position: ui.position,
+ offset: ui.offset
+ };
+ }
+
+ this.uiDialog.draggable({
+ cancel: ".ui-dialog-content, .ui-dialog-titlebar-close",
+ handle: ".ui-dialog-titlebar",
+ containment: "document",
+ start: function( event, ui ) {
+ $( this ).addClass("ui-dialog-dragging");
+ that._blockFrames();
+ that._trigger( "dragStart", event, filteredUi( ui ) );
+ },
+ drag: function( event, ui ) {
+ that._trigger( "drag", event, filteredUi( ui ) );
+ },
+ stop: function( event, ui ) {
+ options.position = [
+ ui.position.left - that.document.scrollLeft(),
+ ui.position.top - that.document.scrollTop()
+ ];
+ $( this ).removeClass("ui-dialog-dragging");
+ that._unblockFrames();
+ that._trigger( "dragStop", event, filteredUi( ui ) );
+ }
+ });
+ },
+
+ _makeResizable: function() {
+ var that = this,
+ options = this.options,
+ handles = options.resizable,
+ // .ui-resizable has position: relative defined in the stylesheet
+ // but dialogs have to use absolute or fixed positioning
+ position = this.uiDialog.css("position"),
+ resizeHandles = typeof handles === "string" ?
+ handles :
+ "n,e,s,w,se,sw,ne,nw";
+
+ function filteredUi( ui ) {
+ return {
+ originalPosition: ui.originalPosition,
+ originalSize: ui.originalSize,
+ position: ui.position,
+ size: ui.size
+ };
+ }
+
+ this.uiDialog.resizable({
+ cancel: ".ui-dialog-content",
+ containment: "document",
+ alsoResize: this.element,
+ maxWidth: options.maxWidth,
+ maxHeight: options.maxHeight,
+ minWidth: options.minWidth,
+ minHeight: this._minHeight(),
+ handles: resizeHandles,
+ start: function( event, ui ) {
+ $( this ).addClass("ui-dialog-resizing");
+ that._blockFrames();
+ that._trigger( "resizeStart", event, filteredUi( ui ) );
+ },
+ resize: function( event, ui ) {
+ that._trigger( "resize", event, filteredUi( ui ) );
+ },
+ stop: function( event, ui ) {
+ options.height = $( this ).height();
+ options.width = $( this ).width();
+ $( this ).removeClass("ui-dialog-resizing");
+ that._unblockFrames();
+ that._trigger( "resizeStop", event, filteredUi( ui ) );
+ }
+ })
+ .css( "position", position );
+ },
+
+ _minHeight: function() {
+ var options = this.options;
+
+ return options.height === "auto" ?
+ options.minHeight :
+ Math.min( options.minHeight, options.height );
+ },
+
+ _position: function() {
+ // Need to show the dialog to get the actual offset in the position plugin
+ var isVisible = this.uiDialog.is(":visible");
+ if ( !isVisible ) {
+ this.uiDialog.show();
+ }
+ this.uiDialog.position( this.options.position );
+ if ( !isVisible ) {
+ this.uiDialog.hide();
+ }
+ },
+
+ _setOptions: function( options ) {
+ var that = this,
+ resize = false,
+ resizableOptions = {};
+
+ $.each( options, function( key, value ) {
+ that._setOption( key, value );
+
+ if ( key in sizeRelatedOptions ) {
+ resize = true;
+ }
+ if ( key in resizableRelatedOptions ) {
+ resizableOptions[ key ] = value;
+ }
+ });
+
+ if ( resize ) {
+ this._size();
+ this._position();
+ }
+ if ( this.uiDialog.is(":data(ui-resizable)") ) {
+ this.uiDialog.resizable( "option", resizableOptions );
+ }
+ },
+
+ _setOption: function( key, value ) {
+ /*jshint maxcomplexity:15*/
+ var isDraggable, isResizable,
+ uiDialog = this.uiDialog;
+
+ if ( key === "dialogClass" ) {
+ uiDialog
+ .removeClass( this.options.dialogClass )
+ .addClass( value );
+ }
+
+ if ( key === "disabled" ) {
+ return;
+ }
+
+ this._super( key, value );
+
+ if ( key === "appendTo" ) {
+ this.uiDialog.appendTo( this._appendTo() );
+ }
+
+ if ( key === "buttons" ) {
+ this._createButtons();
+ }
+
+ if ( key === "closeText" ) {
+ this.uiDialogTitlebarClose.button({
+ // Ensure that we always pass a string
+ label: "" + value
+ });
+ }
+
+ if ( key === "draggable" ) {
+ isDraggable = uiDialog.is(":data(ui-draggable)");
+ if ( isDraggable && !value ) {
+ uiDialog.draggable("destroy");
+ }
+
+ if ( !isDraggable && value ) {
+ this._makeDraggable();
+ }
+ }
+
+ if ( key === "position" ) {
+ this._position();
+ }
+
+ if ( key === "resizable" ) {
+ // currently resizable, becoming non-resizable
+ isResizable = uiDialog.is(":data(ui-resizable)");
+ if ( isResizable && !value ) {
+ uiDialog.resizable("destroy");
+ }
+
+ // currently resizable, changing handles
+ if ( isResizable && typeof value === "string" ) {
+ uiDialog.resizable( "option", "handles", value );
+ }
+
+ // currently non-resizable, becoming resizable
+ if ( !isResizable && value !== false ) {
+ this._makeResizable();
+ }
+ }
+
+ if ( key === "title" ) {
+ this._title( this.uiDialogTitlebar.find(".ui-dialog-title") );
+ }
+ },
+
+ _size: function() {
+ // If the user has resized the dialog, the .ui-dialog and .ui-dialog-content
+ // divs will both have width and height set, so we need to reset them
+ var nonContentHeight, minContentHeight, maxContentHeight,
+ options = this.options;
+
+ // Reset content sizing
+ this.element.show().css({
+ width: "auto",
+ minHeight: 0,
+ maxHeight: "none",
+ height: 0
+ });
+
+ if ( options.minWidth > options.width ) {
+ options.width = options.minWidth;
+ }
+
+ // reset wrapper sizing
+ // determine the height of all the non-content elements
+ nonContentHeight = this.uiDialog.css({
+ height: "auto",
+ width: options.width
+ })
+ .outerHeight();
+ minContentHeight = Math.max( 0, options.minHeight - nonContentHeight );
+ maxContentHeight = typeof options.maxHeight === "number" ?
+ Math.max( 0, options.maxHeight - nonContentHeight ) :
+ "none";
+
+ if ( options.height === "auto" ) {
+ this.element.css({
+ minHeight: minContentHeight,
+ maxHeight: maxContentHeight,
+ height: "auto"
+ });
+ } else {
+ this.element.height( Math.max( 0, options.height - nonContentHeight ) );
+ }
+
+ if (this.uiDialog.is(":data(ui-resizable)") ) {
+ this.uiDialog.resizable( "option", "minHeight", this._minHeight() );
+ }
+ },
+
+ _blockFrames: function() {
+ this.iframeBlocks = this.document.find( "iframe" ).map(function() {
+ var iframe = $( this );
+
+ return $( "<div>" )
+ .css({
+ position: "absolute",
+ width: iframe.outerWidth(),
+ height: iframe.outerHeight()
+ })
+ .appendTo( iframe.parent() )
+ .offset( iframe.offset() )[0];
+ });
+ },
+
+ _unblockFrames: function() {
+ if ( this.iframeBlocks ) {
+ this.iframeBlocks.remove();
+ delete this.iframeBlocks;
+ }
+ },
+
+ _allowInteraction: function( event ) {
+ if ( $( event.target ).closest(".ui-dialog").length ) {
+ return true;
+ }
+
+ // TODO: Remove hack when datepicker implements
+ // the .ui-front logic (#8989)
+ return !!$( event.target ).closest(".ui-datepicker").length;
+ },
+
+ _createOverlay: function() {
+ if ( !this.options.modal ) {
+ return;
+ }
+
+ var that = this,
+ widgetFullName = this.widgetFullName;
+ if ( !$.ui.dialog.overlayInstances ) {
+ // Prevent use of anchors and inputs.
+ // We use a delay in case the overlay is created from an
+ // event that we're going to be cancelling. (#2804)
+ this._delay(function() {
+ // Handle .dialog().dialog("close") (#4065)
+ if ( $.ui.dialog.overlayInstances ) {
+ this.document.bind( "focusin.dialog", function( event ) {
+ if ( !that._allowInteraction( event ) ) {
+ event.preventDefault();
+ $(".ui-dialog:visible:last .ui-dialog-content")
+ .data( widgetFullName )._focusTabbable();
+ }
+ });
+ }
+ });
+ }
+
+ this.overlay = $("<div>")
+ .addClass("ui-widget-overlay ui-front")
+ .appendTo( this._appendTo() );
+ this._on( this.overlay, {
+ mousedown: "_keepFocus"
+ });
+ $.ui.dialog.overlayInstances++;
+ },
+
+ _destroyOverlay: function() {
+ if ( !this.options.modal ) {
+ return;
+ }
+
+ if ( this.overlay ) {
+ $.ui.dialog.overlayInstances--;
+
+ if ( !$.ui.dialog.overlayInstances ) {
+ this.document.unbind( "focusin.dialog" );
+ }
+ this.overlay.remove();
+ this.overlay = null;
+ }
+ }
+});
+
+$.ui.dialog.overlayInstances = 0;
+
+// DEPRECATED
+if ( $.uiBackCompat !== false ) {
+ // position option with array notation
+ // just override with old implementation
+ $.widget( "ui.dialog", $.ui.dialog, {
+ _position: function() {
+ var position = this.options.position,
+ myAt = [],
+ offset = [ 0, 0 ],
+ isVisible;
+
+ if ( position ) {
+ if ( typeof position === "string" || (typeof position === "object" && "0" in position ) ) {
+ myAt = position.split ? position.split(" ") : [ position[0], position[1] ];
+ if ( myAt.length === 1 ) {
+ myAt[1] = myAt[0];
+ }
+
+ $.each( [ "left", "top" ], function( i, offsetPosition ) {
+ if ( +myAt[ i ] === myAt[ i ] ) {
+ offset[ i ] = myAt[ i ];
+ myAt[ i ] = offsetPosition;
+ }
+ });
+
+ position = {
+ my: myAt[0] + (offset[0] < 0 ? offset[0] : "+" + offset[0]) + " " +
+ myAt[1] + (offset[1] < 0 ? offset[1] : "+" + offset[1]),
+ at: myAt.join(" ")
+ };
+ }
+
+ position = $.extend( {}, $.ui.dialog.prototype.options.position, position );
+ } else {
+ position = $.ui.dialog.prototype.options.position;
+ }
+
+ // need to show the dialog to get the actual offset in the position plugin
+ isVisible = this.uiDialog.is(":visible");
+ if ( !isVisible ) {
+ this.uiDialog.show();
+ }
+ this.uiDialog.position( position );
+ if ( !isVisible ) {
+ this.uiDialog.hide();
+ }
+ }
+ });
+}
+
+}( jQuery ) );
+
+(function( $, undefined ) {
+
+var rvertical = /up|down|vertical/,
+ rpositivemotion = /up|left|vertical|horizontal/;
+
+$.effects.effect.blind = function( o, done ) {
+ // Create element
+ var el = $( this ),
+ props = [ "position", "top", "bottom", "left", "right", "height", "width" ],
+ mode = $.effects.setMode( el, o.mode || "hide" ),
+ direction = o.direction || "up",
+ vertical = rvertical.test( direction ),
+ ref = vertical ? "height" : "width",
+ ref2 = vertical ? "top" : "left",
+ motion = rpositivemotion.test( direction ),
+ animation = {},
+ show = mode === "show",
+ wrapper, distance, margin;
+
+ // if already wrapped, the wrapper's properties are my property. #6245
+ if ( el.parent().is( ".ui-effects-wrapper" ) ) {
+ $.effects.save( el.parent(), props );
+ } else {
+ $.effects.save( el, props );
+ }
+ el.show();
+ wrapper = $.effects.createWrapper( el ).css({
+ overflow: "hidden"
+ });
+
+ distance = wrapper[ ref ]();
+ margin = parseFloat( wrapper.css( ref2 ) ) || 0;
+
+ animation[ ref ] = show ? distance : 0;
+ if ( !motion ) {
+ el
+ .css( vertical ? "bottom" : "right", 0 )
+ .css( vertical ? "top" : "left", "auto" )
+ .css({ position: "absolute" });
+
+ animation[ ref2 ] = show ? margin : distance + margin;
+ }
+
+ // start at 0 if we are showing
+ if ( show ) {
+ wrapper.css( ref, 0 );
+ if ( ! motion ) {
+ wrapper.css( ref2, margin + distance );
+ }
+ }
+
+ // Animate
+ wrapper.animate( animation, {
+ duration: o.duration,
+ easing: o.easing,
+ queue: false,
+ complete: function() {
+ if ( mode === "hide" ) {
+ el.hide();
+ }
+ $.effects.restore( el, props );
+ $.effects.removeWrapper( el );
+ done();
+ }
+ });
+
+};
+
+})(jQuery);
+
+(function( $, undefined ) {
+
+$.effects.effect.bounce = function( o, done ) {
+ var el = $( this ),
+ props = [ "position", "top", "bottom", "left", "right", "height", "width" ],
+
+ // defaults:
+ mode = $.effects.setMode( el, o.mode || "effect" ),
+ hide = mode === "hide",
+ show = mode === "show",
+ direction = o.direction || "up",
+ distance = o.distance,
+ times = o.times || 5,
+
+ // number of internal animations
+ anims = times * 2 + ( show || hide ? 1 : 0 ),
+ speed = o.duration / anims,
+ easing = o.easing,
+
+ // utility:
+ ref = ( direction === "up" || direction === "down" ) ? "top" : "left",
+ motion = ( direction === "up" || direction === "left" ),
+ i,
+ upAnim,
+ downAnim,
+
+ // we will need to re-assemble the queue to stack our animations in place
+ queue = el.queue(),
+ queuelen = queue.length;
+
+ // Avoid touching opacity to prevent clearType and PNG issues in IE
+ if ( show || hide ) {
+ props.push( "opacity" );
+ }
+
+ $.effects.save( el, props );
+ el.show();
+ $.effects.createWrapper( el ); // Create Wrapper
+
+ // default distance for the BIGGEST bounce is the outer Distance / 3
+ if ( !distance ) {
+ distance = el[ ref === "top" ? "outerHeight" : "outerWidth" ]() / 3;
+ }
+
+ if ( show ) {
+ downAnim = { opacity: 1 };
+ downAnim[ ref ] = 0;
+
+ // if we are showing, force opacity 0 and set the initial position
+ // then do the "first" animation
+ el.css( "opacity", 0 )
+ .css( ref, motion ? -distance * 2 : distance * 2 )
+ .animate( downAnim, speed, easing );
+ }
+
+ // start at the smallest distance if we are hiding
+ if ( hide ) {
+ distance = distance / Math.pow( 2, times - 1 );
+ }
+
+ downAnim = {};
+ downAnim[ ref ] = 0;
+ // Bounces up/down/left/right then back to 0 -- times * 2 animations happen here
+ for ( i = 0; i < times; i++ ) {
+ upAnim = {};
+ upAnim[ ref ] = ( motion ? "-=" : "+=" ) + distance;
+
+ el.animate( upAnim, speed, easing )
+ .animate( downAnim, speed, easing );
+
+ distance = hide ? distance * 2 : distance / 2;
+ }
+
+ // Last Bounce when Hiding
+ if ( hide ) {
+ upAnim = { opacity: 0 };
+ upAnim[ ref ] = ( motion ? "-=" : "+=" ) + distance;
+
+ el.animate( upAnim, speed, easing );
+ }
+
+ el.queue(function() {
+ if ( hide ) {
+ el.hide();
+ }
+ $.effects.restore( el, props );
+ $.effects.removeWrapper( el );
+ done();
+ });
+
+ // inject all the animations we just queued to be first in line (after "inprogress")
+ if ( queuelen > 1) {
+ queue.splice.apply( queue,
+ [ 1, 0 ].concat( queue.splice( queuelen, anims + 1 ) ) );
+ }
+ el.dequeue();
+
+};
+
+})(jQuery);
+
+(function( $, undefined ) {
+
+$.effects.effect.clip = function( o, done ) {
+ // Create element
+ var el = $( this ),
+ props = [ "position", "top", "bottom", "left", "right", "height", "width" ],
+ mode = $.effects.setMode( el, o.mode || "hide" ),
+ show = mode === "show",
+ direction = o.direction || "vertical",
+ vert = direction === "vertical",
+ size = vert ? "height" : "width",
+ position = vert ? "top" : "left",
+ animation = {},
+ wrapper, animate, distance;
+
+ // Save & Show
+ $.effects.save( el, props );
+ el.show();
+
+ // Create Wrapper
+ wrapper = $.effects.createWrapper( el ).css({
+ overflow: "hidden"
+ });
+ animate = ( el[0].tagName === "IMG" ) ? wrapper : el;
+ distance = animate[ size ]();
+
+ // Shift
+ if ( show ) {
+ animate.css( size, 0 );
+ animate.css( position, distance / 2 );
+ }
+
+ // Create Animation Object:
+ animation[ size ] = show ? distance : 0;
+ animation[ position ] = show ? 0 : distance / 2;
+
+ // Animate
+ animate.animate( animation, {
+ queue: false,
+ duration: o.duration,
+ easing: o.easing,
+ complete: function() {
+ if ( !show ) {
+ el.hide();
+ }
+ $.effects.restore( el, props );
+ $.effects.removeWrapper( el );
+ done();
+ }
+ });
+
+};
+
+})(jQuery);
+
+(function( $, undefined ) {
+
+$.effects.effect.drop = function( o, done ) {
+
+ var el = $( this ),
+ props = [ "position", "top", "bottom", "left", "right", "opacity", "height", "width" ],
+ mode = $.effects.setMode( el, o.mode || "hide" ),
+ show = mode === "show",
+ direction = o.direction || "left",
+ ref = ( direction === "up" || direction === "down" ) ? "top" : "left",
+ motion = ( direction === "up" || direction === "left" ) ? "pos" : "neg",
+ animation = {
+ opacity: show ? 1 : 0
+ },
+ distance;
+
+ // Adjust
+ $.effects.save( el, props );
+ el.show();
+ $.effects.createWrapper( el );
+
+ distance = o.distance || el[ ref === "top" ? "outerHeight": "outerWidth" ]( true ) / 2;
+
+ if ( show ) {
+ el
+ .css( "opacity", 0 )
+ .css( ref, motion === "pos" ? -distance : distance );
+ }
+
+ // Animation
+ animation[ ref ] = ( show ?
+ ( motion === "pos" ? "+=" : "-=" ) :
+ ( motion === "pos" ? "-=" : "+=" ) ) +
+ distance;
+
+ // Animate
+ el.animate( animation, {
+ queue: false,
+ duration: o.duration,
+ easing: o.easing,
+ complete: function() {
+ if ( mode === "hide" ) {
+ el.hide();
+ }
+ $.effects.restore( el, props );
+ $.effects.removeWrapper( el );
+ done();
+ }
+ });
+};
+
+})(jQuery);
+
+(function( $, undefined ) {
+
+$.effects.effect.explode = function( o, done ) {
+
+ var rows = o.pieces ? Math.round( Math.sqrt( o.pieces ) ) : 3,
+ cells = rows,
+ el = $( this ),
+ mode = $.effects.setMode( el, o.mode || "hide" ),
+ show = mode === "show",
+
+ // show and then visibility:hidden the element before calculating offset
+ offset = el.show().css( "visibility", "hidden" ).offset(),
+
+ // width and height of a piece
+ width = Math.ceil( el.outerWidth() / cells ),
+ height = Math.ceil( el.outerHeight() / rows ),
+ pieces = [],
+
+ // loop
+ i, j, left, top, mx, my;
+
+ // children animate complete:
+ function childComplete() {
+ pieces.push( this );
+ if ( pieces.length === rows * cells ) {
+ animComplete();
+ }
+ }
+
+ // clone the element for each row and cell.
+ for( i = 0; i < rows ; i++ ) { // ===>
+ top = offset.top + i * height;
+ my = i - ( rows - 1 ) / 2 ;
+
+ for( j = 0; j < cells ; j++ ) { // |||
+ left = offset.left + j * width;
+ mx = j - ( cells - 1 ) / 2 ;
+
+ // Create a clone of the now hidden main element that will be absolute positioned
+ // within a wrapper div off the -left and -top equal to size of our pieces
+ el
+ .clone()
+ .appendTo( "body" )
+ .wrap( "<div></div>" )
+ .css({
+ position: "absolute",
+ visibility: "visible",
+ left: -j * width,
+ top: -i * height
+ })
+
+ // select the wrapper - make it overflow: hidden and absolute positioned based on
+ // where the original was located +left and +top equal to the size of pieces
+ .parent()
+ .addClass( "ui-effects-explode" )
+ .css({
+ position: "absolute",
+ overflow: "hidden",
+ width: width,
+ height: height,
+ left: left + ( show ? mx * width : 0 ),
+ top: top + ( show ? my * height : 0 ),
+ opacity: show ? 0 : 1
+ }).animate({
+ left: left + ( show ? 0 : mx * width ),
+ top: top + ( show ? 0 : my * height ),
+ opacity: show ? 1 : 0
+ }, o.duration || 500, o.easing, childComplete );
+ }
+ }
+
+ function animComplete() {
+ el.css({
+ visibility: "visible"
+ });
+ $( pieces ).remove();
+ if ( !show ) {
+ el.hide();
+ }
+ done();
+ }
+};
+
+})(jQuery);
+
+(function( $, undefined ) {
+
+$.effects.effect.fade = function( o, done ) {
+ var el = $( this ),
+ mode = $.effects.setMode( el, o.mode || "toggle" );
+
+ el.animate({
+ opacity: mode
+ }, {
+ queue: false,
+ duration: o.duration,
+ easing: o.easing,
+ complete: done
+ });
+};
+
+})( jQuery );
+
+(function( $, undefined ) {
+
+$.effects.effect.fold = function( o, done ) {
+
+ // Create element
+ var el = $( this ),
+ props = [ "position", "top", "bottom", "left", "right", "height", "width" ],
+ mode = $.effects.setMode( el, o.mode || "hide" ),
+ show = mode === "show",
+ hide = mode === "hide",
+ size = o.size || 15,
+ percent = /([0-9]+)%/.exec( size ),
+ horizFirst = !!o.horizFirst,
+ widthFirst = show !== horizFirst,
+ ref = widthFirst ? [ "width", "height" ] : [ "height", "width" ],
+ duration = o.duration / 2,
+ wrapper, distance,
+ animation1 = {},
+ animation2 = {};
+
+ $.effects.save( el, props );
+ el.show();
+
+ // Create Wrapper
+ wrapper = $.effects.createWrapper( el ).css({
+ overflow: "hidden"
+ });
+ distance = widthFirst ?
+ [ wrapper.width(), wrapper.height() ] :
+ [ wrapper.height(), wrapper.width() ];
+
+ if ( percent ) {
+ size = parseInt( percent[ 1 ], 10 ) / 100 * distance[ hide ? 0 : 1 ];
+ }
+ if ( show ) {
+ wrapper.css( horizFirst ? {
+ height: 0,
+ width: size
+ } : {
+ height: size,
+ width: 0
+ });
+ }
+
+ // Animation
+ animation1[ ref[ 0 ] ] = show ? distance[ 0 ] : size;
+ animation2[ ref[ 1 ] ] = show ? distance[ 1 ] : 0;
+
+ // Animate
+ wrapper
+ .animate( animation1, duration, o.easing )
+ .animate( animation2, duration, o.easing, function() {
+ if ( hide ) {
+ el.hide();
+ }
+ $.effects.restore( el, props );
+ $.effects.removeWrapper( el );
+ done();
+ });
+
+};
+
+})(jQuery);
+
+(function( $, undefined ) {
+
+$.effects.effect.highlight = function( o, done ) {
+ var elem = $( this ),
+ props = [ "backgroundImage", "backgroundColor", "opacity" ],
+ mode = $.effects.setMode( elem, o.mode || "show" ),
+ animation = {
+ backgroundColor: elem.css( "backgroundColor" )
+ };
+
+ if (mode === "hide") {
+ animation.opacity = 0;
+ }
+
+ $.effects.save( elem, props );
+
+ elem
+ .show()
+ .css({
+ backgroundImage: "none",
+ backgroundColor: o.color || "#ffff99"
+ })
+ .animate( animation, {
+ queue: false,
+ duration: o.duration,
+ easing: o.easing,
+ complete: function() {
+ if ( mode === "hide" ) {
+ elem.hide();
+ }
+ $.effects.restore( elem, props );
+ done();
+ }
+ });
+};
+
+})(jQuery);
+
+(function( $, undefined ) {
+
+$.effects.effect.pulsate = function( o, done ) {
+ var elem = $( this ),
+ mode = $.effects.setMode( elem, o.mode || "show" ),
+ show = mode === "show",
+ hide = mode === "hide",
+ showhide = ( show || mode === "hide" ),
+
+ // showing or hiding leaves of the "last" animation
+ anims = ( ( o.times || 5 ) * 2 ) + ( showhide ? 1 : 0 ),
+ duration = o.duration / anims,
+ animateTo = 0,
+ queue = elem.queue(),
+ queuelen = queue.length,
+ i;
+
+ if ( show || !elem.is(":visible")) {
+ elem.css( "opacity", 0 ).show();
+ animateTo = 1;
+ }
+
+ // anims - 1 opacity "toggles"
+ for ( i = 1; i < anims; i++ ) {
+ elem.animate({
+ opacity: animateTo
+ }, duration, o.easing );
+ animateTo = 1 - animateTo;
+ }
+
+ elem.animate({
+ opacity: animateTo
+ }, duration, o.easing);
+
+ elem.queue(function() {
+ if ( hide ) {
+ elem.hide();
+ }
+ done();
+ });
+
+ // We just queued up "anims" animations, we need to put them next in the queue
+ if ( queuelen > 1 ) {
+ queue.splice.apply( queue,
+ [ 1, 0 ].concat( queue.splice( queuelen, anims + 1 ) ) );
+ }
+ elem.dequeue();
+};
+
+})(jQuery);
+
+(function( $, undefined ) {
+
+$.effects.effect.puff = function( o, done ) {
+ var elem = $( this ),
+ mode = $.effects.setMode( elem, o.mode || "hide" ),
+ hide = mode === "hide",
+ percent = parseInt( o.percent, 10 ) || 150,
+ factor = percent / 100,
+ original = {
+ height: elem.height(),
+ width: elem.width(),
+ outerHeight: elem.outerHeight(),
+ outerWidth: elem.outerWidth()
+ };
+
+ $.extend( o, {
+ effect: "scale",
+ queue: false,
+ fade: true,
+ mode: mode,
+ complete: done,
+ percent: hide ? percent : 100,
+ from: hide ?
+ original :
+ {
+ height: original.height * factor,
+ width: original.width * factor,
+ outerHeight: original.outerHeight * factor,
+ outerWidth: original.outerWidth * factor
+ }
+ });
+
+ elem.effect( o );
+};
+
+$.effects.effect.scale = function( o, done ) {
+
+ // Create element
+ var el = $( this ),
+ options = $.extend( true, {}, o ),
+ mode = $.effects.setMode( el, o.mode || "effect" ),
+ percent = parseInt( o.percent, 10 ) ||
+ ( parseInt( o.percent, 10 ) === 0 ? 0 : ( mode === "hide" ? 0 : 100 ) ),
+ direction = o.direction || "both",
+ origin = o.origin,
+ original = {
+ height: el.height(),
+ width: el.width(),
+ outerHeight: el.outerHeight(),
+ outerWidth: el.outerWidth()
+ },
+ factor = {
+ y: direction !== "horizontal" ? (percent / 100) : 1,
+ x: direction !== "vertical" ? (percent / 100) : 1
+ };
+
+ // We are going to pass this effect to the size effect:
+ options.effect = "size";
+ options.queue = false;
+ options.complete = done;
+
+ // Set default origin and restore for show/hide
+ if ( mode !== "effect" ) {
+ options.origin = origin || ["middle","center"];
+ options.restore = true;
+ }
+
+ options.from = o.from || ( mode === "show" ? {
+ height: 0,
+ width: 0,
+ outerHeight: 0,
+ outerWidth: 0
+ } : original );
+ options.to = {
+ height: original.height * factor.y,
+ width: original.width * factor.x,
+ outerHeight: original.outerHeight * factor.y,
+ outerWidth: original.outerWidth * factor.x
+ };
+
+ // Fade option to support puff
+ if ( options.fade ) {
+ if ( mode === "show" ) {
+ options.from.opacity = 0;
+ options.to.opacity = 1;
+ }
+ if ( mode === "hide" ) {
+ options.from.opacity = 1;
+ options.to.opacity = 0;
+ }
+ }
+
+ // Animate
+ el.effect( options );
+
+};
+
+$.effects.effect.size = function( o, done ) {
+
+ // Create element
+ var original, baseline, factor,
+ el = $( this ),
+ props0 = [ "position", "top", "bottom", "left", "right", "width", "height", "overflow", "opacity" ],
+
+ // Always restore
+ props1 = [ "position", "top", "bottom", "left", "right", "overflow", "opacity" ],
+
+ // Copy for children
+ props2 = [ "width", "height", "overflow" ],
+ cProps = [ "fontSize" ],
+ vProps = [ "borderTopWidth", "borderBottomWidth", "paddingTop", "paddingBottom" ],
+ hProps = [ "borderLeftWidth", "borderRightWidth", "paddingLeft", "paddingRight" ],
+
+ // Set options
+ mode = $.effects.setMode( el, o.mode || "effect" ),
+ restore = o.restore || mode !== "effect",
+ scale = o.scale || "both",
+ origin = o.origin || [ "middle", "center" ],
+ position = el.css( "position" ),
+ props = restore ? props0 : props1,
+ zero = {
+ height: 0,
+ width: 0,
+ outerHeight: 0,
+ outerWidth: 0
+ };
+
+ if ( mode === "show" ) {
+ el.show();
+ }
+ original = {
+ height: el.height(),
+ width: el.width(),
+ outerHeight: el.outerHeight(),
+ outerWidth: el.outerWidth()
+ };
+
+ if ( o.mode === "toggle" && mode === "show" ) {
+ el.from = o.to || zero;
+ el.to = o.from || original;
+ } else {
+ el.from = o.from || ( mode === "show" ? zero : original );
+ el.to = o.to || ( mode === "hide" ? zero : original );
+ }
+
+ // Set scaling factor
+ factor = {
+ from: {
+ y: el.from.height / original.height,
+ x: el.from.width / original.width
+ },
+ to: {
+ y: el.to.height / original.height,
+ x: el.to.width / original.width
+ }
+ };
+
+ // Scale the css box
+ if ( scale === "box" || scale === "both" ) {
+
+ // Vertical props scaling
+ if ( factor.from.y !== factor.to.y ) {
+ props = props.concat( vProps );
+ el.from = $.effects.setTransition( el, vProps, factor.from.y, el.from );
+ el.to = $.effects.setTransition( el, vProps, factor.to.y, el.to );
+ }
+
+ // Horizontal props scaling
+ if ( factor.from.x !== factor.to.x ) {
+ props = props.concat( hProps );
+ el.from = $.effects.setTransition( el, hProps, factor.from.x, el.from );
+ el.to = $.effects.setTransition( el, hProps, factor.to.x, el.to );
+ }
+ }
+
+ // Scale the content
+ if ( scale === "content" || scale === "both" ) {
+
+ // Vertical props scaling
+ if ( factor.from.y !== factor.to.y ) {
+ props = props.concat( cProps ).concat( props2 );
+ el.from = $.effects.setTransition( el, cProps, factor.from.y, el.from );
+ el.to = $.effects.setTransition( el, cProps, factor.to.y, el.to );
+ }
+ }
+
+ $.effects.save( el, props );
+ el.show();
+ $.effects.createWrapper( el );
+ el.css( "overflow", "hidden" ).css( el.from );
+
+ // Adjust
+ if (origin) { // Calculate baseline shifts
+ baseline = $.effects.getBaseline( origin, original );
+ el.from.top = ( original.outerHeight - el.outerHeight() ) * baseline.y;
+ el.from.left = ( original.outerWidth - el.outerWidth() ) * baseline.x;
+ el.to.top = ( original.outerHeight - el.to.outerHeight ) * baseline.y;
+ el.to.left = ( original.outerWidth - el.to.outerWidth ) * baseline.x;
+ }
+ el.css( el.from ); // set top & left
+
+ // Animate
+ if ( scale === "content" || scale === "both" ) { // Scale the children
+
+ // Add margins/font-size
+ vProps = vProps.concat([ "marginTop", "marginBottom" ]).concat(cProps);
+ hProps = hProps.concat([ "marginLeft", "marginRight" ]);
+ props2 = props0.concat(vProps).concat(hProps);
+
+ el.find( "*[width]" ).each( function(){
+ var child = $( this ),
+ c_original = {
+ height: child.height(),
+ width: child.width(),
+ outerHeight: child.outerHeight(),
+ outerWidth: child.outerWidth()
+ };
+ if (restore) {
+ $.effects.save(child, props2);
+ }
+
+ child.from = {
+ height: c_original.height * factor.from.y,
+ width: c_original.width * factor.from.x,
+ outerHeight: c_original.outerHeight * factor.from.y,
+ outerWidth: c_original.outerWidth * factor.from.x
+ };
+ child.to = {
+ height: c_original.height * factor.to.y,
+ width: c_original.width * factor.to.x,
+ outerHeight: c_original.height * factor.to.y,
+ outerWidth: c_original.width * factor.to.x
+ };
+
+ // Vertical props scaling
+ if ( factor.from.y !== factor.to.y ) {
+ child.from = $.effects.setTransition( child, vProps, factor.from.y, child.from );
+ child.to = $.effects.setTransition( child, vProps, factor.to.y, child.to );
+ }
+
+ // Horizontal props scaling
+ if ( factor.from.x !== factor.to.x ) {
+ child.from = $.effects.setTransition( child, hProps, factor.from.x, child.from );
+ child.to = $.effects.setTransition( child, hProps, factor.to.x, child.to );
+ }
+
+ // Animate children
+ child.css( child.from );
+ child.animate( child.to, o.duration, o.easing, function() {
+
+ // Restore children
+ if ( restore ) {
+ $.effects.restore( child, props2 );
+ }
+ });
+ });
+ }
+
+ // Animate
+ el.animate( el.to, {
+ queue: false,
+ duration: o.duration,
+ easing: o.easing,
+ complete: function() {
+ if ( el.to.opacity === 0 ) {
+ el.css( "opacity", el.from.opacity );
+ }
+ if( mode === "hide" ) {
+ el.hide();
+ }
+ $.effects.restore( el, props );
+ if ( !restore ) {
+
+ // we need to calculate our new positioning based on the scaling
+ if ( position === "static" ) {
+ el.css({
+ position: "relative",
+ top: el.to.top,
+ left: el.to.left
+ });
+ } else {
+ $.each([ "top", "left" ], function( idx, pos ) {
+ el.css( pos, function( _, str ) {
+ var val = parseInt( str, 10 ),
+ toRef = idx ? el.to.left : el.to.top;
+
+ // if original was "auto", recalculate the new value from wrapper
+ if ( str === "auto" ) {
+ return toRef + "px";
+ }
+
+ return val + toRef + "px";
+ });
+ });
+ }
+ }
+
+ $.effects.removeWrapper( el );
+ done();
+ }
+ });
+
+};
+
+})(jQuery);
+
+(function( $, undefined ) {
+
+$.effects.effect.shake = function( o, done ) {
+
+ var el = $( this ),
+ props = [ "position", "top", "bottom", "left", "right", "height", "width" ],
+ mode = $.effects.setMode( el, o.mode || "effect" ),
+ direction = o.direction || "left",
+ distance = o.distance || 20,
+ times = o.times || 3,
+ anims = times * 2 + 1,
+ speed = Math.round(o.duration/anims),
+ ref = (direction === "up" || direction === "down") ? "top" : "left",
+ positiveMotion = (direction === "up" || direction === "left"),
+ animation = {},
+ animation1 = {},
+ animation2 = {},
+ i,
+
+ // we will need to re-assemble the queue to stack our animations in place
+ queue = el.queue(),
+ queuelen = queue.length;
+
+ $.effects.save( el, props );
+ el.show();
+ $.effects.createWrapper( el );
+
+ // Animation
+ animation[ ref ] = ( positiveMotion ? "-=" : "+=" ) + distance;
+ animation1[ ref ] = ( positiveMotion ? "+=" : "-=" ) + distance * 2;
+ animation2[ ref ] = ( positiveMotion ? "-=" : "+=" ) + distance * 2;
+
+ // Animate
+ el.animate( animation, speed, o.easing );
+
+ // Shakes
+ for ( i = 1; i < times; i++ ) {
+ el.animate( animation1, speed, o.easing ).animate( animation2, speed, o.easing );
+ }
+ el
+ .animate( animation1, speed, o.easing )
+ .animate( animation, speed / 2, o.easing )
+ .queue(function() {
+ if ( mode === "hide" ) {
+ el.hide();
+ }
+ $.effects.restore( el, props );
+ $.effects.removeWrapper( el );
+ done();
+ });
+
+ // inject all the animations we just queued to be first in line (after "inprogress")
+ if ( queuelen > 1) {
+ queue.splice.apply( queue,
+ [ 1, 0 ].concat( queue.splice( queuelen, anims + 1 ) ) );
+ }
+ el.dequeue();
+
+};
+
+})(jQuery);
+
+(function( $, undefined ) {
+
+$.effects.effect.slide = function( o, done ) {
+
+ // Create element
+ var el = $( this ),
+ props = [ "position", "top", "bottom", "left", "right", "width", "height" ],
+ mode = $.effects.setMode( el, o.mode || "show" ),
+ show = mode === "show",
+ direction = o.direction || "left",
+ ref = (direction === "up" || direction === "down") ? "top" : "left",
+ positiveMotion = (direction === "up" || direction === "left"),
+ distance,
+ animation = {};
+
+ // Adjust
+ $.effects.save( el, props );
+ el.show();
+ distance = o.distance || el[ ref === "top" ? "outerHeight" : "outerWidth" ]( true );
+
+ $.effects.createWrapper( el ).css({
+ overflow: "hidden"
+ });
+
+ if ( show ) {
+ el.css( ref, positiveMotion ? (isNaN(distance) ? "-" + distance : -distance) : distance );
+ }
+
+ // Animation
+ animation[ ref ] = ( show ?
+ ( positiveMotion ? "+=" : "-=") :
+ ( positiveMotion ? "-=" : "+=")) +
+ distance;
+
+ // Animate
+ el.animate( animation, {
+ queue: false,
+ duration: o.duration,
+ easing: o.easing,
+ complete: function() {
+ if ( mode === "hide" ) {
+ el.hide();
+ }
+ $.effects.restore( el, props );
+ $.effects.removeWrapper( el );
+ done();
+ }
+ });
+};
+
+})(jQuery);
+
+(function( $, undefined ) {
+
+$.effects.effect.transfer = function( o, done ) {
+ var elem = $( this ),
+ target = $( o.to ),
+ targetFixed = target.css( "position" ) === "fixed",
+ body = $("body"),
+ fixTop = targetFixed ? body.scrollTop() : 0,
+ fixLeft = targetFixed ? body.scrollLeft() : 0,
+ endPosition = target.offset(),
+ animation = {
+ top: endPosition.top - fixTop ,
+ left: endPosition.left - fixLeft ,
+ height: target.innerHeight(),
+ width: target.innerWidth()
+ },
+ startPosition = elem.offset(),
+ transfer = $( "<div class='ui-effects-transfer'></div>" )
+ .appendTo( document.body )
+ .addClass( o.className )
+ .css({
+ top: startPosition.top - fixTop ,
+ left: startPosition.left - fixLeft ,
+ height: elem.innerHeight(),
+ width: elem.innerWidth(),
+ position: targetFixed ? "fixed" : "absolute"
+ })
+ .animate( animation, o.duration, o.easing, function() {
+ transfer.remove();
+ done();
+ });
+};
+
+})(jQuery);
+
+(function( $, undefined ) {
+
+$.widget( "ui.menu", {
+ version: "1.10.3",
+ defaultElement: "<ul>",
+ delay: 300,
+ options: {
+ icons: {
+ submenu: "ui-icon-carat-1-e"
+ },
+ menus: "ul",
+ position: {
+ my: "left top",
+ at: "right top"
+ },
+ role: "menu",
+
+ // callbacks
+ blur: null,
+ focus: null,
+ select: null
+ },
+
+ _create: function() {
+ this.activeMenu = this.element;
+ // flag used to prevent firing of the click handler
+ // as the event bubbles up through nested menus
+ this.mouseHandled = false;
+ this.element
+ .uniqueId()
+ .addClass( "ui-menu ui-widget ui-widget-content ui-corner-all" )
+ .toggleClass( "ui-menu-icons", !!this.element.find( ".ui-icon" ).length )
+ .attr({
+ role: this.options.role,
+ tabIndex: 0
+ })
+ // need to catch all clicks on disabled menu
+ // not possible through _on
+ .bind( "click" + this.eventNamespace, $.proxy(function( event ) {
+ if ( this.options.disabled ) {
+ event.preventDefault();
+ }
+ }, this ));
+
+ if ( this.options.disabled ) {
+ this.element
+ .addClass( "ui-state-disabled" )
+ .attr( "aria-disabled", "true" );
+ }
+
+ this._on({
+ // Prevent focus from sticking to links inside menu after clicking
+ // them (focus should always stay on UL during navigation).
+ "mousedown .ui-menu-item > a": function( event ) {
+ event.preventDefault();
+ },
+ "click .ui-state-disabled > a": function( event ) {
+ event.preventDefault();
+ },
+ "click .ui-menu-item:has(a)": function( event ) {
+ var target = $( event.target ).closest( ".ui-menu-item" );
+ if ( !this.mouseHandled && target.not( ".ui-state-disabled" ).length ) {
+ this.mouseHandled = true;
+
+ this.select( event );
+ // Open submenu on click
+ if ( target.has( ".ui-menu" ).length ) {
+ this.expand( event );
+ } else if ( !this.element.is( ":focus" ) ) {
+ // Redirect focus to the menu
+ this.element.trigger( "focus", [ true ] );
+
+ // If the active item is on the top level, let it stay active.
+ // Otherwise, blur the active item since it is no longer visible.
+ if ( this.active && this.active.parents( ".ui-menu" ).length === 1 ) {
+ clearTimeout( this.timer );
+ }
+ }
+ }
+ },
+ "mouseenter .ui-menu-item": function( event ) {
+ var target = $( event.currentTarget );
+ // Remove ui-state-active class from siblings of the newly focused menu item
+ // to avoid a jump caused by adjacent elements both having a class with a border
+ target.siblings().children( ".ui-state-active" ).removeClass( "ui-state-active" );
+ this.focus( event, target );
+ },
+ mouseleave: "collapseAll",
+ "mouseleave .ui-menu": "collapseAll",
+ focus: function( event, keepActiveItem ) {
+ // If there's already an active item, keep it active
+ // If not, activate the first item
+ var item = this.active || this.element.children( ".ui-menu-item" ).eq( 0 );
+
+ if ( !keepActiveItem ) {
+ this.focus( event, item );
+ }
+ },
+ blur: function( event ) {
+ this._delay(function() {
+ if ( !$.contains( this.element[0], this.document[0].activeElement ) ) {
+ this.collapseAll( event );
+ }
+ });
+ },
+ keydown: "_keydown"
+ });
+
+ this.refresh();
+
+ // Clicks outside of a menu collapse any open menus
+ this._on( this.document, {
+ click: function( event ) {
+ if ( !$( event.target ).closest( ".ui-menu" ).length ) {
+ this.collapseAll( event );
+ }
+
+ // Reset the mouseHandled flag
+ this.mouseHandled = false;
+ }
+ });
+ },
+
+ _destroy: function() {
+ // Destroy (sub)menus
+ this.element
+ .removeAttr( "aria-activedescendant" )
+ .find( ".ui-menu" ).addBack()
+ .removeClass( "ui-menu ui-widget ui-widget-content ui-corner-all ui-menu-icons" )
+ .removeAttr( "role" )
+ .removeAttr( "tabIndex" )
+ .removeAttr( "aria-labelledby" )
+ .removeAttr( "aria-expanded" )
+ .removeAttr( "aria-hidden" )
+ .removeAttr( "aria-disabled" )
+ .removeUniqueId()
+ .show();
+
+ // Destroy menu items
+ this.element.find( ".ui-menu-item" )
+ .removeClass( "ui-menu-item" )
+ .removeAttr( "role" )
+ .removeAttr( "aria-disabled" )
+ .children( "a" )
+ .removeUniqueId()
+ .removeClass( "ui-corner-all ui-state-hover" )
+ .removeAttr( "tabIndex" )
+ .removeAttr( "role" )
+ .removeAttr( "aria-haspopup" )
+ .children().each( function() {
+ var elem = $( this );
+ if ( elem.data( "ui-menu-submenu-carat" ) ) {
+ elem.remove();
+ }
+ });
+
+ // Destroy menu dividers
+ this.element.find( ".ui-menu-divider" ).removeClass( "ui-menu-divider ui-widget-content" );
+ },
+
+ _keydown: function( event ) {
+ /*jshint maxcomplexity:20*/
+ var match, prev, character, skip, regex,
+ preventDefault = true;
+
+ function escape( value ) {
+ return value.replace( /[\-\[\]{}()*+?.,\\\^$|#\s]/g, "\\$&" );
+ }
+
+ switch ( event.keyCode ) {
+ case $.ui.keyCode.PAGE_UP:
+ this.previousPage( event );
+ break;
+ case $.ui.keyCode.PAGE_DOWN:
+ this.nextPage( event );
+ break;
+ case $.ui.keyCode.HOME:
+ this._move( "first", "first", event );
+ break;
+ case $.ui.keyCode.END:
+ this._move( "last", "last", event );
+ break;
+ case $.ui.keyCode.UP:
+ this.previous( event );
+ break;
+ case $.ui.keyCode.DOWN:
+ this.next( event );
+ break;
+ case $.ui.keyCode.LEFT:
+ this.collapse( event );
+ break;
+ case $.ui.keyCode.RIGHT:
+ if ( this.active && !this.active.is( ".ui-state-disabled" ) ) {
+ this.expand( event );
+ }
+ break;
+ case $.ui.keyCode.ENTER:
+ case $.ui.keyCode.SPACE:
+ this._activate( event );
+ break;
+ case $.ui.keyCode.ESCAPE:
+ this.collapse( event );
+ break;
+ default:
+ preventDefault = false;
+ prev = this.previousFilter || "";
+ character = String.fromCharCode( event.keyCode );
+ skip = false;
+
+ clearTimeout( this.filterTimer );
+
+ if ( character === prev ) {
+ skip = true;
+ } else {
+ character = prev + character;
+ }
+
+ regex = new RegExp( "^" + escape( character ), "i" );
+ match = this.activeMenu.children( ".ui-menu-item" ).filter(function() {
+ return regex.test( $( this ).children( "a" ).text() );
+ });
+ match = skip && match.index( this.active.next() ) !== -1 ?
+ this.active.nextAll( ".ui-menu-item" ) :
+ match;
+
+ // If no matches on the current filter, reset to the last character pressed
+ // to move down the menu to the first item that starts with that character
+ if ( !match.length ) {
+ character = String.fromCharCode( event.keyCode );
+ regex = new RegExp( "^" + escape( character ), "i" );
+ match = this.activeMenu.children( ".ui-menu-item" ).filter(function() {
+ return regex.test( $( this ).children( "a" ).text() );
+ });
+ }
+
+ if ( match.length ) {
+ this.focus( event, match );
+ if ( match.length > 1 ) {
+ this.previousFilter = character;
+ this.filterTimer = this._delay(function() {
+ delete this.previousFilter;
+ }, 1000 );
+ } else {
+ delete this.previousFilter;
+ }
+ } else {
+ delete this.previousFilter;
+ }
+ }
+
+ if ( preventDefault ) {
+ event.preventDefault();
+ }
+ },
+
+ _activate: function( event ) {
+ if ( !this.active.is( ".ui-state-disabled" ) ) {
+ if ( this.active.children( "a[aria-haspopup='true']" ).length ) {
+ this.expand( event );
+ } else {
+ this.select( event );
+ }
+ }
+ },
+
+ refresh: function() {
+ var menus,
+ icon = this.options.icons.submenu,
+ submenus = this.element.find( this.options.menus );
+
+ // Initialize nested menus
+ submenus.filter( ":not(.ui-menu)" )
+ .addClass( "ui-menu ui-widget ui-widget-content ui-corner-all" )
+ .hide()
+ .attr({
+ role: this.options.role,
+ "aria-hidden": "true",
+ "aria-expanded": "false"
+ })
+ .each(function() {
+ var menu = $( this ),
+ item = menu.prev( "a" ),
+ submenuCarat = $( "<span>" )
+ .addClass( "ui-menu-icon ui-icon " + icon )
+ .data( "ui-menu-submenu-carat", true );
+
+ item
+ .attr( "aria-haspopup", "true" )
+ .prepend( submenuCarat );
+ menu.attr( "aria-labelledby", item.attr( "id" ) );
+ });
+
+ menus = submenus.add( this.element );
+
+ // Don't refresh list items that are already adapted
+ menus.children( ":not(.ui-menu-item):has(a)" )
+ .addClass( "ui-menu-item" )
+ .attr( "role", "presentation" )
+ .children( "a" )
+ .uniqueId()
+ .addClass( "ui-corner-all" )
+ .attr({
+ tabIndex: -1,
+ role: this._itemRole()
+ });
+
+ // Initialize unlinked menu-items containing spaces and/or dashes only as dividers
+ menus.children( ":not(.ui-menu-item)" ).each(function() {
+ var item = $( this );
+ // hyphen, em dash, en dash
+ if ( !/[^\-\u2014\u2013\s]/.test( item.text() ) ) {
+ item.addClass( "ui-widget-content ui-menu-divider" );
+ }
+ });
+
+ // Add aria-disabled attribute to any disabled menu item
+ menus.children( ".ui-state-disabled" ).attr( "aria-disabled", "true" );
+
+ // If the active item has been removed, blur the menu
+ if ( this.active && !$.contains( this.element[ 0 ], this.active[ 0 ] ) ) {
+ this.blur();
+ }
+ },
+
+ _itemRole: function() {
+ return {
+ menu: "menuitem",
+ listbox: "option"
+ }[ this.options.role ];
+ },
+
+ _setOption: function( key, value ) {
+ if ( key === "icons" ) {
+ this.element.find( ".ui-menu-icon" )
+ .removeClass( this.options.icons.submenu )
+ .addClass( value.submenu );
+ }
+ this._super( key, value );
+ },
+
+ focus: function( event, item ) {
+ var nested, focused;
+ this.blur( event, event && event.type === "focus" );
+
+ this._scrollIntoView( item );
+
+ this.active = item.first();
+ focused = this.active.children( "a" ).addClass( "ui-state-focus" );
+ // Only update aria-activedescendant if there's a role
+ // otherwise we assume focus is managed elsewhere
+ if ( this.options.role ) {
+ this.element.attr( "aria-activedescendant", focused.attr( "id" ) );
+ }
+
+ // Highlight active parent menu item, if any
+ this.active
+ .parent()
+ .closest( ".ui-menu-item" )
+ .children( "a:first" )
+ .addClass( "ui-state-active" );
+
+ if ( event && event.type === "keydown" ) {
+ this._close();
+ } else {
+ this.timer = this._delay(function() {
+ this._close();
+ }, this.delay );
+ }
+
+ nested = item.children( ".ui-menu" );
+ if ( nested.length && ( /^mouse/.test( event.type ) ) ) {
+ this._startOpening(nested);
+ }
+ this.activeMenu = item.parent();
+
+ this._trigger( "focus", event, { item: item } );
+ },
+
+ _scrollIntoView: function( item ) {
+ var borderTop, paddingTop, offset, scroll, elementHeight, itemHeight;
+ if ( this._hasScroll() ) {
+ borderTop = parseFloat( $.css( this.activeMenu[0], "borderTopWidth" ) ) || 0;
+ paddingTop = parseFloat( $.css( this.activeMenu[0], "paddingTop" ) ) || 0;
+ offset = item.offset().top - this.activeMenu.offset().top - borderTop - paddingTop;
+ scroll = this.activeMenu.scrollTop();
+ elementHeight = this.activeMenu.height();
+ itemHeight = item.height();
+
+ if ( offset < 0 ) {
+ this.activeMenu.scrollTop( scroll + offset );
+ } else if ( offset + itemHeight > elementHeight ) {
+ this.activeMenu.scrollTop( scroll + offset - elementHeight + itemHeight );
+ }
+ }
+ },
+
+ blur: function( event, fromFocus ) {
+ if ( !fromFocus ) {
+ clearTimeout( this.timer );
+ }
+
+ if ( !this.active ) {
+ return;
+ }
+
+ this.active.children( "a" ).removeClass( "ui-state-focus" );
+ this.active = null;
+
+ this._trigger( "blur", event, { item: this.active } );
+ },
+
+ _startOpening: function( submenu ) {
+ clearTimeout( this.timer );
+
+ // Don't open if already open fixes a Firefox bug that caused a .5 pixel
+ // shift in the submenu position when mousing over the carat icon
+ if ( submenu.attr( "aria-hidden" ) !== "true" ) {
+ return;
+ }
+
+ this.timer = this._delay(function() {
+ this._close();
+ this._open( submenu );
+ }, this.delay );
+ },
+
+ _open: function( submenu ) {
+ var position = $.extend({
+ of: this.active
+ }, this.options.position );
+
+ clearTimeout( this.timer );
+ this.element.find( ".ui-menu" ).not( submenu.parents( ".ui-menu" ) )
+ .hide()
+ .attr( "aria-hidden", "true" );
+
+ submenu
+ .show()
+ .removeAttr( "aria-hidden" )
+ .attr( "aria-expanded", "true" )
+ .position( position );
+ },
+
+ collapseAll: function( event, all ) {
+ clearTimeout( this.timer );
+ this.timer = this._delay(function() {
+ // If we were passed an event, look for the submenu that contains the event
+ var currentMenu = all ? this.element :
+ $( event && event.target ).closest( this.element.find( ".ui-menu" ) );
+
+ // If we found no valid submenu ancestor, use the main menu to close all sub menus anyway
+ if ( !currentMenu.length ) {
+ currentMenu = this.element;
+ }
+
+ this._close( currentMenu );
+
+ this.blur( event );
+ this.activeMenu = currentMenu;
+ }, this.delay );
+ },
+
+ // With no arguments, closes the currently active menu - if nothing is active
+ // it closes all menus. If passed an argument, it will search for menus BELOW
+ _close: function( startMenu ) {
+ if ( !startMenu ) {
+ startMenu = this.active ? this.active.parent() : this.element;
+ }
+
+ startMenu
+ .find( ".ui-menu" )
+ .hide()
+ .attr( "aria-hidden", "true" )
+ .attr( "aria-expanded", "false" )
+ .end()
+ .find( "a.ui-state-active" )
+ .removeClass( "ui-state-active" );
+ },
+
+ collapse: function( event ) {
+ var newItem = this.active &&
+ this.active.parent().closest( ".ui-menu-item", this.element );
+ if ( newItem && newItem.length ) {
+ this._close();
+ this.focus( event, newItem );
+ }
+ },
+
+ expand: function( event ) {
+ var newItem = this.active &&
+ this.active
+ .children( ".ui-menu " )
+ .children( ".ui-menu-item" )
+ .first();
+
+ if ( newItem && newItem.length ) {
+ this._open( newItem.parent() );
+
+ // Delay so Firefox will not hide activedescendant change in expanding submenu from AT
+ this._delay(function() {
+ this.focus( event, newItem );
+ });
+ }
+ },
+
+ next: function( event ) {
+ this._move( "next", "first", event );
+ },
+
+ previous: function( event ) {
+ this._move( "prev", "last", event );
+ },
+
+ isFirstItem: function() {
+ return this.active && !this.active.prevAll( ".ui-menu-item" ).length;
+ },
+
+ isLastItem: function() {
+ return this.active && !this.active.nextAll( ".ui-menu-item" ).length;
+ },
+
+ _move: function( direction, filter, event ) {
+ var next;
+ if ( this.active ) {
+ if ( direction === "first" || direction === "last" ) {
+ next = this.active
+ [ direction === "first" ? "prevAll" : "nextAll" ]( ".ui-menu-item" )
+ .eq( -1 );
+ } else {
+ next = this.active
+ [ direction + "All" ]( ".ui-menu-item" )
+ .eq( 0 );
+ }
+ }
+ if ( !next || !next.length || !this.active ) {
+ next = this.activeMenu.children( ".ui-menu-item" )[ filter ]();
+ }
+
+ this.focus( event, next );
+ },
+
+ nextPage: function( event ) {
+ var item, base, height;
+
+ if ( !this.active ) {
+ this.next( event );
+ return;
+ }
+ if ( this.isLastItem() ) {
+ return;
+ }
+ if ( this._hasScroll() ) {
+ base = this.active.offset().top;
+ height = this.element.height();
+ this.active.nextAll( ".ui-menu-item" ).each(function() {
+ item = $( this );
+ return item.offset().top - base - height < 0;
+ });
+
+ this.focus( event, item );
+ } else {
+ this.focus( event, this.activeMenu.children( ".ui-menu-item" )
+ [ !this.active ? "first" : "last" ]() );
+ }
+ },
+
+ previousPage: function( event ) {
+ var item, base, height;
+ if ( !this.active ) {
+ this.next( event );
+ return;
+ }
+ if ( this.isFirstItem() ) {
+ return;
+ }
+ if ( this._hasScroll() ) {
+ base = this.active.offset().top;
+ height = this.element.height();
+ this.active.prevAll( ".ui-menu-item" ).each(function() {
+ item = $( this );
+ return item.offset().top - base + height > 0;
+ });
+
+ this.focus( event, item );
+ } else {
+ this.focus( event, this.activeMenu.children( ".ui-menu-item" ).first() );
+ }
+ },
+
+ _hasScroll: function() {
+ return this.element.outerHeight() < this.element.prop( "scrollHeight" );
+ },
+
+ select: function( event ) {
+ // TODO: It should never be possible to not have an active item at this
+ // point, but the tests don't trigger mouseenter before click.
+ this.active = this.active || $( event.target ).closest( ".ui-menu-item" );
+ var ui = { item: this.active };
+ if ( !this.active.has( ".ui-menu" ).length ) {
+ this.collapseAll( event, true );
+ }
+ this._trigger( "select", event, ui );
+ }
+});
+
+}( jQuery ));
+
+(function( $, undefined ) {
+
+$.ui = $.ui || {};
+
+var cachedScrollbarWidth,
+ max = Math.max,
+ abs = Math.abs,
+ round = Math.round,
+ rhorizontal = /left|center|right/,
+ rvertical = /top|center|bottom/,
+ roffset = /[\+\-]\d+(\.[\d]+)?%?/,
+ rposition = /^\w+/,
+ rpercent = /%$/,
+ _position = $.fn.position;
+
+function getOffsets( offsets, width, height ) {
+ return [
+ parseFloat( offsets[ 0 ] ) * ( rpercent.test( offsets[ 0 ] ) ? width / 100 : 1 ),
+ parseFloat( offsets[ 1 ] ) * ( rpercent.test( offsets[ 1 ] ) ? height / 100 : 1 )
+ ];
+}
+
+function parseCss( element, property ) {
+ return parseInt( $.css( element, property ), 10 ) || 0;
+}
+
+function getDimensions( elem ) {
+ var raw = elem[0];
+ if ( raw.nodeType === 9 ) {
+ return {
+ width: elem.width(),
+ height: elem.height(),
+ offset: { top: 0, left: 0 }
+ };
+ }
+ if ( $.isWindow( raw ) ) {
+ return {
+ width: elem.width(),
+ height: elem.height(),
+ offset: { top: elem.scrollTop(), left: elem.scrollLeft() }
+ };
+ }
+ if ( raw.preventDefault ) {
+ return {
+ width: 0,
+ height: 0,
+ offset: { top: raw.pageY, left: raw.pageX }
+ };
+ }
+ return {
+ width: elem.outerWidth(),
+ height: elem.outerHeight(),
+ offset: elem.offset()
+ };
+}
+
+$.position = {
+ scrollbarWidth: function() {
+ if ( cachedScrollbarWidth !== undefined ) {
+ return cachedScrollbarWidth;
+ }
+ var w1, w2,
+ div = $( "<div style='display:block;width:50px;height:50px;overflow:hidden;'><div style='height:100px;width:auto;'></div></div>" ),
+ innerDiv = div.children()[0];
+
+ $( "body" ).append( div );
+ w1 = innerDiv.offsetWidth;
+ div.css( "overflow", "scroll" );
+
+ w2 = innerDiv.offsetWidth;
+
+ if ( w1 === w2 ) {
+ w2 = div[0].clientWidth;
+ }
+
+ div.remove();
+
+ return (cachedScrollbarWidth = w1 - w2);
+ },
+ getScrollInfo: function( within ) {
+ var overflowX = within.isWindow ? "" : within.element.css( "overflow-x" ),
+ overflowY = within.isWindow ? "" : within.element.css( "overflow-y" ),
+ hasOverflowX = overflowX === "scroll" ||
+ ( overflowX === "auto" && within.width < within.element[0].scrollWidth ),
+ hasOverflowY = overflowY === "scroll" ||
+ ( overflowY === "auto" && within.height < within.element[0].scrollHeight );
+ return {
+ width: hasOverflowY ? $.position.scrollbarWidth() : 0,
+ height: hasOverflowX ? $.position.scrollbarWidth() : 0
+ };
+ },
+ getWithinInfo: function( element ) {
+ var withinElement = $( element || window ),
+ isWindow = $.isWindow( withinElement[0] );
+ return {
+ element: withinElement,
+ isWindow: isWindow,
+ offset: withinElement.offset() || { left: 0, top: 0 },
+ scrollLeft: withinElement.scrollLeft(),
+ scrollTop: withinElement.scrollTop(),
+ width: isWindow ? withinElement.width() : withinElement.outerWidth(),
+ height: isWindow ? withinElement.height() : withinElement.outerHeight()
+ };
+ }
+};
+
+$.fn.position = function( options ) {
+ if ( !options || !options.of ) {
+ return _position.apply( this, arguments );
+ }
+
+ // make a copy, we don't want to modify arguments
+ options = $.extend( {}, options );
+
+ var atOffset, targetWidth, targetHeight, targetOffset, basePosition, dimensions,
+ target = $( options.of ),
+ within = $.position.getWithinInfo( options.within ),
+ scrollInfo = $.position.getScrollInfo( within ),
+ collision = ( options.collision || "flip" ).split( " " ),
+ offsets = {};
+
+ dimensions = getDimensions( target );
+ if ( target[0].preventDefault ) {
+ // force left top to allow flipping
+ options.at = "left top";
+ }
+ targetWidth = dimensions.width;
+ targetHeight = dimensions.height;
+ targetOffset = dimensions.offset;
+ // clone to reuse original targetOffset later
+ basePosition = $.extend( {}, targetOffset );
+
+ // force my and at to have valid horizontal and vertical positions
+ // if a value is missing or invalid, it will be converted to center
+ $.each( [ "my", "at" ], function() {
+ var pos = ( options[ this ] || "" ).split( " " ),
+ horizontalOffset,
+ verticalOffset;
+
+ if ( pos.length === 1) {
+ pos = rhorizontal.test( pos[ 0 ] ) ?
+ pos.concat( [ "center" ] ) :
+ rvertical.test( pos[ 0 ] ) ?
+ [ "center" ].concat( pos ) :
+ [ "center", "center" ];
+ }
+ pos[ 0 ] = rhorizontal.test( pos[ 0 ] ) ? pos[ 0 ] : "center";
+ pos[ 1 ] = rvertical.test( pos[ 1 ] ) ? pos[ 1 ] : "center";
+
+ // calculate offsets
+ horizontalOffset = roffset.exec( pos[ 0 ] );
+ verticalOffset = roffset.exec( pos[ 1 ] );
+ offsets[ this ] = [
+ horizontalOffset ? horizontalOffset[ 0 ] : 0,
+ verticalOffset ? verticalOffset[ 0 ] : 0
+ ];
+
+ // reduce to just the positions without the offsets
+ options[ this ] = [
+ rposition.exec( pos[ 0 ] )[ 0 ],
+ rposition.exec( pos[ 1 ] )[ 0 ]
+ ];
+ });
+
+ // normalize collision option
+ if ( collision.length === 1 ) {
+ collision[ 1 ] = collision[ 0 ];
+ }
+
+ if ( options.at[ 0 ] === "right" ) {
+ basePosition.left += targetWidth;
+ } else if ( options.at[ 0 ] === "center" ) {
+ basePosition.left += targetWidth / 2;
+ }
+
+ if ( options.at[ 1 ] === "bottom" ) {
+ basePosition.top += targetHeight;
+ } else if ( options.at[ 1 ] === "center" ) {
+ basePosition.top += targetHeight / 2;
+ }
+
+ atOffset = getOffsets( offsets.at, targetWidth, targetHeight );
+ basePosition.left += atOffset[ 0 ];
+ basePosition.top += atOffset[ 1 ];
+
+ return this.each(function() {
+ var collisionPosition, using,
+ elem = $( this ),
+ elemWidth = elem.outerWidth(),
+ elemHeight = elem.outerHeight(),
+ marginLeft = parseCss( this, "marginLeft" ),
+ marginTop = parseCss( this, "marginTop" ),
+ collisionWidth = elemWidth + marginLeft + parseCss( this, "marginRight" ) + scrollInfo.width,
+ collisionHeight = elemHeight + marginTop + parseCss( this, "marginBottom" ) + scrollInfo.height,
+ position = $.extend( {}, basePosition ),
+ myOffset = getOffsets( offsets.my, elem.outerWidth(), elem.outerHeight() );
+
+ if ( options.my[ 0 ] === "right" ) {
+ position.left -= elemWidth;
+ } else if ( options.my[ 0 ] === "center" ) {
+ position.left -= elemWidth / 2;
+ }
+
+ if ( options.my[ 1 ] === "bottom" ) {
+ position.top -= elemHeight;
+ } else if ( options.my[ 1 ] === "center" ) {
+ position.top -= elemHeight / 2;
+ }
+
+ position.left += myOffset[ 0 ];
+ position.top += myOffset[ 1 ];
+
+ // if the browser doesn't support fractions, then round for consistent results
+ if ( !$.support.offsetFractions ) {
+ position.left = round( position.left );
+ position.top = round( position.top );
+ }
+
+ collisionPosition = {
+ marginLeft: marginLeft,
+ marginTop: marginTop
+ };
+
+ $.each( [ "left", "top" ], function( i, dir ) {
+ if ( $.ui.position[ collision[ i ] ] ) {
+ $.ui.position[ collision[ i ] ][ dir ]( position, {
+ targetWidth: targetWidth,
+ targetHeight: targetHeight,
+ elemWidth: elemWidth,
+ elemHeight: elemHeight,
+ collisionPosition: collisionPosition,
+ collisionWidth: collisionWidth,
+ collisionHeight: collisionHeight,
+ offset: [ atOffset[ 0 ] + myOffset[ 0 ], atOffset [ 1 ] + myOffset[ 1 ] ],
+ my: options.my,
+ at: options.at,
+ within: within,
+ elem : elem
+ });
+ }
+ });
+
+ if ( options.using ) {
+ // adds feedback as second argument to using callback, if present
+ using = function( props ) {
+ var left = targetOffset.left - position.left,
+ right = left + targetWidth - elemWidth,
+ top = targetOffset.top - position.top,
+ bottom = top + targetHeight - elemHeight,
+ feedback = {
+ target: {
+ element: target,
+ left: targetOffset.left,
+ top: targetOffset.top,
+ width: targetWidth,
+ height: targetHeight
+ },
+ element: {
+ element: elem,
+ left: position.left,
+ top: position.top,
+ width: elemWidth,
+ height: elemHeight
+ },
+ horizontal: right < 0 ? "left" : left > 0 ? "right" : "center",
+ vertical: bottom < 0 ? "top" : top > 0 ? "bottom" : "middle"
+ };
+ if ( targetWidth < elemWidth && abs( left + right ) < targetWidth ) {
+ feedback.horizontal = "center";
+ }
+ if ( targetHeight < elemHeight && abs( top + bottom ) < targetHeight ) {
+ feedback.vertical = "middle";
+ }
+ if ( max( abs( left ), abs( right ) ) > max( abs( top ), abs( bottom ) ) ) {
+ feedback.important = "horizontal";
+ } else {
+ feedback.important = "vertical";
+ }
+ options.using.call( this, props, feedback );
+ };
+ }
+
+ elem.offset( $.extend( position, { using: using } ) );
+ });
+};
+
+$.ui.position = {
+ fit: {
+ left: function( position, data ) {
+ var within = data.within,
+ withinOffset = within.isWindow ? within.scrollLeft : within.offset.left,
+ outerWidth = within.width,
+ collisionPosLeft = position.left - data.collisionPosition.marginLeft,
+ overLeft = withinOffset - collisionPosLeft,
+ overRight = collisionPosLeft + data.collisionWidth - outerWidth - withinOffset,
+ newOverRight;
+
+ // element is wider than within
+ if ( data.collisionWidth > outerWidth ) {
+ // element is initially over the left side of within
+ if ( overLeft > 0 && overRight <= 0 ) {
+ newOverRight = position.left + overLeft + data.collisionWidth - outerWidth - withinOffset;
+ position.left += overLeft - newOverRight;
+ // element is initially over right side of within
+ } else if ( overRight > 0 && overLeft <= 0 ) {
+ position.left = withinOffset;
+ // element is initially over both left and right sides of within
+ } else {
+ if ( overLeft > overRight ) {
+ position.left = withinOffset + outerWidth - data.collisionWidth;
+ } else {
+ position.left = withinOffset;
+ }
+ }
+ // too far left -> align with left edge
+ } else if ( overLeft > 0 ) {
+ position.left += overLeft;
+ // too far right -> align with right edge
+ } else if ( overRight > 0 ) {
+ position.left -= overRight;
+ // adjust based on position and margin
+ } else {
+ position.left = max( position.left - collisionPosLeft, position.left );
+ }
+ },
+ top: function( position, data ) {
+ var within = data.within,
+ withinOffset = within.isWindow ? within.scrollTop : within.offset.top,
+ outerHeight = data.within.height,
+ collisionPosTop = position.top - data.collisionPosition.marginTop,
+ overTop = withinOffset - collisionPosTop,
+ overBottom = collisionPosTop + data.collisionHeight - outerHeight - withinOffset,
+ newOverBottom;
+
+ // element is taller than within
+ if ( data.collisionHeight > outerHeight ) {
+ // element is initially over the top of within
+ if ( overTop > 0 && overBottom <= 0 ) {
+ newOverBottom = position.top + overTop + data.collisionHeight - outerHeight - withinOffset;
+ position.top += overTop - newOverBottom;
+ // element is initially over bottom of within
+ } else if ( overBottom > 0 && overTop <= 0 ) {
+ position.top = withinOffset;
+ // element is initially over both top and bottom of within
+ } else {
+ if ( overTop > overBottom ) {
+ position.top = withinOffset + outerHeight - data.collisionHeight;
+ } else {
+ position.top = withinOffset;
+ }
+ }
+ // too far up -> align with top
+ } else if ( overTop > 0 ) {
+ position.top += overTop;
+ // too far down -> align with bottom edge
+ } else if ( overBottom > 0 ) {
+ position.top -= overBottom;
+ // adjust based on position and margin
+ } else {
+ position.top = max( position.top - collisionPosTop, position.top );
+ }
+ }
+ },
+ flip: {
+ left: function( position, data ) {
+ var within = data.within,
+ withinOffset = within.offset.left + within.scrollLeft,
+ outerWidth = within.width,
+ offsetLeft = within.isWindow ? within.scrollLeft : within.offset.left,
+ collisionPosLeft = position.left - data.collisionPosition.marginLeft,
+ overLeft = collisionPosLeft - offsetLeft,
+ overRight = collisionPosLeft + data.collisionWidth - outerWidth - offsetLeft,
+ myOffset = data.my[ 0 ] === "left" ?
+ -data.elemWidth :
+ data.my[ 0 ] === "right" ?
+ data.elemWidth :
+ 0,
+ atOffset = data.at[ 0 ] === "left" ?
+ data.targetWidth :
+ data.at[ 0 ] === "right" ?
+ -data.targetWidth :
+ 0,
+ offset = -2 * data.offset[ 0 ],
+ newOverRight,
+ newOverLeft;
+
+ if ( overLeft < 0 ) {
+ newOverRight = position.left + myOffset + atOffset + offset + data.collisionWidth - outerWidth - withinOffset;
+ if ( newOverRight < 0 || newOverRight < abs( overLeft ) ) {
+ position.left += myOffset + atOffset + offset;
+ }
+ }
+ else if ( overRight > 0 ) {
+ newOverLeft = position.left - data.collisionPosition.marginLeft + myOffset + atOffset + offset - offsetLeft;
+ if ( newOverLeft > 0 || abs( newOverLeft ) < overRight ) {
+ position.left += myOffset + atOffset + offset;
+ }
+ }
+ },
+ top: function( position, data ) {
+ var within = data.within,
+ withinOffset = within.offset.top + within.scrollTop,
+ outerHeight = within.height,
+ offsetTop = within.isWindow ? within.scrollTop : within.offset.top,
+ collisionPosTop = position.top - data.collisionPosition.marginTop,
+ overTop = collisionPosTop - offsetTop,
+ overBottom = collisionPosTop + data.collisionHeight - outerHeight - offsetTop,
+ top = data.my[ 1 ] === "top",
+ myOffset = top ?
+ -data.elemHeight :
+ data.my[ 1 ] === "bottom" ?
+ data.elemHeight :
+ 0,
+ atOffset = data.at[ 1 ] === "top" ?
+ data.targetHeight :
+ data.at[ 1 ] === "bottom" ?
+ -data.targetHeight :
+ 0,
+ offset = -2 * data.offset[ 1 ],
+ newOverTop,
+ newOverBottom;
+ if ( overTop < 0 ) {
+ newOverBottom = position.top + myOffset + atOffset + offset + data.collisionHeight - outerHeight - withinOffset;
+ if ( ( position.top + myOffset + atOffset + offset) > overTop && ( newOverBottom < 0 || newOverBottom < abs( overTop ) ) ) {
+ position.top += myOffset + atOffset + offset;
+ }
+ }
+ else if ( overBottom > 0 ) {
+ newOverTop = position.top - data.collisionPosition.marginTop + myOffset + atOffset + offset - offsetTop;
+ if ( ( position.top + myOffset + atOffset + offset) > overBottom && ( newOverTop > 0 || abs( newOverTop ) < overBottom ) ) {
+ position.top += myOffset + atOffset + offset;
+ }
+ }
+ }
+ },
+ flipfit: {
+ left: function() {
+ $.ui.position.flip.left.apply( this, arguments );
+ $.ui.position.fit.left.apply( this, arguments );
+ },
+ top: function() {
+ $.ui.position.flip.top.apply( this, arguments );
+ $.ui.position.fit.top.apply( this, arguments );
+ }
+ }
+};
+
+// fraction support test
+(function () {
+ var testElement, testElementParent, testElementStyle, offsetLeft, i,
+ body = document.getElementsByTagName( "body" )[ 0 ],
+ div = document.createElement( "div" );
+
+ //Create a "fake body" for testing based on method used in jQuery.support
+ testElement = document.createElement( body ? "div" : "body" );
+ testElementStyle = {
+ visibility: "hidden",
+ width: 0,
+ height: 0,
+ border: 0,
+ margin: 0,
+ background: "none"
+ };
+ if ( body ) {
+ $.extend( testElementStyle, {
+ position: "absolute",
+ left: "-1000px",
+ top: "-1000px"
+ });
+ }
+ for ( i in testElementStyle ) {
+ testElement.style[ i ] = testElementStyle[ i ];
+ }
+ testElement.appendChild( div );
+ testElementParent = body || document.documentElement;
+ testElementParent.insertBefore( testElement, testElementParent.firstChild );
+
+ div.style.cssText = "position: absolute; left: 10.7432222px;";
+
+ offsetLeft = $( div ).offset().left;
+ $.support.offsetFractions = offsetLeft > 10 && offsetLeft < 11;
+
+ testElement.innerHTML = "";
+ testElementParent.removeChild( testElement );
+})();
+
+}( jQuery ) );
+
+(function( $, undefined ) {
+
+$.widget( "ui.progressbar", {
+ version: "1.10.3",
+ options: {
+ max: 100,
+ value: 0,
+
+ change: null,
+ complete: null
+ },
+
+ min: 0,
+
+ _create: function() {
+ // Constrain initial value
+ this.oldValue = this.options.value = this._constrainedValue();
+
+ this.element
+ .addClass( "ui-progressbar ui-widget ui-widget-content ui-corner-all" )
+ .attr({
+ // Only set static values, aria-valuenow and aria-valuemax are
+ // set inside _refreshValue()
+ role: "progressbar",
+ "aria-valuemin": this.min
+ });
+
+ this.valueDiv = $( "<div class='ui-progressbar-value ui-widget-header ui-corner-left'></div>" )
+ .appendTo( this.element );
+
+ this._refreshValue();
+ },
+
+ _destroy: function() {
+ this.element
+ .removeClass( "ui-progressbar ui-widget ui-widget-content ui-corner-all" )
+ .removeAttr( "role" )
+ .removeAttr( "aria-valuemin" )
+ .removeAttr( "aria-valuemax" )
+ .removeAttr( "aria-valuenow" );
+
+ this.valueDiv.remove();
+ },
+
+ value: function( newValue ) {
+ if ( newValue === undefined ) {
+ return this.options.value;
+ }
+
+ this.options.value = this._constrainedValue( newValue );
+ this._refreshValue();
+ },
+
+ _constrainedValue: function( newValue ) {
+ if ( newValue === undefined ) {
+ newValue = this.options.value;
+ }
+
+ this.indeterminate = newValue === false;
+
+ // sanitize value
+ if ( typeof newValue !== "number" ) {
+ newValue = 0;
+ }
+
+ return this.indeterminate ? false :
+ Math.min( this.options.max, Math.max( this.min, newValue ) );
+ },
+
+ _setOptions: function( options ) {
+ // Ensure "value" option is set after other values (like max)
+ var value = options.value;
+ delete options.value;
+
+ this._super( options );
+
+ this.options.value = this._constrainedValue( value );
+ this._refreshValue();
+ },
+
+ _setOption: function( key, value ) {
+ if ( key === "max" ) {
+ // Don't allow a max less than min
+ value = Math.max( this.min, value );
+ }
+
+ this._super( key, value );
+ },
+
+ _percentage: function() {
+ return this.indeterminate ? 100 : 100 * ( this.options.value - this.min ) / ( this.options.max - this.min );
+ },
+
+ _refreshValue: function() {
+ var value = this.options.value,
+ percentage = this._percentage();
+
+ this.valueDiv
+ .toggle( this.indeterminate || value > this.min )
+ .toggleClass( "ui-corner-right", value === this.options.max )
+ .width( percentage.toFixed(0) + "%" );
+
+ this.element.toggleClass( "ui-progressbar-indeterminate", this.indeterminate );
+
+ if ( this.indeterminate ) {
+ this.element.removeAttr( "aria-valuenow" );
+ if ( !this.overlayDiv ) {
+ this.overlayDiv = $( "<div class='ui-progressbar-overlay'></div>" ).appendTo( this.valueDiv );
+ }
+ } else {
+ this.element.attr({
+ "aria-valuemax": this.options.max,
+ "aria-valuenow": value
+ });
+ if ( this.overlayDiv ) {
+ this.overlayDiv.remove();
+ this.overlayDiv = null;
+ }
+ }
+
+ if ( this.oldValue !== value ) {
+ this.oldValue = value;
+ this._trigger( "change" );
+ }
+ if ( value === this.options.max ) {
+ this._trigger( "complete" );
+ }
+ }
+});
+
+})( jQuery );
+
+(function( $, undefined ) {
+
+// number of pages in a slider
+// (how many times can you page up/down to go through the whole range)
+var numPages = 5;
+
+$.widget( "ui.slider", $.ui.mouse, {
+ version: "1.10.3",
+ widgetEventPrefix: "slide",
+
+ options: {
+ animate: false,
+ distance: 0,
+ max: 100,
+ min: 0,
+ orientation: "horizontal",
+ range: false,
+ step: 1,
+ value: 0,
+ values: null,
+
+ // callbacks
+ change: null,
+ slide: null,
+ start: null,
+ stop: null
+ },
+
+ _create: function() {
+ this._keySliding = false;
+ this._mouseSliding = false;
+ this._animateOff = true;
+ this._handleIndex = null;
+ this._detectOrientation();
+ this._mouseInit();
+
+ this.element
+ .addClass( "ui-slider" +
+ " ui-slider-" + this.orientation +
+ " ui-widget" +
+ " ui-widget-content" +
+ " ui-corner-all");
+
+ this._refresh();
+ this._setOption( "disabled", this.options.disabled );
+
+ this._animateOff = false;
+ },
+
+ _refresh: function() {
+ this._createRange();
+ this._createHandles();
+ this._setupEvents();
+ this._refreshValue();
+ },
+
+ _createHandles: function() {
+ var i, handleCount,
+ options = this.options,
+ existingHandles = this.element.find( ".ui-slider-handle" ).addClass( "ui-state-default ui-corner-all" ),
+ handle = "<a class='ui-slider-handle ui-state-default ui-corner-all' href='#'></a>",
+ handles = [];
+
+ handleCount = ( options.values && options.values.length ) || 1;
+
+ if ( existingHandles.length > handleCount ) {
+ existingHandles.slice( handleCount ).remove();
+ existingHandles = existingHandles.slice( 0, handleCount );
+ }
+
+ for ( i = existingHandles.length; i < handleCount; i++ ) {
+ handles.push( handle );
+ }
+
+ this.handles = existingHandles.add( $( handles.join( "" ) ).appendTo( this.element ) );
+
+ this.handle = this.handles.eq( 0 );
+
+ this.handles.each(function( i ) {
+ $( this ).data( "ui-slider-handle-index", i );
+ });
+ },
+
+ _createRange: function() {
+ var options = this.options,
+ classes = "";
+
+ if ( options.range ) {
+ if ( options.range === true ) {
+ if ( !options.values ) {
+ options.values = [ this._valueMin(), this._valueMin() ];
+ } else if ( options.values.length && options.values.length !== 2 ) {
+ options.values = [ options.values[0], options.values[0] ];
+ } else if ( $.isArray( options.values ) ) {
+ options.values = options.values.slice(0);
+ }
+ }
+
+ if ( !this.range || !this.range.length ) {
+ this.range = $( "<div></div>" )
+ .appendTo( this.element );
+
+ classes = "ui-slider-range" +
+ // note: this isn't the most fittingly semantic framework class for this element,
+ // but worked best visually with a variety of themes
+ " ui-widget-header ui-corner-all";
+ } else {
+ this.range.removeClass( "ui-slider-range-min ui-slider-range-max" )
+ // Handle range switching from true to min/max
+ .css({
+ "left": "",
+ "bottom": ""
+ });
+ }
+
+ this.range.addClass( classes +
+ ( ( options.range === "min" || options.range === "max" ) ? " ui-slider-range-" + options.range : "" ) );
+ } else {
+ this.range = $([]);
+ }
+ },
+
+ _setupEvents: function() {
+ var elements = this.handles.add( this.range ).filter( "a" );
+ this._off( elements );
+ this._on( elements, this._handleEvents );
+ this._hoverable( elements );
+ this._focusable( elements );
+ },
+
+ _destroy: function() {
+ this.handles.remove();
+ this.range.remove();
+
+ this.element
+ .removeClass( "ui-slider" +
+ " ui-slider-horizontal" +
+ " ui-slider-vertical" +
+ " ui-widget" +
+ " ui-widget-content" +
+ " ui-corner-all" );
+
+ this._mouseDestroy();
+ },
+
+ _mouseCapture: function( event ) {
+ var position, normValue, distance, closestHandle, index, allowed, offset, mouseOverHandle,
+ that = this,
+ o = this.options;
+
+ if ( o.disabled ) {
+ return false;
+ }
+
+ this.elementSize = {
+ width: this.element.outerWidth(),
+ height: this.element.outerHeight()
+ };
+ this.elementOffset = this.element.offset();
+
+ position = { x: event.pageX, y: event.pageY };
+ normValue = this._normValueFromMouse( position );
+ distance = this._valueMax() - this._valueMin() + 1;
+ this.handles.each(function( i ) {
+ var thisDistance = Math.abs( normValue - that.values(i) );
+ if (( distance > thisDistance ) ||
+ ( distance === thisDistance &&
+ (i === that._lastChangedValue || that.values(i) === o.min ))) {
+ distance = thisDistance;
+ closestHandle = $( this );
+ index = i;
+ }
+ });
+
+ allowed = this._start( event, index );
+ if ( allowed === false ) {
+ return false;
+ }
+ this._mouseSliding = true;
+
+ this._handleIndex = index;
+
+ closestHandle
+ .addClass( "ui-state-active" )
+ .focus();
+
+ offset = closestHandle.offset();
+ mouseOverHandle = !$( event.target ).parents().addBack().is( ".ui-slider-handle" );
+ this._clickOffset = mouseOverHandle ? { left: 0, top: 0 } : {
+ left: event.pageX - offset.left - ( closestHandle.width() / 2 ),
+ top: event.pageY - offset.top -
+ ( closestHandle.height() / 2 ) -
+ ( parseInt( closestHandle.css("borderTopWidth"), 10 ) || 0 ) -
+ ( parseInt( closestHandle.css("borderBottomWidth"), 10 ) || 0) +
+ ( parseInt( closestHandle.css("marginTop"), 10 ) || 0)
+ };
+
+ if ( !this.handles.hasClass( "ui-state-hover" ) ) {
+ this._slide( event, index, normValue );
+ }
+ this._animateOff = true;
+ return true;
+ },
+
+ _mouseStart: function() {
+ return true;
+ },
+
+ _mouseDrag: function( event ) {
+ var position = { x: event.pageX, y: event.pageY },
+ normValue = this._normValueFromMouse( position );
+
+ this._slide( event, this._handleIndex, normValue );
+
+ return false;
+ },
+
+ _mouseStop: function( event ) {
+ this.handles.removeClass( "ui-state-active" );
+ this._mouseSliding = false;
+
+ this._stop( event, this._handleIndex );
+ this._change( event, this._handleIndex );
+
+ this._handleIndex = null;
+ this._clickOffset = null;
+ this._animateOff = false;
+
+ return false;
+ },
+
+ _detectOrientation: function() {
+ this.orientation = ( this.options.orientation === "vertical" ) ? "vertical" : "horizontal";
+ },
+
+ _normValueFromMouse: function( position ) {
+ var pixelTotal,
+ pixelMouse,
+ percentMouse,
+ valueTotal,
+ valueMouse;
+
+ if ( this.orientation === "horizontal" ) {
+ pixelTotal = this.elementSize.width;
+ pixelMouse = position.x - this.elementOffset.left - ( this._clickOffset ? this._clickOffset.left : 0 );
+ } else {
+ pixelTotal = this.elementSize.height;
+ pixelMouse = position.y - this.elementOffset.top - ( this._clickOffset ? this._clickOffset.top : 0 );
+ }
+
+ percentMouse = ( pixelMouse / pixelTotal );
+ if ( percentMouse > 1 ) {
+ percentMouse = 1;
+ }
+ if ( percentMouse < 0 ) {
+ percentMouse = 0;
+ }
+ if ( this.orientation === "vertical" ) {
+ percentMouse = 1 - percentMouse;
+ }
+
+ valueTotal = this._valueMax() - this._valueMin();
+ valueMouse = this._valueMin() + percentMouse * valueTotal;
+
+ return this._trimAlignValue( valueMouse );
+ },
+
+ _start: function( event, index ) {
+ var uiHash = {
+ handle: this.handles[ index ],
+ value: this.value()
+ };
+ if ( this.options.values && this.options.values.length ) {
+ uiHash.value = this.values( index );
+ uiHash.values = this.values();
+ }
+ return this._trigger( "start", event, uiHash );
+ },
+
+ _slide: function( event, index, newVal ) {
+ var otherVal,
+ newValues,
+ allowed;
+
+ if ( this.options.values && this.options.values.length ) {
+ otherVal = this.values( index ? 0 : 1 );
+
+ if ( ( this.options.values.length === 2 && this.options.range === true ) &&
+ ( ( index === 0 && newVal > otherVal) || ( index === 1 && newVal < otherVal ) )
+ ) {
+ newVal = otherVal;
+ }
+
+ if ( newVal !== this.values( index ) ) {
+ newValues = this.values();
+ newValues[ index ] = newVal;
+ // A slide can be canceled by returning false from the slide callback
+ allowed = this._trigger( "slide", event, {
+ handle: this.handles[ index ],
+ value: newVal,
+ values: newValues
+ } );
+ otherVal = this.values( index ? 0 : 1 );
+ if ( allowed !== false ) {
+ this.values( index, newVal, true );
+ }
+ }
+ } else {
+ if ( newVal !== this.value() ) {
+ // A slide can be canceled by returning false from the slide callback
+ allowed = this._trigger( "slide", event, {
+ handle: this.handles[ index ],
+ value: newVal
+ } );
+ if ( allowed !== false ) {
+ this.value( newVal );
+ }
+ }
+ }
+ },
+
+ _stop: function( event, index ) {
+ var uiHash = {
+ handle: this.handles[ index ],
+ value: this.value()
+ };
+ if ( this.options.values && this.options.values.length ) {
+ uiHash.value = this.values( index );
+ uiHash.values = this.values();
+ }
+
+ this._trigger( "stop", event, uiHash );
+ },
+
+ _change: function( event, index ) {
+ if ( !this._keySliding && !this._mouseSliding ) {
+ var uiHash = {
+ handle: this.handles[ index ],
+ value: this.value()
+ };
+ if ( this.options.values && this.options.values.length ) {
+ uiHash.value = this.values( index );
+ uiHash.values = this.values();
+ }
+
+ //store the last changed value index for reference when handles overlap
+ this._lastChangedValue = index;
+
+ this._trigger( "change", event, uiHash );
+ }
+ },
+
+ value: function( newValue ) {
+ if ( arguments.length ) {
+ this.options.value = this._trimAlignValue( newValue );
+ this._refreshValue();
+ this._change( null, 0 );
+ return;
+ }
+
+ return this._value();
+ },
+
+ values: function( index, newValue ) {
+ var vals,
+ newValues,
+ i;
+
+ if ( arguments.length > 1 ) {
+ this.options.values[ index ] = this._trimAlignValue( newValue );
+ this._refreshValue();
+ this._change( null, index );
+ return;
+ }
+
+ if ( arguments.length ) {
+ if ( $.isArray( arguments[ 0 ] ) ) {
+ vals = this.options.values;
+ newValues = arguments[ 0 ];
+ for ( i = 0; i < vals.length; i += 1 ) {
+ vals[ i ] = this._trimAlignValue( newValues[ i ] );
+ this._change( null, i );
+ }
+ this._refreshValue();
+ } else {
+ if ( this.options.values && this.options.values.length ) {
+ return this._values( index );
+ } else {
+ return this.value();
+ }
+ }
+ } else {
+ return this._values();
+ }
+ },
+
+ _setOption: function( key, value ) {
+ var i,
+ valsLength = 0;
+
+ if ( key === "range" && this.options.range === true ) {
+ if ( value === "min" ) {
+ this.options.value = this._values( 0 );
+ this.options.values = null;
+ } else if ( value === "max" ) {
+ this.options.value = this._values( this.options.values.length-1 );
+ this.options.values = null;
+ }
+ }
+
+ if ( $.isArray( this.options.values ) ) {
+ valsLength = this.options.values.length;
+ }
+
+ $.Widget.prototype._setOption.apply( this, arguments );
+
+ switch ( key ) {
+ case "orientation":
+ this._detectOrientation();
+ this.element
+ .removeClass( "ui-slider-horizontal ui-slider-vertical" )
+ .addClass( "ui-slider-" + this.orientation );
+ this._refreshValue();
+ break;
+ case "value":
+ this._animateOff = true;
+ this._refreshValue();
+ this._change( null, 0 );
+ this._animateOff = false;
+ break;
+ case "values":
+ this._animateOff = true;
+ this._refreshValue();
+ for ( i = 0; i < valsLength; i += 1 ) {
+ this._change( null, i );
+ }
+ this._animateOff = false;
+ break;
+ case "min":
+ case "max":
+ this._animateOff = true;
+ this._refreshValue();
+ this._animateOff = false;
+ break;
+ case "range":
+ this._animateOff = true;
+ this._refresh();
+ this._animateOff = false;
+ break;
+ }
+ },
+
+ //internal value getter
+ // _value() returns value trimmed by min and max, aligned by step
+ _value: function() {
+ var val = this.options.value;
+ val = this._trimAlignValue( val );
+
+ return val;
+ },
+
+ //internal values getter
+ // _values() returns array of values trimmed by min and max, aligned by step
+ // _values( index ) returns single value trimmed by min and max, aligned by step
+ _values: function( index ) {
+ var val,
+ vals,
+ i;
+
+ if ( arguments.length ) {
+ val = this.options.values[ index ];
+ val = this._trimAlignValue( val );
+
+ return val;
+ } else if ( this.options.values && this.options.values.length ) {
+ // .slice() creates a copy of the array
+ // this copy gets trimmed by min and max and then returned
+ vals = this.options.values.slice();
+ for ( i = 0; i < vals.length; i+= 1) {
+ vals[ i ] = this._trimAlignValue( vals[ i ] );
+ }
+
+ return vals;
+ } else {
+ return [];
+ }
+ },
+
+ // returns the step-aligned value that val is closest to, between (inclusive) min and max
+ _trimAlignValue: function( val ) {
+ if ( val <= this._valueMin() ) {
+ return this._valueMin();
+ }
+ if ( val >= this._valueMax() ) {
+ return this._valueMax();
+ }
+ var step = ( this.options.step > 0 ) ? this.options.step : 1,
+ valModStep = (val - this._valueMin()) % step,
+ alignValue = val - valModStep;
+
+ if ( Math.abs(valModStep) * 2 >= step ) {
+ alignValue += ( valModStep > 0 ) ? step : ( -step );
+ }
+
+ // Since JavaScript has problems with large floats, round
+ // the final value to 5 digits after the decimal point (see #4124)
+ return parseFloat( alignValue.toFixed(5) );
+ },
+
+ _valueMin: function() {
+ return this.options.min;
+ },
+
+ _valueMax: function() {
+ return this.options.max;
+ },
+
+ _refreshValue: function() {
+ var lastValPercent, valPercent, value, valueMin, valueMax,
+ oRange = this.options.range,
+ o = this.options,
+ that = this,
+ animate = ( !this._animateOff ) ? o.animate : false,
+ _set = {};
+
+ if ( this.options.values && this.options.values.length ) {
+ this.handles.each(function( i ) {
+ valPercent = ( that.values(i) - that._valueMin() ) / ( that._valueMax() - that._valueMin() ) * 100;
+ _set[ that.orientation === "horizontal" ? "left" : "bottom" ] = valPercent + "%";
+ $( this ).stop( 1, 1 )[ animate ? "animate" : "css" ]( _set, o.animate );
+ if ( that.options.range === true ) {
+ if ( that.orientation === "horizontal" ) {
+ if ( i === 0 ) {
+ that.range.stop( 1, 1 )[ animate ? "animate" : "css" ]( { left: valPercent + "%" }, o.animate );
+ }
+ if ( i === 1 ) {
+ that.range[ animate ? "animate" : "css" ]( { width: ( valPercent - lastValPercent ) + "%" }, { queue: false, duration: o.animate } );
+ }
+ } else {
+ if ( i === 0 ) {
+ that.range.stop( 1, 1 )[ animate ? "animate" : "css" ]( { bottom: ( valPercent ) + "%" }, o.animate );
+ }
+ if ( i === 1 ) {
+ that.range[ animate ? "animate" : "css" ]( { height: ( valPercent - lastValPercent ) + "%" }, { queue: false, duration: o.animate } );
+ }
+ }
+ }
+ lastValPercent = valPercent;
+ });
+ } else {
+ value = this.value();
+ valueMin = this._valueMin();
+ valueMax = this._valueMax();
+ valPercent = ( valueMax !== valueMin ) ?
+ ( value - valueMin ) / ( valueMax - valueMin ) * 100 :
+ 0;
+ _set[ this.orientation === "horizontal" ? "left" : "bottom" ] = valPercent + "%";
+ this.handle.stop( 1, 1 )[ animate ? "animate" : "css" ]( _set, o.animate );
+
+ if ( oRange === "min" && this.orientation === "horizontal" ) {
+ this.range.stop( 1, 1 )[ animate ? "animate" : "css" ]( { width: valPercent + "%" }, o.animate );
+ }
+ if ( oRange === "max" && this.orientation === "horizontal" ) {
+ this.range[ animate ? "animate" : "css" ]( { width: ( 100 - valPercent ) + "%" }, { queue: false, duration: o.animate } );
+ }
+ if ( oRange === "min" && this.orientation === "vertical" ) {
+ this.range.stop( 1, 1 )[ animate ? "animate" : "css" ]( { height: valPercent + "%" }, o.animate );
+ }
+ if ( oRange === "max" && this.orientation === "vertical" ) {
+ this.range[ animate ? "animate" : "css" ]( { height: ( 100 - valPercent ) + "%" }, { queue: false, duration: o.animate } );
+ }
+ }
+ },
+
+ _handleEvents: {
+ keydown: function( event ) {
+ /*jshint maxcomplexity:25*/
+ var allowed, curVal, newVal, step,
+ index = $( event.target ).data( "ui-slider-handle-index" );
+
+ switch ( event.keyCode ) {
+ case $.ui.keyCode.HOME:
+ case $.ui.keyCode.END:
+ case $.ui.keyCode.PAGE_UP:
+ case $.ui.keyCode.PAGE_DOWN:
+ case $.ui.keyCode.UP:
+ case $.ui.keyCode.RIGHT:
+ case $.ui.keyCode.DOWN:
+ case $.ui.keyCode.LEFT:
+ event.preventDefault();
+ if ( !this._keySliding ) {
+ this._keySliding = true;
+ $( event.target ).addClass( "ui-state-active" );
+ allowed = this._start( event, index );
+ if ( allowed === false ) {
+ return;
+ }
+ }
+ break;
+ }
+
+ step = this.options.step;
+ if ( this.options.values && this.options.values.length ) {
+ curVal = newVal = this.values( index );
+ } else {
+ curVal = newVal = this.value();
+ }
+
+ switch ( event.keyCode ) {
+ case $.ui.keyCode.HOME:
+ newVal = this._valueMin();
+ break;
+ case $.ui.keyCode.END:
+ newVal = this._valueMax();
+ break;
+ case $.ui.keyCode.PAGE_UP:
+ newVal = this._trimAlignValue( curVal + ( (this._valueMax() - this._valueMin()) / numPages ) );
+ break;
+ case $.ui.keyCode.PAGE_DOWN:
+ newVal = this._trimAlignValue( curVal - ( (this._valueMax() - this._valueMin()) / numPages ) );
+ break;
+ case $.ui.keyCode.UP:
+ case $.ui.keyCode.RIGHT:
+ if ( curVal === this._valueMax() ) {
+ return;
+ }
+ newVal = this._trimAlignValue( curVal + step );
+ break;
+ case $.ui.keyCode.DOWN:
+ case $.ui.keyCode.LEFT:
+ if ( curVal === this._valueMin() ) {
+ return;
+ }
+ newVal = this._trimAlignValue( curVal - step );
+ break;
+ }
+
+ this._slide( event, index, newVal );
+ },
+ click: function( event ) {
+ event.preventDefault();
+ },
+ keyup: function( event ) {
+ var index = $( event.target ).data( "ui-slider-handle-index" );
+
+ if ( this._keySliding ) {
+ this._keySliding = false;
+ this._stop( event, index );
+ this._change( event, index );
+ $( event.target ).removeClass( "ui-state-active" );
+ }
+ }
+ }
+
+});
+
+}(jQuery));
+
+(function( $ ) {
+
+function modifier( fn ) {
+ return function() {
+ var previous = this.element.val();
+ fn.apply( this, arguments );
+ this._refresh();
+ if ( previous !== this.element.val() ) {
+ this._trigger( "change" );
+ }
+ };
+}
+
+$.widget( "ui.spinner", {
+ version: "1.10.3",
+ defaultElement: "<input>",
+ widgetEventPrefix: "spin",
+ options: {
+ culture: null,
+ icons: {
+ down: "ui-icon-triangle-1-s",
+ up: "ui-icon-triangle-1-n"
+ },
+ incremental: true,
+ max: null,
+ min: null,
+ numberFormat: null,
+ page: 10,
+ step: 1,
+
+ change: null,
+ spin: null,
+ start: null,
+ stop: null
+ },
+
+ _create: function() {
+ // handle string values that need to be parsed
+ this._setOption( "max", this.options.max );
+ this._setOption( "min", this.options.min );
+ this._setOption( "step", this.options.step );
+
+ // format the value, but don't constrain
+ this._value( this.element.val(), true );
+
+ this._draw();
+ this._on( this._events );
+ this._refresh();
+
+ // turning off autocomplete prevents the browser from remembering the
+ // value when navigating through history, so we re-enable autocomplete
+ // if the page is unloaded before the widget is destroyed. #7790
+ this._on( this.window, {
+ beforeunload: function() {
+ this.element.removeAttr( "autocomplete" );
+ }
+ });
+ },
+
+ _getCreateOptions: function() {
+ var options = {},
+ element = this.element;
+
+ $.each( [ "min", "max", "step" ], function( i, option ) {
+ var value = element.attr( option );
+ if ( value !== undefined && value.length ) {
+ options[ option ] = value;
+ }
+ });
+
+ return options;
+ },
+
+ _events: {
+ keydown: function( event ) {
+ if ( this._start( event ) && this._keydown( event ) ) {
+ event.preventDefault();
+ }
+ },
+ keyup: "_stop",
+ focus: function() {
+ this.previous = this.element.val();
+ },
+ blur: function( event ) {
+ if ( this.cancelBlur ) {
+ delete this.cancelBlur;
+ return;
+ }
+
+ this._stop();
+ this._refresh();
+ if ( this.previous !== this.element.val() ) {
+ this._trigger( "change", event );
+ }
+ },
+ mousewheel: function( event, delta ) {
+ if ( !delta ) {
+ return;
+ }
+ if ( !this.spinning && !this._start( event ) ) {
+ return false;
+ }
+
+ this._spin( (delta > 0 ? 1 : -1) * this.options.step, event );
+ clearTimeout( this.mousewheelTimer );
+ this.mousewheelTimer = this._delay(function() {
+ if ( this.spinning ) {
+ this._stop( event );
+ }
+ }, 100 );
+ event.preventDefault();
+ },
+ "mousedown .ui-spinner-button": function( event ) {
+ var previous;
+
+ // We never want the buttons to have focus; whenever the user is
+ // interacting with the spinner, the focus should be on the input.
+ // If the input is focused then this.previous is properly set from
+ // when the input first received focus. If the input is not focused
+ // then we need to set this.previous based on the value before spinning.
+ previous = this.element[0] === this.document[0].activeElement ?
+ this.previous : this.element.val();
+ function checkFocus() {
+ var isActive = this.element[0] === this.document[0].activeElement;
+ if ( !isActive ) {
+ this.element.focus();
+ this.previous = previous;
+ // support: IE
+ // IE sets focus asynchronously, so we need to check if focus
+ // moved off of the input because the user clicked on the button.
+ this._delay(function() {
+ this.previous = previous;
+ });
+ }
+ }
+
+ // ensure focus is on (or stays on) the text field
+ event.preventDefault();
+ checkFocus.call( this );
+
+ // support: IE
+ // IE doesn't prevent moving focus even with event.preventDefault()
+ // so we set a flag to know when we should ignore the blur event
+ // and check (again) if focus moved off of the input.
+ this.cancelBlur = true;
+ this._delay(function() {
+ delete this.cancelBlur;
+ checkFocus.call( this );
+ });
+
+ if ( this._start( event ) === false ) {
+ return;
+ }
+
+ this._repeat( null, $( event.currentTarget ).hasClass( "ui-spinner-up" ) ? 1 : -1, event );
+ },
+ "mouseup .ui-spinner-button": "_stop",
+ "mouseenter .ui-spinner-button": function( event ) {
+ // button will add ui-state-active if mouse was down while mouseleave and kept down
+ if ( !$( event.currentTarget ).hasClass( "ui-state-active" ) ) {
+ return;
+ }
+
+ if ( this._start( event ) === false ) {
+ return false;
+ }
+ this._repeat( null, $( event.currentTarget ).hasClass( "ui-spinner-up" ) ? 1 : -1, event );
+ },
+ // TODO: do we really want to consider this a stop?
+ // shouldn't we just stop the repeater and wait until mouseup before
+ // we trigger the stop event?
+ "mouseleave .ui-spinner-button": "_stop"
+ },
+
+ _draw: function() {
+ var uiSpinner = this.uiSpinner = this.element
+ .addClass( "ui-spinner-input" )
+ .attr( "autocomplete", "off" )
+ .wrap( this._uiSpinnerHtml() )
+ .parent()
+ // add buttons
+ .append( this._buttonHtml() );
+
+ this.element.attr( "role", "spinbutton" );
+
+ // button bindings
+ this.buttons = uiSpinner.find( ".ui-spinner-button" )
+ .attr( "tabIndex", -1 )
+ .button()
+ .removeClass( "ui-corner-all" );
+
+ // IE 6 doesn't understand height: 50% for the buttons
+ // unless the wrapper has an explicit height
+ if ( this.buttons.height() > Math.ceil( uiSpinner.height() * 0.5 ) &&
+ uiSpinner.height() > 0 ) {
+ uiSpinner.height( uiSpinner.height() );
+ }
+
+ // disable spinner if element was already disabled
+ if ( this.options.disabled ) {
+ this.disable();
+ }
+ },
+
+ _keydown: function( event ) {
+ var options = this.options,
+ keyCode = $.ui.keyCode;
+
+ switch ( event.keyCode ) {
+ case keyCode.UP:
+ this._repeat( null, 1, event );
+ return true;
+ case keyCode.DOWN:
+ this._repeat( null, -1, event );
+ return true;
+ case keyCode.PAGE_UP:
+ this._repeat( null, options.page, event );
+ return true;
+ case keyCode.PAGE_DOWN:
+ this._repeat( null, -options.page, event );
+ return true;
+ }
+
+ return false;
+ },
+
+ _uiSpinnerHtml: function() {
+ return "<span class='ui-spinner ui-widget ui-widget-content ui-corner-all'></span>";
+ },
+
+ _buttonHtml: function() {
+ return "" +
+ "<a class='ui-spinner-button ui-spinner-up ui-corner-tr'>" +
+ "<span class='ui-icon " + this.options.icons.up + "'>&#9650;</span>" +
+ "</a>" +
+ "<a class='ui-spinner-button ui-spinner-down ui-corner-br'>" +
+ "<span class='ui-icon " + this.options.icons.down + "'>&#9660;</span>" +
+ "</a>";
+ },
+
+ _start: function( event ) {
+ if ( !this.spinning && this._trigger( "start", event ) === false ) {
+ return false;
+ }
+
+ if ( !this.counter ) {
+ this.counter = 1;
+ }
+ this.spinning = true;
+ return true;
+ },
+
+ _repeat: function( i, steps, event ) {
+ i = i || 500;
+
+ clearTimeout( this.timer );
+ this.timer = this._delay(function() {
+ this._repeat( 40, steps, event );
+ }, i );
+
+ this._spin( steps * this.options.step, event );
+ },
+
+ _spin: function( step, event ) {
+ var value = this.value() || 0;
+
+ if ( !this.counter ) {
+ this.counter = 1;
+ }
+
+ value = this._adjustValue( value + step * this._increment( this.counter ) );
+
+ if ( !this.spinning || this._trigger( "spin", event, { value: value } ) !== false) {
+ this._value( value );
+ this.counter++;
+ }
+ },
+
+ _increment: function( i ) {
+ var incremental = this.options.incremental;
+
+ if ( incremental ) {
+ return $.isFunction( incremental ) ?
+ incremental( i ) :
+ Math.floor( i*i*i/50000 - i*i/500 + 17*i/200 + 1 );
+ }
+
+ return 1;
+ },
+
+ _precision: function() {
+ var precision = this._precisionOf( this.options.step );
+ if ( this.options.min !== null ) {
+ precision = Math.max( precision, this._precisionOf( this.options.min ) );
+ }
+ return precision;
+ },
+
+ _precisionOf: function( num ) {
+ var str = num.toString(),
+ decimal = str.indexOf( "." );
+ return decimal === -1 ? 0 : str.length - decimal - 1;
+ },
+
+ _adjustValue: function( value ) {
+ var base, aboveMin,
+ options = this.options;
+
+ // make sure we're at a valid step
+ // - find out where we are relative to the base (min or 0)
+ base = options.min !== null ? options.min : 0;
+ aboveMin = value - base;
+ // - round to the nearest step
+ aboveMin = Math.round(aboveMin / options.step) * options.step;
+ // - rounding is based on 0, so adjust back to our base
+ value = base + aboveMin;
+
+ // fix precision from bad JS floating point math
+ value = parseFloat( value.toFixed( this._precision() ) );
+
+ // clamp the value
+ if ( options.max !== null && value > options.max) {
+ return options.max;
+ }
+ if ( options.min !== null && value < options.min ) {
+ return options.min;
+ }
+
+ return value;
+ },
+
+ _stop: function( event ) {
+ if ( !this.spinning ) {
+ return;
+ }
+
+ clearTimeout( this.timer );
+ clearTimeout( this.mousewheelTimer );
+ this.counter = 0;
+ this.spinning = false;
+ this._trigger( "stop", event );
+ },
+
+ _setOption: function( key, value ) {
+ if ( key === "culture" || key === "numberFormat" ) {
+ var prevValue = this._parse( this.element.val() );
+ this.options[ key ] = value;
+ this.element.val( this._format( prevValue ) );
+ return;
+ }
+
+ if ( key === "max" || key === "min" || key === "step" ) {
+ if ( typeof value === "string" ) {
+ value = this._parse( value );
+ }
+ }
+ if ( key === "icons" ) {
+ this.buttons.first().find( ".ui-icon" )
+ .removeClass( this.options.icons.up )
+ .addClass( value.up );
+ this.buttons.last().find( ".ui-icon" )
+ .removeClass( this.options.icons.down )
+ .addClass( value.down );
+ }
+
+ this._super( key, value );
+
+ if ( key === "disabled" ) {
+ if ( value ) {
+ this.element.prop( "disabled", true );
+ this.buttons.button( "disable" );
+ } else {
+ this.element.prop( "disabled", false );
+ this.buttons.button( "enable" );
+ }
+ }
+ },
+
+ _setOptions: modifier(function( options ) {
+ this._super( options );
+ this._value( this.element.val() );
+ }),
+
+ _parse: function( val ) {
+ if ( typeof val === "string" && val !== "" ) {
+ val = window.Globalize && this.options.numberFormat ?
+ Globalize.parseFloat( val, 10, this.options.culture ) : +val;
+ }
+ return val === "" || isNaN( val ) ? null : val;
+ },
+
+ _format: function( value ) {
+ if ( value === "" ) {
+ return "";
+ }
+ return window.Globalize && this.options.numberFormat ?
+ Globalize.format( value, this.options.numberFormat, this.options.culture ) :
+ value;
+ },
+
+ _refresh: function() {
+ this.element.attr({
+ "aria-valuemin": this.options.min,
+ "aria-valuemax": this.options.max,
+ // TODO: what should we do with values that can't be parsed?
+ "aria-valuenow": this._parse( this.element.val() )
+ });
+ },
+
+ // update the value without triggering change
+ _value: function( value, allowAny ) {
+ var parsed;
+ if ( value !== "" ) {
+ parsed = this._parse( value );
+ if ( parsed !== null ) {
+ if ( !allowAny ) {
+ parsed = this._adjustValue( parsed );
+ }
+ value = this._format( parsed );
+ }
+ }
+ this.element.val( value );
+ this._refresh();
+ },
+
+ _destroy: function() {
+ this.element
+ .removeClass( "ui-spinner-input" )
+ .prop( "disabled", false )
+ .removeAttr( "autocomplete" )
+ .removeAttr( "role" )
+ .removeAttr( "aria-valuemin" )
+ .removeAttr( "aria-valuemax" )
+ .removeAttr( "aria-valuenow" );
+ this.uiSpinner.replaceWith( this.element );
+ },
+
+ stepUp: modifier(function( steps ) {
+ this._stepUp( steps );
+ }),
+ _stepUp: function( steps ) {
+ if ( this._start() ) {
+ this._spin( (steps || 1) * this.options.step );
+ this._stop();
+ }
+ },
+
+ stepDown: modifier(function( steps ) {
+ this._stepDown( steps );
+ }),
+ _stepDown: function( steps ) {
+ if ( this._start() ) {
+ this._spin( (steps || 1) * -this.options.step );
+ this._stop();
+ }
+ },
+
+ pageUp: modifier(function( pages ) {
+ this._stepUp( (pages || 1) * this.options.page );
+ }),
+
+ pageDown: modifier(function( pages ) {
+ this._stepDown( (pages || 1) * this.options.page );
+ }),
+
+ value: function( newVal ) {
+ if ( !arguments.length ) {
+ return this._parse( this.element.val() );
+ }
+ modifier( this._value ).call( this, newVal );
+ },
+
+ widget: function() {
+ return this.uiSpinner;
+ }
+});
+
+}( jQuery ) );
+
+(function( $, undefined ) {
+
+var tabId = 0,
+ rhash = /#.*$/;
+
+function getNextTabId() {
+ return ++tabId;
+}
+
+function isLocal( anchor ) {
+ return anchor.hash.length > 1 &&
+ decodeURIComponent( anchor.href.replace( rhash, "" ) ) ===
+ decodeURIComponent( location.href.replace( rhash, "" ) );
+}
+
+$.widget( "ui.tabs", {
+ version: "1.10.3",
+ delay: 300,
+ options: {
+ active: null,
+ collapsible: false,
+ event: "click",
+ heightStyle: "content",
+ hide: null,
+ show: null,
+
+ // callbacks
+ activate: null,
+ beforeActivate: null,
+ beforeLoad: null,
+ load: null
+ },
+
+ _create: function() {
+ var that = this,
+ options = this.options;
+
+ this.running = false;
+
+ this.element
+ .addClass( "ui-tabs ui-widget ui-widget-content ui-corner-all" )
+ .toggleClass( "ui-tabs-collapsible", options.collapsible )
+ // Prevent users from focusing disabled tabs via click
+ .delegate( ".ui-tabs-nav > li", "mousedown" + this.eventNamespace, function( event ) {
+ if ( $( this ).is( ".ui-state-disabled" ) ) {
+ event.preventDefault();
+ }
+ })
+ // support: IE <9
+ // Preventing the default action in mousedown doesn't prevent IE
+ // from focusing the element, so if the anchor gets focused, blur.
+ // We don't have to worry about focusing the previously focused
+ // element since clicking on a non-focusable element should focus
+ // the body anyway.
+ .delegate( ".ui-tabs-anchor", "focus" + this.eventNamespace, function() {
+ if ( $( this ).closest( "li" ).is( ".ui-state-disabled" ) ) {
+ this.blur();
+ }
+ });
+
+ this._processTabs();
+ options.active = this._initialActive();
+
+ // Take disabling tabs via class attribute from HTML
+ // into account and update option properly.
+ if ( $.isArray( options.disabled ) ) {
+ options.disabled = $.unique( options.disabled.concat(
+ $.map( this.tabs.filter( ".ui-state-disabled" ), function( li ) {
+ return that.tabs.index( li );
+ })
+ ) ).sort();
+ }
+
+ // check for length avoids error when initializing empty list
+ if ( this.options.active !== false && this.anchors.length ) {
+ this.active = this._findActive( options.active );
+ } else {
+ this.active = $();
+ }
+
+ this._refresh();
+
+ if ( this.active.length ) {
+ this.load( options.active );
+ }
+ },
+
+ _initialActive: function() {
+ var active = this.options.active,
+ collapsible = this.options.collapsible,
+ locationHash = location.hash.substring( 1 );
+
+ if ( active === null ) {
+ // check the fragment identifier in the URL
+ if ( locationHash ) {
+ this.tabs.each(function( i, tab ) {
+ if ( $( tab ).attr( "aria-controls" ) === locationHash ) {
+ active = i;
+ return false;
+ }
+ });
+ }
+
+ // check for a tab marked active via a class
+ if ( active === null ) {
+ active = this.tabs.index( this.tabs.filter( ".ui-tabs-active" ) );
+ }
+
+ // no active tab, set to false
+ if ( active === null || active === -1 ) {
+ active = this.tabs.length ? 0 : false;
+ }
+ }
+
+ // handle numbers: negative, out of range
+ if ( active !== false ) {
+ active = this.tabs.index( this.tabs.eq( active ) );
+ if ( active === -1 ) {
+ active = collapsible ? false : 0;
+ }
+ }
+
+ // don't allow collapsible: false and active: false
+ if ( !collapsible && active === false && this.anchors.length ) {
+ active = 0;
+ }
+
+ return active;
+ },
+
+ _getCreateEventData: function() {
+ return {
+ tab: this.active,
+ panel: !this.active.length ? $() : this._getPanelForTab( this.active )
+ };
+ },
+
+ _tabKeydown: function( event ) {
+ /*jshint maxcomplexity:15*/
+ var focusedTab = $( this.document[0].activeElement ).closest( "li" ),
+ selectedIndex = this.tabs.index( focusedTab ),
+ goingForward = true;
+
+ if ( this._handlePageNav( event ) ) {
+ return;
+ }
+
+ switch ( event.keyCode ) {
+ case $.ui.keyCode.RIGHT:
+ case $.ui.keyCode.DOWN:
+ selectedIndex++;
+ break;
+ case $.ui.keyCode.UP:
+ case $.ui.keyCode.LEFT:
+ goingForward = false;
+ selectedIndex--;
+ break;
+ case $.ui.keyCode.END:
+ selectedIndex = this.anchors.length - 1;
+ break;
+ case $.ui.keyCode.HOME:
+ selectedIndex = 0;
+ break;
+ case $.ui.keyCode.SPACE:
+ // Activate only, no collapsing
+ event.preventDefault();
+ clearTimeout( this.activating );
+ this._activate( selectedIndex );
+ return;
+ case $.ui.keyCode.ENTER:
+ // Toggle (cancel delayed activation, allow collapsing)
+ event.preventDefault();
+ clearTimeout( this.activating );
+ // Determine if we should collapse or activate
+ this._activate( selectedIndex === this.options.active ? false : selectedIndex );
+ return;
+ default:
+ return;
+ }
+
+ // Focus the appropriate tab, based on which key was pressed
+ event.preventDefault();
+ clearTimeout( this.activating );
+ selectedIndex = this._focusNextTab( selectedIndex, goingForward );
+
+ // Navigating with control key will prevent automatic activation
+ if ( !event.ctrlKey ) {
+ // Update aria-selected immediately so that AT think the tab is already selected.
+ // Otherwise AT may confuse the user by stating that they need to activate the tab,
+ // but the tab will already be activated by the time the announcement finishes.
+ focusedTab.attr( "aria-selected", "false" );
+ this.tabs.eq( selectedIndex ).attr( "aria-selected", "true" );
+
+ this.activating = this._delay(function() {
+ this.option( "active", selectedIndex );
+ }, this.delay );
+ }
+ },
+
+ _panelKeydown: function( event ) {
+ if ( this._handlePageNav( event ) ) {
+ return;
+ }
+
+ // Ctrl+up moves focus to the current tab
+ if ( event.ctrlKey && event.keyCode === $.ui.keyCode.UP ) {
+ event.preventDefault();
+ this.active.focus();
+ }
+ },
+
+ // Alt+page up/down moves focus to the previous/next tab (and activates)
+ _handlePageNav: function( event ) {
+ if ( event.altKey && event.keyCode === $.ui.keyCode.PAGE_UP ) {
+ this._activate( this._focusNextTab( this.options.active - 1, false ) );
+ return true;
+ }
+ if ( event.altKey && event.keyCode === $.ui.keyCode.PAGE_DOWN ) {
+ this._activate( this._focusNextTab( this.options.active + 1, true ) );
+ return true;
+ }
+ },
+
+ _findNextTab: function( index, goingForward ) {
+ var lastTabIndex = this.tabs.length - 1;
+
+ function constrain() {
+ if ( index > lastTabIndex ) {
+ index = 0;
+ }
+ if ( index < 0 ) {
+ index = lastTabIndex;
+ }
+ return index;
+ }
+
+ while ( $.inArray( constrain(), this.options.disabled ) !== -1 ) {
+ index = goingForward ? index + 1 : index - 1;
+ }
+
+ return index;
+ },
+
+ _focusNextTab: function( index, goingForward ) {
+ index = this._findNextTab( index, goingForward );
+ this.tabs.eq( index ).focus();
+ return index;
+ },
+
+ _setOption: function( key, value ) {
+ if ( key === "active" ) {
+ // _activate() will handle invalid values and update this.options
+ this._activate( value );
+ return;
+ }
+
+ if ( key === "disabled" ) {
+ // don't use the widget factory's disabled handling
+ this._setupDisabled( value );
+ return;
+ }
+
+ this._super( key, value);
+
+ if ( key === "collapsible" ) {
+ this.element.toggleClass( "ui-tabs-collapsible", value );
+ // Setting collapsible: false while collapsed; open first panel
+ if ( !value && this.options.active === false ) {
+ this._activate( 0 );
+ }
+ }
+
+ if ( key === "event" ) {
+ this._setupEvents( value );
+ }
+
+ if ( key === "heightStyle" ) {
+ this._setupHeightStyle( value );
+ }
+ },
+
+ _tabId: function( tab ) {
+ return tab.attr( "aria-controls" ) || "ui-tabs-" + getNextTabId();
+ },
+
+ _sanitizeSelector: function( hash ) {
+ return hash ? hash.replace( /[!"$%&'()*+,.\/:;<=>?@\[\]\^`{|}~]/g, "\\$&" ) : "";
+ },
+
+ refresh: function() {
+ var options = this.options,
+ lis = this.tablist.children( ":has(a[href])" );
+
+ // get disabled tabs from class attribute from HTML
+ // this will get converted to a boolean if needed in _refresh()
+ options.disabled = $.map( lis.filter( ".ui-state-disabled" ), function( tab ) {
+ return lis.index( tab );
+ });
+
+ this._processTabs();
+
+ // was collapsed or no tabs
+ if ( options.active === false || !this.anchors.length ) {
+ options.active = false;
+ this.active = $();
+ // was active, but active tab is gone
+ } else if ( this.active.length && !$.contains( this.tablist[ 0 ], this.active[ 0 ] ) ) {
+ // all remaining tabs are disabled
+ if ( this.tabs.length === options.disabled.length ) {
+ options.active = false;
+ this.active = $();
+ // activate previous tab
+ } else {
+ this._activate( this._findNextTab( Math.max( 0, options.active - 1 ), false ) );
+ }
+ // was active, active tab still exists
+ } else {
+ // make sure active index is correct
+ options.active = this.tabs.index( this.active );
+ }
+
+ this._refresh();
+ },
+
+ _refresh: function() {
+ this._setupDisabled( this.options.disabled );
+ this._setupEvents( this.options.event );
+ this._setupHeightStyle( this.options.heightStyle );
+
+ this.tabs.not( this.active ).attr({
+ "aria-selected": "false",
+ tabIndex: -1
+ });
+ this.panels.not( this._getPanelForTab( this.active ) )
+ .hide()
+ .attr({
+ "aria-expanded": "false",
+ "aria-hidden": "true"
+ });
+
+ // Make sure one tab is in the tab order
+ if ( !this.active.length ) {
+ this.tabs.eq( 0 ).attr( "tabIndex", 0 );
+ } else {
+ this.active
+ .addClass( "ui-tabs-active ui-state-active" )
+ .attr({
+ "aria-selected": "true",
+ tabIndex: 0
+ });
+ this._getPanelForTab( this.active )
+ .show()
+ .attr({
+ "aria-expanded": "true",
+ "aria-hidden": "false"
+ });
+ }
+ },
+
+ _processTabs: function() {
+ var that = this;
+
+ this.tablist = this._getList()
+ .addClass( "ui-tabs-nav ui-helper-reset ui-helper-clearfix ui-widget-header ui-corner-all" )
+ .attr( "role", "tablist" );
+
+ this.tabs = this.tablist.find( "> li:has(a[href])" )
+ .addClass( "ui-state-default ui-corner-top" )
+ .attr({
+ role: "tab",
+ tabIndex: -1
+ });
+
+ this.anchors = this.tabs.map(function() {
+ return $( "a", this )[ 0 ];
+ })
+ .addClass( "ui-tabs-anchor" )
+ .attr({
+ role: "presentation",
+ tabIndex: -1
+ });
+
+ this.panels = $();
+
+ this.anchors.each(function( i, anchor ) {
+ var selector, panel, panelId,
+ anchorId = $( anchor ).uniqueId().attr( "id" ),
+ tab = $( anchor ).closest( "li" ),
+ originalAriaControls = tab.attr( "aria-controls" );
+
+ // inline tab
+ if ( isLocal( anchor ) ) {
+ selector = anchor.hash;
+ panel = that.element.find( that._sanitizeSelector( selector ) );
+ // remote tab
+ } else {
+ panelId = that._tabId( tab );
+ selector = "#" + panelId;
+ panel = that.element.find( selector );
+ if ( !panel.length ) {
+ panel = that._createPanel( panelId );
+ panel.insertAfter( that.panels[ i - 1 ] || that.tablist );
+ }
+ panel.attr( "aria-live", "polite" );
+ }
+
+ if ( panel.length) {
+ that.panels = that.panels.add( panel );
+ }
+ if ( originalAriaControls ) {
+ tab.data( "ui-tabs-aria-controls", originalAriaControls );
+ }
+ tab.attr({
+ "aria-controls": selector.substring( 1 ),
+ "aria-labelledby": anchorId
+ });
+ panel.attr( "aria-labelledby", anchorId );
+ });
+
+ this.panels
+ .addClass( "ui-tabs-panel ui-widget-content ui-corner-bottom" )
+ .attr( "role", "tabpanel" );
+ },
+
+ // allow overriding how to find the list for rare usage scenarios (#7715)
+ _getList: function() {
+ return this.element.find( "ol,ul" ).eq( 0 );
+ },
+
+ _createPanel: function( id ) {
+ return $( "<div>" )
+ .attr( "id", id )
+ .addClass( "ui-tabs-panel ui-widget-content ui-corner-bottom" )
+ .data( "ui-tabs-destroy", true );
+ },
+
+ _setupDisabled: function( disabled ) {
+ if ( $.isArray( disabled ) ) {
+ if ( !disabled.length ) {
+ disabled = false;
+ } else if ( disabled.length === this.anchors.length ) {
+ disabled = true;
+ }
+ }
+
+ // disable tabs
+ for ( var i = 0, li; ( li = this.tabs[ i ] ); i++ ) {
+ if ( disabled === true || $.inArray( i, disabled ) !== -1 ) {
+ $( li )
+ .addClass( "ui-state-disabled" )
+ .attr( "aria-disabled", "true" );
+ } else {
+ $( li )
+ .removeClass( "ui-state-disabled" )
+ .removeAttr( "aria-disabled" );
+ }
+ }
+
+ this.options.disabled = disabled;
+ },
+
+ _setupEvents: function( event ) {
+ var events = {
+ click: function( event ) {
+ event.preventDefault();
+ }
+ };
+ if ( event ) {
+ $.each( event.split(" "), function( index, eventName ) {
+ events[ eventName ] = "_eventHandler";
+ });
+ }
+
+ this._off( this.anchors.add( this.tabs ).add( this.panels ) );
+ this._on( this.anchors, events );
+ this._on( this.tabs, { keydown: "_tabKeydown" } );
+ this._on( this.panels, { keydown: "_panelKeydown" } );
+
+ this._focusable( this.tabs );
+ this._hoverable( this.tabs );
+ },
+
+ _setupHeightStyle: function( heightStyle ) {
+ var maxHeight,
+ parent = this.element.parent();
+
+ if ( heightStyle === "fill" ) {
+ maxHeight = parent.height();
+ maxHeight -= this.element.outerHeight() - this.element.height();
+
+ this.element.siblings( ":visible" ).each(function() {
+ var elem = $( this ),
+ position = elem.css( "position" );
+
+ if ( position === "absolute" || position === "fixed" ) {
+ return;
+ }
+ maxHeight -= elem.outerHeight( true );
+ });
+
+ this.element.children().not( this.panels ).each(function() {
+ maxHeight -= $( this ).outerHeight( true );
+ });
+
+ this.panels.each(function() {
+ $( this ).height( Math.max( 0, maxHeight -
+ $( this ).innerHeight() + $( this ).height() ) );
+ })
+ .css( "overflow", "auto" );
+ } else if ( heightStyle === "auto" ) {
+ maxHeight = 0;
+ this.panels.each(function() {
+ maxHeight = Math.max( maxHeight, $( this ).height( "" ).height() );
+ }).height( maxHeight );
+ }
+ },
+
+ _eventHandler: function( event ) {
+ var options = this.options,
+ active = this.active,
+ anchor = $( event.currentTarget ),
+ tab = anchor.closest( "li" ),
+ clickedIsActive = tab[ 0 ] === active[ 0 ],
+ collapsing = clickedIsActive && options.collapsible,
+ toShow = collapsing ? $() : this._getPanelForTab( tab ),
+ toHide = !active.length ? $() : this._getPanelForTab( active ),
+ eventData = {
+ oldTab: active,
+ oldPanel: toHide,
+ newTab: collapsing ? $() : tab,
+ newPanel: toShow
+ };
+
+ event.preventDefault();
+
+ if ( tab.hasClass( "ui-state-disabled" ) ||
+ // tab is already loading
+ tab.hasClass( "ui-tabs-loading" ) ||
+ // can't switch durning an animation
+ this.running ||
+ // click on active header, but not collapsible
+ ( clickedIsActive && !options.collapsible ) ||
+ // allow canceling activation
+ ( this._trigger( "beforeActivate", event, eventData ) === false ) ) {
+ return;
+ }
+
+ options.active = collapsing ? false : this.tabs.index( tab );
+
+ this.active = clickedIsActive ? $() : tab;
+ if ( this.xhr ) {
+ this.xhr.abort();
+ }
+
+ if ( !toHide.length && !toShow.length ) {
+ $.error( "jQuery UI Tabs: Mismatching fragment identifier." );
+ }
+
+ if ( toShow.length ) {
+ this.load( this.tabs.index( tab ), event );
+ }
+ this._toggle( event, eventData );
+ },
+
+ // handles show/hide for selecting tabs
+ _toggle: function( event, eventData ) {
+ var that = this,
+ toShow = eventData.newPanel,
+ toHide = eventData.oldPanel;
+
+ this.running = true;
+
+ function complete() {
+ that.running = false;
+ that._trigger( "activate", event, eventData );
+ }
+
+ function show() {
+ eventData.newTab.closest( "li" ).addClass( "ui-tabs-active ui-state-active" );
+
+ if ( toShow.length && that.options.show ) {
+ that._show( toShow, that.options.show, complete );
+ } else {
+ toShow.show();
+ complete();
+ }
+ }
+
+ // start out by hiding, then showing, then completing
+ if ( toHide.length && this.options.hide ) {
+ this._hide( toHide, this.options.hide, function() {
+ eventData.oldTab.closest( "li" ).removeClass( "ui-tabs-active ui-state-active" );
+ show();
+ });
+ } else {
+ eventData.oldTab.closest( "li" ).removeClass( "ui-tabs-active ui-state-active" );
+ toHide.hide();
+ show();
+ }
+
+ toHide.attr({
+ "aria-expanded": "false",
+ "aria-hidden": "true"
+ });
+ eventData.oldTab.attr( "aria-selected", "false" );
+ // If we're switching tabs, remove the old tab from the tab order.
+ // If we're opening from collapsed state, remove the previous tab from the tab order.
+ // If we're collapsing, then keep the collapsing tab in the tab order.
+ if ( toShow.length && toHide.length ) {
+ eventData.oldTab.attr( "tabIndex", -1 );
+ } else if ( toShow.length ) {
+ this.tabs.filter(function() {
+ return $( this ).attr( "tabIndex" ) === 0;
+ })
+ .attr( "tabIndex", -1 );
+ }
+
+ toShow.attr({
+ "aria-expanded": "true",
+ "aria-hidden": "false"
+ });
+ eventData.newTab.attr({
+ "aria-selected": "true",
+ tabIndex: 0
+ });
+ },
+
+ _activate: function( index ) {
+ var anchor,
+ active = this._findActive( index );
+
+ // trying to activate the already active panel
+ if ( active[ 0 ] === this.active[ 0 ] ) {
+ return;
+ }
+
+ // trying to collapse, simulate a click on the current active header
+ if ( !active.length ) {
+ active = this.active;
+ }
+
+ anchor = active.find( ".ui-tabs-anchor" )[ 0 ];
+ this._eventHandler({
+ target: anchor,
+ currentTarget: anchor,
+ preventDefault: $.noop
+ });
+ },
+
+ _findActive: function( index ) {
+ return index === false ? $() : this.tabs.eq( index );
+ },
+
+ _getIndex: function( index ) {
+ // meta-function to give users option to provide a href string instead of a numerical index.
+ if ( typeof index === "string" ) {
+ index = this.anchors.index( this.anchors.filter( "[href$='" + index + "']" ) );
+ }
+
+ return index;
+ },
+
+ _destroy: function() {
+ if ( this.xhr ) {
+ this.xhr.abort();
+ }
+
+ this.element.removeClass( "ui-tabs ui-widget ui-widget-content ui-corner-all ui-tabs-collapsible" );
+
+ this.tablist
+ .removeClass( "ui-tabs-nav ui-helper-reset ui-helper-clearfix ui-widget-header ui-corner-all" )
+ .removeAttr( "role" );
+
+ this.anchors
+ .removeClass( "ui-tabs-anchor" )
+ .removeAttr( "role" )
+ .removeAttr( "tabIndex" )
+ .removeUniqueId();
+
+ this.tabs.add( this.panels ).each(function() {
+ if ( $.data( this, "ui-tabs-destroy" ) ) {
+ $( this ).remove();
+ } else {
+ $( this )
+ .removeClass( "ui-state-default ui-state-active ui-state-disabled " +
+ "ui-corner-top ui-corner-bottom ui-widget-content ui-tabs-active ui-tabs-panel" )
+ .removeAttr( "tabIndex" )
+ .removeAttr( "aria-live" )
+ .removeAttr( "aria-busy" )
+ .removeAttr( "aria-selected" )
+ .removeAttr( "aria-labelledby" )
+ .removeAttr( "aria-hidden" )
+ .removeAttr( "aria-expanded" )
+ .removeAttr( "role" );
+ }
+ });
+
+ this.tabs.each(function() {
+ var li = $( this ),
+ prev = li.data( "ui-tabs-aria-controls" );
+ if ( prev ) {
+ li
+ .attr( "aria-controls", prev )
+ .removeData( "ui-tabs-aria-controls" );
+ } else {
+ li.removeAttr( "aria-controls" );
+ }
+ });
+
+ this.panels.show();
+
+ if ( this.options.heightStyle !== "content" ) {
+ this.panels.css( "height", "" );
+ }
+ },
+
+ enable: function( index ) {
+ var disabled = this.options.disabled;
+ if ( disabled === false ) {
+ return;
+ }
+
+ if ( index === undefined ) {
+ disabled = false;
+ } else {
+ index = this._getIndex( index );
+ if ( $.isArray( disabled ) ) {
+ disabled = $.map( disabled, function( num ) {
+ return num !== index ? num : null;
+ });
+ } else {
+ disabled = $.map( this.tabs, function( li, num ) {
+ return num !== index ? num : null;
+ });
+ }
+ }
+ this._setupDisabled( disabled );
+ },
+
+ disable: function( index ) {
+ var disabled = this.options.disabled;
+ if ( disabled === true ) {
+ return;
+ }
+
+ if ( index === undefined ) {
+ disabled = true;
+ } else {
+ index = this._getIndex( index );
+ if ( $.inArray( index, disabled ) !== -1 ) {
+ return;
+ }
+ if ( $.isArray( disabled ) ) {
+ disabled = $.merge( [ index ], disabled ).sort();
+ } else {
+ disabled = [ index ];
+ }
+ }
+ this._setupDisabled( disabled );
+ },
+
+ load: function( index, event ) {
+ index = this._getIndex( index );
+ var that = this,
+ tab = this.tabs.eq( index ),
+ anchor = tab.find( ".ui-tabs-anchor" ),
+ panel = this._getPanelForTab( tab ),
+ eventData = {
+ tab: tab,
+ panel: panel
+ };
+
+ // not remote
+ if ( isLocal( anchor[ 0 ] ) ) {
+ return;
+ }
+
+ this.xhr = $.ajax( this._ajaxSettings( anchor, event, eventData ) );
+
+ // support: jQuery <1.8
+ // jQuery <1.8 returns false if the request is canceled in beforeSend,
+ // but as of 1.8, $.ajax() always returns a jqXHR object.
+ if ( this.xhr && this.xhr.statusText !== "canceled" ) {
+ tab.addClass( "ui-tabs-loading" );
+ panel.attr( "aria-busy", "true" );
+
+ this.xhr
+ .success(function( response ) {
+ // support: jQuery <1.8
+ // http://bugs.jquery.com/ticket/11778
+ setTimeout(function() {
+ panel.html( response );
+ that._trigger( "load", event, eventData );
+ }, 1 );
+ })
+ .complete(function( jqXHR, status ) {
+ // support: jQuery <1.8
+ // http://bugs.jquery.com/ticket/11778
+ setTimeout(function() {
+ if ( status === "abort" ) {
+ that.panels.stop( false, true );
+ }
+
+ tab.removeClass( "ui-tabs-loading" );
+ panel.removeAttr( "aria-busy" );
+
+ if ( jqXHR === that.xhr ) {
+ delete that.xhr;
+ }
+ }, 1 );
+ });
+ }
+ },
+
+ _ajaxSettings: function( anchor, event, eventData ) {
+ var that = this;
+ return {
+ url: anchor.attr( "href" ),
+ beforeSend: function( jqXHR, settings ) {
+ return that._trigger( "beforeLoad", event,
+ $.extend( { jqXHR : jqXHR, ajaxSettings: settings }, eventData ) );
+ }
+ };
+ },
+
+ _getPanelForTab: function( tab ) {
+ var id = $( tab ).attr( "aria-controls" );
+ return this.element.find( this._sanitizeSelector( "#" + id ) );
+ }
+});
+
+})( jQuery );
+
+(function( $ ) {
+
+var increments = 0;
+
+function addDescribedBy( elem, id ) {
+ var describedby = (elem.attr( "aria-describedby" ) || "").split( /\s+/ );
+ describedby.push( id );
+ elem
+ .data( "ui-tooltip-id", id )
+ .attr( "aria-describedby", $.trim( describedby.join( " " ) ) );
+}
+
+function removeDescribedBy( elem ) {
+ var id = elem.data( "ui-tooltip-id" ),
+ describedby = (elem.attr( "aria-describedby" ) || "").split( /\s+/ ),
+ index = $.inArray( id, describedby );
+ if ( index !== -1 ) {
+ describedby.splice( index, 1 );
+ }
+
+ elem.removeData( "ui-tooltip-id" );
+ describedby = $.trim( describedby.join( " " ) );
+ if ( describedby ) {
+ elem.attr( "aria-describedby", describedby );
+ } else {
+ elem.removeAttr( "aria-describedby" );
+ }
+}
+
+$.widget( "ui.tooltip", {
+ version: "1.10.3",
+ options: {
+ content: function() {
+ // support: IE<9, Opera in jQuery <1.7
+ // .text() can't accept undefined, so coerce to a string
+ var title = $( this ).attr( "title" ) || "";
+ // Escape title, since we're going from an attribute to raw HTML
+ return $( "<a>" ).text( title ).html();
+ },
+ hide: true,
+ // Disabled elements have inconsistent behavior across browsers (#8661)
+ items: "[title]:not([disabled])",
+ position: {
+ my: "left top+15",
+ at: "left bottom",
+ collision: "flipfit flip"
+ },
+ show: true,
+ tooltipClass: null,
+ track: false,
+
+ // callbacks
+ close: null,
+ open: null
+ },
+
+ _create: function() {
+ this._on({
+ mouseover: "open",
+ focusin: "open"
+ });
+
+ // IDs of generated tooltips, needed for destroy
+ this.tooltips = {};
+ // IDs of parent tooltips where we removed the title attribute
+ this.parents = {};
+
+ if ( this.options.disabled ) {
+ this._disable();
+ }
+ },
+
+ _setOption: function( key, value ) {
+ var that = this;
+
+ if ( key === "disabled" ) {
+ this[ value ? "_disable" : "_enable" ]();
+ this.options[ key ] = value;
+ // disable element style changes
+ return;
+ }
+
+ this._super( key, value );
+
+ if ( key === "content" ) {
+ $.each( this.tooltips, function( id, element ) {
+ that._updateContent( element );
+ });
+ }
+ },
+
+ _disable: function() {
+ var that = this;
+
+ // close open tooltips
+ $.each( this.tooltips, function( id, element ) {
+ var event = $.Event( "blur" );
+ event.target = event.currentTarget = element[0];
+ that.close( event, true );
+ });
+
+ // remove title attributes to prevent native tooltips
+ this.element.find( this.options.items ).addBack().each(function() {
+ var element = $( this );
+ if ( element.is( "[title]" ) ) {
+ element
+ .data( "ui-tooltip-title", element.attr( "title" ) )
+ .attr( "title", "" );
+ }
+ });
+ },
+
+ _enable: function() {
+ // restore title attributes
+ this.element.find( this.options.items ).addBack().each(function() {
+ var element = $( this );
+ if ( element.data( "ui-tooltip-title" ) ) {
+ element.attr( "title", element.data( "ui-tooltip-title" ) );
+ }
+ });
+ },
+
+ open: function( event ) {
+ var that = this,
+ target = $( event ? event.target : this.element )
+ // we need closest here due to mouseover bubbling,
+ // but always pointing at the same event target
+ .closest( this.options.items );
+
+ // No element to show a tooltip for or the tooltip is already open
+ if ( !target.length || target.data( "ui-tooltip-id" ) ) {
+ return;
+ }
+
+ if ( target.attr( "title" ) ) {
+ target.data( "ui-tooltip-title", target.attr( "title" ) );
+ }
+
+ target.data( "ui-tooltip-open", true );
+
+ // kill parent tooltips, custom or native, for hover
+ if ( event && event.type === "mouseover" ) {
+ target.parents().each(function() {
+ var parent = $( this ),
+ blurEvent;
+ if ( parent.data( "ui-tooltip-open" ) ) {
+ blurEvent = $.Event( "blur" );
+ blurEvent.target = blurEvent.currentTarget = this;
+ that.close( blurEvent, true );
+ }
+ if ( parent.attr( "title" ) ) {
+ parent.uniqueId();
+ that.parents[ this.id ] = {
+ element: this,
+ title: parent.attr( "title" )
+ };
+ parent.attr( "title", "" );
+ }
+ });
+ }
+
+ this._updateContent( target, event );
+ },
+
+ _updateContent: function( target, event ) {
+ var content,
+ contentOption = this.options.content,
+ that = this,
+ eventType = event ? event.type : null;
+
+ if ( typeof contentOption === "string" ) {
+ return this._open( event, target, contentOption );
+ }
+
+ content = contentOption.call( target[0], function( response ) {
+ // ignore async response if tooltip was closed already
+ if ( !target.data( "ui-tooltip-open" ) ) {
+ return;
+ }
+ // IE may instantly serve a cached response for ajax requests
+ // delay this call to _open so the other call to _open runs first
+ that._delay(function() {
+ // jQuery creates a special event for focusin when it doesn't
+ // exist natively. To improve performance, the native event
+ // object is reused and the type is changed. Therefore, we can't
+ // rely on the type being correct after the event finished
+ // bubbling, so we set it back to the previous value. (#8740)
+ if ( event ) {
+ event.type = eventType;
+ }
+ this._open( event, target, response );
+ });
+ });
+ if ( content ) {
+ this._open( event, target, content );
+ }
+ },
+
+ _open: function( event, target, content ) {
+ var tooltip, events, delayedShow,
+ positionOption = $.extend( {}, this.options.position );
+
+ if ( !content ) {
+ return;
+ }
+
+ // Content can be updated multiple times. If the tooltip already
+ // exists, then just update the content and bail.
+ tooltip = this._find( target );
+ if ( tooltip.length ) {
+ tooltip.find( ".ui-tooltip-content" ).html( content );
+ return;
+ }
+
+ // if we have a title, clear it to prevent the native tooltip
+ // we have to check first to avoid defining a title if none exists
+ // (we don't want to cause an element to start matching [title])
+ //
+ // We use removeAttr only for key events, to allow IE to export the correct
+ // accessible attributes. For mouse events, set to empty string to avoid
+ // native tooltip showing up (happens only when removing inside mouseover).
+ if ( target.is( "[title]" ) ) {
+ if ( event && event.type === "mouseover" ) {
+ target.attr( "title", "" );
+ } else {
+ target.removeAttr( "title" );
+ }
+ }
+
+ tooltip = this._tooltip( target );
+ addDescribedBy( target, tooltip.attr( "id" ) );
+ tooltip.find( ".ui-tooltip-content" ).html( content );
+
+ function position( event ) {
+ positionOption.of = event;
+ if ( tooltip.is( ":hidden" ) ) {
+ return;
+ }
+ tooltip.position( positionOption );
+ }
+ if ( this.options.track && event && /^mouse/.test( event.type ) ) {
+ this._on( this.document, {
+ mousemove: position
+ });
+ // trigger once to override element-relative positioning
+ position( event );
+ } else {
+ tooltip.position( $.extend({
+ of: target
+ }, this.options.position ) );
+ }
+
+ tooltip.hide();
+
+ this._show( tooltip, this.options.show );
+ // Handle tracking tooltips that are shown with a delay (#8644). As soon
+ // as the tooltip is visible, position the tooltip using the most recent
+ // event.
+ if ( this.options.show && this.options.show.delay ) {
+ delayedShow = this.delayedShow = setInterval(function() {
+ if ( tooltip.is( ":visible" ) ) {
+ position( positionOption.of );
+ clearInterval( delayedShow );
+ }
+ }, $.fx.interval );
+ }
+
+ this._trigger( "open", event, { tooltip: tooltip } );
+
+ events = {
+ keyup: function( event ) {
+ if ( event.keyCode === $.ui.keyCode.ESCAPE ) {
+ var fakeEvent = $.Event(event);
+ fakeEvent.currentTarget = target[0];
+ this.close( fakeEvent, true );
+ }
+ },
+ remove: function() {
+ this._removeTooltip( tooltip );
+ }
+ };
+ if ( !event || event.type === "mouseover" ) {
+ events.mouseleave = "close";
+ }
+ if ( !event || event.type === "focusin" ) {
+ events.focusout = "close";
+ }
+ this._on( true, target, events );
+ },
+
+ close: function( event ) {
+ var that = this,
+ target = $( event ? event.currentTarget : this.element ),
+ tooltip = this._find( target );
+
+ // disabling closes the tooltip, so we need to track when we're closing
+ // to avoid an infinite loop in case the tooltip becomes disabled on close
+ if ( this.closing ) {
+ return;
+ }
+
+ // Clear the interval for delayed tracking tooltips
+ clearInterval( this.delayedShow );
+
+ // only set title if we had one before (see comment in _open())
+ if ( target.data( "ui-tooltip-title" ) ) {
+ target.attr( "title", target.data( "ui-tooltip-title" ) );
+ }
+
+ removeDescribedBy( target );
+
+ tooltip.stop( true );
+ this._hide( tooltip, this.options.hide, function() {
+ that._removeTooltip( $( this ) );
+ });
+
+ target.removeData( "ui-tooltip-open" );
+ this._off( target, "mouseleave focusout keyup" );
+ // Remove 'remove' binding only on delegated targets
+ if ( target[0] !== this.element[0] ) {
+ this._off( target, "remove" );
+ }
+ this._off( this.document, "mousemove" );
+
+ if ( event && event.type === "mouseleave" ) {
+ $.each( this.parents, function( id, parent ) {
+ $( parent.element ).attr( "title", parent.title );
+ delete that.parents[ id ];
+ });
+ }
+
+ this.closing = true;
+ this._trigger( "close", event, { tooltip: tooltip } );
+ this.closing = false;
+ },
+
+ _tooltip: function( element ) {
+ var id = "ui-tooltip-" + increments++,
+ tooltip = $( "<div>" )
+ .attr({
+ id: id,
+ role: "tooltip"
+ })
+ .addClass( "ui-tooltip ui-widget ui-corner-all ui-widget-content " +
+ ( this.options.tooltipClass || "" ) );
+ $( "<div>" )
+ .addClass( "ui-tooltip-content" )
+ .appendTo( tooltip );
+ tooltip.appendTo( this.document[0].body );
+ this.tooltips[ id ] = element;
+ return tooltip;
+ },
+
+ _find: function( target ) {
+ var id = target.data( "ui-tooltip-id" );
+ return id ? $( "#" + id ) : $();
+ },
+
+ _removeTooltip: function( tooltip ) {
+ tooltip.remove();
+ delete this.tooltips[ tooltip.attr( "id" ) ];
+ },
+
+ _destroy: function() {
+ var that = this;
+
+ // close open tooltips
+ $.each( this.tooltips, function( id, element ) {
+ // Delegate to close method to handle common cleanup
+ var event = $.Event( "blur" );
+ event.target = event.currentTarget = element[0];
+ that.close( event, true );
+
+ // Remove immediately; destroying an open tooltip doesn't use the
+ // hide animation
+ $( "#" + id ).remove();
+
+ // Restore the title
+ if ( element.data( "ui-tooltip-title" ) ) {
+ element.attr( "title", element.data( "ui-tooltip-title" ) );
+ element.removeData( "ui-tooltip-title" );
+ }
+ });
+ }
+});
+
+}( jQuery ) );
diff --git a/debian/missing-sources/jquery-ui/jquery.ui.accordion.js b/debian/missing-sources/jquery-ui/jquery.ui.accordion.js
new file mode 100644
index 0000000..bdd2d53
--- /dev/null
+++ b/debian/missing-sources/jquery-ui/jquery.ui.accordion.js
@@ -0,0 +1,572 @@
+/*!
+ * jQuery UI Accordion 1.10.3
+ * http://jqueryui.com
+ *
+ * Copyright 2013 jQuery Foundation and other contributors
+ * Released under the MIT license.
+ * http://jquery.org/license
+ *
+ * http://api.jqueryui.com/accordion/
+ *
+ * Depends:
+ * jquery.ui.core.js
+ * jquery.ui.widget.js
+ */
+(function( $, undefined ) {
+
+var uid = 0,
+ hideProps = {},
+ showProps = {};
+
+hideProps.height = hideProps.paddingTop = hideProps.paddingBottom =
+ hideProps.borderTopWidth = hideProps.borderBottomWidth = "hide";
+showProps.height = showProps.paddingTop = showProps.paddingBottom =
+ showProps.borderTopWidth = showProps.borderBottomWidth = "show";
+
+$.widget( "ui.accordion", {
+ version: "1.10.3",
+ options: {
+ active: 0,
+ animate: {},
+ collapsible: false,
+ event: "click",
+ header: "> li > :first-child,> :not(li):even",
+ heightStyle: "auto",
+ icons: {
+ activeHeader: "ui-icon-triangle-1-s",
+ header: "ui-icon-triangle-1-e"
+ },
+
+ // callbacks
+ activate: null,
+ beforeActivate: null
+ },
+
+ _create: function() {
+ var options = this.options;
+ this.prevShow = this.prevHide = $();
+ this.element.addClass( "ui-accordion ui-widget ui-helper-reset" )
+ // ARIA
+ .attr( "role", "tablist" );
+
+ // don't allow collapsible: false and active: false / null
+ if ( !options.collapsible && (options.active === false || options.active == null) ) {
+ options.active = 0;
+ }
+
+ this._processPanels();
+ // handle negative values
+ if ( options.active < 0 ) {
+ options.active += this.headers.length;
+ }
+ this._refresh();
+ },
+
+ _getCreateEventData: function() {
+ return {
+ header: this.active,
+ panel: !this.active.length ? $() : this.active.next(),
+ content: !this.active.length ? $() : this.active.next()
+ };
+ },
+
+ _createIcons: function() {
+ var icons = this.options.icons;
+ if ( icons ) {
+ $( "<span>" )
+ .addClass( "ui-accordion-header-icon ui-icon " + icons.header )
+ .prependTo( this.headers );
+ this.active.children( ".ui-accordion-header-icon" )
+ .removeClass( icons.header )
+ .addClass( icons.activeHeader );
+ this.headers.addClass( "ui-accordion-icons" );
+ }
+ },
+
+ _destroyIcons: function() {
+ this.headers
+ .removeClass( "ui-accordion-icons" )
+ .children( ".ui-accordion-header-icon" )
+ .remove();
+ },
+
+ _destroy: function() {
+ var contents;
+
+ // clean up main element
+ this.element
+ .removeClass( "ui-accordion ui-widget ui-helper-reset" )
+ .removeAttr( "role" );
+
+ // clean up headers
+ this.headers
+ .removeClass( "ui-accordion-header ui-accordion-header-active ui-helper-reset ui-state-default ui-corner-all ui-state-active ui-state-disabled ui-corner-top" )
+ .removeAttr( "role" )
+ .removeAttr( "aria-selected" )
+ .removeAttr( "aria-controls" )
+ .removeAttr( "tabIndex" )
+ .each(function() {
+ if ( /^ui-accordion/.test( this.id ) ) {
+ this.removeAttribute( "id" );
+ }
+ });
+ this._destroyIcons();
+
+ // clean up content panels
+ contents = this.headers.next()
+ .css( "display", "" )
+ .removeAttr( "role" )
+ .removeAttr( "aria-expanded" )
+ .removeAttr( "aria-hidden" )
+ .removeAttr( "aria-labelledby" )
+ .removeClass( "ui-helper-reset ui-widget-content ui-corner-bottom ui-accordion-content ui-accordion-content-active ui-state-disabled" )
+ .each(function() {
+ if ( /^ui-accordion/.test( this.id ) ) {
+ this.removeAttribute( "id" );
+ }
+ });
+ if ( this.options.heightStyle !== "content" ) {
+ contents.css( "height", "" );
+ }
+ },
+
+ _setOption: function( key, value ) {
+ if ( key === "active" ) {
+ // _activate() will handle invalid values and update this.options
+ this._activate( value );
+ return;
+ }
+
+ if ( key === "event" ) {
+ if ( this.options.event ) {
+ this._off( this.headers, this.options.event );
+ }
+ this._setupEvents( value );
+ }
+
+ this._super( key, value );
+
+ // setting collapsible: false while collapsed; open first panel
+ if ( key === "collapsible" && !value && this.options.active === false ) {
+ this._activate( 0 );
+ }
+
+ if ( key === "icons" ) {
+ this._destroyIcons();
+ if ( value ) {
+ this._createIcons();
+ }
+ }
+
+ // #5332 - opacity doesn't cascade to positioned elements in IE
+ // so we need to add the disabled class to the headers and panels
+ if ( key === "disabled" ) {
+ this.headers.add( this.headers.next() )
+ .toggleClass( "ui-state-disabled", !!value );
+ }
+ },
+
+ _keydown: function( event ) {
+ /*jshint maxcomplexity:15*/
+ if ( event.altKey || event.ctrlKey ) {
+ return;
+ }
+
+ var keyCode = $.ui.keyCode,
+ length = this.headers.length,
+ currentIndex = this.headers.index( event.target ),
+ toFocus = false;
+
+ switch ( event.keyCode ) {
+ case keyCode.RIGHT:
+ case keyCode.DOWN:
+ toFocus = this.headers[ ( currentIndex + 1 ) % length ];
+ break;
+ case keyCode.LEFT:
+ case keyCode.UP:
+ toFocus = this.headers[ ( currentIndex - 1 + length ) % length ];
+ break;
+ case keyCode.SPACE:
+ case keyCode.ENTER:
+ this._eventHandler( event );
+ break;
+ case keyCode.HOME:
+ toFocus = this.headers[ 0 ];
+ break;
+ case keyCode.END:
+ toFocus = this.headers[ length - 1 ];
+ break;
+ }
+
+ if ( toFocus ) {
+ $( event.target ).attr( "tabIndex", -1 );
+ $( toFocus ).attr( "tabIndex", 0 );
+ toFocus.focus();
+ event.preventDefault();
+ }
+ },
+
+ _panelKeyDown : function( event ) {
+ if ( event.keyCode === $.ui.keyCode.UP && event.ctrlKey ) {
+ $( event.currentTarget ).prev().focus();
+ }
+ },
+
+ refresh: function() {
+ var options = this.options;
+ this._processPanels();
+
+ // was collapsed or no panel
+ if ( ( options.active === false && options.collapsible === true ) || !this.headers.length ) {
+ options.active = false;
+ this.active = $();
+ // active false only when collapsible is true
+ } else if ( options.active === false ) {
+ this._activate( 0 );
+ // was active, but active panel is gone
+ } else if ( this.active.length && !$.contains( this.element[ 0 ], this.active[ 0 ] ) ) {
+ // all remaining panel are disabled
+ if ( this.headers.length === this.headers.find(".ui-state-disabled").length ) {
+ options.active = false;
+ this.active = $();
+ // activate previous panel
+ } else {
+ this._activate( Math.max( 0, options.active - 1 ) );
+ }
+ // was active, active panel still exists
+ } else {
+ // make sure active index is correct
+ options.active = this.headers.index( this.active );
+ }
+
+ this._destroyIcons();
+
+ this._refresh();
+ },
+
+ _processPanels: function() {
+ this.headers = this.element.find( this.options.header )
+ .addClass( "ui-accordion-header ui-helper-reset ui-state-default ui-corner-all" );
+
+ this.headers.next()
+ .addClass( "ui-accordion-content ui-helper-reset ui-widget-content ui-corner-bottom" )
+ .filter(":not(.ui-accordion-content-active)")
+ .hide();
+ },
+
+ _refresh: function() {
+ var maxHeight,
+ options = this.options,
+ heightStyle = options.heightStyle,
+ parent = this.element.parent(),
+ accordionId = this.accordionId = "ui-accordion-" +
+ (this.element.attr( "id" ) || ++uid);
+
+ this.active = this._findActive( options.active )
+ .addClass( "ui-accordion-header-active ui-state-active ui-corner-top" )
+ .removeClass( "ui-corner-all" );
+ this.active.next()
+ .addClass( "ui-accordion-content-active" )
+ .show();
+
+ this.headers
+ .attr( "role", "tab" )
+ .each(function( i ) {
+ var header = $( this ),
+ headerId = header.attr( "id" ),
+ panel = header.next(),
+ panelId = panel.attr( "id" );
+ if ( !headerId ) {
+ headerId = accordionId + "-header-" + i;
+ header.attr( "id", headerId );
+ }
+ if ( !panelId ) {
+ panelId = accordionId + "-panel-" + i;
+ panel.attr( "id", panelId );
+ }
+ header.attr( "aria-controls", panelId );
+ panel.attr( "aria-labelledby", headerId );
+ })
+ .next()
+ .attr( "role", "tabpanel" );
+
+ this.headers
+ .not( this.active )
+ .attr({
+ "aria-selected": "false",
+ tabIndex: -1
+ })
+ .next()
+ .attr({
+ "aria-expanded": "false",
+ "aria-hidden": "true"
+ })
+ .hide();
+
+ // make sure at least one header is in the tab order
+ if ( !this.active.length ) {
+ this.headers.eq( 0 ).attr( "tabIndex", 0 );
+ } else {
+ this.active.attr({
+ "aria-selected": "true",
+ tabIndex: 0
+ })
+ .next()
+ .attr({
+ "aria-expanded": "true",
+ "aria-hidden": "false"
+ });
+ }
+
+ this._createIcons();
+
+ this._setupEvents( options.event );
+
+ if ( heightStyle === "fill" ) {
+ maxHeight = parent.height();
+ this.element.siblings( ":visible" ).each(function() {
+ var elem = $( this ),
+ position = elem.css( "position" );
+
+ if ( position === "absolute" || position === "fixed" ) {
+ return;
+ }
+ maxHeight -= elem.outerHeight( true );
+ });
+
+ this.headers.each(function() {
+ maxHeight -= $( this ).outerHeight( true );
+ });
+
+ this.headers.next()
+ .each(function() {
+ $( this ).height( Math.max( 0, maxHeight -
+ $( this ).innerHeight() + $( this ).height() ) );
+ })
+ .css( "overflow", "auto" );
+ } else if ( heightStyle === "auto" ) {
+ maxHeight = 0;
+ this.headers.next()
+ .each(function() {
+ maxHeight = Math.max( maxHeight, $( this ).css( "height", "" ).height() );
+ })
+ .height( maxHeight );
+ }
+ },
+
+ _activate: function( index ) {
+ var active = this._findActive( index )[ 0 ];
+
+ // trying to activate the already active panel
+ if ( active === this.active[ 0 ] ) {
+ return;
+ }
+
+ // trying to collapse, simulate a click on the currently active header
+ active = active || this.active[ 0 ];
+
+ this._eventHandler({
+ target: active,
+ currentTarget: active,
+ preventDefault: $.noop
+ });
+ },
+
+ _findActive: function( selector ) {
+ return typeof selector === "number" ? this.headers.eq( selector ) : $();
+ },
+
+ _setupEvents: function( event ) {
+ var events = {
+ keydown: "_keydown"
+ };
+ if ( event ) {
+ $.each( event.split(" "), function( index, eventName ) {
+ events[ eventName ] = "_eventHandler";
+ });
+ }
+
+ this._off( this.headers.add( this.headers.next() ) );
+ this._on( this.headers, events );
+ this._on( this.headers.next(), { keydown: "_panelKeyDown" });
+ this._hoverable( this.headers );
+ this._focusable( this.headers );
+ },
+
+ _eventHandler: function( event ) {
+ var options = this.options,
+ active = this.active,
+ clicked = $( event.currentTarget ),
+ clickedIsActive = clicked[ 0 ] === active[ 0 ],
+ collapsing = clickedIsActive && options.collapsible,
+ toShow = collapsing ? $() : clicked.next(),
+ toHide = active.next(),
+ eventData = {
+ oldHeader: active,
+ oldPanel: toHide,
+ newHeader: collapsing ? $() : clicked,
+ newPanel: toShow
+ };
+
+ event.preventDefault();
+
+ if (
+ // click on active header, but not collapsible
+ ( clickedIsActive && !options.collapsible ) ||
+ // allow canceling activation
+ ( this._trigger( "beforeActivate", event, eventData ) === false ) ) {
+ return;
+ }
+
+ options.active = collapsing ? false : this.headers.index( clicked );
+
+ // when the call to ._toggle() comes after the class changes
+ // it causes a very odd bug in IE 8 (see #6720)
+ this.active = clickedIsActive ? $() : clicked;
+ this._toggle( eventData );
+
+ // switch classes
+ // corner classes on the previously active header stay after the animation
+ active.removeClass( "ui-accordion-header-active ui-state-active" );
+ if ( options.icons ) {
+ active.children( ".ui-accordion-header-icon" )
+ .removeClass( options.icons.activeHeader )
+ .addClass( options.icons.header );
+ }
+
+ if ( !clickedIsActive ) {
+ clicked
+ .removeClass( "ui-corner-all" )
+ .addClass( "ui-accordion-header-active ui-state-active ui-corner-top" );
+ if ( options.icons ) {
+ clicked.children( ".ui-accordion-header-icon" )
+ .removeClass( options.icons.header )
+ .addClass( options.icons.activeHeader );
+ }
+
+ clicked
+ .next()
+ .addClass( "ui-accordion-content-active" );
+ }
+ },
+
+ _toggle: function( data ) {
+ var toShow = data.newPanel,
+ toHide = this.prevShow.length ? this.prevShow : data.oldPanel;
+
+ // handle activating a panel during the animation for another activation
+ this.prevShow.add( this.prevHide ).stop( true, true );
+ this.prevShow = toShow;
+ this.prevHide = toHide;
+
+ if ( this.options.animate ) {
+ this._animate( toShow, toHide, data );
+ } else {
+ toHide.hide();
+ toShow.show();
+ this._toggleComplete( data );
+ }
+
+ toHide.attr({
+ "aria-expanded": "false",
+ "aria-hidden": "true"
+ });
+ toHide.prev().attr( "aria-selected", "false" );
+ // if we're switching panels, remove the old header from the tab order
+ // if we're opening from collapsed state, remove the previous header from the tab order
+ // if we're collapsing, then keep the collapsing header in the tab order
+ if ( toShow.length && toHide.length ) {
+ toHide.prev().attr( "tabIndex", -1 );
+ } else if ( toShow.length ) {
+ this.headers.filter(function() {
+ return $( this ).attr( "tabIndex" ) === 0;
+ })
+ .attr( "tabIndex", -1 );
+ }
+
+ toShow
+ .attr({
+ "aria-expanded": "true",
+ "aria-hidden": "false"
+ })
+ .prev()
+ .attr({
+ "aria-selected": "true",
+ tabIndex: 0
+ });
+ },
+
+ _animate: function( toShow, toHide, data ) {
+ var total, easing, duration,
+ that = this,
+ adjust = 0,
+ down = toShow.length &&
+ ( !toHide.length || ( toShow.index() < toHide.index() ) ),
+ animate = this.options.animate || {},
+ options = down && animate.down || animate,
+ complete = function() {
+ that._toggleComplete( data );
+ };
+
+ if ( typeof options === "number" ) {
+ duration = options;
+ }
+ if ( typeof options === "string" ) {
+ easing = options;
+ }
+ // fall back from options to animation in case of partial down settings
+ easing = easing || options.easing || animate.easing;
+ duration = duration || options.duration || animate.duration;
+
+ if ( !toHide.length ) {
+ return toShow.animate( showProps, duration, easing, complete );
+ }
+ if ( !toShow.length ) {
+ return toHide.animate( hideProps, duration, easing, complete );
+ }
+
+ total = toShow.show().outerHeight();
+ toHide.animate( hideProps, {
+ duration: duration,
+ easing: easing,
+ step: function( now, fx ) {
+ fx.now = Math.round( now );
+ }
+ });
+ toShow
+ .hide()
+ .animate( showProps, {
+ duration: duration,
+ easing: easing,
+ complete: complete,
+ step: function( now, fx ) {
+ fx.now = Math.round( now );
+ if ( fx.prop !== "height" ) {
+ adjust += fx.now;
+ } else if ( that.options.heightStyle !== "content" ) {
+ fx.now = Math.round( total - toHide.outerHeight() - adjust );
+ adjust = 0;
+ }
+ }
+ });
+ },
+
+ _toggleComplete: function( data ) {
+ var toHide = data.oldPanel;
+
+ toHide
+ .removeClass( "ui-accordion-content-active" )
+ .prev()
+ .removeClass( "ui-corner-top" )
+ .addClass( "ui-corner-all" );
+
+ // Work around for rendering bug in IE (#5421)
+ if ( toHide.length ) {
+ toHide.parent()[0].className = toHide.parent()[0].className;
+ }
+
+ this._trigger( "activate", null, data );
+ }
+});
+
+})( jQuery );
diff --git a/debian/missing-sources/jquery-ui/jquery.ui.autocomplete.js b/debian/missing-sources/jquery-ui/jquery.ui.autocomplete.js
new file mode 100644
index 0000000..ca53d2c
--- /dev/null
+++ b/debian/missing-sources/jquery-ui/jquery.ui.autocomplete.js
@@ -0,0 +1,610 @@
+/*!
+ * jQuery UI Autocomplete 1.10.3
+ * http://jqueryui.com
+ *
+ * Copyright 2013 jQuery Foundation and other contributors
+ * Released under the MIT license.
+ * http://jquery.org/license
+ *
+ * http://api.jqueryui.com/autocomplete/
+ *
+ * Depends:
+ * jquery.ui.core.js
+ * jquery.ui.widget.js
+ * jquery.ui.position.js
+ * jquery.ui.menu.js
+ */
+(function( $, undefined ) {
+
+// used to prevent race conditions with remote data sources
+var requestIndex = 0;
+
+$.widget( "ui.autocomplete", {
+ version: "1.10.3",
+ defaultElement: "<input>",
+ options: {
+ appendTo: null,
+ autoFocus: false,
+ delay: 300,
+ minLength: 1,
+ position: {
+ my: "left top",
+ at: "left bottom",
+ collision: "none"
+ },
+ source: null,
+
+ // callbacks
+ change: null,
+ close: null,
+ focus: null,
+ open: null,
+ response: null,
+ search: null,
+ select: null
+ },
+
+ pending: 0,
+
+ _create: function() {
+ // Some browsers only repeat keydown events, not keypress events,
+ // so we use the suppressKeyPress flag to determine if we've already
+ // handled the keydown event. #7269
+ // Unfortunately the code for & in keypress is the same as the up arrow,
+ // so we use the suppressKeyPressRepeat flag to avoid handling keypress
+ // events when we know the keydown event was used to modify the
+ // search term. #7799
+ var suppressKeyPress, suppressKeyPressRepeat, suppressInput,
+ nodeName = this.element[0].nodeName.toLowerCase(),
+ isTextarea = nodeName === "textarea",
+ isInput = nodeName === "input";
+
+ this.isMultiLine =
+ // Textareas are always multi-line
+ isTextarea ? true :
+ // Inputs are always single-line, even if inside a contentEditable element
+ // IE also treats inputs as contentEditable
+ isInput ? false :
+ // All other element types are determined by whether or not they're contentEditable
+ this.element.prop( "isContentEditable" );
+
+ this.valueMethod = this.element[ isTextarea || isInput ? "val" : "text" ];
+ this.isNewMenu = true;
+
+ this.element
+ .addClass( "ui-autocomplete-input" )
+ .attr( "autocomplete", "off" );
+
+ this._on( this.element, {
+ keydown: function( event ) {
+ /*jshint maxcomplexity:15*/
+ if ( this.element.prop( "readOnly" ) ) {
+ suppressKeyPress = true;
+ suppressInput = true;
+ suppressKeyPressRepeat = true;
+ return;
+ }
+
+ suppressKeyPress = false;
+ suppressInput = false;
+ suppressKeyPressRepeat = false;
+ var keyCode = $.ui.keyCode;
+ switch( event.keyCode ) {
+ case keyCode.PAGE_UP:
+ suppressKeyPress = true;
+ this._move( "previousPage", event );
+ break;
+ case keyCode.PAGE_DOWN:
+ suppressKeyPress = true;
+ this._move( "nextPage", event );
+ break;
+ case keyCode.UP:
+ suppressKeyPress = true;
+ this._keyEvent( "previous", event );
+ break;
+ case keyCode.DOWN:
+ suppressKeyPress = true;
+ this._keyEvent( "next", event );
+ break;
+ case keyCode.ENTER:
+ case keyCode.NUMPAD_ENTER:
+ // when menu is open and has focus
+ if ( this.menu.active ) {
+ // #6055 - Opera still allows the keypress to occur
+ // which causes forms to submit
+ suppressKeyPress = true;
+ event.preventDefault();
+ this.menu.select( event );
+ }
+ break;
+ case keyCode.TAB:
+ if ( this.menu.active ) {
+ this.menu.select( event );
+ }
+ break;
+ case keyCode.ESCAPE:
+ if ( this.menu.element.is( ":visible" ) ) {
+ this._value( this.term );
+ this.close( event );
+ // Different browsers have different default behavior for escape
+ // Single press can mean undo or clear
+ // Double press in IE means clear the whole form
+ event.preventDefault();
+ }
+ break;
+ default:
+ suppressKeyPressRepeat = true;
+ // search timeout should be triggered before the input value is changed
+ this._searchTimeout( event );
+ break;
+ }
+ },
+ keypress: function( event ) {
+ if ( suppressKeyPress ) {
+ suppressKeyPress = false;
+ if ( !this.isMultiLine || this.menu.element.is( ":visible" ) ) {
+ event.preventDefault();
+ }
+ return;
+ }
+ if ( suppressKeyPressRepeat ) {
+ return;
+ }
+
+ // replicate some key handlers to allow them to repeat in Firefox and Opera
+ var keyCode = $.ui.keyCode;
+ switch( event.keyCode ) {
+ case keyCode.PAGE_UP:
+ this._move( "previousPage", event );
+ break;
+ case keyCode.PAGE_DOWN:
+ this._move( "nextPage", event );
+ break;
+ case keyCode.UP:
+ this._keyEvent( "previous", event );
+ break;
+ case keyCode.DOWN:
+ this._keyEvent( "next", event );
+ break;
+ }
+ },
+ input: function( event ) {
+ if ( suppressInput ) {
+ suppressInput = false;
+ event.preventDefault();
+ return;
+ }
+ this._searchTimeout( event );
+ },
+ focus: function() {
+ this.selectedItem = null;
+ this.previous = this._value();
+ },
+ blur: function( event ) {
+ if ( this.cancelBlur ) {
+ delete this.cancelBlur;
+ return;
+ }
+
+ clearTimeout( this.searching );
+ this.close( event );
+ this._change( event );
+ }
+ });
+
+ this._initSource();
+ this.menu = $( "<ul>" )
+ .addClass( "ui-autocomplete ui-front" )
+ .appendTo( this._appendTo() )
+ .menu({
+ // disable ARIA support, the live region takes care of that
+ role: null
+ })
+ .hide()
+ .data( "ui-menu" );
+
+ this._on( this.menu.element, {
+ mousedown: function( event ) {
+ // prevent moving focus out of the text field
+ event.preventDefault();
+
+ // IE doesn't prevent moving focus even with event.preventDefault()
+ // so we set a flag to know when we should ignore the blur event
+ this.cancelBlur = true;
+ this._delay(function() {
+ delete this.cancelBlur;
+ });
+
+ // clicking on the scrollbar causes focus to shift to the body
+ // but we can't detect a mouseup or a click immediately afterward
+ // so we have to track the next mousedown and close the menu if
+ // the user clicks somewhere outside of the autocomplete
+ var menuElement = this.menu.element[ 0 ];
+ if ( !$( event.target ).closest( ".ui-menu-item" ).length ) {
+ this._delay(function() {
+ var that = this;
+ this.document.one( "mousedown", function( event ) {
+ if ( event.target !== that.element[ 0 ] &&
+ event.target !== menuElement &&
+ !$.contains( menuElement, event.target ) ) {
+ that.close();
+ }
+ });
+ });
+ }
+ },
+ menufocus: function( event, ui ) {
+ // support: Firefox
+ // Prevent accidental activation of menu items in Firefox (#7024 #9118)
+ if ( this.isNewMenu ) {
+ this.isNewMenu = false;
+ if ( event.originalEvent && /^mouse/.test( event.originalEvent.type ) ) {
+ this.menu.blur();
+
+ this.document.one( "mousemove", function() {
+ $( event.target ).trigger( event.originalEvent );
+ });
+
+ return;
+ }
+ }
+
+ var item = ui.item.data( "ui-autocomplete-item" );
+ if ( false !== this._trigger( "focus", event, { item: item } ) ) {
+ // use value to match what will end up in the input, if it was a key event
+ if ( event.originalEvent && /^key/.test( event.originalEvent.type ) ) {
+ this._value( item.value );
+ }
+ } else {
+ // Normally the input is populated with the item's value as the
+ // menu is navigated, causing screen readers to notice a change and
+ // announce the item. Since the focus event was canceled, this doesn't
+ // happen, so we update the live region so that screen readers can
+ // still notice the change and announce it.
+ this.liveRegion.text( item.value );
+ }
+ },
+ menuselect: function( event, ui ) {
+ var item = ui.item.data( "ui-autocomplete-item" ),
+ previous = this.previous;
+
+ // only trigger when focus was lost (click on menu)
+ if ( this.element[0] !== this.document[0].activeElement ) {
+ this.element.focus();
+ this.previous = previous;
+ // #6109 - IE triggers two focus events and the second
+ // is asynchronous, so we need to reset the previous
+ // term synchronously and asynchronously :-(
+ this._delay(function() {
+ this.previous = previous;
+ this.selectedItem = item;
+ });
+ }
+
+ if ( false !== this._trigger( "select", event, { item: item } ) ) {
+ this._value( item.value );
+ }
+ // reset the term after the select event
+ // this allows custom select handling to work properly
+ this.term = this._value();
+
+ this.close( event );
+ this.selectedItem = item;
+ }
+ });
+
+ this.liveRegion = $( "<span>", {
+ role: "status",
+ "aria-live": "polite"
+ })
+ .addClass( "ui-helper-hidden-accessible" )
+ .insertBefore( this.element );
+
+ // turning off autocomplete prevents the browser from remembering the
+ // value when navigating through history, so we re-enable autocomplete
+ // if the page is unloaded before the widget is destroyed. #7790
+ this._on( this.window, {
+ beforeunload: function() {
+ this.element.removeAttr( "autocomplete" );
+ }
+ });
+ },
+
+ _destroy: function() {
+ clearTimeout( this.searching );
+ this.element
+ .removeClass( "ui-autocomplete-input" )
+ .removeAttr( "autocomplete" );
+ this.menu.element.remove();
+ this.liveRegion.remove();
+ },
+
+ _setOption: function( key, value ) {
+ this._super( key, value );
+ if ( key === "source" ) {
+ this._initSource();
+ }
+ if ( key === "appendTo" ) {
+ this.menu.element.appendTo( this._appendTo() );
+ }
+ if ( key === "disabled" && value && this.xhr ) {
+ this.xhr.abort();
+ }
+ },
+
+ _appendTo: function() {
+ var element = this.options.appendTo;
+
+ if ( element ) {
+ element = element.jquery || element.nodeType ?
+ $( element ) :
+ this.document.find( element ).eq( 0 );
+ }
+
+ if ( !element ) {
+ element = this.element.closest( ".ui-front" );
+ }
+
+ if ( !element.length ) {
+ element = this.document[0].body;
+ }
+
+ return element;
+ },
+
+ _initSource: function() {
+ var array, url,
+ that = this;
+ if ( $.isArray(this.options.source) ) {
+ array = this.options.source;
+ this.source = function( request, response ) {
+ response( $.ui.autocomplete.filter( array, request.term ) );
+ };
+ } else if ( typeof this.options.source === "string" ) {
+ url = this.options.source;
+ this.source = function( request, response ) {
+ if ( that.xhr ) {
+ that.xhr.abort();
+ }
+ that.xhr = $.ajax({
+ url: url,
+ data: request,
+ dataType: "json",
+ success: function( data ) {
+ response( data );
+ },
+ error: function() {
+ response( [] );
+ }
+ });
+ };
+ } else {
+ this.source = this.options.source;
+ }
+ },
+
+ _searchTimeout: function( event ) {
+ clearTimeout( this.searching );
+ this.searching = this._delay(function() {
+ // only search if the value has changed
+ if ( this.term !== this._value() ) {
+ this.selectedItem = null;
+ this.search( null, event );
+ }
+ }, this.options.delay );
+ },
+
+ search: function( value, event ) {
+ value = value != null ? value : this._value();
+
+ // always save the actual value, not the one passed as an argument
+ this.term = this._value();
+
+ if ( value.length < this.options.minLength ) {
+ return this.close( event );
+ }
+
+ if ( this._trigger( "search", event ) === false ) {
+ return;
+ }
+
+ return this._search( value );
+ },
+
+ _search: function( value ) {
+ this.pending++;
+ this.element.addClass( "ui-autocomplete-loading" );
+ this.cancelSearch = false;
+
+ this.source( { term: value }, this._response() );
+ },
+
+ _response: function() {
+ var that = this,
+ index = ++requestIndex;
+
+ return function( content ) {
+ if ( index === requestIndex ) {
+ that.__response( content );
+ }
+
+ that.pending--;
+ if ( !that.pending ) {
+ that.element.removeClass( "ui-autocomplete-loading" );
+ }
+ };
+ },
+
+ __response: function( content ) {
+ if ( content ) {
+ content = this._normalize( content );
+ }
+ this._trigger( "response", null, { content: content } );
+ if ( !this.options.disabled && content && content.length && !this.cancelSearch ) {
+ this._suggest( content );
+ this._trigger( "open" );
+ } else {
+ // use ._close() instead of .close() so we don't cancel future searches
+ this._close();
+ }
+ },
+
+ close: function( event ) {
+ this.cancelSearch = true;
+ this._close( event );
+ },
+
+ _close: function( event ) {
+ if ( this.menu.element.is( ":visible" ) ) {
+ this.menu.element.hide();
+ this.menu.blur();
+ this.isNewMenu = true;
+ this._trigger( "close", event );
+ }
+ },
+
+ _change: function( event ) {
+ if ( this.previous !== this._value() ) {
+ this._trigger( "change", event, { item: this.selectedItem } );
+ }
+ },
+
+ _normalize: function( items ) {
+ // assume all items have the right format when the first item is complete
+ if ( items.length && items[0].label && items[0].value ) {
+ return items;
+ }
+ return $.map( items, function( item ) {
+ if ( typeof item === "string" ) {
+ return {
+ label: item,
+ value: item
+ };
+ }
+ return $.extend({
+ label: item.label || item.value,
+ value: item.value || item.label
+ }, item );
+ });
+ },
+
+ _suggest: function( items ) {
+ var ul = this.menu.element.empty();
+ this._renderMenu( ul, items );
+ this.isNewMenu = true;
+ this.menu.refresh();
+
+ // size and position menu
+ ul.show();
+ this._resizeMenu();
+ ul.position( $.extend({
+ of: this.element
+ }, this.options.position ));
+
+ if ( this.options.autoFocus ) {
+ this.menu.next();
+ }
+ },
+
+ _resizeMenu: function() {
+ var ul = this.menu.element;
+ ul.outerWidth( Math.max(
+ // Firefox wraps long text (possibly a rounding bug)
+ // so we add 1px to avoid the wrapping (#7513)
+ ul.width( "" ).outerWidth() + 1,
+ this.element.outerWidth()
+ ) );
+ },
+
+ _renderMenu: function( ul, items ) {
+ var that = this;
+ $.each( items, function( index, item ) {
+ that._renderItemData( ul, item );
+ });
+ },
+
+ _renderItemData: function( ul, item ) {
+ return this._renderItem( ul, item ).data( "ui-autocomplete-item", item );
+ },
+
+ _renderItem: function( ul, item ) {
+ return $( "<li>" )
+ .append( $( "<a>" ).text( item.label ) )
+ .appendTo( ul );
+ },
+
+ _move: function( direction, event ) {
+ if ( !this.menu.element.is( ":visible" ) ) {
+ this.search( null, event );
+ return;
+ }
+ if ( this.menu.isFirstItem() && /^previous/.test( direction ) ||
+ this.menu.isLastItem() && /^next/.test( direction ) ) {
+ this._value( this.term );
+ this.menu.blur();
+ return;
+ }
+ this.menu[ direction ]( event );
+ },
+
+ widget: function() {
+ return this.menu.element;
+ },
+
+ _value: function() {
+ return this.valueMethod.apply( this.element, arguments );
+ },
+
+ _keyEvent: function( keyEvent, event ) {
+ if ( !this.isMultiLine || this.menu.element.is( ":visible" ) ) {
+ this._move( keyEvent, event );
+
+ // prevents moving cursor to beginning/end of the text field in some browsers
+ event.preventDefault();
+ }
+ }
+});
+
+$.extend( $.ui.autocomplete, {
+ escapeRegex: function( value ) {
+ return value.replace(/[\-\[\]{}()*+?.,\\\^$|#\s]/g, "\\$&");
+ },
+ filter: function(array, term) {
+ var matcher = new RegExp( $.ui.autocomplete.escapeRegex(term), "i" );
+ return $.grep( array, function(value) {
+ return matcher.test( value.label || value.value || value );
+ });
+ }
+});
+
+
+// live region extension, adding a `messages` option
+// NOTE: This is an experimental API. We are still investigating
+// a full solution for string manipulation and internationalization.
+$.widget( "ui.autocomplete", $.ui.autocomplete, {
+ options: {
+ messages: {
+ noResults: "No search results.",
+ results: function( amount ) {
+ return amount + ( amount > 1 ? " results are" : " result is" ) +
+ " available, use up and down arrow keys to navigate.";
+ }
+ }
+ },
+
+ __response: function( content ) {
+ var message;
+ this._superApply( arguments );
+ if ( this.options.disabled || this.cancelSearch ) {
+ return;
+ }
+ if ( content && content.length ) {
+ message = this.options.messages.results( content.length );
+ } else {
+ message = this.options.messages.noResults;
+ }
+ this.liveRegion.text( message );
+ }
+});
+
+}( jQuery ));
diff --git a/debian/missing-sources/jquery-ui/jquery.ui.button.js b/debian/missing-sources/jquery-ui/jquery.ui.button.js
new file mode 100644
index 0000000..5926642
--- /dev/null
+++ b/debian/missing-sources/jquery-ui/jquery.ui.button.js
@@ -0,0 +1,419 @@
+/*!
+ * jQuery UI Button 1.10.3
+ * http://jqueryui.com
+ *
+ * Copyright 2013 jQuery Foundation and other contributors
+ * Released under the MIT license.
+ * http://jquery.org/license
+ *
+ * http://api.jqueryui.com/button/
+ *
+ * Depends:
+ * jquery.ui.core.js
+ * jquery.ui.widget.js
+ */
+(function( $, undefined ) {
+
+var lastActive, startXPos, startYPos, clickDragged,
+ baseClasses = "ui-button ui-widget ui-state-default ui-corner-all",
+ stateClasses = "ui-state-hover ui-state-active ",
+ typeClasses = "ui-button-icons-only ui-button-icon-only ui-button-text-icons ui-button-text-icon-primary ui-button-text-icon-secondary ui-button-text-only",
+ formResetHandler = function() {
+ var form = $( this );
+ setTimeout(function() {
+ form.find( ":ui-button" ).button( "refresh" );
+ }, 1 );
+ },
+ radioGroup = function( radio ) {
+ var name = radio.name,
+ form = radio.form,
+ radios = $( [] );
+ if ( name ) {
+ name = name.replace( /'/g, "\\'" );
+ if ( form ) {
+ radios = $( form ).find( "[name='" + name + "']" );
+ } else {
+ radios = $( "[name='" + name + "']", radio.ownerDocument )
+ .filter(function() {
+ return !this.form;
+ });
+ }
+ }
+ return radios;
+ };
+
+$.widget( "ui.button", {
+ version: "1.10.3",
+ defaultElement: "<button>",
+ options: {
+ disabled: null,
+ text: true,
+ label: null,
+ icons: {
+ primary: null,
+ secondary: null
+ }
+ },
+ _create: function() {
+ this.element.closest( "form" )
+ .unbind( "reset" + this.eventNamespace )
+ .bind( "reset" + this.eventNamespace, formResetHandler );
+
+ if ( typeof this.options.disabled !== "boolean" ) {
+ this.options.disabled = !!this.element.prop( "disabled" );
+ } else {
+ this.element.prop( "disabled", this.options.disabled );
+ }
+
+ this._determineButtonType();
+ this.hasTitle = !!this.buttonElement.attr( "title" );
+
+ var that = this,
+ options = this.options,
+ toggleButton = this.type === "checkbox" || this.type === "radio",
+ activeClass = !toggleButton ? "ui-state-active" : "",
+ focusClass = "ui-state-focus";
+
+ if ( options.label === null ) {
+ options.label = (this.type === "input" ? this.buttonElement.val() : this.buttonElement.html());
+ }
+
+ this._hoverable( this.buttonElement );
+
+ this.buttonElement
+ .addClass( baseClasses )
+ .attr( "role", "button" )
+ .bind( "mouseenter" + this.eventNamespace, function() {
+ if ( options.disabled ) {
+ return;
+ }
+ if ( this === lastActive ) {
+ $( this ).addClass( "ui-state-active" );
+ }
+ })
+ .bind( "mouseleave" + this.eventNamespace, function() {
+ if ( options.disabled ) {
+ return;
+ }
+ $( this ).removeClass( activeClass );
+ })
+ .bind( "click" + this.eventNamespace, function( event ) {
+ if ( options.disabled ) {
+ event.preventDefault();
+ event.stopImmediatePropagation();
+ }
+ });
+
+ this.element
+ .bind( "focus" + this.eventNamespace, function() {
+ // no need to check disabled, focus won't be triggered anyway
+ that.buttonElement.addClass( focusClass );
+ })
+ .bind( "blur" + this.eventNamespace, function() {
+ that.buttonElement.removeClass( focusClass );
+ });
+
+ if ( toggleButton ) {
+ this.element.bind( "change" + this.eventNamespace, function() {
+ if ( clickDragged ) {
+ return;
+ }
+ that.refresh();
+ });
+ // if mouse moves between mousedown and mouseup (drag) set clickDragged flag
+ // prevents issue where button state changes but checkbox/radio checked state
+ // does not in Firefox (see ticket #6970)
+ this.buttonElement
+ .bind( "mousedown" + this.eventNamespace, function( event ) {
+ if ( options.disabled ) {
+ return;
+ }
+ clickDragged = false;
+ startXPos = event.pageX;
+ startYPos = event.pageY;
+ })
+ .bind( "mouseup" + this.eventNamespace, function( event ) {
+ if ( options.disabled ) {
+ return;
+ }
+ if ( startXPos !== event.pageX || startYPos !== event.pageY ) {
+ clickDragged = true;
+ }
+ });
+ }
+
+ if ( this.type === "checkbox" ) {
+ this.buttonElement.bind( "click" + this.eventNamespace, function() {
+ if ( options.disabled || clickDragged ) {
+ return false;
+ }
+ });
+ } else if ( this.type === "radio" ) {
+ this.buttonElement.bind( "click" + this.eventNamespace, function() {
+ if ( options.disabled || clickDragged ) {
+ return false;
+ }
+ $( this ).addClass( "ui-state-active" );
+ that.buttonElement.attr( "aria-pressed", "true" );
+
+ var radio = that.element[ 0 ];
+ radioGroup( radio )
+ .not( radio )
+ .map(function() {
+ return $( this ).button( "widget" )[ 0 ];
+ })
+ .removeClass( "ui-state-active" )
+ .attr( "aria-pressed", "false" );
+ });
+ } else {
+ this.buttonElement
+ .bind( "mousedown" + this.eventNamespace, function() {
+ if ( options.disabled ) {
+ return false;
+ }
+ $( this ).addClass( "ui-state-active" );
+ lastActive = this;
+ that.document.one( "mouseup", function() {
+ lastActive = null;
+ });
+ })
+ .bind( "mouseup" + this.eventNamespace, function() {
+ if ( options.disabled ) {
+ return false;
+ }
+ $( this ).removeClass( "ui-state-active" );
+ })
+ .bind( "keydown" + this.eventNamespace, function(event) {
+ if ( options.disabled ) {
+ return false;
+ }
+ if ( event.keyCode === $.ui.keyCode.SPACE || event.keyCode === $.ui.keyCode.ENTER ) {
+ $( this ).addClass( "ui-state-active" );
+ }
+ })
+ // see #8559, we bind to blur here in case the button element loses
+ // focus between keydown and keyup, it would be left in an "active" state
+ .bind( "keyup" + this.eventNamespace + " blur" + this.eventNamespace, function() {
+ $( this ).removeClass( "ui-state-active" );
+ });
+
+ if ( this.buttonElement.is("a") ) {
+ this.buttonElement.keyup(function(event) {
+ if ( event.keyCode === $.ui.keyCode.SPACE ) {
+ // TODO pass through original event correctly (just as 2nd argument doesn't work)
+ $( this ).click();
+ }
+ });
+ }
+ }
+
+ // TODO: pull out $.Widget's handling for the disabled option into
+ // $.Widget.prototype._setOptionDisabled so it's easy to proxy and can
+ // be overridden by individual plugins
+ this._setOption( "disabled", options.disabled );
+ this._resetButton();
+ },
+
+ _determineButtonType: function() {
+ var ancestor, labelSelector, checked;
+
+ if ( this.element.is("[type=checkbox]") ) {
+ this.type = "checkbox";
+ } else if ( this.element.is("[type=radio]") ) {
+ this.type = "radio";
+ } else if ( this.element.is("input") ) {
+ this.type = "input";
+ } else {
+ this.type = "button";
+ }
+
+ if ( this.type === "checkbox" || this.type === "radio" ) {
+ // we don't search against the document in case the element
+ // is disconnected from the DOM
+ ancestor = this.element.parents().last();
+ labelSelector = "label[for='" + this.element.attr("id") + "']";
+ this.buttonElement = ancestor.find( labelSelector );
+ if ( !this.buttonElement.length ) {
+ ancestor = ancestor.length ? ancestor.siblings() : this.element.siblings();
+ this.buttonElement = ancestor.filter( labelSelector );
+ if ( !this.buttonElement.length ) {
+ this.buttonElement = ancestor.find( labelSelector );
+ }
+ }
+ this.element.addClass( "ui-helper-hidden-accessible" );
+
+ checked = this.element.is( ":checked" );
+ if ( checked ) {
+ this.buttonElement.addClass( "ui-state-active" );
+ }
+ this.buttonElement.prop( "aria-pressed", checked );
+ } else {
+ this.buttonElement = this.element;
+ }
+ },
+
+ widget: function() {
+ return this.buttonElement;
+ },
+
+ _destroy: function() {
+ this.element
+ .removeClass( "ui-helper-hidden-accessible" );
+ this.buttonElement
+ .removeClass( baseClasses + " " + stateClasses + " " + typeClasses )
+ .removeAttr( "role" )
+ .removeAttr( "aria-pressed" )
+ .html( this.buttonElement.find(".ui-button-text").html() );
+
+ if ( !this.hasTitle ) {
+ this.buttonElement.removeAttr( "title" );
+ }
+ },
+
+ _setOption: function( key, value ) {
+ this._super( key, value );
+ if ( key === "disabled" ) {
+ if ( value ) {
+ this.element.prop( "disabled", true );
+ } else {
+ this.element.prop( "disabled", false );
+ }
+ return;
+ }
+ this._resetButton();
+ },
+
+ refresh: function() {
+ //See #8237 & #8828
+ var isDisabled = this.element.is( "input, button" ) ? this.element.is( ":disabled" ) : this.element.hasClass( "ui-button-disabled" );
+
+ if ( isDisabled !== this.options.disabled ) {
+ this._setOption( "disabled", isDisabled );
+ }
+ if ( this.type === "radio" ) {
+ radioGroup( this.element[0] ).each(function() {
+ if ( $( this ).is( ":checked" ) ) {
+ $( this ).button( "widget" )
+ .addClass( "ui-state-active" )
+ .attr( "aria-pressed", "true" );
+ } else {
+ $( this ).button( "widget" )
+ .removeClass( "ui-state-active" )
+ .attr( "aria-pressed", "false" );
+ }
+ });
+ } else if ( this.type === "checkbox" ) {
+ if ( this.element.is( ":checked" ) ) {
+ this.buttonElement
+ .addClass( "ui-state-active" )
+ .attr( "aria-pressed", "true" );
+ } else {
+ this.buttonElement
+ .removeClass( "ui-state-active" )
+ .attr( "aria-pressed", "false" );
+ }
+ }
+ },
+
+ _resetButton: function() {
+ if ( this.type === "input" ) {
+ if ( this.options.label ) {
+ this.element.val( this.options.label );
+ }
+ return;
+ }
+ var buttonElement = this.buttonElement.removeClass( typeClasses ),
+ buttonText = $( "<span></span>", this.document[0] )
+ .addClass( "ui-button-text" )
+ .html( this.options.label )
+ .appendTo( buttonElement.empty() )
+ .text(),
+ icons = this.options.icons,
+ multipleIcons = icons.primary && icons.secondary,
+ buttonClasses = [];
+
+ if ( icons.primary || icons.secondary ) {
+ if ( this.options.text ) {
+ buttonClasses.push( "ui-button-text-icon" + ( multipleIcons ? "s" : ( icons.primary ? "-primary" : "-secondary" ) ) );
+ }
+
+ if ( icons.primary ) {
+ buttonElement.prepend( "<span class='ui-button-icon-primary ui-icon " + icons.primary + "'></span>" );
+ }
+
+ if ( icons.secondary ) {
+ buttonElement.append( "<span class='ui-button-icon-secondary ui-icon " + icons.secondary + "'></span>" );
+ }
+
+ if ( !this.options.text ) {
+ buttonClasses.push( multipleIcons ? "ui-button-icons-only" : "ui-button-icon-only" );
+
+ if ( !this.hasTitle ) {
+ buttonElement.attr( "title", $.trim( buttonText ) );
+ }
+ }
+ } else {
+ buttonClasses.push( "ui-button-text-only" );
+ }
+ buttonElement.addClass( buttonClasses.join( " " ) );
+ }
+});
+
+$.widget( "ui.buttonset", {
+ version: "1.10.3",
+ options: {
+ items: "button, input[type=button], input[type=submit], input[type=reset], input[type=checkbox], input[type=radio], a, :data(ui-button)"
+ },
+
+ _create: function() {
+ this.element.addClass( "ui-buttonset" );
+ },
+
+ _init: function() {
+ this.refresh();
+ },
+
+ _setOption: function( key, value ) {
+ if ( key === "disabled" ) {
+ this.buttons.button( "option", key, value );
+ }
+
+ this._super( key, value );
+ },
+
+ refresh: function() {
+ var rtl = this.element.css( "direction" ) === "rtl";
+
+ this.buttons = this.element.find( this.options.items )
+ .filter( ":ui-button" )
+ .button( "refresh" )
+ .end()
+ .not( ":ui-button" )
+ .button()
+ .end()
+ .map(function() {
+ return $( this ).button( "widget" )[ 0 ];
+ })
+ .removeClass( "ui-corner-all ui-corner-left ui-corner-right" )
+ .filter( ":first" )
+ .addClass( rtl ? "ui-corner-right" : "ui-corner-left" )
+ .end()
+ .filter( ":last" )
+ .addClass( rtl ? "ui-corner-left" : "ui-corner-right" )
+ .end()
+ .end();
+ },
+
+ _destroy: function() {
+ this.element.removeClass( "ui-buttonset" );
+ this.buttons
+ .map(function() {
+ return $( this ).button( "widget" )[ 0 ];
+ })
+ .removeClass( "ui-corner-left ui-corner-right" )
+ .end()
+ .button( "destroy" );
+ }
+});
+
+}( jQuery ) );
diff --git a/debian/missing-sources/jquery-ui/jquery.ui.core.js b/debian/missing-sources/jquery-ui/jquery.ui.core.js
new file mode 100644
index 0000000..91ca5ff
--- /dev/null
+++ b/debian/missing-sources/jquery-ui/jquery.ui.core.js
@@ -0,0 +1,320 @@
+/*!
+ * jQuery UI Core 1.10.3
+ * http://jqueryui.com
+ *
+ * Copyright 2013 jQuery Foundation and other contributors
+ * Released under the MIT license.
+ * http://jquery.org/license
+ *
+ * http://api.jqueryui.com/category/ui-core/
+ */
+(function( $, undefined ) {
+
+var uuid = 0,
+ runiqueId = /^ui-id-\d+$/;
+
+// $.ui might exist from components with no dependencies, e.g., $.ui.position
+$.ui = $.ui || {};
+
+$.extend( $.ui, {
+ version: "1.10.3",
+
+ keyCode: {
+ BACKSPACE: 8,
+ COMMA: 188,
+ DELETE: 46,
+ DOWN: 40,
+ END: 35,
+ ENTER: 13,
+ ESCAPE: 27,
+ HOME: 36,
+ LEFT: 37,
+ NUMPAD_ADD: 107,
+ NUMPAD_DECIMAL: 110,
+ NUMPAD_DIVIDE: 111,
+ NUMPAD_ENTER: 108,
+ NUMPAD_MULTIPLY: 106,
+ NUMPAD_SUBTRACT: 109,
+ PAGE_DOWN: 34,
+ PAGE_UP: 33,
+ PERIOD: 190,
+ RIGHT: 39,
+ SPACE: 32,
+ TAB: 9,
+ UP: 38
+ }
+});
+
+// plugins
+$.fn.extend({
+ focus: (function( orig ) {
+ return function( delay, fn ) {
+ return typeof delay === "number" ?
+ this.each(function() {
+ var elem = this;
+ setTimeout(function() {
+ $( elem ).focus();
+ if ( fn ) {
+ fn.call( elem );
+ }
+ }, delay );
+ }) :
+ orig.apply( this, arguments );
+ };
+ })( $.fn.focus ),
+
+ scrollParent: function() {
+ var scrollParent;
+ if (($.ui.ie && (/(static|relative)/).test(this.css("position"))) || (/absolute/).test(this.css("position"))) {
+ scrollParent = this.parents().filter(function() {
+ return (/(relative|absolute|fixed)/).test($.css(this,"position")) && (/(auto|scroll)/).test($.css(this,"overflow")+$.css(this,"overflow-y")+$.css(this,"overflow-x"));
+ }).eq(0);
+ } else {
+ scrollParent = this.parents().filter(function() {
+ return (/(auto|scroll)/).test($.css(this,"overflow")+$.css(this,"overflow-y")+$.css(this,"overflow-x"));
+ }).eq(0);
+ }
+
+ return (/fixed/).test(this.css("position")) || !scrollParent.length ? $(document) : scrollParent;
+ },
+
+ zIndex: function( zIndex ) {
+ if ( zIndex !== undefined ) {
+ return this.css( "zIndex", zIndex );
+ }
+
+ if ( this.length ) {
+ var elem = $( this[ 0 ] ), position, value;
+ while ( elem.length && elem[ 0 ] !== document ) {
+ // Ignore z-index if position is set to a value where z-index is ignored by the browser
+ // This makes behavior of this function consistent across browsers
+ // WebKit always returns auto if the element is positioned
+ position = elem.css( "position" );
+ if ( position === "absolute" || position === "relative" || position === "fixed" ) {
+ // IE returns 0 when zIndex is not specified
+ // other browsers return a string
+ // we ignore the case of nested elements with an explicit value of 0
+ // <div style="z-index: -10;"><div style="z-index: 0;"></div></div>
+ value = parseInt( elem.css( "zIndex" ), 10 );
+ if ( !isNaN( value ) && value !== 0 ) {
+ return value;
+ }
+ }
+ elem = elem.parent();
+ }
+ }
+
+ return 0;
+ },
+
+ uniqueId: function() {
+ return this.each(function() {
+ if ( !this.id ) {
+ this.id = "ui-id-" + (++uuid);
+ }
+ });
+ },
+
+ removeUniqueId: function() {
+ return this.each(function() {
+ if ( runiqueId.test( this.id ) ) {
+ $( this ).removeAttr( "id" );
+ }
+ });
+ }
+});
+
+// selectors
+function focusable( element, isTabIndexNotNaN ) {
+ var map, mapName, img,
+ nodeName = element.nodeName.toLowerCase();
+ if ( "area" === nodeName ) {
+ map = element.parentNode;
+ mapName = map.name;
+ if ( !element.href || !mapName || map.nodeName.toLowerCase() !== "map" ) {
+ return false;
+ }
+ img = $( "img[usemap=#" + mapName + "]" )[0];
+ return !!img && visible( img );
+ }
+ return ( /input|select|textarea|button|object/.test( nodeName ) ?
+ !element.disabled :
+ "a" === nodeName ?
+ element.href || isTabIndexNotNaN :
+ isTabIndexNotNaN) &&
+ // the element and all of its ancestors must be visible
+ visible( element );
+}
+
+function visible( element ) {
+ return $.expr.filters.visible( element ) &&
+ !$( element ).parents().addBack().filter(function() {
+ return $.css( this, "visibility" ) === "hidden";
+ }).length;
+}
+
+$.extend( $.expr[ ":" ], {
+ data: $.expr.createPseudo ?
+ $.expr.createPseudo(function( dataName ) {
+ return function( elem ) {
+ return !!$.data( elem, dataName );
+ };
+ }) :
+ // support: jQuery <1.8
+ function( elem, i, match ) {
+ return !!$.data( elem, match[ 3 ] );
+ },
+
+ focusable: function( element ) {
+ return focusable( element, !isNaN( $.attr( element, "tabindex" ) ) );
+ },
+
+ tabbable: function( element ) {
+ var tabIndex = $.attr( element, "tabindex" ),
+ isTabIndexNaN = isNaN( tabIndex );
+ return ( isTabIndexNaN || tabIndex >= 0 ) && focusable( element, !isTabIndexNaN );
+ }
+});
+
+// support: jQuery <1.8
+if ( !$( "<a>" ).outerWidth( 1 ).jquery ) {
+ $.each( [ "Width", "Height" ], function( i, name ) {
+ var side = name === "Width" ? [ "Left", "Right" ] : [ "Top", "Bottom" ],
+ type = name.toLowerCase(),
+ orig = {
+ innerWidth: $.fn.innerWidth,
+ innerHeight: $.fn.innerHeight,
+ outerWidth: $.fn.outerWidth,
+ outerHeight: $.fn.outerHeight
+ };
+
+ function reduce( elem, size, border, margin ) {
+ $.each( side, function() {
+ size -= parseFloat( $.css( elem, "padding" + this ) ) || 0;
+ if ( border ) {
+ size -= parseFloat( $.css( elem, "border" + this + "Width" ) ) || 0;
+ }
+ if ( margin ) {
+ size -= parseFloat( $.css( elem, "margin" + this ) ) || 0;
+ }
+ });
+ return size;
+ }
+
+ $.fn[ "inner" + name ] = function( size ) {
+ if ( size === undefined ) {
+ return orig[ "inner" + name ].call( this );
+ }
+
+ return this.each(function() {
+ $( this ).css( type, reduce( this, size ) + "px" );
+ });
+ };
+
+ $.fn[ "outer" + name] = function( size, margin ) {
+ if ( typeof size !== "number" ) {
+ return orig[ "outer" + name ].call( this, size );
+ }
+
+ return this.each(function() {
+ $( this).css( type, reduce( this, size, true, margin ) + "px" );
+ });
+ };
+ });
+}
+
+// support: jQuery <1.8
+if ( !$.fn.addBack ) {
+ $.fn.addBack = function( selector ) {
+ return this.add( selector == null ?
+ this.prevObject : this.prevObject.filter( selector )
+ );
+ };
+}
+
+// support: jQuery 1.6.1, 1.6.2 (http://bugs.jquery.com/ticket/9413)
+if ( $( "<a>" ).data( "a-b", "a" ).removeData( "a-b" ).data( "a-b" ) ) {
+ $.fn.removeData = (function( removeData ) {
+ return function( key ) {
+ if ( arguments.length ) {
+ return removeData.call( this, $.camelCase( key ) );
+ } else {
+ return removeData.call( this );
+ }
+ };
+ })( $.fn.removeData );
+}
+
+
+
+
+
+// deprecated
+$.ui.ie = !!/msie [\w.]+/.exec( navigator.userAgent.toLowerCase() );
+
+$.support.selectstart = "onselectstart" in document.createElement( "div" );
+$.fn.extend({
+ disableSelection: function() {
+ return this.bind( ( $.support.selectstart ? "selectstart" : "mousedown" ) +
+ ".ui-disableSelection", function( event ) {
+ event.preventDefault();
+ });
+ },
+
+ enableSelection: function() {
+ return this.unbind( ".ui-disableSelection" );
+ }
+});
+
+$.extend( $.ui, {
+ // $.ui.plugin is deprecated. Use $.widget() extensions instead.
+ plugin: {
+ add: function( module, option, set ) {
+ var i,
+ proto = $.ui[ module ].prototype;
+ for ( i in set ) {
+ proto.plugins[ i ] = proto.plugins[ i ] || [];
+ proto.plugins[ i ].push( [ option, set[ i ] ] );
+ }
+ },
+ call: function( instance, name, args ) {
+ var i,
+ set = instance.plugins[ name ];
+ if ( !set || !instance.element[ 0 ].parentNode || instance.element[ 0 ].parentNode.nodeType === 11 ) {
+ return;
+ }
+
+ for ( i = 0; i < set.length; i++ ) {
+ if ( instance.options[ set[ i ][ 0 ] ] ) {
+ set[ i ][ 1 ].apply( instance.element, args );
+ }
+ }
+ }
+ },
+
+ // only used by resizable
+ hasScroll: function( el, a ) {
+
+ //If overflow is hidden, the element might have extra content, but the user wants to hide it
+ if ( $( el ).css( "overflow" ) === "hidden") {
+ return false;
+ }
+
+ var scroll = ( a && a === "left" ) ? "scrollLeft" : "scrollTop",
+ has = false;
+
+ if ( el[ scroll ] > 0 ) {
+ return true;
+ }
+
+ // TODO: determine which cases actually cause this to happen
+ // if the element doesn't have the scroll set, see if it's possible to
+ // set the scroll
+ el[ scroll ] = 1;
+ has = ( el[ scroll ] > 0 );
+ el[ scroll ] = 0;
+ return has;
+ }
+});
+
+})( jQuery );
diff --git a/debian/missing-sources/jquery-ui/jquery.ui.datepicker.js b/debian/missing-sources/jquery-ui/jquery.ui.datepicker.js
new file mode 100644
index 0000000..8afddbd
--- /dev/null
+++ b/debian/missing-sources/jquery-ui/jquery.ui.datepicker.js
@@ -0,0 +1,2038 @@
+/*!
+ * jQuery UI Datepicker 1.10.3
+ * http://jqueryui.com
+ *
+ * Copyright 2013 jQuery Foundation and other contributors
+ * Released under the MIT license.
+ * http://jquery.org/license
+ *
+ * http://api.jqueryui.com/datepicker/
+ *
+ * Depends:
+ * jquery.ui.core.js
+ */
+(function( $, undefined ) {
+
+$.extend($.ui, { datepicker: { version: "1.10.3" } });
+
+var PROP_NAME = "datepicker",
+ instActive;
+
+/* Date picker manager.
+ Use the singleton instance of this class, $.datepicker, to interact with the date picker.
+ Settings for (groups of) date pickers are maintained in an instance object,
+ allowing multiple different settings on the same page. */
+
+function Datepicker() {
+ this._curInst = null; // The current instance in use
+ this._keyEvent = false; // If the last event was a key event
+ this._disabledInputs = []; // List of date picker inputs that have been disabled
+ this._datepickerShowing = false; // True if the popup picker is showing , false if not
+ this._inDialog = false; // True if showing within a "dialog", false if not
+ this._mainDivId = "ui-datepicker-div"; // The ID of the main datepicker division
+ this._inlineClass = "ui-datepicker-inline"; // The name of the inline marker class
+ this._appendClass = "ui-datepicker-append"; // The name of the append marker class
+ this._triggerClass = "ui-datepicker-trigger"; // The name of the trigger marker class
+ this._dialogClass = "ui-datepicker-dialog"; // The name of the dialog marker class
+ this._disableClass = "ui-datepicker-disabled"; // The name of the disabled covering marker class
+ this._unselectableClass = "ui-datepicker-unselectable"; // The name of the unselectable cell marker class
+ this._currentClass = "ui-datepicker-current-day"; // The name of the current day marker class
+ this._dayOverClass = "ui-datepicker-days-cell-over"; // The name of the day hover marker class
+ this.regional = []; // Available regional settings, indexed by language code
+ this.regional[""] = { // Default regional settings
+ closeText: "Done", // Display text for close link
+ prevText: "Prev", // Display text for previous month link
+ nextText: "Next", // Display text for next month link
+ currentText: "Today", // Display text for current month link
+ monthNames: ["January","February","March","April","May","June",
+ "July","August","September","October","November","December"], // Names of months for drop-down and formatting
+ monthNamesShort: ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"], // For formatting
+ dayNames: ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"], // For formatting
+ dayNamesShort: ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"], // For formatting
+ dayNamesMin: ["Su","Mo","Tu","We","Th","Fr","Sa"], // Column headings for days starting at Sunday
+ weekHeader: "Wk", // Column header for week of the year
+ dateFormat: "mm/dd/yy", // See format options on parseDate
+ firstDay: 0, // The first day of the week, Sun = 0, Mon = 1, ...
+ isRTL: false, // True if right-to-left language, false if left-to-right
+ showMonthAfterYear: false, // True if the year select precedes month, false for month then year
+ yearSuffix: "" // Additional text to append to the year in the month headers
+ };
+ this._defaults = { // Global defaults for all the date picker instances
+ showOn: "focus", // "focus" for popup on focus,
+ // "button" for trigger button, or "both" for either
+ showAnim: "fadeIn", // Name of jQuery animation for popup
+ showOptions: {}, // Options for enhanced animations
+ defaultDate: null, // Used when field is blank: actual date,
+ // +/-number for offset from today, null for today
+ appendText: "", // Display text following the input box, e.g. showing the format
+ buttonText: "...", // Text for trigger button
+ buttonImage: "", // URL for trigger button image
+ buttonImageOnly: false, // True if the image appears alone, false if it appears on a button
+ hideIfNoPrevNext: false, // True to hide next/previous month links
+ // if not applicable, false to just disable them
+ navigationAsDateFormat: false, // True if date formatting applied to prev/today/next links
+ gotoCurrent: false, // True if today link goes back to current selection instead
+ changeMonth: false, // True if month can be selected directly, false if only prev/next
+ changeYear: false, // True if year can be selected directly, false if only prev/next
+ yearRange: "c-10:c+10", // Range of years to display in drop-down,
+ // either relative to today's year (-nn:+nn), relative to currently displayed year
+ // (c-nn:c+nn), absolute (nnnn:nnnn), or a combination of the above (nnnn:-n)
+ showOtherMonths: false, // True to show dates in other months, false to leave blank
+ selectOtherMonths: false, // True to allow selection of dates in other months, false for unselectable
+ showWeek: false, // True to show week of the year, false to not show it
+ calculateWeek: this.iso8601Week, // How to calculate the week of the year,
+ // takes a Date and returns the number of the week for it
+ shortYearCutoff: "+10", // Short year values < this are in the current century,
+ // > this are in the previous century,
+ // string value starting with "+" for current year + value
+ minDate: null, // The earliest selectable date, or null for no limit
+ maxDate: null, // The latest selectable date, or null for no limit
+ duration: "fast", // Duration of display/closure
+ beforeShowDay: null, // Function that takes a date and returns an array with
+ // [0] = true if selectable, false if not, [1] = custom CSS class name(s) or "",
+ // [2] = cell title (optional), e.g. $.datepicker.noWeekends
+ beforeShow: null, // Function that takes an input field and
+ // returns a set of custom settings for the date picker
+ onSelect: null, // Define a callback function when a date is selected
+ onChangeMonthYear: null, // Define a callback function when the month or year is changed
+ onClose: null, // Define a callback function when the datepicker is closed
+ numberOfMonths: 1, // Number of months to show at a time
+ showCurrentAtPos: 0, // The position in multipe months at which to show the current month (starting at 0)
+ stepMonths: 1, // Number of months to step back/forward
+ stepBigMonths: 12, // Number of months to step back/forward for the big links
+ altField: "", // Selector for an alternate field to store selected dates into
+ altFormat: "", // The date format to use for the alternate field
+ constrainInput: true, // The input is constrained by the current date format
+ showButtonPanel: false, // True to show button panel, false to not show it
+ autoSize: false, // True to size the input for the date format, false to leave as is
+ disabled: false // The initial disabled state
+ };
+ $.extend(this._defaults, this.regional[""]);
+ this.dpDiv = bindHover($("<div id='" + this._mainDivId + "' class='ui-datepicker ui-widget ui-widget-content ui-helper-clearfix ui-corner-all'></div>"));
+}
+
+$.extend(Datepicker.prototype, {
+ /* Class name added to elements to indicate already configured with a date picker. */
+ markerClassName: "hasDatepicker",
+
+ //Keep track of the maximum number of rows displayed (see #7043)
+ maxRows: 4,
+
+ // TODO rename to "widget" when switching to widget factory
+ _widgetDatepicker: function() {
+ return this.dpDiv;
+ },
+
+ /* Override the default settings for all instances of the date picker.
+ * @param settings object - the new settings to use as defaults (anonymous object)
+ * @return the manager object
+ */
+ setDefaults: function(settings) {
+ extendRemove(this._defaults, settings || {});
+ return this;
+ },
+
+ /* Attach the date picker to a jQuery selection.
+ * @param target element - the target input field or division or span
+ * @param settings object - the new settings to use for this date picker instance (anonymous)
+ */
+ _attachDatepicker: function(target, settings) {
+ var nodeName, inline, inst;
+ nodeName = target.nodeName.toLowerCase();
+ inline = (nodeName === "div" || nodeName === "span");
+ if (!target.id) {
+ this.uuid += 1;
+ target.id = "dp" + this.uuid;
+ }
+ inst = this._newInst($(target), inline);
+ inst.settings = $.extend({}, settings || {});
+ if (nodeName === "input") {
+ this._connectDatepicker(target, inst);
+ } else if (inline) {
+ this._inlineDatepicker(target, inst);
+ }
+ },
+
+ /* Create a new instance object. */
+ _newInst: function(target, inline) {
+ var id = target[0].id.replace(/([^A-Za-z0-9_\-])/g, "\\\\$1"); // escape jQuery meta chars
+ return {id: id, input: target, // associated target
+ selectedDay: 0, selectedMonth: 0, selectedYear: 0, // current selection
+ drawMonth: 0, drawYear: 0, // month being drawn
+ inline: inline, // is datepicker inline or not
+ dpDiv: (!inline ? this.dpDiv : // presentation div
+ bindHover($("<div class='" + this._inlineClass + " ui-datepicker ui-widget ui-widget-content ui-helper-clearfix ui-corner-all'></div>")))};
+ },
+
+ /* Attach the date picker to an input field. */
+ _connectDatepicker: function(target, inst) {
+ var input = $(target);
+ inst.append = $([]);
+ inst.trigger = $([]);
+ if (input.hasClass(this.markerClassName)) {
+ return;
+ }
+ this._attachments(input, inst);
+ input.addClass(this.markerClassName).keydown(this._doKeyDown).
+ keypress(this._doKeyPress).keyup(this._doKeyUp);
+ this._autoSize(inst);
+ $.data(target, PROP_NAME, inst);
+ //If disabled option is true, disable the datepicker once it has been attached to the input (see ticket #5665)
+ if( inst.settings.disabled ) {
+ this._disableDatepicker( target );
+ }
+ },
+
+ /* Make attachments based on settings. */
+ _attachments: function(input, inst) {
+ var showOn, buttonText, buttonImage,
+ appendText = this._get(inst, "appendText"),
+ isRTL = this._get(inst, "isRTL");
+
+ if (inst.append) {
+ inst.append.remove();
+ }
+ if (appendText) {
+ inst.append = $("<span class='" + this._appendClass + "'>" + appendText + "</span>");
+ input[isRTL ? "before" : "after"](inst.append);
+ }
+
+ input.unbind("focus", this._showDatepicker);
+
+ if (inst.trigger) {
+ inst.trigger.remove();
+ }
+
+ showOn = this._get(inst, "showOn");
+ if (showOn === "focus" || showOn === "both") { // pop-up date picker when in the marked field
+ input.focus(this._showDatepicker);
+ }
+ if (showOn === "button" || showOn === "both") { // pop-up date picker when button clicked
+ buttonText = this._get(inst, "buttonText");
+ buttonImage = this._get(inst, "buttonImage");
+ inst.trigger = $(this._get(inst, "buttonImageOnly") ?
+ $("<img/>").addClass(this._triggerClass).
+ attr({ src: buttonImage, alt: buttonText, title: buttonText }) :
+ $("<button type='button'></button>").addClass(this._triggerClass).
+ html(!buttonImage ? buttonText : $("<img/>").attr(
+ { src:buttonImage, alt:buttonText, title:buttonText })));
+ input[isRTL ? "before" : "after"](inst.trigger);
+ inst.trigger.click(function() {
+ if ($.datepicker._datepickerShowing && $.datepicker._lastInput === input[0]) {
+ $.datepicker._hideDatepicker();
+ } else if ($.datepicker._datepickerShowing && $.datepicker._lastInput !== input[0]) {
+ $.datepicker._hideDatepicker();
+ $.datepicker._showDatepicker(input[0]);
+ } else {
+ $.datepicker._showDatepicker(input[0]);
+ }
+ return false;
+ });
+ }
+ },
+
+ /* Apply the maximum length for the date format. */
+ _autoSize: function(inst) {
+ if (this._get(inst, "autoSize") && !inst.inline) {
+ var findMax, max, maxI, i,
+ date = new Date(2009, 12 - 1, 20), // Ensure double digits
+ dateFormat = this._get(inst, "dateFormat");
+
+ if (dateFormat.match(/[DM]/)) {
+ findMax = function(names) {
+ max = 0;
+ maxI = 0;
+ for (i = 0; i < names.length; i++) {
+ if (names[i].length > max) {
+ max = names[i].length;
+ maxI = i;
+ }
+ }
+ return maxI;
+ };
+ date.setMonth(findMax(this._get(inst, (dateFormat.match(/MM/) ?
+ "monthNames" : "monthNamesShort"))));
+ date.setDate(findMax(this._get(inst, (dateFormat.match(/DD/) ?
+ "dayNames" : "dayNamesShort"))) + 20 - date.getDay());
+ }
+ inst.input.attr("size", this._formatDate(inst, date).length);
+ }
+ },
+
+ /* Attach an inline date picker to a div. */
+ _inlineDatepicker: function(target, inst) {
+ var divSpan = $(target);
+ if (divSpan.hasClass(this.markerClassName)) {
+ return;
+ }
+ divSpan.addClass(this.markerClassName).append(inst.dpDiv);
+ $.data(target, PROP_NAME, inst);
+ this._setDate(inst, this._getDefaultDate(inst), true);
+ this._updateDatepicker(inst);
+ this._updateAlternate(inst);
+ //If disabled option is true, disable the datepicker before showing it (see ticket #5665)
+ if( inst.settings.disabled ) {
+ this._disableDatepicker( target );
+ }
+ // Set display:block in place of inst.dpDiv.show() which won't work on disconnected elements
+ // http://bugs.jqueryui.com/ticket/7552 - A Datepicker created on a detached div has zero height
+ inst.dpDiv.css( "display", "block" );
+ },
+
+ /* Pop-up the date picker in a "dialog" box.
+ * @param input element - ignored
+ * @param date string or Date - the initial date to display
+ * @param onSelect function - the function to call when a date is selected
+ * @param settings object - update the dialog date picker instance's settings (anonymous object)
+ * @param pos int[2] - coordinates for the dialog's position within the screen or
+ * event - with x/y coordinates or
+ * leave empty for default (screen centre)
+ * @return the manager object
+ */
+ _dialogDatepicker: function(input, date, onSelect, settings, pos) {
+ var id, browserWidth, browserHeight, scrollX, scrollY,
+ inst = this._dialogInst; // internal instance
+
+ if (!inst) {
+ this.uuid += 1;
+ id = "dp" + this.uuid;
+ this._dialogInput = $("<input type='text' id='" + id +
+ "' style='position: absolute; top: -100px; width: 0px;'/>");
+ this._dialogInput.keydown(this._doKeyDown);
+ $("body").append(this._dialogInput);
+ inst = this._dialogInst = this._newInst(this._dialogInput, false);
+ inst.settings = {};
+ $.data(this._dialogInput[0], PROP_NAME, inst);
+ }
+ extendRemove(inst.settings, settings || {});
+ date = (date && date.constructor === Date ? this._formatDate(inst, date) : date);
+ this._dialogInput.val(date);
+
+ this._pos = (pos ? (pos.length ? pos : [pos.pageX, pos.pageY]) : null);
+ if (!this._pos) {
+ browserWidth = document.documentElement.clientWidth;
+ browserHeight = document.documentElement.clientHeight;
+ scrollX = document.documentElement.scrollLeft || document.body.scrollLeft;
+ scrollY = document.documentElement.scrollTop || document.body.scrollTop;
+ this._pos = // should use actual width/height below
+ [(browserWidth / 2) - 100 + scrollX, (browserHeight / 2) - 150 + scrollY];
+ }
+
+ // move input on screen for focus, but hidden behind dialog
+ this._dialogInput.css("left", (this._pos[0] + 20) + "px").css("top", this._pos[1] + "px");
+ inst.settings.onSelect = onSelect;
+ this._inDialog = true;
+ this.dpDiv.addClass(this._dialogClass);
+ this._showDatepicker(this._dialogInput[0]);
+ if ($.blockUI) {
+ $.blockUI(this.dpDiv);
+ }
+ $.data(this._dialogInput[0], PROP_NAME, inst);
+ return this;
+ },
+
+ /* Detach a datepicker from its control.
+ * @param target element - the target input field or division or span
+ */
+ _destroyDatepicker: function(target) {
+ var nodeName,
+ $target = $(target),
+ inst = $.data(target, PROP_NAME);
+
+ if (!$target.hasClass(this.markerClassName)) {
+ return;
+ }
+
+ nodeName = target.nodeName.toLowerCase();
+ $.removeData(target, PROP_NAME);
+ if (nodeName === "input") {
+ inst.append.remove();
+ inst.trigger.remove();
+ $target.removeClass(this.markerClassName).
+ unbind("focus", this._showDatepicker).
+ unbind("keydown", this._doKeyDown).
+ unbind("keypress", this._doKeyPress).
+ unbind("keyup", this._doKeyUp);
+ } else if (nodeName === "div" || nodeName === "span") {
+ $target.removeClass(this.markerClassName).empty();
+ }
+ },
+
+ /* Enable the date picker to a jQuery selection.
+ * @param target element - the target input field or division or span
+ */
+ _enableDatepicker: function(target) {
+ var nodeName, inline,
+ $target = $(target),
+ inst = $.data(target, PROP_NAME);
+
+ if (!$target.hasClass(this.markerClassName)) {
+ return;
+ }
+
+ nodeName = target.nodeName.toLowerCase();
+ if (nodeName === "input") {
+ target.disabled = false;
+ inst.trigger.filter("button").
+ each(function() { this.disabled = false; }).end().
+ filter("img").css({opacity: "1.0", cursor: ""});
+ } else if (nodeName === "div" || nodeName === "span") {
+ inline = $target.children("." + this._inlineClass);
+ inline.children().removeClass("ui-state-disabled");
+ inline.find("select.ui-datepicker-month, select.ui-datepicker-year").
+ prop("disabled", false);
+ }
+ this._disabledInputs = $.map(this._disabledInputs,
+ function(value) { return (value === target ? null : value); }); // delete entry
+ },
+
+ /* Disable the date picker to a jQuery selection.
+ * @param target element - the target input field or division or span
+ */
+ _disableDatepicker: function(target) {
+ var nodeName, inline,
+ $target = $(target),
+ inst = $.data(target, PROP_NAME);
+
+ if (!$target.hasClass(this.markerClassName)) {
+ return;
+ }
+
+ nodeName = target.nodeName.toLowerCase();
+ if (nodeName === "input") {
+ target.disabled = true;
+ inst.trigger.filter("button").
+ each(function() { this.disabled = true; }).end().
+ filter("img").css({opacity: "0.5", cursor: "default"});
+ } else if (nodeName === "div" || nodeName === "span") {
+ inline = $target.children("." + this._inlineClass);
+ inline.children().addClass("ui-state-disabled");
+ inline.find("select.ui-datepicker-month, select.ui-datepicker-year").
+ prop("disabled", true);
+ }
+ this._disabledInputs = $.map(this._disabledInputs,
+ function(value) { return (value === target ? null : value); }); // delete entry
+ this._disabledInputs[this._disabledInputs.length] = target;
+ },
+
+ /* Is the first field in a jQuery collection disabled as a datepicker?
+ * @param target element - the target input field or division or span
+ * @return boolean - true if disabled, false if enabled
+ */
+ _isDisabledDatepicker: function(target) {
+ if (!target) {
+ return false;
+ }
+ for (var i = 0; i < this._disabledInputs.length; i++) {
+ if (this._disabledInputs[i] === target) {
+ return true;
+ }
+ }
+ return false;
+ },
+
+ /* Retrieve the instance data for the target control.
+ * @param target element - the target input field or division or span
+ * @return object - the associated instance data
+ * @throws error if a jQuery problem getting data
+ */
+ _getInst: function(target) {
+ try {
+ return $.data(target, PROP_NAME);
+ }
+ catch (err) {
+ throw "Missing instance data for this datepicker";
+ }
+ },
+
+ /* Update or retrieve the settings for a date picker attached to an input field or division.
+ * @param target element - the target input field or division or span
+ * @param name object - the new settings to update or
+ * string - the name of the setting to change or retrieve,
+ * when retrieving also "all" for all instance settings or
+ * "defaults" for all global defaults
+ * @param value any - the new value for the setting
+ * (omit if above is an object or to retrieve a value)
+ */
+ _optionDatepicker: function(target, name, value) {
+ var settings, date, minDate, maxDate,
+ inst = this._getInst(target);
+
+ if (arguments.length === 2 && typeof name === "string") {
+ return (name === "defaults" ? $.extend({}, $.datepicker._defaults) :
+ (inst ? (name === "all" ? $.extend({}, inst.settings) :
+ this._get(inst, name)) : null));
+ }
+
+ settings = name || {};
+ if (typeof name === "string") {
+ settings = {};
+ settings[name] = value;
+ }
+
+ if (inst) {
+ if (this._curInst === inst) {
+ this._hideDatepicker();
+ }
+
+ date = this._getDateDatepicker(target, true);
+ minDate = this._getMinMaxDate(inst, "min");
+ maxDate = this._getMinMaxDate(inst, "max");
+ extendRemove(inst.settings, settings);
+ // reformat the old minDate/maxDate values if dateFormat changes and a new minDate/maxDate isn't provided
+ if (minDate !== null && settings.dateFormat !== undefined && settings.minDate === undefined) {
+ inst.settings.minDate = this._formatDate(inst, minDate);
+ }
+ if (maxDate !== null && settings.dateFormat !== undefined && settings.maxDate === undefined) {
+ inst.settings.maxDate = this._formatDate(inst, maxDate);
+ }
+ if ( "disabled" in settings ) {
+ if ( settings.disabled ) {
+ this._disableDatepicker(target);
+ } else {
+ this._enableDatepicker(target);
+ }
+ }
+ this._attachments($(target), inst);
+ this._autoSize(inst);
+ this._setDate(inst, date);
+ this._updateAlternate(inst);
+ this._updateDatepicker(inst);
+ }
+ },
+
+ // change method deprecated
+ _changeDatepicker: function(target, name, value) {
+ this._optionDatepicker(target, name, value);
+ },
+
+ /* Redraw the date picker attached to an input field or division.
+ * @param target element - the target input field or division or span
+ */
+ _refreshDatepicker: function(target) {
+ var inst = this._getInst(target);
+ if (inst) {
+ this._updateDatepicker(inst);
+ }
+ },
+
+ /* Set the dates for a jQuery selection.
+ * @param target element - the target input field or division or span
+ * @param date Date - the new date
+ */
+ _setDateDatepicker: function(target, date) {
+ var inst = this._getInst(target);
+ if (inst) {
+ this._setDate(inst, date);
+ this._updateDatepicker(inst);
+ this._updateAlternate(inst);
+ }
+ },
+
+ /* Get the date(s) for the first entry in a jQuery selection.
+ * @param target element - the target input field or division or span
+ * @param noDefault boolean - true if no default date is to be used
+ * @return Date - the current date
+ */
+ _getDateDatepicker: function(target, noDefault) {
+ var inst = this._getInst(target);
+ if (inst && !inst.inline) {
+ this._setDateFromField(inst, noDefault);
+ }
+ return (inst ? this._getDate(inst) : null);
+ },
+
+ /* Handle keystrokes. */
+ _doKeyDown: function(event) {
+ var onSelect, dateStr, sel,
+ inst = $.datepicker._getInst(event.target),
+ handled = true,
+ isRTL = inst.dpDiv.is(".ui-datepicker-rtl");
+
+ inst._keyEvent = true;
+ if ($.datepicker._datepickerShowing) {
+ switch (event.keyCode) {
+ case 9: $.datepicker._hideDatepicker();
+ handled = false;
+ break; // hide on tab out
+ case 13: sel = $("td." + $.datepicker._dayOverClass + ":not(." +
+ $.datepicker._currentClass + ")", inst.dpDiv);
+ if (sel[0]) {
+ $.datepicker._selectDay(event.target, inst.selectedMonth, inst.selectedYear, sel[0]);
+ }
+
+ onSelect = $.datepicker._get(inst, "onSelect");
+ if (onSelect) {
+ dateStr = $.datepicker._formatDate(inst);
+
+ // trigger custom callback
+ onSelect.apply((inst.input ? inst.input[0] : null), [dateStr, inst]);
+ } else {
+ $.datepicker._hideDatepicker();
+ }
+
+ return false; // don't submit the form
+ case 27: $.datepicker._hideDatepicker();
+ break; // hide on escape
+ case 33: $.datepicker._adjustDate(event.target, (event.ctrlKey ?
+ -$.datepicker._get(inst, "stepBigMonths") :
+ -$.datepicker._get(inst, "stepMonths")), "M");
+ break; // previous month/year on page up/+ ctrl
+ case 34: $.datepicker._adjustDate(event.target, (event.ctrlKey ?
+ +$.datepicker._get(inst, "stepBigMonths") :
+ +$.datepicker._get(inst, "stepMonths")), "M");
+ break; // next month/year on page down/+ ctrl
+ case 35: if (event.ctrlKey || event.metaKey) {
+ $.datepicker._clearDate(event.target);
+ }
+ handled = event.ctrlKey || event.metaKey;
+ break; // clear on ctrl or command +end
+ case 36: if (event.ctrlKey || event.metaKey) {
+ $.datepicker._gotoToday(event.target);
+ }
+ handled = event.ctrlKey || event.metaKey;
+ break; // current on ctrl or command +home
+ case 37: if (event.ctrlKey || event.metaKey) {
+ $.datepicker._adjustDate(event.target, (isRTL ? +1 : -1), "D");
+ }
+ handled = event.ctrlKey || event.metaKey;
+ // -1 day on ctrl or command +left
+ if (event.originalEvent.altKey) {
+ $.datepicker._adjustDate(event.target, (event.ctrlKey ?
+ -$.datepicker._get(inst, "stepBigMonths") :
+ -$.datepicker._get(inst, "stepMonths")), "M");
+ }
+ // next month/year on alt +left on Mac
+ break;
+ case 38: if (event.ctrlKey || event.metaKey) {
+ $.datepicker._adjustDate(event.target, -7, "D");
+ }
+ handled = event.ctrlKey || event.metaKey;
+ break; // -1 week on ctrl or command +up
+ case 39: if (event.ctrlKey || event.metaKey) {
+ $.datepicker._adjustDate(event.target, (isRTL ? -1 : +1), "D");
+ }
+ handled = event.ctrlKey || event.metaKey;
+ // +1 day on ctrl or command +right
+ if (event.originalEvent.altKey) {
+ $.datepicker._adjustDate(event.target, (event.ctrlKey ?
+ +$.datepicker._get(inst, "stepBigMonths") :
+ +$.datepicker._get(inst, "stepMonths")), "M");
+ }
+ // next month/year on alt +right
+ break;
+ case 40: if (event.ctrlKey || event.metaKey) {
+ $.datepicker._adjustDate(event.target, +7, "D");
+ }
+ handled = event.ctrlKey || event.metaKey;
+ break; // +1 week on ctrl or command +down
+ default: handled = false;
+ }
+ } else if (event.keyCode === 36 && event.ctrlKey) { // display the date picker on ctrl+home
+ $.datepicker._showDatepicker(this);
+ } else {
+ handled = false;
+ }
+
+ if (handled) {
+ event.preventDefault();
+ event.stopPropagation();
+ }
+ },
+
+ /* Filter entered characters - based on date format. */
+ _doKeyPress: function(event) {
+ var chars, chr,
+ inst = $.datepicker._getInst(event.target);
+
+ if ($.datepicker._get(inst, "constrainInput")) {
+ chars = $.datepicker._possibleChars($.datepicker._get(inst, "dateFormat"));
+ chr = String.fromCharCode(event.charCode == null ? event.keyCode : event.charCode);
+ return event.ctrlKey || event.metaKey || (chr < " " || !chars || chars.indexOf(chr) > -1);
+ }
+ },
+
+ /* Synchronise manual entry and field/alternate field. */
+ _doKeyUp: function(event) {
+ var date,
+ inst = $.datepicker._getInst(event.target);
+
+ if (inst.input.val() !== inst.lastVal) {
+ try {
+ date = $.datepicker.parseDate($.datepicker._get(inst, "dateFormat"),
+ (inst.input ? inst.input.val() : null),
+ $.datepicker._getFormatConfig(inst));
+
+ if (date) { // only if valid
+ $.datepicker._setDateFromField(inst);
+ $.datepicker._updateAlternate(inst);
+ $.datepicker._updateDatepicker(inst);
+ }
+ }
+ catch (err) {
+ }
+ }
+ return true;
+ },
+
+ /* Pop-up the date picker for a given input field.
+ * If false returned from beforeShow event handler do not show.
+ * @param input element - the input field attached to the date picker or
+ * event - if triggered by focus
+ */
+ _showDatepicker: function(input) {
+ input = input.target || input;
+ if (input.nodeName.toLowerCase() !== "input") { // find from button/image trigger
+ input = $("input", input.parentNode)[0];
+ }
+
+ if ($.datepicker._isDisabledDatepicker(input) || $.datepicker._lastInput === input) { // already here
+ return;
+ }
+
+ var inst, beforeShow, beforeShowSettings, isFixed,
+ offset, showAnim, duration;
+
+ inst = $.datepicker._getInst(input);
+ if ($.datepicker._curInst && $.datepicker._curInst !== inst) {
+ $.datepicker._curInst.dpDiv.stop(true, true);
+ if ( inst && $.datepicker._datepickerShowing ) {
+ $.datepicker._hideDatepicker( $.datepicker._curInst.input[0] );
+ }
+ }
+
+ beforeShow = $.datepicker._get(inst, "beforeShow");
+ beforeShowSettings = beforeShow ? beforeShow.apply(input, [input, inst]) : {};
+ if(beforeShowSettings === false){
+ return;
+ }
+ extendRemove(inst.settings, beforeShowSettings);
+
+ inst.lastVal = null;
+ $.datepicker._lastInput = input;
+ $.datepicker._setDateFromField(inst);
+
+ if ($.datepicker._inDialog) { // hide cursor
+ input.value = "";
+ }
+ if (!$.datepicker._pos) { // position below input
+ $.datepicker._pos = $.datepicker._findPos(input);
+ $.datepicker._pos[1] += input.offsetHeight; // add the height
+ }
+
+ isFixed = false;
+ $(input).parents().each(function() {
+ isFixed |= $(this).css("position") === "fixed";
+ return !isFixed;
+ });
+
+ offset = {left: $.datepicker._pos[0], top: $.datepicker._pos[1]};
+ $.datepicker._pos = null;
+ //to avoid flashes on Firefox
+ inst.dpDiv.empty();
+ // determine sizing offscreen
+ inst.dpDiv.css({position: "absolute", display: "block", top: "-1000px"});
+ $.datepicker._updateDatepicker(inst);
+ // fix width for dynamic number of date pickers
+ // and adjust position before showing
+ offset = $.datepicker._checkOffset(inst, offset, isFixed);
+ inst.dpDiv.css({position: ($.datepicker._inDialog && $.blockUI ?
+ "static" : (isFixed ? "fixed" : "absolute")), display: "none",
+ left: offset.left + "px", top: offset.top + "px"});
+
+ if (!inst.inline) {
+ showAnim = $.datepicker._get(inst, "showAnim");
+ duration = $.datepicker._get(inst, "duration");
+ inst.dpDiv.zIndex($(input).zIndex()+1);
+ $.datepicker._datepickerShowing = true;
+
+ if ( $.effects && $.effects.effect[ showAnim ] ) {
+ inst.dpDiv.show(showAnim, $.datepicker._get(inst, "showOptions"), duration);
+ } else {
+ inst.dpDiv[showAnim || "show"](showAnim ? duration : null);
+ }
+
+ if ( $.datepicker._shouldFocusInput( inst ) ) {
+ inst.input.focus();
+ }
+
+ $.datepicker._curInst = inst;
+ }
+ },
+
+ /* Generate the date picker content. */
+ _updateDatepicker: function(inst) {
+ this.maxRows = 4; //Reset the max number of rows being displayed (see #7043)
+ instActive = inst; // for delegate hover events
+ inst.dpDiv.empty().append(this._generateHTML(inst));
+ this._attachHandlers(inst);
+ inst.dpDiv.find("." + this._dayOverClass + " a").mouseover();
+
+ var origyearshtml,
+ numMonths = this._getNumberOfMonths(inst),
+ cols = numMonths[1],
+ width = 17;
+
+ inst.dpDiv.removeClass("ui-datepicker-multi-2 ui-datepicker-multi-3 ui-datepicker-multi-4").width("");
+ if (cols > 1) {
+ inst.dpDiv.addClass("ui-datepicker-multi-" + cols).css("width", (width * cols) + "em");
+ }
+ inst.dpDiv[(numMonths[0] !== 1 || numMonths[1] !== 1 ? "add" : "remove") +
+ "Class"]("ui-datepicker-multi");
+ inst.dpDiv[(this._get(inst, "isRTL") ? "add" : "remove") +
+ "Class"]("ui-datepicker-rtl");
+
+ if (inst === $.datepicker._curInst && $.datepicker._datepickerShowing && $.datepicker._shouldFocusInput( inst ) ) {
+ inst.input.focus();
+ }
+
+ // deffered render of the years select (to avoid flashes on Firefox)
+ if( inst.yearshtml ){
+ origyearshtml = inst.yearshtml;
+ setTimeout(function(){
+ //assure that inst.yearshtml didn't change.
+ if( origyearshtml === inst.yearshtml && inst.yearshtml ){
+ inst.dpDiv.find("select.ui-datepicker-year:first").replaceWith(inst.yearshtml);
+ }
+ origyearshtml = inst.yearshtml = null;
+ }, 0);
+ }
+ },
+
+ // #6694 - don't focus the input if it's already focused
+ // this breaks the change event in IE
+ // Support: IE and jQuery <1.9
+ _shouldFocusInput: function( inst ) {
+ return inst.input && inst.input.is( ":visible" ) && !inst.input.is( ":disabled" ) && !inst.input.is( ":focus" );
+ },
+
+ /* Check positioning to remain on screen. */
+ _checkOffset: function(inst, offset, isFixed) {
+ var dpWidth = inst.dpDiv.outerWidth(),
+ dpHeight = inst.dpDiv.outerHeight(),
+ inputWidth = inst.input ? inst.input.outerWidth() : 0,
+ inputHeight = inst.input ? inst.input.outerHeight() : 0,
+ viewWidth = document.documentElement.clientWidth + (isFixed ? 0 : $(document).scrollLeft()),
+ viewHeight = document.documentElement.clientHeight + (isFixed ? 0 : $(document).scrollTop());
+
+ offset.left -= (this._get(inst, "isRTL") ? (dpWidth - inputWidth) : 0);
+ offset.left -= (isFixed && offset.left === inst.input.offset().left) ? $(document).scrollLeft() : 0;
+ offset.top -= (isFixed && offset.top === (inst.input.offset().top + inputHeight)) ? $(document).scrollTop() : 0;
+
+ // now check if datepicker is showing outside window viewport - move to a better place if so.
+ offset.left -= Math.min(offset.left, (offset.left + dpWidth > viewWidth && viewWidth > dpWidth) ?
+ Math.abs(offset.left + dpWidth - viewWidth) : 0);
+ offset.top -= Math.min(offset.top, (offset.top + dpHeight > viewHeight && viewHeight > dpHeight) ?
+ Math.abs(dpHeight + inputHeight) : 0);
+
+ return offset;
+ },
+
+ /* Find an object's position on the screen. */
+ _findPos: function(obj) {
+ var position,
+ inst = this._getInst(obj),
+ isRTL = this._get(inst, "isRTL");
+
+ while (obj && (obj.type === "hidden" || obj.nodeType !== 1 || $.expr.filters.hidden(obj))) {
+ obj = obj[isRTL ? "previousSibling" : "nextSibling"];
+ }
+
+ position = $(obj).offset();
+ return [position.left, position.top];
+ },
+
+ /* Hide the date picker from view.
+ * @param input element - the input field attached to the date picker
+ */
+ _hideDatepicker: function(input) {
+ var showAnim, duration, postProcess, onClose,
+ inst = this._curInst;
+
+ if (!inst || (input && inst !== $.data(input, PROP_NAME))) {
+ return;
+ }
+
+ if (this._datepickerShowing) {
+ showAnim = this._get(inst, "showAnim");
+ duration = this._get(inst, "duration");
+ postProcess = function() {
+ $.datepicker._tidyDialog(inst);
+ };
+
+ // DEPRECATED: after BC for 1.8.x $.effects[ showAnim ] is not needed
+ if ( $.effects && ( $.effects.effect[ showAnim ] || $.effects[ showAnim ] ) ) {
+ inst.dpDiv.hide(showAnim, $.datepicker._get(inst, "showOptions"), duration, postProcess);
+ } else {
+ inst.dpDiv[(showAnim === "slideDown" ? "slideUp" :
+ (showAnim === "fadeIn" ? "fadeOut" : "hide"))]((showAnim ? duration : null), postProcess);
+ }
+
+ if (!showAnim) {
+ postProcess();
+ }
+ this._datepickerShowing = false;
+
+ onClose = this._get(inst, "onClose");
+ if (onClose) {
+ onClose.apply((inst.input ? inst.input[0] : null), [(inst.input ? inst.input.val() : ""), inst]);
+ }
+
+ this._lastInput = null;
+ if (this._inDialog) {
+ this._dialogInput.css({ position: "absolute", left: "0", top: "-100px" });
+ if ($.blockUI) {
+ $.unblockUI();
+ $("body").append(this.dpDiv);
+ }
+ }
+ this._inDialog = false;
+ }
+ },
+
+ /* Tidy up after a dialog display. */
+ _tidyDialog: function(inst) {
+ inst.dpDiv.removeClass(this._dialogClass).unbind(".ui-datepicker-calendar");
+ },
+
+ /* Close date picker if clicked elsewhere. */
+ _checkExternalClick: function(event) {
+ if (!$.datepicker._curInst) {
+ return;
+ }
+
+ var $target = $(event.target),
+ inst = $.datepicker._getInst($target[0]);
+
+ if ( ( ( $target[0].id !== $.datepicker._mainDivId &&
+ $target.parents("#" + $.datepicker._mainDivId).length === 0 &&
+ !$target.hasClass($.datepicker.markerClassName) &&
+ !$target.closest("." + $.datepicker._triggerClass).length &&
+ $.datepicker._datepickerShowing && !($.datepicker._inDialog && $.blockUI) ) ) ||
+ ( $target.hasClass($.datepicker.markerClassName) && $.datepicker._curInst !== inst ) ) {
+ $.datepicker._hideDatepicker();
+ }
+ },
+
+ /* Adjust one of the date sub-fields. */
+ _adjustDate: function(id, offset, period) {
+ var target = $(id),
+ inst = this._getInst(target[0]);
+
+ if (this._isDisabledDatepicker(target[0])) {
+ return;
+ }
+ this._adjustInstDate(inst, offset +
+ (period === "M" ? this._get(inst, "showCurrentAtPos") : 0), // undo positioning
+ period);
+ this._updateDatepicker(inst);
+ },
+
+ /* Action for current link. */
+ _gotoToday: function(id) {
+ var date,
+ target = $(id),
+ inst = this._getInst(target[0]);
+
+ if (this._get(inst, "gotoCurrent") && inst.currentDay) {
+ inst.selectedDay = inst.currentDay;
+ inst.drawMonth = inst.selectedMonth = inst.currentMonth;
+ inst.drawYear = inst.selectedYear = inst.currentYear;
+ } else {
+ date = new Date();
+ inst.selectedDay = date.getDate();
+ inst.drawMonth = inst.selectedMonth = date.getMonth();
+ inst.drawYear = inst.selectedYear = date.getFullYear();
+ }
+ this._notifyChange(inst);
+ this._adjustDate(target);
+ },
+
+ /* Action for selecting a new month/year. */
+ _selectMonthYear: function(id, select, period) {
+ var target = $(id),
+ inst = this._getInst(target[0]);
+
+ inst["selected" + (period === "M" ? "Month" : "Year")] =
+ inst["draw" + (period === "M" ? "Month" : "Year")] =
+ parseInt(select.options[select.selectedIndex].value,10);
+
+ this._notifyChange(inst);
+ this._adjustDate(target);
+ },
+
+ /* Action for selecting a day. */
+ _selectDay: function(id, month, year, td) {
+ var inst,
+ target = $(id);
+
+ if ($(td).hasClass(this._unselectableClass) || this._isDisabledDatepicker(target[0])) {
+ return;
+ }
+
+ inst = this._getInst(target[0]);
+ inst.selectedDay = inst.currentDay = $("a", td).html();
+ inst.selectedMonth = inst.currentMonth = month;
+ inst.selectedYear = inst.currentYear = year;
+ this._selectDate(id, this._formatDate(inst,
+ inst.currentDay, inst.currentMonth, inst.currentYear));
+ },
+
+ /* Erase the input field and hide the date picker. */
+ _clearDate: function(id) {
+ var target = $(id);
+ this._selectDate(target, "");
+ },
+
+ /* Update the input field with the selected date. */
+ _selectDate: function(id, dateStr) {
+ var onSelect,
+ target = $(id),
+ inst = this._getInst(target[0]);
+
+ dateStr = (dateStr != null ? dateStr : this._formatDate(inst));
+ if (inst.input) {
+ inst.input.val(dateStr);
+ }
+ this._updateAlternate(inst);
+
+ onSelect = this._get(inst, "onSelect");
+ if (onSelect) {
+ onSelect.apply((inst.input ? inst.input[0] : null), [dateStr, inst]); // trigger custom callback
+ } else if (inst.input) {
+ inst.input.trigger("change"); // fire the change event
+ }
+
+ if (inst.inline){
+ this._updateDatepicker(inst);
+ } else {
+ this._hideDatepicker();
+ this._lastInput = inst.input[0];
+ if (typeof(inst.input[0]) !== "object") {
+ inst.input.focus(); // restore focus
+ }
+ this._lastInput = null;
+ }
+ },
+
+ /* Update any alternate field to synchronise with the main field. */
+ _updateAlternate: function(inst) {
+ var altFormat, date, dateStr,
+ altField = this._get(inst, "altField");
+
+ if (altField) { // update alternate field too
+ altFormat = this._get(inst, "altFormat") || this._get(inst, "dateFormat");
+ date = this._getDate(inst);
+ dateStr = this.formatDate(altFormat, date, this._getFormatConfig(inst));
+ $(altField).each(function() { $(this).val(dateStr); });
+ }
+ },
+
+ /* Set as beforeShowDay function to prevent selection of weekends.
+ * @param date Date - the date to customise
+ * @return [boolean, string] - is this date selectable?, what is its CSS class?
+ */
+ noWeekends: function(date) {
+ var day = date.getDay();
+ return [(day > 0 && day < 6), ""];
+ },
+
+ /* Set as calculateWeek to determine the week of the year based on the ISO 8601 definition.
+ * @param date Date - the date to get the week for
+ * @return number - the number of the week within the year that contains this date
+ */
+ iso8601Week: function(date) {
+ var time,
+ checkDate = new Date(date.getTime());
+
+ // Find Thursday of this week starting on Monday
+ checkDate.setDate(checkDate.getDate() + 4 - (checkDate.getDay() || 7));
+
+ time = checkDate.getTime();
+ checkDate.setMonth(0); // Compare with Jan 1
+ checkDate.setDate(1);
+ return Math.floor(Math.round((time - checkDate) / 86400000) / 7) + 1;
+ },
+
+ /* Parse a string value into a date object.
+ * See formatDate below for the possible formats.
+ *
+ * @param format string - the expected format of the date
+ * @param value string - the date in the above format
+ * @param settings Object - attributes include:
+ * shortYearCutoff number - the cutoff year for determining the century (optional)
+ * dayNamesShort string[7] - abbreviated names of the days from Sunday (optional)
+ * dayNames string[7] - names of the days from Sunday (optional)
+ * monthNamesShort string[12] - abbreviated names of the months (optional)
+ * monthNames string[12] - names of the months (optional)
+ * @return Date - the extracted date value or null if value is blank
+ */
+ parseDate: function (format, value, settings) {
+ if (format == null || value == null) {
+ throw "Invalid arguments";
+ }
+
+ value = (typeof value === "object" ? value.toString() : value + "");
+ if (value === "") {
+ return null;
+ }
+
+ var iFormat, dim, extra,
+ iValue = 0,
+ shortYearCutoffTemp = (settings ? settings.shortYearCutoff : null) || this._defaults.shortYearCutoff,
+ shortYearCutoff = (typeof shortYearCutoffTemp !== "string" ? shortYearCutoffTemp :
+ new Date().getFullYear() % 100 + parseInt(shortYearCutoffTemp, 10)),
+ dayNamesShort = (settings ? settings.dayNamesShort : null) || this._defaults.dayNamesShort,
+ dayNames = (settings ? settings.dayNames : null) || this._defaults.dayNames,
+ monthNamesShort = (settings ? settings.monthNamesShort : null) || this._defaults.monthNamesShort,
+ monthNames = (settings ? settings.monthNames : null) || this._defaults.monthNames,
+ year = -1,
+ month = -1,
+ day = -1,
+ doy = -1,
+ literal = false,
+ date,
+ // Check whether a format character is doubled
+ lookAhead = function(match) {
+ var matches = (iFormat + 1 < format.length && format.charAt(iFormat + 1) === match);
+ if (matches) {
+ iFormat++;
+ }
+ return matches;
+ },
+ // Extract a number from the string value
+ getNumber = function(match) {
+ var isDoubled = lookAhead(match),
+ size = (match === "@" ? 14 : (match === "!" ? 20 :
+ (match === "y" && isDoubled ? 4 : (match === "o" ? 3 : 2)))),
+ digits = new RegExp("^\\d{1," + size + "}"),
+ num = value.substring(iValue).match(digits);
+ if (!num) {
+ throw "Missing number at position " + iValue;
+ }
+ iValue += num[0].length;
+ return parseInt(num[0], 10);
+ },
+ // Extract a name from the string value and convert to an index
+ getName = function(match, shortNames, longNames) {
+ var index = -1,
+ names = $.map(lookAhead(match) ? longNames : shortNames, function (v, k) {
+ return [ [k, v] ];
+ }).sort(function (a, b) {
+ return -(a[1].length - b[1].length);
+ });
+
+ $.each(names, function (i, pair) {
+ var name = pair[1];
+ if (value.substr(iValue, name.length).toLowerCase() === name.toLowerCase()) {
+ index = pair[0];
+ iValue += name.length;
+ return false;
+ }
+ });
+ if (index !== -1) {
+ return index + 1;
+ } else {
+ throw "Unknown name at position " + iValue;
+ }
+ },
+ // Confirm that a literal character matches the string value
+ checkLiteral = function() {
+ if (value.charAt(iValue) !== format.charAt(iFormat)) {
+ throw "Unexpected literal at position " + iValue;
+ }
+ iValue++;
+ };
+
+ for (iFormat = 0; iFormat < format.length; iFormat++) {
+ if (literal) {
+ if (format.charAt(iFormat) === "'" && !lookAhead("'")) {
+ literal = false;
+ } else {
+ checkLiteral();
+ }
+ } else {
+ switch (format.charAt(iFormat)) {
+ case "d":
+ day = getNumber("d");
+ break;
+ case "D":
+ getName("D", dayNamesShort, dayNames);
+ break;
+ case "o":
+ doy = getNumber("o");
+ break;
+ case "m":
+ month = getNumber("m");
+ break;
+ case "M":
+ month = getName("M", monthNamesShort, monthNames);
+ break;
+ case "y":
+ year = getNumber("y");
+ break;
+ case "@":
+ date = new Date(getNumber("@"));
+ year = date.getFullYear();
+ month = date.getMonth() + 1;
+ day = date.getDate();
+ break;
+ case "!":
+ date = new Date((getNumber("!") - this._ticksTo1970) / 10000);
+ year = date.getFullYear();
+ month = date.getMonth() + 1;
+ day = date.getDate();
+ break;
+ case "'":
+ if (lookAhead("'")){
+ checkLiteral();
+ } else {
+ literal = true;
+ }
+ break;
+ default:
+ checkLiteral();
+ }
+ }
+ }
+
+ if (iValue < value.length){
+ extra = value.substr(iValue);
+ if (!/^\s+/.test(extra)) {
+ throw "Extra/unparsed characters found in date: " + extra;
+ }
+ }
+
+ if (year === -1) {
+ year = new Date().getFullYear();
+ } else if (year < 100) {
+ year += new Date().getFullYear() - new Date().getFullYear() % 100 +
+ (year <= shortYearCutoff ? 0 : -100);
+ }
+
+ if (doy > -1) {
+ month = 1;
+ day = doy;
+ do {
+ dim = this._getDaysInMonth(year, month - 1);
+ if (day <= dim) {
+ break;
+ }
+ month++;
+ day -= dim;
+ } while (true);
+ }
+
+ date = this._daylightSavingAdjust(new Date(year, month - 1, day));
+ if (date.getFullYear() !== year || date.getMonth() + 1 !== month || date.getDate() !== day) {
+ throw "Invalid date"; // E.g. 31/02/00
+ }
+ return date;
+ },
+
+ /* Standard date formats. */
+ ATOM: "yy-mm-dd", // RFC 3339 (ISO 8601)
+ COOKIE: "D, dd M yy",
+ ISO_8601: "yy-mm-dd",
+ RFC_822: "D, d M y",
+ RFC_850: "DD, dd-M-y",
+ RFC_1036: "D, d M y",
+ RFC_1123: "D, d M yy",
+ RFC_2822: "D, d M yy",
+ RSS: "D, d M y", // RFC 822
+ TICKS: "!",
+ TIMESTAMP: "@",
+ W3C: "yy-mm-dd", // ISO 8601
+
+ _ticksTo1970: (((1970 - 1) * 365 + Math.floor(1970 / 4) - Math.floor(1970 / 100) +
+ Math.floor(1970 / 400)) * 24 * 60 * 60 * 10000000),
+
+ /* Format a date object into a string value.
+ * The format can be combinations of the following:
+ * d - day of month (no leading zero)
+ * dd - day of month (two digit)
+ * o - day of year (no leading zeros)
+ * oo - day of year (three digit)
+ * D - day name short
+ * DD - day name long
+ * m - month of year (no leading zero)
+ * mm - month of year (two digit)
+ * M - month name short
+ * MM - month name long
+ * y - year (two digit)
+ * yy - year (four digit)
+ * @ - Unix timestamp (ms since 01/01/1970)
+ * ! - Windows ticks (100ns since 01/01/0001)
+ * "..." - literal text
+ * '' - single quote
+ *
+ * @param format string - the desired format of the date
+ * @param date Date - the date value to format
+ * @param settings Object - attributes include:
+ * dayNamesShort string[7] - abbreviated names of the days from Sunday (optional)
+ * dayNames string[7] - names of the days from Sunday (optional)
+ * monthNamesShort string[12] - abbreviated names of the months (optional)
+ * monthNames string[12] - names of the months (optional)
+ * @return string - the date in the above format
+ */
+ formatDate: function (format, date, settings) {
+ if (!date) {
+ return "";
+ }
+
+ var iFormat,
+ dayNamesShort = (settings ? settings.dayNamesShort : null) || this._defaults.dayNamesShort,
+ dayNames = (settings ? settings.dayNames : null) || this._defaults.dayNames,
+ monthNamesShort = (settings ? settings.monthNamesShort : null) || this._defaults.monthNamesShort,
+ monthNames = (settings ? settings.monthNames : null) || this._defaults.monthNames,
+ // Check whether a format character is doubled
+ lookAhead = function(match) {
+ var matches = (iFormat + 1 < format.length && format.charAt(iFormat + 1) === match);
+ if (matches) {
+ iFormat++;
+ }
+ return matches;
+ },
+ // Format a number, with leading zero if necessary
+ formatNumber = function(match, value, len) {
+ var num = "" + value;
+ if (lookAhead(match)) {
+ while (num.length < len) {
+ num = "0" + num;
+ }
+ }
+ return num;
+ },
+ // Format a name, short or long as requested
+ formatName = function(match, value, shortNames, longNames) {
+ return (lookAhead(match) ? longNames[value] : shortNames[value]);
+ },
+ output = "",
+ literal = false;
+
+ if (date) {
+ for (iFormat = 0; iFormat < format.length; iFormat++) {
+ if (literal) {
+ if (format.charAt(iFormat) === "'" && !lookAhead("'")) {
+ literal = false;
+ } else {
+ output += format.charAt(iFormat);
+ }
+ } else {
+ switch (format.charAt(iFormat)) {
+ case "d":
+ output += formatNumber("d", date.getDate(), 2);
+ break;
+ case "D":
+ output += formatName("D", date.getDay(), dayNamesShort, dayNames);
+ break;
+ case "o":
+ output += formatNumber("o",
+ Math.round((new Date(date.getFullYear(), date.getMonth(), date.getDate()).getTime() - new Date(date.getFullYear(), 0, 0).getTime()) / 86400000), 3);
+ break;
+ case "m":
+ output += formatNumber("m", date.getMonth() + 1, 2);
+ break;
+ case "M":
+ output += formatName("M", date.getMonth(), monthNamesShort, monthNames);
+ break;
+ case "y":
+ output += (lookAhead("y") ? date.getFullYear() :
+ (date.getYear() % 100 < 10 ? "0" : "") + date.getYear() % 100);
+ break;
+ case "@":
+ output += date.getTime();
+ break;
+ case "!":
+ output += date.getTime() * 10000 + this._ticksTo1970;
+ break;
+ case "'":
+ if (lookAhead("'")) {
+ output += "'";
+ } else {
+ literal = true;
+ }
+ break;
+ default:
+ output += format.charAt(iFormat);
+ }
+ }
+ }
+ }
+ return output;
+ },
+
+ /* Extract all possible characters from the date format. */
+ _possibleChars: function (format) {
+ var iFormat,
+ chars = "",
+ literal = false,
+ // Check whether a format character is doubled
+ lookAhead = function(match) {
+ var matches = (iFormat + 1 < format.length && format.charAt(iFormat + 1) === match);
+ if (matches) {
+ iFormat++;
+ }
+ return matches;
+ };
+
+ for (iFormat = 0; iFormat < format.length; iFormat++) {
+ if (literal) {
+ if (format.charAt(iFormat) === "'" && !lookAhead("'")) {
+ literal = false;
+ } else {
+ chars += format.charAt(iFormat);
+ }
+ } else {
+ switch (format.charAt(iFormat)) {
+ case "d": case "m": case "y": case "@":
+ chars += "0123456789";
+ break;
+ case "D": case "M":
+ return null; // Accept anything
+ case "'":
+ if (lookAhead("'")) {
+ chars += "'";
+ } else {
+ literal = true;
+ }
+ break;
+ default:
+ chars += format.charAt(iFormat);
+ }
+ }
+ }
+ return chars;
+ },
+
+ /* Get a setting value, defaulting if necessary. */
+ _get: function(inst, name) {
+ return inst.settings[name] !== undefined ?
+ inst.settings[name] : this._defaults[name];
+ },
+
+ /* Parse existing date and initialise date picker. */
+ _setDateFromField: function(inst, noDefault) {
+ if (inst.input.val() === inst.lastVal) {
+ return;
+ }
+
+ var dateFormat = this._get(inst, "dateFormat"),
+ dates = inst.lastVal = inst.input ? inst.input.val() : null,
+ defaultDate = this._getDefaultDate(inst),
+ date = defaultDate,
+ settings = this._getFormatConfig(inst);
+
+ try {
+ date = this.parseDate(dateFormat, dates, settings) || defaultDate;
+ } catch (event) {
+ dates = (noDefault ? "" : dates);
+ }
+ inst.selectedDay = date.getDate();
+ inst.drawMonth = inst.selectedMonth = date.getMonth();
+ inst.drawYear = inst.selectedYear = date.getFullYear();
+ inst.currentDay = (dates ? date.getDate() : 0);
+ inst.currentMonth = (dates ? date.getMonth() : 0);
+ inst.currentYear = (dates ? date.getFullYear() : 0);
+ this._adjustInstDate(inst);
+ },
+
+ /* Retrieve the default date shown on opening. */
+ _getDefaultDate: function(inst) {
+ return this._restrictMinMax(inst,
+ this._determineDate(inst, this._get(inst, "defaultDate"), new Date()));
+ },
+
+ /* A date may be specified as an exact value or a relative one. */
+ _determineDate: function(inst, date, defaultDate) {
+ var offsetNumeric = function(offset) {
+ var date = new Date();
+ date.setDate(date.getDate() + offset);
+ return date;
+ },
+ offsetString = function(offset) {
+ try {
+ return $.datepicker.parseDate($.datepicker._get(inst, "dateFormat"),
+ offset, $.datepicker._getFormatConfig(inst));
+ }
+ catch (e) {
+ // Ignore
+ }
+
+ var date = (offset.toLowerCase().match(/^c/) ?
+ $.datepicker._getDate(inst) : null) || new Date(),
+ year = date.getFullYear(),
+ month = date.getMonth(),
+ day = date.getDate(),
+ pattern = /([+\-]?[0-9]+)\s*(d|D|w|W|m|M|y|Y)?/g,
+ matches = pattern.exec(offset);
+
+ while (matches) {
+ switch (matches[2] || "d") {
+ case "d" : case "D" :
+ day += parseInt(matches[1],10); break;
+ case "w" : case "W" :
+ day += parseInt(matches[1],10) * 7; break;
+ case "m" : case "M" :
+ month += parseInt(matches[1],10);
+ day = Math.min(day, $.datepicker._getDaysInMonth(year, month));
+ break;
+ case "y": case "Y" :
+ year += parseInt(matches[1],10);
+ day = Math.min(day, $.datepicker._getDaysInMonth(year, month));
+ break;
+ }
+ matches = pattern.exec(offset);
+ }
+ return new Date(year, month, day);
+ },
+ newDate = (date == null || date === "" ? defaultDate : (typeof date === "string" ? offsetString(date) :
+ (typeof date === "number" ? (isNaN(date) ? defaultDate : offsetNumeric(date)) : new Date(date.getTime()))));
+
+ newDate = (newDate && newDate.toString() === "Invalid Date" ? defaultDate : newDate);
+ if (newDate) {
+ newDate.setHours(0);
+ newDate.setMinutes(0);
+ newDate.setSeconds(0);
+ newDate.setMilliseconds(0);
+ }
+ return this._daylightSavingAdjust(newDate);
+ },
+
+ /* Handle switch to/from daylight saving.
+ * Hours may be non-zero on daylight saving cut-over:
+ * > 12 when midnight changeover, but then cannot generate
+ * midnight datetime, so jump to 1AM, otherwise reset.
+ * @param date (Date) the date to check
+ * @return (Date) the corrected date
+ */
+ _daylightSavingAdjust: function(date) {
+ if (!date) {
+ return null;
+ }
+ date.setHours(date.getHours() > 12 ? date.getHours() + 2 : 0);
+ return date;
+ },
+
+ /* Set the date(s) directly. */
+ _setDate: function(inst, date, noChange) {
+ var clear = !date,
+ origMonth = inst.selectedMonth,
+ origYear = inst.selectedYear,
+ newDate = this._restrictMinMax(inst, this._determineDate(inst, date, new Date()));
+
+ inst.selectedDay = inst.currentDay = newDate.getDate();
+ inst.drawMonth = inst.selectedMonth = inst.currentMonth = newDate.getMonth();
+ inst.drawYear = inst.selectedYear = inst.currentYear = newDate.getFullYear();
+ if ((origMonth !== inst.selectedMonth || origYear !== inst.selectedYear) && !noChange) {
+ this._notifyChange(inst);
+ }
+ this._adjustInstDate(inst);
+ if (inst.input) {
+ inst.input.val(clear ? "" : this._formatDate(inst));
+ }
+ },
+
+ /* Retrieve the date(s) directly. */
+ _getDate: function(inst) {
+ var startDate = (!inst.currentYear || (inst.input && inst.input.val() === "") ? null :
+ this._daylightSavingAdjust(new Date(
+ inst.currentYear, inst.currentMonth, inst.currentDay)));
+ return startDate;
+ },
+
+ /* Attach the onxxx handlers. These are declared statically so
+ * they work with static code transformers like Caja.
+ */
+ _attachHandlers: function(inst) {
+ var stepMonths = this._get(inst, "stepMonths"),
+ id = "#" + inst.id.replace( /\\\\/g, "\\" );
+ inst.dpDiv.find("[data-handler]").map(function () {
+ var handler = {
+ prev: function () {
+ $.datepicker._adjustDate(id, -stepMonths, "M");
+ },
+ next: function () {
+ $.datepicker._adjustDate(id, +stepMonths, "M");
+ },
+ hide: function () {
+ $.datepicker._hideDatepicker();
+ },
+ today: function () {
+ $.datepicker._gotoToday(id);
+ },
+ selectDay: function () {
+ $.datepicker._selectDay(id, +this.getAttribute("data-month"), +this.getAttribute("data-year"), this);
+ return false;
+ },
+ selectMonth: function () {
+ $.datepicker._selectMonthYear(id, this, "M");
+ return false;
+ },
+ selectYear: function () {
+ $.datepicker._selectMonthYear(id, this, "Y");
+ return false;
+ }
+ };
+ $(this).bind(this.getAttribute("data-event"), handler[this.getAttribute("data-handler")]);
+ });
+ },
+
+ /* Generate the HTML for the current state of the date picker. */
+ _generateHTML: function(inst) {
+ var maxDraw, prevText, prev, nextText, next, currentText, gotoDate,
+ controls, buttonPanel, firstDay, showWeek, dayNames, dayNamesMin,
+ monthNames, monthNamesShort, beforeShowDay, showOtherMonths,
+ selectOtherMonths, defaultDate, html, dow, row, group, col, selectedDate,
+ cornerClass, calender, thead, day, daysInMonth, leadDays, curRows, numRows,
+ printDate, dRow, tbody, daySettings, otherMonth, unselectable,
+ tempDate = new Date(),
+ today = this._daylightSavingAdjust(
+ new Date(tempDate.getFullYear(), tempDate.getMonth(), tempDate.getDate())), // clear time
+ isRTL = this._get(inst, "isRTL"),
+ showButtonPanel = this._get(inst, "showButtonPanel"),
+ hideIfNoPrevNext = this._get(inst, "hideIfNoPrevNext"),
+ navigationAsDateFormat = this._get(inst, "navigationAsDateFormat"),
+ numMonths = this._getNumberOfMonths(inst),
+ showCurrentAtPos = this._get(inst, "showCurrentAtPos"),
+ stepMonths = this._get(inst, "stepMonths"),
+ isMultiMonth = (numMonths[0] !== 1 || numMonths[1] !== 1),
+ currentDate = this._daylightSavingAdjust((!inst.currentDay ? new Date(9999, 9, 9) :
+ new Date(inst.currentYear, inst.currentMonth, inst.currentDay))),
+ minDate = this._getMinMaxDate(inst, "min"),
+ maxDate = this._getMinMaxDate(inst, "max"),
+ drawMonth = inst.drawMonth - showCurrentAtPos,
+ drawYear = inst.drawYear;
+
+ if (drawMonth < 0) {
+ drawMonth += 12;
+ drawYear--;
+ }
+ if (maxDate) {
+ maxDraw = this._daylightSavingAdjust(new Date(maxDate.getFullYear(),
+ maxDate.getMonth() - (numMonths[0] * numMonths[1]) + 1, maxDate.getDate()));
+ maxDraw = (minDate && maxDraw < minDate ? minDate : maxDraw);
+ while (this._daylightSavingAdjust(new Date(drawYear, drawMonth, 1)) > maxDraw) {
+ drawMonth--;
+ if (drawMonth < 0) {
+ drawMonth = 11;
+ drawYear--;
+ }
+ }
+ }
+ inst.drawMonth = drawMonth;
+ inst.drawYear = drawYear;
+
+ prevText = this._get(inst, "prevText");
+ prevText = (!navigationAsDateFormat ? prevText : this.formatDate(prevText,
+ this._daylightSavingAdjust(new Date(drawYear, drawMonth - stepMonths, 1)),
+ this._getFormatConfig(inst)));
+
+ prev = (this._canAdjustMonth(inst, -1, drawYear, drawMonth) ?
+ "<a class='ui-datepicker-prev ui-corner-all' data-handler='prev' data-event='click'" +
+ " title='" + prevText + "'><span class='ui-icon ui-icon-circle-triangle-" + ( isRTL ? "e" : "w") + "'>" + prevText + "</span></a>" :
+ (hideIfNoPrevNext ? "" : "<a class='ui-datepicker-prev ui-corner-all ui-state-disabled' title='"+ prevText +"'><span class='ui-icon ui-icon-circle-triangle-" + ( isRTL ? "e" : "w") + "'>" + prevText + "</span></a>"));
+
+ nextText = this._get(inst, "nextText");
+ nextText = (!navigationAsDateFormat ? nextText : this.formatDate(nextText,
+ this._daylightSavingAdjust(new Date(drawYear, drawMonth + stepMonths, 1)),
+ this._getFormatConfig(inst)));
+
+ next = (this._canAdjustMonth(inst, +1, drawYear, drawMonth) ?
+ "<a class='ui-datepicker-next ui-corner-all' data-handler='next' data-event='click'" +
+ " title='" + nextText + "'><span class='ui-icon ui-icon-circle-triangle-" + ( isRTL ? "w" : "e") + "'>" + nextText + "</span></a>" :
+ (hideIfNoPrevNext ? "" : "<a class='ui-datepicker-next ui-corner-all ui-state-disabled' title='"+ nextText + "'><span class='ui-icon ui-icon-circle-triangle-" + ( isRTL ? "w" : "e") + "'>" + nextText + "</span></a>"));
+
+ currentText = this._get(inst, "currentText");
+ gotoDate = (this._get(inst, "gotoCurrent") && inst.currentDay ? currentDate : today);
+ currentText = (!navigationAsDateFormat ? currentText :
+ this.formatDate(currentText, gotoDate, this._getFormatConfig(inst)));
+
+ controls = (!inst.inline ? "<button type='button' class='ui-datepicker-close ui-state-default ui-priority-primary ui-corner-all' data-handler='hide' data-event='click'>" +
+ this._get(inst, "closeText") + "</button>" : "");
+
+ buttonPanel = (showButtonPanel) ? "<div class='ui-datepicker-buttonpane ui-widget-content'>" + (isRTL ? controls : "") +
+ (this._isInRange(inst, gotoDate) ? "<button type='button' class='ui-datepicker-current ui-state-default ui-priority-secondary ui-corner-all' data-handler='today' data-event='click'" +
+ ">" + currentText + "</button>" : "") + (isRTL ? "" : controls) + "</div>" : "";
+
+ firstDay = parseInt(this._get(inst, "firstDay"),10);
+ firstDay = (isNaN(firstDay) ? 0 : firstDay);
+
+ showWeek = this._get(inst, "showWeek");
+ dayNames = this._get(inst, "dayNames");
+ dayNamesMin = this._get(inst, "dayNamesMin");
+ monthNames = this._get(inst, "monthNames");
+ monthNamesShort = this._get(inst, "monthNamesShort");
+ beforeShowDay = this._get(inst, "beforeShowDay");
+ showOtherMonths = this._get(inst, "showOtherMonths");
+ selectOtherMonths = this._get(inst, "selectOtherMonths");
+ defaultDate = this._getDefaultDate(inst);
+ html = "";
+ dow;
+ for (row = 0; row < numMonths[0]; row++) {
+ group = "";
+ this.maxRows = 4;
+ for (col = 0; col < numMonths[1]; col++) {
+ selectedDate = this._daylightSavingAdjust(new Date(drawYear, drawMonth, inst.selectedDay));
+ cornerClass = " ui-corner-all";
+ calender = "";
+ if (isMultiMonth) {
+ calender += "<div class='ui-datepicker-group";
+ if (numMonths[1] > 1) {
+ switch (col) {
+ case 0: calender += " ui-datepicker-group-first";
+ cornerClass = " ui-corner-" + (isRTL ? "right" : "left"); break;
+ case numMonths[1]-1: calender += " ui-datepicker-group-last";
+ cornerClass = " ui-corner-" + (isRTL ? "left" : "right"); break;
+ default: calender += " ui-datepicker-group-middle"; cornerClass = ""; break;
+ }
+ }
+ calender += "'>";
+ }
+ calender += "<div class='ui-datepicker-header ui-widget-header ui-helper-clearfix" + cornerClass + "'>" +
+ (/all|left/.test(cornerClass) && row === 0 ? (isRTL ? next : prev) : "") +
+ (/all|right/.test(cornerClass) && row === 0 ? (isRTL ? prev : next) : "") +
+ this._generateMonthYearHeader(inst, drawMonth, drawYear, minDate, maxDate,
+ row > 0 || col > 0, monthNames, monthNamesShort) + // draw month headers
+ "</div><table class='ui-datepicker-calendar'><thead>" +
+ "<tr>";
+ thead = (showWeek ? "<th class='ui-datepicker-week-col'>" + this._get(inst, "weekHeader") + "</th>" : "");
+ for (dow = 0; dow < 7; dow++) { // days of the week
+ day = (dow + firstDay) % 7;
+ thead += "<th" + ((dow + firstDay + 6) % 7 >= 5 ? " class='ui-datepicker-week-end'" : "") + ">" +
+ "<span title='" + dayNames[day] + "'>" + dayNamesMin[day] + "</span></th>";
+ }
+ calender += thead + "</tr></thead><tbody>";
+ daysInMonth = this._getDaysInMonth(drawYear, drawMonth);
+ if (drawYear === inst.selectedYear && drawMonth === inst.selectedMonth) {
+ inst.selectedDay = Math.min(inst.selectedDay, daysInMonth);
+ }
+ leadDays = (this._getFirstDayOfMonth(drawYear, drawMonth) - firstDay + 7) % 7;
+ curRows = Math.ceil((leadDays + daysInMonth) / 7); // calculate the number of rows to generate
+ numRows = (isMultiMonth ? this.maxRows > curRows ? this.maxRows : curRows : curRows); //If multiple months, use the higher number of rows (see #7043)
+ this.maxRows = numRows;
+ printDate = this._daylightSavingAdjust(new Date(drawYear, drawMonth, 1 - leadDays));
+ for (dRow = 0; dRow < numRows; dRow++) { // create date picker rows
+ calender += "<tr>";
+ tbody = (!showWeek ? "" : "<td class='ui-datepicker-week-col'>" +
+ this._get(inst, "calculateWeek")(printDate) + "</td>");
+ for (dow = 0; dow < 7; dow++) { // create date picker days
+ daySettings = (beforeShowDay ?
+ beforeShowDay.apply((inst.input ? inst.input[0] : null), [printDate]) : [true, ""]);
+ otherMonth = (printDate.getMonth() !== drawMonth);
+ unselectable = (otherMonth && !selectOtherMonths) || !daySettings[0] ||
+ (minDate && printDate < minDate) || (maxDate && printDate > maxDate);
+ tbody += "<td class='" +
+ ((dow + firstDay + 6) % 7 >= 5 ? " ui-datepicker-week-end" : "") + // highlight weekends
+ (otherMonth ? " ui-datepicker-other-month" : "") + // highlight days from other months
+ ((printDate.getTime() === selectedDate.getTime() && drawMonth === inst.selectedMonth && inst._keyEvent) || // user pressed key
+ (defaultDate.getTime() === printDate.getTime() && defaultDate.getTime() === selectedDate.getTime()) ?
+ // or defaultDate is current printedDate and defaultDate is selectedDate
+ " " + this._dayOverClass : "") + // highlight selected day
+ (unselectable ? " " + this._unselectableClass + " ui-state-disabled": "") + // highlight unselectable days
+ (otherMonth && !showOtherMonths ? "" : " " + daySettings[1] + // highlight custom dates
+ (printDate.getTime() === currentDate.getTime() ? " " + this._currentClass : "") + // highlight selected day
+ (printDate.getTime() === today.getTime() ? " ui-datepicker-today" : "")) + "'" + // highlight today (if different)
+ ((!otherMonth || showOtherMonths) && daySettings[2] ? " title='" + daySettings[2].replace(/'/g, "&#39;") + "'" : "") + // cell title
+ (unselectable ? "" : " data-handler='selectDay' data-event='click' data-month='" + printDate.getMonth() + "' data-year='" + printDate.getFullYear() + "'") + ">" + // actions
+ (otherMonth && !showOtherMonths ? "&#xa0;" : // display for other months
+ (unselectable ? "<span class='ui-state-default'>" + printDate.getDate() + "</span>" : "<a class='ui-state-default" +
+ (printDate.getTime() === today.getTime() ? " ui-state-highlight" : "") +
+ (printDate.getTime() === currentDate.getTime() ? " ui-state-active" : "") + // highlight selected day
+ (otherMonth ? " ui-priority-secondary" : "") + // distinguish dates from other months
+ "' href='#'>" + printDate.getDate() + "</a>")) + "</td>"; // display selectable date
+ printDate.setDate(printDate.getDate() + 1);
+ printDate = this._daylightSavingAdjust(printDate);
+ }
+ calender += tbody + "</tr>";
+ }
+ drawMonth++;
+ if (drawMonth > 11) {
+ drawMonth = 0;
+ drawYear++;
+ }
+ calender += "</tbody></table>" + (isMultiMonth ? "</div>" +
+ ((numMonths[0] > 0 && col === numMonths[1]-1) ? "<div class='ui-datepicker-row-break'></div>" : "") : "");
+ group += calender;
+ }
+ html += group;
+ }
+ html += buttonPanel;
+ inst._keyEvent = false;
+ return html;
+ },
+
+ /* Generate the month and year header. */
+ _generateMonthYearHeader: function(inst, drawMonth, drawYear, minDate, maxDate,
+ secondary, monthNames, monthNamesShort) {
+
+ var inMinYear, inMaxYear, month, years, thisYear, determineYear, year, endYear,
+ changeMonth = this._get(inst, "changeMonth"),
+ changeYear = this._get(inst, "changeYear"),
+ showMonthAfterYear = this._get(inst, "showMonthAfterYear"),
+ html = "<div class='ui-datepicker-title'>",
+ monthHtml = "";
+
+ // month selection
+ if (secondary || !changeMonth) {
+ monthHtml += "<span class='ui-datepicker-month'>" + monthNames[drawMonth] + "</span>";
+ } else {
+ inMinYear = (minDate && minDate.getFullYear() === drawYear);
+ inMaxYear = (maxDate && maxDate.getFullYear() === drawYear);
+ monthHtml += "<select class='ui-datepicker-month' data-handler='selectMonth' data-event='change'>";
+ for ( month = 0; month < 12; month++) {
+ if ((!inMinYear || month >= minDate.getMonth()) && (!inMaxYear || month <= maxDate.getMonth())) {
+ monthHtml += "<option value='" + month + "'" +
+ (month === drawMonth ? " selected='selected'" : "") +
+ ">" + monthNamesShort[month] + "</option>";
+ }
+ }
+ monthHtml += "</select>";
+ }
+
+ if (!showMonthAfterYear) {
+ html += monthHtml + (secondary || !(changeMonth && changeYear) ? "&#xa0;" : "");
+ }
+
+ // year selection
+ if ( !inst.yearshtml ) {
+ inst.yearshtml = "";
+ if (secondary || !changeYear) {
+ html += "<span class='ui-datepicker-year'>" + drawYear + "</span>";
+ } else {
+ // determine range of years to display
+ years = this._get(inst, "yearRange").split(":");
+ thisYear = new Date().getFullYear();
+ determineYear = function(value) {
+ var year = (value.match(/c[+\-].*/) ? drawYear + parseInt(value.substring(1), 10) :
+ (value.match(/[+\-].*/) ? thisYear + parseInt(value, 10) :
+ parseInt(value, 10)));
+ return (isNaN(year) ? thisYear : year);
+ };
+ year = determineYear(years[0]);
+ endYear = Math.max(year, determineYear(years[1] || ""));
+ year = (minDate ? Math.max(year, minDate.getFullYear()) : year);
+ endYear = (maxDate ? Math.min(endYear, maxDate.getFullYear()) : endYear);
+ inst.yearshtml += "<select class='ui-datepicker-year' data-handler='selectYear' data-event='change'>";
+ for (; year <= endYear; year++) {
+ inst.yearshtml += "<option value='" + year + "'" +
+ (year === drawYear ? " selected='selected'" : "") +
+ ">" + year + "</option>";
+ }
+ inst.yearshtml += "</select>";
+
+ html += inst.yearshtml;
+ inst.yearshtml = null;
+ }
+ }
+
+ html += this._get(inst, "yearSuffix");
+ if (showMonthAfterYear) {
+ html += (secondary || !(changeMonth && changeYear) ? "&#xa0;" : "") + monthHtml;
+ }
+ html += "</div>"; // Close datepicker_header
+ return html;
+ },
+
+ /* Adjust one of the date sub-fields. */
+ _adjustInstDate: function(inst, offset, period) {
+ var year = inst.drawYear + (period === "Y" ? offset : 0),
+ month = inst.drawMonth + (period === "M" ? offset : 0),
+ day = Math.min(inst.selectedDay, this._getDaysInMonth(year, month)) + (period === "D" ? offset : 0),
+ date = this._restrictMinMax(inst, this._daylightSavingAdjust(new Date(year, month, day)));
+
+ inst.selectedDay = date.getDate();
+ inst.drawMonth = inst.selectedMonth = date.getMonth();
+ inst.drawYear = inst.selectedYear = date.getFullYear();
+ if (period === "M" || period === "Y") {
+ this._notifyChange(inst);
+ }
+ },
+
+ /* Ensure a date is within any min/max bounds. */
+ _restrictMinMax: function(inst, date) {
+ var minDate = this._getMinMaxDate(inst, "min"),
+ maxDate = this._getMinMaxDate(inst, "max"),
+ newDate = (minDate && date < minDate ? minDate : date);
+ return (maxDate && newDate > maxDate ? maxDate : newDate);
+ },
+
+ /* Notify change of month/year. */
+ _notifyChange: function(inst) {
+ var onChange = this._get(inst, "onChangeMonthYear");
+ if (onChange) {
+ onChange.apply((inst.input ? inst.input[0] : null),
+ [inst.selectedYear, inst.selectedMonth + 1, inst]);
+ }
+ },
+
+ /* Determine the number of months to show. */
+ _getNumberOfMonths: function(inst) {
+ var numMonths = this._get(inst, "numberOfMonths");
+ return (numMonths == null ? [1, 1] : (typeof numMonths === "number" ? [1, numMonths] : numMonths));
+ },
+
+ /* Determine the current maximum date - ensure no time components are set. */
+ _getMinMaxDate: function(inst, minMax) {
+ return this._determineDate(inst, this._get(inst, minMax + "Date"), null);
+ },
+
+ /* Find the number of days in a given month. */
+ _getDaysInMonth: function(year, month) {
+ return 32 - this._daylightSavingAdjust(new Date(year, month, 32)).getDate();
+ },
+
+ /* Find the day of the week of the first of a month. */
+ _getFirstDayOfMonth: function(year, month) {
+ return new Date(year, month, 1).getDay();
+ },
+
+ /* Determines if we should allow a "next/prev" month display change. */
+ _canAdjustMonth: function(inst, offset, curYear, curMonth) {
+ var numMonths = this._getNumberOfMonths(inst),
+ date = this._daylightSavingAdjust(new Date(curYear,
+ curMonth + (offset < 0 ? offset : numMonths[0] * numMonths[1]), 1));
+
+ if (offset < 0) {
+ date.setDate(this._getDaysInMonth(date.getFullYear(), date.getMonth()));
+ }
+ return this._isInRange(inst, date);
+ },
+
+ /* Is the given date in the accepted range? */
+ _isInRange: function(inst, date) {
+ var yearSplit, currentYear,
+ minDate = this._getMinMaxDate(inst, "min"),
+ maxDate = this._getMinMaxDate(inst, "max"),
+ minYear = null,
+ maxYear = null,
+ years = this._get(inst, "yearRange");
+ if (years){
+ yearSplit = years.split(":");
+ currentYear = new Date().getFullYear();
+ minYear = parseInt(yearSplit[0], 10);
+ maxYear = parseInt(yearSplit[1], 10);
+ if ( yearSplit[0].match(/[+\-].*/) ) {
+ minYear += currentYear;
+ }
+ if ( yearSplit[1].match(/[+\-].*/) ) {
+ maxYear += currentYear;
+ }
+ }
+
+ return ((!minDate || date.getTime() >= minDate.getTime()) &&
+ (!maxDate || date.getTime() <= maxDate.getTime()) &&
+ (!minYear || date.getFullYear() >= minYear) &&
+ (!maxYear || date.getFullYear() <= maxYear));
+ },
+
+ /* Provide the configuration settings for formatting/parsing. */
+ _getFormatConfig: function(inst) {
+ var shortYearCutoff = this._get(inst, "shortYearCutoff");
+ shortYearCutoff = (typeof shortYearCutoff !== "string" ? shortYearCutoff :
+ new Date().getFullYear() % 100 + parseInt(shortYearCutoff, 10));
+ return {shortYearCutoff: shortYearCutoff,
+ dayNamesShort: this._get(inst, "dayNamesShort"), dayNames: this._get(inst, "dayNames"),
+ monthNamesShort: this._get(inst, "monthNamesShort"), monthNames: this._get(inst, "monthNames")};
+ },
+
+ /* Format the given date for display. */
+ _formatDate: function(inst, day, month, year) {
+ if (!day) {
+ inst.currentDay = inst.selectedDay;
+ inst.currentMonth = inst.selectedMonth;
+ inst.currentYear = inst.selectedYear;
+ }
+ var date = (day ? (typeof day === "object" ? day :
+ this._daylightSavingAdjust(new Date(year, month, day))) :
+ this._daylightSavingAdjust(new Date(inst.currentYear, inst.currentMonth, inst.currentDay)));
+ return this.formatDate(this._get(inst, "dateFormat"), date, this._getFormatConfig(inst));
+ }
+});
+
+/*
+ * Bind hover events for datepicker elements.
+ * Done via delegate so the binding only occurs once in the lifetime of the parent div.
+ * Global instActive, set by _updateDatepicker allows the handlers to find their way back to the active picker.
+ */
+function bindHover(dpDiv) {
+ var selector = "button, .ui-datepicker-prev, .ui-datepicker-next, .ui-datepicker-calendar td a";
+ return dpDiv.delegate(selector, "mouseout", function() {
+ $(this).removeClass("ui-state-hover");
+ if (this.className.indexOf("ui-datepicker-prev") !== -1) {
+ $(this).removeClass("ui-datepicker-prev-hover");
+ }
+ if (this.className.indexOf("ui-datepicker-next") !== -1) {
+ $(this).removeClass("ui-datepicker-next-hover");
+ }
+ })
+ .delegate(selector, "mouseover", function(){
+ if (!$.datepicker._isDisabledDatepicker( instActive.inline ? dpDiv.parent()[0] : instActive.input[0])) {
+ $(this).parents(".ui-datepicker-calendar").find("a").removeClass("ui-state-hover");
+ $(this).addClass("ui-state-hover");
+ if (this.className.indexOf("ui-datepicker-prev") !== -1) {
+ $(this).addClass("ui-datepicker-prev-hover");
+ }
+ if (this.className.indexOf("ui-datepicker-next") !== -1) {
+ $(this).addClass("ui-datepicker-next-hover");
+ }
+ }
+ });
+}
+
+/* jQuery extend now ignores nulls! */
+function extendRemove(target, props) {
+ $.extend(target, props);
+ for (var name in props) {
+ if (props[name] == null) {
+ target[name] = props[name];
+ }
+ }
+ return target;
+}
+
+/* Invoke the datepicker functionality.
+ @param options string - a command, optionally followed by additional parameters or
+ Object - settings for attaching new datepicker functionality
+ @return jQuery object */
+$.fn.datepicker = function(options){
+
+ /* Verify an empty collection wasn't passed - Fixes #6976 */
+ if ( !this.length ) {
+ return this;
+ }
+
+ /* Initialise the date picker. */
+ if (!$.datepicker.initialized) {
+ $(document).mousedown($.datepicker._checkExternalClick);
+ $.datepicker.initialized = true;
+ }
+
+ /* Append datepicker main container to body if not exist. */
+ if ($("#"+$.datepicker._mainDivId).length === 0) {
+ $("body").append($.datepicker.dpDiv);
+ }
+
+ var otherArgs = Array.prototype.slice.call(arguments, 1);
+ if (typeof options === "string" && (options === "isDisabled" || options === "getDate" || options === "widget")) {
+ return $.datepicker["_" + options + "Datepicker"].
+ apply($.datepicker, [this[0]].concat(otherArgs));
+ }
+ if (options === "option" && arguments.length === 2 && typeof arguments[1] === "string") {
+ return $.datepicker["_" + options + "Datepicker"].
+ apply($.datepicker, [this[0]].concat(otherArgs));
+ }
+ return this.each(function() {
+ typeof options === "string" ?
+ $.datepicker["_" + options + "Datepicker"].
+ apply($.datepicker, [this].concat(otherArgs)) :
+ $.datepicker._attachDatepicker(this, options);
+ });
+};
+
+$.datepicker = new Datepicker(); // singleton instance
+$.datepicker.initialized = false;
+$.datepicker.uuid = new Date().getTime();
+$.datepicker.version = "1.10.3";
+
+})(jQuery);
diff --git a/debian/missing-sources/jquery-ui/jquery.ui.dialog.js b/debian/missing-sources/jquery-ui/jquery.ui.dialog.js
new file mode 100644
index 0000000..3a01e0c
--- /dev/null
+++ b/debian/missing-sources/jquery-ui/jquery.ui.dialog.js
@@ -0,0 +1,808 @@
+/*!
+ * jQuery UI Dialog 1.10.3
+ * http://jqueryui.com
+ *
+ * Copyright 2013 jQuery Foundation and other contributors
+ * Released under the MIT license.
+ * http://jquery.org/license
+ *
+ * http://api.jqueryui.com/dialog/
+ *
+ * Depends:
+ * jquery.ui.core.js
+ * jquery.ui.widget.js
+ * jquery.ui.button.js
+ * jquery.ui.draggable.js
+ * jquery.ui.mouse.js
+ * jquery.ui.position.js
+ * jquery.ui.resizable.js
+ */
+(function( $, undefined ) {
+
+var sizeRelatedOptions = {
+ buttons: true,
+ height: true,
+ maxHeight: true,
+ maxWidth: true,
+ minHeight: true,
+ minWidth: true,
+ width: true
+ },
+ resizableRelatedOptions = {
+ maxHeight: true,
+ maxWidth: true,
+ minHeight: true,
+ minWidth: true
+ };
+
+$.widget( "ui.dialog", {
+ version: "1.10.3",
+ options: {
+ appendTo: "body",
+ autoOpen: true,
+ buttons: [],
+ closeOnEscape: true,
+ closeText: "close",
+ dialogClass: "",
+ draggable: true,
+ hide: null,
+ height: "auto",
+ maxHeight: null,
+ maxWidth: null,
+ minHeight: 150,
+ minWidth: 150,
+ modal: false,
+ position: {
+ my: "center",
+ at: "center",
+ of: window,
+ collision: "fit",
+ // Ensure the titlebar is always visible
+ using: function( pos ) {
+ var topOffset = $( this ).css( pos ).offset().top;
+ if ( topOffset < 0 ) {
+ $( this ).css( "top", pos.top - topOffset );
+ }
+ }
+ },
+ resizable: true,
+ show: null,
+ title: null,
+ width: 300,
+
+ // callbacks
+ beforeClose: null,
+ close: null,
+ drag: null,
+ dragStart: null,
+ dragStop: null,
+ focus: null,
+ open: null,
+ resize: null,
+ resizeStart: null,
+ resizeStop: null
+ },
+
+ _create: function() {
+ this.originalCss = {
+ display: this.element[0].style.display,
+ width: this.element[0].style.width,
+ minHeight: this.element[0].style.minHeight,
+ maxHeight: this.element[0].style.maxHeight,
+ height: this.element[0].style.height
+ };
+ this.originalPosition = {
+ parent: this.element.parent(),
+ index: this.element.parent().children().index( this.element )
+ };
+ this.originalTitle = this.element.attr("title");
+ this.options.title = this.options.title || this.originalTitle;
+
+ this._createWrapper();
+
+ this.element
+ .show()
+ .removeAttr("title")
+ .addClass("ui-dialog-content ui-widget-content")
+ .appendTo( this.uiDialog );
+
+ this._createTitlebar();
+ this._createButtonPane();
+
+ if ( this.options.draggable && $.fn.draggable ) {
+ this._makeDraggable();
+ }
+ if ( this.options.resizable && $.fn.resizable ) {
+ this._makeResizable();
+ }
+
+ this._isOpen = false;
+ },
+
+ _init: function() {
+ if ( this.options.autoOpen ) {
+ this.open();
+ }
+ },
+
+ _appendTo: function() {
+ var element = this.options.appendTo;
+ if ( element && (element.jquery || element.nodeType) ) {
+ return $( element );
+ }
+ return this.document.find( element || "body" ).eq( 0 );
+ },
+
+ _destroy: function() {
+ var next,
+ originalPosition = this.originalPosition;
+
+ this._destroyOverlay();
+
+ this.element
+ .removeUniqueId()
+ .removeClass("ui-dialog-content ui-widget-content")
+ .css( this.originalCss )
+ // Without detaching first, the following becomes really slow
+ .detach();
+
+ this.uiDialog.stop( true, true ).remove();
+
+ if ( this.originalTitle ) {
+ this.element.attr( "title", this.originalTitle );
+ }
+
+ next = originalPosition.parent.children().eq( originalPosition.index );
+ // Don't try to place the dialog next to itself (#8613)
+ if ( next.length && next[0] !== this.element[0] ) {
+ next.before( this.element );
+ } else {
+ originalPosition.parent.append( this.element );
+ }
+ },
+
+ widget: function() {
+ return this.uiDialog;
+ },
+
+ disable: $.noop,
+ enable: $.noop,
+
+ close: function( event ) {
+ var that = this;
+
+ if ( !this._isOpen || this._trigger( "beforeClose", event ) === false ) {
+ return;
+ }
+
+ this._isOpen = false;
+ this._destroyOverlay();
+
+ if ( !this.opener.filter(":focusable").focus().length ) {
+ // Hiding a focused element doesn't trigger blur in WebKit
+ // so in case we have nothing to focus on, explicitly blur the active element
+ // https://bugs.webkit.org/show_bug.cgi?id=47182
+ $( this.document[0].activeElement ).blur();
+ }
+
+ this._hide( this.uiDialog, this.options.hide, function() {
+ that._trigger( "close", event );
+ });
+ },
+
+ isOpen: function() {
+ return this._isOpen;
+ },
+
+ moveToTop: function() {
+ this._moveToTop();
+ },
+
+ _moveToTop: function( event, silent ) {
+ var moved = !!this.uiDialog.nextAll(":visible").insertBefore( this.uiDialog ).length;
+ if ( moved && !silent ) {
+ this._trigger( "focus", event );
+ }
+ return moved;
+ },
+
+ open: function() {
+ var that = this;
+ if ( this._isOpen ) {
+ if ( this._moveToTop() ) {
+ this._focusTabbable();
+ }
+ return;
+ }
+
+ this._isOpen = true;
+ this.opener = $( this.document[0].activeElement );
+
+ this._size();
+ this._position();
+ this._createOverlay();
+ this._moveToTop( null, true );
+ this._show( this.uiDialog, this.options.show, function() {
+ that._focusTabbable();
+ that._trigger("focus");
+ });
+
+ this._trigger("open");
+ },
+
+ _focusTabbable: function() {
+ // Set focus to the first match:
+ // 1. First element inside the dialog matching [autofocus]
+ // 2. Tabbable element inside the content element
+ // 3. Tabbable element inside the buttonpane
+ // 4. The close button
+ // 5. The dialog itself
+ var hasFocus = this.element.find("[autofocus]");
+ if ( !hasFocus.length ) {
+ hasFocus = this.element.find(":tabbable");
+ }
+ if ( !hasFocus.length ) {
+ hasFocus = this.uiDialogButtonPane.find(":tabbable");
+ }
+ if ( !hasFocus.length ) {
+ hasFocus = this.uiDialogTitlebarClose.filter(":tabbable");
+ }
+ if ( !hasFocus.length ) {
+ hasFocus = this.uiDialog;
+ }
+ hasFocus.eq( 0 ).focus();
+ },
+
+ _keepFocus: function( event ) {
+ function checkFocus() {
+ var activeElement = this.document[0].activeElement,
+ isActive = this.uiDialog[0] === activeElement ||
+ $.contains( this.uiDialog[0], activeElement );
+ if ( !isActive ) {
+ this._focusTabbable();
+ }
+ }
+ event.preventDefault();
+ checkFocus.call( this );
+ // support: IE
+ // IE <= 8 doesn't prevent moving focus even with event.preventDefault()
+ // so we check again later
+ this._delay( checkFocus );
+ },
+
+ _createWrapper: function() {
+ this.uiDialog = $("<div>")
+ .addClass( "ui-dialog ui-widget ui-widget-content ui-corner-all ui-front " +
+ this.options.dialogClass )
+ .hide()
+ .attr({
+ // Setting tabIndex makes the div focusable
+ tabIndex: -1,
+ role: "dialog"
+ })
+ .appendTo( this._appendTo() );
+
+ this._on( this.uiDialog, {
+ keydown: function( event ) {
+ if ( this.options.closeOnEscape && !event.isDefaultPrevented() && event.keyCode &&
+ event.keyCode === $.ui.keyCode.ESCAPE ) {
+ event.preventDefault();
+ this.close( event );
+ return;
+ }
+
+ // prevent tabbing out of dialogs
+ if ( event.keyCode !== $.ui.keyCode.TAB ) {
+ return;
+ }
+ var tabbables = this.uiDialog.find(":tabbable"),
+ first = tabbables.filter(":first"),
+ last = tabbables.filter(":last");
+
+ if ( ( event.target === last[0] || event.target === this.uiDialog[0] ) && !event.shiftKey ) {
+ first.focus( 1 );
+ event.preventDefault();
+ } else if ( ( event.target === first[0] || event.target === this.uiDialog[0] ) && event.shiftKey ) {
+ last.focus( 1 );
+ event.preventDefault();
+ }
+ },
+ mousedown: function( event ) {
+ if ( this._moveToTop( event ) ) {
+ this._focusTabbable();
+ }
+ }
+ });
+
+ // We assume that any existing aria-describedby attribute means
+ // that the dialog content is marked up properly
+ // otherwise we brute force the content as the description
+ if ( !this.element.find("[aria-describedby]").length ) {
+ this.uiDialog.attr({
+ "aria-describedby": this.element.uniqueId().attr("id")
+ });
+ }
+ },
+
+ _createTitlebar: function() {
+ var uiDialogTitle;
+
+ this.uiDialogTitlebar = $("<div>")
+ .addClass("ui-dialog-titlebar ui-widget-header ui-corner-all ui-helper-clearfix")
+ .prependTo( this.uiDialog );
+ this._on( this.uiDialogTitlebar, {
+ mousedown: function( event ) {
+ // Don't prevent click on close button (#8838)
+ // Focusing a dialog that is partially scrolled out of view
+ // causes the browser to scroll it into view, preventing the click event
+ if ( !$( event.target ).closest(".ui-dialog-titlebar-close") ) {
+ // Dialog isn't getting focus when dragging (#8063)
+ this.uiDialog.focus();
+ }
+ }
+ });
+
+ this.uiDialogTitlebarClose = $("<button></button>")
+ .button({
+ label: this.options.closeText,
+ icons: {
+ primary: "ui-icon-closethick"
+ },
+ text: false
+ })
+ .addClass("ui-dialog-titlebar-close")
+ .appendTo( this.uiDialogTitlebar );
+ this._on( this.uiDialogTitlebarClose, {
+ click: function( event ) {
+ event.preventDefault();
+ this.close( event );
+ }
+ });
+
+ uiDialogTitle = $("<span>")
+ .uniqueId()
+ .addClass("ui-dialog-title")
+ .prependTo( this.uiDialogTitlebar );
+ this._title( uiDialogTitle );
+
+ this.uiDialog.attr({
+ "aria-labelledby": uiDialogTitle.attr("id")
+ });
+ },
+
+ _title: function( title ) {
+ if ( !this.options.title ) {
+ title.html("&#160;");
+ }
+ title.text( this.options.title );
+ },
+
+ _createButtonPane: function() {
+ this.uiDialogButtonPane = $("<div>")
+ .addClass("ui-dialog-buttonpane ui-widget-content ui-helper-clearfix");
+
+ this.uiButtonSet = $("<div>")
+ .addClass("ui-dialog-buttonset")
+ .appendTo( this.uiDialogButtonPane );
+
+ this._createButtons();
+ },
+
+ _createButtons: function() {
+ var that = this,
+ buttons = this.options.buttons;
+
+ // if we already have a button pane, remove it
+ this.uiDialogButtonPane.remove();
+ this.uiButtonSet.empty();
+
+ if ( $.isEmptyObject( buttons ) || ($.isArray( buttons ) && !buttons.length) ) {
+ this.uiDialog.removeClass("ui-dialog-buttons");
+ return;
+ }
+
+ $.each( buttons, function( name, props ) {
+ var click, buttonOptions;
+ props = $.isFunction( props ) ?
+ { click: props, text: name } :
+ props;
+ // Default to a non-submitting button
+ props = $.extend( { type: "button" }, props );
+ // Change the context for the click callback to be the main element
+ click = props.click;
+ props.click = function() {
+ click.apply( that.element[0], arguments );
+ };
+ buttonOptions = {
+ icons: props.icons,
+ text: props.showText
+ };
+ delete props.icons;
+ delete props.showText;
+ $( "<button></button>", props )
+ .button( buttonOptions )
+ .appendTo( that.uiButtonSet );
+ });
+ this.uiDialog.addClass("ui-dialog-buttons");
+ this.uiDialogButtonPane.appendTo( this.uiDialog );
+ },
+
+ _makeDraggable: function() {
+ var that = this,
+ options = this.options;
+
+ function filteredUi( ui ) {
+ return {
+ position: ui.position,
+ offset: ui.offset
+ };
+ }
+
+ this.uiDialog.draggable({
+ cancel: ".ui-dialog-content, .ui-dialog-titlebar-close",
+ handle: ".ui-dialog-titlebar",
+ containment: "document",
+ start: function( event, ui ) {
+ $( this ).addClass("ui-dialog-dragging");
+ that._blockFrames();
+ that._trigger( "dragStart", event, filteredUi( ui ) );
+ },
+ drag: function( event, ui ) {
+ that._trigger( "drag", event, filteredUi( ui ) );
+ },
+ stop: function( event, ui ) {
+ options.position = [
+ ui.position.left - that.document.scrollLeft(),
+ ui.position.top - that.document.scrollTop()
+ ];
+ $( this ).removeClass("ui-dialog-dragging");
+ that._unblockFrames();
+ that._trigger( "dragStop", event, filteredUi( ui ) );
+ }
+ });
+ },
+
+ _makeResizable: function() {
+ var that = this,
+ options = this.options,
+ handles = options.resizable,
+ // .ui-resizable has position: relative defined in the stylesheet
+ // but dialogs have to use absolute or fixed positioning
+ position = this.uiDialog.css("position"),
+ resizeHandles = typeof handles === "string" ?
+ handles :
+ "n,e,s,w,se,sw,ne,nw";
+
+ function filteredUi( ui ) {
+ return {
+ originalPosition: ui.originalPosition,
+ originalSize: ui.originalSize,
+ position: ui.position,
+ size: ui.size
+ };
+ }
+
+ this.uiDialog.resizable({
+ cancel: ".ui-dialog-content",
+ containment: "document",
+ alsoResize: this.element,
+ maxWidth: options.maxWidth,
+ maxHeight: options.maxHeight,
+ minWidth: options.minWidth,
+ minHeight: this._minHeight(),
+ handles: resizeHandles,
+ start: function( event, ui ) {
+ $( this ).addClass("ui-dialog-resizing");
+ that._blockFrames();
+ that._trigger( "resizeStart", event, filteredUi( ui ) );
+ },
+ resize: function( event, ui ) {
+ that._trigger( "resize", event, filteredUi( ui ) );
+ },
+ stop: function( event, ui ) {
+ options.height = $( this ).height();
+ options.width = $( this ).width();
+ $( this ).removeClass("ui-dialog-resizing");
+ that._unblockFrames();
+ that._trigger( "resizeStop", event, filteredUi( ui ) );
+ }
+ })
+ .css( "position", position );
+ },
+
+ _minHeight: function() {
+ var options = this.options;
+
+ return options.height === "auto" ?
+ options.minHeight :
+ Math.min( options.minHeight, options.height );
+ },
+
+ _position: function() {
+ // Need to show the dialog to get the actual offset in the position plugin
+ var isVisible = this.uiDialog.is(":visible");
+ if ( !isVisible ) {
+ this.uiDialog.show();
+ }
+ this.uiDialog.position( this.options.position );
+ if ( !isVisible ) {
+ this.uiDialog.hide();
+ }
+ },
+
+ _setOptions: function( options ) {
+ var that = this,
+ resize = false,
+ resizableOptions = {};
+
+ $.each( options, function( key, value ) {
+ that._setOption( key, value );
+
+ if ( key in sizeRelatedOptions ) {
+ resize = true;
+ }
+ if ( key in resizableRelatedOptions ) {
+ resizableOptions[ key ] = value;
+ }
+ });
+
+ if ( resize ) {
+ this._size();
+ this._position();
+ }
+ if ( this.uiDialog.is(":data(ui-resizable)") ) {
+ this.uiDialog.resizable( "option", resizableOptions );
+ }
+ },
+
+ _setOption: function( key, value ) {
+ /*jshint maxcomplexity:15*/
+ var isDraggable, isResizable,
+ uiDialog = this.uiDialog;
+
+ if ( key === "dialogClass" ) {
+ uiDialog
+ .removeClass( this.options.dialogClass )
+ .addClass( value );
+ }
+
+ if ( key === "disabled" ) {
+ return;
+ }
+
+ this._super( key, value );
+
+ if ( key === "appendTo" ) {
+ this.uiDialog.appendTo( this._appendTo() );
+ }
+
+ if ( key === "buttons" ) {
+ this._createButtons();
+ }
+
+ if ( key === "closeText" ) {
+ this.uiDialogTitlebarClose.button({
+ // Ensure that we always pass a string
+ label: "" + value
+ });
+ }
+
+ if ( key === "draggable" ) {
+ isDraggable = uiDialog.is(":data(ui-draggable)");
+ if ( isDraggable && !value ) {
+ uiDialog.draggable("destroy");
+ }
+
+ if ( !isDraggable && value ) {
+ this._makeDraggable();
+ }
+ }
+
+ if ( key === "position" ) {
+ this._position();
+ }
+
+ if ( key === "resizable" ) {
+ // currently resizable, becoming non-resizable
+ isResizable = uiDialog.is(":data(ui-resizable)");
+ if ( isResizable && !value ) {
+ uiDialog.resizable("destroy");
+ }
+
+ // currently resizable, changing handles
+ if ( isResizable && typeof value === "string" ) {
+ uiDialog.resizable( "option", "handles", value );
+ }
+
+ // currently non-resizable, becoming resizable
+ if ( !isResizable && value !== false ) {
+ this._makeResizable();
+ }
+ }
+
+ if ( key === "title" ) {
+ this._title( this.uiDialogTitlebar.find(".ui-dialog-title") );
+ }
+ },
+
+ _size: function() {
+ // If the user has resized the dialog, the .ui-dialog and .ui-dialog-content
+ // divs will both have width and height set, so we need to reset them
+ var nonContentHeight, minContentHeight, maxContentHeight,
+ options = this.options;
+
+ // Reset content sizing
+ this.element.show().css({
+ width: "auto",
+ minHeight: 0,
+ maxHeight: "none",
+ height: 0
+ });
+
+ if ( options.minWidth > options.width ) {
+ options.width = options.minWidth;
+ }
+
+ // reset wrapper sizing
+ // determine the height of all the non-content elements
+ nonContentHeight = this.uiDialog.css({
+ height: "auto",
+ width: options.width
+ })
+ .outerHeight();
+ minContentHeight = Math.max( 0, options.minHeight - nonContentHeight );
+ maxContentHeight = typeof options.maxHeight === "number" ?
+ Math.max( 0, options.maxHeight - nonContentHeight ) :
+ "none";
+
+ if ( options.height === "auto" ) {
+ this.element.css({
+ minHeight: minContentHeight,
+ maxHeight: maxContentHeight,
+ height: "auto"
+ });
+ } else {
+ this.element.height( Math.max( 0, options.height - nonContentHeight ) );
+ }
+
+ if (this.uiDialog.is(":data(ui-resizable)") ) {
+ this.uiDialog.resizable( "option", "minHeight", this._minHeight() );
+ }
+ },
+
+ _blockFrames: function() {
+ this.iframeBlocks = this.document.find( "iframe" ).map(function() {
+ var iframe = $( this );
+
+ return $( "<div>" )
+ .css({
+ position: "absolute",
+ width: iframe.outerWidth(),
+ height: iframe.outerHeight()
+ })
+ .appendTo( iframe.parent() )
+ .offset( iframe.offset() )[0];
+ });
+ },
+
+ _unblockFrames: function() {
+ if ( this.iframeBlocks ) {
+ this.iframeBlocks.remove();
+ delete this.iframeBlocks;
+ }
+ },
+
+ _allowInteraction: function( event ) {
+ if ( $( event.target ).closest(".ui-dialog").length ) {
+ return true;
+ }
+
+ // TODO: Remove hack when datepicker implements
+ // the .ui-front logic (#8989)
+ return !!$( event.target ).closest(".ui-datepicker").length;
+ },
+
+ _createOverlay: function() {
+ if ( !this.options.modal ) {
+ return;
+ }
+
+ var that = this,
+ widgetFullName = this.widgetFullName;
+ if ( !$.ui.dialog.overlayInstances ) {
+ // Prevent use of anchors and inputs.
+ // We use a delay in case the overlay is created from an
+ // event that we're going to be cancelling. (#2804)
+ this._delay(function() {
+ // Handle .dialog().dialog("close") (#4065)
+ if ( $.ui.dialog.overlayInstances ) {
+ this.document.bind( "focusin.dialog", function( event ) {
+ if ( !that._allowInteraction( event ) ) {
+ event.preventDefault();
+ $(".ui-dialog:visible:last .ui-dialog-content")
+ .data( widgetFullName )._focusTabbable();
+ }
+ });
+ }
+ });
+ }
+
+ this.overlay = $("<div>")
+ .addClass("ui-widget-overlay ui-front")
+ .appendTo( this._appendTo() );
+ this._on( this.overlay, {
+ mousedown: "_keepFocus"
+ });
+ $.ui.dialog.overlayInstances++;
+ },
+
+ _destroyOverlay: function() {
+ if ( !this.options.modal ) {
+ return;
+ }
+
+ if ( this.overlay ) {
+ $.ui.dialog.overlayInstances--;
+
+ if ( !$.ui.dialog.overlayInstances ) {
+ this.document.unbind( "focusin.dialog" );
+ }
+ this.overlay.remove();
+ this.overlay = null;
+ }
+ }
+});
+
+$.ui.dialog.overlayInstances = 0;
+
+// DEPRECATED
+if ( $.uiBackCompat !== false ) {
+ // position option with array notation
+ // just override with old implementation
+ $.widget( "ui.dialog", $.ui.dialog, {
+ _position: function() {
+ var position = this.options.position,
+ myAt = [],
+ offset = [ 0, 0 ],
+ isVisible;
+
+ if ( position ) {
+ if ( typeof position === "string" || (typeof position === "object" && "0" in position ) ) {
+ myAt = position.split ? position.split(" ") : [ position[0], position[1] ];
+ if ( myAt.length === 1 ) {
+ myAt[1] = myAt[0];
+ }
+
+ $.each( [ "left", "top" ], function( i, offsetPosition ) {
+ if ( +myAt[ i ] === myAt[ i ] ) {
+ offset[ i ] = myAt[ i ];
+ myAt[ i ] = offsetPosition;
+ }
+ });
+
+ position = {
+ my: myAt[0] + (offset[0] < 0 ? offset[0] : "+" + offset[0]) + " " +
+ myAt[1] + (offset[1] < 0 ? offset[1] : "+" + offset[1]),
+ at: myAt.join(" ")
+ };
+ }
+
+ position = $.extend( {}, $.ui.dialog.prototype.options.position, position );
+ } else {
+ position = $.ui.dialog.prototype.options.position;
+ }
+
+ // need to show the dialog to get the actual offset in the position plugin
+ isVisible = this.uiDialog.is(":visible");
+ if ( !isVisible ) {
+ this.uiDialog.show();
+ }
+ this.uiDialog.position( position );
+ if ( !isVisible ) {
+ this.uiDialog.hide();
+ }
+ }
+ });
+}
+
+}( jQuery ) );
diff --git a/debian/missing-sources/jquery-ui/jquery.ui.draggable.js b/debian/missing-sources/jquery-ui/jquery.ui.draggable.js
new file mode 100644
index 0000000..a52519b
--- /dev/null
+++ b/debian/missing-sources/jquery-ui/jquery.ui.draggable.js
@@ -0,0 +1,958 @@
+/*!
+ * jQuery UI Draggable 1.10.3
+ * http://jqueryui.com
+ *
+ * Copyright 2013 jQuery Foundation and other contributors
+ * Released under the MIT license.
+ * http://jquery.org/license
+ *
+ * http://api.jqueryui.com/draggable/
+ *
+ * Depends:
+ * jquery.ui.core.js
+ * jquery.ui.mouse.js
+ * jquery.ui.widget.js
+ */
+(function( $, undefined ) {
+
+$.widget("ui.draggable", $.ui.mouse, {
+ version: "1.10.3",
+ widgetEventPrefix: "drag",
+ options: {
+ addClasses: true,
+ appendTo: "parent",
+ axis: false,
+ connectToSortable: false,
+ containment: false,
+ cursor: "auto",
+ cursorAt: false,
+ grid: false,
+ handle: false,
+ helper: "original",
+ iframeFix: false,
+ opacity: false,
+ refreshPositions: false,
+ revert: false,
+ revertDuration: 500,
+ scope: "default",
+ scroll: true,
+ scrollSensitivity: 20,
+ scrollSpeed: 20,
+ snap: false,
+ snapMode: "both",
+ snapTolerance: 20,
+ stack: false,
+ zIndex: false,
+
+ // callbacks
+ drag: null,
+ start: null,
+ stop: null
+ },
+ _create: function() {
+
+ if (this.options.helper === "original" && !(/^(?:r|a|f)/).test(this.element.css("position"))) {
+ this.element[0].style.position = "relative";
+ }
+ if (this.options.addClasses){
+ this.element.addClass("ui-draggable");
+ }
+ if (this.options.disabled){
+ this.element.addClass("ui-draggable-disabled");
+ }
+
+ this._mouseInit();
+
+ },
+
+ _destroy: function() {
+ this.element.removeClass( "ui-draggable ui-draggable-dragging ui-draggable-disabled" );
+ this._mouseDestroy();
+ },
+
+ _mouseCapture: function(event) {
+
+ var o = this.options;
+
+ // among others, prevent a drag on a resizable-handle
+ if (this.helper || o.disabled || $(event.target).closest(".ui-resizable-handle").length > 0) {
+ return false;
+ }
+
+ //Quit if we're not on a valid handle
+ this.handle = this._getHandle(event);
+ if (!this.handle) {
+ return false;
+ }
+
+ $(o.iframeFix === true ? "iframe" : o.iframeFix).each(function() {
+ $("<div class='ui-draggable-iframeFix' style='background: #fff;'></div>")
+ .css({
+ width: this.offsetWidth+"px", height: this.offsetHeight+"px",
+ position: "absolute", opacity: "0.001", zIndex: 1000
+ })
+ .css($(this).offset())
+ .appendTo("body");
+ });
+
+ return true;
+
+ },
+
+ _mouseStart: function(event) {
+
+ var o = this.options;
+
+ //Create and append the visible helper
+ this.helper = this._createHelper(event);
+
+ this.helper.addClass("ui-draggable-dragging");
+
+ //Cache the helper size
+ this._cacheHelperProportions();
+
+ //If ddmanager is used for droppables, set the global draggable
+ if($.ui.ddmanager) {
+ $.ui.ddmanager.current = this;
+ }
+
+ /*
+ * - Position generation -
+ * This block generates everything position related - it's the core of draggables.
+ */
+
+ //Cache the margins of the original element
+ this._cacheMargins();
+
+ //Store the helper's css position
+ this.cssPosition = this.helper.css( "position" );
+ this.scrollParent = this.helper.scrollParent();
+ this.offsetParent = this.helper.offsetParent();
+ this.offsetParentCssPosition = this.offsetParent.css( "position" );
+
+ //The element's absolute position on the page minus margins
+ this.offset = this.positionAbs = this.element.offset();
+ this.offset = {
+ top: this.offset.top - this.margins.top,
+ left: this.offset.left - this.margins.left
+ };
+
+ //Reset scroll cache
+ this.offset.scroll = false;
+
+ $.extend(this.offset, {
+ click: { //Where the click happened, relative to the element
+ left: event.pageX - this.offset.left,
+ top: event.pageY - this.offset.top
+ },
+ parent: this._getParentOffset(),
+ relative: this._getRelativeOffset() //This is a relative to absolute position minus the actual position calculation - only used for relative positioned helper
+ });
+
+ //Generate the original position
+ this.originalPosition = this.position = this._generatePosition(event);
+ this.originalPageX = event.pageX;
+ this.originalPageY = event.pageY;
+
+ //Adjust the mouse offset relative to the helper if "cursorAt" is supplied
+ (o.cursorAt && this._adjustOffsetFromHelper(o.cursorAt));
+
+ //Set a containment if given in the options
+ this._setContainment();
+
+ //Trigger event + callbacks
+ if(this._trigger("start", event) === false) {
+ this._clear();
+ return false;
+ }
+
+ //Recache the helper size
+ this._cacheHelperProportions();
+
+ //Prepare the droppable offsets
+ if ($.ui.ddmanager && !o.dropBehaviour) {
+ $.ui.ddmanager.prepareOffsets(this, event);
+ }
+
+
+ this._mouseDrag(event, true); //Execute the drag once - this causes the helper not to be visible before getting its correct position
+
+ //If the ddmanager is used for droppables, inform the manager that dragging has started (see #5003)
+ if ( $.ui.ddmanager ) {
+ $.ui.ddmanager.dragStart(this, event);
+ }
+
+ return true;
+ },
+
+ _mouseDrag: function(event, noPropagation) {
+ // reset any necessary cached properties (see #5009)
+ if ( this.offsetParentCssPosition === "fixed" ) {
+ this.offset.parent = this._getParentOffset();
+ }
+
+ //Compute the helpers position
+ this.position = this._generatePosition(event);
+ this.positionAbs = this._convertPositionTo("absolute");
+
+ //Call plugins and callbacks and use the resulting position if something is returned
+ if (!noPropagation) {
+ var ui = this._uiHash();
+ if(this._trigger("drag", event, ui) === false) {
+ this._mouseUp({});
+ return false;
+ }
+ this.position = ui.position;
+ }
+
+ if(!this.options.axis || this.options.axis !== "y") {
+ this.helper[0].style.left = this.position.left+"px";
+ }
+ if(!this.options.axis || this.options.axis !== "x") {
+ this.helper[0].style.top = this.position.top+"px";
+ }
+ if($.ui.ddmanager) {
+ $.ui.ddmanager.drag(this, event);
+ }
+
+ return false;
+ },
+
+ _mouseStop: function(event) {
+
+ //If we are using droppables, inform the manager about the drop
+ var that = this,
+ dropped = false;
+ if ($.ui.ddmanager && !this.options.dropBehaviour) {
+ dropped = $.ui.ddmanager.drop(this, event);
+ }
+
+ //if a drop comes from outside (a sortable)
+ if(this.dropped) {
+ dropped = this.dropped;
+ this.dropped = false;
+ }
+
+ //if the original element is no longer in the DOM don't bother to continue (see #8269)
+ if ( this.options.helper === "original" && !$.contains( this.element[ 0 ].ownerDocument, this.element[ 0 ] ) ) {
+ return false;
+ }
+
+ if((this.options.revert === "invalid" && !dropped) || (this.options.revert === "valid" && dropped) || this.options.revert === true || ($.isFunction(this.options.revert) && this.options.revert.call(this.element, dropped))) {
+ $(this.helper).animate(this.originalPosition, parseInt(this.options.revertDuration, 10), function() {
+ if(that._trigger("stop", event) !== false) {
+ that._clear();
+ }
+ });
+ } else {
+ if(this._trigger("stop", event) !== false) {
+ this._clear();
+ }
+ }
+
+ return false;
+ },
+
+ _mouseUp: function(event) {
+ //Remove frame helpers
+ $("div.ui-draggable-iframeFix").each(function() {
+ this.parentNode.removeChild(this);
+ });
+
+ //If the ddmanager is used for droppables, inform the manager that dragging has stopped (see #5003)
+ if( $.ui.ddmanager ) {
+ $.ui.ddmanager.dragStop(this, event);
+ }
+
+ return $.ui.mouse.prototype._mouseUp.call(this, event);
+ },
+
+ cancel: function() {
+
+ if(this.helper.is(".ui-draggable-dragging")) {
+ this._mouseUp({});
+ } else {
+ this._clear();
+ }
+
+ return this;
+
+ },
+
+ _getHandle: function(event) {
+ return this.options.handle ?
+ !!$( event.target ).closest( this.element.find( this.options.handle ) ).length :
+ true;
+ },
+
+ _createHelper: function(event) {
+
+ var o = this.options,
+ helper = $.isFunction(o.helper) ? $(o.helper.apply(this.element[0], [event])) : (o.helper === "clone" ? this.element.clone().removeAttr("id") : this.element);
+
+ if(!helper.parents("body").length) {
+ helper.appendTo((o.appendTo === "parent" ? this.element[0].parentNode : o.appendTo));
+ }
+
+ if(helper[0] !== this.element[0] && !(/(fixed|absolute)/).test(helper.css("position"))) {
+ helper.css("position", "absolute");
+ }
+
+ return helper;
+
+ },
+
+ _adjustOffsetFromHelper: function(obj) {
+ if (typeof obj === "string") {
+ obj = obj.split(" ");
+ }
+ if ($.isArray(obj)) {
+ obj = {left: +obj[0], top: +obj[1] || 0};
+ }
+ if ("left" in obj) {
+ this.offset.click.left = obj.left + this.margins.left;
+ }
+ if ("right" in obj) {
+ this.offset.click.left = this.helperProportions.width - obj.right + this.margins.left;
+ }
+ if ("top" in obj) {
+ this.offset.click.top = obj.top + this.margins.top;
+ }
+ if ("bottom" in obj) {
+ this.offset.click.top = this.helperProportions.height - obj.bottom + this.margins.top;
+ }
+ },
+
+ _getParentOffset: function() {
+
+ //Get the offsetParent and cache its position
+ var po = this.offsetParent.offset();
+
+ // This is a special case where we need to modify a offset calculated on start, since the following happened:
+ // 1. The position of the helper is absolute, so it's position is calculated based on the next positioned parent
+ // 2. The actual offset parent is a child of the scroll parent, and the scroll parent isn't the document, which means that
+ // the scroll is included in the initial calculation of the offset of the parent, and never recalculated upon drag
+ if(this.cssPosition === "absolute" && this.scrollParent[0] !== document && $.contains(this.scrollParent[0], this.offsetParent[0])) {
+ po.left += this.scrollParent.scrollLeft();
+ po.top += this.scrollParent.scrollTop();
+ }
+
+ //This needs to be actually done for all browsers, since pageX/pageY includes this information
+ //Ugly IE fix
+ if((this.offsetParent[0] === document.body) ||
+ (this.offsetParent[0].tagName && this.offsetParent[0].tagName.toLowerCase() === "html" && $.ui.ie)) {
+ po = { top: 0, left: 0 };
+ }
+
+ return {
+ top: po.top + (parseInt(this.offsetParent.css("borderTopWidth"),10) || 0),
+ left: po.left + (parseInt(this.offsetParent.css("borderLeftWidth"),10) || 0)
+ };
+
+ },
+
+ _getRelativeOffset: function() {
+
+ if(this.cssPosition === "relative") {
+ var p = this.element.position();
+ return {
+ top: p.top - (parseInt(this.helper.css("top"),10) || 0) + this.scrollParent.scrollTop(),
+ left: p.left - (parseInt(this.helper.css("left"),10) || 0) + this.scrollParent.scrollLeft()
+ };
+ } else {
+ return { top: 0, left: 0 };
+ }
+
+ },
+
+ _cacheMargins: function() {
+ this.margins = {
+ left: (parseInt(this.element.css("marginLeft"),10) || 0),
+ top: (parseInt(this.element.css("marginTop"),10) || 0),
+ right: (parseInt(this.element.css("marginRight"),10) || 0),
+ bottom: (parseInt(this.element.css("marginBottom"),10) || 0)
+ };
+ },
+
+ _cacheHelperProportions: function() {
+ this.helperProportions = {
+ width: this.helper.outerWidth(),
+ height: this.helper.outerHeight()
+ };
+ },
+
+ _setContainment: function() {
+
+ var over, c, ce,
+ o = this.options;
+
+ if ( !o.containment ) {
+ this.containment = null;
+ return;
+ }
+
+ if ( o.containment === "window" ) {
+ this.containment = [
+ $( window ).scrollLeft() - this.offset.relative.left - this.offset.parent.left,
+ $( window ).scrollTop() - this.offset.relative.top - this.offset.parent.top,
+ $( window ).scrollLeft() + $( window ).width() - this.helperProportions.width - this.margins.left,
+ $( window ).scrollTop() + ( $( window ).height() || document.body.parentNode.scrollHeight ) - this.helperProportions.height - this.margins.top
+ ];
+ return;
+ }
+
+ if ( o.containment === "document") {
+ this.containment = [
+ 0,
+ 0,
+ $( document ).width() - this.helperProportions.width - this.margins.left,
+ ( $( document ).height() || document.body.parentNode.scrollHeight ) - this.helperProportions.height - this.margins.top
+ ];
+ return;
+ }
+
+ if ( o.containment.constructor === Array ) {
+ this.containment = o.containment;
+ return;
+ }
+
+ if ( o.containment === "parent" ) {
+ o.containment = this.helper[ 0 ].parentNode;
+ }
+
+ c = $( o.containment );
+ ce = c[ 0 ];
+
+ if( !ce ) {
+ return;
+ }
+
+ over = c.css( "overflow" ) !== "hidden";
+
+ this.containment = [
+ ( parseInt( c.css( "borderLeftWidth" ), 10 ) || 0 ) + ( parseInt( c.css( "paddingLeft" ), 10 ) || 0 ),
+ ( parseInt( c.css( "borderTopWidth" ), 10 ) || 0 ) + ( parseInt( c.css( "paddingTop" ), 10 ) || 0 ) ,
+ ( over ? Math.max( ce.scrollWidth, ce.offsetWidth ) : ce.offsetWidth ) - ( parseInt( c.css( "borderRightWidth" ), 10 ) || 0 ) - ( parseInt( c.css( "paddingRight" ), 10 ) || 0 ) - this.helperProportions.width - this.margins.left - this.margins.right,
+ ( over ? Math.max( ce.scrollHeight, ce.offsetHeight ) : ce.offsetHeight ) - ( parseInt( c.css( "borderBottomWidth" ), 10 ) || 0 ) - ( parseInt( c.css( "paddingBottom" ), 10 ) || 0 ) - this.helperProportions.height - this.margins.top - this.margins.bottom
+ ];
+ this.relative_container = c;
+ },
+
+ _convertPositionTo: function(d, pos) {
+
+ if(!pos) {
+ pos = this.position;
+ }
+
+ var mod = d === "absolute" ? 1 : -1,
+ scroll = this.cssPosition === "absolute" && !( this.scrollParent[ 0 ] !== document && $.contains( this.scrollParent[ 0 ], this.offsetParent[ 0 ] ) ) ? this.offsetParent : this.scrollParent;
+
+ //Cache the scroll
+ if (!this.offset.scroll) {
+ this.offset.scroll = {top : scroll.scrollTop(), left : scroll.scrollLeft()};
+ }
+
+ return {
+ top: (
+ pos.top + // The absolute mouse position
+ this.offset.relative.top * mod + // Only for relative positioned nodes: Relative offset from element to offset parent
+ this.offset.parent.top * mod - // The offsetParent's offset without borders (offset + border)
+ ( ( this.cssPosition === "fixed" ? -this.scrollParent.scrollTop() : this.offset.scroll.top ) * mod )
+ ),
+ left: (
+ pos.left + // The absolute mouse position
+ this.offset.relative.left * mod + // Only for relative positioned nodes: Relative offset from element to offset parent
+ this.offset.parent.left * mod - // The offsetParent's offset without borders (offset + border)
+ ( ( this.cssPosition === "fixed" ? -this.scrollParent.scrollLeft() : this.offset.scroll.left ) * mod )
+ )
+ };
+
+ },
+
+ _generatePosition: function(event) {
+
+ var containment, co, top, left,
+ o = this.options,
+ scroll = this.cssPosition === "absolute" && !( this.scrollParent[ 0 ] !== document && $.contains( this.scrollParent[ 0 ], this.offsetParent[ 0 ] ) ) ? this.offsetParent : this.scrollParent,
+ pageX = event.pageX,
+ pageY = event.pageY;
+
+ //Cache the scroll
+ if (!this.offset.scroll) {
+ this.offset.scroll = {top : scroll.scrollTop(), left : scroll.scrollLeft()};
+ }
+
+ /*
+ * - Position constraining -
+ * Constrain the position to a mix of grid, containment.
+ */
+
+ // If we are not dragging yet, we won't check for options
+ if ( this.originalPosition ) {
+ if ( this.containment ) {
+ if ( this.relative_container ){
+ co = this.relative_container.offset();
+ containment = [
+ this.containment[ 0 ] + co.left,
+ this.containment[ 1 ] + co.top,
+ this.containment[ 2 ] + co.left,
+ this.containment[ 3 ] + co.top
+ ];
+ }
+ else {
+ containment = this.containment;
+ }
+
+ if(event.pageX - this.offset.click.left < containment[0]) {
+ pageX = containment[0] + this.offset.click.left;
+ }
+ if(event.pageY - this.offset.click.top < containment[1]) {
+ pageY = containment[1] + this.offset.click.top;
+ }
+ if(event.pageX - this.offset.click.left > containment[2]) {
+ pageX = containment[2] + this.offset.click.left;
+ }
+ if(event.pageY - this.offset.click.top > containment[3]) {
+ pageY = containment[3] + this.offset.click.top;
+ }
+ }
+
+ if(o.grid) {
+ //Check for grid elements set to 0 to prevent divide by 0 error causing invalid argument errors in IE (see ticket #6950)
+ top = o.grid[1] ? this.originalPageY + Math.round((pageY - this.originalPageY) / o.grid[1]) * o.grid[1] : this.originalPageY;
+ pageY = containment ? ((top - this.offset.click.top >= containment[1] || top - this.offset.click.top > containment[3]) ? top : ((top - this.offset.click.top >= containment[1]) ? top - o.grid[1] : top + o.grid[1])) : top;
+
+ left = o.grid[0] ? this.originalPageX + Math.round((pageX - this.originalPageX) / o.grid[0]) * o.grid[0] : this.originalPageX;
+ pageX = containment ? ((left - this.offset.click.left >= containment[0] || left - this.offset.click.left > containment[2]) ? left : ((left - this.offset.click.left >= containment[0]) ? left - o.grid[0] : left + o.grid[0])) : left;
+ }
+
+ }
+
+ return {
+ top: (
+ pageY - // The absolute mouse position
+ this.offset.click.top - // Click offset (relative to the element)
+ this.offset.relative.top - // Only for relative positioned nodes: Relative offset from element to offset parent
+ this.offset.parent.top + // The offsetParent's offset without borders (offset + border)
+ ( this.cssPosition === "fixed" ? -this.scrollParent.scrollTop() : this.offset.scroll.top )
+ ),
+ left: (
+ pageX - // The absolute mouse position
+ this.offset.click.left - // Click offset (relative to the element)
+ this.offset.relative.left - // Only for relative positioned nodes: Relative offset from element to offset parent
+ this.offset.parent.left + // The offsetParent's offset without borders (offset + border)
+ ( this.cssPosition === "fixed" ? -this.scrollParent.scrollLeft() : this.offset.scroll.left )
+ )
+ };
+
+ },
+
+ _clear: function() {
+ this.helper.removeClass("ui-draggable-dragging");
+ if(this.helper[0] !== this.element[0] && !this.cancelHelperRemoval) {
+ this.helper.remove();
+ }
+ this.helper = null;
+ this.cancelHelperRemoval = false;
+ },
+
+ // From now on bulk stuff - mainly helpers
+
+ _trigger: function(type, event, ui) {
+ ui = ui || this._uiHash();
+ $.ui.plugin.call(this, type, [event, ui]);
+ //The absolute position has to be recalculated after plugins
+ if(type === "drag") {
+ this.positionAbs = this._convertPositionTo("absolute");
+ }
+ return $.Widget.prototype._trigger.call(this, type, event, ui);
+ },
+
+ plugins: {},
+
+ _uiHash: function() {
+ return {
+ helper: this.helper,
+ position: this.position,
+ originalPosition: this.originalPosition,
+ offset: this.positionAbs
+ };
+ }
+
+});
+
+$.ui.plugin.add("draggable", "connectToSortable", {
+ start: function(event, ui) {
+
+ var inst = $(this).data("ui-draggable"), o = inst.options,
+ uiSortable = $.extend({}, ui, { item: inst.element });
+ inst.sortables = [];
+ $(o.connectToSortable).each(function() {
+ var sortable = $.data(this, "ui-sortable");
+ if (sortable && !sortable.options.disabled) {
+ inst.sortables.push({
+ instance: sortable,
+ shouldRevert: sortable.options.revert
+ });
+ sortable.refreshPositions(); // Call the sortable's refreshPositions at drag start to refresh the containerCache since the sortable container cache is used in drag and needs to be up to date (this will ensure it's initialised as well as being kept in step with any changes that might have happened on the page).
+ sortable._trigger("activate", event, uiSortable);
+ }
+ });
+
+ },
+ stop: function(event, ui) {
+
+ //If we are still over the sortable, we fake the stop event of the sortable, but also remove helper
+ var inst = $(this).data("ui-draggable"),
+ uiSortable = $.extend({}, ui, { item: inst.element });
+
+ $.each(inst.sortables, function() {
+ if(this.instance.isOver) {
+
+ this.instance.isOver = 0;
+
+ inst.cancelHelperRemoval = true; //Don't remove the helper in the draggable instance
+ this.instance.cancelHelperRemoval = false; //Remove it in the sortable instance (so sortable plugins like revert still work)
+
+ //The sortable revert is supported, and we have to set a temporary dropped variable on the draggable to support revert: "valid/invalid"
+ if(this.shouldRevert) {
+ this.instance.options.revert = this.shouldRevert;
+ }
+
+ //Trigger the stop of the sortable
+ this.instance._mouseStop(event);
+
+ this.instance.options.helper = this.instance.options._helper;
+
+ //If the helper has been the original item, restore properties in the sortable
+ if(inst.options.helper === "original") {
+ this.instance.currentItem.css({ top: "auto", left: "auto" });
+ }
+
+ } else {
+ this.instance.cancelHelperRemoval = false; //Remove the helper in the sortable instance
+ this.instance._trigger("deactivate", event, uiSortable);
+ }
+
+ });
+
+ },
+ drag: function(event, ui) {
+
+ var inst = $(this).data("ui-draggable"), that = this;
+
+ $.each(inst.sortables, function() {
+
+ var innermostIntersecting = false,
+ thisSortable = this;
+
+ //Copy over some variables to allow calling the sortable's native _intersectsWith
+ this.instance.positionAbs = inst.positionAbs;
+ this.instance.helperProportions = inst.helperProportions;
+ this.instance.offset.click = inst.offset.click;
+
+ if(this.instance._intersectsWith(this.instance.containerCache)) {
+ innermostIntersecting = true;
+ $.each(inst.sortables, function () {
+ this.instance.positionAbs = inst.positionAbs;
+ this.instance.helperProportions = inst.helperProportions;
+ this.instance.offset.click = inst.offset.click;
+ if (this !== thisSortable &&
+ this.instance._intersectsWith(this.instance.containerCache) &&
+ $.contains(thisSortable.instance.element[0], this.instance.element[0])
+ ) {
+ innermostIntersecting = false;
+ }
+ return innermostIntersecting;
+ });
+ }
+
+
+ if(innermostIntersecting) {
+ //If it intersects, we use a little isOver variable and set it once, so our move-in stuff gets fired only once
+ if(!this.instance.isOver) {
+
+ this.instance.isOver = 1;
+ //Now we fake the start of dragging for the sortable instance,
+ //by cloning the list group item, appending it to the sortable and using it as inst.currentItem
+ //We can then fire the start event of the sortable with our passed browser event, and our own helper (so it doesn't create a new one)
+ this.instance.currentItem = $(that).clone().removeAttr("id").appendTo(this.instance.element).data("ui-sortable-item", true);
+ this.instance.options._helper = this.instance.options.helper; //Store helper option to later restore it
+ this.instance.options.helper = function() { return ui.helper[0]; };
+
+ event.target = this.instance.currentItem[0];
+ this.instance._mouseCapture(event, true);
+ this.instance._mouseStart(event, true, true);
+
+ //Because the browser event is way off the new appended portlet, we modify a couple of variables to reflect the changes
+ this.instance.offset.click.top = inst.offset.click.top;
+ this.instance.offset.click.left = inst.offset.click.left;
+ this.instance.offset.parent.left -= inst.offset.parent.left - this.instance.offset.parent.left;
+ this.instance.offset.parent.top -= inst.offset.parent.top - this.instance.offset.parent.top;
+
+ inst._trigger("toSortable", event);
+ inst.dropped = this.instance.element; //draggable revert needs that
+ //hack so receive/update callbacks work (mostly)
+ inst.currentItem = inst.element;
+ this.instance.fromOutside = inst;
+
+ }
+
+ //Provided we did all the previous steps, we can fire the drag event of the sortable on every draggable drag, when it intersects with the sortable
+ if(this.instance.currentItem) {
+ this.instance._mouseDrag(event);
+ }
+
+ } else {
+
+ //If it doesn't intersect with the sortable, and it intersected before,
+ //we fake the drag stop of the sortable, but make sure it doesn't remove the helper by using cancelHelperRemoval
+ if(this.instance.isOver) {
+
+ this.instance.isOver = 0;
+ this.instance.cancelHelperRemoval = true;
+
+ //Prevent reverting on this forced stop
+ this.instance.options.revert = false;
+
+ // The out event needs to be triggered independently
+ this.instance._trigger("out", event, this.instance._uiHash(this.instance));
+
+ this.instance._mouseStop(event, true);
+ this.instance.options.helper = this.instance.options._helper;
+
+ //Now we remove our currentItem, the list group clone again, and the placeholder, and animate the helper back to it's original size
+ this.instance.currentItem.remove();
+ if(this.instance.placeholder) {
+ this.instance.placeholder.remove();
+ }
+
+ inst._trigger("fromSortable", event);
+ inst.dropped = false; //draggable revert needs that
+ }
+
+ }
+
+ });
+
+ }
+});
+
+$.ui.plugin.add("draggable", "cursor", {
+ start: function() {
+ var t = $("body"), o = $(this).data("ui-draggable").options;
+ if (t.css("cursor")) {
+ o._cursor = t.css("cursor");
+ }
+ t.css("cursor", o.cursor);
+ },
+ stop: function() {
+ var o = $(this).data("ui-draggable").options;
+ if (o._cursor) {
+ $("body").css("cursor", o._cursor);
+ }
+ }
+});
+
+$.ui.plugin.add("draggable", "opacity", {
+ start: function(event, ui) {
+ var t = $(ui.helper), o = $(this).data("ui-draggable").options;
+ if(t.css("opacity")) {
+ o._opacity = t.css("opacity");
+ }
+ t.css("opacity", o.opacity);
+ },
+ stop: function(event, ui) {
+ var o = $(this).data("ui-draggable").options;
+ if(o._opacity) {
+ $(ui.helper).css("opacity", o._opacity);
+ }
+ }
+});
+
+$.ui.plugin.add("draggable", "scroll", {
+ start: function() {
+ var i = $(this).data("ui-draggable");
+ if(i.scrollParent[0] !== document && i.scrollParent[0].tagName !== "HTML") {
+ i.overflowOffset = i.scrollParent.offset();
+ }
+ },
+ drag: function( event ) {
+
+ var i = $(this).data("ui-draggable"), o = i.options, scrolled = false;
+
+ if(i.scrollParent[0] !== document && i.scrollParent[0].tagName !== "HTML") {
+
+ if(!o.axis || o.axis !== "x") {
+ if((i.overflowOffset.top + i.scrollParent[0].offsetHeight) - event.pageY < o.scrollSensitivity) {
+ i.scrollParent[0].scrollTop = scrolled = i.scrollParent[0].scrollTop + o.scrollSpeed;
+ } else if(event.pageY - i.overflowOffset.top < o.scrollSensitivity) {
+ i.scrollParent[0].scrollTop = scrolled = i.scrollParent[0].scrollTop - o.scrollSpeed;
+ }
+ }
+
+ if(!o.axis || o.axis !== "y") {
+ if((i.overflowOffset.left + i.scrollParent[0].offsetWidth) - event.pageX < o.scrollSensitivity) {
+ i.scrollParent[0].scrollLeft = scrolled = i.scrollParent[0].scrollLeft + o.scrollSpeed;
+ } else if(event.pageX - i.overflowOffset.left < o.scrollSensitivity) {
+ i.scrollParent[0].scrollLeft = scrolled = i.scrollParent[0].scrollLeft - o.scrollSpeed;
+ }
+ }
+
+ } else {
+
+ if(!o.axis || o.axis !== "x") {
+ if(event.pageY - $(document).scrollTop() < o.scrollSensitivity) {
+ scrolled = $(document).scrollTop($(document).scrollTop() - o.scrollSpeed);
+ } else if($(window).height() - (event.pageY - $(document).scrollTop()) < o.scrollSensitivity) {
+ scrolled = $(document).scrollTop($(document).scrollTop() + o.scrollSpeed);
+ }
+ }
+
+ if(!o.axis || o.axis !== "y") {
+ if(event.pageX - $(document).scrollLeft() < o.scrollSensitivity) {
+ scrolled = $(document).scrollLeft($(document).scrollLeft() - o.scrollSpeed);
+ } else if($(window).width() - (event.pageX - $(document).scrollLeft()) < o.scrollSensitivity) {
+ scrolled = $(document).scrollLeft($(document).scrollLeft() + o.scrollSpeed);
+ }
+ }
+
+ }
+
+ if(scrolled !== false && $.ui.ddmanager && !o.dropBehaviour) {
+ $.ui.ddmanager.prepareOffsets(i, event);
+ }
+
+ }
+});
+
+$.ui.plugin.add("draggable", "snap", {
+ start: function() {
+
+ var i = $(this).data("ui-draggable"),
+ o = i.options;
+
+ i.snapElements = [];
+
+ $(o.snap.constructor !== String ? ( o.snap.items || ":data(ui-draggable)" ) : o.snap).each(function() {
+ var $t = $(this),
+ $o = $t.offset();
+ if(this !== i.element[0]) {
+ i.snapElements.push({
+ item: this,
+ width: $t.outerWidth(), height: $t.outerHeight(),
+ top: $o.top, left: $o.left
+ });
+ }
+ });
+
+ },
+ drag: function(event, ui) {
+
+ var ts, bs, ls, rs, l, r, t, b, i, first,
+ inst = $(this).data("ui-draggable"),
+ o = inst.options,
+ d = o.snapTolerance,
+ x1 = ui.offset.left, x2 = x1 + inst.helperProportions.width,
+ y1 = ui.offset.top, y2 = y1 + inst.helperProportions.height;
+
+ for (i = inst.snapElements.length - 1; i >= 0; i--){
+
+ l = inst.snapElements[i].left;
+ r = l + inst.snapElements[i].width;
+ t = inst.snapElements[i].top;
+ b = t + inst.snapElements[i].height;
+
+ if ( x2 < l - d || x1 > r + d || y2 < t - d || y1 > b + d || !$.contains( inst.snapElements[ i ].item.ownerDocument, inst.snapElements[ i ].item ) ) {
+ if(inst.snapElements[i].snapping) {
+ (inst.options.snap.release && inst.options.snap.release.call(inst.element, event, $.extend(inst._uiHash(), { snapItem: inst.snapElements[i].item })));
+ }
+ inst.snapElements[i].snapping = false;
+ continue;
+ }
+
+ if(o.snapMode !== "inner") {
+ ts = Math.abs(t - y2) <= d;
+ bs = Math.abs(b - y1) <= d;
+ ls = Math.abs(l - x2) <= d;
+ rs = Math.abs(r - x1) <= d;
+ if(ts) {
+ ui.position.top = inst._convertPositionTo("relative", { top: t - inst.helperProportions.height, left: 0 }).top - inst.margins.top;
+ }
+ if(bs) {
+ ui.position.top = inst._convertPositionTo("relative", { top: b, left: 0 }).top - inst.margins.top;
+ }
+ if(ls) {
+ ui.position.left = inst._convertPositionTo("relative", { top: 0, left: l - inst.helperProportions.width }).left - inst.margins.left;
+ }
+ if(rs) {
+ ui.position.left = inst._convertPositionTo("relative", { top: 0, left: r }).left - inst.margins.left;
+ }
+ }
+
+ first = (ts || bs || ls || rs);
+
+ if(o.snapMode !== "outer") {
+ ts = Math.abs(t - y1) <= d;
+ bs = Math.abs(b - y2) <= d;
+ ls = Math.abs(l - x1) <= d;
+ rs = Math.abs(r - x2) <= d;
+ if(ts) {
+ ui.position.top = inst._convertPositionTo("relative", { top: t, left: 0 }).top - inst.margins.top;
+ }
+ if(bs) {
+ ui.position.top = inst._convertPositionTo("relative", { top: b - inst.helperProportions.height, left: 0 }).top - inst.margins.top;
+ }
+ if(ls) {
+ ui.position.left = inst._convertPositionTo("relative", { top: 0, left: l }).left - inst.margins.left;
+ }
+ if(rs) {
+ ui.position.left = inst._convertPositionTo("relative", { top: 0, left: r - inst.helperProportions.width }).left - inst.margins.left;
+ }
+ }
+
+ if(!inst.snapElements[i].snapping && (ts || bs || ls || rs || first)) {
+ (inst.options.snap.snap && inst.options.snap.snap.call(inst.element, event, $.extend(inst._uiHash(), { snapItem: inst.snapElements[i].item })));
+ }
+ inst.snapElements[i].snapping = (ts || bs || ls || rs || first);
+
+ }
+
+ }
+});
+
+$.ui.plugin.add("draggable", "stack", {
+ start: function() {
+ var min,
+ o = this.data("ui-draggable").options,
+ group = $.makeArray($(o.stack)).sort(function(a,b) {
+ return (parseInt($(a).css("zIndex"),10) || 0) - (parseInt($(b).css("zIndex"),10) || 0);
+ });
+
+ if (!group.length) { return; }
+
+ min = parseInt($(group[0]).css("zIndex"), 10) || 0;
+ $(group).each(function(i) {
+ $(this).css("zIndex", min + i);
+ });
+ this.css("zIndex", (min + group.length));
+ }
+});
+
+$.ui.plugin.add("draggable", "zIndex", {
+ start: function(event, ui) {
+ var t = $(ui.helper), o = $(this).data("ui-draggable").options;
+ if(t.css("zIndex")) {
+ o._zIndex = t.css("zIndex");
+ }
+ t.css("zIndex", o.zIndex);
+ },
+ stop: function(event, ui) {
+ var o = $(this).data("ui-draggable").options;
+ if(o._zIndex) {
+ $(ui.helper).css("zIndex", o._zIndex);
+ }
+ }
+});
+
+})(jQuery);
diff --git a/debian/missing-sources/jquery-ui/jquery.ui.droppable.js b/debian/missing-sources/jquery-ui/jquery.ui.droppable.js
new file mode 100644
index 0000000..24337d0
--- /dev/null
+++ b/debian/missing-sources/jquery-ui/jquery.ui.droppable.js
@@ -0,0 +1,372 @@
+/*!
+ * jQuery UI Droppable 1.10.3
+ * http://jqueryui.com
+ *
+ * Copyright 2013 jQuery Foundation and other contributors
+ * Released under the MIT license.
+ * http://jquery.org/license
+ *
+ * http://api.jqueryui.com/droppable/
+ *
+ * Depends:
+ * jquery.ui.core.js
+ * jquery.ui.widget.js
+ * jquery.ui.mouse.js
+ * jquery.ui.draggable.js
+ */
+(function( $, undefined ) {
+
+function isOverAxis( x, reference, size ) {
+ return ( x > reference ) && ( x < ( reference + size ) );
+}
+
+$.widget("ui.droppable", {
+ version: "1.10.3",
+ widgetEventPrefix: "drop",
+ options: {
+ accept: "*",
+ activeClass: false,
+ addClasses: true,
+ greedy: false,
+ hoverClass: false,
+ scope: "default",
+ tolerance: "intersect",
+
+ // callbacks
+ activate: null,
+ deactivate: null,
+ drop: null,
+ out: null,
+ over: null
+ },
+ _create: function() {
+
+ var o = this.options,
+ accept = o.accept;
+
+ this.isover = false;
+ this.isout = true;
+
+ this.accept = $.isFunction(accept) ? accept : function(d) {
+ return d.is(accept);
+ };
+
+ //Store the droppable's proportions
+ this.proportions = { width: this.element[0].offsetWidth, height: this.element[0].offsetHeight };
+
+ // Add the reference and positions to the manager
+ $.ui.ddmanager.droppables[o.scope] = $.ui.ddmanager.droppables[o.scope] || [];
+ $.ui.ddmanager.droppables[o.scope].push(this);
+
+ (o.addClasses && this.element.addClass("ui-droppable"));
+
+ },
+
+ _destroy: function() {
+ var i = 0,
+ drop = $.ui.ddmanager.droppables[this.options.scope];
+
+ for ( ; i < drop.length; i++ ) {
+ if ( drop[i] === this ) {
+ drop.splice(i, 1);
+ }
+ }
+
+ this.element.removeClass("ui-droppable ui-droppable-disabled");
+ },
+
+ _setOption: function(key, value) {
+
+ if(key === "accept") {
+ this.accept = $.isFunction(value) ? value : function(d) {
+ return d.is(value);
+ };
+ }
+ $.Widget.prototype._setOption.apply(this, arguments);
+ },
+
+ _activate: function(event) {
+ var draggable = $.ui.ddmanager.current;
+ if(this.options.activeClass) {
+ this.element.addClass(this.options.activeClass);
+ }
+ if(draggable){
+ this._trigger("activate", event, this.ui(draggable));
+ }
+ },
+
+ _deactivate: function(event) {
+ var draggable = $.ui.ddmanager.current;
+ if(this.options.activeClass) {
+ this.element.removeClass(this.options.activeClass);
+ }
+ if(draggable){
+ this._trigger("deactivate", event, this.ui(draggable));
+ }
+ },
+
+ _over: function(event) {
+
+ var draggable = $.ui.ddmanager.current;
+
+ // Bail if draggable and droppable are same element
+ if (!draggable || (draggable.currentItem || draggable.element)[0] === this.element[0]) {
+ return;
+ }
+
+ if (this.accept.call(this.element[0],(draggable.currentItem || draggable.element))) {
+ if(this.options.hoverClass) {
+ this.element.addClass(this.options.hoverClass);
+ }
+ this._trigger("over", event, this.ui(draggable));
+ }
+
+ },
+
+ _out: function(event) {
+
+ var draggable = $.ui.ddmanager.current;
+
+ // Bail if draggable and droppable are same element
+ if (!draggable || (draggable.currentItem || draggable.element)[0] === this.element[0]) {
+ return;
+ }
+
+ if (this.accept.call(this.element[0],(draggable.currentItem || draggable.element))) {
+ if(this.options.hoverClass) {
+ this.element.removeClass(this.options.hoverClass);
+ }
+ this._trigger("out", event, this.ui(draggable));
+ }
+
+ },
+
+ _drop: function(event,custom) {
+
+ var draggable = custom || $.ui.ddmanager.current,
+ childrenIntersection = false;
+
+ // Bail if draggable and droppable are same element
+ if (!draggable || (draggable.currentItem || draggable.element)[0] === this.element[0]) {
+ return false;
+ }
+
+ this.element.find(":data(ui-droppable)").not(".ui-draggable-dragging").each(function() {
+ var inst = $.data(this, "ui-droppable");
+ if(
+ inst.options.greedy &&
+ !inst.options.disabled &&
+ inst.options.scope === draggable.options.scope &&
+ inst.accept.call(inst.element[0], (draggable.currentItem || draggable.element)) &&
+ $.ui.intersect(draggable, $.extend(inst, { offset: inst.element.offset() }), inst.options.tolerance)
+ ) { childrenIntersection = true; return false; }
+ });
+ if(childrenIntersection) {
+ return false;
+ }
+
+ if(this.accept.call(this.element[0],(draggable.currentItem || draggable.element))) {
+ if(this.options.activeClass) {
+ this.element.removeClass(this.options.activeClass);
+ }
+ if(this.options.hoverClass) {
+ this.element.removeClass(this.options.hoverClass);
+ }
+ this._trigger("drop", event, this.ui(draggable));
+ return this.element;
+ }
+
+ return false;
+
+ },
+
+ ui: function(c) {
+ return {
+ draggable: (c.currentItem || c.element),
+ helper: c.helper,
+ position: c.position,
+ offset: c.positionAbs
+ };
+ }
+
+});
+
+$.ui.intersect = function(draggable, droppable, toleranceMode) {
+
+ if (!droppable.offset) {
+ return false;
+ }
+
+ var draggableLeft, draggableTop,
+ x1 = (draggable.positionAbs || draggable.position.absolute).left, x2 = x1 + draggable.helperProportions.width,
+ y1 = (draggable.positionAbs || draggable.position.absolute).top, y2 = y1 + draggable.helperProportions.height,
+ l = droppable.offset.left, r = l + droppable.proportions.width,
+ t = droppable.offset.top, b = t + droppable.proportions.height;
+
+ switch (toleranceMode) {
+ case "fit":
+ return (l <= x1 && x2 <= r && t <= y1 && y2 <= b);
+ case "intersect":
+ return (l < x1 + (draggable.helperProportions.width / 2) && // Right Half
+ x2 - (draggable.helperProportions.width / 2) < r && // Left Half
+ t < y1 + (draggable.helperProportions.height / 2) && // Bottom Half
+ y2 - (draggable.helperProportions.height / 2) < b ); // Top Half
+ case "pointer":
+ draggableLeft = ((draggable.positionAbs || draggable.position.absolute).left + (draggable.clickOffset || draggable.offset.click).left);
+ draggableTop = ((draggable.positionAbs || draggable.position.absolute).top + (draggable.clickOffset || draggable.offset.click).top);
+ return isOverAxis( draggableTop, t, droppable.proportions.height ) && isOverAxis( draggableLeft, l, droppable.proportions.width );
+ case "touch":
+ return (
+ (y1 >= t && y1 <= b) || // Top edge touching
+ (y2 >= t && y2 <= b) || // Bottom edge touching
+ (y1 < t && y2 > b) // Surrounded vertically
+ ) && (
+ (x1 >= l && x1 <= r) || // Left edge touching
+ (x2 >= l && x2 <= r) || // Right edge touching
+ (x1 < l && x2 > r) // Surrounded horizontally
+ );
+ default:
+ return false;
+ }
+
+};
+
+/*
+ This manager tracks offsets of draggables and droppables
+*/
+$.ui.ddmanager = {
+ current: null,
+ droppables: { "default": [] },
+ prepareOffsets: function(t, event) {
+
+ var i, j,
+ m = $.ui.ddmanager.droppables[t.options.scope] || [],
+ type = event ? event.type : null, // workaround for #2317
+ list = (t.currentItem || t.element).find(":data(ui-droppable)").addBack();
+
+ droppablesLoop: for (i = 0; i < m.length; i++) {
+
+ //No disabled and non-accepted
+ if(m[i].options.disabled || (t && !m[i].accept.call(m[i].element[0],(t.currentItem || t.element)))) {
+ continue;
+ }
+
+ // Filter out elements in the current dragged item
+ for (j=0; j < list.length; j++) {
+ if(list[j] === m[i].element[0]) {
+ m[i].proportions.height = 0;
+ continue droppablesLoop;
+ }
+ }
+
+ m[i].visible = m[i].element.css("display") !== "none";
+ if(!m[i].visible) {
+ continue;
+ }
+
+ //Activate the droppable if used directly from draggables
+ if(type === "mousedown") {
+ m[i]._activate.call(m[i], event);
+ }
+
+ m[i].offset = m[i].element.offset();
+ m[i].proportions = { width: m[i].element[0].offsetWidth, height: m[i].element[0].offsetHeight };
+
+ }
+
+ },
+ drop: function(draggable, event) {
+
+ var dropped = false;
+ // Create a copy of the droppables in case the list changes during the drop (#9116)
+ $.each(($.ui.ddmanager.droppables[draggable.options.scope] || []).slice(), function() {
+
+ if(!this.options) {
+ return;
+ }
+ if (!this.options.disabled && this.visible && $.ui.intersect(draggable, this, this.options.tolerance)) {
+ dropped = this._drop.call(this, event) || dropped;
+ }
+
+ if (!this.options.disabled && this.visible && this.accept.call(this.element[0],(draggable.currentItem || draggable.element))) {
+ this.isout = true;
+ this.isover = false;
+ this._deactivate.call(this, event);
+ }
+
+ });
+ return dropped;
+
+ },
+ dragStart: function( draggable, event ) {
+ //Listen for scrolling so that if the dragging causes scrolling the position of the droppables can be recalculated (see #5003)
+ draggable.element.parentsUntil( "body" ).bind( "scroll.droppable", function() {
+ if( !draggable.options.refreshPositions ) {
+ $.ui.ddmanager.prepareOffsets( draggable, event );
+ }
+ });
+ },
+ drag: function(draggable, event) {
+
+ //If you have a highly dynamic page, you might try this option. It renders positions every time you move the mouse.
+ if(draggable.options.refreshPositions) {
+ $.ui.ddmanager.prepareOffsets(draggable, event);
+ }
+
+ //Run through all droppables and check their positions based on specific tolerance options
+ $.each($.ui.ddmanager.droppables[draggable.options.scope] || [], function() {
+
+ if(this.options.disabled || this.greedyChild || !this.visible) {
+ return;
+ }
+
+ var parentInstance, scope, parent,
+ intersects = $.ui.intersect(draggable, this, this.options.tolerance),
+ c = !intersects && this.isover ? "isout" : (intersects && !this.isover ? "isover" : null);
+ if(!c) {
+ return;
+ }
+
+ if (this.options.greedy) {
+ // find droppable parents with same scope
+ scope = this.options.scope;
+ parent = this.element.parents(":data(ui-droppable)").filter(function () {
+ return $.data(this, "ui-droppable").options.scope === scope;
+ });
+
+ if (parent.length) {
+ parentInstance = $.data(parent[0], "ui-droppable");
+ parentInstance.greedyChild = (c === "isover");
+ }
+ }
+
+ // we just moved into a greedy child
+ if (parentInstance && c === "isover") {
+ parentInstance.isover = false;
+ parentInstance.isout = true;
+ parentInstance._out.call(parentInstance, event);
+ }
+
+ this[c] = true;
+ this[c === "isout" ? "isover" : "isout"] = false;
+ this[c === "isover" ? "_over" : "_out"].call(this, event);
+
+ // we just moved out of a greedy child
+ if (parentInstance && c === "isout") {
+ parentInstance.isout = false;
+ parentInstance.isover = true;
+ parentInstance._over.call(parentInstance, event);
+ }
+ });
+
+ },
+ dragStop: function( draggable, event ) {
+ draggable.element.parentsUntil( "body" ).unbind( "scroll.droppable" );
+ //Call prepareOffsets one final time since IE does not fire return scroll events when overflow was caused by drag (see #5003)
+ if( !draggable.options.refreshPositions ) {
+ $.ui.ddmanager.prepareOffsets( draggable, event );
+ }
+ }
+};
+
+})(jQuery);
diff --git a/debian/missing-sources/jquery-ui/jquery.ui.effect-blind.js b/debian/missing-sources/jquery-ui/jquery.ui.effect-blind.js
new file mode 100644
index 0000000..83f7497
--- /dev/null
+++ b/debian/missing-sources/jquery-ui/jquery.ui.effect-blind.js
@@ -0,0 +1,82 @@
+/*!
+ * jQuery UI Effects Blind 1.10.3
+ * http://jqueryui.com
+ *
+ * Copyright 2013 jQuery Foundation and other contributors
+ * Released under the MIT license.
+ * http://jquery.org/license
+ *
+ * http://api.jqueryui.com/blind-effect/
+ *
+ * Depends:
+ * jquery.ui.effect.js
+ */
+(function( $, undefined ) {
+
+var rvertical = /up|down|vertical/,
+ rpositivemotion = /up|left|vertical|horizontal/;
+
+$.effects.effect.blind = function( o, done ) {
+ // Create element
+ var el = $( this ),
+ props = [ "position", "top", "bottom", "left", "right", "height", "width" ],
+ mode = $.effects.setMode( el, o.mode || "hide" ),
+ direction = o.direction || "up",
+ vertical = rvertical.test( direction ),
+ ref = vertical ? "height" : "width",
+ ref2 = vertical ? "top" : "left",
+ motion = rpositivemotion.test( direction ),
+ animation = {},
+ show = mode === "show",
+ wrapper, distance, margin;
+
+ // if already wrapped, the wrapper's properties are my property. #6245
+ if ( el.parent().is( ".ui-effects-wrapper" ) ) {
+ $.effects.save( el.parent(), props );
+ } else {
+ $.effects.save( el, props );
+ }
+ el.show();
+ wrapper = $.effects.createWrapper( el ).css({
+ overflow: "hidden"
+ });
+
+ distance = wrapper[ ref ]();
+ margin = parseFloat( wrapper.css( ref2 ) ) || 0;
+
+ animation[ ref ] = show ? distance : 0;
+ if ( !motion ) {
+ el
+ .css( vertical ? "bottom" : "right", 0 )
+ .css( vertical ? "top" : "left", "auto" )
+ .css({ position: "absolute" });
+
+ animation[ ref2 ] = show ? margin : distance + margin;
+ }
+
+ // start at 0 if we are showing
+ if ( show ) {
+ wrapper.css( ref, 0 );
+ if ( ! motion ) {
+ wrapper.css( ref2, margin + distance );
+ }
+ }
+
+ // Animate
+ wrapper.animate( animation, {
+ duration: o.duration,
+ easing: o.easing,
+ queue: false,
+ complete: function() {
+ if ( mode === "hide" ) {
+ el.hide();
+ }
+ $.effects.restore( el, props );
+ $.effects.removeWrapper( el );
+ done();
+ }
+ });
+
+};
+
+})(jQuery);
diff --git a/debian/missing-sources/jquery-ui/jquery.ui.effect-bounce.js b/debian/missing-sources/jquery-ui/jquery.ui.effect-bounce.js
new file mode 100644
index 0000000..e518a1e
--- /dev/null
+++ b/debian/missing-sources/jquery-ui/jquery.ui.effect-bounce.js
@@ -0,0 +1,113 @@
+/*!
+ * jQuery UI Effects Bounce 1.10.3
+ * http://jqueryui.com
+ *
+ * Copyright 2013 jQuery Foundation and other contributors
+ * Released under the MIT license.
+ * http://jquery.org/license
+ *
+ * http://api.jqueryui.com/bounce-effect/
+ *
+ * Depends:
+ * jquery.ui.effect.js
+ */
+(function( $, undefined ) {
+
+$.effects.effect.bounce = function( o, done ) {
+ var el = $( this ),
+ props = [ "position", "top", "bottom", "left", "right", "height", "width" ],
+
+ // defaults:
+ mode = $.effects.setMode( el, o.mode || "effect" ),
+ hide = mode === "hide",
+ show = mode === "show",
+ direction = o.direction || "up",
+ distance = o.distance,
+ times = o.times || 5,
+
+ // number of internal animations
+ anims = times * 2 + ( show || hide ? 1 : 0 ),
+ speed = o.duration / anims,
+ easing = o.easing,
+
+ // utility:
+ ref = ( direction === "up" || direction === "down" ) ? "top" : "left",
+ motion = ( direction === "up" || direction === "left" ),
+ i,
+ upAnim,
+ downAnim,
+
+ // we will need to re-assemble the queue to stack our animations in place
+ queue = el.queue(),
+ queuelen = queue.length;
+
+ // Avoid touching opacity to prevent clearType and PNG issues in IE
+ if ( show || hide ) {
+ props.push( "opacity" );
+ }
+
+ $.effects.save( el, props );
+ el.show();
+ $.effects.createWrapper( el ); // Create Wrapper
+
+ // default distance for the BIGGEST bounce is the outer Distance / 3
+ if ( !distance ) {
+ distance = el[ ref === "top" ? "outerHeight" : "outerWidth" ]() / 3;
+ }
+
+ if ( show ) {
+ downAnim = { opacity: 1 };
+ downAnim[ ref ] = 0;
+
+ // if we are showing, force opacity 0 and set the initial position
+ // then do the "first" animation
+ el.css( "opacity", 0 )
+ .css( ref, motion ? -distance * 2 : distance * 2 )
+ .animate( downAnim, speed, easing );
+ }
+
+ // start at the smallest distance if we are hiding
+ if ( hide ) {
+ distance = distance / Math.pow( 2, times - 1 );
+ }
+
+ downAnim = {};
+ downAnim[ ref ] = 0;
+ // Bounces up/down/left/right then back to 0 -- times * 2 animations happen here
+ for ( i = 0; i < times; i++ ) {
+ upAnim = {};
+ upAnim[ ref ] = ( motion ? "-=" : "+=" ) + distance;
+
+ el.animate( upAnim, speed, easing )
+ .animate( downAnim, speed, easing );
+
+ distance = hide ? distance * 2 : distance / 2;
+ }
+
+ // Last Bounce when Hiding
+ if ( hide ) {
+ upAnim = { opacity: 0 };
+ upAnim[ ref ] = ( motion ? "-=" : "+=" ) + distance;
+
+ el.animate( upAnim, speed, easing );
+ }
+
+ el.queue(function() {
+ if ( hide ) {
+ el.hide();
+ }
+ $.effects.restore( el, props );
+ $.effects.removeWrapper( el );
+ done();
+ });
+
+ // inject all the animations we just queued to be first in line (after "inprogress")
+ if ( queuelen > 1) {
+ queue.splice.apply( queue,
+ [ 1, 0 ].concat( queue.splice( queuelen, anims + 1 ) ) );
+ }
+ el.dequeue();
+
+};
+
+})(jQuery);
diff --git a/debian/missing-sources/jquery-ui/jquery.ui.effect-clip.js b/debian/missing-sources/jquery-ui/jquery.ui.effect-clip.js
new file mode 100644
index 0000000..4c2c2dc
--- /dev/null
+++ b/debian/missing-sources/jquery-ui/jquery.ui.effect-clip.js
@@ -0,0 +1,67 @@
+/*!
+ * jQuery UI Effects Clip 1.10.3
+ * http://jqueryui.com
+ *
+ * Copyright 2013 jQuery Foundation and other contributors
+ * Released under the MIT license.
+ * http://jquery.org/license
+ *
+ * http://api.jqueryui.com/clip-effect/
+ *
+ * Depends:
+ * jquery.ui.effect.js
+ */
+(function( $, undefined ) {
+
+$.effects.effect.clip = function( o, done ) {
+ // Create element
+ var el = $( this ),
+ props = [ "position", "top", "bottom", "left", "right", "height", "width" ],
+ mode = $.effects.setMode( el, o.mode || "hide" ),
+ show = mode === "show",
+ direction = o.direction || "vertical",
+ vert = direction === "vertical",
+ size = vert ? "height" : "width",
+ position = vert ? "top" : "left",
+ animation = {},
+ wrapper, animate, distance;
+
+ // Save & Show
+ $.effects.save( el, props );
+ el.show();
+
+ // Create Wrapper
+ wrapper = $.effects.createWrapper( el ).css({
+ overflow: "hidden"
+ });
+ animate = ( el[0].tagName === "IMG" ) ? wrapper : el;
+ distance = animate[ size ]();
+
+ // Shift
+ if ( show ) {
+ animate.css( size, 0 );
+ animate.css( position, distance / 2 );
+ }
+
+ // Create Animation Object:
+ animation[ size ] = show ? distance : 0;
+ animation[ position ] = show ? 0 : distance / 2;
+
+ // Animate
+ animate.animate( animation, {
+ queue: false,
+ duration: o.duration,
+ easing: o.easing,
+ complete: function() {
+ if ( !show ) {
+ el.hide();
+ }
+ $.effects.restore( el, props );
+ $.effects.removeWrapper( el );
+ done();
+ }
+ });
+
+};
+
+})(jQuery);
diff --git a/debian/missing-sources/jquery-ui/jquery.ui.effect-drop.js b/debian/missing-sources/jquery-ui/jquery.ui.effect-drop.js
new file mode 100644
index 0000000..21c0737
--- /dev/null
+++ b/debian/missing-sources/jquery-ui/jquery.ui.effect-drop.js
@@ -0,0 +1,65 @@
+/*!
+ * jQuery UI Effects Drop 1.10.3
+ * http://jqueryui.com
+ *
+ * Copyright 2013 jQuery Foundation and other contributors
+ * Released under the MIT license.
+ * http://jquery.org/license
+ *
+ * http://api.jqueryui.com/drop-effect/
+ *
+ * Depends:
+ * jquery.ui.effect.js
+ */
+(function( $, undefined ) {
+
+$.effects.effect.drop = function( o, done ) {
+
+ var el = $( this ),
+ props = [ "position", "top", "bottom", "left", "right", "opacity", "height", "width" ],
+ mode = $.effects.setMode( el, o.mode || "hide" ),
+ show = mode === "show",
+ direction = o.direction || "left",
+ ref = ( direction === "up" || direction === "down" ) ? "top" : "left",
+ motion = ( direction === "up" || direction === "left" ) ? "pos" : "neg",
+ animation = {
+ opacity: show ? 1 : 0
+ },
+ distance;
+
+ // Adjust
+ $.effects.save( el, props );
+ el.show();
+ $.effects.createWrapper( el );
+
+ distance = o.distance || el[ ref === "top" ? "outerHeight": "outerWidth" ]( true ) / 2;
+
+ if ( show ) {
+ el
+ .css( "opacity", 0 )
+ .css( ref, motion === "pos" ? -distance : distance );
+ }
+
+ // Animation
+ animation[ ref ] = ( show ?
+ ( motion === "pos" ? "+=" : "-=" ) :
+ ( motion === "pos" ? "-=" : "+=" ) ) +
+ distance;
+
+ // Animate
+ el.animate( animation, {
+ queue: false,
+ duration: o.duration,
+ easing: o.easing,
+ complete: function() {
+ if ( mode === "hide" ) {
+ el.hide();
+ }
+ $.effects.restore( el, props );
+ $.effects.removeWrapper( el );
+ done();
+ }
+ });
+};
+
+})(jQuery);
diff --git a/debian/missing-sources/jquery-ui/jquery.ui.effect-explode.js b/debian/missing-sources/jquery-ui/jquery.ui.effect-explode.js
new file mode 100644
index 0000000..f60af96
--- /dev/null
+++ b/debian/missing-sources/jquery-ui/jquery.ui.effect-explode.js
@@ -0,0 +1,97 @@
+/*!
+ * jQuery UI Effects Explode 1.10.3
+ * http://jqueryui.com
+ *
+ * Copyright 2013 jQuery Foundation and other contributors
+ * Released under the MIT license.
+ * http://jquery.org/license
+ *
+ * http://api.jqueryui.com/explode-effect/
+ *
+ * Depends:
+ * jquery.ui.effect.js
+ */
+(function( $, undefined ) {
+
+$.effects.effect.explode = function( o, done ) {
+
+ var rows = o.pieces ? Math.round( Math.sqrt( o.pieces ) ) : 3,
+ cells = rows,
+ el = $( this ),
+ mode = $.effects.setMode( el, o.mode || "hide" ),
+ show = mode === "show",
+
+ // show and then visibility:hidden the element before calculating offset
+ offset = el.show().css( "visibility", "hidden" ).offset(),
+
+ // width and height of a piece
+ width = Math.ceil( el.outerWidth() / cells ),
+ height = Math.ceil( el.outerHeight() / rows ),
+ pieces = [],
+
+ // loop
+ i, j, left, top, mx, my;
+
+ // children animate complete:
+ function childComplete() {
+ pieces.push( this );
+ if ( pieces.length === rows * cells ) {
+ animComplete();
+ }
+ }
+
+ // clone the element for each row and cell.
+ for( i = 0; i < rows ; i++ ) { // ===>
+ top = offset.top + i * height;
+ my = i - ( rows - 1 ) / 2 ;
+
+ for( j = 0; j < cells ; j++ ) { // |||
+ left = offset.left + j * width;
+ mx = j - ( cells - 1 ) / 2 ;
+
+ // Create a clone of the now hidden main element that will be absolute positioned
+ // within a wrapper div off the -left and -top equal to size of our pieces
+ el
+ .clone()
+ .appendTo( "body" )
+ .wrap( "<div></div>" )
+ .css({
+ position: "absolute",
+ visibility: "visible",
+ left: -j * width,
+ top: -i * height
+ })
+
+ // select the wrapper - make it overflow: hidden and absolute positioned based on
+ // where the original was located +left and +top equal to the size of pieces
+ .parent()
+ .addClass( "ui-effects-explode" )
+ .css({
+ position: "absolute",
+ overflow: "hidden",
+ width: width,
+ height: height,
+ left: left + ( show ? mx * width : 0 ),
+ top: top + ( show ? my * height : 0 ),
+ opacity: show ? 0 : 1
+ }).animate({
+ left: left + ( show ? 0 : mx * width ),
+ top: top + ( show ? 0 : my * height ),
+ opacity: show ? 1 : 0
+ }, o.duration || 500, o.easing, childComplete );
+ }
+ }
+
+ function animComplete() {
+ el.css({
+ visibility: "visible"
+ });
+ $( pieces ).remove();
+ if ( !show ) {
+ el.hide();
+ }
+ done();
+ }
+};
+
+})(jQuery);
diff --git a/debian/missing-sources/jquery-ui/jquery.ui.effect-fade.js b/debian/missing-sources/jquery-ui/jquery.ui.effect-fade.js
new file mode 100644
index 0000000..aaad697
--- /dev/null
+++ b/debian/missing-sources/jquery-ui/jquery.ui.effect-fade.js
@@ -0,0 +1,30 @@
+/*!
+ * jQuery UI Effects Fade 1.10.3
+ * http://jqueryui.com
+ *
+ * Copyright 2013 jQuery Foundation and other contributors
+ * Released under the MIT license.
+ * http://jquery.org/license
+ *
+ * http://api.jqueryui.com/fade-effect/
+ *
+ * Depends:
+ * jquery.ui.effect.js
+ */
+(function( $, undefined ) {
+
+$.effects.effect.fade = function( o, done ) {
+ var el = $( this ),
+ mode = $.effects.setMode( el, o.mode || "toggle" );
+
+ el.animate({
+ opacity: mode
+ }, {
+ queue: false,
+ duration: o.duration,
+ easing: o.easing,
+ complete: done
+ });
+};
+
+})( jQuery );
diff --git a/debian/missing-sources/jquery-ui/jquery.ui.effect-fold.js b/debian/missing-sources/jquery-ui/jquery.ui.effect-fold.js
new file mode 100644
index 0000000..c4273b8
--- /dev/null
+++ b/debian/missing-sources/jquery-ui/jquery.ui.effect-fold.js
@@ -0,0 +1,76 @@
+/*!
+ * jQuery UI Effects Fold 1.10.3
+ * http://jqueryui.com
+ *
+ * Copyright 2013 jQuery Foundation and other contributors
+ * Released under the MIT license.
+ * http://jquery.org/license
+ *
+ * http://api.jqueryui.com/fold-effect/
+ *
+ * Depends:
+ * jquery.ui.effect.js
+ */
+(function( $, undefined ) {
+
+$.effects.effect.fold = function( o, done ) {
+
+ // Create element
+ var el = $( this ),
+ props = [ "position", "top", "bottom", "left", "right", "height", "width" ],
+ mode = $.effects.setMode( el, o.mode || "hide" ),
+ show = mode === "show",
+ hide = mode === "hide",
+ size = o.size || 15,
+ percent = /([0-9]+)%/.exec( size ),
+ horizFirst = !!o.horizFirst,
+ widthFirst = show !== horizFirst,
+ ref = widthFirst ? [ "width", "height" ] : [ "height", "width" ],
+ duration = o.duration / 2,
+ wrapper, distance,
+ animation1 = {},
+ animation2 = {};
+
+ $.effects.save( el, props );
+ el.show();
+
+ // Create Wrapper
+ wrapper = $.effects.createWrapper( el ).css({
+ overflow: "hidden"
+ });
+ distance = widthFirst ?
+ [ wrapper.width(), wrapper.height() ] :
+ [ wrapper.height(), wrapper.width() ];
+
+ if ( percent ) {
+ size = parseInt( percent[ 1 ], 10 ) / 100 * distance[ hide ? 0 : 1 ];
+ }
+ if ( show ) {
+ wrapper.css( horizFirst ? {
+ height: 0,
+ width: size
+ } : {
+ height: size,
+ width: 0
+ });
+ }
+
+ // Animation
+ animation1[ ref[ 0 ] ] = show ? distance[ 0 ] : size;
+ animation2[ ref[ 1 ] ] = show ? distance[ 1 ] : 0;
+
+ // Animate
+ wrapper
+ .animate( animation1, duration, o.easing )
+ .animate( animation2, duration, o.easing, function() {
+ if ( hide ) {
+ el.hide();
+ }
+ $.effects.restore( el, props );
+ $.effects.removeWrapper( el );
+ done();
+ });
+
+};
+
+})(jQuery);
diff --git a/debian/missing-sources/jquery-ui/jquery.ui.effect-highlight.js b/debian/missing-sources/jquery-ui/jquery.ui.effect-highlight.js
new file mode 100644
index 0000000..6b9438c
--- /dev/null
+++ b/debian/missing-sources/jquery-ui/jquery.ui.effect-highlight.js
@@ -0,0 +1,50 @@
+/*!
+ * jQuery UI Effects Highlight 1.10.3
+ * http://jqueryui.com
+ *
+ * Copyright 2013 jQuery Foundation and other contributors
+ * Released under the MIT license.
+ * http://jquery.org/license
+ *
+ * http://api.jqueryui.com/highlight-effect/
+ *
+ * Depends:
+ * jquery.ui.effect.js
+ */
+(function( $, undefined ) {
+
+$.effects.effect.highlight = function( o, done ) {
+ var elem = $( this ),
+ props = [ "backgroundImage", "backgroundColor", "opacity" ],
+ mode = $.effects.setMode( elem, o.mode || "show" ),
+ animation = {
+ backgroundColor: elem.css( "backgroundColor" )
+ };
+
+ if (mode === "hide") {
+ animation.opacity = 0;
+ }
+
+ $.effects.save( elem, props );
+
+ elem
+ .show()
+ .css({
+ backgroundImage: "none",
+ backgroundColor: o.color || "#ffff99"
+ })
+ .animate( animation, {
+ queue: false,
+ duration: o.duration,
+ easing: o.easing,
+ complete: function() {
+ if ( mode === "hide" ) {
+ elem.hide();
+ }
+ $.effects.restore( elem, props );
+ done();
+ }
+ });
+};
+
+})(jQuery);
diff --git a/debian/missing-sources/jquery-ui/jquery.ui.effect-pulsate.js b/debian/missing-sources/jquery-ui/jquery.ui.effect-pulsate.js
new file mode 100644
index 0000000..b357f1a
--- /dev/null
+++ b/debian/missing-sources/jquery-ui/jquery.ui.effect-pulsate.js
@@ -0,0 +1,63 @@
+/*!
+ * jQuery UI Effects Pulsate 1.10.3
+ * http://jqueryui.com
+ *
+ * Copyright 2013 jQuery Foundation and other contributors
+ * Released under the MIT license.
+ * http://jquery.org/license
+ *
+ * http://api.jqueryui.com/pulsate-effect/
+ *
+ * Depends:
+ * jquery.ui.effect.js
+ */
+(function( $, undefined ) {
+
+$.effects.effect.pulsate = function( o, done ) {
+ var elem = $( this ),
+ mode = $.effects.setMode( elem, o.mode || "show" ),
+ show = mode === "show",
+ hide = mode === "hide",
+ showhide = ( show || mode === "hide" ),
+
+ // showing or hiding leaves of the "last" animation
+ anims = ( ( o.times || 5 ) * 2 ) + ( showhide ? 1 : 0 ),
+ duration = o.duration / anims,
+ animateTo = 0,
+ queue = elem.queue(),
+ queuelen = queue.length,
+ i;
+
+ if ( show || !elem.is(":visible")) {
+ elem.css( "opacity", 0 ).show();
+ animateTo = 1;
+ }
+
+ // anims - 1 opacity "toggles"
+ for ( i = 1; i < anims; i++ ) {
+ elem.animate({
+ opacity: animateTo
+ }, duration, o.easing );
+ animateTo = 1 - animateTo;
+ }
+
+ elem.animate({
+ opacity: animateTo
+ }, duration, o.easing);
+
+ elem.queue(function() {
+ if ( hide ) {
+ elem.hide();
+ }
+ done();
+ });
+
+ // We just queued up "anims" animations, we need to put them next in the queue
+ if ( queuelen > 1 ) {
+ queue.splice.apply( queue,
+ [ 1, 0 ].concat( queue.splice( queuelen, anims + 1 ) ) );
+ }
+ elem.dequeue();
+};
+
+})(jQuery);
diff --git a/debian/missing-sources/jquery-ui/jquery.ui.effect-scale.js b/debian/missing-sources/jquery-ui/jquery.ui.effect-scale.js
new file mode 100644
index 0000000..d35224c
--- /dev/null
+++ b/debian/missing-sources/jquery-ui/jquery.ui.effect-scale.js
@@ -0,0 +1,318 @@
+/*!
+ * jQuery UI Effects Scale 1.10.3
+ * http://jqueryui.com
+ *
+ * Copyright 2013 jQuery Foundation and other contributors
+ * Released under the MIT license.
+ * http://jquery.org/license
+ *
+ * http://api.jqueryui.com/scale-effect/
+ *
+ * Depends:
+ * jquery.ui.effect.js
+ */
+(function( $, undefined ) {
+
+$.effects.effect.puff = function( o, done ) {
+ var elem = $( this ),
+ mode = $.effects.setMode( elem, o.mode || "hide" ),
+ hide = mode === "hide",
+ percent = parseInt( o.percent, 10 ) || 150,
+ factor = percent / 100,
+ original = {
+ height: elem.height(),
+ width: elem.width(),
+ outerHeight: elem.outerHeight(),
+ outerWidth: elem.outerWidth()
+ };
+
+ $.extend( o, {
+ effect: "scale",
+ queue: false,
+ fade: true,
+ mode: mode,
+ complete: done,
+ percent: hide ? percent : 100,
+ from: hide ?
+ original :
+ {
+ height: original.height * factor,
+ width: original.width * factor,
+ outerHeight: original.outerHeight * factor,
+ outerWidth: original.outerWidth * factor
+ }
+ });
+
+ elem.effect( o );
+};
+
+$.effects.effect.scale = function( o, done ) {
+
+ // Create element
+ var el = $( this ),
+ options = $.extend( true, {}, o ),
+ mode = $.effects.setMode( el, o.mode || "effect" ),
+ percent = parseInt( o.percent, 10 ) ||
+ ( parseInt( o.percent, 10 ) === 0 ? 0 : ( mode === "hide" ? 0 : 100 ) ),
+ direction = o.direction || "both",
+ origin = o.origin,
+ original = {
+ height: el.height(),
+ width: el.width(),
+ outerHeight: el.outerHeight(),
+ outerWidth: el.outerWidth()
+ },
+ factor = {
+ y: direction !== "horizontal" ? (percent / 100) : 1,
+ x: direction !== "vertical" ? (percent / 100) : 1
+ };
+
+ // We are going to pass this effect to the size effect:
+ options.effect = "size";
+ options.queue = false;
+ options.complete = done;
+
+ // Set default origin and restore for show/hide
+ if ( mode !== "effect" ) {
+ options.origin = origin || ["middle","center"];
+ options.restore = true;
+ }
+
+ options.from = o.from || ( mode === "show" ? {
+ height: 0,
+ width: 0,
+ outerHeight: 0,
+ outerWidth: 0
+ } : original );
+ options.to = {
+ height: original.height * factor.y,
+ width: original.width * factor.x,
+ outerHeight: original.outerHeight * factor.y,
+ outerWidth: original.outerWidth * factor.x
+ };
+
+ // Fade option to support puff
+ if ( options.fade ) {
+ if ( mode === "show" ) {
+ options.from.opacity = 0;
+ options.to.opacity = 1;
+ }
+ if ( mode === "hide" ) {
+ options.from.opacity = 1;
+ options.to.opacity = 0;
+ }
+ }
+
+ // Animate
+ el.effect( options );
+
+};
+
+$.effects.effect.size = function( o, done ) {
+
+ // Create element
+ var original, baseline, factor,
+ el = $( this ),
+ props0 = [ "position", "top", "bottom", "left", "right", "width", "height", "overflow", "opacity" ],
+
+ // Always restore
+ props1 = [ "position", "top", "bottom", "left", "right", "overflow", "opacity" ],
+
+ // Copy for children
+ props2 = [ "width", "height", "overflow" ],
+ cProps = [ "fontSize" ],
+ vProps = [ "borderTopWidth", "borderBottomWidth", "paddingTop", "paddingBottom" ],
+ hProps = [ "borderLeftWidth", "borderRightWidth", "paddingLeft", "paddingRight" ],
+
+ // Set options
+ mode = $.effects.setMode( el, o.mode || "effect" ),
+ restore = o.restore || mode !== "effect",
+ scale = o.scale || "both",
+ origin = o.origin || [ "middle", "center" ],
+ position = el.css( "position" ),
+ props = restore ? props0 : props1,
+ zero = {
+ height: 0,
+ width: 0,
+ outerHeight: 0,
+ outerWidth: 0
+ };
+
+ if ( mode === "show" ) {
+ el.show();
+ }
+ original = {
+ height: el.height(),
+ width: el.width(),
+ outerHeight: el.outerHeight(),
+ outerWidth: el.outerWidth()
+ };
+
+ if ( o.mode === "toggle" && mode === "show" ) {
+ el.from = o.to || zero;
+ el.to = o.from || original;
+ } else {
+ el.from = o.from || ( mode === "show" ? zero : original );
+ el.to = o.to || ( mode === "hide" ? zero : original );
+ }
+
+ // Set scaling factor
+ factor = {
+ from: {
+ y: el.from.height / original.height,
+ x: el.from.width / original.width
+ },
+ to: {
+ y: el.to.height / original.height,
+ x: el.to.width / original.width
+ }
+ };
+
+ // Scale the css box
+ if ( scale === "box" || scale === "both" ) {
+
+ // Vertical props scaling
+ if ( factor.from.y !== factor.to.y ) {
+ props = props.concat( vProps );
+ el.from = $.effects.setTransition( el, vProps, factor.from.y, el.from );
+ el.to = $.effects.setTransition( el, vProps, factor.to.y, el.to );
+ }
+
+ // Horizontal props scaling
+ if ( factor.from.x !== factor.to.x ) {
+ props = props.concat( hProps );
+ el.from = $.effects.setTransition( el, hProps, factor.from.x, el.from );
+ el.to = $.effects.setTransition( el, hProps, factor.to.x, el.to );
+ }
+ }
+
+ // Scale the content
+ if ( scale === "content" || scale === "both" ) {
+
+ // Vertical props scaling
+ if ( factor.from.y !== factor.to.y ) {
+ props = props.concat( cProps ).concat( props2 );
+ el.from = $.effects.setTransition( el, cProps, factor.from.y, el.from );
+ el.to = $.effects.setTransition( el, cProps, factor.to.y, el.to );
+ }
+ }
+
+ $.effects.save( el, props );
+ el.show();
+ $.effects.createWrapper( el );
+ el.css( "overflow", "hidden" ).css( el.from );
+
+ // Adjust
+ if (origin) { // Calculate baseline shifts
+ baseline = $.effects.getBaseline( origin, original );
+ el.from.top = ( original.outerHeight - el.outerHeight() ) * baseline.y;
+ el.from.left = ( original.outerWidth - el.outerWidth() ) * baseline.x;
+ el.to.top = ( original.outerHeight - el.to.outerHeight ) * baseline.y;
+ el.to.left = ( original.outerWidth - el.to.outerWidth ) * baseline.x;
+ }
+ el.css( el.from ); // set top & left
+
+ // Animate
+ if ( scale === "content" || scale === "both" ) { // Scale the children
+
+ // Add margins/font-size
+ vProps = vProps.concat([ "marginTop", "marginBottom" ]).concat(cProps);
+ hProps = hProps.concat([ "marginLeft", "marginRight" ]);
+ props2 = props0.concat(vProps).concat(hProps);
+
+ el.find( "*[width]" ).each( function(){
+ var child = $( this ),
+ c_original = {
+ height: child.height(),
+ width: child.width(),
+ outerHeight: child.outerHeight(),
+ outerWidth: child.outerWidth()
+ };
+ if (restore) {
+ $.effects.save(child, props2);
+ }
+
+ child.from = {
+ height: c_original.height * factor.from.y,
+ width: c_original.width * factor.from.x,
+ outerHeight: c_original.outerHeight * factor.from.y,
+ outerWidth: c_original.outerWidth * factor.from.x
+ };
+ child.to = {
+ height: c_original.height * factor.to.y,
+ width: c_original.width * factor.to.x,
+ outerHeight: c_original.height * factor.to.y,
+ outerWidth: c_original.width * factor.to.x
+ };
+
+ // Vertical props scaling
+ if ( factor.from.y !== factor.to.y ) {
+ child.from = $.effects.setTransition( child, vProps, factor.from.y, child.from );
+ child.to = $.effects.setTransition( child, vProps, factor.to.y, child.to );
+ }
+
+ // Horizontal props scaling
+ if ( factor.from.x !== factor.to.x ) {
+ child.from = $.effects.setTransition( child, hProps, factor.from.x, child.from );
+ child.to = $.effects.setTransition( child, hProps, factor.to.x, child.to );
+ }
+
+ // Animate children
+ child.css( child.from );
+ child.animate( child.to, o.duration, o.easing, function() {
+
+ // Restore children
+ if ( restore ) {
+ $.effects.restore( child, props2 );
+ }
+ });
+ });
+ }
+
+ // Animate
+ el.animate( el.to, {
+ queue: false,
+ duration: o.duration,
+ easing: o.easing,
+ complete: function() {
+ if ( el.to.opacity === 0 ) {
+ el.css( "opacity", el.from.opacity );
+ }
+ if( mode === "hide" ) {
+ el.hide();
+ }
+ $.effects.restore( el, props );
+ if ( !restore ) {
+
+ // we need to calculate our new positioning based on the scaling
+ if ( position === "static" ) {
+ el.css({
+ position: "relative",
+ top: el.to.top,
+ left: el.to.left
+ });
+ } else {
+ $.each([ "top", "left" ], function( idx, pos ) {
+ el.css( pos, function( _, str ) {
+ var val = parseInt( str, 10 ),
+ toRef = idx ? el.to.left : el.to.top;
+
+ // if original was "auto", recalculate the new value from wrapper
+ if ( str === "auto" ) {
+ return toRef + "px";
+ }
+
+ return val + toRef + "px";
+ });
+ });
+ }
+ }
+
+ $.effects.removeWrapper( el );
+ done();
+ }
+ });
+
+};
+
+})(jQuery);
diff --git a/debian/missing-sources/jquery-ui/jquery.ui.effect-shake.js b/debian/missing-sources/jquery-ui/jquery.ui.effect-shake.js
new file mode 100644
index 0000000..fc12fca
--- /dev/null
+++ b/debian/missing-sources/jquery-ui/jquery.ui.effect-shake.js
@@ -0,0 +1,74 @@
+/*!
+ * jQuery UI Effects Shake 1.10.3
+ * http://jqueryui.com
+ *
+ * Copyright 2013 jQuery Foundation and other contributors
+ * Released under the MIT license.
+ * http://jquery.org/license
+ *
+ * http://api.jqueryui.com/shake-effect/
+ *
+ * Depends:
+ * jquery.ui.effect.js
+ */
+(function( $, undefined ) {
+
+$.effects.effect.shake = function( o, done ) {
+
+ var el = $( this ),
+ props = [ "position", "top", "bottom", "left", "right", "height", "width" ],
+ mode = $.effects.setMode( el, o.mode || "effect" ),
+ direction = o.direction || "left",
+ distance = o.distance || 20,
+ times = o.times || 3,
+ anims = times * 2 + 1,
+ speed = Math.round(o.duration/anims),
+ ref = (direction === "up" || direction === "down") ? "top" : "left",
+ positiveMotion = (direction === "up" || direction === "left"),
+ animation = {},
+ animation1 = {},
+ animation2 = {},
+ i,
+
+ // we will need to re-assemble the queue to stack our animations in place
+ queue = el.queue(),
+ queuelen = queue.length;
+
+ $.effects.save( el, props );
+ el.show();
+ $.effects.createWrapper( el );
+
+ // Animation
+ animation[ ref ] = ( positiveMotion ? "-=" : "+=" ) + distance;
+ animation1[ ref ] = ( positiveMotion ? "+=" : "-=" ) + distance * 2;
+ animation2[ ref ] = ( positiveMotion ? "-=" : "+=" ) + distance * 2;
+
+ // Animate
+ el.animate( animation, speed, o.easing );
+
+ // Shakes
+ for ( i = 1; i < times; i++ ) {
+ el.animate( animation1, speed, o.easing ).animate( animation2, speed, o.easing );
+ }
+ el
+ .animate( animation1, speed, o.easing )
+ .animate( animation, speed / 2, o.easing )
+ .queue(function() {
+ if ( mode === "hide" ) {
+ el.hide();
+ }
+ $.effects.restore( el, props );
+ $.effects.removeWrapper( el );
+ done();
+ });
+
+ // inject all the animations we just queued to be first in line (after "inprogress")
+ if ( queuelen > 1) {
+ queue.splice.apply( queue,
+ [ 1, 0 ].concat( queue.splice( queuelen, anims + 1 ) ) );
+ }
+ el.dequeue();
+
+};
+
+})(jQuery);
diff --git a/debian/missing-sources/jquery-ui/jquery.ui.effect-slide.js b/debian/missing-sources/jquery-ui/jquery.ui.effect-slide.js
new file mode 100644
index 0000000..0737b86
--- /dev/null
+++ b/debian/missing-sources/jquery-ui/jquery.ui.effect-slide.js
@@ -0,0 +1,64 @@
+/*!
+ * jQuery UI Effects Slide 1.10.3
+ * http://jqueryui.com
+ *
+ * Copyright 2013 jQuery Foundation and other contributors
+ * Released under the MIT license.
+ * http://jquery.org/license
+ *
+ * http://api.jqueryui.com/slide-effect/
+ *
+ * Depends:
+ * jquery.ui.effect.js
+ */
+(function( $, undefined ) {
+
+$.effects.effect.slide = function( o, done ) {
+
+ // Create element
+ var el = $( this ),
+ props = [ "position", "top", "bottom", "left", "right", "width", "height" ],
+ mode = $.effects.setMode( el, o.mode || "show" ),
+ show = mode === "show",
+ direction = o.direction || "left",
+ ref = (direction === "up" || direction === "down") ? "top" : "left",
+ positiveMotion = (direction === "up" || direction === "left"),
+ distance,
+ animation = {};
+
+ // Adjust
+ $.effects.save( el, props );
+ el.show();
+ distance = o.distance || el[ ref === "top" ? "outerHeight" : "outerWidth" ]( true );
+
+ $.effects.createWrapper( el ).css({
+ overflow: "hidden"
+ });
+
+ if ( show ) {
+ el.css( ref, positiveMotion ? (isNaN(distance) ? "-" + distance : -distance) : distance );
+ }
+
+ // Animation
+ animation[ ref ] = ( show ?
+ ( positiveMotion ? "+=" : "-=") :
+ ( positiveMotion ? "-=" : "+=")) +
+ distance;
+
+ // Animate
+ el.animate( animation, {
+ queue: false,
+ duration: o.duration,
+ easing: o.easing,
+ complete: function() {
+ if ( mode === "hide" ) {
+ el.hide();
+ }
+ $.effects.restore( el, props );
+ $.effects.removeWrapper( el );
+ done();
+ }
+ });
+};
+
+})(jQuery);
diff --git a/debian/missing-sources/jquery-ui/jquery.ui.effect-transfer.js b/debian/missing-sources/jquery-ui/jquery.ui.effect-transfer.js
new file mode 100644
index 0000000..5543f76
--- /dev/null
+++ b/debian/missing-sources/jquery-ui/jquery.ui.effect-transfer.js
@@ -0,0 +1,47 @@
+/*!
+ * jQuery UI Effects Transfer 1.10.3
+ * http://jqueryui.com
+ *
+ * Copyright 2013 jQuery Foundation and other contributors
+ * Released under the MIT license.
+ * http://jquery.org/license
+ *
+ * http://api.jqueryui.com/transfer-effect/
+ *
+ * Depends:
+ * jquery.ui.effect.js
+ */
+(function( $, undefined ) {
+
+$.effects.effect.transfer = function( o, done ) {
+ var elem = $( this ),
+ target = $( o.to ),
+ targetFixed = target.css( "position" ) === "fixed",
+ body = $("body"),
+ fixTop = targetFixed ? body.scrollTop() : 0,
+ fixLeft = targetFixed ? body.scrollLeft() : 0,
+ endPosition = target.offset(),
+ animation = {
+ top: endPosition.top - fixTop ,
+ left: endPosition.left - fixLeft ,
+ height: target.innerHeight(),
+ width: target.innerWidth()
+ },
+ startPosition = elem.offset(),
+ transfer = $( "<div class='ui-effects-transfer'></div>" )
+ .appendTo( document.body )
+ .addClass( o.className )
+ .css({
+ top: startPosition.top - fixTop ,
+ left: startPosition.left - fixLeft ,
+ height: elem.innerHeight(),
+ width: elem.innerWidth(),
+ position: targetFixed ? "fixed" : "absolute"
+ })
+ .animate( animation, o.duration, o.easing, function() {
+ transfer.remove();
+ done();
+ });
+};
+
+})(jQuery);
diff --git a/debian/missing-sources/jquery-ui/jquery.ui.effect.js b/debian/missing-sources/jquery-ui/jquery.ui.effect.js
new file mode 100644
index 0000000..bad97fa
--- /dev/null
+++ b/debian/missing-sources/jquery-ui/jquery.ui.effect.js
@@ -0,0 +1,1289 @@
+/*!
+ * jQuery UI Effects 1.10.3
+ * http://jqueryui.com
+ *
+ * Copyright 2013 jQuery Foundation and other contributors
+ * Released under the MIT license.
+ * http://jquery.org/license
+ *
+ * http://api.jqueryui.com/category/effects-core/
+ */
+(function($, undefined) {
+
+var dataSpace = "ui-effects-";
+
+$.effects = {
+ effect: {}
+};
+
+/*!
+ * jQuery Color Animations v2.1.2
+ * https://github.com/jquery/jquery-color
+ *
+ * Copyright 2013 jQuery Foundation and other contributors
+ * Released under the MIT license.
+ * http://jquery.org/license
+ *
+ * Date: Wed Jan 16 08:47:09 2013 -0600
+ */
+(function( jQuery, undefined ) {
+
+ var stepHooks = "backgroundColor borderBottomColor borderLeftColor borderRightColor borderTopColor color columnRuleColor outlineColor textDecorationColor textEmphasisColor",
+
+ // plusequals test for += 100 -= 100
+ rplusequals = /^([\-+])=\s*(\d+\.?\d*)/,
+ // a set of RE's that can match strings and generate color tuples.
+ stringParsers = [{
+ re: /rgba?\(\s*(\d{1,3})\s*,\s*(\d{1,3})\s*,\s*(\d{1,3})\s*(?:,\s*(\d?(?:\.\d+)?)\s*)?\)/,
+ parse: function( execResult ) {
+ return [
+ execResult[ 1 ],
+ execResult[ 2 ],
+ execResult[ 3 ],
+ execResult[ 4 ]
+ ];
+ }
+ }, {
+ re: /rgba?\(\s*(\d+(?:\.\d+)?)\%\s*,\s*(\d+(?:\.\d+)?)\%\s*,\s*(\d+(?:\.\d+)?)\%\s*(?:,\s*(\d?(?:\.\d+)?)\s*)?\)/,
+ parse: function( execResult ) {
+ return [
+ execResult[ 1 ] * 2.55,
+ execResult[ 2 ] * 2.55,
+ execResult[ 3 ] * 2.55,
+ execResult[ 4 ]
+ ];
+ }
+ }, {
+ // this regex ignores A-F because it's compared against an already lowercased string
+ re: /#([a-f0-9]{2})([a-f0-9]{2})([a-f0-9]{2})/,
+ parse: function( execResult ) {
+ return [
+ parseInt( execResult[ 1 ], 16 ),
+ parseInt( execResult[ 2 ], 16 ),
+ parseInt( execResult[ 3 ], 16 )
+ ];
+ }
+ }, {
+ // this regex ignores A-F because it's compared against an already lowercased string
+ re: /#([a-f0-9])([a-f0-9])([a-f0-9])/,
+ parse: function( execResult ) {
+ return [
+ parseInt( execResult[ 1 ] + execResult[ 1 ], 16 ),
+ parseInt( execResult[ 2 ] + execResult[ 2 ], 16 ),
+ parseInt( execResult[ 3 ] + execResult[ 3 ], 16 )
+ ];
+ }
+ }, {
+ re: /hsla?\(\s*(\d+(?:\.\d+)?)\s*,\s*(\d+(?:\.\d+)?)\%\s*,\s*(\d+(?:\.\d+)?)\%\s*(?:,\s*(\d?(?:\.\d+)?)\s*)?\)/,
+ space: "hsla",
+ parse: function( execResult ) {
+ return [
+ execResult[ 1 ],
+ execResult[ 2 ] / 100,
+ execResult[ 3 ] / 100,
+ execResult[ 4 ]
+ ];
+ }
+ }],
+
+ // jQuery.Color( )
+ color = jQuery.Color = function( color, green, blue, alpha ) {
+ return new jQuery.Color.fn.parse( color, green, blue, alpha );
+ },
+ spaces = {
+ rgba: {
+ props: {
+ red: {
+ idx: 0,
+ type: "byte"
+ },
+ green: {
+ idx: 1,
+ type: "byte"
+ },
+ blue: {
+ idx: 2,
+ type: "byte"
+ }
+ }
+ },
+
+ hsla: {
+ props: {
+ hue: {
+ idx: 0,
+ type: "degrees"
+ },
+ saturation: {
+ idx: 1,
+ type: "percent"
+ },
+ lightness: {
+ idx: 2,
+ type: "percent"
+ }
+ }
+ }
+ },
+ propTypes = {
+ "byte": {
+ floor: true,
+ max: 255
+ },
+ "percent": {
+ max: 1
+ },
+ "degrees": {
+ mod: 360,
+ floor: true
+ }
+ },
+ support = color.support = {},
+
+ // element for support tests
+ supportElem = jQuery( "<p>" )[ 0 ],
+
+ // colors = jQuery.Color.names
+ colors,
+
+ // local aliases of functions called often
+ each = jQuery.each;
+
+// determine rgba support immediately
+supportElem.style.cssText = "background-color:rgba(1,1,1,.5)";
+support.rgba = supportElem.style.backgroundColor.indexOf( "rgba" ) > -1;
+
+// define cache name and alpha properties
+// for rgba and hsla spaces
+each( spaces, function( spaceName, space ) {
+ space.cache = "_" + spaceName;
+ space.props.alpha = {
+ idx: 3,
+ type: "percent",
+ def: 1
+ };
+});
+
+function clamp( value, prop, allowEmpty ) {
+ var type = propTypes[ prop.type ] || {};
+
+ if ( value == null ) {
+ return (allowEmpty || !prop.def) ? null : prop.def;
+ }
+
+ // ~~ is an short way of doing floor for positive numbers
+ value = type.floor ? ~~value : parseFloat( value );
+
+ // IE will pass in empty strings as value for alpha,
+ // which will hit this case
+ if ( isNaN( value ) ) {
+ return prop.def;
+ }
+
+ if ( type.mod ) {
+ // we add mod before modding to make sure that negatives values
+ // get converted properly: -10 -> 350
+ return (value + type.mod) % type.mod;
+ }
+
+ // for now all property types without mod have min and max
+ return 0 > value ? 0 : type.max < value ? type.max : value;
+}
+
+function stringParse( string ) {
+ var inst = color(),
+ rgba = inst._rgba = [];
+
+ string = string.toLowerCase();
+
+ each( stringParsers, function( i, parser ) {
+ var parsed,
+ match = parser.re.exec( string ),
+ values = match && parser.parse( match ),
+ spaceName = parser.space || "rgba";
+
+ if ( values ) {
+ parsed = inst[ spaceName ]( values );
+
+ // if this was an rgba parse the assignment might happen twice
+ // oh well....
+ inst[ spaces[ spaceName ].cache ] = parsed[ spaces[ spaceName ].cache ];
+ rgba = inst._rgba = parsed._rgba;
+
+ // exit each( stringParsers ) here because we matched
+ return false;
+ }
+ });
+
+ // Found a stringParser that handled it
+ if ( rgba.length ) {
+
+ // if this came from a parsed string, force "transparent" when alpha is 0
+ // chrome, (and maybe others) return "transparent" as rgba(0,0,0,0)
+ if ( rgba.join() === "0,0,0,0" ) {
+ jQuery.extend( rgba, colors.transparent );
+ }
+ return inst;
+ }
+
+ // named colors
+ return colors[ string ];
+}
+
+color.fn = jQuery.extend( color.prototype, {
+ parse: function( red, green, blue, alpha ) {
+ if ( red === undefined ) {
+ this._rgba = [ null, null, null, null ];
+ return this;
+ }
+ if ( red.jquery || red.nodeType ) {
+ red = jQuery( red ).css( green );
+ green = undefined;
+ }
+
+ var inst = this,
+ type = jQuery.type( red ),
+ rgba = this._rgba = [];
+
+ // more than 1 argument specified - assume ( red, green, blue, alpha )
+ if ( green !== undefined ) {
+ red = [ red, green, blue, alpha ];
+ type = "array";
+ }
+
+ if ( type === "string" ) {
+ return this.parse( stringParse( red ) || colors._default );
+ }
+
+ if ( type === "array" ) {
+ each( spaces.rgba.props, function( key, prop ) {
+ rgba[ prop.idx ] = clamp( red[ prop.idx ], prop );
+ });
+ return this;
+ }
+
+ if ( type === "object" ) {
+ if ( red instanceof color ) {
+ each( spaces, function( spaceName, space ) {
+ if ( red[ space.cache ] ) {
+ inst[ space.cache ] = red[ space.cache ].slice();
+ }
+ });
+ } else {
+ each( spaces, function( spaceName, space ) {
+ var cache = space.cache;
+ each( space.props, function( key, prop ) {
+
+ // if the cache doesn't exist, and we know how to convert
+ if ( !inst[ cache ] && space.to ) {
+
+ // if the value was null, we don't need to copy it
+ // if the key was alpha, we don't need to copy it either
+ if ( key === "alpha" || red[ key ] == null ) {
+ return;
+ }
+ inst[ cache ] = space.to( inst._rgba );
+ }
+
+ // this is the only case where we allow nulls for ALL properties.
+ // call clamp with alwaysAllowEmpty
+ inst[ cache ][ prop.idx ] = clamp( red[ key ], prop, true );
+ });
+
+ // everything defined but alpha?
+ if ( inst[ cache ] && jQuery.inArray( null, inst[ cache ].slice( 0, 3 ) ) < 0 ) {
+ // use the default of 1
+ inst[ cache ][ 3 ] = 1;
+ if ( space.from ) {
+ inst._rgba = space.from( inst[ cache ] );
+ }
+ }
+ });
+ }
+ return this;
+ }
+ },
+ is: function( compare ) {
+ var is = color( compare ),
+ same = true,
+ inst = this;
+
+ each( spaces, function( _, space ) {
+ var localCache,
+ isCache = is[ space.cache ];
+ if (isCache) {
+ localCache = inst[ space.cache ] || space.to && space.to( inst._rgba ) || [];
+ each( space.props, function( _, prop ) {
+ if ( isCache[ prop.idx ] != null ) {
+ same = ( isCache[ prop.idx ] === localCache[ prop.idx ] );
+ return same;
+ }
+ });
+ }
+ return same;
+ });
+ return same;
+ },
+ _space: function() {
+ var used = [],
+ inst = this;
+ each( spaces, function( spaceName, space ) {
+ if ( inst[ space.cache ] ) {
+ used.push( spaceName );
+ }
+ });
+ return used.pop();
+ },
+ transition: function( other, distance ) {
+ var end = color( other ),
+ spaceName = end._space(),
+ space = spaces[ spaceName ],
+ startColor = this.alpha() === 0 ? color( "transparent" ) : this,
+ start = startColor[ space.cache ] || space.to( startColor._rgba ),
+ result = start.slice();
+
+ end = end[ space.cache ];
+ each( space.props, function( key, prop ) {
+ var index = prop.idx,
+ startValue = start[ index ],
+ endValue = end[ index ],
+ type = propTypes[ prop.type ] || {};
+
+ // if null, don't override start value
+ if ( endValue === null ) {
+ return;
+ }
+ // if null - use end
+ if ( startValue === null ) {
+ result[ index ] = endValue;
+ } else {
+ if ( type.mod ) {
+ if ( endValue - startValue > type.mod / 2 ) {
+ startValue += type.mod;
+ } else if ( startValue - endValue > type.mod / 2 ) {
+ startValue -= type.mod;
+ }
+ }
+ result[ index ] = clamp( ( endValue - startValue ) * distance + startValue, prop );
+ }
+ });
+ return this[ spaceName ]( result );
+ },
+ blend: function( opaque ) {
+ // if we are already opaque - return ourself
+ if ( this._rgba[ 3 ] === 1 ) {
+ return this;
+ }
+
+ var rgb = this._rgba.slice(),
+ a = rgb.pop(),
+ blend = color( opaque )._rgba;
+
+ return color( jQuery.map( rgb, function( v, i ) {
+ return ( 1 - a ) * blend[ i ] + a * v;
+ }));
+ },
+ toRgbaString: function() {
+ var prefix = "rgba(",
+ rgba = jQuery.map( this._rgba, function( v, i ) {
+ return v == null ? ( i > 2 ? 1 : 0 ) : v;
+ });
+
+ if ( rgba[ 3 ] === 1 ) {
+ rgba.pop();
+ prefix = "rgb(";
+ }
+
+ return prefix + rgba.join() + ")";
+ },
+ toHslaString: function() {
+ var prefix = "hsla(",
+ hsla = jQuery.map( this.hsla(), function( v, i ) {
+ if ( v == null ) {
+ v = i > 2 ? 1 : 0;
+ }
+
+ // catch 1 and 2
+ if ( i && i < 3 ) {
+ v = Math.round( v * 100 ) + "%";
+ }
+ return v;
+ });
+
+ if ( hsla[ 3 ] === 1 ) {
+ hsla.pop();
+ prefix = "hsl(";
+ }
+ return prefix + hsla.join() + ")";
+ },
+ toHexString: function( includeAlpha ) {
+ var rgba = this._rgba.slice(),
+ alpha = rgba.pop();
+
+ if ( includeAlpha ) {
+ rgba.push( ~~( alpha * 255 ) );
+ }
+
+ return "#" + jQuery.map( rgba, function( v ) {
+
+ // default to 0 when nulls exist
+ v = ( v || 0 ).toString( 16 );
+ return v.length === 1 ? "0" + v : v;
+ }).join("");
+ },
+ toString: function() {
+ return this._rgba[ 3 ] === 0 ? "transparent" : this.toRgbaString();
+ }
+});
+color.fn.parse.prototype = color.fn;
+
+// hsla conversions adapted from:
+// https://code.google.com/p/maashaack/source/browse/packages/graphics/trunk/src/graphics/colors/HUE2RGB.as?r=5021
+
+function hue2rgb( p, q, h ) {
+ h = ( h + 1 ) % 1;
+ if ( h * 6 < 1 ) {
+ return p + (q - p) * h * 6;
+ }
+ if ( h * 2 < 1) {
+ return q;
+ }
+ if ( h * 3 < 2 ) {
+ return p + (q - p) * ((2/3) - h) * 6;
+ }
+ return p;
+}
+
+spaces.hsla.to = function ( rgba ) {
+ if ( rgba[ 0 ] == null || rgba[ 1 ] == null || rgba[ 2 ] == null ) {
+ return [ null, null, null, rgba[ 3 ] ];
+ }
+ var r = rgba[ 0 ] / 255,
+ g = rgba[ 1 ] / 255,
+ b = rgba[ 2 ] / 255,
+ a = rgba[ 3 ],
+ max = Math.max( r, g, b ),
+ min = Math.min( r, g, b ),
+ diff = max - min,
+ add = max + min,
+ l = add * 0.5,
+ h, s;
+
+ if ( min === max ) {
+ h = 0;
+ } else if ( r === max ) {
+ h = ( 60 * ( g - b ) / diff ) + 360;
+ } else if ( g === max ) {
+ h = ( 60 * ( b - r ) / diff ) + 120;
+ } else {
+ h = ( 60 * ( r - g ) / diff ) + 240;
+ }
+
+ // chroma (diff) == 0 means greyscale which, by definition, saturation = 0%
+ // otherwise, saturation is based on the ratio of chroma (diff) to lightness (add)
+ if ( diff === 0 ) {
+ s = 0;
+ } else if ( l <= 0.5 ) {
+ s = diff / add;
+ } else {
+ s = diff / ( 2 - add );
+ }
+ return [ Math.round(h) % 360, s, l, a == null ? 1 : a ];
+};
+
+spaces.hsla.from = function ( hsla ) {
+ if ( hsla[ 0 ] == null || hsla[ 1 ] == null || hsla[ 2 ] == null ) {
+ return [ null, null, null, hsla[ 3 ] ];
+ }
+ var h = hsla[ 0 ] / 360,
+ s = hsla[ 1 ],
+ l = hsla[ 2 ],
+ a = hsla[ 3 ],
+ q = l <= 0.5 ? l * ( 1 + s ) : l + s - l * s,
+ p = 2 * l - q;
+
+ return [
+ Math.round( hue2rgb( p, q, h + ( 1 / 3 ) ) * 255 ),
+ Math.round( hue2rgb( p, q, h ) * 255 ),
+ Math.round( hue2rgb( p, q, h - ( 1 / 3 ) ) * 255 ),
+ a
+ ];
+};
+
+
+each( spaces, function( spaceName, space ) {
+ var props = space.props,
+ cache = space.cache,
+ to = space.to,
+ from = space.from;
+
+ // makes rgba() and hsla()
+ color.fn[ spaceName ] = function( value ) {
+
+ // generate a cache for this space if it doesn't exist
+ if ( to && !this[ cache ] ) {
+ this[ cache ] = to( this._rgba );
+ }
+ if ( value === undefined ) {
+ return this[ cache ].slice();
+ }
+
+ var ret,
+ type = jQuery.type( value ),
+ arr = ( type === "array" || type === "object" ) ? value : arguments,
+ local = this[ cache ].slice();
+
+ each( props, function( key, prop ) {
+ var val = arr[ type === "object" ? key : prop.idx ];
+ if ( val == null ) {
+ val = local[ prop.idx ];
+ }
+ local[ prop.idx ] = clamp( val, prop );
+ });
+
+ if ( from ) {
+ ret = color( from( local ) );
+ ret[ cache ] = local;
+ return ret;
+ } else {
+ return color( local );
+ }
+ };
+
+ // makes red() green() blue() alpha() hue() saturation() lightness()
+ each( props, function( key, prop ) {
+ // alpha is included in more than one space
+ if ( color.fn[ key ] ) {
+ return;
+ }
+ color.fn[ key ] = function( value ) {
+ var vtype = jQuery.type( value ),
+ fn = ( key === "alpha" ? ( this._hsla ? "hsla" : "rgba" ) : spaceName ),
+ local = this[ fn ](),
+ cur = local[ prop.idx ],
+ match;
+
+ if ( vtype === "undefined" ) {
+ return cur;
+ }
+
+ if ( vtype === "function" ) {
+ value = value.call( this, cur );
+ vtype = jQuery.type( value );
+ }
+ if ( value == null && prop.empty ) {
+ return this;
+ }
+ if ( vtype === "string" ) {
+ match = rplusequals.exec( value );
+ if ( match ) {
+ value = cur + parseFloat( match[ 2 ] ) * ( match[ 1 ] === "+" ? 1 : -1 );
+ }
+ }
+ local[ prop.idx ] = value;
+ return this[ fn ]( local );
+ };
+ });
+});
+
+// add cssHook and .fx.step function for each named hook.
+// accept a space separated string of properties
+color.hook = function( hook ) {
+ var hooks = hook.split( " " );
+ each( hooks, function( i, hook ) {
+ jQuery.cssHooks[ hook ] = {
+ set: function( elem, value ) {
+ var parsed, curElem,
+ backgroundColor = "";
+
+ if ( value !== "transparent" && ( jQuery.type( value ) !== "string" || ( parsed = stringParse( value ) ) ) ) {
+ value = color( parsed || value );
+ if ( !support.rgba && value._rgba[ 3 ] !== 1 ) {
+ curElem = hook === "backgroundColor" ? elem.parentNode : elem;
+ while (
+ (backgroundColor === "" || backgroundColor === "transparent") &&
+ curElem && curElem.style
+ ) {
+ try {
+ backgroundColor = jQuery.css( curElem, "backgroundColor" );
+ curElem = curElem.parentNode;
+ } catch ( e ) {
+ }
+ }
+
+ value = value.blend( backgroundColor && backgroundColor !== "transparent" ?
+ backgroundColor :
+ "_default" );
+ }
+
+ value = value.toRgbaString();
+ }
+ try {
+ elem.style[ hook ] = value;
+ } catch( e ) {
+ // wrapped to prevent IE from throwing errors on "invalid" values like 'auto' or 'inherit'
+ }
+ }
+ };
+ jQuery.fx.step[ hook ] = function( fx ) {
+ if ( !fx.colorInit ) {
+ fx.start = color( fx.elem, hook );
+ fx.end = color( fx.end );
+ fx.colorInit = true;
+ }
+ jQuery.cssHooks[ hook ].set( fx.elem, fx.start.transition( fx.end, fx.pos ) );
+ };
+ });
+
+};
+
+color.hook( stepHooks );
+
+jQuery.cssHooks.borderColor = {
+ expand: function( value ) {
+ var expanded = {};
+
+ each( [ "Top", "Right", "Bottom", "Left" ], function( i, part ) {
+ expanded[ "border" + part + "Color" ] = value;
+ });
+ return expanded;
+ }
+};
+
+// Basic color names only.
+// Usage of any of the other color names requires adding yourself or including
+// jquery.color.svg-names.js.
+colors = jQuery.Color.names = {
+ // 4.1. Basic color keywords
+ aqua: "#00ffff",
+ black: "#000000",
+ blue: "#0000ff",
+ fuchsia: "#ff00ff",
+ gray: "#808080",
+ green: "#008000",
+ lime: "#00ff00",
+ maroon: "#800000",
+ navy: "#000080",
+ olive: "#808000",
+ purple: "#800080",
+ red: "#ff0000",
+ silver: "#c0c0c0",
+ teal: "#008080",
+ white: "#ffffff",
+ yellow: "#ffff00",
+
+ // 4.2.3. "transparent" color keyword
+ transparent: [ null, null, null, 0 ],
+
+ _default: "#ffffff"
+};
+
+})( jQuery );
+
+
+/******************************************************************************/
+/****************************** CLASS ANIMATIONS ******************************/
+/******************************************************************************/
+(function() {
+
+var classAnimationActions = [ "add", "remove", "toggle" ],
+ shorthandStyles = {
+ border: 1,
+ borderBottom: 1,
+ borderColor: 1,
+ borderLeft: 1,
+ borderRight: 1,
+ borderTop: 1,
+ borderWidth: 1,
+ margin: 1,
+ padding: 1
+ };
+
+$.each([ "borderLeftStyle", "borderRightStyle", "borderBottomStyle", "borderTopStyle" ], function( _, prop ) {
+ $.fx.step[ prop ] = function( fx ) {
+ if ( fx.end !== "none" && !fx.setAttr || fx.pos === 1 && !fx.setAttr ) {
+ jQuery.style( fx.elem, prop, fx.end );
+ fx.setAttr = true;
+ }
+ };
+});
+
+function getElementStyles( elem ) {
+ var key, len,
+ style = elem.ownerDocument.defaultView ?
+ elem.ownerDocument.defaultView.getComputedStyle( elem, null ) :
+ elem.currentStyle,
+ styles = {};
+
+ if ( style && style.length && style[ 0 ] && style[ style[ 0 ] ] ) {
+ len = style.length;
+ while ( len-- ) {
+ key = style[ len ];
+ if ( typeof style[ key ] === "string" ) {
+ styles[ $.camelCase( key ) ] = style[ key ];
+ }
+ }
+ // support: Opera, IE <9
+ } else {
+ for ( key in style ) {
+ if ( typeof style[ key ] === "string" ) {
+ styles[ key ] = style[ key ];
+ }
+ }
+ }
+
+ return styles;
+}
+
+
+function styleDifference( oldStyle, newStyle ) {
+ var diff = {},
+ name, value;
+
+ for ( name in newStyle ) {
+ value = newStyle[ name ];
+ if ( oldStyle[ name ] !== value ) {
+ if ( !shorthandStyles[ name ] ) {
+ if ( $.fx.step[ name ] || !isNaN( parseFloat( value ) ) ) {
+ diff[ name ] = value;
+ }
+ }
+ }
+ }
+
+ return diff;
+}
+
+// support: jQuery <1.8
+if ( !$.fn.addBack ) {
+ $.fn.addBack = function( selector ) {
+ return this.add( selector == null ?
+ this.prevObject : this.prevObject.filter( selector )
+ );
+ };
+}
+
+$.effects.animateClass = function( value, duration, easing, callback ) {
+ var o = $.speed( duration, easing, callback );
+
+ return this.queue( function() {
+ var animated = $( this ),
+ baseClass = animated.attr( "class" ) || "",
+ applyClassChange,
+ allAnimations = o.children ? animated.find( "*" ).addBack() : animated;
+
+ // map the animated objects to store the original styles.
+ allAnimations = allAnimations.map(function() {
+ var el = $( this );
+ return {
+ el: el,
+ start: getElementStyles( this )
+ };
+ });
+
+ // apply class change
+ applyClassChange = function() {
+ $.each( classAnimationActions, function(i, action) {
+ if ( value[ action ] ) {
+ animated[ action + "Class" ]( value[ action ] );
+ }
+ });
+ };
+ applyClassChange();
+
+ // map all animated objects again - calculate new styles and diff
+ allAnimations = allAnimations.map(function() {
+ this.end = getElementStyles( this.el[ 0 ] );
+ this.diff = styleDifference( this.start, this.end );
+ return this;
+ });
+
+ // apply original class
+ animated.attr( "class", baseClass );
+
+ // map all animated objects again - this time collecting a promise
+ allAnimations = allAnimations.map(function() {
+ var styleInfo = this,
+ dfd = $.Deferred(),
+ opts = $.extend({}, o, {
+ queue: false,
+ complete: function() {
+ dfd.resolve( styleInfo );
+ }
+ });
+
+ this.el.animate( this.diff, opts );
+ return dfd.promise();
+ });
+
+ // once all animations have completed:
+ $.when.apply( $, allAnimations.get() ).done(function() {
+
+ // set the final class
+ applyClassChange();
+
+ // for each animated element,
+ // clear all css properties that were animated
+ $.each( arguments, function() {
+ var el = this.el;
+ $.each( this.diff, function(key) {
+ el.css( key, "" );
+ });
+ });
+
+ // this is guarnteed to be there if you use jQuery.speed()
+ // it also handles dequeuing the next anim...
+ o.complete.call( animated[ 0 ] );
+ });
+ });
+};
+
+$.fn.extend({
+ addClass: (function( orig ) {
+ return function( classNames, speed, easing, callback ) {
+ return speed ?
+ $.effects.animateClass.call( this,
+ { add: classNames }, speed, easing, callback ) :
+ orig.apply( this, arguments );
+ };
+ })( $.fn.addClass ),
+
+ removeClass: (function( orig ) {
+ return function( classNames, speed, easing, callback ) {
+ return arguments.length > 1 ?
+ $.effects.animateClass.call( this,
+ { remove: classNames }, speed, easing, callback ) :
+ orig.apply( this, arguments );
+ };
+ })( $.fn.removeClass ),
+
+ toggleClass: (function( orig ) {
+ return function( classNames, force, speed, easing, callback ) {
+ if ( typeof force === "boolean" || force === undefined ) {
+ if ( !speed ) {
+ // without speed parameter
+ return orig.apply( this, arguments );
+ } else {
+ return $.effects.animateClass.call( this,
+ (force ? { add: classNames } : { remove: classNames }),
+ speed, easing, callback );
+ }
+ } else {
+ // without force parameter
+ return $.effects.animateClass.call( this,
+ { toggle: classNames }, force, speed, easing );
+ }
+ };
+ })( $.fn.toggleClass ),
+
+ switchClass: function( remove, add, speed, easing, callback) {
+ return $.effects.animateClass.call( this, {
+ add: add,
+ remove: remove
+ }, speed, easing, callback );
+ }
+});
+
+})();
+
+/******************************************************************************/
+/*********************************** EFFECTS **********************************/
+/******************************************************************************/
+
+(function() {
+
+$.extend( $.effects, {
+ version: "1.10.3",
+
+ // Saves a set of properties in a data storage
+ save: function( element, set ) {
+ for( var i=0; i < set.length; i++ ) {
+ if ( set[ i ] !== null ) {
+ element.data( dataSpace + set[ i ], element[ 0 ].style[ set[ i ] ] );
+ }
+ }
+ },
+
+ // Restores a set of previously saved properties from a data storage
+ restore: function( element, set ) {
+ var val, i;
+ for( i=0; i < set.length; i++ ) {
+ if ( set[ i ] !== null ) {
+ val = element.data( dataSpace + set[ i ] );
+ // support: jQuery 1.6.2
+ // http://bugs.jquery.com/ticket/9917
+ // jQuery 1.6.2 incorrectly returns undefined for any falsy value.
+ // We can't differentiate between "" and 0 here, so we just assume
+ // empty string since it's likely to be a more common value...
+ if ( val === undefined ) {
+ val = "";
+ }
+ element.css( set[ i ], val );
+ }
+ }
+ },
+
+ setMode: function( el, mode ) {
+ if (mode === "toggle") {
+ mode = el.is( ":hidden" ) ? "show" : "hide";
+ }
+ return mode;
+ },
+
+ // Translates a [top,left] array into a baseline value
+ // this should be a little more flexible in the future to handle a string & hash
+ getBaseline: function( origin, original ) {
+ var y, x;
+ switch ( origin[ 0 ] ) {
+ case "top": y = 0; break;
+ case "middle": y = 0.5; break;
+ case "bottom": y = 1; break;
+ default: y = origin[ 0 ] / original.height;
+ }
+ switch ( origin[ 1 ] ) {
+ case "left": x = 0; break;
+ case "center": x = 0.5; break;
+ case "right": x = 1; break;
+ default: x = origin[ 1 ] / original.width;
+ }
+ return {
+ x: x,
+ y: y
+ };
+ },
+
+ // Wraps the element around a wrapper that copies position properties
+ createWrapper: function( element ) {
+
+ // if the element is already wrapped, return it
+ if ( element.parent().is( ".ui-effects-wrapper" )) {
+ return element.parent();
+ }
+
+ // wrap the element
+ var props = {
+ width: element.outerWidth(true),
+ height: element.outerHeight(true),
+ "float": element.css( "float" )
+ },
+ wrapper = $( "<div></div>" )
+ .addClass( "ui-effects-wrapper" )
+ .css({
+ fontSize: "100%",
+ background: "transparent",
+ border: "none",
+ margin: 0,
+ padding: 0
+ }),
+ // Store the size in case width/height are defined in % - Fixes #5245
+ size = {
+ width: element.width(),
+ height: element.height()
+ },
+ active = document.activeElement;
+
+ // support: Firefox
+ // Firefox incorrectly exposes anonymous content
+ // https://bugzilla.mozilla.org/show_bug.cgi?id=561664
+ try {
+ active.id;
+ } catch( e ) {
+ active = document.body;
+ }
+
+ element.wrap( wrapper );
+
+ // Fixes #7595 - Elements lose focus when wrapped.
+ if ( element[ 0 ] === active || $.contains( element[ 0 ], active ) ) {
+ $( active ).focus();
+ }
+
+ wrapper = element.parent(); //Hotfix for jQuery 1.4 since some change in wrap() seems to actually lose the reference to the wrapped element
+
+ // transfer positioning properties to the wrapper
+ if ( element.css( "position" ) === "static" ) {
+ wrapper.css({ position: "relative" });
+ element.css({ position: "relative" });
+ } else {
+ $.extend( props, {
+ position: element.css( "position" ),
+ zIndex: element.css( "z-index" )
+ });
+ $.each([ "top", "left", "bottom", "right" ], function(i, pos) {
+ props[ pos ] = element.css( pos );
+ if ( isNaN( parseInt( props[ pos ], 10 ) ) ) {
+ props[ pos ] = "auto";
+ }
+ });
+ element.css({
+ position: "relative",
+ top: 0,
+ left: 0,
+ right: "auto",
+ bottom: "auto"
+ });
+ }
+ element.css(size);
+
+ return wrapper.css( props ).show();
+ },
+
+ removeWrapper: function( element ) {
+ var active = document.activeElement;
+
+ if ( element.parent().is( ".ui-effects-wrapper" ) ) {
+ element.parent().replaceWith( element );
+
+ // Fixes #7595 - Elements lose focus when wrapped.
+ if ( element[ 0 ] === active || $.contains( element[ 0 ], active ) ) {
+ $( active ).focus();
+ }
+ }
+
+
+ return element;
+ },
+
+ setTransition: function( element, list, factor, value ) {
+ value = value || {};
+ $.each( list, function( i, x ) {
+ var unit = element.cssUnit( x );
+ if ( unit[ 0 ] > 0 ) {
+ value[ x ] = unit[ 0 ] * factor + unit[ 1 ];
+ }
+ });
+ return value;
+ }
+});
+
+// return an effect options object for the given parameters:
+function _normalizeArguments( effect, options, speed, callback ) {
+
+ // allow passing all options as the first parameter
+ if ( $.isPlainObject( effect ) ) {
+ options = effect;
+ effect = effect.effect;
+ }
+
+ // convert to an object
+ effect = { effect: effect };
+
+ // catch (effect, null, ...)
+ if ( options == null ) {
+ options = {};
+ }
+
+ // catch (effect, callback)
+ if ( $.isFunction( options ) ) {
+ callback = options;
+ speed = null;
+ options = {};
+ }
+
+ // catch (effect, speed, ?)
+ if ( typeof options === "number" || $.fx.speeds[ options ] ) {
+ callback = speed;
+ speed = options;
+ options = {};
+ }
+
+ // catch (effect, options, callback)
+ if ( $.isFunction( speed ) ) {
+ callback = speed;
+ speed = null;
+ }
+
+ // add options to effect
+ if ( options ) {
+ $.extend( effect, options );
+ }
+
+ speed = speed || options.duration;
+ effect.duration = $.fx.off ? 0 :
+ typeof speed === "number" ? speed :
+ speed in $.fx.speeds ? $.fx.speeds[ speed ] :
+ $.fx.speeds._default;
+
+ effect.complete = callback || options.complete;
+
+ return effect;
+}
+
+function standardAnimationOption( option ) {
+ // Valid standard speeds (nothing, number, named speed)
+ if ( !option || typeof option === "number" || $.fx.speeds[ option ] ) {
+ return true;
+ }
+
+ // Invalid strings - treat as "normal" speed
+ if ( typeof option === "string" && !$.effects.effect[ option ] ) {
+ return true;
+ }
+
+ // Complete callback
+ if ( $.isFunction( option ) ) {
+ return true;
+ }
+
+ // Options hash (but not naming an effect)
+ if ( typeof option === "object" && !option.effect ) {
+ return true;
+ }
+
+ // Didn't match any standard API
+ return false;
+}
+
+$.fn.extend({
+ effect: function( /* effect, options, speed, callback */ ) {
+ var args = _normalizeArguments.apply( this, arguments ),
+ mode = args.mode,
+ queue = args.queue,
+ effectMethod = $.effects.effect[ args.effect ];
+
+ if ( $.fx.off || !effectMethod ) {
+ // delegate to the original method (e.g., .show()) if possible
+ if ( mode ) {
+ return this[ mode ]( args.duration, args.complete );
+ } else {
+ return this.each( function() {
+ if ( args.complete ) {
+ args.complete.call( this );
+ }
+ });
+ }
+ }
+
+ function run( next ) {
+ var elem = $( this ),
+ complete = args.complete,
+ mode = args.mode;
+
+ function done() {
+ if ( $.isFunction( complete ) ) {
+ complete.call( elem[0] );
+ }
+ if ( $.isFunction( next ) ) {
+ next();
+ }
+ }
+
+ // If the element already has the correct final state, delegate to
+ // the core methods so the internal tracking of "olddisplay" works.
+ if ( elem.is( ":hidden" ) ? mode === "hide" : mode === "show" ) {
+ elem[ mode ]();
+ done();
+ } else {
+ effectMethod.call( elem[0], args, done );
+ }
+ }
+
+ return queue === false ? this.each( run ) : this.queue( queue || "fx", run );
+ },
+
+ show: (function( orig ) {
+ return function( option ) {
+ if ( standardAnimationOption( option ) ) {
+ return orig.apply( this, arguments );
+ } else {
+ var args = _normalizeArguments.apply( this, arguments );
+ args.mode = "show";
+ return this.effect.call( this, args );
+ }
+ };
+ })( $.fn.show ),
+
+ hide: (function( orig ) {
+ return function( option ) {
+ if ( standardAnimationOption( option ) ) {
+ return orig.apply( this, arguments );
+ } else {
+ var args = _normalizeArguments.apply( this, arguments );
+ args.mode = "hide";
+ return this.effect.call( this, args );
+ }
+ };
+ })( $.fn.hide ),
+
+ toggle: (function( orig ) {
+ return function( option ) {
+ if ( standardAnimationOption( option ) || typeof option === "boolean" ) {
+ return orig.apply( this, arguments );
+ } else {
+ var args = _normalizeArguments.apply( this, arguments );
+ args.mode = "toggle";
+ return this.effect.call( this, args );
+ }
+ };
+ })( $.fn.toggle ),
+
+ // helper functions
+ cssUnit: function(key) {
+ var style = this.css( key ),
+ val = [];
+
+ $.each( [ "em", "px", "%", "pt" ], function( i, unit ) {
+ if ( style.indexOf( unit ) > 0 ) {
+ val = [ parseFloat( style ), unit ];
+ }
+ });
+ return val;
+ }
+});
+
+})();
+
+/******************************************************************************/
+/*********************************** EASING ***********************************/
+/******************************************************************************/
+
+(function() {
+
+// based on easing equations from Robert Penner (http://www.robertpenner.com/easing)
+
+var baseEasings = {};
+
+$.each( [ "Quad", "Cubic", "Quart", "Quint", "Expo" ], function( i, name ) {
+ baseEasings[ name ] = function( p ) {
+ return Math.pow( p, i + 2 );
+ };
+});
+
+$.extend( baseEasings, {
+ Sine: function ( p ) {
+ return 1 - Math.cos( p * Math.PI / 2 );
+ },
+ Circ: function ( p ) {
+ return 1 - Math.sqrt( 1 - p * p );
+ },
+ Elastic: function( p ) {
+ return p === 0 || p === 1 ? p :
+ -Math.pow( 2, 8 * (p - 1) ) * Math.sin( ( (p - 1) * 80 - 7.5 ) * Math.PI / 15 );
+ },
+ Back: function( p ) {
+ return p * p * ( 3 * p - 2 );
+ },
+ Bounce: function ( p ) {
+ var pow2,
+ bounce = 4;
+
+ while ( p < ( ( pow2 = Math.pow( 2, --bounce ) ) - 1 ) / 11 ) {}
+ return 1 / Math.pow( 4, 3 - bounce ) - 7.5625 * Math.pow( ( pow2 * 3 - 2 ) / 22 - p, 2 );
+ }
+});
+
+$.each( baseEasings, function( name, easeIn ) {
+ $.easing[ "easeIn" + name ] = easeIn;
+ $.easing[ "easeOut" + name ] = function( p ) {
+ return 1 - easeIn( 1 - p );
+ };
+ $.easing[ "easeInOut" + name ] = function( p ) {
+ return p < 0.5 ?
+ easeIn( p * 2 ) / 2 :
+ 1 - easeIn( p * -2 + 2 ) / 2;
+ };
+});
+
+})();
+
+})(jQuery);
diff --git a/debian/missing-sources/jquery-ui/jquery.ui.menu.js b/debian/missing-sources/jquery-ui/jquery.ui.menu.js
new file mode 100644
index 0000000..ace12e2
--- /dev/null
+++ b/debian/missing-sources/jquery-ui/jquery.ui.menu.js
@@ -0,0 +1,621 @@
+/*!
+ * jQuery UI Menu 1.10.3
+ * http://jqueryui.com
+ *
+ * Copyright 2013 jQuery Foundation and other contributors
+ * Released under the MIT license.
+ * http://jquery.org/license
+ *
+ * http://api.jqueryui.com/menu/
+ *
+ * Depends:
+ * jquery.ui.core.js
+ * jquery.ui.widget.js
+ * jquery.ui.position.js
+ */
+(function( $, undefined ) {
+
+$.widget( "ui.menu", {
+ version: "1.10.3",
+ defaultElement: "<ul>",
+ delay: 300,
+ options: {
+ icons: {
+ submenu: "ui-icon-carat-1-e"
+ },
+ menus: "ul",
+ position: {
+ my: "left top",
+ at: "right top"
+ },
+ role: "menu",
+
+ // callbacks
+ blur: null,
+ focus: null,
+ select: null
+ },
+
+ _create: function() {
+ this.activeMenu = this.element;
+ // flag used to prevent firing of the click handler
+ // as the event bubbles up through nested menus
+ this.mouseHandled = false;
+ this.element
+ .uniqueId()
+ .addClass( "ui-menu ui-widget ui-widget-content ui-corner-all" )
+ .toggleClass( "ui-menu-icons", !!this.element.find( ".ui-icon" ).length )
+ .attr({
+ role: this.options.role,
+ tabIndex: 0
+ })
+ // need to catch all clicks on disabled menu
+ // not possible through _on
+ .bind( "click" + this.eventNamespace, $.proxy(function( event ) {
+ if ( this.options.disabled ) {
+ event.preventDefault();
+ }
+ }, this ));
+
+ if ( this.options.disabled ) {
+ this.element
+ .addClass( "ui-state-disabled" )
+ .attr( "aria-disabled", "true" );
+ }
+
+ this._on({
+ // Prevent focus from sticking to links inside menu after clicking
+ // them (focus should always stay on UL during navigation).
+ "mousedown .ui-menu-item > a": function( event ) {
+ event.preventDefault();
+ },
+ "click .ui-state-disabled > a": function( event ) {
+ event.preventDefault();
+ },
+ "click .ui-menu-item:has(a)": function( event ) {
+ var target = $( event.target ).closest( ".ui-menu-item" );
+ if ( !this.mouseHandled && target.not( ".ui-state-disabled" ).length ) {
+ this.mouseHandled = true;
+
+ this.select( event );
+ // Open submenu on click
+ if ( target.has( ".ui-menu" ).length ) {
+ this.expand( event );
+ } else if ( !this.element.is( ":focus" ) ) {
+ // Redirect focus to the menu
+ this.element.trigger( "focus", [ true ] );
+
+ // If the active item is on the top level, let it stay active.
+ // Otherwise, blur the active item since it is no longer visible.
+ if ( this.active && this.active.parents( ".ui-menu" ).length === 1 ) {
+ clearTimeout( this.timer );
+ }
+ }
+ }
+ },
+ "mouseenter .ui-menu-item": function( event ) {
+ var target = $( event.currentTarget );
+ // Remove ui-state-active class from siblings of the newly focused menu item
+ // to avoid a jump caused by adjacent elements both having a class with a border
+ target.siblings().children( ".ui-state-active" ).removeClass( "ui-state-active" );
+ this.focus( event, target );
+ },
+ mouseleave: "collapseAll",
+ "mouseleave .ui-menu": "collapseAll",
+ focus: function( event, keepActiveItem ) {
+ // If there's already an active item, keep it active
+ // If not, activate the first item
+ var item = this.active || this.element.children( ".ui-menu-item" ).eq( 0 );
+
+ if ( !keepActiveItem ) {
+ this.focus( event, item );
+ }
+ },
+ blur: function( event ) {
+ this._delay(function() {
+ if ( !$.contains( this.element[0], this.document[0].activeElement ) ) {
+ this.collapseAll( event );
+ }
+ });
+ },
+ keydown: "_keydown"
+ });
+
+ this.refresh();
+
+ // Clicks outside of a menu collapse any open menus
+ this._on( this.document, {
+ click: function( event ) {
+ if ( !$( event.target ).closest( ".ui-menu" ).length ) {
+ this.collapseAll( event );
+ }
+
+ // Reset the mouseHandled flag
+ this.mouseHandled = false;
+ }
+ });
+ },
+
+ _destroy: function() {
+ // Destroy (sub)menus
+ this.element
+ .removeAttr( "aria-activedescendant" )
+ .find( ".ui-menu" ).addBack()
+ .removeClass( "ui-menu ui-widget ui-widget-content ui-corner-all ui-menu-icons" )
+ .removeAttr( "role" )
+ .removeAttr( "tabIndex" )
+ .removeAttr( "aria-labelledby" )
+ .removeAttr( "aria-expanded" )
+ .removeAttr( "aria-hidden" )
+ .removeAttr( "aria-disabled" )
+ .removeUniqueId()
+ .show();
+
+ // Destroy menu items
+ this.element.find( ".ui-menu-item" )
+ .removeClass( "ui-menu-item" )
+ .removeAttr( "role" )
+ .removeAttr( "aria-disabled" )
+ .children( "a" )
+ .removeUniqueId()
+ .removeClass( "ui-corner-all ui-state-hover" )
+ .removeAttr( "tabIndex" )
+ .removeAttr( "role" )
+ .removeAttr( "aria-haspopup" )
+ .children().each( function() {
+ var elem = $( this );
+ if ( elem.data( "ui-menu-submenu-carat" ) ) {
+ elem.remove();
+ }
+ });
+
+ // Destroy menu dividers
+ this.element.find( ".ui-menu-divider" ).removeClass( "ui-menu-divider ui-widget-content" );
+ },
+
+ _keydown: function( event ) {
+ /*jshint maxcomplexity:20*/
+ var match, prev, character, skip, regex,
+ preventDefault = true;
+
+ function escape( value ) {
+ return value.replace( /[\-\[\]{}()*+?.,\\\^$|#\s]/g, "\\$&" );
+ }
+
+ switch ( event.keyCode ) {
+ case $.ui.keyCode.PAGE_UP:
+ this.previousPage( event );
+ break;
+ case $.ui.keyCode.PAGE_DOWN:
+ this.nextPage( event );
+ break;
+ case $.ui.keyCode.HOME:
+ this._move( "first", "first", event );
+ break;
+ case $.ui.keyCode.END:
+ this._move( "last", "last", event );
+ break;
+ case $.ui.keyCode.UP:
+ this.previous( event );
+ break;
+ case $.ui.keyCode.DOWN:
+ this.next( event );
+ break;
+ case $.ui.keyCode.LEFT:
+ this.collapse( event );
+ break;
+ case $.ui.keyCode.RIGHT:
+ if ( this.active && !this.active.is( ".ui-state-disabled" ) ) {
+ this.expand( event );
+ }
+ break;
+ case $.ui.keyCode.ENTER:
+ case $.ui.keyCode.SPACE:
+ this._activate( event );
+ break;
+ case $.ui.keyCode.ESCAPE:
+ this.collapse( event );
+ break;
+ default:
+ preventDefault = false;
+ prev = this.previousFilter || "";
+ character = String.fromCharCode( event.keyCode );
+ skip = false;
+
+ clearTimeout( this.filterTimer );
+
+ if ( character === prev ) {
+ skip = true;
+ } else {
+ character = prev + character;
+ }
+
+ regex = new RegExp( "^" + escape( character ), "i" );
+ match = this.activeMenu.children( ".ui-menu-item" ).filter(function() {
+ return regex.test( $( this ).children( "a" ).text() );
+ });
+ match = skip && match.index( this.active.next() ) !== -1 ?
+ this.active.nextAll( ".ui-menu-item" ) :
+ match;
+
+ // If no matches on the current filter, reset to the last character pressed
+ // to move down the menu to the first item that starts with that character
+ if ( !match.length ) {
+ character = String.fromCharCode( event.keyCode );
+ regex = new RegExp( "^" + escape( character ), "i" );
+ match = this.activeMenu.children( ".ui-menu-item" ).filter(function() {
+ return regex.test( $( this ).children( "a" ).text() );
+ });
+ }
+
+ if ( match.length ) {
+ this.focus( event, match );
+ if ( match.length > 1 ) {
+ this.previousFilter = character;
+ this.filterTimer = this._delay(function() {
+ delete this.previousFilter;
+ }, 1000 );
+ } else {
+ delete this.previousFilter;
+ }
+ } else {
+ delete this.previousFilter;
+ }
+ }
+
+ if ( preventDefault ) {
+ event.preventDefault();
+ }
+ },
+
+ _activate: function( event ) {
+ if ( !this.active.is( ".ui-state-disabled" ) ) {
+ if ( this.active.children( "a[aria-haspopup='true']" ).length ) {
+ this.expand( event );
+ } else {
+ this.select( event );
+ }
+ }
+ },
+
+ refresh: function() {
+ var menus,
+ icon = this.options.icons.submenu,
+ submenus = this.element.find( this.options.menus );
+
+ // Initialize nested menus
+ submenus.filter( ":not(.ui-menu)" )
+ .addClass( "ui-menu ui-widget ui-widget-content ui-corner-all" )
+ .hide()
+ .attr({
+ role: this.options.role,
+ "aria-hidden": "true",
+ "aria-expanded": "false"
+ })
+ .each(function() {
+ var menu = $( this ),
+ item = menu.prev( "a" ),
+ submenuCarat = $( "<span>" )
+ .addClass( "ui-menu-icon ui-icon " + icon )
+ .data( "ui-menu-submenu-carat", true );
+
+ item
+ .attr( "aria-haspopup", "true" )
+ .prepend( submenuCarat );
+ menu.attr( "aria-labelledby", item.attr( "id" ) );
+ });
+
+ menus = submenus.add( this.element );
+
+ // Don't refresh list items that are already adapted
+ menus.children( ":not(.ui-menu-item):has(a)" )
+ .addClass( "ui-menu-item" )
+ .attr( "role", "presentation" )
+ .children( "a" )
+ .uniqueId()
+ .addClass( "ui-corner-all" )
+ .attr({
+ tabIndex: -1,
+ role: this._itemRole()
+ });
+
+ // Initialize unlinked menu-items containing spaces and/or dashes only as dividers
+ menus.children( ":not(.ui-menu-item)" ).each(function() {
+ var item = $( this );
+ // hyphen, em dash, en dash
+ if ( !/[^\-\u2014\u2013\s]/.test( item.text() ) ) {
+ item.addClass( "ui-widget-content ui-menu-divider" );
+ }
+ });
+
+ // Add aria-disabled attribute to any disabled menu item
+ menus.children( ".ui-state-disabled" ).attr( "aria-disabled", "true" );
+
+ // If the active item has been removed, blur the menu
+ if ( this.active && !$.contains( this.element[ 0 ], this.active[ 0 ] ) ) {
+ this.blur();
+ }
+ },
+
+ _itemRole: function() {
+ return {
+ menu: "menuitem",
+ listbox: "option"
+ }[ this.options.role ];
+ },
+
+ _setOption: function( key, value ) {
+ if ( key === "icons" ) {
+ this.element.find( ".ui-menu-icon" )
+ .removeClass( this.options.icons.submenu )
+ .addClass( value.submenu );
+ }
+ this._super( key, value );
+ },
+
+ focus: function( event, item ) {
+ var nested, focused;
+ this.blur( event, event && event.type === "focus" );
+
+ this._scrollIntoView( item );
+
+ this.active = item.first();
+ focused = this.active.children( "a" ).addClass( "ui-state-focus" );
+ // Only update aria-activedescendant if there's a role
+ // otherwise we assume focus is managed elsewhere
+ if ( this.options.role ) {
+ this.element.attr( "aria-activedescendant", focused.attr( "id" ) );
+ }
+
+ // Highlight active parent menu item, if any
+ this.active
+ .parent()
+ .closest( ".ui-menu-item" )
+ .children( "a:first" )
+ .addClass( "ui-state-active" );
+
+ if ( event && event.type === "keydown" ) {
+ this._close();
+ } else {
+ this.timer = this._delay(function() {
+ this._close();
+ }, this.delay );
+ }
+
+ nested = item.children( ".ui-menu" );
+ if ( nested.length && ( /^mouse/.test( event.type ) ) ) {
+ this._startOpening(nested);
+ }
+ this.activeMenu = item.parent();
+
+ this._trigger( "focus", event, { item: item } );
+ },
+
+ _scrollIntoView: function( item ) {
+ var borderTop, paddingTop, offset, scroll, elementHeight, itemHeight;
+ if ( this._hasScroll() ) {
+ borderTop = parseFloat( $.css( this.activeMenu[0], "borderTopWidth" ) ) || 0;
+ paddingTop = parseFloat( $.css( this.activeMenu[0], "paddingTop" ) ) || 0;
+ offset = item.offset().top - this.activeMenu.offset().top - borderTop - paddingTop;
+ scroll = this.activeMenu.scrollTop();
+ elementHeight = this.activeMenu.height();
+ itemHeight = item.height();
+
+ if ( offset < 0 ) {
+ this.activeMenu.scrollTop( scroll + offset );
+ } else if ( offset + itemHeight > elementHeight ) {
+ this.activeMenu.scrollTop( scroll + offset - elementHeight + itemHeight );
+ }
+ }
+ },
+
+ blur: function( event, fromFocus ) {
+ if ( !fromFocus ) {
+ clearTimeout( this.timer );
+ }
+
+ if ( !this.active ) {
+ return;
+ }
+
+ this.active.children( "a" ).removeClass( "ui-state-focus" );
+ this.active = null;
+
+ this._trigger( "blur", event, { item: this.active } );
+ },
+
+ _startOpening: function( submenu ) {
+ clearTimeout( this.timer );
+
+ // Don't open if already open fixes a Firefox bug that caused a .5 pixel
+ // shift in the submenu position when mousing over the carat icon
+ if ( submenu.attr( "aria-hidden" ) !== "true" ) {
+ return;
+ }
+
+ this.timer = this._delay(function() {
+ this._close();
+ this._open( submenu );
+ }, this.delay );
+ },
+
+ _open: function( submenu ) {
+ var position = $.extend({
+ of: this.active
+ }, this.options.position );
+
+ clearTimeout( this.timer );
+ this.element.find( ".ui-menu" ).not( submenu.parents( ".ui-menu" ) )
+ .hide()
+ .attr( "aria-hidden", "true" );
+
+ submenu
+ .show()
+ .removeAttr( "aria-hidden" )
+ .attr( "aria-expanded", "true" )
+ .position( position );
+ },
+
+ collapseAll: function( event, all ) {
+ clearTimeout( this.timer );
+ this.timer = this._delay(function() {
+ // If we were passed an event, look for the submenu that contains the event
+ var currentMenu = all ? this.element :
+ $( event && event.target ).closest( this.element.find( ".ui-menu" ) );
+
+ // If we found no valid submenu ancestor, use the main menu to close all sub menus anyway
+ if ( !currentMenu.length ) {
+ currentMenu = this.element;
+ }
+
+ this._close( currentMenu );
+
+ this.blur( event );
+ this.activeMenu = currentMenu;
+ }, this.delay );
+ },
+
+ // With no arguments, closes the currently active menu - if nothing is active
+ // it closes all menus. If passed an argument, it will search for menus BELOW
+ _close: function( startMenu ) {
+ if ( !startMenu ) {
+ startMenu = this.active ? this.active.parent() : this.element;
+ }
+
+ startMenu
+ .find( ".ui-menu" )
+ .hide()
+ .attr( "aria-hidden", "true" )
+ .attr( "aria-expanded", "false" )
+ .end()
+ .find( "a.ui-state-active" )
+ .removeClass( "ui-state-active" );
+ },
+
+ collapse: function( event ) {
+ var newItem = this.active &&
+ this.active.parent().closest( ".ui-menu-item", this.element );
+ if ( newItem && newItem.length ) {
+ this._close();
+ this.focus( event, newItem );
+ }
+ },
+
+ expand: function( event ) {
+ var newItem = this.active &&
+ this.active
+ .children( ".ui-menu " )
+ .children( ".ui-menu-item" )
+ .first();
+
+ if ( newItem && newItem.length ) {
+ this._open( newItem.parent() );
+
+ // Delay so Firefox will not hide activedescendant change in expanding submenu from AT
+ this._delay(function() {
+ this.focus( event, newItem );
+ });
+ }
+ },
+
+ next: function( event ) {
+ this._move( "next", "first", event );
+ },
+
+ previous: function( event ) {
+ this._move( "prev", "last", event );
+ },
+
+ isFirstItem: function() {
+ return this.active && !this.active.prevAll( ".ui-menu-item" ).length;
+ },
+
+ isLastItem: function() {
+ return this.active && !this.active.nextAll( ".ui-menu-item" ).length;
+ },
+
+ _move: function( direction, filter, event ) {
+ var next;
+ if ( this.active ) {
+ if ( direction === "first" || direction === "last" ) {
+ next = this.active
+ [ direction === "first" ? "prevAll" : "nextAll" ]( ".ui-menu-item" )
+ .eq( -1 );
+ } else {
+ next = this.active
+ [ direction + "All" ]( ".ui-menu-item" )
+ .eq( 0 );
+ }
+ }
+ if ( !next || !next.length || !this.active ) {
+ next = this.activeMenu.children( ".ui-menu-item" )[ filter ]();
+ }
+
+ this.focus( event, next );
+ },
+
+ nextPage: function( event ) {
+ var item, base, height;
+
+ if ( !this.active ) {
+ this.next( event );
+ return;
+ }
+ if ( this.isLastItem() ) {
+ return;
+ }
+ if ( this._hasScroll() ) {
+ base = this.active.offset().top;
+ height = this.element.height();
+ this.active.nextAll( ".ui-menu-item" ).each(function() {
+ item = $( this );
+ return item.offset().top - base - height < 0;
+ });
+
+ this.focus( event, item );
+ } else {
+ this.focus( event, this.activeMenu.children( ".ui-menu-item" )
+ [ !this.active ? "first" : "last" ]() );
+ }
+ },
+
+ previousPage: function( event ) {
+ var item, base, height;
+ if ( !this.active ) {
+ this.next( event );
+ return;
+ }
+ if ( this.isFirstItem() ) {
+ return;
+ }
+ if ( this._hasScroll() ) {
+ base = this.active.offset().top;
+ height = this.element.height();
+ this.active.prevAll( ".ui-menu-item" ).each(function() {
+ item = $( this );
+ return item.offset().top - base + height > 0;
+ });
+
+ this.focus( event, item );
+ } else {
+ this.focus( event, this.activeMenu.children( ".ui-menu-item" ).first() );
+ }
+ },
+
+ _hasScroll: function() {
+ return this.element.outerHeight() < this.element.prop( "scrollHeight" );
+ },
+
+ select: function( event ) {
+ // TODO: It should never be possible to not have an active item at this
+ // point, but the tests don't trigger mouseenter before click.
+ this.active = this.active || $( event.target ).closest( ".ui-menu-item" );
+ var ui = { item: this.active };
+ if ( !this.active.has( ".ui-menu" ).length ) {
+ this.collapseAll( event, true );
+ }
+ this._trigger( "select", event, ui );
+ }
+});
+
+}( jQuery ));
diff --git a/debian/missing-sources/jquery-ui/jquery.ui.mouse.js b/debian/missing-sources/jquery-ui/jquery.ui.mouse.js
new file mode 100644
index 0000000..62022ce
--- /dev/null
+++ b/debian/missing-sources/jquery-ui/jquery.ui.mouse.js
@@ -0,0 +1,169 @@
+/*!
+ * jQuery UI Mouse 1.10.3
+ * http://jqueryui.com
+ *
+ * Copyright 2013 jQuery Foundation and other contributors
+ * Released under the MIT license.
+ * http://jquery.org/license
+ *
+ * http://api.jqueryui.com/mouse/
+ *
+ * Depends:
+ * jquery.ui.widget.js
+ */
+(function( $, undefined ) {
+
+var mouseHandled = false;
+$( document ).mouseup( function() {
+ mouseHandled = false;
+});
+
+$.widget("ui.mouse", {
+ version: "1.10.3",
+ options: {
+ cancel: "input,textarea,button,select,option",
+ distance: 1,
+ delay: 0
+ },
+ _mouseInit: function() {
+ var that = this;
+
+ this.element
+ .bind("mousedown."+this.widgetName, function(event) {
+ return that._mouseDown(event);
+ })
+ .bind("click."+this.widgetName, function(event) {
+ if (true === $.data(event.target, that.widgetName + ".preventClickEvent")) {
+ $.removeData(event.target, that.widgetName + ".preventClickEvent");
+ event.stopImmediatePropagation();
+ return false;
+ }
+ });
+
+ this.started = false;
+ },
+
+ // TODO: make sure destroying one instance of mouse doesn't mess with
+ // other instances of mouse
+ _mouseDestroy: function() {
+ this.element.unbind("."+this.widgetName);
+ if ( this._mouseMoveDelegate ) {
+ $(document)
+ .unbind("mousemove."+this.widgetName, this._mouseMoveDelegate)
+ .unbind("mouseup."+this.widgetName, this._mouseUpDelegate);
+ }
+ },
+
+ _mouseDown: function(event) {
+ // don't let more than one widget handle mouseStart
+ if( mouseHandled ) { return; }
+
+ // we may have missed mouseup (out of window)
+ (this._mouseStarted && this._mouseUp(event));
+
+ this._mouseDownEvent = event;
+
+ var that = this,
+ btnIsLeft = (event.which === 1),
+ // event.target.nodeName works around a bug in IE 8 with
+ // disabled inputs (#7620)
+ elIsCancel = (typeof this.options.cancel === "string" && event.target.nodeName ? $(event.target).closest(this.options.cancel).length : false);
+ if (!btnIsLeft || elIsCancel || !this._mouseCapture(event)) {
+ return true;
+ }
+
+ this.mouseDelayMet = !this.options.delay;
+ if (!this.mouseDelayMet) {
+ this._mouseDelayTimer = setTimeout(function() {
+ that.mouseDelayMet = true;
+ }, this.options.delay);
+ }
+
+ if (this._mouseDistanceMet(event) && this._mouseDelayMet(event)) {
+ this._mouseStarted = (this._mouseStart(event) !== false);
+ if (!this._mouseStarted) {
+ event.preventDefault();
+ return true;
+ }
+ }
+
+ // Click event may never have fired (Gecko & Opera)
+ if (true === $.data(event.target, this.widgetName + ".preventClickEvent")) {
+ $.removeData(event.target, this.widgetName + ".preventClickEvent");
+ }
+
+ // these delegates are required to keep context
+ this._mouseMoveDelegate = function(event) {
+ return that._mouseMove(event);
+ };
+ this._mouseUpDelegate = function(event) {
+ return that._mouseUp(event);
+ };
+ $(document)
+ .bind("mousemove."+this.widgetName, this._mouseMoveDelegate)
+ .bind("mouseup."+this.widgetName, this._mouseUpDelegate);
+
+ event.preventDefault();
+
+ mouseHandled = true;
+ return true;
+ },
+
+ _mouseMove: function(event) {
+ // IE mouseup check - mouseup happened when mouse was out of window
+ if ($.ui.ie && ( !document.documentMode || document.documentMode < 9 ) && !event.button) {
+ return this._mouseUp(event);
+ }
+
+ if (this._mouseStarted) {
+ this._mouseDrag(event);
+ return event.preventDefault();
+ }
+
+ if (this._mouseDistanceMet(event) && this._mouseDelayMet(event)) {
+ this._mouseStarted =
+ (this._mouseStart(this._mouseDownEvent, event) !== false);
+ (this._mouseStarted ? this._mouseDrag(event) : this._mouseUp(event));
+ }
+
+ return !this._mouseStarted;
+ },
+
+ _mouseUp: function(event) {
+ $(document)
+ .unbind("mousemove."+this.widgetName, this._mouseMoveDelegate)
+ .unbind("mouseup."+this.widgetName, this._mouseUpDelegate);
+
+ if (this._mouseStarted) {
+ this._mouseStarted = false;
+
+ if (event.target === this._mouseDownEvent.target) {
+ $.data(event.target, this.widgetName + ".preventClickEvent", true);
+ }
+
+ this._mouseStop(event);
+ }
+
+ return false;
+ },
+
+ _mouseDistanceMet: function(event) {
+ return (Math.max(
+ Math.abs(this._mouseDownEvent.pageX - event.pageX),
+ Math.abs(this._mouseDownEvent.pageY - event.pageY)
+ ) >= this.options.distance
+ );
+ },
+
+ _mouseDelayMet: function(/* event */) {
+ return this.mouseDelayMet;
+ },
+
+ // These are placeholder methods, to be overriden by extending plugin
+ _mouseStart: function(/* event */) {},
+ _mouseDrag: function(/* event */) {},
+ _mouseStop: function(/* event */) {},
+ _mouseCapture: function(/* event */) { return true; }
+});
+
+})(jQuery);
diff --git a/debian/missing-sources/jquery-ui/jquery.ui.position.js b/debian/missing-sources/jquery-ui/jquery.ui.position.js
new file mode 100644
index 0000000..3fcdf25
--- /dev/null
+++ b/debian/missing-sources/jquery-ui/jquery.ui.position.js
@@ -0,0 +1,497 @@
+/*!
+ * jQuery UI Position 1.10.3
+ * http://jqueryui.com
+ *
+ * Copyright 2013 jQuery Foundation and other contributors
+ * Released under the MIT license.
+ * http://jquery.org/license
+ *
+ * http://api.jqueryui.com/position/
+ */
+(function( $, undefined ) {
+
+$.ui = $.ui || {};
+
+var cachedScrollbarWidth,
+ max = Math.max,
+ abs = Math.abs,
+ round = Math.round,
+ rhorizontal = /left|center|right/,
+ rvertical = /top|center|bottom/,
+ roffset = /[\+\-]\d+(\.[\d]+)?%?/,
+ rposition = /^\w+/,
+ rpercent = /%$/,
+ _position = $.fn.position;
+
+function getOffsets( offsets, width, height ) {
+ return [
+ parseFloat( offsets[ 0 ] ) * ( rpercent.test( offsets[ 0 ] ) ? width / 100 : 1 ),
+ parseFloat( offsets[ 1 ] ) * ( rpercent.test( offsets[ 1 ] ) ? height / 100 : 1 )
+ ];
+}
+
+function parseCss( element, property ) {
+ return parseInt( $.css( element, property ), 10 ) || 0;
+}
+
+function getDimensions( elem ) {
+ var raw = elem[0];
+ if ( raw.nodeType === 9 ) {
+ return {
+ width: elem.width(),
+ height: elem.height(),
+ offset: { top: 0, left: 0 }
+ };
+ }
+ if ( $.isWindow( raw ) ) {
+ return {
+ width: elem.width(),
+ height: elem.height(),
+ offset: { top: elem.scrollTop(), left: elem.scrollLeft() }
+ };
+ }
+ if ( raw.preventDefault ) {
+ return {
+ width: 0,
+ height: 0,
+ offset: { top: raw.pageY, left: raw.pageX }
+ };
+ }
+ return {
+ width: elem.outerWidth(),
+ height: elem.outerHeight(),
+ offset: elem.offset()
+ };
+}
+
+$.position = {
+ scrollbarWidth: function() {
+ if ( cachedScrollbarWidth !== undefined ) {
+ return cachedScrollbarWidth;
+ }
+ var w1, w2,
+ div = $( "<div style='display:block;width:50px;height:50px;overflow:hidden;'><div style='height:100px;width:auto;'></div></div>" ),
+ innerDiv = div.children()[0];
+
+ $( "body" ).append( div );
+ w1 = innerDiv.offsetWidth;
+ div.css( "overflow", "scroll" );
+
+ w2 = innerDiv.offsetWidth;
+
+ if ( w1 === w2 ) {
+ w2 = div[0].clientWidth;
+ }
+
+ div.remove();
+
+ return (cachedScrollbarWidth = w1 - w2);
+ },
+ getScrollInfo: function( within ) {
+ var overflowX = within.isWindow ? "" : within.element.css( "overflow-x" ),
+ overflowY = within.isWindow ? "" : within.element.css( "overflow-y" ),
+ hasOverflowX = overflowX === "scroll" ||
+ ( overflowX === "auto" && within.width < within.element[0].scrollWidth ),
+ hasOverflowY = overflowY === "scroll" ||
+ ( overflowY === "auto" && within.height < within.element[0].scrollHeight );
+ return {
+ width: hasOverflowY ? $.position.scrollbarWidth() : 0,
+ height: hasOverflowX ? $.position.scrollbarWidth() : 0
+ };
+ },
+ getWithinInfo: function( element ) {
+ var withinElement = $( element || window ),
+ isWindow = $.isWindow( withinElement[0] );
+ return {
+ element: withinElement,
+ isWindow: isWindow,
+ offset: withinElement.offset() || { left: 0, top: 0 },
+ scrollLeft: withinElement.scrollLeft(),
+ scrollTop: withinElement.scrollTop(),
+ width: isWindow ? withinElement.width() : withinElement.outerWidth(),
+ height: isWindow ? withinElement.height() : withinElement.outerHeight()
+ };
+ }
+};
+
+$.fn.position = function( options ) {
+ if ( !options || !options.of ) {
+ return _position.apply( this, arguments );
+ }
+
+ // make a copy, we don't want to modify arguments
+ options = $.extend( {}, options );
+
+ var atOffset, targetWidth, targetHeight, targetOffset, basePosition, dimensions,
+ target = $( options.of ),
+ within = $.position.getWithinInfo( options.within ),
+ scrollInfo = $.position.getScrollInfo( within ),
+ collision = ( options.collision || "flip" ).split( " " ),
+ offsets = {};
+
+ dimensions = getDimensions( target );
+ if ( target[0].preventDefault ) {
+ // force left top to allow flipping
+ options.at = "left top";
+ }
+ targetWidth = dimensions.width;
+ targetHeight = dimensions.height;
+ targetOffset = dimensions.offset;
+ // clone to reuse original targetOffset later
+ basePosition = $.extend( {}, targetOffset );
+
+ // force my and at to have valid horizontal and vertical positions
+ // if a value is missing or invalid, it will be converted to center
+ $.each( [ "my", "at" ], function() {
+ var pos = ( options[ this ] || "" ).split( " " ),
+ horizontalOffset,
+ verticalOffset;
+
+ if ( pos.length === 1) {
+ pos = rhorizontal.test( pos[ 0 ] ) ?
+ pos.concat( [ "center" ] ) :
+ rvertical.test( pos[ 0 ] ) ?
+ [ "center" ].concat( pos ) :
+ [ "center", "center" ];
+ }
+ pos[ 0 ] = rhorizontal.test( pos[ 0 ] ) ? pos[ 0 ] : "center";
+ pos[ 1 ] = rvertical.test( pos[ 1 ] ) ? pos[ 1 ] : "center";
+
+ // calculate offsets
+ horizontalOffset = roffset.exec( pos[ 0 ] );
+ verticalOffset = roffset.exec( pos[ 1 ] );
+ offsets[ this ] = [
+ horizontalOffset ? horizontalOffset[ 0 ] : 0,
+ verticalOffset ? verticalOffset[ 0 ] : 0
+ ];
+
+ // reduce to just the positions without the offsets
+ options[ this ] = [
+ rposition.exec( pos[ 0 ] )[ 0 ],
+ rposition.exec( pos[ 1 ] )[ 0 ]
+ ];
+ });
+
+ // normalize collision option
+ if ( collision.length === 1 ) {
+ collision[ 1 ] = collision[ 0 ];
+ }
+
+ if ( options.at[ 0 ] === "right" ) {
+ basePosition.left += targetWidth;
+ } else if ( options.at[ 0 ] === "center" ) {
+ basePosition.left += targetWidth / 2;
+ }
+
+ if ( options.at[ 1 ] === "bottom" ) {
+ basePosition.top += targetHeight;
+ } else if ( options.at[ 1 ] === "center" ) {
+ basePosition.top += targetHeight / 2;
+ }
+
+ atOffset = getOffsets( offsets.at, targetWidth, targetHeight );
+ basePosition.left += atOffset[ 0 ];
+ basePosition.top += atOffset[ 1 ];
+
+ return this.each(function() {
+ var collisionPosition, using,
+ elem = $( this ),
+ elemWidth = elem.outerWidth(),
+ elemHeight = elem.outerHeight(),
+ marginLeft = parseCss( this, "marginLeft" ),
+ marginTop = parseCss( this, "marginTop" ),
+ collisionWidth = elemWidth + marginLeft + parseCss( this, "marginRight" ) + scrollInfo.width,
+ collisionHeight = elemHeight + marginTop + parseCss( this, "marginBottom" ) + scrollInfo.height,
+ position = $.extend( {}, basePosition ),
+ myOffset = getOffsets( offsets.my, elem.outerWidth(), elem.outerHeight() );
+
+ if ( options.my[ 0 ] === "right" ) {
+ position.left -= elemWidth;
+ } else if ( options.my[ 0 ] === "center" ) {
+ position.left -= elemWidth / 2;
+ }
+
+ if ( options.my[ 1 ] === "bottom" ) {
+ position.top -= elemHeight;
+ } else if ( options.my[ 1 ] === "center" ) {
+ position.top -= elemHeight / 2;
+ }
+
+ position.left += myOffset[ 0 ];
+ position.top += myOffset[ 1 ];
+
+ // if the browser doesn't support fractions, then round for consistent results
+ if ( !$.support.offsetFractions ) {
+ position.left = round( position.left );
+ position.top = round( position.top );
+ }
+
+ collisionPosition = {
+ marginLeft: marginLeft,
+ marginTop: marginTop
+ };
+
+ $.each( [ "left", "top" ], function( i, dir ) {
+ if ( $.ui.position[ collision[ i ] ] ) {
+ $.ui.position[ collision[ i ] ][ dir ]( position, {
+ targetWidth: targetWidth,
+ targetHeight: targetHeight,
+ elemWidth: elemWidth,
+ elemHeight: elemHeight,
+ collisionPosition: collisionPosition,
+ collisionWidth: collisionWidth,
+ collisionHeight: collisionHeight,
+ offset: [ atOffset[ 0 ] + myOffset[ 0 ], atOffset [ 1 ] + myOffset[ 1 ] ],
+ my: options.my,
+ at: options.at,
+ within: within,
+ elem : elem
+ });
+ }
+ });
+
+ if ( options.using ) {
+ // adds feedback as second argument to using callback, if present
+ using = function( props ) {
+ var left = targetOffset.left - position.left,
+ right = left + targetWidth - elemWidth,
+ top = targetOffset.top - position.top,
+ bottom = top + targetHeight - elemHeight,
+ feedback = {
+ target: {
+ element: target,
+ left: targetOffset.left,
+ top: targetOffset.top,
+ width: targetWidth,
+ height: targetHeight
+ },
+ element: {
+ element: elem,
+ left: position.left,
+ top: position.top,
+ width: elemWidth,
+ height: elemHeight
+ },
+ horizontal: right < 0 ? "left" : left > 0 ? "right" : "center",
+ vertical: bottom < 0 ? "top" : top > 0 ? "bottom" : "middle"
+ };
+ if ( targetWidth < elemWidth && abs( left + right ) < targetWidth ) {
+ feedback.horizontal = "center";
+ }
+ if ( targetHeight < elemHeight && abs( top + bottom ) < targetHeight ) {
+ feedback.vertical = "middle";
+ }
+ if ( max( abs( left ), abs( right ) ) > max( abs( top ), abs( bottom ) ) ) {
+ feedback.important = "horizontal";
+ } else {
+ feedback.important = "vertical";
+ }
+ options.using.call( this, props, feedback );
+ };
+ }
+
+ elem.offset( $.extend( position, { using: using } ) );
+ });
+};
+
+$.ui.position = {
+ fit: {
+ left: function( position, data ) {
+ var within = data.within,
+ withinOffset = within.isWindow ? within.scrollLeft : within.offset.left,
+ outerWidth = within.width,
+ collisionPosLeft = position.left - data.collisionPosition.marginLeft,
+ overLeft = withinOffset - collisionPosLeft,
+ overRight = collisionPosLeft + data.collisionWidth - outerWidth - withinOffset,
+ newOverRight;
+
+ // element is wider than within
+ if ( data.collisionWidth > outerWidth ) {
+ // element is initially over the left side of within
+ if ( overLeft > 0 && overRight <= 0 ) {
+ newOverRight = position.left + overLeft + data.collisionWidth - outerWidth - withinOffset;
+ position.left += overLeft - newOverRight;
+ // element is initially over right side of within
+ } else if ( overRight > 0 && overLeft <= 0 ) {
+ position.left = withinOffset;
+ // element is initially over both left and right sides of within
+ } else {
+ if ( overLeft > overRight ) {
+ position.left = withinOffset + outerWidth - data.collisionWidth;
+ } else {
+ position.left = withinOffset;
+ }
+ }
+ // too far left -> align with left edge
+ } else if ( overLeft > 0 ) {
+ position.left += overLeft;
+ // too far right -> align with right edge
+ } else if ( overRight > 0 ) {
+ position.left -= overRight;
+ // adjust based on position and margin
+ } else {
+ position.left = max( position.left - collisionPosLeft, position.left );
+ }
+ },
+ top: function( position, data ) {
+ var within = data.within,
+ withinOffset = within.isWindow ? within.scrollTop : within.offset.top,
+ outerHeight = data.within.height,
+ collisionPosTop = position.top - data.collisionPosition.marginTop,
+ overTop = withinOffset - collisionPosTop,
+ overBottom = collisionPosTop + data.collisionHeight - outerHeight - withinOffset,
+ newOverBottom;
+
+ // element is taller than within
+ if ( data.collisionHeight > outerHeight ) {
+ // element is initially over the top of within
+ if ( overTop > 0 && overBottom <= 0 ) {
+ newOverBottom = position.top + overTop + data.collisionHeight - outerHeight - withinOffset;
+ position.top += overTop - newOverBottom;
+ // element is initially over bottom of within
+ } else if ( overBottom > 0 && overTop <= 0 ) {
+ position.top = withinOffset;
+ // element is initially over both top and bottom of within
+ } else {
+ if ( overTop > overBottom ) {
+ position.top = withinOffset + outerHeight - data.collisionHeight;
+ } else {
+ position.top = withinOffset;
+ }
+ }
+ // too far up -> align with top
+ } else if ( overTop > 0 ) {
+ position.top += overTop;
+ // too far down -> align with bottom edge
+ } else if ( overBottom > 0 ) {
+ position.top -= overBottom;
+ // adjust based on position and margin
+ } else {
+ position.top = max( position.top - collisionPosTop, position.top );
+ }
+ }
+ },
+ flip: {
+ left: function( position, data ) {
+ var within = data.within,
+ withinOffset = within.offset.left + within.scrollLeft,
+ outerWidth = within.width,
+ offsetLeft = within.isWindow ? within.scrollLeft : within.offset.left,
+ collisionPosLeft = position.left - data.collisionPosition.marginLeft,
+ overLeft = collisionPosLeft - offsetLeft,
+ overRight = collisionPosLeft + data.collisionWidth - outerWidth - offsetLeft,
+ myOffset = data.my[ 0 ] === "left" ?
+ -data.elemWidth :
+ data.my[ 0 ] === "right" ?
+ data.elemWidth :
+ 0,
+ atOffset = data.at[ 0 ] === "left" ?
+ data.targetWidth :
+ data.at[ 0 ] === "right" ?
+ -data.targetWidth :
+ 0,
+ offset = -2 * data.offset[ 0 ],
+ newOverRight,
+ newOverLeft;
+
+ if ( overLeft < 0 ) {
+ newOverRight = position.left + myOffset + atOffset + offset + data.collisionWidth - outerWidth - withinOffset;
+ if ( newOverRight < 0 || newOverRight < abs( overLeft ) ) {
+ position.left += myOffset + atOffset + offset;
+ }
+ }
+ else if ( overRight > 0 ) {
+ newOverLeft = position.left - data.collisionPosition.marginLeft + myOffset + atOffset + offset - offsetLeft;
+ if ( newOverLeft > 0 || abs( newOverLeft ) < overRight ) {
+ position.left += myOffset + atOffset + offset;
+ }
+ }
+ },
+ top: function( position, data ) {
+ var within = data.within,
+ withinOffset = within.offset.top + within.scrollTop,
+ outerHeight = within.height,
+ offsetTop = within.isWindow ? within.scrollTop : within.offset.top,
+ collisionPosTop = position.top - data.collisionPosition.marginTop,
+ overTop = collisionPosTop - offsetTop,
+ overBottom = collisionPosTop + data.collisionHeight - outerHeight - offsetTop,
+ top = data.my[ 1 ] === "top",
+ myOffset = top ?
+ -data.elemHeight :
+ data.my[ 1 ] === "bottom" ?
+ data.elemHeight :
+ 0,
+ atOffset = data.at[ 1 ] === "top" ?
+ data.targetHeight :
+ data.at[ 1 ] === "bottom" ?
+ -data.targetHeight :
+ 0,
+ offset = -2 * data.offset[ 1 ],
+ newOverTop,
+ newOverBottom;
+ if ( overTop < 0 ) {
+ newOverBottom = position.top + myOffset + atOffset + offset + data.collisionHeight - outerHeight - withinOffset;
+ if ( ( position.top + myOffset + atOffset + offset) > overTop && ( newOverBottom < 0 || newOverBottom < abs( overTop ) ) ) {
+ position.top += myOffset + atOffset + offset;
+ }
+ }
+ else if ( overBottom > 0 ) {
+ newOverTop = position.top - data.collisionPosition.marginTop + myOffset + atOffset + offset - offsetTop;
+ if ( ( position.top + myOffset + atOffset + offset) > overBottom && ( newOverTop > 0 || abs( newOverTop ) < overBottom ) ) {
+ position.top += myOffset + atOffset + offset;
+ }
+ }
+ }
+ },
+ flipfit: {
+ left: function() {
+ $.ui.position.flip.left.apply( this, arguments );
+ $.ui.position.fit.left.apply( this, arguments );
+ },
+ top: function() {
+ $.ui.position.flip.top.apply( this, arguments );
+ $.ui.position.fit.top.apply( this, arguments );
+ }
+ }
+};
+
+// fraction support test
+(function () {
+ var testElement, testElementParent, testElementStyle, offsetLeft, i,
+ body = document.getElementsByTagName( "body" )[ 0 ],
+ div = document.createElement( "div" );
+
+ //Create a "fake body" for testing based on method used in jQuery.support
+ testElement = document.createElement( body ? "div" : "body" );
+ testElementStyle = {
+ visibility: "hidden",
+ width: 0,
+ height: 0,
+ border: 0,
+ margin: 0,
+ background: "none"
+ };
+ if ( body ) {
+ $.extend( testElementStyle, {
+ position: "absolute",
+ left: "-1000px",
+ top: "-1000px"
+ });
+ }
+ for ( i in testElementStyle ) {
+ testElement.style[ i ] = testElementStyle[ i ];
+ }
+ testElement.appendChild( div );
+ testElementParent = body || document.documentElement;
+ testElementParent.insertBefore( testElement, testElementParent.firstChild );
+
+ div.style.cssText = "position: absolute; left: 10.7432222px;";
+
+ offsetLeft = $( div ).offset().left;
+ $.support.offsetFractions = offsetLeft > 10 && offsetLeft < 11;
+
+ testElement.innerHTML = "";
+ testElementParent.removeChild( testElement );
+})();
+
+}( jQuery ) );
diff --git a/debian/missing-sources/jquery-ui/jquery.ui.progressbar.js b/debian/missing-sources/jquery-ui/jquery.ui.progressbar.js
new file mode 100644
index 0000000..70d716e
--- /dev/null
+++ b/debian/missing-sources/jquery-ui/jquery.ui.progressbar.js
@@ -0,0 +1,145 @@
+/*!
+ * jQuery UI Progressbar 1.10.3
+ * http://jqueryui.com
+ *
+ * Copyright 2013 jQuery Foundation and other contributors
+ * Released under the MIT license.
+ * http://jquery.org/license
+ *
+ * http://api.jqueryui.com/progressbar/
+ *
+ * Depends:
+ * jquery.ui.core.js
+ * jquery.ui.widget.js
+ */
+(function( $, undefined ) {
+
+$.widget( "ui.progressbar", {
+ version: "1.10.3",
+ options: {
+ max: 100,
+ value: 0,
+
+ change: null,
+ complete: null
+ },
+
+ min: 0,
+
+ _create: function() {
+ // Constrain initial value
+ this.oldValue = this.options.value = this._constrainedValue();
+
+ this.element
+ .addClass( "ui-progressbar ui-widget ui-widget-content ui-corner-all" )
+ .attr({
+ // Only set static values, aria-valuenow and aria-valuemax are
+ // set inside _refreshValue()
+ role: "progressbar",
+ "aria-valuemin": this.min
+ });
+
+ this.valueDiv = $( "<div class='ui-progressbar-value ui-widget-header ui-corner-left'></div>" )
+ .appendTo( this.element );
+
+ this._refreshValue();
+ },
+
+ _destroy: function() {
+ this.element
+ .removeClass( "ui-progressbar ui-widget ui-widget-content ui-corner-all" )
+ .removeAttr( "role" )
+ .removeAttr( "aria-valuemin" )
+ .removeAttr( "aria-valuemax" )
+ .removeAttr( "aria-valuenow" );
+
+ this.valueDiv.remove();
+ },
+
+ value: function( newValue ) {
+ if ( newValue === undefined ) {
+ return this.options.value;
+ }
+
+ this.options.value = this._constrainedValue( newValue );
+ this._refreshValue();
+ },
+
+ _constrainedValue: function( newValue ) {
+ if ( newValue === undefined ) {
+ newValue = this.options.value;
+ }
+
+ this.indeterminate = newValue === false;
+
+ // sanitize value
+ if ( typeof newValue !== "number" ) {
+ newValue = 0;
+ }
+
+ return this.indeterminate ? false :
+ Math.min( this.options.max, Math.max( this.min, newValue ) );
+ },
+
+ _setOptions: function( options ) {
+ // Ensure "value" option is set after other values (like max)
+ var value = options.value;
+ delete options.value;
+
+ this._super( options );
+
+ this.options.value = this._constrainedValue( value );
+ this._refreshValue();
+ },
+
+ _setOption: function( key, value ) {
+ if ( key === "max" ) {
+ // Don't allow a max less than min
+ value = Math.max( this.min, value );
+ }
+
+ this._super( key, value );
+ },
+
+ _percentage: function() {
+ return this.indeterminate ? 100 : 100 * ( this.options.value - this.min ) / ( this.options.max - this.min );
+ },
+
+ _refreshValue: function() {
+ var value = this.options.value,
+ percentage = this._percentage();
+
+ this.valueDiv
+ .toggle( this.indeterminate || value > this.min )
+ .toggleClass( "ui-corner-right", value === this.options.max )
+ .width( percentage.toFixed(0) + "%" );
+
+ this.element.toggleClass( "ui-progressbar-indeterminate", this.indeterminate );
+
+ if ( this.indeterminate ) {
+ this.element.removeAttr( "aria-valuenow" );
+ if ( !this.overlayDiv ) {
+ this.overlayDiv = $( "<div class='ui-progressbar-overlay'></div>" ).appendTo( this.valueDiv );
+ }
+ } else {
+ this.element.attr({
+ "aria-valuemax": this.options.max,
+ "aria-valuenow": value
+ });
+ if ( this.overlayDiv ) {
+ this.overlayDiv.remove();
+ this.overlayDiv = null;
+ }
+ }
+
+ if ( this.oldValue !== value ) {
+ this.oldValue = value;
+ this._trigger( "change" );
+ }
+ if ( value === this.options.max ) {
+ this._trigger( "complete" );
+ }
+ }
+});
+
+})( jQuery );
diff --git a/debian/missing-sources/jquery-ui/jquery.ui.resizable.js b/debian/missing-sources/jquery-ui/jquery.ui.resizable.js
new file mode 100644
index 0000000..f007732
--- /dev/null
+++ b/debian/missing-sources/jquery-ui/jquery.ui.resizable.js
@@ -0,0 +1,968 @@
+/*!
+ * jQuery UI Resizable 1.10.3
+ * http://jqueryui.com
+ *
+ * Copyright 2013 jQuery Foundation and other contributors
+ * Released under the MIT license.
+ * http://jquery.org/license
+ *
+ * http://api.jqueryui.com/resizable/
+ *
+ * Depends:
+ * jquery.ui.core.js
+ * jquery.ui.mouse.js
+ * jquery.ui.widget.js
+ */
+(function( $, undefined ) {
+
+function num(v) {
+ return parseInt(v, 10) || 0;
+}
+
+function isNumber(value) {
+ return !isNaN(parseInt(value, 10));
+}
+
+$.widget("ui.resizable", $.ui.mouse, {
+ version: "1.10.3",
+ widgetEventPrefix: "resize",
+ options: {
+ alsoResize: false,
+ animate: false,
+ animateDuration: "slow",
+ animateEasing: "swing",
+ aspectRatio: false,
+ autoHide: false,
+ containment: false,
+ ghost: false,
+ grid: false,
+ handles: "e,s,se",
+ helper: false,
+ maxHeight: null,
+ maxWidth: null,
+ minHeight: 10,
+ minWidth: 10,
+ // See #7960
+ zIndex: 90,
+
+ // callbacks
+ resize: null,
+ start: null,
+ stop: null
+ },
+ _create: function() {
+
+ var n, i, handle, axis, hname,
+ that = this,
+ o = this.options;
+ this.element.addClass("ui-resizable");
+
+ $.extend(this, {
+ _aspectRatio: !!(o.aspectRatio),
+ aspectRatio: o.aspectRatio,
+ originalElement: this.element,
+ _proportionallyResizeElements: [],
+ _helper: o.helper || o.ghost || o.animate ? o.helper || "ui-resizable-helper" : null
+ });
+
+ //Wrap the element if it cannot hold child nodes
+ if(this.element[0].nodeName.match(/canvas|textarea|input|select|button|img/i)) {
+
+ //Create a wrapper element and set the wrapper to the new current internal element
+ this.element.wrap(
+ $("<div class='ui-wrapper' style='overflow: hidden;'></div>").css({
+ position: this.element.css("position"),
+ width: this.element.outerWidth(),
+ height: this.element.outerHeight(),
+ top: this.element.css("top"),
+ left: this.element.css("left")
+ })
+ );
+
+ //Overwrite the original this.element
+ this.element = this.element.parent().data(
+ "ui-resizable", this.element.data("ui-resizable")
+ );
+
+ this.elementIsWrapper = true;
+
+ //Move margins to the wrapper
+ this.element.css({ marginLeft: this.originalElement.css("marginLeft"), marginTop: this.originalElement.css("marginTop"), marginRight: this.originalElement.css("marginRight"), marginBottom: this.originalElement.css("marginBottom") });
+ this.originalElement.css({ marginLeft: 0, marginTop: 0, marginRight: 0, marginBottom: 0});
+
+ //Prevent Safari textarea resize
+ this.originalResizeStyle = this.originalElement.css("resize");
+ this.originalElement.css("resize", "none");
+
+ //Push the actual element to our proportionallyResize internal array
+ this._proportionallyResizeElements.push(this.originalElement.css({ position: "static", zoom: 1, display: "block" }));
+
+ // avoid IE jump (hard set the margin)
+ this.originalElement.css({ margin: this.originalElement.css("margin") });
+
+ // fix handlers offset
+ this._proportionallyResize();
+
+ }
+
+ this.handles = o.handles || (!$(".ui-resizable-handle", this.element).length ? "e,s,se" : { n: ".ui-resizable-n", e: ".ui-resizable-e", s: ".ui-resizable-s", w: ".ui-resizable-w", se: ".ui-resizable-se", sw: ".ui-resizable-sw", ne: ".ui-resizable-ne", nw: ".ui-resizable-nw" });
+ if(this.handles.constructor === String) {
+
+ if ( this.handles === "all") {
+ this.handles = "n,e,s,w,se,sw,ne,nw";
+ }
+
+ n = this.handles.split(",");
+ this.handles = {};
+
+ for(i = 0; i < n.length; i++) {
+
+ handle = $.trim(n[i]);
+ hname = "ui-resizable-"+handle;
+ axis = $("<div class='ui-resizable-handle " + hname + "'></div>");
+
+ // Apply zIndex to all handles - see #7960
+ axis.css({ zIndex: o.zIndex });
+
+ //TODO : What's going on here?
+ if ("se" === handle) {
+ axis.addClass("ui-icon ui-icon-gripsmall-diagonal-se");
+ }
+
+ //Insert into internal handles object and append to element
+ this.handles[handle] = ".ui-resizable-"+handle;
+ this.element.append(axis);
+ }
+
+ }
+
+ this._renderAxis = function(target) {
+
+ var i, axis, padPos, padWrapper;
+
+ target = target || this.element;
+
+ for(i in this.handles) {
+
+ if(this.handles[i].constructor === String) {
+ this.handles[i] = $(this.handles[i], this.element).show();
+ }
+
+ //Apply pad to wrapper element, needed to fix axis position (textarea, inputs, scrolls)
+ if (this.elementIsWrapper && this.originalElement[0].nodeName.match(/textarea|input|select|button/i)) {
+
+ axis = $(this.handles[i], this.element);
+
+ //Checking the correct pad and border
+ padWrapper = /sw|ne|nw|se|n|s/.test(i) ? axis.outerHeight() : axis.outerWidth();
+
+ //The padding type i have to apply...
+ padPos = [ "padding",
+ /ne|nw|n/.test(i) ? "Top" :
+ /se|sw|s/.test(i) ? "Bottom" :
+ /^e$/.test(i) ? "Right" : "Left" ].join("");
+
+ target.css(padPos, padWrapper);
+
+ this._proportionallyResize();
+
+ }
+
+ //TODO: What's that good for? There's not anything to be executed left
+ if(!$(this.handles[i]).length) {
+ continue;
+ }
+ }
+ };
+
+ //TODO: make renderAxis a prototype function
+ this._renderAxis(this.element);
+
+ this._handles = $(".ui-resizable-handle", this.element)
+ .disableSelection();
+
+ //Matching axis name
+ this._handles.mouseover(function() {
+ if (!that.resizing) {
+ if (this.className) {
+ axis = this.className.match(/ui-resizable-(se|sw|ne|nw|n|e|s|w)/i);
+ }
+ //Axis, default = se
+ that.axis = axis && axis[1] ? axis[1] : "se";
+ }
+ });
+
+ //If we want to auto hide the elements
+ if (o.autoHide) {
+ this._handles.hide();
+ $(this.element)
+ .addClass("ui-resizable-autohide")
+ .mouseenter(function() {
+ if (o.disabled) {
+ return;
+ }
+ $(this).removeClass("ui-resizable-autohide");
+ that._handles.show();
+ })
+ .mouseleave(function(){
+ if (o.disabled) {
+ return;
+ }
+ if (!that.resizing) {
+ $(this).addClass("ui-resizable-autohide");
+ that._handles.hide();
+ }
+ });
+ }
+
+ //Initialize the mouse interaction
+ this._mouseInit();
+
+ },
+
+ _destroy: function() {
+
+ this._mouseDestroy();
+
+ var wrapper,
+ _destroy = function(exp) {
+ $(exp).removeClass("ui-resizable ui-resizable-disabled ui-resizable-resizing")
+ .removeData("resizable").removeData("ui-resizable").unbind(".resizable").find(".ui-resizable-handle").remove();
+ };
+
+ //TODO: Unwrap at same DOM position
+ if (this.elementIsWrapper) {
+ _destroy(this.element);
+ wrapper = this.element;
+ this.originalElement.css({
+ position: wrapper.css("position"),
+ width: wrapper.outerWidth(),
+ height: wrapper.outerHeight(),
+ top: wrapper.css("top"),
+ left: wrapper.css("left")
+ }).insertAfter( wrapper );
+ wrapper.remove();
+ }
+
+ this.originalElement.css("resize", this.originalResizeStyle);
+ _destroy(this.originalElement);
+
+ return this;
+ },
+
+ _mouseCapture: function(event) {
+ var i, handle,
+ capture = false;
+
+ for (i in this.handles) {
+ handle = $(this.handles[i])[0];
+ if (handle === event.target || $.contains(handle, event.target)) {
+ capture = true;
+ }
+ }
+
+ return !this.options.disabled && capture;
+ },
+
+ _mouseStart: function(event) {
+
+ var curleft, curtop, cursor,
+ o = this.options,
+ iniPos = this.element.position(),
+ el = this.element;
+
+ this.resizing = true;
+
+ // bugfix for http://dev.jquery.com/ticket/1749
+ if ( (/absolute/).test( el.css("position") ) ) {
+ el.css({ position: "absolute", top: el.css("top"), left: el.css("left") });
+ } else if (el.is(".ui-draggable")) {
+ el.css({ position: "absolute", top: iniPos.top, left: iniPos.left });
+ }
+
+ this._renderProxy();
+
+ curleft = num(this.helper.css("left"));
+ curtop = num(this.helper.css("top"));
+
+ if (o.containment) {
+ curleft += $(o.containment).scrollLeft() || 0;
+ curtop += $(o.containment).scrollTop() || 0;
+ }
+
+ //Store needed variables
+ this.offset = this.helper.offset();
+ this.position = { left: curleft, top: curtop };
+ this.size = this._helper ? { width: el.outerWidth(), height: el.outerHeight() } : { width: el.width(), height: el.height() };
+ this.originalSize = this._helper ? { width: el.outerWidth(), height: el.outerHeight() } : { width: el.width(), height: el.height() };
+ this.originalPosition = { left: curleft, top: curtop };
+ this.sizeDiff = { width: el.outerWidth() - el.width(), height: el.outerHeight() - el.height() };
+ this.originalMousePosition = { left: event.pageX, top: event.pageY };
+
+ //Aspect Ratio
+ this.aspectRatio = (typeof o.aspectRatio === "number") ? o.aspectRatio : ((this.originalSize.width / this.originalSize.height) || 1);
+
+ cursor = $(".ui-resizable-" + this.axis).css("cursor");
+ $("body").css("cursor", cursor === "auto" ? this.axis + "-resize" : cursor);
+
+ el.addClass("ui-resizable-resizing");
+ this._propagate("start", event);
+ return true;
+ },
+
+ _mouseDrag: function(event) {
+
+ //Increase performance, avoid regex
+ var data,
+ el = this.helper, props = {},
+ smp = this.originalMousePosition,
+ a = this.axis,
+ prevTop = this.position.top,
+ prevLeft = this.position.left,
+ prevWidth = this.size.width,
+ prevHeight = this.size.height,
+ dx = (event.pageX-smp.left)||0,
+ dy = (event.pageY-smp.top)||0,
+ trigger = this._change[a];
+
+ if (!trigger) {
+ return false;
+ }
+
+ // Calculate the attrs that will be change
+ data = trigger.apply(this, [event, dx, dy]);
+
+ // Put this in the mouseDrag handler since the user can start pressing shift while resizing
+ this._updateVirtualBoundaries(event.shiftKey);
+ if (this._aspectRatio || event.shiftKey) {
+ data = this._updateRatio(data, event);
+ }
+
+ data = this._respectSize(data, event);
+
+ this._updateCache(data);
+
+ // plugins callbacks need to be called first
+ this._propagate("resize", event);
+
+ if (this.position.top !== prevTop) {
+ props.top = this.position.top + "px";
+ }
+ if (this.position.left !== prevLeft) {
+ props.left = this.position.left + "px";
+ }
+ if (this.size.width !== prevWidth) {
+ props.width = this.size.width + "px";
+ }
+ if (this.size.height !== prevHeight) {
+ props.height = this.size.height + "px";
+ }
+ el.css(props);
+
+ if (!this._helper && this._proportionallyResizeElements.length) {
+ this._proportionallyResize();
+ }
+
+ // Call the user callback if the element was resized
+ if ( ! $.isEmptyObject(props) ) {
+ this._trigger("resize", event, this.ui());
+ }
+
+ return false;
+ },
+
+ _mouseStop: function(event) {
+
+ this.resizing = false;
+ var pr, ista, soffseth, soffsetw, s, left, top,
+ o = this.options, that = this;
+
+ if(this._helper) {
+
+ pr = this._proportionallyResizeElements;
+ ista = pr.length && (/textarea/i).test(pr[0].nodeName);
+ soffseth = ista && $.ui.hasScroll(pr[0], "left") /* TODO - jump height */ ? 0 : that.sizeDiff.height;
+ soffsetw = ista ? 0 : that.sizeDiff.width;
+
+ s = { width: (that.helper.width() - soffsetw), height: (that.helper.height() - soffseth) };
+ left = (parseInt(that.element.css("left"), 10) + (that.position.left - that.originalPosition.left)) || null;
+ top = (parseInt(that.element.css("top"), 10) + (that.position.top - that.originalPosition.top)) || null;
+
+ if (!o.animate) {
+ this.element.css($.extend(s, { top: top, left: left }));
+ }
+
+ that.helper.height(that.size.height);
+ that.helper.width(that.size.width);
+
+ if (this._helper && !o.animate) {
+ this._proportionallyResize();
+ }
+ }
+
+ $("body").css("cursor", "auto");
+
+ this.element.removeClass("ui-resizable-resizing");
+
+ this._propagate("stop", event);
+
+ if (this._helper) {
+ this.helper.remove();
+ }
+
+ return false;
+
+ },
+
+ _updateVirtualBoundaries: function(forceAspectRatio) {
+ var pMinWidth, pMaxWidth, pMinHeight, pMaxHeight, b,
+ o = this.options;
+
+ b = {
+ minWidth: isNumber(o.minWidth) ? o.minWidth : 0,
+ maxWidth: isNumber(o.maxWidth) ? o.maxWidth : Infinity,
+ minHeight: isNumber(o.minHeight) ? o.minHeight : 0,
+ maxHeight: isNumber(o.maxHeight) ? o.maxHeight : Infinity
+ };
+
+ if(this._aspectRatio || forceAspectRatio) {
+ // We want to create an enclosing box whose aspect ration is the requested one
+ // First, compute the "projected" size for each dimension based on the aspect ratio and other dimension
+ pMinWidth = b.minHeight * this.aspectRatio;
+ pMinHeight = b.minWidth / this.aspectRatio;
+ pMaxWidth = b.maxHeight * this.aspectRatio;
+ pMaxHeight = b.maxWidth / this.aspectRatio;
+
+ if(pMinWidth > b.minWidth) {
+ b.minWidth = pMinWidth;
+ }
+ if(pMinHeight > b.minHeight) {
+ b.minHeight = pMinHeight;
+ }
+ if(pMaxWidth < b.maxWidth) {
+ b.maxWidth = pMaxWidth;
+ }
+ if(pMaxHeight < b.maxHeight) {
+ b.maxHeight = pMaxHeight;
+ }
+ }
+ this._vBoundaries = b;
+ },
+
+ _updateCache: function(data) {
+ this.offset = this.helper.offset();
+ if (isNumber(data.left)) {
+ this.position.left = data.left;
+ }
+ if (isNumber(data.top)) {
+ this.position.top = data.top;
+ }
+ if (isNumber(data.height)) {
+ this.size.height = data.height;
+ }
+ if (isNumber(data.width)) {
+ this.size.width = data.width;
+ }
+ },
+
+ _updateRatio: function( data ) {
+
+ var cpos = this.position,
+ csize = this.size,
+ a = this.axis;
+
+ if (isNumber(data.height)) {
+ data.width = (data.height * this.aspectRatio);
+ } else if (isNumber(data.width)) {
+ data.height = (data.width / this.aspectRatio);
+ }
+
+ if (a === "sw") {
+ data.left = cpos.left + (csize.width - data.width);
+ data.top = null;
+ }
+ if (a === "nw") {
+ data.top = cpos.top + (csize.height - data.height);
+ data.left = cpos.left + (csize.width - data.width);
+ }
+
+ return data;
+ },
+
+ _respectSize: function( data ) {
+
+ var o = this._vBoundaries,
+ a = this.axis,
+ ismaxw = isNumber(data.width) && o.maxWidth && (o.maxWidth < data.width), ismaxh = isNumber(data.height) && o.maxHeight && (o.maxHeight < data.height),
+ isminw = isNumber(data.width) && o.minWidth && (o.minWidth > data.width), isminh = isNumber(data.height) && o.minHeight && (o.minHeight > data.height),
+ dw = this.originalPosition.left + this.originalSize.width,
+ dh = this.position.top + this.size.height,
+ cw = /sw|nw|w/.test(a), ch = /nw|ne|n/.test(a);
+ if (isminw) {
+ data.width = o.minWidth;
+ }
+ if (isminh) {
+ data.height = o.minHeight;
+ }
+ if (ismaxw) {
+ data.width = o.maxWidth;
+ }
+ if (ismaxh) {
+ data.height = o.maxHeight;
+ }
+
+ if (isminw && cw) {
+ data.left = dw - o.minWidth;
+ }
+ if (ismaxw && cw) {
+ data.left = dw - o.maxWidth;
+ }
+ if (isminh && ch) {
+ data.top = dh - o.minHeight;
+ }
+ if (ismaxh && ch) {
+ data.top = dh - o.maxHeight;
+ }
+
+ // fixing jump error on top/left - bug #2330
+ if (!data.width && !data.height && !data.left && data.top) {
+ data.top = null;
+ } else if (!data.width && !data.height && !data.top && data.left) {
+ data.left = null;
+ }
+
+ return data;
+ },
+
+ _proportionallyResize: function() {
+
+ if (!this._proportionallyResizeElements.length) {
+ return;
+ }
+
+ var i, j, borders, paddings, prel,
+ element = this.helper || this.element;
+
+ for ( i=0; i < this._proportionallyResizeElements.length; i++) {
+
+ prel = this._proportionallyResizeElements[i];
+
+ if (!this.borderDif) {
+ this.borderDif = [];
+ borders = [prel.css("borderTopWidth"), prel.css("borderRightWidth"), prel.css("borderBottomWidth"), prel.css("borderLeftWidth")];
+ paddings = [prel.css("paddingTop"), prel.css("paddingRight"), prel.css("paddingBottom"), prel.css("paddingLeft")];
+
+ for ( j = 0; j < borders.length; j++ ) {
+ this.borderDif[ j ] = ( parseInt( borders[ j ], 10 ) || 0 ) + ( parseInt( paddings[ j ], 10 ) || 0 );
+ }
+ }
+
+ prel.css({
+ height: (element.height() - this.borderDif[0] - this.borderDif[2]) || 0,
+ width: (element.width() - this.borderDif[1] - this.borderDif[3]) || 0
+ });
+
+ }
+
+ },
+
+ _renderProxy: function() {
+
+ var el = this.element, o = this.options;
+ this.elementOffset = el.offset();
+
+ if(this._helper) {
+
+ this.helper = this.helper || $("<div style='overflow:hidden;'></div>");
+
+ this.helper.addClass(this._helper).css({
+ width: this.element.outerWidth() - 1,
+ height: this.element.outerHeight() - 1,
+ position: "absolute",
+ left: this.elementOffset.left +"px",
+ top: this.elementOffset.top +"px",
+ zIndex: ++o.zIndex //TODO: Don't modify option
+ });
+
+ this.helper
+ .appendTo("body")
+ .disableSelection();
+
+ } else {
+ this.helper = this.element;
+ }
+
+ },
+
+ _change: {
+ e: function(event, dx) {
+ return { width: this.originalSize.width + dx };
+ },
+ w: function(event, dx) {
+ var cs = this.originalSize, sp = this.originalPosition;
+ return { left: sp.left + dx, width: cs.width - dx };
+ },
+ n: function(event, dx, dy) {
+ var cs = this.originalSize, sp = this.originalPosition;
+ return { top: sp.top + dy, height: cs.height - dy };
+ },
+ s: function(event, dx, dy) {
+ return { height: this.originalSize.height + dy };
+ },
+ se: function(event, dx, dy) {
+ return $.extend(this._change.s.apply(this, arguments), this._change.e.apply(this, [event, dx, dy]));
+ },
+ sw: function(event, dx, dy) {
+ return $.extend(this._change.s.apply(this, arguments), this._change.w.apply(this, [event, dx, dy]));
+ },
+ ne: function(event, dx, dy) {
+ return $.extend(this._change.n.apply(this, arguments), this._change.e.apply(this, [event, dx, dy]));
+ },
+ nw: function(event, dx, dy) {
+ return $.extend(this._change.n.apply(this, arguments), this._change.w.apply(this, [event, dx, dy]));
+ }
+ },
+
+ _propagate: function(n, event) {
+ $.ui.plugin.call(this, n, [event, this.ui()]);
+ (n !== "resize" && this._trigger(n, event, this.ui()));
+ },
+
+ plugins: {},
+
+ ui: function() {
+ return {
+ originalElement: this.originalElement,
+ element: this.element,
+ helper: this.helper,
+ position: this.position,
+ size: this.size,
+ originalSize: this.originalSize,
+ originalPosition: this.originalPosition
+ };
+ }
+
+});
+
+/*
+ * Resizable Extensions
+ */
+
+$.ui.plugin.add("resizable", "animate", {
+
+ stop: function( event ) {
+ var that = $(this).data("ui-resizable"),
+ o = that.options,
+ pr = that._proportionallyResizeElements,
+ ista = pr.length && (/textarea/i).test(pr[0].nodeName),
+ soffseth = ista && $.ui.hasScroll(pr[0], "left") /* TODO - jump height */ ? 0 : that.sizeDiff.height,
+ soffsetw = ista ? 0 : that.sizeDiff.width,
+ style = { width: (that.size.width - soffsetw), height: (that.size.height - soffseth) },
+ left = (parseInt(that.element.css("left"), 10) + (that.position.left - that.originalPosition.left)) || null,
+ top = (parseInt(that.element.css("top"), 10) + (that.position.top - that.originalPosition.top)) || null;
+
+ that.element.animate(
+ $.extend(style, top && left ? { top: top, left: left } : {}), {
+ duration: o.animateDuration,
+ easing: o.animateEasing,
+ step: function() {
+
+ var data = {
+ width: parseInt(that.element.css("width"), 10),
+ height: parseInt(that.element.css("height"), 10),
+ top: parseInt(that.element.css("top"), 10),
+ left: parseInt(that.element.css("left"), 10)
+ };
+
+ if (pr && pr.length) {
+ $(pr[0]).css({ width: data.width, height: data.height });
+ }
+
+ // propagating resize, and updating values for each animation step
+ that._updateCache(data);
+ that._propagate("resize", event);
+
+ }
+ }
+ );
+ }
+
+});
+
+$.ui.plugin.add("resizable", "containment", {
+
+ start: function() {
+ var element, p, co, ch, cw, width, height,
+ that = $(this).data("ui-resizable"),
+ o = that.options,
+ el = that.element,
+ oc = o.containment,
+ ce = (oc instanceof $) ? oc.get(0) : (/parent/.test(oc)) ? el.parent().get(0) : oc;
+
+ if (!ce) {
+ return;
+ }
+
+ that.containerElement = $(ce);
+
+ if (/document/.test(oc) || oc === document) {
+ that.containerOffset = { left: 0, top: 0 };
+ that.containerPosition = { left: 0, top: 0 };
+
+ that.parentData = {
+ element: $(document), left: 0, top: 0,
+ width: $(document).width(), height: $(document).height() || document.body.parentNode.scrollHeight
+ };
+ }
+
+ // i'm a node, so compute top, left, right, bottom
+ else {
+ element = $(ce);
+ p = [];
+ $([ "Top", "Right", "Left", "Bottom" ]).each(function(i, name) { p[i] = num(element.css("padding" + name)); });
+
+ that.containerOffset = element.offset();
+ that.containerPosition = element.position();
+ that.containerSize = { height: (element.innerHeight() - p[3]), width: (element.innerWidth() - p[1]) };
+
+ co = that.containerOffset;
+ ch = that.containerSize.height;
+ cw = that.containerSize.width;
+ width = ($.ui.hasScroll(ce, "left") ? ce.scrollWidth : cw );
+ height = ($.ui.hasScroll(ce) ? ce.scrollHeight : ch);
+
+ that.parentData = {
+ element: ce, left: co.left, top: co.top, width: width, height: height
+ };
+ }
+ },
+
+ resize: function( event ) {
+ var woset, hoset, isParent, isOffsetRelative,
+ that = $(this).data("ui-resizable"),
+ o = that.options,
+ co = that.containerOffset, cp = that.position,
+ pRatio = that._aspectRatio || event.shiftKey,
+ cop = { top:0, left:0 }, ce = that.containerElement;
+
+ if (ce[0] !== document && (/static/).test(ce.css("position"))) {
+ cop = co;
+ }
+
+ if (cp.left < (that._helper ? co.left : 0)) {
+ that.size.width = that.size.width + (that._helper ? (that.position.left - co.left) : (that.position.left - cop.left));
+ if (pRatio) {
+ that.size.height = that.size.width / that.aspectRatio;
+ }
+ that.position.left = o.helper ? co.left : 0;
+ }
+
+ if (cp.top < (that._helper ? co.top : 0)) {
+ that.size.height = that.size.height + (that._helper ? (that.position.top - co.top) : that.position.top);
+ if (pRatio) {
+ that.size.width = that.size.height * that.aspectRatio;
+ }
+ that.position.top = that._helper ? co.top : 0;
+ }
+
+ that.offset.left = that.parentData.left+that.position.left;
+ that.offset.top = that.parentData.top+that.position.top;
+
+ woset = Math.abs( (that._helper ? that.offset.left - cop.left : (that.offset.left - cop.left)) + that.sizeDiff.width );
+ hoset = Math.abs( (that._helper ? that.offset.top - cop.top : (that.offset.top - co.top)) + that.sizeDiff.height );
+
+ isParent = that.containerElement.get(0) === that.element.parent().get(0);
+ isOffsetRelative = /relative|absolute/.test(that.containerElement.css("position"));
+
+ if(isParent && isOffsetRelative) {
+ woset -= that.parentData.left;
+ }
+
+ if (woset + that.size.width >= that.parentData.width) {
+ that.size.width = that.parentData.width - woset;
+ if (pRatio) {
+ that.size.height = that.size.width / that.aspectRatio;
+ }
+ }
+
+ if (hoset + that.size.height >= that.parentData.height) {
+ that.size.height = that.parentData.height - hoset;
+ if (pRatio) {
+ that.size.width = that.size.height * that.aspectRatio;
+ }
+ }
+ },
+
+ stop: function(){
+ var that = $(this).data("ui-resizable"),
+ o = that.options,
+ co = that.containerOffset,
+ cop = that.containerPosition,
+ ce = that.containerElement,
+ helper = $(that.helper),
+ ho = helper.offset(),
+ w = helper.outerWidth() - that.sizeDiff.width,
+ h = helper.outerHeight() - that.sizeDiff.height;
+
+ if (that._helper && !o.animate && (/relative/).test(ce.css("position"))) {
+ $(this).css({ left: ho.left - cop.left - co.left, width: w, height: h });
+ }
+
+ if (that._helper && !o.animate && (/static/).test(ce.css("position"))) {
+ $(this).css({ left: ho.left - cop.left - co.left, width: w, height: h });
+ }
+
+ }
+});
+
+$.ui.plugin.add("resizable", "alsoResize", {
+
+ start: function () {
+ var that = $(this).data("ui-resizable"),
+ o = that.options,
+ _store = function (exp) {
+ $(exp).each(function() {
+ var el = $(this);
+ el.data("ui-resizable-alsoresize", {
+ width: parseInt(el.width(), 10), height: parseInt(el.height(), 10),
+ left: parseInt(el.css("left"), 10), top: parseInt(el.css("top"), 10)
+ });
+ });
+ };
+
+ if (typeof(o.alsoResize) === "object" && !o.alsoResize.parentNode) {
+ if (o.alsoResize.length) { o.alsoResize = o.alsoResize[0]; _store(o.alsoResize); }
+ else { $.each(o.alsoResize, function (exp) { _store(exp); }); }
+ }else{
+ _store(o.alsoResize);
+ }
+ },
+
+ resize: function (event, ui) {
+ var that = $(this).data("ui-resizable"),
+ o = that.options,
+ os = that.originalSize,
+ op = that.originalPosition,
+ delta = {
+ height: (that.size.height - os.height) || 0, width: (that.size.width - os.width) || 0,
+ top: (that.position.top - op.top) || 0, left: (that.position.left - op.left) || 0
+ },
+
+ _alsoResize = function (exp, c) {
+ $(exp).each(function() {
+ var el = $(this), start = $(this).data("ui-resizable-alsoresize"), style = {},
+ css = c && c.length ? c : el.parents(ui.originalElement[0]).length ? ["width", "height"] : ["width", "height", "top", "left"];
+
+ $.each(css, function (i, prop) {
+ var sum = (start[prop]||0) + (delta[prop]||0);
+ if (sum && sum >= 0) {
+ style[prop] = sum || null;
+ }
+ });
+
+ el.css(style);
+ });
+ };
+
+ if (typeof(o.alsoResize) === "object" && !o.alsoResize.nodeType) {
+ $.each(o.alsoResize, function (exp, c) { _alsoResize(exp, c); });
+ }else{
+ _alsoResize(o.alsoResize);
+ }
+ },
+
+ stop: function () {
+ $(this).removeData("resizable-alsoresize");
+ }
+});
+
+$.ui.plugin.add("resizable", "ghost", {
+
+ start: function() {
+
+ var that = $(this).data("ui-resizable"), o = that.options, cs = that.size;
+
+ that.ghost = that.originalElement.clone();
+ that.ghost
+ .css({ opacity: 0.25, display: "block", position: "relative", height: cs.height, width: cs.width, margin: 0, left: 0, top: 0 })
+ .addClass("ui-resizable-ghost")
+ .addClass(typeof o.ghost === "string" ? o.ghost : "");
+
+ that.ghost.appendTo(that.helper);
+
+ },
+
+ resize: function(){
+ var that = $(this).data("ui-resizable");
+ if (that.ghost) {
+ that.ghost.css({ position: "relative", height: that.size.height, width: that.size.width });
+ }
+ },
+
+ stop: function() {
+ var that = $(this).data("ui-resizable");
+ if (that.ghost && that.helper) {
+ that.helper.get(0).removeChild(that.ghost.get(0));
+ }
+ }
+
+});
+
+$.ui.plugin.add("resizable", "grid", {
+
+ resize: function() {
+ var that = $(this).data("ui-resizable"),
+ o = that.options,
+ cs = that.size,
+ os = that.originalSize,
+ op = that.originalPosition,
+ a = that.axis,
+ grid = typeof o.grid === "number" ? [o.grid, o.grid] : o.grid,
+ gridX = (grid[0]||1),
+ gridY = (grid[1]||1),
+ ox = Math.round((cs.width - os.width) / gridX) * gridX,
+ oy = Math.round((cs.height - os.height) / gridY) * gridY,
+ newWidth = os.width + ox,
+ newHeight = os.height + oy,
+ isMaxWidth = o.maxWidth && (o.maxWidth < newWidth),
+ isMaxHeight = o.maxHeight && (o.maxHeight < newHeight),
+ isMinWidth = o.minWidth && (o.minWidth > newWidth),
+ isMinHeight = o.minHeight && (o.minHeight > newHeight);
+
+ o.grid = grid;
+
+ if (isMinWidth) {
+ newWidth = newWidth + gridX;
+ }
+ if (isMinHeight) {
+ newHeight = newHeight + gridY;
+ }
+ if (isMaxWidth) {
+ newWidth = newWidth - gridX;
+ }
+ if (isMaxHeight) {
+ newHeight = newHeight - gridY;
+ }
+
+ if (/^(se|s|e)$/.test(a)) {
+ that.size.width = newWidth;
+ that.size.height = newHeight;
+ } else if (/^(ne)$/.test(a)) {
+ that.size.width = newWidth;
+ that.size.height = newHeight;
+ that.position.top = op.top - oy;
+ } else if (/^(sw)$/.test(a)) {
+ that.size.width = newWidth;
+ that.size.height = newHeight;
+ that.position.left = op.left - ox;
+ } else {
+ that.size.width = newWidth;
+ that.size.height = newHeight;
+ that.position.top = op.top - oy;
+ that.position.left = op.left - ox;
+ }
+ }
+
+});
+
+})(jQuery);
diff --git a/debian/missing-sources/jquery-ui/jquery.ui.selectable.js b/debian/missing-sources/jquery-ui/jquery.ui.selectable.js
new file mode 100644
index 0000000..e99ecb6
--- /dev/null
+++ b/debian/missing-sources/jquery-ui/jquery.ui.selectable.js
@@ -0,0 +1,277 @@
+/*!
+ * jQuery UI Selectable 1.10.3
+ * http://jqueryui.com
+ *
+ * Copyright 2013 jQuery Foundation and other contributors
+ * Released under the MIT license.
+ * http://jquery.org/license
+ *
+ * http://api.jqueryui.com/selectable/
+ *
+ * Depends:
+ * jquery.ui.core.js
+ * jquery.ui.mouse.js
+ * jquery.ui.widget.js
+ */
+(function( $, undefined ) {
+
+$.widget("ui.selectable", $.ui.mouse, {
+ version: "1.10.3",
+ options: {
+ appendTo: "body",
+ autoRefresh: true,
+ distance: 0,
+ filter: "*",
+ tolerance: "touch",
+
+ // callbacks
+ selected: null,
+ selecting: null,
+ start: null,
+ stop: null,
+ unselected: null,
+ unselecting: null
+ },
+ _create: function() {
+ var selectees,
+ that = this;
+
+ this.element.addClass("ui-selectable");
+
+ this.dragged = false;
+
+ // cache selectee children based on filter
+ this.refresh = function() {
+ selectees = $(that.options.filter, that.element[0]);
+ selectees.addClass("ui-selectee");
+ selectees.each(function() {
+ var $this = $(this),
+ pos = $this.offset();
+ $.data(this, "selectable-item", {
+ element: this,
+ $element: $this,
+ left: pos.left,
+ top: pos.top,
+ right: pos.left + $this.outerWidth(),
+ bottom: pos.top + $this.outerHeight(),
+ startselected: false,
+ selected: $this.hasClass("ui-selected"),
+ selecting: $this.hasClass("ui-selecting"),
+ unselecting: $this.hasClass("ui-unselecting")
+ });
+ });
+ };
+ this.refresh();
+
+ this.selectees = selectees.addClass("ui-selectee");
+
+ this._mouseInit();
+
+ this.helper = $("<div class='ui-selectable-helper'></div>");
+ },
+
+ _destroy: function() {
+ this.selectees
+ .removeClass("ui-selectee")
+ .removeData("selectable-item");
+ this.element
+ .removeClass("ui-selectable ui-selectable-disabled");
+ this._mouseDestroy();
+ },
+
+ _mouseStart: function(event) {
+ var that = this,
+ options = this.options;
+
+ this.opos = [event.pageX, event.pageY];
+
+ if (this.options.disabled) {
+ return;
+ }
+
+ this.selectees = $(options.filter, this.element[0]);
+
+ this._trigger("start", event);
+
+ $(options.appendTo).append(this.helper);
+ // position helper (lasso)
+ this.helper.css({
+ "left": event.pageX,
+ "top": event.pageY,
+ "width": 0,
+ "height": 0
+ });
+
+ if (options.autoRefresh) {
+ this.refresh();
+ }
+
+ this.selectees.filter(".ui-selected").each(function() {
+ var selectee = $.data(this, "selectable-item");
+ selectee.startselected = true;
+ if (!event.metaKey && !event.ctrlKey) {
+ selectee.$element.removeClass("ui-selected");
+ selectee.selected = false;
+ selectee.$element.addClass("ui-unselecting");
+ selectee.unselecting = true;
+ // selectable UNSELECTING callback
+ that._trigger("unselecting", event, {
+ unselecting: selectee.element
+ });
+ }
+ });
+
+ $(event.target).parents().addBack().each(function() {
+ var doSelect,
+ selectee = $.data(this, "selectable-item");
+ if (selectee) {
+ doSelect = (!event.metaKey && !event.ctrlKey) || !selectee.$element.hasClass("ui-selected");
+ selectee.$element
+ .removeClass(doSelect ? "ui-unselecting" : "ui-selected")
+ .addClass(doSelect ? "ui-selecting" : "ui-unselecting");
+ selectee.unselecting = !doSelect;
+ selectee.selecting = doSelect;
+ selectee.selected = doSelect;
+ // selectable (UN)SELECTING callback
+ if (doSelect) {
+ that._trigger("selecting", event, {
+ selecting: selectee.element
+ });
+ } else {
+ that._trigger("unselecting", event, {
+ unselecting: selectee.element
+ });
+ }
+ return false;
+ }
+ });
+
+ },
+
+ _mouseDrag: function(event) {
+
+ this.dragged = true;
+
+ if (this.options.disabled) {
+ return;
+ }
+
+ var tmp,
+ that = this,
+ options = this.options,
+ x1 = this.opos[0],
+ y1 = this.opos[1],
+ x2 = event.pageX,
+ y2 = event.pageY;
+
+ if (x1 > x2) { tmp = x2; x2 = x1; x1 = tmp; }
+ if (y1 > y2) { tmp = y2; y2 = y1; y1 = tmp; }
+ this.helper.css({left: x1, top: y1, width: x2-x1, height: y2-y1});
+
+ this.selectees.each(function() {
+ var selectee = $.data(this, "selectable-item"),
+ hit = false;
+
+ //prevent helper from being selected if appendTo: selectable
+ if (!selectee || selectee.element === that.element[0]) {
+ return;
+ }
+
+ if (options.tolerance === "touch") {
+ hit = ( !(selectee.left > x2 || selectee.right < x1 || selectee.top > y2 || selectee.bottom < y1) );
+ } else if (options.tolerance === "fit") {
+ hit = (selectee.left > x1 && selectee.right < x2 && selectee.top > y1 && selectee.bottom < y2);
+ }
+
+ if (hit) {
+ // SELECT
+ if (selectee.selected) {
+ selectee.$element.removeClass("ui-selected");
+ selectee.selected = false;
+ }
+ if (selectee.unselecting) {
+ selectee.$element.removeClass("ui-unselecting");
+ selectee.unselecting = false;
+ }
+ if (!selectee.selecting) {
+ selectee.$element.addClass("ui-selecting");
+ selectee.selecting = true;
+ // selectable SELECTING callback
+ that._trigger("selecting", event, {
+ selecting: selectee.element
+ });
+ }
+ } else {
+ // UNSELECT
+ if (selectee.selecting) {
+ if ((event.metaKey || event.ctrlKey) && selectee.startselected) {
+ selectee.$element.removeClass("ui-selecting");
+ selectee.selecting = false;
+ selectee.$element.addClass("ui-selected");
+ selectee.selected = true;
+ } else {
+ selectee.$element.removeClass("ui-selecting");
+ selectee.selecting = false;
+ if (selectee.startselected) {
+ selectee.$element.addClass("ui-unselecting");
+ selectee.unselecting = true;
+ }
+ // selectable UNSELECTING callback
+ that._trigger("unselecting", event, {
+ unselecting: selectee.element
+ });
+ }
+ }
+ if (selectee.selected) {
+ if (!event.metaKey && !event.ctrlKey && !selectee.startselected) {
+ selectee.$element.removeClass("ui-selected");
+ selectee.selected = false;
+
+ selectee.$element.addClass("ui-unselecting");
+ selectee.unselecting = true;
+ // selectable UNSELECTING callback
+ that._trigger("unselecting", event, {
+ unselecting: selectee.element
+ });
+ }
+ }
+ }
+ });
+
+ return false;
+ },
+
+ _mouseStop: function(event) {
+ var that = this;
+
+ this.dragged = false;
+
+ $(".ui-unselecting", this.element[0]).each(function() {
+ var selectee = $.data(this, "selectable-item");
+ selectee.$element.removeClass("ui-unselecting");
+ selectee.unselecting = false;
+ selectee.startselected = false;
+ that._trigger("unselected", event, {
+ unselected: selectee.element
+ });
+ });
+ $(".ui-selecting", this.element[0]).each(function() {
+ var selectee = $.data(this, "selectable-item");
+ selectee.$element.removeClass("ui-selecting").addClass("ui-selected");
+ selectee.selecting = false;
+ selectee.selected = true;
+ selectee.startselected = true;
+ that._trigger("selected", event, {
+ selected: selectee.element
+ });
+ });
+ this._trigger("stop", event);
+
+ this.helper.remove();
+
+ return false;
+ }
+
+});
+
+})(jQuery);
diff --git a/debian/missing-sources/jquery-ui/jquery.ui.slider.js b/debian/missing-sources/jquery-ui/jquery.ui.slider.js
new file mode 100644
index 0000000..b2c4aa3
--- /dev/null
+++ b/debian/missing-sources/jquery-ui/jquery.ui.slider.js
@@ -0,0 +1,672 @@
+/*!
+ * jQuery UI Slider 1.10.3
+ * http://jqueryui.com
+ *
+ * Copyright 2013 jQuery Foundation and other contributors
+ * Released under the MIT license.
+ * http://jquery.org/license
+ *
+ * http://api.jqueryui.com/slider/
+ *
+ * Depends:
+ * jquery.ui.core.js
+ * jquery.ui.mouse.js
+ * jquery.ui.widget.js
+ */
+(function( $, undefined ) {
+
+// number of pages in a slider
+// (how many times can you page up/down to go through the whole range)
+var numPages = 5;
+
+$.widget( "ui.slider", $.ui.mouse, {
+ version: "1.10.3",
+ widgetEventPrefix: "slide",
+
+ options: {
+ animate: false,
+ distance: 0,
+ max: 100,
+ min: 0,
+ orientation: "horizontal",
+ range: false,
+ step: 1,
+ value: 0,
+ values: null,
+
+ // callbacks
+ change: null,
+ slide: null,
+ start: null,
+ stop: null
+ },
+
+ _create: function() {
+ this._keySliding = false;
+ this._mouseSliding = false;
+ this._animateOff = true;
+ this._handleIndex = null;
+ this._detectOrientation();
+ this._mouseInit();
+
+ this.element
+ .addClass( "ui-slider" +
+ " ui-slider-" + this.orientation +
+ " ui-widget" +
+ " ui-widget-content" +
+ " ui-corner-all");
+
+ this._refresh();
+ this._setOption( "disabled", this.options.disabled );
+
+ this._animateOff = false;
+ },
+
+ _refresh: function() {
+ this._createRange();
+ this._createHandles();
+ this._setupEvents();
+ this._refreshValue();
+ },
+
+ _createHandles: function() {
+ var i, handleCount,
+ options = this.options,
+ existingHandles = this.element.find( ".ui-slider-handle" ).addClass( "ui-state-default ui-corner-all" ),
+ handle = "<a class='ui-slider-handle ui-state-default ui-corner-all' href='#'></a>",
+ handles = [];
+
+ handleCount = ( options.values && options.values.length ) || 1;
+
+ if ( existingHandles.length > handleCount ) {
+ existingHandles.slice( handleCount ).remove();
+ existingHandles = existingHandles.slice( 0, handleCount );
+ }
+
+ for ( i = existingHandles.length; i < handleCount; i++ ) {
+ handles.push( handle );
+ }
+
+ this.handles = existingHandles.add( $( handles.join( "" ) ).appendTo( this.element ) );
+
+ this.handle = this.handles.eq( 0 );
+
+ this.handles.each(function( i ) {
+ $( this ).data( "ui-slider-handle-index", i );
+ });
+ },
+
+ _createRange: function() {
+ var options = this.options,
+ classes = "";
+
+ if ( options.range ) {
+ if ( options.range === true ) {
+ if ( !options.values ) {
+ options.values = [ this._valueMin(), this._valueMin() ];
+ } else if ( options.values.length && options.values.length !== 2 ) {
+ options.values = [ options.values[0], options.values[0] ];
+ } else if ( $.isArray( options.values ) ) {
+ options.values = options.values.slice(0);
+ }
+ }
+
+ if ( !this.range || !this.range.length ) {
+ this.range = $( "<div></div>" )
+ .appendTo( this.element );
+
+ classes = "ui-slider-range" +
+ // note: this isn't the most fittingly semantic framework class for this element,
+ // but worked best visually with a variety of themes
+ " ui-widget-header ui-corner-all";
+ } else {
+ this.range.removeClass( "ui-slider-range-min ui-slider-range-max" )
+ // Handle range switching from true to min/max
+ .css({
+ "left": "",
+ "bottom": ""
+ });
+ }
+
+ this.range.addClass( classes +
+ ( ( options.range === "min" || options.range === "max" ) ? " ui-slider-range-" + options.range : "" ) );
+ } else {
+ this.range = $([]);
+ }
+ },
+
+ _setupEvents: function() {
+ var elements = this.handles.add( this.range ).filter( "a" );
+ this._off( elements );
+ this._on( elements, this._handleEvents );
+ this._hoverable( elements );
+ this._focusable( elements );
+ },
+
+ _destroy: function() {
+ this.handles.remove();
+ this.range.remove();
+
+ this.element
+ .removeClass( "ui-slider" +
+ " ui-slider-horizontal" +
+ " ui-slider-vertical" +
+ " ui-widget" +
+ " ui-widget-content" +
+ " ui-corner-all" );
+
+ this._mouseDestroy();
+ },
+
+ _mouseCapture: function( event ) {
+ var position, normValue, distance, closestHandle, index, allowed, offset, mouseOverHandle,
+ that = this,
+ o = this.options;
+
+ if ( o.disabled ) {
+ return false;
+ }
+
+ this.elementSize = {
+ width: this.element.outerWidth(),
+ height: this.element.outerHeight()
+ };
+ this.elementOffset = this.element.offset();
+
+ position = { x: event.pageX, y: event.pageY };
+ normValue = this._normValueFromMouse( position );
+ distance = this._valueMax() - this._valueMin() + 1;
+ this.handles.each(function( i ) {
+ var thisDistance = Math.abs( normValue - that.values(i) );
+ if (( distance > thisDistance ) ||
+ ( distance === thisDistance &&
+ (i === that._lastChangedValue || that.values(i) === o.min ))) {
+ distance = thisDistance;
+ closestHandle = $( this );
+ index = i;
+ }
+ });
+
+ allowed = this._start( event, index );
+ if ( allowed === false ) {
+ return false;
+ }
+ this._mouseSliding = true;
+
+ this._handleIndex = index;
+
+ closestHandle
+ .addClass( "ui-state-active" )
+ .focus();
+
+ offset = closestHandle.offset();
+ mouseOverHandle = !$( event.target ).parents().addBack().is( ".ui-slider-handle" );
+ this._clickOffset = mouseOverHandle ? { left: 0, top: 0 } : {
+ left: event.pageX - offset.left - ( closestHandle.width() / 2 ),
+ top: event.pageY - offset.top -
+ ( closestHandle.height() / 2 ) -
+ ( parseInt( closestHandle.css("borderTopWidth"), 10 ) || 0 ) -
+ ( parseInt( closestHandle.css("borderBottomWidth"), 10 ) || 0) +
+ ( parseInt( closestHandle.css("marginTop"), 10 ) || 0)
+ };
+
+ if ( !this.handles.hasClass( "ui-state-hover" ) ) {
+ this._slide( event, index, normValue );
+ }
+ this._animateOff = true;
+ return true;
+ },
+
+ _mouseStart: function() {
+ return true;
+ },
+
+ _mouseDrag: function( event ) {
+ var position = { x: event.pageX, y: event.pageY },
+ normValue = this._normValueFromMouse( position );
+
+ this._slide( event, this._handleIndex, normValue );
+
+ return false;
+ },
+
+ _mouseStop: function( event ) {
+ this.handles.removeClass( "ui-state-active" );
+ this._mouseSliding = false;
+
+ this._stop( event, this._handleIndex );
+ this._change( event, this._handleIndex );
+
+ this._handleIndex = null;
+ this._clickOffset = null;
+ this._animateOff = false;
+
+ return false;
+ },
+
+ _detectOrientation: function() {
+ this.orientation = ( this.options.orientation === "vertical" ) ? "vertical" : "horizontal";
+ },
+
+ _normValueFromMouse: function( position ) {
+ var pixelTotal,
+ pixelMouse,
+ percentMouse,
+ valueTotal,
+ valueMouse;
+
+ if ( this.orientation === "horizontal" ) {
+ pixelTotal = this.elementSize.width;
+ pixelMouse = position.x - this.elementOffset.left - ( this._clickOffset ? this._clickOffset.left : 0 );
+ } else {
+ pixelTotal = this.elementSize.height;
+ pixelMouse = position.y - this.elementOffset.top - ( this._clickOffset ? this._clickOffset.top : 0 );
+ }
+
+ percentMouse = ( pixelMouse / pixelTotal );
+ if ( percentMouse > 1 ) {
+ percentMouse = 1;
+ }
+ if ( percentMouse < 0 ) {
+ percentMouse = 0;
+ }
+ if ( this.orientation === "vertical" ) {
+ percentMouse = 1 - percentMouse;
+ }
+
+ valueTotal = this._valueMax() - this._valueMin();
+ valueMouse = this._valueMin() + percentMouse * valueTotal;
+
+ return this._trimAlignValue( valueMouse );
+ },
+
+ _start: function( event, index ) {
+ var uiHash = {
+ handle: this.handles[ index ],
+ value: this.value()
+ };
+ if ( this.options.values && this.options.values.length ) {
+ uiHash.value = this.values( index );
+ uiHash.values = this.values();
+ }
+ return this._trigger( "start", event, uiHash );
+ },
+
+ _slide: function( event, index, newVal ) {
+ var otherVal,
+ newValues,
+ allowed;
+
+ if ( this.options.values && this.options.values.length ) {
+ otherVal = this.values( index ? 0 : 1 );
+
+ if ( ( this.options.values.length === 2 && this.options.range === true ) &&
+ ( ( index === 0 && newVal > otherVal) || ( index === 1 && newVal < otherVal ) )
+ ) {
+ newVal = otherVal;
+ }
+
+ if ( newVal !== this.values( index ) ) {
+ newValues = this.values();
+ newValues[ index ] = newVal;
+ // A slide can be canceled by returning false from the slide callback
+ allowed = this._trigger( "slide", event, {
+ handle: this.handles[ index ],
+ value: newVal,
+ values: newValues
+ } );
+ otherVal = this.values( index ? 0 : 1 );
+ if ( allowed !== false ) {
+ this.values( index, newVal, true );
+ }
+ }
+ } else {
+ if ( newVal !== this.value() ) {
+ // A slide can be canceled by returning false from the slide callback
+ allowed = this._trigger( "slide", event, {
+ handle: this.handles[ index ],
+ value: newVal
+ } );
+ if ( allowed !== false ) {
+ this.value( newVal );
+ }
+ }
+ }
+ },
+
+ _stop: function( event, index ) {
+ var uiHash = {
+ handle: this.handles[ index ],
+ value: this.value()
+ };
+ if ( this.options.values && this.options.values.length ) {
+ uiHash.value = this.values( index );
+ uiHash.values = this.values();
+ }
+
+ this._trigger( "stop", event, uiHash );
+ },
+
+ _change: function( event, index ) {
+ if ( !this._keySliding && !this._mouseSliding ) {
+ var uiHash = {
+ handle: this.handles[ index ],
+ value: this.value()
+ };
+ if ( this.options.values && this.options.values.length ) {
+ uiHash.value = this.values( index );
+ uiHash.values = this.values();
+ }
+
+ //store the last changed value index for reference when handles overlap
+ this._lastChangedValue = index;
+
+ this._trigger( "change", event, uiHash );
+ }
+ },
+
+ value: function( newValue ) {
+ if ( arguments.length ) {
+ this.options.value = this._trimAlignValue( newValue );
+ this._refreshValue();
+ this._change( null, 0 );
+ return;
+ }
+
+ return this._value();
+ },
+
+ values: function( index, newValue ) {
+ var vals,
+ newValues,
+ i;
+
+ if ( arguments.length > 1 ) {
+ this.options.values[ index ] = this._trimAlignValue( newValue );
+ this._refreshValue();
+ this._change( null, index );
+ return;
+ }
+
+ if ( arguments.length ) {
+ if ( $.isArray( arguments[ 0 ] ) ) {
+ vals = this.options.values;
+ newValues = arguments[ 0 ];
+ for ( i = 0; i < vals.length; i += 1 ) {
+ vals[ i ] = this._trimAlignValue( newValues[ i ] );
+ this._change( null, i );
+ }
+ this._refreshValue();
+ } else {
+ if ( this.options.values && this.options.values.length ) {
+ return this._values( index );
+ } else {
+ return this.value();
+ }
+ }
+ } else {
+ return this._values();
+ }
+ },
+
+ _setOption: function( key, value ) {
+ var i,
+ valsLength = 0;
+
+ if ( key === "range" && this.options.range === true ) {
+ if ( value === "min" ) {
+ this.options.value = this._values( 0 );
+ this.options.values = null;
+ } else if ( value === "max" ) {
+ this.options.value = this._values( this.options.values.length-1 );
+ this.options.values = null;
+ }
+ }
+
+ if ( $.isArray( this.options.values ) ) {
+ valsLength = this.options.values.length;
+ }
+
+ $.Widget.prototype._setOption.apply( this, arguments );
+
+ switch ( key ) {
+ case "orientation":
+ this._detectOrientation();
+ this.element
+ .removeClass( "ui-slider-horizontal ui-slider-vertical" )
+ .addClass( "ui-slider-" + this.orientation );
+ this._refreshValue();
+ break;
+ case "value":
+ this._animateOff = true;
+ this._refreshValue();
+ this._change( null, 0 );
+ this._animateOff = false;
+ break;
+ case "values":
+ this._animateOff = true;
+ this._refreshValue();
+ for ( i = 0; i < valsLength; i += 1 ) {
+ this._change( null, i );
+ }
+ this._animateOff = false;
+ break;
+ case "min":
+ case "max":
+ this._animateOff = true;
+ this._refreshValue();
+ this._animateOff = false;
+ break;
+ case "range":
+ this._animateOff = true;
+ this._refresh();
+ this._animateOff = false;
+ break;
+ }
+ },
+
+ //internal value getter
+ // _value() returns value trimmed by min and max, aligned by step
+ _value: function() {
+ var val = this.options.value;
+ val = this._trimAlignValue( val );
+
+ return val;
+ },
+
+ //internal values getter
+ // _values() returns array of values trimmed by min and max, aligned by step
+ // _values( index ) returns single value trimmed by min and max, aligned by step
+ _values: function( index ) {
+ var val,
+ vals,
+ i;
+
+ if ( arguments.length ) {
+ val = this.options.values[ index ];
+ val = this._trimAlignValue( val );
+
+ return val;
+ } else if ( this.options.values && this.options.values.length ) {
+ // .slice() creates a copy of the array
+ // this copy gets trimmed by min and max and then returned
+ vals = this.options.values.slice();
+ for ( i = 0; i < vals.length; i+= 1) {
+ vals[ i ] = this._trimAlignValue( vals[ i ] );
+ }
+
+ return vals;
+ } else {
+ return [];
+ }
+ },
+
+ // returns the step-aligned value that val is closest to, between (inclusive) min and max
+ _trimAlignValue: function( val ) {
+ if ( val <= this._valueMin() ) {
+ return this._valueMin();
+ }
+ if ( val >= this._valueMax() ) {
+ return this._valueMax();
+ }
+ var step = ( this.options.step > 0 ) ? this.options.step : 1,
+ valModStep = (val - this._valueMin()) % step,
+ alignValue = val - valModStep;
+
+ if ( Math.abs(valModStep) * 2 >= step ) {
+ alignValue += ( valModStep > 0 ) ? step : ( -step );
+ }
+
+ // Since JavaScript has problems with large floats, round
+ // the final value to 5 digits after the decimal point (see #4124)
+ return parseFloat( alignValue.toFixed(5) );
+ },
+
+ _valueMin: function() {
+ return this.options.min;
+ },
+
+ _valueMax: function() {
+ return this.options.max;
+ },
+
+ _refreshValue: function() {
+ var lastValPercent, valPercent, value, valueMin, valueMax,
+ oRange = this.options.range,
+ o = this.options,
+ that = this,
+ animate = ( !this._animateOff ) ? o.animate : false,
+ _set = {};
+
+ if ( this.options.values && this.options.values.length ) {
+ this.handles.each(function( i ) {
+ valPercent = ( that.values(i) - that._valueMin() ) / ( that._valueMax() - that._valueMin() ) * 100;
+ _set[ that.orientation === "horizontal" ? "left" : "bottom" ] = valPercent + "%";
+ $( this ).stop( 1, 1 )[ animate ? "animate" : "css" ]( _set, o.animate );
+ if ( that.options.range === true ) {
+ if ( that.orientation === "horizontal" ) {
+ if ( i === 0 ) {
+ that.range.stop( 1, 1 )[ animate ? "animate" : "css" ]( { left: valPercent + "%" }, o.animate );
+ }
+ if ( i === 1 ) {
+ that.range[ animate ? "animate" : "css" ]( { width: ( valPercent - lastValPercent ) + "%" }, { queue: false, duration: o.animate } );
+ }
+ } else {
+ if ( i === 0 ) {
+ that.range.stop( 1, 1 )[ animate ? "animate" : "css" ]( { bottom: ( valPercent ) + "%" }, o.animate );
+ }
+ if ( i === 1 ) {
+ that.range[ animate ? "animate" : "css" ]( { height: ( valPercent - lastValPercent ) + "%" }, { queue: false, duration: o.animate } );
+ }
+ }
+ }
+ lastValPercent = valPercent;
+ });
+ } else {
+ value = this.value();
+ valueMin = this._valueMin();
+ valueMax = this._valueMax();
+ valPercent = ( valueMax !== valueMin ) ?
+ ( value - valueMin ) / ( valueMax - valueMin ) * 100 :
+ 0;
+ _set[ this.orientation === "horizontal" ? "left" : "bottom" ] = valPercent + "%";
+ this.handle.stop( 1, 1 )[ animate ? "animate" : "css" ]( _set, o.animate );
+
+ if ( oRange === "min" && this.orientation === "horizontal" ) {
+ this.range.stop( 1, 1 )[ animate ? "animate" : "css" ]( { width: valPercent + "%" }, o.animate );
+ }
+ if ( oRange === "max" && this.orientation === "horizontal" ) {
+ this.range[ animate ? "animate" : "css" ]( { width: ( 100 - valPercent ) + "%" }, { queue: false, duration: o.animate } );
+ }
+ if ( oRange === "min" && this.orientation === "vertical" ) {
+ this.range.stop( 1, 1 )[ animate ? "animate" : "css" ]( { height: valPercent + "%" }, o.animate );
+ }
+ if ( oRange === "max" && this.orientation === "vertical" ) {
+ this.range[ animate ? "animate" : "css" ]( { height: ( 100 - valPercent ) + "%" }, { queue: false, duration: o.animate } );
+ }
+ }
+ },
+
+ _handleEvents: {
+ keydown: function( event ) {
+ /*jshint maxcomplexity:25*/
+ var allowed, curVal, newVal, step,
+ index = $( event.target ).data( "ui-slider-handle-index" );
+
+ switch ( event.keyCode ) {
+ case $.ui.keyCode.HOME:
+ case $.ui.keyCode.END:
+ case $.ui.keyCode.PAGE_UP:
+ case $.ui.keyCode.PAGE_DOWN:
+ case $.ui.keyCode.UP:
+ case $.ui.keyCode.RIGHT:
+ case $.ui.keyCode.DOWN:
+ case $.ui.keyCode.LEFT:
+ event.preventDefault();
+ if ( !this._keySliding ) {
+ this._keySliding = true;
+ $( event.target ).addClass( "ui-state-active" );
+ allowed = this._start( event, index );
+ if ( allowed === false ) {
+ return;
+ }
+ }
+ break;
+ }
+
+ step = this.options.step;
+ if ( this.options.values && this.options.values.length ) {
+ curVal = newVal = this.values( index );
+ } else {
+ curVal = newVal = this.value();
+ }
+
+ switch ( event.keyCode ) {
+ case $.ui.keyCode.HOME:
+ newVal = this._valueMin();
+ break;
+ case $.ui.keyCode.END:
+ newVal = this._valueMax();
+ break;
+ case $.ui.keyCode.PAGE_UP:
+ newVal = this._trimAlignValue( curVal + ( (this._valueMax() - this._valueMin()) / numPages ) );
+ break;
+ case $.ui.keyCode.PAGE_DOWN:
+ newVal = this._trimAlignValue( curVal - ( (this._valueMax() - this._valueMin()) / numPages ) );
+ break;
+ case $.ui.keyCode.UP:
+ case $.ui.keyCode.RIGHT:
+ if ( curVal === this._valueMax() ) {
+ return;
+ }
+ newVal = this._trimAlignValue( curVal + step );
+ break;
+ case $.ui.keyCode.DOWN:
+ case $.ui.keyCode.LEFT:
+ if ( curVal === this._valueMin() ) {
+ return;
+ }
+ newVal = this._trimAlignValue( curVal - step );
+ break;
+ }
+
+ this._slide( event, index, newVal );
+ },
+ click: function( event ) {
+ event.preventDefault();
+ },
+ keyup: function( event ) {
+ var index = $( event.target ).data( "ui-slider-handle-index" );
+
+ if ( this._keySliding ) {
+ this._keySliding = false;
+ this._stop( event, index );
+ this._change( event, index );
+ $( event.target ).removeClass( "ui-state-active" );
+ }
+ }
+ }
+
+});
+
+}(jQuery));
diff --git a/debian/missing-sources/jquery-ui/jquery.ui.sortable.js b/debian/missing-sources/jquery-ui/jquery.ui.sortable.js
new file mode 100644
index 0000000..c9f2c90
--- /dev/null
+++ b/debian/missing-sources/jquery-ui/jquery.ui.sortable.js
@@ -0,0 +1,1285 @@
+/*!
+ * jQuery UI Sortable 1.10.3
+ * http://jqueryui.com
+ *
+ * Copyright 2013 jQuery Foundation and other contributors
+ * Released under the MIT license.
+ * http://jquery.org/license
+ *
+ * http://api.jqueryui.com/sortable/
+ *
+ * Depends:
+ * jquery.ui.core.js
+ * jquery.ui.mouse.js
+ * jquery.ui.widget.js
+ */
+(function( $, undefined ) {
+
+/*jshint loopfunc: true */
+
+function isOverAxis( x, reference, size ) {
+ return ( x > reference ) && ( x < ( reference + size ) );
+}
+
+function isFloating(item) {
+ return (/left|right/).test(item.css("float")) || (/inline|table-cell/).test(item.css("display"));
+}
+
+$.widget("ui.sortable", $.ui.mouse, {
+ version: "1.10.3",
+ widgetEventPrefix: "sort",
+ ready: false,
+ options: {
+ appendTo: "parent",
+ axis: false,
+ connectWith: false,
+ containment: false,
+ cursor: "auto",
+ cursorAt: false,
+ dropOnEmpty: true,
+ forcePlaceholderSize: false,
+ forceHelperSize: false,
+ grid: false,
+ handle: false,
+ helper: "original",
+ items: "> *",
+ opacity: false,
+ placeholder: false,
+ revert: false,
+ scroll: true,
+ scrollSensitivity: 20,
+ scrollSpeed: 20,
+ scope: "default",
+ tolerance: "intersect",
+ zIndex: 1000,
+
+ // callbacks
+ activate: null,
+ beforeStop: null,
+ change: null,
+ deactivate: null,
+ out: null,
+ over: null,
+ receive: null,
+ remove: null,
+ sort: null,
+ start: null,
+ stop: null,
+ update: null
+ },
+ _create: function() {
+
+ var o = this.options;
+ this.containerCache = {};
+ this.element.addClass("ui-sortable");
+
+ //Get the items
+ this.refresh();
+
+ //Let's determine if the items are being displayed horizontally
+ this.floating = this.items.length ? o.axis === "x" || isFloating(this.items[0].item) : false;
+
+ //Let's determine the parent's offset
+ this.offset = this.element.offset();
+
+ //Initialize mouse events for interaction
+ this._mouseInit();
+
+ //We're ready to go
+ this.ready = true;
+
+ },
+
+ _destroy: function() {
+ this.element
+ .removeClass("ui-sortable ui-sortable-disabled");
+ this._mouseDestroy();
+
+ for ( var i = this.items.length - 1; i >= 0; i-- ) {
+ this.items[i].item.removeData(this.widgetName + "-item");
+ }
+
+ return this;
+ },
+
+ _setOption: function(key, value){
+ if ( key === "disabled" ) {
+ this.options[ key ] = value;
+
+ this.widget().toggleClass( "ui-sortable-disabled", !!value );
+ } else {
+ // Don't call widget base _setOption for disable as it adds ui-state-disabled class
+ $.Widget.prototype._setOption.apply(this, arguments);
+ }
+ },
+
+ _mouseCapture: function(event, overrideHandle) {
+ var currentItem = null,
+ validHandle = false,
+ that = this;
+
+ if (this.reverting) {
+ return false;
+ }
+
+ if(this.options.disabled || this.options.type === "static") {
+ return false;
+ }
+
+ //We have to refresh the items data once first
+ this._refreshItems(event);
+
+ //Find out if the clicked node (or one of its parents) is a actual item in this.items
+ $(event.target).parents().each(function() {
+ if($.data(this, that.widgetName + "-item") === that) {
+ currentItem = $(this);
+ return false;
+ }
+ });
+ if($.data(event.target, that.widgetName + "-item") === that) {
+ currentItem = $(event.target);
+ }
+
+ if(!currentItem) {
+ return false;
+ }
+ if(this.options.handle && !overrideHandle) {
+ $(this.options.handle, currentItem).find("*").addBack().each(function() {
+ if(this === event.target) {
+ validHandle = true;
+ }
+ });
+ if(!validHandle) {
+ return false;
+ }
+ }
+
+ this.currentItem = currentItem;
+ this._removeCurrentsFromItems();
+ return true;
+
+ },
+
+ _mouseStart: function(event, overrideHandle, noActivation) {
+
+ var i, body,
+ o = this.options;
+
+ this.currentContainer = this;
+
+ //We only need to call refreshPositions, because the refreshItems call has been moved to mouseCapture
+ this.refreshPositions();
+
+ //Create and append the visible helper
+ this.helper = this._createHelper(event);
+
+ //Cache the helper size
+ this._cacheHelperProportions();
+
+ /*
+ * - Position generation -
+ * This block generates everything position related - it's the core of draggables.
+ */
+
+ //Cache the margins of the original element
+ this._cacheMargins();
+
+ //Get the next scrolling parent
+ this.scrollParent = this.helper.scrollParent();
+
+ //The element's absolute position on the page minus margins
+ this.offset = this.currentItem.offset();
+ this.offset = {
+ top: this.offset.top - this.margins.top,
+ left: this.offset.left - this.margins.left
+ };
+
+ $.extend(this.offset, {
+ click: { //Where the click happened, relative to the element
+ left: event.pageX - this.offset.left,
+ top: event.pageY - this.offset.top
+ },
+ parent: this._getParentOffset(),
+ relative: this._getRelativeOffset() //This is a relative to absolute position minus the actual position calculation - only used for relative positioned helper
+ });
+
+ // Only after we got the offset, we can change the helper's position to absolute
+ // TODO: Still need to figure out a way to make relative sorting possible
+ this.helper.css("position", "absolute");
+ this.cssPosition = this.helper.css("position");
+
+ //Generate the original position
+ this.originalPosition = this._generatePosition(event);
+ this.originalPageX = event.pageX;
+ this.originalPageY = event.pageY;
+
+ //Adjust the mouse offset relative to the helper if "cursorAt" is supplied
+ (o.cursorAt && this._adjustOffsetFromHelper(o.cursorAt));
+
+ //Cache the former DOM position
+ this.domPosition = { prev: this.currentItem.prev()[0], parent: this.currentItem.parent()[0] };
+
+ //If the helper is not the original, hide the original so it's not playing any role during the drag, won't cause anything bad this way
+ if(this.helper[0] !== this.currentItem[0]) {
+ this.currentItem.hide();
+ }
+
+ //Create the placeholder
+ this._createPlaceholder();
+
+ //Set a containment if given in the options
+ if(o.containment) {
+ this._setContainment();
+ }
+
+ if( o.cursor && o.cursor !== "auto" ) { // cursor option
+ body = this.document.find( "body" );
+
+ // support: IE
+ this.storedCursor = body.css( "cursor" );
+ body.css( "cursor", o.cursor );
+
+ this.storedStylesheet = $( "<style>*{ cursor: "+o.cursor+" !important; }</style>" ).appendTo( body );
+ }
+
+ if(o.opacity) { // opacity option
+ if (this.helper.css("opacity")) {
+ this._storedOpacity = this.helper.css("opacity");
+ }
+ this.helper.css("opacity", o.opacity);
+ }
+
+ if(o.zIndex) { // zIndex option
+ if (this.helper.css("zIndex")) {
+ this._storedZIndex = this.helper.css("zIndex");
+ }
+ this.helper.css("zIndex", o.zIndex);
+ }
+
+ //Prepare scrolling
+ if(this.scrollParent[0] !== document && this.scrollParent[0].tagName !== "HTML") {
+ this.overflowOffset = this.scrollParent.offset();
+ }
+
+ //Call callbacks
+ this._trigger("start", event, this._uiHash());
+
+ //Recache the helper size
+ if(!this._preserveHelperProportions) {
+ this._cacheHelperProportions();
+ }
+
+
+ //Post "activate" events to possible containers
+ if( !noActivation ) {
+ for ( i = this.containers.length - 1; i >= 0; i-- ) {
+ this.containers[ i ]._trigger( "activate", event, this._uiHash( this ) );
+ }
+ }
+
+ //Prepare possible droppables
+ if($.ui.ddmanager) {
+ $.ui.ddmanager.current = this;
+ }
+
+ if ($.ui.ddmanager && !o.dropBehaviour) {
+ $.ui.ddmanager.prepareOffsets(this, event);
+ }
+
+ this.dragging = true;
+
+ this.helper.addClass("ui-sortable-helper");
+ this._mouseDrag(event); //Execute the drag once - this causes the helper not to be visible before getting its correct position
+ return true;
+
+ },
+
+ _mouseDrag: function(event) {
+ var i, item, itemElement, intersection,
+ o = this.options,
+ scrolled = false;
+
+ //Compute the helpers position
+ this.position = this._generatePosition(event);
+ this.positionAbs = this._convertPositionTo("absolute");
+
+ if (!this.lastPositionAbs) {
+ this.lastPositionAbs = this.positionAbs;
+ }
+
+ //Do scrolling
+ if(this.options.scroll) {
+ if(this.scrollParent[0] !== document && this.scrollParent[0].tagName !== "HTML") {
+
+ if((this.overflowOffset.top + this.scrollParent[0].offsetHeight) - event.pageY < o.scrollSensitivity) {
+ this.scrollParent[0].scrollTop = scrolled = this.scrollParent[0].scrollTop + o.scrollSpeed;
+ } else if(event.pageY - this.overflowOffset.top < o.scrollSensitivity) {
+ this.scrollParent[0].scrollTop = scrolled = this.scrollParent[0].scrollTop - o.scrollSpeed;
+ }
+
+ if((this.overflowOffset.left + this.scrollParent[0].offsetWidth) - event.pageX < o.scrollSensitivity) {
+ this.scrollParent[0].scrollLeft = scrolled = this.scrollParent[0].scrollLeft + o.scrollSpeed;
+ } else if(event.pageX - this.overflowOffset.left < o.scrollSensitivity) {
+ this.scrollParent[0].scrollLeft = scrolled = this.scrollParent[0].scrollLeft - o.scrollSpeed;
+ }
+
+ } else {
+
+ if(event.pageY - $(document).scrollTop() < o.scrollSensitivity) {
+ scrolled = $(document).scrollTop($(document).scrollTop() - o.scrollSpeed);
+ } else if($(window).height() - (event.pageY - $(document).scrollTop()) < o.scrollSensitivity) {
+ scrolled = $(document).scrollTop($(document).scrollTop() + o.scrollSpeed);
+ }
+
+ if(event.pageX - $(document).scrollLeft() < o.scrollSensitivity) {
+ scrolled = $(document).scrollLeft($(document).scrollLeft() - o.scrollSpeed);
+ } else if($(window).width() - (event.pageX - $(document).scrollLeft()) < o.scrollSensitivity) {
+ scrolled = $(document).scrollLeft($(document).scrollLeft() + o.scrollSpeed);
+ }
+
+ }
+
+ if(scrolled !== false && $.ui.ddmanager && !o.dropBehaviour) {
+ $.ui.ddmanager.prepareOffsets(this, event);
+ }
+ }
+
+ //Regenerate the absolute position used for position checks
+ this.positionAbs = this._convertPositionTo("absolute");
+
+ //Set the helper position
+ if(!this.options.axis || this.options.axis !== "y") {
+ this.helper[0].style.left = this.position.left+"px";
+ }
+ if(!this.options.axis || this.options.axis !== "x") {
+ this.helper[0].style.top = this.position.top+"px";
+ }
+
+ //Rearrange
+ for (i = this.items.length - 1; i >= 0; i--) {
+
+ //Cache variables and intersection, continue if no intersection
+ item = this.items[i];
+ itemElement = item.item[0];
+ intersection = this._intersectsWithPointer(item);
+ if (!intersection) {
+ continue;
+ }
+
+ // Only put the placeholder inside the current Container, skip all
+ // items form other containers. This works because when moving
+ // an item from one container to another the
+ // currentContainer is switched before the placeholder is moved.
+ //
+ // Without this moving items in "sub-sortables" can cause the placeholder to jitter
+ // beetween the outer and inner container.
+ if (item.instance !== this.currentContainer) {
+ continue;
+ }
+
+ // cannot intersect with itself
+ // no useless actions that have been done before
+ // no action if the item moved is the parent of the item checked
+ if (itemElement !== this.currentItem[0] &&
+ this.placeholder[intersection === 1 ? "next" : "prev"]()[0] !== itemElement &&
+ !$.contains(this.placeholder[0], itemElement) &&
+ (this.options.type === "semi-dynamic" ? !$.contains(this.element[0], itemElement) : true)
+ ) {
+
+ this.direction = intersection === 1 ? "down" : "up";
+
+ if (this.options.tolerance === "pointer" || this._intersectsWithSides(item)) {
+ this._rearrange(event, item);
+ } else {
+ break;
+ }
+
+ this._trigger("change", event, this._uiHash());
+ break;
+ }
+ }
+
+ //Post events to containers
+ this._contactContainers(event);
+
+ //Interconnect with droppables
+ if($.ui.ddmanager) {
+ $.ui.ddmanager.drag(this, event);
+ }
+
+ //Call callbacks
+ this._trigger("sort", event, this._uiHash());
+
+ this.lastPositionAbs = this.positionAbs;
+ return false;
+
+ },
+
+ _mouseStop: function(event, noPropagation) {
+
+ if(!event) {
+ return;
+ }
+
+ //If we are using droppables, inform the manager about the drop
+ if ($.ui.ddmanager && !this.options.dropBehaviour) {
+ $.ui.ddmanager.drop(this, event);
+ }
+
+ if(this.options.revert) {
+ var that = this,
+ cur = this.placeholder.offset(),
+ axis = this.options.axis,
+ animation = {};
+
+ if ( !axis || axis === "x" ) {
+ animation.left = cur.left - this.offset.parent.left - this.margins.left + (this.offsetParent[0] === document.body ? 0 : this.offsetParent[0].scrollLeft);
+ }
+ if ( !axis || axis === "y" ) {
+ animation.top = cur.top - this.offset.parent.top - this.margins.top + (this.offsetParent[0] === document.body ? 0 : this.offsetParent[0].scrollTop);
+ }
+ this.reverting = true;
+ $(this.helper).animate( animation, parseInt(this.options.revert, 10) || 500, function() {
+ that._clear(event);
+ });
+ } else {
+ this._clear(event, noPropagation);
+ }
+
+ return false;
+
+ },
+
+ cancel: function() {
+
+ if(this.dragging) {
+
+ this._mouseUp({ target: null });
+
+ if(this.options.helper === "original") {
+ this.currentItem.css(this._storedCSS).removeClass("ui-sortable-helper");
+ } else {
+ this.currentItem.show();
+ }
+
+ //Post deactivating events to containers
+ for (var i = this.containers.length - 1; i >= 0; i--){
+ this.containers[i]._trigger("deactivate", null, this._uiHash(this));
+ if(this.containers[i].containerCache.over) {
+ this.containers[i]._trigger("out", null, this._uiHash(this));
+ this.containers[i].containerCache.over = 0;
+ }
+ }
+
+ }
+
+ if (this.placeholder) {
+ //$(this.placeholder[0]).remove(); would have been the jQuery way - unfortunately, it unbinds ALL events from the original node!
+ if(this.placeholder[0].parentNode) {
+ this.placeholder[0].parentNode.removeChild(this.placeholder[0]);
+ }
+ if(this.options.helper !== "original" && this.helper && this.helper[0].parentNode) {
+ this.helper.remove();
+ }
+
+ $.extend(this, {
+ helper: null,
+ dragging: false,
+ reverting: false,
+ _noFinalSort: null
+ });
+
+ if(this.domPosition.prev) {
+ $(this.domPosition.prev).after(this.currentItem);
+ } else {
+ $(this.domPosition.parent).prepend(this.currentItem);
+ }
+ }
+
+ return this;
+
+ },
+
+ serialize: function(o) {
+
+ var items = this._getItemsAsjQuery(o && o.connected),
+ str = [];
+ o = o || {};
+
+ $(items).each(function() {
+ var res = ($(o.item || this).attr(o.attribute || "id") || "").match(o.expression || (/(.+)[\-=_](.+)/));
+ if (res) {
+ str.push((o.key || res[1]+"[]")+"="+(o.key && o.expression ? res[1] : res[2]));
+ }
+ });
+
+ if(!str.length && o.key) {
+ str.push(o.key + "=");
+ }
+
+ return str.join("&");
+
+ },
+
+ toArray: function(o) {
+
+ var items = this._getItemsAsjQuery(o && o.connected),
+ ret = [];
+
+ o = o || {};
+
+ items.each(function() { ret.push($(o.item || this).attr(o.attribute || "id") || ""); });
+ return ret;
+
+ },
+
+ /* Be careful with the following core functions */
+ _intersectsWith: function(item) {
+
+ var x1 = this.positionAbs.left,
+ x2 = x1 + this.helperProportions.width,
+ y1 = this.positionAbs.top,
+ y2 = y1 + this.helperProportions.height,
+ l = item.left,
+ r = l + item.width,
+ t = item.top,
+ b = t + item.height,
+ dyClick = this.offset.click.top,
+ dxClick = this.offset.click.left,
+ isOverElementHeight = ( this.options.axis === "x" ) || ( ( y1 + dyClick ) > t && ( y1 + dyClick ) < b ),
+ isOverElementWidth = ( this.options.axis === "y" ) || ( ( x1 + dxClick ) > l && ( x1 + dxClick ) < r ),
+ isOverElement = isOverElementHeight && isOverElementWidth;
+
+ if ( this.options.tolerance === "pointer" ||
+ this.options.forcePointerForContainers ||
+ (this.options.tolerance !== "pointer" && this.helperProportions[this.floating ? "width" : "height"] > item[this.floating ? "width" : "height"])
+ ) {
+ return isOverElement;
+ } else {
+
+ return (l < x1 + (this.helperProportions.width / 2) && // Right Half
+ x2 - (this.helperProportions.width / 2) < r && // Left Half
+ t < y1 + (this.helperProportions.height / 2) && // Bottom Half
+ y2 - (this.helperProportions.height / 2) < b ); // Top Half
+
+ }
+ },
+
+ _intersectsWithPointer: function(item) {
+
+ var isOverElementHeight = (this.options.axis === "x") || isOverAxis(this.positionAbs.top + this.offset.click.top, item.top, item.height),
+ isOverElementWidth = (this.options.axis === "y") || isOverAxis(this.positionAbs.left + this.offset.click.left, item.left, item.width),
+ isOverElement = isOverElementHeight && isOverElementWidth,
+ verticalDirection = this._getDragVerticalDirection(),
+ horizontalDirection = this._getDragHorizontalDirection();
+
+ if (!isOverElement) {
+ return false;
+ }
+
+ return this.floating ?
+ ( ((horizontalDirection && horizontalDirection === "right") || verticalDirection === "down") ? 2 : 1 )
+ : ( verticalDirection && (verticalDirection === "down" ? 2 : 1) );
+
+ },
+
+ _intersectsWithSides: function(item) {
+
+ var isOverBottomHalf = isOverAxis(this.positionAbs.top + this.offset.click.top, item.top + (item.height/2), item.height),
+ isOverRightHalf = isOverAxis(this.positionAbs.left + this.offset.click.left, item.left + (item.width/2), item.width),
+ verticalDirection = this._getDragVerticalDirection(),
+ horizontalDirection = this._getDragHorizontalDirection();
+
+ if (this.floating && horizontalDirection) {
+ return ((horizontalDirection === "right" && isOverRightHalf) || (horizontalDirection === "left" && !isOverRightHalf));
+ } else {
+ return verticalDirection && ((verticalDirection === "down" && isOverBottomHalf) || (verticalDirection === "up" && !isOverBottomHalf));
+ }
+
+ },
+
+ _getDragVerticalDirection: function() {
+ var delta = this.positionAbs.top - this.lastPositionAbs.top;
+ return delta !== 0 && (delta > 0 ? "down" : "up");
+ },
+
+ _getDragHorizontalDirection: function() {
+ var delta = this.positionAbs.left - this.lastPositionAbs.left;
+ return delta !== 0 && (delta > 0 ? "right" : "left");
+ },
+
+ refresh: function(event) {
+ this._refreshItems(event);
+ this.refreshPositions();
+ return this;
+ },
+
+ _connectWith: function() {
+ var options = this.options;
+ return options.connectWith.constructor === String ? [options.connectWith] : options.connectWith;
+ },
+
+ _getItemsAsjQuery: function(connected) {
+
+ var i, j, cur, inst,
+ items = [],
+ queries = [],
+ connectWith = this._connectWith();
+
+ if(connectWith && connected) {
+ for (i = connectWith.length - 1; i >= 0; i--){
+ cur = $(connectWith[i]);
+ for ( j = cur.length - 1; j >= 0; j--){
+ inst = $.data(cur[j], this.widgetFullName);
+ if(inst && inst !== this && !inst.options.disabled) {
+ queries.push([$.isFunction(inst.options.items) ? inst.options.items.call(inst.element) : $(inst.options.items, inst.element).not(".ui-sortable-helper").not(".ui-sortable-placeholder"), inst]);
+ }
+ }
+ }
+ }
+
+ queries.push([$.isFunction(this.options.items) ? this.options.items.call(this.element, null, { options: this.options, item: this.currentItem }) : $(this.options.items, this.element).not(".ui-sortable-helper").not(".ui-sortable-placeholder"), this]);
+
+ for (i = queries.length - 1; i >= 0; i--){
+ queries[i][0].each(function() {
+ items.push(this);
+ });
+ }
+
+ return $(items);
+
+ },
+
+ _removeCurrentsFromItems: function() {
+
+ var list = this.currentItem.find(":data(" + this.widgetName + "-item)");
+
+ this.items = $.grep(this.items, function (item) {
+ for (var j=0; j < list.length; j++) {
+ if(list[j] === item.item[0]) {
+ return false;
+ }
+ }
+ return true;
+ });
+
+ },
+
+ _refreshItems: function(event) {
+
+ this.items = [];
+ this.containers = [this];
+
+ var i, j, cur, inst, targetData, _queries, item, queriesLength,
+ items = this.items,
+ queries = [[$.isFunction(this.options.items) ? this.options.items.call(this.element[0], event, { item: this.currentItem }) : $(this.options.items, this.element), this]],
+ connectWith = this._connectWith();
+
+ if(connectWith && this.ready) { //Shouldn't be run the first time through due to massive slow-down
+ for (i = connectWith.length - 1; i >= 0; i--){
+ cur = $(connectWith[i]);
+ for (j = cur.length - 1; j >= 0; j--){
+ inst = $.data(cur[j], this.widgetFullName);
+ if(inst && inst !== this && !inst.options.disabled) {
+ queries.push([$.isFunction(inst.options.items) ? inst.options.items.call(inst.element[0], event, { item: this.currentItem }) : $(inst.options.items, inst.element), inst]);
+ this.containers.push(inst);
+ }
+ }
+ }
+ }
+
+ for (i = queries.length - 1; i >= 0; i--) {
+ targetData = queries[i][1];
+ _queries = queries[i][0];
+
+ for (j=0, queriesLength = _queries.length; j < queriesLength; j++) {
+ item = $(_queries[j]);
+
+ item.data(this.widgetName + "-item", targetData); // Data for target checking (mouse manager)
+
+ items.push({
+ item: item,
+ instance: targetData,
+ width: 0, height: 0,
+ left: 0, top: 0
+ });
+ }
+ }
+
+ },
+
+ refreshPositions: function(fast) {
+
+ //This has to be redone because due to the item being moved out/into the offsetParent, the offsetParent's position will change
+ if(this.offsetParent && this.helper) {
+ this.offset.parent = this._getParentOffset();
+ }
+
+ var i, item, t, p;
+
+ for (i = this.items.length - 1; i >= 0; i--){
+ item = this.items[i];
+
+ //We ignore calculating positions of all connected containers when we're not over them
+ if(item.instance !== this.currentContainer && this.currentContainer && item.item[0] !== this.currentItem[0]) {
+ continue;
+ }
+
+ t = this.options.toleranceElement ? $(this.options.toleranceElement, item.item) : item.item;
+
+ if (!fast) {
+ item.width = t.outerWidth();
+ item.height = t.outerHeight();
+ }
+
+ p = t.offset();
+ item.left = p.left;
+ item.top = p.top;
+ }
+
+ if(this.options.custom && this.options.custom.refreshContainers) {
+ this.options.custom.refreshContainers.call(this);
+ } else {
+ for (i = this.containers.length - 1; i >= 0; i--){
+ p = this.containers[i].element.offset();
+ this.containers[i].containerCache.left = p.left;
+ this.containers[i].containerCache.top = p.top;
+ this.containers[i].containerCache.width = this.containers[i].element.outerWidth();
+ this.containers[i].containerCache.height = this.containers[i].element.outerHeight();
+ }
+ }
+
+ return this;
+ },
+
+ _createPlaceholder: function(that) {
+ that = that || this;
+ var className,
+ o = that.options;
+
+ if(!o.placeholder || o.placeholder.constructor === String) {
+ className = o.placeholder;
+ o.placeholder = {
+ element: function() {
+
+ var nodeName = that.currentItem[0].nodeName.toLowerCase(),
+ element = $( "<" + nodeName + ">", that.document[0] )
+ .addClass(className || that.currentItem[0].className+" ui-sortable-placeholder")
+ .removeClass("ui-sortable-helper");
+
+ if ( nodeName === "tr" ) {
+ that.currentItem.children().each(function() {
+ $( "<td>&#160;</td>", that.document[0] )
+ .attr( "colspan", $( this ).attr( "colspan" ) || 1 )
+ .appendTo( element );
+ });
+ } else if ( nodeName === "img" ) {
+ element.attr( "src", that.currentItem.attr( "src" ) );
+ }
+
+ if ( !className ) {
+ element.css( "visibility", "hidden" );
+ }
+
+ return element;
+ },
+ update: function(container, p) {
+
+ // 1. If a className is set as 'placeholder option, we don't force sizes - the class is responsible for that
+ // 2. The option 'forcePlaceholderSize can be enabled to force it even if a class name is specified
+ if(className && !o.forcePlaceholderSize) {
+ return;
+ }
+
+ //If the element doesn't have a actual height by itself (without styles coming from a stylesheet), it receives the inline height from the dragged item
+ if(!p.height()) { p.height(that.currentItem.innerHeight() - parseInt(that.currentItem.css("paddingTop")||0, 10) - parseInt(that.currentItem.css("paddingBottom")||0, 10)); }
+ if(!p.width()) { p.width(that.currentItem.innerWidth() - parseInt(that.currentItem.css("paddingLeft")||0, 10) - parseInt(that.currentItem.css("paddingRight")||0, 10)); }
+ }
+ };
+ }
+
+ //Create the placeholder
+ that.placeholder = $(o.placeholder.element.call(that.element, that.currentItem));
+
+ //Append it after the actual current item
+ that.currentItem.after(that.placeholder);
+
+ //Update the size of the placeholder (TODO: Logic to fuzzy, see line 316/317)
+ o.placeholder.update(that, that.placeholder);
+
+ },
+
+ _contactContainers: function(event) {
+ var i, j, dist, itemWithLeastDistance, posProperty, sizeProperty, base, cur, nearBottom, floating,
+ innermostContainer = null,
+ innermostIndex = null;
+
+ // get innermost container that intersects with item
+ for (i = this.containers.length - 1; i >= 0; i--) {
+
+ // never consider a container that's located within the item itself
+ if($.contains(this.currentItem[0], this.containers[i].element[0])) {
+ continue;
+ }
+
+ if(this._intersectsWith(this.containers[i].containerCache)) {
+
+ // if we've already found a container and it's more "inner" than this, then continue
+ if(innermostContainer && $.contains(this.containers[i].element[0], innermostContainer.element[0])) {
+ continue;
+ }
+
+ innermostContainer = this.containers[i];
+ innermostIndex = i;
+
+ } else {
+ // container doesn't intersect. trigger "out" event if necessary
+ if(this.containers[i].containerCache.over) {
+ this.containers[i]._trigger("out", event, this._uiHash(this));
+ this.containers[i].containerCache.over = 0;
+ }
+ }
+
+ }
+
+ // if no intersecting containers found, return
+ if(!innermostContainer) {
+ return;
+ }
+
+ // move the item into the container if it's not there already
+ if(this.containers.length === 1) {
+ if (!this.containers[innermostIndex].containerCache.over) {
+ this.containers[innermostIndex]._trigger("over", event, this._uiHash(this));
+ this.containers[innermostIndex].containerCache.over = 1;
+ }
+ } else {
+
+ //When entering a new container, we will find the item with the least distance and append our item near it
+ dist = 10000;
+ itemWithLeastDistance = null;
+ floating = innermostContainer.floating || isFloating(this.currentItem);
+ posProperty = floating ? "left" : "top";
+ sizeProperty = floating ? "width" : "height";
+ base = this.positionAbs[posProperty] + this.offset.click[posProperty];
+ for (j = this.items.length - 1; j >= 0; j--) {
+ if(!$.contains(this.containers[innermostIndex].element[0], this.items[j].item[0])) {
+ continue;
+ }
+ if(this.items[j].item[0] === this.currentItem[0]) {
+ continue;
+ }
+ if (floating && !isOverAxis(this.positionAbs.top + this.offset.click.top, this.items[j].top, this.items[j].height)) {
+ continue;
+ }
+ cur = this.items[j].item.offset()[posProperty];
+ nearBottom = false;
+ if(Math.abs(cur - base) > Math.abs(cur + this.items[j][sizeProperty] - base)){
+ nearBottom = true;
+ cur += this.items[j][sizeProperty];
+ }
+
+ if(Math.abs(cur - base) < dist) {
+ dist = Math.abs(cur - base); itemWithLeastDistance = this.items[j];
+ this.direction = nearBottom ? "up": "down";
+ }
+ }
+
+ //Check if dropOnEmpty is enabled
+ if(!itemWithLeastDistance && !this.options.dropOnEmpty) {
+ return;
+ }
+
+ if(this.currentContainer === this.containers[innermostIndex]) {
+ return;
+ }
+
+ itemWithLeastDistance ? this._rearrange(event, itemWithLeastDistance, null, true) : this._rearrange(event, null, this.containers[innermostIndex].element, true);
+ this._trigger("change", event, this._uiHash());
+ this.containers[innermostIndex]._trigger("change", event, this._uiHash(this));
+ this.currentContainer = this.containers[innermostIndex];
+
+ //Update the placeholder
+ this.options.placeholder.update(this.currentContainer, this.placeholder);
+
+ this.containers[innermostIndex]._trigger("over", event, this._uiHash(this));
+ this.containers[innermostIndex].containerCache.over = 1;
+ }
+
+
+ },
+
+ _createHelper: function(event) {
+
+ var o = this.options,
+ helper = $.isFunction(o.helper) ? $(o.helper.apply(this.element[0], [event, this.currentItem])) : (o.helper === "clone" ? this.currentItem.clone() : this.currentItem);
+
+ //Add the helper to the DOM if that didn't happen already
+ if(!helper.parents("body").length) {
+ $(o.appendTo !== "parent" ? o.appendTo : this.currentItem[0].parentNode)[0].appendChild(helper[0]);
+ }
+
+ if(helper[0] === this.currentItem[0]) {
+ this._storedCSS = { width: this.currentItem[0].style.width, height: this.currentItem[0].style.height, position: this.currentItem.css("position"), top: this.currentItem.css("top"), left: this.currentItem.css("left") };
+ }
+
+ if(!helper[0].style.width || o.forceHelperSize) {
+ helper.width(this.currentItem.width());
+ }
+ if(!helper[0].style.height || o.forceHelperSize) {
+ helper.height(this.currentItem.height());
+ }
+
+ return helper;
+
+ },
+
+ _adjustOffsetFromHelper: function(obj) {
+ if (typeof obj === "string") {
+ obj = obj.split(" ");
+ }
+ if ($.isArray(obj)) {
+ obj = {left: +obj[0], top: +obj[1] || 0};
+ }
+ if ("left" in obj) {
+ this.offset.click.left = obj.left + this.margins.left;
+ }
+ if ("right" in obj) {
+ this.offset.click.left = this.helperProportions.width - obj.right + this.margins.left;
+ }
+ if ("top" in obj) {
+ this.offset.click.top = obj.top + this.margins.top;
+ }
+ if ("bottom" in obj) {
+ this.offset.click.top = this.helperProportions.height - obj.bottom + this.margins.top;
+ }
+ },
+
+ _getParentOffset: function() {
+
+
+ //Get the offsetParent and cache its position
+ this.offsetParent = this.helper.offsetParent();
+ var po = this.offsetParent.offset();
+
+ // This is a special case where we need to modify a offset calculated on start, since the following happened:
+ // 1. The position of the helper is absolute, so it's position is calculated based on the next positioned parent
+ // 2. The actual offset parent is a child of the scroll parent, and the scroll parent isn't the document, which means that
+ // the scroll is included in the initial calculation of the offset of the parent, and never recalculated upon drag
+ if(this.cssPosition === "absolute" && this.scrollParent[0] !== document && $.contains(this.scrollParent[0], this.offsetParent[0])) {
+ po.left += this.scrollParent.scrollLeft();
+ po.top += this.scrollParent.scrollTop();
+ }
+
+ // This needs to be actually done for all browsers, since pageX/pageY includes this information
+ // with an ugly IE fix
+ if( this.offsetParent[0] === document.body || (this.offsetParent[0].tagName && this.offsetParent[0].tagName.toLowerCase() === "html" && $.ui.ie)) {
+ po = { top: 0, left: 0 };
+ }
+
+ return {
+ top: po.top + (parseInt(this.offsetParent.css("borderTopWidth"),10) || 0),
+ left: po.left + (parseInt(this.offsetParent.css("borderLeftWidth"),10) || 0)
+ };
+
+ },
+
+ _getRelativeOffset: function() {
+
+ if(this.cssPosition === "relative") {
+ var p = this.currentItem.position();
+ return {
+ top: p.top - (parseInt(this.helper.css("top"),10) || 0) + this.scrollParent.scrollTop(),
+ left: p.left - (parseInt(this.helper.css("left"),10) || 0) + this.scrollParent.scrollLeft()
+ };
+ } else {
+ return { top: 0, left: 0 };
+ }
+
+ },
+
+ _cacheMargins: function() {
+ this.margins = {
+ left: (parseInt(this.currentItem.css("marginLeft"),10) || 0),
+ top: (parseInt(this.currentItem.css("marginTop"),10) || 0)
+ };
+ },
+
+ _cacheHelperProportions: function() {
+ this.helperProportions = {
+ width: this.helper.outerWidth(),
+ height: this.helper.outerHeight()
+ };
+ },
+
+ _setContainment: function() {
+
+ var ce, co, over,
+ o = this.options;
+ if(o.containment === "parent") {
+ o.containment = this.helper[0].parentNode;
+ }
+ if(o.containment === "document" || o.containment === "window") {
+ this.containment = [
+ 0 - this.offset.relative.left - this.offset.parent.left,
+ 0 - this.offset.relative.top - this.offset.parent.top,
+ $(o.containment === "document" ? document : window).width() - this.helperProportions.width - this.margins.left,
+ ($(o.containment === "document" ? document : window).height() || document.body.parentNode.scrollHeight) - this.helperProportions.height - this.margins.top
+ ];
+ }
+
+ if(!(/^(document|window|parent)$/).test(o.containment)) {
+ ce = $(o.containment)[0];
+ co = $(o.containment).offset();
+ over = ($(ce).css("overflow") !== "hidden");
+
+ this.containment = [
+ co.left + (parseInt($(ce).css("borderLeftWidth"),10) || 0) + (parseInt($(ce).css("paddingLeft"),10) || 0) - this.margins.left,
+ co.top + (parseInt($(ce).css("borderTopWidth"),10) || 0) + (parseInt($(ce).css("paddingTop"),10) || 0) - this.margins.top,
+ co.left+(over ? Math.max(ce.scrollWidth,ce.offsetWidth) : ce.offsetWidth) - (parseInt($(ce).css("borderLeftWidth"),10) || 0) - (parseInt($(ce).css("paddingRight"),10) || 0) - this.helperProportions.width - this.margins.left,
+ co.top+(over ? Math.max(ce.scrollHeight,ce.offsetHeight) : ce.offsetHeight) - (parseInt($(ce).css("borderTopWidth"),10) || 0) - (parseInt($(ce).css("paddingBottom"),10) || 0) - this.helperProportions.height - this.margins.top
+ ];
+ }
+
+ },
+
+ _convertPositionTo: function(d, pos) {
+
+ if(!pos) {
+ pos = this.position;
+ }
+ var mod = d === "absolute" ? 1 : -1,
+ scroll = this.cssPosition === "absolute" && !(this.scrollParent[0] !== document && $.contains(this.scrollParent[0], this.offsetParent[0])) ? this.offsetParent : this.scrollParent,
+ scrollIsRootNode = (/(html|body)/i).test(scroll[0].tagName);
+
+ return {
+ top: (
+ pos.top + // The absolute mouse position
+ this.offset.relative.top * mod + // Only for relative positioned nodes: Relative offset from element to offset parent
+ this.offset.parent.top * mod - // The offsetParent's offset without borders (offset + border)
+ ( ( this.cssPosition === "fixed" ? -this.scrollParent.scrollTop() : ( scrollIsRootNode ? 0 : scroll.scrollTop() ) ) * mod)
+ ),
+ left: (
+ pos.left + // The absolute mouse position
+ this.offset.relative.left * mod + // Only for relative positioned nodes: Relative offset from element to offset parent
+ this.offset.parent.left * mod - // The offsetParent's offset without borders (offset + border)
+ ( ( this.cssPosition === "fixed" ? -this.scrollParent.scrollLeft() : scrollIsRootNode ? 0 : scroll.scrollLeft() ) * mod)
+ )
+ };
+
+ },
+
+ _generatePosition: function(event) {
+
+ var top, left,
+ o = this.options,
+ pageX = event.pageX,
+ pageY = event.pageY,
+ scroll = this.cssPosition === "absolute" && !(this.scrollParent[0] !== document && $.contains(this.scrollParent[0], this.offsetParent[0])) ? this.offsetParent : this.scrollParent, scrollIsRootNode = (/(html|body)/i).test(scroll[0].tagName);
+
+ // This is another very weird special case that only happens for relative elements:
+ // 1. If the css position is relative
+ // 2. and the scroll parent is the document or similar to the offset parent
+ // we have to refresh the relative offset during the scroll so there are no jumps
+ if(this.cssPosition === "relative" && !(this.scrollParent[0] !== document && this.scrollParent[0] !== this.offsetParent[0])) {
+ this.offset.relative = this._getRelativeOffset();
+ }
+
+ /*
+ * - Position constraining -
+ * Constrain the position to a mix of grid, containment.
+ */
+
+ if(this.originalPosition) { //If we are not dragging yet, we won't check for options
+
+ if(this.containment) {
+ if(event.pageX - this.offset.click.left < this.containment[0]) {
+ pageX = this.containment[0] + this.offset.click.left;
+ }
+ if(event.pageY - this.offset.click.top < this.containment[1]) {
+ pageY = this.containment[1] + this.offset.click.top;
+ }
+ if(event.pageX - this.offset.click.left > this.containment[2]) {
+ pageX = this.containment[2] + this.offset.click.left;
+ }
+ if(event.pageY - this.offset.click.top > this.containment[3]) {
+ pageY = this.containment[3] + this.offset.click.top;
+ }
+ }
+
+ if(o.grid) {
+ top = this.originalPageY + Math.round((pageY - this.originalPageY) / o.grid[1]) * o.grid[1];
+ pageY = this.containment ? ( (top - this.offset.click.top >= this.containment[1] && top - this.offset.click.top <= this.containment[3]) ? top : ((top - this.offset.click.top >= this.containment[1]) ? top - o.grid[1] : top + o.grid[1])) : top;
+
+ left = this.originalPageX + Math.round((pageX - this.originalPageX) / o.grid[0]) * o.grid[0];
+ pageX = this.containment ? ( (left - this.offset.click.left >= this.containment[0] && left - this.offset.click.left <= this.containment[2]) ? left : ((left - this.offset.click.left >= this.containment[0]) ? left - o.grid[0] : left + o.grid[0])) : left;
+ }
+
+ }
+
+ return {
+ top: (
+ pageY - // The absolute mouse position
+ this.offset.click.top - // Click offset (relative to the element)
+ this.offset.relative.top - // Only for relative positioned nodes: Relative offset from element to offset parent
+ this.offset.parent.top + // The offsetParent's offset without borders (offset + border)
+ ( ( this.cssPosition === "fixed" ? -this.scrollParent.scrollTop() : ( scrollIsRootNode ? 0 : scroll.scrollTop() ) ))
+ ),
+ left: (
+ pageX - // The absolute mouse position
+ this.offset.click.left - // Click offset (relative to the element)
+ this.offset.relative.left - // Only for relative positioned nodes: Relative offset from element to offset parent
+ this.offset.parent.left + // The offsetParent's offset without borders (offset + border)
+ ( ( this.cssPosition === "fixed" ? -this.scrollParent.scrollLeft() : scrollIsRootNode ? 0 : scroll.scrollLeft() ))
+ )
+ };
+
+ },
+
+ _rearrange: function(event, i, a, hardRefresh) {
+
+ a ? a[0].appendChild(this.placeholder[0]) : i.item[0].parentNode.insertBefore(this.placeholder[0], (this.direction === "down" ? i.item[0] : i.item[0].nextSibling));
+
+ //Various things done here to improve the performance:
+ // 1. we create a setTimeout, that calls refreshPositions
+ // 2. on the instance, we have a counter variable, that get's higher after every append
+ // 3. on the local scope, we copy the counter variable, and check in the timeout, if it's still the same
+ // 4. this lets only the last addition to the timeout stack through
+ this.counter = this.counter ? ++this.counter : 1;
+ var counter = this.counter;
+
+ this._delay(function() {
+ if(counter === this.counter) {
+ this.refreshPositions(!hardRefresh); //Precompute after each DOM insertion, NOT on mousemove
+ }
+ });
+
+ },
+
+ _clear: function(event, noPropagation) {
+
+ this.reverting = false;
+ // We delay all events that have to be triggered to after the point where the placeholder has been removed and
+ // everything else normalized again
+ var i,
+ delayedTriggers = [];
+
+ // We first have to update the dom position of the actual currentItem
+ // Note: don't do it if the current item is already removed (by a user), or it gets reappended (see #4088)
+ if(!this._noFinalSort && this.currentItem.parent().length) {
+ this.placeholder.before(this.currentItem);
+ }
+ this._noFinalSort = null;
+
+ if(this.helper[0] === this.currentItem[0]) {
+ for(i in this._storedCSS) {
+ if(this._storedCSS[i] === "auto" || this._storedCSS[i] === "static") {
+ this._storedCSS[i] = "";
+ }
+ }
+ this.currentItem.css(this._storedCSS).removeClass("ui-sortable-helper");
+ } else {
+ this.currentItem.show();
+ }
+
+ if(this.fromOutside && !noPropagation) {
+ delayedTriggers.push(function(event) { this._trigger("receive", event, this._uiHash(this.fromOutside)); });
+ }
+ if((this.fromOutside || this.domPosition.prev !== this.currentItem.prev().not(".ui-sortable-helper")[0] || this.domPosition.parent !== this.currentItem.parent()[0]) && !noPropagation) {
+ delayedTriggers.push(function(event) { this._trigger("update", event, this._uiHash()); }); //Trigger update callback if the DOM position has changed
+ }
+
+ // Check if the items Container has Changed and trigger appropriate
+ // events.
+ if (this !== this.currentContainer) {
+ if(!noPropagation) {
+ delayedTriggers.push(function(event) { this._trigger("remove", event, this._uiHash()); });
+ delayedTriggers.push((function(c) { return function(event) { c._trigger("receive", event, this._uiHash(this)); }; }).call(this, this.currentContainer));
+ delayedTriggers.push((function(c) { return function(event) { c._trigger("update", event, this._uiHash(this)); }; }).call(this, this.currentContainer));
+ }
+ }
+
+
+ //Post events to containers
+ for (i = this.containers.length - 1; i >= 0; i--){
+ if(!noPropagation) {
+ delayedTriggers.push((function(c) { return function(event) { c._trigger("deactivate", event, this._uiHash(this)); }; }).call(this, this.containers[i]));
+ }
+ if(this.containers[i].containerCache.over) {
+ delayedTriggers.push((function(c) { return function(event) { c._trigger("out", event, this._uiHash(this)); }; }).call(this, this.containers[i]));
+ this.containers[i].containerCache.over = 0;
+ }
+ }
+
+ //Do what was originally in plugins
+ if ( this.storedCursor ) {
+ this.document.find( "body" ).css( "cursor", this.storedCursor );
+ this.storedStylesheet.remove();
+ }
+ if(this._storedOpacity) {
+ this.helper.css("opacity", this._storedOpacity);
+ }
+ if(this._storedZIndex) {
+ this.helper.css("zIndex", this._storedZIndex === "auto" ? "" : this._storedZIndex);
+ }
+
+ this.dragging = false;
+ if(this.cancelHelperRemoval) {
+ if(!noPropagation) {
+ this._trigger("beforeStop", event, this._uiHash());
+ for (i=0; i < delayedTriggers.length; i++) {
+ delayedTriggers[i].call(this, event);
+ } //Trigger all delayed events
+ this._trigger("stop", event, this._uiHash());
+ }
+
+ this.fromOutside = false;
+ return false;
+ }
+
+ if(!noPropagation) {
+ this._trigger("beforeStop", event, this._uiHash());
+ }
+
+ //$(this.placeholder[0]).remove(); would have been the jQuery way - unfortunately, it unbinds ALL events from the original node!
+ this.placeholder[0].parentNode.removeChild(this.placeholder[0]);
+
+ if(this.helper[0] !== this.currentItem[0]) {
+ this.helper.remove();
+ }
+ this.helper = null;
+
+ if(!noPropagation) {
+ for (i=0; i < delayedTriggers.length; i++) {
+ delayedTriggers[i].call(this, event);
+ } //Trigger all delayed events
+ this._trigger("stop", event, this._uiHash());
+ }
+
+ this.fromOutside = false;
+ return true;
+
+ },
+
+ _trigger: function() {
+ if ($.Widget.prototype._trigger.apply(this, arguments) === false) {
+ this.cancel();
+ }
+ },
+
+ _uiHash: function(_inst) {
+ var inst = _inst || this;
+ return {
+ helper: inst.helper,
+ placeholder: inst.placeholder || $([]),
+ position: inst.position,
+ originalPosition: inst.originalPosition,
+ offset: inst.positionAbs,
+ item: inst.currentItem,
+ sender: _inst ? _inst.element : null
+ };
+ }
+
+});
+
+})(jQuery);
diff --git a/debian/missing-sources/jquery-ui/jquery.ui.spinner.js b/debian/missing-sources/jquery-ui/jquery.ui.spinner.js
new file mode 100644
index 0000000..5bfbb27
--- /dev/null
+++ b/debian/missing-sources/jquery-ui/jquery.ui.spinner.js
@@ -0,0 +1,493 @@
+/*!
+ * jQuery UI Spinner 1.10.3
+ * http://jqueryui.com
+ *
+ * Copyright 2013 jQuery Foundation and other contributors
+ * Released under the MIT license.
+ * http://jquery.org/license
+ *
+ * http://api.jqueryui.com/spinner/
+ *
+ * Depends:
+ * jquery.ui.core.js
+ * jquery.ui.widget.js
+ * jquery.ui.button.js
+ */
+(function( $ ) {
+
+function modifier( fn ) {
+ return function() {
+ var previous = this.element.val();
+ fn.apply( this, arguments );
+ this._refresh();
+ if ( previous !== this.element.val() ) {
+ this._trigger( "change" );
+ }
+ };
+}
+
+$.widget( "ui.spinner", {
+ version: "1.10.3",
+ defaultElement: "<input>",
+ widgetEventPrefix: "spin",
+ options: {
+ culture: null,
+ icons: {
+ down: "ui-icon-triangle-1-s",
+ up: "ui-icon-triangle-1-n"
+ },
+ incremental: true,
+ max: null,
+ min: null,
+ numberFormat: null,
+ page: 10,
+ step: 1,
+
+ change: null,
+ spin: null,
+ start: null,
+ stop: null
+ },
+
+ _create: function() {
+ // handle string values that need to be parsed
+ this._setOption( "max", this.options.max );
+ this._setOption( "min", this.options.min );
+ this._setOption( "step", this.options.step );
+
+ // format the value, but don't constrain
+ this._value( this.element.val(), true );
+
+ this._draw();
+ this._on( this._events );
+ this._refresh();
+
+ // turning off autocomplete prevents the browser from remembering the
+ // value when navigating through history, so we re-enable autocomplete
+ // if the page is unloaded before the widget is destroyed. #7790
+ this._on( this.window, {
+ beforeunload: function() {
+ this.element.removeAttr( "autocomplete" );
+ }
+ });
+ },
+
+ _getCreateOptions: function() {
+ var options = {},
+ element = this.element;
+
+ $.each( [ "min", "max", "step" ], function( i, option ) {
+ var value = element.attr( option );
+ if ( value !== undefined && value.length ) {
+ options[ option ] = value;
+ }
+ });
+
+ return options;
+ },
+
+ _events: {
+ keydown: function( event ) {
+ if ( this._start( event ) && this._keydown( event ) ) {
+ event.preventDefault();
+ }
+ },
+ keyup: "_stop",
+ focus: function() {
+ this.previous = this.element.val();
+ },
+ blur: function( event ) {
+ if ( this.cancelBlur ) {
+ delete this.cancelBlur;
+ return;
+ }
+
+ this._stop();
+ this._refresh();
+ if ( this.previous !== this.element.val() ) {
+ this._trigger( "change", event );
+ }
+ },
+ mousewheel: function( event, delta ) {
+ if ( !delta ) {
+ return;
+ }
+ if ( !this.spinning && !this._start( event ) ) {
+ return false;
+ }
+
+ this._spin( (delta > 0 ? 1 : -1) * this.options.step, event );
+ clearTimeout( this.mousewheelTimer );
+ this.mousewheelTimer = this._delay(function() {
+ if ( this.spinning ) {
+ this._stop( event );
+ }
+ }, 100 );
+ event.preventDefault();
+ },
+ "mousedown .ui-spinner-button": function( event ) {
+ var previous;
+
+ // We never want the buttons to have focus; whenever the user is
+ // interacting with the spinner, the focus should be on the input.
+ // If the input is focused then this.previous is properly set from
+ // when the input first received focus. If the input is not focused
+ // then we need to set this.previous based on the value before spinning.
+ previous = this.element[0] === this.document[0].activeElement ?
+ this.previous : this.element.val();
+ function checkFocus() {
+ var isActive = this.element[0] === this.document[0].activeElement;
+ if ( !isActive ) {
+ this.element.focus();
+ this.previous = previous;
+ // support: IE
+ // IE sets focus asynchronously, so we need to check if focus
+ // moved off of the input because the user clicked on the button.
+ this._delay(function() {
+ this.previous = previous;
+ });
+ }
+ }
+
+ // ensure focus is on (or stays on) the text field
+ event.preventDefault();
+ checkFocus.call( this );
+
+ // support: IE
+ // IE doesn't prevent moving focus even with event.preventDefault()
+ // so we set a flag to know when we should ignore the blur event
+ // and check (again) if focus moved off of the input.
+ this.cancelBlur = true;
+ this._delay(function() {
+ delete this.cancelBlur;
+ checkFocus.call( this );
+ });
+
+ if ( this._start( event ) === false ) {
+ return;
+ }
+
+ this._repeat( null, $( event.currentTarget ).hasClass( "ui-spinner-up" ) ? 1 : -1, event );
+ },
+ "mouseup .ui-spinner-button": "_stop",
+ "mouseenter .ui-spinner-button": function( event ) {
+ // button will add ui-state-active if mouse was down while mouseleave and kept down
+ if ( !$( event.currentTarget ).hasClass( "ui-state-active" ) ) {
+ return;
+ }
+
+ if ( this._start( event ) === false ) {
+ return false;
+ }
+ this._repeat( null, $( event.currentTarget ).hasClass( "ui-spinner-up" ) ? 1 : -1, event );
+ },
+ // TODO: do we really want to consider this a stop?
+ // shouldn't we just stop the repeater and wait until mouseup before
+ // we trigger the stop event?
+ "mouseleave .ui-spinner-button": "_stop"
+ },
+
+ _draw: function() {
+ var uiSpinner = this.uiSpinner = this.element
+ .addClass( "ui-spinner-input" )
+ .attr( "autocomplete", "off" )
+ .wrap( this._uiSpinnerHtml() )
+ .parent()
+ // add buttons
+ .append( this._buttonHtml() );
+
+ this.element.attr( "role", "spinbutton" );
+
+ // button bindings
+ this.buttons = uiSpinner.find( ".ui-spinner-button" )
+ .attr( "tabIndex", -1 )
+ .button()
+ .removeClass( "ui-corner-all" );
+
+ // IE 6 doesn't understand height: 50% for the buttons
+ // unless the wrapper has an explicit height
+ if ( this.buttons.height() > Math.ceil( uiSpinner.height() * 0.5 ) &&
+ uiSpinner.height() > 0 ) {
+ uiSpinner.height( uiSpinner.height() );
+ }
+
+ // disable spinner if element was already disabled
+ if ( this.options.disabled ) {
+ this.disable();
+ }
+ },
+
+ _keydown: function( event ) {
+ var options = this.options,
+ keyCode = $.ui.keyCode;
+
+ switch ( event.keyCode ) {
+ case keyCode.UP:
+ this._repeat( null, 1, event );
+ return true;
+ case keyCode.DOWN:
+ this._repeat( null, -1, event );
+ return true;
+ case keyCode.PAGE_UP:
+ this._repeat( null, options.page, event );
+ return true;
+ case keyCode.PAGE_DOWN:
+ this._repeat( null, -options.page, event );
+ return true;
+ }
+
+ return false;
+ },
+
+ _uiSpinnerHtml: function() {
+ return "<span class='ui-spinner ui-widget ui-widget-content ui-corner-all'></span>";
+ },
+
+ _buttonHtml: function() {
+ return "" +
+ "<a class='ui-spinner-button ui-spinner-up ui-corner-tr'>" +
+ "<span class='ui-icon " + this.options.icons.up + "'>&#9650;</span>" +
+ "</a>" +
+ "<a class='ui-spinner-button ui-spinner-down ui-corner-br'>" +
+ "<span class='ui-icon " + this.options.icons.down + "'>&#9660;</span>" +
+ "</a>";
+ },
+
+ _start: function( event ) {
+ if ( !this.spinning && this._trigger( "start", event ) === false ) {
+ return false;
+ }
+
+ if ( !this.counter ) {
+ this.counter = 1;
+ }
+ this.spinning = true;
+ return true;
+ },
+
+ _repeat: function( i, steps, event ) {
+ i = i || 500;
+
+ clearTimeout( this.timer );
+ this.timer = this._delay(function() {
+ this._repeat( 40, steps, event );
+ }, i );
+
+ this._spin( steps * this.options.step, event );
+ },
+
+ _spin: function( step, event ) {
+ var value = this.value() || 0;
+
+ if ( !this.counter ) {
+ this.counter = 1;
+ }
+
+ value = this._adjustValue( value + step * this._increment( this.counter ) );
+
+ if ( !this.spinning || this._trigger( "spin", event, { value: value } ) !== false) {
+ this._value( value );
+ this.counter++;
+ }
+ },
+
+ _increment: function( i ) {
+ var incremental = this.options.incremental;
+
+ if ( incremental ) {
+ return $.isFunction( incremental ) ?
+ incremental( i ) :
+ Math.floor( i*i*i/50000 - i*i/500 + 17*i/200 + 1 );
+ }
+
+ return 1;
+ },
+
+ _precision: function() {
+ var precision = this._precisionOf( this.options.step );
+ if ( this.options.min !== null ) {
+ precision = Math.max( precision, this._precisionOf( this.options.min ) );
+ }
+ return precision;
+ },
+
+ _precisionOf: function( num ) {
+ var str = num.toString(),
+ decimal = str.indexOf( "." );
+ return decimal === -1 ? 0 : str.length - decimal - 1;
+ },
+
+ _adjustValue: function( value ) {
+ var base, aboveMin,
+ options = this.options;
+
+ // make sure we're at a valid step
+ // - find out where we are relative to the base (min or 0)
+ base = options.min !== null ? options.min : 0;
+ aboveMin = value - base;
+ // - round to the nearest step
+ aboveMin = Math.round(aboveMin / options.step) * options.step;
+ // - rounding is based on 0, so adjust back to our base
+ value = base + aboveMin;
+
+ // fix precision from bad JS floating point math
+ value = parseFloat( value.toFixed( this._precision() ) );
+
+ // clamp the value
+ if ( options.max !== null && value > options.max) {
+ return options.max;
+ }
+ if ( options.min !== null && value < options.min ) {
+ return options.min;
+ }
+
+ return value;
+ },
+
+ _stop: function( event ) {
+ if ( !this.spinning ) {
+ return;
+ }
+
+ clearTimeout( this.timer );
+ clearTimeout( this.mousewheelTimer );
+ this.counter = 0;
+ this.spinning = false;
+ this._trigger( "stop", event );
+ },
+
+ _setOption: function( key, value ) {
+ if ( key === "culture" || key === "numberFormat" ) {
+ var prevValue = this._parse( this.element.val() );
+ this.options[ key ] = value;
+ this.element.val( this._format( prevValue ) );
+ return;
+ }
+
+ if ( key === "max" || key === "min" || key === "step" ) {
+ if ( typeof value === "string" ) {
+ value = this._parse( value );
+ }
+ }
+ if ( key === "icons" ) {
+ this.buttons.first().find( ".ui-icon" )
+ .removeClass( this.options.icons.up )
+ .addClass( value.up );
+ this.buttons.last().find( ".ui-icon" )
+ .removeClass( this.options.icons.down )
+ .addClass( value.down );
+ }
+
+ this._super( key, value );
+
+ if ( key === "disabled" ) {
+ if ( value ) {
+ this.element.prop( "disabled", true );
+ this.buttons.button( "disable" );
+ } else {
+ this.element.prop( "disabled", false );
+ this.buttons.button( "enable" );
+ }
+ }
+ },
+
+ _setOptions: modifier(function( options ) {
+ this._super( options );
+ this._value( this.element.val() );
+ }),
+
+ _parse: function( val ) {
+ if ( typeof val === "string" && val !== "" ) {
+ val = window.Globalize && this.options.numberFormat ?
+ Globalize.parseFloat( val, 10, this.options.culture ) : +val;
+ }
+ return val === "" || isNaN( val ) ? null : val;
+ },
+
+ _format: function( value ) {
+ if ( value === "" ) {
+ return "";
+ }
+ return window.Globalize && this.options.numberFormat ?
+ Globalize.format( value, this.options.numberFormat, this.options.culture ) :
+ value;
+ },
+
+ _refresh: function() {
+ this.element.attr({
+ "aria-valuemin": this.options.min,
+ "aria-valuemax": this.options.max,
+ // TODO: what should we do with values that can't be parsed?
+ "aria-valuenow": this._parse( this.element.val() )
+ });
+ },
+
+ // update the value without triggering change
+ _value: function( value, allowAny ) {
+ var parsed;
+ if ( value !== "" ) {
+ parsed = this._parse( value );
+ if ( parsed !== null ) {
+ if ( !allowAny ) {
+ parsed = this._adjustValue( parsed );
+ }
+ value = this._format( parsed );
+ }
+ }
+ this.element.val( value );
+ this._refresh();
+ },
+
+ _destroy: function() {
+ this.element
+ .removeClass( "ui-spinner-input" )
+ .prop( "disabled", false )
+ .removeAttr( "autocomplete" )
+ .removeAttr( "role" )
+ .removeAttr( "aria-valuemin" )
+ .removeAttr( "aria-valuemax" )
+ .removeAttr( "aria-valuenow" );
+ this.uiSpinner.replaceWith( this.element );
+ },
+
+ stepUp: modifier(function( steps ) {
+ this._stepUp( steps );
+ }),
+ _stepUp: function( steps ) {
+ if ( this._start() ) {
+ this._spin( (steps || 1) * this.options.step );
+ this._stop();
+ }
+ },
+
+ stepDown: modifier(function( steps ) {
+ this._stepDown( steps );
+ }),
+ _stepDown: function( steps ) {
+ if ( this._start() ) {
+ this._spin( (steps || 1) * -this.options.step );
+ this._stop();
+ }
+ },
+
+ pageUp: modifier(function( pages ) {
+ this._stepUp( (pages || 1) * this.options.page );
+ }),
+
+ pageDown: modifier(function( pages ) {
+ this._stepDown( (pages || 1) * this.options.page );
+ }),
+
+ value: function( newVal ) {
+ if ( !arguments.length ) {
+ return this._parse( this.element.val() );
+ }
+ modifier( this._value ).call( this, newVal );
+ },
+
+ widget: function() {
+ return this.uiSpinner;
+ }
+});
+
+}( jQuery ) );
diff --git a/debian/missing-sources/jquery-ui/jquery.ui.tabs.js b/debian/missing-sources/jquery-ui/jquery.ui.tabs.js
new file mode 100644
index 0000000..b37858e
--- /dev/null
+++ b/debian/missing-sources/jquery-ui/jquery.ui.tabs.js
@@ -0,0 +1,846 @@
+/*!
+ * jQuery UI Tabs 1.10.3
+ * http://jqueryui.com
+ *
+ * Copyright 2013 jQuery Foundation and other contributors
+ * Released under the MIT license.
+ * http://jquery.org/license
+ *
+ * http://api.jqueryui.com/tabs/
+ *
+ * Depends:
+ * jquery.ui.core.js
+ * jquery.ui.widget.js
+ */
+(function( $, undefined ) {
+
+var tabId = 0,
+ rhash = /#.*$/;
+
+function getNextTabId() {
+ return ++tabId;
+}
+
+function isLocal( anchor ) {
+ return anchor.hash.length > 1 &&
+ decodeURIComponent( anchor.href.replace( rhash, "" ) ) ===
+ decodeURIComponent( location.href.replace( rhash, "" ) );
+}
+
+$.widget( "ui.tabs", {
+ version: "1.10.3",
+ delay: 300,
+ options: {
+ active: null,
+ collapsible: false,
+ event: "click",
+ heightStyle: "content",
+ hide: null,
+ show: null,
+
+ // callbacks
+ activate: null,
+ beforeActivate: null,
+ beforeLoad: null,
+ load: null
+ },
+
+ _create: function() {
+ var that = this,
+ options = this.options;
+
+ this.running = false;
+
+ this.element
+ .addClass( "ui-tabs ui-widget ui-widget-content ui-corner-all" )
+ .toggleClass( "ui-tabs-collapsible", options.collapsible )
+ // Prevent users from focusing disabled tabs via click
+ .delegate( ".ui-tabs-nav > li", "mousedown" + this.eventNamespace, function( event ) {
+ if ( $( this ).is( ".ui-state-disabled" ) ) {
+ event.preventDefault();
+ }
+ })
+ // support: IE <9
+ // Preventing the default action in mousedown doesn't prevent IE
+ // from focusing the element, so if the anchor gets focused, blur.
+ // We don't have to worry about focusing the previously focused
+ // element since clicking on a non-focusable element should focus
+ // the body anyway.
+ .delegate( ".ui-tabs-anchor", "focus" + this.eventNamespace, function() {
+ if ( $( this ).closest( "li" ).is( ".ui-state-disabled" ) ) {
+ this.blur();
+ }
+ });
+
+ this._processTabs();
+ options.active = this._initialActive();
+
+ // Take disabling tabs via class attribute from HTML
+ // into account and update option properly.
+ if ( $.isArray( options.disabled ) ) {
+ options.disabled = $.unique( options.disabled.concat(
+ $.map( this.tabs.filter( ".ui-state-disabled" ), function( li ) {
+ return that.tabs.index( li );
+ })
+ ) ).sort();
+ }
+
+ // check for length avoids error when initializing empty list
+ if ( this.options.active !== false && this.anchors.length ) {
+ this.active = this._findActive( options.active );
+ } else {
+ this.active = $();
+ }
+
+ this._refresh();
+
+ if ( this.active.length ) {
+ this.load( options.active );
+ }
+ },
+
+ _initialActive: function() {
+ var active = this.options.active,
+ collapsible = this.options.collapsible,
+ locationHash = location.hash.substring( 1 );
+
+ if ( active === null ) {
+ // check the fragment identifier in the URL
+ if ( locationHash ) {
+ this.tabs.each(function( i, tab ) {
+ if ( $( tab ).attr( "aria-controls" ) === locationHash ) {
+ active = i;
+ return false;
+ }
+ });
+ }
+
+ // check for a tab marked active via a class
+ if ( active === null ) {
+ active = this.tabs.index( this.tabs.filter( ".ui-tabs-active" ) );
+ }
+
+ // no active tab, set to false
+ if ( active === null || active === -1 ) {
+ active = this.tabs.length ? 0 : false;
+ }
+ }
+
+ // handle numbers: negative, out of range
+ if ( active !== false ) {
+ active = this.tabs.index( this.tabs.eq( active ) );
+ if ( active === -1 ) {
+ active = collapsible ? false : 0;
+ }
+ }
+
+ // don't allow collapsible: false and active: false
+ if ( !collapsible && active === false && this.anchors.length ) {
+ active = 0;
+ }
+
+ return active;
+ },
+
+ _getCreateEventData: function() {
+ return {
+ tab: this.active,
+ panel: !this.active.length ? $() : this._getPanelForTab( this.active )
+ };
+ },
+
+ _tabKeydown: function( event ) {
+ /*jshint maxcomplexity:15*/
+ var focusedTab = $( this.document[0].activeElement ).closest( "li" ),
+ selectedIndex = this.tabs.index( focusedTab ),
+ goingForward = true;
+
+ if ( this._handlePageNav( event ) ) {
+ return;
+ }
+
+ switch ( event.keyCode ) {
+ case $.ui.keyCode.RIGHT:
+ case $.ui.keyCode.DOWN:
+ selectedIndex++;
+ break;
+ case $.ui.keyCode.UP:
+ case $.ui.keyCode.LEFT:
+ goingForward = false;
+ selectedIndex--;
+ break;
+ case $.ui.keyCode.END:
+ selectedIndex = this.anchors.length - 1;
+ break;
+ case $.ui.keyCode.HOME:
+ selectedIndex = 0;
+ break;
+ case $.ui.keyCode.SPACE:
+ // Activate only, no collapsing
+ event.preventDefault();
+ clearTimeout( this.activating );
+ this._activate( selectedIndex );
+ return;
+ case $.ui.keyCode.ENTER:
+ // Toggle (cancel delayed activation, allow collapsing)
+ event.preventDefault();
+ clearTimeout( this.activating );
+ // Determine if we should collapse or activate
+ this._activate( selectedIndex === this.options.active ? false : selectedIndex );
+ return;
+ default:
+ return;
+ }
+
+ // Focus the appropriate tab, based on which key was pressed
+ event.preventDefault();
+ clearTimeout( this.activating );
+ selectedIndex = this._focusNextTab( selectedIndex, goingForward );
+
+ // Navigating with control key will prevent automatic activation
+ if ( !event.ctrlKey ) {
+ // Update aria-selected immediately so that AT think the tab is already selected.
+ // Otherwise AT may confuse the user by stating that they need to activate the tab,
+ // but the tab will already be activated by the time the announcement finishes.
+ focusedTab.attr( "aria-selected", "false" );
+ this.tabs.eq( selectedIndex ).attr( "aria-selected", "true" );
+
+ this.activating = this._delay(function() {
+ this.option( "active", selectedIndex );
+ }, this.delay );
+ }
+ },
+
+ _panelKeydown: function( event ) {
+ if ( this._handlePageNav( event ) ) {
+ return;
+ }
+
+ // Ctrl+up moves focus to the current tab
+ if ( event.ctrlKey && event.keyCode === $.ui.keyCode.UP ) {
+ event.preventDefault();
+ this.active.focus();
+ }
+ },
+
+ // Alt+page up/down moves focus to the previous/next tab (and activates)
+ _handlePageNav: function( event ) {
+ if ( event.altKey && event.keyCode === $.ui.keyCode.PAGE_UP ) {
+ this._activate( this._focusNextTab( this.options.active - 1, false ) );
+ return true;
+ }
+ if ( event.altKey && event.keyCode === $.ui.keyCode.PAGE_DOWN ) {
+ this._activate( this._focusNextTab( this.options.active + 1, true ) );
+ return true;
+ }
+ },
+
+ _findNextTab: function( index, goingForward ) {
+ var lastTabIndex = this.tabs.length - 1;
+
+ function constrain() {
+ if ( index > lastTabIndex ) {
+ index = 0;
+ }
+ if ( index < 0 ) {
+ index = lastTabIndex;
+ }
+ return index;
+ }
+
+ while ( $.inArray( constrain(), this.options.disabled ) !== -1 ) {
+ index = goingForward ? index + 1 : index - 1;
+ }
+
+ return index;
+ },
+
+ _focusNextTab: function( index, goingForward ) {
+ index = this._findNextTab( index, goingForward );
+ this.tabs.eq( index ).focus();
+ return index;
+ },
+
+ _setOption: function( key, value ) {
+ if ( key === "active" ) {
+ // _activate() will handle invalid values and update this.options
+ this._activate( value );
+ return;
+ }
+
+ if ( key === "disabled" ) {
+ // don't use the widget factory's disabled handling
+ this._setupDisabled( value );
+ return;
+ }
+
+ this._super( key, value);
+
+ if ( key === "collapsible" ) {
+ this.element.toggleClass( "ui-tabs-collapsible", value );
+ // Setting collapsible: false while collapsed; open first panel
+ if ( !value && this.options.active === false ) {
+ this._activate( 0 );
+ }
+ }
+
+ if ( key === "event" ) {
+ this._setupEvents( value );
+ }
+
+ if ( key === "heightStyle" ) {
+ this._setupHeightStyle( value );
+ }
+ },
+
+ _tabId: function( tab ) {
+ return tab.attr( "aria-controls" ) || "ui-tabs-" + getNextTabId();
+ },
+
+ _sanitizeSelector: function( hash ) {
+ return hash ? hash.replace( /[!"$%&'()*+,.\/:;<=>?@\[\]\^`{|}~]/g, "\\$&" ) : "";
+ },
+
+ refresh: function() {
+ var options = this.options,
+ lis = this.tablist.children( ":has(a[href])" );
+
+ // get disabled tabs from class attribute from HTML
+ // this will get converted to a boolean if needed in _refresh()
+ options.disabled = $.map( lis.filter( ".ui-state-disabled" ), function( tab ) {
+ return lis.index( tab );
+ });
+
+ this._processTabs();
+
+ // was collapsed or no tabs
+ if ( options.active === false || !this.anchors.length ) {
+ options.active = false;
+ this.active = $();
+ // was active, but active tab is gone
+ } else if ( this.active.length && !$.contains( this.tablist[ 0 ], this.active[ 0 ] ) ) {
+ // all remaining tabs are disabled
+ if ( this.tabs.length === options.disabled.length ) {
+ options.active = false;
+ this.active = $();
+ // activate previous tab
+ } else {
+ this._activate( this._findNextTab( Math.max( 0, options.active - 1 ), false ) );
+ }
+ // was active, active tab still exists
+ } else {
+ // make sure active index is correct
+ options.active = this.tabs.index( this.active );
+ }
+
+ this._refresh();
+ },
+
+ _refresh: function() {
+ this._setupDisabled( this.options.disabled );
+ this._setupEvents( this.options.event );
+ this._setupHeightStyle( this.options.heightStyle );
+
+ this.tabs.not( this.active ).attr({
+ "aria-selected": "false",
+ tabIndex: -1
+ });
+ this.panels.not( this._getPanelForTab( this.active ) )
+ .hide()
+ .attr({
+ "aria-expanded": "false",
+ "aria-hidden": "true"
+ });
+
+ // Make sure one tab is in the tab order
+ if ( !this.active.length ) {
+ this.tabs.eq( 0 ).attr( "tabIndex", 0 );
+ } else {
+ this.active
+ .addClass( "ui-tabs-active ui-state-active" )
+ .attr({
+ "aria-selected": "true",
+ tabIndex: 0
+ });
+ this._getPanelForTab( this.active )
+ .show()
+ .attr({
+ "aria-expanded": "true",
+ "aria-hidden": "false"
+ });
+ }
+ },
+
+ _processTabs: function() {
+ var that = this;
+
+ this.tablist = this._getList()
+ .addClass( "ui-tabs-nav ui-helper-reset ui-helper-clearfix ui-widget-header ui-corner-all" )
+ .attr( "role", "tablist" );
+
+ this.tabs = this.tablist.find( "> li:has(a[href])" )
+ .addClass( "ui-state-default ui-corner-top" )
+ .attr({
+ role: "tab",
+ tabIndex: -1
+ });
+
+ this.anchors = this.tabs.map(function() {
+ return $( "a", this )[ 0 ];
+ })
+ .addClass( "ui-tabs-anchor" )
+ .attr({
+ role: "presentation",
+ tabIndex: -1
+ });
+
+ this.panels = $();
+
+ this.anchors.each(function( i, anchor ) {
+ var selector, panel, panelId,
+ anchorId = $( anchor ).uniqueId().attr( "id" ),
+ tab = $( anchor ).closest( "li" ),
+ originalAriaControls = tab.attr( "aria-controls" );
+
+ // inline tab
+ if ( isLocal( anchor ) ) {
+ selector = anchor.hash;
+ panel = that.element.find( that._sanitizeSelector( selector ) );
+ // remote tab
+ } else {
+ panelId = that._tabId( tab );
+ selector = "#" + panelId;
+ panel = that.element.find( selector );
+ if ( !panel.length ) {
+ panel = that._createPanel( panelId );
+ panel.insertAfter( that.panels[ i - 1 ] || that.tablist );
+ }
+ panel.attr( "aria-live", "polite" );
+ }
+
+ if ( panel.length) {
+ that.panels = that.panels.add( panel );
+ }
+ if ( originalAriaControls ) {
+ tab.data( "ui-tabs-aria-controls", originalAriaControls );
+ }
+ tab.attr({
+ "aria-controls": selector.substring( 1 ),
+ "aria-labelledby": anchorId
+ });
+ panel.attr( "aria-labelledby", anchorId );
+ });
+
+ this.panels
+ .addClass( "ui-tabs-panel ui-widget-content ui-corner-bottom" )
+ .attr( "role", "tabpanel" );
+ },
+
+ // allow overriding how to find the list for rare usage scenarios (#7715)
+ _getList: function() {
+ return this.element.find( "ol,ul" ).eq( 0 );
+ },
+
+ _createPanel: function( id ) {
+ return $( "<div>" )
+ .attr( "id", id )
+ .addClass( "ui-tabs-panel ui-widget-content ui-corner-bottom" )
+ .data( "ui-tabs-destroy", true );
+ },
+
+ _setupDisabled: function( disabled ) {
+ if ( $.isArray( disabled ) ) {
+ if ( !disabled.length ) {
+ disabled = false;
+ } else if ( disabled.length === this.anchors.length ) {
+ disabled = true;
+ }
+ }
+
+ // disable tabs
+ for ( var i = 0, li; ( li = this.tabs[ i ] ); i++ ) {
+ if ( disabled === true || $.inArray( i, disabled ) !== -1 ) {
+ $( li )
+ .addClass( "ui-state-disabled" )
+ .attr( "aria-disabled", "true" );
+ } else {
+ $( li )
+ .removeClass( "ui-state-disabled" )
+ .removeAttr( "aria-disabled" );
+ }
+ }
+
+ this.options.disabled = disabled;
+ },
+
+ _setupEvents: function( event ) {
+ var events = {
+ click: function( event ) {
+ event.preventDefault();
+ }
+ };
+ if ( event ) {
+ $.each( event.split(" "), function( index, eventName ) {
+ events[ eventName ] = "_eventHandler";
+ });
+ }
+
+ this._off( this.anchors.add( this.tabs ).add( this.panels ) );
+ this._on( this.anchors, events );
+ this._on( this.tabs, { keydown: "_tabKeydown" } );
+ this._on( this.panels, { keydown: "_panelKeydown" } );
+
+ this._focusable( this.tabs );
+ this._hoverable( this.tabs );
+ },
+
+ _setupHeightStyle: function( heightStyle ) {
+ var maxHeight,
+ parent = this.element.parent();
+
+ if ( heightStyle === "fill" ) {
+ maxHeight = parent.height();
+ maxHeight -= this.element.outerHeight() - this.element.height();
+
+ this.element.siblings( ":visible" ).each(function() {
+ var elem = $( this ),
+ position = elem.css( "position" );
+
+ if ( position === "absolute" || position === "fixed" ) {
+ return;
+ }
+ maxHeight -= elem.outerHeight( true );
+ });
+
+ this.element.children().not( this.panels ).each(function() {
+ maxHeight -= $( this ).outerHeight( true );
+ });
+
+ this.panels.each(function() {
+ $( this ).height( Math.max( 0, maxHeight -
+ $( this ).innerHeight() + $( this ).height() ) );
+ })
+ .css( "overflow", "auto" );
+ } else if ( heightStyle === "auto" ) {
+ maxHeight = 0;
+ this.panels.each(function() {
+ maxHeight = Math.max( maxHeight, $( this ).height( "" ).height() );
+ }).height( maxHeight );
+ }
+ },
+
+ _eventHandler: function( event ) {
+ var options = this.options,
+ active = this.active,
+ anchor = $( event.currentTarget ),
+ tab = anchor.closest( "li" ),
+ clickedIsActive = tab[ 0 ] === active[ 0 ],
+ collapsing = clickedIsActive && options.collapsible,
+ toShow = collapsing ? $() : this._getPanelForTab( tab ),
+ toHide = !active.length ? $() : this._getPanelForTab( active ),
+ eventData = {
+ oldTab: active,
+ oldPanel: toHide,
+ newTab: collapsing ? $() : tab,
+ newPanel: toShow
+ };
+
+ event.preventDefault();
+
+ if ( tab.hasClass( "ui-state-disabled" ) ||
+ // tab is already loading
+ tab.hasClass( "ui-tabs-loading" ) ||
+ // can't switch durning an animation
+ this.running ||
+ // click on active header, but not collapsible
+ ( clickedIsActive && !options.collapsible ) ||
+ // allow canceling activation
+ ( this._trigger( "beforeActivate", event, eventData ) === false ) ) {
+ return;
+ }
+
+ options.active = collapsing ? false : this.tabs.index( tab );
+
+ this.active = clickedIsActive ? $() : tab;
+ if ( this.xhr ) {
+ this.xhr.abort();
+ }
+
+ if ( !toHide.length && !toShow.length ) {
+ $.error( "jQuery UI Tabs: Mismatching fragment identifier." );
+ }
+
+ if ( toShow.length ) {
+ this.load( this.tabs.index( tab ), event );
+ }
+ this._toggle( event, eventData );
+ },
+
+ // handles show/hide for selecting tabs
+ _toggle: function( event, eventData ) {
+ var that = this,
+ toShow = eventData.newPanel,
+ toHide = eventData.oldPanel;
+
+ this.running = true;
+
+ function complete() {
+ that.running = false;
+ that._trigger( "activate", event, eventData );
+ }
+
+ function show() {
+ eventData.newTab.closest( "li" ).addClass( "ui-tabs-active ui-state-active" );
+
+ if ( toShow.length && that.options.show ) {
+ that._show( toShow, that.options.show, complete );
+ } else {
+ toShow.show();
+ complete();
+ }
+ }
+
+ // start out by hiding, then showing, then completing
+ if ( toHide.length && this.options.hide ) {
+ this._hide( toHide, this.options.hide, function() {
+ eventData.oldTab.closest( "li" ).removeClass( "ui-tabs-active ui-state-active" );
+ show();
+ });
+ } else {
+ eventData.oldTab.closest( "li" ).removeClass( "ui-tabs-active ui-state-active" );
+ toHide.hide();
+ show();
+ }
+
+ toHide.attr({
+ "aria-expanded": "false",
+ "aria-hidden": "true"
+ });
+ eventData.oldTab.attr( "aria-selected", "false" );
+ // If we're switching tabs, remove the old tab from the tab order.
+ // If we're opening from collapsed state, remove the previous tab from the tab order.
+ // If we're collapsing, then keep the collapsing tab in the tab order.
+ if ( toShow.length && toHide.length ) {
+ eventData.oldTab.attr( "tabIndex", -1 );
+ } else if ( toShow.length ) {
+ this.tabs.filter(function() {
+ return $( this ).attr( "tabIndex" ) === 0;
+ })
+ .attr( "tabIndex", -1 );
+ }
+
+ toShow.attr({
+ "aria-expanded": "true",
+ "aria-hidden": "false"
+ });
+ eventData.newTab.attr({
+ "aria-selected": "true",
+ tabIndex: 0
+ });
+ },
+
+ _activate: function( index ) {
+ var anchor,
+ active = this._findActive( index );
+
+ // trying to activate the already active panel
+ if ( active[ 0 ] === this.active[ 0 ] ) {
+ return;
+ }
+
+ // trying to collapse, simulate a click on the current active header
+ if ( !active.length ) {
+ active = this.active;
+ }
+
+ anchor = active.find( ".ui-tabs-anchor" )[ 0 ];
+ this._eventHandler({
+ target: anchor,
+ currentTarget: anchor,
+ preventDefault: $.noop
+ });
+ },
+
+ _findActive: function( index ) {
+ return index === false ? $() : this.tabs.eq( index );
+ },
+
+ _getIndex: function( index ) {
+ // meta-function to give users option to provide a href string instead of a numerical index.
+ if ( typeof index === "string" ) {
+ index = this.anchors.index( this.anchors.filter( "[href$='" + index + "']" ) );
+ }
+
+ return index;
+ },
+
+ _destroy: function() {
+ if ( this.xhr ) {
+ this.xhr.abort();
+ }
+
+ this.element.removeClass( "ui-tabs ui-widget ui-widget-content ui-corner-all ui-tabs-collapsible" );
+
+ this.tablist
+ .removeClass( "ui-tabs-nav ui-helper-reset ui-helper-clearfix ui-widget-header ui-corner-all" )
+ .removeAttr( "role" );
+
+ this.anchors
+ .removeClass( "ui-tabs-anchor" )
+ .removeAttr( "role" )
+ .removeAttr( "tabIndex" )
+ .removeUniqueId();
+
+ this.tabs.add( this.panels ).each(function() {
+ if ( $.data( this, "ui-tabs-destroy" ) ) {
+ $( this ).remove();
+ } else {
+ $( this )
+ .removeClass( "ui-state-default ui-state-active ui-state-disabled " +
+ "ui-corner-top ui-corner-bottom ui-widget-content ui-tabs-active ui-tabs-panel" )
+ .removeAttr( "tabIndex" )
+ .removeAttr( "aria-live" )
+ .removeAttr( "aria-busy" )
+ .removeAttr( "aria-selected" )
+ .removeAttr( "aria-labelledby" )
+ .removeAttr( "aria-hidden" )
+ .removeAttr( "aria-expanded" )
+ .removeAttr( "role" );
+ }
+ });
+
+ this.tabs.each(function() {
+ var li = $( this ),
+ prev = li.data( "ui-tabs-aria-controls" );
+ if ( prev ) {
+ li
+ .attr( "aria-controls", prev )
+ .removeData( "ui-tabs-aria-controls" );
+ } else {
+ li.removeAttr( "aria-controls" );
+ }
+ });
+
+ this.panels.show();
+
+ if ( this.options.heightStyle !== "content" ) {
+ this.panels.css( "height", "" );
+ }
+ },
+
+ enable: function( index ) {
+ var disabled = this.options.disabled;
+ if ( disabled === false ) {
+ return;
+ }
+
+ if ( index === undefined ) {
+ disabled = false;
+ } else {
+ index = this._getIndex( index );
+ if ( $.isArray( disabled ) ) {
+ disabled = $.map( disabled, function( num ) {
+ return num !== index ? num : null;
+ });
+ } else {
+ disabled = $.map( this.tabs, function( li, num ) {
+ return num !== index ? num : null;
+ });
+ }
+ }
+ this._setupDisabled( disabled );
+ },
+
+ disable: function( index ) {
+ var disabled = this.options.disabled;
+ if ( disabled === true ) {
+ return;
+ }
+
+ if ( index === undefined ) {
+ disabled = true;
+ } else {
+ index = this._getIndex( index );
+ if ( $.inArray( index, disabled ) !== -1 ) {
+ return;
+ }
+ if ( $.isArray( disabled ) ) {
+ disabled = $.merge( [ index ], disabled ).sort();
+ } else {
+ disabled = [ index ];
+ }
+ }
+ this._setupDisabled( disabled );
+ },
+
+ load: function( index, event ) {
+ index = this._getIndex( index );
+ var that = this,
+ tab = this.tabs.eq( index ),
+ anchor = tab.find( ".ui-tabs-anchor" ),
+ panel = this._getPanelForTab( tab ),
+ eventData = {
+ tab: tab,
+ panel: panel
+ };
+
+ // not remote
+ if ( isLocal( anchor[ 0 ] ) ) {
+ return;
+ }
+
+ this.xhr = $.ajax( this._ajaxSettings( anchor, event, eventData ) );
+
+ // support: jQuery <1.8
+ // jQuery <1.8 returns false if the request is canceled in beforeSend,
+ // but as of 1.8, $.ajax() always returns a jqXHR object.
+ if ( this.xhr && this.xhr.statusText !== "canceled" ) {
+ tab.addClass( "ui-tabs-loading" );
+ panel.attr( "aria-busy", "true" );
+
+ this.xhr
+ .success(function( response ) {
+ // support: jQuery <1.8
+ // http://bugs.jquery.com/ticket/11778
+ setTimeout(function() {
+ panel.html( response );
+ that._trigger( "load", event, eventData );
+ }, 1 );
+ })
+ .complete(function( jqXHR, status ) {
+ // support: jQuery <1.8
+ // http://bugs.jquery.com/ticket/11778
+ setTimeout(function() {
+ if ( status === "abort" ) {
+ that.panels.stop( false, true );
+ }
+
+ tab.removeClass( "ui-tabs-loading" );
+ panel.removeAttr( "aria-busy" );
+
+ if ( jqXHR === that.xhr ) {
+ delete that.xhr;
+ }
+ }, 1 );
+ });
+ }
+ },
+
+ _ajaxSettings: function( anchor, event, eventData ) {
+ var that = this;
+ return {
+ url: anchor.attr( "href" ),
+ beforeSend: function( jqXHR, settings ) {
+ return that._trigger( "beforeLoad", event,
+ $.extend( { jqXHR : jqXHR, ajaxSettings: settings }, eventData ) );
+ }
+ };
+ },
+
+ _getPanelForTab: function( tab ) {
+ var id = $( tab ).attr( "aria-controls" );
+ return this.element.find( this._sanitizeSelector( "#" + id ) );
+ }
+});
+
+})( jQuery );
diff --git a/debian/missing-sources/jquery-ui/jquery.ui.tooltip.js b/debian/missing-sources/jquery-ui/jquery.ui.tooltip.js
new file mode 100644
index 0000000..8ebf7b3
--- /dev/null
+++ b/debian/missing-sources/jquery-ui/jquery.ui.tooltip.js
@@ -0,0 +1,402 @@
+/*!
+ * jQuery UI Tooltip 1.10.3
+ * http://jqueryui.com
+ *
+ * Copyright 2013 jQuery Foundation and other contributors
+ * Released under the MIT license.
+ * http://jquery.org/license
+ *
+ * http://api.jqueryui.com/tooltip/
+ *
+ * Depends:
+ * jquery.ui.core.js
+ * jquery.ui.widget.js
+ * jquery.ui.position.js
+ */
+(function( $ ) {
+
+var increments = 0;
+
+function addDescribedBy( elem, id ) {
+ var describedby = (elem.attr( "aria-describedby" ) || "").split( /\s+/ );
+ describedby.push( id );
+ elem
+ .data( "ui-tooltip-id", id )
+ .attr( "aria-describedby", $.trim( describedby.join( " " ) ) );
+}
+
+function removeDescribedBy( elem ) {
+ var id = elem.data( "ui-tooltip-id" ),
+ describedby = (elem.attr( "aria-describedby" ) || "").split( /\s+/ ),
+ index = $.inArray( id, describedby );
+ if ( index !== -1 ) {
+ describedby.splice( index, 1 );
+ }
+
+ elem.removeData( "ui-tooltip-id" );
+ describedby = $.trim( describedby.join( " " ) );
+ if ( describedby ) {
+ elem.attr( "aria-describedby", describedby );
+ } else {
+ elem.removeAttr( "aria-describedby" );
+ }
+}
+
+$.widget( "ui.tooltip", {
+ version: "1.10.3",
+ options: {
+ content: function() {
+ // support: IE<9, Opera in jQuery <1.7
+ // .text() can't accept undefined, so coerce to a string
+ var title = $( this ).attr( "title" ) || "";
+ // Escape title, since we're going from an attribute to raw HTML
+ return $( "<a>" ).text( title ).html();
+ },
+ hide: true,
+ // Disabled elements have inconsistent behavior across browsers (#8661)
+ items: "[title]:not([disabled])",
+ position: {
+ my: "left top+15",
+ at: "left bottom",
+ collision: "flipfit flip"
+ },
+ show: true,
+ tooltipClass: null,
+ track: false,
+
+ // callbacks
+ close: null,
+ open: null
+ },
+
+ _create: function() {
+ this._on({
+ mouseover: "open",
+ focusin: "open"
+ });
+
+ // IDs of generated tooltips, needed for destroy
+ this.tooltips = {};
+ // IDs of parent tooltips where we removed the title attribute
+ this.parents = {};
+
+ if ( this.options.disabled ) {
+ this._disable();
+ }
+ },
+
+ _setOption: function( key, value ) {
+ var that = this;
+
+ if ( key === "disabled" ) {
+ this[ value ? "_disable" : "_enable" ]();
+ this.options[ key ] = value;
+ // disable element style changes
+ return;
+ }
+
+ this._super( key, value );
+
+ if ( key === "content" ) {
+ $.each( this.tooltips, function( id, element ) {
+ that._updateContent( element );
+ });
+ }
+ },
+
+ _disable: function() {
+ var that = this;
+
+ // close open tooltips
+ $.each( this.tooltips, function( id, element ) {
+ var event = $.Event( "blur" );
+ event.target = event.currentTarget = element[0];
+ that.close( event, true );
+ });
+
+ // remove title attributes to prevent native tooltips
+ this.element.find( this.options.items ).addBack().each(function() {
+ var element = $( this );
+ if ( element.is( "[title]" ) ) {
+ element
+ .data( "ui-tooltip-title", element.attr( "title" ) )
+ .attr( "title", "" );
+ }
+ });
+ },
+
+ _enable: function() {
+ // restore title attributes
+ this.element.find( this.options.items ).addBack().each(function() {
+ var element = $( this );
+ if ( element.data( "ui-tooltip-title" ) ) {
+ element.attr( "title", element.data( "ui-tooltip-title" ) );
+ }
+ });
+ },
+
+ open: function( event ) {
+ var that = this,
+ target = $( event ? event.target : this.element )
+ // we need closest here due to mouseover bubbling,
+ // but always pointing at the same event target
+ .closest( this.options.items );
+
+ // No element to show a tooltip for or the tooltip is already open
+ if ( !target.length || target.data( "ui-tooltip-id" ) ) {
+ return;
+ }
+
+ if ( target.attr( "title" ) ) {
+ target.data( "ui-tooltip-title", target.attr( "title" ) );
+ }
+
+ target.data( "ui-tooltip-open", true );
+
+ // kill parent tooltips, custom or native, for hover
+ if ( event && event.type === "mouseover" ) {
+ target.parents().each(function() {
+ var parent = $( this ),
+ blurEvent;
+ if ( parent.data( "ui-tooltip-open" ) ) {
+ blurEvent = $.Event( "blur" );
+ blurEvent.target = blurEvent.currentTarget = this;
+ that.close( blurEvent, true );
+ }
+ if ( parent.attr( "title" ) ) {
+ parent.uniqueId();
+ that.parents[ this.id ] = {
+ element: this,
+ title: parent.attr( "title" )
+ };
+ parent.attr( "title", "" );
+ }
+ });
+ }
+
+ this._updateContent( target, event );
+ },
+
+ _updateContent: function( target, event ) {
+ var content,
+ contentOption = this.options.content,
+ that = this,
+ eventType = event ? event.type : null;
+
+ if ( typeof contentOption === "string" ) {
+ return this._open( event, target, contentOption );
+ }
+
+ content = contentOption.call( target[0], function( response ) {
+ // ignore async response if tooltip was closed already
+ if ( !target.data( "ui-tooltip-open" ) ) {
+ return;
+ }
+ // IE may instantly serve a cached response for ajax requests
+ // delay this call to _open so the other call to _open runs first
+ that._delay(function() {
+ // jQuery creates a special event for focusin when it doesn't
+ // exist natively. To improve performance, the native event
+ // object is reused and the type is changed. Therefore, we can't
+ // rely on the type being correct after the event finished
+ // bubbling, so we set it back to the previous value. (#8740)
+ if ( event ) {
+ event.type = eventType;
+ }
+ this._open( event, target, response );
+ });
+ });
+ if ( content ) {
+ this._open( event, target, content );
+ }
+ },
+
+ _open: function( event, target, content ) {
+ var tooltip, events, delayedShow,
+ positionOption = $.extend( {}, this.options.position );
+
+ if ( !content ) {
+ return;
+ }
+
+ // Content can be updated multiple times. If the tooltip already
+ // exists, then just update the content and bail.
+ tooltip = this._find( target );
+ if ( tooltip.length ) {
+ tooltip.find( ".ui-tooltip-content" ).html( content );
+ return;
+ }
+
+ // if we have a title, clear it to prevent the native tooltip
+ // we have to check first to avoid defining a title if none exists
+ // (we don't want to cause an element to start matching [title])
+ //
+ // We use removeAttr only for key events, to allow IE to export the correct
+ // accessible attributes. For mouse events, set to empty string to avoid
+ // native tooltip showing up (happens only when removing inside mouseover).
+ if ( target.is( "[title]" ) ) {
+ if ( event && event.type === "mouseover" ) {
+ target.attr( "title", "" );
+ } else {
+ target.removeAttr( "title" );
+ }
+ }
+
+ tooltip = this._tooltip( target );
+ addDescribedBy( target, tooltip.attr( "id" ) );
+ tooltip.find( ".ui-tooltip-content" ).html( content );
+
+ function position( event ) {
+ positionOption.of = event;
+ if ( tooltip.is( ":hidden" ) ) {
+ return;
+ }
+ tooltip.position( positionOption );
+ }
+ if ( this.options.track && event && /^mouse/.test( event.type ) ) {
+ this._on( this.document, {
+ mousemove: position
+ });
+ // trigger once to override element-relative positioning
+ position( event );
+ } else {
+ tooltip.position( $.extend({
+ of: target
+ }, this.options.position ) );
+ }
+
+ tooltip.hide();
+
+ this._show( tooltip, this.options.show );
+ // Handle tracking tooltips that are shown with a delay (#8644). As soon
+ // as the tooltip is visible, position the tooltip using the most recent
+ // event.
+ if ( this.options.show && this.options.show.delay ) {
+ delayedShow = this.delayedShow = setInterval(function() {
+ if ( tooltip.is( ":visible" ) ) {
+ position( positionOption.of );
+ clearInterval( delayedShow );
+ }
+ }, $.fx.interval );
+ }
+
+ this._trigger( "open", event, { tooltip: tooltip } );
+
+ events = {
+ keyup: function( event ) {
+ if ( event.keyCode === $.ui.keyCode.ESCAPE ) {
+ var fakeEvent = $.Event(event);
+ fakeEvent.currentTarget = target[0];
+ this.close( fakeEvent, true );
+ }
+ },
+ remove: function() {
+ this._removeTooltip( tooltip );
+ }
+ };
+ if ( !event || event.type === "mouseover" ) {
+ events.mouseleave = "close";
+ }
+ if ( !event || event.type === "focusin" ) {
+ events.focusout = "close";
+ }
+ this._on( true, target, events );
+ },
+
+ close: function( event ) {
+ var that = this,
+ target = $( event ? event.currentTarget : this.element ),
+ tooltip = this._find( target );
+
+ // disabling closes the tooltip, so we need to track when we're closing
+ // to avoid an infinite loop in case the tooltip becomes disabled on close
+ if ( this.closing ) {
+ return;
+ }
+
+ // Clear the interval for delayed tracking tooltips
+ clearInterval( this.delayedShow );
+
+ // only set title if we had one before (see comment in _open())
+ if ( target.data( "ui-tooltip-title" ) ) {
+ target.attr( "title", target.data( "ui-tooltip-title" ) );
+ }
+
+ removeDescribedBy( target );
+
+ tooltip.stop( true );
+ this._hide( tooltip, this.options.hide, function() {
+ that._removeTooltip( $( this ) );
+ });
+
+ target.removeData( "ui-tooltip-open" );
+ this._off( target, "mouseleave focusout keyup" );
+ // Remove 'remove' binding only on delegated targets
+ if ( target[0] !== this.element[0] ) {
+ this._off( target, "remove" );
+ }
+ this._off( this.document, "mousemove" );
+
+ if ( event && event.type === "mouseleave" ) {
+ $.each( this.parents, function( id, parent ) {
+ $( parent.element ).attr( "title", parent.title );
+ delete that.parents[ id ];
+ });
+ }
+
+ this.closing = true;
+ this._trigger( "close", event, { tooltip: tooltip } );
+ this.closing = false;
+ },
+
+ _tooltip: function( element ) {
+ var id = "ui-tooltip-" + increments++,
+ tooltip = $( "<div>" )
+ .attr({
+ id: id,
+ role: "tooltip"
+ })
+ .addClass( "ui-tooltip ui-widget ui-corner-all ui-widget-content " +
+ ( this.options.tooltipClass || "" ) );
+ $( "<div>" )
+ .addClass( "ui-tooltip-content" )
+ .appendTo( tooltip );
+ tooltip.appendTo( this.document[0].body );
+ this.tooltips[ id ] = element;
+ return tooltip;
+ },
+
+ _find: function( target ) {
+ var id = target.data( "ui-tooltip-id" );
+ return id ? $( "#" + id ) : $();
+ },
+
+ _removeTooltip: function( tooltip ) {
+ tooltip.remove();
+ delete this.tooltips[ tooltip.attr( "id" ) ];
+ },
+
+ _destroy: function() {
+ var that = this;
+
+ // close open tooltips
+ $.each( this.tooltips, function( id, element ) {
+ // Delegate to close method to handle common cleanup
+ var event = $.Event( "blur" );
+ event.target = event.currentTarget = element[0];
+ that.close( event, true );
+
+ // Remove immediately; destroying an open tooltip doesn't use the
+ // hide animation
+ $( "#" + id ).remove();
+
+ // Restore the title
+ if ( element.data( "ui-tooltip-title" ) ) {
+ element.attr( "title", element.data( "ui-tooltip-title" ) );
+ element.removeData( "ui-tooltip-title" );
+ }
+ });
+ }
+});
+
+}( jQuery ) );
diff --git a/debian/missing-sources/jquery-ui/jquery.ui.widget.js b/debian/missing-sources/jquery-ui/jquery.ui.widget.js
new file mode 100644
index 0000000..916a6ad
--- /dev/null
+++ b/debian/missing-sources/jquery-ui/jquery.ui.widget.js
@@ -0,0 +1,521 @@
+/*!
+ * jQuery UI Widget 1.10.3
+ * http://jqueryui.com
+ *
+ * Copyright 2013 jQuery Foundation and other contributors
+ * Released under the MIT license.
+ * http://jquery.org/license
+ *
+ * http://api.jqueryui.com/jQuery.widget/
+ */
+(function( $, undefined ) {
+
+var uuid = 0,
+ slice = Array.prototype.slice,
+ _cleanData = $.cleanData;
+$.cleanData = function( elems ) {
+ for ( var i = 0, elem; (elem = elems[i]) != null; i++ ) {
+ try {
+ $( elem ).triggerHandler( "remove" );
+ // http://bugs.jquery.com/ticket/8235
+ } catch( e ) {}
+ }
+ _cleanData( elems );
+};
+
+$.widget = function( name, base, prototype ) {
+ var fullName, existingConstructor, constructor, basePrototype,
+ // proxiedPrototype allows the provided prototype to remain unmodified
+ // so that it can be used as a mixin for multiple widgets (#8876)
+ proxiedPrototype = {},
+ namespace = name.split( "." )[ 0 ];
+
+ name = name.split( "." )[ 1 ];
+ fullName = namespace + "-" + name;
+
+ if ( !prototype ) {
+ prototype = base;
+ base = $.Widget;
+ }
+
+ // create selector for plugin
+ $.expr[ ":" ][ fullName.toLowerCase() ] = function( elem ) {
+ return !!$.data( elem, fullName );
+ };
+
+ $[ namespace ] = $[ namespace ] || {};
+ existingConstructor = $[ namespace ][ name ];
+ constructor = $[ namespace ][ name ] = function( options, element ) {
+ // allow instantiation without "new" keyword
+ if ( !this._createWidget ) {
+ return new constructor( options, element );
+ }
+
+ // allow instantiation without initializing for simple inheritance
+ // must use "new" keyword (the code above always passes args)
+ if ( arguments.length ) {
+ this._createWidget( options, element );
+ }
+ };
+ // extend with the existing constructor to carry over any static properties
+ $.extend( constructor, existingConstructor, {
+ version: prototype.version,
+ // copy the object used to create the prototype in case we need to
+ // redefine the widget later
+ _proto: $.extend( {}, prototype ),
+ // track widgets that inherit from this widget in case this widget is
+ // redefined after a widget inherits from it
+ _childConstructors: []
+ });
+
+ basePrototype = new base();
+ // we need to make the options hash a property directly on the new instance
+ // otherwise we'll modify the options hash on the prototype that we're
+ // inheriting from
+ basePrototype.options = $.widget.extend( {}, basePrototype.options );
+ $.each( prototype, function( prop, value ) {
+ if ( !$.isFunction( value ) ) {
+ proxiedPrototype[ prop ] = value;
+ return;
+ }
+ proxiedPrototype[ prop ] = (function() {
+ var _super = function() {
+ return base.prototype[ prop ].apply( this, arguments );
+ },
+ _superApply = function( args ) {
+ return base.prototype[ prop ].apply( this, args );
+ };
+ return function() {
+ var __super = this._super,
+ __superApply = this._superApply,
+ returnValue;
+
+ this._super = _super;
+ this._superApply = _superApply;
+
+ returnValue = value.apply( this, arguments );
+
+ this._super = __super;
+ this._superApply = __superApply;
+
+ return returnValue;
+ };
+ })();
+ });
+ constructor.prototype = $.widget.extend( basePrototype, {
+ // TODO: remove support for widgetEventPrefix
+ // always use the name + a colon as the prefix, e.g., draggable:start
+ // don't prefix for widgets that aren't DOM-based
+ widgetEventPrefix: existingConstructor ? basePrototype.widgetEventPrefix : name
+ }, proxiedPrototype, {
+ constructor: constructor,
+ namespace: namespace,
+ widgetName: name,
+ widgetFullName: fullName
+ });
+
+ // If this widget is being redefined then we need to find all widgets that
+ // are inheriting from it and redefine all of them so that they inherit from
+ // the new version of this widget. We're essentially trying to replace one
+ // level in the prototype chain.
+ if ( existingConstructor ) {
+ $.each( existingConstructor._childConstructors, function( i, child ) {
+ var childPrototype = child.prototype;
+
+ // redefine the child widget using the same prototype that was
+ // originally used, but inherit from the new version of the base
+ $.widget( childPrototype.namespace + "." + childPrototype.widgetName, constructor, child._proto );
+ });
+ // remove the list of existing child constructors from the old constructor
+ // so the old child constructors can be garbage collected
+ delete existingConstructor._childConstructors;
+ } else {
+ base._childConstructors.push( constructor );
+ }
+
+ $.widget.bridge( name, constructor );
+};
+
+$.widget.extend = function( target ) {
+ var input = slice.call( arguments, 1 ),
+ inputIndex = 0,
+ inputLength = input.length,
+ key,
+ value;
+ for ( ; inputIndex < inputLength; inputIndex++ ) {
+ for ( key in input[ inputIndex ] ) {
+ value = input[ inputIndex ][ key ];
+ if ( input[ inputIndex ].hasOwnProperty( key ) && value !== undefined ) {
+ // Clone objects
+ if ( $.isPlainObject( value ) ) {
+ target[ key ] = $.isPlainObject( target[ key ] ) ?
+ $.widget.extend( {}, target[ key ], value ) :
+ // Don't extend strings, arrays, etc. with objects
+ $.widget.extend( {}, value );
+ // Copy everything else by reference
+ } else {
+ target[ key ] = value;
+ }
+ }
+ }
+ }
+ return target;
+};
+
+$.widget.bridge = function( name, object ) {
+ var fullName = object.prototype.widgetFullName || name;
+ $.fn[ name ] = function( options ) {
+ var isMethodCall = typeof options === "string",
+ args = slice.call( arguments, 1 ),
+ returnValue = this;
+
+ // allow multiple hashes to be passed on init
+ options = !isMethodCall && args.length ?
+ $.widget.extend.apply( null, [ options ].concat(args) ) :
+ options;
+
+ if ( isMethodCall ) {
+ this.each(function() {
+ var methodValue,
+ instance = $.data( this, fullName );
+ if ( !instance ) {
+ return $.error( "cannot call methods on " + name + " prior to initialization; " +
+ "attempted to call method '" + options + "'" );
+ }
+ if ( !$.isFunction( instance[options] ) || options.charAt( 0 ) === "_" ) {
+ return $.error( "no such method '" + options + "' for " + name + " widget instance" );
+ }
+ methodValue = instance[ options ].apply( instance, args );
+ if ( methodValue !== instance && methodValue !== undefined ) {
+ returnValue = methodValue && methodValue.jquery ?
+ returnValue.pushStack( methodValue.get() ) :
+ methodValue;
+ return false;
+ }
+ });
+ } else {
+ this.each(function() {
+ var instance = $.data( this, fullName );
+ if ( instance ) {
+ instance.option( options || {} )._init();
+ } else {
+ $.data( this, fullName, new object( options, this ) );
+ }
+ });
+ }
+
+ return returnValue;
+ };
+};
+
+$.Widget = function( /* options, element */ ) {};
+$.Widget._childConstructors = [];
+
+$.Widget.prototype = {
+ widgetName: "widget",
+ widgetEventPrefix: "",
+ defaultElement: "<div>",
+ options: {
+ disabled: false,
+
+ // callbacks
+ create: null
+ },
+ _createWidget: function( options, element ) {
+ element = $( element || this.defaultElement || this )[ 0 ];
+ this.element = $( element );
+ this.uuid = uuid++;
+ this.eventNamespace = "." + this.widgetName + this.uuid;
+ this.options = $.widget.extend( {},
+ this.options,
+ this._getCreateOptions(),
+ options );
+
+ this.bindings = $();
+ this.hoverable = $();
+ this.focusable = $();
+
+ if ( element !== this ) {
+ $.data( element, this.widgetFullName, this );
+ this._on( true, this.element, {
+ remove: function( event ) {
+ if ( event.target === element ) {
+ this.destroy();
+ }
+ }
+ });
+ this.document = $( element.style ?
+ // element within the document
+ element.ownerDocument :
+ // element is window or document
+ element.document || element );
+ this.window = $( this.document[0].defaultView || this.document[0].parentWindow );
+ }
+
+ this._create();
+ this._trigger( "create", null, this._getCreateEventData() );
+ this._init();
+ },
+ _getCreateOptions: $.noop,
+ _getCreateEventData: $.noop,
+ _create: $.noop,
+ _init: $.noop,
+
+ destroy: function() {
+ this._destroy();
+ // we can probably remove the unbind calls in 2.0
+ // all event bindings should go through this._on()
+ this.element
+ .unbind( this.eventNamespace )
+ // 1.9 BC for #7810
+ // TODO remove dual storage
+ .removeData( this.widgetName )
+ .removeData( this.widgetFullName )
+ // support: jquery <1.6.3
+ // http://bugs.jquery.com/ticket/9413
+ .removeData( $.camelCase( this.widgetFullName ) );
+ this.widget()
+ .unbind( this.eventNamespace )
+ .removeAttr( "aria-disabled" )
+ .removeClass(
+ this.widgetFullName + "-disabled " +
+ "ui-state-disabled" );
+
+ // clean up events and states
+ this.bindings.unbind( this.eventNamespace );
+ this.hoverable.removeClass( "ui-state-hover" );
+ this.focusable.removeClass( "ui-state-focus" );
+ },
+ _destroy: $.noop,
+
+ widget: function() {
+ return this.element;
+ },
+
+ option: function( key, value ) {
+ var options = key,
+ parts,
+ curOption,
+ i;
+
+ if ( arguments.length === 0 ) {
+ // don't return a reference to the internal hash
+ return $.widget.extend( {}, this.options );
+ }
+
+ if ( typeof key === "string" ) {
+ // handle nested keys, e.g., "foo.bar" => { foo: { bar: ___ } }
+ options = {};
+ parts = key.split( "." );
+ key = parts.shift();
+ if ( parts.length ) {
+ curOption = options[ key ] = $.widget.extend( {}, this.options[ key ] );
+ for ( i = 0; i < parts.length - 1; i++ ) {
+ curOption[ parts[ i ] ] = curOption[ parts[ i ] ] || {};
+ curOption = curOption[ parts[ i ] ];
+ }
+ key = parts.pop();
+ if ( value === undefined ) {
+ return curOption[ key ] === undefined ? null : curOption[ key ];
+ }
+ curOption[ key ] = value;
+ } else {
+ if ( value === undefined ) {
+ return this.options[ key ] === undefined ? null : this.options[ key ];
+ }
+ options[ key ] = value;
+ }
+ }
+
+ this._setOptions( options );
+
+ return this;
+ },
+ _setOptions: function( options ) {
+ var key;
+
+ for ( key in options ) {
+ this._setOption( key, options[ key ] );
+ }
+
+ return this;
+ },
+ _setOption: function( key, value ) {
+ this.options[ key ] = value;
+
+ if ( key === "disabled" ) {
+ this.widget()
+ .toggleClass( this.widgetFullName + "-disabled ui-state-disabled", !!value )
+ .attr( "aria-disabled", value );
+ this.hoverable.removeClass( "ui-state-hover" );
+ this.focusable.removeClass( "ui-state-focus" );
+ }
+
+ return this;
+ },
+
+ enable: function() {
+ return this._setOption( "disabled", false );
+ },
+ disable: function() {
+ return this._setOption( "disabled", true );
+ },
+
+ _on: function( suppressDisabledCheck, element, handlers ) {
+ var delegateElement,
+ instance = this;
+
+ // no suppressDisabledCheck flag, shuffle arguments
+ if ( typeof suppressDisabledCheck !== "boolean" ) {
+ handlers = element;
+ element = suppressDisabledCheck;
+ suppressDisabledCheck = false;
+ }
+
+ // no element argument, shuffle and use this.element
+ if ( !handlers ) {
+ handlers = element;
+ element = this.element;
+ delegateElement = this.widget();
+ } else {
+ // accept selectors, DOM elements
+ element = delegateElement = $( element );
+ this.bindings = this.bindings.add( element );
+ }
+
+ $.each( handlers, function( event, handler ) {
+ function handlerProxy() {
+ // allow widgets to customize the disabled handling
+ // - disabled as an array instead of boolean
+ // - disabled class as method for disabling individual parts
+ if ( !suppressDisabledCheck &&
+ ( instance.options.disabled === true ||
+ $( this ).hasClass( "ui-state-disabled" ) ) ) {
+ return;
+ }
+ return ( typeof handler === "string" ? instance[ handler ] : handler )
+ .apply( instance, arguments );
+ }
+
+ // copy the guid so direct unbinding works
+ if ( typeof handler !== "string" ) {
+ handlerProxy.guid = handler.guid =
+ handler.guid || handlerProxy.guid || $.guid++;
+ }
+
+ var match = event.match( /^(\w+)\s*(.*)$/ ),
+ eventName = match[1] + instance.eventNamespace,
+ selector = match[2];
+ if ( selector ) {
+ delegateElement.delegate( selector, eventName, handlerProxy );
+ } else {
+ element.bind( eventName, handlerProxy );
+ }
+ });
+ },
+
+ _off: function( element, eventName ) {
+ eventName = (eventName || "").split( " " ).join( this.eventNamespace + " " ) + this.eventNamespace;
+ element.unbind( eventName ).undelegate( eventName );
+ },
+
+ _delay: function( handler, delay ) {
+ function handlerProxy() {
+ return ( typeof handler === "string" ? instance[ handler ] : handler )
+ .apply( instance, arguments );
+ }
+ var instance = this;
+ return setTimeout( handlerProxy, delay || 0 );
+ },
+
+ _hoverable: function( element ) {
+ this.hoverable = this.hoverable.add( element );
+ this._on( element, {
+ mouseenter: function( event ) {
+ $( event.currentTarget ).addClass( "ui-state-hover" );
+ },
+ mouseleave: function( event ) {
+ $( event.currentTarget ).removeClass( "ui-state-hover" );
+ }
+ });
+ },
+
+ _focusable: function( element ) {
+ this.focusable = this.focusable.add( element );
+ this._on( element, {
+ focusin: function( event ) {
+ $( event.currentTarget ).addClass( "ui-state-focus" );
+ },
+ focusout: function( event ) {
+ $( event.currentTarget ).removeClass( "ui-state-focus" );
+ }
+ });
+ },
+
+ _trigger: function( type, event, data ) {
+ var prop, orig,
+ callback = this.options[ type ];
+
+ data = data || {};
+ event = $.Event( event );
+ event.type = ( type === this.widgetEventPrefix ?
+ type :
+ this.widgetEventPrefix + type ).toLowerCase();
+ // the original event may come from any element
+ // so we need to reset the target on the new event
+ event.target = this.element[ 0 ];
+
+ // copy original event properties over to the new event
+ orig = event.originalEvent;
+ if ( orig ) {
+ for ( prop in orig ) {
+ if ( !( prop in event ) ) {
+ event[ prop ] = orig[ prop ];
+ }
+ }
+ }
+
+ this.element.trigger( event, data );
+ return !( $.isFunction( callback ) &&
+ callback.apply( this.element[0], [ event ].concat( data ) ) === false ||
+ event.isDefaultPrevented() );
+ }
+};
+
+$.each( { show: "fadeIn", hide: "fadeOut" }, function( method, defaultEffect ) {
+ $.Widget.prototype[ "_" + method ] = function( element, options, callback ) {
+ if ( typeof options === "string" ) {
+ options = { effect: options };
+ }
+ var hasOptions,
+ effectName = !options ?
+ method :
+ options === true || typeof options === "number" ?
+ defaultEffect :
+ options.effect || defaultEffect;
+ options = options || {};
+ if ( typeof options === "number" ) {
+ options = { duration: options };
+ }
+ hasOptions = !$.isEmptyObject( options );
+ options.complete = callback;
+ if ( options.delay ) {
+ element.delay( options.delay );
+ }
+ if ( hasOptions && $.effects && $.effects.effect[ effectName ] ) {
+ element[ method ]( options );
+ } else if ( effectName !== method && element[ effectName ] ) {
+ element[ effectName ]( options.duration, options.easing, callback );
+ } else {
+ element.queue(function( next ) {
+ $( this )[ method ]();
+ if ( callback ) {
+ callback.call( element[ 0 ] );
+ }
+ next();
+ });
+ }
+ };
+});
+
+})( jQuery );
diff --git a/debian/missing-sources/jquery.color.js b/debian/missing-sources/jquery.color.js
new file mode 100644
index 0000000..4a0c0c9
--- /dev/null
+++ b/debian/missing-sources/jquery.color.js
@@ -0,0 +1,663 @@
+/*!
+ * jQuery Color Animations v2.1.1
+ * https://github.com/jquery/jquery-color
+ *
+ * Copyright 2012 jQuery Foundation and other contributors
+ * Released under the MIT license.
+ * http://jquery.org/license
+ *
+ * Date: Sun Oct 28 15:08:06 2012 -0400
+ */
+(function( jQuery, undefined ) {
+
+ var stepHooks = "backgroundColor borderBottomColor borderLeftColor borderRightColor borderTopColor color columnRuleColor outlineColor textDecorationColor textEmphasisColor",
+
+ // plusequals test for += 100 -= 100
+ rplusequals = /^([\-+])=\s*(\d+\.?\d*)/,
+ // a set of RE's that can match strings and generate color tuples.
+ stringParsers = [{
+ re: /rgba?\(\s*(\d{1,3})\s*,\s*(\d{1,3})\s*,\s*(\d{1,3})\s*(?:,\s*(\d?(?:\.\d+)?)\s*)?\)/,
+ parse: function( execResult ) {
+ return [
+ execResult[ 1 ],
+ execResult[ 2 ],
+ execResult[ 3 ],
+ execResult[ 4 ]
+ ];
+ }
+ }, {
+ re: /rgba?\(\s*(\d+(?:\.\d+)?)\%\s*,\s*(\d+(?:\.\d+)?)\%\s*,\s*(\d+(?:\.\d+)?)\%\s*(?:,\s*(\d?(?:\.\d+)?)\s*)?\)/,
+ parse: function( execResult ) {
+ return [
+ execResult[ 1 ] * 2.55,
+ execResult[ 2 ] * 2.55,
+ execResult[ 3 ] * 2.55,
+ execResult[ 4 ]
+ ];
+ }
+ }, {
+ // this regex ignores A-F because it's compared against an already lowercased string
+ re: /#([a-f0-9]{2})([a-f0-9]{2})([a-f0-9]{2})/,
+ parse: function( execResult ) {
+ return [
+ parseInt( execResult[ 1 ], 16 ),
+ parseInt( execResult[ 2 ], 16 ),
+ parseInt( execResult[ 3 ], 16 )
+ ];
+ }
+ }, {
+ // this regex ignores A-F because it's compared against an already lowercased string
+ re: /#([a-f0-9])([a-f0-9])([a-f0-9])/,
+ parse: function( execResult ) {
+ return [
+ parseInt( execResult[ 1 ] + execResult[ 1 ], 16 ),
+ parseInt( execResult[ 2 ] + execResult[ 2 ], 16 ),
+ parseInt( execResult[ 3 ] + execResult[ 3 ], 16 )
+ ];
+ }
+ }, {
+ re: /hsla?\(\s*(\d+(?:\.\d+)?)\s*,\s*(\d+(?:\.\d+)?)\%\s*,\s*(\d+(?:\.\d+)?)\%\s*(?:,\s*(\d?(?:\.\d+)?)\s*)?\)/,
+ space: "hsla",
+ parse: function( execResult ) {
+ return [
+ execResult[ 1 ],
+ execResult[ 2 ] / 100,
+ execResult[ 3 ] / 100,
+ execResult[ 4 ]
+ ];
+ }
+ }],
+
+ // jQuery.Color( )
+ color = jQuery.Color = function( color, green, blue, alpha ) {
+ return new jQuery.Color.fn.parse( color, green, blue, alpha );
+ },
+ spaces = {
+ rgba: {
+ props: {
+ red: {
+ idx: 0,
+ type: "byte"
+ },
+ green: {
+ idx: 1,
+ type: "byte"
+ },
+ blue: {
+ idx: 2,
+ type: "byte"
+ }
+ }
+ },
+
+ hsla: {
+ props: {
+ hue: {
+ idx: 0,
+ type: "degrees"
+ },
+ saturation: {
+ idx: 1,
+ type: "percent"
+ },
+ lightness: {
+ idx: 2,
+ type: "percent"
+ }
+ }
+ }
+ },
+ propTypes = {
+ "byte": {
+ floor: true,
+ max: 255
+ },
+ "percent": {
+ max: 1
+ },
+ "degrees": {
+ mod: 360,
+ floor: true
+ }
+ },
+ support = color.support = {},
+
+ // element for support tests
+ supportElem = jQuery( "<p>" )[ 0 ],
+
+ // colors = jQuery.Color.names
+ colors,
+
+ // local aliases of functions called often
+ each = jQuery.each;
+
+// determine rgba support immediately
+supportElem.style.cssText = "background-color:rgba(1,1,1,.5)";
+support.rgba = supportElem.style.backgroundColor.indexOf( "rgba" ) > -1;
+
+// define cache name and alpha properties
+// for rgba and hsla spaces
+each( spaces, function( spaceName, space ) {
+ space.cache = "_" + spaceName;
+ space.props.alpha = {
+ idx: 3,
+ type: "percent",
+ def: 1
+ };
+});
+
+function clamp( value, prop, allowEmpty ) {
+ var type = propTypes[ prop.type ] || {};
+
+ if ( value == null ) {
+ return (allowEmpty || !prop.def) ? null : prop.def;
+ }
+
+ // ~~ is an short way of doing floor for positive numbers
+ value = type.floor ? ~~value : parseFloat( value );
+
+ // IE will pass in empty strings as value for alpha,
+ // which will hit this case
+ if ( isNaN( value ) ) {
+ return prop.def;
+ }
+
+ if ( type.mod ) {
+ // we add mod before modding to make sure that negatives values
+ // get converted properly: -10 -> 350
+ return (value + type.mod) % type.mod;
+ }
+
+ // for now all property types without mod have min and max
+ return 0 > value ? 0 : type.max < value ? type.max : value;
+}
+
+function stringParse( string ) {
+ var inst = color(),
+ rgba = inst._rgba = [];
+
+ string = string.toLowerCase();
+
+ each( stringParsers, function( i, parser ) {
+ var parsed,
+ match = parser.re.exec( string ),
+ values = match && parser.parse( match ),
+ spaceName = parser.space || "rgba";
+
+ if ( values ) {
+ parsed = inst[ spaceName ]( values );
+
+ // if this was an rgba parse the assignment might happen twice
+ // oh well....
+ inst[ spaces[ spaceName ].cache ] = parsed[ spaces[ spaceName ].cache ];
+ rgba = inst._rgba = parsed._rgba;
+
+ // exit each( stringParsers ) here because we matched
+ return false;
+ }
+ });
+
+ // Found a stringParser that handled it
+ if ( rgba.length ) {
+
+ // if this came from a parsed string, force "transparent" when alpha is 0
+ // chrome, (and maybe others) return "transparent" as rgba(0,0,0,0)
+ if ( rgba.join() === "0,0,0,0" ) {
+ jQuery.extend( rgba, colors.transparent );
+ }
+ return inst;
+ }
+
+ // named colors
+ return colors[ string ];
+}
+
+color.fn = jQuery.extend( color.prototype, {
+ parse: function( red, green, blue, alpha ) {
+ if ( red === undefined ) {
+ this._rgba = [ null, null, null, null ];
+ return this;
+ }
+ if ( red.jquery || red.nodeType ) {
+ red = jQuery( red ).css( green );
+ green = undefined;
+ }
+
+ var inst = this,
+ type = jQuery.type( red ),
+ rgba = this._rgba = [];
+
+ // more than 1 argument specified - assume ( red, green, blue, alpha )
+ if ( green !== undefined ) {
+ red = [ red, green, blue, alpha ];
+ type = "array";
+ }
+
+ if ( type === "string" ) {
+ return this.parse( stringParse( red ) || colors._default );
+ }
+
+ if ( type === "array" ) {
+ each( spaces.rgba.props, function( key, prop ) {
+ rgba[ prop.idx ] = clamp( red[ prop.idx ], prop );
+ });
+ return this;
+ }
+
+ if ( type === "object" ) {
+ if ( red instanceof color ) {
+ each( spaces, function( spaceName, space ) {
+ if ( red[ space.cache ] ) {
+ inst[ space.cache ] = red[ space.cache ].slice();
+ }
+ });
+ } else {
+ each( spaces, function( spaceName, space ) {
+ var cache = space.cache;
+ each( space.props, function( key, prop ) {
+
+ // if the cache doesn't exist, and we know how to convert
+ if ( !inst[ cache ] && space.to ) {
+
+ // if the value was null, we don't need to copy it
+ // if the key was alpha, we don't need to copy it either
+ if ( key === "alpha" || red[ key ] == null ) {
+ return;
+ }
+ inst[ cache ] = space.to( inst._rgba );
+ }
+
+ // this is the only case where we allow nulls for ALL properties.
+ // call clamp with alwaysAllowEmpty
+ inst[ cache ][ prop.idx ] = clamp( red[ key ], prop, true );
+ });
+
+ // everything defined but alpha?
+ if ( inst[ cache ] && jQuery.inArray( null, inst[ cache ].slice( 0, 3 ) ) < 0 ) {
+ // use the default of 1
+ inst[ cache ][ 3 ] = 1;
+ if ( space.from ) {
+ inst._rgba = space.from( inst[ cache ] );
+ }
+ }
+ });
+ }
+ return this;
+ }
+ },
+ is: function( compare ) {
+ var is = color( compare ),
+ same = true,
+ inst = this;
+
+ each( spaces, function( _, space ) {
+ var localCache,
+ isCache = is[ space.cache ];
+ if (isCache) {
+ localCache = inst[ space.cache ] || space.to && space.to( inst._rgba ) || [];
+ each( space.props, function( _, prop ) {
+ if ( isCache[ prop.idx ] != null ) {
+ same = ( isCache[ prop.idx ] === localCache[ prop.idx ] );
+ return same;
+ }
+ });
+ }
+ return same;
+ });
+ return same;
+ },
+ _space: function() {
+ var used = [],
+ inst = this;
+ each( spaces, function( spaceName, space ) {
+ if ( inst[ space.cache ] ) {
+ used.push( spaceName );
+ }
+ });
+ return used.pop();
+ },
+ transition: function( other, distance ) {
+ var end = color( other ),
+ spaceName = end._space(),
+ space = spaces[ spaceName ],
+ startColor = this.alpha() === 0 ? color( "transparent" ) : this,
+ start = startColor[ space.cache ] || space.to( startColor._rgba ),
+ result = start.slice();
+
+ end = end[ space.cache ];
+ each( space.props, function( key, prop ) {
+ var index = prop.idx,
+ startValue = start[ index ],
+ endValue = end[ index ],
+ type = propTypes[ prop.type ] || {};
+
+ // if null, don't override start value
+ if ( endValue === null ) {
+ return;
+ }
+ // if null - use end
+ if ( startValue === null ) {
+ result[ index ] = endValue;
+ } else {
+ if ( type.mod ) {
+ if ( endValue - startValue > type.mod / 2 ) {
+ startValue += type.mod;
+ } else if ( startValue - endValue > type.mod / 2 ) {
+ startValue -= type.mod;
+ }
+ }
+ result[ index ] = clamp( ( endValue - startValue ) * distance + startValue, prop );
+ }
+ });
+ return this[ spaceName ]( result );
+ },
+ blend: function( opaque ) {
+ // if we are already opaque - return ourself
+ if ( this._rgba[ 3 ] === 1 ) {
+ return this;
+ }
+
+ var rgb = this._rgba.slice(),
+ a = rgb.pop(),
+ blend = color( opaque )._rgba;
+
+ return color( jQuery.map( rgb, function( v, i ) {
+ return ( 1 - a ) * blend[ i ] + a * v;
+ }));
+ },
+ toRgbaString: function() {
+ var prefix = "rgba(",
+ rgba = jQuery.map( this._rgba, function( v, i ) {
+ return v == null ? ( i > 2 ? 1 : 0 ) : v;
+ });
+
+ if ( rgba[ 3 ] === 1 ) {
+ rgba.pop();
+ prefix = "rgb(";
+ }
+
+ return prefix + rgba.join() + ")";
+ },
+ toHslaString: function() {
+ var prefix = "hsla(",
+ hsla = jQuery.map( this.hsla(), function( v, i ) {
+ if ( v == null ) {
+ v = i > 2 ? 1 : 0;
+ }
+
+ // catch 1 and 2
+ if ( i && i < 3 ) {
+ v = Math.round( v * 100 ) + "%";
+ }
+ return v;
+ });
+
+ if ( hsla[ 3 ] === 1 ) {
+ hsla.pop();
+ prefix = "hsl(";
+ }
+ return prefix + hsla.join() + ")";
+ },
+ toHexString: function( includeAlpha ) {
+ var rgba = this._rgba.slice(),
+ alpha = rgba.pop();
+
+ if ( includeAlpha ) {
+ rgba.push( ~~( alpha * 255 ) );
+ }
+
+ return "#" + jQuery.map( rgba, function( v ) {
+
+ // default to 0 when nulls exist
+ v = ( v || 0 ).toString( 16 );
+ return v.length === 1 ? "0" + v : v;
+ }).join("");
+ },
+ toString: function() {
+ return this._rgba[ 3 ] === 0 ? "transparent" : this.toRgbaString();
+ }
+});
+color.fn.parse.prototype = color.fn;
+
+// hsla conversions adapted from:
+// https://code.google.com/p/maashaack/source/browse/packages/graphics/trunk/src/graphics/colors/HUE2RGB.as?r=5021
+
+function hue2rgb( p, q, h ) {
+ h = ( h + 1 ) % 1;
+ if ( h * 6 < 1 ) {
+ return p + (q - p) * h * 6;
+ }
+ if ( h * 2 < 1) {
+ return q;
+ }
+ if ( h * 3 < 2 ) {
+ return p + (q - p) * ((2/3) - h) * 6;
+ }
+ return p;
+}
+
+spaces.hsla.to = function ( rgba ) {
+ if ( rgba[ 0 ] == null || rgba[ 1 ] == null || rgba[ 2 ] == null ) {
+ return [ null, null, null, rgba[ 3 ] ];
+ }
+ var r = rgba[ 0 ] / 255,
+ g = rgba[ 1 ] / 255,
+ b = rgba[ 2 ] / 255,
+ a = rgba[ 3 ],
+ max = Math.max( r, g, b ),
+ min = Math.min( r, g, b ),
+ diff = max - min,
+ add = max + min,
+ l = add * 0.5,
+ h, s;
+
+ if ( min === max ) {
+ h = 0;
+ } else if ( r === max ) {
+ h = ( 60 * ( g - b ) / diff ) + 360;
+ } else if ( g === max ) {
+ h = ( 60 * ( b - r ) / diff ) + 120;
+ } else {
+ h = ( 60 * ( r - g ) / diff ) + 240;
+ }
+
+ // chroma (diff) == 0 means greyscale which, by definition, saturation = 0%
+ // otherwise, saturation is based on the ratio of chroma (diff) to lightness (add)
+ if ( diff === 0 ) {
+ s = 0;
+ } else if ( l <= 0.5 ) {
+ s = diff / add;
+ } else {
+ s = diff / ( 2 - add );
+ }
+ return [ Math.round(h) % 360, s, l, a == null ? 1 : a ];
+};
+
+spaces.hsla.from = function ( hsla ) {
+ if ( hsla[ 0 ] == null || hsla[ 1 ] == null || hsla[ 2 ] == null ) {
+ return [ null, null, null, hsla[ 3 ] ];
+ }
+ var h = hsla[ 0 ] / 360,
+ s = hsla[ 1 ],
+ l = hsla[ 2 ],
+ a = hsla[ 3 ],
+ q = l <= 0.5 ? l * ( 1 + s ) : l + s - l * s,
+ p = 2 * l - q;
+
+ return [
+ Math.round( hue2rgb( p, q, h + ( 1 / 3 ) ) * 255 ),
+ Math.round( hue2rgb( p, q, h ) * 255 ),
+ Math.round( hue2rgb( p, q, h - ( 1 / 3 ) ) * 255 ),
+ a
+ ];
+};
+
+
+each( spaces, function( spaceName, space ) {
+ var props = space.props,
+ cache = space.cache,
+ to = space.to,
+ from = space.from;
+
+ // makes rgba() and hsla()
+ color.fn[ spaceName ] = function( value ) {
+
+ // generate a cache for this space if it doesn't exist
+ if ( to && !this[ cache ] ) {
+ this[ cache ] = to( this._rgba );
+ }
+ if ( value === undefined ) {
+ return this[ cache ].slice();
+ }
+
+ var ret,
+ type = jQuery.type( value ),
+ arr = ( type === "array" || type === "object" ) ? value : arguments,
+ local = this[ cache ].slice();
+
+ each( props, function( key, prop ) {
+ var val = arr[ type === "object" ? key : prop.idx ];
+ if ( val == null ) {
+ val = local[ prop.idx ];
+ }
+ local[ prop.idx ] = clamp( val, prop );
+ });
+
+ if ( from ) {
+ ret = color( from( local ) );
+ ret[ cache ] = local;
+ return ret;
+ } else {
+ return color( local );
+ }
+ };
+
+ // makes red() green() blue() alpha() hue() saturation() lightness()
+ each( props, function( key, prop ) {
+ // alpha is included in more than one space
+ if ( color.fn[ key ] ) {
+ return;
+ }
+ color.fn[ key ] = function( value ) {
+ var vtype = jQuery.type( value ),
+ fn = ( key === "alpha" ? ( this._hsla ? "hsla" : "rgba" ) : spaceName ),
+ local = this[ fn ](),
+ cur = local[ prop.idx ],
+ match;
+
+ if ( vtype === "undefined" ) {
+ return cur;
+ }
+
+ if ( vtype === "function" ) {
+ value = value.call( this, cur );
+ vtype = jQuery.type( value );
+ }
+ if ( value == null && prop.empty ) {
+ return this;
+ }
+ if ( vtype === "string" ) {
+ match = rplusequals.exec( value );
+ if ( match ) {
+ value = cur + parseFloat( match[ 2 ] ) * ( match[ 1 ] === "+" ? 1 : -1 );
+ }
+ }
+ local[ prop.idx ] = value;
+ return this[ fn ]( local );
+ };
+ });
+});
+
+// add cssHook and .fx.step function for each named hook.
+// accept a space separated string of properties
+color.hook = function( hook ) {
+ var hooks = hook.split( " " );
+ each( hooks, function( i, hook ) {
+ jQuery.cssHooks[ hook ] = {
+ set: function( elem, value ) {
+ var parsed, curElem,
+ backgroundColor = "";
+
+ if ( jQuery.type( value ) !== "string" || ( parsed = stringParse( value ) ) ) {
+ value = color( parsed || value );
+ if ( !support.rgba && value._rgba[ 3 ] !== 1 ) {
+ curElem = hook === "backgroundColor" ? elem.parentNode : elem;
+ while (
+ (backgroundColor === "" || backgroundColor === "transparent") &&
+ curElem && curElem.style
+ ) {
+ try {
+ backgroundColor = jQuery.css( curElem, "backgroundColor" );
+ curElem = curElem.parentNode;
+ } catch ( e ) {
+ }
+ }
+
+ value = value.blend( backgroundColor && backgroundColor !== "transparent" ?
+ backgroundColor :
+ "_default" );
+ }
+
+ value = value.toRgbaString();
+ }
+ try {
+ elem.style[ hook ] = value;
+ } catch( e ) {
+ // wrapped to prevent IE from throwing errors on "invalid" values like 'auto' or 'inherit'
+ }
+ }
+ };
+ jQuery.fx.step[ hook ] = function( fx ) {
+ if ( !fx.colorInit ) {
+ fx.start = color( fx.elem, hook );
+ fx.end = color( fx.end );
+ fx.colorInit = true;
+ }
+ jQuery.cssHooks[ hook ].set( fx.elem, fx.start.transition( fx.end, fx.pos ) );
+ };
+ });
+
+};
+
+color.hook( stepHooks );
+
+jQuery.cssHooks.borderColor = {
+ expand: function( value ) {
+ var expanded = {};
+
+ each( [ "Top", "Right", "Bottom", "Left" ], function( i, part ) {
+ expanded[ "border" + part + "Color" ] = value;
+ });
+ return expanded;
+ }
+};
+
+// Basic color names only.
+// Usage of any of the other color names requires adding yourself or including
+// jquery.color.svg-names.js.
+colors = jQuery.Color.names = {
+ // 4.1. Basic color keywords
+ aqua: "#00ffff",
+ black: "#000000",
+ blue: "#0000ff",
+ fuchsia: "#ff00ff",
+ gray: "#808080",
+ green: "#008000",
+ lime: "#00ff00",
+ maroon: "#800000",
+ navy: "#000080",
+ olive: "#808000",
+ purple: "#800080",
+ red: "#ff0000",
+ silver: "#c0c0c0",
+ teal: "#008080",
+ white: "#ffffff",
+ yellow: "#ffff00",
+
+ // 4.2.3. ‘transparent’ color keyword
+ transparent: [ null, null, null, 0 ],
+
+ _default: "#ffffff"
+};
+
+})( jQuery );
diff --git a/debian/missing-sources/jquery.js b/debian/missing-sources/jquery.js
new file mode 100644
index 0000000..c5c6482
--- /dev/null
+++ b/debian/missing-sources/jquery.js
@@ -0,0 +1,9789 @@
+/*!
+ * jQuery JavaScript Library v1.10.2
+ * http://jquery.com/
+ *
+ * Includes Sizzle.js
+ * http://sizzlejs.com/
+ *
+ * Copyright 2005, 2013 jQuery Foundation, Inc. and other contributors
+ * Released under the MIT license
+ * http://jquery.org/license
+ *
+ * Date: 2013-07-03T13:48Z
+ */
+(function( window, undefined ) {
+
+// Can't do this because several apps including ASP.NET trace
+// the stack via arguments.caller.callee and Firefox dies if
+// you try to trace through "use strict" call chains. (#13335)
+// Support: Firefox 18+
+//"use strict";
+var
+ // The deferred used on DOM ready
+ readyList,
+
+ // A central reference to the root jQuery(document)
+ rootjQuery,
+
+ // Support: IE<10
+ // For `typeof xmlNode.method` instead of `xmlNode.method !== undefined`
+ core_strundefined = typeof undefined,
+
+ // Use the correct document accordingly with window argument (sandbox)
+ location = window.location,
+ document = window.document,
+ docElem = document.documentElement,
+
+ // Map over jQuery in case of overwrite
+ _jQuery = window.jQuery,
+
+ // Map over the $ in case of overwrite
+ _$ = window.$,
+
+ // [[Class]] -> type pairs
+ class2type = {},
+
+ // List of deleted data cache ids, so we can reuse them
+ core_deletedIds = [],
+
+ core_version = "1.10.2",
+
+ // Save a reference to some core methods
+ core_concat = core_deletedIds.concat,
+ core_push = core_deletedIds.push,
+ core_slice = core_deletedIds.slice,
+ core_indexOf = core_deletedIds.indexOf,
+ core_toString = class2type.toString,
+ core_hasOwn = class2type.hasOwnProperty,
+ core_trim = core_version.trim,
+
+ // Define a local copy of jQuery
+ jQuery = function( selector, context ) {
+ // The jQuery object is actually just the init constructor 'enhanced'
+ return new jQuery.fn.init( selector, context, rootjQuery );
+ },
+
+ // Used for matching numbers
+ core_pnum = /[+-]?(?:\d*\.|)\d+(?:[eE][+-]?\d+|)/.source,
+
+ // Used for splitting on whitespace
+ core_rnotwhite = /\S+/g,
+
+ // Make sure we trim BOM and NBSP (here's looking at you, Safari 5.0 and IE)
+ rtrim = /^[\s\uFEFF\xA0]+|[\s\uFEFF\xA0]+$/g,
+
+ // A simple way to check for HTML strings
+ // Prioritize #id over <tag> to avoid XSS via location.hash (#9521)
+ // Strict HTML recognition (#11290: must start with <)
+ rquickExpr = /^(?:\s*(<[\w\W]+>)[^>]*|#([\w-]*))$/,
+
+ // Match a standalone tag
+ rsingleTag = /^<(\w+)\s*\/?>(?:<\/\1>|)$/,
+
+ // JSON RegExp
+ rvalidchars = /^[\],:{}\s]*$/,
+ rvalidbraces = /(?:^|:|,)(?:\s*\[)+/g,
+ rvalidescape = /\\(?:["\\\/bfnrt]|u[\da-fA-F]{4})/g,
+ rvalidtokens = /"[^"\\\r\n]*"|true|false|null|-?(?:\d+\.|)\d+(?:[eE][+-]?\d+|)/g,
+
+ // Matches dashed string for camelizing
+ rmsPrefix = /^-ms-/,
+ rdashAlpha = /-([\da-z])/gi,
+
+ // Used by jQuery.camelCase as callback to replace()
+ fcamelCase = function( all, letter ) {
+ return letter.toUpperCase();
+ },
+
+ // The ready event handler
+ completed = function( event ) {
+
+ // readyState === "complete" is good enough for us to call the dom ready in oldIE
+ if ( document.addEventListener || event.type === "load" || document.readyState === "complete" ) {
+ detach();
+ jQuery.ready();
+ }
+ },
+ // Clean-up method for dom ready events
+ detach = function() {
+ if ( document.addEventListener ) {
+ document.removeEventListener( "DOMContentLoaded", completed, false );
+ window.removeEventListener( "load", completed, false );
+
+ } else {
+ document.detachEvent( "onreadystatechange", completed );
+ window.detachEvent( "onload", completed );
+ }
+ };
+
+jQuery.fn = jQuery.prototype = {
+ // The current version of jQuery being used
+ jquery: core_version,
+
+ constructor: jQuery,
+ init: function( selector, context, rootjQuery ) {
+ var match, elem;
+
+ // HANDLE: $(""), $(null), $(undefined), $(false)
+ if ( !selector ) {
+ return this;
+ }
+
+ // Handle HTML strings
+ if ( typeof selector === "string" ) {
+ if ( selector.charAt(0) === "<" && selector.charAt( selector.length - 1 ) === ">" && selector.length >= 3 ) {
+ // Assume that strings that start and end with <> are HTML and skip the regex check
+ match = [ null, selector, null ];
+
+ } else {
+ match = rquickExpr.exec( selector );
+ }
+
+ // Match html or make sure no context is specified for #id
+ if ( match && (match[1] || !context) ) {
+
+ // HANDLE: $(html) -> $(array)
+ if ( match[1] ) {
+ context = context instanceof jQuery ? context[0] : context;
+
+ // scripts is true for back-compat
+ jQuery.merge( this, jQuery.parseHTML(
+ match[1],
+ context && context.nodeType ? context.ownerDocument || context : document,
+ true
+ ) );
+
+ // HANDLE: $(html, props)
+ if ( rsingleTag.test( match[1] ) && jQuery.isPlainObject( context ) ) {
+ for ( match in context ) {
+ // Properties of context are called as methods if possible
+ if ( jQuery.isFunction( this[ match ] ) ) {
+ this[ match ]( context[ match ] );
+
+ // ...and otherwise set as attributes
+ } else {
+ this.attr( match, context[ match ] );
+ }
+ }
+ }
+
+ return this;
+
+ // HANDLE: $(#id)
+ } else {
+ elem = document.getElementById( match[2] );
+
+ // Check parentNode to catch when Blackberry 4.6 returns
+ // nodes that are no longer in the document #6963
+ if ( elem && elem.parentNode ) {
+ // Handle the case where IE and Opera return items
+ // by name instead of ID
+ if ( elem.id !== match[2] ) {
+ return rootjQuery.find( selector );
+ }
+
+ // Otherwise, we inject the element directly into the jQuery object
+ this.length = 1;
+ this[0] = elem;
+ }
+
+ this.context = document;
+ this.selector = selector;
+ return this;
+ }
+
+ // HANDLE: $(expr, $(...))
+ } else if ( !context || context.jquery ) {
+ return ( context || rootjQuery ).find( selector );
+
+ // HANDLE: $(expr, context)
+ // (which is just equivalent to: $(context).find(expr)
+ } else {
+ return this.constructor( context ).find( selector );
+ }
+
+ // HANDLE: $(DOMElement)
+ } else if ( selector.nodeType ) {
+ this.context = this[0] = selector;
+ this.length = 1;
+ return this;
+
+ // HANDLE: $(function)
+ // Shortcut for document ready
+ } else if ( jQuery.isFunction( selector ) ) {
+ return rootjQuery.ready( selector );
+ }
+
+ if ( selector.selector !== undefined ) {
+ this.selector = selector.selector;
+ this.context = selector.context;
+ }
+
+ return jQuery.makeArray( selector, this );
+ },
+
+ // Start with an empty selector
+ selector: "",
+
+ // The default length of a jQuery object is 0
+ length: 0,
+
+ toArray: function() {
+ return core_slice.call( this );
+ },
+
+ // Get the Nth element in the matched element set OR
+ // Get the whole matched element set as a clean array
+ get: function( num ) {
+ return num == null ?
+
+ // Return a 'clean' array
+ this.toArray() :
+
+ // Return just the object
+ ( num < 0 ? this[ this.length + num ] : this[ num ] );
+ },
+
+ // Take an array of elements and push it onto the stack
+ // (returning the new matched element set)
+ pushStack: function( elems ) {
+
+ // Build a new jQuery matched element set
+ var ret = jQuery.merge( this.constructor(), elems );
+
+ // Add the old object onto the stack (as a reference)
+ ret.prevObject = this;
+ ret.context = this.context;
+
+ // Return the newly-formed element set
+ return ret;
+ },
+
+ // Execute a callback for every element in the matched set.
+ // (You can seed the arguments with an array of args, but this is
+ // only used internally.)
+ each: function( callback, args ) {
+ return jQuery.each( this, callback, args );
+ },
+
+ ready: function( fn ) {
+ // Add the callback
+ jQuery.ready.promise().done( fn );
+
+ return this;
+ },
+
+ slice: function() {
+ return this.pushStack( core_slice.apply( this, arguments ) );
+ },
+
+ first: function() {
+ return this.eq( 0 );
+ },
+
+ last: function() {
+ return this.eq( -1 );
+ },
+
+ eq: function( i ) {
+ var len = this.length,
+ j = +i + ( i < 0 ? len : 0 );
+ return this.pushStack( j >= 0 && j < len ? [ this[j] ] : [] );
+ },
+
+ map: function( callback ) {
+ return this.pushStack( jQuery.map(this, function( elem, i ) {
+ return callback.call( elem, i, elem );
+ }));
+ },
+
+ end: function() {
+ return this.prevObject || this.constructor(null);
+ },
+
+ // For internal use only.
+ // Behaves like an Array's method, not like a jQuery method.
+ push: core_push,
+ sort: [].sort,
+ splice: [].splice
+};
+
+// Give the init function the jQuery prototype for later instantiation
+jQuery.fn.init.prototype = jQuery.fn;
+
+jQuery.extend = jQuery.fn.extend = function() {
+ var src, copyIsArray, copy, name, options, clone,
+ target = arguments[0] || {},
+ i = 1,
+ length = arguments.length,
+ deep = false;
+
+ // Handle a deep copy situation
+ if ( typeof target === "boolean" ) {
+ deep = target;
+ target = arguments[1] || {};
+ // skip the boolean and the target
+ i = 2;
+ }
+
+ // Handle case when target is a string or something (possible in deep copy)
+ if ( typeof target !== "object" && !jQuery.isFunction(target) ) {
+ target = {};
+ }
+
+ // extend jQuery itself if only one argument is passed
+ if ( length === i ) {
+ target = this;
+ --i;
+ }
+
+ for ( ; i < length; i++ ) {
+ // Only deal with non-null/undefined values
+ if ( (options = arguments[ i ]) != null ) {
+ // Extend the base object
+ for ( name in options ) {
+ src = target[ name ];
+ copy = options[ name ];
+
+ // Prevent never-ending loop
+ if ( target === copy ) {
+ continue;
+ }
+
+ // Recurse if we're merging plain objects or arrays
+ if ( deep && copy && ( jQuery.isPlainObject(copy) || (copyIsArray = jQuery.isArray(copy)) ) ) {
+ if ( copyIsArray ) {
+ copyIsArray = false;
+ clone = src && jQuery.isArray(src) ? src : [];
+
+ } else {
+ clone = src && jQuery.isPlainObject(src) ? src : {};
+ }
+
+ // Never move original objects, clone them
+ target[ name ] = jQuery.extend( deep, clone, copy );
+
+ // Don't bring in undefined values
+ } else if ( copy !== undefined ) {
+ target[ name ] = copy;
+ }
+ }
+ }
+ }
+
+ // Return the modified object
+ return target;
+};
+
+jQuery.extend({
+ // Unique for each copy of jQuery on the page
+ // Non-digits removed to match rinlinejQuery
+ expando: "jQuery" + ( core_version + Math.random() ).replace( /\D/g, "" ),
+
+ noConflict: function( deep ) {
+ if ( window.$ === jQuery ) {
+ window.$ = _$;
+ }
+
+ if ( deep && window.jQuery === jQuery ) {
+ window.jQuery = _jQuery;
+ }
+
+ return jQuery;
+ },
+
+ // Is the DOM ready to be used? Set to true once it occurs.
+ isReady: false,
+
+ // A counter to track how many items to wait for before
+ // the ready event fires. See #6781
+ readyWait: 1,
+
+ // Hold (or release) the ready event
+ holdReady: function( hold ) {
+ if ( hold ) {
+ jQuery.readyWait++;
+ } else {
+ jQuery.ready( true );
+ }
+ },
+
+ // Handle when the DOM is ready
+ ready: function( wait ) {
+
+ // Abort if there are pending holds or we're already ready
+ if ( wait === true ? --jQuery.readyWait : jQuery.isReady ) {
+ return;
+ }
+
+ // Make sure body exists, at least, in case IE gets a little overzealous (ticket #5443).
+ if ( !document.body ) {
+ return setTimeout( jQuery.ready );
+ }
+
+ // Remember that the DOM is ready
+ jQuery.isReady = true;
+
+ // If a normal DOM Ready event fired, decrement, and wait if need be
+ if ( wait !== true && --jQuery.readyWait > 0 ) {
+ return;
+ }
+
+ // If there are functions bound, to execute
+ readyList.resolveWith( document, [ jQuery ] );
+
+ // Trigger any bound ready events
+ if ( jQuery.fn.trigger ) {
+ jQuery( document ).trigger("ready").off("ready");
+ }
+ },
+
+ // See test/unit/core.js for details concerning isFunction.
+ // Since version 1.3, DOM methods and functions like alert
+ // aren't supported. They return false on IE (#2968).
+ isFunction: function( obj ) {
+ return jQuery.type(obj) === "function";
+ },
+
+ isArray: Array.isArray || function( obj ) {
+ return jQuery.type(obj) === "array";
+ },
+
+ isWindow: function( obj ) {
+ /* jshint eqeqeq: false */
+ return obj != null && obj == obj.window;
+ },
+
+ isNumeric: function( obj ) {
+ return !isNaN( parseFloat(obj) ) && isFinite( obj );
+ },
+
+ type: function( obj ) {
+ if ( obj == null ) {
+ return String( obj );
+ }
+ return typeof obj === "object" || typeof obj === "function" ?
+ class2type[ core_toString.call(obj) ] || "object" :
+ typeof obj;
+ },
+
+ isPlainObject: function( obj ) {
+ var key;
+
+ // Must be an Object.
+ // Because of IE, we also have to check the presence of the constructor property.
+ // Make sure that DOM nodes and window objects don't pass through, as well
+ if ( !obj || jQuery.type(obj) !== "object" || obj.nodeType || jQuery.isWindow( obj ) ) {
+ return false;
+ }
+
+ try {
+ // Not own constructor property must be Object
+ if ( obj.constructor &&
+ !core_hasOwn.call(obj, "constructor") &&
+ !core_hasOwn.call(obj.constructor.prototype, "isPrototypeOf") ) {
+ return false;
+ }
+ } catch ( e ) {
+ // IE8,9 Will throw exceptions on certain host objects #9897
+ return false;
+ }
+
+ // Support: IE<9
+ // Handle iteration over inherited properties before own properties.
+ if ( jQuery.support.ownLast ) {
+ for ( key in obj ) {
+ return core_hasOwn.call( obj, key );
+ }
+ }
+
+ // Own properties are enumerated firstly, so to speed up,
+ // if last one is own, then all properties are own.
+ for ( key in obj ) {}
+
+ return key === undefined || core_hasOwn.call( obj, key );
+ },
+
+ isEmptyObject: function( obj ) {
+ var name;
+ for ( name in obj ) {
+ return false;
+ }
+ return true;
+ },
+
+ error: function( msg ) {
+ throw new Error( msg );
+ },
+
+ // data: string of html
+ // context (optional): If specified, the fragment will be created in this context, defaults to document
+ // keepScripts (optional): If true, will include scripts passed in the html string
+ parseHTML: function( data, context, keepScripts ) {
+ if ( !data || typeof data !== "string" ) {
+ return null;
+ }
+ if ( typeof context === "boolean" ) {
+ keepScripts = context;
+ context = false;
+ }
+ context = context || document;
+
+ var parsed = rsingleTag.exec( data ),
+ scripts = !keepScripts && [];
+
+ // Single tag
+ if ( parsed ) {
+ return [ context.createElement( parsed[1] ) ];
+ }
+
+ parsed = jQuery.buildFragment( [ data ], context, scripts );
+ if ( scripts ) {
+ jQuery( scripts ).remove();
+ }
+ return jQuery.merge( [], parsed.childNodes );
+ },
+
+ parseJSON: function( data ) {
+ // Attempt to parse using the native JSON parser first
+ if ( window.JSON && window.JSON.parse ) {
+ return window.JSON.parse( data );
+ }
+
+ if ( data === null ) {
+ return data;
+ }
+
+ if ( typeof data === "string" ) {
+
+ // Make sure leading/trailing whitespace is removed (IE can't handle it)
+ data = jQuery.trim( data );
+
+ if ( data ) {
+ // Make sure the incoming data is actual JSON
+ // Logic borrowed from http://json.org/json2.js
+ if ( rvalidchars.test( data.replace( rvalidescape, "@" )
+ .replace( rvalidtokens, "]" )
+ .replace( rvalidbraces, "")) ) {
+
+ return ( new Function( "return " + data ) )();
+ }
+ }
+ }
+
+ jQuery.error( "Invalid JSON: " + data );
+ },
+
+ // Cross-browser xml parsing
+ parseXML: function( data ) {
+ var xml, tmp;
+ if ( !data || typeof data !== "string" ) {
+ return null;
+ }
+ try {
+ if ( window.DOMParser ) { // Standard
+ tmp = new DOMParser();
+ xml = tmp.parseFromString( data , "text/xml" );
+ } else { // IE
+ xml = new ActiveXObject( "Microsoft.XMLDOM" );
+ xml.async = "false";
+ xml.loadXML( data );
+ }
+ } catch( e ) {
+ xml = undefined;
+ }
+ if ( !xml || !xml.documentElement || xml.getElementsByTagName( "parsererror" ).length ) {
+ jQuery.error( "Invalid XML: " + data );
+ }
+ return xml;
+ },
+
+ noop: function() {},
+
+ // Evaluates a script in a global context
+ // Workarounds based on findings by Jim Driscoll
+ // http://weblogs.java.net/blog/driscoll/archive/2009/09/08/eval-javascript-global-context
+ globalEval: function( data ) {
+ if ( data && jQuery.trim( data ) ) {
+ // We use execScript on Internet Explorer
+ // We use an anonymous function so that context is window
+ // rather than jQuery in Firefox
+ ( window.execScript || function( data ) {
+ window[ "eval" ].call( window, data );
+ } )( data );
+ }
+ },
+
+ // Convert dashed to camelCase; used by the css and data modules
+ // Microsoft forgot to hump their vendor prefix (#9572)
+ camelCase: function( string ) {
+ return string.replace( rmsPrefix, "ms-" ).replace( rdashAlpha, fcamelCase );
+ },
+
+ nodeName: function( elem, name ) {
+ return elem.nodeName && elem.nodeName.toLowerCase() === name.toLowerCase();
+ },
+
+ // args is for internal usage only
+ each: function( obj, callback, args ) {
+ var value,
+ i = 0,
+ length = obj.length,
+ isArray = isArraylike( obj );
+
+ if ( args ) {
+ if ( isArray ) {
+ for ( ; i < length; i++ ) {
+ value = callback.apply( obj[ i ], args );
+
+ if ( value === false ) {
+ break;
+ }
+ }
+ } else {
+ for ( i in obj ) {
+ value = callback.apply( obj[ i ], args );
+
+ if ( value === false ) {
+ break;
+ }
+ }
+ }
+
+ // A special, fast, case for the most common use of each
+ } else {
+ if ( isArray ) {
+ for ( ; i < length; i++ ) {
+ value = callback.call( obj[ i ], i, obj[ i ] );
+
+ if ( value === false ) {
+ break;
+ }
+ }
+ } else {
+ for ( i in obj ) {
+ value = callback.call( obj[ i ], i, obj[ i ] );
+
+ if ( value === false ) {
+ break;
+ }
+ }
+ }
+ }
+
+ return obj;
+ },
+
+ // Use native String.trim function wherever possible
+ trim: core_trim && !core_trim.call("\uFEFF\xA0") ?
+ function( text ) {
+ return text == null ?
+ "" :
+ core_trim.call( text );
+ } :
+
+ // Otherwise use our own trimming functionality
+ function( text ) {
+ return text == null ?
+ "" :
+ ( text + "" ).replace( rtrim, "" );
+ },
+
+ // results is for internal usage only
+ makeArray: function( arr, results ) {
+ var ret = results || [];
+
+ if ( arr != null ) {
+ if ( isArraylike( Object(arr) ) ) {
+ jQuery.merge( ret,
+ typeof arr === "string" ?
+ [ arr ] : arr
+ );
+ } else {
+ core_push.call( ret, arr );
+ }
+ }
+
+ return ret;
+ },
+
+ inArray: function( elem, arr, i ) {
+ var len;
+
+ if ( arr ) {
+ if ( core_indexOf ) {
+ return core_indexOf.call( arr, elem, i );
+ }
+
+ len = arr.length;
+ i = i ? i < 0 ? Math.max( 0, len + i ) : i : 0;
+
+ for ( ; i < len; i++ ) {
+ // Skip accessing in sparse arrays
+ if ( i in arr && arr[ i ] === elem ) {
+ return i;
+ }
+ }
+ }
+
+ return -1;
+ },
+
+ merge: function( first, second ) {
+ var l = second.length,
+ i = first.length,
+ j = 0;
+
+ if ( typeof l === "number" ) {
+ for ( ; j < l; j++ ) {
+ first[ i++ ] = second[ j ];
+ }
+ } else {
+ while ( second[j] !== undefined ) {
+ first[ i++ ] = second[ j++ ];
+ }
+ }
+
+ first.length = i;
+
+ return first;
+ },
+
+ grep: function( elems, callback, inv ) {
+ var retVal,
+ ret = [],
+ i = 0,
+ length = elems.length;
+ inv = !!inv;
+
+ // Go through the array, only saving the items
+ // that pass the validator function
+ for ( ; i < length; i++ ) {
+ retVal = !!callback( elems[ i ], i );
+ if ( inv !== retVal ) {
+ ret.push( elems[ i ] );
+ }
+ }
+
+ return ret;
+ },
+
+ // arg is for internal usage only
+ map: function( elems, callback, arg ) {
+ var value,
+ i = 0,
+ length = elems.length,
+ isArray = isArraylike( elems ),
+ ret = [];
+
+ // Go through the array, translating each of the items to their
+ if ( isArray ) {
+ for ( ; i < length; i++ ) {
+ value = callback( elems[ i ], i, arg );
+
+ if ( value != null ) {
+ ret[ ret.length ] = value;
+ }
+ }
+
+ // Go through every key on the object,
+ } else {
+ for ( i in elems ) {
+ value = callback( elems[ i ], i, arg );
+
+ if ( value != null ) {
+ ret[ ret.length ] = value;
+ }
+ }
+ }
+
+ // Flatten any nested arrays
+ return core_concat.apply( [], ret );
+ },
+
+ // A global GUID counter for objects
+ guid: 1,
+
+ // Bind a function to a context, optionally partially applying any
+ // arguments.
+ proxy: function( fn, context ) {
+ var args, proxy, tmp;
+
+ if ( typeof context === "string" ) {
+ tmp = fn[ context ];
+ context = fn;
+ fn = tmp;
+ }
+
+ // Quick check to determine if target is callable, in the spec
+ // this throws a TypeError, but we will just return undefined.
+ if ( !jQuery.isFunction( fn ) ) {
+ return undefined;
+ }
+
+ // Simulated bind
+ args = core_slice.call( arguments, 2 );
+ proxy = function() {
+ return fn.apply( context || this, args.concat( core_slice.call( arguments ) ) );
+ };
+
+ // Set the guid of unique handler to the same of original handler, so it can be removed
+ proxy.guid = fn.guid = fn.guid || jQuery.guid++;
+
+ return proxy;
+ },
+
+ // Multifunctional method to get and set values of a collection
+ // The value/s can optionally be executed if it's a function
+ access: function( elems, fn, key, value, chainable, emptyGet, raw ) {
+ var i = 0,
+ length = elems.length,
+ bulk = key == null;
+
+ // Sets many values
+ if ( jQuery.type( key ) === "object" ) {
+ chainable = true;
+ for ( i in key ) {
+ jQuery.access( elems, fn, i, key[i], true, emptyGet, raw );
+ }
+
+ // Sets one value
+ } else if ( value !== undefined ) {
+ chainable = true;
+
+ if ( !jQuery.isFunction( value ) ) {
+ raw = true;
+ }
+
+ if ( bulk ) {
+ // Bulk operations run against the entire set
+ if ( raw ) {
+ fn.call( elems, value );
+ fn = null;
+
+ // ...except when executing function values
+ } else {
+ bulk = fn;
+ fn = function( elem, key, value ) {
+ return bulk.call( jQuery( elem ), value );
+ };
+ }
+ }
+
+ if ( fn ) {
+ for ( ; i < length; i++ ) {
+ fn( elems[i], key, raw ? value : value.call( elems[i], i, fn( elems[i], key ) ) );
+ }
+ }
+ }
+
+ return chainable ?
+ elems :
+
+ // Gets
+ bulk ?
+ fn.call( elems ) :
+ length ? fn( elems[0], key ) : emptyGet;
+ },
+
+ now: function() {
+ return ( new Date() ).getTime();
+ },
+
+ // A method for quickly swapping in/out CSS properties to get correct calculations.
+ // Note: this method belongs to the css module but it's needed here for the support module.
+ // If support gets modularized, this method should be moved back to the css module.
+ swap: function( elem, options, callback, args ) {
+ var ret, name,
+ old = {};
+
+ // Remember the old values, and insert the new ones
+ for ( name in options ) {
+ old[ name ] = elem.style[ name ];
+ elem.style[ name ] = options[ name ];
+ }
+
+ ret = callback.apply( elem, args || [] );
+
+ // Revert the old values
+ for ( name in options ) {
+ elem.style[ name ] = old[ name ];
+ }
+
+ return ret;
+ }
+});
+
+jQuery.ready.promise = function( obj ) {
+ if ( !readyList ) {
+
+ readyList = jQuery.Deferred();
+
+ // Catch cases where $(document).ready() is called after the browser event has already occurred.
+ // we once tried to use readyState "interactive" here, but it caused issues like the one
+ // discovered by ChrisS here: http://bugs.jquery.com/ticket/12282#comment:15
+ if ( document.readyState === "complete" ) {
+ // Handle it asynchronously to allow scripts the opportunity to delay ready
+ setTimeout( jQuery.ready );
+
+ // Standards-based browsers support DOMContentLoaded
+ } else if ( document.addEventListener ) {
+ // Use the handy event callback
+ document.addEventListener( "DOMContentLoaded", completed, false );
+
+ // A fallback to window.onload, that will always work
+ window.addEventListener( "load", completed, false );
+
+ // If IE event model is used
+ } else {
+ // Ensure firing before onload, maybe late but safe also for iframes
+ document.attachEvent( "onreadystatechange", completed );
+
+ // A fallback to window.onload, that will always work
+ window.attachEvent( "onload", completed );
+
+ // If IE and not a frame
+ // continually check to see if the document is ready
+ var top = false;
+
+ try {
+ top = window.frameElement == null && document.documentElement;
+ } catch(e) {}
+
+ if ( top && top.doScroll ) {
+ (function doScrollCheck() {
+ if ( !jQuery.isReady ) {
+
+ try {
+ // Use the trick by Diego Perini
+ // http://javascript.nwbox.com/IEContentLoaded/
+ top.doScroll("left");
+ } catch(e) {
+ return setTimeout( doScrollCheck, 50 );
+ }
+
+ // detach all dom ready events
+ detach();
+
+ // and execute any waiting functions
+ jQuery.ready();
+ }
+ })();
+ }
+ }
+ }
+ return readyList.promise( obj );
+};
+
+// Populate the class2type map
+jQuery.each("Boolean Number String Function Array Date RegExp Object Error".split(" "), function(i, name) {
+ class2type[ "[object " + name + "]" ] = name.toLowerCase();
+});
+
+function isArraylike( obj ) {
+ var length = obj.length,
+ type = jQuery.type( obj );
+
+ if ( jQuery.isWindow( obj ) ) {
+ return false;
+ }
+
+ if ( obj.nodeType === 1 && length ) {
+ return true;
+ }
+
+ return type === "array" || type !== "function" &&
+ ( length === 0 ||
+ typeof length === "number" && length > 0 && ( length - 1 ) in obj );
+}
+
+// All jQuery objects should point back to these
+rootjQuery = jQuery(document);
+/*!
+ * Sizzle CSS Selector Engine v1.10.2
+ * http://sizzlejs.com/
+ *
+ * Copyright 2013 jQuery Foundation, Inc. and other contributors
+ * Released under the MIT license
+ * http://jquery.org/license
+ *
+ * Date: 2013-07-03
+ */
+(function( window, undefined ) {
+
+var i,
+ support,
+ cachedruns,
+ Expr,
+ getText,
+ isXML,
+ compile,
+ outermostContext,
+ sortInput,
+
+ // Local document vars
+ setDocument,
+ document,
+ docElem,
+ documentIsHTML,
+ rbuggyQSA,
+ rbuggyMatches,
+ matches,
+ contains,
+
+ // Instance-specific data
+ expando = "sizzle" + -(new Date()),
+ preferredDoc = window.document,
+ dirruns = 0,
+ done = 0,
+ classCache = createCache(),
+ tokenCache = createCache(),
+ compilerCache = createCache(),
+ hasDuplicate = false,
+ sortOrder = function( a, b ) {
+ if ( a === b ) {
+ hasDuplicate = true;
+ return 0;
+ }
+ return 0;
+ },
+
+ // General-purpose constants
+ strundefined = typeof undefined,
+ MAX_NEGATIVE = 1 << 31,
+
+ // Instance methods
+ hasOwn = ({}).hasOwnProperty,
+ arr = [],
+ pop = arr.pop,
+ push_native = arr.push,
+ push = arr.push,
+ slice = arr.slice,
+ // Use a stripped-down indexOf if we can't use a native one
+ indexOf = arr.indexOf || function( elem ) {
+ var i = 0,
+ len = this.length;
+ for ( ; i < len; i++ ) {
+ if ( this[i] === elem ) {
+ return i;
+ }
+ }
+ return -1;
+ },
+
+ booleans = "checked|selected|async|autofocus|autoplay|controls|defer|disabled|hidden|ismap|loop|multiple|open|readonly|required|scoped",
+
+ // Regular expressions
+
+ // Whitespace characters http://www.w3.org/TR/css3-selectors/#whitespace
+ whitespace = "[\\x20\\t\\r\\n\\f]",
+ // http://www.w3.org/TR/css3-syntax/#characters
+ characterEncoding = "(?:\\\\.|[\\w-]|[^\\x00-\\xa0])+",
+
+ // Loosely modeled on CSS identifier characters
+ // An unquoted value should be a CSS identifier http://www.w3.org/TR/css3-selectors/#attribute-selectors
+ // Proper syntax: http://www.w3.org/TR/CSS21/syndata.html#value-def-identifier
+ identifier = characterEncoding.replace( "w", "w#" ),
+
+ // Acceptable operators http://www.w3.org/TR/selectors/#attribute-selectors
+ attributes = "\\[" + whitespace + "*(" + characterEncoding + ")" + whitespace +
+ "*(?:([*^$|!~]?=)" + whitespace + "*(?:(['\"])((?:\\\\.|[^\\\\])*?)\\3|(" + identifier + ")|)|)" + whitespace + "*\\]",
+
+ // Prefer arguments quoted,
+ // then not containing pseudos/brackets,
+ // then attribute selectors/non-parenthetical expressions,
+ // then anything else
+ // These preferences are here to reduce the number of selectors
+ // needing tokenize in the PSEUDO preFilter
+ pseudos = ":(" + characterEncoding + ")(?:\\(((['\"])((?:\\\\.|[^\\\\])*?)\\3|((?:\\\\.|[^\\\\()[\\]]|" + attributes.replace( 3, 8 ) + ")*)|.*)\\)|)",
+
+ // Leading and non-escaped trailing whitespace, capturing some non-whitespace characters preceding the latter
+ rtrim = new RegExp( "^" + whitespace + "+|((?:^|[^\\\\])(?:\\\\.)*)" + whitespace + "+$", "g" ),
+
+ rcomma = new RegExp( "^" + whitespace + "*," + whitespace + "*" ),
+ rcombinators = new RegExp( "^" + whitespace + "*([>+~]|" + whitespace + ")" + whitespace + "*" ),
+
+ rsibling = new RegExp( whitespace + "*[+~]" ),
+ rattributeQuotes = new RegExp( "=" + whitespace + "*([^\\]'\"]*)" + whitespace + "*\\]", "g" ),
+
+ rpseudo = new RegExp( pseudos ),
+ ridentifier = new RegExp( "^" + identifier + "$" ),
+
+ matchExpr = {
+ "ID": new RegExp( "^#(" + characterEncoding + ")" ),
+ "CLASS": new RegExp( "^\\.(" + characterEncoding + ")" ),
+ "TAG": new RegExp( "^(" + characterEncoding.replace( "w", "w*" ) + ")" ),
+ "ATTR": new RegExp( "^" + attributes ),
+ "PSEUDO": new RegExp( "^" + pseudos ),
+ "CHILD": new RegExp( "^:(only|first|last|nth|nth-last)-(child|of-type)(?:\\(" + whitespace +
+ "*(even|odd|(([+-]|)(\\d*)n|)" + whitespace + "*(?:([+-]|)" + whitespace +
+ "*(\\d+)|))" + whitespace + "*\\)|)", "i" ),
+ "bool": new RegExp( "^(?:" + booleans + ")$", "i" ),
+ // For use in libraries implementing .is()
+ // We use this for POS matching in `select`
+ "needsContext": new RegExp( "^" + whitespace + "*[>+~]|:(even|odd|eq|gt|lt|nth|first|last)(?:\\(" +
+ whitespace + "*((?:-\\d)?\\d*)" + whitespace + "*\\)|)(?=[^-]|$)", "i" )
+ },
+
+ rnative = /^[^{]+\{\s*\[native \w/,
+
+ // Easily-parseable/retrievable ID or TAG or CLASS selectors
+ rquickExpr = /^(?:#([\w-]+)|(\w+)|\.([\w-]+))$/,
+
+ rinputs = /^(?:input|select|textarea|button)$/i,
+ rheader = /^h\d$/i,
+
+ rescape = /'|\\/g,
+
+ // CSS escapes http://www.w3.org/TR/CSS21/syndata.html#escaped-characters
+ runescape = new RegExp( "\\\\([\\da-f]{1,6}" + whitespace + "?|(" + whitespace + ")|.)", "ig" ),
+ funescape = function( _, escaped, escapedWhitespace ) {
+ var high = "0x" + escaped - 0x10000;
+ // NaN means non-codepoint
+ // Support: Firefox
+ // Workaround erroneous numeric interpretation of +"0x"
+ return high !== high || escapedWhitespace ?
+ escaped :
+ // BMP codepoint
+ high < 0 ?
+ String.fromCharCode( high + 0x10000 ) :
+ // Supplemental Plane codepoint (surrogate pair)
+ String.fromCharCode( high >> 10 | 0xD800, high & 0x3FF | 0xDC00 );
+ };
+
+// Optimize for push.apply( _, NodeList )
+try {
+ push.apply(
+ (arr = slice.call( preferredDoc.childNodes )),
+ preferredDoc.childNodes
+ );
+ // Support: Android<4.0
+ // Detect silently failing push.apply
+ arr[ preferredDoc.childNodes.length ].nodeType;
+} catch ( e ) {
+ push = { apply: arr.length ?
+
+ // Leverage slice if possible
+ function( target, els ) {
+ push_native.apply( target, slice.call(els) );
+ } :
+
+ // Support: IE<9
+ // Otherwise append directly
+ function( target, els ) {
+ var j = target.length,
+ i = 0;
+ // Can't trust NodeList.length
+ while ( (target[j++] = els[i++]) ) {}
+ target.length = j - 1;
+ }
+ };
+}
+
+function Sizzle( selector, context, results, seed ) {
+ var match, elem, m, nodeType,
+ // QSA vars
+ i, groups, old, nid, newContext, newSelector;
+
+ if ( ( context ? context.ownerDocument || context : preferredDoc ) !== document ) {
+ setDocument( context );
+ }
+
+ context = context || document;
+ results = results || [];
+
+ if ( !selector || typeof selector !== "string" ) {
+ return results;
+ }
+
+ if ( (nodeType = context.nodeType) !== 1 && nodeType !== 9 ) {
+ return [];
+ }
+
+ if ( documentIsHTML && !seed ) {
+
+ // Shortcuts
+ if ( (match = rquickExpr.exec( selector )) ) {
+ // Speed-up: Sizzle("#ID")
+ if ( (m = match[1]) ) {
+ if ( nodeType === 9 ) {
+ elem = context.getElementById( m );
+ // Check parentNode to catch when Blackberry 4.6 returns
+ // nodes that are no longer in the document #6963
+ if ( elem && elem.parentNode ) {
+ // Handle the case where IE, Opera, and Webkit return items
+ // by name instead of ID
+ if ( elem.id === m ) {
+ results.push( elem );
+ return results;
+ }
+ } else {
+ return results;
+ }
+ } else {
+ // Context is not a document
+ if ( context.ownerDocument && (elem = context.ownerDocument.getElementById( m )) &&
+ contains( context, elem ) && elem.id === m ) {
+ results.push( elem );
+ return results;
+ }
+ }
+
+ // Speed-up: Sizzle("TAG")
+ } else if ( match[2] ) {
+ push.apply( results, context.getElementsByTagName( selector ) );
+ return results;
+
+ // Speed-up: Sizzle(".CLASS")
+ } else if ( (m = match[3]) && support.getElementsByClassName && context.getElementsByClassName ) {
+ push.apply( results, context.getElementsByClassName( m ) );
+ return results;
+ }
+ }
+
+ // QSA path
+ if ( support.qsa && (!rbuggyQSA || !rbuggyQSA.test( selector )) ) {
+ nid = old = expando;
+ newContext = context;
+ newSelector = nodeType === 9 && selector;
+
+ // qSA works strangely on Element-rooted queries
+ // We can work around this by specifying an extra ID on the root
+ // and working up from there (Thanks to Andrew Dupont for the technique)
+ // IE 8 doesn't work on object elements
+ if ( nodeType === 1 && context.nodeName.toLowerCase() !== "object" ) {
+ groups = tokenize( selector );
+
+ if ( (old = context.getAttribute("id")) ) {
+ nid = old.replace( rescape, "\\$&" );
+ } else {
+ context.setAttribute( "id", nid );
+ }
+ nid = "[id='" + nid + "'] ";
+
+ i = groups.length;
+ while ( i-- ) {
+ groups[i] = nid + toSelector( groups[i] );
+ }
+ newContext = rsibling.test( selector ) && context.parentNode || context;
+ newSelector = groups.join(",");
+ }
+
+ if ( newSelector ) {
+ try {
+ push.apply( results,
+ newContext.querySelectorAll( newSelector )
+ );
+ return results;
+ } catch(qsaError) {
+ } finally {
+ if ( !old ) {
+ context.removeAttribute("id");
+ }
+ }
+ }
+ }
+ }
+
+ // All others
+ return select( selector.replace( rtrim, "$1" ), context, results, seed );
+}
+
+/**
+ * Create key-value caches of limited size
+ * @returns {Function(string, Object)} Returns the Object data after storing it on itself with
+ * property name the (space-suffixed) string and (if the cache is larger than Expr.cacheLength)
+ * deleting the oldest entry
+ */
+function createCache() {
+ var keys = [];
+
+ function cache( key, value ) {
+ // Use (key + " ") to avoid collision with native prototype properties (see Issue #157)
+ if ( keys.push( key += " " ) > Expr.cacheLength ) {
+ // Only keep the most recent entries
+ delete cache[ keys.shift() ];
+ }
+ return (cache[ key ] = value);
+ }
+ return cache;
+}
+
+/**
+ * Mark a function for special use by Sizzle
+ * @param {Function} fn The function to mark
+ */
+function markFunction( fn ) {
+ fn[ expando ] = true;
+ return fn;
+}
+
+/**
+ * Support testing using an element
+ * @param {Function} fn Passed the created div and expects a boolean result
+ */
+function assert( fn ) {
+ var div = document.createElement("div");
+
+ try {
+ return !!fn( div );
+ } catch (e) {
+ return false;
+ } finally {
+ // Remove from its parent by default
+ if ( div.parentNode ) {
+ div.parentNode.removeChild( div );
+ }
+ // release memory in IE
+ div = null;
+ }
+}
+
+/**
+ * Adds the same handler for all of the specified attrs
+ * @param {String} attrs Pipe-separated list of attributes
+ * @param {Function} handler The method that will be applied
+ */
+function addHandle( attrs, handler ) {
+ var arr = attrs.split("|"),
+ i = attrs.length;
+
+ while ( i-- ) {
+ Expr.attrHandle[ arr[i] ] = handler;
+ }
+}
+
+/**
+ * Checks document order of two siblings
+ * @param {Element} a
+ * @param {Element} b
+ * @returns {Number} Returns less than 0 if a precedes b, greater than 0 if a follows b
+ */
+function siblingCheck( a, b ) {
+ var cur = b && a,
+ diff = cur && a.nodeType === 1 && b.nodeType === 1 &&
+ ( ~b.sourceIndex || MAX_NEGATIVE ) -
+ ( ~a.sourceIndex || MAX_NEGATIVE );
+
+ // Use IE sourceIndex if available on both nodes
+ if ( diff ) {
+ return diff;
+ }
+
+ // Check if b follows a
+ if ( cur ) {
+ while ( (cur = cur.nextSibling) ) {
+ if ( cur === b ) {
+ return -1;
+ }
+ }
+ }
+
+ return a ? 1 : -1;
+}
+
+/**
+ * Returns a function to use in pseudos for input types
+ * @param {String} type
+ */
+function createInputPseudo( type ) {
+ return function( elem ) {
+ var name = elem.nodeName.toLowerCase();
+ return name === "input" && elem.type === type;
+ };
+}
+
+/**
+ * Returns a function to use in pseudos for buttons
+ * @param {String} type
+ */
+function createButtonPseudo( type ) {
+ return function( elem ) {
+ var name = elem.nodeName.toLowerCase();
+ return (name === "input" || name === "button") && elem.type === type;
+ };
+}
+
+/**
+ * Returns a function to use in pseudos for positionals
+ * @param {Function} fn
+ */
+function createPositionalPseudo( fn ) {
+ return markFunction(function( argument ) {
+ argument = +argument;
+ return markFunction(function( seed, matches ) {
+ var j,
+ matchIndexes = fn( [], seed.length, argument ),
+ i = matchIndexes.length;
+
+ // Match elements found at the specified indexes
+ while ( i-- ) {
+ if ( seed[ (j = matchIndexes[i]) ] ) {
+ seed[j] = !(matches[j] = seed[j]);
+ }
+ }
+ });
+ });
+}
+
+/**
+ * Detect xml
+ * @param {Element|Object} elem An element or a document
+ */
+isXML = Sizzle.isXML = function( elem ) {
+ // documentElement is verified for cases where it doesn't yet exist
+ // (such as loading iframes in IE - #4833)
+ var documentElement = elem && (elem.ownerDocument || elem).documentElement;
+ return documentElement ? documentElement.nodeName !== "HTML" : false;
+};
+
+// Expose support vars for convenience
+support = Sizzle.support = {};
+
+/**
+ * Sets document-related variables once based on the current document
+ * @param {Element|Object} [doc] An element or document object to use to set the document
+ * @returns {Object} Returns the current document
+ */
+setDocument = Sizzle.setDocument = function( node ) {
+ var doc = node ? node.ownerDocument || node : preferredDoc,
+ parent = doc.defaultView;
+
+ // If no document and documentElement is available, return
+ if ( doc === document || doc.nodeType !== 9 || !doc.documentElement ) {
+ return document;
+ }
+
+ // Set our document
+ document = doc;
+ docElem = doc.documentElement;
+
+ // Support tests
+ documentIsHTML = !isXML( doc );
+
+ // Support: IE>8
+ // If iframe document is assigned to "document" variable and if iframe has been reloaded,
+ // IE will throw "permission denied" error when accessing "document" variable, see jQuery #13936
+ // IE6-8 do not support the defaultView property so parent will be undefined
+ if ( parent && parent.attachEvent && parent !== parent.top ) {
+ parent.attachEvent( "onbeforeunload", function() {
+ setDocument();
+ });
+ }
+
+ /* Attributes
+ ---------------------------------------------------------------------- */
+
+ // Support: IE<8
+ // Verify that getAttribute really returns attributes and not properties (excepting IE8 booleans)
+ support.attributes = assert(function( div ) {
+ div.className = "i";
+ return !div.getAttribute("className");
+ });
+
+ /* getElement(s)By*
+ ---------------------------------------------------------------------- */
+
+ // Check if getElementsByTagName("*") returns only elements
+ support.getElementsByTagName = assert(function( div ) {
+ div.appendChild( doc.createComment("") );
+ return !div.getElementsByTagName("*").length;
+ });
+
+ // Check if getElementsByClassName can be trusted
+ support.getElementsByClassName = assert(function( div ) {
+ div.innerHTML = "<div class='a'></div><div class='a i'></div>";
+
+ // Support: Safari<4
+ // Catch class over-caching
+ div.firstChild.className = "i";
+ // Support: Opera<10
+ // Catch gEBCN failure to find non-leading classes
+ return div.getElementsByClassName("i").length === 2;
+ });
+
+ // Support: IE<10
+ // Check if getElementById returns elements by name
+ // The broken getElementById methods don't pick up programatically-set names,
+ // so use a roundabout getElementsByName test
+ support.getById = assert(function( div ) {
+ docElem.appendChild( div ).id = expando;
+ return !doc.getElementsByName || !doc.getElementsByName( expando ).length;
+ });
+
+ // ID find and filter
+ if ( support.getById ) {
+ Expr.find["ID"] = function( id, context ) {
+ if ( typeof context.getElementById !== strundefined && documentIsHTML ) {
+ var m = context.getElementById( id );
+ // Check parentNode to catch when Blackberry 4.6 returns
+ // nodes that are no longer in the document #6963
+ return m && m.parentNode ? [m] : [];
+ }
+ };
+ Expr.filter["ID"] = function( id ) {
+ var attrId = id.replace( runescape, funescape );
+ return function( elem ) {
+ return elem.getAttribute("id") === attrId;
+ };
+ };
+ } else {
+ // Support: IE6/7
+ // getElementById is not reliable as a find shortcut
+ delete Expr.find["ID"];
+
+ Expr.filter["ID"] = function( id ) {
+ var attrId = id.replace( runescape, funescape );
+ return function( elem ) {
+ var node = typeof elem.getAttributeNode !== strundefined && elem.getAttributeNode("id");
+ return node && node.value === attrId;
+ };
+ };
+ }
+
+ // Tag
+ Expr.find["TAG"] = support.getElementsByTagName ?
+ function( tag, context ) {
+ if ( typeof context.getElementsByTagName !== strundefined ) {
+ return context.getElementsByTagName( tag );
+ }
+ } :
+ function( tag, context ) {
+ var elem,
+ tmp = [],
+ i = 0,
+ results = context.getElementsByTagName( tag );
+
+ // Filter out possible comments
+ if ( tag === "*" ) {
+ while ( (elem = results[i++]) ) {
+ if ( elem.nodeType === 1 ) {
+ tmp.push( elem );
+ }
+ }
+
+ return tmp;
+ }
+ return results;
+ };
+
+ // Class
+ Expr.find["CLASS"] = support.getElementsByClassName && function( className, context ) {
+ if ( typeof context.getElementsByClassName !== strundefined && documentIsHTML ) {
+ return context.getElementsByClassName( className );
+ }
+ };
+
+ /* QSA/matchesSelector
+ ---------------------------------------------------------------------- */
+
+ // QSA and matchesSelector support
+
+ // matchesSelector(:active) reports false when true (IE9/Opera 11.5)
+ rbuggyMatches = [];
+
+ // qSa(:focus) reports false when true (Chrome 21)
+ // We allow this because of a bug in IE8/9 that throws an error
+ // whenever `document.activeElement` is accessed on an iframe
+ // So, we allow :focus to pass through QSA all the time to avoid the IE error
+ // See http://bugs.jquery.com/ticket/13378
+ rbuggyQSA = [];
+
+ if ( (support.qsa = rnative.test( doc.querySelectorAll )) ) {
+ // Build QSA regex
+ // Regex strategy adopted from Diego Perini
+ assert(function( div ) {
+ // Select is set to empty string on purpose
+ // This is to test IE's treatment of not explicitly
+ // setting a boolean content attribute,
+ // since its presence should be enough
+ // http://bugs.jquery.com/ticket/12359
+ div.innerHTML = "<select><option selected=''></option></select>";
+
+ // Support: IE8
+ // Boolean attributes and "value" are not treated correctly
+ if ( !div.querySelectorAll("[selected]").length ) {
+ rbuggyQSA.push( "\\[" + whitespace + "*(?:value|" + booleans + ")" );
+ }
+
+ // Webkit/Opera - :checked should return selected option elements
+ // http://www.w3.org/TR/2011/REC-css3-selectors-20110929/#checked
+ // IE8 throws error here and will not see later tests
+ if ( !div.querySelectorAll(":checked").length ) {
+ rbuggyQSA.push(":checked");
+ }
+ });
+
+ assert(function( div ) {
+
+ // Support: Opera 10-12/IE8
+ // ^= $= *= and empty values
+ // Should not select anything
+ // Support: Windows 8 Native Apps
+ // The type attribute is restricted during .innerHTML assignment
+ var input = doc.createElement("input");
+ input.setAttribute( "type", "hidden" );
+ div.appendChild( input ).setAttribute( "t", "" );
+
+ if ( div.querySelectorAll("[t^='']").length ) {
+ rbuggyQSA.push( "[*^$]=" + whitespace + "*(?:''|\"\")" );
+ }
+
+ // FF 3.5 - :enabled/:disabled and hidden elements (hidden elements are still enabled)
+ // IE8 throws error here and will not see later tests
+ if ( !div.querySelectorAll(":enabled").length ) {
+ rbuggyQSA.push( ":enabled", ":disabled" );
+ }
+
+ // Opera 10-11 does not throw on post-comma invalid pseudos
+ div.querySelectorAll("*,:x");
+ rbuggyQSA.push(",.*:");
+ });
+ }
+
+ if ( (support.matchesSelector = rnative.test( (matches = docElem.webkitMatchesSelector ||
+ docElem.mozMatchesSelector ||
+ docElem.oMatchesSelector ||
+ docElem.msMatchesSelector) )) ) {
+
+ assert(function( div ) {
+ // Check to see if it's possible to do matchesSelector
+ // on a disconnected node (IE 9)
+ support.disconnectedMatch = matches.call( div, "div" );
+
+ // This should fail with an exception
+ // Gecko does not error, returns false instead
+ matches.call( div, "[s!='']:x" );
+ rbuggyMatches.push( "!=", pseudos );
+ });
+ }
+
+ rbuggyQSA = rbuggyQSA.length && new RegExp( rbuggyQSA.join("|") );
+ rbuggyMatches = rbuggyMatches.length && new RegExp( rbuggyMatches.join("|") );
+
+ /* Contains
+ ---------------------------------------------------------------------- */
+
+ // Element contains another
+ // Purposefully does not implement inclusive descendent
+ // As in, an element does not contain itself
+ contains = rnative.test( docElem.contains ) || docElem.compareDocumentPosition ?
+ function( a, b ) {
+ var adown = a.nodeType === 9 ? a.documentElement : a,
+ bup = b && b.parentNode;
+ return a === bup || !!( bup && bup.nodeType === 1 && (
+ adown.contains ?
+ adown.contains( bup ) :
+ a.compareDocumentPosition && a.compareDocumentPosition( bup ) & 16
+ ));
+ } :
+ function( a, b ) {
+ if ( b ) {
+ while ( (b = b.parentNode) ) {
+ if ( b === a ) {
+ return true;
+ }
+ }
+ }
+ return false;
+ };
+
+ /* Sorting
+ ---------------------------------------------------------------------- */
+
+ // Document order sorting
+ sortOrder = docElem.compareDocumentPosition ?
+ function( a, b ) {
+
+ // Flag for duplicate removal
+ if ( a === b ) {
+ hasDuplicate = true;
+ return 0;
+ }
+
+ var compare = b.compareDocumentPosition && a.compareDocumentPosition && a.compareDocumentPosition( b );
+
+ if ( compare ) {
+ // Disconnected nodes
+ if ( compare & 1 ||
+ (!support.sortDetached && b.compareDocumentPosition( a ) === compare) ) {
+
+ // Choose the first element that is related to our preferred document
+ if ( a === doc || contains(preferredDoc, a) ) {
+ return -1;
+ }
+ if ( b === doc || contains(preferredDoc, b) ) {
+ return 1;
+ }
+
+ // Maintain original order
+ return sortInput ?
+ ( indexOf.call( sortInput, a ) - indexOf.call( sortInput, b ) ) :
+ 0;
+ }
+
+ return compare & 4 ? -1 : 1;
+ }
+
+ // Not directly comparable, sort on existence of method
+ return a.compareDocumentPosition ? -1 : 1;
+ } :
+ function( a, b ) {
+ var cur,
+ i = 0,
+ aup = a.parentNode,
+ bup = b.parentNode,
+ ap = [ a ],
+ bp = [ b ];
+
+ // Exit early if the nodes are identical
+ if ( a === b ) {
+ hasDuplicate = true;
+ return 0;
+
+ // Parentless nodes are either documents or disconnected
+ } else if ( !aup || !bup ) {
+ return a === doc ? -1 :
+ b === doc ? 1 :
+ aup ? -1 :
+ bup ? 1 :
+ sortInput ?
+ ( indexOf.call( sortInput, a ) - indexOf.call( sortInput, b ) ) :
+ 0;
+
+ // If the nodes are siblings, we can do a quick check
+ } else if ( aup === bup ) {
+ return siblingCheck( a, b );
+ }
+
+ // Otherwise we need full lists of their ancestors for comparison
+ cur = a;
+ while ( (cur = cur.parentNode) ) {
+ ap.unshift( cur );
+ }
+ cur = b;
+ while ( (cur = cur.parentNode) ) {
+ bp.unshift( cur );
+ }
+
+ // Walk down the tree looking for a discrepancy
+ while ( ap[i] === bp[i] ) {
+ i++;
+ }
+
+ return i ?
+ // Do a sibling check if the nodes have a common ancestor
+ siblingCheck( ap[i], bp[i] ) :
+
+ // Otherwise nodes in our document sort first
+ ap[i] === preferredDoc ? -1 :
+ bp[i] === preferredDoc ? 1 :
+ 0;
+ };
+
+ return doc;
+};
+
+Sizzle.matches = function( expr, elements ) {
+ return Sizzle( expr, null, null, elements );
+};
+
+Sizzle.matchesSelector = function( elem, expr ) {
+ // Set document vars if needed
+ if ( ( elem.ownerDocument || elem ) !== document ) {
+ setDocument( elem );
+ }
+
+ // Make sure that attribute selectors are quoted
+ expr = expr.replace( rattributeQuotes, "='$1']" );
+
+ if ( support.matchesSelector && documentIsHTML &&
+ ( !rbuggyMatches || !rbuggyMatches.test( expr ) ) &&
+ ( !rbuggyQSA || !rbuggyQSA.test( expr ) ) ) {
+
+ try {
+ var ret = matches.call( elem, expr );
+
+ // IE 9's matchesSelector returns false on disconnected nodes
+ if ( ret || support.disconnectedMatch ||
+ // As well, disconnected nodes are said to be in a document
+ // fragment in IE 9
+ elem.document && elem.document.nodeType !== 11 ) {
+ return ret;
+ }
+ } catch(e) {}
+ }
+
+ return Sizzle( expr, document, null, [elem] ).length > 0;
+};
+
+Sizzle.contains = function( context, elem ) {
+ // Set document vars if needed
+ if ( ( context.ownerDocument || context ) !== document ) {
+ setDocument( context );
+ }
+ return contains( context, elem );
+};
+
+Sizzle.attr = function( elem, name ) {
+ // Set document vars if needed
+ if ( ( elem.ownerDocument || elem ) !== document ) {
+ setDocument( elem );
+ }
+
+ var fn = Expr.attrHandle[ name.toLowerCase() ],
+ // Don't get fooled by Object.prototype properties (jQuery #13807)
+ val = fn && hasOwn.call( Expr.attrHandle, name.toLowerCase() ) ?
+ fn( elem, name, !documentIsHTML ) :
+ undefined;
+
+ return val === undefined ?
+ support.attributes || !documentIsHTML ?
+ elem.getAttribute( name ) :
+ (val = elem.getAttributeNode(name)) && val.specified ?
+ val.value :
+ null :
+ val;
+};
+
+Sizzle.error = function( msg ) {
+ throw new Error( "Syntax error, unrecognized expression: " + msg );
+};
+
+/**
+ * Document sorting and removing duplicates
+ * @param {ArrayLike} results
+ */
+Sizzle.uniqueSort = function( results ) {
+ var elem,
+ duplicates = [],
+ j = 0,
+ i = 0;
+
+ // Unless we *know* we can detect duplicates, assume their presence
+ hasDuplicate = !support.detectDuplicates;
+ sortInput = !support.sortStable && results.slice( 0 );
+ results.sort( sortOrder );
+
+ if ( hasDuplicate ) {
+ while ( (elem = results[i++]) ) {
+ if ( elem === results[ i ] ) {
+ j = duplicates.push( i );
+ }
+ }
+ while ( j-- ) {
+ results.splice( duplicates[ j ], 1 );
+ }
+ }
+
+ return results;
+};
+
+/**
+ * Utility function for retrieving the text value of an array of DOM nodes
+ * @param {Array|Element} elem
+ */
+getText = Sizzle.getText = function( elem ) {
+ var node,
+ ret = "",
+ i = 0,
+ nodeType = elem.nodeType;
+
+ if ( !nodeType ) {
+ // If no nodeType, this is expected to be an array
+ for ( ; (node = elem[i]); i++ ) {
+ // Do not traverse comment nodes
+ ret += getText( node );
+ }
+ } else if ( nodeType === 1 || nodeType === 9 || nodeType === 11 ) {
+ // Use textContent for elements
+ // innerText usage removed for consistency of new lines (see #11153)
+ if ( typeof elem.textContent === "string" ) {
+ return elem.textContent;
+ } else {
+ // Traverse its children
+ for ( elem = elem.firstChild; elem; elem = elem.nextSibling ) {
+ ret += getText( elem );
+ }
+ }
+ } else if ( nodeType === 3 || nodeType === 4 ) {
+ return elem.nodeValue;
+ }
+ // Do not include comment or processing instruction nodes
+
+ return ret;
+};
+
+Expr = Sizzle.selectors = {
+
+ // Can be adjusted by the user
+ cacheLength: 50,
+
+ createPseudo: markFunction,
+
+ match: matchExpr,
+
+ attrHandle: {},
+
+ find: {},
+
+ relative: {
+ ">": { dir: "parentNode", first: true },
+ " ": { dir: "parentNode" },
+ "+": { dir: "previousSibling", first: true },
+ "~": { dir: "previousSibling" }
+ },
+
+ preFilter: {
+ "ATTR": function( match ) {
+ match[1] = match[1].replace( runescape, funescape );
+
+ // Move the given value to match[3] whether quoted or unquoted
+ match[3] = ( match[4] || match[5] || "" ).replace( runescape, funescape );
+
+ if ( match[2] === "~=" ) {
+ match[3] = " " + match[3] + " ";
+ }
+
+ return match.slice( 0, 4 );
+ },
+
+ "CHILD": function( match ) {
+ /* matches from matchExpr["CHILD"]
+ 1 type (only|nth|...)
+ 2 what (child|of-type)
+ 3 argument (even|odd|\d*|\d*n([+-]\d+)?|...)
+ 4 xn-component of xn+y argument ([+-]?\d*n|)
+ 5 sign of xn-component
+ 6 x of xn-component
+ 7 sign of y-component
+ 8 y of y-component
+ */
+ match[1] = match[1].toLowerCase();
+
+ if ( match[1].slice( 0, 3 ) === "nth" ) {
+ // nth-* requires argument
+ if ( !match[3] ) {
+ Sizzle.error( match[0] );
+ }
+
+ // numeric x and y parameters for Expr.filter.CHILD
+ // remember that false/true cast respectively to 0/1
+ match[4] = +( match[4] ? match[5] + (match[6] || 1) : 2 * ( match[3] === "even" || match[3] === "odd" ) );
+ match[5] = +( ( match[7] + match[8] ) || match[3] === "odd" );
+
+ // other types prohibit arguments
+ } else if ( match[3] ) {
+ Sizzle.error( match[0] );
+ }
+
+ return match;
+ },
+
+ "PSEUDO": function( match ) {
+ var excess,
+ unquoted = !match[5] && match[2];
+
+ if ( matchExpr["CHILD"].test( match[0] ) ) {
+ return null;
+ }
+
+ // Accept quoted arguments as-is
+ if ( match[3] && match[4] !== undefined ) {
+ match[2] = match[4];
+
+ // Strip excess characters from unquoted arguments
+ } else if ( unquoted && rpseudo.test( unquoted ) &&
+ // Get excess from tokenize (recursively)
+ (excess = tokenize( unquoted, true )) &&
+ // advance to the next closing parenthesis
+ (excess = unquoted.indexOf( ")", unquoted.length - excess ) - unquoted.length) ) {
+
+ // excess is a negative index
+ match[0] = match[0].slice( 0, excess );
+ match[2] = unquoted.slice( 0, excess );
+ }
+
+ // Return only captures needed by the pseudo filter method (type and argument)
+ return match.slice( 0, 3 );
+ }
+ },
+
+ filter: {
+
+ "TAG": function( nodeNameSelector ) {
+ var nodeName = nodeNameSelector.replace( runescape, funescape ).toLowerCase();
+ return nodeNameSelector === "*" ?
+ function() { return true; } :
+ function( elem ) {
+ return elem.nodeName && elem.nodeName.toLowerCase() === nodeName;
+ };
+ },
+
+ "CLASS": function( className ) {
+ var pattern = classCache[ className + " " ];
+
+ return pattern ||
+ (pattern = new RegExp( "(^|" + whitespace + ")" + className + "(" + whitespace + "|$)" )) &&
+ classCache( className, function( elem ) {
+ return pattern.test( typeof elem.className === "string" && elem.className || typeof elem.getAttribute !== strundefined && elem.getAttribute("class") || "" );
+ });
+ },
+
+ "ATTR": function( name, operator, check ) {
+ return function( elem ) {
+ var result = Sizzle.attr( elem, name );
+
+ if ( result == null ) {
+ return operator === "!=";
+ }
+ if ( !operator ) {
+ return true;
+ }
+
+ result += "";
+
+ return operator === "=" ? result === check :
+ operator === "!=" ? result !== check :
+ operator === "^=" ? check && result.indexOf( check ) === 0 :
+ operator === "*=" ? check && result.indexOf( check ) > -1 :
+ operator === "$=" ? check && result.slice( -check.length ) === check :
+ operator === "~=" ? ( " " + result + " " ).indexOf( check ) > -1 :
+ operator === "|=" ? result === check || result.slice( 0, check.length + 1 ) === check + "-" :
+ false;
+ };
+ },
+
+ "CHILD": function( type, what, argument, first, last ) {
+ var simple = type.slice( 0, 3 ) !== "nth",
+ forward = type.slice( -4 ) !== "last",
+ ofType = what === "of-type";
+
+ return first === 1 && last === 0 ?
+
+ // Shortcut for :nth-*(n)
+ function( elem ) {
+ return !!elem.parentNode;
+ } :
+
+ function( elem, context, xml ) {
+ var cache, outerCache, node, diff, nodeIndex, start,
+ dir = simple !== forward ? "nextSibling" : "previousSibling",
+ parent = elem.parentNode,
+ name = ofType && elem.nodeName.toLowerCase(),
+ useCache = !xml && !ofType;
+
+ if ( parent ) {
+
+ // :(first|last|only)-(child|of-type)
+ if ( simple ) {
+ while ( dir ) {
+ node = elem;
+ while ( (node = node[ dir ]) ) {
+ if ( ofType ? node.nodeName.toLowerCase() === name : node.nodeType === 1 ) {
+ return false;
+ }
+ }
+ // Reverse direction for :only-* (if we haven't yet done so)
+ start = dir = type === "only" && !start && "nextSibling";
+ }
+ return true;
+ }
+
+ start = [ forward ? parent.firstChild : parent.lastChild ];
+
+ // non-xml :nth-child(...) stores cache data on `parent`
+ if ( forward && useCache ) {
+ // Seek `elem` from a previously-cached index
+ outerCache = parent[ expando ] || (parent[ expando ] = {});
+ cache = outerCache[ type ] || [];
+ nodeIndex = cache[0] === dirruns && cache[1];
+ diff = cache[0] === dirruns && cache[2];
+ node = nodeIndex && parent.childNodes[ nodeIndex ];
+
+ while ( (node = ++nodeIndex && node && node[ dir ] ||
+
+ // Fallback to seeking `elem` from the start
+ (diff = nodeIndex = 0) || start.pop()) ) {
+
+ // When found, cache indexes on `parent` and break
+ if ( node.nodeType === 1 && ++diff && node === elem ) {
+ outerCache[ type ] = [ dirruns, nodeIndex, diff ];
+ break;
+ }
+ }
+
+ // Use previously-cached element index if available
+ } else if ( useCache && (cache = (elem[ expando ] || (elem[ expando ] = {}))[ type ]) && cache[0] === dirruns ) {
+ diff = cache[1];
+
+ // xml :nth-child(...) or :nth-last-child(...) or :nth(-last)?-of-type(...)
+ } else {
+ // Use the same loop as above to seek `elem` from the start
+ while ( (node = ++nodeIndex && node && node[ dir ] ||
+ (diff = nodeIndex = 0) || start.pop()) ) {
+
+ if ( ( ofType ? node.nodeName.toLowerCase() === name : node.nodeType === 1 ) && ++diff ) {
+ // Cache the index of each encountered element
+ if ( useCache ) {
+ (node[ expando ] || (node[ expando ] = {}))[ type ] = [ dirruns, diff ];
+ }
+
+ if ( node === elem ) {
+ break;
+ }
+ }
+ }
+ }
+
+ // Incorporate the offset, then check against cycle size
+ diff -= last;
+ return diff === first || ( diff % first === 0 && diff / first >= 0 );
+ }
+ };
+ },
+
+ "PSEUDO": function( pseudo, argument ) {
+ // pseudo-class names are case-insensitive
+ // http://www.w3.org/TR/selectors/#pseudo-classes
+ // Prioritize by case sensitivity in case custom pseudos are added with uppercase letters
+ // Remember that setFilters inherits from pseudos
+ var args,
+ fn = Expr.pseudos[ pseudo ] || Expr.setFilters[ pseudo.toLowerCase() ] ||
+ Sizzle.error( "unsupported pseudo: " + pseudo );
+
+ // The user may use createPseudo to indicate that
+ // arguments are needed to create the filter function
+ // just as Sizzle does
+ if ( fn[ expando ] ) {
+ return fn( argument );
+ }
+
+ // But maintain support for old signatures
+ if ( fn.length > 1 ) {
+ args = [ pseudo, pseudo, "", argument ];
+ return Expr.setFilters.hasOwnProperty( pseudo.toLowerCase() ) ?
+ markFunction(function( seed, matches ) {
+ var idx,
+ matched = fn( seed, argument ),
+ i = matched.length;
+ while ( i-- ) {
+ idx = indexOf.call( seed, matched[i] );
+ seed[ idx ] = !( matches[ idx ] = matched[i] );
+ }
+ }) :
+ function( elem ) {
+ return fn( elem, 0, args );
+ };
+ }
+
+ return fn;
+ }
+ },
+
+ pseudos: {
+ // Potentially complex pseudos
+ "not": markFunction(function( selector ) {
+ // Trim the selector passed to compile
+ // to avoid treating leading and trailing
+ // spaces as combinators
+ var input = [],
+ results = [],
+ matcher = compile( selector.replace( rtrim, "$1" ) );
+
+ return matcher[ expando ] ?
+ markFunction(function( seed, matches, context, xml ) {
+ var elem,
+ unmatched = matcher( seed, null, xml, [] ),
+ i = seed.length;
+
+ // Match elements unmatched by `matcher`
+ while ( i-- ) {
+ if ( (elem = unmatched[i]) ) {
+ seed[i] = !(matches[i] = elem);
+ }
+ }
+ }) :
+ function( elem, context, xml ) {
+ input[0] = elem;
+ matcher( input, null, xml, results );
+ return !results.pop();
+ };
+ }),
+
+ "has": markFunction(function( selector ) {
+ return function( elem ) {
+ return Sizzle( selector, elem ).length > 0;
+ };
+ }),
+
+ "contains": markFunction(function( text ) {
+ return function( elem ) {
+ return ( elem.textContent || elem.innerText || getText( elem ) ).indexOf( text ) > -1;
+ };
+ }),
+
+ // "Whether an element is represented by a :lang() selector
+ // is based solely on the element's language value
+ // being equal to the identifier C,
+ // or beginning with the identifier C immediately followed by "-".
+ // The matching of C against the element's language value is performed case-insensitively.
+ // The identifier C does not have to be a valid language name."
+ // http://www.w3.org/TR/selectors/#lang-pseudo
+ "lang": markFunction( function( lang ) {
+ // lang value must be a valid identifier
+ if ( !ridentifier.test(lang || "") ) {
+ Sizzle.error( "unsupported lang: " + lang );
+ }
+ lang = lang.replace( runescape, funescape ).toLowerCase();
+ return function( elem ) {
+ var elemLang;
+ do {
+ if ( (elemLang = documentIsHTML ?
+ elem.lang :
+ elem.getAttribute("xml:lang") || elem.getAttribute("lang")) ) {
+
+ elemLang = elemLang.toLowerCase();
+ return elemLang === lang || elemLang.indexOf( lang + "-" ) === 0;
+ }
+ } while ( (elem = elem.parentNode) && elem.nodeType === 1 );
+ return false;
+ };
+ }),
+
+ // Miscellaneous
+ "target": function( elem ) {
+ var hash = window.location && window.location.hash;
+ return hash && hash.slice( 1 ) === elem.id;
+ },
+
+ "root": function( elem ) {
+ return elem === docElem;
+ },
+
+ "focus": function( elem ) {
+ return elem === document.activeElement && (!document.hasFocus || document.hasFocus()) && !!(elem.type || elem.href || ~elem.tabIndex);
+ },
+
+ // Boolean properties
+ "enabled": function( elem ) {
+ return elem.disabled === false;
+ },
+
+ "disabled": function( elem ) {
+ return elem.disabled === true;
+ },
+
+ "checked": function( elem ) {
+ // In CSS3, :checked should return both checked and selected elements
+ // http://www.w3.org/TR/2011/REC-css3-selectors-20110929/#checked
+ var nodeName = elem.nodeName.toLowerCase();
+ return (nodeName === "input" && !!elem.checked) || (nodeName === "option" && !!elem.selected);
+ },
+
+ "selected": function( elem ) {
+ // Accessing this property makes selected-by-default
+ // options in Safari work properly
+ if ( elem.parentNode ) {
+ elem.parentNode.selectedIndex;
+ }
+
+ return elem.selected === true;
+ },
+
+ // Contents
+ "empty": function( elem ) {
+ // http://www.w3.org/TR/selectors/#empty-pseudo
+ // :empty is only affected by element nodes and content nodes(including text(3), cdata(4)),
+ // not comment, processing instructions, or others
+ // Thanks to Diego Perini for the nodeName shortcut
+ // Greater than "@" means alpha characters (specifically not starting with "#" or "?")
+ for ( elem = elem.firstChild; elem; elem = elem.nextSibling ) {
+ if ( elem.nodeName > "@" || elem.nodeType === 3 || elem.nodeType === 4 ) {
+ return false;
+ }
+ }
+ return true;
+ },
+
+ "parent": function( elem ) {
+ return !Expr.pseudos["empty"]( elem );
+ },
+
+ // Element/input types
+ "header": function( elem ) {
+ return rheader.test( elem.nodeName );
+ },
+
+ "input": function( elem ) {
+ return rinputs.test( elem.nodeName );
+ },
+
+ "button": function( elem ) {
+ var name = elem.nodeName.toLowerCase();
+ return name === "input" && elem.type === "button" || name === "button";
+ },
+
+ "text": function( elem ) {
+ var attr;
+ // IE6 and 7 will map elem.type to 'text' for new HTML5 types (search, etc)
+ // use getAttribute instead to test this case
+ return elem.nodeName.toLowerCase() === "input" &&
+ elem.type === "text" &&
+ ( (attr = elem.getAttribute("type")) == null || attr.toLowerCase() === elem.type );
+ },
+
+ // Position-in-collection
+ "first": createPositionalPseudo(function() {
+ return [ 0 ];
+ }),
+
+ "last": createPositionalPseudo(function( matchIndexes, length ) {
+ return [ length - 1 ];
+ }),
+
+ "eq": createPositionalPseudo(function( matchIndexes, length, argument ) {
+ return [ argument < 0 ? argument + length : argument ];
+ }),
+
+ "even": createPositionalPseudo(function( matchIndexes, length ) {
+ var i = 0;
+ for ( ; i < length; i += 2 ) {
+ matchIndexes.push( i );
+ }
+ return matchIndexes;
+ }),
+
+ "odd": createPositionalPseudo(function( matchIndexes, length ) {
+ var i = 1;
+ for ( ; i < length; i += 2 ) {
+ matchIndexes.push( i );
+ }
+ return matchIndexes;
+ }),
+
+ "lt": createPositionalPseudo(function( matchIndexes, length, argument ) {
+ var i = argument < 0 ? argument + length : argument;
+ for ( ; --i >= 0; ) {
+ matchIndexes.push( i );
+ }
+ return matchIndexes;
+ }),
+
+ "gt": createPositionalPseudo(function( matchIndexes, length, argument ) {
+ var i = argument < 0 ? argument + length : argument;
+ for ( ; ++i < length; ) {
+ matchIndexes.push( i );
+ }
+ return matchIndexes;
+ })
+ }
+};
+
+Expr.pseudos["nth"] = Expr.pseudos["eq"];
+
+// Add button/input type pseudos
+for ( i in { radio: true, checkbox: true, file: true, password: true, image: true } ) {
+ Expr.pseudos[ i ] = createInputPseudo( i );
+}
+for ( i in { submit: true, reset: true } ) {
+ Expr.pseudos[ i ] = createButtonPseudo( i );
+}
+
+// Easy API for creating new setFilters
+function setFilters() {}
+setFilters.prototype = Expr.filters = Expr.pseudos;
+Expr.setFilters = new setFilters();
+
+function tokenize( selector, parseOnly ) {
+ var matched, match, tokens, type,
+ soFar, groups, preFilters,
+ cached = tokenCache[ selector + " " ];
+
+ if ( cached ) {
+ return parseOnly ? 0 : cached.slice( 0 );
+ }
+
+ soFar = selector;
+ groups = [];
+ preFilters = Expr.preFilter;
+
+ while ( soFar ) {
+
+ // Comma and first run
+ if ( !matched || (match = rcomma.exec( soFar )) ) {
+ if ( match ) {
+ // Don't consume trailing commas as valid
+ soFar = soFar.slice( match[0].length ) || soFar;
+ }
+ groups.push( tokens = [] );
+ }
+
+ matched = false;
+
+ // Combinators
+ if ( (match = rcombinators.exec( soFar )) ) {
+ matched = match.shift();
+ tokens.push({
+ value: matched,
+ // Cast descendant combinators to space
+ type: match[0].replace( rtrim, " " )
+ });
+ soFar = soFar.slice( matched.length );
+ }
+
+ // Filters
+ for ( type in Expr.filter ) {
+ if ( (match = matchExpr[ type ].exec( soFar )) && (!preFilters[ type ] ||
+ (match = preFilters[ type ]( match ))) ) {
+ matched = match.shift();
+ tokens.push({
+ value: matched,
+ type: type,
+ matches: match
+ });
+ soFar = soFar.slice( matched.length );
+ }
+ }
+
+ if ( !matched ) {
+ break;
+ }
+ }
+
+ // Return the length of the invalid excess
+ // if we're just parsing
+ // Otherwise, throw an error or return tokens
+ return parseOnly ?
+ soFar.length :
+ soFar ?
+ Sizzle.error( selector ) :
+ // Cache the tokens
+ tokenCache( selector, groups ).slice( 0 );
+}
+
+function toSelector( tokens ) {
+ var i = 0,
+ len = tokens.length,
+ selector = "";
+ for ( ; i < len; i++ ) {
+ selector += tokens[i].value;
+ }
+ return selector;
+}
+
+function addCombinator( matcher, combinator, base ) {
+ var dir = combinator.dir,
+ checkNonElements = base && dir === "parentNode",
+ doneName = done++;
+
+ return combinator.first ?
+ // Check against closest ancestor/preceding element
+ function( elem, context, xml ) {
+ while ( (elem = elem[ dir ]) ) {
+ if ( elem.nodeType === 1 || checkNonElements ) {
+ return matcher( elem, context, xml );
+ }
+ }
+ } :
+
+ // Check against all ancestor/preceding elements
+ function( elem, context, xml ) {
+ var data, cache, outerCache,
+ dirkey = dirruns + " " + doneName;
+
+ // We can't set arbitrary data on XML nodes, so they don't benefit from dir caching
+ if ( xml ) {
+ while ( (elem = elem[ dir ]) ) {
+ if ( elem.nodeType === 1 || checkNonElements ) {
+ if ( matcher( elem, context, xml ) ) {
+ return true;
+ }
+ }
+ }
+ } else {
+ while ( (elem = elem[ dir ]) ) {
+ if ( elem.nodeType === 1 || checkNonElements ) {
+ outerCache = elem[ expando ] || (elem[ expando ] = {});
+ if ( (cache = outerCache[ dir ]) && cache[0] === dirkey ) {
+ if ( (data = cache[1]) === true || data === cachedruns ) {
+ return data === true;
+ }
+ } else {
+ cache = outerCache[ dir ] = [ dirkey ];
+ cache[1] = matcher( elem, context, xml ) || cachedruns;
+ if ( cache[1] === true ) {
+ return true;
+ }
+ }
+ }
+ }
+ }
+ };
+}
+
+function elementMatcher( matchers ) {
+ return matchers.length > 1 ?
+ function( elem, context, xml ) {
+ var i = matchers.length;
+ while ( i-- ) {
+ if ( !matchers[i]( elem, context, xml ) ) {
+ return false;
+ }
+ }
+ return true;
+ } :
+ matchers[0];
+}
+
+function condense( unmatched, map, filter, context, xml ) {
+ var elem,
+ newUnmatched = [],
+ i = 0,
+ len = unmatched.length,
+ mapped = map != null;
+
+ for ( ; i < len; i++ ) {
+ if ( (elem = unmatched[i]) ) {
+ if ( !filter || filter( elem, context, xml ) ) {
+ newUnmatched.push( elem );
+ if ( mapped ) {
+ map.push( i );
+ }
+ }
+ }
+ }
+
+ return newUnmatched;
+}
+
+function setMatcher( preFilter, selector, matcher, postFilter, postFinder, postSelector ) {
+ if ( postFilter && !postFilter[ expando ] ) {
+ postFilter = setMatcher( postFilter );
+ }
+ if ( postFinder && !postFinder[ expando ] ) {
+ postFinder = setMatcher( postFinder, postSelector );
+ }
+ return markFunction(function( seed, results, context, xml ) {
+ var temp, i, elem,
+ preMap = [],
+ postMap = [],
+ preexisting = results.length,
+
+ // Get initial elements from seed or context
+ elems = seed || multipleContexts( selector || "*", context.nodeType ? [ context ] : context, [] ),
+
+ // Prefilter to get matcher input, preserving a map for seed-results synchronization
+ matcherIn = preFilter && ( seed || !selector ) ?
+ condense( elems, preMap, preFilter, context, xml ) :
+ elems,
+
+ matcherOut = matcher ?
+ // If we have a postFinder, or filtered seed, or non-seed postFilter or preexisting results,
+ postFinder || ( seed ? preFilter : preexisting || postFilter ) ?
+
+ // ...intermediate processing is necessary
+ [] :
+
+ // ...otherwise use results directly
+ results :
+ matcherIn;
+
+ // Find primary matches
+ if ( matcher ) {
+ matcher( matcherIn, matcherOut, context, xml );
+ }
+
+ // Apply postFilter
+ if ( postFilter ) {
+ temp = condense( matcherOut, postMap );
+ postFilter( temp, [], context, xml );
+
+ // Un-match failing elements by moving them back to matcherIn
+ i = temp.length;
+ while ( i-- ) {
+ if ( (elem = temp[i]) ) {
+ matcherOut[ postMap[i] ] = !(matcherIn[ postMap[i] ] = elem);
+ }
+ }
+ }
+
+ if ( seed ) {
+ if ( postFinder || preFilter ) {
+ if ( postFinder ) {
+ // Get the final matcherOut by condensing this intermediate into postFinder contexts
+ temp = [];
+ i = matcherOut.length;
+ while ( i-- ) {
+ if ( (elem = matcherOut[i]) ) {
+ // Restore matcherIn since elem is not yet a final match
+ temp.push( (matcherIn[i] = elem) );
+ }
+ }
+ postFinder( null, (matcherOut = []), temp, xml );
+ }
+
+ // Move matched elements from seed to results to keep them synchronized
+ i = matcherOut.length;
+ while ( i-- ) {
+ if ( (elem = matcherOut[i]) &&
+ (temp = postFinder ? indexOf.call( seed, elem ) : preMap[i]) > -1 ) {
+
+ seed[temp] = !(results[temp] = elem);
+ }
+ }
+ }
+
+ // Add elements to results, through postFinder if defined
+ } else {
+ matcherOut = condense(
+ matcherOut === results ?
+ matcherOut.splice( preexisting, matcherOut.length ) :
+ matcherOut
+ );
+ if ( postFinder ) {
+ postFinder( null, results, matcherOut, xml );
+ } else {
+ push.apply( results, matcherOut );
+ }
+ }
+ });
+}
+
+function matcherFromTokens( tokens ) {
+ var checkContext, matcher, j,
+ len = tokens.length,
+ leadingRelative = Expr.relative[ tokens[0].type ],
+ implicitRelative = leadingRelative || Expr.relative[" "],
+ i = leadingRelative ? 1 : 0,
+
+ // The foundational matcher ensures that elements are reachable from top-level context(s)
+ matchContext = addCombinator( function( elem ) {
+ return elem === checkContext;
+ }, implicitRelative, true ),
+ matchAnyContext = addCombinator( function( elem ) {
+ return indexOf.call( checkContext, elem ) > -1;
+ }, implicitRelative, true ),
+ matchers = [ function( elem, context, xml ) {
+ return ( !leadingRelative && ( xml || context !== outermostContext ) ) || (
+ (checkContext = context).nodeType ?
+ matchContext( elem, context, xml ) :
+ matchAnyContext( elem, context, xml ) );
+ } ];
+
+ for ( ; i < len; i++ ) {
+ if ( (matcher = Expr.relative[ tokens[i].type ]) ) {
+ matchers = [ addCombinator(elementMatcher( matchers ), matcher) ];
+ } else {
+ matcher = Expr.filter[ tokens[i].type ].apply( null, tokens[i].matches );
+
+ // Return special upon seeing a positional matcher
+ if ( matcher[ expando ] ) {
+ // Find the next relative operator (if any) for proper handling
+ j = ++i;
+ for ( ; j < len; j++ ) {
+ if ( Expr.relative[ tokens[j].type ] ) {
+ break;
+ }
+ }
+ return setMatcher(
+ i > 1 && elementMatcher( matchers ),
+ i > 1 && toSelector(
+ // If the preceding token was a descendant combinator, insert an implicit any-element `*`
+ tokens.slice( 0, i - 1 ).concat({ value: tokens[ i - 2 ].type === " " ? "*" : "" })
+ ).replace( rtrim, "$1" ),
+ matcher,
+ i < j && matcherFromTokens( tokens.slice( i, j ) ),
+ j < len && matcherFromTokens( (tokens = tokens.slice( j )) ),
+ j < len && toSelector( tokens )
+ );
+ }
+ matchers.push( matcher );
+ }
+ }
+
+ return elementMatcher( matchers );
+}
+
+function matcherFromGroupMatchers( elementMatchers, setMatchers ) {
+ // A counter to specify which element is currently being matched
+ var matcherCachedRuns = 0,
+ bySet = setMatchers.length > 0,
+ byElement = elementMatchers.length > 0,
+ superMatcher = function( seed, context, xml, results, expandContext ) {
+ var elem, j, matcher,
+ setMatched = [],
+ matchedCount = 0,
+ i = "0",
+ unmatched = seed && [],
+ outermost = expandContext != null,
+ contextBackup = outermostContext,
+ // We must always have either seed elements or context
+ elems = seed || byElement && Expr.find["TAG"]( "*", expandContext && context.parentNode || context ),
+ // Use integer dirruns iff this is the outermost matcher
+ dirrunsUnique = (dirruns += contextBackup == null ? 1 : Math.random() || 0.1);
+
+ if ( outermost ) {
+ outermostContext = context !== document && context;
+ cachedruns = matcherCachedRuns;
+ }
+
+ // Add elements passing elementMatchers directly to results
+ // Keep `i` a string if there are no elements so `matchedCount` will be "00" below
+ for ( ; (elem = elems[i]) != null; i++ ) {
+ if ( byElement && elem ) {
+ j = 0;
+ while ( (matcher = elementMatchers[j++]) ) {
+ if ( matcher( elem, context, xml ) ) {
+ results.push( elem );
+ break;
+ }
+ }
+ if ( outermost ) {
+ dirruns = dirrunsUnique;
+ cachedruns = ++matcherCachedRuns;
+ }
+ }
+
+ // Track unmatched elements for set filters
+ if ( bySet ) {
+ // They will have gone through all possible matchers
+ if ( (elem = !matcher && elem) ) {
+ matchedCount--;
+ }
+
+ // Lengthen the array for every element, matched or not
+ if ( seed ) {
+ unmatched.push( elem );
+ }
+ }
+ }
+
+ // Apply set filters to unmatched elements
+ matchedCount += i;
+ if ( bySet && i !== matchedCount ) {
+ j = 0;
+ while ( (matcher = setMatchers[j++]) ) {
+ matcher( unmatched, setMatched, context, xml );
+ }
+
+ if ( seed ) {
+ // Reintegrate element matches to eliminate the need for sorting
+ if ( matchedCount > 0 ) {
+ while ( i-- ) {
+ if ( !(unmatched[i] || setMatched[i]) ) {
+ setMatched[i] = pop.call( results );
+ }
+ }
+ }
+
+ // Discard index placeholder values to get only actual matches
+ setMatched = condense( setMatched );
+ }
+
+ // Add matches to results
+ push.apply( results, setMatched );
+
+ // Seedless set matches succeeding multiple successful matchers stipulate sorting
+ if ( outermost && !seed && setMatched.length > 0 &&
+ ( matchedCount + setMatchers.length ) > 1 ) {
+
+ Sizzle.uniqueSort( results );
+ }
+ }
+
+ // Override manipulation of globals by nested matchers
+ if ( outermost ) {
+ dirruns = dirrunsUnique;
+ outermostContext = contextBackup;
+ }
+
+ return unmatched;
+ };
+
+ return bySet ?
+ markFunction( superMatcher ) :
+ superMatcher;
+}
+
+compile = Sizzle.compile = function( selector, group /* Internal Use Only */ ) {
+ var i,
+ setMatchers = [],
+ elementMatchers = [],
+ cached = compilerCache[ selector + " " ];
+
+ if ( !cached ) {
+ // Generate a function of recursive functions that can be used to check each element
+ if ( !group ) {
+ group = tokenize( selector );
+ }
+ i = group.length;
+ while ( i-- ) {
+ cached = matcherFromTokens( group[i] );
+ if ( cached[ expando ] ) {
+ setMatchers.push( cached );
+ } else {
+ elementMatchers.push( cached );
+ }
+ }
+
+ // Cache the compiled function
+ cached = compilerCache( selector, matcherFromGroupMatchers( elementMatchers, setMatchers ) );
+ }
+ return cached;
+};
+
+function multipleContexts( selector, contexts, results ) {
+ var i = 0,
+ len = contexts.length;
+ for ( ; i < len; i++ ) {
+ Sizzle( selector, contexts[i], results );
+ }
+ return results;
+}
+
+function select( selector, context, results, seed ) {
+ var i, tokens, token, type, find,
+ match = tokenize( selector );
+
+ if ( !seed ) {
+ // Try to minimize operations if there is only one group
+ if ( match.length === 1 ) {
+
+ // Take a shortcut and set the context if the root selector is an ID
+ tokens = match[0] = match[0].slice( 0 );
+ if ( tokens.length > 2 && (token = tokens[0]).type === "ID" &&
+ support.getById && context.nodeType === 9 && documentIsHTML &&
+ Expr.relative[ tokens[1].type ] ) {
+
+ context = ( Expr.find["ID"]( token.matches[0].replace(runescape, funescape), context ) || [] )[0];
+ if ( !context ) {
+ return results;
+ }
+ selector = selector.slice( tokens.shift().value.length );
+ }
+
+ // Fetch a seed set for right-to-left matching
+ i = matchExpr["needsContext"].test( selector ) ? 0 : tokens.length;
+ while ( i-- ) {
+ token = tokens[i];
+
+ // Abort if we hit a combinator
+ if ( Expr.relative[ (type = token.type) ] ) {
+ break;
+ }
+ if ( (find = Expr.find[ type ]) ) {
+ // Search, expanding context for leading sibling combinators
+ if ( (seed = find(
+ token.matches[0].replace( runescape, funescape ),
+ rsibling.test( tokens[0].type ) && context.parentNode || context
+ )) ) {
+
+ // If seed is empty or no tokens remain, we can return early
+ tokens.splice( i, 1 );
+ selector = seed.length && toSelector( tokens );
+ if ( !selector ) {
+ push.apply( results, seed );
+ return results;
+ }
+
+ break;
+ }
+ }
+ }
+ }
+ }
+
+ // Compile and execute a filtering function
+ // Provide `match` to avoid retokenization if we modified the selector above
+ compile( selector, match )(
+ seed,
+ context,
+ !documentIsHTML,
+ results,
+ rsibling.test( selector )
+ );
+ return results;
+}
+
+// One-time assignments
+
+// Sort stability
+support.sortStable = expando.split("").sort( sortOrder ).join("") === expando;
+
+// Support: Chrome<14
+// Always assume duplicates if they aren't passed to the comparison function
+support.detectDuplicates = hasDuplicate;
+
+// Initialize against the default document
+setDocument();
+
+// Support: Webkit<537.32 - Safari 6.0.3/Chrome 25 (fixed in Chrome 27)
+// Detached nodes confoundingly follow *each other*
+support.sortDetached = assert(function( div1 ) {
+ // Should return 1, but returns 4 (following)
+ return div1.compareDocumentPosition( document.createElement("div") ) & 1;
+});
+
+// Support: IE<8
+// Prevent attribute/property "interpolation"
+// http://msdn.microsoft.com/en-us/library/ms536429%28VS.85%29.aspx
+if ( !assert(function( div ) {
+ div.innerHTML = "<a href='#'></a>";
+ return div.firstChild.getAttribute("href") === "#" ;
+}) ) {
+ addHandle( "type|href|height|width", function( elem, name, isXML ) {
+ if ( !isXML ) {
+ return elem.getAttribute( name, name.toLowerCase() === "type" ? 1 : 2 );
+ }
+ });
+}
+
+// Support: IE<9
+// Use defaultValue in place of getAttribute("value")
+if ( !support.attributes || !assert(function( div ) {
+ div.innerHTML = "<input/>";
+ div.firstChild.setAttribute( "value", "" );
+ return div.firstChild.getAttribute( "value" ) === "";
+}) ) {
+ addHandle( "value", function( elem, name, isXML ) {
+ if ( !isXML && elem.nodeName.toLowerCase() === "input" ) {
+ return elem.defaultValue;
+ }
+ });
+}
+
+// Support: IE<9
+// Use getAttributeNode to fetch booleans when getAttribute lies
+if ( !assert(function( div ) {
+ return div.getAttribute("disabled") == null;
+}) ) {
+ addHandle( booleans, function( elem, name, isXML ) {
+ var val;
+ if ( !isXML ) {
+ return (val = elem.getAttributeNode( name )) && val.specified ?
+ val.value :
+ elem[ name ] === true ? name.toLowerCase() : null;
+ }
+ });
+}
+
+jQuery.find = Sizzle;
+jQuery.expr = Sizzle.selectors;
+jQuery.expr[":"] = jQuery.expr.pseudos;
+jQuery.unique = Sizzle.uniqueSort;
+jQuery.text = Sizzle.getText;
+jQuery.isXMLDoc = Sizzle.isXML;
+jQuery.contains = Sizzle.contains;
+
+
+})( window );
+// String to Object options format cache
+var optionsCache = {};
+
+// Convert String-formatted options into Object-formatted ones and store in cache
+function createOptions( options ) {
+ var object = optionsCache[ options ] = {};
+ jQuery.each( options.match( core_rnotwhite ) || [], function( _, flag ) {
+ object[ flag ] = true;
+ });
+ return object;
+}
+
+/*
+ * Create a callback list using the following parameters:
+ *
+ * options: an optional list of space-separated options that will change how
+ * the callback list behaves or a more traditional option object
+ *
+ * By default a callback list will act like an event callback list and can be
+ * "fired" multiple times.
+ *
+ * Possible options:
+ *
+ * once: will ensure the callback list can only be fired once (like a Deferred)
+ *
+ * memory: will keep track of previous values and will call any callback added
+ * after the list has been fired right away with the latest "memorized"
+ * values (like a Deferred)
+ *
+ * unique: will ensure a callback can only be added once (no duplicate in the list)
+ *
+ * stopOnFalse: interrupt callings when a callback returns false
+ *
+ */
+jQuery.Callbacks = function( options ) {
+
+ // Convert options from String-formatted to Object-formatted if needed
+ // (we check in cache first)
+ options = typeof options === "string" ?
+ ( optionsCache[ options ] || createOptions( options ) ) :
+ jQuery.extend( {}, options );
+
+ var // Flag to know if list is currently firing
+ firing,
+ // Last fire value (for non-forgettable lists)
+ memory,
+ // Flag to know if list was already fired
+ fired,
+ // End of the loop when firing
+ firingLength,
+ // Index of currently firing callback (modified by remove if needed)
+ firingIndex,
+ // First callback to fire (used internally by add and fireWith)
+ firingStart,
+ // Actual callback list
+ list = [],
+ // Stack of fire calls for repeatable lists
+ stack = !options.once && [],
+ // Fire callbacks
+ fire = function( data ) {
+ memory = options.memory && data;
+ fired = true;
+ firingIndex = firingStart || 0;
+ firingStart = 0;
+ firingLength = list.length;
+ firing = true;
+ for ( ; list && firingIndex < firingLength; firingIndex++ ) {
+ if ( list[ firingIndex ].apply( data[ 0 ], data[ 1 ] ) === false && options.stopOnFalse ) {
+ memory = false; // To prevent further calls using add
+ break;
+ }
+ }
+ firing = false;
+ if ( list ) {
+ if ( stack ) {
+ if ( stack.length ) {
+ fire( stack.shift() );
+ }
+ } else if ( memory ) {
+ list = [];
+ } else {
+ self.disable();
+ }
+ }
+ },
+ // Actual Callbacks object
+ self = {
+ // Add a callback or a collection of callbacks to the list
+ add: function() {
+ if ( list ) {
+ // First, we save the current length
+ var start = list.length;
+ (function add( args ) {
+ jQuery.each( args, function( _, arg ) {
+ var type = jQuery.type( arg );
+ if ( type === "function" ) {
+ if ( !options.unique || !self.has( arg ) ) {
+ list.push( arg );
+ }
+ } else if ( arg && arg.length && type !== "string" ) {
+ // Inspect recursively
+ add( arg );
+ }
+ });
+ })( arguments );
+ // Do we need to add the callbacks to the
+ // current firing batch?
+ if ( firing ) {
+ firingLength = list.length;
+ // With memory, if we're not firing then
+ // we should call right away
+ } else if ( memory ) {
+ firingStart = start;
+ fire( memory );
+ }
+ }
+ return this;
+ },
+ // Remove a callback from the list
+ remove: function() {
+ if ( list ) {
+ jQuery.each( arguments, function( _, arg ) {
+ var index;
+ while( ( index = jQuery.inArray( arg, list, index ) ) > -1 ) {
+ list.splice( index, 1 );
+ // Handle firing indexes
+ if ( firing ) {
+ if ( index <= firingLength ) {
+ firingLength--;
+ }
+ if ( index <= firingIndex ) {
+ firingIndex--;
+ }
+ }
+ }
+ });
+ }
+ return this;
+ },
+ // Check if a given callback is in the list.
+ // If no argument is given, return whether or not list has callbacks attached.
+ has: function( fn ) {
+ return fn ? jQuery.inArray( fn, list ) > -1 : !!( list && list.length );
+ },
+ // Remove all callbacks from the list
+ empty: function() {
+ list = [];
+ firingLength = 0;
+ return this;
+ },
+ // Have the list do nothing anymore
+ disable: function() {
+ list = stack = memory = undefined;
+ return this;
+ },
+ // Is it disabled?
+ disabled: function() {
+ return !list;
+ },
+ // Lock the list in its current state
+ lock: function() {
+ stack = undefined;
+ if ( !memory ) {
+ self.disable();
+ }
+ return this;
+ },
+ // Is it locked?
+ locked: function() {
+ return !stack;
+ },
+ // Call all callbacks with the given context and arguments
+ fireWith: function( context, args ) {
+ if ( list && ( !fired || stack ) ) {
+ args = args || [];
+ args = [ context, args.slice ? args.slice() : args ];
+ if ( firing ) {
+ stack.push( args );
+ } else {
+ fire( args );
+ }
+ }
+ return this;
+ },
+ // Call all the callbacks with the given arguments
+ fire: function() {
+ self.fireWith( this, arguments );
+ return this;
+ },
+ // To know if the callbacks have already been called at least once
+ fired: function() {
+ return !!fired;
+ }
+ };
+
+ return self;
+};
+jQuery.extend({
+
+ Deferred: function( func ) {
+ var tuples = [
+ // action, add listener, listener list, final state
+ [ "resolve", "done", jQuery.Callbacks("once memory"), "resolved" ],
+ [ "reject", "fail", jQuery.Callbacks("once memory"), "rejected" ],
+ [ "notify", "progress", jQuery.Callbacks("memory") ]
+ ],
+ state = "pending",
+ promise = {
+ state: function() {
+ return state;
+ },
+ always: function() {
+ deferred.done( arguments ).fail( arguments );
+ return this;
+ },
+ then: function( /* fnDone, fnFail, fnProgress */ ) {
+ var fns = arguments;
+ return jQuery.Deferred(function( newDefer ) {
+ jQuery.each( tuples, function( i, tuple ) {
+ var action = tuple[ 0 ],
+ fn = jQuery.isFunction( fns[ i ] ) && fns[ i ];
+ // deferred[ done | fail | progress ] for forwarding actions to newDefer
+ deferred[ tuple[1] ](function() {
+ var returned = fn && fn.apply( this, arguments );
+ if ( returned && jQuery.isFunction( returned.promise ) ) {
+ returned.promise()
+ .done( newDefer.resolve )
+ .fail( newDefer.reject )
+ .progress( newDefer.notify );
+ } else {
+ newDefer[ action + "With" ]( this === promise ? newDefer.promise() : this, fn ? [ returned ] : arguments );
+ }
+ });
+ });
+ fns = null;
+ }).promise();
+ },
+ // Get a promise for this deferred
+ // If obj is provided, the promise aspect is added to the object
+ promise: function( obj ) {
+ return obj != null ? jQuery.extend( obj, promise ) : promise;
+ }
+ },
+ deferred = {};
+
+ // Keep pipe for back-compat
+ promise.pipe = promise.then;
+
+ // Add list-specific methods
+ jQuery.each( tuples, function( i, tuple ) {
+ var list = tuple[ 2 ],
+ stateString = tuple[ 3 ];
+
+ // promise[ done | fail | progress ] = list.add
+ promise[ tuple[1] ] = list.add;
+
+ // Handle state
+ if ( stateString ) {
+ list.add(function() {
+ // state = [ resolved | rejected ]
+ state = stateString;
+
+ // [ reject_list | resolve_list ].disable; progress_list.lock
+ }, tuples[ i ^ 1 ][ 2 ].disable, tuples[ 2 ][ 2 ].lock );
+ }
+
+ // deferred[ resolve | reject | notify ]
+ deferred[ tuple[0] ] = function() {
+ deferred[ tuple[0] + "With" ]( this === deferred ? promise : this, arguments );
+ return this;
+ };
+ deferred[ tuple[0] + "With" ] = list.fireWith;
+ });
+
+ // Make the deferred a promise
+ promise.promise( deferred );
+
+ // Call given func if any
+ if ( func ) {
+ func.call( deferred, deferred );
+ }
+
+ // All done!
+ return deferred;
+ },
+
+ // Deferred helper
+ when: function( subordinate /* , ..., subordinateN */ ) {
+ var i = 0,
+ resolveValues = core_slice.call( arguments ),
+ length = resolveValues.length,
+
+ // the count of uncompleted subordinates
+ remaining = length !== 1 || ( subordinate && jQuery.isFunction( subordinate.promise ) ) ? length : 0,
+
+ // the master Deferred. If resolveValues consist of only a single Deferred, just use that.
+ deferred = remaining === 1 ? subordinate : jQuery.Deferred(),
+
+ // Update function for both resolve and progress values
+ updateFunc = function( i, contexts, values ) {
+ return function( value ) {
+ contexts[ i ] = this;
+ values[ i ] = arguments.length > 1 ? core_slice.call( arguments ) : value;
+ if( values === progressValues ) {
+ deferred.notifyWith( contexts, values );
+ } else if ( !( --remaining ) ) {
+ deferred.resolveWith( contexts, values );
+ }
+ };
+ },
+
+ progressValues, progressContexts, resolveContexts;
+
+ // add listeners to Deferred subordinates; treat others as resolved
+ if ( length > 1 ) {
+ progressValues = new Array( length );
+ progressContexts = new Array( length );
+ resolveContexts = new Array( length );
+ for ( ; i < length; i++ ) {
+ if ( resolveValues[ i ] && jQuery.isFunction( resolveValues[ i ].promise ) ) {
+ resolveValues[ i ].promise()
+ .done( updateFunc( i, resolveContexts, resolveValues ) )
+ .fail( deferred.reject )
+ .progress( updateFunc( i, progressContexts, progressValues ) );
+ } else {
+ --remaining;
+ }
+ }
+ }
+
+ // if we're not waiting on anything, resolve the master
+ if ( !remaining ) {
+ deferred.resolveWith( resolveContexts, resolveValues );
+ }
+
+ return deferred.promise();
+ }
+});
+jQuery.support = (function( support ) {
+
+ var all, a, input, select, fragment, opt, eventName, isSupported, i,
+ div = document.createElement("div");
+
+ // Setup
+ div.setAttribute( "className", "t" );
+ div.innerHTML = " <link/><table></table><a href='/a'>a</a><input type='checkbox'/>";
+
+ // Finish early in limited (non-browser) environments
+ all = div.getElementsByTagName("*") || [];
+ a = div.getElementsByTagName("a")[ 0 ];
+ if ( !a || !a.style || !all.length ) {
+ return support;
+ }
+
+ // First batch of tests
+ select = document.createElement("select");
+ opt = select.appendChild( document.createElement("option") );
+ input = div.getElementsByTagName("input")[ 0 ];
+
+ a.style.cssText = "top:1px;float:left;opacity:.5";
+
+ // Test setAttribute on camelCase class. If it works, we need attrFixes when doing get/setAttribute (ie6/7)
+ support.getSetAttribute = div.className !== "t";
+
+ // IE strips leading whitespace when .innerHTML is used
+ support.leadingWhitespace = div.firstChild.nodeType === 3;
+
+ // Make sure that tbody elements aren't automatically inserted
+ // IE will insert them into empty tables
+ support.tbody = !div.getElementsByTagName("tbody").length;
+
+ // Make sure that link elements get serialized correctly by innerHTML
+ // This requires a wrapper element in IE
+ support.htmlSerialize = !!div.getElementsByTagName("link").length;
+
+ // Get the style information from getAttribute
+ // (IE uses .cssText instead)
+ support.style = /top/.test( a.getAttribute("style") );
+
+ // Make sure that URLs aren't manipulated
+ // (IE normalizes it by default)
+ support.hrefNormalized = a.getAttribute("href") === "/a";
+
+ // Make sure that element opacity exists
+ // (IE uses filter instead)
+ // Use a regex to work around a WebKit issue. See #5145
+ support.opacity = /^0.5/.test( a.style.opacity );
+
+ // Verify style float existence
+ // (IE uses styleFloat instead of cssFloat)
+ support.cssFloat = !!a.style.cssFloat;
+
+ // Check the default checkbox/radio value ("" on WebKit; "on" elsewhere)
+ support.checkOn = !!input.value;
+
+ // Make sure that a selected-by-default option has a working selected property.
+ // (WebKit defaults to false instead of true, IE too, if it's in an optgroup)
+ support.optSelected = opt.selected;
+
+ // Tests for enctype support on a form (#6743)
+ support.enctype = !!document.createElement("form").enctype;
+
+ // Makes sure cloning an html5 element does not cause problems
+ // Where outerHTML is undefined, this still works
+ support.html5Clone = document.createElement("nav").cloneNode( true ).outerHTML !== "<:nav></:nav>";
+
+ // Will be defined later
+ support.inlineBlockNeedsLayout = false;
+ support.shrinkWrapBlocks = false;
+ support.pixelPosition = false;
+ support.deleteExpando = true;
+ support.noCloneEvent = true;
+ support.reliableMarginRight = true;
+ support.boxSizingReliable = true;
+
+ // Make sure checked status is properly cloned
+ input.checked = true;
+ support.noCloneChecked = input.cloneNode( true ).checked;
+
+ // Make sure that the options inside disabled selects aren't marked as disabled
+ // (WebKit marks them as disabled)
+ select.disabled = true;
+ support.optDisabled = !opt.disabled;
+
+ // Support: IE<9
+ try {
+ delete div.test;
+ } catch( e ) {
+ support.deleteExpando = false;
+ }
+
+ // Check if we can trust getAttribute("value")
+ input = document.createElement("input");
+ input.setAttribute( "value", "" );
+ support.input = input.getAttribute( "value" ) === "";
+
+ // Check if an input maintains its value after becoming a radio
+ input.value = "t";
+ input.setAttribute( "type", "radio" );
+ support.radioValue = input.value === "t";
+
+ // #11217 - WebKit loses check when the name is after the checked attribute
+ input.setAttribute( "checked", "t" );
+ input.setAttribute( "name", "t" );
+
+ fragment = document.createDocumentFragment();
+ fragment.appendChild( input );
+
+ // Check if a disconnected checkbox will retain its checked
+ // value of true after appended to the DOM (IE6/7)
+ support.appendChecked = input.checked;
+
+ // WebKit doesn't clone checked state correctly in fragments
+ support.checkClone = fragment.cloneNode( true ).cloneNode( true ).lastChild.checked;
+
+ // Support: IE<9
+ // Opera does not clone events (and typeof div.attachEvent === undefined).
+ // IE9-10 clones events bound via attachEvent, but they don't trigger with .click()
+ if ( div.attachEvent ) {
+ div.attachEvent( "onclick", function() {
+ support.noCloneEvent = false;
+ });
+
+ div.cloneNode( true ).click();
+ }
+
+ // Support: IE<9 (lack submit/change bubble), Firefox 17+ (lack focusin event)
+ // Beware of CSP restrictions (https://developer.mozilla.org/en/Security/CSP)
+ for ( i in { submit: true, change: true, focusin: true }) {
+ div.setAttribute( eventName = "on" + i, "t" );
+
+ support[ i + "Bubbles" ] = eventName in window || div.attributes[ eventName ].expando === false;
+ }
+
+ div.style.backgroundClip = "content-box";
+ div.cloneNode( true ).style.backgroundClip = "";
+ support.clearCloneStyle = div.style.backgroundClip === "content-box";
+
+ // Support: IE<9
+ // Iteration over object's inherited properties before its own.
+ for ( i in jQuery( support ) ) {
+ break;
+ }
+ support.ownLast = i !== "0";
+
+ // Run tests that need a body at doc ready
+ jQuery(function() {
+ var container, marginDiv, tds,
+ divReset = "padding:0;margin:0;border:0;display:block;box-sizing:content-box;-moz-box-sizing:content-box;-webkit-box-sizing:content-box;",
+ body = document.getElementsByTagName("body")[0];
+
+ if ( !body ) {
+ // Return for frameset docs that don't have a body
+ return;
+ }
+
+ container = document.createElement("div");
+ container.style.cssText = "border:0;width:0;height:0;position:absolute;top:0;left:-9999px;margin-top:1px";
+
+ body.appendChild( container ).appendChild( div );
+
+ // Support: IE8
+ // Check if table cells still have offsetWidth/Height when they are set
+ // to display:none and there are still other visible table cells in a
+ // table row; if so, offsetWidth/Height are not reliable for use when
+ // determining if an element has been hidden directly using
+ // display:none (it is still safe to use offsets if a parent element is
+ // hidden; don safety goggles and see bug #4512 for more information).
+ div.innerHTML = "<table><tr><td></td><td>t</td></tr></table>";
+ tds = div.getElementsByTagName("td");
+ tds[ 0 ].style.cssText = "padding:0;margin:0;border:0;display:none";
+ isSupported = ( tds[ 0 ].offsetHeight === 0 );
+
+ tds[ 0 ].style.display = "";
+ tds[ 1 ].style.display = "none";
+
+ // Support: IE8
+ // Check if empty table cells still have offsetWidth/Height
+ support.reliableHiddenOffsets = isSupported && ( tds[ 0 ].offsetHeight === 0 );
+
+ // Check box-sizing and margin behavior.
+ div.innerHTML = "";
+ div.style.cssText = "box-sizing:border-box;-moz-box-sizing:border-box;-webkit-box-sizing:border-box;padding:1px;border:1px;display:block;width:4px;margin-top:1%;position:absolute;top:1%;";
+
+ // Workaround failing boxSizing test due to offsetWidth returning wrong value
+ // with some non-1 values of body zoom, ticket #13543
+ jQuery.swap( body, body.style.zoom != null ? { zoom: 1 } : {}, function() {
+ support.boxSizing = div.offsetWidth === 4;
+ });
+
+ // Use window.getComputedStyle because jsdom on node.js will break without it.
+ if ( window.getComputedStyle ) {
+ support.pixelPosition = ( window.getComputedStyle( div, null ) || {} ).top !== "1%";
+ support.boxSizingReliable = ( window.getComputedStyle( div, null ) || { width: "4px" } ).width === "4px";
+
+ // Check if div with explicit width and no margin-right incorrectly
+ // gets computed margin-right based on width of container. (#3333)
+ // Fails in WebKit before Feb 2011 nightlies
+ // WebKit Bug 13343 - getComputedStyle returns wrong value for margin-right
+ marginDiv = div.appendChild( document.createElement("div") );
+ marginDiv.style.cssText = div.style.cssText = divReset;
+ marginDiv.style.marginRight = marginDiv.style.width = "0";
+ div.style.width = "1px";
+
+ support.reliableMarginRight =
+ !parseFloat( ( window.getComputedStyle( marginDiv, null ) || {} ).marginRight );
+ }
+
+ if ( typeof div.style.zoom !== core_strundefined ) {
+ // Support: IE<8
+ // Check if natively block-level elements act like inline-block
+ // elements when setting their display to 'inline' and giving
+ // them layout
+ div.innerHTML = "";
+ div.style.cssText = divReset + "width:1px;padding:1px;display:inline;zoom:1";
+ support.inlineBlockNeedsLayout = ( div.offsetWidth === 3 );
+
+ // Support: IE6
+ // Check if elements with layout shrink-wrap their children
+ div.style.display = "block";
+ div.innerHTML = "<div></div>";
+ div.firstChild.style.width = "5px";
+ support.shrinkWrapBlocks = ( div.offsetWidth !== 3 );
+
+ if ( support.inlineBlockNeedsLayout ) {
+ // Prevent IE 6 from affecting layout for positioned elements #11048
+ // Prevent IE from shrinking the body in IE 7 mode #12869
+ // Support: IE<8
+ body.style.zoom = 1;
+ }
+ }
+
+ body.removeChild( container );
+
+ // Null elements to avoid leaks in IE
+ container = div = tds = marginDiv = null;
+ });
+
+ // Null elements to avoid leaks in IE
+ all = select = fragment = opt = a = input = null;
+
+ return support;
+})({});
+
+var rbrace = /(?:\{[\s\S]*\}|\[[\s\S]*\])$/,
+ rmultiDash = /([A-Z])/g;
+
+function internalData( elem, name, data, pvt /* Internal Use Only */ ){
+ if ( !jQuery.acceptData( elem ) ) {
+ return;
+ }
+
+ var ret, thisCache,
+ internalKey = jQuery.expando,
+
+ // We have to handle DOM nodes and JS objects differently because IE6-7
+ // can't GC object references properly across the DOM-JS boundary
+ isNode = elem.nodeType,
+
+ // Only DOM nodes need the global jQuery cache; JS object data is
+ // attached directly to the object so GC can occur automatically
+ cache = isNode ? jQuery.cache : elem,
+
+ // Only defining an ID for JS objects if its cache already exists allows
+ // the code to shortcut on the same path as a DOM node with no cache
+ id = isNode ? elem[ internalKey ] : elem[ internalKey ] && internalKey;
+
+ // Avoid doing any more work than we need to when trying to get data on an
+ // object that has no data at all
+ if ( (!id || !cache[id] || (!pvt && !cache[id].data)) && data === undefined && typeof name === "string" ) {
+ return;
+ }
+
+ if ( !id ) {
+ // Only DOM nodes need a new unique ID for each element since their data
+ // ends up in the global cache
+ if ( isNode ) {
+ id = elem[ internalKey ] = core_deletedIds.pop() || jQuery.guid++;
+ } else {
+ id = internalKey;
+ }
+ }
+
+ if ( !cache[ id ] ) {
+ // Avoid exposing jQuery metadata on plain JS objects when the object
+ // is serialized using JSON.stringify
+ cache[ id ] = isNode ? {} : { toJSON: jQuery.noop };
+ }
+
+ // An object can be passed to jQuery.data instead of a key/value pair; this gets
+ // shallow copied over onto the existing cache
+ if ( typeof name === "object" || typeof name === "function" ) {
+ if ( pvt ) {
+ cache[ id ] = jQuery.extend( cache[ id ], name );
+ } else {
+ cache[ id ].data = jQuery.extend( cache[ id ].data, name );
+ }
+ }
+
+ thisCache = cache[ id ];
+
+ // jQuery data() is stored in a separate object inside the object's internal data
+ // cache in order to avoid key collisions between internal data and user-defined
+ // data.
+ if ( !pvt ) {
+ if ( !thisCache.data ) {
+ thisCache.data = {};
+ }
+
+ thisCache = thisCache.data;
+ }
+
+ if ( data !== undefined ) {
+ thisCache[ jQuery.camelCase( name ) ] = data;
+ }
+
+ // Check for both converted-to-camel and non-converted data property names
+ // If a data property was specified
+ if ( typeof name === "string" ) {
+
+ // First Try to find as-is property data
+ ret = thisCache[ name ];
+
+ // Test for null|undefined property data
+ if ( ret == null ) {
+
+ // Try to find the camelCased property
+ ret = thisCache[ jQuery.camelCase( name ) ];
+ }
+ } else {
+ ret = thisCache;
+ }
+
+ return ret;
+}
+
+function internalRemoveData( elem, name, pvt ) {
+ if ( !jQuery.acceptData( elem ) ) {
+ return;
+ }
+
+ var thisCache, i,
+ isNode = elem.nodeType,
+
+ // See jQuery.data for more information
+ cache = isNode ? jQuery.cache : elem,
+ id = isNode ? elem[ jQuery.expando ] : jQuery.expando;
+
+ // If there is already no cache entry for this object, there is no
+ // purpose in continuing
+ if ( !cache[ id ] ) {
+ return;
+ }
+
+ if ( name ) {
+
+ thisCache = pvt ? cache[ id ] : cache[ id ].data;
+
+ if ( thisCache ) {
+
+ // Support array or space separated string names for data keys
+ if ( !jQuery.isArray( name ) ) {
+
+ // try the string as a key before any manipulation
+ if ( name in thisCache ) {
+ name = [ name ];
+ } else {
+
+ // split the camel cased version by spaces unless a key with the spaces exists
+ name = jQuery.camelCase( name );
+ if ( name in thisCache ) {
+ name = [ name ];
+ } else {
+ name = name.split(" ");
+ }
+ }
+ } else {
+ // If "name" is an array of keys...
+ // When data is initially created, via ("key", "val") signature,
+ // keys will be converted to camelCase.
+ // Since there is no way to tell _how_ a key was added, remove
+ // both plain key and camelCase key. #12786
+ // This will only penalize the array argument path.
+ name = name.concat( jQuery.map( name, jQuery.camelCase ) );
+ }
+
+ i = name.length;
+ while ( i-- ) {
+ delete thisCache[ name[i] ];
+ }
+
+ // If there is no data left in the cache, we want to continue
+ // and let the cache object itself get destroyed
+ if ( pvt ? !isEmptyDataObject(thisCache) : !jQuery.isEmptyObject(thisCache) ) {
+ return;
+ }
+ }
+ }
+
+ // See jQuery.data for more information
+ if ( !pvt ) {
+ delete cache[ id ].data;
+
+ // Don't destroy the parent cache unless the internal data object
+ // had been the only thing left in it
+ if ( !isEmptyDataObject( cache[ id ] ) ) {
+ return;
+ }
+ }
+
+ // Destroy the cache
+ if ( isNode ) {
+ jQuery.cleanData( [ elem ], true );
+
+ // Use delete when supported for expandos or `cache` is not a window per isWindow (#10080)
+ /* jshint eqeqeq: false */
+ } else if ( jQuery.support.deleteExpando || cache != cache.window ) {
+ /* jshint eqeqeq: true */
+ delete cache[ id ];
+
+ // When all else fails, null
+ } else {
+ cache[ id ] = null;
+ }
+}
+
+jQuery.extend({
+ cache: {},
+
+ // The following elements throw uncatchable exceptions if you
+ // attempt to add expando properties to them.
+ noData: {
+ "applet": true,
+ "embed": true,
+ // Ban all objects except for Flash (which handle expandos)
+ "object": "clsid:D27CDB6E-AE6D-11cf-96B8-444553540000"
+ },
+
+ hasData: function( elem ) {
+ elem = elem.nodeType ? jQuery.cache[ elem[jQuery.expando] ] : elem[ jQuery.expando ];
+ return !!elem && !isEmptyDataObject( elem );
+ },
+
+ data: function( elem, name, data ) {
+ return internalData( elem, name, data );
+ },
+
+ removeData: function( elem, name ) {
+ return internalRemoveData( elem, name );
+ },
+
+ // For internal use only.
+ _data: function( elem, name, data ) {
+ return internalData( elem, name, data, true );
+ },
+
+ _removeData: function( elem, name ) {
+ return internalRemoveData( elem, name, true );
+ },
+
+ // A method for determining if a DOM node can handle the data expando
+ acceptData: function( elem ) {
+ // Do not set data on non-element because it will not be cleared (#8335).
+ if ( elem.nodeType && elem.nodeType !== 1 && elem.nodeType !== 9 ) {
+ return false;
+ }
+
+ var noData = elem.nodeName && jQuery.noData[ elem.nodeName.toLowerCase() ];
+
+ // nodes accept data unless otherwise specified; rejection can be conditional
+ return !noData || noData !== true && elem.getAttribute("classid") === noData;
+ }
+});
+
+jQuery.fn.extend({
+ data: function( key, value ) {
+ var attrs, name,
+ data = null,
+ i = 0,
+ elem = this[0];
+
+ // Special expections of .data basically thwart jQuery.access,
+ // so implement the relevant behavior ourselves
+
+ // Gets all values
+ if ( key === undefined ) {
+ if ( this.length ) {
+ data = jQuery.data( elem );
+
+ if ( elem.nodeType === 1 && !jQuery._data( elem, "parsedAttrs" ) ) {
+ attrs = elem.attributes;
+ for ( ; i < attrs.length; i++ ) {
+ name = attrs[i].name;
+
+ if ( name.indexOf("data-") === 0 ) {
+ name = jQuery.camelCase( name.slice(5) );
+
+ dataAttr( elem, name, data[ name ] );
+ }
+ }
+ jQuery._data( elem, "parsedAttrs", true );
+ }
+ }
+
+ return data;
+ }
+
+ // Sets multiple values
+ if ( typeof key === "object" ) {
+ return this.each(function() {
+ jQuery.data( this, key );
+ });
+ }
+
+ return arguments.length > 1 ?
+
+ // Sets one value
+ this.each(function() {
+ jQuery.data( this, key, value );
+ }) :
+
+ // Gets one value
+ // Try to fetch any internally stored data first
+ elem ? dataAttr( elem, key, jQuery.data( elem, key ) ) : null;
+ },
+
+ removeData: function( key ) {
+ return this.each(function() {
+ jQuery.removeData( this, key );
+ });
+ }
+});
+
+function dataAttr( elem, key, data ) {
+ // If nothing was found internally, try to fetch any
+ // data from the HTML5 data-* attribute
+ if ( data === undefined && elem.nodeType === 1 ) {
+
+ var name = "data-" + key.replace( rmultiDash, "-$1" ).toLowerCase();
+
+ data = elem.getAttribute( name );
+
+ if ( typeof data === "string" ) {
+ try {
+ data = data === "true" ? true :
+ data === "false" ? false :
+ data === "null" ? null :
+ // Only convert to a number if it doesn't change the string
+ +data + "" === data ? +data :
+ rbrace.test( data ) ? jQuery.parseJSON( data ) :
+ data;
+ } catch( e ) {}
+
+ // Make sure we set the data so it isn't changed later
+ jQuery.data( elem, key, data );
+
+ } else {
+ data = undefined;
+ }
+ }
+
+ return data;
+}
+
+// checks a cache object for emptiness
+function isEmptyDataObject( obj ) {
+ var name;
+ for ( name in obj ) {
+
+ // if the public data object is empty, the private is still empty
+ if ( name === "data" && jQuery.isEmptyObject( obj[name] ) ) {
+ continue;
+ }
+ if ( name !== "toJSON" ) {
+ return false;
+ }
+ }
+
+ return true;
+}
+jQuery.extend({
+ queue: function( elem, type, data ) {
+ var queue;
+
+ if ( elem ) {
+ type = ( type || "fx" ) + "queue";
+ queue = jQuery._data( elem, type );
+
+ // Speed up dequeue by getting out quickly if this is just a lookup
+ if ( data ) {
+ if ( !queue || jQuery.isArray(data) ) {
+ queue = jQuery._data( elem, type, jQuery.makeArray(data) );
+ } else {
+ queue.push( data );
+ }
+ }
+ return queue || [];
+ }
+ },
+
+ dequeue: function( elem, type ) {
+ type = type || "fx";
+
+ var queue = jQuery.queue( elem, type ),
+ startLength = queue.length,
+ fn = queue.shift(),
+ hooks = jQuery._queueHooks( elem, type ),
+ next = function() {
+ jQuery.dequeue( elem, type );
+ };
+
+ // If the fx queue is dequeued, always remove the progress sentinel
+ if ( fn === "inprogress" ) {
+ fn = queue.shift();
+ startLength--;
+ }
+
+ if ( fn ) {
+
+ // Add a progress sentinel to prevent the fx queue from being
+ // automatically dequeued
+ if ( type === "fx" ) {
+ queue.unshift( "inprogress" );
+ }
+
+ // clear up the last queue stop function
+ delete hooks.stop;
+ fn.call( elem, next, hooks );
+ }
+
+ if ( !startLength && hooks ) {
+ hooks.empty.fire();
+ }
+ },
+
+ // not intended for public consumption - generates a queueHooks object, or returns the current one
+ _queueHooks: function( elem, type ) {
+ var key = type + "queueHooks";
+ return jQuery._data( elem, key ) || jQuery._data( elem, key, {
+ empty: jQuery.Callbacks("once memory").add(function() {
+ jQuery._removeData( elem, type + "queue" );
+ jQuery._removeData( elem, key );
+ })
+ });
+ }
+});
+
+jQuery.fn.extend({
+ queue: function( type, data ) {
+ var setter = 2;
+
+ if ( typeof type !== "string" ) {
+ data = type;
+ type = "fx";
+ setter--;
+ }
+
+ if ( arguments.length < setter ) {
+ return jQuery.queue( this[0], type );
+ }
+
+ return data === undefined ?
+ this :
+ this.each(function() {
+ var queue = jQuery.queue( this, type, data );
+
+ // ensure a hooks for this queue
+ jQuery._queueHooks( this, type );
+
+ if ( type === "fx" && queue[0] !== "inprogress" ) {
+ jQuery.dequeue( this, type );
+ }
+ });
+ },
+ dequeue: function( type ) {
+ return this.each(function() {
+ jQuery.dequeue( this, type );
+ });
+ },
+ // Based off of the plugin by Clint Helfers, with permission.
+ // http://blindsignals.com/index.php/2009/07/jquery-delay/
+ delay: function( time, type ) {
+ time = jQuery.fx ? jQuery.fx.speeds[ time ] || time : time;
+ type = type || "fx";
+
+ return this.queue( type, function( next, hooks ) {
+ var timeout = setTimeout( next, time );
+ hooks.stop = function() {
+ clearTimeout( timeout );
+ };
+ });
+ },
+ clearQueue: function( type ) {
+ return this.queue( type || "fx", [] );
+ },
+ // Get a promise resolved when queues of a certain type
+ // are emptied (fx is the type by default)
+ promise: function( type, obj ) {
+ var tmp,
+ count = 1,
+ defer = jQuery.Deferred(),
+ elements = this,
+ i = this.length,
+ resolve = function() {
+ if ( !( --count ) ) {
+ defer.resolveWith( elements, [ elements ] );
+ }
+ };
+
+ if ( typeof type !== "string" ) {
+ obj = type;
+ type = undefined;
+ }
+ type = type || "fx";
+
+ while( i-- ) {
+ tmp = jQuery._data( elements[ i ], type + "queueHooks" );
+ if ( tmp && tmp.empty ) {
+ count++;
+ tmp.empty.add( resolve );
+ }
+ }
+ resolve();
+ return defer.promise( obj );
+ }
+});
+var nodeHook, boolHook,
+ rclass = /[\t\r\n\f]/g,
+ rreturn = /\r/g,
+ rfocusable = /^(?:input|select|textarea|button|object)$/i,
+ rclickable = /^(?:a|area)$/i,
+ ruseDefault = /^(?:checked|selected)$/i,
+ getSetAttribute = jQuery.support.getSetAttribute,
+ getSetInput = jQuery.support.input;
+
+jQuery.fn.extend({
+ attr: function( name, value ) {
+ return jQuery.access( this, jQuery.attr, name, value, arguments.length > 1 );
+ },
+
+ removeAttr: function( name ) {
+ return this.each(function() {
+ jQuery.removeAttr( this, name );
+ });
+ },
+
+ prop: function( name, value ) {
+ return jQuery.access( this, jQuery.prop, name, value, arguments.length > 1 );
+ },
+
+ removeProp: function( name ) {
+ name = jQuery.propFix[ name ] || name;
+ return this.each(function() {
+ // try/catch handles cases where IE balks (such as removing a property on window)
+ try {
+ this[ name ] = undefined;
+ delete this[ name ];
+ } catch( e ) {}
+ });
+ },
+
+ addClass: function( value ) {
+ var classes, elem, cur, clazz, j,
+ i = 0,
+ len = this.length,
+ proceed = typeof value === "string" && value;
+
+ if ( jQuery.isFunction( value ) ) {
+ return this.each(function( j ) {
+ jQuery( this ).addClass( value.call( this, j, this.className ) );
+ });
+ }
+
+ if ( proceed ) {
+ // The disjunction here is for better compressibility (see removeClass)
+ classes = ( value || "" ).match( core_rnotwhite ) || [];
+
+ for ( ; i < len; i++ ) {
+ elem = this[ i ];
+ cur = elem.nodeType === 1 && ( elem.className ?
+ ( " " + elem.className + " " ).replace( rclass, " " ) :
+ " "
+ );
+
+ if ( cur ) {
+ j = 0;
+ while ( (clazz = classes[j++]) ) {
+ if ( cur.indexOf( " " + clazz + " " ) < 0 ) {
+ cur += clazz + " ";
+ }
+ }
+ elem.className = jQuery.trim( cur );
+
+ }
+ }
+ }
+
+ return this;
+ },
+
+ removeClass: function( value ) {
+ var classes, elem, cur, clazz, j,
+ i = 0,
+ len = this.length,
+ proceed = arguments.length === 0 || typeof value === "string" && value;
+
+ if ( jQuery.isFunction( value ) ) {
+ return this.each(function( j ) {
+ jQuery( this ).removeClass( value.call( this, j, this.className ) );
+ });
+ }
+ if ( proceed ) {
+ classes = ( value || "" ).match( core_rnotwhite ) || [];
+
+ for ( ; i < len; i++ ) {
+ elem = this[ i ];
+ // This expression is here for better compressibility (see addClass)
+ cur = elem.nodeType === 1 && ( elem.className ?
+ ( " " + elem.className + " " ).replace( rclass, " " ) :
+ ""
+ );
+
+ if ( cur ) {
+ j = 0;
+ while ( (clazz = classes[j++]) ) {
+ // Remove *all* instances
+ while ( cur.indexOf( " " + clazz + " " ) >= 0 ) {
+ cur = cur.replace( " " + clazz + " ", " " );
+ }
+ }
+ elem.className = value ? jQuery.trim( cur ) : "";
+ }
+ }
+ }
+
+ return this;
+ },
+
+ toggleClass: function( value, stateVal ) {
+ var type = typeof value;
+
+ if ( typeof stateVal === "boolean" && type === "string" ) {
+ return stateVal ? this.addClass( value ) : this.removeClass( value );
+ }
+
+ if ( jQuery.isFunction( value ) ) {
+ return this.each(function( i ) {
+ jQuery( this ).toggleClass( value.call(this, i, this.className, stateVal), stateVal );
+ });
+ }
+
+ return this.each(function() {
+ if ( type === "string" ) {
+ // toggle individual class names
+ var className,
+ i = 0,
+ self = jQuery( this ),
+ classNames = value.match( core_rnotwhite ) || [];
+
+ while ( (className = classNames[ i++ ]) ) {
+ // check each className given, space separated list
+ if ( self.hasClass( className ) ) {
+ self.removeClass( className );
+ } else {
+ self.addClass( className );
+ }
+ }
+
+ // Toggle whole class name
+ } else if ( type === core_strundefined || type === "boolean" ) {
+ if ( this.className ) {
+ // store className if set
+ jQuery._data( this, "__className__", this.className );
+ }
+
+ // If the element has a class name or if we're passed "false",
+ // then remove the whole classname (if there was one, the above saved it).
+ // Otherwise bring back whatever was previously saved (if anything),
+ // falling back to the empty string if nothing was stored.
+ this.className = this.className || value === false ? "" : jQuery._data( this, "__className__" ) || "";
+ }
+ });
+ },
+
+ hasClass: function( selector ) {
+ var className = " " + selector + " ",
+ i = 0,
+ l = this.length;
+ for ( ; i < l; i++ ) {
+ if ( this[i].nodeType === 1 && (" " + this[i].className + " ").replace(rclass, " ").indexOf( className ) >= 0 ) {
+ return true;
+ }
+ }
+
+ return false;
+ },
+
+ val: function( value ) {
+ var ret, hooks, isFunction,
+ elem = this[0];
+
+ if ( !arguments.length ) {
+ if ( elem ) {
+ hooks = jQuery.valHooks[ elem.type ] || jQuery.valHooks[ elem.nodeName.toLowerCase() ];
+
+ if ( hooks && "get" in hooks && (ret = hooks.get( elem, "value" )) !== undefined ) {
+ return ret;
+ }
+
+ ret = elem.value;
+
+ return typeof ret === "string" ?
+ // handle most common string cases
+ ret.replace(rreturn, "") :
+ // handle cases where value is null/undef or number
+ ret == null ? "" : ret;
+ }
+
+ return;
+ }
+
+ isFunction = jQuery.isFunction( value );
+
+ return this.each(function( i ) {
+ var val;
+
+ if ( this.nodeType !== 1 ) {
+ return;
+ }
+
+ if ( isFunction ) {
+ val = value.call( this, i, jQuery( this ).val() );
+ } else {
+ val = value;
+ }
+
+ // Treat null/undefined as ""; convert numbers to string
+ if ( val == null ) {
+ val = "";
+ } else if ( typeof val === "number" ) {
+ val += "";
+ } else if ( jQuery.isArray( val ) ) {
+ val = jQuery.map(val, function ( value ) {
+ return value == null ? "" : value + "";
+ });
+ }
+
+ hooks = jQuery.valHooks[ this.type ] || jQuery.valHooks[ this.nodeName.toLowerCase() ];
+
+ // If set returns undefined, fall back to normal setting
+ if ( !hooks || !("set" in hooks) || hooks.set( this, val, "value" ) === undefined ) {
+ this.value = val;
+ }
+ });
+ }
+});
+
+jQuery.extend({
+ valHooks: {
+ option: {
+ get: function( elem ) {
+ // Use proper attribute retrieval(#6932, #12072)
+ var val = jQuery.find.attr( elem, "value" );
+ return val != null ?
+ val :
+ elem.text;
+ }
+ },
+ select: {
+ get: function( elem ) {
+ var value, option,
+ options = elem.options,
+ index = elem.selectedIndex,
+ one = elem.type === "select-one" || index < 0,
+ values = one ? null : [],
+ max = one ? index + 1 : options.length,
+ i = index < 0 ?
+ max :
+ one ? index : 0;
+
+ // Loop through all the selected options
+ for ( ; i < max; i++ ) {
+ option = options[ i ];
+
+ // oldIE doesn't update selected after form reset (#2551)
+ if ( ( option.selected || i === index ) &&
+ // Don't return options that are disabled or in a disabled optgroup
+ ( jQuery.support.optDisabled ? !option.disabled : option.getAttribute("disabled") === null ) &&
+ ( !option.parentNode.disabled || !jQuery.nodeName( option.parentNode, "optgroup" ) ) ) {
+
+ // Get the specific value for the option
+ value = jQuery( option ).val();
+
+ // We don't need an array for one selects
+ if ( one ) {
+ return value;
+ }
+
+ // Multi-Selects return an array
+ values.push( value );
+ }
+ }
+
+ return values;
+ },
+
+ set: function( elem, value ) {
+ var optionSet, option,
+ options = elem.options,
+ values = jQuery.makeArray( value ),
+ i = options.length;
+
+ while ( i-- ) {
+ option = options[ i ];
+ if ( (option.selected = jQuery.inArray( jQuery(option).val(), values ) >= 0) ) {
+ optionSet = true;
+ }
+ }
+
+ // force browsers to behave consistently when non-matching value is set
+ if ( !optionSet ) {
+ elem.selectedIndex = -1;
+ }
+ return values;
+ }
+ }
+ },
+
+ attr: function( elem, name, value ) {
+ var hooks, ret,
+ nType = elem.nodeType;
+
+ // don't get/set attributes on text, comment and attribute nodes
+ if ( !elem || nType === 3 || nType === 8 || nType === 2 ) {
+ return;
+ }
+
+ // Fallback to prop when attributes are not supported
+ if ( typeof elem.getAttribute === core_strundefined ) {
+ return jQuery.prop( elem, name, value );
+ }
+
+ // All attributes are lowercase
+ // Grab necessary hook if one is defined
+ if ( nType !== 1 || !jQuery.isXMLDoc( elem ) ) {
+ name = name.toLowerCase();
+ hooks = jQuery.attrHooks[ name ] ||
+ ( jQuery.expr.match.bool.test( name ) ? boolHook : nodeHook );
+ }
+
+ if ( value !== undefined ) {
+
+ if ( value === null ) {
+ jQuery.removeAttr( elem, name );
+
+ } else if ( hooks && "set" in hooks && (ret = hooks.set( elem, value, name )) !== undefined ) {
+ return ret;
+
+ } else {
+ elem.setAttribute( name, value + "" );
+ return value;
+ }
+
+ } else if ( hooks && "get" in hooks && (ret = hooks.get( elem, name )) !== null ) {
+ return ret;
+
+ } else {
+ ret = jQuery.find.attr( elem, name );
+
+ // Non-existent attributes return null, we normalize to undefined
+ return ret == null ?
+ undefined :
+ ret;
+ }
+ },
+
+ removeAttr: function( elem, value ) {
+ var name, propName,
+ i = 0,
+ attrNames = value && value.match( core_rnotwhite );
+
+ if ( attrNames && elem.nodeType === 1 ) {
+ while ( (name = attrNames[i++]) ) {
+ propName = jQuery.propFix[ name ] || name;
+
+ // Boolean attributes get special treatment (#10870)
+ if ( jQuery.expr.match.bool.test( name ) ) {
+ // Set corresponding property to false
+ if ( getSetInput && getSetAttribute || !ruseDefault.test( name ) ) {
+ elem[ propName ] = false;
+ // Support: IE<9
+ // Also clear defaultChecked/defaultSelected (if appropriate)
+ } else {
+ elem[ jQuery.camelCase( "default-" + name ) ] =
+ elem[ propName ] = false;
+ }
+
+ // See #9699 for explanation of this approach (setting first, then removal)
+ } else {
+ jQuery.attr( elem, name, "" );
+ }
+
+ elem.removeAttribute( getSetAttribute ? name : propName );
+ }
+ }
+ },
+
+ attrHooks: {
+ type: {
+ set: function( elem, value ) {
+ if ( !jQuery.support.radioValue && value === "radio" && jQuery.nodeName(elem, "input") ) {
+ // Setting the type on a radio button after the value resets the value in IE6-9
+ // Reset value to default in case type is set after value during creation
+ var val = elem.value;
+ elem.setAttribute( "type", value );
+ if ( val ) {
+ elem.value = val;
+ }
+ return value;
+ }
+ }
+ }
+ },
+
+ propFix: {
+ "for": "htmlFor",
+ "class": "className"
+ },
+
+ prop: function( elem, name, value ) {
+ var ret, hooks, notxml,
+ nType = elem.nodeType;
+
+ // don't get/set properties on text, comment and attribute nodes
+ if ( !elem || nType === 3 || nType === 8 || nType === 2 ) {
+ return;
+ }
+
+ notxml = nType !== 1 || !jQuery.isXMLDoc( elem );
+
+ if ( notxml ) {
+ // Fix name and attach hooks
+ name = jQuery.propFix[ name ] || name;
+ hooks = jQuery.propHooks[ name ];
+ }
+
+ if ( value !== undefined ) {
+ return hooks && "set" in hooks && (ret = hooks.set( elem, value, name )) !== undefined ?
+ ret :
+ ( elem[ name ] = value );
+
+ } else {
+ return hooks && "get" in hooks && (ret = hooks.get( elem, name )) !== null ?
+ ret :
+ elem[ name ];
+ }
+ },
+
+ propHooks: {
+ tabIndex: {
+ get: function( elem ) {
+ // elem.tabIndex doesn't always return the correct value when it hasn't been explicitly set
+ // http://fluidproject.org/blog/2008/01/09/getting-setting-and-removing-tabindex-values-with-javascript/
+ // Use proper attribute retrieval(#12072)
+ var tabindex = jQuery.find.attr( elem, "tabindex" );
+
+ return tabindex ?
+ parseInt( tabindex, 10 ) :
+ rfocusable.test( elem.nodeName ) || rclickable.test( elem.nodeName ) && elem.href ?
+ 0 :
+ -1;
+ }
+ }
+ }
+});
+
+// Hooks for boolean attributes
+boolHook = {
+ set: function( elem, value, name ) {
+ if ( value === false ) {
+ // Remove boolean attributes when set to false
+ jQuery.removeAttr( elem, name );
+ } else if ( getSetInput && getSetAttribute || !ruseDefault.test( name ) ) {
+ // IE<8 needs the *property* name
+ elem.setAttribute( !getSetAttribute && jQuery.propFix[ name ] || name, name );
+
+ // Use defaultChecked and defaultSelected for oldIE
+ } else {
+ elem[ jQuery.camelCase( "default-" + name ) ] = elem[ name ] = true;
+ }
+
+ return name;
+ }
+};
+jQuery.each( jQuery.expr.match.bool.source.match( /\w+/g ), function( i, name ) {
+ var getter = jQuery.expr.attrHandle[ name ] || jQuery.find.attr;
+
+ jQuery.expr.attrHandle[ name ] = getSetInput && getSetAttribute || !ruseDefault.test( name ) ?
+ function( elem, name, isXML ) {
+ var fn = jQuery.expr.attrHandle[ name ],
+ ret = isXML ?
+ undefined :
+ /* jshint eqeqeq: false */
+ (jQuery.expr.attrHandle[ name ] = undefined) !=
+ getter( elem, name, isXML ) ?
+
+ name.toLowerCase() :
+ null;
+ jQuery.expr.attrHandle[ name ] = fn;
+ return ret;
+ } :
+ function( elem, name, isXML ) {
+ return isXML ?
+ undefined :
+ elem[ jQuery.camelCase( "default-" + name ) ] ?
+ name.toLowerCase() :
+ null;
+ };
+});
+
+// fix oldIE attroperties
+if ( !getSetInput || !getSetAttribute ) {
+ jQuery.attrHooks.value = {
+ set: function( elem, value, name ) {
+ if ( jQuery.nodeName( elem, "input" ) ) {
+ // Does not return so that setAttribute is also used
+ elem.defaultValue = value;
+ } else {
+ // Use nodeHook if defined (#1954); otherwise setAttribute is fine
+ return nodeHook && nodeHook.set( elem, value, name );
+ }
+ }
+ };
+}
+
+// IE6/7 do not support getting/setting some attributes with get/setAttribute
+if ( !getSetAttribute ) {
+
+ // Use this for any attribute in IE6/7
+ // This fixes almost every IE6/7 issue
+ nodeHook = {
+ set: function( elem, value, name ) {
+ // Set the existing or create a new attribute node
+ var ret = elem.getAttributeNode( name );
+ if ( !ret ) {
+ elem.setAttributeNode(
+ (ret = elem.ownerDocument.createAttribute( name ))
+ );
+ }
+
+ ret.value = value += "";
+
+ // Break association with cloned elements by also using setAttribute (#9646)
+ return name === "value" || value === elem.getAttribute( name ) ?
+ value :
+ undefined;
+ }
+ };
+ jQuery.expr.attrHandle.id = jQuery.expr.attrHandle.name = jQuery.expr.attrHandle.coords =
+ // Some attributes are constructed with empty-string values when not defined
+ function( elem, name, isXML ) {
+ var ret;
+ return isXML ?
+ undefined :
+ (ret = elem.getAttributeNode( name )) && ret.value !== "" ?
+ ret.value :
+ null;
+ };
+ jQuery.valHooks.button = {
+ get: function( elem, name ) {
+ var ret = elem.getAttributeNode( name );
+ return ret && ret.specified ?
+ ret.value :
+ undefined;
+ },
+ set: nodeHook.set
+ };
+
+ // Set contenteditable to false on removals(#10429)
+ // Setting to empty string throws an error as an invalid value
+ jQuery.attrHooks.contenteditable = {
+ set: function( elem, value, name ) {
+ nodeHook.set( elem, value === "" ? false : value, name );
+ }
+ };
+
+ // Set width and height to auto instead of 0 on empty string( Bug #8150 )
+ // This is for removals
+ jQuery.each([ "width", "height" ], function( i, name ) {
+ jQuery.attrHooks[ name ] = {
+ set: function( elem, value ) {
+ if ( value === "" ) {
+ elem.setAttribute( name, "auto" );
+ return value;
+ }
+ }
+ };
+ });
+}
+
+
+// Some attributes require a special call on IE
+// http://msdn.microsoft.com/en-us/library/ms536429%28VS.85%29.aspx
+if ( !jQuery.support.hrefNormalized ) {
+ // href/src property should get the full normalized URL (#10299/#12915)
+ jQuery.each([ "href", "src" ], function( i, name ) {
+ jQuery.propHooks[ name ] = {
+ get: function( elem ) {
+ return elem.getAttribute( name, 4 );
+ }
+ };
+ });
+}
+
+if ( !jQuery.support.style ) {
+ jQuery.attrHooks.style = {
+ get: function( elem ) {
+ // Return undefined in the case of empty string
+ // Note: IE uppercases css property names, but if we were to .toLowerCase()
+ // .cssText, that would destroy case senstitivity in URL's, like in "background"
+ return elem.style.cssText || undefined;
+ },
+ set: function( elem, value ) {
+ return ( elem.style.cssText = value + "" );
+ }
+ };
+}
+
+// Safari mis-reports the default selected property of an option
+// Accessing the parent's selectedIndex property fixes it
+if ( !jQuery.support.optSelected ) {
+ jQuery.propHooks.selected = {
+ get: function( elem ) {
+ var parent = elem.parentNode;
+
+ if ( parent ) {
+ parent.selectedIndex;
+
+ // Make sure that it also works with optgroups, see #5701
+ if ( parent.parentNode ) {
+ parent.parentNode.selectedIndex;
+ }
+ }
+ return null;
+ }
+ };
+}
+
+jQuery.each([
+ "tabIndex",
+ "readOnly",
+ "maxLength",
+ "cellSpacing",
+ "cellPadding",
+ "rowSpan",
+ "colSpan",
+ "useMap",
+ "frameBorder",
+ "contentEditable"
+], function() {
+ jQuery.propFix[ this.toLowerCase() ] = this;
+});
+
+// IE6/7 call enctype encoding
+if ( !jQuery.support.enctype ) {
+ jQuery.propFix.enctype = "encoding";
+}
+
+// Radios and checkboxes getter/setter
+jQuery.each([ "radio", "checkbox" ], function() {
+ jQuery.valHooks[ this ] = {
+ set: function( elem, value ) {
+ if ( jQuery.isArray( value ) ) {
+ return ( elem.checked = jQuery.inArray( jQuery(elem).val(), value ) >= 0 );
+ }
+ }
+ };
+ if ( !jQuery.support.checkOn ) {
+ jQuery.valHooks[ this ].get = function( elem ) {
+ // Support: Webkit
+ // "" is returned instead of "on" if a value isn't specified
+ return elem.getAttribute("value") === null ? "on" : elem.value;
+ };
+ }
+});
+var rformElems = /^(?:input|select|textarea)$/i,
+ rkeyEvent = /^key/,
+ rmouseEvent = /^(?:mouse|contextmenu)|click/,
+ rfocusMorph = /^(?:focusinfocus|focusoutblur)$/,
+ rtypenamespace = /^([^.]*)(?:\.(.+)|)$/;
+
+function returnTrue() {
+ return true;
+}
+
+function returnFalse() {
+ return false;
+}
+
+function safeActiveElement() {
+ try {
+ return document.activeElement;
+ } catch ( err ) { }
+}
+
+/*
+ * Helper functions for managing events -- not part of the public interface.
+ * Props to Dean Edwards' addEvent library for many of the ideas.
+ */
+jQuery.event = {
+
+ global: {},
+
+ add: function( elem, types, handler, data, selector ) {
+ var tmp, events, t, handleObjIn,
+ special, eventHandle, handleObj,
+ handlers, type, namespaces, origType,
+ elemData = jQuery._data( elem );
+
+ // Don't attach events to noData or text/comment nodes (but allow plain objects)
+ if ( !elemData ) {
+ return;
+ }
+
+ // Caller can pass in an object of custom data in lieu of the handler
+ if ( handler.handler ) {
+ handleObjIn = handler;
+ handler = handleObjIn.handler;
+ selector = handleObjIn.selector;
+ }
+
+ // Make sure that the handler has a unique ID, used to find/remove it later
+ if ( !handler.guid ) {
+ handler.guid = jQuery.guid++;
+ }
+
+ // Init the element's event structure and main handler, if this is the first
+ if ( !(events = elemData.events) ) {
+ events = elemData.events = {};
+ }
+ if ( !(eventHandle = elemData.handle) ) {
+ eventHandle = elemData.handle = function( e ) {
+ // Discard the second event of a jQuery.event.trigger() and
+ // when an event is called after a page has unloaded
+ return typeof jQuery !== core_strundefined && (!e || jQuery.event.triggered !== e.type) ?
+ jQuery.event.dispatch.apply( eventHandle.elem, arguments ) :
+ undefined;
+ };
+ // Add elem as a property of the handle fn to prevent a memory leak with IE non-native events
+ eventHandle.elem = elem;
+ }
+
+ // Handle multiple events separated by a space
+ types = ( types || "" ).match( core_rnotwhite ) || [""];
+ t = types.length;
+ while ( t-- ) {
+ tmp = rtypenamespace.exec( types[t] ) || [];
+ type = origType = tmp[1];
+ namespaces = ( tmp[2] || "" ).split( "." ).sort();
+
+ // There *must* be a type, no attaching namespace-only handlers
+ if ( !type ) {
+ continue;
+ }
+
+ // If event changes its type, use the special event handlers for the changed type
+ special = jQuery.event.special[ type ] || {};
+
+ // If selector defined, determine special event api type, otherwise given type
+ type = ( selector ? special.delegateType : special.bindType ) || type;
+
+ // Update special based on newly reset type
+ special = jQuery.event.special[ type ] || {};
+
+ // handleObj is passed to all event handlers
+ handleObj = jQuery.extend({
+ type: type,
+ origType: origType,
+ data: data,
+ handler: handler,
+ guid: handler.guid,
+ selector: selector,
+ needsContext: selector && jQuery.expr.match.needsContext.test( selector ),
+ namespace: namespaces.join(".")
+ }, handleObjIn );
+
+ // Init the event handler queue if we're the first
+ if ( !(handlers = events[ type ]) ) {
+ handlers = events[ type ] = [];
+ handlers.delegateCount = 0;
+
+ // Only use addEventListener/attachEvent if the special events handler returns false
+ if ( !special.setup || special.setup.call( elem, data, namespaces, eventHandle ) === false ) {
+ // Bind the global event handler to the element
+ if ( elem.addEventListener ) {
+ elem.addEventListener( type, eventHandle, false );
+
+ } else if ( elem.attachEvent ) {
+ elem.attachEvent( "on" + type, eventHandle );
+ }
+ }
+ }
+
+ if ( special.add ) {
+ special.add.call( elem, handleObj );
+
+ if ( !handleObj.handler.guid ) {
+ handleObj.handler.guid = handler.guid;
+ }
+ }
+
+ // Add to the element's handler list, delegates in front
+ if ( selector ) {
+ handlers.splice( handlers.delegateCount++, 0, handleObj );
+ } else {
+ handlers.push( handleObj );
+ }
+
+ // Keep track of which events have ever been used, for event optimization
+ jQuery.event.global[ type ] = true;
+ }
+
+ // Nullify elem to prevent memory leaks in IE
+ elem = null;
+ },
+
+ // Detach an event or set of events from an element
+ remove: function( elem, types, handler, selector, mappedTypes ) {
+ var j, handleObj, tmp,
+ origCount, t, events,
+ special, handlers, type,
+ namespaces, origType,
+ elemData = jQuery.hasData( elem ) && jQuery._data( elem );
+
+ if ( !elemData || !(events = elemData.events) ) {
+ return;
+ }
+
+ // Once for each type.namespace in types; type may be omitted
+ types = ( types || "" ).match( core_rnotwhite ) || [""];
+ t = types.length;
+ while ( t-- ) {
+ tmp = rtypenamespace.exec( types[t] ) || [];
+ type = origType = tmp[1];
+ namespaces = ( tmp[2] || "" ).split( "." ).sort();
+
+ // Unbind all events (on this namespace, if provided) for the element
+ if ( !type ) {
+ for ( type in events ) {
+ jQuery.event.remove( elem, type + types[ t ], handler, selector, true );
+ }
+ continue;
+ }
+
+ special = jQuery.event.special[ type ] || {};
+ type = ( selector ? special.delegateType : special.bindType ) || type;
+ handlers = events[ type ] || [];
+ tmp = tmp[2] && new RegExp( "(^|\\.)" + namespaces.join("\\.(?:.*\\.|)") + "(\\.|$)" );
+
+ // Remove matching events
+ origCount = j = handlers.length;
+ while ( j-- ) {
+ handleObj = handlers[ j ];
+
+ if ( ( mappedTypes || origType === handleObj.origType ) &&
+ ( !handler || handler.guid === handleObj.guid ) &&
+ ( !tmp || tmp.test( handleObj.namespace ) ) &&
+ ( !selector || selector === handleObj.selector || selector === "**" && handleObj.selector ) ) {
+ handlers.splice( j, 1 );
+
+ if ( handleObj.selector ) {
+ handlers.delegateCount--;
+ }
+ if ( special.remove ) {
+ special.remove.call( elem, handleObj );
+ }
+ }
+ }
+
+ // Remove generic event handler if we removed something and no more handlers exist
+ // (avoids potential for endless recursion during removal of special event handlers)
+ if ( origCount && !handlers.length ) {
+ if ( !special.teardown || special.teardown.call( elem, namespaces, elemData.handle ) === false ) {
+ jQuery.removeEvent( elem, type, elemData.handle );
+ }
+
+ delete events[ type ];
+ }
+ }
+
+ // Remove the expando if it's no longer used
+ if ( jQuery.isEmptyObject( events ) ) {
+ delete elemData.handle;
+
+ // removeData also checks for emptiness and clears the expando if empty
+ // so use it instead of delete
+ jQuery._removeData( elem, "events" );
+ }
+ },
+
+ trigger: function( event, data, elem, onlyHandlers ) {
+ var handle, ontype, cur,
+ bubbleType, special, tmp, i,
+ eventPath = [ elem || document ],
+ type = core_hasOwn.call( event, "type" ) ? event.type : event,
+ namespaces = core_hasOwn.call( event, "namespace" ) ? event.namespace.split(".") : [];
+
+ cur = tmp = elem = elem || document;
+
+ // Don't do events on text and comment nodes
+ if ( elem.nodeType === 3 || elem.nodeType === 8 ) {
+ return;
+ }
+
+ // focus/blur morphs to focusin/out; ensure we're not firing them right now
+ if ( rfocusMorph.test( type + jQuery.event.triggered ) ) {
+ return;
+ }
+
+ if ( type.indexOf(".") >= 0 ) {
+ // Namespaced trigger; create a regexp to match event type in handle()
+ namespaces = type.split(".");
+ type = namespaces.shift();
+ namespaces.sort();
+ }
+ ontype = type.indexOf(":") < 0 && "on" + type;
+
+ // Caller can pass in a jQuery.Event object, Object, or just an event type string
+ event = event[ jQuery.expando ] ?
+ event :
+ new jQuery.Event( type, typeof event === "object" && event );
+
+ // Trigger bitmask: & 1 for native handlers; & 2 for jQuery (always true)
+ event.isTrigger = onlyHandlers ? 2 : 3;
+ event.namespace = namespaces.join(".");
+ event.namespace_re = event.namespace ?
+ new RegExp( "(^|\\.)" + namespaces.join("\\.(?:.*\\.|)") + "(\\.|$)" ) :
+ null;
+
+ // Clean up the event in case it is being reused
+ event.result = undefined;
+ if ( !event.target ) {
+ event.target = elem;
+ }
+
+ // Clone any incoming data and prepend the event, creating the handler arg list
+ data = data == null ?
+ [ event ] :
+ jQuery.makeArray( data, [ event ] );
+
+ // Allow special events to draw outside the lines
+ special = jQuery.event.special[ type ] || {};
+ if ( !onlyHandlers && special.trigger && special.trigger.apply( elem, data ) === false ) {
+ return;
+ }
+
+ // Determine event propagation path in advance, per W3C events spec (#9951)
+ // Bubble up to document, then to window; watch for a global ownerDocument var (#9724)
+ if ( !onlyHandlers && !special.noBubble && !jQuery.isWindow( elem ) ) {
+
+ bubbleType = special.delegateType || type;
+ if ( !rfocusMorph.test( bubbleType + type ) ) {
+ cur = cur.parentNode;
+ }
+ for ( ; cur; cur = cur.parentNode ) {
+ eventPath.push( cur );
+ tmp = cur;
+ }
+
+ // Only add window if we got to document (e.g., not plain obj or detached DOM)
+ if ( tmp === (elem.ownerDocument || document) ) {
+ eventPath.push( tmp.defaultView || tmp.parentWindow || window );
+ }
+ }
+
+ // Fire handlers on the event path
+ i = 0;
+ while ( (cur = eventPath[i++]) && !event.isPropagationStopped() ) {
+
+ event.type = i > 1 ?
+ bubbleType :
+ special.bindType || type;
+
+ // jQuery handler
+ handle = ( jQuery._data( cur, "events" ) || {} )[ event.type ] && jQuery._data( cur, "handle" );
+ if ( handle ) {
+ handle.apply( cur, data );
+ }
+
+ // Native handler
+ handle = ontype && cur[ ontype ];
+ if ( handle && jQuery.acceptData( cur ) && handle.apply && handle.apply( cur, data ) === false ) {
+ event.preventDefault();
+ }
+ }
+ event.type = type;
+
+ // If nobody prevented the default action, do it now
+ if ( !onlyHandlers && !event.isDefaultPrevented() ) {
+
+ if ( (!special._default || special._default.apply( eventPath.pop(), data ) === false) &&
+ jQuery.acceptData( elem ) ) {
+
+ // Call a native DOM method on the target with the same name name as the event.
+ // Can't use an .isFunction() check here because IE6/7 fails that test.
+ // Don't do default actions on window, that's where global variables be (#6170)
+ if ( ontype && elem[ type ] && !jQuery.isWindow( elem ) ) {
+
+ // Don't re-trigger an onFOO event when we call its FOO() method
+ tmp = elem[ ontype ];
+
+ if ( tmp ) {
+ elem[ ontype ] = null;
+ }
+
+ // Prevent re-triggering of the same event, since we already bubbled it above
+ jQuery.event.triggered = type;
+ try {
+ elem[ type ]();
+ } catch ( e ) {
+ // IE<9 dies on focus/blur to hidden element (#1486,#12518)
+ // only reproducible on winXP IE8 native, not IE9 in IE8 mode
+ }
+ jQuery.event.triggered = undefined;
+
+ if ( tmp ) {
+ elem[ ontype ] = tmp;
+ }
+ }
+ }
+ }
+
+ return event.result;
+ },
+
+ dispatch: function( event ) {
+
+ // Make a writable jQuery.Event from the native event object
+ event = jQuery.event.fix( event );
+
+ var i, ret, handleObj, matched, j,
+ handlerQueue = [],
+ args = core_slice.call( arguments ),
+ handlers = ( jQuery._data( this, "events" ) || {} )[ event.type ] || [],
+ special = jQuery.event.special[ event.type ] || {};
+
+ // Use the fix-ed jQuery.Event rather than the (read-only) native event
+ args[0] = event;
+ event.delegateTarget = this;
+
+ // Call the preDispatch hook for the mapped type, and let it bail if desired
+ if ( special.preDispatch && special.preDispatch.call( this, event ) === false ) {
+ return;
+ }
+
+ // Determine handlers
+ handlerQueue = jQuery.event.handlers.call( this, event, handlers );
+
+ // Run delegates first; they may want to stop propagation beneath us
+ i = 0;
+ while ( (matched = handlerQueue[ i++ ]) && !event.isPropagationStopped() ) {
+ event.currentTarget = matched.elem;
+
+ j = 0;
+ while ( (handleObj = matched.handlers[ j++ ]) && !event.isImmediatePropagationStopped() ) {
+
+ // Triggered event must either 1) have no namespace, or
+ // 2) have namespace(s) a subset or equal to those in the bound event (both can have no namespace).
+ if ( !event.namespace_re || event.namespace_re.test( handleObj.namespace ) ) {
+
+ event.handleObj = handleObj;
+ event.data = handleObj.data;
+
+ ret = ( (jQuery.event.special[ handleObj.origType ] || {}).handle || handleObj.handler )
+ .apply( matched.elem, args );
+
+ if ( ret !== undefined ) {
+ if ( (event.result = ret) === false ) {
+ event.preventDefault();
+ event.stopPropagation();
+ }
+ }
+ }
+ }
+ }
+
+ // Call the postDispatch hook for the mapped type
+ if ( special.postDispatch ) {
+ special.postDispatch.call( this, event );
+ }
+
+ return event.result;
+ },
+
+ handlers: function( event, handlers ) {
+ var sel, handleObj, matches, i,
+ handlerQueue = [],
+ delegateCount = handlers.delegateCount,
+ cur = event.target;
+
+ // Find delegate handlers
+ // Black-hole SVG <use> instance trees (#13180)
+ // Avoid non-left-click bubbling in Firefox (#3861)
+ if ( delegateCount && cur.nodeType && (!event.button || event.type !== "click") ) {
+
+ /* jshint eqeqeq: false */
+ for ( ; cur != this; cur = cur.parentNode || this ) {
+ /* jshint eqeqeq: true */
+
+ // Don't check non-elements (#13208)
+ // Don't process clicks on disabled elements (#6911, #8165, #11382, #11764)
+ if ( cur.nodeType === 1 && (cur.disabled !== true || event.type !== "click") ) {
+ matches = [];
+ for ( i = 0; i < delegateCount; i++ ) {
+ handleObj = handlers[ i ];
+
+ // Don't conflict with Object.prototype properties (#13203)
+ sel = handleObj.selector + " ";
+
+ if ( matches[ sel ] === undefined ) {
+ matches[ sel ] = handleObj.needsContext ?
+ jQuery( sel, this ).index( cur ) >= 0 :
+ jQuery.find( sel, this, null, [ cur ] ).length;
+ }
+ if ( matches[ sel ] ) {
+ matches.push( handleObj );
+ }
+ }
+ if ( matches.length ) {
+ handlerQueue.push({ elem: cur, handlers: matches });
+ }
+ }
+ }
+ }
+
+ // Add the remaining (directly-bound) handlers
+ if ( delegateCount < handlers.length ) {
+ handlerQueue.push({ elem: this, handlers: handlers.slice( delegateCount ) });
+ }
+
+ return handlerQueue;
+ },
+
+ fix: function( event ) {
+ if ( event[ jQuery.expando ] ) {
+ return event;
+ }
+
+ // Create a writable copy of the event object and normalize some properties
+ var i, prop, copy,
+ type = event.type,
+ originalEvent = event,
+ fixHook = this.fixHooks[ type ];
+
+ if ( !fixHook ) {
+ this.fixHooks[ type ] = fixHook =
+ rmouseEvent.test( type ) ? this.mouseHooks :
+ rkeyEvent.test( type ) ? this.keyHooks :
+ {};
+ }
+ copy = fixHook.props ? this.props.concat( fixHook.props ) : this.props;
+
+ event = new jQuery.Event( originalEvent );
+
+ i = copy.length;
+ while ( i-- ) {
+ prop = copy[ i ];
+ event[ prop ] = originalEvent[ prop ];
+ }
+
+ // Support: IE<9
+ // Fix target property (#1925)
+ if ( !event.target ) {
+ event.target = originalEvent.srcElement || document;
+ }
+
+ // Support: Chrome 23+, Safari?
+ // Target should not be a text node (#504, #13143)
+ if ( event.target.nodeType === 3 ) {
+ event.target = event.target.parentNode;
+ }
+
+ // Support: IE<9
+ // For mouse/key events, metaKey==false if it's undefined (#3368, #11328)
+ event.metaKey = !!event.metaKey;
+
+ return fixHook.filter ? fixHook.filter( event, originalEvent ) : event;
+ },
+
+ // Includes some event props shared by KeyEvent and MouseEvent
+ props: "altKey bubbles cancelable ctrlKey currentTarget eventPhase metaKey relatedTarget shiftKey target timeStamp view which".split(" "),
+
+ fixHooks: {},
+
+ keyHooks: {
+ props: "char charCode key keyCode".split(" "),
+ filter: function( event, original ) {
+
+ // Add which for key events
+ if ( event.which == null ) {
+ event.which = original.charCode != null ? original.charCode : original.keyCode;
+ }
+
+ return event;
+ }
+ },
+
+ mouseHooks: {
+ props: "button buttons clientX clientY fromElement offsetX offsetY pageX pageY screenX screenY toElement".split(" "),
+ filter: function( event, original ) {
+ var body, eventDoc, doc,
+ button = original.button,
+ fromElement = original.fromElement;
+
+ // Calculate pageX/Y if missing and clientX/Y available
+ if ( event.pageX == null && original.clientX != null ) {
+ eventDoc = event.target.ownerDocument || document;
+ doc = eventDoc.documentElement;
+ body = eventDoc.body;
+
+ event.pageX = original.clientX + ( doc && doc.scrollLeft || body && body.scrollLeft || 0 ) - ( doc && doc.clientLeft || body && body.clientLeft || 0 );
+ event.pageY = original.clientY + ( doc && doc.scrollTop || body && body.scrollTop || 0 ) - ( doc && doc.clientTop || body && body.clientTop || 0 );
+ }
+
+ // Add relatedTarget, if necessary
+ if ( !event.relatedTarget && fromElement ) {
+ event.relatedTarget = fromElement === event.target ? original.toElement : fromElement;
+ }
+
+ // Add which for click: 1 === left; 2 === middle; 3 === right
+ // Note: button is not normalized, so don't use it
+ if ( !event.which && button !== undefined ) {
+ event.which = ( button & 1 ? 1 : ( button & 2 ? 3 : ( button & 4 ? 2 : 0 ) ) );
+ }
+
+ return event;
+ }
+ },
+
+ special: {
+ load: {
+ // Prevent triggered image.load events from bubbling to window.load
+ noBubble: true
+ },
+ focus: {
+ // Fire native event if possible so blur/focus sequence is correct
+ trigger: function() {
+ if ( this !== safeActiveElement() && this.focus ) {
+ try {
+ this.focus();
+ return false;
+ } catch ( e ) {
+ // Support: IE<9
+ // If we error on focus to hidden element (#1486, #12518),
+ // let .trigger() run the handlers
+ }
+ }
+ },
+ delegateType: "focusin"
+ },
+ blur: {
+ trigger: function() {
+ if ( this === safeActiveElement() && this.blur ) {
+ this.blur();
+ return false;
+ }
+ },
+ delegateType: "focusout"
+ },
+ click: {
+ // For checkbox, fire native event so checked state will be right
+ trigger: function() {
+ if ( jQuery.nodeName( this, "input" ) && this.type === "checkbox" && this.click ) {
+ this.click();
+ return false;
+ }
+ },
+
+ // For cross-browser consistency, don't fire native .click() on links
+ _default: function( event ) {
+ return jQuery.nodeName( event.target, "a" );
+ }
+ },
+
+ beforeunload: {
+ postDispatch: function( event ) {
+
+ // Even when returnValue equals to undefined Firefox will still show alert
+ if ( event.result !== undefined ) {
+ event.originalEvent.returnValue = event.result;
+ }
+ }
+ }
+ },
+
+ simulate: function( type, elem, event, bubble ) {
+ // Piggyback on a donor event to simulate a different one.
+ // Fake originalEvent to avoid donor's stopPropagation, but if the
+ // simulated event prevents default then we do the same on the donor.
+ var e = jQuery.extend(
+ new jQuery.Event(),
+ event,
+ {
+ type: type,
+ isSimulated: true,
+ originalEvent: {}
+ }
+ );
+ if ( bubble ) {
+ jQuery.event.trigger( e, null, elem );
+ } else {
+ jQuery.event.dispatch.call( elem, e );
+ }
+ if ( e.isDefaultPrevented() ) {
+ event.preventDefault();
+ }
+ }
+};
+
+jQuery.removeEvent = document.removeEventListener ?
+ function( elem, type, handle ) {
+ if ( elem.removeEventListener ) {
+ elem.removeEventListener( type, handle, false );
+ }
+ } :
+ function( elem, type, handle ) {
+ var name = "on" + type;
+
+ if ( elem.detachEvent ) {
+
+ // #8545, #7054, preventing memory leaks for custom events in IE6-8
+ // detachEvent needed property on element, by name of that event, to properly expose it to GC
+ if ( typeof elem[ name ] === core_strundefined ) {
+ elem[ name ] = null;
+ }
+
+ elem.detachEvent( name, handle );
+ }
+ };
+
+jQuery.Event = function( src, props ) {
+ // Allow instantiation without the 'new' keyword
+ if ( !(this instanceof jQuery.Event) ) {
+ return new jQuery.Event( src, props );
+ }
+
+ // Event object
+ if ( src && src.type ) {
+ this.originalEvent = src;
+ this.type = src.type;
+
+ // Events bubbling up the document may have been marked as prevented
+ // by a handler lower down the tree; reflect the correct value.
+ this.isDefaultPrevented = ( src.defaultPrevented || src.returnValue === false ||
+ src.getPreventDefault && src.getPreventDefault() ) ? returnTrue : returnFalse;
+
+ // Event type
+ } else {
+ this.type = src;
+ }
+
+ // Put explicitly provided properties onto the event object
+ if ( props ) {
+ jQuery.extend( this, props );
+ }
+
+ // Create a timestamp if incoming event doesn't have one
+ this.timeStamp = src && src.timeStamp || jQuery.now();
+
+ // Mark it as fixed
+ this[ jQuery.expando ] = true;
+};
+
+// jQuery.Event is based on DOM3 Events as specified by the ECMAScript Language Binding
+// http://www.w3.org/TR/2003/WD-DOM-Level-3-Events-20030331/ecma-script-binding.html
+jQuery.Event.prototype = {
+ isDefaultPrevented: returnFalse,
+ isPropagationStopped: returnFalse,
+ isImmediatePropagationStopped: returnFalse,
+
+ preventDefault: function() {
+ var e = this.originalEvent;
+
+ this.isDefaultPrevented = returnTrue;
+ if ( !e ) {
+ return;
+ }
+
+ // If preventDefault exists, run it on the original event
+ if ( e.preventDefault ) {
+ e.preventDefault();
+
+ // Support: IE
+ // Otherwise set the returnValue property of the original event to false
+ } else {
+ e.returnValue = false;
+ }
+ },
+ stopPropagation: function() {
+ var e = this.originalEvent;
+
+ this.isPropagationStopped = returnTrue;
+ if ( !e ) {
+ return;
+ }
+ // If stopPropagation exists, run it on the original event
+ if ( e.stopPropagation ) {
+ e.stopPropagation();
+ }
+
+ // Support: IE
+ // Set the cancelBubble property of the original event to true
+ e.cancelBubble = true;
+ },
+ stopImmediatePropagation: function() {
+ this.isImmediatePropagationStopped = returnTrue;
+ this.stopPropagation();
+ }
+};
+
+// Create mouseenter/leave events using mouseover/out and event-time checks
+jQuery.each({
+ mouseenter: "mouseover",
+ mouseleave: "mouseout"
+}, function( orig, fix ) {
+ jQuery.event.special[ orig ] = {
+ delegateType: fix,
+ bindType: fix,
+
+ handle: function( event ) {
+ var ret,
+ target = this,
+ related = event.relatedTarget,
+ handleObj = event.handleObj;
+
+ // For mousenter/leave call the handler if related is outside the target.
+ // NB: No relatedTarget if the mouse left/entered the browser window
+ if ( !related || (related !== target && !jQuery.contains( target, related )) ) {
+ event.type = handleObj.origType;
+ ret = handleObj.handler.apply( this, arguments );
+ event.type = fix;
+ }
+ return ret;
+ }
+ };
+});
+
+// IE submit delegation
+if ( !jQuery.support.submitBubbles ) {
+
+ jQuery.event.special.submit = {
+ setup: function() {
+ // Only need this for delegated form submit events
+ if ( jQuery.nodeName( this, "form" ) ) {
+ return false;
+ }
+
+ // Lazy-add a submit handler when a descendant form may potentially be submitted
+ jQuery.event.add( this, "click._submit keypress._submit", function( e ) {
+ // Node name check avoids a VML-related crash in IE (#9807)
+ var elem = e.target,
+ form = jQuery.nodeName( elem, "input" ) || jQuery.nodeName( elem, "button" ) ? elem.form : undefined;
+ if ( form && !jQuery._data( form, "submitBubbles" ) ) {
+ jQuery.event.add( form, "submit._submit", function( event ) {
+ event._submit_bubble = true;
+ });
+ jQuery._data( form, "submitBubbles", true );
+ }
+ });
+ // return undefined since we don't need an event listener
+ },
+
+ postDispatch: function( event ) {
+ // If form was submitted by the user, bubble the event up the tree
+ if ( event._submit_bubble ) {
+ delete event._submit_bubble;
+ if ( this.parentNode && !event.isTrigger ) {
+ jQuery.event.simulate( "submit", this.parentNode, event, true );
+ }
+ }
+ },
+
+ teardown: function() {
+ // Only need this for delegated form submit events
+ if ( jQuery.nodeName( this, "form" ) ) {
+ return false;
+ }
+
+ // Remove delegated handlers; cleanData eventually reaps submit handlers attached above
+ jQuery.event.remove( this, "._submit" );
+ }
+ };
+}
+
+// IE change delegation and checkbox/radio fix
+if ( !jQuery.support.changeBubbles ) {
+
+ jQuery.event.special.change = {
+
+ setup: function() {
+
+ if ( rformElems.test( this.nodeName ) ) {
+ // IE doesn't fire change on a check/radio until blur; trigger it on click
+ // after a propertychange. Eat the blur-change in special.change.handle.
+ // This still fires onchange a second time for check/radio after blur.
+ if ( this.type === "checkbox" || this.type === "radio" ) {
+ jQuery.event.add( this, "propertychange._change", function( event ) {
+ if ( event.originalEvent.propertyName === "checked" ) {
+ this._just_changed = true;
+ }
+ });
+ jQuery.event.add( this, "click._change", function( event ) {
+ if ( this._just_changed && !event.isTrigger ) {
+ this._just_changed = false;
+ }
+ // Allow triggered, simulated change events (#11500)
+ jQuery.event.simulate( "change", this, event, true );
+ });
+ }
+ return false;
+ }
+ // Delegated event; lazy-add a change handler on descendant inputs
+ jQuery.event.add( this, "beforeactivate._change", function( e ) {
+ var elem = e.target;
+
+ if ( rformElems.test( elem.nodeName ) && !jQuery._data( elem, "changeBubbles" ) ) {
+ jQuery.event.add( elem, "change._change", function( event ) {
+ if ( this.parentNode && !event.isSimulated && !event.isTrigger ) {
+ jQuery.event.simulate( "change", this.parentNode, event, true );
+ }
+ });
+ jQuery._data( elem, "changeBubbles", true );
+ }
+ });
+ },
+
+ handle: function( event ) {
+ var elem = event.target;
+
+ // Swallow native change events from checkbox/radio, we already triggered them above
+ if ( this !== elem || event.isSimulated || event.isTrigger || (elem.type !== "radio" && elem.type !== "checkbox") ) {
+ return event.handleObj.handler.apply( this, arguments );
+ }
+ },
+
+ teardown: function() {
+ jQuery.event.remove( this, "._change" );
+
+ return !rformElems.test( this.nodeName );
+ }
+ };
+}
+
+// Create "bubbling" focus and blur events
+if ( !jQuery.support.focusinBubbles ) {
+ jQuery.each({ focus: "focusin", blur: "focusout" }, function( orig, fix ) {
+
+ // Attach a single capturing handler while someone wants focusin/focusout
+ var attaches = 0,
+ handler = function( event ) {
+ jQuery.event.simulate( fix, event.target, jQuery.event.fix( event ), true );
+ };
+
+ jQuery.event.special[ fix ] = {
+ setup: function() {
+ if ( attaches++ === 0 ) {
+ document.addEventListener( orig, handler, true );
+ }
+ },
+ teardown: function() {
+ if ( --attaches === 0 ) {
+ document.removeEventListener( orig, handler, true );
+ }
+ }
+ };
+ });
+}
+
+jQuery.fn.extend({
+
+ on: function( types, selector, data, fn, /*INTERNAL*/ one ) {
+ var type, origFn;
+
+ // Types can be a map of types/handlers
+ if ( typeof types === "object" ) {
+ // ( types-Object, selector, data )
+ if ( typeof selector !== "string" ) {
+ // ( types-Object, data )
+ data = data || selector;
+ selector = undefined;
+ }
+ for ( type in types ) {
+ this.on( type, selector, data, types[ type ], one );
+ }
+ return this;
+ }
+
+ if ( data == null && fn == null ) {
+ // ( types, fn )
+ fn = selector;
+ data = selector = undefined;
+ } else if ( fn == null ) {
+ if ( typeof selector === "string" ) {
+ // ( types, selector, fn )
+ fn = data;
+ data = undefined;
+ } else {
+ // ( types, data, fn )
+ fn = data;
+ data = selector;
+ selector = undefined;
+ }
+ }
+ if ( fn === false ) {
+ fn = returnFalse;
+ } else if ( !fn ) {
+ return this;
+ }
+
+ if ( one === 1 ) {
+ origFn = fn;
+ fn = function( event ) {
+ // Can use an empty set, since event contains the info
+ jQuery().off( event );
+ return origFn.apply( this, arguments );
+ };
+ // Use same guid so caller can remove using origFn
+ fn.guid = origFn.guid || ( origFn.guid = jQuery.guid++ );
+ }
+ return this.each( function() {
+ jQuery.event.add( this, types, fn, data, selector );
+ });
+ },
+ one: function( types, selector, data, fn ) {
+ return this.on( types, selector, data, fn, 1 );
+ },
+ off: function( types, selector, fn ) {
+ var handleObj, type;
+ if ( types && types.preventDefault && types.handleObj ) {
+ // ( event ) dispatched jQuery.Event
+ handleObj = types.handleObj;
+ jQuery( types.delegateTarget ).off(
+ handleObj.namespace ? handleObj.origType + "." + handleObj.namespace : handleObj.origType,
+ handleObj.selector,
+ handleObj.handler
+ );
+ return this;
+ }
+ if ( typeof types === "object" ) {
+ // ( types-object [, selector] )
+ for ( type in types ) {
+ this.off( type, selector, types[ type ] );
+ }
+ return this;
+ }
+ if ( selector === false || typeof selector === "function" ) {
+ // ( types [, fn] )
+ fn = selector;
+ selector = undefined;
+ }
+ if ( fn === false ) {
+ fn = returnFalse;
+ }
+ return this.each(function() {
+ jQuery.event.remove( this, types, fn, selector );
+ });
+ },
+
+ trigger: function( type, data ) {
+ return this.each(function() {
+ jQuery.event.trigger( type, data, this );
+ });
+ },
+ triggerHandler: function( type, data ) {
+ var elem = this[0];
+ if ( elem ) {
+ return jQuery.event.trigger( type, data, elem, true );
+ }
+ }
+});
+var isSimple = /^.[^:#\[\.,]*$/,
+ rparentsprev = /^(?:parents|prev(?:Until|All))/,
+ rneedsContext = jQuery.expr.match.needsContext,
+ // methods guaranteed to produce a unique set when starting from a unique set
+ guaranteedUnique = {
+ children: true,
+ contents: true,
+ next: true,
+ prev: true
+ };
+
+jQuery.fn.extend({
+ find: function( selector ) {
+ var i,
+ ret = [],
+ self = this,
+ len = self.length;
+
+ if ( typeof selector !== "string" ) {
+ return this.pushStack( jQuery( selector ).filter(function() {
+ for ( i = 0; i < len; i++ ) {
+ if ( jQuery.contains( self[ i ], this ) ) {
+ return true;
+ }
+ }
+ }) );
+ }
+
+ for ( i = 0; i < len; i++ ) {
+ jQuery.find( selector, self[ i ], ret );
+ }
+
+ // Needed because $( selector, context ) becomes $( context ).find( selector )
+ ret = this.pushStack( len > 1 ? jQuery.unique( ret ) : ret );
+ ret.selector = this.selector ? this.selector + " " + selector : selector;
+ return ret;
+ },
+
+ has: function( target ) {
+ var i,
+ targets = jQuery( target, this ),
+ len = targets.length;
+
+ return this.filter(function() {
+ for ( i = 0; i < len; i++ ) {
+ if ( jQuery.contains( this, targets[i] ) ) {
+ return true;
+ }
+ }
+ });
+ },
+
+ not: function( selector ) {
+ return this.pushStack( winnow(this, selector || [], true) );
+ },
+
+ filter: function( selector ) {
+ return this.pushStack( winnow(this, selector || [], false) );
+ },
+
+ is: function( selector ) {
+ return !!winnow(
+ this,
+
+ // If this is a positional/relative selector, check membership in the returned set
+ // so $("p:first").is("p:last") won't return true for a doc with two "p".
+ typeof selector === "string" && rneedsContext.test( selector ) ?
+ jQuery( selector ) :
+ selector || [],
+ false
+ ).length;
+ },
+
+ closest: function( selectors, context ) {
+ var cur,
+ i = 0,
+ l = this.length,
+ ret = [],
+ pos = rneedsContext.test( selectors ) || typeof selectors !== "string" ?
+ jQuery( selectors, context || this.context ) :
+ 0;
+
+ for ( ; i < l; i++ ) {
+ for ( cur = this[i]; cur && cur !== context; cur = cur.parentNode ) {
+ // Always skip document fragments
+ if ( cur.nodeType < 11 && (pos ?
+ pos.index(cur) > -1 :
+
+ // Don't pass non-elements to Sizzle
+ cur.nodeType === 1 &&
+ jQuery.find.matchesSelector(cur, selectors)) ) {
+
+ cur = ret.push( cur );
+ break;
+ }
+ }
+ }
+
+ return this.pushStack( ret.length > 1 ? jQuery.unique( ret ) : ret );
+ },
+
+ // Determine the position of an element within
+ // the matched set of elements
+ index: function( elem ) {
+
+ // No argument, return index in parent
+ if ( !elem ) {
+ return ( this[0] && this[0].parentNode ) ? this.first().prevAll().length : -1;
+ }
+
+ // index in selector
+ if ( typeof elem === "string" ) {
+ return jQuery.inArray( this[0], jQuery( elem ) );
+ }
+
+ // Locate the position of the desired element
+ return jQuery.inArray(
+ // If it receives a jQuery object, the first element is used
+ elem.jquery ? elem[0] : elem, this );
+ },
+
+ add: function( selector, context ) {
+ var set = typeof selector === "string" ?
+ jQuery( selector, context ) :
+ jQuery.makeArray( selector && selector.nodeType ? [ selector ] : selector ),
+ all = jQuery.merge( this.get(), set );
+
+ return this.pushStack( jQuery.unique(all) );
+ },
+
+ addBack: function( selector ) {
+ return this.add( selector == null ?
+ this.prevObject : this.prevObject.filter(selector)
+ );
+ }
+});
+
+function sibling( cur, dir ) {
+ do {
+ cur = cur[ dir ];
+ } while ( cur && cur.nodeType !== 1 );
+
+ return cur;
+}
+
+jQuery.each({
+ parent: function( elem ) {
+ var parent = elem.parentNode;
+ return parent && parent.nodeType !== 11 ? parent : null;
+ },
+ parents: function( elem ) {
+ return jQuery.dir( elem, "parentNode" );
+ },
+ parentsUntil: function( elem, i, until ) {
+ return jQuery.dir( elem, "parentNode", until );
+ },
+ next: function( elem ) {
+ return sibling( elem, "nextSibling" );
+ },
+ prev: function( elem ) {
+ return sibling( elem, "previousSibling" );
+ },
+ nextAll: function( elem ) {
+ return jQuery.dir( elem, "nextSibling" );
+ },
+ prevAll: function( elem ) {
+ return jQuery.dir( elem, "previousSibling" );
+ },
+ nextUntil: function( elem, i, until ) {
+ return jQuery.dir( elem, "nextSibling", until );
+ },
+ prevUntil: function( elem, i, until ) {
+ return jQuery.dir( elem, "previousSibling", until );
+ },
+ siblings: function( elem ) {
+ return jQuery.sibling( ( elem.parentNode || {} ).firstChild, elem );
+ },
+ children: function( elem ) {
+ return jQuery.sibling( elem.firstChild );
+ },
+ contents: function( elem ) {
+ return jQuery.nodeName( elem, "iframe" ) ?
+ elem.contentDocument || elem.contentWindow.document :
+ jQuery.merge( [], elem.childNodes );
+ }
+}, function( name, fn ) {
+ jQuery.fn[ name ] = function( until, selector ) {
+ var ret = jQuery.map( this, fn, until );
+
+ if ( name.slice( -5 ) !== "Until" ) {
+ selector = until;
+ }
+
+ if ( selector && typeof selector === "string" ) {
+ ret = jQuery.filter( selector, ret );
+ }
+
+ if ( this.length > 1 ) {
+ // Remove duplicates
+ if ( !guaranteedUnique[ name ] ) {
+ ret = jQuery.unique( ret );
+ }
+
+ // Reverse order for parents* and prev-derivatives
+ if ( rparentsprev.test( name ) ) {
+ ret = ret.reverse();
+ }
+ }
+
+ return this.pushStack( ret );
+ };
+});
+
+jQuery.extend({
+ filter: function( expr, elems, not ) {
+ var elem = elems[ 0 ];
+
+ if ( not ) {
+ expr = ":not(" + expr + ")";
+ }
+
+ return elems.length === 1 && elem.nodeType === 1 ?
+ jQuery.find.matchesSelector( elem, expr ) ? [ elem ] : [] :
+ jQuery.find.matches( expr, jQuery.grep( elems, function( elem ) {
+ return elem.nodeType === 1;
+ }));
+ },
+
+ dir: function( elem, dir, until ) {
+ var matched = [],
+ cur = elem[ dir ];
+
+ while ( cur && cur.nodeType !== 9 && (until === undefined || cur.nodeType !== 1 || !jQuery( cur ).is( until )) ) {
+ if ( cur.nodeType === 1 ) {
+ matched.push( cur );
+ }
+ cur = cur[dir];
+ }
+ return matched;
+ },
+
+ sibling: function( n, elem ) {
+ var r = [];
+
+ for ( ; n; n = n.nextSibling ) {
+ if ( n.nodeType === 1 && n !== elem ) {
+ r.push( n );
+ }
+ }
+
+ return r;
+ }
+});
+
+// Implement the identical functionality for filter and not
+function winnow( elements, qualifier, not ) {
+ if ( jQuery.isFunction( qualifier ) ) {
+ return jQuery.grep( elements, function( elem, i ) {
+ /* jshint -W018 */
+ return !!qualifier.call( elem, i, elem ) !== not;
+ });
+
+ }
+
+ if ( qualifier.nodeType ) {
+ return jQuery.grep( elements, function( elem ) {
+ return ( elem === qualifier ) !== not;
+ });
+
+ }
+
+ if ( typeof qualifier === "string" ) {
+ if ( isSimple.test( qualifier ) ) {
+ return jQuery.filter( qualifier, elements, not );
+ }
+
+ qualifier = jQuery.filter( qualifier, elements );
+ }
+
+ return jQuery.grep( elements, function( elem ) {
+ return ( jQuery.inArray( elem, qualifier ) >= 0 ) !== not;
+ });
+}
+function createSafeFragment( document ) {
+ var list = nodeNames.split( "|" ),
+ safeFrag = document.createDocumentFragment();
+
+ if ( safeFrag.createElement ) {
+ while ( list.length ) {
+ safeFrag.createElement(
+ list.pop()
+ );
+ }
+ }
+ return safeFrag;
+}
+
+var nodeNames = "abbr|article|aside|audio|bdi|canvas|data|datalist|details|figcaption|figure|footer|" +
+ "header|hgroup|mark|meter|nav|output|progress|section|summary|time|video",
+ rinlinejQuery = / jQuery\d+="(?:null|\d+)"/g,
+ rnoshimcache = new RegExp("<(?:" + nodeNames + ")[\\s/>]", "i"),
+ rleadingWhitespace = /^\s+/,
+ rxhtmlTag = /<(?!area|br|col|embed|hr|img|input|link|meta|param)(([\w:]+)[^>]*)\/>/gi,
+ rtagName = /<([\w:]+)/,
+ rtbody = /<tbody/i,
+ rhtml = /<|&#?\w+;/,
+ rnoInnerhtml = /<(?:script|style|link)/i,
+ manipulation_rcheckableType = /^(?:checkbox|radio)$/i,
+ // checked="checked" or checked
+ rchecked = /checked\s*(?:[^=]|=\s*.checked.)/i,
+ rscriptType = /^$|\/(?:java|ecma)script/i,
+ rscriptTypeMasked = /^true\/(.*)/,
+ rcleanScript = /^\s*<!(?:\[CDATA\[|--)|(?:\]\]|--)>\s*$/g,
+
+ // We have to close these tags to support XHTML (#13200)
+ wrapMap = {
+ option: [ 1, "<select multiple='multiple'>", "</select>" ],
+ legend: [ 1, "<fieldset>", "</fieldset>" ],
+ area: [ 1, "<map>", "</map>" ],
+ param: [ 1, "<object>", "</object>" ],
+ thead: [ 1, "<table>", "</table>" ],
+ tr: [ 2, "<table><tbody>", "</tbody></table>" ],
+ col: [ 2, "<table><tbody></tbody><colgroup>", "</colgroup></table>" ],
+ td: [ 3, "<table><tbody><tr>", "</tr></tbody></table>" ],
+
+ // IE6-8 can't serialize link, script, style, or any html5 (NoScope) tags,
+ // unless wrapped in a div with non-breaking characters in front of it.
+ _default: jQuery.support.htmlSerialize ? [ 0, "", "" ] : [ 1, "X<div>", "</div>" ]
+ },
+ safeFragment = createSafeFragment( document ),
+ fragmentDiv = safeFragment.appendChild( document.createElement("div") );
+
+wrapMap.optgroup = wrapMap.option;
+wrapMap.tbody = wrapMap.tfoot = wrapMap.colgroup = wrapMap.caption = wrapMap.thead;
+wrapMap.th = wrapMap.td;
+
+jQuery.fn.extend({
+ text: function( value ) {
+ return jQuery.access( this, function( value ) {
+ return value === undefined ?
+ jQuery.text( this ) :
+ this.empty().append( ( this[0] && this[0].ownerDocument || document ).createTextNode( value ) );
+ }, null, value, arguments.length );
+ },
+
+ append: function() {
+ return this.domManip( arguments, function( elem ) {
+ if ( this.nodeType === 1 || this.nodeType === 11 || this.nodeType === 9 ) {
+ var target = manipulationTarget( this, elem );
+ target.appendChild( elem );
+ }
+ });
+ },
+
+ prepend: function() {
+ return this.domManip( arguments, function( elem ) {
+ if ( this.nodeType === 1 || this.nodeType === 11 || this.nodeType === 9 ) {
+ var target = manipulationTarget( this, elem );
+ target.insertBefore( elem, target.firstChild );
+ }
+ });
+ },
+
+ before: function() {
+ return this.domManip( arguments, function( elem ) {
+ if ( this.parentNode ) {
+ this.parentNode.insertBefore( elem, this );
+ }
+ });
+ },
+
+ after: function() {
+ return this.domManip( arguments, function( elem ) {
+ if ( this.parentNode ) {
+ this.parentNode.insertBefore( elem, this.nextSibling );
+ }
+ });
+ },
+
+ // keepData is for internal use only--do not document
+ remove: function( selector, keepData ) {
+ var elem,
+ elems = selector ? jQuery.filter( selector, this ) : this,
+ i = 0;
+
+ for ( ; (elem = elems[i]) != null; i++ ) {
+
+ if ( !keepData && elem.nodeType === 1 ) {
+ jQuery.cleanData( getAll( elem ) );
+ }
+
+ if ( elem.parentNode ) {
+ if ( keepData && jQuery.contains( elem.ownerDocument, elem ) ) {
+ setGlobalEval( getAll( elem, "script" ) );
+ }
+ elem.parentNode.removeChild( elem );
+ }
+ }
+
+ return this;
+ },
+
+ empty: function() {
+ var elem,
+ i = 0;
+
+ for ( ; (elem = this[i]) != null; i++ ) {
+ // Remove element nodes and prevent memory leaks
+ if ( elem.nodeType === 1 ) {
+ jQuery.cleanData( getAll( elem, false ) );
+ }
+
+ // Remove any remaining nodes
+ while ( elem.firstChild ) {
+ elem.removeChild( elem.firstChild );
+ }
+
+ // If this is a select, ensure that it displays empty (#12336)
+ // Support: IE<9
+ if ( elem.options && jQuery.nodeName( elem, "select" ) ) {
+ elem.options.length = 0;
+ }
+ }
+
+ return this;
+ },
+
+ clone: function( dataAndEvents, deepDataAndEvents ) {
+ dataAndEvents = dataAndEvents == null ? false : dataAndEvents;
+ deepDataAndEvents = deepDataAndEvents == null ? dataAndEvents : deepDataAndEvents;
+
+ return this.map( function () {
+ return jQuery.clone( this, dataAndEvents, deepDataAndEvents );
+ });
+ },
+
+ html: function( value ) {
+ return jQuery.access( this, function( value ) {
+ var elem = this[0] || {},
+ i = 0,
+ l = this.length;
+
+ if ( value === undefined ) {
+ return elem.nodeType === 1 ?
+ elem.innerHTML.replace( rinlinejQuery, "" ) :
+ undefined;
+ }
+
+ // See if we can take a shortcut and just use innerHTML
+ if ( typeof value === "string" && !rnoInnerhtml.test( value ) &&
+ ( jQuery.support.htmlSerialize || !rnoshimcache.test( value ) ) &&
+ ( jQuery.support.leadingWhitespace || !rleadingWhitespace.test( value ) ) &&
+ !wrapMap[ ( rtagName.exec( value ) || ["", ""] )[1].toLowerCase() ] ) {
+
+ value = value.replace( rxhtmlTag, "<$1></$2>" );
+
+ try {
+ for (; i < l; i++ ) {
+ // Remove element nodes and prevent memory leaks
+ elem = this[i] || {};
+ if ( elem.nodeType === 1 ) {
+ jQuery.cleanData( getAll( elem, false ) );
+ elem.innerHTML = value;
+ }
+ }
+
+ elem = 0;
+
+ // If using innerHTML throws an exception, use the fallback method
+ } catch(e) {}
+ }
+
+ if ( elem ) {
+ this.empty().append( value );
+ }
+ }, null, value, arguments.length );
+ },
+
+ replaceWith: function() {
+ var
+ // Snapshot the DOM in case .domManip sweeps something relevant into its fragment
+ args = jQuery.map( this, function( elem ) {
+ return [ elem.nextSibling, elem.parentNode ];
+ }),
+ i = 0;
+
+ // Make the changes, replacing each context element with the new content
+ this.domManip( arguments, function( elem ) {
+ var next = args[ i++ ],
+ parent = args[ i++ ];
+
+ if ( parent ) {
+ // Don't use the snapshot next if it has moved (#13810)
+ if ( next && next.parentNode !== parent ) {
+ next = this.nextSibling;
+ }
+ jQuery( this ).remove();
+ parent.insertBefore( elem, next );
+ }
+ // Allow new content to include elements from the context set
+ }, true );
+
+ // Force removal if there was no new content (e.g., from empty arguments)
+ return i ? this : this.remove();
+ },
+
+ detach: function( selector ) {
+ return this.remove( selector, true );
+ },
+
+ domManip: function( args, callback, allowIntersection ) {
+
+ // Flatten any nested arrays
+ args = core_concat.apply( [], args );
+
+ var first, node, hasScripts,
+ scripts, doc, fragment,
+ i = 0,
+ l = this.length,
+ set = this,
+ iNoClone = l - 1,
+ value = args[0],
+ isFunction = jQuery.isFunction( value );
+
+ // We can't cloneNode fragments that contain checked, in WebKit
+ if ( isFunction || !( l <= 1 || typeof value !== "string" || jQuery.support.checkClone || !rchecked.test( value ) ) ) {
+ return this.each(function( index ) {
+ var self = set.eq( index );
+ if ( isFunction ) {
+ args[0] = value.call( this, index, self.html() );
+ }
+ self.domManip( args, callback, allowIntersection );
+ });
+ }
+
+ if ( l ) {
+ fragment = jQuery.buildFragment( args, this[ 0 ].ownerDocument, false, !allowIntersection && this );
+ first = fragment.firstChild;
+
+ if ( fragment.childNodes.length === 1 ) {
+ fragment = first;
+ }
+
+ if ( first ) {
+ scripts = jQuery.map( getAll( fragment, "script" ), disableScript );
+ hasScripts = scripts.length;
+
+ // Use the original fragment for the last item instead of the first because it can end up
+ // being emptied incorrectly in certain situations (#8070).
+ for ( ; i < l; i++ ) {
+ node = fragment;
+
+ if ( i !== iNoClone ) {
+ node = jQuery.clone( node, true, true );
+
+ // Keep references to cloned scripts for later restoration
+ if ( hasScripts ) {
+ jQuery.merge( scripts, getAll( node, "script" ) );
+ }
+ }
+
+ callback.call( this[i], node, i );
+ }
+
+ if ( hasScripts ) {
+ doc = scripts[ scripts.length - 1 ].ownerDocument;
+
+ // Reenable scripts
+ jQuery.map( scripts, restoreScript );
+
+ // Evaluate executable scripts on first document insertion
+ for ( i = 0; i < hasScripts; i++ ) {
+ node = scripts[ i ];
+ if ( rscriptType.test( node.type || "" ) &&
+ !jQuery._data( node, "globalEval" ) && jQuery.contains( doc, node ) ) {
+
+ if ( node.src ) {
+ // Hope ajax is available...
+ jQuery._evalUrl( node.src );
+ } else {
+ jQuery.globalEval( ( node.text || node.textContent || node.innerHTML || "" ).replace( rcleanScript, "" ) );
+ }
+ }
+ }
+ }
+
+ // Fix #11809: Avoid leaking memory
+ fragment = first = null;
+ }
+ }
+
+ return this;
+ }
+});
+
+// Support: IE<8
+// Manipulating tables requires a tbody
+function manipulationTarget( elem, content ) {
+ return jQuery.nodeName( elem, "table" ) &&
+ jQuery.nodeName( content.nodeType === 1 ? content : content.firstChild, "tr" ) ?
+
+ elem.getElementsByTagName("tbody")[0] ||
+ elem.appendChild( elem.ownerDocument.createElement("tbody") ) :
+ elem;
+}
+
+// Replace/restore the type attribute of script elements for safe DOM manipulation
+function disableScript( elem ) {
+ elem.type = (jQuery.find.attr( elem, "type" ) !== null) + "/" + elem.type;
+ return elem;
+}
+function restoreScript( elem ) {
+ var match = rscriptTypeMasked.exec( elem.type );
+ if ( match ) {
+ elem.type = match[1];
+ } else {
+ elem.removeAttribute("type");
+ }
+ return elem;
+}
+
+// Mark scripts as having already been evaluated
+function setGlobalEval( elems, refElements ) {
+ var elem,
+ i = 0;
+ for ( ; (elem = elems[i]) != null; i++ ) {
+ jQuery._data( elem, "globalEval", !refElements || jQuery._data( refElements[i], "globalEval" ) );
+ }
+}
+
+function cloneCopyEvent( src, dest ) {
+
+ if ( dest.nodeType !== 1 || !jQuery.hasData( src ) ) {
+ return;
+ }
+
+ var type, i, l,
+ oldData = jQuery._data( src ),
+ curData = jQuery._data( dest, oldData ),
+ events = oldData.events;
+
+ if ( events ) {
+ delete curData.handle;
+ curData.events = {};
+
+ for ( type in events ) {
+ for ( i = 0, l = events[ type ].length; i < l; i++ ) {
+ jQuery.event.add( dest, type, events[ type ][ i ] );
+ }
+ }
+ }
+
+ // make the cloned public data object a copy from the original
+ if ( curData.data ) {
+ curData.data = jQuery.extend( {}, curData.data );
+ }
+}
+
+function fixCloneNodeIssues( src, dest ) {
+ var nodeName, e, data;
+
+ // We do not need to do anything for non-Elements
+ if ( dest.nodeType !== 1 ) {
+ return;
+ }
+
+ nodeName = dest.nodeName.toLowerCase();
+
+ // IE6-8 copies events bound via attachEvent when using cloneNode.
+ if ( !jQuery.support.noCloneEvent && dest[ jQuery.expando ] ) {
+ data = jQuery._data( dest );
+
+ for ( e in data.events ) {
+ jQuery.removeEvent( dest, e, data.handle );
+ }
+
+ // Event data gets referenced instead of copied if the expando gets copied too
+ dest.removeAttribute( jQuery.expando );
+ }
+
+ // IE blanks contents when cloning scripts, and tries to evaluate newly-set text
+ if ( nodeName === "script" && dest.text !== src.text ) {
+ disableScript( dest ).text = src.text;
+ restoreScript( dest );
+
+ // IE6-10 improperly clones children of object elements using classid.
+ // IE10 throws NoModificationAllowedError if parent is null, #12132.
+ } else if ( nodeName === "object" ) {
+ if ( dest.parentNode ) {
+ dest.outerHTML = src.outerHTML;
+ }
+
+ // This path appears unavoidable for IE9. When cloning an object
+ // element in IE9, the outerHTML strategy above is not sufficient.
+ // If the src has innerHTML and the destination does not,
+ // copy the src.innerHTML into the dest.innerHTML. #10324
+ if ( jQuery.support.html5Clone && ( src.innerHTML && !jQuery.trim(dest.innerHTML) ) ) {
+ dest.innerHTML = src.innerHTML;
+ }
+
+ } else if ( nodeName === "input" && manipulation_rcheckableType.test( src.type ) ) {
+ // IE6-8 fails to persist the checked state of a cloned checkbox
+ // or radio button. Worse, IE6-7 fail to give the cloned element
+ // a checked appearance if the defaultChecked value isn't also set
+
+ dest.defaultChecked = dest.checked = src.checked;
+
+ // IE6-7 get confused and end up setting the value of a cloned
+ // checkbox/radio button to an empty string instead of "on"
+ if ( dest.value !== src.value ) {
+ dest.value = src.value;
+ }
+
+ // IE6-8 fails to return the selected option to the default selected
+ // state when cloning options
+ } else if ( nodeName === "option" ) {
+ dest.defaultSelected = dest.selected = src.defaultSelected;
+
+ // IE6-8 fails to set the defaultValue to the correct value when
+ // cloning other types of input fields
+ } else if ( nodeName === "input" || nodeName === "textarea" ) {
+ dest.defaultValue = src.defaultValue;
+ }
+}
+
+jQuery.each({
+ appendTo: "append",
+ prependTo: "prepend",
+ insertBefore: "before",
+ insertAfter: "after",
+ replaceAll: "replaceWith"
+}, function( name, original ) {
+ jQuery.fn[ name ] = function( selector ) {
+ var elems,
+ i = 0,
+ ret = [],
+ insert = jQuery( selector ),
+ last = insert.length - 1;
+
+ for ( ; i <= last; i++ ) {
+ elems = i === last ? this : this.clone(true);
+ jQuery( insert[i] )[ original ]( elems );
+
+ // Modern browsers can apply jQuery collections as arrays, but oldIE needs a .get()
+ core_push.apply( ret, elems.get() );
+ }
+
+ return this.pushStack( ret );
+ };
+});
+
+function getAll( context, tag ) {
+ var elems, elem,
+ i = 0,
+ found = typeof context.getElementsByTagName !== core_strundefined ? context.getElementsByTagName( tag || "*" ) :
+ typeof context.querySelectorAll !== core_strundefined ? context.querySelectorAll( tag || "*" ) :
+ undefined;
+
+ if ( !found ) {
+ for ( found = [], elems = context.childNodes || context; (elem = elems[i]) != null; i++ ) {
+ if ( !tag || jQuery.nodeName( elem, tag ) ) {
+ found.push( elem );
+ } else {
+ jQuery.merge( found, getAll( elem, tag ) );
+ }
+ }
+ }
+
+ return tag === undefined || tag && jQuery.nodeName( context, tag ) ?
+ jQuery.merge( [ context ], found ) :
+ found;
+}
+
+// Used in buildFragment, fixes the defaultChecked property
+function fixDefaultChecked( elem ) {
+ if ( manipulation_rcheckableType.test( elem.type ) ) {
+ elem.defaultChecked = elem.checked;
+ }
+}
+
+jQuery.extend({
+ clone: function( elem, dataAndEvents, deepDataAndEvents ) {
+ var destElements, node, clone, i, srcElements,
+ inPage = jQuery.contains( elem.ownerDocument, elem );
+
+ if ( jQuery.support.html5Clone || jQuery.isXMLDoc(elem) || !rnoshimcache.test( "<" + elem.nodeName + ">" ) ) {
+ clone = elem.cloneNode( true );
+
+ // IE<=8 does not properly clone detached, unknown element nodes
+ } else {
+ fragmentDiv.innerHTML = elem.outerHTML;
+ fragmentDiv.removeChild( clone = fragmentDiv.firstChild );
+ }
+
+ if ( (!jQuery.support.noCloneEvent || !jQuery.support.noCloneChecked) &&
+ (elem.nodeType === 1 || elem.nodeType === 11) && !jQuery.isXMLDoc(elem) ) {
+
+ // We eschew Sizzle here for performance reasons: http://jsperf.com/getall-vs-sizzle/2
+ destElements = getAll( clone );
+ srcElements = getAll( elem );
+
+ // Fix all IE cloning issues
+ for ( i = 0; (node = srcElements[i]) != null; ++i ) {
+ // Ensure that the destination node is not null; Fixes #9587
+ if ( destElements[i] ) {
+ fixCloneNodeIssues( node, destElements[i] );
+ }
+ }
+ }
+
+ // Copy the events from the original to the clone
+ if ( dataAndEvents ) {
+ if ( deepDataAndEvents ) {
+ srcElements = srcElements || getAll( elem );
+ destElements = destElements || getAll( clone );
+
+ for ( i = 0; (node = srcElements[i]) != null; i++ ) {
+ cloneCopyEvent( node, destElements[i] );
+ }
+ } else {
+ cloneCopyEvent( elem, clone );
+ }
+ }
+
+ // Preserve script evaluation history
+ destElements = getAll( clone, "script" );
+ if ( destElements.length > 0 ) {
+ setGlobalEval( destElements, !inPage && getAll( elem, "script" ) );
+ }
+
+ destElements = srcElements = node = null;
+
+ // Return the cloned set
+ return clone;
+ },
+
+ buildFragment: function( elems, context, scripts, selection ) {
+ var j, elem, contains,
+ tmp, tag, tbody, wrap,
+ l = elems.length,
+
+ // Ensure a safe fragment
+ safe = createSafeFragment( context ),
+
+ nodes = [],
+ i = 0;
+
+ for ( ; i < l; i++ ) {
+ elem = elems[ i ];
+
+ if ( elem || elem === 0 ) {
+
+ // Add nodes directly
+ if ( jQuery.type( elem ) === "object" ) {
+ jQuery.merge( nodes, elem.nodeType ? [ elem ] : elem );
+
+ // Convert non-html into a text node
+ } else if ( !rhtml.test( elem ) ) {
+ nodes.push( context.createTextNode( elem ) );
+
+ // Convert html into DOM nodes
+ } else {
+ tmp = tmp || safe.appendChild( context.createElement("div") );
+
+ // Deserialize a standard representation
+ tag = ( rtagName.exec( elem ) || ["", ""] )[1].toLowerCase();
+ wrap = wrapMap[ tag ] || wrapMap._default;
+
+ tmp.innerHTML = wrap[1] + elem.replace( rxhtmlTag, "<$1></$2>" ) + wrap[2];
+
+ // Descend through wrappers to the right content
+ j = wrap[0];
+ while ( j-- ) {
+ tmp = tmp.lastChild;
+ }
+
+ // Manually add leading whitespace removed by IE
+ if ( !jQuery.support.leadingWhitespace && rleadingWhitespace.test( elem ) ) {
+ nodes.push( context.createTextNode( rleadingWhitespace.exec( elem )[0] ) );
+ }
+
+ // Remove IE's autoinserted <tbody> from table fragments
+ if ( !jQuery.support.tbody ) {
+
+ // String was a <table>, *may* have spurious <tbody>
+ elem = tag === "table" && !rtbody.test( elem ) ?
+ tmp.firstChild :
+
+ // String was a bare <thead> or <tfoot>
+ wrap[1] === "<table>" && !rtbody.test( elem ) ?
+ tmp :
+ 0;
+
+ j = elem && elem.childNodes.length;
+ while ( j-- ) {
+ if ( jQuery.nodeName( (tbody = elem.childNodes[j]), "tbody" ) && !tbody.childNodes.length ) {
+ elem.removeChild( tbody );
+ }
+ }
+ }
+
+ jQuery.merge( nodes, tmp.childNodes );
+
+ // Fix #12392 for WebKit and IE > 9
+ tmp.textContent = "";
+
+ // Fix #12392 for oldIE
+ while ( tmp.firstChild ) {
+ tmp.removeChild( tmp.firstChild );
+ }
+
+ // Remember the top-level container for proper cleanup
+ tmp = safe.lastChild;
+ }
+ }
+ }
+
+ // Fix #11356: Clear elements from fragment
+ if ( tmp ) {
+ safe.removeChild( tmp );
+ }
+
+ // Reset defaultChecked for any radios and checkboxes
+ // about to be appended to the DOM in IE 6/7 (#8060)
+ if ( !jQuery.support.appendChecked ) {
+ jQuery.grep( getAll( nodes, "input" ), fixDefaultChecked );
+ }
+
+ i = 0;
+ while ( (elem = nodes[ i++ ]) ) {
+
+ // #4087 - If origin and destination elements are the same, and this is
+ // that element, do not do anything
+ if ( selection && jQuery.inArray( elem, selection ) !== -1 ) {
+ continue;
+ }
+
+ contains = jQuery.contains( elem.ownerDocument, elem );
+
+ // Append to fragment
+ tmp = getAll( safe.appendChild( elem ), "script" );
+
+ // Preserve script evaluation history
+ if ( contains ) {
+ setGlobalEval( tmp );
+ }
+
+ // Capture executables
+ if ( scripts ) {
+ j = 0;
+ while ( (elem = tmp[ j++ ]) ) {
+ if ( rscriptType.test( elem.type || "" ) ) {
+ scripts.push( elem );
+ }
+ }
+ }
+ }
+
+ tmp = null;
+
+ return safe;
+ },
+
+ cleanData: function( elems, /* internal */ acceptData ) {
+ var elem, type, id, data,
+ i = 0,
+ internalKey = jQuery.expando,
+ cache = jQuery.cache,
+ deleteExpando = jQuery.support.deleteExpando,
+ special = jQuery.event.special;
+
+ for ( ; (elem = elems[i]) != null; i++ ) {
+
+ if ( acceptData || jQuery.acceptData( elem ) ) {
+
+ id = elem[ internalKey ];
+ data = id && cache[ id ];
+
+ if ( data ) {
+ if ( data.events ) {
+ for ( type in data.events ) {
+ if ( special[ type ] ) {
+ jQuery.event.remove( elem, type );
+
+ // This is a shortcut to avoid jQuery.event.remove's overhead
+ } else {
+ jQuery.removeEvent( elem, type, data.handle );
+ }
+ }
+ }
+
+ // Remove cache only if it was not already removed by jQuery.event.remove
+ if ( cache[ id ] ) {
+
+ delete cache[ id ];
+
+ // IE does not allow us to delete expando properties from nodes,
+ // nor does it have a removeAttribute function on Document nodes;
+ // we must handle all of these cases
+ if ( deleteExpando ) {
+ delete elem[ internalKey ];
+
+ } else if ( typeof elem.removeAttribute !== core_strundefined ) {
+ elem.removeAttribute( internalKey );
+
+ } else {
+ elem[ internalKey ] = null;
+ }
+
+ core_deletedIds.push( id );
+ }
+ }
+ }
+ }
+ },
+
+ _evalUrl: function( url ) {
+ return jQuery.ajax({
+ url: url,
+ type: "GET",
+ dataType: "script",
+ async: false,
+ global: false,
+ "throws": true
+ });
+ }
+});
+jQuery.fn.extend({
+ wrapAll: function( html ) {
+ if ( jQuery.isFunction( html ) ) {
+ return this.each(function(i) {
+ jQuery(this).wrapAll( html.call(this, i) );
+ });
+ }
+
+ if ( this[0] ) {
+ // The elements to wrap the target around
+ var wrap = jQuery( html, this[0].ownerDocument ).eq(0).clone(true);
+
+ if ( this[0].parentNode ) {
+ wrap.insertBefore( this[0] );
+ }
+
+ wrap.map(function() {
+ var elem = this;
+
+ while ( elem.firstChild && elem.firstChild.nodeType === 1 ) {
+ elem = elem.firstChild;
+ }
+
+ return elem;
+ }).append( this );
+ }
+
+ return this;
+ },
+
+ wrapInner: function( html ) {
+ if ( jQuery.isFunction( html ) ) {
+ return this.each(function(i) {
+ jQuery(this).wrapInner( html.call(this, i) );
+ });
+ }
+
+ return this.each(function() {
+ var self = jQuery( this ),
+ contents = self.contents();
+
+ if ( contents.length ) {
+ contents.wrapAll( html );
+
+ } else {
+ self.append( html );
+ }
+ });
+ },
+
+ wrap: function( html ) {
+ var isFunction = jQuery.isFunction( html );
+
+ return this.each(function(i) {
+ jQuery( this ).wrapAll( isFunction ? html.call(this, i) : html );
+ });
+ },
+
+ unwrap: function() {
+ return this.parent().each(function() {
+ if ( !jQuery.nodeName( this, "body" ) ) {
+ jQuery( this ).replaceWith( this.childNodes );
+ }
+ }).end();
+ }
+});
+var iframe, getStyles, curCSS,
+ ralpha = /alpha\([^)]*\)/i,
+ ropacity = /opacity\s*=\s*([^)]*)/,
+ rposition = /^(top|right|bottom|left)$/,
+ // swappable if display is none or starts with table except "table", "table-cell", or "table-caption"
+ // see here for display values: https://developer.mozilla.org/en-US/docs/CSS/display
+ rdisplayswap = /^(none|table(?!-c[ea]).+)/,
+ rmargin = /^margin/,
+ rnumsplit = new RegExp( "^(" + core_pnum + ")(.*)$", "i" ),
+ rnumnonpx = new RegExp( "^(" + core_pnum + ")(?!px)[a-z%]+$", "i" ),
+ rrelNum = new RegExp( "^([+-])=(" + core_pnum + ")", "i" ),
+ elemdisplay = { BODY: "block" },
+
+ cssShow = { position: "absolute", visibility: "hidden", display: "block" },
+ cssNormalTransform = {
+ letterSpacing: 0,
+ fontWeight: 400
+ },
+
+ cssExpand = [ "Top", "Right", "Bottom", "Left" ],
+ cssPrefixes = [ "Webkit", "O", "Moz", "ms" ];
+
+// return a css property mapped to a potentially vendor prefixed property
+function vendorPropName( style, name ) {
+
+ // shortcut for names that are not vendor prefixed
+ if ( name in style ) {
+ return name;
+ }
+
+ // check for vendor prefixed names
+ var capName = name.charAt(0).toUpperCase() + name.slice(1),
+ origName = name,
+ i = cssPrefixes.length;
+
+ while ( i-- ) {
+ name = cssPrefixes[ i ] + capName;
+ if ( name in style ) {
+ return name;
+ }
+ }
+
+ return origName;
+}
+
+function isHidden( elem, el ) {
+ // isHidden might be called from jQuery#filter function;
+ // in that case, element will be second argument
+ elem = el || elem;
+ return jQuery.css( elem, "display" ) === "none" || !jQuery.contains( elem.ownerDocument, elem );
+}
+
+function showHide( elements, show ) {
+ var display, elem, hidden,
+ values = [],
+ index = 0,
+ length = elements.length;
+
+ for ( ; index < length; index++ ) {
+ elem = elements[ index ];
+ if ( !elem.style ) {
+ continue;
+ }
+
+ values[ index ] = jQuery._data( elem, "olddisplay" );
+ display = elem.style.display;
+ if ( show ) {
+ // Reset the inline display of this element to learn if it is
+ // being hidden by cascaded rules or not
+ if ( !values[ index ] && display === "none" ) {
+ elem.style.display = "";
+ }
+
+ // Set elements which have been overridden with display: none
+ // in a stylesheet to whatever the default browser style is
+ // for such an element
+ if ( elem.style.display === "" && isHidden( elem ) ) {
+ values[ index ] = jQuery._data( elem, "olddisplay", css_defaultDisplay(elem.nodeName) );
+ }
+ } else {
+
+ if ( !values[ index ] ) {
+ hidden = isHidden( elem );
+
+ if ( display && display !== "none" || !hidden ) {
+ jQuery._data( elem, "olddisplay", hidden ? display : jQuery.css( elem, "display" ) );
+ }
+ }
+ }
+ }
+
+ // Set the display of most of the elements in a second loop
+ // to avoid the constant reflow
+ for ( index = 0; index < length; index++ ) {
+ elem = elements[ index ];
+ if ( !elem.style ) {
+ continue;
+ }
+ if ( !show || elem.style.display === "none" || elem.style.display === "" ) {
+ elem.style.display = show ? values[ index ] || "" : "none";
+ }
+ }
+
+ return elements;
+}
+
+jQuery.fn.extend({
+ css: function( name, value ) {
+ return jQuery.access( this, function( elem, name, value ) {
+ var len, styles,
+ map = {},
+ i = 0;
+
+ if ( jQuery.isArray( name ) ) {
+ styles = getStyles( elem );
+ len = name.length;
+
+ for ( ; i < len; i++ ) {
+ map[ name[ i ] ] = jQuery.css( elem, name[ i ], false, styles );
+ }
+
+ return map;
+ }
+
+ return value !== undefined ?
+ jQuery.style( elem, name, value ) :
+ jQuery.css( elem, name );
+ }, name, value, arguments.length > 1 );
+ },
+ show: function() {
+ return showHide( this, true );
+ },
+ hide: function() {
+ return showHide( this );
+ },
+ toggle: function( state ) {
+ if ( typeof state === "boolean" ) {
+ return state ? this.show() : this.hide();
+ }
+
+ return this.each(function() {
+ if ( isHidden( this ) ) {
+ jQuery( this ).show();
+ } else {
+ jQuery( this ).hide();
+ }
+ });
+ }
+});
+
+jQuery.extend({
+ // Add in style property hooks for overriding the default
+ // behavior of getting and setting a style property
+ cssHooks: {
+ opacity: {
+ get: function( elem, computed ) {
+ if ( computed ) {
+ // We should always get a number back from opacity
+ var ret = curCSS( elem, "opacity" );
+ return ret === "" ? "1" : ret;
+ }
+ }
+ }
+ },
+
+ // Don't automatically add "px" to these possibly-unitless properties
+ cssNumber: {
+ "columnCount": true,
+ "fillOpacity": true,
+ "fontWeight": true,
+ "lineHeight": true,
+ "opacity": true,
+ "order": true,
+ "orphans": true,
+ "widows": true,
+ "zIndex": true,
+ "zoom": true
+ },
+
+ // Add in properties whose names you wish to fix before
+ // setting or getting the value
+ cssProps: {
+ // normalize float css property
+ "float": jQuery.support.cssFloat ? "cssFloat" : "styleFloat"
+ },
+
+ // Get and set the style property on a DOM Node
+ style: function( elem, name, value, extra ) {
+ // Don't set styles on text and comment nodes
+ if ( !elem || elem.nodeType === 3 || elem.nodeType === 8 || !elem.style ) {
+ return;
+ }
+
+ // Make sure that we're working with the right name
+ var ret, type, hooks,
+ origName = jQuery.camelCase( name ),
+ style = elem.style;
+
+ name = jQuery.cssProps[ origName ] || ( jQuery.cssProps[ origName ] = vendorPropName( style, origName ) );
+
+ // gets hook for the prefixed version
+ // followed by the unprefixed version
+ hooks = jQuery.cssHooks[ name ] || jQuery.cssHooks[ origName ];
+
+ // Check if we're setting a value
+ if ( value !== undefined ) {
+ type = typeof value;
+
+ // convert relative number strings (+= or -=) to relative numbers. #7345
+ if ( type === "string" && (ret = rrelNum.exec( value )) ) {
+ value = ( ret[1] + 1 ) * ret[2] + parseFloat( jQuery.css( elem, name ) );
+ // Fixes bug #9237
+ type = "number";
+ }
+
+ // Make sure that NaN and null values aren't set. See: #7116
+ if ( value == null || type === "number" && isNaN( value ) ) {
+ return;
+ }
+
+ // If a number was passed in, add 'px' to the (except for certain CSS properties)
+ if ( type === "number" && !jQuery.cssNumber[ origName ] ) {
+ value += "px";
+ }
+
+ // Fixes #8908, it can be done more correctly by specifing setters in cssHooks,
+ // but it would mean to define eight (for every problematic property) identical functions
+ if ( !jQuery.support.clearCloneStyle && value === "" && name.indexOf("background") === 0 ) {
+ style[ name ] = "inherit";
+ }
+
+ // If a hook was provided, use that value, otherwise just set the specified value
+ if ( !hooks || !("set" in hooks) || (value = hooks.set( elem, value, extra )) !== undefined ) {
+
+ // Wrapped to prevent IE from throwing errors when 'invalid' values are provided
+ // Fixes bug #5509
+ try {
+ style[ name ] = value;
+ } catch(e) {}
+ }
+
+ } else {
+ // If a hook was provided get the non-computed value from there
+ if ( hooks && "get" in hooks && (ret = hooks.get( elem, false, extra )) !== undefined ) {
+ return ret;
+ }
+
+ // Otherwise just get the value from the style object
+ return style[ name ];
+ }
+ },
+
+ css: function( elem, name, extra, styles ) {
+ var num, val, hooks,
+ origName = jQuery.camelCase( name );
+
+ // Make sure that we're working with the right name
+ name = jQuery.cssProps[ origName ] || ( jQuery.cssProps[ origName ] = vendorPropName( elem.style, origName ) );
+
+ // gets hook for the prefixed version
+ // followed by the unprefixed version
+ hooks = jQuery.cssHooks[ name ] || jQuery.cssHooks[ origName ];
+
+ // If a hook was provided get the computed value from there
+ if ( hooks && "get" in hooks ) {
+ val = hooks.get( elem, true, extra );
+ }
+
+ // Otherwise, if a way to get the computed value exists, use that
+ if ( val === undefined ) {
+ val = curCSS( elem, name, styles );
+ }
+
+ //convert "normal" to computed value
+ if ( val === "normal" && name in cssNormalTransform ) {
+ val = cssNormalTransform[ name ];
+ }
+
+ // Return, converting to number if forced or a qualifier was provided and val looks numeric
+ if ( extra === "" || extra ) {
+ num = parseFloat( val );
+ return extra === true || jQuery.isNumeric( num ) ? num || 0 : val;
+ }
+ return val;
+ }
+});
+
+// NOTE: we've included the "window" in window.getComputedStyle
+// because jsdom on node.js will break without it.
+if ( window.getComputedStyle ) {
+ getStyles = function( elem ) {
+ return window.getComputedStyle( elem, null );
+ };
+
+ curCSS = function( elem, name, _computed ) {
+ var width, minWidth, maxWidth,
+ computed = _computed || getStyles( elem ),
+
+ // getPropertyValue is only needed for .css('filter') in IE9, see #12537
+ ret = computed ? computed.getPropertyValue( name ) || computed[ name ] : undefined,
+ style = elem.style;
+
+ if ( computed ) {
+
+ if ( ret === "" && !jQuery.contains( elem.ownerDocument, elem ) ) {
+ ret = jQuery.style( elem, name );
+ }
+
+ // A tribute to the "awesome hack by Dean Edwards"
+ // Chrome < 17 and Safari 5.0 uses "computed value" instead of "used value" for margin-right
+ // Safari 5.1.7 (at least) returns percentage for a larger set of values, but width seems to be reliably pixels
+ // this is against the CSSOM draft spec: http://dev.w3.org/csswg/cssom/#resolved-values
+ if ( rnumnonpx.test( ret ) && rmargin.test( name ) ) {
+
+ // Remember the original values
+ width = style.width;
+ minWidth = style.minWidth;
+ maxWidth = style.maxWidth;
+
+ // Put in the new values to get a computed value out
+ style.minWidth = style.maxWidth = style.width = ret;
+ ret = computed.width;
+
+ // Revert the changed values
+ style.width = width;
+ style.minWidth = minWidth;
+ style.maxWidth = maxWidth;
+ }
+ }
+
+ return ret;
+ };
+} else if ( document.documentElement.currentStyle ) {
+ getStyles = function( elem ) {
+ return elem.currentStyle;
+ };
+
+ curCSS = function( elem, name, _computed ) {
+ var left, rs, rsLeft,
+ computed = _computed || getStyles( elem ),
+ ret = computed ? computed[ name ] : undefined,
+ style = elem.style;
+
+ // Avoid setting ret to empty string here
+ // so we don't default to auto
+ if ( ret == null && style && style[ name ] ) {
+ ret = style[ name ];
+ }
+
+ // From the awesome hack by Dean Edwards
+ // http://erik.eae.net/archives/2007/07/27/18.54.15/#comment-102291
+
+ // If we're not dealing with a regular pixel number
+ // but a number that has a weird ending, we need to convert it to pixels
+ // but not position css attributes, as those are proportional to the parent element instead
+ // and we can't measure the parent instead because it might trigger a "stacking dolls" problem
+ if ( rnumnonpx.test( ret ) && !rposition.test( name ) ) {
+
+ // Remember the original values
+ left = style.left;
+ rs = elem.runtimeStyle;
+ rsLeft = rs && rs.left;
+
+ // Put in the new values to get a computed value out
+ if ( rsLeft ) {
+ rs.left = elem.currentStyle.left;
+ }
+ style.left = name === "fontSize" ? "1em" : ret;
+ ret = style.pixelLeft + "px";
+
+ // Revert the changed values
+ style.left = left;
+ if ( rsLeft ) {
+ rs.left = rsLeft;
+ }
+ }
+
+ return ret === "" ? "auto" : ret;
+ };
+}
+
+function setPositiveNumber( elem, value, subtract ) {
+ var matches = rnumsplit.exec( value );
+ return matches ?
+ // Guard against undefined "subtract", e.g., when used as in cssHooks
+ Math.max( 0, matches[ 1 ] - ( subtract || 0 ) ) + ( matches[ 2 ] || "px" ) :
+ value;
+}
+
+function augmentWidthOrHeight( elem, name, extra, isBorderBox, styles ) {
+ var i = extra === ( isBorderBox ? "border" : "content" ) ?
+ // If we already have the right measurement, avoid augmentation
+ 4 :
+ // Otherwise initialize for horizontal or vertical properties
+ name === "width" ? 1 : 0,
+
+ val = 0;
+
+ for ( ; i < 4; i += 2 ) {
+ // both box models exclude margin, so add it if we want it
+ if ( extra === "margin" ) {
+ val += jQuery.css( elem, extra + cssExpand[ i ], true, styles );
+ }
+
+ if ( isBorderBox ) {
+ // border-box includes padding, so remove it if we want content
+ if ( extra === "content" ) {
+ val -= jQuery.css( elem, "padding" + cssExpand[ i ], true, styles );
+ }
+
+ // at this point, extra isn't border nor margin, so remove border
+ if ( extra !== "margin" ) {
+ val -= jQuery.css( elem, "border" + cssExpand[ i ] + "Width", true, styles );
+ }
+ } else {
+ // at this point, extra isn't content, so add padding
+ val += jQuery.css( elem, "padding" + cssExpand[ i ], true, styles );
+
+ // at this point, extra isn't content nor padding, so add border
+ if ( extra !== "padding" ) {
+ val += jQuery.css( elem, "border" + cssExpand[ i ] + "Width", true, styles );
+ }
+ }
+ }
+
+ return val;
+}
+
+function getWidthOrHeight( elem, name, extra ) {
+
+ // Start with offset property, which is equivalent to the border-box value
+ var valueIsBorderBox = true,
+ val = name === "width" ? elem.offsetWidth : elem.offsetHeight,
+ styles = getStyles( elem ),
+ isBorderBox = jQuery.support.boxSizing && jQuery.css( elem, "boxSizing", false, styles ) === "border-box";
+
+ // some non-html elements return undefined for offsetWidth, so check for null/undefined
+ // svg - https://bugzilla.mozilla.org/show_bug.cgi?id=649285
+ // MathML - https://bugzilla.mozilla.org/show_bug.cgi?id=491668
+ if ( val <= 0 || val == null ) {
+ // Fall back to computed then uncomputed css if necessary
+ val = curCSS( elem, name, styles );
+ if ( val < 0 || val == null ) {
+ val = elem.style[ name ];
+ }
+
+ // Computed unit is not pixels. Stop here and return.
+ if ( rnumnonpx.test(val) ) {
+ return val;
+ }
+
+ // we need the check for style in case a browser which returns unreliable values
+ // for getComputedStyle silently falls back to the reliable elem.style
+ valueIsBorderBox = isBorderBox && ( jQuery.support.boxSizingReliable || val === elem.style[ name ] );
+
+ // Normalize "", auto, and prepare for extra
+ val = parseFloat( val ) || 0;
+ }
+
+ // use the active box-sizing model to add/subtract irrelevant styles
+ return ( val +
+ augmentWidthOrHeight(
+ elem,
+ name,
+ extra || ( isBorderBox ? "border" : "content" ),
+ valueIsBorderBox,
+ styles
+ )
+ ) + "px";
+}
+
+// Try to determine the default display value of an element
+function css_defaultDisplay( nodeName ) {
+ var doc = document,
+ display = elemdisplay[ nodeName ];
+
+ if ( !display ) {
+ display = actualDisplay( nodeName, doc );
+
+ // If the simple way fails, read from inside an iframe
+ if ( display === "none" || !display ) {
+ // Use the already-created iframe if possible
+ iframe = ( iframe ||
+ jQuery("<iframe frameborder='0' width='0' height='0'/>")
+ .css( "cssText", "display:block !important" )
+ ).appendTo( doc.documentElement );
+
+ // Always write a new HTML skeleton so Webkit and Firefox don't choke on reuse
+ doc = ( iframe[0].contentWindow || iframe[0].contentDocument ).document;
+ doc.write("<!doctype html><html><body>");
+ doc.close();
+
+ display = actualDisplay( nodeName, doc );
+ iframe.detach();
+ }
+
+ // Store the correct default display
+ elemdisplay[ nodeName ] = display;
+ }
+
+ return display;
+}
+
+// Called ONLY from within css_defaultDisplay
+function actualDisplay( name, doc ) {
+ var elem = jQuery( doc.createElement( name ) ).appendTo( doc.body ),
+ display = jQuery.css( elem[0], "display" );
+ elem.remove();
+ return display;
+}
+
+jQuery.each([ "height", "width" ], function( i, name ) {
+ jQuery.cssHooks[ name ] = {
+ get: function( elem, computed, extra ) {
+ if ( computed ) {
+ // certain elements can have dimension info if we invisibly show them
+ // however, it must have a current display style that would benefit from this
+ return elem.offsetWidth === 0 && rdisplayswap.test( jQuery.css( elem, "display" ) ) ?
+ jQuery.swap( elem, cssShow, function() {
+ return getWidthOrHeight( elem, name, extra );
+ }) :
+ getWidthOrHeight( elem, name, extra );
+ }
+ },
+
+ set: function( elem, value, extra ) {
+ var styles = extra && getStyles( elem );
+ return setPositiveNumber( elem, value, extra ?
+ augmentWidthOrHeight(
+ elem,
+ name,
+ extra,
+ jQuery.support.boxSizing && jQuery.css( elem, "boxSizing", false, styles ) === "border-box",
+ styles
+ ) : 0
+ );
+ }
+ };
+});
+
+if ( !jQuery.support.opacity ) {
+ jQuery.cssHooks.opacity = {
+ get: function( elem, computed ) {
+ // IE uses filters for opacity
+ return ropacity.test( (computed && elem.currentStyle ? elem.currentStyle.filter : elem.style.filter) || "" ) ?
+ ( 0.01 * parseFloat( RegExp.$1 ) ) + "" :
+ computed ? "1" : "";
+ },
+
+ set: function( elem, value ) {
+ var style = elem.style,
+ currentStyle = elem.currentStyle,
+ opacity = jQuery.isNumeric( value ) ? "alpha(opacity=" + value * 100 + ")" : "",
+ filter = currentStyle && currentStyle.filter || style.filter || "";
+
+ // IE has trouble with opacity if it does not have layout
+ // Force it by setting the zoom level
+ style.zoom = 1;
+
+ // if setting opacity to 1, and no other filters exist - attempt to remove filter attribute #6652
+ // if value === "", then remove inline opacity #12685
+ if ( ( value >= 1 || value === "" ) &&
+ jQuery.trim( filter.replace( ralpha, "" ) ) === "" &&
+ style.removeAttribute ) {
+
+ // Setting style.filter to null, "" & " " still leave "filter:" in the cssText
+ // if "filter:" is present at all, clearType is disabled, we want to avoid this
+ // style.removeAttribute is IE Only, but so apparently is this code path...
+ style.removeAttribute( "filter" );
+
+ // if there is no filter style applied in a css rule or unset inline opacity, we are done
+ if ( value === "" || currentStyle && !currentStyle.filter ) {
+ return;
+ }
+ }
+
+ // otherwise, set new filter values
+ style.filter = ralpha.test( filter ) ?
+ filter.replace( ralpha, opacity ) :
+ filter + " " + opacity;
+ }
+ };
+}
+
+// These hooks cannot be added until DOM ready because the support test
+// for it is not run until after DOM ready
+jQuery(function() {
+ if ( !jQuery.support.reliableMarginRight ) {
+ jQuery.cssHooks.marginRight = {
+ get: function( elem, computed ) {
+ if ( computed ) {
+ // WebKit Bug 13343 - getComputedStyle returns wrong value for margin-right
+ // Work around by temporarily setting element display to inline-block
+ return jQuery.swap( elem, { "display": "inline-block" },
+ curCSS, [ elem, "marginRight" ] );
+ }
+ }
+ };
+ }
+
+ // Webkit bug: https://bugs.webkit.org/show_bug.cgi?id=29084
+ // getComputedStyle returns percent when specified for top/left/bottom/right
+ // rather than make the css module depend on the offset module, we just check for it here
+ if ( !jQuery.support.pixelPosition && jQuery.fn.position ) {
+ jQuery.each( [ "top", "left" ], function( i, prop ) {
+ jQuery.cssHooks[ prop ] = {
+ get: function( elem, computed ) {
+ if ( computed ) {
+ computed = curCSS( elem, prop );
+ // if curCSS returns percentage, fallback to offset
+ return rnumnonpx.test( computed ) ?
+ jQuery( elem ).position()[ prop ] + "px" :
+ computed;
+ }
+ }
+ };
+ });
+ }
+
+});
+
+if ( jQuery.expr && jQuery.expr.filters ) {
+ jQuery.expr.filters.hidden = function( elem ) {
+ // Support: Opera <= 12.12
+ // Opera reports offsetWidths and offsetHeights less than zero on some elements
+ return elem.offsetWidth <= 0 && elem.offsetHeight <= 0 ||
+ (!jQuery.support.reliableHiddenOffsets && ((elem.style && elem.style.display) || jQuery.css( elem, "display" )) === "none");
+ };
+
+ jQuery.expr.filters.visible = function( elem ) {
+ return !jQuery.expr.filters.hidden( elem );
+ };
+}
+
+// These hooks are used by animate to expand properties
+jQuery.each({
+ margin: "",
+ padding: "",
+ border: "Width"
+}, function( prefix, suffix ) {
+ jQuery.cssHooks[ prefix + suffix ] = {
+ expand: function( value ) {
+ var i = 0,
+ expanded = {},
+
+ // assumes a single number if not a string
+ parts = typeof value === "string" ? value.split(" ") : [ value ];
+
+ for ( ; i < 4; i++ ) {
+ expanded[ prefix + cssExpand[ i ] + suffix ] =
+ parts[ i ] || parts[ i - 2 ] || parts[ 0 ];
+ }
+
+ return expanded;
+ }
+ };
+
+ if ( !rmargin.test( prefix ) ) {
+ jQuery.cssHooks[ prefix + suffix ].set = setPositiveNumber;
+ }
+});
+var r20 = /%20/g,
+ rbracket = /\[\]$/,
+ rCRLF = /\r?\n/g,
+ rsubmitterTypes = /^(?:submit|button|image|reset|file)$/i,
+ rsubmittable = /^(?:input|select|textarea|keygen)/i;
+
+jQuery.fn.extend({
+ serialize: function() {
+ return jQuery.param( this.serializeArray() );
+ },
+ serializeArray: function() {
+ return this.map(function(){
+ // Can add propHook for "elements" to filter or add form elements
+ var elements = jQuery.prop( this, "elements" );
+ return elements ? jQuery.makeArray( elements ) : this;
+ })
+ .filter(function(){
+ var type = this.type;
+ // Use .is(":disabled") so that fieldset[disabled] works
+ return this.name && !jQuery( this ).is( ":disabled" ) &&
+ rsubmittable.test( this.nodeName ) && !rsubmitterTypes.test( type ) &&
+ ( this.checked || !manipulation_rcheckableType.test( type ) );
+ })
+ .map(function( i, elem ){
+ var val = jQuery( this ).val();
+
+ return val == null ?
+ null :
+ jQuery.isArray( val ) ?
+ jQuery.map( val, function( val ){
+ return { name: elem.name, value: val.replace( rCRLF, "\r\n" ) };
+ }) :
+ { name: elem.name, value: val.replace( rCRLF, "\r\n" ) };
+ }).get();
+ }
+});
+
+//Serialize an array of form elements or a set of
+//key/values into a query string
+jQuery.param = function( a, traditional ) {
+ var prefix,
+ s = [],
+ add = function( key, value ) {
+ // If value is a function, invoke it and return its value
+ value = jQuery.isFunction( value ) ? value() : ( value == null ? "" : value );
+ s[ s.length ] = encodeURIComponent( key ) + "=" + encodeURIComponent( value );
+ };
+
+ // Set traditional to true for jQuery <= 1.3.2 behavior.
+ if ( traditional === undefined ) {
+ traditional = jQuery.ajaxSettings && jQuery.ajaxSettings.traditional;
+ }
+
+ // If an array was passed in, assume that it is an array of form elements.
+ if ( jQuery.isArray( a ) || ( a.jquery && !jQuery.isPlainObject( a ) ) ) {
+ // Serialize the form elements
+ jQuery.each( a, function() {
+ add( this.name, this.value );
+ });
+
+ } else {
+ // If traditional, encode the "old" way (the way 1.3.2 or older
+ // did it), otherwise encode params recursively.
+ for ( prefix in a ) {
+ buildParams( prefix, a[ prefix ], traditional, add );
+ }
+ }
+
+ // Return the resulting serialization
+ return s.join( "&" ).replace( r20, "+" );
+};
+
+function buildParams( prefix, obj, traditional, add ) {
+ var name;
+
+ if ( jQuery.isArray( obj ) ) {
+ // Serialize array item.
+ jQuery.each( obj, function( i, v ) {
+ if ( traditional || rbracket.test( prefix ) ) {
+ // Treat each array item as a scalar.
+ add( prefix, v );
+
+ } else {
+ // Item is non-scalar (array or object), encode its numeric index.
+ buildParams( prefix + "[" + ( typeof v === "object" ? i : "" ) + "]", v, traditional, add );
+ }
+ });
+
+ } else if ( !traditional && jQuery.type( obj ) === "object" ) {
+ // Serialize object item.
+ for ( name in obj ) {
+ buildParams( prefix + "[" + name + "]", obj[ name ], traditional, add );
+ }
+
+ } else {
+ // Serialize scalar item.
+ add( prefix, obj );
+ }
+}
+jQuery.each( ("blur focus focusin focusout load resize scroll unload click dblclick " +
+ "mousedown mouseup mousemove mouseover mouseout mouseenter mouseleave " +
+ "change select submit keydown keypress keyup error contextmenu").split(" "), function( i, name ) {
+
+ // Handle event binding
+ jQuery.fn[ name ] = function( data, fn ) {
+ return arguments.length > 0 ?
+ this.on( name, null, data, fn ) :
+ this.trigger( name );
+ };
+});
+
+jQuery.fn.extend({
+ hover: function( fnOver, fnOut ) {
+ return this.mouseenter( fnOver ).mouseleave( fnOut || fnOver );
+ },
+
+ bind: function( types, data, fn ) {
+ return this.on( types, null, data, fn );
+ },
+ unbind: function( types, fn ) {
+ return this.off( types, null, fn );
+ },
+
+ delegate: function( selector, types, data, fn ) {
+ return this.on( types, selector, data, fn );
+ },
+ undelegate: function( selector, types, fn ) {
+ // ( namespace ) or ( selector, types [, fn] )
+ return arguments.length === 1 ? this.off( selector, "**" ) : this.off( types, selector || "**", fn );
+ }
+});
+var
+ // Document location
+ ajaxLocParts,
+ ajaxLocation,
+ ajax_nonce = jQuery.now(),
+
+ ajax_rquery = /\?/,
+ rhash = /#.*$/,
+ rts = /([?&])_=[^&]*/,
+ rheaders = /^(.*?):[ \t]*([^\r\n]*)\r?$/mg, // IE leaves an \r character at EOL
+ // #7653, #8125, #8152: local protocol detection
+ rlocalProtocol = /^(?:about|app|app-storage|.+-extension|file|res|widget):$/,
+ rnoContent = /^(?:GET|HEAD)$/,
+ rprotocol = /^\/\//,
+ rurl = /^([\w.+-]+:)(?:\/\/([^\/?#:]*)(?::(\d+)|)|)/,
+
+ // Keep a copy of the old load method
+ _load = jQuery.fn.load,
+
+ /* Prefilters
+ * 1) They are useful to introduce custom dataTypes (see ajax/jsonp.js for an example)
+ * 2) These are called:
+ * - BEFORE asking for a transport
+ * - AFTER param serialization (s.data is a string if s.processData is true)
+ * 3) key is the dataType
+ * 4) the catchall symbol "*" can be used
+ * 5) execution will start with transport dataType and THEN continue down to "*" if needed
+ */
+ prefilters = {},
+
+ /* Transports bindings
+ * 1) key is the dataType
+ * 2) the catchall symbol "*" can be used
+ * 3) selection will start with transport dataType and THEN go to "*" if needed
+ */
+ transports = {},
+
+ // Avoid comment-prolog char sequence (#10098); must appease lint and evade compression
+ allTypes = "*/".concat("*");
+
+// #8138, IE may throw an exception when accessing
+// a field from window.location if document.domain has been set
+try {
+ ajaxLocation = location.href;
+} catch( e ) {
+ // Use the href attribute of an A element
+ // since IE will modify it given document.location
+ ajaxLocation = document.createElement( "a" );
+ ajaxLocation.href = "";
+ ajaxLocation = ajaxLocation.href;
+}
+
+// Segment location into parts
+ajaxLocParts = rurl.exec( ajaxLocation.toLowerCase() ) || [];
+
+// Base "constructor" for jQuery.ajaxPrefilter and jQuery.ajaxTransport
+function addToPrefiltersOrTransports( structure ) {
+
+ // dataTypeExpression is optional and defaults to "*"
+ return function( dataTypeExpression, func ) {
+
+ if ( typeof dataTypeExpression !== "string" ) {
+ func = dataTypeExpression;
+ dataTypeExpression = "*";
+ }
+
+ var dataType,
+ i = 0,
+ dataTypes = dataTypeExpression.toLowerCase().match( core_rnotwhite ) || [];
+
+ if ( jQuery.isFunction( func ) ) {
+ // For each dataType in the dataTypeExpression
+ while ( (dataType = dataTypes[i++]) ) {
+ // Prepend if requested
+ if ( dataType[0] === "+" ) {
+ dataType = dataType.slice( 1 ) || "*";
+ (structure[ dataType ] = structure[ dataType ] || []).unshift( func );
+
+ // Otherwise append
+ } else {
+ (structure[ dataType ] = structure[ dataType ] || []).push( func );
+ }
+ }
+ }
+ };
+}
+
+// Base inspection function for prefilters and transports
+function inspectPrefiltersOrTransports( structure, options, originalOptions, jqXHR ) {
+
+ var inspected = {},
+ seekingTransport = ( structure === transports );
+
+ function inspect( dataType ) {
+ var selected;
+ inspected[ dataType ] = true;
+ jQuery.each( structure[ dataType ] || [], function( _, prefilterOrFactory ) {
+ var dataTypeOrTransport = prefilterOrFactory( options, originalOptions, jqXHR );
+ if( typeof dataTypeOrTransport === "string" && !seekingTransport && !inspected[ dataTypeOrTransport ] ) {
+ options.dataTypes.unshift( dataTypeOrTransport );
+ inspect( dataTypeOrTransport );
+ return false;
+ } else if ( seekingTransport ) {
+ return !( selected = dataTypeOrTransport );
+ }
+ });
+ return selected;
+ }
+
+ return inspect( options.dataTypes[ 0 ] ) || !inspected[ "*" ] && inspect( "*" );
+}
+
+// A special extend for ajax options
+// that takes "flat" options (not to be deep extended)
+// Fixes #9887
+function ajaxExtend( target, src ) {
+ var deep, key,
+ flatOptions = jQuery.ajaxSettings.flatOptions || {};
+
+ for ( key in src ) {
+ if ( src[ key ] !== undefined ) {
+ ( flatOptions[ key ] ? target : ( deep || (deep = {}) ) )[ key ] = src[ key ];
+ }
+ }
+ if ( deep ) {
+ jQuery.extend( true, target, deep );
+ }
+
+ return target;
+}
+
+jQuery.fn.load = function( url, params, callback ) {
+ if ( typeof url !== "string" && _load ) {
+ return _load.apply( this, arguments );
+ }
+
+ var selector, response, type,
+ self = this,
+ off = url.indexOf(" ");
+
+ if ( off >= 0 ) {
+ selector = url.slice( off, url.length );
+ url = url.slice( 0, off );
+ }
+
+ // If it's a function
+ if ( jQuery.isFunction( params ) ) {
+
+ // We assume that it's the callback
+ callback = params;
+ params = undefined;
+
+ // Otherwise, build a param string
+ } else if ( params && typeof params === "object" ) {
+ type = "POST";
+ }
+
+ // If we have elements to modify, make the request
+ if ( self.length > 0 ) {
+ jQuery.ajax({
+ url: url,
+
+ // if "type" variable is undefined, then "GET" method will be used
+ type: type,
+ dataType: "html",
+ data: params
+ }).done(function( responseText ) {
+
+ // Save response for use in complete callback
+ response = arguments;
+
+ self.html( selector ?
+
+ // If a selector was specified, locate the right elements in a dummy div
+ // Exclude scripts to avoid IE 'Permission Denied' errors
+ jQuery("<div>").append( jQuery.parseHTML( responseText ) ).find( selector ) :
+
+ // Otherwise use the full result
+ responseText );
+
+ }).complete( callback && function( jqXHR, status ) {
+ self.each( callback, response || [ jqXHR.responseText, status, jqXHR ] );
+ });
+ }
+
+ return this;
+};
+
+// Attach a bunch of functions for handling common AJAX events
+jQuery.each( [ "ajaxStart", "ajaxStop", "ajaxComplete", "ajaxError", "ajaxSuccess", "ajaxSend" ], function( i, type ){
+ jQuery.fn[ type ] = function( fn ){
+ return this.on( type, fn );
+ };
+});
+
+jQuery.extend({
+
+ // Counter for holding the number of active queries
+ active: 0,
+
+ // Last-Modified header cache for next request
+ lastModified: {},
+ etag: {},
+
+ ajaxSettings: {
+ url: ajaxLocation,
+ type: "GET",
+ isLocal: rlocalProtocol.test( ajaxLocParts[ 1 ] ),
+ global: true,
+ processData: true,
+ async: true,
+ contentType: "application/x-www-form-urlencoded; charset=UTF-8",
+ /*
+ timeout: 0,
+ data: null,
+ dataType: null,
+ username: null,
+ password: null,
+ cache: null,
+ throws: false,
+ traditional: false,
+ headers: {},
+ */
+
+ accepts: {
+ "*": allTypes,
+ text: "text/plain",
+ html: "text/html",
+ xml: "application/xml, text/xml",
+ json: "application/json, text/javascript"
+ },
+
+ contents: {
+ xml: /xml/,
+ html: /html/,
+ json: /json/
+ },
+
+ responseFields: {
+ xml: "responseXML",
+ text: "responseText",
+ json: "responseJSON"
+ },
+
+ // Data converters
+ // Keys separate source (or catchall "*") and destination types with a single space
+ converters: {
+
+ // Convert anything to text
+ "* text": String,
+
+ // Text to html (true = no transformation)
+ "text html": true,
+
+ // Evaluate text as a json expression
+ "text json": jQuery.parseJSON,
+
+ // Parse text as xml
+ "text xml": jQuery.parseXML
+ },
+
+ // For options that shouldn't be deep extended:
+ // you can add your own custom options here if
+ // and when you create one that shouldn't be
+ // deep extended (see ajaxExtend)
+ flatOptions: {
+ url: true,
+ context: true
+ }
+ },
+
+ // Creates a full fledged settings object into target
+ // with both ajaxSettings and settings fields.
+ // If target is omitted, writes into ajaxSettings.
+ ajaxSetup: function( target, settings ) {
+ return settings ?
+
+ // Building a settings object
+ ajaxExtend( ajaxExtend( target, jQuery.ajaxSettings ), settings ) :
+
+ // Extending ajaxSettings
+ ajaxExtend( jQuery.ajaxSettings, target );
+ },
+
+ ajaxPrefilter: addToPrefiltersOrTransports( prefilters ),
+ ajaxTransport: addToPrefiltersOrTransports( transports ),
+
+ // Main method
+ ajax: function( url, options ) {
+
+ // If url is an object, simulate pre-1.5 signature
+ if ( typeof url === "object" ) {
+ options = url;
+ url = undefined;
+ }
+
+ // Force options to be an object
+ options = options || {};
+
+ var // Cross-domain detection vars
+ parts,
+ // Loop variable
+ i,
+ // URL without anti-cache param
+ cacheURL,
+ // Response headers as string
+ responseHeadersString,
+ // timeout handle
+ timeoutTimer,
+
+ // To know if global events are to be dispatched
+ fireGlobals,
+
+ transport,
+ // Response headers
+ responseHeaders,
+ // Create the final options object
+ s = jQuery.ajaxSetup( {}, options ),
+ // Callbacks context
+ callbackContext = s.context || s,
+ // Context for global events is callbackContext if it is a DOM node or jQuery collection
+ globalEventContext = s.context && ( callbackContext.nodeType || callbackContext.jquery ) ?
+ jQuery( callbackContext ) :
+ jQuery.event,
+ // Deferreds
+ deferred = jQuery.Deferred(),
+ completeDeferred = jQuery.Callbacks("once memory"),
+ // Status-dependent callbacks
+ statusCode = s.statusCode || {},
+ // Headers (they are sent all at once)
+ requestHeaders = {},
+ requestHeadersNames = {},
+ // The jqXHR state
+ state = 0,
+ // Default abort message
+ strAbort = "canceled",
+ // Fake xhr
+ jqXHR = {
+ readyState: 0,
+
+ // Builds headers hashtable if needed
+ getResponseHeader: function( key ) {
+ var match;
+ if ( state === 2 ) {
+ if ( !responseHeaders ) {
+ responseHeaders = {};
+ while ( (match = rheaders.exec( responseHeadersString )) ) {
+ responseHeaders[ match[1].toLowerCase() ] = match[ 2 ];
+ }
+ }
+ match = responseHeaders[ key.toLowerCase() ];
+ }
+ return match == null ? null : match;
+ },
+
+ // Raw string
+ getAllResponseHeaders: function() {
+ return state === 2 ? responseHeadersString : null;
+ },
+
+ // Caches the header
+ setRequestHeader: function( name, value ) {
+ var lname = name.toLowerCase();
+ if ( !state ) {
+ name = requestHeadersNames[ lname ] = requestHeadersNames[ lname ] || name;
+ requestHeaders[ name ] = value;
+ }
+ return this;
+ },
+
+ // Overrides response content-type header
+ overrideMimeType: function( type ) {
+ if ( !state ) {
+ s.mimeType = type;
+ }
+ return this;
+ },
+
+ // Status-dependent callbacks
+ statusCode: function( map ) {
+ var code;
+ if ( map ) {
+ if ( state < 2 ) {
+ for ( code in map ) {
+ // Lazy-add the new callback in a way that preserves old ones
+ statusCode[ code ] = [ statusCode[ code ], map[ code ] ];
+ }
+ } else {
+ // Execute the appropriate callbacks
+ jqXHR.always( map[ jqXHR.status ] );
+ }
+ }
+ return this;
+ },
+
+ // Cancel the request
+ abort: function( statusText ) {
+ var finalText = statusText || strAbort;
+ if ( transport ) {
+ transport.abort( finalText );
+ }
+ done( 0, finalText );
+ return this;
+ }
+ };
+
+ // Attach deferreds
+ deferred.promise( jqXHR ).complete = completeDeferred.add;
+ jqXHR.success = jqXHR.done;
+ jqXHR.error = jqXHR.fail;
+
+ // Remove hash character (#7531: and string promotion)
+ // Add protocol if not provided (#5866: IE7 issue with protocol-less urls)
+ // Handle falsy url in the settings object (#10093: consistency with old signature)
+ // We also use the url parameter if available
+ s.url = ( ( url || s.url || ajaxLocation ) + "" ).replace( rhash, "" ).replace( rprotocol, ajaxLocParts[ 1 ] + "//" );
+
+ // Alias method option to type as per ticket #12004
+ s.type = options.method || options.type || s.method || s.type;
+
+ // Extract dataTypes list
+ s.dataTypes = jQuery.trim( s.dataType || "*" ).toLowerCase().match( core_rnotwhite ) || [""];
+
+ // A cross-domain request is in order when we have a protocol:host:port mismatch
+ if ( s.crossDomain == null ) {
+ parts = rurl.exec( s.url.toLowerCase() );
+ s.crossDomain = !!( parts &&
+ ( parts[ 1 ] !== ajaxLocParts[ 1 ] || parts[ 2 ] !== ajaxLocParts[ 2 ] ||
+ ( parts[ 3 ] || ( parts[ 1 ] === "http:" ? "80" : "443" ) ) !==
+ ( ajaxLocParts[ 3 ] || ( ajaxLocParts[ 1 ] === "http:" ? "80" : "443" ) ) )
+ );
+ }
+
+ // Convert data if not already a string
+ if ( s.data && s.processData && typeof s.data !== "string" ) {
+ s.data = jQuery.param( s.data, s.traditional );
+ }
+
+ // Apply prefilters
+ inspectPrefiltersOrTransports( prefilters, s, options, jqXHR );
+
+ // If request was aborted inside a prefilter, stop there
+ if ( state === 2 ) {
+ return jqXHR;
+ }
+
+ // We can fire global events as of now if asked to
+ fireGlobals = s.global;
+
+ // Watch for a new set of requests
+ if ( fireGlobals && jQuery.active++ === 0 ) {
+ jQuery.event.trigger("ajaxStart");
+ }
+
+ // Uppercase the type
+ s.type = s.type.toUpperCase();
+
+ // Determine if request has content
+ s.hasContent = !rnoContent.test( s.type );
+
+ // Save the URL in case we're toying with the If-Modified-Since
+ // and/or If-None-Match header later on
+ cacheURL = s.url;
+
+ // More options handling for requests with no content
+ if ( !s.hasContent ) {
+
+ // If data is available, append data to url
+ if ( s.data ) {
+ cacheURL = ( s.url += ( ajax_rquery.test( cacheURL ) ? "&" : "?" ) + s.data );
+ // #9682: remove data so that it's not used in an eventual retry
+ delete s.data;
+ }
+
+ // Add anti-cache in url if needed
+ if ( s.cache === false ) {
+ s.url = rts.test( cacheURL ) ?
+
+ // If there is already a '_' parameter, set its value
+ cacheURL.replace( rts, "$1_=" + ajax_nonce++ ) :
+
+ // Otherwise add one to the end
+ cacheURL + ( ajax_rquery.test( cacheURL ) ? "&" : "?" ) + "_=" + ajax_nonce++;
+ }
+ }
+
+ // Set the If-Modified-Since and/or If-None-Match header, if in ifModified mode.
+ if ( s.ifModified ) {
+ if ( jQuery.lastModified[ cacheURL ] ) {
+ jqXHR.setRequestHeader( "If-Modified-Since", jQuery.lastModified[ cacheURL ] );
+ }
+ if ( jQuery.etag[ cacheURL ] ) {
+ jqXHR.setRequestHeader( "If-None-Match", jQuery.etag[ cacheURL ] );
+ }
+ }
+
+ // Set the correct header, if data is being sent
+ if ( s.data && s.hasContent && s.contentType !== false || options.contentType ) {
+ jqXHR.setRequestHeader( "Content-Type", s.contentType );
+ }
+
+ // Set the Accepts header for the server, depending on the dataType
+ jqXHR.setRequestHeader(
+ "Accept",
+ s.dataTypes[ 0 ] && s.accepts[ s.dataTypes[0] ] ?
+ s.accepts[ s.dataTypes[0] ] + ( s.dataTypes[ 0 ] !== "*" ? ", " + allTypes + "; q=0.01" : "" ) :
+ s.accepts[ "*" ]
+ );
+
+ // Check for headers option
+ for ( i in s.headers ) {
+ jqXHR.setRequestHeader( i, s.headers[ i ] );
+ }
+
+ // Allow custom headers/mimetypes and early abort
+ if ( s.beforeSend && ( s.beforeSend.call( callbackContext, jqXHR, s ) === false || state === 2 ) ) {
+ // Abort if not done already and return
+ return jqXHR.abort();
+ }
+
+ // aborting is no longer a cancellation
+ strAbort = "abort";
+
+ // Install callbacks on deferreds
+ for ( i in { success: 1, error: 1, complete: 1 } ) {
+ jqXHR[ i ]( s[ i ] );
+ }
+
+ // Get transport
+ transport = inspectPrefiltersOrTransports( transports, s, options, jqXHR );
+
+ // If no transport, we auto-abort
+ if ( !transport ) {
+ done( -1, "No Transport" );
+ } else {
+ jqXHR.readyState = 1;
+
+ // Send global event
+ if ( fireGlobals ) {
+ globalEventContext.trigger( "ajaxSend", [ jqXHR, s ] );
+ }
+ // Timeout
+ if ( s.async && s.timeout > 0 ) {
+ timeoutTimer = setTimeout(function() {
+ jqXHR.abort("timeout");
+ }, s.timeout );
+ }
+
+ try {
+ state = 1;
+ transport.send( requestHeaders, done );
+ } catch ( e ) {
+ // Propagate exception as error if not done
+ if ( state < 2 ) {
+ done( -1, e );
+ // Simply rethrow otherwise
+ } else {
+ throw e;
+ }
+ }
+ }
+
+ // Callback for when everything is done
+ function done( status, nativeStatusText, responses, headers ) {
+ var isSuccess, success, error, response, modified,
+ statusText = nativeStatusText;
+
+ // Called once
+ if ( state === 2 ) {
+ return;
+ }
+
+ // State is "done" now
+ state = 2;
+
+ // Clear timeout if it exists
+ if ( timeoutTimer ) {
+ clearTimeout( timeoutTimer );
+ }
+
+ // Dereference transport for early garbage collection
+ // (no matter how long the jqXHR object will be used)
+ transport = undefined;
+
+ // Cache response headers
+ responseHeadersString = headers || "";
+
+ // Set readyState
+ jqXHR.readyState = status > 0 ? 4 : 0;
+
+ // Determine if successful
+ isSuccess = status >= 200 && status < 300 || status === 304;
+
+ // Get response data
+ if ( responses ) {
+ response = ajaxHandleResponses( s, jqXHR, responses );
+ }
+
+ // Convert no matter what (that way responseXXX fields are always set)
+ response = ajaxConvert( s, response, jqXHR, isSuccess );
+
+ // If successful, handle type chaining
+ if ( isSuccess ) {
+
+ // Set the If-Modified-Since and/or If-None-Match header, if in ifModified mode.
+ if ( s.ifModified ) {
+ modified = jqXHR.getResponseHeader("Last-Modified");
+ if ( modified ) {
+ jQuery.lastModified[ cacheURL ] = modified;
+ }
+ modified = jqXHR.getResponseHeader("etag");
+ if ( modified ) {
+ jQuery.etag[ cacheURL ] = modified;
+ }
+ }
+
+ // if no content
+ if ( status === 204 || s.type === "HEAD" ) {
+ statusText = "nocontent";
+
+ // if not modified
+ } else if ( status === 304 ) {
+ statusText = "notmodified";
+
+ // If we have data, let's convert it
+ } else {
+ statusText = response.state;
+ success = response.data;
+ error = response.error;
+ isSuccess = !error;
+ }
+ } else {
+ // We extract error from statusText
+ // then normalize statusText and status for non-aborts
+ error = statusText;
+ if ( status || !statusText ) {
+ statusText = "error";
+ if ( status < 0 ) {
+ status = 0;
+ }
+ }
+ }
+
+ // Set data for the fake xhr object
+ jqXHR.status = status;
+ jqXHR.statusText = ( nativeStatusText || statusText ) + "";
+
+ // Success/Error
+ if ( isSuccess ) {
+ deferred.resolveWith( callbackContext, [ success, statusText, jqXHR ] );
+ } else {
+ deferred.rejectWith( callbackContext, [ jqXHR, statusText, error ] );
+ }
+
+ // Status-dependent callbacks
+ jqXHR.statusCode( statusCode );
+ statusCode = undefined;
+
+ if ( fireGlobals ) {
+ globalEventContext.trigger( isSuccess ? "ajaxSuccess" : "ajaxError",
+ [ jqXHR, s, isSuccess ? success : error ] );
+ }
+
+ // Complete
+ completeDeferred.fireWith( callbackContext, [ jqXHR, statusText ] );
+
+ if ( fireGlobals ) {
+ globalEventContext.trigger( "ajaxComplete", [ jqXHR, s ] );
+ // Handle the global AJAX counter
+ if ( !( --jQuery.active ) ) {
+ jQuery.event.trigger("ajaxStop");
+ }
+ }
+ }
+
+ return jqXHR;
+ },
+
+ getJSON: function( url, data, callback ) {
+ return jQuery.get( url, data, callback, "json" );
+ },
+
+ getScript: function( url, callback ) {
+ return jQuery.get( url, undefined, callback, "script" );
+ }
+});
+
+jQuery.each( [ "get", "post" ], function( i, method ) {
+ jQuery[ method ] = function( url, data, callback, type ) {
+ // shift arguments if data argument was omitted
+ if ( jQuery.isFunction( data ) ) {
+ type = type || callback;
+ callback = data;
+ data = undefined;
+ }
+
+ return jQuery.ajax({
+ url: url,
+ type: method,
+ dataType: type,
+ data: data,
+ success: callback
+ });
+ };
+});
+
+/* Handles responses to an ajax request:
+ * - finds the right dataType (mediates between content-type and expected dataType)
+ * - returns the corresponding response
+ */
+function ajaxHandleResponses( s, jqXHR, responses ) {
+ var firstDataType, ct, finalDataType, type,
+ contents = s.contents,
+ dataTypes = s.dataTypes;
+
+ // Remove auto dataType and get content-type in the process
+ while( dataTypes[ 0 ] === "*" ) {
+ dataTypes.shift();
+ if ( ct === undefined ) {
+ ct = s.mimeType || jqXHR.getResponseHeader("Content-Type");
+ }
+ }
+
+ // Check if we're dealing with a known content-type
+ if ( ct ) {
+ for ( type in contents ) {
+ if ( contents[ type ] && contents[ type ].test( ct ) ) {
+ dataTypes.unshift( type );
+ break;
+ }
+ }
+ }
+
+ // Check to see if we have a response for the expected dataType
+ if ( dataTypes[ 0 ] in responses ) {
+ finalDataType = dataTypes[ 0 ];
+ } else {
+ // Try convertible dataTypes
+ for ( type in responses ) {
+ if ( !dataTypes[ 0 ] || s.converters[ type + " " + dataTypes[0] ] ) {
+ finalDataType = type;
+ break;
+ }
+ if ( !firstDataType ) {
+ firstDataType = type;
+ }
+ }
+ // Or just use first one
+ finalDataType = finalDataType || firstDataType;
+ }
+
+ // If we found a dataType
+ // We add the dataType to the list if needed
+ // and return the corresponding response
+ if ( finalDataType ) {
+ if ( finalDataType !== dataTypes[ 0 ] ) {
+ dataTypes.unshift( finalDataType );
+ }
+ return responses[ finalDataType ];
+ }
+}
+
+/* Chain conversions given the request and the original response
+ * Also sets the responseXXX fields on the jqXHR instance
+ */
+function ajaxConvert( s, response, jqXHR, isSuccess ) {
+ var conv2, current, conv, tmp, prev,
+ converters = {},
+ // Work with a copy of dataTypes in case we need to modify it for conversion
+ dataTypes = s.dataTypes.slice();
+
+ // Create converters map with lowercased keys
+ if ( dataTypes[ 1 ] ) {
+ for ( conv in s.converters ) {
+ converters[ conv.toLowerCase() ] = s.converters[ conv ];
+ }
+ }
+
+ current = dataTypes.shift();
+
+ // Convert to each sequential dataType
+ while ( current ) {
+
+ if ( s.responseFields[ current ] ) {
+ jqXHR[ s.responseFields[ current ] ] = response;
+ }
+
+ // Apply the dataFilter if provided
+ if ( !prev && isSuccess && s.dataFilter ) {
+ response = s.dataFilter( response, s.dataType );
+ }
+
+ prev = current;
+ current = dataTypes.shift();
+
+ if ( current ) {
+
+ // There's only work to do if current dataType is non-auto
+ if ( current === "*" ) {
+
+ current = prev;
+
+ // Convert response if prev dataType is non-auto and differs from current
+ } else if ( prev !== "*" && prev !== current ) {
+
+ // Seek a direct converter
+ conv = converters[ prev + " " + current ] || converters[ "* " + current ];
+
+ // If none found, seek a pair
+ if ( !conv ) {
+ for ( conv2 in converters ) {
+
+ // If conv2 outputs current
+ tmp = conv2.split( " " );
+ if ( tmp[ 1 ] === current ) {
+
+ // If prev can be converted to accepted input
+ conv = converters[ prev + " " + tmp[ 0 ] ] ||
+ converters[ "* " + tmp[ 0 ] ];
+ if ( conv ) {
+ // Condense equivalence converters
+ if ( conv === true ) {
+ conv = converters[ conv2 ];
+
+ // Otherwise, insert the intermediate dataType
+ } else if ( converters[ conv2 ] !== true ) {
+ current = tmp[ 0 ];
+ dataTypes.unshift( tmp[ 1 ] );
+ }
+ break;
+ }
+ }
+ }
+ }
+
+ // Apply converter (if not an equivalence)
+ if ( conv !== true ) {
+
+ // Unless errors are allowed to bubble, catch and return them
+ if ( conv && s[ "throws" ] ) {
+ response = conv( response );
+ } else {
+ try {
+ response = conv( response );
+ } catch ( e ) {
+ return { state: "parsererror", error: conv ? e : "No conversion from " + prev + " to " + current };
+ }
+ }
+ }
+ }
+ }
+ }
+
+ return { state: "success", data: response };
+}
+// Install script dataType
+jQuery.ajaxSetup({
+ accepts: {
+ script: "text/javascript, application/javascript, application/ecmascript, application/x-ecmascript"
+ },
+ contents: {
+ script: /(?:java|ecma)script/
+ },
+ converters: {
+ "text script": function( text ) {
+ jQuery.globalEval( text );
+ return text;
+ }
+ }
+});
+
+// Handle cache's special case and global
+jQuery.ajaxPrefilter( "script", function( s ) {
+ if ( s.cache === undefined ) {
+ s.cache = false;
+ }
+ if ( s.crossDomain ) {
+ s.type = "GET";
+ s.global = false;
+ }
+});
+
+// Bind script tag hack transport
+jQuery.ajaxTransport( "script", function(s) {
+
+ // This transport only deals with cross domain requests
+ if ( s.crossDomain ) {
+
+ var script,
+ head = document.head || jQuery("head")[0] || document.documentElement;
+
+ return {
+
+ send: function( _, callback ) {
+
+ script = document.createElement("script");
+
+ script.async = true;
+
+ if ( s.scriptCharset ) {
+ script.charset = s.scriptCharset;
+ }
+
+ script.src = s.url;
+
+ // Attach handlers for all browsers
+ script.onload = script.onreadystatechange = function( _, isAbort ) {
+
+ if ( isAbort || !script.readyState || /loaded|complete/.test( script.readyState ) ) {
+
+ // Handle memory leak in IE
+ script.onload = script.onreadystatechange = null;
+
+ // Remove the script
+ if ( script.parentNode ) {
+ script.parentNode.removeChild( script );
+ }
+
+ // Dereference the script
+ script = null;
+
+ // Callback if not abort
+ if ( !isAbort ) {
+ callback( 200, "success" );
+ }
+ }
+ };
+
+ // Circumvent IE6 bugs with base elements (#2709 and #4378) by prepending
+ // Use native DOM manipulation to avoid our domManip AJAX trickery
+ head.insertBefore( script, head.firstChild );
+ },
+
+ abort: function() {
+ if ( script ) {
+ script.onload( undefined, true );
+ }
+ }
+ };
+ }
+});
+var oldCallbacks = [],
+ rjsonp = /(=)\?(?=&|$)|\?\?/;
+
+// Default jsonp settings
+jQuery.ajaxSetup({
+ jsonp: "callback",
+ jsonpCallback: function() {
+ var callback = oldCallbacks.pop() || ( jQuery.expando + "_" + ( ajax_nonce++ ) );
+ this[ callback ] = true;
+ return callback;
+ }
+});
+
+// Detect, normalize options and install callbacks for jsonp requests
+jQuery.ajaxPrefilter( "json jsonp", function( s, originalSettings, jqXHR ) {
+
+ var callbackName, overwritten, responseContainer,
+ jsonProp = s.jsonp !== false && ( rjsonp.test( s.url ) ?
+ "url" :
+ typeof s.data === "string" && !( s.contentType || "" ).indexOf("application/x-www-form-urlencoded") && rjsonp.test( s.data ) && "data"
+ );
+
+ // Handle iff the expected data type is "jsonp" or we have a parameter to set
+ if ( jsonProp || s.dataTypes[ 0 ] === "jsonp" ) {
+
+ // Get callback name, remembering preexisting value associated with it
+ callbackName = s.jsonpCallback = jQuery.isFunction( s.jsonpCallback ) ?
+ s.jsonpCallback() :
+ s.jsonpCallback;
+
+ // Insert callback into url or form data
+ if ( jsonProp ) {
+ s[ jsonProp ] = s[ jsonProp ].replace( rjsonp, "$1" + callbackName );
+ } else if ( s.jsonp !== false ) {
+ s.url += ( ajax_rquery.test( s.url ) ? "&" : "?" ) + s.jsonp + "=" + callbackName;
+ }
+
+ // Use data converter to retrieve json after script execution
+ s.converters["script json"] = function() {
+ if ( !responseContainer ) {
+ jQuery.error( callbackName + " was not called" );
+ }
+ return responseContainer[ 0 ];
+ };
+
+ // force json dataType
+ s.dataTypes[ 0 ] = "json";
+
+ // Install callback
+ overwritten = window[ callbackName ];
+ window[ callbackName ] = function() {
+ responseContainer = arguments;
+ };
+
+ // Clean-up function (fires after converters)
+ jqXHR.always(function() {
+ // Restore preexisting value
+ window[ callbackName ] = overwritten;
+
+ // Save back as free
+ if ( s[ callbackName ] ) {
+ // make sure that re-using the options doesn't screw things around
+ s.jsonpCallback = originalSettings.jsonpCallback;
+
+ // save the callback name for future use
+ oldCallbacks.push( callbackName );
+ }
+
+ // Call if it was a function and we have a response
+ if ( responseContainer && jQuery.isFunction( overwritten ) ) {
+ overwritten( responseContainer[ 0 ] );
+ }
+
+ responseContainer = overwritten = undefined;
+ });
+
+ // Delegate to script
+ return "script";
+ }
+});
+var xhrCallbacks, xhrSupported,
+ xhrId = 0,
+ // #5280: Internet Explorer will keep connections alive if we don't abort on unload
+ xhrOnUnloadAbort = window.ActiveXObject && function() {
+ // Abort all pending requests
+ var key;
+ for ( key in xhrCallbacks ) {
+ xhrCallbacks[ key ]( undefined, true );
+ }
+ };
+
+// Functions to create xhrs
+function createStandardXHR() {
+ try {
+ return new window.XMLHttpRequest();
+ } catch( e ) {}
+}
+
+function createActiveXHR() {
+ try {
+ return new window.ActiveXObject("Microsoft.XMLHTTP");
+ } catch( e ) {}
+}
+
+// Create the request object
+// (This is still attached to ajaxSettings for backward compatibility)
+jQuery.ajaxSettings.xhr = window.ActiveXObject ?
+ /* Microsoft failed to properly
+ * implement the XMLHttpRequest in IE7 (can't request local files),
+ * so we use the ActiveXObject when it is available
+ * Additionally XMLHttpRequest can be disabled in IE7/IE8 so
+ * we need a fallback.
+ */
+ function() {
+ return !this.isLocal && createStandardXHR() || createActiveXHR();
+ } :
+ // For all other browsers, use the standard XMLHttpRequest object
+ createStandardXHR;
+
+// Determine support properties
+xhrSupported = jQuery.ajaxSettings.xhr();
+jQuery.support.cors = !!xhrSupported && ( "withCredentials" in xhrSupported );
+xhrSupported = jQuery.support.ajax = !!xhrSupported;
+
+// Create transport if the browser can provide an xhr
+if ( xhrSupported ) {
+
+ jQuery.ajaxTransport(function( s ) {
+ // Cross domain only allowed if supported through XMLHttpRequest
+ if ( !s.crossDomain || jQuery.support.cors ) {
+
+ var callback;
+
+ return {
+ send: function( headers, complete ) {
+
+ // Get a new xhr
+ var handle, i,
+ xhr = s.xhr();
+
+ // Open the socket
+ // Passing null username, generates a login popup on Opera (#2865)
+ if ( s.username ) {
+ xhr.open( s.type, s.url, s.async, s.username, s.password );
+ } else {
+ xhr.open( s.type, s.url, s.async );
+ }
+
+ // Apply custom fields if provided
+ if ( s.xhrFields ) {
+ for ( i in s.xhrFields ) {
+ xhr[ i ] = s.xhrFields[ i ];
+ }
+ }
+
+ // Override mime type if needed
+ if ( s.mimeType && xhr.overrideMimeType ) {
+ xhr.overrideMimeType( s.mimeType );
+ }
+
+ // X-Requested-With header
+ // For cross-domain requests, seeing as conditions for a preflight are
+ // akin to a jigsaw puzzle, we simply never set it to be sure.
+ // (it can always be set on a per-request basis or even using ajaxSetup)
+ // For same-domain requests, won't change header if already provided.
+ if ( !s.crossDomain && !headers["X-Requested-With"] ) {
+ headers["X-Requested-With"] = "XMLHttpRequest";
+ }
+
+ // Need an extra try/catch for cross domain requests in Firefox 3
+ try {
+ for ( i in headers ) {
+ xhr.setRequestHeader( i, headers[ i ] );
+ }
+ } catch( err ) {}
+
+ // Do send the request
+ // This may raise an exception which is actually
+ // handled in jQuery.ajax (so no try/catch here)
+ xhr.send( ( s.hasContent && s.data ) || null );
+
+ // Listener
+ callback = function( _, isAbort ) {
+ var status, responseHeaders, statusText, responses;
+
+ // Firefox throws exceptions when accessing properties
+ // of an xhr when a network error occurred
+ // http://helpful.knobs-dials.com/index.php/Component_returned_failure_code:_0x80040111_(NS_ERROR_NOT_AVAILABLE)
+ try {
+
+ // Was never called and is aborted or complete
+ if ( callback && ( isAbort || xhr.readyState === 4 ) ) {
+
+ // Only called once
+ callback = undefined;
+
+ // Do not keep as active anymore
+ if ( handle ) {
+ xhr.onreadystatechange = jQuery.noop;
+ if ( xhrOnUnloadAbort ) {
+ delete xhrCallbacks[ handle ];
+ }
+ }
+
+ // If it's an abort
+ if ( isAbort ) {
+ // Abort it manually if needed
+ if ( xhr.readyState !== 4 ) {
+ xhr.abort();
+ }
+ } else {
+ responses = {};
+ status = xhr.status;
+ responseHeaders = xhr.getAllResponseHeaders();
+
+ // When requesting binary data, IE6-9 will throw an exception
+ // on any attempt to access responseText (#11426)
+ if ( typeof xhr.responseText === "string" ) {
+ responses.text = xhr.responseText;
+ }
+
+ // Firefox throws an exception when accessing
+ // statusText for faulty cross-domain requests
+ try {
+ statusText = xhr.statusText;
+ } catch( e ) {
+ // We normalize with Webkit giving an empty statusText
+ statusText = "";
+ }
+
+ // Filter status for non standard behaviors
+
+ // If the request is local and we have data: assume a success
+ // (success with no data won't get notified, that's the best we
+ // can do given current implementations)
+ if ( !status && s.isLocal && !s.crossDomain ) {
+ status = responses.text ? 200 : 404;
+ // IE - #1450: sometimes returns 1223 when it should be 204
+ } else if ( status === 1223 ) {
+ status = 204;
+ }
+ }
+ }
+ } catch( firefoxAccessException ) {
+ if ( !isAbort ) {
+ complete( -1, firefoxAccessException );
+ }
+ }
+
+ // Call complete if needed
+ if ( responses ) {
+ complete( status, statusText, responses, responseHeaders );
+ }
+ };
+
+ if ( !s.async ) {
+ // if we're in sync mode we fire the callback
+ callback();
+ } else if ( xhr.readyState === 4 ) {
+ // (IE6 & IE7) if it's in cache and has been
+ // retrieved directly we need to fire the callback
+ setTimeout( callback );
+ } else {
+ handle = ++xhrId;
+ if ( xhrOnUnloadAbort ) {
+ // Create the active xhrs callbacks list if needed
+ // and attach the unload handler
+ if ( !xhrCallbacks ) {
+ xhrCallbacks = {};
+ jQuery( window ).unload( xhrOnUnloadAbort );
+ }
+ // Add to list of active xhrs callbacks
+ xhrCallbacks[ handle ] = callback;
+ }
+ xhr.onreadystatechange = callback;
+ }
+ },
+
+ abort: function() {
+ if ( callback ) {
+ callback( undefined, true );
+ }
+ }
+ };
+ }
+ });
+}
+var fxNow, timerId,
+ rfxtypes = /^(?:toggle|show|hide)$/,
+ rfxnum = new RegExp( "^(?:([+-])=|)(" + core_pnum + ")([a-z%]*)$", "i" ),
+ rrun = /queueHooks$/,
+ animationPrefilters = [ defaultPrefilter ],
+ tweeners = {
+ "*": [function( prop, value ) {
+ var tween = this.createTween( prop, value ),
+ target = tween.cur(),
+ parts = rfxnum.exec( value ),
+ unit = parts && parts[ 3 ] || ( jQuery.cssNumber[ prop ] ? "" : "px" ),
+
+ // Starting value computation is required for potential unit mismatches
+ start = ( jQuery.cssNumber[ prop ] || unit !== "px" && +target ) &&
+ rfxnum.exec( jQuery.css( tween.elem, prop ) ),
+ scale = 1,
+ maxIterations = 20;
+
+ if ( start && start[ 3 ] !== unit ) {
+ // Trust units reported by jQuery.css
+ unit = unit || start[ 3 ];
+
+ // Make sure we update the tween properties later on
+ parts = parts || [];
+
+ // Iteratively approximate from a nonzero starting point
+ start = +target || 1;
+
+ do {
+ // If previous iteration zeroed out, double until we get *something*
+ // Use a string for doubling factor so we don't accidentally see scale as unchanged below
+ scale = scale || ".5";
+
+ // Adjust and apply
+ start = start / scale;
+ jQuery.style( tween.elem, prop, start + unit );
+
+ // Update scale, tolerating zero or NaN from tween.cur()
+ // And breaking the loop if scale is unchanged or perfect, or if we've just had enough
+ } while ( scale !== (scale = tween.cur() / target) && scale !== 1 && --maxIterations );
+ }
+
+ // Update tween properties
+ if ( parts ) {
+ start = tween.start = +start || +target || 0;
+ tween.unit = unit;
+ // If a +=/-= token was provided, we're doing a relative animation
+ tween.end = parts[ 1 ] ?
+ start + ( parts[ 1 ] + 1 ) * parts[ 2 ] :
+ +parts[ 2 ];
+ }
+
+ return tween;
+ }]
+ };
+
+// Animations created synchronously will run synchronously
+function createFxNow() {
+ setTimeout(function() {
+ fxNow = undefined;
+ });
+ return ( fxNow = jQuery.now() );
+}
+
+function createTween( value, prop, animation ) {
+ var tween,
+ collection = ( tweeners[ prop ] || [] ).concat( tweeners[ "*" ] ),
+ index = 0,
+ length = collection.length;
+ for ( ; index < length; index++ ) {
+ if ( (tween = collection[ index ].call( animation, prop, value )) ) {
+
+ // we're done with this property
+ return tween;
+ }
+ }
+}
+
+function Animation( elem, properties, options ) {
+ var result,
+ stopped,
+ index = 0,
+ length = animationPrefilters.length,
+ deferred = jQuery.Deferred().always( function() {
+ // don't match elem in the :animated selector
+ delete tick.elem;
+ }),
+ tick = function() {
+ if ( stopped ) {
+ return false;
+ }
+ var currentTime = fxNow || createFxNow(),
+ remaining = Math.max( 0, animation.startTime + animation.duration - currentTime ),
+ // archaic crash bug won't allow us to use 1 - ( 0.5 || 0 ) (#12497)
+ temp = remaining / animation.duration || 0,
+ percent = 1 - temp,
+ index = 0,
+ length = animation.tweens.length;
+
+ for ( ; index < length ; index++ ) {
+ animation.tweens[ index ].run( percent );
+ }
+
+ deferred.notifyWith( elem, [ animation, percent, remaining ]);
+
+ if ( percent < 1 && length ) {
+ return remaining;
+ } else {
+ deferred.resolveWith( elem, [ animation ] );
+ return false;
+ }
+ },
+ animation = deferred.promise({
+ elem: elem,
+ props: jQuery.extend( {}, properties ),
+ opts: jQuery.extend( true, { specialEasing: {} }, options ),
+ originalProperties: properties,
+ originalOptions: options,
+ startTime: fxNow || createFxNow(),
+ duration: options.duration,
+ tweens: [],
+ createTween: function( prop, end ) {
+ var tween = jQuery.Tween( elem, animation.opts, prop, end,
+ animation.opts.specialEasing[ prop ] || animation.opts.easing );
+ animation.tweens.push( tween );
+ return tween;
+ },
+ stop: function( gotoEnd ) {
+ var index = 0,
+ // if we are going to the end, we want to run all the tweens
+ // otherwise we skip this part
+ length = gotoEnd ? animation.tweens.length : 0;
+ if ( stopped ) {
+ return this;
+ }
+ stopped = true;
+ for ( ; index < length ; index++ ) {
+ animation.tweens[ index ].run( 1 );
+ }
+
+ // resolve when we played the last frame
+ // otherwise, reject
+ if ( gotoEnd ) {
+ deferred.resolveWith( elem, [ animation, gotoEnd ] );
+ } else {
+ deferred.rejectWith( elem, [ animation, gotoEnd ] );
+ }
+ return this;
+ }
+ }),
+ props = animation.props;
+
+ propFilter( props, animation.opts.specialEasing );
+
+ for ( ; index < length ; index++ ) {
+ result = animationPrefilters[ index ].call( animation, elem, props, animation.opts );
+ if ( result ) {
+ return result;
+ }
+ }
+
+ jQuery.map( props, createTween, animation );
+
+ if ( jQuery.isFunction( animation.opts.start ) ) {
+ animation.opts.start.call( elem, animation );
+ }
+
+ jQuery.fx.timer(
+ jQuery.extend( tick, {
+ elem: elem,
+ anim: animation,
+ queue: animation.opts.queue
+ })
+ );
+
+ // attach callbacks from options
+ return animation.progress( animation.opts.progress )
+ .done( animation.opts.done, animation.opts.complete )
+ .fail( animation.opts.fail )
+ .always( animation.opts.always );
+}
+
+function propFilter( props, specialEasing ) {
+ var index, name, easing, value, hooks;
+
+ // camelCase, specialEasing and expand cssHook pass
+ for ( index in props ) {
+ name = jQuery.camelCase( index );
+ easing = specialEasing[ name ];
+ value = props[ index ];
+ if ( jQuery.isArray( value ) ) {
+ easing = value[ 1 ];
+ value = props[ index ] = value[ 0 ];
+ }
+
+ if ( index !== name ) {
+ props[ name ] = value;
+ delete props[ index ];
+ }
+
+ hooks = jQuery.cssHooks[ name ];
+ if ( hooks && "expand" in hooks ) {
+ value = hooks.expand( value );
+ delete props[ name ];
+
+ // not quite $.extend, this wont overwrite keys already present.
+ // also - reusing 'index' from above because we have the correct "name"
+ for ( index in value ) {
+ if ( !( index in props ) ) {
+ props[ index ] = value[ index ];
+ specialEasing[ index ] = easing;
+ }
+ }
+ } else {
+ specialEasing[ name ] = easing;
+ }
+ }
+}
+
+jQuery.Animation = jQuery.extend( Animation, {
+
+ tweener: function( props, callback ) {
+ if ( jQuery.isFunction( props ) ) {
+ callback = props;
+ props = [ "*" ];
+ } else {
+ props = props.split(" ");
+ }
+
+ var prop,
+ index = 0,
+ length = props.length;
+
+ for ( ; index < length ; index++ ) {
+ prop = props[ index ];
+ tweeners[ prop ] = tweeners[ prop ] || [];
+ tweeners[ prop ].unshift( callback );
+ }
+ },
+
+ prefilter: function( callback, prepend ) {
+ if ( prepend ) {
+ animationPrefilters.unshift( callback );
+ } else {
+ animationPrefilters.push( callback );
+ }
+ }
+});
+
+function defaultPrefilter( elem, props, opts ) {
+ /* jshint validthis: true */
+ var prop, value, toggle, tween, hooks, oldfire,
+ anim = this,
+ orig = {},
+ style = elem.style,
+ hidden = elem.nodeType && isHidden( elem ),
+ dataShow = jQuery._data( elem, "fxshow" );
+
+ // handle queue: false promises
+ if ( !opts.queue ) {
+ hooks = jQuery._queueHooks( elem, "fx" );
+ if ( hooks.unqueued == null ) {
+ hooks.unqueued = 0;
+ oldfire = hooks.empty.fire;
+ hooks.empty.fire = function() {
+ if ( !hooks.unqueued ) {
+ oldfire();
+ }
+ };
+ }
+ hooks.unqueued++;
+
+ anim.always(function() {
+ // doing this makes sure that the complete handler will be called
+ // before this completes
+ anim.always(function() {
+ hooks.unqueued--;
+ if ( !jQuery.queue( elem, "fx" ).length ) {
+ hooks.empty.fire();
+ }
+ });
+ });
+ }
+
+ // height/width overflow pass
+ if ( elem.nodeType === 1 && ( "height" in props || "width" in props ) ) {
+ // Make sure that nothing sneaks out
+ // Record all 3 overflow attributes because IE does not
+ // change the overflow attribute when overflowX and
+ // overflowY are set to the same value
+ opts.overflow = [ style.overflow, style.overflowX, style.overflowY ];
+
+ // Set display property to inline-block for height/width
+ // animations on inline elements that are having width/height animated
+ if ( jQuery.css( elem, "display" ) === "inline" &&
+ jQuery.css( elem, "float" ) === "none" ) {
+
+ // inline-level elements accept inline-block;
+ // block-level elements need to be inline with layout
+ if ( !jQuery.support.inlineBlockNeedsLayout || css_defaultDisplay( elem.nodeName ) === "inline" ) {
+ style.display = "inline-block";
+
+ } else {
+ style.zoom = 1;
+ }
+ }
+ }
+
+ if ( opts.overflow ) {
+ style.overflow = "hidden";
+ if ( !jQuery.support.shrinkWrapBlocks ) {
+ anim.always(function() {
+ style.overflow = opts.overflow[ 0 ];
+ style.overflowX = opts.overflow[ 1 ];
+ style.overflowY = opts.overflow[ 2 ];
+ });
+ }
+ }
+
+
+ // show/hide pass
+ for ( prop in props ) {
+ value = props[ prop ];
+ if ( rfxtypes.exec( value ) ) {
+ delete props[ prop ];
+ toggle = toggle || value === "toggle";
+ if ( value === ( hidden ? "hide" : "show" ) ) {
+ continue;
+ }
+ orig[ prop ] = dataShow && dataShow[ prop ] || jQuery.style( elem, prop );
+ }
+ }
+
+ if ( !jQuery.isEmptyObject( orig ) ) {
+ if ( dataShow ) {
+ if ( "hidden" in dataShow ) {
+ hidden = dataShow.hidden;
+ }
+ } else {
+ dataShow = jQuery._data( elem, "fxshow", {} );
+ }
+
+ // store state if its toggle - enables .stop().toggle() to "reverse"
+ if ( toggle ) {
+ dataShow.hidden = !hidden;
+ }
+ if ( hidden ) {
+ jQuery( elem ).show();
+ } else {
+ anim.done(function() {
+ jQuery( elem ).hide();
+ });
+ }
+ anim.done(function() {
+ var prop;
+ jQuery._removeData( elem, "fxshow" );
+ for ( prop in orig ) {
+ jQuery.style( elem, prop, orig[ prop ] );
+ }
+ });
+ for ( prop in orig ) {
+ tween = createTween( hidden ? dataShow[ prop ] : 0, prop, anim );
+
+ if ( !( prop in dataShow ) ) {
+ dataShow[ prop ] = tween.start;
+ if ( hidden ) {
+ tween.end = tween.start;
+ tween.start = prop === "width" || prop === "height" ? 1 : 0;
+ }
+ }
+ }
+ }
+}
+
+function Tween( elem, options, prop, end, easing ) {
+ return new Tween.prototype.init( elem, options, prop, end, easing );
+}
+jQuery.Tween = Tween;
+
+Tween.prototype = {
+ constructor: Tween,
+ init: function( elem, options, prop, end, easing, unit ) {
+ this.elem = elem;
+ this.prop = prop;
+ this.easing = easing || "swing";
+ this.options = options;
+ this.start = this.now = this.cur();
+ this.end = end;
+ this.unit = unit || ( jQuery.cssNumber[ prop ] ? "" : "px" );
+ },
+ cur: function() {
+ var hooks = Tween.propHooks[ this.prop ];
+
+ return hooks && hooks.get ?
+ hooks.get( this ) :
+ Tween.propHooks._default.get( this );
+ },
+ run: function( percent ) {
+ var eased,
+ hooks = Tween.propHooks[ this.prop ];
+
+ if ( this.options.duration ) {
+ this.pos = eased = jQuery.easing[ this.easing ](
+ percent, this.options.duration * percent, 0, 1, this.options.duration
+ );
+ } else {
+ this.pos = eased = percent;
+ }
+ this.now = ( this.end - this.start ) * eased + this.start;
+
+ if ( this.options.step ) {
+ this.options.step.call( this.elem, this.now, this );
+ }
+
+ if ( hooks && hooks.set ) {
+ hooks.set( this );
+ } else {
+ Tween.propHooks._default.set( this );
+ }
+ return this;
+ }
+};
+
+Tween.prototype.init.prototype = Tween.prototype;
+
+Tween.propHooks = {
+ _default: {
+ get: function( tween ) {
+ var result;
+
+ if ( tween.elem[ tween.prop ] != null &&
+ (!tween.elem.style || tween.elem.style[ tween.prop ] == null) ) {
+ return tween.elem[ tween.prop ];
+ }
+
+ // passing an empty string as a 3rd parameter to .css will automatically
+ // attempt a parseFloat and fallback to a string if the parse fails
+ // so, simple values such as "10px" are parsed to Float.
+ // complex values such as "rotate(1rad)" are returned as is.
+ result = jQuery.css( tween.elem, tween.prop, "" );
+ // Empty strings, null, undefined and "auto" are converted to 0.
+ return !result || result === "auto" ? 0 : result;
+ },
+ set: function( tween ) {
+ // use step hook for back compat - use cssHook if its there - use .style if its
+ // available and use plain properties where available
+ if ( jQuery.fx.step[ tween.prop ] ) {
+ jQuery.fx.step[ tween.prop ]( tween );
+ } else if ( tween.elem.style && ( tween.elem.style[ jQuery.cssProps[ tween.prop ] ] != null || jQuery.cssHooks[ tween.prop ] ) ) {
+ jQuery.style( tween.elem, tween.prop, tween.now + tween.unit );
+ } else {
+ tween.elem[ tween.prop ] = tween.now;
+ }
+ }
+ }
+};
+
+// Support: IE <=9
+// Panic based approach to setting things on disconnected nodes
+
+Tween.propHooks.scrollTop = Tween.propHooks.scrollLeft = {
+ set: function( tween ) {
+ if ( tween.elem.nodeType && tween.elem.parentNode ) {
+ tween.elem[ tween.prop ] = tween.now;
+ }
+ }
+};
+
+jQuery.each([ "toggle", "show", "hide" ], function( i, name ) {
+ var cssFn = jQuery.fn[ name ];
+ jQuery.fn[ name ] = function( speed, easing, callback ) {
+ return speed == null || typeof speed === "boolean" ?
+ cssFn.apply( this, arguments ) :
+ this.animate( genFx( name, true ), speed, easing, callback );
+ };
+});
+
+jQuery.fn.extend({
+ fadeTo: function( speed, to, easing, callback ) {
+
+ // show any hidden elements after setting opacity to 0
+ return this.filter( isHidden ).css( "opacity", 0 ).show()
+
+ // animate to the value specified
+ .end().animate({ opacity: to }, speed, easing, callback );
+ },
+ animate: function( prop, speed, easing, callback ) {
+ var empty = jQuery.isEmptyObject( prop ),
+ optall = jQuery.speed( speed, easing, callback ),
+ doAnimation = function() {
+ // Operate on a copy of prop so per-property easing won't be lost
+ var anim = Animation( this, jQuery.extend( {}, prop ), optall );
+
+ // Empty animations, or finishing resolves immediately
+ if ( empty || jQuery._data( this, "finish" ) ) {
+ anim.stop( true );
+ }
+ };
+ doAnimation.finish = doAnimation;
+
+ return empty || optall.queue === false ?
+ this.each( doAnimation ) :
+ this.queue( optall.queue, doAnimation );
+ },
+ stop: function( type, clearQueue, gotoEnd ) {
+ var stopQueue = function( hooks ) {
+ var stop = hooks.stop;
+ delete hooks.stop;
+ stop( gotoEnd );
+ };
+
+ if ( typeof type !== "string" ) {
+ gotoEnd = clearQueue;
+ clearQueue = type;
+ type = undefined;
+ }
+ if ( clearQueue && type !== false ) {
+ this.queue( type || "fx", [] );
+ }
+
+ return this.each(function() {
+ var dequeue = true,
+ index = type != null && type + "queueHooks",
+ timers = jQuery.timers,
+ data = jQuery._data( this );
+
+ if ( index ) {
+ if ( data[ index ] && data[ index ].stop ) {
+ stopQueue( data[ index ] );
+ }
+ } else {
+ for ( index in data ) {
+ if ( data[ index ] && data[ index ].stop && rrun.test( index ) ) {
+ stopQueue( data[ index ] );
+ }
+ }
+ }
+
+ for ( index = timers.length; index--; ) {
+ if ( timers[ index ].elem === this && (type == null || timers[ index ].queue === type) ) {
+ timers[ index ].anim.stop( gotoEnd );
+ dequeue = false;
+ timers.splice( index, 1 );
+ }
+ }
+
+ // start the next in the queue if the last step wasn't forced
+ // timers currently will call their complete callbacks, which will dequeue
+ // but only if they were gotoEnd
+ if ( dequeue || !gotoEnd ) {
+ jQuery.dequeue( this, type );
+ }
+ });
+ },
+ finish: function( type ) {
+ if ( type !== false ) {
+ type = type || "fx";
+ }
+ return this.each(function() {
+ var index,
+ data = jQuery._data( this ),
+ queue = data[ type + "queue" ],
+ hooks = data[ type + "queueHooks" ],
+ timers = jQuery.timers,
+ length = queue ? queue.length : 0;
+
+ // enable finishing flag on private data
+ data.finish = true;
+
+ // empty the queue first
+ jQuery.queue( this, type, [] );
+
+ if ( hooks && hooks.stop ) {
+ hooks.stop.call( this, true );
+ }
+
+ // look for any active animations, and finish them
+ for ( index = timers.length; index--; ) {
+ if ( timers[ index ].elem === this && timers[ index ].queue === type ) {
+ timers[ index ].anim.stop( true );
+ timers.splice( index, 1 );
+ }
+ }
+
+ // look for any animations in the old queue and finish them
+ for ( index = 0; index < length; index++ ) {
+ if ( queue[ index ] && queue[ index ].finish ) {
+ queue[ index ].finish.call( this );
+ }
+ }
+
+ // turn off finishing flag
+ delete data.finish;
+ });
+ }
+});
+
+// Generate parameters to create a standard animation
+function genFx( type, includeWidth ) {
+ var which,
+ attrs = { height: type },
+ i = 0;
+
+ // if we include width, step value is 1 to do all cssExpand values,
+ // if we don't include width, step value is 2 to skip over Left and Right
+ includeWidth = includeWidth? 1 : 0;
+ for( ; i < 4 ; i += 2 - includeWidth ) {
+ which = cssExpand[ i ];
+ attrs[ "margin" + which ] = attrs[ "padding" + which ] = type;
+ }
+
+ if ( includeWidth ) {
+ attrs.opacity = attrs.width = type;
+ }
+
+ return attrs;
+}
+
+// Generate shortcuts for custom animations
+jQuery.each({
+ slideDown: genFx("show"),
+ slideUp: genFx("hide"),
+ slideToggle: genFx("toggle"),
+ fadeIn: { opacity: "show" },
+ fadeOut: { opacity: "hide" },
+ fadeToggle: { opacity: "toggle" }
+}, function( name, props ) {
+ jQuery.fn[ name ] = function( speed, easing, callback ) {
+ return this.animate( props, speed, easing, callback );
+ };
+});
+
+jQuery.speed = function( speed, easing, fn ) {
+ var opt = speed && typeof speed === "object" ? jQuery.extend( {}, speed ) : {
+ complete: fn || !fn && easing ||
+ jQuery.isFunction( speed ) && speed,
+ duration: speed,
+ easing: fn && easing || easing && !jQuery.isFunction( easing ) && easing
+ };
+
+ opt.duration = jQuery.fx.off ? 0 : typeof opt.duration === "number" ? opt.duration :
+ opt.duration in jQuery.fx.speeds ? jQuery.fx.speeds[ opt.duration ] : jQuery.fx.speeds._default;
+
+ // normalize opt.queue - true/undefined/null -> "fx"
+ if ( opt.queue == null || opt.queue === true ) {
+ opt.queue = "fx";
+ }
+
+ // Queueing
+ opt.old = opt.complete;
+
+ opt.complete = function() {
+ if ( jQuery.isFunction( opt.old ) ) {
+ opt.old.call( this );
+ }
+
+ if ( opt.queue ) {
+ jQuery.dequeue( this, opt.queue );
+ }
+ };
+
+ return opt;
+};
+
+jQuery.easing = {
+ linear: function( p ) {
+ return p;
+ },
+ swing: function( p ) {
+ return 0.5 - Math.cos( p*Math.PI ) / 2;
+ }
+};
+
+jQuery.timers = [];
+jQuery.fx = Tween.prototype.init;
+jQuery.fx.tick = function() {
+ var timer,
+ timers = jQuery.timers,
+ i = 0;
+
+ fxNow = jQuery.now();
+
+ for ( ; i < timers.length; i++ ) {
+ timer = timers[ i ];
+ // Checks the timer has not already been removed
+ if ( !timer() && timers[ i ] === timer ) {
+ timers.splice( i--, 1 );
+ }
+ }
+
+ if ( !timers.length ) {
+ jQuery.fx.stop();
+ }
+ fxNow = undefined;
+};
+
+jQuery.fx.timer = function( timer ) {
+ if ( timer() && jQuery.timers.push( timer ) ) {
+ jQuery.fx.start();
+ }
+};
+
+jQuery.fx.interval = 13;
+
+jQuery.fx.start = function() {
+ if ( !timerId ) {
+ timerId = setInterval( jQuery.fx.tick, jQuery.fx.interval );
+ }
+};
+
+jQuery.fx.stop = function() {
+ clearInterval( timerId );
+ timerId = null;
+};
+
+jQuery.fx.speeds = {
+ slow: 600,
+ fast: 200,
+ // Default speed
+ _default: 400
+};
+
+// Back Compat <1.8 extension point
+jQuery.fx.step = {};
+
+if ( jQuery.expr && jQuery.expr.filters ) {
+ jQuery.expr.filters.animated = function( elem ) {
+ return jQuery.grep(jQuery.timers, function( fn ) {
+ return elem === fn.elem;
+ }).length;
+ };
+}
+jQuery.fn.offset = function( options ) {
+ if ( arguments.length ) {
+ return options === undefined ?
+ this :
+ this.each(function( i ) {
+ jQuery.offset.setOffset( this, options, i );
+ });
+ }
+
+ var docElem, win,
+ box = { top: 0, left: 0 },
+ elem = this[ 0 ],
+ doc = elem && elem.ownerDocument;
+
+ if ( !doc ) {
+ return;
+ }
+
+ docElem = doc.documentElement;
+
+ // Make sure it's not a disconnected DOM node
+ if ( !jQuery.contains( docElem, elem ) ) {
+ return box;
+ }
+
+ // If we don't have gBCR, just use 0,0 rather than error
+ // BlackBerry 5, iOS 3 (original iPhone)
+ if ( typeof elem.getBoundingClientRect !== core_strundefined ) {
+ box = elem.getBoundingClientRect();
+ }
+ win = getWindow( doc );
+ return {
+ top: box.top + ( win.pageYOffset || docElem.scrollTop ) - ( docElem.clientTop || 0 ),
+ left: box.left + ( win.pageXOffset || docElem.scrollLeft ) - ( docElem.clientLeft || 0 )
+ };
+};
+
+jQuery.offset = {
+
+ setOffset: function( elem, options, i ) {
+ var position = jQuery.css( elem, "position" );
+
+ // set position first, in-case top/left are set even on static elem
+ if ( position === "static" ) {
+ elem.style.position = "relative";
+ }
+
+ var curElem = jQuery( elem ),
+ curOffset = curElem.offset(),
+ curCSSTop = jQuery.css( elem, "top" ),
+ curCSSLeft = jQuery.css( elem, "left" ),
+ calculatePosition = ( position === "absolute" || position === "fixed" ) && jQuery.inArray("auto", [curCSSTop, curCSSLeft]) > -1,
+ props = {}, curPosition = {}, curTop, curLeft;
+
+ // need to be able to calculate position if either top or left is auto and position is either absolute or fixed
+ if ( calculatePosition ) {
+ curPosition = curElem.position();
+ curTop = curPosition.top;
+ curLeft = curPosition.left;
+ } else {
+ curTop = parseFloat( curCSSTop ) || 0;
+ curLeft = parseFloat( curCSSLeft ) || 0;
+ }
+
+ if ( jQuery.isFunction( options ) ) {
+ options = options.call( elem, i, curOffset );
+ }
+
+ if ( options.top != null ) {
+ props.top = ( options.top - curOffset.top ) + curTop;
+ }
+ if ( options.left != null ) {
+ props.left = ( options.left - curOffset.left ) + curLeft;
+ }
+
+ if ( "using" in options ) {
+ options.using.call( elem, props );
+ } else {
+ curElem.css( props );
+ }
+ }
+};
+
+
+jQuery.fn.extend({
+
+ position: function() {
+ if ( !this[ 0 ] ) {
+ return;
+ }
+
+ var offsetParent, offset,
+ parentOffset = { top: 0, left: 0 },
+ elem = this[ 0 ];
+
+ // fixed elements are offset from window (parentOffset = {top:0, left: 0}, because it is it's only offset parent
+ if ( jQuery.css( elem, "position" ) === "fixed" ) {
+ // we assume that getBoundingClientRect is available when computed position is fixed
+ offset = elem.getBoundingClientRect();
+ } else {
+ // Get *real* offsetParent
+ offsetParent = this.offsetParent();
+
+ // Get correct offsets
+ offset = this.offset();
+ if ( !jQuery.nodeName( offsetParent[ 0 ], "html" ) ) {
+ parentOffset = offsetParent.offset();
+ }
+
+ // Add offsetParent borders
+ parentOffset.top += jQuery.css( offsetParent[ 0 ], "borderTopWidth", true );
+ parentOffset.left += jQuery.css( offsetParent[ 0 ], "borderLeftWidth", true );
+ }
+
+ // Subtract parent offsets and element margins
+ // note: when an element has margin: auto the offsetLeft and marginLeft
+ // are the same in Safari causing offset.left to incorrectly be 0
+ return {
+ top: offset.top - parentOffset.top - jQuery.css( elem, "marginTop", true ),
+ left: offset.left - parentOffset.left - jQuery.css( elem, "marginLeft", true)
+ };
+ },
+
+ offsetParent: function() {
+ return this.map(function() {
+ var offsetParent = this.offsetParent || docElem;
+ while ( offsetParent && ( !jQuery.nodeName( offsetParent, "html" ) && jQuery.css( offsetParent, "position") === "static" ) ) {
+ offsetParent = offsetParent.offsetParent;
+ }
+ return offsetParent || docElem;
+ });
+ }
+});
+
+
+// Create scrollLeft and scrollTop methods
+jQuery.each( {scrollLeft: "pageXOffset", scrollTop: "pageYOffset"}, function( method, prop ) {
+ var top = /Y/.test( prop );
+
+ jQuery.fn[ method ] = function( val ) {
+ return jQuery.access( this, function( elem, method, val ) {
+ var win = getWindow( elem );
+
+ if ( val === undefined ) {
+ return win ? (prop in win) ? win[ prop ] :
+ win.document.documentElement[ method ] :
+ elem[ method ];
+ }
+
+ if ( win ) {
+ win.scrollTo(
+ !top ? val : jQuery( win ).scrollLeft(),
+ top ? val : jQuery( win ).scrollTop()
+ );
+
+ } else {
+ elem[ method ] = val;
+ }
+ }, method, val, arguments.length, null );
+ };
+});
+
+function getWindow( elem ) {
+ return jQuery.isWindow( elem ) ?
+ elem :
+ elem.nodeType === 9 ?
+ elem.defaultView || elem.parentWindow :
+ false;
+}
+// Create innerHeight, innerWidth, height, width, outerHeight and outerWidth methods
+jQuery.each( { Height: "height", Width: "width" }, function( name, type ) {
+ jQuery.each( { padding: "inner" + name, content: type, "": "outer" + name }, function( defaultExtra, funcName ) {
+ // margin is only for outerHeight, outerWidth
+ jQuery.fn[ funcName ] = function( margin, value ) {
+ var chainable = arguments.length && ( defaultExtra || typeof margin !== "boolean" ),
+ extra = defaultExtra || ( margin === true || value === true ? "margin" : "border" );
+
+ return jQuery.access( this, function( elem, type, value ) {
+ var doc;
+
+ if ( jQuery.isWindow( elem ) ) {
+ // As of 5/8/2012 this will yield incorrect results for Mobile Safari, but there
+ // isn't a whole lot we can do. See pull request at this URL for discussion:
+ // https://github.com/jquery/jquery/pull/764
+ return elem.document.documentElement[ "client" + name ];
+ }
+
+ // Get document width or height
+ if ( elem.nodeType === 9 ) {
+ doc = elem.documentElement;
+
+ // Either scroll[Width/Height] or offset[Width/Height] or client[Width/Height], whichever is greatest
+ // unfortunately, this causes bug #3838 in IE6/8 only, but there is currently no good, small way to fix it.
+ return Math.max(
+ elem.body[ "scroll" + name ], doc[ "scroll" + name ],
+ elem.body[ "offset" + name ], doc[ "offset" + name ],
+ doc[ "client" + name ]
+ );
+ }
+
+ return value === undefined ?
+ // Get width or height on the element, requesting but not forcing parseFloat
+ jQuery.css( elem, type, extra ) :
+
+ // Set width or height on the element
+ jQuery.style( elem, type, value, extra );
+ }, type, chainable ? margin : undefined, chainable, null );
+ };
+ });
+});
+// Limit scope pollution from any deprecated API
+// (function() {
+
+// The number of elements contained in the matched element set
+jQuery.fn.size = function() {
+ return this.length;
+};
+
+jQuery.fn.andSelf = jQuery.fn.addBack;
+
+// })();
+if ( typeof module === "object" && module && typeof module.exports === "object" ) {
+ // Expose jQuery as module.exports in loaders that implement the Node
+ // module pattern (including browserify). Do not create the global, since
+ // the user will be storing it themselves locally, and globals are frowned
+ // upon in the Node module world.
+ module.exports = jQuery;
+} else {
+ // Otherwise expose jQuery to the global object as usual
+ window.jQuery = window.$ = jQuery;
+
+ // Register as a named AMD module, since jQuery can be concatenated with other
+ // files that may use define, but not via a proper concatenation script that
+ // understands anonymous AMD modules. A named AMD is safest and most robust
+ // way to register. Lowercase jquery is used because AMD module names are
+ // derived from file names, and jQuery is normally delivered in a lowercase
+ // file name. Do this after creating the global so that if an AMD module wants
+ // to call noConflict to hide this version of jQuery, it will work.
+ if ( typeof define === "function" && define.amd ) {
+ define( "jquery", [], function () { return jQuery; } );
+ }
+}
+
+})( window );
diff --git a/debian/missing-sources/jquery.masonry.js b/debian/missing-sources/jquery.masonry.js
new file mode 100644
index 0000000..2493250
--- /dev/null
+++ b/debian/missing-sources/jquery.masonry.js
@@ -0,0 +1,499 @@
+/**
+ * jQuery Masonry v2.1.05
+ * A dynamic layout plugin for jQuery
+ * The flip-side of CSS Floats
+ * http://masonry.desandro.com
+ *
+ * Licensed under the MIT license.
+ * Copyright 2012 David DeSandro
+ */
+
+/*jshint browser: true, curly: true, eqeqeq: true, forin: false, immed: false, newcap: true, noempty: true, strict: true, undef: true */
+/*global jQuery: false */
+
+(function( window, $, undefined ){
+
+ 'use strict';
+
+ /*
+ * smartresize: debounced resize event for jQuery
+ *
+ * latest version and complete README available on Github:
+ * https://github.com/louisremi/jquery.smartresize.js
+ *
+ * Copyright 2011 @louis_remi
+ * Licensed under the MIT license.
+ */
+
+ var $event = $.event,
+ resizeTimeout;
+
+ $event.special.smartresize = {
+ setup: function() {
+ $(this).bind( "resize", $event.special.smartresize.handler );
+ },
+ teardown: function() {
+ $(this).unbind( "resize", $event.special.smartresize.handler );
+ },
+ handler: function( event, execAsap ) {
+ // Save the context
+ var context = this,
+ args = arguments;
+
+ // set correct event type
+ event.type = "smartresize";
+
+ if ( resizeTimeout ) { clearTimeout( resizeTimeout ); }
+ resizeTimeout = setTimeout(function() {
+ $.event.handle.apply( context, args );
+ }, execAsap === "execAsap"? 0 : 100 );
+ }
+ };
+
+ $.fn.smartresize = function( fn ) {
+ return fn ? this.bind( "smartresize", fn ) : this.trigger( "smartresize", ["execAsap"] );
+ };
+
+
+
+// ========================= Masonry ===============================
+
+
+ // our "Widget" object constructor
+ $.Mason = function( options, element ){
+ this.element = $( element );
+
+ this._create( options );
+ this._init();
+ };
+
+ $.Mason.settings = {
+ isResizable: true,
+ isAnimated: false,
+ animationOptions: {
+ queue: false,
+ duration: 500
+ },
+ gutterWidth: 0,
+ isRTL: false,
+ isFitWidth: false,
+ containerStyle: {
+ position: 'relative'
+ }
+ };
+
+ $.Mason.prototype = {
+
+ _filterFindBricks: function( $elems ) {
+ var selector = this.options.itemSelector;
+ // if there is a selector
+ // filter/find appropriate item elements
+ return !selector ? $elems : $elems.filter( selector ).add( $elems.find( selector ) );
+ },
+
+ _getBricks: function( $elems ) {
+ var $bricks = this._filterFindBricks( $elems )
+ .css({ position: 'absolute' })
+ .addClass('masonry-brick');
+ return $bricks;
+ },
+
+ // sets up widget
+ _create : function( options ) {
+
+ this.options = $.extend( true, {}, $.Mason.settings, options );
+ this.styleQueue = [];
+
+ // get original styles in case we re-apply them in .destroy()
+ var elemStyle = this.element[0].style;
+ this.originalStyle = {
+ // get height
+ height: elemStyle.height || ''
+ };
+ // get other styles that will be overwritten
+ var containerStyle = this.options.containerStyle;
+ for ( var prop in containerStyle ) {
+ this.originalStyle[ prop ] = elemStyle[ prop ] || '';
+ }
+
+ this.element.css( containerStyle );
+
+ this.horizontalDirection = this.options.isRTL ? 'right' : 'left';
+
+ this.offset = {
+ x: parseInt( this.element.css( 'padding-' + this.horizontalDirection ), 10 ),
+ y: parseInt( this.element.css( 'padding-top' ), 10 )
+ };
+
+ this.isFluid = this.options.columnWidth && typeof this.options.columnWidth === 'function';
+
+ // add masonry class first time around
+ var instance = this;
+ setTimeout( function() {
+ instance.element.addClass('masonry');
+ }, 0 );
+
+ // bind resize method
+ if ( this.options.isResizable ) {
+ $(window).bind( 'smartresize.masonry', function() {
+ instance.resize();
+ });
+ }
+
+
+ // need to get bricks
+ this.reloadItems();
+
+ },
+
+ // _init fires when instance is first created
+ // and when instance is triggered again -> $el.masonry();
+ _init : function( callback ) {
+ this._getColumns();
+ this._reLayout( callback );
+ },
+
+ option: function( key, value ){
+ // set options AFTER initialization:
+ // signature: $('#foo').bar({ cool:false });
+ if ( $.isPlainObject( key ) ){
+ this.options = $.extend(true, this.options, key);
+ }
+ },
+
+ // ====================== General Layout ======================
+
+ // used on collection of atoms (should be filtered, and sorted before )
+ // accepts atoms-to-be-laid-out to start with
+ layout : function( $bricks, callback ) {
+
+ // place each brick
+ for (var i=0, len = $bricks.length; i < len; i++) {
+ this._placeBrick( $bricks[i] );
+ }
+
+ // set the size of the container
+ var containerSize = {};
+ containerSize.height = Math.max.apply( Math, this.colYs );
+ if ( this.options.isFitWidth ) {
+ var unusedCols = 0;
+ i = this.cols;
+ // count unused columns
+ while ( --i ) {
+ if ( this.colYs[i] !== 0 ) {
+ break;
+ }
+ unusedCols++;
+ }
+ // fit container to columns that have been used;
+ containerSize.width = (this.cols - unusedCols) * this.columnWidth - this.options.gutterWidth;
+ }
+ this.styleQueue.push({ $el: this.element, style: containerSize });
+
+ // are we animating the layout arrangement?
+ // use plugin-ish syntax for css or animate
+ var styleFn = !this.isLaidOut ? 'css' : (
+ this.options.isAnimated ? 'animate' : 'css'
+ ),
+ animOpts = this.options.animationOptions;
+
+ // process styleQueue
+ var obj;
+ for (i=0, len = this.styleQueue.length; i < len; i++) {
+ obj = this.styleQueue[i];
+ obj.$el[ styleFn ]( obj.style, animOpts );
+ }
+
+ // clear out queue for next time
+ this.styleQueue = [];
+
+ // provide $elems as context for the callback
+ if ( callback ) {
+ callback.call( $bricks );
+ }
+
+ this.isLaidOut = true;
+ },
+
+ // calculates number of columns
+ // i.e. this.columnWidth = 200
+ _getColumns : function() {
+ var container = this.options.isFitWidth ? this.element.parent() : this.element,
+ containerWidth = container.width();
+
+ // use fluid columnWidth function if there
+ this.columnWidth = this.isFluid ? this.options.columnWidth( containerWidth ) :
+ // if not, how about the explicitly set option?
+ this.options.columnWidth ||
+ // or use the size of the first item
+ this.$bricks.outerWidth(true) ||
+ // if there's no items, use size of container
+ containerWidth;
+
+ this.columnWidth += this.options.gutterWidth;
+
+ this.cols = Math.floor( ( containerWidth + this.options.gutterWidth ) / this.columnWidth );
+ this.cols = Math.max( this.cols, 1 );
+
+ },
+
+ // layout logic
+ _placeBrick: function( brick ) {
+ var $brick = $(brick),
+ colSpan, groupCount, groupY, groupColY, j;
+
+ //how many columns does this brick span
+ colSpan = Math.ceil( $brick.outerWidth(true) / this.columnWidth );
+ colSpan = Math.min( colSpan, this.cols );
+
+ if ( colSpan === 1 ) {
+ // if brick spans only one column, just like singleMode
+ groupY = this.colYs;
+ } else {
+ // brick spans more than one column
+ // how many different places could this brick fit horizontally
+ groupCount = this.cols + 1 - colSpan;
+ groupY = [];
+
+ // for each group potential horizontal position
+ for ( j=0; j < groupCount; j++ ) {
+ // make an array of colY values for that one group
+ groupColY = this.colYs.slice( j, j+colSpan );
+ // and get the max value of the array
+ groupY[j] = Math.max.apply( Math, groupColY );
+ }
+
+ }
+
+ // get the minimum Y value from the columns
+ var minimumY = Math.min.apply( Math, groupY ),
+ shortCol = 0;
+
+ // Find index of short column, the first from the left
+ for (var i=0, len = groupY.length; i < len; i++) {
+ if ( groupY[i] === minimumY ) {
+ shortCol = i;
+ break;
+ }
+ }
+
+ // position the brick
+ var position = {
+ top: minimumY + this.offset.y
+ };
+ // position.left or position.right
+ position[ this.horizontalDirection ] = this.columnWidth * shortCol + this.offset.x;
+ this.styleQueue.push({ $el: $brick, style: position });
+
+ // apply setHeight to necessary columns
+ var setHeight = minimumY + $brick.outerHeight(true),
+ setSpan = this.cols + 1 - len;
+ for ( i=0; i < setSpan; i++ ) {
+ this.colYs[ shortCol + i ] = setHeight;
+ }
+
+ },
+
+
+ resize: function() {
+ var prevColCount = this.cols;
+ // get updated colCount
+ this._getColumns();
+ if ( this.isFluid || this.cols !== prevColCount ) {
+ // if column count has changed, trigger new layout
+ this._reLayout();
+ }
+ },
+
+
+ _reLayout : function( callback ) {
+ // reset columns
+ var i = this.cols;
+ this.colYs = [];
+ while (i--) {
+ this.colYs.push( 0 );
+ }
+ // apply layout logic to all bricks
+ this.layout( this.$bricks, callback );
+ },
+
+ // ====================== Convenience methods ======================
+
+ // goes through all children again and gets bricks in proper order
+ reloadItems : function() {
+ this.$bricks = this._getBricks( this.element.children() );
+ },
+
+
+ reload : function( callback ) {
+ this.reloadItems();
+ this._init( callback );
+ },
+
+
+ // convienence method for working with Infinite Scroll
+ appended : function( $content, isAnimatedFromBottom, callback ) {
+ if ( isAnimatedFromBottom ) {
+ // set new stuff to the bottom
+ this._filterFindBricks( $content ).css({ top: this.element.height() });
+ var instance = this;
+ setTimeout( function(){
+ instance._appended( $content, callback );
+ }, 1 );
+ } else {
+ this._appended( $content, callback );
+ }
+ },
+
+ _appended : function( $content, callback ) {
+ var $newBricks = this._getBricks( $content );
+ // add new bricks to brick pool
+ this.$bricks = this.$bricks.add( $newBricks );
+ this.layout( $newBricks, callback );
+ },
+
+ // removes elements from Masonry widget
+ remove : function( $content ) {
+ this.$bricks = this.$bricks.not( $content );
+ $content.remove();
+ },
+
+ // destroys widget, returns elements and container back (close) to original style
+ destroy : function() {
+
+ this.$bricks
+ .removeClass('masonry-brick')
+ .each(function(){
+ this.style.position = '';
+ this.style.top = '';
+ this.style.left = '';
+ });
+
+ // re-apply saved container styles
+ var elemStyle = this.element[0].style;
+ for ( var prop in this.originalStyle ) {
+ elemStyle[ prop ] = this.originalStyle[ prop ];
+ }
+
+ this.element
+ .unbind('.masonry')
+ .removeClass('masonry')
+ .removeData('masonry');
+
+ $(window).unbind('.masonry');
+
+ }
+
+ };
+
+
+ // ======================= imagesLoaded Plugin ===============================
+ /*!
+ * jQuery imagesLoaded plugin v1.1.0
+ * http://github.com/desandro/imagesloaded
+ *
+ * MIT License. by Paul Irish et al.
+ */
+
+
+ // $('#my-container').imagesLoaded(myFunction)
+ // or
+ // $('img').imagesLoaded(myFunction)
+
+ // execute a callback when all images have loaded.
+ // needed because .load() doesn't work on cached images
+
+ // callback function gets image collection as argument
+ // `this` is the container
+
+ $.fn.imagesLoaded = function( callback ) {
+ var $this = this,
+ $images = $this.find('img').add( $this.filter('img') ),
+ len = $images.length,
+ blank = 'data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///ywAAAAAAQABAAACAUwAOw==',
+ loaded = [];
+
+ function triggerCallback() {
+ callback.call( $this, $images );
+ }
+
+ function imgLoaded( event ) {
+ var img = event.target;
+ if ( img.src !== blank && $.inArray( img, loaded ) === -1 ){
+ loaded.push( img );
+ if ( --len <= 0 ){
+ setTimeout( triggerCallback );
+ $images.unbind( '.imagesLoaded', imgLoaded );
+ }
+ }
+ }
+
+ // if no images, trigger immediately
+ if ( !len ) {
+ triggerCallback();
+ }
+
+ $images.bind( 'load.imagesLoaded error.imagesLoaded', imgLoaded ).each( function() {
+ // cached images don't fire load sometimes, so we reset src.
+ var src = this.src;
+ // webkit hack from http://groups.google.com/group/jquery-dev/browse_thread/thread/eee6ab7b2da50e1f
+ // data uri bypasses webkit log warning (thx doug jones)
+ this.src = blank;
+ this.src = src;
+ });
+
+ return $this;
+ };
+
+
+ // helper function for logging errors
+ // $.error breaks jQuery chaining
+ var logError = function( message ) {
+ if ( window.console ) {
+ window.console.error( message );
+ }
+ };
+
+ // ======================= Plugin bridge ===============================
+ // leverages data method to either create or return $.Mason constructor
+ // A bit from jQuery UI
+ // https://github.com/jquery/jquery-ui/blob/master/ui/jquery.ui.widget.js
+ // A bit from jcarousel
+ // https://github.com/jsor/jcarousel/blob/master/lib/jquery.jcarousel.js
+
+ $.fn.masonry = function( options ) {
+ if ( typeof options === 'string' ) {
+ // call method
+ var args = Array.prototype.slice.call( arguments, 1 );
+
+ this.each(function(){
+ var instance = $.data( this, 'masonry' );
+ if ( !instance ) {
+ logError( "cannot call methods on masonry prior to initialization; " +
+ "attempted to call method '" + options + "'" );
+ return;
+ }
+ if ( !$.isFunction( instance[options] ) || options.charAt(0) === "_" ) {
+ logError( "no such method '" + options + "' for masonry instance" );
+ return;
+ }
+ // apply method
+ instance[ options ].apply( instance, args );
+ });
+ } else {
+ this.each(function() {
+ var instance = $.data( this, 'masonry' );
+ if ( instance ) {
+ // apply options & init
+ instance.option( options || {} );
+ instance._init();
+ } else {
+ // initialize new instance
+ $.data( this, 'masonry', new $.Mason( options, this ) );
+ }
+ });
+ }
+ return this;
+ };
+
+})( window, jQuery ); \ No newline at end of file
diff --git a/debian/missing-sources/jquery.query.js b/debian/missing-sources/jquery.query.js
new file mode 100644
index 0000000..0156d22
--- /dev/null
+++ b/debian/missing-sources/jquery.query.js
@@ -0,0 +1,224 @@
+/**
+ * jQuery.query - Query String Modification and Creation for jQuery
+ * Written by Blair Mitchelmore (blair DOT mitchelmore AT gmail DOT com)
+ * Licensed under the WTFPL (http://sam.zoy.org/wtfpl/).
+ * Date: 2009/8/13
+ *
+ * @author Blair Mitchelmore
+ * @version 2.1.7
+ *
+ **/
+new function(settings) {
+ // Various Settings
+ var $separator = settings.separator || '&';
+ var $spaces = settings.spaces === false ? false : true;
+ var $suffix = settings.suffix === false ? '' : '[]';
+ var $prefix = settings.prefix === false ? false : true;
+ var $hash = $prefix ? settings.hash === true ? "#" : "?" : "";
+ var $numbers = settings.numbers === false ? false : true;
+
+ jQuery.query = new function() {
+ var is = function(o, t) {
+ return o != undefined && o !== null && (!!t ? o.constructor == t : true);
+ };
+ var parse = function(path) {
+ var m, rx = /\[([^[]*)\]/g, match = /^([^[]+)(\[.*\])?$/.exec(path), base = match[1], tokens = [];
+ while (m = rx.exec(match[2])) tokens.push(m[1]);
+ return [base, tokens];
+ };
+ var set = function(target, tokens, value) {
+ var o, token = tokens.shift();
+ if (typeof target != 'object') target = null;
+ if (token === "") {
+ if (!target) target = [];
+ if (is(target, Array)) {
+ target.push(tokens.length == 0 ? value : set(null, tokens.slice(0), value));
+ } else if (is(target, Object)) {
+ var i = 0;
+ while (target[i++] != null);
+ target[--i] = tokens.length == 0 ? value : set(target[i], tokens.slice(0), value);
+ } else {
+ target = [];
+ target.push(tokens.length == 0 ? value : set(null, tokens.slice(0), value));
+ }
+ } else if (token && token.match(/^\s*[0-9]+\s*$/)) {
+ var index = parseInt(token, 10);
+ if (!target) target = [];
+ target[index] = tokens.length == 0 ? value : set(target[index], tokens.slice(0), value);
+ } else if (token) {
+ var index = token.replace(/^\s*|\s*$/g, "");
+ if (!target) target = {};
+ if (is(target, Array)) {
+ var temp = {};
+ for (var i = 0; i < target.length; ++i) {
+ temp[i] = target[i];
+ }
+ target = temp;
+ }
+ target[index] = tokens.length == 0 ? value : set(target[index], tokens.slice(0), value);
+ } else {
+ return value;
+ }
+ return target;
+ };
+
+ var queryObject = function(a) {
+ var self = this;
+ self.keys = {};
+
+ if (a.queryObject) {
+ jQuery.each(a.get(), function(key, val) {
+ self.SET(key, val);
+ });
+ } else {
+ jQuery.each(arguments, function() {
+ var q = "" + this;
+ q = q.replace(/^[?#]/,''); // remove any leading ? || #
+ q = q.replace(/[;&]$/,''); // remove any trailing & || ;
+ if ($spaces) q = q.replace(/[+]/g,' '); // replace +'s with spaces
+
+ jQuery.each(q.split(/[&;]/), function(){
+ var key = decodeURIComponent(this.split('=')[0] || "");
+ var val = decodeURIComponent(this.split('=')[1] || "");
+
+ if (!key) return;
+
+ if ($numbers) {
+ if (/^[+-]?[0-9]+\.[0-9]*$/.test(val)) // simple float regex
+ val = parseFloat(val);
+ else if (/^[+-]?[0-9]+$/.test(val)) // simple int regex
+ val = parseInt(val, 10);
+ }
+
+ val = (!val && val !== 0) ? true : val;
+
+ if (val !== false && val !== true && typeof val != 'number')
+ val = val;
+
+ self.SET(key, val);
+ });
+ });
+ }
+ return self;
+ };
+
+ queryObject.prototype = {
+ queryObject: true,
+ has: function(key, type) {
+ var value = this.get(key);
+ return is(value, type);
+ },
+ GET: function(key) {
+ if (!is(key)) return this.keys;
+ var parsed = parse(key), base = parsed[0], tokens = parsed[1];
+ var target = this.keys[base];
+ while (target != null && tokens.length != 0) {
+ target = target[tokens.shift()];
+ }
+ return typeof target == 'number' ? target : target || "";
+ },
+ get: function(key) {
+ var target = this.GET(key);
+ if (is(target, Object))
+ return jQuery.extend(true, {}, target);
+ else if (is(target, Array))
+ return target.slice(0);
+ return target;
+ },
+ SET: function(key, val) {
+ var value = !is(val) ? null : val;
+ var parsed = parse(key), base = parsed[0], tokens = parsed[1];
+ var target = this.keys[base];
+ this.keys[base] = set(target, tokens.slice(0), value);
+ return this;
+ },
+ set: function(key, val) {
+ return this.copy().SET(key, val);
+ },
+ REMOVE: function(key) {
+ return this.SET(key, null).COMPACT();
+ },
+ remove: function(key) {
+ return this.copy().REMOVE(key);
+ },
+ EMPTY: function() {
+ var self = this;
+ jQuery.each(self.keys, function(key, value) {
+ delete self.keys[key];
+ });
+ return self;
+ },
+ load: function(url) {
+ var hash = url.replace(/^.*?[#](.+?)(?:\?.+)?$/, "$1");
+ var search = url.replace(/^.*?[?](.+?)(?:#.+)?$/, "$1");
+ return new queryObject(url.length == search.length ? '' : search, url.length == hash.length ? '' : hash);
+ },
+ empty: function() {
+ return this.copy().EMPTY();
+ },
+ copy: function() {
+ return new queryObject(this);
+ },
+ COMPACT: function() {
+ function build(orig) {
+ var obj = typeof orig == "object" ? is(orig, Array) ? [] : {} : orig;
+ if (typeof orig == 'object') {
+ function add(o, key, value) {
+ if (is(o, Array))
+ o.push(value);
+ else
+ o[key] = value;
+ }
+ jQuery.each(orig, function(key, value) {
+ if (!is(value)) return true;
+ add(obj, key, build(value));
+ });
+ }
+ return obj;
+ }
+ this.keys = build(this.keys);
+ return this;
+ },
+ compact: function() {
+ return this.copy().COMPACT();
+ },
+ toString: function() {
+ var i = 0, queryString = [], chunks = [], self = this;
+ var encode = function(str) {
+ str = str + "";
+ if ($spaces) str = str.replace(/ /g, "+");
+ return encodeURIComponent(str);
+ };
+ var addFields = function(arr, key, value) {
+ if (!is(value) || value === false) return;
+ var o = [encode(key)];
+ if (value !== true) {
+ o.push("=");
+ o.push(encode(value));
+ }
+ arr.push(o.join(""));
+ };
+ var build = function(obj, base) {
+ var newKey = function(key) {
+ return !base || base == "" ? [key].join("") : [base, "[", key, "]"].join("");
+ };
+ jQuery.each(obj, function(key, value) {
+ if (typeof value == 'object')
+ build(value, newKey(key));
+ else
+ addFields(chunks, newKey(key), value);
+ });
+ };
+
+ build(this.keys);
+
+ if (chunks.length > 0) queryString.push($hash);
+ queryString.push(chunks.join($separator));
+
+ return queryString.join("");
+ }
+ };
+
+ return new queryObject(location.search, location.hash);
+ };
+}(jQuery.query || {}); // Pass in jQuery.query as settings object
diff --git a/debian/missing-sources/jquery.schedule.js b/debian/missing-sources/jquery.schedule.js
new file mode 100644
index 0000000..7b37e59
--- /dev/null
+++ b/debian/missing-sources/jquery.schedule.js
@@ -0,0 +1,708 @@
+/*
+** jquery.schedule.js -- jQuery plugin for scheduled/deferred actions
+** Copyright (c) 2007 Ralf S. Engelschall <rse@engelschall.com>
+** Licensed under GPL <http://www.gnu.org/licenses/gpl.txt>
+**
+** $LastChangedDate$
+** $LastChangedRevision$
+*/
+
+/*
+ * <div id="button">TEST BUTTON</div>
+ * <div id="test"></div>
+ *
+ * <script type="text/javascript">
+ * $(document).ready(
+ * function(){
+ * $('#button').click(function () {
+ * $(this).css("color", "blue").schedule(2000, function (x) {
+ * $(this).css("color", "red");
+ * $("#test").html("test: x = " + x);
+ * }, 42);
+ * });
+ * });
+ * </script>
+ */
+
+(function($) {
+
+ /* object constructor */
+ $.scheduler = function () {
+ this.bucket = {};
+ return;
+ };
+
+ /* object methods */
+ $.scheduler.prototype = {
+ /* schedule a task */
+ schedule: function () {
+ /* schedule context with default parameters */
+ var ctx = {
+ "id": null, /* unique identifier of high-level schedule */
+ "time": 1000, /* time in milliseconds after which the task is run */
+ "repeat": false, /* whether schedule should be automatically repeated */
+ "protect": false, /* whether schedule should be protected from double scheduling */
+ "obj": null, /* function context object ("this") */
+ "func": function(){}, /* function to call */
+ "args": [] /* function arguments to pass */
+ };
+
+ /* helper function: portable checking whether something is a function */
+ function _isfn (fn) {
+ return (
+ !!fn
+ && typeof fn != "string"
+ && typeof fn[0] == "undefined"
+ && RegExp("function", "i").test(fn + "")
+ );
+ };
+
+ /* parse arguments into context parameters (part 1/4):
+ detect an override object (special case to support jQuery method) */
+ var i = 0;
+ var override = false;
+ if (typeof arguments[i] == "object" && arguments.length > 1) {
+ override = true;
+ i++;
+ }
+
+ /* parse arguments into context parameters (part 2/4):
+ support the flexible way of an associated array */
+ if (typeof arguments[i] == "object") {
+ for (var option in arguments[i])
+ if (typeof ctx[option] != "undefined")
+ ctx[option] = arguments[i][option];
+ i++;
+ }
+
+ /* parse arguments into context parameters (part 3/4):
+ support: schedule([time [, repeat], ]{{obj, methodname} | func}[, arg, ...]); */
+ if ( typeof arguments[i] == "number"
+ || ( typeof arguments[i] == "string"
+ && arguments[i].match(RegExp("^[0-9]+[smhdw]$"))))
+ ctx["time"] = arguments[i++];
+ if (typeof arguments[i] == "boolean")
+ ctx["repeat"] = arguments[i++];
+ if (typeof arguments[i] == "boolean")
+ ctx["protect"] = arguments[i++];
+ if ( typeof arguments[i] == "object"
+ && typeof arguments[i+1] == "string"
+ && _isfn(arguments[i][arguments[i+1]])) {
+ ctx["obj"] = arguments[i++];
+ ctx["func"] = arguments[i++];
+ }
+ else if ( typeof arguments[i] != "undefined"
+ && ( _isfn(arguments[i])
+ || typeof arguments[i] == "string"))
+ ctx["func"] = arguments[i++];
+ while (typeof arguments[i] != "undefined")
+ ctx["args"].push(arguments[i++]);
+
+ /* parse arguments into context parameters (part 4/4):
+ apply parameters from override object */
+ if (override) {
+ if (typeof arguments[1] == "object") {
+ for (var option in arguments[0])
+ if ( typeof ctx[option] != "undefined"
+ && typeof arguments[1][option] == "undefined")
+ ctx[option] = arguments[0][option];
+ }
+ else {
+ for (var option in arguments[0])
+ if (typeof ctx[option] != "undefined")
+ ctx[option] = arguments[0][option];
+ }
+ i++;
+ }
+
+ /* annotate context with internals */
+ ctx["_scheduler"] = this; /* internal: back-reference to scheduler object */
+ ctx["_handle"] = null; /* internal: unique handle of low-level task */
+
+ /* determine time value in milliseconds */
+ var match = String(ctx["time"]).match(RegExp("^([0-9]+)([smhdw])$"));
+ if (match && match[0] != "undefined" && match[1] != "undefined")
+ ctx["time"] = String(parseInt(match[1]) *
+ { s: 1000, m: 1000*60, h: 1000*60*60,
+ d: 1000*60*60*24, w: 1000*60*60*24*7 }[match[2]]);
+
+ /* determine unique identifier of task */
+ if (ctx["id"] == null)
+ ctx["id"] = ( String(ctx["repeat"]) + ":"
+ + String(ctx["protect"]) + ":"
+ + String(ctx["time"]) + ":"
+ + String(ctx["obj"]) + ":"
+ + String(ctx["func"]) + ":"
+ + String(ctx["args"]) );
+
+ /* optionally protect from duplicate calls */
+ if (ctx["protect"])
+ if (typeof this.bucket[ctx["id"]] != "undefined")
+ return this.bucket[ctx["id"]];
+
+ /* support execution of methods by name and arbitrary scripts */
+ if (!_isfn(ctx["func"])) {
+ if ( ctx["obj"] != null
+ && typeof ctx["obj"] == "object"
+ && typeof ctx["func"] == "string"
+ && _isfn(ctx["obj"][ctx["func"]]))
+ /* method by name */
+ ctx["func"] = ctx["obj"][ctx["func"]];
+ else
+ /* arbitrary script */
+ ctx["func"] = eval("function () { " + ctx["func"] + " }");
+ }
+
+ /* pass-through to internal scheduling operation */
+ ctx["_handle"] = this._schedule(ctx);
+
+ /* store context into bucket of scheduler object */
+ this.bucket[ctx["id"]] = ctx;
+
+ /* return context */
+ return ctx;
+ },
+
+ /* re-schedule a task */
+ reschedule: function (ctx) {
+ if (typeof ctx == "string")
+ ctx = this.bucket[ctx];
+
+ /* pass-through to internal scheduling operation */
+ ctx["_handle"] = this._schedule(ctx);
+
+ /* return context */
+ return ctx;
+ },
+
+ /* internal scheduling operation */
+ _schedule: function (ctx) {
+ /* closure to act as the call trampoline function */
+ var trampoline = function () {
+ /* jump into function */
+ var obj = (ctx["obj"] != null ? ctx["obj"] : ctx);
+ (ctx["func"]).apply(obj, ctx["args"]);
+
+ /* either repeat scheduling and keep in bucket or
+ just stop scheduling and delete from scheduler bucket */
+ if ( /* not cancelled from inside... */
+ typeof (ctx["_scheduler"]).bucket[ctx["id"]] != "undefined"
+ && /* ...and repeating requested */
+ ctx["repeat"])
+ (ctx["_scheduler"])._schedule(ctx);
+ else
+ delete (ctx["_scheduler"]).bucket[ctx["id"]];
+ };
+
+ /* schedule task and return handle */
+ return setTimeout(trampoline, ctx["time"]);
+ },
+
+ /* cancel a scheduled task */
+ cancel: function (ctx) {
+ if (typeof ctx == "string")
+ ctx = this.bucket[ctx];
+
+ /* cancel scheduled task */
+ if (typeof ctx == "object") {
+ clearTimeout(ctx["_handle"]);
+ delete this.bucket[ctx["id"]];
+ }
+ }
+ };
+
+ /* integrate a global instance of the scheduler into the global jQuery object */
+ $.extend({
+ scheduler$: new $.scheduler(),
+ schedule: function () { return $.scheduler$.schedule.apply ($.scheduler$, arguments) },
+ reschedule: function () { return $.scheduler$.reschedule.apply($.scheduler$, arguments) },
+ cancel: function () { return $.scheduler$.cancel.apply ($.scheduler$, arguments) }
+ });
+
+ /* integrate scheduling convinience method into all jQuery objects */
+ $.fn.extend({
+ schedule: function () {
+ var a = [ {} ];
+ for (var i = 0; i < arguments.length; i++)
+ a.push(arguments[i]);
+ return this.each(function () {
+ a[0] = { "id": this, "obj": this };
+ return $.schedule.apply($, a);
+ });
+ }
+ });
+
+})(jQuery);
+
+/*
+** jquery.schedule.js -- jQuery plugin for scheduled/deferred actions
+** Copyright (c) 2007 Ralf S. Engelschall <rse@engelschall.com>
+** Licensed under GPL <http://www.gnu.org/licenses/gpl.txt>
+**
+** $LastChangedDate$
+** $LastChangedRevision$
+*/
+
+/*
+ * <div id="button">TEST BUTTON</div>
+ * <div id="test"></div>
+ *
+ * <script type="text/javascript">
+ * $(document).ready(
+ * function(){
+ * $('#button').click(function () {
+ * $(this).css("color", "blue").schedule(2000, function (x) {
+ * $(this).css("color", "red");
+ * $("#test").html("test: x = " + x);
+ * }, 42);
+ * });
+ * });
+ * </script>
+ */
+
+(function($) {
+
+ /* object constructor */
+ $.scheduler = function () {
+ this.bucket = {};
+ return;
+ };
+
+ /* object methods */
+ $.scheduler.prototype = {
+ /* schedule a task */
+ schedule: function () {
+ /* schedule context with default parameters */
+ var ctx = {
+ "id": null, /* unique identifier of high-level schedule */
+ "time": 1000, /* time in milliseconds after which the task is run */
+ "repeat": false, /* whether schedule should be automatically repeated */
+ "protect": false, /* whether schedule should be protected from double scheduling */
+ "obj": null, /* function context object ("this") */
+ "func": function(){}, /* function to call */
+ "args": [] /* function arguments to pass */
+ };
+
+ /* helper function: portable checking whether something is a function */
+ function _isfn (fn) {
+ return (
+ !!fn
+ && typeof fn != "string"
+ && typeof fn[0] == "undefined"
+ && RegExp("function", "i").test(fn + "")
+ );
+ };
+
+ /* parse arguments into context parameters (part 1/4):
+ detect an override object (special case to support jQuery method) */
+ var i = 0;
+ var override = false;
+ if (typeof arguments[i] == "object" && arguments.length > 1) {
+ override = true;
+ i++;
+ }
+
+ /* parse arguments into context parameters (part 2/4):
+ support the flexible way of an associated array */
+ if (typeof arguments[i] == "object") {
+ for (var option in arguments[i])
+ if (typeof ctx[option] != "undefined")
+ ctx[option] = arguments[i][option];
+ i++;
+ }
+
+ /* parse arguments into context parameters (part 3/4):
+ support: schedule([time [, repeat], ]{{obj, methodname} | func}[, arg, ...]); */
+ if ( typeof arguments[i] == "number"
+ || ( typeof arguments[i] == "string"
+ && arguments[i].match(RegExp("^[0-9]+[smhdw]$"))))
+ ctx["time"] = arguments[i++];
+ if (typeof arguments[i] == "boolean")
+ ctx["repeat"] = arguments[i++];
+ if (typeof arguments[i] == "boolean")
+ ctx["protect"] = arguments[i++];
+ if ( typeof arguments[i] == "object"
+ && typeof arguments[i+1] == "string"
+ && _isfn(arguments[i][arguments[i+1]])) {
+ ctx["obj"] = arguments[i++];
+ ctx["func"] = arguments[i++];
+ }
+ else if ( typeof arguments[i] != "undefined"
+ && ( _isfn(arguments[i])
+ || typeof arguments[i] == "string"))
+ ctx["func"] = arguments[i++];
+ while (typeof arguments[i] != "undefined")
+ ctx["args"].push(arguments[i++]);
+
+ /* parse arguments into context parameters (part 4/4):
+ apply parameters from override object */
+ if (override) {
+ if (typeof arguments[1] == "object") {
+ for (var option in arguments[0])
+ if ( typeof ctx[option] != "undefined"
+ && typeof arguments[1][option] == "undefined")
+ ctx[option] = arguments[0][option];
+ }
+ else {
+ for (var option in arguments[0])
+ if (typeof ctx[option] != "undefined")
+ ctx[option] = arguments[0][option];
+ }
+ i++;
+ }
+
+ /* annotate context with internals */
+ ctx["_scheduler"] = this; /* internal: back-reference to scheduler object */
+ ctx["_handle"] = null; /* internal: unique handle of low-level task */
+
+ /* determine time value in milliseconds */
+ var match = String(ctx["time"]).match(RegExp("^([0-9]+)([smhdw])$"));
+ if (match && match[0] != "undefined" && match[1] != "undefined")
+ ctx["time"] = String(parseInt(match[1]) *
+ { s: 1000, m: 1000*60, h: 1000*60*60,
+ d: 1000*60*60*24, w: 1000*60*60*24*7 }[match[2]]);
+
+ /* determine unique identifier of task */
+ if (ctx["id"] == null)
+ ctx["id"] = ( String(ctx["repeat"]) + ":"
+ + String(ctx["protect"]) + ":"
+ + String(ctx["time"]) + ":"
+ + String(ctx["obj"]) + ":"
+ + String(ctx["func"]) + ":"
+ + String(ctx["args"]) );
+
+ /* optionally protect from duplicate calls */
+ if (ctx["protect"])
+ if (typeof this.bucket[ctx["id"]] != "undefined")
+ return this.bucket[ctx["id"]];
+
+ /* support execution of methods by name and arbitrary scripts */
+ if (!_isfn(ctx["func"])) {
+ if ( ctx["obj"] != null
+ && typeof ctx["obj"] == "object"
+ && typeof ctx["func"] == "string"
+ && _isfn(ctx["obj"][ctx["func"]]))
+ /* method by name */
+ ctx["func"] = ctx["obj"][ctx["func"]];
+ else
+ /* arbitrary script */
+ ctx["func"] = eval("function () { " + ctx["func"] + " }");
+ }
+
+ /* pass-through to internal scheduling operation */
+ ctx["_handle"] = this._schedule(ctx);
+
+ /* store context into bucket of scheduler object */
+ this.bucket[ctx["id"]] = ctx;
+
+ /* return context */
+ return ctx;
+ },
+
+ /* re-schedule a task */
+ reschedule: function (ctx) {
+ if (typeof ctx == "string")
+ ctx = this.bucket[ctx];
+
+ /* pass-through to internal scheduling operation */
+ ctx["_handle"] = this._schedule(ctx);
+
+ /* return context */
+ return ctx;
+ },
+
+ /* internal scheduling operation */
+ _schedule: function (ctx) {
+ /* closure to act as the call trampoline function */
+ var trampoline = function () {
+ /* jump into function */
+ var obj = (ctx["obj"] != null ? ctx["obj"] : ctx);
+ (ctx["func"]).apply(obj, ctx["args"]);
+
+ /* either repeat scheduling and keep in bucket or
+ just stop scheduling and delete from scheduler bucket */
+ if ( /* not cancelled from inside... */
+ typeof (ctx["_scheduler"]).bucket[ctx["id"]] != "undefined"
+ && /* ...and repeating requested */
+ ctx["repeat"])
+ (ctx["_scheduler"])._schedule(ctx);
+ else
+ delete (ctx["_scheduler"]).bucket[ctx["id"]];
+ };
+
+ /* schedule task and return handle */
+ return setTimeout(trampoline, ctx["time"]);
+ },
+
+ /* cancel a scheduled task */
+ cancel: function (ctx) {
+ if (typeof ctx == "string")
+ ctx = this.bucket[ctx];
+
+ /* cancel scheduled task */
+ if (typeof ctx == "object") {
+ clearTimeout(ctx["_handle"]);
+ delete this.bucket[ctx["id"]];
+ }
+ }
+ };
+
+ /* integrate a global instance of the scheduler into the global jQuery object */
+ $.extend({
+ scheduler$: new $.scheduler(),
+ schedule: function () { return $.scheduler$.schedule.apply ($.scheduler$, arguments) },
+ reschedule: function () { return $.scheduler$.reschedule.apply($.scheduler$, arguments) },
+ cancel: function () { return $.scheduler$.cancel.apply ($.scheduler$, arguments) }
+ });
+
+ /* integrate scheduling convinience method into all jQuery objects */
+ $.fn.extend({
+ schedule: function () {
+ var a = [ {} ];
+ for (var i = 0; i < arguments.length; i++)
+ a.push(arguments[i]);
+ return this.each(function () {
+ a[0] = { "id": this, "obj": this };
+ return $.schedule.apply($, a);
+ });
+ }
+ });
+
+})(jQuery);
+
+/*
+** jquery.schedule.js -- jQuery plugin for scheduled/deferred actions
+** Copyright (c) 2007 Ralf S. Engelschall <rse@engelschall.com>
+** Licensed under GPL <http://www.gnu.org/licenses/gpl.txt>
+**
+** $LastChangedDate$
+** $LastChangedRevision$
+*/
+
+/*
+ * <div id="button">TEST BUTTON</div>
+ * <div id="test"></div>
+ *
+ * <script type="text/javascript">
+ * $(document).ready(
+ * function(){
+ * $('#button').click(function () {
+ * $(this).css("color", "blue").schedule(2000, function (x) {
+ * $(this).css("color", "red");
+ * $("#test").html("test: x = " + x);
+ * }, 42);
+ * });
+ * });
+ * </script>
+ */
+
+(function($) {
+
+ /* object constructor */
+ $.scheduler = function () {
+ this.bucket = {};
+ return;
+ };
+
+ /* object methods */
+ $.scheduler.prototype = {
+ /* schedule a task */
+ schedule: function () {
+ /* schedule context with default parameters */
+ var ctx = {
+ "id": null, /* unique identifier of high-level schedule */
+ "time": 1000, /* time in milliseconds after which the task is run */
+ "repeat": false, /* whether schedule should be automatically repeated */
+ "protect": false, /* whether schedule should be protected from double scheduling */
+ "obj": null, /* function context object ("this") */
+ "func": function(){}, /* function to call */
+ "args": [] /* function arguments to pass */
+ };
+
+ /* helper function: portable checking whether something is a function */
+ function _isfn (fn) {
+ return (
+ !!fn
+ && typeof fn != "string"
+ && typeof fn[0] == "undefined"
+ && RegExp("function", "i").test(fn + "")
+ );
+ };
+
+ /* parse arguments into context parameters (part 1/4):
+ detect an override object (special case to support jQuery method) */
+ var i = 0;
+ var override = false;
+ if (typeof arguments[i] == "object" && arguments.length > 1) {
+ override = true;
+ i++;
+ }
+
+ /* parse arguments into context parameters (part 2/4):
+ support the flexible way of an associated array */
+ if (typeof arguments[i] == "object") {
+ for (var option in arguments[i])
+ if (typeof ctx[option] != "undefined")
+ ctx[option] = arguments[i][option];
+ i++;
+ }
+
+ /* parse arguments into context parameters (part 3/4):
+ support: schedule([time [, repeat], ]{{obj, methodname} | func}[, arg, ...]); */
+ if ( typeof arguments[i] == "number"
+ || ( typeof arguments[i] == "string"
+ && arguments[i].match(RegExp("^[0-9]+[smhdw]$"))))
+ ctx["time"] = arguments[i++];
+ if (typeof arguments[i] == "boolean")
+ ctx["repeat"] = arguments[i++];
+ if (typeof arguments[i] == "boolean")
+ ctx["protect"] = arguments[i++];
+ if ( typeof arguments[i] == "object"
+ && typeof arguments[i+1] == "string"
+ && _isfn(arguments[i][arguments[i+1]])) {
+ ctx["obj"] = arguments[i++];
+ ctx["func"] = arguments[i++];
+ }
+ else if ( typeof arguments[i] != "undefined"
+ && ( _isfn(arguments[i])
+ || typeof arguments[i] == "string"))
+ ctx["func"] = arguments[i++];
+ while (typeof arguments[i] != "undefined")
+ ctx["args"].push(arguments[i++]);
+
+ /* parse arguments into context parameters (part 4/4):
+ apply parameters from override object */
+ if (override) {
+ if (typeof arguments[1] == "object") {
+ for (var option in arguments[0])
+ if ( typeof ctx[option] != "undefined"
+ && typeof arguments[1][option] == "undefined")
+ ctx[option] = arguments[0][option];
+ }
+ else {
+ for (var option in arguments[0])
+ if (typeof ctx[option] != "undefined")
+ ctx[option] = arguments[0][option];
+ }
+ i++;
+ }
+
+ /* annotate context with internals */
+ ctx["_scheduler"] = this; /* internal: back-reference to scheduler object */
+ ctx["_handle"] = null; /* internal: unique handle of low-level task */
+
+ /* determine time value in milliseconds */
+ var match = String(ctx["time"]).match(RegExp("^([0-9]+)([smhdw])$"));
+ if (match && match[0] != "undefined" && match[1] != "undefined")
+ ctx["time"] = String(parseInt(match[1]) *
+ { s: 1000, m: 1000*60, h: 1000*60*60,
+ d: 1000*60*60*24, w: 1000*60*60*24*7 }[match[2]]);
+
+ /* determine unique identifier of task */
+ if (ctx["id"] == null)
+ ctx["id"] = ( String(ctx["repeat"]) + ":"
+ + String(ctx["protect"]) + ":"
+ + String(ctx["time"]) + ":"
+ + String(ctx["obj"]) + ":"
+ + String(ctx["func"]) + ":"
+ + String(ctx["args"]) );
+
+ /* optionally protect from duplicate calls */
+ if (ctx["protect"])
+ if (typeof this.bucket[ctx["id"]] != "undefined")
+ return this.bucket[ctx["id"]];
+
+ /* support execution of methods by name and arbitrary scripts */
+ if (!_isfn(ctx["func"])) {
+ if ( ctx["obj"] != null
+ && typeof ctx["obj"] == "object"
+ && typeof ctx["func"] == "string"
+ && _isfn(ctx["obj"][ctx["func"]]))
+ /* method by name */
+ ctx["func"] = ctx["obj"][ctx["func"]];
+ else
+ /* arbitrary script */
+ ctx["func"] = eval("function () { " + ctx["func"] + " }");
+ }
+
+ /* pass-through to internal scheduling operation */
+ ctx["_handle"] = this._schedule(ctx);
+
+ /* store context into bucket of scheduler object */
+ this.bucket[ctx["id"]] = ctx;
+
+ /* return context */
+ return ctx;
+ },
+
+ /* re-schedule a task */
+ reschedule: function (ctx) {
+ if (typeof ctx == "string")
+ ctx = this.bucket[ctx];
+
+ /* pass-through to internal scheduling operation */
+ ctx["_handle"] = this._schedule(ctx);
+
+ /* return context */
+ return ctx;
+ },
+
+ /* internal scheduling operation */
+ _schedule: function (ctx) {
+ /* closure to act as the call trampoline function */
+ var trampoline = function () {
+ /* jump into function */
+ var obj = (ctx["obj"] != null ? ctx["obj"] : ctx);
+ (ctx["func"]).apply(obj, ctx["args"]);
+
+ /* either repeat scheduling and keep in bucket or
+ just stop scheduling and delete from scheduler bucket */
+ if ( /* not cancelled from inside... */
+ typeof (ctx["_scheduler"]).bucket[ctx["id"]] != "undefined"
+ && /* ...and repeating requested */
+ ctx["repeat"])
+ (ctx["_scheduler"])._schedule(ctx);
+ else
+ delete (ctx["_scheduler"]).bucket[ctx["id"]];
+ };
+
+ /* schedule task and return handle */
+ return setTimeout(trampoline, ctx["time"]);
+ },
+
+ /* cancel a scheduled task */
+ cancel: function (ctx) {
+ if (typeof ctx == "string")
+ ctx = this.bucket[ctx];
+
+ /* cancel scheduled task */
+ if (typeof ctx == "object") {
+ clearTimeout(ctx["_handle"]);
+ delete this.bucket[ctx["id"]];
+ }
+ }
+ };
+
+ /* integrate a global instance of the scheduler into the global jQuery object */
+ $.extend({
+ scheduler$: new $.scheduler(),
+ schedule: function () { return $.scheduler$.schedule.apply ($.scheduler$, arguments) },
+ reschedule: function () { return $.scheduler$.reschedule.apply($.scheduler$, arguments) },
+ cancel: function () { return $.scheduler$.cancel.apply ($.scheduler$, arguments) }
+ });
+
+ /* integrate scheduling convinience method into all jQuery objects */
+ $.fn.extend({
+ schedule: function () {
+ var a = [ {} ];
+ for (var i = 0; i < arguments.length; i++)
+ a.push(arguments[i]);
+ return this.each(function () {
+ a[0] = { "id": this, "obj": this };
+ return $.schedule.apply($, a);
+ });
+ }
+ });
+
+})(jQuery);
+
diff --git a/debian/missing-sources/jquery.ui.touch-punch.js b/debian/missing-sources/jquery.ui.touch-punch.js
new file mode 100644
index 0000000..2766f41
--- /dev/null
+++ b/debian/missing-sources/jquery.ui.touch-punch.js
@@ -0,0 +1,160 @@
+/*!
+ * jQuery UI Touch Punch 0.2.2
+ *
+ * Copyright 2011, 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,
+ 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'))
+ .bind('touchmove', $.proxy(self, '_touchMove'))
+ .bind('touchend', $.proxy(self, '_touchEnd'));
+
+ // Call the original $.ui.mouse init method
+ _mouseInit.call(self);
+ };
+
+})(jQuery); \ No newline at end of file
diff --git a/debian/missing-sources/jsCropperUI-1.2.0.tar.gz b/debian/missing-sources/jsCropperUI-1.2.0.tar.gz
new file mode 100644
index 0000000..f9aab2d
--- /dev/null
+++ b/debian/missing-sources/jsCropperUI-1.2.0.tar.gz
Binary files differ
diff --git a/debian/missing-sources/mediaelement/README.md b/debian/missing-sources/mediaelement/README.md
new file mode 100644
index 0000000..acbfbff
--- /dev/null
+++ b/debian/missing-sources/mediaelement/README.md
@@ -0,0 +1,681 @@
+# `<video>` and `<audio>` made easy. One file. Any browser. Same UI.
+
+* Author: John Dyer [http://j.hn/](http://j.hn/)
+* Website: [http://mediaelementjs.com/](http://mediaelementjs.com/)
+* License: MIT
+* Meaning: Use everywhere, keep copyright, it'd be swell if you'd link back here.
+* Thanks: my employer, [Dallas Theological Seminary](http://www.dts.edu/)
+* Contributors: [mikesten](https://github.com/mikesten), [sylvinus](https://github.com/sylvinus), [mattfarina](https://github.com/mattfarina), [romaninsh](https://github.com/romaninsh), [fmalk](https://github.com/fmalk), [jeffrafter](https://github.com/jeffrafter), [sompylasar](https://github.com/sompylasar), [andyfowler](https://github.com/andyfowler), [RobRoy](https://github.com/RobRoy), [jakearchibald](https://github.com/jakearchibald), [seanhellwig](https://github.com/seanhellwig), [CJ-Jackson](https://github.com/CJ-Jackson), [kaichen](https://github.com/kaichen), [gselva](https://github.com/gselva), [erktime](https://github.com/erktime), [bradleyboy](https://github.com/bradleyboy), [kristerkari](https://github.com/kristerkari), [rmhall](https://github.com/rmhall), [tantalic](https://github.com/tantalic), [madesign](http://github.com/madesign), [aschempp](http://github.com/aschempp), [gavinlynch](https://github.com/gavinlynch), [Birol2010](http://github.com/Birol2010), tons of others (see pulls)
+
+
+## Installation and Usage
+
+_MediaElementPlayer: HTML5 `<video>` and `<audio>` player_
+
+A complete HTML/CSS audio/video player built on top `MediaElement.js` and `jQuery`. Many great HTML5 players have a completely separate Flash UI in fallback mode, but MediaElementPlayer.js uses the same HTML/CSS for all players.
+
+### 1. Add Script and Stylesheet
+
+ <script src="jquery.js"></script>
+ <script src="mediaelement-and-player.min.js"></script>
+ <link rel="stylesheet" href="mediaelementplayer.css" />
+
+### 2. Option A: Single H.264 file
+
+If your users have JavaScript and Flash, this is the easist route for all browsers and mobile devices.
+
+ <video src="myvideo.mp4" width="320" height="240"></video>
+
+### 2. Option B: Multiple codecs with Flash fall-through when JavaScript is disabled
+
+This includes multiple codecs for various browsers (H.264 for IE and Safari, WebM for Chrome, Firefox 4, and Opera, Ogg for Firefox 3) as well as a Flash fallback for non HTML5 browsers with JavaScript disabled.
+
+ <video width="320" height="240" poster="poster.jpg" controls="controls" preload="none">
+ <source type="video/mp4" src="myvideo.mp4" />
+ <source type="video/webm" src="myvideo.webm" />
+ <source type="video/ogg" src="myvideo.ogv" />
+ <object width="320" height="240" type="application/x-shockwave-flash" data="flashmediaelement.swf">
+ <param name="movie" value="flashmediaelement.swf" />
+ <param name="flashvars" value="controls=true&amp;poster=myvideo.jpg&amp;file=myvideo.mp4" />
+ <img src="myvideo.jpg" width="320" height="240" title="No video playback capabilities" />
+ </object>
+ </video>
+
+### 3. Run startup script
+
+Make sure this is not in the `<head>` tag or iOS 3 will fail.
+
+ <script>
+ // jQuery method
+ $('video').mediaelementplayer();
+ </script>
+
+ <script>
+ // normal JavaScript
+ var player = new MediaElementPlayer('#player');
+ </script>
+
+## How it Works:
+_MediaElement.js: HTML5 `<video>` and `<audio>` shim_
+
+`MediaElement.js` is a set of custom Flash and Silverlight plugins that mimic the HTML5 MediaElement API for browsers that don't support HTML5 or don't support the media codecs you're using.
+Instead of using Flash as a _fallback_, Flash is used to make the browser seem HTML5 compliant and enable codecs like H.264 (via Flash) and even WMV (via Silverlight) on all browsers.
+
+ <script src="mediaelement.js"></script>
+ <video src="myvideo.mp4" width="320" height="240"></video>
+
+ <script>
+ var v = document.getElementsByTagName("video")[0];
+ new MediaElement(v, {success: function(media) {
+ media.play();
+ }});
+ </script>
+
+You can use this as a standalone library if you wish, or just stick with the full MediaElementPlayer.
+
+### Version History
+
+*Proposed features*
+
+* deeper WebVTT support (alignment, color, etc.) - include captionator
+* Full support for Ender.js, including mediaelement-and-player-standalone which includes ender.
+* thin line when controls are off
+* system-wide events
+* Ogg/Theora playback
+* Better alignment with native MediaElement (using shimichanga.com techniques)
+
+*2.12.1 (X)*
+
+* More i18n fixes for Wordpress (SergeyBiryukov) https://github.com/johndyer/mediaelement/pull/940
+* Fix touch detection in QtWebKit (peterbrook) https://github.com/johndyer/mediaelement/pull/939
+* Added configuration option httpsBasicAuthSite fix sites using HTTPS basic authentication (benroy73) https://github.com/johndyer/mediaelement/pull/937
+* Fixed backlight plugin error (eviweb) https://github.com/johndyer/mediaelement/pull/932
+* Fix some wrong dates on the change log (heartcode) https://github.com/johndyer/mediaelement/pull/930
+* Add a mejs-fullscreen css class on the root element (fbuecklers) https://github.com/johndyer/mediaelement/pull/925
+* fix for ff switch between fullscreen and normal mode (fbuecklers) https://github.com/johndyer/mediaelement/pull/924
+
+
+*2.12.0 (2013/06/02)*
+
+* Removed old media files from repo (reduced filesize from 150MB to 25MB)
+* Added `test.html` to `/tests/` folder to use JS files in `/src/` folder
+* Fullscreen plugin player toggles play/pause when controls are clicked (JeffreyATW) https://github.com/johndyer/mediaelement/pull/742
+* Making use of pluginWidth & pluginHeight (simonschuh) https://github.com/johndyer/mediaelement/pull/837
+* Proportional poster images (IE9+ Chrome, Safari, Firefox) (eyefood) https://github.com/johndyer/mediaelement/pull/838
+* Fixed video resolution on seek in flash (efEris) https://github.com/johndyer/mediaelement/pull/839
+* Option for custom error message when no plugins are found. (svoynow-lz) https://github.com/johndyer/mediaelement/pull/842
+* Fix for Safari to play video on HTTPS site (benroy73) https://github.com/johndyer/mediaelement/pull/845
+* Fixes Mute/UnMute when playing from a YouTube source (mbaker3) https://github.com/johndyer/mediaelement/pull/848
+* i18n fixes for better compatibility with WordPress (SergeyBiryukov) https://github.com/johndyer/mediaelement/pull/850
+* Fixing invalid characters restrictions for URLs (sebablanco) https://github.com/johndyer/mediaelement/pull/859
+* Checking for pluginType on media instead of mediaelementplayer in Fullscreen (JeffreyATW) https://github.com/johndyer/mediaelement/pull/865
+* Problem with IE9 on Windows 7 N / Windows 7 KN without WMP installed (sarvaje) https://github.com/johndyer/mediaelement/pull/868
+* Cleanup stylesheet (jawittdesigns) https://github.com/johndyer/mediaelement/pull/867
+* Properly treat namespace-only events for `globalUnbind()` (odnamrataizem) https://github.com/johndyer/mediaelement/pull/878
+* Fixed issue with slash character separating time (S2) https://github.com/johndyer/mediaelement/pull/879
+
+*2.11.3 (2013/04/13)*
+
+* Change to `getScriptPath` to allow querystring variables to be added (for Wordpress Core)
+
+*2.11.2 (2013/04/12)*
+
+* Fixed overly aggressive XSS testing (excluding forward slashes)
+* Fixed line endings on Flash (*.as) files (markjaquith) (https://github.com/johndyer/mediaelement/pull/834)
+* Included protocol relative URL for YouTube (Dan Tsosie) (https://github.com/johndyer/mediaelement/pull/832)
+
+*2.11.1 (2013/04/11)*
+
+Major changes
+
+* Removed Ogg, WebM, and MP3 files to keep download under 10MB. Files are now at https://github.com/johndyer/mediaelement-files
+* Simple Flash Pseudo-streaming [set enablePseudoStreaming:true, pseudoStreamingStartQueryParam:'start'] (BryanMorgan) (https://github.com/johndyer/mediaelement/pull/814)
+* Fixed possible XSS attack through `file=` parameter in `flashmediaelement.swf`
+
+Fixes and updates
+
+* Protocol relative YouTube URLs for `iframe` API (dtsosie) (https://github.com/johndyer/mediaelement/pull/825)
+* Added aria-label to all button elements (Luzifer) (https://github.com/johndyer/mediaelement/pull/824)
+* Fixed preroll adclick URL (johndyer)
+* Traditional chinese locale strings for i18n module (latzt) (https://github.com/johndyer/mediaelement/pull/820)
+* Allow captions on audio player (LeResKP) (https://github.com/johndyer/mediaelement/pull/819)
+* Fix incorrect path returned by `getScriptPath()` (Ciki) (Fix incorrect path returned by getScriptPath())
+* Overhauling hover div creation and placement (JeffreyATW) (https://github.com/johndyer/mediaelement/pull/813)
+* Clear timeout for second fullscreen stretch attempt (JeffreyATW) (https://github.com/johndyer/mediaelement/pull/812)
+* fix type resolution when extension is uppercased (jbdemonte) (https://github.com/johndyer/mediaelement/pull/801)
+* "splice is not a function" fix on `MediaElementPlayer.remove()` (odnamrataizem) (https://github.com/johndyer/mediaelement/pull/799)
+* Make Flash stage handle CLICK rather than MOUSE_DOWN (odnamrataizem) (https://github.com/johndyer/mediaelement/pull/804)
+
+
+*2.11.0 (2013/03/13)*
+
+* Preroll ads manager
+* VAST ads plugin (sponsored by Minito Video)
+* Slides `<track>` type (non-standard HTML5 use)
+* Calculate rails size only with visible elements (romanbsd) (https://github.com/johndyer/mediaelement/pull/773)
+* Round calculations of progress bar to prevent fractions (romanbsd) (https://github.com/johndyer/mediaelement/pull/768)
+* Fix AndroidUseNativeControls (LeResKP) (https://github.com/johndyer/mediaelement/pull/749)
+* Muting the volume icon if startVolume is set to 0 (heartcode) (https://github.com/johndyer/mediaelement/pull/747)
+* Make YouTube URL protocol relative (strworkstation) (https://github.com/johndyer/mediaelement/pull/761)
+* Prevent Flash audio player from sending too many 'progress' events (johndyer)
+* Properly clean up player when calling MediaElementPlayer.remove() (odnamrataizem) (https://github.com/johndyer/mediaelement/pull/779)
+* Add "mejs-shim" class to all shims to prevent improper resizing (JeffreyATW) (https://github.com/johndyer/mediaelement/pull/789)
+* Bug fix for the error "this.pluginApi.pauseMedia is not a function" when using the flash player and removing the dom element. (Jmaharman) https://github.com/johndyer/mediaelement/pull/788
+* Make possible to open youtube links as audio only (Seb33300) https://github.com/johndyer/mediaelement/pull/784
+* Add a few basic Jasmine tests (msgilligan) https://github.com/johndyer/mediaelement/pull/781
+* Add option to hide the video controls on load (eResKP) https://github.com/johndyer/mediaelement/pull/780#issuecomment-14781622
+* [cc] button can now be a toggle when there's just one track (LeResKP) https://github.com/johndyer/mediaelement/pull/793
+* fixed error when srclang was missing
+
+*2.10.3 (2013/01/27)*
+
+* Fix broken scrollbar from API reference error (peterbrook) (https://github.com/johndyer/mediaelement/pull/739)
+
+*2.10.2 (2013/01/26)*
+
+* The project is now MIT-only, instead of dual licensed MIT and GPL (just as jQuery has done: http://jquery.org/license/)
+* Fix audio height in 100% mode (https://github.com/johndyer/mediaelement/pull/667)
+* Make rewinding at the end optional (https://github.com/johndyer/mediaelement/pull/725)
+* Bugfix: attributes for PluginMediaElement (https://github.com/johndyer/mediaelement/pull/722)
+* Add mejs-long-video class when capture is 1hr or longer, custom styles (https://github.com/johndyer/mediaelement/pull/715)
+* Fix for dragging playhead horizontally off the video (https://github.com/johndyer/mediaelement/pull/711)
+* Align timing of captions with show/hide controls (https://github.com/johndyer/mediaelement/pull/708)
+* Missing semicolon (https://github.com/johndyer/mediaelement/pull/737)
+* Don't send timeupdate event after ended event (https://github.com/johndyer/mediaelement/pull/727)
+* Added option to disable pause/play on main div click (https://github.com/johndyer/mediaelement/pull/735)
+
+*2.10.1 (2012/12/31)*
+
+* New postroll feature (https://github.com/johndyer/mediaelement/pull/660)
+* PluginMediaElement click-to-pause behavior doesn't work (https://github.com/johndyer/mediaelement/pull/691)
+* Use the normal CSS property name after the vendor prefix (https://github.com/johndyer/mediaelement/pull/686)
+* Select first source that is supported by the browser (https://github.com/johndyer/mediaelement/pull/679)
+* fixed outerWidth for jQuery 1.8 compatiability (https://github.com/johndyer/mediaelement/pull/680)
+* Fix for Issue #676 when Stop button does not behaves as expected in selected browsers (https://github.com/johndyer/mediaelement/pull/678)
+* Fix source switching on Webkit in SourceChooser (https://github.com/johndyer/mediaelement/pull/675)
+* Better 100% mode handling within non-visible container (https://github.com/johndyer/mediaelement/pull/668)
+* Display chapter tracks for late-loading video sources, including YouTube (https://github.com/johndyer/mediaelement/pull/665)
+* Added SVG Stop icon (https://github.com/johndyer/mediaelement/pull/696)
+* Added SVG source chooser icon (https://github.com/johndyer/mediaelement/pull/669)
+* Adding rounding to volume slider left, top, and and width setters (https://github.com/johndyer/mediaelement/pull/684)
+* Display chapter tracks for late-loading video sources, including YouTube (https://github.com/johndyer/mediaelement/pull/665)
+
+*2.10.0 (2012/11/23)*
+
+* Support of matchMedia where possible [zachleat]
+* Fix for 100% audio using correct sizing [dougwilson]
+* SVG icons for better Retina support [johndyer]
+* Localized buttons [latzt] https://github.com/johndyer/mediaelement/pull/627
+* Volume handle doesn't set initial position properly [JeffreyATW] https://github.com/johndyer/mediaelement/pull/625
+* Cleaned up some CSS whitespace https://github.com/johndyer/mediaelement/pull/656
+* Vimeo - updated to iframe code (from old megaloop)
+
+*2.9.5 (2012/09/26)*
+
+* Fixed faulty FlashMediaElement.swf (due to Git program mashing it)
+* Fixed track element issues introduced by DFXP captions
+
+*2.9.4 (2012/09/24)*
+
+* Improved RTMP parsing [pansapien] https://github.com/johndyer/mediaelement/pull/574
+* Added `flashStreamer` option to separate streamer from file
+* Raise an error for unknown video size in Flash [denmarkin] https://github.com/johndyer/mediaelement/pull/571
+* Fix for alwaysShowControls with keyboard interaction [peterh-capella] https://github.com/johndyer/mediaelement/pull/569
+* Support for DFXP captions [justinl-capella] https://github.com/johndyer/mediaelement/pull/420
+
+*2.9.3 (2012/08/23) *
+
+* Allows use of `style="max-width: 100%;"` for responsive video
+* Added type to source buttons in mep-feature-sourcechooser.js:48 [flamadiddle ]
+* Fix use of inArray and $ in src/js/me-shim.js [lftl, Seb33300, eusonic and others] (this was a regression bug from another fix)
+* Fixing syntax error in events demo [JeffreyATW]
+
+*2.9.2 (2012/07/06) *
+
+* Added a few height checks (from Joe Anderson)
+* Removed console.log statements
+* Better file MIME type detection when the "type" attribute is not set (Seb33300)
+* Pass the event keyCode to the keyActions handler, and make seek interval configurable (bborn)
+* Responsive flash fix, YouTube edits (heikki)
+* New `auto_plugin` mode that starts with plugins then tries HTML5 (savil)
+
+*2.9.1 (2012/06/01)*
+
+* Fixed Firefox 10+ Fullscreen error
+
+*2.9.0 (2012/05/31)*
+
+* Fixed pointer-events detection in IE9 (when using Flash mode or YouTube)
+* YouTube now shows annotations (using YouTube player rather than chromeless)
+* Fix play/pause when clicking on video when overlays are displayed [markomarkovic]
+* Dont listen to mouse events when there's not a reason to [neverarriving]
+* Adding CSS animated buffer to the time rail [neverarriving]
+* Fix for box-sizing: border-box from cutting off time text. [MatthewCallis]
+
+*2.8.2 (2012/05/15)*
+
+* Fixed volume slider bug when initially hidden
+* Fixed YouTube size problems in Flash mode
+
+*2.8.1 (2012/04/19)*
+
+* Flash fullscreen: video not fullsized
+* Flash fullscreen: youtube controls not working
+
+*2.8.0 (2012/04/17)*
+
+* Revamped YouTube to work using the Flash shim so that it supports fullscreen
+* Fix for `remove()` method (lennym)
+* Fix possible issue with ContextMenu ( quangvhg)
+* Fix for stop button ( slavva97)
+* Type on `var` and `;` (lennym)
+* Fix for keyboard support forward and backward (myffical)
+
+*2.7.0 (2012/03/12)*
+
+* Added horizontal volume control, the new default for audio (based on work by [gavinlynch](http://github.com/gavinlynch))
+* Possible issues with &lt; IE8 centering resolved
+* Full set of controls under Silverlight ([Birol2010](https://github.com/Birol2010/))
+* YouTube fix [raknam]
+* shim now has a .tagName property, and other DOM-like methods [tantalic]
+* Poster display fix when HTML5, Flash, and Silverlight are all missing [bruha]
+* Source Chooser plugin [markomarkovic]
+* Fix for flash audio mute [lbernau]
+
+*2.6.5 (2012/02/01)*
+
+* Removed iOS 3.x poster code [xtat] [James Cross]
+* Fixed bug when player is initially hidden in `display:none;`
+* Workaround for when inside an `<iframe>` and Chrome doesn't correctly report exiting from fullscreen
+
+*2.6.4 (2012/01/10)*
+
+* Fixed a Flash bug when one video ended and another was loaded through `setSrc()` and `load()`
+* Option for markup between current time and duration [tantalic]
+
+*2.6.3 (2012/01/08)*
+
+* Sending all options to Flash including colors
+
+*2.6.2 (2012/01/06)*
+
+* Fixed Flash fullscreen button inside an `<iframe>`
+* Fixed flash auto starting in 100% mode
+
+*2.6.1 (2012/01/03)*
+
+* Updated Opera's Flash Fullscreen support (apparently, it doesn't like pointer-events:none with Flash)
+* Added a `fullscreenchange` event to Flash to better track events
+
+*2.6.0 (2011/12/27)*
+
+* added major updates to Flash fullscreen mode controls [rmhall]
+* added sneaky `pointer-events: none` to allow Flash to enter fullscreen in one clean click
+* added missing CSS3 gradients syntaxes (kristerkari)[https://github.com/johndyer/mediaelement/pull/339]
+* added check for left offset to detect when mousedrag exceeds top boundary [jmcneese](https://github.com/johndyer/mediaelement/pull/335)
+
+*2.5.0 (2011/12/15) - 56kb*
+
+* Flash fullscreen now works on hover, so it's much easier to use. For Firefox it's always on, but for others `usePluginFullScreen:true` option
+* For the audio player, Flash objects are positioned outside the main `<div>` which allows the player to be hidden without breaking flash
+* Volume controls was adjusted slightly
+* Removed Google translate features (Google killed the API)
+
+*2.4.3 (2011/12/10)*
+
+* keyboard controls are now an array, allowing multiple keys to do the same thing
+* support for Google TV keybuttons (based on above)
+* arrow keys now move when paused
+* floating time is now handled via JavaScript instead of CSS :hover (and removed from touch devices)
+
+*2.4.2 (2011/12/06) - 57.3kb*
+
+* keyboard controls (up/down controls volume, left/right seeks, space play/pause, f goes fullscreen)
+* `<audio>` now works with 100% for responsive layouts [283](https://github.com/johndyer/mediaelement/issues/283)
+* Support for auto start with class `mejs-player` and `data-mejsoptions` e.g. `<video src="media.mp4" class="mejs-player" data-mejsoptions='{"features":["playpause","progress","volume"}, "success": "myCallback"}'><video>`
+* With multiple players on a page, when one starts the others pause (toggle `pauseOtherPlayers: true`) [285](https://github.com/johndyer/mediaelement/issues/285)
+
+*2.4.1 (2011/12/05) - 55.7kb*
+
+* Fixed fullscreen bug with Firefox (with Video for Everybody syntax) [270](https://github.com/johndyer/mediaelement/issues/270)
+* Added `remove()` method to `MediaElement` and `MediaElementPlayer` to safely remove Flash (from IE) [111](https://github.com/johndyer/mediaelement/issues/111)
+* Added a demo of MEJS skins to the /demo/ folder
+* Closed issue with `ended` event in Flash (my example works) [246](https://github.com/johndyer/mediaelement/issues/246)
+* Flash has better support for `preload="auto"` [290](https://github.com/johndyer/mediaelement/issues/290)
+
+*2.4.0 (2011/11/28) - 54.9kb*
+
+* Integration with YouTube API (and intial support for Vimeo API) : http://mediaelementjs.com/examples/?name=youtube
+* Catch when Google Translate fails due to API limits
+
+*2.3.3 (2011/11/21) - 49.4kb*
+
+* removed volume controls for touch devices (Android and iOS require hardware volume)
+* set a timeout to hide controls on touch devices
+* fixed timecode bug with :09 (used radix)
+* fixed bug when long videos end: (try/catch)
+* fixed issue with `alwaysShowControls`
+* removed a `console.log` in fullscreen that broke IE
+
+*2.3.2 (2011/11/12) 49.6kb*
+
+* removed `http` from Flash and Silverlight embeds to support SSL
+* fixed a possible bug when neither `src` nor `type` was specified
+* turned off useCapture for a few events
+
+*2.3.1 (2011/11/07)*
+
+* Another set of changes to handle various browser native fullscreen issues
+* New control behavior for touch enabled devices (iPad, Android tablets)
+* Bug fix for Flash (bradleyboy)
+
+*2.3.0 (2011/11/01) - 48.5kb*
+
+* Fixed bug when fullscreen was called before play pressed
+* Additional classes mejs-audio, mejs-video, mejs-ios, mejs-iphone, mejs-ipad, mejs-android added to contianing `<div>` for styles
+* IE9 can't use `<video width="100%">` so you must use either options ({videoHeight:'100%'}) or inline style `<video style="width:100%;height:100%;">`
+* updated fullscreen code for Safari (erktime)
+* loading indicators shows during 'waiting' event
+* iOS and Android now show "big play" button again (sometimes overlaps on iPhone)
+
+*2.2.5 (2011/10/14)*
+
+* fix for Flash fallback in certain scenarios (IE RegExp problem, Firefox fullscreen Flash issue)
+* adjustments for floating time indicator
+
+*2.2.4 (2011/10/10)*
+
+* True FullScreen support in Firefox (nightly) and Chrome (Canary)
+* more updates for 100% mode
+* enableContextMenu(), disableContextMenu() methods
+* change to poster code to let it be set later
+
+*2.2.3 (2011/10/07b) - 45.8kb*
+
+* updated accessibility again for JAWS and NVDA (thanks to twitter.com/mohammed0204)
+* added CSS class `<html class="mejs-embed">` for `<iframe>` embeds
+
+*2.2.2 (2011/10/07) - 45.8kb*
+
+* added support for <del>`<video width="100%" height="100%"></video>`</del> `<video style="width:100%;height:100%"></video>` (i.e. responsive/adaptive players)
+* added :focus state for buttons to improve accessibility
+* added title and aria-controls attributes to buttons to improve accessibility
+* changed when loading circle appears (WebKit fires the 'loadstart' event differently than FF or IE)
+
+*2.2.1 (2011/10/06) - 44.1kb*
+
+* fixed a bug with fullscreen that caused IE to completely mess up it layout
+* fixed another bug with fullscreen and z-index
+
+*2.2.0 (2011/10/04)*
+
+* controls now display on iPad, iPhone, and Android. Can be turned off using (iPadForceNativeControls:true)
+* fullscreen support for iPad (different from true fullscreen on Safari 5.1)
+* added frameaccurate timecode (via gselva)
+* added contextmenu as a feature. if turned on the default includes: fullscreen toggle, mute toggle, and media download
+* updated WebVTT support (still had some SRT formatting restrictions)
+* dynamic player creation: from `<a href="media.mp4">video</a>` and `<div class="mejs"></div>` specifying type (string or array)
+* Fixed bug where Flash couldn't go fullscreen with track chapters
+* fixed a bug with Flash fullscreen ratios
+* controls now disappear on timeout when mouse is idle (useful for fullscreen)
+* enableControls() and disableControls() (for pre/post roll scenarios)
+* added an autoplay override (especially for WebKit browsers)
+* fixed functionality of mute toggling
+* reorganized plugins to use $.extend
+* updating functionality of loading graphic to account for various browser inconsistencies (loadstart event)
+
+*2.1.9 (2011/08/04) - 36.9kb*
+
+* fixed Android 2.1 and 2.2 playing problems (still need a good 2.3 and 3.0 device. hint. hint.)
+
+*2.1.8 (2011/08/03) - 36.9kb*
+
+* True fullscreen for Safari 5.1
+* Flash/Silverlight fullscreen is now "full window" (except for Firefox which cannot handle adjusting Flash without reloading it)
+
+*2.1.7 (2011/07/19) - 35.9kb*
+
+* fixed mute button (kaichen)
+* added alwaysShowControls option (kaichen)
+* forceful padding override on buttons
+* started "ender" branch to experiment with removing jQuery dependency and baking in ender.js
+* updated the use of `type` javascript option with src is present
+* remove preload="none" hack for Chrome now that it supports it (note: Chrome still strangely fires a 'loadstart' event)
+* added hooks for other jQuery compatible libraries like [ender.js](http://enderjs.com)
+* Wordpress: if you don't specify a file extension, mejs will look for attached files and use them [video src="/wp-content/uploads/myfile"]
+* Wordpress: option to select a 'skin'
+* Wordpress: option to select audio width/height
+
+*2.1.6 (2011/06/14) - 35.5kb*
+
+* fix errors when the progress bar isn't present
+* buttons are now actual `<button>` tags which allows tabbed controls (for better accessibility and possible ARIA support)
+* fix problems with low volume in Flash on startup (startVolume was sometimes 0!)
+* updated a few places to use jQuery 1.6's new prop/attr methods
+* updated skins to account for new `<button>` (still need highlighted style)
+
+*2.1.5 (2011/05/28) - 35.2kb*
+
+* minor fix for controls not showing time or duration
+* when switching files, the Flash plugin now forcibly stops downliading
+
+*2.1.4 (2011/05/20) - 35.2kb*
+
+* fixed display of hours
+* fixed Flash audio bug where pausing when the file wasn't fully loaded would cause the progress bar to go offscreen
+* fixed Flash video bug where percent loaded was always 100%
+* fixed Flash audio bug where pressing pause, then play would always restart playback from the beginning
+* startVolume works more clearly in plugins (esp. Opera and Linux)
+* tracks support no longer refers to WebSRT, but is more generic for WebVTT (not all features of WebVTT are supported yet)
+* fixed fullscreen in Safari OS X 10.5 (which doens't really support true fullscreen)
+* Flash and Silverlight can now start downloading if preload="auto" or preload="metadata" (warning: preload="metadata" will load the entire thing)
+
+*2.1.3 (2011/04/12) - 35.8kb*
+
+* added support for hours in time format (00:00:00) and an alwaysShowHours option to force hours to always show
+* removed some duplicate flash events
+* added 'seeking' event to Flash/SL (already had 'seeked')
+
+*2.1.2 (2011/03/23) - 34.4kb*
+
+* fixed IE6 and IE7 caption position
+* fixed IE7 failure in certain places
+* changed browser UA detection to use only lowercase (iPhone iphone)
+* fixed Flash audio loaded bug (reporting 0 after loaded)
+* added removeEventListener to shims
+* new rail-resizing code
+
+*2.1.1 (2011/03/07) - 33.5kb*
+
+* added 'loadeddata' event to Flash and Silverlight
+* switched to flashvars parameter to support Apache's mod_security
+* better flash fullscreen support
+* added flv-x to flash's accepted types
+* Fixed a bug in poster sizing (only affected IE)
+* added "isFullScreen" property to media objects (like Safari's webkitDisplayingFullscreen)
+* controls start hidden with autoplay
+* fixed iOS loading issues (success wasn't firing, other errors)
+* fixed IE6 when using new MediaElementPlayer(), rather than jQuery
+
+*2.1.0 (2011/02/23) - 32.9kb*
+
+* Updated control styles for a cleaner look
+* Added loadeddata and canplay events to Flash and Silverlight
+* Added loading indicator to MediaElementPlayer
+* Added stop button (pause, then return to currentTime:0)
+* IE6/7 CSS updates
+* Poster is now forced to the size of the player (could be updated to be proportional if someone wants to add that)
+* Updated Flash ended event to account for buffering weirdness
+* Fixed a track text hovering problem
+
+*2.0.7 (2011/02/13) - 31.9kb*
+
+* Added 'mode' option to force native (HTML5) or shim (Flash,Silverlight) modes
+* Fixed audio seeking bug in Flash (thanks Andy!)
+* Fixed startVolume not working in Flash
+* Overrided Chrome's autoplay since it doesn't always work
+
+*2.0.6 (2011/02/04) - 31.7kb*
+
+* Whitespace cleanup on files
+* Preventing flash/sl plugins from reinitializing when they are removed by another script
+* Fixed IE JavaScript errors in Flash fallback (seen in Wordpress)
+* Added 'play' event to Silverlight to prevent errors
+
+*2.0.5 (2011/01/25) - 31.7kb*
+
+* Added error object to player
+* Adjusted popup timer and progress bar
+* Fixed media URL escaping
+* Stopped sending poster to plugin
+* Silverlight culture update
+* Added back reference check (also makes jQuery usage easier)
+* Added stop() function to mediaelement
+* timerupdate still fires when paused (plugins)
+* Added Security.allowDomain("*") to Flash so it can be used on different domains
+* Fixed progress bar for Firefox 3 with Ogg files
+* Prevented Flash from re-creating the player when show/hide restarts it
+* Fixed initial volume level in non-HTML5 players
+* Made PNG8 versions of controls images (for IE6)
+
+*2.0.4 (2011/01/14) - 31.2kb*
+
+* Fixed a major bug in plugin detection.
+
+*2.0.3 (2011/01/13) - 31.2kb*
+
+* changed IE Flash insertion to include me-plugin CSS class
+* changed player error handling
+* fixed a bug in the Silverlight player related to URLs
+
+*2.0.2 (2010/12/31) - 31.1kb*
+
+* Changed HTML escape method to encodeURICompnent
+* Flash-based RMTP support (contributor: sylvinus)
+* Fixed Wordpress loop bug
+* Changed time popup to move with mouse instead of currentTime
+* added enablePluginSmoothing (Flash)
+* Added some "play" "playing" event duplication to Flash
+
+*2.0.1 (2010/12/20) - XX.Xkb*
+
+* Changed Flash to allow cross domain video
+* Added 'click' event to Flash and Silverlight
+* Updated autoplay attribute detection
+
+*2.0.0 (2010/12/13) - 30.8kb*
+
+* Reorganized MediaElementPlayer code to allow each button to become a pluggable feature that can be removed or overrided
+* Enabled a no JavaScript version to support Video for Everybody nested syntax (optional)
+* Enabled drag on progress bar
+* Preload="none" is default for Flash and Silverlight
+* Preload="none" enabled on Google Chrome
+* Added skins to download
+* Support for skin swapping
+* Updated volume handle controls
+* Update progress controls display
+* Exposed MediaElement API methods on player
+* Adjusted layout for IE6
+
+*1.1.7 (2010/11/29) - 29.8kb*
+
+* Fixed bug with `<track>` loading on `<audio>` player
+
+*1.1.6 (2010/11/23) - 29.8kb*
+
+* Chapters support `<track kind="chapters" />`
+
+*1.1.5 (2010/11/21) - 29.8kb*
+
+* Workaround for IE issues when accidentally placed inside `<p>` tag
+* Fixed silverlight pause state reporting
+* Switched back to Flash as default
+* Removed requirement for Google translate API `<script>` (direct JSONP call)
+* Added googleApiKey option
+
+*1.1.4 (2010/11/21) - 29.5kb*
+
+* Added Default volume level to options (0.8)
+* Fix for IE volume slider positioning
+* Fix for IE tracks parsing (replacement String.split)
+* Changed namespace from html5 to mejs
+* Remove all showMessage references
+* Controls show again after playback ends
+
+*1.1.3 (2010/11/20) - 29.0kb*
+
+* Change to fallback mechanism and styling (Windows Phone 7)
+
+*1.1.2 (2010/11/19) - 28.9kb*
+
+* Removed messages, added big play button
+* Google translate now supports more than 1000 characters
+* Added a dropdownlist of languages from which the user can select
+* Added timerUpdate option to set the millisecond speed of timeupdate events
+* Updated the media file and examples
+
+*1.1.1 (2010/11/18) - 27.1kb*
+
+* added captioning support via the `<track>` tag (thanks to [Playr](http://www.delphiki.com/html5/playr) for the example)
+* added auto-translation support via Google translate API
+
+*1.1.0 (2010/11/17) - 22.6kb*
+
+* Total re-oganization of MediaElement, MediaElementPlayer, and supporting objects
+* Updated CSS to a cleaner look, with better IE support & big play button
+* Simplified all plugin and version detection
+* Added loop option (useful for audio files)
+* Added the ability to turn each control button on/off
+* Added canPlayType to PluginMediaElement
+* Updated setSrc to take multiple sources
+
+*1.0.7 (2010/11/16) - 18.15kb*
+
+* Total re-oganization of MediaElement code
+* JSLint compliant, YUI compliant
+
+*1.0.6 (2010/11/15) - 17.96kb*
+
+* Rebuilt PluginDetection (removed SWFObject and Microsoft code)
+* More JSLint compatible (still a few iterations to get there)
+* Added jQuery 1.4.4
+
+*1.0.5 (2010/11/10 later on)*
+
+* Fixed a problem with the *.min.js files
+* Added jQuery 1.4.3
+
+*1.0.4 (2010/11/10) - 18.32kb*
+
+* Fixed Flash display when `<video>` did not match actual dimensions
+* autosizing in Flash and Silverlight
+* added options for defaultVideoWidth, defaultVideoHeight when `<video>` `height` and `width` are not set
+* included minified versions using YUI compressor
+
+*1.0.3 (2010/09/24)*
+
+* changes in poster handling
+* fix IE9 startup bug (its 'play' event fires wrongly it seems)
+* fixed Flock, Opera sizing bugs
+* fixed audio ended bug in special cases under Flash
+* added default height/width when they are not specified in attributes
+
+*1.0.2 (2010/09/17)*
+
+* minor updates to support IE9 beta1
+
+*1.0.1 (2010/09/13)*
+
+* added native fullscreen support for Safari 5 (via webkitEnterFullScreen)
+
+*1.0.0 (2010/08/09)*
+
+* initial release
+
+###TODO
+
+2.x features
+* HTML5 error handling
+* Flash/SL error codes
+* Postroll
+* Flash StageVideo?
diff --git a/debian/missing-sources/mediaelement/src/FlashMediaElement.as b/debian/missing-sources/mediaelement/src/FlashMediaElement.as
new file mode 100644
index 0000000..2bc82ab
--- /dev/null
+++ b/debian/missing-sources/mediaelement/src/FlashMediaElement.as
@@ -0,0 +1,1080 @@
+package
+{
+ import flash.display.*;
+ import flash.events.*;
+ import flash.media.*;
+ import flash.net.*;
+ import flash.text.*;
+ import flash.system.*;
+
+ import flash.media.Video;
+ import flash.net.NetConnection;
+ import flash.net.NetStream;
+
+ import flash.geom.ColorTransform;
+
+ import flash.filters.DropShadowFilter;
+ import flash.utils.Timer;
+ import flash.external.ExternalInterface;
+ import flash.geom.Rectangle;
+
+ import htmlelements.IMediaElement;
+ import htmlelements.VideoElement;
+ import htmlelements.AudioElement;
+ import htmlelements.YouTubeElement;
+
+ public class FlashMediaElement extends MovieClip {
+
+ private var _mediaUrl:String;
+ private var _autoplay:Boolean;
+ private var _preload:String;
+ private var _debug:Boolean;
+ private var _isVideo:Boolean;
+ private var _video:DisplayObject;
+ private var _timerRate:Number;
+ private var _stageWidth:Number;
+ private var _stageHeight:Number;
+ private var _enableSmoothing:Boolean;
+ private var _allowedPluginDomain:String;
+ private var _isFullScreen:Boolean = false;
+ private var _startVolume:Number;
+ private var _controlStyle:String;
+ private var _autoHide:Boolean = true;
+ private var _streamer:String = "";
+ private var _enablePseudoStreaming:Boolean;
+ private var _pseudoStreamingStartQueryParam:String;
+
+ // native video size (from meta data)
+ private var _nativeVideoWidth:Number = 0;
+ private var _nativeVideoHeight:Number = 0;
+
+ // visual elements
+ private var _output:TextField;
+ private var _fullscreenButton:SimpleButton;
+
+ // media
+ private var _mediaElement:IMediaElement;
+
+ // connection to fullscreen
+ private var _connection:LocalConnection;
+ private var _connectionName:String;
+
+ //private var fullscreen_btn:SimpleButton;
+
+ // CONTROLS
+ private var _alwaysShowControls:Boolean;
+ private var _controlBar:MovieClip;
+ private var _controlBarBg:MovieClip;
+ private var _scrubBar:MovieClip;
+ private var _scrubTrack:MovieClip;
+ private var _scrubOverlay:MovieClip;
+ private var _scrubLoaded:MovieClip;
+ private var _hoverTime:MovieClip;
+ private var _hoverTimeText:TextField;
+ private var _playButton:SimpleButton;
+ private var _pauseButton:SimpleButton;
+ private var _duration:TextField;
+ private var _currentTime:TextField;
+ private var _fullscreenIcon:SimpleButton;
+ private var _volumeMuted:SimpleButton;
+ private var _volumeUnMuted:SimpleButton;
+ private var _scrubTrackColor:String;
+ private var _scrubBarColor:String;
+ private var _scrubLoadedColor:String;
+
+ // IDLE Timer for mouse for showing/hiding controls
+ private var _inactiveTime:int;
+ private var _timer:Timer;
+ private var _idleTime:int;
+ private var _isMouseActive:Boolean
+ private var _isOverStage:Boolean = false;
+
+ // security checkes
+ private var securityIssue:Boolean = false; // When SWF parameters contain illegal characters
+ private var directAccess:Boolean = false; // When SWF visited directly with no parameters (or when security issue detected)
+
+
+ public function FlashMediaElement() {
+ // check for security issues (borrowed from jPLayer)
+ checkFlashVars(loaderInfo.parameters);
+
+ // allows this player to be called from a different domain than the HTML page hosting the player
+ //Security.allowDomain("*");
+ //Security.allowInsecureDomain('*');
+
+
+ // add debug output
+ _output = new TextField();
+ _output.textColor = 0xeeeeee;
+ _output.width = stage.stageWidth - 100;
+ _output.height = stage.stageHeight;
+ _output.multiline = true;
+ _output.wordWrap = true;
+ _output.border = false;
+ _output.filters = [new DropShadowFilter(1, 0x000000, 45, 1, 2, 2, 1)];
+
+ _output.text = "Initializing...\n";
+ addChild(_output);
+ _output.visible = securityIssue;
+
+ if (securityIssue) {
+ _output.text = "WARNING: Security issue detected. Player stopped.";
+ return;
+ }
+
+ // get parameters
+ // Use only FlashVars, ignore QueryString
+ var params:Object, pos:int, query:Object;
+
+ params = LoaderInfo(this.root.loaderInfo).parameters;
+ pos = root.loaderInfo.url.indexOf('?');
+ if (pos !== -1) {
+ query = parseStr(root.loaderInfo.url.substr(pos + 1));
+
+ for (var key:String in params) {
+ if (query.hasOwnProperty(trim(key))) {
+ delete params[key];
+ }
+ }
+ }
+
+ _mediaUrl = (params['file'] != undefined) ? String(params['file']) : "";
+ _autoplay = (params['autoplay'] != undefined) ? (String(params['autoplay']) == "true") : false;
+ _debug = (params['debug'] != undefined) ? (String(params['debug']) == "true") : false;
+ _isVideo = (params['isvideo'] != undefined) ? ((String(params['isvideo']) == "false") ? false : true ) : true;
+ _timerRate = (params['timerrate'] != undefined) ? (parseInt(params['timerrate'], 10)) : 250;
+ _alwaysShowControls = (params['controls'] != undefined) ? (String(params['controls']) == "true") : false;
+ _enableSmoothing = (params['smoothing'] != undefined) ? (String(params['smoothing']) == "true") : false;
+ _startVolume = (params['startvolume'] != undefined) ? (parseFloat(params['startvolume'])) : 0.8;
+ _preload = (params['preload'] != undefined) ? params['preload'] : "none";
+ _controlStyle = (params['controlstyle'] != undefined) ? (String(params['controlstyle'])) : ""; // blank or "floating"
+ _autoHide = (params['autohide'] != undefined) ? (String(params['autohide'])) : true;
+ _scrubTrackColor = (params['scrubtrackcolor'] != undefined) ? (String(params['scrubtrackcolor'])) : "0x333333";
+ _scrubBarColor = (params['scrubbarcolor'] != undefined) ? (String(params['scrubbarcolor'])) : "0xefefef";
+ _scrubLoadedColor = (params['scrubloadedcolor'] != undefined) ? (String(params['scrubloadedcolor'])) : "0x3CACC8";
+ _enablePseudoStreaming = (params['pseudostreaming'] != undefined) ? (String(params['pseudostreaming']) == "true") : false;
+ _pseudoStreamingStartQueryParam = (params['pseudostreamstart'] != undefined) ? (String(params['pseudostreamstart'])) : "start";
+ _streamer = (params['flashstreamer'] != undefined) ? (String(params['flashstreamer'])) : "";
+
+ _output.visible = _debug;
+
+ if (isNaN(_timerRate))
+ _timerRate = 250;
+
+ // setup stage and player sizes/scales
+ stage.align = StageAlign.TOP_LEFT;
+ stage.scaleMode = StageScaleMode.NO_SCALE;
+ _stageWidth = stage.stageWidth;
+ _stageHeight = stage.stageHeight;
+
+ //_autoplay = true;
+ //_mediaUrl = "http://mediafiles.dts.edu/chapel/mp4/20100609.mp4";
+ //_alwaysShowControls = true;
+ //_mediaUrl = "../media/Parades-PastLives.mp3";
+ //_mediaUrl = "../media/echo-hereweare.mp4";
+
+ //_mediaUrl = "http://video.ted.com/talks/podcast/AlGore_2006_480.mp4";
+ //_mediaUrl = "rtmp://stream2.france24.yacast.net/france24_live/en/f24_liveen";
+
+ //_mediaUrl = "http://www.youtube.com/watch?feature=player_embedded&v=yyWWXSwtPP0"; // hosea
+ //_mediaUrl = "http://www.youtube.com/watch?feature=player_embedded&v=m5VDDJlsD6I"; // railer with notes
+
+ //_alwaysShowControls = true;
+
+ //_debug=true;
+
+
+
+
+ // position and hide
+ _fullscreenButton = getChildByName("fullscreen_btn") as SimpleButton;
+ //_fullscreenButton.visible = false;
+ _fullscreenButton.alpha = 0;
+ _fullscreenButton.addEventListener(MouseEvent.CLICK, fullscreenClick, false);
+ _fullscreenButton.x = stage.stageWidth - _fullscreenButton.width;
+ _fullscreenButton.y = stage.stageHeight - _fullscreenButton.height;
+
+
+ // create media element
+ if (_isVideo) {
+
+ if (_mediaUrl.indexOf("youtube.com") > -1 || _mediaUrl.indexOf("youtu.be") > -1) {
+
+ //Security.allowDomain("http://www.youtube.com");
+
+ _mediaElement = new YouTubeElement(this, _autoplay, _preload, _timerRate, _startVolume);
+ _video = (_mediaElement as YouTubeElement).player;
+
+ // these are set and then used once the player is loaded
+ (_mediaElement as YouTubeElement).initWidth = _stageWidth;
+ (_mediaElement as YouTubeElement).initHeight = _stageHeight;
+
+ } else {
+
+ _mediaElement = new VideoElement(this, _autoplay, _preload, _timerRate, _startVolume, _streamer);
+ _video = (_mediaElement as VideoElement).video;
+ _video.width = _stageWidth;
+ _video.height = _stageHeight;
+ (_video as Video).smoothing = _enableSmoothing;
+ (_mediaElement as VideoElement).setReference(this);
+ (_mediaElement as VideoElement).setPseudoStreaming(_enablePseudoStreaming);
+ (_mediaElement as VideoElement).setPseudoStreamingStartParam(_pseudoStreamingStartQueryParam);
+ //_video.scaleMode = VideoScaleMode.MAINTAIN_ASPECT_RATIO;
+ addChild(_video);
+ }
+ } else {
+
+ //var player2:AudioDecoder = new com.automatastudios.audio.audiodecoder.AudioDecoder();
+ _mediaElement = new AudioElement(this, _autoplay, _preload, _timerRate, _startVolume);
+ }
+
+
+ // controls!
+ _controlBar = getChildByName("controls_mc") as MovieClip;
+ _controlBarBg = _controlBar.getChildByName("controls_bg_mc") as MovieClip;
+ _scrubTrack = _controlBar.getChildByName("scrubTrack") as MovieClip;
+ _scrubBar = _controlBar.getChildByName("scrubBar") as MovieClip;
+ _scrubOverlay = _controlBar.getChildByName("scrubOverlay") as MovieClip;
+ _scrubLoaded = _controlBar.getChildByName("scrubLoaded") as MovieClip;
+
+ _scrubOverlay.buttonMode = true;
+ _scrubOverlay.useHandCursor = true
+
+ applyColor(_scrubTrack, _scrubTrackColor);
+ applyColor(_scrubBar, _scrubBarColor);
+ applyColor(_scrubLoaded, _scrubLoadedColor);
+
+ _fullscreenIcon = _controlBar.getChildByName("fullscreenIcon") as SimpleButton;
+
+ // New fullscreenIcon for new fullscreen floating controls
+ //if(_alwaysShowControls && _controlStyle.toUpperCase()=="FLOATING") {
+ _fullscreenIcon.addEventListener(MouseEvent.CLICK, fullScreenIconClick, false);
+ //}
+
+ _volumeMuted = _controlBar.getChildByName("muted_mc") as SimpleButton;
+ _volumeUnMuted = _controlBar.getChildByName("unmuted_mc") as SimpleButton;
+
+ _volumeMuted.addEventListener(MouseEvent.CLICK, toggleVolume, false);
+ _volumeUnMuted.addEventListener(MouseEvent.CLICK, toggleVolume, false);
+
+ _playButton = _controlBar.getChildByName("play_btn") as SimpleButton;
+ _playButton.addEventListener(MouseEvent.CLICK, function(e:MouseEvent) {
+ _mediaElement.play();
+ });
+ _pauseButton = _controlBar.getChildByName("pause_btn") as SimpleButton;
+ _pauseButton.addEventListener(MouseEvent.CLICK, function(e:MouseEvent) {
+ _mediaElement.pause();
+ });
+ _pauseButton.visible = false;
+ _duration = _controlBar.getChildByName("duration_txt") as TextField;
+ _currentTime = _controlBar.getChildByName("currentTime_txt") as TextField;
+ _hoverTime = _controlBar.getChildByName("hoverTime") as MovieClip;
+ _hoverTimeText = _hoverTime.getChildByName("hoverTime_txt") as TextField;
+ _hoverTime.visible=false;
+ _hoverTime.y=(_hoverTime.height/2)+1;
+ _hoverTime.x=0;
+
+
+
+ // Add new timeline scrubber events
+ _scrubOverlay.addEventListener(MouseEvent.MOUSE_MOVE, scrubMove);
+ _scrubOverlay.addEventListener(MouseEvent.CLICK, scrubClick);
+ _scrubOverlay.addEventListener(MouseEvent.MOUSE_OVER, scrubOver);
+ _scrubOverlay.addEventListener(MouseEvent.MOUSE_OUT, scrubOut);
+
+ if (_autoHide) { // && _alwaysShowControls) {
+ // Add mouse activity for show/hide of controls
+ stage.addEventListener(Event.MOUSE_LEAVE, mouseActivityLeave);
+ stage.addEventListener(MouseEvent.MOUSE_MOVE, mouseActivityMove);
+ _inactiveTime = 2500;
+ _timer = new Timer(_inactiveTime)
+ _timer.addEventListener(TimerEvent.TIMER, idleTimer);
+ _timer.start();
+ // set
+ }
+
+ if(_startVolume<=0) {
+ trace("INITIAL VOLUME: "+_startVolume+" MUTED");
+ _volumeMuted.visible=true;
+ _volumeUnMuted.visible=false;
+ } else {
+ trace("INITIAL VOLUME: "+_startVolume+" UNMUTED");
+ _volumeMuted.visible=false;
+ _volumeUnMuted.visible=true;
+ }
+
+ _controlBar.visible = _alwaysShowControls;
+
+ setControlDepth();
+
+ _output.appendText("stage: " + stage.stageWidth + "x" + stage.stageHeight + "\n");
+ _output.appendText("file: " + _mediaUrl + "\n");
+ _output.appendText("autoplay: " + _autoplay.toString() + "\n");
+ _output.appendText("preload: " + _preload.toString() + "\n");
+ _output.appendText("isvideo: " + _isVideo.toString() + "\n");
+ _output.appendText("smoothing: " + _enableSmoothing.toString() + "\n");
+ _output.appendText("timerrate: " + _timerRate.toString() + "\n");
+ _output.appendText("displayState: " +(stage.hasOwnProperty("displayState")).toString() + "\n");
+
+ // attach javascript
+ _output.appendText("ExternalInterface.available: " + ExternalInterface.available.toString() + "\n");
+ _output.appendText("ExternalInterface.objectID: " + ((ExternalInterface.objectID != null)? ExternalInterface.objectID.toString() : "null") + "\n");
+
+ if (_mediaUrl != "") {
+ _mediaElement.setSrc(_mediaUrl);
+ }
+
+ positionControls();
+
+ // Fire this once just to set the width on some dynamically sized scrub bar items;
+ _scrubBar.scaleX=0;
+ _scrubLoaded.scaleX=0;
+
+
+ if (ExternalInterface.available) { // && !_alwaysShowControls
+
+ _output.appendText("Adding callbacks...\n");
+ try {
+ if (ExternalInterface.objectID != null && ExternalInterface.objectID.toString() != "") {
+
+ // add HTML media methods
+ ExternalInterface.addCallback("playMedia", playMedia);
+ ExternalInterface.addCallback("loadMedia", loadMedia);
+ ExternalInterface.addCallback("pauseMedia", pauseMedia);
+ ExternalInterface.addCallback("stopMedia", stopMedia);
+
+ ExternalInterface.addCallback("setSrc", setSrc);
+ ExternalInterface.addCallback("setCurrentTime", setCurrentTime);
+ ExternalInterface.addCallback("setVolume", setVolume);
+ ExternalInterface.addCallback("setMuted", setMuted);
+
+ ExternalInterface.addCallback("setFullscreen", setFullscreen);
+ ExternalInterface.addCallback("setVideoSize", setVideoSize);
+
+ ExternalInterface.addCallback("positionFullscreenButton", positionFullscreenButton);
+ ExternalInterface.addCallback("hideFullscreenButton", hideFullscreenButton);
+
+ // fire init method
+ ExternalInterface.call("mejs.MediaPluginBridge.initPlugin", ExternalInterface.objectID);
+ }
+
+ _output.appendText("Success...\n");
+
+ } catch (error:SecurityError) {
+ _output.appendText("A SecurityError occurred: " + error.message + "\n");
+ } catch (error:Error) {
+ _output.appendText("An Error occurred: " + error.message + "\n");
+ }
+
+ }
+
+ if (_preload != "none") {
+ _mediaElement.load();
+
+ if (_autoplay) {
+ _mediaElement.play();
+ }
+ } else if (_autoplay) {
+ _mediaElement.load();
+ _mediaElement.play();
+ }
+
+ // listen for resize
+ stage.addEventListener(Event.RESIZE, resizeHandler);
+
+ // send click events up to javascript
+ stage.addEventListener(MouseEvent.CLICK, stageClicked);
+
+ // resize
+ stage.addEventListener(FullScreenEvent.FULL_SCREEN, stageFullScreenChanged);
+ }
+
+ public function setControlDepth():void {
+ // put these on top
+ addChild(_output);
+ addChild(_controlBar);
+ addChild(_fullscreenButton);
+
+ }
+
+ // borrowed from jPLayer
+ // https://github.com/happyworm/jPlayer/blob/e8ca190f7f972a6a421cb95f09e138720e40ed6d/actionscript/Jplayer.as#L228
+ private function checkFlashVars(p:Object):void {
+ var i:Number = 0;
+ for (var s:String in p) {
+ if (isIllegalChar(p[s], s === 'file')) {
+ securityIssue = true; // Illegal char found
+ }
+ i++;
+ }
+ if(i === 0 || securityIssue) {
+ directAccess = true;
+ }
+ }
+
+ private static function parseStr (str:String) : Object {
+ var hash:Object = {},
+ arr1:Array, arr2:Array;
+
+ str = unescape(str).replace(/\+/g, " ");
+
+ arr1 = str.split('&');
+ if (!arr1.length) {
+ return {};
+ }
+
+ for (var i:uint = 0, length:uint = arr1.length; i < length; i++) {
+ arr2 = arr1[i].split('=');
+ if (!arr2.length) {
+ continue;
+ }
+ hash[trim(arr2[0])] = trim(arr2[1]);
+ }
+ return hash;
+ }
+
+
+ private static function trim(str:String) : String {
+ if (!str) {
+ return str;
+ }
+
+ return str.toString().replace(/^\s*/, '').replace(/\s*$/, '');
+ }
+
+ private function isIllegalChar(s:String, isUrl:Boolean):Boolean {
+ var illegals:String = "' \" ( ) { } * + \\ < >";
+ if(isUrl) {
+ illegals = "\" { } \\ < >";
+ }
+ if(Boolean(s)) { // Otherwise exception if parameter null.
+ for each (var illegal:String in illegals.split(' ')) {
+ if(s.indexOf(illegal) >= 0) {
+ return true; // Illegal char found
+ }
+ }
+ }
+ return false;
+ }
+
+
+ // START: Controls and events
+ function mouseActivityMove(event:MouseEvent):void {
+
+ // if mouse is in the video area
+ if (_autoHide && (mouseX>=0 && mouseX<=stage.stageWidth) && (mouseY>=0 && mouseY<=stage.stageHeight)) {
+
+ // This could be move to a nice fade at some point...
+ _controlBar.visible = (_alwaysShowControls || _isFullScreen);
+ _isMouseActive = true;
+ _idleTime = 0;
+ _timer.reset();
+ _timer.start()
+ }
+ }
+
+ function mouseActivityLeave(event:Event):void {
+ if (_autoHide) {
+ _isOverStage = false;
+ // This could be move to a nice fade at some point...
+ _controlBar.visible = false;
+ _isMouseActive = false;
+ _idleTime = 0;
+ _timer.reset();
+ _timer.stop();
+ }
+ }
+
+ function idleTimer(event:TimerEvent):void {
+
+ if (_autoHide) {
+ // This could be move to a nice fade at some point...
+ _controlBar.visible = false;
+ _isMouseActive = false;
+ _idleTime += _inactiveTime;
+ _idleTime = 0;
+ _timer.reset();
+ _timer.stop();
+ }
+ }
+
+
+ function scrubMove(event:MouseEvent):void {
+
+ //if (_alwaysShowControls) {
+ if (_hoverTime.visible) {
+ var seekBarPosition:Number = ((event.localX / _scrubTrack.width) *_mediaElement.duration())*_scrubTrack.scaleX;
+ var hoverPos:Number = (seekBarPosition / _mediaElement.duration()) *_scrubTrack.scaleX;
+
+ if (_isFullScreen) {
+ _hoverTime.x=event.target.parent.mouseX;
+ } else {
+ _hoverTime.x=mouseX;
+ }
+ _hoverTime.y = _scrubBar.y - (_hoverTime.height/2);
+ _hoverTimeText.text = secondsToTimeCode(seekBarPosition);
+ }
+ //}
+ //trace(event);
+ }
+
+ function scrubOver(event:MouseEvent):void {
+ _hoverTime.y = _scrubBar.y-(_hoverTime.height/2)+1;
+ _hoverTime.visible = true;
+ trace(event);
+ }
+
+ function scrubOut(event:MouseEvent):void {
+ _hoverTime.y = _scrubBar.y+(_hoverTime.height/2)+1;
+ _hoverTime.visible = false;
+ //_hoverTime.x=0;
+ //trace(event);
+ }
+
+ function scrubClick(event:MouseEvent):void {
+ //trace(event);
+ var seekBarPosition:Number = ((event.localX / _scrubTrack.width) *_mediaElement.duration())*_scrubTrack.scaleX;
+
+ var tmp:Number = (_mediaElement.currentTime()/_mediaElement.duration())*_scrubTrack.width;
+ var canSeekToPosition:Boolean = _scrubLoaded.scaleX > (seekBarPosition / _mediaElement.duration()) *_scrubTrack.scaleX;
+ //var canSeekToPosition:Boolean = true;
+
+ /*
+ amountLoaded = ns.bytesLoaded / ns.bytesTotal;
+ loader.loadbar._width = amountLoaded * 208.9;
+ loader.scrub._x = ns.time / duration * 208.9;
+ */
+
+ trace("seekBarPosition:"+seekBarPosition, "CanSeekToPosition: "+canSeekToPosition);
+
+ if (seekBarPosition>0 && seekBarPosition<_mediaElement.duration() && canSeekToPosition) {
+ _mediaElement.setCurrentTime(seekBarPosition);
+ }
+ }
+
+ function toggleVolume(event:MouseEvent):void {
+ trace(event.currentTarget.name);
+ switch(event.currentTarget.name) {
+ case "muted_mc":
+ setMuted(false);
+ break;
+ case "unmuted_mc":
+ setMuted(true);
+ break;
+ }
+ }
+
+ function toggleVolumeIcons(volume:Number) {
+ if(volume<=0) {
+ _volumeMuted.visible = true;
+ _volumeUnMuted.visible = false;
+ } else {
+ _volumeMuted.visible = false;
+ _volumeUnMuted.visible = true;
+ }
+ }
+
+ public function positionControls(forced:Boolean=false) {
+
+
+ if ( _controlStyle.toUpperCase() == "FLOATING" && _isFullScreen) {
+
+ trace("CONTROLS: floating");
+ _hoverTime.y=(_hoverTime.height/2)+1;
+ _hoverTime.x=0;
+ _controlBarBg.width = 300;
+ _controlBarBg.height = 93;
+ //_controlBarBg.x = (stage.stageWidth/2) - (_controlBarBg.width/2);
+ //_controlBarBg.y = stage.stageHeight - 300;
+
+ _pauseButton.scaleX = _playButton.scaleX=3.5;
+ _pauseButton.scaleY= _playButton.scaleY=3.5;
+ // center the play button and make it big and at the top
+ _pauseButton.x = _playButton.x = (_controlBarBg.width/2)-(_playButton.width/2)+7;
+ _pauseButton.y = _playButton.y = _controlBarBg.height-_playButton.height-(14)
+
+ _controlBar.x = (stage.stageWidth/2) -150;
+ _controlBar.y = stage.stageHeight - _controlBar.height-100;
+
+
+ // reposition the time and duration items
+
+ _duration.x = _controlBarBg.width - _duration.width - 10;
+ _duration.y = _controlBarBg.height - _duration.height -7;
+ //_currentTime.x = _controlBarBg.width - _duration.width - 10 - _currentTime.width - 10;
+ _currentTime.x = 5
+ _currentTime.y= _controlBarBg.height - _currentTime.height-7;
+
+ _fullscreenIcon.x = _controlBarBg.width - _fullscreenIcon.width - 7;
+ _fullscreenIcon.y = 7;
+
+ _volumeMuted.x = _volumeUnMuted.x = 7;
+ _volumeMuted.y = _volumeUnMuted.y = 7;
+
+ _scrubLoaded.x = _scrubBar.x = _scrubOverlay.x = _scrubTrack.x =_currentTime.x+_currentTime.width+7;
+ _scrubLoaded.y = _scrubBar.y = _scrubOverlay.y = _scrubTrack.y=_controlBarBg.height-_scrubTrack.height-10;
+
+ _scrubBar.width = _scrubOverlay.width = _scrubTrack.width = (_duration.x-_duration.width-14);
+
+
+ } else {
+ trace("CONTROLS: normal, original");
+
+ /*
+ // Original style bottom display
+ _hoverTime.y=(_hoverTime.height/2)+1;
+ _hoverTime.x=0;
+ _controlBarBg.width = stage.stageWidth;
+ _controlBar.y = stage.stageHeight - _controlBar.height;
+ _duration.x = stage.stageWidth - _duration.width - 10;
+ //_currentTime.x = stage.stageWidth - _duration.width - 10 - _currentTime.width - 10;
+ _currentTime.x = _playButton.x+_playButton.width;
+ _scrubTrack.width = (_duration.x-_duration.width-10)-_duration.width+10;
+ _scrubOverlay.width = _scrubTrack.width;
+ _scrubBar.width = _scrubTrack.width;
+ */
+
+ // FLOATING MODE BOTTOM DISPLAY - similar to normal
+ trace("THAT WAY!");
+ _hoverTime.y=(_hoverTime.height/2)+1;
+ _hoverTime.x=0;
+ _controlBarBg.width = stage.stageWidth;
+ _controlBarBg.height = 30;
+ _controlBarBg.y=0;
+ _controlBarBg.x=0;
+ // _controlBarBg.x = 0;
+ // _controlBarBg.y = stage.stageHeight - _controlBar.height;
+
+ _pauseButton.scaleX = _playButton.scaleX=1;
+ _pauseButton.scaleY = _playButton.scaleY=1;
+
+ _pauseButton.x = _playButton.x = 7;
+ _pauseButton.y = _playButton.y = _controlBarBg.height-_playButton.height-2;
+
+
+ //_currentTime.x = stage.stageWidth - _duration.width - 10 - _currentTime.width - 10;
+ _currentTime.x = _playButton.x+_playButton.width;
+
+ _fullscreenIcon.x = _controlBarBg.width - _fullscreenIcon.width - 7;
+ _fullscreenIcon.y = 8;
+
+ _volumeMuted.x = _volumeUnMuted.x = _fullscreenIcon.x - _volumeMuted.width - 10;
+ _volumeMuted.y = _volumeUnMuted.y = 10;
+
+ _duration.x = _volumeMuted.x - _volumeMuted.width - _duration.width + 5;
+ _duration.y = _currentTime.y = _controlBarBg.height - _currentTime.height - 7;
+
+ _scrubLoaded.x = _scrubBar.x = _scrubOverlay.x = _scrubTrack.x = _currentTime.x + _currentTime.width + 10;
+ _scrubLoaded.y = _scrubBar.y = _scrubOverlay.y = _scrubTrack.y = _controlBarBg.height - _scrubTrack.height - 9;
+
+ _scrubBar.width = _scrubOverlay.width = _scrubTrack.width = (_duration.x-_duration.width-10)-_duration.width+5;
+ _controlBar.x = 0;
+ _controlBar.y = stage.stageHeight - _controlBar.height;
+
+ }
+
+ }
+
+ // END: Controls
+
+
+ function stageClicked(e:MouseEvent):void {
+ //_output.appendText("click: " + e.stageX.toString() +","+e.stageY.toString() + "\n");
+ if (e.target == stage) {
+ sendEvent("click", "");
+ }
+ }
+
+ function resizeHandler(e:Event):void {
+ //_video.scaleX = stage.stageWidth / _stageWidth;
+ //_video.scaleY = stage.stageHeight / _stageHeight;
+ //positionControls();
+
+ repositionVideo();
+ }
+
+ // START: Fullscreen
+ function enterFullscreen() {
+
+ _output.appendText("enterFullscreen()\n");
+
+ var screenRectangle:Rectangle = new Rectangle(0, 0, flash.system.Capabilities.screenResolutionX, flash.system.Capabilities.screenResolutionY);
+ stage.fullScreenSourceRect = screenRectangle;
+
+ stage.displayState = StageDisplayState.FULL_SCREEN;
+
+ repositionVideo();
+ positionControls();
+ updateControls(HtmlMediaEvent.FULLSCREENCHANGE);
+
+ _controlBar.visible = true;
+
+ _isFullScreen = true;
+ }
+
+ function exitFullscreen() {
+
+ stage.displayState = StageDisplayState.NORMAL;
+
+
+ _controlBar.visible = false;
+
+ _isFullScreen = false;
+ }
+
+ function setFullscreen(gofullscreen:Boolean) {
+
+ _output.appendText("setFullscreen: " + gofullscreen.toString() + "\n");
+
+ try {
+ //_fullscreenButton.visible = false;
+
+ if (gofullscreen) {
+ enterFullscreen();
+
+ } else {
+ exitFullscreen();
+ }
+
+ } catch (error:Error) {
+
+ // show the button when the security error doesn't let it work
+ //_fullscreenButton.visible = true;
+ _fullscreenButton.alpha = 1;
+
+ _isFullScreen = false;
+
+ _output.appendText("error setting fullscreen: " + error.message.toString() + "\n");
+ }
+ }
+
+ // control bar button/icon
+ function fullScreenIconClick(e:MouseEvent) {
+ try {
+ _controlBar.visible = true;
+ setFullscreen(!_isFullScreen);
+ repositionVideo();
+ } catch (error:Error) {
+ }
+ }
+
+ // special floating fullscreen icon
+ function fullscreenClick(e:MouseEvent) {
+ //_fullscreenButton.visible = false;
+ _fullscreenButton.alpha = 0
+
+ try {
+ _controlBar.visible = true;
+ setFullscreen(true);
+ repositionVideo();
+ positionControls();
+ } catch (error:Error) {
+ }
+ }
+
+
+ function stageFullScreenChanged(e:FullScreenEvent) {
+ _output.appendText("fullscreen event: " + e.fullScreen.toString() + "\n");
+
+ //_fullscreenButton.visible = false;
+ _fullscreenButton.alpha = 0;
+ _isFullScreen = e.fullScreen;
+
+ sendEvent(HtmlMediaEvent.FULLSCREENCHANGE, "isFullScreen:" + e.fullScreen );
+
+ if (!e.fullScreen) {
+ _controlBar.visible = _alwaysShowControls;
+ }
+ }
+ // END: Fullscreen
+
+ // START: external interface
+ function playMedia() {
+ _output.appendText("play\n");
+ _mediaElement.play();
+ }
+
+ function loadMedia() {
+ _output.appendText("load\n");
+ _mediaElement.load();
+ }
+
+ function pauseMedia() {
+ _output.appendText("pause\n");
+ _mediaElement.pause();
+ }
+
+ function setSrc(url:String) {
+ _output.appendText("setSrc: " + url + "\n");
+ _mediaElement.setSrc(url);
+ }
+
+ function stopMedia() {
+ _output.appendText("stop\n");
+ _mediaElement.stop();
+ }
+
+ function setCurrentTime(time:Number) {
+ _output.appendText("seek: " + time.toString() + "\n");
+ _mediaElement.setCurrentTime(time);
+ }
+
+ function setVolume(volume:Number) {
+ _output.appendText("volume: " + volume.toString() + "\n");
+ _mediaElement.setVolume(volume);
+ toggleVolumeIcons(volume);
+ }
+
+ function setMuted(muted:Boolean) {
+ _output.appendText("muted: " + muted.toString() + "\n");
+ _mediaElement.setMuted(muted);
+ toggleVolumeIcons(_mediaElement.getVolume());
+ }
+
+ function setVideoSize(width:Number, height:Number) {
+ _output.appendText("setVideoSize: " + width.toString() + "," + height.toString() + "\n");
+
+ _stageWidth = width;
+ _stageHeight = height;
+
+ if (_video != null) {
+ repositionVideo();
+ positionControls();
+ //_fullscreenButton.x = stage.stageWidth - _fullscreenButton.width - 10;
+ _output.appendText("result: " + _video.width.toString() + "," + _video.height.toString() + "\n");
+ }
+
+
+ }
+
+ function positionFullscreenButton(x:Number, y:Number, visibleAndAbove:Boolean ) {
+
+ _output.appendText("position FS: " + x.toString() + "x" + y.toString() + "\n");
+
+ // bottom corner
+ /*
+ _fullscreenButton.x = stage.stageWidth - _fullscreenButton.width
+ _fullscreenButton.y = stage.stageHeight - _fullscreenButton.height;
+ */
+
+ // position just above
+ if (visibleAndAbove) {
+ _fullscreenButton.x = x+1;
+ _fullscreenButton.y = y - _fullscreenButton.height+1;
+ } else {
+ _fullscreenButton.x = x;
+ _fullscreenButton.y = y;
+ }
+
+ // check for oversizing
+ if ((_fullscreenButton.x + _fullscreenButton.width) > stage.stageWidth)
+ _fullscreenButton.x = stage.stageWidth - _fullscreenButton.width;
+
+ // show it!
+ if (visibleAndAbove) {
+ _fullscreenButton.alpha = 1;
+ }
+ }
+
+ function hideFullscreenButton() {
+
+ //_fullscreenButton.visible = false;
+ _fullscreenButton.alpha = 0;
+ }
+
+ // END: external interface
+
+
+ function repositionVideo():void {
+
+ if (stage.displayState == "fullScreen") {
+ fullscreen = true;
+ } else {
+ fullscreen = false;
+ }
+
+ _output.appendText("positioning video "+stage.displayState+"\n");
+
+ if (_mediaElement is VideoElement) {
+
+ if (isNaN(_nativeVideoWidth) || isNaN(_nativeVideoHeight) || _nativeVideoWidth <= 0 || _nativeVideoHeight <= 0) {
+ _output.appendText("ERR: I dont' have the native dimension\n");
+ return;
+ }
+
+ // calculate ratios
+ var stageRatio, nativeRatio;
+
+ _video.x = 0;
+ _video.y = 0;
+
+ if(fullscreen == true) {
+ stageRatio = flash.system.Capabilities.screenResolutionX/flash.system.Capabilities.screenResolutionY;
+ nativeRatio = _nativeVideoWidth/_nativeVideoHeight;
+
+ // adjust size and position
+ if (nativeRatio > stageRatio) {
+ _mediaElement.setSize(flash.system.Capabilities.screenResolutionX, _nativeVideoHeight * flash.system.Capabilities.screenResolutionX / _nativeVideoWidth);
+ _video.y = flash.system.Capabilities.screenResolutionY/2 - _video.height/2;
+ } else if (stageRatio > nativeRatio) {
+ _mediaElement.setSize(_nativeVideoWidth * flash.system.Capabilities.screenResolutionY / _nativeVideoHeight, flash.system.Capabilities.screenResolutionY);
+ _video.x = flash.system.Capabilities.screenResolutionX/2 - _video.width/2;
+ } else if (stageRatio == nativeRatio) {
+ _mediaElement.setSize(flash.system.Capabilities.screenResolutionX, flash.system.Capabilities.screenResolutionY);
+ }
+
+ } else {
+ stageRatio = _stageWidth/_stageHeight;
+ nativeRatio = _nativeVideoWidth/_nativeVideoHeight;
+
+ // adjust size and position
+ if (nativeRatio > stageRatio) {
+ _mediaElement.setSize(_stageWidth, _nativeVideoHeight * _stageWidth / _nativeVideoWidth);
+ _video.y = _stageHeight/2 - _video.height/2;
+ } else if (stageRatio > nativeRatio) {
+ _mediaElement.setSize( _nativeVideoWidth * _stageHeight / _nativeVideoHeight, _stageHeight);
+ _video.x = _stageWidth/2 - _video.width/2;
+ } else if (stageRatio == nativeRatio) {
+ _mediaElement.setSize(_stageWidth, _stageHeight);
+ }
+
+ }
+
+ } else if (_mediaElement is YouTubeElement) {
+ if(fullscreen == true) {
+ _mediaElement.setSize(flash.system.Capabilities.screenResolutionX, flash.system.Capabilities.screenResolutionY);
+
+ } else {
+ _mediaElement.setSize(_stageWidth, _stageHeight);
+
+ }
+
+ }
+
+ positionControls();
+ }
+
+ // SEND events to JavaScript
+ public function sendEvent(eventName:String, eventValues:String) {
+
+ // special video event
+ if (eventName == HtmlMediaEvent.LOADEDMETADATA && _isVideo) {
+
+ _output.appendText("METADATA RECEIVED: ");
+
+ try {
+ if (_mediaElement is VideoElement) {
+ _nativeVideoWidth = (_mediaElement as VideoElement).videoWidth;
+ _nativeVideoHeight = (_mediaElement as VideoElement).videoHeight;
+ }
+ } catch (e:Error) {
+ _output.appendText(e.toString() + "\n");
+ }
+
+ _output.appendText(_nativeVideoWidth.toString() + "x" + _nativeVideoHeight.toString() + "\n");
+
+
+ if(stage.displayState == "fullScreen" ) {
+ setVideoSize(_nativeVideoWidth, _nativeVideoHeight);
+ }
+ repositionVideo();
+
+ }
+
+ updateControls(eventName);
+
+ //trace((_mediaElement.duration()*1).toString() + " / " + (_mediaElement.currentTime()*1).toString());
+ //trace("CurrentProgress:"+_mediaElement.currentProgress());
+
+ if (ExternalInterface.objectID != null && ExternalInterface.objectID.toString() != "") {
+
+ //_output.appendText("event:" + eventName + " : " + eventValues);
+ //trace("event", eventName, eventValues);
+
+ if (eventValues == null)
+ eventValues == "";
+
+ if (_isVideo) {
+ eventValues += (eventValues != "" ? "," : "") + "isFullScreen:" + _isFullScreen;
+ }
+
+ eventValues = "{" + eventValues + "}";
+
+ /*
+ OLD DIRECT METHOD
+ ExternalInterface.call(
+ "function(id, name) { mejs.MediaPluginBridge.fireEvent(id,name," + eventValues + "); }",
+ ExternalInterface.objectID,
+ eventName);
+ */
+
+ // use set timeout for performance reasons
+ //if (!_alwaysShowControls) {
+ ExternalInterface.call("setTimeout", "mejs.MediaPluginBridge.fireEvent('" + ExternalInterface.objectID + "','" + eventName + "'," + eventValues + ")",0);
+ //}
+ }
+ }
+
+
+ function updateControls(eventName:String):void {
+
+ //trace("updating controls");
+
+ try {
+ // update controls
+ switch (eventName) {
+ case "pause":
+ case "paused":
+ case "ended":
+ _playButton.visible = true;
+ _pauseButton.visible = false;
+ break;
+ case "play":
+ case "playing":
+ _playButton.visible = false;
+ _pauseButton.visible = true;
+ break;
+ }
+
+ if (eventName == HtmlMediaEvent.TIMEUPDATE ||
+ eventName == HtmlMediaEvent.PROGRESS ||
+ eventName == HtmlMediaEvent.FULLSCREENCHANGE) {
+
+ //_duration.text = (_mediaElement.duration()*1).toString();
+ _duration.text = secondsToTimeCode(_mediaElement.duration());
+ //_currentTime.text = (_mediaElement.currentTime()*1).toString();
+ _currentTime.text = secondsToTimeCode(_mediaElement.currentTime());
+
+ var pct:Number = (_mediaElement.currentTime() / _mediaElement.duration()) *_scrubTrack.scaleX;
+
+ _scrubBar.scaleX = pct;
+ _scrubLoaded.scaleX = (_mediaElement.currentProgress()*_scrubTrack.scaleX)/100;
+ }
+ } catch (error:Error) {
+ trace("error: " + error.toString());
+
+ }
+
+ }
+
+ // START: utility
+ function secondsToTimeCode(seconds:Number):String {
+ var timeCode:String = "";
+ seconds = Math.round(seconds);
+ var minutes:Number = Math.floor(seconds / 60);
+ timeCode = (minutes >= 10) ? minutes.toString() : "0" + minutes.toString();
+ seconds = Math.floor(seconds % 60);
+ timeCode += ":" + ((seconds >= 10) ? seconds.toString() : "0" + seconds.toString());
+ return timeCode; //minutes.toString() + ":" + seconds.toString();
+ }
+
+ function applyColor(item:Object, color:String):void {
+
+ var myColor:ColorTransform = item.transform.colorTransform;
+ myColor.color = Number(color);
+ item.transform.colorTransform = myColor;
+ }
+ // END: utility
+
+ }
+} \ No newline at end of file
diff --git a/debian/missing-sources/mediaelement/src/FlashMediaElement.fla b/debian/missing-sources/mediaelement/src/FlashMediaElement.fla
new file mode 100644
index 0000000..b39f581
--- /dev/null
+++ b/debian/missing-sources/mediaelement/src/FlashMediaElement.fla
Binary files differ
diff --git a/debian/missing-sources/mediaelement/src/HtmlMediaEvent.as b/debian/missing-sources/mediaelement/src/HtmlMediaEvent.as
new file mode 100644
index 0000000..d12c0fe
--- /dev/null
+++ b/debian/missing-sources/mediaelement/src/HtmlMediaEvent.as
@@ -0,0 +1,29 @@
+package {
+
+ public class HtmlMediaEvent {
+
+ public static var LOADED_DATA:String = "loadeddata";
+ public static var PROGRESS:String = "progress";
+ public static var TIMEUPDATE:String = "timeupdate";
+ public static var SEEKED:String = "seeked";
+ public static var PLAY:String = "play";
+ public static var PLAYING:String = "playing";
+ public static var PAUSE:String = "pause";
+ public static var LOADEDMETADATA:String = "loadedmetadata";
+ public static var ENDED:String = "ended";
+ public static var VOLUMECHANGE:String = "volumechange";
+ public static var STOP:String = "stop";
+
+ // new : 2/15/2011
+ public static var LOADSTART:String = "loadstart";
+ public static var CANPLAY:String = "canplay";
+ // new : 3/3/2011
+ public static var LOADEDDATA:String = "loadeddata";
+
+ // new : 4/12/2011
+ public static var SEEKING:String = "seeking";
+
+ // new : 1/2/2012
+ public static var FULLSCREENCHANGE:String = "fullscreenchange";
+ }
+}
diff --git a/debian/missing-sources/mediaelement/src/htmlelements/AudioElement.as b/debian/missing-sources/mediaelement/src/htmlelements/AudioElement.as
new file mode 100644
index 0000000..750599d
--- /dev/null
+++ b/debian/missing-sources/mediaelement/src/htmlelements/AudioElement.as
@@ -0,0 +1,332 @@
+
+package htmlelements
+{
+ import flash.events.Event;
+ import flash.events.IOErrorEvent;
+ import flash.events.ProgressEvent;
+ import flash.events.TimerEvent;
+ import flash.media.ID3Info;
+ import flash.media.Sound;
+ import flash.media.SoundChannel;
+ import flash.media.SoundLoaderContext;
+ import flash.media.SoundTransform;
+ import flash.net.URLRequest;
+ import flash.utils.Timer;
+
+
+
+ /**
+ * ...
+ * @author DefaultUser (Tools -> Custom Arguments...)
+ */
+ public class AudioElement implements IMediaElement
+ {
+
+ private var _sound:Sound;
+ private var _soundTransform:SoundTransform;
+ private var _soundChannel:SoundChannel;
+ private var _soundLoaderContext:SoundLoaderContext;
+
+ private var _volume:Number = 1;
+ private var _preMuteVolume:Number = 0;
+ private var _isMuted:Boolean = false;
+ private var _isPaused:Boolean = true;
+ private var _isEnded:Boolean = false;
+ private var _isLoaded:Boolean = false;
+ private var _currentTime:Number = 0;
+ private var _duration:Number = 0;
+ private var _bytesLoaded:Number = 0;
+ private var _bytesTotal:Number = 0;
+ private var _bufferedTime:Number = 0;
+ private var _bufferingChanged:Boolean = false;
+
+ private var _currentUrl:String = "";
+ private var _autoplay:Boolean = true;
+ private var _preload:String = "";
+
+ private var _element:FlashMediaElement;
+ private var _timer:Timer;
+ private var _firedCanPlay:Boolean = false;
+
+ public function setSize(width:Number, height:Number):void {
+ // do nothing!
+ }
+
+ public function duration():Number {
+ return _duration;
+ }
+
+ public function currentTime():Number {
+ return _currentTime;
+ }
+
+ public function currentProgress():Number {
+ return Math.round(_bytesLoaded/_bytesTotal*100);
+ }
+
+ public function AudioElement(element:FlashMediaElement, autoplay:Boolean, preload:String, timerRate:Number, startVolume:Number)
+ {
+ _element = element;
+ _autoplay = autoplay;
+ _volume = startVolume;
+ _preload = preload;
+
+ _timer = new Timer(timerRate);
+ _timer.addEventListener(TimerEvent.TIMER, timerEventHandler);
+
+ _soundTransform = new SoundTransform(_volume);
+ _soundLoaderContext = new SoundLoaderContext();
+ }
+
+ // events
+ function progressHandler(e:ProgressEvent):void {
+
+ _bytesLoaded = e.bytesLoaded;
+ _bytesTotal = e.bytesTotal;
+
+ // this happens too much to send every time
+ //sendEvent(HtmlMediaEvent.PROGRESS);
+
+ // so now we just trigger a flag and send with the timer
+ _bufferingChanged = true;
+ }
+
+ function id3Handler(e:Event):void {
+ sendEvent(HtmlMediaEvent.LOADEDMETADATA);
+
+ try {
+ var id3:ID3Info = _sound.id3;
+ var obj = {
+ type:'id3',
+ album:id3.album,
+ artist:id3.artist,
+ comment:id3.comment,
+ genre:id3.genre,
+ songName:id3.songName,
+ track:id3.track,
+ year:id3.year
+ }
+ } catch (err:Error) {}
+
+
+ }
+
+ function timerEventHandler(e:TimerEvent) {
+ _currentTime = _soundChannel.position/1000;
+
+ // calculate duration
+ var duration = Math.round(_sound.length * _sound.bytesTotal/_sound.bytesLoaded/100) / 10;
+
+ // check to see if the estimated duration changed
+ if (_duration != duration && !isNaN(duration)) {
+
+ _duration = duration;
+ sendEvent(HtmlMediaEvent.LOADEDMETADATA);
+ }
+
+ // check for progress
+ if (_bufferingChanged) {
+
+ sendEvent(HtmlMediaEvent.PROGRESS);
+
+ _bufferingChanged = false;
+ }
+
+ // send timeupdate
+ sendEvent(HtmlMediaEvent.TIMEUPDATE);
+
+ // sometimes the ended event doesn't fire, here's a fake one
+ if (_duration > 0 && _currentTime >= _duration-0.2) {
+ handleEnded();
+ }
+ }
+
+ function soundCompleteHandler(e:Event) {
+ handleEnded();
+ }
+
+ function handleEnded():void {
+ _timer.stop();
+ _currentTime = 0;
+ _isEnded = true;
+
+ sendEvent(HtmlMediaEvent.ENDED);
+ }
+
+ //events
+
+
+ // METHODS
+ public function setSrc(url:String):void {
+ _currentUrl = url;
+ _isLoaded = false;
+ }
+
+
+ public function load():void {
+
+ if (_currentUrl == "")
+ return;
+
+ _sound = new Sound();
+ //sound.addEventListener(IOErrorEvent.IO_ERROR,errorHandler);
+ _sound.addEventListener(ProgressEvent.PROGRESS,progressHandler);
+ _sound.addEventListener(Event.ID3,id3Handler);
+ _sound.load(new URLRequest(_currentUrl));
+ _currentTime = 0;
+
+ sendEvent(HtmlMediaEvent.LOADSTART);
+
+ _isLoaded = true;
+
+ sendEvent(HtmlMediaEvent.LOADEDDATA);
+ sendEvent(HtmlMediaEvent.CANPLAY);
+ _firedCanPlay = true;
+
+ if (_playAfterLoading) {
+ _playAfterLoading = false;
+ play();
+ }
+ }
+
+ private var _playAfterLoading:Boolean= false;
+
+ public function play():void {
+
+ if (!_isLoaded) {
+ _playAfterLoading = true;
+ load();
+ return;
+ }
+
+ _timer.stop();
+
+ _soundChannel = _sound.play(_currentTime*1000, 0, _soundTransform);
+ _soundChannel.removeEventListener(Event.SOUND_COMPLETE, soundCompleteHandler);
+ _soundChannel.addEventListener(Event.SOUND_COMPLETE, soundCompleteHandler);
+
+ _timer.start();
+
+ didStartPlaying();
+ }
+
+ public function pause():void {
+
+ _timer.stop();
+ if (_soundChannel != null) {
+ _currentTime = _soundChannel.position/1000;
+ _soundChannel.stop();
+ }
+
+ _isPaused = true;
+ sendEvent(HtmlMediaEvent.PAUSE);
+ }
+
+
+ public function stop():void {
+ if (_timer != null) {
+ _timer.stop();
+ }
+ if (_soundChannel != null) {
+ _soundChannel.stop();
+ _sound.close();
+ }
+ unload();
+ sendEvent(HtmlMediaEvent.STOP);
+ }
+
+ public function setCurrentTime(pos:Number):void {
+ sendEvent(HtmlMediaEvent.SEEKING);
+ _timer.stop();
+ _currentTime = pos;
+ _soundChannel.stop();
+ _sound.length
+ _soundChannel = _sound.play(_currentTime * 1000, 0, _soundTransform);
+ sendEvent(HtmlMediaEvent.SEEKED);
+
+ _timer.start();
+
+ didStartPlaying();
+ }
+
+ private function didStartPlaying():void {
+ _isPaused = false;
+ sendEvent(HtmlMediaEvent.PLAY);
+ sendEvent(HtmlMediaEvent.PLAYING);
+ if (!_firedCanPlay) {
+ sendEvent(HtmlMediaEvent.LOADEDDATA);
+ sendEvent(HtmlMediaEvent.CANPLAY);
+ _firedCanPlay = true;
+ }
+ }
+
+
+ public function setVolume(volume:Number):void {
+
+ _volume = volume;
+ _soundTransform.volume = volume;
+
+ if (_soundChannel != null) {
+ _soundChannel.soundTransform = _soundTransform;
+ }
+
+ _isMuted = (_volume == 0);
+
+ sendEvent(HtmlMediaEvent.VOLUMECHANGE);
+ }
+
+ public function getVolume():Number {
+ if(_isMuted) {
+ return 0;
+ } else {
+ return _volume;
+ }
+ }
+
+
+ public function setMuted(muted:Boolean):void {
+
+ // ignore if already set
+ if ( (muted && _isMuted) || (!muted && !_isMuted))
+ return;
+
+ if (muted) {
+ _preMuteVolume = _soundTransform.volume;
+ setVolume(0);
+ } else {
+ setVolume(_preMuteVolume);
+ }
+
+ _isMuted = muted;
+ }
+
+ public function unload():void {
+ _sound = null;
+ _isLoaded = false;
+ }
+
+ private function sendEvent(eventName:String) {
+
+ // calculate this to mimic HTML5
+ _bufferedTime = _bytesLoaded / _bytesTotal * _duration;
+
+ // build JSON
+ var values:String = "duration:" + _duration +
+ ",currentTime:" + _currentTime +
+ ",muted:" + _isMuted +
+ ",paused:" + _isPaused +
+ ",ended:" + _isEnded +
+ ",volume:" + _volume +
+ ",src:\"" + _currentUrl + "\"" +
+ ",bytesTotal:" + _bytesTotal +
+ ",bufferedBytes:" + _bytesLoaded +
+ ",bufferedTime:" + _bufferedTime +
+ "";
+
+ _element.sendEvent(eventName, values);
+ }
+
+ }
+
+}
+
diff --git a/debian/missing-sources/mediaelement/src/htmlelements/IMediaElement.as b/debian/missing-sources/mediaelement/src/htmlelements/IMediaElement.as
new file mode 100644
index 0000000..d626607
--- /dev/null
+++ b/debian/missing-sources/mediaelement/src/htmlelements/IMediaElement.as
@@ -0,0 +1,35 @@
+
+package htmlelements
+{
+
+ public interface IMediaElement {
+
+ function play():void;
+
+ function pause():void;
+
+ function load():void;
+
+ function stop():void;
+
+ function setSrc(url:String):void;
+
+ function setSize(width:Number, height:Number):void;
+
+ function setCurrentTime(pos:Number):void;
+
+ function setVolume(vol:Number):void;
+
+ function getVolume():Number;
+
+ function setMuted(muted:Boolean):void;
+
+ function duration():Number;
+
+ function currentTime():Number;
+
+ function currentProgress():Number;
+
+ }
+
+}
diff --git a/debian/missing-sources/mediaelement/src/htmlelements/VideoElement.as b/debian/missing-sources/mediaelement/src/htmlelements/VideoElement.as
new file mode 100644
index 0000000..7673c4f
--- /dev/null
+++ b/debian/missing-sources/mediaelement/src/htmlelements/VideoElement.as
@@ -0,0 +1 @@
+package htmlelements { import flash.display.Sprite; import flash.events.*; import flash.net.NetConnection; import flash.net.NetStream; import flash.media.Video; import flash.media.SoundTransform; import flash.utils.Timer; import FlashMediaElement; import HtmlMediaEvent; public class VideoElement extends Sprite implements IMediaElement { private var _currentUrl:String = ""; private var _autoplay:Boolean = true; private var _preload:String = ""; private var _isPreloading:Boolean = false; private var _connection:NetConnection; private var _stream:NetStream; private var _video:Video; private var _element:FlashMediaElement; private var _soundTransform; private var _oldVolume:Number = 1; // event values private var _duration:Number = 0; private var _framerate:Number; private var _isPaused:Boolean = true; private var _isEnded:Boolean = false; private var _volume:Number = 1; private var _isMuted:Boolean = false; private var _bytesLoaded:Number = 0; private var _bytesTotal:Number = 0; private var _bufferedTime:Number = 0; private var _bufferEmpty:Boolean = false; private var _bufferingChanged:Boolean = false; private var _seekOffset:Number = 0; private var _videoWidth:Number = -1; private var _videoHeight:Number = -1; private var _timer:Timer; private var _isRTMP:Boolean = false; private var _streamer:String = ""; private var _isConnected:Boolean = false; private var _playWhenConnected:Boolean = false; private var _hasStartedPlaying:Boolean = false; private var _parentReference:Object; private var _pseudoStreamingEnabled:Boolean = false; private var _pseudoStreamingStartQueryParam:String = "start"; public function setReference(arg:Object):void { _parentReference = arg; } public function setSize(width:Number, height:Number):void { _video.width = width; _video.height = height; } public function setPseudoStreaming(enablePseudoStreaming:Boolean):void { _pseudoStreamingEnabled = enablePseudoStreaming; } public function setPseudoStreamingStartParam(pseudoStreamingStartQueryParam:String):void { _pseudoStreamingStartQueryParam = pseudoStreamingStartQueryParam; } public function get video():Video { return _video; } public function get videoHeight():Number { return _videoHeight; } public function get videoWidth():Number { return _videoWidth; } public function duration():Number { return _duration; } public function currentProgress():Number { if(_stream != null) { return Math.round(_stream.bytesLoaded/_stream.bytesTotal*100); } else { return 0; } } public function currentTime():Number { var currentTime:Number = 0; if (_stream != null) { currentTime = _stream.time; if (_pseudoStreamingEnabled) { currentTime += _seekOffset; } } return currentTime; } // (1) load() // calls _connection.connect(); // waits for NetConnection.Connect.Success // _stream gets created public function VideoElement(element:FlashMediaElement, autoplay:Boolean, preload:String, timerRate:Number, startVolume:Number, streamer:String) { _element = element; _autoplay = autoplay; _volume = startVolume; _preload = preload; _streamer = streamer; _video = new Video(); addChild(_video); _connection = new NetConnection(); _connection.client = { onBWDone: function():void{} }; _connection.addEventListener(NetStatusEvent.NET_STATUS, netStatusHandler); _connection.addEventListener(SecurityErrorEvent.SECURITY_ERROR, securityErrorHandler); //_connection.connect(null); _timer = new Timer(timerRate); _timer.addEventListener("timer", timerHandler); } private function timerHandler(e:TimerEvent) { _bytesLoaded = _stream.bytesLoaded; _bytesTotal = _stream.bytesTotal; if (!_isPaused) { sendEvent(HtmlMediaEvent.TIMEUPDATE); } //trace("bytes", _bytesLoaded, _bytesTotal); if (_bytesLoaded < _bytesTotal) sendEvent(HtmlMediaEvent.PROGRESS); } // internal events private function netStatusHandler(event:NetStatusEvent):void { trace("netStatus", event.info.code); switch (event.info.code) { case "NetStream.Buffer.Empty": _bufferEmpty = true; _isEnded ? sendEvent(HtmlMediaEvent.ENDED) : null; break; case "NetStream.Buffer.Full": _bytesLoaded = _stream.bytesLoaded; _bytesTotal = _stream.bytesTotal; _bufferEmpty = false; sendEvent(HtmlMediaEvent.PROGRESS); break; case "NetConnection.Connect.Success": connectStream(); break; case "NetStream.Play.StreamNotFound": trace("Unable to locate video"); break; // STREAM case "NetStream.Play.Start": _isPaused = false; sendEvent(HtmlMediaEvent.LOADEDDATA); sendEvent(HtmlMediaEvent.CANPLAY); if (!_isPreloading) { sendEvent(HtmlMediaEvent.PLAY); sendEvent(HtmlMediaEvent.PLAYING); } _timer.start(); break; case "NetStream.Seek.Notify": sendEvent(HtmlMediaEvent.SEEKED); break; case "NetStream.Pause.Notify": _isPaused = true; sendEvent(HtmlMediaEvent.PAUSE); break; case "NetStream.Play.Stop": _isEnded = true; _isPaused = false; _timer.stop(); _bufferEmpty ? sendEvent(HtmlMediaEvent.ENDED) : null; break; } } private function securityErrorHandler(event:SecurityErrorEvent):void { trace("securityErrorHandler: " + event); } private function asyncErrorHandler(event:AsyncErrorEvent):void { // ignore AsyncErrorEvent events. } private function onMetaDataHandler(info:Object):void { // Only set the duration when we first load the video if (_duration == 0) { _duration = info.duration; } _framerate = info.framerate; _videoWidth = info.width; _videoHeight = info.height; // set size? sendEvent(HtmlMediaEvent.LOADEDMETADATA); if (_isPreloading) { _stream.pause(); _isPaused = true; _isPreloading = false; sendEvent(HtmlMediaEvent.PROGRESS); sendEvent(HtmlMediaEvent.TIMEUPDATE); } } // interface members public function setSrc(url:String):void { if (_isConnected && _stream) { // stop and restart _stream.pause(); } _currentUrl = url; _isRTMP = !!_currentUrl.match(/^rtmp(s|t|e|te)?\:\/\//) || _streamer != ""; _isConnected = false; _hasStartedPlaying = false; } public function load():void { // disconnect existing stream and connection if (_isConnected && _stream) { _stream.pause(); _stream.close(); _connection.close(); } _isConnected = false; _isPreloading = false; _isEnded = false; _bufferEmpty = false; // start new connection if (_isRTMP) { var rtmpInfo:Object = parseRTMP(_currentUrl); if (_streamer != "") { rtmpInfo.server = _streamer; rtmpInfo.stream = _currentUrl; } _connection.connect(rtmpInfo.server); } else { _connection.connect(null); } // in a few moments the "NetConnection.Connect.Success" event will fire // and call createConnection which finishes the "load" sequence sendEvent(HtmlMediaEvent.LOADSTART); } private function connectStream():void { trace("connectStream"); _stream = new NetStream(_connection); // explicitly set the sound since it could have come before the connection was made _soundTransform = new SoundTransform(_volume); _stream.soundTransform = _soundTransform; // set the buffer to ensure nice playback _stream.bufferTime = 1; _stream.bufferTimeMax = 3; _stream.addEventListener(NetStatusEvent.NET_STATUS, netStatusHandler); // same event as connection _stream.addEventListener(AsyncErrorEvent.ASYNC_ERROR, asyncErrorHandler); var customClient:Object = new Object(); customClient.onMetaData = onMetaDataHandler; _stream.client = customClient; _video.attachNetStream(_stream); // start downloading without playing )based on preload and play() hasn't been called) // I wish flash had a load() command to make this less awkward if (_preload != "none" && !_playWhenConnected) { _isPaused = true; //stream.bufferTime = 20; _stream.play(getCurrentUrl(0), 0, 0); _stream.pause(); _isPreloading = true; //_stream.pause(); // //sendEvent(HtmlMediaEvent.PAUSE); // have to send this because the "playing" event gets sent via event handlers } _isConnected = true; if (_playWhenConnected && !_hasStartedPlaying) { play(); _playWhenConnected = false; } } public function play():void { if (!_hasStartedPlaying && !_isConnected) { _playWhenConnected = true; load(); return; } if (_hasStartedPlaying) { if (_isPaused) { _stream.resume(); _timer.start(); _isPaused = false; sendEvent(HtmlMediaEvent.PLAY); sendEvent(HtmlMediaEvent.PLAYING); } } else { if (_isRTMP) { var rtmpInfo:Object = parseRTMP(_currentUrl); _stream.play(rtmpInfo.stream); } else { _stream.play(getCurrentUrl(0)); } _timer.start(); _isPaused = false; _hasStartedPlaying = true; // don't toss play/playing events here, because we haven't sent a // canplay / loadeddata event yet. that'll be handled in the net // event listener } } public function pause():void { if (_stream == null) return; _stream.pause(); _isPaused = true; if (_bytesLoaded == _bytesTotal) { _timer.stop(); } _isPaused = true; sendEvent(HtmlMediaEvent.PAUSE); } public function stop():void { if (_stream == null) return; _stream.close(); _isPaused = false; _timer.stop(); sendEvent(HtmlMediaEvent.STOP); } public function setCurrentTime(pos:Number):void { if (_stream == null) { return; } // Calculate the position of the buffered video var bufferPosition:Number = _bytesLoaded / _bytesTotal * _duration; if (_pseudoStreamingEnabled) { sendEvent(HtmlMediaEvent.SEEKING); // Normal seek if it is in buffer and this is the first seek if (pos < bufferPosition && _seekOffset == 0) { _stream.seek(pos); } else { // Uses server-side pseudo-streaming to seek _stream.play(getCurrentUrl(pos)); _seekOffset = pos; } } else { sendEvent(HtmlMediaEvent.SEEKING); _stream.seek(pos); } if (!_isEnded) { sendEvent(HtmlMediaEvent.TIMEUPDATE); } } public function setVolume(volume:Number):void { if (_stream != null) { _soundTransform = new SoundTransform(volume); _stream.soundTransform = _soundTransform; } _volume = volume; _isMuted = (_volume == 0); sendEvent(HtmlMediaEvent.VOLUMECHANGE); } public function getVolume():Number { if(_isMuted) { return 0; } else { return _volume; } } public function setMuted(muted:Boolean):void { if (_isMuted == muted) return; if (muted) { _oldVolume = (_stream == null) ? _oldVolume : _stream.soundTransform.volume; setVolume(0); } else { setVolume(_oldVolume); } _isMuted = muted; } private function sendEvent(eventName:String) { // calculate this to mimic HTML5 _bufferedTime = _bytesLoaded / _bytesTotal * _duration; // build JSON var values:String = "duration:" + _duration + ",framerate:" + _framerate + ",currentTime:" + currentTime() + ",muted:" + _isMuted + ",paused:" + _isPaused + ",ended:" + _isEnded + ",volume:" + _volume + ",src:\"" + _currentUrl + "\"" + ",bytesTotal:" + _bytesTotal + ",bufferedBytes:" + _bytesLoaded + ",bufferedTime:" + _bufferedTime + ",videoWidth:" + _videoWidth + ",videoHeight:" + _videoHeight + ""; _element.sendEvent(eventName, values); } private function parseRTMP(url:String) { var match:Array = url.match(/(.*)\/((flv|mp4|mp3):.*)/); var rtmpInfo:Object = { server: null, stream: null }; if (match) { rtmpInfo.server = match[1]; rtmpInfo.stream = match[2]; } else { rtmpInfo.server = url.replace(/\/[^\/]+$/,"/"); rtmpInfo.stream = url.split("/").pop(); } trace("parseRTMP - server: " + rtmpInfo.server + " stream: " + rtmpInfo.stream); return rtmpInfo; } private function getCurrentUrl(pos:Number):String { var url:String = _currentUrl; if (_pseudoStreamingEnabled) { if (url.indexOf('?') > -1) { url = url + '&' + _pseudoStreamingStartQueryParam + '=' + pos; } else { url = url + '?' + _pseudoStreamingStartQueryParam + '=' + pos; } } return url; } } } \ No newline at end of file
diff --git a/debian/missing-sources/mediaelement/src/htmlelements/YouTubeElement.as b/debian/missing-sources/mediaelement/src/htmlelements/YouTubeElement.as
new file mode 100644
index 0000000..80986fa
--- /dev/null
+++ b/debian/missing-sources/mediaelement/src/htmlelements/YouTubeElement.as
@@ -0,0 +1,403 @@
+package htmlelements
+{
+ import flash.display.Sprite;
+ import flash.events.*;
+ import flash.net.NetConnection;
+ import flash.net.NetStream;
+ import flash.media.Video;
+ import flash.media.SoundTransform;
+ import flash.utils.Timer;
+ import flash.net.URLLoader;
+ import flash.net.URLRequest;
+ import flash.net.URLVariables;
+ import flash.net.URLRequestMethod;
+ import flash.display.MovieClip;
+ import flash.display.Loader;
+ import flash.display.DisplayObject;
+
+
+
+ import FlashMediaElement;
+ import HtmlMediaEvent;
+
+ public class YouTubeElement extends Sprite implements IMediaElement
+ {
+ private var _currentUrl:String = "";
+ private var _autoplay:Boolean = true;
+ private var _preload:String = "";
+
+ private var _element:FlashMediaElement;
+
+ // event values
+ private var _currentTime:Number = 0;
+ private var _duration:Number = 0;
+ private var _framerate:Number;
+ private var _isPaused:Boolean = true;
+ private var _isEnded:Boolean = false;
+ private var _volume:Number = 1;
+ private var _isMuted:Boolean = false;
+
+ private var _bytesLoaded:Number = 0;
+ private var _bytesTotal:Number = 0;
+ private var _bufferedTime:Number = 0;
+ private var _bufferEmpty:Boolean = false;
+
+ private var _videoWidth:Number = -1;
+ private var _videoHeight:Number = -1;
+
+ private var _timer:Timer;
+
+ // YouTube stuff
+ private var _playerLoader:Loader;
+ private var _player:Object = null;
+ private var _playerIsLoaded:Boolean = false;
+ private var _youTubeId:String = "";
+
+ //http://code.google.com/p/gdata-samples/source/browse/trunk/ytplayer/actionscript3/com/google/youtube/examples/AS3Player.as
+ private static const WIDESCREEN_ASPECT_RATIO:String = "widescreen";
+ private static const QUALITY_TO_PLAYER_WIDTH:Object = {
+ small: 320,
+ medium: 640,
+ large: 854,
+ hd720: 1280
+ };
+ private static const STATE_ENDED:Number = 0;
+ private static const STATE_PLAYING:Number = 1;
+ private static const STATE_PAUSED:Number = 2;
+ private static const STATE_CUED:Number = 5;
+
+
+ public function get player():DisplayObject {
+ return _player;
+ }
+
+ public function setSize(width:Number, height:Number):void {
+ if (_player != null) {
+ _player.setSize(width, height);
+ } else {
+ initHeight = height;
+ initWidth = width;
+ }
+ }
+
+ public function get videoHeight():Number {
+ return _videoHeight;
+ }
+
+ public function get videoWidth():Number {
+ return _videoWidth;
+ }
+
+
+ public function duration():Number {
+ return _duration;
+ }
+
+ public function currentProgress():Number {
+ if(_bytesTotal> 0) {
+ return Math.round(_bytesLoaded/_bytesTotal*100);
+ } else {
+ return 0;
+ }
+ }
+
+ public function currentTime():Number {
+ return _currentTime;
+ }
+
+
+ public var initHeight:Number;
+ public var initWidth:Number;
+
+ // (1) load()
+ // calls _connection.connect();
+ // waits for NetConnection.Connect.Success
+ // _stream gets created
+
+ private var _isChromeless:Boolean = false;
+
+
+ public function YouTubeElement(element:FlashMediaElement, autoplay:Boolean, preload:String, timerRate:Number, startVolume:Number)
+ {
+ _element = element;
+ _autoplay = autoplay;
+ _volume = startVolume;
+ _preload = preload;
+ initHeight = 0;
+ initWidth = 0;
+
+ _playerLoader = new Loader();
+ _playerLoader.contentLoaderInfo.addEventListener(Event.COMPLETE, playerLoaderInitHandler);
+
+ // chromeless
+ if (_isChromeless) {
+ _playerLoader.load(new URLRequest("//www.youtube.com/apiplayer?version=3&controls=1&rel=0&showinfo=0&iv_load_policy=1"));
+ }
+
+
+ _timer = new Timer(timerRate);
+ _timer.addEventListener("timer", timerHandler);
+ _timer.start();
+ }
+
+ private function playerLoaderInitHandler(event:Event):void {
+
+ trace("yt player init");
+
+ _element.addChild(_playerLoader.content);
+ _element.setControlDepth();
+ _playerLoader.content.addEventListener("onReady", onPlayerReady);
+ _playerLoader.content.addEventListener("onError", onPlayerError);
+ _playerLoader.content.addEventListener("onStateChange", onPlayerStateChange);
+ _playerLoader.content.addEventListener("onPlaybackQualityChange", onVideoPlaybackQualityChange);
+ }
+
+ private function onPlayerReady(event:Event):void {
+ _playerIsLoaded = true;
+
+ _player = _playerLoader.content;
+
+ if (initHeight > 0 && initWidth > 0)
+ _player.setSize(initWidth, initHeight);
+
+ if (_youTubeId != "") { // && _isChromeless) {
+ if (_autoplay) {
+ player.loadVideoById(_youTubeId);
+ } else {
+ player.cueVideoById(_youTubeId);
+ }
+ _timer.start();
+ }
+ }
+
+ private function onPlayerError(event:Event):void {
+ // trace("Player error:", Object(event).data);
+ }
+
+ private function onPlayerStateChange(event:Event):void {
+ trace("State is", Object(event).data);
+
+ _duration = _player.getDuration();
+
+ switch (Object(event).data) {
+ case STATE_ENDED:
+ _isEnded = true;
+ _isPaused = false;
+
+ sendEvent(HtmlMediaEvent.ENDED);
+
+ break;
+
+ case STATE_PLAYING:
+ _isEnded = false;
+ _isPaused = false;
+
+ sendEvent(HtmlMediaEvent.PLAY);
+ sendEvent(HtmlMediaEvent.PLAYING);
+ break;
+
+ case STATE_PAUSED:
+ _isEnded = false;
+ _isPaused = true;
+
+ sendEvent(HtmlMediaEvent.PAUSE);
+
+ break;
+
+ case STATE_CUED:
+ sendEvent(HtmlMediaEvent.CANPLAY);
+
+ // resize?
+
+ break;
+ }
+ }
+
+ private function onVideoPlaybackQualityChange(event:Event):void {
+ trace("Current video quality:", Object(event).data);
+ //resizePlayer(Object(event).data);
+ }
+
+ private function timerHandler(e:TimerEvent) {
+
+ if (_playerIsLoaded) {
+ _bytesLoaded = _player.getVideoBytesLoaded();
+ _bytesTotal = _player.getVideoBytesTotal();
+ _currentTime = player.getCurrentTime();
+
+ if (!_isPaused)
+ sendEvent(HtmlMediaEvent.TIMEUPDATE);
+
+ if (_bytesLoaded < _bytesTotal)
+ sendEvent(HtmlMediaEvent.PROGRESS);
+ }
+
+ }
+
+ private function getYouTubeId(url:String):String {
+ // http://www.youtube.com/watch?feature=player_embedded&v=yyWWXSwtPP0
+ // http://www.youtube.com/v/VIDEO_ID?version=3
+ // http://youtu.be/Djd6tPrxc08
+
+ url = unescape(url);
+
+ var youTubeId:String = "";
+
+ if (url.indexOf("?") > 0) {
+ // assuming: http://www.youtube.com/watch?feature=player_embedded&v=yyWWXSwtPP0
+ youTubeId = getYouTubeIdFromParam(url);
+
+ // if it's http://www.youtube.com/v/VIDEO_ID?version=3
+ if (youTubeId == "") {
+ youTubeId = getYouTubeIdFromUrl(url);
+ }
+ } else {
+ youTubeId = getYouTubeIdFromUrl(url);
+ }
+
+ return youTubeId;
+ }
+
+ // http://www.youtube.com/watch?feature=player_embedded&v=yyWWXSwtPP0
+ private function getYouTubeIdFromParam(url:String):String {
+
+
+ var youTubeId:String = "";
+ var parts:Array = url.split('?');
+ var parameters:Array = parts[1].split('&');
+
+ for (var i:Number=0; i<parameters.length; i++) {
+ var paramParts = parameters[i].split('=');
+ if (paramParts[0] == "v") {
+
+ youTubeId = paramParts[1];
+ break;
+ }
+
+ }
+
+
+ return youTubeId;
+ }
+
+
+ // http://www.youtube.com/v/VIDEO_ID?version=3
+ // http://youtu.be/Djd6tPrxc08
+ private function getYouTubeIdFromUrl(url:String):String {
+
+
+ var youTubeId:String = "";
+
+ // remove any querystring elements
+ var parts:Array = url.split('?');
+ url = parts[0];
+
+ youTubeId = url.substring(url.lastIndexOf("/")+1);
+
+ return youTubeId;
+ }
+
+
+ // interface members
+ public function setSrc(url:String):void {
+ trace("yt setSrc()" + url );
+
+ _currentUrl = url;
+
+ _youTubeId = getYouTubeId(url);
+
+ if (!_playerIsLoaded && !_isChromeless) {
+ _playerLoader.load(new URLRequest("//www.youtube.com/v/" + _youTubeId + "?version=3&controls=0&rel=0&showinfo=0&iv_load_policy=1"));
+ }
+ }
+
+
+
+
+ public function load():void {
+ // do nothing
+ trace("yt load()");
+
+ if (_playerIsLoaded) {
+ player.loadVideoById(_youTubeId);
+ _timer.start();
+ } else {
+ /*
+ if (!_isChromless && _youTubeId != "") {
+ _playerLoader.load(new URLRequest("http://www.youtube.com/v/" + _youTubeId + "?version=3&controls=0&rel=0&showinfo=0&iv_load_policy=1"));
+ }
+ */
+ }
+ }
+
+ public function play():void {
+ if (_playerIsLoaded) {
+ _player.playVideo();
+ }
+
+ }
+
+ public function pause():void {
+ if (_playerIsLoaded) {
+ _player.pauseVideo();
+ }
+ }
+
+ public function stop():void {
+ if (_playerIsLoaded) {
+ _player.pauseVideo();
+ }
+ }
+
+ public function setCurrentTime(pos:Number):void {
+ //_player.seekTo(pos, false);
+ _player.seekTo(pos, true); // works in all places now
+ }
+
+ public function setVolume(volume:Number):void {
+ _player.setVolume(volume*100);
+ _volume = volume;
+ }
+
+ public function getVolume():Number {
+ return _player.getVolume()*100;
+ }
+
+ public function setMuted(muted:Boolean):void {
+ if (muted) {
+ _player.mute();
+
+ } else {
+ _player.unMute();
+ }
+ _isMuted = _player.isMuted();
+ sendEvent(HtmlMediaEvent.VOLUMECHANGE);
+ }
+
+
+ private function sendEvent(eventName:String) {
+
+ // calculate this to mimic HTML5
+ _bufferedTime = _bytesLoaded / _bytesTotal * _duration;
+
+ // build JSON
+ var values:String =
+ "duration:" + _duration +
+ ",framerate:" + _framerate +
+ ",currentTime:" + _currentTime +
+ ",muted:" + _isMuted +
+ ",paused:" + _isPaused +
+ ",ended:" + _isEnded +
+ ",volume:" + _volume +
+ ",src:\"" + _currentUrl + "\"" +
+ ",bytesTotal:" + _bytesTotal +
+ ",bufferedBytes:" + _bytesLoaded +
+ ",bufferedTime:" + _bufferedTime +
+ ",videoWidth:" + _videoWidth +
+ ",videoHeight:" + _videoHeight +
+ "";
+
+ _element.sendEvent(eventName, values);
+ }
+ }
+}
diff --git a/debian/missing-sources/mediaelement/test/Spec-CreateRemove.js b/debian/missing-sources/mediaelement/test/Spec-CreateRemove.js
new file mode 100644
index 0000000..8735efa
--- /dev/null
+++ b/debian/missing-sources/mediaelement/test/Spec-CreateRemove.js
@@ -0,0 +1,45 @@
+describe("HTMLMediaElement", function() {
+ var player;
+ var element;
+ var domElem;
+ var NETWORK_EMPTY = 0, NETWORK_IDLE = 1, NETWORK_LOADING = 2, NETWORK_NO_SOURCE = 3;
+ var HAVE_NOTHING = 0, HAVE_METADATA = 1, HAVE_CURRENT_DATA = 2, HAVE_FUTURE_DATA = 3, HAVE_ENOUGH_DATA = 4;
+ var METADATA_TIMEOUT = 500, ENOUGH_DATA_TIMEOUT = 1000;
+
+ beforeEach(function() {
+ });
+
+ afterEach(function() {
+ });
+
+ it("should be able to create and remove a player and clean up everything", function() {
+ runs(function() {
+ $('body').prepend('<video width="640" height="360" id="player1" poster="../media/echo-hereweare.jpg">' +
+ '<source type="video/mp4" src="../media/echo-hereweare.mp4" ></source>' +
+ '<source type="video/webm" src="../media/echo-hereweare.webm" ></source>' +
+ '</video>');
+ player = new MediaElementPlayer('#player1', {
+ enableAutosize: false,
+ success: function(mediaElement, domObject) {
+ element = mediaElement;
+ domElem = domObject;
+ }
+ });
+ });
+ waitsFor(function() {
+ return element !== null;
+ }, "MediaElement should have loaded", 5000);
+ runs(function() {
+ expect(element.pluginType).toEqual('native');
+ player.remove();
+ player = null;
+ element = null;
+ domElem.parentNode.removeChild(domElem);
+ domElem = null;
+ // Issue #670: https://github.com/johndyer/mediaelement/issues/670
+ expect(mejs.players.length).toEqual(0);
+
+ });
+ });
+
+});
diff --git a/debian/missing-sources/mediaelement/test/Spec-Player.js b/debian/missing-sources/mediaelement/test/Spec-Player.js
new file mode 100644
index 0000000..c5e6c52
--- /dev/null
+++ b/debian/missing-sources/mediaelement/test/Spec-Player.js
@@ -0,0 +1,90 @@
+describe("HTMLMediaElement", function() {
+ var player;
+ var element;
+ var domElem;
+ var NETWORK_EMPTY = 0, NETWORK_IDLE = 1, NETWORK_LOADING = 2, NETWORK_NO_SOURCE = 3;
+ var HAVE_NOTHING = 0, HAVE_METADATA = 1, HAVE_CURRENT_DATA = 2, HAVE_FUTURE_DATA = 3, HAVE_ENOUGH_DATA = 4;
+ var METADATA_TIMEOUT = 500, ENOUGH_DATA_TIMEOUT = 1000;
+
+ beforeEach(function() {
+ $('body').prepend('<video width="640" height="360" id="player1" poster="../media/echo-hereweare.jpg">' +
+ '<source type="video/mp4" src="../media/echo-hereweare.mp4" ></source>' +
+ '<source type="video/webm" src="../media/echo-hereweare.webm" ></source>' +
+ '</video>');
+ player = new MediaElementPlayer('#player1', {
+ enableAutosize: false,
+ success: function(mediaElement, domObject) {
+ element = mediaElement;
+ domElem = domObject;
+ }
+ });
+ waitsFor(function() {
+ return element !== null;
+ }, "MediaElement should have loaded", 5000);
+ });
+
+ afterEach(function() {
+ player.remove();
+ player = null;
+ element = null;
+ domElem.parentNode.removeChild(domElem);
+ domElem = null;
+ });
+
+ it("should be of pluginType native", function() {
+ expect(element.pluginType).toEqual('native');
+ });
+
+ it("should not be in Full Screen Mode", function() {
+ expect(element.isFullScreen).toEqual(false);
+ });
+
+ it("should be able to set video size", function() {
+ var expectedWidth = 200, expectedHeight = 100;
+ element.setVideoSize(expectedWidth, expectedHeight);
+ expect(element.width).toEqual(expectedWidth);
+ expect(element.height).toEqual(expectedHeight);
+ });
+
+ it("should be able to set volume", function() {
+ var expectedVolume = 0.5;
+ element.setVolume(expectedVolume);
+ expect(element.volume).toEqual(expectedVolume);
+ });
+
+ it("should be able to mute and un-mute", function() {
+ element.setMuted(true);
+ expect(element.muted).toEqual(true);
+ element.setMuted(false);
+ expect(element.muted).toEqual(false);
+ });
+
+ it("should be able to read the currentTime", function() {
+ expect(element.currentTime).toEqual(0);
+ });
+
+ it("should be able to read the paused state", function() {
+ expect(element.paused).toEqual(true);
+ });
+
+ it("should be able to set the play/paused state", function() {
+ element.play();
+ expect(element.paused).toEqual(false);
+ element.pause();
+ expect(element.paused).toEqual(true);
+ });
+
+ it("should implmenent stop() for parity with MEJS plugin versions", function() {
+ element.play();
+ expect(element.paused).toEqual(false);
+ element.stop();
+ expect(element.paused).toEqual(true);
+ });
+
+ it("should HAVE_METADATA within a timeout period", function() {
+ waitsFor(function() {
+ return element.readyState >= HAVE_METADATA;
+ }, "Metadata should be loaded", METADATA_TIMEOUT);
+ });
+
+});
diff --git a/debian/missing-sources/mediaelement/test/SpecRunner-CreateRemove.html b/debian/missing-sources/mediaelement/test/SpecRunner-CreateRemove.html
new file mode 100644
index 0000000..fb20fb6
--- /dev/null
+++ b/debian/missing-sources/mediaelement/test/SpecRunner-CreateRemove.html
@@ -0,0 +1,78 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
+ "http://www.w3.org/TR/html4/loose.dtd">
+<html>
+<head>
+ <title>Jasmine Spec Runner</title>
+
+ <link rel="shortcut icon" type="image/png" href="lib/jasmine-1.3.1/jasmine_favicon.png">
+ <link rel="stylesheet" type="text/css" href="lib/jasmine-1.3.1/jasmine.css">
+ <link rel="stylesheet" href="../build/mediaelementplayer.min.css" />
+
+ <script type="text/javascript" src="lib/jasmine-1.3.1/jasmine.js"></script>
+ <script type="text/javascript" src="lib/jasmine-1.3.1/jasmine-html.js"></script>
+
+ <script src="../build/jquery.js"></script>
+
+ <!-- include source files here... -->
+ <script src="../src/js/me-header.js"></script>
+ <script src="../src/js/me-namespace.js"></script>
+ <script src="../src/js/me-utility.js"></script>
+ <script src="../src/js/me-plugindetector.js"></script>
+ <script src="../src/js/me-featuredetection.js"></script>
+ <script src="../src/js/me-mediaelements.js"></script>
+ <script src="../src/js/me-shim.js"></script>
+ <script src="../src/js/me-i18n.js"></script>
+ <script src="../src/js/me-i18n-locale-de.js"></script>
+
+ <script src="../src/js/mep-header.js"></script>
+ <script src="../src/js/mep-library.js"></script>
+ <script src="../src/js/mep-player.js"></script>
+ <script src="../src/js/mep-feature-playpause.js"></script>
+ <script src="../src/js/mep-feature-stop.js"></script>
+ <script src="../src/js/mep-feature-progress.js"></script>
+ <script src="../src/js/mep-feature-time.js"></script>
+ <script src="../src/js/mep-feature-volume.js"></script>
+ <script src="../src/js/mep-feature-fullscreen.js"></script>
+ <script src="../src/js/mep-feature-tracks.js"></script>
+ <script src="../src/js/mep-feature-contextmenu.js"></script>
+ <script src="../src/js/mep-feature-postroll.js"></script>
+
+ <!-- include spec files here... -->
+<!-- <script src="SpecHelper.js"></script> -->
+ <script src="Spec-CreateRemove.js"></script>
+
+ <script type="text/javascript">
+ (function() {
+ var jasmineEnv = jasmine.getEnv();
+ jasmineEnv.updateInterval = 1000;
+
+ var htmlReporter = new jasmine.HtmlReporter();
+
+ jasmineEnv.addReporter(htmlReporter);
+
+ jasmineEnv.specFilter = function(spec) {
+ return htmlReporter.specFilter(spec);
+ };
+
+ var currentWindowOnload = window.onload;
+
+ window.onload = function() {
+ if (currentWindowOnload) {
+ currentWindowOnload();
+ }
+ execJasmine();
+ };
+
+ function execJasmine() {
+ jasmineEnv.execute();
+ }
+
+ })();
+ </script>
+
+</head>
+
+<body>
+ <!-- VIDEO TAG GETS PREPENDED ABOVE HERE -->
+</body>
+</html>
diff --git a/debian/missing-sources/mediaelement/test/SpecRunner-Player.html b/debian/missing-sources/mediaelement/test/SpecRunner-Player.html
new file mode 100644
index 0000000..1782504
--- /dev/null
+++ b/debian/missing-sources/mediaelement/test/SpecRunner-Player.html
@@ -0,0 +1,78 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
+ "http://www.w3.org/TR/html4/loose.dtd">
+<html>
+<head>
+ <title>Jasmine Spec Runner</title>
+
+ <link rel="shortcut icon" type="image/png" href="lib/jasmine-1.3.1/jasmine_favicon.png">
+ <link rel="stylesheet" type="text/css" href="lib/jasmine-1.3.1/jasmine.css">
+ <link rel="stylesheet" href="../build/mediaelementplayer.min.css" />
+
+ <script type="text/javascript" src="lib/jasmine-1.3.1/jasmine.js"></script>
+ <script type="text/javascript" src="lib/jasmine-1.3.1/jasmine-html.js"></script>
+
+ <script src="../build/jquery.js"></script>
+
+ <!-- include source files here... -->
+ <script src="../src/js/me-header.js"></script>
+ <script src="../src/js/me-namespace.js"></script>
+ <script src="../src/js/me-utility.js"></script>
+ <script src="../src/js/me-plugindetector.js"></script>
+ <script src="../src/js/me-featuredetection.js"></script>
+ <script src="../src/js/me-mediaelements.js"></script>
+ <script src="../src/js/me-shim.js"></script>
+ <script src="../src/js/me-i18n.js"></script>
+ <script src="../src/js/me-i18n-locale-de.js"></script>
+
+ <script src="../src/js/mep-header.js"></script>
+ <script src="../src/js/mep-library.js"></script>
+ <script src="../src/js/mep-player.js"></script>
+ <script src="../src/js/mep-feature-playpause.js"></script>
+ <script src="../src/js/mep-feature-stop.js"></script>
+ <script src="../src/js/mep-feature-progress.js"></script>
+ <script src="../src/js/mep-feature-time.js"></script>
+ <script src="../src/js/mep-feature-volume.js"></script>
+ <script src="../src/js/mep-feature-fullscreen.js"></script>
+ <script src="../src/js/mep-feature-tracks.js"></script>
+ <script src="../src/js/mep-feature-contextmenu.js"></script>
+ <script src="../src/js/mep-feature-postroll.js"></script>
+
+ <!-- include spec files here... -->
+<!-- <script src="SpecHelper.js"></script> -->
+ <script src="Spec-Player.js"></script>
+
+ <script type="text/javascript">
+ (function() {
+ var jasmineEnv = jasmine.getEnv();
+ jasmineEnv.updateInterval = 1000;
+
+ var htmlReporter = new jasmine.HtmlReporter();
+
+ jasmineEnv.addReporter(htmlReporter);
+
+ jasmineEnv.specFilter = function(spec) {
+ return htmlReporter.specFilter(spec);
+ };
+
+ var currentWindowOnload = window.onload;
+
+ window.onload = function() {
+ if (currentWindowOnload) {
+ currentWindowOnload();
+ }
+ execJasmine();
+ };
+
+ function execJasmine() {
+ jasmineEnv.execute();
+ }
+
+ })();
+ </script>
+
+</head>
+
+<body>
+ <!-- VIDEO TAG GETS PREPENDED ABOVE HERE -->
+</body>
+</html>
diff --git a/debian/missing-sources/mediaelement/test/lib/jasmine-1.3.1/MIT.LICENSE b/debian/missing-sources/mediaelement/test/lib/jasmine-1.3.1/MIT.LICENSE
new file mode 100644
index 0000000..7c435ba
--- /dev/null
+++ b/debian/missing-sources/mediaelement/test/lib/jasmine-1.3.1/MIT.LICENSE
@@ -0,0 +1,20 @@
+Copyright (c) 2008-2011 Pivotal Labs
+
+Permission is hereby granted, free of charge, to any person obtaining
+a copy of this software and associated documentation files (the
+"Software"), to deal in the Software without restriction, including
+without limitation the rights to use, copy, modify, merge, publish,
+distribute, sublicense, and/or sell copies of the Software, and to
+permit persons to whom the Software is furnished to do so, subject to
+the following conditions:
+
+The above copyright notice and this permission notice shall be
+included in all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
diff --git a/debian/missing-sources/mediaelement/test/lib/jasmine-1.3.1/jasmine-html.js b/debian/missing-sources/mediaelement/test/lib/jasmine-1.3.1/jasmine-html.js
new file mode 100644
index 0000000..543d569
--- /dev/null
+++ b/debian/missing-sources/mediaelement/test/lib/jasmine-1.3.1/jasmine-html.js
@@ -0,0 +1,681 @@
+jasmine.HtmlReporterHelpers = {};
+
+jasmine.HtmlReporterHelpers.createDom = function(type, attrs, childrenVarArgs) {
+ var el = document.createElement(type);
+
+ for (var i = 2; i < arguments.length; i++) {
+ var child = arguments[i];
+
+ if (typeof child === 'string') {
+ el.appendChild(document.createTextNode(child));
+ } else {
+ if (child) {
+ el.appendChild(child);
+ }
+ }
+ }
+
+ for (var attr in attrs) {
+ if (attr == "className") {
+ el[attr] = attrs[attr];
+ } else {
+ el.setAttribute(attr, attrs[attr]);
+ }
+ }
+
+ return el;
+};
+
+jasmine.HtmlReporterHelpers.getSpecStatus = function(child) {
+ var results = child.results();
+ var status = results.passed() ? 'passed' : 'failed';
+ if (results.skipped) {
+ status = 'skipped';
+ }
+
+ return status;
+};
+
+jasmine.HtmlReporterHelpers.appendToSummary = function(child, childElement) {
+ var parentDiv = this.dom.summary;
+ var parentSuite = (typeof child.parentSuite == 'undefined') ? 'suite' : 'parentSuite';
+ var parent = child[parentSuite];
+
+ if (parent) {
+ if (typeof this.views.suites[parent.id] == 'undefined') {
+ this.views.suites[parent.id] = new jasmine.HtmlReporter.SuiteView(parent, this.dom, this.views);
+ }
+ parentDiv = this.views.suites[parent.id].element;
+ }
+
+ parentDiv.appendChild(childElement);
+};
+
+
+jasmine.HtmlReporterHelpers.addHelpers = function(ctor) {
+ for(var fn in jasmine.HtmlReporterHelpers) {
+ ctor.prototype[fn] = jasmine.HtmlReporterHelpers[fn];
+ }
+};
+
+jasmine.HtmlReporter = function(_doc) {
+ var self = this;
+ var doc = _doc || window.document;
+
+ var reporterView;
+
+ var dom = {};
+
+ // Jasmine Reporter Public Interface
+ self.logRunningSpecs = false;
+
+ self.reportRunnerStarting = function(runner) {
+ var specs = runner.specs() || [];
+
+ if (specs.length == 0) {
+ return;
+ }
+
+ createReporterDom(runner.env.versionString());
+ doc.body.appendChild(dom.reporter);
+ setExceptionHandling();
+
+ reporterView = new jasmine.HtmlReporter.ReporterView(dom);
+ reporterView.addSpecs(specs, self.specFilter);
+ };
+
+ self.reportRunnerResults = function(runner) {
+ reporterView && reporterView.complete();
+ };
+
+ self.reportSuiteResults = function(suite) {
+ reporterView.suiteComplete(suite);
+ };
+
+ self.reportSpecStarting = function(spec) {
+ if (self.logRunningSpecs) {
+ self.log('>> Jasmine Running ' + spec.suite.description + ' ' + spec.description + '...');
+ }
+ };
+
+ self.reportSpecResults = function(spec) {
+ reporterView.specComplete(spec);
+ };
+
+ self.log = function() {
+ var console = jasmine.getGlobal().console;
+ if (console && console.log) {
+ if (console.log.apply) {
+ console.log.apply(console, arguments);
+ } else {
+ console.log(arguments); // ie fix: console.log.apply doesn't exist on ie
+ }
+ }
+ };
+
+ self.specFilter = function(spec) {
+ if (!focusedSpecName()) {
+ return true;
+ }
+
+ return spec.getFullName().indexOf(focusedSpecName()) === 0;
+ };
+
+ return self;
+
+ function focusedSpecName() {
+ var specName;
+
+ (function memoizeFocusedSpec() {
+ if (specName) {
+ return;
+ }
+
+ var paramMap = [];
+ var params = jasmine.HtmlReporter.parameters(doc);
+
+ for (var i = 0; i < params.length; i++) {
+ var p = params[i].split('=');
+ paramMap[decodeURIComponent(p[0])] = decodeURIComponent(p[1]);
+ }
+
+ specName = paramMap.spec;
+ })();
+
+ return specName;
+ }
+
+ function createReporterDom(version) {
+ dom.reporter = self.createDom('div', { id: 'HTMLReporter', className: 'jasmine_reporter' },
+ dom.banner = self.createDom('div', { className: 'banner' },
+ self.createDom('span', { className: 'title' }, "Jasmine "),
+ self.createDom('span', { className: 'version' }, version)),
+
+ dom.symbolSummary = self.createDom('ul', {className: 'symbolSummary'}),
+ dom.alert = self.createDom('div', {className: 'alert'},
+ self.createDom('span', { className: 'exceptions' },
+ self.createDom('label', { className: 'label', 'for': 'no_try_catch' }, 'No try/catch'),
+ self.createDom('input', { id: 'no_try_catch', type: 'checkbox' }))),
+ dom.results = self.createDom('div', {className: 'results'},
+ dom.summary = self.createDom('div', { className: 'summary' }),
+ dom.details = self.createDom('div', { id: 'details' }))
+ );
+ }
+
+ function noTryCatch() {
+ return window.location.search.match(/catch=false/);
+ }
+
+ function searchWithCatch() {
+ var params = jasmine.HtmlReporter.parameters(window.document);
+ var removed = false;
+ var i = 0;
+
+ while (!removed && i < params.length) {
+ if (params[i].match(/catch=/)) {
+ params.splice(i, 1);
+ removed = true;
+ }
+ i++;
+ }
+ if (jasmine.CATCH_EXCEPTIONS) {
+ params.push("catch=false");
+ }
+
+ return params.join("&");
+ }
+
+ function setExceptionHandling() {
+ var chxCatch = document.getElementById('no_try_catch');
+
+ if (noTryCatch()) {
+ chxCatch.setAttribute('checked', true);
+ jasmine.CATCH_EXCEPTIONS = false;
+ }
+ chxCatch.onclick = function() {
+ window.location.search = searchWithCatch();
+ };
+ }
+};
+jasmine.HtmlReporter.parameters = function(doc) {
+ var paramStr = doc.location.search.substring(1);
+ var params = [];
+
+ if (paramStr.length > 0) {
+ params = paramStr.split('&');
+ }
+ return params;
+}
+jasmine.HtmlReporter.sectionLink = function(sectionName) {
+ var link = '?';
+ var params = [];
+
+ if (sectionName) {
+ params.push('spec=' + encodeURIComponent(sectionName));
+ }
+ if (!jasmine.CATCH_EXCEPTIONS) {
+ params.push("catch=false");
+ }
+ if (params.length > 0) {
+ link += params.join("&");
+ }
+
+ return link;
+};
+jasmine.HtmlReporterHelpers.addHelpers(jasmine.HtmlReporter);
+jasmine.HtmlReporter.ReporterView = function(dom) {
+ this.startedAt = new Date();
+ this.runningSpecCount = 0;
+ this.completeSpecCount = 0;
+ this.passedCount = 0;
+ this.failedCount = 0;
+ this.skippedCount = 0;
+
+ this.createResultsMenu = function() {
+ this.resultsMenu = this.createDom('span', {className: 'resultsMenu bar'},
+ this.summaryMenuItem = this.createDom('a', {className: 'summaryMenuItem', href: "#"}, '0 specs'),
+ ' | ',
+ this.detailsMenuItem = this.createDom('a', {className: 'detailsMenuItem', href: "#"}, '0 failing'));
+
+ this.summaryMenuItem.onclick = function() {
+ dom.reporter.className = dom.reporter.className.replace(/ showDetails/g, '');
+ };
+
+ this.detailsMenuItem.onclick = function() {
+ showDetails();
+ };
+ };
+
+ this.addSpecs = function(specs, specFilter) {
+ this.totalSpecCount = specs.length;
+
+ this.views = {
+ specs: {},
+ suites: {}
+ };
+
+ for (var i = 0; i < specs.length; i++) {
+ var spec = specs[i];
+ this.views.specs[spec.id] = new jasmine.HtmlReporter.SpecView(spec, dom, this.views);
+ if (specFilter(spec)) {
+ this.runningSpecCount++;
+ }
+ }
+ };
+
+ this.specComplete = function(spec) {
+ this.completeSpecCount++;
+
+ if (isUndefined(this.views.specs[spec.id])) {
+ this.views.specs[spec.id] = new jasmine.HtmlReporter.SpecView(spec, dom);
+ }
+
+ var specView = this.views.specs[spec.id];
+
+ switch (specView.status()) {
+ case 'passed':
+ this.passedCount++;
+ break;
+
+ case 'failed':
+ this.failedCount++;
+ break;
+
+ case 'skipped':
+ this.skippedCount++;
+ break;
+ }
+
+ specView.refresh();
+ this.refresh();
+ };
+
+ this.suiteComplete = function(suite) {
+ var suiteView = this.views.suites[suite.id];
+ if (isUndefined(suiteView)) {
+ return;
+ }
+ suiteView.refresh();
+ };
+
+ this.refresh = function() {
+
+ if (isUndefined(this.resultsMenu)) {
+ this.createResultsMenu();
+ }
+
+ // currently running UI
+ if (isUndefined(this.runningAlert)) {
+ this.runningAlert = this.createDom('a', { href: jasmine.HtmlReporter.sectionLink(), className: "runningAlert bar" });
+ dom.alert.appendChild(this.runningAlert);
+ }
+ this.runningAlert.innerHTML = "Running " + this.completeSpecCount + " of " + specPluralizedFor(this.totalSpecCount);
+
+ // skipped specs UI
+ if (isUndefined(this.skippedAlert)) {
+ this.skippedAlert = this.createDom('a', { href: jasmine.HtmlReporter.sectionLink(), className: "skippedAlert bar" });
+ }
+
+ this.skippedAlert.innerHTML = "Skipping " + this.skippedCount + " of " + specPluralizedFor(this.totalSpecCount) + " - run all";
+
+ if (this.skippedCount === 1 && isDefined(dom.alert)) {
+ dom.alert.appendChild(this.skippedAlert);
+ }
+
+ // passing specs UI
+ if (isUndefined(this.passedAlert)) {
+ this.passedAlert = this.createDom('span', { href: jasmine.HtmlReporter.sectionLink(), className: "passingAlert bar" });
+ }
+ this.passedAlert.innerHTML = "Passing " + specPluralizedFor(this.passedCount);
+
+ // failing specs UI
+ if (isUndefined(this.failedAlert)) {
+ this.failedAlert = this.createDom('span', {href: "?", className: "failingAlert bar"});
+ }
+ this.failedAlert.innerHTML = "Failing " + specPluralizedFor(this.failedCount);
+
+ if (this.failedCount === 1 && isDefined(dom.alert)) {
+ dom.alert.appendChild(this.failedAlert);
+ dom.alert.appendChild(this.resultsMenu);
+ }
+
+ // summary info
+ this.summaryMenuItem.innerHTML = "" + specPluralizedFor(this.runningSpecCount);
+ this.detailsMenuItem.innerHTML = "" + this.failedCount + " failing";
+ };
+
+ this.complete = function() {
+ dom.alert.removeChild(this.runningAlert);
+
+ this.skippedAlert.innerHTML = "Ran " + this.runningSpecCount + " of " + specPluralizedFor(this.totalSpecCount) + " - run all";
+
+ if (this.failedCount === 0) {
+ dom.alert.appendChild(this.createDom('span', {className: 'passingAlert bar'}, "Passing " + specPluralizedFor(this.passedCount)));
+ } else {
+ showDetails();
+ }
+
+ dom.banner.appendChild(this.createDom('span', {className: 'duration'}, "finished in " + ((new Date().getTime() - this.startedAt.getTime()) / 1000) + "s"));
+ };
+
+ return this;
+
+ function showDetails() {
+ if (dom.reporter.className.search(/showDetails/) === -1) {
+ dom.reporter.className += " showDetails";
+ }
+ }
+
+ function isUndefined(obj) {
+ return typeof obj === 'undefined';
+ }
+
+ function isDefined(obj) {
+ return !isUndefined(obj);
+ }
+
+ function specPluralizedFor(count) {
+ var str = count + " spec";
+ if (count > 1) {
+ str += "s"
+ }
+ return str;
+ }
+
+};
+
+jasmine.HtmlReporterHelpers.addHelpers(jasmine.HtmlReporter.ReporterView);
+
+
+jasmine.HtmlReporter.SpecView = function(spec, dom, views) {
+ this.spec = spec;
+ this.dom = dom;
+ this.views = views;
+
+ this.symbol = this.createDom('li', { className: 'pending' });
+ this.dom.symbolSummary.appendChild(this.symbol);
+
+ this.summary = this.createDom('div', { className: 'specSummary' },
+ this.createDom('a', {
+ className: 'description',
+ href: jasmine.HtmlReporter.sectionLink(this.spec.getFullName()),
+ title: this.spec.getFullName()
+ }, this.spec.description)
+ );
+
+ this.detail = this.createDom('div', { className: 'specDetail' },
+ this.createDom('a', {
+ className: 'description',
+ href: '?spec=' + encodeURIComponent(this.spec.getFullName()),
+ title: this.spec.getFullName()
+ }, this.spec.getFullName())
+ );
+};
+
+jasmine.HtmlReporter.SpecView.prototype.status = function() {
+ return this.getSpecStatus(this.spec);
+};
+
+jasmine.HtmlReporter.SpecView.prototype.refresh = function() {
+ this.symbol.className = this.status();
+
+ switch (this.status()) {
+ case 'skipped':
+ break;
+
+ case 'passed':
+ this.appendSummaryToSuiteDiv();
+ break;
+
+ case 'failed':
+ this.appendSummaryToSuiteDiv();
+ this.appendFailureDetail();
+ break;
+ }
+};
+
+jasmine.HtmlReporter.SpecView.prototype.appendSummaryToSuiteDiv = function() {
+ this.summary.className += ' ' + this.status();
+ this.appendToSummary(this.spec, this.summary);
+};
+
+jasmine.HtmlReporter.SpecView.prototype.appendFailureDetail = function() {
+ this.detail.className += ' ' + this.status();
+
+ var resultItems = this.spec.results().getItems();
+ var messagesDiv = this.createDom('div', { className: 'messages' });
+
+ for (var i = 0; i < resultItems.length; i++) {
+ var result = resultItems[i];
+
+ if (result.type == 'log') {
+ messagesDiv.appendChild(this.createDom('div', {className: 'resultMessage log'}, result.toString()));
+ } else if (result.type == 'expect' && result.passed && !result.passed()) {
+ messagesDiv.appendChild(this.createDom('div', {className: 'resultMessage fail'}, result.message));
+
+ if (result.trace.stack) {
+ messagesDiv.appendChild(this.createDom('div', {className: 'stackTrace'}, result.trace.stack));
+ }
+ }
+ }
+
+ if (messagesDiv.childNodes.length > 0) {
+ this.detail.appendChild(messagesDiv);
+ this.dom.details.appendChild(this.detail);
+ }
+};
+
+jasmine.HtmlReporterHelpers.addHelpers(jasmine.HtmlReporter.SpecView);jasmine.HtmlReporter.SuiteView = function(suite, dom, views) {
+ this.suite = suite;
+ this.dom = dom;
+ this.views = views;
+
+ this.element = this.createDom('div', { className: 'suite' },
+ this.createDom('a', { className: 'description', href: jasmine.HtmlReporter.sectionLink(this.suite.getFullName()) }, this.suite.description)
+ );
+
+ this.appendToSummary(this.suite, this.element);
+};
+
+jasmine.HtmlReporter.SuiteView.prototype.status = function() {
+ return this.getSpecStatus(this.suite);
+};
+
+jasmine.HtmlReporter.SuiteView.prototype.refresh = function() {
+ this.element.className += " " + this.status();
+};
+
+jasmine.HtmlReporterHelpers.addHelpers(jasmine.HtmlReporter.SuiteView);
+
+/* @deprecated Use jasmine.HtmlReporter instead
+ */
+jasmine.TrivialReporter = function(doc) {
+ this.document = doc || document;
+ this.suiteDivs = {};
+ this.logRunningSpecs = false;
+};
+
+jasmine.TrivialReporter.prototype.createDom = function(type, attrs, childrenVarArgs) {
+ var el = document.createElement(type);
+
+ for (var i = 2; i < arguments.length; i++) {
+ var child = arguments[i];
+
+ if (typeof child === 'string') {
+ el.appendChild(document.createTextNode(child));
+ } else {
+ if (child) { el.appendChild(child); }
+ }
+ }
+
+ for (var attr in attrs) {
+ if (attr == "className") {
+ el[attr] = attrs[attr];
+ } else {
+ el.setAttribute(attr, attrs[attr]);
+ }
+ }
+
+ return el;
+};
+
+jasmine.TrivialReporter.prototype.reportRunnerStarting = function(runner) {
+ var showPassed, showSkipped;
+
+ this.outerDiv = this.createDom('div', { id: 'TrivialReporter', className: 'jasmine_reporter' },
+ this.createDom('div', { className: 'banner' },
+ this.createDom('div', { className: 'logo' },
+ this.createDom('span', { className: 'title' }, "Jasmine"),
+ this.createDom('span', { className: 'version' }, runner.env.versionString())),
+ this.createDom('div', { className: 'options' },
+ "Show ",
+ showPassed = this.createDom('input', { id: "__jasmine_TrivialReporter_showPassed__", type: 'checkbox' }),
+ this.createDom('label', { "for": "__jasmine_TrivialReporter_showPassed__" }, " passed "),
+ showSkipped = this.createDom('input', { id: "__jasmine_TrivialReporter_showSkipped__", type: 'checkbox' }),
+ this.createDom('label', { "for": "__jasmine_TrivialReporter_showSkipped__" }, " skipped")
+ )
+ ),
+
+ this.runnerDiv = this.createDom('div', { className: 'runner running' },
+ this.createDom('a', { className: 'run_spec', href: '?' }, "run all"),
+ this.runnerMessageSpan = this.createDom('span', {}, "Running..."),
+ this.finishedAtSpan = this.createDom('span', { className: 'finished-at' }, ""))
+ );
+
+ this.document.body.appendChild(this.outerDiv);
+
+ var suites = runner.suites();
+ for (var i = 0; i < suites.length; i++) {
+ var suite = suites[i];
+ var suiteDiv = this.createDom('div', { className: 'suite' },
+ this.createDom('a', { className: 'run_spec', href: '?spec=' + encodeURIComponent(suite.getFullName()) }, "run"),
+ this.createDom('a', { className: 'description', href: '?spec=' + encodeURIComponent(suite.getFullName()) }, suite.description));
+ this.suiteDivs[suite.id] = suiteDiv;
+ var parentDiv = this.outerDiv;
+ if (suite.parentSuite) {
+ parentDiv = this.suiteDivs[suite.parentSuite.id];
+ }
+ parentDiv.appendChild(suiteDiv);
+ }
+
+ this.startedAt = new Date();
+
+ var self = this;
+ showPassed.onclick = function(evt) {
+ if (showPassed.checked) {
+ self.outerDiv.className += ' show-passed';
+ } else {
+ self.outerDiv.className = self.outerDiv.className.replace(/ show-passed/, '');
+ }
+ };
+
+ showSkipped.onclick = function(evt) {
+ if (showSkipped.checked) {
+ self.outerDiv.className += ' show-skipped';
+ } else {
+ self.outerDiv.className = self.outerDiv.className.replace(/ show-skipped/, '');
+ }
+ };
+};
+
+jasmine.TrivialReporter.prototype.reportRunnerResults = function(runner) {
+ var results = runner.results();
+ var className = (results.failedCount > 0) ? "runner failed" : "runner passed";
+ this.runnerDiv.setAttribute("class", className);
+ //do it twice for IE
+ this.runnerDiv.setAttribute("className", className);
+ var specs = runner.specs();
+ var specCount = 0;
+ for (var i = 0; i < specs.length; i++) {
+ if (this.specFilter(specs[i])) {
+ specCount++;
+ }
+ }
+ var message = "" + specCount + " spec" + (specCount == 1 ? "" : "s" ) + ", " + results.failedCount + " failure" + ((results.failedCount == 1) ? "" : "s");
+ message += " in " + ((new Date().getTime() - this.startedAt.getTime()) / 1000) + "s";
+ this.runnerMessageSpan.replaceChild(this.createDom('a', { className: 'description', href: '?'}, message), this.runnerMessageSpan.firstChild);
+
+ this.finishedAtSpan.appendChild(document.createTextNode("Finished at " + new Date().toString()));
+};
+
+jasmine.TrivialReporter.prototype.reportSuiteResults = function(suite) {
+ var results = suite.results();
+ var status = results.passed() ? 'passed' : 'failed';
+ if (results.totalCount === 0) { // todo: change this to check results.skipped
+ status = 'skipped';
+ }
+ this.suiteDivs[suite.id].className += " " + status;
+};
+
+jasmine.TrivialReporter.prototype.reportSpecStarting = function(spec) {
+ if (this.logRunningSpecs) {
+ this.log('>> Jasmine Running ' + spec.suite.description + ' ' + spec.description + '...');
+ }
+};
+
+jasmine.TrivialReporter.prototype.reportSpecResults = function(spec) {
+ var results = spec.results();
+ var status = results.passed() ? 'passed' : 'failed';
+ if (results.skipped) {
+ status = 'skipped';
+ }
+ var specDiv = this.createDom('div', { className: 'spec ' + status },
+ this.createDom('a', { className: 'run_spec', href: '?spec=' + encodeURIComponent(spec.getFullName()) }, "run"),
+ this.createDom('a', {
+ className: 'description',
+ href: '?spec=' + encodeURIComponent(spec.getFullName()),
+ title: spec.getFullName()
+ }, spec.description));
+
+
+ var resultItems = results.getItems();
+ var messagesDiv = this.createDom('div', { className: 'messages' });
+ for (var i = 0; i < resultItems.length; i++) {
+ var result = resultItems[i];
+
+ if (result.type == 'log') {
+ messagesDiv.appendChild(this.createDom('div', {className: 'resultMessage log'}, result.toString()));
+ } else if (result.type == 'expect' && result.passed && !result.passed()) {
+ messagesDiv.appendChild(this.createDom('div', {className: 'resultMessage fail'}, result.message));
+
+ if (result.trace.stack) {
+ messagesDiv.appendChild(this.createDom('div', {className: 'stackTrace'}, result.trace.stack));
+ }
+ }
+ }
+
+ if (messagesDiv.childNodes.length > 0) {
+ specDiv.appendChild(messagesDiv);
+ }
+
+ this.suiteDivs[spec.suite.id].appendChild(specDiv);
+};
+
+jasmine.TrivialReporter.prototype.log = function() {
+ var console = jasmine.getGlobal().console;
+ if (console && console.log) {
+ if (console.log.apply) {
+ console.log.apply(console, arguments);
+ } else {
+ console.log(arguments); // ie fix: console.log.apply doesn't exist on ie
+ }
+ }
+};
+
+jasmine.TrivialReporter.prototype.getLocation = function() {
+ return this.document.location;
+};
+
+jasmine.TrivialReporter.prototype.specFilter = function(spec) {
+ var paramMap = {};
+ var params = this.getLocation().search.substring(1).split('&');
+ for (var i = 0; i < params.length; i++) {
+ var p = params[i].split('=');
+ paramMap[decodeURIComponent(p[0])] = decodeURIComponent(p[1]);
+ }
+
+ if (!paramMap.spec) {
+ return true;
+ }
+ return spec.getFullName().indexOf(paramMap.spec) === 0;
+};
diff --git a/debian/missing-sources/mediaelement/test/lib/jasmine-1.3.1/jasmine.css b/debian/missing-sources/mediaelement/test/lib/jasmine-1.3.1/jasmine.css
new file mode 100644
index 0000000..8c008dc
--- /dev/null
+++ b/debian/missing-sources/mediaelement/test/lib/jasmine-1.3.1/jasmine.css
@@ -0,0 +1,82 @@
+body { background-color: #eeeeee; padding: 0; margin: 5px; overflow-y: scroll; }
+
+#HTMLReporter { font-size: 11px; font-family: Monaco, "Lucida Console", monospace; line-height: 14px; color: #333333; }
+#HTMLReporter a { text-decoration: none; }
+#HTMLReporter a:hover { text-decoration: underline; }
+#HTMLReporter p, #HTMLReporter h1, #HTMLReporter h2, #HTMLReporter h3, #HTMLReporter h4, #HTMLReporter h5, #HTMLReporter h6 { margin: 0; line-height: 14px; }
+#HTMLReporter .banner, #HTMLReporter .symbolSummary, #HTMLReporter .summary, #HTMLReporter .resultMessage, #HTMLReporter .specDetail .description, #HTMLReporter .alert .bar, #HTMLReporter .stackTrace { padding-left: 9px; padding-right: 9px; }
+#HTMLReporter #jasmine_content { position: fixed; right: 100%; }
+#HTMLReporter .version { color: #aaaaaa; }
+#HTMLReporter .banner { margin-top: 14px; }
+#HTMLReporter .duration { color: #aaaaaa; float: right; }
+#HTMLReporter .symbolSummary { overflow: hidden; *zoom: 1; margin: 14px 0; }
+#HTMLReporter .symbolSummary li { display: block; float: left; height: 7px; width: 14px; margin-bottom: 7px; font-size: 16px; }
+#HTMLReporter .symbolSummary li.passed { font-size: 14px; }
+#HTMLReporter .symbolSummary li.passed:before { color: #5e7d00; content: "\02022"; }
+#HTMLReporter .symbolSummary li.failed { line-height: 9px; }
+#HTMLReporter .symbolSummary li.failed:before { color: #b03911; content: "x"; font-weight: bold; margin-left: -1px; }
+#HTMLReporter .symbolSummary li.skipped { font-size: 14px; }
+#HTMLReporter .symbolSummary li.skipped:before { color: #bababa; content: "\02022"; }
+#HTMLReporter .symbolSummary li.pending { line-height: 11px; }
+#HTMLReporter .symbolSummary li.pending:before { color: #aaaaaa; content: "-"; }
+#HTMLReporter .exceptions { color: #fff; float: right; margin-top: 5px; margin-right: 5px; }
+#HTMLReporter .bar { line-height: 28px; font-size: 14px; display: block; color: #eee; }
+#HTMLReporter .runningAlert { background-color: #666666; }
+#HTMLReporter .skippedAlert { background-color: #aaaaaa; }
+#HTMLReporter .skippedAlert:first-child { background-color: #333333; }
+#HTMLReporter .skippedAlert:hover { text-decoration: none; color: white; text-decoration: underline; }
+#HTMLReporter .passingAlert { background-color: #a6b779; }
+#HTMLReporter .passingAlert:first-child { background-color: #5e7d00; }
+#HTMLReporter .failingAlert { background-color: #cf867e; }
+#HTMLReporter .failingAlert:first-child { background-color: #b03911; }
+#HTMLReporter .results { margin-top: 14px; }
+#HTMLReporter #details { display: none; }
+#HTMLReporter .resultsMenu, #HTMLReporter .resultsMenu a { background-color: #fff; color: #333333; }
+#HTMLReporter.showDetails .summaryMenuItem { font-weight: normal; text-decoration: inherit; }
+#HTMLReporter.showDetails .summaryMenuItem:hover { text-decoration: underline; }
+#HTMLReporter.showDetails .detailsMenuItem { font-weight: bold; text-decoration: underline; }
+#HTMLReporter.showDetails .summary { display: none; }
+#HTMLReporter.showDetails #details { display: block; }
+#HTMLReporter .summaryMenuItem { font-weight: bold; text-decoration: underline; }
+#HTMLReporter .summary { margin-top: 14px; }
+#HTMLReporter .summary .suite .suite, #HTMLReporter .summary .specSummary { margin-left: 14px; }
+#HTMLReporter .summary .specSummary.passed a { color: #5e7d00; }
+#HTMLReporter .summary .specSummary.failed a { color: #b03911; }
+#HTMLReporter .description + .suite { margin-top: 0; }
+#HTMLReporter .suite { margin-top: 14px; }
+#HTMLReporter .suite a { color: #333333; }
+#HTMLReporter #details .specDetail { margin-bottom: 28px; }
+#HTMLReporter #details .specDetail .description { display: block; color: white; background-color: #b03911; }
+#HTMLReporter .resultMessage { padding-top: 14px; color: #333333; }
+#HTMLReporter .resultMessage span.result { display: block; }
+#HTMLReporter .stackTrace { margin: 5px 0 0 0; max-height: 224px; overflow: auto; line-height: 18px; color: #666666; border: 1px solid #ddd; background: white; white-space: pre; }
+
+#TrivialReporter { padding: 8px 13px; position: absolute; top: 0; bottom: 0; left: 0; right: 0; overflow-y: scroll; background-color: white; font-family: "Helvetica Neue Light", "Lucida Grande", "Calibri", "Arial", sans-serif; /*.resultMessage {*/ /*white-space: pre;*/ /*}*/ }
+#TrivialReporter a:visited, #TrivialReporter a { color: #303; }
+#TrivialReporter a:hover, #TrivialReporter a:active { color: blue; }
+#TrivialReporter .run_spec { float: right; padding-right: 5px; font-size: .8em; text-decoration: none; }
+#TrivialReporter .banner { color: #303; background-color: #fef; padding: 5px; }
+#TrivialReporter .logo { float: left; font-size: 1.1em; padding-left: 5px; }
+#TrivialReporter .logo .version { font-size: .6em; padding-left: 1em; }
+#TrivialReporter .runner.running { background-color: yellow; }
+#TrivialReporter .options { text-align: right; font-size: .8em; }
+#TrivialReporter .suite { border: 1px outset gray; margin: 5px 0; padding-left: 1em; }
+#TrivialReporter .suite .suite { margin: 5px; }
+#TrivialReporter .suite.passed { background-color: #dfd; }
+#TrivialReporter .suite.failed { background-color: #fdd; }
+#TrivialReporter .spec { margin: 5px; padding-left: 1em; clear: both; }
+#TrivialReporter .spec.failed, #TrivialReporter .spec.passed, #TrivialReporter .spec.skipped { padding-bottom: 5px; border: 1px solid gray; }
+#TrivialReporter .spec.failed { background-color: #fbb; border-color: red; }
+#TrivialReporter .spec.passed { background-color: #bfb; border-color: green; }
+#TrivialReporter .spec.skipped { background-color: #bbb; }
+#TrivialReporter .messages { border-left: 1px dashed gray; padding-left: 1em; padding-right: 1em; }
+#TrivialReporter .passed { background-color: #cfc; display: none; }
+#TrivialReporter .failed { background-color: #fbb; }
+#TrivialReporter .skipped { color: #777; background-color: #eee; display: none; }
+#TrivialReporter .resultMessage span.result { display: block; line-height: 2em; color: black; }
+#TrivialReporter .resultMessage .mismatch { color: black; }
+#TrivialReporter .stackTrace { white-space: pre; font-size: .8em; margin-left: 10px; max-height: 5em; overflow: auto; border: 1px inset red; padding: 1em; background: #eef; }
+#TrivialReporter .finished-at { padding-left: 1em; font-size: .6em; }
+#TrivialReporter.show-passed .passed, #TrivialReporter.show-skipped .skipped { display: block; }
+#TrivialReporter #jasmine_content { position: fixed; right: 100%; }
+#TrivialReporter .runner { border: 1px solid gray; display: block; margin: 5px 0; padding: 2px 0 2px 10px; }
diff --git a/debian/missing-sources/mediaelement/test/lib/jasmine-1.3.1/jasmine.js b/debian/missing-sources/mediaelement/test/lib/jasmine-1.3.1/jasmine.js
new file mode 100644
index 0000000..6b3459b
--- /dev/null
+++ b/debian/missing-sources/mediaelement/test/lib/jasmine-1.3.1/jasmine.js
@@ -0,0 +1,2600 @@
+var isCommonJS = typeof window == "undefined" && typeof exports == "object";
+
+/**
+ * Top level namespace for Jasmine, a lightweight JavaScript BDD/spec/testing framework.
+ *
+ * @namespace
+ */
+var jasmine = {};
+if (isCommonJS) exports.jasmine = jasmine;
+/**
+ * @private
+ */
+jasmine.unimplementedMethod_ = function() {
+ throw new Error("unimplemented method");
+};
+
+/**
+ * Use <code>jasmine.undefined</code> instead of <code>undefined</code>, since <code>undefined</code> is just
+ * a plain old variable and may be redefined by somebody else.
+ *
+ * @private
+ */
+jasmine.undefined = jasmine.___undefined___;
+
+/**
+ * Show diagnostic messages in the console if set to true
+ *
+ */
+jasmine.VERBOSE = false;
+
+/**
+ * Default interval in milliseconds for event loop yields (e.g. to allow network activity or to refresh the screen with the HTML-based runner). Small values here may result in slow test running. Zero means no updates until all tests have completed.
+ *
+ */
+jasmine.DEFAULT_UPDATE_INTERVAL = 250;
+
+/**
+ * Maximum levels of nesting that will be included when an object is pretty-printed
+ */
+jasmine.MAX_PRETTY_PRINT_DEPTH = 40;
+
+/**
+ * Default timeout interval in milliseconds for waitsFor() blocks.
+ */
+jasmine.DEFAULT_TIMEOUT_INTERVAL = 5000;
+
+/**
+ * By default exceptions thrown in the context of a test are caught by jasmine so that it can run the remaining tests in the suite.
+ * Set to false to let the exception bubble up in the browser.
+ *
+ */
+jasmine.CATCH_EXCEPTIONS = true;
+
+jasmine.getGlobal = function() {
+ function getGlobal() {
+ return this;
+ }
+
+ return getGlobal();
+};
+
+/**
+ * Allows for bound functions to be compared. Internal use only.
+ *
+ * @ignore
+ * @private
+ * @param base {Object} bound 'this' for the function
+ * @param name {Function} function to find
+ */
+jasmine.bindOriginal_ = function(base, name) {
+ var original = base[name];
+ if (original.apply) {
+ return function() {
+ return original.apply(base, arguments);
+ };
+ } else {
+ // IE support
+ return jasmine.getGlobal()[name];
+ }
+};
+
+jasmine.setTimeout = jasmine.bindOriginal_(jasmine.getGlobal(), 'setTimeout');
+jasmine.clearTimeout = jasmine.bindOriginal_(jasmine.getGlobal(), 'clearTimeout');
+jasmine.setInterval = jasmine.bindOriginal_(jasmine.getGlobal(), 'setInterval');
+jasmine.clearInterval = jasmine.bindOriginal_(jasmine.getGlobal(), 'clearInterval');
+
+jasmine.MessageResult = function(values) {
+ this.type = 'log';
+ this.values = values;
+ this.trace = new Error(); // todo: test better
+};
+
+jasmine.MessageResult.prototype.toString = function() {
+ var text = "";
+ for (var i = 0; i < this.values.length; i++) {
+ if (i > 0) text += " ";
+ if (jasmine.isString_(this.values[i])) {
+ text += this.values[i];
+ } else {
+ text += jasmine.pp(this.values[i]);
+ }
+ }
+ return text;
+};
+
+jasmine.ExpectationResult = function(params) {
+ this.type = 'expect';
+ this.matcherName = params.matcherName;
+ this.passed_ = params.passed;
+ this.expected = params.expected;
+ this.actual = params.actual;
+ this.message = this.passed_ ? 'Passed.' : params.message;
+
+ var trace = (params.trace || new Error(this.message));
+ this.trace = this.passed_ ? '' : trace;
+};
+
+jasmine.ExpectationResult.prototype.toString = function () {
+ return this.message;
+};
+
+jasmine.ExpectationResult.prototype.passed = function () {
+ return this.passed_;
+};
+
+/**
+ * Getter for the Jasmine environment. Ensures one gets created
+ */
+jasmine.getEnv = function() {
+ var env = jasmine.currentEnv_ = jasmine.currentEnv_ || new jasmine.Env();
+ return env;
+};
+
+/**
+ * @ignore
+ * @private
+ * @param value
+ * @returns {Boolean}
+ */
+jasmine.isArray_ = function(value) {
+ return jasmine.isA_("Array", value);
+};
+
+/**
+ * @ignore
+ * @private
+ * @param value
+ * @returns {Boolean}
+ */
+jasmine.isString_ = function(value) {
+ return jasmine.isA_("String", value);
+};
+
+/**
+ * @ignore
+ * @private
+ * @param value
+ * @returns {Boolean}
+ */
+jasmine.isNumber_ = function(value) {
+ return jasmine.isA_("Number", value);
+};
+
+/**
+ * @ignore
+ * @private
+ * @param {String} typeName
+ * @param value
+ * @returns {Boolean}
+ */
+jasmine.isA_ = function(typeName, value) {
+ return Object.prototype.toString.apply(value) === '[object ' + typeName + ']';
+};
+
+/**
+ * Pretty printer for expecations. Takes any object and turns it into a human-readable string.
+ *
+ * @param value {Object} an object to be outputted
+ * @returns {String}
+ */
+jasmine.pp = function(value) {
+ var stringPrettyPrinter = new jasmine.StringPrettyPrinter();
+ stringPrettyPrinter.format(value);
+ return stringPrettyPrinter.string;
+};
+
+/**
+ * Returns true if the object is a DOM Node.
+ *
+ * @param {Object} obj object to check
+ * @returns {Boolean}
+ */
+jasmine.isDomNode = function(obj) {
+ return obj.nodeType > 0;
+};
+
+/**
+ * Returns a matchable 'generic' object of the class type. For use in expecations of type when values don't matter.
+ *
+ * @example
+ * // don't care about which function is passed in, as long as it's a function
+ * expect(mySpy).toHaveBeenCalledWith(jasmine.any(Function));
+ *
+ * @param {Class} clazz
+ * @returns matchable object of the type clazz
+ */
+jasmine.any = function(clazz) {
+ return new jasmine.Matchers.Any(clazz);
+};
+
+/**
+ * Returns a matchable subset of a JSON object. For use in expectations when you don't care about all of the
+ * attributes on the object.
+ *
+ * @example
+ * // don't care about any other attributes than foo.
+ * expect(mySpy).toHaveBeenCalledWith(jasmine.objectContaining({foo: "bar"});
+ *
+ * @param sample {Object} sample
+ * @returns matchable object for the sample
+ */
+jasmine.objectContaining = function (sample) {
+ return new jasmine.Matchers.ObjectContaining(sample);
+};
+
+/**
+ * Jasmine Spies are test doubles that can act as stubs, spies, fakes or when used in an expecation, mocks.
+ *
+ * Spies should be created in test setup, before expectations. They can then be checked, using the standard Jasmine
+ * expectation syntax. Spies can be checked if they were called or not and what the calling params were.
+ *
+ * A Spy has the following fields: wasCalled, callCount, mostRecentCall, and argsForCall (see docs).
+ *
+ * Spies are torn down at the end of every spec.
+ *
+ * Note: Do <b>not</b> call new jasmine.Spy() directly - a spy must be created using spyOn, jasmine.createSpy or jasmine.createSpyObj.
+ *
+ * @example
+ * // a stub
+ * var myStub = jasmine.createSpy('myStub'); // can be used anywhere
+ *
+ * // spy example
+ * var foo = {
+ * not: function(bool) { return !bool; }
+ * }
+ *
+ * // actual foo.not will not be called, execution stops
+ * spyOn(foo, 'not');
+
+ // foo.not spied upon, execution will continue to implementation
+ * spyOn(foo, 'not').andCallThrough();
+ *
+ * // fake example
+ * var foo = {
+ * not: function(bool) { return !bool; }
+ * }
+ *
+ * // foo.not(val) will return val
+ * spyOn(foo, 'not').andCallFake(function(value) {return value;});
+ *
+ * // mock example
+ * foo.not(7 == 7);
+ * expect(foo.not).toHaveBeenCalled();
+ * expect(foo.not).toHaveBeenCalledWith(true);
+ *
+ * @constructor
+ * @see spyOn, jasmine.createSpy, jasmine.createSpyObj
+ * @param {String} name
+ */
+jasmine.Spy = function(name) {
+ /**
+ * The name of the spy, if provided.
+ */
+ this.identity = name || 'unknown';
+ /**
+ * Is this Object a spy?
+ */
+ this.isSpy = true;
+ /**
+ * The actual function this spy stubs.
+ */
+ this.plan = function() {
+ };
+ /**
+ * Tracking of the most recent call to the spy.
+ * @example
+ * var mySpy = jasmine.createSpy('foo');
+ * mySpy(1, 2);
+ * mySpy.mostRecentCall.args = [1, 2];
+ */
+ this.mostRecentCall = {};
+
+ /**
+ * Holds arguments for each call to the spy, indexed by call count
+ * @example
+ * var mySpy = jasmine.createSpy('foo');
+ * mySpy(1, 2);
+ * mySpy(7, 8);
+ * mySpy.mostRecentCall.args = [7, 8];
+ * mySpy.argsForCall[0] = [1, 2];
+ * mySpy.argsForCall[1] = [7, 8];
+ */
+ this.argsForCall = [];
+ this.calls = [];
+};
+
+/**
+ * Tells a spy to call through to the actual implemenatation.
+ *
+ * @example
+ * var foo = {
+ * bar: function() { // do some stuff }
+ * }
+ *
+ * // defining a spy on an existing property: foo.bar
+ * spyOn(foo, 'bar').andCallThrough();
+ */
+jasmine.Spy.prototype.andCallThrough = function() {
+ this.plan = this.originalValue;
+ return this;
+};
+
+/**
+ * For setting the return value of a spy.
+ *
+ * @example
+ * // defining a spy from scratch: foo() returns 'baz'
+ * var foo = jasmine.createSpy('spy on foo').andReturn('baz');
+ *
+ * // defining a spy on an existing property: foo.bar() returns 'baz'
+ * spyOn(foo, 'bar').andReturn('baz');
+ *
+ * @param {Object} value
+ */
+jasmine.Spy.prototype.andReturn = function(value) {
+ this.plan = function() {
+ return value;
+ };
+ return this;
+};
+
+/**
+ * For throwing an exception when a spy is called.
+ *
+ * @example
+ * // defining a spy from scratch: foo() throws an exception w/ message 'ouch'
+ * var foo = jasmine.createSpy('spy on foo').andThrow('baz');
+ *
+ * // defining a spy on an existing property: foo.bar() throws an exception w/ message 'ouch'
+ * spyOn(foo, 'bar').andThrow('baz');
+ *
+ * @param {String} exceptionMsg
+ */
+jasmine.Spy.prototype.andThrow = function(exceptionMsg) {
+ this.plan = function() {
+ throw exceptionMsg;
+ };
+ return this;
+};
+
+/**
+ * Calls an alternate implementation when a spy is called.
+ *
+ * @example
+ * var baz = function() {
+ * // do some stuff, return something
+ * }
+ * // defining a spy from scratch: foo() calls the function baz
+ * var foo = jasmine.createSpy('spy on foo').andCall(baz);
+ *
+ * // defining a spy on an existing property: foo.bar() calls an anonymnous function
+ * spyOn(foo, 'bar').andCall(function() { return 'baz';} );
+ *
+ * @param {Function} fakeFunc
+ */
+jasmine.Spy.prototype.andCallFake = function(fakeFunc) {
+ this.plan = fakeFunc;
+ return this;
+};
+
+/**
+ * Resets all of a spy's the tracking variables so that it can be used again.
+ *
+ * @example
+ * spyOn(foo, 'bar');
+ *
+ * foo.bar();
+ *
+ * expect(foo.bar.callCount).toEqual(1);
+ *
+ * foo.bar.reset();
+ *
+ * expect(foo.bar.callCount).toEqual(0);
+ */
+jasmine.Spy.prototype.reset = function() {
+ this.wasCalled = false;
+ this.callCount = 0;
+ this.argsForCall = [];
+ this.calls = [];
+ this.mostRecentCall = {};
+};
+
+jasmine.createSpy = function(name) {
+
+ var spyObj = function() {
+ spyObj.wasCalled = true;
+ spyObj.callCount++;
+ var args = jasmine.util.argsToArray(arguments);
+ spyObj.mostRecentCall.object = this;
+ spyObj.mostRecentCall.args = args;
+ spyObj.argsForCall.push(args);
+ spyObj.calls.push({object: this, args: args});
+ return spyObj.plan.apply(this, arguments);
+ };
+
+ var spy = new jasmine.Spy(name);
+
+ for (var prop in spy) {
+ spyObj[prop] = spy[prop];
+ }
+
+ spyObj.reset();
+
+ return spyObj;
+};
+
+/**
+ * Determines whether an object is a spy.
+ *
+ * @param {jasmine.Spy|Object} putativeSpy
+ * @returns {Boolean}
+ */
+jasmine.isSpy = function(putativeSpy) {
+ return putativeSpy && putativeSpy.isSpy;
+};
+
+/**
+ * Creates a more complicated spy: an Object that has every property a function that is a spy. Used for stubbing something
+ * large in one call.
+ *
+ * @param {String} baseName name of spy class
+ * @param {Array} methodNames array of names of methods to make spies
+ */
+jasmine.createSpyObj = function(baseName, methodNames) {
+ if (!jasmine.isArray_(methodNames) || methodNames.length === 0) {
+ throw new Error('createSpyObj requires a non-empty array of method names to create spies for');
+ }
+ var obj = {};
+ for (var i = 0; i < methodNames.length; i++) {
+ obj[methodNames[i]] = jasmine.createSpy(baseName + '.' + methodNames[i]);
+ }
+ return obj;
+};
+
+/**
+ * All parameters are pretty-printed and concatenated together, then written to the current spec's output.
+ *
+ * Be careful not to leave calls to <code>jasmine.log</code> in production code.
+ */
+jasmine.log = function() {
+ var spec = jasmine.getEnv().currentSpec;
+ spec.log.apply(spec, arguments);
+};
+
+/**
+ * Function that installs a spy on an existing object's method name. Used within a Spec to create a spy.
+ *
+ * @example
+ * // spy example
+ * var foo = {
+ * not: function(bool) { return !bool; }
+ * }
+ * spyOn(foo, 'not'); // actual foo.not will not be called, execution stops
+ *
+ * @see jasmine.createSpy
+ * @param obj
+ * @param methodName
+ * @return {jasmine.Spy} a Jasmine spy that can be chained with all spy methods
+ */
+var spyOn = function(obj, methodName) {
+ return jasmine.getEnv().currentSpec.spyOn(obj, methodName);
+};
+if (isCommonJS) exports.spyOn = spyOn;
+
+/**
+ * Creates a Jasmine spec that will be added to the current suite.
+ *
+ * // TODO: pending tests
+ *
+ * @example
+ * it('should be true', function() {
+ * expect(true).toEqual(true);
+ * });
+ *
+ * @param {String} desc description of this specification
+ * @param {Function} func defines the preconditions and expectations of the spec
+ */
+var it = function(desc, func) {
+ return jasmine.getEnv().it(desc, func);
+};
+if (isCommonJS) exports.it = it;
+
+/**
+ * Creates a <em>disabled</em> Jasmine spec.
+ *
+ * A convenience method that allows existing specs to be disabled temporarily during development.
+ *
+ * @param {String} desc description of this specification
+ * @param {Function} func defines the preconditions and expectations of the spec
+ */
+var xit = function(desc, func) {
+ return jasmine.getEnv().xit(desc, func);
+};
+if (isCommonJS) exports.xit = xit;
+
+/**
+ * Starts a chain for a Jasmine expectation.
+ *
+ * It is passed an Object that is the actual value and should chain to one of the many
+ * jasmine.Matchers functions.
+ *
+ * @param {Object} actual Actual value to test against and expected value
+ * @return {jasmine.Matchers}
+ */
+var expect = function(actual) {
+ return jasmine.getEnv().currentSpec.expect(actual);
+};
+if (isCommonJS) exports.expect = expect;
+
+/**
+ * Defines part of a jasmine spec. Used in cominbination with waits or waitsFor in asynchrnous specs.
+ *
+ * @param {Function} func Function that defines part of a jasmine spec.
+ */
+var runs = function(func) {
+ jasmine.getEnv().currentSpec.runs(func);
+};
+if (isCommonJS) exports.runs = runs;
+
+/**
+ * Waits a fixed time period before moving to the next block.
+ *
+ * @deprecated Use waitsFor() instead
+ * @param {Number} timeout milliseconds to wait
+ */
+var waits = function(timeout) {
+ jasmine.getEnv().currentSpec.waits(timeout);
+};
+if (isCommonJS) exports.waits = waits;
+
+/**
+ * Waits for the latchFunction to return true before proceeding to the next block.
+ *
+ * @param {Function} latchFunction
+ * @param {String} optional_timeoutMessage
+ * @param {Number} optional_timeout
+ */
+var waitsFor = function(latchFunction, optional_timeoutMessage, optional_timeout) {
+ jasmine.getEnv().currentSpec.waitsFor.apply(jasmine.getEnv().currentSpec, arguments);
+};
+if (isCommonJS) exports.waitsFor = waitsFor;
+
+/**
+ * A function that is called before each spec in a suite.
+ *
+ * Used for spec setup, including validating assumptions.
+ *
+ * @param {Function} beforeEachFunction
+ */
+var beforeEach = function(beforeEachFunction) {
+ jasmine.getEnv().beforeEach(beforeEachFunction);
+};
+if (isCommonJS) exports.beforeEach = beforeEach;
+
+/**
+ * A function that is called after each spec in a suite.
+ *
+ * Used for restoring any state that is hijacked during spec execution.
+ *
+ * @param {Function} afterEachFunction
+ */
+var afterEach = function(afterEachFunction) {
+ jasmine.getEnv().afterEach(afterEachFunction);
+};
+if (isCommonJS) exports.afterEach = afterEach;
+
+/**
+ * Defines a suite of specifications.
+ *
+ * Stores the description and all defined specs in the Jasmine environment as one suite of specs. Variables declared
+ * are accessible by calls to beforeEach, it, and afterEach. Describe blocks can be nested, allowing for specialization
+ * of setup in some tests.
+ *
+ * @example
+ * // TODO: a simple suite
+ *
+ * // TODO: a simple suite with a nested describe block
+ *
+ * @param {String} description A string, usually the class under test.
+ * @param {Function} specDefinitions function that defines several specs.
+ */
+var describe = function(description, specDefinitions) {
+ return jasmine.getEnv().describe(description, specDefinitions);
+};
+if (isCommonJS) exports.describe = describe;
+
+/**
+ * Disables a suite of specifications. Used to disable some suites in a file, or files, temporarily during development.
+ *
+ * @param {String} description A string, usually the class under test.
+ * @param {Function} specDefinitions function that defines several specs.
+ */
+var xdescribe = function(description, specDefinitions) {
+ return jasmine.getEnv().xdescribe(description, specDefinitions);
+};
+if (isCommonJS) exports.xdescribe = xdescribe;
+
+
+// Provide the XMLHttpRequest class for IE 5.x-6.x:
+jasmine.XmlHttpRequest = (typeof XMLHttpRequest == "undefined") ? function() {
+ function tryIt(f) {
+ try {
+ return f();
+ } catch(e) {
+ }
+ return null;
+ }
+
+ var xhr = tryIt(function() {
+ return new ActiveXObject("Msxml2.XMLHTTP.6.0");
+ }) ||
+ tryIt(function() {
+ return new ActiveXObject("Msxml2.XMLHTTP.3.0");
+ }) ||
+ tryIt(function() {
+ return new ActiveXObject("Msxml2.XMLHTTP");
+ }) ||
+ tryIt(function() {
+ return new ActiveXObject("Microsoft.XMLHTTP");
+ });
+
+ if (!xhr) throw new Error("This browser does not support XMLHttpRequest.");
+
+ return xhr;
+} : XMLHttpRequest;
+/**
+ * @namespace
+ */
+jasmine.util = {};
+
+/**
+ * Declare that a child class inherit it's prototype from the parent class.
+ *
+ * @private
+ * @param {Function} childClass
+ * @param {Function} parentClass
+ */
+jasmine.util.inherit = function(childClass, parentClass) {
+ /**
+ * @private
+ */
+ var subclass = function() {
+ };
+ subclass.prototype = parentClass.prototype;
+ childClass.prototype = new subclass();
+};
+
+jasmine.util.formatException = function(e) {
+ var lineNumber;
+ if (e.line) {
+ lineNumber = e.line;
+ }
+ else if (e.lineNumber) {
+ lineNumber = e.lineNumber;
+ }
+
+ var file;
+
+ if (e.sourceURL) {
+ file = e.sourceURL;
+ }
+ else if (e.fileName) {
+ file = e.fileName;
+ }
+
+ var message = (e.name && e.message) ? (e.name + ': ' + e.message) : e.toString();
+
+ if (file && lineNumber) {
+ message += ' in ' + file + ' (line ' + lineNumber + ')';
+ }
+
+ return message;
+};
+
+jasmine.util.htmlEscape = function(str) {
+ if (!str) return str;
+ return str.replace(/&/g, '&amp;')
+ .replace(/</g, '&lt;')
+ .replace(/>/g, '&gt;');
+};
+
+jasmine.util.argsToArray = function(args) {
+ var arrayOfArgs = [];
+ for (var i = 0; i < args.length; i++) arrayOfArgs.push(args[i]);
+ return arrayOfArgs;
+};
+
+jasmine.util.extend = function(destination, source) {
+ for (var property in source) destination[property] = source[property];
+ return destination;
+};
+
+/**
+ * Environment for Jasmine
+ *
+ * @constructor
+ */
+jasmine.Env = function() {
+ this.currentSpec = null;
+ this.currentSuite = null;
+ this.currentRunner_ = new jasmine.Runner(this);
+
+ this.reporter = new jasmine.MultiReporter();
+
+ this.updateInterval = jasmine.DEFAULT_UPDATE_INTERVAL;
+ this.defaultTimeoutInterval = jasmine.DEFAULT_TIMEOUT_INTERVAL;
+ this.lastUpdate = 0;
+ this.specFilter = function() {
+ return true;
+ };
+
+ this.nextSpecId_ = 0;
+ this.nextSuiteId_ = 0;
+ this.equalityTesters_ = [];
+
+ // wrap matchers
+ this.matchersClass = function() {
+ jasmine.Matchers.apply(this, arguments);
+ };
+ jasmine.util.inherit(this.matchersClass, jasmine.Matchers);
+
+ jasmine.Matchers.wrapInto_(jasmine.Matchers.prototype, this.matchersClass);
+};
+
+
+jasmine.Env.prototype.setTimeout = jasmine.setTimeout;
+jasmine.Env.prototype.clearTimeout = jasmine.clearTimeout;
+jasmine.Env.prototype.setInterval = jasmine.setInterval;
+jasmine.Env.prototype.clearInterval = jasmine.clearInterval;
+
+/**
+ * @returns an object containing jasmine version build info, if set.
+ */
+jasmine.Env.prototype.version = function () {
+ if (jasmine.version_) {
+ return jasmine.version_;
+ } else {
+ throw new Error('Version not set');
+ }
+};
+
+/**
+ * @returns string containing jasmine version build info, if set.
+ */
+jasmine.Env.prototype.versionString = function() {
+ if (!jasmine.version_) {
+ return "version unknown";
+ }
+
+ var version = this.version();
+ var versionString = version.major + "." + version.minor + "." + version.build;
+ if (version.release_candidate) {
+ versionString += ".rc" + version.release_candidate;
+ }
+ versionString += " revision " + version.revision;
+ return versionString;
+};
+
+/**
+ * @returns a sequential integer starting at 0
+ */
+jasmine.Env.prototype.nextSpecId = function () {
+ return this.nextSpecId_++;
+};
+
+/**
+ * @returns a sequential integer starting at 0
+ */
+jasmine.Env.prototype.nextSuiteId = function () {
+ return this.nextSuiteId_++;
+};
+
+/**
+ * Register a reporter to receive status updates from Jasmine.
+ * @param {jasmine.Reporter} reporter An object which will receive status updates.
+ */
+jasmine.Env.prototype.addReporter = function(reporter) {
+ this.reporter.addReporter(reporter);
+};
+
+jasmine.Env.prototype.execute = function() {
+ this.currentRunner_.execute();
+};
+
+jasmine.Env.prototype.describe = function(description, specDefinitions) {
+ var suite = new jasmine.Suite(this, description, specDefinitions, this.currentSuite);
+
+ var parentSuite = this.currentSuite;
+ if (parentSuite) {
+ parentSuite.add(suite);
+ } else {
+ this.currentRunner_.add(suite);
+ }
+
+ this.currentSuite = suite;
+
+ var declarationError = null;
+ try {
+ specDefinitions.call(suite);
+ } catch(e) {
+ declarationError = e;
+ }
+
+ if (declarationError) {
+ this.it("encountered a declaration exception", function() {
+ throw declarationError;
+ });
+ }
+
+ this.currentSuite = parentSuite;
+
+ return suite;
+};
+
+jasmine.Env.prototype.beforeEach = function(beforeEachFunction) {
+ if (this.currentSuite) {
+ this.currentSuite.beforeEach(beforeEachFunction);
+ } else {
+ this.currentRunner_.beforeEach(beforeEachFunction);
+ }
+};
+
+jasmine.Env.prototype.currentRunner = function () {
+ return this.currentRunner_;
+};
+
+jasmine.Env.prototype.afterEach = function(afterEachFunction) {
+ if (this.currentSuite) {
+ this.currentSuite.afterEach(afterEachFunction);
+ } else {
+ this.currentRunner_.afterEach(afterEachFunction);
+ }
+
+};
+
+jasmine.Env.prototype.xdescribe = function(desc, specDefinitions) {
+ return {
+ execute: function() {
+ }
+ };
+};
+
+jasmine.Env.prototype.it = function(description, func) {
+ var spec = new jasmine.Spec(this, this.currentSuite, description);
+ this.currentSuite.add(spec);
+ this.currentSpec = spec;
+
+ if (func) {
+ spec.runs(func);
+ }
+
+ return spec;
+};
+
+jasmine.Env.prototype.xit = function(desc, func) {
+ return {
+ id: this.nextSpecId(),
+ runs: function() {
+ }
+ };
+};
+
+jasmine.Env.prototype.compareRegExps_ = function(a, b, mismatchKeys, mismatchValues) {
+ if (a.source != b.source)
+ mismatchValues.push("expected pattern /" + b.source + "/ is not equal to the pattern /" + a.source + "/");
+
+ if (a.ignoreCase != b.ignoreCase)
+ mismatchValues.push("expected modifier i was" + (b.ignoreCase ? " " : " not ") + "set and does not equal the origin modifier");
+
+ if (a.global != b.global)
+ mismatchValues.push("expected modifier g was" + (b.global ? " " : " not ") + "set and does not equal the origin modifier");
+
+ if (a.multiline != b.multiline)
+ mismatchValues.push("expected modifier m was" + (b.multiline ? " " : " not ") + "set and does not equal the origin modifier");
+
+ if (a.sticky != b.sticky)
+ mismatchValues.push("expected modifier y was" + (b.sticky ? " " : " not ") + "set and does not equal the origin modifier");
+
+ return (mismatchValues.length === 0);
+};
+
+jasmine.Env.prototype.compareObjects_ = function(a, b, mismatchKeys, mismatchValues) {
+ if (a.__Jasmine_been_here_before__ === b && b.__Jasmine_been_here_before__ === a) {
+ return true;
+ }
+
+ a.__Jasmine_been_here_before__ = b;
+ b.__Jasmine_been_here_before__ = a;
+
+ var hasKey = function(obj, keyName) {
+ return obj !== null && obj[keyName] !== jasmine.undefined;
+ };
+
+ for (var property in b) {
+ if (!hasKey(a, property) && hasKey(b, property)) {
+ mismatchKeys.push("expected has key '" + property + "', but missing from actual.");
+ }
+ }
+ for (property in a) {
+ if (!hasKey(b, property) && hasKey(a, property)) {
+ mismatchKeys.push("expected missing key '" + property + "', but present in actual.");
+ }
+ }
+ for (property in b) {
+ if (property == '__Jasmine_been_here_before__') continue;
+ if (!this.equals_(a[property], b[property], mismatchKeys, mismatchValues)) {
+ mismatchValues.push("'" + property + "' was '" + (b[property] ? jasmine.util.htmlEscape(b[property].toString()) : b[property]) + "' in expected, but was '" + (a[property] ? jasmine.util.htmlEscape(a[property].toString()) : a[property]) + "' in actual.");
+ }
+ }
+
+ if (jasmine.isArray_(a) && jasmine.isArray_(b) && a.length != b.length) {
+ mismatchValues.push("arrays were not the same length");
+ }
+
+ delete a.__Jasmine_been_here_before__;
+ delete b.__Jasmine_been_here_before__;
+ return (mismatchKeys.length === 0 && mismatchValues.length === 0);
+};
+
+jasmine.Env.prototype.equals_ = function(a, b, mismatchKeys, mismatchValues) {
+ mismatchKeys = mismatchKeys || [];
+ mismatchValues = mismatchValues || [];
+
+ for (var i = 0; i < this.equalityTesters_.length; i++) {
+ var equalityTester = this.equalityTesters_[i];
+ var result = equalityTester(a, b, this, mismatchKeys, mismatchValues);
+ if (result !== jasmine.undefined) return result;
+ }
+
+ if (a === b) return true;
+
+ if (a === jasmine.undefined || a === null || b === jasmine.undefined || b === null) {
+ return (a == jasmine.undefined && b == jasmine.undefined);
+ }
+
+ if (jasmine.isDomNode(a) && jasmine.isDomNode(b)) {
+ return a === b;
+ }
+
+ if (a instanceof Date && b instanceof Date) {
+ return a.getTime() == b.getTime();
+ }
+
+ if (a.jasmineMatches) {
+ return a.jasmineMatches(b);
+ }
+
+ if (b.jasmineMatches) {
+ return b.jasmineMatches(a);
+ }
+
+ if (a instanceof jasmine.Matchers.ObjectContaining) {
+ return a.matches(b);
+ }
+
+ if (b instanceof jasmine.Matchers.ObjectContaining) {
+ return b.matches(a);
+ }
+
+ if (jasmine.isString_(a) && jasmine.isString_(b)) {
+ return (a == b);
+ }
+
+ if (jasmine.isNumber_(a) && jasmine.isNumber_(b)) {
+ return (a == b);
+ }
+
+ if (a instanceof RegExp && b instanceof RegExp) {
+ return this.compareRegExps_(a, b, mismatchKeys, mismatchValues);
+ }
+
+ if (typeof a === "object" && typeof b === "object") {
+ return this.compareObjects_(a, b, mismatchKeys, mismatchValues);
+ }
+
+ //Straight check
+ return (a === b);
+};
+
+jasmine.Env.prototype.contains_ = function(haystack, needle) {
+ if (jasmine.isArray_(haystack)) {
+ for (var i = 0; i < haystack.length; i++) {
+ if (this.equals_(haystack[i], needle)) return true;
+ }
+ return false;
+ }
+ return haystack.indexOf(needle) >= 0;
+};
+
+jasmine.Env.prototype.addEqualityTester = function(equalityTester) {
+ this.equalityTesters_.push(equalityTester);
+};
+/** No-op base class for Jasmine reporters.
+ *
+ * @constructor
+ */
+jasmine.Reporter = function() {
+};
+
+//noinspection JSUnusedLocalSymbols
+jasmine.Reporter.prototype.reportRunnerStarting = function(runner) {
+};
+
+//noinspection JSUnusedLocalSymbols
+jasmine.Reporter.prototype.reportRunnerResults = function(runner) {
+};
+
+//noinspection JSUnusedLocalSymbols
+jasmine.Reporter.prototype.reportSuiteResults = function(suite) {
+};
+
+//noinspection JSUnusedLocalSymbols
+jasmine.Reporter.prototype.reportSpecStarting = function(spec) {
+};
+
+//noinspection JSUnusedLocalSymbols
+jasmine.Reporter.prototype.reportSpecResults = function(spec) {
+};
+
+//noinspection JSUnusedLocalSymbols
+jasmine.Reporter.prototype.log = function(str) {
+};
+
+/**
+ * Blocks are functions with executable code that make up a spec.
+ *
+ * @constructor
+ * @param {jasmine.Env} env
+ * @param {Function} func
+ * @param {jasmine.Spec} spec
+ */
+jasmine.Block = function(env, func, spec) {
+ this.env = env;
+ this.func = func;
+ this.spec = spec;
+};
+
+jasmine.Block.prototype.execute = function(onComplete) {
+ if (!jasmine.CATCH_EXCEPTIONS) {
+ this.func.apply(this.spec);
+ }
+ else {
+ try {
+ this.func.apply(this.spec);
+ } catch (e) {
+ this.spec.fail(e);
+ }
+ }
+ onComplete();
+};
+/** JavaScript API reporter.
+ *
+ * @constructor
+ */
+jasmine.JsApiReporter = function() {
+ this.started = false;
+ this.finished = false;
+ this.suites_ = [];
+ this.results_ = {};
+};
+
+jasmine.JsApiReporter.prototype.reportRunnerStarting = function(runner) {
+ this.started = true;
+ var suites = runner.topLevelSuites();
+ for (var i = 0; i < suites.length; i++) {
+ var suite = suites[i];
+ this.suites_.push(this.summarize_(suite));
+ }
+};
+
+jasmine.JsApiReporter.prototype.suites = function() {
+ return this.suites_;
+};
+
+jasmine.JsApiReporter.prototype.summarize_ = function(suiteOrSpec) {
+ var isSuite = suiteOrSpec instanceof jasmine.Suite;
+ var summary = {
+ id: suiteOrSpec.id,
+ name: suiteOrSpec.description,
+ type: isSuite ? 'suite' : 'spec',
+ children: []
+ };
+
+ if (isSuite) {
+ var children = suiteOrSpec.children();
+ for (var i = 0; i < children.length; i++) {
+ summary.children.push(this.summarize_(children[i]));
+ }
+ }
+ return summary;
+};
+
+jasmine.JsApiReporter.prototype.results = function() {
+ return this.results_;
+};
+
+jasmine.JsApiReporter.prototype.resultsForSpec = function(specId) {
+ return this.results_[specId];
+};
+
+//noinspection JSUnusedLocalSymbols
+jasmine.JsApiReporter.prototype.reportRunnerResults = function(runner) {
+ this.finished = true;
+};
+
+//noinspection JSUnusedLocalSymbols
+jasmine.JsApiReporter.prototype.reportSuiteResults = function(suite) {
+};
+
+//noinspection JSUnusedLocalSymbols
+jasmine.JsApiReporter.prototype.reportSpecResults = function(spec) {
+ this.results_[spec.id] = {
+ messages: spec.results().getItems(),
+ result: spec.results().failedCount > 0 ? "failed" : "passed"
+ };
+};
+
+//noinspection JSUnusedLocalSymbols
+jasmine.JsApiReporter.prototype.log = function(str) {
+};
+
+jasmine.JsApiReporter.prototype.resultsForSpecs = function(specIds){
+ var results = {};
+ for (var i = 0; i < specIds.length; i++) {
+ var specId = specIds[i];
+ results[specId] = this.summarizeResult_(this.results_[specId]);
+ }
+ return results;
+};
+
+jasmine.JsApiReporter.prototype.summarizeResult_ = function(result){
+ var summaryMessages = [];
+ var messagesLength = result.messages.length;
+ for (var messageIndex = 0; messageIndex < messagesLength; messageIndex++) {
+ var resultMessage = result.messages[messageIndex];
+ summaryMessages.push({
+ text: resultMessage.type == 'log' ? resultMessage.toString() : jasmine.undefined,
+ passed: resultMessage.passed ? resultMessage.passed() : true,
+ type: resultMessage.type,
+ message: resultMessage.message,
+ trace: {
+ stack: resultMessage.passed && !resultMessage.passed() ? resultMessage.trace.stack : jasmine.undefined
+ }
+ });
+ }
+
+ return {
+ result : result.result,
+ messages : summaryMessages
+ };
+};
+
+/**
+ * @constructor
+ * @param {jasmine.Env} env
+ * @param actual
+ * @param {jasmine.Spec} spec
+ */
+jasmine.Matchers = function(env, actual, spec, opt_isNot) {
+ this.env = env;
+ this.actual = actual;
+ this.spec = spec;
+ this.isNot = opt_isNot || false;
+ this.reportWasCalled_ = false;
+};
+
+// todo: @deprecated as of Jasmine 0.11, remove soon [xw]
+jasmine.Matchers.pp = function(str) {
+ throw new Error("jasmine.Matchers.pp() is no longer supported, please use jasmine.pp() instead!");
+};
+
+// todo: @deprecated Deprecated as of Jasmine 0.10. Rewrite your custom matchers to return true or false. [xw]
+jasmine.Matchers.prototype.report = function(result, failing_message, details) {
+ throw new Error("As of jasmine 0.11, custom matchers must be implemented differently -- please see jasmine docs");
+};
+
+jasmine.Matchers.wrapInto_ = function(prototype, matchersClass) {
+ for (var methodName in prototype) {
+ if (methodName == 'report') continue;
+ var orig = prototype[methodName];
+ matchersClass.prototype[methodName] = jasmine.Matchers.matcherFn_(methodName, orig);
+ }
+};
+
+jasmine.Matchers.matcherFn_ = function(matcherName, matcherFunction) {
+ return function() {
+ var matcherArgs = jasmine.util.argsToArray(arguments);
+ var result = matcherFunction.apply(this, arguments);
+
+ if (this.isNot) {
+ result = !result;
+ }
+
+ if (this.reportWasCalled_) return result;
+
+ var message;
+ if (!result) {
+ if (this.message) {
+ message = this.message.apply(this, arguments);
+ if (jasmine.isArray_(message)) {
+ message = message[this.isNot ? 1 : 0];
+ }
+ } else {
+ var englishyPredicate = matcherName.replace(/[A-Z]/g, function(s) { return ' ' + s.toLowerCase(); });
+ message = "Expected " + jasmine.pp(this.actual) + (this.isNot ? " not " : " ") + englishyPredicate;
+ if (matcherArgs.length > 0) {
+ for (var i = 0; i < matcherArgs.length; i++) {
+ if (i > 0) message += ",";
+ message += " " + jasmine.pp(matcherArgs[i]);
+ }
+ }
+ message += ".";
+ }
+ }
+ var expectationResult = new jasmine.ExpectationResult({
+ matcherName: matcherName,
+ passed: result,
+ expected: matcherArgs.length > 1 ? matcherArgs : matcherArgs[0],
+ actual: this.actual,
+ message: message
+ });
+ this.spec.addMatcherResult(expectationResult);
+ return jasmine.undefined;
+ };
+};
+
+
+
+
+/**
+ * toBe: compares the actual to the expected using ===
+ * @param expected
+ */
+jasmine.Matchers.prototype.toBe = function(expected) {
+ return this.actual === expected;
+};
+
+/**
+ * toNotBe: compares the actual to the expected using !==
+ * @param expected
+ * @deprecated as of 1.0. Use not.toBe() instead.
+ */
+jasmine.Matchers.prototype.toNotBe = function(expected) {
+ return this.actual !== expected;
+};
+
+/**
+ * toEqual: compares the actual to the expected using common sense equality. Handles Objects, Arrays, etc.
+ *
+ * @param expected
+ */
+jasmine.Matchers.prototype.toEqual = function(expected) {
+ return this.env.equals_(this.actual, expected);
+};
+
+/**
+ * toNotEqual: compares the actual to the expected using the ! of jasmine.Matchers.toEqual
+ * @param expected
+ * @deprecated as of 1.0. Use not.toEqual() instead.
+ */
+jasmine.Matchers.prototype.toNotEqual = function(expected) {
+ return !this.env.equals_(this.actual, expected);
+};
+
+/**
+ * Matcher that compares the actual to the expected using a regular expression. Constructs a RegExp, so takes
+ * a pattern or a String.
+ *
+ * @param expected
+ */
+jasmine.Matchers.prototype.toMatch = function(expected) {
+ return new RegExp(expected).test(this.actual);
+};
+
+/**
+ * Matcher that compares the actual to the expected using the boolean inverse of jasmine.Matchers.toMatch
+ * @param expected
+ * @deprecated as of 1.0. Use not.toMatch() instead.
+ */
+jasmine.Matchers.prototype.toNotMatch = function(expected) {
+ return !(new RegExp(expected).test(this.actual));
+};
+
+/**
+ * Matcher that compares the actual to jasmine.undefined.
+ */
+jasmine.Matchers.prototype.toBeDefined = function() {
+ return (this.actual !== jasmine.undefined);
+};
+
+/**
+ * Matcher that compares the actual to jasmine.undefined.
+ */
+jasmine.Matchers.prototype.toBeUndefined = function() {
+ return (this.actual === jasmine.undefined);
+};
+
+/**
+ * Matcher that compares the actual to null.
+ */
+jasmine.Matchers.prototype.toBeNull = function() {
+ return (this.actual === null);
+};
+
+/**
+ * Matcher that compares the actual to NaN.
+ */
+jasmine.Matchers.prototype.toBeNaN = function() {
+ this.message = function() {
+ return [ "Expected " + jasmine.pp(this.actual) + " to be NaN." ];
+ };
+
+ return (this.actual !== this.actual);
+};
+
+/**
+ * Matcher that boolean not-nots the actual.
+ */
+jasmine.Matchers.prototype.toBeTruthy = function() {
+ return !!this.actual;
+};
+
+
+/**
+ * Matcher that boolean nots the actual.
+ */
+jasmine.Matchers.prototype.toBeFalsy = function() {
+ return !this.actual;
+};
+
+
+/**
+ * Matcher that checks to see if the actual, a Jasmine spy, was called.
+ */
+jasmine.Matchers.prototype.toHaveBeenCalled = function() {
+ if (arguments.length > 0) {
+ throw new Error('toHaveBeenCalled does not take arguments, use toHaveBeenCalledWith');
+ }
+
+ if (!jasmine.isSpy(this.actual)) {
+ throw new Error('Expected a spy, but got ' + jasmine.pp(this.actual) + '.');
+ }
+
+ this.message = function() {
+ return [
+ "Expected spy " + this.actual.identity + " to have been called.",
+ "Expected spy " + this.actual.identity + " not to have been called."
+ ];
+ };
+
+ return this.actual.wasCalled;
+};
+
+/** @deprecated Use expect(xxx).toHaveBeenCalled() instead */
+jasmine.Matchers.prototype.wasCalled = jasmine.Matchers.prototype.toHaveBeenCalled;
+
+/**
+ * Matcher that checks to see if the actual, a Jasmine spy, was not called.
+ *
+ * @deprecated Use expect(xxx).not.toHaveBeenCalled() instead
+ */
+jasmine.Matchers.prototype.wasNotCalled = function() {
+ if (arguments.length > 0) {
+ throw new Error('wasNotCalled does not take arguments');
+ }
+
+ if (!jasmine.isSpy(this.actual)) {
+ throw new Error('Expected a spy, but got ' + jasmine.pp(this.actual) + '.');
+ }
+
+ this.message = function() {
+ return [
+ "Expected spy " + this.actual.identity + " to not have been called.",
+ "Expected spy " + this.actual.identity + " to have been called."
+ ];
+ };
+
+ return !this.actual.wasCalled;
+};
+
+/**
+ * Matcher that checks to see if the actual, a Jasmine spy, was called with a set of parameters.
+ *
+ * @example
+ *
+ */
+jasmine.Matchers.prototype.toHaveBeenCalledWith = function() {
+ var expectedArgs = jasmine.util.argsToArray(arguments);
+ if (!jasmine.isSpy(this.actual)) {
+ throw new Error('Expected a spy, but got ' + jasmine.pp(this.actual) + '.');
+ }
+ this.message = function() {
+ var invertedMessage = "Expected spy " + this.actual.identity + " not to have been called with " + jasmine.pp(expectedArgs) + " but it was.";
+ var positiveMessage = "";
+ if (this.actual.callCount === 0) {
+ positiveMessage = "Expected spy " + this.actual.identity + " to have been called with " + jasmine.pp(expectedArgs) + " but it was never called.";
+ } else {
+ positiveMessage = "Expected spy " + this.actual.identity + " to have been called with " + jasmine.pp(expectedArgs) + " but actual calls were " + jasmine.pp(this.actual.argsForCall).replace(/^\[ | \]$/g, '')
+ }
+ return [positiveMessage, invertedMessage];
+ };
+
+ return this.env.contains_(this.actual.argsForCall, expectedArgs);
+};
+
+/** @deprecated Use expect(xxx).toHaveBeenCalledWith() instead */
+jasmine.Matchers.prototype.wasCalledWith = jasmine.Matchers.prototype.toHaveBeenCalledWith;
+
+/** @deprecated Use expect(xxx).not.toHaveBeenCalledWith() instead */
+jasmine.Matchers.prototype.wasNotCalledWith = function() {
+ var expectedArgs = jasmine.util.argsToArray(arguments);
+ if (!jasmine.isSpy(this.actual)) {
+ throw new Error('Expected a spy, but got ' + jasmine.pp(this.actual) + '.');
+ }
+
+ this.message = function() {
+ return [
+ "Expected spy not to have been called with " + jasmine.pp(expectedArgs) + " but it was",
+ "Expected spy to have been called with " + jasmine.pp(expectedArgs) + " but it was"
+ ];
+ };
+
+ return !this.env.contains_(this.actual.argsForCall, expectedArgs);
+};
+
+/**
+ * Matcher that checks that the expected item is an element in the actual Array.
+ *
+ * @param {Object} expected
+ */
+jasmine.Matchers.prototype.toContain = function(expected) {
+ return this.env.contains_(this.actual, expected);
+};
+
+/**
+ * Matcher that checks that the expected item is NOT an element in the actual Array.
+ *
+ * @param {Object} expected
+ * @deprecated as of 1.0. Use not.toContain() instead.
+ */
+jasmine.Matchers.prototype.toNotContain = function(expected) {
+ return !this.env.contains_(this.actual, expected);
+};
+
+jasmine.Matchers.prototype.toBeLessThan = function(expected) {
+ return this.actual < expected;
+};
+
+jasmine.Matchers.prototype.toBeGreaterThan = function(expected) {
+ return this.actual > expected;
+};
+
+/**
+ * Matcher that checks that the expected item is equal to the actual item
+ * up to a given level of decimal precision (default 2).
+ *
+ * @param {Number} expected
+ * @param {Number} precision, as number of decimal places
+ */
+jasmine.Matchers.prototype.toBeCloseTo = function(expected, precision) {
+ if (!(precision === 0)) {
+ precision = precision || 2;
+ }
+ return Math.abs(expected - this.actual) < (Math.pow(10, -precision) / 2);
+};
+
+/**
+ * Matcher that checks that the expected exception was thrown by the actual.
+ *
+ * @param {String} [expected]
+ */
+jasmine.Matchers.prototype.toThrow = function(expected) {
+ var result = false;
+ var exception;
+ if (typeof this.actual != 'function') {
+ throw new Error('Actual is not a function');
+ }
+ try {
+ this.actual();
+ } catch (e) {
+ exception = e;
+ }
+ if (exception) {
+ result = (expected === jasmine.undefined || this.env.equals_(exception.message || exception, expected.message || expected));
+ }
+
+ var not = this.isNot ? "not " : "";
+
+ this.message = function() {
+ if (exception && (expected === jasmine.undefined || !this.env.equals_(exception.message || exception, expected.message || expected))) {
+ return ["Expected function " + not + "to throw", expected ? expected.message || expected : "an exception", ", but it threw", exception.message || exception].join(' ');
+ } else {
+ return "Expected function to throw an exception.";
+ }
+ };
+
+ return result;
+};
+
+jasmine.Matchers.Any = function(expectedClass) {
+ this.expectedClass = expectedClass;
+};
+
+jasmine.Matchers.Any.prototype.jasmineMatches = function(other) {
+ if (this.expectedClass == String) {
+ return typeof other == 'string' || other instanceof String;
+ }
+
+ if (this.expectedClass == Number) {
+ return typeof other == 'number' || other instanceof Number;
+ }
+
+ if (this.expectedClass == Function) {
+ return typeof other == 'function' || other instanceof Function;
+ }
+
+ if (this.expectedClass == Object) {
+ return typeof other == 'object';
+ }
+
+ return other instanceof this.expectedClass;
+};
+
+jasmine.Matchers.Any.prototype.jasmineToString = function() {
+ return '<jasmine.any(' + this.expectedClass + ')>';
+};
+
+jasmine.Matchers.ObjectContaining = function (sample) {
+ this.sample = sample;
+};
+
+jasmine.Matchers.ObjectContaining.prototype.jasmineMatches = function(other, mismatchKeys, mismatchValues) {
+ mismatchKeys = mismatchKeys || [];
+ mismatchValues = mismatchValues || [];
+
+ var env = jasmine.getEnv();
+
+ var hasKey = function(obj, keyName) {
+ return obj != null && obj[keyName] !== jasmine.undefined;
+ };
+
+ for (var property in this.sample) {
+ if (!hasKey(other, property) && hasKey(this.sample, property)) {
+ mismatchKeys.push("expected has key '" + property + "', but missing from actual.");
+ }
+ else if (!env.equals_(this.sample[property], other[property], mismatchKeys, mismatchValues)) {
+ mismatchValues.push("'" + property + "' was '" + (other[property] ? jasmine.util.htmlEscape(other[property].toString()) : other[property]) + "' in expected, but was '" + (this.sample[property] ? jasmine.util.htmlEscape(this.sample[property].toString()) : this.sample[property]) + "' in actual.");
+ }
+ }
+
+ return (mismatchKeys.length === 0 && mismatchValues.length === 0);
+};
+
+jasmine.Matchers.ObjectContaining.prototype.jasmineToString = function () {
+ return "<jasmine.objectContaining(" + jasmine.pp(this.sample) + ")>";
+};
+// Mock setTimeout, clearTimeout
+// Contributed by Pivotal Computer Systems, www.pivotalsf.com
+
+jasmine.FakeTimer = function() {
+ this.reset();
+
+ var self = this;
+ self.setTimeout = function(funcToCall, millis) {
+ self.timeoutsMade++;
+ self.scheduleFunction(self.timeoutsMade, funcToCall, millis, false);
+ return self.timeoutsMade;
+ };
+
+ self.setInterval = function(funcToCall, millis) {
+ self.timeoutsMade++;
+ self.scheduleFunction(self.timeoutsMade, funcToCall, millis, true);
+ return self.timeoutsMade;
+ };
+
+ self.clearTimeout = function(timeoutKey) {
+ self.scheduledFunctions[timeoutKey] = jasmine.undefined;
+ };
+
+ self.clearInterval = function(timeoutKey) {
+ self.scheduledFunctions[timeoutKey] = jasmine.undefined;
+ };
+
+};
+
+jasmine.FakeTimer.prototype.reset = function() {
+ this.timeoutsMade = 0;
+ this.scheduledFunctions = {};
+ this.nowMillis = 0;
+};
+
+jasmine.FakeTimer.prototype.tick = function(millis) {
+ var oldMillis = this.nowMillis;
+ var newMillis = oldMillis + millis;
+ this.runFunctionsWithinRange(oldMillis, newMillis);
+ this.nowMillis = newMillis;
+};
+
+jasmine.FakeTimer.prototype.runFunctionsWithinRange = function(oldMillis, nowMillis) {
+ var scheduledFunc;
+ var funcsToRun = [];
+ for (var timeoutKey in this.scheduledFunctions) {
+ scheduledFunc = this.scheduledFunctions[timeoutKey];
+ if (scheduledFunc != jasmine.undefined &&
+ scheduledFunc.runAtMillis >= oldMillis &&
+ scheduledFunc.runAtMillis <= nowMillis) {
+ funcsToRun.push(scheduledFunc);
+ this.scheduledFunctions[timeoutKey] = jasmine.undefined;
+ }
+ }
+
+ if (funcsToRun.length > 0) {
+ funcsToRun.sort(function(a, b) {
+ return a.runAtMillis - b.runAtMillis;
+ });
+ for (var i = 0; i < funcsToRun.length; ++i) {
+ try {
+ var funcToRun = funcsToRun[i];
+ this.nowMillis = funcToRun.runAtMillis;
+ funcToRun.funcToCall();
+ if (funcToRun.recurring) {
+ this.scheduleFunction(funcToRun.timeoutKey,
+ funcToRun.funcToCall,
+ funcToRun.millis,
+ true);
+ }
+ } catch(e) {
+ }
+ }
+ this.runFunctionsWithinRange(oldMillis, nowMillis);
+ }
+};
+
+jasmine.FakeTimer.prototype.scheduleFunction = function(timeoutKey, funcToCall, millis, recurring) {
+ this.scheduledFunctions[timeoutKey] = {
+ runAtMillis: this.nowMillis + millis,
+ funcToCall: funcToCall,
+ recurring: recurring,
+ timeoutKey: timeoutKey,
+ millis: millis
+ };
+};
+
+/**
+ * @namespace
+ */
+jasmine.Clock = {
+ defaultFakeTimer: new jasmine.FakeTimer(),
+
+ reset: function() {
+ jasmine.Clock.assertInstalled();
+ jasmine.Clock.defaultFakeTimer.reset();
+ },
+
+ tick: function(millis) {
+ jasmine.Clock.assertInstalled();
+ jasmine.Clock.defaultFakeTimer.tick(millis);
+ },
+
+ runFunctionsWithinRange: function(oldMillis, nowMillis) {
+ jasmine.Clock.defaultFakeTimer.runFunctionsWithinRange(oldMillis, nowMillis);
+ },
+
+ scheduleFunction: function(timeoutKey, funcToCall, millis, recurring) {
+ jasmine.Clock.defaultFakeTimer.scheduleFunction(timeoutKey, funcToCall, millis, recurring);
+ },
+
+ useMock: function() {
+ if (!jasmine.Clock.isInstalled()) {
+ var spec = jasmine.getEnv().currentSpec;
+ spec.after(jasmine.Clock.uninstallMock);
+
+ jasmine.Clock.installMock();
+ }
+ },
+
+ installMock: function() {
+ jasmine.Clock.installed = jasmine.Clock.defaultFakeTimer;
+ },
+
+ uninstallMock: function() {
+ jasmine.Clock.assertInstalled();
+ jasmine.Clock.installed = jasmine.Clock.real;
+ },
+
+ real: {
+ setTimeout: jasmine.getGlobal().setTimeout,
+ clearTimeout: jasmine.getGlobal().clearTimeout,
+ setInterval: jasmine.getGlobal().setInterval,
+ clearInterval: jasmine.getGlobal().clearInterval
+ },
+
+ assertInstalled: function() {
+ if (!jasmine.Clock.isInstalled()) {
+ throw new Error("Mock clock is not installed, use jasmine.Clock.useMock()");
+ }
+ },
+
+ isInstalled: function() {
+ return jasmine.Clock.installed == jasmine.Clock.defaultFakeTimer;
+ },
+
+ installed: null
+};
+jasmine.Clock.installed = jasmine.Clock.real;
+
+//else for IE support
+jasmine.getGlobal().setTimeout = function(funcToCall, millis) {
+ if (jasmine.Clock.installed.setTimeout.apply) {
+ return jasmine.Clock.installed.setTimeout.apply(this, arguments);
+ } else {
+ return jasmine.Clock.installed.setTimeout(funcToCall, millis);
+ }
+};
+
+jasmine.getGlobal().setInterval = function(funcToCall, millis) {
+ if (jasmine.Clock.installed.setInterval.apply) {
+ return jasmine.Clock.installed.setInterval.apply(this, arguments);
+ } else {
+ return jasmine.Clock.installed.setInterval(funcToCall, millis);
+ }
+};
+
+jasmine.getGlobal().clearTimeout = function(timeoutKey) {
+ if (jasmine.Clock.installed.clearTimeout.apply) {
+ return jasmine.Clock.installed.clearTimeout.apply(this, arguments);
+ } else {
+ return jasmine.Clock.installed.clearTimeout(timeoutKey);
+ }
+};
+
+jasmine.getGlobal().clearInterval = function(timeoutKey) {
+ if (jasmine.Clock.installed.clearTimeout.apply) {
+ return jasmine.Clock.installed.clearInterval.apply(this, arguments);
+ } else {
+ return jasmine.Clock.installed.clearInterval(timeoutKey);
+ }
+};
+
+/**
+ * @constructor
+ */
+jasmine.MultiReporter = function() {
+ this.subReporters_ = [];
+};
+jasmine.util.inherit(jasmine.MultiReporter, jasmine.Reporter);
+
+jasmine.MultiReporter.prototype.addReporter = function(reporter) {
+ this.subReporters_.push(reporter);
+};
+
+(function() {
+ var functionNames = [
+ "reportRunnerStarting",
+ "reportRunnerResults",
+ "reportSuiteResults",
+ "reportSpecStarting",
+ "reportSpecResults",
+ "log"
+ ];
+ for (var i = 0; i < functionNames.length; i++) {
+ var functionName = functionNames[i];
+ jasmine.MultiReporter.prototype[functionName] = (function(functionName) {
+ return function() {
+ for (var j = 0; j < this.subReporters_.length; j++) {
+ var subReporter = this.subReporters_[j];
+ if (subReporter[functionName]) {
+ subReporter[functionName].apply(subReporter, arguments);
+ }
+ }
+ };
+ })(functionName);
+ }
+})();
+/**
+ * Holds results for a set of Jasmine spec. Allows for the results array to hold another jasmine.NestedResults
+ *
+ * @constructor
+ */
+jasmine.NestedResults = function() {
+ /**
+ * The total count of results
+ */
+ this.totalCount = 0;
+ /**
+ * Number of passed results
+ */
+ this.passedCount = 0;
+ /**
+ * Number of failed results
+ */
+ this.failedCount = 0;
+ /**
+ * Was this suite/spec skipped?
+ */
+ this.skipped = false;
+ /**
+ * @ignore
+ */
+ this.items_ = [];
+};
+
+/**
+ * Roll up the result counts.
+ *
+ * @param result
+ */
+jasmine.NestedResults.prototype.rollupCounts = function(result) {
+ this.totalCount += result.totalCount;
+ this.passedCount += result.passedCount;
+ this.failedCount += result.failedCount;
+};
+
+/**
+ * Adds a log message.
+ * @param values Array of message parts which will be concatenated later.
+ */
+jasmine.NestedResults.prototype.log = function(values) {
+ this.items_.push(new jasmine.MessageResult(values));
+};
+
+/**
+ * Getter for the results: message & results.
+ */
+jasmine.NestedResults.prototype.getItems = function() {
+ return this.items_;
+};
+
+/**
+ * Adds a result, tracking counts (total, passed, & failed)
+ * @param {jasmine.ExpectationResult|jasmine.NestedResults} result
+ */
+jasmine.NestedResults.prototype.addResult = function(result) {
+ if (result.type != 'log') {
+ if (result.items_) {
+ this.rollupCounts(result);
+ } else {
+ this.totalCount++;
+ if (result.passed()) {
+ this.passedCount++;
+ } else {
+ this.failedCount++;
+ }
+ }
+ }
+ this.items_.push(result);
+};
+
+/**
+ * @returns {Boolean} True if <b>everything</b> below passed
+ */
+jasmine.NestedResults.prototype.passed = function() {
+ return this.passedCount === this.totalCount;
+};
+/**
+ * Base class for pretty printing for expectation results.
+ */
+jasmine.PrettyPrinter = function() {
+ this.ppNestLevel_ = 0;
+};
+
+/**
+ * Formats a value in a nice, human-readable string.
+ *
+ * @param value
+ */
+jasmine.PrettyPrinter.prototype.format = function(value) {
+ this.ppNestLevel_++;
+ try {
+ if (value === jasmine.undefined) {
+ this.emitScalar('undefined');
+ } else if (value === null) {
+ this.emitScalar('null');
+ } else if (value === jasmine.getGlobal()) {
+ this.emitScalar('<global>');
+ } else if (value.jasmineToString) {
+ this.emitScalar(value.jasmineToString());
+ } else if (typeof value === 'string') {
+ this.emitString(value);
+ } else if (jasmine.isSpy(value)) {
+ this.emitScalar("spy on " + value.identity);
+ } else if (value instanceof RegExp) {
+ this.emitScalar(value.toString());
+ } else if (typeof value === 'function') {
+ this.emitScalar('Function');
+ } else if (typeof value.nodeType === 'number') {
+ this.emitScalar('HTMLNode');
+ } else if (value instanceof Date) {
+ this.emitScalar('Date(' + value + ')');
+ } else if (value.__Jasmine_been_here_before__) {
+ this.emitScalar('<circular reference: ' + (jasmine.isArray_(value) ? 'Array' : 'Object') + '>');
+ } else if (jasmine.isArray_(value) || typeof value == 'object') {
+ value.__Jasmine_been_here_before__ = true;
+ if (jasmine.isArray_(value)) {
+ this.emitArray(value);
+ } else {
+ this.emitObject(value);
+ }
+ delete value.__Jasmine_been_here_before__;
+ } else {
+ this.emitScalar(value.toString());
+ }
+ } finally {
+ this.ppNestLevel_--;
+ }
+};
+
+jasmine.PrettyPrinter.prototype.iterateObject = function(obj, fn) {
+ for (var property in obj) {
+ if (!obj.hasOwnProperty(property)) continue;
+ if (property == '__Jasmine_been_here_before__') continue;
+ fn(property, obj.__lookupGetter__ ? (obj.__lookupGetter__(property) !== jasmine.undefined &&
+ obj.__lookupGetter__(property) !== null) : false);
+ }
+};
+
+jasmine.PrettyPrinter.prototype.emitArray = jasmine.unimplementedMethod_;
+jasmine.PrettyPrinter.prototype.emitObject = jasmine.unimplementedMethod_;
+jasmine.PrettyPrinter.prototype.emitScalar = jasmine.unimplementedMethod_;
+jasmine.PrettyPrinter.prototype.emitString = jasmine.unimplementedMethod_;
+
+jasmine.StringPrettyPrinter = function() {
+ jasmine.PrettyPrinter.call(this);
+
+ this.string = '';
+};
+jasmine.util.inherit(jasmine.StringPrettyPrinter, jasmine.PrettyPrinter);
+
+jasmine.StringPrettyPrinter.prototype.emitScalar = function(value) {
+ this.append(value);
+};
+
+jasmine.StringPrettyPrinter.prototype.emitString = function(value) {
+ this.append("'" + value + "'");
+};
+
+jasmine.StringPrettyPrinter.prototype.emitArray = function(array) {
+ if (this.ppNestLevel_ > jasmine.MAX_PRETTY_PRINT_DEPTH) {
+ this.append("Array");
+ return;
+ }
+
+ this.append('[ ');
+ for (var i = 0; i < array.length; i++) {
+ if (i > 0) {
+ this.append(', ');
+ }
+ this.format(array[i]);
+ }
+ this.append(' ]');
+};
+
+jasmine.StringPrettyPrinter.prototype.emitObject = function(obj) {
+ if (this.ppNestLevel_ > jasmine.MAX_PRETTY_PRINT_DEPTH) {
+ this.append("Object");
+ return;
+ }
+
+ var self = this;
+ this.append('{ ');
+ var first = true;
+
+ this.iterateObject(obj, function(property, isGetter) {
+ if (first) {
+ first = false;
+ } else {
+ self.append(', ');
+ }
+
+ self.append(property);
+ self.append(' : ');
+ if (isGetter) {
+ self.append('<getter>');
+ } else {
+ self.format(obj[property]);
+ }
+ });
+
+ this.append(' }');
+};
+
+jasmine.StringPrettyPrinter.prototype.append = function(value) {
+ this.string += value;
+};
+jasmine.Queue = function(env) {
+ this.env = env;
+
+ // parallel to blocks. each true value in this array means the block will
+ // get executed even if we abort
+ this.ensured = [];
+ this.blocks = [];
+ this.running = false;
+ this.index = 0;
+ this.offset = 0;
+ this.abort = false;
+};
+
+jasmine.Queue.prototype.addBefore = function(block, ensure) {
+ if (ensure === jasmine.undefined) {
+ ensure = false;
+ }
+
+ this.blocks.unshift(block);
+ this.ensured.unshift(ensure);
+};
+
+jasmine.Queue.prototype.add = function(block, ensure) {
+ if (ensure === jasmine.undefined) {
+ ensure = false;
+ }
+
+ this.blocks.push(block);
+ this.ensured.push(ensure);
+};
+
+jasmine.Queue.prototype.insertNext = function(block, ensure) {
+ if (ensure === jasmine.undefined) {
+ ensure = false;
+ }
+
+ this.ensured.splice((this.index + this.offset + 1), 0, ensure);
+ this.blocks.splice((this.index + this.offset + 1), 0, block);
+ this.offset++;
+};
+
+jasmine.Queue.prototype.start = function(onComplete) {
+ this.running = true;
+ this.onComplete = onComplete;
+ this.next_();
+};
+
+jasmine.Queue.prototype.isRunning = function() {
+ return this.running;
+};
+
+jasmine.Queue.LOOP_DONT_RECURSE = true;
+
+jasmine.Queue.prototype.next_ = function() {
+ var self = this;
+ var goAgain = true;
+
+ while (goAgain) {
+ goAgain = false;
+
+ if (self.index < self.blocks.length && !(this.abort && !this.ensured[self.index])) {
+ var calledSynchronously = true;
+ var completedSynchronously = false;
+
+ var onComplete = function () {
+ if (jasmine.Queue.LOOP_DONT_RECURSE && calledSynchronously) {
+ completedSynchronously = true;
+ return;
+ }
+
+ if (self.blocks[self.index].abort) {
+ self.abort = true;
+ }
+
+ self.offset = 0;
+ self.index++;
+
+ var now = new Date().getTime();
+ if (self.env.updateInterval && now - self.env.lastUpdate > self.env.updateInterval) {
+ self.env.lastUpdate = now;
+ self.env.setTimeout(function() {
+ self.next_();
+ }, 0);
+ } else {
+ if (jasmine.Queue.LOOP_DONT_RECURSE && completedSynchronously) {
+ goAgain = true;
+ } else {
+ self.next_();
+ }
+ }
+ };
+ self.blocks[self.index].execute(onComplete);
+
+ calledSynchronously = false;
+ if (completedSynchronously) {
+ onComplete();
+ }
+
+ } else {
+ self.running = false;
+ if (self.onComplete) {
+ self.onComplete();
+ }
+ }
+ }
+};
+
+jasmine.Queue.prototype.results = function() {
+ var results = new jasmine.NestedResults();
+ for (var i = 0; i < this.blocks.length; i++) {
+ if (this.blocks[i].results) {
+ results.addResult(this.blocks[i].results());
+ }
+ }
+ return results;
+};
+
+
+/**
+ * Runner
+ *
+ * @constructor
+ * @param {jasmine.Env} env
+ */
+jasmine.Runner = function(env) {
+ var self = this;
+ self.env = env;
+ self.queue = new jasmine.Queue(env);
+ self.before_ = [];
+ self.after_ = [];
+ self.suites_ = [];
+};
+
+jasmine.Runner.prototype.execute = function() {
+ var self = this;
+ if (self.env.reporter.reportRunnerStarting) {
+ self.env.reporter.reportRunnerStarting(this);
+ }
+ self.queue.start(function () {
+ self.finishCallback();
+ });
+};
+
+jasmine.Runner.prototype.beforeEach = function(beforeEachFunction) {
+ beforeEachFunction.typeName = 'beforeEach';
+ this.before_.splice(0,0,beforeEachFunction);
+};
+
+jasmine.Runner.prototype.afterEach = function(afterEachFunction) {
+ afterEachFunction.typeName = 'afterEach';
+ this.after_.splice(0,0,afterEachFunction);
+};
+
+
+jasmine.Runner.prototype.finishCallback = function() {
+ this.env.reporter.reportRunnerResults(this);
+};
+
+jasmine.Runner.prototype.addSuite = function(suite) {
+ this.suites_.push(suite);
+};
+
+jasmine.Runner.prototype.add = function(block) {
+ if (block instanceof jasmine.Suite) {
+ this.addSuite(block);
+ }
+ this.queue.add(block);
+};
+
+jasmine.Runner.prototype.specs = function () {
+ var suites = this.suites();
+ var specs = [];
+ for (var i = 0; i < suites.length; i++) {
+ specs = specs.concat(suites[i].specs());
+ }
+ return specs;
+};
+
+jasmine.Runner.prototype.suites = function() {
+ return this.suites_;
+};
+
+jasmine.Runner.prototype.topLevelSuites = function() {
+ var topLevelSuites = [];
+ for (var i = 0; i < this.suites_.length; i++) {
+ if (!this.suites_[i].parentSuite) {
+ topLevelSuites.push(this.suites_[i]);
+ }
+ }
+ return topLevelSuites;
+};
+
+jasmine.Runner.prototype.results = function() {
+ return this.queue.results();
+};
+/**
+ * Internal representation of a Jasmine specification, or test.
+ *
+ * @constructor
+ * @param {jasmine.Env} env
+ * @param {jasmine.Suite} suite
+ * @param {String} description
+ */
+jasmine.Spec = function(env, suite, description) {
+ if (!env) {
+ throw new Error('jasmine.Env() required');
+ }
+ if (!suite) {
+ throw new Error('jasmine.Suite() required');
+ }
+ var spec = this;
+ spec.id = env.nextSpecId ? env.nextSpecId() : null;
+ spec.env = env;
+ spec.suite = suite;
+ spec.description = description;
+ spec.queue = new jasmine.Queue(env);
+
+ spec.afterCallbacks = [];
+ spec.spies_ = [];
+
+ spec.results_ = new jasmine.NestedResults();
+ spec.results_.description = description;
+ spec.matchersClass = null;
+};
+
+jasmine.Spec.prototype.getFullName = function() {
+ return this.suite.getFullName() + ' ' + this.description + '.';
+};
+
+
+jasmine.Spec.prototype.results = function() {
+ return this.results_;
+};
+
+/**
+ * All parameters are pretty-printed and concatenated together, then written to the spec's output.
+ *
+ * Be careful not to leave calls to <code>jasmine.log</code> in production code.
+ */
+jasmine.Spec.prototype.log = function() {
+ return this.results_.log(arguments);
+};
+
+jasmine.Spec.prototype.runs = function (func) {
+ var block = new jasmine.Block(this.env, func, this);
+ this.addToQueue(block);
+ return this;
+};
+
+jasmine.Spec.prototype.addToQueue = function (block) {
+ if (this.queue.isRunning()) {
+ this.queue.insertNext(block);
+ } else {
+ this.queue.add(block);
+ }
+};
+
+/**
+ * @param {jasmine.ExpectationResult} result
+ */
+jasmine.Spec.prototype.addMatcherResult = function(result) {
+ this.results_.addResult(result);
+};
+
+jasmine.Spec.prototype.expect = function(actual) {
+ var positive = new (this.getMatchersClass_())(this.env, actual, this);
+ positive.not = new (this.getMatchersClass_())(this.env, actual, this, true);
+ return positive;
+};
+
+/**
+ * Waits a fixed time period before moving to the next block.
+ *
+ * @deprecated Use waitsFor() instead
+ * @param {Number} timeout milliseconds to wait
+ */
+jasmine.Spec.prototype.waits = function(timeout) {
+ var waitsFunc = new jasmine.WaitsBlock(this.env, timeout, this);
+ this.addToQueue(waitsFunc);
+ return this;
+};
+
+/**
+ * Waits for the latchFunction to return true before proceeding to the next block.
+ *
+ * @param {Function} latchFunction
+ * @param {String} optional_timeoutMessage
+ * @param {Number} optional_timeout
+ */
+jasmine.Spec.prototype.waitsFor = function(latchFunction, optional_timeoutMessage, optional_timeout) {
+ var latchFunction_ = null;
+ var optional_timeoutMessage_ = null;
+ var optional_timeout_ = null;
+
+ for (var i = 0; i < arguments.length; i++) {
+ var arg = arguments[i];
+ switch (typeof arg) {
+ case 'function':
+ latchFunction_ = arg;
+ break;
+ case 'string':
+ optional_timeoutMessage_ = arg;
+ break;
+ case 'number':
+ optional_timeout_ = arg;
+ break;
+ }
+ }
+
+ var waitsForFunc = new jasmine.WaitsForBlock(this.env, optional_timeout_, latchFunction_, optional_timeoutMessage_, this);
+ this.addToQueue(waitsForFunc);
+ return this;
+};
+
+jasmine.Spec.prototype.fail = function (e) {
+ var expectationResult = new jasmine.ExpectationResult({
+ passed: false,
+ message: e ? jasmine.util.formatException(e) : 'Exception',
+ trace: { stack: e.stack }
+ });
+ this.results_.addResult(expectationResult);
+};
+
+jasmine.Spec.prototype.getMatchersClass_ = function() {
+ return this.matchersClass || this.env.matchersClass;
+};
+
+jasmine.Spec.prototype.addMatchers = function(matchersPrototype) {
+ var parent = this.getMatchersClass_();
+ var newMatchersClass = function() {
+ parent.apply(this, arguments);
+ };
+ jasmine.util.inherit(newMatchersClass, parent);
+ jasmine.Matchers.wrapInto_(matchersPrototype, newMatchersClass);
+ this.matchersClass = newMatchersClass;
+};
+
+jasmine.Spec.prototype.finishCallback = function() {
+ this.env.reporter.reportSpecResults(this);
+};
+
+jasmine.Spec.prototype.finish = function(onComplete) {
+ this.removeAllSpies();
+ this.finishCallback();
+ if (onComplete) {
+ onComplete();
+ }
+};
+
+jasmine.Spec.prototype.after = function(doAfter) {
+ if (this.queue.isRunning()) {
+ this.queue.add(new jasmine.Block(this.env, doAfter, this), true);
+ } else {
+ this.afterCallbacks.unshift(doAfter);
+ }
+};
+
+jasmine.Spec.prototype.execute = function(onComplete) {
+ var spec = this;
+ if (!spec.env.specFilter(spec)) {
+ spec.results_.skipped = true;
+ spec.finish(onComplete);
+ return;
+ }
+
+ this.env.reporter.reportSpecStarting(this);
+
+ spec.env.currentSpec = spec;
+
+ spec.addBeforesAndAftersToQueue();
+
+ spec.queue.start(function () {
+ spec.finish(onComplete);
+ });
+};
+
+jasmine.Spec.prototype.addBeforesAndAftersToQueue = function() {
+ var runner = this.env.currentRunner();
+ var i;
+
+ for (var suite = this.suite; suite; suite = suite.parentSuite) {
+ for (i = 0; i < suite.before_.length; i++) {
+ this.queue.addBefore(new jasmine.Block(this.env, suite.before_[i], this));
+ }
+ }
+ for (i = 0; i < runner.before_.length; i++) {
+ this.queue.addBefore(new jasmine.Block(this.env, runner.before_[i], this));
+ }
+ for (i = 0; i < this.afterCallbacks.length; i++) {
+ this.queue.add(new jasmine.Block(this.env, this.afterCallbacks[i], this), true);
+ }
+ for (suite = this.suite; suite; suite = suite.parentSuite) {
+ for (i = 0; i < suite.after_.length; i++) {
+ this.queue.add(new jasmine.Block(this.env, suite.after_[i], this), true);
+ }
+ }
+ for (i = 0; i < runner.after_.length; i++) {
+ this.queue.add(new jasmine.Block(this.env, runner.after_[i], this), true);
+ }
+};
+
+jasmine.Spec.prototype.explodes = function() {
+ throw 'explodes function should not have been called';
+};
+
+jasmine.Spec.prototype.spyOn = function(obj, methodName, ignoreMethodDoesntExist) {
+ if (obj == jasmine.undefined) {
+ throw "spyOn could not find an object to spy upon for " + methodName + "()";
+ }
+
+ if (!ignoreMethodDoesntExist && obj[methodName] === jasmine.undefined) {
+ throw methodName + '() method does not exist';
+ }
+
+ if (!ignoreMethodDoesntExist && obj[methodName] && obj[methodName].isSpy) {
+ throw new Error(methodName + ' has already been spied upon');
+ }
+
+ var spyObj = jasmine.createSpy(methodName);
+
+ this.spies_.push(spyObj);
+ spyObj.baseObj = obj;
+ spyObj.methodName = methodName;
+ spyObj.originalValue = obj[methodName];
+
+ obj[methodName] = spyObj;
+
+ return spyObj;
+};
+
+jasmine.Spec.prototype.removeAllSpies = function() {
+ for (var i = 0; i < this.spies_.length; i++) {
+ var spy = this.spies_[i];
+ spy.baseObj[spy.methodName] = spy.originalValue;
+ }
+ this.spies_ = [];
+};
+
+/**
+ * Internal representation of a Jasmine suite.
+ *
+ * @constructor
+ * @param {jasmine.Env} env
+ * @param {String} description
+ * @param {Function} specDefinitions
+ * @param {jasmine.Suite} parentSuite
+ */
+jasmine.Suite = function(env, description, specDefinitions, parentSuite) {
+ var self = this;
+ self.id = env.nextSuiteId ? env.nextSuiteId() : null;
+ self.description = description;
+ self.queue = new jasmine.Queue(env);
+ self.parentSuite = parentSuite;
+ self.env = env;
+ self.before_ = [];
+ self.after_ = [];
+ self.children_ = [];
+ self.suites_ = [];
+ self.specs_ = [];
+};
+
+jasmine.Suite.prototype.getFullName = function() {
+ var fullName = this.description;
+ for (var parentSuite = this.parentSuite; parentSuite; parentSuite = parentSuite.parentSuite) {
+ fullName = parentSuite.description + ' ' + fullName;
+ }
+ return fullName;
+};
+
+jasmine.Suite.prototype.finish = function(onComplete) {
+ this.env.reporter.reportSuiteResults(this);
+ this.finished = true;
+ if (typeof(onComplete) == 'function') {
+ onComplete();
+ }
+};
+
+jasmine.Suite.prototype.beforeEach = function(beforeEachFunction) {
+ beforeEachFunction.typeName = 'beforeEach';
+ this.before_.unshift(beforeEachFunction);
+};
+
+jasmine.Suite.prototype.afterEach = function(afterEachFunction) {
+ afterEachFunction.typeName = 'afterEach';
+ this.after_.unshift(afterEachFunction);
+};
+
+jasmine.Suite.prototype.results = function() {
+ return this.queue.results();
+};
+
+jasmine.Suite.prototype.add = function(suiteOrSpec) {
+ this.children_.push(suiteOrSpec);
+ if (suiteOrSpec instanceof jasmine.Suite) {
+ this.suites_.push(suiteOrSpec);
+ this.env.currentRunner().addSuite(suiteOrSpec);
+ } else {
+ this.specs_.push(suiteOrSpec);
+ }
+ this.queue.add(suiteOrSpec);
+};
+
+jasmine.Suite.prototype.specs = function() {
+ return this.specs_;
+};
+
+jasmine.Suite.prototype.suites = function() {
+ return this.suites_;
+};
+
+jasmine.Suite.prototype.children = function() {
+ return this.children_;
+};
+
+jasmine.Suite.prototype.execute = function(onComplete) {
+ var self = this;
+ this.queue.start(function () {
+ self.finish(onComplete);
+ });
+};
+jasmine.WaitsBlock = function(env, timeout, spec) {
+ this.timeout = timeout;
+ jasmine.Block.call(this, env, null, spec);
+};
+
+jasmine.util.inherit(jasmine.WaitsBlock, jasmine.Block);
+
+jasmine.WaitsBlock.prototype.execute = function (onComplete) {
+ if (jasmine.VERBOSE) {
+ this.env.reporter.log('>> Jasmine waiting for ' + this.timeout + ' ms...');
+ }
+ this.env.setTimeout(function () {
+ onComplete();
+ }, this.timeout);
+};
+/**
+ * A block which waits for some condition to become true, with timeout.
+ *
+ * @constructor
+ * @extends jasmine.Block
+ * @param {jasmine.Env} env The Jasmine environment.
+ * @param {Number} timeout The maximum time in milliseconds to wait for the condition to become true.
+ * @param {Function} latchFunction A function which returns true when the desired condition has been met.
+ * @param {String} message The message to display if the desired condition hasn't been met within the given time period.
+ * @param {jasmine.Spec} spec The Jasmine spec.
+ */
+jasmine.WaitsForBlock = function(env, timeout, latchFunction, message, spec) {
+ this.timeout = timeout || env.defaultTimeoutInterval;
+ this.latchFunction = latchFunction;
+ this.message = message;
+ this.totalTimeSpentWaitingForLatch = 0;
+ jasmine.Block.call(this, env, null, spec);
+};
+jasmine.util.inherit(jasmine.WaitsForBlock, jasmine.Block);
+
+jasmine.WaitsForBlock.TIMEOUT_INCREMENT = 10;
+
+jasmine.WaitsForBlock.prototype.execute = function(onComplete) {
+ if (jasmine.VERBOSE) {
+ this.env.reporter.log('>> Jasmine waiting for ' + (this.message || 'something to happen'));
+ }
+ var latchFunctionResult;
+ try {
+ latchFunctionResult = this.latchFunction.apply(this.spec);
+ } catch (e) {
+ this.spec.fail(e);
+ onComplete();
+ return;
+ }
+
+ if (latchFunctionResult) {
+ onComplete();
+ } else if (this.totalTimeSpentWaitingForLatch >= this.timeout) {
+ var message = 'timed out after ' + this.timeout + ' msec waiting for ' + (this.message || 'something to happen');
+ this.spec.fail({
+ name: 'timeout',
+ message: message
+ });
+
+ this.abort = true;
+ onComplete();
+ } else {
+ this.totalTimeSpentWaitingForLatch += jasmine.WaitsForBlock.TIMEOUT_INCREMENT;
+ var self = this;
+ this.env.setTimeout(function() {
+ self.execute(onComplete);
+ }, jasmine.WaitsForBlock.TIMEOUT_INCREMENT);
+ }
+};
+
+jasmine.version_= {
+ "major": 1,
+ "minor": 3,
+ "build": 1,
+ "revision": 1354556913
+};
diff --git a/debian/missing-sources/mediaelement/test/test.html b/debian/missing-sources/mediaelement/test/test.html
new file mode 100644
index 0000000..41b6f61
--- /dev/null
+++ b/debian/missing-sources/mediaelement/test/test.html
@@ -0,0 +1,237 @@
+<!DOCTYPE html>
+<html>
+<head>
+ <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
+ <meta http-equiv="X-UA-Compatible" content="IE=edge" />
+ <title>HTML5 MediaElement</title>
+
+ <script src="../build/jquery.js"></script>
+
+ <script src="../src/js/me-namespace.js" type="text/javascript"></script>
+ <script src="../src/js/me-utility.js" type="text/javascript"></script>
+ <script src="../src/js/me-i18n.js" type="text/javascript"></script>
+ <script src="../src/js/me-plugindetector.js" type="text/javascript"></script>
+ <script src="../src/js/me-featuredetection.js" type="text/javascript"></script>
+ <script src="../src/js/me-mediaelements.js" type="text/javascript"></script>
+ <script src="../src/js/me-shim.js" type="text/javascript"></script>
+
+ <script src="../src/js/mep-library.js" type="text/javascript"></script>
+ <script src="../src/js/mep-player.js" type="text/javascript"></script>
+ <script src="../src/js/mep-feature-playpause.js" type="text/javascript"></script>
+ <script src="../src/js/mep-feature-progress.js" type="text/javascript"></script>
+ <script src="../src/js/mep-feature-time.js" type="text/javascript"></script>
+ <script src="../src/js/mep-feature-tracks.js" type="text/javascript"></script>
+ <script src="../src/js/mep-feature-volume.js" type="text/javascript"></script>
+ <script src="../src/js/mep-feature-stop.js" type="text/javascript"></script>
+ <script src="../src/js/mep-feature-fullscreen.js" type="text/javascript"></script>
+ <link rel="stylesheet" href="../src/css/mediaelementplayer.css" />
+
+ <style>
+ #container{
+ width: 700px;
+ margin: 20px auto;
+ }
+ </style>
+</head>
+<body>
+
+<div id="container">
+
+<h1>MediaElementPlayer.js</h1>
+
+<p>Recommended Setup</p>
+
+<form>
+
+
+<h2>MP3 audio (as src)</h2>
+
+<audio id="player2" src="../media/AirReview-Landmarks-02-ChasingCorporate.mp3" preload="none" type="audio/mp3" controls="controls">
+ <p>Your browser leaves much to be desired.</p>
+</audio>
+
+<span id="audio-mode"></span>
+
+<h2>MP4/WebM</h2>
+
+
+<video width="640" height="360" id="player1" controls="controls" preload="none" poster="../media/echo-hereweare.jpg">
+
+ <source src="../media/echo-hereweare.mp4" type="video/mp4" />
+
+ <track kind="subtitles" src="../media/mediaelement.srt" srclang="en" ></track>
+
+</video>
+
+<span id="video-mode"></span>
+<div style="min-height: 400px">
+<div id="video-events"></div>
+<div id="video-props"></div>
+</div>
+
+<video width="640" height="360" id="player2" controls="controls" preload="none" poster="../media/big_buck_bunny.jpg">
+ <!--
+ <source src="../media/big_buck_bunny.mp4" type="video/mp4" />
+ -->
+
+ <source src="../media/big_buck_bunny.webm" type="video/webm" />
+</video>
+
+
+</form>
+
+</div>
+
+
+<script>
+function appendMediaEvents($node, media) {
+ var
+ mediaEventNames = 'loadstart progress suspend abort error emptied stalled play pause loadedmetadata loadeddata waiting playing canplay canplaythrough seeking seeked timeupdate ended ratechange durationchange volumechange'.split(' ');
+ mediaEventTable = $('<table class="media-events"><caption>Media Events</caption><tbody></tbody></table>').appendTo($node).find('tbody'),
+ tr = null,
+ th = null,
+ td = null,
+ eventName = null,
+ il = 0,
+ i=0;
+
+ for (il = mediaEventNames.length;i<il;i++) {
+ eventName = mediaEventNames[i];
+ th = $('<th>' + eventName + '</th>');
+ td = $('<td id="e_' + media.id + '_' + eventName + '" class="not-fired">0</td>');
+
+ if (tr == null)
+ tr = $("<tr/>");
+
+ tr.append(th);
+ tr.append(td);
+
+ if ((i+1) % 5 == 0) {
+ mediaEventTable.append(tr);
+ tr = null;
+ }
+
+ // listen for event
+ media.addEventListener(eventName, function(e) {
+
+ var notice = $('#e_' + media.id + '_' + e.type),
+ number = parseInt(notice.html(), 10);
+
+ notice
+ .html(number+1)
+ .attr('class','fired');
+ }, true);
+ }
+
+ mediaEventTable.append(tr);
+}
+
+function appendMediaProperties($node, media) {
+ var /* src currentSrc */
+ mediaPropertyNames = 'error currentSrc networkState preload buffered bufferedBytes bufferedTime readyState seeking currentTime initialTime duration startOffsetTime paused defaultPlaybackRate playbackRate played seekable ended autoplay loop controls volume muted'.split(' '),
+ mediaPropertyTable = $('<table class="media-properties"><caption>Media Properties</caption><tbody></tbody></table>').appendTo($node).find('tbody'),
+ tr = null,
+ th = null,
+ td = null,
+ propName = null,
+ il = 0,
+ i=0;
+
+ for (il = mediaPropertyNames.length; i<il; i++) {
+ propName = mediaPropertyNames[i];
+ th = $('<th>' + propName + '</th>');
+ td = $('<td id="p_' + media.id + '_' + propName + '" class=""></td>');
+
+ if (tr == null)
+ tr = $("<tr/>");
+
+ tr.append(th);
+ tr.append(td);
+
+ if ((i+1) % 3 == 0) {
+ mediaPropertyTable.append(tr);
+ tr = null;
+ }
+ }
+
+ setInterval(function() {
+ var
+ propName = '',
+ val = null,
+ td = null;
+
+ for (i = 0, il = mediaPropertyNames.length; i<il; i++) {
+ propName = mediaPropertyNames[i];
+ td = $('#p_' + media.id + '_' + propName);
+ val = media[propName];
+ val =
+ (typeof val == 'undefined') ?
+ 'undefined' : (val == null) ? 'null' : val.toString();
+ td.html(val);
+ }
+ }, 500);
+
+}
+
+</script>
+
+
+<script type="text/javascript">
+$('audio, video').bind('error', function(e) {
+
+ //console.log('error',this, e, this.src, this.error.code);
+});
+
+jQuery(document).ready(function() {
+ $('audio, video').mediaelementplayer({
+ mode: 'shim',
+
+ pluginPath:'../build/',
+ enablePluginSmoothing:true,
+ //duration: 489,
+ //startVolume: 0.4,
+ enablePluginDebug: true,
+ //iPadUseNativeControls: true,
+ //mode: 'shim',
+ //forcePluginFullScreen: true,
+ usePluginFullScreen: true,
+ //mode: 'native',
+ //plugins: ['silverlight'],
+ //features: ['playpause','volume','stop'],
+ success: function(me,node) {
+ // report type
+ var tagName = node.tagName.toLowerCase();
+ $('#' + tagName + '-mode').html( me.pluginType + ': success' + ', touch: ' + mejs.MediaFeatures.hasTouch);
+
+
+ if (tagName == 'audio') {
+
+ me.addEventListener('progress',function(e) {
+ //console.log(e);
+ }, false);
+
+ }
+
+ me.addEventListener('progress',function(e) {
+ //console.log(e);
+ }, false);
+
+
+ // add events
+ if (tagName == 'video' && node.id == 'player1') {
+ appendMediaProperties($('#' + tagName + '-props'), me);
+ appendMediaEvents($('#' + tagName + '-events'), me);
+
+ }
+ }
+ });
+
+
+
+});
+
+</script>
+
+
+</body>
+</html> \ No newline at end of file
diff --git a/debian/missing-sources/plupload/csharp/Plupload/App.xaml b/debian/missing-sources/plupload/csharp/Plupload/App.xaml
new file mode 100644
index 0000000..32f7a7e
--- /dev/null
+++ b/debian/missing-sources/plupload/csharp/Plupload/App.xaml
@@ -0,0 +1,8 @@
+<Application
+ xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
+ xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
+ x:Class="Moxiecode.Plupload.App">
+ <Application.Resources>
+ <!-- Resources scoped at the Application level should be defined here. -->
+ </Application.Resources>
+</Application>
diff --git a/debian/missing-sources/plupload/csharp/Plupload/App.xaml.cs b/debian/missing-sources/plupload/csharp/Plupload/App.xaml.cs
new file mode 100644
index 0000000..9683c6d
--- /dev/null
+++ b/debian/missing-sources/plupload/csharp/Plupload/App.xaml.cs
@@ -0,0 +1,45 @@
+/**
+ * App.xaml.cs
+ *
+ * Copyright 2009, Moxiecode Systems AB
+ * Released under GPL License.
+ *
+ * License: http://www.plupload.com/license
+ * Contributing: http://www.plupload.com/contributing
+ */
+
+using System.Windows;
+using System;
+using System.Windows.Browser;
+
+namespace Moxiecode.Plupload {
+ /// <summary>
+ /// Partial class for the Silverlight application.
+ /// </summary>
+ public partial class App : Application {
+ public App() {
+ this.Startup += this.OnStartup;
+ this.UnhandledException += this.Application_UnhandledException;
+
+ InitializeComponent();
+ }
+
+ private void OnStartup(object sender, StartupEventArgs e) {
+ this.RootVisual = new Page(e.InitParams);
+ }
+
+ private void Application_UnhandledException(object sender, ApplicationUnhandledExceptionEventArgs e) {
+ if (!System.Diagnostics.Debugger.IsAttached) {
+ e.Handled = true;
+
+ try {
+ string errorMsg = e.ExceptionObject.Message + @"\n" + e.ExceptionObject.StackTrace;
+ errorMsg = errorMsg.Replace("\"", "\\\"").Replace("\r\n", @"\n");
+
+ System.Windows.Browser.HtmlPage.Window.Eval("throw new Error(\"Unhandled Error in Silverlight 2 Application: " + errorMsg + "\");");
+ } catch (Exception) {
+ }
+ }
+ }
+ }
+} \ No newline at end of file
diff --git a/debian/missing-sources/plupload/csharp/Plupload/FJCore/DCT.cs b/debian/missing-sources/plupload/csharp/Plupload/FJCore/DCT.cs
new file mode 100644
index 0000000..e621799
--- /dev/null
+++ b/debian/missing-sources/plupload/csharp/Plupload/FJCore/DCT.cs
@@ -0,0 +1,222 @@
+/// Copyright (c) 2008 Jeffrey Powers for Fluxcapacity Open Source.
+/// Under the MIT License, details: License.txt..
+
+// NOTE: Compile with DYNAMIC_IDCT for a decode performance boost.
+// May not yield a perceptible boost for small images,
+// since there is some overhead in emitting CIL dynamically.
+
+using System;
+using System.Reflection.Emit;
+using System.Reflection;
+
+namespace FluxJpeg.Core
+{
+ /// <summary>
+ /// Implements the Discrete Cosine Transform with dynamic CIL
+ /// </summary>
+ public partial class DCT
+ {
+ private float[] _temp = new float[64];
+
+ // Cosine matrix and transposed cosine matrix
+ private static readonly float[,] c = buildC();
+ private static readonly float[,] cT = buildCT();
+
+ internal DCT()
+ {
+ #if DYNAMIC_IDCT
+ dynamicIDCT = dynamicIDCT ?? EmitIDCT();
+ #endif
+ }
+
+ /// <summary>
+ /// Precomputes cosine terms in A.3.3 of
+ /// http://www.w3.org/Graphics/JPEG/itu-t81.pdf
+ ///
+ /// Closely follows the term precomputation in the
+ /// Java Advanced Imaging library.
+ /// </summary>
+ private static float[,] buildC()
+ {
+ float[,] c = new float[8, 8];
+
+ for (int i = 0; i < 8; i++) // i == u or v
+ {
+ for (int j = 0; j < 8; j++) // j == x or y
+ {
+ c[i, j] = i == 0 ?
+ 0.353553391f : /* 1 / SQRT(8) */
+ (float)(0.5 * Math.Cos(((2.0 * j + 1) * i * Math.PI) / 16.0));
+ }
+ }
+
+ return c;
+ }
+ private static float[,] buildCT()
+ {
+ // Transpose i,k <-- j,i
+ float[,] cT = new float[8, 8];
+ for (int i = 0; i < 8; i++)
+ for (int j = 0; j < 8; j++)
+ cT[j, i] = c[i, j];
+ return cT;
+ }
+
+ public static void SetValueClipped(byte[,] arr, int i, int j, float val)
+ {
+ // Clip into the 0...255 range & round
+ arr[i, j] = val < 0 ? (byte)0
+ : val > 255 ? (byte)255
+ : (byte)(val + 0.5);
+ }
+
+ /// See figure A.3.3 IDCT (informative) on A-5.
+ /// http://www.w3.org/Graphics/JPEG/itu-t81.pdf
+ internal byte[,] FastIDCT(float[] input)
+ {
+ byte[,] output = new byte[8, 8];
+
+ #if DYNAMIC_IDCT
+
+ // Fastest, dynamic MSIL stream
+ dynamicIDCT(input, _temp, output);
+
+ #else
+
+ #region Slower, easy-to-read, pure C# IDCT
+
+ float temp, val = 0;
+ int idx = 0;
+ for (int i = 0; i < 8; i++)
+ {
+ for (int j = 0; j < 8; j++)
+ {
+ val = 0;
+
+ for(int k = 0; k < 8; k++)
+ {
+ val += input[i * 8 + k] * c[k, j];
+ }
+
+ _temp[idx++] = val;
+ }
+ }
+ for (int i = 0; i < 8; i++)
+ {
+ for (int j = 0; j < 8; j++)
+ {
+ temp = 128f;
+
+ for (int k = 0; k < 8; k++)
+ {
+ temp += cT[i, k] * _temp[k * 8 + j];
+ }
+
+ if (temp < 0) output[i, j] = 0;
+ else if (temp > 255) output[i, j] = 255;
+ else output[i, j] = (byte)(temp + 0.5); // Implements rounding
+ }
+ }
+
+
+ #endregion
+
+ #endif
+
+ return output;
+ }
+
+
+
+ #if DYNAMIC_IDCT
+
+ /// <summary>
+ /// Generates a pure-IL nonbranching stream of instructions
+ /// that perform the inverse DCT. Relies on helper function
+ /// SetValueClipped.
+ /// </summary>
+ /// <returns>A delegate to the DynamicMethod</returns>
+ private static IDCTFunc EmitIDCT()
+ {
+ Type[] args = { typeof(float[]), typeof(float[]), typeof(byte[,]) };
+
+ DynamicMethod idctMethod = new DynamicMethod("dynamicIDCT",
+ null, // no return type
+ args); // input arrays
+
+ ILGenerator il = idctMethod.GetILGenerator();
+
+ int idx = 0;
+
+ for (int i = 0; i < 8; i++)
+ {
+ for (int j = 0; j < 8; j++)
+ {
+ il.Emit(OpCodes.Ldarg_1); // 1 {temp}
+ il.Emit(OpCodes.Ldc_I4_S, (short)idx++); // 3 {temp, idx}
+
+ for (int k = 0; k < 8; k++)
+ {
+ il.Emit(OpCodes.Ldarg_0); // {in}
+ il.Emit(OpCodes.Ldc_I4_S, (short)(i * 8 + k)); // {in,idx}
+ il.Emit(OpCodes.Ldelem_R4); // {in[idx]}
+ il.Emit(OpCodes.Ldc_R4, c[k, j]); // {in[idx],c[k,j]}
+ il.Emit(OpCodes.Mul); // {in[idx]*c[k,j]}
+ if (k != 0) il.Emit(OpCodes.Add);
+ }
+
+ il.Emit(OpCodes.Stelem_R4); // {}
+ }
+ }
+
+ var meth = typeof(DCT).GetMethod("SetValueClipped",
+ BindingFlags.Static | BindingFlags.Public, null,
+ CallingConventions.Standard,
+ new Type[] {
+ typeof(byte[,]), // arr
+ typeof(int), // i
+ typeof(int), // j
+ typeof(float) } // val
+ , null);
+
+ for (int i = 0; i < 8; i++)
+ {
+ for (int j = 0; j < 8; j++)
+ {
+ il.Emit(OpCodes.Ldarg_2); // {output}
+ il.Emit(OpCodes.Ldc_I4_S, (short)i); // {output,i}
+ il.Emit(OpCodes.Ldc_I4_S, (short)j); // X={output,i,j}
+
+ il.Emit(OpCodes.Ldc_R4, 128.0f); // {X,128.0f}
+
+ for (int k = 0; k < 8; k++)
+ {
+ il.Emit(OpCodes.Ldarg_1); // {X,temp}
+ il.Emit(OpCodes.Ldc_I4_S,
+ (short)(k * 8 + j)); // {X,temp,idx}
+ il.Emit(OpCodes.Ldelem_R4); // {X,temp[idx]}
+ il.Emit(OpCodes.Ldc_R4, cT[i, k]); // {X,temp[idx],cT[i,k]}
+ il.Emit(OpCodes.Mul); // {X,in[idx]*c[k,j]}
+ il.Emit(OpCodes.Add);
+ }
+
+ il.EmitCall(OpCodes.Call, meth, null);
+ }
+ }
+
+ il.Emit(OpCodes.Ret);
+
+ return (IDCTFunc)idctMethod.CreateDelegate(typeof(IDCTFunc));
+ }
+
+ private delegate void IDCTFunc(float[] input, float[] temp, byte[,] output);
+ private static IDCTFunc dynamicIDCT = null;
+#endif
+
+
+ }
+
+
+
+
+}
diff --git a/debian/missing-sources/plupload/csharp/Plupload/FJCore/DecodedJpeg.cs b/debian/missing-sources/plupload/csharp/Plupload/FJCore/DecodedJpeg.cs
new file mode 100644
index 0000000..96ca213
--- /dev/null
+++ b/debian/missing-sources/plupload/csharp/Plupload/FJCore/DecodedJpeg.cs
@@ -0,0 +1,121 @@
+/// Copyright (c) 2008 Jeffrey Powers for Fluxcapacity Open Source.
+/// Under the MIT License, details: License.txt.
+
+using System;
+using System.Collections.Generic;
+using System.Text;
+
+namespace FluxJpeg.Core
+{
+ public class JpegHeader
+ {
+ public byte Marker;
+ public byte[] Data;
+ internal bool IsJFIF = false;
+ public new string ToString { get { return Encoding.UTF8.GetString(Data, 0, Data.Length); } }
+ }
+
+ public class DecodedJpeg
+ {
+ private Image _image; public Image Image { get { return _image; } }
+
+ internal int[] BlockWidth;
+ internal int[] BlockHeight;
+
+ internal int Precision = 8;
+ internal int[] HsampFactor = { 1, 1, 1 };
+ internal int[] VsampFactor = { 1, 1, 1 };
+ internal bool[] lastColumnIsDummy = new bool[] { false, false, false };
+ internal bool[] lastRowIsDummy = new bool[] { false, false, false };
+
+ internal int[] compWidth, compHeight;
+ internal int MaxHsampFactor;
+ internal int MaxVsampFactor;
+
+ public bool HasJFIF { get; private set; }
+
+ private List<JpegHeader> _metaHeaders;
+
+ public IList<JpegHeader> MetaHeaders { get { return _metaHeaders.AsReadOnly(); } }
+
+ public DecodedJpeg(Image image, IEnumerable<JpegHeader> metaHeaders)
+ {
+ _image = image;
+
+ // Handles null as an empty list
+ _metaHeaders = (metaHeaders == null) ?
+ new List<JpegHeader>(0) : new List<JpegHeader>(metaHeaders);
+
+ // Check if the JFIF header was present
+ foreach (JpegHeader h in _metaHeaders)
+ if (h.IsJFIF) { HasJFIF = true; break; }
+
+ int components = _image.ComponentCount;
+
+ compWidth = new int[components];
+ compHeight = new int[components];
+ BlockWidth = new int[components];
+ BlockHeight = new int[components];
+
+ Initialize();
+ }
+
+ public DecodedJpeg(Image image)
+ : this(image, null)
+ {
+ _metaHeaders = new List<JpegHeader>();
+
+ string comment = "Jpeg Codec | fluxcapacity.net ";
+
+ _metaHeaders.Add(
+ new JpegHeader() {
+ Marker = JPEGMarker.COM,
+ Data = System.Text.Encoding.UTF8.GetBytes(comment)
+ }
+ );
+ }
+
+ /// <summary>
+ /// This method creates and fills three arrays, Y, Cb, and Cr using the input image.
+ /// </summary>
+ private void Initialize()
+ {
+ int w = _image.Width, h = _image.Height;
+
+ int y;
+
+ MaxHsampFactor = 1;
+ MaxVsampFactor = 1;
+
+ for (y = 0; y < _image.ComponentCount; y++)
+ {
+ MaxHsampFactor = Math.Max(MaxHsampFactor, HsampFactor[y]);
+ MaxVsampFactor = Math.Max(MaxVsampFactor, VsampFactor[y]);
+ }
+ for (y = 0; y < _image.ComponentCount; y++)
+ {
+ compWidth[y] = (((w % 8 != 0) ? ((int)Math.Ceiling((double)w / 8.0)) * 8 : w) / MaxHsampFactor) * HsampFactor[y];
+ if (compWidth[y] != ((w / MaxHsampFactor) * HsampFactor[y]))
+ {
+ lastColumnIsDummy[y] = true;
+ }
+
+ // results in a multiple of 8 for compWidthz
+ // this will make the rest of the program fail for the unlikely
+ // event that someone tries to compress an 16 x 16 pixel image
+ // which would of course be worse than pointless
+
+ BlockWidth[y] = (int)Math.Ceiling((double)compWidth[y] / 8.0);
+ compHeight[y] = (((h % 8 != 0) ? ((int)Math.Ceiling((double)h / 8.0)) * 8 : h) / MaxVsampFactor) * VsampFactor[y];
+ if (compHeight[y] != ((h / MaxVsampFactor) * VsampFactor[y]))
+ {
+ lastRowIsDummy[y] = true;
+ }
+
+ BlockHeight[y] = (int)Math.Ceiling((double)compHeight[y] / 8.0);
+ }
+ }
+
+ }
+
+} \ No newline at end of file
diff --git a/debian/missing-sources/plupload/csharp/Plupload/FJCore/Decoder/HuffmanTable.cs b/debian/missing-sources/plupload/csharp/Plupload/FJCore/Decoder/HuffmanTable.cs
new file mode 100644
index 0000000..3da2818
--- /dev/null
+++ b/debian/missing-sources/plupload/csharp/Plupload/FJCore/Decoder/HuffmanTable.cs
@@ -0,0 +1,487 @@
+/// Copyright (c) 2008 Jeffrey Powers for Fluxcapacity Open Source.
+/// Under the MIT License, details: License.txt.
+
+// Partially derives from a Java encoder, JpegEncoder.java by James R Weeks.
+// Implements Baseline JPEG Encoding http://www.opennet.ru/docs/formats/jpeg.txt
+
+using System;
+
+using FluxJpeg.Core.IO;
+using System.IO;
+using System.Collections.Generic;
+
+namespace FluxJpeg.Core
+{
+ internal class HuffmanTable
+ {
+ public static int HUFFMAN_MAX_TABLES = 4;
+
+ private short[] huffcode = new short[256];
+ private short[] huffsize = new short[256];
+ private short[] valptr = new short[16];
+ private short[] mincode = {-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,-1,-1};
+ private short[] maxcode = {-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1};
+
+ private short[] huffval;
+ private short[] bits;
+
+ int bufferPutBits, bufferPutBuffer;
+ internal int ImageHeight;
+ internal int ImageWidth;
+ internal int[,] DC_matrix0;
+ internal int[,] AC_matrix0;
+ internal int[,] DC_matrix1;
+ internal int[,] AC_matrix1;
+ internal int[][,] DC_matrix;
+ internal int[][,] AC_matrix;
+ internal int NumOfDCTables;
+ internal int NumOfACTables;
+
+ public List<short[]> bitsList;
+ public List<short[]> val;
+
+
+ public static byte JPEG_DC_TABLE = 0;
+ public static byte JPEG_AC_TABLE = 1;
+
+ private short lastk = 0;
+
+ internal HuffmanTable(JpegHuffmanTable table)
+ {
+ if (table != null)
+ {
+ huffval = table.Values;
+ bits = table.Lengths;
+
+ GenerateSizeTable();
+ GenerateCodeTable();
+ GenerateDecoderTables();
+ }
+ else
+ {
+ // Encode initialization
+
+ bitsList = new List<short[]>();
+ bitsList.Add(JpegHuffmanTable.StdDCLuminance.Lengths);
+ bitsList.Add(JpegHuffmanTable.StdACLuminance.Lengths);
+ bitsList.Add(JpegHuffmanTable.StdDCChrominance.Lengths);
+ bitsList.Add(JpegHuffmanTable.StdACChrominance.Lengths);
+
+ val = new List<short[]>();
+ val.Add(JpegHuffmanTable.StdDCLuminance.Values);
+ val.Add(JpegHuffmanTable.StdACLuminance.Values);
+ val.Add(JpegHuffmanTable.StdDCChrominance.Values);
+ val.Add(JpegHuffmanTable.StdACChrominance.Values);
+
+ initHuf();
+ }
+ }
+
+ /// <summary>See Figure C.1</summary>
+ private void GenerateSizeTable()
+ {
+ short index = 0;
+ for (short i = 0; i < bits.Length; i++)
+ {
+ for (short j = 0; j < bits[i]; j++)
+ {
+ huffsize[index] = (short)(i + 1);
+ index++;
+ }
+ }
+ lastk = index;
+ }
+
+ /// <summary>See Figure C.2</summary>
+ private void GenerateCodeTable()
+ {
+ short k = 0;
+ short si = huffsize[0];
+ short code = 0;
+ for (short i = 0; i < huffsize.Length; i++)
+ {
+ while (huffsize[k] == si)
+ {
+ huffcode[k] = code;
+ code++;
+ k++;
+ }
+ code <<= 1;
+ si++;
+ }
+ }
+
+ /// <summary>See figure F.15</summary>
+ private void GenerateDecoderTables()
+ {
+ short bitcount = 0;
+ for (int i = 0; i < 16; i++)
+ {
+ if (bits[i] != 0)
+ valptr[i] = bitcount;
+ for (int j = 0; j < bits[i]; j++)
+ {
+ if (huffcode[j + bitcount] < mincode[i] || mincode[i] == -1)
+ mincode[i] = huffcode[j + bitcount];
+
+ if (huffcode[j + bitcount] > maxcode[i])
+ maxcode[i] = huffcode[j + bitcount];
+ }
+ if (mincode[i] != -1)
+ valptr[i] = (short)(valptr[i] - mincode[i]);
+ bitcount += bits[i];
+ }
+ }
+
+ /// <summary>Figure F.12</summary>
+ public static int Extend(int diff, int t)
+ {
+ // here we use bitshift to implement 2^ ...
+ // NOTE: Math.Pow returns 0 for negative powers, which occassionally happen here!
+
+ int Vt = 1 << t - 1;
+ // WAS: int Vt = (int)Math.Pow(2, (t - 1));
+
+ if (diff < Vt)
+ {
+ Vt = (-1 << t) + 1;
+ diff = diff + Vt;
+ }
+ return diff;
+ }
+
+ /// <summary>Figure F.16 - Reads the huffman code bit-by-bit.</summary>
+ /*public int Decode(JPEGBinaryReader JPEGStream)
+ {
+ int i = 0;
+ short code = (short)JPEGStream.ReadBits(1);
+ while (code > maxcode[i])
+ {
+ i++;
+ code <<= 1;
+ code |= (short)JPEGStream.ReadBits(1);
+ }
+ int val = huffval[code + (valptr[i])];
+ if (val < 0)
+ val = 256 + val;
+ return val;
+ }*/
+
+ /// <summary>
+ /// HuffmanBlockEncoder run length encodes and Huffman encodes the quantized data.
+ /// </summary>
+ internal void HuffmanBlockEncoder(Stream outStream, int[] zigzag, int prec, int DCcode, int ACcode)
+ {
+ int temp, temp2, nbits, k, r, i;
+
+ NumOfDCTables = 2;
+ NumOfACTables = 2;
+
+ // The DC portion
+
+ temp = temp2 = zigzag[0] - prec;
+ if (temp < 0)
+ {
+ temp = -temp;
+ temp2--;
+ }
+ nbits = 0;
+ while (temp != 0)
+ {
+ nbits++;
+ temp >>= 1;
+ }
+ // if (nbits > 11) nbits = 11;
+ bufferIt(outStream,
+ DC_matrix[DCcode][nbits, 0],
+ DC_matrix[DCcode][nbits, 1]);
+
+ // The arguments in bufferIt are code and size.
+ if (nbits != 0)
+ {
+ bufferIt(outStream, temp2, nbits);
+ }
+
+ // The AC portion
+
+ r = 0;
+
+ for (k = 1; k < 64; k++)
+ {
+ if ((temp = zigzag[ ZigZag.ZigZagMap[k] ]) == 0)
+ {
+ r++;
+ }
+ else
+ {
+ while (r > 15)
+ {
+ bufferIt(outStream,
+ AC_matrix[ACcode][0xF0, 0],
+ AC_matrix[ACcode][0xF0, 1]);
+
+ r -= 16;
+ }
+ temp2 = temp;
+ if (temp < 0)
+ {
+ temp = -temp;
+ temp2--;
+ }
+ nbits = 1;
+ while ((temp >>= 1) != 0)
+ {
+ nbits++;
+ }
+ i = (r << 4) + nbits;
+ bufferIt(outStream,
+ AC_matrix[ACcode][i, 0],
+ AC_matrix[ACcode][i, 1]);
+ bufferIt(outStream, temp2, nbits);
+
+ r = 0;
+ }
+ }
+
+ if (r > 0)
+ {
+ bufferIt(outStream,
+ AC_matrix[ACcode][0, 0],
+ AC_matrix[ACcode][0, 1]);
+ }
+ }
+
+ /// <summary>
+ /// Uses an integer long (32 bits) buffer to store the Huffman encoded bits
+ /// and sends them to outStream by the byte.
+ /// </summary>
+ void bufferIt(Stream outStream, int code, int size)
+ {
+ int PutBuffer = code;
+ int PutBits = bufferPutBits;
+
+ PutBuffer &= (1 << size) - 1;
+ PutBits += size;
+ PutBuffer <<= 24 - PutBits;
+ PutBuffer |= bufferPutBuffer;
+
+ while (PutBits >= 8)
+ {
+ int c = ((PutBuffer >> 16) & 0xFF);
+ outStream.WriteByte((byte)c);
+
+ // FF must be escaped
+ if (c == 0xFF) outStream.WriteByte(0);
+
+ PutBuffer <<= 8;
+ PutBits -= 8;
+ }
+ bufferPutBuffer = PutBuffer;
+ bufferPutBits = PutBits;
+
+ }
+
+ public void FlushBuffer(Stream outStream)
+ {
+ int PutBuffer = bufferPutBuffer;
+ int PutBits = bufferPutBits;
+ while (PutBits >= 8)
+ {
+ int c = ((PutBuffer >> 16) & 0xFF);
+ outStream.WriteByte((byte)c);
+
+ // FF must be escaped
+ if (c == 0xFF) outStream.WriteByte(0);
+
+ PutBuffer <<= 8;
+ PutBits -= 8;
+ }
+ if (PutBits > 0)
+ {
+ int c = ((PutBuffer >> 16) & 0xFF);
+ outStream.WriteByte((byte)c);
+ }
+ }
+
+
+ /// <summary>
+ /// Initialisation of the Huffman codes for Luminance and Chrominance.
+ /// This code results in the same tables created in the IJG Jpeg-6a
+ /// library.
+ /// </summary>
+ public void initHuf()
+ {
+ DC_matrix0 = new int[12, 2];
+ DC_matrix1 = new int[12, 2];
+ AC_matrix0 = new int[255, 2];
+ AC_matrix1 = new int[255, 2];
+ DC_matrix = new int[2][,];
+ AC_matrix = new int[2][,];
+ int p, l, i, lastp, si, code;
+ int[] huffsize = new int[257];
+ int[] huffcode = new int[257];
+
+ short[] bitsDCchrominance = JpegHuffmanTable.StdDCChrominance.Lengths;
+ short[] bitsACchrominance = JpegHuffmanTable.StdACChrominance.Lengths;
+ short[] bitsDCluminance = JpegHuffmanTable.StdDCLuminance.Lengths;
+ short[] bitsACluminance = JpegHuffmanTable.StdACLuminance.Lengths;
+
+
+ short[] valDCchrominance = JpegHuffmanTable.StdDCChrominance.Values;
+ short[] valACchrominance = JpegHuffmanTable.StdACChrominance.Values;
+ short[] valDCluminance = JpegHuffmanTable.StdDCLuminance.Values;
+ short[] valACluminance = JpegHuffmanTable.StdACLuminance.Values;
+
+
+ /*
+ * init of the DC values for the chrominance
+ * [,0] is the code [,1] is the number of bit
+ */
+
+ p = 0;
+ for (l = 0; l < 16; l++)
+ {
+ for (i = 1; i <= bitsDCchrominance[l]; i++)
+ {
+ huffsize[p++] = l+1;
+ }
+ }
+
+ huffsize[p] = 0;
+ lastp = p;
+
+ code = 0;
+ si = huffsize[0];
+ p = 0;
+ while (huffsize[p] != 0)
+ {
+ while (huffsize[p] == si)
+ {
+ huffcode[p++] = code;
+ code++;
+ }
+ code <<= 1;
+ si++;
+ }
+
+ for (p = 0; p < lastp; p++)
+ {
+ DC_matrix1[valDCchrominance[p], 0] = huffcode[p];
+ DC_matrix1[valDCchrominance[p], 1] = huffsize[p];
+ }
+
+ /*
+ * Init of the AC hufmann code for the chrominance
+ * matrix [,,0] is the code & matrix[,,1] is the number of bit needed
+ */
+
+ p = 0;
+ for (l = 0; l < 16; l++)
+ {
+ for (i = 1; i <= bitsACchrominance[l]; i++)
+ {
+ huffsize[p++] = l+1;
+ }
+ }
+ huffsize[p] = 0;
+ lastp = p;
+
+ code = 0;
+ si = huffsize[0];
+ p = 0;
+ while (huffsize[p] != 0)
+ {
+ while (huffsize[p] == si)
+ {
+ huffcode[p++] = code;
+ code++;
+ }
+ code <<= 1;
+ si++;
+ }
+
+ for (p = 0; p < lastp; p++)
+ {
+ AC_matrix1[valACchrominance[p], 0] = huffcode[p];
+ AC_matrix1[valACchrominance[p], 1] = huffsize[p];
+ }
+
+ /*
+ * init of the DC values for the luminance
+ * [,0] is the code [,1] is the number of bit
+ */
+ p = 0;
+ for (l = 0; l < 16; l++)
+ {
+ for (i = 1; i <= bitsDCluminance[l]; i++)
+ {
+ huffsize[p++] = l+1;
+ }
+ }
+ huffsize[p] = 0;
+ lastp = p;
+
+ code = 0;
+ si = huffsize[0];
+ p = 0;
+ while (huffsize[p] != 0)
+ {
+ while (huffsize[p] == si)
+ {
+ huffcode[p++] = code;
+ code++;
+ }
+ code <<= 1;
+ si++;
+ }
+
+ for (p = 0; p < lastp; p++)
+ {
+ DC_matrix0[valDCluminance[p], 0] = huffcode[p];
+ DC_matrix0[valDCluminance[p], 1] = huffsize[p];
+ }
+
+ /*
+ * Init of the AC hufmann code for luminance
+ * matrix [,,0] is the code & matrix[,,1] is the number of bit
+ */
+
+ p = 0;
+ for (l = 0; l < 16; l++)
+ {
+ for (i = 1; i <= bitsACluminance[l]; i++)
+ {
+ huffsize[p++] = l+1;
+ }
+ }
+ huffsize[p] = 0;
+ lastp = p;
+
+ code = 0;
+ si = huffsize[0];
+ p = 0;
+ while (huffsize[p] != 0)
+ {
+ while (huffsize[p] == si)
+ {
+ huffcode[p++] = code;
+ code++;
+ }
+ code <<= 1;
+ si++;
+ }
+ for (int q = 0; q < lastp; q++)
+ {
+ AC_matrix0[valACluminance[q], 0] = huffcode[q];
+ AC_matrix0[valACluminance[q], 1] = huffsize[q];
+ }
+
+ DC_matrix[0] = DC_matrix0;
+ DC_matrix[1] = DC_matrix1;
+ AC_matrix[0] = AC_matrix0;
+ AC_matrix[1] = AC_matrix1;
+ }
+
+
+ }
+}
diff --git a/debian/missing-sources/plupload/csharp/Plupload/FJCore/Decoder/JpegComponent.cs b/debian/missing-sources/plupload/csharp/Plupload/FJCore/Decoder/JpegComponent.cs
new file mode 100644
index 0000000..4d8c8e0
--- /dev/null
+++ b/debian/missing-sources/plupload/csharp/Plupload/FJCore/Decoder/JpegComponent.cs
@@ -0,0 +1,702 @@
+/// Copyright (c) 2008 Jeffrey Powers for Fluxcapacity Open Source.
+/// Under the MIT License, details: License.txt.
+
+using System;
+using System.Collections.Generic;
+using System.Text;
+using FluxJpeg.Core.IO;
+using System.Reflection.Emit;
+using System.Diagnostics;
+
+namespace FluxJpeg.Core.Decoder
+{
+
+ internal class JpegComponent
+ {
+ public byte factorH, factorV, component_id, quant_id;
+ public int width = 0, height = 0;
+ public HuffmanTable ACTable;
+ public HuffmanTable DCTable;
+
+ public int[] QuantizationTable {
+ set
+ {
+ quantizationTable = value;
+ _quant = EmitQuantize();
+ }
+ }
+ private int[] quantizationTable;
+
+ public float previousDC = 0;
+ private JpegScan parent;
+
+ // Current MCU block
+ float[,][] scanMCUs = null;
+
+ private List<float[,][]> scanData = new List<float[,][]>();
+
+ public int BlockCount { get { return scanData.Count; } }
+
+ private List<byte[,]> scanDecoded = new List<byte[,]>();
+
+ public int spectralStart, spectralEnd;
+ public int successiveLow;
+
+ public JpegComponent(JpegScan parentScan, byte id, byte factorHorizontal, byte factorVertical,
+ byte quantizationID, byte colorMode)
+ {
+ parent = parentScan;
+
+ /* Set default tables in case they're not provided. J. Powers */
+ // TODO: only gen if needed
+
+ if (colorMode == JPEGFrame.JPEG_COLOR_YCbCr)
+ {
+ if (id == 1) // Luminance
+ {
+ ACTable = new HuffmanTable(JpegHuffmanTable.StdACLuminance);
+ DCTable = new HuffmanTable(JpegHuffmanTable.StdDCLuminance);
+ }
+ else
+ {
+ ACTable = new HuffmanTable( JpegHuffmanTable.StdACChrominance);
+ DCTable = new HuffmanTable( JpegHuffmanTable.StdACLuminance);
+ }
+ }
+
+ component_id = id;
+
+ factorH = factorHorizontal;
+ factorV = factorVertical;
+
+ quant_id = quantizationID;
+ }
+
+ /// <summary>
+ /// If a restart marker is found with too little of an MCU count (i.e. our
+ /// Restart Interval is 63 and we have 61 we copy the last MCU until it's full)
+ /// </summary>
+ public void padMCU(int index, int length)
+ {
+ scanMCUs = new float[factorH, factorV][];
+
+ for(int n = 0; n < length; n++)
+ {
+ if (scanData.Count >= (index + length)) continue;
+
+ for (int i = 0; i < factorH; i++)
+ for (int j = 0; j < factorV; j++)
+ scanMCUs[i, j] = (float[])scanData[index - 1][i,j].Clone();
+
+ scanData.Add(scanMCUs);
+ }
+
+ }
+
+ /// <summary>
+ /// Reset the interval by setting the previous DC value
+ /// </summary>
+ public void resetInterval()
+ {
+ previousDC = 0;
+ }
+
+ private delegate void QuantizeDel(float[] arr);
+ private QuantizeDel _quant = null;
+
+ private QuantizeDel EmitQuantize()
+ {
+ Type[] args = { typeof(float[]) };
+
+ DynamicMethod quantizeMethod = new DynamicMethod("Quantize",
+ null, // no return type
+ args); // input array
+
+ ILGenerator il = quantizeMethod.GetILGenerator();
+
+ for (int i = 0; i < quantizationTable.Length; i++)
+ {
+ float mult = (float)quantizationTable[i];
+
+ // Sz Stack:
+ il.Emit(OpCodes.Ldarg_0); // 1 {arr}
+ il.Emit(OpCodes.Ldc_I4_S, (short)i); // 3 {arr,i}
+ il.Emit(OpCodes.Ldarg_0); // 1 {arr,i,arr}
+ il.Emit(OpCodes.Ldc_I4_S, (short)i); // 3 {arr,i,arr,i}
+ il.Emit(OpCodes.Ldelem_R4); // 1 {arr,i,arr[i]}
+ il.Emit(OpCodes.Ldc_R4, mult); // 5 {arr,i,arr[i],mult}
+ il.Emit(OpCodes.Mul); // 1 {arr,i,arr[i]*mult}
+ il.Emit(OpCodes.Stelem_R4); // 1 {}
+
+ }
+
+ il.Emit(OpCodes.Ret);
+
+ return (QuantizeDel)quantizeMethod.CreateDelegate(typeof(QuantizeDel));
+ }
+
+ /// <summary>
+ /// Run the Quantization backward method on all of the block data.
+ /// </summary>
+ public void quantizeData()
+ {
+ for (int i = 0; i < scanData.Count; i++)
+ {
+ for(int v = 0; v < factorV; v++)
+ for (int h = 0; h < factorH; h++)
+ {
+ // Dynamic IL method
+ _quant(scanData[i][h, v]);
+
+ // Old technique
+ //float[] toQuantize = scanData[i][h, v];
+ //for (int j = 0; j < 64; j++) toQuantize[j] *= quantizationTable[j];
+ }
+ }
+
+ }
+
+ public void setDCTable(JpegHuffmanTable table)
+ {
+ DCTable = new HuffmanTable(table);
+ }
+
+ public void setACTable(JpegHuffmanTable table)
+ {
+ ACTable = new HuffmanTable(table);
+ }
+
+ DCT _dct = new DCT();
+
+ /// <summary>
+ /// Run the Inverse DCT method on all of the block data
+ /// </summary>
+ public void idctData()
+ {
+ float[] unZZ = new float[64];
+ float[] toDecode = null;
+
+ for (int i = 0; i < scanData.Count; i++)
+ {
+ for (int v = 0; v < factorV; v++)
+ for (int h = 0; h < factorH; h++)
+ {
+ toDecode = scanData[i][h, v];
+ ZigZag.UnZigZag(toDecode, unZZ);
+ //FJCore.Profiling.IDCTWatch.Start();
+ scanDecoded.Add(_dct.FastIDCT(unZZ));
+ //FJCore.Profiling.IDCTWatch.Stop();
+ }
+ }
+ }
+
+ private int factorUpV { get { return parent.MaxV / factorV; } }
+ private int factorUpH { get { return parent.MaxH / factorH; } }
+
+
+ /// <summary>
+ /// Stretches components as needed to normalize the size of all components.
+ /// For example, in a 2x1 (4:2:2) sequence, the Cr and Cb channels will be
+ /// scaled vertically by a factor of 2.
+ /// </summary>
+ public void scaleByFactors( BlockUpsamplingMode mode )
+ {
+ int factorUpVertical = factorUpV,
+ factorUpHorizontal = factorUpH;
+
+ if (factorUpVertical == 1 && factorUpHorizontal == 1) return;
+
+ for (int i = 0; i < scanDecoded.Count; i++)
+ {
+ byte[,] src = scanDecoded[i];
+
+ int oldV = src.GetLength(0),
+ oldH = src.GetLength(1),
+ newV = oldV * factorUpVertical,
+ newH = oldH * factorUpHorizontal;
+
+ byte[,] dest = new byte[newV, newH];
+
+ switch (mode)
+ {
+ case BlockUpsamplingMode.BoxFilter:
+ #region Upsampling by repeating values
+ /* Perform scaling (Box filter) */
+ for (int u = 0; u < newH; u++)
+ {
+ int src_u = u / factorUpHorizontal;
+ for (int v = 0; v < newV; v++)
+ {
+ int src_v = v / factorUpVertical;
+ dest[v, u] = src[src_v, src_u];
+ }
+ }
+ #endregion
+ break;
+
+ case BlockUpsamplingMode.Interpolate:
+ #region Upsampling by interpolation
+
+ for (int u = 0; u < newH; u++)
+ {
+ for (int v = 0; v < newV; v++)
+ {
+ int val = 0;
+
+ for (int x = 0; x < factorUpHorizontal; x++)
+ {
+ int src_u = (u + x) / factorUpHorizontal;
+ if (src_u >= oldH) src_u = oldH - 1;
+
+ for (int y = 0; y < factorUpVertical; y++)
+ {
+ int src_v = (v + y) / factorUpVertical;
+
+ if (src_v >= oldV) src_v = oldV - 1;
+
+ val += src[src_v, src_u];
+ }
+ }
+
+ dest[v, u] = (byte)(val / (factorUpHorizontal * factorUpVertical));
+ }
+ }
+
+ #endregion
+ break;
+
+ default:
+ throw new ArgumentException("Upsampling mode not supported.");
+ }
+
+ scanDecoded[i] = dest;
+ }
+
+ }
+
+
+ public void writeBlock(byte[][,] raster, byte[,] data,
+ int compIndex, int x, int y)
+ {
+ int w = raster[0].GetLength(0),
+ h = raster[0].GetLength(1);
+
+ byte[,] comp = raster[compIndex];
+
+ // Blocks may spill over the frame so we bound by the frame size
+ int yMax = data.GetLength(0); if ((y + yMax) > h) yMax = h - y;
+ int xMax = data.GetLength(1); if ((x + xMax) > w) xMax = w - x;
+
+ for (int yIndex = 0; yIndex < yMax; yIndex++)
+ {
+ for (int xIndex = 0; xIndex < xMax; xIndex++)
+ {
+ comp[x + xIndex, y + yIndex] = data[yIndex, xIndex];
+ }
+ }
+ }
+
+ public void writeDataScaled(byte[][,] raster, int componentIndex, BlockUpsamplingMode mode)
+ {
+ int x = 0, y = 0, lastblockheight = 0, incrementblock = 0;
+
+ int blockIdx = 0;
+
+ int w = raster[0].GetLength(0),
+ h = raster[0].GetLength(1);
+
+ // Keep looping through all of the blocks until there are no more.
+ while (blockIdx < scanDecoded.Count)
+ {
+ int blockwidth = 0;
+ int blockheight = 0;
+
+ if (x >= w) { x = 0; y += incrementblock; }
+
+ // Loop through the horizontal component blocks of the MCU first
+ // then for each horizontal line write out all of the vertical
+ // components
+ for (int factorVIndex = 0; factorVIndex < factorV; factorVIndex++)
+ {
+ blockwidth = 0;
+
+ for (int factorHIndex = 0; factorHIndex < factorH; factorHIndex++)
+ {
+ // Captures the width of this block so we can increment the X coordinate
+ byte[,] blockdata = scanDecoded[blockIdx++];
+
+ // Writes the data at the specific X and Y coordinate of this component
+ writeBlockScaled(raster, blockdata, componentIndex, x, y, mode);
+
+ blockwidth += blockdata.GetLength(1) * factorUpH;
+ x += blockdata.GetLength(1) * factorUpH;
+ blockheight = blockdata.GetLength(0) * factorUpV;
+ }
+
+ y += blockheight;
+ x -= blockwidth;
+ lastblockheight += blockheight;
+ }
+ y -= lastblockheight;
+ incrementblock = lastblockheight;
+ lastblockheight = 0;
+ x += blockwidth;
+ }
+ }
+
+ private void writeBlockScaled(byte[][,] raster, byte[,] blockdata, int compIndex, int x, int y, BlockUpsamplingMode mode)
+ {
+ int w = raster[0].GetLength(0),
+ h = raster[0].GetLength(1);
+
+ int factorUpVertical = factorUpV,
+ factorUpHorizontal = factorUpH;
+
+ int oldV = blockdata.GetLength(0),
+ oldH = blockdata.GetLength(1),
+ newV = oldV * factorUpVertical,
+ newH = oldH * factorUpHorizontal;
+
+ byte[,] comp = raster[compIndex];
+
+ // Blocks may spill over the frame so we bound by the frame size
+ int yMax = newV; if ((y + yMax) > h) yMax = h - y;
+ int xMax = newH; if ((x + xMax) > w) xMax = w - x;
+
+ switch (mode)
+ {
+ case BlockUpsamplingMode.BoxFilter:
+
+ #region Upsampling by repeating values
+
+ // Special case 1: No scale-up
+ if (factorUpVertical == 1 && factorUpHorizontal == 1)
+ {
+ for (int u = 0; u < xMax; u++)
+ for (int v = 0; v < yMax; v++)
+ comp[u + x, y + v] = blockdata[v, u];
+ }
+ // Special case 2: Perform scale-up 4 pixels at a time
+ else if (factorUpHorizontal == 2 &&
+ factorUpVertical == 2 &&
+ xMax == newH && yMax == newV)
+ {
+ for (int src_u = 0; src_u < oldH; src_u++)
+ {
+ int bx = src_u * 2 + x;
+
+ for ( int src_v = 0; src_v < oldV; src_v++)
+ {
+ byte val = blockdata[src_v, src_u];
+ int by = src_v * 2 + y;
+
+ comp[bx, by] = val;
+ comp[bx, by + 1] = val;
+ comp[bx + 1, by] = val;
+ comp[bx + 1, by + 1] = val;
+ }
+ }
+ }
+ else
+ {
+ /* Perform scaling (Box filter) */
+ for (int u = 0; u < xMax; u++)
+ {
+ int src_u = u / factorUpHorizontal;
+ for (int v = 0; v < yMax; v++)
+ {
+ int src_v = v / factorUpVertical;
+ comp[u + x, y + v] = blockdata[src_v, src_u];
+ }
+ }
+ }
+
+
+ #endregion
+ break;
+
+ // JRP 4/7/08 -- This mode is disabled temporarily as it needs to be fixed after
+ // recent performance tweaks.
+ // It can produce slightly better (less blocky) decodings.
+
+ //case BlockUpsamplingMode.Interpolate:
+ // #region Upsampling by interpolation
+ // for (int u = 0; u < newH; u++)
+ // {
+ // for (int v = 0; v < newV; v++)
+ // {
+ // int val = 0;
+ // for (int x = 0; x < factorUpHorizontal; x++)
+ // {
+ // int src_u = (u + x) / factorUpHorizontal;
+ // if (src_u >= oldH) src_u = oldH - 1;
+ // for (int y = 0; y < factorUpVertical; y++)
+ // {
+ // int src_v = (v + y) / factorUpVertical;
+ // if (src_v >= oldV) src_v = oldV - 1;
+ // val += src[src_v, src_u];
+ // }
+ // }
+ // dest[v, u] = (byte)(val / (factorUpHorizontal * factorUpVertical));
+ // }
+ // }
+ // #endregion
+ // break;
+
+ default:
+ throw new ArgumentException("Upsampling mode not supported.");
+ }
+
+ }
+
+
+
+
+ internal delegate void DecodeFunction(JPEGBinaryReader jpegReader, float[] zigzagMCU);
+ public DecodeFunction Decode;
+
+ public void DecodeBaseline(JPEGBinaryReader stream, float[] dest)
+ {
+ float dc = decode_dc_coefficient(stream);
+ decode_ac_coefficients(stream, dest);
+ dest[0] = dc;
+ }
+
+ public void DecodeDCFirst(JPEGBinaryReader stream, float[] dest)
+ {
+ float[] datablock = new float[64];
+ int s = DCTable.Decode(stream);
+ int r = stream.ReadBits(s);
+ s = HuffmanTable.Extend(r, s);
+ s = (int)previousDC + s;
+ previousDC = s;
+
+ dest[0] = s << successiveLow;
+ }
+
+ public void DecodeACFirst(JPEGBinaryReader stream, float[] zz)
+ {
+ if (stream.eob_run > 0)
+ {
+ stream.eob_run--;
+ return;
+ }
+
+ for (int k = spectralStart; k <= spectralEnd; k++)
+ {
+ int s = ACTable.Decode(stream);
+ int r = s >> 4;
+ s &= 15;
+
+
+ if (s != 0)
+ {
+ k += r;
+
+ r = (int)stream.ReadBits(s);
+ s = (int)HuffmanTable.Extend(r, s);
+ zz[k] = s << successiveLow;
+ }
+ else
+ {
+ if (r != 15)
+ {
+ stream.eob_run = 1 << r;
+
+ if (r != 0)
+ stream.eob_run += stream.ReadBits(r);
+
+ stream.eob_run--;
+
+ break;
+ }
+
+ k += 15;
+ }
+ }
+ }
+
+ public void DecodeDCRefine(JPEGBinaryReader stream, float[] dest)
+ {
+ if (stream.ReadBits(1) == 1)
+ {
+ dest[0] = (int)dest[0] | (1 << successiveLow);
+ }
+ }
+
+ public void DecodeACRefine(JPEGBinaryReader stream, float[] dest)
+ {
+ int p1 = 1 << successiveLow;
+ int m1 = (-1) << successiveLow;
+
+ int k = spectralStart;
+
+ if (stream.eob_run == 0)
+ for (; k <= spectralEnd; k++)
+ {
+ #region Decode and check S
+
+ int s = ACTable.Decode(stream);
+ int r = s >> 4;
+ s &= 15;
+
+ if (s != 0)
+ {
+ if (s != 1)
+ throw new Exception("Decode Error");
+
+ if (stream.ReadBits(1) == 1)
+ s = p1;
+ else
+ s = m1;
+ }
+ else
+ {
+ if (r != 15)
+ {
+ stream.eob_run = 1 << r;
+
+ if (r > 0)
+ stream.eob_run += stream.ReadBits(r);
+ break;
+ }
+
+ } // if (s != 0)
+
+ #endregion
+
+ // Apply the update
+ do
+ {
+ if (dest[k] != 0)
+ {
+ if (stream.ReadBits(1) == 1)
+ {
+ if (((int)dest[k] & p1) == 0)
+ {
+ if (dest[k] >= 0)
+ dest[k] += p1;
+ else
+ dest[k] += m1;
+ }
+ }
+ }
+ else
+ {
+ if (--r < 0)
+ break;
+ }
+
+ k++;
+
+ } while (k <= spectralEnd);
+
+ if( (s != 0) && k < 64)
+ {
+ dest[k] = s;
+ }
+ } // for k = start ... end
+
+
+ if (stream.eob_run > 0)
+ {
+ for (; k <= spectralEnd; k++)
+ {
+ if (dest[k] != 0)
+ {
+ if (stream.ReadBits(1) == 1)
+ {
+ if (((int)dest[k] & p1) == 0)
+ {
+ if (dest[k] >= 0)
+ dest[k] += p1;
+ else
+ dest[k] += m1;
+ }
+ }
+ }
+ }
+
+ stream.eob_run--;
+ }
+ }
+
+
+ public void SetBlock(int idx)
+ {
+ if (scanData.Count < idx)
+ throw new Exception("Invalid block ID.");
+
+ // expand the data list
+ if (scanData.Count == idx)
+ {
+ scanMCUs = new float[factorH, factorV][];
+ for (int i = 0; i < factorH; i++)
+ for (int j = 0; j < factorV; j++)
+ scanMCUs[i, j] = new float[64];
+
+ scanData.Add(scanMCUs);
+ }
+ else // reference an existing block
+ {
+ scanMCUs = scanData[idx];
+ }
+ }
+
+ public void DecodeMCU(JPEGBinaryReader jpegReader, int i, int j)
+ {
+ Decode(jpegReader, scanMCUs[i,j]);
+ }
+
+ /// <summary>
+ /// Generated from text on F-22, F.2.2.1 - Huffman decoding of DC
+ /// coefficients on ISO DIS 10918-1. Requirements and Guidelines.
+ /// </summary>
+ /// <param name="JPEGStream">Stream that contains huffman bits</param>
+ /// <returns>DC coefficient</returns>
+ public float decode_dc_coefficient(JPEGBinaryReader JPEGStream)
+ {
+ int t = DCTable.Decode(JPEGStream);
+ float diff = JPEGStream.ReadBits(t);
+ diff = HuffmanTable.Extend((int)diff, t);
+ diff = (previousDC + diff);
+ previousDC = diff;
+ return diff;
+ }
+
+
+ /// <summary>
+ /// Generated from text on F-23, F.13 - Huffman decoded of AC coefficients
+ /// on ISO DIS 10918-1. Requirements and Guidelines.
+ /// </summary>
+ internal void decode_ac_coefficients(JPEGBinaryReader JPEGStream, float[] zz)
+ {
+ for (int k = 1; k < 64; k++)
+ {
+ int s = ACTable.Decode(JPEGStream);
+ int r = s >> 4;
+ s &= 15;
+
+
+ if (s != 0)
+ {
+ k += r;
+
+ r = (int)JPEGStream.ReadBits(s);
+ s = (int)HuffmanTable.Extend(r, s);
+ zz[k] = s;
+ }
+ else
+ {
+ if (r != 15)
+ {
+ //throw new JPEGMarkerFoundException();
+ return;
+ }
+ k += 15;
+ }
+ }
+ }
+ }
+
+}
diff --git a/debian/missing-sources/plupload/csharp/Plupload/FJCore/Decoder/JpegDecoder.cs b/debian/missing-sources/plupload/csharp/Plupload/FJCore/Decoder/JpegDecoder.cs
new file mode 100644
index 0000000..6e654db
--- /dev/null
+++ b/debian/missing-sources/plupload/csharp/Plupload/FJCore/Decoder/JpegDecoder.cs
@@ -0,0 +1,614 @@
+/// Copyright (c) 2008 Jeffrey Powers for Fluxcapacity Open Source.
+/// Under the MIT License, details: License.txt.
+
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.IO;
+using FluxJpeg.Core.IO;
+using System.Diagnostics;
+
+namespace FluxJpeg.Core.Decoder
+{
+ public enum BlockUpsamplingMode {
+ /// <summary> The simplest upsampling mode. Produces sharper edges. </summary>
+ BoxFilter,
+ /// <summary> Smoother upsampling. May improve color spread for some images. </summary>
+ Interpolate
+ }
+
+ public class JpegDecodeProgressChangedArgs : EventArgs
+ {
+ public bool SizeReady;
+ public int Width;
+ public int Height;
+
+ public bool Abort;
+ public long ReadPosition; // 0 to input stream length
+ public double DecodeProgress; // 0 to 1.0
+ }
+
+ public class JpegDecoder
+ {
+ public static long ProgressUpdateByteInterval = 100;
+
+ public event EventHandler<JpegDecodeProgressChangedArgs> DecodeProgressChanged;
+ private JpegDecodeProgressChangedArgs DecodeProgress = new JpegDecodeProgressChangedArgs();
+
+ public BlockUpsamplingMode BlockUpsamplingMode { get; set; }
+
+ byte majorVersion, minorVersion;
+ private enum UnitType { None = 0, Inches = 1, Centimeters = 2 };
+ UnitType Units;
+ ushort XDensity, YDensity;
+ byte Xthumbnail, Ythumbnail;
+ byte[] thumbnail;
+ Image image;
+ int width;
+ int height;
+
+ bool progressive = false;
+
+ byte marker;
+
+ /// <summary>
+ /// This decoder expects JFIF 1.02 encoding.
+ /// </summary>
+ internal const byte MAJOR_VERSION = (byte)1;
+ internal const byte MINOR_VERSION = (byte)2;
+
+ /// <summary>
+ /// The length of the JFIF field not including thumbnail data.
+ /// </summary>
+ internal static short JFIF_FIXED_LENGTH = 16;
+
+ /// <summary>
+ /// The length of the JFIF extension field not including extension data.
+ /// </summary>
+ internal static short JFXX_FIXED_LENGTH = 8;
+
+ private JPEGBinaryReader jpegReader;
+
+ List<JPEGFrame> jpegFrames = new List<JPEGFrame>();
+
+ JpegHuffmanTable[] dcTables = new JpegHuffmanTable[4];
+ JpegHuffmanTable[] acTables = new JpegHuffmanTable[4];
+ JpegQuantizationTable[] qTables = new JpegQuantizationTable[4];
+
+ public JpegDecoder(Stream input)
+ {
+ jpegReader = new JPEGBinaryReader(input);
+
+ if (jpegReader.GetNextMarker() != JPEGMarker.SOI)
+ throw new Exception("Failed to find SOI marker.");
+ }
+
+ /// <summary>
+ /// Tries to parse the JFIF APP0 header
+ /// See http://en.wikipedia.org/wiki/JFIF
+ /// </summary>
+ private bool TryParseJFIF(byte[] data)
+ {
+ IO.BinaryReader reader = new IO.BinaryReader(new MemoryStream(data));
+
+ int length = data.Length + 2; // Data & length
+
+ if (!(length >= JFIF_FIXED_LENGTH))
+ return false; // Header's too small.
+
+ byte[] identifier = new byte[5];
+ reader.Read(identifier, 0, identifier.Length);
+ if (identifier[0] != JPEGMarker.JFIF_J
+ || identifier[1] != JPEGMarker.JFIF_F
+ || identifier[2] != JPEGMarker.JFIF_I
+ || identifier[3] != JPEGMarker.JFIF_F
+ || identifier[4] != JPEGMarker.X00)
+ return false; // Incorrect bytes
+
+ majorVersion = reader.ReadByte();
+ minorVersion = reader.ReadByte();
+ if (majorVersion != MAJOR_VERSION
+ || (majorVersion == MAJOR_VERSION
+ && minorVersion > MINOR_VERSION)) // changed from <
+ return false; // Unsupported version
+
+ Units = (UnitType)reader.ReadByte();
+ if (Units != UnitType.None &&
+ Units != UnitType.Inches &&
+ Units != UnitType.Centimeters)
+ return false; // Invalid units
+
+ XDensity = reader.ReadShort();
+ YDensity = reader.ReadShort();
+ Xthumbnail = reader.ReadByte();
+ Ythumbnail = reader.ReadByte();
+
+ // 3 * for RGB data
+ int thumbnailLength = 3 * Xthumbnail * Ythumbnail;
+ if (length > JFIF_FIXED_LENGTH
+ && thumbnailLength != length - JFIF_FIXED_LENGTH)
+ return false; // Thumbnail fields invalid
+
+ if (thumbnailLength > 0)
+ {
+ thumbnail = new byte[thumbnailLength];
+ if (reader.Read(thumbnail, 0, thumbnailLength) != thumbnailLength)
+ return false; // Thumbnail data was missing!
+
+ }
+
+ return true;
+ }
+
+ public DecodedJpeg Decode()
+ {
+ // The frames in this jpeg are loaded into a list. There is
+ // usually just one frame except in heirarchial progression where
+ // there are multiple frames.
+ JPEGFrame frame = null;
+
+ // The restart interval defines how many MCU's we should have
+ // between the 8-modulo restart marker. The restart markers allow
+ // us to tell whether or not our decoding process is working
+ // correctly, also if there is corruption in the image we can
+ // recover with these restart intervals. (See RSTm DRI).
+ int resetInterval = 0;
+
+ bool haveMarker = false;
+ bool foundJFIF = false;
+
+ List<JpegHeader> headers = new List<JpegHeader>();
+
+ // Loop through until there are no more markers to read in, at
+ // that point everything is loaded into the jpegFrames array and
+ // can be processed.
+ while (true)
+ {
+ if (DecodeProgress.Abort) return null;
+
+ #region Switch over marker types
+ switch (marker)
+ {
+ case JPEGMarker.APP0:
+ // APP1 is used for EXIF data
+ case JPEGMarker.APP1:
+ // Seldomly, APP2 gets used for extended EXIF, too
+ case JPEGMarker.APP2:
+ case JPEGMarker.APP3:
+ case JPEGMarker.APP4:
+ case JPEGMarker.APP5:
+ case JPEGMarker.APP6:
+ case JPEGMarker.APP7:
+ case JPEGMarker.APP8:
+ case JPEGMarker.APP9:
+ case JPEGMarker.APP10:
+ case JPEGMarker.APP11:
+ case JPEGMarker.APP12:
+ case JPEGMarker.APP13:
+ case JPEGMarker.APP14:
+ case JPEGMarker.APP15:
+ // COM: Comment
+ case JPEGMarker.COM:
+
+ // Debug.WriteLine(string.Format("Extracting Header, Type={0:X}", marker));
+
+ JpegHeader header = ExtractHeader();
+
+ #region Check explicitly for Exif Data
+
+ if (header.Marker == JPEGMarker.APP1 && header.Data.Length >= 6)
+ {
+ byte[] d = header.Data;
+
+ if( d[0] == 'E' &&
+ d[1] == 'x' &&
+ d[2] == 'i' &&
+ d[3] == 'f' &&
+ d[4] == 0 &&
+ d[5] == 0)
+ {
+ // Exif. Do something?
+ }
+ }
+
+ #endregion
+
+ #region Check for Adobe header
+
+ if (header.Data.Length >= 5 && header.Marker == JPEGMarker.APP14)
+ {
+ string asText = UTF8Encoding.UTF8.GetString(header.Data, 0, 5);
+ if (asText == "Adobe") {
+ // ADOBE HEADER. Do anything?
+ }
+ }
+
+ #endregion
+
+ headers.Add(header);
+
+ if (!foundJFIF && marker == JPEGMarker.APP0)
+ {
+ foundJFIF = TryParseJFIF(header.Data);
+
+ if (foundJFIF) // Found JFIF... do JFIF extension follow?
+ {
+ header.IsJFIF = true;
+ marker = jpegReader.GetNextMarker();
+
+ // Yes, they do.
+ if (marker == JPEGMarker.APP0)
+ {
+ header = ExtractHeader();
+ headers.Add(header);
+ }
+ else // No. Delay processing this one.
+ haveMarker = true;
+ }
+ }
+
+ break;
+
+ case JPEGMarker.SOF0:
+ case JPEGMarker.SOF2:
+
+ // SOFn Start of Frame Marker, Baseline DCT - This is the start
+ // of the frame header that defines certain variables that will
+ // be carried out through the rest of the encoding. Multiple
+ // frames are used in a hierarchical system, however most JPEG's
+ // only contain a single frame.
+
+ // Progressive or baseline?
+ progressive = marker == JPEGMarker.SOF2;
+
+ jpegFrames.Add(new JPEGFrame());
+ frame = (JPEGFrame)jpegFrames[jpegFrames.Count - 1];
+ frame.ProgressUpdateMethod = new Action<long>(UpdateStreamProgress);
+
+ // Skip the frame length.
+ jpegReader.ReadShort();
+ // Bits percision, either 8 or 12.
+ frame.setPrecision(jpegReader.ReadByte());
+ // Scan lines (height)
+ frame.ScanLines = jpegReader.ReadShort();
+ // Scan samples per line (width)
+ frame.SamplesPerLine = jpegReader.ReadShort();
+ // Number of Color Components (channels).
+ frame.ComponentCount = jpegReader.ReadByte();
+
+ DecodeProgress.Height = frame.Height;
+ DecodeProgress.Width = frame.Width;
+ DecodeProgress.SizeReady = true;
+
+ if(DecodeProgressChanged != null)
+ {
+ DecodeProgressChanged(this, DecodeProgress);
+ if (DecodeProgress.Abort) return null;
+ }
+
+ // Add all of the necessary components to the frame.
+ for (int i = 0; i < frame.ComponentCount; i++)
+ {
+ byte compId = jpegReader.ReadByte();
+ byte sampleFactors = jpegReader.ReadByte();
+ byte qTableId = jpegReader.ReadByte();
+
+ byte sampleHFactor = (byte)(sampleFactors >> 4);
+ byte sampleVFactor = (byte)(sampleFactors & 0x0f);
+
+ frame.AddComponent(compId, sampleHFactor, sampleVFactor, qTableId);
+ }
+ break;
+
+ case JPEGMarker.DHT:
+
+ // DHT non-SOF Marker - Huffman Table is required for decoding
+ // the JPEG stream, when we receive a marker we load in first
+ // the table length (16 bits), the table class (4 bits), table
+ // identifier (4 bits), then we load in 16 bytes and each byte
+ // represents the count of bytes to load in for each of the 16
+ // bytes. We load this into an array to use later and move on 4
+ // huffman tables can only be used in an image.
+ int huffmanLength = (jpegReader.ReadShort() - 2);
+
+ // Keep looping until we are out of length.
+ int index = huffmanLength;
+
+ // Multiple tables may be defined within a DHT marker. This
+ // will keep reading until there are no tables left, most
+ // of the time there are just one tables.
+ while (index > 0)
+ {
+ // Read the identifier information and class
+ // information about the Huffman table, then read the
+ // 16 byte codelength in and read in the Huffman values
+ // and put it into table info.
+ byte huffmanInfo = jpegReader.ReadByte();
+ byte tableClass = (byte)(huffmanInfo >> 4);
+ byte huffmanIndex = (byte)(huffmanInfo & 0x0f);
+ short[] codeLength = new short[16];
+
+ for (int i = 0; i < codeLength.Length; i++)
+ codeLength[i] = jpegReader.ReadByte();
+
+ int huffmanValueLen = 0;
+ for (int i = 0; i < 16; i++)
+ huffmanValueLen += codeLength[i];
+ index -= (huffmanValueLen + 17);
+
+ short[] huffmanVal = new short[huffmanValueLen];
+ for (int i = 0; i < huffmanVal.Length; i++)
+ {
+ huffmanVal[i] = jpegReader.ReadByte();
+ }
+ // Assign DC Huffman Table.
+ if (tableClass == HuffmanTable.JPEG_DC_TABLE)
+ dcTables[(int)huffmanIndex] = new JpegHuffmanTable(codeLength, huffmanVal);
+
+ // Assign AC Huffman Table.
+ else if (tableClass == HuffmanTable.JPEG_AC_TABLE)
+ acTables[(int)huffmanIndex] = new JpegHuffmanTable(codeLength, huffmanVal);
+ }
+ break;
+
+ case JPEGMarker.DQT:
+
+ // DQT non-SOF Marker - This defines the quantization
+ // coeffecients, this allows us to figure out the quality of
+ // compression and unencode the data. The data is loaded and
+ // then stored in to an array.
+ short quantizationLength = (short)(jpegReader.ReadShort() - 2);
+ for (int j = 0; j < quantizationLength / 65; j++)
+ {
+ byte quantSpecs = jpegReader.ReadByte();
+ int[] quantData = new int[64];
+ if ((byte)(quantSpecs >> 4) == 0)
+ // Precision 8 bit.
+ {
+ for (int i = 0; i < 64; i++)
+ quantData[i] = jpegReader.ReadByte();
+
+ }
+ else if ((byte)(quantSpecs >> 4) == 1)
+ // Precision 16 bit.
+ {
+ for (int i = 0; i < 64; i++)
+ quantData[i] = jpegReader.ReadShort();
+ }
+ qTables[(int)(quantSpecs & 0x0f)] = new JpegQuantizationTable(quantData);
+ }
+ break;
+
+ case JPEGMarker.SOS:
+
+ Debug.WriteLine("Start of Scan (SOS)");
+
+
+ // SOS non-SOF Marker - Start Of Scan Marker, this is where the
+ // actual data is stored in a interlaced or non-interlaced with
+ // from 1-4 components of color data, if three components most
+ // likely a YCrCb model, this is a fairly complex process.
+
+ // Read in the scan length.
+ ushort scanLen = jpegReader.ReadShort();
+ // Number of components in the scan.
+ byte numberOfComponents = jpegReader.ReadByte();
+ byte[] componentSelector = new byte[numberOfComponents];
+
+ for (int i = 0; i < numberOfComponents; i++)
+ {
+ // Component ID, packed byte containing the Id for the
+ // AC table and DC table.
+ byte componentID = jpegReader.ReadByte();
+ byte tableInfo = jpegReader.ReadByte();
+
+ int DC = (tableInfo >> 4) & 0x0f;
+ int AC = (tableInfo) & 0x0f;
+
+ frame.setHuffmanTables(componentID,
+ acTables[(byte)AC],
+ dcTables[(byte)DC]);
+
+
+ componentSelector[i] = componentID;
+ }
+
+ byte startSpectralSelection = jpegReader.ReadByte();
+ byte endSpectralSelection = jpegReader.ReadByte();
+ byte successiveApproximation = jpegReader.ReadByte();
+
+ #region Baseline JPEG Scan Decoding
+
+ if (!progressive)
+ {
+ frame.DecodeScanBaseline(numberOfComponents, componentSelector, resetInterval, jpegReader, ref marker);
+ haveMarker = true; // use resultant marker for the next switch(..)
+ }
+
+ #endregion
+
+ #region Progressive JPEG Scan Decoding
+
+ if (progressive)
+ {
+ frame.DecodeScanProgressive(
+ successiveApproximation, startSpectralSelection, endSpectralSelection,
+ numberOfComponents, componentSelector, resetInterval, jpegReader, ref marker);
+
+ haveMarker = true; // use resultant marker for the next switch(..)
+ }
+
+ #endregion
+
+ break;
+
+
+ case JPEGMarker.DRI:
+ jpegReader.BaseStream.Seek(2, System.IO.SeekOrigin.Current);
+ resetInterval = jpegReader.ReadShort();
+ break;
+
+ /// Defines the number of lines. (Not usually present)
+ case JPEGMarker.DNL:
+
+ frame.ScanLines = jpegReader.ReadShort();
+ break;
+
+ /// End of Image. Finish the decode.
+ case JPEGMarker.EOI:
+
+ if (jpegFrames.Count == 0)
+ {
+ throw new NotSupportedException("No JPEG frames could be located.");
+ }
+ else if (jpegFrames.Count == 1)
+ {
+ // Only one frame, JPEG Non-Heirarchial Frame.
+ byte[][,] raster = Image.CreateRaster(frame.Width, frame.Height, frame.ComponentCount);
+
+ IList<JpegComponent> components = frame.Scan.Components;
+
+ int totalSteps = components.Count * 3; // Three steps per loop
+ int stepsFinished = 0;
+
+ for(int i = 0; i < components.Count; i++)
+ {
+ JpegComponent comp = components[i];
+
+ comp.QuantizationTable = qTables[comp.quant_id].Table;
+
+ // 1. Quantize
+ comp.quantizeData();
+ UpdateProgress(++stepsFinished, totalSteps);
+
+ // 2. Run iDCT (expensive)
+ comp.idctData();
+ UpdateProgress(++stepsFinished, totalSteps);
+
+ // 3. Scale the image and write the data to the raster.
+ comp.writeDataScaled(raster, i, BlockUpsamplingMode);
+
+ UpdateProgress(++stepsFinished, totalSteps);
+
+ // Ensure garbage collection.
+ comp = null; GC.Collect();
+ }
+
+ // Grayscale Color Image (1 Component).
+ if (frame.ComponentCount == 1)
+ {
+ ColorModel cm = new ColorModel() { colorspace = ColorSpace.Gray, Opaque = true };
+ image = new Image(cm, raster);
+ }
+ // YCbCr Color Image (3 Components).
+ else if (frame.ComponentCount == 3)
+ {
+ ColorModel cm = new ColorModel() { colorspace = ColorSpace.YCbCr, Opaque = true };
+ image = new Image(cm, raster);
+ }
+ // Possibly CMYK or RGBA ?
+ else
+ {
+ throw new NotSupportedException("Unsupported Color Mode: 4 Component Color Mode found.");
+ }
+
+ // If needed, convert centimeters to inches.
+ Func<double, double> conv = x =>
+ Units == UnitType.Inches ? x : x / 2.54;
+
+ image.DensityX = conv(XDensity);
+ image.DensityY = conv(YDensity);
+
+ height = frame.Height;
+ width = frame.Width;
+ }
+ else
+ {
+ // JPEG Heirarchial Frame
+ throw new NotSupportedException("Unsupported Codec Type: Hierarchial JPEG");
+ }
+ break;
+
+ // Only SOF0 (baseline) and SOF2 (progressive) are supported by FJCore
+ case JPEGMarker.SOF1:
+ case JPEGMarker.SOF3:
+ case JPEGMarker.SOF5:
+ case JPEGMarker.SOF6:
+ case JPEGMarker.SOF7:
+ case JPEGMarker.SOF9:
+ case JPEGMarker.SOF10:
+ case JPEGMarker.SOF11:
+ case JPEGMarker.SOF13:
+ case JPEGMarker.SOF14:
+ case JPEGMarker.SOF15:
+ throw new NotSupportedException("Unsupported codec type.");
+
+ default: break; // ignore
+
+ }
+
+ #endregion switch over markers
+
+ if (haveMarker) haveMarker = false;
+ else
+ {
+ try
+ {
+ marker = jpegReader.GetNextMarker();
+ }
+ catch (System.IO.EndOfStreamException)
+ {
+ break; /* done reading the file */
+ }
+ }
+ }
+
+ DecodedJpeg result = new DecodedJpeg(image, headers);
+
+ return result;
+ }
+
+ private JpegHeader ExtractHeader()
+ {
+ #region Extract the header
+
+ int length = jpegReader.ReadShort() - 2;
+ byte[] data = new byte[length];
+ jpegReader.Read(data, 0, length);
+
+ #endregion
+
+ JpegHeader header = new JpegHeader()
+ {
+ Marker = marker,
+ Data = data
+ };
+ return header;
+ }
+
+ #region Decode Progress Monitoring
+
+ private void UpdateStreamProgress(long StreamPosition)
+ {
+ if (DecodeProgressChanged != null)
+ {
+ DecodeProgress.ReadPosition = StreamPosition;
+ DecodeProgressChanged(this, DecodeProgress);
+ };
+ }
+
+ private void UpdateProgress(int stepsFinished, int stepsTotal)
+ {
+ if (DecodeProgressChanged != null)
+ {
+ DecodeProgress.DecodeProgress = (double)stepsFinished / stepsTotal;
+ DecodeProgressChanged(this, DecodeProgress);
+ };
+ }
+
+ #endregion
+
+
+ }
+}
diff --git a/debian/missing-sources/plupload/csharp/Plupload/FJCore/Decoder/JpegFrame.cs b/debian/missing-sources/plupload/csharp/Plupload/FJCore/Decoder/JpegFrame.cs
new file mode 100644
index 0000000..02f8027
--- /dev/null
+++ b/debian/missing-sources/plupload/csharp/Plupload/FJCore/Decoder/JpegFrame.cs
@@ -0,0 +1,283 @@
+/// Copyright (c) 2008 Jeffrey Powers for Fluxcapacity Open Source.
+/// Under the MIT License, details: License.txt.
+
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using FluxJpeg.Core.IO;
+
+namespace FluxJpeg.Core.Decoder
+{
+ internal class JPEGFrame
+ {
+ public static byte JPEG_COLOR_GRAY = 1;
+ public static byte JPEG_COLOR_RGB = 2;
+ public static byte JPEG_COLOR_YCbCr = 3;
+ public static byte JPEG_COLOR_CMYK = 4;
+
+ public byte precision = 8;
+ public byte colorMode = JPEGFrame.JPEG_COLOR_YCbCr;
+
+ public ushort Width { get; private set; }
+ public ushort Height { get; private set; }
+
+ public JpegScan Scan = new JpegScan();
+
+ public Action<long> ProgressUpdateMethod = null;
+
+ public void AddComponent(byte componentID, byte sampleHFactor, byte sampleVFactor,
+ byte quantizationTableID)
+ {
+ Scan.AddComponent(componentID, sampleHFactor, sampleVFactor, quantizationTableID, colorMode);
+ }
+
+ public void setPrecision(byte data) { precision = data; }
+
+ public ushort ScanLines { set { Height = value; } }
+ public ushort SamplesPerLine { set { Width = value; } }
+
+ public byte ColorMode { get {
+ return ComponentCount == 1 ?
+ JPEGFrame.JPEG_COLOR_GRAY :
+ JPEGFrame.JPEG_COLOR_YCbCr;
+
+ }
+ }
+
+ public byte ComponentCount { get ; set; }
+
+ public void setHuffmanTables(byte componentID, JpegHuffmanTable ACTable, JpegHuffmanTable DCTable)
+ {
+ JpegComponent comp = Scan.GetComponentById(componentID);
+
+ if(DCTable != null) comp.setDCTable(DCTable);
+ if(ACTable != null) comp.setACTable(ACTable);
+ }
+
+ public void DecodeScanBaseline(byte numberOfComponents, byte[] componentSelector, int resetInterval, JPEGBinaryReader jpegReader, ref byte marker)
+ {
+ // Set the decode function for all the components
+ for (int compIndex = 0; compIndex < numberOfComponents; compIndex++)
+ {
+ JpegComponent comp = Scan.GetComponentById(componentSelector[compIndex]);
+ comp.Decode = comp.DecodeBaseline;
+ }
+
+ DecodeScan(numberOfComponents, componentSelector, resetInterval, jpegReader, ref marker);
+ }
+
+ private int mcus_per_row(JpegComponent c)
+ {
+ return (((( Width * c.factorH ) + ( Scan.MaxH - 1)) / Scan.MaxH) + 7) / 8;
+ }
+
+ private void DecodeScan(byte numberOfComponents, byte[] componentSelector, int resetInterval, JPEGBinaryReader jpegReader, ref byte marker)
+ {
+ //TODO: not necessary
+ jpegReader.eob_run = 0;
+
+ int mcuIndex = 0;
+ int mcuTotalIndex = 0;
+
+ // This loops through until a MarkerTagFound exception is
+ // found, if the marker tag is a RST (Restart Marker) it
+ // simply skips it and moves on this system does not handle
+ // corrupt data streams very well, it could be improved by
+ // handling misplaced restart markers.
+
+ int h = 0, v = 0;
+ int x = 0;
+
+ long lastPosition = jpegReader.BaseStream.Position;
+
+ //TODO: replace this with a loop which knows how much data to expect
+ while (true)
+ {
+ #region Inform caller of decode progress
+
+ if (ProgressUpdateMethod != null)
+ {
+ if (jpegReader.BaseStream.Position >= lastPosition + JpegDecoder.ProgressUpdateByteInterval)
+ {
+ lastPosition = jpegReader.BaseStream.Position;
+ ProgressUpdateMethod(lastPosition);
+ }
+ }
+
+ #endregion
+
+ try
+ {
+ // Loop though capturing MCU, instruct each
+ // component to read in its necessary count, for
+ // scaling factors the components automatically
+ // read in how much they need
+
+ // Sec A.2.2 from CCITT Rec. T.81 (1992 E)
+ bool interleaved = !(numberOfComponents == 1);
+
+ if (!interleaved)
+ {
+ JpegComponent comp = Scan.GetComponentById(componentSelector[0]);
+
+ comp.SetBlock(mcuIndex);
+
+ comp.DecodeMCU(jpegReader, h, v);
+
+ int mcus_per_line = mcus_per_row(comp);
+ int blocks_per_line = (int) Math.Ceiling((double)this.Width / (8 * comp.factorH));
+
+
+ // TODO: Explain the non-interleaved scan ------
+
+ h++; x++;
+
+ if (h == comp.factorH)
+ {
+ h = 0; mcuIndex++;
+ }
+
+ if( (x % mcus_per_line) == 0)
+ {
+ x = 0;
+ v++;
+
+ if (v == comp.factorV)
+ {
+ if (h != 0) { mcuIndex++; h = 0; }
+ v = 0;
+ }
+ else
+ {
+ mcuIndex -= blocks_per_line;
+
+ // we were mid-block
+ if (h != 0) { mcuIndex++; h = 0; }
+ }
+ }
+
+ // -----------------------------------------------
+
+ }
+ else // Components are interleaved
+ {
+ for (int compIndex = 0; compIndex < numberOfComponents; compIndex++)
+ {
+ JpegComponent comp = Scan.GetComponentById(componentSelector[compIndex]);
+ comp.SetBlock(mcuTotalIndex);
+
+ for (int j = 0; j < comp.factorV; j++)
+ for (int i = 0; i < comp.factorH; i++)
+ {
+ comp.DecodeMCU(jpegReader, i, j);
+ }
+ }
+
+ mcuIndex++;
+ mcuTotalIndex++;
+ }
+ }
+ // We've found a marker, see if the marker is a restart
+ // marker or just the next marker in the stream. If
+ // it's the next marker in the stream break out of the
+ // while loop, if it's just a restart marker skip it
+ catch (JPEGMarkerFoundException ex)
+ {
+ marker = ex.Marker;
+
+ // Handle JPEG Restart Markers, this is where the
+ // count of MCU's per interval is compared with
+ // the count actually obtained, if it's short then
+ // pad on some MCU's ONLY for components that are
+ // greater than one. Also restart the DC prediction
+ // to zero.
+ if (marker == JPEGMarker.RST0
+ || marker == JPEGMarker.RST1
+ || marker == JPEGMarker.RST2
+ || marker == JPEGMarker.RST3
+ || marker == JPEGMarker.RST4
+ || marker == JPEGMarker.RST5
+ || marker == JPEGMarker.RST6
+ || marker == JPEGMarker.RST7)
+ {
+ for (int compIndex = 0; compIndex < numberOfComponents; compIndex++)
+ {
+ JpegComponent comp = Scan.GetComponentById(componentSelector[compIndex]);
+ if (compIndex > 1)
+ comp.padMCU(mcuTotalIndex, resetInterval - mcuIndex);
+ comp.resetInterval();
+ }
+
+ mcuTotalIndex += (resetInterval - mcuIndex);
+ mcuIndex = 0;
+ }
+ else
+ {
+ break; // We're at the end of our scan, exit out.
+ }
+ }
+ }
+
+ }
+
+ public void DecodeScanProgressive(byte successiveApproximation, byte startSpectralSelection, byte endSpectralSelection,
+ byte numberOfComponents, byte[] componentSelector, int resetInterval, JPEGBinaryReader jpegReader, ref byte marker)
+ {
+
+ byte successiveHigh = (byte)(successiveApproximation >> 4);
+ byte successiveLow = (byte)(successiveApproximation & 0x0f);
+
+ if ((startSpectralSelection > endSpectralSelection) || (endSpectralSelection > 63))
+ throw new Exception("Bad spectral selection.");
+
+ bool dcOnly = startSpectralSelection == 0;
+ bool refinementScan = (successiveHigh != 0);
+
+ if (dcOnly) // DC scan
+ {
+ if (endSpectralSelection != 0)
+ throw new Exception("Bad spectral selection for DC only scan.");
+ }
+ else // AC scan
+ {
+ if (numberOfComponents > 1)
+ throw new Exception("Too many components for AC scan!");
+ }
+
+ // Set the decode function for all the components
+ // TODO: set this for the scan and let the component figure it out
+ for (int compIndex = 0; compIndex < numberOfComponents; compIndex++)
+ {
+ JpegComponent comp = Scan.GetComponentById(componentSelector[compIndex]);
+
+ comp.successiveLow = successiveLow;
+
+ if (dcOnly)
+ {
+ if (refinementScan) // DC refine
+ comp.Decode = comp.DecodeDCRefine;
+ else // DC first
+ comp.Decode = comp.DecodeDCFirst;
+ }
+ else
+ {
+ comp.spectralStart = startSpectralSelection;
+ comp.spectralEnd = endSpectralSelection;
+
+ if (refinementScan) // AC refine
+ comp.Decode = comp.DecodeACRefine;
+ else // AC first
+ comp.Decode = comp.DecodeACFirst;
+ }
+ }
+
+ DecodeScan(numberOfComponents, componentSelector, resetInterval, jpegReader, ref marker);
+
+ }
+
+
+
+ }
+
+}
diff --git a/debian/missing-sources/plupload/csharp/Plupload/FJCore/Decoder/JpegHuffmanTable.cs b/debian/missing-sources/plupload/csharp/Plupload/FJCore/Decoder/JpegHuffmanTable.cs
new file mode 100644
index 0000000..cb4b8f1
--- /dev/null
+++ b/debian/missing-sources/plupload/csharp/Plupload/FJCore/Decoder/JpegHuffmanTable.cs
@@ -0,0 +1,183 @@
+/// Copyright (c) 2008 Jeffrey Powers for Fluxcapacity Open Source.
+/// Under the MIT License, details: License.txt.
+
+using System;
+using System.Linq;
+
+namespace FluxJpeg.Core
+{
+ /// <summary>
+ /// The JPEGHuffmanTable class represents a Huffman table read from a
+ /// JPEG image file. The standard JPEG AC and DC chrominance and
+ /// luminance values are provided as static fields.
+ /// </summary>
+ internal class JpegHuffmanTable
+ {
+ private short[] lengths;
+ private short[] values;
+
+ #region Standard JPEG Huffman Tables
+
+ public static JpegHuffmanTable StdACChrominance =
+ new JpegHuffmanTable(new short[] { 0, 2, 1, 2, 4, 4, 3, 4, 7, 5,
+ 4, 4, 0, 1, 2, 0x77 },
+ new short[] { 0x00, 0x01, 0x02, 0x03, 0x11,
+ 0x04, 0x05, 0x21, 0x31, 0x06,
+ 0x12, 0x41, 0x51, 0x07, 0x61,
+ 0x71, 0x13, 0x22, 0x32, 0x81,
+ 0x08, 0x14, 0x42, 0x91, 0xa1,
+ 0xb1, 0xc1, 0x09, 0x23, 0x33,
+ 0x52, 0xf0, 0x15, 0x62, 0x72,
+ 0xd1, 0x0a, 0x16, 0x24, 0x34,
+ 0xe1, 0x25, 0xf1, 0x17, 0x18,
+ 0x19, 0x1a, 0x26, 0x27, 0x28,
+ 0x29, 0x2a, 0x35, 0x36, 0x37,
+ 0x38, 0x39, 0x3a, 0x43, 0x44,
+ 0x45, 0x46, 0x47, 0x48, 0x49,
+ 0x4a, 0x53, 0x54, 0x55, 0x56,
+ 0x57, 0x58, 0x59, 0x5a, 0x63,
+ 0x64, 0x65, 0x66, 0x67, 0x68,
+ 0x69, 0x6a, 0x73, 0x74, 0x75,
+ 0x76, 0x77, 0x78, 0x79, 0x7a,
+ 0x82, 0x83, 0x84, 0x85, 0x86,
+ 0x87, 0x88, 0x89, 0x8a, 0x92,
+ 0x93, 0x94, 0x95, 0x96, 0x97,
+ 0x98, 0x99, 0x9a, 0xa2, 0xa3,
+ 0xa4, 0xa5, 0xa6, 0xa7, 0xa8,
+ 0xa9, 0xaa, 0xb2, 0xb3, 0xb4,
+ 0xb5, 0xb6, 0xb7, 0xb8, 0xb9,
+ 0xba, 0xc2, 0xc3, 0xc4, 0xc5,
+ 0xc6, 0xc7, 0xc8, 0xc9, 0xca,
+ 0xd2, 0xd3, 0xd4, 0xd5, 0xd6,
+ 0xd7, 0xd8, 0xd9, 0xda, 0xe2,
+ 0xe3, 0xe4, 0xe5, 0xe6, 0xe7,
+ 0xe8, 0xe9, 0xea, 0xf2, 0xf3,
+ 0xf4, 0xf5, 0xf6, 0xf7, 0xf8,
+ 0xf9, 0xfa }, false);
+
+ public static JpegHuffmanTable StdACLuminance =
+ new JpegHuffmanTable(new short[] { 0, 2, 1, 3, 3, 2, 4, 3, 5, 5,
+ 4, 4, 0, 0, 1, 0x7d },
+ new short[] { 0x01, 0x02, 0x03, 0x00, 0x04,
+ 0x11, 0x05, 0x12, 0x21, 0x31,
+ 0x41, 0x06, 0x13, 0x51, 0x61,
+ 0x07, 0x22, 0x71, 0x14, 0x32,
+ 0x81, 0x91, 0xa1, 0x08, 0x23,
+ 0x42, 0xb1, 0xc1, 0x15, 0x52,
+ 0xd1, 0xf0, 0x24, 0x33, 0x62,
+ 0x72, 0x82, 0x09, 0x0a, 0x16,
+ 0x17, 0x18, 0x19, 0x1a, 0x25,
+ 0x26, 0x27, 0x28, 0x29, 0x2a,
+ 0x34, 0x35, 0x36, 0x37, 0x38,
+ 0x39, 0x3a, 0x43, 0x44, 0x45,
+ 0x46, 0x47, 0x48, 0x49, 0x4a,
+ 0x53, 0x54, 0x55, 0x56, 0x57,
+ 0x58, 0x59, 0x5a, 0x63, 0x64,
+ 0x65, 0x66, 0x67, 0x68, 0x69,
+ 0x6a, 0x73, 0x74, 0x75, 0x76,
+ 0x77, 0x78, 0x79, 0x7a, 0x83,
+ 0x84, 0x85, 0x86, 0x87, 0x88,
+ 0x89, 0x8a, 0x92, 0x93, 0x94,
+ 0x95, 0x96, 0x97, 0x98, 0x99,
+ 0x9a, 0xa2, 0xa3, 0xa4, 0xa5,
+ 0xa6, 0xa7, 0xa8, 0xa9, 0xaa,
+ 0xb2, 0xb3, 0xb4, 0xb5, 0xb6,
+ 0xb7, 0xb8, 0xb9, 0xba, 0xc2,
+ 0xc3, 0xc4, 0xc5, 0xc6, 0xc7,
+ 0xc8, 0xc9, 0xca, 0xd2, 0xd3,
+ 0xd4, 0xd5, 0xd6, 0xd7, 0xd8,
+ 0xd9, 0xda, 0xe1, 0xe2, 0xe3,
+ 0xe4, 0xe5, 0xe6, 0xe7, 0xe8,
+ 0xe9, 0xea, 0xf1, 0xf2, 0xf3,
+ 0xf4, 0xf5, 0xf6, 0xf7, 0xf8,
+ 0xf9, 0xfa }, false);
+
+ public static JpegHuffmanTable StdDCChrominance =
+ new JpegHuffmanTable(new short[] { 0, 3, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 0, 0, 0, 0, 0 },
+ new short[] { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,
+ 10, 11 }, false);
+
+ public static JpegHuffmanTable StdDCLuminance =
+ new JpegHuffmanTable(new short[] { 0, 1, 5, 1, 1, 1, 1, 1, 1, 0,
+ 0, 0, 0, 0, 0, 0 },
+ new short[] { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,
+ 10, 11 }, false);
+
+ #endregion
+
+
+ /// <summary>
+ /// Construct and initialize a Huffman table. Copies are created of
+ /// the array arguments. lengths[index] stores the number of Huffman
+ /// values with Huffman codes of length index + 1. The values array
+ /// stores the Huffman values in order of increasing code length.
+ ///
+ /// throws ArgumentException if either parameter is null, if
+ /// lengths.Length > 16 or values.Length > 256, if any value in
+ /// length or values is negative, or if the parameters do not
+ /// describe a valid Huffman table
+ /// </summary>
+ /// <param name="lengths"> an array of Huffman code lengths</param>
+ /// <param name="values">a sorted array of Huffman values</param>
+ public JpegHuffmanTable(short[] lengths, short[] values)
+ // Create copies of the lengths and values arguments.
+ : this(checkLengths(lengths), checkValues(values, lengths), true)
+ {
+ }
+
+ /// <summary>
+ /// Private constructor that avoids unnecessary copying and argument checking.
+ /// </summary>
+ /// <param name="lengths">lengths an array of Huffman code lengths</param>
+ /// <param name="values">a sorted array of Huffman values</param>
+ /// <param name="copy">true if copies should be created of the given arrays</param>
+ private JpegHuffmanTable(short[] lengths, short[] values, bool copy)
+ {
+ this.lengths = copy ? (short[])lengths.Clone() : lengths;
+ this.values = copy ? (short[])values.Clone() : values;
+ }
+
+ private static short[] checkLengths(short[] lengths)
+ {
+ if (lengths == null || lengths.Length > 16)
+ throw new ArgumentException("Length array is null or too long.");
+
+ if(lengths.Any(x => x < 0))
+ throw new ArgumentException("Negative values cannot appear in the length array.");
+
+ for (int i = 0; i < lengths.Length; i++)
+ {
+ if (lengths[i] > ((1 << (i + 1)) - 1))
+ throw new ArgumentException(
+ string.Format("Invalid number of codes for code length {0}", (i + 1).ToString() ));
+ }
+
+ return lengths;
+ }
+
+ private static short[] checkValues(short[] values, short[] lengths)
+ {
+ if (values == null || values.Length > 256)
+ throw new ArgumentException("Values array is null or too long.");
+
+ if (values.Any(x => x < 0))
+ throw new ArgumentException("Negative values cannot appear in the values array.");
+
+ if (values.Length != lengths.Sum(x => (int)x))
+ throw new ArgumentException("Number of values does not match code length sum.");
+
+ return values;
+ }
+
+ /// <summary>
+ /// Retrieve the array of Huffman code lengths. If the
+ /// returned array is called lengthcount, there are
+ /// lengthcount[index] codes of length index + 1.
+ /// </summary>
+ public short[] Lengths { get { return lengths; } }
+ public short[] Values { get { return values; } }
+
+ }
+
+}
diff --git a/debian/missing-sources/plupload/csharp/Plupload/FJCore/Decoder/JpegQuantizationTable.cs b/debian/missing-sources/plupload/csharp/Plupload/FJCore/Decoder/JpegQuantizationTable.cs
new file mode 100644
index 0000000..d1f073a
--- /dev/null
+++ b/debian/missing-sources/plupload/csharp/Plupload/FJCore/Decoder/JpegQuantizationTable.cs
@@ -0,0 +1,116 @@
+/// Copyright (c) 2008 Jeffrey Powers for Fluxcapacity Open Source.
+/// Under the MIT License, details: License.txt.
+
+using System;
+
+namespace FluxJpeg.Core
+{
+ internal class JpegQuantizationTable
+ {
+ // The table entries, stored in natural order.
+ private int[] table; public int[] Table { get { return table; } }
+
+ /// <summary>
+ /// The standard JPEG luminance quantization table. Values are
+ /// stored in natural order.
+ /// </summary>
+ public static JpegQuantizationTable K1Luminance = new JpegQuantizationTable(new int[]
+ {
+ 16, 11, 10, 16, 24, 40, 51, 61,
+ 12, 12, 14, 19, 26, 58, 60, 55,
+ 14, 13, 16, 24, 40, 57, 69, 56,
+ 14, 17, 22, 29, 51, 87, 80, 62,
+ 18, 22, 37, 56, 68, 109, 103, 77,
+ 24, 35, 55, 64, 81, 104, 113, 92,
+ 49, 64, 78, 87, 103, 121, 120, 101,
+ 72, 92, 95, 98, 112, 100, 103, 99
+ }, false);
+
+ /// <summary>
+ /// The standard JPEG luminance quantization table, scaled by
+ /// one-half. Values are stored in natural order.
+ /// </summary>
+ public static JpegQuantizationTable K1Div2Luminance =
+ K1Luminance.getScaledInstance(0.5f, true);
+
+ /// <summary>
+ /// The standard JPEG chrominance quantization table. Values are
+ /// stored in natural order.
+ /// </summary>
+ public static JpegQuantizationTable K2Chrominance = new JpegQuantizationTable(new int[]
+ {
+ 17, 18, 24, 47, 99, 99, 99, 99,
+ 18, 21, 26, 66, 99, 99, 99, 99,
+ 24, 26, 56, 99, 99, 99, 99, 99,
+ 47, 66, 99, 99, 99, 99, 99, 99,
+ 99, 99, 99, 99, 99, 99, 99, 99,
+ 99, 99, 99, 99, 99, 99, 99, 99,
+ 99, 99, 99, 99, 99, 99, 99, 99,
+ 99, 99, 99, 99, 99, 99, 99, 99
+ }, false);
+
+ /// <summary>
+ /// The standard JPEG chrominance quantization table, scaled by
+ /// one-half. Values are stored in natural order.
+ /// </summary>
+ public static JpegQuantizationTable K2Div2Chrominance =
+ K2Chrominance.getScaledInstance(0.5f, true);
+
+ /// <summary>
+ /// Construct a new JPEG quantization table. A copy is created of
+ /// the table argument.
+ /// </summary>
+ /// <param name="table">The 64-element value table, stored in natural order</param>
+ public JpegQuantizationTable(int[] table)
+ : this(checkTable(table), true)
+ {
+ }
+
+ /// <summary>
+ /// Private constructor that avoids unnecessary copying and argument
+ /// checking.
+ /// </summary>
+ /// <param name="table">the 64-element value table, stored in natural order</param>
+ /// <param name="copy">true if a copy should be created of the given table</param>
+ private JpegQuantizationTable(int[] table, bool copy)
+ {
+ this.table = copy ? (int[])table.Clone() : table;
+ }
+
+ private static int[] checkTable(int[] table)
+ {
+ if (table == null || table.Length != 64)
+ throw new ArgumentException("Invalid JPEG quantization table");
+
+ return table;
+ }
+
+ /// <summary>
+ /// Retrieve a copy of this JPEG quantization table with every value
+ /// scaled by the given scale factor, and clamped from 1 to 255
+ /// </summary>
+ /// <param name="scaleFactor">the factor by which to scale this table</param>
+ /// <param name="forceBaseline"> clamp scaled values to a maximum of 255 if baseline or from 1 to 32767 otherwise.</param>
+ /// <returns>new scaled JPEG quantization table</returns>
+ public JpegQuantizationTable getScaledInstance(float scaleFactor,
+ bool forceBaseline)
+ {
+ int[] scaledTable = (int[])table.Clone();
+ int max = forceBaseline ? 255 : 32767;
+
+ for (int i = 0; i < scaledTable.Length; i++)
+ {
+ scaledTable[i] = (int)Math.Round(scaleFactor * (float)scaledTable[i]);
+ if (scaledTable[i] < 1)
+ scaledTable[i] = 1;
+ else if (scaledTable[i] > max)
+ scaledTable[i] = max;
+ }
+
+ return new JpegQuantizationTable(scaledTable, false);
+ }
+
+ }
+
+
+}
diff --git a/debian/missing-sources/plupload/csharp/Plupload/FJCore/Decoder/JpegScan.cs b/debian/missing-sources/plupload/csharp/Plupload/FJCore/Decoder/JpegScan.cs
new file mode 100644
index 0000000..38e1911
--- /dev/null
+++ b/debian/missing-sources/plupload/csharp/Plupload/FJCore/Decoder/JpegScan.cs
@@ -0,0 +1,37 @@
+/// Copyright (c) 2008 Jeffrey Powers for Fluxcapacity Open Source.
+/// Under the MIT License, details: License.txt.
+
+using System;
+using System.Collections.Generic;
+using System.Linq;
+
+namespace FluxJpeg.Core.Decoder
+{
+ internal class JpegScan
+ {
+ private List<JpegComponent> components = new List<JpegComponent>();
+ public IList<JpegComponent> Components { get { return components.AsReadOnly(); } }
+
+ private int maxV = 0, maxH = 0;
+ internal int MaxH { get { return maxH; } }
+ internal int MaxV { get { return maxV; } }
+
+ public void AddComponent(byte id, byte factorHorizontal, byte factorVertical,
+ byte quantizationID, byte colorMode)
+ {
+ JpegComponent component = new JpegComponent( this,
+ id, factorHorizontal, factorVertical, quantizationID, colorMode);
+
+ components.Add(component);
+
+ // Defined in Annex A
+ maxH = components.Max(x => x.factorH);
+ maxV = components.Max(x => x.factorV);
+ }
+
+ public JpegComponent GetComponentById(byte Id)
+ {
+ return components.First(x => x.component_id == Id);
+ }
+ }
+}
diff --git a/debian/missing-sources/plupload/csharp/Plupload/FJCore/Encoder/JpegEncoder.cs b/debian/missing-sources/plupload/csharp/Plupload/FJCore/Encoder/JpegEncoder.cs
new file mode 100644
index 0000000..3ff9a93
--- /dev/null
+++ b/debian/missing-sources/plupload/csharp/Plupload/FJCore/Encoder/JpegEncoder.cs
@@ -0,0 +1,327 @@
+/// Copyright (c) 2008 Jeffrey Powers for Fluxcapacity Open Source.
+/// Under the MIT License, details: License.txt.
+//
+// Partially derives from a Java encoder, JpegEncoder.java by James R Weeks.
+// Implements Baseline JPEG Encoding http://www.opennet.ru/docs/formats/jpeg.txt
+
+using System;
+using System.Collections.Generic;
+using System.IO;
+
+namespace FluxJpeg.Core.Encoder
+{
+ public class JpegEncodeProgressChangedArgs : EventArgs
+ {
+ public double EncodeProgress; // 0.0 to 1.0
+ }
+
+ public class JpegEncoder
+ {
+ JpegEncodeProgressChangedArgs _progress;
+
+ DecodedJpeg _input;
+ Stream _outStream;
+ HuffmanTable _huf;
+ DCT _dct;
+
+ int _height;
+ int _width;
+ int _quality;
+
+ private const int Ss = 0;
+ private const int Se = 63;
+ private const int Ah = 0;
+ private const int Al = 0;
+
+ private static readonly int[] CompID = { 1, 2, 3 };
+ private static readonly int[] HsampFactor = { 1, 1, 1 };
+ private static readonly int[] VsampFactor = { 1, 1, 1 };
+ private static readonly int[] QtableNumber = { 0, 1, 1 };
+ private static readonly int[] DCtableNumber = { 0, 1, 1 };
+ private static readonly int[] ACtableNumber = { 0, 1, 1 };
+
+ public event EventHandler<JpegEncodeProgressChangedArgs> EncodeProgressChanged;
+
+ public JpegEncoder(Image image, int quality, Stream outStream)
+ : this(new DecodedJpeg(image), quality, outStream) { /* see overload */ }
+
+ /// <summary>
+ /// Encodes a JPEG, preserving the colorspace and metadata of the input JPEG.
+ /// </summary>
+ /// <param name="decodedJpeg">Decoded Jpeg to start with.</param>
+ /// <param name="quality">Quality of the image from 0 to 100. (Compression from max to min.)</param>
+ /// <param name="outStream">Stream where the result will be placed.</param>
+ public JpegEncoder(DecodedJpeg decodedJpeg, int quality, Stream outStream)
+ {
+ _input = decodedJpeg;
+
+ /* This encoder requires YCbCr */
+ _input.Image.ChangeColorSpace(ColorSpace.YCbCr);
+
+ _quality = quality;
+
+ _height = _input.Image.Height;
+ _width = _input.Image.Width;
+ _outStream = outStream;
+ _dct = new DCT(_quality);
+ _huf = new HuffmanTable(null);
+ }
+
+ public void Encode()
+ {
+ _progress = new JpegEncodeProgressChangedArgs();
+
+ WriteHeaders();
+ CompressTo(_outStream);
+ WriteMarker(new byte[] { 0xFF, 0xD9 }); // End of Image
+
+ _progress.EncodeProgress = 1.0;
+ if (EncodeProgressChanged != null)
+ EncodeProgressChanged(this, _progress);
+
+ _outStream.Flush();
+ }
+
+ internal void WriteHeaders()
+ {
+ int i, j, index, offset;
+ int[] tempArray;
+
+ // Start of Image
+ byte[] SOI = { (byte)0xFF, (byte)0xD8 };
+ WriteMarker(SOI);
+
+ if (!_input.HasJFIF) // Supplement JFIF if missing
+ {
+ byte[] JFIF = new byte[18]
+ {
+ (byte)0xff, (byte)0xe0,
+ (byte)0x00, (byte)0x10,
+ (byte)0x4a, (byte)0x46,
+ (byte)0x49, (byte)0x46,
+ (byte)0x00, (byte)0x01,
+ (byte)0x00, (byte)0x00,
+ (byte)0x00, (byte)0x01,
+ (byte)0x00, (byte)0x01,
+ (byte)0x00, (byte)0x00
+ };
+
+ WriteArray(JFIF);
+ }
+
+ IO.BinaryWriter writer = new IO.BinaryWriter(_outStream);
+
+ /* APP headers and COM headers follow the same format
+ * which has a 16-bit integer length followed by a block
+ * of binary data. */
+ foreach (JpegHeader header in _input.MetaHeaders)
+ {
+ writer.Write(JPEGMarker.XFF);
+ writer.Write(header.Marker);
+
+ // Header's length
+ writer.Write((short)(header.Data.Length + 2));
+ writer.Write(header.Data);
+ }
+
+ // The DQT header
+ // 0 is the luminance index and 1 is the chrominance index
+ byte[] DQT = new byte[134];
+ DQT[0] = JPEGMarker.XFF;
+ DQT[1] = JPEGMarker.DQT;
+ DQT[2] = (byte)0x00;
+ DQT[3] = (byte)0x84;
+ offset = 4;
+ for (i = 0; i < 2; i++)
+ {
+ DQT[offset++] = (byte)((0 << 4) + i);
+ tempArray = (int[])_dct.quantum[i];
+
+ for (j = 0; j < 64; j++)
+ {
+ DQT[offset++] = (byte)tempArray[ ZigZag.ZigZagMap[j] ];
+ }
+ }
+
+ WriteArray(DQT);
+
+ // Start of Frame Header ( Baseline JPEG )
+ byte[] SOF = new byte[19];
+ SOF[0] = JPEGMarker.XFF;
+ SOF[1] = JPEGMarker.SOF0;
+ SOF[2] = (byte)0x00;
+ SOF[3] = (byte)17;
+ SOF[4] = (byte)_input.Precision;
+ SOF[5] = (byte)((_input.Image.Height >> 8) & 0xFF);
+ SOF[6] = (byte)((_input.Image.Height) & 0xFF);
+ SOF[7] = (byte)((_input.Image.Width >> 8) & 0xFF);
+ SOF[8] = (byte)((_input.Image.Width) & 0xFF);
+ SOF[9] = (byte)_input.Image.ComponentCount;
+ index = 10;
+
+ for (i = 0; i < SOF[9]; i++)
+ {
+ SOF[index++] = (byte)JpegEncoder.CompID[i];
+ SOF[index++] = (byte)((_input.HsampFactor[i] << 4) + _input.VsampFactor[i]);
+ SOF[index++] = (byte)JpegEncoder.QtableNumber[i];
+ }
+
+ WriteArray(SOF);
+
+ // The DHT Header
+ byte[] DHT1, DHT2, DHT3, DHT4;
+ int bytes, temp, oldindex, intermediateindex;
+ index = 4;
+ oldindex = 4;
+ DHT1 = new byte[17];
+ DHT4 = new byte[4];
+ DHT4[0] = JPEGMarker.XFF;
+ DHT4[1] = JPEGMarker.DHT;
+ for (i = 0; i < 4; i++)
+ {
+ bytes = 0;
+
+ // top 4 bits: table class (0=DC, 1=AC)
+ // bottom 4: index (0=luminance, 1=chrominance)
+ byte huffmanInfo = (i == 0) ? (byte)0x00 :
+ (i == 1) ? (byte)0x10 :
+ (i == 2) ? (byte)0x01 : (byte)0x11;
+
+ DHT1[index++ - oldindex] = huffmanInfo;
+
+ for (j = 0; j < 16; j++)
+ {
+ temp = _huf.bitsList[i][j];
+ DHT1[index++ - oldindex] = (byte)temp;
+ bytes += temp;
+ }
+
+ intermediateindex = index;
+ DHT2 = new byte[bytes];
+ for (j = 0; j < bytes; j++)
+ {
+ DHT2[index++ - intermediateindex] = (byte)_huf.val[i][j];
+ }
+ DHT3 = new byte[index];
+ Array.Copy(DHT4, 0, DHT3, 0, oldindex);
+ Array.Copy(DHT1, 0, DHT3, oldindex, 17);
+ Array.Copy(DHT2, 0, DHT3, oldindex + 17, bytes);
+ DHT4 = DHT3;
+ oldindex = index;
+ }
+ DHT4[2] = (byte)(((index - 2) >> 8) & 0xFF);
+ DHT4[3] = (byte)((index - 2) & 0xFF);
+ WriteArray(DHT4);
+
+ // Start of Scan Header
+ byte[] SOS = new byte[14];
+ SOS[0] = JPEGMarker.XFF;
+ SOS[1] = JPEGMarker.SOS;
+ SOS[2] = (byte)0x00;
+ SOS[3] = (byte)12;
+ SOS[4] = (byte)_input.Image.ComponentCount;
+
+ index = 5;
+
+ for (i = 0; i < SOS[4]; i++)
+ {
+ SOS[index++] = (byte)JpegEncoder.CompID[i];
+ SOS[index++] = (byte)((JpegEncoder.DCtableNumber[i] << 4) + JpegEncoder.ACtableNumber[i]);
+ }
+
+ SOS[index++] = (byte)JpegEncoder.Ss;
+ SOS[index++] = (byte)JpegEncoder.Se;
+ SOS[index++] = (byte)((JpegEncoder.Ah << 4) + JpegEncoder.Al);
+ WriteArray(SOS);
+
+ }
+
+
+ internal void CompressTo(Stream outStream)
+ {
+ int i = 0, j = 0, r = 0, c = 0, a = 0, b = 0;
+ int comp, xpos, ypos, xblockoffset, yblockoffset;
+ byte[,] inputArray = null;
+ float[,] dctArray1 = new float[8, 8];
+ float[,] dctArray2 = new float[8, 8];
+ int[] dctArray3 = new int[8 * 8];
+
+ int[] lastDCvalue = new int[_input.Image.ComponentCount];
+
+ int Width = 0, Height = 0;
+ int MinBlockWidth, MinBlockHeight;
+
+ // This initial setting of MinBlockWidth and MinBlockHeight is done to
+ // ensure they start with values larger than will actually be the case.
+ MinBlockWidth = ((_width % 8 != 0) ? (int)(Math.Floor((double)_width / 8.0) + 1) * 8 : _width);
+ MinBlockHeight = ((_height % 8 != 0) ? (int)(Math.Floor((double)_height / 8.0) + 1) * 8 : _height);
+ for (comp = 0; comp < _input.Image.ComponentCount; comp++)
+ {
+ MinBlockWidth = Math.Min(MinBlockWidth, _input.BlockWidth[comp]);
+ MinBlockHeight = Math.Min(MinBlockHeight, _input.BlockHeight[comp]);
+ }
+ xpos = 0;
+
+ for (r = 0; r < MinBlockHeight; r++)
+ {
+ // Keep track of progress
+ _progress.EncodeProgress = (double)r / MinBlockHeight;
+ if (EncodeProgressChanged != null) EncodeProgressChanged(this, _progress);
+
+ for (c = 0; c < MinBlockWidth; c++)
+ {
+ xpos = c * 8;
+ ypos = r * 8;
+ for (comp = 0; comp < _input.Image.ComponentCount; comp++)
+ {
+ Width = _input.BlockWidth[comp];
+ Height = _input.BlockHeight[comp];
+
+ inputArray = _input.Image.Raster[comp];
+
+ for (i = 0; i < _input.VsampFactor[comp]; i++)
+ {
+ for (j = 0; j < _input.HsampFactor[comp]; j++)
+ {
+ xblockoffset = j * 8;
+ yblockoffset = i * 8;
+ for (a = 0; a < 8; a++)
+ {
+ // set Y value. check bounds
+ int y = ypos + yblockoffset + a; if (y >= _height) break;
+
+ for (b = 0; b < 8; b++)
+ {
+ int x = xpos + xblockoffset + b; if (x >= _width) break;
+ dctArray1[a, b] = inputArray[x,y];
+ }
+ }
+ dctArray2 = _dct.FastFDCT(dctArray1);
+ dctArray3 = _dct.QuantizeBlock(dctArray2, JpegEncoder.QtableNumber[comp]);
+
+ _huf.HuffmanBlockEncoder(outStream, dctArray3, lastDCvalue[comp], JpegEncoder.DCtableNumber[comp], JpegEncoder.ACtableNumber[comp]);
+ lastDCvalue[comp] = dctArray3[0];
+ }
+ }
+ }
+ }
+ }
+
+ _huf.FlushBuffer(outStream);
+ }
+
+
+ void WriteMarker(byte[] data)
+ {
+ _outStream.Write(data, 0, 2);
+ }
+
+ void WriteArray(byte[] data)
+ {
+ int length = (((int)(data[2] & 0xFF)) << 8) + (int)(data[3] & 0xFF) + 2;
+ _outStream.Write(data, 0, length);
+ }
+
+ }
+
+} \ No newline at end of file
diff --git a/debian/missing-sources/plupload/csharp/Plupload/FJCore/FDCT.cs b/debian/missing-sources/plupload/csharp/Plupload/FJCore/FDCT.cs
new file mode 100644
index 0000000..630ce88
--- /dev/null
+++ b/debian/missing-sources/plupload/csharp/Plupload/FJCore/FDCT.cs
@@ -0,0 +1,201 @@
+using System;
+
+namespace FluxJpeg.Core
+{
+ public partial class DCT
+ {
+ public const int N = 8;
+
+ public int[][] quantum = new int[2][];
+ public double[][] divisors = new double[2][];
+
+ // Quantitization Matrix for luminace.
+ public double[] DivisorsLuminance = new double[N * N];
+
+ // Quantitization Matrix for chrominance.
+ public double[] DivisorsChrominance = new double[N * N];
+
+ public DCT(int quality) : this()
+ {
+ Initialize(quality);
+ }
+
+ private void Initialize(int quality)
+ {
+ double[] aanScaleFactor =
+ {
+ 1.0, 1.387039845, 1.306562965, 1.175875602,
+ 1.0, 0.785694958, 0.541196100, 0.275899379
+ };
+
+ int i, j, index, Quality;
+
+ // jpeg_quality_scaling
+ if (quality <= 0) Quality = 1;
+ if (quality > 100) Quality = 100;
+ if (quality < 50) Quality = 5000 / quality;
+ else Quality = 200 - quality * 2;
+
+ int[] scaledLum = JpegQuantizationTable.K1Luminance
+ .getScaledInstance(Quality / 100f, true).Table;
+
+ index = 0;
+ for (i = 0; i < 8; i++)
+ {
+ for (j = 0; j < 8; j++)
+ {
+ DivisorsLuminance[index] =
+ (double)1.0 /
+ ((double)scaledLum[index] * aanScaleFactor[i] * aanScaleFactor[j] * 8.0);
+
+ index++;
+ }
+ }
+
+ // Creating the chrominance matrix
+ int[] scaledChrom = JpegQuantizationTable.K2Chrominance
+ .getScaledInstance(Quality / 100f, true).Table;
+
+ index = 0;
+ for (i = 0; i < 8; i++)
+ {
+ for (j = 0; j < 8; j++)
+ {
+ DivisorsChrominance[index] = (double)((double)1.0 / ((double)scaledChrom[index] * aanScaleFactor[i] * aanScaleFactor[j] * (double)8.0));
+ index++;
+ }
+ }
+
+ quantum[0] = scaledLum;
+ divisors[0] = DivisorsLuminance;
+ quantum[1] = scaledChrom;
+ divisors[1] = DivisorsChrominance;
+ }
+
+ internal float[,] FastFDCT(float[,] input)
+ {
+ float[,] output = new float[N, N];
+
+ float tmp0, tmp1, tmp2, tmp3, tmp4, tmp5, tmp6, tmp7;
+ float tmp10, tmp11, tmp12, tmp13;
+ float z1, z2, z3, z4, z5, z11, z13;
+ int i, j;
+
+ for (i = 0; i < 8; i++)
+ for (j = 0; j < 8; j++)
+ output[i, j] = input[i, j] - 128f;
+
+ // Pass 1: process rows.
+
+ for (i = 0; i < 8; i++)
+ {
+ tmp0 = output[i, 0] + output[i, 7];
+ tmp7 = output[i, 0] - output[i, 7];
+ tmp1 = output[i, 1] + output[i, 6];
+ tmp6 = output[i, 1] - output[i, 6];
+ tmp2 = output[i, 2] + output[i, 5];
+ tmp5 = output[i, 2] - output[i, 5];
+ tmp3 = output[i, 3] + output[i, 4];
+ tmp4 = output[i, 3] - output[i, 4];
+
+ // Even part
+ tmp10 = tmp0 + tmp3;
+ tmp13 = tmp0 - tmp3;
+ tmp11 = tmp1 + tmp2;
+ tmp12 = tmp1 - tmp2;
+
+ output[i, 0] = tmp10 + tmp11;
+ output[i, 4] = tmp10 - tmp11;
+
+ z1 = (tmp12 + tmp13) * (float)0.707106781;
+ output[i, 2] = tmp13 + z1;
+ output[i, 6] = tmp13 - z1;
+
+ // Odd part
+ tmp10 = tmp4 + tmp5;
+ tmp11 = tmp5 + tmp6;
+ tmp12 = tmp6 + tmp7;
+
+ // The rotator is modified from fig 4-8 to avoid extra negations.
+ z5 = (tmp10 - tmp12) * (float)0.382683433;
+ z2 = ((float)0.541196100) * tmp10 + z5;
+ z4 = ((float)1.306562965) * tmp12 + z5;
+ z3 = tmp11 * ((float)0.707106781);
+
+ z11 = tmp7 + z3;
+ z13 = tmp7 - z3;
+
+ output[i, 5] = z13 + z2;
+ output[i, 3] = z13 - z2;
+ output[i, 1] = z11 + z4;
+ output[i, 7] = z11 - z4;
+ }
+
+ // Pass 2: process columns
+
+ for (i = 0; i < 8; i++)
+ {
+ tmp0 = output[0, i] + output[7, i];
+ tmp7 = output[0, i] - output[7, i];
+ tmp1 = output[1, i] + output[6, i];
+ tmp6 = output[1, i] - output[6, i];
+ tmp2 = output[2, i] + output[5, i];
+ tmp5 = output[2, i] - output[5, i];
+ tmp3 = output[3, i] + output[4, i];
+ tmp4 = output[3, i] - output[4, i];
+
+ // Even part
+ tmp10 = tmp0 + tmp3;
+ tmp13 = tmp0 - tmp3;
+ tmp11 = tmp1 + tmp2;
+ tmp12 = tmp1 - tmp2;
+
+ output[0, i] = tmp10 + tmp11;
+ output[4, i] = tmp10 - tmp11;
+
+ z1 = (tmp12 + tmp13) * (float)0.707106781;
+ output[2, i] = tmp13 + z1;
+ output[6, i] = tmp13 - z1;
+
+ // Odd part
+ tmp10 = tmp4 + tmp5;
+ tmp11 = tmp5 + tmp6;
+ tmp12 = tmp6 + tmp7;
+
+ // The rotator is modified from fig 4-8 to avoid extra negations.
+ z5 = (tmp10 - tmp12) * (float)0.382683433;
+ z2 = ((float)0.541196100) * tmp10 + z5;
+ z4 = ((float)1.306562965) * tmp12 + z5;
+ z3 = tmp11 * ((float)0.707106781);
+
+ z11 = tmp7 + z3;
+ z13 = tmp7 - z3;
+
+ output[5, i] = z13 + z2;
+ output[3, i] = z13 - z2;
+ output[1, i] = z11 + z4;
+ output[7, i] = z11 - z4;
+ }
+
+ return output;
+ }
+
+
+ internal int[] QuantizeBlock(float[,] inputData, int code)
+ {
+ int[] result = new int[N * N];
+ int index = 0;
+
+ for (int i = 0; i < N; i++)
+ for (int j = 0; j < N; j++)
+ {
+ result[index] = (int)(Math.Round(inputData[i, j] * divisors[code][index]));
+ index++;
+ }
+
+ return result;
+ }
+
+
+ }
+}
diff --git a/debian/missing-sources/plupload/csharp/Plupload/FJCore/Filter/Convolution.cs b/debian/missing-sources/plupload/csharp/Plupload/FJCore/Filter/Convolution.cs
new file mode 100644
index 0000000..9099e8c
--- /dev/null
+++ b/debian/missing-sources/plupload/csharp/Plupload/FJCore/Filter/Convolution.cs
@@ -0,0 +1,404 @@
+/// Copyright (c) 2009 Jeffrey Powers for Occipital Open Source.
+/// Under the MIT License, details: License.txt.
+
+using System;
+using System.Threading;
+
+using FluxJpeg.Core;
+
+namespace FluxJpeg.Core.Filtering
+{
+ public class Convolution
+ {
+
+ public static readonly Convolution Instance = new Convolution();
+
+ public GrayImage GaussianConv(GrayImage data, double std)
+ {
+ float[] filter = GaussianFilter(std);
+ return Conv2DSeparable(data, filter);
+ }
+
+ public float[] GaussianFilter(double std)
+ {
+ const double Precision = 0.01f;
+
+ double var = std * std;
+
+ double n = Math.Sqrt(-1 * var * Math.Log(Precision));
+ int half = (int)Math.Ceiling(n);
+
+ float[] filter = new float[half];
+
+ double sum = -1.0;
+ for (int i = 0; i < half; i++)
+ {
+ double val = Math.Exp(-0.5 * (i * i) / var);
+ filter[i] = (float)val;
+ sum += 2 * val;
+ }
+
+ /* Normalize */
+ for (int i = 0; i < half; i++)
+ filter[i] /= (float)sum;
+
+ return filter;
+
+ }
+
+ public GrayImage Conv2DSeparable(GrayImage data, float[] filter)
+ {
+ GrayImage pass1 = Filter1DSymmetric(data, filter, true);
+ GrayImage result = Filter1DSymmetric(pass1, filter, true);
+
+ return result;
+ }
+
+ private struct FilterJob
+ {
+ public float[] filter;
+ public int start;
+ public int end;
+ public GrayImage data;
+ public GrayImage result;
+ public int dataPtr;
+ public int destPtr;
+ }
+
+
+ /// <summary>
+ /// Filters an GrayImage with a 1D symmetric filter along the X-axis.
+ /// (This operation is multithreaded)
+ /// </summary>
+ /// <param name="data">GrayImage to be operated on</param>
+ /// <param name="filter">Filter to use (center tap plus right-hand-side)</param>
+ /// <param name="transpose">Transpose the result?</param>
+ /// <returns>Transposed, filtered GrayImage.</returns>
+ public GrayImage Filter1DSymmetric(GrayImage data, float[] filter, bool transpose)
+ {
+ GrayImage result = transpose ?
+ new GrayImage(data.Height, data.Width) :
+ new GrayImage(data.Width, data.Height);
+
+ int startY = 0;
+
+ int destPtr = transpose ? startY : (startY * result.Width);
+
+ FilterJob job
+ = new FilterJob
+ {
+ filter = filter,
+ data = data,
+ destPtr = destPtr,
+ result = result,
+ start = startY,
+ end = data.Height / 2
+ };
+
+ ParameterizedThreadStart del = transpose ?
+ new ParameterizedThreadStart(FilterPartSymmetricT) :
+ new ParameterizedThreadStart(FilterPartSymmetric);
+
+ Thread worker = new Thread(del);
+ worker.Start(job);
+
+ startY = data.Height / 2;
+ destPtr = transpose ? startY : (startY * result.Width);
+
+
+ job.start = startY;
+ job.destPtr = destPtr;
+ job.end = data.Height;
+
+ del((object)job); // Run the appropriate filter in this thread, too
+
+ worker.Join();
+
+
+ return result;
+ }
+
+
+ /// <summary>
+ /// Convolves part of an GrayImage with a 1D filter along the X-axis
+ /// and transposes it as well.
+ /// </summary>
+ /// <param name="filterJob">Filter operation details</param>
+ private void FilterPartSymmetricT(object filterJob)
+ {
+ FilterJob fj = (FilterJob)filterJob;
+
+
+ GrayImage data = fj.data;
+ float[] srcData = data.Scan0;
+ float[] filter = fj.filter;
+ GrayImage result = fj.result;
+
+ int pad = filter.Length - 1;
+
+ #region Filter and transpose
+ for (int y = fj.start; y < fj.end; y++)
+ {
+ int rowStart = y * data.Width;
+
+ int ptr = rowStart;
+
+ // Left checked region
+ for (int x = 0; x < pad; x++)
+ {
+ float pixel = srcData[ptr] * filter[0];
+
+ // Part of the filter that fits within the GrayImage
+ for (int i = 1; i < x + 1; i++)
+ pixel += (srcData[ptr + i] + srcData[ptr - i]) * filter[i];
+
+ // Part of the filter that falls off the left side
+ for (int i = x + 1; i < filter.Length; i++)
+ pixel += (srcData[ptr + i] + srcData[ptr + i]) * filter[i];
+
+ result[y, x] = pixel; ptr++;
+ }
+
+ // Unchecked region
+ for (int x = pad; x < data.Width - pad; x++)
+ {
+ float pixel = srcData[ptr] * filter[0];
+
+ for (int i = 1; i < filter.Length; i++)
+ pixel += (srcData[ptr + i] + srcData[ptr - i]) * filter[i];
+
+ result[y, x] = pixel; ptr++;
+ }
+
+ // Right checked region
+ for (int x = data.Width - pad; x < data.Width; x++)
+ {
+ float pixel = srcData[ptr] * filter[0];
+
+ // Part of the filter that fits within the GrayImage
+ for (int i = 1; i < (data.Width - x); i++)
+ pixel += (srcData[ptr + i] + srcData[ptr - i]) * filter[i];
+
+ // Part of the filter that falls off the right side
+ for (int i = (data.Width - x); i < filter.Length; i++)
+ pixel += (srcData[ptr - i] + srcData[ptr - i]) * filter[i];
+
+ result[y, x] = pixel; ptr++;
+ }
+ }
+ #endregion
+
+ }
+
+ /// <summary>
+ /// Convolves an GrayImage with a 1D filter along the X-axis.
+ /// </summary>
+ /// <param name="filterJob">Filter operation details</param>
+ private void FilterPartSymmetric(object filterJob)
+ {
+ FilterJob fj = (FilterJob)filterJob;
+
+ GrayImage data = fj.data;
+ float[] srcData = data.Scan0;
+ float[] filter = fj.filter;
+ GrayImage result = fj.result;
+ float[] resData = result.Scan0;
+
+ int pad = filter.Length - 1;
+
+ int destPtr = fj.destPtr;
+
+ #region Filter (no transpose)
+ for (int y = fj.start; y < fj.end; y++)
+ {
+ int rowStart = y * data.Width;
+
+ int ptr = fj.dataPtr + rowStart;
+
+ // Left checked region
+ for (int x = 0; x < pad; x++)
+ {
+ float pixel = srcData[ptr] * filter[0];
+
+ // Part of the filter that fits within the GrayImage
+ for (int i = 1; i < x + 1; i++)
+ pixel += (srcData[ptr + i] + srcData[ptr - i]) * filter[i];
+
+ // Part of the filter that falls off the left side
+ for (int i = x + 1; i < filter.Length; i++)
+ pixel += (srcData[ptr + i] + srcData[ptr + i]) * filter[i];
+
+ resData[destPtr++] = pixel; ptr++;
+ }
+
+ // Unchecked region
+ for (int x = pad; x < data.Width - pad; x++)
+ {
+ float pixel = srcData[ptr] * filter[0];
+
+ for (int i = 1; i < filter.Length; i++)
+ pixel += (srcData[ptr + i] + srcData[ptr - i]) * filter[i];
+
+ resData[destPtr++] = pixel; ptr++;
+ }
+
+ // Right checked region
+ for (int x = data.Width - pad; x < data.Width; x++)
+ {
+ float pixel = srcData[ptr] * filter[0];
+
+ // Part of the filter that fits within the GrayImage
+ for (int i = 0; i < (data.Width - x); i++)
+ pixel += (srcData[ptr + i] + srcData[ptr - i]) * filter[i];
+
+ // Part of the filter that falls off the right side
+ for (int i = (data.Width - x); i < filter.Length; i++)
+ pixel += (srcData[ptr + i] + srcData[ptr - i]) * filter[i];
+
+ resData[destPtr++] = pixel; ptr++;
+ }
+ }
+
+ #endregion
+
+ }
+
+
+
+ public GrayImage Conv2DSymmetric(GrayImage data, GrayImage opLR)
+ {
+ int xPad = opLR.Width - 1;
+ int yPad = opLR.Height - 1;
+
+ GrayImage padded = new GrayImage(data.Width + 2 * xPad, data.Height + 2 * yPad);
+
+ int dataIdx = 0;
+ for (int y = 0; y < data.Height; y++)
+ {
+ int rowStart = (y + yPad) * (data.Width + 2 * xPad) + xPad;
+ for (int x = 0; x < data.Width; x++)
+ {
+ padded.Scan0[rowStart + x] = data.Scan0[dataIdx];
+ dataIdx++;
+ }
+ }
+
+ return Conv2DSymm(padded, opLR);
+ }
+
+
+ /// <summary>
+ /// Convolves an GrayImage with a 2D-symmetric operator.
+ /// </summary>
+ /// <param name="data">Data to be convolved with the operator</param>
+ /// <param name="opUL">Lower-right quadrant of the operator.</param>
+ /// <returns></returns>
+ private GrayImage Conv2DSymm(GrayImage data, GrayImage opLR)
+ {
+ if (opLR.Width % 2 != 0 || opLR.Height % 2 != 0)
+ throw new ArgumentException("Operator must have an even number of rows and columns.");
+
+ int xPad = opLR.Width - 1;
+ int yPad = opLR.Height - 1;
+
+ GrayImage result = new GrayImage(data.Width - 2 * xPad, data.Height - 2 * yPad);
+
+ for (int y = yPad; y < data.Height - yPad; y++)
+ {
+ for (int x = xPad; x < data.Width - xPad; x++)
+ {
+ // Center pixel
+ float pixel = data[x, y] * opLR.Scan0[0];
+
+ // Vertical center
+ for (int op_y = 1; op_y < opLR.Height; op_y++)
+ pixel += (data[x, y + op_y] + data[x, y - op_y]) * opLR[0, op_y];
+
+ //Horizontal center
+ for (int op_x = 1; op_x < opLR.Width; op_x++)
+ pixel += (data[x + op_x, y] + data[x - op_x, y]) * opLR[op_x, 0];
+
+ //Quadrants
+ int opIdx = 1;
+
+ for (int op_y = 1; op_y < opLR.Height; op_y++)
+ {
+ int baseIdx1 = ((y + op_y) * data.Width) + x;
+ int baseIdx2 = ((y - op_y) * data.Width) + x;
+
+ // Loop unrolling can save 25% execution time here
+
+ for (int op_x = 1; op_x < opLR.Width; op_x++)
+ {
+ pixel += (data.Scan0[baseIdx1 + op_x] +
+ data.Scan0[baseIdx2 + op_x] +
+ data.Scan0[baseIdx1 - op_x] +
+ data.Scan0[baseIdx2 - op_x]) * opLR.Scan0[opIdx];
+
+ opIdx++;
+ }
+
+ opIdx++; // Skip 0th col on next row
+ }
+
+ result[x - xPad, y - yPad] = pixel;
+
+ } // loop over data x
+
+ } // loop over data y
+
+ return result;
+ }
+
+ /// <summary>
+ /// Vanilla 2D convolution. Not optimized.
+ /// </summary>
+ /// <param name="data"></param>
+ /// <param name="op"></param>
+ /// <returns></returns>
+ public GrayImage Conv2D(GrayImage data, GrayImage op)
+ {
+ GrayImage result = new GrayImage(data.Width, data.Height);
+
+ if (op.Width % 2 == 0 || op.Height % 2 == 0)
+ throw new ArgumentException("Operator must have an odd number of rows and columns.");
+
+ int x_offset = op.Width / 2;
+ int y_offset = op.Height / 2;
+
+ for (int y = 0; y < data.Height; y++)
+ {
+ for (int x = 0; x < data.Width; x++)
+ {
+ float pixel = 0;
+ float wt = 0;
+
+ for (int op_y = 0; op_y < op.Height; op_y++)
+ {
+ int d_y = y - y_offset + op_y;
+ if (d_y < 0 || d_y >= data.Height) continue;
+
+ for (int op_x = 0; op_x < op.Width; op_x++)
+ {
+ int d_x = x - x_offset + op_x;
+ if (d_x < 0 || d_x >= data.Width) continue;
+
+ float op_val = op[op_x, op_y];
+
+ /* Perform actual convolution */
+ wt += Math.Abs(op_val);
+ pixel += data[d_x, d_y] * op_val;
+ }
+ }
+
+ result[x, y] = pixel / wt;
+
+ } // loop over data x
+
+ } // loop over data y
+
+ return result;
+ }
+
+ }
+}
diff --git a/debian/missing-sources/plupload/csharp/Plupload/FJCore/Filter/FilterBase.cs b/debian/missing-sources/plupload/csharp/Plupload/FJCore/Filter/FilterBase.cs
new file mode 100644
index 0000000..a3f4b3a
--- /dev/null
+++ b/debian/missing-sources/plupload/csharp/Plupload/FJCore/Filter/FilterBase.cs
@@ -0,0 +1,47 @@
+/// Copyright (c) 2008-09 Jeffrey Powers for Occipital Open Source.
+/// Under the MIT License, details: License.txt.
+
+namespace FluxJpeg.Core.Filtering
+{
+ using System;
+
+ public enum ResamplingFilters
+ {
+ NearestNeighbor,
+ LowpassAntiAlias
+ //Bicubic
+ }
+
+ public class FilterProgressEventArgs : EventArgs { public double Progress; }
+
+ internal abstract class Filter
+ {
+ protected int _newWidth, _newHeight;
+ protected byte[][,] _sourceData, _destinationData;
+ protected bool _color;
+
+ public event EventHandler<FilterProgressEventArgs> ProgressChanged;
+ FilterProgressEventArgs progressArgs = new FilterProgressEventArgs();
+
+ protected void UpdateProgress(double progress)
+ {
+ progressArgs.Progress = progress;
+ if (ProgressChanged != null) ProgressChanged(this, progressArgs);
+ }
+
+ public byte[][,] Apply( byte[][,] imageData, int newWidth, int newHeight )
+ {
+ _newHeight = newHeight;
+ _newWidth = newWidth;
+ _color = !(imageData.Length == 1);
+ _destinationData = Image.CreateRaster(newWidth, newHeight, imageData.Length);
+ _sourceData = imageData;
+
+ ApplyFilter();
+
+ return _destinationData;
+ }
+
+ protected abstract void ApplyFilter();
+ }
+}
diff --git a/debian/missing-sources/plupload/csharp/Plupload/FJCore/Filter/FilterLowpassResize.cs b/debian/missing-sources/plupload/csharp/Plupload/FJCore/Filter/FilterLowpassResize.cs
new file mode 100644
index 0000000..e45004e
--- /dev/null
+++ b/debian/missing-sources/plupload/csharp/Plupload/FJCore/Filter/FilterLowpassResize.cs
@@ -0,0 +1,44 @@
+/// Copyright (c) 2009 Jeffrey Powers for Occipital Open Source.
+/// Under the MIT License, details: License.txt.
+
+namespace FluxJpeg.Core.Filtering
+{
+ using System;
+
+ internal class LowpassResize : Filter
+ {
+ protected override void ApplyFilter()
+ {
+ // get source image size
+ int width = _sourceData[0].GetLength(0),
+ height = _sourceData[0].GetLength(1);
+
+ int channels = _sourceData.Length;
+
+ // Estimate a good filter size for the gaussian.
+ // Note that gaussian isn't an ideal bandpass filter
+ // so this is an experimentally determined quantity
+ double std = (width / _newWidth) * 0.50;
+
+ for(int i = 0; i < channels; i++)
+ {
+ GrayImage channel = new GrayImage(_sourceData[i]);
+
+ channel = Convolution.Instance.GaussianConv(channel, std);
+
+ _sourceData[i] = channel.ToByteArray2D();
+ }
+
+ // number of pixels to shift in the original image
+ double xStep = (double)width / _newWidth,
+ yStep = (double)height / _newHeight;
+
+
+ NNResize resizer = new NNResize();
+
+ _destinationData = resizer.Apply(_sourceData, _newWidth, _newHeight);
+
+
+ }
+ }
+}
diff --git a/debian/missing-sources/plupload/csharp/Plupload/FJCore/Filter/FilterNNResize.cs b/debian/missing-sources/plupload/csharp/Plupload/FJCore/Filter/FilterNNResize.cs
new file mode 100644
index 0000000..44e3ddb
--- /dev/null
+++ b/debian/missing-sources/plupload/csharp/Plupload/FJCore/Filter/FilterNNResize.cs
@@ -0,0 +1,47 @@
+/// Copyright (c) 2008 Jeffrey Powers for Fluxcapacity Open Source.
+/// Under the MIT License, details: License.txt.
+
+namespace FluxJpeg.Core.Filtering
+{
+ using System;
+
+ internal class NNResize : Filter
+ {
+ protected override void ApplyFilter()
+ {
+ // get source image size
+ int width = _sourceData[0].GetLength(0),
+ height = _sourceData[0].GetLength(1);
+
+ // number of pixels to shift in the original image
+ double xStep = (double)width / _newWidth,
+ yStep = (double)height / _newHeight;
+
+ double sX = 0.5*xStep, sY = 0.5*yStep;
+ int i_sY, i_sX;
+
+ for (int y = 0; y < _newHeight; y++)
+ {
+ i_sY = (int)sY; sX = 0;
+
+ UpdateProgress((double)y / _newHeight);
+
+ for (int x = 0; x < _newWidth; x++)
+ {
+ i_sX = (int)sX;
+
+ _destinationData[0][x, y] = _sourceData[0][i_sX, i_sY];
+
+ if (_color) {
+
+ _destinationData[1][x, y] = _sourceData[1][i_sX, i_sY];
+ _destinationData[2][x, y] = _sourceData[2][i_sX, i_sY];
+ }
+
+ sX += xStep;
+ }
+ sY += yStep;
+ }
+ }
+ }
+}
diff --git a/debian/missing-sources/plupload/csharp/Plupload/FJCore/Filter/GrayImage.cs b/debian/missing-sources/plupload/csharp/Plupload/FJCore/Filter/GrayImage.cs
new file mode 100644
index 0000000..0ea84e0
--- /dev/null
+++ b/debian/missing-sources/plupload/csharp/Plupload/FJCore/Filter/GrayImage.cs
@@ -0,0 +1,77 @@
+using System;
+using System.Collections.Generic;
+using System.Text;
+using System.IO;
+using System.Runtime.InteropServices;
+
+namespace FluxJpeg.Core.Filtering
+{
+ public class GrayImage
+ {
+ public float[] Scan0;
+ private int _width;
+ private int _height;
+
+ public int Width { get { return _width; } }
+ public int Height { get { return _height; } }
+
+ /// <summary>
+ /// Returns a new 0.0-initialized image of specified size.
+ /// </summary>
+ /// <param name="width">Width in pixels</param>
+ /// <param name="height">Height in pixels</param>
+ public GrayImage(int width, int height)
+ {
+ _width = width; _height = height;
+ Scan0 = new float[width * height];
+ }
+
+ /// <summary>
+ /// Creates a 0.0 to 1.0 grayscale image from a bitmap.
+ /// </summary>
+ public GrayImage(byte[,] channel)
+ {
+ Convert(channel);
+ }
+
+ /// <summary>
+ /// Access a pixel within the image.
+ /// </summary>
+ /// <param name="x">X-coordinate</param>
+ /// <param name="y">Y-coordinate</param>
+ /// <returns>Pixel brightness between 0.0 and 1.0</returns>
+ public float this[int x, int y]
+ {
+ get { return Scan0[y * _width + x]; }
+ set { Scan0[y * _width + x] = value; }
+ }
+
+ private void Convert(byte[,] channel)
+ {
+ _width = channel.GetLength(0);
+ _height = channel.GetLength(1);
+
+ Scan0 = new float[_width* _height];
+
+ int i = 0;
+
+ for (int y = 0; y < _height; y++)
+ for (int x = 0; x < _width; x++)
+ Scan0[i++] = channel[x, y] / 255f;
+ }
+
+ public byte[,] ToByteArray2D()
+ {
+ byte[,] result = new byte[_width, _height];
+
+ int i = 0;
+ for (int y = 0; y < _height; y++)
+ for (int x = 0; x < _width; x++)
+ result[x, y] = (byte)(Scan0[i++] * 255f);
+
+ return result;
+ }
+
+
+ }
+}
diff --git a/debian/missing-sources/plupload/csharp/Plupload/FJCore/IJG.txt b/debian/missing-sources/plupload/csharp/Plupload/FJCore/IJG.txt
new file mode 100644
index 0000000..08a1ed8
--- /dev/null
+++ b/debian/missing-sources/plupload/csharp/Plupload/FJCore/IJG.txt
@@ -0,0 +1,90 @@
+This software is based in part on the work of the Independent JPEG Group:
+
+The Independent JPEG Group's JPEG software
+==========================================
+
+LEGAL ISSUES
+============
+
+In plain English:
+
+1. We don't promise that this software works. (But if you find any bugs,
+ please let us know!)
+2. You can use this software for whatever you want. You don't have to pay us.
+3. You may not pretend that you wrote this software. If you use it in a
+ program, you must acknowledge somewhere in your documentation that
+ you've used the IJG code.
+
+In legalese:
+
+The authors make NO WARRANTY or representation, either express or implied,
+with respect to this software, its quality, accuracy, merchantability, or
+fitness for a particular purpose. This software is provided "AS IS", and you,
+its user, assume the entire risk as to its quality and accuracy.
+
+This software is copyright (C) 1991-1998, Thomas G. Lane.
+All Rights Reserved except as specified below.
+
+Permission is hereby granted to use, copy, modify, and distribute this
+software (or portions thereof) for any purpose, without fee, subject to these
+conditions:
+(1) If any part of the source code for this software is distributed, then this
+README file must be included, with this copyright and no-warranty notice
+unaltered; and any additions, deletions, or changes to the original files
+must be clearly indicated in accompanying documentation.
+(2) If only executable code is distributed, then the accompanying
+documentation must state that "this software is based in part on the work of
+the Independent JPEG Group".
+(3) Permission for use of this software is granted only if the user accepts
+full responsibility for any undesirable consequences; the authors accept
+NO LIABILITY for damages of any kind.
+
+These conditions apply to any software derived from or based on the IJG code,
+not just to the unmodified library. If you use our work, you ought to
+acknowledge us.
+
+Permission is NOT granted for the use of any IJG author's name or company name
+in advertising or publicity relating to this software or products derived from
+it. This software may be referred to only as "the Independent JPEG Group's
+software".
+
+We specifically permit and encourage the use of this software as the basis of
+commercial products, provided that all warranty or liability claims are
+assumed by the product vendor.
+
+
+ansi2knr.c is included in this distribution by permission of L. Peter Deutsch,
+sole proprietor of its copyright holder, Aladdin Enterprises of Menlo Park, CA.
+ansi2knr.c is NOT covered by the above copyright and conditions, but instead
+by the usual distribution terms of the Free Software Foundation; principally,
+that you must include source code if you redistribute it. (See the file
+ansi2knr.c for full details.) However, since ansi2knr.c is not needed as part
+of any program generated from the IJG code, this does not limit you more than
+the foregoing paragraphs do.
+
+The Unix configuration script "configure" was produced with GNU Autoconf.
+It is copyright by the Free Software Foundation but is freely distributable.
+The same holds for its supporting scripts (config.guess, config.sub,
+ltconfig, ltmain.sh). Another support script, install-sh, is copyright
+by M.I.T. but is also freely distributable.
+
+It appears that the arithmetic coding option of the JPEG spec is covered by
+patents owned by IBM, AT&T, and Mitsubishi. Hence arithmetic coding cannot
+legally be used without obtaining one or more licenses. For this reason,
+support for arithmetic coding has been removed from the free JPEG software.
+(Since arithmetic coding provides only a marginal gain over the unpatented
+Huffman mode, it is unlikely that very many implementations will support it.)
+So far as we are aware, there are no patent restrictions on the remaining
+code.
+
+The IJG distribution formerly included code to read and write GIF files.
+To avoid entanglement with the Unisys LZW patent, GIF reading support has
+been removed altogether, and the GIF writer has been simplified to produce
+"uncompressed GIFs". This technique does not use the LZW algorithm; the
+resulting GIF files are larger than usual, but are readable by all standard
+GIF decoders.
+
+We are required to state that
+ "The Graphics Interchange Format(c) is the Copyright property of
+ CompuServe Incorporated. GIF(sm) is a Service Mark property of
+ CompuServe Incorporated."
diff --git a/debian/missing-sources/plupload/csharp/Plupload/FJCore/IO/BinaryReader.cs b/debian/missing-sources/plupload/csharp/Plupload/FJCore/IO/BinaryReader.cs
new file mode 100644
index 0000000..70a0ee6
--- /dev/null
+++ b/debian/missing-sources/plupload/csharp/Plupload/FJCore/IO/BinaryReader.cs
@@ -0,0 +1,46 @@
+/// Copyright (c) 2008 Jeffrey Powers for Fluxcapacity Open Source.
+/// Under the MIT License, details: License.txt.
+
+using System;
+using System.IO;
+
+namespace FluxJpeg.Core.IO
+{
+ /// <summary>
+ /// Big-endian binary reader
+ /// </summary>
+ internal class BinaryReader
+ {
+ Stream _stream;
+ byte[] _buffer;
+
+ public Stream BaseStream { get { return _stream; } }
+
+ public BinaryReader(byte[] data) : this(new MemoryStream(data)) { }
+
+ public BinaryReader(Stream stream)
+ {
+ _stream = stream;
+ _buffer = new byte[2];
+ }
+
+ public byte ReadByte()
+ {
+ int b = _stream.ReadByte();
+ if (b == -1) throw new EndOfStreamException();
+ return (byte)b;
+ }
+
+ public ushort ReadShort()
+ {
+ _stream.Read(_buffer, 0, 2);
+ return (ushort)((_buffer[0] << 8) | (_buffer[1] & 0xff));
+ }
+
+ public int Read(byte[] buffer, int offset, int count)
+ {
+ return _stream.Read(buffer, offset, count);
+ }
+
+ }
+}
diff --git a/debian/missing-sources/plupload/csharp/Plupload/FJCore/IO/BinaryWriter.cs b/debian/missing-sources/plupload/csharp/Plupload/FJCore/IO/BinaryWriter.cs
new file mode 100644
index 0000000..b9dc969
--- /dev/null
+++ b/debian/missing-sources/plupload/csharp/Plupload/FJCore/IO/BinaryWriter.cs
@@ -0,0 +1,45 @@
+/// Copyright (c) 2008 Jeffrey Powers for Fluxcapacity Open Source.
+/// Under the MIT License, details: License.txt.
+
+using System;
+using System.Text;
+using System.IO;
+
+namespace FluxJpeg.Core.IO
+{
+ /// <summary>
+ /// A Big-endian binary writer.
+ /// </summary>
+ internal class BinaryWriter
+ {
+ private Stream _stream;
+
+ internal BinaryWriter(Stream stream)
+ {
+ _stream = stream;
+ }
+
+ internal void Write(byte[] val)
+ {
+ _stream.Write(val, 0, val.Length);
+ }
+
+ internal void Write(byte[] val, int offset, int count)
+ {
+ _stream.Write(val, offset, count);
+ }
+
+
+ internal void Write(short val)
+ {
+ _stream.WriteByte((byte)(( val >> 8 ) & 0xFF));
+ _stream.WriteByte((byte)(val & 0xFF));
+ }
+
+ internal void Write(byte val)
+ {
+ _stream.WriteByte(val);
+ }
+
+ }
+}
diff --git a/debian/missing-sources/plupload/csharp/Plupload/FJCore/IO/JpegBinaryReader.cs b/debian/missing-sources/plupload/csharp/Plupload/FJCore/IO/JpegBinaryReader.cs
new file mode 100644
index 0000000..759b248
--- /dev/null
+++ b/debian/missing-sources/plupload/csharp/Plupload/FJCore/IO/JpegBinaryReader.cs
@@ -0,0 +1,117 @@
+/// Copyright (c) 2008 Jeffrey Powers for Fluxcapacity Open Source.
+/// Under the MIT License, details: License.txt.
+
+using System;
+using System.IO;
+
+namespace FluxJpeg.Core.IO
+{
+ internal class JPEGMarkerFoundException : Exception
+ {
+ public JPEGMarkerFoundException(byte marker) { this.Marker = marker; }
+ public byte Marker;
+ }
+
+ internal class JPEGBinaryReader : IO.BinaryReader
+ {
+ public int eob_run = 0;
+
+ private byte marker;
+
+ public JPEGBinaryReader(Stream input)
+ : base(input)
+ {
+ }
+
+ /// <summary>
+ /// Seeks through the stream until a marker is found.
+ /// </summary>
+ public byte GetNextMarker()
+ {
+ try { while (true) { ReadJpegByte(); } }
+ catch (JPEGMarkerFoundException ex) {
+ return ex.Marker;
+ }
+ }
+
+ byte _bitBuffer;
+
+ protected int _bitsLeft = 0;
+
+ public int BitOffset
+ {
+ get { return (8 - _bitsLeft) % 8; }
+ set
+ {
+ if (_bitsLeft != 0) BaseStream.Seek(-1, SeekOrigin.Current);
+ _bitsLeft = (8 - value) % 8;
+ }
+ }
+
+ /// <summary>
+ /// Places n bits from the stream, where the most-significant bits
+ /// from the first byte read end up as the most-significant of the returned
+ /// n bits.
+ /// </summary>
+ /// <param name="n">Number of bits to return</param>
+ /// <returns>Integer containing the bits desired -- shifted all the way right.</returns>
+ public int ReadBits(int n)
+ {
+ int result = 0;
+
+ #region Special case -- included for optimization purposes
+ if (_bitsLeft >= n)
+ {
+ _bitsLeft-=n;
+ result = _bitBuffer >> (8 - n);
+ _bitBuffer = (byte)(_bitBuffer << n);
+ return result;
+ }
+ #endregion
+
+ while (n > 0)
+ {
+ if (_bitsLeft == 0)
+ {
+ _bitBuffer = ReadJpegByte();
+ _bitsLeft = 8;
+ }
+
+ int take = n <= _bitsLeft ? n : _bitsLeft;
+
+ result = result | ((_bitBuffer >> 8 - take) << (n - take));
+
+ _bitBuffer = (byte)(_bitBuffer << take);
+
+ _bitsLeft -= take;
+ n -= take;
+ }
+
+ return result;
+ }
+
+ protected byte ReadJpegByte()
+ {
+ byte c = ReadByte();
+
+ /* If it's 0xFF, check and discard stuffed zero byte */
+ if (c == JPEGMarker.XFF)
+ {
+ // Discard padded oxFFs
+ while ((c = ReadByte()) == 0xff) ;
+
+ // ff00 is the escaped form of 0xff
+ if (c == 0) c = 0xff;
+ else
+ {
+ // Otherwise we've found a new marker.
+ marker = c;
+ throw new JPEGMarkerFoundException(marker);
+ }
+ }
+
+ return c;
+ }
+
+ }
+}
diff --git a/debian/missing-sources/plupload/csharp/Plupload/FJCore/Image.cs b/debian/missing-sources/plupload/csharp/Plupload/FJCore/Image.cs
new file mode 100644
index 0000000..d1db8cd
--- /dev/null
+++ b/debian/missing-sources/plupload/csharp/Plupload/FJCore/Image.cs
@@ -0,0 +1,183 @@
+/// Copyright (c) 2008 Jeffrey Powers for Fluxcapacity Open Source.
+/// Under the MIT License, details: License.txt.
+
+using System;
+#if SILVERLIGHT
+#else
+using System.Drawing;
+using System.Drawing.Imaging;
+#endif
+
+namespace FluxJpeg.Core {
+ public struct ColorModel {
+ public ColorSpace colorspace;
+ public bool Opaque;
+ }
+
+ public enum ColorSpace { Gray, YCbCr, RGB }
+
+ public class Image {
+ private ColorModel _cm;
+ private byte[][,] _raster;
+
+ public byte[][,] Raster { get { return _raster; } }
+ public ColorModel ColorModel { get { return _cm; } }
+
+ /// <summary> X density (dots per inch).</summary>
+ public double DensityX { get; set; }
+ /// <summary> Y density (dots per inch).</summary>
+ public double DensityY { get; set; }
+
+ public int ComponentCount { get { return _raster.Length; } }
+
+ /// <summary>
+ /// Converts the colorspace of an image (in-place)
+ /// </summary>
+ /// <param name="cs">Colorspace to convert into</param>
+ /// <returns>Self</returns>
+ public Image ChangeColorSpace(ColorSpace cs) {
+ // Colorspace is already correct
+ if (_cm.colorspace == cs) return this;
+
+ byte[] ycbcr = new byte[3];
+ byte[] rgb = new byte[3];
+
+ if (_cm.colorspace == ColorSpace.RGB && cs == ColorSpace.YCbCr) {
+ /*
+ * Y' = + 0.299 * R'd + 0.587 * G'd + 0.114 * B'd
+ Cb = 128 - 0.168736 * R'd - 0.331264 * G'd + 0.5 * B'd
+ Cr = 128 + 0.5 * R'd - 0.418688 * G'd - 0.081312 * B'd
+ *
+ */
+
+ for (int x = 0; x < width; x++)
+ for (int y = 0; y < height; y++) {
+ YCbCr.fromRGB(ref _raster[0][x, y], ref _raster[1][x, y], ref _raster[2][x, y]);
+ }
+
+ _cm.colorspace = ColorSpace.YCbCr;
+
+
+ } else if (_cm.colorspace == ColorSpace.YCbCr && cs == ColorSpace.RGB) {
+
+ for (int x = 0; x < width; x++)
+ for (int y = 0; y < height; y++) {
+ // 0 is LUMA
+ // 1 is BLUE
+ // 2 is RED
+
+ YCbCr.toRGB(ref _raster[0][x, y], ref _raster[1][x, y], ref _raster[2][x, y]);
+ }
+
+ _cm.colorspace = ColorSpace.RGB;
+ } else if (_cm.colorspace == ColorSpace.Gray && cs == ColorSpace.YCbCr) {
+ // To convert to YCbCr, we just add two 128-filled chroma channels
+
+ byte[,] Cb = new byte[width, height];
+ byte[,] Cr = new byte[width, height];
+
+ for (int x = 0; x < width; x++)
+ for (int y = 0; y < height; y++) {
+ Cb[x, y] = 128; Cr[x, y] = 128;
+ }
+
+ _raster = new byte[][,] { _raster[0], Cb, Cr };
+
+ _cm.colorspace = ColorSpace.YCbCr;
+ } else if (_cm.colorspace == ColorSpace.Gray && cs == ColorSpace.RGB) {
+ ChangeColorSpace(ColorSpace.YCbCr);
+ ChangeColorSpace(ColorSpace.RGB);
+ } else {
+ throw new Exception("Colorspace conversion not supported.");
+ }
+
+ return this;
+ }
+
+ private int width; private int height;
+
+ public int Width { get { return width; } }
+ public int Height { get { return height; } }
+
+ public Image(ColorModel cm, byte[][,] raster) {
+ width = raster[0].GetLength(0);
+ height = raster[0].GetLength(1);
+
+ _cm = cm;
+ _raster = raster;
+ }
+
+ public static byte[][,] CreateRaster(int width, int height, int bands) {
+ // Create the raster
+ byte[][,] raster = new byte[bands][,];
+ for (int b = 0; b < bands; b++)
+ raster[b] = new byte[width, height];
+ return raster;
+ }
+
+ delegate void ConvertColor(ref byte c1, ref byte c2, ref byte c3);
+
+#if SILVERLIGHT
+#else
+ public Bitmap ToBitmap()
+ {
+ ConvertColor ColorConverter;
+
+ switch(_cm.colorspace)
+ {
+ case ColorSpace.YCbCr:
+ ColorConverter = YCbCr.toRGB;
+ break;
+ default:
+ throw new Exception("Colorspace not supported yet.");
+ }
+
+ int _width = width;
+ int _height = height;
+
+ Bitmap bitmap = new Bitmap(_width, _height, PixelFormat.Format32bppArgb);
+
+ BitmapData bmData = bitmap.LockBits(new Rectangle(0, 0, bitmap.Width, bitmap.Height),
+ System.Drawing.Imaging.ImageLockMode.WriteOnly,
+ System.Drawing.Imaging.PixelFormat.Format32bppArgb);
+
+ byte[] outColor = new byte[3];
+ byte[] inColor = new byte[3];
+
+ unsafe
+ {
+ int i = 0;
+
+ byte* ptrBitmap = (byte*)bmData.Scan0;
+
+ for (int y = 0; y < _height; y++)
+ {
+ for (int x = 0; x < _width; x++)
+ {
+ ptrBitmap[0] = (byte)_raster[0][x, y];
+ ptrBitmap[1] = (byte)_raster[1][x, y];
+ ptrBitmap[2] = (byte)_raster[2][x, y];
+
+ ColorConverter(ref ptrBitmap[0], ref ptrBitmap[1], ref ptrBitmap[2]);
+
+ // Swap RGB --> BGR
+ byte R = ptrBitmap[0];
+ ptrBitmap[0] = ptrBitmap[2];
+ ptrBitmap[2] = R;
+
+ ptrBitmap[3] = 255; /* 100% opacity */
+ ptrBitmap += 4; // advance to the next pixel
+ i++; // "
+ }
+ }
+ }
+
+ bitmap.UnlockBits(bmData);
+
+ return bitmap;
+
+ }
+#endif
+
+ }
+}
diff --git a/debian/missing-sources/plupload/csharp/Plupload/FJCore/JAI.txt b/debian/missing-sources/plupload/csharp/Plupload/FJCore/JAI.txt
new file mode 100644
index 0000000..999e4de
--- /dev/null
+++ b/debian/missing-sources/plupload/csharp/Plupload/FJCore/JAI.txt
@@ -0,0 +1,40 @@
+This software is based in part on the Java Advanced Imaging IO by Sun Microsystems.
+
+That software is governed by the following license:
+===================================================
+
+Copyright (c) 2005 Sun Microsystems, Inc. All Rights Reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+
+- Redistribution of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+
+- Redistribution in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in
+ the documentation and/or other materials provided with the
+ distribution.
+
+Neither the name of Sun Microsystems, Inc. or the names of
+contributors may be used to endorse or promote products derived
+from this software without specific prior written permission.
+
+This software is provided "AS IS," without a warranty of any
+kind. ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND
+WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY
+EXCLUDED. SUN MIDROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL
+NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF
+USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS
+DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR
+ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL,
+CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND
+REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR
+INABILITY TO USE THIS SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGES.
+
+You acknowledge that this software is not designed or intended for
+use in the design, construction, operation or maintenance of any
+nuclear facility. \ No newline at end of file
diff --git a/debian/missing-sources/plupload/csharp/Plupload/FJCore/JpegMarker.cs b/debian/missing-sources/plupload/csharp/Plupload/FJCore/JpegMarker.cs
new file mode 100644
index 0000000..2d18b0a
--- /dev/null
+++ b/debian/missing-sources/plupload/csharp/Plupload/FJCore/JpegMarker.cs
@@ -0,0 +1,128 @@
+/// Copyright (c) 2008 Jeffrey Powers for Fluxcapacity Open Source.
+/// Under the MIT License, details: License.txt.
+
+using System;
+
+namespace FluxJpeg.Core
+{
+ internal sealed class JPEGMarker
+ {
+ // JFIF identifiers
+ public const byte JFIF_J = (byte)0x4a;
+ public const byte JFIF_F = (byte)0x46;
+ public const byte JFIF_I = (byte)0x49;
+ public const byte JFIF_X = (byte)0x46;
+
+ // JFIF extension codes
+ public const byte JFXX_JPEG = (byte)0x10;
+ public const byte JFXX_ONE_BPP = (byte)0x11;
+ public const byte JFXX_THREE_BPP = (byte)0x13;
+
+ // Marker prefix. Next byte is a marker, unless ...
+ public const byte XFF = (byte)0xff;
+ // ... marker byte encoding an xff.
+ public const byte X00 = (byte)0x00;
+
+ #region Section Markers
+
+ /// <summary>Huffman Table</summary>
+ public const byte DHT = (byte)0xc4;
+
+ /// <summary>Quantization Table</summary>
+ public const byte DQT = (byte)0xdb;
+
+ /// <summary>Start of Scan</summary>
+ public const byte SOS = (byte)0xda;
+
+ /// <summary>Define Restart Interval</summary>
+ public const byte DRI = (byte)0xdd;
+
+ /// <summary>Comment</summary>
+ public const byte COM = (byte)0xfe;
+
+ /// <summary>Start of Image</summary>
+ public const byte SOI = (byte)0xd8;
+
+ /// <summary>End of Image</summary>
+ public const byte EOI = (byte)0xd9;
+
+ /// <summary>Define Number of Lines</summary>
+ public const byte DNL = (byte)0xdc;
+
+ #endregion
+
+ #region Application Reserved Keywords
+
+ public const byte APP0 = (byte)0xe0;
+ public const byte APP1 = (byte)0xe1;
+ public const byte APP2 = (byte)0xe2;
+ public const byte APP3 = (byte)0xe3;
+ public const byte APP4 = (byte)0xe4;
+ public const byte APP5 = (byte)0xe5;
+ public const byte APP6 = (byte)0xe6;
+ public const byte APP7 = (byte)0xe7;
+ public const byte APP8 = (byte)0xe8;
+ public const byte APP9 = (byte)0xe9;
+ public const byte APP10 = (byte)0xea;
+ public const byte APP11 = (byte)0xeb;
+ public const byte APP12 = (byte)0xec;
+ public const byte APP13 = (byte)0xed;
+ public const byte APP14 = (byte)0xee;
+ public const byte APP15 = (byte)0xef;
+
+ #endregion
+
+ public const byte RST0 = (byte)0xd0;
+ public const byte RST1 = (byte)0xd1;
+ public const byte RST2 = (byte)0xd2;
+ public const byte RST3 = (byte)0xd3;
+ public const byte RST4 = (byte)0xd4;
+ public const byte RST5 = (byte)0xd5;
+ public const byte RST6 = (byte)0xd6;
+ public const byte RST7 = (byte)0xd7;
+
+ #region Start of Frame (SOF)
+
+ /// <summary>Nondifferential Huffman-coding frame (baseline dct)</summary>
+ public const byte SOF0 = (byte)0xc0;
+
+ /// <summary>Nondifferential Huffman-coding frame (extended dct)</summary>
+ public const byte SOF1 = (byte)0xc1;
+
+ /// <summary>Nondifferential Huffman-coding frame (progressive dct)</summary>
+ public const byte SOF2 = (byte)0xc2;
+
+ /// <summary>Nondifferential Huffman-coding frame Lossless (Sequential)</summary>
+ public const byte SOF3 = (byte)0xc3;
+
+ /// <summary>Differential Huffman-coding frame Sequential DCT</summary>
+ public const byte SOF5 = (byte)0xc5;
+
+ /// <summary>Differential Huffman-coding frame Progressive DCT</summary>
+ public const byte SOF6 = (byte)0xc6;
+
+ /// <summary>Differential Huffman-coding frame lossless</summary>
+ public const byte SOF7 = (byte)0xc7;
+
+ /// <summary>Nondifferential Arithmetic-coding frame (extended dct)</summary>
+ public const byte SOF9 = (byte)0xc9;
+
+ /// <summary>Nondifferential Arithmetic-coding frame (progressive dct)</summary>
+ public const byte SOF10 = (byte)0xca;
+
+ /// <summary>Nondifferential Arithmetic-coding frame (lossless)</summary>
+ public const byte SOF11 = (byte)0xcb;
+
+ /// <summary>Differential Arithmetic-coding frame (sequential dct)</summary>
+ public const byte SOF13 = (byte)0xcd;
+
+ /// <summary>Differential Arithmetic-coding frame (progressive dct)</summary>
+ public const byte SOF14 = (byte)0xce;
+
+ /// <summary>Differential Arithmetic-coding frame (lossless)</summary>
+ public const byte SOF15 = (byte)0xcf;
+
+ #endregion
+
+ }
+}
diff --git a/debian/missing-sources/plupload/csharp/Plupload/FJCore/License.txt b/debian/missing-sources/plupload/csharp/Plupload/FJCore/License.txt
new file mode 100644
index 0000000..99cc648
--- /dev/null
+++ b/debian/missing-sources/plupload/csharp/Plupload/FJCore/License.txt
@@ -0,0 +1,24 @@
+Copyright (c) 2008-2009 Occipital Open Source
+
+Partial derivations: See IJG.txt and JAI.txt.
+
+Permission is hereby granted, free of charge, to any person
+obtaining a copy of this software and associated documentation
+files (the "Software"), to deal in the Software without
+restriction, including without limitation the rights to use,
+copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the
+Software is furnished to do so, subject to the following
+conditions:
+
+The above copyright notice and this permission notice shall be
+included in all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+OTHER DEALINGS IN THE SOFTWARE.
diff --git a/debian/missing-sources/plupload/csharp/Plupload/FJCore/README.txt b/debian/missing-sources/plupload/csharp/Plupload/FJCore/README.txt
new file mode 100644
index 0000000..7069e9e
--- /dev/null
+++ b/debian/missing-sources/plupload/csharp/Plupload/FJCore/README.txt
@@ -0,0 +1,30 @@
+FJCore: A Fluxcapacity Open Source Project
+--------------------------------------------------------------------------------------------
+
+Thanks for checking out FJCore, an image library including a pure C# implementation
+of the JPEG baseline and progressive codecs.
+
+Design goals:
+ - No external dependencies (besides a C# compiler and ECMA-standard CIL runtime)
+ - High performance
+ - High image quality
+ - Simple, intuitive usage pattern
+
+With your help, we can make this one of the most readable and efficient libraries
+available to run on any CIL runtime (including the .NET framework, Mono, and Silverlight)!
+
+Try FJCore online: fluxtools.net/emailphotos
+
+More information: fluxcapacity.net/open-source
+
+--------------------------------------------------------------------------------------------
+
+April 7, 2008:
+
+- Initial release.
+
+July 13, 2008:
+
+- Encoder is now included.
+- Silverlight project added (both FJCore and FJCoreWin share source).
+- FJExample, a Silverlight test application, is included. \ No newline at end of file
diff --git a/debian/missing-sources/plupload/csharp/Plupload/FJCore/Resize/ImageResizer.cs b/debian/missing-sources/plupload/csharp/Plupload/FJCore/Resize/ImageResizer.cs
new file mode 100644
index 0000000..3a896b5
--- /dev/null
+++ b/debian/missing-sources/plupload/csharp/Plupload/FJCore/Resize/ImageResizer.cs
@@ -0,0 +1,98 @@
+/// Copyright (c) 2008 Jeffrey Powers for Fluxcapacity Open Source.
+/// Under the MIT License, details: License.txt.
+
+using System;
+using System.Collections.Generic;
+using System.Text;
+using FluxJpeg.Core.Filtering;
+
+namespace FluxJpeg.Core
+{
+ public class ResizeNotNeededException : Exception { }
+ public class ResizeProgressChangedEventArgs : EventArgs { public double Progress; }
+
+ public class ImageResizer
+ {
+ private ResizeProgressChangedEventArgs progress = new ResizeProgressChangedEventArgs();
+ public event EventHandler<ResizeProgressChangedEventArgs> ProgressChanged;
+
+ private Image _input;
+
+ public ImageResizer(Image input)
+ {
+ _input = input;
+ }
+
+ public static bool ResizeNeeded(FluxJpeg.Core.Image image, int maxEdgeLength)
+ {
+ double scale = (image.Width > image.Height) ?
+ (double)maxEdgeLength / image.Width :
+ (double)maxEdgeLength / image.Height;
+
+ return scale < 1.0; // true if we must downscale
+ }
+
+ public Image Resize(int maxEdgeLength, ResamplingFilters technique)
+ {
+ double scale = 0;
+
+ if (_input.Width > _input.Height)
+ scale = (double)maxEdgeLength / _input.Width;
+ else
+ scale = (double)maxEdgeLength / _input.Height;
+
+ if (scale >= 1.0)
+ throw new ResizeNotNeededException();
+ else
+ return Resize(scale, technique);
+ }
+
+ public Image Resize(int maxWidth, int maxHeight, ResamplingFilters technique)
+ {
+ double wFrac = (double)maxWidth / _input.Width;
+ double hFrac = (double)maxHeight / _input.Height;
+ double scale = 0;
+
+ // Make the image as large as possible, while
+ // fitting in the supplied box and
+ // obeying the aspect ratio
+
+ if (wFrac < hFrac) { scale = wFrac; }
+ else { scale = hFrac; }
+
+ if (scale >= 1.0)
+ throw new ResizeNotNeededException();
+ else
+ return Resize(scale, technique);
+ }
+
+ public Image Resize(double scale, ResamplingFilters technique)
+ {
+ int height = (int)(scale * _input.Height);
+ int width = (int)(scale * _input.Width);
+
+ Filter resizeFilter;
+
+ switch (technique)
+ {
+ case ResamplingFilters.NearestNeighbor:
+ resizeFilter = new NNResize();
+ break;
+ case ResamplingFilters.LowpassAntiAlias:
+ resizeFilter = new LowpassResize();
+ break;
+ default:
+ throw new NotSupportedException();
+ }
+
+ return new Image(_input.ColorModel, resizeFilter.Apply(_input.Raster, width, height));
+ }
+
+ void ResizeProgressChanged(object sender, Filtering.FilterProgressEventArgs e)
+ {
+ progress.Progress = e.Progress;
+ if (ProgressChanged != null) ProgressChanged(this, progress);
+ }
+
+ }
+}
diff --git a/debian/missing-sources/plupload/csharp/Plupload/FJCore/YCbCr.cs b/debian/missing-sources/plupload/csharp/Plupload/FJCore/YCbCr.cs
new file mode 100644
index 0000000..3128b36
--- /dev/null
+++ b/debian/missing-sources/plupload/csharp/Plupload/FJCore/YCbCr.cs
@@ -0,0 +1,59 @@
+/// Copyright (c) 2008 Jeffrey Powers for Fluxcapacity Open Source.
+/// Under the MIT License, details: License.txt.
+
+using System;
+
+namespace FluxJpeg.Core
+{
+ internal class YCbCr
+ {
+
+ public static void toRGB(ref byte c1, ref byte c2, ref byte c3)
+ {
+ double dY = (double)c1;
+ double dCb2 = (double)c2 - 128;
+ double dCr2 = (double)c3 - 128;
+
+ double dR = dY + 1.402 * dCr2;
+ double dG = dY - 0.34414 * dCb2 - 0.71414 * dCr2;
+ double dB = dY + 1.772 * dCb2;
+
+ c1 = dR > 255 ? (byte)255 : dR < 0 ? (byte)0 : (byte)dR;
+ c2 = dG > 255 ? (byte)255 : dG < 0 ? (byte)0 : (byte)dG;
+ c3 = dB > 255 ? (byte)255 : dB < 0 ? (byte)0 : (byte)dB;
+ }
+
+ public static void fromRGB(ref byte c1, ref byte c2, ref byte c3)
+ {
+ double dR = (double)c1;
+ double dG = (double)c2;
+ double dB = (double)c3;
+
+ c1 = (byte)(0.299 * dR + 0.587 * dG + 0.114 * dB);
+ c2 = (byte)(-0.16874 * dR - 0.33126 * dG + 0.5 * dB + 128);
+ c3 = (byte)(0.5 * dR - 0.41869 * dG - 0.08131 * dB + 128);
+ }
+
+ ///* RGB to YCbCr range 0-255 */
+ //public static void fromRGB(byte[] rgb, byte[] ycbcr)
+ //{
+ // ycbcr[0] = (byte)((0.299 * (float)rgb[0] + 0.587 * (float)rgb[1] + 0.114 * (float)rgb[2]));
+ // ycbcr[1] = (byte)(128 + (byte)((-0.16874 * (float)rgb[0] - 0.33126 * (float)rgb[1] + 0.5 * (float)rgb[2])));
+ // ycbcr[2] = (byte)(128 + (byte)((0.5 * (float)rgb[0] - 0.41869 * (float)rgb[1] - 0.08131 * (float)rgb[2])));
+ //}
+
+
+ /* RGB to YCbCr range 0-255 */
+ public static float[] fromRGB(float[] data)
+ {
+ float[] dest = new float[3];
+
+ dest[0] = (float)((0.299 * (float)data[0] + 0.587 * (float)data[1] + 0.114 * (float)data[2]));
+ dest[1] = 128 + (float)((-0.16874 * (float)data[0] - 0.33126 * (float)data[1] + 0.5 * (float)data[2]));
+ dest[2] = 128 + (float)((0.5 * (float)data[0] - 0.41869 * (float)data[1] - 0.08131 * (float)data[2]));
+
+ return (dest);
+ }
+ }
+
+} \ No newline at end of file
diff --git a/debian/missing-sources/plupload/csharp/Plupload/FJCore/ZigZag.cs b/debian/missing-sources/plupload/csharp/Plupload/FJCore/ZigZag.cs
new file mode 100644
index 0000000..0dd7ac0
--- /dev/null
+++ b/debian/missing-sources/plupload/csharp/Plupload/FJCore/ZigZag.cs
@@ -0,0 +1,65 @@
+/// Copyright (c) 2008 Jeffrey Powers for Fluxcapacity Open Source.
+/// Under the MIT License, details: License.txt.
+
+namespace FluxJpeg.Core
+{
+ internal class ZigZag
+ {
+
+ #region Alternate Form
+ internal static readonly int[] ZigZagMap =
+ {
+ 0, 1, 8, 16, 9, 2, 3, 10,
+ 17, 24, 32, 25, 18, 11, 4, 5,
+ 12, 19, 26, 33, 40, 48, 41, 34,
+ 27, 20, 13, 6, 7, 14, 21, 28,
+ 35, 42, 49, 56, 57, 50, 43, 36,
+ 29, 22, 15, 23, 30, 37, 44, 51,
+ 58, 59, 52, 45, 38, 31, 39, 46,
+ 53, 60, 61, 54, 47, 55, 62, 63
+ };
+ //public static void UnZigZag(float[] input, float[] output)
+ //{
+ // for (int i = 0; i < 64; i++)
+ // output[ZigZagMap[i] / 8, ZigZagMap[i] % 8] = input[i];
+ //}
+ #endregion
+
+ public static void UnZigZag(float[] input, float[] output)
+ {
+ output[0] = input[0]; output[1] = input[1];
+ output[8] = input[2]; output[16] = input[3];
+ output[9] = input[4]; output[2] = input[5];
+ output[3] = input[6]; output[10] = input[7];
+ output[17] = input[8]; output[24] = input[9];
+ output[32] = input[10]; output[25] = input[11];
+ output[18] = input[12]; output[11] = input[13];
+ output[4] = input[14]; output[5] = input[15];
+ output[12] = input[16]; output[19] = input[17];
+ output[26] = input[18]; output[33] = input[19];
+ output[40] = input[20]; output[48] = input[21];
+ output[41] = input[22]; output[34] = input[23];
+ output[27] = input[24]; output[20] = input[25];
+ output[13] = input[26]; output[6] = input[27];
+ output[7] = input[28]; output[14] = input[29];
+ output[21] = input[30]; output[28] = input[31];
+ output[35] = input[32]; output[42] = input[33];
+ output[49] = input[34]; output[56] = input[35];
+ output[57] = input[36]; output[50] = input[37];
+ output[43] = input[38]; output[36] = input[39];
+ output[29] = input[40]; output[22] = input[41];
+ output[15] = input[42]; output[23] = input[43];
+ output[30] = input[44]; output[37] = input[45];
+ output[44] = input[46]; output[51] = input[47];
+ output[58] = input[48]; output[59] = input[49];
+ output[52] = input[50]; output[45] = input[51];
+ output[38] = input[52]; output[31] = input[53];
+ output[39] = input[54]; output[46] = input[55];
+ output[53] = input[56]; output[60] = input[57];
+ output[61] = input[58]; output[54] = input[59];
+ output[47] = input[60]; output[55] = input[61];
+ output[62] = input[62]; output[63] = input[63];
+ }
+
+ }
+}
diff --git a/debian/missing-sources/plupload/csharp/Plupload/FileReference.cs b/debian/missing-sources/plupload/csharp/Plupload/FileReference.cs
new file mode 100644
index 0000000..4ba86a9
--- /dev/null
+++ b/debian/missing-sources/plupload/csharp/Plupload/FileReference.cs
@@ -0,0 +1,721 @@
+/**
+ * FileReference.cs
+ *
+ * Copyright 2009, Moxiecode Systems AB
+ * Released under GPL License.
+ *
+ * License: http://www.plupload.com/license
+ * Contributing: http://www.plupload.com/contributing
+ */
+
+using System;
+using System.IO;
+using System.Threading;
+using System.Windows.Threading;
+using System.Net;
+using System.Text.RegularExpressions;
+using System.Windows.Browser;
+using System.Windows.Media.Imaging;
+using System.Collections.Generic;
+using FluxJpeg.Core.Encoder;
+using FluxJpeg.Core;
+using Plupload.PngEncoder;
+
+namespace Moxiecode.Plupload {
+ enum ImageType {
+ Jpeg,
+ Png
+ }
+
+ /// <summary>
+ /// Description of File.
+ /// </summary>
+ public class FileReference {
+ #region private fields
+ private string name, uploadUrl, id, targetName, mimeType;
+ private FileInfo info;
+ private SynchronizationContext syncContext;
+ private int chunks, chunkSize;
+ private bool multipart, chunking;
+ private long size, chunk;
+ private string fileDataName;
+ private Dictionary<string, object> multipartParams;
+ private Dictionary<string, object> headers;
+ private Stream fileStream;
+ private Stream imageStream;
+ private HttpWebRequest req;
+ #endregion
+
+ /// <summary>Upload complete delegate.</summary>
+ public delegate void UploadCompleteHandler(object sender, UploadEventArgs e);
+
+ /// <summary>Upload chunk compleate delegate.</summary>
+ public delegate void UploadChunkCompleteHandler(object sender, UploadEventArgs e);
+
+ /// <summary>Upload error delegate.</summary>
+ public delegate void ErrorHandler(object sender, ErrorEventArgs e);
+
+ /// <summary>Upload progress delegate.</summary>
+ public delegate void ProgressHandler(object sender, ProgressEventArgs e);
+
+ /// <summary>Upload complete event</summary>
+ public event UploadCompleteHandler UploadComplete;
+
+ /// <summary>Upload chunk complete event</summary>
+ public event UploadChunkCompleteHandler UploadChunkComplete;
+
+ /// <summary>Error event</summary>
+ public event ErrorHandler Error;
+
+ /// <summary>Progress event</summary>
+ public event ProgressHandler Progress;
+
+ /// <summary>
+ /// Main constructor for the file reference.
+ /// </summary>
+ /// <param name="id">Unique file id for item.</param>
+ /// <param name="info">FileInfo that got returned from a file selection.</param>
+ public FileReference(string id, FileInfo info) {
+ this.id = id;
+ this.name = info.Name;
+ this.info = info;
+ this.size = info.Length;
+ }
+
+ /// <summary>Unique id for the file reference.</summary>
+ public string Id {
+ get { return id; }
+ }
+
+ /// <summary>File name to use with upload.</summary>
+ public string Name {
+ get { return name; }
+ set { name = value; }
+ }
+
+ /// <summary>File size for the selected file.</summary>
+ public long Size {
+ get { return this.size; }
+ }
+
+ /// <summary>
+ /// Uploads the file to the specific url and using the specified chunk_size.
+ /// </summary>
+ /// <param name="upload_url">URL to upload to.</param>
+ /// <param name="chunk_size">Chunk size to use.</param>
+ /// <param name="image_width">Image width to scale to.</param>
+ /// <param name="image_height">Image height to scale to.</param>
+ /// <param name="image_quality">Image quality to store as.</param>
+ public void Upload(string upload_url, string json_settings) {
+ int chunkSize = 0, imageWidth = 0, imageHeight = 0, imageQuality = 90;
+
+ Dictionary<string, object> settings = (Dictionary<string, object>) Moxiecode.Plupload.Utils.JsonReader.ParseJson(json_settings);
+
+ chunkSize = Convert.ToInt32(settings["chunk_size"]);
+ imageWidth = Convert.ToInt32(settings["image_width"]);
+ imageHeight = Convert.ToInt32(settings["image_height"]);
+ imageQuality = Convert.ToInt32(settings["image_quality"]);
+
+ this.fileDataName = (string)settings["file_data_name"];
+ this.multipart = Convert.ToBoolean(settings["multipart"]);
+ this.multipartParams = (Dictionary<string, object>)settings["multipart_params"];
+ this.headers = (Dictionary<string, object>)settings["headers"];
+ this.targetName = (string) settings["name"];
+ this.mimeType = (string) settings["mime"];
+
+ this.chunk = 0;
+ this.chunking = chunkSize > 0;
+
+ this.uploadUrl = upload_url;
+
+ try {
+ // Is jpeg and image size is defined
+ if (Regex.IsMatch(this.name, @"\.(jpeg|jpg|png)$", RegexOptions.IgnoreCase) && (imageWidth != 0 || imageHeight != 0 || imageQuality != 0))
+ {
+ if (Regex.IsMatch(this.name, @"\.png$"))
+ this.imageStream = this.ResizeImage(this.info.OpenRead(), imageWidth, imageHeight, imageQuality, ImageType.Png);
+ else
+ this.imageStream = this.ResizeImage(this.info.OpenRead(), imageWidth, imageHeight, imageQuality, ImageType.Jpeg);
+
+ this.imageStream.Seek(0, SeekOrigin.Begin);
+ this.size = this.imageStream.Length;
+ }
+ } catch (Exception ex) {
+ syncContext.Send(delegate {
+ this.OnIOError(new ErrorEventArgs(ex.Message, 0, this.chunks));
+ }, this);
+ }
+
+ if (this.chunking) {
+ this.chunkSize = chunkSize;
+ this.chunks = (int) Math.Ceiling((double) this.Size / (double) chunkSize);
+ } else {
+ this.chunkSize = (int) this.Size;
+ this.chunks = 1;
+ }
+
+ this.UploadNextChunk();
+ }
+
+ private int ReadByteRange(byte[] buffer, long position, int offset, int count) {
+ int bytes = -1;
+
+ // Read from image memory stream if it's defined
+ if (this.imageStream != null) {
+ this.imageStream.Seek(position, SeekOrigin.Begin);
+ return this.imageStream.Read(buffer, offset, count);
+ }
+
+ // Open the file and read the specified part of it
+ if (this.fileStream == null) {
+ this.fileStream = this.info.OpenRead();
+ }
+
+ bytes = this.fileStream.Read(buffer, offset, count);
+
+ return bytes;
+ }
+
+ /// <summary>
+ /// Uploads the next chunk if there are more in queue.
+ /// </summary>
+ /// <returns>True/false if there are more chunks to be uploaded.</returns>
+ public bool UploadNextChunk() {
+ string url = this.uploadUrl;
+
+ // Is there more chunks
+ if (this.chunk >= this.chunks)
+ return false;
+
+ this.syncContext = SynchronizationContext.Current;
+
+ // Add name, chunk and chunks to query string when we don't use multipart
+ if (!this.multipart) {
+ if (url.IndexOf('?') == -1) {
+ url += '?';
+ } else {
+ url += '&';
+ }
+
+ url += "name=" + Uri.EscapeDataString(this.targetName);
+
+ if (this.chunking) {
+ url += "&chunk=" + this.chunk;
+ url += "&chunks=" + this.chunks;
+ }
+ }
+
+ this.req = WebRequest.Create(new Uri(HtmlPage.Document.DocumentUri, url)) as HttpWebRequest;
+ this.req.Method = "POST";
+
+ // Add custom headers
+ if (this.headers != null) {
+ foreach (string key in this.headers.Keys) {
+ if (this.headers[key] == null)
+ continue;
+
+ switch (key.ToLower())
+ {
+ // in silverlight 3, these are set by the web browser that hosts the Silverlight application.
+ // http://msdn.microsoft.com/en-us/library/system.net.httpwebrequest%28v=vs.95%29.aspx
+ case "connection":
+ case "content-length":
+ case "expect":
+ case "if-modified-since":
+ case "referer":
+ case "transfer-encoding":
+ case "user-agent":
+ break;
+
+ // in silverlight this isn't supported, can not find reference to why not
+ case "range":
+ break;
+
+ // in .NET Framework 3.5 and below, these are set by the system.
+ // http://msdn.microsoft.com/en-us/library/system.net.httpwebrequest%28v=VS.90%29.aspx
+ case "date":
+ case "host":
+ break;
+
+ case "accept":
+ this.req.Accept = (string)this.headers[key];
+ break;
+
+ case "content-type":
+ this.req.ContentType = (string)this.headers[key];
+ break;
+ default:
+ this.req.Headers[key] = (string)this.headers[key];
+ break;
+ }
+ }
+ }
+
+ IAsyncResult asyncResult = this.req.BeginGetRequestStream(new AsyncCallback(RequestStreamCallback), this.req);
+
+ return true;
+ }
+
+ /// <summary>
+ /// Cancels uploading the current file.
+ /// </summary>
+ public void CancelUpload() {
+ if (this.req != null) {
+ this.req.Abort();
+ this.req = null;
+ DisposeStreams();
+ }
+ }
+
+ #region protected methods
+
+ protected virtual void OnUploadComplete(UploadEventArgs e) {
+ DisposeStreams();
+
+ if (UploadComplete != null)
+ UploadComplete(this, e);
+ }
+
+ protected virtual void OnUploadChunkComplete(UploadEventArgs e) {
+ if (UploadChunkComplete != null)
+ UploadChunkComplete(this, e);
+ }
+
+ protected virtual void OnIOError(ErrorEventArgs e) {
+ DisposeStreams();
+
+ if (Error != null)
+ Error(this, e);
+ }
+
+ protected virtual void OnProgress(ProgressEventArgs e) {
+ if (Progress != null)
+ Progress(this, e);
+ }
+
+ #endregion
+
+ #region private methods
+
+ private void RequestStreamCallback(IAsyncResult ar) {
+ HttpWebRequest request = (HttpWebRequest) ar.AsyncState;
+ string boundary = "----pluploadboundary" + DateTime.Now.Ticks, dashdash = "--", crlf = "\r\n";
+ Stream requestStream = null;
+ byte[] buffer = new byte[1048576], strBuff;
+ int bytes;
+ long loaded = 0, end = 0;
+ int percent, lastPercent = 0;
+
+ try {
+ requestStream = request.EndGetRequestStream(ar);
+
+ if (this.multipart) {
+ request.ContentType = "multipart/form-data; boundary=" + boundary;
+
+ // Add name to multipart array
+ this.multipartParams["name"] = this.targetName;
+
+ // Add chunking when needed
+ if (this.chunking) {
+ this.multipartParams["chunk"] = this.chunk;
+ this.multipartParams["chunks"] = this.chunks;
+ }
+
+ // Append mutlipart parameters
+ foreach (KeyValuePair<string, object> pair in this.multipartParams) {
+ strBuff = this.StrToByteArray(dashdash + boundary + crlf +
+ "Content-Disposition: form-data; name=\"" + pair.Key + '"' + crlf + crlf +
+ pair.Value + crlf
+ );
+
+ requestStream.Write(strBuff, 0, strBuff.Length);
+ }
+
+ // Append multipart file header
+ strBuff = this.StrToByteArray(
+ dashdash + boundary + crlf +
+ "Content-Disposition: form-data; name=\"" + this.fileDataName + "\"; filename=\"" + this.name + '"' +
+ crlf + "Content-Type: " + this.mimeType + crlf + crlf
+ );
+
+ requestStream.Write(strBuff, 0, strBuff.Length);
+ } else {
+ request.ContentType = "application/octet-stream";
+ }
+
+ // Move to start
+ loaded = this.chunk * this.chunkSize;
+
+ // Find end
+ end = (this.chunk + 1) * this.chunkSize;
+ if (end > this.Size)
+ end = this.Size;
+
+ while (loaded < end && (bytes = ReadByteRange(buffer, loaded, 0, (int)(end - loaded < buffer.Length ? end - loaded : buffer.Length))) != 0) {
+ loaded += bytes;
+ percent = (int) Math.Round((double) loaded / (double) this.Size * 100.0);
+
+ if (percent > lastPercent) {
+ syncContext.Post(delegate {
+ if (percent > lastPercent) {
+ this.OnProgress(new ProgressEventArgs(loaded, this.Size));
+ lastPercent = percent;
+ }
+ }, this);
+ }
+
+ requestStream.Write(buffer, 0, bytes);
+ requestStream.Flush();
+ }
+
+ // Append multipart file footer
+ if (this.multipart) {
+ strBuff = this.StrToByteArray(crlf + dashdash + boundary + dashdash + crlf);
+ requestStream.Write(strBuff, 0, strBuff.Length);
+ }
+ } catch (Exception ex) {
+ syncContext.Send(delegate {
+ this.OnIOError(new ErrorEventArgs(ex.Message, this.chunk, this.chunks));
+ }, this);
+ } finally {
+ try {
+ if (requestStream != null) {
+ requestStream.Close();
+ requestStream.Dispose();
+ requestStream = null;
+ }
+ } catch (Exception ex) {
+ syncContext.Send(delegate {
+ this.OnIOError(new ErrorEventArgs(ex.Message, this.chunk, this.chunks));
+ }, this);
+ }
+ }
+
+ try {
+ request.BeginGetResponse(new AsyncCallback(ResponseCallback), request);
+ }
+ catch (WebException ex)
+ {
+ if (ex.Status != WebExceptionStatus.RequestCanceled) {
+ syncContext.Send(delegate {
+ this.OnIOError(new ErrorEventArgs(ex.Message, this.chunk, this.chunks));
+ }, this);
+ }
+ }
+ catch (Exception ex) {
+ syncContext.Send(delegate {
+ this.OnIOError(new ErrorEventArgs(ex.Message, this.chunk, this.chunks));
+ }, this);
+ }
+ }
+
+ private void ResponseCallback(IAsyncResult ar) {
+ try
+ {
+ HttpWebRequest request = ar.AsyncState as HttpWebRequest;
+
+ WebResponse response = request.EndGetResponse(ar);
+
+ syncContext.Post(ExtractResponse, response);
+ }
+ catch (WebException ex) {
+ if (ex.Status != WebExceptionStatus.RequestCanceled) {
+ syncContext.Send(delegate {
+ this.OnIOError(new ErrorEventArgs(ex.Message, this.chunk, this.chunks));
+ }, this);
+ }
+ }
+ catch (Exception ex) {
+ syncContext.Send(delegate {
+ this.OnIOError(new ErrorEventArgs(ex.Message, this.chunk, this.chunks));
+ }, this);
+ }
+ }
+
+ private void ExtractResponse(object state) {
+ HttpWebResponse response = state as HttpWebResponse;
+ StreamReader respReader = null;
+ Stream respStream = null;
+ string content;
+
+ try {
+ respStream = response.GetResponseStream();
+
+ if (response.StatusCode == HttpStatusCode.OK) {
+ respReader = new StreamReader(respStream);
+
+ if (respStream != null) {
+ content = respReader.ReadToEnd();
+ } else
+ throw new Exception("Error could not open response stream.");
+ } else
+ throw new Exception("Error server returned status: " + ((int) response.StatusCode) + " " + response.StatusDescription);
+
+ this.chunk++;
+
+ syncContext.Send(delegate {
+ this.OnUploadChunkComplete(new UploadEventArgs(content, this.chunk - 1, this.chunks));
+ }, this);
+ } catch (Exception ex) {
+ syncContext.Send(delegate {
+ this.OnIOError(new ErrorEventArgs(ex.Message, chunk, chunks));
+ }, this);
+ } finally {
+ if (respStream != null)
+ respStream.Close();
+
+ if (respReader != null)
+ respReader.Close();
+
+ response.Close();
+ }
+ }
+
+ private void DisposeStreams() {
+ if (fileStream != null) {
+ fileStream.Dispose();
+ fileStream = null;
+ }
+
+ if (imageStream != null) {
+ imageStream.Dispose();
+ imageStream = null;
+ }
+ }
+
+ private void Debug(string msg) {
+ ((ScriptObject) HtmlPage.Window.Eval("console")).Invoke("log", new string[] {msg});
+ }
+
+ private Stream ResizeImage(Stream image_stream, int width, int height, int quality, ImageType type) {
+ try {
+ // Load the image as a writeablebitmap
+ WriteableBitmap writableBitmap;
+ BitmapImage bitmapImage = new BitmapImage();
+ bitmapImage.SetSource(image_stream);
+ writableBitmap = new WriteableBitmap(bitmapImage);
+
+ if (width == 0) {
+ width = writableBitmap.PixelWidth;
+ }
+
+ if (height == 0) {
+ height = writableBitmap.PixelHeight;
+ }
+
+ double scale = Math.Min((double) width / writableBitmap.PixelWidth, (double) height / writableBitmap.PixelHeight);
+
+ // No resize needed
+ if (scale >= 1.0 && (quality == 0 || type != ImageType.Jpeg))
+ return image_stream;
+
+ if (quality == 0) {
+ quality = 90;
+ }
+
+ // Setup shorter names and pixelbuffers
+ int w = writableBitmap.PixelWidth;
+ int h = writableBitmap.PixelHeight;
+ int[] p = writableBitmap.Pixels;
+ byte[][,] imageRaster = new byte[3][,]; // RGB colors
+ imageRaster[0] = new byte[w, h];
+ imageRaster[1] = new byte[w, h];
+ imageRaster[2] = new byte[w, h];
+
+ // Copy WriteableBitmap data into buffer for FluxJpeg
+ int i = 0;
+ for (int y = 0; y < h; y++) {
+ for (int x = 0; x < w; x++) {
+ int color = p[i++];
+
+ imageRaster[0][x, y] = (byte) (color >> 16); // R
+ imageRaster[1][x, y] = (byte) (color >> 8); // G
+ imageRaster[2][x, y] = (byte) (color); // B
+ }
+ }
+
+ // Create new FluxJpeg image based on pixel data
+ Image jpegImage = new Image(new ColorModel {
+ colorspace = ColorSpace.RGB
+ }, imageRaster);
+
+ ImageResizer resizer = new ImageResizer(jpegImage);
+ Image resizedImage;
+
+ if (scale < 1.0) {
+ // Calc new proportional size
+ width = (int) Math.Round(writableBitmap.PixelWidth * scale);
+ height = (int) Math.Round(writableBitmap.PixelHeight * scale);
+
+ // Resize the image
+ resizedImage = resizer.Resize(width, height, FluxJpeg.Core.Filtering.ResamplingFilters.LowpassAntiAlias);
+ } else {
+ resizedImage = jpegImage;
+ }
+
+ Stream imageStream = new MemoryStream();
+
+ if (type == ImageType.Jpeg) {
+ // Encode the resized image as Jpeg
+ JpegEncoder jpegEncoder = new JpegEncoder(resizedImage, quality, imageStream);
+ jpegEncoder.Encode();
+ } else {
+ int[] pixelBuffer = new int[resizedImage.Height * resizedImage.Width];
+ byte[][,] resizedRaster = resizedImage.Raster;
+
+ // Convert FJCore raster to PixelBuffer
+ for (int y = 0; y < resizedImage.Height; y++) {
+ for (int x = 0; x < resizedImage.Width; x++) {
+ int color = 0;
+
+ color = color | resizedRaster[0][x, y] << 16; // R
+ color = color | resizedRaster[1][x, y] << 8; // G
+ color = color | resizedRaster[2][x, y]; // B
+
+ pixelBuffer[(y * resizedImage.Width) + x] = color;
+ }
+ }
+
+ // Encode the resized image as Png
+ PngEncoder pngEncoder = new PngEncoder(pixelBuffer, resizedImage.Width, resizedImage.Height, false, PngEncoder.FILTER_NONE, Deflater.BEST_COMPRESSION);
+ byte[] pngBuffer = pngEncoder.pngEncode();
+ imageStream.Write(pngBuffer, 0, pngBuffer.Length);
+ }
+
+ return imageStream;
+ } catch {
+ // Ignore the error and let the server resize the image
+ }
+
+ return image_stream;
+ }
+
+ private byte[] StrToByteArray(string str) {
+ System.Text.UTF8Encoding encoding = new System.Text.UTF8Encoding();
+
+ return encoding.GetBytes(str);
+ }
+
+ #endregion
+ }
+
+ /// <summary>
+ /// Upload event arguments class.
+ /// </summary>
+ public class UploadEventArgs : EventArgs {
+ #region private fields
+ private string response;
+ private long chunk;
+ private int chunks;
+ #endregion
+
+ /// <summary>
+ /// Main constructor for the upload event.
+ /// </summary>
+ /// <param name="response">Response contents as a string.</param>
+ public UploadEventArgs(string response) : this(response, 0, 0) {
+ }
+
+ /// <summary>
+ /// Main constructor for the upload event.
+ /// </summary>
+ /// <param name="response">Response contents as a string.</param>
+ /// <param name="chunk">Current chunk number.</param>
+ /// <param name="chunks">Total chunks.</param>
+ public UploadEventArgs(string response, long chunk, int chunks) {
+ this.response = response;
+ this.chunk = chunk;
+ this.chunks = chunks;
+ }
+
+ /// <summary>Response from upload request.</summary>
+ public string Response {
+ get { return response; }
+ }
+
+ /// <summary>Chunk number.</summary>
+ public long Chunk {
+ get { return chunk; }
+ }
+
+ /// <summary>Total number of chunks.</summary>
+ public int Chunks {
+ get { return chunks; }
+ }
+ }
+
+ /// <summary>
+ /// Error event arguments class.
+ /// </summary>
+ public class ErrorEventArgs : EventArgs {
+ #region private fields
+ private string message;
+ private long chunk;
+ private int chunks;
+ #endregion
+
+ /// <summary>
+ /// Main constructor for the error event.
+ /// </summary>
+ /// <param name="message">Error message.</param>
+ public ErrorEventArgs(string message) : this(message, 0, 0) {
+ this.message = message;
+ }
+
+ /// <summary>
+ /// Main constructor for the error event.
+ /// </summary>
+ /// <param name="message">Error message.</param>
+ /// <param name="chunk">Current chunk number.</param>
+ /// <param name="chunks">Total chunks.</param>
+ public ErrorEventArgs(string message, long chunk, int chunks) {
+ this.message = message;
+ this.chunk = chunk;
+ this.chunks = chunks;
+ }
+
+ /// <summary>Chunk number.</summary>
+ public long Chunk {
+ get { return chunk; }
+ }
+
+ /// <summary>Total number of chunks.</summary>
+ public int Chunks {
+ get { return chunks; }
+ }
+
+ /// <summary>Error message.</summary>
+ public string Message {
+ get { return message; }
+ }
+ }
+
+ /// <summary>
+ /// Progress event arguments class.
+ /// </summary>
+ public class ProgressEventArgs : EventArgs {
+ #region private fields
+ private long loaded, total;
+ #endregion
+
+ /// <summary>
+ /// Main constructor for the progress events args.
+ /// </summary>
+ /// <param name="loaded">Number of bytes uploaded.</param>
+ /// <param name="total">Total bytes to upload.</param>
+ public ProgressEventArgs(long loaded, long total) {
+ this.loaded = loaded;
+ this.total = total;
+ }
+
+ /// <summary>Total bytes to upload.</summary>
+ public long Total {
+ get { return total; }
+ }
+
+ /// <summary>Number of bytes upload so far.</summary>
+ public long Loaded {
+ get { return loaded; }
+ }
+ }
+}
diff --git a/debian/missing-sources/plupload/csharp/Plupload/Page.xaml b/debian/missing-sources/plupload/csharp/Plupload/Page.xaml
new file mode 100644
index 0000000..6236e84
--- /dev/null
+++ b/debian/missing-sources/plupload/csharp/Plupload/Page.xaml
@@ -0,0 +1,7 @@
+<UserControl
+ xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
+ xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
+ x:Class="Moxiecode.Plupload.Page"
+ Width="1024" Height="1024" Background="Transparent" Cursor="Hand">
+ <Canvas Background="Transparent"></Canvas>
+</UserControl> \ No newline at end of file
diff --git a/debian/missing-sources/plupload/csharp/Plupload/Page.xaml.cs b/debian/missing-sources/plupload/csharp/Plupload/Page.xaml.cs
new file mode 100644
index 0000000..66bfeef
--- /dev/null
+++ b/debian/missing-sources/plupload/csharp/Plupload/Page.xaml.cs
@@ -0,0 +1,230 @@
+/**
+ * Page.xaml.cs
+ *
+ * Copyright 2009, Moxiecode Systems AB
+ * Released under GPL License.
+ *
+ * License: http://www.plupload.com/license
+ * Contributing: http://www.plupload.com/contributing
+ */
+
+using System;
+using System.Windows;
+using System.Windows.Controls;
+using System.Windows.Documents;
+using System.Windows.Ink;
+using System.Windows.Input;
+using System.Windows.Media;
+using System.Windows.Media.Animation;
+using System.Windows.Shapes;
+using System.Windows.Browser;
+using System.Net;
+using System.IO;
+using System.Collections.Generic;
+using System.Threading;
+using Moxiecode.Plupload;
+
+namespace Moxiecode.Plupload {
+ /// <summary>
+ /// Partial page class for the Silverlight page.
+ /// </summary>
+ public partial class Page : UserControl {
+ #region private fields
+ private Dictionary<string, FileReference> files;
+ private int idCount = 0;
+ private FileReference currentFile;
+ private string id, filter;
+ private bool multiselect;
+ private bool disabled = false;
+ #endregion
+
+ /// <summary>
+ /// Main constructor.
+ /// </summary>
+ /// <param name="init_params">Silverlight init params.</param>
+ public Page(IDictionary<string, string> init_params) {
+ InitializeComponent();
+
+ HtmlPage.RegisterScriptableObject("Upload", this);
+
+ this.files = new Dictionary<string, FileReference>();
+ this.id = init_params["id"];
+ this.filter = init_params["filter"];
+ this.multiselect = Convert.ToBoolean(init_params["multiselect"]);
+
+ this.FireEvent("Init");
+ this.MouseLeftButtonUp += new MouseButtonEventHandler(OnClick);
+
+ this.MouseLeftButtonDown += new MouseButtonEventHandler(OnMouseLeftButtonDown);
+ this.MouseEnter += new MouseEventHandler(OnMouseEnter);
+ this.MouseLeave += new MouseEventHandler(OnMouseLeave);
+ }
+
+ private void OnClick(object sender, MouseEventArgs e) {
+ if (this.disabled) {
+ return;
+ }
+
+ OpenFileDialog dlg = new OpenFileDialog();
+
+ this.FireEvent("StartSelectFiles");
+
+ try {
+ dlg.Multiselect = this.multiselect;
+ dlg.Filter = this.filter;
+
+ if ((bool) dlg.ShowDialog()) {
+ foreach (FileInfo file in dlg.Files) {
+ FileReference uploadFile = new FileReference("u" + this.idCount++, file);
+
+ uploadFile.UploadChunkComplete += delegate(object up_sender, UploadEventArgs args) {
+ FileReference evtFile = (FileReference) up_sender;
+
+ this.FireEvent("UploadChunkSuccessful", evtFile.Id, args.Chunk, args.Chunks, args.Response);
+ };
+
+ uploadFile.UploadComplete += delegate(object up_sender, UploadEventArgs args) {
+ FileReference evtFile = (FileReference) up_sender;
+
+ this.FireEvent("UploadSuccessful", evtFile.Id, args.Response);
+ };
+
+ uploadFile.Error += delegate(object up_sender, ErrorEventArgs args) {
+ FileReference evtFile = (FileReference) up_sender;
+
+ this.FireEvent("UploadChunkError", evtFile.Id, args.Chunk, args.Chunks, args.Message);
+ };
+
+ uploadFile.Progress += delegate(object up_sender, ProgressEventArgs args) {
+ FileReference evtFile = (FileReference) up_sender;
+
+ this.FireEvent("UploadFileProgress", evtFile.Id, args.Loaded, args.Total);
+ };
+
+ this.FireEvent("SelectFile", uploadFile.Id, uploadFile.Name, uploadFile.Size);
+ this.files[uploadFile.Id] = uploadFile;
+ }
+
+ this.FireEvent("SelectSuccessful");
+ } else
+ this.FireEvent("SelectCancelled");
+ } catch (Exception ex) {
+ this.FireEvent("SelectError", ex.Message);
+ }
+ }
+
+
+ private void OnMouseLeftButtonDown(object sender, MouseEventArgs e) {
+ this.FireEvent("MouseLeftButtonDown");
+ }
+
+ private void OnMouseEnter(object sender, MouseEventArgs e) {
+ this.FireEvent("MouseEnter");
+ }
+
+ private void OnMouseLeave(object sender, MouseEventArgs e) {
+ this.FireEvent("MouseLeave");
+ }
+
+ /// <summary>
+ /// Reference to page level plupload.silverlight script object.
+ /// </summary>
+ public ScriptObject PluploadScriptObject {
+ get { return ((ScriptObject) HtmlPage.Window.Eval("plupload.silverlight")); }
+ }
+
+ /// <summary>
+ /// Fires a specific event to the page level multi upload script.
+ /// </summary>
+ /// <param name="name">Event name to fire.</param>
+ public void FireEvent(string name) {
+ this.PluploadScriptObject.Invoke("trigger", new string[] { this.id, name });
+ }
+
+ /// <summary>
+ /// Fires a specific event to the page level multi upload script.
+ /// </summary>
+ /// <param name="name">Event name to fire.</param>
+ /// <param name="paramlist">Numerous parameters to send.</param>
+ public void FireEvent(string name, params object[] paramlist) {
+ List<object> args = new List<object>(paramlist);
+
+ args.Insert(0, name);
+ args.Insert(0, this.id);
+
+ this.PluploadScriptObject.Invoke("trigger", args.ToArray());
+ }
+
+ [ScriptableMember]
+ /// <summary>
+ /// Uploads a specific file by id to the specific url and using a chunks.
+ /// </summary>
+ /// <param name="id">File id to upload.</param>
+ /// <param name="upload_url">Url to upload to.</param>
+ /// <param name="chunk_size">Chunk size to use.</param>
+ public void UploadFile(string id, string upload_url, string json_settings) {
+ if (this.files.ContainsKey(id)) {
+ FileReference file = this.files[id];
+
+ this.currentFile = file;
+ file.Upload(upload_url, json_settings);
+ }
+ }
+
+ [ScriptableMember]
+ /// <summary>
+ /// Removes the specified file by id.
+ /// </summary>
+ /// <param name="id">File id to remove.</param>
+ public void RemoveFile(string id) {
+ if (this.files.ContainsKey(id))
+ this.files[id] = null;
+ }
+
+ [ScriptableMember]
+ /// <summary>
+ /// Clears all files.
+ /// </summary>
+ public void ClearFiles() {
+ this.files = new Dictionary<string, FileReference>();
+ }
+
+ [ScriptableMember]
+ /// <summary>
+ /// Uploads the next chunk of the current file. Returns true/false if there is more chunks.
+ /// </summary>
+ /// <return>true/false if there is more chunks</return>
+ public bool UploadNextChunk() {
+ if (this.currentFile != null)
+ return this.currentFile.UploadNextChunk();
+
+ return false;
+ }
+
+ [ScriptableMember]
+ /// <summary>
+ /// Cancel upload.
+ /// </summary>
+ public void CancelUpload() {
+ if (this.currentFile != null)
+ this.currentFile.CancelUpload();
+ }
+
+ [ScriptableMember]
+ /// <summary>
+ /// Disable dialog trigger.
+ /// </summary>
+ public void DisableBrowse(bool disabled = true)
+ {
+ this.disabled = disabled;
+ }
+
+ /// <summary>
+ /// Send debug message to firebug console.
+ /// </summary>
+ /// <param name="msg">Message to write.</param>
+ private void Debug(string msg) {
+ ((ScriptObject) HtmlPage.Window.Eval("console")).Invoke("log", new string[] { msg });
+ }
+ }
+}
diff --git a/debian/missing-sources/plupload/csharp/Plupload/Plupload.csproj b/debian/missing-sources/plupload/csharp/Plupload/Plupload.csproj
new file mode 100644
index 0000000..b40f00f
--- /dev/null
+++ b/debian/missing-sources/plupload/csharp/Plupload/Plupload.csproj
@@ -0,0 +1,222 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project ToolsVersion="4.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <PropertyGroup Condition="'$(MSBuildToolsVersion)' == '3.5'">
+ <TargetFrameworkVersion>v3.5</TargetFrameworkVersion>
+ </PropertyGroup>
+ <PropertyGroup>
+ <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
+ <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
+ <DefaultClrNameSpace>Plupload</DefaultClrNameSpace>
+ <AssemblyName>plupload.silverlight</AssemblyName>
+ <RootNamespace>Moxiecode.Plupload</RootNamespace>
+ <AlwaysCompileMarkupFilesInSeparateDomain>false</AlwaysCompileMarkupFilesInSeparateDomain>
+ <ExpressionBlendCreationVersion>2.1.1535.0</ExpressionBlendCreationVersion>
+ <ProjectGuid>{95F0DEE8-DE7A-46C5-9DCC-0570B0FC4643}</ProjectGuid>
+ <OutputType>Library</OutputType>
+ <NoStdLib>true</NoStdLib>
+ <TargetFrameworkVersion>v4.0</TargetFrameworkVersion>
+ <StartPageUrl>Default.html</StartPageUrl>
+ <XapOutputs>true</XapOutputs>
+ <XapFilename>plupload.silverlight.xap</XapFilename>
+ <GenerateSilverlightManifest>true</GenerateSilverlightManifest>
+ <SilverlightManifestTemplate>Properties\AppManifest.xml</SilverlightManifestTemplate>
+ <SilverlightAppEntry>Moxiecode.Plupload.App</SilverlightAppEntry>
+ <CreateTestPage>true</CreateTestPage>
+ <TestPageFileName>Default.html</TestPageFileName>
+ <DefineConstants>SILVERLIGHT</DefineConstants>
+ <SilverlightApplication>true</SilverlightApplication>
+ <SourceAnalysisOverrideSettingsFile>C:\Users\spocke\AppData\Roaming\ICSharpCode/SharpDevelop3.0\Settings.SourceAnalysis</SourceAnalysisOverrideSettingsFile>
+ <RunPostBuildEvent>OnBuildSuccess</RunPostBuildEvent>
+ <AllowUnsafeBlocks>False</AllowUnsafeBlocks>
+ <TreatWarningsAsErrors>false</TreatWarningsAsErrors>
+ <FileUpgradeFlags>
+ </FileUpgradeFlags>
+ <UpgradeBackupLocation>
+ </UpgradeBackupLocation>
+ <OldToolsVersion>3.5</OldToolsVersion>
+ <TargetFrameworkIdentifier>Silverlight</TargetFrameworkIdentifier>
+ <SilverlightVersion>$(TargetFrameworkVersion)</SilverlightVersion>
+ <IsWebBootstrapper>false</IsWebBootstrapper>
+ <PublishUrl>publish\</PublishUrl>
+ <Install>true</Install>
+ <InstallFrom>Disk</InstallFrom>
+ <UpdateEnabled>false</UpdateEnabled>
+ <UpdateMode>Foreground</UpdateMode>
+ <UpdateInterval>7</UpdateInterval>
+ <UpdateIntervalUnits>Days</UpdateIntervalUnits>
+ <UpdatePeriodically>false</UpdatePeriodically>
+ <UpdateRequired>false</UpdateRequired>
+ <MapFileExtensions>true</MapFileExtensions>
+ <ApplicationRevision>0</ApplicationRevision>
+ <ApplicationVersion>1.0.0.%2a</ApplicationVersion>
+ <UseApplicationTrust>false</UseApplicationTrust>
+ <BootstrapperEnabled>true</BootstrapperEnabled>
+ <UsePlatformExtensions>true</UsePlatformExtensions>
+ </PropertyGroup>
+ <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
+ <DebugSymbols>true</DebugSymbols>
+ <DebugType>full</DebugType>
+ <Optimize>false</Optimize>
+ <OutputPath>bin\Debug\</OutputPath>
+ <DefineConstants>TRACE;DEBUG;SILVERLIGHT</DefineConstants>
+ <ErrorReport>prompt</ErrorReport>
+ <WarningLevel>4</WarningLevel>
+ </PropertyGroup>
+ <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
+ <DebugType>PdbOnly</DebugType>
+ <Optimize>true</Optimize>
+ <OutputPath>bin\</OutputPath>
+ <DefineConstants>SILVERLIGHT</DefineConstants>
+ <ErrorReport>prompt</ErrorReport>
+ <WarningLevel>4</WarningLevel>
+ <DebugSymbols>false</DebugSymbols>
+ </PropertyGroup>
+ <PropertyGroup Condition=" '$(Configuration)' == 'Release' ">
+ <CheckForOverflowUnderflow>False</CheckForOverflowUnderflow>
+ </PropertyGroup>
+ <PropertyGroup Condition=" '$(Platform)' == 'AnyCPU' ">
+ <RegisterForComInterop>False</RegisterForComInterop>
+ <GenerateSerializationAssemblies>Auto</GenerateSerializationAssemblies>
+ <BaseAddress>4194304</BaseAddress>
+ <PlatformTarget>AnyCPU</PlatformTarget>
+ <FileAlignment>4096</FileAlignment>
+ </PropertyGroup>
+ <ItemGroup>
+ <Reference Include="mscorlib" />
+ <Reference Include="System" />
+ <Reference Include="System.Core" />
+ <Reference Include="System.Net" />
+ <Reference Include="System.Windows" />
+ <Reference Include="System.Windows.Browser" />
+ <Reference Include="System.Xml" />
+ <ApplicationDefinition Include="App.xaml">
+ <Generator>MSBuild:Compile</Generator>
+ <SubType>Designer</SubType>
+ <Generator>MSBuild:Compile</Generator>
+ <SubType>Designer</SubType>
+ </ApplicationDefinition>
+ <Compile Include="App.xaml.cs">
+ <DependentUpon>App.xaml</DependentUpon>
+ </Compile>
+ <Compile Include="FJCore\DCT.cs">
+ <SubType>Code</SubType>
+ </Compile>
+ <Compile Include="FJCore\DecodedJpeg.cs">
+ <SubType>Code</SubType>
+ </Compile>
+ <Compile Include="FJCore\Decoder\HuffmanTable.cs">
+ <SubType>Code</SubType>
+ </Compile>
+ <Compile Include="FJCore\Decoder\JpegHuffmanTable.cs">
+ <SubType>Code</SubType>
+ </Compile>
+ <Compile Include="FJCore\Decoder\JpegQuantizationTable.cs">
+ <SubType>Code</SubType>
+ </Compile>
+ <Compile Include="FJCore\Encoder\JpegEncoder.cs">
+ <SubType>Code</SubType>
+ </Compile>
+ <Compile Include="FJCore\FDCT.cs">
+ <SubType>Code</SubType>
+ </Compile>
+ <Compile Include="FJCore\Filter\Convolution.cs">
+ <SubType>Code</SubType>
+ </Compile>
+ <Compile Include="FJCore\Filter\FilterBase.cs">
+ <SubType>Code</SubType>
+ </Compile>
+ <Compile Include="FJCore\Filter\FilterLowpassResize.cs">
+ <SubType>Code</SubType>
+ </Compile>
+ <Compile Include="FJCore\Filter\FilterNNResize.cs">
+ <SubType>Code</SubType>
+ </Compile>
+ <Compile Include="FJCore\Filter\GrayImage.cs">
+ <SubType>Code</SubType>
+ </Compile>
+ <Compile Include="FJCore\Image.cs">
+ <SubType>Code</SubType>
+ </Compile>
+ <Compile Include="FJCore\IO\BinaryWriter.cs">
+ <SubType>Code</SubType>
+ </Compile>
+ <Compile Include="FJCore\JpegMarker.cs">
+ <SubType>Code</SubType>
+ </Compile>
+ <Compile Include="FJCore\Resize\ImageResizer.cs">
+ <SubType>Code</SubType>
+ </Compile>
+ <Compile Include="FJCore\YCbCr.cs">
+ <SubType>Code</SubType>
+ </Compile>
+ <Compile Include="FJCore\ZigZag.cs">
+ <SubType>Code</SubType>
+ </Compile>
+ <Compile Include="Page.xaml.cs">
+ <DependentUpon>Page.xaml</DependentUpon>
+ </Compile>
+ <Compile Include="PngEncoder\Adler32.cs" />
+ <Compile Include="PngEncoder\CRC32.cs" />
+ <Compile Include="PngEncoder\Deflater.cs" />
+ <Compile Include="PngEncoder\DeflaterConstants.cs" />
+ <Compile Include="PngEncoder\DeflaterEngine.cs" />
+ <Compile Include="PngEncoder\DeflaterHuffman.cs" />
+ <Compile Include="PngEncoder\DeflaterOutputStream.cs" />
+ <Compile Include="PngEncoder\DeflaterPending.cs" />
+ <Compile Include="PngEncoder\IChecksum.cs" />
+ <Compile Include="PngEncoder\PngEncoder.cs" />
+ <Compile Include="PngEncoder\PendingBuffer.cs" />
+ <Compile Include="Properties\AssemblyInfo.cs" />
+ <Page Include="Page.xaml">
+ <Generator>MSBuild:Compile</Generator>
+ <SubType>Designer</SubType>
+ <Generator>MSBuild:Compile</Generator>
+ <SubType>Designer</SubType>
+ </Page>
+ <None Include="Properties\AppManifest.xml" />
+ </ItemGroup>
+ <ItemGroup>
+ <Compile Include="FileReference.cs" />
+ <Compile Include="Utils\JsonReader.cs" />
+ </ItemGroup>
+ <ItemGroup>
+ <BootstrapperPackage Include="Microsoft.Net.Client.3.5">
+ <Visible>False</Visible>
+ <ProductName>.NET Framework 3.5 SP1 Client Profile</ProductName>
+ <Install>false</Install>
+ </BootstrapperPackage>
+ <BootstrapperPackage Include="Microsoft.Net.Framework.3.5.SP1">
+ <Visible>False</Visible>
+ <ProductName>.NET Framework 3.5 SP1</ProductName>
+ <Install>true</Install>
+ </BootstrapperPackage>
+ <BootstrapperPackage Include="Microsoft.VisualBasic.PowerPacks.10.0">
+ <Visible>False</Visible>
+ <ProductName>Microsoft Visual Basic PowerPacks 10.0</ProductName>
+ <Install>true</Install>
+ </BootstrapperPackage>
+ <BootstrapperPackage Include="Microsoft.Windows.Installer.3.1">
+ <Visible>False</Visible>
+ <ProductName>Windows Installer 3.1</ProductName>
+ <Install>true</Install>
+ </BootstrapperPackage>
+ </ItemGroup>
+ <ItemGroup />
+ <ItemGroup>
+ <Content Include="FJCore\IJG.txt" />
+ <Content Include="FJCore\JAI.txt" />
+ <Content Include="FJCore\License.txt" />
+ <Content Include="FJCore\README.txt" />
+ </ItemGroup>
+ <Import Project="$(MSBuildExtensionsPath32)\Microsoft\Silverlight\$(SilverlightVersion)\Microsoft.Silverlight.CSharp.targets" />
+ <PropertyGroup>
+ <PostBuildEvent>copy /Y plupload.silverlight.xap ..\..\..\..\js\plupload.silverlight.xap</PostBuildEvent>
+ </PropertyGroup>
+ <ProjectExtensions>
+ <VisualStudio>
+ <FlavorProperties GUID="{A1591282-1198-4647-A2B1-27E5FF5F6F3B}">
+ <SilverlightProjectProperties />
+ </FlavorProperties>
+ </VisualStudio>
+ </ProjectExtensions>
+</Project>
diff --git a/debian/missing-sources/plupload/csharp/Plupload/Plupload.sln b/debian/missing-sources/plupload/csharp/Plupload/Plupload.sln
new file mode 100644
index 0000000..47a792e
--- /dev/null
+++ b/debian/missing-sources/plupload/csharp/Plupload/Plupload.sln
@@ -0,0 +1,20 @@
+
+Microsoft Visual Studio Solution File, Format Version 11.00
+# Visual Studio 2010
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Plupload", "Plupload.csproj", "{95F0DEE8-DE7A-46C5-9DCC-0570B0FC4643}"
+EndProject
+Global
+ GlobalSection(SolutionConfigurationPlatforms) = preSolution
+ Debug|Any CPU = Debug|Any CPU
+ Release|Any CPU = Release|Any CPU
+ EndGlobalSection
+ GlobalSection(ProjectConfigurationPlatforms) = postSolution
+ {95F0DEE8-DE7A-46C5-9DCC-0570B0FC4643}.Debug|Any CPU.ActiveCfg = Release|Any CPU
+ {95F0DEE8-DE7A-46C5-9DCC-0570B0FC4643}.Debug|Any CPU.Build.0 = Release|Any CPU
+ {95F0DEE8-DE7A-46C5-9DCC-0570B0FC4643}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {95F0DEE8-DE7A-46C5-9DCC-0570B0FC4643}.Release|Any CPU.Build.0 = Release|Any CPU
+ EndGlobalSection
+ GlobalSection(SolutionProperties) = preSolution
+ HideSolutionNode = FALSE
+ EndGlobalSection
+EndGlobal
diff --git a/debian/missing-sources/plupload/csharp/Plupload/PngEncoder/Adler32.cs b/debian/missing-sources/plupload/csharp/Plupload/PngEncoder/Adler32.cs
new file mode 100644
index 0000000..febc82e
--- /dev/null
+++ b/debian/missing-sources/plupload/csharp/Plupload/PngEncoder/Adler32.cs
@@ -0,0 +1,216 @@
+// Adler32.cs - Computes Adler32 data checksum of a data stream
+// Copyright (C) 2001 Mike Krueger
+//
+// This file was translated from java, it was part of the GNU Classpath
+// Copyright (C) 1999, 2000, 2001 Free Software Foundation, Inc.
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+//
+// Linking this library statically or dynamically with other modules is
+// making a combined work based on this library. Thus, the terms and
+// conditions of the GNU General Public License cover the whole
+// combination.
+//
+// As a special exception, the copyright holders of this library give you
+// permission to link this library with independent modules to produce an
+// executable, regardless of the license terms of these independent
+// modules, and to copy and distribute the resulting executable under
+// terms of your choice, provided that you also meet, for each linked
+// independent module, the terms and conditions of the license of that
+// module. An independent module is a module which is not derived from
+// or based on this library. If you modify this library, you may extend
+// this exception to your version of the library, but you are not
+// obligated to do so. If you do not wish to do so, delete this
+// exception statement from your version.
+
+using System;
+
+namespace Plupload.PngEncoder {
+
+ /// <summary>
+ /// Computes Adler32 checksum for a stream of data. An Adler32
+ /// checksum is not as reliable as a CRC32 checksum, but a lot faster to
+ /// compute.
+ ///
+ /// The specification for Adler32 may be found in RFC 1950.
+ /// ZLIB Compressed Data Format Specification version 3.3)
+ ///
+ ///
+ /// From that document:
+ ///
+ /// "ADLER32 (Adler-32 checksum)
+ /// This contains a checksum value of the uncompressed data
+ /// (excluding any dictionary data) computed according to Adler-32
+ /// algorithm. This algorithm is a 32-bit extension and improvement
+ /// of the Fletcher algorithm, used in the ITU-T X.224 / ISO 8073
+ /// standard.
+ ///
+ /// Adler-32 is composed of two sums accumulated per byte: s1 is
+ /// the sum of all bytes, s2 is the sum of all s1 values. Both sums
+ /// are done modulo 65521. s1 is initialized to 1, s2 to zero. The
+ /// Adler-32 checksum is stored as s2*65536 + s1 in most-
+ /// significant-byte first (network) order."
+ ///
+ /// "8.2. The Adler-32 algorithm
+ ///
+ /// The Adler-32 algorithm is much faster than the CRC32 algorithm yet
+ /// still provides an extremely low probability of undetected errors.
+ ///
+ /// The modulo on unsigned long accumulators can be delayed for 5552
+ /// bytes, so the modulo operation time is negligible. If the bytes
+ /// are a, b, c, the second sum is 3a + 2b + c + 3, and so is position
+ /// and order sensitive, unlike the first sum, which is just a
+ /// checksum. That 65521 is prime is important to avoid a possible
+ /// large class of two-byte errors that leave the check unchanged.
+ /// (The Fletcher checksum uses 255, which is not prime and which also
+ /// makes the Fletcher check insensitive to single byte changes 0 -
+ /// 255.)
+ ///
+ /// The sum s1 is initialized to 1 instead of zero to make the length
+ /// of the sequence part of s2, so that the length does not have to be
+ /// checked separately. (Any sequence of zeroes has a Fletcher
+ /// checksum of zero.)"
+ /// </summary>
+ /// <see cref="ICSharpCode.SharpZipLib.Zip.Compression.Streams.InflaterInputStream"/>
+ /// <see cref="ICSharpCode.SharpZipLib.Zip.Compression.Streams.DeflaterOutputStream"/>
+ public sealed class Adler32 : IChecksum {
+ /// <summary>
+ /// largest prime smaller than 65536
+ /// </summary>
+ const uint BASE = 65521;
+
+ /// <summary>
+ /// Returns the Adler32 data checksum computed so far.
+ /// </summary>
+ public long Value {
+ get {
+ return checksum;
+ }
+ }
+
+ /// <summary>
+ /// Creates a new instance of the Adler32 class.
+ /// The checksum starts off with a value of 1.
+ /// </summary>
+ public Adler32() {
+ Reset();
+ }
+
+ /// <summary>
+ /// Resets the Adler32 checksum to the initial value.
+ /// </summary>
+ public void Reset() {
+ checksum = 1;
+ }
+
+ /// <summary>
+ /// Updates the checksum with a byte value.
+ /// </summary>
+ /// <param name="value">
+ /// The data value to add. The high byte of the int is ignored.
+ /// </param>
+ public void Update(int value) {
+ // We could make a length 1 byte array and call update again, but I
+ // would rather not have that overhead
+ uint s1 = checksum & 0xFFFF;
+ uint s2 = checksum >> 16;
+
+ s1 = (s1 + ((uint) value & 0xFF)) % BASE;
+ s2 = (s1 + s2) % BASE;
+
+ checksum = (s2 << 16) + s1;
+ }
+
+ /// <summary>
+ /// Updates the checksum with an array of bytes.
+ /// </summary>
+ /// <param name="buffer">
+ /// The source of the data to update with.
+ /// </param>
+ public void Update(byte[] buffer) {
+ if (buffer == null) {
+ throw new ArgumentNullException("buffer");
+ }
+
+ Update(buffer, 0, buffer.Length);
+ }
+
+ /// <summary>
+ /// Updates the checksum with the bytes taken from the array.
+ /// </summary>
+ /// <param name="buffer">
+ /// an array of bytes
+ /// </param>
+ /// <param name="offset">
+ /// the start of the data used for this update
+ /// </param>
+ /// <param name="count">
+ /// the number of bytes to use for this update
+ /// </param>
+ public void Update(byte[] buffer, int offset, int count) {
+ if (buffer == null) {
+ throw new ArgumentNullException("buffer");
+ }
+
+ if (offset < 0) {
+
+ throw new ArgumentOutOfRangeException("offset");
+
+ }
+
+ if (count < 0) {
+
+ throw new ArgumentOutOfRangeException("count");
+
+ }
+
+ if (offset >= buffer.Length) {
+ throw new ArgumentOutOfRangeException("offset");
+
+ }
+
+ if (offset + count > buffer.Length) {
+ throw new ArgumentOutOfRangeException("count");
+ }
+
+ //(By Per Bothner)
+ uint s1 = checksum & 0xFFFF;
+ uint s2 = checksum >> 16;
+
+ while (count > 0) {
+ // We can defer the modulo operation:
+ // s1 maximally grows from 65521 to 65521 + 255 * 3800
+ // s2 maximally grows by 3800 * median(s1) = 2090079800 < 2^31
+ int n = 3800;
+ if (n > count) {
+ n = count;
+ }
+ count -= n;
+ while (--n >= 0) {
+ s1 = s1 + (uint) (buffer[offset++] & 0xff);
+ s2 = s2 + s1;
+ }
+ s1 %= BASE;
+ s2 %= BASE;
+ }
+
+ checksum = (s2 << 16) | s1;
+ }
+
+ #region Instance Fields
+ uint checksum;
+ #endregion
+ }
+}
diff --git a/debian/missing-sources/plupload/csharp/Plupload/PngEncoder/CRC32.cs b/debian/missing-sources/plupload/csharp/Plupload/PngEncoder/CRC32.cs
new file mode 100644
index 0000000..685fc57
--- /dev/null
+++ b/debian/missing-sources/plupload/csharp/Plupload/PngEncoder/CRC32.cs
@@ -0,0 +1,213 @@
+// CRC32.cs - Computes CRC32 data checksum of a data stream
+// Copyright (C) 2001 Mike Krueger
+//
+// This file was translated from java, it was part of the GNU Classpath
+// Copyright (C) 1999, 2000, 2001 Free Software Foundation, Inc.
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+//
+// Linking this library statically or dynamically with other modules is
+// making a combined work based on this library. Thus, the terms and
+// conditions of the GNU General Public License cover the whole
+// combination.
+//
+// As a special exception, the copyright holders of this library give you
+// permission to link this library with independent modules to produce an
+// executable, regardless of the license terms of these independent
+// modules, and to copy and distribute the resulting executable under
+// terms of your choice, provided that you also meet, for each linked
+// independent module, the terms and conditions of the license of that
+// module. An independent module is a module which is not derived from
+// or based on this library. If you modify this library, you may extend
+// this exception to your version of the library, but you are not
+// obligated to do so. If you do not wish to do so, delete this
+// exception statement from your version.
+
+using System;
+
+namespace Plupload.PngEncoder {
+
+ /// <summary>
+ /// Generate a table for a byte-wise 32-bit CRC calculation on the polynomial:
+ /// x^32+x^26+x^23+x^22+x^16+x^12+x^11+x^10+x^8+x^7+x^5+x^4+x^2+x+1.
+ ///
+ /// Polynomials over GF(2) are represented in binary, one bit per coefficient,
+ /// with the lowest powers in the most significant bit. Then adding polynomials
+ /// is just exclusive-or, and multiplying a polynomial by x is a right shift by
+ /// one. If we call the above polynomial p, and represent a byte as the
+ /// polynomial q, also with the lowest power in the most significant bit (so the
+ /// byte 0xb1 is the polynomial x^7+x^3+x+1), then the CRC is (q*x^32) mod p,
+ /// where a mod b means the remainder after dividing a by b.
+ ///
+ /// This calculation is done using the shift-register method of multiplying and
+ /// taking the remainder. The register is initialized to zero, and for each
+ /// incoming bit, x^32 is added mod p to the register if the bit is a one (where
+ /// x^32 mod p is p+x^32 = x^26+...+1), and the register is multiplied mod p by
+ /// x (which is shifting right by one and adding x^32 mod p if the bit shifted
+ /// out is a one). We start with the highest power (least significant bit) of
+ /// q and repeat for all eight bits of q.
+ ///
+ /// The table is simply the CRC of all possible eight bit values. This is all
+ /// the information needed to generate CRC's on data a byte at a time for all
+ /// combinations of CRC register values and incoming bytes.
+ /// </summary>
+ public sealed class Crc32 : IChecksum {
+ const uint CrcSeed = 0xFFFFFFFF;
+
+ readonly static uint[] CrcTable = new uint[] {
+ 0x00000000, 0x77073096, 0xEE0E612C, 0x990951BA, 0x076DC419,
+ 0x706AF48F, 0xE963A535, 0x9E6495A3, 0x0EDB8832, 0x79DCB8A4,
+ 0xE0D5E91E, 0x97D2D988, 0x09B64C2B, 0x7EB17CBD, 0xE7B82D07,
+ 0x90BF1D91, 0x1DB71064, 0x6AB020F2, 0xF3B97148, 0x84BE41DE,
+ 0x1ADAD47D, 0x6DDDE4EB, 0xF4D4B551, 0x83D385C7, 0x136C9856,
+ 0x646BA8C0, 0xFD62F97A, 0x8A65C9EC, 0x14015C4F, 0x63066CD9,
+ 0xFA0F3D63, 0x8D080DF5, 0x3B6E20C8, 0x4C69105E, 0xD56041E4,
+ 0xA2677172, 0x3C03E4D1, 0x4B04D447, 0xD20D85FD, 0xA50AB56B,
+ 0x35B5A8FA, 0x42B2986C, 0xDBBBC9D6, 0xACBCF940, 0x32D86CE3,
+ 0x45DF5C75, 0xDCD60DCF, 0xABD13D59, 0x26D930AC, 0x51DE003A,
+ 0xC8D75180, 0xBFD06116, 0x21B4F4B5, 0x56B3C423, 0xCFBA9599,
+ 0xB8BDA50F, 0x2802B89E, 0x5F058808, 0xC60CD9B2, 0xB10BE924,
+ 0x2F6F7C87, 0x58684C11, 0xC1611DAB, 0xB6662D3D, 0x76DC4190,
+ 0x01DB7106, 0x98D220BC, 0xEFD5102A, 0x71B18589, 0x06B6B51F,
+ 0x9FBFE4A5, 0xE8B8D433, 0x7807C9A2, 0x0F00F934, 0x9609A88E,
+ 0xE10E9818, 0x7F6A0DBB, 0x086D3D2D, 0x91646C97, 0xE6635C01,
+ 0x6B6B51F4, 0x1C6C6162, 0x856530D8, 0xF262004E, 0x6C0695ED,
+ 0x1B01A57B, 0x8208F4C1, 0xF50FC457, 0x65B0D9C6, 0x12B7E950,
+ 0x8BBEB8EA, 0xFCB9887C, 0x62DD1DDF, 0x15DA2D49, 0x8CD37CF3,
+ 0xFBD44C65, 0x4DB26158, 0x3AB551CE, 0xA3BC0074, 0xD4BB30E2,
+ 0x4ADFA541, 0x3DD895D7, 0xA4D1C46D, 0xD3D6F4FB, 0x4369E96A,
+ 0x346ED9FC, 0xAD678846, 0xDA60B8D0, 0x44042D73, 0x33031DE5,
+ 0xAA0A4C5F, 0xDD0D7CC9, 0x5005713C, 0x270241AA, 0xBE0B1010,
+ 0xC90C2086, 0x5768B525, 0x206F85B3, 0xB966D409, 0xCE61E49F,
+ 0x5EDEF90E, 0x29D9C998, 0xB0D09822, 0xC7D7A8B4, 0x59B33D17,
+ 0x2EB40D81, 0xB7BD5C3B, 0xC0BA6CAD, 0xEDB88320, 0x9ABFB3B6,
+ 0x03B6E20C, 0x74B1D29A, 0xEAD54739, 0x9DD277AF, 0x04DB2615,
+ 0x73DC1683, 0xE3630B12, 0x94643B84, 0x0D6D6A3E, 0x7A6A5AA8,
+ 0xE40ECF0B, 0x9309FF9D, 0x0A00AE27, 0x7D079EB1, 0xF00F9344,
+ 0x8708A3D2, 0x1E01F268, 0x6906C2FE, 0xF762575D, 0x806567CB,
+ 0x196C3671, 0x6E6B06E7, 0xFED41B76, 0x89D32BE0, 0x10DA7A5A,
+ 0x67DD4ACC, 0xF9B9DF6F, 0x8EBEEFF9, 0x17B7BE43, 0x60B08ED5,
+ 0xD6D6A3E8, 0xA1D1937E, 0x38D8C2C4, 0x4FDFF252, 0xD1BB67F1,
+ 0xA6BC5767, 0x3FB506DD, 0x48B2364B, 0xD80D2BDA, 0xAF0A1B4C,
+ 0x36034AF6, 0x41047A60, 0xDF60EFC3, 0xA867DF55, 0x316E8EEF,
+ 0x4669BE79, 0xCB61B38C, 0xBC66831A, 0x256FD2A0, 0x5268E236,
+ 0xCC0C7795, 0xBB0B4703, 0x220216B9, 0x5505262F, 0xC5BA3BBE,
+ 0xB2BD0B28, 0x2BB45A92, 0x5CB36A04, 0xC2D7FFA7, 0xB5D0CF31,
+ 0x2CD99E8B, 0x5BDEAE1D, 0x9B64C2B0, 0xEC63F226, 0x756AA39C,
+ 0x026D930A, 0x9C0906A9, 0xEB0E363F, 0x72076785, 0x05005713,
+ 0x95BF4A82, 0xE2B87A14, 0x7BB12BAE, 0x0CB61B38, 0x92D28E9B,
+ 0xE5D5BE0D, 0x7CDCEFB7, 0x0BDBDF21, 0x86D3D2D4, 0xF1D4E242,
+ 0x68DDB3F8, 0x1FDA836E, 0x81BE16CD, 0xF6B9265B, 0x6FB077E1,
+ 0x18B74777, 0x88085AE6, 0xFF0F6A70, 0x66063BCA, 0x11010B5C,
+ 0x8F659EFF, 0xF862AE69, 0x616BFFD3, 0x166CCF45, 0xA00AE278,
+ 0xD70DD2EE, 0x4E048354, 0x3903B3C2, 0xA7672661, 0xD06016F7,
+ 0x4969474D, 0x3E6E77DB, 0xAED16A4A, 0xD9D65ADC, 0x40DF0B66,
+ 0x37D83BF0, 0xA9BCAE53, 0xDEBB9EC5, 0x47B2CF7F, 0x30B5FFE9,
+ 0xBDBDF21C, 0xCABAC28A, 0x53B39330, 0x24B4A3A6, 0xBAD03605,
+ 0xCDD70693, 0x54DE5729, 0x23D967BF, 0xB3667A2E, 0xC4614AB8,
+ 0x5D681B02, 0x2A6F2B94, 0xB40BBE37, 0xC30C8EA1, 0x5A05DF1B,
+ 0x2D02EF8D
+ };
+
+ internal static uint ComputeCrc32(uint oldCrc, byte value) {
+ return (uint) (Crc32.CrcTable[(oldCrc ^ value) & 0xFF] ^ (oldCrc >> 8));
+ }
+
+ /// <summary>
+ /// The crc data checksum so far.
+ /// </summary>
+ uint crc;
+
+ /// <summary>
+ /// Returns the CRC32 data checksum computed so far.
+ /// </summary>
+ public long Value {
+ get {
+ return (long) crc;
+ }
+ set {
+ crc = (uint) value;
+ }
+ }
+
+ /// <summary>
+ /// Resets the CRC32 data checksum as if no update was ever called.
+ /// </summary>
+ public void Reset() {
+ crc = 0;
+ }
+
+ /// <summary>
+ /// Updates the checksum with the int bval.
+ /// </summary>
+ /// <param name = "value">
+ /// the byte is taken as the lower 8 bits of value
+ /// </param>
+ public void Update(int value) {
+ crc ^= CrcSeed;
+ crc = CrcTable[(crc ^ value) & 0xFF] ^ (crc >> 8);
+ crc ^= CrcSeed;
+ }
+
+ /// <summary>
+ /// Updates the checksum with the bytes taken from the array.
+ /// </summary>
+ /// <param name="buffer">
+ /// buffer an array of bytes
+ /// </param>
+ public void Update(byte[] buffer) {
+ if (buffer == null) {
+ throw new ArgumentNullException("buffer");
+ }
+
+ Update(buffer, 0, buffer.Length);
+ }
+
+ /// <summary>
+ /// Adds the byte array to the data checksum.
+ /// </summary>
+ /// <param name = "buffer">
+ /// The buffer which contains the data
+ /// </param>
+ /// <param name = "offset">
+ /// The offset in the buffer where the data starts
+ /// </param>
+ /// <param name = "count">
+ /// The number of data bytes to update the CRC with.
+ /// </param>
+ public void Update(byte[] buffer, int offset, int count) {
+ if (buffer == null) {
+ throw new ArgumentNullException("buffer");
+ }
+
+ if (count < 0) {
+
+ throw new ArgumentOutOfRangeException("count");
+ }
+
+ if (offset < 0 || offset + count > buffer.Length) {
+ throw new ArgumentOutOfRangeException("offset");
+ }
+
+ crc ^= CrcSeed;
+
+ while (--count >= 0) {
+ crc = CrcTable[(crc ^ buffer[offset++]) & 0xFF] ^ (crc >> 8);
+ }
+
+ crc ^= CrcSeed;
+ }
+ }
+}
diff --git a/debian/missing-sources/plupload/csharp/Plupload/PngEncoder/Deflater.cs b/debian/missing-sources/plupload/csharp/Plupload/PngEncoder/Deflater.cs
new file mode 100644
index 0000000..f4a2094
--- /dev/null
+++ b/debian/missing-sources/plupload/csharp/Plupload/PngEncoder/Deflater.cs
@@ -0,0 +1,543 @@
+// Deflater.cs
+//
+// Copyright (C) 2001 Mike Krueger
+// Copyright (C) 2004 John Reilly
+//
+// This file was translated from java, it was part of the GNU Classpath
+// Copyright (C) 2001 Free Software Foundation, Inc.
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+//
+// Linking this library statically or dynamically with other modules is
+// making a combined work based on this library. Thus, the terms and
+// conditions of the GNU General Public License cover the whole
+// combination.
+//
+// As a special exception, the copyright holders of this library give you
+// permission to link this library with independent modules to produce an
+// executable, regardless of the license terms of these independent
+// modules, and to copy and distribute the resulting executable under
+// terms of your choice, provided that you also meet, for each linked
+// independent module, the terms and conditions of the license of that
+// module. An independent module is a module which is not derived from
+// or based on this library. If you modify this library, you may extend
+// this exception to your version of the library, but you are not
+// obligated to do so. If you do not wish to do so, delete this
+// exception statement from your version.
+
+using System;
+
+namespace Plupload.PngEncoder {
+
+ /// <summary>
+ /// This is the Deflater class. The deflater class compresses input
+ /// with the deflate algorithm described in RFC 1951. It has several
+ /// compression levels and three different strategies described below.
+ ///
+ /// This class is <i>not</i> thread safe. This is inherent in the API, due
+ /// to the split of deflate and setInput.
+ ///
+ /// author of the original java version : Jochen Hoenicke
+ /// </summary>
+ public class Deflater {
+ #region Deflater Documentation
+ /*
+ * The Deflater can do the following state transitions:
+ *
+ * (1) -> INIT_STATE ----> INIT_FINISHING_STATE ---.
+ * / | (2) (5) |
+ * / v (5) |
+ * (3)| SETDICT_STATE ---> SETDICT_FINISHING_STATE |(3)
+ * \ | (3) | ,--------'
+ * | | | (3) /
+ * v v (5) v v
+ * (1) -> BUSY_STATE ----> FINISHING_STATE
+ * | (6)
+ * v
+ * FINISHED_STATE
+ * \_____________________________________/
+ * | (7)
+ * v
+ * CLOSED_STATE
+ *
+ * (1) If we should produce a header we start in INIT_STATE, otherwise
+ * we start in BUSY_STATE.
+ * (2) A dictionary may be set only when we are in INIT_STATE, then
+ * we change the state as indicated.
+ * (3) Whether a dictionary is set or not, on the first call of deflate
+ * we change to BUSY_STATE.
+ * (4) -- intentionally left blank -- :)
+ * (5) FINISHING_STATE is entered, when flush() is called to indicate that
+ * there is no more INPUT. There are also states indicating, that
+ * the header wasn't written yet.
+ * (6) FINISHED_STATE is entered, when everything has been flushed to the
+ * internal pending output buffer.
+ * (7) At any time (7)
+ *
+ */
+ #endregion
+ #region Public Constants
+ /// <summary>
+ /// The best and slowest compression level. This tries to find very
+ /// long and distant string repetitions.
+ /// </summary>
+ public const int BEST_COMPRESSION = 9;
+
+ /// <summary>
+ /// The worst but fastest compression level.
+ /// </summary>
+ public const int BEST_SPEED = 1;
+
+ /// <summary>
+ /// The default compression level.
+ /// </summary>
+ public const int DEFAULT_COMPRESSION = -1;
+
+ /// <summary>
+ /// This level won't compress at all but output uncompressed blocks.
+ /// </summary>
+ public const int NO_COMPRESSION = 0;
+
+ /// <summary>
+ /// The compression method. This is the only method supported so far.
+ /// There is no need to use this constant at all.
+ /// </summary>
+ public const int DEFLATED = 8;
+ #endregion
+ #region Local Constants
+ private const int IS_SETDICT = 0x01;
+ private const int IS_FLUSHING = 0x04;
+ private const int IS_FINISHING = 0x08;
+
+ private const int INIT_STATE = 0x00;
+ private const int SETDICT_STATE = 0x01;
+ // private static int INIT_FINISHING_STATE = 0x08;
+ // private static int SETDICT_FINISHING_STATE = 0x09;
+ private const int BUSY_STATE = 0x10;
+ private const int FLUSHING_STATE = 0x14;
+ private const int FINISHING_STATE = 0x1c;
+ private const int FINISHED_STATE = 0x1e;
+ private const int CLOSED_STATE = 0x7f;
+ #endregion
+ #region Constructors
+ /// <summary>
+ /// Creates a new deflater with default compression level.
+ /// </summary>
+ public Deflater()
+ : this(DEFAULT_COMPRESSION, false) {
+
+ }
+
+ /// <summary>
+ /// Creates a new deflater with given compression level.
+ /// </summary>
+ /// <param name="level">
+ /// the compression level, a value between NO_COMPRESSION
+ /// and BEST_COMPRESSION, or DEFAULT_COMPRESSION.
+ /// </param>
+ /// <exception cref="System.ArgumentOutOfRangeException">if lvl is out of range.</exception>
+ public Deflater(int level)
+ : this(level, false) {
+
+ }
+
+ /// <summary>
+ /// Creates a new deflater with given compression level.
+ /// </summary>
+ /// <param name="level">
+ /// the compression level, a value between NO_COMPRESSION
+ /// and BEST_COMPRESSION.
+ /// </param>
+ /// <param name="noZlibHeaderOrFooter">
+ /// true, if we should suppress the Zlib/RFC1950 header at the
+ /// beginning and the adler checksum at the end of the output. This is
+ /// useful for the GZIP/PKZIP formats.
+ /// </param>
+ /// <exception cref="System.ArgumentOutOfRangeException">if lvl is out of range.</exception>
+ public Deflater(int level, bool noZlibHeaderOrFooter) {
+ if (level == DEFAULT_COMPRESSION) {
+ level = 6;
+ } else if (level < NO_COMPRESSION || level > BEST_COMPRESSION) {
+ throw new ArgumentOutOfRangeException("level");
+ }
+
+ pending = new DeflaterPending();
+ engine = new DeflaterEngine(pending);
+ this.noZlibHeaderOrFooter = noZlibHeaderOrFooter;
+ SetStrategy(DeflateStrategy.Default);
+ SetLevel(level);
+ Reset();
+ }
+ #endregion
+
+ /// <summary>
+ /// Resets the deflater. The deflater acts afterwards as if it was
+ /// just created with the same compression level and strategy as it
+ /// had before.
+ /// </summary>
+ public void Reset() {
+ state = (noZlibHeaderOrFooter ? BUSY_STATE : INIT_STATE);
+ totalOut = 0;
+ pending.Reset();
+ engine.Reset();
+ }
+
+ /// <summary>
+ /// Gets the current adler checksum of the data that was processed so far.
+ /// </summary>
+ public int Adler {
+ get {
+ return engine.Adler;
+ }
+ }
+
+ /// <summary>
+ /// Gets the number of input bytes processed so far.
+ /// </summary>
+ public long TotalIn {
+ get {
+ return engine.TotalIn;
+ }
+ }
+
+ /// <summary>
+ /// Gets the number of output bytes so far.
+ /// </summary>
+ public long TotalOut {
+ get {
+ return totalOut;
+ }
+ }
+
+ /// <summary>
+ /// Flushes the current input block. Further calls to deflate() will
+ /// produce enough output to inflate everything in the current input
+ /// block. This is not part of Sun's JDK so I have made it package
+ /// private. It is used by DeflaterOutputStream to implement
+ /// flush().
+ /// </summary>
+ public void Flush() {
+ state |= IS_FLUSHING;
+ }
+
+ /// <summary>
+ /// Finishes the deflater with the current input block. It is an error
+ /// to give more input after this method was called. This method must
+ /// be called to force all bytes to be flushed.
+ /// </summary>
+ public void Finish() {
+ state |= (IS_FLUSHING | IS_FINISHING);
+ }
+
+ /// <summary>
+ /// Returns true if the stream was finished and no more output bytes
+ /// are available.
+ /// </summary>
+ public bool IsFinished {
+ get {
+ return (state == FINISHED_STATE) && pending.IsFlushed;
+ }
+ }
+
+ /// <summary>
+ /// Returns true, if the input buffer is empty.
+ /// You should then call setInput().
+ /// NOTE: This method can also return true when the stream
+ /// was finished.
+ /// </summary>
+ public bool IsNeedingInput {
+ get {
+ return engine.NeedsInput();
+ }
+ }
+
+ /// <summary>
+ /// Sets the data which should be compressed next. This should be only
+ /// called when needsInput indicates that more input is needed.
+ /// If you call setInput when needsInput() returns false, the
+ /// previous input that is still pending will be thrown away.
+ /// The given byte array should not be changed, before needsInput() returns
+ /// true again.
+ /// This call is equivalent to <code>setInput(input, 0, input.length)</code>.
+ /// </summary>
+ /// <param name="input">
+ /// the buffer containing the input data.
+ /// </param>
+ /// <exception cref="System.InvalidOperationException">
+ /// if the buffer was finished() or ended().
+ /// </exception>
+ public void SetInput(byte[] input) {
+ SetInput(input, 0, input.Length);
+ }
+
+ /// <summary>
+ /// Sets the data which should be compressed next. This should be
+ /// only called when needsInput indicates that more input is needed.
+ /// The given byte array should not be changed, before needsInput() returns
+ /// true again.
+ /// </summary>
+ /// <param name="input">
+ /// the buffer containing the input data.
+ /// </param>
+ /// <param name="offset">
+ /// the start of the data.
+ /// </param>
+ /// <param name="count">
+ /// the number of data bytes of input.
+ /// </param>
+ /// <exception cref="System.InvalidOperationException">
+ /// if the buffer was Finish()ed or if previous input is still pending.
+ /// </exception>
+ public void SetInput(byte[] input, int offset, int count) {
+ if ((state & IS_FINISHING) != 0) {
+ throw new InvalidOperationException("Finish() already called");
+ }
+ engine.SetInput(input, offset, count);
+ }
+
+ /// <summary>
+ /// Sets the compression level. There is no guarantee of the exact
+ /// position of the change, but if you call this when needsInput is
+ /// true the change of compression level will occur somewhere near
+ /// before the end of the so far given input.
+ /// </summary>
+ /// <param name="level">
+ /// the new compression level.
+ /// </param>
+ public void SetLevel(int level) {
+ if (level == DEFAULT_COMPRESSION) {
+ level = 6;
+ } else if (level < NO_COMPRESSION || level > BEST_COMPRESSION) {
+ throw new ArgumentOutOfRangeException("level");
+ }
+
+ if (this.level != level) {
+ this.level = level;
+ engine.SetLevel(level);
+ }
+ }
+
+ /// <summary>
+ /// Get current compression level
+ /// </summary>
+ /// <returns>Returns the current compression level</returns>
+ public int GetLevel() {
+ return level;
+ }
+
+ /// <summary>
+ /// Sets the compression strategy. Strategy is one of
+ /// DEFAULT_STRATEGY, HUFFMAN_ONLY and FILTERED. For the exact
+ /// position where the strategy is changed, the same as for
+ /// SetLevel() applies.
+ /// </summary>
+ /// <param name="strategy">
+ /// The new compression strategy.
+ /// </param>
+ public void SetStrategy(DeflateStrategy strategy) {
+ engine.Strategy = strategy;
+ }
+
+ /// <summary>
+ /// Deflates the current input block with to the given array.
+ /// </summary>
+ /// <param name="output">
+ /// The buffer where compressed data is stored
+ /// </param>
+ /// <returns>
+ /// The number of compressed bytes added to the output, or 0 if either
+ /// IsNeedingInput() or IsFinished returns true or length is zero.
+ /// </returns>
+ public int Deflate(byte[] output) {
+ return Deflate(output, 0, output.Length);
+ }
+
+ /// <summary>
+ /// Deflates the current input block to the given array.
+ /// </summary>
+ /// <param name="output">
+ /// Buffer to store the compressed data.
+ /// </param>
+ /// <param name="offset">
+ /// Offset into the output array.
+ /// </param>
+ /// <param name="length">
+ /// The maximum number of bytes that may be stored.
+ /// </param>
+ /// <returns>
+ /// The number of compressed bytes added to the output, or 0 if either
+ /// needsInput() or finished() returns true or length is zero.
+ /// </returns>
+ /// <exception cref="System.InvalidOperationException">
+ /// If Finish() was previously called.
+ /// </exception>
+ /// <exception cref="System.ArgumentOutOfRangeException">
+ /// If offset or length don't match the array length.
+ /// </exception>
+ public int Deflate(byte[] output, int offset, int length) {
+ int origLength = length;
+
+ if (state == CLOSED_STATE) {
+ throw new InvalidOperationException("Deflater closed");
+ }
+
+ if (state < BUSY_STATE) {
+ // output header
+ int header = (DEFLATED +
+ ((DeflaterConstants.MAX_WBITS - 8) << 4)) << 8;
+ int level_flags = (level - 1) >> 1;
+ if (level_flags < 0 || level_flags > 3) {
+ level_flags = 3;
+ }
+ header |= level_flags << 6;
+ if ((state & IS_SETDICT) != 0) {
+ // Dictionary was set
+ header |= DeflaterConstants.PRESET_DICT;
+ }
+ header += 31 - (header % 31);
+
+ pending.WriteShortMSB(header);
+ if ((state & IS_SETDICT) != 0) {
+ int chksum = engine.Adler;
+ engine.ResetAdler();
+ pending.WriteShortMSB(chksum >> 16);
+ pending.WriteShortMSB(chksum & 0xffff);
+ }
+
+ state = BUSY_STATE | (state & (IS_FLUSHING | IS_FINISHING));
+ }
+
+ for (; ; ) {
+ int count = pending.Flush(output, offset, length);
+ offset += count;
+ totalOut += count;
+ length -= count;
+
+ if (length == 0 || state == FINISHED_STATE) {
+ break;
+ }
+
+ if (!engine.Deflate((state & IS_FLUSHING) != 0, (state & IS_FINISHING) != 0)) {
+ if (state == BUSY_STATE) {
+ // We need more input now
+ return origLength - length;
+ } else if (state == FLUSHING_STATE) {
+ if (level != NO_COMPRESSION) {
+ /* We have to supply some lookahead. 8 bit lookahead
+ * is needed by the zlib inflater, and we must fill
+ * the next byte, so that all bits are flushed.
+ */
+ int neededbits = 8 + ((-pending.BitCount) & 7);
+ while (neededbits > 0) {
+ /* write a static tree block consisting solely of
+ * an EOF:
+ */
+ pending.WriteBits(2, 10);
+ neededbits -= 10;
+ }
+ }
+ state = BUSY_STATE;
+ } else if (state == FINISHING_STATE) {
+ pending.AlignToByte();
+
+ // Compressed data is complete. Write footer information if required.
+ if (!noZlibHeaderOrFooter) {
+ int adler = engine.Adler;
+ pending.WriteShortMSB(adler >> 16);
+ pending.WriteShortMSB(adler & 0xffff);
+ }
+ state = FINISHED_STATE;
+ }
+ }
+ }
+ return origLength - length;
+ }
+
+ /// <summary>
+ /// Sets the dictionary which should be used in the deflate process.
+ /// This call is equivalent to <code>setDictionary(dict, 0, dict.Length)</code>.
+ /// </summary>
+ /// <param name="dictionary">
+ /// the dictionary.
+ /// </param>
+ /// <exception cref="System.InvalidOperationException">
+ /// if SetInput () or Deflate () were already called or another dictionary was already set.
+ /// </exception>
+ public void SetDictionary(byte[] dictionary) {
+ SetDictionary(dictionary, 0, dictionary.Length);
+ }
+
+ /// <summary>
+ /// Sets the dictionary which should be used in the deflate process.
+ /// The dictionary is a byte array containing strings that are
+ /// likely to occur in the data which should be compressed. The
+ /// dictionary is not stored in the compressed output, only a
+ /// checksum. To decompress the output you need to supply the same
+ /// dictionary again.
+ /// </summary>
+ /// <param name="dictionary">
+ /// The dictionary data
+ /// </param>
+ /// <param name="index">
+ /// The index where dictionary information commences.
+ /// </param>
+ /// <param name="count">
+ /// The number of bytes in the dictionary.
+ /// </param>
+ /// <exception cref="System.InvalidOperationException">
+ /// If SetInput () or Deflate() were already called or another dictionary was already set.
+ /// </exception>
+ public void SetDictionary(byte[] dictionary, int index, int count) {
+ if (state != INIT_STATE) {
+ throw new InvalidOperationException();
+ }
+
+ state = SETDICT_STATE;
+ engine.SetDictionary(dictionary, index, count);
+ }
+
+ #region Instance Fields
+ /// <summary>
+ /// Compression level.
+ /// </summary>
+ int level;
+
+ /// <summary>
+ /// If true no Zlib/RFC1950 headers or footers are generated
+ /// </summary>
+ bool noZlibHeaderOrFooter;
+
+ /// <summary>
+ /// The current state.
+ /// </summary>
+ int state;
+
+ /// <summary>
+ /// The total bytes of output written.
+ /// </summary>
+ long totalOut;
+
+ /// <summary>
+ /// The pending output.
+ /// </summary>
+ DeflaterPending pending;
+
+ /// <summary>
+ /// The deflater engine.
+ /// </summary>
+ DeflaterEngine engine;
+ #endregion
+ }
+}
diff --git a/debian/missing-sources/plupload/csharp/Plupload/PngEncoder/DeflaterConstants.cs b/debian/missing-sources/plupload/csharp/Plupload/PngEncoder/DeflaterConstants.cs
new file mode 100644
index 0000000..46587b6
--- /dev/null
+++ b/debian/missing-sources/plupload/csharp/Plupload/PngEncoder/DeflaterConstants.cs
@@ -0,0 +1,184 @@
+// DeflaterConstants.cs
+//
+// Copyright (C) 2001 Mike Krueger
+// Copyright (C) 2004 John Reilly
+//
+// This file was translated from java, it was part of the GNU Classpath
+// Copyright (C) 2001 Free Software Foundation, Inc.
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+//
+// Linking this library statically or dynamically with other modules is
+// making a combined work based on this library. Thus, the terms and
+// conditions of the GNU General Public License cover the whole
+// combination.
+//
+// As a special exception, the copyright holders of this library give you
+// permission to link this library with independent modules to produce an
+// executable, regardless of the license terms of these independent
+// modules, and to copy and distribute the resulting executable under
+// terms of your choice, provided that you also meet, for each linked
+// independent module, the terms and conditions of the license of that
+// module. An independent module is a module which is not derived from
+// or based on this library. If you modify this library, you may extend
+// this exception to your version of the library, but you are not
+// obligated to do so. If you do not wish to do so, delete this
+// exception statement from your version.
+
+using System;
+
+namespace Plupload.PngEncoder {
+
+ /// <summary>
+ /// This class contains constants used for deflation.
+ /// </summary>
+ public class DeflaterConstants {
+ /// <summary>
+ /// Set to true to enable debugging
+ /// </summary>
+ public const bool DEBUGGING = false;
+
+ /// <summary>
+ /// Written to Zip file to identify a stored block
+ /// </summary>
+ public const int STORED_BLOCK = 0;
+
+ /// <summary>
+ /// Identifies static tree in Zip file
+ /// </summary>
+ public const int STATIC_TREES = 1;
+
+ /// <summary>
+ /// Identifies dynamic tree in Zip file
+ /// </summary>
+ public const int DYN_TREES = 2;
+
+ /// <summary>
+ /// Header flag indicating a preset dictionary for deflation
+ /// </summary>
+ public const int PRESET_DICT = 0x20;
+
+ /// <summary>
+ /// Sets internal buffer sizes for Huffman encoding
+ /// </summary>
+ public const int DEFAULT_MEM_LEVEL = 8;
+
+ /// <summary>
+ /// Internal compression engine constant
+ /// </summary>
+ public const int MAX_MATCH = 258;
+
+ /// <summary>
+ /// Internal compression engine constant
+ /// </summary>
+ public const int MIN_MATCH = 3;
+
+ /// <summary>
+ /// Internal compression engine constant
+ /// </summary>
+ public const int MAX_WBITS = 15;
+
+ /// <summary>
+ /// Internal compression engine constant
+ /// </summary>
+ public const int WSIZE = 1 << MAX_WBITS;
+
+ /// <summary>
+ /// Internal compression engine constant
+ /// </summary>
+ public const int WMASK = WSIZE - 1;
+
+ /// <summary>
+ /// Internal compression engine constant
+ /// </summary>
+ public const int HASH_BITS = DEFAULT_MEM_LEVEL + 7;
+
+ /// <summary>
+ /// Internal compression engine constant
+ /// </summary>
+ public const int HASH_SIZE = 1 << HASH_BITS;
+
+ /// <summary>
+ /// Internal compression engine constant
+ /// </summary>
+ public const int HASH_MASK = HASH_SIZE - 1;
+
+ /// <summary>
+ /// Internal compression engine constant
+ /// </summary>
+ public const int HASH_SHIFT = (HASH_BITS + MIN_MATCH - 1) / MIN_MATCH;
+
+ /// <summary>
+ /// Internal compression engine constant
+ /// </summary>
+ public const int MIN_LOOKAHEAD = MAX_MATCH + MIN_MATCH + 1;
+
+ /// <summary>
+ /// Internal compression engine constant
+ /// </summary>
+ public const int MAX_DIST = WSIZE - MIN_LOOKAHEAD;
+
+ /// <summary>
+ /// Internal compression engine constant
+ /// </summary>
+ public const int PENDING_BUF_SIZE = 1 << (DEFAULT_MEM_LEVEL + 8);
+
+ /// <summary>
+ /// Internal compression engine constant
+ /// </summary>
+ public static int MAX_BLOCK_SIZE = Math.Min(65535, PENDING_BUF_SIZE - 5);
+
+ /// <summary>
+ /// Internal compression engine constant
+ /// </summary>
+ public const int DEFLATE_STORED = 0;
+
+ /// <summary>
+ /// Internal compression engine constant
+ /// </summary>
+ public const int DEFLATE_FAST = 1;
+
+ /// <summary>
+ /// Internal compression engine constant
+ /// </summary>
+ public const int DEFLATE_SLOW = 2;
+
+ /// <summary>
+ /// Internal compression engine constant
+ /// </summary>
+ public static int[] GOOD_LENGTH = { 0, 4, 4, 4, 4, 8, 8, 8, 32, 32 };
+
+ /// <summary>
+ /// Internal compression engine constant
+ /// </summary>
+ public static int[] MAX_LAZY = { 0, 4, 5, 6, 4, 16, 16, 32, 128, 258 };
+
+ /// <summary>
+ /// Internal compression engine constant
+ /// </summary>
+ public static int[] NICE_LENGTH = { 0, 8, 16, 32, 16, 32, 128, 128, 258, 258 };
+
+ /// <summary>
+ /// Internal compression engine constant
+ /// </summary>
+ public static int[] MAX_CHAIN = { 0, 4, 8, 32, 16, 32, 128, 256, 1024, 4096 };
+
+ /// <summary>
+ /// Internal compression engine constant
+ /// </summary>
+ public static int[] COMPR_FUNC = { 0, 1, 1, 1, 1, 2, 2, 2, 2, 2 };
+
+ }
+}
diff --git a/debian/missing-sources/plupload/csharp/Plupload/PngEncoder/DeflaterEngine.cs b/debian/missing-sources/plupload/csharp/Plupload/PngEncoder/DeflaterEngine.cs
new file mode 100644
index 0000000..7b56b59
--- /dev/null
+++ b/debian/missing-sources/plupload/csharp/Plupload/PngEncoder/DeflaterEngine.cs
@@ -0,0 +1,832 @@
+// DeflaterEngine.cs
+//
+// Copyright (C) 2001 Mike Krueger
+// Copyright (C) 2004 John Reilly
+//
+// This file was translated from java, it was part of the GNU Classpath
+// Copyright (C) 2001 Free Software Foundation, Inc.
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+//
+// Linking this library statically or dynamically with other modules is
+// making a combined work based on this library. Thus, the terms and
+// conditions of the GNU General Public License cover the whole
+// combination.
+//
+// As a special exception, the copyright holders of this library give you
+// permission to link this library with independent modules to produce an
+// executable, regardless of the license terms of these independent
+// modules, and to copy and distribute the resulting executable under
+// terms of your choice, provided that you also meet, for each linked
+// independent module, the terms and conditions of the license of that
+// module. An independent module is a module which is not derived from
+// or based on this library. If you modify this library, you may extend
+// this exception to your version of the library, but you are not
+// obligated to do so. If you do not wish to do so, delete this
+// exception statement from your version.
+
+using System;
+
+namespace Plupload.PngEncoder {
+
+ /// <summary>
+ /// Strategies for deflater
+ /// </summary>
+ public enum DeflateStrategy {
+ /// <summary>
+ /// The default strategy
+ /// </summary>
+ Default = 0,
+
+ /// <summary>
+ /// This strategy will only allow longer string repetitions. It is
+ /// useful for random data with a small character set.
+ /// </summary>
+ Filtered = 1,
+
+
+ /// <summary>
+ /// This strategy will not look for string repetitions at all. It
+ /// only encodes with Huffman trees (which means, that more common
+ /// characters get a smaller encoding.
+ /// </summary>
+ HuffmanOnly = 2
+ }
+
+ // DEFLATE ALGORITHM:
+ //
+ // The uncompressed stream is inserted into the window array. When
+ // the window array is full the first half is thrown away and the
+ // second half is copied to the beginning.
+ //
+ // The head array is a hash table. Three characters build a hash value
+ // and they the value points to the corresponding index in window of
+ // the last string with this hash. The prev array implements a
+ // linked list of matches with the same hash: prev[index & WMASK] points
+ // to the previous index with the same hash.
+ //
+
+
+ /// <summary>
+ /// Low level compression engine for deflate algorithm which uses a 32K sliding window
+ /// with secondary compression from Huffman/Shannon-Fano codes.
+ /// </summary>
+ public class DeflaterEngine : DeflaterConstants {
+ #region Constants
+ const int TooFar = 4096;
+ #endregion
+
+ #region Constructors
+ /// <summary>
+ /// Construct instance with pending buffer
+ /// </summary>
+ /// <param name="pending">
+ /// Pending buffer to use
+ /// </param>>
+ public DeflaterEngine(DeflaterPending pending) {
+ this.pending = pending;
+ huffman = new DeflaterHuffman(pending);
+ adler = new Adler32();
+
+ window = new byte[2 * WSIZE];
+ head = new short[HASH_SIZE];
+ prev = new short[WSIZE];
+
+ // We start at index 1, to avoid an implementation deficiency, that
+ // we cannot build a repeat pattern at index 0.
+ blockStart = strstart = 1;
+ }
+
+ #endregion
+
+ /// <summary>
+ /// Deflate drives actual compression of data
+ /// </summary>
+ /// <param name="flush">True to flush input buffers</param>
+ /// <param name="finish">Finish deflation with the current input.</param>
+ /// <returns>Returns true if progress has been made.</returns>
+ public bool Deflate(bool flush, bool finish) {
+ bool progress;
+ do {
+ FillWindow();
+ bool canFlush = flush && (inputOff == inputEnd);
+
+#if DebugDeflation
+ if (DeflaterConstants.DEBUGGING) {
+ Console.WriteLine("window: [" + blockStart + "," + strstart + ","
+ + lookahead + "], " + compressionFunction + "," + canFlush);
+ }
+#endif
+ switch (compressionFunction) {
+ case DEFLATE_STORED:
+ progress = DeflateStored(canFlush, finish);
+ break;
+ case DEFLATE_FAST:
+ progress = DeflateFast(canFlush, finish);
+ break;
+ case DEFLATE_SLOW:
+ progress = DeflateSlow(canFlush, finish);
+ break;
+ default:
+ throw new InvalidOperationException("unknown compressionFunction");
+ }
+ } while (pending.IsFlushed && progress); // repeat while we have no pending output and progress was made
+ return progress;
+ }
+
+ /// <summary>
+ /// Sets input data to be deflated. Should only be called when <code>NeedsInput()</code>
+ /// returns true
+ /// </summary>
+ /// <param name="buffer">The buffer containing input data.</param>
+ /// <param name="offset">The offset of the first byte of data.</param>
+ /// <param name="count">The number of bytes of data to use as input.</param>
+ public void SetInput(byte[] buffer, int offset, int count) {
+ if (buffer == null) {
+ throw new ArgumentNullException("buffer");
+ }
+
+ if (offset < 0) {
+ throw new ArgumentOutOfRangeException("offset");
+ }
+
+ if (count < 0) {
+ throw new ArgumentOutOfRangeException("count");
+ }
+
+ if (inputOff < inputEnd) {
+ throw new InvalidOperationException("Old input was not completely processed");
+ }
+
+ int end = offset + count;
+
+ /* We want to throw an ArrayIndexOutOfBoundsException early. The
+ * check is very tricky: it also handles integer wrap around.
+ */
+ if ((offset > end) || (end > buffer.Length)) {
+ throw new ArgumentOutOfRangeException("count");
+ }
+
+ inputBuf = buffer;
+ inputOff = offset;
+ inputEnd = end;
+ }
+
+ /// <summary>
+ /// Determines if more <see cref="SetInput">input</see> is needed.
+ /// </summary>
+ /// <returns>Return true if input is needed via <see cref="SetInput">SetInput</see></returns>
+ public bool NeedsInput() {
+ return (inputEnd == inputOff);
+ }
+
+ /// <summary>
+ /// Set compression dictionary
+ /// </summary>
+ /// <param name="buffer">The buffer containing the dictionary data</param>
+ /// <param name="offset">The offset in the buffer for the first byte of data</param>
+ /// <param name="length">The length of the dictionary data.</param>
+ public void SetDictionary(byte[] buffer, int offset, int length) {
+#if DebugDeflation
+ if (DeflaterConstants.DEBUGGING && (strstart != 1) )
+ {
+ throw new InvalidOperationException("strstart not 1");
+ }
+#endif
+ adler.Update(buffer, offset, length);
+ if (length < MIN_MATCH) {
+ return;
+ }
+
+ if (length > MAX_DIST) {
+ offset += length - MAX_DIST;
+ length = MAX_DIST;
+ }
+
+ System.Array.Copy(buffer, offset, window, strstart, length);
+
+ UpdateHash();
+ --length;
+ while (--length > 0) {
+ InsertString();
+ strstart++;
+ }
+ strstart += 2;
+ blockStart = strstart;
+ }
+
+ /// <summary>
+ /// Reset internal state
+ /// </summary>
+ public void Reset() {
+ huffman.Reset();
+ adler.Reset();
+ blockStart = strstart = 1;
+ lookahead = 0;
+ totalIn = 0;
+ prevAvailable = false;
+ matchLen = MIN_MATCH - 1;
+
+ for (int i = 0; i < HASH_SIZE; i++) {
+ head[i] = 0;
+ }
+
+ for (int i = 0; i < WSIZE; i++) {
+ prev[i] = 0;
+ }
+ }
+
+ /// <summary>
+ /// Reset Adler checksum
+ /// </summary>
+ public void ResetAdler() {
+ adler.Reset();
+ }
+
+ /// <summary>
+ /// Get current value of Adler checksum
+ /// </summary>
+ public int Adler {
+ get {
+ return unchecked((int) adler.Value);
+ }
+ }
+
+ /// <summary>
+ /// Total data processed
+ /// </summary>
+ public long TotalIn {
+ get {
+ return totalIn;
+ }
+ }
+
+ /// <summary>
+ /// Get/set the <see cref="DeflateStrategy">deflate strategy</see>
+ /// </summary>
+ public DeflateStrategy Strategy {
+ get {
+ return strategy;
+ }
+ set {
+ strategy = value;
+ }
+ }
+
+ /// <summary>
+ /// Set the deflate level (0-9)
+ /// </summary>
+ /// <param name="level">The value to set the level to.</param>
+ public void SetLevel(int level) {
+ if ((level < 0) || (level > 9)) {
+ throw new ArgumentOutOfRangeException("level");
+ }
+
+ goodLength = DeflaterConstants.GOOD_LENGTH[level];
+ max_lazy = DeflaterConstants.MAX_LAZY[level];
+ niceLength = DeflaterConstants.NICE_LENGTH[level];
+ max_chain = DeflaterConstants.MAX_CHAIN[level];
+
+ if (DeflaterConstants.COMPR_FUNC[level] != compressionFunction) {
+
+#if DebugDeflation
+ if (DeflaterConstants.DEBUGGING) {
+ Console.WriteLine("Change from " + compressionFunction + " to "
+ + DeflaterConstants.COMPR_FUNC[level]);
+ }
+#endif
+ switch (compressionFunction) {
+ case DEFLATE_STORED:
+ if (strstart > blockStart) {
+ huffman.FlushStoredBlock(window, blockStart,
+ strstart - blockStart, false);
+ blockStart = strstart;
+ }
+ UpdateHash();
+ break;
+
+ case DEFLATE_FAST:
+ if (strstart > blockStart) {
+ huffman.FlushBlock(window, blockStart, strstart - blockStart,
+ false);
+ blockStart = strstart;
+ }
+ break;
+
+ case DEFLATE_SLOW:
+ if (prevAvailable) {
+ huffman.TallyLit(window[strstart - 1] & 0xff);
+ }
+ if (strstart > blockStart) {
+ huffman.FlushBlock(window, blockStart, strstart - blockStart, false);
+ blockStart = strstart;
+ }
+ prevAvailable = false;
+ matchLen = MIN_MATCH - 1;
+ break;
+ }
+ compressionFunction = COMPR_FUNC[level];
+ }
+ }
+
+ /// <summary>
+ /// Fill the window
+ /// </summary>
+ public void FillWindow() {
+ /* If the window is almost full and there is insufficient lookahead,
+ * move the upper half to the lower one to make room in the upper half.
+ */
+ if (strstart >= WSIZE + MAX_DIST) {
+ SlideWindow();
+ }
+
+ /* If there is not enough lookahead, but still some input left,
+ * read in the input
+ */
+ while (lookahead < DeflaterConstants.MIN_LOOKAHEAD && inputOff < inputEnd) {
+ int more = 2 * WSIZE - lookahead - strstart;
+
+ if (more > inputEnd - inputOff) {
+ more = inputEnd - inputOff;
+ }
+
+ System.Array.Copy(inputBuf, inputOff, window, strstart + lookahead, more);
+ adler.Update(inputBuf, inputOff, more);
+
+ inputOff += more;
+ totalIn += more;
+ lookahead += more;
+ }
+
+ if (lookahead >= MIN_MATCH) {
+ UpdateHash();
+ }
+ }
+
+ void UpdateHash() {
+ /*
+ if (DEBUGGING) {
+ Console.WriteLine("updateHash: "+strstart);
+ }
+ */
+ ins_h = (window[strstart] << HASH_SHIFT) ^ window[strstart + 1];
+ }
+
+ /// <summary>
+ /// Inserts the current string in the head hash and returns the previous
+ /// value for this hash.
+ /// </summary>
+ /// <returns>The previous hash value</returns>
+ int InsertString() {
+ short match;
+ int hash = ((ins_h << HASH_SHIFT) ^ window[strstart + (MIN_MATCH - 1)]) & HASH_MASK;
+
+#if DebugDeflation
+ if (DeflaterConstants.DEBUGGING)
+ {
+ if (hash != (((window[strstart] << (2*HASH_SHIFT)) ^
+ (window[strstart + 1] << HASH_SHIFT) ^
+ (window[strstart + 2])) & HASH_MASK)) {
+ throw new SharpZipBaseException("hash inconsistent: " + hash + "/"
+ +window[strstart] + ","
+ +window[strstart + 1] + ","
+ +window[strstart + 2] + "," + HASH_SHIFT);
+ }
+ }
+#endif
+ prev[strstart & WMASK] = match = head[hash];
+ head[hash] = unchecked((short) strstart);
+ ins_h = hash;
+ return match & 0xffff;
+ }
+
+ void SlideWindow() {
+ Array.Copy(window, WSIZE, window, 0, WSIZE);
+ matchStart -= WSIZE;
+ strstart -= WSIZE;
+ blockStart -= WSIZE;
+
+ // Slide the hash table (could be avoided with 32 bit values
+ // at the expense of memory usage).
+ for (int i = 0; i < HASH_SIZE; ++i) {
+ int m = head[i] & 0xffff;
+ head[i] = (short) (m >= WSIZE ? (m - WSIZE) : 0);
+ }
+
+ // Slide the prev table.
+ for (int i = 0; i < WSIZE; i++) {
+ int m = prev[i] & 0xffff;
+ prev[i] = (short) (m >= WSIZE ? (m - WSIZE) : 0);
+ }
+ }
+
+ /// <summary>
+ /// Find the best (longest) string in the window matching the
+ /// string starting at strstart.
+ ///
+ /// Preconditions:
+ /// <code>
+ /// strstart + MAX_MATCH &lt;= window.length.</code>
+ /// </summary>
+ /// <param name="curMatch"></param>
+ /// <returns>True if a match greater than the minimum length is found</returns>
+ bool FindLongestMatch(int curMatch) {
+ int chainLength = this.max_chain;
+ int niceLength = this.niceLength;
+ short[] prev = this.prev;
+ int scan = this.strstart;
+ int match;
+ int best_end = this.strstart + matchLen;
+ int best_len = Math.Max(matchLen, MIN_MATCH - 1);
+
+ int limit = Math.Max(strstart - MAX_DIST, 0);
+
+ int strend = strstart + MAX_MATCH - 1;
+ byte scan_end1 = window[best_end - 1];
+ byte scan_end = window[best_end];
+
+ // Do not waste too much time if we already have a good match:
+ if (best_len >= this.goodLength) {
+ chainLength >>= 2;
+ }
+
+ /* Do not look for matches beyond the end of the input. This is necessary
+ * to make deflate deterministic.
+ */
+ if (niceLength > lookahead) {
+ niceLength = lookahead;
+ }
+
+#if DebugDeflation
+
+ if (DeflaterConstants.DEBUGGING && (strstart > 2 * WSIZE - MIN_LOOKAHEAD))
+ {
+ throw new InvalidOperationException("need lookahead");
+ }
+#endif
+
+ do {
+
+#if DebugDeflation
+
+ if (DeflaterConstants.DEBUGGING && (curMatch >= strstart) )
+ {
+ throw new InvalidOperationException("no future");
+ }
+#endif
+ if (window[curMatch + best_len] != scan_end ||
+ window[curMatch + best_len - 1] != scan_end1 ||
+ window[curMatch] != window[scan] ||
+ window[curMatch + 1] != window[scan + 1]) {
+ continue;
+ }
+
+ match = curMatch + 2;
+ scan += 2;
+
+ /* We check for insufficient lookahead only every 8th comparison;
+ * the 256th check will be made at strstart + 258.
+ */
+ while (
+ window[++scan] == window[++match] &&
+ window[++scan] == window[++match] &&
+ window[++scan] == window[++match] &&
+ window[++scan] == window[++match] &&
+ window[++scan] == window[++match] &&
+ window[++scan] == window[++match] &&
+ window[++scan] == window[++match] &&
+ window[++scan] == window[++match] &&
+ (scan < strend)) {
+ // Do nothing
+ }
+
+ if (scan > best_end) {
+#if DebugDeflation
+ if (DeflaterConstants.DEBUGGING && (ins_h == 0) )
+ Console.Error.WriteLine("Found match: " + curMatch + "-" + (scan - strstart));
+#endif
+ matchStart = curMatch;
+ best_end = scan;
+ best_len = scan - strstart;
+
+ if (best_len >= niceLength) {
+ break;
+ }
+
+ scan_end1 = window[best_end - 1];
+ scan_end = window[best_end];
+ }
+ scan = strstart;
+ } while ((curMatch = (prev[curMatch & WMASK] & 0xffff)) > limit && --chainLength != 0);
+
+ matchLen = Math.Min(best_len, lookahead);
+ return matchLen >= MIN_MATCH;
+ }
+
+ bool DeflateStored(bool flush, bool finish) {
+ if (!flush && (lookahead == 0)) {
+ return false;
+ }
+
+ strstart += lookahead;
+ lookahead = 0;
+
+ int storedLength = strstart - blockStart;
+
+ if ((storedLength >= DeflaterConstants.MAX_BLOCK_SIZE) || // Block is full
+ (blockStart < WSIZE && storedLength >= MAX_DIST) || // Block may move out of window
+ flush) {
+ bool lastBlock = finish;
+ if (storedLength > DeflaterConstants.MAX_BLOCK_SIZE) {
+ storedLength = DeflaterConstants.MAX_BLOCK_SIZE;
+ lastBlock = false;
+ }
+
+#if DebugDeflation
+ if (DeflaterConstants.DEBUGGING)
+ {
+ Console.WriteLine("storedBlock[" + storedLength + "," + lastBlock + "]");
+ }
+#endif
+
+ huffman.FlushStoredBlock(window, blockStart, storedLength, lastBlock);
+ blockStart += storedLength;
+ return !lastBlock;
+ }
+ return true;
+ }
+
+ bool DeflateFast(bool flush, bool finish) {
+ if (lookahead < MIN_LOOKAHEAD && !flush) {
+ return false;
+ }
+
+ while (lookahead >= MIN_LOOKAHEAD || flush) {
+ if (lookahead == 0) {
+ // We are flushing everything
+ huffman.FlushBlock(window, blockStart, strstart - blockStart, finish);
+ blockStart = strstart;
+ return false;
+ }
+
+ if (strstart > 2 * WSIZE - MIN_LOOKAHEAD) {
+ /* slide window, as FindLongestMatch needs this.
+ * This should only happen when flushing and the window
+ * is almost full.
+ */
+ SlideWindow();
+ }
+
+ int hashHead;
+ if (lookahead >= MIN_MATCH &&
+ (hashHead = InsertString()) != 0 &&
+ strategy != DeflateStrategy.HuffmanOnly &&
+ strstart - hashHead <= MAX_DIST &&
+ FindLongestMatch(hashHead)) {
+ // longestMatch sets matchStart and matchLen
+#if DebugDeflation
+ if (DeflaterConstants.DEBUGGING)
+ {
+ for (int i = 0 ; i < matchLen; i++) {
+ if (window[strstart + i] != window[matchStart + i]) {
+ throw new SharpZipBaseException("Match failure");
+ }
+ }
+ }
+#endif
+
+ bool full = huffman.TallyDist(strstart - matchStart, matchLen);
+
+ lookahead -= matchLen;
+ if (matchLen <= max_lazy && lookahead >= MIN_MATCH) {
+ while (--matchLen > 0) {
+ ++strstart;
+ InsertString();
+ }
+ ++strstart;
+ } else {
+ strstart += matchLen;
+ if (lookahead >= MIN_MATCH - 1) {
+ UpdateHash();
+ }
+ }
+ matchLen = MIN_MATCH - 1;
+ if (!full) {
+ continue;
+ }
+ } else {
+ // No match found
+ huffman.TallyLit(window[strstart] & 0xff);
+ ++strstart;
+ --lookahead;
+ }
+
+ if (huffman.IsFull()) {
+ bool lastBlock = finish && (lookahead == 0);
+ huffman.FlushBlock(window, blockStart, strstart - blockStart, lastBlock);
+ blockStart = strstart;
+ return !lastBlock;
+ }
+ }
+ return true;
+ }
+
+ bool DeflateSlow(bool flush, bool finish) {
+ if (lookahead < MIN_LOOKAHEAD && !flush) {
+ return false;
+ }
+
+ while (lookahead >= MIN_LOOKAHEAD || flush) {
+ if (lookahead == 0) {
+ if (prevAvailable) {
+ huffman.TallyLit(window[strstart - 1] & 0xff);
+ }
+ prevAvailable = false;
+
+ // We are flushing everything
+#if DebugDeflation
+ if (DeflaterConstants.DEBUGGING && !flush)
+ {
+ throw new SharpZipBaseException("Not flushing, but no lookahead");
+ }
+#endif
+ huffman.FlushBlock(window, blockStart, strstart - blockStart,
+ finish);
+ blockStart = strstart;
+ return false;
+ }
+
+ if (strstart >= 2 * WSIZE - MIN_LOOKAHEAD) {
+ /* slide window, as FindLongestMatch needs this.
+ * This should only happen when flushing and the window
+ * is almost full.
+ */
+ SlideWindow();
+ }
+
+ int prevMatch = matchStart;
+ int prevLen = matchLen;
+ if (lookahead >= MIN_MATCH) {
+
+ int hashHead = InsertString();
+
+ if (strategy != DeflateStrategy.HuffmanOnly &&
+ hashHead != 0 &&
+ strstart - hashHead <= MAX_DIST &&
+ FindLongestMatch(hashHead)) {
+
+ // longestMatch sets matchStart and matchLen
+
+ // Discard match if too small and too far away
+ if (matchLen <= 5 && (strategy == DeflateStrategy.Filtered || (matchLen == MIN_MATCH && strstart - matchStart > TooFar))) {
+ matchLen = MIN_MATCH - 1;
+ }
+ }
+ }
+
+ // previous match was better
+ if ((prevLen >= MIN_MATCH) && (matchLen <= prevLen)) {
+#if DebugDeflation
+ if (DeflaterConstants.DEBUGGING)
+ {
+ for (int i = 0 ; i < matchLen; i++) {
+ if (window[strstart-1+i] != window[prevMatch + i])
+ throw new SharpZipBaseException();
+ }
+ }
+#endif
+ huffman.TallyDist(strstart - 1 - prevMatch, prevLen);
+ prevLen -= 2;
+ do {
+ strstart++;
+ lookahead--;
+ if (lookahead >= MIN_MATCH) {
+ InsertString();
+ }
+ } while (--prevLen > 0);
+
+ strstart++;
+ lookahead--;
+ prevAvailable = false;
+ matchLen = MIN_MATCH - 1;
+ } else {
+ if (prevAvailable) {
+ huffman.TallyLit(window[strstart - 1] & 0xff);
+ }
+ prevAvailable = true;
+ strstart++;
+ lookahead--;
+ }
+
+ if (huffman.IsFull()) {
+ int len = strstart - blockStart;
+ if (prevAvailable) {
+ len--;
+ }
+ bool lastBlock = (finish && (lookahead == 0) && !prevAvailable);
+ huffman.FlushBlock(window, blockStart, len, lastBlock);
+ blockStart += len;
+ return !lastBlock;
+ }
+ }
+ return true;
+ }
+
+ #region Instance Fields
+
+ // Hash index of string to be inserted
+ int ins_h;
+
+ /// <summary>
+ /// Hashtable, hashing three characters to an index for window, so
+ /// that window[index]..window[index+2] have this hash code.
+ /// Note that the array should really be unsigned short, so you need
+ /// to and the values with 0xffff.
+ /// </summary>
+ short[] head;
+
+ /// <summary>
+ /// <code>prev[index &amp; WMASK]</code> points to the previous index that has the
+ /// same hash code as the string starting at index. This way
+ /// entries with the same hash code are in a linked list.
+ /// Note that the array should really be unsigned short, so you need
+ /// to and the values with 0xffff.
+ /// </summary>
+ short[] prev;
+
+ int matchStart;
+ // Length of best match
+ int matchLen;
+ // Set if previous match exists
+ bool prevAvailable;
+ int blockStart;
+
+ /// <summary>
+ /// Points to the current character in the window.
+ /// </summary>
+ int strstart;
+
+ /// <summary>
+ /// lookahead is the number of characters starting at strstart in
+ /// window that are valid.
+ /// So window[strstart] until window[strstart+lookahead-1] are valid
+ /// characters.
+ /// </summary>
+ int lookahead;
+
+ /// <summary>
+ /// This array contains the part of the uncompressed stream that
+ /// is of relevance. The current character is indexed by strstart.
+ /// </summary>
+ byte[] window;
+
+ DeflateStrategy strategy;
+ int max_chain, max_lazy, niceLength, goodLength;
+
+ /// <summary>
+ /// The current compression function.
+ /// </summary>
+ int compressionFunction;
+
+ /// <summary>
+ /// The input data for compression.
+ /// </summary>
+ byte[] inputBuf;
+
+ /// <summary>
+ /// The total bytes of input read.
+ /// </summary>
+ long totalIn;
+
+ /// <summary>
+ /// The offset into inputBuf, where input data starts.
+ /// </summary>
+ int inputOff;
+
+ /// <summary>
+ /// The end offset of the input data.
+ /// </summary>
+ int inputEnd;
+
+ DeflaterPending pending;
+ DeflaterHuffman huffman;
+
+ /// <summary>
+ /// The adler checksum
+ /// </summary>
+ Adler32 adler;
+ #endregion
+ }
+}
diff --git a/debian/missing-sources/plupload/csharp/Plupload/PngEncoder/DeflaterHuffman.cs b/debian/missing-sources/plupload/csharp/Plupload/PngEncoder/DeflaterHuffman.cs
new file mode 100644
index 0000000..e94cbd5
--- /dev/null
+++ b/debian/missing-sources/plupload/csharp/Plupload/PngEncoder/DeflaterHuffman.cs
@@ -0,0 +1,881 @@
+// DeflaterHuffman.cs
+//
+// Copyright (C) 2001 Mike Krueger
+// Copyright (C) 2004 John Reilly
+//
+// This file was translated from java, it was part of the GNU Classpath
+// Copyright (C) 2001 Free Software Foundation, Inc.
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+//
+// Linking this library statically or dynamically with other modules is
+// making a combined work based on this library. Thus, the terms and
+// conditions of the GNU General Public License cover the whole
+// combination.
+//
+// As a special exception, the copyright holders of this library give you
+// permission to link this library with independent modules to produce an
+// executable, regardless of the license terms of these independent
+// modules, and to copy and distribute the resulting executable under
+// terms of your choice, provided that you also meet, for each linked
+// independent module, the terms and conditions of the license of that
+// module. An independent module is a module which is not derived from
+// or based on this library. If you modify this library, you may extend
+// this exception to your version of the library, but you are not
+// obligated to do so. If you do not wish to do so, delete this
+// exception statement from your version.
+
+using System;
+
+namespace Plupload.PngEncoder {
+
+ /// <summary>
+ /// This is the DeflaterHuffman class.
+ ///
+ /// This class is <i>not</i> thread safe. This is inherent in the API, due
+ /// to the split of Deflate and SetInput.
+ ///
+ /// author of the original java version : Jochen Hoenicke
+ /// </summary>
+ public class DeflaterHuffman {
+ const int BUFSIZE = 1 << (DeflaterConstants.DEFAULT_MEM_LEVEL + 6);
+ const int LITERAL_NUM = 286;
+
+ // Number of distance codes
+ const int DIST_NUM = 30;
+ // Number of codes used to transfer bit lengths
+ const int BITLEN_NUM = 19;
+
+ // repeat previous bit length 3-6 times (2 bits of repeat count)
+ const int REP_3_6 = 16;
+ // repeat a zero length 3-10 times (3 bits of repeat count)
+ const int REP_3_10 = 17;
+ // repeat a zero length 11-138 times (7 bits of repeat count)
+ const int REP_11_138 = 18;
+
+ const int EOF_SYMBOL = 256;
+
+ // The lengths of the bit length codes are sent in order of decreasing
+ // probability, to avoid transmitting the lengths for unused bit length codes.
+ static readonly int[] BL_ORDER = { 16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15 };
+
+ static readonly byte[] bit4Reverse = {
+ 0,
+ 8,
+ 4,
+ 12,
+ 2,
+ 10,
+ 6,
+ 14,
+ 1,
+ 9,
+ 5,
+ 13,
+ 3,
+ 11,
+ 7,
+ 15
+ };
+
+ static short[] staticLCodes;
+ static byte[] staticLLength;
+ static short[] staticDCodes;
+ static byte[] staticDLength;
+
+ class Tree {
+ #region Instance Fields
+ public short[] freqs;
+
+ public byte[] length;
+
+ public int minNumCodes;
+
+ public int numCodes;
+
+ short[] codes;
+ int[] bl_counts;
+ int maxLength;
+ DeflaterHuffman dh;
+ #endregion
+
+ #region Constructors
+ public Tree(DeflaterHuffman dh, int elems, int minCodes, int maxLength) {
+ this.dh = dh;
+ this.minNumCodes = minCodes;
+ this.maxLength = maxLength;
+ freqs = new short[elems];
+ bl_counts = new int[maxLength];
+ }
+
+ #endregion
+
+ /// <summary>
+ /// Resets the internal state of the tree
+ /// </summary>
+ public void Reset() {
+ for (int i = 0; i < freqs.Length; i++) {
+ freqs[i] = 0;
+ }
+ codes = null;
+ length = null;
+ }
+
+ public void WriteSymbol(int code) {
+ // if (DeflaterConstants.DEBUGGING) {
+ // freqs[code]--;
+ // // Console.Write("writeSymbol("+freqs.length+","+code+"): ");
+ // }
+ dh.pending.WriteBits(codes[code] & 0xffff, length[code]);
+ }
+
+ /// <summary>
+ /// Check that all frequencies are zero
+ /// </summary>
+ /// <exception cref="SharpZipBaseException">
+ /// At least one frequency is non-zero
+ /// </exception>
+ public void CheckEmpty() {
+ bool empty = true;
+ for (int i = 0; i < freqs.Length; i++) {
+ if (freqs[i] != 0) {
+ //Console.WriteLine("freqs[" + i + "] == " + freqs[i]);
+ empty = false;
+ }
+ }
+
+ if (!empty) {
+ throw new Exception("!Empty");
+ }
+ }
+
+ /// <summary>
+ /// Set static codes and length
+ /// </summary>
+ /// <param name="staticCodes">new codes</param>
+ /// <param name="staticLengths">length for new codes</param>
+ public void SetStaticCodes(short[] staticCodes, byte[] staticLengths) {
+ codes = staticCodes;
+ length = staticLengths;
+ }
+
+ /// <summary>
+ /// Build dynamic codes and lengths
+ /// </summary>
+ public void BuildCodes() {
+ int numSymbols = freqs.Length;
+ int[] nextCode = new int[maxLength];
+ int code = 0;
+
+ codes = new short[freqs.Length];
+
+ // if (DeflaterConstants.DEBUGGING) {
+ // //Console.WriteLine("buildCodes: "+freqs.Length);
+ // }
+
+ for (int bits = 0; bits < maxLength; bits++) {
+ nextCode[bits] = code;
+ code += bl_counts[bits] << (15 - bits);
+
+ // if (DeflaterConstants.DEBUGGING) {
+ // //Console.WriteLine("bits: " + ( bits + 1) + " count: " + bl_counts[bits]
+ // +" nextCode: "+code);
+ // }
+ }
+
+#if DebugDeflation
+ if ( DeflaterConstants.DEBUGGING && (code != 65536) )
+ {
+ throw new SharpZipBaseException("Inconsistent bl_counts!");
+ }
+#endif
+ for (int i = 0; i < numCodes; i++) {
+ int bits = length[i];
+ if (bits > 0) {
+
+ // if (DeflaterConstants.DEBUGGING) {
+ // //Console.WriteLine("codes["+i+"] = rev(" + nextCode[bits-1]+"),
+ // +bits);
+ // }
+
+ codes[i] = BitReverse(nextCode[bits - 1]);
+ nextCode[bits - 1] += 1 << (16 - bits);
+ }
+ }
+ }
+
+ public void BuildTree() {
+ int numSymbols = freqs.Length;
+
+ /* heap is a priority queue, sorted by frequency, least frequent
+ * nodes first. The heap is a binary tree, with the property, that
+ * the parent node is smaller than both child nodes. This assures
+ * that the smallest node is the first parent.
+ *
+ * The binary tree is encoded in an array: 0 is root node and
+ * the nodes 2*n+1, 2*n+2 are the child nodes of node n.
+ */
+ int[] heap = new int[numSymbols];
+ int heapLen = 0;
+ int maxCode = 0;
+ for (int n = 0; n < numSymbols; n++) {
+ int freq = freqs[n];
+ if (freq != 0) {
+ // Insert n into heap
+ int pos = heapLen++;
+ int ppos;
+ while (pos > 0 && freqs[heap[ppos = (pos - 1) / 2]] > freq) {
+ heap[pos] = heap[ppos];
+ pos = ppos;
+ }
+ heap[pos] = n;
+
+ maxCode = n;
+ }
+ }
+
+ /* We could encode a single literal with 0 bits but then we
+ * don't see the literals. Therefore we force at least two
+ * literals to avoid this case. We don't care about order in
+ * this case, both literals get a 1 bit code.
+ */
+ while (heapLen < 2) {
+ int node = maxCode < 2 ? ++maxCode : 0;
+ heap[heapLen++] = node;
+ }
+
+ numCodes = Math.Max(maxCode + 1, minNumCodes);
+
+ int numLeafs = heapLen;
+ int[] childs = new int[4 * heapLen - 2];
+ int[] values = new int[2 * heapLen - 1];
+ int numNodes = numLeafs;
+ for (int i = 0; i < heapLen; i++) {
+ int node = heap[i];
+ childs[2 * i] = node;
+ childs[2 * i + 1] = -1;
+ values[i] = freqs[node] << 8;
+ heap[i] = i;
+ }
+
+ /* Construct the Huffman tree by repeatedly combining the least two
+ * frequent nodes.
+ */
+ do {
+ int first = heap[0];
+ int last = heap[--heapLen];
+
+ // Propagate the hole to the leafs of the heap
+ int ppos = 0;
+ int path = 1;
+
+ while (path < heapLen) {
+ if (path + 1 < heapLen && values[heap[path]] > values[heap[path + 1]]) {
+ path++;
+ }
+
+ heap[ppos] = heap[path];
+ ppos = path;
+ path = path * 2 + 1;
+ }
+
+ /* Now propagate the last element down along path. Normally
+ * it shouldn't go too deep.
+ */
+ int lastVal = values[last];
+ while ((path = ppos) > 0 && values[heap[ppos = (path - 1) / 2]] > lastVal) {
+ heap[path] = heap[ppos];
+ }
+ heap[path] = last;
+
+
+ int second = heap[0];
+
+ // Create a new node father of first and second
+ last = numNodes++;
+ childs[2 * last] = first;
+ childs[2 * last + 1] = second;
+ int mindepth = Math.Min(values[first] & 0xff, values[second] & 0xff);
+ values[last] = lastVal = values[first] + values[second] - mindepth + 1;
+
+ // Again, propagate the hole to the leafs
+ ppos = 0;
+ path = 1;
+
+ while (path < heapLen) {
+ if (path + 1 < heapLen && values[heap[path]] > values[heap[path + 1]]) {
+ path++;
+ }
+
+ heap[ppos] = heap[path];
+ ppos = path;
+ path = ppos * 2 + 1;
+ }
+
+ // Now propagate the new element down along path
+ while ((path = ppos) > 0 && values[heap[ppos = (path - 1) / 2]] > lastVal) {
+ heap[path] = heap[ppos];
+ }
+ heap[path] = last;
+ } while (heapLen > 1);
+
+ if (heap[0] != childs.Length / 2 - 1) {
+ throw new Exception("Heap invariant violated");
+ }
+
+ BuildLength(childs);
+ }
+
+ /// <summary>
+ /// Get encoded length
+ /// </summary>
+ /// <returns>Encoded length, the sum of frequencies * lengths</returns>
+ public int GetEncodedLength() {
+ int len = 0;
+ for (int i = 0; i < freqs.Length; i++) {
+ len += freqs[i] * length[i];
+ }
+ return len;
+ }
+
+ /// <summary>
+ /// Scan a literal or distance tree to determine the frequencies of the codes
+ /// in the bit length tree.
+ /// </summary>
+ public void CalcBLFreq(Tree blTree) {
+ int max_count; /* max repeat count */
+ int min_count; /* min repeat count */
+ int count; /* repeat count of the current code */
+ int curlen = -1; /* length of current code */
+
+ int i = 0;
+ while (i < numCodes) {
+ count = 1;
+ int nextlen = length[i];
+ if (nextlen == 0) {
+ max_count = 138;
+ min_count = 3;
+ } else {
+ max_count = 6;
+ min_count = 3;
+ if (curlen != nextlen) {
+ blTree.freqs[nextlen]++;
+ count = 0;
+ }
+ }
+ curlen = nextlen;
+ i++;
+
+ while (i < numCodes && curlen == length[i]) {
+ i++;
+ if (++count >= max_count) {
+ break;
+ }
+ }
+
+ if (count < min_count) {
+ blTree.freqs[curlen] += (short) count;
+ } else if (curlen != 0) {
+ blTree.freqs[REP_3_6]++;
+ } else if (count <= 10) {
+ blTree.freqs[REP_3_10]++;
+ } else {
+ blTree.freqs[REP_11_138]++;
+ }
+ }
+ }
+
+ /// <summary>
+ /// Write tree values
+ /// </summary>
+ /// <param name="blTree">Tree to write</param>
+ public void WriteTree(Tree blTree) {
+ int max_count; // max repeat count
+ int min_count; // min repeat count
+ int count; // repeat count of the current code
+ int curlen = -1; // length of current code
+
+ int i = 0;
+ while (i < numCodes) {
+ count = 1;
+ int nextlen = length[i];
+ if (nextlen == 0) {
+ max_count = 138;
+ min_count = 3;
+ } else {
+ max_count = 6;
+ min_count = 3;
+ if (curlen != nextlen) {
+ blTree.WriteSymbol(nextlen);
+ count = 0;
+ }
+ }
+ curlen = nextlen;
+ i++;
+
+ while (i < numCodes && curlen == length[i]) {
+ i++;
+ if (++count >= max_count) {
+ break;
+ }
+ }
+
+ if (count < min_count) {
+ while (count-- > 0) {
+ blTree.WriteSymbol(curlen);
+ }
+ } else if (curlen != 0) {
+ blTree.WriteSymbol(REP_3_6);
+ dh.pending.WriteBits(count - 3, 2);
+ } else if (count <= 10) {
+ blTree.WriteSymbol(REP_3_10);
+ dh.pending.WriteBits(count - 3, 3);
+ } else {
+ blTree.WriteSymbol(REP_11_138);
+ dh.pending.WriteBits(count - 11, 7);
+ }
+ }
+ }
+
+ void BuildLength(int[] childs) {
+ this.length = new byte[freqs.Length];
+ int numNodes = childs.Length / 2;
+ int numLeafs = (numNodes + 1) / 2;
+ int overflow = 0;
+
+ for (int i = 0; i < maxLength; i++) {
+ bl_counts[i] = 0;
+ }
+
+ // First calculate optimal bit lengths
+ int[] lengths = new int[numNodes];
+ lengths[numNodes - 1] = 0;
+
+ for (int i = numNodes - 1; i >= 0; i--) {
+ if (childs[2 * i + 1] != -1) {
+ int bitLength = lengths[i] + 1;
+ if (bitLength > maxLength) {
+ bitLength = maxLength;
+ overflow++;
+ }
+ lengths[childs[2 * i]] = lengths[childs[2 * i + 1]] = bitLength;
+ } else {
+ // A leaf node
+ int bitLength = lengths[i];
+ bl_counts[bitLength - 1]++;
+ this.length[childs[2 * i]] = (byte) lengths[i];
+ }
+ }
+
+ // if (DeflaterConstants.DEBUGGING) {
+ // //Console.WriteLine("Tree "+freqs.Length+" lengths:");
+ // for (int i=0; i < numLeafs; i++) {
+ // //Console.WriteLine("Node "+childs[2*i]+" freq: "+freqs[childs[2*i]]
+ // + " len: "+length[childs[2*i]]);
+ // }
+ // }
+
+ if (overflow == 0) {
+ return;
+ }
+
+ int incrBitLen = maxLength - 1;
+ do {
+ // Find the first bit length which could increase:
+ while (bl_counts[--incrBitLen] == 0)
+ ;
+
+ // Move this node one down and remove a corresponding
+ // number of overflow nodes.
+ do {
+ bl_counts[incrBitLen]--;
+ bl_counts[++incrBitLen]++;
+ overflow -= 1 << (maxLength - 1 - incrBitLen);
+ } while (overflow > 0 && incrBitLen < maxLength - 1);
+ } while (overflow > 0);
+
+ /* We may have overshot above. Move some nodes from maxLength to
+ * maxLength-1 in that case.
+ */
+ bl_counts[maxLength - 1] += overflow;
+ bl_counts[maxLength - 2] -= overflow;
+
+ /* Now recompute all bit lengths, scanning in increasing
+ * frequency. It is simpler to reconstruct all lengths instead of
+ * fixing only the wrong ones. This idea is taken from 'ar'
+ * written by Haruhiko Okumura.
+ *
+ * The nodes were inserted with decreasing frequency into the childs
+ * array.
+ */
+ int nodePtr = 2 * numLeafs;
+ for (int bits = maxLength; bits != 0; bits--) {
+ int n = bl_counts[bits - 1];
+ while (n > 0) {
+ int childPtr = 2 * childs[nodePtr++];
+ if (childs[childPtr + 1] == -1) {
+ // We found another leaf
+ length[childs[childPtr]] = (byte) bits;
+ n--;
+ }
+ }
+ }
+ // if (DeflaterConstants.DEBUGGING) {
+ // //Console.WriteLine("*** After overflow elimination. ***");
+ // for (int i=0; i < numLeafs; i++) {
+ // //Console.WriteLine("Node "+childs[2*i]+" freq: "+freqs[childs[2*i]]
+ // + " len: "+length[childs[2*i]]);
+ // }
+ // }
+ }
+
+ }
+
+ #region Instance Fields
+ /// <summary>
+ /// Pending buffer to use
+ /// </summary>
+ public DeflaterPending pending;
+
+ Tree literalTree;
+ Tree distTree;
+ Tree blTree;
+
+ // Buffer for distances
+ short[] d_buf;
+ byte[] l_buf;
+ int last_lit;
+ int extra_bits;
+ #endregion
+
+ static DeflaterHuffman() {
+ // See RFC 1951 3.2.6
+ // Literal codes
+ staticLCodes = new short[LITERAL_NUM];
+ staticLLength = new byte[LITERAL_NUM];
+
+ int i = 0;
+ while (i < 144) {
+ staticLCodes[i] = BitReverse((0x030 + i) << 8);
+ staticLLength[i++] = 8;
+ }
+
+ while (i < 256) {
+ staticLCodes[i] = BitReverse((0x190 - 144 + i) << 7);
+ staticLLength[i++] = 9;
+ }
+
+ while (i < 280) {
+ staticLCodes[i] = BitReverse((0x000 - 256 + i) << 9);
+ staticLLength[i++] = 7;
+ }
+
+ while (i < LITERAL_NUM) {
+ staticLCodes[i] = BitReverse((0x0c0 - 280 + i) << 8);
+ staticLLength[i++] = 8;
+ }
+
+ // Distance codes
+ staticDCodes = new short[DIST_NUM];
+ staticDLength = new byte[DIST_NUM];
+ for (i = 0; i < DIST_NUM; i++) {
+ staticDCodes[i] = BitReverse(i << 11);
+ staticDLength[i] = 5;
+ }
+ }
+
+ /// <summary>
+ /// Construct instance with pending buffer
+ /// </summary>
+ /// <param name="pending">Pending buffer to use</param>
+ public DeflaterHuffman(DeflaterPending pending) {
+ this.pending = pending;
+
+ literalTree = new Tree(this, LITERAL_NUM, 257, 15);
+ distTree = new Tree(this, DIST_NUM, 1, 15);
+ blTree = new Tree(this, BITLEN_NUM, 4, 7);
+
+ d_buf = new short[BUFSIZE];
+ l_buf = new byte[BUFSIZE];
+ }
+
+ /// <summary>
+ /// Reset internal state
+ /// </summary>
+ public void Reset() {
+ last_lit = 0;
+ extra_bits = 0;
+ literalTree.Reset();
+ distTree.Reset();
+ blTree.Reset();
+ }
+
+ /// <summary>
+ /// Write all trees to pending buffer
+ /// </summary>
+ /// <param name="blTreeCodes">The number/rank of treecodes to send.</param>
+ public void SendAllTrees(int blTreeCodes) {
+ blTree.BuildCodes();
+ literalTree.BuildCodes();
+ distTree.BuildCodes();
+ pending.WriteBits(literalTree.numCodes - 257, 5);
+ pending.WriteBits(distTree.numCodes - 1, 5);
+ pending.WriteBits(blTreeCodes - 4, 4);
+ for (int rank = 0; rank < blTreeCodes; rank++) {
+ pending.WriteBits(blTree.length[BL_ORDER[rank]], 3);
+ }
+ literalTree.WriteTree(blTree);
+ distTree.WriteTree(blTree);
+
+#if DebugDeflation
+ if (DeflaterConstants.DEBUGGING) {
+ blTree.CheckEmpty();
+ }
+#endif
+ }
+
+ /// <summary>
+ /// Compress current buffer writing data to pending buffer
+ /// </summary>
+ public void CompressBlock() {
+ for (int i = 0; i < last_lit; i++) {
+ int litlen = l_buf[i] & 0xff;
+ int dist = d_buf[i];
+ if (dist-- != 0) {
+ // if (DeflaterConstants.DEBUGGING) {
+ // Console.Write("["+(dist+1)+","+(litlen+3)+"]: ");
+ // }
+
+ int lc = Lcode(litlen);
+ literalTree.WriteSymbol(lc);
+
+ int bits = (lc - 261) / 4;
+ if (bits > 0 && bits <= 5) {
+ pending.WriteBits(litlen & ((1 << bits) - 1), bits);
+ }
+
+ int dc = Dcode(dist);
+ distTree.WriteSymbol(dc);
+
+ bits = dc / 2 - 1;
+ if (bits > 0) {
+ pending.WriteBits(dist & ((1 << bits) - 1), bits);
+ }
+ } else {
+ // if (DeflaterConstants.DEBUGGING) {
+ // if (litlen > 32 && litlen < 127) {
+ // Console.Write("("+(char)litlen+"): ");
+ // } else {
+ // Console.Write("{"+litlen+"}: ");
+ // }
+ // }
+ literalTree.WriteSymbol(litlen);
+ }
+ }
+
+#if DebugDeflation
+ if (DeflaterConstants.DEBUGGING) {
+ Console.Write("EOF: ");
+ }
+#endif
+ literalTree.WriteSymbol(EOF_SYMBOL);
+
+#if DebugDeflation
+ if (DeflaterConstants.DEBUGGING) {
+ literalTree.CheckEmpty();
+ distTree.CheckEmpty();
+ }
+#endif
+ }
+
+ /// <summary>
+ /// Flush block to output with no compression
+ /// </summary>
+ /// <param name="stored">Data to write</param>
+ /// <param name="storedOffset">Index of first byte to write</param>
+ /// <param name="storedLength">Count of bytes to write</param>
+ /// <param name="lastBlock">True if this is the last block</param>
+ public void FlushStoredBlock(byte[] stored, int storedOffset, int storedLength, bool lastBlock) {
+#if DebugDeflation
+ // if (DeflaterConstants.DEBUGGING) {
+ // //Console.WriteLine("Flushing stored block "+ storedLength);
+ // }
+#endif
+ pending.WriteBits((DeflaterConstants.STORED_BLOCK << 1) + (lastBlock ? 1 : 0), 3);
+ pending.AlignToByte();
+ pending.WriteShort(storedLength);
+ pending.WriteShort(~storedLength);
+ pending.WriteBlock(stored, storedOffset, storedLength);
+ Reset();
+ }
+
+ /// <summary>
+ /// Flush block to output with compression
+ /// </summary>
+ /// <param name="stored">Data to flush</param>
+ /// <param name="storedOffset">Index of first byte to flush</param>
+ /// <param name="storedLength">Count of bytes to flush</param>
+ /// <param name="lastBlock">True if this is the last block</param>
+ public void FlushBlock(byte[] stored, int storedOffset, int storedLength, bool lastBlock) {
+ literalTree.freqs[EOF_SYMBOL]++;
+
+ // Build trees
+ literalTree.BuildTree();
+ distTree.BuildTree();
+
+ // Calculate bitlen frequency
+ literalTree.CalcBLFreq(blTree);
+ distTree.CalcBLFreq(blTree);
+
+ // Build bitlen tree
+ blTree.BuildTree();
+
+ int blTreeCodes = 4;
+ for (int i = 18; i > blTreeCodes; i--) {
+ if (blTree.length[BL_ORDER[i]] > 0) {
+ blTreeCodes = i + 1;
+ }
+ }
+ int opt_len = 14 + blTreeCodes * 3 + blTree.GetEncodedLength() +
+ literalTree.GetEncodedLength() + distTree.GetEncodedLength() +
+ extra_bits;
+
+ int static_len = extra_bits;
+ for (int i = 0; i < LITERAL_NUM; i++) {
+ static_len += literalTree.freqs[i] * staticLLength[i];
+ }
+ for (int i = 0; i < DIST_NUM; i++) {
+ static_len += distTree.freqs[i] * staticDLength[i];
+ }
+ if (opt_len >= static_len) {
+ // Force static trees
+ opt_len = static_len;
+ }
+
+ if (storedOffset >= 0 && storedLength + 4 < opt_len >> 3) {
+ // Store Block
+
+ // if (DeflaterConstants.DEBUGGING) {
+ // //Console.WriteLine("Storing, since " + storedLength + " < " + opt_len
+ // + " <= " + static_len);
+ // }
+ FlushStoredBlock(stored, storedOffset, storedLength, lastBlock);
+ } else if (opt_len == static_len) {
+ // Encode with static tree
+ pending.WriteBits((DeflaterConstants.STATIC_TREES << 1) + (lastBlock ? 1 : 0), 3);
+ literalTree.SetStaticCodes(staticLCodes, staticLLength);
+ distTree.SetStaticCodes(staticDCodes, staticDLength);
+ CompressBlock();
+ Reset();
+ } else {
+ // Encode with dynamic tree
+ pending.WriteBits((DeflaterConstants.DYN_TREES << 1) + (lastBlock ? 1 : 0), 3);
+ SendAllTrees(blTreeCodes);
+ CompressBlock();
+ Reset();
+ }
+ }
+
+ /// <summary>
+ /// Get value indicating if internal buffer is full
+ /// </summary>
+ /// <returns>true if buffer is full</returns>
+ public bool IsFull() {
+ return last_lit >= BUFSIZE;
+ }
+
+ /// <summary>
+ /// Add literal to buffer
+ /// </summary>
+ /// <param name="literal">Literal value to add to buffer.</param>
+ /// <returns>Value indicating internal buffer is full</returns>
+ public bool TallyLit(int literal) {
+ // if (DeflaterConstants.DEBUGGING) {
+ // if (lit > 32 && lit < 127) {
+ // //Console.WriteLine("("+(char)lit+")");
+ // } else {
+ // //Console.WriteLine("{"+lit+"}");
+ // }
+ // }
+ d_buf[last_lit] = 0;
+ l_buf[last_lit++] = (byte) literal;
+ literalTree.freqs[literal]++;
+ return IsFull();
+ }
+
+ /// <summary>
+ /// Add distance code and length to literal and distance trees
+ /// </summary>
+ /// <param name="distance">Distance code</param>
+ /// <param name="length">Length</param>
+ /// <returns>Value indicating if internal buffer is full</returns>
+ public bool TallyDist(int distance, int length) {
+ // if (DeflaterConstants.DEBUGGING) {
+ // //Console.WriteLine("[" + distance + "," + length + "]");
+ // }
+
+ d_buf[last_lit] = (short) distance;
+ l_buf[last_lit++] = (byte) (length - 3);
+
+ int lc = Lcode(length - 3);
+ literalTree.freqs[lc]++;
+ if (lc >= 265 && lc < 285) {
+ extra_bits += (lc - 261) / 4;
+ }
+
+ int dc = Dcode(distance - 1);
+ distTree.freqs[dc]++;
+ if (dc >= 4) {
+ extra_bits += dc / 2 - 1;
+ }
+ return IsFull();
+ }
+
+
+ /// <summary>
+ /// Reverse the bits of a 16 bit value.
+ /// </summary>
+ /// <param name="toReverse">Value to reverse bits</param>
+ /// <returns>Value with bits reversed</returns>
+ public static short BitReverse(int toReverse) {
+ return (short) (bit4Reverse[toReverse & 0xF] << 12 |
+ bit4Reverse[(toReverse >> 4) & 0xF] << 8 |
+ bit4Reverse[(toReverse >> 8) & 0xF] << 4 |
+ bit4Reverse[toReverse >> 12]);
+ }
+
+ static int Lcode(int length) {
+ if (length == 255) {
+ return 285;
+ }
+
+ int code = 257;
+ while (length >= 8) {
+ code += 4;
+ length >>= 1;
+ }
+ return code + length;
+ }
+
+ static int Dcode(int distance) {
+ int code = 0;
+ while (distance >= 4) {
+ code += 2;
+ distance >>= 1;
+ }
+ return code + distance;
+ }
+ }
+}
diff --git a/debian/missing-sources/plupload/csharp/Plupload/PngEncoder/DeflaterOutputStream.cs b/debian/missing-sources/plupload/csharp/Plupload/PngEncoder/DeflaterOutputStream.cs
new file mode 100644
index 0000000..4556487
--- /dev/null
+++ b/debian/missing-sources/plupload/csharp/Plupload/PngEncoder/DeflaterOutputStream.cs
@@ -0,0 +1,469 @@
+// DeflaterOutputStream.cs
+//
+// Copyright (C) 2001 Mike Krueger
+//
+// This file was translated from java, it was part of the GNU Classpath
+// Copyright (C) 2001 Free Software Foundation, Inc.
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+//
+// Linking this library statically or dynamically with other modules is
+// making a combined work based on this library. Thus, the terms and
+// conditions of the GNU General Public License cover the whole
+// combination.
+//
+// As a special exception, the copyright holders of this library give you
+// permission to link this library with independent modules to produce an
+// executable, regardless of the license terms of these independent
+// modules, and to copy and distribute the resulting executable under
+// terms of your choice, provided that you also meet, for each linked
+// independent module, the terms and conditions of the license of that
+// module. An independent module is a module which is not derived from
+// or based on this library. If you modify this library, you may extend
+// this exception to your version of the library, but you are not
+// obligated to do so. If you do not wish to do so, delete this
+// exception statement from your version.
+
+using System;
+using System.IO;
+
+namespace Plupload.PngEncoder {
+ /// <summary>
+ /// A special stream deflating or compressing the bytes that are
+ /// written to it. It uses a Deflater to perform actual deflating.<br/>
+ /// Authors of the original java version : Tom Tromey, Jochen Hoenicke
+ /// </summary>
+ public class DeflaterOutputStream : Stream {
+ #region Constructors
+ /// <summary>
+ /// Creates a new DeflaterOutputStream with a default Deflater and default buffer size.
+ /// </summary>
+ /// <param name="baseOutputStream">
+ /// the output stream where deflated output should be written.
+ /// </param>
+ public DeflaterOutputStream(Stream baseOutputStream)
+ : this(baseOutputStream, new Deflater(), 512) {
+ }
+
+ /// <summary>
+ /// Creates a new DeflaterOutputStream with the given Deflater and
+ /// default buffer size.
+ /// </summary>
+ /// <param name="baseOutputStream">
+ /// the output stream where deflated output should be written.
+ /// </param>
+ /// <param name="deflater">
+ /// the underlying deflater.
+ /// </param>
+ public DeflaterOutputStream(Stream baseOutputStream, Deflater deflater)
+ : this(baseOutputStream, deflater, 512) {
+ }
+
+ /// <summary>
+ /// Creates a new DeflaterOutputStream with the given Deflater and
+ /// buffer size.
+ /// </summary>
+ /// <param name="baseOutputStream">
+ /// The output stream where deflated output is written.
+ /// </param>
+ /// <param name="deflater">
+ /// The underlying deflater to use
+ /// </param>
+ /// <param name="bufferSize">
+ /// The buffer size to use when deflating
+ /// </param>
+ /// <exception cref="ArgumentOutOfRangeException">
+ /// bufsize is less than or equal to zero.
+ /// </exception>
+ /// <exception cref="ArgumentException">
+ /// baseOutputStream does not support writing
+ /// </exception>
+ /// <exception cref="ArgumentNullException">
+ /// deflater instance is null
+ /// </exception>
+ public DeflaterOutputStream(Stream baseOutputStream, Deflater deflater, int bufferSize) {
+ if (baseOutputStream == null) {
+ throw new ArgumentNullException("baseOutputStream");
+ }
+
+ if (baseOutputStream.CanWrite == false) {
+ throw new ArgumentException("Must support writing", "baseOutputStream");
+ }
+
+ if (deflater == null) {
+ throw new ArgumentNullException("deflater");
+ }
+
+ if (bufferSize <= 0) {
+ throw new ArgumentOutOfRangeException("bufferSize");
+ }
+
+ baseOutputStream_ = baseOutputStream;
+ buffer_ = new byte[bufferSize];
+ deflater_ = deflater;
+ }
+ #endregion
+
+ #region Public API
+ /// <summary>
+ /// Finishes the stream by calling finish() on the deflater.
+ /// </summary>
+ /// <exception cref="SharpZipBaseException">
+ /// Not all input is deflated
+ /// </exception>
+ public virtual void Finish() {
+ deflater_.Finish();
+ while (!deflater_.IsFinished) {
+ int len = deflater_.Deflate(buffer_, 0, buffer_.Length);
+ if (len <= 0) {
+ break;
+ }
+
+ if (keys != null) {
+ EncryptBlock(buffer_, 0, len);
+ }
+
+ baseOutputStream_.Write(buffer_, 0, len);
+ }
+
+ if (!deflater_.IsFinished) {
+ throw new Exception("Can't deflate all input?");
+ }
+
+ baseOutputStream_.Flush();
+
+
+ if (keys != null) {
+ keys = null;
+ }
+
+ }
+
+ /// <summary>
+ /// Get/set flag indicating ownership of the underlying stream.
+ /// When the flag is true <see cref="Close"></see> will close the underlying stream also.
+ /// </summary>
+ public bool IsStreamOwner {
+ get { return isStreamOwner_; }
+ set { isStreamOwner_ = value; }
+ }
+
+ /// <summary>
+ /// Allows client to determine if an entry can be patched after its added
+ /// </summary>
+ public bool CanPatchEntries {
+ get {
+ return baseOutputStream_.CanSeek;
+ }
+ }
+
+ #endregion
+
+ #region Encryption
+
+ string password;
+
+ uint[] keys;
+
+ /// <summary>
+ /// Get/set the password used for encryption.
+ /// </summary>
+ /// <remarks>When set to null or if the password is empty no encryption is performed</remarks>
+ public string Password {
+ get {
+ return password;
+ }
+ set {
+ if ((value != null) && (value.Length == 0)) {
+ password = null;
+ } else {
+ password = value;
+ }
+ }
+ }
+
+ /// <summary>
+ /// Encrypt a block of data
+ /// </summary>
+ /// <param name="buffer">
+ /// Data to encrypt. NOTE the original contents of the buffer are lost
+ /// </param>
+ /// <param name="offset">
+ /// Offset of first byte in buffer to encrypt
+ /// </param>
+ /// <param name="length">
+ /// Number of bytes in buffer to encrypt
+ /// </param>
+ protected void EncryptBlock(byte[] buffer, int offset, int length) {
+ for (int i = offset; i < offset + length; ++i) {
+ byte oldbyte = buffer[i];
+ buffer[i] ^= EncryptByte();
+ UpdateKeys(oldbyte);
+ }
+ }
+
+ /// <summary>
+ /// Encrypt a single byte
+ /// </summary>
+ /// <returns>
+ /// The encrypted value
+ /// </returns>
+ protected byte EncryptByte() {
+ uint temp = ((keys[2] & 0xFFFF) | 2);
+ return (byte) ((temp * (temp ^ 1)) >> 8);
+ }
+
+ /// <summary>
+ /// Update encryption keys
+ /// </summary>
+ protected void UpdateKeys(byte ch) {
+ keys[0] = Crc32.ComputeCrc32(keys[0], ch);
+ keys[1] = keys[1] + (byte) keys[0];
+ keys[1] = keys[1] * 134775813 + 1;
+ keys[2] = Crc32.ComputeCrc32(keys[2], (byte) (keys[1] >> 24));
+ }
+
+ #endregion
+
+ #region Deflation Support
+ /// <summary>
+ /// Deflates everything in the input buffers. This will call
+ /// <code>def.deflate()</code> until all bytes from the input buffers
+ /// are processed.
+ /// </summary>
+ protected void Deflate() {
+ while (!deflater_.IsNeedingInput) {
+ int deflateCount = deflater_.Deflate(buffer_, 0, buffer_.Length);
+
+ if (deflateCount <= 0) {
+ break;
+ }
+
+ if (keys != null) {
+ EncryptBlock(buffer_, 0, deflateCount);
+ }
+
+ baseOutputStream_.Write(buffer_, 0, deflateCount);
+ }
+
+ if (!deflater_.IsNeedingInput) {
+ throw new Exception("DeflaterOutputStream can't deflate all input?");
+ }
+ }
+ #endregion
+
+ #region Stream Overrides
+ /// <summary>
+ /// Gets value indicating stream can be read from
+ /// </summary>
+ public override bool CanRead {
+ get {
+ return false;
+ }
+ }
+
+ /// <summary>
+ /// Gets a value indicating if seeking is supported for this stream
+ /// This property always returns false
+ /// </summary>
+ public override bool CanSeek {
+ get {
+ return false;
+ }
+ }
+
+ /// <summary>
+ /// Get value indicating if this stream supports writing
+ /// </summary>
+ public override bool CanWrite {
+ get {
+ return baseOutputStream_.CanWrite;
+ }
+ }
+
+ /// <summary>
+ /// Get current length of stream
+ /// </summary>
+ public override long Length {
+ get {
+ return baseOutputStream_.Length;
+ }
+ }
+
+ /// <summary>
+ /// Gets the current position within the stream.
+ /// </summary>
+ /// <exception cref="NotSupportedException">Any attempt to set position</exception>
+ public override long Position {
+ get {
+ return baseOutputStream_.Position;
+ }
+ set {
+ throw new NotSupportedException("Position property not supported");
+ }
+ }
+
+ /// <summary>
+ /// Sets the current position of this stream to the given value. Not supported by this class!
+ /// </summary>
+ /// <param name="offset">The offset relative to the <paramref name="origin"/> to seek.</param>
+ /// <param name="origin">The <see cref="SeekOrigin"/> to seek from.</param>
+ /// <returns>The new position in the stream.</returns>
+ /// <exception cref="NotSupportedException">Any access</exception>
+ public override long Seek(long offset, SeekOrigin origin) {
+ throw new NotSupportedException("DeflaterOutputStream Seek not supported");
+ }
+
+ /// <summary>
+ /// Sets the length of this stream to the given value. Not supported by this class!
+ /// </summary>
+ /// <param name="value">The new stream length.</param>
+ /// <exception cref="NotSupportedException">Any access</exception>
+ public override void SetLength(long value) {
+ throw new NotSupportedException("DeflaterOutputStream SetLength not supported");
+ }
+
+ /// <summary>
+ /// Read a byte from stream advancing position by one
+ /// </summary>
+ /// <returns>The byte read cast to an int. THe value is -1 if at the end of the stream.</returns>
+ /// <exception cref="NotSupportedException">Any access</exception>
+ public override int ReadByte() {
+ throw new NotSupportedException("DeflaterOutputStream ReadByte not supported");
+ }
+
+ /// <summary>
+ /// Read a block of bytes from stream
+ /// </summary>
+ /// <param name="buffer">The buffer to store read data in.</param>
+ /// <param name="offset">The offset to start storing at.</param>
+ /// <param name="count">The maximum number of bytes to read.</param>
+ /// <returns>The actual number of bytes read. Zero if end of stream is detected.</returns>
+ /// <exception cref="NotSupportedException">Any access</exception>
+ public override int Read(byte[] buffer, int offset, int count) {
+ throw new NotSupportedException("DeflaterOutputStream Read not supported");
+ }
+
+ /// <summary>
+ /// Asynchronous reads are not supported a NotSupportedException is always thrown
+ /// </summary>
+ /// <param name="buffer">The buffer to read into.</param>
+ /// <param name="offset">The offset to start storing data at.</param>
+ /// <param name="count">The number of bytes to read</param>
+ /// <param name="callback">The async callback to use.</param>
+ /// <param name="state">The state to use.</param>
+ /// <returns>Returns an <see cref="IAsyncResult"/></returns>
+ /// <exception cref="NotSupportedException">Any access</exception>
+ public override IAsyncResult BeginRead(byte[] buffer, int offset, int count, AsyncCallback callback, object state) {
+ throw new NotSupportedException("DeflaterOutputStream BeginRead not currently supported");
+ }
+
+ /// <summary>
+ /// Asynchronous writes arent supported, a NotSupportedException is always thrown
+ /// </summary>
+ /// <param name="buffer">The buffer to write.</param>
+ /// <param name="offset">The offset to begin writing at.</param>
+ /// <param name="count">The number of bytes to write.</param>
+ /// <param name="callback">The <see cref="AsyncCallback"/> to use.</param>
+ /// <param name="state">The state object.</param>
+ /// <returns>Returns an IAsyncResult.</returns>
+ /// <exception cref="NotSupportedException">Any access</exception>
+ public override IAsyncResult BeginWrite(byte[] buffer, int offset, int count, AsyncCallback callback, object state) {
+ throw new NotSupportedException("BeginWrite is not supported");
+ }
+
+ /// <summary>
+ /// Flushes the stream by calling <see cref="DeflaterOutputStream.Flush">Flush</see> on the deflater and then
+ /// on the underlying stream. This ensures that all bytes are flushed.
+ /// </summary>
+ public override void Flush() {
+ deflater_.Flush();
+ Deflate();
+ baseOutputStream_.Flush();
+ }
+
+ /// <summary>
+ /// Calls <see cref="Finish"/> and closes the underlying
+ /// stream when <see cref="IsStreamOwner"></see> is true.
+ /// </summary>
+ public override void Close() {
+ if (!isClosed_) {
+ isClosed_ = true;
+
+ try {
+ Finish();
+
+ keys = null;
+ } finally {
+ if (isStreamOwner_) {
+ baseOutputStream_.Close();
+ }
+ }
+ }
+ }
+
+ /// <summary>
+ /// Writes a single byte to the compressed output stream.
+ /// </summary>
+ /// <param name="value">
+ /// The byte value.
+ /// </param>
+ public override void WriteByte(byte value) {
+ byte[] b = new byte[1];
+ b[0] = value;
+ Write(b, 0, 1);
+ }
+
+ /// <summary>
+ /// Writes bytes from an array to the compressed stream.
+ /// </summary>
+ /// <param name="buffer">
+ /// The byte array
+ /// </param>
+ /// <param name="offset">
+ /// The offset into the byte array where to start.
+ /// </param>
+ /// <param name="count">
+ /// The number of bytes to write.
+ /// </param>
+ public override void Write(byte[] buffer, int offset, int count) {
+ deflater_.SetInput(buffer, offset, count);
+ Deflate();
+ }
+ #endregion
+
+ #region Instance Fields
+ /// <summary>
+ /// This buffer is used temporarily to retrieve the bytes from the
+ /// deflater and write them to the underlying output stream.
+ /// </summary>
+ byte[] buffer_;
+
+ /// <summary>
+ /// The deflater which is used to deflate the stream.
+ /// </summary>
+ protected Deflater deflater_;
+
+ /// <summary>
+ /// Base stream the deflater depends on.
+ /// </summary>
+ protected Stream baseOutputStream_;
+
+ bool isClosed_;
+
+ bool isStreamOwner_ = true;
+ #endregion
+ }
+}
diff --git a/debian/missing-sources/plupload/csharp/Plupload/PngEncoder/DeflaterPending.cs b/debian/missing-sources/plupload/csharp/Plupload/PngEncoder/DeflaterPending.cs
new file mode 100644
index 0000000..3d5ea36
--- /dev/null
+++ b/debian/missing-sources/plupload/csharp/Plupload/PngEncoder/DeflaterPending.cs
@@ -0,0 +1,55 @@
+// DeflaterPending.cs
+//
+// Copyright (C) 2001 Mike Krueger
+// Copyright (C) 2004 John Reilly
+//
+// This file was translated from java, it was part of the GNU Classpath
+// Copyright (C) 2001 Free Software Foundation, Inc.
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+//
+// Linking this library statically or dynamically with other modules is
+// making a combined work based on this library. Thus, the terms and
+// conditions of the GNU General Public License cover the whole
+// combination.
+//
+// As a special exception, the copyright holders of this library give you
+// permission to link this library with independent modules to produce an
+// executable, regardless of the license terms of these independent
+// modules, and to copy and distribute the resulting executable under
+// terms of your choice, provided that you also meet, for each linked
+// independent module, the terms and conditions of the license of that
+// module. An independent module is a module which is not derived from
+// or based on this library. If you modify this library, you may extend
+// this exception to your version of the library, but you are not
+// obligated to do so. If you do not wish to do so, delete this
+// exception statement from your version.
+
+namespace Plupload.PngEncoder {
+
+ /// <summary>
+ /// This class stores the pending output of the Deflater.
+ ///
+ /// author of the original java version : Jochen Hoenicke
+ /// </summary>
+ public class DeflaterPending : PendingBuffer {
+ /// <summary>
+ /// Construct instance with default buffer size
+ /// </summary>
+ public DeflaterPending()
+ : base(DeflaterConstants.PENDING_BUF_SIZE) {
+ }
+ }
+}
diff --git a/debian/missing-sources/plupload/csharp/Plupload/PngEncoder/IChecksum.cs b/debian/missing-sources/plupload/csharp/Plupload/PngEncoder/IChecksum.cs
new file mode 100644
index 0000000..66c5111
--- /dev/null
+++ b/debian/missing-sources/plupload/csharp/Plupload/PngEncoder/IChecksum.cs
@@ -0,0 +1,90 @@
+// IChecksum.cs - Interface to compute a data checksum
+// Copyright (C) 2001 Mike Krueger
+//
+// This file was translated from java, it was part of the GNU Classpath
+// Copyright (C) 1999, 2000, 2001 Free Software Foundation, Inc.
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+//
+// Linking this library statically or dynamically with other modules is
+// making a combined work based on this library. Thus, the terms and
+// conditions of the GNU General Public License cover the whole
+// combination.
+//
+// As a special exception, the copyright holders of this library give you
+// permission to link this library with independent modules to produce an
+// executable, regardless of the license terms of these independent
+// modules, and to copy and distribute the resulting executable under
+// terms of your choice, provided that you also meet, for each linked
+// independent module, the terms and conditions of the license of that
+// module. An independent module is a module which is not derived from
+// or based on this library. If you modify this library, you may extend
+// this exception to your version of the library, but you are not
+// obligated to do so. If you do not wish to do so, delete this
+// exception statement from your version.
+
+namespace Plupload.PngEncoder {
+
+ /// <summary>
+ /// Interface to compute a data checksum used by checked input/output streams.
+ /// A data checksum can be updated by one byte or with a byte array. After each
+ /// update the value of the current checksum can be returned by calling
+ /// <code>getValue</code>. The complete checksum object can also be reset
+ /// so it can be used again with new data.
+ /// </summary>
+ public interface IChecksum {
+ /// <summary>
+ /// Returns the data checksum computed so far.
+ /// </summary>
+ long Value {
+ get;
+ }
+
+ /// <summary>
+ /// Resets the data checksum as if no update was ever called.
+ /// </summary>
+ void Reset();
+
+ /// <summary>
+ /// Adds one byte to the data checksum.
+ /// </summary>
+ /// <param name = "value">
+ /// the data value to add. The high byte of the int is ignored.
+ /// </param>
+ void Update(int value);
+
+ /// <summary>
+ /// Updates the data checksum with the bytes taken from the array.
+ /// </summary>
+ /// <param name="buffer">
+ /// buffer an array of bytes
+ /// </param>
+ void Update(byte[] buffer);
+
+ /// <summary>
+ /// Adds the byte array to the data checksum.
+ /// </summary>
+ /// <param name = "buffer">
+ /// The buffer which contains the data
+ /// </param>
+ /// <param name = "offset">
+ /// The offset in the buffer where the data starts
+ /// </param>
+ /// <param name = "count">
+ /// the number of data bytes to add.
+ /// </param>
+ void Update(byte[] buffer, int offset, int count);
+ }
+}
diff --git a/debian/missing-sources/plupload/csharp/Plupload/PngEncoder/PendingBuffer.cs b/debian/missing-sources/plupload/csharp/Plupload/PngEncoder/PendingBuffer.cs
new file mode 100644
index 0000000..d1ef02d
--- /dev/null
+++ b/debian/missing-sources/plupload/csharp/Plupload/PngEncoder/PendingBuffer.cs
@@ -0,0 +1,281 @@
+// PendingBuffer.cs
+//
+// Copyright (C) 2001 Mike Krueger
+// Copyright (C) 2004 John Reilly
+//
+// This file was translated from java, it was part of the GNU Classpath
+// Copyright (C) 2001 Free Software Foundation, Inc.
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+//
+// Linking this library statically or dynamically with other modules is
+// making a combined work based on this library. Thus, the terms and
+// conditions of the GNU General Public License cover the whole
+// combination.
+//
+// As a special exception, the copyright holders of this library give you
+// permission to link this library with independent modules to produce an
+// executable, regardless of the license terms of these independent
+// modules, and to copy and distribute the resulting executable under
+// terms of your choice, provided that you also meet, for each linked
+// independent module, the terms and conditions of the license of that
+// module. An independent module is a module which is not derived from
+// or based on this library. If you modify this library, you may extend
+// this exception to your version of the library, but you are not
+// obligated to do so. If you do not wish to do so, delete this
+// exception statement from your version.
+
+using System;
+
+namespace Plupload.PngEncoder {
+
+ /// <summary>
+ /// This class is general purpose class for writing data to a buffer.
+ ///
+ /// It allows you to write bits as well as bytes
+ /// Based on DeflaterPending.java
+ ///
+ /// author of the original java version : Jochen Hoenicke
+ /// </summary>
+ public class PendingBuffer {
+ #region Instance Fields
+ /// <summary>
+ /// Internal work buffer
+ /// </summary>
+ byte[] buffer_;
+
+ int start;
+ int end;
+
+ uint bits;
+ int bitCount;
+ #endregion
+
+ #region Constructors
+ /// <summary>
+ /// construct instance using default buffer size of 4096
+ /// </summary>
+ public PendingBuffer()
+ : this(4096) {
+ }
+
+ /// <summary>
+ /// construct instance using specified buffer size
+ /// </summary>
+ /// <param name="bufferSize">
+ /// size to use for internal buffer
+ /// </param>
+ public PendingBuffer(int bufferSize) {
+ buffer_ = new byte[bufferSize];
+ }
+
+ #endregion
+
+ /// <summary>
+ /// Clear internal state/buffers
+ /// </summary>
+ public void Reset() {
+ start = end = bitCount = 0;
+ }
+
+ /// <summary>
+ /// Write a byte to buffer
+ /// </summary>
+ /// <param name="value">
+ /// The value to write
+ /// </param>
+ public void WriteByte(int value) {
+#if DebugDeflation
+ if (DeflaterConstants.DEBUGGING && (start != 0) )
+ {
+ throw new SharpZipBaseException("Debug check: start != 0");
+ }
+#endif
+ buffer_[end++] = unchecked((byte) value);
+ }
+
+ /// <summary>
+ /// Write a short value to buffer LSB first
+ /// </summary>
+ /// <param name="value">
+ /// The value to write.
+ /// </param>
+ public void WriteShort(int value) {
+#if DebugDeflation
+ if (DeflaterConstants.DEBUGGING && (start != 0) )
+ {
+ throw new SharpZipBaseException("Debug check: start != 0");
+ }
+#endif
+ buffer_[end++] = unchecked((byte) value);
+ buffer_[end++] = unchecked((byte) (value >> 8));
+ }
+
+ /// <summary>
+ /// write an integer LSB first
+ /// </summary>
+ /// <param name="value">The value to write.</param>
+ public void WriteInt(int value) {
+#if DebugDeflation
+ if (DeflaterConstants.DEBUGGING && (start != 0) )
+ {
+ throw new SharpZipBaseException("Debug check: start != 0");
+ }
+#endif
+ buffer_[end++] = unchecked((byte) value);
+ buffer_[end++] = unchecked((byte) (value >> 8));
+ buffer_[end++] = unchecked((byte) (value >> 16));
+ buffer_[end++] = unchecked((byte) (value >> 24));
+ }
+
+ /// <summary>
+ /// Write a block of data to buffer
+ /// </summary>
+ /// <param name="block">data to write</param>
+ /// <param name="offset">offset of first byte to write</param>
+ /// <param name="length">number of bytes to write</param>
+ public void WriteBlock(byte[] block, int offset, int length) {
+#if DebugDeflation
+ if (DeflaterConstants.DEBUGGING && (start != 0) )
+ {
+ throw new SharpZipBaseException("Debug check: start != 0");
+ }
+#endif
+ System.Array.Copy(block, offset, buffer_, end, length);
+ end += length;
+ }
+
+ /// <summary>
+ /// The number of bits written to the buffer
+ /// </summary>
+ public int BitCount {
+ get {
+ return bitCount;
+ }
+ }
+
+ /// <summary>
+ /// Align internal buffer on a byte boundary
+ /// </summary>
+ public void AlignToByte() {
+#if DebugDeflation
+ if (DeflaterConstants.DEBUGGING && (start != 0) )
+ {
+ throw new SharpZipBaseException("Debug check: start != 0");
+ }
+#endif
+ if (bitCount > 0) {
+ buffer_[end++] = unchecked((byte) bits);
+ if (bitCount > 8) {
+ buffer_[end++] = unchecked((byte) (bits >> 8));
+ }
+ }
+ bits = 0;
+ bitCount = 0;
+ }
+
+ /// <summary>
+ /// Write bits to internal buffer
+ /// </summary>
+ /// <param name="b">source of bits</param>
+ /// <param name="count">number of bits to write</param>
+ public void WriteBits(int b, int count) {
+#if DebugDeflation
+ if (DeflaterConstants.DEBUGGING && (start != 0) )
+ {
+ throw new SharpZipBaseException("Debug check: start != 0");
+ }
+
+ // if (DeflaterConstants.DEBUGGING) {
+ // //Console.WriteLine("writeBits("+b+","+count+")");
+ // }
+#endif
+ bits |= (uint) (b << bitCount);
+ bitCount += count;
+ if (bitCount >= 16) {
+ buffer_[end++] = unchecked((byte) bits);
+ buffer_[end++] = unchecked((byte) (bits >> 8));
+ bits >>= 16;
+ bitCount -= 16;
+ }
+ }
+
+ /// <summary>
+ /// Write a short value to internal buffer most significant byte first
+ /// </summary>
+ /// <param name="s">value to write</param>
+ public void WriteShortMSB(int s) {
+#if DebugDeflation
+ if (DeflaterConstants.DEBUGGING && (start != 0) )
+ {
+ throw new SharpZipBaseException("Debug check: start != 0");
+ }
+#endif
+ buffer_[end++] = unchecked((byte) (s >> 8));
+ buffer_[end++] = unchecked((byte) s);
+ }
+
+ /// <summary>
+ /// Indicates if buffer has been flushed
+ /// </summary>
+ public bool IsFlushed {
+ get {
+ return end == 0;
+ }
+ }
+
+ /// <summary>
+ /// Flushes the pending buffer into the given output array. If the
+ /// output array is to small, only a partial flush is done.
+ /// </summary>
+ /// <param name="output">The output array.</param>
+ /// <param name="offset">The offset into output array.</param>
+ /// <param name="length">The maximum number of bytes to store.</param>
+ /// <returns>The number of bytes flushed.</returns>
+ public int Flush(byte[] output, int offset, int length) {
+ if (bitCount >= 8) {
+ buffer_[end++] = unchecked((byte) bits);
+ bits >>= 8;
+ bitCount -= 8;
+ }
+
+ if (length > end - start) {
+ length = end - start;
+ System.Array.Copy(buffer_, start, output, offset, length);
+ start = 0;
+ end = 0;
+ } else {
+ System.Array.Copy(buffer_, start, output, offset, length);
+ start += length;
+ }
+ return length;
+ }
+
+ /// <summary>
+ /// Convert internal buffer to byte array.
+ /// Buffer is empty on completion
+ /// </summary>
+ /// <returns>
+ /// The internal buffer contents converted to a byte array.
+ /// </returns>
+ public byte[] ToByteArray() {
+ byte[] result = new byte[end - start];
+ System.Array.Copy(buffer_, start, result, 0, result.Length);
+ start = 0;
+ end = 0;
+ return result;
+ }
+ }
+}
diff --git a/debian/missing-sources/plupload/csharp/Plupload/PngEncoder/PngEncoder.cs b/debian/missing-sources/plupload/csharp/Plupload/PngEncoder/PngEncoder.cs
new file mode 100644
index 0000000..7ef7366
--- /dev/null
+++ b/debian/missing-sources/plupload/csharp/Plupload/PngEncoder/PngEncoder.cs
@@ -0,0 +1,467 @@
+/**
+ * PngEncoder takes a pixel data byte array and creates a byte string which can be saved as a PNG file.
+ *
+ * <p>Thanks to Jay Denny at KeyPoint Software
+ * http://www.keypoint.com/
+ * who let me develop this code on company time.</p>
+ *
+ * <p>You may contact me with (probably very-much-needed) improvements,
+ * comments, and bug fixes at:</p>
+ *
+ * <p><code>david@catcode.com</code></p>
+ *
+ * <p>This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.</p>
+ *
+ * <p>This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.</p>
+ *
+ * <p>You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ * A copy of the GNU LGPL may be found at
+ * <code>http://www.gnu.org/copyleft/lesser.html</code></p>
+ *
+ * @author J. David Eisenberg
+ * @version 1.5, 19 Oct 2003
+ *
+ * CHANGES:
+ * --------
+ * 19-Nov-2002 : CODING STYLE CHANGES ONLY (by David Gilbert for Object Refinery Limited);
+ * 19-Sep-2003 : Fix for platforms using EBCDIC (contributed by Paulo Soares);
+ * 19-Oct-2003 : Change private fields to protected fields so that
+ * PngEncoderB can inherit them (JDE)
+ * Fixed bug with calculation of nRows
+ * 2009-12-22 : Ported Java version over to C#.
+ */
+
+using System;
+using System.IO;
+
+namespace Plupload.PngEncoder {
+ public class PngEncoder {
+ /** Constant specifying that alpha channel should be encoded. */
+ public const bool ENCODE_ALPHA = true;
+
+ /** Constant specifying that alpha channel should not be encoded. */
+ public const bool NO_ALPHA = false;
+
+ /** Constants for filter (NONE) */
+ public const int FILTER_NONE = 0;
+
+ /** Constants for filter (SUB) */
+ public const int FILTER_SUB = 1;
+
+ /** Constants for filter (UP) */
+ public const int FILTER_UP = 2;
+
+ /** Constants for filter (LAST) */
+ public const int FILTER_LAST = 2;
+
+ /** IHDR tag. */
+ protected static byte[] IHDR = new byte[] { 73, 72, 68, 82 };
+
+ /** IDAT tag. */
+ protected static byte[] IDAT = new byte[] { 73, 68, 65, 84 };
+
+ /** IEND tag. */
+ protected static byte[] IEND = new byte[] { 73, 69, 78, 68 };
+
+ /** The png bytes. */
+ protected byte[] pngBytes;
+
+ /** The prior row. */
+ protected byte[] priorRow;
+
+ /** The left bytes. */
+ protected byte[] leftBytes;
+
+ /** The width. */
+ protected int width, height;
+
+ /** The byte position. */
+ protected int bytePos, maxPos;
+
+ /** CRC. */
+ protected Crc32 crc = new Crc32();
+
+ /** The CRC value. */
+ protected long crcValue;
+
+ /** Encode alpha? */
+ protected bool encodeAlpha;
+
+ /** The filter type. */
+ protected int filter;
+
+ /** The bytes-per-pixel. */
+ protected int bytesPerPixel;
+
+ /** The compression level. */
+ protected int compressionLevel;
+
+ /** PixelData array to encode */
+ protected int[] pixelData;
+
+ /**
+ * Class constructor specifying Image source to encode, whether to encode alpha, filter to use,
+ * and compression level.
+ *
+ * @param pixel_data A Java Image object
+ * @param encodeAlpha Encode the alpha channel? false=no; true=yes
+ * @param whichFilter 0=none, 1=sub, 2=up
+ * @param compLevel 0..9
+ * @see java.awt.Image
+ */
+ public PngEncoder(int[] pixel_data, int width, int height, bool encodeAlpha, int whichFilter, int compLevel) {
+ this.pixelData = pixel_data;
+ this.width = width;
+ this.height = height;
+ this.encodeAlpha = encodeAlpha;
+
+ this.filter = FILTER_NONE;
+ if (whichFilter <= FILTER_LAST) {
+ this.filter = whichFilter;
+ }
+
+ if (compLevel >= 0 && compLevel <= 9) {
+ this.compressionLevel = compLevel;
+ }
+ }
+
+ /**
+ * Creates an array of bytes that is the PNG equivalent of the current image, specifying
+ * whether to encode alpha or not.
+ *
+ * @param encodeAlpha boolean false=no alpha, true=encode alpha
+ * @return an array of bytes, or null if there was a problem
+ */
+ public byte[] Encode(bool encodeAlpha) {
+ byte[] pngIdBytes = { 0x89, 0x50, 0x4E, 0x47, 0x0D, 0x0A, 0x1A, 0x0A };
+
+ /*
+ * start with an array that is big enough to hold all the pixels
+ * (plus filter bytes), and an extra 200 bytes for header info
+ */
+ pngBytes = new byte[((width + 1) * height * 3) + 200];
+
+ /*
+ * keep track of largest byte written to the array
+ */
+ maxPos = 0;
+
+ bytePos = WriteBytes(pngIdBytes, 0);
+ //hdrPos = bytePos;
+ writeHeader();
+ //dataPos = bytePos;
+ if (WriteImageData()) {
+ writeEnd();
+ pngBytes = ResizeByteArray(pngBytes, maxPos);
+ } else {
+ pngBytes = null;
+ }
+ return pngBytes;
+ }
+
+ /**
+ * Creates an array of bytes that is the PNG equivalent of the current image.
+ * Alpha encoding is determined by its setting in the constructor.
+ *
+ * @return an array of bytes, or null if there was a problem
+ */
+ public byte[] pngEncode() {
+ return Encode(encodeAlpha);
+ }
+
+ /**
+ * Increase or decrease the length of a byte array.
+ *
+ * @param array The original array.
+ * @param newLength The length you wish the new array to have.
+ * @return Array of newly desired length. If shorter than the
+ * original, the trailing elements are truncated.
+ */
+ protected byte[] ResizeByteArray(byte[] array, int newLength) {
+ byte[] newArray = new byte[newLength];
+ int oldLength = array.Length;
+
+ Array.Copy(array, 0, newArray, 0, Math.Min(oldLength, newLength));
+ return newArray;
+ }
+
+ /**
+ * Write an array of bytes into the pngBytes array.
+ * Note: This routine has the side effect of updating
+ * maxPos, the largest element written in the array.
+ * The array is resized by 1000 bytes or the length
+ * of the data to be written, whichever is larger.
+ *
+ * @param data The data to be written into pngBytes.
+ * @param offset The starting point to write to.
+ * @return The next place to be written to in the pngBytes array.
+ */
+ protected int WriteBytes(byte[] data, int offset) {
+ maxPos = Math.Max(maxPos, offset + data.Length);
+ if (data.Length + offset > pngBytes.Length)
+ pngBytes = ResizeByteArray(pngBytes, pngBytes.Length + Math.Max(1000, data.Length));
+
+ Array.Copy(data, 0, pngBytes, offset, data.Length);
+ return offset + data.Length;
+ }
+
+ /**
+ * Write an array of bytes into the pngBytes array, specifying number of bytes to write.
+ * Note: This routine has the side effect of updating
+ * maxPos, the largest element written in the array.
+ * The array is resized by 1000 bytes or the length
+ * of the data to be written, whichever is larger.
+ *
+ * @param data The data to be written into pngBytes.
+ * @param nBytes The number of bytes to be written.
+ * @param offset The starting point to write to.
+ * @return The next place to be written to in the pngBytes array.
+ */
+ protected int WriteBytes(byte[] data, int nBytes, int offset) {
+ maxPos = Math.Max(maxPos, offset + nBytes);
+ if (nBytes + offset > pngBytes.Length)
+ pngBytes = ResizeByteArray(pngBytes, pngBytes.Length + Math.Max(1000, nBytes));
+
+ Array.Copy(data, 0, pngBytes, offset, nBytes);
+ return offset + nBytes;
+ }
+
+ /**
+ * Write a two-byte integer into the pngBytes array at a given position.
+ *
+ * @param n The integer to be written into pngBytes.
+ * @param offset The starting point to write to.
+ * @return The next place to be written to in the pngBytes array.
+ */
+ protected int WriteInt2(int n, int offset) {
+ byte[] temp = { (byte) ((n >> 8) & 0xff), (byte) (n & 0xff) };
+
+ return WriteBytes(temp, offset);
+ }
+
+ /**
+ * Write a four-byte integer into the pngBytes array at a given position.
+ *
+ * @param n The integer to be written into pngBytes.
+ * @param offset The starting point to write to.
+ * @return The next place to be written to in the pngBytes array.
+ */
+ protected int WriteInt4(int n, int offset) {
+ byte[] temp = {(byte) ((n >> 24) & 0xff),
+ (byte) ((n >> 16) & 0xff),
+ (byte) ((n >> 8) & 0xff),
+ (byte) (n & 0xff)};
+
+ return WriteBytes(temp, offset);
+ }
+
+ /**
+ * Write a single byte into the pngBytes array at a given position.
+ *
+ * @param b The integer to be written into pngBytes.
+ * @param offset The starting point to write to.
+ * @return The next place to be written to in the pngBytes array.
+ */
+ protected int WriteByte(int b, int offset) {
+ byte[] temp = { (byte) b };
+
+ return WriteBytes(temp, offset);
+ }
+
+ /**
+ * Write a PNG "IHDR" chunk into the pngBytes array.
+ */
+ protected void writeHeader() {
+ int startPos;
+
+ startPos = bytePos = WriteInt4(13, bytePos);
+
+ bytePos = WriteBytes(IHDR, bytePos);
+ bytePos = WriteInt4(width, bytePos);
+ bytePos = WriteInt4(height, bytePos);
+ bytePos = WriteByte(8, bytePos); // bit depth
+ bytePos = WriteByte((encodeAlpha) ? 6 : 2, bytePos); // direct model
+ bytePos = WriteByte(0, bytePos); // compression method
+ bytePos = WriteByte(0, bytePos); // filter method
+ bytePos = WriteByte(0, bytePos); // no interlace
+
+ crc.Reset();
+ crc.Update(pngBytes, startPos, bytePos - startPos);
+ crcValue = crc.Value;
+
+ bytePos = WriteInt4((int) crcValue, bytePos);
+ }
+
+ /**
+ * Perform "sub" filtering on the given row.
+ * Uses temporary array leftBytes to store the original values
+ * of the previous pixels. The array is 16 bytes long, which
+ * will easily hold two-byte samples plus two-byte alpha.
+ *
+ * @param pixels The array holding the scan lines being built
+ * @param startPos Starting position within pixels of bytes to be filtered.
+ * @param width Width of a scanline in pixels.
+ */
+ protected void FilterSub(byte[] pixels, int startPos, int width) {
+ int i;
+ int offset = bytesPerPixel;
+ int actualStart = startPos + offset;
+ int nBytes = width * bytesPerPixel;
+ int leftInsert = offset;
+ int leftExtract = 0;
+
+ for (i = actualStart; i < startPos + nBytes; i++) {
+ leftBytes[leftInsert] = pixels[i];
+ pixels[i] = (byte) ((pixels[i] - leftBytes[leftExtract]) % 256);
+ leftInsert = (leftInsert + 1) % 0x0f;
+ leftExtract = (leftExtract + 1) % 0x0f;
+ }
+ }
+
+ /**
+ * Perform "up" filtering on the given row.
+ * Side effect: refills the prior row with current row
+ *
+ * @param pixels The array holding the scan lines being built
+ * @param startPos Starting position within pixels of bytes to be filtered.
+ * @param width Width of a scanline in pixels.
+ */
+ protected void FilterUp(byte[] pixels, int startPos, int width) {
+ int i, nBytes;
+ byte currentByte;
+
+ nBytes = width * bytesPerPixel;
+
+ for (i = 0; i < nBytes; i++) {
+ currentByte = pixels[startPos + i];
+ pixels[startPos + i] = (byte) ((pixels[startPos + i] - priorRow[i]) % 256);
+ priorRow[i] = currentByte;
+ }
+ }
+
+ /**
+ * Write the image data into the pngBytes array.
+ * This will write one or more PNG "IDAT" chunks. In order
+ * to conserve memory, this method grabs as many rows as will
+ * fit into 32K bytes, or the whole image; whichever is less.
+ *
+ *
+ * @return true if no errors; false if error grabbing pixels
+ */
+ protected bool WriteImageData() {
+ int rowsLeft = height; // number of rows remaining to write
+ int startRow = 0; // starting row to process this time through
+ int nRows; // how many rows to grab at a time
+
+ byte[] scanLines; // the scan lines to be compressed
+ int scanPos; // where we are in the scan lines
+ int startPos; // where this line's actual pixels start (used for filtering)
+
+ byte[] compressedLines; // the resultant compressed lines
+ int nCompressed; // how big is the compressed area?
+
+ //int depth; // color depth ( handle only 8 or 32 )
+
+ bytesPerPixel = (encodeAlpha) ? 4 : 3;
+
+ Deflater scrunch = new Deflater(compressionLevel);
+ MemoryStream outBytes = new MemoryStream(1024);
+
+ DeflaterOutputStream compBytes = new DeflaterOutputStream(outBytes, scrunch);
+ try {
+ while (rowsLeft > 0) {
+ nRows = Math.Min(32767 / (width * (bytesPerPixel + 1)), rowsLeft);
+ nRows = Math.Max(nRows, 1);
+
+ int[] pixels = new int[width * nRows];
+ Array.Copy(this.pixelData, width * startRow, pixels, 0, width * nRows);
+
+ /*
+ * Create a data chunk. scanLines adds "nRows" for
+ * the filter bytes.
+ */
+ scanLines = new byte[width * nRows * bytesPerPixel + nRows];
+
+ if (filter == FILTER_SUB) {
+ leftBytes = new byte[16];
+ }
+ if (filter == FILTER_UP) {
+ priorRow = new byte[width * bytesPerPixel];
+ }
+
+ scanPos = 0;
+ startPos = 1;
+ for (int i = 0; i < width * nRows; i++) {
+ if (i % width == 0) {
+ scanLines[scanPos++] = (byte) filter;
+ startPos = scanPos;
+ }
+ scanLines[scanPos++] = (byte) ((pixels[i] >> 16) & 0xff);
+ scanLines[scanPos++] = (byte) ((pixels[i] >> 8) & 0xff);
+ scanLines[scanPos++] = (byte) ((pixels[i]) & 0xff);
+ if (encodeAlpha) {
+ scanLines[scanPos++] = (byte) ((pixels[i] >> 24) & 0xff);
+ }
+ if ((i % width == width - 1) && (filter != FILTER_NONE)) {
+ if (filter == FILTER_SUB) {
+ FilterSub(scanLines, startPos, width);
+ }
+ if (filter == FILTER_UP) {
+ FilterUp(scanLines, startPos, width);
+ }
+ }
+ }
+
+ /*
+ * Write these lines to the output area
+ */
+ compBytes.Write(scanLines, 0, scanPos);
+
+ startRow += nRows;
+ rowsLeft -= nRows;
+ }
+ compBytes.Close();
+
+ /*
+ * Write the compressed bytes
+ */
+ compressedLines = outBytes.ToArray();
+ nCompressed = compressedLines.Length;
+
+ crc.Reset();
+ bytePos = WriteInt4(nCompressed, bytePos);
+ bytePos = WriteBytes(IDAT, bytePos);
+ crc.Update(IDAT);
+ bytePos = WriteBytes(compressedLines, nCompressed, bytePos);
+ crc.Update(compressedLines, 0, nCompressed);
+
+ crcValue = crc.Value;
+ bytePos = WriteInt4((int) crcValue, bytePos);
+ scrunch.Finish();
+ return true;
+ } catch {
+ return false;
+ }
+ }
+
+ /**
+ * Write a PNG "IEND" chunk into the pngBytes array.
+ */
+ protected void writeEnd() {
+ bytePos = WriteInt4(0, bytePos);
+ bytePos = WriteBytes(IEND, bytePos);
+ crc.Reset();
+ crc.Update(IEND);
+ crcValue = crc.Value;
+ bytePos = WriteInt4((int) crcValue, bytePos);
+ }
+ }
+} \ No newline at end of file
diff --git a/debian/missing-sources/plupload/csharp/Plupload/Properties/AppManifest.xml b/debian/missing-sources/plupload/csharp/Plupload/Properties/AppManifest.xml
new file mode 100644
index 0000000..1b45a1d
--- /dev/null
+++ b/debian/missing-sources/plupload/csharp/Plupload/Properties/AppManifest.xml
@@ -0,0 +1,6 @@
+<Deployment xmlns="http://schemas.microsoft.com/client/2007/deployment"
+ xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
+ ExternalCallersFromCrossDomain="ScriptableOnly">
+ <Deployment.Parts>
+ </Deployment.Parts>
+</Deployment> \ No newline at end of file
diff --git a/debian/missing-sources/plupload/csharp/Plupload/Properties/AssemblyInfo.cs b/debian/missing-sources/plupload/csharp/Plupload/Properties/AssemblyInfo.cs
new file mode 100644
index 0000000..005e313
--- /dev/null
+++ b/debian/missing-sources/plupload/csharp/Plupload/Properties/AssemblyInfo.cs
@@ -0,0 +1,45 @@
+/**
+ * $Id: AssemblyInfo.cs 480 2008-10-20 15:37:42Z spocke $
+ *
+ * @package MCManagerCore
+ * @author Moxiecode
+ * @copyright Copyright © 2007, Moxiecode Systems AB, All rights reserved.
+ */
+
+using System.Reflection;
+using System.Runtime.CompilerServices;
+using System.Runtime.InteropServices;
+
+// General Information about an assembly is controlled through the following
+// set of attributes. Change these attribute values to modify the information
+// associated with an assembly.
+[assembly: AssemblyTitle("Plupload")]
+[assembly: AssemblyDescription("Multiple upload component.")]
+[assembly: AssemblyConfiguration("")]
+[assembly: AssemblyCompany("Moxiecode Systems AB")]
+[assembly: AssemblyProduct("Upload")]
+[assembly: AssemblyCopyright("Copyright © 2009")]
+[assembly: AssemblyTrademark("")]
+[assembly: AssemblyCulture("")]
+
+// Setting ComVisible to false makes the types in this assembly not visible
+// to COM components. If you need to access a type in this assembly from
+// COM, set the ComVisible attribute to true on that type.
+[assembly: ComVisible(false)]
+
+// The following GUID is for the ID of the typelib if this project is exposed to COM
+[assembly: Guid("95f0dee8-de7a-46c5-9dcc-0570b0fc4643")]
+
+// Version information for an assembly consists of the following four values:
+//
+// Major Version
+// Minor Version
+// Build Number
+// Revision
+//
+// You can specify all the values or you can default the Revision and Build Numbers
+// by using the '*' as shown below:
+// [assembly: AssemblyVersion("1.0.*")]
+
+[assembly: AssemblyVersion("1.0.0.0")]
+[assembly: AssemblyFileVersion("1.0.0.0")]
diff --git a/debian/missing-sources/plupload/csharp/Plupload/Utils/JsonReader.cs b/debian/missing-sources/plupload/csharp/Plupload/Utils/JsonReader.cs
new file mode 100644
index 0000000..659c4fe
--- /dev/null
+++ b/debian/missing-sources/plupload/csharp/Plupload/Utils/JsonReader.cs
@@ -0,0 +1,486 @@
+/*
+ * $Id: JSONReader.cs 9 2007-05-27 10:47:07Z spocke $
+ *
+ * Copyright © 2007, Moxiecode Systems AB, All rights reserved.
+ */
+
+using System;
+using System.IO;
+using System.Text;
+using System.Collections;
+using System.Collections.Generic;
+
+namespace Moxiecode.Plupload.Utils {
+ class Stack {
+ private List<object> items;
+
+ public Stack() {
+ items = new List<object>();
+ }
+
+ public void Push(object item) {
+ items.Add(item);
+ }
+
+ public object Pop() {
+ object item = items[items.Count - 1];
+
+ items.RemoveAt(items.Count - 1);
+
+ return item;
+ }
+ }
+
+ /// <summary>
+ ///
+ /// </summary>
+ public enum JsonLocation {
+ /// <summary> </summary>
+ InArray,
+
+ /// <summary> </summary>
+ InObject,
+
+ /// <summary> </summary>
+ Normal
+ }
+
+ /// <summary>
+ ///
+ /// </summary>
+ public enum JsonToken {
+ /// <summary> </summary>
+ Boolean,
+
+ /// <summary> </summary>
+ Integer,
+
+ /// <summary> </summary>
+ String,
+
+ /// <summary> </summary>
+ Null,
+
+ /// <summary> </summary>
+ Float,
+
+ /// <summary> </summary>
+ StartArray,
+
+ /// <summary> </summary>
+ EndArray,
+
+ /// <summary> </summary>
+ PropertyName,
+
+ /// <summary> </summary>
+ StartObject,
+
+ /// <summary> </summary>
+ EndObject
+ }
+
+ /// <summary>
+ /// Description of JSONReader.
+ /// </summary>
+ public class JsonReader {
+ private TextReader reader;
+ private JsonToken token;
+ private object val;
+ private JsonLocation location;
+ private Stack lastLocations;
+ private bool needProp;
+
+ /// <summary>
+ ///
+ /// </summary>
+ /// <param name="reader"></param>
+ public JsonReader(TextReader reader) {
+ this.reader = reader;
+ this.val = null;
+ this.token = JsonToken.Null;
+ this.location = JsonLocation.Normal;
+ this.lastLocations = new Stack();
+ this.needProp = false;
+ }
+
+ public static object ParseJson(String json) {
+ JsonReader reader = new JsonReader(new StringReader(json));
+
+ return reader.ReadValue();
+ }
+
+ /// <summary>
+ ///
+ /// </summary>
+ public JsonLocation Location {
+ get { return location; }
+ }
+
+ /// <summary>
+ ///
+ /// </summary>
+ public JsonToken TokenType {
+ get {
+ return this.token;
+ }
+ }
+
+ /// <summary>
+ ///
+ /// </summary>
+ public object Value {
+ get {
+ return this.val;
+ }
+ }
+
+ /// <summary>
+ ///
+ /// </summary>
+ /// <returns></returns>
+ public bool Read() {
+ int chr = this.reader.Read();
+
+ if (chr != -1) {
+ switch ((char) chr) {
+ case '[':
+ this.lastLocations.Push(this.location);
+ this.location = JsonLocation.InArray;
+ this.token = JsonToken.StartArray;
+ this.val = null;
+ this.ReadAway();
+ return true;
+
+ case ']':
+ this.location = (JsonLocation)this.lastLocations.Pop();
+ this.token = JsonToken.EndArray;
+ this.val = null;
+ this.ReadAway();
+
+ if (this.location == JsonLocation.InObject)
+ this.needProp = true;
+
+ return true;
+
+ case '{':
+ this.lastLocations.Push(this.location);
+ this.location = JsonLocation.InObject;
+ this.needProp = true;
+ this.token = JsonToken.StartObject;
+ this.val = null;
+ this.ReadAway();
+ return true;
+
+ case '}':
+ this.location = (JsonLocation) this.lastLocations.Pop();
+ this.token = JsonToken.EndObject;
+ this.val = null;
+ this.ReadAway();
+
+ if (this.location == JsonLocation.InObject)
+ this.needProp = true;
+
+ return true;
+
+ // String
+ case '"':
+ case '\'':
+ return this.ReadString((char) chr);
+
+ // Null
+ case 'n':
+ return this.ReadNull();
+
+ // Bool
+ case 't':
+ case 'f':
+ return this.ReadBool((char) chr);
+
+ default:
+ // Is number
+ if (Char.IsNumber((char) chr) || (char) chr == '-' || (char) chr == '.')
+ return this.ReadNumber((char) chr);
+
+ return true;
+ }
+ }
+
+ return false;
+ }
+
+ /// <summary>
+ ///
+ /// </summary>
+ /// <returns></returns>
+ public override string ToString() {
+ switch (this.token) {
+ case JsonToken.Boolean:
+ return "[Boolean] = " + ((bool) this.Value ? "true" : "false");
+
+ case JsonToken.EndArray:
+ return "[EndArray]";
+
+ case JsonToken.EndObject:
+ return "[EndObject]";
+
+ case JsonToken.Float:
+ return "[Float] = " + Convert.ToDouble(this.Value);
+
+ case JsonToken.Integer:
+ return "[Integer] = " + ((int) this.Value);
+
+ case JsonToken.Null:
+ return "[Null]";
+
+ case JsonToken.StartArray:
+ return "[StartArray]";
+
+ case JsonToken.StartObject:
+ return "[StartObject]";
+
+ case JsonToken.String:
+ return "[String]" + (string) this.Value;
+
+ case JsonToken.PropertyName:
+ return "[PropertyName]" + (string) this.Value;
+ }
+
+ return base.ToString();
+ }
+
+ #region private methods
+
+ private bool ReadString(char quote) {
+ StringBuilder buff = new StringBuilder();
+ this.token = JsonToken.String;
+ bool endString = false;
+ int chr;
+
+ while ((chr = this.reader.Peek()) != -1) {
+ switch (chr) {
+ case '\\':
+ // Read away slash
+ chr = this.reader.Read();
+
+ // Read escape code
+ chr = this.reader.Read();
+ switch (chr) {
+ case 't':
+ buff.Append('\t');
+ break;
+
+ case 'b':
+ buff.Append('\b');
+ break;
+
+ case 'f':
+ buff.Append('\f');
+ break;
+
+ case 'r':
+ buff.Append('\r');
+ break;
+
+ case 'n':
+ buff.Append('\n');
+ break;
+
+ case 'u':
+ buff.Append((char) Convert.ToInt32(ReadLen(4), 16));
+ break;
+
+ default:
+ buff.Append((char) chr);
+ break;
+ }
+
+ break;
+
+ case '\'':
+ case '"':
+ if (chr == quote)
+ endString = true;
+
+ chr = this.reader.Read();
+ if (chr != -1 && chr != quote)
+ buff.Append((char) chr);
+
+ break;
+
+ default:
+ buff.Append((char) this.reader.Read());
+ break;
+ }
+
+ // String terminated
+ if (endString)
+ break;
+ }
+
+ this.ReadAway();
+
+ this.val = buff.ToString();
+
+ // Needed a property
+ if (this.needProp) {
+ this.token = JsonToken.PropertyName;
+ this.needProp = false;
+ return true;
+ }
+
+ if (this.location == JsonLocation.InObject && !this.needProp)
+ this.needProp = true;
+
+ return true;
+ }
+
+ private bool ReadNull() {
+ this.token = JsonToken.Null;
+ this.val = null;
+
+ this.ReadAway(3); // ull
+ this.ReadAway();
+
+ if (this.location == JsonLocation.InObject && !this.needProp)
+ this.needProp = true;
+
+ return true;
+ }
+
+ private bool ReadNumber(char start) {
+ StringBuilder buff = new StringBuilder();
+ int chr;
+ bool isFloat = false;
+
+ this.token = JsonToken.Integer;
+ buff.Append(start);
+
+ while ((chr = this.reader.Peek()) != -1) {
+ if (Char.IsNumber((char) chr) || (char) chr == '-' || (char) chr == '.') {
+ if (((char) chr) == '.')
+ isFloat = true;
+
+ buff.Append((char) this.reader.Read());
+ } else
+ break;
+ }
+
+ this.ReadAway();
+
+ if (isFloat) {
+ this.token = JsonToken.Float;
+ this.val = Convert.ToDouble(buff.ToString().Replace('.', ','));
+ } else
+ this.val = Convert.ToInt32(buff.ToString());
+
+ if (this.location == JsonLocation.InObject && !this.needProp)
+ this.needProp = true;
+
+ return true;
+ }
+
+ private bool ReadBool(char chr) {
+ this.token = JsonToken.Boolean;
+ this.val = chr == 't';
+
+ if (chr == 't')
+ this.ReadAway(3); // rue
+ else
+ this.ReadAway(4); // alse
+
+ this.ReadAway();
+
+ if (this.location == JsonLocation.InObject && !this.needProp)
+ this.needProp = true;
+
+ return true;
+ }
+
+ private void ReadAway() {
+ int chr;
+
+ while ((chr = this.reader.Peek()) != -1) {
+ if (chr != ':' && chr != ',' && !Char.IsWhiteSpace((char) chr))
+ break;
+
+ this.reader.Read();
+ }
+ }
+
+ private string ReadLen(int num) {
+ StringBuilder buff = new StringBuilder();
+ int chr;
+
+ for (int i=0; i<num && (chr = this.reader.Read()) != -1; i++)
+ buff.Append((char) chr);
+
+ return buff.ToString();
+ }
+
+ private void ReadAway(int num) {
+ for (int i=0; i<num && this.reader.Read() != -1; i++) ;
+ }
+
+ private object ReadValue() {
+ Stack parents = new Stack();
+ object cur = null;
+ string key = null;
+ object obj;
+
+ while (this.Read()) {
+ switch (this.TokenType) {
+ case JsonToken.Boolean:
+ case JsonToken.Integer:
+ case JsonToken.String:
+ case JsonToken.Float:
+ case JsonToken.Null:
+ if (cur is Dictionary<string, object>) {
+ ((Dictionary<string, object>)cur)[key] = this.Value;
+ } else if (cur is List<object>)
+ ((List<object>) cur).Add(this.Value);
+ else
+ return this.Value;
+
+ break;
+
+ case JsonToken.PropertyName:
+ key = (string) this.Value;
+ break;
+
+ case JsonToken.StartArray:
+ case JsonToken.StartObject:
+ if (this.TokenType == JsonToken.StartObject) {
+ obj = new Dictionary<string, object>();
+ } else {
+ obj = new List<object>();
+ }
+
+ if (cur is Dictionary<string, object>) {
+ ((Dictionary<string, object>)cur)[key] = obj;
+ } else if (cur is List<object>) {
+ ((List<object>)cur).Add(obj);
+ }
+
+ parents.Push(cur);
+ cur = obj;
+
+ break;
+
+ case JsonToken.EndArray:
+ case JsonToken.EndObject:
+ obj = parents.Pop();
+
+ if (obj != null)
+ cur = obj;
+
+ break;
+ }
+ }
+
+ return cur;
+ }
+
+ #endregion
+ }
+}
diff --git a/debian/missing-sources/plupload/flash/plupload/Plupload.as3proj b/debian/missing-sources/plupload/flash/plupload/Plupload.as3proj
new file mode 100644
index 0000000..7dc2ba0
--- /dev/null
+++ b/debian/missing-sources/plupload/flash/plupload/Plupload.as3proj
@@ -0,0 +1,85 @@
+<?xml version="1.0" encoding="utf-8"?>
+<project>
+ <!-- Output SWF options -->
+ <output>
+ <movie disabled="False" />
+ <movie input="" />
+ <movie path="..\..\..\js\plupload.flash.swf" />
+ <movie fps="30" />
+ <movie width="800" />
+ <movie height="600" />
+ <movie version="10" />
+ <movie background="#FFFFFF" />
+ </output>
+ <!-- Other classes to be compiled into your SWF -->
+ <classpaths>
+ <class path="src" />
+ </classpaths>
+ <!-- Build options -->
+ <build>
+ <option accessible="False" />
+ <option allowSourcePathOverlap="False" />
+ <option benchmark="False" />
+ <option es="False" />
+ <option locale="" />
+ <option loadConfig="" />
+ <option optimize="True" />
+ <option showActionScriptWarnings="True" />
+ <option showBindingWarnings="True" />
+ <option showInvalidCSS="True" />
+ <option showDeprecationWarnings="True" />
+ <option showUnusedTypeSelectorWarnings="True" />
+ <option strict="True" />
+ <option useNetwork="True" />
+ <option useResourceBundleMetadata="True" />
+ <option warnings="True" />
+ <option verboseStackTraces="False" />
+ <option linkReport="" />
+ <option loadExterns="" />
+ <option staticLinkRSL="True" />
+ <option additional="" />
+ <option compilerConstants="" />
+ <option customSDK="" />
+ </build>
+ <!-- SWC Include Libraries -->
+ <includeLibraries>
+ <!-- example: <element path="..." /> -->
+ </includeLibraries>
+ <!-- SWC Libraries -->
+ <libraryPaths>
+ <!-- example: <element path="..." /> -->
+ </libraryPaths>
+ <!-- External Libraries -->
+ <externalLibraryPaths>
+ <!-- example: <element path="..." /> -->
+ </externalLibraryPaths>
+ <!-- Runtime Shared Libraries -->
+ <rslPaths>
+ <!-- example: <element path="..." /> -->
+ </rslPaths>
+ <!-- Intrinsic Libraries -->
+ <intrinsics>
+ <!-- example: <element path="..." /> -->
+ </intrinsics>
+ <!-- Assets to embed into the output SWF -->
+ <library>
+ <!-- example: <asset path="..." id="..." update="..." glyphs="..." mode="..." place="..." sharepoint="..." /> -->
+ </library>
+ <!-- Class files to compile (other referenced classes will automatically be included) -->
+ <compileTargets>
+ <compile path="src\com\plupload\Plupload.as" />
+ </compileTargets>
+ <!-- Paths to exclude from the Project Explorer tree -->
+ <hiddenPaths>
+ <!-- example: <hidden path="..." /> -->
+ </hiddenPaths>
+ <!-- Executed before build -->
+ <preBuildCommand />
+ <!-- Executed after build -->
+ <postBuildCommand alwaysRun="False" />
+ <!-- Other project options -->
+ <options>
+ <option showHiddenPaths="False" />
+ <option testMovie="Default" />
+ </options>
+</project> \ No newline at end of file
diff --git a/debian/missing-sources/plupload/flash/plupload/build.sh b/debian/missing-sources/plupload/flash/plupload/build.sh
new file mode 100755
index 0000000..ec0ae46
--- /dev/null
+++ b/debian/missing-sources/plupload/flash/plupload/build.sh
@@ -0,0 +1,21 @@
+#!/bin/sh
+
+if [ -z "$FLEX_HOME" ]; then
+ FLEX_HOME=/opt/flex/flex
+fi
+
+export FLEX_HOME
+
+$FLEX_HOME/bin/mxmlc \
+ -compiler.source-path src \
+ -compiler.optimize \
+ -compiler.use-resource-bundle-metadata \
+ -compiler.show-actionscript-warnings \
+ -compiler.show-binding-warnings \
+ -compiler.show-unused-type-selector-warnings \
+ -compiler.strict \
+ -compiler.accessible=false \
+ -use-network \
+ -static-link-runtime-shared-libraries \
+ -output ../../../js/plupload.flash.swf \
+ src/com/plupload/Plupload.as
diff --git a/debian/missing-sources/plupload/flash/plupload/build.vbs b/debian/missing-sources/plupload/flash/plupload/build.vbs
new file mode 100644
index 0000000..51d96cf
--- /dev/null
+++ b/debian/missing-sources/plupload/flash/plupload/build.vbs
@@ -0,0 +1,83 @@
+' http://todayguesswhat.blogspot.com.br/2012/08/windows-7-replacement-for.html
+strComputer = "."
+
+Set objFSO = CreateObject("Scripting.FileSystemObject")
+Set objShell = CreateObject("Shell.Application")
+Set objWSShell = CreateObject("WScript.Shell")
+
+strScriptFile = Wscript.ScriptFullName ' C:\plupload-1.x\src\flash\plupload\build.vbs
+Set objFile = objFSO.GetFile(strScriptFile)
+strFolder = objFSO.GetParentFolderName(objFile) ' C:\plupload-1.x\src\flash\plupload
+
+strWorkspace = Mid(strFolder,1,(Len(strFolder) - 19)) 'C:\plupload-1.x (Removed '\src\flash\plupload')
+
+comspec = objWSShell.ExpandEnvironmentStrings("%comspec%")
+
+Set objFile = objShell.BrowseForFolder(0, "Please select the directory that you have extracted Flex SDK:", &H0001) 'Change to &H4000 to show files too
+
+If IsValue(objFile) Then
+ strPathToExileFile = objFile.self.Path
+
+ If Not objFSO.FileExists(strPathToExileFile & "\bin\mxmlc.exe") Then
+ MsgBox strPathToExileFile & "\bin\mxmlc.exe can't be located." & vbcrlf & "Please make sure that you selected the Flex SDK directory.", 48
+ ' http://stackoverflow.com/questions/1686454/run-a-vbscript-from-another-vbscript
+ objWSShell.Run strScriptFile
+ WScript.Quit
+ End If
+Else
+ WScript.Quit
+End If
+
+' I wrote an article on CodeProject about it:
+' http://www.codeproject.com/Tips/507798/Differences-between-Run-and-Exec-VBScript
+
+' ////////////////////////////////////////////////////////
+strExec = Quotes(strPathToExileFile & "\bin\mxmlc.exe") &_
+ " -source-path " & Quotes(strFolder & "\src") &_
+ " -optimize -use-resource-bundle-metadata" &_
+ " -show-actionscript-warnings -show-binding-warnings" &_
+ " -show-unused-type-selector-warnings -strict" &_
+ " -accessible=false -use-network " &_
+ " -static-link-runtime-shared-libraries" &_
+ " -output " & Quotes(strWorkspace & "\js\plupload.flash.swf") &_
+ " " & Quotes(strFolder & "\src\com\plupload\Plupload.as")
+
+'1: Show prompt, True: Wait to finish to continue processing
+'strErrorCode =
+objWSShell.Run(Quotes(strFolder & "\exec.bat") & " " & Quotes(strPathToExileFile),1,True)
+
+'If strErrorCode = 0 Then
+If objFSO.FileExists(strWorkspace & "\js\plupload.flash.swf") Then
+ objWSShell.Exec("explorer.exe /select," & Quotes(strWorkspace & "\js\plupload.flash.swf"))
+Else
+ strResponse = MsgBox("Please make sure you have installed Java JDK (32-bit)." & vbCrLf &_
+ "If Java JDK is installed, you may need to set JAVA_HOME " &_
+ "manually at " & strPathToExileFile & "\bin\jvm.config." & vbCrLf &_
+ "Click YES to read instructions how to do that, or NO to exit this script." & vbCrLf & vbCrLf &_
+ "Command Executed:" & vbCrLf & "(" & strFolder & "\exec.bat) " & vbCrLf & vbCrLf &_
+ strExec,20,"Build failed.")
+
+ If strResponse = vbYes Then
+ objWSShell.Run "iexplore.exe http://stackoverflow.com/questions/3364623/flexsdk-to-compile-mxml-file"
+ Else
+ WScript.Quit
+ End If
+End If
+
+Function IsValue(obj)
+ ' Check whether a value has been returned.
+ Dim tmp
+ On Error Resume Next
+ tmp = " " & obj
+ If Err <> 0 Then
+ IsValue = False
+ Else
+ IsValue = True
+ End If
+ On Error GoTo 0
+End Function
+
+' http://stackoverflow.com/questions/2942554/vbscript-adding-quotes-to-a-string
+Function Quotes(strQuotes)
+ Quotes = chr(34) & strQuotes & chr(34)
+End Function
diff --git a/debian/missing-sources/plupload/flash/plupload/exec.bat b/debian/missing-sources/plupload/flash/plupload/exec.bat
new file mode 100644
index 0000000..fe38e41
--- /dev/null
+++ b/debian/missing-sources/plupload/flash/plupload/exec.bat
@@ -0,0 +1,13 @@
+@echo off
+Set dir=%~dp0
+REM flex_dir received by VBScript
+Set flex_dir=%~1
+
+if [%flex_dir%] EQU [] (
+ echo Please do not call this file directly! Use build.vbs
+ pause
+ exit
+)
+
+"%flex_dir%\bin\mxmlc.exe" -source-path "%dir%\src" -optimize -use-resource-bundle-metadata -show-actionscript-warnings -show-binding-warnings -show-unused-type-selector-warnings -strict -accessible=false -use-network -static-link-runtime-shared-libraries -output "%dir:~0,-20%\js\plupload.flash.swf" "%dir%\src\com\plupload\Plupload.as"
+pause
diff --git a/debian/missing-sources/plupload/flash/plupload/src/com/formatlos/BitmapDataUnlimited.as b/debian/missing-sources/plupload/flash/plupload/src/com/formatlos/BitmapDataUnlimited.as
new file mode 100644
index 0000000..38c9291
--- /dev/null
+++ b/debian/missing-sources/plupload/flash/plupload/src/com/formatlos/BitmapDataUnlimited.as
@@ -0,0 +1,254 @@
+/*
+Copyright (c) 2008 Martin Raedlinger (mr@formatlos.de)
+
+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.
+*/
+
+package com.formatlos
+{
+ import com.formatlos.events.BitmapDataUnlimitedEvent;
+
+ import flash.display.Bitmap;
+ import flash.display.BitmapData;
+ import flash.display.DisplayObject;
+ import flash.display.IBitmapDrawable;
+ import flash.display.Loader;
+ import flash.events.Event;
+ import flash.events.EventDispatcher;
+ import flash.geom.ColorTransform;
+ import flash.geom.Matrix;
+ import flash.geom.Point;
+ import flash.geom.Rectangle;
+
+ /**
+ * Dispatched when the BitmapData is ready
+ *
+ * @eventType com.formatlos.events.BitmapDataUnlimitedEvent
+ */
+ [Event(name='COMPLETE', type='com.formatlos.events.BitmapDataUnlimitedEvent')]
+
+ /**
+ * Dispatched when the BitmapData can't be created due to memory issues.
+ * watch your system memory and/or System.totalMemory
+ *
+ * @eventType com.formatlos.events.BitmapDataUnlimitedEvent
+ */
+ [Event(name='ERROR', type='com.formatlos.events.BitmapDataUnlimitedEvent')]
+
+ // ---------------------------------------------------------------------------
+
+ /**
+ * The BitmapDataUnlimited Class creates an empty gif image
+ *
+ * @author Martin Raedlinger
+ *
+ * @example
+ * The example shows how to use the BitmapDataUnlimited
+ * <div class="listing">
+ * <pre>
+ *
+ * var bdu:BitmapDataUnlimited = new BitmapDataUnlimited();
+ * bdu.addEventListener(BitmapDataUnlimitedEvent.COMPLETE, onBmpReady);
+ * bdu.create(5000, 5000, true);
+ *
+ * var hugeBitmapData : BitmapData;
+ *
+ * function onBmpReady(event : BitmapDataUnlimitedEvent) : void
+ * {
+ * hugeBitmapData = bdu.bitmapData;
+ *
+ * var rect : Rectangle = new Rectangle(10, 10, 10, 10);
+ *
+ * hugeBitmapData.fillRect(rect, 0xffff0000);
+ * addChild(new Bitmap(hugeBitmapData));
+ *
+ * trace("BitmapData: w=" + hugeBitmapData.width + " h=" + hugeBitmapData.height);
+ * }
+ *
+ * </pre>
+ * </div>
+ *
+ */
+ public class BitmapDataUnlimited extends EventDispatcher
+ {
+ // basically this value is 4096, but take 4000 to have some buffer
+ static private const DRAW_LIMIT : uint = 4000;
+
+ private var _loader : Loader;
+ private var _gif : Gif;
+ private var _fillColor : uint;
+ private var _transparent : Boolean;
+
+
+ // created bitmapData
+ private var _bitmapData : BitmapData;
+
+ /**
+ * Returns the created BitmapData Object
+ *
+ * @return Huge BitmapData
+ */
+ public function get bitmapData() : BitmapData
+ {
+ return _bitmapData;
+ }
+
+
+ /**
+ * Creates a huge BitmapData object.
+ *
+ * @param width The width of the huge BitmapData
+ * @param height The height of the huge BitmapData
+ * @param transparent transparent BitmapData or not
+ * @param fillColor Fill the BitmapData with color
+ */
+ public function create(width_ : int, height_ : int, transparent_ : Boolean = true, fillColor_ : uint = 0xFFFFFF) : void
+ {
+ try
+ {
+ _bitmapData = new BitmapData(width_, height_, transparent_, fillColor_);
+ dispatchComplete();
+ }
+ catch(error : ArgumentError)
+ {
+ if(width_ <= 0 || height_ <= 0)
+ {
+ throw error;
+ }
+ else
+ {
+ _transparent = transparent_;
+ _fillColor = fillColor_;
+
+ _gif = new Gif(width_, height_, transparent_, fillColor_);
+ _loader = new Loader();
+ _loader.contentLoaderInfo.addEventListener(Event.COMPLETE, onLoaderComplete);
+ _loader.loadBytes(_gif.bytes);
+ }
+ }
+ }
+
+ /**
+ * Bypasses the 4096px limit in BitmapData.draw() and draws the source display object onto the bitmap image.
+ *
+ * @see http://blog.formatlos.de/2008/12/11/bitmapdatadraw-is-limited-to-4096px/
+ *
+ * @param source_ The display object or BitmapData object to draw to the BitmapData object. (The DisplayObject and BitmapData classes implement the IBitmapDrawable interface.)
+ * @param colorTransform_ A ColorTransform object that you use to adjust the color values of the bitmap. If no object is supplied, the bitmap image's colors are not transformed
+ * @param blendMode_ A string value, from the flash.display.BlendMode class, specifying the blend mode to be applied to the resulting bitmap.
+ * @param clipRect_ A Rectangle object that defines the area of the source object to draw. If you do not supply this value, no clipping occurs and the entire source object is drawn.
+ * @param smoothing_ A Boolean value that determines whether a BitmapData object is smoothed
+ */
+ public function draw(source_ : IBitmapDrawable, matrix_ : Matrix = null, colorTransform_ : ColorTransform = null, blendMode_ : String = null, clipRect_:Rectangle = null, smoothing_ : Boolean = false) : void
+ {
+ var srcRect : Rectangle;
+
+ if (source_ is BitmapData) srcRect = (source_ as BitmapData).rect.clone();
+ else if (source_ is DisplayObject) srcRect = (source_ as DisplayObject).getBounds(source_ as DisplayObject);
+
+
+ if(srcRect)
+ {
+ var x : int = (clipRect_) ? clipRect_.x : 0;
+ var y : int = (clipRect_) ? clipRect_.y : 0;
+ var clipWidth : int = (clipRect_) ? clipRect_.right : _bitmapData.width;
+ var clipHeight : int = (clipRect_) ? clipRect_.bottom : _bitmapData.height;
+ var xMax : int = Math.min(srcRect.right, clipWidth);
+ var yMax : int = Math.min(srcRect.bottom, clipHeight);
+ var matrix : Matrix;
+ var chunk : BitmapData;
+ var clip : Rectangle = new Rectangle();
+
+ if(matrix_) {
+ xMax *= matrix_.a;
+ yMax *= matrix_.d;
+ }
+
+ while(x < xMax)
+ {
+ while(y < yMax)
+ {
+ matrix = new Matrix();
+ if(matrix_) {
+ matrix.a = matrix_.a;
+ matrix.d = matrix_.d;
+ }
+ matrix.translate(-x, -y);
+ clip.width = (xMax - x >= DRAW_LIMIT) ? DRAW_LIMIT : xMax - x;
+ clip.height = (yMax - y >= DRAW_LIMIT) ? DRAW_LIMIT : yMax - y ;
+
+ // use source
+ if(x == 0 && y == 0)
+ {
+ _bitmapData.draw(source_, matrix, colorTransform_, blendMode_, clip, smoothing_);
+ }
+ // copy to chunk first
+ else
+ {
+ if(!chunk) chunk = _bitmapData.clone();
+ chunk.fillRect(chunk.rect, (!_transparent) ? _fillColor : 0x00000000 );
+ chunk.draw(source_, matrix, colorTransform_, blendMode_, clip, smoothing_);
+ _bitmapData.copyPixels(chunk, chunk.rect, new Point(x, y), null, null, true);
+
+ }
+
+ y += DRAW_LIMIT;
+ }
+
+ x += DRAW_LIMIT;
+ y = 0;
+ }
+
+ if(chunk)
+ {
+ chunk.dispose();
+ chunk = null;
+ }
+ }
+ }
+
+
+ private function onLoaderComplete(event : Event) : void
+ {
+ var ok:Boolean = true;
+
+ try
+ {
+ _bitmapData = Bitmap(_loader.content).bitmapData.clone();
+ if(!_transparent) _bitmapData.fillRect(_bitmapData.rect, _fillColor);
+ }
+ catch(error : ArgumentError)
+ {
+ ok = false;
+ dispatchEvent(new BitmapDataUnlimitedEvent(BitmapDataUnlimitedEvent.ERROR));
+ }
+
+ _loader.contentLoaderInfo.removeEventListener(Event.COMPLETE, onLoaderComplete);
+ _loader = null;
+
+ if(ok) dispatchComplete();
+ }
+
+ private function dispatchComplete() : void
+ {
+ dispatchEvent(new BitmapDataUnlimitedEvent(BitmapDataUnlimitedEvent.COMPLETE));
+ }
+
+ }
+} \ No newline at end of file
diff --git a/debian/missing-sources/plupload/flash/plupload/src/com/formatlos/Gif.as b/debian/missing-sources/plupload/flash/plupload/src/com/formatlos/Gif.as
new file mode 100644
index 0000000..3921026
--- /dev/null
+++ b/debian/missing-sources/plupload/flash/plupload/src/com/formatlos/Gif.as
@@ -0,0 +1,197 @@
+/*
+Copyright (c) 2008 Martin Raedlinger (mr@formatlos.de)
+
+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.
+ */
+
+package com.formatlos
+{
+ import flash.utils.ByteArray;
+
+ /**
+ * The Gif Class creates an empty gif image
+ *
+ * @author Martin Raedlinger
+ */
+ public class Gif
+ {
+ private var _width : int;
+ private var _height : int;
+ private var _colorTable : ByteArray;
+ private var _colorTableSize : int = 7;
+ private var _transparent : Boolean;
+ private var _transparentIndex : int = 0;
+ private var _fillColor : uint;
+
+ // binary gif data
+ private var _binaryGif : ByteArray;
+
+ /**
+ * Returns the created binary gif data
+ *
+ * @return binary gif data
+ */
+ public function get bytes() : ByteArray
+ {
+ return _binaryGif;
+ }
+
+
+ public function Gif(width_ : int, height_ : int, transparent_ : Boolean = false, fillColor_ : uint = 4.294967295E9)
+ {
+ _width = width_;
+ _height = height_;
+ _transparent = transparent_;
+ _fillColor = fillColor_;
+
+ initialize();
+ }
+
+ private function initialize() : void
+ {
+ _binaryGif = new ByteArray();
+
+ writeHeader();
+ writeLogicalScreenDescriptor();
+ writeColorTable();
+ writeGraphicControlExtensionBlock();
+ writeImageBlock();
+ writeTrailer();
+ }
+
+ private function writeHeader() : void
+ {
+ _binaryGif.writeUTFBytes("GIF89a");
+ }
+
+ private function writeLogicalScreenDescriptor() : void
+ {
+ // size
+ writeShort(_width);
+ writeShort(_height);
+
+ // Packed Fields
+ // bit 0: Global Color Table Flag (GCTF)
+ // bit 1..3: Color Resolution
+ // bit 4: Sort Flag to Global Color Table
+ // bit 5..7: Size of Global Color Table: 2^(1+n)
+ _binaryGif.writeByte((0x80 | 0x70 | 0x00 | _colorTableSize));
+ // Background Color Index
+ _binaryGif.writeByte(0);
+ // Pixel Aspect Ratio
+ _binaryGif.writeByte(0); //
+ }
+
+
+ private function writeColorTable() : void
+ {
+ _colorTable = new ByteArray();
+ //_colorTable[0] = 0xFF0000 >> 16;
+ //_colorTable[1] = 0x00FF00 >> 8;
+ //_colorTable[2] = 0x0000FF;
+ _colorTable[0] = _fillColor >> 16 & 0xFF;
+ _colorTable[1] = _fillColor >> 8 & 0xFF;
+ _colorTable[2] = _fillColor & 0xFF;
+
+ _binaryGif.writeBytes(_colorTable, 0, _colorTable.length);
+
+ var i : int = 0;
+ var n : int = (3 * 256) - _colorTable.length;
+
+ while(i < n)
+ {
+ _binaryGif.writeByte(0);
+ ++i;
+ }
+ }
+
+ private function writeGraphicControlExtensionBlock() : void
+ {
+ // Extension Introducer
+ _binaryGif.writeByte(0x21);
+ // Graphic Control Label
+ _binaryGif.writeByte(0xf9);
+ // Block Size
+ _binaryGif.writeByte(4);
+
+
+ var transparent : int;
+ var dispose : int;
+
+ if (_transparent)
+ {
+ transparent = 1;
+ dispose = 2;
+ }
+ else
+ {
+ transparent = 0;
+ dispose = 0;
+ }
+
+ dispose <<= 2;
+
+ // Packed Fields
+ // bit 0..2: Reserved
+ // bit 3..5: Disposal Method
+ // bit 6: User Input Flag
+ // bit 7: Transparent Color Flag
+ _binaryGif.writeByte(0 | dispose | 0 | transparent);
+
+ // Delay Time
+ writeShort(0);
+ // Transparent Color Index
+ _binaryGif.writeByte(_transparentIndex);
+ // Block Terminator
+ _binaryGif.writeByte(0);
+ }
+
+ private function writeImageBlock() : void
+ {
+ //Image Separator
+ _binaryGif.writeByte(0x2c);
+ // Image Left Position
+ writeShort(0);
+ // image position x,y = 0,0
+ // Image Top Position
+ writeShort(0);
+ // Image Width
+ writeShort(_width);
+ // Image Height
+ writeShort(_height);
+ // Packed Fields
+ _binaryGif.writeByte(0);
+ }
+
+
+ private function writeTrailer() : void
+ {
+ _binaryGif.writeByte(0x3b);
+ }
+
+ private function writeShort(pValue : int) : void
+ {
+ _binaryGif.writeByte(pValue & 0xFF);
+ _binaryGif.writeByte((pValue >> 8) & 0xFF);
+ }
+
+
+
+ }
+} \ No newline at end of file
diff --git a/debian/missing-sources/plupload/flash/plupload/src/com/formatlos/events/BitmapDataUnlimitedEvent.as b/debian/missing-sources/plupload/flash/plupload/src/com/formatlos/events/BitmapDataUnlimitedEvent.as
new file mode 100644
index 0000000..1720065
--- /dev/null
+++ b/debian/missing-sources/plupload/flash/plupload/src/com/formatlos/events/BitmapDataUnlimitedEvent.as
@@ -0,0 +1 @@
+/* Copyright (c) 2008 Martin Raedlinger (mr@formatlos.de) 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. */ package com.formatlos.events { import flash.events.Event; /** * @author Martin Raedlinger */ public class BitmapDataUnlimitedEvent extends Event { public static const COMPLETE : String = "bitmapDataComplete"; public static const ERROR : String = "bitmapDataError"; public function BitmapDataUnlimitedEvent(type : String, bubbles : Boolean = false, cancelable : Boolean = false) { super(type, bubbles, cancelable); } override public function clone() : Event { return new BitmapDataUnlimitedEvent(type, bubbles, cancelable); } } } \ No newline at end of file
diff --git a/debian/missing-sources/plupload/flash/plupload/src/com/mxi/BinaryReader.as b/debian/missing-sources/plupload/flash/plupload/src/com/mxi/BinaryReader.as
new file mode 100644
index 0000000..f440b78
--- /dev/null
+++ b/debian/missing-sources/plupload/flash/plupload/src/com/mxi/BinaryReader.as
@@ -0,0 +1,92 @@
+/**
+ *
+ * Copyright 2011, Moxiecode Systems AB
+ * Released under GPL License.
+ *
+ * License: http://www.plupload.com/license
+ * Contributing: http://www.plupload.com/contributing
+ */
+
+package com.mxi {
+ import flash.utils.ByteArray;
+ import flash.utils.Endian;
+
+ public class BinaryReader extends ByteArray {
+
+ public function init(binData:ByteArray):void {
+ clear();
+ endian = Endian.BIG_ENDIAN;
+ writeBytes(binData);
+ }
+
+ public function II(... args):* {
+ if (!args.length)
+ return endian == Endian.LITTLE_ENDIAN ? true : false;
+ else
+ endian = args[0] == true ? Endian.LITTLE_ENDIAN : Endian.BIG_ENDIAN;
+ }
+
+ public function SEGMENT(... args):ByteArray {
+ var seg:ByteArray = new ByteArray();
+
+ switch (args.length) {
+
+ case 1:
+ position = args[0];
+ readBytes(seg, 0);
+ break;
+
+ case 2:
+ position = args[0];
+ readBytes(seg, 0, args[1]);
+ break;
+
+ case 3:
+ position = args[0] + args[1];
+ readBytes(seg);
+ position = args[0];
+ writeBytes(args[2]);
+ writeBytes(seg);
+ break;
+
+ default:
+ position = 0;
+ readBytes(seg, 0, length);
+ }
+
+ return seg;
+ }
+
+ public function BYTE(idx:int):uint {
+ position = idx;
+ return readUnsignedByte();
+ }
+
+ public function SHORT(idx:int):uint {
+ position = idx;
+ return readUnsignedShort();
+ }
+
+ public function LONG(idx:int, ... args):* {
+ position = idx;
+ if (!args.length)
+ return readUnsignedInt();
+ else
+ writeUnsignedInt(args[0]);
+ }
+
+ public function SLONG(idx:uint):int {
+ position = idx;
+ return readInt();
+ }
+
+ public function STRING(idx:uint, size:uint):String {
+ position = idx;
+ return readUTFBytes(size);
+ }
+
+
+ }
+
+
+}
diff --git a/debian/missing-sources/plupload/flash/plupload/src/com/mxi/CleanEventDispatcher.as b/debian/missing-sources/plupload/flash/plupload/src/com/mxi/CleanEventDispatcher.as
new file mode 100644
index 0000000..3d5818c
--- /dev/null
+++ b/debian/missing-sources/plupload/flash/plupload/src/com/mxi/CleanEventDispatcher.as
@@ -0,0 +1,42 @@
+/**
+ *
+ * Copyright 2011, Moxiecode Systems AB
+ * Released under GPL License.
+ *
+ * License: http://www.plupload.com/license
+ * Contributing: http://www.plupload.com/contributing
+ */
+
+package com.mxi
+{
+ import flash.events.EventDispatcher;
+
+ public class CleanEventDispatcher extends EventDispatcher
+ {
+ protected var events:Array = [];
+
+ override public function addEventListener(type:String, callback:Function, useCapture:Boolean = false, priority:int = 0, useWeak:Boolean = false) : void
+ {
+ events.push({
+ type: type,
+ callback: callback
+ });
+
+ /* we pass only required params for simplicity of removal operation, if you need to use other params
+ you will need something more intricate then this one */
+ super.addEventListener(type, callback);
+ }
+
+
+ /* anyone any idea why Flash doesn't have a call like this?.. */
+ public function removeAllEventListeners() : void
+ {
+ var i:int,
+ max:int = events.length;
+ for (i=0; i<max; i++) {
+ removeEventListener(events[i].type, events[i].callback);
+ }
+ events = [];
+ }
+ }
+} \ No newline at end of file
diff --git a/debian/missing-sources/plupload/flash/plupload/src/com/mxi/image/ExifParser.as b/debian/missing-sources/plupload/flash/plupload/src/com/mxi/image/ExifParser.as
new file mode 100644
index 0000000..0370fc6
--- /dev/null
+++ b/debian/missing-sources/plupload/flash/plupload/src/com/mxi/image/ExifParser.as
@@ -0,0 +1,417 @@
+/**
+ * Copyright 2011, Moxiecode Systems AB
+ * Released under GPL License.
+ *
+ * License: http://www.plupload.com/license
+ * Contributing: http://www.plupload.com/contributing
+ */
+
+package com.mxi.image {
+ import flash.events.EventDispatcher;
+ import flash.utils.ByteArray;
+ import com.mxi.BinaryReader;
+ import flash.external.ExternalInterface;
+
+ public class ExifParser extends EventDispatcher {
+
+ private var data:BinaryReader = new BinaryReader();
+
+ private var offsets:Object = {
+ tiffHeader : 10
+ };
+
+ private var tags:Object = {
+
+ tiff: {
+ 0x0112: 'Orientation',
+ 0x8769: 'ExifIFDPointer',
+ 0x8825: 'GPSInfoIFDPointer'
+ },
+
+ exif: {
+ 0x9000: 'ExifVersion',
+ 0xA001: 'ColorSpace',
+ 0xA002: 'PixelXDimension',
+ 0xA003: 'PixelYDimension',
+ 0x9003: 'DateTimeOriginal',
+ 0x829A: 'ExposureTime',
+ 0x829D: 'FNumber',
+ 0x8827: 'ISOSpeedRatings',
+ 0x9201: 'ShutterSpeedValue',
+ 0x9202: 'ApertureValue' ,
+ 0x9207: 'MeteringMode',
+ 0x9208: 'LightSource',
+ 0x9209: 'Flash',
+ 0xA402: 'ExposureMode',
+ 0xA403: 'WhiteBalance',
+ 0xA406: 'SceneCaptureType',
+ 0xA404: 'DigitalZoomRatio',
+ 0xA408: 'Contrast',
+ 0xA409: 'Saturation',
+ 0xA40A: 'Sharpness'
+ },
+
+ gps: {
+ 0x0000: 'GPSVersionID',
+ 0x0001: 'GPSLatitudeRef',
+ 0x0002: 'GPSLatitude',
+ 0x0003: 'GPSLongitudeRef',
+ 0x0004: 'GPSLongitude'
+ }
+ },
+
+ tagDescs:Object = {
+ 'ColorSpace': {
+ 1: 'sRGB',
+ 0: 'Uncalibrated'
+ },
+ 'MeteringMode': {
+ 0: 'Unknown',
+ 1: 'Average',
+ 2: 'CenterWeightedAverage',
+ 3: 'Spot',
+ 4: 'MultiSpot',
+ 5: 'Pattern',
+ 6: 'Partial',
+ 255: 'Other'
+ },
+ 'LightSource': {
+ 1: 'Daylight',
+ 2: 'Fliorescent',
+ 3: 'Tungsten',
+ 4: 'Flash',
+ 9: 'Fine weather',
+ 10: 'Cloudy weather',
+ 11: 'Shade',
+ 12: 'Daylight fluorescent (D 5700 - 7100K)',
+ 13: 'Day white fluorescent (N 4600 -5400K)',
+ 14: 'Cool white fluorescent (W 3900 - 4500K)',
+ 15: 'White fluorescent (WW 3200 - 3700K)',
+ 17: 'Standard light A',
+ 18: 'Standard light B',
+ 19: 'Standard light C',
+ 20: 'D55',
+ 21: 'D65',
+ 22: 'D75',
+ 23: 'D50',
+ 24: 'ISO studio tungsten',
+ 255: 'Other'
+ },
+ 'Flash': {
+ 0x0000: 'Flash did not fire.',
+ 0x0001: 'Flash fired.',
+ 0x0005: 'Strobe return light not detected.',
+ 0x0007: 'Strobe return light detected.',
+ 0x0009: 'Flash fired, compulsory flash mode',
+ 0x000D: 'Flash fired, compulsory flash mode, return light not detected',
+ 0x000F: 'Flash fired, compulsory flash mode, return light detected',
+ 0x0010: 'Flash did not fire, compulsory flash mode',
+ 0x0018: 'Flash did not fire, auto mode',
+ 0x0019: 'Flash fired, auto mode',
+ 0x001D: 'Flash fired, auto mode, return light not detected',
+ 0x001F: 'Flash fired, auto mode, return light detected',
+ 0x0020: 'No flash function',
+ 0x0041: 'Flash fired, red-eye reduction mode',
+ 0x0045: 'Flash fired, red-eye reduction mode, return light not detected',
+ 0x0047: 'Flash fired, red-eye reduction mode, return light detected',
+ 0x0049: 'Flash fired, compulsory flash mode, red-eye reduction mode',
+ 0x004D: 'Flash fired, compulsory flash mode, red-eye reduction mode, return light not detected',
+ 0x004F: 'Flash fired, compulsory flash mode, red-eye reduction mode, return light detected',
+ 0x0059: 'Flash fired, auto mode, red-eye reduction mode',
+ 0x005D: 'Flash fired, auto mode, return light not detected, red-eye reduction mode',
+ 0x005F: 'Flash fired, auto mode, return light detected, red-eye reduction mode'
+ },
+ 'ExposureMode': {
+ 0: 'Auto exposure',
+ 1: 'Manual exposure',
+ 2: 'Auto bracket'
+ },
+ 'WhiteBalance': {
+ 0: 'Auto white balance',
+ 1: 'Manual white balance'
+ },
+ 'SceneCaptureType': {
+ 0: 'Standard',
+ 1: 'Landscape',
+ 2: 'Portrait',
+ 3: 'Night scene'
+ },
+ 'Contrast': {
+ 0: 'Normal',
+ 1: 'Soft',
+ 2: 'Hard'
+ },
+ 'Saturation': {
+ 0: 'Normal',
+ 1: 'Low saturation',
+ 2: 'High saturation'
+ },
+ 'Sharpness': {
+ 0: 'Normal',
+ 1: 'Soft',
+ 2: 'Hard'
+ },
+
+ // GPS related
+ 'GPSLatitudeRef': {
+ N: 'North latitude',
+ S: 'South latitude'
+ },
+ 'GPSLongitudeRef': {
+ E: 'East longitude',
+ W: 'West longitude'
+ }
+ };
+
+ public function init(segment:ByteArray):Boolean {
+ // Reset internal data
+ offsets = {
+ tiffHeader: 10
+ };
+
+ if (!segment || !segment.length) {
+ return false;
+ }
+
+ data.init(segment);
+
+ // Check if that's APP1 and that it has EXIF
+ if (data.SHORT(0) === 0xFFE1 && data.STRING(4, 4).toUpperCase() === "EXIF") {
+ return getIFDOffsets();
+ }
+ return false;
+ }
+
+
+ public function EXIF():Object {
+ var Exif:Object;
+
+ if (!offsets.hasOwnProperty('exifIFD') || offsets['exifIFD'] === null) {
+ return null;
+ }
+
+ try { // survive invalid offsets
+ Exif = extractTags(offsets['exifIFD'], tags.exif);
+ } catch (ex:Error) {
+ return null;
+ }
+
+ // fix formatting of some tags
+ if (Exif.hasOwnProperty('ExifVersion') && Exif.ExifVersion is Array) {
+ for (var i:uint = 0, exifVersion:String = ''; i < Exif.ExifVersion.length; i++) {
+ exifVersion += String.fromCharCode(Exif.ExifVersion[i]);
+ }
+ Exif.ExifVersion = exifVersion;
+ }
+
+ return Exif;
+ }
+
+ public function GPS():Object {
+ var Gps:Object;
+
+ if (!offsets.hasOwnProperty('gpsIFD') || offsets['gps'] === null) {
+ return null;
+ }
+
+ try { // survive invalid offsets
+ Gps = extractTags(offsets['gpsIFD'], tags.gps);
+ } catch (ex:Error) {
+ return null;
+ }
+
+ if (Gps.hasOwnProperty('GPSVersionID') && Gps.GPSVersionID is Array) {
+ Gps.GPSVersionID = Gps.GPSVersionID.join('.');
+ }
+
+ return Gps;
+ }
+
+
+ public function setExif(tag:String, value:*) : Boolean {
+ // Right now only setting of width/height is possible
+ if (tag !== 'PixelXDimension' && tag !== 'PixelYDimension') return false;
+
+ return setTag('exif', tag, value);
+ }
+
+
+ public function getBinary():ByteArray {
+ return data.SEGMENT();
+ }
+
+
+ private function isJPEG():Boolean {
+ return data.SHORT(0) == 0xFFD8;
+ }
+
+
+ private function getIFDOffsets():Boolean {
+ var Tiff:Object, idx:uint = offsets.tiffHeader;
+
+ // Set read order of multi-byte data
+ data.II(data.SHORT(idx) == 0x4949);
+
+ // Check if always present bytes are indeed present
+ if (data.SHORT(idx+=2) !== 0x002A) {
+ return false;
+ }
+
+ offsets['IFD0'] = offsets.tiffHeader + data.LONG(idx += 2);
+ Tiff = extractTags(offsets['IFD0'], tags.tiff);
+
+ offsets['exifIFD'] = ('ExifIFDPointer' in Tiff ? offsets.tiffHeader + Tiff.ExifIFDPointer : null);
+ offsets['gpsIFD'] = ('GPSInfoIFDPointer' in Tiff ? offsets.tiffHeader + Tiff.GPSInfoIFDPointer : null);
+
+ return true;
+ }
+
+
+ private function extractTags(IFD_offset:int, tags2extract:Object):Object {
+ var length:uint = data.SHORT(IFD_offset), i:uint, ii:uint,
+ tag:String, type:uint, count:uint, tagOffset:uint, offset:uint, value:*,
+ values:Array = [], hash:Object = {};
+
+ for (i = 0; i < length; i++) {
+ // Set binary reader pointer to beginning of the next tag
+ offset = tagOffset = IFD_offset + 12 * i + 2;
+
+ tag = tags2extract[data.SHORT(offset)];
+
+ if (!tag) {
+ continue; // Not the tag we requested
+ }
+
+ type = data.SHORT(offset+=2);
+ count = data.LONG(offset+=2);
+
+ offset += 4;
+ values = [];
+
+ switch (type) {
+ case 1: // BYTE
+ case 7: // UNDEFINED
+ if (count > 4) {
+ offset = data.LONG(offset) + offsets.tiffHeader;
+ }
+
+ for (ii = 0; ii < count; ii++) {
+ values[ii] = data.BYTE(offset + ii);
+ }
+
+ break;
+
+ case 2: // STRING
+ if (count > 4) {
+ offset = data.LONG(offset) + offsets.tiffHeader;
+ }
+
+ hash[tag] = data.STRING(offset, count - 1);
+
+ continue;
+
+ case 3: // SHORT
+ if (count > 2) {
+ offset = data.LONG(offset) + offsets.tiffHeader;
+ }
+
+ for (ii = 0; ii < count; ii++) {
+ values[ii] = data.SHORT(offset + ii*2);
+ }
+
+ break;
+
+ case 4: // LONG
+ if (count > 1) {
+ offset = data.LONG(offset) + offsets.tiffHeader;
+ }
+
+ for (ii = 0; ii < count; ii++) {
+ values[ii] = data.LONG(offset + ii*4);
+ }
+
+ break;
+
+ case 5: // RATIONAL
+ offset = data.LONG(offset) + offsets.tiffHeader;
+
+ for (ii = 0; ii < count; ii++) {
+ values[ii] = data.LONG(offset + ii*4) / data.LONG(offset + ii*4 + 4);
+ }
+
+ break;
+
+ case 9: // SLONG
+ offset = data.LONG(offset) + offsets.tiffHeader;
+
+ for (ii = 0; ii < count; ii++) {
+ values[ii] = data.SLONG(offset + ii*4);
+ }
+
+ break;
+
+ case 10: // SRATIONAL
+ offset = data.LONG(offset) + offsets.tiffHeader;
+
+ for (ii = 0; ii < count; ii++) {
+ values[ii] = data.SLONG(offset + ii*4) / data.SLONG(offset + ii*4 + 4);
+ }
+
+ break;
+
+ default:
+ continue;
+ }
+
+ value = (count == 1 ? values[0] : values);
+
+ if (tagDescs.hasOwnProperty(tag) && typeof value != 'object') {
+ hash[tag] = tagDescs[tag][value];
+ } else {
+ hash[tag] = value;
+ }
+ }
+
+ return hash;
+ }
+
+
+ // At the moment only setting of simple (LONG) values, that do not require offset recalculation, is supported
+ private function setTag(ifd:String, tag:*, value:*) : Boolean {
+ var offset:*, length:uint, tagOffset:uint, valueOffset:uint = 0, hex:*;
+
+ // If tag name passed translate into hex key
+ if (tag is String) {
+ var tmpTags:Object = tags[ifd.toLowerCase()];
+ for (hex in tmpTags) {
+ if (tmpTags[hex] === tag) {
+ tag = hex;
+ break;
+ }
+ }
+ }
+ offset = offsets[ifd.toLowerCase() + 'IFD'];
+ if (offset === null) {
+ return false;
+ }
+
+ length = data.SHORT(offset);
+
+ for (var i:uint = 0; i < length; i++) {
+ tagOffset = offset + 12 * i + 2;
+
+ if (data.SHORT(tagOffset) == tag) {
+ valueOffset = tagOffset + 8;
+ break;
+ }
+ }
+
+ if (!valueOffset) return false;
+
+ data.LONG(valueOffset, value);
+ return true;
+ }
+
+ }
+
+}
diff --git a/debian/missing-sources/plupload/flash/plupload/src/com/mxi/image/Image.as b/debian/missing-sources/plupload/flash/plupload/src/com/mxi/image/Image.as
new file mode 100644
index 0000000..c1d91c3
--- /dev/null
+++ b/debian/missing-sources/plupload/flash/plupload/src/com/mxi/image/Image.as
@@ -0,0 +1,216 @@
+/**
+ * Copyright 2011, Moxiecode Systems AB
+ * Released under GPL License.
+ *
+ * License: http://www.plupload.com/license
+ * Contributing: http://www.plupload.com/contributing
+ */
+
+package com.mxi.image
+{
+ import com.formatlos.BitmapDataUnlimited;
+ import com.formatlos.events.BitmapDataUnlimitedEvent;
+ import com.mxi.CleanEventDispatcher;
+ import com.mxi.image.events.ExifParserEvent;
+ import flash.display.BitmapData;
+ import flash.display.IBitmapDrawable;
+ import flash.display.Loader;
+ import flash.events.Event;
+ import flash.geom.Matrix;
+ import flash.utils.ByteArray;
+ import flash.utils.getQualifiedClassName;
+ import mx.graphics.codec.JPEGEncoder;
+ import mx.graphics.codec.PNGEncoder;
+ import com.mxi.image.events.ImageEvent;
+ import flash.system.System;
+ import flash.external.ExternalInterface;
+
+ public class Image extends CleanEventDispatcher
+ {
+ private var _source:ByteArray;
+
+ private var _info:Object = null;
+
+ private var _width:Number;
+ private var _height:Number;
+ private var _quality:Number;
+
+ public static const MAX_WIDTH:uint = 8191;
+ public static const MAX_HEIGHT:uint = 8191;
+
+ private var _loader:Loader;
+ private var _image:*;
+
+ public var imageData:ByteArray;
+
+
+ public function Image(source:ByteArray)
+ {
+ _source = source;
+ super();
+ }
+
+ public function scale(width:* = null, height:* = null, quality:* = null) : void
+ {
+ var info:Object, scale:Number;
+
+ info = _getImageInfo();
+ if (!info) {
+ dispatchEvent(new ImageEvent(ImageEvent.ERROR, ImageEvent.WRONG_FORMAT));
+ return;
+ }
+
+ if (info.width > Image.MAX_WIDTH || info.height > Image.MAX_HEIGHT) {
+ dispatchEvent(new ImageEvent(ImageEvent.ERROR, ImageEvent.OUT_OF_DIMENSIONS));
+ return;
+ }
+
+ _width = width || info.width;
+ _height = height || info.height;
+
+ // we might not need to scale
+ scale = Math.min(_width / info.width, _height / info.height);
+
+ if (scale > 1 && (!quality || info.type != "JPEG")) {
+ dispatchEvent(new ImageEvent(ImageEvent.COMPLETE));
+ return;
+ }
+
+ _quality = quality || 90;
+
+ // scale
+ _loader = new Loader;
+ _loader.contentLoaderInfo.addEventListener(Event.COMPLETE, onBitmapDataReady);
+ _loader.loadBytes(_source);
+ }
+
+
+ protected function _getImageInfo() : Object
+ {
+ var type:String;
+
+ if (_info) return _info;
+
+ if (JPEG.test(_source)) {
+ _image = new JPEG(_source);
+ }
+ else if (PNG.test(_source)) {
+ _image = new PNG(_source);
+ }
+
+ if (_image) {
+ _info = _image.info();
+ if (_info) {
+ _info['type'] = getQualifiedClassName(_image).replace(/^.*::/, '');
+ }
+ }
+ return _info;
+ }
+
+
+ protected function onBitmapDataReady(e:Event) : void
+ {
+ var bitmapSource:IBitmapDrawable, output:BitmapData, width:Number, height:Number, scale:Number;
+
+ _loader.contentLoaderInfo.removeEventListener(Event.COMPLETE, onBitmapDataReady);
+
+ bitmapSource = e.target.content as IBitmapDrawable;
+
+ width = _info.width;
+ height = _info.height;
+
+ // re-calculate width/height proportionally
+ scale = Math.min(_width / width, _height / height);
+
+ // whatever the case, do not upsize
+ if (scale > 1) {
+ scale = 1;
+ }
+
+ _width = Math.round(width * scale);
+ _height = Math.round(height * scale);
+
+ var prepareBitmap:Function = function(width:Number, height:Number, callback:Function) : void
+ {
+ var bitmapCreator:BitmapDataUnlimited = new BitmapDataUnlimited;
+ bitmapCreator.addEventListener(BitmapDataUnlimitedEvent.COMPLETE, function(e:BitmapDataUnlimitedEvent) : void
+ {
+ callback(bitmapCreator.bitmapData);
+ });
+ bitmapCreator.addEventListener(BitmapDataUnlimitedEvent.ERROR, function(e:BitmapDataUnlimitedEvent) : void
+ {
+ dispatchEvent(new ImageEvent(ImageEvent.ERROR, ImageEvent.OUT_OF_MEMORY));
+ });
+ bitmapCreator.create(width, height, true);
+ };
+
+ var outputScale:Function = function(width:Number, height:Number) : void
+ {
+ prepareBitmap(width, height, function(bitmapData:BitmapData) : void
+ {
+ var scale:Number, matrix:Matrix;
+
+ scale = Math.min(width / output.width, height / output.height);
+
+ matrix = new Matrix;
+ matrix.scale(scale, scale);
+
+ bitmapData.draw(output, matrix, null, null, null, true);
+ output.dispose();
+
+ output = bitmapData;
+ });
+ };
+
+ prepareBitmap(width, height, function(bitmapData:BitmapData) : void
+ {
+ output = bitmapData;
+ output.draw(bitmapSource, null, null, null, null, true);
+
+ while (output.width / 2 > _width) {
+ outputScale(output.width / 2, output.height / 2); // modifies output internally
+ }
+
+ // finalize
+ outputScale(_width, _height);
+
+ // encode
+ if (_info.type == "JPEG") {
+ var headers:Array, exifParser:ExifParser;
+
+ imageData = new JPEGEncoder(_quality).encode(output);
+
+ // transfer headers
+ _image.extractHeaders();
+
+ headers = _image.getHeaders('exif');
+ if (headers.length) {
+ exifParser = new ExifParser;
+ if (exifParser.init(headers[0])) {
+
+ exifParser.setExif('PixelXDimension', _width);
+ exifParser.setExif('PixelYDimension', _height);
+
+ dispatchEvent(new ExifParserEvent(ExifParserEvent.EXIF_DATA, exifParser.EXIF()));
+ dispatchEvent(new ExifParserEvent(ExifParserEvent.GPS_DATA, exifParser.GPS()));
+
+ _image.setHeaders('exif', exifParser.getBinary());
+
+ try {
+ imageData = _image.insertHeaders(imageData);
+ } catch (e:Error) {}
+ }
+ }
+ } else {
+ imageData = new PNGEncoder().encode(output);
+ }
+
+ dispatchEvent(new ImageEvent(ImageEvent.COMPLETE));
+ });
+
+ }
+
+
+ }
+
+} \ No newline at end of file
diff --git a/debian/missing-sources/plupload/flash/plupload/src/com/mxi/image/JPEG.as b/debian/missing-sources/plupload/flash/plupload/src/com/mxi/image/JPEG.as
new file mode 100644
index 0000000..33b0df3
--- /dev/null
+++ b/debian/missing-sources/plupload/flash/plupload/src/com/mxi/image/JPEG.as
@@ -0,0 +1,186 @@
+/**
+ * Copyright 2011, Moxiecode Systems AB
+ * Released under GPL License.
+ *
+ * License: http://www.plupload.com/license
+ * Contributing: http://www.plupload.com/contributing
+ */
+
+package com.mxi.image
+{
+ import com.mxi.BinaryReader;
+ import flash.external.ExternalInterface;
+ import flash.utils.ByteArray;
+
+ public class JPEG
+ {
+ protected var _markers:Object = {
+ 0xFFE1: {
+ app: 'EXIF',
+ name: 'APP1',
+ signature: "Exif"
+ },
+ 0xFFE2: {
+ app: 'ICC',
+ name: 'APP2',
+ signature: "ICC_PROFILE"
+ },
+ 0xFFED: {
+ app: 'IPTC',
+ name: 'APP13',
+ signature: "Photoshop 3.0"
+ }
+ };
+
+ protected var _headers:Array = [];
+ protected var _br:BinaryReader;
+
+ public function JPEG(binData:ByteArray)
+ {
+ _br = new BinaryReader;
+ _br.init(binData);
+ }
+
+ static public function test(binData:ByteArray) : Boolean
+ {
+ var sign:Array = [ 255, 216 ];
+
+ for (var i:int = sign.length - 1; i >= 0 ; i--) {
+ if (binData[i] != sign[i]) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ public function info() : Object
+ {
+ var idx:uint = 0, marker:uint, length:uint;
+
+ // examine all through the end, since some images might have very large APP segments
+ while (idx <= _br.length) {
+ marker = _br.SHORT(idx += 2);
+
+ if (marker >= 0xFFC0 && marker <= 0xFFC3) { // SOFn
+ idx += 5; // marker (2 bytes) + length (2 bytes) + Sample precision (1 byte)
+ return {
+ height: _br.SHORT(idx),
+ width: _br.SHORT(idx += 2)
+ };
+ }
+ length = _br.SHORT(idx += 2);
+ idx += length - 2;
+ }
+
+ return null;
+ }
+
+ public function extractHeaders() : Array
+ {
+ var idx:uint, marker:uint, length:uint;
+
+ idx = 2;
+
+ while (idx <= _br.length) {
+ marker = _br.SHORT(idx);
+
+ // omit RST (restart) markers
+ if (marker >= 0xFFD0 && marker <= 0xFFD7) {
+ idx += 2;
+ continue;
+ }
+
+ // no headers allowed after SOS marker
+ if (marker === 0xFFDA || marker === 0xFFD9) {
+ break;
+ }
+
+ length = _br.SHORT(idx + 2) + 2;
+
+ if (_markers[marker] &&
+ _br.STRING(idx + 4, _markers[marker].signature.length) === _markers[marker].signature) {
+ _headers.push({
+ hex: marker,
+ app: _markers[marker].app.toUpperCase(),
+ name: _markers[marker].name.toUpperCase(),
+ start: idx,
+ length: length,
+ segment: _br.SEGMENT(idx, length)
+ });
+ }
+ idx += length;
+ }
+
+ return _headers;
+ }
+
+ public function getHeaders(app:String = null) : Array
+ {
+ var headers:Array, array:Array = [];
+
+ headers = _headers.length ? _headers : extractHeaders();
+
+ if (!app) {
+ return headers;
+ }
+
+ for (var i:uint = 0, max:uint = headers.length; i < max; i++) {
+ if (headers[i].app === app.toUpperCase()) {
+ array.push(headers[i].segment);
+ }
+ }
+ return array;
+ }
+
+ public function setHeaders(app:String, segment:*) : void
+ {
+ var array:Array = [];
+
+ if (segment is ByteArray) {
+ array.push(segment);
+ } else {
+ array = segment;
+ }
+
+ for (var i:uint = 0, ii:uint = 0, max:uint = _headers.length; i < max; i++) {
+ if (_headers[i].app === app.toUpperCase()) {
+ _headers[i].segment = array[ii];
+ _headers[i].length = array[ii].length;
+ ii++;
+ }
+ if (ii >= array.length) break;
+ }
+ }
+
+ public function insertHeaders(binData:ByteArray, headers:Array = null) : ByteArray
+ {
+ var idx:uint, br:BinaryReader = new BinaryReader;
+
+ if (!headers || !headers.length) {
+ headers = _headers;
+ }
+
+ br.init(binData);
+
+ // Check if data is jpeg
+ if (br.SHORT(0) !== 0xFFD8) {
+ throw new Error("Invalid JPEG");
+ }
+
+ if (headers.length) {
+ idx = br.SHORT(2) == 0xFFE0 ? 4 + br.SHORT(4) : 2;
+
+ for (var i:uint = 0, max:uint = headers.length; i < max; i++) {
+ br.SEGMENT(idx, 0, headers[i].segment);
+ idx += headers[i].length;
+ }
+ }
+ return br.SEGMENT();
+ }
+
+ public function purge() : void
+ {
+ _br.clear();
+ }
+ }
+} \ No newline at end of file
diff --git a/debian/missing-sources/plupload/flash/plupload/src/com/mxi/image/PNG.as b/debian/missing-sources/plupload/flash/plupload/src/com/mxi/image/PNG.as
new file mode 100644
index 0000000..f05c93f
--- /dev/null
+++ b/debian/missing-sources/plupload/flash/plupload/src/com/mxi/image/PNG.as
@@ -0,0 +1,77 @@
+/**
+ * Copyright 2011, Moxiecode Systems AB
+ * Released under GPL License.
+ *
+ * License: http://www.plupload.com/license
+ * Contributing: http://www.plupload.com/contributing
+ */
+
+package com.mxi.image
+{
+ import com.mxi.BinaryReader;
+ import flash.utils.ByteArray;
+
+ public class PNG
+ {
+ protected var _br:BinaryReader;
+
+ public function PNG(binData:ByteArray)
+ {
+ _br = new BinaryReader;
+ _br.init(binData);
+ }
+
+
+ static public function test(binData:ByteArray) : Boolean
+ {
+ var sign:Array = [ 137, 80, 78, 71, 13, 10, 26, 10 ];
+
+ for (var i:int = sign.length - 1; i >= 0 ; i--) {
+ if (binData[i] != sign[i]) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+
+ public function info() : Object
+ {
+ var chunk:Object, idx:uint;
+
+ chunk = _getChunkAt(8);
+
+ if (chunk.type == 'IHDR') {
+ idx = chunk.start;
+ return {
+ width: _br.LONG(idx),
+ height: _br.LONG(idx += 4)
+ };
+ }
+
+ return null;
+ }
+
+
+ private function _getChunkAt(idx:uint) : Object
+ {
+ var length:uint, type:String, start:uint, CRC:uint;
+
+ length = _br.LONG(idx);
+ type = _br.STRING(idx += 4, 4);
+ start = idx += 4;
+ CRC = _br.LONG(idx + length);
+
+ return {
+ length: length,
+ type: type,
+ start: start,
+ CRC: CRC
+ };
+ }
+
+
+
+ }
+
+} \ No newline at end of file
diff --git a/debian/missing-sources/plupload/flash/plupload/src/com/mxi/image/events/ExifParserEvent.as b/debian/missing-sources/plupload/flash/plupload/src/com/mxi/image/events/ExifParserEvent.as
new file mode 100644
index 0000000..fd611da
--- /dev/null
+++ b/debian/missing-sources/plupload/flash/plupload/src/com/mxi/image/events/ExifParserEvent.as
@@ -0,0 +1,29 @@
+/**
+ * Copyright 2011, Moxiecode Systems AB
+ * Released under GPL License.
+ *
+ * License: http://www.plupload.com/license
+ * Contributing: http://www.plupload.com/contributing
+ */
+
+package com.mxi.image.events {
+ import flash.events.Event;
+
+ public class ExifParserEvent extends Event {
+
+ public var data:Object;
+
+ public static const EXIF_DATA:String = 'exifdata';
+ public static const GPS_DATA:String = 'gpsdata';
+
+ function ExifParserEvent(type:String, data:Object) {
+ this.data = data;
+ super(type);
+ }
+
+ override public function clone() : Event
+ {
+ return new ExifParserEvent(type, data);
+ }
+ }
+} \ No newline at end of file
diff --git a/debian/missing-sources/plupload/flash/plupload/src/com/mxi/image/events/ImageEvent.as b/debian/missing-sources/plupload/flash/plupload/src/com/mxi/image/events/ImageEvent.as
new file mode 100644
index 0000000..780b655
--- /dev/null
+++ b/debian/missing-sources/plupload/flash/plupload/src/com/mxi/image/events/ImageEvent.as
@@ -0,0 +1,36 @@
+/**
+ * Copyright 2011, Moxiecode Systems AB
+ * Released under GPL License.
+ *
+ * License: http://www.plupload.com/license
+ * Contributing: http://www.plupload.com/contributing
+ */
+
+package com.mxi.image.events {
+ import flash.events.Event;
+
+ /**
+ * This class is used for uploads of chunks.
+ */
+ public class ImageEvent extends Event {
+
+ public static const COMPLETE:String = 'imagecomplete';
+ public static const ERROR:String = 'imageerror';
+
+ public static const WRONG_FORMAT:String = '-700';
+ public static const OUT_OF_MEMORY:String = '-701';
+ public static const OUT_OF_DIMENSIONS:String = '-702';
+
+ public var code:String;
+
+ function ImageEvent(type:String, code:String = null) {
+ this.code = code;
+ super(type, false, false);
+ }
+
+ override public function clone() : Event
+ {
+ return new ImageEvent(type, code);
+ }
+ }
+} \ No newline at end of file
diff --git a/debian/missing-sources/plupload/flash/plupload/src/com/plupload/File.as b/debian/missing-sources/plupload/flash/plupload/src/com/plupload/File.as
new file mode 100644
index 0000000..74500d4
--- /dev/null
+++ b/debian/missing-sources/plupload/flash/plupload/src/com/plupload/File.as
@@ -0,0 +1,499 @@
+/**
+ * File.as
+ *
+ * Copyright 2009, Moxiecode Systems AB
+ * Released under GPL License.
+ *
+ * License: http://www.plupload.com/license
+ * Contributing: http://www.plupload.com/contributing
+ */
+
+package com.plupload {
+ import com.formatlos.BitmapDataUnlimited;
+ import com.formatlos.events.BitmapDataUnlimitedEvent;
+ import flash.display.Bitmap;
+ import flash.display.BitmapData;
+ import flash.display.IBitmapDrawable;
+ import flash.events.EventDispatcher;
+ import flash.geom.Matrix;
+ import flash.net.FileReference;
+ import flash.events.Event;
+ import flash.events.IOErrorEvent;
+ import flash.events.HTTPStatusEvent;
+ import flash.events.ProgressEvent;
+ import flash.events.SecurityErrorEvent;
+ import flash.events.DataEvent;
+ import flash.net.FileReferenceList;
+ import flash.net.URLLoader;
+ import flash.net.URLRequest;
+ import flash.net.URLRequestHeader;
+ import flash.net.URLRequestMethod;
+ import flash.net.URLStream;
+ import flash.net.URLVariables;
+ import flash.utils.ByteArray;
+ import flash.utils.setTimeout;
+ import flash.external.ExternalInterface;
+ import com.mxi.image.events.ExifParserEvent;
+
+ import com.mxi.image.Image;
+ import com.mxi.image.events.ImageEvent;
+
+
+ /**
+ * Container class for file references, this handles upload logic for individual files.
+ */
+ public class File extends EventDispatcher {
+ // Private fields
+ private var _fileRef:FileReference, _urlStream:URLStream, _cancelled:Boolean;
+ private var _uploadUrl:String, _uploadPath:String, _mimeType:String;
+ private var _id:String, _fileName:String, _size:Number, _imageData:ByteArray;
+ private var _multipart:Boolean, _fileDataName:String, _chunking:Boolean, _chunk:int, _chunks:int, _chunkSize:int, _postvars:Object;
+ private var _headers:Object, _settings:Object;
+ private var _removeAllListeners:Function;
+ private var _removeAllURLStreamListeners:Function;
+
+ /**
+ * Id property of file.
+ */
+ public function get id():String {
+ return this._id;
+ }
+
+ /**
+ * File name for the file.
+ */
+ public function get fileName():String {
+ return this._fileName;
+ }
+
+ /**
+ * File name for the file.
+ */
+ public function set fileName(value:String):void {
+ this._fileName = value;
+ }
+
+ /**
+ * File size property.
+ */
+ public function get size():Number {
+ return this._size;
+ }
+
+ /**
+ * Constructs a new file object.
+ *
+ * @param id Unique indentifier for the file.
+ * @param file_ref File reference for the selected file.
+ */
+ public function File(id:String, file_ref:FileReference) {
+ this._id = id;
+ this._fileRef = file_ref;
+ this._size = file_ref.size;
+ this._fileName = file_ref.name;
+ }
+
+ /**
+ * Cancel current upload.
+ */
+ public function cancelUpload(): void
+ {
+ if (this.canUseSimpleUpload(this._settings)) {
+ this._fileRef.cancel();
+ } else if (!this._urlStream) {
+ // In case of a large file and before _fileRef.load#COMPLETE.
+ // Need to cancel() twice, not sure why.
+ // If single cancel(), #2037 will occurred at _fileRef.load().
+ this._fileRef.cancel();
+ this._fileRef.cancel();
+ this._removeAllListeners();
+ } else if (this._urlStream.connected) {
+ // just in case
+ this._removeAllURLStreamListeners();
+
+ this._urlStream.close();
+
+ // In case of a large file and after the first uploadNextChunk().
+ // #2174 will occur at _fileRef.load() and
+ // #2029 will occur at _urlStream.readUTFBytes as well
+ // after loading file is stopped before _fileRef.load#COMPLETE.
+
+ // Uploaded file will be broken as well if the following line does not exist.
+ this._urlStream = null;
+ }
+ }
+
+ /**
+ * Uploads a the file to the specified url. This method will upload it as a normal
+ * multipart file upload if the file size is smaller than the chunk size. But if the file is to
+ * large it will be chunked into multiple requests.
+ *
+ * @param url Url to upload the file to.
+ * @param settings Settings object.
+ */
+ public function upload(url:String, settings:Object):void {
+ this._settings = settings;
+
+ if (this.canUseSimpleUpload(settings)) {
+ this.simpleUpload(url, settings);
+ } else {
+ this.advancedUpload(url, settings);
+ }
+ }
+
+ // Private methods
+
+ public function canUseSimpleUpload(settings:Object):Boolean {
+ var multipart:Boolean = new Boolean(settings["multipart"]);
+ var resize:Boolean = (settings["width"] || settings["height"] || settings["quality"]);
+ var chunking:Boolean = (settings["chunk_size"] > 0);
+
+ // Check if it's not an image, chunking is disabled, multipart enabled and the ref_upload setting isn't forced
+ return (!(/\.(jpeg|jpg|png)$/i.test(this._fileName)) || !resize) && multipart && !chunking && !settings.urlstream_upload && !settings.headers;
+ }
+
+ public function simpleUpload(url:String, settings:Object):void {
+ var file:File = this, request:URLRequest, postData:URLVariables, fileDataName:String;
+ var onProgress:Function, onUploadComplete:Function, onIOError:Function, onSecurityErrorEvent:Function;
+ var removeAllListeners:Function = function () : void {
+ file._fileRef.removeEventListener(ProgressEvent.PROGRESS, onProgress);
+ file._fileRef.removeEventListener(DataEvent.UPLOAD_COMPLETE_DATA, onUploadComplete);
+ file._fileRef.removeEventListener(IOErrorEvent.IO_ERROR, onIOError);
+ file._fileRef.removeEventListener(SecurityErrorEvent.SECURITY_ERROR, onSecurityErrorEvent);
+ };
+
+ this._removeAllListeners = removeAllListeners;
+
+ file._postvars = settings["multipart_params"];
+ file._chunk = 0;
+ file._chunks = 1;
+
+ postData = new URLVariables();
+
+ file._postvars["name"] = settings["name"];
+
+ for (var key:String in file._postvars) {
+ if (key != 'Filename') { // Flash will add it by itself, so we need to omit potential duplicate
+ postData[key] = file._postvars[key];
+ }
+ }
+
+ request = new URLRequest();
+ request.method = URLRequestMethod.POST;
+ request.url = url;
+ request.data = postData;
+
+ fileDataName = new String(settings["file_data_name"]);
+
+ onUploadComplete = function(e:DataEvent):void {
+ removeAllListeners();
+
+ var pe:ProgressEvent = new ProgressEvent(ProgressEvent.PROGRESS, false, false, file._size, file._size);
+ dispatchEvent(pe);
+
+ // Fake UPLOAD_COMPLETE_DATA event
+ var uploadChunkEvt:UploadChunkEvent = new UploadChunkEvent(
+ UploadChunkEvent.UPLOAD_CHUNK_COMPLETE_DATA,
+ false,
+ false,
+ e.data,
+ file._chunk,
+ file._chunks
+ );
+
+ file._chunk++;
+
+ dispatchEvent(uploadChunkEvt);
+
+ dispatchEvent(e);
+ };
+ file._fileRef.addEventListener(DataEvent.UPLOAD_COMPLETE_DATA, onUploadComplete);
+
+ // Delegate upload IO errors
+ onIOError = function(e:IOErrorEvent):void {
+ removeAllListeners();
+ dispatchEvent(e);
+ };
+ file._fileRef.addEventListener(IOErrorEvent.IO_ERROR, onIOError);
+
+ // Delegate secuirty errors
+ onSecurityErrorEvent = function(e:SecurityErrorEvent):void {
+ removeAllListeners();
+ dispatchEvent(e);
+ };
+ file._fileRef.addEventListener(SecurityErrorEvent.SECURITY_ERROR, onSecurityErrorEvent);
+
+ // Delegate progress
+ onProgress = function(e:ProgressEvent):void {
+ dispatchEvent(e);
+ };
+ file._fileRef.addEventListener(ProgressEvent.PROGRESS, onProgress);
+
+ file._fileRef.upload(request, fileDataName, false);
+ }
+
+ public function advancedUpload(url:String, settings:Object):void {
+ var file:File = this, width:int, height:int, quality:int, multipart:Boolean, chunking:Boolean, fileDataName:String;
+ var chunk:int, chunks:int, chunkSize:int, postvars:Object;
+ var onComplete:Function, onIOError:Function;
+ var removeAllListeners:Function = function() : void {
+ file._fileRef.removeEventListener(Event.COMPLETE, onComplete);
+ file._fileRef.removeEventListener(IOErrorEvent.IO_ERROR, onIOError);
+ };
+
+ // Setup internal vars
+ this._uploadUrl = url;
+ this._cancelled = false;
+ this._headers = settings.headers;
+ this._mimeType = settings.mime;
+
+ // make it available for whole class (cancelUpload requires it for example)
+ this._removeAllListeners = removeAllListeners;
+
+ multipart = new Boolean(settings["multipart"]);
+ fileDataName = new String(settings["file_data_name"]);
+ chunkSize = settings["chunk_size"];
+ chunking = chunkSize > 0;
+ postvars = settings["multipart_params"];
+ chunk = 0;
+
+ // When file is loaded start uploading
+ onComplete = function(e:Event):void {
+ removeAllListeners();
+
+ var startUpload:Function = function() : void
+ {
+ if (chunking) {
+ chunks = Math.ceil(file._size / chunkSize);
+
+ // Force at least 4 chunks to fake progress. We need to fake this since the URLLoader
+ // doesn't have a upload progress event and we can't use FileReference.upload since it
+ // doesn't support cookies, breaks on HTTPS and doesn't support custom data so client
+ // side image resizing will not be possible.
+ if (chunks < 4 && file._size > 1024 * 32) {
+ chunkSize = Math.ceil(file._size / 4);
+ chunks = 4;
+ }
+ } else {
+ // If chunking is disabled then upload file in one huge chunk
+ chunkSize = file._size;
+ chunks = 1;
+ }
+
+ // Start uploading the scaled down image
+ file._multipart = multipart;
+ file._fileDataName = fileDataName;
+ file._chunking = chunking;
+ file._chunk = chunk;
+ file._chunks = chunks;
+ file._chunkSize = chunkSize;
+ file._postvars = postvars;
+
+ file.uploadNextChunk();
+ }
+
+ if (/\.(jpeg|jpg|png)$/i.test(file._fileName) && (settings["width"] || settings["height"] || settings["quality"])) {
+ var image:Image = new Image(file._fileRef.data);
+ image.addEventListener(ImageEvent.COMPLETE, function(e:ImageEvent) : void
+ {
+ image.removeAllEventListeners();
+ if (image.imageData) {
+ file._imageData = image.imageData;
+ file._imageData.position = 0;
+ file._size = image.imageData.length;
+ }
+ startUpload();
+ });
+ image.addEventListener(ImageEvent.ERROR, function(e:ImageEvent) : void
+ {
+ image.removeAllEventListeners();
+ file.dispatchEvent(e);
+ });
+ image.addEventListener(ExifParserEvent.EXIF_DATA, function(e:ExifParserEvent) : void
+ {
+ file.dispatchEvent(e);
+ });
+ image.addEventListener(ExifParserEvent.GPS_DATA, function(e:ExifParserEvent) : void
+ {
+ file.dispatchEvent(e);
+ });
+ image.scale(settings["width"], settings["height"], settings["quality"]);
+ } else {
+ startUpload();
+ }
+ };
+ this._fileRef.addEventListener(Event.COMPLETE, onComplete);
+
+ // File load IO error
+ onIOError = function(e:Event):void {
+ removeAllListeners();
+ dispatchEvent(e);
+ };
+ this._fileRef.addEventListener(IOErrorEvent.IO_ERROR, onIOError);
+
+ // Start loading local file
+ this._fileRef.load();
+ }
+
+ /**
+ * Uploads the next chunk or terminates the upload loop if all chunks are done.
+ */
+ public function uploadNextChunk():Boolean {
+ var file:File = this, fileData:ByteArray, chunkData:ByteArray, req:URLRequest, url:String;
+ var onComplete:Function, onIOError:Function, onSecurityError:Function;
+ var removeAllEventListeners:Function = function() : void {
+ file._urlStream.removeEventListener(Event.COMPLETE, onComplete);
+ file._urlStream.removeEventListener(IOErrorEvent.IO_ERROR, onIOError);
+ file._urlStream.removeEventListener(SecurityErrorEvent.SECURITY_ERROR, onSecurityError);
+ };
+
+ this._removeAllURLStreamListeners = removeAllEventListeners;
+
+ // All chunks uploaded?
+ if (this._chunk >= this._chunks) {
+ // Clean up memory
+ if(this._fileRef.data) {
+ this._fileRef.data.clear();
+ }
+ this._imageData = null;
+
+ return false;
+ }
+
+ // Slice out a chunk
+ chunkData = new ByteArray();
+
+ // Use image data if it exists, will exist if the image was resized
+ if (this._imageData != null)
+ fileData = this._imageData;
+ else
+ fileData = this._fileRef.data;
+
+ fileData.readBytes(chunkData, 0, fileData.position + this._chunkSize > fileData.length ? fileData.length - fileData.position : this._chunkSize);
+
+ // Setup URL stream
+ file._urlStream = null;
+ file._urlStream = new URLStream();
+
+ // Wait for response and dispatch it
+ onComplete = function(e:Event):void {
+
+
+ var response:String = file._urlStream.readUTFBytes(file._urlStream.bytesAvailable);
+
+ // Fake UPLOAD_COMPLETE_DATA event
+ var uploadChunkEvt:UploadChunkEvent = new UploadChunkEvent(
+ UploadChunkEvent.UPLOAD_CHUNK_COMPLETE_DATA,
+ false,
+ false,
+ response,
+ file._chunk,
+ file._chunks
+ );
+
+ file._chunk++;
+ dispatchEvent(uploadChunkEvt);
+
+ // Fake progress event since Flash doesn't have a progress event for streaming data up to the server
+ var pe:ProgressEvent = new ProgressEvent(ProgressEvent.PROGRESS, false, false, fileData.position, file._size);
+ dispatchEvent(pe);
+
+ // Clean up memory
+ file._urlStream.close();
+ removeAllEventListeners();
+ chunkData.clear();
+ };
+ file._urlStream.addEventListener(Event.COMPLETE, onComplete);
+
+ // Delegate upload IO errors
+ onIOError = function(e:IOErrorEvent):void {
+ removeAllEventListeners();
+ dispatchEvent(e);
+ };
+ file._urlStream.addEventListener(IOErrorEvent.IO_ERROR, onIOError);
+
+ // Delegate secuirty errors
+ onSecurityError = function(e:SecurityErrorEvent):void {
+ removeAllEventListeners();
+ dispatchEvent(e);
+ };
+ file._urlStream.addEventListener(SecurityErrorEvent.SECURITY_ERROR, onSecurityError);
+
+ // Setup URL
+ url = this._uploadUrl;
+
+ // Add name and chunk/chunks to URL if we use direct streaming method
+ if (!this._multipart) {
+ if (url.indexOf('?') == -1)
+ url += '?';
+ else
+ url += '&';
+
+ url += "name=" + encodeURIComponent(this._settings["name"]);
+
+ if (this._chunking) {
+ url += "&chunk=" + this._chunk + "&chunks=" + this._chunks;
+ }
+ }
+
+ // Setup request
+ req = new URLRequest(url);
+ req.method = URLRequestMethod.POST;
+
+ // Add custom headers
+ if (this._headers) {
+ for (var headerName:String in this._headers) {
+ req.requestHeaders.push(new URLRequestHeader(headerName, this._headers[headerName]));
+ }
+ }
+
+ // Build multipart request
+ if (this._multipart) {
+ var boundary:String = '----pluploadboundary' + new Date().getTime(),
+ dashdash:String = '--', crlf:String = '\r\n', multipartBlob: ByteArray = new ByteArray();
+
+ req.requestHeaders.push(new URLRequestHeader("Content-Type", 'multipart/form-data; boundary=' + boundary));
+
+ this._postvars["name"] = this._settings["name"];
+
+ // Add chunking parameters if needed
+ if (this._chunking) {
+ this._postvars["chunk"] = this._chunk;
+ this._postvars["chunks"] = this._chunks;
+ }
+
+ // Append mutlipart parameters
+ for (var name:String in this._postvars) {
+ multipartBlob.writeUTFBytes(
+ dashdash + boundary + crlf +
+ 'Content-Disposition: form-data; name="' + name + '"' + crlf + crlf +
+ this._postvars[name] + crlf
+ );
+ }
+
+ // Add file header
+ multipartBlob.writeUTFBytes(
+ dashdash + boundary + crlf +
+ 'Content-Disposition: form-data; name="' + this._fileDataName + '"; filename="' + this._fileName + '"' + crlf +
+ 'Content-Type: ' + this._mimeType + crlf + crlf
+ );
+
+ // Add file data
+ multipartBlob.writeBytes(chunkData, 0, chunkData.length);
+
+ // Add file footer
+ multipartBlob.writeUTFBytes(crlf + dashdash + boundary + dashdash + crlf);
+ req.data = multipartBlob;
+ } else {
+ req.requestHeaders.push(new URLRequestHeader("Content-Type", "application/octet-stream"));
+ req.data = chunkData;
+ }
+
+ // Make request
+ setTimeout(function() : void { // otherwise URLStream eventually hangs for Chrome+Flash (as of FP11.2 r202)
+ file._urlStream.load(req);
+ }, 1);
+ return true;
+ }
+ }
+}
diff --git a/debian/missing-sources/plupload/flash/plupload/src/com/plupload/Plupload.as b/debian/missing-sources/plupload/flash/plupload/src/com/plupload/Plupload.as
new file mode 100644
index 0000000..2c4981f
--- /dev/null
+++ b/debian/missing-sources/plupload/flash/plupload/src/com/plupload/Plupload.as
@@ -0,0 +1,413 @@
+/**
+ * Plupload.as
+ *
+ * Copyright 2009, Moxiecode Systems AB
+ * Released under GPL License.
+ *
+ * License: http://www.plupload.com/license
+ * Contributing: http://www.plupload.com/contributing
+ */
+
+package com.plupload {
+ import flash.display.LoaderInfo;
+ import flash.display.Sprite;
+ import flash.errors.IOError;
+ import flash.net.FileReferenceList;
+ import flash.net.FileReference;
+ import flash.net.FileFilter;
+ import flash.net.URLLoader;
+ import flash.net.URLRequest;
+ import flash.net.URLRequestMethod;
+ import flash.net.URLVariables;
+ import flash.net.URLStream;
+ import flash.events.Event;
+ import flash.events.MouseEvent;
+ import flash.events.FocusEvent;
+ import flash.events.ProgressEvent;
+ import flash.events.IOErrorEvent;
+ import flash.events.SecurityErrorEvent;
+ import flash.events.DataEvent;
+ import flash.display.MovieClip;
+ import flash.display.StageAlign;
+ import flash.display.StageScaleMode;
+ import flash.external.ExternalInterface;
+ import flash.utils.ByteArray;
+ import flash.utils.Dictionary;
+ import flash.errors.IllegalOperationError;
+ import flash.system.Security;
+ import com.mxi.image.events.ImageEvent;
+ import com.mxi.image.events.ExifParserEvent;
+
+ /**
+ * This is the main class of the Plupload package.
+ */
+ public class Plupload extends Sprite {
+ // Private fields
+ private var clickArea:MovieClip;
+ private var fileRefList:FileReferenceList;
+ private var files:Dictionary;
+ private var idCounter:int = 0;
+ private var currentFile:File;
+ private var id:String;
+ private var fileFilters:Array;
+ private var multipleFiles:Boolean;
+ private var fileRefArray:Array = [];
+ private var fileRef:FileReference;
+ private var _disabled:Boolean = false;
+
+ /**
+ * Main constructor for the Plupload class.
+ */
+ public function Plupload():void {
+ if (stage)
+ init();
+ else
+ addEventListener(Event.ADDED_TO_STAGE, init);
+ }
+
+ /**
+ * Initialization event handler.
+ *
+ * @param e Event object.
+ */
+ private function init(e:Event = null):void {
+ removeEventListener(Event.ADDED_TO_STAGE, init);
+
+ // Allow cross domain scripting access
+ // Security.allowDomain("*");
+
+ // Setup id
+ this.id = (this.stage.loaderInfo.parameters["id"]).toString().replace(/[^\w]/g, ''); // allow only [a-zA-Z0-9_]
+
+ // Setup file reference list
+ this.fileRefList = new FileReferenceList();
+ this.fileRefList.addEventListener(Event.CANCEL, cancelEvent);
+ this.fileRefList.addEventListener(Event.SELECT, selectEvent);
+
+ initSingleFileReference();
+
+ this.files = new Dictionary();
+
+ // Align and scale stage
+ this.stage.align = StageAlign.TOP_LEFT;
+ this.stage.scaleMode = StageScaleMode.NO_SCALE;
+
+ // Add something to click on
+ this.clickArea = new MovieClip();
+ this.clickArea.graphics.beginFill(0x000000, 0); // Fill with transparent color
+ this.clickArea.graphics.drawRect(0, 0, 1024, 1024);
+ this.clickArea.x = 0;
+ this.clickArea.y = 0;
+ this.clickArea.width = 1024;
+ this.clickArea.height = 1024;
+ this.clickArea.graphics.endFill();
+ this.clickArea.buttonMode = true;
+ this.clickArea.useHandCursor = true;
+ addChild(this.clickArea);
+
+ // Register event handlers
+ this.clickArea.addEventListener(MouseEvent.ROLL_OVER, this.stageEvent);
+ this.clickArea.addEventListener(MouseEvent.ROLL_OUT, this.stageEvent);
+ this.clickArea.addEventListener(MouseEvent.CLICK, this.stageClickEvent);
+ this.clickArea.addEventListener(MouseEvent.MOUSE_DOWN, this.stageEvent);
+ this.clickArea.addEventListener(MouseEvent.MOUSE_UP, this.stageEvent);
+ this.clickArea.addEventListener(FocusEvent.FOCUS_IN, this.stageEvent);
+ this.clickArea.addEventListener(FocusEvent.FOCUS_OUT, this.stageEvent);
+
+ // Add external callbacks
+ ExternalInterface.addCallback('disableBrowse', this.disableBrowse);
+ ExternalInterface.addCallback('uploadFile', this.uploadFile);
+ ExternalInterface.addCallback('removeFile', this.removeFile);
+ ExternalInterface.addCallback('cancelUpload', this.cancelUpload);
+ ExternalInterface.addCallback('clearQueue', this.clearFiles);
+ ExternalInterface.addCallback('setFileFilters', this.setFileFilters);
+ ExternalInterface.addCallback('uploadNextChunk', this.uploadNextChunk);
+
+ this.fireEvent("Init");
+ }
+
+
+ /**
+ * In case of multipleFiles=false FileReference needs to be reinitialized for every file select dialog
+ */
+ private function initSingleFileReference() : void {
+ if (this.fileRef) {
+ this.fileRef = null;
+ }
+
+ this.fileRef = new FileReference();
+ this.fileRef.addEventListener(Event.CANCEL, cancelEvent);
+ this.fileRef.addEventListener(Event.SELECT, selectEvent);
+ }
+
+ /**
+ * Event handler for selection cancelled. This simply fires the event out to the page level JS.
+ *
+ * @param e Event object.
+ */
+ private function cancelEvent(e:Event):void {
+ this.fireEvent("CancelSelect");
+ }
+
+ /**
+ * Event handler for when the user select files to upload. This method builds up a simpler object
+ * representation and passes this back to the page level JS.
+ *
+ * @param e Event object.
+ */
+ private function selectEvent(e:Event):void {
+ var selectedFiles:Array = [], files:Dictionary = this.files;
+
+ function processFile(file:File):void {
+ // Add progress listener
+ file.addEventListener(ProgressEvent.PROGRESS, function(e:ProgressEvent):void {
+ var file:File = e.target as File;
+
+ fireEvent("UploadProcess", {
+ id : file.id,
+ loaded : e.bytesLoaded,
+ size : e.bytesTotal
+ });
+ });
+
+ // Add error listener
+ file.addEventListener(IOErrorEvent.IO_ERROR, function(e:IOErrorEvent):void {
+ var file:File = e.target as File;
+
+ fireEvent("IOError", {
+ id : file.id,
+ message : e.text.replace(/\\/g, "\\\\")
+ });
+ });
+
+ // Add error listener
+ file.addEventListener(SecurityErrorEvent.SECURITY_ERROR, function(e:SecurityErrorEvent):void {
+ var file:File = e.target as File;
+
+ fireEvent("SecurityError", {
+ id : file.id,
+ message : e.text.replace(/\\/g, "\\\\")
+ });
+ });
+
+ file.addEventListener(ExifParserEvent.EXIF_DATA, function(e:ExifParserEvent) : void {
+ var file:File = e.target as File;
+
+ fireEvent("ExifData", {
+ id : file.id,
+ data : e.data
+ });
+ });
+
+
+ file.addEventListener(ExifParserEvent.GPS_DATA, function(e:ExifParserEvent) : void
+ {
+ var file:File = e.target as File;
+
+ fireEvent("GpsData", {
+ id : file.id,
+ data : e.data
+ });
+ });
+
+
+ file.addEventListener(ImageEvent.ERROR, function(e:ImageEvent) : void {
+ var file:File = e.target as File;
+
+ fireEvent("ImageError", {
+ id : file.id,
+ code: e.code
+ });
+ });
+
+
+ // Add response listener
+ file.addEventListener(DataEvent.UPLOAD_COMPLETE_DATA, function(e:DataEvent):void {
+ var file:File = e.target as File;
+
+ fireEvent("UploadComplete", {
+ id : file.id,
+ text : e.text.replace(/\\/g, "\\\\")
+ });
+ });
+
+ // Add chunk response listener
+ file.addEventListener(UploadChunkEvent.UPLOAD_CHUNK_COMPLETE_DATA, function(e:UploadChunkEvent):void {
+ var file:File = e.target as File;
+
+ fireEvent("UploadChunkComplete", {
+ id : file.id,
+ text : e.text.replace(/\\/g, "\\\\"),
+ chunk : e.chunk,
+ chunks : e.chunks
+ });
+ });
+
+ files[file.id] = file;
+
+ // Setup selected files object to pass page to page level js
+ selectedFiles.push({id : file.id, name : file.fileName, size : file.size, loaded : 0});
+ }
+
+ if (this.multipleFiles) {
+ for (var i:Number = 0; i < this.fileRefList.fileList.length; i++) {
+ processFile(new File("file_" + (this.idCounter++), this.fileRefList.fileList[i]));
+ }
+ } else {
+ processFile(new File("file_" + (this.idCounter++), this.fileRef));
+ this.fileRefArray.push(this.fileRef);
+ initSingleFileReference();
+ }
+
+ this.fireEvent("SelectFiles", selectedFiles);
+ }
+
+ /**
+ * Sefnd out all stage events to page level JS inorder to fake click, hover etc.
+ *
+ * @param e Event object.
+ */
+ private function stageEvent(e:Event):void {
+ this.fireEvent("StageEvent:" + e.type);
+ }
+
+ /**
+ * Event handler that get executed when the user clicks the state. This will bring up
+ * the file browser dialog.
+ *
+ * @param e Event object.
+ */
+ private function stageClickEvent(e:Event):void {
+ var filters:Array = [], i:int;
+
+ if (this._disabled) {
+ return;
+ }
+
+ if (this.fileFilters != null) {
+ for (i = 0; i < this.fileFilters.length; i++) {
+ filters.push(new FileFilter(
+ this.fileFilters[i].title,
+ '*.' + this.fileFilters[i].extensions.replace(/,/g, ";*."),
+ this.fileFilters[i].mac_types
+ ));
+ }
+ }
+
+ try {
+ if (this.multipleFiles) {
+ if (filters.length > 0)
+ this.fileRefList.browse(filters);
+ else
+ this.fileRefList.browse();
+ } else {
+ if (filters.length > 0)
+ this.fileRef.browse(filters);
+ else
+ this.fileRef.browse();
+ }
+ } catch (ex1:IllegalOperationError) {
+ this.fireEvent("SelectError", ex1.message);
+ } catch (ex2:ArgumentError) {
+ this.fireEvent("SelectError", ex2.message);
+ }
+ }
+
+ /**
+ * Disable file dialog trigger.
+ *
+ * @param disabled Boolean Disable or enable file dialog trigger.
+ */
+ private function disableBrowse(disabled:Boolean = true):void {
+ this._disabled = disabled;
+ }
+
+
+ /**
+ * External interface function. This can be called from page level JS to start the upload of a specific file.
+ *
+ * @param id File id to upload.
+ * @param url Url to upload the file to.
+ * @param settings Settings object.
+ */
+ private function uploadFile(id:String, url:String, settings:Object):void {
+ var file:File = this.files[id] as File;
+
+ if (file) {
+ this.currentFile = file;
+ file.upload(url, settings);
+ }
+ }
+
+ /**
+ * Uploads the next chunk of the current file will return false when all chunks are uploaded.
+ *
+ * @return true/false if there is chunks left to upload.
+ */
+ private function uploadNextChunk():Boolean {
+ if (this.currentFile) {
+ return this.currentFile.uploadNextChunk();
+ }
+
+ return false;
+ }
+
+ /**
+ * File id to remove form upload queue.
+ *
+ * @param id Id of the file to remove.
+ */
+ private function removeFile(id:String):void {
+ if (this.files[id] != null)
+ delete this.files[id];
+ }
+
+ /**
+ * Cancel upload.
+ */
+ private function cancelUpload(): void {
+ if (this.currentFile) {
+ this.currentFile.cancelUpload();
+ }
+ }
+
+ /**
+ * Remove all files from upload queue.
+ *
+ * @param id Id of the file to remove.
+ */
+ private function clearFiles():void {
+ this.files = new Dictionary();
+ }
+
+ /**
+ * Sets file filters to be used for selection.
+ *
+ * @param filters Id of the file to remove.
+ * @param multi Bool state if multiple files is to be selected.
+ */
+ private function setFileFilters(filters:Array, multi:Boolean):void {
+ this.fileFilters = filters;
+ this.multipleFiles = multi;
+ }
+
+ /**
+ * Fires an event from the flash movie out to the page level JS.
+ *
+ * @param type Name of event to fire.
+ * @param obj Object with optional data.
+ */
+ private function fireEvent(type:String, obj:Object = null):void {
+ ExternalInterface.call("plupload.flash.trigger", this.id, type, obj);
+ }
+
+ /**
+ * Debugs out a message to Firebug.
+ *
+ * @param msg Message to output to firebug.
+ */
+ public static function debug(msg:String):void {
+ ExternalInterface.call("console.log", msg);
+ }
+ }
+}
diff --git a/debian/missing-sources/plupload/flash/plupload/src/com/plupload/UploadChunkEvent.as b/debian/missing-sources/plupload/flash/plupload/src/com/plupload/UploadChunkEvent.as
new file mode 100644
index 0000000..1b3d6a3
--- /dev/null
+++ b/debian/missing-sources/plupload/flash/plupload/src/com/plupload/UploadChunkEvent.as
@@ -0,0 +1,56 @@
+/**
+ * UploadChunkEvent.as
+ *
+ * Copyright 2009, Moxiecode Systems AB
+ * Released under GPL License.
+ *
+ * License: http://www.plupload.com/license
+ * Contributing: http://www.plupload.com/contributing
+ */
+
+package com.plupload {
+ import flash.events.DataEvent;
+
+ /**
+ * This class is used for uploads of chunks.
+ */
+ public class UploadChunkEvent extends DataEvent {
+ // Private fields
+ private var _chunk:int, _chunks:int;
+
+ /**
+ * Chunk complete event name.
+ */
+ public static const UPLOAD_CHUNK_COMPLETE_DATA:String = 'uploadchunk';
+
+ /**
+ * Chunk property.
+ */
+ public function get chunk():int {
+ return this._chunk;
+ }
+
+ /**
+ * Chunks property.
+ */
+ public function get chunks():int {
+ return this._chunks;
+ }
+
+ /**
+ * Main constructor for the UploadChunkEvent.
+ *
+ * @param type
+ * @param bubbles
+ * @param cancelable
+ * @param data
+ * @param chunk
+ * @param chunks
+ */
+ function UploadChunkEvent(type:String, bubbles:Boolean, cancelable:Boolean, data:String, chunk:int, chunks:int) {
+ super(type, bubbles, cancelable, data);
+ this._chunk = chunk;
+ this._chunks = chunks;
+ }
+ }
+} \ No newline at end of file
diff --git a/debian/missing-sources/plupload/javascript/i18n/cs.js b/debian/missing-sources/plupload/javascript/i18n/cs.js
new file mode 100644
index 0000000..1ee5d5f
--- /dev/null
+++ b/debian/missing-sources/plupload/javascript/i18n/cs.js
@@ -0,0 +1,14 @@
+// .po file like language pack
+plupload.addI18n({
+ 'Select files' : 'Vyberte soubory',
+ 'Add files to the upload queue and click the start button.' : 'Přidejte soubory do fronty a pak spusťte nahrávání.',
+ 'Filename' : 'Název souboru',
+ 'Status' : 'Status',
+ 'Size' : 'Velikost',
+ 'Add Files' : 'Přidat soubory',
+ 'Stop current upload' : 'Zastavit nahrávání',
+ 'Start uploading queue' : 'Spustit frontu nahrávání',
+ 'Drag files here.' : 'Sem přetáhněte soubory.',
+ 'Start Upload': 'Spustit nahrávání',
+ 'Uploaded %d/%d files': 'Nahráno %d/%d souborů'
+}); \ No newline at end of file
diff --git a/debian/missing-sources/plupload/javascript/i18n/da.js b/debian/missing-sources/plupload/javascript/i18n/da.js
new file mode 100644
index 0000000..fc95896
--- /dev/null
+++ b/debian/missing-sources/plupload/javascript/i18n/da.js
@@ -0,0 +1,12 @@
+// .po file like language pack
+plupload.addI18n({
+ 'Select files' : 'Vælg filer',
+ 'Add files to the upload queue and click the start button.' : 'Tilføj filer til køen, og tryk på start.',
+ 'Filename' : 'Filnavn',
+ 'Status' : 'Status',
+ 'Size' : 'Størrelse',
+ 'Add files' : 'Tilføj filer',
+ 'Stop current upload' : 'Stop upload',
+ 'Start uploading queue' : 'Start upload',
+ 'Drag files here.' : 'Træk filer her.'
+}); \ No newline at end of file
diff --git a/debian/missing-sources/plupload/javascript/i18n/de.js b/debian/missing-sources/plupload/javascript/i18n/de.js
new file mode 100644
index 0000000..4c4de07
--- /dev/null
+++ b/debian/missing-sources/plupload/javascript/i18n/de.js
@@ -0,0 +1,24 @@
+// German
+plupload.addI18n({
+ 'Select files' : 'Dateien hochladen',
+ 'Add files to the upload queue and click the start button.' : 'Dateien hinzuf&uuml;gen und auf \'Hochladen\' klicken.',
+ 'Filename' : 'Dateiname',
+ 'Status' : 'Status',
+ 'Size' : 'Gr&ouml;&szlig;e',
+ 'Add files' : 'Dateien', // hinzuf&uuml;gen',
+ 'Stop current upload' : 'Aktuelles Hochladen stoppen',
+ 'Start uploading queue' : 'Hochladen starten',
+ 'Uploaded %d/%d files': '%d/%d Dateien sind hochgeladen',
+ 'N/A' : 'Nicht verf&uuml;gbar',
+ 'Drag files here.' : 'Ziehen Sie die Dateien hier hin',
+ 'File extension error.': 'Fehler bei Dateiendung',
+ 'File size error.': 'Fehler bei Dateigr&ouml;ße',
+ 'Init error.': 'Initialisierungsfehler',
+ 'HTTP Error.': 'HTTP-Fehler',
+ 'Security error.': 'Sicherheitsfehler',
+ 'Generic error.': 'Typischer Fehler',
+ 'IO error.': 'Ein/Ausgabe-Fehler',
+ 'Stop Upload': 'Hochladen stoppen',
+ 'Start upload': 'Hochladen',
+ '%d files queued': '%d Dateien in der Warteschlange'
+}); \ No newline at end of file
diff --git a/debian/missing-sources/plupload/javascript/i18n/el.js b/debian/missing-sources/plupload/javascript/i18n/el.js
new file mode 100644
index 0000000..aafbaf1
--- /dev/null
+++ b/debian/missing-sources/plupload/javascript/i18n/el.js
@@ -0,0 +1,14 @@
+// Greek
+plupload.addI18n({
+ 'Select files' : 'Επιλέξτε ΑÏχεία',
+ 'Add files to the upload queue and click the start button.' : 'ΠÏοσθήκη αÏχείων στην ουÏά μεταφόÏτωσης',
+ 'Filename' : 'Όνομα αÏχείου',
+ 'Status' : 'Κατάσταση',
+ 'Size' : 'Μέγεθος',
+ 'Add Files' : 'ΠÏοσθέστε αÏχεία',
+ 'Stop current upload' : 'Διακοπή Ï„Ïέχουσας μεταφόÏτωσης',
+ 'Start uploading queue' : 'Εκκίνηση μεταφόÏτωσης ουÏάς αÏχείων',
+ 'Drag files here.' : 'ΣÏÏετε αÏχεία εδώ',
+ 'Start Upload': 'Εκκίνηση μεταφόÏτωσης',
+ 'Uploaded %d/%d files': 'Ανέβηκαν %d/%d αÏχεία'
+}); \ No newline at end of file
diff --git a/debian/missing-sources/plupload/javascript/i18n/es.js b/debian/missing-sources/plupload/javascript/i18n/es.js
new file mode 100644
index 0000000..2379421
--- /dev/null
+++ b/debian/missing-sources/plupload/javascript/i18n/es.js
@@ -0,0 +1,25 @@
+// Spanish
+plupload.addI18n({
+ 'Select files' : 'Elija archivos:',
+ 'Add files to the upload queue and click the start button.' : 'Agregue archivos a la cola de subida y haga click en el boton de iniciar.',
+ 'Filename' : 'Nombre de archivo',
+ 'Status' : 'Estado',
+ 'Size' : 'Tama&ntilde;o',
+ 'Add files' : 'Agregue archivos',
+ 'Stop current upload' : 'Detener subida actual',
+ 'Start uploading queue' : 'Iniciar subida de cola',
+ 'Uploaded %d/%d files': 'Subidos %d/%d archivos',
+ 'N/A' : 'No disponible',
+ 'Drag files here.' : 'Arrastre archivos aqu&iacute;',
+ 'File extension error.': 'Error de extensi&oacute;n de archivo.',
+ 'File size error.': 'Error de tama&ntilde;o de archivo.',
+ 'Init error.': 'Error de inicializaci&oacute;n.',
+ 'HTTP Error.': 'Error de HTTP.',
+ 'Security error.': 'Error de seguridad.',
+ 'Generic error.': 'Error gen&eacute;rico.',
+ 'IO error.': 'Error de entrada/salida.',
+ 'Stop Upload': 'Detener Subida.',
+ 'Add Files': 'Agregar Archivos',
+ 'Start Upload': 'Comenzar Subida.',
+ '%d files queued': '%d archivos en cola.'
+}); \ No newline at end of file
diff --git a/debian/missing-sources/plupload/javascript/i18n/et.js b/debian/missing-sources/plupload/javascript/i18n/et.js
new file mode 100644
index 0000000..a4a5e3a
--- /dev/null
+++ b/debian/missing-sources/plupload/javascript/i18n/et.js
@@ -0,0 +1,33 @@
+// Estonian translation, et.js
+plupload.addI18n({
+ 'Select files' : 'Vali faile',
+ 'Add files to the upload queue and click the start button.' : 'Lisa failid üleslaadimise järjekorda ja klõpsa alustamise nupule.',
+ 'Filename' : 'Failinimi',
+ 'Status' : 'Olek',
+ 'Size' : 'Suurus',
+ 'Add files' : 'Lisa faile',
+ 'Stop current upload' : 'Praeguse üleslaadimise peatamine',
+ 'Start uploading queue' : 'Järjekorras ootavate failide üleslaadimise alustamine',
+ 'Drag files here.' : 'Lohista failid siia.',
+ 'Start upload' : 'Alusta üleslaadimist',
+ 'Uploaded %d/%d files': 'Ãœles laaditud %d/%d',
+ 'Stop upload': 'Peata üleslaadimine',
+ 'Start upload': 'Alusta üleslaadimist',
+ '%d files queued': 'Järjekorras on %d faili',
+ 'File: %s': 'Fail: %s',
+ 'Close': 'Sulge',
+ 'Using runtime: ': 'Kasutatakse varianti: ',
+ 'File: %f, size: %s, max file size: %m': 'Fail: %f, suurus: %s, suurim failisuurus: %m',
+ 'Upload element accepts only %d file(s) at a time. Extra files were stripped.': 'Üleslaadimise element saab vastu võtta ainult %d faili ühe korraga. Ülejäänud failid jäetakse laadimata.',
+ 'Upload URL might be wrong or doesn\'t exist': 'Üleslaadimise URL võib olla vale või seda pole',
+ 'Error: File too large: ': 'Viga: fail on liiga suur: ',
+ 'Error: Invalid file extension: ': 'Viga: sobimatu faililaiend: ',
+ 'File extension error.': 'Faililaiendi viga.',
+ 'File size error.': 'Failisuuruse viga.',
+ 'File count error.': 'Failide arvu viga.',
+ 'Init error.': 'Lähtestamise viga.',
+ 'HTTP Error.': 'HTTP ühenduse viga.',
+ 'Security error.': 'Turvaviga.',
+ 'Generic error.': 'Ãœldine viga.',
+ 'IO error.': 'S/V (I/O) viga.'
+}); \ No newline at end of file
diff --git a/debian/missing-sources/plupload/javascript/i18n/fa.js b/debian/missing-sources/plupload/javascript/i18n/fa.js
new file mode 100644
index 0000000..af36e22
--- /dev/null
+++ b/debian/missing-sources/plupload/javascript/i18n/fa.js
@@ -0,0 +1,37 @@
+// Persian
+plupload.addI18n({
+ 'Select files' : 'انتخاب Ùایل',
+ 'Add files to the upload queue and click the start button.' : 'اضاÙÙ‡ کنید Ùایل ها را به ص٠آپلود Ùˆ دکمه شروع را کلیک کنید.',
+ 'Filename' : 'نام Ùایل',
+ 'Status' : 'وضعیت',
+ 'Size' : 'سایز',
+ 'Add Files' : 'اÙزودن Ùایل',
+ 'Stop Upload' : 'توق٠انتقال',
+ 'Start Upload' : 'شروع انتقال',
+ 'Add files' : 'اÙزودن Ùایل',
+ 'Add files.' : 'اÙزودن Ùایل',
+ 'Stop current upload' : 'توق٠انتقال جاری',
+ 'Start uploading queue' : 'شروع ص٠انتقال',
+ 'Stop upload' : 'توق٠انتقال',
+ 'Start upload' : 'شروع انتقال',
+ 'Uploaded %d/%d files': 'منتقل شد %d/%d از Ùایلها',
+ 'N/A' : 'N/A',
+ 'Drag files here.' : 'بکشید Ùایل ها رو به اینجا',
+ 'File extension error.': 'خطا پیشوند Ùایل',
+ 'File size error.': 'خطای سایز Ùایل',
+ 'File count error.': 'خطای تعداد Ùایل',
+ 'Init error.': 'خطا در استارت اسکریپت',
+ 'HTTP Error.': 'HTTP خطای',
+ 'Security error.': 'خطای امنیتی',
+ 'Generic error.': 'خطای عمومی',
+ 'IO error.': 'IO خطای',
+ 'File: %s': ' Ùایل ها : %s',
+ 'Close': 'بستن',
+ '%d files queued': '%d Ùایل در صÙ',
+ 'Using runtime: ': 'استÙاده میکنید از : ',
+ 'File: %f, size: %s, max file size: %m': Ùایل: %f, سایز: %s, بزرگترین سایز Ùایل: %m',
+ 'Upload element accepts only %d file(s) at a time. Extra files were stripped.': 'عنصر بارگذار Ùقط %d Ùایل رو در یک زمان Ù…ÛŒ پذیرد. سایر Ùایل ها مجرد از این موضوع هستند.',
+ 'Upload URL might be wrong or doesn\'t exist': 'آدرس آپلود اشتباه می باشد یا وجود ندارد',
+ 'Error: File too large: ': 'خطا: Ùایل حجیم است :: ',
+ 'Error: Invalid file extension: ': 'خطا پسوند Ùایل معتبر نمی باشد : '
+});
diff --git a/debian/missing-sources/plupload/javascript/i18n/fi.js b/debian/missing-sources/plupload/javascript/i18n/fi.js
new file mode 100644
index 0000000..12a639e
--- /dev/null
+++ b/debian/missing-sources/plupload/javascript/i18n/fi.js
@@ -0,0 +1,33 @@
+// .fi file like language pack
+plupload.addI18n({
+ 'Select files' : 'Valitse tiedostoja',
+ 'Add files to the upload queue and click the start button.' : 'Lisää tiedostoja latausjonoon ja klikkaa aloita-nappia.',
+ 'Filename' : 'Tiedostonimi',
+ 'Status' : 'Tila',
+ 'Size' : 'Koko',
+ 'Add files' : 'Lisää tiedostoja',
+ 'Stop current upload' : 'Pysäytä nykyinen lataus',
+ 'Start uploading queue' : 'Aloita jonon lataus',
+ 'Drag files here.' : 'Raahaa tiedostot tänne.',
+ 'Start upload' : 'Aloita lataus',
+ 'Uploaded %d/%d files': 'Ladattu %d/%d tiedostoa',
+ 'Stop upload': 'Pysäytä lataus',
+ 'Start upload': 'Aloita lataus',
+ '%d files queued': '%d tiedostoa jonossa',
+ 'File: %s': 'Tiedosto: %s',
+ 'Close': 'Sulje',
+ 'Using runtime: ': 'Käytetään ajonaikaista: ',
+ 'File: %f, size: %s, max file size: %m': 'Tiedosto: %f, koko: %s, maksimi tiedostokoko: %m',
+ 'Upload element accepts only %d file(s) at a time. Extra files were stripped.': 'Latauselementti sallii ladata vain %d tiedosto(a) kerrallaan. Ylimääräiset tiedostot ohitettiin.',
+ 'Upload URL might be wrong or doesn\'t exist': 'Lataus URL saattaa olla väärin tai ei ole olemassa',
+ 'Error: File too large: ': 'Virhe: Tiedosto liian suuri: ',
+ 'Error: Invalid file extension: ': 'Virhe: Kelpaamaton tiedostopääte: ',
+ 'File extension error.': 'Tiedostopäätevirhe.',
+ 'File size error.': 'Tiedostokokovirhe.',
+ 'File count error.': 'Tiedostolaskentavirhe.',
+ 'Init error.': 'Init virhe.',
+ 'HTTP Error.': 'HTTP virhe.',
+ 'Security error.': 'Tietoturvavirhe.',
+ 'Generic error.': 'Yleinen virhe.',
+ 'IO error.': 'I/O virhe.'
+}); \ No newline at end of file
diff --git a/debian/missing-sources/plupload/javascript/i18n/fr-ca.js b/debian/missing-sources/plupload/javascript/i18n/fr-ca.js
new file mode 100644
index 0000000..61aba23
--- /dev/null
+++ b/debian/missing-sources/plupload/javascript/i18n/fr-ca.js
@@ -0,0 +1,35 @@
+// French-Canadian
+plupload.addI18n({
+ 'Select files' : 'Sélectionnez les fichiers',
+ 'Add files to the upload queue and click the start button.' : 'Ajoutez des fichiers à la file d\'attente et appuyez sur le bouton démarrer.',
+ 'Filename' : 'Nom du fichier',
+ 'Status' : 'Statut',
+ 'Size' : 'Taille',
+ 'Add files' : 'Ajouter Fichiers',
+ 'Stop current upload' : 'Arrêter le téléversement actuel',
+ 'Start uploading queue' : 'Démarrer le téléversement',
+ 'Uploaded %d/%d files': '%d/%d fichiers envoyés',
+ 'N/A' : 'Non applicable',
+ 'Drag files here.' : 'Glisser-déposer les fichiers ici',
+ 'File extension error.': 'Erreur d\'extension de fichier',
+ 'File size error.': 'Erreur de taille de fichier',
+ 'Init error.': 'Erreur d\'initialisation',
+ 'HTTP Error.': 'Erreur HTTP',
+ 'Security error.': 'Erreur de sécurité',
+ 'Generic error.': 'Erreur commune',
+ 'IO error.': 'Erreur E/S',
+ 'Stop Upload': 'Arrêter le téléversement',
+ 'Add Files': 'Ajouter des fichiers',
+ 'Start upload': 'Démarrer le téléversement',
+ '%d files queued': '%d fichiers en attente',
+ 'File: %s':'Fichier: %s',
+ 'Close':'Fermer',
+ 'Using runtime:':'Moteur logiciel:',
+ 'File: %f, size: %s, max file size: %m':'Fichier: %f, poids: %s, poids maximal: %m',
+ 'Upload element accepts only %d file(s) at a time. Extra files were stripped.':'La file accepte %d fichier(s) à la fois. Les fichiers en trop sont ignorés',
+ 'Upload URL might be wrong or doesn\'t exist':'L\'URL de téléversement est erroné ou inexistant',
+ 'Error: File to large: ':'Fichier trop volumineux: ',
+ 'Error: Invalid file extension: ':'Extension de fichier invalide: ',
+ 'File size error.':'Erreur de taile de fichier',
+ 'File count error.':'Erreur de décompte des fichiers'
+}); \ No newline at end of file
diff --git a/debian/missing-sources/plupload/javascript/i18n/fr.js b/debian/missing-sources/plupload/javascript/i18n/fr.js
new file mode 100644
index 0000000..53dbe28
--- /dev/null
+++ b/debian/missing-sources/plupload/javascript/i18n/fr.js
@@ -0,0 +1,25 @@
+// French
+plupload.addI18n({
+ 'Select files' : 'Sélectionnez les fichiers',
+ 'Add files to the upload queue and click the start button.' : 'Ajoutez des fichiers à la file et appuyez sur le bouton démarrer.',
+ 'Filename' : 'Nom de fichier',
+ 'Status' : 'Status',
+ 'Size' : 'Taille',
+ 'Add files' : 'Ajouter Fichiers',
+ 'Stop current upload' : 'Arrêter l\'envoi en cours',
+ 'Start uploading queue' : 'Démarrer l\'envoi',
+ 'Uploaded %d/%d files': '%d/%d fichiers envoyés',
+ 'N/A' : 'Non applicable',
+ 'Drag files here.' : 'Déposer les fichiers ici.',
+ 'File extension error.': 'Erreur extension fichier',
+ 'File size error.': 'Erreur taille fichier.',
+ 'Init error.': 'Erreur d\'initialisation.',
+ 'HTTP Error.': 'Erreur HTTP.',
+ 'Security error.': 'Erreur de sécurité.',
+ 'Generic error.': 'Erreur générique.',
+ 'IO error.': 'Erreur E/S.',
+ 'Stop Upload': 'Arrêter les envois.',
+ 'Add Files': 'Ajouter des fichiers',
+ 'Start Upload': 'Démarrer les envois.',
+ '%d files queued': '%d fichiers en attente.'
+}); \ No newline at end of file
diff --git a/debian/missing-sources/plupload/javascript/i18n/hr.js b/debian/missing-sources/plupload/javascript/i18n/hr.js
new file mode 100644
index 0000000..084be51
--- /dev/null
+++ b/debian/missing-sources/plupload/javascript/i18n/hr.js
@@ -0,0 +1,25 @@
+// Croatian
+plupload.addI18n({
+ 'Select files': 'Izaberite datoteke:',
+ 'Add files to the upload queue and click the start button.': 'Dodajte datoteke u listu i kliknite Upload.',
+ 'Filename': 'Ime datoteke',
+ 'Status': 'Status',
+ 'Size': 'VeliÄina',
+ 'Add files': 'Dodajte datoteke',
+ 'Stop current upload': 'Zaustavi trenutan upload',
+ 'Start uploading queue': 'Pokreni Upload',
+ 'Uploaded %d/%d files': 'Uploadano %d/%d datoteka',
+ 'N/A': 'N/A',
+ 'Drag files here.': 'Dovucite datoteke ovdje',
+ 'File extension error.': 'Greška ekstenzije datoteke.',
+ 'File size error.': 'GreÅ¡ka veliÄine datoteke.',
+ 'Init error.': 'Greška inicijalizacije.',
+ 'HTTP Error.': 'HTTP greška.',
+ 'Security error.': 'Sigurnosna greška.',
+ 'Generic error.': 'GeneriÄka greÅ¡ka.',
+ 'IO error.': 'I/O greška.',
+ 'Stop Upload': 'Zaustavi upload.',
+ 'Add Files': 'Dodaj datoteke',
+ 'Start Upload': 'Pokreni upload.',
+ '%d files queued': '%d datoteka na Äekanju.'
+}); \ No newline at end of file
diff --git a/debian/missing-sources/plupload/javascript/i18n/hu.js b/debian/missing-sources/plupload/javascript/i18n/hu.js
new file mode 100644
index 0000000..87070ba
--- /dev/null
+++ b/debian/missing-sources/plupload/javascript/i18n/hu.js
@@ -0,0 +1,33 @@
+// Hungarian
+plupload.addI18n({
+ 'Select files' : 'Fájlok kiválasztása',
+ 'Add files to the upload queue and click the start button.' : 'Válaszd ki a fájlokat, majd kattints az Indítás gombra.',
+ 'Filename' : 'Fájlnév',
+ 'Status' : 'Ãllapot',
+ 'Size' : 'Méret',
+ 'Add files' : 'Hozzáadás',
+ 'Stop current upload' : 'Jelenlegi feltöltés megszakítása',
+ 'Start uploading queue' : 'Várakozási sor feltöltésének indítása',
+ 'Uploaded %d/%d files': 'Feltöltött fájlok: %d/%d',
+ 'N/A': 'Nem elérhető',
+ 'Drag files here.' : 'Húzd ide a fájlokat.',
+ 'Stop upload': 'Feltöltés megszakítása',
+ 'Start upload': 'Indítás',
+ '%d files queued': '%d fájl sorbaállítva',
+ 'File: %s': 'Fájl: %s',
+ 'Close': 'Bezárás',
+ 'Using runtime: ': 'Használt runtime: ',
+ 'File: %f, size: %s, max file size: %m': 'Fájl: %f, méret: %s, maximális fájlméret: %m',
+ 'Upload element accepts only %d file(s) at a time. Extra files were stripped.': 'A feltöltés egyszerre csak %d fájlt fogad el, a többi fájl nem lesz feltöltve.',
+ 'Upload URL might be wrong or doesn\'t exist': 'A megadott URL hibás vagy nem létezik',
+ 'Error: File too large: ': 'Hiba: A fájl túl nagy: ',
+ 'Error: Invalid file extension: ': 'Hiba: Érvénytelen fájlkiterjesztés: ',
+ 'File extension error.': 'Hibás fájlkiterjesztés.',
+ 'File size error.': 'Hibás fájlméret.',
+ 'File count error.': 'A fájlok számával kapcsolatos hiba.',
+ 'Init error.': 'Init hiba.',
+ 'HTTP Error.': 'HTTP hiba.',
+ 'Security error.': 'Biztonsági hiba.',
+ 'Generic error.': 'Ãltalános hiba.',
+ 'IO error.': 'I/O hiba.'
+});
diff --git a/debian/missing-sources/plupload/javascript/i18n/it.js b/debian/missing-sources/plupload/javascript/i18n/it.js
new file mode 100644
index 0000000..891e4fb
--- /dev/null
+++ b/debian/missing-sources/plupload/javascript/i18n/it.js
@@ -0,0 +1,24 @@
+// Italian
+plupload.addI18n({
+ 'Select files' : 'Seleziona i files',
+ 'Add files to the upload queue and click the start button.' : 'Aggiungi i file alla coda di caricamento e clicca il pulsante di avvio.',
+ 'Filename' : 'Nome file',
+ 'Status' : 'Stato',
+ 'Size' : 'Dimensione',
+ 'Add Files' : 'Aggiungi file',
+ 'Stop current upload' : 'Interrompi il caricamento',
+ 'Start uploading queue' : 'Avvia il caricamento',
+ 'Uploaded %d/%d files': 'Caricati %d/%d file',
+ 'N/A' : 'N/D',
+ 'Drag files here.' : 'Trascina i file qui.',
+ 'File extension error.': 'Errore estensione file.',
+ 'File size error.': 'Errore dimensione file.',
+ 'Init error.': 'Errore inizializzazione.',
+ 'HTTP Error.': 'Errore HTTP.',
+ 'Security error.': 'Errore sicurezza.',
+ 'Generic error.': 'Errore generico.',
+ 'IO error.': 'Errore IO.',
+ 'Stop Upload': 'Ferma Upload',
+ 'Start Upload': 'Inizia Upload',
+ '%d files queued': '%d file in lista'
+}); \ No newline at end of file
diff --git a/debian/missing-sources/plupload/javascript/i18n/ja.js b/debian/missing-sources/plupload/javascript/i18n/ja.js
new file mode 100644
index 0000000..02c85ae
--- /dev/null
+++ b/debian/missing-sources/plupload/javascript/i18n/ja.js
@@ -0,0 +1,37 @@
+// Japanese
+plupload.addI18n({
+ 'Select files' : 'ファイルé¸æŠž',
+ 'Add files to the upload queue and click the start button.' : 'ファイルをアップロードキューã«è¿½åŠ ã—ã¦ã‚¹ã‚¿ãƒ¼ãƒˆãƒœã‚¿ãƒ³ã‚’クリックã—ã¦ãã ã•ã„',
+ 'Filename' : 'ファイルå',
+ 'Status' : 'ステータス',
+ 'Size' : 'サイズ',
+ 'Add Files' : 'ファイルを追加',
+ 'Stop Upload' : 'アップロードåœæ­¢',
+ 'Start Upload' : 'アップロード',
+ 'Add files' : 'ファイルを追加',
+ 'Add files.' : 'ファイルを追加',
+ 'Stop current upload' : 'ç¾åœ¨ã®ã‚¢ãƒƒãƒ—ロードをåœæ­¢',
+ 'Start uploading queue' : 'アップロード',
+ 'Stop upload' : 'アップロードåœæ­¢',
+ 'Start upload' : 'アップロード',
+ 'Uploaded %d/%d files': 'アップロード中 %d/%d ファイル',
+ 'N/A' : 'N/A',
+ 'Drag files here.' : 'ã“ã“ã«ãƒ•ã‚¡ã‚¤ãƒ«ã‚’ドラッグ',
+ 'File extension error.': 'ファイル拡張å­ã‚¨ãƒ©ãƒ¼',
+ 'File size error.': 'ファイルサイズエラー',
+ 'File count error.': 'ファイル数エラー',
+ 'Init error.': 'イニシャライズエラー',
+ 'HTTP Error.': 'HTTP エラー',
+ 'Security error.': 'セキュリティエラー',
+ 'Generic error.': 'エラー',
+ 'IO error.': 'IO エラー',
+ 'File: %s': 'ファイル: %s',
+ 'Close': 'é–‰ã˜ã‚‹',
+ '%d files queued': '%d ファイルãŒè¿½åŠ ã•ã‚Œã¾ã—ãŸ',
+ 'Using runtime: ': 'モード: ',
+ 'File: %f, size: %s, max file size: %m': 'ファイル: %f, サイズ: %s, 最大ファイルサイズ: %m',
+ 'Upload element accepts only %d file(s) at a time. Extra files were stripped.': 'アップロードå¯èƒ½ãªãƒ•ã‚¡ã‚¤ãƒ«æ•°ã¯ %d ã§ã™ã€‚余分ãªãƒ•ã‚¡ã‚¤ãƒ«ã¯å‰Šé™¤ã•ã‚Œã¾ã—ãŸ',
+ 'Upload URL might be wrong or doesn\'t exist': 'アップロード先㮠URL ãŒå­˜åœ¨ã—ã¾ã›ã‚“',
+ 'Error: File too large: ': 'エラー: サイズãŒå¤§ãã™ãŽã¾ã™: ',
+ 'Error: Invalid file extension: ': 'エラー: æ‹¡å¼µå­ãŒè¨±å¯ã•ã‚Œã¦ã„ã¾ã›ã‚“: '
+});
diff --git a/debian/missing-sources/plupload/javascript/i18n/ko.js b/debian/missing-sources/plupload/javascript/i18n/ko.js
new file mode 100644
index 0000000..a2c5e66
--- /dev/null
+++ b/debian/missing-sources/plupload/javascript/i18n/ko.js
@@ -0,0 +1,36 @@
+// Republic of Korea
+plupload.addI18n({
+ 'Select files' : 'íŒŒì¼ ì„ íƒ',
+ 'Add files to the upload queue and click the start button.' : '파ì¼ì„ 업로드 íì— ì¶”ê°€í•˜ì—¬ 시작 ë²„íŠ¼ì„ í´ë¦­í•˜ì‹­ì‹œì˜¤.',
+ 'Filename' : 'íŒŒì¼ ì´ë¦„',
+ 'Status' : 'ìƒíƒœ',
+ 'Size' : 'í¬ê¸°',
+ 'Add Files' : 'íŒŒì¼ ì¶”ê°€',
+ 'Stop Upload': '업로드 중지',
+ 'Start Upload': '업로드',
+ 'Add files': 'íŒŒì¼ ì¶”ê°€',
+ 'Stop current upload': '현재 업로드를 정지',
+ 'Start uploading queue': '업로드',
+ 'Stop upload': '업로드 중지',
+ 'Start upload': '업로드',
+ 'Uploaded % d / % d files': '업로드 중 % d / % d 파ì¼',
+ 'N / A': 'N / A',
+ 'Drag files here': 'ì—¬ê¸°ì— íŒŒì¼ì„ 드래그',
+ 'File extension error': 'íŒŒì¼ í™•ìž¥ìž ì˜¤ë¥˜',
+ 'File size error': 'íŒŒì¼ í¬ê¸° 오류',
+ 'File count error': 'ì´ë¯¸ì§€ : 오류',
+ 'Init error': '초기화 오류',
+ 'HTTP Error': 'HTTP 오류',
+ 'Security error': '보안 오류',
+ 'Generic error': '오류',
+ 'IO error': 'IO 오류',
+ 'File : % s': 'íŒŒì¼ % s',
+ 'Close': '닫기',
+ '% d files queued': '% d 파ì¼ì´ 추가ë˜ì—ˆìŠµë‹ˆë‹¤',
+ 'Using runtime :': '모드',
+ 'File : % f, size : % s, max file size : % m': 'íŒŒì¼ : % f, í¬ê¸° : % s, 최대 íŒŒì¼ í¬ê¸° : % m',
+ 'Upload element accepts only % d file (s) at a time. Extra files were stripped': '업로드 가능한 파ì¼ì˜ 수는 % d입니다. 불필요한 파ì¼ì€ ì‚­ì œë˜ì—ˆìŠµë‹ˆë‹¤ ',
+ 'Upload URL might be wrong or doesn \'t exist ':'업로드할 URLì´ ì¡´ìž¬í•˜ì§€ 않습니다 ',
+ 'Error : File too large :': '오류 : í¬ê¸°ê°€ 너무 í½ë‹ˆë‹¤',
+ 'Error : Invalid file extension :': '오류 : 확장ìžê°€ 허용ë˜ì§€ 않습니다 :'
+}); \ No newline at end of file
diff --git a/debian/missing-sources/plupload/javascript/i18n/lv.js b/debian/missing-sources/plupload/javascript/i18n/lv.js
new file mode 100644
index 0000000..2a04045
--- /dev/null
+++ b/debian/missing-sources/plupload/javascript/i18n/lv.js
@@ -0,0 +1,33 @@
+// .lv file like language pack
+plupload.addI18n({
+ 'Select files' : 'Izvēlieties failus',
+ 'Add files to the upload queue and click the start button.' : 'Pieveinojiet failus rindai un klikÅ¡Ä·iniet uz "SÄkt augÅ¡upielÄdi" pogas.',
+ 'Filename' : 'Faila nosaukums',
+ 'Status' : 'Statuss',
+ 'Size' : 'Izmērs',
+ 'Add files' : 'Pievienot failus',
+ 'Stop current upload' : 'ApturÄ“t paÅ¡reizÄ“jo augÅ¡upielÄdi',
+ 'Start uploading queue' : 'SÄkt augÅ¡upielÄdi',
+ 'Drag files here.' : 'Ievelciet failus Å¡eit',
+ 'Start upload' : 'SÄkt augÅ¡upielÄdi',
+ 'Uploaded %d/%d files': 'AugÅ¡upielÄdÄ“ti %d/%d faili',
+ 'Stop upload': 'PÄrtraukt augÅ¡upielÄdi',
+ 'Start upload': 'SÄkt augÅ¡upielÄdi',
+ '%d files queued': '%d faili pievienoti rindai',
+ 'File: %s': 'Fails: %s',
+ 'Close': 'Aizvērt',
+ 'Using runtime: ': 'Lieto saskarni: ',
+ 'File: %f, size: %s, max file size: %m': 'Fails: %f, izmÄ“rs: %s, maksimÄlais faila izmÄ“rs: %m',
+ 'Upload element accepts only %d file(s) at a time. Extra files were stripped.': 'IespÄ“jams ielÄdÄ“t tikai %d failus vienÄ reizÄ“. AtlikuÅ¡ie faili netika pievienoti',
+ 'Upload URL might be wrong or doesn\'t exist': 'AugÅ¡upielÄdes URL varÄ“tu bÅ«t nepareizs vai neeksistÄ“',
+ 'Error: File too large: ': 'Kļūda: Fails pÄrÄk liels: ',
+ 'Error: Invalid file extension: ': 'Kļūda: Nekorekts faila paplaÅ¡inÄjums:',
+ 'File extension error.': 'Faila paplaÅ¡inÄjuma kļūda.',
+ 'File size error.': 'Faila izmēra kļūda.',
+ 'File count error.': 'Failu skaita kļūda',
+ 'Init error.': 'InicializÄcijas kļūda.',
+ 'HTTP Error.': 'HTTP kļūda.',
+ 'Security error.': 'Drošības kļūda.',
+ 'Generic error.': 'VispÄrÄ“ja rakstura kļūda.',
+ 'IO error.': 'Ievades/Izvades kļūda.'
+}); \ No newline at end of file
diff --git a/debian/missing-sources/plupload/javascript/i18n/nl.js b/debian/missing-sources/plupload/javascript/i18n/nl.js
new file mode 100644
index 0000000..8372c88
--- /dev/null
+++ b/debian/missing-sources/plupload/javascript/i18n/nl.js
@@ -0,0 +1,21 @@
+// Dutch
+plupload.addI18n({
+ 'Select files' : 'Selecteer bestand(en):',
+ 'Add files to the upload queue and click the start button.' : 'Voeg bestanden toe aan de wachtrij en druk op \'Start\'.',
+ 'Filename' : 'Bestandsnaam',
+ 'Status' : 'Status',
+ 'Size' : 'Grootte',
+ 'Add files' : 'Voeg bestanden toe',
+ 'Stop current upload' : 'Stop upload',
+ 'Start uploading queue' : 'Start upload',
+ 'Uploaded %d/%d files': '%d/%d bestanden ge-upload',
+ 'N/A' : 'Niet beschikbaar',
+ 'Drag files here.' : 'Sleep bestanden hierheen.',
+ 'File extension error.': 'Ongeldig bestandstype.',
+ 'File size error.': 'Bestandsgrootte Error.',
+ 'Init error.': 'Initialisatie error.',
+ 'HTTP Error.': 'HTTP Error.',
+ 'Security error.': 'Beveiliging error.',
+ 'Generic error.': 'Onbekende error.',
+ 'IO error.': 'IO error.'
+}); \ No newline at end of file
diff --git a/debian/missing-sources/plupload/javascript/i18n/pl.js b/debian/missing-sources/plupload/javascript/i18n/pl.js
new file mode 100644
index 0000000..3d1b9be
--- /dev/null
+++ b/debian/missing-sources/plupload/javascript/i18n/pl.js
@@ -0,0 +1,24 @@
+plupload.addI18n({
+'Select files' : 'Wybierz pliki:',
+'Add files to the upload queue and click the start button.' : 'Dodaj pliki i kliknij \'Rozpocznij transfer\'.',
+'Filename' : 'Nazwa pliku',
+'Status' : 'Status',
+'Size' : 'Rozmiar',
+'Add files' : 'Dodaj pliki',
+'Stop current upload' : 'Przerwij aktualny transfer',
+'Start uploading queue' : 'Rozpocznij wysyłanie',
+'Uploaded %d/%d files': 'Wysłano %d/%d plików',
+'N/A' : 'Nie dostępne',
+'Drag files here.' : 'PrzeciÄ…gnij tu pliki',
+'File extension error.': 'Nieobsługiwany format pliku.',
+'File size error.': 'Plik jest zbyt duży.',
+'Init error.': 'BÅ‚Ä…d inicjalizacji.',
+'HTTP Error.': 'BÅ‚Ä…d HTTP.',
+'Security error.': 'Błąd bezpieczeństwa.',
+'Generic error.': 'Błąd ogólny.',
+'IO error.': 'BÅ‚Ä…d IO.',
+'Stop Upload': 'Przerwij transfer.',
+'Add Files': 'Dodaj pliki',
+'Start upload': 'Rozpocznij transfer.',
+'%d files queued': '%d plików w kolejce.'
+});
diff --git a/debian/missing-sources/plupload/javascript/i18n/pt-br.js b/debian/missing-sources/plupload/javascript/i18n/pt-br.js
new file mode 100644
index 0000000..9f34a64
--- /dev/null
+++ b/debian/missing-sources/plupload/javascript/i18n/pt-br.js
@@ -0,0 +1,35 @@
+// Brazilian Portuguese
+plupload.addI18n({
+ 'Select files' : 'Escolha os arquivos',
+ 'Add files to the upload queue and click the start button.' : 'Adicione os arquivos abaixo e clique no botão "Iniciar o envio".',
+ 'Filename' : 'Nome do arquivo',
+ 'Status' : 'Status',
+ 'Size' : 'Tamanho',
+ 'Add Files' : 'Adicionar arquivo(s)',
+ 'Stop Upload' : 'Parar o envio',
+ 'Start Upload' : 'Iniciar o envio',
+ 'Add files' : 'Adicionar arquivo(s)',
+ 'Add files.' : 'Adicionar arquivo(s)',
+ 'Stop upload' : 'Parar o envio',
+ 'Start upload' : 'Iniciar o envio',
+ 'Uploaded %d/%d files': 'Enviado(s) %d/%d arquivo(s)',
+ 'N/A' : 'N/D',
+ 'Drag files here.' : 'Arraste os arquivos pra cá',
+ 'File extension error.': 'Tipo de arquivo não permitido.',
+ 'File size error.': 'Tamanho de arquivo não permitido.',
+ 'File count error.': 'Erro na contagem dos arquivos',
+ 'Init error.': 'Erro inicializando.',
+ 'HTTP Error.': 'Erro HTTP.',
+ 'Security error.': 'Erro de segurança.',
+ 'Generic error.': 'Erro genérico.',
+ 'IO error.': 'Erro de E/S.',
+ 'File: %s': 'Arquivo: %s',
+ 'Close': 'Fechar',
+ '%d files queued': '%d arquivo(s)',
+ 'Using runtime: ': 'Usando: ',
+ 'File: %f, size: %s, max file size: %m': 'Arquivo: %f, tamanho: %s, máximo: %m',
+ 'Upload element accepts only %d file(s) at a time. Extra files were stripped.': 'Só são aceitos %d arquivos por vez. O que passou disso foi descartado.',
+ 'Upload URL might be wrong or doesn\'t exist': 'URL de envio está errada ou não existe',
+ 'Error: File too large: ': 'Erro: Arquivo muito grande: ',
+ 'Error: Invalid file extension: ': 'Erro: Tipo de arquivo não permitido: '
+});
diff --git a/debian/missing-sources/plupload/javascript/i18n/ro.js b/debian/missing-sources/plupload/javascript/i18n/ro.js
new file mode 100644
index 0000000..fd198f0
--- /dev/null
+++ b/debian/missing-sources/plupload/javascript/i18n/ro.js
@@ -0,0 +1,24 @@
+// Romanian
+plupload.addI18n({
+ 'Select files' : 'Selectare fiÅŸiere',
+ 'Add files to the upload queue and click the start button.' : 'Adaugă fişiere în lista apoi apasă butonul \'Începe încărcare\'.',
+ 'Filename' : 'Nume fiÅŸier',
+ 'Status' : 'Stare',
+ 'Size' : 'Mărime',
+ 'Add files' : 'Adăugare fişiere',
+ 'Stop current upload' : 'Întrerupe încărcarea curentă',
+ 'Start uploading queue' : 'Începe incărcarea',
+ 'Uploaded %d/%d files': 'Fişiere încărcate %d/%d',
+ 'N/A' : 'N/A',
+ 'Drag files here.' : 'Trage aici fiÅŸierele',
+ 'File extension error.': 'Extensie fişier eronată',
+ 'File size error.': 'Eroare dimensiune fiÅŸier',
+ 'Init error.': 'Eroare iniţializare',
+ 'HTTP Error.': 'Eroare HTTP',
+ 'Security error.': 'Eroare securitate',
+ 'Generic error.': 'Eroare generică',
+ 'IO error.': 'Eroare Intrare/IeÅŸire',
+ 'Stop Upload': 'Oprire încărcare',
+ 'Start upload': 'Începe încărcare',
+ '%d files queued': '%d fiÅŸiere listate'
+}); \ No newline at end of file
diff --git a/debian/missing-sources/plupload/javascript/i18n/ru.js b/debian/missing-sources/plupload/javascript/i18n/ru.js
new file mode 100644
index 0000000..86469c7
--- /dev/null
+++ b/debian/missing-sources/plupload/javascript/i18n/ru.js
@@ -0,0 +1,21 @@
+// Russian
+plupload.addI18n({
+ 'Select files' : 'Выберите файлы',
+ 'Add files to the upload queue and click the start button.' : 'Добавьте файлы в очередь и нажмите кнопку "Загрузить файлы".',
+ 'Filename' : 'Ð˜Ð¼Ñ Ñ„Ð°Ð¹Ð»Ð°',
+ 'Status' : 'СтатуÑ',
+ 'Size' : 'Размер',
+ 'Add files' : 'Добавить файлы',
+ 'Stop current upload' : 'ОÑтановить загрузку',
+ 'Start uploading queue' : 'Загрузить файлы',
+ 'Uploaded %d/%d files': 'Загружено %d/%d файлов',
+ 'N/A' : 'N/D',
+ 'Drag files here.' : 'Перетащите файлы Ñюда.',
+ 'File extension error.': 'Ðеправильное раÑширение файла.',
+ 'File size error.': 'Ðеправильный размер файла.',
+ 'Init error.': 'Ошибка инициализации.',
+ 'HTTP Error.': 'Ошибка HTTP.',
+ 'Security error.': 'Ошибка безопаÑноÑти.',
+ 'Generic error.': 'ÐžÐ±Ñ‰Ð°Ñ Ð¾ÑˆÐ¸Ð±ÐºÐ°.',
+ 'IO error.': 'Ошибка ввода-вывода.'
+}); \ No newline at end of file
diff --git a/debian/missing-sources/plupload/javascript/i18n/sk.js b/debian/missing-sources/plupload/javascript/i18n/sk.js
new file mode 100644
index 0000000..8b4b2d9
--- /dev/null
+++ b/debian/missing-sources/plupload/javascript/i18n/sk.js
@@ -0,0 +1,25 @@
+// .po file like language pack
+plupload.addI18n({
+ 'Select files' : 'Vyberte súbory',
+ 'Add files to the upload queue and click the start button.' : 'Pridajte súbory do zoznamu a potom spustite nahrávanie.',
+ 'Filename' : 'Názov súboru',
+ 'Status' : 'Stav',
+ 'Size' : 'Veľkosť',
+ 'Add files' : 'Pridať súbory',
+ 'Stop current upload' : 'Zastaviť nahrávanie',
+ 'Start uploading queue' : 'Spustiť nahrávanie zoznamu',
+ 'Drag files here.' : 'Sem pretiahnite súbory.',
+ 'Start upload': 'Spustiť nahrávanie',
+ 'Uploaded %d/%d files': 'Nahraných %d/%d súborov',
+ 'Using runtime: ': 'K odoslaniu súborov sa použije rozhranie: ',
+ 'N/A' : 'N/A',
+ 'File extension error.': 'Chybný typ súboru.',
+ 'File size error.': 'Súbor je príliš veľký.',
+ 'Init error.': 'Chyba inicializácie.',
+ 'HTTP Error.': 'HTTP Chyba.',
+ 'Security error.': 'BezpeÄnostná Chyba.',
+ 'Generic error.': 'Chyba.',
+ 'IO error.': 'IO Chyba',
+ 'Stop Upload': 'Zastaviť nahrávanie',
+ '%d files queued': '%d súborov pridaných do zoznamu'
+}); \ No newline at end of file
diff --git a/debian/missing-sources/plupload/javascript/i18n/sr.js b/debian/missing-sources/plupload/javascript/i18n/sr.js
new file mode 100644
index 0000000..59dc0a9
--- /dev/null
+++ b/debian/missing-sources/plupload/javascript/i18n/sr.js
@@ -0,0 +1,14 @@
+// Serbian
+plupload.addI18n({
+ 'Select files' : 'Izaberite fajlove',
+ 'Add files to the upload queue and click the start button.' : 'Dodajte fajlove u listu i kliknite na dugme Start.',
+ 'Filename' : 'Naziv fajla',
+ 'Status' : 'Status',
+ 'Size' : 'VeliÄina',
+ 'Add Files' : 'Dodaj fajlove',
+ 'Stop current upload' : 'Zaustavi upload',
+ 'Start uploading queue' : 'PoÄni upload',
+ 'Drag files here.' : 'Prevucite fajlove ovde.',
+ 'Start Upload': 'PoÄni upload',
+ 'Uploaded %d/%d files': 'Snimljeno %d/%d fajlova'
+}); \ No newline at end of file
diff --git a/debian/missing-sources/plupload/javascript/i18n/sv.js b/debian/missing-sources/plupload/javascript/i18n/sv.js
new file mode 100644
index 0000000..11c7524
--- /dev/null
+++ b/debian/missing-sources/plupload/javascript/i18n/sv.js
@@ -0,0 +1,12 @@
+// .po file like language pack
+plupload.addI18n({
+ 'Select files' : 'Välj filer',
+ 'Add files to the upload queue and click the start button.' : 'Lägg till filer till kön och tryck på start.',
+ 'Filename' : 'Filnamn',
+ 'Status' : 'Status',
+ 'Size' : 'Storlek',
+ 'Add files' : 'Lägg till filer',
+ 'Stop current upload' : 'Stoppa uppladdningen',
+ 'Start uploading queue' : 'Starta uppladdningen',
+ 'Drag files here.' : 'Dra filer hit'
+}); \ No newline at end of file
diff --git a/debian/missing-sources/plupload/javascript/jquery.plupload.queue/css/jquery.plupload.queue.css b/debian/missing-sources/plupload/javascript/jquery.plupload.queue/css/jquery.plupload.queue.css
new file mode 100644
index 0000000..8581fdd
--- /dev/null
+++ b/debian/missing-sources/plupload/javascript/jquery.plupload.queue/css/jquery.plupload.queue.css
@@ -0,0 +1,177 @@
+/*
+ Plupload
+------------------------------------------------------------------- */
+
+.plupload_button {
+ display: -moz-inline-box; /* FF < 3*/
+ display: inline-block;
+ font: normal 12px sans-serif;
+ text-decoration: none;
+ color: #42454a;
+ border: 1px solid #bababa;
+ padding: 2px 8px 3px 20px;
+ margin-right: 4px;
+ background: #f3f3f3 url('../img/buttons.png') no-repeat 0 center;
+ outline: 0;
+
+ /* Optional rounded corners for browsers that support it */
+ -moz-border-radius: 3px;
+ -khtml-border-radius: 3px;
+ -webkit-border-radius: 3px;
+ border-radius: 3px;
+}
+
+.plupload_button:hover {
+ color: #000;
+ text-decoration: none;
+}
+
+.plupload_disabled, a.plupload_disabled:hover {
+ color: #737373;
+ border-color: #c5c5c5;
+ background: #ededed url('../img/buttons-disabled.png') no-repeat 0 center;
+ cursor: default;
+}
+
+.plupload_add {
+ background-position: -181px center;
+}
+
+.plupload_wrapper {
+ font: normal 11px Verdana,sans-serif;
+ width: 100%;
+}
+
+.plupload_container {
+ padding: 8px;
+ background: url('../img/transp50.png');
+ /*-moz-border-radius: 5px;*/
+}
+
+.plupload_container input {
+ border: 1px solid #DDD;
+ font: normal 11px Verdana,sans-serif;
+ width: 98%;
+}
+
+.plupload_header {background: #2A2C2E url('../img/backgrounds.gif') repeat-x;}
+.plupload_header_content {
+ background: url('../img/backgrounds.gif') no-repeat 0 -317px;
+ min-height: 56px;
+ padding-left: 60px;
+ color: #FFF;
+}
+.plupload_header_title {
+ font: normal 18px sans-serif;
+ padding: 6px 0 3px;
+}
+.plupload_header_text {
+ font: normal 12px sans-serif;
+}
+
+.plupload_filelist {
+ margin: 0;
+ padding: 0;
+ list-style: none;
+}
+
+.plupload_scroll .plupload_filelist {
+ height: 185px;
+ background: #F5F5F5;
+ overflow-y: scroll;
+}
+
+.plupload_filelist li {
+ padding: 10px 8px;
+ background: #F5F5F5 url('../img/backgrounds.gif') repeat-x 0 -156px;
+ border-bottom: 1px solid #DDD;
+}
+
+.plupload_filelist_header, .plupload_filelist_footer {
+ background: #DFDFDF;
+ padding: 8px 8px;
+ color: #42454A;
+}
+.plupload_filelist_header {
+ border-top: 1px solid #EEE;
+ border-bottom: 1px solid #CDCDCD;
+}
+
+.plupload_filelist_footer {border-top: 1px solid #FFF; height: 22px; line-height: 20px; vertical-align: middle;}
+.plupload_file_name {float: left; overflow: hidden}
+.plupload_file_status {color: #777;}
+.plupload_file_status span {color: #42454A;}
+.plupload_file_size, .plupload_file_status, .plupload_progress {
+ float: right;
+ width: 80px;
+}
+.plupload_file_size, .plupload_file_status, .plupload_file_action {text-align: right;}
+
+.plupload_filelist .plupload_file_name {width: 205px}
+
+.plupload_file_action {
+ float: right;
+ width: 16px;
+ height: 16px;
+ margin-left: 15px;
+}
+
+.plupload_file_action * {
+ display: none;
+ width: 16px;
+ height: 16px;
+}
+
+li.plupload_uploading {background: #ECF3DC url('../img/backgrounds.gif') repeat-x 0 -238px;}
+li.plupload_done {color:#AAA}
+
+li.plupload_delete a {
+ background: url('../img/delete.gif');
+}
+
+li.plupload_failed a {
+ background: url('../img/error.gif');
+ cursor: default;
+}
+
+li.plupload_done a {
+ background: url('../img/done.gif');
+ cursor: default;
+}
+
+.plupload_progress, .plupload_upload_status {
+ display: none;
+}
+
+.plupload_progress_container {
+ margin-top: 3px;
+ border: 1px solid #CCC;
+ background: #FFF;
+ padding: 1px;
+}
+.plupload_progress_bar {
+ width: 0px;
+ height: 7px;
+ background: #CDEB8B;
+}
+
+.plupload_scroll .plupload_filelist_header .plupload_file_action, .plupload_scroll .plupload_filelist_footer .plupload_file_action {
+ margin-right: 17px;
+}
+
+/* Floats */
+
+.plupload_clear,.plupload_clearer {clear: both;}
+.plupload_clearer, .plupload_progress_bar {
+ display: block;
+ font-size: 0;
+ line-height: 0;
+}
+
+li.plupload_droptext {
+ background: transparent;
+ text-align: center;
+ vertical-align: middle;
+ border: 0;
+ line-height: 165px;
+}
diff --git a/debian/missing-sources/plupload/javascript/jquery.plupload.queue/img/backgrounds.gif b/debian/missing-sources/plupload/javascript/jquery.plupload.queue/img/backgrounds.gif
new file mode 100644
index 0000000..39e33eb
--- /dev/null
+++ b/debian/missing-sources/plupload/javascript/jquery.plupload.queue/img/backgrounds.gif
Binary files differ
diff --git a/debian/missing-sources/plupload/javascript/jquery.plupload.queue/img/buttons-disabled.png b/debian/missing-sources/plupload/javascript/jquery.plupload.queue/img/buttons-disabled.png
new file mode 100644
index 0000000..afa11af
--- /dev/null
+++ b/debian/missing-sources/plupload/javascript/jquery.plupload.queue/img/buttons-disabled.png
Binary files differ
diff --git a/debian/missing-sources/plupload/javascript/jquery.plupload.queue/img/buttons.png b/debian/missing-sources/plupload/javascript/jquery.plupload.queue/img/buttons.png
new file mode 100644
index 0000000..153e738
--- /dev/null
+++ b/debian/missing-sources/plupload/javascript/jquery.plupload.queue/img/buttons.png
Binary files differ
diff --git a/debian/missing-sources/plupload/javascript/jquery.plupload.queue/img/delete.gif b/debian/missing-sources/plupload/javascript/jquery.plupload.queue/img/delete.gif
new file mode 100644
index 0000000..78ca8b3
--- /dev/null
+++ b/debian/missing-sources/plupload/javascript/jquery.plupload.queue/img/delete.gif
Binary files differ
diff --git a/debian/missing-sources/plupload/javascript/jquery.plupload.queue/img/done.gif b/debian/missing-sources/plupload/javascript/jquery.plupload.queue/img/done.gif
new file mode 100644
index 0000000..29f3ed7
--- /dev/null
+++ b/debian/missing-sources/plupload/javascript/jquery.plupload.queue/img/done.gif
Binary files differ
diff --git a/debian/missing-sources/plupload/javascript/jquery.plupload.queue/img/error.gif b/debian/missing-sources/plupload/javascript/jquery.plupload.queue/img/error.gif
new file mode 100644
index 0000000..4682b63
--- /dev/null
+++ b/debian/missing-sources/plupload/javascript/jquery.plupload.queue/img/error.gif
Binary files differ
diff --git a/debian/missing-sources/plupload/javascript/jquery.plupload.queue/img/throbber.gif b/debian/missing-sources/plupload/javascript/jquery.plupload.queue/img/throbber.gif
new file mode 100644
index 0000000..4ae8b16
--- /dev/null
+++ b/debian/missing-sources/plupload/javascript/jquery.plupload.queue/img/throbber.gif
Binary files differ
diff --git a/debian/missing-sources/plupload/javascript/jquery.plupload.queue/img/transp50.png b/debian/missing-sources/plupload/javascript/jquery.plupload.queue/img/transp50.png
new file mode 100644
index 0000000..eb0efe1
--- /dev/null
+++ b/debian/missing-sources/plupload/javascript/jquery.plupload.queue/img/transp50.png
Binary files differ
diff --git a/debian/missing-sources/plupload/javascript/jquery.plupload.queue/jquery.plupload.queue.js b/debian/missing-sources/plupload/javascript/jquery.plupload.queue/jquery.plupload.queue.js
new file mode 100644
index 0000000..0de6a1c
--- /dev/null
+++ b/debian/missing-sources/plupload/javascript/jquery.plupload.queue/jquery.plupload.queue.js
@@ -0,0 +1,336 @@
+/**
+ * jquery.plupload.queue.js
+ *
+ * Copyright 2009, Moxiecode Systems AB
+ * Released under GPL License.
+ *
+ * License: http://www.plupload.com/license
+ * Contributing: http://www.plupload.com/contributing
+ */
+
+// JSLint defined globals
+/*global plupload:false, jQuery:false, alert:false */
+
+(function($) {
+ var uploaders = {};
+
+ function _(str) {
+ return plupload.translate(str) || str;
+ }
+
+ function renderUI(id, target) {
+ // Remove all existing non plupload items
+ target.contents().each(function(i, node) {
+ node = $(node);
+
+ if (!node.is('.plupload')) {
+ node.remove();
+ }
+ });
+
+ target.prepend(
+ '<div class="plupload_wrapper plupload_scroll">' +
+ '<div id="' + id + '_container" class="plupload_container">' +
+ '<div class="plupload">' +
+ '<div class="plupload_header">' +
+ '<div class="plupload_header_content">' +
+ '<div class="plupload_header_title">' + _('Select files') + '</div>' +
+ '<div class="plupload_header_text">' + _('Add files to the upload queue and click the start button.') + '</div>' +
+ '</div>' +
+ '</div>' +
+
+ '<div class="plupload_content">' +
+ '<div class="plupload_filelist_header">' +
+ '<div class="plupload_file_name">' + _('Filename') + '</div>' +
+ '<div class="plupload_file_action">&nbsp;</div>' +
+ '<div class="plupload_file_status"><span>' + _('Status') + '</span></div>' +
+ '<div class="plupload_file_size">' + _('Size') + '</div>' +
+ '<div class="plupload_clearer">&nbsp;</div>' +
+ '</div>' +
+
+ '<ul id="' + id + '_filelist" class="plupload_filelist"></ul>' +
+
+ '<div class="plupload_filelist_footer">' +
+ '<div class="plupload_file_name">' +
+ '<div class="plupload_buttons">' +
+ '<a href="#" class="plupload_button plupload_add">' + _('Add files') + '</a>' +
+ '<a href="#" class="plupload_button plupload_start">' + _('Start upload') + '</a>' +
+ '</div>' +
+ '<span class="plupload_upload_status"></span>' +
+ '</div>' +
+ '<div class="plupload_file_action"></div>' +
+ '<div class="plupload_file_status"><span class="plupload_total_status">0%</span></div>' +
+ '<div class="plupload_file_size"><span class="plupload_total_file_size">0 b</span></div>' +
+ '<div class="plupload_progress">' +
+ '<div class="plupload_progress_container">' +
+ '<div class="plupload_progress_bar"></div>' +
+ '</div>' +
+ '</div>' +
+ '<div class="plupload_clearer">&nbsp;</div>' +
+ '</div>' +
+ '</div>' +
+ '</div>' +
+ '</div>' +
+ '<input type="hidden" id="' + id + '_count" name="' + id + '_count" value="0" />' +
+ '</div>'
+ );
+ }
+
+ $.fn.pluploadQueue = function(settings) {
+ if (settings) {
+ this.each(function() {
+ var uploader, target, id;
+
+ target = $(this);
+ id = target.attr('id');
+
+ if (!id) {
+ id = plupload.guid();
+ target.attr('id', id);
+ }
+
+ uploader = new plupload.Uploader($.extend({
+ dragdrop : true,
+ container : id
+ }, settings));
+
+ uploaders[id] = uploader;
+
+ function handleStatus(file) {
+ var actionClass;
+
+ if (file.status == plupload.DONE) {
+ actionClass = 'plupload_done';
+ }
+
+ if (file.status == plupload.FAILED) {
+ actionClass = 'plupload_failed';
+ }
+
+ if (file.status == plupload.QUEUED) {
+ actionClass = 'plupload_delete';
+ }
+
+ if (file.status == plupload.UPLOADING) {
+ actionClass = 'plupload_uploading';
+ }
+
+ var icon = $('#' + file.id).attr('class', actionClass).find('a').css('display', 'block');
+ if (file.hint) {
+ icon.attr('title', file.hint);
+ }
+ }
+
+ function updateTotalProgress() {
+ $('span.plupload_total_status', target).html(uploader.total.percent + '%');
+ $('div.plupload_progress_bar', target).css('width', uploader.total.percent + '%');
+ $('span.plupload_upload_status', target).html(
+ _('Uploaded %d/%d files').replace(/%d\/%d/, uploader.total.uploaded+'/'+uploader.files.length)
+ );
+ }
+
+ function updateList() {
+ var fileList = $('ul.plupload_filelist', target).html(''), inputCount = 0, inputHTML;
+
+ $.each(uploader.files, function(i, file) {
+ inputHTML = '';
+
+ if (file.status == plupload.DONE) {
+ if (file.target_name) {
+ inputHTML += '<input type="hidden" name="' + id + '_' + inputCount + '_tmpname" value="' + plupload.xmlEncode(file.target_name) + '" />';
+ }
+
+ inputHTML += '<input type="hidden" name="' + id + '_' + inputCount + '_name" value="' + plupload.xmlEncode(file.name) + '" />';
+ inputHTML += '<input type="hidden" name="' + id + '_' + inputCount + '_status" value="' + (file.status == plupload.DONE ? 'done' : 'failed') + '" />';
+
+ inputCount++;
+
+ $('#' + id + '_count').val(inputCount);
+ }
+
+ fileList.append(
+ '<li id="' + file.id + '">' +
+ '<div class="plupload_file_name"><span>' + file.name + '</span></div>' +
+ '<div class="plupload_file_action"><a href="#"></a></div>' +
+ '<div class="plupload_file_status">' + file.percent + '%</div>' +
+ '<div class="plupload_file_size">' + plupload.formatSize(file.size) + '</div>' +
+ '<div class="plupload_clearer">&nbsp;</div>' +
+ inputHTML +
+ '</li>'
+ );
+
+ handleStatus(file);
+
+ $('#' + file.id + '.plupload_delete a').click(function(e) {
+ $('#' + file.id).remove();
+ uploader.removeFile(file);
+
+ e.preventDefault();
+ });
+ });
+
+ $('span.plupload_total_file_size', target).html(plupload.formatSize(uploader.total.size));
+
+ if (uploader.total.queued === 0) {
+ $('span.plupload_add_text', target).html(_('Add files.'));
+ } else {
+ $('span.plupload_add_text', target).html(uploader.total.queued + ' files queued.');
+ }
+
+ $('a.plupload_start', target).toggleClass('plupload_disabled', uploader.files.length == (uploader.total.uploaded + uploader.total.failed));
+
+ // Scroll to end of file list
+ fileList[0].scrollTop = fileList[0].scrollHeight;
+
+ updateTotalProgress();
+
+ // Re-add drag message if there is no files
+ if (!uploader.files.length && uploader.features.dragdrop && uploader.settings.dragdrop) {
+ $('#' + id + '_filelist').append('<li class="plupload_droptext">' + _("Drag files here.") + '</li>');
+ }
+ }
+
+ uploader.bind("UploadFile", function(up, file) {
+ $('#' + file.id).addClass('plupload_current_file');
+ });
+
+ uploader.bind('Init', function(up, res) {
+ renderUI(id, target);
+
+ // Enable rename support
+ if (!settings.unique_names && settings.rename) {
+ target.on('click', '#' + id + '_filelist div.plupload_file_name span', function(e) {
+ var targetSpan = $(e.target), file, parts, name, ext = "";
+
+ // Get file name and split out name and extension
+ file = up.getFile(targetSpan.parents('li')[0].id);
+ name = file.name;
+ parts = /^(.+)(\.[^.]+)$/.exec(name);
+ if (parts) {
+ name = parts[1];
+ ext = parts[2];
+ }
+
+ // Display input element
+ targetSpan.hide().after('<input type="text" />');
+ targetSpan.next().val(name).focus().blur(function() {
+ targetSpan.show().next().remove();
+ }).keydown(function(e) {
+ var targetInput = $(this);
+
+ if ($.inArray(e.keyCode, [13, 27]) !== -1) {
+ e.preventDefault();
+
+ // Rename file and glue extension back on
+ if (e.keyCode === 13) {
+ file.name = targetInput.val() + ext;
+ targetSpan.html(file.name);
+ }
+ targetInput.blur();
+ }
+ });
+ });
+ }
+
+ $('a.plupload_add', target).attr('id', id + '_browse');
+
+ up.settings.browse_button = id + '_browse';
+
+ // Enable drag/drop
+ if (up.features.dragdrop && up.settings.dragdrop) {
+ up.settings.drop_element = id + '_filelist';
+ $('#' + id + '_filelist').append('<li class="plupload_droptext">' + _("Drag files here.") + '</li>');
+ }
+
+ $('#' + id + '_container').attr('title', 'Using runtime: ' + res.runtime);
+
+ $('a.plupload_start', target).click(function(e) {
+ if (!$(this).hasClass('plupload_disabled')) {
+ uploader.start();
+ }
+
+ e.preventDefault();
+ });
+
+ $('a.plupload_stop', target).click(function(e) {
+ e.preventDefault();
+ uploader.stop();
+ });
+
+ $('a.plupload_start', target).addClass('plupload_disabled');
+ });
+
+ uploader.init();
+
+ uploader.bind("Error", function(up, err) {
+ var file = err.file, message;
+
+ if (file) {
+ message = err.message;
+
+ if (err.details) {
+ message += " (" + err.details + ")";
+ }
+
+ if (err.code == plupload.FILE_SIZE_ERROR) {
+ alert(_("Error: File too large: ") + file.name);
+ }
+
+ if (err.code == plupload.FILE_EXTENSION_ERROR) {
+ alert(_("Error: Invalid file extension: ") + file.name);
+ }
+
+ file.hint = message;
+ $('#' + file.id).attr('class', 'plupload_failed').find('a').css('display', 'block').attr('title', message);
+ }
+ });
+
+ uploader.bind('StateChanged', function() {
+ if (uploader.state === plupload.STARTED) {
+ $('li.plupload_delete a,div.plupload_buttons', target).hide();
+ $('span.plupload_upload_status,div.plupload_progress,a.plupload_stop', target).css('display', 'block');
+ $('span.plupload_upload_status', target).html('Uploaded ' + uploader.total.uploaded + '/' + uploader.files.length + ' files');
+
+ if (settings.multiple_queues) {
+ $('span.plupload_total_status,span.plupload_total_file_size', target).show();
+ }
+ } else {
+ updateList();
+ $('a.plupload_stop,div.plupload_progress', target).hide();
+ $('a.plupload_delete', target).css('display', 'block');
+ }
+ });
+
+ uploader.bind('QueueChanged', updateList);
+
+ uploader.bind('FileUploaded', function(up, file) {
+ handleStatus(file);
+ });
+
+ uploader.bind("UploadProgress", function(up, file) {
+ // Set file specific progress
+ $('#' + file.id + ' div.plupload_file_status', target).html(file.percent + '%');
+
+ handleStatus(file);
+ updateTotalProgress();
+
+ if (settings.multiple_queues && uploader.total.uploaded + uploader.total.failed == uploader.files.length) {
+ $(".plupload_buttons,.plupload_upload_status", target).css("display", "inline");
+ $(".plupload_start", target).addClass("plupload_disabled");
+ $('span.plupload_total_status,span.plupload_total_file_size', target).hide();
+ }
+ });
+
+ // Call setup function
+ if (settings.setup) {
+ settings.setup(uploader);
+ }
+ });
+
+ return this;
+ } else {
+ // Get uploader instance for specified element
+ return uploaders[$(this[0]).attr('id')];
+ }
+ };
+})(jQuery);
diff --git a/debian/missing-sources/plupload/javascript/jquery.ui.plupload/css/jquery.ui.plupload.css b/debian/missing-sources/plupload/javascript/jquery.ui.plupload/css/jquery.ui.plupload.css
new file mode 100644
index 0000000..a819fff
--- /dev/null
+++ b/debian/missing-sources/plupload/javascript/jquery.ui.plupload/css/jquery.ui.plupload.css
@@ -0,0 +1,147 @@
+/*
+ Plupload
+------------------------------------------------------------------- */
+
+.plupload_button {cursor: pointer;}
+
+.plupload_wrapper {
+ font: normal 11px Verdana,sans-serif;
+ width: 100%;
+}
+
+.plupload .plupload_container input {width: 98%;}
+.plupload .plupload_filelist_footer {border-width: 1px 0 0 0}
+.plupload .plupload_filelist_header {border-width: 0 0 1px 0}
+div.plupload .plupload_file {border-width: 0 0 1px 0}
+div.plupload div.plupload_header {border-width: 0 0 1px 0; position: relative;}
+
+.plupload_file .ui-icon {
+ cursor:pointer;
+}
+
+.plupload_header_content {
+ background-image: url('../img/plupload.png');
+ background-repeat: no-repeat;
+ background-position: 8px center;
+ min-height: 56px;
+ padding-left: 60px;
+ position:relative;
+}
+.plupload_header_content_bw {background-image: url('../img/plupload-bw.png');}
+.plupload_header_title {
+ font: normal 18px sans-serif;
+ padding: 6px 0 3px;
+}
+.plupload_header_text {font: normal 12px sans-serif;}
+
+.plupload_filelist,
+.plupload_filelist_content {
+ border-collapse: collapse;
+ margin: 0;
+ padding: 0;
+ width: 100%;
+ -moz-user-select:none;
+ -webkit-user-select:none;
+ user-select:none;
+}
+
+.plupload_cell {padding: 8px 6px;}
+
+.plupload_file {
+ border-left: none;
+ border-right: none;
+}
+
+.plupload .ui-sortable-helper,
+.plupload .ui-sortable .plupload_file {
+ cursor:move;
+}
+
+.plupload_scroll {
+ max-height: 180px;
+ min-height: 168px;
+ _height: 168px;
+ overflow-y: auto;
+}
+
+.plupload_file_size, .plupload_file_status {text-align: right;}
+.plupload_file_size, .plupload_file_status {width: 52px;}
+.plupload_file_action {width: 16px;}
+.plupload_file_name {
+ overflow: hidden;
+ padding-left: 10px;
+}
+
+.plupload_file_rename {
+ width:95%;
+}
+
+.plupload_progress {width: 60px;}
+.plupload_progress_container {padding: 1px;}
+
+
+/* Floats */
+
+.plupload_right {float: right;}
+.plupload_left {float: left;}
+.plupload_clear,.plupload_clearer {clear: both;}
+.plupload_clearer, .plupload_progress_bar {
+ display: block;
+ font-size: 0;
+ line-height: 0;
+}
+.plupload_clearer {height: 0;}
+
+/* Misc */
+.plupload_hidden {display: none;}
+.plupload_droptext {
+ background: transparent;
+ text-align: center;
+ vertical-align: middle;
+ border: 0;
+ line-height: 165px;
+}
+
+.plupload_buttons, .plupload_upload_status {float: left}
+
+.plupload_message {
+ position: absolute;
+ top: 0px;
+ left: 0px;
+ height: 100%;
+ width: 100%;
+}
+
+.plupload_message p {
+ padding:0.7em;
+ margin:0;
+}
+
+.plupload_message strong {
+ font-weight: bold;
+}
+
+plupload_message i {
+ font-style: italic;
+}
+
+.plupload_message p span.ui-icon {
+ float: left;
+ margin-right: 0.3em;
+}
+
+.plupload_header_content .ui-state-error,
+.plupload_header_content .ui-state-highlight {
+ border:none;
+}
+
+.plupload_message_close {
+ position:absolute;
+ top:5px;
+ right:5px;
+ cursor:pointer;
+}
+
+.plupload .ui-sortable-placeholder {
+ height:35px;
+}
diff --git a/debian/missing-sources/plupload/javascript/jquery.ui.plupload/img/plupload-bw.png b/debian/missing-sources/plupload/javascript/jquery.ui.plupload/img/plupload-bw.png
new file mode 100644
index 0000000..bb4147e
--- /dev/null
+++ b/debian/missing-sources/plupload/javascript/jquery.ui.plupload/img/plupload-bw.png
Binary files differ
diff --git a/debian/missing-sources/plupload/javascript/jquery.ui.plupload/img/plupload.png b/debian/missing-sources/plupload/javascript/jquery.ui.plupload/img/plupload.png
new file mode 100644
index 0000000..74fa3ad
--- /dev/null
+++ b/debian/missing-sources/plupload/javascript/jquery.ui.plupload/img/plupload.png
Binary files differ
diff --git a/debian/missing-sources/plupload/javascript/jquery.ui.plupload/jquery.ui.plupload.js b/debian/missing-sources/plupload/javascript/jquery.ui.plupload/jquery.ui.plupload.js
new file mode 100644
index 0000000..9efafd4
--- /dev/null
+++ b/debian/missing-sources/plupload/javascript/jquery.ui.plupload/jquery.ui.plupload.js
@@ -0,0 +1,754 @@
+/**
+ * jquery.ui.plupload.js
+ *
+ * Copyright 2009, Moxiecode Systems AB
+ * Released under GPL License.
+ *
+ * License: http://www.plupload.com/license
+ * Contributing: http://www.plupload.com/contributing
+ *
+ * Depends:
+ * jquery.ui.core.js
+ * jquery.ui.widget.js
+ *
+ * Optionally:
+ * jquery.ui.button.js
+ * jquery.ui.progressbar.js
+ * jquery.ui.sortable.js
+ */
+
+// JSLint defined globals
+/*global window:false, document:false, plupload:false, jQuery:false */
+
+(function(window, document, plupload, $, undef) {
+
+var uploaders = {};
+
+function _(str) {
+ return plupload.translate(str) || str;
+}
+
+function renderUI(obj) {
+ obj.html(
+ '<div class="plupload_wrapper">' +
+ '<div class="ui-widget-content plupload_container">' +
+ '<div class="plupload">' +
+ '<div class="ui-state-default ui-widget-header plupload_header">' +
+ '<div class="plupload_header_content">' +
+ '<div class="plupload_header_title">' + _('Select files') + '</div>' +
+ '<div class="plupload_header_text">' + _('Add files to the upload queue and click the start button.') + '</div>' +
+ '</div>' +
+ '</div>' +
+
+ '<div class="plupload_content">' +
+ '<table class="plupload_filelist">' +
+ '<tr class="ui-widget-header plupload_filelist_header">' +
+ '<td class="plupload_cell plupload_file_name">' + _('Filename') + '</td>' +
+ '<td class="plupload_cell plupload_file_status">' + _('Status') + '</td>' +
+ '<td class="plupload_cell plupload_file_size">' + _('Size') + '</td>' +
+ '<td class="plupload_cell plupload_file_action">&nbsp;</td>' +
+ '</tr>' +
+ '</table>' +
+
+ '<div class="plupload_scroll">' +
+ '<table class="plupload_filelist_content"></table>' +
+ '</div>' +
+
+ '<table class="plupload_filelist">' +
+ '<tr class="ui-widget-header ui-widget-content plupload_filelist_footer">' +
+ '<td class="plupload_cell plupload_file_name">' +
+
+ '<div class="plupload_buttons"><!-- Visible -->' +
+ '<a class="plupload_button plupload_add">' + _('Add Files') + '</a>&nbsp;' +
+ '<a class="plupload_button plupload_start">' + _('Start Upload') + '</a>&nbsp;' +
+ '<a class="plupload_button plupload_stop plupload_hidden">'+_('Stop Upload') + '</a>&nbsp;' +
+ '</div>' +
+
+ '<div class="plupload_started plupload_hidden"><!-- Hidden -->' +
+
+ '<div class="plupload_progress plupload_right">' +
+ '<div class="plupload_progress_container"></div>' +
+ '</div>' +
+
+ '<div class="plupload_cell plupload_upload_status"></div>' +
+
+ '<div class="plupload_clearer">&nbsp;</div>' +
+
+ '</div>' +
+ '</td>' +
+ '<td class="plupload_file_status"><span class="plupload_total_status">0%</span></td>' +
+ '<td class="plupload_file_size"><span class="plupload_total_file_size">0 kb</span></td>' +
+ '<td class="plupload_file_action"></td>' +
+ '</tr>' +
+ '</table>' +
+ '</div>' +
+ '</div>' +
+ '</div>' +
+ '<input class="plupload_count" value="0" type="hidden">' +
+ '</div>'
+ );
+}
+
+
+$.widget("ui.plupload", {
+
+ contents_bak: '',
+
+ runtime: null,
+
+ options: {
+ browse_button_hover: 'ui-state-hover',
+ browse_button_active: 'ui-state-active',
+
+ // widget specific
+ dragdrop : true,
+ multiple_queues: true, // re-use widget by default
+
+ buttons: {
+ browse: true,
+ start: true,
+ stop: true
+ },
+ autostart: false,
+ sortable: false,
+ rename: false,
+ max_file_count: 0 // unlimited
+ },
+
+ FILE_COUNT_ERROR: -9001,
+
+ _create: function() {
+ var self = this, id, uploader;
+
+ id = this.element.attr('id');
+ if (!id) {
+ id = plupload.guid();
+ this.element.attr('id', id);
+ }
+ this.id = id;
+
+ // backup the elements initial state
+ this.contents_bak = this.element.html();
+ renderUI(this.element);
+
+ // container, just in case
+ this.container = $('.plupload_container', this.element).attr('id', id + '_container');
+
+ // list of files, may become sortable
+ this.filelist = $('.plupload_filelist_content', this.container)
+ .attr({
+ id: id + '_filelist',
+ unselectable: 'on'
+ });
+
+ // buttons
+ this.browse_button = $('.plupload_add', this.container).attr('id', id + '_browse');
+ this.start_button = $('.plupload_start', this.container).attr('id', id + '_start');
+ this.stop_button = $('.plupload_stop', this.container).attr('id', id + '_stop');
+
+ if ($.ui.button) {
+ this.browse_button.button({
+ icons: { primary: 'ui-icon-circle-plus' }
+ });
+
+ this.start_button.button({
+ icons: { primary: 'ui-icon-circle-arrow-e' },
+ disabled: true
+ });
+
+ this.stop_button.button({
+ icons: { primary: 'ui-icon-circle-close' }
+ });
+ }
+
+ // progressbar
+ this.progressbar = $('.plupload_progress_container', this.container);
+
+ if ($.ui.progressbar) {
+ this.progressbar.progressbar();
+ }
+
+ // counter
+ this.counter = $('.plupload_count', this.element)
+ .attr({
+ id: id + '_count',
+ name: id + '_count'
+ });
+
+ // initialize uploader instance
+ uploader = this.uploader = uploaders[id] = new plupload.Uploader($.extend({
+ container: id ,
+ browse_button: id + '_browse'
+ }, this.options));
+
+ // do not show UI if no runtime can be initialized
+ uploader.bind('Error', function(up, err) {
+ if (err.code === plupload.INIT_ERROR) {
+ self.destroy();
+ }
+ });
+
+ uploader.bind('Init', function(up, res) {
+ // all buttons are optional, so they can be disabled and hidden
+ if (!self.options.buttons.browse) {
+ self.browse_button.button('disable').hide();
+ up.disableBrowse(true);
+ }
+
+ if (!self.options.buttons.start) {
+ self.start_button.button('disable').hide();
+ }
+
+ if (!self.options.buttons.stop) {
+ self.stop_button.button('disable').hide();
+ }
+
+ if (!self.options.unique_names && self.options.rename) {
+ self._enableRenaming();
+ }
+
+ if (uploader.features.dragdrop && self.options.dragdrop) {
+ self._enableDragAndDrop();
+ }
+
+ self.container.attr('title', _('Using runtime: ') + (self.runtime = res.runtime));
+
+ self.start_button.click(function(e) {
+ if (!$(this).button('option', 'disabled')) {
+ self.start();
+ }
+ e.preventDefault();
+ });
+
+ self.stop_button.click(function(e) {
+ self.stop();
+ e.preventDefault();
+ });
+ });
+
+
+ // check if file count doesn't exceed the limit
+ if (self.options.max_file_count) {
+ uploader.bind('FilesAdded', function(up, selectedFiles) {
+ var removed = [], selectedCount = selectedFiles.length;
+ var extraCount = up.files.length + selectedCount - self.options.max_file_count;
+
+ if (extraCount > 0) {
+ removed = selectedFiles.splice(selectedCount - extraCount, extraCount);
+
+ up.trigger('Error', {
+ code : self.FILE_COUNT_ERROR,
+ message : _('File count error.'),
+ file : removed
+ });
+ }
+ });
+ }
+
+ // uploader internal events must run first
+ uploader.init();
+
+ uploader.bind('FilesAdded', function(up, files) {
+ self._trigger('selected', null, { up: up, files: files } );
+
+ if (self.options.autostart) {
+ // set a little delay to make sure that QueueChanged triggered by the core has time to complete
+ setTimeout(function() {
+ self.start();
+ }, 10);
+ }
+ });
+
+ uploader.bind('FilesRemoved', function(up, files) {
+ self._trigger('removed', null, { up: up, files: files } );
+ });
+
+ uploader.bind('QueueChanged', function() {
+ self._updateFileList();
+ });
+
+ uploader.bind('StateChanged', function() {
+ self._handleState();
+ });
+
+ uploader.bind('UploadFile', function(up, file) {
+ self._handleFileStatus(file);
+ });
+
+ uploader.bind('FileUploaded', function(up, file) {
+ self._handleFileStatus(file);
+
+ self._trigger('uploaded', null, { up: up, file: file } );
+ });
+
+ uploader.bind('UploadProgress', function(up, file) {
+ // Set file specific progress
+ $('#' + file.id)
+ .find('.plupload_file_status')
+ .html(file.percent + '%')
+ .end()
+ .find('.plupload_file_size')
+ .html(plupload.formatSize(file.size));
+
+ self._handleFileStatus(file);
+ self._updateTotalProgress();
+
+ self._trigger('progress', null, { up: up, file: file } );
+ });
+
+ uploader.bind('UploadComplete', function(up, files) {
+ self._trigger('complete', null, { up: up, files: files } );
+ });
+
+ uploader.bind('Error', function(up, err) {
+ var file = err.file, message, details;
+
+ if (file) {
+ message = '<strong>' + err.message + '</strong>';
+ details = err.details;
+
+ if (details) {
+ message += " <br /><i>" + err.details + "</i>";
+ } else {
+
+ switch (err.code) {
+ case plupload.FILE_EXTENSION_ERROR:
+ details = _("File: %s").replace('%s', file.name);
+ break;
+
+ case plupload.FILE_SIZE_ERROR:
+ details = _("File: %f, size: %s, max file size: %m").replace(/%([fsm])/g, function($0, $1) {
+ switch ($1) {
+ case 'f': return file.name;
+ case 's': return file.size;
+ case 'm': return plupload.parseSize(self.options.max_file_size);
+ }
+ });
+ break;
+
+ case self.FILE_COUNT_ERROR:
+ details = _("Upload element accepts only %d file(s) at a time. Extra files were stripped.")
+ .replace('%d', self.options.max_file_count);
+ break;
+
+ case plupload.IMAGE_FORMAT_ERROR :
+ details = plupload.translate('Image format either wrong or not supported.');
+ break;
+
+ case plupload.IMAGE_MEMORY_ERROR :
+ details = plupload.translate('Runtime ran out of available memory.');
+ break;
+
+ case plupload.IMAGE_DIMENSIONS_ERROR :
+ details = plupload.translate('Resoultion out of boundaries! <b>%s</b> runtime supports images only up to %wx%hpx.').replace(/%([swh])/g, function($0, $1) {
+ switch ($1) {
+ case 's': return up.runtime;
+ case 'w': return up.features.maxWidth;
+ case 'h': return up.features.maxHeight;
+ }
+ });
+ break;
+
+ case plupload.HTTP_ERROR:
+ details = _("Upload URL might be wrong or doesn't exist");
+ break;
+ }
+ message += " <br /><i>" + details + "</i>";
+ }
+
+ self.notify('error', message);
+ self._trigger('error', null, { up: up, file: file, error: message } );
+ }
+ });
+ },
+
+ _setOption: function(key, value) {
+ var self = this;
+
+ if (key == 'buttons' && typeof(value) == 'object') {
+ value = $.extend(self.options.buttons, value);
+
+ if (!value.browse) {
+ self.browse_button.button('disable').hide();
+ up.disableBrowse(true);
+ } else {
+ self.browse_button.button('enable').show();
+ up.disableBrowse(false);
+ }
+
+ if (!value.start) {
+ self.start_button.button('disable').hide();
+ } else {
+ self.start_button.button('enable').show();
+ }
+
+ if (!value.stop) {
+ self.stop_button.button('disable').hide();
+ } else {
+ self.start_button.button('enable').show();
+ }
+ }
+
+ self.uploader.settings[key] = value;
+ },
+
+
+ start: function() {
+ this.uploader.start();
+ this._trigger('start', null);
+ },
+
+ stop: function() {
+ this.uploader.stop();
+ this._trigger('stop', null);
+ },
+
+ getFile: function(id) {
+ var file;
+
+ if (typeof id === 'number') {
+ file = this.uploader.files[id];
+ } else {
+ file = this.uploader.getFile(id);
+ }
+ return file;
+ },
+
+ removeFile: function(id) {
+ var file = this.getFile(id);
+ if (file) {
+ this.uploader.removeFile(file);
+ }
+ },
+
+ clearQueue: function() {
+ this.uploader.splice();
+ },
+
+ getUploader: function() {
+ return this.uploader;
+ },
+
+ refresh: function() {
+ this.uploader.refresh();
+ },
+
+
+ _handleState: function() {
+ var self = this, up = this.uploader;
+
+ if (up.state === plupload.STARTED) {
+
+ $(self.start_button).button('disable');
+
+ $([])
+ .add(self.stop_button)
+ .add('.plupload_started')
+ .removeClass('plupload_hidden');
+
+ $('.plupload_upload_status', self.element).html(
+ _('Uploaded %d/%d files').replace('%d/%d', up.total.uploaded+'/'+up.files.length)
+ );
+
+ $('.plupload_header_content', self.element).addClass('plupload_header_content_bw');
+
+ } else {
+
+ $([])
+ .add(self.stop_button)
+ .add('.plupload_started')
+ .addClass('plupload_hidden');
+
+ if (self.options.multiple_queues) {
+ $(self.start_button).button('enable');
+
+ $('.plupload_header_content', self.element).removeClass('plupload_header_content_bw');
+ }
+
+ self._updateFileList();
+ }
+ },
+
+
+ _handleFileStatus: function(file) {
+ var actionClass, iconClass;
+
+ // since this method might be called asynchronously, file row might not yet be rendered
+ if (!$('#' + file.id).length) {
+ return;
+ }
+
+ switch (file.status) {
+ case plupload.DONE:
+ actionClass = 'plupload_done';
+ iconClass = 'ui-icon ui-icon-circle-check';
+ break;
+
+ case plupload.FAILED:
+ actionClass = 'ui-state-error plupload_failed';
+ iconClass = 'ui-icon ui-icon-alert';
+ break;
+
+ case plupload.QUEUED:
+ actionClass = 'plupload_delete';
+ iconClass = 'ui-icon ui-icon-circle-minus';
+ break;
+
+ case plupload.UPLOADING:
+ actionClass = 'ui-state-highlight plupload_uploading';
+ iconClass = 'ui-icon ui-icon-circle-arrow-w';
+
+ // scroll uploading file into the view if its bottom boundary is out of it
+ var scroller = $('.plupload_scroll', this.container),
+ scrollTop = scroller.scrollTop(),
+ scrollerHeight = scroller.height(),
+ rowOffset = $('#' + file.id).position().top + $('#' + file.id).height();
+
+ if (scrollerHeight < rowOffset) {
+ scroller.scrollTop(scrollTop + rowOffset - scrollerHeight);
+ }
+ break;
+ }
+ actionClass += ' ui-state-default plupload_file';
+
+ $('#' + file.id)
+ .attr('class', actionClass)
+ .find('.ui-icon')
+ .attr('class', iconClass);
+ },
+
+
+ _updateTotalProgress: function() {
+ var up = this.uploader;
+
+ this.progressbar.progressbar('value', up.total.percent);
+
+ this.element
+ .find('.plupload_total_status')
+ .html(up.total.percent + '%')
+ .end()
+ .find('.plupload_total_file_size')
+ .html(plupload.formatSize(up.total.size))
+ .end()
+ .find('.plupload_upload_status')
+ .html(_('Uploaded %d/%d files').replace('%d/%d', up.total.uploaded+'/'+up.files.length));
+ },
+
+
+ _updateFileList: function() {
+ var self = this, up = this.uploader, filelist = this.filelist,
+ count = 0,
+ id, prefix = this.id + '_',
+ fields;
+
+ // destroy sortable if enabled
+ if ($.ui.sortable && this.options.sortable) {
+ $('tbody.ui-sortable', filelist).sortable('destroy');
+ }
+
+ filelist.empty();
+
+ $.each(up.files, function(i, file) {
+ fields = '';
+ id = prefix + count;
+
+ if (file.status === plupload.DONE) {
+ if (file.target_name) {
+ fields += '<input type="hidden" name="' + id + '_tmpname" value="'+plupload.xmlEncode(file.target_name)+'" />';
+ }
+ fields += '<input type="hidden" name="' + id + '_name" value="'+plupload.xmlEncode(file.name)+'" />';
+ fields += '<input type="hidden" name="' + id + '_status" value="' + (file.status === plupload.DONE ? 'done' : 'failed') + '" />';
+
+ count++;
+ self.counter.val(count);
+ }
+
+ filelist.append(
+ '<tr class="ui-state-default plupload_file" id="' + file.id + '">' +
+ '<td class="plupload_cell plupload_file_name"><span>' + file.name + '</span></td>' +
+ '<td class="plupload_cell plupload_file_status">' + file.percent + '%</td>' +
+ '<td class="plupload_cell plupload_file_size">' + plupload.formatSize(file.size) + '</td>' +
+ '<td class="plupload_cell plupload_file_action"><div class="ui-icon"></div>' + fields + '</td>' +
+ '</tr>'
+ );
+
+ self._handleFileStatus(file);
+
+ $('#' + file.id + '.plupload_delete .ui-icon, #' + file.id + '.plupload_done .ui-icon')
+ .click(function(e) {
+ $('#' + file.id).remove();
+ up.removeFile(file);
+
+ e.preventDefault();
+ });
+
+ self._trigger('updatelist', null, filelist);
+ });
+
+ if (up.total.queued === 0) {
+ $('.ui-button-text', self.browse_button).html(_('Add Files'));
+ } else {
+ $('.ui-button-text', self.browse_button).html(_('%d files queued').replace('%d', up.total.queued));
+ }
+
+
+ if (up.files.length === (up.total.uploaded + up.total.failed)) {
+ self.start_button.button('disable');
+ } else {
+ self.start_button.button('enable');
+ }
+
+
+ // Scroll to end of file list
+ filelist[0].scrollTop = filelist[0].scrollHeight;
+
+ self._updateTotalProgress();
+
+ if (!up.files.length && up.features.dragdrop && up.settings.dragdrop) {
+ // Re-add drag message if there are no files
+ $('#' + id + '_filelist').append('<tr><td class="plupload_droptext">' + _("Drag files here.") + '</td></tr>');
+ } else {
+ // Otherwise re-initialize sortable
+ if (self.options.sortable && $.ui.sortable) {
+ self._enableSortingList();
+ }
+ }
+ },
+
+
+ _enableRenaming: function() {
+ var self = this;
+
+ this.filelist.on('click', '.plupload_delete .plupload_file_name span', function(e) {
+ var targetSpan = $(e.target), file, parts, name, ext = "";
+
+ // Get file name and split out name and extension
+ file = self.uploader.getFile(targetSpan.parents('tr')[0].id);
+ name = file.name;
+ parts = /^(.+)(\.[^.]+)$/.exec(name);
+ if (parts) {
+ name = parts[1];
+ ext = parts[2];
+ }
+
+ // Display input element
+ targetSpan.hide().after('<input class="plupload_file_rename" type="text" />');
+ targetSpan.next().val(name).focus().blur(function() {
+ targetSpan.show().next().remove();
+ }).keydown(function(e) {
+ var targetInput = $(this);
+
+ if ($.inArray(e.keyCode, [13, 27]) !== -1) {
+ e.preventDefault();
+
+ // Rename file and glue extension back on
+ if (e.keyCode === 13) {
+ file.name = targetInput.val() + ext;
+ targetSpan.html(file.name);
+ }
+ targetInput.blur();
+ }
+ });
+ });
+ },
+
+
+ _enableDragAndDrop: function() {
+ this.filelist.append('<tr><td class="plupload_droptext">' + _("Drag files here.") + '</td></tr>');
+
+ this.filelist.parent().attr('id', this.id + '_dropbox');
+
+ this.uploader.settings.drop_element = this.options.drop_element = this.id + '_dropbox';
+ },
+
+
+ _enableSortingList: function() {
+ var idxStart, self = this;
+
+ if ($('tbody tr', this.filelist).length < 2) {
+ return;
+ }
+
+ $('tbody', this.filelist).sortable({
+ containment: 'parent',
+ items: '.plupload_delete',
+
+ helper: function(e, el) {
+ return el.clone(true).find('td:not(.plupload_file_name)').remove().end().css('width', '100%');
+ },
+
+ stop: function(e, ui) {
+ var i, length, idx, files = [];
+
+ $.each($(this).sortable('toArray'), function(i, id) {
+ files[files.length] = self.uploader.getFile(id);
+ });
+
+ files.unshift(files.length);
+ files.unshift(0);
+
+ // re-populate files array
+ Array.prototype.splice.apply(self.uploader.files, files);
+ }
+ });
+ },
+
+ notify: function(type, message) {
+ var popup = $(
+ '<div class="plupload_message">' +
+ '<span class="plupload_message_close ui-icon ui-icon-circle-close" title="'+_('Close')+'"></span>' +
+ '<p><span class="ui-icon"></span>' + message + '</p>' +
+ '</div>'
+ );
+
+ popup
+ .addClass('ui-state-' + (type === 'error' ? 'error' : 'highlight'))
+ .find('p .ui-icon')
+ .addClass('ui-icon-' + (type === 'error' ? 'alert' : 'info'))
+ .end()
+ .find('.plupload_message_close')
+ .click(function() {
+ popup.remove();
+ })
+ .end();
+
+ $('.plupload_header_content', this.container).append(popup);
+ },
+
+
+
+ destroy: function() {
+ // unbind all button events
+ $('.plupload_button', this.element).unbind();
+
+ // destroy buttons
+ if ($.ui.button) {
+ $('.plupload_add, .plupload_start, .plupload_stop', this.container)
+ .button('destroy');
+ }
+
+ // destroy progressbar
+ if ($.ui.progressbar) {
+ this.progressbar.progressbar('destroy');
+ }
+
+ // destroy sortable behavior
+ if ($.ui.sortable && this.options.sortable) {
+ $('tbody', this.filelist).sortable('destroy');
+ }
+
+ // destroy uploader instance
+ this.uploader.destroy();
+
+ // restore the elements initial state
+ this.element
+ .empty()
+ .html(this.contents_bak);
+ this.contents_bak = '';
+
+ $.Widget.prototype.destroy.apply(this);
+ }
+});
+
+
+} (window, document, plupload, jQuery));
diff --git a/debian/missing-sources/plupload/javascript/plupload.browserplus.js b/debian/missing-sources/plupload/javascript/plupload.browserplus.js
new file mode 100644
index 0000000..1a06b79
--- /dev/null
+++ b/debian/missing-sources/plupload/javascript/plupload.browserplus.js
@@ -0,0 +1,361 @@
+/**
+ * plupload.browserplus.js
+ *
+ * Copyright 2009, Moxiecode Systems AB
+ * Released under GPL License.
+ *
+ * License: http://www.plupload.com/license
+ * Contributing: http://www.plupload.com/contributing
+ */
+
+// JSLint defined globals
+/*global plupload:false, BrowserPlus:false, window:false */
+
+(function(plupload) {
+ /**
+ * Yahoo BrowserPlus implementation. This runtime supports these features: dragdrop, jpgresize, pngresize.
+ *
+ * @static
+ * @class plupload.runtimes.BrowserPlus
+ * @extends plupload.Runtime
+ */
+ plupload.runtimes.BrowserPlus = plupload.addRuntime("browserplus", {
+ /**
+ * Returns a list of supported features for the runtime.
+ *
+ * @return {Object} Name/value object with supported features.
+ */
+ getFeatures : function() {
+ return {
+ dragdrop : true,
+ jpgresize : true,
+ pngresize : true,
+ chunks : true,
+ progress: true,
+ multipart: true,
+ multi_selection: true
+ };
+ },
+
+ /**
+ * Initializes the browserplus runtime.
+ *
+ * @method init
+ * @param {plupload.Uploader} uploader Uploader instance that needs to be initialized.
+ * @param {function} callback Callback to execute when the runtime initializes or fails to initialize. If it succeeds an object with a parameter name success will be set to true.
+ */
+ init : function(uploader, callback) {
+ var browserPlus = window.BrowserPlus, browserPlusFiles = {}, settings = uploader.settings, resize = settings.resize;
+
+ function addSelectedFiles(native_files) {
+ var files, i, selectedFiles = [], file, id;
+
+ // Add the native files and setup plupload files
+ for (i = 0; i < native_files.length; i++) {
+ file = native_files[i];
+ id = plupload.guid();
+ browserPlusFiles[id] = file;
+
+ selectedFiles.push(new plupload.File(id, file.name, file.size));
+ }
+
+ // Any files selected fire event
+ if (i) {
+ uploader.trigger("FilesAdded", selectedFiles);
+ }
+ }
+
+ // Setup event listeners if browserplus was initialized
+ function setup() {
+ var disabled = false;
+
+ // Add drop handler
+ uploader.bind("PostInit", function() {
+ var dropTargetElm, dropElmId = settings.drop_element,
+ dropTargetId = uploader.id + '_droptarget',
+ dropElm = document.getElementById(dropElmId),
+ lastState;
+
+ // Enable/disable drop support for the drop target
+ // this is needed to resolve IE bubbeling issues and make it possible to drag/drop
+ // files into gears runtimes on the same page
+ function addDropHandler(id, end_callback) {
+ // Add drop target and listener
+ browserPlus.DragAndDrop.AddDropTarget({id : id}, function(res) {
+ browserPlus.DragAndDrop.AttachCallbacks({
+ id : id,
+ hover : function(res) {
+ if (!res && end_callback) {
+ end_callback();
+ }
+ },
+ drop : function(res) {
+ if (end_callback) {
+ end_callback();
+ }
+
+ addSelectedFiles(res);
+ }
+ }, function() {
+ });
+ });
+ }
+
+ function hide() {
+ document.getElementById(dropTargetId).style.top = '-1000px';
+ }
+
+ if (dropElm) {
+ // Since IE has issues with bubbeling when it comes to the drop of files
+ // we need to do this hack where we show a drop target div element while dropping
+ if (document.attachEvent && (/MSIE/gi).test(navigator.userAgent)) {
+ // Create drop target
+ dropTargetElm = document.createElement('div');
+ dropTargetElm.setAttribute('id', dropTargetId);
+ plupload.extend(dropTargetElm.style, {
+ position : 'absolute',
+ top : '-1000px',
+ background : 'red',
+ filter : 'alpha(opacity=0)',
+ opacity : 0
+ });
+
+ document.body.appendChild(dropTargetElm);
+
+ plupload.addEvent(dropElm, 'dragenter', function(e) {
+ var dropElm, dropElmPos;
+
+ dropElm = document.getElementById(dropElmId);
+ dropElmPos = plupload.getPos(dropElm);
+
+ plupload.extend(document.getElementById(dropTargetId).style, {
+ top : dropElmPos.y + 'px',
+ left : dropElmPos.x + 'px',
+ width : dropElm.offsetWidth + 'px',
+ height : dropElm.offsetHeight + 'px'
+ });
+ });
+
+ addDropHandler(dropTargetId, hide);
+ } else {
+ addDropHandler(dropElmId);
+ }
+ }
+
+ plupload.addEvent(document.getElementById(settings.browse_button), 'click', function(e) {
+ var mimes = [], i, a, filters = settings.filters, ext, type;
+
+ e.preventDefault();
+
+ if (disabled) {
+ return;
+ }
+
+ // Convert extensions to mimetypes
+ no_type_restriction:
+ for (i = 0; i < filters.length; i++) {
+ ext = filters[i].extensions.split(',');
+
+ for (a = 0; a < ext.length; a++) {
+ if (ext[a] === '*') {
+ mimes = [];
+ break no_type_restriction;
+ }
+ type = plupload.mimeTypes[ext[a]];
+
+ if (type && plupload.inArray(type, mimes) === -1) {
+ mimes.push(plupload.mimeTypes[ext[a]]);
+ }
+ }
+ }
+
+ browserPlus.FileBrowse.OpenBrowseDialog({
+ mimeTypes : mimes
+ }, function(res) {
+ if (res.success) {
+ addSelectedFiles(res.value);
+ }
+ });
+ });
+
+ // Prevent IE leaks
+ dropElm = dropTargetElm = null;
+ });
+
+ uploader.bind("CancelUpload", function() {
+ browserPlus.Uploader.cancel({}, function(){});
+ });
+
+ uploader.bind("DisableBrowse", function(up, state) {
+ disabled = state;
+ });
+
+ uploader.bind("UploadFile", function(up, file) {
+ var nativeFile = browserPlusFiles[file.id], reqParams = {},
+ chunkSize = up.settings.chunk_size, loadProgress, chunkStack = [];
+
+ function uploadFile(chunk, chunks) {
+ var chunkFile;
+
+ // Stop upload if file is maked as failed
+ if (file.status == plupload.FAILED) {
+ return;
+ }
+
+ reqParams.name = file.target_name || file.name;
+
+ // Only send chunk parameters if chunk size is defined
+ if (chunkSize) {
+ reqParams.chunk = "" + chunk;
+ reqParams.chunks = "" + chunks;
+ }
+
+ chunkFile = chunkStack.shift();
+
+ browserPlus.Uploader.upload({
+ url : up.settings.url,
+ files : {file : chunkFile},
+ cookies : document.cookies,
+ postvars : plupload.extend(reqParams, up.settings.multipart_params),
+ progressCallback : function(res) {
+ var i, loaded = 0;
+
+ // since more than 1 chunk can be sent at a time, keep track of how many bytes
+ // of each chunk was sent
+ loadProgress[chunk] = parseInt(res.filePercent * chunkFile.size / 100, 10);
+ for (i = 0; i < loadProgress.length; i++) {
+ loaded += loadProgress[i];
+ }
+
+ file.loaded = loaded;
+ up.trigger('UploadProgress', file);
+ }
+ }, function(res) {
+ var httpStatus, chunkArgs;
+
+ if (res.success) {
+ httpStatus = res.value.statusCode;
+
+ if (chunkSize) {
+ up.trigger('ChunkUploaded', file, {
+ chunk : chunk,
+ chunks : chunks,
+ response : res.value.body,
+ status : httpStatus
+ });
+ }
+
+ if (chunkStack.length > 0) {
+ // More chunks to be uploaded
+ uploadFile(++chunk, chunks);
+ } else {
+ file.status = plupload.DONE;
+
+ up.trigger('FileUploaded', file, {
+ response : res.value.body,
+ status : httpStatus
+ });
+
+ // Is error status
+ if (httpStatus >= 400) {
+ up.trigger('Error', {
+ code : plupload.HTTP_ERROR,
+ message : plupload.translate('HTTP Error.'),
+ file : file,
+ status : httpStatus
+ });
+ }
+ }
+ } else {
+ up.trigger('Error', {
+ code : plupload.GENERIC_ERROR,
+ message : plupload.translate('Generic Error.'),
+ file : file,
+ details : res.error
+ });
+ }
+ });
+ }
+
+ function chunkAndUploadFile(native_file) {
+ file.size = native_file.size;
+ if (chunkSize) {
+ browserPlus.FileAccess.chunk({file : native_file, chunkSize : chunkSize}, function(cr) {
+ if (cr.success) {
+ var chunks = cr.value, len = chunks.length;
+
+ loadProgress = Array(len);
+
+ for (var i = 0; i < len; i++) {
+ loadProgress[i] = 0;
+ chunkStack.push(chunks[i]);
+ }
+
+ uploadFile(0, len);
+ }
+ });
+ } else {
+ loadProgress = Array(1);
+ chunkStack.push(native_file);
+ uploadFile(0, 1);
+ }
+ }
+
+ // Resize image if it's a supported format and resize is enabled
+ if (resize && /\.(png|jpg|jpeg)$/i.test(file.name)) {
+ BrowserPlus.ImageAlter.transform({
+ file : nativeFile,
+ quality : resize.quality || 90,
+ actions : [{
+ scale : {
+ maxwidth : resize.width,
+ maxheight : resize.height
+ }
+ }]
+ }, function(res) {
+ if (res.success) {
+ chunkAndUploadFile(res.value.file);
+ }
+ });
+ } else {
+ chunkAndUploadFile(nativeFile);
+ }
+ });
+
+ callback({success : true});
+ }
+
+ // Check for browserplus object
+ if (browserPlus) {
+ browserPlus.init(function(res) {
+ var services = [
+ {service: "Uploader", version: "3"},
+ {service: "DragAndDrop", version: "1"},
+ {service: "FileBrowse", version: "1"},
+ {service: "FileAccess", version: "2"}
+ ];
+
+ if (resize) {
+ services.push({service : 'ImageAlter', version : "4"});
+ }
+
+ if (res.success) {
+ browserPlus.require({
+ services : services
+ }, function(sres) {
+ if (sres.success) {
+ setup();
+ } else {
+ callback();
+ }
+ });
+ } else {
+ callback();
+ }
+ });
+ } else {
+ callback();
+ }
+ }
+ });
+})(plupload);
diff --git a/debian/missing-sources/plupload/javascript/plupload.flash.js b/debian/missing-sources/plupload/javascript/plupload.flash.js
new file mode 100644
index 0000000..7caa511
--- /dev/null
+++ b/debian/missing-sources/plupload/javascript/plupload.flash.js
@@ -0,0 +1,431 @@
+/**
+ * plupload.flash.js
+ *
+ * Copyright 2009, Moxiecode Systems AB
+ * Released under GPL License.
+ *
+ * License: http://www.plupload.com/license
+ * Contributing: http://www.plupload.com/contributing
+ */
+
+// JSLint defined globals
+/*global window:false, document:false, plupload:false, ActiveXObject:false, escape:false */
+
+(function(window, document, plupload, undef) {
+ var uploadInstances = {}, initialized = {};
+
+ function getFlashVersion() {
+ var version;
+
+ try {
+ version = navigator.plugins['Shockwave Flash'];
+ version = version.description;
+ } catch (e1) {
+ try {
+ version = new ActiveXObject('ShockwaveFlash.ShockwaveFlash').GetVariable('$version');
+ } catch (e2) {
+ version = '0.0';
+ }
+ }
+
+ version = version.match(/\d+/g);
+
+ return parseFloat(version[0] + '.' + version[1]);
+ }
+
+ plupload.flash = {
+ /**
+ * Will be executed by the Flash runtime when it sends out events.
+ *
+ * @param {String} id If for the upload instance.
+ * @param {String} name Event name to trigger.
+ * @param {Object} obj Parameters to be passed with event.
+ */
+ trigger : function(id, name, obj) {
+
+ // Detach the call so that error handling in the browser is presented correctly
+ setTimeout(function() {
+ var uploader = uploadInstances[id], i, args;
+
+ if (uploader) {
+ uploader.trigger('Flash:' + name, obj);
+ }
+ }, 0);
+ }
+ };
+
+ /**
+ * FlashRuntime implementation. This runtime supports these features: jpgresize, pngresize, chunks.
+ *
+ * @static
+ * @class plupload.runtimes.Flash
+ * @extends plupload.Runtime
+ */
+ plupload.runtimes.Flash = plupload.addRuntime("flash", {
+
+ /**
+ * Returns a list of supported features for the runtime.
+ *
+ * @return {Object} Name/value object with supported features.
+ */
+ getFeatures : function() {
+ return {
+ jpgresize: true,
+ pngresize: true,
+ maxWidth: 8091,
+ maxHeight: 8091,
+ chunks: true,
+ progress: true,
+ multipart: true,
+ multi_selection: true
+ };
+ },
+
+ /**
+ * Initializes the upload runtime. This method should add necessary items to the DOM and register events needed for operation.
+ *
+ * @method init
+ * @param {plupload.Uploader} uploader Uploader instance that needs to be initialized.
+ * @param {function} callback Callback to execute when the runtime initializes or fails to initialize. If it succeeds an object with a parameter name success will be set to true.
+ */
+ init : function(uploader, callback) {
+ var browseButton, flashContainer, waitCount = 0, container = document.body;
+
+ if (getFlashVersion() < 10) {
+ callback({success : false});
+ return;
+ }
+
+ initialized[uploader.id] = false;
+ uploadInstances[uploader.id] = uploader;
+
+ // Find browse button and set to to be relative
+ browseButton = document.getElementById(uploader.settings.browse_button);
+
+ // Create flash container and insert it at an absolute position within the browse button
+ flashContainer = document.createElement('div');
+ flashContainer.id = uploader.id + '_flash_container';
+
+ plupload.extend(flashContainer.style, {
+ position : 'absolute',
+ top : '0px',
+ background : uploader.settings.shim_bgcolor || 'transparent',
+ zIndex : 99999,
+ width : '100%',
+ height : '100%'
+ });
+
+ flashContainer.className = 'plupload flash';
+
+ if (uploader.settings.container) {
+ container = document.getElementById(uploader.settings.container);
+ if (plupload.getStyle(container, 'position') === 'static') {
+ container.style.position = 'relative';
+ }
+ }
+
+ container.appendChild(flashContainer);
+
+ // insert flash object
+ (function() {
+ var html, el;
+
+ html = '<object id="' + uploader.id + '_flash" type="application/x-shockwave-flash" data="' + uploader.settings.flash_swf_url + '" ';
+
+ if (plupload.ua.ie) {
+ html += 'classid="clsid:d27cdb6e-ae6d-11cf-96b8-444553540000" ';
+ }
+
+ html += 'width="100%" height="100%" style="outline:0">' +
+ '<param name="movie" value="' + uploader.settings.flash_swf_url + '" />' +
+ '<param name="flashvars" value="id=' + escape(uploader.id) + '" />' +
+ '<param name="wmode" value="transparent" />' +
+ '<param name="allowscriptaccess" value="always" />' +
+ '</object>';
+
+ if (plupload.ua.ie) {
+ el = document.createElement('div');
+ flashContainer.appendChild(el);
+ el.outerHTML = html;
+ el = null; // just in case
+ } else {
+ flashContainer.innerHTML = html;
+ }
+ }());
+
+ function getFlashObj() {
+ return document.getElementById(uploader.id + '_flash');
+ }
+
+ function waitLoad() {
+
+ // Wait for 5 sec
+ if (waitCount++ > 5000) {
+ callback({success : false});
+ return;
+ }
+
+ if (initialized[uploader.id] === false) { // might also be undefined, if uploader was destroyed by that moment
+ setTimeout(waitLoad, 1);
+ }
+ }
+
+ waitLoad();
+
+ // Fix IE memory leaks
+ browseButton = flashContainer = null;
+
+ // destroy should always be available, after Flash:Init or before (#516)
+ uploader.bind("Destroy", function(up) {
+ var flashContainer;
+
+ plupload.removeAllEvents(document.body, up.id);
+
+ delete initialized[up.id];
+ delete uploadInstances[up.id];
+
+ flashContainer = document.getElementById(up.id + '_flash_container');
+ if (flashContainer) {
+ flashContainer.parentNode.removeChild(flashContainer);
+ }
+ });
+
+ // Wait for Flash to send init event
+ uploader.bind("Flash:Init", function() {
+ var lookup = {}, i;
+
+ try {
+ getFlashObj().setFileFilters(uploader.settings.filters, uploader.settings.multi_selection);
+ } catch (ex) {
+ callback({success : false});
+ return;
+ }
+
+ // Prevent eventual reinitialization of the instance
+ if (initialized[uploader.id]) {
+ return;
+ }
+ initialized[uploader.id] = true;
+
+ uploader.bind("UploadFile", function(up, file) {
+ var settings = up.settings, resize = uploader.settings.resize || {};
+
+ getFlashObj().uploadFile(lookup[file.id], settings.url, {
+ name : file.target_name || file.name,
+ mime : plupload.mimeTypes[file.name.replace(/^.+\.([^.]+)/, '$1').toLowerCase()] || 'application/octet-stream',
+ chunk_size : settings.chunk_size,
+ width : resize.width,
+ height : resize.height,
+ quality : resize.quality,
+ multipart : settings.multipart,
+ multipart_params : settings.multipart_params || {},
+ file_data_name : settings.file_data_name,
+ format : /\.(jpg|jpeg)$/i.test(file.name) ? 'jpg' : 'png',
+ headers : settings.headers,
+ urlstream_upload : settings.urlstream_upload
+ });
+ });
+
+ uploader.bind("CancelUpload", function() {
+ getFlashObj().cancelUpload();
+ });
+
+
+ uploader.bind("Flash:UploadProcess", function(up, flash_file) {
+ var file = up.getFile(lookup[flash_file.id]);
+
+ if (file.status != plupload.FAILED) {
+ file.loaded = flash_file.loaded;
+ file.size = flash_file.size;
+
+ up.trigger('UploadProgress', file);
+ }
+ });
+
+ uploader.bind("Flash:UploadChunkComplete", function(up, info) {
+ var chunkArgs, file = up.getFile(lookup[info.id]);
+
+ chunkArgs = {
+ chunk : info.chunk,
+ chunks : info.chunks,
+ response : info.text
+ };
+
+ up.trigger('ChunkUploaded', file, chunkArgs);
+
+ // Stop upload if file is maked as failed
+ if (file.status !== plupload.FAILED && up.state !== plupload.STOPPED) {
+ getFlashObj().uploadNextChunk();
+ }
+
+ // Last chunk then dispatch FileUploaded event
+ if (info.chunk == info.chunks - 1) {
+ file.status = plupload.DONE;
+
+ up.trigger('FileUploaded', file, {
+ response : info.text
+ });
+ }
+ });
+
+ uploader.bind("Flash:SelectFiles", function(up, selected_files) {
+ var file, i, files = [], id;
+
+ // Add the selected files to the file queue
+ for (i = 0; i < selected_files.length; i++) {
+ file = selected_files[i];
+
+ // Store away flash ref internally
+ id = plupload.guid();
+ lookup[id] = file.id;
+ lookup[file.id] = id;
+
+ files.push(new plupload.File(id, file.name, file.size));
+ }
+
+ // Trigger FilesAdded event if we added any
+ if (files.length) {
+ uploader.trigger("FilesAdded", files);
+ }
+ });
+
+ uploader.bind("Flash:SecurityError", function(up, err) {
+ uploader.trigger('Error', {
+ code : plupload.SECURITY_ERROR,
+ message : plupload.translate('Security error.'),
+ details : err.message,
+ file : uploader.getFile(lookup[err.id])
+ });
+ });
+
+ uploader.bind("Flash:GenericError", function(up, err) {
+ uploader.trigger('Error', {
+ code : plupload.GENERIC_ERROR,
+ message : plupload.translate('Generic error.'),
+ details : err.message,
+ file : uploader.getFile(lookup[err.id])
+ });
+ });
+
+ uploader.bind("Flash:IOError", function(up, err) {
+ uploader.trigger('Error', {
+ code : plupload.IO_ERROR,
+ message : plupload.translate('IO error.'),
+ details : err.message,
+ file : uploader.getFile(lookup[err.id])
+ });
+ });
+
+ uploader.bind("Flash:ImageError", function(up, err) {
+ uploader.trigger('Error', {
+ code : parseInt(err.code, 10),
+ message : plupload.translate('Image error.'),
+ file : uploader.getFile(lookup[err.id])
+ });
+ });
+
+ uploader.bind('Flash:StageEvent:rollOver', function(up) {
+ var browseButton, hoverClass;
+
+ browseButton = document.getElementById(uploader.settings.browse_button);
+ hoverClass = up.settings.browse_button_hover;
+
+ if (browseButton && hoverClass) {
+ plupload.addClass(browseButton, hoverClass);
+ }
+ });
+
+ uploader.bind('Flash:StageEvent:rollOut', function(up) {
+ var browseButton, hoverClass;
+
+ browseButton = document.getElementById(uploader.settings.browse_button);
+ hoverClass = up.settings.browse_button_hover;
+
+ if (browseButton && hoverClass) {
+ plupload.removeClass(browseButton, hoverClass);
+ }
+ });
+
+ uploader.bind('Flash:StageEvent:mouseDown', function(up) {
+ var browseButton, activeClass;
+
+ browseButton = document.getElementById(uploader.settings.browse_button);
+ activeClass = up.settings.browse_button_active;
+
+ if (browseButton && activeClass) {
+ plupload.addClass(browseButton, activeClass);
+
+ // Make sure that browse_button has active state removed from it
+ plupload.addEvent(document.body, 'mouseup', function() {
+ plupload.removeClass(browseButton, activeClass);
+ }, up.id);
+ }
+ });
+
+ uploader.bind('Flash:StageEvent:mouseUp', function(up) {
+ var browseButton, activeClass;
+
+ browseButton = document.getElementById(uploader.settings.browse_button);
+ activeClass = up.settings.browse_button_active;
+
+ if (browseButton && activeClass) {
+ plupload.removeClass(browseButton, activeClass);
+ }
+ });
+
+
+ uploader.bind('Flash:ExifData', function(up, obj) {
+ uploader.trigger('ExifData', uploader.getFile(lookup[obj.id]), obj.data);
+ });
+
+
+ uploader.bind('Flash:GpsData', function(up, obj) {
+ uploader.trigger('GpsData', uploader.getFile(lookup[obj.id]), obj.data);
+ });
+
+
+ uploader.bind("QueueChanged", function(up) {
+ uploader.refresh();
+ });
+
+ uploader.bind("FilesRemoved", function(up, files) {
+ var i;
+
+ for (i = 0; i < files.length; i++) {
+ getFlashObj().removeFile(lookup[files[i].id]);
+ }
+ });
+
+ uploader.bind("StateChanged", function(up) {
+ uploader.refresh();
+ });
+
+ uploader.bind("Refresh", function(up) {
+ var browseButton, browsePos, browseSize;
+
+ // Set file filters incase it has been changed dynamically
+ getFlashObj().setFileFilters(uploader.settings.filters, uploader.settings.multi_selection);
+
+ browseButton = document.getElementById(up.settings.browse_button);
+ if (browseButton) {
+ browsePos = plupload.getPos(browseButton, document.getElementById(up.settings.container));
+ browseSize = plupload.getSize(browseButton);
+
+ plupload.extend(document.getElementById(up.id + '_flash_container').style, {
+ top : browsePos.y + 'px',
+ left : browsePos.x + 'px',
+ width : browseSize.w + 'px',
+ height : browseSize.h + 'px'
+ });
+ }
+ });
+
+ uploader.bind("DisableBrowse", function(up, disabled) {
+ getFlashObj().disableBrowse(disabled);
+ });
+
+ callback({success : true});
+ });
+ }
+ });
+})(window, document, plupload);
diff --git a/debian/missing-sources/plupload/javascript/plupload.gears.js b/debian/missing-sources/plupload/javascript/plupload.gears.js
new file mode 100644
index 0000000..c18a828
--- /dev/null
+++ b/debian/missing-sources/plupload/javascript/plupload.gears.js
@@ -0,0 +1,446 @@
+/**
+ * plupload.gears.js
+ *
+ * Copyright 2009, Moxiecode Systems AB
+ * Released under GPL License.
+ *
+ * License: http://www.plupload.com/license
+ * Contributing: http://www.plupload.com/contributing
+ */
+
+// JSLint defined globals
+/*global window:false, document:false, plupload:false, google:false, GearsFactory:false, ActiveXObject:false */
+
+// Copyright 2007, Google Inc.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are met:
+//
+// 1. Redistributions of source code must retain the above copyright notice,
+// this list of conditions and the following disclaimer.
+// 2. Redistributions in binary form must reproduce the above copyright notice,
+// this list of conditions and the following disclaimer in the documentation
+// and/or other materials provided with the distribution.
+// 3. Neither the name of Google Inc. nor the names of its contributors may be
+// used to endorse or promote products derived from this software without
+// specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
+// WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
+// EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
+// OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+// WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+// OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+// ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// Sets up google.gears.*, which is *the only* supported way to access Gears.
+//
+// Circumvent this file at your own risk!
+//
+// In the future, Gears may automatically define google.gears.* without this
+// file. Gears may use these objects to transparently fix bugs and compatibility
+// issues. Applications that use the code below will continue to work seamlessly
+// when that happens.
+
+(function() {
+ // We are already defined. Hooray!
+ if (window.google && google.gears) {
+ return;
+ }
+
+ var factory = null;
+
+ // Firefox
+ if (typeof GearsFactory != 'undefined') {
+ factory = new GearsFactory();
+ } else {
+ // IE
+ try {
+ factory = new ActiveXObject('Gears.Factory');
+ // privateSetGlobalObject is only required and supported on WinCE.
+ if (factory.getBuildInfo().indexOf('ie_mobile') != -1) {
+ factory.privateSetGlobalObject(this);
+ }
+ } catch (e) {
+ // Safari
+ if ((typeof navigator.mimeTypes != 'undefined') && navigator.mimeTypes["application/x-googlegears"]) {
+ factory = document.createElement("object");
+ factory.style.display = "none";
+ factory.width = 0;
+ factory.height = 0;
+ factory.type = "application/x-googlegears";
+ document.documentElement.appendChild(factory);
+ }
+ }
+ }
+
+ // *Do not* define any objects if Gears is not installed. This mimics the
+ // behavior of Gears defining the objects in the future.
+ if (!factory) {
+ return;
+ }
+
+ // Now set up the objects, being careful not to overwrite anything.
+ //
+ // Note: In Internet Explorer for Windows Mobile, you can't add properties to
+ // the window object. However, global objects are automatically added as
+ // properties of the window object in all browsers.
+ if (!window.google) {
+ window.google = {};
+ }
+
+ if (!google.gears) {
+ google.gears = {factory: factory};
+ }
+})();
+
+(function(window, document, plupload, undef) {
+ var blobs = {};
+
+ function scaleImage(image_blob, resize, mime) {
+ var percentage, canvas, context, scale;
+
+ // Setup canvas and scale
+ canvas = google.gears.factory.create('beta.canvas');
+ try {
+ canvas.decode(image_blob);
+
+ if (!resize.width) {
+ resize.width = canvas.width;
+ }
+
+ if (!resize.height) {
+ resize.height = canvas.height;
+ }
+
+ scale = Math.min(resize.width / canvas.width, resize.height / canvas.height);
+
+ if (scale < 1) {
+ canvas.resize(Math.round(canvas.width * scale), Math.round(canvas.height * scale));
+ } else if (!resize.quality || mime !== 'image/jpeg') {
+ return image_blob;
+ }
+
+ if (resize.quality) {
+ return canvas.encode(mime, {quality : resize.quality / 100});
+ }
+
+ return canvas.encode(mime);
+ } catch (e) {
+ // Ignore for example when a user uploads a file that can't be decoded
+ }
+
+ return image_blob;
+ }
+
+ /**
+ * Gears implementation. This runtime supports these features: dragdrop, jpgresize, pngresize, chunks.
+ *
+ * @static
+ * @class plupload.runtimes.Gears
+ * @extends plupload.Runtime
+ */
+ plupload.runtimes.Gears = plupload.addRuntime("gears", {
+ /**
+ * Returns a list of supported features for the runtime.
+ *
+ * @return {Object} Name/value object with supported features.
+ */
+ getFeatures : function() {
+ return {
+ dragdrop: true,
+ jpgresize: true,
+ pngresize: true,
+ chunks: true,
+ progress: true,
+ multipart: true,
+ multi_selection: true
+ };
+ },
+
+ /**
+ * Initializes the upload runtime.
+ *
+ * @method init
+ * @param {plupload.Uploader} uploader Uploader instance that needs to be initialized.
+ * @param {function} callback Callback to execute when the runtime initializes or fails to initialize. If it succeeds an object with a parameter name success will be set to true.
+ */
+ init : function(uploader, callback) {
+ var desktop, req, disabled = false;
+
+ // Check for gears support
+ if (!window.google || !google.gears) {
+ return callback({success : false});
+ }
+
+ try {
+ desktop = google.gears.factory.create('beta.desktop');
+ } catch (e) {
+ // Might fail on the latest Gecko build for some odd reason
+ return callback({success : false});
+ }
+
+ function addSelectedFiles(selected_files) {
+ var file, i, files = [], id;
+
+ // Add the selected files to the file queue
+ for (i = 0; i < selected_files.length; i++) {
+ file = selected_files[i];
+
+ // Store away gears blob internally
+ id = plupload.guid();
+ blobs[id] = file.blob;
+
+ files.push(new plupload.File(id, file.name, file.blob.length));
+ }
+
+ // Fire FilesAdded event
+ uploader.trigger("FilesAdded", files);
+ }
+
+ // Add drop handler
+ uploader.bind("PostInit", function() {
+ var settings = uploader.settings, dropElm = document.getElementById(settings.drop_element);
+
+ if (dropElm) {
+ // Block browser default drag over
+ plupload.addEvent(dropElm, 'dragover', function(e) {
+ desktop.setDropEffect(e, 'copy');
+ e.preventDefault();
+ }, uploader.id);
+
+ // Attach drop handler and grab files from Gears
+ plupload.addEvent(dropElm, 'drop', function(e) {
+ var dragData = desktop.getDragData(e, 'application/x-gears-files');
+
+ if (dragData) {
+ addSelectedFiles(dragData.files);
+ }
+
+ e.preventDefault();
+ }, uploader.id);
+
+ // Prevent IE leak
+ dropElm = 0;
+ }
+
+ // Add browse button
+ plupload.addEvent(document.getElementById(settings.browse_button), 'click', function(e) {
+ var filters = [], i, a, ext;
+
+ e.preventDefault();
+
+ if (disabled) {
+ return;
+ }
+
+ no_type_restriction:
+ for (i = 0; i < settings.filters.length; i++) {
+ ext = settings.filters[i].extensions.split(',');
+
+ for (a = 0; a < ext.length; a++) {
+ if (ext[a] === '*') {
+ filters = [];
+ break no_type_restriction;
+ }
+
+ filters.push('.' + ext[a]);
+ }
+ }
+
+ desktop.openFiles(addSelectedFiles, {singleFile : !settings.multi_selection, filter : filters});
+ }, uploader.id);
+ });
+
+
+ uploader.bind("CancelUpload", function() {
+ if (req.abort) {
+ req.abort();
+ }
+ });
+
+
+ uploader.bind("UploadFile", function(up, file) {
+ var chunk = 0, chunks, chunkSize, loaded = 0, resize = up.settings.resize, chunking;
+
+ // If file is png or jpeg and resize is configured then resize it
+ if (resize && /\.(png|jpg|jpeg)$/i.test(file.name)) {
+ blobs[file.id] = scaleImage(blobs[file.id], resize, /\.png$/i.test(file.name) ? 'image/png' : 'image/jpeg');
+ }
+
+ file.size = blobs[file.id].length;
+
+ chunkSize = up.settings.chunk_size;
+ chunking = chunkSize > 0;
+ chunks = Math.ceil(file.size / chunkSize);
+
+ // If chunking is disabled then upload the whole file in one huge chunk
+ if (!chunking) {
+ chunkSize = file.size;
+ chunks = 1;
+ }
+
+ function uploadNextChunk() {
+ var curChunkSize, multipart = up.settings.multipart, multipartLength = 0, reqArgs = {name : file.target_name || file.name}, url = up.settings.url;
+
+ // Sends the binary blob multipart encoded or raw depending on config
+ function sendBinaryBlob(blob) {
+ var builder, boundary = '----pluploadboundary' + plupload.guid(), dashdash = '--', crlf = '\r\n', multipartBlob, mimeType;
+
+ // Build multipart request
+ if (multipart) {
+ req.setRequestHeader('Content-Type', 'multipart/form-data; boundary=' + boundary);
+ builder = google.gears.factory.create('beta.blobbuilder');
+
+ // Append mutlipart parameters
+ plupload.each(plupload.extend(reqArgs, up.settings.multipart_params), function(value, name) {
+ builder.append(
+ dashdash + boundary + crlf +
+ 'Content-Disposition: form-data; name="' + name + '"' + crlf + crlf
+ );
+
+ builder.append(value + crlf);
+ });
+
+ mimeType = plupload.mimeTypes[file.name.replace(/^.+\.([^.]+)/, '$1').toLowerCase()] || 'application/octet-stream';
+
+ // Add file header
+ builder.append(
+ dashdash + boundary + crlf +
+ 'Content-Disposition: form-data; name="' + up.settings.file_data_name + '"; filename="' + file.name + '"' + crlf +
+ 'Content-Type: ' + mimeType + crlf + crlf
+ );
+
+ // Add file data
+ builder.append(blob);
+
+ // Add footer
+ builder.append(crlf + dashdash + boundary + dashdash + crlf);
+ multipartBlob = builder.getAsBlob();
+ multipartLength = multipartBlob.length - blob.length;
+ blob = multipartBlob;
+ }
+
+ // Send blob or multipart blob depending on config
+ req.send(blob);
+ }
+
+ // File upload finished
+ if (file.status == plupload.DONE || file.status == plupload.FAILED || up.state == plupload.STOPPED) {
+ return;
+ }
+
+ // Only add chunking args if needed
+ if (chunking) {
+ reqArgs.chunk = chunk;
+ reqArgs.chunks = chunks;
+ }
+
+ // Setup current chunk size
+ curChunkSize = Math.min(chunkSize, file.size - (chunk * chunkSize));
+
+ if (!multipart) {
+ url = plupload.buildUrl(up.settings.url, reqArgs);
+ }
+
+ req = google.gears.factory.create('beta.httprequest');
+ req.open('POST', url);
+
+ // Add disposition and type if multipart is disabled
+ if (!multipart) {
+ req.setRequestHeader('Content-Disposition', 'attachment; filename="' + file.name + '"');
+ req.setRequestHeader('Content-Type', 'application/octet-stream');
+ }
+
+ // Set custom headers
+ plupload.each(up.settings.headers, function(value, name) {
+ req.setRequestHeader(name, value);
+ });
+
+ req.upload.onprogress = function(progress) {
+ file.loaded = loaded + progress.loaded - multipartLength;
+ up.trigger('UploadProgress', file);
+ };
+
+ req.onreadystatechange = function() {
+ var chunkArgs;
+
+ if (req.readyState == 4 && up.state !== plupload.STOPPED) {
+ if (req.status == 200) {
+ chunkArgs = {
+ chunk : chunk,
+ chunks : chunks,
+ response : req.responseText,
+ status : req.status
+ };
+
+ up.trigger('ChunkUploaded', file, chunkArgs);
+
+ // Stop upload
+ if (chunkArgs.cancelled) {
+ file.status = plupload.FAILED;
+ return;
+ }
+
+ loaded += curChunkSize;
+
+ if (++chunk >= chunks) {
+ file.status = plupload.DONE;
+ up.trigger('FileUploaded', file, {
+ response : req.responseText,
+ status : req.status
+ });
+ } else {
+ uploadNextChunk();
+ }
+ } else {
+ up.trigger('Error', {
+ code : plupload.HTTP_ERROR,
+ message : plupload.translate('HTTP Error.'),
+ file : file,
+ chunk : chunk,
+ chunks : chunks,
+ status : req.status
+ });
+ }
+ }
+ };
+
+ if (chunk < chunks) {
+ sendBinaryBlob(blobs[file.id].slice(chunk * chunkSize, curChunkSize));
+ }
+ }
+
+ // Start uploading chunks
+ uploadNextChunk();
+ });
+
+ uploader.bind("DisableBrowse", function(up, state) {
+ disabled = state;
+ });
+
+
+ uploader.bind("Destroy", function(up) {
+ var name, element,
+ elements = {
+ browseButton: up.settings.browse_button,
+ dropElm: up.settings.drop_element
+ };
+
+ // Unbind event handlers
+ for (name in elements) {
+ element = document.getElementById(elements[name]);
+ if (element) {
+ plupload.removeAllEvents(element, up.id);
+ }
+ }
+ });
+
+
+ callback({success : true});
+ }
+ });
+})(window, document, plupload);
diff --git a/debian/missing-sources/plupload/javascript/plupload.html4.js b/debian/missing-sources/plupload/javascript/plupload.html4.js
new file mode 100644
index 0000000..f3d7846
--- /dev/null
+++ b/debian/missing-sources/plupload/javascript/plupload.html4.js
@@ -0,0 +1,430 @@
+/**
+ * plupload.html4.js
+ *
+ * Copyright 2010, Ryan Demmer
+ * Copyright 2009, Moxiecode Systems AB
+ * Released under GPL License.
+ *
+ * License: http://www.plupload.com/license
+ * Contributing: http://www.plupload.com/contributing
+ */
+
+// JSLint defined globals
+/*global plupload:false, window:false */
+
+(function(window, document, plupload, undef) {
+ function getById(id) {
+ return document.getElementById(id);
+ }
+
+ /**
+ * HTML4 implementation. This runtime has no special features it uses an form that posts files into an hidden iframe.
+ *
+ * @static
+ * @class plupload.runtimes.Html4
+ * @extends plupload.Runtime
+ */
+ plupload.runtimes.Html4 = plupload.addRuntime("html4", {
+ /**
+ * Returns a list of supported features for the runtime.
+ *
+ * @return {Object} Name/value object with supported features.
+ */
+ getFeatures : function() {
+ // Only multipart feature
+ return {
+ multipart: true,
+
+ // WebKit and Gecko 2+ can trigger file dialog progrmmatically
+ triggerDialog: (plupload.ua.gecko && window.FormData || plupload.ua.webkit)
+ };
+ },
+
+ /**
+ * Initializes the upload runtime.
+ *
+ * @method init
+ * @param {plupload.Uploader} uploader Uploader instance that needs to be initialized.
+ * @param {function} callback Callback to execute when the runtime initializes or fails to initialize. If it succeeds an object with a parameter name success will be set to true.
+ */
+ init : function(uploader, callback) {
+ uploader.bind("Init", function(up) {
+ var container = document.body, iframe, url = "javascript", currentFile,
+ input, currentFileId, fileIds = [], IE = /MSIE/.test(navigator.userAgent), mimes = [],
+ filters = up.settings.filters, i, ext, type, y;
+
+ // Convert extensions to mime types list
+ no_type_restriction:
+ for (i = 0; i < filters.length; i++) {
+ ext = filters[i].extensions.split(/,/);
+
+ for (y = 0; y < ext.length; y++) {
+
+ // If there's an asterisk in the list, then accept attribute is not required
+ if (ext[y] === '*') {
+ mimes = [];
+ break no_type_restriction;
+ }
+
+ type = plupload.mimeTypes[ext[y]];
+
+ if (type && plupload.inArray(type, mimes) === -1) {
+ mimes.push(type);
+ }
+ }
+ }
+
+ mimes = mimes.join(',');
+
+ function createForm() {
+ var form, input, bgcolor, browseButton;
+
+ // Setup unique id for form
+ currentFileId = plupload.guid();
+
+ // Save id for Destroy handler
+ fileIds.push(currentFileId);
+
+ // Create form
+ form = document.createElement('form');
+ form.setAttribute('id', 'form_' + currentFileId);
+ form.setAttribute('method', 'post');
+ form.setAttribute('enctype', 'multipart/form-data');
+ form.setAttribute('encoding', 'multipart/form-data');
+ form.setAttribute("target", up.id + '_iframe');
+ form.style.position = 'absolute';
+
+ // Create input and set attributes
+ input = document.createElement('input');
+ input.setAttribute('id', 'input_' + currentFileId);
+ input.setAttribute('type', 'file');
+ input.setAttribute('accept', mimes);
+ input.setAttribute('size', 1);
+
+ browseButton = getById(up.settings.browse_button);
+
+ // Route click event to input element programmatically, if possible
+ if (up.features.triggerDialog && browseButton) {
+ plupload.addEvent(getById(up.settings.browse_button), 'click', function(e) {
+ if (!input.disabled) {
+ input.click();
+ }
+ e.preventDefault();
+ }, up.id);
+ }
+
+ // Set input styles
+ plupload.extend(input.style, {
+ width : '100%',
+ height : '100%',
+ opacity : 0,
+ fontSize: '99px', // force input element to be bigger then needed to occupy whole space
+ cursor: 'pointer'
+ });
+
+ plupload.extend(form.style, {
+ overflow: 'hidden'
+ });
+
+ // Show the container if shim_bgcolor is specified
+ bgcolor = up.settings.shim_bgcolor;
+ if (bgcolor) {
+ form.style.background = bgcolor;
+ }
+
+ // no opacity in IE
+ if (IE) {
+ plupload.extend(input.style, {
+ filter : "alpha(opacity=0)"
+ });
+ }
+
+ // add change event
+ plupload.addEvent(input, 'change', function(e) {
+ var element = e.target, name, files = [], topElement;
+
+ if (element.value) {
+ getById('form_' + currentFileId).style.top = -0xFFFFF + "px";
+
+ // Get file name
+ name = element.value.replace(/\\/g, '/');
+ name = name.substring(name.length, name.lastIndexOf('/') + 1);
+
+ // Push files
+ files.push(new plupload.File(currentFileId, name));
+
+ // Clean-up events - they won't be needed anymore
+ if (!up.features.triggerDialog) {
+ plupload.removeAllEvents(form, up.id);
+ } else {
+ plupload.removeEvent(browseButton, 'click', up.id);
+ }
+ plupload.removeEvent(input, 'change', up.id);
+
+ // Create and position next form
+ createForm();
+
+ // Fire FilesAdded event
+ if (files.length) {
+ uploader.trigger("FilesAdded", files);
+ }
+ }
+ }, up.id);
+
+ // append to container
+ form.appendChild(input);
+ container.appendChild(form);
+
+ up.refresh();
+ }
+
+
+ function createIframe() {
+ var temp = document.createElement('div');
+
+ // Create iframe using a temp div since IE 6 won't be able to set the name using setAttribute or iframe.name
+ temp.innerHTML = '<iframe id="' + up.id + '_iframe" name="' + up.id + '_iframe" src="' + url + ':&quot;&quot;" style="display:none"></iframe>';
+ iframe = temp.firstChild;
+ container.appendChild(iframe);
+
+ // Add IFrame onload event
+ plupload.addEvent(iframe, 'load', function(e) {
+ var n = e.target, el, result;
+
+ // Ignore load event if there is no file
+ if (!currentFile) {
+ return;
+ }
+
+ try {
+ el = n.contentWindow.document || n.contentDocument || window.frames[n.id].document;
+ } catch (ex) {
+ // Probably a permission denied error
+ up.trigger('Error', {
+ code : plupload.SECURITY_ERROR,
+ message : plupload.translate('Security error.'),
+ file : currentFile
+ });
+
+ return;
+ }
+
+ // Get result
+ result = el.documentElement.innerText || el.documentElement.textContent;
+
+ // Assume no error
+ if (result) {
+ currentFile.status = plupload.DONE;
+ currentFile.loaded = 1025;
+ currentFile.percent = 100;
+
+ up.trigger('UploadProgress', currentFile);
+ up.trigger('FileUploaded', currentFile, {
+ response : result
+ });
+ }
+ }, up.id);
+ } // end createIframe
+
+ if (up.settings.container) {
+ container = getById(up.settings.container);
+ if (plupload.getStyle(container, 'position') === 'static') {
+ container.style.position = 'relative';
+ }
+ }
+
+ // Upload file
+ up.bind("UploadFile", function(up, file) {
+ var form, input;
+
+ // File upload finished
+ if (file.status == plupload.DONE || file.status == plupload.FAILED || up.state == plupload.STOPPED) {
+ return;
+ }
+
+ // Get the form and input elements
+ form = getById('form_' + file.id);
+ input = getById('input_' + file.id);
+
+ // Set input element name attribute which allows it to be submitted
+ input.setAttribute('name', up.settings.file_data_name);
+
+ // Store action
+ form.setAttribute("action", up.settings.url);
+
+ // Append multipart parameters
+ plupload.each(plupload.extend({name : file.target_name || file.name}, up.settings.multipart_params), function(value, name) {
+ var hidden = document.createElement('input');
+
+ plupload.extend(hidden, {
+ type : 'hidden',
+ name : name,
+ value : value
+ });
+
+ form.insertBefore(hidden, form.firstChild);
+ });
+
+ currentFile = file;
+
+ // Hide the current form
+ getById('form_' + currentFileId).style.top = -0xFFFFF + "px";
+
+ form.submit();
+ });
+
+
+
+ up.bind('FileUploaded', function(up) {
+ up.refresh(); // just to get the form back on top of browse_button
+ });
+
+ up.bind('StateChanged', function(up) {
+ if (up.state == plupload.STARTED) {
+ createIframe();
+ } else if (up.state == plupload.STOPPED) {
+ window.setTimeout(function() {
+ plupload.removeEvent(iframe, 'load', up.id);
+ if (iframe.parentNode) { // #382
+ iframe.parentNode.removeChild(iframe);
+ }
+ }, 0);
+ }
+
+ plupload.each(up.files, function(file, i) {
+ if (file.status === plupload.DONE || file.status === plupload.FAILED) {
+ var form = getById('form_' + file.id);
+
+ if(form){
+ form.parentNode.removeChild(form);
+ }
+ }
+ });
+ });
+
+ // Refresh button, will reposition the input form
+ up.bind("Refresh", function(up) {
+ var browseButton, topElement, hoverClass, activeClass, browsePos, browseSize, inputContainer, inputFile, zIndex;
+
+ browseButton = getById(up.settings.browse_button);
+ if (browseButton) {
+ browsePos = plupload.getPos(browseButton, getById(up.settings.container));
+ browseSize = plupload.getSize(browseButton);
+ inputContainer = getById('form_' + currentFileId);
+ inputFile = getById('input_' + currentFileId);
+
+ plupload.extend(inputContainer.style, {
+ top : browsePos.y + 'px',
+ left : browsePos.x + 'px',
+ width : browseSize.w + 'px',
+ height : browseSize.h + 'px'
+ });
+
+ // for IE and WebKit place input element underneath the browse button and route onclick event
+ // TODO: revise when browser support for this feature will change
+ if (up.features.triggerDialog) {
+ if (plupload.getStyle(browseButton, 'position') === 'static') {
+ plupload.extend(browseButton.style, {
+ position : 'relative'
+ });
+ }
+
+ zIndex = parseInt(browseButton.style.zIndex, 10);
+
+ if (isNaN(zIndex)) {
+ zIndex = 0;
+ }
+
+ plupload.extend(browseButton.style, {
+ zIndex : zIndex
+ });
+
+ plupload.extend(inputContainer.style, {
+ zIndex : zIndex - 1
+ });
+ }
+
+ /* Since we have to place input[type=file] on top of the browse_button for some browsers (FF, Opera),
+ browse_button loses interactivity, here we try to neutralize this issue highlighting browse_button
+ with a special class
+ TODO: needs to be revised as things will change */
+ hoverClass = up.settings.browse_button_hover;
+ activeClass = up.settings.browse_button_active;
+ topElement = up.features.triggerDialog ? browseButton : inputContainer;
+
+ if (hoverClass) {
+ plupload.addEvent(topElement, 'mouseover', function() {
+ plupload.addClass(browseButton, hoverClass);
+ }, up.id);
+ plupload.addEvent(topElement, 'mouseout', function() {
+ plupload.removeClass(browseButton, hoverClass);
+ }, up.id);
+ }
+
+ if (activeClass) {
+ plupload.addEvent(topElement, 'mousedown', function() {
+ plupload.addClass(browseButton, activeClass);
+ }, up.id);
+ plupload.addEvent(document.body, 'mouseup', function() {
+ plupload.removeClass(browseButton, activeClass);
+ }, up.id);
+ }
+ }
+ });
+
+ // Remove files
+ uploader.bind("FilesRemoved", function(up, files) {
+ var i, n;
+
+ for (i = 0; i < files.length; i++) {
+ n = getById('form_' + files[i].id);
+ if (n) {
+ n.parentNode.removeChild(n);
+ }
+ }
+ });
+
+ uploader.bind("DisableBrowse", function(up, disabled) {
+ var input = document.getElementById('input_' + currentFileId);
+ if (input) {
+ input.disabled = disabled;
+ }
+ });
+
+
+ // Completely destroy the runtime
+ uploader.bind("Destroy", function(up) {
+ var name, element, form,
+ elements = {
+ inputContainer: 'form_' + currentFileId,
+ inputFile: 'input_' + currentFileId,
+ browseButton: up.settings.browse_button
+ };
+
+ // Unbind event handlers
+ for (name in elements) {
+ element = getById(elements[name]);
+ if (element) {
+ plupload.removeAllEvents(element, up.id);
+ }
+ }
+ plupload.removeAllEvents(document.body, up.id);
+
+ // Remove mark-up
+ plupload.each(fileIds, function(id, i) {
+ form = getById('form_' + id);
+ if (form) {
+ form.parentNode.removeChild(form);
+ }
+ });
+
+ });
+
+ // Create initial form
+ createForm();
+ });
+
+ callback({success : true});
+ }
+ });
+})(window, document, plupload);
diff --git a/debian/missing-sources/plupload/javascript/plupload.html5.js b/debian/missing-sources/plupload/javascript/plupload.html5.js
new file mode 100644
index 0000000..4b154b8
--- /dev/null
+++ b/debian/missing-sources/plupload/javascript/plupload.html5.js
@@ -0,0 +1,1525 @@
+/**
+ * plupload.html5.js
+ *
+ * Copyright 2009, Moxiecode Systems AB
+ * Released under GPL License.
+ *
+ * License: http://www.plupload.com/license
+ * Contributing: http://www.plupload.com/contributing
+ */
+
+// JSLint defined globals
+/*global plupload:false, File:false, window:false, atob:false, FormData:false, FileReader:false, ArrayBuffer:false, Uint8Array:false, BlobBuilder:false, unescape:false */
+
+(function(window, document, plupload, undef) {
+ var html5files = {}, // queue of original File objects
+ fakeSafariDragDrop;
+
+ /**
+ * Detect subsampling in loaded image.
+ * In iOS, larger images than 2M pixels may be subsampled in rendering.
+ */
+ function detectSubsampling(img) {
+ var iw = img.naturalWidth, ih = img.naturalHeight;
+ if (iw * ih > 1024 * 1024) { // subsampling may happen over megapixel image
+ var canvas = document.createElement('canvas');
+ canvas.width = canvas.height = 1;
+ var ctx = canvas.getContext('2d');
+ ctx.drawImage(img, -iw + 1, 0);
+ // subsampled image becomes half smaller in rendering size.
+ // check alpha channel value to confirm image is covering edge pixel or not.
+ // if alpha value is 0 image is not covering, hence subsampled.
+ return ctx.getImageData(0, 0, 1, 1).data[3] === 0;
+ } else {
+ return false;
+ }
+ }
+
+ /**
+ * Detecting vertical squash in loaded image.
+ * Fixes a bug which squash image vertically while drawing into canvas for some images.
+ */
+ function detectVerticalSquash(img, iw, ih) {
+ var canvas = document.createElement('canvas');
+ canvas.width = 1;
+ canvas.height = ih;
+ var ctx = canvas.getContext('2d');
+ ctx.drawImage(img, 0, 0);
+ var data = ctx.getImageData(0, 0, 1, ih).data;
+ // search image edge pixel position in case it is squashed vertically.
+ var sy = 0;
+ var ey = ih;
+ var py = ih;
+ while (py > sy) {
+ var alpha = data[(py - 1) * 4 + 3];
+ if (alpha === 0) {
+ ey = py;
+ } else {
+ sy = py;
+ }
+
+ py = (ey + sy) >> 1;
+ }
+
+ var ratio = (py / ih);
+ return (ratio === 0) ? 1 : ratio;
+ }
+
+ /**
+ * Rendering image element (with resizing) into the canvas element
+ */
+ function renderImageToCanvas(img, canvas, options) {
+ var iw = img.naturalWidth, ih = img.naturalHeight;
+ var width = options.width, height = options.height;
+ var ctx = canvas.getContext('2d');
+ ctx.save();
+ var subsampled = detectSubsampling(img);
+ if (subsampled) {
+ iw /= 2;
+ ih /= 2;
+ }
+
+ var d = 1024; // size of tiling canvas
+ var tmpCanvas = document.createElement('canvas');
+ tmpCanvas.width = tmpCanvas.height = d;
+ var tmpCtx = tmpCanvas.getContext('2d');
+ var vertSquashRatio = detectVerticalSquash(img, iw, ih);
+ var sy = 0;
+ while (sy < ih) {
+ var sh = sy + d > ih ? ih - sy : d;
+ var sx = 0;
+ while (sx < iw) {
+ var sw = sx + d > iw ? iw - sx : d;
+ tmpCtx.clearRect(0, 0, d, d);
+ tmpCtx.drawImage(img, -sx, -sy);
+ var dx = (sx * width / iw) << 0;
+ var dw = Math.ceil(sw * width / iw);
+ var dy = (sy * height / ih / vertSquashRatio) << 0;
+ var dh = Math.ceil(sh * height / ih / vertSquashRatio);
+ ctx.drawImage(tmpCanvas, 0, 0, sw, sh, dx, dy, dw, dh);
+ sx += d;
+ }
+
+ sy += d;
+ }
+
+ ctx.restore();
+ tmpCanvas = tmpCtx = null;
+ }
+
+ function readFileAsDataURL(file, callback) {
+ var reader;
+
+ // Use FileReader if it's available
+ if ("FileReader" in window) {
+ reader = new FileReader();
+ reader.readAsDataURL(file);
+ reader.onload = function() {
+ callback(reader.result);
+ };
+ } else {
+ return callback(file.getAsDataURL());
+ }
+ }
+
+ function readFileAsBinary(file, callback) {
+ var reader;
+
+ // Use FileReader if it's available
+ if ("FileReader" in window) {
+ reader = new FileReader();
+ reader.readAsBinaryString(file);
+ reader.onload = function() {
+ callback(reader.result);
+ };
+ } else {
+ return callback(file.getAsBinary());
+ }
+ }
+
+ function scaleImage(file, resize, mime, callback) {
+ var canvas, context, img, scale,
+ up = this;
+
+ readFileAsDataURL(html5files[file.id], function(data) {
+ // Setup canvas and context
+ canvas = document.createElement("canvas");
+ canvas.style.display = 'none';
+ document.body.appendChild(canvas);
+
+ // Load image
+ img = new Image();
+ img.onerror = img.onabort = function() {
+ // Failed to load, the image may be invalid
+ callback({success : false});
+ };
+ img.onload = function() {
+ var width, height, percentage, jpegHeaders, exifParser;
+
+ if (!resize['width']) {
+ resize['width'] = img.width;
+ }
+
+ if (!resize['height']) {
+ resize['height'] = img.height;
+ }
+
+ scale = Math.min(resize.width / img.width, resize.height / img.height);
+
+ if (scale < 1) {
+ width = Math.round(img.width * scale);
+ height = Math.round(img.height * scale);
+ } else if (resize['quality'] && mime === 'image/jpeg') {
+ // do not upsize, but drop the quality for jpegs
+ width = img.width;
+ height = img.height;
+ } else {
+ // Image does not need to be resized
+ callback({success : false});
+ return;
+ }
+
+ // Scale image and canvas
+ canvas.width = width;
+ canvas.height = height;
+ renderImageToCanvas(img, canvas, { width: width, height: height });
+
+ // Preserve JPEG headers
+ if (mime === 'image/jpeg') {
+ jpegHeaders = new JPEG_Headers(atob(data.substring(data.indexOf('base64,') + 7)));
+ if (jpegHeaders['headers'] && jpegHeaders['headers'].length) {
+ exifParser = new ExifParser();
+
+ if (exifParser.init(jpegHeaders.get('exif')[0])) {
+ // Set new width and height
+ exifParser.setExif('PixelXDimension', width);
+ exifParser.setExif('PixelYDimension', height);
+
+ // Update EXIF header
+ jpegHeaders.set('exif', exifParser.getBinary());
+
+ // trigger Exif events only if someone listens to them
+ if (up.hasEventListener('ExifData')) {
+ up.trigger('ExifData', file, exifParser.EXIF());
+ }
+
+ if (up.hasEventListener('GpsData')) {
+ up.trigger('GpsData', file, exifParser.GPS());
+ }
+ }
+ }
+ }
+
+ if (resize['quality'] && mime === 'image/jpeg') {
+ // Try quality property first
+ try {
+ data = canvas.toDataURL(mime, resize['quality'] / 100); // used to throw an exception in Firefox
+ } catch (ex) {
+ data = canvas.toDataURL(mime);
+ }
+ } else {
+ data = canvas.toDataURL(mime);
+ }
+
+
+ // Remove data prefix information and grab the base64 encoded data and decode it
+ data = data.substring(data.indexOf('base64,') + 7);
+ data = atob(data);
+
+ // Restore JPEG headers if applicable
+ if (jpegHeaders && jpegHeaders['headers'] && jpegHeaders['headers'].length) {
+ data = jpegHeaders.restore(data);
+ jpegHeaders.purge(); // free memory
+ }
+
+ // Remove canvas and execute callback with decoded image data
+ canvas.parentNode.removeChild(canvas);
+ callback({success : true, data : data});
+ };
+
+ img.src = data;
+ });
+ }
+
+ /**
+ * HMTL5 implementation. This runtime supports these features: dragdrop, jpgresize, pngresize.
+ *
+ * @static
+ * @class plupload.runtimes.Html5
+ * @extends plupload.Runtime
+ */
+ plupload.runtimes.Html5 = plupload.addRuntime("html5", {
+ /**
+ * Returns a list of supported features for the runtime.
+ *
+ * @return {Object} Name/value object with supported features.
+ */
+ getFeatures : function() {
+ var xhr, hasXhrSupport, hasProgress, canSendBinary, dataAccessSupport, sliceSupport;
+
+ hasXhrSupport = hasProgress = dataAccessSupport = sliceSupport = false;
+
+ if (window.XMLHttpRequest) {
+ xhr = new XMLHttpRequest();
+ hasProgress = !!xhr.upload;
+ hasXhrSupport = !!(xhr.sendAsBinary || xhr.upload);
+ }
+
+ // Check for support for various features
+ if (hasXhrSupport) {
+ canSendBinary = !!(xhr.sendAsBinary || (window.Uint8Array && window.ArrayBuffer));
+
+ // Set dataAccessSupport only for Gecko since BlobBuilder and XHR doesn't handle binary data correctly
+ dataAccessSupport = !!(File && (File.prototype.getAsDataURL || window.FileReader) && canSendBinary);
+ sliceSupport = !!(File && (File.prototype.mozSlice || File.prototype.webkitSlice || File.prototype.slice));
+ }
+
+ // sniff out Safari for Windows and fake drag/drop
+ fakeSafariDragDrop = plupload.ua.safari && plupload.ua.windows;
+
+ return {
+ html5: hasXhrSupport, // This is a special one that we check inside the init call
+ dragdrop: (function() {
+ // this comes directly from Modernizr: http://www.modernizr.com/
+ var div = document.createElement('div');
+ return ('draggable' in div) || ('ondragstart' in div && 'ondrop' in div);
+ }()),
+ jpgresize: dataAccessSupport,
+ pngresize: dataAccessSupport,
+ multipart: dataAccessSupport || !!window.FileReader || !!window.FormData,
+ canSendBinary: canSendBinary,
+ // gecko 2/5/6 can't send blob with FormData: https://bugzilla.mozilla.org/show_bug.cgi?id=649150
+ // Android browsers (default one and Dolphin) seem to have the same issue, see: #613
+ cantSendBlobInFormData: !!(plupload.ua.gecko && window.FormData && window.FileReader && !FileReader.prototype.readAsArrayBuffer) || plupload.ua.android,
+ progress: hasProgress,
+ chunks: sliceSupport,
+ // Safari on Windows has problems when selecting multiple files
+ multi_selection: !(plupload.ua.safari && plupload.ua.windows),
+ // WebKit and Gecko 2+ can trigger file dialog progrmmatically
+ triggerDialog: (plupload.ua.gecko && window.FormData || plupload.ua.webkit)
+ };
+ },
+
+ /**
+ * Initializes the upload runtime.
+ *
+ * @method init
+ * @param {plupload.Uploader} uploader Uploader instance that needs to be initialized.
+ * @param {function} callback Callback to execute when the runtime initializes or fails to initialize. If it succeeds an object with a parameter name success will be set to true.
+ */
+ init : function(uploader, callback) {
+ var features, xhr;
+
+ function addSelectedFiles(native_files) {
+ var file, i, files = [], id, fileNames = {};
+
+ // Add the selected files to the file queue
+ for (i = 0; i < native_files.length; i++) {
+ file = native_files[i];
+
+ // Safari on Windows will add first file from dragged set multiple times
+ // @see: https://bugs.webkit.org/show_bug.cgi?id=37957
+ if (fileNames[file.name] && plupload.ua.safari && plupload.ua.windows) {
+ continue;
+ }
+ fileNames[file.name] = true;
+
+ // Store away gears blob internally
+ id = plupload.guid();
+ html5files[id] = file;
+
+ // Expose id, name and size
+ files.push(new plupload.File(id, file.fileName || file.name, file.fileSize || file.size)); // fileName / fileSize depricated
+ }
+
+ // Trigger FilesAdded event if we added any
+ if (files.length) {
+ uploader.trigger("FilesAdded", files);
+ }
+ }
+
+ // No HTML5 upload support
+ features = this.getFeatures();
+ if (!features.html5) {
+ callback({success : false});
+ return;
+ }
+
+ uploader.bind("Init", function(up) {
+ var inputContainer, browseButton, mimes = [], i, y, filters = up.settings.filters, ext, type, container = document.body, inputFile;
+
+ // Create input container and insert it at an absolute position within the browse button
+ inputContainer = document.createElement('div');
+ inputContainer.id = up.id + '_html5_container';
+
+ plupload.extend(inputContainer.style, {
+ position : 'absolute',
+ background : uploader.settings.shim_bgcolor || 'transparent',
+ width : '100px',
+ height : '100px',
+ overflow : 'hidden',
+ zIndex : 99999,
+ opacity : uploader.settings.shim_bgcolor ? '' : 0 // Force transparent if bgcolor is undefined
+ });
+ inputContainer.className = 'plupload html5';
+
+ if (uploader.settings.container) {
+ container = document.getElementById(uploader.settings.container);
+ if (plupload.getStyle(container, 'position') === 'static') {
+ container.style.position = 'relative';
+ }
+ }
+
+ container.appendChild(inputContainer);
+
+ // Convert extensions to mime types list
+ no_type_restriction:
+ for (i = 0; i < filters.length; i++) {
+ ext = filters[i].extensions.split(/,/);
+
+ for (y = 0; y < ext.length; y++) {
+
+ // If there's an asterisk in the list, then accept attribute is not required
+ if (ext[y] === '*') {
+ mimes = [];
+ break no_type_restriction;
+ }
+
+ type = plupload.mimeTypes[ext[y]];
+
+ if (type && plupload.inArray(type, mimes) === -1) {
+ mimes.push(type);
+ }
+ }
+ }
+
+
+ // Insert the input inside the input container
+ inputContainer.innerHTML = '<input id="' + uploader.id + '_html5" ' + ' style="font-size:999px"' +
+ ' type="file" accept="' + mimes.join(',') + '" ' +
+ (uploader.settings.multi_selection && uploader.features.multi_selection ? 'multiple="multiple"' : '') + ' />';
+
+ inputContainer.scrollTop = 100;
+ inputFile = document.getElementById(uploader.id + '_html5');
+
+ if (up.features.triggerDialog) {
+ plupload.extend(inputFile.style, {
+ position: 'absolute',
+ width: '100%',
+ height: '100%'
+ });
+ } else {
+ // shows arrow cursor instead of the text one, bit more logical
+ plupload.extend(inputFile.style, {
+ cssFloat: 'right',
+ styleFloat: 'right'
+ });
+ }
+
+ inputFile.onchange = function() {
+ // Add the selected files from file input
+ addSelectedFiles(this.files);
+
+ // Clearing the value enables the user to select the same file again if they want to
+ this.value = '';
+ };
+
+ /* Since we have to place input[type=file] on top of the browse_button for some browsers (FF, Opera),
+ browse_button loses interactivity, here we try to neutralize this issue highlighting browse_button
+ with a special classes
+ TODO: needs to be revised as things will change */
+ browseButton = document.getElementById(up.settings.browse_button);
+ if (browseButton) {
+ var hoverClass = up.settings.browse_button_hover,
+ activeClass = up.settings.browse_button_active,
+ topElement = up.features.triggerDialog ? browseButton : inputContainer;
+
+ if (hoverClass) {
+ plupload.addEvent(topElement, 'mouseover', function() {
+ plupload.addClass(browseButton, hoverClass);
+ }, up.id);
+ plupload.addEvent(topElement, 'mouseout', function() {
+ plupload.removeClass(browseButton, hoverClass);
+ }, up.id);
+ }
+
+ if (activeClass) {
+ plupload.addEvent(topElement, 'mousedown', function() {
+ plupload.addClass(browseButton, activeClass);
+ }, up.id);
+ plupload.addEvent(document.body, 'mouseup', function() {
+ plupload.removeClass(browseButton, activeClass);
+ }, up.id);
+ }
+
+ // Route click event to the input[type=file] element for supporting browsers
+ if (up.features.triggerDialog) {
+ plupload.addEvent(browseButton, 'click', function(e) {
+ var input = document.getElementById(up.id + '_html5');
+ if (input && !input.disabled) { // for some reason FF (up to 8.0.1 so far) lets to click disabled input[type=file]
+ input.click();
+ }
+ e.preventDefault();
+ }, up.id);
+ }
+ }
+ });
+
+ // Add drop handler
+ uploader.bind("PostInit", function() {
+ var dropElm = document.getElementById(uploader.settings.drop_element);
+
+ if (dropElm) {
+ // Lets fake drag/drop on Safari by moving a input type file in front of the mouse pointer when we drag into the drop zone
+ // TODO: Remove this logic once Safari has official drag/drop support
+ if (fakeSafariDragDrop) {
+ plupload.addEvent(dropElm, 'dragenter', function(e) {
+ var dropInputElm, dropPos, dropSize;
+
+ // Get or create drop zone
+ dropInputElm = document.getElementById(uploader.id + "_drop");
+ if (!dropInputElm) {
+ dropInputElm = document.createElement("input");
+ dropInputElm.setAttribute('type', "file");
+ dropInputElm.setAttribute('id', uploader.id + "_drop");
+ dropInputElm.setAttribute('multiple', 'multiple');
+
+ plupload.addEvent(dropInputElm, 'change', function() {
+ // Add the selected files from file input
+ addSelectedFiles(this.files);
+
+ // Remove input element
+ plupload.removeEvent(dropInputElm, 'change', uploader.id);
+ dropInputElm.parentNode.removeChild(dropInputElm);
+ }, uploader.id);
+
+ // avoid event propagation as Safari cancels the whole capability of dropping files if you are doing a preventDefault of this event on the document body
+ plupload.addEvent(dropInputElm, 'dragover', function(e) {
+ e.stopPropagation();
+ }, uploader.id);
+
+ dropElm.appendChild(dropInputElm);
+ }
+
+ dropPos = plupload.getPos(dropElm, document.getElementById(uploader.settings.container));
+ dropSize = plupload.getSize(dropElm);
+
+ if (plupload.getStyle(dropElm, 'position') === 'static') {
+ plupload.extend(dropElm.style, {
+ position : 'relative'
+ });
+ }
+
+ plupload.extend(dropInputElm.style, {
+ position : 'absolute',
+ display : 'block',
+ top : 0,
+ left : 0,
+ width : dropSize.w + 'px',
+ height : dropSize.h + 'px',
+ opacity : 0
+ });
+ }, uploader.id);
+
+ return;
+ }
+
+ // Block browser default drag over
+ plupload.addEvent(dropElm, 'dragover', function(e) {
+ e.preventDefault();
+ }, uploader.id);
+
+ // Attach drop handler and grab files
+ plupload.addEvent(dropElm, 'drop', function(e) {
+ var dataTransfer = e.dataTransfer;
+
+ // Add dropped files
+ if (dataTransfer && dataTransfer.files) {
+ addSelectedFiles(dataTransfer.files);
+ }
+
+ e.preventDefault();
+ }, uploader.id);
+ }
+ });
+
+ uploader.bind("Refresh", function(up) {
+ var browseButton, browsePos, browseSize, inputContainer, zIndex;
+
+ browseButton = document.getElementById(uploader.settings.browse_button);
+ if (browseButton) {
+ browsePos = plupload.getPos(browseButton, document.getElementById(up.settings.container));
+ browseSize = plupload.getSize(browseButton);
+ inputContainer = document.getElementById(uploader.id + '_html5_container');
+
+ plupload.extend(inputContainer.style, {
+ top : browsePos.y + 'px',
+ left : browsePos.x + 'px',
+ width : browseSize.w + 'px',
+ height : browseSize.h + 'px'
+ });
+
+ // for WebKit place input element underneath the browse button and route onclick event
+ // TODO: revise when browser support for this feature will change
+ if (uploader.features.triggerDialog) {
+ if (plupload.getStyle(browseButton, 'position') === 'static') {
+ plupload.extend(browseButton.style, {
+ position : 'relative'
+ });
+ }
+
+ zIndex = parseInt(plupload.getStyle(browseButton, 'zIndex'), 10);
+ if (isNaN(zIndex)) {
+ zIndex = 0;
+ }
+
+ plupload.extend(browseButton.style, {
+ zIndex : zIndex
+ });
+
+ plupload.extend(inputContainer.style, {
+ zIndex : zIndex - 1
+ });
+ }
+ }
+ });
+
+ uploader.bind("DisableBrowse", function(up, disabled) {
+ var input = document.getElementById(up.id + '_html5');
+ if (input) {
+ input.disabled = disabled;
+ }
+ });
+
+ uploader.bind("CancelUpload", function() {
+ if (xhr && xhr.abort) {
+ xhr.abort();
+ }
+ });
+
+ uploader.bind("UploadFile", function(up, file) {
+ var settings = up.settings, nativeFile, resize;
+
+ function w3cBlobSlice(blob, start, end) {
+ var blobSlice;
+
+ if (File.prototype.slice) {
+ try {
+ blob.slice(); // depricated version will throw WRONG_ARGUMENTS_ERR exception
+ return blob.slice(start, end);
+ } catch (e) {
+ // depricated slice method
+ return blob.slice(start, end - start);
+ }
+ // slice method got prefixed: https://bugzilla.mozilla.org/show_bug.cgi?id=649672
+ } else if (blobSlice = File.prototype.webkitSlice || File.prototype.mozSlice) {
+ return blobSlice.call(blob, start, end);
+ } else {
+ return null; // or throw some exception
+ }
+ }
+
+ function sendBinaryBlob(blob) {
+ var chunk = 0, loaded = 0;
+
+
+ function uploadNextChunk() {
+ var chunkBlob, br, chunks, args, chunkSize, curChunkSize, mimeType, url = up.settings.url;
+
+ function sendAsBinaryString(bin) {
+ if (xhr.sendAsBinary) { // Gecko
+ xhr.sendAsBinary(bin);
+ } else if (up.features.canSendBinary) { // WebKit with typed arrays support
+ var ui8a = new Uint8Array(bin.length);
+ for (var i = 0; i < bin.length; i++) {
+ ui8a[i] = (bin.charCodeAt(i) & 0xff);
+ }
+ xhr.send(ui8a.buffer);
+ }
+ }
+
+ function prepareAndSend(bin) {
+ var multipartDeltaSize = 0,
+ boundary = '----pluploadboundary' + plupload.guid(), formData, dashdash = '--', crlf = '\r\n', multipartBlob = '';
+
+ xhr = new XMLHttpRequest;
+
+ // Do we have upload progress support
+ if (xhr.upload) {
+ xhr.upload.onprogress = function(e) {
+ file.loaded = Math.min(file.size, loaded + e.loaded - multipartDeltaSize); // Loaded can be larger than file size due to multipart encoding
+ up.trigger('UploadProgress', file);
+ };
+ }
+
+ xhr.onreadystatechange = function() {
+ var httpStatus, chunkArgs;
+
+ if (xhr.readyState == 4 && up.state !== plupload.STOPPED) {
+ // Getting the HTTP status might fail on some Gecko versions
+ try {
+ httpStatus = xhr.status;
+ } catch (ex) {
+ httpStatus = 0;
+ }
+
+ // Is error status
+ if (httpStatus >= 400) {
+ up.trigger('Error', {
+ code : plupload.HTTP_ERROR,
+ message : plupload.translate('HTTP Error.'),
+ file : file,
+ status : httpStatus
+ });
+ } else {
+ // Handle chunk response
+ if (chunks) {
+ chunkArgs = {
+ chunk : chunk,
+ chunks : chunks,
+ response : xhr.responseText,
+ status : httpStatus
+ };
+
+ up.trigger('ChunkUploaded', file, chunkArgs);
+ loaded += curChunkSize;
+
+ // Stop upload
+ if (chunkArgs.cancelled) {
+ file.status = plupload.FAILED;
+ return;
+ }
+
+ file.loaded = Math.min(file.size, (chunk + 1) * chunkSize);
+ } else {
+ file.loaded = file.size;
+ }
+
+ up.trigger('UploadProgress', file);
+
+ bin = chunkBlob = formData = multipartBlob = null; // Free memory
+
+ // Check if file is uploaded
+ if (!chunks || ++chunk >= chunks) {
+ file.status = plupload.DONE;
+
+ up.trigger('FileUploaded', file, {
+ response : xhr.responseText,
+ status : httpStatus
+ });
+ } else {
+ // Still chunks left
+ uploadNextChunk();
+ }
+ }
+ }
+ };
+
+
+ // Build multipart request
+ if (up.settings.multipart && features.multipart) {
+
+ args.name = file.target_name || file.name;
+
+ xhr.open("post", url, true);
+
+ // Set custom headers
+ plupload.each(up.settings.headers, function(value, name) {
+ xhr.setRequestHeader(name, value);
+ });
+
+
+ // if has FormData support like Chrome 6+, Safari 5+, Firefox 4, use it
+ if (typeof(bin) !== 'string' && !!window.FormData) {
+ formData = new FormData();
+
+ // Add multipart params
+ plupload.each(plupload.extend(args, up.settings.multipart_params), function(value, name) {
+ formData.append(name, value);
+ });
+
+ // Add file and send it
+ formData.append(up.settings.file_data_name, bin);
+ xhr.send(formData);
+
+ return;
+ } // if no FormData we can still try to send it directly as last resort (see below)
+
+
+ if (typeof(bin) === 'string') {
+ // Trying to send the whole thing as binary...
+
+ // multipart request
+ xhr.setRequestHeader('Content-Type', 'multipart/form-data; boundary=' + boundary);
+
+ // append multipart parameters
+ plupload.each(plupload.extend(args, up.settings.multipart_params), function(value, name) {
+ multipartBlob += dashdash + boundary + crlf +
+ 'Content-Disposition: form-data; name="' + name + '"' + crlf + crlf;
+
+ multipartBlob += unescape(encodeURIComponent(value)) + crlf;
+ });
+
+ mimeType = plupload.mimeTypes[file.name.replace(/^.+\.([^.]+)/, '$1').toLowerCase()] || 'application/octet-stream';
+
+ // Build RFC2388 blob
+ multipartBlob += dashdash + boundary + crlf +
+ 'Content-Disposition: form-data; name="' + up.settings.file_data_name + '"; filename="' + unescape(encodeURIComponent(file.name)) + '"' + crlf +
+ 'Content-Type: ' + mimeType + crlf + crlf +
+ bin + crlf +
+ dashdash + boundary + dashdash + crlf;
+
+ multipartDeltaSize = multipartBlob.length - bin.length;
+ bin = multipartBlob;
+
+ sendAsBinaryString(bin);
+ return; // will return from here only if shouldn't send binary
+ }
+ }
+
+ // if no multipart, or last resort, send as binary stream
+ url = plupload.buildUrl(up.settings.url, plupload.extend(args, up.settings.multipart_params));
+
+ xhr.open("post", url, true);
+
+ xhr.setRequestHeader('Content-Type', 'application/octet-stream'); // Binary stream header
+
+ // Set custom headers
+ plupload.each(up.settings.headers, function(value, name) {
+ xhr.setRequestHeader(name, value);
+ });
+
+ if (typeof(bin) === 'string') {
+ sendAsBinaryString(bin);
+ } else {
+ xhr.send(bin);
+ }
+ } // prepareAndSend
+
+
+ // File upload finished
+ if (file.status == plupload.DONE || file.status == plupload.FAILED || up.state == plupload.STOPPED) {
+ return;
+ }
+
+ // Standard arguments
+ args = {name : file.target_name || file.name};
+
+ // Only add chunking args if needed
+ if (settings.chunk_size && file.size > settings.chunk_size && (features.chunks || typeof(blob) == 'string')) { // blob will be of type string if it was loaded in memory
+ chunkSize = settings.chunk_size;
+ chunks = Math.ceil(file.size / chunkSize);
+ curChunkSize = Math.min(chunkSize, file.size - (chunk * chunkSize));
+
+ // Blob is string so we need to fake chunking, this is not
+ // ideal since the whole file is loaded into memory
+ if (typeof(blob) == 'string') {
+ chunkBlob = blob.substring(chunk * chunkSize, chunk * chunkSize + curChunkSize);
+ } else {
+ // Slice the chunk
+ chunkBlob = w3cBlobSlice(blob, chunk * chunkSize, chunk * chunkSize + curChunkSize);
+ }
+
+ // Setup query string arguments
+ args.chunk = chunk;
+ args.chunks = chunks;
+ } else {
+ curChunkSize = file.size;
+ chunkBlob = blob;
+ }
+
+ // workaround for Android and Gecko 2,5,6 FormData+Blob bug: https://bugzilla.mozilla.org/show_bug.cgi?id=649150
+ if (up.settings.multipart && features.multipart && typeof(chunkBlob) !== 'string' && window.FileReader && features.cantSendBlobInFormData && features.chunks && up.settings.chunk_size) { // Gecko 2,5,6
+ (function() {
+ var fr = new FileReader(); // we need to recreate FileReader object in Android, otherwise it hangs
+ fr.onload = function() {
+ prepareAndSend(fr.result);
+ fr = null; // maybe give a hand to GC (Gecko had problems with this)
+ }
+ fr.readAsBinaryString(chunkBlob);
+ }());
+ } else {
+ prepareAndSend(chunkBlob);
+ }
+ }
+
+ // Start uploading chunks
+ uploadNextChunk();
+ }
+
+ nativeFile = html5files[file.id];
+
+ // Resize image if it's a supported format and resize is enabled
+ if (features.jpgresize && up.settings.resize && /\.(png|jpg|jpeg)$/i.test(file.name)) {
+ scaleImage.call(up, file, up.settings.resize, /\.png$/i.test(file.name) ? 'image/png' : 'image/jpeg', function(res) {
+ // If it was scaled send the scaled image if it failed then
+ // send the raw image and let the server do the scaling
+ if (res.success) {
+ file.size = res.data.length;
+ sendBinaryBlob(res.data);
+ } else if (features.chunks) {
+ sendBinaryBlob(nativeFile);
+ } else {
+ readFileAsBinary(nativeFile, sendBinaryBlob); // for browsers not supporting File.slice (e.g. FF3.6)
+ }
+ });
+ // if there's no way to slice file without preloading it in memory, preload it
+ } else if (!features.chunks && features.jpgresize) {
+ readFileAsBinary(nativeFile, sendBinaryBlob);
+ } else {
+ sendBinaryBlob(nativeFile);
+ }
+ });
+
+
+ uploader.bind('Destroy', function(up) {
+ var name, element, container = document.body,
+ elements = {
+ inputContainer: up.id + '_html5_container',
+ inputFile: up.id + '_html5',
+ browseButton: up.settings.browse_button,
+ dropElm: up.settings.drop_element
+ };
+
+ // Unbind event handlers
+ for (name in elements) {
+ element = document.getElementById(elements[name]);
+ if (element) {
+ plupload.removeAllEvents(element, up.id);
+ }
+ }
+ plupload.removeAllEvents(document.body, up.id);
+
+ if (up.settings.container) {
+ container = document.getElementById(up.settings.container);
+ }
+
+ // Remove mark-up
+ container.removeChild(document.getElementById(elements.inputContainer));
+ });
+
+ callback({success : true});
+ }
+ });
+
+ function BinaryReader() {
+ var II = false, bin;
+
+ // Private functions
+ function read(idx, size) {
+ var mv = II ? 0 : -8 * (size - 1), sum = 0, i;
+
+ for (i = 0; i < size; i++) {
+ sum |= (bin.charCodeAt(idx + i) << Math.abs(mv + i*8));
+ }
+
+ return sum;
+ }
+
+ function putstr(segment, idx, length) {
+ var length = arguments.length === 3 ? length : bin.length - idx - 1;
+
+ bin = bin.substr(0, idx) + segment + bin.substr(length + idx);
+ }
+
+ function write(idx, num, size) {
+ var str = '', mv = II ? 0 : -8 * (size - 1), i;
+
+ for (i = 0; i < size; i++) {
+ str += String.fromCharCode((num >> Math.abs(mv + i*8)) & 255);
+ }
+
+ putstr(str, idx, size);
+ }
+
+ // Public functions
+ return {
+ II: function(order) {
+ if (order === undef) {
+ return II;
+ } else {
+ II = order;
+ }
+ },
+
+ init: function(binData) {
+ II = false;
+ bin = binData;
+ },
+
+ SEGMENT: function(idx, length, segment) {
+ switch (arguments.length) {
+ case 1:
+ return bin.substr(idx, bin.length - idx - 1);
+ case 2:
+ return bin.substr(idx, length);
+ case 3:
+ putstr(segment, idx, length);
+ break;
+ default: return bin;
+ }
+ },
+
+ BYTE: function(idx) {
+ return read(idx, 1);
+ },
+
+ SHORT: function(idx) {
+ return read(idx, 2);
+ },
+
+ LONG: function(idx, num) {
+ if (num === undef) {
+ return read(idx, 4);
+ } else {
+ write(idx, num, 4);
+ }
+ },
+
+ SLONG: function(idx) { // 2's complement notation
+ var num = read(idx, 4);
+
+ return (num > 2147483647 ? num - 4294967296 : num);
+ },
+
+ STRING: function(idx, size) {
+ var str = '';
+
+ for (size += idx; idx < size; idx++) {
+ str += String.fromCharCode(read(idx, 1));
+ }
+
+ return str;
+ }
+ };
+ }
+
+ function JPEG_Headers(data) {
+
+ var markers = {
+ 0xFFE1: {
+ app: 'EXIF',
+ name: 'APP1',
+ signature: "Exif\0"
+ },
+ 0xFFE2: {
+ app: 'ICC',
+ name: 'APP2',
+ signature: "ICC_PROFILE\0"
+ },
+ 0xFFED: {
+ app: 'IPTC',
+ name: 'APP13',
+ signature: "Photoshop 3.0\0"
+ }
+ },
+ headers = [], read, idx, marker = undef, length = 0, limit;
+
+
+ read = new BinaryReader();
+ read.init(data);
+
+ // Check if data is jpeg
+ if (read.SHORT(0) !== 0xFFD8) {
+ return;
+ }
+
+ idx = 2;
+ limit = Math.min(1048576, data.length);
+
+ while (idx <= limit) {
+ marker = read.SHORT(idx);
+
+ // omit RST (restart) markers
+ if (marker >= 0xFFD0 && marker <= 0xFFD7) {
+ idx += 2;
+ continue;
+ }
+
+ // no headers allowed after SOS marker
+ if (marker === 0xFFDA || marker === 0xFFD9) {
+ break;
+ }
+
+ length = read.SHORT(idx + 2) + 2;
+
+ if (markers[marker] &&
+ read.STRING(idx + 4, markers[marker].signature.length) === markers[marker].signature) {
+ headers.push({
+ hex: marker,
+ app: markers[marker].app.toUpperCase(),
+ name: markers[marker].name.toUpperCase(),
+ start: idx,
+ length: length,
+ segment: read.SEGMENT(idx, length)
+ });
+ }
+ idx += length;
+ }
+
+ read.init(null); // free memory
+
+ return {
+
+ headers: headers,
+
+ restore: function(data) {
+ read.init(data);
+
+ // Check if data is jpeg
+ var jpegHeaders = new JPEG_Headers(data);
+
+ if (!jpegHeaders['headers']) {
+ return false;
+ }
+
+ // Delete any existing headers that need to be replaced
+ for (var i = jpegHeaders['headers'].length; i > 0; i--) {
+ var hdr = jpegHeaders['headers'][i - 1];
+ read.SEGMENT(hdr.start, hdr.length, '')
+ }
+ jpegHeaders.purge();
+
+ idx = read.SHORT(2) == 0xFFE0 ? 4 + read.SHORT(4) : 2;
+
+ for (var i = 0, max = headers.length; i < max; i++) {
+ read.SEGMENT(idx, 0, headers[i].segment);
+ idx += headers[i].length;
+ }
+
+ return read.SEGMENT();
+ },
+
+ get: function(app) {
+ var array = [];
+
+ for (var i = 0, max = headers.length; i < max; i++) {
+ if (headers[i].app === app.toUpperCase()) {
+ array.push(headers[i].segment);
+ }
+ }
+ return array;
+ },
+
+ set: function(app, segment) {
+ var array = [];
+
+ if (typeof(segment) === 'string') {
+ array.push(segment);
+ } else {
+ array = segment;
+ }
+
+ for (var i = ii = 0, max = headers.length; i < max; i++) {
+ if (headers[i].app === app.toUpperCase()) {
+ headers[i].segment = array[ii];
+ headers[i].length = array[ii].length;
+ ii++;
+ }
+ if (ii >= array.length) break;
+ }
+ },
+
+ purge: function() {
+ headers = [];
+ read.init(null);
+ }
+ };
+ }
+
+
+ function ExifParser() {
+ // Private ExifParser fields
+ var data, tags, offsets = {}, tagDescs;
+
+ data = new BinaryReader();
+
+ tags = {
+ tiff : {
+ /*
+ The image orientation viewed in terms of rows and columns.
+
+ 1 - The 0th row is at the visual top of the image, and the 0th column is the visual left-hand side.
+ 2 - The 0th row is at the visual top of the image, and the 0th column is the visual left-hand side.
+ 3 - The 0th row is at the visual top of the image, and the 0th column is the visual right-hand side.
+ 4 - The 0th row is at the visual bottom of the image, and the 0th column is the visual right-hand side.
+ 5 - The 0th row is at the visual bottom of the image, and the 0th column is the visual left-hand side.
+ 6 - The 0th row is the visual left-hand side of the image, and the 0th column is the visual top.
+ 7 - The 0th row is the visual right-hand side of the image, and the 0th column is the visual top.
+ 8 - The 0th row is the visual right-hand side of the image, and the 0th column is the visual bottom.
+ 9 - The 0th row is the visual left-hand side of the image, and the 0th column is the visual bottom.
+ */
+ 0x0112: 'Orientation',
+ 0x8769: 'ExifIFDPointer',
+ 0x8825: 'GPSInfoIFDPointer'
+ },
+ exif : {
+ 0x9000: 'ExifVersion',
+ 0xA001: 'ColorSpace',
+ 0xA002: 'PixelXDimension',
+ 0xA003: 'PixelYDimension',
+ 0x9003: 'DateTimeOriginal',
+ 0x829A: 'ExposureTime',
+ 0x829D: 'FNumber',
+ 0x8827: 'ISOSpeedRatings',
+ 0x9201: 'ShutterSpeedValue',
+ 0x9202: 'ApertureValue' ,
+ 0x9207: 'MeteringMode',
+ 0x9208: 'LightSource',
+ 0x9209: 'Flash',
+ 0xA402: 'ExposureMode',
+ 0xA403: 'WhiteBalance',
+ 0xA406: 'SceneCaptureType',
+ 0xA404: 'DigitalZoomRatio',
+ 0xA408: 'Contrast',
+ 0xA409: 'Saturation',
+ 0xA40A: 'Sharpness'
+ },
+ gps : {
+ 0x0000: 'GPSVersionID',
+ 0x0001: 'GPSLatitudeRef',
+ 0x0002: 'GPSLatitude',
+ 0x0003: 'GPSLongitudeRef',
+ 0x0004: 'GPSLongitude'
+ }
+ };
+
+ tagDescs = {
+ 'ColorSpace': {
+ 1: 'sRGB',
+ 0: 'Uncalibrated'
+ },
+
+ 'MeteringMode': {
+ 0: 'Unknown',
+ 1: 'Average',
+ 2: 'CenterWeightedAverage',
+ 3: 'Spot',
+ 4: 'MultiSpot',
+ 5: 'Pattern',
+ 6: 'Partial',
+ 255: 'Other'
+ },
+
+ 'LightSource': {
+ 1: 'Daylight',
+ 2: 'Fliorescent',
+ 3: 'Tungsten',
+ 4: 'Flash',
+ 9: 'Fine weather',
+ 10: 'Cloudy weather',
+ 11: 'Shade',
+ 12: 'Daylight fluorescent (D 5700 - 7100K)',
+ 13: 'Day white fluorescent (N 4600 -5400K)',
+ 14: 'Cool white fluorescent (W 3900 - 4500K)',
+ 15: 'White fluorescent (WW 3200 - 3700K)',
+ 17: 'Standard light A',
+ 18: 'Standard light B',
+ 19: 'Standard light C',
+ 20: 'D55',
+ 21: 'D65',
+ 22: 'D75',
+ 23: 'D50',
+ 24: 'ISO studio tungsten',
+ 255: 'Other'
+ },
+
+ 'Flash': {
+ 0x0000: 'Flash did not fire.',
+ 0x0001: 'Flash fired.',
+ 0x0005: 'Strobe return light not detected.',
+ 0x0007: 'Strobe return light detected.',
+ 0x0009: 'Flash fired, compulsory flash mode',
+ 0x000D: 'Flash fired, compulsory flash mode, return light not detected',
+ 0x000F: 'Flash fired, compulsory flash mode, return light detected',
+ 0x0010: 'Flash did not fire, compulsory flash mode',
+ 0x0018: 'Flash did not fire, auto mode',
+ 0x0019: 'Flash fired, auto mode',
+ 0x001D: 'Flash fired, auto mode, return light not detected',
+ 0x001F: 'Flash fired, auto mode, return light detected',
+ 0x0020: 'No flash function',
+ 0x0041: 'Flash fired, red-eye reduction mode',
+ 0x0045: 'Flash fired, red-eye reduction mode, return light not detected',
+ 0x0047: 'Flash fired, red-eye reduction mode, return light detected',
+ 0x0049: 'Flash fired, compulsory flash mode, red-eye reduction mode',
+ 0x004D: 'Flash fired, compulsory flash mode, red-eye reduction mode, return light not detected',
+ 0x004F: 'Flash fired, compulsory flash mode, red-eye reduction mode, return light detected',
+ 0x0059: 'Flash fired, auto mode, red-eye reduction mode',
+ 0x005D: 'Flash fired, auto mode, return light not detected, red-eye reduction mode',
+ 0x005F: 'Flash fired, auto mode, return light detected, red-eye reduction mode'
+ },
+
+ 'ExposureMode': {
+ 0: 'Auto exposure',
+ 1: 'Manual exposure',
+ 2: 'Auto bracket'
+ },
+
+ 'WhiteBalance': {
+ 0: 'Auto white balance',
+ 1: 'Manual white balance'
+ },
+
+ 'SceneCaptureType': {
+ 0: 'Standard',
+ 1: 'Landscape',
+ 2: 'Portrait',
+ 3: 'Night scene'
+ },
+
+ 'Contrast': {
+ 0: 'Normal',
+ 1: 'Soft',
+ 2: 'Hard'
+ },
+
+ 'Saturation': {
+ 0: 'Normal',
+ 1: 'Low saturation',
+ 2: 'High saturation'
+ },
+
+ 'Sharpness': {
+ 0: 'Normal',
+ 1: 'Soft',
+ 2: 'Hard'
+ },
+
+ // GPS related
+ 'GPSLatitudeRef': {
+ N: 'North latitude',
+ S: 'South latitude'
+ },
+
+ 'GPSLongitudeRef': {
+ E: 'East longitude',
+ W: 'West longitude'
+ }
+ };
+
+ function extractTags(IFD_offset, tags2extract) {
+ var length = data.SHORT(IFD_offset), i, ii,
+ tag, type, count, tagOffset, offset, value, values = [], hash = {};
+
+ for (i = 0; i < length; i++) {
+ // Set binary reader pointer to beginning of the next tag
+ offset = tagOffset = IFD_offset + 12 * i + 2;
+
+ tag = tags2extract[data.SHORT(offset)];
+
+ if (tag === undef) {
+ continue; // Not the tag we requested
+ }
+
+ type = data.SHORT(offset+=2);
+ count = data.LONG(offset+=2);
+
+ offset += 4;
+ values = [];
+
+ switch (type) {
+ case 1: // BYTE
+ case 7: // UNDEFINED
+ if (count > 4) {
+ offset = data.LONG(offset) + offsets.tiffHeader;
+ }
+
+ for (ii = 0; ii < count; ii++) {
+ values[ii] = data.BYTE(offset + ii);
+ }
+
+ break;
+
+ case 2: // STRING
+ if (count > 4) {
+ offset = data.LONG(offset) + offsets.tiffHeader;
+ }
+
+ hash[tag] = data.STRING(offset, count - 1);
+
+ continue;
+
+ case 3: // SHORT
+ if (count > 2) {
+ offset = data.LONG(offset) + offsets.tiffHeader;
+ }
+
+ for (ii = 0; ii < count; ii++) {
+ values[ii] = data.SHORT(offset + ii*2);
+ }
+
+ break;
+
+ case 4: // LONG
+ if (count > 1) {
+ offset = data.LONG(offset) + offsets.tiffHeader;
+ }
+
+ for (ii = 0; ii < count; ii++) {
+ values[ii] = data.LONG(offset + ii*4);
+ }
+
+ break;
+
+ case 5: // RATIONAL
+ offset = data.LONG(offset) + offsets.tiffHeader;
+
+ for (ii = 0; ii < count; ii++) {
+ values[ii] = data.LONG(offset + ii*4) / data.LONG(offset + ii*4 + 4);
+ }
+
+ break;
+
+ case 9: // SLONG
+ offset = data.LONG(offset) + offsets.tiffHeader;
+
+ for (ii = 0; ii < count; ii++) {
+ values[ii] = data.SLONG(offset + ii*4);
+ }
+
+ break;
+
+ case 10: // SRATIONAL
+ offset = data.LONG(offset) + offsets.tiffHeader;
+
+ for (ii = 0; ii < count; ii++) {
+ values[ii] = data.SLONG(offset + ii*4) / data.SLONG(offset + ii*4 + 4);
+ }
+
+ break;
+
+ default:
+ continue;
+ }
+
+ value = (count == 1 ? values[0] : values);
+
+ if (tagDescs.hasOwnProperty(tag) && typeof value != 'object') {
+ hash[tag] = tagDescs[tag][value];
+ } else {
+ hash[tag] = value;
+ }
+ }
+
+ return hash;
+ }
+
+ function getIFDOffsets() {
+ var Tiff = undef, idx = offsets.tiffHeader;
+
+ // Set read order of multi-byte data
+ data.II(data.SHORT(idx) == 0x4949);
+
+ // Check if always present bytes are indeed present
+ if (data.SHORT(idx+=2) !== 0x002A) {
+ return false;
+ }
+
+ offsets['IFD0'] = offsets.tiffHeader + data.LONG(idx += 2);
+ Tiff = extractTags(offsets['IFD0'], tags.tiff);
+
+ offsets['exifIFD'] = ('ExifIFDPointer' in Tiff ? offsets.tiffHeader + Tiff.ExifIFDPointer : undef);
+ offsets['gpsIFD'] = ('GPSInfoIFDPointer' in Tiff ? offsets.tiffHeader + Tiff.GPSInfoIFDPointer : undef);
+
+ return true;
+ }
+
+ // At the moment only setting of simple (LONG) values, that do not require offset recalculation, is supported
+ function setTag(ifd, tag, value) {
+ var offset, length, tagOffset, valueOffset = 0;
+
+ // If tag name passed translate into hex key
+ if (typeof(tag) === 'string') {
+ var tmpTags = tags[ifd.toLowerCase()];
+ for (hex in tmpTags) {
+ if (tmpTags[hex] === tag) {
+ tag = hex;
+ break;
+ }
+ }
+ }
+ offset = offsets[ifd.toLowerCase() + 'IFD'];
+ length = data.SHORT(offset);
+
+ for (i = 0; i < length; i++) {
+ tagOffset = offset + 12 * i + 2;
+
+ if (data.SHORT(tagOffset) == tag) {
+ valueOffset = tagOffset + 8;
+ break;
+ }
+ }
+
+ if (!valueOffset) return false;
+
+
+ data.LONG(valueOffset, value);
+ return true;
+ }
+
+
+ // Public functions
+ return {
+ init: function(segment) {
+ // Reset internal data
+ offsets = {
+ tiffHeader: 10
+ };
+
+ if (segment === undef || !segment.length) {
+ return false;
+ }
+
+ data.init(segment);
+
+ // Check if that's APP1 and that it has EXIF
+ if (data.SHORT(0) === 0xFFE1 && data.STRING(4, 5).toUpperCase() === "EXIF\0") {
+ return getIFDOffsets();
+ }
+ return false;
+ },
+
+ EXIF: function() {
+ var Exif;
+
+ // Populate EXIF hash
+ Exif = extractTags(offsets.exifIFD, tags.exif);
+
+ // Fix formatting of some tags
+ if (Exif.ExifVersion && plupload.typeOf(Exif.ExifVersion) === 'array') {
+ for (var i = 0, exifVersion = ''; i < Exif.ExifVersion.length; i++) {
+ exifVersion += String.fromCharCode(Exif.ExifVersion[i]);
+ }
+ Exif.ExifVersion = exifVersion;
+ }
+
+ return Exif;
+ },
+
+ GPS: function() {
+ var GPS;
+
+ GPS = extractTags(offsets.gpsIFD, tags.gps);
+
+ // iOS devices (and probably some others) do not put in GPSVersionID tag (why?..)
+ if (GPS.GPSVersionID) {
+ GPS.GPSVersionID = GPS.GPSVersionID.join('.');
+ }
+
+ return GPS;
+ },
+
+ setExif: function(tag, value) {
+ // Right now only setting of width/height is possible
+ if (tag !== 'PixelXDimension' && tag !== 'PixelYDimension') return false;
+
+ return setTag('exif', tag, value);
+ },
+
+
+ getBinary: function() {
+ return data.SEGMENT();
+ }
+ };
+ };
+})(window, document, plupload);
diff --git a/debian/missing-sources/plupload/javascript/plupload.js b/debian/missing-sources/plupload/javascript/plupload.js
new file mode 100644
index 0000000..94156df
--- /dev/null
+++ b/debian/missing-sources/plupload/javascript/plupload.js
@@ -0,0 +1,1774 @@
+/**
+ * plupload.js
+ *
+ * Copyright 2009, Moxiecode Systems AB
+ * Released under GPL License.
+ *
+ * License: http://www.plupload.com/license
+ * Contributing: http://www.plupload.com/contributing
+ */
+
+// JSLint defined globals
+/*global window:false, escape:false */
+
+/*!@@version@@*/
+
+(function() {
+ var count = 0, runtimes = [], i18n = {}, mimes = {},
+ xmlEncodeChars = {'<' : 'lt', '>' : 'gt', '&' : 'amp', '"' : 'quot', '\'' : '#39'},
+ xmlEncodeRegExp = /[<>&\"\']/g, undef, delay = window.setTimeout,
+ // A place to store references to event handlers
+ eventhash = {},
+ uid;
+
+ // IE W3C like event funcs
+ function preventDefault() {
+ this.returnValue = false;
+ }
+
+ function stopPropagation() {
+ this.cancelBubble = true;
+ }
+
+ // Parses the default mime types string into a mimes lookup map
+ (function(mime_data) {
+ var items = mime_data.split(/,/), i, y, ext;
+
+ for (i = 0; i < items.length; i += 2) {
+ ext = items[i + 1].split(/ /);
+
+ for (y = 0; y < ext.length; y++) {
+ mimes[ext[y]] = items[i];
+ }
+ }
+ })(
+ "application/msword,doc dot," +
+ "application/pdf,pdf," +
+ "application/pgp-signature,pgp," +
+ "application/postscript,ps ai eps," +
+ "application/rtf,rtf," +
+ "application/vnd.ms-excel,xls xlb," +
+ "application/vnd.ms-powerpoint,ppt pps pot," +
+ "application/zip,zip," +
+ "application/x-shockwave-flash,swf swfl," +
+ "application/vnd.openxmlformats-officedocument.wordprocessingml.document,docx," +
+ "application/vnd.openxmlformats-officedocument.wordprocessingml.template,dotx," +
+ "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet,xlsx," +
+ "application/vnd.openxmlformats-officedocument.presentationml.presentation,pptx," +
+ "application/vnd.openxmlformats-officedocument.presentationml.template,potx," +
+ "application/vnd.openxmlformats-officedocument.presentationml.slideshow,ppsx," +
+ "application/x-javascript,js," +
+ "application/json,json," +
+ "audio/mpeg,mpga mpega mp2 mp3," +
+ "audio/x-wav,wav," +
+ "audio/mp4,m4a," +
+ "image/bmp,bmp," +
+ "image/gif,gif," +
+ "image/jpeg,jpeg jpg jpe," +
+ "image/photoshop,psd," +
+ "image/png,png," +
+ "image/svg+xml,svg svgz," +
+ "image/tiff,tiff tif," +
+ "text/plain,asc txt text diff log," +
+ "text/html,htm html xhtml," +
+ "text/css,css," +
+ "text/csv,csv," +
+ "text/rtf,rtf," +
+ "video/mpeg,mpeg mpg mpe m2v," +
+ "video/quicktime,qt mov," +
+ "video/mp4,mp4," +
+ "video/x-m4v,m4v," +
+ "video/x-flv,flv," +
+ "video/x-ms-wmv,wmv," +
+ "video/avi,avi," +
+ "video/webm,webm," +
+ "video/3gpp,3gp," +
+ "video/3gpp2,3g2," +
+ "video/vnd.rn-realvideo,rv," +
+ "application/vnd.oasis.opendocument.formula-template,otf," +
+ "application/octet-stream,exe"
+ );
+
+ /**
+ * Plupload class with some global constants and functions.
+ *
+ * @example
+ * // Encode entities
+ * console.log(plupload.xmlEncode("My string &lt;&gt;"));
+ *
+ * // Generate unique id
+ * console.log(plupload.guid());
+ *
+ * @static
+ * @class plupload
+ */
+ var plupload = {
+ /**
+ * Plupload version will be replaced on build.
+ */
+ VERSION : '@@version@@',
+
+ /**
+ * Inital state of the queue and also the state ones it's finished all it's uploads.
+ *
+ * @property STOPPED
+ * @final
+ */
+ STOPPED : 1,
+
+ /**
+ * Upload process is running
+ *
+ * @property STARTED
+ * @final
+ */
+ STARTED : 2,
+
+ /**
+ * File is queued for upload
+ *
+ * @property QUEUED
+ * @final
+ */
+ QUEUED : 1,
+
+ /**
+ * File is being uploaded
+ *
+ * @property UPLOADING
+ * @final
+ */
+ UPLOADING : 2,
+
+ /**
+ * File has failed to be uploaded
+ *
+ * @property FAILED
+ * @final
+ */
+ FAILED : 4,
+
+ /**
+ * File has been uploaded successfully
+ *
+ * @property DONE
+ * @final
+ */
+ DONE : 5,
+
+ // Error constants used by the Error event
+
+ /**
+ * Generic error for example if an exception is thrown inside Silverlight.
+ *
+ * @property GENERIC_ERROR
+ * @final
+ */
+ GENERIC_ERROR : -100,
+
+ /**
+ * HTTP transport error. For example if the server produces a HTTP status other than 200.
+ *
+ * @property HTTP_ERROR
+ * @final
+ */
+ HTTP_ERROR : -200,
+
+ /**
+ * Generic I/O error. For exampe if it wasn't possible to open the file stream on local machine.
+ *
+ * @property IO_ERROR
+ * @final
+ */
+ IO_ERROR : -300,
+
+ /**
+ * Generic I/O error. For exampe if it wasn't possible to open the file stream on local machine.
+ *
+ * @property SECURITY_ERROR
+ * @final
+ */
+ SECURITY_ERROR : -400,
+
+ /**
+ * Initialization error. Will be triggered if no runtime was initialized.
+ *
+ * @property INIT_ERROR
+ * @final
+ */
+ INIT_ERROR : -500,
+
+ /**
+ * File size error. If the user selects a file that is too large it will be blocked and an error of this type will be triggered.
+ *
+ * @property FILE_SIZE_ERROR
+ * @final
+ */
+ FILE_SIZE_ERROR : -600,
+
+ /**
+ * File extension error. If the user selects a file that isn't valid according to the filters setting.
+ *
+ * @property FILE_EXTENSION_ERROR
+ * @final
+ */
+ FILE_EXTENSION_ERROR : -601,
+
+ /**
+ * Runtime will try to detect if image is proper one. Otherwise will throw this error.
+ *
+ * @property IMAGE_FORMAT_ERROR
+ * @final
+ */
+ IMAGE_FORMAT_ERROR : -700,
+
+ /**
+ * While working on the image runtime will try to detect if the operation may potentially run out of memeory and will throw this error.
+ *
+ * @property IMAGE_MEMORY_ERROR
+ * @final
+ */
+ IMAGE_MEMORY_ERROR : -701,
+
+ /**
+ * Each runtime has an upper limit on a dimension of the image it can handle. If bigger, will throw this error.
+ *
+ * @property IMAGE_DIMENSIONS_ERROR
+ * @final
+ */
+ IMAGE_DIMENSIONS_ERROR : -702,
+
+
+ /**
+ * Mime type lookup table.
+ *
+ * @property mimeTypes
+ * @type Object
+ * @final
+ */
+ mimeTypes : mimes,
+
+ /**
+ * In some cases sniffing is the only way around :(
+ */
+ ua: (function() {
+ var nav = navigator, userAgent = nav.userAgent, vendor = nav.vendor, webkit, opera, safari;
+
+ webkit = /WebKit/.test(userAgent);
+ safari = webkit && vendor.indexOf('Apple') !== -1;
+ opera = window.opera && window.opera.buildNumber;
+
+ return {
+ windows: navigator.platform.indexOf('Win') !== -1,
+ android: /Android/.test(userAgent),
+ ie: !webkit && !opera && (/MSIE/gi).test(userAgent) && (/Explorer/gi).test(nav.appName),
+ webkit: webkit,
+ gecko: !webkit && /Gecko/.test(userAgent),
+ safari: safari,
+ opera: !!opera
+ };
+ }()),
+
+ /**
+ * Gets the true type of the built-in object (better version of typeof).
+ * @credits Angus Croll (http://javascriptweblog.wordpress.com/)
+ *
+ * @param {Object} o Object to check.
+ * @return {String} Object [[Class]]
+ */
+ typeOf: function(o) {
+ return ({}).toString.call(o).match(/\s([a-z|A-Z]+)/)[1].toLowerCase();
+ },
+
+ /**
+ * Extends the specified object with another object.
+ *
+ * @method extend
+ * @param {Object} target Object to extend.
+ * @param {Object..} obj Multiple objects to extend with.
+ * @return {Object} Same as target, the extended object.
+ */
+ extend : function(target) {
+ plupload.each(arguments, function(arg, i) {
+ if (i > 0) {
+ plupload.each(arg, function(value, key) {
+ target[key] = value;
+ });
+ }
+ });
+
+ return target;
+ },
+
+ /**
+ * Cleans the specified name from national characters (diacritics). The result will be a name with only a-z, 0-9 and _.
+ *
+ * @method cleanName
+ * @param {String} s String to clean up.
+ * @return {String} Cleaned string.
+ */
+ cleanName : function(name) {
+ var i, lookup;
+
+ // Replace diacritics
+ lookup = [
+ /[\300-\306]/g, 'A', /[\340-\346]/g, 'a',
+ /\307/g, 'C', /\347/g, 'c',
+ /[\310-\313]/g, 'E', /[\350-\353]/g, 'e',
+ /[\314-\317]/g, 'I', /[\354-\357]/g, 'i',
+ /\321/g, 'N', /\361/g, 'n',
+ /[\322-\330]/g, 'O', /[\362-\370]/g, 'o',
+ /[\331-\334]/g, 'U', /[\371-\374]/g, 'u'
+ ];
+
+ for (i = 0; i < lookup.length; i += 2) {
+ name = name.replace(lookup[i], lookup[i + 1]);
+ }
+
+ // Replace whitespace
+ name = name.replace(/\s+/g, '_');
+
+ // Remove anything else
+ name = name.replace(/[^a-z0-9_\-\.]+/gi, '');
+
+ return name;
+ },
+
+ /**
+ * Adds a specific upload runtime like for example flash or gears.
+ *
+ * @method addRuntime
+ * @param {String} name Runtime name for example flash.
+ * @param {Object} obj Object containing init/destroy method.
+ */
+ addRuntime : function(name, runtime) {
+ runtime.name = name;
+ runtimes[name] = runtime;
+ runtimes.push(runtime);
+
+ return runtime;
+ },
+
+ /**
+ * Generates an unique ID. This is 99.99% unique since it takes the current time and 5 random numbers.
+ * The only way a user would be able to get the same ID is if the two persons at the same exact milisecond manages
+ * to get 5 the same random numbers between 0-65535 it also uses a counter so each call will be guaranteed to be page unique.
+ * It's more probable for the earth to be hit with an ansteriod. You can also if you want to be 100% sure set the plupload.guidPrefix property
+ * to an user unique key.
+ *
+ * @method guid
+ * @return {String} Virtually unique id.
+ */
+ guid : function() {
+ var guid = new Date().getTime().toString(32), i;
+
+ for (i = 0; i < 5; i++) {
+ guid += Math.floor(Math.random() * 65535).toString(32);
+ }
+
+ return (plupload.guidPrefix || 'p') + guid + (count++).toString(32);
+ },
+
+ /**
+ * Builds a full url out of a base URL and an object with items to append as query string items.
+ *
+ * @param {String} url Base URL to append query string items to.
+ * @param {Object} items Name/value object to serialize as a querystring.
+ * @return {String} String with url + serialized query string items.
+ */
+ buildUrl : function(url, items) {
+ var query = '';
+
+ plupload.each(items, function(value, name) {
+ query += (query ? '&' : '') + encodeURIComponent(name) + '=' + encodeURIComponent(value);
+ });
+
+ if (query) {
+ url += (url.indexOf('?') > 0 ? '&' : '?') + query;
+ }
+
+ return url;
+ },
+
+ /**
+ * Executes the callback function for each item in array/object. If you return false in the
+ * callback it will break the loop.
+ *
+ * @param {Object} obj Object to iterate.
+ * @param {function} callback Callback function to execute for each item.
+ */
+ each : function(obj, callback) {
+ var length, key, i;
+
+ if (obj) {
+ length = obj.length;
+
+ if (length === undef) {
+ // Loop object items
+ for (key in obj) {
+ if (obj.hasOwnProperty(key)) {
+ if (callback(obj[key], key) === false) {
+ return;
+ }
+ }
+ }
+ } else {
+ // Loop array items
+ for (i = 0; i < length; i++) {
+ if (callback(obj[i], i) === false) {
+ return;
+ }
+ }
+ }
+ }
+ },
+
+ /**
+ * Formats the specified number as a size string for example 1024 becomes 1 KB.
+ *
+ * @method formatSize
+ * @param {Number} size Size to format as string.
+ * @return {String} Formatted size string.
+ */
+ formatSize : function(size) {
+ if (size === undef || /\D/.test(size)) {
+ return plupload.translate('N/A');
+ }
+
+ // GB
+ if (size > 1073741824) {
+ return Math.round(size / 1073741824, 1) + " GB";
+ }
+
+ // MB
+ if (size > 1048576) {
+ return Math.round(size / 1048576, 1) + " MB";
+ }
+
+ // KB
+ if (size > 1024) {
+ return Math.round(size / 1024, 1) + " KB";
+ }
+
+ return size + " b";
+ },
+
+ /**
+ * Returns the absolute x, y position of an Element. The position will be returned in a object with x, y fields.
+ *
+ * @method getPos
+ * @param {Element} node HTML element or element id to get x, y position from.
+ * @param {Element} root Optional root element to stop calculations at.
+ * @return {object} Absolute position of the specified element object with x, y fields.
+ */
+ getPos : function(node, root) {
+ var x = 0, y = 0, parent, doc = document, nodeRect, rootRect;
+
+ node = node;
+ root = root || doc.body;
+
+ // Returns the x, y cordinate for an element on IE 6 and IE 7
+ function getIEPos(node) {
+ var bodyElm, rect, x = 0, y = 0;
+
+ if (node) {
+ rect = node.getBoundingClientRect();
+ bodyElm = doc.compatMode === "CSS1Compat" ? doc.documentElement : doc.body;
+ x = rect.left + bodyElm.scrollLeft;
+ y = rect.top + bodyElm.scrollTop;
+ }
+
+ return {
+ x : x,
+ y : y
+ };
+ }
+
+ // Use getBoundingClientRect on IE 6 and IE 7 but not on IE 8 in standards mode
+ if (node && node.getBoundingClientRect && plupload.ua.ie && (!doc.documentMode || doc.documentMode < 8)) {
+ nodeRect = getIEPos(node);
+ rootRect = getIEPos(root);
+
+ return {
+ x : nodeRect.x - rootRect.x,
+ y : nodeRect.y - rootRect.y
+ };
+ }
+
+ parent = node;
+ while (parent && parent != root && parent.nodeType) {
+ x += parent.offsetLeft || 0;
+ y += parent.offsetTop || 0;
+ parent = parent.offsetParent;
+ }
+
+ parent = node.parentNode;
+ while (parent && parent != root && parent.nodeType) {
+ x -= parent.scrollLeft || 0;
+ y -= parent.scrollTop || 0;
+ parent = parent.parentNode;
+ }
+
+ return {
+ x : x,
+ y : y
+ };
+ },
+
+ /**
+ * Returns the size of the specified node in pixels.
+ *
+ * @param {Node} node Node to get the size of.
+ * @return {Object} Object with a w and h property.
+ */
+ getSize : function(node) {
+ return {
+ w : node.offsetWidth || node.clientWidth,
+ h : node.offsetHeight || node.clientHeight
+ };
+ },
+
+ /**
+ * Parses the specified size string into a byte value. For example 10kb becomes 10240.
+ *
+ * @method parseSize
+ * @param {String/Number} size String to parse or number to just pass through.
+ * @return {Number} Size in bytes.
+ */
+ parseSize : function(size) {
+ var mul;
+
+ if (typeof(size) == 'string') {
+ size = /^([0-9]+)([mgk]?)$/.exec(size.toLowerCase().replace(/[^0-9mkg]/g, ''));
+ mul = size[2];
+ size = +size[1];
+
+ if (mul == 'g') {
+ size *= 1073741824;
+ }
+
+ if (mul == 'm') {
+ size *= 1048576;
+ }
+
+ if (mul == 'k') {
+ size *= 1024;
+ }
+ }
+
+ return size;
+ },
+
+ /**
+ * Encodes the specified string.
+ *
+ * @method xmlEncode
+ * @param {String} s String to encode.
+ * @return {String} Encoded string.
+ */
+ xmlEncode : function(str) {
+ return str ? ('' + str).replace(xmlEncodeRegExp, function(chr) {
+ return xmlEncodeChars[chr] ? '&' + xmlEncodeChars[chr] + ';' : chr;
+ }) : str;
+ },
+
+ /**
+ * Forces anything into an array.
+ *
+ * @method toArray
+ * @param {Object} obj Object with length field.
+ * @return {Array} Array object containing all items.
+ */
+ toArray : function(obj) {
+ var i, arr = [];
+
+ for (i = 0; i < obj.length; i++) {
+ arr[i] = obj[i];
+ }
+
+ return arr;
+ },
+
+ /**
+ * Find an element in array and return it's index if present, otherwise return -1.
+ *
+ * @method inArray
+ * @param {mixed} needle Element to find
+ * @param {Array} array
+ * @return {Int} Index of the element, or -1 if not found
+ */
+ inArray : function(needle, array) {
+ if (array) {
+ if (Array.prototype.indexOf) {
+ return Array.prototype.indexOf.call(array, needle);
+ }
+
+ for (var i = 0, length = array.length; i < length; i++) {
+ if (array[i] === needle) {
+ return i;
+ }
+ }
+ }
+ return -1;
+ },
+
+ /**
+ * Extends the language pack object with new items.
+ *
+ * @param {Object} pack Language pack items to add.
+ * @return {Object} Extended language pack object.
+ */
+ addI18n : function(pack) {
+ return plupload.extend(i18n, pack);
+ },
+
+ /**
+ * Translates the specified string by checking for the english string in the language pack lookup.
+ *
+ * @param {String} str String to look for.
+ * @return {String} Translated string or the input string if it wasn't found.
+ */
+ translate : function(str) {
+ return i18n[str] || str;
+ },
+
+ /**
+ * Checks if object is empty.
+ *
+ * @param {Object} obj Object to check.
+ * @return {Boolean}
+ */
+ isEmptyObj : function(obj) {
+ if (obj === undef) return true;
+
+ for (var prop in obj) {
+ return false;
+ }
+ return true;
+ },
+
+ /**
+ * Checks if specified DOM element has specified class.
+ *
+ * @param {Object} obj DOM element like object to add handler to.
+ * @param {String} name Class name
+ */
+ hasClass : function(obj, name) {
+ var regExp;
+
+ if (obj.className == '') {
+ return false;
+ }
+
+ regExp = new RegExp("(^|\\s+)"+name+"(\\s+|$)");
+
+ return regExp.test(obj.className);
+ },
+
+ /**
+ * Adds specified className to specified DOM element.
+ *
+ * @param {Object} obj DOM element like object to add handler to.
+ * @param {String} name Class name
+ */
+ addClass : function(obj, name) {
+ if (!plupload.hasClass(obj, name)) {
+ obj.className = obj.className == '' ? name : obj.className.replace(/\s+$/, '')+' '+name;
+ }
+ },
+
+ /**
+ * Removes specified className from specified DOM element.
+ *
+ * @param {Object} obj DOM element like object to add handler to.
+ * @param {String} name Class name
+ */
+ removeClass : function(obj, name) {
+ var regExp = new RegExp("(^|\\s+)"+name+"(\\s+|$)");
+
+ obj.className = obj.className.replace(regExp, function($0, $1, $2) {
+ return $1 === ' ' && $2 === ' ' ? ' ' : '';
+ });
+ },
+
+ /**
+ * Returns a given computed style of a DOM element.
+ *
+ * @param {Object} obj DOM element like object.
+ * @param {String} name Style you want to get from the DOM element
+ */
+ getStyle : function(obj, name) {
+ if (obj.currentStyle) {
+ return obj.currentStyle[name];
+ } else if (window.getComputedStyle) {
+ return window.getComputedStyle(obj, null)[name];
+ }
+ },
+
+ /**
+ * Adds an event handler to the specified object and store reference to the handler
+ * in objects internal Plupload registry (@see removeEvent).
+ *
+ * @param {Object} obj DOM element like object to add handler to.
+ * @param {String} name Name to add event listener to.
+ * @param {Function} callback Function to call when event occurs.
+ * @param {String} (optional) key that might be used to add specifity to the event record.
+ */
+ addEvent : function(obj, name, callback) {
+ var func, events, types, key;
+
+ // if passed in, event will be locked with this key - one would need to provide it to removeEvent
+ key = arguments[3];
+
+ name = name.toLowerCase();
+
+ // Initialize unique identifier if needed
+ if (uid === undef) {
+ uid = 'Plupload_' + plupload.guid();
+ }
+
+ // Add event listener
+ if (obj.addEventListener) {
+ func = callback;
+
+ obj.addEventListener(name, func, false);
+ } else if (obj.attachEvent) {
+
+ func = function() {
+ var evt = window.event;
+
+ if (!evt.target) {
+ evt.target = evt.srcElement;
+ }
+
+ evt.preventDefault = preventDefault;
+ evt.stopPropagation = stopPropagation;
+
+ callback(evt);
+ };
+ obj.attachEvent('on' + name, func);
+ }
+
+ // Log event handler to objects internal Plupload registry
+ if (obj[uid] === undef) {
+ obj[uid] = plupload.guid();
+ }
+
+ if (!eventhash.hasOwnProperty(obj[uid])) {
+ eventhash[obj[uid]] = {};
+ }
+
+ events = eventhash[obj[uid]];
+
+ if (!events.hasOwnProperty(name)) {
+ events[name] = [];
+ }
+
+ events[name].push({
+ func: func,
+ orig: callback, // store original callback for IE
+ key: key
+ });
+ },
+
+
+ /**
+ * Remove event handler from the specified object. If third argument (callback)
+ * is not specified remove all events with the specified name.
+ *
+ * @param {Object} obj DOM element to remove event listener(s) from.
+ * @param {String} name Name of event listener to remove.
+ * @param {Function|String} (optional) might be a callback or unique key to match.
+ */
+ removeEvent: function(obj, name) {
+ var type, callback, key;
+
+ // match the handler either by callback or by key
+ if (typeof(arguments[2]) == "function") {
+ callback = arguments[2];
+ } else {
+ key = arguments[2];
+ }
+
+ name = name.toLowerCase();
+
+ if (obj[uid] && eventhash[obj[uid]] && eventhash[obj[uid]][name]) {
+ type = eventhash[obj[uid]][name];
+ } else {
+ return;
+ }
+
+
+ for (var i=type.length-1; i>=0; i--) {
+ // undefined or not, key should match
+ if (type[i].key === key || type[i].orig === callback) {
+
+ if (obj.removeEventListener) {
+ obj.removeEventListener(name, type[i].func, false);
+ } else if (obj.detachEvent) {
+ obj.detachEvent('on'+name, type[i].func);
+ }
+
+ type[i].orig = null;
+ type[i].func = null;
+
+ type.splice(i, 1);
+
+ // If callback was passed we are done here, otherwise proceed
+ if (callback !== undef) {
+ break;
+ }
+ }
+ }
+
+ // If event array got empty, remove it
+ if (!type.length) {
+ delete eventhash[obj[uid]][name];
+ }
+
+ // If Plupload registry has become empty, remove it
+ if (plupload.isEmptyObj(eventhash[obj[uid]])) {
+ delete eventhash[obj[uid]];
+
+ // IE doesn't let you remove DOM object property with - delete
+ try {
+ delete obj[uid];
+ } catch(e) {
+ obj[uid] = undef;
+ }
+ }
+ },
+
+
+ /**
+ * Remove all kind of events from the specified object
+ *
+ * @param {Object} obj DOM element to remove event listeners from.
+ * @param {String} (optional) unique key to match, when removing events.
+ */
+ removeAllEvents: function(obj) {
+ var key = arguments[1];
+
+ if (obj[uid] === undef || !obj[uid]) {
+ return;
+ }
+
+ plupload.each(eventhash[obj[uid]], function(events, name) {
+ plupload.removeEvent(obj, name, key);
+ });
+ }
+ };
+
+
+ /**
+ * Uploader class, an instance of this class will be created for each upload field.
+ *
+ * @example
+ * var uploader = new plupload.Uploader({
+ * runtimes : 'gears,html5,flash',
+ * browse_button : 'button_id'
+ * });
+ *
+ * uploader.bind('Init', function(up) {
+ * alert('Supports drag/drop: ' + (!!up.features.dragdrop));
+ * });
+ *
+ * uploader.bind('FilesAdded', function(up, files) {
+ * alert('Selected files: ' + files.length);
+ * });
+ *
+ * uploader.bind('QueueChanged', function(up) {
+ * alert('Queued files: ' + uploader.files.length);
+ * });
+ *
+ * uploader.init();
+ *
+ * @class plupload.Uploader
+ */
+
+ /**
+ * Constructs a new uploader instance.
+ *
+ * @constructor
+ * @method Uploader
+ * @param {Object} settings Initialization settings, to be used by the uploader instance and runtimes.
+ */
+ plupload.Uploader = function(settings) {
+ var events = {}, total, files = [], startTime, disabled = false;
+
+ // Inital total state
+ total = new plupload.QueueProgress();
+
+ // Default settings
+ settings = plupload.extend({
+ chunk_size : 0,
+ multipart : true,
+ multi_selection : true,
+ file_data_name : 'file',
+ filters : []
+ }, settings);
+
+ // Private methods
+ function uploadNext() {
+ var file, count = 0, i;
+
+ if (this.state == plupload.STARTED) {
+ // Find first QUEUED file
+ for (i = 0; i < files.length; i++) {
+ if (!file && files[i].status == plupload.QUEUED) {
+ file = files[i];
+ file.status = plupload.UPLOADING;
+ if (this.trigger("BeforeUpload", file)) {
+ this.trigger("UploadFile", file);
+ }
+ } else {
+ count++;
+ }
+ }
+
+ // All files are DONE or FAILED
+ if (count == files.length) {
+ this.stop();
+ this.trigger("UploadComplete", files);
+ }
+ }
+ }
+
+ function calc() {
+ var i, file;
+
+ // Reset stats
+ total.reset();
+
+ // Check status, size, loaded etc on all files
+ for (i = 0; i < files.length; i++) {
+ file = files[i];
+
+ if (file.size !== undef) {
+ total.size += file.size;
+ total.loaded += file.loaded;
+ } else {
+ total.size = undef;
+ }
+
+ if (file.status == plupload.DONE) {
+ total.uploaded++;
+ } else if (file.status == plupload.FAILED) {
+ total.failed++;
+ } else {
+ total.queued++;
+ }
+ }
+
+ // If we couldn't calculate a total file size then use the number of files to calc percent
+ if (total.size === undef) {
+ total.percent = files.length > 0 ? Math.ceil(total.uploaded / files.length * 100) : 0;
+ } else {
+ total.bytesPerSec = Math.ceil(total.loaded / ((+new Date() - startTime || 1) / 1000.0));
+ total.percent = total.size > 0 ? Math.ceil(total.loaded / total.size * 100) : 0;
+ }
+ }
+
+ // Add public methods
+ plupload.extend(this, {
+ /**
+ * Current state of the total uploading progress. This one can either be plupload.STARTED or plupload.STOPPED.
+ * These states are controlled by the stop/start methods. The default value is STOPPED.
+ *
+ * @property state
+ * @type Number
+ */
+ state : plupload.STOPPED,
+
+ /**
+ * Current runtime name.
+ *
+ * @property runtime
+ * @type String
+ */
+ runtime: '',
+
+ /**
+ * Map of features that are available for the uploader runtime. Features will be filled
+ * before the init event is called, these features can then be used to alter the UI for the end user.
+ * Some of the current features that might be in this map is: dragdrop, chunks, jpgresize, pngresize.
+ *
+ * @property features
+ * @type Object
+ */
+ features : {},
+
+ /**
+ * Current upload queue, an array of File instances.
+ *
+ * @property files
+ * @type Array
+ * @see plupload.File
+ */
+ files : files,
+
+ /**
+ * Object with name/value settings.
+ *
+ * @property settings
+ * @type Object
+ */
+ settings : settings,
+
+ /**
+ * Total progess information. How many files has been uploaded, total percent etc.
+ *
+ * @property total
+ * @type plupload.QueueProgress
+ */
+ total : total,
+
+ /**
+ * Unique id for the Uploader instance.
+ *
+ * @property id
+ * @type String
+ */
+ id : plupload.guid(),
+
+ /**
+ * Initializes the Uploader instance and adds internal event listeners.
+ *
+ * @method init
+ */
+ init : function() {
+ var self = this, i, runtimeList, a, runTimeIndex = 0, items;
+
+ if (typeof(settings.preinit) == "function") {
+ settings.preinit(self);
+ } else {
+ plupload.each(settings.preinit, function(func, name) {
+ self.bind(name, func);
+ });
+ }
+
+ settings.page_url = settings.page_url || document.location.pathname.replace(/\/[^\/]+$/g, '/');
+
+ // If url is relative force it absolute to the current page
+ if (!/^(\w+:\/\/|\/)/.test(settings.url)) {
+ settings.url = settings.page_url + settings.url;
+ }
+
+ // Convert settings
+ settings.chunk_size = plupload.parseSize(settings.chunk_size);
+ settings.max_file_size = plupload.parseSize(settings.max_file_size);
+
+ // Add files to queue
+ self.bind('FilesAdded', function(up, selected_files) {
+ var i, file, count = 0, extensionsRegExp, filters = settings.filters;
+
+ // Convert extensions to regexp
+ if (filters && filters.length) {
+ extensionsRegExp = [];
+
+ plupload.each(filters, function(filter) {
+ plupload.each(filter.extensions.split(/,/), function(ext) {
+ if (/^\s*\*\s*$/.test(ext)) {
+ extensionsRegExp.push('\\.*');
+ } else {
+ extensionsRegExp.push('\\.' + ext.replace(new RegExp('[' + ('/^$.*+?|()[]{}\\'.replace(/./g, '\\$&')) + ']', 'g'), '\\$&'));
+ }
+ });
+ });
+
+ extensionsRegExp = new RegExp(extensionsRegExp.join('|') + '$', 'i');
+ }
+
+ for (i = 0; i < selected_files.length; i++) {
+ file = selected_files[i];
+ file.loaded = 0;
+ file.percent = 0;
+ file.status = plupload.QUEUED;
+
+ // Invalid file extension
+ if (extensionsRegExp && !extensionsRegExp.test(file.name)) {
+ up.trigger('Error', {
+ code : plupload.FILE_EXTENSION_ERROR,
+ message : plupload.translate('File extension error.'),
+ file : file
+ });
+
+ continue;
+ }
+
+ // Invalid file size
+ if (file.size !== undef && file.size > settings.max_file_size) {
+ up.trigger('Error', {
+ code : plupload.FILE_SIZE_ERROR,
+ message : plupload.translate('File size error.'),
+ file : file
+ });
+
+ continue;
+ }
+
+ // Add valid file to list
+ files.push(file);
+ count++;
+ }
+
+ // Only trigger QueueChanged event if any files where added
+ if (count) {
+ delay(function() {
+ self.trigger("QueueChanged");
+ self.refresh();
+ }, 1);
+ } else {
+ return false; // Stop the FilesAdded event from immediate propagation
+ }
+ });
+
+ // Generate unique target filenames
+ if (settings.unique_names) {
+ self.bind("UploadFile", function(up, file) {
+ var matches = file.name.match(/\.([^.]+)$/), ext = "tmp";
+
+ if (matches) {
+ ext = matches[1];
+ }
+
+ file.target_name = file.id + '.' + ext;
+ });
+ }
+
+ self.bind('UploadProgress', function(up, file) {
+ file.percent = file.size > 0 ? Math.ceil(file.loaded / file.size * 100) : 100;
+ calc();
+ });
+
+ self.bind('StateChanged', function(up) {
+ if (up.state == plupload.STARTED) {
+ // Get start time to calculate bps
+ startTime = (+new Date());
+
+ } else if (up.state == plupload.STOPPED) {
+ // Reset currently uploading files
+ for (i = up.files.length - 1; i >= 0; i--) {
+ if (up.files[i].status == plupload.UPLOADING) {
+ up.files[i].status = plupload.QUEUED;
+ calc();
+ }
+ }
+ }
+ });
+
+ self.bind('QueueChanged', calc);
+
+ self.bind("Error", function(up, err) {
+ // Set failed status if an error occured on a file
+ if (err.file) {
+ err.file.status = plupload.FAILED;
+ calc();
+
+ // Upload next file but detach it from the error event
+ // since other custom listeners might want to stop the queue
+ if (up.state == plupload.STARTED) {
+ delay(function() {
+ uploadNext.call(self);
+ }, 1);
+ }
+ }
+ });
+
+ self.bind("FileUploaded", function(up, file) {
+ file.status = plupload.DONE;
+ file.loaded = file.size;
+ up.trigger('UploadProgress', file);
+
+ // Upload next file but detach it from the error event
+ // since other custom listeners might want to stop the queue
+ delay(function() {
+ uploadNext.call(self);
+ }, 1);
+ });
+
+ // Setup runtimeList
+ if (settings.runtimes) {
+ runtimeList = [];
+ items = settings.runtimes.split(/\s?,\s?/);
+
+ for (i = 0; i < items.length; i++) {
+ if (runtimes[items[i]]) {
+ runtimeList.push(runtimes[items[i]]);
+ }
+ }
+ } else {
+ runtimeList = runtimes;
+ }
+
+ // Call init on each runtime in sequence
+ function callNextInit() {
+ var runtime = runtimeList[runTimeIndex++], features, requiredFeatures, i;
+
+ if (runtime) {
+ features = runtime.getFeatures();
+
+ // Check if runtime supports required features
+ requiredFeatures = self.settings.required_features;
+ if (requiredFeatures) {
+ requiredFeatures = requiredFeatures.split(',');
+
+ for (i = 0; i < requiredFeatures.length; i++) {
+ // Specified feature doesn't exist
+ if (!features[requiredFeatures[i]]) {
+ callNextInit();
+ return;
+ }
+ }
+ }
+
+ // Try initializing the runtime
+ runtime.init(self, function(res) {
+ if (res && res.success) {
+ // Successful initialization
+ self.features = features;
+ self.runtime = runtime.name;
+ self.trigger('Init', {runtime : runtime.name});
+ self.trigger('PostInit');
+ self.refresh();
+ } else {
+ callNextInit();
+ }
+ });
+ } else {
+ // Trigger an init error if we run out of runtimes
+ self.trigger('Error', {
+ code : plupload.INIT_ERROR,
+ message : plupload.translate('Init error.')
+ });
+ }
+ }
+
+ callNextInit();
+
+ if (typeof(settings.init) == "function") {
+ settings.init(self);
+ } else {
+ plupload.each(settings.init, function(func, name) {
+ self.bind(name, func);
+ });
+ }
+ },
+
+ /**
+ * Refreshes the upload instance by dispatching out a refresh event to all runtimes.
+ * This would for example reposition flash/silverlight shims on the page.
+ *
+ * @method refresh
+ */
+ refresh : function() {
+ this.trigger("Refresh");
+ },
+
+ /**
+ * Starts uploading the queued files.
+ *
+ * @method start
+ */
+ start : function() {
+ if (files.length && this.state != plupload.STARTED) {
+ this.state = plupload.STARTED;
+ this.trigger("StateChanged");
+
+ uploadNext.call(this);
+ }
+ },
+
+ /**
+ * Stops the upload of the queued files.
+ *
+ * @method stop
+ */
+ stop : function() {
+ if (this.state != plupload.STOPPED) {
+ this.state = plupload.STOPPED;
+ this.trigger("CancelUpload");
+ this.trigger("StateChanged");
+ }
+ },
+
+ /**
+ * Disables/enables browse button on request.
+ *
+ * @method disableBrowse
+ * @param {Boolean} disable Whether to disable or enable (default: true)
+ */
+ disableBrowse : function() {
+ disabled = arguments[0] !== undef ? arguments[0] : true;
+ this.trigger("DisableBrowse", disabled);
+ },
+
+ /**
+ * Returns the specified file object by id.
+ *
+ * @method getFile
+ * @param {String} id File id to look for.
+ * @return {plupload.File} File object or undefined if it wasn't found;
+ */
+ getFile : function(id) {
+ var i;
+
+ for (i = files.length - 1; i >= 0; i--) {
+ if (files[i].id === id) {
+ return files[i];
+ }
+ }
+ },
+
+ /**
+ * Removes a specific file.
+ *
+ * @method removeFile
+ * @param {plupload.File} file File to remove from queue.
+ */
+ removeFile : function(file) {
+ var i;
+
+ for (i = files.length - 1; i >= 0; i--) {
+ if (files[i].id === file.id) {
+ return this.splice(i, 1)[0];
+ }
+ }
+ },
+
+ /**
+ * Removes part of the queue and returns the files removed. This will also trigger the FilesRemoved and QueueChanged events.
+ *
+ * @method splice
+ * @param {Number} start (Optional) Start index to remove from.
+ * @param {Number} length (Optional) Lengh of items to remove.
+ * @return {Array} Array of files that was removed.
+ */
+ splice : function(start, length) {
+ var removed;
+
+ // Splice and trigger events
+ removed = files.splice(start === undef ? 0 : start, length === undef ? files.length : length);
+
+ this.trigger("FilesRemoved", removed);
+ this.trigger("QueueChanged");
+
+ return removed;
+ },
+
+ /**
+ * Dispatches the specified event name and it's arguments to all listeners.
+ *
+ *
+ * @method trigger
+ * @param {String} name Event name to fire.
+ * @param {Object..} Multiple arguments to pass along to the listener functions.
+ */
+ trigger : function(name) {
+ var list = events[name.toLowerCase()], i, args;
+
+ // console.log(name, arguments);
+
+ if (list) {
+ // Replace name with sender in args
+ args = Array.prototype.slice.call(arguments);
+ args[0] = this;
+
+ // Dispatch event to all listeners
+ for (i = 0; i < list.length; i++) {
+ // Fire event, break chain if false is returned
+ if (list[i].func.apply(list[i].scope, args) === false) {
+ return false;
+ }
+ }
+ }
+
+ return true;
+ },
+
+ /**
+ * Check whether uploader has any listeners to the specified event.
+ *
+ * @method hasEventListener
+ * @param {String} name Event name to check for.
+ */
+ hasEventListener : function(name) {
+ return !!events[name.toLowerCase()];
+ },
+
+ /**
+ * Adds an event listener by name.
+ *
+ * @method bind
+ * @param {String} name Event name to listen for.
+ * @param {function} func Function to call ones the event gets fired.
+ * @param {Object} scope Optional scope to execute the specified function in.
+ */
+ bind : function(name, func, scope) {
+ var list;
+
+ name = name.toLowerCase();
+ list = events[name] || [];
+ list.push({func : func, scope : scope || this});
+ events[name] = list;
+ },
+
+ /**
+ * Removes the specified event listener.
+ *
+ * @method unbind
+ * @param {String} name Name of event to remove.
+ * @param {function} func Function to remove from listener.
+ */
+ unbind : function(name) {
+ name = name.toLowerCase();
+
+ var list = events[name], i, func = arguments[1];
+
+ if (list) {
+ if (func !== undef) {
+ for (i = list.length - 1; i >= 0; i--) {
+ if (list[i].func === func) {
+ list.splice(i, 1);
+ break;
+ }
+ }
+ } else {
+ list = [];
+ }
+
+ // delete event list if it has become empty
+ if (!list.length) {
+ delete events[name];
+ }
+ }
+ },
+
+ /**
+ * Removes all event listeners.
+ *
+ * @method unbindAll
+ */
+ unbindAll : function() {
+ var self = this;
+
+ plupload.each(events, function(list, name) {
+ self.unbind(name);
+ });
+ },
+
+ /**
+ * Destroys Plupload instance and cleans after itself.
+ *
+ * @method destroy
+ */
+ destroy : function() {
+ this.stop();
+ this.trigger('Destroy');
+
+ // Clean-up after uploader itself
+ this.unbindAll();
+ }
+
+ /**
+ * Fires when the current RunTime has been initialized.
+ *
+ * @event Init
+ * @param {plupload.Uploader} uploader Uploader instance sending the event.
+ */
+
+ /**
+ * Fires after the init event incase you need to perform actions there.
+ *
+ * @event PostInit
+ * @param {plupload.Uploader} uploader Uploader instance sending the event.
+ */
+
+ /**
+ * Fires when the silverlight/flash or other shim needs to move.
+ *
+ * @event Refresh
+ * @param {plupload.Uploader} uploader Uploader instance sending the event.
+ */
+
+ /**
+ * Fires when the overall state is being changed for the upload queue.
+ *
+ * @event StateChanged
+ * @param {plupload.Uploader} uploader Uploader instance sending the event.
+ */
+
+ /**
+ * Fires when a file is to be uploaded by the runtime.
+ *
+ * @event UploadFile
+ * @param {plupload.Uploader} uploader Uploader instance sending the event.
+ * @param {plupload.File} file File to be uploaded.
+ */
+
+ /**
+ * Fires when just before a file is uploaded. This event enables you to override settings
+ * on the uploader instance before the file is uploaded.
+ *
+ * @event BeforeUpload
+ * @param {plupload.Uploader} uploader Uploader instance sending the event.
+ * @param {plupload.File} file File to be uploaded.
+ */
+
+ /**
+ * Fires when the file queue is changed. In other words when files are added/removed to the files array of the uploader instance.
+ *
+ * @event QueueChanged
+ * @param {plupload.Uploader} uploader Uploader instance sending the event.
+ */
+
+ /**
+ * Fires while a file is being uploaded. Use this event to update the current file upload progress.
+ *
+ * @event UploadProgress
+ * @param {plupload.Uploader} uploader Uploader instance sending the event.
+ * @param {plupload.File} file File that is currently being uploaded.
+ */
+
+ /**
+ * Fires while a file was removed from queue.
+ *
+ * @event FilesRemoved
+ * @param {plupload.Uploader} uploader Uploader instance sending the event.
+ * @param {Array} files Array of files that got removed.
+ */
+
+ /**
+ * Fires while when the user selects files to upload.
+ *
+ * @event FilesAdded
+ * @param {plupload.Uploader} uploader Uploader instance sending the event.
+ * @param {Array} files Array of file objects that was added to queue/selected by the user.
+ */
+
+ /**
+ * Fires when a file is successfully uploaded.
+ *
+ * @event FileUploaded
+ * @param {plupload.Uploader} uploader Uploader instance sending the event.
+ * @param {plupload.File} file File that was uploaded.
+ * @param {Object} response Object with response properties.
+ */
+
+ /**
+ * Fires when file chunk is uploaded.
+ *
+ * @event ChunkUploaded
+ * @param {plupload.Uploader} uploader Uploader instance sending the event.
+ * @param {plupload.File} file File that the chunk was uploaded for.
+ * @param {Object} response Object with response properties.
+ */
+
+ /**
+ * Fires when all files in a queue are uploaded.
+ *
+ * @event UploadComplete
+ * @param {plupload.Uploader} uploader Uploader instance sending the event.
+ * @param {Array} files Array of file objects that was added to queue/selected by the user.
+ */
+
+ /**
+ * Fires when a error occurs.
+ *
+ * @event Error
+ * @param {plupload.Uploader} uploader Uploader instance sending the event.
+ * @param {Object} error Contains code, message and sometimes file and other details.
+ */
+
+ /**
+ * Fires when destroy method is called.
+ *
+ * @event Destroy
+ * @param {plupload.Uploader} uploader Uploader instance sending the event.
+ */
+ });
+ };
+
+ /**
+ * File instance.
+ *
+ * @class plupload.File
+ * @param {String} name Name of the file.
+ * @param {Number} size File size.
+ */
+
+ /**
+ * Constructs a new file instance.
+ *
+ * @constructor
+ * @method File
+ * @param {String} id Unique file id.
+ * @param {String} name File name.
+ * @param {Number} size File size in bytes.
+ */
+ plupload.File = function(id, name, size) {
+ var self = this; // Setup alias for self to reduce code size when it's compressed
+
+ /**
+ * File id this is a globally unique id for the specific file.
+ *
+ * @property id
+ * @type String
+ */
+ self.id = id;
+
+ /**
+ * File name for example "myfile.gif".
+ *
+ * @property name
+ * @type String
+ */
+ self.name = name;
+
+ /**
+ * File size in bytes.
+ *
+ * @property size
+ * @type Number
+ */
+ self.size = size;
+
+ /**
+ * Number of bytes uploaded of the files total size.
+ *
+ * @property loaded
+ * @type Number
+ */
+ self.loaded = 0;
+
+ /**
+ * Number of percentage uploaded of the file.
+ *
+ * @property percent
+ * @type Number
+ */
+ self.percent = 0;
+
+ /**
+ * Status constant matching the plupload states QUEUED, UPLOADING, FAILED, DONE.
+ *
+ * @property status
+ * @type Number
+ * @see plupload
+ */
+ self.status = 0;
+ };
+
+ /**
+ * Runtime class gets implemented by each upload runtime.
+ *
+ * @class plupload.Runtime
+ * @static
+ */
+ plupload.Runtime = function() {
+ /**
+ * Returns a list of supported features for the runtime.
+ *
+ * @return {Object} Name/value object with supported features.
+ */
+ this.getFeatures = function() {
+ };
+
+ /**
+ * Initializes the upload runtime. This method should add necessary items to the DOM and register events needed for operation.
+ *
+ * @method init
+ * @param {plupload.Uploader} uploader Uploader instance that needs to be initialized.
+ * @param {function} callback Callback function to execute when the runtime initializes or fails to initialize. If it succeeds an object with a parameter name success will be set to true.
+ */
+ this.init = function(uploader, callback) {
+ };
+ };
+
+ /**
+ * Runtime class gets implemented by each upload runtime.
+ *
+ * @class plupload.QueueProgress
+ */
+
+ /**
+ * Constructs a queue progress.
+ *
+ * @constructor
+ * @method QueueProgress
+ */
+ plupload.QueueProgress = function() {
+ var self = this; // Setup alias for self to reduce code size when it's compressed
+
+ /**
+ * Total queue file size.
+ *
+ * @property size
+ * @type Number
+ */
+ self.size = 0;
+
+ /**
+ * Total bytes uploaded.
+ *
+ * @property loaded
+ * @type Number
+ */
+ self.loaded = 0;
+
+ /**
+ * Number of files uploaded.
+ *
+ * @property uploaded
+ * @type Number
+ */
+ self.uploaded = 0;
+
+ /**
+ * Number of files failed to upload.
+ *
+ * @property failed
+ * @type Number
+ */
+ self.failed = 0;
+
+ /**
+ * Number of files yet to be uploaded.
+ *
+ * @property queued
+ * @type Number
+ */
+ self.queued = 0;
+
+ /**
+ * Total percent of the uploaded bytes.
+ *
+ * @property percent
+ * @type Number
+ */
+ self.percent = 0;
+
+ /**
+ * Bytes uploaded per second.
+ *
+ * @property bytesPerSec
+ * @type Number
+ */
+ self.bytesPerSec = 0;
+
+ /**
+ * Resets the progress to it's initial values.
+ *
+ * @method reset
+ */
+ self.reset = function() {
+ self.size = self.loaded = self.uploaded = self.failed = self.queued = self.percent = self.bytesPerSec = 0;
+ };
+ };
+
+ // Create runtimes namespace
+ plupload.runtimes = {};
+
+ // Expose plupload namespace
+ window.plupload = plupload;
+})();
diff --git a/debian/missing-sources/plupload/javascript/plupload.silverlight.js b/debian/missing-sources/plupload/javascript/plupload.silverlight.js
new file mode 100644
index 0000000..c0903f2
--- /dev/null
+++ b/debian/missing-sources/plupload/javascript/plupload.silverlight.js
@@ -0,0 +1,447 @@
+/**
+ * plupload.silverlight.js
+ *
+ * Copyright 2009, Moxiecode Systems AB
+ * Released under GPL License.
+ *
+ * License: http://www.plupload.com/license
+ * Contributing: http://www.plupload.com/contributing
+ */
+
+// JSLint defined globals
+/*global window:false, document:false, plupload:false, ActiveXObject:false */
+
+(function(window, document, plupload, undef) {
+ var uploadInstances = {}, initialized = {};
+
+ function jsonSerialize(obj) {
+ var value, type = typeof obj, isArray, i, key;
+
+ // Treat undefined as null
+ if (obj === undef || obj === null) {
+ return 'null';
+ }
+
+ // Encode strings
+ if (type === 'string') {
+ value = '\bb\tt\nn\ff\rr\""\'\'\\\\';
+
+ return '"' + obj.replace(/([\u0080-\uFFFF\x00-\x1f\"])/g, function(a, b) {
+ var idx = value.indexOf(b);
+
+ if (idx + 1) {
+ return '\\' + value.charAt(idx + 1);
+ }
+
+ a = b.charCodeAt().toString(16);
+
+ return '\\u' + '0000'.substring(a.length) + a;
+ }) + '"';
+ }
+
+ // Loop objects/arrays
+ if (type == 'object') {
+ isArray = obj.length !== undef;
+ value = '';
+
+ if (isArray) {
+ for (i = 0; i < obj.length; i++) {
+ if (value) {
+ value += ',';
+ }
+
+ value += jsonSerialize(obj[i]);
+ }
+
+ value = '[' + value + ']';
+ } else {
+ for (key in obj) {
+ if (obj.hasOwnProperty(key)) {
+ if (value) {
+ value += ',';
+ }
+
+ value += jsonSerialize(key) + ':' + jsonSerialize(obj[key]);
+ }
+ }
+
+ value = '{' + value + '}';
+ }
+
+ return value;
+ }
+
+ // Convert all other types to string
+ return '' + obj;
+ }
+
+ function isInstalled(version) {
+ var isVersionSupported = false, container = null, control = null, actualVer,
+ actualVerArray, reqVerArray, requiredVersionPart, actualVersionPart, index = 0;
+
+ try {
+ try {
+ control = new ActiveXObject('AgControl.AgControl');
+
+ if (control.IsVersionSupported(version)) {
+ isVersionSupported = true;
+ }
+
+ control = null;
+ } catch (e) {
+ var plugin = navigator.plugins["Silverlight Plug-In"];
+
+ if (plugin) {
+ actualVer = plugin.description;
+
+ if (actualVer === "1.0.30226.2") {
+ actualVer = "2.0.30226.2";
+ }
+
+ actualVerArray = actualVer.split(".");
+
+ while (actualVerArray.length > 3) {
+ actualVerArray.pop();
+ }
+
+ while ( actualVerArray.length < 4) {
+ actualVerArray.push(0);
+ }
+
+ reqVerArray = version.split(".");
+
+ while (reqVerArray.length > 4) {
+ reqVerArray.pop();
+ }
+
+ do {
+ requiredVersionPart = parseInt(reqVerArray[index], 10);
+ actualVersionPart = parseInt(actualVerArray[index], 10);
+ index++;
+ } while (index < reqVerArray.length && requiredVersionPart === actualVersionPart);
+
+ if (requiredVersionPart <= actualVersionPart && !isNaN(requiredVersionPart)) {
+ isVersionSupported = true;
+ }
+ }
+ }
+ } catch (e2) {
+ isVersionSupported = false;
+ }
+
+ return isVersionSupported;
+ }
+
+ plupload.silverlight = {
+ trigger : function(id, name) {
+ var uploader = uploadInstances[id], i, args;
+
+ if (uploader) {
+ args = plupload.toArray(arguments).slice(1);
+ args[0] = 'Silverlight:' + name;
+
+ // Detach the call so that error handling in the browser is presented correctly
+ setTimeout(function() {
+ uploader.trigger.apply(uploader, args);
+ }, 0);
+ }
+ }
+ };
+
+ /**
+ * Silverlight implementation. This runtime supports these features: jpgresize, pngresize, chunks.
+ *
+ * @static
+ * @class plupload.runtimes.Silverlight
+ * @extends plupload.Runtime
+ */
+ plupload.runtimes.Silverlight = plupload.addRuntime("silverlight", {
+ /**
+ * Returns a list of supported features for the runtime.
+ *
+ * @return {Object} Name/value object with supported features.
+ */
+ getFeatures : function() {
+ return {
+ jpgresize: true,
+ pngresize: true,
+ chunks: true,
+ progress: true,
+ multipart: true,
+ multi_selection: true
+ };
+ },
+
+ /**
+ * Initializes the upload runtime. This runtime supports these features: jpgresize, pngresize, chunks.
+ *
+ * @method init
+ * @param {plupload.Uploader} uploader Uploader instance that needs to be initialized.
+ * @param {function} callback Callback to execute when the runtime initializes or fails to initialize. If it succeeds an object with a parameter name success will be set to true.
+ */
+ init : function(uploader, callback) {
+ var silverlightContainer, filter = '', filters = uploader.settings.filters, i, container = document.body;
+
+ // Check if Silverlight is installed, Silverlight windowless parameter doesn't work correctly on Opera so we disable it for now
+ if (!isInstalled('2.0.31005.0') || (window.opera && window.opera.buildNumber)) {
+ callback({success : false});
+ return;
+ }
+
+ initialized[uploader.id] = false;
+ uploadInstances[uploader.id] = uploader;
+
+ // Create silverlight container and insert it at an absolute position within the browse button
+ silverlightContainer = document.createElement('div');
+ silverlightContainer.id = uploader.id + '_silverlight_container';
+
+ plupload.extend(silverlightContainer.style, {
+ position : 'absolute',
+ top : '0px',
+ background : uploader.settings.shim_bgcolor || 'transparent',
+ zIndex : 99999,
+ width : '100px',
+ height : '100px',
+ overflow : 'hidden',
+ opacity : uploader.settings.shim_bgcolor || document.documentMode > 8 ? '' : 0.01 // Force transparent if bgcolor is undefined
+ });
+
+ silverlightContainer.className = 'plupload silverlight';
+
+ if (uploader.settings.container) {
+ container = document.getElementById(uploader.settings.container);
+ if (plupload.getStyle(container, 'position') === 'static') {
+ container.style.position = 'relative';
+ }
+ }
+
+ container.appendChild(silverlightContainer);
+
+ for (i = 0; i < filters.length; i++) {
+ filter += (filter != '' ? '|' : '') + filters[i].title + " | *." + filters[i].extensions.replace(/,/g, ';*.');
+ }
+
+ // Insert the Silverlight object inide the Silverlight container
+ silverlightContainer.innerHTML = '<object id="' + uploader.id + '_silverlight" data="data:application/x-silverlight," type="application/x-silverlight-2" style="outline:none;" width="1024" height="1024">' +
+ '<param name="source" value="' + uploader.settings.silverlight_xap_url + '"/>' +
+ '<param name="background" value="Transparent"/>' +
+ '<param name="windowless" value="true"/>' +
+ '<param name="enablehtmlaccess" value="true"/>' +
+ '<param name="initParams" value="id=' + uploader.id + ',filter=' + filter + ',multiselect=' + uploader.settings.multi_selection + '"/>' +
+ '</object>';
+
+ function getSilverlightObj() {
+ return document.getElementById(uploader.id + '_silverlight').content.Upload;
+ }
+
+ uploader.bind("Silverlight:Init", function() {
+ var selectedFiles, lookup = {};
+
+ // Prevent eventual reinitialization of the instance
+ if (initialized[uploader.id]) {
+ return;
+ }
+
+ initialized[uploader.id] = true;
+
+ uploader.bind("Silverlight:StartSelectFiles", function(up) {
+ selectedFiles = [];
+ });
+
+ uploader.bind("Silverlight:SelectFile", function(up, sl_id, name, size) {
+ var id;
+
+ // Store away silverlight ids
+ id = plupload.guid();
+ lookup[id] = sl_id;
+ lookup[sl_id] = id;
+
+ // Expose id, name and size
+ selectedFiles.push(new plupload.File(id, name, size));
+ });
+
+ uploader.bind("Silverlight:SelectSuccessful", function() {
+ // Trigger FilesAdded event if we added any
+ if (selectedFiles.length) {
+ uploader.trigger("FilesAdded", selectedFiles);
+ }
+ });
+
+ uploader.bind("Silverlight:UploadChunkError", function(up, file_id, chunk, chunks, message) {
+ uploader.trigger("Error", {
+ code : plupload.IO_ERROR,
+ message : 'IO Error.',
+ details : message,
+ file : up.getFile(lookup[file_id])
+ });
+ });
+
+ uploader.bind("Silverlight:UploadFileProgress", function(up, sl_id, loaded, total) {
+ var file = up.getFile(lookup[sl_id]);
+
+ if (file.status != plupload.FAILED) {
+ file.size = total;
+ file.loaded = loaded;
+
+ up.trigger('UploadProgress', file);
+ }
+ });
+
+ uploader.bind("Refresh", function(up) {
+ var browseButton, browsePos, browseSize;
+
+ browseButton = document.getElementById(up.settings.browse_button);
+ if (browseButton) {
+ browsePos = plupload.getPos(browseButton, document.getElementById(up.settings.container));
+ browseSize = plupload.getSize(browseButton);
+
+ plupload.extend(document.getElementById(up.id + '_silverlight_container').style, {
+ top : browsePos.y + 'px',
+ left : browsePos.x + 'px',
+ width : browseSize.w + 'px',
+ height : browseSize.h + 'px'
+ });
+ }
+ });
+
+ uploader.bind("Silverlight:UploadChunkSuccessful", function(up, sl_id, chunk, chunks, text) {
+ var chunkArgs, file = up.getFile(lookup[sl_id]);
+
+ chunkArgs = {
+ chunk : chunk,
+ chunks : chunks,
+ response : text
+ };
+
+ up.trigger('ChunkUploaded', file, chunkArgs);
+
+ // Stop upload if file is maked as failed
+ if (file.status != plupload.FAILED && up.state !== plupload.STOPPED) {
+ getSilverlightObj().UploadNextChunk();
+ }
+
+ // Last chunk then dispatch FileUploaded event
+ if (chunk == chunks - 1) {
+ file.status = plupload.DONE;
+
+ up.trigger('FileUploaded', file, {
+ response : text
+ });
+ }
+ });
+
+ uploader.bind("Silverlight:UploadSuccessful", function(up, sl_id, response) {
+ var file = up.getFile(lookup[sl_id]);
+
+ file.status = plupload.DONE;
+
+ up.trigger('FileUploaded', file, {
+ response : response
+ });
+ });
+
+ uploader.bind("FilesRemoved", function(up, files) {
+ var i;
+
+ for (i = 0; i < files.length; i++) {
+ getSilverlightObj().RemoveFile(lookup[files[i].id]);
+ }
+ });
+
+ uploader.bind("UploadFile", function(up, file) {
+ var settings = up.settings, resize = settings.resize || {};
+
+ getSilverlightObj().UploadFile(
+ lookup[file.id],
+ up.settings.url,
+ jsonSerialize({
+ name : file.target_name || file.name,
+ mime : plupload.mimeTypes[file.name.replace(/^.+\.([^.]+)/, '$1').toLowerCase()] || 'application/octet-stream',
+ chunk_size : settings.chunk_size,
+ image_width : resize.width,
+ image_height : resize.height,
+ image_quality : resize.quality,
+ multipart : !!settings.multipart,
+ multipart_params : settings.multipart_params || {},
+ file_data_name : settings.file_data_name,
+ headers : settings.headers
+ })
+ );
+ });
+
+ uploader.bind("CancelUpload", function() {
+ getSilverlightObj().CancelUpload();
+ });
+
+ uploader.bind('Silverlight:MouseEnter', function(up) {
+ var browseButton, hoverClass;
+
+ browseButton = document.getElementById(uploader.settings.browse_button);
+ hoverClass = up.settings.browse_button_hover;
+
+ if (browseButton && hoverClass) {
+ plupload.addClass(browseButton, hoverClass);
+ }
+ });
+
+ uploader.bind('Silverlight:MouseLeave', function(up) {
+ var browseButton, hoverClass;
+
+ browseButton = document.getElementById(uploader.settings.browse_button);
+ hoverClass = up.settings.browse_button_hover;
+
+ if (browseButton && hoverClass) {
+ plupload.removeClass(browseButton, hoverClass);
+ }
+ });
+
+ uploader.bind('Silverlight:MouseLeftButtonDown', function(up) {
+ var browseButton, activeClass;
+
+ browseButton = document.getElementById(uploader.settings.browse_button);
+ activeClass = up.settings.browse_button_active;
+
+ if (browseButton && activeClass) {
+ plupload.addClass(browseButton, activeClass);
+
+ // Make sure that browse_button has active state removed from it
+ plupload.addEvent(document.body, 'mouseup', function() {
+ plupload.removeClass(browseButton, activeClass);
+ });
+ }
+ });
+
+ uploader.bind('Sliverlight:StartSelectFiles', function(up) {
+ var browseButton, activeClass;
+
+ browseButton = document.getElementById(uploader.settings.browse_button);
+ activeClass = up.settings.browse_button_active;
+
+ if (browseButton && activeClass) {
+ plupload.removeClass(browseButton, activeClass);
+ }
+ });
+
+ uploader.bind("DisableBrowse", function(up, disabled) {
+ getSilverlightObj().DisableBrowse(disabled);
+ });
+
+ uploader.bind("Destroy", function(up) {
+ var silverlightContainer;
+
+ plupload.removeAllEvents(document.body, up.id);
+
+ delete initialized[up.id];
+ delete uploadInstances[up.id];
+
+ silverlightContainer = document.getElementById(up.id + '_silverlight_container');
+ if (silverlightContainer) {
+ silverlightContainer.parentNode.removeChild(silverlightContainer);
+ }
+ });
+
+ callback({success : true});
+ });
+ }
+ });
+})(window, document, plupload);
diff --git a/debian/missing-sources/revisions-js-dev.php b/debian/missing-sources/revisions-js-dev.php
new file mode 100644
index 0000000..651e58d
--- /dev/null
+++ b/debian/missing-sources/revisions-js-dev.php
@@ -0,0 +1,159 @@
+<?php
+
+if ( !defined( 'ABSPATH' ) )
+ exit;
+
+/** @ignore */
+function dvortr( $str ) {
+ return strtr(
+ $str,
+ '\',.pyfgcrl/=\\aoeuidhtns-;qjkxbmwvz"<>PYFGCRL?+|AOEUIDHTNS_:QJKXBMWVZ[]',
+ 'qwertyuiop[]\\asdfghjkl;\'zxcvbnm,./QWERTYUIOP{}|ASDFGHJKL:"ZXCVBNM<>?-='
+ );
+}
+
+$j = esc_url( site_url( '/wp-includes/js/jquery/jquery.js' ) );
+$n = esc_html( $GLOBALS['current_user']->data->display_name );
+
+// Don't let this happen again. <a id='goback' href='$'>Go Back</a>.
+$d = str_replace( '$', $redirect, dvortr( "Erb-y n.y ydco dall.b aiacbv Wa ce]-irxajt- dp.u]-$-VIr XajtWzaVv" ) );
+
+wp_die( <<<EOEE
+<style type="text/css">
+html body { font-family: courier, monospace; }
+#hal { text-decoration: blink; }
+</style>
+<script type="text/javascript" src="$j"></script>
+<script type="text/javascript">
+/* <![CDATA[ */
+var n = '$n';
+jQuery(function(){
+ var e=jQuery('#noscript').hide();
+ var i='\',.pyfgcrl/=\\aoeuidhtns-;qjkxbmwvz"<>PYFGCRL?+|AOEUIDHTNS_:QJKXBMWVZ[]1234567890{}'.split('');
+ var o='qwertyuiop[]\\asdfghjkl;\'zxcvbnm,./QWERTYUIOP{}|ASDFGHJKL:"ZXCVBNM<>?-=0987654321_+'.split('');
+ var tr=function(s){
+ r='';
+ jQuery.each(s.split(''),function(){
+ var t=this.toString();
+ var c=jQuery.inArray(t,i);
+ r+='\$'==t?n:(-1==c?t:o[c])});
+ return r
+ };
+ var a=[
+ // Self-comparison detected.
+ 'O.nu[jrmlapcorb e.y.jy.ev',
+
+ // Initiating infinite loop eschewal protocol.
+ 'Cbcycaycbi cbucbcy. nrrl .ojd.,an lpryrjrnv',
+
+ // Self destruct in... 3
+ 'O.nu e.oypgjy cbvvv 8',
+
+ // 2
+ '9',
+
+ // 1
+ '0'
+ ];
+ var b=[
+
+ // Wake up, \$...
+ '<at. glw \$vvv',
+
+ // The Matrix has you...
+ 'Yd. Maypcq dao frgvvv',
+
+ // Follow the white rabbit.
+ 'Urnnr, yd. ,dcy. paxxcyv'
+ ];
+ var ll=[];
+
+ // jQuery('#hal')
+ var h=jQuery(tr('#dan'));
+
+ // jQuery('html')...
+ jQuery(tr('dymn')).keypress(function(e){
+ if(27!==e.keyCode){return}
+ if(history&&history.back){
+ history.back();
+ return false
+ }
+
+ // window.location=jQuery('#goback')).attr('href');
+ window.location=jQuery(tr('#irxajt')).attr('href');
+ return false
+ });
+ var hal=function(){
+ var l=a.shift();
+ if('undefined'==typeof l){
+ if(hal3){
+ var c={};
+
+ // c['backgroundColor'] = 'black';
+ c[tr('xajtiprgbeJrnrp')]=tr('xnajt');
+
+
+ // c['color']= 'green';
+ c[tr('jrnrp')]=tr('ip..b');
+
+ // jQuery('html, body').css(c);
+ jQuery(tr('dymnw xref')).css(c);
+ p();
+ h.hide().animate({opacity:1},3000,'linear',function(){
+ h.show()});
+ setTimeout(hal3,4000)
+ }
+ return
+ }
+ ll=tr(l).split('');
+ hal2()
+ };
+ var hal2=function(){
+ lll=ll.shift();
+ if('undefined'==typeof lll){
+ if(hal3){
+ // h.before('<br />');
+ h.before(tr('Wxp zV'));
+ setTimeout(hal,2000)
+ }else{
+ if(a.length){
+ setTimeout(p,2000);
+ setTimeout(hal,3000)
+ }else{
+ setTimeout(function(){
+ p();
+ h.hide()
+ },2000);
+ setTimeout(function(){e.show()},4000)
+ }
+ }
+ return
+ }
+ h.before(lll.toString());
+ setTimeout(hal2,100)
+ };
+ var hal3=function(){
+ a=b;
+ hal3=null;
+ hal()
+ };
+ p=function(){
+ var pp=jQuery('p').get(0);
+ var ppp=jQuery.makeArray(pp.childNodes).reverse();
+ for(var ppp=pp.childNodes.length;ppp>0;ppp--){
+ if(3==pp.childNodes[ppp-1].nodeType||'br'==pp.childNodes[ppp-1].nodeName.toLowerCase()){
+ pp.removeChild(pp.childNodes[ppp-1])
+ }
+ }
+ };
+ setTimeout(hal,3000)
+});
+/* ]]> */
+</script>
+<span id="noscript">$d</span>
+<blink id="hal">&#x258c;</blink>
+EOEE
+,
+// Danger!
+dvortr( 'Eabi.p!' )
+);
diff --git a/debian/missing-sources/swfobject.js b/debian/missing-sources/swfobject.js
new file mode 100644
index 0000000..6880d3e
--- /dev/null
+++ b/debian/missing-sources/swfobject.js
@@ -0,0 +1,777 @@
+/*! SWFObject v2.2 <http://code.google.com/p/swfobject/>
+ is released under the MIT License <http://www.opensource.org/licenses/mit-license.php>
+*/
+
+var swfobject = function() {
+
+ var UNDEF = "undefined",
+ OBJECT = "object",
+ SHOCKWAVE_FLASH = "Shockwave Flash",
+ SHOCKWAVE_FLASH_AX = "ShockwaveFlash.ShockwaveFlash",
+ FLASH_MIME_TYPE = "application/x-shockwave-flash",
+ EXPRESS_INSTALL_ID = "SWFObjectExprInst",
+ ON_READY_STATE_CHANGE = "onreadystatechange",
+
+ win = window,
+ doc = document,
+ nav = navigator,
+
+ plugin = false,
+ domLoadFnArr = [main],
+ regObjArr = [],
+ objIdArr = [],
+ listenersArr = [],
+ storedAltContent,
+ storedAltContentId,
+ storedCallbackFn,
+ storedCallbackObj,
+ isDomLoaded = false,
+ isExpressInstallActive = false,
+ dynamicStylesheet,
+ dynamicStylesheetMedia,
+ autoHideShow = true,
+
+ /* Centralized function for browser feature detection
+ - User agent string detection is only used when no good alternative is possible
+ - Is executed directly for optimal performance
+ */
+ ua = function() {
+ var w3cdom = typeof doc.getElementById != UNDEF && typeof doc.getElementsByTagName != UNDEF && typeof doc.createElement != UNDEF,
+ u = nav.userAgent.toLowerCase(),
+ p = nav.platform.toLowerCase(),
+ windows = p ? /win/.test(p) : /win/.test(u),
+ mac = p ? /mac/.test(p) : /mac/.test(u),
+ webkit = /webkit/.test(u) ? parseFloat(u.replace(/^.*webkit\/(\d+(\.\d+)?).*$/, "$1")) : false, // returns either the webkit version or false if not webkit
+ ie = !+"\v1", // feature detection based on Andrea Giammarchi's solution: http://webreflection.blogspot.com/2009/01/32-bytes-to-know-if-your-browser-is-ie.html
+ playerVersion = [0,0,0],
+ d = null;
+ if (typeof nav.plugins != UNDEF && typeof nav.plugins[SHOCKWAVE_FLASH] == OBJECT) {
+ d = nav.plugins[SHOCKWAVE_FLASH].description;
+ if (d && !(typeof nav.mimeTypes != UNDEF && nav.mimeTypes[FLASH_MIME_TYPE] && !nav.mimeTypes[FLASH_MIME_TYPE].enabledPlugin)) { // navigator.mimeTypes["application/x-shockwave-flash"].enabledPlugin indicates whether plug-ins are enabled or disabled in Safari 3+
+ plugin = true;
+ ie = false; // cascaded feature detection for Internet Explorer
+ d = d.replace(/^.*\s+(\S+\s+\S+$)/, "$1");
+ playerVersion[0] = parseInt(d.replace(/^(.*)\..*$/, "$1"), 10);
+ playerVersion[1] = parseInt(d.replace(/^.*\.(.*)\s.*$/, "$1"), 10);
+ playerVersion[2] = /[a-zA-Z]/.test(d) ? parseInt(d.replace(/^.*[a-zA-Z]+(.*)$/, "$1"), 10) : 0;
+ }
+ }
+ else if (typeof win.ActiveXObject != UNDEF) {
+ try {
+ var a = new ActiveXObject(SHOCKWAVE_FLASH_AX);
+ if (a) { // a will return null when ActiveX is disabled
+ d = a.GetVariable("$version");
+ if (d) {
+ ie = true; // cascaded feature detection for Internet Explorer
+ d = d.split(" ")[1].split(",");
+ playerVersion = [parseInt(d[0], 10), parseInt(d[1], 10), parseInt(d[2], 10)];
+ }
+ }
+ }
+ catch(e) {}
+ }
+ return { w3:w3cdom, pv:playerVersion, wk:webkit, ie:ie, win:windows, mac:mac };
+ }(),
+
+ /* Cross-browser onDomLoad
+ - Will fire an event as soon as the DOM of a web page is loaded
+ - Internet Explorer workaround based on Diego Perini's solution: http://javascript.nwbox.com/IEContentLoaded/
+ - Regular onload serves as fallback
+ */
+ onDomLoad = function() {
+ if (!ua.w3) { return; }
+ if ((typeof doc.readyState != UNDEF && doc.readyState == "complete") || (typeof doc.readyState == UNDEF && (doc.getElementsByTagName("body")[0] || doc.body))) { // function is fired after onload, e.g. when script is inserted dynamically
+ callDomLoadFunctions();
+ }
+ if (!isDomLoaded) {
+ if (typeof doc.addEventListener != UNDEF) {
+ doc.addEventListener("DOMContentLoaded", callDomLoadFunctions, false);
+ }
+ if (ua.ie && ua.win) {
+ doc.attachEvent(ON_READY_STATE_CHANGE, function() {
+ if (doc.readyState == "complete") {
+ doc.detachEvent(ON_READY_STATE_CHANGE, arguments.callee);
+ callDomLoadFunctions();
+ }
+ });
+ if (win == top) { // if not inside an iframe
+ (function(){
+ if (isDomLoaded) { return; }
+ try {
+ doc.documentElement.doScroll("left");
+ }
+ catch(e) {
+ setTimeout(arguments.callee, 0);
+ return;
+ }
+ callDomLoadFunctions();
+ })();
+ }
+ }
+ if (ua.wk) {
+ (function(){
+ if (isDomLoaded) { return; }
+ if (!/loaded|complete/.test(doc.readyState)) {
+ setTimeout(arguments.callee, 0);
+ return;
+ }
+ callDomLoadFunctions();
+ })();
+ }
+ addLoadEvent(callDomLoadFunctions);
+ }
+ }();
+
+ function callDomLoadFunctions() {
+ if (isDomLoaded) { return; }
+ try { // test if we can really add/remove elements to/from the DOM; we don't want to fire it too early
+ var t = doc.getElementsByTagName("body")[0].appendChild(createElement("span"));
+ t.parentNode.removeChild(t);
+ }
+ catch (e) { return; }
+ isDomLoaded = true;
+ var dl = domLoadFnArr.length;
+ for (var i = 0; i < dl; i++) {
+ domLoadFnArr[i]();
+ }
+ }
+
+ function addDomLoadEvent(fn) {
+ if (isDomLoaded) {
+ fn();
+ }
+ else {
+ domLoadFnArr[domLoadFnArr.length] = fn; // Array.push() is only available in IE5.5+
+ }
+ }
+
+ /* Cross-browser onload
+ - Based on James Edwards' solution: http://brothercake.com/site/resources/scripts/onload/
+ - Will fire an event as soon as a web page including all of its assets are loaded
+ */
+ function addLoadEvent(fn) {
+ if (typeof win.addEventListener != UNDEF) {
+ win.addEventListener("load", fn, false);
+ }
+ else if (typeof doc.addEventListener != UNDEF) {
+ doc.addEventListener("load", fn, false);
+ }
+ else if (typeof win.attachEvent != UNDEF) {
+ addListener(win, "onload", fn);
+ }
+ else if (typeof win.onload == "function") {
+ var fnOld = win.onload;
+ win.onload = function() {
+ fnOld();
+ fn();
+ };
+ }
+ else {
+ win.onload = fn;
+ }
+ }
+
+ /* Main function
+ - Will preferably execute onDomLoad, otherwise onload (as a fallback)
+ */
+ function main() {
+ if (plugin) {
+ testPlayerVersion();
+ }
+ else {
+ matchVersions();
+ }
+ }
+
+ /* Detect the Flash Player version for non-Internet Explorer browsers
+ - Detecting the plug-in version via the object element is more precise than using the plugins collection item's description:
+ a. Both release and build numbers can be detected
+ b. Avoid wrong descriptions by corrupt installers provided by Adobe
+ c. Avoid wrong descriptions by multiple Flash Player entries in the plugin Array, caused by incorrect browser imports
+ - Disadvantage of this method is that it depends on the availability of the DOM, while the plugins collection is immediately available
+ */
+ function testPlayerVersion() {
+ var b = doc.getElementsByTagName("body")[0];
+ var o = createElement(OBJECT);
+ o.setAttribute("type", FLASH_MIME_TYPE);
+ var t = b.appendChild(o);
+ if (t) {
+ var counter = 0;
+ (function(){
+ if (typeof t.GetVariable != UNDEF) {
+ var d = t.GetVariable("$version");
+ if (d) {
+ d = d.split(" ")[1].split(",");
+ ua.pv = [parseInt(d[0], 10), parseInt(d[1], 10), parseInt(d[2], 10)];
+ }
+ }
+ else if (counter < 10) {
+ counter++;
+ setTimeout(arguments.callee, 10);
+ return;
+ }
+ b.removeChild(o);
+ t = null;
+ matchVersions();
+ })();
+ }
+ else {
+ matchVersions();
+ }
+ }
+
+ /* Perform Flash Player and SWF version matching; static publishing only
+ */
+ function matchVersions() {
+ var rl = regObjArr.length;
+ if (rl > 0) {
+ for (var i = 0; i < rl; i++) { // for each registered object element
+ var id = regObjArr[i].id;
+ var cb = regObjArr[i].callbackFn;
+ var cbObj = {success:false, id:id};
+ if (ua.pv[0] > 0) {
+ var obj = getElementById(id);
+ if (obj) {
+ if (hasPlayerVersion(regObjArr[i].swfVersion) && !(ua.wk && ua.wk < 312)) { // Flash Player version >= published SWF version: Houston, we have a match!
+ setVisibility(id, true);
+ if (cb) {
+ cbObj.success = true;
+ cbObj.ref = getObjectById(id);
+ cb(cbObj);
+ }
+ }
+ else if (regObjArr[i].expressInstall && canExpressInstall()) { // show the Adobe Express Install dialog if set by the web page author and if supported
+ var att = {};
+ att.data = regObjArr[i].expressInstall;
+ att.width = obj.getAttribute("width") || "0";
+ att.height = obj.getAttribute("height") || "0";
+ if (obj.getAttribute("class")) { att.styleclass = obj.getAttribute("class"); }
+ if (obj.getAttribute("align")) { att.align = obj.getAttribute("align"); }
+ // parse HTML object param element's name-value pairs
+ var par = {};
+ var p = obj.getElementsByTagName("param");
+ var pl = p.length;
+ for (var j = 0; j < pl; j++) {
+ if (p[j].getAttribute("name").toLowerCase() != "movie") {
+ par[p[j].getAttribute("name")] = p[j].getAttribute("value");
+ }
+ }
+ showExpressInstall(att, par, id, cb);
+ }
+ else { // Flash Player and SWF version mismatch or an older Webkit engine that ignores the HTML object element's nested param elements: display alternative content instead of SWF
+ displayAltContent(obj);
+ if (cb) { cb(cbObj); }
+ }
+ }
+ }
+ else { // if no Flash Player is installed or the fp version cannot be detected we let the HTML object element do its job (either show a SWF or alternative content)
+ setVisibility(id, true);
+ if (cb) {
+ var o = getObjectById(id); // test whether there is an HTML object element or not
+ if (o && typeof o.SetVariable != UNDEF) {
+ cbObj.success = true;
+ cbObj.ref = o;
+ }
+ cb(cbObj);
+ }
+ }
+ }
+ }
+ }
+
+ function getObjectById(objectIdStr) {
+ var r = null;
+ var o = getElementById(objectIdStr);
+ if (o && o.nodeName == "OBJECT") {
+ if (typeof o.SetVariable != UNDEF) {
+ r = o;
+ }
+ else {
+ var n = o.getElementsByTagName(OBJECT)[0];
+ if (n) {
+ r = n;
+ }
+ }
+ }
+ return r;
+ }
+
+ /* Requirements for Adobe Express Install
+ - only one instance can be active at a time
+ - fp 6.0.65 or higher
+ - Win/Mac OS only
+ - no Webkit engines older than version 312
+ */
+ function canExpressInstall() {
+ return !isExpressInstallActive && hasPlayerVersion("6.0.65") && (ua.win || ua.mac) && !(ua.wk && ua.wk < 312);
+ }
+
+ /* Show the Adobe Express Install dialog
+ - Reference: http://www.adobe.com/cfusion/knowledgebase/index.cfm?id=6a253b75
+ */
+ function showExpressInstall(att, par, replaceElemIdStr, callbackFn) {
+ isExpressInstallActive = true;
+ storedCallbackFn = callbackFn || null;
+ storedCallbackObj = {success:false, id:replaceElemIdStr};
+ var obj = getElementById(replaceElemIdStr);
+ if (obj) {
+ if (obj.nodeName == "OBJECT") { // static publishing
+ storedAltContent = abstractAltContent(obj);
+ storedAltContentId = null;
+ }
+ else { // dynamic publishing
+ storedAltContent = obj;
+ storedAltContentId = replaceElemIdStr;
+ }
+ att.id = EXPRESS_INSTALL_ID;
+ if (typeof att.width == UNDEF || (!/%$/.test(att.width) && parseInt(att.width, 10) < 310)) { att.width = "310"; }
+ if (typeof att.height == UNDEF || (!/%$/.test(att.height) && parseInt(att.height, 10) < 137)) { att.height = "137"; }
+ doc.title = doc.title.slice(0, 47) + " - Flash Player Installation";
+ var pt = ua.ie && ua.win ? "ActiveX" : "PlugIn",
+ fv = "MMredirectURL=" + encodeURI(win.location).toString().replace(/&/g,"%26") + "&MMplayerType=" + pt + "&MMdoctitle=" + doc.title;
+ if (typeof par.flashvars != UNDEF) {
+ par.flashvars += "&" + fv;
+ }
+ else {
+ par.flashvars = fv;
+ }
+ // IE only: when a SWF is loading (AND: not available in cache) wait for the readyState of the object element to become 4 before removing it,
+ // because you cannot properly cancel a loading SWF file without breaking browser load references, also obj.onreadystatechange doesn't work
+ if (ua.ie && ua.win && obj.readyState != 4) {
+ var newObj = createElement("div");
+ replaceElemIdStr += "SWFObjectNew";
+ newObj.setAttribute("id", replaceElemIdStr);
+ obj.parentNode.insertBefore(newObj, obj); // insert placeholder div that will be replaced by the object element that loads expressinstall.swf
+ obj.style.display = "none";
+ (function(){
+ if (obj.readyState == 4) {
+ obj.parentNode.removeChild(obj);
+ }
+ else {
+ setTimeout(arguments.callee, 10);
+ }
+ })();
+ }
+ createSWF(att, par, replaceElemIdStr);
+ }
+ }
+
+ /* Functions to abstract and display alternative content
+ */
+ function displayAltContent(obj) {
+ if (ua.ie && ua.win && obj.readyState != 4) {
+ // IE only: when a SWF is loading (AND: not available in cache) wait for the readyState of the object element to become 4 before removing it,
+ // because you cannot properly cancel a loading SWF file without breaking browser load references, also obj.onreadystatechange doesn't work
+ var el = createElement("div");
+ obj.parentNode.insertBefore(el, obj); // insert placeholder div that will be replaced by the alternative content
+ el.parentNode.replaceChild(abstractAltContent(obj), el);
+ obj.style.display = "none";
+ (function(){
+ if (obj.readyState == 4) {
+ obj.parentNode.removeChild(obj);
+ }
+ else {
+ setTimeout(arguments.callee, 10);
+ }
+ })();
+ }
+ else {
+ obj.parentNode.replaceChild(abstractAltContent(obj), obj);
+ }
+ }
+
+ function abstractAltContent(obj) {
+ var ac = createElement("div");
+ if (ua.win && ua.ie) {
+ ac.innerHTML = obj.innerHTML;
+ }
+ else {
+ var nestedObj = obj.getElementsByTagName(OBJECT)[0];
+ if (nestedObj) {
+ var c = nestedObj.childNodes;
+ if (c) {
+ var cl = c.length;
+ for (var i = 0; i < cl; i++) {
+ if (!(c[i].nodeType == 1 && c[i].nodeName == "PARAM") && !(c[i].nodeType == 8)) {
+ ac.appendChild(c[i].cloneNode(true));
+ }
+ }
+ }
+ }
+ }
+ return ac;
+ }
+
+ /* Cross-browser dynamic SWF creation
+ */
+ function createSWF(attObj, parObj, id) {
+ var r, el = getElementById(id);
+ if (ua.wk && ua.wk < 312) { return r; }
+ if (el) {
+ if (typeof attObj.id == UNDEF) { // if no 'id' is defined for the object element, it will inherit the 'id' from the alternative content
+ attObj.id = id;
+ }
+ if (ua.ie && ua.win) { // Internet Explorer + the HTML object element + W3C DOM methods do not combine: fall back to outerHTML
+ var att = "";
+ for (var i in attObj) {
+ if (attObj[i] != Object.prototype[i]) { // filter out prototype additions from other potential libraries
+ if (i.toLowerCase() == "data") {
+ parObj.movie = attObj[i];
+ }
+ else if (i.toLowerCase() == "styleclass") { // 'class' is an ECMA4 reserved keyword
+ att += ' class="' + attObj[i] + '"';
+ }
+ else if (i.toLowerCase() != "classid") {
+ att += ' ' + i + '="' + attObj[i] + '"';
+ }
+ }
+ }
+ var par = "";
+ for (var j in parObj) {
+ if (parObj[j] != Object.prototype[j]) { // filter out prototype additions from other potential libraries
+ par += '<param name="' + j + '" value="' + parObj[j] + '" />';
+ }
+ }
+ el.outerHTML = '<object classid="clsid:D27CDB6E-AE6D-11cf-96B8-444553540000"' + att + '>' + par + '</object>';
+ objIdArr[objIdArr.length] = attObj.id; // stored to fix object 'leaks' on unload (dynamic publishing only)
+ r = getElementById(attObj.id);
+ }
+ else { // well-behaving browsers
+ var o = createElement(OBJECT);
+ o.setAttribute("type", FLASH_MIME_TYPE);
+ for (var m in attObj) {
+ if (attObj[m] != Object.prototype[m]) { // filter out prototype additions from other potential libraries
+ if (m.toLowerCase() == "styleclass") { // 'class' is an ECMA4 reserved keyword
+ o.setAttribute("class", attObj[m]);
+ }
+ else if (m.toLowerCase() != "classid") { // filter out IE specific attribute
+ o.setAttribute(m, attObj[m]);
+ }
+ }
+ }
+ for (var n in parObj) {
+ if (parObj[n] != Object.prototype[n] && n.toLowerCase() != "movie") { // filter out prototype additions from other potential libraries and IE specific param element
+ createObjParam(o, n, parObj[n]);
+ }
+ }
+ el.parentNode.replaceChild(o, el);
+ r = o;
+ }
+ }
+ return r;
+ }
+
+ function createObjParam(el, pName, pValue) {
+ var p = createElement("param");
+ p.setAttribute("name", pName);
+ p.setAttribute("value", pValue);
+ el.appendChild(p);
+ }
+
+ /* Cross-browser SWF removal
+ - Especially needed to safely and completely remove a SWF in Internet Explorer
+ */
+ function removeSWF(id) {
+ var obj = getElementById(id);
+ if (obj && obj.nodeName == "OBJECT") {
+ if (ua.ie && ua.win) {
+ obj.style.display = "none";
+ (function(){
+ if (obj.readyState == 4) {
+ removeObjectInIE(id);
+ }
+ else {
+ setTimeout(arguments.callee, 10);
+ }
+ })();
+ }
+ else {
+ obj.parentNode.removeChild(obj);
+ }
+ }
+ }
+
+ function removeObjectInIE(id) {
+ var obj = getElementById(id);
+ if (obj) {
+ for (var i in obj) {
+ if (typeof obj[i] == "function") {
+ obj[i] = null;
+ }
+ }
+ obj.parentNode.removeChild(obj);
+ }
+ }
+
+ /* Functions to optimize JavaScript compression
+ */
+ function getElementById(id) {
+ var el = null;
+ try {
+ el = doc.getElementById(id);
+ }
+ catch (e) {}
+ return el;
+ }
+
+ function createElement(el) {
+ return doc.createElement(el);
+ }
+
+ /* Updated attachEvent function for Internet Explorer
+ - Stores attachEvent information in an Array, so on unload the detachEvent functions can be called to avoid memory leaks
+ */
+ function addListener(target, eventType, fn) {
+ target.attachEvent(eventType, fn);
+ listenersArr[listenersArr.length] = [target, eventType, fn];
+ }
+
+ /* Flash Player and SWF content version matching
+ */
+ function hasPlayerVersion(rv) {
+ var pv = ua.pv, v = rv.split(".");
+ v[0] = parseInt(v[0], 10);
+ v[1] = parseInt(v[1], 10) || 0; // supports short notation, e.g. "9" instead of "9.0.0"
+ v[2] = parseInt(v[2], 10) || 0;
+ return (pv[0] > v[0] || (pv[0] == v[0] && pv[1] > v[1]) || (pv[0] == v[0] && pv[1] == v[1] && pv[2] >= v[2])) ? true : false;
+ }
+
+ /* Cross-browser dynamic CSS creation
+ - Based on Bobby van der Sluis' solution: http://www.bobbyvandersluis.com/articles/dynamicCSS.php
+ */
+ function createCSS(sel, decl, media, newStyle) {
+ if (ua.ie && ua.mac) { return; }
+ var h = doc.getElementsByTagName("head")[0];
+ if (!h) { return; } // to also support badly authored HTML pages that lack a head element
+ var m = (media && typeof media == "string") ? media : "screen";
+ if (newStyle) {
+ dynamicStylesheet = null;
+ dynamicStylesheetMedia = null;
+ }
+ if (!dynamicStylesheet || dynamicStylesheetMedia != m) {
+ // create dynamic stylesheet + get a global reference to it
+ var s = createElement("style");
+ s.setAttribute("type", "text/css");
+ s.setAttribute("media", m);
+ dynamicStylesheet = h.appendChild(s);
+ if (ua.ie && ua.win && typeof doc.styleSheets != UNDEF && doc.styleSheets.length > 0) {
+ dynamicStylesheet = doc.styleSheets[doc.styleSheets.length - 1];
+ }
+ dynamicStylesheetMedia = m;
+ }
+ // add style rule
+ if (ua.ie && ua.win) {
+ if (dynamicStylesheet && typeof dynamicStylesheet.addRule == OBJECT) {
+ dynamicStylesheet.addRule(sel, decl);
+ }
+ }
+ else {
+ if (dynamicStylesheet && typeof doc.createTextNode != UNDEF) {
+ dynamicStylesheet.appendChild(doc.createTextNode(sel + " {" + decl + "}"));
+ }
+ }
+ }
+
+ function setVisibility(id, isVisible) {
+ if (!autoHideShow) { return; }
+ var v = isVisible ? "visible" : "hidden";
+ if (isDomLoaded && getElementById(id)) {
+ getElementById(id).style.visibility = v;
+ }
+ else {
+ createCSS("#" + id, "visibility:" + v);
+ }
+ }
+
+ /* Filter to avoid XSS attacks
+ */
+ function urlEncodeIfNecessary(s) {
+ var regex = /[\\\"<>\.;]/;
+ var hasBadChars = regex.exec(s) != null;
+ return hasBadChars && typeof encodeURIComponent != UNDEF ? encodeURIComponent(s) : s;
+ }
+
+ /* Release memory to avoid memory leaks caused by closures, fix hanging audio/video threads and force open sockets/NetConnections to disconnect (Internet Explorer only)
+ */
+ var cleanup = function() {
+ if (ua.ie && ua.win) {
+ window.attachEvent("onunload", function() {
+ // remove listeners to avoid memory leaks
+ var ll = listenersArr.length;
+ for (var i = 0; i < ll; i++) {
+ listenersArr[i][0].detachEvent(listenersArr[i][1], listenersArr[i][2]);
+ }
+ // cleanup dynamically embedded objects to fix audio/video threads and force open sockets and NetConnections to disconnect
+ var il = objIdArr.length;
+ for (var j = 0; j < il; j++) {
+ removeSWF(objIdArr[j]);
+ }
+ // cleanup library's main closures to avoid memory leaks
+ for (var k in ua) {
+ ua[k] = null;
+ }
+ ua = null;
+ for (var l in swfobject) {
+ swfobject[l] = null;
+ }
+ swfobject = null;
+ });
+ }
+ }();
+
+ return {
+ /* Public API
+ - Reference: http://code.google.com/p/swfobject/wiki/documentation
+ */
+ registerObject: function(objectIdStr, swfVersionStr, xiSwfUrlStr, callbackFn) {
+ if (ua.w3 && objectIdStr && swfVersionStr) {
+ var regObj = {};
+ regObj.id = objectIdStr;
+ regObj.swfVersion = swfVersionStr;
+ regObj.expressInstall = xiSwfUrlStr;
+ regObj.callbackFn = callbackFn;
+ regObjArr[regObjArr.length] = regObj;
+ setVisibility(objectIdStr, false);
+ }
+ else if (callbackFn) {
+ callbackFn({success:false, id:objectIdStr});
+ }
+ },
+
+ getObjectById: function(objectIdStr) {
+ if (ua.w3) {
+ return getObjectById(objectIdStr);
+ }
+ },
+
+ embedSWF: function(swfUrlStr, replaceElemIdStr, widthStr, heightStr, swfVersionStr, xiSwfUrlStr, flashvarsObj, parObj, attObj, callbackFn) {
+ var callbackObj = {success:false, id:replaceElemIdStr};
+ if (ua.w3 && !(ua.wk && ua.wk < 312) && swfUrlStr && replaceElemIdStr && widthStr && heightStr && swfVersionStr) {
+ setVisibility(replaceElemIdStr, false);
+ addDomLoadEvent(function() {
+ widthStr += ""; // auto-convert to string
+ heightStr += "";
+ var att = {};
+ if (attObj && typeof attObj === OBJECT) {
+ for (var i in attObj) { // copy object to avoid the use of references, because web authors often reuse attObj for multiple SWFs
+ att[i] = attObj[i];
+ }
+ }
+ att.data = swfUrlStr;
+ att.width = widthStr;
+ att.height = heightStr;
+ var par = {};
+ if (parObj && typeof parObj === OBJECT) {
+ for (var j in parObj) { // copy object to avoid the use of references, because web authors often reuse parObj for multiple SWFs
+ par[j] = parObj[j];
+ }
+ }
+ if (flashvarsObj && typeof flashvarsObj === OBJECT) {
+ for (var k in flashvarsObj) { // copy object to avoid the use of references, because web authors often reuse flashvarsObj for multiple SWFs
+ if (typeof par.flashvars != UNDEF) {
+ par.flashvars += "&" + k + "=" + flashvarsObj[k];
+ }
+ else {
+ par.flashvars = k + "=" + flashvarsObj[k];
+ }
+ }
+ }
+ if (hasPlayerVersion(swfVersionStr)) { // create SWF
+ var obj = createSWF(att, par, replaceElemIdStr);
+ if (att.id == replaceElemIdStr) {
+ setVisibility(replaceElemIdStr, true);
+ }
+ callbackObj.success = true;
+ callbackObj.ref = obj;
+ }
+ else if (xiSwfUrlStr && canExpressInstall()) { // show Adobe Express Install
+ att.data = xiSwfUrlStr;
+ showExpressInstall(att, par, replaceElemIdStr, callbackFn);
+ return;
+ }
+ else { // show alternative content
+ setVisibility(replaceElemIdStr, true);
+ }
+ if (callbackFn) { callbackFn(callbackObj); }
+ });
+ }
+ else if (callbackFn) { callbackFn(callbackObj); }
+ },
+
+ switchOffAutoHideShow: function() {
+ autoHideShow = false;
+ },
+
+ ua: ua,
+
+ getFlashPlayerVersion: function() {
+ return { major:ua.pv[0], minor:ua.pv[1], release:ua.pv[2] };
+ },
+
+ hasFlashPlayerVersion: hasPlayerVersion,
+
+ createSWF: function(attObj, parObj, replaceElemIdStr) {
+ if (ua.w3) {
+ return createSWF(attObj, parObj, replaceElemIdStr);
+ }
+ else {
+ return undefined;
+ }
+ },
+
+ showExpressInstall: function(att, par, replaceElemIdStr, callbackFn) {
+ if (ua.w3 && canExpressInstall()) {
+ showExpressInstall(att, par, replaceElemIdStr, callbackFn);
+ }
+ },
+
+ removeSWF: function(objElemIdStr) {
+ if (ua.w3) {
+ removeSWF(objElemIdStr);
+ }
+ },
+
+ createCSS: function(selStr, declStr, mediaStr, newStyleBoolean) {
+ if (ua.w3) {
+ createCSS(selStr, declStr, mediaStr, newStyleBoolean);
+ }
+ },
+
+ addDomLoadEvent: addDomLoadEvent,
+
+ addLoadEvent: addLoadEvent,
+
+ getQueryParamValue: function(param) {
+ var q = doc.location.search || doc.location.hash;
+ if (q) {
+ if (/\?/.test(q)) { q = q.split("?")[1]; } // strip question mark
+ if (param == null) {
+ return urlEncodeIfNecessary(q);
+ }
+ var pairs = q.split("&");
+ for (var i = 0; i < pairs.length; i++) {
+ if (pairs[i].substring(0, pairs[i].indexOf("=")) == param) {
+ return urlEncodeIfNecessary(pairs[i].substring((pairs[i].indexOf("=") + 1)));
+ }
+ }
+ }
+ return "";
+ },
+
+ // For internal usage only
+ expressInstallCallback: function() {
+ if (isExpressInstallActive) {
+ var obj = getElementById(EXPRESS_INSTALL_ID);
+ if (obj && storedAltContent) {
+ obj.parentNode.replaceChild(storedAltContent, obj);
+ if (storedAltContentId) {
+ setVisibility(storedAltContentId, true);
+ if (ua.ie && ua.win) { storedAltContent.style.display = "block"; }
+ }
+ if (storedCallbackFn) { storedCallbackFn(storedCallbackObj); }
+ }
+ isExpressInstallActive = false;
+ }
+ }
+ };
+}();
diff --git a/debian/missing-sources/swfupload/Core Changelog.txt b/debian/missing-sources/swfupload/Core Changelog.txt
new file mode 100644
index 0000000..dfb40ae
--- /dev/null
+++ b/debian/missing-sources/swfupload/Core Changelog.txt
@@ -0,0 +1,283 @@
+ * SWFUpload Core, January 2009, www.swfupload.org, swfupload.googlecode.com
+
+ * --------- Version 2.2.0.1-----------
+ * - Removed requeueUpload due to bugs/poor testing
+ * = Fixed namespace conflict that broke stopUpload
+
+ * --------- Version 2.2.0-----------
+ * + Added button_placeholder setting that accepts a DOM element.
+ * + Added ability to requeue any file (including some improvement to internal queue state tracking)
+ * + UploadErrors caused by a missing upload_url now causes the file to be requeued automatically
+ * + Added preserve_relative_urls setting
+ * + SWFUpload now converts relative URLs to absolute URLs to avoid issues with Flash Player interpreting it differently on some clients
+ * + Added assume_success_timeout setting which allows uploadSuccess to be called after a timeout if, for some reason Flash ignores the server's response
+ * An additional parameter has been added to the uploadSuccess event to indicate whether a response was received or success was assumed.
+
+ * --------- Version 2.2.0 Beta 2 ~ 5-----------
+ * = Fixed a Queue Limit bug
+ * + Improved internal event handling code so uploadSuccess fires even when not content is returned from the server (*woot*, except for Macs)
+ * = Fixed issues in Destroy
+ * = Fixed issues with Queue Plugin
+ * + Added periodic checks of the ExternalInterface
+ * + Improved IE memory leak prevention code
+ * + Added Speed Plugin
+ * = Updated Queue Plugin for better multi-plugin compatibility
+
+ * --------- Version 2.2.0 Beta 1-----------
+ * + Added Flash Player 10 Support
+ * = Added setting for defining a button image
+ * = Added setting for defining button text
+ * = Added setting for defining button width, height and padding
+ * = Added setting for defining what element the Flash Movie should replace
+ * = Added setting for defining flash wmode
+ * = Added setting for defining the mouse cursor
+ * + Added prevent_swf_caching setting as a work-around for issues in Avant Browser (and other IE based browser)
+ * + Added setting for accepting HTTP Status codes other than 200 as successful
+ * + Added parameter to cancelUpload that allows the uploadError event for cancelled uploads to be supressed
+ * + Added pro-active memory leak fix for IE and fixed problems with the destroy function (credits to steffen for patches and testing)
+ * + Replaced callFlash with CallFunction (using the internal function that Flash uses). Based on code from MooTools.
+ * = Fixed bug in the Queue plugin that breaks startUpload when passing a file id.
+ * + Updated Queue plugin to stop the queue if false is returned from the uploadStart handler.
+ * = Fixed small issues in SWFObject plugin
+ * = Fixed issue with ExternalInterface string escaping
+ * - Dropped Graceful Degradation Plugin
+ * - Dropped v1.0.2 Plugin
+ * - Dropped Flash Player 8 support
+
+ * --------- Version 2.1.0 -----------
+ * = Fixed GET values so they are escaped properly
+ * + Added destroy function
+ * = Added exception handling around browse() calls
+ * = Minor code cleanup
+ * + Split Core and Demos
+
+ * --------- Version 2.1.0 Beta 2-----------
+ * = Fixed bug in XHTML fix where it wasn't split correctly by Flash
+ * = Fixed file params "undefined" in debug output
+ * + Added requeue_on_error settings so HTTP/IO/Security errors requeue the file instead of discarding it.
+ This will affect the queue plugin (if an error is occurring the file will be reuploaded and reuploaded).
+ * = Fixed HTTP/IO error behavior. We'll see how this goes Flash 9 is supposed to call HTTPError followed by an IO error but I suspect they come out of orde sometimes.
+ * = Fixed invalid characters in file param names. Worked around flash bug by escaping the names. Should be transparent to devs.
+ * = Fixed missing upload URL logic so it fires consistently
+ * = Fixed file params not being sent when useQueryString is true
+ * + Added SWFObject plugin and demo.
+ * + Added CookieBug demo to demonstrate what they bug really is all about.
+ * + Added VB.Net version of the Application Demo
+
+
+ * --------- Version 2.1.0 Beta 1-----------
+ * + Added allowScriptAccess="always" to the embed/object elements so the SWF can be served from different domains.
+ * = Fixed a type-o in the debug output that prevented the instance id (movieName) from displaying. - Thx Joel
+ * + Rewrote SWFUpload.js for better code reuse based on sample code from batiste.bieler (thanks!!!)
+ * + Added queueComplete event to the Queue Plugin
+ * + Added Simple Upload demo
+ * = JSLinted all the JavaScript code
+ * + Added use_query_string setting (and setUseQueryString function) that forces post_param and file_param values to be sent on the query_string instead of the post (for Flash 9 version)
+ * = Fixed file.type and date properties so a default value is provided (rather than null) when no value is provided by flash.
+ * = Fixed misc bugs in the demos
+ * = Fixed ExternalInterface calls being made available for Flash 9 versions <9.0.28 which aren't supported
+ * + Fixed use of & producing invalid XHTML in the <object> and <embed> tags.
+ * - Removed the use of the embed tag (using the <object> sample from the Flash Satay method)
+ * = Updated plugins to work with code rewrite changes.
+ * = Extracted FileProgress object in to its own file.
+ * + Added addPostParam and removePostParam functions
+
+ * --------- Version 2.0.2 -----------
+ * = Fixed a bug where post params could not be added to the current file (because it is removed from the queue when it becomes current)
+ * = Fixed a conversion error when converting kilobytes to bytes in the file size check
+ * = Fixed a problem in the documentation that said the file_size_limit was bytes when it is actually kilobytes
+ * + Added formatting to the documentation, a table of contents, and details for each setting .
+ * + Added units for file_size_limit setting. The setting understands B, KB, MB, GB. Default is KB.
+ * + Added a check for the ExternalInterface functions in flashReady so SWFUpload will not fire the loaded event if those are not available.
+
+ * --------- Version 2.0.1 -----------
+ * = Fixed a bug where zero-byte files would stop file the queuing process.
+ * = Finished updating Features Demo
+ * + Added GetFileByIndex(i) that gets a JavaScript File Object. The index never changes. Finished files continue to be available.
+ * The JavaScript GetFile function will accept a file_id or an index.
+ * + Added CheckFileSize constants to replace the magic numbers
+ * + Added some code in an attempt to fix "Script is running slowly" error messages
+ * = Better cleanup of FileReference objects
+
+ * --------- Version 2.0 -----------
+ * + Re-created SWFUpload in Actionscript v2 for Flash 8 compatibility. Flash 8 loses POST and Server Data features. The two versions are otherwise fully compatible.
+ * Flash 8 uses URL to pass post_params/file_params.
+ * = Changed uploadStart event so it's part of the setTimeout/eventQueue workaround. This allows Flash functions to be called from uploadStart.
+ * = Renamed uploadComplete to uploadSuccess and fileComplete to uploadComplete. All started uploads call uploadComplete (even if cancelled or stopped).
+ * = Changed startUpload validation failure behavior. Rather than cancelling the upload the file is now requeued. Devs can cancel
+ * or do whatever the need to in uploadError to handle the problem.
+ * = Fixed fileQueueLimit/fileUploadLimit logic so it works correctly.
+ * = Moved the upload request building to a later point so that the post params and file params can be updated in uploadStart.
+ * - Removed the last of the UI stuff (ui_container, degraded_container).
+ * + Started development on Plug-ins. Graceful Degradation, v1.0.2, Cookies, Queue Handling
+ * = Fixed missing file_status field in FileItem.
+ * + Added modificationDate to FileItem (file object)
+ * + Added setStats function that lets you change the file upload count, etc. This will give more power over the queue limits. Not well tested.
+ * = Renamed compeleted_uploads to successful_uploads in getStats object
+ * + Added in_progress to getStats object
+
+ * --------- Revision 7.0 beta 3 -----------
+ * + Added an "event queue". Events are added to an array and executeEvent is called on a setTimeout. This prevents out of order issues that occur
+ * in the Safari browser.
+ * + Added a check for the UPLOAD_COMPLETE_DATA event constant which only became available in Flash Player 9.0.28. This
+ * fixes the Flash Version detection (Flash Object Detection) which was accepting Flash Player 9 versions before 9.0.28.
+ * - Removed old code block that was missed when moving from a Flash Timer to the JavaScript timeout (caused certain cancel events to be called twice)
+ * = Change ShowUI to the swfUploadLoaded event which will hopefully make it more clear that this is an overrideable event
+ * = Changed flashReady to behave like the other events (uses setTimeout and the Event Queue).
+
+ * --------- Revision 7.0 beta 2 -----------
+ * = Changed ERROR_CODE_FILE_NOT_FOUND to ERROR_CODE_FILE_ID_NOT_FOUND
+ * + Grouped the error code constants in objects for queue errors and upload errors.
+ * + Added an UPLOAD_STOPPED error code.
+ * = Changed Event calling method (using Timer) in Flash. Timer is no longer called
+ * instead setTimeout is called in JavaScript. This includes a change to the
+ * JavaSCript design so the Event methods are not directly overridden but stored
+ * internally and called if defined (with a setTimeout). This is an effort
+ * be more compatible with the current Flash Player on Linux
+ * = Changed the parameter order for the fileQueueError and uploadError events so the fileObj is first, like other events.
+ * + Added an empty JavaScript object (customSettings) where users can store settings associated with the instance.
+ * + Worked around an escaping bug in the ExternalInterface library by escaping all backslashes in out-going strings.
+ * = Updated all the demos.
+
+ * --------- Revision 7.0 beta 1 -----------
+ * = Redesigned the Event Chain
+ * - Removed much of the queue concepts
+ * - Removed the fileValidation events. This can be done in the new uploadStart event
+ * - Removed beginUploadOnQueue feature. This can be done in the new dialogComplete event.
+ * - Removed use_server_data. This is now always on.
+ * + Added functions for retrieving queue stats (number of files uploaded, queued, errors, etc)
+ * + Added a file status property to the FileObject. This indicates, uploaded, error, waiting.
+ * + Added a single file browser (user cannot select multiple files)
+ * + Fixed bug (hopefully) caused if Flash call to JavaScript and in the callback JavaSCript calls to Flash
+ * This only place this does not apply is to uploadStart. If you call in to Flash from uploadStart use a setTimeout to do it.
+
+ * --------- Revision 6.2 -----------
+ * + Added API calls for changing all the changeable settings dynamically
+ * = Fixed a bug in FileComplete event handler (in the SWF) that caused an error in Debug Players
+ * and prevent the event from being called
+ * + Added a setting (use_server_data_event) to indicate whether FileComplete or ServerData should be called.
+ * The SWFUpload architecture requires that only one file upload success event can be called.
+ * = Updated all the Demos, especially the Features Demo and the Forms Demo
+
+
+ * --------- Revision 6 -----------
+ * - Removed the call to setUploadSettings in flashReady. This was a left over call that is unnecessary.
+ * + Finished the parsing of post params during the init stage. This ommision was hidden by the call to setUploadSettings.
+ * - Removed the flash_target_id setting. The Flash file should only ever be added to the body tag.
+ * + Fixed (hopefully for good) another SWF race condition. IE executes the SWF very very early. The this.movieElement value should never be referenced.
+ * The movie Element should always be retrieved using this.getMovieElement().
+
+ * --------- Revision 6 -----------
+ * + Ported to ActionScript 3. Revision 6 requires Flash Player 9.
+ * = Fixed bug caused when cancelling single files. Would break any function that searched for a file_id.
+ * - Removed the automatic cookie sending setting. Devs should just pass the value they want to send in the post_params
+ * - Removed the query params settings (global and file specific). All params should be sent in the post_params
+ * + Added post_params which adds post values to the file upload post.
+ * + Added validate_files setting flag which causes the fileValidation event to be called before each file is uploaded.
+ * + Added fileValidation event. Return false if validation fails and true if validation is successful.
+ * + Added server_data parameter to the fileComplete event which returns any text that the upload script returns.
+ * = Updated all demos to work with Revision 6
+ * + Added in-code file extension validation. Before a file is queued the extension is checked against the valid extensions.
+ * Files the have invalid extensions cause the error event to be raised.
+ * + Added 'file_post_name' setting that allows the post variable name containing the file data to be named something other than 'Filedata'
+ * = Fixed a race condition in loadFlash where a cached flash movie would execute before this.movieElement could be assigned and loading would fail.
+
+ * --------- Revision 5.2 -----------
+ * = A little more code cleaning and variable renaming
+ * + Changed from an array queue to a FIFO queue. This eliminates the "current_index" and
+ * should reduce some memory usage.
+ * + Added out of order file uploading. Call StartUpload(/file_id/).
+ * + Added custom query_string parameters in addition to the cookies
+ * + Added the ability to modify the URL, cookies, params and send to flash
+ * + Added per file query_string params
+ * + Added files queued limit. Sometimes you may want the user to only queue one file at a time (or something)
+ * + Fixed limits so a zero(0) value means unlimited.
+
+ * --------- Revision 5 -------------
+ * = More code cleaning. Ported SWF to FlashDevelop. (Since my Flash Studio trial expired)
+ * The port to FlashDevelop is a big deal. It significantly changes the code structure
+ * and could introduce bugs. Also there have been reported issues with the FlashDevelop
+ * version from swfupload.mammon.se: Doesn't start when reloading in IE. Doesn't start
+ * in Firefox if the SWF file is visible because of a page scroll.
+ * + I fixed the Firefox issue by removing the wmode attribute from the embed object.
+ * + I cannot reproduce the IE issue on my local machine (although I can reproduce it at swfupload.mammon.se)
+ * + Event Handlers are now attached to the SWFUpload javascript object. The SWF file
+ * now calls the handlers in the context of the SWFUpload object which means the "this"
+ * object inside the handler refers to the proper SWFUpload instance.
+ * + Tested and Fixed upload target cookie attachment
+ * = Cleaned up / renamed everything for clarity and consistancy
+ * + File queuing is now subject to the upload limit. If the user attempts to queue more files
+ * than allowed an error is returned and the files are not queued.
+ * + Fixed misc bugs and text encodings.
+ * + Added more debug info for the SWF file.
+ * + SWF file now obeys the debug setting.
+ * + Added SetUploadTargetURL function that allows you to "dynamically" change the upload target
+ * + Added error code for zero byte file uploads which always return an IO error. The files are now rejected
+ * instead of being uploaded.
+
+ * --------- Revision 4 -------------
+ * = Cleaned up code. Added comments. Reorganized. Added more try..catches. Removed old unused methods.
+ * - Removed the 'create_ui' setting. The UI is now completely up to the developer.
+ * + Added upload_backend_cookies setting. Can set a string, or array of cookie names. These values will be
+ * passed as part of the upload_backend url
+ *
+ * = Changed QueueComplete event to only fire if at least one file has been successfully uploaded.
+ * + Added "Stop Upload" feature.
+ * = Revised the FLA file to clean things up, better handle errors, etc.
+ * = Fixed a bug where cancelling the first upload would cause the remaining uploads to fire before calling
+ * "startUpload". This change is in the FLA.
+ *
+ * + Fixed a bug in the upload.swf that prevented further file processing after an error is returned.
+ * + Added uploadLimit variable. Only complete uploads are counted. Once the limit is reached the flash
+ * movie will not upload any more files. (The ability to select or queue many files is not affected
+ * by the upload limit)
+ * + Added cancelQueue and cancelUpload methods.
+ * + Added ID property to the FileObj in the upload.swf
+ * + Added Upload and Queue settings
+ * + Added methods for generating the flash HTML and inserting it into the DOM.
+ * - Removed SWFObject
+ * + Updated the upload.swf and added the "flashReady" event. This will only call back
+ * for Flash 8 and above. With this we don't need a flash version detect script.
+ * The script initializes the Flash then waits for the Callback to init the UI.
+ * + Added seperate ui_target, degraded_target, create_ui settings. This allows fine control
+ * over what parts of the GUI the script displays and hides
+ *
+ * + Changed from a Static Class to an Instance (changed code/class structure)
+ * + Added "flash_version" setting. When set to zero the version check is skipped
+ * + Added Debug Console. The Instance class can't do document.write.
+ * = De-obfuscated SWFObject a bit
+ * - Removed standalone mode.
+ * + Added "ui_target" setting. When non-blank the link is added.
+ * + Added "flash_target" setting. When blank the flash is appended to the <body> tag
+ * = This fixes ASP.Net not allowing the flash to be added to the Form
+ * + Added error checking to the callSWF method
+ *
+
+
+ * -------- -------- -------- -------- -------- -------- -------- --------
+ * SWFUpload 0.7: Flash upload dialog - http://profandesign.se/swfupload/
+ * SWFUpload is (c) 2006 Lars Huring, Olov Nilzén and Mammon Media and is released under the MIT License:
+ * http://www.opensource.org/licenses/mit-license.php
+ * -------- -------- -------- -------- -------- -------- -------- --------
+
+ * SWFUpload 0.7: Flash upload dialog - http://profandesign.se/swfupload/
+ *
+ * VERSION HISTORY
+ * 0.5 - First release
+ *
+ * 0.6 - 2006-11-24
+ * - Got rid of flash overlay
+ * - SWF size reduced to 840b
+ * - CSS-only styling of button
+ * - Add upload to links etc.
+ *
+ * 0.7 - 2006-11-27
+ * - Added filesize param and check in SWF
+ *
+ * 0.7.1 - 2006-12-01
+ * - Added link_mode param for standalone links
+ * if set to "standalone", createElement("a") won't run.
+ * - Added link_text param if css isn't needed.
+ * - Renamed cssClass to css_class for consistency
+ *
+ */
diff --git a/debian/missing-sources/swfupload/Documentation/index.html b/debian/missing-sources/swfupload/Documentation/index.html
new file mode 100644
index 0000000..419d47f
--- /dev/null
+++ b/debian/missing-sources/swfupload/Documentation/index.html
@@ -0,0 +1,1181 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml" >
+<head>
+ <title>SWFUpload v2 Documentation</title>
+</head>
+
+<style type="text/css">
+ h1 /* Title */ {
+ }
+ h2 /* Chapter Header */ {
+ background-color: #DCE7F2;
+ border: solid 1px #CCD7E0;
+ padding: 10px;
+
+ margin-top: 50px;
+ margin-left: 5px;
+ }
+ h3 /* Section Header */ {
+ background-color: #EDFFEB;
+ padding: 10px;
+
+ margin-left: 15px;
+ }
+ h4 {
+ background-color: #FFFFD1;
+ padding: 7px;
+
+ margin-left: 20px;
+ }
+
+ h5 {
+ background-color: #F0F0F0;
+ padding: 4px;
+
+ font-weight: normal;
+
+ margin-left: 25px;
+ }
+
+ p {
+ margin-left: 35px;
+ }
+ span.function {
+ font-weight: bold;
+ }
+ span.parameter {
+ font-style: italic;
+ font-weight: normal;
+ }
+
+ hr {
+ margin-right: 25px;
+ }
+
+ ul, ol {
+ list-style-position: outside;
+ margin: 0;
+ padding: 0;
+ margin-left: 50px;
+ }
+ li {
+ padding-left: 15px;
+ }
+
+ code {
+ display: block;
+ border: solid 1px #EFEFEF;
+ background-color: #FAFAFA;
+ padding: 15px;
+ margin-left: 25px;
+
+ white-space: pre;
+
+ overflow-x: scroll;
+ overflow-y: visible;
+ }
+</style>
+
+<body>
+ <h1>SWFUpload v2.2.0.1 Documentation</h1>
+ <h2>TOC</h2>
+ <ol>
+ <li><a href="#swfupload">SWFUpload</a></li>
+ <li><a href="#v2">SWFUpload Version 2</a></li>
+ <li><a href="#overview">Overview</a></li>
+ <li><a href="#gettingstarted">Getting Started</a></li>
+ <li><a href="#javascriptobject">SWFUpload JavaScript Object</a>
+ <ol>
+ <li><a href="#constructor">Constructor</a></li>
+ <li><a href="#globals">Globals and Constants</a>
+ <ol>
+ <li><a href="#instances">instances</a></li>
+ <li><a href="#movieCount">movieCount</a></li>
+ <li><a href="#queue_error">QUEUE_ERROR</a></li>
+ <li><a href="#upload_error">UPLOAD_ERROR</a></li>
+ <li><a href="#file_status">FILE_STATUS</a></li>
+ <li><a href="#button_action">BUTTON_ACTION</a></li>
+ <li><a href="#button_cursor">CURSOR</a></li>
+ <li><a href="#button_window_mode">BUTTON_WINDOW_MODE</a></li>
+ </ol>
+ </li>
+ <li><a href="#properties">Properties</a>
+ <ol>
+ <li><a href="#customSettings">customSettings</a></li>
+ <li><a href="#movieName">movieName</a></li>
+ </ol>
+ </li>
+ <li><a href="#methods">Methods</a>
+ <ol>
+ <li><a href="#addSetting">addSetting</a> (deprecated)</li>
+ <li><a href="#getSetting">getSetting</a> (deprecated)</li>
+ <li><a href="#retrieveSetting">retrieveSetting</a> (removed in v2.1.0)</li>
+ <li><a href="#destroy">destroy</a> (added in v2.1.0)</li>
+ <li><a href="#displayDebugInfo">displayDebugInfo</a></li>
+ <li><a href="#selectFile">selectFile</a></li>
+ <li><a href="#selectFiles">selectFiles</a></li>
+ <li><a href="#startUpload">startUpload</a></li>
+ <li><a href="#cancelUpload">cancelUpload</a></li>
+ <li><a href="#stopUpload">stopUpload</a></li>
+ <li><a href="#getStats">getStats</a></li>
+ <li><a href="#setStats">setStats</a></li>
+ <li><a href="#getFile">getFile</a></li>
+ <li><a href="#addPostParam">addPostParam</a></li>
+ <li><a href="#removePostParam">removePostParam</a></li>
+ <li><a href="#addFileParam">addFileParam</a></li>
+ <li><a href="#removeFileParam">removeFileParam</a></li>
+ <li><a href="#setUploadURL">setUploadURL</a></li>
+ <li><a href="#setPostParams">setPostParams</a></li>
+ <li><a href="#setFileTypes">setFileTypes</a></li>
+ <li><a href="#setFileSizeLimit">setFileSizeLimit</a></li>
+ <li><a href="#setFileUploadLimit">setFileUploadLimit</a></li>
+ <li><a href="#setFileQueueLimit">setFileQueueLimit</a></li>
+ <li><a href="#setFilePostName">setFilePostName</a></li>
+ <li><a href="#setUseQueryString">setUseQueryString</a></li>
+ <li><a href="#setDebugEnabled">setDebugEnabled</a></li>
+ <li><a href="#setButtonImageURL">setButtonImageURL (added in v2.2.0)</a></li>
+ <li><a href="#setButtonDimensions">setButtonDimensions (added in v2.2.0)</a></li>
+ <li><a href="#setButtonText">setButtonText (added in v2.2.0)</a></li>
+ <li><a href="#setButtonTextStyle">setButtonTextStyle (added in v2.2.0)</a></li>
+ <li><a href="#setButtonTextPadding">setButtonTextPadding (added in v2.2.0)</a></li>
+ <li><a href="#setButtonDisabled">setButtonDisabled (added in v2.2.0)</a></li>
+ <li><a href="#setButtonAction">setButtonAction (added in v2.2.0)</a></li>
+ <li><a href="#setButtonCursor">setButtonCursor (added in v2.2.0)</a></li>
+ </ol>
+ </li>
+ <li><a href="#events">Events</a>
+ <ol>
+ <li><a href="#flashReady">flashReady</a></li>
+ <li><a href="#swfUploadLoaded">swfUploadLoaded</a></li>
+ <li><a href="#fileDialogStart">fileDialogStart</a></li>
+ <li><a href="#fileQueued">fileQueued</a></li>
+ <li><a href="#fileQueueError">fileQueueError</a></li>
+ <li><a href="#fileDialogComplete">fileDialogComplete</a></li>
+ <li><a href="#uploadStart">uploadStart</a></li>
+ <li><a href="#uploadProgress">uploadProgress</a></li>
+ <li><a href="#uploadError">uploadError</a></li>
+ <li><a href="#uploadSuccess">uploadSuccess</a></li>
+ <li><a href="#uploadComplete">uploadComplete</a></li>
+ <li><a href="#debug">debug</a></li>
+ </ol>
+ </li>
+ <li><a href="#utility">SWFUpload Utility Objects</a>
+ <ol>
+ <li><a href="#settingsobject">Settings Object</a></li>
+ <li><a href="#settingsdescription">Settings Description</a></li>
+ <li><a href="#fileobject">File Object</a></li>
+ <li><a href="#statsobject">Stats Object</a></li>
+ </ol>
+ </li>
+ </ol>
+ </li>
+ <li><a href="#plugins">SWFUpload Plug-ins</a></li>
+ <li><a href="#knownissues">Known Issues</a></li>
+ </ol>
+
+
+ <h2><a name="swfupload"></a>SWFUpload</h2>
+ <p>
+ <a href="http://www.swfupload.org">SWFUpload</a> is a client-side file upload tool originally developed by <a href="http://www.vinterwebb.se/">Vinterwebb.se</a>. It uses a combination of Flash and JavaScript to
+ provide file upload functionality beyond what the basic browser provides with the &lt;input type="file" /&gt; tag.
+ </p>
+ <p>The main features that SWFUpload provides are:</p>
+ <p>
+ <ul>
+ <li>The ability to select multiple files in the file browser dialog.</li>
+ <li>AJAX-style uploading without a page refresh.</li>
+ <li>Upload progress events.</li>
+ <li>Namespaced classes compatible with other JavaScript libraries (i.e., jQuery, Prototype, etc.).</li>
+ <li>Flash 9 and Flash 10 support. (Flash 8 support dropped in version 2.2.0)</li>
+ </ul>
+ </p>
+ <p>
+ SWFUpload is different from other Flash based upload tools because of the philosophy
+ behind its design. SWFUpload gives developers control by leaving the UI in the browser (as much as possible).
+ Developers can use XHTML, CSS, and JavaScript to tailor the upload UI to the needs and
+ style of their site. Upload status updates are made through a set of simple JavaScript events.
+ The developer uses these events to update the webpage as the file upload progresses.
+ </p>
+ <p>
+ Unfortunately Flash Player 10 has forced us have one button in a flash movie in order to trigger the file browser dialog window. SWFUpload
+ still empowers the devloper by provding the ability the button and overlay text from JavaScript.
+ </p>
+
+ <h2><a name="v2"></a>SWFUpload v2</h2>
+ <p>
+ SWFUpload v2 includes new advanced features, improved stability, Flash Player
+ bug work-arounds and a helpful set of Plug-ins. New features include:
+ </p>
+ <p>
+ <ul>
+ <li>Flash Player 10 security compatibility.</li>
+ <li>The ability to send additional POST values with the uploads.</li>
+ <li>Sending per file POST values.</li>
+ <li>Complete set of events.</li>
+ <li>All settings dynamically updateable.</li>
+ <li>Retrieve result data from the server.</li>
+ <li>Stop an upload without cancelling.</li>
+ <li>Upload files in any order.</li>
+ <li>Multi- &amp; Single-file selection dialogs.</li>
+ <li>Queue size, files uploaded and file size limits.</li>
+ <li>Properly handling of zero-byte files.</li>
+ <li>Pre-upload validation event.</li>
+ <li>Work-arounds for bugs in Flash and Browser.</li>
+ </ul>
+ </p>
+
+ <h2><a name="overview"></a>Overview</h2>
+ <h3>HTML Upload</h3>
+ <p>
+ The standard HTML upload input box provides a box and a button to the user for selecting a file.
+ The file is submitted with the form. The entire file must be uploaded before the next
+ page is displayed. No pre-upload validation can be made on the file (e.g., file size limits or valid extensions).
+ Very little feedback is given to the user while the file uploads.
+ </p>
+ <p>
+ The usage pattern for standard HTML uploads is simple, straight forward, and supported by nearly all browser.
+ </p>
+ <h3>SWFUpload</h3>
+ <p>
+ SWFUpload uses a Flash movie to handle file selection and upload. A customizable button is displayed by the
+ Flash movie that activates Flashes advanced file selection dialog window.
+ The file selection dialog is configured to allow the user select to a single file or multiple files.
+ The file types can be restricted so users only select the appropriate files (e.g., *.jpg;*.gif).
+ </p>
+ <p>
+ Once selected each file is validated and queued. As the file is uploaded by Flash
+ several JavaScript events are fired which the developer handles in order to update the page's UI allowing you to provide
+ upload status and error messages in real-time.
+ </p>
+ <p>
+ The uploaded file is submitted separately from the rest of the page and form. Each file is uploaded
+ individually keeping the server-side upload handling script simple. Since Flash is providing the upload
+ service the page does not have to be submitted or reloaded. The usage pattern for SWFUpload is more
+ like that of an AJAX application than that of a standard HTML form. The page's form will be processed
+ separately from the file upload.
+ </p>
+ <h2><a name="gettingstarted"></a>Getting Started</h2>
+ <p>SWFUpload is not a drag &amp; drop upload control. It requires knowledge of JavaScript and the DOM. Several demos are available that
+ show some of the things SWFUpload is capable of and how to accomplish common tasks.</p>
+
+ <p>SWFUpload consists of 4 pieces:</p>
+ <ol>
+ <li>Initialization and Settings (JavaScript)</li>
+ <li>JavaScript library: SWFUpload.js</li>
+ <li>Flash Control: swfupload.swf</li>
+ <li>The Event Handlers (JavaScript)</li>
+ </ol>
+
+ <p>Most problems implementing SWFUpload are caused by incorrect settings, poorly built event handlers, Flash/Browser Bugs, or server configuration.</p>
+
+ <h3>Initialization and Settings</h3>
+ <p>SWFUpload must be initialized on the page. This is commonly done in the window.onload event. The SWFUpload constructor takes a settings object.
+ The settings object can be passed directly to the constructor as an object literal.</p>
+ <p>A reference to the initialized SWFUpload object should be kept as it is needed to start uploads and to control other aspects of SWFUpload.</p>
+
+ <p><strong>Example:</strong> Initializing SWFUpload with an object literal</p>
+
+ <code>var swfu;
+
+window.onload = function () {
+ swfu = new SWFUpload({
+ upload_url : "http://www.swfupload.org/upload.php",
+ flash_url : "http://www.swfupload.org/swfupload.swf",
+ file_size_limit : "20 MB"
+ });
+};</code>
+
+ <p><strong>Example:</strong> Initializing SWFUpload with a settings object stored in a variable</p>
+
+ <code>var swfu;
+
+window.onload = function () {
+ var settings_object = {
+ upload_url : "http://www.swfupload.org/upload.php",
+ flash_url : "http://www.swfupload.org/swfupload.swf",
+ file_size_limit : "20 MB"
+ };
+
+ swfu = new SWFUpload(settings_object);
+};</code>
+
+ <h3>JavaScript library</h3>
+ <p>The JavaScript library file (swfupload.js) must be included on the page where the user will upload files.</p>
+ <p>Once a SWFUpload object has been created access to several functions become available which allow the developer to control SWFUpload.</p>
+
+ <p><strong>Example:</strong> Adding SWFUpload.js to a page</p>
+
+ <code>
+&lt;script type="text/javascript" src="http://www.swfupload.org/swfupload.js"&gt;&lt;/script&gt;
+ </code>
+
+ <p><strong>Example:</strong> Initializing SWFUpload with the required settings.</p>
+ <code>var swfu = new SWFUpload({
+ upload_url : "http://www.swfupload.org/upload.php",
+ flash_url : "http://www.swfupload.org/swfupload_f9.swf",
+ button_placeholder_id : "spanSWFUploadButton"
+});
+</code>
+
+ <h3>Flash Control</h3>
+ <p>The SWFUpload JavaScript library dynamically loads the Flash Control (swfupload.swf).</p>
+
+ <p>The location of the Flash Control file must be provided in the SWFUpload settings object during setup.</p>
+
+ <p>The Flash Control is a small Flash Movie that handles file browsing, validation and upload. It appears on the page as
+ a button and communicates with JavaScript to notify the browser of upload status and other events.</p>
+
+ <h3>The Event Handlers</h3>
+
+ <p>Developers must create a set of JavaScript functions that handle SWFUpload events. These functions are called as different important events occur.</p>
+
+ <p>By handling the SWFUpload events developers can provide feedback regarding the upload progress, error messages, and upload completion. Developers should not
+ overwrite functions stored in SWFUpload.prototype. Instead create your own set of functions and pass references to them in the settings object.</p>
+
+ <p><strong>Example:</strong> SWFUpload event handlers and initialization.</p>
+
+ <code>// The uploadStart event handler. This function variable is assigned to upload_start_handler in the settings object
+var myCustomUploadStartEventHandler = function (file) {
+ var continue_with_upload;
+
+ if (file.name === "the sky is blue") {
+ continue_with_upload = true;
+ } else {
+ continue_with_upload = false;
+ }
+
+ return continue_with_upload;
+};
+
+// The uploadSuccess event handler. This function variable is assigned to upload_success_handler in the settings object
+var myCustomUploadSuccessEventHandler = function (file, server_data, receivedResponse) {
+ alert("The file " + file.name + " has been delivered to the server. The server responded with " + server_data);
+};
+
+// Create the SWFUpload Object
+var swfu = new SWFUpload({
+ upload_url : "http://www.swfupload.org/upload.php",
+ flash_url : "http://www.swfupload.org/swfupload.swf",
+ file_size_limit : "200 MB",
+
+ upload_start_handler : myCustomUploadStartEventHandler,
+ upload_success_handler : myCustomUploadSuccessEventHandler
+});</code>
+
+
+ <h2><a name="javascriptobject"></a>SWFUpload JavaScript Object</h2>
+
+ <h3><a name="constructor"></a>Constructor</h3>
+
+ <p><span class="function">SWFUpload(<span class="parameter">settings object</span>)</span></p>
+ <p><b>Returns:</b> A SWFUpload instance</p>
+ <code>var swfupload_instance = new SWFUpload(settings_object);</code>
+
+ <h3><a name="globals"></a>Globals and Constants</h3>
+ <p>
+ Several globals and constants are associated with the SWFUpload object. These are useful for
+ advanced SWFUpload applications and for handling errors. These are considered read-only.
+ </p>
+ <h4><a name="instances"></a>SWFUpload.instances</h4>
+ <p>SWFUpload.instances is an object containing a reference to each SWFUpload instance loaded on a page. The Flash Player
+ relies on this object in order to call the correct event handlers. SWFUpload.instances indexes by the movieName property.</p>
+
+ <h4><a name="movieCount"></a>SWFUpload.movieCount</h4>
+ <p>SWFUpload.movieCount is a global that tracks the number on SWFUpload instances that have been created and helps to ensure each movie is
+ given a unique movieName.</p>
+
+ <h4><a name="queue_error"></a>SWFUpload.QUEUE_ERROR</h4>
+ <p>SWFUpload.QUEUE_ERROR is a simple object that contains Queue Error code constants. It is generally used to determine which error code was sent
+ in the fileQueueError event.</p>
+
+ <ul style="padding-left: 15px;">
+ <li>QUEUE_LIMIT_EXCEEDED - indicates that the user has attempted to queue more files that is allowed by the settings. Once files have been updated and removed from the queue the user is again allowed to queue additional files.</li>
+ <li>FILE_EXCEEDS_SIZE_LIMIT - indicates the selected file is larger than is allwed by the file_size_limit.</li>
+ <li>ZERO_BYTE_FILE - indicates that the selected file is empty. The Flash Player cannot handle empty files and the file is rejected. Windows Shortcut files may also trigger this error.</li>
+ <li>INVALID_FILETYPE - The selected file's extension does not match a valid extension from the file_types setting. User's can circumvent the file_types restriction by manually entering a file name.</li>
+ </ul>
+
+ <h4><a name="upload_error"></a>SWFUpload.UPLOAD_ERROR</h4>
+ <p>SWFUpload.UPLOAD_ERROR is a simple object that contains Upload Error code constants. It is generally used to determine which error code was sent
+ in the uploadError event.</p>
+
+ <ul style="padding-left: 15px;">
+ <li>HTTP_ERROR - The file upload was attempted but the server did not return a 200 status code.</li>
+ <li>MISSING_UPLOAD_URL - The upload_url setting was not set.</li>
+ <li>IO_ERROR - Some kind of error occurred while reading or transmitting the file. This most commonly occurs when the server unexpectedly terminates the connection.</li>
+ <li>SECURITY_ERROR - The upload violates a security restriction. This error is rare.</li>
+ <li>UPLOAD_LIMIT_EXCEEDED - The user has attempted to upload more files than is allowed by the file_upload_limit setting.</li>
+ <li>UPLOAD_FAILED - The attempt to initiate the upload caused an error. This error is rare.</li>
+ <li>SPECIFIED_FILE_ID_NOT_FOUND - A file ID was passed to startUpload but that file ID could not be found.</li>
+ <li>FILE_VALIDATION_FAILED - False was returned from the uploadStart event</li>
+ <li>FILE_CANCELLED - cancelUpload was called</li>
+ <li>UPLOAD_STOPPED - stopUpload was called.</li>
+ </ul>
+
+ <h4><a name="file_status"></a>SWFUpload.FILE_STATUS</h4>
+ <p>SWFUpload.FILE_STATUS is a simple object that contains File Status code constants. It can be used to check the file status property on the File object.</p>
+
+ <ul style="padding-left: 15px;">
+ <li>QUEUED - indicates the this file is waiting in the queue.</li>
+ <li>IN_PROGRESS - indicates that this file is currently being uploaded.</li>
+ <li>ERROR - indicates that this file caused a queue or upload error.</li>
+ <li>COMPLETE - indicates that this file was successfully transmitted to the server.</li>
+ <li>CANCELLED - indicates that this file was cancelled by a call to cancelUpload.</li>
+ </ul>
+
+
+ <h4><a name="button_action"></a>SWFUpload.BUTTON_ACTION</h4>
+ <p>SWFUpload.BUTTON_ACTION is a simple object that contains button action code constants. It is used with the button_action setting to set the behavior of the Flash based file dialog button.</p>
+
+ <ul style="padding-left: 15px;">
+ <li>SELECT_FILE - when the Flash button is clicked the file dialog will only allow a single file to be selected.</li>
+ <li>SELECT_FILES - when the Flash button is clicked the file dialog allows multiple files to be selected.</li>
+ <li>START_UPLOAD - while the Flash button is clicked the first queued file will be uploaded.</li>
+ </ul>
+
+ <h4><a name="button_cursor"></a>SWFUpload.CURSOR</h4>
+ <p>SWFUpload.CURSOR is a simple object that contains button cursor code constants. It is used with the button_cursor setting to set the mouse cursor when hovering over the Flash button.</p>
+
+ <ul style="padding-left: 15px;">
+ <li>ARROW - the cursor will display as an arrow pointer</li>
+ <li>HAND - the cursor will display has a finger/hand pointer</li>
+ </ul>
+
+ <h4><a name="button_window_mode"></a>SWFUpload.WINDOW_MODE</h4>
+ <p>SWFUpload.WINDOW_MODE is a simple object that contains button movie wmode parameter constants. It is used to tell the browser how to display the Flash Movie.</p>
+ <p>The some WINDOW_MODE/WMODE settings can cause problems in some browsers. See the <a href="#knownissues">Known Issues</a>.</p>
+
+ <ul style="padding-left: 15px;">
+ <li>WINDOW is the default mode. The movie is drawn over the top of all other elements on the page.</li>
+ <li>OPAQUE causes the movie to be rendered in the page allowing other elements to cover up the button.</li>
+ <li>TRANSPARENT the button background is rendered transparent allowing html elements under the button to show through.</li>
+ </ul>
+
+ <h3><a name="properties"></a>Properties</h3>
+ <p>
+ The following list of properties is intended for your use as described below. Using other properties or
+ writing to read-only properties can cause SWFUpload to malfunction.
+ </p>
+ <h4><a name="customSettings"></a>customSettings (read/write)</h4>
+ <p>
+ The customSettings property is an empty JavaScript object that can be used to store data associated with
+ an instance of SWFUpload. The customSettings object contents can be initialized using the custom_settings setting.
+ </p>
+
+ <p><strong>Example:</strong></p>
+ <code>// Initialize SWFUpload with some custom settings
+var swfu = new SWFUpload({
+ custom_settings : {
+ custom_setting_1 : "custom_setting_value_1",
+ custom_setting_2 : "custom_setting_value_2",
+ custom_setting_n : "custom_setting_value_n",
+ }
+});
+
+swfu.customSettings.custom_setting_1 = "custom_setting_value_1"; // Change an existing custom setting
+swfu.customSettings.myNewCustomSetting = "new custom setting value"; // Add a new custom setting
+
+// Overwrite the customSettings with a completely new object
+swfu.customSettings = {
+ custom_setting_A : "custom_setting_value_A",
+ custom_setting_B : "custom_setting_value_B"
+};
+ </code>
+
+ <p>The values stored in the customSettings object can then be easily accessed in the event handlers: </p>
+
+ <code>
+function uploadSuccess(file, serverData, receivedResponse) {
+ if (this.customSettings.custom_setting_A === true) {
+ alert("Checked the custom setting!");
+ }
+}
+ </code>
+
+ <h4><a name="movieName"></a>movieName</h4>
+ <p>Contains the unique movie name of the SWFUpload instance. This value is passed to Flash and is used to facilitate Flash-to-JavaScript communication.
+ This value is used to index the instance in the SWFUpload.instances array. You should not change the movieName value.</p>
+
+ <h3><a name="methods"></a>Methods</h3>
+ <p>The following methods are used to operate SWFUpload. Some are bound to DOM element click event handlers and others are used inside
+ SWFUpload event handlers.</p>
+
+ <h4><a name="addSetting"></a>object addSetting(<span class="parameter">setting_name</span>, <span class="parameter">value</span>, <span class="parameter">default_value</span>)</h4>
+ <p><strong>Deprecated</strong> The addSetting function sets a setting value. If the value is undefined then the default_value is used. The function is used by SWFUpload
+ during initialization. Using addSetting to update a setting will not change the setting in the Flash Control.</p>
+ <p>addSetting returns the value that was stored in the setting.</p>
+
+ <h4><a name="getSetting"></a>object getSetting(<span class="parameter">setting_name</span>)</h4>
+ <p><strong>Deprecated</strong> The getSetting function retrieves the value of a setting. If the setting is not found an empty string is returned.</p>
+
+ <h4><a name="retrieveSetting"></a>object retrieveSetting(<span class="parameter">setting_value</span>, <span class="parameter">default_value</span>)</h4>
+ <p><strong>Removed in v2.1.0</strong> The retrieveSetting function is similar to the addSetting function except it does not modify the internal settings object. retrieveSetting
+ returns the setting_value unless it is undefined in which case it returns the default_value</p>
+ <p>This is a utility function.</p>
+
+ <h4><a name="destroy"></a>bool destroy()</h4>
+ <p><strong>Added in v2.1.0</strong></p>
+ <p>Removes the SWF DOM elements and then destroys SWFUpload internal references. Used for removing a SWFUpload instance from a page. It also attempts to prevent memory leaks in IE.</p>
+ <p>Returns true if the elements were removed successfully. Returns false if any error occurs leaving the SWFUpload instance in an inconsistent state.</p>
+
+ <h4><a name="displayDebugInfo"></a>void displayDebugInfo()</h4>
+ <p>The displayDebugInfo outputs SWFUpload settings using the debug event. This function is automatically called after initialization if the debug setting is 'true'</p>
+
+ <h4><a name="selectFile"></a>void selectFile()</h4>
+ <p><strong>Deprecated. Not compatible with Flash Player 10.</strong></p>
+ <p>selectFile causes the Flash Control to display a File Selection Dialog window. A single file may be selected from the Dialog window.</p>
+ <p>Calling selectFile begins the File Event Chain.</p>
+
+ <h4><a name="selectFiles"></a>void selectFiles()</h4>
+ <p><strong>Deprecated. Not compatible with Flash Player 10.</strong></p>
+ <p>selectFiles causes the Flash Control to display a File Selection Dialog window. A multiple files may be selected from the Dialog window.</p>
+ <p>Calling selectFiles begins the File Event Chain.</p>
+
+ <h4><a name="startUpload"></a>void startUpload(<span class="parameter">file_id</span>)</h4>
+ <p>startUpload causes the file specified by the file_id parameter to start the upload process. If the file_id parameter is omitted or undefined then the first file in the queue is uploaded.</p>
+
+ <p>Calling startUpload begins the Upload Event Chain.</p>
+
+ <h4><a name="cancelUpload"></a>void cancelUpload(<span class="parameter">file_id</span>, <span class="parameter">trigger_error_event</span>)</h4>
+
+ <p>cancelUpload cancels the file specified by the file_id parameter. The file is then removed from the queue.</p>
+ <p>If the file_id parameter is omitted or undefined then the first file in the queue is cancelled.</p>
+ <p>The trigger_error_event is optional. If set to false the uploadError event is suppressed.</p>
+
+ <h4><a name="stopUpload"></a>void stopUpload()</h4>
+
+ <p>stopUpload stops and re-queues the file currently being uploaded.</p>
+ <p>After the uploading file is stopped the uploadError event is fired. If no file is being uploaded then nothing happens and no event is fired.</p>
+
+ <h4><a name="getStats"></a>object getStats()</h4>
+ <p>Retrieves the stats object.</p>
+
+ <h4><a name="setStats"></a>void setStats(<span class="parameter">stats_object</span>)</h4>
+ <p>The Stats Object may be modified. This is useful if you wish to change the number of successful uploads or upload errors after an upload
+ has completed.</p>
+
+ <h4><a name="getFile"></a>object getFile(<span class="parameter">file_id</span>|<span class="parameter">index</span>)</h4>
+ <p>getFile is used to retrieve a File Object from the queue. The file retrieved by passing in a file id (the id property from a file object) or a file index (the index property from a file object).</p>
+ <p>When getting a file by file_id only files in the queue are available. If the file is not found null is returned.</p>
+ <p>When getting a file by index all queued (or files that generated a queue error) are available. If the index is out of range then null is returned</p>
+
+ <h4><a name="addPostParam"></a>void addPostParam(<span class="parameter">name</span>, <span class="parameter">value</span>)</h4>
+ <p>The addPostParam function adds a name/value pair that will be sent in the POST for all files uploaded.</p>
+ <p>The name/value pair will also appear in the post_params setting.</p>
+
+ <h4><a name="removePostParam"></a>void removePostParam(<span class="parameter">name</span>)</h4>
+ <p>The removePostParam function removes a name/value pair from the values sent with the POST for file uploads.</p>
+ <p>The name/value pair is also be removed from the post_params setting.</p>
+
+ <h4><a name="addFileParam"></a>bool addFileParam(<span class="parameter">file_id</span>, <span class="parameter">name</span>, <span class="parameter">value</span>)</h4>
+ <p>The addFileParam function adds a name/value pair that will be sent in the POST with the file specified by the file_id parameter.</p>
+ <p>The name/value pair will only be sent with the file it is added to. To send name/value pairs with all uploads use the post_param setting.</p>
+
+ <h4><a name="removeFileParam"></a>bool removeFileParam(<span class="parameter">file_id</span>, <span class="parameter">name</span>)</h4>
+ <p>The removeFileParam function removes a name/value pair from a file upload that was added using addFileParam.</p>
+ <p>If the name/value pair was not found then 'false' is returned.</p>
+
+ <h4><a name="setUploadURL"></a>void setUploadURL(<span class="parameter">url</span>)</h4>
+ <p>Dynamically modifies the upload_url setting.</p>
+
+ <h4><a name="setPostParams"></a>void setPostParams(<span class="parameter">param_object</span>)</h4>
+ <p>Dynamically modifies the post_params setting. Any previous values are over-written. The param_object should be a simple JavaScript object. All names and values must be strings.</p>
+
+ <h4><a name="setFileTypes"></a>void setFileTypes(<span class="parameter">types</span>, <span class="parameter">description</span>)</h4>
+ <p>Dynamically updates the file_types and file_types_description settings. Both parameters are required.</p>
+
+ <h4><a name="setFileSizeLimit"></a>void setFileSizeLimit(<span class="parameter">file_size_limit</span>)</h4>
+ <p>Dynamically modifies the file_size_limit setting. This applies to all future files that are queued. The file_size_limit parameter will accept a unit. Valid units are B, KB, MB, and GB. The default unit is KB.</p>
+ <p>Examples: 2147483648 B, 2097152, 2097152KB, 2048 MB, 2 GB</p>
+
+ <h4><a name="setFileUploadLimit"></a>void setFileUploadLimit(<span class="parameter">file_upload_limit</span>)</h4>
+ <p>Dynamically modifies the file_upload_limit setting. The special value zero (0) indicates "no limit".</p>
+
+ <h4><a name="setFileQueueLimit"></a>void setFileQueueLimit(<span class="parameter">file_queue_limit</span>)</h4>
+ <p>Dynamically modifies the file_queue_limit setting. The special value zero (0) indicates "no limit".</p>
+
+ <h4><a name="setFilePostName"></a>void setFilePostName(<span class="parameter">file_post_name</span>)</h4>
+ <p>Dynamically modifies the file_post_name setting. The Linux Flash Player ignores this setting.</p>
+
+ <h4><a name="setUseQueryString"></a>void setUseQueryString(<span class="parameter">use_query_string</span>)</h4>
+ <p>Dynamically modifies the use_query_string setting. When true this forces SWFUpload to send post parameters on the query string rather than in the post. The use_query_string parameter should be a boolean true or false.</p>
+
+ <h4><a name="setDebugEnabled"></a>void setDebugEnabled(<span class="parameter">debug_enabled</span>)</h4>
+ <p>Dynamically enables or disables debug output. The debug_enabled parameter should be a boolean true or false.</p>
+
+ <h4><a name="setButtonImageURL"></a>void setButtonImageURL(<span class="parameter">url</span>)</h4>
+ <p>Dynamically change the image used in the Flash Button. The image url must be relative to the swfupload.swf file, an absolute path (e.g., starting with a /), or
+ a fully qualified url (e.g., http://www.swfupload.org/buttonImage.png). Any image format supported by Flash can be loaded. The most notable formats are jpg, gif, and png.</p>
+
+ <p>The button image is expected to be a button sprite (or a single image file with several images stacked together). The image will be used to represent
+ all the button states by moving the image up or down to only display the needed portion. These states include: normal, hover, click, disabled. See the sample button images.</p>
+
+ <h4><a name="setButtonDimensions"></a>void setButtonDimensions(<span class="parameter">width</span>, <span class="parameter">height</span>)</h4>
+ <p>Dynamically change the Flash button's width and height. The values should be numeric and should not include any units. The height value should
+ be 1/4th of the total button image height so the button state sprite images can be displayed correctly</p>
+
+ <h4><a name="setButtonText"></a>void setButtonText(<span class="parameter">text</span>)</h4>
+ <p>Sets the text that should be displayed over the Flash button. Text that is too large and overflows the button size will be clipped.</p>
+ <p>The text can be styled using HTML supported by the Flash Player (<a target="_blank" href="http://livedocs.adobe.com/flash/9.0/ActionScriptLangRefV3/flash/text/TextField.html#htmlText">Adobe Documentation</a>)</p>
+
+ <h4><a name="setButtonTextStyle"></a>void setButtonTextStyle(<span class="parameter">css_style_text</span>)</h4>
+ <p>Sets the CSS styles used to style the Flash Button Text. CSS should be formatted according to the Flash Player documentation (<a target="_blank" href="http://livedocs.adobe.com/flash/9.0/ActionScriptLangRefV3/flash/text/StyleSheet.html">Adobe Documentation</a>)</p>
+ <p>Style classes defined here can then be referenced by HTML in the button_text setting.</p>
+
+ <h4><a name="setButtonTextPadding"></a>void setButtonTextPadding(<span class="parameter">left</span>, <span class="parameter">top</span>)</h4>
+ <p>Sets the top and left padding of the Flash button text. The values may be negative.</p>
+
+ <h4><a name="setButtonDisabled"></a>void setButtonDisabled(<span class="parameter">isDisabled</span>)</h4>
+ <p>When 'true' changes the Flash Button state to disabled and ignores any clicks.</p>
+
+ <h4><a name="setButtonAction"></a>void setButtonAction(<span class="parameter">buttonAction</span>)</h4>
+ <p>Sets the action taken when the Flash button is clicked. Valid action values are taken from the BUTTON_ACTION constants.</p>
+
+ <h4><a name="setButtonCursor"></a>void setButtonCursor(<span class="parameter">buttonCursor</span>)</h4>
+ <p>Sets the mouse cursor shown when hovering over the Flash button. Valid cursor values are taken from the CURSOR constants.</p>
+
+
+
+ <h3><a name="events"></a>Events</h3>
+ <p>SWFUpload fires various events during its operation. These events can be handled by the developer to update the UI, change behavior, or report errors.</p>
+ <p>All SWFUpload events are called in the context of a SWFUpload instance. This means that the 'this' object refers to the SWFUpload instance that
+ fired the event.</p>
+
+ <p>SWFUpload events should be set only by assigning the event handler function in the settings object during object initialization. You should not override the
+ internal functions belonging to the SWFUpload.prototype object.</p>
+
+ <p>During a file upload events are usually called in this order (the Upload Event Chain):</p>
+ <ul>
+ <li>uploadStart</li>
+ <li>uploadProgress (called over and over again as the file uploads)</li>
+ <li>uploadError (called if some kind of error occurs, the file is canceled or stopped)</li>
+ <li>uploadSuccess (the upload finished successfully, data returned from the server is available)</li>
+ <li>uploadComplete (the upload is complete and SWFUpload is ready to start the next file)</li>
+ </ul>
+
+ <h4><a name="flashReady"></a><span class="function">flashReady()</span></h4>
+ <p>flashReady is an internal event that should not be overwritten. It is called by the Flash Control to notify SWFUpload that the Flash
+ movie has loaded and is ready to accept commands.</p>
+
+ <h4><a name="swfUploadLoaded"></a><span class="function">swfUploadLoaded()</span></h4>
+ <p>The swfUploadLoaded event is fired by flashReady. It is settable. swfUploadLoaded is called to let you know that it is safe to call SWFUpload methods.</p>
+
+ <h4><a name="fileDialogStart"></a><span class="function">fileDialogStart(<span class="parameter"></span>)</span></h4>
+ <p>fileDialogStart is fired after selectFile for selectFiles is called. This event is fired immediately before the File Selection Dialog
+ window is displayed. However, the event may not execute until after the Dialog window is closed.</p>
+
+ <h4><a name="fileQueued"></a><span class="function">fileQueued(<span class="parameter">file object</span>)</span></h4>
+ <p>The fileQueued event is fired for each file that is queued after the File Selection Dialog window is closed.</p>
+
+ <h4><a name="fileQueueError"></a><span class="function">fileQueueError(<span class="parameter">file object</span>, <span class="parameter">error code</span>, <span class="parameter">message</span>)</span></h4>
+ <p>The fileQueueError event is fired for each file that was not queued after the File Selection Dialog window is closed. A file may not be queued
+ for several reasons such as, the file exceeds the file size, the file is empty or a file or queue limit has been exceeded.</p>
+ <p>The reason for the queue error is specified by the error code parameter. The error code corresponds to a SWFUpload.QUEUE_ERROR constant.</p>
+
+ <h4><a name="fileDialogComplete"></a><span class="function">fileDialogComplete(<span class="parameter">number of files selected</span>, <span class="parameter">number of files queued</span>, <span class="parameter">total number of files in the queued</span>)</span></h4>
+ <p>The fileDialogComplete event fires after the File Selection Dialog window has been closed and all the selected files have been processed. The 'number of files queued' argument indicates the number of files that were queued from the dialog selection (as opposed to the number of files in the queue).</p>
+ <p>If you want file uploading to begin automatically this is a good place to call 'this.startUpload()'</p>
+
+ <h4><a name="uploadStart"></a><span class="function">uploadStart(<span class="parameter">file object</span>)</span></h4>
+ <p>uploadStart is called immediately before the file is uploaded. This event provides an opportunity to perform any last minute validation, add post
+ params or do any other work before the file is uploaded.</p>
+
+ <p>The upload can be cancelled by returning 'false' from uploadStart. If you return 'true' or do not return any value then the upload proceeds. Returning
+ 'false' will cause an uploadError event to fired.</p>
+
+ <h4><a name="uploadProgress"></a><span class="function">uploadProgress(<span class="parameter">file object</span>, <span class="parameter">bytes complete</span>, <span class="parameter">total bytes</span>)</span></h4>
+ <p>The uploadProgress event is fired periodically by the Flash Control. This event is useful for providing UI updates on the page.</p>
+ <p><strong>Note:</strong> The Linux Flash Player fires a single uploadProgress event after the entire file has been uploaded. This is a bug in
+ the Linux Flash Player that we cannot work around.</p>
+
+ <h4><a name="uploadError"></a><span class="function">uploadError(<span class="parameter">file object</span>, <span class="parameter">error code</span>, <span class="parameter">message</span>)</span></h4>
+ <p>The uploadError event is fired any time an upload is interrupted or does not complete successfully. The error code parameter indicates the type of error
+ that occurred. The error code parameter specifies a constant in SWFUpload.UPLOAD_ERROR.</p>
+ <p>Stopping, Cancelling or returning 'false' from uploadStart will cause uploadError to fire. Upload error will not fire for files that are cancelled
+ but still waiting in the queue.</p>
+
+ <h4><a name="uploadSuccess"></a><span class="function">uploadSuccess(<span class="parameter">file object</span>, <span class="parameter">server data</span>, <span class="parameter">received response</span>)</span></h4>
+ <p>uploadSuccess is fired when the entire upload has been transmitted and the server returns a HTTP 200 status code. Any data outputted by the server is available
+ in the server data parameter.</p>
+
+ <p>
+ Due to some bugs in the Flash Player the server response may not be acknowledged and no uploadSuccess event is fired by Flash. In this case the
+ assume_success_timeout setting is checked to see if enough time has passed to fire uploadSuccess anyway. In this case the received response parameter will be false.
+ </p>
+
+ <p>
+ The http_success setting allows uploadSuccess to be fired for HTTP status codes other than 200. In this case no server data is available from the Flash Player.
+ </p>
+
+ <p>At this point the upload is not yet complete. Another upload cannot be started from uploadSuccess.</p>
+
+ <h4><a name="uploadComplete"></a><span class="function">uploadComplete(<span class="parameter">file object</span>)</span></h4>
+ <p>uploadComplete is always fired at the end of an upload cycle (after uploadError or uploadSuccess). At this point the upload is complete and
+ another upload can be started.</p>
+ <p>If you want the next upload to start automatically this is a good place to call this.uploadStart(). Use caution when calling uploadStart inside
+ the uploadComplete event if you also have code that cancels all the uploads in a queue.</p>
+
+ <h4><a name="debug"></a><span class="function">debug(<span class="parameter">message</span>)</span></h4>
+ <p>The debug event is called by the SWFUpload library and the Flash Control when the debug setting is set to 'true'. If the debug
+ event is not overridden then SWFUpload writes debug messages to the SWFUpload console (a text box dynamically added to the end of the page body).</p>
+
+ <h3><a name="utility"></a>SWFUpload Utility Objects</h3>
+ <h4><a name="settingsobject"></a>Settings object</h4>
+ <p>The settings object is a JavaScript object that provides the settings for the SWFUpload instance. <strong>Each setting should only appear once.</strong> Many settings
+ are optional and provide suitable default values if omitted. See the setting details for required and optional settings.</p>
+ <p><strong>Example:</strong></p>
+ <code>{
+ upload_url : "http://www.swfupload.org/upload.php",
+ flash_url : "http://www.swfupload.org/swfupload.swf",
+
+ file_post_name : "Filedata",
+ post_params : {
+ "post_param_name_1" : "post_param_value_1",
+ "post_param_name_2" : "post_param_value_2",
+ "post_param_name_n" : "post_param_value_n"
+ },
+ use_query_string : false,
+ requeue_on_error : false,
+ http_success : [201, 202],
+ assume_success_timeout : 0,
+ file_types : "*.jpg;*.gif",
+ file_types_description: "Web Image Files",
+ file_size_limit : "1024",
+ file_upload_limit : 10,
+ file_queue_limit : 2,
+
+ debug : false,
+
+ prevent_swf_caching : false,
+ preserve_relative_urls : false,
+
+ button_placeholder_id : "element_id",
+ button_image_url : "http://www.swfupload.org/button_sprite.png",
+ button_width : 61,
+ button_height : 22,
+ button_text : "&lt;b&gt;Click&lt;/b&gt; &lt;span class="redText"&gt;here&lt;/span&gt;",
+ button_text_style : ".redText { color: #FF0000; }",
+ button_text_left_padding : 3,
+ button_text_top_padding : 2,
+ button_action : SWFUpload.BUTTON_ACTION.SELECT_FILES,
+ button_disabled : false,
+ button_cursor : SWFUpload.CURSOR.HAND,
+ button_window_mode : SWFUpload.WINDOW_MODE.TRANSPARENT,
+
+ swfupload_loaded_handler : swfupload_loaded_function,
+ file_dialog_start_handler : file_dialog_start_function,
+ file_queued_handler : file_queued_function,
+ file_queue_error_handler : file_queue_error_function,
+ file_dialog_complete_handler : file_dialog_complete_function,
+ upload_start_handler : upload_start_function,
+ upload_progress_handler : upload_progress_function,
+ upload_error_handler : upload_error_function,
+ upload_success_handler : upload_success_function,
+ upload_complete_handler : upload_complete_function,
+ debug_handler : debug_function,
+
+ custom_settings : {
+ custom_setting_1 : "custom_setting_value_1",
+ custom_setting_2 : "custom_setting_value_2",
+ custom_setting_n : "custom_setting_value_n",
+ }
+}</code>
+ <h4><a name="settingsdescription"></a>Settings Description</h4>
+
+ <h5>upload_url</h5>
+ <p>The upload_url setting accepts a full, absolute, or relative target URL for the uploaded file. Relative URLs should be relative to document. The upload_url should be in the same domain as the Flash Control for best compatibility.</p>
+ <p>If the preserve_relative_urls setting is false SWFUpload will convert the relative URL to an absolute URL to avoid the URL being interpreted differently by the Flash Player on different platforms. If you disable SWFUploads conversion of the URL relative URLs should be relative to the swfupload.swf file.</p>
+
+ <h5>file_post_name</h5>
+ <p>The file_post_name allows you to set the value name used to post the file. This is not related to the file name.
+ The default value is 'Filedata'. For maximum compatibility it is recommended that the default value is used.</p>
+
+ <h5>post_params</h5>
+ <p>
+ The post_params setting defines the name/value pairs that will be posted with each uploaded file. This setting accepts a simple JavaScript object.
+ Multiple post name/value pairs should be defined as demonstrated in the sample settings object. Values must be either strings or numbers (as interpreted by the JavaScript typeof function).
+ </p>
+ <p>Note: Flash Player 8 does not support sending additional post parameters. SWFUpload will automatically send the post_params as part of the query string.</p>
+
+ <h5>use_query_string</h5>
+ <p>
+ The use_query_string setting may be true or false. This value indicates whether SWFUpload should send the post_params and file params on the query string or the post. This setting was introduced in SWFUpload v2.1.0.
+ </p>
+
+ <h5>preserve_relative_urls</h5>
+ <p>A boolean value that indicates whether SWFUpload should attempt to convert relative URLs used by the Flash Player to absolute URLs. If set to true SWFUpload will not modify any URLs. The default value is false.</p>
+
+ <h5>requeue_on_error</h5>
+ <p>
+ The requeue_on_error setting may be true or false. When this setting is true any files that has an
+ uploadError (excluding fileQueue errors and the FILE_CANCELLED uploadError) is returned to the front of
+ the queue rather than being discarded. The file can be uploaded again if needed. To remove the file from the
+ queue the cancelUpload method must be called.
+ </p>
+ <p>
+ All the events associated with a failed upload are still called and so the requeuing the failed upload can conflict
+ with the Queue Plugin (or custom code that uploads the entire queue). Code that automatically uploads the next file
+ in the queue will upload the failed file over and over again if care is not taken to allow the failing upload to be
+ cancelled.
+ </p>
+ <p>
+ This setting was introduced in SWFUpload v2.1.0.
+ </p>
+
+ <h5>http_success</h5>
+ <p>
+ An array that defines the HTTP Status Codes that will trigger success. 200 is always a success. Also, only the 200 status code provides the serverData.
+ </p>
+ <p>
+ When returning and accepting an HTTP Status Code other than 200 it is not necessary for the server to return content.
+ </p>
+
+ <h5>assume_success_timeout</h5>
+ <p>
+ The number of seconds SWFUpload should wait for Flash to detect the server's response after the file has finished uploading. This setting allows you to
+ work around the Flash Player bugs where long running server side scripts causes Flash to ignore the server response or the Mac Flash Player bug that ignores
+ server responses with no content.
+ </p>
+ <p>
+ Testing has shown that Flash will ignore server responses that take longer than 30 seconds after the last uploadProgress event.
+ </p>
+ <p>
+ A timeout of zero (0) seconds disables this feature and is the default value. SWFUpload will wait indefinitely for the Flash Player to trigger the uploadSuccess event.
+ </p>
+
+ <h5>file_types</h5>
+ <p>
+ The file_types setting accepts a semi-colon separated list of file extensions that are allowed to be selected by the user. Use '*.*' to allow all file types.
+ </p>
+
+ <h5>file_types_description</h5>
+ <p>
+ A text description that is displayed to the user in the File Browser dialog.
+ </p>
+
+ <h5>file_size_limit</h5>
+ <p>
+ The file_size_limit setting defines the maximum allowed size of a file to be uploaded. This setting accepts a value and unit.
+ Valid units are B, KB, MB and GB. If the unit is omitted default is KB. A value of 0 (zero) is interpreted as unlimited.
+ </p>
+ <p>
+ Note: This setting only applies to the user's browser. It does not affect any settings or limits on the web server.
+ </p>
+
+ <h5>file_upload_limit</h5>
+ <p>
+ Defines the number of files allowed to be uploaded by SWFUpload. This setting also sets the upper bound of the file_queue_limit
+ setting. Once the user has uploaded or queued the maximum number of files she will no longer be able to queue additional files. The
+ value of 0 (zero) is interpreted as unlimited. Only successful uploads (uploads the trigger the uploadSuccess event) are counted
+ toward the upload limit. The setStats function can be used to modify the number of successful uploads.
+ </p>
+ <p>Note: This value is not tracked across pages and is reset when a page is refreshed. File quotas should be managed by the web server.</p>
+
+ <h5>file_queue_limit</h5>
+ <p>
+ Defines the number of unprocessed files allowed to be simultaneously queued. Once a file is uploaded, errored, or cancelled a new
+ files can be queued in its place until the queue limit has been reached. If the upload limit (or remaining uploads allowed) is less
+ than the queue limit then the lower number is used.
+ </p>
+
+ <h5>flash_url</h5>
+ <p>
+ The full, absolute, or relative URL to the Flash Control swf file. This setting cannot be changed once the SWFUpload has been
+ instantiated. Relative URLs are relative to the page URL.
+ </p>
+
+ <h5>flash_width</h5>
+ <p>
+ <strong>(Removed in v2.1.0)</strong> Defines the width of the HTML element that contains the flash. Some browsers do not function correctly if this setting is less than 1 px.
+ This setting is optional and has a default value of 1px.
+ </p>
+
+ <h5>flash_height</h5>
+ <p>
+ <strong>(Removed in v2.1.0)</strong> Defines the height of the HTML element that contains the flash. Some browsers do not function correctly if this setting is less than 1 px.
+ This setting is optional and has a default value of 1px.
+ </p>
+
+ <h5>flash_color</h5>
+ <p>
+ <strong>Removed in v2.2.0</strong> This setting sets the background color of the HTML element that contains the flash. The default value is '#FFFFFF'.
+ </p>
+ <p>
+ Note: This setting may not be effective in "skinning" 1px flash element in all browsers.
+ </p>
+
+ <h5>prevent_swf_caching</h5>
+ <p>
+ <strong>Added in v2.2.0</strong> This boolean setting indicates whether a random value should be added to the Flash URL in an attempt to
+ prevent the browser from caching the SWF movie. This works around a bug in some IE-engine based browsers.
+ </p>
+ <p>Note: The algorithm for adding the random number to the URL is dumb and cannot handle URLs that already have some parameters.</p>
+
+ <h5>debug</h5>
+ <p>A boolean value that defines whether the debug event handler should be fired.</p>
+
+ <h5>button_placeholder_id</h5>
+ <p><strong>(Added in v2.2.0)</strong> This required setting sets the ID of DOM element that will be <em>replaced</em> by the Flash Button. This setting overrides the button_placeholder setting. The Flash button can be styled using the CSS class 'swfupload'.</p>
+
+ <h5>button_placeholder</h5>
+ <p><strong>(Added in v2.2.0)</strong> This required setting sets the DOM element that will be <em>replaced</em> by the Flash Button. This setting is only applied if the button_placeholder_id is not set. The Flash button can be styled using the CSS class 'swfupload'.</p>
+
+ <h5>button_image_url</h5>
+ <p><strong>(Added in v2.2.0)</strong> Fully qualified, absolute or relative URL to the image file to be used as the Flash button. Any Flash supported image file format can be used (another SWF file or gif, jpg, or png).</p>
+ <p>This URL is affected by the preserve_relative_urls setting and should follow the same rules as the upload_url setting.</p>
+
+ <p>The button image is treated as a sprite. There are 4 button states that must be represented by the button image. Each button state image
+ should be stacked above the other in this order: normal, hover, down/click, disabled.</p>
+
+ <h5>button_width</h5>
+ <p><strong>(Added in v2.2.0)</strong> A number defining the width of the Flash button.</p>
+
+ <h5>button_height</h5>
+ <p><strong>(Added in v2.2.0)</strong> A number defining the height of the Flash button. This value should be 1/4th of the height or
+ the button image.</p>
+
+ <h5>button_text</h5>
+ <p><strong>(Added in v2.2.0)</strong> Plain or HTML text that is displayed over the Flash button. HTML text can be further styled using CSS
+ classes and the button_text_style setting. See <a target="_blank" href="http://livedocs.adobe.com/flash/9.0/ActionScriptLangRefV3/flash/text/TextField.html#htmlText">Adobe's Flash documentation</a> for details.</p>
+
+ <h5>button_text_style</h5>
+ <p><strong>(Added in v2.2.0)</strong> CSS style string that defines how the button_text is displayed.
+ See <a target="_blank" href="http://livedocs.adobe.com/flash/9.0/ActionScriptLangRefV3/flash/text/StyleSheet.html">Adobe's Flash documentation</a> for details.</p>
+
+ <h5>button_text_top_padding</h5>
+ <p><strong>(Added in v2.2.0)</strong> Used to vertically position the Flash button text. Negative values may be used.</p>
+
+ <h5>button_text_left_padding</h5>
+ <p><strong>(Added in v2.2.0)</strong> Used to horizontally position the Flash button text. Negative values may be used.</p>
+
+ <h5>button_action</h5>
+ <p><strong>(Added in v2.2.0)</strong> Defines the action taken when the Flash button is clicked. Valid action values can be found in the swfupload.js file under the BUTTON_ACTION object.</p>
+
+ <h5>button_disabled</h5>
+ <p><strong>(Added in v2.2.0)</strong> A boolean value that sets whether the Flash button is in the disabled state. When in the disabled state the button will not execute any actions.</p>
+
+ <h5>button_cursor</h5>
+ <p><strong>(Added in v2.2.0)</strong> Used to define what type of mouse cursor is displayed when hovering over the Flash button.</p>
+
+ <h5>button_window_mode</h5>
+ <p><strong>(Added in v2.2.0)</strong> Sets the WMODE property of the Flash Movie. Valid values are available in the SWFUpload.WINDOW_MODE constants.</p>
+
+ <h5>custom_settings</h5>
+ <p>
+ The custom_settings setting allows developers to safely attach additional information to a SWFUpload instance without
+ worrying about affecting internal SWFUpload values or changes in new SWFUpload versions. This setting accepts a JavaScript
+ object.
+ </p>
+ <p>
+ Once instantiated the custom settings are accessed in the 'customSettings' property of the SWFUpload instance.
+ </p>
+ <code>var swfu = new SWFUpload({
+ custom_settings : {
+ "My Setting" : "This is my setting",
+ myothersetting : "This is my other setting",
+ integer_setting : 100,
+ a_dom_setting : document.getElementById("some_element_id")
+ }
+});
+
+var my_setting = swfu.customSettings["My Setting"]);
+swfu.customSettings["My Setting"] = "This is my new setting";
+swfu.customSetting.myothersetting = "another new value";
+swfu.customSetting.integer_setting += 25;
+swfu.customSetting["a_dom_setting"].style.visibility = "hidden";</code>
+
+ <h5>Event Handlers</h5>
+ <p>
+ The remaining settings define the event handlers called by SWFUpload during its operation. JavaScript functions should
+ be defined to handle these events as needed.
+ </p>
+
+
+
+ <h4><a name="fileobject"></a>File Object</h4>
+ <p>The file object is passed to several event handlers. It contains information about the file. Some operating systems do not fill in all the values (this
+ is especially true for the createdate and modificationdate values).</p>
+ <code>{
+ id : string, // SWFUpload file id, used for starting or cancelling and upload
+ index : number, // The index of this file for use in getFile(i)
+ name : string, // The file name. The path is not included.
+ size : number, // The file size in bytes
+ type : string, // The file type as reported by the client operating system
+ creationdate : Date, // The date the file was created
+ modificationdate : Date, // The date the file was last modified
+ filestatus : number, // The file's current status. Use SWFUpload.FILE_STATUS to interpret the value.
+
+}</code>
+
+ <h4><a name="statsobject"></a>Stats Object</h4>
+ <p>The Stats object provides information about the upload queue.</p>
+ <p>That stats object contains the following properties:</p>
+ <code>{
+ in_progress : number // 1 or 0 indicating if a file upload is currently in progress
+ files_queued : number // The number of files currently in the queue
+ successful_uploads : number // The number of files that have uploaded successfully (caused uploadSuccess to be fired)
+ upload_errors : number // The number of files that have had errors (excluding cancelled files)
+ upload_cancelled : number // The number of files that have been cancelled
+ queue_errors : number // The number of files that caused fileQueueError to be fired
+}</code>
+ <p>All these values can be updated using setStats() except the <em>in_progress</em> and <em>files_queued</em> values.</p>
+
+ <h2><a name="plugins"></a>SWFUpload Plug-ins</h2>
+
+ <p>With SWFUpload v2.0 several plugins have been introduced. They are provided to help with common tasks associated with implementing SWFUpload.</p>
+ <p>Currently most of the documentation for using the plugins is contained in the plugin JavaScript file.</p>
+
+ <h3>SWFObject</h3>
+ <p>
+ The SWFObject plugin uses the <a href="http://code.google.com/p/swfobject/">SWFObject library</a> to handle the embedding
+ of the SWFUpload Flash Component into the page.
+ </p>
+ <p>
+ This plugin also provides support for Document Ready loading and Flash Version Detection. Usage details are documented
+ in the plugin file itself. You should not use the SWFObject's Document Ready loading mixed with another libraries DOMReady. Use
+ one or the other but not both.
+ </p>
+
+ <p><strong>Flash Player 10: </strong> Because Flash Player 10 requires the SWFUpload swf to act is a button the movie must be visible in order
+ for it to load. If the button_placeholder_id is set to an element that is hidden (visibility set to hidden or display set to none) SWFUpload will
+ fail to load.</p>
+
+ <h3>Cookies</h3>
+ <p>In response to the Flash Cookie Bug the Cookies Plugin automatically retrieves your browser's cookies and sends them
+ with the upload. The are sent as POST or GET variables to the upload url.</p>
+
+ <p>Note that this plugin sends the cookies name/values in the POST or GET. On the server side they will not be accessible as cookies. Some frameworks that
+ automatically check cookies for session or authentication values still will not be able to find the values.</p>
+
+ <h3>Queue Handling</h3>
+ <p>This plugin provides Queue Handling features such as entire queue uploading, entire queue cancelling and automatic starting of uploads after being queued.</p>
+
+
+ <h3>Speed</h3>
+ <p>This Plugin extends the 'file' object with several properties that describe the current upload. This includes current speed, average speed, elapsed time, remaining time and more.</p>
+
+
+ <h2><a name="knownissues"></a>Known Issues</h2>
+ <p>The Flash Player and many Browsers have bugs that have a direct impact on the performance of SWFUpload. While we have worked
+ hard to get around many issues but there are some things that we cannot fix.</p>
+
+ <h3>Cancelling in Linux</h3>
+ <p>Older Flash 9 Players for Linux cause the browser to crash if an upload is cancelled. Newer Flash 9 Players behave better.</p>
+
+ <h3>Upload Progress in Linux</h3>
+ <p>The Flash Player in Linux sends a single uploadProgress event after the file has finished uploading.</p>
+ <p>In some distributions the entire browser locks up while the upload is in progress.</p>
+
+ <h3>Upload Progress in OS X</h3>
+ <p>There have been some reports that uploadProgress events are not fired in MAC Flash Players. The specifics haven't been pinned down but be aware of the possible issue.</p>
+
+ <h3>MIME Type</h3>
+ <p>The Flash Player uploads all files with a mime type of <em>application/octet-stream</em> regardless of the file's actual mime type.</p>
+
+ <h3>Maximum number of selected files</h3>
+ <p>The Flash Player does not impose a maximum number of selected files. However, it builds a selected files string which does have a maximum length.
+ The string is built using the file's name and the separator [quote][space][quote]. The total number of files selected is determined by the sum
+ of the lengths of the file names and a prefixed and postfixed [quote] character (2 characters) and the number of files selected minus one times 3 (for the separator string)</p>
+
+ <p>This limitation may vary from system to system. If a use selects too many files they will be receive a Flash Player generated warning message and will
+ be left at the File Selection Dialog.</p>
+
+ <h3>Proxies</h3>
+ <p>The Flash Player may not properly use proxies. It does not handle authenticating proxies well (if at all) and will some-times crash.</p>
+ <p>Some anti-virus software uses a proxy to scan uploads and cause SWFUpload to believe the entire file has been uploaded. SWFUpload will fire uploadProgress events very quickly
+ until it reaches 100% and will then seem to pause until the proxy completes uploading the file to the server.</p>
+
+ <h3>Apache mod_security</h3>
+ <p>Apache's mod_security validates POST to the server. Flash Player has implemented an edge case (there is argument as to whether it is invalid or note)
+ POST for file uploads and so servers implementing
+ mod_security will reject the upload. mod_security can be disabled using your .htaccess file</p>
+
+ <h3>SSL</h3>
+ <p>There have been some reports that the Flash Player cannot upload through SSL.
+ The issue has not been pinned down but uploading over SSL may be unreliable. There especially seems to be an issue with
+ using self-signed certificates.</p>
+ <p>Also, SSL tickets from untrusted Certificate Authorities (CA) do not work as Flash does not provide a method for accepting the certificate. It has been noted that, like the cookie bug,
+ that Flash Player on Windows obtains its trusted CA list from Internet Explorer regardless of the browser in use.</p>
+
+ <h3>Authentication</h3>
+ <p>HTTP Authentication is not well supported by the Flash Player. Later versions of Flash Player behave better. Old version of Flash Player would crash the browser.</p>
+
+ <h3>Prematurely terminated connections</h3>
+ <p>Prematurely ending the response (such as a Response.end() in ASP.Net) can sometimes cause successful uploads to be reported as failed.</p>
+
+ <h3>Filedata in Linux</h3>
+ <p>Changing the Filedata value (file_post_name setting) is ignored in Linux Flash Players.</p>
+
+ <h3>Cookie issue</h3>
+ <p>On Windows the Non-IE Flash Player plugin (FireFox, Opera, Safari, etc) will send the IE cookies regardless of the browser used. This breaks authentication and sessions for many server-side scripting technologies.</p>
+ <p>Developers should manually pass Session and Authentication cookie information and manually restore Sessions on the Server Side if they wish to use Sessions</p>
+ <p>The SWFUpload package contains work-around sample code for PHP and ASP.Net</p>
+
+ <h3>ExternalInterface bugs</h3>
+ <p>Flash Player does not properly escape data when communication with the browser/JavaScript. SWFUpload goes to great lengths to work-around this issue. If this
+ bug is fixed in future Flash Players/Browsers then SWFUpload will send extra escaped data.</p>
+
+ <h3>Server Data length bugs</h3>
+ <p>Very long server data is corrupted on Mac and Linux Flash Players. Server data will be truncated, garbled, and/or repeated. We recommend
+ keeping data returned from the server short and concise.</p>
+
+ <h3>Avant Browser</h3>
+ <p>For some users the Avant Browser does not work with SWFUpload after the Flash Control has been cached. This has been reproduced by the
+ SWFUpload developers but the Avant Browser developers did not experience any problems.</p>
+ <p>When the page is reloaded SWFUpload loads and fires the swfupload_loaded event. However, none of the ExternalInterface callback functions are defined
+ on the movie element. SWFUpload v2.0.2 has added checks which prevent swfupload_loaded from firing if the callback functions are not detected.</p>
+
+ <p><strong>SWFUpload v2.2.0 added the prevent_swf_caching setting that attempts to work around this issue.</strong></p>
+
+ <h3>File Dialog &amp; Page Changing</h3>
+ <p>Leaving or reloading the current page while the File Browser Dialog window is open will cause the browser to crash (all browsers, all OSs). Most commonly this is caused by failing to
+ cancel a click event on an &lt;a&gt; tag where the onclick event calls the selectFile or selectFiles function.</p>
+
+ <h3>Long Running Upload Scripts</h3>
+ <p>After Flash has uploaded the file to the webserver the upload script is executed. This script handles the file whether that means saving it, creating a thumbnail, scanning for viruses, etc.
+ If the upload script does not return any data within 30 seconds Flash will disconnect and return an IO Error. You can prevent this by returning characters or data while
+ the script runs (if possible). For PHP, the script continues to run and complete successfully even though Flash has terminated the connection. Any data returned
+ by the script after Flash has disconnected is lost.</p>
+
+ <h3>WMODE / BUTTON_WINDOW_MODE</h3>
+
+ <p>In some browsers the selected WMODE (which is set using the BUTTON_WINDOW_MODE) can prevent the Flash Control from loading
+ if the control is not on screen. The control will finally load once the user scrolls the page so the control becomes visible.</p>
+
+ <p>This behavior can adversely affect the SWFObject plugin. No SWFUpload events will be fire and the button image will not be
+ loaded until the control becomes visible.</p>
+
+ <h3>Memory Leaks</h3>
+ <p>Some browsers (especially IE) cannot recover memory used by the Flash Player when JavaScript communication via the ExternalInterface classes is used (like in SWFUpload).
+ Creating many SWFUpload instances and/or reloading the page several times will cause the browser to consume more and more memory until it crashes or otherwise harms the
+ system.</p>
+
+ <p>In v2.2.0 SWFUpload we gave implemented some preventative measures. Some of these measures are pro-active but it is still recommended that you
+ call the destroy method when the page unloads. If you are using hundreds of SWFUpload instances on a page you should use caution and test
+ carefully for memory leaks.</p>
+
+ <h3>Other Mac Issues</h3>
+ <ul>
+ <li>
+ Users have reported that uploading to subdomains does not work with the Mac Flash Player.
+ </li>
+ <li>
+ Users have reported that pages that redirect (HTTP Status 302) are not handled by the Mac Flash Player. Windows
+ clients seem to handle this issue.
+ </li>
+ <li>
+ The flash documentation states that on OS early than OS X 10.3 the bytes loaded is always reported as -1. SWFUpload converts
+ this to 0 but the total bytes will never be sent and 100% won't be reached. The UI should be updated to display 100% complete in
+ uploadSuccess or uploadComplete events to maintain a consistent UI.
+ </li>
+ <li>
+ Some users have reported issues if there is a space character in the upload_url for the Mac Flash Player. Avoid spaces or try replacing them with + or %20.
+ </li>
+ <li>
+ Users have reported that the Flash Player for Mac adds the PORT to the HTTP_HOST server variable (e.g., http://www.example.com:80). If you are
+ checking this variable in your server-side script be aware of the possible issue.
+ </li>
+ </ul>
+
+</body>
+</html> \ No newline at end of file
diff --git a/debian/missing-sources/swfupload/Flash/ExternalCall.as b/debian/missing-sources/swfupload/Flash/ExternalCall.as
new file mode 100644
index 0000000..091f5ec
--- /dev/null
+++ b/debian/missing-sources/swfupload/Flash/ExternalCall.as
@@ -0,0 +1,121 @@
+package {
+ import flash.external.ExternalInterface;
+
+ internal class ExternalCall
+ {
+
+ /*public function ExternalCall()
+ {
+
+ }
+ */
+
+ public static function Simple(callback:String):void {
+ ExternalInterface.call(callback);
+ }
+ public static function FileQueued(callback:String, file_object:Object):void {
+ ExternalInterface.call(callback, EscapeMessage(file_object));
+ }
+ public static function FileQueueError(callback:String, error_code:Number, file_object:Object, message:String):void {
+
+ ExternalInterface.call(callback, EscapeMessage(file_object), EscapeMessage(error_code), EscapeMessage(message));
+
+ }
+ public static function FileDialogComplete(callback:String, num_files_selected:Number, num_files_queued:Number, total_num_files_queued:Number):void {
+
+ ExternalInterface.call(callback, EscapeMessage(num_files_selected), EscapeMessage(num_files_queued), EscapeMessage(total_num_files_queued));
+
+ }
+
+ public static function UploadStart(callback:String, file_object:Object):void {
+ ExternalInterface.call(callback, EscapeMessage(file_object));
+ }
+
+ public static function UploadProgress(callback:String, file_object:Object, bytes_loaded:uint, bytes_total:uint):void {
+
+ ExternalInterface.call(callback, EscapeMessage(file_object), EscapeMessage(bytes_loaded), EscapeMessage(bytes_total));
+
+ }
+ public static function UploadSuccess(callback:String, file_object:Object, server_data:String, responseReceived:Boolean):void {
+
+ ExternalInterface.call(callback, EscapeMessage(file_object), EscapeMessage(server_data), EscapeMessage(responseReceived));
+
+ }
+ public static function UploadError(callback:String, error_code:Number, file_object:Object, message:String):void {
+
+ ExternalInterface.call(callback, EscapeMessage(file_object), EscapeMessage(error_code), EscapeMessage(message));
+
+ }
+ public static function UploadComplete(callback:String, file_object:Object):void {
+
+ ExternalInterface.call(callback, EscapeMessage(file_object));
+
+ }
+ public static function Debug(callback:String, message:String):void {
+
+ ExternalInterface.call(callback, EscapeMessage(message));
+ }
+
+ public static function Bool(callback:String):Boolean {
+ return ExternalInterface.call(callback);
+ }
+
+
+ /* Escapes all the backslashes which are not translated correctly in the Flash -> JavaScript Interface
+ *
+ * These functions had to be developed because the ExternalInterface has a bug that simply places the
+ * value a string in quotes (except for a " which is escaped) in a JavaScript string literal which
+ * is executed by the browser. These often results in improperly escaped string literals if your
+ * input string has any backslash characters. For example the string:
+ * "c:\Program Files\uploadtools\"
+ * is placed in a string literal (with quotes escaped) and becomes:
+ * var __flash__temp = "\"c:\Program Files\uploadtools\\"";
+ * This statement will cause errors when executed by the JavaScript interpreter:
+ * 1) The first \" is succesfully transformed to a "
+ * 2) \P is translated to P and the \ is lost
+ * 3) \u is interpreted as a unicode character and causes an error in IE
+ * 4) \\ is translated to \
+ * 5) leaving an unescaped " which causes an error
+ *
+ * I fixed this by escaping \ characters in all outgoing strings. The above escaped string becomes:
+ * var __flash__temp = "\"c:\\Program Files\\uploadtools\\\"";
+ * which contains the correct string literal.
+ *
+ * Note: The "var __flash__temp = " portion of the example is part of the ExternalInterface not part of
+ * my escaping routine.
+ */
+ private static function EscapeMessage(message:*):* {
+ if (message is String) {
+ message = EscapeString(message);
+ }
+ else if (message is Array) {
+ message = EscapeArray(message);
+ }
+ else if (message is Object) {
+ message = EscapeObject(message);
+ }
+
+ return message;
+ }
+
+ private static function EscapeString(message:String):String {
+ var replacePattern:RegExp = /\\/g; //new RegExp("/\\/", "g");
+ return message.replace(replacePattern, "\\\\");
+ }
+ private static function EscapeArray(message_array:Array):Array {
+ var length:uint = message_array.length;
+ var i:uint = 0;
+ for (i; i < length; i++) {
+ message_array[i] = EscapeMessage(message_array[i]);
+ }
+ return message_array;
+ }
+ private static function EscapeObject(message_obj:Object):Object {
+ for (var name:String in message_obj) {
+ message_obj[name] = EscapeMessage(message_obj[name]);
+ }
+ return message_obj;
+ }
+
+ }
+} \ No newline at end of file
diff --git a/debian/missing-sources/swfupload/Flash/FileItem.as b/debian/missing-sources/swfupload/Flash/FileItem.as
new file mode 100644
index 0000000..9eb3952
--- /dev/null
+++ b/debian/missing-sources/swfupload/Flash/FileItem.as
@@ -0,0 +1,112 @@
+package {
+ import flash.net.FileReference;
+
+ internal class FileItem
+ {
+ private static var file_id_sequence:Number = 0; // tracks the file id sequence
+
+ private var postObject:Object;
+ public var file_reference:FileReference;
+ public var id:String;
+ public var index:Number = -1;
+ public var file_status:int = 0;
+ private var js_object:Object;
+
+ public static var FILE_STATUS_QUEUED:int = -1;
+ public static var FILE_STATUS_IN_PROGRESS:int = -2;
+ public static var FILE_STATUS_ERROR:int = -3;
+ public static var FILE_STATUS_SUCCESS:int = -4;
+ public static var FILE_STATUS_CANCELLED:int = -5;
+ public static var FILE_STATUS_NEW:int = -6; // This file status should never be sent to JavaScript
+
+ public function FileItem(file_reference:FileReference, control_id:String, index:Number)
+ {
+ this.postObject = {};
+ this.file_reference = file_reference;
+ this.id = control_id + "_" + (FileItem.file_id_sequence++);
+ this.file_status = FileItem.FILE_STATUS_NEW;
+ this.index = index;
+
+ this.js_object = {
+ id: this.id,
+ index: this.index,
+ post: this.GetPostObject()
+ };
+
+ // Cleanly attempt to retrieve the FileReference info
+ // this can fail and so is wrapped in try..catch
+ try {
+ this.js_object.name = this.file_reference.name;
+ this.js_object.size = this.file_reference.size;
+ this.js_object.type = this.file_reference.type || "";
+ this.js_object.creationdate = this.file_reference.creationDate || new Date(0);
+ this.js_object.modificationdate = this.file_reference.modificationDate || new Date(0);
+ } catch (ex:Error) {
+ this.file_status = FileItem.FILE_STATUS_ERROR;
+ }
+
+ this.js_object.filestatus = this.file_status;
+ }
+
+ public function AddParam(name:String, value:String):void {
+ this.postObject[name] = value;
+ }
+
+ public function RemoveParam(name:String):void {
+ delete this.postObject[name];
+ }
+
+ public function GetPostObject(escape:Boolean = false):Object {
+ if (escape) {
+ var escapedPostObject:Object = { };
+ for (var k:String in this.postObject) {
+ if (this.postObject.hasOwnProperty(k)) {
+ var escapedName:String = FileItem.EscapeParamName(k);
+ escapedPostObject[escapedName] = this.postObject[k];
+ }
+ }
+ return escapedPostObject;
+ } else {
+ return this.postObject;
+ }
+ }
+
+ // Create the simply file object that is passed to the browser
+ public function ToJavaScriptObject():Object {
+ this.js_object.filestatus = this.file_status;
+ this.js_object.post = this.GetPostObject(true);
+
+ return this.js_object;
+ }
+
+ public function toString():String {
+ return "FileItem - ID: " + this.id;
+ }
+
+ /*
+ // The purpose of this function is to escape the property names so when Flash
+ // passes them back to javascript they can be interpretted correctly.
+ // ***They have to be unescaped again by JavaScript.**
+ //
+ // This works around a bug where Flash sends objects this way:
+ // object.parametername = "value";
+ // instead of
+ // object["parametername"] = "value";
+ // This can be a problem if the parameter name has characters that are not
+ // allowed in JavaScript identifiers:
+ // object.parameter.name! = "value";
+ // does not work but,
+ // object["parameter.name!"] = "value";
+ // would have worked.
+ */
+ public static function EscapeParamName(name:String):String {
+ name = name.replace(/[^a-z0-9_]/gi, FileItem.EscapeCharacter);
+ name = name.replace(/^[0-9]/, FileItem.EscapeCharacter);
+ return name;
+ }
+ public static function EscapeCharacter():String {
+ return "$" + ("0000" + arguments[0].charCodeAt(0).toString(16)).substr(-4, 4);
+ }
+
+ }
+} \ No newline at end of file
diff --git a/debian/missing-sources/swfupload/Flash/SWFUpload v2.as3proj b/debian/missing-sources/swfupload/Flash/SWFUpload v2.as3proj
new file mode 100644
index 0000000..302944a
--- /dev/null
+++ b/debian/missing-sources/swfupload/Flash/SWFUpload v2.as3proj
@@ -0,0 +1,79 @@
+<?xml version="1.0" encoding="utf-8"?>
+<project>
+ <!-- Output SWF options -->
+ <output>
+ <movie disabled="False" />
+ <movie input="" />
+ <movie path="swfupload.swf" />
+ <movie fps="15" />
+ <movie width="300" />
+ <movie height="300" />
+ <movie version="9" />
+ <movie background="#FFFFFF" />
+ </output>
+ <!-- Other classes to be compiled into your SWF -->
+ <classpaths>
+ <class path="." />
+ </classpaths>
+ <!-- Build options -->
+ <build>
+ <option accessible="False" />
+ <option allowSourcePathOverlap="False" />
+ <option benchmark="False" />
+ <option es="False" />
+ <option loadConfig="" />
+ <option optimize="True" />
+ <option showActionScriptWarnings="True" />
+ <option showBindingWarnings="True" />
+ <option showDeprecationWarnings="True" />
+ <option showUnusedTypeSelectorWarnings="True" />
+ <option strict="True" />
+ <option useNetwork="True" />
+ <option useResourceBundleMetadata="True" />
+ <option warnings="True" />
+ <option verboseStackTraces="False" />
+ <option additional="" />
+ <option customSDK="" />
+ </build>
+ <!-- SWC Include Libraries -->
+ <includeLibraries>
+ <!-- example: <element path="..." /> -->
+ </includeLibraries>
+ <!-- SWC Libraries -->
+ <libraryPaths>
+ <!-- example: <element path="..." /> -->
+ </libraryPaths>
+ <!-- External Libraries -->
+ <externalLibraryPaths>
+ <!-- example: <element path="..." /> -->
+ </externalLibraryPaths>
+ <!-- Runtime Shared Libraries -->
+ <rslPaths>
+ <!-- example: <element path="..." /> -->
+ </rslPaths>
+ <!-- Intrinsic Libraries -->
+ <intrinsics>
+ <!-- example: <element path="..." /> -->
+ </intrinsics>
+ <!-- Assets to embed into the output SWF -->
+ <library>
+ <!-- example: <asset path="..." id="..." update="..." glyphs="..." mode="..." place="..." sharepoint="..." /> -->
+ </library>
+ <!-- Class files to compile (other referenced classes will automatically be included) -->
+ <compileTargets>
+ <compile path="SWFUpload.as" />
+ </compileTargets>
+ <!-- Paths to exclude from the Project Explorer tree -->
+ <hiddenPaths>
+ <!-- example: <hidden path="..." /> -->
+ </hiddenPaths>
+ <!-- Executed before build -->
+ <preBuildCommand />
+ <!-- Executed after build -->
+ <postBuildCommand alwaysRun="True">deploy.bat</postBuildCommand>
+ <!-- Other project options -->
+ <options>
+ <option showHiddenPaths="False" />
+ <option testMovie="NewWindow" />
+ </options>
+</project> \ No newline at end of file
diff --git a/debian/missing-sources/swfupload/Flash/SWFUpload.as b/debian/missing-sources/swfupload/Flash/SWFUpload.as
new file mode 100644
index 0000000..3b0e11d
--- /dev/null
+++ b/debian/missing-sources/swfupload/Flash/SWFUpload.as
@@ -0,0 +1,1519 @@
+package {
+ import flash.display.BlendMode;
+ import flash.display.DisplayObjectContainer;
+ import flash.display.Loader;
+ import flash.display.Stage;
+ import flash.display.Sprite;
+ import flash.display.StageAlign;
+ import flash.display.StageScaleMode;
+ import flash.net.FileReferenceList;
+ import flash.net.FileReference;
+ import flash.net.FileFilter;
+ import flash.net.URLRequest;
+ import flash.net.URLRequestMethod;
+ import flash.net.URLVariables;
+ import flash.events.*;
+ import flash.external.ExternalInterface;
+ import flash.system.Security;
+ import flash.text.AntiAliasType;
+ import flash.text.GridFitType;
+ import flash.text.StaticText;
+ import flash.text.StyleSheet;
+ import flash.text.TextDisplayMode;
+ import flash.text.TextField;
+ import flash.text.TextFieldType;
+ import flash.text.TextFieldAutoSize;
+ import flash.text.TextFormat;
+ import flash.ui.Mouse;
+ import flash.utils.Timer;
+
+ import FileItem;
+ import ExternalCall;
+
+ public class SWFUpload extends Sprite {
+ // Cause SWFUpload to start as soon as the movie starts
+ public static function main():void
+ {
+ var SWFUpload:SWFUpload = new SWFUpload();
+ }
+
+ private const build_number:String = "SWFUPLOAD 2.2.0";
+
+ // State tracking variables
+ private var fileBrowserMany:FileReferenceList = new FileReferenceList();
+ private var fileBrowserOne:FileReference = null; // This isn't set because it can't be reused like the FileReferenceList. It gets setup in the SelectFile method
+
+ private var file_queue:Array = new Array(); // holds a list of all items that are to be uploaded.
+ private var current_file_item:FileItem = null; // the item that is currently being uploaded.
+
+ private var file_index:Array = new Array();
+
+ private var successful_uploads:Number = 0; // Tracks the uploads that have been completed
+ private var queue_errors:Number = 0; // Tracks files rejected during queueing
+ private var upload_errors:Number = 0; // Tracks files that fail upload
+ private var upload_cancelled:Number = 0; // Tracks number of cancelled files
+ private var queued_uploads:Number = 0; // Tracks the FileItems that are waiting to be uploaded.
+
+ private var valid_file_extensions:Array = new Array();// Holds the parsed valid extensions.
+
+ private var serverDataTimer:Timer = null;
+ private var assumeSuccessTimer:Timer = null;
+
+ private var restoreExtIntTimer:Timer;
+ private var hasCalledFlashReady:Boolean = false;
+
+ // Callbacks
+ private var flashReady_Callback:String;
+ private var fileDialogStart_Callback:String;
+ private var fileQueued_Callback:String;
+ private var fileQueueError_Callback:String;
+ private var fileDialogComplete_Callback:String;
+
+ private var uploadStart_Callback:String;
+ private var uploadProgress_Callback:String;
+ private var uploadError_Callback:String;
+ private var uploadSuccess_Callback:String;
+
+ private var uploadComplete_Callback:String;
+
+ private var debug_Callback:String;
+ private var testExternalInterface_Callback:String;
+ private var cleanUp_Callback:String;
+
+ // Values passed in from the HTML
+ private var movieName:String;
+ private var uploadURL:String;
+ private var filePostName:String;
+ private var uploadPostObject:Object;
+ private var fileTypes:String;
+ private var fileTypesDescription:String;
+ private var fileSizeLimit:Number;
+ private var fileUploadLimit:Number = 0;
+ private var fileQueueLimit:Number = 0;
+ private var useQueryString:Boolean = false;
+ private var requeueOnError:Boolean = false;
+ private var httpSuccess:Array = [];
+ private var assumeSuccessTimeout:Number = 0;
+ private var debugEnabled:Boolean;
+
+ private var buttonLoader:Loader;
+ private var buttonTextField:TextField;
+ private var buttonCursorSprite:Sprite;
+ private var buttonImageURL:String;
+ private var buttonWidth:Number;
+ private var buttonHeight:Number;
+ private var buttonText:String;
+ private var buttonTextStyle:String;
+ private var buttonTextTopPadding:Number;
+ private var buttonTextLeftPadding:Number;
+ private var buttonAction:Number;
+ private var buttonCursor:Number;
+ private var buttonStateOver:Boolean;
+ private var buttonStateMouseDown:Boolean;
+ private var buttonStateDisabled:Boolean;
+
+ // Error code "constants"
+ // Size check constants
+ private var SIZE_TOO_BIG:Number = 1;
+ private var SIZE_ZERO_BYTE:Number = -1;
+ private var SIZE_OK:Number = 0;
+
+ // Queue errors
+ private var ERROR_CODE_QUEUE_LIMIT_EXCEEDED:Number = -100;
+ private var ERROR_CODE_FILE_EXCEEDS_SIZE_LIMIT:Number = -110;
+ private var ERROR_CODE_ZERO_BYTE_FILE:Number = -120;
+ private var ERROR_CODE_INVALID_FILETYPE:Number = -130;
+
+ // Upload Errors
+ private var ERROR_CODE_HTTP_ERROR:Number = -200;
+ private var ERROR_CODE_MISSING_UPLOAD_URL:Number = -210;
+ private var ERROR_CODE_IO_ERROR:Number = -220;
+ private var ERROR_CODE_SECURITY_ERROR:Number = -230;
+ private var ERROR_CODE_UPLOAD_LIMIT_EXCEEDED:Number = -240;
+ private var ERROR_CODE_UPLOAD_FAILED:Number = -250;
+ private var ERROR_CODE_SPECIFIED_FILE_ID_NOT_FOUND:Number = -260;
+ private var ERROR_CODE_FILE_VALIDATION_FAILED:Number = -270;
+ private var ERROR_CODE_FILE_CANCELLED:Number = -280;
+ private var ERROR_CODE_UPLOAD_STOPPED:Number = -290;
+
+
+ // Button Actions
+ private var BUTTON_ACTION_SELECT_FILE:Number = -100;
+ private var BUTTON_ACTION_SELECT_FILES:Number = -110;
+ private var BUTTON_ACTION_START_UPLOAD:Number = -120;
+
+ private var BUTTON_CURSOR_ARROW:Number = -1;
+ private var BUTTON_CURSOR_HAND:Number = -2;
+
+ public function SWFUpload() {
+ // Do the feature detection. Make sure this version of Flash supports the features we need. If not
+ // abort initialization.
+ if (!flash.net.FileReferenceList || !flash.net.FileReference || !flash.net.URLRequest || !flash.external.ExternalInterface || !flash.external.ExternalInterface.available || !DataEvent.UPLOAD_COMPLETE_DATA) {
+ return;
+ }
+
+ Security.allowDomain("*"); // Allow uploading to any domain
+
+ // Keep Flash Player busy so it doesn't show the "flash script is running slowly" error
+ var counter:Number = 0;
+ root.addEventListener(Event.ENTER_FRAME, function ():void { if (++counter > 100) counter = 0; });
+
+ // Setup file FileReferenceList events
+ this.fileBrowserMany.addEventListener(Event.SELECT, this.Select_Many_Handler);
+ this.fileBrowserMany.addEventListener(Event.CANCEL, this.DialogCancelled_Handler);
+
+
+ this.stage.align = StageAlign.TOP_LEFT;
+ this.stage.scaleMode = StageScaleMode.NO_SCALE;
+
+ // Setup the button and text label
+ this.buttonLoader = new Loader();
+ var doNothing:Function = function ():void { };
+ this.buttonLoader.contentLoaderInfo.addEventListener(IOErrorEvent.IO_ERROR, doNothing );
+ this.buttonLoader.contentLoaderInfo.addEventListener(HTTPStatusEvent.HTTP_STATUS, doNothing );
+ this.stage.addChild(this.buttonLoader);
+
+ var self:SWFUpload = this;
+
+ this.stage.addEventListener(MouseEvent.CLICK, function (event:MouseEvent):void {
+ self.UpdateButtonState();
+ self.ButtonClickHandler(event);
+ });
+ this.stage.addEventListener(MouseEvent.MOUSE_DOWN, function (event:MouseEvent):void {
+ self.buttonStateMouseDown = true;
+ self.UpdateButtonState();
+ });
+ this.stage.addEventListener(MouseEvent.MOUSE_UP, function (event:MouseEvent):void {
+ self.buttonStateMouseDown = false;
+ self.UpdateButtonState();
+ });
+ this.stage.addEventListener(MouseEvent.MOUSE_OVER, function (event:MouseEvent):void {
+ self.buttonStateMouseDown = event.buttonDown;
+ self.buttonStateOver = true;
+ self.UpdateButtonState();
+ });
+ this.stage.addEventListener(MouseEvent.MOUSE_OUT, function (event:MouseEvent):void {
+ self.buttonStateMouseDown = false;
+ self.buttonStateOver = false;
+ self.UpdateButtonState();
+ });
+ // Handle the mouse leaving the flash movie altogether
+ this.stage.addEventListener(Event.MOUSE_LEAVE, function (event:Event):void {
+ self.buttonStateMouseDown = false;
+ self.buttonStateOver = false;
+ self.UpdateButtonState();
+ });
+
+ this.buttonTextField = new TextField();
+ this.buttonTextField.type = TextFieldType.DYNAMIC;
+ this.buttonTextField.antiAliasType = AntiAliasType.ADVANCED;
+ this.buttonTextField.autoSize = TextFieldAutoSize.NONE;
+ this.buttonTextField.cacheAsBitmap = true;
+ this.buttonTextField.multiline = true;
+ this.buttonTextField.wordWrap = false;
+ this.buttonTextField.tabEnabled = false;
+ this.buttonTextField.background = false;
+ this.buttonTextField.border = false;
+ this.buttonTextField.selectable = false;
+ this.buttonTextField.condenseWhite = true;
+
+ this.stage.addChild(this.buttonTextField);
+
+
+ this.buttonCursorSprite = new Sprite();
+ this.buttonCursorSprite.graphics.beginFill(0xFFFFFF, 0);
+ this.buttonCursorSprite.graphics.drawRect(0, 0, 1, 1);
+ this.buttonCursorSprite.graphics.endFill();
+ this.buttonCursorSprite.buttonMode = true;
+ this.buttonCursorSprite.x = 0;
+ this.buttonCursorSprite.y = 0;
+ this.buttonCursorSprite.addEventListener(MouseEvent.CLICK, doNothing);
+ this.stage.addChild(this.buttonCursorSprite);
+
+ // Get the movie name
+ this.movieName = root.loaderInfo.parameters.movieName;
+
+ // **Configure the callbacks**
+ // The JavaScript tracks all the instances of SWFUpload on a page. We can access the instance
+ // associated with this SWF file using the movieName. Each callback is accessible by making
+ // a call directly to it on our instance. There is no error handling for undefined callback functions.
+ // A developer would have to deliberately remove the default functions,set the variable to null, or remove
+ // it from the init function.
+ this.flashReady_Callback = "SWFUpload.instances[\"" + this.movieName + "\"].flashReady";
+ this.fileDialogStart_Callback = "SWFUpload.instances[\"" + this.movieName + "\"].fileDialogStart";
+ this.fileQueued_Callback = "SWFUpload.instances[\"" + this.movieName + "\"].fileQueued";
+ this.fileQueueError_Callback = "SWFUpload.instances[\"" + this.movieName + "\"].fileQueueError";
+ this.fileDialogComplete_Callback = "SWFUpload.instances[\"" + this.movieName + "\"].fileDialogComplete";
+
+ this.uploadStart_Callback = "SWFUpload.instances[\"" + this.movieName + "\"].uploadStart";
+ this.uploadProgress_Callback = "SWFUpload.instances[\"" + this.movieName + "\"].uploadProgress";
+ this.uploadError_Callback = "SWFUpload.instances[\"" + this.movieName + "\"].uploadError";
+ this.uploadSuccess_Callback = "SWFUpload.instances[\"" + this.movieName + "\"].uploadSuccess";
+
+ this.uploadComplete_Callback = "SWFUpload.instances[\"" + this.movieName + "\"].uploadComplete";
+
+ this.debug_Callback = "SWFUpload.instances[\"" + this.movieName + "\"].debug";
+
+ this.testExternalInterface_Callback = "SWFUpload.instances[\"" + this.movieName + "\"].testExternalInterface";
+ this.cleanUp_Callback = "SWFUpload.instances[\"" + this.movieName + "\"].cleanUp";
+
+ // Get the Flash Vars
+ this.uploadURL = root.loaderInfo.parameters.uploadURL;
+ this.filePostName = root.loaderInfo.parameters.filePostName;
+ this.fileTypes = root.loaderInfo.parameters.fileTypes;
+ this.fileTypesDescription = root.loaderInfo.parameters.fileTypesDescription + " (" + this.fileTypes + ")";
+ this.loadPostParams(root.loaderInfo.parameters.params);
+
+
+ if (!this.filePostName) {
+ this.filePostName = "Filedata";
+ }
+ if (!this.fileTypes) {
+ this.fileTypes = "*.*";
+ }
+ if (!this.fileTypesDescription) {
+ this.fileTypesDescription = "All Files";
+ }
+
+ this.LoadFileExensions(this.fileTypes);
+
+ try {
+ this.debugEnabled = root.loaderInfo.parameters.debugEnabled == "true" ? true : false;
+ } catch (ex:Object) {
+ this.debugEnabled = false;
+ }
+
+ try {
+ this.SetFileSizeLimit(String(root.loaderInfo.parameters.fileSizeLimit));
+ } catch (ex:Object) {
+ this.fileSizeLimit = 0;
+ }
+
+
+ try {
+ this.fileUploadLimit = Number(root.loaderInfo.parameters.fileUploadLimit);
+ if (this.fileUploadLimit < 0) this.fileUploadLimit = 0;
+ } catch (ex:Object) {
+ this.fileUploadLimit = 0;
+ }
+
+ try {
+ this.fileQueueLimit = Number(root.loaderInfo.parameters.fileQueueLimit);
+ if (this.fileQueueLimit < 0) this.fileQueueLimit = 0;
+ } catch (ex:Object) {
+ this.fileQueueLimit = 0;
+ }
+
+ // Set the queue limit to match the upload limit when the queue limit is bigger than the upload limit
+ if (this.fileQueueLimit > this.fileUploadLimit && this.fileUploadLimit != 0) this.fileQueueLimit = this.fileUploadLimit;
+ // The the queue limit is unlimited and the upload limit is not then set the queue limit to the upload limit
+ if (this.fileQueueLimit == 0 && this.fileUploadLimit != 0) this.fileQueueLimit = this.fileUploadLimit;
+
+ try {
+ this.useQueryString = root.loaderInfo.parameters.useQueryString == "true" ? true : false;
+ } catch (ex:Object) {
+ this.useQueryString = false;
+ }
+
+ try {
+ this.requeueOnError = root.loaderInfo.parameters.requeueOnError == "true" ? true : false;
+ } catch (ex:Object) {
+ this.requeueOnError = false;
+ }
+
+ try {
+ this.SetHTTPSuccess(String(root.loaderInfo.parameters.httpSuccess));
+ } catch (ex:Object) {
+ this.SetHTTPSuccess([]);
+ }
+
+ try {
+ this.SetAssumeSuccessTimeout(Number(root.loaderInfo.parameters.assumeSuccessTimeout));
+ } catch (ex:Object) {
+ this.SetAssumeSuccessTimeout(0);
+ }
+
+
+ try {
+ this.SetButtonDimensions(Number(root.loaderInfo.parameters.buttonWidth), Number(root.loaderInfo.parameters.buttonHeight));
+ } catch (ex:Object) {
+ this.SetButtonDimensions(0, 0);
+ }
+
+ try {
+ this.SetButtonImageURL(String(root.loaderInfo.parameters.buttonImageURL));
+ } catch (ex:Object) {
+ this.SetButtonImageURL("");
+ }
+
+ try {
+ this.SetButtonText(String(root.loaderInfo.parameters.buttonText));
+ } catch (ex:Object) {
+ this.SetButtonText("");
+ }
+
+ try {
+ this.SetButtonTextPadding(Number(root.loaderInfo.parameters.buttonTextLeftPadding), Number(root.loaderInfo.parameters.buttonTextTopPadding));
+ } catch (ex:Object) {
+ this.SetButtonTextPadding(0, 0);
+ }
+
+ try {
+ this.SetButtonTextStyle(String(root.loaderInfo.parameters.buttonTextStyle));
+ } catch (ex:Object) {
+ this.SetButtonTextStyle("");
+ }
+
+ try {
+ this.SetButtonAction(Number(root.loaderInfo.parameters.buttonAction));
+ } catch (ex:Object) {
+ this.SetButtonAction(this.BUTTON_ACTION_SELECT_FILES);
+ }
+
+ try {
+ this.SetButtonDisabled(root.loaderInfo.parameters.buttonDisabled == "true" ? true : false);
+ } catch (ex:Object) {
+ this.SetButtonDisabled(Boolean(false));
+ }
+
+ try {
+ this.SetButtonCursor(Number(root.loaderInfo.parameters.buttonCursor));
+ } catch (ex:Object) {
+ this.SetButtonCursor(this.BUTTON_CURSOR_ARROW);
+ }
+
+ this.SetupExternalInterface();
+
+ this.Debug("SWFUpload Init Complete");
+ this.PrintDebugInfo();
+
+ if (ExternalCall.Bool(this.testExternalInterface_Callback)) {
+ ExternalCall.Simple(this.flashReady_Callback);
+ this.hasCalledFlashReady = true;
+ }
+
+ // Start periodically checking the external interface
+ var oSelf:SWFUpload = this;
+ this.restoreExtIntTimer = new Timer(1000, 0);
+ this.restoreExtIntTimer.addEventListener(TimerEvent.TIMER, function ():void { oSelf.CheckExternalInterface();} );
+ this.restoreExtIntTimer.start();
+ }
+
+ // Used to periodically check that the External Interface functions are still working
+ private function CheckExternalInterface():void {
+ if (!ExternalCall.Bool(this.testExternalInterface_Callback)) {
+ this.SetupExternalInterface();
+ this.Debug("ExternalInterface reinitialized");
+ if (!this.hasCalledFlashReady) {
+ ExternalCall.Simple(this.flashReady_Callback);
+ this.hasCalledFlashReady = true;
+ }
+ }
+ }
+
+ // Called by JS to see if it can access the external interface
+ private function TestExternalInterface():Boolean {
+ return true;
+ }
+
+ private function SetupExternalInterface():void {
+ try {
+ ExternalInterface.addCallback("SelectFile", this.SelectFile);
+ ExternalInterface.addCallback("SelectFiles", this.SelectFiles);
+ ExternalInterface.addCallback("StartUpload", this.StartUpload);
+ ExternalInterface.addCallback("ReturnUploadStart", this.ReturnUploadStart);
+ ExternalInterface.addCallback("StopUpload", this.StopUpload);
+ ExternalInterface.addCallback("CancelUpload", this.CancelUpload);
+ ExternalInterface.addCallback("RequeueUpload", this.RequeueUpload);
+
+ ExternalInterface.addCallback("GetStats", this.GetStats);
+ ExternalInterface.addCallback("SetStats", this.SetStats);
+ ExternalInterface.addCallback("GetFile", this.GetFile);
+ ExternalInterface.addCallback("GetFileByIndex", this.GetFileByIndex);
+
+ ExternalInterface.addCallback("AddFileParam", this.AddFileParam);
+ ExternalInterface.addCallback("RemoveFileParam", this.RemoveFileParam);
+
+ ExternalInterface.addCallback("SetUploadURL", this.SetUploadURL);
+ ExternalInterface.addCallback("SetPostParams", this.SetPostParams);
+ ExternalInterface.addCallback("SetFileTypes", this.SetFileTypes);
+ ExternalInterface.addCallback("SetFileSizeLimit", this.SetFileSizeLimit);
+ ExternalInterface.addCallback("SetFileUploadLimit", this.SetFileUploadLimit);
+ ExternalInterface.addCallback("SetFileQueueLimit", this.SetFileQueueLimit);
+ ExternalInterface.addCallback("SetFilePostName", this.SetFilePostName);
+ ExternalInterface.addCallback("SetUseQueryString", this.SetUseQueryString);
+ ExternalInterface.addCallback("SetRequeueOnError", this.SetRequeueOnError);
+ ExternalInterface.addCallback("SetHTTPSuccess", this.SetHTTPSuccess);
+ ExternalInterface.addCallback("SetAssumeSuccessTimeout", this.SetAssumeSuccessTimeout);
+ ExternalInterface.addCallback("SetDebugEnabled", this.SetDebugEnabled);
+
+ ExternalInterface.addCallback("SetButtonImageURL", this.SetButtonImageURL);
+ ExternalInterface.addCallback("SetButtonDimensions", this.SetButtonDimensions);
+ ExternalInterface.addCallback("SetButtonText", this.SetButtonText);
+ ExternalInterface.addCallback("SetButtonTextPadding", this.SetButtonTextPadding);
+ ExternalInterface.addCallback("SetButtonTextStyle", this.SetButtonTextStyle);
+ ExternalInterface.addCallback("SetButtonAction", this.SetButtonAction);
+ ExternalInterface.addCallback("SetButtonDisabled", this.SetButtonDisabled);
+ ExternalInterface.addCallback("SetButtonCursor", this.SetButtonCursor);
+
+ ExternalInterface.addCallback("TestExternalInterface", this.TestExternalInterface);
+
+ } catch (ex:Error) {
+ this.Debug("Callbacks where not set: " + ex.message);
+ return;
+ }
+
+ ExternalCall.Simple(this.cleanUp_Callback);
+ }
+
+ /* *****************************************
+ * FileReference Event Handlers
+ * *************************************** */
+ private function DialogCancelled_Handler(event:Event):void {
+ this.Debug("Event: fileDialogComplete: File Dialog window cancelled.");
+ ExternalCall.FileDialogComplete(this.fileDialogComplete_Callback, 0, 0, this.queued_uploads);
+ }
+
+ private function Open_Handler(event:Event):void {
+ this.Debug("Event: uploadProgress (OPEN): File ID: " + this.current_file_item.id);
+ ExternalCall.UploadProgress(this.uploadProgress_Callback, this.current_file_item.ToJavaScriptObject(), 0, this.current_file_item.file_reference.size);
+ }
+
+ private function FileProgress_Handler(event:ProgressEvent):void {
+ // On early than Mac OS X 10.3 bytesLoaded is always -1, convert this to zero. Do bytesTotal for good measure.
+ // http://livedocs.adobe.com/flex/3/langref/flash/net/FileReference.html#event:progress
+ var bytesLoaded:Number = event.bytesLoaded < 0 ? 0 : event.bytesLoaded;
+ var bytesTotal:Number = event.bytesTotal < 0 ? 0 : event.bytesTotal;
+
+ // Because Flash never fires a complete event if the server doesn't respond after 30 seconds or on Macs if there
+ // is no content in the response we'll set a timer and assume that the upload is successful after the defined amount of
+ // time. If the timeout is zero then we won't use the timer.
+ if (bytesLoaded === bytesTotal && bytesTotal > 0 && this.assumeSuccessTimeout > 0) {
+ if (this.assumeSuccessTimer !== null) {
+ this.assumeSuccessTimer.stop();
+ this.assumeSuccessTimer = null;
+ }
+
+ this.assumeSuccessTimer = new Timer(this.assumeSuccessTimeout * 1000, 1);
+ this.assumeSuccessTimer.addEventListener(TimerEvent.TIMER_COMPLETE, AssumeSuccessTimer_Handler);
+ this.assumeSuccessTimer.start();
+ }
+
+ this.Debug("Event: uploadProgress: File ID: " + this.current_file_item.id + ". Bytes: " + bytesLoaded + ". Total: " + bytesTotal);
+ ExternalCall.UploadProgress(this.uploadProgress_Callback, this.current_file_item.ToJavaScriptObject(), bytesLoaded, bytesTotal);
+ }
+
+ private function AssumeSuccessTimer_Handler(event:TimerEvent):void {
+ this.Debug("Event: AssumeSuccess: " + this.assumeSuccessTimeout + " passed without server response");
+ this.UploadSuccess(this.current_file_item, "", false);
+ }
+
+ private function Complete_Handler(event:Event):void {
+ /* Because we can't do COMPLETE or DATA events (we have to do both) we can't
+ * just call uploadSuccess from the complete handler, we have to wait for
+ * the Data event which may never come. However, testing shows it always comes
+ * within a couple milliseconds if it is going to come so the solution is:
+ *
+ * Set a timer in the COMPLETE event (which always fires) and if DATA is fired
+ * it will stop the timer and call uploadComplete
+ *
+ * If the timer expires then DATA won't be fired and we call uploadComplete
+ * */
+
+ // Set the timer
+ if (serverDataTimer != null) {
+ this.serverDataTimer.stop();
+ this.serverDataTimer = null;
+ }
+
+ this.serverDataTimer = new Timer(100, 1);
+ //var self:SWFUpload = this;
+ this.serverDataTimer.addEventListener(TimerEvent.TIMER, this.ServerDataTimer_Handler);
+ this.serverDataTimer.start();
+ }
+ private function ServerDataTimer_Handler(event:TimerEvent):void {
+ this.UploadSuccess(this.current_file_item, "");
+ }
+
+ private function ServerData_Handler(event:DataEvent):void {
+ this.UploadSuccess(this.current_file_item, event.data);
+ }
+
+ private function UploadSuccess(file:FileItem, serverData:String, responseReceived:Boolean = true):void {
+ if (this.serverDataTimer !== null) {
+ this.serverDataTimer.stop();
+ this.serverDataTimer = null;
+ }
+ if (this.assumeSuccessTimer !== null) {
+ this.assumeSuccessTimer.stop();
+ this.assumeSuccessTimer = null;
+ }
+
+ this.successful_uploads++;
+ file.file_status = FileItem.FILE_STATUS_SUCCESS;
+
+ this.Debug("Event: uploadSuccess: File ID: " + file.id + " Response Received: " + responseReceived.toString() + " Data: " + serverData);
+ ExternalCall.UploadSuccess(this.uploadSuccess_Callback, file.ToJavaScriptObject(), serverData, responseReceived);
+
+ this.UploadComplete(false);
+
+ }
+
+ private function HTTPError_Handler(event:HTTPStatusEvent):void {
+ var isSuccessStatus:Boolean = false;
+ for (var i:Number = 0; i < this.httpSuccess.length; i++) {
+ if (this.httpSuccess[i] === event.status) {
+ isSuccessStatus = true;
+ break;
+ }
+ }
+
+
+ if (isSuccessStatus) {
+ this.Debug("Event: httpError: Translating status code " + event.status + " to uploadSuccess");
+
+ var serverDataEvent:DataEvent = new DataEvent(DataEvent.UPLOAD_COMPLETE_DATA, event.bubbles, event.cancelable, "");
+ this.ServerData_Handler(serverDataEvent);
+ } else {
+ this.upload_errors++;
+ this.current_file_item.file_status = FileItem.FILE_STATUS_ERROR;
+
+ this.Debug("Event: uploadError: HTTP ERROR : File ID: " + this.current_file_item.id + ". HTTP Status: " + event.status + ".");
+ ExternalCall.UploadError(this.uploadError_Callback, this.ERROR_CODE_HTTP_ERROR, this.current_file_item.ToJavaScriptObject(), event.status.toString());
+ this.UploadComplete(true); // An IO Error is also called so we don't want to complete the upload yet.
+ }
+ }
+
+ // Note: Flash Player does not support Uploads that require authentication. Attempting this will trigger an
+ // IO Error or it will prompt for a username and password and may crash the browser (FireFox/Opera)
+ private function IOError_Handler(event:IOErrorEvent):void {
+ // Only trigger an IO Error event if we haven't already done an HTTP error
+ if (this.current_file_item.file_status != FileItem.FILE_STATUS_ERROR) {
+ this.upload_errors++;
+ this.current_file_item.file_status = FileItem.FILE_STATUS_ERROR;
+
+ this.Debug("Event: uploadError : IO Error : File ID: " + this.current_file_item.id + ". IO Error: " + event.text);
+ ExternalCall.UploadError(this.uploadError_Callback, this.ERROR_CODE_IO_ERROR, this.current_file_item.ToJavaScriptObject(), event.text);
+ }
+
+ this.UploadComplete(true);
+ }
+
+ private function SecurityError_Handler(event:SecurityErrorEvent):void {
+ this.upload_errors++;
+ this.current_file_item.file_status = FileItem.FILE_STATUS_ERROR;
+
+ this.Debug("Event: uploadError : Security Error : File Number: " + this.current_file_item.id + ". Error text: " + event.text);
+ ExternalCall.UploadError(this.uploadError_Callback, this.ERROR_CODE_SECURITY_ERROR, this.current_file_item.ToJavaScriptObject(), event.text);
+
+ this.UploadComplete(true);
+ }
+
+ private function Select_Many_Handler(event:Event):void {
+ this.Select_Handler(this.fileBrowserMany.fileList);
+ }
+ private function Select_One_Handler(event:Event):void {
+ var fileArray:Array = new Array(1);
+ fileArray[0] = this.fileBrowserOne;
+ this.Select_Handler(fileArray);
+ }
+
+ private function Select_Handler(file_reference_list:Array):void {
+ this.Debug("Select Handler: Received the files selected from the dialog. Processing the file list...");
+
+ var num_files_queued:Number = 0;
+
+ // Determine how many queue slots are remaining (check the unlimited (0) settings, successful uploads and queued uploads)
+ var queue_slots_remaining:Number = 0;
+ if (this.fileUploadLimit == 0) {
+ queue_slots_remaining = this.fileQueueLimit == 0 ? file_reference_list.length : (this.fileQueueLimit - this.queued_uploads); // If unlimited queue make the allowed size match however many files were selected.
+ } else {
+ var remaining_uploads:Number = this.fileUploadLimit - this.successful_uploads - this.queued_uploads;
+ if (remaining_uploads < 0) remaining_uploads = 0;
+ if (this.fileQueueLimit == 0 || this.fileQueueLimit >= remaining_uploads) {
+ queue_slots_remaining = remaining_uploads;
+ } else if (this.fileQueueLimit < remaining_uploads) {
+ queue_slots_remaining = this.fileQueueLimit - this.queued_uploads;
+ }
+ }
+
+ if (queue_slots_remaining < 0) queue_slots_remaining = 0;
+
+ // Check if the number of files selected is greater than the number allowed to queue up.
+ if (queue_slots_remaining < file_reference_list.length) {
+ this.Debug("Event: fileQueueError : Selected Files (" + file_reference_list.length + ") exceeds remaining Queue size (" + queue_slots_remaining + ").");
+ ExternalCall.FileQueueError(this.fileQueueError_Callback, this.ERROR_CODE_QUEUE_LIMIT_EXCEEDED, null, queue_slots_remaining.toString());
+ } else {
+ // Process each selected file
+ for (var i:Number = 0; i < file_reference_list.length; i++) {
+ var file_item:FileItem = new FileItem(file_reference_list[i], this.movieName, this.file_index.length);
+ this.file_index[file_item.index] = file_item;
+
+ // Verify that the file is accessible. Zero byte files and possibly other conditions can cause a file to be inaccessible.
+ var jsFileObj:Object = file_item.ToJavaScriptObject();
+ var is_valid_file_reference:Boolean = (jsFileObj.filestatus !== FileItem.FILE_STATUS_ERROR);
+
+ if (is_valid_file_reference) {
+ // Check the size, if it's within the limit add it to the upload list.
+ var size_result:Number = this.CheckFileSize(file_item);
+ var is_valid_filetype:Boolean = this.CheckFileType(file_item);
+ if(size_result == this.SIZE_OK && is_valid_filetype) {
+ file_item.file_status = FileItem.FILE_STATUS_QUEUED;
+ this.file_queue.push(file_item);
+ this.queued_uploads++;
+ num_files_queued++;
+ this.Debug("Event: fileQueued : File ID: " + file_item.id);
+ ExternalCall.FileQueued(this.fileQueued_Callback, file_item.ToJavaScriptObject());
+ }
+ else if (!is_valid_filetype) {
+ file_item.file_reference = null; // Cleanup the object
+ this.queue_errors++;
+ this.Debug("Event: fileQueueError : File not of a valid type.");
+ ExternalCall.FileQueueError(this.fileQueueError_Callback, this.ERROR_CODE_INVALID_FILETYPE, file_item.ToJavaScriptObject(), "File is not an allowed file type.");
+ }
+ else if (size_result == this.SIZE_TOO_BIG) {
+ file_item.file_reference = null; // Cleanup the object
+ this.queue_errors++;
+ this.Debug("Event: fileQueueError : File exceeds size limit.");
+ ExternalCall.FileQueueError(this.fileQueueError_Callback, this.ERROR_CODE_FILE_EXCEEDS_SIZE_LIMIT, file_item.ToJavaScriptObject(), "File size exceeds allowed limit.");
+ }
+ else if (size_result == this.SIZE_ZERO_BYTE) {
+ file_item.file_reference = null; // Cleanup the object
+ this.queue_errors++;
+ this.Debug("Event: fileQueueError : File is zero bytes.");
+ ExternalCall.FileQueueError(this.fileQueueError_Callback, this.ERROR_CODE_ZERO_BYTE_FILE, file_item.ToJavaScriptObject(), "File is zero bytes and cannot be uploaded.");
+ }
+ } else {
+ file_item.file_reference = null; // Cleanup the object
+ this.queue_errors++;
+ this.Debug("Event: fileQueueError : File is zero bytes or FileReference is invalid.");
+ ExternalCall.FileQueueError(this.fileQueueError_Callback, this.ERROR_CODE_ZERO_BYTE_FILE, file_item.ToJavaScriptObject(), "File is zero bytes or cannot be accessed and cannot be uploaded.");
+ }
+ }
+ }
+
+ this.Debug("Event: fileDialogComplete : Finished processing selected files. Files selected: " + file_reference_list.length + ". Files Queued: " + num_files_queued);
+ ExternalCall.FileDialogComplete(this.fileDialogComplete_Callback, file_reference_list.length, num_files_queued, this.queued_uploads);
+ }
+
+
+ /* ****************************************************************
+ Externally exposed functions
+ ****************************************************************** */
+ // Opens a file browser dialog that allows one file to be selected.
+ private function SelectFile():void {
+ this.fileBrowserOne = new FileReference();
+ this.fileBrowserOne.addEventListener(Event.SELECT, this.Select_One_Handler);
+ this.fileBrowserOne.addEventListener(Event.CANCEL, this.DialogCancelled_Handler);
+
+ // Default file type settings
+ var allowed_file_types:String = "*.*";
+ var allowed_file_types_description:String = "All Files";
+
+ // Get the instance settings
+ if (this.fileTypes.length > 0) allowed_file_types = this.fileTypes;
+ if (this.fileTypesDescription.length > 0) allowed_file_types_description = this.fileTypesDescription;
+
+ this.Debug("Event: fileDialogStart : Browsing files. Single Select. Allowed file types: " + allowed_file_types);
+ ExternalCall.Simple(this.fileDialogStart_Callback);
+
+ try {
+ this.fileBrowserOne.browse([new FileFilter(allowed_file_types_description, allowed_file_types)]);
+ } catch (ex:Error) {
+ this.Debug("Exception: " + ex.toString());
+ }
+ }
+
+ // Opens a file browser dialog that allows multiple files to be selected.
+ private function SelectFiles():void {
+ var allowed_file_types:String = "*.*";
+ var allowed_file_types_description:String = "All Files";
+
+ if (this.fileTypes.length > 0) allowed_file_types = this.fileTypes;
+ if (this.fileTypesDescription.length > 0) allowed_file_types_description = this.fileTypesDescription;
+
+ this.Debug("Event: fileDialogStart : Browsing files. Multi Select. Allowed file types: " + allowed_file_types);
+ ExternalCall.Simple(this.fileDialogStart_Callback);
+
+ try {
+ this.fileBrowserMany.browse([new FileFilter(allowed_file_types_description, allowed_file_types)]);
+ } catch (ex:Error) {
+ this.Debug("Exception: " + ex.toString());
+ }
+ }
+
+
+ // Cancel the current upload and stops. Doesn't advance the upload pointer. The current file is requeued at the beginning.
+ private function StopUpload():void {
+ if (this.current_file_item != null) {
+ // Cancel the upload and re-queue the FileItem
+ this.current_file_item.file_reference.cancel();
+
+ // Remove the event handlers
+ this.removeFileReferenceEventListeners(this.current_file_item);
+
+ this.current_file_item.file_status = FileItem.FILE_STATUS_QUEUED;
+ this.file_queue.unshift(this.current_file_item);
+ var js_object:Object = this.current_file_item.ToJavaScriptObject();
+ this.current_file_item = null;
+
+ this.Debug("Event: uploadError: upload stopped. File ID: " + js_object.ID);
+ ExternalCall.UploadError(this.uploadError_Callback, this.ERROR_CODE_UPLOAD_STOPPED, js_object, "Upload Stopped");
+ this.Debug("Event: uploadComplete. File ID: " + js_object.ID);
+ ExternalCall.UploadComplete(this.uploadComplete_Callback, js_object);
+
+ this.Debug("StopUpload(): upload stopped.");
+ } else {
+ this.Debug("StopUpload(): No file is currently uploading. Nothing to do.");
+ }
+ }
+
+ /* Cancels the upload specified by file_id
+ * If the file is currently uploading it is cancelled and the uploadComplete
+ * event gets called.
+ * If the file is not currently uploading then only the uploadCancelled event is fired.
+ * */
+ private function CancelUpload(file_id:String, triggerErrorEvent:Boolean = true):void {
+ var file_item:FileItem = null;
+
+ // Check the current file item
+ if (this.current_file_item != null && (this.current_file_item.id == file_id || !file_id)) {
+ this.current_file_item.file_reference.cancel();
+ this.current_file_item.file_status = FileItem.FILE_STATUS_CANCELLED;
+ this.upload_cancelled++;
+
+ if (triggerErrorEvent) {
+ this.Debug("Event: uploadError: File ID: " + this.current_file_item.id + ". Cancelled current upload");
+ ExternalCall.UploadError(this.uploadError_Callback, this.ERROR_CODE_FILE_CANCELLED, this.current_file_item.ToJavaScriptObject(), "File Upload Cancelled.");
+ } else {
+ this.Debug("Event: cancelUpload: File ID: " + this.current_file_item.id + ". Cancelled current upload. Suppressed uploadError event.");
+ }
+ this.UploadComplete(false);
+ } else if (file_id) {
+ // Find the file in the queue
+ var file_index:Number = this.FindIndexInFileQueue(file_id);
+ if (file_index >= 0) {
+ // Remove the file from the queue
+ file_item = FileItem(this.file_queue[file_index]);
+ file_item.file_status = FileItem.FILE_STATUS_CANCELLED;
+ this.file_queue[file_index] = null;
+ this.queued_uploads--;
+ this.upload_cancelled++;
+
+ // Cancel the file (just for good measure) and make the callback
+ file_item.file_reference.cancel();
+ this.removeFileReferenceEventListeners(file_item);
+ file_item.file_reference = null;
+
+ if (triggerErrorEvent) {
+ this.Debug("Event: uploadError : " + file_item.id + ". Cancelled queued upload");
+ ExternalCall.UploadError(this.uploadError_Callback, this.ERROR_CODE_FILE_CANCELLED, file_item.ToJavaScriptObject(), "File Cancelled");
+ } else {
+ this.Debug("Event: cancelUpload: File ID: " + file_item.id + ". Cancelled current upload. Suppressed uploadError event.");
+ }
+
+ // Get rid of the file object
+ file_item = null;
+ }
+ } else {
+ // Get the first file and cancel it
+ while (this.file_queue.length > 0 && file_item == null) {
+ // Check that File Reference is valid (if not make sure it's deleted and get the next one on the next loop)
+ file_item = FileItem(this.file_queue.shift()); // Cast back to a FileItem
+ if (typeof(file_item) == "undefined") {
+ file_item = null;
+ continue;
+ }
+ }
+
+ if (file_item != null) {
+ file_item.file_status = FileItem.FILE_STATUS_CANCELLED;
+ this.queued_uploads--;
+ this.upload_cancelled++;
+
+
+ // Cancel the file (just for good measure) and make the callback
+ file_item.file_reference.cancel();
+ this.removeFileReferenceEventListeners(file_item);
+ file_item.file_reference = null;
+
+ if (triggerErrorEvent) {
+ this.Debug("Event: uploadError : " + file_item.id + ". Cancelled queued upload");
+ ExternalCall.UploadError(this.uploadError_Callback, this.ERROR_CODE_FILE_CANCELLED, file_item.ToJavaScriptObject(), "File Cancelled");
+ } else {
+ this.Debug("Event: cancelUpload: File ID: " + file_item.id + ". Cancelled current upload. Suppressed uploadError event.");
+ }
+
+ // Get rid of the file object
+ file_item = null;
+ }
+
+ }
+
+ }
+
+ /* Requeues the indicated file. Returns true if successful or if the file is
+ * already in the queue. Otherwise returns false.
+ * */
+ private function RequeueUpload(fileIdentifier:*):Boolean {
+ var file:FileItem = null;
+ if (typeof(fileIdentifier) === "number") {
+ var fileIndex:Number = Number(fileIdentifier);
+ if (fileIndex >= 0 && fileIndex < this.file_index.length) {
+ file = this.file_index[fileIndex];
+ }
+ } else if (typeof(fileIdentifier) === "string") {
+ file = FindFileInFileIndex(String(fileIdentifier));
+ } else {
+ return false;
+ }
+
+ if (file !== null) {
+ if (file.file_status === FileItem.FILE_STATUS_IN_PROGRESS || file.file_status === FileItem.FILE_STATUS_NEW) {
+ return false;
+ } else if (file.file_status !== FileItem.FILE_STATUS_QUEUED) {
+ file.file_status = FileItem.FILE_STATUS_QUEUED;
+ this.file_queue.unshift(file);
+ this.queued_uploads++;
+ }
+ return true;
+ } else {
+ return false;
+ }
+ }
+
+
+ private function GetStats():Object {
+ return {
+ in_progress : this.current_file_item == null ? 0 : 1,
+ files_queued : this.queued_uploads,
+ successful_uploads : this.successful_uploads,
+ upload_errors : this.upload_errors,
+ upload_cancelled : this.upload_cancelled,
+ queue_errors : this.queue_errors
+ };
+ }
+ private function SetStats(stats:Object):void {
+ this.successful_uploads = typeof(stats["successful_uploads"]) === "number" ? stats["successful_uploads"] : this.successful_uploads;
+ this.upload_errors = typeof(stats["upload_errors"]) === "number" ? stats["upload_errors"] : this.upload_errors;
+ this.upload_cancelled = typeof(stats["upload_cancelled"]) === "number" ? stats["upload_cancelled"] : this.upload_cancelled;
+ this.queue_errors = typeof(stats["queue_errors"]) === "number" ? stats["queue_errors"] : this.queue_errors;
+ }
+
+ private function GetFile(file_id:String):Object {
+ var file_index:Number = this.FindIndexInFileQueue(file_id);
+ if (file_index >= 0) {
+ var file:FileItem = this.file_queue[file_index];
+ } else {
+ if (this.current_file_item != null) {
+ file = this.current_file_item;
+ } else {
+ for (var i:Number = 0; i < this.file_queue.length; i++) {
+ file = this.file_queue[i];
+ if (file != null) break;
+ }
+ }
+ }
+
+ if (file == null) {
+ return null;
+ } else {
+ return file.ToJavaScriptObject();
+ }
+
+ }
+
+ private function GetFileByIndex(index:Number):Object {
+ if (index < 0 || index > this.file_index.length - 1) {
+ return null;
+ } else {
+ return this.file_index[index].ToJavaScriptObject();
+ }
+ }
+
+ private function AddFileParam(file_id:String, name:String, value:String):Boolean {
+ var item:FileItem = this.FindFileInFileIndex(file_id);
+ if (item != null) {
+ item.AddParam(name, value);
+ return true;
+ }
+ else {
+ return false;
+ }
+ }
+ private function RemoveFileParam(file_id:String, name:String):Boolean {
+ var item:FileItem = this.FindFileInFileIndex(file_id);
+ if (item != null) {
+ item.RemoveParam(name);
+ return true;
+ }
+ else {
+ return false;
+ }
+ }
+
+ private function SetUploadURL(url:String):void {
+ if (typeof(url) !== "undefined" && url !== "") {
+ this.uploadURL = url;
+ }
+ }
+
+ private function SetPostParams(post_object:Object):void {
+ if (typeof(post_object) !== "undefined" && post_object !== null) {
+ this.uploadPostObject = post_object;
+ }
+ }
+
+ private function SetFileTypes(types:String, description:String):void {
+ this.fileTypes = types;
+ this.fileTypesDescription = description;
+
+ this.LoadFileExensions(this.fileTypes);
+ }
+
+ // Sets the file size limit. Accepts size values with units: 100 b, 1KB, 23Mb, 4 Gb
+ // Parsing is not robust. "100 200 MB KB B GB" parses as "100 MB"
+ private function SetFileSizeLimit(size:String):void {
+ var value:Number = 0;
+ var unit:String = "kb";
+
+ // Trim the string
+ var trimPattern:RegExp = /^\s*|\s*$/;
+
+ size = size.toLowerCase();
+ size = size.replace(trimPattern, "");
+
+
+ // Get the value part
+ var values:Array = size.match(/^\d+/);
+ if (values !== null && values.length > 0) {
+ value = parseInt(values[0]);
+ }
+ if (isNaN(value) || value < 0) value = 0;
+
+ // Get the units part
+ var units:Array = size.match(/(b|kb|mb|gb)/);
+ if (units != null && units.length > 0) {
+ unit = units[0];
+ }
+
+ // Set the multiplier for converting the unit to bytes
+ var multiplier:Number = 1024;
+ if (unit === "b")
+ multiplier = 1;
+ else if (unit === "mb")
+ multiplier = 1048576;
+ else if (unit === "gb")
+ multiplier = 1073741824;
+
+ this.fileSizeLimit = value * multiplier;
+ }
+
+ private function SetFileUploadLimit(file_upload_limit:Number):void {
+ if (file_upload_limit < 0) file_upload_limit = 0;
+ this.fileUploadLimit = file_upload_limit;
+ }
+
+ private function SetFileQueueLimit(file_queue_limit:Number):void {
+ if (file_queue_limit < 0) file_queue_limit = 0;
+ this.fileQueueLimit = file_queue_limit;
+ }
+
+ private function SetFilePostName(file_post_name:String):void {
+ if (file_post_name != "") {
+ this.filePostName = file_post_name;
+ }
+ }
+
+ private function SetUseQueryString(use_query_string:Boolean):void {
+ this.useQueryString = use_query_string;
+ }
+
+ private function SetRequeueOnError(requeue_on_error:Boolean):void {
+ this.requeueOnError = requeue_on_error;
+ }
+
+ private function SetHTTPSuccess(http_status_codes:*):void {
+ this.httpSuccess = [];
+
+ if (typeof http_status_codes === "string") {
+ var status_code_strings:Array = http_status_codes.replace(" ", "").split(",");
+ for each (var http_status_string:String in status_code_strings)
+ {
+ try {
+ this.httpSuccess.push(Number(http_status_string));
+ } catch (ex:Object) {
+ // Ignore errors
+ this.Debug("Could not add HTTP Success code: " + http_status_string);
+ }
+ }
+ }
+ else if (typeof http_status_codes === "object" && typeof http_status_codes.length === "number") {
+ for each (var http_status:* in http_status_codes)
+ {
+ try {
+ this.Debug("adding: " + http_status);
+ this.httpSuccess.push(Number(http_status));
+ } catch (ex:Object) {
+ this.Debug("Could not add HTTP Success code: " + http_status);
+ }
+ }
+ }
+ }
+
+ private function SetAssumeSuccessTimeout(timeout_seconds:Number):void {
+ this.assumeSuccessTimeout = timeout_seconds < 0 ? 0 : timeout_seconds;
+ }
+
+ private function SetDebugEnabled(debug_enabled:Boolean):void {
+ this.debugEnabled = debug_enabled;
+ }
+
+ /* *************************************************************
+ Button Handling Functions
+ *************************************************************** */
+ private function SetButtonImageURL(button_image_url:String):void {
+ this.buttonImageURL = button_image_url;
+
+ try {
+ if (this.buttonImageURL !== null && this.buttonImageURL !== "") {
+ this.buttonLoader.load(new URLRequest(this.buttonImageURL));
+ }
+ } catch (ex:Object) {
+ }
+ }
+
+ private function ButtonClickHandler(e:MouseEvent):void {
+ if (!this.buttonStateDisabled) {
+ if (this.buttonAction === this.BUTTON_ACTION_SELECT_FILE) {
+ this.SelectFile();
+ }
+ else if (this.buttonAction === this.BUTTON_ACTION_START_UPLOAD) {
+ this.StartUpload();
+ }
+ else {
+ this.SelectFiles();
+ }
+ }
+ }
+
+ private function UpdateButtonState():void {
+ var xOffset:Number = 0;
+ var yOffset:Number = 0;
+
+ this.buttonLoader.x = xOffset;
+ this.buttonLoader.y = yOffset;
+
+ if (this.buttonStateDisabled) {
+ this.buttonLoader.y = this.buttonHeight * -3 + yOffset;
+ }
+ else if (this.buttonStateMouseDown) {
+ this.buttonLoader.y = this.buttonHeight * -2 + yOffset;
+ }
+ else if (this.buttonStateOver) {
+ this.buttonLoader.y = this.buttonHeight * -1 + yOffset;
+ }
+ else {
+ this.buttonLoader.y = -yOffset;
+ }
+ };
+
+ private function SetButtonDimensions(width:Number = -1, height:Number = -1):void {
+ if (width >= 0) {
+ this.buttonWidth = width;
+ }
+ if (height >= 0) {
+ this.buttonHeight = height;
+ }
+
+ this.buttonTextField.width = this.buttonWidth;
+ this.buttonTextField.height = this.buttonHeight;
+ this.buttonCursorSprite.width = this.buttonWidth;
+ this.buttonCursorSprite.height = this.buttonHeight;
+
+ this.UpdateButtonState();
+ }
+
+ private function SetButtonText(button_text:String):void {
+ this.buttonText = button_text;
+
+ this.SetButtonTextStyle(this.buttonTextStyle);
+ }
+
+ private function SetButtonTextStyle(button_text_style:String):void {
+ this.buttonTextStyle = button_text_style;
+
+ var style:StyleSheet = new StyleSheet();
+ style.parseCSS(this.buttonTextStyle);
+ this.buttonTextField.styleSheet = style;
+ this.buttonTextField.htmlText = this.buttonText;
+ }
+
+ private function SetButtonTextPadding(left:Number, top:Number):void {
+ this.buttonTextField.x = this.buttonTextLeftPadding = left;
+ this.buttonTextField.y = this.buttonTextTopPadding = top;
+ }
+
+ private function SetButtonDisabled(disabled:Boolean):void {
+ this.buttonStateDisabled = disabled;
+ this.UpdateButtonState();
+ }
+
+ private function SetButtonAction(button_action:Number):void {
+ this.buttonAction = button_action;
+ }
+
+ private function SetButtonCursor(button_cursor:Number):void {
+ this.buttonCursor = button_cursor;
+
+ this.buttonCursorSprite.useHandCursor = (button_cursor === this.BUTTON_CURSOR_HAND);
+ }
+
+ /* *************************************************************
+ File processing and handling functions
+ *************************************************************** */
+ private function StartUpload(file_id:String = ""):void {
+ // Only upload a file uploads are being processed.
+ if (this.current_file_item != null) {
+ this.Debug("StartUpload(): Upload already in progress. Not starting another upload.");
+ return;
+ }
+
+ this.Debug("StartUpload: " + (file_id ? "File ID: " + file_id : "First file in queue"));
+
+ // Check the upload limit
+ if (this.successful_uploads >= this.fileUploadLimit && this.fileUploadLimit != 0) {
+ this.Debug("Event: uploadError : Upload limit reached. No more files can be uploaded.");
+ ExternalCall.UploadError(this.uploadError_Callback, this.ERROR_CODE_UPLOAD_LIMIT_EXCEEDED, null, "The upload limit has been reached.");
+ this.current_file_item = null;
+ return;
+ }
+
+ // Get the next file to upload
+ if (!file_id) {
+ while (this.file_queue.length > 0 && this.current_file_item == null) {
+ this.current_file_item = FileItem(this.file_queue.shift());
+ if (typeof(this.current_file_item) == "undefined") {
+ this.current_file_item = null;
+ }
+ }
+ } else {
+ var file_index:Number = this.FindIndexInFileQueue(file_id);
+ if (file_index >= 0) {
+ // Set the file as the current upload and remove it from the queue
+ this.current_file_item = FileItem(this.file_queue[file_index]);
+ this.file_queue[file_index] = null;
+ } else {
+ this.Debug("Event: uploadError : File ID not found in queue: " + file_id);
+ ExternalCall.UploadError(this.uploadError_Callback, this.ERROR_CODE_SPECIFIED_FILE_ID_NOT_FOUND, null, "File ID not found in the queue.");
+ }
+ }
+
+
+ if (this.current_file_item != null) {
+ // Trigger the uploadStart event which will call ReturnUploadStart to begin the actual upload
+ this.Debug("Event: uploadStart : File ID: " + this.current_file_item.id);
+
+ this.current_file_item.file_status = FileItem.FILE_STATUS_IN_PROGRESS;
+ ExternalCall.UploadStart(this.uploadStart_Callback, this.current_file_item.ToJavaScriptObject());
+ }
+ // Otherwise we've would have looped through all the FileItems. This means the queue is empty)
+ else {
+ this.Debug("StartUpload(): No files found in the queue.");
+ }
+ }
+
+ // This starts the upload when the user returns TRUE from the uploadStart event. Rather than just have the value returned from
+ // the function we do a return function call so we can use the setTimeout work-around for Flash/JS circular calls.
+ private function ReturnUploadStart(start_upload:Boolean):void {
+ if (this.current_file_item == null) {
+ this.Debug("ReturnUploadStart called but no file was prepped for uploading. The file may have been cancelled or stopped.");
+ return;
+ }
+
+ var js_object:Object;
+
+ if (start_upload) {
+ try {
+ // Set the event handlers
+ this.current_file_item.file_reference.addEventListener(Event.OPEN, this.Open_Handler);
+ this.current_file_item.file_reference.addEventListener(ProgressEvent.PROGRESS, this.FileProgress_Handler);
+ this.current_file_item.file_reference.addEventListener(IOErrorEvent.IO_ERROR, this.IOError_Handler);
+ this.current_file_item.file_reference.addEventListener(SecurityErrorEvent.SECURITY_ERROR, this.SecurityError_Handler);
+ this.current_file_item.file_reference.addEventListener(HTTPStatusEvent.HTTP_STATUS, this.HTTPError_Handler);
+ this.current_file_item.file_reference.addEventListener(Event.COMPLETE, this.Complete_Handler);
+ this.current_file_item.file_reference.addEventListener(DataEvent.UPLOAD_COMPLETE_DATA, this.ServerData_Handler);
+
+ // Get the request (post values, etc)
+ var request:URLRequest = this.BuildRequest();
+
+ if (this.uploadURL.length == 0) {
+ this.Debug("Event: uploadError : IO Error : File ID: " + this.current_file_item.id + ". Upload URL string is empty.");
+
+ // Remove the event handlers
+ this.removeFileReferenceEventListeners(this.current_file_item);
+
+ this.current_file_item.file_status = FileItem.FILE_STATUS_QUEUED;
+ this.file_queue.unshift(this.current_file_item);
+ js_object = this.current_file_item.ToJavaScriptObject();
+ this.current_file_item = null;
+
+ ExternalCall.UploadError(this.uploadError_Callback, this.ERROR_CODE_MISSING_UPLOAD_URL, js_object, "Upload URL string is empty.");
+ } else {
+ this.Debug("ReturnUploadStart(): File accepted by startUpload event and readied for upload. Starting upload to " + request.url + " for File ID: " + this.current_file_item.id);
+ this.current_file_item.file_status = FileItem.FILE_STATUS_IN_PROGRESS;
+ this.current_file_item.file_reference.upload(request, this.filePostName, false);
+ }
+ } catch (ex:Error) {
+ this.Debug("ReturnUploadStart: Exception occurred: " + message);
+
+ this.upload_errors++;
+ this.current_file_item.file_status = FileItem.FILE_STATUS_ERROR;
+
+ var message:String = ex.errorID + "\n" + ex.name + "\n" + ex.message + "\n" + ex.getStackTrace();
+ this.Debug("Event: uploadError(): Upload Failed. Exception occurred: " + message);
+ ExternalCall.UploadError(this.uploadError_Callback, this.ERROR_CODE_UPLOAD_FAILED, this.current_file_item.ToJavaScriptObject(), message);
+
+ this.UploadComplete(true);
+ }
+ } else {
+ // Remove the event handlers
+ this.removeFileReferenceEventListeners(this.current_file_item);
+
+ // Re-queue the FileItem
+ this.current_file_item.file_status = FileItem.FILE_STATUS_QUEUED;
+ js_object = this.current_file_item.ToJavaScriptObject();
+ this.file_queue.unshift(this.current_file_item);
+ this.current_file_item = null;
+
+ this.Debug("Event: uploadError : Call to uploadStart returned false. Not uploading the file.");
+ ExternalCall.UploadError(this.uploadError_Callback, this.ERROR_CODE_FILE_VALIDATION_FAILED, js_object, "Call to uploadStart return false. Not uploading file.");
+ this.Debug("Event: uploadComplete : Call to uploadStart returned false. Not uploading the file.");
+ ExternalCall.UploadComplete(this.uploadComplete_Callback, js_object);
+ }
+ }
+
+ // Completes the file upload by deleting it's reference, advancing the pointer.
+ // Once this event fires a new upload can be started.
+ private function UploadComplete(eligible_for_requeue:Boolean):void {
+ var jsFileObj:Object = this.current_file_item.ToJavaScriptObject();
+
+ this.removeFileReferenceEventListeners(this.current_file_item);
+
+ if (!eligible_for_requeue || this.requeueOnError == false) {
+ this.current_file_item.file_reference = null;
+ this.queued_uploads--;
+ } else if (this.requeueOnError == true) {
+ this.current_file_item.file_status = FileItem.FILE_STATUS_QUEUED;
+ this.file_queue.unshift(this.current_file_item);
+ }
+
+ this.current_file_item = null;
+
+ this.Debug("Event: uploadComplete : Upload cycle complete.");
+ ExternalCall.UploadComplete(this.uploadComplete_Callback, jsFileObj);
+ }
+
+
+ /* *************************************************************
+ Utility Functions
+ *************************************************************** */
+
+
+ // Check the size of the file against the allowed file size. If it is less the return TRUE. If it is too large return FALSE
+ private function CheckFileSize(file_item:FileItem):Number {
+ if (file_item.file_reference.size == 0) {
+ return this.SIZE_ZERO_BYTE;
+ } else if (this.fileSizeLimit != 0 && file_item.file_reference.size > this.fileSizeLimit) {
+ return this.SIZE_TOO_BIG;
+ } else {
+ return this.SIZE_OK;
+ }
+ }
+
+ private function CheckFileType(file_item:FileItem):Boolean {
+ // If no extensions are defined then a *.* was passed and the check is unnecessary
+ if (this.valid_file_extensions.length == 0) {
+ return true;
+ }
+
+ var fileRef:FileReference = file_item.file_reference;
+ var last_dot_index:Number = fileRef.name.lastIndexOf(".");
+ var extension:String = "";
+ if (last_dot_index >= 0) {
+ extension = fileRef.name.substr(last_dot_index + 1).toLowerCase();
+ }
+
+ var is_valid_filetype:Boolean = false;
+ for (var i:Number=0; i < this.valid_file_extensions.length; i++) {
+ if (String(this.valid_file_extensions[i]) == extension) {
+ is_valid_filetype = true;
+ break;
+ }
+ }
+
+ return is_valid_filetype;
+ }
+
+ private function BuildRequest():URLRequest {
+ // Create the request object
+ var request:URLRequest = new URLRequest();
+ request.method = URLRequestMethod.POST;
+
+ var file_post:Object = this.current_file_item.GetPostObject();
+
+ if (this.useQueryString) {
+ var pairs:Array = new Array();
+ for (key in this.uploadPostObject) {
+ this.Debug("Global URL Item: " + key + "=" + this.uploadPostObject[key]);
+ if (this.uploadPostObject.hasOwnProperty(key)) {
+ pairs.push(escape(key) + "=" + escape(this.uploadPostObject[key]));
+ }
+ }
+
+ for (key in file_post) {
+ this.Debug("File Post Item: " + key + "=" + file_post[key]);
+ if (file_post.hasOwnProperty(key)) {
+ pairs.push(escape(key) + "=" + escape(file_post[key]));
+ }
+ }
+
+ request.url = this.uploadURL + (this.uploadURL.indexOf("?") > -1 ? "&" : "?") + pairs.join("&");
+
+ } else {
+ var key:String;
+ var post:URLVariables = new URLVariables();
+ for (key in this.uploadPostObject) {
+ this.Debug("Global Post Item: " + key + "=" + this.uploadPostObject[key]);
+ if (this.uploadPostObject.hasOwnProperty(key)) {
+ post[key] = this.uploadPostObject[key];
+ }
+ }
+
+ for (key in file_post) {
+ this.Debug("File Post Item: " + key + "=" + file_post[key]);
+ if (file_post.hasOwnProperty(key)) {
+ post[key] = file_post[key];
+ }
+ }
+
+ request.url = this.uploadURL;
+ request.data = post;
+ }
+
+ return request;
+ }
+
+ private function Debug(msg:String):void {
+ try {
+ if (this.debugEnabled) {
+ var lines:Array = msg.split("\n");
+ for (var i:Number=0; i < lines.length; i++) {
+ lines[i] = "SWF DEBUG: " + lines[i];
+ }
+ ExternalCall.Debug(this.debug_Callback, lines.join("\n"));
+ }
+ } catch (ex:Error) {
+ // pretend nothing happened
+ trace(ex);
+ }
+ }
+
+ private function PrintDebugInfo():void {
+ var debug_info:String = "\n----- SWF DEBUG OUTPUT ----\n";
+ debug_info += "Build Number: " + this.build_number + "\n";
+ debug_info += "movieName: " + this.movieName + "\n";
+ debug_info += "Upload URL: " + this.uploadURL + "\n";
+ debug_info += "File Types String: " + this.fileTypes + "\n";
+ debug_info += "Parsed File Types: " + this.valid_file_extensions.toString() + "\n";
+ debug_info += "HTTP Success: " + this.httpSuccess.join(", ") + "\n";
+ debug_info += "File Types Description: " + this.fileTypesDescription + "\n";
+ debug_info += "File Size Limit: " + this.fileSizeLimit + " bytes\n";
+ debug_info += "File Upload Limit: " + this.fileUploadLimit + "\n";
+ debug_info += "File Queue Limit: " + this.fileQueueLimit + "\n";
+ debug_info += "Post Params:\n";
+ for (var key:String in this.uploadPostObject) {
+ if (this.uploadPostObject.hasOwnProperty(key)) {
+ debug_info += " " + key + "=" + this.uploadPostObject[key] + "\n";
+ }
+ }
+ debug_info += "----- END SWF DEBUG OUTPUT ----\n";
+
+ this.Debug(debug_info);
+ }
+
+ private function FindIndexInFileQueue(file_id:String):Number {
+ for (var i:Number = 0; i < this.file_queue.length; i++) {
+ var item:FileItem = this.file_queue[i];
+ if (item != null && item.id == file_id) return i;
+ }
+
+ return -1;
+ }
+
+ private function FindFileInFileIndex(file_id:String):FileItem {
+ for (var i:Number = 0; i < this.file_index.length; i++) {
+ var item:FileItem = this.file_index[i];
+ if (item != null && item.id == file_id) return item;
+ }
+
+ return null;
+ }
+
+
+ // Parse the file extensions in to an array so we can validate them agains
+ // the files selected later.
+ private function LoadFileExensions(filetypes:String):void {
+ var extensions:Array = filetypes.split(";");
+ this.valid_file_extensions = new Array();
+
+ for (var i:Number=0; i < extensions.length; i++) {
+ var extension:String = String(extensions[i]);
+ var dot_index:Number = extension.lastIndexOf(".");
+
+ if (dot_index >= 0) {
+ extension = extension.substr(dot_index + 1).toLowerCase();
+ } else {
+ extension = extension.toLowerCase();
+ }
+
+ // If one of the extensions is * then we allow all files
+ if (extension == "*") {
+ this.valid_file_extensions = new Array();
+ break;
+ }
+
+ this.valid_file_extensions.push(extension);
+ }
+ }
+
+ private function loadPostParams(param_string:String):void {
+ var post_object:Object = {};
+
+ if (param_string != null) {
+ var name_value_pairs:Array = param_string.split("&amp;");
+
+ for (var i:Number = 0; i < name_value_pairs.length; i++) {
+ var name_value:String = String(name_value_pairs[i]);
+ var index_of_equals:Number = name_value.indexOf("=");
+ if (index_of_equals > 0) {
+ post_object[decodeURIComponent(name_value.substring(0, index_of_equals))] = decodeURIComponent(name_value.substr(index_of_equals + 1));
+ }
+ }
+ }
+ this.uploadPostObject = post_object;
+ }
+
+ private function removeFileReferenceEventListeners(file_item:FileItem):void {
+ if (file_item != null && file_item.file_reference != null) {
+ file_item.file_reference.removeEventListener(Event.OPEN, this.Open_Handler);
+ file_item.file_reference.removeEventListener(ProgressEvent.PROGRESS, this.FileProgress_Handler);
+ file_item.file_reference.removeEventListener(IOErrorEvent.IO_ERROR, this.IOError_Handler);
+ file_item.file_reference.removeEventListener(SecurityErrorEvent.SECURITY_ERROR, this.SecurityError_Handler);
+ file_item.file_reference.removeEventListener(HTTPStatusEvent.HTTP_STATUS, this.HTTPError_Handler);
+ file_item.file_reference.removeEventListener(DataEvent.UPLOAD_COMPLETE_DATA, this.ServerData_Handler);
+ }
+ }
+
+ }
+}
diff --git a/debian/missing-sources/swfupload/Flash/deploy.bat b/debian/missing-sources/swfupload/Flash/deploy.bat
new file mode 100644
index 0000000..a6a95f8
--- /dev/null
+++ b/debian/missing-sources/swfupload/Flash/deploy.bat
@@ -0,0 +1,3 @@
+@echo off
+copy ..\swfupload.js ..\..\samples\demos\swfupload
+copy swfupload.swf ..\..\samples\demos\swfupload
diff --git a/debian/missing-sources/swfupload/Flash/obj/SWFUpload-v2Config.old b/debian/missing-sources/swfupload/Flash/obj/SWFUpload-v2Config.old
new file mode 100644
index 0000000..0f4039a
--- /dev/null
+++ b/debian/missing-sources/swfupload/Flash/obj/SWFUpload-v2Config.old
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--Flex compiler config for project SWFUpload-v2 generated by FDBuild-->
+<!--============-->
+<!--This file was generated by a tool.-->
+<!--Any modifications you make may be lost.-->
+<flex-config>
+ <compiler>
+ <source-path append="true">
+ <path-element>C:\inetpub\wwwroot\other\swfupload\core\Flash</path-element>
+ <path-element>C:\Program Files (x86)\FlashDevelop\Library\AS3\classes</path-element>
+ </source-path>
+ </compiler>
+ <file-specs>
+ <path-element>C:\inetpub\wwwroot\other\swfupload\core\Flash\SWFUpload.as</path-element>
+ </file-specs>
+ <default-background-color>#FFFFFF</default-background-color>
+ <default-frame-rate>15</default-frame-rate>
+ <default-size>
+ <width>300</width>
+ <height>300</height>
+ </default-size>
+</flex-config> \ No newline at end of file
diff --git a/debian/missing-sources/swfupload/Flash/obj/SWFUpload-v2Config.xml b/debian/missing-sources/swfupload/Flash/obj/SWFUpload-v2Config.xml
new file mode 100644
index 0000000..0f4039a
--- /dev/null
+++ b/debian/missing-sources/swfupload/Flash/obj/SWFUpload-v2Config.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--Flex compiler config for project SWFUpload-v2 generated by FDBuild-->
+<!--============-->
+<!--This file was generated by a tool.-->
+<!--Any modifications you make may be lost.-->
+<flex-config>
+ <compiler>
+ <source-path append="true">
+ <path-element>C:\inetpub\wwwroot\other\swfupload\core\Flash</path-element>
+ <path-element>C:\Program Files (x86)\FlashDevelop\Library\AS3\classes</path-element>
+ </source-path>
+ </compiler>
+ <file-specs>
+ <path-element>C:\inetpub\wwwroot\other\swfupload\core\Flash\SWFUpload.as</path-element>
+ </file-specs>
+ <default-background-color>#FFFFFF</default-background-color>
+ <default-frame-rate>15</default-frame-rate>
+ <default-size>
+ <width>300</width>
+ <height>300</height>
+ </default-size>
+</flex-config> \ No newline at end of file
diff --git a/debian/missing-sources/swfupload/Flash/swfupload.swf b/debian/missing-sources/swfupload/Flash/swfupload.swf
new file mode 100644
index 0000000..e3f7670
--- /dev/null
+++ b/debian/missing-sources/swfupload/Flash/swfupload.swf
Binary files differ
diff --git a/debian/missing-sources/swfupload/plugins/SWFObject License.txt b/debian/missing-sources/swfupload/plugins/SWFObject License.txt
new file mode 100644
index 0000000..c393619
--- /dev/null
+++ b/debian/missing-sources/swfupload/plugins/SWFObject License.txt
@@ -0,0 +1,4 @@
+/* SWFObject v2.0 rc4 <http://code.google.com/p/swfobject/>
+ Copyright (c) 2007 Geoff Stearns, Michael Williams, and Bobby van der Sluis
+ This software is released under the MIT License <http://www.opensource.org/licenses/mit-license.php>
+*/
diff --git a/debian/missing-sources/swfupload/plugins/swfupload.cookies.js b/debian/missing-sources/swfupload/plugins/swfupload.cookies.js
new file mode 100644
index 0000000..b8fa5f5
--- /dev/null
+++ b/debian/missing-sources/swfupload/plugins/swfupload.cookies.js
@@ -0,0 +1,53 @@
+/*
+ Cookie Plug-in
+
+ This plug in automatically gets all the cookies for this site and adds them to the post_params.
+ Cookies are loaded only on initialization. The refreshCookies function can be called to update the post_params.
+ The cookies will override any other post params with the same name.
+*/
+
+var SWFUpload;
+if (typeof(SWFUpload) === "function") {
+ SWFUpload.prototype.initSettings = function (oldInitSettings) {
+ return function () {
+ if (typeof(oldInitSettings) === "function") {
+ oldInitSettings.call(this);
+ }
+
+ this.refreshCookies(false); // The false parameter must be sent since SWFUpload has not initialzed at this point
+ };
+ }(SWFUpload.prototype.initSettings);
+
+ // refreshes the post_params and updates SWFUpload. The sendToFlash parameters is optional and defaults to True
+ SWFUpload.prototype.refreshCookies = function (sendToFlash) {
+ if (sendToFlash === undefined) {
+ sendToFlash = true;
+ }
+ sendToFlash = !!sendToFlash;
+
+ // Get the post_params object
+ var postParams = this.settings.post_params;
+
+ // Get the cookies
+ var i, cookieArray = document.cookie.split(';'), caLength = cookieArray.length, c, eqIndex, name, value;
+ for (i = 0; i < caLength; i++) {
+ c = cookieArray[i];
+
+ // Left Trim spaces
+ while (c.charAt(0) === " ") {
+ c = c.substring(1, c.length);
+ }
+ eqIndex = c.indexOf("=");
+ if (eqIndex > 0) {
+ name = c.substring(0, eqIndex);
+ value = c.substring(eqIndex + 1);
+ postParams[name] = value;
+ }
+ }
+
+ if (sendToFlash) {
+ this.setPostParams(postParams);
+ }
+ };
+
+}
diff --git a/debian/missing-sources/swfupload/plugins/swfupload.queue.js b/debian/missing-sources/swfupload/plugins/swfupload.queue.js
new file mode 100644
index 0000000..00aef32
--- /dev/null
+++ b/debian/missing-sources/swfupload/plugins/swfupload.queue.js
@@ -0,0 +1,98 @@
+/*
+ Queue Plug-in
+
+ Features:
+ *Adds a cancelQueue() method for cancelling the entire queue.
+ *All queued files are uploaded when startUpload() is called.
+ *If false is returned from uploadComplete then the queue upload is stopped.
+ If false is not returned (strict comparison) then the queue upload is continued.
+ *Adds a QueueComplete event that is fired when all the queued files have finished uploading.
+ Set the event handler with the queue_complete_handler setting.
+
+ */
+
+var SWFUpload;
+if (typeof(SWFUpload) === "function") {
+ SWFUpload.queue = {};
+
+ SWFUpload.prototype.initSettings = (function (oldInitSettings) {
+ return function () {
+ if (typeof(oldInitSettings) === "function") {
+ oldInitSettings.call(this);
+ }
+
+ this.queueSettings = {};
+
+ this.queueSettings.queue_cancelled_flag = false;
+ this.queueSettings.queue_upload_count = 0;
+
+ this.queueSettings.user_upload_complete_handler = this.settings.upload_complete_handler;
+ this.queueSettings.user_upload_start_handler = this.settings.upload_start_handler;
+ this.settings.upload_complete_handler = SWFUpload.queue.uploadCompleteHandler;
+ this.settings.upload_start_handler = SWFUpload.queue.uploadStartHandler;
+
+ this.settings.queue_complete_handler = this.settings.queue_complete_handler || null;
+ };
+ })(SWFUpload.prototype.initSettings);
+
+ SWFUpload.prototype.startUpload = function (fileID) {
+ this.queueSettings.queue_cancelled_flag = false;
+ this.callFlash("StartUpload", [fileID]);
+ };
+
+ SWFUpload.prototype.cancelQueue = function () {
+ this.queueSettings.queue_cancelled_flag = true;
+ this.stopUpload();
+
+ var stats = this.getStats();
+ while (stats.files_queued > 0) {
+ this.cancelUpload();
+ stats = this.getStats();
+ }
+ };
+
+ SWFUpload.queue.uploadStartHandler = function (file) {
+ var returnValue;
+ if (typeof(this.queueSettings.user_upload_start_handler) === "function") {
+ returnValue = this.queueSettings.user_upload_start_handler.call(this, file);
+ }
+
+ // To prevent upload a real "FALSE" value must be returned, otherwise default to a real "TRUE" value.
+ returnValue = (returnValue === false) ? false : true;
+
+ this.queueSettings.queue_cancelled_flag = !returnValue;
+
+ return returnValue;
+ };
+
+ SWFUpload.queue.uploadCompleteHandler = function (file) {
+ var user_upload_complete_handler = this.queueSettings.user_upload_complete_handler;
+ var continueUpload;
+
+ if (file.filestatus === SWFUpload.FILE_STATUS.COMPLETE) {
+ this.queueSettings.queue_upload_count++;
+ }
+
+ if (typeof(user_upload_complete_handler) === "function") {
+ continueUpload = (user_upload_complete_handler.call(this, file) === false) ? false : true;
+ } else if (file.filestatus === SWFUpload.FILE_STATUS.QUEUED) {
+ // If the file was stopped and re-queued don't restart the upload
+ continueUpload = false;
+ } else {
+ continueUpload = true;
+ }
+
+ if (continueUpload) {
+ var stats = this.getStats();
+ if (stats.files_queued > 0 && this.queueSettings.queue_cancelled_flag === false) {
+ this.startUpload();
+ } else if (this.queueSettings.queue_cancelled_flag === false) {
+ this.queueEvent("queue_complete_handler", [this.queueSettings.queue_upload_count]);
+ this.queueSettings.queue_upload_count = 0;
+ } else {
+ this.queueSettings.queue_cancelled_flag = false;
+ this.queueSettings.queue_upload_count = 0;
+ }
+ }
+ };
+} \ No newline at end of file
diff --git a/debian/missing-sources/swfupload/plugins/swfupload.speed.js b/debian/missing-sources/swfupload/plugins/swfupload.speed.js
new file mode 100644
index 0000000..6b7bf94
--- /dev/null
+++ b/debian/missing-sources/swfupload/plugins/swfupload.speed.js
@@ -0,0 +1,342 @@
+/*
+ Speed Plug-in
+
+ Features:
+ *Adds several properties to the 'file' object indicated upload speed, time left, upload time, etc.
+ - currentSpeed -- String indicating the upload speed, bytes per second
+ - averageSpeed -- Overall average upload speed, bytes per second
+ - movingAverageSpeed -- Speed over averaged over the last several measurements, bytes per second
+ - timeRemaining -- Estimated remaining upload time in seconds
+ - timeElapsed -- Number of seconds passed for this upload
+ - percentUploaded -- Percentage of the file uploaded (0 to 100)
+ - sizeUploaded -- Formatted size uploaded so far, bytes
+
+ *Adds setting 'moving_average_history_size' for defining the window size used to calculate the moving average speed.
+
+ *Adds several Formatting functions for formatting that values provided on the file object.
+ - SWFUpload.speed.formatBPS(bps) -- outputs string formatted in the best units (Gbps, Mbps, Kbps, bps)
+ - SWFUpload.speed.formatTime(seconds) -- outputs string formatted in the best units (x Hr y M z S)
+ - SWFUpload.speed.formatSize(bytes) -- outputs string formatted in the best units (w GB x MB y KB z B )
+ - SWFUpload.speed.formatPercent(percent) -- outputs string formatted with a percent sign (x.xx %)
+ - SWFUpload.speed.formatUnits(baseNumber, divisionArray, unitLabelArray, fractionalBoolean)
+ - Formats a number using the division array to determine how to apply the labels in the Label Array
+ - factionalBoolean indicates whether the number should be returned as a single fractional number with a unit (speed)
+ or as several numbers labeled with units (time)
+ */
+
+var SWFUpload;
+if (typeof(SWFUpload) === "function") {
+ SWFUpload.speed = {};
+
+ SWFUpload.prototype.initSettings = (function (oldInitSettings) {
+ return function () {
+ if (typeof(oldInitSettings) === "function") {
+ oldInitSettings.call(this);
+ }
+
+ this.ensureDefault = function (settingName, defaultValue) {
+ this.settings[settingName] = (this.settings[settingName] == undefined) ? defaultValue : this.settings[settingName];
+ };
+
+ // List used to keep the speed stats for the files we are tracking
+ this.fileSpeedStats = {};
+ this.speedSettings = {};
+
+ this.ensureDefault("moving_average_history_size", "10");
+
+ this.speedSettings.user_file_queued_handler = this.settings.file_queued_handler;
+ this.speedSettings.user_file_queue_error_handler = this.settings.file_queue_error_handler;
+ this.speedSettings.user_upload_start_handler = this.settings.upload_start_handler;
+ this.speedSettings.user_upload_error_handler = this.settings.upload_error_handler;
+ this.speedSettings.user_upload_progress_handler = this.settings.upload_progress_handler;
+ this.speedSettings.user_upload_success_handler = this.settings.upload_success_handler;
+ this.speedSettings.user_upload_complete_handler = this.settings.upload_complete_handler;
+
+ this.settings.file_queued_handler = SWFUpload.speed.fileQueuedHandler;
+ this.settings.file_queue_error_handler = SWFUpload.speed.fileQueueErrorHandler;
+ this.settings.upload_start_handler = SWFUpload.speed.uploadStartHandler;
+ this.settings.upload_error_handler = SWFUpload.speed.uploadErrorHandler;
+ this.settings.upload_progress_handler = SWFUpload.speed.uploadProgressHandler;
+ this.settings.upload_success_handler = SWFUpload.speed.uploadSuccessHandler;
+ this.settings.upload_complete_handler = SWFUpload.speed.uploadCompleteHandler;
+
+ delete this.ensureDefault;
+ };
+ })(SWFUpload.prototype.initSettings);
+
+
+ SWFUpload.speed.fileQueuedHandler = function (file) {
+ if (typeof this.speedSettings.user_file_queued_handler === "function") {
+ file = SWFUpload.speed.extendFile(file);
+
+ return this.speedSettings.user_file_queued_handler.call(this, file);
+ }
+ };
+
+ SWFUpload.speed.fileQueueErrorHandler = function (file, errorCode, message) {
+ if (typeof this.speedSettings.user_file_queue_error_handler === "function") {
+ file = SWFUpload.speed.extendFile(file);
+
+ return this.speedSettings.user_file_queue_error_handler.call(this, file, errorCode, message);
+ }
+ };
+
+ SWFUpload.speed.uploadStartHandler = function (file) {
+ if (typeof this.speedSettings.user_upload_start_handler === "function") {
+ file = SWFUpload.speed.extendFile(file, this.fileSpeedStats);
+ return this.speedSettings.user_upload_start_handler.call(this, file);
+ }
+ };
+
+ SWFUpload.speed.uploadErrorHandler = function (file, errorCode, message) {
+ file = SWFUpload.speed.extendFile(file, this.fileSpeedStats);
+ SWFUpload.speed.removeTracking(file, this.fileSpeedStats);
+
+ if (typeof this.speedSettings.user_upload_error_handler === "function") {
+ return this.speedSettings.user_upload_error_handler.call(this, file, errorCode, message);
+ }
+ };
+ SWFUpload.speed.uploadProgressHandler = function (file, bytesComplete, bytesTotal) {
+ this.updateTracking(file, bytesComplete);
+ file = SWFUpload.speed.extendFile(file, this.fileSpeedStats);
+
+ if (typeof this.speedSettings.user_upload_progress_handler === "function") {
+ return this.speedSettings.user_upload_progress_handler.call(this, file, bytesComplete, bytesTotal);
+ }
+ };
+
+ SWFUpload.speed.uploadSuccessHandler = function (file, serverData) {
+ if (typeof this.speedSettings.user_upload_success_handler === "function") {
+ file = SWFUpload.speed.extendFile(file, this.fileSpeedStats);
+ return this.speedSettings.user_upload_success_handler.call(this, file, serverData);
+ }
+ };
+ SWFUpload.speed.uploadCompleteHandler = function (file) {
+ file = SWFUpload.speed.extendFile(file, this.fileSpeedStats);
+ SWFUpload.speed.removeTracking(file, this.fileSpeedStats);
+
+ if (typeof this.speedSettings.user_upload_complete_handler === "function") {
+ return this.speedSettings.user_upload_complete_handler.call(this, file);
+ }
+ };
+
+ // Private: extends the file object with the speed plugin values
+ SWFUpload.speed.extendFile = function (file, trackingList) {
+ var tracking;
+
+ if (trackingList) {
+ tracking = trackingList[file.id];
+ }
+
+ if (tracking) {
+ file.currentSpeed = tracking.currentSpeed;
+ file.averageSpeed = tracking.averageSpeed;
+ file.movingAverageSpeed = tracking.movingAverageSpeed;
+ file.timeRemaining = tracking.timeRemaining;
+ file.timeElapsed = tracking.timeElapsed;
+ file.percentUploaded = tracking.percentUploaded;
+ file.sizeUploaded = tracking.bytesUploaded;
+
+ } else {
+ file.currentSpeed = 0;
+ file.averageSpeed = 0;
+ file.movingAverageSpeed = 0;
+ file.timeRemaining = 0;
+ file.timeElapsed = 0;
+ file.percentUploaded = 0;
+ file.sizeUploaded = 0;
+ }
+
+ return file;
+ };
+
+ // Private: Updates the speed tracking object, or creates it if necessary
+ SWFUpload.prototype.updateTracking = function (file, bytesUploaded) {
+ var tracking = this.fileSpeedStats[file.id];
+ if (!tracking) {
+ this.fileSpeedStats[file.id] = tracking = {};
+ }
+
+ // Sanity check inputs
+ bytesUploaded = bytesUploaded || tracking.bytesUploaded || 0;
+ if (bytesUploaded < 0) {
+ bytesUploaded = 0;
+ }
+ if (bytesUploaded > file.size) {
+ bytesUploaded = file.size;
+ }
+
+ var tickTime = (new Date()).getTime();
+ if (!tracking.startTime) {
+ tracking.startTime = (new Date()).getTime();
+ tracking.lastTime = tracking.startTime;
+ tracking.currentSpeed = 0;
+ tracking.averageSpeed = 0;
+ tracking.movingAverageSpeed = 0;
+ tracking.movingAverageHistory = [];
+ tracking.timeRemaining = 0;
+ tracking.timeElapsed = 0;
+ tracking.percentUploaded = bytesUploaded / file.size;
+ tracking.bytesUploaded = bytesUploaded;
+ } else if (tracking.startTime > tickTime) {
+ this.debug("When backwards in time");
+ } else {
+ // Get time and deltas
+ var now = (new Date()).getTime();
+ var lastTime = tracking.lastTime;
+ var deltaTime = now - lastTime;
+ var deltaBytes = bytesUploaded - tracking.bytesUploaded;
+
+ if (deltaBytes === 0 || deltaTime === 0) {
+ return tracking;
+ }
+
+ // Update tracking object
+ tracking.lastTime = now;
+ tracking.bytesUploaded = bytesUploaded;
+
+ // Calculate speeds
+ tracking.currentSpeed = (deltaBytes * 8 ) / (deltaTime / 1000);
+ tracking.averageSpeed = (tracking.bytesUploaded * 8) / ((now - tracking.startTime) / 1000);
+
+ // Calculate moving average
+ tracking.movingAverageHistory.push(tracking.currentSpeed);
+ if (tracking.movingAverageHistory.length > this.settings.moving_average_history_size) {
+ tracking.movingAverageHistory.shift();
+ }
+
+ tracking.movingAverageSpeed = SWFUpload.speed.calculateMovingAverage(tracking.movingAverageHistory);
+
+ // Update times
+ tracking.timeRemaining = (file.size - tracking.bytesUploaded) * 8 / tracking.movingAverageSpeed;
+ tracking.timeElapsed = (now - tracking.startTime) / 1000;
+
+ // Update percent
+ tracking.percentUploaded = (tracking.bytesUploaded / file.size * 100);
+ }
+
+ return tracking;
+ };
+ SWFUpload.speed.removeTracking = function (file, trackingList) {
+ try {
+ trackingList[file.id] = null;
+ delete trackingList[file.id];
+ } catch (ex) {
+ }
+ };
+
+ SWFUpload.speed.formatUnits = function (baseNumber, unitDivisors, unitLabels, singleFractional) {
+ var i, unit, unitDivisor, unitLabel;
+
+ if (baseNumber === 0) {
+ return "0 " + unitLabels[unitLabels.length - 1];
+ }
+
+ if (singleFractional) {
+ unit = baseNumber;
+ unitLabel = unitLabels.length >= unitDivisors.length ? unitLabels[unitDivisors.length - 1] : "";
+ for (i = 0; i < unitDivisors.length; i++) {
+ if (baseNumber >= unitDivisors[i]) {
+ unit = (baseNumber / unitDivisors[i]).toFixed(2);
+ unitLabel = unitLabels.length >= i ? " " + unitLabels[i] : "";
+ break;
+ }
+ }
+
+ return unit + unitLabel;
+ } else {
+ var formattedStrings = [];
+ var remainder = baseNumber;
+
+ for (i = 0; i < unitDivisors.length; i++) {
+ unitDivisor = unitDivisors[i];
+ unitLabel = unitLabels.length > i ? " " + unitLabels[i] : "";
+
+ unit = remainder / unitDivisor;
+ if (i < unitDivisors.length -1) {
+ unit = Math.floor(unit);
+ } else {
+ unit = unit.toFixed(2);
+ }
+ if (unit > 0) {
+ remainder = remainder % unitDivisor;
+
+ formattedStrings.push(unit + unitLabel);
+ }
+ }
+
+ return formattedStrings.join(" ");
+ }
+ };
+
+ SWFUpload.speed.formatBPS = function (baseNumber) {
+ var bpsUnits = [1073741824, 1048576, 1024, 1], bpsUnitLabels = ["Gbps", "Mbps", "Kbps", "bps"];
+ return SWFUpload.speed.formatUnits(baseNumber, bpsUnits, bpsUnitLabels, true);
+
+ };
+ SWFUpload.speed.formatTime = function (baseNumber) {
+ var timeUnits = [86400, 3600, 60, 1], timeUnitLabels = ["d", "h", "m", "s"];
+ return SWFUpload.speed.formatUnits(baseNumber, timeUnits, timeUnitLabels, false);
+
+ };
+ SWFUpload.speed.formatBytes = function (baseNumber) {
+ var sizeUnits = [1073741824, 1048576, 1024, 1], sizeUnitLabels = ["GB", "MB", "KB", "bytes"];
+ return SWFUpload.speed.formatUnits(baseNumber, sizeUnits, sizeUnitLabels, true);
+
+ };
+ SWFUpload.speed.formatPercent = function (baseNumber) {
+ return baseNumber.toFixed(2) + " %";
+ };
+
+ SWFUpload.speed.calculateMovingAverage = function (history) {
+ var vals = [], size, sum = 0.0, mean = 0.0, varianceTemp = 0.0, variance = 0.0, standardDev = 0.0;
+ var i;
+ var mSum = 0, mCount = 0;
+
+ size = history.length;
+
+ // Check for sufficient data
+ if (size >= 8) {
+ // Clone the array and Calculate sum of the values
+ for (i = 0; i < size; i++) {
+ vals[i] = history[i];
+ sum += vals[i];
+ }
+
+ mean = sum / size;
+
+ // Calculate variance for the set
+ for (i = 0; i < size; i++) {
+ varianceTemp += Math.pow((vals[i] - mean), 2);
+ }
+
+ variance = varianceTemp / size;
+ standardDev = Math.sqrt(variance);
+
+ //Standardize the Data
+ for (i = 0; i < size; i++) {
+ vals[i] = (vals[i] - mean) / standardDev;
+ }
+
+ // Calculate the average excluding outliers
+ var deviationRange = 2.0;
+ for (i = 0; i < size; i++) {
+
+ if (vals[i] <= deviationRange && vals[i] >= -deviationRange) {
+ mCount++;
+ mSum += history[i];
+ }
+ }
+
+ } else {
+ // Calculate the average (not enough data points to remove outliers)
+ mCount = size;
+ for (i = 0; i < size; i++) {
+ mSum += history[i];
+ }
+ }
+
+ return mSum / mCount;
+ };
+
+} \ No newline at end of file
diff --git a/debian/missing-sources/swfupload/plugins/swfupload.swfobject.js b/debian/missing-sources/swfupload/plugins/swfupload.swfobject.js
new file mode 100644
index 0000000..a75adbf
--- /dev/null
+++ b/debian/missing-sources/swfupload/plugins/swfupload.swfobject.js
@@ -0,0 +1,111 @@
+/*
+ SWFUpload.SWFObject Plugin
+
+ Summary:
+ This plugin uses SWFObject to embed SWFUpload dynamically in the page. SWFObject provides accurate Flash Player detection and DOM Ready loading.
+ This plugin replaces the Graceful Degradation plugin.
+
+ Features:
+ * swfupload_load_failed_hander event
+ * swfupload_pre_load_handler event
+ * minimum_flash_version setting (default: "9.0.28")
+ * SWFUpload.onload event for early loading
+
+ Usage:
+ Provide handlers and settings as needed. When using the SWFUpload.SWFObject plugin you should initialize SWFUploading
+ in SWFUpload.onload rather than in window.onload. When initialized this way SWFUpload can load earlier preventing the UI flicker
+ that was seen using the Graceful Degradation plugin.
+
+ <script type="text/javascript">
+ var swfu;
+ SWFUpload.onload = function () {
+ swfu = new SWFUpload({
+ minimum_flash_version: "9.0.28",
+ swfupload_pre_load_handler: swfuploadPreLoad,
+ swfupload_load_failed_handler: swfuploadLoadFailed
+ });
+ };
+ </script>
+
+ Notes:
+ You must provide set minimum_flash_version setting to "8" if you are using SWFUpload for Flash Player 8.
+ The swfuploadLoadFailed event is only fired if the minimum version of Flash Player is not met. Other issues such as missing SWF files, browser bugs
+ or corrupt Flash Player installations will not trigger this event.
+ The swfuploadPreLoad event is fired as soon as the minimum version of Flash Player is found. It does not wait for SWFUpload to load and can
+ be used to prepare the SWFUploadUI and hide alternate content.
+ swfobject's onDomReady event is cross-browser safe but will default to the window.onload event when DOMReady is not supported by the browser.
+ Early DOM Loading is supported in major modern browsers but cannot be guaranteed for every browser ever made.
+*/
+
+
+/* SWFObject v2.1 <http://code.google.com/p/swfobject/>
+ Copyright (c) 2007-2008 Geoff Stearns, Michael Williams, and Bobby van der Sluis
+ This software is released under the MIT License <http://www.opensource.org/licenses/mit-license.php>
+*/
+var swfobject=function(){var b="undefined",Q="object",n="Shockwave Flash",p="ShockwaveFlash.ShockwaveFlash",P="application/x-shockwave-flash",m="SWFObjectExprInst",j=window,K=document,T=navigator,o=[],N=[],i=[],d=[],J,Z=null,M=null,l=null,e=false,A=false;var h=function(){var v=typeof K.getElementById!=b&&typeof K.getElementsByTagName!=b&&typeof K.createElement!=b,AC=[0,0,0],x=null;if(typeof T.plugins!=b&&typeof T.plugins[n]==Q){x=T.plugins[n].description;if(x&&!(typeof T.mimeTypes!=b&&T.mimeTypes[P]&&!T.mimeTypes[P].enabledPlugin)){x=x.replace(/^.*\s+(\S+\s+\S+$)/,"$1");AC[0]=parseInt(x.replace(/^(.*)\..*$/,"$1"),10);AC[1]=parseInt(x.replace(/^.*\.(.*)\s.*$/,"$1"),10);AC[2]=/r/.test(x)?parseInt(x.replace(/^.*r(.*)$/,"$1"),10):0}}else{if(typeof j.ActiveXObject!=b){var y=null,AB=false;try{y=new ActiveXObject(p+".7")}catch(t){try{y=new ActiveXObject(p+".6");AC=[6,0,21];y.AllowScriptAccess="always"}catch(t){if(AC[0]==6){AB=true}}if(!AB){try{y=new ActiveXObject(p)}catch(t){}}}if(!AB&&y){try{x=y.GetVariable("$version");if(x){x=x.split(" ")[1].split(",");AC=[parseInt(x[0],10),parseInt(x[1],10),parseInt(x[2],10)]}}catch(t){}}}}var AD=T.userAgent.toLowerCase(),r=T.platform.toLowerCase(),AA=/webkit/.test(AD)?parseFloat(AD.replace(/^.*webkit\/(\d+(\.\d+)?).*$/,"$1")):false,q=false,z=r?/win/.test(r):/win/.test(AD),w=r?/mac/.test(r):/mac/.test(AD);/*@cc_on q=true;@if(@_win32)z=true;@elif(@_mac)w=true;@end@*/return{w3cdom:v,pv:AC,webkit:AA,ie:q,win:z,mac:w}}();var L=function(){if(!h.w3cdom){return }f(H);if(h.ie&&h.win){try{K.write("<script id=__ie_ondomload defer=true src=//:><\/script>");J=C("__ie_ondomload");if(J){I(J,"onreadystatechange",S)}}catch(q){}}if(h.webkit&&typeof K.readyState!=b){Z=setInterval(function(){if(/loaded|complete/.test(K.readyState)){E()}},10)}if(typeof K.addEventListener!=b){K.addEventListener("DOMContentLoaded",E,null)}R(E)}();function S(){if(J.readyState=="complete"){J.parentNode.removeChild(J);E()}}function E(){if(e){return }if(h.ie&&h.win){var v=a("span");try{var u=K.getElementsByTagName("body")[0].appendChild(v);u.parentNode.removeChild(u)}catch(w){return }}e=true;if(Z){clearInterval(Z);Z=null}var q=o.length;for(var r=0;r<q;r++){o[r]()}}function f(q){if(e){q()}else{o[o.length]=q}}function R(r){if(typeof j.addEventListener!=b){j.addEventListener("load",r,false)}else{if(typeof K.addEventListener!=b){K.addEventListener("load",r,false)}else{if(typeof j.attachEvent!=b){I(j,"onload",r)}else{if(typeof j.onload=="function"){var q=j.onload;j.onload=function(){q();r()}}else{j.onload=r}}}}}function H(){var t=N.length;for(var q=0;q<t;q++){var u=N[q].id;if(h.pv[0]>0){var r=C(u);if(r){N[q].width=r.getAttribute("width")?r.getAttribute("width"):"0";N[q].height=r.getAttribute("height")?r.getAttribute("height"):"0";if(c(N[q].swfVersion)){if(h.webkit&&h.webkit<312){Y(r)}W(u,true)}else{if(N[q].expressInstall&&!A&&c("6.0.65")&&(h.win||h.mac)){k(N[q])}else{O(r)}}}}else{W(u,true)}}}function Y(t){var q=t.getElementsByTagName(Q)[0];if(q){var w=a("embed"),y=q.attributes;if(y){var v=y.length;for(var u=0;u<v;u++){if(y[u].nodeName=="DATA"){w.setAttribute("src",y[u].nodeValue)}else{w.setAttribute(y[u].nodeName,y[u].nodeValue)}}}var x=q.childNodes;if(x){var z=x.length;for(var r=0;r<z;r++){if(x[r].nodeType==1&&x[r].nodeName=="PARAM"){w.setAttribute(x[r].getAttribute("name"),x[r].getAttribute("value"))}}}t.parentNode.replaceChild(w,t)}}function k(w){A=true;var u=C(w.id);if(u){if(w.altContentId){var y=C(w.altContentId);if(y){M=y;l=w.altContentId}}else{M=G(u)}if(!(/%$/.test(w.width))&&parseInt(w.width,10)<310){w.width="310"}if(!(/%$/.test(w.height))&&parseInt(w.height,10)<137){w.height="137"}K.title=K.title.slice(0,47)+" - Flash Player Installation";var z=h.ie&&h.win?"ActiveX":"PlugIn",q=K.title,r="MMredirectURL="+j.location+"&MMplayerType="+z+"&MMdoctitle="+q,x=w.id;if(h.ie&&h.win&&u.readyState!=4){var t=a("div");x+="SWFObjectNew";t.setAttribute("id",x);u.parentNode.insertBefore(t,u);u.style.display="none";var v=function(){u.parentNode.removeChild(u)};I(j,"onload",v)}U({data:w.expressInstall,id:m,width:w.width,height:w.height},{flashvars:r},x)}}function O(t){if(h.ie&&h.win&&t.readyState!=4){var r=a("div");t.parentNode.insertBefore(r,t);r.parentNode.replaceChild(G(t),r);t.style.display="none";var q=function(){t.parentNode.removeChild(t)};I(j,"onload",q)}else{t.parentNode.replaceChild(G(t),t)}}function G(v){var u=a("div");if(h.win&&h.ie){u.innerHTML=v.innerHTML}else{var r=v.getElementsByTagName(Q)[0];if(r){var w=r.childNodes;if(w){var q=w.length;for(var t=0;t<q;t++){if(!(w[t].nodeType==1&&w[t].nodeName=="PARAM")&&!(w[t].nodeType==8)){u.appendChild(w[t].cloneNode(true))}}}}}return u}function U(AG,AE,t){var q,v=C(t);if(v){if(typeof AG.id==b){AG.id=t}if(h.ie&&h.win){var AF="";for(var AB in AG){if(AG[AB]!=Object.prototype[AB]){if(AB.toLowerCase()=="data"){AE.movie=AG[AB]}else{if(AB.toLowerCase()=="styleclass"){AF+=' class="'+AG[AB]+'"'}else{if(AB.toLowerCase()!="classid"){AF+=" "+AB+'="'+AG[AB]+'"'}}}}}var AD="";for(var AA in AE){if(AE[AA]!=Object.prototype[AA]){AD+='<param name="'+AA+'" value="'+AE[AA]+'" />'}}v.outerHTML='<object classid="clsid:D27CDB6E-AE6D-11cf-96B8-444553540000"'+AF+">"+AD+"</object>";i[i.length]=AG.id;q=C(AG.id)}else{if(h.webkit&&h.webkit<312){var AC=a("embed");AC.setAttribute("type",P);for(var z in AG){if(AG[z]!=Object.prototype[z]){if(z.toLowerCase()=="data"){AC.setAttribute("src",AG[z])}else{if(z.toLowerCase()=="styleclass"){AC.setAttribute("class",AG[z])}else{if(z.toLowerCase()!="classid"){AC.setAttribute(z,AG[z])}}}}}for(var y in AE){if(AE[y]!=Object.prototype[y]){if(y.toLowerCase()!="movie"){AC.setAttribute(y,AE[y])}}}v.parentNode.replaceChild(AC,v);q=AC}else{var u=a(Q);u.setAttribute("type",P);for(var x in AG){if(AG[x]!=Object.prototype[x]){if(x.toLowerCase()=="styleclass"){u.setAttribute("class",AG[x])}else{if(x.toLowerCase()!="classid"){u.setAttribute(x,AG[x])}}}}for(var w in AE){if(AE[w]!=Object.prototype[w]&&w.toLowerCase()!="movie"){F(u,w,AE[w])}}v.parentNode.replaceChild(u,v);q=u}}}return q}function F(t,q,r){var u=a("param");u.setAttribute("name",q);u.setAttribute("value",r);t.appendChild(u)}function X(r){var q=C(r);if(q&&(q.nodeName=="OBJECT"||q.nodeName=="EMBED")){if(h.ie&&h.win){if(q.readyState==4){B(r)}else{j.attachEvent("onload",function(){B(r)})}}else{q.parentNode.removeChild(q)}}}function B(t){var r=C(t);if(r){for(var q in r){if(typeof r[q]=="function"){r[q]=null}}r.parentNode.removeChild(r)}}function C(t){var q=null;try{q=K.getElementById(t)}catch(r){}return q}function a(q){return K.createElement(q)}function I(t,q,r){t.attachEvent(q,r);d[d.length]=[t,q,r]}function c(t){var r=h.pv,q=t.split(".");q[0]=parseInt(q[0],10);q[1]=parseInt(q[1],10)||0;q[2]=parseInt(q[2],10)||0;return(r[0]>q[0]||(r[0]==q[0]&&r[1]>q[1])||(r[0]==q[0]&&r[1]==q[1]&&r[2]>=q[2]))?true:false}function V(v,r){if(h.ie&&h.mac){return }var u=K.getElementsByTagName("head")[0],t=a("style");t.setAttribute("type","text/css");t.setAttribute("media","screen");if(!(h.ie&&h.win)&&typeof K.createTextNode!=b){t.appendChild(K.createTextNode(v+" {"+r+"}"))}u.appendChild(t);if(h.ie&&h.win&&typeof K.styleSheets!=b&&K.styleSheets.length>0){var q=K.styleSheets[K.styleSheets.length-1];if(typeof q.addRule==Q){q.addRule(v,r)}}}function W(t,q){var r=q?"visible":"hidden";if(e&&C(t)){C(t).style.visibility=r}else{V("#"+t,"visibility:"+r)}}function g(s){var r=/[\\\"<>\.;]/;var q=r.exec(s)!=null;return q?encodeURIComponent(s):s}var D=function(){if(h.ie&&h.win){window.attachEvent("onunload",function(){var w=d.length;for(var v=0;v<w;v++){d[v][0].detachEvent(d[v][1],d[v][2])}var t=i.length;for(var u=0;u<t;u++){X(i[u])}for(var r in h){h[r]=null}h=null;for(var q in swfobject){swfobject[q]=null}swfobject=null})}}();return{registerObject:function(u,q,t){if(!h.w3cdom||!u||!q){return }var r={};r.id=u;r.swfVersion=q;r.expressInstall=t?t:false;N[N.length]=r;W(u,false)},getObjectById:function(v){var q=null;if(h.w3cdom){var t=C(v);if(t){var u=t.getElementsByTagName(Q)[0];if(!u||(u&&typeof t.SetVariable!=b)){q=t}else{if(typeof u.SetVariable!=b){q=u}}}}return q},embedSWF:function(x,AE,AB,AD,q,w,r,z,AC){if(!h.w3cdom||!x||!AE||!AB||!AD||!q){return }AB+="";AD+="";if(c(q)){W(AE,false);var AA={};if(AC&&typeof AC===Q){for(var v in AC){if(AC[v]!=Object.prototype[v]){AA[v]=AC[v]}}}AA.data=x;AA.width=AB;AA.height=AD;var y={};if(z&&typeof z===Q){for(var u in z){if(z[u]!=Object.prototype[u]){y[u]=z[u]}}}if(r&&typeof r===Q){for(var t in r){if(r[t]!=Object.prototype[t]){if(typeof y.flashvars!=b){y.flashvars+="&"+t+"="+r[t]}else{y.flashvars=t+"="+r[t]}}}}f(function(){U(AA,y,AE);if(AA.id==AE){W(AE,true)}})}else{if(w&&!A&&c("6.0.65")&&(h.win||h.mac)){A=true;W(AE,false);f(function(){var AF={};AF.id=AF.altContentId=AE;AF.width=AB;AF.height=AD;AF.expressInstall=w;k(AF)})}}},getFlashPlayerVersion:function(){return{major:h.pv[0],minor:h.pv[1],release:h.pv[2]}},hasFlashPlayerVersion:c,createSWF:function(t,r,q){if(h.w3cdom){return U(t,r,q)}else{return undefined}},removeSWF:function(q){if(h.w3cdom){X(q)}},createCSS:function(r,q){if(h.w3cdom){V(r,q)}},addDomLoadEvent:f,addLoadEvent:R,getQueryParamValue:function(v){var u=K.location.search||K.location.hash;if(v==null){return g(u)}if(u){var t=u.substring(1).split("&");for(var r=0;r<t.length;r++){if(t[r].substring(0,t[r].indexOf("="))==v){return g(t[r].substring((t[r].indexOf("=")+1)))}}}return""},expressInstallCallback:function(){if(A&&M){var q=C(m);if(q){q.parentNode.replaceChild(M,q);if(l){W(l,true);if(h.ie&&h.win){M.style.display="block"}}M=null;l=null;A=false}}}}}();
+
+
+
+var SWFUpload;
+if (typeof(SWFUpload) === "function") {
+ SWFUpload.onload = function () {};
+
+ swfobject.addDomLoadEvent(function () {
+ if (typeof(SWFUpload.onload) === "function") {
+ SWFUpload.onload.call(window);
+ }
+ });
+
+ SWFUpload.prototype.initSettings = (function (oldInitSettings) {
+ return function () {
+ if (typeof(oldInitSettings) === "function") {
+ oldInitSettings.call(this);
+ }
+
+ this.ensureDefault = function (settingName, defaultValue) {
+ this.settings[settingName] = (this.settings[settingName] == undefined) ? defaultValue : this.settings[settingName];
+ };
+
+ this.ensureDefault("minimum_flash_version", "9.0.28");
+ this.ensureDefault("swfupload_pre_load_handler", null);
+ this.ensureDefault("swfupload_load_failed_handler", null);
+
+ delete this.ensureDefault;
+
+ };
+ })(SWFUpload.prototype.initSettings);
+
+
+ SWFUpload.prototype.loadFlash = function (oldLoadFlash) {
+ return function () {
+ var hasFlash = swfobject.hasFlashPlayerVersion(this.settings.minimum_flash_version);
+
+ if (hasFlash) {
+ this.queueEvent("swfupload_pre_load_handler");
+ if (typeof(oldLoadFlash) === "function") {
+ oldLoadFlash.call(this);
+ }
+ } else {
+ this.queueEvent("swfupload_load_failed_handler");
+ }
+ };
+
+ }(SWFUpload.prototype.loadFlash);
+
+ SWFUpload.prototype.displayDebugInfo = function (oldDisplayDebugInfo) {
+ return function () {
+ if (typeof(oldDisplayDebugInfo) === "function") {
+ oldDisplayDebugInfo.call(this);
+ }
+
+ this.debug(
+ [
+ "SWFUpload.SWFObject Plugin settings:", "\n",
+ "\t", "minimum_flash_version: ", this.settings.minimum_flash_version, "\n",
+ "\t", "swfupload_pre_load_handler assigned: ", (typeof(this.settings.swfupload_pre_load_handler) === "function").toString(), "\n",
+ "\t", "swfupload_load_failed_handler assigned: ", (typeof(this.settings.swfupload_load_failed_handler) === "function").toString(), "\n",
+ ].join("")
+ );
+ };
+ }(SWFUpload.prototype.displayDebugInfo);
+}
diff --git a/debian/missing-sources/swfupload/swfupload license.txt b/debian/missing-sources/swfupload/swfupload license.txt
new file mode 100644
index 0000000..3704d20
--- /dev/null
+++ b/debian/missing-sources/swfupload/swfupload license.txt
@@ -0,0 +1,12 @@
+/**
+ * SWFUpload: http://www.swfupload.org, http://swfupload.googlecode.com
+ *
+ * mmSWFUpload 1.0: Flash upload dialog - http://profandesign.se/swfupload/, http://www.vinterwebb.se/
+ *
+ * SWFUpload is (c) 2006-2007 Lars Huring, Olov Nilzén and Mammon Media and is released under the MIT License:
+ * http://www.opensource.org/licenses/mit-license.php
+ *
+ * SWFUpload 2 is (c) 2007-2008 Jake Roberts and is released under the MIT License:
+ * http://www.opensource.org/licenses/mit-license.php
+ *
+ */
diff --git a/debian/missing-sources/swfupload/swfupload.js b/debian/missing-sources/swfupload/swfupload.js
new file mode 100644
index 0000000..969e200
--- /dev/null
+++ b/debian/missing-sources/swfupload/swfupload.js
@@ -0,0 +1,980 @@
+/**
+ * SWFUpload: http://www.swfupload.org, http://swfupload.googlecode.com
+ *
+ * mmSWFUpload 1.0: Flash upload dialog - http://profandesign.se/swfupload/, http://www.vinterwebb.se/
+ *
+ * SWFUpload is (c) 2006-2007 Lars Huring, Olov Nilzén and Mammon Media and is released under the MIT License:
+ * http://www.opensource.org/licenses/mit-license.php
+ *
+ * SWFUpload 2 is (c) 2007-2008 Jake Roberts and is released under the MIT License:
+ * http://www.opensource.org/licenses/mit-license.php
+ *
+ */
+
+
+/* ******************* */
+/* Constructor & Init */
+/* ******************* */
+var SWFUpload;
+
+if (SWFUpload == undefined) {
+ SWFUpload = function (settings) {
+ this.initSWFUpload(settings);
+ };
+}
+
+SWFUpload.prototype.initSWFUpload = function (settings) {
+ try {
+ this.customSettings = {}; // A container where developers can place their own settings associated with this instance.
+ this.settings = settings;
+ this.eventQueue = [];
+ this.movieName = "SWFUpload_" + SWFUpload.movieCount++;
+ this.movieElement = null;
+
+
+ // Setup global control tracking
+ SWFUpload.instances[this.movieName] = this;
+
+ // Load the settings. Load the Flash movie.
+ this.initSettings();
+ this.loadFlash();
+ this.displayDebugInfo();
+ } catch (ex) {
+ delete SWFUpload.instances[this.movieName];
+ throw ex;
+ }
+};
+
+/* *************** */
+/* Static Members */
+/* *************** */
+SWFUpload.instances = {};
+SWFUpload.movieCount = 0;
+SWFUpload.version = "2.2.0 2009-03-25";
+SWFUpload.QUEUE_ERROR = {
+ QUEUE_LIMIT_EXCEEDED : -100,
+ FILE_EXCEEDS_SIZE_LIMIT : -110,
+ ZERO_BYTE_FILE : -120,
+ INVALID_FILETYPE : -130
+};
+SWFUpload.UPLOAD_ERROR = {
+ HTTP_ERROR : -200,
+ MISSING_UPLOAD_URL : -210,
+ IO_ERROR : -220,
+ SECURITY_ERROR : -230,
+ UPLOAD_LIMIT_EXCEEDED : -240,
+ UPLOAD_FAILED : -250,
+ SPECIFIED_FILE_ID_NOT_FOUND : -260,
+ FILE_VALIDATION_FAILED : -270,
+ FILE_CANCELLED : -280,
+ UPLOAD_STOPPED : -290
+};
+SWFUpload.FILE_STATUS = {
+ QUEUED : -1,
+ IN_PROGRESS : -2,
+ ERROR : -3,
+ COMPLETE : -4,
+ CANCELLED : -5
+};
+SWFUpload.BUTTON_ACTION = {
+ SELECT_FILE : -100,
+ SELECT_FILES : -110,
+ START_UPLOAD : -120
+};
+SWFUpload.CURSOR = {
+ ARROW : -1,
+ HAND : -2
+};
+SWFUpload.WINDOW_MODE = {
+ WINDOW : "window",
+ TRANSPARENT : "transparent",
+ OPAQUE : "opaque"
+};
+
+// Private: takes a URL, determines if it is relative and converts to an absolute URL
+// using the current site. Only processes the URL if it can, otherwise returns the URL untouched
+SWFUpload.completeURL = function(url) {
+ if (typeof(url) !== "string" || url.match(/^https?:\/\//i) || url.match(/^\//)) {
+ return url;
+ }
+
+ var currentURL = window.location.protocol + "//" + window.location.hostname + (window.location.port ? ":" + window.location.port : "");
+
+ var indexSlash = window.location.pathname.lastIndexOf("/");
+ if (indexSlash <= 0) {
+ path = "/";
+ } else {
+ path = window.location.pathname.substr(0, indexSlash) + "/";
+ }
+
+ return /*currentURL +*/ path + url;
+
+};
+
+
+/* ******************** */
+/* Instance Members */
+/* ******************** */
+
+// Private: initSettings ensures that all the
+// settings are set, getting a default value if one was not assigned.
+SWFUpload.prototype.initSettings = function () {
+ this.ensureDefault = function (settingName, defaultValue) {
+ this.settings[settingName] = (this.settings[settingName] == undefined) ? defaultValue : this.settings[settingName];
+ };
+
+ // Upload backend settings
+ this.ensureDefault("upload_url", "");
+ this.ensureDefault("preserve_relative_urls", false);
+ this.ensureDefault("file_post_name", "Filedata");
+ this.ensureDefault("post_params", {});
+ this.ensureDefault("use_query_string", false);
+ this.ensureDefault("requeue_on_error", false);
+ this.ensureDefault("http_success", []);
+ this.ensureDefault("assume_success_timeout", 0);
+
+ // File Settings
+ this.ensureDefault("file_types", "*.*");
+ this.ensureDefault("file_types_description", "All Files");
+ this.ensureDefault("file_size_limit", 0); // Default zero means "unlimited"
+ this.ensureDefault("file_upload_limit", 0);
+ this.ensureDefault("file_queue_limit", 0);
+
+ // Flash Settings
+ this.ensureDefault("flash_url", "swfupload.swf");
+ this.ensureDefault("prevent_swf_caching", true);
+
+ // Button Settings
+ this.ensureDefault("button_image_url", "");
+ this.ensureDefault("button_width", 1);
+ this.ensureDefault("button_height", 1);
+ this.ensureDefault("button_text", "");
+ this.ensureDefault("button_text_style", "color: #000000; font-size: 16pt;");
+ this.ensureDefault("button_text_top_padding", 0);
+ this.ensureDefault("button_text_left_padding", 0);
+ this.ensureDefault("button_action", SWFUpload.BUTTON_ACTION.SELECT_FILES);
+ this.ensureDefault("button_disabled", false);
+ this.ensureDefault("button_placeholder_id", "");
+ this.ensureDefault("button_placeholder", null);
+ this.ensureDefault("button_cursor", SWFUpload.CURSOR.ARROW);
+ this.ensureDefault("button_window_mode", SWFUpload.WINDOW_MODE.WINDOW);
+
+ // Debug Settings
+ this.ensureDefault("debug", false);
+ this.settings.debug_enabled = this.settings.debug; // Here to maintain v2 API
+
+ // Event Handlers
+ this.settings.return_upload_start_handler = this.returnUploadStart;
+ this.ensureDefault("swfupload_loaded_handler", null);
+ this.ensureDefault("file_dialog_start_handler", null);
+ this.ensureDefault("file_queued_handler", null);
+ this.ensureDefault("file_queue_error_handler", null);
+ this.ensureDefault("file_dialog_complete_handler", null);
+
+ this.ensureDefault("upload_start_handler", null);
+ this.ensureDefault("upload_progress_handler", null);
+ this.ensureDefault("upload_error_handler", null);
+ this.ensureDefault("upload_success_handler", null);
+ this.ensureDefault("upload_complete_handler", null);
+
+ this.ensureDefault("debug_handler", this.debugMessage);
+
+ this.ensureDefault("custom_settings", {});
+
+ // Other settings
+ this.customSettings = this.settings.custom_settings;
+
+ // Update the flash url if needed
+ if (!!this.settings.prevent_swf_caching) {
+ this.settings.flash_url = this.settings.flash_url + (this.settings.flash_url.indexOf("?") < 0 ? "?" : "&") + "preventswfcaching=" + new Date().getTime();
+ }
+
+ if (!this.settings.preserve_relative_urls) {
+ //this.settings.flash_url = SWFUpload.completeURL(this.settings.flash_url); // Don't need to do this one since flash doesn't look at it
+ this.settings.upload_url = SWFUpload.completeURL(this.settings.upload_url);
+ this.settings.button_image_url = SWFUpload.completeURL(this.settings.button_image_url);
+ }
+
+ delete this.ensureDefault;
+};
+
+// Private: loadFlash replaces the button_placeholder element with the flash movie.
+SWFUpload.prototype.loadFlash = function () {
+ var targetElement, tempParent;
+
+ // Make sure an element with the ID we are going to use doesn't already exist
+ if (document.getElementById(this.movieName) !== null) {
+ throw "ID " + this.movieName + " is already in use. The Flash Object could not be added";
+ }
+
+ // Get the element where we will be placing the flash movie
+ targetElement = document.getElementById(this.settings.button_placeholder_id) || this.settings.button_placeholder;
+
+ if (targetElement == undefined) {
+ throw "Could not find the placeholder element: " + this.settings.button_placeholder_id;
+ }
+
+ // Append the container and load the flash
+ tempParent = document.createElement("div");
+ tempParent.innerHTML = this.getFlashHTML(); // Using innerHTML is non-standard but the only sensible way to dynamically add Flash in IE (and maybe other browsers)
+ targetElement.parentNode.replaceChild(tempParent.firstChild, targetElement);
+
+ // Fix IE Flash/Form bug
+ if (window[this.movieName] == undefined) {
+ window[this.movieName] = this.getMovieElement();
+ }
+
+};
+
+// Private: getFlashHTML generates the object tag needed to embed the flash in to the document
+SWFUpload.prototype.getFlashHTML = function () {
+ // Flash Satay object syntax: http://www.alistapart.com/articles/flashsatay
+ return ['<object id="', this.movieName, '" type="application/x-shockwave-flash" data="', this.settings.flash_url, '" width="', this.settings.button_width, '" height="', this.settings.button_height, '" class="swfupload">',
+ '<param name="wmode" value="', this.settings.button_window_mode, '" />',
+ '<param name="movie" value="', this.settings.flash_url, '" />',
+ '<param name="quality" value="high" />',
+ '<param name="menu" value="false" />',
+ '<param name="allowScriptAccess" value="always" />',
+ '<param name="flashvars" value="' + this.getFlashVars() + '" />',
+ '</object>'].join("");
+};
+
+// Private: getFlashVars builds the parameter string that will be passed
+// to flash in the flashvars param.
+SWFUpload.prototype.getFlashVars = function () {
+ // Build a string from the post param object
+ var paramString = this.buildParamString();
+ var httpSuccessString = this.settings.http_success.join(",");
+
+ // Build the parameter string
+ return ["movieName=", encodeURIComponent(this.movieName),
+ "&amp;uploadURL=", encodeURIComponent(this.settings.upload_url),
+ "&amp;useQueryString=", encodeURIComponent(this.settings.use_query_string),
+ "&amp;requeueOnError=", encodeURIComponent(this.settings.requeue_on_error),
+ "&amp;httpSuccess=", encodeURIComponent(httpSuccessString),
+ "&amp;assumeSuccessTimeout=", encodeURIComponent(this.settings.assume_success_timeout),
+ "&amp;params=", encodeURIComponent(paramString),
+ "&amp;filePostName=", encodeURIComponent(this.settings.file_post_name),
+ "&amp;fileTypes=", encodeURIComponent(this.settings.file_types),
+ "&amp;fileTypesDescription=", encodeURIComponent(this.settings.file_types_description),
+ "&amp;fileSizeLimit=", encodeURIComponent(this.settings.file_size_limit),
+ "&amp;fileUploadLimit=", encodeURIComponent(this.settings.file_upload_limit),
+ "&amp;fileQueueLimit=", encodeURIComponent(this.settings.file_queue_limit),
+ "&amp;debugEnabled=", encodeURIComponent(this.settings.debug_enabled),
+ "&amp;buttonImageURL=", encodeURIComponent(this.settings.button_image_url),
+ "&amp;buttonWidth=", encodeURIComponent(this.settings.button_width),
+ "&amp;buttonHeight=", encodeURIComponent(this.settings.button_height),
+ "&amp;buttonText=", encodeURIComponent(this.settings.button_text),
+ "&amp;buttonTextTopPadding=", encodeURIComponent(this.settings.button_text_top_padding),
+ "&amp;buttonTextLeftPadding=", encodeURIComponent(this.settings.button_text_left_padding),
+ "&amp;buttonTextStyle=", encodeURIComponent(this.settings.button_text_style),
+ "&amp;buttonAction=", encodeURIComponent(this.settings.button_action),
+ "&amp;buttonDisabled=", encodeURIComponent(this.settings.button_disabled),
+ "&amp;buttonCursor=", encodeURIComponent(this.settings.button_cursor)
+ ].join("");
+};
+
+// Public: getMovieElement retrieves the DOM reference to the Flash element added by SWFUpload
+// The element is cached after the first lookup
+SWFUpload.prototype.getMovieElement = function () {
+ if (this.movieElement == undefined) {
+ this.movieElement = document.getElementById(this.movieName);
+ }
+
+ if (this.movieElement === null) {
+ throw "Could not find Flash element";
+ }
+
+ return this.movieElement;
+};
+
+// Private: buildParamString takes the name/value pairs in the post_params setting object
+// and joins them up in to a string formatted "name=value&amp;name=value"
+SWFUpload.prototype.buildParamString = function () {
+ var postParams = this.settings.post_params;
+ var paramStringPairs = [];
+
+ if (typeof(postParams) === "object") {
+ for (var name in postParams) {
+ if (postParams.hasOwnProperty(name)) {
+ paramStringPairs.push(encodeURIComponent(name.toString()) + "=" + encodeURIComponent(postParams[name].toString()));
+ }
+ }
+ }
+
+ return paramStringPairs.join("&amp;");
+};
+
+// Public: Used to remove a SWFUpload instance from the page. This method strives to remove
+// all references to the SWF, and other objects so memory is properly freed.
+// Returns true if everything was destroyed. Returns a false if a failure occurs leaving SWFUpload in an inconsistant state.
+// Credits: Major improvements provided by steffen
+SWFUpload.prototype.destroy = function () {
+ try {
+ // Make sure Flash is done before we try to remove it
+ this.cancelUpload(null, false);
+
+
+ // Remove the SWFUpload DOM nodes
+ var movieElement = null;
+ movieElement = this.getMovieElement();
+
+ if (movieElement && typeof(movieElement.CallFunction) === "unknown") { // We only want to do this in IE
+ // Loop through all the movie's properties and remove all function references (DOM/JS IE 6/7 memory leak workaround)
+ for (var i in movieElement) {
+ try {
+ if (typeof(movieElement[i]) === "function") {
+ movieElement[i] = null;
+ }
+ } catch (ex1) {}
+ }
+
+ // Remove the Movie Element from the page
+ try {
+ movieElement.parentNode.removeChild(movieElement);
+ } catch (ex) {}
+ }
+
+ // Remove IE form fix reference
+ window[this.movieName] = null;
+
+ // Destroy other references
+ SWFUpload.instances[this.movieName] = null;
+ delete SWFUpload.instances[this.movieName];
+
+ this.movieElement = null;
+ this.settings = null;
+ this.customSettings = null;
+ this.eventQueue = null;
+ this.movieName = null;
+
+
+ return true;
+ } catch (ex2) {
+ return false;
+ }
+};
+
+
+// Public: displayDebugInfo prints out settings and configuration
+// information about this SWFUpload instance.
+// This function (and any references to it) can be deleted when placing
+// SWFUpload in production.
+SWFUpload.prototype.displayDebugInfo = function () {
+ this.debug(
+ [
+ "---SWFUpload Instance Info---\n",
+ "Version: ", SWFUpload.version, "\n",
+ "Movie Name: ", this.movieName, "\n",
+ "Settings:\n",
+ "\t", "upload_url: ", this.settings.upload_url, "\n",
+ "\t", "flash_url: ", this.settings.flash_url, "\n",
+ "\t", "use_query_string: ", this.settings.use_query_string.toString(), "\n",
+ "\t", "requeue_on_error: ", this.settings.requeue_on_error.toString(), "\n",
+ "\t", "http_success: ", this.settings.http_success.join(", "), "\n",
+ "\t", "assume_success_timeout: ", this.settings.assume_success_timeout, "\n",
+ "\t", "file_post_name: ", this.settings.file_post_name, "\n",
+ "\t", "post_params: ", this.settings.post_params.toString(), "\n",
+ "\t", "file_types: ", this.settings.file_types, "\n",
+ "\t", "file_types_description: ", this.settings.file_types_description, "\n",
+ "\t", "file_size_limit: ", this.settings.file_size_limit, "\n",
+ "\t", "file_upload_limit: ", this.settings.file_upload_limit, "\n",
+ "\t", "file_queue_limit: ", this.settings.file_queue_limit, "\n",
+ "\t", "debug: ", this.settings.debug.toString(), "\n",
+
+ "\t", "prevent_swf_caching: ", this.settings.prevent_swf_caching.toString(), "\n",
+
+ "\t", "button_placeholder_id: ", this.settings.button_placeholder_id.toString(), "\n",
+ "\t", "button_placeholder: ", (this.settings.button_placeholder ? "Set" : "Not Set"), "\n",
+ "\t", "button_image_url: ", this.settings.button_image_url.toString(), "\n",
+ "\t", "button_width: ", this.settings.button_width.toString(), "\n",
+ "\t", "button_height: ", this.settings.button_height.toString(), "\n",
+ "\t", "button_text: ", this.settings.button_text.toString(), "\n",
+ "\t", "button_text_style: ", this.settings.button_text_style.toString(), "\n",
+ "\t", "button_text_top_padding: ", this.settings.button_text_top_padding.toString(), "\n",
+ "\t", "button_text_left_padding: ", this.settings.button_text_left_padding.toString(), "\n",
+ "\t", "button_action: ", this.settings.button_action.toString(), "\n",
+ "\t", "button_disabled: ", this.settings.button_disabled.toString(), "\n",
+
+ "\t", "custom_settings: ", this.settings.custom_settings.toString(), "\n",
+ "Event Handlers:\n",
+ "\t", "swfupload_loaded_handler assigned: ", (typeof this.settings.swfupload_loaded_handler === "function").toString(), "\n",
+ "\t", "file_dialog_start_handler assigned: ", (typeof this.settings.file_dialog_start_handler === "function").toString(), "\n",
+ "\t", "file_queued_handler assigned: ", (typeof this.settings.file_queued_handler === "function").toString(), "\n",
+ "\t", "file_queue_error_handler assigned: ", (typeof this.settings.file_queue_error_handler === "function").toString(), "\n",
+ "\t", "upload_start_handler assigned: ", (typeof this.settings.upload_start_handler === "function").toString(), "\n",
+ "\t", "upload_progress_handler assigned: ", (typeof this.settings.upload_progress_handler === "function").toString(), "\n",
+ "\t", "upload_error_handler assigned: ", (typeof this.settings.upload_error_handler === "function").toString(), "\n",
+ "\t", "upload_success_handler assigned: ", (typeof this.settings.upload_success_handler === "function").toString(), "\n",
+ "\t", "upload_complete_handler assigned: ", (typeof this.settings.upload_complete_handler === "function").toString(), "\n",
+ "\t", "debug_handler assigned: ", (typeof this.settings.debug_handler === "function").toString(), "\n"
+ ].join("")
+ );
+};
+
+/* Note: addSetting and getSetting are no longer used by SWFUpload but are included
+ the maintain v2 API compatibility
+*/
+// Public: (Deprecated) addSetting adds a setting value. If the value given is undefined or null then the default_value is used.
+SWFUpload.prototype.addSetting = function (name, value, default_value) {
+ if (value == undefined) {
+ return (this.settings[name] = default_value);
+ } else {
+ return (this.settings[name] = value);
+ }
+};
+
+// Public: (Deprecated) getSetting gets a setting. Returns an empty string if the setting was not found.
+SWFUpload.prototype.getSetting = function (name) {
+ if (this.settings[name] != undefined) {
+ return this.settings[name];
+ }
+
+ return "";
+};
+
+
+
+// Private: callFlash handles function calls made to the Flash element.
+// Calls are made with a setTimeout for some functions to work around
+// bugs in the ExternalInterface library.
+SWFUpload.prototype.callFlash = function (functionName, argumentArray) {
+ argumentArray = argumentArray || [];
+
+ var movieElement = this.getMovieElement();
+ var returnValue, returnString;
+
+ // Flash's method if calling ExternalInterface methods (code adapted from MooTools).
+ try {
+ returnString = movieElement.CallFunction('<invoke name="' + functionName + '" returntype="javascript">' + __flash__argumentsToXML(argumentArray, 0) + '</invoke>');
+ returnValue = eval(returnString);
+ } catch (ex) {
+ throw "Call to " + functionName + " failed";
+ }
+
+ // Unescape file post param values
+ if (returnValue != undefined && typeof returnValue.post === "object") {
+ returnValue = this.unescapeFilePostParams(returnValue);
+ }
+
+ return returnValue;
+};
+
+/* *****************************
+ -- Flash control methods --
+ Your UI should use these
+ to operate SWFUpload
+ ***************************** */
+
+// WARNING: this function does not work in Flash Player 10
+// Public: selectFile causes a File Selection Dialog window to appear. This
+// dialog only allows 1 file to be selected.
+SWFUpload.prototype.selectFile = function () {
+ this.callFlash("SelectFile");
+};
+
+// WARNING: this function does not work in Flash Player 10
+// Public: selectFiles causes a File Selection Dialog window to appear/ This
+// dialog allows the user to select any number of files
+// Flash Bug Warning: Flash limits the number of selectable files based on the combined length of the file names.
+// If the selection name length is too long the dialog will fail in an unpredictable manner. There is no work-around
+// for this bug.
+SWFUpload.prototype.selectFiles = function () {
+ this.callFlash("SelectFiles");
+};
+
+
+// Public: startUpload starts uploading the first file in the queue unless
+// the optional parameter 'fileID' specifies the ID
+SWFUpload.prototype.startUpload = function (fileID) {
+ this.callFlash("StartUpload", [fileID]);
+};
+
+// Public: cancelUpload cancels any queued file. The fileID parameter may be the file ID or index.
+// If you do not specify a fileID the current uploading file or first file in the queue is cancelled.
+// If you do not want the uploadError event to trigger you can specify false for the triggerErrorEvent parameter.
+SWFUpload.prototype.cancelUpload = function (fileID, triggerErrorEvent) {
+ if (triggerErrorEvent !== false) {
+ triggerErrorEvent = true;
+ }
+ this.callFlash("CancelUpload", [fileID, triggerErrorEvent]);
+};
+
+// Public: stopUpload stops the current upload and requeues the file at the beginning of the queue.
+// If nothing is currently uploading then nothing happens.
+SWFUpload.prototype.stopUpload = function () {
+ this.callFlash("StopUpload");
+};
+
+/* ************************
+ * Settings methods
+ * These methods change the SWFUpload settings.
+ * SWFUpload settings should not be changed directly on the settings object
+ * since many of the settings need to be passed to Flash in order to take
+ * effect.
+ * *********************** */
+
+// Public: getStats gets the file statistics object.
+SWFUpload.prototype.getStats = function () {
+ return this.callFlash("GetStats");
+};
+
+// Public: setStats changes the SWFUpload statistics. You shouldn't need to
+// change the statistics but you can. Changing the statistics does not
+// affect SWFUpload accept for the successful_uploads count which is used
+// by the upload_limit setting to determine how many files the user may upload.
+SWFUpload.prototype.setStats = function (statsObject) {
+ this.callFlash("SetStats", [statsObject]);
+};
+
+// Public: getFile retrieves a File object by ID or Index. If the file is
+// not found then 'null' is returned.
+SWFUpload.prototype.getFile = function (fileID) {
+ if (typeof(fileID) === "number") {
+ return this.callFlash("GetFileByIndex", [fileID]);
+ } else {
+ return this.callFlash("GetFile", [fileID]);
+ }
+};
+
+// Public: addFileParam sets a name/value pair that will be posted with the
+// file specified by the Files ID. If the name already exists then the
+// exiting value will be overwritten.
+SWFUpload.prototype.addFileParam = function (fileID, name, value) {
+ return this.callFlash("AddFileParam", [fileID, name, value]);
+};
+
+// Public: removeFileParam removes a previously set (by addFileParam) name/value
+// pair from the specified file.
+SWFUpload.prototype.removeFileParam = function (fileID, name) {
+ this.callFlash("RemoveFileParam", [fileID, name]);
+};
+
+// Public: setUploadUrl changes the upload_url setting.
+SWFUpload.prototype.setUploadURL = function (url) {
+ this.settings.upload_url = url.toString();
+ this.callFlash("SetUploadURL", [url]);
+};
+
+// Public: setPostParams changes the post_params setting
+SWFUpload.prototype.setPostParams = function (paramsObject) {
+ this.settings.post_params = paramsObject;
+ this.callFlash("SetPostParams", [paramsObject]);
+};
+
+// Public: addPostParam adds post name/value pair. Each name can have only one value.
+SWFUpload.prototype.addPostParam = function (name, value) {
+ this.settings.post_params[name] = value;
+ this.callFlash("SetPostParams", [this.settings.post_params]);
+};
+
+// Public: removePostParam deletes post name/value pair.
+SWFUpload.prototype.removePostParam = function (name) {
+ delete this.settings.post_params[name];
+ this.callFlash("SetPostParams", [this.settings.post_params]);
+};
+
+// Public: setFileTypes changes the file_types setting and the file_types_description setting
+SWFUpload.prototype.setFileTypes = function (types, description) {
+ this.settings.file_types = types;
+ this.settings.file_types_description = description;
+ this.callFlash("SetFileTypes", [types, description]);
+};
+
+// Public: setFileSizeLimit changes the file_size_limit setting
+SWFUpload.prototype.setFileSizeLimit = function (fileSizeLimit) {
+ this.settings.file_size_limit = fileSizeLimit;
+ this.callFlash("SetFileSizeLimit", [fileSizeLimit]);
+};
+
+// Public: setFileUploadLimit changes the file_upload_limit setting
+SWFUpload.prototype.setFileUploadLimit = function (fileUploadLimit) {
+ this.settings.file_upload_limit = fileUploadLimit;
+ this.callFlash("SetFileUploadLimit", [fileUploadLimit]);
+};
+
+// Public: setFileQueueLimit changes the file_queue_limit setting
+SWFUpload.prototype.setFileQueueLimit = function (fileQueueLimit) {
+ this.settings.file_queue_limit = fileQueueLimit;
+ this.callFlash("SetFileQueueLimit", [fileQueueLimit]);
+};
+
+// Public: setFilePostName changes the file_post_name setting
+SWFUpload.prototype.setFilePostName = function (filePostName) {
+ this.settings.file_post_name = filePostName;
+ this.callFlash("SetFilePostName", [filePostName]);
+};
+
+// Public: setUseQueryString changes the use_query_string setting
+SWFUpload.prototype.setUseQueryString = function (useQueryString) {
+ this.settings.use_query_string = useQueryString;
+ this.callFlash("SetUseQueryString", [useQueryString]);
+};
+
+// Public: setRequeueOnError changes the requeue_on_error setting
+SWFUpload.prototype.setRequeueOnError = function (requeueOnError) {
+ this.settings.requeue_on_error = requeueOnError;
+ this.callFlash("SetRequeueOnError", [requeueOnError]);
+};
+
+// Public: setHTTPSuccess changes the http_success setting
+SWFUpload.prototype.setHTTPSuccess = function (http_status_codes) {
+ if (typeof http_status_codes === "string") {
+ http_status_codes = http_status_codes.replace(" ", "").split(",");
+ }
+
+ this.settings.http_success = http_status_codes;
+ this.callFlash("SetHTTPSuccess", [http_status_codes]);
+};
+
+// Public: setHTTPSuccess changes the http_success setting
+SWFUpload.prototype.setAssumeSuccessTimeout = function (timeout_seconds) {
+ this.settings.assume_success_timeout = timeout_seconds;
+ this.callFlash("SetAssumeSuccessTimeout", [timeout_seconds]);
+};
+
+// Public: setDebugEnabled changes the debug_enabled setting
+SWFUpload.prototype.setDebugEnabled = function (debugEnabled) {
+ this.settings.debug_enabled = debugEnabled;
+ this.callFlash("SetDebugEnabled", [debugEnabled]);
+};
+
+// Public: setButtonImageURL loads a button image sprite
+SWFUpload.prototype.setButtonImageURL = function (buttonImageURL) {
+ if (buttonImageURL == undefined) {
+ buttonImageURL = "";
+ }
+
+ this.settings.button_image_url = buttonImageURL;
+ this.callFlash("SetButtonImageURL", [buttonImageURL]);
+};
+
+// Public: setButtonDimensions resizes the Flash Movie and button
+SWFUpload.prototype.setButtonDimensions = function (width, height) {
+ this.settings.button_width = width;
+ this.settings.button_height = height;
+
+ var movie = this.getMovieElement();
+ if (movie != undefined) {
+ movie.style.width = width + "px";
+ movie.style.height = height + "px";
+ }
+
+ this.callFlash("SetButtonDimensions", [width, height]);
+};
+// Public: setButtonText Changes the text overlaid on the button
+SWFUpload.prototype.setButtonText = function (html) {
+ this.settings.button_text = html;
+ this.callFlash("SetButtonText", [html]);
+};
+// Public: setButtonTextPadding changes the top and left padding of the text overlay
+SWFUpload.prototype.setButtonTextPadding = function (left, top) {
+ this.settings.button_text_top_padding = top;
+ this.settings.button_text_left_padding = left;
+ this.callFlash("SetButtonTextPadding", [left, top]);
+};
+
+// Public: setButtonTextStyle changes the CSS used to style the HTML/Text overlaid on the button
+SWFUpload.prototype.setButtonTextStyle = function (css) {
+ this.settings.button_text_style = css;
+ this.callFlash("SetButtonTextStyle", [css]);
+};
+// Public: setButtonDisabled disables/enables the button
+SWFUpload.prototype.setButtonDisabled = function (isDisabled) {
+ this.settings.button_disabled = isDisabled;
+ this.callFlash("SetButtonDisabled", [isDisabled]);
+};
+// Public: setButtonAction sets the action that occurs when the button is clicked
+SWFUpload.prototype.setButtonAction = function (buttonAction) {
+ this.settings.button_action = buttonAction;
+ this.callFlash("SetButtonAction", [buttonAction]);
+};
+
+// Public: setButtonCursor changes the mouse cursor displayed when hovering over the button
+SWFUpload.prototype.setButtonCursor = function (cursor) {
+ this.settings.button_cursor = cursor;
+ this.callFlash("SetButtonCursor", [cursor]);
+};
+
+/* *******************************
+ Flash Event Interfaces
+ These functions are used by Flash to trigger the various
+ events.
+
+ All these functions a Private.
+
+ Because the ExternalInterface library is buggy the event calls
+ are added to a queue and the queue then executed by a setTimeout.
+ This ensures that events are executed in a determinate order and that
+ the ExternalInterface bugs are avoided.
+******************************* */
+
+SWFUpload.prototype.queueEvent = function (handlerName, argumentArray) {
+ // Warning: Don't call this.debug inside here or you'll create an infinite loop
+
+ if (argumentArray == undefined) {
+ argumentArray = [];
+ } else if (!(argumentArray instanceof Array)) {
+ argumentArray = [argumentArray];
+ }
+
+ var self = this;
+ if (typeof this.settings[handlerName] === "function") {
+ // Queue the event
+ this.eventQueue.push(function () {
+ this.settings[handlerName].apply(this, argumentArray);
+ });
+
+ // Execute the next queued event
+ setTimeout(function () {
+ self.executeNextEvent();
+ }, 0);
+
+ } else if (this.settings[handlerName] !== null) {
+ throw "Event handler " + handlerName + " is unknown or is not a function";
+ }
+};
+
+// Private: Causes the next event in the queue to be executed. Since events are queued using a setTimeout
+// we must queue them in order to garentee that they are executed in order.
+SWFUpload.prototype.executeNextEvent = function () {
+ // Warning: Don't call this.debug inside here or you'll create an infinite loop
+
+ var f = this.eventQueue ? this.eventQueue.shift() : null;
+ if (typeof(f) === "function") {
+ f.apply(this);
+ }
+};
+
+// Private: unescapeFileParams is part of a workaround for a flash bug where objects passed through ExternalInterface cannot have
+// properties that contain characters that are not valid for JavaScript identifiers. To work around this
+// the Flash Component escapes the parameter names and we must unescape again before passing them along.
+SWFUpload.prototype.unescapeFilePostParams = function (file) {
+ var reg = /[$]([0-9a-f]{4})/i;
+ var unescapedPost = {};
+ var uk;
+
+ if (file != undefined) {
+ for (var k in file.post) {
+ if (file.post.hasOwnProperty(k)) {
+ uk = k;
+ var match;
+ while ((match = reg.exec(uk)) !== null) {
+ uk = uk.replace(match[0], String.fromCharCode(parseInt("0x" + match[1], 16)));
+ }
+ unescapedPost[uk] = file.post[k];
+ }
+ }
+
+ file.post = unescapedPost;
+ }
+
+ return file;
+};
+
+// Private: Called by Flash to see if JS can call in to Flash (test if External Interface is working)
+SWFUpload.prototype.testExternalInterface = function () {
+ try {
+ return this.callFlash("TestExternalInterface");
+ } catch (ex) {
+ return false;
+ }
+};
+
+// Private: This event is called by Flash when it has finished loading. Don't modify this.
+// Use the swfupload_loaded_handler event setting to execute custom code when SWFUpload has loaded.
+SWFUpload.prototype.flashReady = function () {
+ // Check that the movie element is loaded correctly with its ExternalInterface methods defined
+ var movieElement = this.getMovieElement();
+
+ if (!movieElement) {
+ this.debug("Flash called back ready but the flash movie can't be found.");
+ return;
+ }
+
+ this.cleanUp(movieElement);
+
+ this.queueEvent("swfupload_loaded_handler");
+};
+
+// Private: removes Flash added fuctions to the DOM node to prevent memory leaks in IE.
+// This function is called by Flash each time the ExternalInterface functions are created.
+SWFUpload.prototype.cleanUp = function (movieElement) {
+ // Pro-actively unhook all the Flash functions
+ try {
+ if (this.movieElement && typeof(movieElement.CallFunction) === "unknown") { // We only want to do this in IE
+ this.debug("Removing Flash functions hooks (this should only run in IE and should prevent memory leaks)");
+ for (var key in movieElement) {
+ try {
+ if (typeof(movieElement[key]) === "function") {
+ movieElement[key] = null;
+ }
+ } catch (ex) {
+ }
+ }
+ }
+ } catch (ex1) {
+
+ }
+
+ // Fix Flashes own cleanup code so if the SWFMovie was removed from the page
+ // it doesn't display errors.
+ window["__flash__removeCallback"] = function (instance, name) {
+ try {
+ if (instance) {
+ instance[name] = null;
+ }
+ } catch (flashEx) {
+
+ }
+ };
+
+};
+
+
+/* This is a chance to do something before the browse window opens */
+SWFUpload.prototype.fileDialogStart = function () {
+ this.queueEvent("file_dialog_start_handler");
+};
+
+
+/* Called when a file is successfully added to the queue. */
+SWFUpload.prototype.fileQueued = function (file) {
+ file = this.unescapeFilePostParams(file);
+ this.queueEvent("file_queued_handler", file);
+};
+
+
+/* Handle errors that occur when an attempt to queue a file fails. */
+SWFUpload.prototype.fileQueueError = function (file, errorCode, message) {
+ file = this.unescapeFilePostParams(file);
+ this.queueEvent("file_queue_error_handler", [file, errorCode, message]);
+};
+
+/* Called after the file dialog has closed and the selected files have been queued.
+ You could call startUpload here if you want the queued files to begin uploading immediately. */
+SWFUpload.prototype.fileDialogComplete = function (numFilesSelected, numFilesQueued, numFilesInQueue) {
+ this.queueEvent("file_dialog_complete_handler", [numFilesSelected, numFilesQueued, numFilesInQueue]);
+};
+
+SWFUpload.prototype.uploadStart = function (file) {
+ file = this.unescapeFilePostParams(file);
+ this.queueEvent("return_upload_start_handler", file);
+};
+
+SWFUpload.prototype.returnUploadStart = function (file) {
+ var returnValue;
+ if (typeof this.settings.upload_start_handler === "function") {
+ file = this.unescapeFilePostParams(file);
+ returnValue = this.settings.upload_start_handler.call(this, file);
+ } else if (this.settings.upload_start_handler != undefined) {
+ throw "upload_start_handler must be a function";
+ }
+
+ // Convert undefined to true so if nothing is returned from the upload_start_handler it is
+ // interpretted as 'true'.
+ if (returnValue === undefined) {
+ returnValue = true;
+ }
+
+ returnValue = !!returnValue;
+
+ this.callFlash("ReturnUploadStart", [returnValue]);
+};
+
+
+
+SWFUpload.prototype.uploadProgress = function (file, bytesComplete, bytesTotal) {
+ file = this.unescapeFilePostParams(file);
+ this.queueEvent("upload_progress_handler", [file, bytesComplete, bytesTotal]);
+};
+
+SWFUpload.prototype.uploadError = function (file, errorCode, message) {
+ file = this.unescapeFilePostParams(file);
+ this.queueEvent("upload_error_handler", [file, errorCode, message]);
+};
+
+SWFUpload.prototype.uploadSuccess = function (file, serverData, responseReceived) {
+ file = this.unescapeFilePostParams(file);
+ this.queueEvent("upload_success_handler", [file, serverData, responseReceived]);
+};
+
+SWFUpload.prototype.uploadComplete = function (file) {
+ file = this.unescapeFilePostParams(file);
+ this.queueEvent("upload_complete_handler", file);
+};
+
+/* Called by SWFUpload JavaScript and Flash functions when debug is enabled. By default it writes messages to the
+ internal debug console. You can override this event and have messages written where you want. */
+SWFUpload.prototype.debug = function (message) {
+ this.queueEvent("debug_handler", message);
+};
+
+
+/* **********************************
+ Debug Console
+ The debug console is a self contained, in page location
+ for debug message to be sent. The Debug Console adds
+ itself to the body if necessary.
+
+ The console is automatically scrolled as messages appear.
+
+ If you are using your own debug handler or when you deploy to production and
+ have debug disabled you can remove these functions to reduce the file size
+ and complexity.
+********************************** */
+
+// Private: debugMessage is the default debug_handler. If you want to print debug messages
+// call the debug() function. When overriding the function your own function should
+// check to see if the debug setting is true before outputting debug information.
+SWFUpload.prototype.debugMessage = function (message) {
+ if (this.settings.debug) {
+ var exceptionMessage, exceptionValues = [];
+
+ // Check for an exception object and print it nicely
+ if (typeof message === "object" && typeof message.name === "string" && typeof message.message === "string") {
+ for (var key in message) {
+ if (message.hasOwnProperty(key)) {
+ exceptionValues.push(key + ": " + message[key]);
+ }
+ }
+ exceptionMessage = exceptionValues.join("\n") || "";
+ exceptionValues = exceptionMessage.split("\n");
+ exceptionMessage = "EXCEPTION: " + exceptionValues.join("\nEXCEPTION: ");
+ SWFUpload.Console.writeLine(exceptionMessage);
+ } else {
+ SWFUpload.Console.writeLine(message);
+ }
+ }
+};
+
+SWFUpload.Console = {};
+SWFUpload.Console.writeLine = function (message) {
+ var console, documentForm;
+
+ try {
+ console = document.getElementById("SWFUpload_Console");
+
+ if (!console) {
+ documentForm = document.createElement("form");
+ document.getElementsByTagName("body")[0].appendChild(documentForm);
+
+ console = document.createElement("textarea");
+ console.id = "SWFUpload_Console";
+ console.style.fontFamily = "monospace";
+ console.setAttribute("wrap", "off");
+ console.wrap = "off";
+ console.style.overflow = "auto";
+ console.style.width = "700px";
+ console.style.height = "350px";
+ console.style.margin = "5px";
+ documentForm.appendChild(console);
+ }
+
+ console.value += message + "\n";
+
+ console.scrollTop = console.scrollHeight - console.clientHeight;
+ } catch (ex) {
+ alert("Exception: " + ex.name + " Message: " + ex.message);
+ }
+};
diff --git a/debian/missing-sources/tinymce-4.3.10.tar.gz b/debian/missing-sources/tinymce-4.3.10.tar.gz
new file mode 100644
index 0000000..cc2e64a
--- /dev/null
+++ b/debian/missing-sources/tinymce-4.3.10.tar.gz
Binary files differ
diff --git a/debian/missing-sources/underscore.js b/debian/missing-sources/underscore.js
new file mode 100644
index 0000000..a12f0d9
--- /dev/null
+++ b/debian/missing-sources/underscore.js
@@ -0,0 +1,1226 @@
+// Underscore.js 1.4.4
+// http://underscorejs.org
+// (c) 2009-2013 Jeremy Ashkenas, DocumentCloud Inc.
+// Underscore may be freely distributed under the MIT license.
+
+(function() {
+
+ // Baseline setup
+ // --------------
+
+ // Establish the root object, `window` in the browser, or `global` on the server.
+ var root = this;
+
+ // Save the previous value of the `_` variable.
+ var previousUnderscore = root._;
+
+ // Establish the object that gets returned to break out of a loop iteration.
+ var breaker = {};
+
+ // Save bytes in the minified (but not gzipped) version:
+ var ArrayProto = Array.prototype, ObjProto = Object.prototype, FuncProto = Function.prototype;
+
+ // Create quick reference variables for speed access to core prototypes.
+ var push = ArrayProto.push,
+ slice = ArrayProto.slice,
+ concat = ArrayProto.concat,
+ toString = ObjProto.toString,
+ hasOwnProperty = ObjProto.hasOwnProperty;
+
+ // All **ECMAScript 5** native function implementations that we hope to use
+ // are declared here.
+ var
+ nativeForEach = ArrayProto.forEach,
+ nativeMap = ArrayProto.map,
+ nativeReduce = ArrayProto.reduce,
+ nativeReduceRight = ArrayProto.reduceRight,
+ nativeFilter = ArrayProto.filter,
+ nativeEvery = ArrayProto.every,
+ nativeSome = ArrayProto.some,
+ nativeIndexOf = ArrayProto.indexOf,
+ nativeLastIndexOf = ArrayProto.lastIndexOf,
+ nativeIsArray = Array.isArray,
+ nativeKeys = Object.keys,
+ nativeBind = FuncProto.bind;
+
+ // Create a safe reference to the Underscore object for use below.
+ var _ = function(obj) {
+ if (obj instanceof _) return obj;
+ if (!(this instanceof _)) return new _(obj);
+ this._wrapped = obj;
+ };
+
+ // Export the Underscore object for **Node.js**, with
+ // backwards-compatibility for the old `require()` API. If we're in
+ // the browser, add `_` as a global object via a string identifier,
+ // for Closure Compiler "advanced" mode.
+ if (typeof exports !== 'undefined') {
+ if (typeof module !== 'undefined' && module.exports) {
+ exports = module.exports = _;
+ }
+ exports._ = _;
+ } else {
+ root._ = _;
+ }
+
+ // Current version.
+ _.VERSION = '1.4.4';
+
+ // Collection Functions
+ // --------------------
+
+ // The cornerstone, an `each` implementation, aka `forEach`.
+ // Handles objects with the built-in `forEach`, arrays, and raw objects.
+ // Delegates to **ECMAScript 5**'s native `forEach` if available.
+ var each = _.each = _.forEach = function(obj, iterator, context) {
+ if (obj == null) return;
+ if (nativeForEach && obj.forEach === nativeForEach) {
+ obj.forEach(iterator, context);
+ } else if (obj.length === +obj.length) {
+ for (var i = 0, l = obj.length; i < l; i++) {
+ if (iterator.call(context, obj[i], i, obj) === breaker) return;
+ }
+ } else {
+ for (var key in obj) {
+ if (_.has(obj, key)) {
+ if (iterator.call(context, obj[key], key, obj) === breaker) return;
+ }
+ }
+ }
+ };
+
+ // Return the results of applying the iterator to each element.
+ // Delegates to **ECMAScript 5**'s native `map` if available.
+ _.map = _.collect = function(obj, iterator, context) {
+ var results = [];
+ if (obj == null) return results;
+ if (nativeMap && obj.map === nativeMap) return obj.map(iterator, context);
+ each(obj, function(value, index, list) {
+ results[results.length] = iterator.call(context, value, index, list);
+ });
+ return results;
+ };
+
+ var reduceError = 'Reduce of empty array with no initial value';
+
+ // **Reduce** builds up a single result from a list of values, aka `inject`,
+ // or `foldl`. Delegates to **ECMAScript 5**'s native `reduce` if available.
+ _.reduce = _.foldl = _.inject = function(obj, iterator, memo, context) {
+ var initial = arguments.length > 2;
+ if (obj == null) obj = [];
+ if (nativeReduce && obj.reduce === nativeReduce) {
+ if (context) iterator = _.bind(iterator, context);
+ return initial ? obj.reduce(iterator, memo) : obj.reduce(iterator);
+ }
+ each(obj, function(value, index, list) {
+ if (!initial) {
+ memo = value;
+ initial = true;
+ } else {
+ memo = iterator.call(context, memo, value, index, list);
+ }
+ });
+ if (!initial) throw new TypeError(reduceError);
+ return memo;
+ };
+
+ // The right-associative version of reduce, also known as `foldr`.
+ // Delegates to **ECMAScript 5**'s native `reduceRight` if available.
+ _.reduceRight = _.foldr = function(obj, iterator, memo, context) {
+ var initial = arguments.length > 2;
+ if (obj == null) obj = [];
+ if (nativeReduceRight && obj.reduceRight === nativeReduceRight) {
+ if (context) iterator = _.bind(iterator, context);
+ return initial ? obj.reduceRight(iterator, memo) : obj.reduceRight(iterator);
+ }
+ var length = obj.length;
+ if (length !== +length) {
+ var keys = _.keys(obj);
+ length = keys.length;
+ }
+ each(obj, function(value, index, list) {
+ index = keys ? keys[--length] : --length;
+ if (!initial) {
+ memo = obj[index];
+ initial = true;
+ } else {
+ memo = iterator.call(context, memo, obj[index], index, list);
+ }
+ });
+ if (!initial) throw new TypeError(reduceError);
+ return memo;
+ };
+
+ // Return the first value which passes a truth test. Aliased as `detect`.
+ _.find = _.detect = function(obj, iterator, context) {
+ var result;
+ any(obj, function(value, index, list) {
+ if (iterator.call(context, value, index, list)) {
+ result = value;
+ return true;
+ }
+ });
+ return result;
+ };
+
+ // Return all the elements that pass a truth test.
+ // Delegates to **ECMAScript 5**'s native `filter` if available.
+ // Aliased as `select`.
+ _.filter = _.select = function(obj, iterator, context) {
+ var results = [];
+ if (obj == null) return results;
+ if (nativeFilter && obj.filter === nativeFilter) return obj.filter(iterator, context);
+ each(obj, function(value, index, list) {
+ if (iterator.call(context, value, index, list)) results[results.length] = value;
+ });
+ return results;
+ };
+
+ // Return all the elements for which a truth test fails.
+ _.reject = function(obj, iterator, context) {
+ return _.filter(obj, function(value, index, list) {
+ return !iterator.call(context, value, index, list);
+ }, context);
+ };
+
+ // Determine whether all of the elements match a truth test.
+ // Delegates to **ECMAScript 5**'s native `every` if available.
+ // Aliased as `all`.
+ _.every = _.all = function(obj, iterator, context) {
+ iterator || (iterator = _.identity);
+ var result = true;
+ if (obj == null) return result;
+ if (nativeEvery && obj.every === nativeEvery) return obj.every(iterator, context);
+ each(obj, function(value, index, list) {
+ if (!(result = result && iterator.call(context, value, index, list))) return breaker;
+ });
+ return !!result;
+ };
+
+ // Determine if at least one element in the object matches a truth test.
+ // Delegates to **ECMAScript 5**'s native `some` if available.
+ // Aliased as `any`.
+ var any = _.some = _.any = function(obj, iterator, context) {
+ iterator || (iterator = _.identity);
+ var result = false;
+ if (obj == null) return result;
+ if (nativeSome && obj.some === nativeSome) return obj.some(iterator, context);
+ each(obj, function(value, index, list) {
+ if (result || (result = iterator.call(context, value, index, list))) return breaker;
+ });
+ return !!result;
+ };
+
+ // Determine if the array or object contains a given value (using `===`).
+ // Aliased as `include`.
+ _.contains = _.include = function(obj, target) {
+ if (obj == null) return false;
+ if (nativeIndexOf && obj.indexOf === nativeIndexOf) return obj.indexOf(target) != -1;
+ return any(obj, function(value) {
+ return value === target;
+ });
+ };
+
+ // Invoke a method (with arguments) on every item in a collection.
+ _.invoke = function(obj, method) {
+ var args = slice.call(arguments, 2);
+ var isFunc = _.isFunction(method);
+ return _.map(obj, function(value) {
+ return (isFunc ? method : value[method]).apply(value, args);
+ });
+ };
+
+ // Convenience version of a common use case of `map`: fetching a property.
+ _.pluck = function(obj, key) {
+ return _.map(obj, function(value){ return value[key]; });
+ };
+
+ // Convenience version of a common use case of `filter`: selecting only objects
+ // containing specific `key:value` pairs.
+ _.where = function(obj, attrs, first) {
+ if (_.isEmpty(attrs)) return first ? null : [];
+ return _[first ? 'find' : 'filter'](obj, function(value) {
+ for (var key in attrs) {
+ if (attrs[key] !== value[key]) return false;
+ }
+ return true;
+ });
+ };
+
+ // Convenience version of a common use case of `find`: getting the first object
+ // containing specific `key:value` pairs.
+ _.findWhere = function(obj, attrs) {
+ return _.where(obj, attrs, true);
+ };
+
+ // Return the maximum element or (element-based computation).
+ // Can't optimize arrays of integers longer than 65,535 elements.
+ // See: https://bugs.webkit.org/show_bug.cgi?id=80797
+ _.max = function(obj, iterator, context) {
+ if (!iterator && _.isArray(obj) && obj[0] === +obj[0] && obj.length < 65535) {
+ return Math.max.apply(Math, obj);
+ }
+ if (!iterator && _.isEmpty(obj)) return -Infinity;
+ var result = {computed : -Infinity, value: -Infinity};
+ each(obj, function(value, index, list) {
+ var computed = iterator ? iterator.call(context, value, index, list) : value;
+ computed >= result.computed && (result = {value : value, computed : computed});
+ });
+ return result.value;
+ };
+
+ // Return the minimum element (or element-based computation).
+ _.min = function(obj, iterator, context) {
+ if (!iterator && _.isArray(obj) && obj[0] === +obj[0] && obj.length < 65535) {
+ return Math.min.apply(Math, obj);
+ }
+ if (!iterator && _.isEmpty(obj)) return Infinity;
+ var result = {computed : Infinity, value: Infinity};
+ each(obj, function(value, index, list) {
+ var computed = iterator ? iterator.call(context, value, index, list) : value;
+ computed < result.computed && (result = {value : value, computed : computed});
+ });
+ return result.value;
+ };
+
+ // Shuffle an array.
+ _.shuffle = function(obj) {
+ var rand;
+ var index = 0;
+ var shuffled = [];
+ each(obj, function(value) {
+ rand = _.random(index++);
+ shuffled[index - 1] = shuffled[rand];
+ shuffled[rand] = value;
+ });
+ return shuffled;
+ };
+
+ // An internal function to generate lookup iterators.
+ var lookupIterator = function(value) {
+ return _.isFunction(value) ? value : function(obj){ return obj[value]; };
+ };
+
+ // Sort the object's values by a criterion produced by an iterator.
+ _.sortBy = function(obj, value, context) {
+ var iterator = lookupIterator(value);
+ return _.pluck(_.map(obj, function(value, index, list) {
+ return {
+ value : value,
+ index : index,
+ criteria : iterator.call(context, value, index, list)
+ };
+ }).sort(function(left, right) {
+ var a = left.criteria;
+ var b = right.criteria;
+ if (a !== b) {
+ if (a > b || a === void 0) return 1;
+ if (a < b || b === void 0) return -1;
+ }
+ return left.index < right.index ? -1 : 1;
+ }), 'value');
+ };
+
+ // An internal function used for aggregate "group by" operations.
+ var group = function(obj, value, context, behavior) {
+ var result = {};
+ var iterator = lookupIterator(value || _.identity);
+ each(obj, function(value, index) {
+ var key = iterator.call(context, value, index, obj);
+ behavior(result, key, value);
+ });
+ return result;
+ };
+
+ // Groups the object's values by a criterion. Pass either a string attribute
+ // to group by, or a function that returns the criterion.
+ _.groupBy = function(obj, value, context) {
+ return group(obj, value, context, function(result, key, value) {
+ (_.has(result, key) ? result[key] : (result[key] = [])).push(value);
+ });
+ };
+
+ // Counts instances of an object that group by a certain criterion. Pass
+ // either a string attribute to count by, or a function that returns the
+ // criterion.
+ _.countBy = function(obj, value, context) {
+ return group(obj, value, context, function(result, key) {
+ if (!_.has(result, key)) result[key] = 0;
+ result[key]++;
+ });
+ };
+
+ // Use a comparator function to figure out the smallest index at which
+ // an object should be inserted so as to maintain order. Uses binary search.
+ _.sortedIndex = function(array, obj, iterator, context) {
+ iterator = iterator == null ? _.identity : lookupIterator(iterator);
+ var value = iterator.call(context, obj);
+ var low = 0, high = array.length;
+ while (low < high) {
+ var mid = (low + high) >>> 1;
+ iterator.call(context, array[mid]) < value ? low = mid + 1 : high = mid;
+ }
+ return low;
+ };
+
+ // Safely convert anything iterable into a real, live array.
+ _.toArray = function(obj) {
+ if (!obj) return [];
+ if (_.isArray(obj)) return slice.call(obj);
+ if (obj.length === +obj.length) return _.map(obj, _.identity);
+ return _.values(obj);
+ };
+
+ // Return the number of elements in an object.
+ _.size = function(obj) {
+ if (obj == null) return 0;
+ return (obj.length === +obj.length) ? obj.length : _.keys(obj).length;
+ };
+
+ // Array Functions
+ // ---------------
+
+ // Get the first element of an array. Passing **n** will return the first N
+ // values in the array. Aliased as `head` and `take`. The **guard** check
+ // allows it to work with `_.map`.
+ _.first = _.head = _.take = function(array, n, guard) {
+ if (array == null) return void 0;
+ return (n != null) && !guard ? slice.call(array, 0, n) : array[0];
+ };
+
+ // Returns everything but the last entry of the array. Especially useful on
+ // the arguments object. Passing **n** will return all the values in
+ // the array, excluding the last N. The **guard** check allows it to work with
+ // `_.map`.
+ _.initial = function(array, n, guard) {
+ return slice.call(array, 0, array.length - ((n == null) || guard ? 1 : n));
+ };
+
+ // Get the last element of an array. Passing **n** will return the last N
+ // values in the array. The **guard** check allows it to work with `_.map`.
+ _.last = function(array, n, guard) {
+ if (array == null) return void 0;
+ if ((n != null) && !guard) {
+ return slice.call(array, Math.max(array.length - n, 0));
+ } else {
+ return array[array.length - 1];
+ }
+ };
+
+ // Returns everything but the first entry of the array. Aliased as `tail` and `drop`.
+ // Especially useful on the arguments object. Passing an **n** will return
+ // the rest N values in the array. The **guard**
+ // check allows it to work with `_.map`.
+ _.rest = _.tail = _.drop = function(array, n, guard) {
+ return slice.call(array, (n == null) || guard ? 1 : n);
+ };
+
+ // Trim out all falsy values from an array.
+ _.compact = function(array) {
+ return _.filter(array, _.identity);
+ };
+
+ // Internal implementation of a recursive `flatten` function.
+ var flatten = function(input, shallow, output) {
+ each(input, function(value) {
+ if (_.isArray(value)) {
+ shallow ? push.apply(output, value) : flatten(value, shallow, output);
+ } else {
+ output.push(value);
+ }
+ });
+ return output;
+ };
+
+ // Return a completely flattened version of an array.
+ _.flatten = function(array, shallow) {
+ return flatten(array, shallow, []);
+ };
+
+ // Return a version of the array that does not contain the specified value(s).
+ _.without = function(array) {
+ return _.difference(array, slice.call(arguments, 1));
+ };
+
+ // Produce a duplicate-free version of the array. If the array has already
+ // been sorted, you have the option of using a faster algorithm.
+ // Aliased as `unique`.
+ _.uniq = _.unique = function(array, isSorted, iterator, context) {
+ if (_.isFunction(isSorted)) {
+ context = iterator;
+ iterator = isSorted;
+ isSorted = false;
+ }
+ var initial = iterator ? _.map(array, iterator, context) : array;
+ var results = [];
+ var seen = [];
+ each(initial, function(value, index) {
+ if (isSorted ? (!index || seen[seen.length - 1] !== value) : !_.contains(seen, value)) {
+ seen.push(value);
+ results.push(array[index]);
+ }
+ });
+ return results;
+ };
+
+ // Produce an array that contains the union: each distinct element from all of
+ // the passed-in arrays.
+ _.union = function() {
+ return _.uniq(concat.apply(ArrayProto, arguments));
+ };
+
+ // Produce an array that contains every item shared between all the
+ // passed-in arrays.
+ _.intersection = function(array) {
+ var rest = slice.call(arguments, 1);
+ return _.filter(_.uniq(array), function(item) {
+ return _.every(rest, function(other) {
+ return _.indexOf(other, item) >= 0;
+ });
+ });
+ };
+
+ // Take the difference between one array and a number of other arrays.
+ // Only the elements present in just the first array will remain.
+ _.difference = function(array) {
+ var rest = concat.apply(ArrayProto, slice.call(arguments, 1));
+ return _.filter(array, function(value){ return !_.contains(rest, value); });
+ };
+
+ // Zip together multiple lists into a single array -- elements that share
+ // an index go together.
+ _.zip = function() {
+ var args = slice.call(arguments);
+ var length = _.max(_.pluck(args, 'length'));
+ var results = new Array(length);
+ for (var i = 0; i < length; i++) {
+ results[i] = _.pluck(args, "" + i);
+ }
+ return results;
+ };
+
+ // Converts lists into objects. Pass either a single array of `[key, value]`
+ // pairs, or two parallel arrays of the same length -- one of keys, and one of
+ // the corresponding values.
+ _.object = function(list, values) {
+ if (list == null) return {};
+ var result = {};
+ for (var i = 0, l = list.length; i < l; i++) {
+ if (values) {
+ result[list[i]] = values[i];
+ } else {
+ result[list[i][0]] = list[i][1];
+ }
+ }
+ return result;
+ };
+
+ // If the browser doesn't supply us with indexOf (I'm looking at you, **MSIE**),
+ // we need this function. Return the position of the first occurrence of an
+ // item in an array, or -1 if the item is not included in the array.
+ // Delegates to **ECMAScript 5**'s native `indexOf` if available.
+ // If the array is large and already in sort order, pass `true`
+ // for **isSorted** to use binary search.
+ _.indexOf = function(array, item, isSorted) {
+ if (array == null) return -1;
+ var i = 0, l = array.length;
+ if (isSorted) {
+ if (typeof isSorted == 'number') {
+ i = (isSorted < 0 ? Math.max(0, l + isSorted) : isSorted);
+ } else {
+ i = _.sortedIndex(array, item);
+ return array[i] === item ? i : -1;
+ }
+ }
+ if (nativeIndexOf && array.indexOf === nativeIndexOf) return array.indexOf(item, isSorted);
+ for (; i < l; i++) if (array[i] === item) return i;
+ return -1;
+ };
+
+ // Delegates to **ECMAScript 5**'s native `lastIndexOf` if available.
+ _.lastIndexOf = function(array, item, from) {
+ if (array == null) return -1;
+ var hasIndex = from != null;
+ if (nativeLastIndexOf && array.lastIndexOf === nativeLastIndexOf) {
+ return hasIndex ? array.lastIndexOf(item, from) : array.lastIndexOf(item);
+ }
+ var i = (hasIndex ? from : array.length);
+ while (i--) if (array[i] === item) return i;
+ return -1;
+ };
+
+ // Generate an integer Array containing an arithmetic progression. A port of
+ // the native Python `range()` function. See
+ // [the Python documentation](http://docs.python.org/library/functions.html#range).
+ _.range = function(start, stop, step) {
+ if (arguments.length <= 1) {
+ stop = start || 0;
+ start = 0;
+ }
+ step = arguments[2] || 1;
+
+ var len = Math.max(Math.ceil((stop - start) / step), 0);
+ var idx = 0;
+ var range = new Array(len);
+
+ while(idx < len) {
+ range[idx++] = start;
+ start += step;
+ }
+
+ return range;
+ };
+
+ // Function (ahem) Functions
+ // ------------------
+
+ // Create a function bound to a given object (assigning `this`, and arguments,
+ // optionally). Delegates to **ECMAScript 5**'s native `Function.bind` if
+ // available.
+ _.bind = function(func, context) {
+ if (func.bind === nativeBind && nativeBind) return nativeBind.apply(func, slice.call(arguments, 1));
+ var args = slice.call(arguments, 2);
+ return function() {
+ return func.apply(context, args.concat(slice.call(arguments)));
+ };
+ };
+
+ // Partially apply a function by creating a version that has had some of its
+ // arguments pre-filled, without changing its dynamic `this` context.
+ _.partial = function(func) {
+ var args = slice.call(arguments, 1);
+ return function() {
+ return func.apply(this, args.concat(slice.call(arguments)));
+ };
+ };
+
+ // Bind all of an object's methods to that object. Useful for ensuring that
+ // all callbacks defined on an object belong to it.
+ _.bindAll = function(obj) {
+ var funcs = slice.call(arguments, 1);
+ if (funcs.length === 0) funcs = _.functions(obj);
+ each(funcs, function(f) { obj[f] = _.bind(obj[f], obj); });
+ return obj;
+ };
+
+ // Memoize an expensive function by storing its results.
+ _.memoize = function(func, hasher) {
+ var memo = {};
+ hasher || (hasher = _.identity);
+ return function() {
+ var key = hasher.apply(this, arguments);
+ return _.has(memo, key) ? memo[key] : (memo[key] = func.apply(this, arguments));
+ };
+ };
+
+ // Delays a function for the given number of milliseconds, and then calls
+ // it with the arguments supplied.
+ _.delay = function(func, wait) {
+ var args = slice.call(arguments, 2);
+ return setTimeout(function(){ return func.apply(null, args); }, wait);
+ };
+
+ // Defers a function, scheduling it to run after the current call stack has
+ // cleared.
+ _.defer = function(func) {
+ return _.delay.apply(_, [func, 1].concat(slice.call(arguments, 1)));
+ };
+
+ // Returns a function, that, when invoked, will only be triggered at most once
+ // during a given window of time.
+ _.throttle = function(func, wait) {
+ var context, args, timeout, result;
+ var previous = 0;
+ var later = function() {
+ previous = new Date;
+ timeout = null;
+ result = func.apply(context, args);
+ };
+ return function() {
+ var now = new Date;
+ var remaining = wait - (now - previous);
+ context = this;
+ args = arguments;
+ if (remaining <= 0) {
+ clearTimeout(timeout);
+ timeout = null;
+ previous = now;
+ result = func.apply(context, args);
+ } else if (!timeout) {
+ timeout = setTimeout(later, remaining);
+ }
+ return result;
+ };
+ };
+
+ // Returns a function, that, as long as it continues to be invoked, will not
+ // be triggered. The function will be called after it stops being called for
+ // N milliseconds. If `immediate` is passed, trigger the function on the
+ // leading edge, instead of the trailing.
+ _.debounce = function(func, wait, immediate) {
+ var timeout, result;
+ return function() {
+ var context = this, args = arguments;
+ var later = function() {
+ timeout = null;
+ if (!immediate) result = func.apply(context, args);
+ };
+ var callNow = immediate && !timeout;
+ clearTimeout(timeout);
+ timeout = setTimeout(later, wait);
+ if (callNow) result = func.apply(context, args);
+ return result;
+ };
+ };
+
+ // Returns a function that will be executed at most one time, no matter how
+ // often you call it. Useful for lazy initialization.
+ _.once = function(func) {
+ var ran = false, memo;
+ return function() {
+ if (ran) return memo;
+ ran = true;
+ memo = func.apply(this, arguments);
+ func = null;
+ return memo;
+ };
+ };
+
+ // Returns the first function passed as an argument to the second,
+ // allowing you to adjust arguments, run code before and after, and
+ // conditionally execute the original function.
+ _.wrap = function(func, wrapper) {
+ return function() {
+ var args = [func];
+ push.apply(args, arguments);
+ return wrapper.apply(this, args);
+ };
+ };
+
+ // Returns a function that is the composition of a list of functions, each
+ // consuming the return value of the function that follows.
+ _.compose = function() {
+ var funcs = arguments;
+ return function() {
+ var args = arguments;
+ for (var i = funcs.length - 1; i >= 0; i--) {
+ args = [funcs[i].apply(this, args)];
+ }
+ return args[0];
+ };
+ };
+
+ // Returns a function that will only be executed after being called N times.
+ _.after = function(times, func) {
+ if (times <= 0) return func();
+ return function() {
+ if (--times < 1) {
+ return func.apply(this, arguments);
+ }
+ };
+ };
+
+ // Object Functions
+ // ----------------
+
+ // Retrieve the names of an object's properties.
+ // Delegates to **ECMAScript 5**'s native `Object.keys`
+ _.keys = nativeKeys || function(obj) {
+ if (obj !== Object(obj)) throw new TypeError('Invalid object');
+ var keys = [];
+ for (var key in obj) if (_.has(obj, key)) keys[keys.length] = key;
+ return keys;
+ };
+
+ // Retrieve the values of an object's properties.
+ _.values = function(obj) {
+ var values = [];
+ for (var key in obj) if (_.has(obj, key)) values.push(obj[key]);
+ return values;
+ };
+
+ // Convert an object into a list of `[key, value]` pairs.
+ _.pairs = function(obj) {
+ var pairs = [];
+ for (var key in obj) if (_.has(obj, key)) pairs.push([key, obj[key]]);
+ return pairs;
+ };
+
+ // Invert the keys and values of an object. The values must be serializable.
+ _.invert = function(obj) {
+ var result = {};
+ for (var key in obj) if (_.has(obj, key)) result[obj[key]] = key;
+ return result;
+ };
+
+ // Return a sorted list of the function names available on the object.
+ // Aliased as `methods`
+ _.functions = _.methods = function(obj) {
+ var names = [];
+ for (var key in obj) {
+ if (_.isFunction(obj[key])) names.push(key);
+ }
+ return names.sort();
+ };
+
+ // Extend a given object with all the properties in passed-in object(s).
+ _.extend = function(obj) {
+ each(slice.call(arguments, 1), function(source) {
+ if (source) {
+ for (var prop in source) {
+ obj[prop] = source[prop];
+ }
+ }
+ });
+ return obj;
+ };
+
+ // Return a copy of the object only containing the whitelisted properties.
+ _.pick = function(obj) {
+ var copy = {};
+ var keys = concat.apply(ArrayProto, slice.call(arguments, 1));
+ each(keys, function(key) {
+ if (key in obj) copy[key] = obj[key];
+ });
+ return copy;
+ };
+
+ // Return a copy of the object without the blacklisted properties.
+ _.omit = function(obj) {
+ var copy = {};
+ var keys = concat.apply(ArrayProto, slice.call(arguments, 1));
+ for (var key in obj) {
+ if (!_.contains(keys, key)) copy[key] = obj[key];
+ }
+ return copy;
+ };
+
+ // Fill in a given object with default properties.
+ _.defaults = function(obj) {
+ each(slice.call(arguments, 1), function(source) {
+ if (source) {
+ for (var prop in source) {
+ if (obj[prop] == null) obj[prop] = source[prop];
+ }
+ }
+ });
+ return obj;
+ };
+
+ // Create a (shallow-cloned) duplicate of an object.
+ _.clone = function(obj) {
+ if (!_.isObject(obj)) return obj;
+ return _.isArray(obj) ? obj.slice() : _.extend({}, obj);
+ };
+
+ // Invokes interceptor with the obj, and then returns obj.
+ // The primary purpose of this method is to "tap into" a method chain, in
+ // order to perform operations on intermediate results within the chain.
+ _.tap = function(obj, interceptor) {
+ interceptor(obj);
+ return obj;
+ };
+
+ // Internal recursive comparison function for `isEqual`.
+ var eq = function(a, b, aStack, bStack) {
+ // Identical objects are equal. `0 === -0`, but they aren't identical.
+ // See the Harmony `egal` proposal: http://wiki.ecmascript.org/doku.php?id=harmony:egal.
+ if (a === b) return a !== 0 || 1 / a == 1 / b;
+ // A strict comparison is necessary because `null == undefined`.
+ if (a == null || b == null) return a === b;
+ // Unwrap any wrapped objects.
+ if (a instanceof _) a = a._wrapped;
+ if (b instanceof _) b = b._wrapped;
+ // Compare `[[Class]]` names.
+ var className = toString.call(a);
+ if (className != toString.call(b)) return false;
+ switch (className) {
+ // Strings, numbers, dates, and booleans are compared by value.
+ case '[object String]':
+ // Primitives and their corresponding object wrappers are equivalent; thus, `"5"` is
+ // equivalent to `new String("5")`.
+ return a == String(b);
+ case '[object Number]':
+ // `NaN`s are equivalent, but non-reflexive. An `egal` comparison is performed for
+ // other numeric values.
+ return a != +a ? b != +b : (a == 0 ? 1 / a == 1 / b : a == +b);
+ case '[object Date]':
+ case '[object Boolean]':
+ // Coerce dates and booleans to numeric primitive values. Dates are compared by their
+ // millisecond representations. Note that invalid dates with millisecond representations
+ // of `NaN` are not equivalent.
+ return +a == +b;
+ // RegExps are compared by their source patterns and flags.
+ case '[object RegExp]':
+ return a.source == b.source &&
+ a.global == b.global &&
+ a.multiline == b.multiline &&
+ a.ignoreCase == b.ignoreCase;
+ }
+ if (typeof a != 'object' || typeof b != 'object') return false;
+ // Assume equality for cyclic structures. The algorithm for detecting cyclic
+ // structures is adapted from ES 5.1 section 15.12.3, abstract operation `JO`.
+ var length = aStack.length;
+ while (length--) {
+ // Linear search. Performance is inversely proportional to the number of
+ // unique nested structures.
+ if (aStack[length] == a) return bStack[length] == b;
+ }
+ // Add the first object to the stack of traversed objects.
+ aStack.push(a);
+ bStack.push(b);
+ var size = 0, result = true;
+ // Recursively compare objects and arrays.
+ if (className == '[object Array]') {
+ // Compare array lengths to determine if a deep comparison is necessary.
+ size = a.length;
+ result = size == b.length;
+ if (result) {
+ // Deep compare the contents, ignoring non-numeric properties.
+ while (size--) {
+ if (!(result = eq(a[size], b[size], aStack, bStack))) break;
+ }
+ }
+ } else {
+ // Objects with different constructors are not equivalent, but `Object`s
+ // from different frames are.
+ var aCtor = a.constructor, bCtor = b.constructor;
+ if (aCtor !== bCtor && !(_.isFunction(aCtor) && (aCtor instanceof aCtor) &&
+ _.isFunction(bCtor) && (bCtor instanceof bCtor))) {
+ return false;
+ }
+ // Deep compare objects.
+ for (var key in a) {
+ if (_.has(a, key)) {
+ // Count the expected number of properties.
+ size++;
+ // Deep compare each member.
+ if (!(result = _.has(b, key) && eq(a[key], b[key], aStack, bStack))) break;
+ }
+ }
+ // Ensure that both objects contain the same number of properties.
+ if (result) {
+ for (key in b) {
+ if (_.has(b, key) && !(size--)) break;
+ }
+ result = !size;
+ }
+ }
+ // Remove the first object from the stack of traversed objects.
+ aStack.pop();
+ bStack.pop();
+ return result;
+ };
+
+ // Perform a deep comparison to check if two objects are equal.
+ _.isEqual = function(a, b) {
+ return eq(a, b, [], []);
+ };
+
+ // Is a given array, string, or object empty?
+ // An "empty" object has no enumerable own-properties.
+ _.isEmpty = function(obj) {
+ if (obj == null) return true;
+ if (_.isArray(obj) || _.isString(obj)) return obj.length === 0;
+ for (var key in obj) if (_.has(obj, key)) return false;
+ return true;
+ };
+
+ // Is a given value a DOM element?
+ _.isElement = function(obj) {
+ return !!(obj && obj.nodeType === 1);
+ };
+
+ // Is a given value an array?
+ // Delegates to ECMA5's native Array.isArray
+ _.isArray = nativeIsArray || function(obj) {
+ return toString.call(obj) == '[object Array]';
+ };
+
+ // Is a given variable an object?
+ _.isObject = function(obj) {
+ return obj === Object(obj);
+ };
+
+ // Add some isType methods: isArguments, isFunction, isString, isNumber, isDate, isRegExp.
+ each(['Arguments', 'Function', 'String', 'Number', 'Date', 'RegExp'], function(name) {
+ _['is' + name] = function(obj) {
+ return toString.call(obj) == '[object ' + name + ']';
+ };
+ });
+
+ // Define a fallback version of the method in browsers (ahem, IE), where
+ // there isn't any inspectable "Arguments" type.
+ if (!_.isArguments(arguments)) {
+ _.isArguments = function(obj) {
+ return !!(obj && _.has(obj, 'callee'));
+ };
+ }
+
+ // Optimize `isFunction` if appropriate.
+ if (typeof (/./) !== 'function') {
+ _.isFunction = function(obj) {
+ return typeof obj === 'function';
+ };
+ }
+
+ // Is a given object a finite number?
+ _.isFinite = function(obj) {
+ return isFinite(obj) && !isNaN(parseFloat(obj));
+ };
+
+ // Is the given value `NaN`? (NaN is the only number which does not equal itself).
+ _.isNaN = function(obj) {
+ return _.isNumber(obj) && obj != +obj;
+ };
+
+ // Is a given value a boolean?
+ _.isBoolean = function(obj) {
+ return obj === true || obj === false || toString.call(obj) == '[object Boolean]';
+ };
+
+ // Is a given value equal to null?
+ _.isNull = function(obj) {
+ return obj === null;
+ };
+
+ // Is a given variable undefined?
+ _.isUndefined = function(obj) {
+ return obj === void 0;
+ };
+
+ // Shortcut function for checking if an object has a given property directly
+ // on itself (in other words, not on a prototype).
+ _.has = function(obj, key) {
+ return hasOwnProperty.call(obj, key);
+ };
+
+ // Utility Functions
+ // -----------------
+
+ // Run Underscore.js in *noConflict* mode, returning the `_` variable to its
+ // previous owner. Returns a reference to the Underscore object.
+ _.noConflict = function() {
+ root._ = previousUnderscore;
+ return this;
+ };
+
+ // Keep the identity function around for default iterators.
+ _.identity = function(value) {
+ return value;
+ };
+
+ // Run a function **n** times.
+ _.times = function(n, iterator, context) {
+ var accum = Array(n);
+ for (var i = 0; i < n; i++) accum[i] = iterator.call(context, i);
+ return accum;
+ };
+
+ // Return a random integer between min and max (inclusive).
+ _.random = function(min, max) {
+ if (max == null) {
+ max = min;
+ min = 0;
+ }
+ return min + Math.floor(Math.random() * (max - min + 1));
+ };
+
+ // List of HTML entities for escaping.
+ var entityMap = {
+ escape: {
+ '&': '&amp;',
+ '<': '&lt;',
+ '>': '&gt;',
+ '"': '&quot;',
+ "'": '&#x27;',
+ '/': '&#x2F;'
+ }
+ };
+ entityMap.unescape = _.invert(entityMap.escape);
+
+ // Regexes containing the keys and values listed immediately above.
+ var entityRegexes = {
+ escape: new RegExp('[' + _.keys(entityMap.escape).join('') + ']', 'g'),
+ unescape: new RegExp('(' + _.keys(entityMap.unescape).join('|') + ')', 'g')
+ };
+
+ // Functions for escaping and unescaping strings to/from HTML interpolation.
+ _.each(['escape', 'unescape'], function(method) {
+ _[method] = function(string) {
+ if (string == null) return '';
+ return ('' + string).replace(entityRegexes[method], function(match) {
+ return entityMap[method][match];
+ });
+ };
+ });
+
+ // If the value of the named property is a function then invoke it;
+ // otherwise, return it.
+ _.result = function(object, property) {
+ if (object == null) return null;
+ var value = object[property];
+ return _.isFunction(value) ? value.call(object) : value;
+ };
+
+ // Add your own custom functions to the Underscore object.
+ _.mixin = function(obj) {
+ each(_.functions(obj), function(name){
+ var func = _[name] = obj[name];
+ _.prototype[name] = function() {
+ var args = [this._wrapped];
+ push.apply(args, arguments);
+ return result.call(this, func.apply(_, args));
+ };
+ });
+ };
+
+ // Generate a unique integer id (unique within the entire client session).
+ // Useful for temporary DOM ids.
+ var idCounter = 0;
+ _.uniqueId = function(prefix) {
+ var id = ++idCounter + '';
+ return prefix ? prefix + id : id;
+ };
+
+ // By default, Underscore uses ERB-style template delimiters, change the
+ // following template settings to use alternative delimiters.
+ _.templateSettings = {
+ evaluate : /<%([\s\S]+?)%>/g,
+ interpolate : /<%=([\s\S]+?)%>/g,
+ escape : /<%-([\s\S]+?)%>/g
+ };
+
+ // When customizing `templateSettings`, if you don't want to define an
+ // interpolation, evaluation or escaping regex, we need one that is
+ // guaranteed not to match.
+ var noMatch = /(.)^/;
+
+ // Certain characters need to be escaped so that they can be put into a
+ // string literal.
+ var escapes = {
+ "'": "'",
+ '\\': '\\',
+ '\r': 'r',
+ '\n': 'n',
+ '\t': 't',
+ '\u2028': 'u2028',
+ '\u2029': 'u2029'
+ };
+
+ var escaper = /\\|'|\r|\n|\t|\u2028|\u2029/g;
+
+ // JavaScript micro-templating, similar to John Resig's implementation.
+ // Underscore templating handles arbitrary delimiters, preserves whitespace,
+ // and correctly escapes quotes within interpolated code.
+ _.template = function(text, data, settings) {
+ var render;
+ settings = _.defaults({}, settings, _.templateSettings);
+
+ // Combine delimiters into one regular expression via alternation.
+ var matcher = new RegExp([
+ (settings.escape || noMatch).source,
+ (settings.interpolate || noMatch).source,
+ (settings.evaluate || noMatch).source
+ ].join('|') + '|$', 'g');
+
+ // Compile the template source, escaping string literals appropriately.
+ var index = 0;
+ var source = "__p+='";
+ text.replace(matcher, function(match, escape, interpolate, evaluate, offset) {
+ source += text.slice(index, offset)
+ .replace(escaper, function(match) { return '\\' + escapes[match]; });
+
+ if (escape) {
+ source += "'+\n((__t=(" + escape + "))==null?'':_.escape(__t))+\n'";
+ }
+ if (interpolate) {
+ source += "'+\n((__t=(" + interpolate + "))==null?'':__t)+\n'";
+ }
+ if (evaluate) {
+ source += "';\n" + evaluate + "\n__p+='";
+ }
+ index = offset + match.length;
+ return match;
+ });
+ source += "';\n";
+
+ // If a variable is not specified, place data values in local scope.
+ if (!settings.variable) source = 'with(obj||{}){\n' + source + '}\n';
+
+ source = "var __t,__p='',__j=Array.prototype.join," +
+ "print=function(){__p+=__j.call(arguments,'');};\n" +
+ source + "return __p;\n";
+
+ try {
+ render = new Function(settings.variable || 'obj', '_', source);
+ } catch (e) {
+ e.source = source;
+ throw e;
+ }
+
+ if (data) return render(data, _);
+ var template = function(data) {
+ return render.call(this, data, _);
+ };
+
+ // Provide the compiled function source as a convenience for precompilation.
+ template.source = 'function(' + (settings.variable || 'obj') + '){\n' + source + '}';
+
+ return template;
+ };
+
+ // Add a "chain" function, which will delegate to the wrapper.
+ _.chain = function(obj) {
+ return _(obj).chain();
+ };
+
+ // OOP
+ // ---------------
+ // If Underscore is called as a function, it returns a wrapped object that
+ // can be used OO-style. This wrapper holds altered versions of all the
+ // underscore functions. Wrapped objects may be chained.
+
+ // Helper function to continue chaining intermediate results.
+ var result = function(obj) {
+ return this._chain ? _(obj).chain() : obj;
+ };
+
+ // Add all of the Underscore functions to the wrapper object.
+ _.mixin(_);
+
+ // Add all mutator Array functions to the wrapper.
+ each(['pop', 'push', 'reverse', 'shift', 'sort', 'splice', 'unshift'], function(name) {
+ var method = ArrayProto[name];
+ _.prototype[name] = function() {
+ var obj = this._wrapped;
+ method.apply(obj, arguments);
+ if ((name == 'shift' || name == 'splice') && obj.length === 0) delete obj[0];
+ return result.call(this, obj);
+ };
+ });
+
+ // Add all accessor Array functions to the wrapper.
+ each(['concat', 'join', 'slice'], function(name) {
+ var method = ArrayProto[name];
+ _.prototype[name] = function() {
+ return result.call(this, method.apply(this._wrapped, arguments));
+ };
+ });
+
+ _.extend(_.prototype, {
+
+ // Start chaining a wrapped Underscore object.
+ chain: function() {
+ this._chain = true;
+ return this;
+ },
+
+ // Extracts the result from a wrapped and chained object.
+ value: function() {
+ return this._wrapped;
+ }
+
+ });
+
+}).call(this);