Techinflo_Productlookbook - Version 1.0.0

Version Notes

This extension allows a vendor to upload Images with the popular styles /trend and then customer can click on a particular part of the image, like Dress, Accessories, footwear etc, to view the matching products. Allow customers to view/purchase products of a matching look.

Download this release

Release Info

Developer Techinflo
Extension Techinflo_Productlookbook
Version 1.0.0
Comparing to
See all releases


Version 1.0.0

Files changed (134) hide show
  1. app/code/local/Techinflo/Productlookbook/Block/Adminhtml/Productlookbook.php +17 -0
  2. app/code/local/Techinflo/Productlookbook/Block/Adminhtml/Productlookbook/Edit.php +41 -0
  3. app/code/local/Techinflo/Productlookbook/Block/Adminhtml/Productlookbook/Edit/Form.php +23 -0
  4. app/code/local/Techinflo/Productlookbook/Block/Adminhtml/Productlookbook/Edit/Form/Element/Hotspots.php +117 -0
  5. app/code/local/Techinflo/Productlookbook/Block/Adminhtml/Productlookbook/Edit/Form/Element/Productlookbookimage.php +105 -0
  6. app/code/local/Techinflo/Productlookbook/Block/Adminhtml/Productlookbook/Edit/Tab/Form.php +66 -0
  7. app/code/local/Techinflo/Productlookbook/Block/Adminhtml/Productlookbook/Edit/Tabs.php +28 -0
  8. app/code/local/Techinflo/Productlookbook/Block/Adminhtml/Productlookbook/Grid.php +129 -0
  9. app/code/local/Techinflo/Productlookbook/Block/Adminhtml/System/Config/Form/Field/Categories.php +116 -0
  10. app/code/local/Techinflo/Productlookbook/Block/Adminhtml/System/Config/Template/Renderer/Category.php +187 -0
  11. app/code/local/Techinflo/Productlookbook/Block/Adminhtml/Template/Grid/Renderer/Image.php +29 -0
  12. app/code/local/Techinflo/Productlookbook/Block/Productlookbook.php +32 -0
  13. app/code/local/Techinflo/Productlookbook/Helper/Data.php +268 -0
  14. app/code/local/Techinflo/Productlookbook/Model/Config/Source/Effect.php +65 -0
  15. app/code/local/Techinflo/Productlookbook/Model/Fileuploader.php +137 -0
  16. app/code/local/Techinflo/Productlookbook/Model/Layout/Generate/Observer.php +34 -0
  17. app/code/local/Techinflo/Productlookbook/Model/Mysql4/Productlookbook.php +14 -0
  18. app/code/local/Techinflo/Productlookbook/Model/Mysql4/Productlookbook/Collection.php +14 -0
  19. app/code/local/Techinflo/Productlookbook/Model/Productlookbook.php +18 -0
  20. app/code/local/Techinflo/Productlookbook/Model/Status.php +19 -0
  21. app/code/local/Techinflo/Productlookbook/Model/Uploadedfileform.php +26 -0
  22. app/code/local/Techinflo/Productlookbook/Model/Uploadedfilexhr.php +37 -0
  23. app/code/local/Techinflo/Productlookbook/controllers/Adminhtml/ProductlookbookController.php +241 -0
  24. app/code/local/Techinflo/Productlookbook/controllers/IndexController.php +33 -0
  25. app/code/local/Techinflo/Productlookbook/etc/config.xml +159 -0
  26. app/code/local/Techinflo/Productlookbook/etc/system.xml +176 -0
  27. app/code/local/Techinflo/Productlookbook/sql/productlookbook_setup/mysql4-install-1.0.2.php +30 -0
  28. app/code/local/Techinflo/Productlookbook/sql/productlookbook_setup/mysql4-upgrade-1.0.2-1.0.3.php +8 -0
  29. app/design/adminhtml/default/default/layout/productlookbook.xml +27 -0
  30. app/design/frontend/default/default/layout/productlookbook.xml +25 -0
  31. app/design/frontend/default/default/template/productlookbook/productlookbook.phtml +71 -0
  32. app/etc/modules/Techinflo_Productlookbook.xml +21 -0
  33. js/jquery/jquery-1.8.2.min.js +2 -0
  34. js/jquery/jquery.noconflict.js +1 -0
  35. js/productlookbook/fileuploader.js +1251 -0
  36. js/productlookbook/jquery-ui-1.9.1.js +14823 -0
  37. js/productlookbook/jquery.annotate.js +536 -0
  38. js/productlookbook/jquery.mobile.customized.min.js +10 -0
  39. js/productlookbook/json2.min.js +1 -0
  40. media/productlookbook/100X100/53be81b791bde.JPG +0 -0
  41. media/productlookbook/100X100/53be81db38e27.JPG +0 -0
  42. media/productlookbook/100X100/53be820cd989e.JPG +0 -0
  43. media/productlookbook/100X100/53be86dff2a40.JPG +0 -0
  44. media/productlookbook/100X100/53be86f283a61.JPG +0 -0
  45. media/productlookbook/100X100/53be870222845.JPG +0 -0
  46. media/productlookbook/100X100/53be8956c4665.JPG +0 -0
  47. media/productlookbook/100X100/53be8aa8f1366.JPG +0 -0
  48. media/productlookbook/100X100/53be909503fcd.JPG +0 -0
  49. media/productlookbook/100X100/53be90b4ba6b7.JPG +0 -0
  50. media/productlookbook/100X100/53be90c2b9acb.JPG +0 -0
  51. media/productlookbook/100X100/53bfc454e7037.JPG +0 -0
  52. media/productlookbook/450X600/53be81b791bde.JPG +0 -0
  53. media/productlookbook/450X600/53be81db38e27.JPG +0 -0
  54. media/productlookbook/450X600/53be820cd989e.JPG +0 -0
  55. media/productlookbook/450X600/53be86dff2a40.JPG +0 -0
  56. media/productlookbook/450X600/53be86f283a61.JPG +0 -0
  57. media/productlookbook/450X600/53be870222845.JPG +0 -0
  58. media/productlookbook/450X600/53be8956c4665.JPG +0 -0
  59. media/productlookbook/450X600/53be8aa8f1366.JPG +0 -0
  60. media/productlookbook/450X600/53be909503fcd.JPG +0 -0
  61. media/productlookbook/450X600/53be90b4ba6b7.JPG +0 -0
  62. media/productlookbook/450X600/53be90c2b9acb.JPG +0 -0
  63. media/productlookbook/450X600/53bfc454e7037.JPG +0 -0
  64. media/productlookbook/53be81b791bde.JPG +0 -0
  65. media/productlookbook/53be81db38e27.JPG +0 -0
  66. media/productlookbook/53be820cd989e.JPG +0 -0
  67. media/productlookbook/53be86dff2a40.JPG +0 -0
  68. media/productlookbook/53be86f283a61.JPG +0 -0
  69. media/productlookbook/53be870222845.JPG +0 -0
  70. media/productlookbook/53be8956c4665.JPG +0 -0
  71. media/productlookbook/53be8aa8f1366.JPG +0 -0
  72. media/productlookbook/53be909503fcd.JPG +0 -0
  73. media/productlookbook/53be90b4ba6b7.JPG +0 -0
  74. media/productlookbook/53be90c2b9acb.JPG +0 -0
  75. media/productlookbook/53bfc454e7037.JPG +0 -0
  76. media/productlookbook/75X75/53be81b791bde.JPG +0 -0
  77. media/productlookbook/75X75/53be81db38e27.JPG +0 -0
  78. media/productlookbook/75X75/53be820cd989e.JPG +0 -0
  79. media/productlookbook/75X75/53be86dff2a40.JPG +0 -0
  80. media/productlookbook/75X75/53be86f283a61.JPG +0 -0
  81. media/productlookbook/75X75/53be870222845.JPG +0 -0
  82. media/productlookbook/75X75/53be8956c4665.JPG +0 -0
  83. media/productlookbook/75X75/53be8aa8f1366.JPG +0 -0
  84. media/productlookbook/75X75/53be909503fcd.JPG +0 -0
  85. media/productlookbook/75X75/53be90b4ba6b7.JPG +0 -0
  86. media/productlookbook/75X75/53be90c2b9acb.JPG +0 -0
  87. media/productlookbook/75X75/53bfc454e7037.JPG +0 -0
  88. media/productlookbook/Thumbs.db +0 -0
  89. media/productlookbook/icons/default/QuickIcon.png +0 -0
  90. media/productlookbook/icons/default/ebs.jpg +0 -0
  91. media/productlookbook/icons/default/hotspot-icon.png +0 -0
  92. media/productlookbook/icons/default/logo1.PNG +0 -0
  93. media/productlookbook/icons/default/logo2.PNG +0 -0
  94. media/productlookbook/icons/default/logo2_1.PNG +0 -0
  95. media/productlookbook/icons/stores/1/1234.PNG +0 -0
  96. media/productlookbook/icons/stores/1/1234_1.PNG +0 -0
  97. media/productlookbook/icons/websites/default/DSC00140.JPG +0 -0
  98. media/productlookbook/icons/websites/default/Thumbs.db +0 -0
  99. package.xml +18 -0
  100. skin/adminhtml/default/default/productlookbook/css/annotation.css +292 -0
  101. skin/adminhtml/default/default/productlookbook/css/fileuploader.css +75 -0
  102. skin/adminhtml/default/default/productlookbook/images/Thumbs.db +0 -0
  103. skin/adminhtml/default/default/productlookbook/images/btn_bg.gif +0 -0
  104. skin/adminhtml/default/default/productlookbook/images/btn_gray_bg.gif +0 -0
  105. skin/adminhtml/default/default/productlookbook/images/btn_over_bg.gif +0 -0
  106. skin/adminhtml/default/default/productlookbook/images/cancel_btn_icon.png +0 -0
  107. skin/adminhtml/default/default/productlookbook/images/cross.png +0 -0
  108. skin/adminhtml/default/default/productlookbook/images/delete_btn_icon.png +0 -0
  109. skin/adminhtml/default/default/productlookbook/images/icon_btn_add.png +0 -0
  110. skin/adminhtml/default/default/productlookbook/images/link_external.png +0 -0
  111. skin/adminhtml/default/default/productlookbook/images/loading.gif +0 -0
  112. skin/adminhtml/default/default/productlookbook/images/ok_btn_icon.png +0 -0
  113. skin/adminhtml/default/default/productlookbook/images/upload_btn_icon.png +0 -0
  114. skin/frontend/base/default/productlookbook/css/hotspots.css +608 -0
  115. skin/frontend/base/default/productlookbook/images/Thumbs.db +0 -0
  116. skin/frontend/base/default/productlookbook/images/adv-bg.png +0 -0
  117. skin/frontend/base/default/productlookbook/images/camera-loader.gif +0 -0
  118. skin/frontend/base/default/productlookbook/images/camera_skins.png +0 -0
  119. skin/frontend/base/default/productlookbook/images/caption-bg.png +0 -0
  120. skin/frontend/base/default/productlookbook/images/info-bg.png +0 -0
  121. skin/frontend/base/default/productlookbook/images/patterns/Thumbs.db +0 -0
  122. skin/frontend/base/default/productlookbook/images/patterns/overlay1.png +0 -0
  123. skin/frontend/base/default/productlookbook/images/patterns/overlay10.png +0 -0
  124. skin/frontend/base/default/productlookbook/images/patterns/overlay2.png +0 -0
  125. skin/frontend/base/default/productlookbook/images/patterns/overlay3.png +0 -0
  126. skin/frontend/base/default/productlookbook/images/patterns/overlay4.png +0 -0
  127. skin/frontend/base/default/productlookbook/images/patterns/overlay5.png +0 -0
  128. skin/frontend/base/default/productlookbook/images/patterns/overlay6.png +0 -0
  129. skin/frontend/base/default/productlookbook/images/patterns/overlay7.png +0 -0
  130. skin/frontend/base/default/productlookbook/images/patterns/overlay8.png +0 -0
  131. skin/frontend/base/default/productlookbook/images/patterns/overlay9.png +0 -0
  132. skin/frontend/base/default/productlookbook/js/camera.min.js +4 -0
  133. skin/frontend/base/default/productlookbook/js/hotspots.js +85 -0
  134. skin/frontend/base/default/productlookbook/js/jquery.easing.1.3.js +205 -0
app/code/local/Techinflo/Productlookbook/Block/Adminhtml/Productlookbook.php ADDED
@@ -0,0 +1,17 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /*
3
+ * @category Techinflo
4
+ * @package Techinflo LookBook
5
+ * @author <Techinflo Team>
6
+ */
7
+ class Techinflo_Productlookbook_Block_Adminhtml_Productlookbook extends Mage_Adminhtml_Block_Widget_Grid_Container
8
+ {
9
+ public function __construct()
10
+ {
11
+ $this->_controller = 'adminhtml_productlookbook';
12
+ $this->_blockGroup = 'productlookbook';
13
+ $this->_headerText = Mage::helper('productlookbook')->__('Product Lookbook Slide Manager');
14
+ $this->_addButtonLabel = Mage::helper('productlookbook')->__('Add Product Slide');
15
+ parent::__construct();
16
+ }
17
+ }
app/code/local/Techinflo/Productlookbook/Block/Adminhtml/Productlookbook/Edit.php ADDED
@@ -0,0 +1,41 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /*
3
+ * @category Techinflo
4
+ * @package Techinflo LookBook
5
+ * @author <Techinflo Team>
6
+ */
7
+ class Techinflo_Productlookbook_Block_Adminhtml_Productlookbook_Edit extends Mage_Adminhtml_Block_Widget_Form_Container
8
+ {
9
+ public function __construct()
10
+ {
11
+ parent::__construct();
12
+
13
+ $this->_objectId = 'id';
14
+ $this->_blockGroup = 'productlookbook';
15
+ $this->_controller = 'adminhtml_productlookbook';
16
+
17
+ $this->_updateButton('save', 'label', Mage::helper('productlookbook')->__('Save slide'));
18
+ $this->_updateButton('delete', 'label', Mage::helper('productlookbook')->__('Delete slide'));
19
+
20
+ $this->_addButton('saveandcontinue', array(
21
+ 'label' => Mage::helper('adminhtml')->__('Save And Continue Edit'),
22
+ 'onclick' => 'saveAndContinueEdit()',
23
+ 'class' => 'save',
24
+ ), -100);
25
+
26
+ $this->_formScripts[] = "
27
+ function saveAndContinueEdit(){
28
+ editForm.submit($('edit_form').action+'back/edit/');
29
+ }
30
+ ";
31
+ }
32
+
33
+ public function getHeaderText()
34
+ {
35
+ if( Mage::registry('productlookbook_data') && Mage::registry('productlookbook_data')->getId() ) {
36
+ return Mage::helper('productlookbook')->__("Edit slide '%s'", $this->htmlEscape(Mage::registry('productlookbook_data')->getName()));
37
+ } else {
38
+ return Mage::helper('productlookbook')->__('Add slide');
39
+ }
40
+ }
41
+ }
app/code/local/Techinflo/Productlookbook/Block/Adminhtml/Productlookbook/Edit/Form.php ADDED
@@ -0,0 +1,23 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /*
3
+ * @category Techinflo
4
+ * @package Techinflo LookBook
5
+ * @author <Techinflo Team>
6
+ */
7
+ class Techinflo_Productlookbook_Block_Adminhtml_Productlookbook_Edit_Form extends Mage_Adminhtml_Block_Widget_Form
8
+ {
9
+ protected function _prepareForm()
10
+ {
11
+ $form = new Varien_Data_Form(array(
12
+ 'id' => 'edit_form',
13
+ 'action' => $this->getUrl('*/*/save', array('id' => $this->getRequest()->getParam('id'))),
14
+ 'method' => 'post',
15
+ 'enctype' => 'multipart/form-data'
16
+ )
17
+ );
18
+
19
+ $form->setUseContainer(true);
20
+ $this->setForm($form);
21
+ return parent::_prepareForm();
22
+ }
23
+ }
app/code/local/Techinflo/Productlookbook/Block/Adminhtml/Productlookbook/Edit/Form/Element/Hotspots.php ADDED
@@ -0,0 +1,117 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /*
3
+ * @category Techinflo
4
+ * @package Techinflo LookBook
5
+ * @author <Techinflo Team>
6
+ */
7
+ class Techinflo_Productlookbook_Block_Adminhtml_Productlookbook_Edit_Form_Element_Hotspots extends Varien_Data_Form_Element_Abstract
8
+ {
9
+ public function __construct($data)
10
+ {
11
+ parent::__construct($data);
12
+ $this->setType('hidden');
13
+ }
14
+
15
+ public function getElementHtml()
16
+ {
17
+ $selecticon= Mage::getStoreConfig('productlookbook/general/hotspot_iconselect');
18
+ if($selecticon==1)
19
+ {
20
+ $siteurl=Mage::getBaseUrl(Mage_Core_Model_Store::URL_TYPE_WEB);
21
+ $dir = 'media/productlookbook/icons/default/';
22
+ $base_url = Mage::getBaseUrl('media').'productlookbook/icons/default/';
23
+ $newest_mtime = 0;
24
+ $show_file = 'BROKEN';
25
+ if ($handle = opendir($dir)) {
26
+ while (false !== ($file = readdir($handle))) {
27
+ if (($file != '.') && ($file != '..')) {
28
+ $mtime = filemtime("$dir/$file");
29
+ if ($mtime > $newest_mtime) {
30
+ $newest_mtime = $mtime;
31
+ $hotspot_icon = "$base_url/$file";
32
+ }
33
+ }
34
+ }
35
+ }
36
+ }
37
+ else{
38
+ $hotspot_icon = Mage::getBaseUrl('media').'productlookbook/icons/default/hotspot-icon.png';
39
+ }
40
+
41
+ $products_link = Mage::helper("adminhtml")->getUrl('adminhtml/catalog_product/');
42
+ $helper = Mage::helper('productlookbook');
43
+
44
+ $html = '
45
+ <style>
46
+ .image-annotate-area, .image-annotate-edit-area {
47
+ background-size:30px 30px;
48
+ background: url('.$hotspot_icon.') no-repeat center center;
49
+ }
50
+ </style>
51
+ <script type="text/javascript">
52
+ //<![CDATA[
53
+ function InitHotspotBtn() {
54
+ if (jQuery("img#ProductlookbookImage").attr("id")) {
55
+ var annotObj = jQuery("img#ProductlookbookImage").annotateImage({
56
+ editable: true,
57
+ useAjax: false,';
58
+ if ($this->getValue()) $html .= 'notes: '. $this->getValue() . ',';
59
+
60
+ $html .= ' input_field_id: "hotspots"
61
+ });
62
+
63
+ jQuery("img#ProductlookbookImage").before(\'<div class="products-link"><a href="'.$products_link.'" title="'.$helper->__('Products List').'" target="_blank">'. $helper->__('Products List').'</a></div>\');
64
+
65
+ var top = Math.round(jQuery("img#ProductlookbookImage").height()/2);
66
+ jQuery(".image-annotate-canvas").append(\'<div class="hotspots-msg" style="top:\' + top + \'px;">'. $helper->__('Rollover on the image to see hotspots').'</div>\');
67
+
68
+ jQuery(".image-annotate-canvas").hover(
69
+ function () {
70
+ ShowHideHotspotsMsg();
71
+ },
72
+ function () {
73
+ ShowHideHotspotsMsg();
74
+ }
75
+ );
76
+
77
+ return annotObj;
78
+ }
79
+ else
80
+ {
81
+ return false;
82
+ }
83
+ };
84
+
85
+ function checkSKU(){
86
+ result = "";
87
+ request = new Ajax.Request(
88
+ "'. Mage::getUrl("productlookbook/adminhtml_productlookbook/getproduct", array('_secure'=>true)).'",
89
+ {
90
+ method: \'post\',
91
+ asynchronous: false,
92
+ onComplete: function(transport){
93
+ if (200 == transport.status) {
94
+ result = transport.responseText;
95
+ return result;
96
+ }
97
+ if (result.error) {
98
+ alert("Unable to check product SKU");
99
+ return false;
100
+ }
101
+ },
102
+ parameters: Form.serialize($("annotate-edit-form"))
103
+ }
104
+ );
105
+ return result;
106
+ };
107
+ //]]>
108
+ </script>';
109
+
110
+ $html.= parent::getElementHtml();
111
+
112
+ return $html;
113
+ }
114
+ }
115
+
116
+
117
+
app/code/local/Techinflo/Productlookbook/Block/Adminhtml/Productlookbook/Edit/Form/Element/Productlookbookimage.php ADDED
@@ -0,0 +1,105 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /*
3
+ * @category Techinflo
4
+ * @package Techinflo LookBook
5
+ * @author <Techinflo Team>
6
+ */
7
+ class Techinflo_Productlookbook_Block_Adminhtml_Productlookbook_Edit_Form_Element_Productlookbookimage extends Varien_Data_Form_Element_Abstract
8
+ {
9
+ public function __construct($data)
10
+ {
11
+ parent::__construct($data);
12
+ $this->setType('hidden');
13
+ }
14
+
15
+ public function getElementHtml()
16
+ {
17
+ $block_class = Mage::getBlockSingleton('productlookbook/adminhtml_productlookbook');
18
+ $upload_action = Mage::getUrl('productlookbook/adminhtml_productlookbook/upload', array('_secure'=>true)).'?isAjax=true';
19
+ $media_url = Mage::getBaseUrl('media');
20
+ $upload_folder_path = str_replace("/",DS, Mage::getBaseDir("media").DS);
21
+ $helper = Mage::helper('productlookbook');
22
+ $min_image_width = $helper->getMinImageWidth();
23
+ $min_image_height = $helper->getMinImageHeight();
24
+ $sizeLimit = $helper->getMaxUploadFilesize();
25
+ $allowed_extensions = implode('","',explode(',',$helper->getAllowedExtensions()));
26
+
27
+ $html = '<script type="text/javascript">
28
+ //<![CDATA[
29
+ jQuery(document).ready(function() {
30
+
31
+ InitHotspotBtn();
32
+
33
+ img_uploader = new qq.FileUploader({
34
+ element: document.getElementById(\'maket_image\'),
35
+ action: "'.$upload_action.'",
36
+ params: {"form_key":"'.$block_class->getFormKey().'"},
37
+ multiple: false,
38
+ allowedExtensions: ["'.$allowed_extensions.'"],
39
+ sizeLimit: '. $sizeLimit .',
40
+ onComplete: function(id, fileName, responseJSON){
41
+ if (responseJSON.success)
42
+ {
43
+ if (jQuery(\'#ProductlookbookImageBlock\'))
44
+ {
45
+ jQuery.each(jQuery(\'#ProductlookbookImageBlock\').children(),function(index) {
46
+ jQuery(this).remove();
47
+ });
48
+ }
49
+ jQuery(\'#ProductlookbookImageBlock\').append(\'<img id="ProductlookbookImage"';
50
+ $html .= ' src="'.$media_url.'productlookbook/\'+responseJSON.filename+\'" alt="\'+responseJSON.filename+\'"';
51
+ $html .= ' width="\'+responseJSON.dimensions.width+\'" height="\'+responseJSON.dimensions.height+\'"/>\');
52
+
53
+ if (jQuery(\'#advice-required-entry-image\'))
54
+ {
55
+ jQuery(\'#advice-required-entry-image\').remove();
56
+ }
57
+ jQuery(\'#ProductlookbookImage\').load(function(){
58
+ jQuery(this).attr(\'width\',responseJSON.dimensions.width);
59
+ jQuery(this).attr(\'height\',responseJSON.dimensions.height);
60
+ InitHotspotBtn();
61
+ });
62
+ jQuery(\'#image\').val(\'productlookbook/\'+responseJSON.filename);
63
+ jQuery(\'#image\').removeClass(\'validation-failed\');
64
+ }
65
+
66
+ }
67
+ });
68
+ });
69
+ //]]>
70
+ </script>
71
+ <div id="ProductlookbookImageBlock">';
72
+
73
+ if ($this->getValue()) {
74
+ $img_src = $media_url.$this->getValue();
75
+ $img_path = $upload_folder_path.$this->getValue();
76
+ if (file_exists($img_path)) {
77
+
78
+ $dimensions = Mage::helper('productlookbook')->getImageDimensions($img_path);
79
+
80
+ $html .= '<img id="ProductlookbookImage" src="'.$img_src.'" alt="'.basename($img_src).'" width="'.$dimensions['width'].'" height="'.$dimensions['height'].'"/>';
81
+ }
82
+ else
83
+ {
84
+ $html .= '<h4 id="ProductlookbookImage" style="color:red;">File '.$img_src.' doesn\'t exists.</h4>';
85
+ }
86
+ }
87
+
88
+ $html .= '</div>
89
+ <div id="maket_image">
90
+ <noscript>
91
+ <p>Please enable JavaScript to use file uploader.</p>
92
+ <!-- or put a simple form for upload here -->
93
+ </noscript>
94
+ </div>';
95
+
96
+ $html.= parent::getElementHtml();
97
+
98
+ if ($min_image_width!=0 && $min_image_height!=0){
99
+ $html.= '<p class="note" style="clear:both; float:left;">Please make sure that the image your load is at least '
100
+ .$min_image_width.'x'.$min_image_height.' pixels</p>';
101
+ }
102
+
103
+ return $html;
104
+ }
105
+ }
app/code/local/Techinflo/Productlookbook/Block/Adminhtml/Productlookbook/Edit/Tab/Form.php ADDED
@@ -0,0 +1,66 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /*
3
+ * @category Techinflo
4
+ * @package Techinflo LookBook
5
+ * @author <Techinflo Team>
6
+ */
7
+ class Techinflo_Productlookbook_Block_Adminhtml_Productlookbook_Edit_Tab_Form extends Mage_Adminhtml_Block_Widget_Form
8
+ {
9
+ protected function _prepareForm()
10
+ {
11
+ $form = new Varien_Data_Form();
12
+
13
+ $this->setForm($form);
14
+
15
+ $fieldset = $form->addFieldset('productlookbook_form', array('legend'=>Mage::helper('productlookbook')->__('Product Lookbook Slide Information')));
16
+
17
+ $fieldset->addField('name', 'text', array(
18
+ 'label' => Mage::helper('productlookbook')->__('Name'),
19
+ 'required' => true,
20
+ 'name' => 'name',
21
+ ));
22
+
23
+ $fieldset->addField('position', 'text', array(
24
+ 'label' => Mage::helper('productlookbook')->__('Order'),
25
+ 'required' => false,
26
+ 'name' => 'position',
27
+ ));
28
+
29
+ $fieldset->addField('status', 'select', array(
30
+ 'label' => Mage::helper('productlookbook')->__('Status'),
31
+ 'name' => 'status',
32
+ 'values' => array(
33
+ array(
34
+ 'value' => 1,
35
+ 'label' => Mage::helper('productlookbook')->__('Enabled'),
36
+ ),
37
+
38
+ array(
39
+ 'value' => 2,
40
+ 'label' => Mage::helper('productlookbook')->__('Disabled'),
41
+ ),
42
+ ),
43
+ ));
44
+
45
+ $fieldset->addType('productlookbookimage','Techinflo_Productlookbook_Block_Adminhtml_Productlookbook_Edit_Form_Element_Productlookbookimage');
46
+ $fieldset->addField('image', 'productlookbookimage', array(
47
+ 'label' => Mage::helper('productlookbook')->__('Image'),
48
+ 'name' => 'image',
49
+ 'required' => true,
50
+ ));
51
+
52
+ $fieldset->addType('hotspots','Techinflo_Productlookbook_Block_Adminhtml_Productlookbook_Edit_Form_Element_Hotspots');
53
+ $fieldset->addField('hotspots', 'hotspots', array(
54
+ 'name' => 'hotspots',
55
+ ));
56
+
57
+ if ( Mage::getSingleton('adminhtml/session')->getProductlookbookData() )
58
+ {
59
+ $form->setValues(Mage::getSingleton('adminhtml/session')->getProductlookbookData());
60
+ Mage::getSingleton('adminhtml/session')->setProductlookbookData(null);
61
+ } elseif ( Mage::registry('productlookbook_data') ) {
62
+ $form->setValues(Mage::registry('productlookbook_data')->getData());
63
+ }
64
+ return parent::_prepareForm();
65
+ }
66
+ }
app/code/local/Techinflo/Productlookbook/Block/Adminhtml/Productlookbook/Edit/Tabs.php ADDED
@@ -0,0 +1,28 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /*
3
+ * @category Techinflo
4
+ * @package Techinflo LookBook
5
+ * @author <Techinflo Team>
6
+ */
7
+ class Techinflo_Productlookbook_Block_Adminhtml_Productlookbook_Edit_Tabs extends Mage_Adminhtml_Block_Widget_Tabs
8
+ {
9
+
10
+ public function __construct()
11
+ {
12
+ parent::__construct();
13
+ $this->setId('productlookbook_tabs');
14
+ $this->setDestElementId('edit_form');
15
+ $this->setTitle(Mage::helper('productlookbook')->__('Product Lookbook Slide Information'));
16
+ }
17
+
18
+ protected function _beforeToHtml()
19
+ {
20
+ $this->addTab('form_section', array(
21
+ 'label' => Mage::helper('productlookbook')->__('Product Lookbook Slide Information'),
22
+ 'title' => Mage::helper('productlookbook')->__('Product Lookbook Slide Information'),
23
+ 'content' => $this->getLayout()->createBlock('productlookbook/adminhtml_productlookbook_edit_tab_form')->toHtml(),
24
+ ));
25
+
26
+ return parent::_beforeToHtml();
27
+ }
28
+ }
app/code/local/Techinflo/Productlookbook/Block/Adminhtml/Productlookbook/Grid.php ADDED
@@ -0,0 +1,129 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /*
3
+ * @category Techinflo
4
+ * @package Techinflo LookBook
5
+ * @author <Techinflo Team>
6
+ */
7
+ class Techinflo_Productlookbook_Block_Adminhtml_Productlookbook_Grid extends Mage_Adminhtml_Block_Widget_Grid
8
+ {
9
+ public function __construct()
10
+ {
11
+ parent::__construct();
12
+ $this->setId('productlookbookGrid');
13
+ $this->setDefaultSort('productlookbook_id');
14
+ $this->setDefaultDir('ASC');
15
+ $this->setSaveParametersInSession(true);
16
+ }
17
+
18
+ protected function _prepareCollection()
19
+ {
20
+ $collection = Mage::getModel('productlookbook/productlookbook')->getCollection();
21
+ $this->setCollection($collection);
22
+ return parent::_prepareCollection();
23
+ }
24
+
25
+ protected function _prepareColumns()
26
+ {
27
+ $this->addColumn('productlookbook_id', array(
28
+ 'header' => Mage::helper('productlookbook')->__('ID'),
29
+ 'align' =>'right',
30
+ 'width' => '50px',
31
+ 'index' => 'productlookbook_id',
32
+ ));
33
+
34
+ $this->addColumn( 'image', array(
35
+ 'header' => Mage::helper( 'productlookbook' )->__( 'Image' ),
36
+ 'type' => 'image',
37
+ 'width' => '75px',
38
+ 'index' => 'image',
39
+ 'filter' => false,
40
+ 'sortable' => false,
41
+ 'renderer' => 'productlookbook/adminhtml_template_grid_renderer_image',
42
+ ));
43
+
44
+ $this->addColumn('name', array(
45
+ 'header' => Mage::helper('productlookbook')->__('Name'),
46
+ 'align' =>'left',
47
+ 'index' => 'name',
48
+ ));
49
+
50
+ $this->addColumn('position', array(
51
+ 'header' => Mage::helper('productlookbook')->__('Order'),
52
+ 'align' =>'left',
53
+ 'width' => '50px',
54
+ 'index' => 'position',
55
+ ));
56
+
57
+ $this->addColumn('status', array(
58
+ 'header' => Mage::helper('productlookbook')->__('Status'),
59
+ 'align' => 'left',
60
+ 'width' => '80px',
61
+ 'index' => 'status',
62
+ 'type' => 'options',
63
+ 'options' => array(
64
+ 1 => 'Enabled',
65
+ 2 => 'Disabled',
66
+ ),
67
+ ));
68
+
69
+ $this->addColumn('action',
70
+ array(
71
+ 'header' => Mage::helper('productlookbook')->__('Action'),
72
+ 'width' => '100',
73
+ 'type' => 'action',
74
+ 'getter' => 'getId',
75
+ 'actions' => array(
76
+ array(
77
+ 'caption' => Mage::helper('productlookbook')->__('Edit'),
78
+ 'url' => array('base'=> '*/*/edit'),
79
+ 'field' => 'id'
80
+ )
81
+ ),
82
+ 'filter' => false,
83
+ 'sortable' => false,
84
+ 'index' => 'stores',
85
+ 'is_system' => true,
86
+ ));
87
+
88
+ $this->addExportType('*/*/exportCsv', Mage::helper('productlookbook')->__('CSV'));
89
+ $this->addExportType('*/*/exportXml', Mage::helper('productlookbook')->__('XML'));
90
+
91
+ return parent::_prepareColumns();
92
+ }
93
+
94
+ protected function _prepareMassaction()
95
+ {
96
+ $this->setMassactionIdField('productlookbook_id');
97
+ $this->getMassactionBlock()->setFormFieldName('productlookbook');
98
+
99
+ $this->getMassactionBlock()->addItem('delete', array(
100
+ 'label' => Mage::helper('productlookbook')->__('Delete'),
101
+ 'url' => $this->getUrl('*/*/massDelete'),
102
+ 'confirm' => Mage::helper('productlookbook')->__('Are you sure?')
103
+ ));
104
+
105
+ $statuses = Mage::getSingleton('productlookbook/status')->getOptionArray();
106
+
107
+ array_unshift($statuses, array('label'=>'', 'value'=>''));
108
+ $this->getMassactionBlock()->addItem('status', array(
109
+ 'label'=> Mage::helper('productlookbook')->__('Change status'),
110
+ 'url' => $this->getUrl('*/*/massStatus', array('_current'=>true)),
111
+ 'additional' => array(
112
+ 'visibility' => array(
113
+ 'name' => 'status',
114
+ 'type' => 'select',
115
+ 'class' => 'required-entry',
116
+ 'label' => Mage::helper('productlookbook')->__('Status'),
117
+ 'values' => $statuses
118
+ )
119
+ )
120
+ ));
121
+ return $this;
122
+ }
123
+
124
+ public function getRowUrl($row)
125
+ {
126
+ return $this->getUrl('*/*/edit', array('id' => $row->getId()));
127
+ }
128
+
129
+ }
app/code/local/Techinflo/Productlookbook/Block/Adminhtml/System/Config/Form/Field/Categories.php ADDED
@@ -0,0 +1,116 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ class Techinflo_Productlookbook_Block_Adminhtml_System_Config_Form_Field_Categories
3
+ extends Mage_Adminhtml_Block_Abstract
4
+ implements Varien_Data_Form_Element_Renderer_Interface
5
+ {
6
+ /**
7
+ * Enter description here...
8
+ *
9
+ * @param Varien_Data_Form_Element_Abstract $element
10
+ * @return string
11
+ */
12
+ protected function _getElementHtml(Varien_Data_Form_Element_Abstract $element)
13
+ {
14
+ $html = Mage::getBlockSingleton('productlookbook/adminhtml_system_config_template_renderer_category')
15
+ ->setElementName($element->getName())
16
+ ->toHtml();
17
+ $html.= $this->getAfterElementHtml();
18
+ return $html;
19
+ }
20
+
21
+ /**
22
+ * Enter description here...
23
+ *
24
+ * @param Varien_Data_Form_Element_Abstract $element
25
+ * @return string
26
+ */
27
+ public function render(Varien_Data_Form_Element_Abstract $element)
28
+ {
29
+ $id = $element->getHtmlId();
30
+
31
+ $html = '<td class="label"><label for="'.$id.'">'.$element->getLabel().'</label></td>';
32
+
33
+ // replace [value] with [inherit]
34
+ $namePrefix = preg_replace('#\[value\](\[\])?$#', '', $element->getName());
35
+
36
+ $options = $element->getValues();
37
+
38
+ $addInheritCheckbox = false;
39
+ if ($element->getCanUseWebsiteValue()) {
40
+ $addInheritCheckbox = true;
41
+ $checkboxLabel = Mage::helper('adminhtml')->__('Use Website');
42
+ }
43
+ elseif ($element->getCanUseDefaultValue()) {
44
+ $addInheritCheckbox = true;
45
+ $checkboxLabel = Mage::helper('adminhtml')->__('Use Default');
46
+ }
47
+
48
+ if ($addInheritCheckbox) {
49
+ $inherit = $element->getInherit()==1 ? 'checked="checked"' : '';
50
+ if ($inherit) {
51
+ $element->setDisabled(true);
52
+ }
53
+ }
54
+
55
+ if ($element->getTooltip()) {
56
+ $html .= '<td class="value with-tooltip">';
57
+ $html .= $this->_getElementHtml($element);
58
+ $html .= '<div class="field-tooltip"><div>' . $element->getTooltip() . '</div></div>';
59
+ } else {
60
+ $html .= '<td class="value">';
61
+ $html .= $this->_getElementHtml($element);
62
+ };
63
+ if ($element->getComment()) {
64
+ $html.= '<p class="note"><span>'.$element->getComment().'</span></p>';
65
+ }
66
+ $html.= '</td>';
67
+
68
+ if ($addInheritCheckbox) {
69
+
70
+ $defText = $element->getDefaultValue();
71
+ if ($options) {
72
+ $defTextArr = array();
73
+ foreach ($options as $k=>$v) {
74
+ $defTextArr[] = $v['label'];
75
+ break;
76
+ }
77
+ $defText = join(', ', $defTextArr);
78
+ }
79
+
80
+ // default value
81
+ $html.= '<td class="use-default">';
82
+ //$html.= '<input id="'.$id.'_inherit" name="'.$namePrefix.'[inherit]" type="checkbox" value="1" class="input-checkbox config-inherit" '.$inherit.' onclick="$(\''.$id.'\').disabled = this.checked">';
83
+ $html.= '<input id="'.$id.'_inherit" name="'.$namePrefix.'[inherit]" type="checkbox" value="1" class="checkbox config-inherit" '.$inherit.' onclick="toggleValueElements(this, Element.previous(this.parentNode))" /> ';
84
+ $html.= '<label for="'.$id.'_inherit" class="inherit" title="'.htmlspecialchars($defText).'">'.$checkboxLabel.'</label>';
85
+ $html.= '</td>';
86
+ }
87
+
88
+ $html.= '<td class="scope-label">';
89
+ if ($element->getScope()) {
90
+ $html .= $element->getScopeLabel();
91
+ }
92
+ $html.= '</td>';
93
+
94
+ $html.= '<td class="">';
95
+ if ($element->getHint()) {
96
+ $html.= '<div class="hint" >';
97
+ $html.= '<div style="display: none;">' . $element->getHint() . '</div>';
98
+ $html.= '</div>';
99
+ }
100
+ $html.= '</td>';
101
+
102
+ return $this->_decorateRowHtml($element, $html);
103
+ }
104
+
105
+ /**
106
+ * Decorate field row html
107
+ *
108
+ * @param Varien_Data_Form_Element_Abstract $element
109
+ * @param string $html
110
+ * @return string
111
+ */
112
+ protected function _decorateRowHtml($element, $html)
113
+ {
114
+ return '<tr id="row_' . $element->getHtmlId() . '">' . $html . '</tr>';
115
+ }
116
+ }
app/code/local/Techinflo/Productlookbook/Block/Adminhtml/System/Config/Template/Renderer/Category.php ADDED
@@ -0,0 +1,187 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ class Techinflo_Productlookbook_Block_Adminhtml_System_Config_Template_Renderer_Category
3
+ extends Mage_Adminhtml_Block_Catalog_Category_Tree
4
+ {
5
+ protected $_categoryIds;
6
+ protected $_selectedNodes = null;
7
+
8
+ public function __construct()
9
+ {
10
+ parent::__construct();
11
+ $this->setTemplate('productlookbook/category.phtml');
12
+ }
13
+
14
+ public function getCategoryIds()
15
+ {
16
+ $_categoryList = explode(',', $this->getIdsString());
17
+ return is_array($_categoryList) ? $_categoryList : array();
18
+ }
19
+
20
+
21
+ public function getIdsString()
22
+ {
23
+ return Mage::getStoreConfig('productlookbook/general/categories');
24
+ }
25
+
26
+ public function getRootNode()
27
+ {
28
+ // $root = parent::getRoot();
29
+ $root = $this->getRoot();
30
+ if ($root && in_array($root->getId(), $this->getCategoryIds())) {
31
+ $root->setChecked(true);
32
+ }
33
+ return $root;
34
+ }
35
+
36
+ public function getRoot($parentNodeCategory=null, $recursionLevel=3)
37
+ {
38
+ if (!is_null($parentNodeCategory) && $parentNodeCategory->getId()) {
39
+ return $this->getNode($parentNodeCategory, $recursionLevel);
40
+ }
41
+ $root = Mage::registry('root');
42
+ if (is_null($root)) {
43
+ $storeId = (int) $this->getRequest()->getParam('store');
44
+
45
+ if ($storeId) {
46
+ $store = Mage::app()->getStore($storeId);
47
+ $rootId = $store->getRootCategoryId();
48
+ }
49
+ else {
50
+ $rootId = Mage_Catalog_Model_Category::TREE_ROOT_ID;
51
+ }
52
+
53
+ $ids = $this->getSelectedCategoriesPathIds($rootId);
54
+ $tree = Mage::getResourceSingleton('catalog/category_tree')
55
+ ->loadByIds($ids, false, false);
56
+
57
+ if ($this->getCategory()) {
58
+ $tree->loadEnsuredNodes($this->getCategory(), $tree->getNodeById($rootId));
59
+ }
60
+
61
+ $tree->addCollectionData($this->getCategoryCollection());
62
+
63
+ $root = $tree->getNodeById($rootId);
64
+
65
+ if ($root && $rootId != Mage_Catalog_Model_Category::TREE_ROOT_ID) {
66
+ $root->setIsVisible(true);
67
+ }
68
+ elseif($root && $root->getId() == Mage_Catalog_Model_Category::TREE_ROOT_ID) {
69
+ $root->setName(Mage::helper('catalog')->__('Root'));
70
+ }
71
+
72
+ Mage::register('root', $root);
73
+ }
74
+
75
+ return $root;
76
+ }
77
+
78
+ protected function _getNodeJson($node, $level=1)
79
+ {
80
+ $item = parent::_getNodeJson($node, $level);
81
+
82
+ $isParent = $this->_isParentSelectedCategory($node);
83
+
84
+ if ($isParent) {
85
+ $item['expanded'] = true;
86
+ }
87
+
88
+ // if ($node->getLevel() > 1 && !$isParent && isset($item['children'])) {
89
+ // $item['children'] = array();
90
+ // }
91
+
92
+
93
+ if (in_array($node->getId(), $this->getCategoryIds())) {
94
+ $item['checked'] = true;
95
+ }
96
+
97
+ return $item;
98
+ }
99
+
100
+ protected function _isParentSelectedCategory($node)
101
+ {
102
+ foreach ($this->_getSelectedNodes() as $selected) {
103
+ if ($selected) {
104
+ $pathIds = explode('/', $selected->getPathId());
105
+ if (in_array($node->getId(), $pathIds)) {
106
+ return true;
107
+ }
108
+ }
109
+ }
110
+
111
+ return false;
112
+ }
113
+
114
+ protected function _getSelectedNodes()
115
+ {
116
+ if ($this->_selectedNodes === null) {
117
+ $this->_selectedNodes = array();
118
+ $root = $this->getRoot();
119
+ foreach ($this->getCategoryIds() as $categoryId) {
120
+ if ($root) {
121
+ $this->_selectedNodes[] = $root->getTree()->getNodeById($categoryId);
122
+ }
123
+ }
124
+ }
125
+
126
+ return $this->_selectedNodes;
127
+ }
128
+
129
+ public function jsonEncode($valueToEncode, $cycleCheck = false, $options = array())
130
+ {
131
+ $json = Zend_Json::encode($valueToEncode, $cycleCheck, $options);
132
+ /* @var $inline Mage_Core_Model_Translate_Inline */
133
+ $inline = Mage::getSingleton('core/translate_inline');
134
+ if ($inline->isAllowed()) {
135
+ $inline->setIsJson(true);
136
+ $inline->processResponseBody($json);
137
+ $inline->setIsJson(false);
138
+ }
139
+
140
+ return $json;
141
+ }
142
+
143
+ public function getCategoryChildrenJson($categoryId)
144
+ {
145
+ $category = Mage::getModel('catalog/category')->load($categoryId);
146
+ $node = $this->getRoot($category, 1)->getTree()->getNodeById($categoryId);
147
+
148
+ if (!$node || !$node->hasChildren()) {
149
+ return '[]';
150
+ }
151
+
152
+ $children = array();
153
+ foreach ($node->getChildren() as $child) {
154
+ $children[] = $this->_getNodeJson($child);
155
+ }
156
+ return $this->jsonEncode($children);
157
+ }
158
+
159
+ public function getLoadTreeUrl($expanded=null)
160
+ {
161
+ return $this->getUrl('productlookbook/adminhtml_productlookbook/categoriesJson', array('_current'=>true));
162
+ }
163
+
164
+ /**
165
+ * Return distinct path ids of selected categories
166
+ *
167
+ * @param int $rootId Root category Id for context
168
+ * @return array
169
+ */
170
+ public function getSelectedCategoriesPathIds($rootId = false)
171
+ {
172
+ $ids = array();
173
+ $collection = Mage::getModel('catalog/category')->getCollection()
174
+ ->addFieldToFilter('entity_id', array('in'=>$this->getCategoryIds()));
175
+ foreach ($collection as $item) {
176
+ if ($rootId && !in_array($rootId, $item->getPathIds())) {
177
+ continue;
178
+ }
179
+ foreach ($item->getPathIds() as $id) {
180
+ if (!in_array($id, $ids)) {
181
+ $ids[] = $id;
182
+ }
183
+ }
184
+ }
185
+ return $ids;
186
+ }
187
+ }
app/code/local/Techinflo/Productlookbook/Block/Adminhtml/Template/Grid/Renderer/Image.php ADDED
@@ -0,0 +1,29 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /*
3
+ * @category Techinflo
4
+ * @package Techinflo LookBook
5
+ * @author <Techinflo Team>
6
+ */
7
+ class Techinflo_Productlookbook_Block_Adminhtml_Template_Grid_Renderer_Image extends Mage_Adminhtml_Block_Widget_Grid_Column_Renderer_Action
8
+ {
9
+ public function render(Varien_Object $row)
10
+ {
11
+ return $this->_getValue($row);
12
+ }
13
+
14
+ public function _getValue(Varien_Object $row)
15
+ {
16
+ if ($getter = $this->getColumn()->getGetter()) {
17
+ $val = $row->$getter();
18
+ }
19
+ $width = str_replace('px','',$this->getColumn()->getWidth());
20
+ $val = $row->getData($this->getColumn()->getIndex());
21
+ $url = Mage::helper('productlookbook')->getResizedUrl($val,$width);
22
+ $out = '<center>';
23
+ $out .= "<img src=" . $url . " />";
24
+ $out .= '</center>';
25
+
26
+ return $out;
27
+
28
+ }
29
+ }
app/code/local/Techinflo/Productlookbook/Block/Productlookbook.php ADDED
@@ -0,0 +1,32 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /*
3
+ * @category Techinflo
4
+ * @package Techinflo LookBook
5
+ * @author <Techinflo Team>
6
+ */
7
+ class Techinflo_Productlookbook_Block_Productlookbook extends Mage_Core_Block_Template
8
+ {
9
+ protected function _construct()
10
+ {
11
+ $this->addData(array(
12
+ 'cache_lifetime' => false,
13
+ 'cache_tags' => array(Techinflo_Productlookbook_Model_Productlookbook::CACHE_TAG),
14
+ 'cache_key' => 'slider',
15
+ ));
16
+ }
17
+
18
+ public function _prepareLayout()
19
+ {
20
+ return parent::_prepareLayout();
21
+ }
22
+
23
+ public function getCollection()
24
+ {
25
+ $collection = Mage::getModel('productlookbook/productlookbook')
26
+ ->getCollection()
27
+ ->addFieldToFilter('status', 1)
28
+ ->setOrder('position', 'ASC');
29
+ return $collection;
30
+ }
31
+
32
+ }
app/code/local/Techinflo/Productlookbook/Helper/Data.php ADDED
@@ -0,0 +1,268 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /*
3
+ * @category Techinflo
4
+ * @package Techinflo LookBook
5
+ * @author <Techinflo Team>
6
+ */
7
+ class Techinflo_Productlookbook_Helper_Data extends Mage_Core_Helper_Abstract
8
+ {
9
+ public function getEnabled()
10
+ {
11
+ return Mage::getStoreConfig('productlookbook/general/enabled');
12
+ }
13
+
14
+ public function getMaxImageWidth()
15
+ {
16
+ return intval(Mage::getStoreConfig('productlookbook/general/max_image_width'));
17
+ }
18
+
19
+ public function getMaxImageHeight()
20
+ {
21
+ return intval(Mage::getStoreConfig('productlookbook/general/max_image_height'));
22
+ }
23
+
24
+ public function getMinImageWidth()
25
+ {
26
+ return intval(Mage::getStoreConfig('productlookbook/general/min_image_width'));
27
+ }
28
+
29
+ public function getMinImageHeight()
30
+ {
31
+ return intval(Mage::getStoreConfig('productlookbook/general/min_image_height'));
32
+ }
33
+
34
+ public function getMaxUploadFilesize()
35
+ {
36
+ return intval(Mage::getStoreConfig('productlookbook/general/max_upload_filesize'));
37
+ }
38
+
39
+ public function getAllowedExtensions()
40
+ {
41
+ return Mage::getStoreConfig('productlookbook/general/allowed_extensions');
42
+ }
43
+
44
+ public function getEffects()
45
+ {
46
+ return Mage::getStoreConfig('productlookbook/general/effects');
47
+ }
48
+ public function getNavigation()
49
+ {
50
+ return Mage::getStoreConfig('productlookbook/general/navigation');
51
+ }
52
+ public function getNavigationHover()
53
+ {
54
+ return Mage::getStoreConfig('productlookbook/general/navigation_hover');
55
+ }
56
+ public function getThumbnails()
57
+ {
58
+ return Mage::getStoreConfig('productlookbook/general/thumbnails');
59
+ }
60
+ public function getPause()
61
+ {
62
+ return Mage::getStoreConfig('productlookbook/general/pause');
63
+ }
64
+ public function getTransitionDuration()
65
+ {
66
+ return Mage::getStoreConfig('productlookbook/general/transition_duration');
67
+ }
68
+
69
+ /**
70
+ * Returns the resized Image URL
71
+ *
72
+ * @param string $imgUrl - This is relative to the the media folder (custom/module/images/example.jpg)
73
+ * @param int $x Width
74
+ * @param int $y Height
75
+ *Remember your base image or big image must be in Root/media/productlookbook/example.jpg
76
+ *
77
+ * echo Mage::helper('productlookbook')->getResizedUrl("productlookbook/example.jpg",101,65)
78
+ *
79
+ *By doing this new image will be created in Root/media/productlookbook/101X65/example.jpg
80
+ */
81
+
82
+ public function getResizedUrl($imgUrl,$x,$y=NULL){
83
+
84
+ $imgPath=$this->splitImageValue($imgUrl,"path");
85
+ $imgName=$this->splitImageValue($imgUrl,"name");
86
+
87
+ /**
88
+ * Path with Directory Seperator
89
+ */
90
+ $imgPath=str_replace("/",DS,$imgPath);
91
+
92
+ /**
93
+ * Absolute full path of Image
94
+ */
95
+ $imgPathFull=Mage::getBaseDir("media").DS.$imgPath.DS.$imgName;
96
+
97
+ /**
98
+ * If Y is not set set it to as X
99
+ */
100
+ $width=$x;
101
+ $y?$height=$y:$height=$x;
102
+
103
+ /**
104
+ * Resize folder is widthXheight
105
+ */
106
+ $resizeFolder=$width."X".$height;
107
+
108
+ /**
109
+ * Image resized path will then be
110
+ */
111
+ $imageResizedPath=Mage::getBaseDir("media").DS.$imgPath.DS.$resizeFolder.DS.$imgName;
112
+
113
+ /**
114
+ * First check in cache i.e image resized path
115
+ * If not in cache then create image of the width=X and height = Y
116
+ */
117
+ if (!file_exists($imageResizedPath) && file_exists($imgPathFull)) :
118
+ $imageObj = new Varien_Image($imgPathFull);
119
+ $imageObj->constrainOnly(TRUE);
120
+ $imageObj->keepAspectRatio(TRUE);
121
+ $imageObj->keepTransparency(TRUE);
122
+ $imageObj->resize($width,$height);
123
+ $imageObj->save($imageResizedPath);
124
+ endif;
125
+
126
+ /**
127
+ * Else image is in cache replace the Image Path with / for http path.
128
+ */
129
+ $imgUrl=str_replace(DS,"/",$imgPath);
130
+
131
+ /**
132
+ * Return full http path of the image
133
+ */
134
+ return Mage::getBaseUrl("media").$imgUrl."/".$resizeFolder."/".$imgName;
135
+ }
136
+
137
+ /**
138
+ * Splits images Path and Name
139
+ *
140
+ * Path=productlookbook/
141
+ * Name=example.jpg
142
+ *
143
+ * @param string $imageValue
144
+ * @param string $attr
145
+ * @return string
146
+ */
147
+ public function splitImageValue($imageValue,$attr="name"){
148
+ $imArray=explode("/",$imageValue);
149
+
150
+ $name=$imArray[count($imArray)-1];
151
+ $path=implode("/",array_diff($imArray,array($name)));
152
+ if($attr=="path"){
153
+ return $path;
154
+ }
155
+ else
156
+ return $name;
157
+
158
+ }
159
+
160
+ /**
161
+ * Splits images Path and Name
162
+ *
163
+ * img_path=productlookbook/example.jpg
164
+ *
165
+ * @param string $img_path
166
+ * @return array('width'=>$width, 'height'=>$height)
167
+ */
168
+ public function getImageDimensions($img_path){
169
+ $imageObj = new Varien_Image($img_path);
170
+ $width = $imageObj->getOriginalWidth();
171
+ $height = $imageObj->getOriginalHeight();
172
+ $result = array('width'=>$width, 'height'=>$height);
173
+ return $result;
174
+ }
175
+
176
+ /**
177
+ * Change SKU to product information into Json array
178
+ *
179
+ * img_path=productlookbook/example.jpg
180
+ *
181
+ * @param json array $array
182
+ * @return json array('width'=>$width, 'height'=>$height)
183
+ */
184
+ public function getHotspotsWithProductDetails($hotspots_json){
185
+ if ($hotspots_json=='') return '';
186
+ $decoded_array = json_decode($hotspots_json,true);
187
+ $img_width = intval(Mage::getStoreConfig('productlookbook/general/max_image_width'));
188
+
189
+ $selecticon= Mage::getStoreConfig('productlookbook/general/hotspot_iconselect');
190
+ if($selecticon==1)
191
+ {
192
+ $dir = 'media/productlookbook/icons/default/';
193
+ $base_url = Mage::getBaseUrl('media').'productlookbook/icons/default/';
194
+ $newest_mtime = 0;
195
+ $show_file = 'BROKEN';
196
+ if ($handle = opendir($dir)) {
197
+ while (false !== ($file = readdir($handle))) {
198
+ if (($file != '.') && ($file != '..')) {
199
+ $mtime = filemtime("$dir/$file");
200
+ if ($mtime > $newest_mtime) {
201
+ $newest_mtime = $mtime;
202
+ $hotspot_icon = "$base_url/$file";
203
+ }
204
+ }
205
+ }
206
+ }
207
+ }
208
+ else{
209
+ $hotspot_icon = Mage::getBaseUrl('media').'productlookbook/icons/default/hotspot-icon.png';
210
+ }
211
+ $hotspot_icon_path = Mage::getBaseDir('media').DS.'productlookbook'.DS.'icons'.DS.'default'.DS.'hotspot-icon.png';
212
+ $icon_dimensions = $this->getImageDimensions($hotspot_icon_path);
213
+ $_coreHelper = Mage::helper('core');
214
+ foreach($decoded_array as $key => $value){
215
+ $product_details = Mage::getModel('catalog/product')->loadByAttribute('sku',$decoded_array[$key]['text']);
216
+
217
+ $html_content = '<img class="hotspot-icon" src="'.$hotspot_icon.'" alt="" style="
218
+ left:'. (round($value['width']/2)-round($icon_dimensions['width']/2)) .'px;
219
+ top:'. (round($value['height']/2)-round($icon_dimensions['height']/2)) .'px;width:30px;height:30px;
220
+ "/><div class="product-info" style="';
221
+ $html_content .= 'left:'.round($value['width']/2).'px;';
222
+ $html_content .= 'top:'.round($value['height']/2).'px;';
223
+
224
+ if ($product_details) {
225
+ $_p_name = $product_details->getName();
226
+ $html_content .= 'width: '. strlen($_p_name)*8 .'px;';
227
+ }
228
+ else
229
+ {
230
+ $html_content .= 'width: 200px;';
231
+ }
232
+
233
+ $html_content .= '">';
234
+ if ($product_details) {
235
+ $_p_price = $_coreHelper->currency($product_details->getFinalPrice(),true,false);
236
+ if($product_details->isAvailable())
237
+ {
238
+ $_p_url = $product_details->getProductUrl();
239
+ $html_content .= '<div><a href=\''.$_p_url.'\'>'.$_p_name.'</a></div>';
240
+ }
241
+ else
242
+ {
243
+ $html_content .= '<div>'.$_p_name.'</div>';
244
+ $html_content .= '<div class="out-of-stock"><span>'. $this->__('Out of stock') .'</span></div>';
245
+ }
246
+
247
+ if($product_details->getFinalPrice()){
248
+ if ($product_details->getPrice()>$product_details->getFinalPrice()){
249
+ $regular_price = $_coreHelper->currency($product_details->getPrice(),true,false);
250
+ $_p_price = '<div class="old-price">'.$regular_price.'</div>'.$_p_price;
251
+ }
252
+ $html_content .= '<div class="price">'.$_p_price.'</div>';
253
+ }
254
+ }
255
+ else
256
+ {
257
+ $html_content .= '<div>Product with SKU "'.$decoded_array[$key]['text'].'" doesn\'t exists.</div>';
258
+ }
259
+ $html_content .= '
260
+ </div>
261
+ ';
262
+
263
+ $decoded_array[$key]['text'] = $html_content;
264
+ }
265
+ $result = $decoded_array;
266
+ return $result;
267
+ }
268
+ }
app/code/local/Techinflo/Productlookbook/Model/Config/Source/Effect.php ADDED
@@ -0,0 +1,65 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ class Techinflo_Productlookbook_Model_Config_Source_Effect extends Mage_Core_Model_Abstract
4
+ {
5
+ const SIMPLE_FADE = 'simpleFade';
6
+ const CURTAIN_TOP_LEFT = 'curtainTopLeft';
7
+ const CURTAIN_TOP_RIGHT = 'curtainTopRight';
8
+ const CURTAIN_BOTTOM_LEFT = 'curtainBottomLeft';
9
+ const CURTAIN_BOTTOM_RIGHT = 'curtainBottomRight';
10
+ const CURTAIN_SLISE_LEFT = 'curtainSliceLeft';
11
+ const CURTAIN_SLISE_RIGHT = 'curtainSliceRight';
12
+ const BLIND_CURTAIN_TOP_LEFT = 'blindCurtainTopLeft';
13
+ const BLIND_CURTAIN_TOP_RIGHT = 'blindCurtainTopRight';
14
+ const BLIND_CURTAIN_BOTTOM_LEFT = 'blindCurtainBottomLeft';
15
+ const BLIND_CURTAIN_BOTTOM_RIGHT = 'blindCurtainBottomRight';
16
+ const BLIND_CURTAIN_SLICE_BOTTOM = 'blindCurtainSliceBottom';
17
+ const BLIND_CURTAIN_SLICE_TOP = 'blindCurtainSliceTop';
18
+ const STAMPEDE = 'stampede';
19
+ const MOSAIC = 'mosaic';
20
+ const MOSAIC_REVERSE = 'mosaicReverse';
21
+ const MOSAIC_RANDOM = 'mosaicRandom';
22
+ const MOSAIC_SPIRAL = 'mosaicSpiral';
23
+ const MOSAIC_SPIRAL_REVERSE = 'mosaicSpiralReverse';
24
+ const TOP_LEFT_BOTTOM_RIGHT = 'topLeftBottomRight';
25
+ const BOTTOM_RIGHT_TOP_LEFT = 'bottomRightTopLeft';
26
+ const BOTTOM_LEFT_TOP_RIGHT = 'bottomLeftTopRight';
27
+ const SCROLL_LEFT = 'scrollLeft';
28
+ const SCROLL_RIGHT = 'scrollRight';
29
+ const SCROLL_HORZ = 'scrollHorz';
30
+ const SCROLL_BOTTOM = 'scrollBottom';
31
+ const SCROLL_TOP = 'scrollTop';
32
+
33
+ static public function toOptionArray()
34
+ {
35
+ return array(
36
+ array( 'value'=> self::SIMPLE_FADE , 'label' => 'simpleFade'),
37
+ array( 'value'=> self::CURTAIN_TOP_LEFT , 'label' => 'curtainTopLeft'),
38
+ array( 'value'=> self::CURTAIN_TOP_RIGHT , 'label' => 'curtainTopRight'),
39
+ array( 'value'=> self::CURTAIN_BOTTOM_LEFT , 'label' => 'curtainBottomLeft'),
40
+ array( 'value'=> self::CURTAIN_BOTTOM_RIGHT , 'label' => 'curtainBottomRight'),
41
+ array( 'value'=> self::CURTAIN_SLISE_LEFT , 'label' => 'curtainSliceLeft'),
42
+ array( 'value'=> self::CURTAIN_SLISE_RIGHT , 'label' => 'curtainSliceRight'),
43
+ array( 'value'=> self::BLIND_CURTAIN_TOP_LEFT , 'label' => 'blindCurtainTopLeft'),
44
+ array( 'value'=> self::BLIND_CURTAIN_TOP_RIGHT , 'label' => 'blindCurtainTopRight'),
45
+ array( 'value'=> self::BLIND_CURTAIN_BOTTOM_LEFT , 'label' => 'blindCurtainBottomLeft'),
46
+ array( 'value'=> self::BLIND_CURTAIN_BOTTOM_RIGHT , 'label' => 'blindCurtainBottomRight'),
47
+ array( 'value'=> self::BLIND_CURTAIN_SLICE_BOTTOM , 'label' => 'blindCurtainSliceBottom'),
48
+ array( 'value'=> self::BLIND_CURTAIN_SLICE_TOP , 'label' => 'blindCurtainSliceTop'),
49
+ array( 'value'=> self::STAMPEDE , 'label' => 'stampede'),
50
+ array( 'value'=> self::MOSAIC , 'label' => 'mosaic'),
51
+ array( 'value'=> self::MOSAIC_REVERSE , 'label' => 'mosaicReverse'),
52
+ array( 'value'=> self::MOSAIC_RANDOM , 'label' => 'mosaicRandom'),
53
+ array( 'value'=> self::MOSAIC_SPIRAL , 'label' => 'mosaicSpiral'),
54
+ array( 'value'=> self::MOSAIC_SPIRAL_REVERSE , 'label' => 'mosaicSpiralReverse'),
55
+ array( 'value'=> self::TOP_LEFT_BOTTOM_RIGHT , 'label' => 'topLeftBottomRight'),
56
+ array( 'value'=> self::BOTTOM_RIGHT_TOP_LEFT , 'label' => 'bottomRightTopLeft'),
57
+ array( 'value'=> self::BOTTOM_LEFT_TOP_RIGHT , 'label' => 'bottomLeftTopRight'),
58
+ array( 'value'=> self::SCROLL_LEFT , 'label' => 'scrollLeft'),
59
+ array( 'value'=> self::SCROLL_RIGHT , 'label' => 'scrollRight'),
60
+ array( 'value'=> self::SCROLL_HORZ , 'label' => 'scrollHorz'),
61
+ array( 'value'=> self::SCROLL_BOTTOM , 'label' => 'scrollBottom'),
62
+ array( 'value'=> self::SCROLL_TOP , 'label' => 'scrollTop')
63
+ );
64
+ }
65
+ }
app/code/local/Techinflo/Productlookbook/Model/Fileuploader.php ADDED
@@ -0,0 +1,137 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /*
3
+ * @category Techinflo
4
+ * @package Techinflo LookBook
5
+ * @author <Techinflo Team>
6
+ */
7
+ class Techinflo_Productlookbook_Model_Fileuploader {
8
+
9
+ private $allowedExtensions = array();
10
+ private $sizeLimit = 10485760;
11
+ private $min_image_width = 0;
12
+ private $min_image_height = 0;
13
+ private $max_image_width = 0;
14
+ private $max_image_height = 0;
15
+ private $filemodel;
16
+
17
+ function __construct(){
18
+
19
+ $helper = Mage::helper('productlookbook');
20
+ $sizeLimit = $helper->getMaxUploadFilesize();
21
+ $this->min_image_width = $helper->getMinImageWidth();
22
+ $this->min_image_height = $helper->getMinImageHeight();
23
+ $this->max_image_width = $helper->getMaxImageWidth();
24
+ $this->max_image_height = $helper->getMaxImageHeight();
25
+ $allowed_extensions = explode(',',$helper->getAllowedExtensions());
26
+
27
+ $this->allowedExtensions = array_map("strtolower", $allowed_extensions);
28
+ if ($sizeLimit>0) $this->sizeLimit = $sizeLimit;
29
+
30
+ if (isset($_GET['qqfile'])) {
31
+ $this->filemodel = Mage::getModel('productlookbook/uploadedfilexhr');
32
+ } elseif (isset($_FILES['qqfile'])) {
33
+ $this->filemodel = Mage::getModel('productlookbook/uploadedfileform');
34
+ } else {
35
+ $this->filemodel = false;
36
+ }
37
+
38
+ }
39
+
40
+ public function checkServerSettings(){
41
+ $postSize = $this->toBytes(ini_get('post_max_size'));
42
+ $uploadSize = $this->toBytes(ini_get('upload_max_filesize'));
43
+
44
+ if ($postSize < $this->sizeLimit || $uploadSize < $this->sizeLimit){
45
+ $size = max(1, $this->sizeLimit / 1024 / 1024) . 'M';
46
+ return array('error' => 'increase post_max_size and upload_max_filesize to $size');
47
+ }
48
+
49
+ if ($this->max_image_width < $this->min_image_width || $this->max_image_height < $this->min_image_height){
50
+ return array('error' => 'File was not uploaded. Minimal image width (height) can\'t be greater then maximal. Please, check settings.');
51
+ }
52
+ return true;
53
+
54
+ }
55
+
56
+ private function toBytes($str){
57
+ $val = trim($str);
58
+ $last = strtolower($str[strlen($str)-1]);
59
+ switch($last) {
60
+ case 'g': $val *= 1024;
61
+ case 'm': $val *= 1024;
62
+ case 'k': $val *= 1024;
63
+ }
64
+ return $val;
65
+ }
66
+
67
+ /**
68
+ * Returns array('success'=>true) or array('error'=>'error message')
69
+ */
70
+ function handleUpload($uploadDirectory, $replaceOldFile = FALSE){
71
+ if (!is_writable($uploadDirectory)){
72
+ return array('error' => "Server error. Upload directory isn't writable.");
73
+ }
74
+
75
+ if (!$this->filemodel){
76
+ return array('error' => 'No files were uploaded.');
77
+ }
78
+
79
+ $size = $this->filemodel->getSize();
80
+
81
+ if ($size == 0) {
82
+ return array('error' => 'File is empty');
83
+ }
84
+
85
+ if ($size > $this->sizeLimit) {
86
+ return array('error' => 'File is too large');
87
+ }
88
+
89
+ $pathinfo = pathinfo($this->filemodel->getName());
90
+ $filename = $pathinfo['filename'];
91
+ //$filename = md5(uniqid());
92
+ $filename = uniqid();
93
+ $ext = $pathinfo['extension'];
94
+
95
+ if($this->allowedExtensions && !in_array(strtolower($ext), $this->allowedExtensions)){
96
+ $these = implode(', ', $this->allowedExtensions);
97
+ return array('error' => 'File has an invalid extension, it should be one of '. $these . '.');
98
+ }
99
+
100
+ if(!$replaceOldFile){
101
+ /// don't overwrite previous files that were uploaded
102
+ while (file_exists($uploadDirectory . $filename . '.' . $ext)) {
103
+ $filename .= rand(10, 99);
104
+ }
105
+ }
106
+
107
+ if ($this->filemodel->save($uploadDirectory . $filename . '.' . $ext)){
108
+ $imgPathFull = $uploadDirectory . $filename . '.' . $ext;
109
+ $dimensions = Mage::helper('productlookbook')->getImageDimensions($imgPathFull);
110
+ if ($this->min_image_width!=0 && $this->min_image_height!=0) {
111
+ if ($dimensions['width'] < $this->min_image_width || $dimensions['height'] < $this->min_image_height)
112
+ {
113
+ unlink($imgPathFull);
114
+ return array('error'=> 'Uploaded file dimensions are less than those specified in the configuration.');
115
+ }
116
+ }
117
+
118
+ if ($this->max_image_width!=0 && $this->max_image_height!=0) {
119
+ if ($dimensions['width'] > $this->max_image_width || $dimensions['height'] > $this->max_image_heigh)
120
+ {
121
+ $resized_image = new Varien_Image($imgPathFull);
122
+ $resized_image->constrainOnly(TRUE);
123
+ $resized_image->keepAspectRatio(TRUE);
124
+ $resized_image->keepTransparency(TRUE);
125
+ $resized_image->resize($this->max_image_width,$this->max_image_height);
126
+ $resized_image->save($imgPathFull);
127
+ $dimensions = Mage::helper('productlookbook')->getImageDimensions($imgPathFull);
128
+ }
129
+ }
130
+ return array('success'=>true, 'filename'=>$filename . '.' . $ext, 'dimensions' => $dimensions);
131
+ } else {
132
+ return array('error'=> 'Could not save uploaded file.' .
133
+ 'The upload was cancelled, or server error encountered');
134
+ }
135
+
136
+ }
137
+ }
app/code/local/Techinflo/Productlookbook/Model/Layout/Generate/Observer.php ADDED
@@ -0,0 +1,34 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /*
3
+ * @category Techinflo
4
+ * @package Techinflo LookBook
5
+ * @author <Techinflo Team>
6
+ */
7
+ class Techinflo_Productlookbook_Model_Layout_Generate_Observer {
8
+
9
+ public function addHeadItems($observer) {
10
+ if (Mage::helper('productlookbook')->getEnabled()) {
11
+ $data = $observer->getData();
12
+ $page = $data['page'];
13
+ if ($page) {
14
+ $pagecontent = $page->getContent();
15
+ $search_string = '{{block type="productlookbook/productlookbook" template="productlookbook/productlookbook.phtml"}}';
16
+ if (preg_match($search_string, $pagecontent)) {
17
+ $updates = $page->getLayoutUpdateXml();
18
+ $newupdates = '<reference name="head">
19
+ <action method="addCss"><stylesheet>productlookbook/css/hotspots.css</stylesheet></action>
20
+ <action method="addJs"><script>jquery/jquery-1.8.2.min.js</script></action>
21
+ <action method="addJs"><script>productlookbook/jquery.mobile.customized.min.js</script></action>
22
+ <action method="addJs"><script>jquery/jquery.noconflict.js</script></action>
23
+ <action method="addItem"><type>skin_js</type><name>productlookbook/js/jquery.easing.1.3.js</name></action>
24
+ <action method="addItem"><type>skin_js</type><name>productlookbook/js/camera.min.js</name></action>
25
+ <action method="addItem"><type>skin_js</type><name>productlookbook/js/hotspots.js</name></action>
26
+ </reference>';
27
+ $page->setLayoutUpdateXml($updates.$newupdates);
28
+ }
29
+
30
+ }
31
+ }
32
+ }
33
+
34
+ }
app/code/local/Techinflo/Productlookbook/Model/Mysql4/Productlookbook.php ADDED
@@ -0,0 +1,14 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /*
3
+ * @category Techinflo
4
+ * @package Techinflo LookBook
5
+ * @author <Techinflo Team>
6
+ */
7
+ class Techinflo_Productlookbook_Model_Mysql4_Productlookbook extends Mage_Core_Model_Mysql4_Abstract
8
+ {
9
+ public function _construct()
10
+ {
11
+ // Note that the productlookbook_id refers to the key field in your database table.
12
+ $this->_init('productlookbook/productlookbook', 'productlookbook_id');
13
+ }
14
+ }
app/code/local/Techinflo/Productlookbook/Model/Mysql4/Productlookbook/Collection.php ADDED
@@ -0,0 +1,14 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /*
3
+ * @category Techinflo
4
+ * @package Techinflo LookBook
5
+ * @author <Techinflo Team>
6
+ */
7
+ class Techinflo_Productlookbook_Model_Mysql4_Productlookbook_Collection extends Mage_Core_Model_Mysql4_Collection_Abstract
8
+ {
9
+ public function _construct()
10
+ {
11
+ parent::_construct();
12
+ $this->_init('productlookbook/productlookbook');
13
+ }
14
+ }
app/code/local/Techinflo/Productlookbook/Model/Productlookbook.php ADDED
@@ -0,0 +1,18 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /*
3
+ * @category Techinflo
4
+ * @package Techinflo LookBook
5
+ * @author <Techinflo Team>
6
+ */
7
+ class Techinflo_Productlookbook_Model_Productlookbook extends Mage_Core_Model_Abstract
8
+ {
9
+ const CACHE_TAG = 'productlookbook_free';
10
+ protected $_cacheTag = 'productlookbook_free';
11
+
12
+ public function _construct()
13
+ {
14
+ parent::_construct();
15
+ $this->_init('productlookbook/productlookbook');
16
+ }
17
+
18
+ }
app/code/local/Techinflo/Productlookbook/Model/Status.php ADDED
@@ -0,0 +1,19 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /*
3
+ * @category Techinflo
4
+ * @package Techinflo LookBook
5
+ * @author <Techinflo Team>
6
+ */
7
+ class Techinflo_Productlookbook_Model_Status extends Varien_Object
8
+ {
9
+ const STATUS_ENABLED = 1;
10
+ const STATUS_DISABLED = 2;
11
+
12
+ static public function getOptionArray()
13
+ {
14
+ return array(
15
+ self::STATUS_ENABLED => Mage::helper('productlookbook')->__('Enabled'),
16
+ self::STATUS_DISABLED => Mage::helper('productlookbook')->__('Disabled')
17
+ );
18
+ }
19
+ }
app/code/local/Techinflo/Productlookbook/Model/Uploadedfileform.php ADDED
@@ -0,0 +1,26 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /*
3
+ * @category Techinflo
4
+ * @package Techinflo LookBook
5
+ * @author <Techinflo Team>
6
+ */
7
+ class Techinflo_Productlookbook_Model_Uploadedfileform {
8
+ /**
9
+ * Save the file to the specified path
10
+ * @return boolean TRUE on success
11
+ */
12
+ function save($path) {
13
+ if(!move_uploaded_file($_FILES['qqfile']['tmp_name'], $path)){
14
+ return false;
15
+ }
16
+ return true;
17
+ }
18
+ function getName() {
19
+ return $_FILES['qqfile']['name'];
20
+ }
21
+ function getSize() {
22
+ return (int)$_FILES['qqfile']['size'];
23
+ }
24
+ }
25
+
26
+
app/code/local/Techinflo/Productlookbook/Model/Uploadedfilexhr.php ADDED
@@ -0,0 +1,37 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /*
3
+ * @category Techinflo
4
+ * @package Techinflo LookBook
5
+ * @author <Techinflo Team>
6
+ */
7
+ class Techinflo_Productlookbook_Model_Uploadedfilexhr {
8
+
9
+ function save($path) {
10
+ $input = fopen("php://input", "r");
11
+ $temp = tmpfile();
12
+ $realSize = stream_copy_to_stream($input, $temp);
13
+ fclose($input);
14
+
15
+ if ($realSize != $this->getSize()){
16
+ return false;
17
+ }
18
+
19
+ $target = fopen($path, "w");
20
+ fseek($temp, 0, SEEK_SET);
21
+ stream_copy_to_stream($temp, $target);
22
+ fclose($target);
23
+
24
+ return true;
25
+ }
26
+ function getName() {
27
+ return $_GET['qqfile'];
28
+ }
29
+ function getSize() {
30
+ if (isset($_SERVER["CONTENT_LENGTH"])){
31
+ return (int)$_SERVER["CONTENT_LENGTH"];
32
+ } else {
33
+ throw new Exception('Getting content length is not supported.');
34
+ }
35
+ }
36
+ }
37
+
app/code/local/Techinflo/Productlookbook/controllers/Adminhtml/ProductlookbookController.php ADDED
@@ -0,0 +1,241 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /*
3
+ * @category Techinflo
4
+ * @package Techinflo LookBook
5
+ * @author <Techinflo Team>
6
+ */
7
+ class Techinflo_Productlookbook_Adminhtml_ProductlookbookController extends Mage_Adminhtml_Controller_Action
8
+ {
9
+
10
+ protected function _initAction() {
11
+ $this->loadLayout()
12
+ ->_setActiveMenu('cms')
13
+ ->_addBreadcrumb(Mage::helper('adminhtml')->__('Product Lookbook Slide Manager'), Mage::helper('adminhtml')->__('Product Lookbook Slide Manager'));
14
+
15
+ return $this;
16
+ }
17
+
18
+ public function indexAction() {
19
+ $this->_initAction()
20
+ ->renderLayout();
21
+ }
22
+
23
+ public function editAction() {
24
+ $slides_count = Mage::getModel('productlookbook/productlookbook')->getCollection()
25
+ ->getSize();
26
+ $id = $this->getRequest()->getParam('id');
27
+ if ($slides_count<10 || $id) {
28
+
29
+ $model = Mage::getModel('productlookbook/productlookbook')->load($id);
30
+
31
+ if ($model->getId() || $id == 0) {
32
+ $data = Mage::getSingleton('adminhtml/session')->getFormData(true);
33
+ if (!empty($data)) {
34
+ $model->setData($data);
35
+ }
36
+
37
+ Mage::register('productlookbook_data', $model);
38
+
39
+ $this->loadLayout();
40
+ $this->_setActiveMenu('cms');
41
+
42
+ $this->_addBreadcrumb(Mage::helper('adminhtml')->__('Product Lookbook Slide Manager'), Mage::helper('adminhtml')->__('Product Lookbook Slide Manager'));
43
+
44
+ $this->_addContent($this->getLayout()->createBlock('productlookbook/adminhtml_productlookbook_edit'))
45
+ ->_addLeft($this->getLayout()->createBlock('productlookbook/adminhtml_productlookbook_edit_tabs'));
46
+
47
+ $this->renderLayout();
48
+ } else {
49
+ Mage::getSingleton('adminhtml/session')->addError(Mage::helper('productlookbook')->__('Slide does not exist'));
50
+ $this->_redirect('*/*/');
51
+ }
52
+ }
53
+ else
54
+ {
55
+ Mage::getSingleton('adminhtml/session')->addError(Mage::helper('productlookbook')->__('Only up to 10 slides could be uploaded in Product Lookbook extension.'));
56
+ $this->_redirect('*/*/');
57
+ }
58
+ }
59
+
60
+ public function newAction() {
61
+ $this->_forward('edit');
62
+ }
63
+
64
+ public function saveAction() {
65
+ if ($data = $this->getRequest()->getPost()) {
66
+
67
+ $model = Mage::getModel('productlookbook/productlookbook');
68
+ $model->setData($data)
69
+ ->setId($this->getRequest()->getParam('id'));
70
+
71
+ try {
72
+
73
+ if ($model->getId() && isset($data['identifier_create_redirect']))
74
+ {
75
+ $model->setData('save_rewrites_history', (bool)$data['identifier_create_redirect']);
76
+ }
77
+
78
+ $model->save();
79
+ Mage::getSingleton('adminhtml/session')->addSuccess(Mage::helper('productlookbook')->__('Slide was successfully saved'));
80
+ Mage::getSingleton('adminhtml/session')->setFormData(false);
81
+
82
+ if ($this->getRequest()->getParam('back')) {
83
+ $this->_redirect('*/*/edit', array('id' => $model->getId()));
84
+ return;
85
+ }
86
+ $this->_redirect('*/*/');
87
+ return;
88
+ } catch (Exception $e) {
89
+ Mage::getSingleton('adminhtml/session')->addError($e->getMessage());
90
+ Mage::getSingleton('adminhtml/session')->setFormData($data);
91
+ $this->_redirect('*/*/edit', array('id' => $this->getRequest()->getParam('id')));
92
+ return;
93
+ }
94
+ }
95
+ Mage::getSingleton('adminhtml/session')->addError(Mage::helper('productlookbook')->__('Unable to find slide to save'));
96
+ $this->_redirect('*/*/');
97
+ }
98
+
99
+ public function deleteAction() {
100
+ if( $this->getRequest()->getParam('id') > 0 ) {
101
+ try {
102
+ $model = Mage::getModel('productlookbook/productlookbook');
103
+
104
+ $model->setId($this->getRequest()->getParam('id'))
105
+ ->delete();
106
+
107
+ Mage::getSingleton('adminhtml/session')->addSuccess(Mage::helper('adminhtml')->__('Slide was successfully deleted'));
108
+ $this->_redirect('*/*/');
109
+ } catch (Exception $e) {
110
+ Mage::getSingleton('adminhtml/session')->addError($e->getMessage());
111
+ $this->_redirect('*/*/edit', array('id' => $this->getRequest()->getParam('id')));
112
+ }
113
+ }
114
+ $this->_redirect('*/*/');
115
+ }
116
+
117
+ public function uploadAction()
118
+ {
119
+
120
+ $upload_dir = Mage::getBaseDir('media').'/productlookbook/';
121
+ if (!file_exists($upload_dir)) mkdir($upload_dir, 0755, true);
122
+
123
+ $uploader = Mage::getModel('productlookbook/fileuploader');
124
+
125
+ $config_check = $uploader->checkServerSettings();
126
+
127
+ if ($config_check === true){
128
+ $result = $uploader->handleUpload($upload_dir);
129
+ }
130
+ else
131
+ {
132
+ $result = $config_check;
133
+ }
134
+
135
+ // to pass data through iframe you will need to encode all html tags
136
+ $this->getResponse()->setBody(htmlspecialchars(json_encode($result), ENT_NOQUOTES));
137
+ }
138
+
139
+
140
+ public function getproductAction(){
141
+ $sku = $this->getRequest()->getParam('text');
142
+ $product_id = Mage::getModel('catalog/product')->getIdBySku($sku);
143
+ $status = Mage::getModel('catalog/product')->load($product_id)->getStatus();
144
+ if ($product_id) {
145
+ if ($status==1)
146
+ {
147
+ $result= 1;
148
+ }
149
+ else
150
+ {
151
+ $result = "is disabled";
152
+ }
153
+
154
+ }
155
+ else
156
+ {
157
+ $result = "doesn't exists";
158
+ }
159
+ $this->getResponse()->setBody($result);
160
+ }
161
+
162
+ public function massDeleteAction() {
163
+ $productlookbookIds = $this->getRequest()->getParam('productlookbook');
164
+ if(!is_array($productlookbookIds)) {
165
+ Mage::getSingleton('adminhtml/session')->addError(Mage::helper('adminhtml')->__('Please select slide(s)'));
166
+ } else {
167
+ try {
168
+ foreach ($productlookbookIds as $productlookbookId) {
169
+ $productlookbook = Mage::getModel('productlookbook/productlookbook')->load($productlookbookId);
170
+ $productlookbook->delete();
171
+ }
172
+ Mage::getSingleton('adminhtml/session')->addSuccess(
173
+ Mage::helper('adminhtml')->__(
174
+ 'Total of %d record(s) were successfully deleted', count($productlookbookIds)
175
+ )
176
+ );
177
+ } catch (Exception $e) {
178
+ Mage::getSingleton('adminhtml/session')->addError($e->getMessage());
179
+ }
180
+ }
181
+ $this->_redirect('*/*/index');
182
+ }
183
+
184
+ public function massStatusAction()
185
+ {
186
+ $productlookbookIds = $this->getRequest()->getParam('productlookbook');
187
+ if(!is_array($productlookbookIds)) {
188
+ Mage::getSingleton('adminhtml/session')->addError($this->__('Please select slide(s)'));
189
+ } else {
190
+ try {
191
+ foreach ($productlookbookIds as $productlookbookId) {
192
+ $productlookbook = Mage::getSingleton('productlookbook/productlookbook')
193
+ ->load($productlookbookId)
194
+ ->setStatus($this->getRequest()->getParam('status'))
195
+ ->setIsMassupdate(true)
196
+ ->save();
197
+ }
198
+ $this->_getSession()->addSuccess(
199
+ $this->__('Total of %d record(s) were successfully updated', count($productlookbookIds))
200
+ );
201
+ } catch (Exception $e) {
202
+ $this->_getSession()->addError($e->getMessage());
203
+ }
204
+ }
205
+ $this->_redirect('*/*/index');
206
+ }
207
+
208
+ public function exportCsvAction()
209
+ {
210
+ $fileName = 'productlookbook.csv';
211
+ $content = $this->getLayout()->createBlock('productlookbook/adminhtml_productlookbook_grid')
212
+ ->getCsv();
213
+
214
+ $this->_sendUploadResponse($fileName, $content);
215
+ }
216
+
217
+ public function exportXmlAction()
218
+ {
219
+ $fileName = 'productlookbook.xml';
220
+ $content = $this->getLayout()->createBlock('productlookbook/adminhtml_productlookbook_grid')
221
+ ->getXml();
222
+
223
+ $this->_sendUploadResponse($fileName, $content);
224
+ }
225
+
226
+ protected function _sendUploadResponse($fileName, $content, $contentType='application/octet-stream')
227
+ {
228
+ $response = $this->getResponse();
229
+ $response->setHeader('HTTP/1.1 200 OK','');
230
+ $response->setHeader('Pragma', 'public', true);
231
+ $response->setHeader('Cache-Control', 'must-revalidate, post-check=0, pre-check=0', true);
232
+ $response->setHeader('Content-Disposition', 'attachment; filename='.$fileName);
233
+ $response->setHeader('Last-Modified', date('r'));
234
+ $response->setHeader('Accept-Ranges', 'bytes');
235
+ $response->setHeader('Content-Length', strlen($content));
236
+ $response->setHeader('Content-type', $contentType);
237
+ $response->setBody($content);
238
+ $response->sendResponse();
239
+ die;
240
+ }
241
+ }
app/code/local/Techinflo/Productlookbook/controllers/IndexController.php ADDED
@@ -0,0 +1,33 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /*
3
+ * @category Techinflo
4
+ * @package Techinflo LookBook
5
+ * @author <Techinflo Team>
6
+ */
7
+ class Techinflo_Productlookbook_IndexController extends Mage_Core_Controller_Front_Action
8
+ {
9
+ public function indexAction()
10
+ {
11
+ if (Mage::helper('productlookbook')->getEnabled()) {
12
+ $this->loadLayout();
13
+ $this->renderLayout();
14
+ }
15
+ else
16
+ {
17
+ $this->_forward('*/*/noRouteAction');
18
+ }
19
+
20
+ }
21
+
22
+ public function noRouteAction($coreRoute = null)
23
+ {
24
+ //modify this method as you need
25
+ $this->getResponse()->setHeader('HTTP/1.1','404 Not Found');
26
+ $this->getResponse()->setHeader('Status','404 File not found');
27
+ $pageId = Mage::getStoreConfig('web/default/cms_no_route');
28
+ if (!Mage::helper('cms/page')->renderPage($this, $pageId)) {
29
+ $this->_forward('defaultNoRoute');
30
+ }
31
+ }
32
+
33
+ }
app/code/local/Techinflo/Productlookbook/etc/config.xml ADDED
@@ -0,0 +1,159 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?xml version="1.0"?>
2
+ <!--
3
+ /*
4
+ * @category Techinflo
5
+ * @package Techinflo LookBook
6
+ * @author <Techinflo Team>
7
+ */
8
+ -->
9
+ <config>
10
+ <modules>
11
+ <Techinflo_Productlookbook>
12
+ <version>1.0.3</version>
13
+ </Techinflo_Productlookbook>
14
+ </modules>
15
+ <frontend>
16
+ <routers>
17
+ <productlookbook>
18
+ <use>standard</use>
19
+ <args>
20
+ <module>Techinflo_Productlookbook</module>
21
+ <frontName>productlookbook</frontName>
22
+ </args>
23
+ </productlookbook>
24
+ </routers>
25
+ <layout>
26
+ <updates>
27
+ <productlookbook>
28
+ <file>productlookbook.xml</file>
29
+ </productlookbook>
30
+ </updates>
31
+ </layout>
32
+ </frontend>
33
+ <admin>
34
+ <routers>
35
+ <productlookbook>
36
+ <use>admin</use>
37
+ <args>
38
+ <module>Techinflo_Productlookbook</module>
39
+ <frontName>productlookbook</frontName>
40
+ </args>
41
+ </productlookbook>
42
+ </routers>
43
+ </admin>
44
+ <adminhtml>
45
+ <menu>
46
+ <cms>
47
+ <children>
48
+ <productlookbook translate="title" module="productlookbook">
49
+ <title>Product Look Book</title>
50
+ <action>productlookbook/adminhtml_productlookbook</action>
51
+ </productlookbook>
52
+ </children>
53
+ </cms>
54
+ </menu>
55
+ <acl>
56
+ <resources>
57
+ <admin>
58
+ <children>
59
+ <cms>
60
+ <children>
61
+ <productlookbook>
62
+ <title>Product Look Book</title>
63
+ </productlookbook>
64
+ </children>
65
+ </cms>
66
+ <system>
67
+ <children>
68
+ <config>
69
+ <children>
70
+ <productlookbook>
71
+ <title>Product Look Book</title>
72
+ </productlookbook>
73
+ </children>
74
+ </config>
75
+ </children>
76
+ </system>
77
+ </children>
78
+ </admin>
79
+ </resources>
80
+ </acl>
81
+ <layout>
82
+ <updates>
83
+ <productlookbook>
84
+ <file>productlookbook.xml</file>
85
+ </productlookbook>
86
+ </updates>
87
+ </layout>
88
+ </adminhtml>
89
+ <default>
90
+ <productlookbook>
91
+ <general>
92
+ <enabled>1</enabled>
93
+ <min_image_width>300</min_image_width>
94
+ <min_image_height>400</min_image_height>
95
+ <max_image_width>450</max_image_width>
96
+ <max_image_height>600</max_image_height>
97
+ <max_upload_filesize>2097152</max_upload_filesize>
98
+ <allowed_extensions>jpg,jpeg,png,gif</allowed_extensions>
99
+ </general>
100
+ </productlookbook>
101
+ </default>
102
+ <global>
103
+ <models>
104
+ <productlookbook>
105
+ <class>Techinflo_Productlookbook_Model</class>
106
+ <resourceModel>productlookbook_mysql4</resourceModel>
107
+ </productlookbook>
108
+ <productlookbook_mysql4>
109
+ <class>Techinflo_Productlookbook_Model_Mysql4</class>
110
+ <entities>
111
+ <productlookbook>
112
+ <table>productlookbook</table>
113
+ </productlookbook>
114
+ </entities>
115
+ </productlookbook_mysql4>
116
+ </models>
117
+ <resources>
118
+ <productlookbook_setup>
119
+ <setup>
120
+ <module>Techinflo_Productlookbook</module>
121
+ </setup>
122
+ <connection>
123
+ <use>core_setup</use>
124
+ </connection>
125
+ </productlookbook_setup>
126
+ <productlookbook_write>
127
+ <connection>
128
+ <use>core_write</use>
129
+ </connection>
130
+ </productlookbook_write>
131
+ <productlookbook_read>
132
+ <connection>
133
+ <use>core_read</use>
134
+ </connection>
135
+ </productlookbook_read>
136
+ </resources>
137
+ <blocks>
138
+ <productlookbook>
139
+ <class>Techinflo_Productlookbook_Block</class>
140
+ </productlookbook>
141
+ </blocks>
142
+ <helpers>
143
+ <productlookbook>
144
+ <class>Techinflo_Productlookbook_Helper</class>
145
+ </productlookbook>
146
+ </helpers>
147
+ <events>
148
+ <cms_page_render>
149
+ <observers>
150
+ <productlookbook_layout_generate_observer>
151
+ <type>singleton</type>
152
+ <class>productlookbook/layout_generate_observer</class>
153
+ <method>addHeadItems</method>
154
+ </productlookbook_layout_generate_observer>
155
+ </observers>
156
+ </cms_page_render>
157
+ </events>
158
+ </global>
159
+ </config>
app/code/local/Techinflo/Productlookbook/etc/system.xml ADDED
@@ -0,0 +1,176 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?xml version="1.0"?>
2
+
3
+ <config>
4
+ <tabs>
5
+ <techinflo translate="label comment" module="productlookbook">
6
+ <label>Techinflo</label>
7
+ <sort_order>500</sort_order>
8
+ </techinflo>
9
+ </tabs>
10
+ <sections>
11
+ <productlookbook translate="label comment" module="productlookbook">
12
+ <tab>techinflo</tab>
13
+ <label>Product Look Book</label>
14
+ <frontend_type>text</frontend_type>
15
+ <sort_order>800</sort_order>
16
+ <show_in_default>1</show_in_default>
17
+ <show_in_website>1</show_in_website>
18
+ <show_in_store>1</show_in_store>
19
+ <groups>
20
+ <general translate="label comment" module="productlookbook">
21
+ <label>General Settings</label>
22
+ <frontend_type>text</frontend_type>
23
+ <sort_order>10</sort_order>
24
+ <show_in_default>1</show_in_default>
25
+ <show_in_website>1</show_in_website>
26
+ <show_in_store>1</show_in_store>
27
+ <fields>
28
+ <enabled translate="label">
29
+ <label>Enabled</label>
30
+ <frontend_type>select</frontend_type>
31
+ <source_model>adminhtml/system_config_source_yesno</source_model>
32
+ <sort_order>10</sort_order>
33
+ <show_in_default>1</show_in_default>
34
+ <show_in_website>1</show_in_website>
35
+ <show_in_store>1</show_in_store>
36
+ </enabled>
37
+ <min_image_width translate="label">
38
+ <label>Minimal Image Width (px)</label>
39
+ <frontend_type>text</frontend_type>
40
+ <sort_order>20</sort_order>
41
+ <show_in_default>1</show_in_default>
42
+ <show_in_website>1</show_in_website>
43
+ <show_in_store>1</show_in_store>
44
+ <comment><![CDATA[Integer value. Must be less then Maximal Image Width.]]></comment>
45
+ </min_image_width>
46
+ <min_image_height translate="label">
47
+ <label>Minimal Image Height (px)</label>
48
+ <frontend_type>text</frontend_type>
49
+ <sort_order>30</sort_order>
50
+ <show_in_default>1</show_in_default>
51
+ <show_in_website>1</show_in_website>
52
+ <show_in_store>1</show_in_store>
53
+ <comment><![CDATA[Integer value. Must be less then Maximal Image Height.]]></comment>
54
+ </min_image_height>
55
+ <max_image_width translate="label">
56
+ <label>Maximal Image Width (px)</label>
57
+ <frontend_type>text</frontend_type>
58
+ <sort_order>40</sort_order>
59
+ <show_in_default>1</show_in_default>
60
+ <show_in_website>1</show_in_website>
61
+ <show_in_store>1</show_in_store>
62
+ <comment><![CDATA[Integer value. Must be greater then Minimal Image Width.]]></comment>
63
+ </max_image_width>
64
+ <max_image_height translate="label">
65
+ <label>Maximal Image Height (px)</label>
66
+ <frontend_type>text</frontend_type>
67
+ <sort_order>50</sort_order>
68
+ <show_in_default>1</show_in_default>
69
+ <show_in_website>1</show_in_website>
70
+ <show_in_store>1</show_in_store>
71
+ <comment><![CDATA[Integer value. Must be greater then Minimal Image Height.]]></comment>
72
+ </max_image_height>
73
+ <max_upload_filesize translate="label">
74
+ <label>Uploaded file max size (bytes)</label>
75
+ <frontend_type>text</frontend_type>
76
+ <sort_order>60</sort_order>
77
+ <show_in_default>1</show_in_default>
78
+ <show_in_website>1</show_in_website>
79
+ <show_in_store>1</show_in_store>
80
+ <comment><![CDATA[Integer value. Must be less then upload_max_filesize and post_max_size in php.ini]]></comment>
81
+ </max_upload_filesize>
82
+ <allowed_extensions translate="label">
83
+ <label>Allowed extensions</label>
84
+ <frontend_type>text</frontend_type>
85
+ <sort_order>70</sort_order>
86
+ <show_in_default>1</show_in_default>
87
+ <show_in_website>1</show_in_website>
88
+ <show_in_store>1</show_in_store>
89
+ <comment><![CDATA[Comma separated file extensions. Example, "jpg,gif,png"]]></comment>
90
+ </allowed_extensions>
91
+ <effects translate="label">
92
+ <label>Effect</label>
93
+ <frontend_type>multiselect</frontend_type>
94
+ <source_model>productlookbook/config_source_effect</source_model>
95
+ <sort_order>80</sort_order>
96
+ <show_in_default>1</show_in_default>
97
+ <show_in_website>1</show_in_website>
98
+ <show_in_store>1</show_in_store>
99
+ <can_be_empty>1</can_be_empty>
100
+ <comment><![CDATA[You can use more than one effect or leave empty to use the random effect.]]></comment>
101
+ </effects>
102
+ <navigation translate="label">
103
+ <label>Show navigation</label>
104
+ <frontend_type>select</frontend_type>
105
+ <source_model>adminhtml/system_config_source_yesno</source_model>
106
+ <sort_order>90</sort_order>
107
+ <show_in_default>1</show_in_default>
108
+ <show_in_website>1</show_in_website>
109
+ <show_in_store>1</show_in_store>
110
+ <comment><![CDATA[If YES the navigation button (prev, next and play/stop buttons) will be visible, if NO they will be always hidden.]]></comment>
111
+ </navigation>
112
+ <navigation_hover translate="label">
113
+ <label>Navigation on hover state only</label>
114
+ <frontend_type>select</frontend_type>
115
+ <source_model>adminhtml/system_config_source_yesno</source_model>
116
+ <sort_order>100</sort_order>
117
+ <show_in_default>1</show_in_default>
118
+ <show_in_website>1</show_in_website>
119
+ <show_in_store>1</show_in_store>
120
+ <comment><![CDATA[If YES the navigation button (prev, next and play/stop buttons) will be visible on hover state only, if NO they will be visible always.]]></comment>
121
+ </navigation_hover>
122
+ <thumbnails translate="label">
123
+ <label>Show thumbnails</label>
124
+ <frontend_type>select</frontend_type>
125
+ <source_model>adminhtml/system_config_source_yesno</source_model>
126
+ <sort_order>110</sort_order>
127
+ <show_in_default>1</show_in_default>
128
+ <show_in_website>1</show_in_website>
129
+ <show_in_store>1</show_in_store>
130
+ <comment><![CDATA[If YES the thumbnails will be visible, if NO will show the pagination.]]></comment>
131
+ </thumbnails>
132
+ <pause translate="label">
133
+ <label>Pause</label>
134
+ <frontend_type>text</frontend_type>
135
+ <sort_order>120</sort_order>
136
+ <show_in_default>1</show_in_default>
137
+ <show_in_website>1</show_in_website>
138
+ <show_in_store>1</show_in_store>
139
+ <comment><![CDATA[Milliseconds between the end of the sliding effect and the start of the next one]]></comment>
140
+ </pause>
141
+ <transition_duration translate="label">
142
+ <label>Transition duration</label>
143
+ <frontend_type>text</frontend_type>
144
+ <sort_order>130</sort_order>
145
+ <show_in_default>1</show_in_default>
146
+ <show_in_website>1</show_in_website>
147
+ <show_in_store>1</show_in_store>
148
+ <comment><![CDATA[Length of the sliding effect in milliseconds.]]></comment>
149
+ </transition_duration>
150
+ <hotspot_iconselect translate="label">
151
+ <label>Upload Custom Hotspot Icon</label>
152
+ <frontend_type>select</frontend_type>
153
+ <source_model>adminhtml/system_config_source_yesno</source_model>
154
+ <sort_order>132</sort_order>
155
+ <show_in_default>1</show_in_default>
156
+ <show_in_website>1</show_in_website>
157
+ <show_in_store>1</show_in_store>
158
+ </hotspot_iconselect>
159
+ <hotspot_icon translate="label comment">
160
+ <label>Hotspot Icon</label>
161
+ <frontend_type>image</frontend_type>
162
+ <backend_model>adminhtml/system_config_backend_image</backend_model>
163
+ <upload_dir config="system/filesystem/media" scope_info="1">productlookbook/icons/</upload_dir>
164
+ <base_url type="media" scope_info="1">productlookbook/icons/</base_url>
165
+ <sort_order>135</sort_order>
166
+ <show_in_default>1</show_in_default>
167
+ <show_in_website>1</show_in_website>
168
+ <show_in_store>1</show_in_store>
169
+ <comment><![CDATA[Upload 30*30 png format size Icon.]]></comment>
170
+ </hotspot_icon>
171
+ </fields>
172
+ </general>
173
+ </groups>
174
+ </productlookbook>
175
+ </sections>
176
+ </config>
app/code/local/Techinflo/Productlookbook/sql/productlookbook_setup/mysql4-install-1.0.2.php ADDED
@@ -0,0 +1,30 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /*
3
+ * @category Techinflo
4
+ * @package Techinflo LookBook
5
+ * @author <Techinflo Team>
6
+ */
7
+
8
+ $installer = $this;
9
+
10
+ $installer->startSetup();
11
+
12
+ $installer->run("
13
+
14
+ -- DROP TABLE IF EXISTS {$this->getTable('productlookbook')};
15
+ CREATE TABLE {$this->getTable('productlookbook')} (
16
+ `productlookbook_id` int(11) unsigned NOT NULL auto_increment,
17
+ `name` varchar(255) NOT NULL default '',
18
+ `image` varchar(255) NOT NULL default '',
19
+ `hotspots` text NOT NULL default '',
20
+ `position` smallint(5) unsigned NOT NULL,
21
+ `status` smallint(6) NOT NULL default '0',
22
+ PRIMARY KEY (`productlookbook_id`),
23
+ KEY `IDX_LOOKBOOK_LOOKBOOK_ID` (`productlookbook_id`)
24
+ ) ENGINE=InnoDB DEFAULT CHARSET=utf8;
25
+
26
+ ");
27
+
28
+ $installer->setConfigData('productlookbook/general/hotspot_icon/','default/hotspot-icon.png');
29
+
30
+ $installer->endSetup();
app/code/local/Techinflo/Productlookbook/sql/productlookbook_setup/mysql4-upgrade-1.0.2-1.0.3.php ADDED
@@ -0,0 +1,8 @@
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ $installer = $this;
4
+ /* @var $installer Mage_Core_Model_Resource_Setup */
5
+
6
+ $installer->startSetup();
7
+
8
+ $installer->endSetup();
app/design/adminhtml/default/default/layout/productlookbook.xml ADDED
@@ -0,0 +1,27 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?xml version="1.0"?>
2
+ <!--
3
+ /*
4
+ * @category Techinflo
5
+ * @package Techinflo LookBook
6
+ * @author <Techinflo Team>
7
+ */
8
+ -->
9
+ <layout version="0.1.0">
10
+ <productlookbook_adminhtml_productlookbook_index>
11
+ <reference name="content">
12
+ <block type="productlookbook/adminhtml_productlookbook" name="productlookbook" />
13
+ </reference>
14
+ </productlookbook_adminhtml_productlookbook_index>
15
+ <productlookbook_adminhtml_productlookbook_edit>
16
+ <reference name="head">
17
+ <action method="addCss"><stylesheet>productlookbook/css/annotation.css</stylesheet></action>
18
+ <action method="addCss"><stylesheet>productlookbook/css/fileuploader.css</stylesheet></action>
19
+ <action method="addJs"><script>jquery/jquery-1.8.2.min.js</script></action>
20
+ <action method="addJs"><script>jquery/jquery.noconflict.js</script></action>
21
+ <action method="addJs"><script>productlookbook/jquery-ui-1.9.1.js</script></action>
22
+ <action method="addJs"><script>productlookbook/jquery.annotate.js</script></action>
23
+ <action method="addJs"><script>productlookbook/fileuploader.js</script></action>
24
+ <action method="addJs"><script>productlookbook/json2.min.js</script></action>
25
+ </reference>
26
+ </productlookbook_adminhtml_productlookbook_edit>
27
+ </layout>
app/design/frontend/default/default/layout/productlookbook.xml ADDED
@@ -0,0 +1,25 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?xml version="1.0"?>
2
+ <!--
3
+ /*
4
+ * @category Techinflo
5
+ * @package Techinflo LookBook
6
+ * @author <Techinflo Team>
7
+ */
8
+ -->
9
+ <layout version="0.1.0">
10
+ <default>
11
+ </default>
12
+ <productlookbook_index_index>
13
+ <reference name="head">
14
+ <action method="addCss"><stylesheet>productlookbook/css/hotspots.css</stylesheet></action>
15
+ <action method="addJs"><script>jquery/jquery-1.8.2.min.js</script></action>
16
+ <action method="addJs"><script>jquery/jquery.noconflict.js</script></action>
17
+ <action method="addItem"><type>skin_js</type><name>productlookbook/js/jquery.easing.1.3.js</name></action>
18
+ <action method="addItem"><type>skin_js</type><name>productlookbook/js/camera.min.js</name></action>
19
+ <action method="addItem"><type>skin_js</type><name>productlookbook/js/hotspots.js</name></action>
20
+ </reference>
21
+ <reference name="content">
22
+ <block type="productlookbook/productlookbook" name="productlookbook" template="productlookbook/productlookbook.phtml" />
23
+ </reference>
24
+ </productlookbook_index_index>
25
+ </layout>
app/design/frontend/default/default/template/productlookbook/productlookbook.phtml ADDED
@@ -0,0 +1,71 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /*
3
+ * @category Techinflo
4
+ * @package Techinflo LookBook
5
+ * @author <Techinflo Team>
6
+ */
7
+ $helper = Mage::helper('productlookbook');
8
+
9
+ if ($helper->getEnabled()) :
10
+
11
+ $makets = $this->getCollection();
12
+
13
+ $width = $helper->getMaxImageWidth();
14
+ $height = $helper->getMaxImageHeight();
15
+ $effects = $helper->getEffects();
16
+ if (!$effects || $effects=='') $effects = 'random';
17
+ $navigation = ($helper->getNavigation()==1) ? 'true' : 'false';
18
+ $navigationHover = ($helper->getNavigationHover()==1) ? 'true' : 'false';
19
+ $thumbnails = ($helper->getThumbnails()==1) ? 'true' : 'false';
20
+ $pause = ($helper->getPause()) ? $helper->getPause() : 7000;
21
+ $trans_period = ($helper->getTransitionDuration()) ? $helper->getTransitionDuration() : 1500;
22
+ $hotspots = array();
23
+
24
+ if ($makets->getSize()) :
25
+ ?>
26
+ <div class="camera_wrap camera_black_skin" id="productlookbook" style="width:<?php echo $width;?>px;">
27
+ <?php foreach ($makets as $image): ?>
28
+ <div data-thumb="<?php echo $helper->getResizedUrl($image->getData('image'), 100, 100);?>" data-src="<?php echo $helper->getResizedUrl($image->getData('image'), $width, $height);?>">
29
+ <?php echo base64_decode('PGRpdiBpZD0iYWR2X2xpbmsiPjxkaXY+UG93ZXJlZCBieSA8YSBocmVmPSJodHRwOi8vc2hvcC5hbHRpbWEubmV0LmF1L21hZ2VudG8tZXh0ZW5zaW9ucy5odG1sIiB0aXRsZT0iQWx0aW1hIFdlYiBTeXN0ZW1zIiB0YXJnZXQ9Il9ibGFuayI+QWx0aW1hPC9hPjwvZGl2PjwvZGl2Pg==');?>
30
+ <img src="<?php echo $helper->getResizedUrl($image->getData('image'), $width, $height);?>" alt="Slide <?php echo $image->getId();?>"/>
31
+ <?php if($image->getName()!='') :?>
32
+ <div class="camera_caption fadeFromBottom">
33
+ <?php echo $image->getName();?>
34
+ </div>
35
+ <?php endif;?>
36
+ </div>
37
+ <?php $hotspots[] = $helper->getHotspotsWithProductDetails($image->getHotspots()); ?>
38
+ <?php endforeach; ?>
39
+ </div>
40
+
41
+ <script type="text/javascript">
42
+ //<![CDATA[
43
+ jQuery(document).ready(function(){
44
+ jQuery('#productlookbook').camera({
45
+ fx: '<?php echo $effects;?>',
46
+ navigation: <?php echo $navigation;?>,
47
+ navigationHover: <?php echo $navigationHover;?>,
48
+ <?php if ($thumbnails=='true'): ?>
49
+ pagination: false,
50
+ thumbnails: true,
51
+ <?php else: ?>
52
+ pagination: true,
53
+ thumbnails: false,
54
+ <?php endif; ?>
55
+ time: <?php echo $pause;?>,
56
+ trans_period: <?php echo $trans_period;?>,
57
+ piePosition: 'leftTop',
58
+ height: '<?php echo $height;?>px',
59
+ width: '<?php echo $width;?>px'
60
+ });
61
+ var hotspots = <?php echo json_encode($hotspots);?>;
62
+ jQuery('#productlookbook .cameraContent').each(function(){
63
+ var ind = jQuery(this).index();
64
+ jQuery.setHotspots(jQuery(this), hotspots[ind]);
65
+ });
66
+ });
67
+ //]]>
68
+ </script>
69
+ <?php endif;?>
70
+ <?php endif;?>
71
+
app/etc/modules/Techinflo_Productlookbook.xml ADDED
@@ -0,0 +1,21 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?xml version="1.0"?>
2
+ <!--
3
+ /*
4
+ * @category Techinflo
5
+ * @package Techinflo Product LookBook
6
+ * @author <Techinflo Team>
7
+ */
8
+ -->
9
+ <config>
10
+ <modules>
11
+ <Techinflo_Productlookbook>
12
+ <active>true</active>
13
+ <codePool>local</codePool>
14
+ <depends>
15
+ <Mage_Core/>
16
+ <Mage_Adminhtml/>
17
+ <Mage_Catalog/>
18
+ </depends>
19
+ </Techinflo_Productlookbook>
20
+ </modules>
21
+ </config>
js/jquery/jquery-1.8.2.min.js ADDED
@@ -0,0 +1,2 @@
 
 
1
+ /*! jQuery v1.8.2 jquery.com | jquery.org/license */
2
+ (function(a,b){function G(a){var b=F[a]={};return p.each(a.split(s),function(a,c){b[c]=!0}),b}function J(a,c,d){if(d===b&&a.nodeType===1){var e="data-"+c.replace(I,"-$1").toLowerCase();d=a.getAttribute(e);if(typeof d=="string"){try{d=d==="true"?!0:d==="false"?!1:d==="null"?null:+d+""===d?+d:H.test(d)?p.parseJSON(d):d}catch(f){}p.data(a,c,d)}else d=b}return d}function K(a){var b;for(b in a){if(b==="data"&&p.isEmptyObject(a[b]))continue;if(b!=="toJSON")return!1}return!0}function ba(){return!1}function bb(){return!0}function bh(a){return!a||!a.parentNode||a.parentNode.nodeType===11}function bi(a,b){do a=a[b];while(a&&a.nodeType!==1);return a}function bj(a,b,c){b=b||0;if(p.isFunction(b))return p.grep(a,function(a,d){var e=!!b.call(a,d,a);return e===c});if(b.nodeType)return p.grep(a,function(a,d){return a===b===c});if(typeof b=="string"){var d=p.grep(a,function(a){return a.nodeType===1});if(be.test(b))return p.filter(b,d,!c);b=p.filter(b,d)}return p.grep(a,function(a,d){return p.inArray(a,b)>=0===c})}function bk(a){var b=bl.split("|"),c=a.createDocumentFragment();if(c.createElement)while(b.length)c.createElement(b.pop());return c}function bC(a,b){return a.getElementsByTagName(b)[0]||a.appendChild(a.ownerDocument.createElement(b))}function bD(a,b){if(b.nodeType!==1||!p.hasData(a))return;var c,d,e,f=p._data(a),g=p._data(b,f),h=f.events;if(h){delete g.handle,g.events={};for(c in h)for(d=0,e=h[c].length;d<e;d++)p.event.add(b,c,h[c][d])}g.data&&(g.data=p.extend({},g.data))}function bE(a,b){var c;if(b.nodeType!==1)return;b.clearAttributes&&b.clearAttributes(),b.mergeAttributes&&b.mergeAttributes(a),c=b.nodeName.toLowerCase(),c==="object"?(b.parentNode&&(b.outerHTML=a.outerHTML),p.support.html5Clone&&a.innerHTML&&!p.trim(b.innerHTML)&&(b.innerHTML=a.innerHTML)):c==="input"&&bv.test(a.type)?(b.defaultChecked=b.checked=a.checked,b.value!==a.value&&(b.value=a.value)):c==="option"?b.selected=a.defaultSelected:c==="input"||c==="textarea"?b.defaultValue=a.defaultValue:c==="script"&&b.text!==a.text&&(b.text=a.text),b.removeAttribute(p.expando)}function bF(a){return typeof a.getElementsByTagName!="undefined"?a.getElementsByTagName("*"):typeof a.querySelectorAll!="undefined"?a.querySelectorAll("*"):[]}function bG(a){bv.test(a.type)&&(a.defaultChecked=a.checked)}function bY(a,b){if(b in a)return b;var c=b.charAt(0).toUpperCase()+b.slice(1),d=b,e=bW.length;while(e--){b=bW[e]+c;if(b in a)return b}return d}function bZ(a,b){return a=b||a,p.css(a,"display")==="none"||!p.contains(a.ownerDocument,a)}function b$(a,b){var c,d,e=[],f=0,g=a.length;for(;f<g;f++){c=a[f];if(!c.style)continue;e[f]=p._data(c,"olddisplay"),b?(!e[f]&&c.style.display==="none"&&(c.style.display=""),c.style.display===""&&bZ(c)&&(e[f]=p._data(c,"olddisplay",cc(c.nodeName)))):(d=bH(c,"display"),!e[f]&&d!=="none"&&p._data(c,"olddisplay",d))}for(f=0;f<g;f++){c=a[f];if(!c.style)continue;if(!b||c.style.display==="none"||c.style.display==="")c.style.display=b?e[f]||"":"none"}return a}function b_(a,b,c){var d=bP.exec(b);return d?Math.max(0,d[1]-(c||0))+(d[2]||"px"):b}function ca(a,b,c,d){var e=c===(d?"border":"content")?4:b==="width"?1:0,f=0;for(;e<4;e+=2)c==="margin"&&(f+=p.css(a,c+bV[e],!0)),d?(c==="content"&&(f-=parseFloat(bH(a,"padding"+bV[e]))||0),c!=="margin"&&(f-=parseFloat(bH(a,"border"+bV[e]+"Width"))||0)):(f+=parseFloat(bH(a,"padding"+bV[e]))||0,c!=="padding"&&(f+=parseFloat(bH(a,"border"+bV[e]+"Width"))||0));return f}function cb(a,b,c){var d=b==="width"?a.offsetWidth:a.offsetHeight,e=!0,f=p.support.boxSizing&&p.css(a,"boxSizing")==="border-box";if(d<=0||d==null){d=bH(a,b);if(d<0||d==null)d=a.style[b];if(bQ.test(d))return d;e=f&&(p.support.boxSizingReliable||d===a.style[b]),d=parseFloat(d)||0}return d+ca(a,b,c||(f?"border":"content"),e)+"px"}function cc(a){if(bS[a])return bS[a];var b=p("<"+a+">").appendTo(e.body),c=b.css("display");b.remove();if(c==="none"||c===""){bI=e.body.appendChild(bI||p.extend(e.createElement("iframe"),{frameBorder:0,width:0,height:0}));if(!bJ||!bI.createElement)bJ=(bI.contentWindow||bI.contentDocument).document,bJ.write("<!doctype html><html><body>"),bJ.close();b=bJ.body.appendChild(bJ.createElement(a)),c=bH(b,"display"),e.body.removeChild(bI)}return bS[a]=c,c}function ci(a,b,c,d){var e;if(p.isArray(b))p.each(b,function(b,e){c||ce.test(a)?d(a,e):ci(a+"["+(typeof e=="object"?b:"")+"]",e,c,d)});else if(!c&&p.type(b)==="object")for(e in b)ci(a+"["+e+"]",b[e],c,d);else d(a,b)}function cz(a){return function(b,c){typeof b!="string"&&(c=b,b="*");var d,e,f,g=b.toLowerCase().split(s),h=0,i=g.length;if(p.isFunction(c))for(;h<i;h++)d=g[h],f=/^\+/.test(d),f&&(d=d.substr(1)||"*"),e=a[d]=a[d]||[],e[f?"unshift":"push"](c)}}function cA(a,c,d,e,f,g){f=f||c.dataTypes[0],g=g||{},g[f]=!0;var h,i=a[f],j=0,k=i?i.length:0,l=a===cv;for(;j<k&&(l||!h);j++)h=i[j](c,d,e),typeof h=="string"&&(!l||g[h]?h=b:(c.dataTypes.unshift(h),h=cA(a,c,d,e,h,g)));return(l||!h)&&!g["*"]&&(h=cA(a,c,d,e,"*",g)),h}function cB(a,c){var d,e,f=p.ajaxSettings.flatOptions||{};for(d in c)c[d]!==b&&((f[d]?a:e||(e={}))[d]=c[d]);e&&p.extend(!0,a,e)}function cC(a,c,d){var e,f,g,h,i=a.contents,j=a.dataTypes,k=a.responseFields;for(f in k)f in d&&(c[k[f]]=d[f]);while(j[0]==="*")j.shift(),e===b&&(e=a.mimeType||c.getResponseHeader("content-type"));if(e)for(f in i)if(i[f]&&i[f].test(e)){j.unshift(f);break}if(j[0]in d)g=j[0];else{for(f in d){if(!j[0]||a.converters[f+" "+j[0]]){g=f;break}h||(h=f)}g=g||h}if(g)return g!==j[0]&&j.unshift(g),d[g]}function cD(a,b){var c,d,e,f,g=a.dataTypes.slice(),h=g[0],i={},j=0;a.dataFilter&&(b=a.dataFilter(b,a.dataType));if(g[1])for(c in a.converters)i[c.toLowerCase()]=a.converters[c];for(;e=g[++j];)if(e!=="*"){if(h!=="*"&&h!==e){c=i[h+" "+e]||i["* "+e];if(!c)for(d in i){f=d.split(" ");if(f[1]===e){c=i[h+" "+f[0]]||i["* "+f[0]];if(c){c===!0?c=i[d]:i[d]!==!0&&(e=f[0],g.splice(j--,0,e));break}}}if(c!==!0)if(c&&a["throws"])b=c(b);else try{b=c(b)}catch(k){return{state:"parsererror",error:c?k:"No conversion from "+h+" to "+e}}}h=e}return{state:"success",data:b}}function cL(){try{return new a.XMLHttpRequest}catch(b){}}function cM(){try{return new a.ActiveXObject("Microsoft.XMLHTTP")}catch(b){}}function cU(){return setTimeout(function(){cN=b},0),cN=p.now()}function cV(a,b){p.each(b,function(b,c){var d=(cT[b]||[]).concat(cT["*"]),e=0,f=d.length;for(;e<f;e++)if(d[e].call(a,b,c))return})}function cW(a,b,c){var d,e=0,f=0,g=cS.length,h=p.Deferred().always(function(){delete i.elem}),i=function(){var b=cN||cU(),c=Math.max(0,j.startTime+j.duration-b),d=1-(c/j.duration||0),e=0,f=j.tweens.length;for(;e<f;e++)j.tweens[e].run(d);return h.notifyWith(a,[j,d,c]),d<1&&f?c:(h.resolveWith(a,[j]),!1)},j=h.promise({elem:a,props:p.extend({},b),opts:p.extend(!0,{specialEasing:{}},c),originalProperties:b,originalOptions:c,startTime:cN||cU(),duration:c.duration,tweens:[],createTween:function(b,c,d){var e=p.Tween(a,j.opts,b,c,j.opts.specialEasing[b]||j.opts.easing);return j.tweens.push(e),e},stop:function(b){var c=0,d=b?j.tweens.length:0;for(;c<d;c++)j.tweens[c].run(1);return b?h.resolveWith(a,[j,b]):h.rejectWith(a,[j,b]),this}}),k=j.props;cX(k,j.opts.specialEasing);for(;e<g;e++){d=cS[e].call(j,a,k,j.opts);if(d)return d}return cV(j,k),p.isFunction(j.opts.start)&&j.opts.start.call(a,j),p.fx.timer(p.extend(i,{anim:j,queue:j.opts.queue,elem:a})),j.progress(j.opts.progress).done(j.opts.done,j.opts.complete).fail(j.opts.fail).always(j.opts.always)}function cX(a,b){var c,d,e,f,g;for(c in a){d=p.camelCase(c),e=b[d],f=a[c],p.isArray(f)&&(e=f[1],f=a[c]=f[0]),c!==d&&(a[d]=f,delete a[c]),g=p.cssHooks[d];if(g&&"expand"in g){f=g.expand(f),delete a[d];for(c in f)c in a||(a[c]=f[c],b[c]=e)}else b[d]=e}}function cY(a,b,c){var d,e,f,g,h,i,j,k,l=this,m=a.style,n={},o=[],q=a.nodeType&&bZ(a);c.queue||(j=p._queueHooks(a,"fx"),j.unqueued==null&&(j.unqueued=0,k=j.empty.fire,j.empty.fire=function(){j.unqueued||k()}),j.unqueued++,l.always(function(){l.always(function(){j.unqueued--,p.queue(a,"fx").length||j.empty.fire()})})),a.nodeType===1&&("height"in b||"width"in b)&&(c.overflow=[m.overflow,m.overflowX,m.overflowY],p.css(a,"display")==="inline"&&p.css(a,"float")==="none"&&(!p.support.inlineBlockNeedsLayout||cc(a.nodeName)==="inline"?m.display="inline-block":m.zoom=1)),c.overflow&&(m.overflow="hidden",p.support.shrinkWrapBlocks||l.done(function(){m.overflow=c.overflow[0],m.overflowX=c.overflow[1],m.overflowY=c.overflow[2]}));for(d in b){f=b[d];if(cP.exec(f)){delete b[d];if(f===(q?"hide":"show"))continue;o.push(d)}}g=o.length;if(g){h=p._data(a,"fxshow")||p._data(a,"fxshow",{}),q?p(a).show():l.done(function(){p(a).hide()}),l.done(function(){var b;p.removeData(a,"fxshow",!0);for(b in n)p.style(a,b,n[b])});for(d=0;d<g;d++)e=o[d],i=l.createTween(e,q?h[e]:0),n[e]=h[e]||p.style(a,e),e in h||(h[e]=i.start,q&&(i.end=i.start,i.start=e==="width"||e==="height"?1:0))}}function cZ(a,b,c,d,e){return new cZ.prototype.init(a,b,c,d,e)}function c$(a,b){var c,d={height:a},e=0;b=b?1:0;for(;e<4;e+=2-b)c=bV[e],d["margin"+c]=d["padding"+c]=a;return b&&(d.opacity=d.width=a),d}function da(a){return p.isWindow(a)?a:a.nodeType===9?a.defaultView||a.parentWindow:!1}var c,d,e=a.document,f=a.location,g=a.navigator,h=a.jQuery,i=a.$,j=Array.prototype.push,k=Array.prototype.slice,l=Array.prototype.indexOf,m=Object.prototype.toString,n=Object.prototype.hasOwnProperty,o=String.prototype.trim,p=function(a,b){return new p.fn.init(a,b,c)},q=/[\-+]?(?:\d*\.|)\d+(?:[eE][\-+]?\d+|)/.source,r=/\S/,s=/\s+/,t=/^[\s\uFEFF\xA0]+|[\s\uFEFF\xA0]+$/g,u=/^(?:[^#<]*(<[\w\W]+>)[^>]*$|#([\w\-]*)$)/,v=/^<(\w+)\s*\/?>(?:<\/\1>|)$/,w=/^[\],:{}\s]*$/,x=/(?:^|:|,)(?:\s*\[)+/g,y=/\\(?:["\\\/bfnrt]|u[\da-fA-F]{4})/g,z=/"[^"\\\r\n]*"|true|false|null|-?(?:\d\d*\.|)\d+(?:[eE][\-+]?\d+|)/g,A=/^-ms-/,B=/-([\da-z])/gi,C=function(a,b){return(b+"").toUpperCase()},D=function(){e.addEventListener?(e.removeEventListener("DOMContentLoaded",D,!1),p.ready()):e.readyState==="complete"&&(e.detachEvent("onreadystatechange",D),p.ready())},E={};p.fn=p.prototype={constructor:p,init:function(a,c,d){var f,g,h,i;if(!a)return this;if(a.nodeType)return this.context=this[0]=a,this.length=1,this;if(typeof a=="string"){a.charAt(0)==="<"&&a.charAt(a.length-1)===">"&&a.length>=3?f=[null,a,null]:f=u.exec(a);if(f&&(f[1]||!c)){if(f[1])return c=c instanceof p?c[0]:c,i=c&&c.nodeType?c.ownerDocument||c:e,a=p.parseHTML(f[1],i,!0),v.test(f[1])&&p.isPlainObject(c)&&this.attr.call(a,c,!0),p.merge(this,a);g=e.getElementById(f[2]);if(g&&g.parentNode){if(g.id!==f[2])return d.find(a);this.length=1,this[0]=g}return this.context=e,this.selector=a,this}return!c||c.jquery?(c||d).find(a):this.constructor(c).find(a)}return p.isFunction(a)?d.ready(a):(a.selector!==b&&(this.selector=a.selector,this.context=a.context),p.makeArray(a,this))},selector:"",jquery:"1.8.2",length:0,size:function(){return this.length},toArray:function(){return k.call(this)},get:function(a){return a==null?this.toArray():a<0?this[this.length+a]:this[a]},pushStack:function(a,b,c){var d=p.merge(this.constructor(),a);return d.prevObject=this,d.context=this.context,b==="find"?d.selector=this.selector+(this.selector?" ":"")+c:b&&(d.selector=this.selector+"."+b+"("+c+")"),d},each:function(a,b){return p.each(this,a,b)},ready:function(a){return p.ready.promise().done(a),this},eq:function(a){return a=+a,a===-1?this.slice(a):this.slice(a,a+1)},first:function(){return this.eq(0)},last:function(){return this.eq(-1)},slice:function(){return this.pushStack(k.apply(this,arguments),"slice",k.call(arguments).join(","))},map:function(a){return this.pushStack(p.map(this,function(b,c){return a.call(b,c,b)}))},end:function(){return this.prevObject||this.constructor(null)},push:j,sort:[].sort,splice:[].splice},p.fn.init.prototype=p.fn,p.extend=p.fn.extend=function(){var a,c,d,e,f,g,h=arguments[0]||{},i=1,j=arguments.length,k=!1;typeof h=="boolean"&&(k=h,h=arguments[1]||{},i=2),typeof h!="object"&&!p.isFunction(h)&&(h={}),j===i&&(h=this,--i);for(;i<j;i++)if((a=arguments[i])!=null)for(c in a){d=h[c],e=a[c];if(h===e)continue;k&&e&&(p.isPlainObject(e)||(f=p.isArray(e)))?(f?(f=!1,g=d&&p.isArray(d)?d:[]):g=d&&p.isPlainObject(d)?d:{},h[c]=p.extend(k,g,e)):e!==b&&(h[c]=e)}return h},p.extend({noConflict:function(b){return a.$===p&&(a.$=i),b&&a.jQuery===p&&(a.jQuery=h),p},isReady:!1,readyWait:1,holdReady:function(a){a?p.readyWait++:p.ready(!0)},ready:function(a){if(a===!0?--p.readyWait:p.isReady)return;if(!e.body)return setTimeout(p.ready,1);p.isReady=!0;if(a!==!0&&--p.readyWait>0)return;d.resolveWith(e,[p]),p.fn.trigger&&p(e).trigger("ready").off("ready")},isFunction:function(a){return p.type(a)==="function"},isArray:Array.isArray||function(a){return p.type(a)==="array"},isWindow:function(a){return a!=null&&a==a.window},isNumeric:function(a){return!isNaN(parseFloat(a))&&isFinite(a)},type:function(a){return a==null?String(a):E[m.call(a)]||"object"},isPlainObject:function(a){if(!a||p.type(a)!=="object"||a.nodeType||p.isWindow(a))return!1;try{if(a.constructor&&!n.call(a,"constructor")&&!n.call(a.constructor.prototype,"isPrototypeOf"))return!1}catch(c){return!1}var d;for(d in a);return d===b||n.call(a,d)},isEmptyObject:function(a){var b;for(b in a)return!1;return!0},error:function(a){throw new Error(a)},parseHTML:function(a,b,c){var d;return!a||typeof a!="string"?null:(typeof b=="boolean"&&(c=b,b=0),b=b||e,(d=v.exec(a))?[b.createElement(d[1])]:(d=p.buildFragment([a],b,c?null:[]),p.merge([],(d.cacheable?p.clone(d.fragment):d.fragment).childNodes)))},parseJSON:function(b){if(!b||typeof b!="string")return null;b=p.trim(b);if(a.JSON&&a.JSON.parse)return a.JSON.parse(b);if(w.test(b.replace(y,"@").replace(z,"]").replace(x,"")))return(new Function("return "+b))();p.error("Invalid JSON: "+b)},parseXML:function(c){var d,e;if(!c||typeof c!="string")return null;try{a.DOMParser?(e=new DOMParser,d=e.parseFromString(c,"text/xml")):(d=new ActiveXObject("Microsoft.XMLDOM"),d.async="false",d.loadXML(c))}catch(f){d=b}return(!d||!d.documentElement||d.getElementsByTagName("parsererror").length)&&p.error("Invalid XML: "+c),d},noop:function(){},globalEval:function(b){b&&r.test(b)&&(a.execScript||function(b){a.eval.call(a,b)})(b)},camelCase:function(a){return a.replace(A,"ms-").replace(B,C)},nodeName:function(a,b){return a.nodeName&&a.nodeName.toLowerCase()===b.toLowerCase()},each:function(a,c,d){var e,f=0,g=a.length,h=g===b||p.isFunction(a);if(d){if(h){for(e in a)if(c.apply(a[e],d)===!1)break}else for(;f<g;)if(c.apply(a[f++],d)===!1)break}else if(h){for(e in a)if(c.call(a[e],e,a[e])===!1)break}else for(;f<g;)if(c.call(a[f],f,a[f++])===!1)break;return a},trim:o&&!o.call(" ")?function(a){return a==null?"":o.call(a)}:function(a){return a==null?"":(a+"").replace(t,"")},makeArray:function(a,b){var c,d=b||[];return a!=null&&(c=p.type(a),a.length==null||c==="string"||c==="function"||c==="regexp"||p.isWindow(a)?j.call(d,a):p.merge(d,a)),d},inArray:function(a,b,c){var d;if(b){if(l)return l.call(b,a,c);d=b.length,c=c?c<0?Math.max(0,d+c):c:0;for(;c<d;c++)if(c in b&&b[c]===a)return c}return-1},merge:function(a,c){var d=c.length,e=a.length,f=0;if(typeof d=="number")for(;f<d;f++)a[e++]=c[f];else while(c[f]!==b)a[e++]=c[f++];return a.length=e,a},grep:function(a,b,c){var d,e=[],f=0,g=a.length;c=!!c;for(;f<g;f++)d=!!b(a[f],f),c!==d&&e.push(a[f]);return e},map:function(a,c,d){var e,f,g=[],h=0,i=a.length,j=a instanceof p||i!==b&&typeof i=="number"&&(i>0&&a[0]&&a[i-1]||i===0||p.isArray(a));if(j)for(;h<i;h++)e=c(a[h],h,d),e!=null&&(g[g.length]=e);else for(f in a)e=c(a[f],f,d),e!=null&&(g[g.length]=e);return g.concat.apply([],g)},guid:1,proxy:function(a,c){var d,e,f;return typeof c=="string"&&(d=a[c],c=a,a=d),p.isFunction(a)?(e=k.call(arguments,2),f=function(){return a.apply(c,e.concat(k.call(arguments)))},f.guid=a.guid=a.guid||p.guid++,f):b},access:function(a,c,d,e,f,g,h){var i,j=d==null,k=0,l=a.length;if(d&&typeof d=="object"){for(k in d)p.access(a,c,k,d[k],1,g,e);f=1}else if(e!==b){i=h===b&&p.isFunction(e),j&&(i?(i=c,c=function(a,b,c){return i.call(p(a),c)}):(c.call(a,e),c=null));if(c)for(;k<l;k++)c(a[k],d,i?e.call(a[k],k,c(a[k],d)):e,h);f=1}return f?a:j?c.call(a):l?c(a[0],d):g},now:function(){return(new Date).getTime()}}),p.ready.promise=function(b){if(!d){d=p.Deferred();if(e.readyState==="complete")setTimeout(p.ready,1);else if(e.addEventListener)e.addEventListener("DOMContentLoaded",D,!1),a.addEventListener("load",p.ready,!1);else{e.attachEvent("onreadystatechange",D),a.attachEvent("onload",p.ready);var c=!1;try{c=a.frameElement==null&&e.documentElement}catch(f){}c&&c.doScroll&&function g(){if(!p.isReady){try{c.doScroll("left")}catch(a){return setTimeout(g,50)}p.ready()}}()}}return d.promise(b)},p.each("Boolean Number String Function Array Date RegExp Object".split(" "),function(a,b){E["[object "+b+"]"]=b.toLowerCase()}),c=p(e);var F={};p.Callbacks=function(a){a=typeof a=="string"?F[a]||G(a):p.extend({},a);var c,d,e,f,g,h,i=[],j=!a.once&&[],k=function(b){c=a.memory&&b,d=!0,h=f||0,f=0,g=i.length,e=!0;for(;i&&h<g;h++)if(i[h].apply(b[0],b[1])===!1&&a.stopOnFalse){c=!1;break}e=!1,i&&(j?j.length&&k(j.shift()):c?i=[]:l.disable())},l={add:function(){if(i){var b=i.length;(function d(b){p.each(b,function(b,c){var e=p.type(c);e==="function"&&(!a.unique||!l.has(c))?i.push(c):c&&c.length&&e!=="string"&&d(c)})})(arguments),e?g=i.length:c&&(f=b,k(c))}return this},remove:function(){return i&&p.each(arguments,function(a,b){var c;while((c=p.inArray(b,i,c))>-1)i.splice(c,1),e&&(c<=g&&g--,c<=h&&h--)}),this},has:function(a){return p.inArray(a,i)>-1},empty:function(){return i=[],this},disable:function(){return i=j=c=b,this},disabled:function(){return!i},lock:function(){return j=b,c||l.disable(),this},locked:function(){return!j},fireWith:function(a,b){return b=b||[],b=[a,b.slice?b.slice():b],i&&(!d||j)&&(e?j.push(b):k(b)),this},fire:function(){return l.fireWith(this,arguments),this},fired:function(){return!!d}};return l},p.extend({Deferred:function(a){var b=[["resolve","done",p.Callbacks("once memory"),"resolved"],["reject","fail",p.Callbacks("once memory"),"rejected"],["notify","progress",p.Callbacks("memory")]],c="pending",d={state:function(){return c},always:function(){return e.done(arguments).fail(arguments),this},then:function(){var a=arguments;return p.Deferred(function(c){p.each(b,function(b,d){var f=d[0],g=a[b];e[d[1]](p.isFunction(g)?function(){var a=g.apply(this,arguments);a&&p.isFunction(a.promise)?a.promise().done(c.resolve).fail(c.reject).progress(c.notify):c[f+"With"](this===e?c:this,[a])}:c[f])}),a=null}).promise()},promise:function(a){return a!=null?p.extend(a,d):d}},e={};return d.pipe=d.then,p.each(b,function(a,f){var g=f[2],h=f[3];d[f[1]]=g.add,h&&g.add(function(){c=h},b[a^1][2].disable,b[2][2].lock),e[f[0]]=g.fire,e[f[0]+"With"]=g.fireWith}),d.promise(e),a&&a.call(e,e),e},when:function(a){var b=0,c=k.call(arguments),d=c.length,e=d!==1||a&&p.isFunction(a.promise)?d:0,f=e===1?a:p.Deferred(),g=function(a,b,c){return function(d){b[a]=this,c[a]=arguments.length>1?k.call(arguments):d,c===h?f.notifyWith(b,c):--e||f.resolveWith(b,c)}},h,i,j;if(d>1){h=new Array(d),i=new Array(d),j=new Array(d);for(;b<d;b++)c[b]&&p.isFunction(c[b].promise)?c[b].promise().done(g(b,j,c)).fail(f.reject).progress(g(b,i,h)):--e}return e||f.resolveWith(j,c),f.promise()}}),p.support=function(){var b,c,d,f,g,h,i,j,k,l,m,n=e.createElement("div");n.setAttribute("className","t"),n.innerHTML=" <link/><table></table><a href='/a'>a</a><input type='checkbox'/>",c=n.getElementsByTagName("*"),d=n.getElementsByTagName("a")[0],d.style.cssText="top:1px;float:left;opacity:.5";if(!c||!c.length)return{};f=e.createElement("select"),g=f.appendChild(e.createElement("option")),h=n.getElementsByTagName("input")[0],b={leadingWhitespace:n.firstChild.nodeType===3,tbody:!n.getElementsByTagName("tbody").length,htmlSerialize:!!n.getElementsByTagName("link").length,style:/top/.test(d.getAttribute("style")),hrefNormalized:d.getAttribute("href")==="/a",opacity:/^0.5/.test(d.style.opacity),cssFloat:!!d.style.cssFloat,checkOn:h.value==="on",optSelected:g.selected,getSetAttribute:n.className!=="t",enctype:!!e.createElement("form").enctype,html5Clone:e.createElement("nav").cloneNode(!0).outerHTML!=="<:nav></:nav>",boxModel:e.compatMode==="CSS1Compat",submitBubbles:!0,changeBubbles:!0,focusinBubbles:!1,deleteExpando:!0,noCloneEvent:!0,inlineBlockNeedsLayout:!1,shrinkWrapBlocks:!1,reliableMarginRight:!0,boxSizingReliable:!0,pixelPosition:!1},h.checked=!0,b.noCloneChecked=h.cloneNode(!0).checked,f.disabled=!0,b.optDisabled=!g.disabled;try{delete n.test}catch(o){b.deleteExpando=!1}!n.addEventListener&&n.attachEvent&&n.fireEvent&&(n.attachEvent("onclick",m=function(){b.noCloneEvent=!1}),n.cloneNode(!0).fireEvent("onclick"),n.detachEvent("onclick",m)),h=e.createElement("input"),h.value="t",h.setAttribute("type","radio"),b.radioValue=h.value==="t",h.setAttribute("checked","checked"),h.setAttribute("name","t"),n.appendChild(h),i=e.createDocumentFragment(),i.appendChild(n.lastChild),b.checkClone=i.cloneNode(!0).cloneNode(!0).lastChild.checked,b.appendChecked=h.checked,i.removeChild(h),i.appendChild(n);if(n.attachEvent)for(k in{submit:!0,change:!0,focusin:!0})j="on"+k,l=j in n,l||(n.setAttribute(j,"return;"),l=typeof n[j]=="function"),b[k+"Bubbles"]=l;return p(function(){var c,d,f,g,h="padding:0;margin:0;border:0;display:block;overflow:hidden;",i=e.getElementsByTagName("body")[0];if(!i)return;c=e.createElement("div"),c.style.cssText="visibility:hidden;border:0;width:0;height:0;position:static;top:0;margin-top:1px",i.insertBefore(c,i.firstChild),d=e.createElement("div"),c.appendChild(d),d.innerHTML="<table><tr><td></td><td>t</td></tr></table>",f=d.getElementsByTagName("td"),f[0].style.cssText="padding:0;margin:0;border:0;display:none",l=f[0].offsetHeight===0,f[0].style.display="",f[1].style.display="none",b.reliableHiddenOffsets=l&&f[0].offsetHeight===0,d.innerHTML="",d.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%;",b.boxSizing=d.offsetWidth===4,b.doesNotIncludeMarginInBodyOffset=i.offsetTop!==1,a.getComputedStyle&&(b.pixelPosition=(a.getComputedStyle(d,null)||{}).top!=="1%",b.boxSizingReliable=(a.getComputedStyle(d,null)||{width:"4px"}).width==="4px",g=e.createElement("div"),g.style.cssText=d.style.cssText=h,g.style.marginRight=g.style.width="0",d.style.width="1px",d.appendChild(g),b.reliableMarginRight=!parseFloat((a.getComputedStyle(g,null)||{}).marginRight)),typeof d.style.zoom!="undefined"&&(d.innerHTML="",d.style.cssText=h+"width:1px;padding:1px;display:inline;zoom:1",b.inlineBlockNeedsLayout=d.offsetWidth===3,d.style.display="block",d.style.overflow="visible",d.innerHTML="<div></div>",d.firstChild.style.width="5px",b.shrinkWrapBlocks=d.offsetWidth!==3,c.style.zoom=1),i.removeChild(c),c=d=f=g=null}),i.removeChild(n),c=d=f=g=h=i=n=null,b}();var H=/(?:\{[\s\S]*\}|\[[\s\S]*\])$/,I=/([A-Z])/g;p.extend({cache:{},deletedIds:[],uuid:0,expando:"jQuery"+(p.fn.jquery+Math.random()).replace(/\D/g,""),noData:{embed:!0,object:"clsid:D27CDB6E-AE6D-11cf-96B8-444553540000",applet:!0},hasData:function(a){return a=a.nodeType?p.cache[a[p.expando]]:a[p.expando],!!a&&!K(a)},data:function(a,c,d,e){if(!p.acceptData(a))return;var f,g,h=p.expando,i=typeof c=="string",j=a.nodeType,k=j?p.cache:a,l=j?a[h]:a[h]&&h;if((!l||!k[l]||!e&&!k[l].data)&&i&&d===b)return;l||(j?a[h]=l=p.deletedIds.pop()||p.guid++:l=h),k[l]||(k[l]={},j||(k[l].toJSON=p.noop));if(typeof c=="object"||typeof c=="function")e?k[l]=p.extend(k[l],c):k[l].data=p.extend(k[l].data,c);return f=k[l],e||(f.data||(f.data={}),f=f.data),d!==b&&(f[p.camelCase(c)]=d),i?(g=f[c],g==null&&(g=f[p.camelCase(c)])):g=f,g},removeData:function(a,b,c){if(!p.acceptData(a))return;var d,e,f,g=a.nodeType,h=g?p.cache:a,i=g?a[p.expando]:p.expando;if(!h[i])return;if(b){d=c?h[i]:h[i].data;if(d){p.isArray(b)||(b in d?b=[b]:(b=p.camelCase(b),b in d?b=[b]:b=b.split(" ")));for(e=0,f=b.length;e<f;e++)delete d[b[e]];if(!(c?K:p.isEmptyObject)(d))return}}if(!c){delete h[i].data;if(!K(h[i]))return}g?p.cleanData([a],!0):p.support.deleteExpando||h!=h.window?delete h[i]:h[i]=null},_data:function(a,b,c){return p.data(a,b,c,!0)},acceptData:function(a){var b=a.nodeName&&p.noData[a.nodeName.toLowerCase()];return!b||b!==!0&&a.getAttribute("classid")===b}}),p.fn.extend({data:function(a,c){var d,e,f,g,h,i=this[0],j=0,k=null;if(a===b){if(this.length){k=p.data(i);if(i.nodeType===1&&!p._data(i,"parsedAttrs")){f=i.attributes;for(h=f.length;j<h;j++)g=f[j].name,g.indexOf("data-")||(g=p.camelCase(g.substring(5)),J(i,g,k[g]));p._data(i,"parsedAttrs",!0)}}return k}return typeof a=="object"?this.each(function(){p.data(this,a)}):(d=a.split(".",2),d[1]=d[1]?"."+d[1]:"",e=d[1]+"!",p.access(this,function(c){if(c===b)return k=this.triggerHandler("getData"+e,[d[0]]),k===b&&i&&(k=p.data(i,a),k=J(i,a,k)),k===b&&d[1]?this.data(d[0]):k;d[1]=c,this.each(function(){var b=p(this);b.triggerHandler("setData"+e,d),p.data(this,a,c),b.triggerHandler("changeData"+e,d)})},null,c,arguments.length>1,null,!1))},removeData:function(a){return this.each(function(){p.removeData(this,a)})}}),p.extend({queue:function(a,b,c){var d;if(a)return b=(b||"fx")+"queue",d=p._data(a,b),c&&(!d||p.isArray(c)?d=p._data(a,b,p.makeArray(c)):d.push(c)),d||[]},dequeue:function(a,b){b=b||"fx";var c=p.queue(a,b),d=c.length,e=c.shift(),f=p._queueHooks(a,b),g=function(){p.dequeue(a,b)};e==="inprogress"&&(e=c.shift(),d--),e&&(b==="fx"&&c.unshift("inprogress"),delete f.stop,e.call(a,g,f)),!d&&f&&f.empty.fire()},_queueHooks:function(a,b){var c=b+"queueHooks";return p._data(a,c)||p._data(a,c,{empty:p.Callbacks("once memory").add(function(){p.removeData(a,b+"queue",!0),p.removeData(a,c,!0)})})}}),p.fn.extend({queue:function(a,c){var d=2;return typeof a!="string"&&(c=a,a="fx",d--),arguments.length<d?p.queue(this[0],a):c===b?this:this.each(function(){var b=p.queue(this,a,c);p._queueHooks(this,a),a==="fx"&&b[0]!=="inprogress"&&p.dequeue(this,a)})},dequeue:function(a){return this.each(function(){p.dequeue(this,a)})},delay:function(a,b){return a=p.fx?p.fx.speeds[a]||a:a,b=b||"fx",this.queue(b,function(b,c){var d=setTimeout(b,a);c.stop=function(){clearTimeout(d)}})},clearQueue:function(a){return this.queue(a||"fx",[])},promise:function(a,c){var d,e=1,f=p.Deferred(),g=this,h=this.length,i=function(){--e||f.resolveWith(g,[g])};typeof a!="string"&&(c=a,a=b),a=a||"fx";while(h--)d=p._data(g[h],a+"queueHooks"),d&&d.empty&&(e++,d.empty.add(i));return i(),f.promise(c)}});var L,M,N,O=/[\t\r\n]/g,P=/\r/g,Q=/^(?:button|input)$/i,R=/^(?:button|input|object|select|textarea)$/i,S=/^a(?:rea|)$/i,T=/^(?:autofocus|autoplay|async|checked|controls|defer|disabled|hidden|loop|multiple|open|readonly|required|scoped|selected)$/i,U=p.support.getSetAttribute;p.fn.extend({attr:function(a,b){return p.access(this,p.attr,a,b,arguments.length>1)},removeAttr:function(a){return this.each(function(){p.removeAttr(this,a)})},prop:function(a,b){return p.access(this,p.prop,a,b,arguments.length>1)},removeProp:function(a){return a=p.propFix[a]||a,this.each(function(){try{this[a]=b,delete this[a]}catch(c){}})},addClass:function(a){var b,c,d,e,f,g,h;if(p.isFunction(a))return this.each(function(b){p(this).addClass(a.call(this,b,this.className))});if(a&&typeof a=="string"){b=a.split(s);for(c=0,d=this.length;c<d;c++){e=this[c];if(e.nodeType===1)if(!e.className&&b.length===1)e.className=a;else{f=" "+e.className+" ";for(g=0,h=b.length;g<h;g++)f.indexOf(" "+b[g]+" ")<0&&(f+=b[g]+" ");e.className=p.trim(f)}}}return this},removeClass:function(a){var c,d,e,f,g,h,i;if(p.isFunction(a))return this.each(function(b){p(this).removeClass(a.call(this,b,this.className))});if(a&&typeof a=="string"||a===b){c=(a||"").split(s);for(h=0,i=this.length;h<i;h++){e=this[h];if(e.nodeType===1&&e.className){d=(" "+e.className+" ").replace(O," ");for(f=0,g=c.length;f<g;f++)while(d.indexOf(" "+c[f]+" ")>=0)d=d.replace(" "+c[f]+" "," ");e.className=a?p.trim(d):""}}}return this},toggleClass:function(a,b){var c=typeof a,d=typeof b=="boolean";return p.isFunction(a)?this.each(function(c){p(this).toggleClass(a.call(this,c,this.className,b),b)}):this.each(function(){if(c==="string"){var e,f=0,g=p(this),h=b,i=a.split(s);while(e=i[f++])h=d?h:!g.hasClass(e),g[h?"addClass":"removeClass"](e)}else if(c==="undefined"||c==="boolean")this.className&&p._data(this,"__className__",this.className),this.className=this.className||a===!1?"":p._data(this,"__className__")||""})},hasClass:function(a){var b=" "+a+" ",c=0,d=this.length;for(;c<d;c++)if(this[c].nodeType===1&&(" "+this[c].className+" ").replace(O," ").indexOf(b)>=0)return!0;return!1},val:function(a){var c,d,e,f=this[0];if(!arguments.length){if(f)return c=p.valHooks[f.type]||p.valHooks[f.nodeName.toLowerCase()],c&&"get"in c&&(d=c.get(f,"value"))!==b?d:(d=f.value,typeof d=="string"?d.replace(P,""):d==null?"":d);return}return e=p.isFunction(a),this.each(function(d){var f,g=p(this);if(this.nodeType!==1)return;e?f=a.call(this,d,g.val()):f=a,f==null?f="":typeof f=="number"?f+="":p.isArray(f)&&(f=p.map(f,function(a){return a==null?"":a+""})),c=p.valHooks[this.type]||p.valHooks[this.nodeName.toLowerCase()];if(!c||!("set"in c)||c.set(this,f,"value")===b)this.value=f})}}),p.extend({valHooks:{option:{get:function(a){var b=a.attributes.value;return!b||b.specified?a.value:a.text}},select:{get:function(a){var b,c,d,e,f=a.selectedIndex,g=[],h=a.options,i=a.type==="select-one";if(f<0)return null;c=i?f:0,d=i?f+1:h.length;for(;c<d;c++){e=h[c];if(e.selected&&(p.support.optDisabled?!e.disabled:e.getAttribute("disabled")===null)&&(!e.parentNode.disabled||!p.nodeName(e.parentNode,"optgroup"))){b=p(e).val();if(i)return b;g.push(b)}}return i&&!g.length&&h.length?p(h[f]).val():g},set:function(a,b){var c=p.makeArray(b);return p(a).find("option").each(function(){this.selected=p.inArray(p(this).val(),c)>=0}),c.length||(a.selectedIndex=-1),c}}},attrFn:{},attr:function(a,c,d,e){var f,g,h,i=a.nodeType;if(!a||i===3||i===8||i===2)return;if(e&&p.isFunction(p.fn[c]))return p(a)[c](d);if(typeof a.getAttribute=="undefined")return p.prop(a,c,d);h=i!==1||!p.isXMLDoc(a),h&&(c=c.toLowerCase(),g=p.attrHooks[c]||(T.test(c)?M:L));if(d!==b){if(d===null){p.removeAttr(a,c);return}return g&&"set"in g&&h&&(f=g.set(a,d,c))!==b?f:(a.setAttribute(c,d+""),d)}return g&&"get"in g&&h&&(f=g.get(a,c))!==null?f:(f=a.getAttribute(c),f===null?b:f)},removeAttr:function(a,b){var c,d,e,f,g=0;if(b&&a.nodeType===1){d=b.split(s);for(;g<d.length;g++)e=d[g],e&&(c=p.propFix[e]||e,f=T.test(e),f||p.attr(a,e,""),a.removeAttribute(U?e:c),f&&c in a&&(a[c]=!1))}},attrHooks:{type:{set:function(a,b){if(Q.test(a.nodeName)&&a.parentNode)p.error("type property can't be changed");else if(!p.support.radioValue&&b==="radio"&&p.nodeName(a,"input")){var c=a.value;return a.setAttribute("type",b),c&&(a.value=c),b}}},value:{get:function(a,b){return L&&p.nodeName(a,"button")?L.get(a,b):b in a?a.value:null},set:function(a,b,c){if(L&&p.nodeName(a,"button"))return L.set(a,b,c);a.value=b}}},propFix:{tabindex:"tabIndex",readonly:"readOnly","for":"htmlFor","class":"className",maxlength:"maxLength",cellspacing:"cellSpacing",cellpadding:"cellPadding",rowspan:"rowSpan",colspan:"colSpan",usemap:"useMap",frameborder:"frameBorder",contenteditable:"contentEditable"},prop:function(a,c,d){var e,f,g,h=a.nodeType;if(!a||h===3||h===8||h===2)return;return g=h!==1||!p.isXMLDoc(a),g&&(c=p.propFix[c]||c,f=p.propHooks[c]),d!==b?f&&"set"in f&&(e=f.set(a,d,c))!==b?e:a[c]=d:f&&"get"in f&&(e=f.get(a,c))!==null?e:a[c]},propHooks:{tabIndex:{get:function(a){var c=a.getAttributeNode("tabindex");return c&&c.specified?parseInt(c.value,10):R.test(a.nodeName)||S.test(a.nodeName)&&a.href?0:b}}}}),M={get:function(a,c){var d,e=p.prop(a,c);return e===!0||typeof e!="boolean"&&(d=a.getAttributeNode(c))&&d.nodeValue!==!1?c.toLowerCase():b},set:function(a,b,c){var d;return b===!1?p.removeAttr(a,c):(d=p.propFix[c]||c,d in a&&(a[d]=!0),a.setAttribute(c,c.toLowerCase())),c}},U||(N={name:!0,id:!0,coords:!0},L=p.valHooks.button={get:function(a,c){var d;return d=a.getAttributeNode(c),d&&(N[c]?d.value!=="":d.specified)?d.value:b},set:function(a,b,c){var d=a.getAttributeNode(c);return d||(d=e.createAttribute(c),a.setAttributeNode(d)),d.value=b+""}},p.each(["width","height"],function(a,b){p.attrHooks[b]=p.extend(p.attrHooks[b],{set:function(a,c){if(c==="")return a.setAttribute(b,"auto"),c}})}),p.attrHooks.contenteditable={get:L.get,set:function(a,b,c){b===""&&(b="false"),L.set(a,b,c)}}),p.support.hrefNormalized||p.each(["href","src","width","height"],function(a,c){p.attrHooks[c]=p.extend(p.attrHooks[c],{get:function(a){var d=a.getAttribute(c,2);return d===null?b:d}})}),p.support.style||(p.attrHooks.style={get:function(a){return a.style.cssText.toLowerCase()||b},set:function(a,b){return a.style.cssText=b+""}}),p.support.optSelected||(p.propHooks.selected=p.extend(p.propHooks.selected,{get:function(a){var b=a.parentNode;return b&&(b.selectedIndex,b.parentNode&&b.parentNode.selectedIndex),null}})),p.support.enctype||(p.propFix.enctype="encoding"),p.support.checkOn||p.each(["radio","checkbox"],function(){p.valHooks[this]={get:function(a){return a.getAttribute("value")===null?"on":a.value}}}),p.each(["radio","checkbox"],function(){p.valHooks[this]=p.extend(p.valHooks[this],{set:function(a,b){if(p.isArray(b))return a.checked=p.inArray(p(a).val(),b)>=0}})});var V=/^(?:textarea|input|select)$/i,W=/^([^\.]*|)(?:\.(.+)|)$/,X=/(?:^|\s)hover(\.\S+|)\b/,Y=/^key/,Z=/^(?:mouse|contextmenu)|click/,$=/^(?:focusinfocus|focusoutblur)$/,_=function(a){return p.event.special.hover?a:a.replace(X,"mouseenter$1 mouseleave$1")};p.event={add:function(a,c,d,e,f){var g,h,i,j,k,l,m,n,o,q,r;if(a.nodeType===3||a.nodeType===8||!c||!d||!(g=p._data(a)))return;d.handler&&(o=d,d=o.handler,f=o.selector),d.guid||(d.guid=p.guid++),i=g.events,i||(g.events=i={}),h=g.handle,h||(g.handle=h=function(a){return typeof p!="undefined"&&(!a||p.event.triggered!==a.type)?p.event.dispatch.apply(h.elem,arguments):b},h.elem=a),c=p.trim(_(c)).split(" ");for(j=0;j<c.length;j++){k=W.exec(c[j])||[],l=k[1],m=(k[2]||"").split(".").sort(),r=p.event.special[l]||{},l=(f?r.delegateType:r.bindType)||l,r=p.event.special[l]||{},n=p.extend({type:l,origType:k[1],data:e,handler:d,guid:d.guid,selector:f,needsContext:f&&p.expr.match.needsContext.test(f),namespace:m.join(".")},o),q=i[l];if(!q){q=i[l]=[],q.delegateCount=0;if(!r.setup||r.setup.call(a,e,m,h)===!1)a.addEventListener?a.addEventListener(l,h,!1):a.attachEvent&&a.attachEvent("on"+l,h)}r.add&&(r.add.call(a,n),n.handler.guid||(n.handler.guid=d.guid)),f?q.splice(q.delegateCount++,0,n):q.push(n),p.event.global[l]=!0}a=null},global:{},remove:function(a,b,c,d,e){var f,g,h,i,j,k,l,m,n,o,q,r=p.hasData(a)&&p._data(a);if(!r||!(m=r.events))return;b=p.trim(_(b||"")).split(" ");for(f=0;f<b.length;f++){g=W.exec(b[f])||[],h=i=g[1],j=g[2];if(!h){for(h in m)p.event.remove(a,h+b[f],c,d,!0);continue}n=p.event.special[h]||{},h=(d?n.delegateType:n.bindType)||h,o=m[h]||[],k=o.length,j=j?new RegExp("(^|\\.)"+j.split(".").sort().join("\\.(?:.*\\.|)")+"(\\.|$)"):null;for(l=0;l<o.length;l++)q=o[l],(e||i===q.origType)&&(!c||c.guid===q.guid)&&(!j||j.test(q.namespace))&&(!d||d===q.selector||d==="**"&&q.selector)&&(o.splice(l--,1),q.selector&&o.delegateCount--,n.remove&&n.remove.call(a,q));o.length===0&&k!==o.length&&((!n.teardown||n.teardown.call(a,j,r.handle)===!1)&&p.removeEvent(a,h,r.handle),delete m[h])}p.isEmptyObject(m)&&(delete r.handle,p.removeData(a,"events",!0))},customEvent:{getData:!0,setData:!0,changeData:!0},trigger:function(c,d,f,g){if(!f||f.nodeType!==3&&f.nodeType!==8){var h,i,j,k,l,m,n,o,q,r,s=c.type||c,t=[];if($.test(s+p.event.triggered))return;s.indexOf("!")>=0&&(s=s.slice(0,-1),i=!0),s.indexOf(".")>=0&&(t=s.split("."),s=t.shift(),t.sort());if((!f||p.event.customEvent[s])&&!p.event.global[s])return;c=typeof c=="object"?c[p.expando]?c:new p.Event(s,c):new p.Event(s),c.type=s,c.isTrigger=!0,c.exclusive=i,c.namespace=t.join("."),c.namespace_re=c.namespace?new RegExp("(^|\\.)"+t.join("\\.(?:.*\\.|)")+"(\\.|$)"):null,m=s.indexOf(":")<0?"on"+s:"";if(!f){h=p.cache;for(j in h)h[j].events&&h[j].events[s]&&p.event.trigger(c,d,h[j].handle.elem,!0);return}c.result=b,c.target||(c.target=f),d=d!=null?p.makeArray(d):[],d.unshift(c),n=p.event.special[s]||{};if(n.trigger&&n.trigger.apply(f,d)===!1)return;q=[[f,n.bindType||s]];if(!g&&!n.noBubble&&!p.isWindow(f)){r=n.delegateType||s,k=$.test(r+s)?f:f.parentNode;for(l=f;k;k=k.parentNode)q.push([k,r]),l=k;l===(f.ownerDocument||e)&&q.push([l.defaultView||l.parentWindow||a,r])}for(j=0;j<q.length&&!c.isPropagationStopped();j++)k=q[j][0],c.type=q[j][1],o=(p._data(k,"events")||{})[c.type]&&p._data(k,"handle"),o&&o.apply(k,d),o=m&&k[m],o&&p.acceptData(k)&&o.apply&&o.apply(k,d)===!1&&c.preventDefault();return c.type=s,!g&&!c.isDefaultPrevented()&&(!n._default||n._default.apply(f.ownerDocument,d)===!1)&&(s!=="click"||!p.nodeName(f,"a"))&&p.acceptData(f)&&m&&f[s]&&(s!=="focus"&&s!=="blur"||c.target.offsetWidth!==0)&&!p.isWindow(f)&&(l=f[m],l&&(f[m]=null),p.event.triggered=s,f[s](),p.event.triggered=b,l&&(f[m]=l)),c.result}return},dispatch:function(c){c=p.event.fix(c||a.event);var d,e,f,g,h,i,j,l,m,n,o=(p._data(this,"events")||{})[c.type]||[],q=o.delegateCount,r=k.call(arguments),s=!c.exclusive&&!c.namespace,t=p.event.special[c.type]||{},u=[];r[0]=c,c.delegateTarget=this;if(t.preDispatch&&t.preDispatch.call(this,c)===!1)return;if(q&&(!c.button||c.type!=="click"))for(f=c.target;f!=this;f=f.parentNode||this)if(f.disabled!==!0||c.type!=="click"){h={},j=[];for(d=0;d<q;d++)l=o[d],m=l.selector,h[m]===b&&(h[m]=l.needsContext?p(m,this).index(f)>=0:p.find(m,this,null,[f]).length),h[m]&&j.push(l);j.length&&u.push({elem:f,matches:j})}o.length>q&&u.push({elem:this,matches:o.slice(q)});for(d=0;d<u.length&&!c.isPropagationStopped();d++){i=u[d],c.currentTarget=i.elem;for(e=0;e<i.matches.length&&!c.isImmediatePropagationStopped();e++){l=i.matches[e];if(s||!c.namespace&&!l.namespace||c.namespace_re&&c.namespace_re.test(l.namespace))c.data=l.data,c.handleObj=l,g=((p.event.special[l.origType]||{}).handle||l.handler).apply(i.elem,r),g!==b&&(c.result=g,g===!1&&(c.preventDefault(),c.stopPropagation()))}}return t.postDispatch&&t.postDispatch.call(this,c),c.result},props:"attrChange attrName relatedNode srcElement altKey bubbles cancelable ctrlKey currentTarget eventPhase metaKey relatedTarget shiftKey target timeStamp view which".split(" "),fixHooks:{},keyHooks:{props:"char charCode key keyCode".split(" "),filter:function(a,b){return a.which==null&&(a.which=b.charCode!=null?b.charCode:b.keyCode),a}},mouseHooks:{props:"button buttons clientX clientY fromElement offsetX offsetY pageX pageY screenX screenY toElement".split(" "),filter:function(a,c){var d,f,g,h=c.button,i=c.fromElement;return a.pageX==null&&c.clientX!=null&&(d=a.target.ownerDocument||e,f=d.documentElement,g=d.body,a.pageX=c.clientX+(f&&f.scrollLeft||g&&g.scrollLeft||0)-(f&&f.clientLeft||g&&g.clientLeft||0),a.pageY=c.clientY+(f&&f.scrollTop||g&&g.scrollTop||0)-(f&&f.clientTop||g&&g.clientTop||0)),!a.relatedTarget&&i&&(a.relatedTarget=i===a.target?c.toElement:i),!a.which&&h!==b&&(a.which=h&1?1:h&2?3:h&4?2:0),a}},fix:function(a){if(a[p.expando])return a;var b,c,d=a,f=p.event.fixHooks[a.type]||{},g=f.props?this.props.concat(f.props):this.props;a=p.Event(d);for(b=g.length;b;)c=g[--b],a[c]=d[c];return a.target||(a.target=d.srcElement||e),a.target.nodeType===3&&(a.target=a.target.parentNode),a.metaKey=!!a.metaKey,f.filter?f.filter(a,d):a},special:{load:{noBubble:!0},focus:{delegateType:"focusin"},blur:{delegateType:"focusout"},beforeunload:{setup:function(a,b,c){p.isWindow(this)&&(this.onbeforeunload=c)},teardown:function(a,b){this.onbeforeunload===b&&(this.onbeforeunload=null)}}},simulate:function(a,b,c,d){var e=p.extend(new p.Event,c,{type:a,isSimulated:!0,originalEvent:{}});d?p.event.trigger(e,null,b):p.event.dispatch.call(b,e),e.isDefaultPrevented()&&c.preventDefault()}},p.event.handle=p.event.dispatch,p.removeEvent=e.removeEventListener?function(a,b,c){a.removeEventListener&&a.removeEventListener(b,c,!1)}:function(a,b,c){var d="on"+b;a.detachEvent&&(typeof a[d]=="undefined"&&(a[d]=null),a.detachEvent(d,c))},p.Event=function(a,b){if(this instanceof p.Event)a&&a.type?(this.originalEvent=a,this.type=a.type,this.isDefaultPrevented=a.defaultPrevented||a.returnValue===!1||a.getPreventDefault&&a.getPreventDefault()?bb:ba):this.type=a,b&&p.extend(this,b),this.timeStamp=a&&a.timeStamp||p.now(),this[p.expando]=!0;else return new p.Event(a,b)},p.Event.prototype={preventDefault:function(){this.isDefaultPrevented=bb;var a=this.originalEvent;if(!a)return;a.preventDefault?a.preventDefault():a.returnValue=!1},stopPropagation:function(){this.isPropagationStopped=bb;var a=this.originalEvent;if(!a)return;a.stopPropagation&&a.stopPropagation(),a.cancelBubble=!0},stopImmediatePropagation:function(){this.isImmediatePropagationStopped=bb,this.stopPropagation()},isDefaultPrevented:ba,isPropagationStopped:ba,isImmediatePropagationStopped:ba},p.each({mouseenter:"mouseover",mouseleave:"mouseout"},function(a,b){p.event.special[a]={delegateType:b,bindType:b,handle:function(a){var c,d=this,e=a.relatedTarget,f=a.handleObj,g=f.selector;if(!e||e!==d&&!p.contains(d,e))a.type=f.origType,c=f.handler.apply(this,arguments),a.type=b;return c}}}),p.support.submitBubbles||(p.event.special.submit={setup:function(){if(p.nodeName(this,"form"))return!1;p.event.add(this,"click._submit keypress._submit",function(a){var c=a.target,d=p.nodeName(c,"input")||p.nodeName(c,"button")?c.form:b;d&&!p._data(d,"_submit_attached")&&(p.event.add(d,"submit._submit",function(a){a._submit_bubble=!0}),p._data(d,"_submit_attached",!0))})},postDispatch:function(a){a._submit_bubble&&(delete a._submit_bubble,this.parentNode&&!a.isTrigger&&p.event.simulate("submit",this.parentNode,a,!0))},teardown:function(){if(p.nodeName(this,"form"))return!1;p.event.remove(this,"._submit")}}),p.support.changeBubbles||(p.event.special.change={setup:function(){if(V.test(this.nodeName)){if(this.type==="checkbox"||this.type==="radio")p.event.add(this,"propertychange._change",function(a){a.originalEvent.propertyName==="checked"&&(this._just_changed=!0)}),p.event.add(this,"click._change",function(a){this._just_changed&&!a.isTrigger&&(this._just_changed=!1),p.event.simulate("change",this,a,!0)});return!1}p.event.add(this,"beforeactivate._change",function(a){var b=a.target;V.test(b.nodeName)&&!p._data(b,"_change_attached")&&(p.event.add(b,"change._change",function(a){this.parentNode&&!a.isSimulated&&!a.isTrigger&&p.event.simulate("change",this.parentNode,a,!0)}),p._data(b,"_change_attached",!0))})},handle:function(a){var b=a.target;if(this!==b||a.isSimulated||a.isTrigger||b.type!=="radio"&&b.type!=="checkbox")return a.handleObj.handler.apply(this,arguments)},teardown:function(){return p.event.remove(this,"._change"),!V.test(this.nodeName)}}),p.support.focusinBubbles||p.each({focus:"focusin",blur:"focusout"},function(a,b){var c=0,d=function(a){p.event.simulate(b,a.target,p.event.fix(a),!0)};p.event.special[b]={setup:function(){c++===0&&e.addEventListener(a,d,!0)},teardown:function(){--c===0&&e.removeEventListener(a,d,!0)}}}),p.fn.extend({on:function(a,c,d,e,f){var g,h;if(typeof a=="object"){typeof c!="string"&&(d=d||c,c=b);for(h in a)this.on(h,c,d,a[h],f);return this}d==null&&e==null?(e=c,d=c=b):e==null&&(typeof c=="string"?(e=d,d=b):(e=d,d=c,c=b));if(e===!1)e=ba;else if(!e)return this;return f===1&&(g=e,e=function(a){return p().off(a),g.apply(this,arguments)},e.guid=g.guid||(g.guid=p.guid++)),this.each(function(){p.event.add(this,a,e,d,c)})},one:function(a,b,c,d){return this.on(a,b,c,d,1)},off:function(a,c,d){var e,f;if(a&&a.preventDefault&&a.handleObj)return e=a.handleObj,p(a.delegateTarget).off(e.namespace?e.origType+"."+e.namespace:e.origType,e.selector,e.handler),this;if(typeof a=="object"){for(f in a)this.off(f,c,a[f]);return this}if(c===!1||typeof c=="function")d=c,c=b;return d===!1&&(d=ba),this.each(function(){p.event.remove(this,a,d,c)})},bind:function(a,b,c){return this.on(a,null,b,c)},unbind:function(a,b){return this.off(a,null,b)},live:function(a,b,c){return p(this.context).on(a,this.selector,b,c),this},die:function(a,b){return p(this.context).off(a,this.selector||"**",b),this},delegate:function(a,b,c,d){return this.on(b,a,c,d)},undelegate:function(a,b,c){return arguments.length===1?this.off(a,"**"):this.off(b,a||"**",c)},trigger:function(a,b){return this.each(function(){p.event.trigger(a,b,this)})},triggerHandler:function(a,b){if(this[0])return p.event.trigger(a,b,this[0],!0)},toggle:function(a){var b=arguments,c=a.guid||p.guid++,d=0,e=function(c){var e=(p._data(this,"lastToggle"+a.guid)||0)%d;return p._data(this,"lastToggle"+a.guid,e+1),c.preventDefault(),b[e].apply(this,arguments)||!1};e.guid=c;while(d<b.length)b[d++].guid=c;return this.click(e)},hover:function(a,b){return this.mouseenter(a).mouseleave(b||a)}}),p.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(a,b){p.fn[b]=function(a,c){return c==null&&(c=a,a=null),arguments.length>0?this.on(b,null,a,c):this.trigger(b)},Y.test(b)&&(p.event.fixHooks[b]=p.event.keyHooks),Z.test(b)&&(p.event.fixHooks[b]=p.event.mouseHooks)}),function(a,b){function bc(a,b,c,d){c=c||[],b=b||r;var e,f,i,j,k=b.nodeType;if(!a||typeof a!="string")return c;if(k!==1&&k!==9)return[];i=g(b);if(!i&&!d)if(e=P.exec(a))if(j=e[1]){if(k===9){f=b.getElementById(j);if(!f||!f.parentNode)return c;if(f.id===j)return c.push(f),c}else if(b.ownerDocument&&(f=b.ownerDocument.getElementById(j))&&h(b,f)&&f.id===j)return c.push(f),c}else{if(e[2])return w.apply(c,x.call(b.getElementsByTagName(a),0)),c;if((j=e[3])&&_&&b.getElementsByClassName)return w.apply(c,x.call(b.getElementsByClassName(j),0)),c}return bp(a.replace(L,"$1"),b,c,d,i)}function bd(a){return function(b){var c=b.nodeName.toLowerCase();return c==="input"&&b.type===a}}function be(a){return function(b){var c=b.nodeName.toLowerCase();return(c==="input"||c==="button")&&b.type===a}}function bf(a){return z(function(b){return b=+b,z(function(c,d){var e,f=a([],c.length,b),g=f.length;while(g--)c[e=f[g]]&&(c[e]=!(d[e]=c[e]))})})}function bg(a,b,c){if(a===b)return c;var d=a.nextSibling;while(d){if(d===b)return-1;d=d.nextSibling}return 1}function bh(a,b){var c,d,f,g,h,i,j,k=C[o][a];if(k)return b?0:k.slice(0);h=a,i=[],j=e.preFilter;while(h){if(!c||(d=M.exec(h)))d&&(h=h.slice(d[0].length)),i.push(f=[]);c=!1;if(d=N.exec(h))f.push(c=new q(d.shift())),h=h.slice(c.length),c.type=d[0].replace(L," ");for(g in e.filter)(d=W[g].exec(h))&&(!j[g]||(d=j[g](d,r,!0)))&&(f.push(c=new q(d.shift())),h=h.slice(c.length),c.type=g,c.matches=d);if(!c)break}return b?h.length:h?bc.error(a):C(a,i).slice(0)}function bi(a,b,d){var e=b.dir,f=d&&b.dir==="parentNode",g=u++;return b.first?function(b,c,d){while(b=b[e])if(f||b.nodeType===1)return a(b,c,d)}:function(b,d,h){if(!h){var i,j=t+" "+g+" ",k=j+c;while(b=b[e])if(f||b.nodeType===1){if((i=b[o])===k)return b.sizset;if(typeof i=="string"&&i.indexOf(j)===0){if(b.sizset)return b}else{b[o]=k;if(a(b,d,h))return b.sizset=!0,b;b.sizset=!1}}}else while(b=b[e])if(f||b.nodeType===1)if(a(b,d,h))return b}}function bj(a){return a.length>1?function(b,c,d){var e=a.length;while(e--)if(!a[e](b,c,d))return!1;return!0}:a[0]}function bk(a,b,c,d,e){var f,g=[],h=0,i=a.length,j=b!=null;for(;h<i;h++)if(f=a[h])if(!c||c(f,d,e))g.push(f),j&&b.push(h);return g}function bl(a,b,c,d,e,f){return d&&!d[o]&&(d=bl(d)),e&&!e[o]&&(e=bl(e,f)),z(function(f,g,h,i){if(f&&e)return;var j,k,l,m=[],n=[],o=g.length,p=f||bo(b||"*",h.nodeType?[h]:h,[],f),q=a&&(f||!b)?bk(p,m,a,h,i):p,r=c?e||(f?a:o||d)?[]:g:q;c&&c(q,r,h,i);if(d){l=bk(r,n),d(l,[],h,i),j=l.length;while(j--)if(k=l[j])r[n[j]]=!(q[n[j]]=k)}if(f){j=a&&r.length;while(j--)if(k=r[j])f[m[j]]=!(g[m[j]]=k)}else r=bk(r===g?r.splice(o,r.length):r),e?e(null,g,r,i):w.apply(g,r)})}function bm(a){var b,c,d,f=a.length,g=e.relative[a[0].type],h=g||e.relative[" "],i=g?1:0,j=bi(function(a){return a===b},h,!0),k=bi(function(a){return y.call(b,a)>-1},h,!0),m=[function(a,c,d){return!g&&(d||c!==l)||((b=c).nodeType?j(a,c,d):k(a,c,d))}];for(;i<f;i++)if(c=e.relative[a[i].type])m=[bi(bj(m),c)];else{c=e.filter[a[i].type].apply(null,a[i].matches);if(c[o]){d=++i;for(;d<f;d++)if(e.relative[a[d].type])break;return bl(i>1&&bj(m),i>1&&a.slice(0,i-1).join("").replace(L,"$1"),c,i<d&&bm(a.slice(i,d)),d<f&&bm(a=a.slice(d)),d<f&&a.join(""))}m.push(c)}return bj(m)}function bn(a,b){var d=b.length>0,f=a.length>0,g=function(h,i,j,k,m){var n,o,p,q=[],s=0,u="0",x=h&&[],y=m!=null,z=l,A=h||f&&e.find.TAG("*",m&&i.parentNode||i),B=t+=z==null?1:Math.E;y&&(l=i!==r&&i,c=g.el);for(;(n=A[u])!=null;u++){if(f&&n){for(o=0;p=a[o];o++)if(p(n,i,j)){k.push(n);break}y&&(t=B,c=++g.el)}d&&((n=!p&&n)&&s--,h&&x.push(n))}s+=u;if(d&&u!==s){for(o=0;p=b[o];o++)p(x,q,i,j);if(h){if(s>0)while(u--)!x[u]&&!q[u]&&(q[u]=v.call(k));q=bk(q)}w.apply(k,q),y&&!h&&q.length>0&&s+b.length>1&&bc.uniqueSort(k)}return y&&(t=B,l=z),x};return g.el=0,d?z(g):g}function bo(a,b,c,d){var e=0,f=b.length;for(;e<f;e++)bc(a,b[e],c,d);return c}function bp(a,b,c,d,f){var g,h,j,k,l,m=bh(a),n=m.length;if(!d&&m.length===1){h=m[0]=m[0].slice(0);if(h.length>2&&(j=h[0]).type==="ID"&&b.nodeType===9&&!f&&e.relative[h[1].type]){b=e.find.ID(j.matches[0].replace(V,""),b,f)[0];if(!b)return c;a=a.slice(h.shift().length)}for(g=W.POS.test(a)?-1:h.length-1;g>=0;g--){j=h[g];if(e.relative[k=j.type])break;if(l=e.find[k])if(d=l(j.matches[0].replace(V,""),R.test(h[0].type)&&b.parentNode||b,f)){h.splice(g,1),a=d.length&&h.join("");if(!a)return w.apply(c,x.call(d,0)),c;break}}}return i(a,m)(d,b,f,c,R.test(a)),c}function bq(){}var c,d,e,f,g,h,i,j,k,l,m=!0,n="undefined",o=("sizcache"+Math.random()).replace(".",""),q=String,r=a.document,s=r.documentElement,t=0,u=0,v=[].pop,w=[].push,x=[].slice,y=[].indexOf||function(a){var b=0,c=this.length;for(;b<c;b++)if(this[b]===a)return b;return-1},z=function(a,b){return a[o]=b==null||b,a},A=function(){var a={},b=[];return z(function(c,d){return b.push(c)>e.cacheLength&&delete a[b.shift()],a[c]=d},a)},B=A(),C=A(),D=A(),E="[\\x20\\t\\r\\n\\f]",F="(?:\\\\.|[-\\w]|[^\\x00-\\xa0])+",G=F.replace("w","w#"),H="([*^$|!~]?=)",I="\\["+E+"*("+F+")"+E+"*(?:"+H+E+"*(?:(['\"])((?:\\\\.|[^\\\\])*?)\\3|("+G+")|)|)"+E+"*\\]",J=":("+F+")(?:\\((?:(['\"])((?:\\\\.|[^\\\\])*?)\\2|([^()[\\]]*|(?:(?:"+I+")|[^:]|\\\\.)*|.*))\\)|)",K=":(even|odd|eq|gt|lt|nth|first|last)(?:\\("+E+"*((?:-\\d)?\\d*)"+E+"*\\)|)(?=[^-]|$)",L=new RegExp("^"+E+"+|((?:^|[^\\\\])(?:\\\\.)*)"+E+"+$","g"),M=new RegExp("^"+E+"*,"+E+"*"),N=new RegExp("^"+E+"*([\\x20\\t\\r\\n\\f>+~])"+E+"*"),O=new RegExp(J),P=/^(?:#([\w\-]+)|(\w+)|\.([\w\-]+))$/,Q=/^:not/,R=/[\x20\t\r\n\f]*[+~]/,S=/:not\($/,T=/h\d/i,U=/input|select|textarea|button/i,V=/\\(?!\\)/g,W={ID:new RegExp("^#("+F+")"),CLASS:new RegExp("^\\.("+F+")"),NAME:new RegExp("^\\[name=['\"]?("+F+")['\"]?\\]"),TAG:new RegExp("^("+F.replace("w","w*")+")"),ATTR:new RegExp("^"+I),PSEUDO:new RegExp("^"+J),POS:new RegExp(K,"i"),CHILD:new RegExp("^:(only|nth|first|last)-child(?:\\("+E+"*(even|odd|(([+-]|)(\\d*)n|)"+E+"*(?:([+-]|)"+E+"*(\\d+)|))"+E+"*\\)|)","i"),needsContext:new RegExp("^"+E+"*[>+~]|"+K,"i")},X=function(a){var b=r.createElement("div");try{return a(b)}catch(c){return!1}finally{b=null}},Y=X(function(a){return a.appendChild(r.createComment("")),!a.getElementsByTagName("*").length}),Z=X(function(a){return a.innerHTML="<a href='#'></a>",a.firstChild&&typeof a.firstChild.getAttribute!==n&&a.firstChild.getAttribute("href")==="#"}),$=X(function(a){a.innerHTML="<select></select>";var b=typeof a.lastChild.getAttribute("multiple");return b!=="boolean"&&b!=="string"}),_=X(function(a){return a.innerHTML="<div class='hidden e'></div><div class='hidden'></div>",!a.getElementsByClassName||!a.getElementsByClassName("e").length?!1:(a.lastChild.className="e",a.getElementsByClassName("e").length===2)}),ba=X(function(a){a.id=o+0,a.innerHTML="<a name='"+o+"'></a><div name='"+o+"'></div>",s.insertBefore(a,s.firstChild);var b=r.getElementsByName&&r.getElementsByName(o).length===2+r.getElementsByName(o+0).length;return d=!r.getElementById(o),s.removeChild(a),b});try{x.call(s.childNodes,0)[0].nodeType}catch(bb){x=function(a){var b,c=[];for(;b=this[a];a++)c.push(b);return c}}bc.matches=function(a,b){return bc(a,null,null,b)},bc.matchesSelector=function(a,b){return bc(b,null,null,[a]).length>0},f=bc.getText=function(a){var b,c="",d=0,e=a.nodeType;if(e){if(e===1||e===9||e===11){if(typeof a.textContent=="string")return a.textContent;for(a=a.firstChild;a;a=a.nextSibling)c+=f(a)}else if(e===3||e===4)return a.nodeValue}else for(;b=a[d];d++)c+=f(b);return c},g=bc.isXML=function(a){var b=a&&(a.ownerDocument||a).documentElement;return b?b.nodeName!=="HTML":!1},h=bc.contains=s.contains?function(a,b){var c=a.nodeType===9?a.documentElement:a,d=b&&b.parentNode;return a===d||!!(d&&d.nodeType===1&&c.contains&&c.contains(d))}:s.compareDocumentPosition?function(a,b){return b&&!!(a.compareDocumentPosition(b)&16)}:function(a,b){while(b=b.parentNode)if(b===a)return!0;return!1},bc.attr=function(a,b){var c,d=g(a);return d||(b=b.toLowerCase()),(c=e.attrHandle[b])?c(a):d||$?a.getAttribute(b):(c=a.getAttributeNode(b),c?typeof a[b]=="boolean"?a[b]?b:null:c.specified?c.value:null:null)},e=bc.selectors={cacheLength:50,createPseudo:z,match:W,attrHandle:Z?{}:{href:function(a){return a.getAttribute("href",2)},type:function(a){return a.getAttribute("type")}},find:{ID:d?function(a,b,c){if(typeof b.getElementById!==n&&!c){var d=b.getElementById(a);return d&&d.parentNode?[d]:[]}}:function(a,c,d){if(typeof c.getElementById!==n&&!d){var e=c.getElementById(a);return e?e.id===a||typeof e.getAttributeNode!==n&&e.getAttributeNode("id").value===a?[e]:b:[]}},TAG:Y?function(a,b){if(typeof b.getElementsByTagName!==n)return b.getElementsByTagName(a)}:function(a,b){var c=b.getElementsByTagName(a);if(a==="*"){var d,e=[],f=0;for(;d=c[f];f++)d.nodeType===1&&e.push(d);return e}return c},NAME:ba&&function(a,b){if(typeof b.getElementsByName!==n)return b.getElementsByName(name)},CLASS:_&&function(a,b,c){if(typeof b.getElementsByClassName!==n&&!c)return b.getElementsByClassName(a)}},relative:{">":{dir:"parentNode",first:!0}," ":{dir:"parentNode"},"+":{dir:"previousSibling",first:!0},"~":{dir:"previousSibling"}},preFilter:{ATTR:function(a){return a[1]=a[1].replace(V,""),a[3]=(a[4]||a[5]||"").replace(V,""),a[2]==="~="&&(a[3]=" "+a[3]+" "),a.slice(0,4)},CHILD:function(a){return a[1]=a[1].toLowerCase(),a[1]==="nth"?(a[2]||bc.error(a[0]),a[3]=+(a[3]?a[4]+(a[5]||1):2*(a[2]==="even"||a[2]==="odd")),a[4]=+(a[6]+a[7]||a[2]==="odd")):a[2]&&bc.error(a[0]),a},PSEUDO:function(a){var b,c;if(W.CHILD.test(a[0]))return null;if(a[3])a[2]=a[3];else if(b=a[4])O.test(b)&&(c=bh(b,!0))&&(c=b.indexOf(")",b.length-c)-b.length)&&(b=b.slice(0,c),a[0]=a[0].slice(0,c)),a[2]=b;return a.slice(0,3)}},filter:{ID:d?function(a){return a=a.replace(V,""),function(b){return b.getAttribute("id")===a}}:function(a){return a=a.replace(V,""),function(b){var c=typeof b.getAttributeNode!==n&&b.getAttributeNode("id");return c&&c.value===a}},TAG:function(a){return a==="*"?function(){return!0}:(a=a.replace(V,"").toLowerCase(),function(b){return b.nodeName&&b.nodeName.toLowerCase()===a})},CLASS:function(a){var b=B[o][a];return b||(b=B(a,new RegExp("(^|"+E+")"+a+"("+E+"|$)"))),function(a){return b.test(a.className||typeof a.getAttribute!==n&&a.getAttribute("class")||"")}},ATTR:function(a,b,c){return function(d,e){var f=bc.attr(d,a);return f==null?b==="!=":b?(f+="",b==="="?f===c:b==="!="?f!==c:b==="^="?c&&f.indexOf(c)===0:b==="*="?c&&f.indexOf(c)>-1:b==="$="?c&&f.substr(f.length-c.length)===c:b==="~="?(" "+f+" ").indexOf(c)>-1:b==="|="?f===c||f.substr(0,c.length+1)===c+"-":!1):!0}},CHILD:function(a,b,c,d){return a==="nth"?function(a){var b,e,f=a.parentNode;if(c===1&&d===0)return!0;if(f){e=0;for(b=f.firstChild;b;b=b.nextSibling)if(b.nodeType===1){e++;if(a===b)break}}return e-=d,e===c||e%c===0&&e/c>=0}:function(b){var c=b;switch(a){case"only":case"first":while(c=c.previousSibling)if(c.nodeType===1)return!1;if(a==="first")return!0;c=b;case"last":while(c=c.nextSibling)if(c.nodeType===1)return!1;return!0}}},PSEUDO:function(a,b){var c,d=e.pseudos[a]||e.setFilters[a.toLowerCase()]||bc.error("unsupported pseudo: "+a);return d[o]?d(b):d.length>1?(c=[a,a,"",b],e.setFilters.hasOwnProperty(a.toLowerCase())?z(function(a,c){var e,f=d(a,b),g=f.length;while(g--)e=y.call(a,f[g]),a[e]=!(c[e]=f[g])}):function(a){return d(a,0,c)}):d}},pseudos:{not:z(function(a){var b=[],c=[],d=i(a.replace(L,"$1"));return d[o]?z(function(a,b,c,e){var f,g=d(a,null,e,[]),h=a.length;while(h--)if(f=g[h])a[h]=!(b[h]=f)}):function(a,e,f){return b[0]=a,d(b,null,f,c),!c.pop()}}),has:z(function(a){return function(b){return bc(a,b).length>0}}),contains:z(function(a){return function(b){return(b.textContent||b.innerText||f(b)).indexOf(a)>-1}}),enabled:function(a){return a.disabled===!1},disabled:function(a){return a.disabled===!0},checked:function(a){var b=a.nodeName.toLowerCase();return b==="input"&&!!a.checked||b==="option"&&!!a.selected},selected:function(a){return a.parentNode&&a.parentNode.selectedIndex,a.selected===!0},parent:function(a){return!e.pseudos.empty(a)},empty:function(a){var b;a=a.firstChild;while(a){if(a.nodeName>"@"||(b=a.nodeType)===3||b===4)return!1;a=a.nextSibling}return!0},header:function(a){return T.test(a.nodeName)},text:function(a){var b,c;return a.nodeName.toLowerCase()==="input"&&(b=a.type)==="text"&&((c=a.getAttribute("type"))==null||c.toLowerCase()===b)},radio:bd("radio"),checkbox:bd("checkbox"),file:bd("file"),password:bd("password"),image:bd("image"),submit:be("submit"),reset:be("reset"),button:function(a){var b=a.nodeName.toLowerCase();return b==="input"&&a.type==="button"||b==="button"},input:function(a){return U.test(a.nodeName)},focus:function(a){var b=a.ownerDocument;return a===b.activeElement&&(!b.hasFocus||b.hasFocus())&&(!!a.type||!!a.href)},active:function(a){return a===a.ownerDocument.activeElement},first:bf(function(a,b,c){return[0]}),last:bf(function(a,b,c){return[b-1]}),eq:bf(function(a,b,c){return[c<0?c+b:c]}),even:bf(function(a,b,c){for(var d=0;d<b;d+=2)a.push(d);return a}),odd:bf(function(a,b,c){for(var d=1;d<b;d+=2)a.push(d);return a}),lt:bf(function(a,b,c){for(var d=c<0?c+b:c;--d>=0;)a.push(d);return a}),gt:bf(function(a,b,c){for(var d=c<0?c+b:c;++d<b;)a.push(d);return a})}},j=s.compareDocumentPosition?function(a,b){return a===b?(k=!0,0):(!a.compareDocumentPosition||!b.compareDocumentPosition?a.compareDocumentPosition:a.compareDocumentPosition(b)&4)?-1:1}:function(a,b){if(a===b)return k=!0,0;if(a.sourceIndex&&b.sourceIndex)return a.sourceIndex-b.sourceIndex;var c,d,e=[],f=[],g=a.parentNode,h=b.parentNode,i=g;if(g===h)return bg(a,b);if(!g)return-1;if(!h)return 1;while(i)e.unshift(i),i=i.parentNode;i=h;while(i)f.unshift(i),i=i.parentNode;c=e.length,d=f.length;for(var j=0;j<c&&j<d;j++)if(e[j]!==f[j])return bg(e[j],f[j]);return j===c?bg(a,f[j],-1):bg(e[j],b,1)},[0,0].sort(j),m=!k,bc.uniqueSort=function(a){var b,c=1;k=m,a.sort(j);if(k)for(;b=a[c];c++)b===a[c-1]&&a.splice(c--,1);return a},bc.error=function(a){throw new Error("Syntax error, unrecognized expression: "+a)},i=bc.compile=function(a,b){var c,d=[],e=[],f=D[o][a];if(!f){b||(b=bh(a)),c=b.length;while(c--)f=bm(b[c]),f[o]?d.push(f):e.push(f);f=D(a,bn(e,d))}return f},r.querySelectorAll&&function(){var a,b=bp,c=/'|\\/g,d=/\=[\x20\t\r\n\f]*([^'"\]]*)[\x20\t\r\n\f]*\]/g,e=[":focus"],f=[":active",":focus"],h=s.matchesSelector||s.mozMatchesSelector||s.webkitMatchesSelector||s.oMatchesSelector||s.msMatchesSelector;X(function(a){a.innerHTML="<select><option selected=''></option></select>",a.querySelectorAll("[selected]").length||e.push("\\["+E+"*(?:checked|disabled|ismap|multiple|readonly|selected|value)"),a.querySelectorAll(":checked").length||e.push(":checked")}),X(function(a){a.innerHTML="<p test=''></p>",a.querySelectorAll("[test^='']").length&&e.push("[*^$]="+E+"*(?:\"\"|'')"),a.innerHTML="<input type='hidden'/>",a.querySelectorAll(":enabled").length||e.push(":enabled",":disabled")}),e=new RegExp(e.join("|")),bp=function(a,d,f,g,h){if(!g&&!h&&(!e||!e.test(a))){var i,j,k=!0,l=o,m=d,n=d.nodeType===9&&a;if(d.nodeType===1&&d.nodeName.toLowerCase()!=="object"){i=bh(a),(k=d.getAttribute("id"))?l=k.replace(c,"\\$&"):d.setAttribute("id",l),l="[id='"+l+"'] ",j=i.length;while(j--)i[j]=l+i[j].join("");m=R.test(a)&&d.parentNode||d,n=i.join(",")}if(n)try{return w.apply(f,x.call(m.querySelectorAll(n),0)),f}catch(p){}finally{k||d.removeAttribute("id")}}return b(a,d,f,g,h)},h&&(X(function(b){a=h.call(b,"div");try{h.call(b,"[test!='']:sizzle"),f.push("!=",J)}catch(c){}}),f=new RegExp(f.join("|")),bc.matchesSelector=function(b,c){c=c.replace(d,"='$1']");if(!g(b)&&!f.test(c)&&(!e||!e.test(c)))try{var i=h.call(b,c);if(i||a||b.document&&b.document.nodeType!==11)return i}catch(j){}return bc(c,null,null,[b]).length>0})}(),e.pseudos.nth=e.pseudos.eq,e.filters=bq.prototype=e.pseudos,e.setFilters=new bq,bc.attr=p.attr,p.find=bc,p.expr=bc.selectors,p.expr[":"]=p.expr.pseudos,p.unique=bc.uniqueSort,p.text=bc.getText,p.isXMLDoc=bc.isXML,p.contains=bc.contains}(a);var bc=/Until$/,bd=/^(?:parents|prev(?:Until|All))/,be=/^.[^:#\[\.,]*$/,bf=p.expr.match.needsContext,bg={children:!0,contents:!0,next:!0,prev:!0};p.fn.extend({find:function(a){var b,c,d,e,f,g,h=this;if(typeof a!="string")return p(a).filter(function(){for(b=0,c=h.length;b<c;b++)if(p.contains(h[b],this))return!0});g=this.pushStack("","find",a);for(b=0,c=this.length;b<c;b++){d=g.length,p.find(a,this[b],g);if(b>0)for(e=d;e<g.length;e++)for(f=0;f<d;f++)if(g[f]===g[e]){g.splice(e--,1);break}}return g},has:function(a){var b,c=p(a,this),d=c.length;return this.filter(function(){for(b=0;b<d;b++)if(p.contains(this,c[b]))return!0})},not:function(a){return this.pushStack(bj(this,a,!1),"not",a)},filter:function(a){return this.pushStack(bj(this,a,!0),"filter",a)},is:function(a){return!!a&&(typeof a=="string"?bf.test(a)?p(a,this.context).index(this[0])>=0:p.filter(a,this).length>0:this.filter(a).length>0)},closest:function(a,b){var c,d=0,e=this.length,f=[],g=bf.test(a)||typeof a!="string"?p(a,b||this.context):0;for(;d<e;d++){c=this[d];while(c&&c.ownerDocument&&c!==b&&c.nodeType!==11){if(g?g.index(c)>-1:p.find.matchesSelector(c,a)){f.push(c);break}c=c.parentNode}}return f=f.length>1?p.unique(f):f,this.pushStack(f,"closest",a)},index:function(a){return a?typeof a=="string"?p.inArray(this[0],p(a)):p.inArray(a.jquery?a[0]:a,this):this[0]&&this[0].parentNode?this.prevAll().length:-1},add:function(a,b){var c=typeof a=="string"?p(a,b):p.makeArray(a&&a.nodeType?[a]:a),d=p.merge(this.get(),c);return this.pushStack(bh(c[0])||bh(d[0])?d:p.unique(d))},addBack:function(a){return this.add(a==null?this.prevObject:this.prevObject.filter(a))}}),p.fn.andSelf=p.fn.addBack,p.each({parent:function(a){var b=a.parentNode;return b&&b.nodeType!==11?b:null},parents:function(a){return p.dir(a,"parentNode")},parentsUntil:function(a,b,c){return p.dir(a,"parentNode",c)},next:function(a){return bi(a,"nextSibling")},prev:function(a){return bi(a,"previousSibling")},nextAll:function(a){return p.dir(a,"nextSibling")},prevAll:function(a){return p.dir(a,"previousSibling")},nextUntil:function(a,b,c){return p.dir(a,"nextSibling",c)},prevUntil:function(a,b,c){return p.dir(a,"previousSibling",c)},siblings:function(a){return p.sibling((a.parentNode||{}).firstChild,a)},children:function(a){return p.sibling(a.firstChild)},contents:function(a){return p.nodeName(a,"iframe")?a.contentDocument||a.contentWindow.document:p.merge([],a.childNodes)}},function(a,b){p.fn[a]=function(c,d){var e=p.map(this,b,c);return bc.test(a)||(d=c),d&&typeof d=="string"&&(e=p.filter(d,e)),e=this.length>1&&!bg[a]?p.unique(e):e,this.length>1&&bd.test(a)&&(e=e.reverse()),this.pushStack(e,a,k.call(arguments).join(","))}}),p.extend({filter:function(a,b,c){return c&&(a=":not("+a+")"),b.length===1?p.find.matchesSelector(b[0],a)?[b[0]]:[]:p.find.matches(a,b)},dir:function(a,c,d){var e=[],f=a[c];while(f&&f.nodeType!==9&&(d===b||f.nodeType!==1||!p(f).is(d)))f.nodeType===1&&e.push(f),f=f[c];return e},sibling:function(a,b){var c=[];for(;a;a=a.nextSibling)a.nodeType===1&&a!==b&&c.push(a);return c}});var bl="abbr|article|aside|audio|bdi|canvas|data|datalist|details|figcaption|figure|footer|header|hgroup|mark|meter|nav|output|progress|section|summary|time|video",bm=/ jQuery\d+="(?:null|\d+)"/g,bn=/^\s+/,bo=/<(?!area|br|col|embed|hr|img|input|link|meta|param)(([\w:]+)[^>]*)\/>/gi,bp=/<([\w:]+)/,bq=/<tbody/i,br=/<|&#?\w+;/,bs=/<(?:script|style|link)/i,bt=/<(?:script|object|embed|option|style)/i,bu=new RegExp("<(?:"+bl+")[\\s/>]","i"),bv=/^(?:checkbox|radio)$/,bw=/checked\s*(?:[^=]|=\s*.checked.)/i,bx=/\/(java|ecma)script/i,by=/^\s*<!(?:\[CDATA\[|\-\-)|[\]\-]{2}>\s*$/g,bz={option:[1,"<select multiple='multiple'>","</select>"],legend:[1,"<fieldset>","</fieldset>"],thead:[1,"<table>","</table>"],tr:[2,"<table><tbody>","</tbody></table>"],td:[3,"<table><tbody><tr>","</tr></tbody></table>"],col:[2,"<table><tbody></tbody><colgroup>","</colgroup></table>"],area:[1,"<map>","</map>"],_default:[0,"",""]},bA=bk(e),bB=bA.appendChild(e.createElement("div"));bz.optgroup=bz.option,bz.tbody=bz.tfoot=bz.colgroup=bz.caption=bz.thead,bz.th=bz.td,p.support.htmlSerialize||(bz._default=[1,"X<div>","</div>"]),p.fn.extend({text:function(a){return p.access(this,function(a){return a===b?p.text(this):this.empty().append((this[0]&&this[0].ownerDocument||e).createTextNode(a))},null,a,arguments.length)},wrapAll:function(a){if(p.isFunction(a))return this.each(function(b){p(this).wrapAll(a.call(this,b))});if(this[0]){var b=p(a,this[0].ownerDocument).eq(0).clone(!0);this[0].parentNode&&b.insertBefore(this[0]),b.map(function(){var a=this;while(a.firstChild&&a.firstChild.nodeType===1)a=a.firstChild;return a}).append(this)}return this},wrapInner:function(a){return p.isFunction(a)?this.each(function(b){p(this).wrapInner(a.call(this,b))}):this.each(function(){var b=p(this),c=b.contents();c.length?c.wrapAll(a):b.append(a)})},wrap:function(a){var b=p.isFunction(a);return this.each(function(c){p(this).wrapAll(b?a.call(this,c):a)})},unwrap:function(){return this.parent().each(function(){p.nodeName(this,"body")||p(this).replaceWith(this.childNodes)}).end()},append:function(){return this.domManip(arguments,!0,function(a){(this.nodeType===1||this.nodeType===11)&&this.appendChild(a)})},prepend:function(){return this.domManip(arguments,!0,function(a){(this.nodeType===1||this.nodeType===11)&&this.insertBefore(a,this.firstChild)})},before:function(){if(!bh(this[0]))return this.domManip(arguments,!1,function(a){this.parentNode.insertBefore(a,this)});if(arguments.length){var a=p.clean(arguments);return this.pushStack(p.merge(a,this),"before",this.selector)}},after:function(){if(!bh(this[0]))return this.domManip(arguments,!1,function(a){this.parentNode.insertBefore(a,this.nextSibling)});if(arguments.length){var a=p.clean(arguments);return this.pushStack(p.merge(this,a),"after",this.selector)}},remove:function(a,b){var c,d=0;for(;(c=this[d])!=null;d++)if(!a||p.filter(a,[c]).length)!b&&c.nodeType===1&&(p.cleanData(c.getElementsByTagName("*")),p.cleanData([c])),c.parentNode&&c.parentNode.removeChild(c);return this},empty:function(){var a,b=0;for(;(a=this[b])!=null;b++){a.nodeType===1&&p.cleanData(a.getElementsByTagName("*"));while(a.firstChild)a.removeChild(a.firstChild)}return this},clone:function(a,b){return a=a==null?!1:a,b=b==null?a:b,this.map(function(){return p.clone(this,a,b)})},html:function(a){return p.access(this,function(a){var c=this[0]||{},d=0,e=this.length;if(a===b)return c.nodeType===1?c.innerHTML.replace(bm,""):b;if(typeof a=="string"&&!bs.test(a)&&(p.support.htmlSerialize||!bu.test(a))&&(p.support.leadingWhitespace||!bn.test(a))&&!bz[(bp.exec(a)||["",""])[1].toLowerCase()]){a=a.replace(bo,"<$1></$2>");try{for(;d<e;d++)c=this[d]||{},c.nodeType===1&&(p.cleanData(c.getElementsByTagName("*")),c.innerHTML=a);c=0}catch(f){}}c&&this.empty().append(a)},null,a,arguments.length)},replaceWith:function(a){return bh(this[0])?this.length?this.pushStack(p(p.isFunction(a)?a():a),"replaceWith",a):this:p.isFunction(a)?this.each(function(b){var c=p(this),d=c.html();c.replaceWith(a.call(this,b,d))}):(typeof a!="string"&&(a=p(a).detach()),this.each(function(){var b=this.nextSibling,c=this.parentNode;p(this).remove(),b?p(b).before(a):p(c).append(a)}))},detach:function(a){return this.remove(a,!0)},domManip:function(a,c,d){a=[].concat.apply([],a);var e,f,g,h,i=0,j=a[0],k=[],l=this.length;if(!p.support.checkClone&&l>1&&typeof j=="string"&&bw.test(j))return this.each(function(){p(this).domManip(a,c,d)});if(p.isFunction(j))return this.each(function(e){var f=p(this);a[0]=j.call(this,e,c?f.html():b),f.domManip(a,c,d)});if(this[0]){e=p.buildFragment(a,this,k),g=e.fragment,f=g.firstChild,g.childNodes.length===1&&(g=f);if(f){c=c&&p.nodeName(f,"tr");for(h=e.cacheable||l-1;i<l;i++)d.call(c&&p.nodeName(this[i],"table")?bC(this[i],"tbody"):this[i],i===h?g:p.clone(g,!0,!0))}g=f=null,k.length&&p.each(k,function(a,b){b.src?p.ajax?p.ajax({url:b.src,type:"GET",dataType:"script",async:!1,global:!1,"throws":!0}):p.error("no ajax"):p.globalEval((b.text||b.textContent||b.innerHTML||"").replace(by,"")),b.parentNode&&b.parentNode.removeChild(b)})}return this}}),p.buildFragment=function(a,c,d){var f,g,h,i=a[0];return c=c||e,c=!c.nodeType&&c[0]||c,c=c.ownerDocument||c,a.length===1&&typeof i=="string"&&i.length<512&&c===e&&i.charAt(0)==="<"&&!bt.test(i)&&(p.support.checkClone||!bw.test(i))&&(p.support.html5Clone||!bu.test(i))&&(g=!0,f=p.fragments[i],h=f!==b),f||(f=c.createDocumentFragment(),p.clean(a,c,f,d),g&&(p.fragments[i]=h&&f)),{fragment:f,cacheable:g}},p.fragments={},p.each({appendTo:"append",prependTo:"prepend",insertBefore:"before",insertAfter:"after",replaceAll:"replaceWith"},function(a,b){p.fn[a]=function(c){var d,e=0,f=[],g=p(c),h=g.length,i=this.length===1&&this[0].parentNode;if((i==null||i&&i.nodeType===11&&i.childNodes.length===1)&&h===1)return g[b](this[0]),this;for(;e<h;e++)d=(e>0?this.clone(!0):this).get(),p(g[e])[b](d),f=f.concat(d);return this.pushStack(f,a,g.selector)}}),p.extend({clone:function(a,b,c){var d,e,f,g;p.support.html5Clone||p.isXMLDoc(a)||!bu.test("<"+a.nodeName+">")?g=a.cloneNode(!0):(bB.innerHTML=a.outerHTML,bB.removeChild(g=bB.firstChild));if((!p.support.noCloneEvent||!p.support.noCloneChecked)&&(a.nodeType===1||a.nodeType===11)&&!p.isXMLDoc(a)){bE(a,g),d=bF(a),e=bF(g);for(f=0;d[f];++f)e[f]&&bE(d[f],e[f])}if(b){bD(a,g);if(c){d=bF(a),e=bF(g);for(f=0;d[f];++f)bD(d[f],e[f])}}return d=e=null,g},clean:function(a,b,c,d){var f,g,h,i,j,k,l,m,n,o,q,r,s=b===e&&bA,t=[];if(!b||typeof b.createDocumentFragment=="undefined")b=e;for(f=0;(h=a[f])!=null;f++){typeof h=="number"&&(h+="");if(!h)continue;if(typeof h=="string")if(!br.test(h))h=b.createTextNode(h);else{s=s||bk(b),l=b.createElement("div"),s.appendChild(l),h=h.replace(bo,"<$1></$2>"),i=(bp.exec(h)||["",""])[1].toLowerCase(),j=bz[i]||bz._default,k=j[0],l.innerHTML=j[1]+h+j[2];while(k--)l=l.lastChild;if(!p.support.tbody){m=bq.test(h),n=i==="table"&&!m?l.firstChild&&l.firstChild.childNodes:j[1]==="<table>"&&!m?l.childNodes:[];for(g=n.length-1;g>=0;--g)p.nodeName(n[g],"tbody")&&!n[g].childNodes.length&&n[g].parentNode.removeChild(n[g])}!p.support.leadingWhitespace&&bn.test(h)&&l.insertBefore(b.createTextNode(bn.exec(h)[0]),l.firstChild),h=l.childNodes,l.parentNode.removeChild(l)}h.nodeType?t.push(h):p.merge(t,h)}l&&(h=l=s=null);if(!p.support.appendChecked)for(f=0;(h=t[f])!=null;f++)p.nodeName(h,"input")?bG(h):typeof h.getElementsByTagName!="undefined"&&p.grep(h.getElementsByTagName("input"),bG);if(c){q=function(a){if(!a.type||bx.test(a.type))return d?d.push(a.parentNode?a.parentNode.removeChild(a):a):c.appendChild(a)};for(f=0;(h=t[f])!=null;f++)if(!p.nodeName(h,"script")||!q(h))c.appendChild(h),typeof h.getElementsByTagName!="undefined"&&(r=p.grep(p.merge([],h.getElementsByTagName("script")),q),t.splice.apply(t,[f+1,0].concat(r)),f+=r.length)}return t},cleanData:function(a,b){var c,d,e,f,g=0,h=p.expando,i=p.cache,j=p.support.deleteExpando,k=p.event.special;for(;(e=a[g])!=null;g++)if(b||p.acceptData(e)){d=e[h],c=d&&i[d];if(c){if(c.events)for(f in c.events)k[f]?p.event.remove(e,f):p.removeEvent(e,f,c.handle);i[d]&&(delete i[d],j?delete e[h]:e.removeAttribute?e.removeAttribute(h):e[h]=null,p.deletedIds.push(d))}}}}),function(){var a,b;p.uaMatch=function(a){a=a.toLowerCase();var b=/(chrome)[ \/]([\w.]+)/.exec(a)||/(webkit)[ \/]([\w.]+)/.exec(a)||/(opera)(?:.*version|)[ \/]([\w.]+)/.exec(a)||/(msie) ([\w.]+)/.exec(a)||a.indexOf("compatible")<0&&/(mozilla)(?:.*? rv:([\w.]+)|)/.exec(a)||[];return{browser:b[1]||"",version:b[2]||"0"}},a=p.uaMatch(g.userAgent),b={},a.browser&&(b[a.browser]=!0,b.version=a.version),b.chrome?b.webkit=!0:b.webkit&&(b.safari=!0),p.browser=b,p.sub=function(){function a(b,c){return new a.fn.init(b,c)}p.extend(!0,a,this),a.superclass=this,a.fn=a.prototype=this(),a.fn.constructor=a,a.sub=this.sub,a.fn.init=function c(c,d){return d&&d instanceof p&&!(d instanceof a)&&(d=a(d)),p.fn.init.call(this,c,d,b)},a.fn.init.prototype=a.fn;var b=a(e);return a}}();var bH,bI,bJ,bK=/alpha\([^)]*\)/i,bL=/opacity=([^)]*)/,bM=/^(top|right|bottom|left)$/,bN=/^(none|table(?!-c[ea]).+)/,bO=/^margin/,bP=new RegExp("^("+q+")(.*)$","i"),bQ=new RegExp("^("+q+")(?!px)[a-z%]+$","i"),bR=new RegExp("^([-+])=("+q+")","i"),bS={},bT={position:"absolute",visibility:"hidden",display:"block"},bU={letterSpacing:0,fontWeight:400},bV=["Top","Right","Bottom","Left"],bW=["Webkit","O","Moz","ms"],bX=p.fn.toggle;p.fn.extend({css:function(a,c){return p.access(this,function(a,c,d){return d!==b?p.style(a,c,d):p.css(a,c)},a,c,arguments.length>1)},show:function(){return b$(this,!0)},hide:function(){return b$(this)},toggle:function(a,b){var c=typeof a=="boolean";return p.isFunction(a)&&p.isFunction(b)?bX.apply(this,arguments):this.each(function(){(c?a:bZ(this))?p(this).show():p(this).hide()})}}),p.extend({cssHooks:{opacity:{get:function(a,b){if(b){var c=bH(a,"opacity");return c===""?"1":c}}}},cssNumber:{fillOpacity:!0,fontWeight:!0,lineHeight:!0,opacity:!0,orphans:!0,widows:!0,zIndex:!0,zoom:!0},cssProps:{"float":p.support.cssFloat?"cssFloat":"styleFloat"},style:function(a,c,d,e){if(!a||a.nodeType===3||a.nodeType===8||!a.style)return;var f,g,h,i=p.camelCase(c),j=a.style;c=p.cssProps[i]||(p.cssProps[i]=bY(j,i)),h=p.cssHooks[c]||p.cssHooks[i];if(d===b)return h&&"get"in h&&(f=h.get(a,!1,e))!==b?f:j[c];g=typeof d,g==="string"&&(f=bR.exec(d))&&(d=(f[1]+1)*f[2]+parseFloat(p.css(a,c)),g="number");if(d==null||g==="number"&&isNaN(d))return;g==="number"&&!p.cssNumber[i]&&(d+="px");if(!h||!("set"in h)||(d=h.set(a,d,e))!==b)try{j[c]=d}catch(k){}},css:function(a,c,d,e){var f,g,h,i=p.camelCase(c);return c=p.cssProps[i]||(p.cssProps[i]=bY(a.style,i)),h=p.cssHooks[c]||p.cssHooks[i],h&&"get"in h&&(f=h.get(a,!0,e)),f===b&&(f=bH(a,c)),f==="normal"&&c in bU&&(f=bU[c]),d||e!==b?(g=parseFloat(f),d||p.isNumeric(g)?g||0:f):f},swap:function(a,b,c){var d,e,f={};for(e in b)f[e]=a.style[e],a.style[e]=b[e];d=c.call(a);for(e in b)a.style[e]=f[e];return d}}),a.getComputedStyle?bH=function(b,c){var d,e,f,g,h=a.getComputedStyle(b,null),i=b.style;return h&&(d=h[c],d===""&&!p.contains(b.ownerDocument,b)&&(d=p.style(b,c)),bQ.test(d)&&bO.test(c)&&(e=i.width,f=i.minWidth,g=i.maxWidth,i.minWidth=i.maxWidth=i.width=d,d=h.width,i.width=e,i.minWidth=f,i.maxWidth=g)),d}:e.documentElement.currentStyle&&(bH=function(a,b){var c,d,e=a.currentStyle&&a.currentStyle[b],f=a.style;return e==null&&f&&f[b]&&(e=f[b]),bQ.test(e)&&!bM.test(b)&&(c=f.left,d=a.runtimeStyle&&a.runtimeStyle.left,d&&(a.runtimeStyle.left=a.currentStyle.left),f.left=b==="fontSize"?"1em":e,e=f.pixelLeft+"px",f.left=c,d&&(a.runtimeStyle.left=d)),e===""?"auto":e}),p.each(["height","width"],function(a,b){p.cssHooks[b]={get:function(a,c,d){if(c)return a.offsetWidth===0&&bN.test(bH(a,"display"))?p.swap(a,bT,function(){return cb(a,b,d)}):cb(a,b,d)},set:function(a,c,d){return b_(a,c,d?ca(a,b,d,p.support.boxSizing&&p.css(a,"boxSizing")==="border-box"):0)}}}),p.support.opacity||(p.cssHooks.opacity={get:function(a,b){return bL.test((b&&a.currentStyle?a.currentStyle.filter:a.style.filter)||"")?.01*parseFloat(RegExp.$1)+"":b?"1":""},set:function(a,b){var c=a.style,d=a.currentStyle,e=p.isNumeric(b)?"alpha(opacity="+b*100+")":"",f=d&&d.filter||c.filter||"";c.zoom=1;if(b>=1&&p.trim(f.replace(bK,""))===""&&c.removeAttribute){c.removeAttribute("filter");if(d&&!d.filter)return}c.filter=bK.test(f)?f.replace(bK,e):f+" "+e}}),p(function(){p.support.reliableMarginRight||(p.cssHooks.marginRight={get:function(a,b){return p.swap(a,{display:"inline-block"},function(){if(b)return bH(a,"marginRight")})}}),!p.support.pixelPosition&&p.fn.position&&p.each(["top","left"],function(a,b){p.cssHooks[b]={get:function(a,c){if(c){var d=bH(a,b);return bQ.test(d)?p(a).position()[b]+"px":d}}}})}),p.expr&&p.expr.filters&&(p.expr.filters.hidden=function(a){return a.offsetWidth===0&&a.offsetHeight===0||!p.support.reliableHiddenOffsets&&(a.style&&a.style.display||bH(a,"display"))==="none"},p.expr.filters.visible=function(a){return!p.expr.filters.hidden(a)}),p.each({margin:"",padding:"",border:"Width"},function(a,b){p.cssHooks[a+b]={expand:function(c){var d,e=typeof c=="string"?c.split(" "):[c],f={};for(d=0;d<4;d++)f[a+bV[d]+b]=e[d]||e[d-2]||e[0];return f}},bO.test(a)||(p.cssHooks[a+b].set=b_)});var cd=/%20/g,ce=/\[\]$/,cf=/\r?\n/g,cg=/^(?:color|date|datetime|datetime-local|email|hidden|month|number|password|range|search|tel|text|time|url|week)$/i,ch=/^(?:select|textarea)/i;p.fn.extend({serialize:function(){return p.param(this.serializeArray())},serializeArray:function(){return this.map(function(){return this.elements?p.makeArray(this.elements):this}).filter(function(){return this.name&&!this.disabled&&(this.checked||ch.test(this.nodeName)||cg.test(this.type))}).map(function(a,b){var c=p(this).val();return c==null?null:p.isArray(c)?p.map(c,function(a,c){return{name:b.name,value:a.replace(cf,"\r\n")}}):{name:b.name,value:c.replace(cf,"\r\n")}}).get()}}),p.param=function(a,c){var d,e=[],f=function(a,b){b=p.isFunction(b)?b():b==null?"":b,e[e.length]=encodeURIComponent(a)+"="+encodeURIComponent(b)};c===b&&(c=p.ajaxSettings&&p.ajaxSettings.traditional);if(p.isArray(a)||a.jquery&&!p.isPlainObject(a))p.each(a,function(){f(this.name,this.value)});else for(d in a)ci(d,a[d],c,f);return e.join("&").replace(cd,"+")};var cj,ck,cl=/#.*$/,cm=/^(.*?):[ \t]*([^\r\n]*)\r?$/mg,cn=/^(?:about|app|app\-storage|.+\-extension|file|res|widget):$/,co=/^(?:GET|HEAD)$/,cp=/^\/\//,cq=/\?/,cr=/<script\b[^<]*(?:(?!<\/script>)<[^<]*)*<\/script>/gi,cs=/([?&])_=[^&]*/,ct=/^([\w\+\.\-]+:)(?:\/\/([^\/?#:]*)(?::(\d+)|)|)/,cu=p.fn.load,cv={},cw={},cx=["*/"]+["*"];try{ck=f.href}catch(cy){ck=e.createElement("a"),ck.href="",ck=ck.href}cj=ct.exec(ck.toLowerCase())||[],p.fn.load=function(a,c,d){if(typeof a!="string"&&cu)return cu.apply(this,arguments);if(!this.length)return this;var e,f,g,h=this,i=a.indexOf(" ");return i>=0&&(e=a.slice(i,a.length),a=a.slice(0,i)),p.isFunction(c)?(d=c,c=b):c&&typeof c=="object"&&(f="POST"),p.ajax({url:a,type:f,dataType:"html",data:c,complete:function(a,b){d&&h.each(d,g||[a.responseText,b,a])}}).done(function(a){g=arguments,h.html(e?p("<div>").append(a.replace(cr,"")).find(e):a)}),this},p.each("ajaxStart ajaxStop ajaxComplete ajaxError ajaxSuccess ajaxSend".split(" "),function(a,b){p.fn[b]=function(a){return this.on(b,a)}}),p.each(["get","post"],function(a,c){p[c]=function(a,d,e,f){return p.isFunction(d)&&(f=f||e,e=d,d=b),p.ajax({type:c,url:a,data:d,success:e,dataType:f})}}),p.extend({getScript:function(a,c){return p.get(a,b,c,"script")},getJSON:function(a,b,c){return p.get(a,b,c,"json")},ajaxSetup:function(a,b){return b?cB(a,p.ajaxSettings):(b=a,a=p.ajaxSettings),cB(a,b),a},ajaxSettings:{url:ck,isLocal:cn.test(cj[1]),global:!0,type:"GET",contentType:"application/x-www-form-urlencoded; charset=UTF-8",processData:!0,async:!0,accepts:{xml:"application/xml, text/xml",html:"text/html",text:"text/plain",json:"application/json, text/javascript","*":cx},contents:{xml:/xml/,html:/html/,json:/json/},responseFields:{xml:"responseXML",text:"responseText"},converters:{"* text":a.String,"text html":!0,"text json":p.parseJSON,"text xml":p.parseXML},flatOptions:{context:!0,url:!0}},ajaxPrefilter:cz(cv),ajaxTransport:cz(cw),ajax:function(a,c){function y(a,c,f,i){var k,s,t,u,w,y=c;if(v===2)return;v=2,h&&clearTimeout(h),g=b,e=i||"",x.readyState=a>0?4:0,f&&(u=cC(l,x,f));if(a>=200&&a<300||a===304)l.ifModified&&(w=x.getResponseHeader("Last-Modified"),w&&(p.lastModified[d]=w),w=x.getResponseHeader("Etag"),w&&(p.etag[d]=w)),a===304?(y="notmodified",k=!0):(k=cD(l,u),y=k.state,s=k.data,t=k.error,k=!t);else{t=y;if(!y||a)y="error",a<0&&(a=0)}x.status=a,x.statusText=(c||y)+"",k?o.resolveWith(m,[s,y,x]):o.rejectWith(m,[x,y,t]),x.statusCode(r),r=b,j&&n.trigger("ajax"+(k?"Success":"Error"),[x,l,k?s:t]),q.fireWith(m,[x,y]),j&&(n.trigger("ajaxComplete",[x,l]),--p.active||p.event.trigger("ajaxStop"))}typeof a=="object"&&(c=a,a=b),c=c||{};var d,e,f,g,h,i,j,k,l=p.ajaxSetup({},c),m=l.context||l,n=m!==l&&(m.nodeType||m instanceof p)?p(m):p.event,o=p.Deferred(),q=p.Callbacks("once memory"),r=l.statusCode||{},t={},u={},v=0,w="canceled",x={readyState:0,setRequestHeader:function(a,b){if(!v){var c=a.toLowerCase();a=u[c]=u[c]||a,t[a]=b}return this},getAllResponseHeaders:function(){return v===2?e:null},getResponseHeader:function(a){var c;if(v===2){if(!f){f={};while(c=cm.exec(e))f[c[1].toLowerCase()]=c[2]}c=f[a.toLowerCase()]}return c===b?null:c},overrideMimeType:function(a){return v||(l.mimeType=a),this},abort:function(a){return a=a||w,g&&g.abort(a),y(0,a),this}};o.promise(x),x.success=x.done,x.error=x.fail,x.complete=q.add,x.statusCode=function(a){if(a){var b;if(v<2)for(b in a)r[b]=[r[b],a[b]];else b=a[x.status],x.always(b)}return this},l.url=((a||l.url)+"").replace(cl,"").replace(cp,cj[1]+"//"),l.dataTypes=p.trim(l.dataType||"*").toLowerCase().split(s),l.crossDomain==null&&(i=ct.exec(l.url.toLowerCase())||!1,l.crossDomain=i&&i.join(":")+(i[3]?"":i[1]==="http:"?80:443)!==cj.join(":")+(cj[3]?"":cj[1]==="http:"?80:443)),l.data&&l.processData&&typeof l.data!="string"&&(l.data=p.param(l.data,l.traditional)),cA(cv,l,c,x);if(v===2)return x;j=l.global,l.type=l.type.toUpperCase(),l.hasContent=!co.test(l.type),j&&p.active++===0&&p.event.trigger("ajaxStart");if(!l.hasContent){l.data&&(l.url+=(cq.test(l.url)?"&":"?")+l.data,delete l.data),d=l.url;if(l.cache===!1){var z=p.now(),A=l.url.replace(cs,"$1_="+z);l.url=A+(A===l.url?(cq.test(l.url)?"&":"?")+"_="+z:"")}}(l.data&&l.hasContent&&l.contentType!==!1||c.contentType)&&x.setRequestHeader("Content-Type",l.contentType),l.ifModified&&(d=d||l.url,p.lastModified[d]&&x.setRequestHeader("If-Modified-Since",p.lastModified[d]),p.etag[d]&&x.setRequestHeader("If-None-Match",p.etag[d])),x.setRequestHeader("Accept",l.dataTypes[0]&&l.accepts[l.dataTypes[0]]?l.accepts[l.dataTypes[0]]+(l.dataTypes[0]!=="*"?", "+cx+"; q=0.01":""):l.accepts["*"]);for(k in l.headers)x.setRequestHeader(k,l.headers[k]);if(!l.beforeSend||l.beforeSend.call(m,x,l)!==!1&&v!==2){w="abort";for(k in{success:1,error:1,complete:1})x[k](l[k]);g=cA(cw,l,c,x);if(!g)y(-1,"No Transport");else{x.readyState=1,j&&n.trigger("ajaxSend",[x,l]),l.async&&l.timeout>0&&(h=setTimeout(function(){x.abort("timeout")},l.timeout));try{v=1,g.send(t,y)}catch(B){if(v<2)y(-1,B);else throw B}}return x}return x.abort()},active:0,lastModified:{},etag:{}});var cE=[],cF=/\?/,cG=/(=)\?(?=&|$)|\?\?/,cH=p.now();p.ajaxSetup({jsonp:"callback",jsonpCallback:function(){var a=cE.pop()||p.expando+"_"+cH++;return this[a]=!0,a}}),p.ajaxPrefilter("json jsonp",function(c,d,e){var f,g,h,i=c.data,j=c.url,k=c.jsonp!==!1,l=k&&cG.test(j),m=k&&!l&&typeof i=="string"&&!(c.contentType||"").indexOf("application/x-www-form-urlencoded")&&cG.test(i);if(c.dataTypes[0]==="jsonp"||l||m)return f=c.jsonpCallback=p.isFunction(c.jsonpCallback)?c.jsonpCallback():c.jsonpCallback,g=a[f],l?c.url=j.replace(cG,"$1"+f):m?c.data=i.replace(cG,"$1"+f):k&&(c.url+=(cF.test(j)?"&":"?")+c.jsonp+"="+f),c.converters["script json"]=function(){return h||p.error(f+" was not called"),h[0]},c.dataTypes[0]="json",a[f]=function(){h=arguments},e.always(function(){a[f]=g,c[f]&&(c.jsonpCallback=d.jsonpCallback,cE.push(f)),h&&p.isFunction(g)&&g(h[0]),h=g=b}),"script"}),p.ajaxSetup({accepts:{script:"text/javascript, application/javascript, application/ecmascript, application/x-ecmascript"},contents:{script:/javascript|ecmascript/},converters:{"text script":function(a){return p.globalEval(a),a}}}),p.ajaxPrefilter("script",function(a){a.cache===b&&(a.cache=!1),a.crossDomain&&(a.type="GET",a.global=!1)}),p.ajaxTransport("script",function(a){if(a.crossDomain){var c,d=e.head||e.getElementsByTagName("head")[0]||e.documentElement;return{send:function(f,g){c=e.createElement("script"),c.async="async",a.scriptCharset&&(c.charset=a.scriptCharset),c.src=a.url,c.onload=c.onreadystatechange=function(a,e){if(e||!c.readyState||/loaded|complete/.test(c.readyState))c.onload=c.onreadystatechange=null,d&&c.parentNode&&d.removeChild(c),c=b,e||g(200,"success")},d.insertBefore(c,d.firstChild)},abort:function(){c&&c.onload(0,1)}}}});var cI,cJ=a.ActiveXObject?function(){for(var a in cI)cI[a](0,1)}:!1,cK=0;p.ajaxSettings.xhr=a.ActiveXObject?function(){return!this.isLocal&&cL()||cM()}:cL,function(a){p.extend(p.support,{ajax:!!a,cors:!!a&&"withCredentials"in a})}(p.ajaxSettings.xhr()),p.support.ajax&&p.ajaxTransport(function(c){if(!c.crossDomain||p.support.cors){var d;return{send:function(e,f){var g,h,i=c.xhr();c.username?i.open(c.type,c.url,c.async,c.username,c.password):i.open(c.type,c.url,c.async);if(c.xhrFields)for(h in c.xhrFields)i[h]=c.xhrFields[h];c.mimeType&&i.overrideMimeType&&i.overrideMimeType(c.mimeType),!c.crossDomain&&!e["X-Requested-With"]&&(e["X-Requested-With"]="XMLHttpRequest");try{for(h in e)i.setRequestHeader(h,e[h])}catch(j){}i.send(c.hasContent&&c.data||null),d=function(a,e){var h,j,k,l,m;try{if(d&&(e||i.readyState===4)){d=b,g&&(i.onreadystatechange=p.noop,cJ&&delete cI[g]);if(e)i.readyState!==4&&i.abort();else{h=i.status,k=i.getAllResponseHeaders(),l={},m=i.responseXML,m&&m.documentElement&&(l.xml=m);try{l.text=i.responseText}catch(a){}try{j=i.statusText}catch(n){j=""}!h&&c.isLocal&&!c.crossDomain?h=l.text?200:404:h===1223&&(h=204)}}}catch(o){e||f(-1,o)}l&&f(h,j,l,k)},c.async?i.readyState===4?setTimeout(d,0):(g=++cK,cJ&&(cI||(cI={},p(a).unload(cJ)),cI[g]=d),i.onreadystatechange=d):d()},abort:function(){d&&d(0,1)}}}});var cN,cO,cP=/^(?:toggle|show|hide)$/,cQ=new RegExp("^(?:([-+])=|)("+q+")([a-z%]*)$","i"),cR=/queueHooks$/,cS=[cY],cT={"*":[function(a,b){var c,d,e=this.createTween(a,b),f=cQ.exec(b),g=e.cur(),h=+g||0,i=1,j=20;if(f){c=+f[2],d=f[3]||(p.cssNumber[a]?"":"px");if(d!=="px"&&h){h=p.css(e.elem,a,!0)||c||1;do i=i||".5",h=h/i,p.style(e.elem,a,h+d);while(i!==(i=e.cur()/g)&&i!==1&&--j)}e.unit=d,e.start=h,e.end=f[1]?h+(f[1]+1)*c:c}return e}]};p.Animation=p.extend(cW,{tweener:function(a,b){p.isFunction(a)?(b=a,a=["*"]):a=a.split(" ");var c,d=0,e=a.length;for(;d<e;d++)c=a[d],cT[c]=cT[c]||[],cT[c].unshift(b)},prefilter:function(a,b){b?cS.unshift(a):cS.push(a)}}),p.Tween=cZ,cZ.prototype={constructor:cZ,init:function(a,b,c,d,e,f){this.elem=a,this.prop=c,this.easing=e||"swing",this.options=b,this.start=this.now=this.cur(),this.end=d,this.unit=f||(p.cssNumber[c]?"":"px")},cur:function(){var a=cZ.propHooks[this.prop];return a&&a.get?a.get(this):cZ.propHooks._default.get(this)},run:function(a){var b,c=cZ.propHooks[this.prop];return this.options.duration?this.pos=b=p.easing[this.easing](a,this.options.duration*a,0,1,this.options.duration):this.pos=b=a,this.now=(this.end-this.start)*b+this.start,this.options.step&&this.options.step.call(this.elem,this.now,this),c&&c.set?c.set(this):cZ.propHooks._default.set(this),this}},cZ.prototype.init.prototype=cZ.prototype,cZ.propHooks={_default:{get:function(a){var b;return a.elem[a.prop]==null||!!a.elem.style&&a.elem.style[a.prop]!=null?(b=p.css(a.elem,a.prop,!1,""),!b||b==="auto"?0:b):a.elem[a.prop]},set:function(a){p.fx.step[a.prop]?p.fx.step[a.prop](a):a.elem.style&&(a.elem.style[p.cssProps[a.prop]]!=null||p.cssHooks[a.prop])?p.style(a.elem,a.prop,a.now+a.unit):a.elem[a.prop]=a.now}}},cZ.propHooks.scrollTop=cZ.propHooks.scrollLeft={set:function(a){a.elem.nodeType&&a.elem.parentNode&&(a.elem[a.prop]=a.now)}},p.each(["toggle","show","hide"],function(a,b){var c=p.fn[b];p.fn[b]=function(d,e,f){return d==null||typeof d=="boolean"||!a&&p.isFunction(d)&&p.isFunction(e)?c.apply(this,arguments):this.animate(c$(b,!0),d,e,f)}}),p.fn.extend({fadeTo:function(a,b,c,d){return this.filter(bZ).css("opacity",0).show().end().animate({opacity:b},a,c,d)},animate:function(a,b,c,d){var e=p.isEmptyObject(a),f=p.speed(b,c,d),g=function(){var b=cW(this,p.extend({},a),f);e&&b.stop(!0)};return e||f.queue===!1?this.each(g):this.queue(f.queue,g)},stop:function(a,c,d){var e=function(a){var b=a.stop;delete a.stop,b(d)};return typeof a!="string"&&(d=c,c=a,a=b),c&&a!==!1&&this.queue(a||"fx",[]),this.each(function(){var b=!0,c=a!=null&&a+"queueHooks",f=p.timers,g=p._data(this);if(c)g[c]&&g[c].stop&&e(g[c]);else for(c in g)g[c]&&g[c].stop&&cR.test(c)&&e(g[c]);for(c=f.length;c--;)f[c].elem===this&&(a==null||f[c].queue===a)&&(f[c].anim.stop(d),b=!1,f.splice(c,1));(b||!d)&&p.dequeue(this,a)})}}),p.each({slideDown:c$("show"),slideUp:c$("hide"),slideToggle:c$("toggle"),fadeIn:{opacity:"show"},fadeOut:{opacity:"hide"},fadeToggle:{opacity:"toggle"}},function(a,b){p.fn[a]=function(a,c,d){return this.animate(b,a,c,d)}}),p.speed=function(a,b,c){var d=a&&typeof a=="object"?p.extend({},a):{complete:c||!c&&b||p.isFunction(a)&&a,duration:a,easing:c&&b||b&&!p.isFunction(b)&&b};d.duration=p.fx.off?0:typeof d.duration=="number"?d.duration:d.duration in p.fx.speeds?p.fx.speeds[d.duration]:p.fx.speeds._default;if(d.queue==null||d.queue===!0)d.queue="fx";return d.old=d.complete,d.complete=function(){p.isFunction(d.old)&&d.old.call(this),d.queue&&p.dequeue(this,d.queue)},d},p.easing={linear:function(a){return a},swing:function(a){return.5-Math.cos(a*Math.PI)/2}},p.timers=[],p.fx=cZ.prototype.init,p.fx.tick=function(){var a,b=p.timers,c=0;for(;c<b.length;c++)a=b[c],!a()&&b[c]===a&&b.splice(c--,1);b.length||p.fx.stop()},p.fx.timer=function(a){a()&&p.timers.push(a)&&!cO&&(cO=setInterval(p.fx.tick,p.fx.interval))},p.fx.interval=13,p.fx.stop=function(){clearInterval(cO),cO=null},p.fx.speeds={slow:600,fast:200,_default:400},p.fx.step={},p.expr&&p.expr.filters&&(p.expr.filters.animated=function(a){return p.grep(p.timers,function(b){return a===b.elem}).length});var c_=/^(?:body|html)$/i;p.fn.offset=function(a){if(arguments.length)return a===b?this:this.each(function(b){p.offset.setOffset(this,a,b)});var c,d,e,f,g,h,i,j={top:0,left:0},k=this[0],l=k&&k.ownerDocument;if(!l)return;return(d=l.body)===k?p.offset.bodyOffset(k):(c=l.documentElement,p.contains(c,k)?(typeof k.getBoundingClientRect!="undefined"&&(j=k.getBoundingClientRect()),e=da(l),f=c.clientTop||d.clientTop||0,g=c.clientLeft||d.clientLeft||0,h=e.pageYOffset||c.scrollTop,i=e.pageXOffset||c.scrollLeft,{top:j.top+h-f,left:j.left+i-g}):j)},p.offset={bodyOffset:function(a){var b=a.offsetTop,c=a.offsetLeft;return p.support.doesNotIncludeMarginInBodyOffset&&(b+=parseFloat(p.css(a,"marginTop"))||0,c+=parseFloat(p.css(a,"marginLeft"))||0),{top:b,left:c}},setOffset:function(a,b,c){var d=p.css(a,"position");d==="static"&&(a.style.position="relative");var e=p(a),f=e.offset(),g=p.css(a,"top"),h=p.css(a,"left"),i=(d==="absolute"||d==="fixed")&&p.inArray("auto",[g,h])>-1,j={},k={},l,m;i?(k=e.position(),l=k.top,m=k.left):(l=parseFloat(g)||0,m=parseFloat(h)||0),p.isFunction(b)&&(b=b.call(a,c,f)),b.top!=null&&(j.top=b.top-f.top+l),b.left!=null&&(j.left=b.left-f.left+m),"using"in b?b.using.call(a,j):e.css(j)}},p.fn.extend({position:function(){if(!this[0])return;var a=this[0],b=this.offsetParent(),c=this.offset(),d=c_.test(b[0].nodeName)?{top:0,left:0}:b.offset();return c.top-=parseFloat(p.css(a,"marginTop"))||0,c.left-=parseFloat(p.css(a,"marginLeft"))||0,d.top+=parseFloat(p.css(b[0],"borderTopWidth"))||0,d.left+=parseFloat(p.css(b[0],"borderLeftWidth"))||0,{top:c.top-d.top,left:c.left-d.left}},offsetParent:function(){return this.map(function(){var a=this.offsetParent||e.body;while(a&&!c_.test(a.nodeName)&&p.css(a,"position")==="static")a=a.offsetParent;return a||e.body})}}),p.each({scrollLeft:"pageXOffset",scrollTop:"pageYOffset"},function(a,c){var d=/Y/.test(c);p.fn[a]=function(e){return p.access(this,function(a,e,f){var g=da(a);if(f===b)return g?c in g?g[c]:g.document.documentElement[e]:a[e];g?g.scrollTo(d?p(g).scrollLeft():f,d?f:p(g).scrollTop()):a[e]=f},a,e,arguments.length,null)}}),p.each({Height:"height",Width:"width"},function(a,c){p.each({padding:"inner"+a,content:c,"":"outer"+a},function(d,e){p.fn[e]=function(e,f){var g=arguments.length&&(d||typeof e!="boolean"),h=d||(e===!0||f===!0?"margin":"border");return p.access(this,function(c,d,e){var f;return p.isWindow(c)?c.document.documentElement["client"+a]:c.nodeType===9?(f=c.documentElement,Math.max(c.body["scroll"+a],f["scroll"+a],c.body["offset"+a],f["offset"+a],f["client"+a])):e===b?p.css(c,d,e,h):p.style(c,d,e,h)},c,g?e:b,g,null)}})}),a.jQuery=a.$=p,typeof define=="function"&&define.amd&&define.amd.jQuery&&define("jquery",[],function(){return p})})(window);
js/jquery/jquery.noconflict.js ADDED
@@ -0,0 +1 @@
 
1
+ jQuery.noConflict();
js/productlookbook/fileuploader.js ADDED
@@ -0,0 +1,1251 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ /**
2
+ * http://github.com/valums/file-uploader
3
+ *
4
+ * Multiple file upload component with progress-bar, drag-and-drop.
5
+ * © 2010 Andrew Valums ( andrew(at)valums.com )
6
+ *
7
+ * Licensed under GNU GPL 2 or later and GNU LGPL 2 or later, see license.txt.
8
+ */
9
+
10
+ //
11
+ // Helper functions
12
+ //
13
+
14
+ var qq = qq || {};
15
+
16
+ /**
17
+ * Adds all missing properties from second obj to first obj
18
+ */
19
+ qq.extend = function(first, second){
20
+ for (var prop in second){
21
+ first[prop] = second[prop];
22
+ }
23
+ };
24
+
25
+ /**
26
+ * Searches for a given element in the array, returns -1 if it is not present.
27
+ * @param {Number} [from] The index at which to begin the search
28
+ */
29
+ qq.indexOf = function(arr, elt, from){
30
+ if (arr.indexOf) return arr.indexOf(elt, from);
31
+
32
+ from = from || 0;
33
+ var len = arr.length;
34
+
35
+ if (from < 0) from += len;
36
+
37
+ for (; from < len; from++){
38
+ if (from in arr && arr[from] === elt){
39
+ return from;
40
+ }
41
+ }
42
+ return -1;
43
+ };
44
+
45
+ qq.getUniqueId = (function(){
46
+ var id = 0;
47
+ return function(){ return id++; };
48
+ })();
49
+
50
+ //
51
+ // Events
52
+
53
+ qq.attach = function(element, type, fn){
54
+ if (element.addEventListener){
55
+ element.addEventListener(type, fn, false);
56
+ } else if (element.attachEvent){
57
+ element.attachEvent('on' + type, fn);
58
+ }
59
+ };
60
+ qq.detach = function(element, type, fn){
61
+ if (element.removeEventListener){
62
+ element.removeEventListener(type, fn, false);
63
+ } else if (element.attachEvent){
64
+ element.detachEvent('on' + type, fn);
65
+ }
66
+ };
67
+
68
+ qq.preventDefault = function(e){
69
+ if (e.preventDefault){
70
+ e.preventDefault();
71
+ } else{
72
+ e.returnValue = false;
73
+ }
74
+ };
75
+
76
+ //
77
+ // Node manipulations
78
+
79
+ /**
80
+ * Insert node a before node b.
81
+ */
82
+ qq.insertBefore = function(a, b){
83
+ b.parentNode.insertBefore(a, b);
84
+ };
85
+ qq.remove = function(element){
86
+ element.parentNode.removeChild(element);
87
+ };
88
+
89
+ qq.contains = function(parent, descendant){
90
+ // compareposition returns false in this case
91
+ if (parent == descendant) return true;
92
+
93
+ if (parent.contains){
94
+ return parent.contains(descendant);
95
+ } else {
96
+ return !!(descendant.compareDocumentPosition(parent) & 8);
97
+ }
98
+ };
99
+
100
+ /**
101
+ * Creates and returns element from html string
102
+ * Uses innerHTML to create an element
103
+ */
104
+ qq.toElement = (function(){
105
+ var div = document.createElement('div');
106
+ return function(html){
107
+ div.innerHTML = html;
108
+ var element = div.firstChild;
109
+ div.removeChild(element);
110
+ return element;
111
+ };
112
+ })();
113
+
114
+ //
115
+ // Node properties and attributes
116
+
117
+ /**
118
+ * Sets styles for an element.
119
+ * Fixes opacity in IE6-8.
120
+ */
121
+ qq.css = function(element, styles){
122
+ if (styles.opacity != null){
123
+ if (typeof element.style.opacity != 'string' && typeof(element.filters) != 'undefined'){
124
+ styles.filter = 'alpha(opacity=' + Math.round(100 * styles.opacity) + ')';
125
+ }
126
+ }
127
+ qq.extend(element.style, styles);
128
+ };
129
+ qq.hasClass = function(element, name){
130
+ var re = new RegExp('(^| )' + name + '( |$)');
131
+ return re.test(element.className);
132
+ };
133
+ qq.addClass = function(element, name){
134
+ if (!qq.hasClass(element, name)){
135
+ element.className += ' ' + name;
136
+ }
137
+ };
138
+ qq.removeClass = function(element, name){
139
+ var re = new RegExp('(^| )' + name + '( |$)');
140
+ element.className = element.className.replace(re, ' ').replace(/^\s+|\s+$/g, "");
141
+ };
142
+ qq.setText = function(element, text){
143
+ element.innerText = text;
144
+ element.textContent = text;
145
+ };
146
+
147
+ //
148
+ // Selecting elements
149
+
150
+ qq.children = function(element){
151
+ var children = [],
152
+ child = element.firstChild;
153
+
154
+ while (child){
155
+ if (child.nodeType == 1){
156
+ children.push(child);
157
+ }
158
+ child = child.nextSibling;
159
+ }
160
+
161
+ return children;
162
+ };
163
+
164
+ qq.getByClass = function(element, className){
165
+ if (element.querySelectorAll){
166
+ return element.querySelectorAll('.' + className);
167
+ }
168
+
169
+ var result = [];
170
+ var candidates = element.getElementsByTagName("*");
171
+ var len = candidates.length;
172
+
173
+ for (var i = 0; i < len; i++){
174
+ if (qq.hasClass(candidates[i], className)){
175
+ result.push(candidates[i]);
176
+ }
177
+ }
178
+ return result;
179
+ };
180
+
181
+ /**
182
+ * obj2url() takes a json-object as argument and generates
183
+ * a querystring. pretty much like jQuery.param()
184
+ *
185
+ * how to use:
186
+ *
187
+ * `qq.obj2url({a:'b',c:'d'},'http://any.url/upload?otherParam=value');`
188
+ *
189
+ * will result in:
190
+ *
191
+ * `http://any.url/upload?otherParam=value&a=b&c=d`
192
+ *
193
+ * @param Object JSON-Object
194
+ * @param String current querystring-part
195
+ * @return String encoded querystring
196
+ */
197
+ qq.obj2url = function(obj, temp, prefixDone){
198
+ var uristrings = [],
199
+ prefix = '&',
200
+ add = function(nextObj, i){
201
+ var nextTemp = temp
202
+ ? (/\[\]$/.test(temp)) // prevent double-encoding
203
+ ? temp
204
+ : temp+'['+i+']'
205
+ : i;
206
+ if ((nextTemp != 'undefined') && (i != 'undefined')) {
207
+ uristrings.push(
208
+ (typeof nextObj === 'object')
209
+ ? qq.obj2url(nextObj, nextTemp, true)
210
+ : (Object.prototype.toString.call(nextObj) === '[object Function]')
211
+ ? encodeURIComponent(nextTemp) + '=' + encodeURIComponent(nextObj())
212
+ : encodeURIComponent(nextTemp) + '=' + encodeURIComponent(nextObj)
213
+ );
214
+ }
215
+ };
216
+
217
+ if (!prefixDone && temp) {
218
+ prefix = (/\?/.test(temp)) ? (/\?$/.test(temp)) ? '' : '&' : '?';
219
+ uristrings.push(temp);
220
+ uristrings.push(qq.obj2url(obj));
221
+ } else if ((Object.prototype.toString.call(obj) === '[object Array]') && (typeof obj != 'undefined') ) {
222
+ // we wont use a for-in-loop on an array (performance)
223
+ for (var i = 0, len = obj.length; i < len; ++i){
224
+ add(obj[i], i);
225
+ }
226
+ } else if ((typeof obj != 'undefined') && (obj !== null) && (typeof obj === "object")){
227
+ // for anything else but a scalar, we will use for-in-loop
228
+ for (var i in obj){
229
+ add(obj[i], i);
230
+ }
231
+ } else {
232
+ uristrings.push(encodeURIComponent(temp) + '=' + encodeURIComponent(obj));
233
+ }
234
+
235
+ return uristrings.join(prefix)
236
+ .replace(/^&/, '')
237
+ .replace(/%20/g, '+');
238
+ };
239
+
240
+ //
241
+ //
242
+ // Uploader Classes
243
+ //
244
+ //
245
+
246
+ var qq = qq || {};
247
+
248
+ /**
249
+ * Creates upload button, validates upload, but doesn't create file list or dd.
250
+ */
251
+ qq.FileUploaderBasic = function(o){
252
+ this._options = {
253
+ // set to true to see the server response
254
+ debug: false,
255
+ action: '/server/upload',
256
+ params: {},
257
+ button: null,
258
+ buttontext: 'Upload file',
259
+ multiple: true,
260
+ maxConnections: 3,
261
+ // validation
262
+ allowedExtensions: [],
263
+ sizeLimit: 0,
264
+ minSizeLimit: 0,
265
+ // events
266
+ // return false to cancel submit
267
+ onSubmit: function(id, fileName){},
268
+ onProgress: function(id, fileName, loaded, total){},
269
+ onComplete: function(id, fileName, responseJSON){},
270
+ onCancel: function(id, fileName){},
271
+ // messages
272
+ messages: {
273
+ typeError: "{file} has invalid extension. Only {extensions} are allowed.",
274
+ sizeError: "{file} is too large, maximum file size is {sizeLimit}.",
275
+ minSizeError: "{file} is too small, minimum file size is {minSizeLimit}.",
276
+ emptyError: "{file} is empty, please select files again without it.",
277
+ onLeave: "The files are being uploaded, if you leave now the upload will be cancelled."
278
+ },
279
+ showMessage: function(message){
280
+ alert(message);
281
+ }
282
+ };
283
+ qq.extend(this._options, o);
284
+
285
+ // number of files being uploaded
286
+ this._filesInProgress = 0;
287
+ this._handler = this._createUploadHandler();
288
+
289
+ if (this._options.button){
290
+ this._button = this._createUploadButton(this._options.button);
291
+ }
292
+
293
+ this._preventLeaveInProgress();
294
+ };
295
+
296
+ qq.FileUploaderBasic.prototype = {
297
+ setParams: function(params){
298
+ this._options.params = params;
299
+ },
300
+ getInProgress: function(){
301
+ return this._filesInProgress;
302
+ },
303
+ _createUploadButton: function(element){
304
+ var self = this;
305
+
306
+ return new qq.UploadButton({
307
+ element: element,
308
+ multiple: this._options.multiple && qq.UploadHandlerXhr.isSupported(),
309
+ onChange: function(input){
310
+ self._onInputChange(input);
311
+ }
312
+ });
313
+ },
314
+ _createUploadHandler: function(){
315
+ var self = this,
316
+ handlerClass;
317
+
318
+ if(qq.UploadHandlerXhr.isSupported()){
319
+ handlerClass = 'UploadHandlerXhr';
320
+ } else {
321
+ handlerClass = 'UploadHandlerForm';
322
+ }
323
+
324
+ var handler = new qq[handlerClass]({
325
+ debug: this._options.debug,
326
+ action: this._options.action,
327
+ maxConnections: this._options.maxConnections,
328
+ onProgress: function(id, fileName, loaded, total){
329
+ self._onProgress(id, fileName, loaded, total);
330
+ self._options.onProgress(id, fileName, loaded, total);
331
+ },
332
+ onComplete: function(id, fileName, result){
333
+ self._onComplete(id, fileName, result);
334
+ self._options.onComplete(id, fileName, result);
335
+ },
336
+ onCancel: function(id, fileName){
337
+ self._onCancel(id, fileName);
338
+ self._options.onCancel(id, fileName);
339
+ }
340
+ });
341
+
342
+ return handler;
343
+ },
344
+ _preventLeaveInProgress: function(){
345
+ var self = this;
346
+
347
+ qq.attach(window, 'beforeunload', function(e){
348
+ if (!self._filesInProgress){return;}
349
+
350
+ var e = e || window.event;
351
+ // for ie, ff
352
+ e.returnValue = self._options.messages.onLeave;
353
+ // for webkit
354
+ return self._options.messages.onLeave;
355
+ });
356
+ },
357
+ _onSubmit: function(id, fileName){
358
+ this._filesInProgress++;
359
+ },
360
+ _onProgress: function(id, fileName, loaded, total){
361
+ },
362
+ _onComplete: function(id, fileName, result){
363
+ this._filesInProgress--;
364
+ if (result.error){
365
+ this._options.showMessage(result.error);
366
+ }
367
+ },
368
+ _onCancel: function(id, fileName){
369
+ this._filesInProgress--;
370
+ },
371
+ _onInputChange: function(input){
372
+ if (this._handler instanceof qq.UploadHandlerXhr){
373
+ this._uploadFileList(input.files);
374
+ } else {
375
+ if (this._validateFile(input)){
376
+ this._uploadFile(input);
377
+ }
378
+ }
379
+ this._button.reset();
380
+ },
381
+ _uploadFileList: function(files){
382
+ for (var i=0; i<files.length; i++){
383
+ if ( !this._validateFile(files[i])){
384
+ return;
385
+ }
386
+ }
387
+
388
+ for (var i=0; i<files.length; i++){
389
+ this._uploadFile(files[i]);
390
+ }
391
+ },
392
+ _uploadFile: function(fileContainer){
393
+ var id = this._handler.add(fileContainer);
394
+ var fileName = this._handler.getName(id);
395
+
396
+ if (this._options.onSubmit(id, fileName) !== false){
397
+ this._onSubmit(id, fileName);
398
+ this._handler.upload(id, this._options.params);
399
+ }
400
+ },
401
+ _validateFile: function(file){
402
+ var name, size;
403
+
404
+ if (file.value){
405
+ // it is a file input
406
+ // get input value and remove path to normalize
407
+ name = file.value.replace(/.*(\/|\\)/, "");
408
+ } else {
409
+ // fix missing properties in Safari
410
+ name = file.fileName != null ? file.fileName : file.name;
411
+ size = file.fileSize != null ? file.fileSize : file.size;
412
+ }
413
+
414
+ if (! this._isAllowedExtension(name)){
415
+ this._error('typeError', name);
416
+ return false;
417
+
418
+ } else if (size === 0){
419
+ this._error('emptyError', name);
420
+ return false;
421
+
422
+ } else if (size && this._options.sizeLimit && size > this._options.sizeLimit){
423
+ this._error('sizeError', name);
424
+ return false;
425
+
426
+ } else if (size && size < this._options.minSizeLimit){
427
+ this._error('minSizeError', name);
428
+ return false;
429
+ }
430
+
431
+ return true;
432
+ },
433
+ _error: function(code, fileName){
434
+ var message = this._options.messages[code];
435
+ function r(name, replacement){ message = message.replace(name, replacement); }
436
+
437
+ r('{file}', this._formatFileName(fileName));
438
+ r('{extensions}', this._options.allowedExtensions.join(', '));
439
+ r('{sizeLimit}', this._formatSize(this._options.sizeLimit));
440
+ r('{minSizeLimit}', this._formatSize(this._options.minSizeLimit));
441
+
442
+ this._options.showMessage(message);
443
+ },
444
+ _formatFileName: function(name){
445
+ if (name.length > 33){
446
+ name = name.slice(0, 19) + '...' + name.slice(-13);
447
+ }
448
+ return name;
449
+ },
450
+ _isAllowedExtension: function(fileName){
451
+ var ext = (-1 !== fileName.indexOf('.')) ? fileName.replace(/.*[.]/, '').toLowerCase() : '';
452
+ var allowed = this._options.allowedExtensions;
453
+
454
+ if (!allowed.length){return true;}
455
+
456
+ for (var i=0; i<allowed.length; i++){
457
+ if (allowed[i].toLowerCase() == ext){ return true;}
458
+ }
459
+
460
+ return false;
461
+ },
462
+ _formatSize: function(bytes){
463
+ var i = -1;
464
+ do {
465
+ bytes = bytes / 1024;
466
+ i++;
467
+ } while (bytes > 99);
468
+
469
+ return Math.max(bytes, 0.1).toFixed(1) + ['kB', 'MB', 'GB', 'TB', 'PB', 'EB'][i];
470
+ }
471
+ };
472
+
473
+
474
+ /**
475
+ * Class that creates upload widget with drag-and-drop and file list
476
+ * @inherits qq.FileUploaderBasic
477
+ */
478
+ qq.FileUploader = function(o){
479
+ // call parent constructor
480
+ qq.FileUploaderBasic.apply(this, arguments);
481
+
482
+ // additional options
483
+ qq.extend(this._options, {
484
+ element: null,
485
+ // if set, will be used instead of qq-upload-list in template
486
+ listElement: null,
487
+
488
+ template: '<div class="qq-uploader">' +
489
+ '<div class="qq-upload-drop-area"><span>Drop files here to upload</span></div>' +
490
+ '<div class="qq-upload-button"><span>'+this._options.buttontext+'</span></div>' +
491
+ '<ul class="qq-upload-list"></ul>' +
492
+ '</div>',
493
+
494
+ // template for one item in file list
495
+ fileTemplate: '<li>' +
496
+ '<span class="qq-upload-file"></span>' +
497
+ '<span class="qq-upload-spinner"></span>' +
498
+ '<span class="qq-upload-size"></span>' +
499
+ '<a class="qq-upload-cancel" href="#">Cancel</a>' +
500
+ '<span class="qq-upload-failed-text">Failed</span>' +
501
+ '</li>',
502
+
503
+ classes: {
504
+ // used to get elements from templates
505
+ button: 'qq-upload-button',
506
+ drop: 'qq-upload-drop-area',
507
+ dropActive: 'qq-upload-drop-area-active',
508
+ list: 'qq-upload-list',
509
+
510
+ file: 'qq-upload-file',
511
+ spinner: 'qq-upload-spinner',
512
+ size: 'qq-upload-size',
513
+ cancel: 'qq-upload-cancel',
514
+
515
+ // added to list item when upload completes
516
+ // used in css to hide progress spinner
517
+ success: 'qq-upload-success',
518
+ fail: 'qq-upload-fail'
519
+ }
520
+ });
521
+ // overwrite options with user supplied
522
+ qq.extend(this._options, o);
523
+
524
+ this._element = this._options.element;
525
+ this._element.innerHTML = this._options.template;
526
+ this._listElement = this._options.listElement || this._find(this._element, 'list');
527
+
528
+ this._classes = this._options.classes;
529
+
530
+ this._button = this._createUploadButton(this._find(this._element, 'button'));
531
+
532
+ this._bindCancelEvent();
533
+ this._setupDragDrop();
534
+ };
535
+
536
+ // inherit from Basic Uploader
537
+ qq.extend(qq.FileUploader.prototype, qq.FileUploaderBasic.prototype);
538
+
539
+ qq.extend(qq.FileUploader.prototype, {
540
+ /**
541
+ * Gets one of the elements listed in this._options.classes
542
+ **/
543
+ _find: function(parent, type){
544
+ var element = qq.getByClass(parent, this._options.classes[type])[0];
545
+ if (!element){
546
+ throw new Error('element not found ' + type);
547
+ }
548
+
549
+ return element;
550
+ },
551
+ _setupDragDrop: function(){
552
+ var self = this,
553
+ dropArea = this._find(this._element, 'drop');
554
+
555
+ var dz = new qq.UploadDropZone({
556
+ element: dropArea,
557
+ onEnter: function(e){
558
+ qq.addClass(dropArea, self._classes.dropActive);
559
+ e.stopPropagation();
560
+ },
561
+ onLeave: function(e){
562
+ e.stopPropagation();
563
+ },
564
+ onLeaveNotDescendants: function(e){
565
+ qq.removeClass(dropArea, self._classes.dropActive);
566
+ },
567
+ onDrop: function(e){
568
+ dropArea.style.display = 'none';
569
+ qq.removeClass(dropArea, self._classes.dropActive);
570
+ self._uploadFileList(e.dataTransfer.files);
571
+ }
572
+ });
573
+
574
+ dropArea.style.display = 'none';
575
+
576
+ qq.attach(document, 'dragenter', function(e){
577
+ if (!dz._isValidFileDrag(e)) return;
578
+
579
+ dropArea.style.display = 'block';
580
+ });
581
+ qq.attach(document, 'dragleave', function(e){
582
+ if (!dz._isValidFileDrag(e)) return;
583
+
584
+ var relatedTarget = document.elementFromPoint(e.clientX, e.clientY);
585
+ // only fire when leaving document out
586
+ if ( ! relatedTarget || relatedTarget.nodeName == "HTML"){
587
+ dropArea.style.display = 'none';
588
+ }
589
+ });
590
+ },
591
+ _onSubmit: function(id, fileName){
592
+ qq.FileUploaderBasic.prototype._onSubmit.apply(this, arguments);
593
+ this._addToList(id, fileName);
594
+ },
595
+ _onProgress: function(id, fileName, loaded, total){
596
+ qq.FileUploaderBasic.prototype._onProgress.apply(this, arguments);
597
+
598
+ var item = this._getItemByFileId(id);
599
+ var size = this._find(item, 'size');
600
+ size.style.display = 'inline';
601
+
602
+ var text;
603
+ if (loaded != total){
604
+ text = Math.round(loaded / total * 100) + '% from ' + this._formatSize(total);
605
+ } else {
606
+ text = this._formatSize(total);
607
+ }
608
+
609
+ qq.setText(size, text);
610
+ },
611
+ _onComplete: function(id, fileName, result){
612
+ qq.FileUploaderBasic.prototype._onComplete.apply(this, arguments);
613
+
614
+ // mark completed
615
+ var item = this._getItemByFileId(id);
616
+ qq.remove(this._find(item, 'cancel'));
617
+ qq.remove(this._find(item, 'spinner'));
618
+
619
+ if (result.success){
620
+ qq.addClass(item, this._classes.success);
621
+ } else {
622
+ qq.addClass(item, this._classes.fail);
623
+ }
624
+ },
625
+ _addToList: function(id, fileName){
626
+ var item = qq.toElement(this._options.fileTemplate);
627
+ item.qqFileId = id;
628
+
629
+ var fileElement = this._find(item, 'file');
630
+ qq.setText(fileElement, this._formatFileName(fileName));
631
+ this._find(item, 'size').style.display = 'none';
632
+
633
+ if( this._options.multiple || this._listElement.childNodes.length == 0 )
634
+ this._listElement.appendChild(item);
635
+ else
636
+ this._listElement.replaceChild(item, this._listElement.firstChild);
637
+ },
638
+ _getItemByFileId: function(id){
639
+ var item = this._listElement.firstChild;
640
+
641
+ // there can't be txt nodes in dynamically created list
642
+ // and we can use nextSibling
643
+ while (item){
644
+ if (item.qqFileId == id) return item;
645
+ item = item.nextSibling;
646
+ }
647
+ },
648
+ /**
649
+ * delegate click event for cancel link
650
+ **/
651
+ _bindCancelEvent: function(){
652
+ var self = this,
653
+ list = this._listElement;
654
+
655
+ qq.attach(list, 'click', function(e){
656
+ e = e || window.event;
657
+ var target = e.target || e.srcElement;
658
+
659
+ if (qq.hasClass(target, self._classes.cancel)){
660
+ qq.preventDefault(e);
661
+
662
+ var item = target.parentNode;
663
+ self._handler.cancel(item.qqFileId);
664
+ qq.remove(item);
665
+ }
666
+ });
667
+ }
668
+ });
669
+
670
+ qq.UploadDropZone = function(o){
671
+ this._options = {
672
+ element: null,
673
+ onEnter: function(e){},
674
+ onLeave: function(e){},
675
+ // is not fired when leaving element by hovering descendants
676
+ onLeaveNotDescendants: function(e){},
677
+ onDrop: function(e){}
678
+ };
679
+ qq.extend(this._options, o);
680
+
681
+ this._element = this._options.element;
682
+
683
+ this._disableDropOutside();
684
+ this._attachEvents();
685
+ };
686
+
687
+ qq.UploadDropZone.prototype = {
688
+ _disableDropOutside: function(e){
689
+ // run only once for all instances
690
+ if (!qq.UploadDropZone.dropOutsideDisabled ){
691
+
692
+ qq.attach(document, 'dragover', function(e){
693
+ if (e.dataTransfer){
694
+ e.dataTransfer.dropEffect = 'none';
695
+ e.preventDefault();
696
+ }
697
+ });
698
+
699
+ qq.UploadDropZone.dropOutsideDisabled = true;
700
+ }
701
+ },
702
+ _attachEvents: function(){
703
+ var self = this;
704
+
705
+ qq.attach(self._element, 'dragover', function(e){
706
+ if (!self._isValidFileDrag(e)) return;
707
+
708
+ var effect = e.dataTransfer.effectAllowed;
709
+ if (effect == 'move' || effect == 'linkMove'){
710
+ e.dataTransfer.dropEffect = 'move'; // for FF (only move allowed)
711
+ } else {
712
+ e.dataTransfer.dropEffect = 'copy'; // for Chrome
713
+ }
714
+
715
+ e.stopPropagation();
716
+ e.preventDefault();
717
+ });
718
+
719
+ qq.attach(self._element, 'dragenter', function(e){
720
+ if (!self._isValidFileDrag(e)) return;
721
+
722
+ self._options.onEnter(e);
723
+ });
724
+
725
+ qq.attach(self._element, 'dragleave', function(e){
726
+ if (!self._isValidFileDrag(e)) return;
727
+
728
+ self._options.onLeave(e);
729
+
730
+ var relatedTarget = document.elementFromPoint(e.clientX, e.clientY);
731
+ // do not fire when moving a mouse over a descendant
732
+ if (qq.contains(this, relatedTarget)) return;
733
+
734
+ self._options.onLeaveNotDescendants(e);
735
+ });
736
+
737
+ qq.attach(self._element, 'drop', function(e){
738
+ if (!self._isValidFileDrag(e)) return;
739
+
740
+ e.preventDefault();
741
+ self._options.onDrop(e);
742
+ });
743
+ },
744
+ _isValidFileDrag: function(e){
745
+ var dt = e.dataTransfer,
746
+ // do not check dt.types.contains in webkit, because it crashes safari 4
747
+ isWebkit = navigator.userAgent.indexOf("AppleWebKit") > -1;
748
+
749
+ // dt.effectAllowed is none in Safari 5
750
+ // dt.types.contains check is for firefox
751
+ return dt && dt.effectAllowed != 'none' &&
752
+ (dt.files || (!isWebkit && dt.types.contains && dt.types.contains('Files')));
753
+
754
+ }
755
+ };
756
+
757
+ qq.UploadButton = function(o){
758
+ this._options = {
759
+ element: null,
760
+ // if set to true adds multiple attribute to file input
761
+ multiple: false,
762
+ // name attribute of file input
763
+ name: 'file',
764
+ onChange: function(input){},
765
+ hoverClass: 'qq-upload-button-hover',
766
+ focusClass: 'qq-upload-button-focus'
767
+ };
768
+
769
+ qq.extend(this._options, o);
770
+
771
+ this._element = this._options.element;
772
+
773
+ // make button suitable container for input
774
+ qq.css(this._element, {
775
+ position: 'relative',
776
+ overflow: 'hidden',
777
+ // Make sure browse button is in the right side
778
+ // in Internet Explorer
779
+ direction: 'ltr'
780
+ });
781
+
782
+ this._input = this._createInput();
783
+ };
784
+
785
+ qq.UploadButton.prototype = {
786
+ /* returns file input element */
787
+ getInput: function(){
788
+ return this._input;
789
+ },
790
+ /* cleans/recreates the file input */
791
+ reset: function(){
792
+ if (this._input.parentNode){
793
+ qq.remove(this._input);
794
+ }
795
+
796
+ qq.removeClass(this._element, this._options.focusClass);
797
+ this._input = this._createInput();
798
+ },
799
+ _createInput: function(){
800
+ var input = document.createElement("input");
801
+
802
+ if (this._options.multiple){
803
+ input.setAttribute("multiple", "multiple");
804
+ }
805
+
806
+ input.setAttribute("type", "file");
807
+ input.setAttribute("name", this._options.name);
808
+
809
+ qq.css(input, {
810
+ position: 'absolute',
811
+ // in Opera only 'browse' button
812
+ // is clickable and it is located at
813
+ // the right side of the input
814
+ right: 0,
815
+ top: 0,
816
+ fontFamily: 'Arial',
817
+ // 4 persons reported this, the max values that worked for them were 243, 236, 236, 118
818
+ fontSize: '118px',
819
+ margin: 0,
820
+ padding: 0,
821
+ cursor: 'pointer',
822
+ opacity: 0
823
+ });
824
+
825
+ this._element.appendChild(input);
826
+
827
+ var self = this;
828
+ qq.attach(input, 'change', function(){
829
+ self._options.onChange(input);
830
+ });
831
+
832
+ qq.attach(input, 'mouseover', function(){
833
+ qq.addClass(self._element, self._options.hoverClass);
834
+ });
835
+ qq.attach(input, 'mouseout', function(){
836
+ qq.removeClass(self._element, self._options.hoverClass);
837
+ });
838
+ qq.attach(input, 'focus', function(){
839
+ qq.addClass(self._element, self._options.focusClass);
840
+ });
841
+ qq.attach(input, 'blur', function(){
842
+ qq.removeClass(self._element, self._options.focusClass);
843
+ });
844
+
845
+ // IE and Opera, unfortunately have 2 tab stops on file input
846
+ // which is unacceptable in our case, disable keyboard access
847
+ if (window.attachEvent){
848
+ // it is IE or Opera
849
+ input.setAttribute('tabIndex', "-1");
850
+ }
851
+
852
+ return input;
853
+ }
854
+ };
855
+
856
+ /**
857
+ * Class for uploading files, uploading itself is handled by child classes
858
+ */
859
+ qq.UploadHandlerAbstract = function(o){
860
+ this._options = {
861
+ debug: false,
862
+ action: '/upload.php',
863
+ // maximum number of concurrent uploads
864
+ maxConnections: 999,
865
+ onProgress: function(id, fileName, loaded, total){},
866
+ onComplete: function(id, fileName, response){},
867
+ onCancel: function(id, fileName){}
868
+ };
869
+ qq.extend(this._options, o);
870
+
871
+ this._queue = [];
872
+ // params for files in queue
873
+ this._params = [];
874
+ };
875
+ qq.UploadHandlerAbstract.prototype = {
876
+ log: function(str){
877
+ if (this._options.debug && window.console) console.log('[uploader] ' + str);
878
+ },
879
+ /**
880
+ * Adds file or file input to the queue
881
+ * @returns id
882
+ **/
883
+ add: function(file){},
884
+ /**
885
+ * Sends the file identified by id and additional query params to the server
886
+ */
887
+ upload: function(id, params){
888
+ var len = this._queue.push(id);
889
+
890
+ var copy = {};
891
+ qq.extend(copy, params);
892
+ this._params[id] = copy;
893
+
894
+ // if too many active uploads, wait...
895
+ if (len <= this._options.maxConnections){
896
+ this._upload(id, this._params[id]);
897
+ }
898
+ },
899
+ /**
900
+ * Cancels file upload by id
901
+ */
902
+ cancel: function(id){
903
+ this._cancel(id);
904
+ this._dequeue(id);
905
+ },
906
+ /**
907
+ * Cancells all uploads
908
+ */
909
+ cancelAll: function(){
910
+ for (var i=0; i<this._queue.length; i++){
911
+ this._cancel(this._queue[i]);
912
+ }
913
+ this._queue = [];
914
+ },
915
+ /**
916
+ * Returns name of the file identified by id
917
+ */
918
+ getName: function(id){},
919
+ /**
920
+ * Returns size of the file identified by id
921
+ */
922
+ getSize: function(id){},
923
+ /**
924
+ * Returns id of files being uploaded or
925
+ * waiting for their turn
926
+ */
927
+ getQueue: function(){
928
+ return this._queue;
929
+ },
930
+ /**
931
+ * Actual upload method
932
+ */
933
+ _upload: function(id){},
934
+ /**
935
+ * Actual cancel method
936
+ */
937
+ _cancel: function(id){},
938
+ /**
939
+ * Removes element from queue, starts upload of next
940
+ */
941
+ _dequeue: function(id){
942
+ var i = qq.indexOf(this._queue, id);
943
+ this._queue.splice(i, 1);
944
+
945
+ var max = this._options.maxConnections;
946
+
947
+ if (this._queue.length >= max && i < max){
948
+ var nextId = this._queue[max-1];
949
+ this._upload(nextId, this._params[nextId]);
950
+ }
951
+ }
952
+ };
953
+
954
+ /**
955
+ * Class for uploading files using form and iframe
956
+ * @inherits qq.UploadHandlerAbstract
957
+ */
958
+ qq.UploadHandlerForm = function(o){
959
+ qq.UploadHandlerAbstract.apply(this, arguments);
960
+
961
+ this._inputs = {};
962
+ };
963
+ // @inherits qq.UploadHandlerAbstract
964
+ qq.extend(qq.UploadHandlerForm.prototype, qq.UploadHandlerAbstract.prototype);
965
+
966
+ qq.extend(qq.UploadHandlerForm.prototype, {
967
+ add: function(fileInput){
968
+ fileInput.setAttribute('name', 'qqfile');
969
+ var id = 'qq-upload-handler-iframe' + qq.getUniqueId();
970
+
971
+ this._inputs[id] = fileInput;
972
+
973
+ // remove file input from DOM
974
+ if (fileInput.parentNode){
975
+ qq.remove(fileInput);
976
+ }
977
+
978
+ return id;
979
+ },
980
+ getName: function(id){
981
+ // get input value and remove path to normalize
982
+ return this._inputs[id].value.replace(/.*(\/|\\)/, "");
983
+ },
984
+ _cancel: function(id){
985
+ this._options.onCancel(id, this.getName(id));
986
+
987
+ delete this._inputs[id];
988
+
989
+ var iframe = document.getElementById(id);
990
+ if (iframe){
991
+ // to cancel request set src to something else
992
+ // we use src="javascript:false;" because it doesn't
993
+ // trigger ie6 prompt on https
994
+ iframe.setAttribute('src', 'javascript:false;');
995
+
996
+ qq.remove(iframe);
997
+ }
998
+ },
999
+ _upload: function(id, params){
1000
+ var input = this._inputs[id];
1001
+
1002
+ if (!input){
1003
+ throw new Error('file with passed id was not added, or already uploaded or cancelled');
1004
+ }
1005
+
1006
+ var fileName = this.getName(id);
1007
+
1008
+ var iframe = this._createIframe(id);
1009
+ var form = this._createForm(iframe, params);
1010
+ form.appendChild(input);
1011
+
1012
+ var self = this;
1013
+ this._attachLoadEvent(iframe, function(){
1014
+ self.log('iframe loaded');
1015
+
1016
+ var response = self._getIframeContentJSON(iframe);
1017
+
1018
+ self._options.onComplete(id, fileName, response);
1019
+ self._dequeue(id);
1020
+
1021
+ delete self._inputs[id];
1022
+ // timeout added to fix busy state in FF3.6
1023
+ setTimeout(function(){
1024
+ qq.remove(iframe);
1025
+ }, 1);
1026
+ });
1027
+
1028
+ form.submit();
1029
+ qq.remove(form);
1030
+
1031
+ return id;
1032
+ },
1033
+ _attachLoadEvent: function(iframe, callback){
1034
+ qq.attach(iframe, 'load', function(){
1035
+ // when we remove iframe from dom
1036
+ // the request stops, but in IE load
1037
+ // event fires
1038
+ if (!iframe.parentNode){
1039
+ return;
1040
+ }
1041
+
1042
+ // fixing Opera 10.53
1043
+ if (iframe.contentDocument &&
1044
+ iframe.contentDocument.body &&
1045
+ iframe.contentDocument.body.innerHTML == "false"){
1046
+ // In Opera event is fired second time
1047
+ // when body.innerHTML changed from false
1048
+ // to server response approx. after 1 sec
1049
+ // when we upload file with iframe
1050
+ return;
1051
+ }
1052
+
1053
+ callback();
1054
+ });
1055
+ },
1056
+ /**
1057
+ * Returns json object received by iframe from server.
1058
+ */
1059
+ _getIframeContentJSON: function(iframe){
1060
+ // iframe.contentWindow.document - for IE<7
1061
+ var doc = iframe.contentDocument ? iframe.contentDocument: iframe.contentWindow.document,
1062
+ response;
1063
+
1064
+ this.log("converting iframe's innerHTML to JSON");
1065
+ this.log("innerHTML = " + doc.body.innerHTML);
1066
+
1067
+ try {
1068
+ response = eval("(" + doc.body.innerHTML + ")");
1069
+ } catch(err){
1070
+ response = {};
1071
+ }
1072
+
1073
+ return response;
1074
+ },
1075
+ /**
1076
+ * Creates iframe with unique name
1077
+ */
1078
+ _createIframe: function(id){
1079
+ // We can't use following code as the name attribute
1080
+ // won't be properly registered in IE6, and new window
1081
+ // on form submit will open
1082
+ // var iframe = document.createElement('iframe');
1083
+ // iframe.setAttribute('name', id);
1084
+
1085
+ var iframe = qq.toElement('<iframe src="javascript:false;" name="' + id + '" />');
1086
+ // src="javascript:false;" removes ie6 prompt on https
1087
+
1088
+ iframe.setAttribute('id', id);
1089
+
1090
+ iframe.style.display = 'none';
1091
+ document.body.appendChild(iframe);
1092
+
1093
+ return iframe;
1094
+ },
1095
+ /**
1096
+ * Creates form, that will be submitted to iframe
1097
+ */
1098
+ _createForm: function(iframe, params){
1099
+ // We can't use the following code in IE6
1100
+ // var form = document.createElement('form');
1101
+ // form.setAttribute('method', 'post');
1102
+ // form.setAttribute('enctype', 'multipart/form-data');
1103
+ // Because in this case file won't be attached to request
1104
+ var form = qq.toElement('<form method="post" enctype="multipart/form-data"></form>');
1105
+
1106
+ var queryString = qq.obj2url(params, this._options.action);
1107
+
1108
+ form.setAttribute('action', queryString);
1109
+ form.setAttribute('target', iframe.name);
1110
+ form.style.display = 'none';
1111
+ document.body.appendChild(form);
1112
+
1113
+ return form;
1114
+ }
1115
+ });
1116
+
1117
+ /**
1118
+ * Class for uploading files using xhr
1119
+ * @inherits qq.UploadHandlerAbstract
1120
+ */
1121
+ qq.UploadHandlerXhr = function(o){
1122
+ qq.UploadHandlerAbstract.apply(this, arguments);
1123
+
1124
+ this._files = [];
1125
+ this._xhrs = [];
1126
+
1127
+ // current loaded size in bytes for each file
1128
+ this._loaded = [];
1129
+ };
1130
+
1131
+ // static method
1132
+ qq.UploadHandlerXhr.isSupported = function(){
1133
+ var input = document.createElement('input');
1134
+ input.type = 'file';
1135
+
1136
+ return (
1137
+ 'multiple' in input &&
1138
+ typeof File != "undefined" &&
1139
+ typeof (new XMLHttpRequest()).upload != "undefined" );
1140
+ };
1141
+
1142
+ // @inherits qq.UploadHandlerAbstract
1143
+ qq.extend(qq.UploadHandlerXhr.prototype, qq.UploadHandlerAbstract.prototype)
1144
+
1145
+ qq.extend(qq.UploadHandlerXhr.prototype, {
1146
+ /**
1147
+ * Adds file to the queue
1148
+ * Returns id to use with upload, cancel
1149
+ **/
1150
+ add: function(file){
1151
+ if (!(file instanceof File)){
1152
+ throw new Error('Passed obj in not a File (in qq.UploadHandlerXhr)');
1153
+ }
1154
+
1155
+ return this._files.push(file) - 1;
1156
+ },
1157
+ getName: function(id){
1158
+ var file = this._files[id];
1159
+ // fix missing name in Safari 4
1160
+ return file.fileName != null ? file.fileName : file.name;
1161
+ },
1162
+ getSize: function(id){
1163
+ var file = this._files[id];
1164
+ return file.fileSize != null ? file.fileSize : file.size;
1165
+ },
1166
+ /**
1167
+ * Returns uploaded bytes for file identified by id
1168
+ */
1169
+ getLoaded: function(id){
1170
+ return this._loaded[id] || 0;
1171
+ },
1172
+ /**
1173
+ * Sends the file identified by id and additional query params to the server
1174
+ * @param {Object} params name-value string pairs
1175
+ */
1176
+ _upload: function(id, params){
1177
+ var file = this._files[id],
1178
+ name = this.getName(id),
1179
+ size = this.getSize(id);
1180
+
1181
+ this._loaded[id] = 0;
1182
+
1183
+ var xhr = this._xhrs[id] = new XMLHttpRequest();
1184
+ var self = this;
1185
+
1186
+ xhr.upload.onprogress = function(e){
1187
+ if (e.lengthComputable){
1188
+ self._loaded[id] = e.loaded;
1189
+ self._options.onProgress(id, name, e.loaded, e.total);
1190
+ }
1191
+ };
1192
+
1193
+ xhr.onreadystatechange = function(){
1194
+ if (xhr.readyState == 4){
1195
+ self._onComplete(id, xhr);
1196
+ }
1197
+ };
1198
+
1199
+ // build query string
1200
+ params = params || {};
1201
+ params['qqfile'] = name;
1202
+ var queryString = qq.obj2url(params, this._options.action);
1203
+
1204
+ xhr.open("POST", queryString, true);
1205
+ xhr.setRequestHeader("X-Requested-With", "XMLHttpRequest");
1206
+ xhr.setRequestHeader("X-File-Name", encodeURIComponent(name));
1207
+ xhr.setRequestHeader("Content-Type", "application/octet-stream");
1208
+ xhr.send(file);
1209
+ },
1210
+ _onComplete: function(id, xhr){
1211
+ // the request was aborted/cancelled
1212
+ if (!this._files[id]) return;
1213
+
1214
+ var name = this.getName(id);
1215
+ var size = this.getSize(id);
1216
+
1217
+ this._options.onProgress(id, name, size, size);
1218
+
1219
+ if (xhr.status == 200){
1220
+ this.log("xhr - server response received");
1221
+ this.log("responseText = " + xhr.responseText);
1222
+
1223
+ var response;
1224
+
1225
+ try {
1226
+ response = eval("(" + xhr.responseText + ")");
1227
+ } catch(err){
1228
+ response = {};
1229
+ }
1230
+
1231
+ this._options.onComplete(id, name, response);
1232
+
1233
+ } else {
1234
+ this._options.onComplete(id, name, {});
1235
+ }
1236
+
1237
+ this._files[id] = null;
1238
+ this._xhrs[id] = null;
1239
+ this._dequeue(id);
1240
+ },
1241
+ _cancel: function(id){
1242
+ this._options.onCancel(id, this.getName(id));
1243
+
1244
+ this._files[id] = null;
1245
+
1246
+ if (this._xhrs[id]){
1247
+ this._xhrs[id].abort();
1248
+ this._xhrs[id] = null;
1249
+ }
1250
+ }
1251
+ });
js/productlookbook/jquery-ui-1.9.1.js ADDED
@@ -0,0 +1,14823 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ /*! jQuery UI - v1.9.1 - 2012-10-25
2
+ * http://jqueryui.com
3
+ * Includes: jquery.ui.core.js, jquery.ui.widget.js, jquery.ui.mouse.js, jquery.ui.position.js, jquery.ui.accordion.js, jquery.ui.autocomplete.js, jquery.ui.button.js, jquery.ui.datepicker.js, jquery.ui.dialog.js, jquery.ui.draggable.js, jquery.ui.droppable.js, jquery.ui.effect.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.progressbar.js, jquery.ui.resizable.js, jquery.ui.selectable.js, jquery.ui.slider.js, jquery.ui.sortable.js, jquery.ui.spinner.js, jquery.ui.tabs.js, jquery.ui.tooltip.js
4
+ * Copyright (c) 2012 jQuery Foundation and other contributors Licensed MIT */
5
+
6
+ (function( $, undefined ) {
7
+
8
+ var uuid = 0,
9
+ runiqueId = /^ui-id-\d+$/;
10
+
11
+ // prevent duplicate loading
12
+ // this is only a problem because we proxy existing functions
13
+ // and we don't want to double proxy them
14
+ $.ui = $.ui || {};
15
+ if ( $.ui.version ) {
16
+ return;
17
+ }
18
+
19
+ $.extend( $.ui, {
20
+ version: "1.9.1",
21
+
22
+ keyCode: {
23
+ BACKSPACE: 8,
24
+ COMMA: 188,
25
+ DELETE: 46,
26
+ DOWN: 40,
27
+ END: 35,
28
+ ENTER: 13,
29
+ ESCAPE: 27,
30
+ HOME: 36,
31
+ LEFT: 37,
32
+ NUMPAD_ADD: 107,
33
+ NUMPAD_DECIMAL: 110,
34
+ NUMPAD_DIVIDE: 111,
35
+ NUMPAD_ENTER: 108,
36
+ NUMPAD_MULTIPLY: 106,
37
+ NUMPAD_SUBTRACT: 109,
38
+ PAGE_DOWN: 34,
39
+ PAGE_UP: 33,
40
+ PERIOD: 190,
41
+ RIGHT: 39,
42
+ SPACE: 32,
43
+ TAB: 9,
44
+ UP: 38
45
+ }
46
+ });
47
+
48
+ // plugins
49
+ $.fn.extend({
50
+ _focus: $.fn.focus,
51
+ focus: function( delay, fn ) {
52
+ return typeof delay === "number" ?
53
+ this.each(function() {
54
+ var elem = this;
55
+ setTimeout(function() {
56
+ $( elem ).focus();
57
+ if ( fn ) {
58
+ fn.call( elem );
59
+ }
60
+ }, delay );
61
+ }) :
62
+ this._focus.apply( this, arguments );
63
+ },
64
+
65
+ scrollParent: function() {
66
+ var scrollParent;
67
+ if (($.ui.ie && (/(static|relative)/).test(this.css('position'))) || (/absolute/).test(this.css('position'))) {
68
+ scrollParent = this.parents().filter(function() {
69
+ return (/(relative|absolute|fixed)/).test($.css(this,'position')) && (/(auto|scroll)/).test($.css(this,'overflow')+$.css(this,'overflow-y')+$.css(this,'overflow-x'));
70
+ }).eq(0);
71
+ } else {
72
+ scrollParent = this.parents().filter(function() {
73
+ return (/(auto|scroll)/).test($.css(this,'overflow')+$.css(this,'overflow-y')+$.css(this,'overflow-x'));
74
+ }).eq(0);
75
+ }
76
+
77
+ return (/fixed/).test(this.css('position')) || !scrollParent.length ? $(document) : scrollParent;
78
+ },
79
+
80
+ zIndex: function( zIndex ) {
81
+ if ( zIndex !== undefined ) {
82
+ return this.css( "zIndex", zIndex );
83
+ }
84
+
85
+ if ( this.length ) {
86
+ var elem = $( this[ 0 ] ), position, value;
87
+ while ( elem.length && elem[ 0 ] !== document ) {
88
+ // Ignore z-index if position is set to a value where z-index is ignored by the browser
89
+ // This makes behavior of this function consistent across browsers
90
+ // WebKit always returns auto if the element is positioned
91
+ position = elem.css( "position" );
92
+ if ( position === "absolute" || position === "relative" || position === "fixed" ) {
93
+ // IE returns 0 when zIndex is not specified
94
+ // other browsers return a string
95
+ // we ignore the case of nested elements with an explicit value of 0
96
+ // <div style="z-index: -10;"><div style="z-index: 0;"></div></div>
97
+ value = parseInt( elem.css( "zIndex" ), 10 );
98
+ if ( !isNaN( value ) && value !== 0 ) {
99
+ return value;
100
+ }
101
+ }
102
+ elem = elem.parent();
103
+ }
104
+ }
105
+
106
+ return 0;
107
+ },
108
+
109
+ uniqueId: function() {
110
+ return this.each(function() {
111
+ if ( !this.id ) {
112
+ this.id = "ui-id-" + (++uuid);
113
+ }
114
+ });
115
+ },
116
+
117
+ removeUniqueId: function() {
118
+ return this.each(function() {
119
+ if ( runiqueId.test( this.id ) ) {
120
+ $( this ).removeAttr( "id" );
121
+ }
122
+ });
123
+ }
124
+ });
125
+
126
+ // support: jQuery <1.8
127
+ if ( !$( "<a>" ).outerWidth( 1 ).jquery ) {
128
+ $.each( [ "Width", "Height" ], function( i, name ) {
129
+ var side = name === "Width" ? [ "Left", "Right" ] : [ "Top", "Bottom" ],
130
+ type = name.toLowerCase(),
131
+ orig = {
132
+ innerWidth: $.fn.innerWidth,
133
+ innerHeight: $.fn.innerHeight,
134
+ outerWidth: $.fn.outerWidth,
135
+ outerHeight: $.fn.outerHeight
136
+ };
137
+
138
+ function reduce( elem, size, border, margin ) {
139
+ $.each( side, function() {
140
+ size -= parseFloat( $.css( elem, "padding" + this ) ) || 0;
141
+ if ( border ) {
142
+ size -= parseFloat( $.css( elem, "border" + this + "Width" ) ) || 0;
143
+ }
144
+ if ( margin ) {
145
+ size -= parseFloat( $.css( elem, "margin" + this ) ) || 0;
146
+ }
147
+ });
148
+ return size;
149
+ }
150
+
151
+ $.fn[ "inner" + name ] = function( size ) {
152
+ if ( size === undefined ) {
153
+ return orig[ "inner" + name ].call( this );
154
+ }
155
+
156
+ return this.each(function() {
157
+ $( this ).css( type, reduce( this, size ) + "px" );
158
+ });
159
+ };
160
+
161
+ $.fn[ "outer" + name] = function( size, margin ) {
162
+ if ( typeof size !== "number" ) {
163
+ return orig[ "outer" + name ].call( this, size );
164
+ }
165
+
166
+ return this.each(function() {
167
+ $( this).css( type, reduce( this, size, true, margin ) + "px" );
168
+ });
169
+ };
170
+ });
171
+ }
172
+
173
+ // selectors
174
+ function focusable( element, isTabIndexNotNaN ) {
175
+ var map, mapName, img,
176
+ nodeName = element.nodeName.toLowerCase();
177
+ if ( "area" === nodeName ) {
178
+ map = element.parentNode;
179
+ mapName = map.name;
180
+ if ( !element.href || !mapName || map.nodeName.toLowerCase() !== "map" ) {
181
+ return false;
182
+ }
183
+ img = $( "img[usemap=#" + mapName + "]" )[0];
184
+ return !!img && visible( img );
185
+ }
186
+ return ( /input|select|textarea|button|object/.test( nodeName ) ?
187
+ !element.disabled :
188
+ "a" === nodeName ?
189
+ element.href || isTabIndexNotNaN :
190
+ isTabIndexNotNaN) &&
191
+ // the element and all of its ancestors must be visible
192
+ visible( element );
193
+ }
194
+
195
+ function visible( element ) {
196
+ return $.expr.filters.visible( element ) &&
197
+ !$( element ).parents().andSelf().filter(function() {
198
+ return $.css( this, "visibility" ) === "hidden";
199
+ }).length;
200
+ }
201
+
202
+ $.extend( $.expr[ ":" ], {
203
+ data: $.expr.createPseudo ?
204
+ $.expr.createPseudo(function( dataName ) {
205
+ return function( elem ) {
206
+ return !!$.data( elem, dataName );
207
+ };
208
+ }) :
209
+ // support: jQuery <1.8
210
+ function( elem, i, match ) {
211
+ return !!$.data( elem, match[ 3 ] );
212
+ },
213
+
214
+ focusable: function( element ) {
215
+ return focusable( element, !isNaN( $.attr( element, "tabindex" ) ) );
216
+ },
217
+
218
+ tabbable: function( element ) {
219
+ var tabIndex = $.attr( element, "tabindex" ),
220
+ isTabIndexNaN = isNaN( tabIndex );
221
+ return ( isTabIndexNaN || tabIndex >= 0 ) && focusable( element, !isTabIndexNaN );
222
+ }
223
+ });
224
+
225
+ // support
226
+ $(function() {
227
+ var body = document.body,
228
+ div = body.appendChild( div = document.createElement( "div" ) );
229
+
230
+ // access offsetHeight before setting the style to prevent a layout bug
231
+ // in IE 9 which causes the element to continue to take up space even
232
+ // after it is removed from the DOM (#8026)
233
+ div.offsetHeight;
234
+
235
+ $.extend( div.style, {
236
+ minHeight: "100px",
237
+ height: "auto",
238
+ padding: 0,
239
+ borderWidth: 0
240
+ });
241
+
242
+ $.support.minHeight = div.offsetHeight === 100;
243
+ $.support.selectstart = "onselectstart" in div;
244
+
245
+ // set display to none to avoid a layout bug in IE
246
+ // http://dev.jquery.com/ticket/4014
247
+ body.removeChild( div ).style.display = "none";
248
+ });
249
+
250
+
251
+
252
+
253
+
254
+ // deprecated
255
+
256
+ (function() {
257
+ var uaMatch = /msie ([\w.]+)/.exec( navigator.userAgent.toLowerCase() ) || [];
258
+ $.ui.ie = uaMatch.length ? true : false;
259
+ $.ui.ie6 = parseFloat( uaMatch[ 1 ], 10 ) === 6;
260
+ })();
261
+
262
+ $.fn.extend({
263
+ disableSelection: function() {
264
+ return this.bind( ( $.support.selectstart ? "selectstart" : "mousedown" ) +
265
+ ".ui-disableSelection", function( event ) {
266
+ event.preventDefault();
267
+ });
268
+ },
269
+
270
+ enableSelection: function() {
271
+ return this.unbind( ".ui-disableSelection" );
272
+ }
273
+ });
274
+
275
+ $.extend( $.ui, {
276
+ // $.ui.plugin is deprecated. Use the proxy pattern instead.
277
+ plugin: {
278
+ add: function( module, option, set ) {
279
+ var i,
280
+ proto = $.ui[ module ].prototype;
281
+ for ( i in set ) {
282
+ proto.plugins[ i ] = proto.plugins[ i ] || [];
283
+ proto.plugins[ i ].push( [ option, set[ i ] ] );
284
+ }
285
+ },
286
+ call: function( instance, name, args ) {
287
+ var i,
288
+ set = instance.plugins[ name ];
289
+ if ( !set || !instance.element[ 0 ].parentNode || instance.element[ 0 ].parentNode.nodeType === 11 ) {
290
+ return;
291
+ }
292
+
293
+ for ( i = 0; i < set.length; i++ ) {
294
+ if ( instance.options[ set[ i ][ 0 ] ] ) {
295
+ set[ i ][ 1 ].apply( instance.element, args );
296
+ }
297
+ }
298
+ }
299
+ },
300
+
301
+ contains: $.contains,
302
+
303
+ // only used by resizable
304
+ hasScroll: function( el, a ) {
305
+
306
+ //If overflow is hidden, the element might have extra content, but the user wants to hide it
307
+ if ( $( el ).css( "overflow" ) === "hidden") {
308
+ return false;
309
+ }
310
+
311
+ var scroll = ( a && a === "left" ) ? "scrollLeft" : "scrollTop",
312
+ has = false;
313
+
314
+ if ( el[ scroll ] > 0 ) {
315
+ return true;
316
+ }
317
+
318
+ // TODO: determine which cases actually cause this to happen
319
+ // if the element doesn't have the scroll set, see if it's possible to
320
+ // set the scroll
321
+ el[ scroll ] = 1;
322
+ has = ( el[ scroll ] > 0 );
323
+ el[ scroll ] = 0;
324
+ return has;
325
+ },
326
+
327
+ // these are odd functions, fix the API or move into individual plugins
328
+ isOverAxis: function( x, reference, size ) {
329
+ //Determines when x coordinate is over "b" element axis
330
+ return ( x > reference ) && ( x < ( reference + size ) );
331
+ },
332
+ isOver: function( y, x, top, left, height, width ) {
333
+ //Determines when x, y coordinates is over "b" element
334
+ return $.ui.isOverAxis( y, top, height ) && $.ui.isOverAxis( x, left, width );
335
+ }
336
+ });
337
+
338
+ })( jQuery );
339
+ (function( $, undefined ) {
340
+
341
+ var uuid = 0,
342
+ slice = Array.prototype.slice,
343
+ _cleanData = $.cleanData;
344
+ $.cleanData = function( elems ) {
345
+ for ( var i = 0, elem; (elem = elems[i]) != null; i++ ) {
346
+ try {
347
+ $( elem ).triggerHandler( "remove" );
348
+ // http://bugs.jquery.com/ticket/8235
349
+ } catch( e ) {}
350
+ }
351
+ _cleanData( elems );
352
+ };
353
+
354
+ $.widget = function( name, base, prototype ) {
355
+ var fullName, existingConstructor, constructor, basePrototype,
356
+ namespace = name.split( "." )[ 0 ];
357
+
358
+ name = name.split( "." )[ 1 ];
359
+ fullName = namespace + "-" + name;
360
+
361
+ if ( !prototype ) {
362
+ prototype = base;
363
+ base = $.Widget;
364
+ }
365
+
366
+ // create selector for plugin
367
+ $.expr[ ":" ][ fullName.toLowerCase() ] = function( elem ) {
368
+ return !!$.data( elem, fullName );
369
+ };
370
+
371
+ $[ namespace ] = $[ namespace ] || {};
372
+ existingConstructor = $[ namespace ][ name ];
373
+ constructor = $[ namespace ][ name ] = function( options, element ) {
374
+ // allow instantiation without "new" keyword
375
+ if ( !this._createWidget ) {
376
+ return new constructor( options, element );
377
+ }
378
+
379
+ // allow instantiation without initializing for simple inheritance
380
+ // must use "new" keyword (the code above always passes args)
381
+ if ( arguments.length ) {
382
+ this._createWidget( options, element );
383
+ }
384
+ };
385
+ // extend with the existing constructor to carry over any static properties
386
+ $.extend( constructor, existingConstructor, {
387
+ version: prototype.version,
388
+ // copy the object used to create the prototype in case we need to
389
+ // redefine the widget later
390
+ _proto: $.extend( {}, prototype ),
391
+ // track widgets that inherit from this widget in case this widget is
392
+ // redefined after a widget inherits from it
393
+ _childConstructors: []
394
+ });
395
+
396
+ basePrototype = new base();
397
+ // we need to make the options hash a property directly on the new instance
398
+ // otherwise we'll modify the options hash on the prototype that we're
399
+ // inheriting from
400
+ basePrototype.options = $.widget.extend( {}, basePrototype.options );
401
+ $.each( prototype, function( prop, value ) {
402
+ if ( $.isFunction( value ) ) {
403
+ prototype[ prop ] = (function() {
404
+ var _super = function() {
405
+ return base.prototype[ prop ].apply( this, arguments );
406
+ },
407
+ _superApply = function( args ) {
408
+ return base.prototype[ prop ].apply( this, args );
409
+ };
410
+ return function() {
411
+ var __super = this._super,
412
+ __superApply = this._superApply,
413
+ returnValue;
414
+
415
+ this._super = _super;
416
+ this._superApply = _superApply;
417
+
418
+ returnValue = value.apply( this, arguments );
419
+
420
+ this._super = __super;
421
+ this._superApply = __superApply;
422
+
423
+ return returnValue;
424
+ };
425
+ })();
426
+ }
427
+ });
428
+ constructor.prototype = $.widget.extend( basePrototype, {
429
+ // TODO: remove support for widgetEventPrefix
430
+ // always use the name + a colon as the prefix, e.g., draggable:start
431
+ // don't prefix for widgets that aren't DOM-based
432
+ widgetEventPrefix: basePrototype.widgetEventPrefix || name
433
+ }, prototype, {
434
+ constructor: constructor,
435
+ namespace: namespace,
436
+ widgetName: name,
437
+ // TODO remove widgetBaseClass, see #8155
438
+ widgetBaseClass: fullName,
439
+ widgetFullName: fullName
440
+ });
441
+
442
+ // If this widget is being redefined then we need to find all widgets that
443
+ // are inheriting from it and redefine all of them so that they inherit from
444
+ // the new version of this widget. We're essentially trying to replace one
445
+ // level in the prototype chain.
446
+ if ( existingConstructor ) {
447
+ $.each( existingConstructor._childConstructors, function( i, child ) {
448
+ var childPrototype = child.prototype;
449
+
450
+ // redefine the child widget using the same prototype that was
451
+ // originally used, but inherit from the new version of the base
452
+ $.widget( childPrototype.namespace + "." + childPrototype.widgetName, constructor, child._proto );
453
+ });
454
+ // remove the list of existing child constructors from the old constructor
455
+ // so the old child constructors can be garbage collected
456
+ delete existingConstructor._childConstructors;
457
+ } else {
458
+ base._childConstructors.push( constructor );
459
+ }
460
+
461
+ $.widget.bridge( name, constructor );
462
+ };
463
+
464
+ $.widget.extend = function( target ) {
465
+ var input = slice.call( arguments, 1 ),
466
+ inputIndex = 0,
467
+ inputLength = input.length,
468
+ key,
469
+ value;
470
+ for ( ; inputIndex < inputLength; inputIndex++ ) {
471
+ for ( key in input[ inputIndex ] ) {
472
+ value = input[ inputIndex ][ key ];
473
+ if ( input[ inputIndex ].hasOwnProperty( key ) && value !== undefined ) {
474
+ // Clone objects
475
+ if ( $.isPlainObject( value ) ) {
476
+ target[ key ] = $.isPlainObject( target[ key ] ) ?
477
+ $.widget.extend( {}, target[ key ], value ) :
478
+ // Don't extend strings, arrays, etc. with objects
479
+ $.widget.extend( {}, value );
480
+ // Copy everything else by reference
481
+ } else {
482
+ target[ key ] = value;
483
+ }
484
+ }
485
+ }
486
+ }
487
+ return target;
488
+ };
489
+
490
+ $.widget.bridge = function( name, object ) {
491
+ var fullName = object.prototype.widgetFullName;
492
+ $.fn[ name ] = function( options ) {
493
+ var isMethodCall = typeof options === "string",
494
+ args = slice.call( arguments, 1 ),
495
+ returnValue = this;
496
+
497
+ // allow multiple hashes to be passed on init
498
+ options = !isMethodCall && args.length ?
499
+ $.widget.extend.apply( null, [ options ].concat(args) ) :
500
+ options;
501
+
502
+ if ( isMethodCall ) {
503
+ this.each(function() {
504
+ var methodValue,
505
+ instance = $.data( this, fullName );
506
+ if ( !instance ) {
507
+ return $.error( "cannot call methods on " + name + " prior to initialization; " +
508
+ "attempted to call method '" + options + "'" );
509
+ }
510
+ if ( !$.isFunction( instance[options] ) || options.charAt( 0 ) === "_" ) {
511
+ return $.error( "no such method '" + options + "' for " + name + " widget instance" );
512
+ }
513
+ methodValue = instance[ options ].apply( instance, args );
514
+ if ( methodValue !== instance && methodValue !== undefined ) {
515
+ returnValue = methodValue && methodValue.jquery ?
516
+ returnValue.pushStack( methodValue.get() ) :
517
+ methodValue;
518
+ return false;
519
+ }
520
+ });
521
+ } else {
522
+ this.each(function() {
523
+ var instance = $.data( this, fullName );
524
+ if ( instance ) {
525
+ instance.option( options || {} )._init();
526
+ } else {
527
+ new object( options, this );
528
+ }
529
+ });
530
+ }
531
+
532
+ return returnValue;
533
+ };
534
+ };
535
+
536
+ $.Widget = function( /* options, element */ ) {};
537
+ $.Widget._childConstructors = [];
538
+
539
+ $.Widget.prototype = {
540
+ widgetName: "widget",
541
+ widgetEventPrefix: "",
542
+ defaultElement: "<div>",
543
+ options: {
544
+ disabled: false,
545
+
546
+ // callbacks
547
+ create: null
548
+ },
549
+ _createWidget: function( options, element ) {
550
+ element = $( element || this.defaultElement || this )[ 0 ];
551
+ this.element = $( element );
552
+ this.uuid = uuid++;
553
+ this.eventNamespace = "." + this.widgetName + this.uuid;
554
+ this.options = $.widget.extend( {},
555
+ this.options,
556
+ this._getCreateOptions(),
557
+ options );
558
+
559
+ this.bindings = $();
560
+ this.hoverable = $();
561
+ this.focusable = $();
562
+
563
+ if ( element !== this ) {
564
+ // 1.9 BC for #7810
565
+ // TODO remove dual storage
566
+ $.data( element, this.widgetName, this );
567
+ $.data( element, this.widgetFullName, this );
568
+ this._on( this.element, {
569
+ remove: function( event ) {
570
+ if ( event.target === element ) {
571
+ this.destroy();
572
+ }
573
+ }
574
+ });
575
+ this.document = $( element.style ?
576
+ // element within the document
577
+ element.ownerDocument :
578
+ // element is window or document
579
+ element.document || element );
580
+ this.window = $( this.document[0].defaultView || this.document[0].parentWindow );
581
+ }
582
+
583
+ this._create();
584
+ this._trigger( "create", null, this._getCreateEventData() );
585
+ this._init();
586
+ },
587
+ _getCreateOptions: $.noop,
588
+ _getCreateEventData: $.noop,
589
+ _create: $.noop,
590
+ _init: $.noop,
591
+
592
+ destroy: function() {
593
+ this._destroy();
594
+ // we can probably remove the unbind calls in 2.0
595
+ // all event bindings should go through this._on()
596
+ this.element
597
+ .unbind( this.eventNamespace )
598
+ // 1.9 BC for #7810
599
+ // TODO remove dual storage
600
+ .removeData( this.widgetName )
601
+ .removeData( this.widgetFullName )
602
+ // support: jquery <1.6.3
603
+ // http://bugs.jquery.com/ticket/9413
604
+ .removeData( $.camelCase( this.widgetFullName ) );
605
+ this.widget()
606
+ .unbind( this.eventNamespace )
607
+ .removeAttr( "aria-disabled" )
608
+ .removeClass(
609
+ this.widgetFullName + "-disabled " +
610
+ "ui-state-disabled" );
611
+
612
+ // clean up events and states
613
+ this.bindings.unbind( this.eventNamespace );
614
+ this.hoverable.removeClass( "ui-state-hover" );
615
+ this.focusable.removeClass( "ui-state-focus" );
616
+ },
617
+ _destroy: $.noop,
618
+
619
+ widget: function() {
620
+ return this.element;
621
+ },
622
+
623
+ option: function( key, value ) {
624
+ var options = key,
625
+ parts,
626
+ curOption,
627
+ i;
628
+
629
+ if ( arguments.length === 0 ) {
630
+ // don't return a reference to the internal hash
631
+ return $.widget.extend( {}, this.options );
632
+ }
633
+
634
+ if ( typeof key === "string" ) {
635
+ // handle nested keys, e.g., "foo.bar" => { foo: { bar: ___ } }
636
+ options = {};
637
+ parts = key.split( "." );
638
+ key = parts.shift();
639
+ if ( parts.length ) {
640
+ curOption = options[ key ] = $.widget.extend( {}, this.options[ key ] );
641
+ for ( i = 0; i < parts.length - 1; i++ ) {
642
+ curOption[ parts[ i ] ] = curOption[ parts[ i ] ] || {};
643
+ curOption = curOption[ parts[ i ] ];
644
+ }
645
+ key = parts.pop();
646
+ if ( value === undefined ) {
647
+ return curOption[ key ] === undefined ? null : curOption[ key ];
648
+ }
649
+ curOption[ key ] = value;
650
+ } else {
651
+ if ( value === undefined ) {
652
+ return this.options[ key ] === undefined ? null : this.options[ key ];
653
+ }
654
+ options[ key ] = value;
655
+ }
656
+ }
657
+
658
+ this._setOptions( options );
659
+
660
+ return this;
661
+ },
662
+ _setOptions: function( options ) {
663
+ var key;
664
+
665
+ for ( key in options ) {
666
+ this._setOption( key, options[ key ] );
667
+ }
668
+
669
+ return this;
670
+ },
671
+ _setOption: function( key, value ) {
672
+ this.options[ key ] = value;
673
+
674
+ if ( key === "disabled" ) {
675
+ this.widget()
676
+ .toggleClass( this.widgetFullName + "-disabled ui-state-disabled", !!value )
677
+ .attr( "aria-disabled", value );
678
+ this.hoverable.removeClass( "ui-state-hover" );
679
+ this.focusable.removeClass( "ui-state-focus" );
680
+ }
681
+
682
+ return this;
683
+ },
684
+
685
+ enable: function() {
686
+ return this._setOption( "disabled", false );
687
+ },
688
+ disable: function() {
689
+ return this._setOption( "disabled", true );
690
+ },
691
+
692
+ _on: function( element, handlers ) {
693
+ var delegateElement,
694
+ instance = this;
695
+ // no element argument, shuffle and use this.element
696
+ if ( !handlers ) {
697
+ handlers = element;
698
+ element = this.element;
699
+ delegateElement = this.widget();
700
+ } else {
701
+ // accept selectors, DOM elements
702
+ element = delegateElement = $( element );
703
+ this.bindings = this.bindings.add( element );
704
+ }
705
+
706
+ $.each( handlers, function( event, handler ) {
707
+ function handlerProxy() {
708
+ // allow widgets to customize the disabled handling
709
+ // - disabled as an array instead of boolean
710
+ // - disabled class as method for disabling individual parts
711
+ if ( instance.options.disabled === true ||
712
+ $( this ).hasClass( "ui-state-disabled" ) ) {
713
+ return;
714
+ }
715
+ return ( typeof handler === "string" ? instance[ handler ] : handler )
716
+ .apply( instance, arguments );
717
+ }
718
+
719
+ // copy the guid so direct unbinding works
720
+ if ( typeof handler !== "string" ) {
721
+ handlerProxy.guid = handler.guid =
722
+ handler.guid || handlerProxy.guid || $.guid++;
723
+ }
724
+
725
+ var match = event.match( /^(\w+)\s*(.*)$/ ),
726
+ eventName = match[1] + instance.eventNamespace,
727
+ selector = match[2];
728
+ if ( selector ) {
729
+ delegateElement.delegate( selector, eventName, handlerProxy );
730
+ } else {
731
+ element.bind( eventName, handlerProxy );
732
+ }
733
+ });
734
+ },
735
+
736
+ _off: function( element, eventName ) {
737
+ eventName = (eventName || "").split( " " ).join( this.eventNamespace + " " ) + this.eventNamespace;
738
+ element.unbind( eventName ).undelegate( eventName );
739
+ },
740
+
741
+ _delay: function( handler, delay ) {
742
+ function handlerProxy() {
743
+ return ( typeof handler === "string" ? instance[ handler ] : handler )
744
+ .apply( instance, arguments );
745
+ }
746
+ var instance = this;
747
+ return setTimeout( handlerProxy, delay || 0 );
748
+ },
749
+
750
+ _hoverable: function( element ) {
751
+ this.hoverable = this.hoverable.add( element );
752
+ this._on( element, {
753
+ mouseenter: function( event ) {
754
+ $( event.currentTarget ).addClass( "ui-state-hover" );
755
+ },
756
+ mouseleave: function( event ) {
757
+ $( event.currentTarget ).removeClass( "ui-state-hover" );
758
+ }
759
+ });
760
+ },
761
+
762
+ _focusable: function( element ) {
763
+ this.focusable = this.focusable.add( element );
764
+ this._on( element, {
765
+ focusin: function( event ) {
766
+ $( event.currentTarget ).addClass( "ui-state-focus" );
767
+ },
768
+ focusout: function( event ) {
769
+ $( event.currentTarget ).removeClass( "ui-state-focus" );
770
+ }
771
+ });
772
+ },
773
+
774
+ _trigger: function( type, event, data ) {
775
+ var prop, orig,
776
+ callback = this.options[ type ];
777
+
778
+ data = data || {};
779
+ event = $.Event( event );
780
+ event.type = ( type === this.widgetEventPrefix ?
781
+ type :
782
+ this.widgetEventPrefix + type ).toLowerCase();
783
+ // the original event may come from any element
784
+ // so we need to reset the target on the new event
785
+ event.target = this.element[ 0 ];
786
+
787
+ // copy original event properties over to the new event
788
+ orig = event.originalEvent;
789
+ if ( orig ) {
790
+ for ( prop in orig ) {
791
+ if ( !( prop in event ) ) {
792
+ event[ prop ] = orig[ prop ];
793
+ }
794
+ }
795
+ }
796
+
797
+ this.element.trigger( event, data );
798
+ return !( $.isFunction( callback ) &&
799
+ callback.apply( this.element[0], [ event ].concat( data ) ) === false ||
800
+ event.isDefaultPrevented() );
801
+ }
802
+ };
803
+
804
+ $.each( { show: "fadeIn", hide: "fadeOut" }, function( method, defaultEffect ) {
805
+ $.Widget.prototype[ "_" + method ] = function( element, options, callback ) {
806
+ if ( typeof options === "string" ) {
807
+ options = { effect: options };
808
+ }
809
+ var hasOptions,
810
+ effectName = !options ?
811
+ method :
812
+ options === true || typeof options === "number" ?
813
+ defaultEffect :
814
+ options.effect || defaultEffect;
815
+ options = options || {};
816
+ if ( typeof options === "number" ) {
817
+ options = { duration: options };
818
+ }
819
+ hasOptions = !$.isEmptyObject( options );
820
+ options.complete = callback;
821
+ if ( options.delay ) {
822
+ element.delay( options.delay );
823
+ }
824
+ if ( hasOptions && $.effects && ( $.effects.effect[ effectName ] || $.uiBackCompat !== false && $.effects[ effectName ] ) ) {
825
+ element[ method ]( options );
826
+ } else if ( effectName !== method && element[ effectName ] ) {
827
+ element[ effectName ]( options.duration, options.easing, callback );
828
+ } else {
829
+ element.queue(function( next ) {
830
+ $( this )[ method ]();
831
+ if ( callback ) {
832
+ callback.call( element[ 0 ] );
833
+ }
834
+ next();
835
+ });
836
+ }
837
+ };
838
+ });
839
+
840
+ // DEPRECATED
841
+ if ( $.uiBackCompat !== false ) {
842
+ $.Widget.prototype._getCreateOptions = function() {
843
+ return $.metadata && $.metadata.get( this.element[0] )[ this.widgetName ];
844
+ };
845
+ }
846
+
847
+ })( jQuery );
848
+ (function( $, undefined ) {
849
+
850
+ var mouseHandled = false;
851
+ $( document ).mouseup( function( e ) {
852
+ mouseHandled = false;
853
+ });
854
+
855
+ $.widget("ui.mouse", {
856
+ version: "1.9.1",
857
+ options: {
858
+ cancel: 'input,textarea,button,select,option',
859
+ distance: 1,
860
+ delay: 0
861
+ },
862
+ _mouseInit: function() {
863
+ var that = this;
864
+
865
+ this.element
866
+ .bind('mousedown.'+this.widgetName, function(event) {
867
+ return that._mouseDown(event);
868
+ })
869
+ .bind('click.'+this.widgetName, function(event) {
870
+ if (true === $.data(event.target, that.widgetName + '.preventClickEvent')) {
871
+ $.removeData(event.target, that.widgetName + '.preventClickEvent');
872
+ event.stopImmediatePropagation();
873
+ return false;
874
+ }
875
+ });
876
+
877
+ this.started = false;
878
+ },
879
+
880
+ // TODO: make sure destroying one instance of mouse doesn't mess with
881
+ // other instances of mouse
882
+ _mouseDestroy: function() {
883
+ this.element.unbind('.'+this.widgetName);
884
+ if ( this._mouseMoveDelegate ) {
885
+ $(document)
886
+ .unbind('mousemove.'+this.widgetName, this._mouseMoveDelegate)
887
+ .unbind('mouseup.'+this.widgetName, this._mouseUpDelegate);
888
+ }
889
+ },
890
+
891
+ _mouseDown: function(event) {
892
+ // don't let more than one widget handle mouseStart
893
+ if( mouseHandled ) { return; }
894
+
895
+ // we may have missed mouseup (out of window)
896
+ (this._mouseStarted && this._mouseUp(event));
897
+
898
+ this._mouseDownEvent = event;
899
+
900
+ var that = this,
901
+ btnIsLeft = (event.which === 1),
902
+ // event.target.nodeName works around a bug in IE 8 with
903
+ // disabled inputs (#7620)
904
+ elIsCancel = (typeof this.options.cancel === "string" && event.target.nodeName ? $(event.target).closest(this.options.cancel).length : false);
905
+ if (!btnIsLeft || elIsCancel || !this._mouseCapture(event)) {
906
+ return true;
907
+ }
908
+
909
+ this.mouseDelayMet = !this.options.delay;
910
+ if (!this.mouseDelayMet) {
911
+ this._mouseDelayTimer = setTimeout(function() {
912
+ that.mouseDelayMet = true;
913
+ }, this.options.delay);
914
+ }
915
+
916
+ if (this._mouseDistanceMet(event) && this._mouseDelayMet(event)) {
917
+ this._mouseStarted = (this._mouseStart(event) !== false);
918
+ if (!this._mouseStarted) {
919
+ event.preventDefault();
920
+ return true;
921
+ }
922
+ }
923
+
924
+ // Click event may never have fired (Gecko & Opera)
925
+ if (true === $.data(event.target, this.widgetName + '.preventClickEvent')) {
926
+ $.removeData(event.target, this.widgetName + '.preventClickEvent');
927
+ }
928
+
929
+ // these delegates are required to keep context
930
+ this._mouseMoveDelegate = function(event) {
931
+ return that._mouseMove(event);
932
+ };
933
+ this._mouseUpDelegate = function(event) {
934
+ return that._mouseUp(event);
935
+ };
936
+ $(document)
937
+ .bind('mousemove.'+this.widgetName, this._mouseMoveDelegate)
938
+ .bind('mouseup.'+this.widgetName, this._mouseUpDelegate);
939
+
940
+ event.preventDefault();
941
+
942
+ mouseHandled = true;
943
+ return true;
944
+ },
945
+
946
+ _mouseMove: function(event) {
947
+ // IE mouseup check - mouseup happened when mouse was out of window
948
+ if ($.ui.ie && !(document.documentMode >= 9) && !event.button) {
949
+ return this._mouseUp(event);
950
+ }
951
+
952
+ if (this._mouseStarted) {
953
+ this._mouseDrag(event);
954
+ return event.preventDefault();
955
+ }
956
+
957
+ if (this._mouseDistanceMet(event) && this._mouseDelayMet(event)) {
958
+ this._mouseStarted =
959
+ (this._mouseStart(this._mouseDownEvent, event) !== false);
960
+ (this._mouseStarted ? this._mouseDrag(event) : this._mouseUp(event));
961
+ }
962
+
963
+ return !this._mouseStarted;
964
+ },
965
+
966
+ _mouseUp: function(event) {
967
+ $(document)
968
+ .unbind('mousemove.'+this.widgetName, this._mouseMoveDelegate)
969
+ .unbind('mouseup.'+this.widgetName, this._mouseUpDelegate);
970
+
971
+ if (this._mouseStarted) {
972
+ this._mouseStarted = false;
973
+
974
+ if (event.target === this._mouseDownEvent.target) {
975
+ $.data(event.target, this.widgetName + '.preventClickEvent', true);
976
+ }
977
+
978
+ this._mouseStop(event);
979
+ }
980
+
981
+ return false;
982
+ },
983
+
984
+ _mouseDistanceMet: function(event) {
985
+ return (Math.max(
986
+ Math.abs(this._mouseDownEvent.pageX - event.pageX),
987
+ Math.abs(this._mouseDownEvent.pageY - event.pageY)
988
+ ) >= this.options.distance
989
+ );
990
+ },
991
+
992
+ _mouseDelayMet: function(event) {
993
+ return this.mouseDelayMet;
994
+ },
995
+
996
+ // These are placeholder methods, to be overriden by extending plugin
997
+ _mouseStart: function(event) {},
998
+ _mouseDrag: function(event) {},
999
+ _mouseStop: function(event) {},
1000
+ _mouseCapture: function(event) { return true; }
1001
+ });
1002
+
1003
+ })(jQuery);
1004
+ (function( $, undefined ) {
1005
+
1006
+ $.ui = $.ui || {};
1007
+
1008
+ var cachedScrollbarWidth,
1009
+ max = Math.max,
1010
+ abs = Math.abs,
1011
+ round = Math.round,
1012
+ rhorizontal = /left|center|right/,
1013
+ rvertical = /top|center|bottom/,
1014
+ roffset = /[\+\-]\d+%?/,
1015
+ rposition = /^\w+/,
1016
+ rpercent = /%$/,
1017
+ _position = $.fn.position;
1018
+
1019
+ function getOffsets( offsets, width, height ) {
1020
+ return [
1021
+ parseInt( offsets[ 0 ], 10 ) * ( rpercent.test( offsets[ 0 ] ) ? width / 100 : 1 ),
1022
+ parseInt( offsets[ 1 ], 10 ) * ( rpercent.test( offsets[ 1 ] ) ? height / 100 : 1 )
1023
+ ];
1024
+ }
1025
+ function parseCss( element, property ) {
1026
+ return parseInt( $.css( element, property ), 10 ) || 0;
1027
+ }
1028
+
1029
+ $.position = {
1030
+ scrollbarWidth: function() {
1031
+ if ( cachedScrollbarWidth !== undefined ) {
1032
+ return cachedScrollbarWidth;
1033
+ }
1034
+ var w1, w2,
1035
+ div = $( "<div style='display:block;width:50px;height:50px;overflow:hidden;'><div style='height:100px;width:auto;'></div></div>" ),
1036
+ innerDiv = div.children()[0];
1037
+
1038
+ $( "body" ).append( div );
1039
+ w1 = innerDiv.offsetWidth;
1040
+ div.css( "overflow", "scroll" );
1041
+
1042
+ w2 = innerDiv.offsetWidth;
1043
+
1044
+ if ( w1 === w2 ) {
1045
+ w2 = div[0].clientWidth;
1046
+ }
1047
+
1048
+ div.remove();
1049
+
1050
+ return (cachedScrollbarWidth = w1 - w2);
1051
+ },
1052
+ getScrollInfo: function( within ) {
1053
+ var overflowX = within.isWindow ? "" : within.element.css( "overflow-x" ),
1054
+ overflowY = within.isWindow ? "" : within.element.css( "overflow-y" ),
1055
+ hasOverflowX = overflowX === "scroll" ||
1056
+ ( overflowX === "auto" && within.width < within.element[0].scrollWidth ),
1057
+ hasOverflowY = overflowY === "scroll" ||
1058
+ ( overflowY === "auto" && within.height < within.element[0].scrollHeight );
1059
+ return {
1060
+ width: hasOverflowX ? $.position.scrollbarWidth() : 0,
1061
+ height: hasOverflowY ? $.position.scrollbarWidth() : 0
1062
+ };
1063
+ },
1064
+ getWithinInfo: function( element ) {
1065
+ var withinElement = $( element || window ),
1066
+ isWindow = $.isWindow( withinElement[0] );
1067
+ return {
1068
+ element: withinElement,
1069
+ isWindow: isWindow,
1070
+ offset: withinElement.offset() || { left: 0, top: 0 },
1071
+ scrollLeft: withinElement.scrollLeft(),
1072
+ scrollTop: withinElement.scrollTop(),
1073
+ width: isWindow ? withinElement.width() : withinElement.outerWidth(),
1074
+ height: isWindow ? withinElement.height() : withinElement.outerHeight()
1075
+ };
1076
+ }
1077
+ };
1078
+
1079
+ $.fn.position = function( options ) {
1080
+ if ( !options || !options.of ) {
1081
+ return _position.apply( this, arguments );
1082
+ }
1083
+
1084
+ // make a copy, we don't want to modify arguments
1085
+ options = $.extend( {}, options );
1086
+
1087
+ var atOffset, targetWidth, targetHeight, targetOffset, basePosition,
1088
+ target = $( options.of ),
1089
+ within = $.position.getWithinInfo( options.within ),
1090
+ scrollInfo = $.position.getScrollInfo( within ),
1091
+ targetElem = target[0],
1092
+ collision = ( options.collision || "flip" ).split( " " ),
1093
+ offsets = {};
1094
+
1095
+ if ( targetElem.nodeType === 9 ) {
1096
+ targetWidth = target.width();
1097
+ targetHeight = target.height();
1098
+ targetOffset = { top: 0, left: 0 };
1099
+ } else if ( $.isWindow( targetElem ) ) {
1100
+ targetWidth = target.width();
1101
+ targetHeight = target.height();
1102
+ targetOffset = { top: target.scrollTop(), left: target.scrollLeft() };
1103
+ } else if ( targetElem.preventDefault ) {
1104
+ // force left top to allow flipping
1105
+ options.at = "left top";
1106
+ targetWidth = targetHeight = 0;
1107
+ targetOffset = { top: targetElem.pageY, left: targetElem.pageX };
1108
+ } else {
1109
+ targetWidth = target.outerWidth();
1110
+ targetHeight = target.outerHeight();
1111
+ targetOffset = target.offset();
1112
+ }
1113
+ // clone to reuse original targetOffset later
1114
+ basePosition = $.extend( {}, targetOffset );
1115
+
1116
+ // force my and at to have valid horizontal and vertical positions
1117
+ // if a value is missing or invalid, it will be converted to center
1118
+ $.each( [ "my", "at" ], function() {
1119
+ var pos = ( options[ this ] || "" ).split( " " ),
1120
+ horizontalOffset,
1121
+ verticalOffset;
1122
+
1123
+ if ( pos.length === 1) {
1124
+ pos = rhorizontal.test( pos[ 0 ] ) ?
1125
+ pos.concat( [ "center" ] ) :
1126
+ rvertical.test( pos[ 0 ] ) ?
1127
+ [ "center" ].concat( pos ) :
1128
+ [ "center", "center" ];
1129
+ }
1130
+ pos[ 0 ] = rhorizontal.test( pos[ 0 ] ) ? pos[ 0 ] : "center";
1131
+ pos[ 1 ] = rvertical.test( pos[ 1 ] ) ? pos[ 1 ] : "center";
1132
+
1133
+ // calculate offsets
1134
+ horizontalOffset = roffset.exec( pos[ 0 ] );
1135
+ verticalOffset = roffset.exec( pos[ 1 ] );
1136
+ offsets[ this ] = [
1137
+ horizontalOffset ? horizontalOffset[ 0 ] : 0,
1138
+ verticalOffset ? verticalOffset[ 0 ] : 0
1139
+ ];
1140
+
1141
+ // reduce to just the positions without the offsets
1142
+ options[ this ] = [
1143
+ rposition.exec( pos[ 0 ] )[ 0 ],
1144
+ rposition.exec( pos[ 1 ] )[ 0 ]
1145
+ ];
1146
+ });
1147
+
1148
+ // normalize collision option
1149
+ if ( collision.length === 1 ) {
1150
+ collision[ 1 ] = collision[ 0 ];
1151
+ }
1152
+
1153
+ if ( options.at[ 0 ] === "right" ) {
1154
+ basePosition.left += targetWidth;
1155
+ } else if ( options.at[ 0 ] === "center" ) {
1156
+ basePosition.left += targetWidth / 2;
1157
+ }
1158
+
1159
+ if ( options.at[ 1 ] === "bottom" ) {
1160
+ basePosition.top += targetHeight;
1161
+ } else if ( options.at[ 1 ] === "center" ) {
1162
+ basePosition.top += targetHeight / 2;
1163
+ }
1164
+
1165
+ atOffset = getOffsets( offsets.at, targetWidth, targetHeight );
1166
+ basePosition.left += atOffset[ 0 ];
1167
+ basePosition.top += atOffset[ 1 ];
1168
+
1169
+ return this.each(function() {
1170
+ var collisionPosition, using,
1171
+ elem = $( this ),
1172
+ elemWidth = elem.outerWidth(),
1173
+ elemHeight = elem.outerHeight(),
1174
+ marginLeft = parseCss( this, "marginLeft" ),
1175
+ marginTop = parseCss( this, "marginTop" ),
1176
+ collisionWidth = elemWidth + marginLeft + parseCss( this, "marginRight" ) + scrollInfo.width,
1177
+ collisionHeight = elemHeight + marginTop + parseCss( this, "marginBottom" ) + scrollInfo.height,
1178
+ position = $.extend( {}, basePosition ),
1179
+ myOffset = getOffsets( offsets.my, elem.outerWidth(), elem.outerHeight() );
1180
+
1181
+ if ( options.my[ 0 ] === "right" ) {
1182
+ position.left -= elemWidth;
1183
+ } else if ( options.my[ 0 ] === "center" ) {
1184
+ position.left -= elemWidth / 2;
1185
+ }
1186
+
1187
+ if ( options.my[ 1 ] === "bottom" ) {
1188
+ position.top -= elemHeight;
1189
+ } else if ( options.my[ 1 ] === "center" ) {
1190
+ position.top -= elemHeight / 2;
1191
+ }
1192
+
1193
+ position.left += myOffset[ 0 ];
1194
+ position.top += myOffset[ 1 ];
1195
+
1196
+ // if the browser doesn't support fractions, then round for consistent results
1197
+ if ( !$.support.offsetFractions ) {
1198
+ position.left = round( position.left );
1199
+ position.top = round( position.top );
1200
+ }
1201
+
1202
+ collisionPosition = {
1203
+ marginLeft: marginLeft,
1204
+ marginTop: marginTop
1205
+ };
1206
+
1207
+ $.each( [ "left", "top" ], function( i, dir ) {
1208
+ if ( $.ui.position[ collision[ i ] ] ) {
1209
+ $.ui.position[ collision[ i ] ][ dir ]( position, {
1210
+ targetWidth: targetWidth,
1211
+ targetHeight: targetHeight,
1212
+ elemWidth: elemWidth,
1213
+ elemHeight: elemHeight,
1214
+ collisionPosition: collisionPosition,
1215
+ collisionWidth: collisionWidth,
1216
+ collisionHeight: collisionHeight,
1217
+ offset: [ atOffset[ 0 ] + myOffset[ 0 ], atOffset [ 1 ] + myOffset[ 1 ] ],
1218
+ my: options.my,
1219
+ at: options.at,
1220
+ within: within,
1221
+ elem : elem
1222
+ });
1223
+ }
1224
+ });
1225
+
1226
+ if ( $.fn.bgiframe ) {
1227
+ elem.bgiframe();
1228
+ }
1229
+
1230
+ if ( options.using ) {
1231
+ // adds feedback as second argument to using callback, if present
1232
+ using = function( props ) {
1233
+ var left = targetOffset.left - position.left,
1234
+ right = left + targetWidth - elemWidth,
1235
+ top = targetOffset.top - position.top,
1236
+ bottom = top + targetHeight - elemHeight,
1237
+ feedback = {
1238
+ target: {
1239
+ element: target,
1240
+ left: targetOffset.left,
1241
+ top: targetOffset.top,
1242
+ width: targetWidth,
1243
+ height: targetHeight
1244
+ },
1245
+ element: {
1246
+ element: elem,
1247
+ left: position.left,
1248
+ top: position.top,
1249
+ width: elemWidth,
1250
+ height: elemHeight
1251
+ },
1252
+ horizontal: right < 0 ? "left" : left > 0 ? "right" : "center",
1253
+ vertical: bottom < 0 ? "top" : top > 0 ? "bottom" : "middle"
1254
+ };
1255
+ if ( targetWidth < elemWidth && abs( left + right ) < targetWidth ) {
1256
+ feedback.horizontal = "center";
1257
+ }
1258
+ if ( targetHeight < elemHeight && abs( top + bottom ) < targetHeight ) {
1259
+ feedback.vertical = "middle";
1260
+ }
1261
+ if ( max( abs( left ), abs( right ) ) > max( abs( top ), abs( bottom ) ) ) {
1262
+ feedback.important = "horizontal";
1263
+ } else {
1264
+ feedback.important = "vertical";
1265
+ }
1266
+ options.using.call( this, props, feedback );
1267
+ };
1268
+ }
1269
+
1270
+ elem.offset( $.extend( position, { using: using } ) );
1271
+ });
1272
+ };
1273
+
1274
+ $.ui.position = {
1275
+ fit: {
1276
+ left: function( position, data ) {
1277
+ var within = data.within,
1278
+ withinOffset = within.isWindow ? within.scrollLeft : within.offset.left,
1279
+ outerWidth = within.width,
1280
+ collisionPosLeft = position.left - data.collisionPosition.marginLeft,
1281
+ overLeft = withinOffset - collisionPosLeft,
1282
+ overRight = collisionPosLeft + data.collisionWidth - outerWidth - withinOffset,
1283
+ newOverRight;
1284
+
1285
+ // element is wider than within
1286
+ if ( data.collisionWidth > outerWidth ) {
1287
+ // element is initially over the left side of within
1288
+ if ( overLeft > 0 && overRight <= 0 ) {
1289
+ newOverRight = position.left + overLeft + data.collisionWidth - outerWidth - withinOffset;
1290
+ position.left += overLeft - newOverRight;
1291
+ // element is initially over right side of within
1292
+ } else if ( overRight > 0 && overLeft <= 0 ) {
1293
+ position.left = withinOffset;
1294
+ // element is initially over both left and right sides of within
1295
+ } else {
1296
+ if ( overLeft > overRight ) {
1297
+ position.left = withinOffset + outerWidth - data.collisionWidth;
1298
+ } else {
1299
+ position.left = withinOffset;
1300
+ }
1301
+ }
1302
+ // too far left -> align with left edge
1303
+ } else if ( overLeft > 0 ) {
1304
+ position.left += overLeft;
1305
+ // too far right -> align with right edge
1306
+ } else if ( overRight > 0 ) {
1307
+ position.left -= overRight;
1308
+ // adjust based on position and margin
1309
+ } else {
1310
+ position.left = max( position.left - collisionPosLeft, position.left );
1311
+ }
1312
+ },
1313
+ top: function( position, data ) {
1314
+ var within = data.within,
1315
+ withinOffset = within.isWindow ? within.scrollTop : within.offset.top,
1316
+ outerHeight = data.within.height,
1317
+ collisionPosTop = position.top - data.collisionPosition.marginTop,
1318
+ overTop = withinOffset - collisionPosTop,
1319
+ overBottom = collisionPosTop + data.collisionHeight - outerHeight - withinOffset,
1320
+ newOverBottom;
1321
+
1322
+ // element is taller than within
1323
+ if ( data.collisionHeight > outerHeight ) {
1324
+ // element is initially over the top of within
1325
+ if ( overTop > 0 && overBottom <= 0 ) {
1326
+ newOverBottom = position.top + overTop + data.collisionHeight - outerHeight - withinOffset;
1327
+ position.top += overTop - newOverBottom;
1328
+ // element is initially over bottom of within
1329
+ } else if ( overBottom > 0 && overTop <= 0 ) {
1330
+ position.top = withinOffset;
1331
+ // element is initially over both top and bottom of within
1332
+ } else {
1333
+ if ( overTop > overBottom ) {
1334
+ position.top = withinOffset + outerHeight - data.collisionHeight;
1335
+ } else {
1336
+ position.top = withinOffset;
1337
+ }
1338
+ }
1339
+ // too far up -> align with top
1340
+ } else if ( overTop > 0 ) {
1341
+ position.top += overTop;
1342
+ // too far down -> align with bottom edge
1343
+ } else if ( overBottom > 0 ) {
1344
+ position.top -= overBottom;
1345
+ // adjust based on position and margin
1346
+ } else {
1347
+ position.top = max( position.top - collisionPosTop, position.top );
1348
+ }
1349
+ }
1350
+ },
1351
+ flip: {
1352
+ left: function( position, data ) {
1353
+ var within = data.within,
1354
+ withinOffset = within.offset.left + within.scrollLeft,
1355
+ outerWidth = within.width,
1356
+ offsetLeft = within.isWindow ? within.scrollLeft : within.offset.left,
1357
+ collisionPosLeft = position.left - data.collisionPosition.marginLeft,
1358
+ overLeft = collisionPosLeft - offsetLeft,
1359
+ overRight = collisionPosLeft + data.collisionWidth - outerWidth - offsetLeft,
1360
+ myOffset = data.my[ 0 ] === "left" ?
1361
+ -data.elemWidth :
1362
+ data.my[ 0 ] === "right" ?
1363
+ data.elemWidth :
1364
+ 0,
1365
+ atOffset = data.at[ 0 ] === "left" ?
1366
+ data.targetWidth :
1367
+ data.at[ 0 ] === "right" ?
1368
+ -data.targetWidth :
1369
+ 0,
1370
+ offset = -2 * data.offset[ 0 ],
1371
+ newOverRight,
1372
+ newOverLeft;
1373
+
1374
+ if ( overLeft < 0 ) {
1375
+ newOverRight = position.left + myOffset + atOffset + offset + data.collisionWidth - outerWidth - withinOffset;
1376
+ if ( newOverRight < 0 || newOverRight < abs( overLeft ) ) {
1377
+ position.left += myOffset + atOffset + offset;
1378
+ }
1379
+ }
1380
+ else if ( overRight > 0 ) {
1381
+ newOverLeft = position.left - data.collisionPosition.marginLeft + myOffset + atOffset + offset - offsetLeft;
1382
+ if ( newOverLeft > 0 || abs( newOverLeft ) < overRight ) {
1383
+ position.left += myOffset + atOffset + offset;
1384
+ }
1385
+ }
1386
+ },
1387
+ top: function( position, data ) {
1388
+ var within = data.within,
1389
+ withinOffset = within.offset.top + within.scrollTop,
1390
+ outerHeight = within.height,
1391
+ offsetTop = within.isWindow ? within.scrollTop : within.offset.top,
1392
+ collisionPosTop = position.top - data.collisionPosition.marginTop,
1393
+ overTop = collisionPosTop - offsetTop,
1394
+ overBottom = collisionPosTop + data.collisionHeight - outerHeight - offsetTop,
1395
+ top = data.my[ 1 ] === "top",
1396
+ myOffset = top ?
1397
+ -data.elemHeight :
1398
+ data.my[ 1 ] === "bottom" ?
1399
+ data.elemHeight :
1400
+ 0,
1401
+ atOffset = data.at[ 1 ] === "top" ?
1402
+ data.targetHeight :
1403
+ data.at[ 1 ] === "bottom" ?
1404
+ -data.targetHeight :
1405
+ 0,
1406
+ offset = -2 * data.offset[ 1 ],
1407
+ newOverTop,
1408
+ newOverBottom;
1409
+ if ( overTop < 0 ) {
1410
+ newOverBottom = position.top + myOffset + atOffset + offset + data.collisionHeight - outerHeight - withinOffset;
1411
+ if ( ( position.top + myOffset + atOffset + offset) > overTop && ( newOverBottom < 0 || newOverBottom < abs( overTop ) ) ) {
1412
+ position.top += myOffset + atOffset + offset;
1413
+ }
1414
+ }
1415
+ else if ( overBottom > 0 ) {
1416
+ newOverTop = position.top - data.collisionPosition.marginTop + myOffset + atOffset + offset - offsetTop;
1417
+ if ( ( position.top + myOffset + atOffset + offset) > overBottom && ( newOverTop > 0 || abs( newOverTop ) < overBottom ) ) {
1418
+ position.top += myOffset + atOffset + offset;
1419
+ }
1420
+ }
1421
+ }
1422
+ },
1423
+ flipfit: {
1424
+ left: function() {
1425
+ $.ui.position.flip.left.apply( this, arguments );
1426
+ $.ui.position.fit.left.apply( this, arguments );
1427
+ },
1428
+ top: function() {
1429
+ $.ui.position.flip.top.apply( this, arguments );
1430
+ $.ui.position.fit.top.apply( this, arguments );
1431
+ }
1432
+ }
1433
+ };
1434
+
1435
+ // fraction support test
1436
+ (function () {
1437
+ var testElement, testElementParent, testElementStyle, offsetLeft, i,
1438
+ body = document.getElementsByTagName( "body" )[ 0 ],
1439
+ div = document.createElement( "div" );
1440
+
1441
+ //Create a "fake body" for testing based on method used in jQuery.support
1442
+ testElement = document.createElement( body ? "div" : "body" );
1443
+ testElementStyle = {
1444
+ visibility: "hidden",
1445
+ width: 0,
1446
+ height: 0,
1447
+ border: 0,
1448
+ margin: 0,
1449
+ background: "none"
1450
+ };
1451
+ if ( body ) {
1452
+ $.extend( testElementStyle, {
1453
+ position: "absolute",
1454
+ left: "-1000px",
1455
+ top: "-1000px"
1456
+ });
1457
+ }
1458
+ for ( i in testElementStyle ) {
1459
+ testElement.style[ i ] = testElementStyle[ i ];
1460
+ }
1461
+ testElement.appendChild( div );
1462
+ testElementParent = body || document.documentElement;
1463
+ testElementParent.insertBefore( testElement, testElementParent.firstChild );
1464
+
1465
+ div.style.cssText = "position: absolute; left: 10.7432222px;";
1466
+
1467
+ offsetLeft = $( div ).offset().left;
1468
+ $.support.offsetFractions = offsetLeft > 10 && offsetLeft < 11;
1469
+
1470
+ testElement.innerHTML = "";
1471
+ testElementParent.removeChild( testElement );
1472
+ })();
1473
+
1474
+ // DEPRECATED
1475
+ if ( $.uiBackCompat !== false ) {
1476
+ // offset option
1477
+ (function( $ ) {
1478
+ var _position = $.fn.position;
1479
+ $.fn.position = function( options ) {
1480
+ if ( !options || !options.offset ) {
1481
+ return _position.call( this, options );
1482
+ }
1483
+ var offset = options.offset.split( " " ),
1484
+ at = options.at.split( " " );
1485
+ if ( offset.length === 1 ) {
1486
+ offset[ 1 ] = offset[ 0 ];
1487
+ }
1488
+ if ( /^\d/.test( offset[ 0 ] ) ) {
1489
+ offset[ 0 ] = "+" + offset[ 0 ];
1490
+ }
1491
+ if ( /^\d/.test( offset[ 1 ] ) ) {
1492
+ offset[ 1 ] = "+" + offset[ 1 ];
1493
+ }
1494
+ if ( at.length === 1 ) {
1495
+ if ( /left|center|right/.test( at[ 0 ] ) ) {
1496
+ at[ 1 ] = "center";
1497
+ } else {
1498
+ at[ 1 ] = at[ 0 ];
1499
+ at[ 0 ] = "center";
1500
+ }
1501
+ }
1502
+ return _position.call( this, $.extend( options, {
1503
+ at: at[ 0 ] + offset[ 0 ] + " " + at[ 1 ] + offset[ 1 ],
1504
+ offset: undefined
1505
+ } ) );
1506
+ };
1507
+ }( jQuery ) );
1508
+ }
1509
+
1510
+ }( jQuery ) );
1511
+ (function( $, undefined ) {
1512
+
1513
+ var uid = 0,
1514
+ hideProps = {},
1515
+ showProps = {};
1516
+
1517
+ hideProps.height = hideProps.paddingTop = hideProps.paddingBottom =
1518
+ hideProps.borderTopWidth = hideProps.borderBottomWidth = "hide";
1519
+ showProps.height = showProps.paddingTop = showProps.paddingBottom =
1520
+ showProps.borderTopWidth = showProps.borderBottomWidth = "show";
1521
+
1522
+ $.widget( "ui.accordion", {
1523
+ version: "1.9.1",
1524
+ options: {
1525
+ active: 0,
1526
+ animate: {},
1527
+ collapsible: false,
1528
+ event: "click",
1529
+ header: "> li > :first-child,> :not(li):even",
1530
+ heightStyle: "auto",
1531
+ icons: {
1532
+ activeHeader: "ui-icon-triangle-1-s",
1533
+ header: "ui-icon-triangle-1-e"
1534
+ },
1535
+
1536
+ // callbacks
1537
+ activate: null,
1538
+ beforeActivate: null
1539
+ },
1540
+
1541
+ _create: function() {
1542
+ var accordionId = this.accordionId = "ui-accordion-" +
1543
+ (this.element.attr( "id" ) || ++uid),
1544
+ options = this.options;
1545
+
1546
+ this.prevShow = this.prevHide = $();
1547
+ this.element.addClass( "ui-accordion ui-widget ui-helper-reset" );
1548
+
1549
+ this.headers = this.element.find( options.header )
1550
+ .addClass( "ui-accordion-header ui-helper-reset ui-state-default ui-corner-all" );
1551
+ this._hoverable( this.headers );
1552
+ this._focusable( this.headers );
1553
+
1554
+ this.headers.next()
1555
+ .addClass( "ui-accordion-content ui-helper-reset ui-widget-content ui-corner-bottom" )
1556
+ .hide();
1557
+
1558
+ // don't allow collapsible: false and active: false / null
1559
+ if ( !options.collapsible && (options.active === false || options.active == null) ) {
1560
+ options.active = 0;
1561
+ }
1562
+ // handle negative values
1563
+ if ( options.active < 0 ) {
1564
+ options.active += this.headers.length;
1565
+ }
1566
+ this.active = this._findActive( options.active )
1567
+ .addClass( "ui-accordion-header-active ui-state-active" )
1568
+ .toggleClass( "ui-corner-all ui-corner-top" );
1569
+ this.active.next()
1570
+ .addClass( "ui-accordion-content-active" )
1571
+ .show();
1572
+
1573
+ this._createIcons();
1574
+ this.refresh();
1575
+
1576
+ // ARIA
1577
+ this.element.attr( "role", "tablist" );
1578
+
1579
+ this.headers
1580
+ .attr( "role", "tab" )
1581
+ .each(function( i ) {
1582
+ var header = $( this ),
1583
+ headerId = header.attr( "id" ),
1584
+ panel = header.next(),
1585
+ panelId = panel.attr( "id" );
1586
+ if ( !headerId ) {
1587
+ headerId = accordionId + "-header-" + i;
1588
+ header.attr( "id", headerId );
1589
+ }
1590
+ if ( !panelId ) {
1591
+ panelId = accordionId + "-panel-" + i;
1592
+ panel.attr( "id", panelId );
1593
+ }
1594
+ header.attr( "aria-controls", panelId );
1595
+ panel.attr( "aria-labelledby", headerId );
1596
+ })
1597
+ .next()
1598
+ .attr( "role", "tabpanel" );
1599
+
1600
+ this.headers
1601
+ .not( this.active )
1602
+ .attr({
1603
+ "aria-selected": "false",
1604
+ tabIndex: -1
1605
+ })
1606
+ .next()
1607
+ .attr({
1608
+ "aria-expanded": "false",
1609
+ "aria-hidden": "true"
1610
+ })
1611
+ .hide();
1612
+
1613
+ // make sure at least one header is in the tab order
1614
+ if ( !this.active.length ) {
1615
+ this.headers.eq( 0 ).attr( "tabIndex", 0 );
1616
+ } else {
1617
+ this.active.attr({
1618
+ "aria-selected": "true",
1619
+ tabIndex: 0
1620
+ })
1621
+ .next()
1622
+ .attr({
1623
+ "aria-expanded": "true",
1624
+ "aria-hidden": "false"
1625
+ });
1626
+ }
1627
+
1628
+ this._on( this.headers, { keydown: "_keydown" });
1629
+ this._on( this.headers.next(), { keydown: "_panelKeyDown" });
1630
+ this._setupEvents( options.event );
1631
+ },
1632
+
1633
+ _getCreateEventData: function() {
1634
+ return {
1635
+ header: this.active,
1636
+ content: !this.active.length ? $() : this.active.next()
1637
+ };
1638
+ },
1639
+
1640
+ _createIcons: function() {
1641
+ var icons = this.options.icons;
1642
+ if ( icons ) {
1643
+ $( "<span>" )
1644
+ .addClass( "ui-accordion-header-icon ui-icon " + icons.header )
1645
+ .prependTo( this.headers );
1646
+ this.active.children( ".ui-accordion-header-icon" )
1647
+ .removeClass( icons.header )
1648
+ .addClass( icons.activeHeader );
1649
+ this.headers.addClass( "ui-accordion-icons" );
1650
+ }
1651
+ },
1652
+
1653
+ _destroyIcons: function() {
1654
+ this.headers
1655
+ .removeClass( "ui-accordion-icons" )
1656
+ .children( ".ui-accordion-header-icon" )
1657
+ .remove();
1658
+ },
1659
+
1660
+ _destroy: function() {
1661
+ var contents;
1662
+
1663
+ // clean up main element
1664
+ this.element
1665
+ .removeClass( "ui-accordion ui-widget ui-helper-reset" )
1666
+ .removeAttr( "role" );
1667
+
1668
+ // clean up headers
1669
+ this.headers
1670
+ .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" )
1671
+ .removeAttr( "role" )
1672
+ .removeAttr( "aria-selected" )
1673
+ .removeAttr( "aria-controls" )
1674
+ .removeAttr( "tabIndex" )
1675
+ .each(function() {
1676
+ if ( /^ui-accordion/.test( this.id ) ) {
1677
+ this.removeAttribute( "id" );
1678
+ }
1679
+ });
1680
+ this._destroyIcons();
1681
+
1682
+ // clean up content panels
1683
+ contents = this.headers.next()
1684
+ .css( "display", "" )
1685
+ .removeAttr( "role" )
1686
+ .removeAttr( "aria-expanded" )
1687
+ .removeAttr( "aria-hidden" )
1688
+ .removeAttr( "aria-labelledby" )
1689
+ .removeClass( "ui-helper-reset ui-widget-content ui-corner-bottom ui-accordion-content ui-accordion-content-active ui-state-disabled" )
1690
+ .each(function() {
1691
+ if ( /^ui-accordion/.test( this.id ) ) {
1692
+ this.removeAttribute( "id" );
1693
+ }
1694
+ });
1695
+ if ( this.options.heightStyle !== "content" ) {
1696
+ contents.css( "height", "" );
1697
+ }
1698
+ },
1699
+
1700
+ _setOption: function( key, value ) {
1701
+ if ( key === "active" ) {
1702
+ // _activate() will handle invalid values and update this.options
1703
+ this._activate( value );
1704
+ return;
1705
+ }
1706
+
1707
+ if ( key === "event" ) {
1708
+ if ( this.options.event ) {
1709
+ this._off( this.headers, this.options.event );
1710
+ }
1711
+ this._setupEvents( value );
1712
+ }
1713
+
1714
+ this._super( key, value );
1715
+
1716
+ // setting collapsible: false while collapsed; open first panel
1717
+ if ( key === "collapsible" && !value && this.options.active === false ) {
1718
+ this._activate( 0 );
1719
+ }
1720
+
1721
+ if ( key === "icons" ) {
1722
+ this._destroyIcons();
1723
+ if ( value ) {
1724
+ this._createIcons();
1725
+ }
1726
+ }
1727
+
1728
+ // #5332 - opacity doesn't cascade to positioned elements in IE
1729
+ // so we need to add the disabled class to the headers and panels
1730
+ if ( key === "disabled" ) {
1731
+ this.headers.add( this.headers.next() )
1732
+ .toggleClass( "ui-state-disabled", !!value );
1733
+ }
1734
+ },
1735
+
1736
+ _keydown: function( event ) {
1737
+ if ( event.altKey || event.ctrlKey ) {
1738
+ return;
1739
+ }
1740
+
1741
+ var keyCode = $.ui.keyCode,
1742
+ length = this.headers.length,
1743
+ currentIndex = this.headers.index( event.target ),
1744
+ toFocus = false;
1745
+
1746
+ switch ( event.keyCode ) {
1747
+ case keyCode.RIGHT:
1748
+ case keyCode.DOWN:
1749
+ toFocus = this.headers[ ( currentIndex + 1 ) % length ];
1750
+ break;
1751
+ case keyCode.LEFT:
1752
+ case keyCode.UP:
1753
+ toFocus = this.headers[ ( currentIndex - 1 + length ) % length ];
1754
+ break;
1755
+ case keyCode.SPACE:
1756
+ case keyCode.ENTER:
1757
+ this._eventHandler( event );
1758
+ break;
1759
+ case keyCode.HOME:
1760
+ toFocus = this.headers[ 0 ];
1761
+ break;
1762
+ case keyCode.END:
1763
+ toFocus = this.headers[ length - 1 ];
1764
+ break;
1765
+ }
1766
+
1767
+ if ( toFocus ) {
1768
+ $( event.target ).attr( "tabIndex", -1 );
1769
+ $( toFocus ).attr( "tabIndex", 0 );
1770
+ toFocus.focus();
1771
+ event.preventDefault();
1772
+ }
1773
+ },
1774
+
1775
+ _panelKeyDown : function( event ) {
1776
+ if ( event.keyCode === $.ui.keyCode.UP && event.ctrlKey ) {
1777
+ $( event.currentTarget ).prev().focus();
1778
+ }
1779
+ },
1780
+
1781
+ refresh: function() {
1782
+ var maxHeight, overflow,
1783
+ heightStyle = this.options.heightStyle,
1784
+ parent = this.element.parent();
1785
+
1786
+
1787
+ if ( heightStyle === "fill" ) {
1788
+ // IE 6 treats height like minHeight, so we need to turn off overflow
1789
+ // in order to get a reliable height
1790
+ // we use the minHeight support test because we assume that only
1791
+ // browsers that don't support minHeight will treat height as minHeight
1792
+ if ( !$.support.minHeight ) {
1793
+ overflow = parent.css( "overflow" );
1794
+ parent.css( "overflow", "hidden");
1795
+ }
1796
+ maxHeight = parent.height();
1797
+ this.element.siblings( ":visible" ).each(function() {
1798
+ var elem = $( this ),
1799
+ position = elem.css( "position" );
1800
+
1801
+ if ( position === "absolute" || position === "fixed" ) {
1802
+ return;
1803
+ }
1804
+ maxHeight -= elem.outerHeight( true );
1805
+ });
1806
+ if ( overflow ) {
1807
+ parent.css( "overflow", overflow );
1808
+ }
1809
+
1810
+ this.headers.each(function() {
1811
+ maxHeight -= $( this ).outerHeight( true );
1812
+ });
1813
+
1814
+ this.headers.next()
1815
+ .each(function() {
1816
+ $( this ).height( Math.max( 0, maxHeight -
1817
+ $( this ).innerHeight() + $( this ).height() ) );
1818
+ })
1819
+ .css( "overflow", "auto" );
1820
+ } else if ( heightStyle === "auto" ) {
1821
+ maxHeight = 0;
1822
+ this.headers.next()
1823
+ .each(function() {
1824
+ maxHeight = Math.max( maxHeight, $( this ).height( "" ).height() );
1825
+ })
1826
+ .height( maxHeight );
1827
+ }
1828
+ },
1829
+
1830
+ _activate: function( index ) {
1831
+ var active = this._findActive( index )[ 0 ];
1832
+
1833
+ // trying to activate the already active panel
1834
+ if ( active === this.active[ 0 ] ) {
1835
+ return;
1836
+ }
1837
+
1838
+ // trying to collapse, simulate a click on the currently active header
1839
+ active = active || this.active[ 0 ];
1840
+
1841
+ this._eventHandler({
1842
+ target: active,
1843
+ currentTarget: active,
1844
+ preventDefault: $.noop
1845
+ });
1846
+ },
1847
+
1848
+ _findActive: function( selector ) {
1849
+ return typeof selector === "number" ? this.headers.eq( selector ) : $();
1850
+ },
1851
+
1852
+ _setupEvents: function( event ) {
1853
+ var events = {};
1854
+ if ( !event ) {
1855
+ return;
1856
+ }
1857
+ $.each( event.split(" "), function( index, eventName ) {
1858
+ events[ eventName ] = "_eventHandler";
1859
+ });
1860
+ this._on( this.headers, events );
1861
+ },
1862
+
1863
+ _eventHandler: function( event ) {
1864
+ var options = this.options,
1865
+ active = this.active,
1866
+ clicked = $( event.currentTarget ),
1867
+ clickedIsActive = clicked[ 0 ] === active[ 0 ],
1868
+ collapsing = clickedIsActive && options.collapsible,
1869
+ toShow = collapsing ? $() : clicked.next(),
1870
+ toHide = active.next(),
1871
+ eventData = {
1872
+ oldHeader: active,
1873
+ oldPanel: toHide,
1874
+ newHeader: collapsing ? $() : clicked,
1875
+ newPanel: toShow
1876
+ };
1877
+
1878
+ event.preventDefault();
1879
+
1880
+ if (
1881
+ // click on active header, but not collapsible
1882
+ ( clickedIsActive && !options.collapsible ) ||
1883
+ // allow canceling activation
1884
+ ( this._trigger( "beforeActivate", event, eventData ) === false ) ) {
1885
+ return;
1886
+ }
1887
+
1888
+ options.active = collapsing ? false : this.headers.index( clicked );
1889
+
1890
+ // when the call to ._toggle() comes after the class changes
1891
+ // it causes a very odd bug in IE 8 (see #6720)
1892
+ this.active = clickedIsActive ? $() : clicked;
1893
+ this._toggle( eventData );
1894
+
1895
+ // switch classes
1896
+ // corner classes on the previously active header stay after the animation
1897
+ active.removeClass( "ui-accordion-header-active ui-state-active" );
1898
+ if ( options.icons ) {
1899
+ active.children( ".ui-accordion-header-icon" )
1900
+ .removeClass( options.icons.activeHeader )
1901
+ .addClass( options.icons.header );
1902
+ }
1903
+
1904
+ if ( !clickedIsActive ) {
1905
+ clicked
1906
+ .removeClass( "ui-corner-all" )
1907
+ .addClass( "ui-accordion-header-active ui-state-active ui-corner-top" );
1908
+ if ( options.icons ) {
1909
+ clicked.children( ".ui-accordion-header-icon" )
1910
+ .removeClass( options.icons.header )
1911
+ .addClass( options.icons.activeHeader );
1912
+ }
1913
+
1914
+ clicked
1915
+ .next()
1916
+ .addClass( "ui-accordion-content-active" );
1917
+ }
1918
+ },
1919
+
1920
+ _toggle: function( data ) {
1921
+ var toShow = data.newPanel,
1922
+ toHide = this.prevShow.length ? this.prevShow : data.oldPanel;
1923
+
1924
+ // handle activating a panel during the animation for another activation
1925
+ this.prevShow.add( this.prevHide ).stop( true, true );
1926
+ this.prevShow = toShow;
1927
+ this.prevHide = toHide;
1928
+
1929
+ if ( this.options.animate ) {
1930
+ this._animate( toShow, toHide, data );
1931
+ } else {
1932
+ toHide.hide();
1933
+ toShow.show();
1934
+ this._toggleComplete( data );
1935
+ }
1936
+
1937
+ toHide.attr({
1938
+ "aria-expanded": "false",
1939
+ "aria-hidden": "true"
1940
+ });
1941
+ toHide.prev().attr( "aria-selected", "false" );
1942
+ // if we're switching panels, remove the old header from the tab order
1943
+ // if we're opening from collapsed state, remove the previous header from the tab order
1944
+ // if we're collapsing, then keep the collapsing header in the tab order
1945
+ if ( toShow.length && toHide.length ) {
1946
+ toHide.prev().attr( "tabIndex", -1 );
1947
+ } else if ( toShow.length ) {
1948
+ this.headers.filter(function() {
1949
+ return $( this ).attr( "tabIndex" ) === 0;
1950
+ })
1951
+ .attr( "tabIndex", -1 );
1952
+ }
1953
+
1954
+ toShow
1955
+ .attr({
1956
+ "aria-expanded": "true",
1957
+ "aria-hidden": "false"
1958
+ })
1959
+ .prev()
1960
+ .attr({
1961
+ "aria-selected": "true",
1962
+ tabIndex: 0
1963
+ });
1964
+ },
1965
+
1966
+ _animate: function( toShow, toHide, data ) {
1967
+ var total, easing, duration,
1968
+ that = this,
1969
+ adjust = 0,
1970
+ down = toShow.length &&
1971
+ ( !toHide.length || ( toShow.index() < toHide.index() ) ),
1972
+ animate = this.options.animate || {},
1973
+ options = down && animate.down || animate,
1974
+ complete = function() {
1975
+ that._toggleComplete( data );
1976
+ };
1977
+
1978
+ if ( typeof options === "number" ) {
1979
+ duration = options;
1980
+ }
1981
+ if ( typeof options === "string" ) {
1982
+ easing = options;
1983
+ }
1984
+ // fall back from options to animation in case of partial down settings
1985
+ easing = easing || options.easing || animate.easing;
1986
+ duration = duration || options.duration || animate.duration;
1987
+
1988
+ if ( !toHide.length ) {
1989
+ return toShow.animate( showProps, duration, easing, complete );
1990
+ }
1991
+ if ( !toShow.length ) {
1992
+ return toHide.animate( hideProps, duration, easing, complete );
1993
+ }
1994
+
1995
+ total = toShow.show().outerHeight();
1996
+ toHide.animate( hideProps, {
1997
+ duration: duration,
1998
+ easing: easing,
1999
+ step: function( now, fx ) {
2000
+ fx.now = Math.round( now );
2001
+ }
2002
+ });
2003
+ toShow
2004
+ .hide()
2005
+ .animate( showProps, {
2006
+ duration: duration,
2007
+ easing: easing,
2008
+ complete: complete,
2009
+ step: function( now, fx ) {
2010
+ fx.now = Math.round( now );
2011
+ if ( fx.prop !== "height" ) {
2012
+ adjust += fx.now;
2013
+ } else if ( that.options.heightStyle !== "content" ) {
2014
+ fx.now = Math.round( total - toHide.outerHeight() - adjust );
2015
+ adjust = 0;
2016
+ }
2017
+ }
2018
+ });
2019
+ },
2020
+
2021
+ _toggleComplete: function( data ) {
2022
+ var toHide = data.oldPanel;
2023
+
2024
+ toHide
2025
+ .removeClass( "ui-accordion-content-active" )
2026
+ .prev()
2027
+ .removeClass( "ui-corner-top" )
2028
+ .addClass( "ui-corner-all" );
2029
+
2030
+ // Work around for rendering bug in IE (#5421)
2031
+ if ( toHide.length ) {
2032
+ toHide.parent()[0].className = toHide.parent()[0].className;
2033
+ }
2034
+
2035
+ this._trigger( "activate", null, data );
2036
+ }
2037
+ });
2038
+
2039
+
2040
+
2041
+ // DEPRECATED
2042
+ if ( $.uiBackCompat !== false ) {
2043
+ // navigation options
2044
+ (function( $, prototype ) {
2045
+ $.extend( prototype.options, {
2046
+ navigation: false,
2047
+ navigationFilter: function() {
2048
+ return this.href.toLowerCase() === location.href.toLowerCase();
2049
+ }
2050
+ });
2051
+
2052
+ var _create = prototype._create;
2053
+ prototype._create = function() {
2054
+ if ( this.options.navigation ) {
2055
+ var that = this,
2056
+ headers = this.element.find( this.options.header ),
2057
+ content = headers.next(),
2058
+ current = headers.add( content )
2059
+ .find( "a" )
2060
+ .filter( this.options.navigationFilter )
2061
+ [ 0 ];
2062
+ if ( current ) {
2063
+ headers.add( content ).each( function( index ) {
2064
+ if ( $.contains( this, current ) ) {
2065
+ that.options.active = Math.floor( index / 2 );
2066
+ return false;
2067
+ }
2068
+ });
2069
+ }
2070
+ }
2071
+ _create.call( this );
2072
+ };
2073
+ }( jQuery, jQuery.ui.accordion.prototype ) );
2074
+
2075
+ // height options
2076
+ (function( $, prototype ) {
2077
+ $.extend( prototype.options, {
2078
+ heightStyle: null, // remove default so we fall back to old values
2079
+ autoHeight: true, // use heightStyle: "auto"
2080
+ clearStyle: false, // use heightStyle: "content"
2081
+ fillSpace: false // use heightStyle: "fill"
2082
+ });
2083
+
2084
+ var _create = prototype._create,
2085
+ _setOption = prototype._setOption;
2086
+
2087
+ $.extend( prototype, {
2088
+ _create: function() {
2089
+ this.options.heightStyle = this.options.heightStyle ||
2090
+ this._mergeHeightStyle();
2091
+
2092
+ _create.call( this );
2093
+ },
2094
+
2095
+ _setOption: function( key ) {
2096
+ if ( key === "autoHeight" || key === "clearStyle" || key === "fillSpace" ) {
2097
+ this.options.heightStyle = this._mergeHeightStyle();
2098
+ }
2099
+ _setOption.apply( this, arguments );
2100
+ },
2101
+
2102
+ _mergeHeightStyle: function() {
2103
+ var options = this.options;
2104
+
2105
+ if ( options.fillSpace ) {
2106
+ return "fill";
2107
+ }
2108
+
2109
+ if ( options.clearStyle ) {
2110
+ return "content";
2111
+ }
2112
+
2113
+ if ( options.autoHeight ) {
2114
+ return "auto";
2115
+ }
2116
+ }
2117
+ });
2118
+ }( jQuery, jQuery.ui.accordion.prototype ) );
2119
+
2120
+ // icon options
2121
+ (function( $, prototype ) {
2122
+ $.extend( prototype.options.icons, {
2123
+ activeHeader: null, // remove default so we fall back to old values
2124
+ headerSelected: "ui-icon-triangle-1-s"
2125
+ });
2126
+
2127
+ var _createIcons = prototype._createIcons;
2128
+ prototype._createIcons = function() {
2129
+ if ( this.options.icons ) {
2130
+ this.options.icons.activeHeader = this.options.icons.activeHeader ||
2131
+ this.options.icons.headerSelected;
2132
+ }
2133
+ _createIcons.call( this );
2134
+ };
2135
+ }( jQuery, jQuery.ui.accordion.prototype ) );
2136
+
2137
+ // expanded active option, activate method
2138
+ (function( $, prototype ) {
2139
+ prototype.activate = prototype._activate;
2140
+
2141
+ var _findActive = prototype._findActive;
2142
+ prototype._findActive = function( index ) {
2143
+ if ( index === -1 ) {
2144
+ index = false;
2145
+ }
2146
+ if ( index && typeof index !== "number" ) {
2147
+ index = this.headers.index( this.headers.filter( index ) );
2148
+ if ( index === -1 ) {
2149
+ index = false;
2150
+ }
2151
+ }
2152
+ return _findActive.call( this, index );
2153
+ };
2154
+ }( jQuery, jQuery.ui.accordion.prototype ) );
2155
+
2156
+ // resize method
2157
+ jQuery.ui.accordion.prototype.resize = jQuery.ui.accordion.prototype.refresh;
2158
+
2159
+ // change events
2160
+ (function( $, prototype ) {
2161
+ $.extend( prototype.options, {
2162
+ change: null,
2163
+ changestart: null
2164
+ });
2165
+
2166
+ var _trigger = prototype._trigger;
2167
+ prototype._trigger = function( type, event, data ) {
2168
+ var ret = _trigger.apply( this, arguments );
2169
+ if ( !ret ) {
2170
+ return false;
2171
+ }
2172
+
2173
+ if ( type === "beforeActivate" ) {
2174
+ ret = _trigger.call( this, "changestart", event, {
2175
+ oldHeader: data.oldHeader,
2176
+ oldContent: data.oldPanel,
2177
+ newHeader: data.newHeader,
2178
+ newContent: data.newPanel
2179
+ });
2180
+ } else if ( type === "activate" ) {
2181
+ ret = _trigger.call( this, "change", event, {
2182
+ oldHeader: data.oldHeader,
2183
+ oldContent: data.oldPanel,
2184
+ newHeader: data.newHeader,
2185
+ newContent: data.newPanel
2186
+ });
2187
+ }
2188
+ return ret;
2189
+ };
2190
+ }( jQuery, jQuery.ui.accordion.prototype ) );
2191
+
2192
+ // animated option
2193
+ // NOTE: this only provides support for "slide", "bounceslide", and easings
2194
+ // not the full $.ui.accordion.animations API
2195
+ (function( $, prototype ) {
2196
+ $.extend( prototype.options, {
2197
+ animate: null,
2198
+ animated: "slide"
2199
+ });
2200
+
2201
+ var _create = prototype._create;
2202
+ prototype._create = function() {
2203
+ var options = this.options;
2204
+ if ( options.animate === null ) {
2205
+ if ( !options.animated ) {
2206
+ options.animate = false;
2207
+ } else if ( options.animated === "slide" ) {
2208
+ options.animate = 300;
2209
+ } else if ( options.animated === "bounceslide" ) {
2210
+ options.animate = {
2211
+ duration: 200,
2212
+ down: {
2213
+ easing: "easeOutBounce",
2214
+ duration: 1000
2215
+ }
2216
+ };
2217
+ } else {
2218
+ options.animate = options.animated;
2219
+ }
2220
+ }
2221
+
2222
+ _create.call( this );
2223
+ };
2224
+ }( jQuery, jQuery.ui.accordion.prototype ) );
2225
+ }
2226
+
2227
+ })( jQuery );
2228
+ (function( $, undefined ) {
2229
+
2230
+ // used to prevent race conditions with remote data sources
2231
+ var requestIndex = 0;
2232
+
2233
+ $.widget( "ui.autocomplete", {
2234
+ version: "1.9.1",
2235
+ defaultElement: "<input>",
2236
+ options: {
2237
+ appendTo: "body",
2238
+ autoFocus: false,
2239
+ delay: 300,
2240
+ minLength: 1,
2241
+ position: {
2242
+ my: "left top",
2243
+ at: "left bottom",
2244
+ collision: "none"
2245
+ },
2246
+ source: null,
2247
+
2248
+ // callbacks
2249
+ change: null,
2250
+ close: null,
2251
+ focus: null,
2252
+ open: null,
2253
+ response: null,
2254
+ search: null,
2255
+ select: null
2256
+ },
2257
+
2258
+ pending: 0,
2259
+
2260
+ _create: function() {
2261
+ // Some browsers only repeat keydown events, not keypress events,
2262
+ // so we use the suppressKeyPress flag to determine if we've already
2263
+ // handled the keydown event. #7269
2264
+ // Unfortunately the code for & in keypress is the same as the up arrow,
2265
+ // so we use the suppressKeyPressRepeat flag to avoid handling keypress
2266
+ // events when we know the keydown event was used to modify the
2267
+ // search term. #7799
2268
+ var suppressKeyPress, suppressKeyPressRepeat, suppressInput;
2269
+
2270
+ this.isMultiLine = this._isMultiLine();
2271
+ this.valueMethod = this.element[ this.element.is( "input,textarea" ) ? "val" : "text" ];
2272
+ this.isNewMenu = true;
2273
+
2274
+ this.element
2275
+ .addClass( "ui-autocomplete-input" )
2276
+ .attr( "autocomplete", "off" );
2277
+
2278
+ this._on( this.element, {
2279
+ keydown: function( event ) {
2280
+ if ( this.element.prop( "readOnly" ) ) {
2281
+ suppressKeyPress = true;
2282
+ suppressInput = true;
2283
+ suppressKeyPressRepeat = true;
2284
+ return;
2285
+ }
2286
+
2287
+ suppressKeyPress = false;
2288
+ suppressInput = false;
2289
+ suppressKeyPressRepeat = false;
2290
+ var keyCode = $.ui.keyCode;
2291
+ switch( event.keyCode ) {
2292
+ case keyCode.PAGE_UP:
2293
+ suppressKeyPress = true;
2294
+ this._move( "previousPage", event );
2295
+ break;
2296
+ case keyCode.PAGE_DOWN:
2297
+ suppressKeyPress = true;
2298
+ this._move( "nextPage", event );
2299
+ break;
2300
+ case keyCode.UP:
2301
+ suppressKeyPress = true;
2302
+ this._keyEvent( "previous", event );
2303
+ break;
2304
+ case keyCode.DOWN:
2305
+ suppressKeyPress = true;
2306
+ this._keyEvent( "next", event );
2307
+ break;
2308
+ case keyCode.ENTER:
2309
+ case keyCode.NUMPAD_ENTER:
2310
+ // when menu is open and has focus
2311
+ if ( this.menu.active ) {
2312
+ // #6055 - Opera still allows the keypress to occur
2313
+ // which causes forms to submit
2314
+ suppressKeyPress = true;
2315
+ event.preventDefault();
2316
+ this.menu.select( event );
2317
+ }
2318
+ break;
2319
+ case keyCode.TAB:
2320
+ if ( this.menu.active ) {
2321
+ this.menu.select( event );
2322
+ }
2323
+ break;
2324
+ case keyCode.ESCAPE:
2325
+ if ( this.menu.element.is( ":visible" ) ) {
2326
+ this._value( this.term );
2327
+ this.close( event );
2328
+ // Different browsers have different default behavior for escape
2329
+ // Single press can mean undo or clear
2330
+ // Double press in IE means clear the whole form
2331
+ event.preventDefault();
2332
+ }
2333
+ break;
2334
+ default:
2335
+ suppressKeyPressRepeat = true;
2336
+ // search timeout should be triggered before the input value is changed
2337
+ this._searchTimeout( event );
2338
+ break;
2339
+ }
2340
+ },
2341
+ keypress: function( event ) {
2342
+ if ( suppressKeyPress ) {
2343
+ suppressKeyPress = false;
2344
+ event.preventDefault();
2345
+ return;
2346
+ }
2347
+ if ( suppressKeyPressRepeat ) {
2348
+ return;
2349
+ }
2350
+
2351
+ // replicate some key handlers to allow them to repeat in Firefox and Opera
2352
+ var keyCode = $.ui.keyCode;
2353
+ switch( event.keyCode ) {
2354
+ case keyCode.PAGE_UP:
2355
+ this._move( "previousPage", event );
2356
+ break;
2357
+ case keyCode.PAGE_DOWN:
2358
+ this._move( "nextPage", event );
2359
+ break;
2360
+ case keyCode.UP:
2361
+ this._keyEvent( "previous", event );
2362
+ break;
2363
+ case keyCode.DOWN:
2364
+ this._keyEvent( "next", event );
2365
+ break;
2366
+ }
2367
+ },
2368
+ input: function( event ) {
2369
+ if ( suppressInput ) {
2370
+ suppressInput = false;
2371
+ event.preventDefault();
2372
+ return;
2373
+ }
2374
+ this._searchTimeout( event );
2375
+ },
2376
+ focus: function() {
2377
+ this.selectedItem = null;
2378
+ this.previous = this._value();
2379
+ },
2380
+ blur: function( event ) {
2381
+ if ( this.cancelBlur ) {
2382
+ delete this.cancelBlur;
2383
+ return;
2384
+ }
2385
+
2386
+ clearTimeout( this.searching );
2387
+ this.close( event );
2388
+ this._change( event );
2389
+ }
2390
+ });
2391
+
2392
+ this._initSource();
2393
+ this.menu = $( "<ul>" )
2394
+ .addClass( "ui-autocomplete" )
2395
+ .appendTo( this.document.find( this.options.appendTo || "body" )[ 0 ] )
2396
+ .menu({
2397
+ // custom key handling for now
2398
+ input: $(),
2399
+ // disable ARIA support, the live region takes care of that
2400
+ role: null
2401
+ })
2402
+ .zIndex( this.element.zIndex() + 1 )
2403
+ .hide()
2404
+ .data( "menu" );
2405
+
2406
+ this._on( this.menu.element, {
2407
+ mousedown: function( event ) {
2408
+ // prevent moving focus out of the text field
2409
+ event.preventDefault();
2410
+
2411
+ // IE doesn't prevent moving focus even with event.preventDefault()
2412
+ // so we set a flag to know when we should ignore the blur event
2413
+ this.cancelBlur = true;
2414
+ this._delay(function() {
2415
+ delete this.cancelBlur;
2416
+ });
2417
+
2418
+ // clicking on the scrollbar causes focus to shift to the body
2419
+ // but we can't detect a mouseup or a click immediately afterward
2420
+ // so we have to track the next mousedown and close the menu if
2421
+ // the user clicks somewhere outside of the autocomplete
2422
+ var menuElement = this.menu.element[ 0 ];
2423
+ if ( !$( event.target ).closest( ".ui-menu-item" ).length ) {
2424
+ this._delay(function() {
2425
+ var that = this;
2426
+ this.document.one( "mousedown", function( event ) {
2427
+ if ( event.target !== that.element[ 0 ] &&
2428
+ event.target !== menuElement &&
2429
+ !$.contains( menuElement, event.target ) ) {
2430
+ that.close();
2431
+ }
2432
+ });
2433
+ });
2434
+ }
2435
+ },
2436
+ menufocus: function( event, ui ) {
2437
+ // #7024 - Prevent accidental activation of menu items in Firefox
2438
+ if ( this.isNewMenu ) {
2439
+ this.isNewMenu = false;
2440
+ if ( event.originalEvent && /^mouse/.test( event.originalEvent.type ) ) {
2441
+ this.menu.blur();
2442
+
2443
+ this.document.one( "mousemove", function() {
2444
+ $( event.target ).trigger( event.originalEvent );
2445
+ });
2446
+
2447
+ return;
2448
+ }
2449
+ }
2450
+
2451
+ // back compat for _renderItem using item.autocomplete, via #7810
2452
+ // TODO remove the fallback, see #8156
2453
+ var item = ui.item.data( "ui-autocomplete-item" ) || ui.item.data( "item.autocomplete" );
2454
+ if ( false !== this._trigger( "focus", event, { item: item } ) ) {
2455
+ // use value to match what will end up in the input, if it was a key event
2456
+ if ( event.originalEvent && /^key/.test( event.originalEvent.type ) ) {
2457
+ this._value( item.value );
2458
+ }
2459
+ } else {
2460
+ // Normally the input is populated with the item's value as the
2461
+ // menu is navigated, causing screen readers to notice a change and
2462
+ // announce the item. Since the focus event was canceled, this doesn't
2463
+ // happen, so we update the live region so that screen readers can
2464
+ // still notice the change and announce it.
2465
+ this.liveRegion.text( item.value );
2466
+ }
2467
+ },
2468
+ menuselect: function( event, ui ) {
2469
+ // back compat for _renderItem using item.autocomplete, via #7810
2470
+ // TODO remove the fallback, see #8156
2471
+ var item = ui.item.data( "ui-autocomplete-item" ) || ui.item.data( "item.autocomplete" ),
2472
+ previous = this.previous;
2473
+
2474
+ // only trigger when focus was lost (click on menu)
2475
+ if ( this.element[0] !== this.document[0].activeElement ) {
2476
+ this.element.focus();
2477
+ this.previous = previous;
2478
+ // #6109 - IE triggers two focus events and the second
2479
+ // is asynchronous, so we need to reset the previous
2480
+ // term synchronously and asynchronously :-(
2481
+ this._delay(function() {
2482
+ this.previous = previous;
2483
+ this.selectedItem = item;
2484
+ });
2485
+ }
2486
+
2487
+ if ( false !== this._trigger( "select", event, { item: item } ) ) {
2488
+ this._value( item.value );
2489
+ }
2490
+ // reset the term after the select event
2491
+ // this allows custom select handling to work properly
2492
+ this.term = this._value();
2493
+
2494
+ this.close( event );
2495
+ this.selectedItem = item;
2496
+ }
2497
+ });
2498
+
2499
+ this.liveRegion = $( "<span>", {
2500
+ role: "status",
2501
+ "aria-live": "polite"
2502
+ })
2503
+ .addClass( "ui-helper-hidden-accessible" )
2504
+ .insertAfter( this.element );
2505
+
2506
+ if ( $.fn.bgiframe ) {
2507
+ this.menu.element.bgiframe();
2508
+ }
2509
+
2510
+ // turning off autocomplete prevents the browser from remembering the
2511
+ // value when navigating through history, so we re-enable autocomplete
2512
+ // if the page is unloaded before the widget is destroyed. #7790
2513
+ this._on( this.window, {
2514
+ beforeunload: function() {
2515
+ this.element.removeAttr( "autocomplete" );
2516
+ }
2517
+ });
2518
+ },
2519
+
2520
+ _destroy: function() {
2521
+ clearTimeout( this.searching );
2522
+ this.element
2523
+ .removeClass( "ui-autocomplete-input" )
2524
+ .removeAttr( "autocomplete" );
2525
+ this.menu.element.remove();
2526
+ this.liveRegion.remove();
2527
+ },
2528
+
2529
+ _setOption: function( key, value ) {
2530
+ this._super( key, value );
2531
+ if ( key === "source" ) {
2532
+ this._initSource();
2533
+ }
2534
+ if ( key === "appendTo" ) {
2535
+ this.menu.element.appendTo( this.document.find( value || "body" )[0] );
2536
+ }
2537
+ if ( key === "disabled" && value && this.xhr ) {
2538
+ this.xhr.abort();
2539
+ }
2540
+ },
2541
+
2542
+ _isMultiLine: function() {
2543
+ // Textareas are always multi-line
2544
+ if ( this.element.is( "textarea" ) ) {
2545
+ return true;
2546
+ }
2547
+ // Inputs are always single-line, even if inside a contentEditable element
2548
+ // IE also treats inputs as contentEditable
2549
+ if ( this.element.is( "input" ) ) {
2550
+ return false;
2551
+ }
2552
+ // All other element types are determined by whether or not they're contentEditable
2553
+ return this.element.prop( "isContentEditable" );
2554
+ },
2555
+
2556
+ _initSource: function() {
2557
+ var array, url,
2558
+ that = this;
2559
+ if ( $.isArray(this.options.source) ) {
2560
+ array = this.options.source;
2561
+ this.source = function( request, response ) {
2562
+ response( $.ui.autocomplete.filter( array, request.term ) );
2563
+ };
2564
+ } else if ( typeof this.options.source === "string" ) {
2565
+ url = this.options.source;
2566
+ this.source = function( request, response ) {
2567
+ if ( that.xhr ) {
2568
+ that.xhr.abort();
2569
+ }
2570
+ that.xhr = $.ajax({
2571
+ url: url,
2572
+ data: request,
2573
+ dataType: "json",
2574
+ success: function( data ) {
2575
+ response( data );
2576
+ },
2577
+ error: function() {
2578
+ response( [] );
2579
+ }
2580
+ });
2581
+ };
2582
+ } else {
2583
+ this.source = this.options.source;
2584
+ }
2585
+ },
2586
+
2587
+ _searchTimeout: function( event ) {
2588
+ clearTimeout( this.searching );
2589
+ this.searching = this._delay(function() {
2590
+ // only search if the value has changed
2591
+ if ( this.term !== this._value() ) {
2592
+ this.selectedItem = null;
2593
+ this.search( null, event );
2594
+ }
2595
+ }, this.options.delay );
2596
+ },
2597
+
2598
+ search: function( value, event ) {
2599
+ value = value != null ? value : this._value();
2600
+
2601
+ // always save the actual value, not the one passed as an argument
2602
+ this.term = this._value();
2603
+
2604
+ if ( value.length < this.options.minLength ) {
2605
+ return this.close( event );
2606
+ }
2607
+
2608
+ if ( this._trigger( "search", event ) === false ) {
2609
+ return;
2610
+ }
2611
+
2612
+ return this._search( value );
2613
+ },
2614
+
2615
+ _search: function( value ) {
2616
+ this.pending++;
2617
+ this.element.addClass( "ui-autocomplete-loading" );
2618
+ this.cancelSearch = false;
2619
+
2620
+ this.source( { term: value }, this._response() );
2621
+ },
2622
+
2623
+ _response: function() {
2624
+ var that = this,
2625
+ index = ++requestIndex;
2626
+
2627
+ return function( content ) {
2628
+ if ( index === requestIndex ) {
2629
+ that.__response( content );
2630
+ }
2631
+
2632
+ that.pending--;
2633
+ if ( !that.pending ) {
2634
+ that.element.removeClass( "ui-autocomplete-loading" );
2635
+ }
2636
+ };
2637
+ },
2638
+
2639
+ __response: function( content ) {
2640
+ if ( content ) {
2641
+ content = this._normalize( content );
2642
+ }
2643
+ this._trigger( "response", null, { content: content } );
2644
+ if ( !this.options.disabled && content && content.length && !this.cancelSearch ) {
2645
+ this._suggest( content );
2646
+ this._trigger( "open" );
2647
+ } else {
2648
+ // use ._close() instead of .close() so we don't cancel future searches
2649
+ this._close();
2650
+ }
2651
+ },
2652
+
2653
+ close: function( event ) {
2654
+ this.cancelSearch = true;
2655
+ this._close( event );
2656
+ },
2657
+
2658
+ _close: function( event ) {
2659
+ if ( this.menu.element.is( ":visible" ) ) {
2660
+ this.menu.element.hide();
2661
+ this.menu.blur();
2662
+ this.isNewMenu = true;
2663
+ this._trigger( "close", event );
2664
+ }
2665
+ },
2666
+
2667
+ _change: function( event ) {
2668
+ if ( this.previous !== this._value() ) {
2669
+ this._trigger( "change", event, { item: this.selectedItem } );
2670
+ }
2671
+ },
2672
+
2673
+ _normalize: function( items ) {
2674
+ // assume all items have the right format when the first item is complete
2675
+ if ( items.length && items[0].label && items[0].value ) {
2676
+ return items;
2677
+ }
2678
+ return $.map( items, function( item ) {
2679
+ if ( typeof item === "string" ) {
2680
+ return {
2681
+ label: item,
2682
+ value: item
2683
+ };
2684
+ }
2685
+ return $.extend({
2686
+ label: item.label || item.value,
2687
+ value: item.value || item.label
2688
+ }, item );
2689
+ });
2690
+ },
2691
+
2692
+ _suggest: function( items ) {
2693
+ var ul = this.menu.element
2694
+ .empty()
2695
+ .zIndex( this.element.zIndex() + 1 );
2696
+ this._renderMenu( ul, items );
2697
+ this.menu.refresh();
2698
+
2699
+ // size and position menu
2700
+ ul.show();
2701
+ this._resizeMenu();
2702
+ ul.position( $.extend({
2703
+ of: this.element
2704
+ }, this.options.position ));
2705
+
2706
+ if ( this.options.autoFocus ) {
2707
+ this.menu.next();
2708
+ }
2709
+ },
2710
+
2711
+ _resizeMenu: function() {
2712
+ var ul = this.menu.element;
2713
+ ul.outerWidth( Math.max(
2714
+ // Firefox wraps long text (possibly a rounding bug)
2715
+ // so we add 1px to avoid the wrapping (#7513)
2716
+ ul.width( "" ).outerWidth() + 1,
2717
+ this.element.outerWidth()
2718
+ ) );
2719
+ },
2720
+
2721
+ _renderMenu: function( ul, items ) {
2722
+ var that = this;
2723
+ $.each( items, function( index, item ) {
2724
+ that._renderItemData( ul, item );
2725
+ });
2726
+ },
2727
+
2728
+ _renderItemData: function( ul, item ) {
2729
+ return this._renderItem( ul, item ).data( "ui-autocomplete-item", item );
2730
+ },
2731
+
2732
+ _renderItem: function( ul, item ) {
2733
+ return $( "<li>" )
2734
+ .append( $( "<a>" ).text( item.label ) )
2735
+ .appendTo( ul );
2736
+ },
2737
+
2738
+ _move: function( direction, event ) {
2739
+ if ( !this.menu.element.is( ":visible" ) ) {
2740
+ this.search( null, event );
2741
+ return;
2742
+ }
2743
+ if ( this.menu.isFirstItem() && /^previous/.test( direction ) ||
2744
+ this.menu.isLastItem() && /^next/.test( direction ) ) {
2745
+ this._value( this.term );
2746
+ this.menu.blur();
2747
+ return;
2748
+ }
2749
+ this.menu[ direction ]( event );
2750
+ },
2751
+
2752
+ widget: function() {
2753
+ return this.menu.element;
2754
+ },
2755
+
2756
+ _value: function() {
2757
+ return this.valueMethod.apply( this.element, arguments );
2758
+ },
2759
+
2760
+ _keyEvent: function( keyEvent, event ) {
2761
+ if ( !this.isMultiLine || this.menu.element.is( ":visible" ) ) {
2762
+ this._move( keyEvent, event );
2763
+
2764
+ // prevents moving cursor to beginning/end of the text field in some browsers
2765
+ event.preventDefault();
2766
+ }
2767
+ }
2768
+ });
2769
+
2770
+ $.extend( $.ui.autocomplete, {
2771
+ escapeRegex: function( value ) {
2772
+ return value.replace(/[\-\[\]{}()*+?.,\\\^$|#\s]/g, "\\$&");
2773
+ },
2774
+ filter: function(array, term) {
2775
+ var matcher = new RegExp( $.ui.autocomplete.escapeRegex(term), "i" );
2776
+ return $.grep( array, function(value) {
2777
+ return matcher.test( value.label || value.value || value );
2778
+ });
2779
+ }
2780
+ });
2781
+
2782
+
2783
+ // live region extension, adding a `messages` option
2784
+ // NOTE: This is an experimental API. We are still investigating
2785
+ // a full solution for string manipulation and internationalization.
2786
+ $.widget( "ui.autocomplete", $.ui.autocomplete, {
2787
+ options: {
2788
+ messages: {
2789
+ noResults: "No search results.",
2790
+ results: function( amount ) {
2791
+ return amount + ( amount > 1 ? " results are" : " result is" ) +
2792
+ " available, use up and down arrow keys to navigate.";
2793
+ }
2794
+ }
2795
+ },
2796
+
2797
+ __response: function( content ) {
2798
+ var message;
2799
+ this._superApply( arguments );
2800
+ if ( this.options.disabled || this.cancelSearch ) {
2801
+ return;
2802
+ }
2803
+ if ( content && content.length ) {
2804
+ message = this.options.messages.results( content.length );
2805
+ } else {
2806
+ message = this.options.messages.noResults;
2807
+ }
2808
+ this.liveRegion.text( message );
2809
+ }
2810
+ });
2811
+
2812
+
2813
+ }( jQuery ));
2814
+ (function( $, undefined ) {
2815
+
2816
+ var lastActive, startXPos, startYPos, clickDragged,
2817
+ baseClasses = "ui-button ui-widget ui-state-default ui-corner-all",
2818
+ stateClasses = "ui-state-hover ui-state-active ",
2819
+ 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",
2820
+ formResetHandler = function() {
2821
+ var buttons = $( this ).find( ":ui-button" );
2822
+ setTimeout(function() {
2823
+ buttons.button( "refresh" );
2824
+ }, 1 );
2825
+ },
2826
+ radioGroup = function( radio ) {
2827
+ var name = radio.name,
2828
+ form = radio.form,
2829
+ radios = $( [] );
2830
+ if ( name ) {
2831
+ if ( form ) {
2832
+ radios = $( form ).find( "[name='" + name + "']" );
2833
+ } else {
2834
+ radios = $( "[name='" + name + "']", radio.ownerDocument )
2835
+ .filter(function() {
2836
+ return !this.form;
2837
+ });
2838
+ }
2839
+ }
2840
+ return radios;
2841
+ };
2842
+
2843
+ $.widget( "ui.button", {
2844
+ version: "1.9.1",
2845
+ defaultElement: "<button>",
2846
+ options: {
2847
+ disabled: null,
2848
+ text: true,
2849
+ label: null,
2850
+ icons: {
2851
+ primary: null,
2852
+ secondary: null
2853
+ }
2854
+ },
2855
+ _create: function() {
2856
+ this.element.closest( "form" )
2857
+ .unbind( "reset" + this.eventNamespace )
2858
+ .bind( "reset" + this.eventNamespace, formResetHandler );
2859
+
2860
+ if ( typeof this.options.disabled !== "boolean" ) {
2861
+ this.options.disabled = !!this.element.prop( "disabled" );
2862
+ } else {
2863
+ this.element.prop( "disabled", this.options.disabled );
2864
+ }
2865
+
2866
+ this._determineButtonType();
2867
+ this.hasTitle = !!this.buttonElement.attr( "title" );
2868
+
2869
+ var that = this,
2870
+ options = this.options,
2871
+ toggleButton = this.type === "checkbox" || this.type === "radio",
2872
+ hoverClass = "ui-state-hover" + ( !toggleButton ? " ui-state-active" : "" ),
2873
+ focusClass = "ui-state-focus";
2874
+
2875
+ if ( options.label === null ) {
2876
+ options.label = (this.type === "input" ? this.buttonElement.val() : this.buttonElement.html());
2877
+ }
2878
+
2879
+ this.buttonElement
2880
+ .addClass( baseClasses )
2881
+ .attr( "role", "button" )
2882
+ .bind( "mouseenter" + this.eventNamespace, function() {
2883
+ if ( options.disabled ) {
2884
+ return;
2885
+ }
2886
+ $( this ).addClass( "ui-state-hover" );
2887
+ if ( this === lastActive ) {
2888
+ $( this ).addClass( "ui-state-active" );
2889
+ }
2890
+ })
2891
+ .bind( "mouseleave" + this.eventNamespace, function() {
2892
+ if ( options.disabled ) {
2893
+ return;
2894
+ }
2895
+ $( this ).removeClass( hoverClass );
2896
+ })
2897
+ .bind( "click" + this.eventNamespace, function( event ) {
2898
+ if ( options.disabled ) {
2899
+ event.preventDefault();
2900
+ event.stopImmediatePropagation();
2901
+ }
2902
+ });
2903
+
2904
+ this.element
2905
+ .bind( "focus" + this.eventNamespace, function() {
2906
+ // no need to check disabled, focus won't be triggered anyway
2907
+ that.buttonElement.addClass( focusClass );
2908
+ })
2909
+ .bind( "blur" + this.eventNamespace, function() {
2910
+ that.buttonElement.removeClass( focusClass );
2911
+ });
2912
+
2913
+ if ( toggleButton ) {
2914
+ this.element.bind( "change" + this.eventNamespace, function() {
2915
+ if ( clickDragged ) {
2916
+ return;
2917
+ }
2918
+ that.refresh();
2919
+ });
2920
+ // if mouse moves between mousedown and mouseup (drag) set clickDragged flag
2921
+ // prevents issue where button state changes but checkbox/radio checked state
2922
+ // does not in Firefox (see ticket #6970)
2923
+ this.buttonElement
2924
+ .bind( "mousedown" + this.eventNamespace, function( event ) {
2925
+ if ( options.disabled ) {
2926
+ return;
2927
+ }
2928
+ clickDragged = false;
2929
+ startXPos = event.pageX;
2930
+ startYPos = event.pageY;
2931
+ })
2932
+ .bind( "mouseup" + this.eventNamespace, function( event ) {
2933
+ if ( options.disabled ) {
2934
+ return;
2935
+ }
2936
+ if ( startXPos !== event.pageX || startYPos !== event.pageY ) {
2937
+ clickDragged = true;
2938
+ }
2939
+ });
2940
+ }
2941
+
2942
+ if ( this.type === "checkbox" ) {
2943
+ this.buttonElement.bind( "click" + this.eventNamespace, function() {
2944
+ if ( options.disabled || clickDragged ) {
2945
+ return false;
2946
+ }
2947
+ $( this ).toggleClass( "ui-state-active" );
2948
+ that.buttonElement.attr( "aria-pressed", that.element[0].checked );
2949
+ });
2950
+ } else if ( this.type === "radio" ) {
2951
+ this.buttonElement.bind( "click" + this.eventNamespace, function() {
2952
+ if ( options.disabled || clickDragged ) {
2953
+ return false;
2954
+ }
2955
+ $( this ).addClass( "ui-state-active" );
2956
+ that.buttonElement.attr( "aria-pressed", "true" );
2957
+
2958
+ var radio = that.element[ 0 ];
2959
+ radioGroup( radio )
2960
+ .not( radio )
2961
+ .map(function() {
2962
+ return $( this ).button( "widget" )[ 0 ];
2963
+ })
2964
+ .removeClass( "ui-state-active" )
2965
+ .attr( "aria-pressed", "false" );
2966
+ });
2967
+ } else {
2968
+ this.buttonElement
2969
+ .bind( "mousedown" + this.eventNamespace, function() {
2970
+ if ( options.disabled ) {
2971
+ return false;
2972
+ }
2973
+ $( this ).addClass( "ui-state-active" );
2974
+ lastActive = this;
2975
+ that.document.one( "mouseup", function() {
2976
+ lastActive = null;
2977
+ });
2978
+ })
2979
+ .bind( "mouseup" + this.eventNamespace, function() {
2980
+ if ( options.disabled ) {
2981
+ return false;
2982
+ }
2983
+ $( this ).removeClass( "ui-state-active" );
2984
+ })
2985
+ .bind( "keydown" + this.eventNamespace, function(event) {
2986
+ if ( options.disabled ) {
2987
+ return false;
2988
+ }
2989
+ if ( event.keyCode === $.ui.keyCode.SPACE || event.keyCode === $.ui.keyCode.ENTER ) {
2990
+ $( this ).addClass( "ui-state-active" );
2991
+ }
2992
+ })
2993
+ .bind( "keyup" + this.eventNamespace, function() {
2994
+ $( this ).removeClass( "ui-state-active" );
2995
+ });
2996
+
2997
+ if ( this.buttonElement.is("a") ) {
2998
+ this.buttonElement.keyup(function(event) {
2999
+ if ( event.keyCode === $.ui.keyCode.SPACE ) {
3000
+ // TODO pass through original event correctly (just as 2nd argument doesn't work)
3001
+ $( this ).click();
3002
+ }
3003
+ });
3004
+ }
3005
+ }
3006
+
3007
+ // TODO: pull out $.Widget's handling for the disabled option into
3008
+ // $.Widget.prototype._setOptionDisabled so it's easy to proxy and can
3009
+ // be overridden by individual plugins
3010
+ this._setOption( "disabled", options.disabled );
3011
+ this._resetButton();
3012
+ },
3013
+
3014
+ _determineButtonType: function() {
3015
+ var ancestor, labelSelector, checked;
3016
+
3017
+ if ( this.element.is("[type=checkbox]") ) {
3018
+ this.type = "checkbox";
3019
+ } else if ( this.element.is("[type=radio]") ) {
3020
+ this.type = "radio";
3021
+ } else if ( this.element.is("input") ) {
3022
+ this.type = "input";
3023
+ } else {
3024
+ this.type = "button";
3025
+ }
3026
+
3027
+ if ( this.type === "checkbox" || this.type === "radio" ) {
3028
+ // we don't search against the document in case the element
3029
+ // is disconnected from the DOM
3030
+ ancestor = this.element.parents().last();
3031
+ labelSelector = "label[for='" + this.element.attr("id") + "']";
3032
+ this.buttonElement = ancestor.find( labelSelector );
3033
+ if ( !this.buttonElement.length ) {
3034
+ ancestor = ancestor.length ? ancestor.siblings() : this.element.siblings();
3035
+ this.buttonElement = ancestor.filter( labelSelector );
3036
+ if ( !this.buttonElement.length ) {
3037
+ this.buttonElement = ancestor.find( labelSelector );
3038
+ }
3039
+ }
3040
+ this.element.addClass( "ui-helper-hidden-accessible" );
3041
+
3042
+ checked = this.element.is( ":checked" );
3043
+ if ( checked ) {
3044
+ this.buttonElement.addClass( "ui-state-active" );
3045
+ }
3046
+ this.buttonElement.prop( "aria-pressed", checked );
3047
+ } else {
3048
+ this.buttonElement = this.element;
3049
+ }
3050
+ },
3051
+
3052
+ widget: function() {
3053
+ return this.buttonElement;
3054
+ },
3055
+
3056
+ _destroy: function() {
3057
+ this.element
3058
+ .removeClass( "ui-helper-hidden-accessible" );
3059
+ this.buttonElement
3060
+ .removeClass( baseClasses + " " + stateClasses + " " + typeClasses )
3061
+ .removeAttr( "role" )
3062
+ .removeAttr( "aria-pressed" )
3063
+ .html( this.buttonElement.find(".ui-button-text").html() );
3064
+
3065
+ if ( !this.hasTitle ) {
3066
+ this.buttonElement.removeAttr( "title" );
3067
+ }
3068
+ },
3069
+
3070
+ _setOption: function( key, value ) {
3071
+ this._super( key, value );
3072
+ if ( key === "disabled" ) {
3073
+ if ( value ) {
3074
+ this.element.prop( "disabled", true );
3075
+ } else {
3076
+ this.element.prop( "disabled", false );
3077
+ }
3078
+ return;
3079
+ }
3080
+ this._resetButton();
3081
+ },
3082
+
3083
+ refresh: function() {
3084
+ var isDisabled = this.element.is( ":disabled" ) || this.element.hasClass( "ui-button-disabled" );
3085
+ if ( isDisabled !== this.options.disabled ) {
3086
+ this._setOption( "disabled", isDisabled );
3087
+ }
3088
+ if ( this.type === "radio" ) {
3089
+ radioGroup( this.element[0] ).each(function() {
3090
+ if ( $( this ).is( ":checked" ) ) {
3091
+ $( this ).button( "widget" )
3092
+ .addClass( "ui-state-active" )
3093
+ .attr( "aria-pressed", "true" );
3094
+ } else {
3095
+ $( this ).button( "widget" )
3096
+ .removeClass( "ui-state-active" )
3097
+ .attr( "aria-pressed", "false" );
3098
+ }
3099
+ });
3100
+ } else if ( this.type === "checkbox" ) {
3101
+ if ( this.element.is( ":checked" ) ) {
3102
+ this.buttonElement
3103
+ .addClass( "ui-state-active" )
3104
+ .attr( "aria-pressed", "true" );
3105
+ } else {
3106
+ this.buttonElement
3107
+ .removeClass( "ui-state-active" )
3108
+ .attr( "aria-pressed", "false" );
3109
+ }
3110
+ }
3111
+ },
3112
+
3113
+ _resetButton: function() {
3114
+ if ( this.type === "input" ) {
3115
+ if ( this.options.label ) {
3116
+ this.element.val( this.options.label );
3117
+ }
3118
+ return;
3119
+ }
3120
+ var buttonElement = this.buttonElement.removeClass( typeClasses ),
3121
+ buttonText = $( "<span></span>", this.document[0] )
3122
+ .addClass( "ui-button-text" )
3123
+ .html( this.options.label )
3124
+ .appendTo( buttonElement.empty() )
3125
+ .text(),
3126
+ icons = this.options.icons,
3127
+ multipleIcons = icons.primary && icons.secondary,
3128
+ buttonClasses = [];
3129
+
3130
+ if ( icons.primary || icons.secondary ) {
3131
+ if ( this.options.text ) {
3132
+ buttonClasses.push( "ui-button-text-icon" + ( multipleIcons ? "s" : ( icons.primary ? "-primary" : "-secondary" ) ) );
3133
+ }
3134
+
3135
+ if ( icons.primary ) {
3136
+ buttonElement.prepend( "<span class='ui-button-icon-primary ui-icon " + icons.primary + "'></span>" );
3137
+ }
3138
+
3139
+ if ( icons.secondary ) {
3140
+ buttonElement.append( "<span class='ui-button-icon-secondary ui-icon " + icons.secondary + "'></span>" );
3141
+ }
3142
+
3143
+ if ( !this.options.text ) {
3144
+ buttonClasses.push( multipleIcons ? "ui-button-icons-only" : "ui-button-icon-only" );
3145
+
3146
+ if ( !this.hasTitle ) {
3147
+ buttonElement.attr( "title", $.trim( buttonText ) );
3148
+ }
3149
+ }
3150
+ } else {
3151
+ buttonClasses.push( "ui-button-text-only" );
3152
+ }
3153
+ buttonElement.addClass( buttonClasses.join( " " ) );
3154
+ }
3155
+ });
3156
+
3157
+ $.widget( "ui.buttonset", {
3158
+ version: "1.9.1",
3159
+ options: {
3160
+ items: "button, input[type=button], input[type=submit], input[type=reset], input[type=checkbox], input[type=radio], a, :data(button)"
3161
+ },
3162
+
3163
+ _create: function() {
3164
+ this.element.addClass( "ui-buttonset" );
3165
+ },
3166
+
3167
+ _init: function() {
3168
+ this.refresh();
3169
+ },
3170
+
3171
+ _setOption: function( key, value ) {
3172
+ if ( key === "disabled" ) {
3173
+ this.buttons.button( "option", key, value );
3174
+ }
3175
+
3176
+ this._super( key, value );
3177
+ },
3178
+
3179
+ refresh: function() {
3180
+ var rtl = this.element.css( "direction" ) === "rtl";
3181
+
3182
+ this.buttons = this.element.find( this.options.items )
3183
+ .filter( ":ui-button" )
3184
+ .button( "refresh" )
3185
+ .end()
3186
+ .not( ":ui-button" )
3187
+ .button()
3188
+ .end()
3189
+ .map(function() {
3190
+ return $( this ).button( "widget" )[ 0 ];
3191
+ })
3192
+ .removeClass( "ui-corner-all ui-corner-left ui-corner-right" )
3193
+ .filter( ":first" )
3194
+ .addClass( rtl ? "ui-corner-right" : "ui-corner-left" )
3195
+ .end()
3196
+ .filter( ":last" )
3197
+ .addClass( rtl ? "ui-corner-left" : "ui-corner-right" )
3198
+ .end()
3199
+ .end();
3200
+ },
3201
+
3202
+ _destroy: function() {
3203
+ this.element.removeClass( "ui-buttonset" );
3204
+ this.buttons
3205
+ .map(function() {
3206
+ return $( this ).button( "widget" )[ 0 ];
3207
+ })
3208
+ .removeClass( "ui-corner-left ui-corner-right" )
3209
+ .end()
3210
+ .button( "destroy" );
3211
+ }
3212
+ });
3213
+
3214
+ }( jQuery ) );
3215
+ (function( $, undefined ) {
3216
+
3217
+ $.extend($.ui, { datepicker: { version: "1.9.1" } });
3218
+
3219
+ var PROP_NAME = 'datepicker';
3220
+ var dpuuid = new Date().getTime();
3221
+ var instActive;
3222
+
3223
+ /* Date picker manager.
3224
+ Use the singleton instance of this class, $.datepicker, to interact with the date picker.
3225
+ Settings for (groups of) date pickers are maintained in an instance object,
3226
+ allowing multiple different settings on the same page. */
3227
+
3228
+ function Datepicker() {
3229
+ this.debug = false; // Change this to true to start debugging
3230
+ this._curInst = null; // The current instance in use
3231
+ this._keyEvent = false; // If the last event was a key event
3232
+ this._disabledInputs = []; // List of date picker inputs that have been disabled
3233
+ this._datepickerShowing = false; // True if the popup picker is showing , false if not
3234
+ this._inDialog = false; // True if showing within a "dialog", false if not
3235
+ this._mainDivId = 'ui-datepicker-div'; // The ID of the main datepicker division
3236
+ this._inlineClass = 'ui-datepicker-inline'; // The name of the inline marker class
3237
+ this._appendClass = 'ui-datepicker-append'; // The name of the append marker class
3238
+ this._triggerClass = 'ui-datepicker-trigger'; // The name of the trigger marker class
3239
+ this._dialogClass = 'ui-datepicker-dialog'; // The name of the dialog marker class
3240
+ this._disableClass = 'ui-datepicker-disabled'; // The name of the disabled covering marker class
3241
+ this._unselectableClass = 'ui-datepicker-unselectable'; // The name of the unselectable cell marker class
3242
+ this._currentClass = 'ui-datepicker-current-day'; // The name of the current day marker class
3243
+ this._dayOverClass = 'ui-datepicker-days-cell-over'; // The name of the day hover marker class
3244
+ this.regional = []; // Available regional settings, indexed by language code
3245
+ this.regional[''] = { // Default regional settings
3246
+ closeText: 'Done', // Display text for close link
3247
+ prevText: 'Prev', // Display text for previous month link
3248
+ nextText: 'Next', // Display text for next month link
3249
+ currentText: 'Today', // Display text for current month link
3250
+ monthNames: ['January','February','March','April','May','June',
3251
+ 'July','August','September','October','November','December'], // Names of months for drop-down and formatting
3252
+ monthNamesShort: ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'], // For formatting
3253
+ dayNames: ['Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday'], // For formatting
3254
+ dayNamesShort: ['Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat'], // For formatting
3255
+ dayNamesMin: ['Su','Mo','Tu','We','Th','Fr','Sa'], // Column headings for days starting at Sunday
3256
+ weekHeader: 'Wk', // Column header for week of the year
3257
+ dateFormat: 'mm/dd/yy', // See format options on parseDate
3258
+ firstDay: 0, // The first day of the week, Sun = 0, Mon = 1, ...
3259
+ isRTL: false, // True if right-to-left language, false if left-to-right
3260
+ showMonthAfterYear: false, // True if the year select precedes month, false for month then year
3261
+ yearSuffix: '' // Additional text to append to the year in the month headers
3262
+ };
3263
+ this._defaults = { // Global defaults for all the date picker instances
3264
+ showOn: 'focus', // 'focus' for popup on focus,
3265
+ // 'button' for trigger button, or 'both' for either
3266
+ showAnim: 'fadeIn', // Name of jQuery animation for popup
3267
+ showOptions: {}, // Options for enhanced animations
3268
+ defaultDate: null, // Used when field is blank: actual date,
3269
+ // +/-number for offset from today, null for today
3270
+ appendText: '', // Display text following the input box, e.g. showing the format
3271
+ buttonText: '...', // Text for trigger button
3272
+ buttonImage: '', // URL for trigger button image
3273
+ buttonImageOnly: false, // True if the image appears alone, false if it appears on a button
3274
+ hideIfNoPrevNext: false, // True to hide next/previous month links
3275
+ // if not applicable, false to just disable them
3276
+ navigationAsDateFormat: false, // True if date formatting applied to prev/today/next links
3277
+ gotoCurrent: false, // True if today link goes back to current selection instead
3278
+ changeMonth: false, // True if month can be selected directly, false if only prev/next
3279
+ changeYear: false, // True if year can be selected directly, false if only prev/next
3280
+ yearRange: 'c-10:c+10', // Range of years to display in drop-down,
3281
+ // either relative to today's year (-nn:+nn), relative to currently displayed year
3282
+ // (c-nn:c+nn), absolute (nnnn:nnnn), or a combination of the above (nnnn:-n)
3283
+ showOtherMonths: false, // True to show dates in other months, false to leave blank
3284
+ selectOtherMonths: false, // True to allow selection of dates in other months, false for unselectable
3285
+ showWeek: false, // True to show week of the year, false to not show it
3286
+ calculateWeek: this.iso8601Week, // How to calculate the week of the year,
3287
+ // takes a Date and returns the number of the week for it
3288
+ shortYearCutoff: '+10', // Short year values < this are in the current century,
3289
+ // > this are in the previous century,
3290
+ // string value starting with '+' for current year + value
3291
+ minDate: null, // The earliest selectable date, or null for no limit
3292
+ maxDate: null, // The latest selectable date, or null for no limit
3293
+ duration: 'fast', // Duration of display/closure
3294
+ beforeShowDay: null, // Function that takes a date and returns an array with
3295
+ // [0] = true if selectable, false if not, [1] = custom CSS class name(s) or '',
3296
+ // [2] = cell title (optional), e.g. $.datepicker.noWeekends
3297
+ beforeShow: null, // Function that takes an input field and
3298
+ // returns a set of custom settings for the date picker
3299
+ onSelect: null, // Define a callback function when a date is selected
3300
+ onChangeMonthYear: null, // Define a callback function when the month or year is changed
3301
+ onClose: null, // Define a callback function when the datepicker is closed
3302
+ numberOfMonths: 1, // Number of months to show at a time
3303
+ showCurrentAtPos: 0, // The position in multipe months at which to show the current month (starting at 0)
3304
+ stepMonths: 1, // Number of months to step back/forward
3305
+ stepBigMonths: 12, // Number of months to step back/forward for the big links
3306
+ altField: '', // Selector for an alternate field to store selected dates into
3307
+ altFormat: '', // The date format to use for the alternate field
3308
+ constrainInput: true, // The input is constrained by the current date format
3309
+ showButtonPanel: false, // True to show button panel, false to not show it
3310
+ autoSize: false, // True to size the input for the date format, false to leave as is
3311
+ disabled: false // The initial disabled state
3312
+ };
3313
+ $.extend(this._defaults, this.regional['']);
3314
+ this.dpDiv = bindHover($('<div id="' + this._mainDivId + '" class="ui-datepicker ui-widget ui-widget-content ui-helper-clearfix ui-corner-all"></div>'));
3315
+ }
3316
+
3317
+ $.extend(Datepicker.prototype, {
3318
+ /* Class name added to elements to indicate already configured with a date picker. */
3319
+ markerClassName: 'hasDatepicker',
3320
+
3321
+ //Keep track of the maximum number of rows displayed (see #7043)
3322
+ maxRows: 4,
3323
+
3324
+ /* Debug logging (if enabled). */
3325
+ log: function () {
3326
+ if (this.debug)
3327
+ console.log.apply('', arguments);
3328
+ },
3329
+
3330
+ // TODO rename to "widget" when switching to widget factory
3331
+ _widgetDatepicker: function() {
3332
+ return this.dpDiv;
3333
+ },
3334
+
3335
+ /* Override the default settings for all instances of the date picker.
3336
+ @param settings object - the new settings to use as defaults (anonymous object)
3337
+ @return the manager object */
3338
+ setDefaults: function(settings) {
3339
+ extendRemove(this._defaults, settings || {});
3340
+ return this;
3341
+ },
3342
+
3343
+ /* Attach the date picker to a jQuery selection.
3344
+ @param target element - the target input field or division or span
3345
+ @param settings object - the new settings to use for this date picker instance (anonymous) */
3346
+ _attachDatepicker: function(target, settings) {
3347
+ // check for settings on the control itself - in namespace 'date:'
3348
+ var inlineSettings = null;
3349
+ for (var attrName in this._defaults) {
3350
+ var attrValue = target.getAttribute('date:' + attrName);
3351
+ if (attrValue) {
3352
+ inlineSettings = inlineSettings || {};
3353
+ try {
3354
+ inlineSettings[attrName] = eval(attrValue);
3355
+ } catch (err) {
3356
+ inlineSettings[attrName] = attrValue;
3357
+ }
3358
+ }
3359
+ }
3360
+ var nodeName = target.nodeName.toLowerCase();
3361
+ var inline = (nodeName == 'div' || nodeName == 'span');
3362
+ if (!target.id) {
3363
+ this.uuid += 1;
3364
+ target.id = 'dp' + this.uuid;
3365
+ }
3366
+ var inst = this._newInst($(target), inline);
3367
+ inst.settings = $.extend({}, settings || {}, inlineSettings || {});
3368
+ if (nodeName == 'input') {
3369
+ this._connectDatepicker(target, inst);
3370
+ } else if (inline) {
3371
+ this._inlineDatepicker(target, inst);
3372
+ }
3373
+ },
3374
+
3375
+ /* Create a new instance object. */
3376
+ _newInst: function(target, inline) {
3377
+ var id = target[0].id.replace(/([^A-Za-z0-9_-])/g, '\\\\$1'); // escape jQuery meta chars
3378
+ return {id: id, input: target, // associated target
3379
+ selectedDay: 0, selectedMonth: 0, selectedYear: 0, // current selection
3380
+ drawMonth: 0, drawYear: 0, // month being drawn
3381
+ inline: inline, // is datepicker inline or not
3382
+ dpDiv: (!inline ? this.dpDiv : // presentation div
3383
+ bindHover($('<div class="' + this._inlineClass + ' ui-datepicker ui-widget ui-widget-content ui-helper-clearfix ui-corner-all"></div>')))};
3384
+ },
3385
+
3386
+ /* Attach the date picker to an input field. */
3387
+ _connectDatepicker: function(target, inst) {
3388
+ var input = $(target);
3389
+ inst.append = $([]);
3390
+ inst.trigger = $([]);
3391
+ if (input.hasClass(this.markerClassName))
3392
+ return;
3393
+ this._attachments(input, inst);
3394
+ input.addClass(this.markerClassName).keydown(this._doKeyDown).
3395
+ keypress(this._doKeyPress).keyup(this._doKeyUp).
3396
+ bind("setData.datepicker", function(event, key, value) {
3397
+ inst.settings[key] = value;
3398
+ }).bind("getData.datepicker", function(event, key) {
3399
+ return this._get(inst, key);
3400
+ });
3401
+ this._autoSize(inst);
3402
+ $.data(target, PROP_NAME, inst);
3403
+ //If disabled option is true, disable the datepicker once it has been attached to the input (see ticket #5665)
3404
+ if( inst.settings.disabled ) {
3405
+ this._disableDatepicker( target );
3406
+ }
3407
+ },
3408
+
3409
+ /* Make attachments based on settings. */
3410
+ _attachments: function(input, inst) {
3411
+ var appendText = this._get(inst, 'appendText');
3412
+ var isRTL = this._get(inst, 'isRTL');
3413
+ if (inst.append)
3414
+ inst.append.remove();
3415
+ if (appendText) {
3416
+ inst.append = $('<span class="' + this._appendClass + '">' + appendText + '</span>');
3417
+ input[isRTL ? 'before' : 'after'](inst.append);
3418
+ }
3419
+ input.unbind('focus', this._showDatepicker);
3420
+ if (inst.trigger)
3421
+ inst.trigger.remove();
3422
+ var showOn = this._get(inst, 'showOn');
3423
+ if (showOn == 'focus' || showOn == 'both') // pop-up date picker when in the marked field
3424
+ input.focus(this._showDatepicker);
3425
+ if (showOn == 'button' || showOn == 'both') { // pop-up date picker when button clicked
3426
+ var buttonText = this._get(inst, 'buttonText');
3427
+ var buttonImage = this._get(inst, 'buttonImage');
3428
+ inst.trigger = $(this._get(inst, 'buttonImageOnly') ?
3429
+ $('<img/>').addClass(this._triggerClass).
3430
+ attr({ src: buttonImage, alt: buttonText, title: buttonText }) :
3431
+ $('<button type="button"></button>').addClass(this._triggerClass).
3432
+ html(buttonImage == '' ? buttonText : $('<img/>').attr(
3433
+ { src:buttonImage, alt:buttonText, title:buttonText })));
3434
+ input[isRTL ? 'before' : 'after'](inst.trigger);
3435
+ inst.trigger.click(function() {
3436
+ if ($.datepicker._datepickerShowing && $.datepicker._lastInput == input[0])
3437
+ $.datepicker._hideDatepicker();
3438
+ else if ($.datepicker._datepickerShowing && $.datepicker._lastInput != input[0]) {
3439
+ $.datepicker._hideDatepicker();
3440
+ $.datepicker._showDatepicker(input[0]);
3441
+ } else
3442
+ $.datepicker._showDatepicker(input[0]);
3443
+ return false;
3444
+ });
3445
+ }
3446
+ },
3447
+
3448
+ /* Apply the maximum length for the date format. */
3449
+ _autoSize: function(inst) {
3450
+ if (this._get(inst, 'autoSize') && !inst.inline) {
3451
+ var date = new Date(2009, 12 - 1, 20); // Ensure double digits
3452
+ var dateFormat = this._get(inst, 'dateFormat');
3453
+ if (dateFormat.match(/[DM]/)) {
3454
+ var findMax = function(names) {
3455
+ var max = 0;
3456
+ var maxI = 0;
3457
+ for (var i = 0; i < names.length; i++) {
3458
+ if (names[i].length > max) {
3459
+ max = names[i].length;
3460
+ maxI = i;
3461
+ }
3462
+ }
3463
+ return maxI;
3464
+ };
3465
+ date.setMonth(findMax(this._get(inst, (dateFormat.match(/MM/) ?
3466
+ 'monthNames' : 'monthNamesShort'))));
3467
+ date.setDate(findMax(this._get(inst, (dateFormat.match(/DD/) ?
3468
+ 'dayNames' : 'dayNamesShort'))) + 20 - date.getDay());
3469
+ }
3470
+ inst.input.attr('size', this._formatDate(inst, date).length);
3471
+ }
3472
+ },
3473
+
3474
+ /* Attach an inline date picker to a div. */
3475
+ _inlineDatepicker: function(target, inst) {
3476
+ var divSpan = $(target);
3477
+ if (divSpan.hasClass(this.markerClassName))
3478
+ return;
3479
+ divSpan.addClass(this.markerClassName).append(inst.dpDiv).
3480
+ bind("setData.datepicker", function(event, key, value){
3481
+ inst.settings[key] = value;
3482
+ }).bind("getData.datepicker", function(event, key){
3483
+ return this._get(inst, key);
3484
+ });
3485
+ $.data(target, PROP_NAME, inst);
3486
+ this._setDate(inst, this._getDefaultDate(inst), true);
3487
+ this._updateDatepicker(inst);
3488
+ this._updateAlternate(inst);
3489
+ //If disabled option is true, disable the datepicker before showing it (see ticket #5665)
3490
+ if( inst.settings.disabled ) {
3491
+ this._disableDatepicker( target );
3492
+ }
3493
+ // Set display:block in place of inst.dpDiv.show() which won't work on disconnected elements
3494
+ // http://bugs.jqueryui.com/ticket/7552 - A Datepicker created on a detached div has zero height
3495
+ inst.dpDiv.css( "display", "block" );
3496
+ },
3497
+
3498
+ /* Pop-up the date picker in a "dialog" box.
3499
+ @param input element - ignored
3500
+ @param date string or Date - the initial date to display
3501
+ @param onSelect function - the function to call when a date is selected
3502
+ @param settings object - update the dialog date picker instance's settings (anonymous object)
3503
+ @param pos int[2] - coordinates for the dialog's position within the screen or
3504
+ event - with x/y coordinates or
3505
+ leave empty for default (screen centre)
3506
+ @return the manager object */
3507
+ _dialogDatepicker: function(input, date, onSelect, settings, pos) {
3508
+ var inst = this._dialogInst; // internal instance
3509
+ if (!inst) {
3510
+ this.uuid += 1;
3511
+ var id = 'dp' + this.uuid;
3512
+ this._dialogInput = $('<input type="text" id="' + id +
3513
+ '" style="position: absolute; top: -100px; width: 0px;"/>');
3514
+ this._dialogInput.keydown(this._doKeyDown);
3515
+ $('body').append(this._dialogInput);
3516
+ inst = this._dialogInst = this._newInst(this._dialogInput, false);
3517
+ inst.settings = {};
3518
+ $.data(this._dialogInput[0], PROP_NAME, inst);
3519
+ }
3520
+ extendRemove(inst.settings, settings || {});
3521
+ date = (date && date.constructor == Date ? this._formatDate(inst, date) : date);
3522
+ this._dialogInput.val(date);
3523
+
3524
+ this._pos = (pos ? (pos.length ? pos : [pos.pageX, pos.pageY]) : null);
3525
+ if (!this._pos) {
3526
+ var browserWidth = document.documentElement.clientWidth;
3527
+ var browserHeight = document.documentElement.clientHeight;
3528
+ var scrollX = document.documentElement.scrollLeft || document.body.scrollLeft;
3529
+ var scrollY = document.documentElement.scrollTop || document.body.scrollTop;
3530
+ this._pos = // should use actual width/height below
3531
+ [(browserWidth / 2) - 100 + scrollX, (browserHeight / 2) - 150 + scrollY];
3532
+ }
3533
+
3534
+ // move input on screen for focus, but hidden behind dialog
3535
+ this._dialogInput.css('left', (this._pos[0] + 20) + 'px').css('top', this._pos[1] + 'px');
3536
+ inst.settings.onSelect = onSelect;
3537
+ this._inDialog = true;
3538
+ this.dpDiv.addClass(this._dialogClass);
3539
+ this._showDatepicker(this._dialogInput[0]);
3540
+ if ($.blockUI)
3541
+ $.blockUI(this.dpDiv);
3542
+ $.data(this._dialogInput[0], PROP_NAME, inst);
3543
+ return this;
3544
+ },
3545
+
3546
+ /* Detach a datepicker from its control.
3547
+ @param target element - the target input field or division or span */
3548
+ _destroyDatepicker: function(target) {
3549
+ var $target = $(target);
3550
+ var inst = $.data(target, PROP_NAME);
3551
+ if (!$target.hasClass(this.markerClassName)) {
3552
+ return;
3553
+ }
3554
+ var nodeName = target.nodeName.toLowerCase();
3555
+ $.removeData(target, PROP_NAME);
3556
+ if (nodeName == 'input') {
3557
+ inst.append.remove();
3558
+ inst.trigger.remove();
3559
+ $target.removeClass(this.markerClassName).
3560
+ unbind('focus', this._showDatepicker).
3561
+ unbind('keydown', this._doKeyDown).
3562
+ unbind('keypress', this._doKeyPress).
3563
+ unbind('keyup', this._doKeyUp);
3564
+ } else if (nodeName == 'div' || nodeName == 'span')
3565
+ $target.removeClass(this.markerClassName).empty();
3566
+ },
3567
+
3568
+ /* Enable the date picker to a jQuery selection.
3569
+ @param target element - the target input field or division or span */
3570
+ _enableDatepicker: function(target) {
3571
+ var $target = $(target);
3572
+ var inst = $.data(target, PROP_NAME);
3573
+ if (!$target.hasClass(this.markerClassName)) {
3574
+ return;
3575
+ }
3576
+ var nodeName = target.nodeName.toLowerCase();
3577
+ if (nodeName == 'input') {
3578
+ target.disabled = false;
3579
+ inst.trigger.filter('button').
3580
+ each(function() { this.disabled = false; }).end().
3581
+ filter('img').css({opacity: '1.0', cursor: ''});
3582
+ }
3583
+ else if (nodeName == 'div' || nodeName == 'span') {
3584
+ var inline = $target.children('.' + this._inlineClass);
3585
+ inline.children().removeClass('ui-state-disabled');
3586
+ inline.find("select.ui-datepicker-month, select.ui-datepicker-year").
3587
+ prop("disabled", false);
3588
+ }
3589
+ this._disabledInputs = $.map(this._disabledInputs,
3590
+ function(value) { return (value == target ? null : value); }); // delete entry
3591
+ },
3592
+
3593
+ /* Disable the date picker to a jQuery selection.
3594
+ @param target element - the target input field or division or span */
3595
+ _disableDatepicker: function(target) {
3596
+ var $target = $(target);
3597
+ var inst = $.data(target, PROP_NAME);
3598
+ if (!$target.hasClass(this.markerClassName)) {
3599
+ return;
3600
+ }
3601
+ var nodeName = target.nodeName.toLowerCase();
3602
+ if (nodeName == 'input') {
3603
+ target.disabled = true;
3604
+ inst.trigger.filter('button').
3605
+ each(function() { this.disabled = true; }).end().
3606
+ filter('img').css({opacity: '0.5', cursor: 'default'});
3607
+ }
3608
+ else if (nodeName == 'div' || nodeName == 'span') {
3609
+ var inline = $target.children('.' + this._inlineClass);
3610
+ inline.children().addClass('ui-state-disabled');
3611
+ inline.find("select.ui-datepicker-month, select.ui-datepicker-year").
3612
+ prop("disabled", true);
3613
+ }
3614
+ this._disabledInputs = $.map(this._disabledInputs,
3615
+ function(value) { return (value == target ? null : value); }); // delete entry
3616
+ this._disabledInputs[this._disabledInputs.length] = target;
3617
+ },
3618
+
3619
+ /* Is the first field in a jQuery collection disabled as a datepicker?
3620
+ @param target element - the target input field or division or span
3621
+ @return boolean - true if disabled, false if enabled */
3622
+ _isDisabledDatepicker: function(target) {
3623
+ if (!target) {
3624
+ return false;
3625
+ }
3626
+ for (var i = 0; i < this._disabledInputs.length; i++) {
3627
+ if (this._disabledInputs[i] == target)
3628
+ return true;
3629
+ }
3630
+ return false;
3631
+ },
3632
+
3633
+ /* Retrieve the instance data for the target control.
3634
+ @param target element - the target input field or division or span
3635
+ @return object - the associated instance data
3636
+ @throws error if a jQuery problem getting data */
3637
+ _getInst: function(target) {
3638
+ try {
3639
+ return $.data(target, PROP_NAME);
3640
+ }
3641
+ catch (err) {
3642
+ throw 'Missing instance data for this datepicker';
3643
+ }
3644
+ },
3645
+
3646
+ /* Update or retrieve the settings for a date picker attached to an input field or division.
3647
+ @param target element - the target input field or division or span
3648
+ @param name object - the new settings to update or
3649
+ string - the name of the setting to change or retrieve,
3650
+ when retrieving also 'all' for all instance settings or
3651
+ 'defaults' for all global defaults
3652
+ @param value any - the new value for the setting
3653
+ (omit if above is an object or to retrieve a value) */
3654
+ _optionDatepicker: function(target, name, value) {
3655
+ var inst = this._getInst(target);
3656
+ if (arguments.length == 2 && typeof name == 'string') {
3657
+ return (name == 'defaults' ? $.extend({}, $.datepicker._defaults) :
3658
+ (inst ? (name == 'all' ? $.extend({}, inst.settings) :
3659
+ this._get(inst, name)) : null));
3660
+ }
3661
+ var settings = name || {};
3662
+ if (typeof name == 'string') {
3663
+ settings = {};
3664
+ settings[name] = value;
3665
+ }
3666
+ if (inst) {
3667
+ if (this._curInst == inst) {
3668
+ this._hideDatepicker();
3669
+ }
3670
+ var date = this._getDateDatepicker(target, true);
3671
+ var minDate = this._getMinMaxDate(inst, 'min');
3672
+ var maxDate = this._getMinMaxDate(inst, 'max');
3673
+ extendRemove(inst.settings, settings);
3674
+ // reformat the old minDate/maxDate values if dateFormat changes and a new minDate/maxDate isn't provided
3675
+ if (minDate !== null && settings['dateFormat'] !== undefined && settings['minDate'] === undefined)
3676
+ inst.settings.minDate = this._formatDate(inst, minDate);
3677
+ if (maxDate !== null && settings['dateFormat'] !== undefined && settings['maxDate'] === undefined)
3678
+ inst.settings.maxDate = this._formatDate(inst, maxDate);
3679
+ this._attachments($(target), inst);
3680
+ this._autoSize(inst);
3681
+ this._setDate(inst, date);
3682
+ this._updateAlternate(inst);
3683
+ this._updateDatepicker(inst);
3684
+ }
3685
+ },
3686
+
3687
+ // change method deprecated
3688
+ _changeDatepicker: function(target, name, value) {
3689
+ this._optionDatepicker(target, name, value);
3690
+ },
3691
+
3692
+ /* Redraw the date picker attached to an input field or division.
3693
+ @param target element - the target input field or division or span */
3694
+ _refreshDatepicker: function(target) {
3695
+ var inst = this._getInst(target);
3696
+ if (inst) {
3697
+ this._updateDatepicker(inst);
3698
+ }
3699
+ },
3700
+
3701
+ /* Set the dates for a jQuery selection.
3702
+ @param target element - the target input field or division or span
3703
+ @param date Date - the new date */
3704
+ _setDateDatepicker: function(target, date) {
3705
+ var inst = this._getInst(target);
3706
+ if (inst) {
3707
+ this._setDate(inst, date);
3708
+ this._updateDatepicker(inst);
3709
+ this._updateAlternate(inst);
3710
+ }
3711
+ },
3712
+
3713
+ /* Get the date(s) for the first entry in a jQuery selection.
3714
+ @param target element - the target input field or division or span
3715
+ @param noDefault boolean - true if no default date is to be used
3716
+ @return Date - the current date */
3717
+ _getDateDatepicker: function(target, noDefault) {
3718
+ var inst = this._getInst(target);
3719
+ if (inst && !inst.inline)
3720
+ this._setDateFromField(inst, noDefault);
3721
+ return (inst ? this._getDate(inst) : null);
3722
+ },
3723
+
3724
+ /* Handle keystrokes. */
3725
+ _doKeyDown: function(event) {
3726
+ var inst = $.datepicker._getInst(event.target);
3727
+ var handled = true;
3728
+ var isRTL = inst.dpDiv.is('.ui-datepicker-rtl');
3729
+ inst._keyEvent = true;
3730
+ if ($.datepicker._datepickerShowing)
3731
+ switch (event.keyCode) {
3732
+ case 9: $.datepicker._hideDatepicker();
3733
+ handled = false;
3734
+ break; // hide on tab out
3735
+ case 13: var sel = $('td.' + $.datepicker._dayOverClass + ':not(.' +
3736
+ $.datepicker._currentClass + ')', inst.dpDiv);
3737
+ if (sel[0])
3738
+ $.datepicker._selectDay(event.target, inst.selectedMonth, inst.selectedYear, sel[0]);
3739
+ var onSelect = $.datepicker._get(inst, 'onSelect');
3740
+ if (onSelect) {
3741
+ var dateStr = $.datepicker._formatDate(inst);
3742
+
3743
+ // trigger custom callback
3744
+ onSelect.apply((inst.input ? inst.input[0] : null), [dateStr, inst]);
3745
+ }
3746
+ else
3747
+ $.datepicker._hideDatepicker();
3748
+ return false; // don't submit the form
3749
+ break; // select the value on enter
3750
+ case 27: $.datepicker._hideDatepicker();
3751
+ break; // hide on escape
3752
+ case 33: $.datepicker._adjustDate(event.target, (event.ctrlKey ?
3753
+ -$.datepicker._get(inst, 'stepBigMonths') :
3754
+ -$.datepicker._get(inst, 'stepMonths')), 'M');
3755
+ break; // previous month/year on page up/+ ctrl
3756
+ case 34: $.datepicker._adjustDate(event.target, (event.ctrlKey ?
3757
+ +$.datepicker._get(inst, 'stepBigMonths') :
3758
+ +$.datepicker._get(inst, 'stepMonths')), 'M');
3759
+ break; // next month/year on page down/+ ctrl
3760
+ case 35: if (event.ctrlKey || event.metaKey) $.datepicker._clearDate(event.target);
3761
+ handled = event.ctrlKey || event.metaKey;
3762
+ break; // clear on ctrl or command +end
3763
+ case 36: if (event.ctrlKey || event.metaKey) $.datepicker._gotoToday(event.target);
3764
+ handled = event.ctrlKey || event.metaKey;
3765
+ break; // current on ctrl or command +home
3766
+ case 37: if (event.ctrlKey || event.metaKey) $.datepicker._adjustDate(event.target, (isRTL ? +1 : -1), 'D');
3767
+ handled = event.ctrlKey || event.metaKey;
3768
+ // -1 day on ctrl or command +left
3769
+ if (event.originalEvent.altKey) $.datepicker._adjustDate(event.target, (event.ctrlKey ?
3770
+ -$.datepicker._get(inst, 'stepBigMonths') :
3771
+ -$.datepicker._get(inst, 'stepMonths')), 'M');
3772
+ // next month/year on alt +left on Mac
3773
+ break;
3774
+ case 38: if (event.ctrlKey || event.metaKey) $.datepicker._adjustDate(event.target, -7, 'D');
3775
+ handled = event.ctrlKey || event.metaKey;
3776
+ break; // -1 week on ctrl or command +up
3777
+ case 39: if (event.ctrlKey || event.metaKey) $.datepicker._adjustDate(event.target, (isRTL ? -1 : +1), 'D');
3778
+ handled = event.ctrlKey || event.metaKey;
3779
+ // +1 day on ctrl or command +right
3780
+ if (event.originalEvent.altKey) $.datepicker._adjustDate(event.target, (event.ctrlKey ?
3781
+ +$.datepicker._get(inst, 'stepBigMonths') :
3782
+ +$.datepicker._get(inst, 'stepMonths')), 'M');
3783
+ // next month/year on alt +right
3784
+ break;
3785
+ case 40: if (event.ctrlKey || event.metaKey) $.datepicker._adjustDate(event.target, +7, 'D');
3786
+ handled = event.ctrlKey || event.metaKey;
3787
+ break; // +1 week on ctrl or command +down
3788
+ default: handled = false;
3789
+ }
3790
+ else if (event.keyCode == 36 && event.ctrlKey) // display the date picker on ctrl+home
3791
+ $.datepicker._showDatepicker(this);
3792
+ else {
3793
+ handled = false;
3794
+ }
3795
+ if (handled) {
3796
+ event.preventDefault();
3797
+ event.stopPropagation();
3798
+ }
3799
+ },
3800
+
3801
+ /* Filter entered characters - based on date format. */
3802
+ _doKeyPress: function(event) {
3803
+ var inst = $.datepicker._getInst(event.target);
3804
+ if ($.datepicker._get(inst, 'constrainInput')) {
3805
+ var chars = $.datepicker._possibleChars($.datepicker._get(inst, 'dateFormat'));
3806
+ var chr = String.fromCharCode(event.charCode == undefined ? event.keyCode : event.charCode);
3807
+ return event.ctrlKey || event.metaKey || (chr < ' ' || !chars || chars.indexOf(chr) > -1);
3808
+ }
3809
+ },
3810
+
3811
+ /* Synchronise manual entry and field/alternate field. */
3812
+ _doKeyUp: function(event) {
3813
+ var inst = $.datepicker._getInst(event.target);
3814
+ if (inst.input.val() != inst.lastVal) {
3815
+ try {
3816
+ var date = $.datepicker.parseDate($.datepicker._get(inst, 'dateFormat'),
3817
+ (inst.input ? inst.input.val() : null),
3818
+ $.datepicker._getFormatConfig(inst));
3819
+ if (date) { // only if valid
3820
+ $.datepicker._setDateFromField(inst);
3821
+ $.datepicker._updateAlternate(inst);
3822
+ $.datepicker._updateDatepicker(inst);
3823
+ }
3824
+ }
3825
+ catch (err) {
3826
+ $.datepicker.log(err);
3827
+ }
3828
+ }
3829
+ return true;
3830
+ },
3831
+
3832
+ /* Pop-up the date picker for a given input field.
3833
+ If false returned from beforeShow event handler do not show.
3834
+ @param input element - the input field attached to the date picker or
3835
+ event - if triggered by focus */
3836
+ _showDatepicker: function(input) {
3837
+ input = input.target || input;
3838
+ if (input.nodeName.toLowerCase() != 'input') // find from button/image trigger
3839
+ input = $('input', input.parentNode)[0];
3840
+ if ($.datepicker._isDisabledDatepicker(input) || $.datepicker._lastInput == input) // already here
3841
+ return;
3842
+ var inst = $.datepicker._getInst(input);
3843
+ if ($.datepicker._curInst && $.datepicker._curInst != inst) {
3844
+ $.datepicker._curInst.dpDiv.stop(true, true);
3845
+ if ( inst && $.datepicker._datepickerShowing ) {
3846
+ $.datepicker._hideDatepicker( $.datepicker._curInst.input[0] );
3847
+ }
3848
+ }
3849
+ var beforeShow = $.datepicker._get(inst, 'beforeShow');
3850
+ var beforeShowSettings = beforeShow ? beforeShow.apply(input, [input, inst]) : {};
3851
+ if(beforeShowSettings === false){
3852
+ //false
3853
+ return;
3854
+ }
3855
+ extendRemove(inst.settings, beforeShowSettings);
3856
+ inst.lastVal = null;
3857
+ $.datepicker._lastInput = input;
3858
+ $.datepicker._setDateFromField(inst);
3859
+ if ($.datepicker._inDialog) // hide cursor
3860
+ input.value = '';
3861
+ if (!$.datepicker._pos) { // position below input
3862
+ $.datepicker._pos = $.datepicker._findPos(input);
3863
+ $.datepicker._pos[1] += input.offsetHeight; // add the height
3864
+ }
3865
+ var isFixed = false;
3866
+ $(input).parents().each(function() {
3867
+ isFixed |= $(this).css('position') == 'fixed';
3868
+ return !isFixed;
3869
+ });
3870
+ var offset = {left: $.datepicker._pos[0], top: $.datepicker._pos[1]};
3871
+ $.datepicker._pos = null;
3872
+ //to avoid flashes on Firefox
3873
+ inst.dpDiv.empty();
3874
+ // determine sizing offscreen
3875
+ inst.dpDiv.css({position: 'absolute', display: 'block', top: '-1000px'});
3876
+ $.datepicker._updateDatepicker(inst);
3877
+ // fix width for dynamic number of date pickers
3878
+ // and adjust position before showing
3879
+ offset = $.datepicker._checkOffset(inst, offset, isFixed);
3880
+ inst.dpDiv.css({position: ($.datepicker._inDialog && $.blockUI ?
3881
+ 'static' : (isFixed ? 'fixed' : 'absolute')), display: 'none',
3882
+ left: offset.left + 'px', top: offset.top + 'px'});
3883
+ if (!inst.inline) {
3884
+ var showAnim = $.datepicker._get(inst, 'showAnim');
3885
+ var duration = $.datepicker._get(inst, 'duration');
3886
+ var postProcess = function() {
3887
+ var cover = inst.dpDiv.find('iframe.ui-datepicker-cover'); // IE6- only
3888
+ if( !! cover.length ){
3889
+ var borders = $.datepicker._getBorders(inst.dpDiv);
3890
+ cover.css({left: -borders[0], top: -borders[1],
3891
+ width: inst.dpDiv.outerWidth(), height: inst.dpDiv.outerHeight()});
3892
+ }
3893
+ };
3894
+ inst.dpDiv.zIndex($(input).zIndex()+1);
3895
+ $.datepicker._datepickerShowing = true;
3896
+
3897
+ // DEPRECATED: after BC for 1.8.x $.effects[ showAnim ] is not needed
3898
+ if ( $.effects && ( $.effects.effect[ showAnim ] || $.effects[ showAnim ] ) )
3899
+ inst.dpDiv.show(showAnim, $.datepicker._get(inst, 'showOptions'), duration, postProcess);
3900
+ else
3901
+ inst.dpDiv[showAnim || 'show']((showAnim ? duration : null), postProcess);
3902
+ if (!showAnim || !duration)
3903
+ postProcess();
3904
+ if (inst.input.is(':visible') && !inst.input.is(':disabled'))
3905
+ inst.input.focus();
3906
+ $.datepicker._curInst = inst;
3907
+ }
3908
+ },
3909
+
3910
+ /* Generate the date picker content. */
3911
+ _updateDatepicker: function(inst) {
3912
+ this.maxRows = 4; //Reset the max number of rows being displayed (see #7043)
3913
+ var borders = $.datepicker._getBorders(inst.dpDiv);
3914
+ instActive = inst; // for delegate hover events
3915
+ inst.dpDiv.empty().append(this._generateHTML(inst));
3916
+ this._attachHandlers(inst);
3917
+ var cover = inst.dpDiv.find('iframe.ui-datepicker-cover'); // IE6- only
3918
+ if( !!cover.length ){ //avoid call to outerXXXX() when not in IE6
3919
+ cover.css({left: -borders[0], top: -borders[1], width: inst.dpDiv.outerWidth(), height: inst.dpDiv.outerHeight()})
3920
+ }
3921
+ inst.dpDiv.find('.' + this._dayOverClass + ' a').mouseover();
3922
+ var numMonths = this._getNumberOfMonths(inst);
3923
+ var cols = numMonths[1];
3924
+ var width = 17;
3925
+ inst.dpDiv.removeClass('ui-datepicker-multi-2 ui-datepicker-multi-3 ui-datepicker-multi-4').width('');
3926
+ if (cols > 1)
3927
+ inst.dpDiv.addClass('ui-datepicker-multi-' + cols).css('width', (width * cols) + 'em');
3928
+ inst.dpDiv[(numMonths[0] != 1 || numMonths[1] != 1 ? 'add' : 'remove') +
3929
+ 'Class']('ui-datepicker-multi');
3930
+ inst.dpDiv[(this._get(inst, 'isRTL') ? 'add' : 'remove') +
3931
+ 'Class']('ui-datepicker-rtl');
3932
+ if (inst == $.datepicker._curInst && $.datepicker._datepickerShowing && inst.input &&
3933
+ // #6694 - don't focus the input if it's already focused
3934
+ // this breaks the change event in IE
3935
+ inst.input.is(':visible') && !inst.input.is(':disabled') && inst.input[0] != document.activeElement)
3936
+ inst.input.focus();
3937
+ // deffered render of the years select (to avoid flashes on Firefox)
3938
+ if( inst.yearshtml ){
3939
+ var origyearshtml = inst.yearshtml;
3940
+ setTimeout(function(){
3941
+ //assure that inst.yearshtml didn't change.
3942
+ if( origyearshtml === inst.yearshtml && inst.yearshtml ){
3943
+ inst.dpDiv.find('select.ui-datepicker-year:first').replaceWith(inst.yearshtml);
3944
+ }
3945
+ origyearshtml = inst.yearshtml = null;
3946
+ }, 0);
3947
+ }
3948
+ },
3949
+
3950
+ /* Retrieve the size of left and top borders for an element.
3951
+ @param elem (jQuery object) the element of interest
3952
+ @return (number[2]) the left and top borders */
3953
+ _getBorders: function(elem) {
3954
+ var convert = function(value) {
3955
+ return {thin: 1, medium: 2, thick: 3}[value] || value;
3956
+ };
3957
+ return [parseFloat(convert(elem.css('border-left-width'))),
3958
+ parseFloat(convert(elem.css('border-top-width')))];
3959
+ },
3960
+
3961
+ /* Check positioning to remain on screen. */
3962
+ _checkOffset: function(inst, offset, isFixed) {
3963
+ var dpWidth = inst.dpDiv.outerWidth();
3964
+ var dpHeight = inst.dpDiv.outerHeight();
3965
+ var inputWidth = inst.input ? inst.input.outerWidth() : 0;
3966
+ var inputHeight = inst.input ? inst.input.outerHeight() : 0;
3967
+ var viewWidth = document.documentElement.clientWidth + (isFixed ? 0 : $(document).scrollLeft());
3968
+ var viewHeight = document.documentElement.clientHeight + (isFixed ? 0 : $(document).scrollTop());
3969
+
3970
+ offset.left -= (this._get(inst, 'isRTL') ? (dpWidth - inputWidth) : 0);
3971
+ offset.left -= (isFixed && offset.left == inst.input.offset().left) ? $(document).scrollLeft() : 0;
3972
+ offset.top -= (isFixed && offset.top == (inst.input.offset().top + inputHeight)) ? $(document).scrollTop() : 0;
3973
+
3974
+ // now check if datepicker is showing outside window viewport - move to a better place if so.
3975
+ offset.left -= Math.min(offset.left, (offset.left + dpWidth > viewWidth && viewWidth > dpWidth) ?
3976
+ Math.abs(offset.left + dpWidth - viewWidth) : 0);
3977
+ offset.top -= Math.min(offset.top, (offset.top + dpHeight > viewHeight && viewHeight > dpHeight) ?
3978
+ Math.abs(dpHeight + inputHeight) : 0);
3979
+
3980
+ return offset;
3981
+ },
3982
+
3983
+ /* Find an object's position on the screen. */
3984
+ _findPos: function(obj) {
3985
+ var inst = this._getInst(obj);
3986
+ var isRTL = this._get(inst, 'isRTL');
3987
+ while (obj && (obj.type == 'hidden' || obj.nodeType != 1 || $.expr.filters.hidden(obj))) {
3988
+ obj = obj[isRTL ? 'previousSibling' : 'nextSibling'];
3989
+ }
3990
+ var position = $(obj).offset();
3991
+ return [position.left, position.top];
3992
+ },
3993
+
3994
+ /* Hide the date picker from view.
3995
+ @param input element - the input field attached to the date picker */
3996
+ _hideDatepicker: function(input) {
3997
+ var inst = this._curInst;
3998
+ if (!inst || (input && inst != $.data(input, PROP_NAME)))
3999
+ return;
4000
+ if (this._datepickerShowing) {
4001
+ var showAnim = this._get(inst, 'showAnim');
4002
+ var duration = this._get(inst, 'duration');
4003
+ var postProcess = function() {
4004
+ $.datepicker._tidyDialog(inst);
4005
+ };
4006
+
4007
+ // DEPRECATED: after BC for 1.8.x $.effects[ showAnim ] is not needed
4008
+ if ( $.effects && ( $.effects.effect[ showAnim ] || $.effects[ showAnim ] ) )
4009
+ inst.dpDiv.hide(showAnim, $.datepicker._get(inst, 'showOptions'), duration, postProcess);
4010
+ else
4011
+ inst.dpDiv[(showAnim == 'slideDown' ? 'slideUp' :
4012
+ (showAnim == 'fadeIn' ? 'fadeOut' : 'hide'))]((showAnim ? duration : null), postProcess);
4013
+ if (!showAnim)
4014
+ postProcess();
4015
+ this._datepickerShowing = false;
4016
+ var onClose = this._get(inst, 'onClose');
4017
+ if (onClose)
4018
+ onClose.apply((inst.input ? inst.input[0] : null),
4019
+ [(inst.input ? inst.input.val() : ''), inst]);
4020
+ this._lastInput = null;
4021
+ if (this._inDialog) {
4022
+ this._dialogInput.css({ position: 'absolute', left: '0', top: '-100px' });
4023
+ if ($.blockUI) {
4024
+ $.unblockUI();
4025
+ $('body').append(this.dpDiv);
4026
+ }
4027
+ }
4028
+ this._inDialog = false;
4029
+ }
4030
+ },
4031
+
4032
+ /* Tidy up after a dialog display. */
4033
+ _tidyDialog: function(inst) {
4034
+ inst.dpDiv.removeClass(this._dialogClass).unbind('.ui-datepicker-calendar');
4035
+ },
4036
+
4037
+ /* Close date picker if clicked elsewhere. */
4038
+ _checkExternalClick: function(event) {
4039
+ if (!$.datepicker._curInst)
4040
+ return;
4041
+
4042
+ var $target = $(event.target),
4043
+ inst = $.datepicker._getInst($target[0]);
4044
+
4045
+ if ( ( ( $target[0].id != $.datepicker._mainDivId &&
4046
+ $target.parents('#' + $.datepicker._mainDivId).length == 0 &&
4047
+ !$target.hasClass($.datepicker.markerClassName) &&
4048
+ !$target.closest("." + $.datepicker._triggerClass).length &&
4049
+ $.datepicker._datepickerShowing && !($.datepicker._inDialog && $.blockUI) ) ) ||
4050
+ ( $target.hasClass($.datepicker.markerClassName) && $.datepicker._curInst != inst ) )
4051
+ $.datepicker._hideDatepicker();
4052
+ },
4053
+
4054
+ /* Adjust one of the date sub-fields. */
4055
+ _adjustDate: function(id, offset, period) {
4056
+ var target = $(id);
4057
+ var inst = this._getInst(target[0]);
4058
+ if (this._isDisabledDatepicker(target[0])) {
4059
+ return;
4060
+ }
4061
+ this._adjustInstDate(inst, offset +
4062
+ (period == 'M' ? this._get(inst, 'showCurrentAtPos') : 0), // undo positioning
4063
+ period);
4064
+ this._updateDatepicker(inst);
4065
+ },
4066
+
4067
+ /* Action for current link. */
4068
+ _gotoToday: function(id) {
4069
+ var target = $(id);
4070
+ var inst = this._getInst(target[0]);
4071
+ if (this._get(inst, 'gotoCurrent') && inst.currentDay) {
4072
+ inst.selectedDay = inst.currentDay;
4073
+ inst.drawMonth = inst.selectedMonth = inst.currentMonth;
4074
+ inst.drawYear = inst.selectedYear = inst.currentYear;
4075
+ }
4076
+ else {
4077
+ var date = new Date();
4078
+ inst.selectedDay = date.getDate();
4079
+ inst.drawMonth = inst.selectedMonth = date.getMonth();
4080
+ inst.drawYear = inst.selectedYear = date.getFullYear();
4081
+ }
4082
+ this._notifyChange(inst);
4083
+ this._adjustDate(target);
4084
+ },
4085
+
4086
+ /* Action for selecting a new month/year. */
4087
+ _selectMonthYear: function(id, select, period) {
4088
+ var target = $(id);
4089
+ var inst = this._getInst(target[0]);
4090
+ inst['selected' + (period == 'M' ? 'Month' : 'Year')] =
4091
+ inst['draw' + (period == 'M' ? 'Month' : 'Year')] =
4092
+ parseInt(select.options[select.selectedIndex].value,10);
4093
+ this._notifyChange(inst);
4094
+ this._adjustDate(target);
4095
+ },
4096
+
4097
+ /* Action for selecting a day. */
4098
+ _selectDay: function(id, month, year, td) {
4099
+ var target = $(id);
4100
+ if ($(td).hasClass(this._unselectableClass) || this._isDisabledDatepicker(target[0])) {
4101
+ return;
4102
+ }
4103
+ var inst = this._getInst(target[0]);
4104
+ inst.selectedDay = inst.currentDay = $('a', td).html();
4105
+ inst.selectedMonth = inst.currentMonth = month;
4106
+ inst.selectedYear = inst.currentYear = year;
4107
+ this._selectDate(id, this._formatDate(inst,
4108
+ inst.currentDay, inst.currentMonth, inst.currentYear));
4109
+ },
4110
+
4111
+ /* Erase the input field and hide the date picker. */
4112
+ _clearDate: function(id) {
4113
+ var target = $(id);
4114
+ var inst = this._getInst(target[0]);
4115
+ this._selectDate(target, '');
4116
+ },
4117
+
4118
+ /* Update the input field with the selected date. */
4119
+ _selectDate: function(id, dateStr) {
4120
+ var target = $(id);
4121
+ var inst = this._getInst(target[0]);
4122
+ dateStr = (dateStr != null ? dateStr : this._formatDate(inst));
4123
+ if (inst.input)
4124
+ inst.input.val(dateStr);
4125
+ this._updateAlternate(inst);
4126
+ var onSelect = this._get(inst, 'onSelect');
4127
+ if (onSelect)
4128
+ onSelect.apply((inst.input ? inst.input[0] : null), [dateStr, inst]); // trigger custom callback
4129
+ else if (inst.input)
4130
+ inst.input.trigger('change'); // fire the change event
4131
+ if (inst.inline)
4132
+ this._updateDatepicker(inst);
4133
+ else {
4134
+ this._hideDatepicker();
4135
+ this._lastInput = inst.input[0];
4136
+ if (typeof(inst.input[0]) != 'object')
4137
+ inst.input.focus(); // restore focus
4138
+ this._lastInput = null;
4139
+ }
4140
+ },
4141
+
4142
+ /* Update any alternate field to synchronise with the main field. */
4143
+ _updateAlternate: function(inst) {
4144
+ var altField = this._get(inst, 'altField');
4145
+ if (altField) { // update alternate field too
4146
+ var altFormat = this._get(inst, 'altFormat') || this._get(inst, 'dateFormat');
4147
+ var date = this._getDate(inst);
4148
+ var dateStr = this.formatDate(altFormat, date, this._getFormatConfig(inst));
4149
+ $(altField).each(function() { $(this).val(dateStr); });
4150
+ }
4151
+ },
4152
+
4153
+ /* Set as beforeShowDay function to prevent selection of weekends.
4154
+ @param date Date - the date to customise
4155
+ @return [boolean, string] - is this date selectable?, what is its CSS class? */
4156
+ noWeekends: function(date) {
4157
+ var day = date.getDay();
4158
+ return [(day > 0 && day < 6), ''];
4159
+ },
4160
+
4161
+ /* Set as calculateWeek to determine the week of the year based on the ISO 8601 definition.
4162
+ @param date Date - the date to get the week for
4163
+ @return number - the number of the week within the year that contains this date */
4164
+ iso8601Week: function(date) {
4165
+ var checkDate = new Date(date.getTime());
4166
+ // Find Thursday of this week starting on Monday
4167
+ checkDate.setDate(checkDate.getDate() + 4 - (checkDate.getDay() || 7));
4168
+ var time = checkDate.getTime();
4169
+ checkDate.setMonth(0); // Compare with Jan 1
4170
+ checkDate.setDate(1);
4171
+ return Math.floor(Math.round((time - checkDate) / 86400000) / 7) + 1;
4172
+ },
4173
+
4174
+ /* Parse a string value into a date object.
4175
+ See formatDate below for the possible formats.
4176
+
4177
+ @param format string - the expected format of the date
4178
+ @param value string - the date in the above format
4179
+ @param settings Object - attributes include:
4180
+ shortYearCutoff number - the cutoff year for determining the century (optional)
4181
+ dayNamesShort string[7] - abbreviated names of the days from Sunday (optional)
4182
+ dayNames string[7] - names of the days from Sunday (optional)
4183
+ monthNamesShort string[12] - abbreviated names of the months (optional)
4184
+ monthNames string[12] - names of the months (optional)
4185
+ @return Date - the extracted date value or null if value is blank */
4186
+ parseDate: function (format, value, settings) {
4187
+ if (format == null || value == null)
4188
+ throw 'Invalid arguments';
4189
+ value = (typeof value == 'object' ? value.toString() : value + '');
4190
+ if (value == '')
4191
+ return null;
4192
+ var shortYearCutoff = (settings ? settings.shortYearCutoff : null) || this._defaults.shortYearCutoff;
4193
+ shortYearCutoff = (typeof shortYearCutoff != 'string' ? shortYearCutoff :
4194
+ new Date().getFullYear() % 100 + parseInt(shortYearCutoff, 10));
4195
+ var dayNamesShort = (settings ? settings.dayNamesShort : null) || this._defaults.dayNamesShort;
4196
+ var dayNames = (settings ? settings.dayNames : null) || this._defaults.dayNames;
4197
+ var monthNamesShort = (settings ? settings.monthNamesShort : null) || this._defaults.monthNamesShort;
4198
+ var monthNames = (settings ? settings.monthNames : null) || this._defaults.monthNames;
4199
+ var year = -1;
4200
+ var month = -1;
4201
+ var day = -1;
4202
+ var doy = -1;
4203
+ var literal = false;
4204
+ // Check whether a format character is doubled
4205
+ var lookAhead = function(match) {
4206
+ var matches = (iFormat + 1 < format.length && format.charAt(iFormat + 1) == match);
4207
+ if (matches)
4208
+ iFormat++;
4209
+ return matches;
4210
+ };
4211
+ // Extract a number from the string value
4212
+ var getNumber = function(match) {
4213
+ var isDoubled = lookAhead(match);
4214
+ var size = (match == '@' ? 14 : (match == '!' ? 20 :
4215
+ (match == 'y' && isDoubled ? 4 : (match == 'o' ? 3 : 2))));
4216
+ var digits = new RegExp('^\\d{1,' + size + '}');
4217
+ var num = value.substring(iValue).match(digits);
4218
+ if (!num)
4219
+ throw 'Missing number at position ' + iValue;
4220
+ iValue += num[0].length;
4221
+ return parseInt(num[0], 10);
4222
+ };
4223
+ // Extract a name from the string value and convert to an index
4224
+ var getName = function(match, shortNames, longNames) {
4225
+ var names = $.map(lookAhead(match) ? longNames : shortNames, function (v, k) {
4226
+ return [ [k, v] ];
4227
+ }).sort(function (a, b) {
4228
+ return -(a[1].length - b[1].length);
4229
+ });
4230
+ var index = -1;
4231
+ $.each(names, function (i, pair) {
4232
+ var name = pair[1];
4233
+ if (value.substr(iValue, name.length).toLowerCase() == name.toLowerCase()) {
4234
+ index = pair[0];
4235
+ iValue += name.length;
4236
+ return false;
4237
+ }
4238
+ });
4239
+ if (index != -1)
4240
+ return index + 1;
4241
+ else
4242
+ throw 'Unknown name at position ' + iValue;
4243
+ };
4244
+ // Confirm that a literal character matches the string value
4245
+ var checkLiteral = function() {
4246
+ if (value.charAt(iValue) != format.charAt(iFormat))
4247
+ throw 'Unexpected literal at position ' + iValue;
4248
+ iValue++;
4249
+ };
4250
+ var iValue = 0;
4251
+ for (var iFormat = 0; iFormat < format.length; iFormat++) {
4252
+ if (literal)
4253
+ if (format.charAt(iFormat) == "'" && !lookAhead("'"))
4254
+ literal = false;
4255
+ else
4256
+ checkLiteral();
4257
+ else
4258
+ switch (format.charAt(iFormat)) {
4259
+ case 'd':
4260
+ day = getNumber('d');
4261
+ break;
4262
+ case 'D':
4263
+ getName('D', dayNamesShort, dayNames);
4264
+ break;
4265
+ case 'o':
4266
+ doy = getNumber('o');
4267
+ break;
4268
+ case 'm':
4269
+ month = getNumber('m');
4270
+ break;
4271
+ case 'M':
4272
+ month = getName('M', monthNamesShort, monthNames);
4273
+ break;
4274
+ case 'y':
4275
+ year = getNumber('y');
4276
+ break;
4277
+ case '@':
4278
+ var date = new Date(getNumber('@'));
4279
+ year = date.getFullYear();
4280
+ month = date.getMonth() + 1;
4281
+ day = date.getDate();
4282
+ break;
4283
+ case '!':
4284
+ var date = new Date((getNumber('!') - this._ticksTo1970) / 10000);
4285
+ year = date.getFullYear();
4286
+ month = date.getMonth() + 1;
4287
+ day = date.getDate();
4288
+ break;
4289
+ case "'":
4290
+ if (lookAhead("'"))
4291
+ checkLiteral();
4292
+ else
4293
+ literal = true;
4294
+ break;
4295
+ default:
4296
+ checkLiteral();
4297
+ }
4298
+ }
4299
+ if (iValue < value.length){
4300
+ var extra = value.substr(iValue);
4301
+ if (!/^\s+/.test(extra)) {
4302
+ throw "Extra/unparsed characters found in date: " + extra;
4303
+ }
4304
+ }
4305
+ if (year == -1)
4306
+ year = new Date().getFullYear();
4307
+ else if (year < 100)
4308
+ year += new Date().getFullYear() - new Date().getFullYear() % 100 +
4309
+ (year <= shortYearCutoff ? 0 : -100);
4310
+ if (doy > -1) {
4311
+ month = 1;
4312
+ day = doy;
4313
+ do {
4314
+ var dim = this._getDaysInMonth(year, month - 1);
4315
+ if (day <= dim)
4316
+ break;
4317
+ month++;
4318
+ day -= dim;
4319
+ } while (true);
4320
+ }
4321
+ var date = this._daylightSavingAdjust(new Date(year, month - 1, day));
4322
+ if (date.getFullYear() != year || date.getMonth() + 1 != month || date.getDate() != day)
4323
+ throw 'Invalid date'; // E.g. 31/02/00
4324
+ return date;
4325
+ },
4326
+
4327
+ /* Standard date formats. */
4328
+ ATOM: 'yy-mm-dd', // RFC 3339 (ISO 8601)
4329
+ COOKIE: 'D, dd M yy',
4330
+ ISO_8601: 'yy-mm-dd',
4331
+ RFC_822: 'D, d M y',
4332
+ RFC_850: 'DD, dd-M-y',
4333
+ RFC_1036: 'D, d M y',
4334
+ RFC_1123: 'D, d M yy',
4335
+ RFC_2822: 'D, d M yy',
4336
+ RSS: 'D, d M y', // RFC 822
4337
+ TICKS: '!',
4338
+ TIMESTAMP: '@',
4339
+ W3C: 'yy-mm-dd', // ISO 8601
4340
+
4341
+ _ticksTo1970: (((1970 - 1) * 365 + Math.floor(1970 / 4) - Math.floor(1970 / 100) +
4342
+ Math.floor(1970 / 400)) * 24 * 60 * 60 * 10000000),
4343
+
4344
+ /* Format a date object into a string value.
4345
+ The format can be combinations of the following:
4346
+ d - day of month (no leading zero)
4347
+ dd - day of month (two digit)
4348
+ o - day of year (no leading zeros)
4349
+ oo - day of year (three digit)
4350
+ D - day name short
4351
+ DD - day name long
4352
+ m - month of year (no leading zero)
4353
+ mm - month of year (two digit)
4354
+ M - month name short
4355
+ MM - month name long
4356
+ y - year (two digit)
4357
+ yy - year (four digit)
4358
+ @ - Unix timestamp (ms since 01/01/1970)
4359
+ ! - Windows ticks (100ns since 01/01/0001)
4360
+ '...' - literal text
4361
+ '' - single quote
4362
+
4363
+ @param format string - the desired format of the date
4364
+ @param date Date - the date value to format
4365
+ @param settings Object - attributes include:
4366
+ dayNamesShort string[7] - abbreviated names of the days from Sunday (optional)
4367
+ dayNames string[7] - names of the days from Sunday (optional)
4368
+ monthNamesShort string[12] - abbreviated names of the months (optional)
4369
+ monthNames string[12] - names of the months (optional)
4370
+ @return string - the date in the above format */
4371
+ formatDate: function (format, date, settings) {
4372
+ if (!date)
4373
+ return '';
4374
+ var dayNamesShort = (settings ? settings.dayNamesShort : null) || this._defaults.dayNamesShort;
4375
+ var dayNames = (settings ? settings.dayNames : null) || this._defaults.dayNames;
4376
+ var monthNamesShort = (settings ? settings.monthNamesShort : null) || this._defaults.monthNamesShort;
4377
+ var monthNames = (settings ? settings.monthNames : null) || this._defaults.monthNames;
4378
+ // Check whether a format character is doubled
4379
+ var lookAhead = function(match) {
4380
+ var matches = (iFormat + 1 < format.length && format.charAt(iFormat + 1) == match);
4381
+ if (matches)
4382
+ iFormat++;
4383
+ return matches;
4384
+ };
4385
+ // Format a number, with leading zero if necessary
4386
+ var formatNumber = function(match, value, len) {
4387
+ var num = '' + value;
4388
+ if (lookAhead(match))
4389
+ while (num.length < len)
4390
+ num = '0' + num;
4391
+ return num;
4392
+ };
4393
+ // Format a name, short or long as requested
4394
+ var formatName = function(match, value, shortNames, longNames) {
4395
+ return (lookAhead(match) ? longNames[value] : shortNames[value]);
4396
+ };
4397
+ var output = '';
4398
+ var literal = false;
4399
+ if (date)
4400
+ for (var iFormat = 0; iFormat < format.length; iFormat++) {
4401
+ if (literal)
4402
+ if (format.charAt(iFormat) == "'" && !lookAhead("'"))
4403
+ literal = false;
4404
+ else
4405
+ output += format.charAt(iFormat);
4406
+ else
4407
+ switch (format.charAt(iFormat)) {
4408
+ case 'd':
4409
+ output += formatNumber('d', date.getDate(), 2);
4410
+ break;
4411
+ case 'D':
4412
+ output += formatName('D', date.getDay(), dayNamesShort, dayNames);
4413
+ break;
4414
+ case 'o':
4415
+ output += formatNumber('o',
4416
+ Math.round((new Date(date.getFullYear(), date.getMonth(), date.getDate()).getTime() - new Date(date.getFullYear(), 0, 0).getTime()) / 86400000), 3);
4417
+ break;
4418
+ case 'm':
4419
+ output += formatNumber('m', date.getMonth() + 1, 2);
4420
+ break;
4421
+ case 'M':
4422
+ output += formatName('M', date.getMonth(), monthNamesShort, monthNames);
4423
+ break;
4424
+ case 'y':
4425
+ output += (lookAhead('y') ? date.getFullYear() :
4426
+ (date.getYear() % 100 < 10 ? '0' : '') + date.getYear() % 100);
4427
+ break;
4428
+ case '@':
4429
+ output += date.getTime();
4430
+ break;
4431
+ case '!':
4432
+ output += date.getTime() * 10000 + this._ticksTo1970;
4433
+ break;
4434
+ case "'":
4435
+ if (lookAhead("'"))
4436
+ output += "'";
4437
+ else
4438
+ literal = true;
4439
+ break;
4440
+ default:
4441
+ output += format.charAt(iFormat);
4442
+ }
4443
+ }
4444
+ return output;
4445
+ },
4446
+
4447
+ /* Extract all possible characters from the date format. */
4448
+ _possibleChars: function (format) {
4449
+ var chars = '';
4450
+ var literal = false;
4451
+ // Check whether a format character is doubled
4452
+ var lookAhead = function(match) {
4453
+ var matches = (iFormat + 1 < format.length && format.charAt(iFormat + 1) == match);
4454
+ if (matches)
4455
+ iFormat++;
4456
+ return matches;
4457
+ };
4458
+ for (var iFormat = 0; iFormat < format.length; iFormat++)
4459
+ if (literal)
4460
+ if (format.charAt(iFormat) == "'" && !lookAhead("'"))
4461
+ literal = false;
4462
+ else
4463
+ chars += format.charAt(iFormat);
4464
+ else
4465
+ switch (format.charAt(iFormat)) {
4466
+ case 'd': case 'm': case 'y': case '@':
4467
+ chars += '0123456789';
4468
+ break;
4469
+ case 'D': case 'M':
4470
+ return null; // Accept anything
4471
+ case "'":
4472
+ if (lookAhead("'"))
4473
+ chars += "'";
4474
+ else
4475
+ literal = true;
4476
+ break;
4477
+ default:
4478
+ chars += format.charAt(iFormat);
4479
+ }
4480
+ return chars;
4481
+ },
4482
+
4483
+ /* Get a setting value, defaulting if necessary. */
4484
+ _get: function(inst, name) {
4485
+ return inst.settings[name] !== undefined ?
4486
+ inst.settings[name] : this._defaults[name];
4487
+ },
4488
+
4489
+ /* Parse existing date and initialise date picker. */
4490
+ _setDateFromField: function(inst, noDefault) {
4491
+ if (inst.input.val() == inst.lastVal) {
4492
+ return;
4493
+ }
4494
+ var dateFormat = this._get(inst, 'dateFormat');
4495
+ var dates = inst.lastVal = inst.input ? inst.input.val() : null;
4496
+ var date, defaultDate;
4497
+ date = defaultDate = this._getDefaultDate(inst);
4498
+ var settings = this._getFormatConfig(inst);
4499
+ try {
4500
+ date = this.parseDate(dateFormat, dates, settings) || defaultDate;
4501
+ } catch (event) {
4502
+ this.log(event);
4503
+ dates = (noDefault ? '' : dates);
4504
+ }
4505
+ inst.selectedDay = date.getDate();
4506
+ inst.drawMonth = inst.selectedMonth = date.getMonth();
4507
+ inst.drawYear = inst.selectedYear = date.getFullYear();
4508
+ inst.currentDay = (dates ? date.getDate() : 0);
4509
+ inst.currentMonth = (dates ? date.getMonth() : 0);
4510
+ inst.currentYear = (dates ? date.getFullYear() : 0);
4511
+ this._adjustInstDate(inst);
4512
+ },
4513
+
4514
+ /* Retrieve the default date shown on opening. */
4515
+ _getDefaultDate: function(inst) {
4516
+ return this._restrictMinMax(inst,
4517
+ this._determineDate(inst, this._get(inst, 'defaultDate'), new Date()));
4518
+ },
4519
+
4520
+ /* A date may be specified as an exact value or a relative one. */
4521
+ _determineDate: function(inst, date, defaultDate) {
4522
+ var offsetNumeric = function(offset) {
4523
+ var date = new Date();
4524
+ date.setDate(date.getDate() + offset);
4525
+ return date;
4526
+ };
4527
+ var offsetString = function(offset) {
4528
+ try {
4529
+ return $.datepicker.parseDate($.datepicker._get(inst, 'dateFormat'),
4530
+ offset, $.datepicker._getFormatConfig(inst));
4531
+ }
4532
+ catch (e) {
4533
+ // Ignore
4534
+ }
4535
+ var date = (offset.toLowerCase().match(/^c/) ?
4536
+ $.datepicker._getDate(inst) : null) || new Date();
4537
+ var year = date.getFullYear();
4538
+ var month = date.getMonth();
4539
+ var day = date.getDate();
4540
+ var pattern = /([+-]?[0-9]+)\s*(d|D|w|W|m|M|y|Y)?/g;
4541
+ var matches = pattern.exec(offset);
4542
+ while (matches) {
4543
+ switch (matches[2] || 'd') {
4544
+ case 'd' : case 'D' :
4545
+ day += parseInt(matches[1],10); break;
4546
+ case 'w' : case 'W' :
4547
+ day += parseInt(matches[1],10) * 7; break;
4548
+ case 'm' : case 'M' :
4549
+ month += parseInt(matches[1],10);
4550
+ day = Math.min(day, $.datepicker._getDaysInMonth(year, month));
4551
+ break;
4552
+ case 'y': case 'Y' :
4553
+ year += parseInt(matches[1],10);
4554
+ day = Math.min(day, $.datepicker._getDaysInMonth(year, month));
4555
+ break;
4556
+ }
4557
+ matches = pattern.exec(offset);
4558
+ }
4559
+ return new Date(year, month, day);
4560
+ };
4561
+ var newDate = (date == null || date === '' ? defaultDate : (typeof date == 'string' ? offsetString(date) :
4562
+ (typeof date == 'number' ? (isNaN(date) ? defaultDate : offsetNumeric(date)) : new Date(date.getTime()))));
4563
+ newDate = (newDate && newDate.toString() == 'Invalid Date' ? defaultDate : newDate);
4564
+ if (newDate) {
4565
+ newDate.setHours(0);
4566
+ newDate.setMinutes(0);
4567
+ newDate.setSeconds(0);
4568
+ newDate.setMilliseconds(0);
4569
+ }
4570
+ return this._daylightSavingAdjust(newDate);
4571
+ },
4572
+
4573
+ /* Handle switch to/from daylight saving.
4574
+ Hours may be non-zero on daylight saving cut-over:
4575
+ > 12 when midnight changeover, but then cannot generate
4576
+ midnight datetime, so jump to 1AM, otherwise reset.
4577
+ @param date (Date) the date to check
4578
+ @return (Date) the corrected date */
4579
+ _daylightSavingAdjust: function(date) {
4580
+ if (!date) return null;
4581
+ date.setHours(date.getHours() > 12 ? date.getHours() + 2 : 0);
4582
+ return date;
4583
+ },
4584
+
4585
+ /* Set the date(s) directly. */
4586
+ _setDate: function(inst, date, noChange) {
4587
+ var clear = !date;
4588
+ var origMonth = inst.selectedMonth;
4589
+ var origYear = inst.selectedYear;
4590
+ var newDate = this._restrictMinMax(inst, this._determineDate(inst, date, new Date()));
4591
+ inst.selectedDay = inst.currentDay = newDate.getDate();
4592
+ inst.drawMonth = inst.selectedMonth = inst.currentMonth = newDate.getMonth();
4593
+ inst.drawYear = inst.selectedYear = inst.currentYear = newDate.getFullYear();
4594
+ if ((origMonth != inst.selectedMonth || origYear != inst.selectedYear) && !noChange)
4595
+ this._notifyChange(inst);
4596
+ this._adjustInstDate(inst);
4597
+ if (inst.input) {
4598
+ inst.input.val(clear ? '' : this._formatDate(inst));
4599
+ }
4600
+ },
4601
+
4602
+ /* Retrieve the date(s) directly. */
4603
+ _getDate: function(inst) {
4604
+ var startDate = (!inst.currentYear || (inst.input && inst.input.val() == '') ? null :
4605
+ this._daylightSavingAdjust(new Date(
4606
+ inst.currentYear, inst.currentMonth, inst.currentDay)));
4607
+ return startDate;
4608
+ },
4609
+
4610
+ /* Attach the onxxx handlers. These are declared statically so
4611
+ * they work with static code transformers like Caja.
4612
+ */
4613
+ _attachHandlers: function(inst) {
4614
+ var stepMonths = this._get(inst, 'stepMonths');
4615
+ var id = '#' + inst.id.replace( /\\\\/g, "\\" );
4616
+ inst.dpDiv.find('[data-handler]').map(function () {
4617
+ var handler = {
4618
+ prev: function () {
4619
+ window['DP_jQuery_' + dpuuid].datepicker._adjustDate(id, -stepMonths, 'M');
4620
+ },
4621
+ next: function () {
4622
+ window['DP_jQuery_' + dpuuid].datepicker._adjustDate(id, +stepMonths, 'M');
4623
+ },
4624
+ hide: function () {
4625
+ window['DP_jQuery_' + dpuuid].datepicker._hideDatepicker();
4626
+ },
4627
+ today: function () {
4628
+ window['DP_jQuery_' + dpuuid].datepicker._gotoToday(id);
4629
+ },
4630
+ selectDay: function () {
4631
+ window['DP_jQuery_' + dpuuid].datepicker._selectDay(id, +this.getAttribute('data-month'), +this.getAttribute('data-year'), this);
4632
+ return false;
4633
+ },
4634
+ selectMonth: function () {
4635
+ window['DP_jQuery_' + dpuuid].datepicker._selectMonthYear(id, this, 'M');
4636
+ return false;
4637
+ },
4638
+ selectYear: function () {
4639
+ window['DP_jQuery_' + dpuuid].datepicker._selectMonthYear(id, this, 'Y');
4640
+ return false;
4641
+ }
4642
+ };
4643
+ $(this).bind(this.getAttribute('data-event'), handler[this.getAttribute('data-handler')]);
4644
+ });
4645
+ },
4646
+
4647
+ /* Generate the HTML for the current state of the date picker. */
4648
+ _generateHTML: function(inst) {
4649
+ var today = new Date();
4650
+ today = this._daylightSavingAdjust(
4651
+ new Date(today.getFullYear(), today.getMonth(), today.getDate())); // clear time
4652
+ var isRTL = this._get(inst, 'isRTL');
4653
+ var showButtonPanel = this._get(inst, 'showButtonPanel');
4654
+ var hideIfNoPrevNext = this._get(inst, 'hideIfNoPrevNext');
4655
+ var navigationAsDateFormat = this._get(inst, 'navigationAsDateFormat');
4656
+ var numMonths = this._getNumberOfMonths(inst);
4657
+ var showCurrentAtPos = this._get(inst, 'showCurrentAtPos');
4658
+ var stepMonths = this._get(inst, 'stepMonths');
4659
+ var isMultiMonth = (numMonths[0] != 1 || numMonths[1] != 1);
4660
+ var currentDate = this._daylightSavingAdjust((!inst.currentDay ? new Date(9999, 9, 9) :
4661
+ new Date(inst.currentYear, inst.currentMonth, inst.currentDay)));
4662
+ var minDate = this._getMinMaxDate(inst, 'min');
4663
+ var maxDate = this._getMinMaxDate(inst, 'max');
4664
+ var drawMonth = inst.drawMonth - showCurrentAtPos;
4665
+ var drawYear = inst.drawYear;
4666
+ if (drawMonth < 0) {
4667
+ drawMonth += 12;
4668
+ drawYear--;
4669
+ }
4670
+ if (maxDate) {
4671
+ var maxDraw = this._daylightSavingAdjust(new Date(maxDate.getFullYear(),
4672
+ maxDate.getMonth() - (numMonths[0] * numMonths[1]) + 1, maxDate.getDate()));
4673
+ maxDraw = (minDate && maxDraw < minDate ? minDate : maxDraw);
4674
+ while (this._daylightSavingAdjust(new Date(drawYear, drawMonth, 1)) > maxDraw) {
4675
+ drawMonth--;
4676
+ if (drawMonth < 0) {
4677
+ drawMonth = 11;
4678
+ drawYear--;
4679
+ }
4680
+ }
4681
+ }
4682
+ inst.drawMonth = drawMonth;
4683
+ inst.drawYear = drawYear;
4684
+ var prevText = this._get(inst, 'prevText');
4685
+ prevText = (!navigationAsDateFormat ? prevText : this.formatDate(prevText,
4686
+ this._daylightSavingAdjust(new Date(drawYear, drawMonth - stepMonths, 1)),
4687
+ this._getFormatConfig(inst)));
4688
+ var prev = (this._canAdjustMonth(inst, -1, drawYear, drawMonth) ?
4689
+ '<a class="ui-datepicker-prev ui-corner-all" data-handler="prev" data-event="click"' +
4690
+ ' title="' + prevText + '"><span class="ui-icon ui-icon-circle-triangle-' + ( isRTL ? 'e' : 'w') + '">' + prevText + '</span></a>' :
4691
+ (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>'));
4692
+ var nextText = this._get(inst, 'nextText');
4693
+ nextText = (!navigationAsDateFormat ? nextText : this.formatDate(nextText,
4694
+ this._daylightSavingAdjust(new Date(drawYear, drawMonth + stepMonths, 1)),
4695
+ this._getFormatConfig(inst)));
4696
+ var next = (this._canAdjustMonth(inst, +1, drawYear, drawMonth) ?
4697
+ '<a class="ui-datepicker-next ui-corner-all" data-handler="next" data-event="click"' +
4698
+ ' title="' + nextText + '"><span class="ui-icon ui-icon-circle-triangle-' + ( isRTL ? 'w' : 'e') + '">' + nextText + '</span></a>' :
4699
+ (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>'));
4700
+ var currentText = this._get(inst, 'currentText');
4701
+ var gotoDate = (this._get(inst, 'gotoCurrent') && inst.currentDay ? currentDate : today);
4702
+ currentText = (!navigationAsDateFormat ? currentText :
4703
+ this.formatDate(currentText, gotoDate, this._getFormatConfig(inst)));
4704
+ var 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">' +
4705
+ this._get(inst, 'closeText') + '</button>' : '');
4706
+ var buttonPanel = (showButtonPanel) ? '<div class="ui-datepicker-buttonpane ui-widget-content">' + (isRTL ? controls : '') +
4707
+ (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"' +
4708
+ '>' + currentText + '</button>' : '') + (isRTL ? '' : controls) + '</div>' : '';
4709
+ var firstDay = parseInt(this._get(inst, 'firstDay'),10);
4710
+ firstDay = (isNaN(firstDay) ? 0 : firstDay);
4711
+ var showWeek = this._get(inst, 'showWeek');
4712
+ var dayNames = this._get(inst, 'dayNames');
4713
+ var dayNamesShort = this._get(inst, 'dayNamesShort');
4714
+ var dayNamesMin = this._get(inst, 'dayNamesMin');
4715
+ var monthNames = this._get(inst, 'monthNames');
4716
+ var monthNamesShort = this._get(inst, 'monthNamesShort');
4717
+ var beforeShowDay = this._get(inst, 'beforeShowDay');
4718
+ var showOtherMonths = this._get(inst, 'showOtherMonths');
4719
+ var selectOtherMonths = this._get(inst, 'selectOtherMonths');
4720
+ var calculateWeek = this._get(inst, 'calculateWeek') || this.iso8601Week;
4721
+ var defaultDate = this._getDefaultDate(inst);
4722
+ var html = '';
4723
+ for (var row = 0; row < numMonths[0]; row++) {
4724
+ var group = '';
4725
+ this.maxRows = 4;
4726
+ for (var col = 0; col < numMonths[1]; col++) {
4727
+ var selectedDate = this._daylightSavingAdjust(new Date(drawYear, drawMonth, inst.selectedDay));
4728
+ var cornerClass = ' ui-corner-all';
4729
+ var calender = '';
4730
+ if (isMultiMonth) {
4731
+ calender += '<div class="ui-datepicker-group';
4732
+ if (numMonths[1] > 1)
4733
+ switch (col) {
4734
+ case 0: calender += ' ui-datepicker-group-first';
4735
+ cornerClass = ' ui-corner-' + (isRTL ? 'right' : 'left'); break;
4736
+ case numMonths[1]-1: calender += ' ui-datepicker-group-last';
4737
+ cornerClass = ' ui-corner-' + (isRTL ? 'left' : 'right'); break;
4738
+ default: calender += ' ui-datepicker-group-middle'; cornerClass = ''; break;
4739
+ }
4740
+ calender += '">';
4741
+ }
4742
+ calender += '<div class="ui-datepicker-header ui-widget-header ui-helper-clearfix' + cornerClass + '">' +
4743
+ (/all|left/.test(cornerClass) && row == 0 ? (isRTL ? next : prev) : '') +
4744
+ (/all|right/.test(cornerClass) && row == 0 ? (isRTL ? prev : next) : '') +
4745
+ this._generateMonthYearHeader(inst, drawMonth, drawYear, minDate, maxDate,
4746
+ row > 0 || col > 0, monthNames, monthNamesShort) + // draw month headers
4747
+ '</div><table class="ui-datepicker-calendar"><thead>' +
4748
+ '<tr>';
4749
+ var thead = (showWeek ? '<th class="ui-datepicker-week-col">' + this._get(inst, 'weekHeader') + '</th>' : '');
4750
+ for (var dow = 0; dow < 7; dow++) { // days of the week
4751
+ var day = (dow + firstDay) % 7;
4752
+ thead += '<th' + ((dow + firstDay + 6) % 7 >= 5 ? ' class="ui-datepicker-week-end"' : '') + '>' +
4753
+ '<span title="' + dayNames[day] + '">' + dayNamesMin[day] + '</span></th>';
4754
+ }
4755
+ calender += thead + '</tr></thead><tbody>';
4756
+ var daysInMonth = this._getDaysInMonth(drawYear, drawMonth);
4757
+ if (drawYear == inst.selectedYear && drawMonth == inst.selectedMonth)
4758
+ inst.selectedDay = Math.min(inst.selectedDay, daysInMonth);
4759
+ var leadDays = (this._getFirstDayOfMonth(drawYear, drawMonth) - firstDay + 7) % 7;
4760
+ var curRows = Math.ceil((leadDays + daysInMonth) / 7); // calculate the number of rows to generate
4761
+ var numRows = (isMultiMonth ? this.maxRows > curRows ? this.maxRows : curRows : curRows); //If multiple months, use the higher number of rows (see #7043)
4762
+ this.maxRows = numRows;
4763
+ var printDate = this._daylightSavingAdjust(new Date(drawYear, drawMonth, 1 - leadDays));
4764
+ for (var dRow = 0; dRow < numRows; dRow++) { // create date picker rows
4765
+ calender += '<tr>';
4766
+ var tbody = (!showWeek ? '' : '<td class="ui-datepicker-week-col">' +
4767
+ this._get(inst, 'calculateWeek')(printDate) + '</td>');
4768
+ for (var dow = 0; dow < 7; dow++) { // create date picker days
4769
+ var daySettings = (beforeShowDay ?
4770
+ beforeShowDay.apply((inst.input ? inst.input[0] : null), [printDate]) : [true, '']);
4771
+ var otherMonth = (printDate.getMonth() != drawMonth);
4772
+ var unselectable = (otherMonth && !selectOtherMonths) || !daySettings[0] ||
4773
+ (minDate && printDate < minDate) || (maxDate && printDate > maxDate);
4774
+ tbody += '<td class="' +
4775
+ ((dow + firstDay + 6) % 7 >= 5 ? ' ui-datepicker-week-end' : '') + // highlight weekends
4776
+ (otherMonth ? ' ui-datepicker-other-month' : '') + // highlight days from other months
4777
+ ((printDate.getTime() == selectedDate.getTime() && drawMonth == inst.selectedMonth && inst._keyEvent) || // user pressed key
4778
+ (defaultDate.getTime() == printDate.getTime() && defaultDate.getTime() == selectedDate.getTime()) ?
4779
+ // or defaultDate is current printedDate and defaultDate is selectedDate
4780
+ ' ' + this._dayOverClass : '') + // highlight selected day
4781
+ (unselectable ? ' ' + this._unselectableClass + ' ui-state-disabled': '') + // highlight unselectable days
4782
+ (otherMonth && !showOtherMonths ? '' : ' ' + daySettings[1] + // highlight custom dates
4783
+ (printDate.getTime() == currentDate.getTime() ? ' ' + this._currentClass : '') + // highlight selected day
4784
+ (printDate.getTime() == today.getTime() ? ' ui-datepicker-today' : '')) + '"' + // highlight today (if different)
4785
+ ((!otherMonth || showOtherMonths) && daySettings[2] ? ' title="' + daySettings[2] + '"' : '') + // cell title
4786
+ (unselectable ? '' : ' data-handler="selectDay" data-event="click" data-month="' + printDate.getMonth() + '" data-year="' + printDate.getFullYear() + '"') + '>' + // actions
4787
+ (otherMonth && !showOtherMonths ? '&#xa0;' : // display for other months
4788
+ (unselectable ? '<span class="ui-state-default">' + printDate.getDate() + '</span>' : '<a class="ui-state-default' +
4789
+ (printDate.getTime() == today.getTime() ? ' ui-state-highlight' : '') +
4790
+ (printDate.getTime() == currentDate.getTime() ? ' ui-state-active' : '') + // highlight selected day
4791
+ (otherMonth ? ' ui-priority-secondary' : '') + // distinguish dates from other months
4792
+ '" href="#">' + printDate.getDate() + '</a>')) + '</td>'; // display selectable date
4793
+ printDate.setDate(printDate.getDate() + 1);
4794
+ printDate = this._daylightSavingAdjust(printDate);
4795
+ }
4796
+ calender += tbody + '</tr>';
4797
+ }
4798
+ drawMonth++;
4799
+ if (drawMonth > 11) {
4800
+ drawMonth = 0;
4801
+ drawYear++;
4802
+ }
4803
+ calender += '</tbody></table>' + (isMultiMonth ? '</div>' +
4804
+ ((numMonths[0] > 0 && col == numMonths[1]-1) ? '<div class="ui-datepicker-row-break"></div>' : '') : '');
4805
+ group += calender;
4806
+ }
4807
+ html += group;
4808
+ }
4809
+ html += buttonPanel + ($.ui.ie6 && !inst.inline ?
4810
+ '<iframe src="javascript:false;" class="ui-datepicker-cover" frameborder="0"></iframe>' : '');
4811
+ inst._keyEvent = false;
4812
+ return html;
4813
+ },
4814
+
4815
+ /* Generate the month and year header. */
4816
+ _generateMonthYearHeader: function(inst, drawMonth, drawYear, minDate, maxDate,
4817
+ secondary, monthNames, monthNamesShort) {
4818
+ var changeMonth = this._get(inst, 'changeMonth');
4819
+ var changeYear = this._get(inst, 'changeYear');
4820
+ var showMonthAfterYear = this._get(inst, 'showMonthAfterYear');
4821
+ var html = '<div class="ui-datepicker-title">';
4822
+ var monthHtml = '';
4823
+ // month selection
4824
+ if (secondary || !changeMonth)
4825
+ monthHtml += '<span class="ui-datepicker-month">' + monthNames[drawMonth] + '</span>';
4826
+ else {
4827
+ var inMinYear = (minDate && minDate.getFullYear() == drawYear);
4828
+ var inMaxYear = (maxDate && maxDate.getFullYear() == drawYear);
4829
+ monthHtml += '<select class="ui-datepicker-month" data-handler="selectMonth" data-event="change">';
4830
+ for (var month = 0; month < 12; month++) {
4831
+ if ((!inMinYear || month >= minDate.getMonth()) &&
4832
+ (!inMaxYear || month <= maxDate.getMonth()))
4833
+ monthHtml += '<option value="' + month + '"' +
4834
+ (month == drawMonth ? ' selected="selected"' : '') +
4835
+ '>' + monthNamesShort[month] + '</option>';
4836
+ }
4837
+ monthHtml += '</select>';
4838
+ }
4839
+ if (!showMonthAfterYear)
4840
+ html += monthHtml + (secondary || !(changeMonth && changeYear) ? '&#xa0;' : '');
4841
+ // year selection
4842
+ if ( !inst.yearshtml ) {
4843
+ inst.yearshtml = '';
4844
+ if (secondary || !changeYear)
4845
+ html += '<span class="ui-datepicker-year">' + drawYear + '</span>';
4846
+ else {
4847
+ // determine range of years to display
4848
+ var years = this._get(inst, 'yearRange').split(':');
4849
+ var thisYear = new Date().getFullYear();
4850
+ var determineYear = function(value) {
4851
+ var year = (value.match(/c[+-].*/) ? drawYear + parseInt(value.substring(1), 10) :
4852
+ (value.match(/[+-].*/) ? thisYear + parseInt(value, 10) :
4853
+ parseInt(value, 10)));
4854
+ return (isNaN(year) ? thisYear : year);
4855
+ };
4856
+ var year = determineYear(years[0]);
4857
+ var endYear = Math.max(year, determineYear(years[1] || ''));
4858
+ year = (minDate ? Math.max(year, minDate.getFullYear()) : year);
4859
+ endYear = (maxDate ? Math.min(endYear, maxDate.getFullYear()) : endYear);
4860
+ inst.yearshtml += '<select class="ui-datepicker-year" data-handler="selectYear" data-event="change">';
4861
+ for (; year <= endYear; year++) {
4862
+ inst.yearshtml += '<option value="' + year + '"' +
4863
+ (year == drawYear ? ' selected="selected"' : '') +
4864
+ '>' + year + '</option>';
4865
+ }
4866
+ inst.yearshtml += '</select>';
4867
+
4868
+ html += inst.yearshtml;
4869
+ inst.yearshtml = null;
4870
+ }
4871
+ }
4872
+ html += this._get(inst, 'yearSuffix');
4873
+ if (showMonthAfterYear)
4874
+ html += (secondary || !(changeMonth && changeYear) ? '&#xa0;' : '') + monthHtml;
4875
+ html += '</div>'; // Close datepicker_header
4876
+ return html;
4877
+ },
4878
+
4879
+ /* Adjust one of the date sub-fields. */
4880
+ _adjustInstDate: function(inst, offset, period) {
4881
+ var year = inst.drawYear + (period == 'Y' ? offset : 0);
4882
+ var month = inst.drawMonth + (period == 'M' ? offset : 0);
4883
+ var day = Math.min(inst.selectedDay, this._getDaysInMonth(year, month)) +
4884
+ (period == 'D' ? offset : 0);
4885
+ var date = this._restrictMinMax(inst,
4886
+ this._daylightSavingAdjust(new Date(year, month, day)));
4887
+ inst.selectedDay = date.getDate();
4888
+ inst.drawMonth = inst.selectedMonth = date.getMonth();
4889
+ inst.drawYear = inst.selectedYear = date.getFullYear();
4890
+ if (period == 'M' || period == 'Y')
4891
+ this._notifyChange(inst);
4892
+ },
4893
+
4894
+ /* Ensure a date is within any min/max bounds. */
4895
+ _restrictMinMax: function(inst, date) {
4896
+ var minDate = this._getMinMaxDate(inst, 'min');
4897
+ var maxDate = this._getMinMaxDate(inst, 'max');
4898
+ var newDate = (minDate && date < minDate ? minDate : date);
4899
+ newDate = (maxDate && newDate > maxDate ? maxDate : newDate);
4900
+ return newDate;
4901
+ },
4902
+
4903
+ /* Notify change of month/year. */
4904
+ _notifyChange: function(inst) {
4905
+ var onChange = this._get(inst, 'onChangeMonthYear');
4906
+ if (onChange)
4907
+ onChange.apply((inst.input ? inst.input[0] : null),
4908
+ [inst.selectedYear, inst.selectedMonth + 1, inst]);
4909
+ },
4910
+
4911
+ /* Determine the number of months to show. */
4912
+ _getNumberOfMonths: function(inst) {
4913
+ var numMonths = this._get(inst, 'numberOfMonths');
4914
+ return (numMonths == null ? [1, 1] : (typeof numMonths == 'number' ? [1, numMonths] : numMonths));
4915
+ },
4916
+
4917
+ /* Determine the current maximum date - ensure no time components are set. */
4918
+ _getMinMaxDate: function(inst, minMax) {
4919
+ return this._determineDate(inst, this._get(inst, minMax + 'Date'), null);
4920
+ },
4921
+
4922
+ /* Find the number of days in a given month. */
4923
+ _getDaysInMonth: function(year, month) {
4924
+ return 32 - this._daylightSavingAdjust(new Date(year, month, 32)).getDate();
4925
+ },
4926
+
4927
+ /* Find the day of the week of the first of a month. */
4928
+ _getFirstDayOfMonth: function(year, month) {
4929
+ return new Date(year, month, 1).getDay();
4930
+ },
4931
+
4932
+ /* Determines if we should allow a "next/prev" month display change. */
4933
+ _canAdjustMonth: function(inst, offset, curYear, curMonth) {
4934
+ var numMonths = this._getNumberOfMonths(inst);
4935
+ var date = this._daylightSavingAdjust(new Date(curYear,
4936
+ curMonth + (offset < 0 ? offset : numMonths[0] * numMonths[1]), 1));
4937
+ if (offset < 0)
4938
+ date.setDate(this._getDaysInMonth(date.getFullYear(), date.getMonth()));
4939
+ return this._isInRange(inst, date);
4940
+ },
4941
+
4942
+ /* Is the given date in the accepted range? */
4943
+ _isInRange: function(inst, date) {
4944
+ var minDate = this._getMinMaxDate(inst, 'min');
4945
+ var maxDate = this._getMinMaxDate(inst, 'max');
4946
+ return ((!minDate || date.getTime() >= minDate.getTime()) &&
4947
+ (!maxDate || date.getTime() <= maxDate.getTime()));
4948
+ },
4949
+
4950
+ /* Provide the configuration settings for formatting/parsing. */
4951
+ _getFormatConfig: function(inst) {
4952
+ var shortYearCutoff = this._get(inst, 'shortYearCutoff');
4953
+ shortYearCutoff = (typeof shortYearCutoff != 'string' ? shortYearCutoff :
4954
+ new Date().getFullYear() % 100 + parseInt(shortYearCutoff, 10));
4955
+ return {shortYearCutoff: shortYearCutoff,
4956
+ dayNamesShort: this._get(inst, 'dayNamesShort'), dayNames: this._get(inst, 'dayNames'),
4957
+ monthNamesShort: this._get(inst, 'monthNamesShort'), monthNames: this._get(inst, 'monthNames')};
4958
+ },
4959
+
4960
+ /* Format the given date for display. */
4961
+ _formatDate: function(inst, day, month, year) {
4962
+ if (!day) {
4963
+ inst.currentDay = inst.selectedDay;
4964
+ inst.currentMonth = inst.selectedMonth;
4965
+ inst.currentYear = inst.selectedYear;
4966
+ }
4967
+ var date = (day ? (typeof day == 'object' ? day :
4968
+ this._daylightSavingAdjust(new Date(year, month, day))) :
4969
+ this._daylightSavingAdjust(new Date(inst.currentYear, inst.currentMonth, inst.currentDay)));
4970
+ return this.formatDate(this._get(inst, 'dateFormat'), date, this._getFormatConfig(inst));
4971
+ }
4972
+ });
4973
+
4974
+ /*
4975
+ * Bind hover events for datepicker elements.
4976
+ * Done via delegate so the binding only occurs once in the lifetime of the parent div.
4977
+ * Global instActive, set by _updateDatepicker allows the handlers to find their way back to the active picker.
4978
+ */
4979
+ function bindHover(dpDiv) {
4980
+ var selector = 'button, .ui-datepicker-prev, .ui-datepicker-next, .ui-datepicker-calendar td a';
4981
+ return dpDiv.delegate(selector, 'mouseout', function() {
4982
+ $(this).removeClass('ui-state-hover');
4983
+ if (this.className.indexOf('ui-datepicker-prev') != -1) $(this).removeClass('ui-datepicker-prev-hover');
4984
+ if (this.className.indexOf('ui-datepicker-next') != -1) $(this).removeClass('ui-datepicker-next-hover');
4985
+ })
4986
+ .delegate(selector, 'mouseover', function(){
4987
+ if (!$.datepicker._isDisabledDatepicker( instActive.inline ? dpDiv.parent()[0] : instActive.input[0])) {
4988
+ $(this).parents('.ui-datepicker-calendar').find('a').removeClass('ui-state-hover');
4989
+ $(this).addClass('ui-state-hover');
4990
+ if (this.className.indexOf('ui-datepicker-prev') != -1) $(this).addClass('ui-datepicker-prev-hover');
4991
+ if (this.className.indexOf('ui-datepicker-next') != -1) $(this).addClass('ui-datepicker-next-hover');
4992
+ }
4993
+ });
4994
+ }
4995
+
4996
+ /* jQuery extend now ignores nulls! */
4997
+ function extendRemove(target, props) {
4998
+ $.extend(target, props);
4999
+ for (var name in props)
5000
+ if (props[name] == null || props[name] == undefined)
5001
+ target[name] = props[name];
5002
+ return target;
5003
+ };
5004
+
5005
+ /* Invoke the datepicker functionality.
5006
+ @param options string - a command, optionally followed by additional parameters or
5007
+ Object - settings for attaching new datepicker functionality
5008
+ @return jQuery object */
5009
+ $.fn.datepicker = function(options){
5010
+
5011
+ /* Verify an empty collection wasn't passed - Fixes #6976 */
5012
+ if ( !this.length ) {
5013
+ return this;
5014
+ }
5015
+
5016
+ /* Initialise the date picker. */
5017
+ if (!$.datepicker.initialized) {
5018
+ $(document).mousedown($.datepicker._checkExternalClick).
5019
+ find(document.body).append($.datepicker.dpDiv);
5020
+ $.datepicker.initialized = true;
5021
+ }
5022
+
5023
+ var otherArgs = Array.prototype.slice.call(arguments, 1);
5024
+ if (typeof options == 'string' && (options == 'isDisabled' || options == 'getDate' || options == 'widget'))
5025
+ return $.datepicker['_' + options + 'Datepicker'].
5026
+ apply($.datepicker, [this[0]].concat(otherArgs));
5027
+ if (options == 'option' && arguments.length == 2 && typeof arguments[1] == 'string')
5028
+ return $.datepicker['_' + options + 'Datepicker'].
5029
+ apply($.datepicker, [this[0]].concat(otherArgs));
5030
+ return this.each(function() {
5031
+ typeof options == 'string' ?
5032
+ $.datepicker['_' + options + 'Datepicker'].
5033
+ apply($.datepicker, [this].concat(otherArgs)) :
5034
+ $.datepicker._attachDatepicker(this, options);
5035
+ });
5036
+ };
5037
+
5038
+ $.datepicker = new Datepicker(); // singleton instance
5039
+ $.datepicker.initialized = false;
5040
+ $.datepicker.uuid = new Date().getTime();
5041
+ $.datepicker.version = "1.9.1";
5042
+
5043
+ // Workaround for #4055
5044
+ // Add another global to avoid noConflict issues with inline event handlers
5045
+ window['DP_jQuery_' + dpuuid] = $;
5046
+
5047
+ })(jQuery);
5048
+ (function( $, undefined ) {
5049
+
5050
+ var uiDialogClasses = "ui-dialog ui-widget ui-widget-content ui-corner-all ",
5051
+ sizeRelatedOptions = {
5052
+ buttons: true,
5053
+ height: true,
5054
+ maxHeight: true,
5055
+ maxWidth: true,
5056
+ minHeight: true,
5057
+ minWidth: true,
5058
+ width: true
5059
+ },
5060
+ resizableRelatedOptions = {
5061
+ maxHeight: true,
5062
+ maxWidth: true,
5063
+ minHeight: true,
5064
+ minWidth: true
5065
+ };
5066
+
5067
+ $.widget("ui.dialog", {
5068
+ version: "1.9.1",
5069
+ options: {
5070
+ autoOpen: true,
5071
+ buttons: {},
5072
+ closeOnEscape: true,
5073
+ closeText: "close",
5074
+ dialogClass: "",
5075
+ draggable: true,
5076
+ hide: null,
5077
+ height: "auto",
5078
+ maxHeight: false,
5079
+ maxWidth: false,
5080
+ minHeight: 150,
5081
+ minWidth: 150,
5082
+ modal: false,
5083
+ position: {
5084
+ my: "center",
5085
+ at: "center",
5086
+ of: window,
5087
+ collision: "fit",
5088
+ // ensure that the titlebar is never outside the document
5089
+ using: function( pos ) {
5090
+ var topOffset = $( this ).css( pos ).offset().top;
5091
+ if ( topOffset < 0 ) {
5092
+ $( this ).css( "top", pos.top - topOffset );
5093
+ }
5094
+ }
5095
+ },
5096
+ resizable: true,
5097
+ show: null,
5098
+ stack: true,
5099
+ title: "",
5100
+ width: 300,
5101
+ zIndex: 1000
5102
+ },
5103
+
5104
+ _create: function() {
5105
+ this.originalTitle = this.element.attr( "title" );
5106
+ // #5742 - .attr() might return a DOMElement
5107
+ if ( typeof this.originalTitle !== "string" ) {
5108
+ this.originalTitle = "";
5109
+ }
5110
+ this.oldPosition = {
5111
+ parent: this.element.parent(),
5112
+ index: this.element.parent().children().index( this.element )
5113
+ };
5114
+ this.options.title = this.options.title || this.originalTitle;
5115
+ var that = this,
5116
+ options = this.options,
5117
+
5118
+ title = options.title || "&#160;",
5119
+ uiDialog,
5120
+ uiDialogTitlebar,
5121
+ uiDialogTitlebarClose,
5122
+ uiDialogTitle,
5123
+ uiDialogButtonPane;
5124
+
5125
+ uiDialog = ( this.uiDialog = $( "<div>" ) )
5126
+ .addClass( uiDialogClasses + options.dialogClass )
5127
+ .css({
5128
+ display: "none",
5129
+ outline: 0, // TODO: move to stylesheet
5130
+ zIndex: options.zIndex
5131
+ })
5132
+ // setting tabIndex makes the div focusable
5133
+ .attr( "tabIndex", -1)
5134
+ .keydown(function( event ) {
5135
+ if ( options.closeOnEscape && !event.isDefaultPrevented() && event.keyCode &&
5136
+ event.keyCode === $.ui.keyCode.ESCAPE ) {
5137
+ that.close( event );
5138
+ event.preventDefault();
5139
+ }
5140
+ })
5141
+ .mousedown(function( event ) {
5142
+ that.moveToTop( false, event );
5143
+ })
5144
+ .appendTo( "body" );
5145
+
5146
+ this.element
5147
+ .show()
5148
+ .removeAttr( "title" )
5149
+ .addClass( "ui-dialog-content ui-widget-content" )
5150
+ .appendTo( uiDialog );
5151
+
5152
+ uiDialogTitlebar = ( this.uiDialogTitlebar = $( "<div>" ) )
5153
+ .addClass( "ui-dialog-titlebar ui-widget-header " +
5154
+ "ui-corner-all ui-helper-clearfix" )
5155
+ .bind( "mousedown", function() {
5156
+ // Dialog isn't getting focus when dragging (#8063)
5157
+ uiDialog.focus();
5158
+ })
5159
+ .prependTo( uiDialog );
5160
+
5161
+ uiDialogTitlebarClose = $( "<a href='#'></a>" )
5162
+ .addClass( "ui-dialog-titlebar-close ui-corner-all" )
5163
+ .attr( "role", "button" )
5164
+ .click(function( event ) {
5165
+ event.preventDefault();
5166
+ that.close( event );
5167
+ })
5168
+ .appendTo( uiDialogTitlebar );
5169
+
5170
+ ( this.uiDialogTitlebarCloseText = $( "<span>" ) )
5171
+ .addClass( "ui-icon ui-icon-closethick" )
5172
+ .text( options.closeText )
5173
+ .appendTo( uiDialogTitlebarClose );
5174
+
5175
+ uiDialogTitle = $( "<span>" )
5176
+ .uniqueId()
5177
+ .addClass( "ui-dialog-title" )
5178
+ .html( title )
5179
+ .prependTo( uiDialogTitlebar );
5180
+
5181
+ uiDialogButtonPane = ( this.uiDialogButtonPane = $( "<div>" ) )
5182
+ .addClass( "ui-dialog-buttonpane ui-widget-content ui-helper-clearfix" );
5183
+
5184
+ ( this.uiButtonSet = $( "<div>" ) )
5185
+ .addClass( "ui-dialog-buttonset" )
5186
+ .appendTo( uiDialogButtonPane );
5187
+
5188
+ uiDialog.attr({
5189
+ role: "dialog",
5190
+ "aria-labelledby": uiDialogTitle.attr( "id" )
5191
+ });
5192
+
5193
+ uiDialogTitlebar.find( "*" ).add( uiDialogTitlebar ).disableSelection();
5194
+ this._hoverable( uiDialogTitlebarClose );
5195
+ this._focusable( uiDialogTitlebarClose );
5196
+
5197
+ if ( options.draggable && $.fn.draggable ) {
5198
+ this._makeDraggable();
5199
+ }
5200
+ if ( options.resizable && $.fn.resizable ) {
5201
+ this._makeResizable();
5202
+ }
5203
+
5204
+ this._createButtons( options.buttons );
5205
+ this._isOpen = false;
5206
+
5207
+ if ( $.fn.bgiframe ) {
5208
+ uiDialog.bgiframe();
5209
+ }
5210
+
5211
+ // prevent tabbing out of modal dialogs
5212
+ this._on( uiDialog, { keydown: function( event ) {
5213
+ if ( !options.modal || event.keyCode !== $.ui.keyCode.TAB ) {
5214
+ return;
5215
+ }
5216
+
5217
+ var tabbables = $( ":tabbable", uiDialog ),
5218
+ first = tabbables.filter( ":first" ),
5219
+ last = tabbables.filter( ":last" );
5220
+
5221
+ if ( event.target === last[0] && !event.shiftKey ) {
5222
+ first.focus( 1 );
5223
+ return false;
5224
+ } else if ( event.target === first[0] && event.shiftKey ) {
5225
+ last.focus( 1 );
5226
+ return false;
5227
+ }
5228
+ }});
5229
+ },
5230
+
5231
+ _init: function() {
5232
+ if ( this.options.autoOpen ) {
5233
+ this.open();
5234
+ }
5235
+ },
5236
+
5237
+ _destroy: function() {
5238
+ var next,
5239
+ oldPosition = this.oldPosition;
5240
+
5241
+ if ( this.overlay ) {
5242
+ this.overlay.destroy();
5243
+ }
5244
+ this.uiDialog.hide();
5245
+ this.element
5246
+ .removeClass( "ui-dialog-content ui-widget-content" )
5247
+ .hide()
5248
+ .appendTo( "body" );
5249
+ this.uiDialog.remove();
5250
+
5251
+ if ( this.originalTitle ) {
5252
+ this.element.attr( "title", this.originalTitle );
5253
+ }
5254
+
5255
+ next = oldPosition.parent.children().eq( oldPosition.index );
5256
+ // Don't try to place the dialog next to itself (#8613)
5257
+ if ( next.length && next[ 0 ] !== this.element[ 0 ] ) {
5258
+ next.before( this.element );
5259
+ } else {
5260
+ oldPosition.parent.append( this.element );
5261
+ }
5262
+ },
5263
+
5264
+ widget: function() {
5265
+ return this.uiDialog;
5266
+ },
5267
+
5268
+ close: function( event ) {
5269
+ var that = this,
5270
+ maxZ, thisZ;
5271
+
5272
+ if ( !this._isOpen ) {
5273
+ return;
5274
+ }
5275
+
5276
+ if ( false === this._trigger( "beforeClose", event ) ) {
5277
+ return;
5278
+ }
5279
+
5280
+ this._isOpen = false;
5281
+
5282
+ if ( this.overlay ) {
5283
+ this.overlay.destroy();
5284
+ }
5285
+
5286
+ if ( this.options.hide ) {
5287
+ this._hide( this.uiDialog, this.options.hide, function() {
5288
+ that._trigger( "close", event );
5289
+ });
5290
+ } else {
5291
+ this.uiDialog.hide();
5292
+ this._trigger( "close", event );
5293
+ }
5294
+
5295
+ $.ui.dialog.overlay.resize();
5296
+
5297
+ // adjust the maxZ to allow other modal dialogs to continue to work (see #4309)
5298
+ if ( this.options.modal ) {
5299
+ maxZ = 0;
5300
+ $( ".ui-dialog" ).each(function() {
5301
+ if ( this !== that.uiDialog[0] ) {
5302
+ thisZ = $( this ).css( "z-index" );
5303
+ if ( !isNaN( thisZ ) ) {
5304
+ maxZ = Math.max( maxZ, thisZ );
5305
+ }
5306
+ }
5307
+ });
5308
+ $.ui.dialog.maxZ = maxZ;
5309
+ }
5310
+
5311
+ return this;
5312
+ },
5313
+
5314
+ isOpen: function() {
5315
+ return this._isOpen;
5316
+ },
5317
+
5318
+ // the force parameter allows us to move modal dialogs to their correct
5319
+ // position on open
5320
+ moveToTop: function( force, event ) {
5321
+ var options = this.options,
5322
+ saveScroll;
5323
+
5324
+ if ( ( options.modal && !force ) ||
5325
+ ( !options.stack && !options.modal ) ) {
5326
+ return this._trigger( "focus", event );
5327
+ }
5328
+
5329
+ if ( options.zIndex > $.ui.dialog.maxZ ) {
5330
+ $.ui.dialog.maxZ = options.zIndex;
5331
+ }
5332
+ if ( this.overlay ) {
5333
+ $.ui.dialog.maxZ += 1;
5334
+ $.ui.dialog.overlay.maxZ = $.ui.dialog.maxZ;
5335
+ this.overlay.$el.css( "z-index", $.ui.dialog.overlay.maxZ );
5336
+ }
5337
+
5338
+ // Save and then restore scroll
5339
+ // Opera 9.5+ resets when parent z-index is changed.
5340
+ // http://bugs.jqueryui.com/ticket/3193
5341
+ saveScroll = {
5342
+ scrollTop: this.element.scrollTop(),
5343
+ scrollLeft: this.element.scrollLeft()
5344
+ };
5345
+ $.ui.dialog.maxZ += 1;
5346
+ this.uiDialog.css( "z-index", $.ui.dialog.maxZ );
5347
+ this.element.attr( saveScroll );
5348
+ this._trigger( "focus", event );
5349
+
5350
+ return this;
5351
+ },
5352
+
5353
+ open: function() {
5354
+ if ( this._isOpen ) {
5355
+ return;
5356
+ }
5357
+
5358
+ var hasFocus,
5359
+ options = this.options,
5360
+ uiDialog = this.uiDialog;
5361
+
5362
+ this._size();
5363
+ this._position( options.position );
5364
+ uiDialog.show( options.show );
5365
+ this.overlay = options.modal ? new $.ui.dialog.overlay( this ) : null;
5366
+ this.moveToTop( true );
5367
+
5368
+ // set focus to the first tabbable element in the content area or the first button
5369
+ // if there are no tabbable elements, set focus on the dialog itself
5370
+ hasFocus = this.element.find( ":tabbable" );
5371
+ if ( !hasFocus.length ) {
5372
+ hasFocus = this.uiDialogButtonPane.find( ":tabbable" );
5373
+ if ( !hasFocus.length ) {
5374
+ hasFocus = uiDialog;
5375
+ }
5376
+ }
5377
+ hasFocus.eq( 0 ).focus();
5378
+
5379
+ this._isOpen = true;
5380
+ this._trigger( "open" );
5381
+
5382
+ return this;
5383
+ },
5384
+
5385
+ _createButtons: function( buttons ) {
5386
+ var that = this,
5387
+ hasButtons = false;
5388
+
5389
+ // if we already have a button pane, remove it
5390
+ this.uiDialogButtonPane.remove();
5391
+ this.uiButtonSet.empty();
5392
+
5393
+ if ( typeof buttons === "object" && buttons !== null ) {
5394
+ $.each( buttons, function() {
5395
+ return !(hasButtons = true);
5396
+ });
5397
+ }
5398
+ if ( hasButtons ) {
5399
+ $.each( buttons, function( name, props ) {
5400
+ props = $.isFunction( props ) ?
5401
+ { click: props, text: name } :
5402
+ props;
5403
+ var button = $( "<button type='button'></button>" )
5404
+ .attr( props, true )
5405
+ .unbind( "click" )
5406
+ .click(function() {
5407
+ props.click.apply( that.element[0], arguments );
5408
+ })
5409
+ .appendTo( that.uiButtonSet );
5410
+ if ( $.fn.button ) {
5411
+ button.button();
5412
+ }
5413
+ });
5414
+ this.uiDialog.addClass( "ui-dialog-buttons" );
5415
+ this.uiDialogButtonPane.appendTo( this.uiDialog );
5416
+ } else {
5417
+ this.uiDialog.removeClass( "ui-dialog-buttons" );
5418
+ }
5419
+ },
5420
+
5421
+ _makeDraggable: function() {
5422
+ var that = this,
5423
+ options = this.options;
5424
+
5425
+ function filteredUi( ui ) {
5426
+ return {
5427
+ position: ui.position,
5428
+ offset: ui.offset
5429
+ };
5430
+ }
5431
+
5432
+ this.uiDialog.draggable({
5433
+ cancel: ".ui-dialog-content, .ui-dialog-titlebar-close",
5434
+ handle: ".ui-dialog-titlebar",
5435
+ containment: "document",
5436
+ start: function( event, ui ) {
5437
+ $( this )
5438
+ .addClass( "ui-dialog-dragging" );
5439
+ that._trigger( "dragStart", event, filteredUi( ui ) );
5440
+ },
5441
+ drag: function( event, ui ) {
5442
+ that._trigger( "drag", event, filteredUi( ui ) );
5443
+ },
5444
+ stop: function( event, ui ) {
5445
+ options.position = [
5446
+ ui.position.left - that.document.scrollLeft(),
5447
+ ui.position.top - that.document.scrollTop()
5448
+ ];
5449
+ $( this )
5450
+ .removeClass( "ui-dialog-dragging" );
5451
+ that._trigger( "dragStop", event, filteredUi( ui ) );
5452
+ $.ui.dialog.overlay.resize();
5453
+ }
5454
+ });
5455
+ },
5456
+
5457
+ _makeResizable: function( handles ) {
5458
+ handles = (handles === undefined ? this.options.resizable : handles);
5459
+ var that = this,
5460
+ options = this.options,
5461
+ // .ui-resizable has position: relative defined in the stylesheet
5462
+ // but dialogs have to use absolute or fixed positioning
5463
+ position = this.uiDialog.css( "position" ),
5464
+ resizeHandles = typeof handles === 'string' ?
5465
+ handles :
5466
+ "n,e,s,w,se,sw,ne,nw";
5467
+
5468
+ function filteredUi( ui ) {
5469
+ return {
5470
+ originalPosition: ui.originalPosition,
5471
+ originalSize: ui.originalSize,
5472
+ position: ui.position,
5473
+ size: ui.size
5474
+ };
5475
+ }
5476
+
5477
+ this.uiDialog.resizable({
5478
+ cancel: ".ui-dialog-content",
5479
+ containment: "document",
5480
+ alsoResize: this.element,
5481
+ maxWidth: options.maxWidth,
5482
+ maxHeight: options.maxHeight,
5483
+ minWidth: options.minWidth,
5484
+ minHeight: this._minHeight(),
5485
+ handles: resizeHandles,
5486
+ start: function( event, ui ) {
5487
+ $( this ).addClass( "ui-dialog-resizing" );
5488
+ that._trigger( "resizeStart", event, filteredUi( ui ) );
5489
+ },
5490
+ resize: function( event, ui ) {
5491
+ that._trigger( "resize", event, filteredUi( ui ) );
5492
+ },
5493
+ stop: function( event, ui ) {
5494
+ $( this ).removeClass( "ui-dialog-resizing" );
5495
+ options.height = $( this ).height();
5496
+ options.width = $( this ).width();
5497
+ that._trigger( "resizeStop", event, filteredUi( ui ) );
5498
+ $.ui.dialog.overlay.resize();
5499
+ }
5500
+ })
5501
+ .css( "position", position )
5502
+ .find( ".ui-resizable-se" )
5503
+ .addClass( "ui-icon ui-icon-grip-diagonal-se" );
5504
+ },
5505
+
5506
+ _minHeight: function() {
5507
+ var options = this.options;
5508
+
5509
+ if ( options.height === "auto" ) {
5510
+ return options.minHeight;
5511
+ } else {
5512
+ return Math.min( options.minHeight, options.height );
5513
+ }
5514
+ },
5515
+
5516
+ _position: function( position ) {
5517
+ var myAt = [],
5518
+ offset = [ 0, 0 ],
5519
+ isVisible;
5520
+
5521
+ if ( position ) {
5522
+ // deep extending converts arrays to objects in jQuery <= 1.3.2 :-(
5523
+ // if (typeof position == 'string' || $.isArray(position)) {
5524
+ // myAt = $.isArray(position) ? position : position.split(' ');
5525
+
5526
+ if ( typeof position === "string" || (typeof position === "object" && "0" in position ) ) {
5527
+ myAt = position.split ? position.split( " " ) : [ position[ 0 ], position[ 1 ] ];
5528
+ if ( myAt.length === 1 ) {
5529
+ myAt[ 1 ] = myAt[ 0 ];
5530
+ }
5531
+
5532
+ $.each( [ "left", "top" ], function( i, offsetPosition ) {
5533
+ if ( +myAt[ i ] === myAt[ i ] ) {
5534
+ offset[ i ] = myAt[ i ];
5535
+ myAt[ i ] = offsetPosition;
5536
+ }
5537
+ });
5538
+
5539
+ position = {
5540
+ my: myAt[0] + (offset[0] < 0 ? offset[0] : "+" + offset[0]) + " " +
5541
+ myAt[1] + (offset[1] < 0 ? offset[1] : "+" + offset[1]),
5542
+ at: myAt.join( " " )
5543
+ };
5544
+ }
5545
+
5546
+ position = $.extend( {}, $.ui.dialog.prototype.options.position, position );
5547
+ } else {
5548
+ position = $.ui.dialog.prototype.options.position;
5549
+ }
5550
+
5551
+ // need to show the dialog to get the actual offset in the position plugin
5552
+ isVisible = this.uiDialog.is( ":visible" );
5553
+ if ( !isVisible ) {
5554
+ this.uiDialog.show();
5555
+ }
5556
+ this.uiDialog.position( position );
5557
+ if ( !isVisible ) {
5558
+ this.uiDialog.hide();
5559
+ }
5560
+ },
5561
+
5562
+ _setOptions: function( options ) {
5563
+ var that = this,
5564
+ resizableOptions = {},
5565
+ resize = false;
5566
+
5567
+ $.each( options, function( key, value ) {
5568
+ that._setOption( key, value );
5569
+
5570
+ if ( key in sizeRelatedOptions ) {
5571
+ resize = true;
5572
+ }
5573
+ if ( key in resizableRelatedOptions ) {
5574
+ resizableOptions[ key ] = value;
5575
+ }
5576
+ });
5577
+
5578
+ if ( resize ) {
5579
+ this._size();
5580
+ }
5581
+ if ( this.uiDialog.is( ":data(resizable)" ) ) {
5582
+ this.uiDialog.resizable( "option", resizableOptions );
5583
+ }
5584
+ },
5585
+
5586
+ _setOption: function( key, value ) {
5587
+ var isDraggable, isResizable,
5588
+ uiDialog = this.uiDialog;
5589
+
5590
+ switch ( key ) {
5591
+ case "buttons":
5592
+ this._createButtons( value );
5593
+ break;
5594
+ case "closeText":
5595
+ // ensure that we always pass a string
5596
+ this.uiDialogTitlebarCloseText.text( "" + value );
5597
+ break;
5598
+ case "dialogClass":
5599
+ uiDialog
5600
+ .removeClass( this.options.dialogClass )
5601
+ .addClass( uiDialogClasses + value );
5602
+ break;
5603
+ case "disabled":
5604
+ if ( value ) {
5605
+ uiDialog.addClass( "ui-dialog-disabled" );
5606
+ } else {
5607
+ uiDialog.removeClass( "ui-dialog-disabled" );
5608
+ }
5609
+ break;
5610
+ case "draggable":
5611
+ isDraggable = uiDialog.is( ":data(draggable)" );
5612
+ if ( isDraggable && !value ) {
5613
+ uiDialog.draggable( "destroy" );
5614
+ }
5615
+
5616
+ if ( !isDraggable && value ) {
5617
+ this._makeDraggable();
5618
+ }
5619
+ break;
5620
+ case "position":
5621
+ this._position( value );
5622
+ break;
5623
+ case "resizable":
5624
+ // currently resizable, becoming non-resizable
5625
+ isResizable = uiDialog.is( ":data(resizable)" );
5626
+ if ( isResizable && !value ) {
5627
+ uiDialog.resizable( "destroy" );
5628
+ }
5629
+
5630
+ // currently resizable, changing handles
5631
+ if ( isResizable && typeof value === "string" ) {
5632
+ uiDialog.resizable( "option", "handles", value );
5633
+ }
5634
+
5635
+ // currently non-resizable, becoming resizable
5636
+ if ( !isResizable && value !== false ) {
5637
+ this._makeResizable( value );
5638
+ }
5639
+ break;
5640
+ case "title":
5641
+ // convert whatever was passed in o a string, for html() to not throw up
5642
+ $( ".ui-dialog-title", this.uiDialogTitlebar )
5643
+ .html( "" + ( value || "&#160;" ) );
5644
+ break;
5645
+ }
5646
+
5647
+ this._super( key, value );
5648
+ },
5649
+
5650
+ _size: function() {
5651
+ /* If the user has resized the dialog, the .ui-dialog and .ui-dialog-content
5652
+ * divs will both have width and height set, so we need to reset them
5653
+ */
5654
+ var nonContentHeight, minContentHeight, autoHeight,
5655
+ options = this.options,
5656
+ isVisible = this.uiDialog.is( ":visible" );
5657
+
5658
+ // reset content sizing
5659
+ this.element.show().css({
5660
+ width: "auto",
5661
+ minHeight: 0,
5662
+ height: 0
5663
+ });
5664
+
5665
+ if ( options.minWidth > options.width ) {
5666
+ options.width = options.minWidth;
5667
+ }
5668
+
5669
+ // reset wrapper sizing
5670
+ // determine the height of all the non-content elements
5671
+ nonContentHeight = this.uiDialog.css({
5672
+ height: "auto",
5673
+ width: options.width
5674
+ })
5675
+ .outerHeight();
5676
+ minContentHeight = Math.max( 0, options.minHeight - nonContentHeight );
5677
+
5678
+ if ( options.height === "auto" ) {
5679
+ // only needed for IE6 support
5680
+ if ( $.support.minHeight ) {
5681
+ this.element.css({
5682
+ minHeight: minContentHeight,
5683
+ height: "auto"
5684
+ });
5685
+ } else {
5686
+ this.uiDialog.show();
5687
+ autoHeight = this.element.css( "height", "auto" ).height();
5688
+ if ( !isVisible ) {
5689
+ this.uiDialog.hide();
5690
+ }
5691
+ this.element.height( Math.max( autoHeight, minContentHeight ) );
5692
+ }
5693
+ } else {
5694
+ this.element.height( Math.max( options.height - nonContentHeight, 0 ) );
5695
+ }
5696
+
5697
+ if (this.uiDialog.is( ":data(resizable)" ) ) {
5698
+ this.uiDialog.resizable( "option", "minHeight", this._minHeight() );
5699
+ }
5700
+ }
5701
+ });
5702
+
5703
+ $.extend($.ui.dialog, {
5704
+ uuid: 0,
5705
+ maxZ: 0,
5706
+
5707
+ getTitleId: function($el) {
5708
+ var id = $el.attr( "id" );
5709
+ if ( !id ) {
5710
+ this.uuid += 1;
5711
+ id = this.uuid;
5712
+ }
5713
+ return "ui-dialog-title-" + id;
5714
+ },
5715
+
5716
+ overlay: function( dialog ) {
5717
+ this.$el = $.ui.dialog.overlay.create( dialog );
5718
+ }
5719
+ });
5720
+
5721
+ $.extend( $.ui.dialog.overlay, {
5722
+ instances: [],
5723
+ // reuse old instances due to IE memory leak with alpha transparency (see #5185)
5724
+ oldInstances: [],
5725
+ maxZ: 0,
5726
+ events: $.map(
5727
+ "focus,mousedown,mouseup,keydown,keypress,click".split( "," ),
5728
+ function( event ) {
5729
+ return event + ".dialog-overlay";
5730
+ }
5731
+ ).join( " " ),
5732
+ create: function( dialog ) {
5733
+ if ( this.instances.length === 0 ) {
5734
+ // prevent use of anchors and inputs
5735
+ // we use a setTimeout in case the overlay is created from an
5736
+ // event that we're going to be cancelling (see #2804)
5737
+ setTimeout(function() {
5738
+ // handle $(el).dialog().dialog('close') (see #4065)
5739
+ if ( $.ui.dialog.overlay.instances.length ) {
5740
+ $( document ).bind( $.ui.dialog.overlay.events, function( event ) {
5741
+ // stop events if the z-index of the target is < the z-index of the overlay
5742
+ // we cannot return true when we don't want to cancel the event (#3523)
5743
+ if ( $( event.target ).zIndex() < $.ui.dialog.overlay.maxZ ) {
5744
+ return false;
5745
+ }
5746
+ });
5747
+ }
5748
+ }, 1 );
5749
+
5750
+ // handle window resize
5751
+ $( window ).bind( "resize.dialog-overlay", $.ui.dialog.overlay.resize );
5752
+ }
5753
+
5754
+ var $el = ( this.oldInstances.pop() || $( "<div>" ).addClass( "ui-widget-overlay" ) );
5755
+
5756
+ // allow closing by pressing the escape key
5757
+ $( document ).bind( "keydown.dialog-overlay", function( event ) {
5758
+ var instances = $.ui.dialog.overlay.instances;
5759
+ // only react to the event if we're the top overlay
5760
+ if ( instances.length !== 0 && instances[ instances.length - 1 ] === $el &&
5761
+ dialog.options.closeOnEscape && !event.isDefaultPrevented() && event.keyCode &&
5762
+ event.keyCode === $.ui.keyCode.ESCAPE ) {
5763
+
5764
+ dialog.close( event );
5765
+ event.preventDefault();
5766
+ }
5767
+ });
5768
+
5769
+ $el.appendTo( document.body ).css({
5770
+ width: this.width(),
5771
+ height: this.height()
5772
+ });
5773
+
5774
+ if ( $.fn.bgiframe ) {
5775
+ $el.bgiframe();
5776
+ }
5777
+
5778
+ this.instances.push( $el );
5779
+ return $el;
5780
+ },
5781
+
5782
+ destroy: function( $el ) {
5783
+ var indexOf = $.inArray( $el, this.instances ),
5784
+ maxZ = 0;
5785
+
5786
+ if ( indexOf !== -1 ) {
5787
+ this.oldInstances.push( this.instances.splice( indexOf, 1 )[ 0 ] );
5788
+ }
5789
+
5790
+ if ( this.instances.length === 0 ) {
5791
+ $( [ document, window ] ).unbind( ".dialog-overlay" );
5792
+ }
5793
+
5794
+ $el.height( 0 ).width( 0 ).remove();
5795
+
5796
+ // adjust the maxZ to allow other modal dialogs to continue to work (see #4309)
5797
+ $.each( this.instances, function() {
5798
+ maxZ = Math.max( maxZ, this.css( "z-index" ) );
5799
+ });
5800
+ this.maxZ = maxZ;
5801
+ },
5802
+
5803
+ height: function() {
5804
+ var scrollHeight,
5805
+ offsetHeight;
5806
+ // handle IE
5807
+ if ( $.ui.ie ) {
5808
+ scrollHeight = Math.max(
5809
+ document.documentElement.scrollHeight,
5810
+ document.body.scrollHeight
5811
+ );
5812
+ offsetHeight = Math.max(
5813
+ document.documentElement.offsetHeight,
5814
+ document.body.offsetHeight
5815
+ );
5816
+
5817
+ if ( scrollHeight < offsetHeight ) {
5818
+ return $( window ).height() + "px";
5819
+ } else {
5820
+ return scrollHeight + "px";
5821
+ }
5822
+ // handle "good" browsers
5823
+ } else {
5824
+ return $( document ).height() + "px";
5825
+ }
5826
+ },
5827
+
5828
+ width: function() {
5829
+ var scrollWidth,
5830
+ offsetWidth;
5831
+ // handle IE
5832
+ if ( $.ui.ie ) {
5833
+ scrollWidth = Math.max(
5834
+ document.documentElement.scrollWidth,
5835
+ document.body.scrollWidth
5836
+ );
5837
+ offsetWidth = Math.max(
5838
+ document.documentElement.offsetWidth,
5839
+ document.body.offsetWidth
5840
+ );
5841
+
5842
+ if ( scrollWidth < offsetWidth ) {
5843
+ return $( window ).width() + "px";
5844
+ } else {
5845
+ return scrollWidth + "px";
5846
+ }
5847
+ // handle "good" browsers
5848
+ } else {
5849
+ return $( document ).width() + "px";
5850
+ }
5851
+ },
5852
+
5853
+ resize: function() {
5854
+ /* If the dialog is draggable and the user drags it past the
5855
+ * right edge of the window, the document becomes wider so we
5856
+ * need to stretch the overlay. If the user then drags the
5857
+ * dialog back to the left, the document will become narrower,
5858
+ * so we need to shrink the overlay to the appropriate size.
5859
+ * This is handled by shrinking the overlay before setting it
5860
+ * to the full document size.
5861
+ */
5862
+ var $overlays = $( [] );
5863
+ $.each( $.ui.dialog.overlay.instances, function() {
5864
+ $overlays = $overlays.add( this );
5865
+ });
5866
+
5867
+ $overlays.css({
5868
+ width: 0,
5869
+ height: 0
5870
+ }).css({
5871
+ width: $.ui.dialog.overlay.width(),
5872
+ height: $.ui.dialog.overlay.height()
5873
+ });
5874
+ }
5875
+ });
5876
+
5877
+ $.extend( $.ui.dialog.overlay.prototype, {
5878
+ destroy: function() {
5879
+ $.ui.dialog.overlay.destroy( this.$el );
5880
+ }
5881
+ });
5882
+
5883
+ }( jQuery ) );
5884
+ (function( $, undefined ) {
5885
+
5886
+ $.widget("ui.draggable", $.ui.mouse, {
5887
+ version: "1.9.1",
5888
+ widgetEventPrefix: "drag",
5889
+ options: {
5890
+ addClasses: true,
5891
+ appendTo: "parent",
5892
+ axis: false,
5893
+ connectToSortable: false,
5894
+ containment: false,
5895
+ cursor: "auto",
5896
+ cursorAt: false,
5897
+ grid: false,
5898
+ handle: false,
5899
+ helper: "original",
5900
+ iframeFix: false,
5901
+ opacity: false,
5902
+ refreshPositions: false,
5903
+ revert: false,
5904
+ revertDuration: 500,
5905
+ scope: "default",
5906
+ scroll: true,
5907
+ scrollSensitivity: 20,
5908
+ scrollSpeed: 20,
5909
+ snap: false,
5910
+ snapMode: "both",
5911
+ snapTolerance: 20,
5912
+ stack: false,
5913
+ zIndex: false
5914
+ },
5915
+ _create: function() {
5916
+
5917
+ if (this.options.helper == 'original' && !(/^(?:r|a|f)/).test(this.element.css("position")))
5918
+ this.element[0].style.position = 'relative';
5919
+
5920
+ (this.options.addClasses && this.element.addClass("ui-draggable"));
5921
+ (this.options.disabled && this.element.addClass("ui-draggable-disabled"));
5922
+
5923
+ this._mouseInit();
5924
+
5925
+ },
5926
+
5927
+ _destroy: function() {
5928
+ this.element.removeClass( "ui-draggable ui-draggable-dragging ui-draggable-disabled" );
5929
+ this._mouseDestroy();
5930
+ },
5931
+
5932
+ _mouseCapture: function(event) {
5933
+
5934
+ var o = this.options;
5935
+
5936
+ // among others, prevent a drag on a resizable-handle
5937
+ if (this.helper || o.disabled || $(event.target).is('.ui-resizable-handle'))
5938
+ return false;
5939
+
5940
+ //Quit if we're not on a valid handle
5941
+ this.handle = this._getHandle(event);
5942
+ if (!this.handle)
5943
+ return false;
5944
+
5945
+ $(o.iframeFix === true ? "iframe" : o.iframeFix).each(function() {
5946
+ $('<div class="ui-draggable-iframeFix" style="background: #fff;"></div>')
5947
+ .css({
5948
+ width: this.offsetWidth+"px", height: this.offsetHeight+"px",
5949
+ position: "absolute", opacity: "0.001", zIndex: 1000
5950
+ })
5951
+ .css($(this).offset())
5952
+ .appendTo("body");
5953
+ });
5954
+
5955
+ return true;
5956
+
5957
+ },
5958
+
5959
+ _mouseStart: function(event) {
5960
+
5961
+ var o = this.options;
5962
+
5963
+ //Create and append the visible helper
5964
+ this.helper = this._createHelper(event);
5965
+
5966
+ this.helper.addClass("ui-draggable-dragging");
5967
+
5968
+ //Cache the helper size
5969
+ this._cacheHelperProportions();
5970
+
5971
+ //If ddmanager is used for droppables, set the global draggable
5972
+ if($.ui.ddmanager)
5973
+ $.ui.ddmanager.current = this;
5974
+
5975
+ /*
5976
+ * - Position generation -
5977
+ * This block generates everything position related - it's the core of draggables.
5978
+ */
5979
+
5980
+ //Cache the margins of the original element
5981
+ this._cacheMargins();
5982
+
5983
+ //Store the helper's css position
5984
+ this.cssPosition = this.helper.css("position");
5985
+ this.scrollParent = this.helper.scrollParent();
5986
+
5987
+ //The element's absolute position on the page minus margins
5988
+ this.offset = this.positionAbs = this.element.offset();
5989
+ this.offset = {
5990
+ top: this.offset.top - this.margins.top,
5991
+ left: this.offset.left - this.margins.left
5992
+ };
5993
+
5994
+ $.extend(this.offset, {
5995
+ click: { //Where the click happened, relative to the element
5996
+ left: event.pageX - this.offset.left,
5997
+ top: event.pageY - this.offset.top
5998
+ },
5999
+ parent: this._getParentOffset(),
6000
+ relative: this._getRelativeOffset() //This is a relative to absolute position minus the actual position calculation - only used for relative positioned helper
6001
+ });
6002
+
6003
+ //Generate the original position
6004
+ this.originalPosition = this.position = this._generatePosition(event);
6005
+ this.originalPageX = event.pageX;
6006
+ this.originalPageY = event.pageY;
6007
+
6008
+ //Adjust the mouse offset relative to the helper if 'cursorAt' is supplied
6009
+ (o.cursorAt && this._adjustOffsetFromHelper(o.cursorAt));
6010
+
6011
+ //Set a containment if given in the options
6012
+ if(o.containment)
6013
+ this._setContainment();
6014
+
6015
+ //Trigger event + callbacks
6016
+ if(this._trigger("start", event) === false) {
6017
+ this._clear();
6018
+ return false;
6019
+ }
6020
+
6021
+ //Recache the helper size
6022
+ this._cacheHelperProportions();
6023
+
6024
+ //Prepare the droppable offsets
6025
+ if ($.ui.ddmanager && !o.dropBehaviour)
6026
+ $.ui.ddmanager.prepareOffsets(this, event);
6027
+
6028
+
6029
+ this._mouseDrag(event, true); //Execute the drag once - this causes the helper not to be visible before getting its correct position
6030
+
6031
+ //If the ddmanager is used for droppables, inform the manager that dragging has started (see #5003)
6032
+ if ( $.ui.ddmanager ) $.ui.ddmanager.dragStart(this, event);
6033
+
6034
+ return true;
6035
+ },
6036
+
6037
+ _mouseDrag: function(event, noPropagation) {
6038
+
6039
+ //Compute the helpers position
6040
+ this.position = this._generatePosition(event);
6041
+ this.positionAbs = this._convertPositionTo("absolute");
6042
+
6043
+ //Call plugins and callbacks and use the resulting position if something is returned
6044
+ if (!noPropagation) {
6045
+ var ui = this._uiHash();
6046
+ if(this._trigger('drag', event, ui) === false) {
6047
+ this._mouseUp({});
6048
+ return false;
6049
+ }
6050
+ this.position = ui.position;
6051
+ }
6052
+
6053
+ if(!this.options.axis || this.options.axis != "y") this.helper[0].style.left = this.position.left+'px';
6054
+ if(!this.options.axis || this.options.axis != "x") this.helper[0].style.top = this.position.top+'px';
6055
+ if($.ui.ddmanager) $.ui.ddmanager.drag(this, event);
6056
+
6057
+ return false;
6058
+ },
6059
+
6060
+ _mouseStop: function(event) {
6061
+
6062
+ //If we are using droppables, inform the manager about the drop
6063
+ var dropped = false;
6064
+ if ($.ui.ddmanager && !this.options.dropBehaviour)
6065
+ dropped = $.ui.ddmanager.drop(this, event);
6066
+
6067
+ //if a drop comes from outside (a sortable)
6068
+ if(this.dropped) {
6069
+ dropped = this.dropped;
6070
+ this.dropped = false;
6071
+ }
6072
+
6073
+ //if the original element is no longer in the DOM don't bother to continue (see #8269)
6074
+ var element = this.element[0], elementInDom = false;
6075
+ while ( element && (element = element.parentNode) ) {
6076
+ if (element == document ) {
6077
+ elementInDom = true;
6078
+ }
6079
+ }
6080
+ if ( !elementInDom && this.options.helper === "original" )
6081
+ return false;
6082
+
6083
+ 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))) {
6084
+ var that = this;
6085
+ $(this.helper).animate(this.originalPosition, parseInt(this.options.revertDuration, 10), function() {
6086
+ if(that._trigger("stop", event) !== false) {
6087
+ that._clear();
6088
+ }
6089
+ });
6090
+ } else {
6091
+ if(this._trigger("stop", event) !== false) {
6092
+ this._clear();
6093
+ }
6094
+ }
6095
+
6096
+ return false;
6097
+ },
6098
+
6099
+ _mouseUp: function(event) {
6100
+ //Remove frame helpers
6101
+ $("div.ui-draggable-iframeFix").each(function() {
6102
+ this.parentNode.removeChild(this);
6103
+ });
6104
+
6105
+ //If the ddmanager is used for droppables, inform the manager that dragging has stopped (see #5003)
6106
+ if( $.ui.ddmanager ) $.ui.ddmanager.dragStop(this, event);
6107
+
6108
+ return $.ui.mouse.prototype._mouseUp.call(this, event);
6109
+ },
6110
+
6111
+ cancel: function() {
6112
+
6113
+ if(this.helper.is(".ui-draggable-dragging")) {
6114
+ this._mouseUp({});
6115
+ } else {
6116
+ this._clear();
6117
+ }
6118
+
6119
+ return this;
6120
+
6121
+ },
6122
+
6123
+ _getHandle: function(event) {
6124
+
6125
+ var handle = !this.options.handle || !$(this.options.handle, this.element).length ? true : false;
6126
+ $(this.options.handle, this.element)
6127
+ .find("*")
6128
+ .andSelf()
6129
+ .each(function() {
6130
+ if(this == event.target) handle = true;
6131
+ });
6132
+
6133
+ return handle;
6134
+
6135
+ },
6136
+
6137
+ _createHelper: function(event) {
6138
+
6139
+ var o = this.options;
6140
+ var helper = $.isFunction(o.helper) ? $(o.helper.apply(this.element[0], [event])) : (o.helper == 'clone' ? this.element.clone().removeAttr('id') : this.element);
6141
+
6142
+ if(!helper.parents('body').length)
6143
+ helper.appendTo((o.appendTo == 'parent' ? this.element[0].parentNode : o.appendTo));
6144
+
6145
+ if(helper[0] != this.element[0] && !(/(fixed|absolute)/).test(helper.css("position")))
6146
+ helper.css("position", "absolute");
6147
+
6148
+ return helper;
6149
+
6150
+ },
6151
+
6152
+ _adjustOffsetFromHelper: function(obj) {
6153
+ if (typeof obj == 'string') {
6154
+ obj = obj.split(' ');
6155
+ }
6156
+ if ($.isArray(obj)) {
6157
+ obj = {left: +obj[0], top: +obj[1] || 0};
6158
+ }
6159
+ if ('left' in obj) {
6160
+ this.offset.click.left = obj.left + this.margins.left;
6161
+ }
6162
+ if ('right' in obj) {
6163
+ this.offset.click.left = this.helperProportions.width - obj.right + this.margins.left;
6164
+ }
6165
+ if ('top' in obj) {
6166
+ this.offset.click.top = obj.top + this.margins.top;
6167
+ }
6168
+ if ('bottom' in obj) {
6169
+ this.offset.click.top = this.helperProportions.height - obj.bottom + this.margins.top;
6170
+ }
6171
+ },
6172
+
6173
+ _getParentOffset: function() {
6174
+
6175
+ //Get the offsetParent and cache its position
6176
+ this.offsetParent = this.helper.offsetParent();
6177
+ var po = this.offsetParent.offset();
6178
+
6179
+ // This is a special case where we need to modify a offset calculated on start, since the following happened:
6180
+ // 1. The position of the helper is absolute, so it's position is calculated based on the next positioned parent
6181
+ // 2. The actual offset parent is a child of the scroll parent, and the scroll parent isn't the document, which means that
6182
+ // the scroll is included in the initial calculation of the offset of the parent, and never recalculated upon drag
6183
+ if(this.cssPosition == 'absolute' && this.scrollParent[0] != document && $.contains(this.scrollParent[0], this.offsetParent[0])) {
6184
+ po.left += this.scrollParent.scrollLeft();
6185
+ po.top += this.scrollParent.scrollTop();
6186
+ }
6187
+
6188
+ if((this.offsetParent[0] == document.body) //This needs to be actually done for all browsers, since pageX/pageY includes this information
6189
+ || (this.offsetParent[0].tagName && this.offsetParent[0].tagName.toLowerCase() == 'html' && $.ui.ie)) //Ugly IE fix
6190
+ po = { top: 0, left: 0 };
6191
+
6192
+ return {
6193
+ top: po.top + (parseInt(this.offsetParent.css("borderTopWidth"),10) || 0),
6194
+ left: po.left + (parseInt(this.offsetParent.css("borderLeftWidth"),10) || 0)
6195
+ };
6196
+
6197
+ },
6198
+
6199
+ _getRelativeOffset: function() {
6200
+
6201
+ if(this.cssPosition == "relative") {
6202
+ var p = this.element.position();
6203
+ return {
6204
+ top: p.top - (parseInt(this.helper.css("top"),10) || 0) + this.scrollParent.scrollTop(),
6205
+ left: p.left - (parseInt(this.helper.css("left"),10) || 0) + this.scrollParent.scrollLeft()
6206
+ };
6207
+ } else {
6208
+ return { top: 0, left: 0 };
6209
+ }
6210
+
6211
+ },
6212
+
6213
+ _cacheMargins: function() {
6214
+ this.margins = {
6215
+ left: (parseInt(this.element.css("marginLeft"),10) || 0),
6216
+ top: (parseInt(this.element.css("marginTop"),10) || 0),
6217
+ right: (parseInt(this.element.css("marginRight"),10) || 0),
6218
+ bottom: (parseInt(this.element.css("marginBottom"),10) || 0)
6219
+ };
6220
+ },
6221
+
6222
+ _cacheHelperProportions: function() {
6223
+ this.helperProportions = {
6224
+ width: this.helper.outerWidth(),
6225
+ height: this.helper.outerHeight()
6226
+ };
6227
+ },
6228
+
6229
+ _setContainment: function() {
6230
+
6231
+ var o = this.options;
6232
+ if(o.containment == 'parent') o.containment = this.helper[0].parentNode;
6233
+ if(o.containment == 'document' || o.containment == 'window') this.containment = [
6234
+ o.containment == 'document' ? 0 : $(window).scrollLeft() - this.offset.relative.left - this.offset.parent.left,
6235
+ o.containment == 'document' ? 0 : $(window).scrollTop() - this.offset.relative.top - this.offset.parent.top,
6236
+ (o.containment == 'document' ? 0 : $(window).scrollLeft()) + $(o.containment == 'document' ? document : window).width() - this.helperProportions.width - this.margins.left,
6237
+ (o.containment == 'document' ? 0 : $(window).scrollTop()) + ($(o.containment == 'document' ? document : window).height() || document.body.parentNode.scrollHeight) - this.helperProportions.height - this.margins.top
6238
+ ];
6239
+
6240
+ if(!(/^(document|window|parent)$/).test(o.containment) && o.containment.constructor != Array) {
6241
+ var c = $(o.containment);
6242
+ var ce = c[0]; if(!ce) return;
6243
+ var co = c.offset();
6244
+ var over = ($(ce).css("overflow") != 'hidden');
6245
+
6246
+ this.containment = [
6247
+ (parseInt($(ce).css("borderLeftWidth"),10) || 0) + (parseInt($(ce).css("paddingLeft"),10) || 0),
6248
+ (parseInt($(ce).css("borderTopWidth"),10) || 0) + (parseInt($(ce).css("paddingTop"),10) || 0),
6249
+ (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 - this.margins.right,
6250
+ (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 - this.margins.bottom
6251
+ ];
6252
+ this.relative_container = c;
6253
+
6254
+ } else if(o.containment.constructor == Array) {
6255
+ this.containment = o.containment;
6256
+ }
6257
+
6258
+ },
6259
+
6260
+ _convertPositionTo: function(d, pos) {
6261
+
6262
+ if(!pos) pos = this.position;
6263
+ var mod = d == "absolute" ? 1 : -1;
6264
+ var o = this.options, 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);
6265
+
6266
+ return {
6267
+ top: (
6268
+ pos.top // The absolute mouse position
6269
+ + this.offset.relative.top * mod // Only for relative positioned nodes: Relative offset from element to offset parent
6270
+ + this.offset.parent.top * mod // The offsetParent's offset without borders (offset + border)
6271
+ - ( ( this.cssPosition == 'fixed' ? -this.scrollParent.scrollTop() : ( scrollIsRootNode ? 0 : scroll.scrollTop() ) ) * mod)
6272
+ ),
6273
+ left: (
6274
+ pos.left // The absolute mouse position
6275
+ + this.offset.relative.left * mod // Only for relative positioned nodes: Relative offset from element to offset parent
6276
+ + this.offset.parent.left * mod // The offsetParent's offset without borders (offset + border)
6277
+ - ( ( this.cssPosition == 'fixed' ? -this.scrollParent.scrollLeft() : scrollIsRootNode ? 0 : scroll.scrollLeft() ) * mod)
6278
+ )
6279
+ };
6280
+
6281
+ },
6282
+
6283
+ _generatePosition: function(event) {
6284
+
6285
+ var o = this.options, 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);
6286
+ var pageX = event.pageX;
6287
+ var pageY = event.pageY;
6288
+
6289
+ /*
6290
+ * - Position constraining -
6291
+ * Constrain the position to a mix of grid, containment.
6292
+ */
6293
+
6294
+ if(this.originalPosition) { //If we are not dragging yet, we won't check for options
6295
+ var containment;
6296
+ if(this.containment) {
6297
+ if (this.relative_container){
6298
+ var co = this.relative_container.offset();
6299
+ containment = [ this.containment[0] + co.left,
6300
+ this.containment[1] + co.top,
6301
+ this.containment[2] + co.left,
6302
+ this.containment[3] + co.top ];
6303
+ }
6304
+ else {
6305
+ containment = this.containment;
6306
+ }
6307
+
6308
+ if(event.pageX - this.offset.click.left < containment[0]) pageX = containment[0] + this.offset.click.left;
6309
+ if(event.pageY - this.offset.click.top < containment[1]) pageY = containment[1] + this.offset.click.top;
6310
+ if(event.pageX - this.offset.click.left > containment[2]) pageX = containment[2] + this.offset.click.left;
6311
+ if(event.pageY - this.offset.click.top > containment[3]) pageY = containment[3] + this.offset.click.top;
6312
+ }
6313
+
6314
+ if(o.grid) {
6315
+ //Check for grid elements set to 0 to prevent divide by 0 error causing invalid argument errors in IE (see ticket #6950)
6316
+ var top = o.grid[1] ? this.originalPageY + Math.round((pageY - this.originalPageY) / o.grid[1]) * o.grid[1] : this.originalPageY;
6317
+ 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;
6318
+
6319
+ var left = o.grid[0] ? this.originalPageX + Math.round((pageX - this.originalPageX) / o.grid[0]) * o.grid[0] : this.originalPageX;
6320
+ 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;
6321
+ }
6322
+
6323
+ }
6324
+
6325
+ return {
6326
+ top: (
6327
+ pageY // The absolute mouse position
6328
+ - this.offset.click.top // Click offset (relative to the element)
6329
+ - this.offset.relative.top // Only for relative positioned nodes: Relative offset from element to offset parent
6330
+ - this.offset.parent.top // The offsetParent's offset without borders (offset + border)
6331
+ + ( ( this.cssPosition == 'fixed' ? -this.scrollParent.scrollTop() : ( scrollIsRootNode ? 0 : scroll.scrollTop() ) ))
6332
+ ),
6333
+ left: (
6334
+ pageX // The absolute mouse position
6335
+ - this.offset.click.left // Click offset (relative to the element)
6336
+ - this.offset.relative.left // Only for relative positioned nodes: Relative offset from element to offset parent
6337
+ - this.offset.parent.left // The offsetParent's offset without borders (offset + border)
6338
+ + ( ( this.cssPosition == 'fixed' ? -this.scrollParent.scrollLeft() : scrollIsRootNode ? 0 : scroll.scrollLeft() ))
6339
+ )
6340
+ };
6341
+
6342
+ },
6343
+
6344
+ _clear: function() {
6345
+ this.helper.removeClass("ui-draggable-dragging");
6346
+ if(this.helper[0] != this.element[0] && !this.cancelHelperRemoval) this.helper.remove();
6347
+ //if($.ui.ddmanager) $.ui.ddmanager.current = null;
6348
+ this.helper = null;
6349
+ this.cancelHelperRemoval = false;
6350
+ },
6351
+
6352
+ // From now on bulk stuff - mainly helpers
6353
+
6354
+ _trigger: function(type, event, ui) {
6355
+ ui = ui || this._uiHash();
6356
+ $.ui.plugin.call(this, type, [event, ui]);
6357
+ if(type == "drag") this.positionAbs = this._convertPositionTo("absolute"); //The absolute position has to be recalculated after plugins
6358
+ return $.Widget.prototype._trigger.call(this, type, event, ui);
6359
+ },
6360
+
6361
+ plugins: {},
6362
+
6363
+ _uiHash: function(event) {
6364
+ return {
6365
+ helper: this.helper,
6366
+ position: this.position,
6367
+ originalPosition: this.originalPosition,
6368
+ offset: this.positionAbs
6369
+ };
6370
+ }
6371
+
6372
+ });
6373
+
6374
+ $.ui.plugin.add("draggable", "connectToSortable", {
6375
+ start: function(event, ui) {
6376
+
6377
+ var inst = $(this).data("draggable"), o = inst.options,
6378
+ uiSortable = $.extend({}, ui, { item: inst.element });
6379
+ inst.sortables = [];
6380
+ $(o.connectToSortable).each(function() {
6381
+ var sortable = $.data(this, 'sortable');
6382
+ if (sortable && !sortable.options.disabled) {
6383
+ inst.sortables.push({
6384
+ instance: sortable,
6385
+ shouldRevert: sortable.options.revert
6386
+ });
6387
+ 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).
6388
+ sortable._trigger("activate", event, uiSortable);
6389
+ }
6390
+ });
6391
+
6392
+ },
6393
+ stop: function(event, ui) {
6394
+
6395
+ //If we are still over the sortable, we fake the stop event of the sortable, but also remove helper
6396
+ var inst = $(this).data("draggable"),
6397
+ uiSortable = $.extend({}, ui, { item: inst.element });
6398
+
6399
+ $.each(inst.sortables, function() {
6400
+ if(this.instance.isOver) {
6401
+
6402
+ this.instance.isOver = 0;
6403
+
6404
+ inst.cancelHelperRemoval = true; //Don't remove the helper in the draggable instance
6405
+ this.instance.cancelHelperRemoval = false; //Remove it in the sortable instance (so sortable plugins like revert still work)
6406
+
6407
+ //The sortable revert is supported, and we have to set a temporary dropped variable on the draggable to support revert: 'valid/invalid'
6408
+ if(this.shouldRevert) this.instance.options.revert = true;
6409
+
6410
+ //Trigger the stop of the sortable
6411
+ this.instance._mouseStop(event);
6412
+
6413
+ this.instance.options.helper = this.instance.options._helper;
6414
+
6415
+ //If the helper has been the original item, restore properties in the sortable
6416
+ if(inst.options.helper == 'original')
6417
+ this.instance.currentItem.css({ top: 'auto', left: 'auto' });
6418
+
6419
+ } else {
6420
+ this.instance.cancelHelperRemoval = false; //Remove the helper in the sortable instance
6421
+ this.instance._trigger("deactivate", event, uiSortable);
6422
+ }
6423
+
6424
+ });
6425
+
6426
+ },
6427
+ drag: function(event, ui) {
6428
+
6429
+ var inst = $(this).data("draggable"), that = this;
6430
+
6431
+ var checkPos = function(o) {
6432
+ var dyClick = this.offset.click.top, dxClick = this.offset.click.left;
6433
+ var helperTop = this.positionAbs.top, helperLeft = this.positionAbs.left;
6434
+ var itemHeight = o.height, itemWidth = o.width;
6435
+ var itemTop = o.top, itemLeft = o.left;
6436
+
6437
+ return $.ui.isOver(helperTop + dyClick, helperLeft + dxClick, itemTop, itemLeft, itemHeight, itemWidth);
6438
+ };
6439
+
6440
+ $.each(inst.sortables, function(i) {
6441
+
6442
+ var innermostIntersecting = false;
6443
+ var thisSortable = this;
6444
+ //Copy over some variables to allow calling the sortable's native _intersectsWith
6445
+ this.instance.positionAbs = inst.positionAbs;
6446
+ this.instance.helperProportions = inst.helperProportions;
6447
+ this.instance.offset.click = inst.offset.click;
6448
+
6449
+ if(this.instance._intersectsWith(this.instance.containerCache)) {
6450
+ innermostIntersecting = true;
6451
+ $.each(inst.sortables, function () {
6452
+ this.instance.positionAbs = inst.positionAbs;
6453
+ this.instance.helperProportions = inst.helperProportions;
6454
+ this.instance.offset.click = inst.offset.click;
6455
+ if (this != thisSortable
6456
+ && this.instance._intersectsWith(this.instance.containerCache)
6457
+ && $.ui.contains(thisSortable.instance.element[0], this.instance.element[0]))
6458
+ innermostIntersecting = false;
6459
+ return innermostIntersecting;
6460
+ });
6461
+ }
6462
+
6463
+
6464
+ if(innermostIntersecting) {
6465
+ //If it intersects, we use a little isOver variable and set it once, so our move-in stuff gets fired only once
6466
+ if(!this.instance.isOver) {
6467
+
6468
+ this.instance.isOver = 1;
6469
+ //Now we fake the start of dragging for the sortable instance,
6470
+ //by cloning the list group item, appending it to the sortable and using it as inst.currentItem
6471
+ //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)
6472
+ this.instance.currentItem = $(that).clone().removeAttr('id').appendTo(this.instance.element).data("sortable-item", true);
6473
+ this.instance.options._helper = this.instance.options.helper; //Store helper option to later restore it
6474
+ this.instance.options.helper = function() { return ui.helper[0]; };
6475
+
6476
+ event.target = this.instance.currentItem[0];
6477
+ this.instance._mouseCapture(event, true);
6478
+ this.instance._mouseStart(event, true, true);
6479
+
6480
+ //Because the browser event is way off the new appended portlet, we modify a couple of variables to reflect the changes
6481
+ this.instance.offset.click.top = inst.offset.click.top;
6482
+ this.instance.offset.click.left = inst.offset.click.left;
6483
+ this.instance.offset.parent.left -= inst.offset.parent.left - this.instance.offset.parent.left;
6484
+ this.instance.offset.parent.top -= inst.offset.parent.top - this.instance.offset.parent.top;
6485
+
6486
+ inst._trigger("toSortable", event);
6487
+ inst.dropped = this.instance.element; //draggable revert needs that
6488
+ //hack so receive/update callbacks work (mostly)
6489
+ inst.currentItem = inst.element;
6490
+ this.instance.fromOutside = inst;
6491
+
6492
+ }
6493
+
6494
+ //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
6495
+ if(this.instance.currentItem) this.instance._mouseDrag(event);
6496
+
6497
+ } else {
6498
+
6499
+ //If it doesn't intersect with the sortable, and it intersected before,
6500
+ //we fake the drag stop of the sortable, but make sure it doesn't remove the helper by using cancelHelperRemoval
6501
+ if(this.instance.isOver) {
6502
+
6503
+ this.instance.isOver = 0;
6504
+ this.instance.cancelHelperRemoval = true;
6505
+
6506
+ //Prevent reverting on this forced stop
6507
+ this.instance.options.revert = false;
6508
+
6509
+ // The out event needs to be triggered independently
6510
+ this.instance._trigger('out', event, this.instance._uiHash(this.instance));
6511
+
6512
+ this.instance._mouseStop(event, true);
6513
+ this.instance.options.helper = this.instance.options._helper;
6514
+
6515
+ //Now we remove our currentItem, the list group clone again, and the placeholder, and animate the helper back to it's original size
6516
+ this.instance.currentItem.remove();
6517
+ if(this.instance.placeholder) this.instance.placeholder.remove();
6518
+
6519
+ inst._trigger("fromSortable", event);
6520
+ inst.dropped = false; //draggable revert needs that
6521
+ }
6522
+
6523
+ };
6524
+
6525
+ });
6526
+
6527
+ }
6528
+ });
6529
+
6530
+ $.ui.plugin.add("draggable", "cursor", {
6531
+ start: function(event, ui) {
6532
+ var t = $('body'), o = $(this).data('draggable').options;
6533
+ if (t.css("cursor")) o._cursor = t.css("cursor");
6534
+ t.css("cursor", o.cursor);
6535
+ },
6536
+ stop: function(event, ui) {
6537
+ var o = $(this).data('draggable').options;
6538
+ if (o._cursor) $('body').css("cursor", o._cursor);
6539
+ }
6540
+ });
6541
+
6542
+ $.ui.plugin.add("draggable", "opacity", {
6543
+ start: function(event, ui) {
6544
+ var t = $(ui.helper), o = $(this).data('draggable').options;
6545
+ if(t.css("opacity")) o._opacity = t.css("opacity");
6546
+ t.css('opacity', o.opacity);
6547
+ },
6548
+ stop: function(event, ui) {
6549
+ var o = $(this).data('draggable').options;
6550
+ if(o._opacity) $(ui.helper).css('opacity', o._opacity);
6551
+ }
6552
+ });
6553
+
6554
+ $.ui.plugin.add("draggable", "scroll", {
6555
+ start: function(event, ui) {
6556
+ var i = $(this).data("draggable");
6557
+ if(i.scrollParent[0] != document && i.scrollParent[0].tagName != 'HTML') i.overflowOffset = i.scrollParent.offset();
6558
+ },
6559
+ drag: function(event, ui) {
6560
+
6561
+ var i = $(this).data("draggable"), o = i.options, scrolled = false;
6562
+
6563
+ if(i.scrollParent[0] != document && i.scrollParent[0].tagName != 'HTML') {
6564
+
6565
+ if(!o.axis || o.axis != 'x') {
6566
+ if((i.overflowOffset.top + i.scrollParent[0].offsetHeight) - event.pageY < o.scrollSensitivity)
6567
+ i.scrollParent[0].scrollTop = scrolled = i.scrollParent[0].scrollTop + o.scrollSpeed;
6568
+ else if(event.pageY - i.overflowOffset.top < o.scrollSensitivity)
6569
+ i.scrollParent[0].scrollTop = scrolled = i.scrollParent[0].scrollTop - o.scrollSpeed;
6570
+ }
6571
+
6572
+ if(!o.axis || o.axis != 'y') {
6573
+ if((i.overflowOffset.left + i.scrollParent[0].offsetWidth) - event.pageX < o.scrollSensitivity)
6574
+ i.scrollParent[0].scrollLeft = scrolled = i.scrollParent[0].scrollLeft + o.scrollSpeed;
6575
+ else if(event.pageX - i.overflowOffset.left < o.scrollSensitivity)
6576
+ i.scrollParent[0].scrollLeft = scrolled = i.scrollParent[0].scrollLeft - o.scrollSpeed;
6577
+ }
6578
+
6579
+ } else {
6580
+
6581
+ if(!o.axis || o.axis != 'x') {
6582
+ if(event.pageY - $(document).scrollTop() < o.scrollSensitivity)
6583
+ scrolled = $(document).scrollTop($(document).scrollTop() - o.scrollSpeed);
6584
+ else if($(window).height() - (event.pageY - $(document).scrollTop()) < o.scrollSensitivity)
6585
+ scrolled = $(document).scrollTop($(document).scrollTop() + o.scrollSpeed);
6586
+ }
6587
+
6588
+ if(!o.axis || o.axis != 'y') {
6589
+ if(event.pageX - $(document).scrollLeft() < o.scrollSensitivity)
6590
+ scrolled = $(document).scrollLeft($(document).scrollLeft() - o.scrollSpeed);
6591
+ else if($(window).width() - (event.pageX - $(document).scrollLeft()) < o.scrollSensitivity)
6592
+ scrolled = $(document).scrollLeft($(document).scrollLeft() + o.scrollSpeed);
6593
+ }
6594
+
6595
+ }
6596
+
6597
+ if(scrolled !== false && $.ui.ddmanager && !o.dropBehaviour)
6598
+ $.ui.ddmanager.prepareOffsets(i, event);
6599
+
6600
+ }
6601
+ });
6602
+
6603
+ $.ui.plugin.add("draggable", "snap", {
6604
+ start: function(event, ui) {
6605
+
6606
+ var i = $(this).data("draggable"), o = i.options;
6607
+ i.snapElements = [];
6608
+
6609
+ $(o.snap.constructor != String ? ( o.snap.items || ':data(draggable)' ) : o.snap).each(function() {
6610
+ var $t = $(this); var $o = $t.offset();
6611
+ if(this != i.element[0]) i.snapElements.push({
6612
+ item: this,
6613
+ width: $t.outerWidth(), height: $t.outerHeight(),
6614
+ top: $o.top, left: $o.left
6615
+ });
6616
+ });
6617
+
6618
+ },
6619
+ drag: function(event, ui) {
6620
+
6621
+ var inst = $(this).data("draggable"), o = inst.options;
6622
+ var d = o.snapTolerance;
6623
+
6624
+ var x1 = ui.offset.left, x2 = x1 + inst.helperProportions.width,
6625
+ y1 = ui.offset.top, y2 = y1 + inst.helperProportions.height;
6626
+
6627
+ for (var i = inst.snapElements.length - 1; i >= 0; i--){
6628
+
6629
+ var l = inst.snapElements[i].left, r = l + inst.snapElements[i].width,
6630
+ t = inst.snapElements[i].top, b = t + inst.snapElements[i].height;
6631
+
6632
+ //Yes, I know, this is insane ;)
6633
+ if(!((l-d < x1 && x1 < r+d && t-d < y1 && y1 < b+d) || (l-d < x1 && x1 < r+d && t-d < y2 && y2 < b+d) || (l-d < x2 && x2 < r+d && t-d < y1 && y1 < b+d) || (l-d < x2 && x2 < r+d && t-d < y2 && y2 < b+d))) {
6634
+ 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 })));
6635
+ inst.snapElements[i].snapping = false;
6636
+ continue;
6637
+ }
6638
+
6639
+ if(o.snapMode != 'inner') {
6640
+ var ts = Math.abs(t - y2) <= d;
6641
+ var bs = Math.abs(b - y1) <= d;
6642
+ var ls = Math.abs(l - x2) <= d;
6643
+ var rs = Math.abs(r - x1) <= d;
6644
+ if(ts) ui.position.top = inst._convertPositionTo("relative", { top: t - inst.helperProportions.height, left: 0 }).top - inst.margins.top;
6645
+ if(bs) ui.position.top = inst._convertPositionTo("relative", { top: b, left: 0 }).top - inst.margins.top;
6646
+ if(ls) ui.position.left = inst._convertPositionTo("relative", { top: 0, left: l - inst.helperProportions.width }).left - inst.margins.left;
6647
+ if(rs) ui.position.left = inst._convertPositionTo("relative", { top: 0, left: r }).left - inst.margins.left;
6648
+ }
6649
+
6650
+ var first = (ts || bs || ls || rs);
6651
+
6652
+ if(o.snapMode != 'outer') {
6653
+ var ts = Math.abs(t - y1) <= d;
6654
+ var bs = Math.abs(b - y2) <= d;
6655
+ var ls = Math.abs(l - x1) <= d;
6656
+ var rs = Math.abs(r - x2) <= d;
6657
+ if(ts) ui.position.top = inst._convertPositionTo("relative", { top: t, left: 0 }).top - inst.margins.top;
6658
+ if(bs) ui.position.top = inst._convertPositionTo("relative", { top: b - inst.helperProportions.height, left: 0 }).top - inst.margins.top;
6659
+ if(ls) ui.position.left = inst._convertPositionTo("relative", { top: 0, left: l }).left - inst.margins.left;
6660
+ if(rs) ui.position.left = inst._convertPositionTo("relative", { top: 0, left: r - inst.helperProportions.width }).left - inst.margins.left;
6661
+ }
6662
+
6663
+ if(!inst.snapElements[i].snapping && (ts || bs || ls || rs || first))
6664
+ (inst.options.snap.snap && inst.options.snap.snap.call(inst.element, event, $.extend(inst._uiHash(), { snapItem: inst.snapElements[i].item })));
6665
+ inst.snapElements[i].snapping = (ts || bs || ls || rs || first);
6666
+
6667
+ };
6668
+
6669
+ }
6670
+ });
6671
+
6672
+ $.ui.plugin.add("draggable", "stack", {
6673
+ start: function(event, ui) {
6674
+
6675
+ var o = $(this).data("draggable").options;
6676
+
6677
+ var group = $.makeArray($(o.stack)).sort(function(a,b) {
6678
+ return (parseInt($(a).css("zIndex"),10) || 0) - (parseInt($(b).css("zIndex"),10) || 0);
6679
+ });
6680
+ if (!group.length) { return; }
6681
+
6682
+ var min = parseInt(group[0].style.zIndex) || 0;
6683
+ $(group).each(function(i) {
6684
+ this.style.zIndex = min + i;
6685
+ });
6686
+
6687
+ this[0].style.zIndex = min + group.length;
6688
+
6689
+ }
6690
+ });
6691
+
6692
+ $.ui.plugin.add("draggable", "zIndex", {
6693
+ start: function(event, ui) {
6694
+ var t = $(ui.helper), o = $(this).data("draggable").options;
6695
+ if(t.css("zIndex")) o._zIndex = t.css("zIndex");
6696
+ t.css('zIndex', o.zIndex);
6697
+ },
6698
+ stop: function(event, ui) {
6699
+ var o = $(this).data("draggable").options;
6700
+ if(o._zIndex) $(ui.helper).css('zIndex', o._zIndex);
6701
+ }
6702
+ });
6703
+
6704
+ })(jQuery);
6705
+ (function( $, undefined ) {
6706
+
6707
+ $.widget("ui.droppable", {
6708
+ version: "1.9.1",
6709
+ widgetEventPrefix: "drop",
6710
+ options: {
6711
+ accept: '*',
6712
+ activeClass: false,
6713
+ addClasses: true,
6714
+ greedy: false,
6715
+ hoverClass: false,
6716
+ scope: 'default',
6717
+ tolerance: 'intersect'
6718
+ },
6719
+ _create: function() {
6720
+
6721
+ var o = this.options, accept = o.accept;
6722
+ this.isover = 0; this.isout = 1;
6723
+
6724
+ this.accept = $.isFunction(accept) ? accept : function(d) {
6725
+ return d.is(accept);
6726
+ };
6727
+
6728
+ //Store the droppable's proportions
6729
+ this.proportions = { width: this.element[0].offsetWidth, height: this.element[0].offsetHeight };
6730
+
6731
+ // Add the reference and positions to the manager
6732
+ $.ui.ddmanager.droppables[o.scope] = $.ui.ddmanager.droppables[o.scope] || [];
6733
+ $.ui.ddmanager.droppables[o.scope].push(this);
6734
+
6735
+ (o.addClasses && this.element.addClass("ui-droppable"));
6736
+
6737
+ },
6738
+
6739
+ _destroy: function() {
6740
+ var drop = $.ui.ddmanager.droppables[this.options.scope];
6741
+ for ( var i = 0; i < drop.length; i++ )
6742
+ if ( drop[i] == this )
6743
+ drop.splice(i, 1);
6744
+
6745
+ this.element.removeClass("ui-droppable ui-droppable-disabled");
6746
+ },
6747
+
6748
+ _setOption: function(key, value) {
6749
+
6750
+ if(key == 'accept') {
6751
+ this.accept = $.isFunction(value) ? value : function(d) {
6752
+ return d.is(value);
6753
+ };
6754
+ }
6755
+ $.Widget.prototype._setOption.apply(this, arguments);
6756
+ },
6757
+
6758
+ _activate: function(event) {
6759
+ var draggable = $.ui.ddmanager.current;
6760
+ if(this.options.activeClass) this.element.addClass(this.options.activeClass);
6761
+ (draggable && this._trigger('activate', event, this.ui(draggable)));
6762
+ },
6763
+
6764
+ _deactivate: function(event) {
6765
+ var draggable = $.ui.ddmanager.current;
6766
+ if(this.options.activeClass) this.element.removeClass(this.options.activeClass);
6767
+ (draggable && this._trigger('deactivate', event, this.ui(draggable)));
6768
+ },
6769
+
6770
+ _over: function(event) {
6771
+
6772
+ var draggable = $.ui.ddmanager.current;
6773
+ if (!draggable || (draggable.currentItem || draggable.element)[0] == this.element[0]) return; // Bail if draggable and droppable are same element
6774
+
6775
+ if (this.accept.call(this.element[0],(draggable.currentItem || draggable.element))) {
6776
+ if(this.options.hoverClass) this.element.addClass(this.options.hoverClass);
6777
+ this._trigger('over', event, this.ui(draggable));
6778
+ }
6779
+
6780
+ },
6781
+
6782
+ _out: function(event) {
6783
+
6784
+ var draggable = $.ui.ddmanager.current;
6785
+ if (!draggable || (draggable.currentItem || draggable.element)[0] == this.element[0]) return; // Bail if draggable and droppable are same element
6786
+
6787
+ if (this.accept.call(this.element[0],(draggable.currentItem || draggable.element))) {
6788
+ if(this.options.hoverClass) this.element.removeClass(this.options.hoverClass);
6789
+ this._trigger('out', event, this.ui(draggable));
6790
+ }
6791
+
6792
+ },
6793
+
6794
+ _drop: function(event,custom) {
6795
+
6796
+ var draggable = custom || $.ui.ddmanager.current;
6797
+ if (!draggable || (draggable.currentItem || draggable.element)[0] == this.element[0]) return false; // Bail if draggable and droppable are same element
6798
+
6799
+ var childrenIntersection = false;
6800
+ this.element.find(":data(droppable)").not(".ui-draggable-dragging").each(function() {
6801
+ var inst = $.data(this, 'droppable');
6802
+ if(
6803
+ inst.options.greedy
6804
+ && !inst.options.disabled
6805
+ && inst.options.scope == draggable.options.scope
6806
+ && inst.accept.call(inst.element[0], (draggable.currentItem || draggable.element))
6807
+ && $.ui.intersect(draggable, $.extend(inst, { offset: inst.element.offset() }), inst.options.tolerance)
6808
+ ) { childrenIntersection = true; return false; }
6809
+ });
6810
+ if(childrenIntersection) return false;
6811
+
6812
+ if(this.accept.call(this.element[0],(draggable.currentItem || draggable.element))) {
6813
+ if(this.options.activeClass) this.element.removeClass(this.options.activeClass);
6814
+ if(this.options.hoverClass) this.element.removeClass(this.options.hoverClass);
6815
+ this._trigger('drop', event, this.ui(draggable));
6816
+ return this.element;
6817
+ }
6818
+
6819
+ return false;
6820
+
6821
+ },
6822
+
6823
+ ui: function(c) {
6824
+ return {
6825
+ draggable: (c.currentItem || c.element),
6826
+ helper: c.helper,
6827
+ position: c.position,
6828
+ offset: c.positionAbs
6829
+ };
6830
+ }
6831
+
6832
+ });
6833
+
6834
+ $.ui.intersect = function(draggable, droppable, toleranceMode) {
6835
+
6836
+ if (!droppable.offset) return false;
6837
+
6838
+ var x1 = (draggable.positionAbs || draggable.position.absolute).left, x2 = x1 + draggable.helperProportions.width,
6839
+ y1 = (draggable.positionAbs || draggable.position.absolute).top, y2 = y1 + draggable.helperProportions.height;
6840
+ var l = droppable.offset.left, r = l + droppable.proportions.width,
6841
+ t = droppable.offset.top, b = t + droppable.proportions.height;
6842
+
6843
+ switch (toleranceMode) {
6844
+ case 'fit':
6845
+ return (l <= x1 && x2 <= r
6846
+ && t <= y1 && y2 <= b);
6847
+ break;
6848
+ case 'intersect':
6849
+ return (l < x1 + (draggable.helperProportions.width / 2) // Right Half
6850
+ && x2 - (draggable.helperProportions.width / 2) < r // Left Half
6851
+ && t < y1 + (draggable.helperProportions.height / 2) // Bottom Half
6852
+ && y2 - (draggable.helperProportions.height / 2) < b ); // Top Half
6853
+ break;
6854
+ case 'pointer':
6855
+ var draggableLeft = ((draggable.positionAbs || draggable.position.absolute).left + (draggable.clickOffset || draggable.offset.click).left),
6856
+ draggableTop = ((draggable.positionAbs || draggable.position.absolute).top + (draggable.clickOffset || draggable.offset.click).top),
6857
+ isOver = $.ui.isOver(draggableTop, draggableLeft, t, l, droppable.proportions.height, droppable.proportions.width);
6858
+ return isOver;
6859
+ break;
6860
+ case 'touch':
6861
+ return (
6862
+ (y1 >= t && y1 <= b) || // Top edge touching
6863
+ (y2 >= t && y2 <= b) || // Bottom edge touching
6864
+ (y1 < t && y2 > b) // Surrounded vertically
6865
+ ) && (
6866
+ (x1 >= l && x1 <= r) || // Left edge touching
6867
+ (x2 >= l && x2 <= r) || // Right edge touching
6868
+ (x1 < l && x2 > r) // Surrounded horizontally
6869
+ );
6870
+ break;
6871
+ default:
6872
+ return false;
6873
+ break;
6874
+ }
6875
+
6876
+ };
6877
+
6878
+ /*
6879
+ This manager tracks offsets of draggables and droppables
6880
+ */
6881
+ $.ui.ddmanager = {
6882
+ current: null,
6883
+ droppables: { 'default': [] },
6884
+ prepareOffsets: function(t, event) {
6885
+
6886
+ var m = $.ui.ddmanager.droppables[t.options.scope] || [];
6887
+ var type = event ? event.type : null; // workaround for #2317
6888
+ var list = (t.currentItem || t.element).find(":data(droppable)").andSelf();
6889
+
6890
+ droppablesLoop: for (var i = 0; i < m.length; i++) {
6891
+
6892
+ if(m[i].options.disabled || (t && !m[i].accept.call(m[i].element[0],(t.currentItem || t.element)))) continue; //No disabled and non-accepted
6893
+ for (var j=0; j < list.length; j++) { if(list[j] == m[i].element[0]) { m[i].proportions.height = 0; continue droppablesLoop; } }; //Filter out elements in the current dragged item
6894
+ m[i].visible = m[i].element.css("display") != "none"; if(!m[i].visible) continue; //If the element is not visible, continue
6895
+
6896
+ if(type == "mousedown") m[i]._activate.call(m[i], event); //Activate the droppable if used directly from draggables
6897
+
6898
+ m[i].offset = m[i].element.offset();
6899
+ m[i].proportions = { width: m[i].element[0].offsetWidth, height: m[i].element[0].offsetHeight };
6900
+
6901
+ }
6902
+
6903
+ },
6904
+ drop: function(draggable, event) {
6905
+
6906
+ var dropped = false;
6907
+ $.each($.ui.ddmanager.droppables[draggable.options.scope] || [], function() {
6908
+
6909
+ if(!this.options) return;
6910
+ if (!this.options.disabled && this.visible && $.ui.intersect(draggable, this, this.options.tolerance))
6911
+ dropped = this._drop.call(this, event) || dropped;
6912
+
6913
+ if (!this.options.disabled && this.visible && this.accept.call(this.element[0],(draggable.currentItem || draggable.element))) {
6914
+ this.isout = 1; this.isover = 0;
6915
+ this._deactivate.call(this, event);
6916
+ }
6917
+
6918
+ });
6919
+ return dropped;
6920
+
6921
+ },
6922
+ dragStart: function( draggable, event ) {
6923
+ //Listen for scrolling so that if the dragging causes scrolling the position of the droppables can be recalculated (see #5003)
6924
+ draggable.element.parentsUntil( "body" ).bind( "scroll.droppable", function() {
6925
+ if( !draggable.options.refreshPositions ) $.ui.ddmanager.prepareOffsets( draggable, event );
6926
+ });
6927
+ },
6928
+ drag: function(draggable, event) {
6929
+
6930
+ //If you have a highly dynamic page, you might try this option. It renders positions every time you move the mouse.
6931
+ if(draggable.options.refreshPositions) $.ui.ddmanager.prepareOffsets(draggable, event);
6932
+
6933
+ //Run through all droppables and check their positions based on specific tolerance options
6934
+ $.each($.ui.ddmanager.droppables[draggable.options.scope] || [], function() {
6935
+
6936
+ if(this.options.disabled || this.greedyChild || !this.visible) return;
6937
+ var intersects = $.ui.intersect(draggable, this, this.options.tolerance);
6938
+
6939
+ var c = !intersects && this.isover == 1 ? 'isout' : (intersects && this.isover == 0 ? 'isover' : null);
6940
+ if(!c) return;
6941
+
6942
+ var parentInstance;
6943
+ if (this.options.greedy) {
6944
+ // find droppable parents with same scope
6945
+ var scope = this.options.scope;
6946
+ var parent = this.element.parents(':data(droppable)').filter(function () {
6947
+ return $.data(this, 'droppable').options.scope === scope;
6948
+ });
6949
+
6950
+ if (parent.length) {
6951
+ parentInstance = $.data(parent[0], 'droppable');
6952
+ parentInstance.greedyChild = (c == 'isover' ? 1 : 0);
6953
+ }
6954
+ }
6955
+
6956
+ // we just moved into a greedy child
6957
+ if (parentInstance && c == 'isover') {
6958
+ parentInstance['isover'] = 0;
6959
+ parentInstance['isout'] = 1;
6960
+ parentInstance._out.call(parentInstance, event);
6961
+ }
6962
+
6963
+ this[c] = 1; this[c == 'isout' ? 'isover' : 'isout'] = 0;
6964
+ this[c == "isover" ? "_over" : "_out"].call(this, event);
6965
+
6966
+ // we just moved out of a greedy child
6967
+ if (parentInstance && c == 'isout') {
6968
+ parentInstance['isout'] = 0;
6969
+ parentInstance['isover'] = 1;
6970
+ parentInstance._over.call(parentInstance, event);
6971
+ }
6972
+ });
6973
+
6974
+ },
6975
+ dragStop: function( draggable, event ) {
6976
+ draggable.element.parentsUntil( "body" ).unbind( "scroll.droppable" );
6977
+ //Call prepareOffsets one final time since IE does not fire return scroll events when overflow was caused by drag (see #5003)
6978
+ if( !draggable.options.refreshPositions ) $.ui.ddmanager.prepareOffsets( draggable, event );
6979
+ }
6980
+ };
6981
+
6982
+ })(jQuery);
6983
+ ;(jQuery.effects || (function($, undefined) {
6984
+
6985
+ var backCompat = $.uiBackCompat !== false,
6986
+ // prefix used for storing data on .data()
6987
+ dataSpace = "ui-effects-";
6988
+
6989
+ $.effects = {
6990
+ effect: {}
6991
+ };
6992
+
6993
+ /*!
6994
+ * jQuery Color Animations v2.0.0
6995
+ * http://jquery.com/
6996
+ *
6997
+ * Copyright 2012 jQuery Foundation and other contributors
6998
+ * Released under the MIT license.
6999
+ * http://jquery.org/license
7000
+ *
7001
+ * Date: Mon Aug 13 13:41:02 2012 -0500
7002
+ */
7003
+ (function( jQuery, undefined ) {
7004
+
7005
+ var stepHooks = "backgroundColor borderBottomColor borderLeftColor borderRightColor borderTopColor color columnRuleColor outlineColor textDecorationColor textEmphasisColor".split(" "),
7006
+
7007
+ // plusequals test for += 100 -= 100
7008
+ rplusequals = /^([\-+])=\s*(\d+\.?\d*)/,
7009
+ // a set of RE's that can match strings and generate color tuples.
7010
+ stringParsers = [{
7011
+ re: /rgba?\(\s*(\d{1,3})\s*,\s*(\d{1,3})\s*,\s*(\d{1,3})\s*(?:,\s*(\d+(?:\.\d+)?)\s*)?\)/,
7012
+ parse: function( execResult ) {
7013
+ return [
7014
+ execResult[ 1 ],
7015
+ execResult[ 2 ],
7016
+ execResult[ 3 ],
7017
+ execResult[ 4 ]
7018
+ ];
7019
+ }
7020
+ }, {
7021
+ re: /rgba?\(\s*(\d+(?:\.\d+)?)\%\s*,\s*(\d+(?:\.\d+)?)\%\s*,\s*(\d+(?:\.\d+)?)\%\s*(?:,\s*(\d+(?:\.\d+)?)\s*)?\)/,
7022
+ parse: function( execResult ) {
7023
+ return [
7024
+ execResult[ 1 ] * 2.55,
7025
+ execResult[ 2 ] * 2.55,
7026
+ execResult[ 3 ] * 2.55,
7027
+ execResult[ 4 ]
7028
+ ];
7029
+ }
7030
+ }, {
7031
+ // this regex ignores A-F because it's compared against an already lowercased string
7032
+ re: /#([a-f0-9]{2})([a-f0-9]{2})([a-f0-9]{2})/,
7033
+ parse: function( execResult ) {
7034
+ return [
7035
+ parseInt( execResult[ 1 ], 16 ),
7036
+ parseInt( execResult[ 2 ], 16 ),
7037
+ parseInt( execResult[ 3 ], 16 )
7038
+ ];
7039
+ }
7040
+ }, {
7041
+ // this regex ignores A-F because it's compared against an already lowercased string
7042
+ re: /#([a-f0-9])([a-f0-9])([a-f0-9])/,
7043
+ parse: function( execResult ) {
7044
+ return [
7045
+ parseInt( execResult[ 1 ] + execResult[ 1 ], 16 ),
7046
+ parseInt( execResult[ 2 ] + execResult[ 2 ], 16 ),
7047
+ parseInt( execResult[ 3 ] + execResult[ 3 ], 16 )
7048
+ ];
7049
+ }
7050
+ }, {
7051
+ re: /hsla?\(\s*(\d+(?:\.\d+)?)\s*,\s*(\d+(?:\.\d+)?)\%\s*,\s*(\d+(?:\.\d+)?)\%\s*(?:,\s*(\d+(?:\.\d+)?)\s*)?\)/,
7052
+ space: "hsla",
7053
+ parse: function( execResult ) {
7054
+ return [
7055
+ execResult[ 1 ],
7056
+ execResult[ 2 ] / 100,
7057
+ execResult[ 3 ] / 100,
7058
+ execResult[ 4 ]
7059
+ ];
7060
+ }
7061
+ }],
7062
+
7063
+ // jQuery.Color( )
7064
+ color = jQuery.Color = function( color, green, blue, alpha ) {
7065
+ return new jQuery.Color.fn.parse( color, green, blue, alpha );
7066
+ },
7067
+ spaces = {
7068
+ rgba: {
7069
+ props: {
7070
+ red: {
7071
+ idx: 0,
7072
+ type: "byte"
7073
+ },
7074
+ green: {
7075
+ idx: 1,
7076
+ type: "byte"
7077
+ },
7078
+ blue: {
7079
+ idx: 2,
7080
+ type: "byte"
7081
+ }
7082
+ }
7083
+ },
7084
+
7085
+ hsla: {
7086
+ props: {
7087
+ hue: {
7088
+ idx: 0,
7089
+ type: "degrees"
7090
+ },
7091
+ saturation: {
7092
+ idx: 1,
7093
+ type: "percent"
7094
+ },
7095
+ lightness: {
7096
+ idx: 2,
7097
+ type: "percent"
7098
+ }
7099
+ }
7100
+ }
7101
+ },
7102
+ propTypes = {
7103
+ "byte": {
7104
+ floor: true,
7105
+ max: 255
7106
+ },
7107
+ "percent": {
7108
+ max: 1
7109
+ },
7110
+ "degrees": {
7111
+ mod: 360,
7112
+ floor: true
7113
+ }
7114
+ },
7115
+ support = color.support = {},
7116
+
7117
+ // element for support tests
7118
+ supportElem = jQuery( "<p>" )[ 0 ],
7119
+
7120
+ // colors = jQuery.Color.names
7121
+ colors,
7122
+
7123
+ // local aliases of functions called often
7124
+ each = jQuery.each;
7125
+
7126
+ // determine rgba support immediately
7127
+ supportElem.style.cssText = "background-color:rgba(1,1,1,.5)";
7128
+ support.rgba = supportElem.style.backgroundColor.indexOf( "rgba" ) > -1;
7129
+
7130
+ // define cache name and alpha properties
7131
+ // for rgba and hsla spaces
7132
+ each( spaces, function( spaceName, space ) {
7133
+ space.cache = "_" + spaceName;
7134
+ space.props.alpha = {
7135
+ idx: 3,
7136
+ type: "percent",
7137
+ def: 1
7138
+ };
7139
+ });
7140
+
7141
+ function clamp( value, prop, allowEmpty ) {
7142
+ var type = propTypes[ prop.type ] || {};
7143
+
7144
+ if ( value == null ) {
7145
+ return (allowEmpty || !prop.def) ? null : prop.def;
7146
+ }
7147
+
7148
+ // ~~ is an short way of doing floor for positive numbers
7149
+ value = type.floor ? ~~value : parseFloat( value );
7150
+
7151
+ // IE will pass in empty strings as value for alpha,
7152
+ // which will hit this case
7153
+ if ( isNaN( value ) ) {
7154
+ return prop.def;
7155
+ }
7156
+
7157
+ if ( type.mod ) {
7158
+ // we add mod before modding to make sure that negatives values
7159
+ // get converted properly: -10 -> 350
7160
+ return (value + type.mod) % type.mod;
7161
+ }
7162
+
7163
+ // for now all property types without mod have min and max
7164
+ return 0 > value ? 0 : type.max < value ? type.max : value;
7165
+ }
7166
+
7167
+ function stringParse( string ) {
7168
+ var inst = color(),
7169
+ rgba = inst._rgba = [];
7170
+
7171
+ string = string.toLowerCase();
7172
+
7173
+ each( stringParsers, function( i, parser ) {
7174
+ var parsed,
7175
+ match = parser.re.exec( string ),
7176
+ values = match && parser.parse( match ),
7177
+ spaceName = parser.space || "rgba";
7178
+
7179
+ if ( values ) {
7180
+ parsed = inst[ spaceName ]( values );
7181
+
7182
+ // if this was an rgba parse the assignment might happen twice
7183
+ // oh well....
7184
+ inst[ spaces[ spaceName ].cache ] = parsed[ spaces[ spaceName ].cache ];
7185
+ rgba = inst._rgba = parsed._rgba;
7186
+
7187
+ // exit each( stringParsers ) here because we matched
7188
+ return false;
7189
+ }
7190
+ });
7191
+
7192
+ // Found a stringParser that handled it
7193
+ if ( rgba.length ) {
7194
+
7195
+ // if this came from a parsed string, force "transparent" when alpha is 0
7196
+ // chrome, (and maybe others) return "transparent" as rgba(0,0,0,0)
7197
+ if ( rgba.join() === "0,0,0,0" ) {
7198
+ jQuery.extend( rgba, colors.transparent );
7199
+ }
7200
+ return inst;
7201
+ }
7202
+
7203
+ // named colors
7204
+ return colors[ string ];
7205
+ }
7206
+
7207
+ color.fn = jQuery.extend( color.prototype, {
7208
+ parse: function( red, green, blue, alpha ) {
7209
+ if ( red === undefined ) {
7210
+ this._rgba = [ null, null, null, null ];
7211
+ return this;
7212
+ }
7213
+ if ( red.jquery || red.nodeType ) {
7214
+ red = jQuery( red ).css( green );
7215
+ green = undefined;
7216
+ }
7217
+
7218
+ var inst = this,
7219
+ type = jQuery.type( red ),
7220
+ rgba = this._rgba = [];
7221
+
7222
+ // more than 1 argument specified - assume ( red, green, blue, alpha )
7223
+ if ( green !== undefined ) {
7224
+ red = [ red, green, blue, alpha ];
7225
+ type = "array";
7226
+ }
7227
+
7228
+ if ( type === "string" ) {
7229
+ return this.parse( stringParse( red ) || colors._default );
7230
+ }
7231
+
7232
+ if ( type === "array" ) {
7233
+ each( spaces.rgba.props, function( key, prop ) {
7234
+ rgba[ prop.idx ] = clamp( red[ prop.idx ], prop );
7235
+ });
7236
+ return this;
7237
+ }
7238
+
7239
+ if ( type === "object" ) {
7240
+ if ( red instanceof color ) {
7241
+ each( spaces, function( spaceName, space ) {
7242
+ if ( red[ space.cache ] ) {
7243
+ inst[ space.cache ] = red[ space.cache ].slice();
7244
+ }
7245
+ });
7246
+ } else {
7247
+ each( spaces, function( spaceName, space ) {
7248
+ var cache = space.cache;
7249
+ each( space.props, function( key, prop ) {
7250
+
7251
+ // if the cache doesn't exist, and we know how to convert
7252
+ if ( !inst[ cache ] && space.to ) {
7253
+
7254
+ // if the value was null, we don't need to copy it
7255
+ // if the key was alpha, we don't need to copy it either
7256
+ if ( key === "alpha" || red[ key ] == null ) {
7257
+ return;
7258
+ }
7259
+ inst[ cache ] = space.to( inst._rgba );
7260
+ }
7261
+
7262
+ // this is the only case where we allow nulls for ALL properties.
7263
+ // call clamp with alwaysAllowEmpty
7264
+ inst[ cache ][ prop.idx ] = clamp( red[ key ], prop, true );
7265
+ });
7266
+
7267
+ // everything defined but alpha?
7268
+ if ( inst[ cache ] && $.inArray( null, inst[ cache ].slice( 0, 3 ) ) < 0 ) {
7269
+ // use the default of 1
7270
+ inst[ cache ][ 3 ] = 1;
7271
+ if ( space.from ) {
7272
+ inst._rgba = space.from( inst[ cache ] );
7273
+ }
7274
+ }
7275
+ });
7276
+ }
7277
+ return this;
7278
+ }
7279
+ },
7280
+ is: function( compare ) {
7281
+ var is = color( compare ),
7282
+ same = true,
7283
+ inst = this;
7284
+
7285
+ each( spaces, function( _, space ) {
7286
+ var localCache,
7287
+ isCache = is[ space.cache ];
7288
+ if (isCache) {
7289
+ localCache = inst[ space.cache ] || space.to && space.to( inst._rgba ) || [];
7290
+ each( space.props, function( _, prop ) {
7291
+ if ( isCache[ prop.idx ] != null ) {
7292
+ same = ( isCache[ prop.idx ] === localCache[ prop.idx ] );
7293
+ return same;
7294
+ }
7295
+ });
7296
+ }
7297
+ return same;
7298
+ });
7299
+ return same;
7300
+ },
7301
+ _space: function() {
7302
+ var used = [],
7303
+ inst = this;
7304
+ each( spaces, function( spaceName, space ) {
7305
+ if ( inst[ space.cache ] ) {
7306
+ used.push( spaceName );
7307
+ }
7308
+ });
7309
+ return used.pop();
7310
+ },
7311
+ transition: function( other, distance ) {
7312
+ var end = color( other ),
7313
+ spaceName = end._space(),
7314
+ space = spaces[ spaceName ],
7315
+ startColor = this.alpha() === 0 ? color( "transparent" ) : this,
7316
+ start = startColor[ space.cache ] || space.to( startColor._rgba ),
7317
+ result = start.slice();
7318
+
7319
+ end = end[ space.cache ];
7320
+ each( space.props, function( key, prop ) {
7321
+ var index = prop.idx,
7322
+ startValue = start[ index ],
7323
+ endValue = end[ index ],
7324
+ type = propTypes[ prop.type ] || {};
7325
+
7326
+ // if null, don't override start value
7327
+ if ( endValue === null ) {
7328
+ return;
7329
+ }
7330
+ // if null - use end
7331
+ if ( startValue === null ) {
7332
+ result[ index ] = endValue;
7333
+ } else {
7334
+ if ( type.mod ) {
7335
+ if ( endValue - startValue > type.mod / 2 ) {
7336
+ startValue += type.mod;
7337
+ } else if ( startValue - endValue > type.mod / 2 ) {
7338
+ startValue -= type.mod;
7339
+ }
7340
+ }
7341
+ result[ index ] = clamp( ( endValue - startValue ) * distance + startValue, prop );
7342
+ }
7343
+ });
7344
+ return this[ spaceName ]( result );
7345
+ },
7346
+ blend: function( opaque ) {
7347
+ // if we are already opaque - return ourself
7348
+ if ( this._rgba[ 3 ] === 1 ) {
7349
+ return this;
7350
+ }
7351
+
7352
+ var rgb = this._rgba.slice(),
7353
+ a = rgb.pop(),
7354
+ blend = color( opaque )._rgba;
7355
+
7356
+ return color( jQuery.map( rgb, function( v, i ) {
7357
+ return ( 1 - a ) * blend[ i ] + a * v;
7358
+ }));
7359
+ },
7360
+ toRgbaString: function() {
7361
+ var prefix = "rgba(",
7362
+ rgba = jQuery.map( this._rgba, function( v, i ) {
7363
+ return v == null ? ( i > 2 ? 1 : 0 ) : v;
7364
+ });
7365
+
7366
+ if ( rgba[ 3 ] === 1 ) {
7367
+ rgba.pop();
7368
+ prefix = "rgb(";
7369
+ }
7370
+
7371
+ return prefix + rgba.join() + ")";
7372
+ },
7373
+ toHslaString: function() {
7374
+ var prefix = "hsla(",
7375
+ hsla = jQuery.map( this.hsla(), function( v, i ) {
7376
+ if ( v == null ) {
7377
+ v = i > 2 ? 1 : 0;
7378
+ }
7379
+
7380
+ // catch 1 and 2
7381
+ if ( i && i < 3 ) {
7382
+ v = Math.round( v * 100 ) + "%";
7383
+ }
7384
+ return v;
7385
+ });
7386
+
7387
+ if ( hsla[ 3 ] === 1 ) {
7388
+ hsla.pop();
7389
+ prefix = "hsl(";
7390
+ }
7391
+ return prefix + hsla.join() + ")";
7392
+ },
7393
+ toHexString: function( includeAlpha ) {
7394
+ var rgba = this._rgba.slice(),
7395
+ alpha = rgba.pop();
7396
+
7397
+ if ( includeAlpha ) {
7398
+ rgba.push( ~~( alpha * 255 ) );
7399
+ }
7400
+
7401
+ return "#" + jQuery.map( rgba, function( v ) {
7402
+
7403
+ // default to 0 when nulls exist
7404
+ v = ( v || 0 ).toString( 16 );
7405
+ return v.length === 1 ? "0" + v : v;
7406
+ }).join("");
7407
+ },
7408
+ toString: function() {
7409
+ return this._rgba[ 3 ] === 0 ? "transparent" : this.toRgbaString();
7410
+ }
7411
+ });
7412
+ color.fn.parse.prototype = color.fn;
7413
+
7414
+ // hsla conversions adapted from:
7415
+ // https://code.google.com/p/maashaack/source/browse/packages/graphics/trunk/src/graphics/colors/HUE2RGB.as?r=5021
7416
+
7417
+ function hue2rgb( p, q, h ) {
7418
+ h = ( h + 1 ) % 1;
7419
+ if ( h * 6 < 1 ) {
7420
+ return p + (q - p) * h * 6;
7421
+ }
7422
+ if ( h * 2 < 1) {
7423
+ return q;
7424
+ }
7425
+ if ( h * 3 < 2 ) {
7426
+ return p + (q - p) * ((2/3) - h) * 6;
7427
+ }
7428
+ return p;
7429
+ }
7430
+
7431
+ spaces.hsla.to = function ( rgba ) {
7432
+ if ( rgba[ 0 ] == null || rgba[ 1 ] == null || rgba[ 2 ] == null ) {
7433
+ return [ null, null, null, rgba[ 3 ] ];
7434
+ }
7435
+ var r = rgba[ 0 ] / 255,
7436
+ g = rgba[ 1 ] / 255,
7437
+ b = rgba[ 2 ] / 255,
7438
+ a = rgba[ 3 ],
7439
+ max = Math.max( r, g, b ),
7440
+ min = Math.min( r, g, b ),
7441
+ diff = max - min,
7442
+ add = max + min,
7443
+ l = add * 0.5,
7444
+ h, s;
7445
+
7446
+ if ( min === max ) {
7447
+ h = 0;
7448
+ } else if ( r === max ) {
7449
+ h = ( 60 * ( g - b ) / diff ) + 360;
7450
+ } else if ( g === max ) {
7451
+ h = ( 60 * ( b - r ) / diff ) + 120;
7452
+ } else {
7453
+ h = ( 60 * ( r - g ) / diff ) + 240;
7454
+ }
7455
+
7456
+ if ( l === 0 || l === 1 ) {
7457
+ s = l;
7458
+ } else if ( l <= 0.5 ) {
7459
+ s = diff / add;
7460
+ } else {
7461
+ s = diff / ( 2 - add );
7462
+ }
7463
+ return [ Math.round(h) % 360, s, l, a == null ? 1 : a ];
7464
+ };
7465
+
7466
+ spaces.hsla.from = function ( hsla ) {
7467
+ if ( hsla[ 0 ] == null || hsla[ 1 ] == null || hsla[ 2 ] == null ) {
7468
+ return [ null, null, null, hsla[ 3 ] ];
7469
+ }
7470
+ var h = hsla[ 0 ] / 360,
7471
+ s = hsla[ 1 ],
7472
+ l = hsla[ 2 ],
7473
+ a = hsla[ 3 ],
7474
+ q = l <= 0.5 ? l * ( 1 + s ) : l + s - l * s,
7475
+ p = 2 * l - q;
7476
+
7477
+ return [
7478
+ Math.round( hue2rgb( p, q, h + ( 1 / 3 ) ) * 255 ),
7479
+ Math.round( hue2rgb( p, q, h ) * 255 ),
7480
+ Math.round( hue2rgb( p, q, h - ( 1 / 3 ) ) * 255 ),
7481
+ a
7482
+ ];
7483
+ };
7484
+
7485
+
7486
+ each( spaces, function( spaceName, space ) {
7487
+ var props = space.props,
7488
+ cache = space.cache,
7489
+ to = space.to,
7490
+ from = space.from;
7491
+
7492
+ // makes rgba() and hsla()
7493
+ color.fn[ spaceName ] = function( value ) {
7494
+
7495
+ // generate a cache for this space if it doesn't exist
7496
+ if ( to && !this[ cache ] ) {
7497
+ this[ cache ] = to( this._rgba );
7498
+ }
7499
+ if ( value === undefined ) {
7500
+ return this[ cache ].slice();
7501
+ }
7502
+
7503
+ var ret,
7504
+ type = jQuery.type( value ),
7505
+ arr = ( type === "array" || type === "object" ) ? value : arguments,
7506
+ local = this[ cache ].slice();
7507
+
7508
+ each( props, function( key, prop ) {
7509
+ var val = arr[ type === "object" ? key : prop.idx ];
7510
+ if ( val == null ) {
7511
+ val = local[ prop.idx ];
7512
+ }
7513
+ local[ prop.idx ] = clamp( val, prop );
7514
+ });
7515
+
7516
+ if ( from ) {
7517
+ ret = color( from( local ) );
7518
+ ret[ cache ] = local;
7519
+ return ret;
7520
+ } else {
7521
+ return color( local );
7522
+ }
7523
+ };
7524
+
7525
+ // makes red() green() blue() alpha() hue() saturation() lightness()
7526
+ each( props, function( key, prop ) {
7527
+ // alpha is included in more than one space
7528
+ if ( color.fn[ key ] ) {
7529
+ return;
7530
+ }
7531
+ color.fn[ key ] = function( value ) {
7532
+ var vtype = jQuery.type( value ),
7533
+ fn = ( key === "alpha" ? ( this._hsla ? "hsla" : "rgba" ) : spaceName ),
7534
+ local = this[ fn ](),
7535
+ cur = local[ prop.idx ],
7536
+ match;
7537
+
7538
+ if ( vtype === "undefined" ) {
7539
+ return cur;
7540
+ }
7541
+
7542
+ if ( vtype === "function" ) {
7543
+ value = value.call( this, cur );
7544
+ vtype = jQuery.type( value );
7545
+ }
7546
+ if ( value == null && prop.empty ) {
7547
+ return this;
7548
+ }
7549
+ if ( vtype === "string" ) {
7550
+ match = rplusequals.exec( value );
7551
+ if ( match ) {
7552
+ value = cur + parseFloat( match[ 2 ] ) * ( match[ 1 ] === "+" ? 1 : -1 );
7553
+ }
7554
+ }
7555
+ local[ prop.idx ] = value;
7556
+ return this[ fn ]( local );
7557
+ };
7558
+ });
7559
+ });
7560
+
7561
+ // add .fx.step functions
7562
+ each( stepHooks, function( i, hook ) {
7563
+ jQuery.cssHooks[ hook ] = {
7564
+ set: function( elem, value ) {
7565
+ var parsed, curElem,
7566
+ backgroundColor = "";
7567
+
7568
+ if ( jQuery.type( value ) !== "string" || ( parsed = stringParse( value ) ) ) {
7569
+ value = color( parsed || value );
7570
+ if ( !support.rgba && value._rgba[ 3 ] !== 1 ) {
7571
+ curElem = hook === "backgroundColor" ? elem.parentNode : elem;
7572
+ while (
7573
+ (backgroundColor === "" || backgroundColor === "transparent") &&
7574
+ curElem && curElem.style
7575
+ ) {
7576
+ try {
7577
+ backgroundColor = jQuery.css( curElem, "backgroundColor" );
7578
+ curElem = curElem.parentNode;
7579
+ } catch ( e ) {
7580
+ }
7581
+ }
7582
+
7583
+ value = value.blend( backgroundColor && backgroundColor !== "transparent" ?
7584
+ backgroundColor :
7585
+ "_default" );
7586
+ }
7587
+
7588
+ value = value.toRgbaString();
7589
+ }
7590
+ try {
7591
+ elem.style[ hook ] = value;
7592
+ } catch( error ) {
7593
+ // wrapped to prevent IE from throwing errors on "invalid" values like 'auto' or 'inherit'
7594
+ }
7595
+ }
7596
+ };
7597
+ jQuery.fx.step[ hook ] = function( fx ) {
7598
+ if ( !fx.colorInit ) {
7599
+ fx.start = color( fx.elem, hook );
7600
+ fx.end = color( fx.end );
7601
+ fx.colorInit = true;
7602
+ }
7603
+ jQuery.cssHooks[ hook ].set( fx.elem, fx.start.transition( fx.end, fx.pos ) );
7604
+ };
7605
+ });
7606
+
7607
+ jQuery.cssHooks.borderColor = {
7608
+ expand: function( value ) {
7609
+ var expanded = {};
7610
+
7611
+ each( [ "Top", "Right", "Bottom", "Left" ], function( i, part ) {
7612
+ expanded[ "border" + part + "Color" ] = value;
7613
+ });
7614
+ return expanded;
7615
+ }
7616
+ };
7617
+
7618
+ // Basic color names only.
7619
+ // Usage of any of the other color names requires adding yourself or including
7620
+ // jquery.color.svg-names.js.
7621
+ colors = jQuery.Color.names = {
7622
+ // 4.1. Basic color keywords
7623
+ aqua: "#00ffff",
7624
+ black: "#000000",
7625
+ blue: "#0000ff",
7626
+ fuchsia: "#ff00ff",
7627
+ gray: "#808080",
7628
+ green: "#008000",
7629
+ lime: "#00ff00",
7630
+ maroon: "#800000",
7631
+ navy: "#000080",
7632
+ olive: "#808000",
7633
+ purple: "#800080",
7634
+ red: "#ff0000",
7635
+ silver: "#c0c0c0",
7636
+ teal: "#008080",
7637
+ white: "#ffffff",
7638
+ yellow: "#ffff00",
7639
+
7640
+ // 4.2.3. "transparent" color keyword
7641
+ transparent: [ null, null, null, 0 ],
7642
+
7643
+ _default: "#ffffff"
7644
+ };
7645
+
7646
+ })( jQuery );
7647
+
7648
+
7649
+
7650
+ /******************************************************************************/
7651
+ /****************************** CLASS ANIMATIONS ******************************/
7652
+ /******************************************************************************/
7653
+ (function() {
7654
+
7655
+ var classAnimationActions = [ "add", "remove", "toggle" ],
7656
+ shorthandStyles = {
7657
+ border: 1,
7658
+ borderBottom: 1,
7659
+ borderColor: 1,
7660
+ borderLeft: 1,
7661
+ borderRight: 1,
7662
+ borderTop: 1,
7663
+ borderWidth: 1,
7664
+ margin: 1,
7665
+ padding: 1
7666
+ };
7667
+
7668
+ $.each([ "borderLeftStyle", "borderRightStyle", "borderBottomStyle", "borderTopStyle" ], function( _, prop ) {
7669
+ $.fx.step[ prop ] = function( fx ) {
7670
+ if ( fx.end !== "none" && !fx.setAttr || fx.pos === 1 && !fx.setAttr ) {
7671
+ jQuery.style( fx.elem, prop, fx.end );
7672
+ fx.setAttr = true;
7673
+ }
7674
+ };
7675
+ });
7676
+
7677
+ function getElementStyles() {
7678
+ var style = this.ownerDocument.defaultView ?
7679
+ this.ownerDocument.defaultView.getComputedStyle( this, null ) :
7680
+ this.currentStyle,
7681
+ newStyle = {},
7682
+ key,
7683
+ len;
7684
+
7685
+ // webkit enumerates style porperties
7686
+ if ( style && style.length && style[ 0 ] && style[ style[ 0 ] ] ) {
7687
+ len = style.length;
7688
+ while ( len-- ) {
7689
+ key = style[ len ];
7690
+ if ( typeof style[ key ] === "string" ) {
7691
+ newStyle[ $.camelCase( key ) ] = style[ key ];
7692
+ }
7693
+ }
7694
+ } else {
7695
+ for ( key in style ) {
7696
+ if ( typeof style[ key ] === "string" ) {
7697
+ newStyle[ key ] = style[ key ];
7698
+ }
7699
+ }
7700
+ }
7701
+
7702
+ return newStyle;
7703
+ }
7704
+
7705
+
7706
+ function styleDifference( oldStyle, newStyle ) {
7707
+ var diff = {},
7708
+ name, value;
7709
+
7710
+ for ( name in newStyle ) {
7711
+ value = newStyle[ name ];
7712
+ if ( oldStyle[ name ] !== value ) {
7713
+ if ( !shorthandStyles[ name ] ) {
7714
+ if ( $.fx.step[ name ] || !isNaN( parseFloat( value ) ) ) {
7715
+ diff[ name ] = value;
7716
+ }
7717
+ }
7718
+ }
7719
+ }
7720
+
7721
+ return diff;
7722
+ }
7723
+
7724
+ $.effects.animateClass = function( value, duration, easing, callback ) {
7725
+ var o = $.speed( duration, easing, callback );
7726
+
7727
+ return this.queue( function() {
7728
+ var animated = $( this ),
7729
+ baseClass = animated.attr( "class" ) || "",
7730
+ applyClassChange,
7731
+ allAnimations = o.children ? animated.find( "*" ).andSelf() : animated;
7732
+
7733
+ // map the animated objects to store the original styles.
7734
+ allAnimations = allAnimations.map(function() {
7735
+ var el = $( this );
7736
+ return {
7737
+ el: el,
7738
+ start: getElementStyles.call( this )
7739
+ };
7740
+ });
7741
+
7742
+ // apply class change
7743
+ applyClassChange = function() {
7744
+ $.each( classAnimationActions, function(i, action) {
7745
+ if ( value[ action ] ) {
7746
+ animated[ action + "Class" ]( value[ action ] );
7747
+ }
7748
+ });
7749
+ };
7750
+ applyClassChange();
7751
+
7752
+ // map all animated objects again - calculate new styles and diff
7753
+ allAnimations = allAnimations.map(function() {
7754
+ this.end = getElementStyles.call( this.el[ 0 ] );
7755
+ this.diff = styleDifference( this.start, this.end );
7756
+ return this;
7757
+ });
7758
+
7759
+ // apply original class
7760
+ animated.attr( "class", baseClass );
7761
+
7762
+ // map all animated objects again - this time collecting a promise
7763
+ allAnimations = allAnimations.map(function() {
7764
+ var styleInfo = this,
7765
+ dfd = $.Deferred(),
7766
+ opts = jQuery.extend({}, o, {
7767
+ queue: false,
7768
+ complete: function() {
7769
+ dfd.resolve( styleInfo );
7770
+ }
7771
+ });
7772
+
7773
+ this.el.animate( this.diff, opts );
7774
+ return dfd.promise();
7775
+ });
7776
+
7777
+ // once all animations have completed:
7778
+ $.when.apply( $, allAnimations.get() ).done(function() {
7779
+
7780
+ // set the final class
7781
+ applyClassChange();
7782
+
7783
+ // for each animated element,
7784
+ // clear all css properties that were animated
7785
+ $.each( arguments, function() {
7786
+ var el = this.el;
7787
+ $.each( this.diff, function(key) {
7788
+ el.css( key, '' );
7789
+ });
7790
+ });
7791
+
7792
+ // this is guarnteed to be there if you use jQuery.speed()
7793
+ // it also handles dequeuing the next anim...
7794
+ o.complete.call( animated[ 0 ] );
7795
+ });
7796
+ });
7797
+ };
7798
+
7799
+ $.fn.extend({
7800
+ _addClass: $.fn.addClass,
7801
+ addClass: function( classNames, speed, easing, callback ) {
7802
+ return speed ?
7803
+ $.effects.animateClass.call( this,
7804
+ { add: classNames }, speed, easing, callback ) :
7805
+ this._addClass( classNames );
7806
+ },
7807
+
7808
+ _removeClass: $.fn.removeClass,
7809
+ removeClass: function( classNames, speed, easing, callback ) {
7810
+ return speed ?
7811
+ $.effects.animateClass.call( this,
7812
+ { remove: classNames }, speed, easing, callback ) :
7813
+ this._removeClass( classNames );
7814
+ },
7815
+
7816
+ _toggleClass: $.fn.toggleClass,
7817
+ toggleClass: function( classNames, force, speed, easing, callback ) {
7818
+ if ( typeof force === "boolean" || force === undefined ) {
7819
+ if ( !speed ) {
7820
+ // without speed parameter
7821
+ return this._toggleClass( classNames, force );
7822
+ } else {
7823
+ return $.effects.animateClass.call( this,
7824
+ (force ? { add: classNames } : { remove: classNames }),
7825
+ speed, easing, callback );
7826
+ }
7827
+ } else {
7828
+ // without force parameter
7829
+ return $.effects.animateClass.call( this,
7830
+ { toggle: classNames }, force, speed, easing );
7831
+ }
7832
+ },
7833
+
7834
+ switchClass: function( remove, add, speed, easing, callback) {
7835
+ return $.effects.animateClass.call( this, {
7836
+ add: add,
7837
+ remove: remove
7838
+ }, speed, easing, callback );
7839
+ }
7840
+ });
7841
+
7842
+ })();
7843
+
7844
+ /******************************************************************************/
7845
+ /*********************************** EFFECTS **********************************/
7846
+ /******************************************************************************/
7847
+
7848
+ (function() {
7849
+
7850
+ $.extend( $.effects, {
7851
+ version: "1.9.1",
7852
+
7853
+ // Saves a set of properties in a data storage
7854
+ save: function( element, set ) {
7855
+ for( var i=0; i < set.length; i++ ) {
7856
+ if ( set[ i ] !== null ) {
7857
+ element.data( dataSpace + set[ i ], element[ 0 ].style[ set[ i ] ] );
7858
+ }
7859
+ }
7860
+ },
7861
+
7862
+ // Restores a set of previously saved properties from a data storage
7863
+ restore: function( element, set ) {
7864
+ var val, i;
7865
+ for( i=0; i < set.length; i++ ) {
7866
+ if ( set[ i ] !== null ) {
7867
+ val = element.data( dataSpace + set[ i ] );
7868
+ // support: jQuery 1.6.2
7869
+ // http://bugs.jquery.com/ticket/9917
7870
+ // jQuery 1.6.2 incorrectly returns undefined for any falsy value.
7871
+ // We can't differentiate between "" and 0 here, so we just assume
7872
+ // empty string since it's likely to be a more common value...
7873
+ if ( val === undefined ) {
7874
+ val = "";
7875
+ }
7876
+ element.css( set[ i ], val );
7877
+ }
7878
+ }
7879
+ },
7880
+
7881
+ setMode: function( el, mode ) {
7882
+ if (mode === "toggle") {
7883
+ mode = el.is( ":hidden" ) ? "show" : "hide";
7884
+ }
7885
+ return mode;
7886
+ },
7887
+
7888
+ // Translates a [top,left] array into a baseline value
7889
+ // this should be a little more flexible in the future to handle a string & hash
7890
+ getBaseline: function( origin, original ) {
7891
+ var y, x;
7892
+ switch ( origin[ 0 ] ) {
7893
+ case "top": y = 0; break;
7894
+ case "middle": y = 0.5; break;
7895
+ case "bottom": y = 1; break;
7896
+ default: y = origin[ 0 ] / original.height;
7897
+ }
7898
+ switch ( origin[ 1 ] ) {
7899
+ case "left": x = 0; break;
7900
+ case "center": x = 0.5; break;
7901
+ case "right": x = 1; break;
7902
+ default: x = origin[ 1 ] / original.width;
7903
+ }
7904
+ return {
7905
+ x: x,
7906
+ y: y
7907
+ };
7908
+ },
7909
+
7910
+ // Wraps the element around a wrapper that copies position properties
7911
+ createWrapper: function( element ) {
7912
+
7913
+ // if the element is already wrapped, return it
7914
+ if ( element.parent().is( ".ui-effects-wrapper" )) {
7915
+ return element.parent();
7916
+ }
7917
+
7918
+ // wrap the element
7919
+ var props = {
7920
+ width: element.outerWidth(true),
7921
+ height: element.outerHeight(true),
7922
+ "float": element.css( "float" )
7923
+ },
7924
+ wrapper = $( "<div></div>" )
7925
+ .addClass( "ui-effects-wrapper" )
7926
+ .css({
7927
+ fontSize: "100%",
7928
+ background: "transparent",
7929
+ border: "none",
7930
+ margin: 0,
7931
+ padding: 0
7932
+ }),
7933
+ // Store the size in case width/height are defined in % - Fixes #5245
7934
+ size = {
7935
+ width: element.width(),
7936
+ height: element.height()
7937
+ },
7938
+ active = document.activeElement;
7939
+
7940
+ // support: Firefox
7941
+ // Firefox incorrectly exposes anonymous content
7942
+ // https://bugzilla.mozilla.org/show_bug.cgi?id=561664
7943
+ try {
7944
+ active.id;
7945
+ } catch( e ) {
7946
+ active = document.body;
7947
+ }
7948
+
7949
+ element.wrap( wrapper );
7950
+
7951
+ // Fixes #7595 - Elements lose focus when wrapped.
7952
+ if ( element[ 0 ] === active || $.contains( element[ 0 ], active ) ) {
7953
+ $( active ).focus();
7954
+ }
7955
+
7956
+ wrapper = element.parent(); //Hotfix for jQuery 1.4 since some change in wrap() seems to actually lose the reference to the wrapped element
7957
+
7958
+ // transfer positioning properties to the wrapper
7959
+ if ( element.css( "position" ) === "static" ) {
7960
+ wrapper.css({ position: "relative" });
7961
+ element.css({ position: "relative" });
7962
+ } else {
7963
+ $.extend( props, {
7964
+ position: element.css( "position" ),
7965
+ zIndex: element.css( "z-index" )
7966
+ });
7967
+ $.each([ "top", "left", "bottom", "right" ], function(i, pos) {
7968
+ props[ pos ] = element.css( pos );
7969
+ if ( isNaN( parseInt( props[ pos ], 10 ) ) ) {
7970
+ props[ pos ] = "auto";
7971
+ }
7972
+ });
7973
+ element.css({
7974
+ position: "relative",
7975
+ top: 0,
7976
+ left: 0,
7977
+ right: "auto",
7978
+ bottom: "auto"
7979
+ });
7980
+ }
7981
+ element.css(size);
7982
+
7983
+ return wrapper.css( props ).show();
7984
+ },
7985
+
7986
+ removeWrapper: function( element ) {
7987
+ var active = document.activeElement;
7988
+
7989
+ if ( element.parent().is( ".ui-effects-wrapper" ) ) {
7990
+ element.parent().replaceWith( element );
7991
+
7992
+ // Fixes #7595 - Elements lose focus when wrapped.
7993
+ if ( element[ 0 ] === active || $.contains( element[ 0 ], active ) ) {
7994
+ $( active ).focus();
7995
+ }
7996
+ }
7997
+
7998
+
7999
+ return element;
8000
+ },
8001
+
8002
+ setTransition: function( element, list, factor, value ) {
8003
+ value = value || {};
8004
+ $.each( list, function( i, x ) {
8005
+ var unit = element.cssUnit( x );
8006
+ if ( unit[ 0 ] > 0 ) {
8007
+ value[ x ] = unit[ 0 ] * factor + unit[ 1 ];
8008
+ }
8009
+ });
8010
+ return value;
8011
+ }
8012
+ });
8013
+
8014
+ // return an effect options object for the given parameters:
8015
+ function _normalizeArguments( effect, options, speed, callback ) {
8016
+
8017
+ // allow passing all options as the first parameter
8018
+ if ( $.isPlainObject( effect ) ) {
8019
+ options = effect;
8020
+ effect = effect.effect;
8021
+ }
8022
+
8023
+ // convert to an object
8024
+ effect = { effect: effect };
8025
+
8026
+ // catch (effect, null, ...)
8027
+ if ( options == null ) {
8028
+ options = {};
8029
+ }
8030
+
8031
+ // catch (effect, callback)
8032
+ if ( $.isFunction( options ) ) {
8033
+ callback = options;
8034
+ speed = null;
8035
+ options = {};
8036
+ }
8037
+
8038
+ // catch (effect, speed, ?)
8039
+ if ( typeof options === "number" || $.fx.speeds[ options ] ) {
8040
+ callback = speed;
8041
+ speed = options;
8042
+ options = {};
8043
+ }
8044
+
8045
+ // catch (effect, options, callback)
8046
+ if ( $.isFunction( speed ) ) {
8047
+ callback = speed;
8048
+ speed = null;
8049
+ }
8050
+
8051
+ // add options to effect
8052
+ if ( options ) {
8053
+ $.extend( effect, options );
8054
+ }
8055
+
8056
+ speed = speed || options.duration;
8057
+ effect.duration = $.fx.off ? 0 :
8058
+ typeof speed === "number" ? speed :
8059
+ speed in $.fx.speeds ? $.fx.speeds[ speed ] :
8060
+ $.fx.speeds._default;
8061
+
8062
+ effect.complete = callback || options.complete;
8063
+
8064
+ return effect;
8065
+ }
8066
+
8067
+ function standardSpeed( speed ) {
8068
+ // valid standard speeds
8069
+ if ( !speed || typeof speed === "number" || $.fx.speeds[ speed ] ) {
8070
+ return true;
8071
+ }
8072
+
8073
+ // invalid strings - treat as "normal" speed
8074
+ if ( typeof speed === "string" && !$.effects.effect[ speed ] ) {
8075
+ // TODO: remove in 2.0 (#7115)
8076
+ if ( backCompat && $.effects[ speed ] ) {
8077
+ return false;
8078
+ }
8079
+ return true;
8080
+ }
8081
+
8082
+ return false;
8083
+ }
8084
+
8085
+ $.fn.extend({
8086
+ effect: function( /* effect, options, speed, callback */ ) {
8087
+ var args = _normalizeArguments.apply( this, arguments ),
8088
+ mode = args.mode,
8089
+ queue = args.queue,
8090
+ effectMethod = $.effects.effect[ args.effect ],
8091
+
8092
+ // DEPRECATED: remove in 2.0 (#7115)
8093
+ oldEffectMethod = !effectMethod && backCompat && $.effects[ args.effect ];
8094
+
8095
+ if ( $.fx.off || !( effectMethod || oldEffectMethod ) ) {
8096
+ // delegate to the original method (e.g., .show()) if possible
8097
+ if ( mode ) {
8098
+ return this[ mode ]( args.duration, args.complete );
8099
+ } else {
8100
+ return this.each( function() {
8101
+ if ( args.complete ) {
8102
+ args.complete.call( this );
8103
+ }
8104
+ });
8105
+ }
8106
+ }
8107
+
8108
+ function run( next ) {
8109
+ var elem = $( this ),
8110
+ complete = args.complete,
8111
+ mode = args.mode;
8112
+
8113
+ function done() {
8114
+ if ( $.isFunction( complete ) ) {
8115
+ complete.call( elem[0] );
8116
+ }
8117
+ if ( $.isFunction( next ) ) {
8118
+ next();
8119
+ }
8120
+ }
8121
+
8122
+ // if the element is hiddden and mode is hide,
8123
+ // or element is visible and mode is show
8124
+ if ( elem.is( ":hidden" ) ? mode === "hide" : mode === "show" ) {
8125
+ done();
8126
+ } else {
8127
+ effectMethod.call( elem[0], args, done );
8128
+ }
8129
+ }
8130
+
8131
+ // TODO: remove this check in 2.0, effectMethod will always be true
8132
+ if ( effectMethod ) {
8133
+ return queue === false ? this.each( run ) : this.queue( queue || "fx", run );
8134
+ } else {
8135
+ // DEPRECATED: remove in 2.0 (#7115)
8136
+ return oldEffectMethod.call(this, {
8137
+ options: args,
8138
+ duration: args.duration,
8139
+ callback: args.complete,
8140
+ mode: args.mode
8141
+ });
8142
+ }
8143
+ },
8144
+
8145
+ _show: $.fn.show,
8146
+ show: function( speed ) {
8147
+ if ( standardSpeed( speed ) ) {
8148
+ return this._show.apply( this, arguments );
8149
+ } else {
8150
+ var args = _normalizeArguments.apply( this, arguments );
8151
+ args.mode = "show";
8152
+ return this.effect.call( this, args );
8153
+ }
8154
+ },
8155
+
8156
+ _hide: $.fn.hide,
8157
+ hide: function( speed ) {
8158
+ if ( standardSpeed( speed ) ) {
8159
+ return this._hide.apply( this, arguments );
8160
+ } else {
8161
+ var args = _normalizeArguments.apply( this, arguments );
8162
+ args.mode = "hide";
8163
+ return this.effect.call( this, args );
8164
+ }
8165
+ },
8166
+
8167
+ // jQuery core overloads toggle and creates _toggle
8168
+ __toggle: $.fn.toggle,
8169
+ toggle: function( speed ) {
8170
+ if ( standardSpeed( speed ) || typeof speed === "boolean" || $.isFunction( speed ) ) {
8171
+ return this.__toggle.apply( this, arguments );
8172
+ } else {
8173
+ var args = _normalizeArguments.apply( this, arguments );
8174
+ args.mode = "toggle";
8175
+ return this.effect.call( this, args );
8176
+ }
8177
+ },
8178
+
8179
+ // helper functions
8180
+ cssUnit: function(key) {
8181
+ var style = this.css( key ),
8182
+ val = [];
8183
+
8184
+ $.each( [ "em", "px", "%", "pt" ], function( i, unit ) {
8185
+ if ( style.indexOf( unit ) > 0 ) {
8186
+ val = [ parseFloat( style ), unit ];
8187
+ }
8188
+ });
8189
+ return val;
8190
+ }
8191
+ });
8192
+
8193
+ })();
8194
+
8195
+ /******************************************************************************/
8196
+ /*********************************** EASING ***********************************/
8197
+ /******************************************************************************/
8198
+
8199
+ (function() {
8200
+
8201
+ // based on easing equations from Robert Penner (http://www.robertpenner.com/easing)
8202
+
8203
+ var baseEasings = {};
8204
+
8205
+ $.each( [ "Quad", "Cubic", "Quart", "Quint", "Expo" ], function( i, name ) {
8206
+ baseEasings[ name ] = function( p ) {
8207
+ return Math.pow( p, i + 2 );
8208
+ };
8209
+ });
8210
+
8211
+ $.extend( baseEasings, {
8212
+ Sine: function ( p ) {
8213
+ return 1 - Math.cos( p * Math.PI / 2 );
8214
+ },
8215
+ Circ: function ( p ) {
8216
+ return 1 - Math.sqrt( 1 - p * p );
8217
+ },
8218
+ Elastic: function( p ) {
8219
+ return p === 0 || p === 1 ? p :
8220
+ -Math.pow( 2, 8 * (p - 1) ) * Math.sin( ( (p - 1) * 80 - 7.5 ) * Math.PI / 15 );
8221
+ },
8222
+ Back: function( p ) {
8223
+ return p * p * ( 3 * p - 2 );
8224
+ },
8225
+ Bounce: function ( p ) {
8226
+ var pow2,
8227
+ bounce = 4;
8228
+
8229
+ while ( p < ( ( pow2 = Math.pow( 2, --bounce ) ) - 1 ) / 11 ) {}
8230
+ return 1 / Math.pow( 4, 3 - bounce ) - 7.5625 * Math.pow( ( pow2 * 3 - 2 ) / 22 - p, 2 );
8231
+ }
8232
+ });
8233
+
8234
+ $.each( baseEasings, function( name, easeIn ) {
8235
+ $.easing[ "easeIn" + name ] = easeIn;
8236
+ $.easing[ "easeOut" + name ] = function( p ) {
8237
+ return 1 - easeIn( 1 - p );
8238
+ };
8239
+ $.easing[ "easeInOut" + name ] = function( p ) {
8240
+ return p < 0.5 ?
8241
+ easeIn( p * 2 ) / 2 :
8242
+ 1 - easeIn( p * -2 + 2 ) / 2;
8243
+ };
8244
+ });
8245
+
8246
+ })();
8247
+
8248
+ })(jQuery));
8249
+ (function( $, undefined ) {
8250
+
8251
+ var rvertical = /up|down|vertical/,
8252
+ rpositivemotion = /up|left|vertical|horizontal/;
8253
+
8254
+ $.effects.effect.blind = function( o, done ) {
8255
+ // Create element
8256
+ var el = $( this ),
8257
+ props = [ "position", "top", "bottom", "left", "right", "height", "width" ],
8258
+ mode = $.effects.setMode( el, o.mode || "hide" ),
8259
+ direction = o.direction || "up",
8260
+ vertical = rvertical.test( direction ),
8261
+ ref = vertical ? "height" : "width",
8262
+ ref2 = vertical ? "top" : "left",
8263
+ motion = rpositivemotion.test( direction ),
8264
+ animation = {},
8265
+ show = mode === "show",
8266
+ wrapper, distance, margin;
8267
+
8268
+ // if already wrapped, the wrapper's properties are my property. #6245
8269
+ if ( el.parent().is( ".ui-effects-wrapper" ) ) {
8270
+ $.effects.save( el.parent(), props );
8271
+ } else {
8272
+ $.effects.save( el, props );
8273
+ }
8274
+ el.show();
8275
+ wrapper = $.effects.createWrapper( el ).css({
8276
+ overflow: "hidden"
8277
+ });
8278
+
8279
+ distance = wrapper[ ref ]();
8280
+ margin = parseFloat( wrapper.css( ref2 ) ) || 0;
8281
+
8282
+ animation[ ref ] = show ? distance : 0;
8283
+ if ( !motion ) {
8284
+ el
8285
+ .css( vertical ? "bottom" : "right", 0 )
8286
+ .css( vertical ? "top" : "left", "auto" )
8287
+ .css({ position: "absolute" });
8288
+
8289
+ animation[ ref2 ] = show ? margin : distance + margin;
8290
+ }
8291
+
8292
+ // start at 0 if we are showing
8293
+ if ( show ) {
8294
+ wrapper.css( ref, 0 );
8295
+ if ( ! motion ) {
8296
+ wrapper.css( ref2, margin + distance );
8297
+ }
8298
+ }
8299
+
8300
+ // Animate
8301
+ wrapper.animate( animation, {
8302
+ duration: o.duration,
8303
+ easing: o.easing,
8304
+ queue: false,
8305
+ complete: function() {
8306
+ if ( mode === "hide" ) {
8307
+ el.hide();
8308
+ }
8309
+ $.effects.restore( el, props );
8310
+ $.effects.removeWrapper( el );
8311
+ done();
8312
+ }
8313
+ });
8314
+
8315
+ };
8316
+
8317
+ })(jQuery);
8318
+ (function( $, undefined ) {
8319
+
8320
+ $.effects.effect.bounce = function( o, done ) {
8321
+ var el = $( this ),
8322
+ props = [ "position", "top", "bottom", "left", "right", "height", "width" ],
8323
+
8324
+ // defaults:
8325
+ mode = $.effects.setMode( el, o.mode || "effect" ),
8326
+ hide = mode === "hide",
8327
+ show = mode === "show",
8328
+ direction = o.direction || "up",
8329
+ distance = o.distance,
8330
+ times = o.times || 5,
8331
+
8332
+ // number of internal animations
8333
+ anims = times * 2 + ( show || hide ? 1 : 0 ),
8334
+ speed = o.duration / anims,
8335
+ easing = o.easing,
8336
+
8337
+ // utility:
8338
+ ref = ( direction === "up" || direction === "down" ) ? "top" : "left",
8339
+ motion = ( direction === "up" || direction === "left" ),
8340
+ i,
8341
+ upAnim,
8342
+ downAnim,
8343
+
8344
+ // we will need to re-assemble the queue to stack our animations in place
8345
+ queue = el.queue(),
8346
+ queuelen = queue.length;
8347
+
8348
+ // Avoid touching opacity to prevent clearType and PNG issues in IE
8349
+ if ( show || hide ) {
8350
+ props.push( "opacity" );
8351
+ }
8352
+
8353
+ $.effects.save( el, props );
8354
+ el.show();
8355
+ $.effects.createWrapper( el ); // Create Wrapper
8356
+
8357
+ // default distance for the BIGGEST bounce is the outer Distance / 3
8358
+ if ( !distance ) {
8359
+ distance = el[ ref === "top" ? "outerHeight" : "outerWidth" ]() / 3;
8360
+ }
8361
+
8362
+ if ( show ) {
8363
+ downAnim = { opacity: 1 };
8364
+ downAnim[ ref ] = 0;
8365
+
8366
+ // if we are showing, force opacity 0 and set the initial position
8367
+ // then do the "first" animation
8368
+ el.css( "opacity", 0 )
8369
+ .css( ref, motion ? -distance * 2 : distance * 2 )
8370
+ .animate( downAnim, speed, easing );
8371
+ }
8372
+
8373
+ // start at the smallest distance if we are hiding
8374
+ if ( hide ) {
8375
+ distance = distance / Math.pow( 2, times - 1 );
8376
+ }
8377
+
8378
+ downAnim = {};
8379
+ downAnim[ ref ] = 0;
8380
+ // Bounces up/down/left/right then back to 0 -- times * 2 animations happen here
8381
+ for ( i = 0; i < times; i++ ) {
8382
+ upAnim = {};
8383
+ upAnim[ ref ] = ( motion ? "-=" : "+=" ) + distance;
8384
+
8385
+ el.animate( upAnim, speed, easing )
8386
+ .animate( downAnim, speed, easing );
8387
+
8388
+ distance = hide ? distance * 2 : distance / 2;
8389
+ }
8390
+
8391
+ // Last Bounce when Hiding
8392
+ if ( hide ) {
8393
+ upAnim = { opacity: 0 };
8394
+ upAnim[ ref ] = ( motion ? "-=" : "+=" ) + distance;
8395
+
8396
+ el.animate( upAnim, speed, easing );
8397
+ }
8398
+
8399
+ el.queue(function() {
8400
+ if ( hide ) {
8401
+ el.hide();
8402
+ }
8403
+ $.effects.restore( el, props );
8404
+ $.effects.removeWrapper( el );
8405
+ done();
8406
+ });
8407
+
8408
+ // inject all the animations we just queued to be first in line (after "inprogress")
8409
+ if ( queuelen > 1) {
8410
+ queue.splice.apply( queue,
8411
+ [ 1, 0 ].concat( queue.splice( queuelen, anims + 1 ) ) );
8412
+ }
8413
+ el.dequeue();
8414
+
8415
+ };
8416
+
8417
+ })(jQuery);
8418
+ (function( $, undefined ) {
8419
+
8420
+ $.effects.effect.clip = function( o, done ) {
8421
+ // Create element
8422
+ var el = $( this ),
8423
+ props = [ "position", "top", "bottom", "left", "right", "height", "width" ],
8424
+ mode = $.effects.setMode( el, o.mode || "hide" ),
8425
+ show = mode === "show",
8426
+ direction = o.direction || "vertical",
8427
+ vert = direction === "vertical",
8428
+ size = vert ? "height" : "width",
8429
+ position = vert ? "top" : "left",
8430
+ animation = {},
8431
+ wrapper, animate, distance;
8432
+
8433
+ // Save & Show
8434
+ $.effects.save( el, props );
8435
+ el.show();
8436
+
8437
+ // Create Wrapper
8438
+ wrapper = $.effects.createWrapper( el ).css({
8439
+ overflow: "hidden"
8440
+ });
8441
+ animate = ( el[0].tagName === "IMG" ) ? wrapper : el;
8442
+ distance = animate[ size ]();
8443
+
8444
+ // Shift
8445
+ if ( show ) {
8446
+ animate.css( size, 0 );
8447
+ animate.css( position, distance / 2 );
8448
+ }
8449
+
8450
+ // Create Animation Object:
8451
+ animation[ size ] = show ? distance : 0;
8452
+ animation[ position ] = show ? 0 : distance / 2;
8453
+
8454
+ // Animate
8455
+ animate.animate( animation, {
8456
+ queue: false,
8457
+ duration: o.duration,
8458
+ easing: o.easing,
8459
+ complete: function() {
8460
+ if ( !show ) {
8461
+ el.hide();
8462
+ }
8463
+ $.effects.restore( el, props );
8464
+ $.effects.removeWrapper( el );
8465
+ done();
8466
+ }
8467
+ });
8468
+
8469
+ };
8470
+
8471
+ })(jQuery);
8472
+ (function( $, undefined ) {
8473
+
8474
+ $.effects.effect.drop = function( o, done ) {
8475
+
8476
+ var el = $( this ),
8477
+ props = [ "position", "top", "bottom", "left", "right", "opacity", "height", "width" ],
8478
+ mode = $.effects.setMode( el, o.mode || "hide" ),
8479
+ show = mode === "show",
8480
+ direction = o.direction || "left",
8481
+ ref = ( direction === "up" || direction === "down" ) ? "top" : "left",
8482
+ motion = ( direction === "up" || direction === "left" ) ? "pos" : "neg",
8483
+ animation = {
8484
+ opacity: show ? 1 : 0
8485
+ },
8486
+ distance;
8487
+
8488
+ // Adjust
8489
+ $.effects.save( el, props );
8490
+ el.show();
8491
+ $.effects.createWrapper( el );
8492
+
8493
+ distance = o.distance || el[ ref === "top" ? "outerHeight": "outerWidth" ]( true ) / 2;
8494
+
8495
+ if ( show ) {
8496
+ el
8497
+ .css( "opacity", 0 )
8498
+ .css( ref, motion === "pos" ? -distance : distance );
8499
+ }
8500
+
8501
+ // Animation
8502
+ animation[ ref ] = ( show ?
8503
+ ( motion === "pos" ? "+=" : "-=" ) :
8504
+ ( motion === "pos" ? "-=" : "+=" ) ) +
8505
+ distance;
8506
+
8507
+ // Animate
8508
+ el.animate( animation, {
8509
+ queue: false,
8510
+ duration: o.duration,
8511
+ easing: o.easing,
8512
+ complete: function() {
8513
+ if ( mode === "hide" ) {
8514
+ el.hide();
8515
+ }
8516
+ $.effects.restore( el, props );
8517
+ $.effects.removeWrapper( el );
8518
+ done();
8519
+ }
8520
+ });
8521
+ };
8522
+
8523
+ })(jQuery);
8524
+ (function( $, undefined ) {
8525
+
8526
+ $.effects.effect.explode = function( o, done ) {
8527
+
8528
+ var rows = o.pieces ? Math.round( Math.sqrt( o.pieces ) ) : 3,
8529
+ cells = rows,
8530
+ el = $( this ),
8531
+ mode = $.effects.setMode( el, o.mode || "hide" ),
8532
+ show = mode === "show",
8533
+
8534
+ // show and then visibility:hidden the element before calculating offset
8535
+ offset = el.show().css( "visibility", "hidden" ).offset(),
8536
+
8537
+ // width and height of a piece
8538
+ width = Math.ceil( el.outerWidth() / cells ),
8539
+ height = Math.ceil( el.outerHeight() / rows ),
8540
+ pieces = [],
8541
+
8542
+ // loop
8543
+ i, j, left, top, mx, my;
8544
+
8545
+ // children animate complete:
8546
+ function childComplete() {
8547
+ pieces.push( this );
8548
+ if ( pieces.length === rows * cells ) {
8549
+ animComplete();
8550
+ }
8551
+ }
8552
+
8553
+ // clone the element for each row and cell.
8554
+ for( i = 0; i < rows ; i++ ) { // ===>
8555
+ top = offset.top + i * height;
8556
+ my = i - ( rows - 1 ) / 2 ;
8557
+
8558
+ for( j = 0; j < cells ; j++ ) { // |||
8559
+ left = offset.left + j * width;
8560
+ mx = j - ( cells - 1 ) / 2 ;
8561
+
8562
+ // Create a clone of the now hidden main element that will be absolute positioned
8563
+ // within a wrapper div off the -left and -top equal to size of our pieces
8564
+ el
8565
+ .clone()
8566
+ .appendTo( "body" )
8567
+ .wrap( "<div></div>" )
8568
+ .css({
8569
+ position: "absolute",
8570
+ visibility: "visible",
8571
+ left: -j * width,
8572
+ top: -i * height
8573
+ })
8574
+
8575
+ // select the wrapper - make it overflow: hidden and absolute positioned based on
8576
+ // where the original was located +left and +top equal to the size of pieces
8577
+ .parent()
8578
+ .addClass( "ui-effects-explode" )
8579
+ .css({
8580
+ position: "absolute",
8581
+ overflow: "hidden",
8582
+ width: width,
8583
+ height: height,
8584
+ left: left + ( show ? mx * width : 0 ),
8585
+ top: top + ( show ? my * height : 0 ),
8586
+ opacity: show ? 0 : 1
8587
+ }).animate({
8588
+ left: left + ( show ? 0 : mx * width ),
8589
+ top: top + ( show ? 0 : my * height ),
8590
+ opacity: show ? 1 : 0
8591
+ }, o.duration || 500, o.easing, childComplete );
8592
+ }
8593
+ }
8594
+
8595
+ function animComplete() {
8596
+ el.css({
8597
+ visibility: "visible"
8598
+ });
8599
+ $( pieces ).remove();
8600
+ if ( !show ) {
8601
+ el.hide();
8602
+ }
8603
+ done();
8604
+ }
8605
+ };
8606
+
8607
+ })(jQuery);
8608
+ (function( $, undefined ) {
8609
+
8610
+ $.effects.effect.fade = function( o, done ) {
8611
+ var el = $( this ),
8612
+ mode = $.effects.setMode( el, o.mode || "toggle" );
8613
+
8614
+ el.animate({
8615
+ opacity: mode
8616
+ }, {
8617
+ queue: false,
8618
+ duration: o.duration,
8619
+ easing: o.easing,
8620
+ complete: done
8621
+ });
8622
+ };
8623
+
8624
+ })( jQuery );
8625
+ (function( $, undefined ) {
8626
+
8627
+ $.effects.effect.fold = function( o, done ) {
8628
+
8629
+ // Create element
8630
+ var el = $( this ),
8631
+ props = [ "position", "top", "bottom", "left", "right", "height", "width" ],
8632
+ mode = $.effects.setMode( el, o.mode || "hide" ),
8633
+ show = mode === "show",
8634
+ hide = mode === "hide",
8635
+ size = o.size || 15,
8636
+ percent = /([0-9]+)%/.exec( size ),
8637
+ horizFirst = !!o.horizFirst,
8638
+ widthFirst = show !== horizFirst,
8639
+ ref = widthFirst ? [ "width", "height" ] : [ "height", "width" ],
8640
+ duration = o.duration / 2,
8641
+ wrapper, distance,
8642
+ animation1 = {},
8643
+ animation2 = {};
8644
+
8645
+ $.effects.save( el, props );
8646
+ el.show();
8647
+
8648
+ // Create Wrapper
8649
+ wrapper = $.effects.createWrapper( el ).css({
8650
+ overflow: "hidden"
8651
+ });
8652
+ distance = widthFirst ?
8653
+ [ wrapper.width(), wrapper.height() ] :
8654
+ [ wrapper.height(), wrapper.width() ];
8655
+
8656
+ if ( percent ) {
8657
+ size = parseInt( percent[ 1 ], 10 ) / 100 * distance[ hide ? 0 : 1 ];
8658
+ }
8659
+ if ( show ) {
8660
+ wrapper.css( horizFirst ? {
8661
+ height: 0,
8662
+ width: size
8663
+ } : {
8664
+ height: size,
8665
+ width: 0
8666
+ });
8667
+ }
8668
+
8669
+ // Animation
8670
+ animation1[ ref[ 0 ] ] = show ? distance[ 0 ] : size;
8671
+ animation2[ ref[ 1 ] ] = show ? distance[ 1 ] : 0;
8672
+
8673
+ // Animate
8674
+ wrapper
8675
+ .animate( animation1, duration, o.easing )
8676
+ .animate( animation2, duration, o.easing, function() {
8677
+ if ( hide ) {
8678
+ el.hide();
8679
+ }
8680
+ $.effects.restore( el, props );
8681
+ $.effects.removeWrapper( el );
8682
+ done();
8683
+ });
8684
+
8685
+ };
8686
+
8687
+ })(jQuery);
8688
+ (function( $, undefined ) {
8689
+
8690
+ $.effects.effect.highlight = function( o, done ) {
8691
+ var elem = $( this ),
8692
+ props = [ "backgroundImage", "backgroundColor", "opacity" ],
8693
+ mode = $.effects.setMode( elem, o.mode || "show" ),
8694
+ animation = {
8695
+ backgroundColor: elem.css( "backgroundColor" )
8696
+ };
8697
+
8698
+ if (mode === "hide") {
8699
+ animation.opacity = 0;
8700
+ }
8701
+
8702
+ $.effects.save( elem, props );
8703
+
8704
+ elem
8705
+ .show()
8706
+ .css({
8707
+ backgroundImage: "none",
8708
+ backgroundColor: o.color || "#ffff99"
8709
+ })
8710
+ .animate( animation, {
8711
+ queue: false,
8712
+ duration: o.duration,
8713
+ easing: o.easing,
8714
+ complete: function() {
8715
+ if ( mode === "hide" ) {
8716
+ elem.hide();
8717
+ }
8718
+ $.effects.restore( elem, props );
8719
+ done();
8720
+ }
8721
+ });
8722
+ };
8723
+
8724
+ })(jQuery);
8725
+ (function( $, undefined ) {
8726
+
8727
+ $.effects.effect.pulsate = function( o, done ) {
8728
+ var elem = $( this ),
8729
+ mode = $.effects.setMode( elem, o.mode || "show" ),
8730
+ show = mode === "show",
8731
+ hide = mode === "hide",
8732
+ showhide = ( show || mode === "hide" ),
8733
+
8734
+ // showing or hiding leaves of the "last" animation
8735
+ anims = ( ( o.times || 5 ) * 2 ) + ( showhide ? 1 : 0 ),
8736
+ duration = o.duration / anims,
8737
+ animateTo = 0,
8738
+ queue = elem.queue(),
8739
+ queuelen = queue.length,
8740
+ i;
8741
+
8742
+ if ( show || !elem.is(":visible")) {
8743
+ elem.css( "opacity", 0 ).show();
8744
+ animateTo = 1;
8745
+ }
8746
+
8747
+ // anims - 1 opacity "toggles"
8748
+ for ( i = 1; i < anims; i++ ) {
8749
+ elem.animate({
8750
+ opacity: animateTo
8751
+ }, duration, o.easing );
8752
+ animateTo = 1 - animateTo;
8753
+ }
8754
+
8755
+ elem.animate({
8756
+ opacity: animateTo
8757
+ }, duration, o.easing);
8758
+
8759
+ elem.queue(function() {
8760
+ if ( hide ) {
8761
+ elem.hide();
8762
+ }
8763
+ done();
8764
+ });
8765
+
8766
+ // We just queued up "anims" animations, we need to put them next in the queue
8767
+ if ( queuelen > 1 ) {
8768
+ queue.splice.apply( queue,
8769
+ [ 1, 0 ].concat( queue.splice( queuelen, anims + 1 ) ) );
8770
+ }
8771
+ elem.dequeue();
8772
+ };
8773
+
8774
+ })(jQuery);
8775
+ (function( $, undefined ) {
8776
+
8777
+ $.effects.effect.puff = function( o, done ) {
8778
+ var elem = $( this ),
8779
+ mode = $.effects.setMode( elem, o.mode || "hide" ),
8780
+ hide = mode === "hide",
8781
+ percent = parseInt( o.percent, 10 ) || 150,
8782
+ factor = percent / 100,
8783
+ original = {
8784
+ height: elem.height(),
8785
+ width: elem.width()
8786
+ };
8787
+
8788
+ $.extend( o, {
8789
+ effect: "scale",
8790
+ queue: false,
8791
+ fade: true,
8792
+ mode: mode,
8793
+ complete: done,
8794
+ percent: hide ? percent : 100,
8795
+ from: hide ?
8796
+ original :
8797
+ {
8798
+ height: original.height * factor,
8799
+ width: original.width * factor
8800
+ }
8801
+ });
8802
+
8803
+ elem.effect( o );
8804
+ };
8805
+
8806
+ $.effects.effect.scale = function( o, done ) {
8807
+
8808
+ // Create element
8809
+ var el = $( this ),
8810
+ options = $.extend( true, {}, o ),
8811
+ mode = $.effects.setMode( el, o.mode || "effect" ),
8812
+ percent = parseInt( o.percent, 10 ) ||
8813
+ ( parseInt( o.percent, 10 ) === 0 ? 0 : ( mode === "hide" ? 0 : 100 ) ),
8814
+ direction = o.direction || "both",
8815
+ origin = o.origin,
8816
+ original = {
8817
+ height: el.height(),
8818
+ width: el.width(),
8819
+ outerHeight: el.outerHeight(),
8820
+ outerWidth: el.outerWidth()
8821
+ },
8822
+ factor = {
8823
+ y: direction !== "horizontal" ? (percent / 100) : 1,
8824
+ x: direction !== "vertical" ? (percent / 100) : 1
8825
+ };
8826
+
8827
+ // We are going to pass this effect to the size effect:
8828
+ options.effect = "size";
8829
+ options.queue = false;
8830
+ options.complete = done;
8831
+
8832
+ // Set default origin and restore for show/hide
8833
+ if ( mode !== "effect" ) {
8834
+ options.origin = origin || ["middle","center"];
8835
+ options.restore = true;
8836
+ }
8837
+
8838
+ options.from = o.from || ( mode === "show" ? { height: 0, width: 0 } : original );
8839
+ options.to = {
8840
+ height: original.height * factor.y,
8841
+ width: original.width * factor.x,
8842
+ outerHeight: original.outerHeight * factor.y,
8843
+ outerWidth: original.outerWidth * factor.x
8844
+ };
8845
+
8846
+ // Fade option to support puff
8847
+ if ( options.fade ) {
8848
+ if ( mode === "show" ) {
8849
+ options.from.opacity = 0;
8850
+ options.to.opacity = 1;
8851
+ }
8852
+ if ( mode === "hide" ) {
8853
+ options.from.opacity = 1;
8854
+ options.to.opacity = 0;
8855
+ }
8856
+ }
8857
+
8858
+ // Animate
8859
+ el.effect( options );
8860
+
8861
+ };
8862
+
8863
+ $.effects.effect.size = function( o, done ) {
8864
+
8865
+ // Create element
8866
+ var original, baseline, factor,
8867
+ el = $( this ),
8868
+ props0 = [ "position", "top", "bottom", "left", "right", "width", "height", "overflow", "opacity" ],
8869
+
8870
+ // Always restore
8871
+ props1 = [ "position", "top", "bottom", "left", "right", "overflow", "opacity" ],
8872
+
8873
+ // Copy for children
8874
+ props2 = [ "width", "height", "overflow" ],
8875
+ cProps = [ "fontSize" ],
8876
+ vProps = [ "borderTopWidth", "borderBottomWidth", "paddingTop", "paddingBottom" ],
8877
+ hProps = [ "borderLeftWidth", "borderRightWidth", "paddingLeft", "paddingRight" ],
8878
+
8879
+ // Set options
8880
+ mode = $.effects.setMode( el, o.mode || "effect" ),
8881
+ restore = o.restore || mode !== "effect",
8882
+ scale = o.scale || "both",
8883
+ origin = o.origin || [ "middle", "center" ],
8884
+ position = el.css( "position" ),
8885
+ props = restore ? props0 : props1,
8886
+ zero = {
8887
+ height: 0,
8888
+ width: 0
8889
+ };
8890
+
8891
+ if ( mode === "show" ) {
8892
+ el.show();
8893
+ }
8894
+ original = {
8895
+ height: el.height(),
8896
+ width: el.width(),
8897
+ outerHeight: el.outerHeight(),
8898
+ outerWidth: el.outerWidth()
8899
+ };
8900
+
8901
+ if ( o.mode === "toggle" && mode === "show" ) {
8902
+ el.from = o.to || zero;
8903
+ el.to = o.from || original;
8904
+ } else {
8905
+ el.from = o.from || ( mode === "show" ? zero : original );
8906
+ el.to = o.to || ( mode === "hide" ? zero : original );
8907
+ }
8908
+
8909
+ // Set scaling factor
8910
+ factor = {
8911
+ from: {
8912
+ y: el.from.height / original.height,
8913
+ x: el.from.width / original.width
8914
+ },
8915
+ to: {
8916
+ y: el.to.height / original.height,
8917
+ x: el.to.width / original.width
8918
+ }
8919
+ };
8920
+
8921
+ // Scale the css box
8922
+ if ( scale === "box" || scale === "both" ) {
8923
+
8924
+ // Vertical props scaling
8925
+ if ( factor.from.y !== factor.to.y ) {
8926
+ props = props.concat( vProps );
8927
+ el.from = $.effects.setTransition( el, vProps, factor.from.y, el.from );
8928
+ el.to = $.effects.setTransition( el, vProps, factor.to.y, el.to );
8929
+ }
8930
+
8931
+ // Horizontal props scaling
8932
+ if ( factor.from.x !== factor.to.x ) {
8933
+ props = props.concat( hProps );
8934
+ el.from = $.effects.setTransition( el, hProps, factor.from.x, el.from );
8935
+ el.to = $.effects.setTransition( el, hProps, factor.to.x, el.to );
8936
+ }
8937
+ }
8938
+
8939
+ // Scale the content
8940
+ if ( scale === "content" || scale === "both" ) {
8941
+
8942
+ // Vertical props scaling
8943
+ if ( factor.from.y !== factor.to.y ) {
8944
+ props = props.concat( cProps ).concat( props2 );
8945
+ el.from = $.effects.setTransition( el, cProps, factor.from.y, el.from );
8946
+ el.to = $.effects.setTransition( el, cProps, factor.to.y, el.to );
8947
+ }
8948
+ }
8949
+
8950
+ $.effects.save( el, props );
8951
+ el.show();
8952
+ $.effects.createWrapper( el );
8953
+ el.css( "overflow", "hidden" ).css( el.from );
8954
+
8955
+ // Adjust
8956
+ if (origin) { // Calculate baseline shifts
8957
+ baseline = $.effects.getBaseline( origin, original );
8958
+ el.from.top = ( original.outerHeight - el.outerHeight() ) * baseline.y;
8959
+ el.from.left = ( original.outerWidth - el.outerWidth() ) * baseline.x;
8960
+ el.to.top = ( original.outerHeight - el.to.outerHeight ) * baseline.y;
8961
+ el.to.left = ( original.outerWidth - el.to.outerWidth ) * baseline.x;
8962
+ }
8963
+ el.css( el.from ); // set top & left
8964
+
8965
+ // Animate
8966
+ if ( scale === "content" || scale === "both" ) { // Scale the children
8967
+
8968
+ // Add margins/font-size
8969
+ vProps = vProps.concat([ "marginTop", "marginBottom" ]).concat(cProps);
8970
+ hProps = hProps.concat([ "marginLeft", "marginRight" ]);
8971
+ props2 = props0.concat(vProps).concat(hProps);
8972
+
8973
+ el.find( "*[width]" ).each( function(){
8974
+ var child = $( this ),
8975
+ c_original = {
8976
+ height: child.height(),
8977
+ width: child.width()
8978
+ };
8979
+ if (restore) {
8980
+ $.effects.save(child, props2);
8981
+ }
8982
+
8983
+ child.from = {
8984
+ height: c_original.height * factor.from.y,
8985
+ width: c_original.width * factor.from.x
8986
+ };
8987
+ child.to = {
8988
+ height: c_original.height * factor.to.y,
8989
+ width: c_original.width * factor.to.x
8990
+ };
8991
+
8992
+ // Vertical props scaling
8993
+ if ( factor.from.y !== factor.to.y ) {
8994
+ child.from = $.effects.setTransition( child, vProps, factor.from.y, child.from );
8995
+ child.to = $.effects.setTransition( child, vProps, factor.to.y, child.to );
8996
+ }
8997
+
8998
+ // Horizontal props scaling
8999
+ if ( factor.from.x !== factor.to.x ) {
9000
+ child.from = $.effects.setTransition( child, hProps, factor.from.x, child.from );
9001
+ child.to = $.effects.setTransition( child, hProps, factor.to.x, child.to );
9002
+ }
9003
+
9004
+ // Animate children
9005
+ child.css( child.from );
9006
+ child.animate( child.to, o.duration, o.easing, function() {
9007
+
9008
+ // Restore children
9009
+ if ( restore ) {
9010
+ $.effects.restore( child, props2 );
9011
+ }
9012
+ });
9013
+ });
9014
+ }
9015
+
9016
+ // Animate
9017
+ el.animate( el.to, {
9018
+ queue: false,
9019
+ duration: o.duration,
9020
+ easing: o.easing,
9021
+ complete: function() {
9022
+ if ( el.to.opacity === 0 ) {
9023
+ el.css( "opacity", el.from.opacity );
9024
+ }
9025
+ if( mode === "hide" ) {
9026
+ el.hide();
9027
+ }
9028
+ $.effects.restore( el, props );
9029
+ if ( !restore ) {
9030
+
9031
+ // we need to calculate our new positioning based on the scaling
9032
+ if ( position === "static" ) {
9033
+ el.css({
9034
+ position: "relative",
9035
+ top: el.to.top,
9036
+ left: el.to.left
9037
+ });
9038
+ } else {
9039
+ $.each([ "top", "left" ], function( idx, pos ) {
9040
+ el.css( pos, function( _, str ) {
9041
+ var val = parseInt( str, 10 ),
9042
+ toRef = idx ? el.to.left : el.to.top;
9043
+
9044
+ // if original was "auto", recalculate the new value from wrapper
9045
+ if ( str === "auto" ) {
9046
+ return toRef + "px";
9047
+ }
9048
+
9049
+ return val + toRef + "px";
9050
+ });
9051
+ });
9052
+ }
9053
+ }
9054
+
9055
+ $.effects.removeWrapper( el );
9056
+ done();
9057
+ }
9058
+ });
9059
+
9060
+ };
9061
+
9062
+ })(jQuery);
9063
+ (function( $, undefined ) {
9064
+
9065
+ $.effects.effect.shake = function( o, done ) {
9066
+
9067
+ var el = $( this ),
9068
+ props = [ "position", "top", "bottom", "left", "right", "height", "width" ],
9069
+ mode = $.effects.setMode( el, o.mode || "effect" ),
9070
+ direction = o.direction || "left",
9071
+ distance = o.distance || 20,
9072
+ times = o.times || 3,
9073
+ anims = times * 2 + 1,
9074
+ speed = Math.round(o.duration/anims),
9075
+ ref = (direction === "up" || direction === "down") ? "top" : "left",
9076
+ positiveMotion = (direction === "up" || direction === "left"),
9077
+ animation = {},
9078
+ animation1 = {},
9079
+ animation2 = {},
9080
+ i,
9081
+
9082
+ // we will need to re-assemble the queue to stack our animations in place
9083
+ queue = el.queue(),
9084
+ queuelen = queue.length;
9085
+
9086
+ $.effects.save( el, props );
9087
+ el.show();
9088
+ $.effects.createWrapper( el );
9089
+
9090
+ // Animation
9091
+ animation[ ref ] = ( positiveMotion ? "-=" : "+=" ) + distance;
9092
+ animation1[ ref ] = ( positiveMotion ? "+=" : "-=" ) + distance * 2;
9093
+ animation2[ ref ] = ( positiveMotion ? "-=" : "+=" ) + distance * 2;
9094
+
9095
+ // Animate
9096
+ el.animate( animation, speed, o.easing );
9097
+
9098
+ // Shakes
9099
+ for ( i = 1; i < times; i++ ) {
9100
+ el.animate( animation1, speed, o.easing ).animate( animation2, speed, o.easing );
9101
+ }
9102
+ el
9103
+ .animate( animation1, speed, o.easing )
9104
+ .animate( animation, speed / 2, o.easing )
9105
+ .queue(function() {
9106
+ if ( mode === "hide" ) {
9107
+ el.hide();
9108
+ }
9109
+ $.effects.restore( el, props );
9110
+ $.effects.removeWrapper( el );
9111
+ done();
9112
+ });
9113
+
9114
+ // inject all the animations we just queued to be first in line (after "inprogress")
9115
+ if ( queuelen > 1) {
9116
+ queue.splice.apply( queue,
9117
+ [ 1, 0 ].concat( queue.splice( queuelen, anims + 1 ) ) );
9118
+ }
9119
+ el.dequeue();
9120
+
9121
+ };
9122
+
9123
+ })(jQuery);
9124
+ (function( $, undefined ) {
9125
+
9126
+ $.effects.effect.slide = function( o, done ) {
9127
+
9128
+ // Create element
9129
+ var el = $( this ),
9130
+ props = [ "position", "top", "bottom", "left", "right", "width", "height" ],
9131
+ mode = $.effects.setMode( el, o.mode || "show" ),
9132
+ show = mode === "show",
9133
+ direction = o.direction || "left",
9134
+ ref = (direction === "up" || direction === "down") ? "top" : "left",
9135
+ positiveMotion = (direction === "up" || direction === "left"),
9136
+ distance,
9137
+ animation = {};
9138
+
9139
+ // Adjust
9140
+ $.effects.save( el, props );
9141
+ el.show();
9142
+ distance = o.distance || el[ ref === "top" ? "outerHeight" : "outerWidth" ]( true );
9143
+
9144
+ $.effects.createWrapper( el ).css({
9145
+ overflow: "hidden"
9146
+ });
9147
+
9148
+ if ( show ) {
9149
+ el.css( ref, positiveMotion ? (isNaN(distance) ? "-" + distance : -distance) : distance );
9150
+ }
9151
+
9152
+ // Animation
9153
+ animation[ ref ] = ( show ?
9154
+ ( positiveMotion ? "+=" : "-=") :
9155
+ ( positiveMotion ? "-=" : "+=")) +
9156
+ distance;
9157
+
9158
+ // Animate
9159
+ el.animate( animation, {
9160
+ queue: false,
9161
+ duration: o.duration,
9162
+ easing: o.easing,
9163
+ complete: function() {
9164
+ if ( mode === "hide" ) {
9165
+ el.hide();
9166
+ }
9167
+ $.effects.restore( el, props );
9168
+ $.effects.removeWrapper( el );
9169
+ done();
9170
+ }
9171
+ });
9172
+ };
9173
+
9174
+ })(jQuery);
9175
+ (function( $, undefined ) {
9176
+
9177
+ $.effects.effect.transfer = function( o, done ) {
9178
+ var elem = $( this ),
9179
+ target = $( o.to ),
9180
+ targetFixed = target.css( "position" ) === "fixed",
9181
+ body = $("body"),
9182
+ fixTop = targetFixed ? body.scrollTop() : 0,
9183
+ fixLeft = targetFixed ? body.scrollLeft() : 0,
9184
+ endPosition = target.offset(),
9185
+ animation = {
9186
+ top: endPosition.top - fixTop ,
9187
+ left: endPosition.left - fixLeft ,
9188
+ height: target.innerHeight(),
9189
+ width: target.innerWidth()
9190
+ },
9191
+ startPosition = elem.offset(),
9192
+ transfer = $( '<div class="ui-effects-transfer"></div>' )
9193
+ .appendTo( document.body )
9194
+ .addClass( o.className )
9195
+ .css({
9196
+ top: startPosition.top - fixTop ,
9197
+ left: startPosition.left - fixLeft ,
9198
+ height: elem.innerHeight(),
9199
+ width: elem.innerWidth(),
9200
+ position: targetFixed ? "fixed" : "absolute"
9201
+ })
9202
+ .animate( animation, o.duration, o.easing, function() {
9203
+ transfer.remove();
9204
+ done();
9205
+ });
9206
+ };
9207
+
9208
+ })(jQuery);
9209
+ (function( $, undefined ) {
9210
+
9211
+ var mouseHandled = false;
9212
+
9213
+ $.widget( "ui.menu", {
9214
+ version: "1.9.1",
9215
+ defaultElement: "<ul>",
9216
+ delay: 300,
9217
+ options: {
9218
+ icons: {
9219
+ submenu: "ui-icon-carat-1-e"
9220
+ },
9221
+ menus: "ul",
9222
+ position: {
9223
+ my: "left top",
9224
+ at: "right top"
9225
+ },
9226
+ role: "menu",
9227
+
9228
+ // callbacks
9229
+ blur: null,
9230
+ focus: null,
9231
+ select: null
9232
+ },
9233
+
9234
+ _create: function() {
9235
+ this.activeMenu = this.element;
9236
+ this.element
9237
+ .uniqueId()
9238
+ .addClass( "ui-menu ui-widget ui-widget-content ui-corner-all" )
9239
+ .toggleClass( "ui-menu-icons", !!this.element.find( ".ui-icon" ).length )
9240
+ .attr({
9241
+ role: this.options.role,
9242
+ tabIndex: 0
9243
+ })
9244
+ // need to catch all clicks on disabled menu
9245
+ // not possible through _on
9246
+ .bind( "click" + this.eventNamespace, $.proxy(function( event ) {
9247
+ if ( this.options.disabled ) {
9248
+ event.preventDefault();
9249
+ }
9250
+ }, this ));
9251
+
9252
+ if ( this.options.disabled ) {
9253
+ this.element
9254
+ .addClass( "ui-state-disabled" )
9255
+ .attr( "aria-disabled", "true" );
9256
+ }
9257
+
9258
+ this._on({
9259
+ // Prevent focus from sticking to links inside menu after clicking
9260
+ // them (focus should always stay on UL during navigation).
9261
+ "mousedown .ui-menu-item > a": function( event ) {
9262
+ event.preventDefault();
9263
+ },
9264
+ "click .ui-state-disabled > a": function( event ) {
9265
+ event.preventDefault();
9266
+ },
9267
+ "click .ui-menu-item:has(a)": function( event ) {
9268
+ var target = $( event.target ).closest( ".ui-menu-item" );
9269
+ if ( !mouseHandled && target.not( ".ui-state-disabled" ).length ) {
9270
+ mouseHandled = true;
9271
+
9272
+ this.select( event );
9273
+ // Open submenu on click
9274
+ if ( target.has( ".ui-menu" ).length ) {
9275
+ this.expand( event );
9276
+ } else if ( !this.element.is( ":focus" ) ) {
9277
+ // Redirect focus to the menu
9278
+ this.element.trigger( "focus", [ true ] );
9279
+
9280
+ // If the active item is on the top level, let it stay active.
9281
+ // Otherwise, blur the active item since it is no longer visible.
9282
+ if ( this.active && this.active.parents( ".ui-menu" ).length === 1 ) {
9283
+ clearTimeout( this.timer );
9284
+ }
9285
+ }
9286
+ }
9287
+ },
9288
+ "mouseenter .ui-menu-item": function( event ) {
9289
+ var target = $( event.currentTarget );
9290
+ // Remove ui-state-active class from siblings of the newly focused menu item
9291
+ // to avoid a jump caused by adjacent elements both having a class with a border
9292
+ target.siblings().children( ".ui-state-active" ).removeClass( "ui-state-active" );
9293
+ this.focus( event, target );
9294
+ },
9295
+ mouseleave: "collapseAll",
9296
+ "mouseleave .ui-menu": "collapseAll",
9297
+ focus: function( event, keepActiveItem ) {
9298
+ // If there's already an active item, keep it active
9299
+ // If not, activate the first item
9300
+ var item = this.active || this.element.children( ".ui-menu-item" ).eq( 0 );
9301
+
9302
+ if ( !keepActiveItem ) {
9303
+ this.focus( event, item );
9304
+ }
9305
+ },
9306
+ blur: function( event ) {
9307
+ this._delay(function() {
9308
+ if ( !$.contains( this.element[0], this.document[0].activeElement ) ) {
9309
+ this.collapseAll( event );
9310
+ }
9311
+ });
9312
+ },
9313
+ keydown: "_keydown"
9314
+ });
9315
+
9316
+ this.refresh();
9317
+
9318
+ // Clicks outside of a menu collapse any open menus
9319
+ this._on( this.document, {
9320
+ click: function( event ) {
9321
+ if ( !$( event.target ).closest( ".ui-menu" ).length ) {
9322
+ this.collapseAll( event );
9323
+ }
9324
+
9325
+ // Reset the mouseHandled flag
9326
+ mouseHandled = false;
9327
+ }
9328
+ });
9329
+ },
9330
+
9331
+ _destroy: function() {
9332
+ // Destroy (sub)menus
9333
+ this.element
9334
+ .removeAttr( "aria-activedescendant" )
9335
+ .find( ".ui-menu" ).andSelf()
9336
+ .removeClass( "ui-menu ui-widget ui-widget-content ui-corner-all ui-menu-icons" )
9337
+ .removeAttr( "role" )
9338
+ .removeAttr( "tabIndex" )
9339
+ .removeAttr( "aria-labelledby" )
9340
+ .removeAttr( "aria-expanded" )
9341
+ .removeAttr( "aria-hidden" )
9342
+ .removeAttr( "aria-disabled" )
9343
+ .removeUniqueId()
9344
+ .show();
9345
+
9346
+ // Destroy menu items
9347
+ this.element.find( ".ui-menu-item" )
9348
+ .removeClass( "ui-menu-item" )
9349
+ .removeAttr( "role" )
9350
+ .removeAttr( "aria-disabled" )
9351
+ .children( "a" )
9352
+ .removeUniqueId()
9353
+ .removeClass( "ui-corner-all ui-state-hover" )
9354
+ .removeAttr( "tabIndex" )
9355
+ .removeAttr( "role" )
9356
+ .removeAttr( "aria-haspopup" )
9357
+ .children().each( function() {
9358
+ var elem = $( this );
9359
+ if ( elem.data( "ui-menu-submenu-carat" ) ) {
9360
+ elem.remove();
9361
+ }
9362
+ });
9363
+
9364
+ // Destroy menu dividers
9365
+ this.element.find( ".ui-menu-divider" ).removeClass( "ui-menu-divider ui-widget-content" );
9366
+ },
9367
+
9368
+ _keydown: function( event ) {
9369
+ var match, prev, character, skip, regex,
9370
+ preventDefault = true;
9371
+
9372
+ function escape( value ) {
9373
+ return value.replace( /[\-\[\]{}()*+?.,\\\^$|#\s]/g, "\\$&" );
9374
+ }
9375
+
9376
+ switch ( event.keyCode ) {
9377
+ case $.ui.keyCode.PAGE_UP:
9378
+ this.previousPage( event );
9379
+ break;
9380
+ case $.ui.keyCode.PAGE_DOWN:
9381
+ this.nextPage( event );
9382
+ break;
9383
+ case $.ui.keyCode.HOME:
9384
+ this._move( "first", "first", event );
9385
+ break;
9386
+ case $.ui.keyCode.END:
9387
+ this._move( "last", "last", event );
9388
+ break;
9389
+ case $.ui.keyCode.UP:
9390
+ this.previous( event );
9391
+ break;
9392
+ case $.ui.keyCode.DOWN:
9393
+ this.next( event );
9394
+ break;
9395
+ case $.ui.keyCode.LEFT:
9396
+ this.collapse( event );
9397
+ break;
9398
+ case $.ui.keyCode.RIGHT:
9399
+ if ( this.active && !this.active.is( ".ui-state-disabled" ) ) {
9400
+ this.expand( event );
9401
+ }
9402
+ break;
9403
+ case $.ui.keyCode.ENTER:
9404
+ case $.ui.keyCode.SPACE:
9405
+ this._activate( event );
9406
+ break;
9407
+ case $.ui.keyCode.ESCAPE:
9408
+ this.collapse( event );
9409
+ break;
9410
+ default:
9411
+ preventDefault = false;
9412
+ prev = this.previousFilter || "";
9413
+ character = String.fromCharCode( event.keyCode );
9414
+ skip = false;
9415
+
9416
+ clearTimeout( this.filterTimer );
9417
+
9418
+ if ( character === prev ) {
9419
+ skip = true;
9420
+ } else {
9421
+ character = prev + character;
9422
+ }
9423
+
9424
+ regex = new RegExp( "^" + escape( character ), "i" );
9425
+ match = this.activeMenu.children( ".ui-menu-item" ).filter(function() {
9426
+ return regex.test( $( this ).children( "a" ).text() );
9427
+ });
9428
+ match = skip && match.index( this.active.next() ) !== -1 ?
9429
+ this.active.nextAll( ".ui-menu-item" ) :
9430
+ match;
9431
+
9432
+ // If no matches on the current filter, reset to the last character pressed
9433
+ // to move down the menu to the first item that starts with that character
9434
+ if ( !match.length ) {
9435
+ character = String.fromCharCode( event.keyCode );
9436
+ regex = new RegExp( "^" + escape( character ), "i" );
9437
+ match = this.activeMenu.children( ".ui-menu-item" ).filter(function() {
9438
+ return regex.test( $( this ).children( "a" ).text() );
9439
+ });
9440
+ }
9441
+
9442
+ if ( match.length ) {
9443
+ this.focus( event, match );
9444
+ if ( match.length > 1 ) {
9445
+ this.previousFilter = character;
9446
+ this.filterTimer = this._delay(function() {
9447
+ delete this.previousFilter;
9448
+ }, 1000 );
9449
+ } else {
9450
+ delete this.previousFilter;
9451
+ }
9452
+ } else {
9453
+ delete this.previousFilter;
9454
+ }
9455
+ }
9456
+
9457
+ if ( preventDefault ) {
9458
+ event.preventDefault();
9459
+ }
9460
+ },
9461
+
9462
+ _activate: function( event ) {
9463
+ if ( !this.active.is( ".ui-state-disabled" ) ) {
9464
+ if ( this.active.children( "a[aria-haspopup='true']" ).length ) {
9465
+ this.expand( event );
9466
+ } else {
9467
+ this.select( event );
9468
+ }
9469
+ }
9470
+ },
9471
+
9472
+ refresh: function() {
9473
+ // Initialize nested menus
9474
+ var menus,
9475
+ icon = this.options.icons.submenu,
9476
+ submenus = this.element.find( this.options.menus + ":not(.ui-menu)" )
9477
+ .addClass( "ui-menu ui-widget ui-widget-content ui-corner-all" )
9478
+ .hide()
9479
+ .attr({
9480
+ role: this.options.role,
9481
+ "aria-hidden": "true",
9482
+ "aria-expanded": "false"
9483
+ });
9484
+
9485
+ // Don't refresh list items that are already adapted
9486
+ menus = submenus.add( this.element );
9487
+
9488
+ menus.children( ":not(.ui-menu-item):has(a)" )
9489
+ .addClass( "ui-menu-item" )
9490
+ .attr( "role", "presentation" )
9491
+ .children( "a" )
9492
+ .uniqueId()
9493
+ .addClass( "ui-corner-all" )
9494
+ .attr({
9495
+ tabIndex: -1,
9496
+ role: this._itemRole()
9497
+ });
9498
+
9499
+ // Initialize unlinked menu-items containing spaces and/or dashes only as dividers
9500
+ menus.children( ":not(.ui-menu-item)" ).each(function() {
9501
+ var item = $( this );
9502
+ // hyphen, em dash, en dash
9503
+ if ( !/[^\-—–\s]/.test( item.text() ) ) {
9504
+ item.addClass( "ui-widget-content ui-menu-divider" );
9505
+ }
9506
+ });
9507
+
9508
+ // Add aria-disabled attribute to any disabled menu item
9509
+ menus.children( ".ui-state-disabled" ).attr( "aria-disabled", "true" );
9510
+
9511
+ submenus.each(function() {
9512
+ var menu = $( this ),
9513
+ item = menu.prev( "a" ),
9514
+ submenuCarat = $( "<span>" )
9515
+ .addClass( "ui-menu-icon ui-icon " + icon )
9516
+ .data( "ui-menu-submenu-carat", true );
9517
+
9518
+ item
9519
+ .attr( "aria-haspopup", "true" )
9520
+ .prepend( submenuCarat );
9521
+ menu.attr( "aria-labelledby", item.attr( "id" ) );
9522
+ });
9523
+
9524
+ // If the active item has been removed, blur the menu
9525
+ if ( this.active && !$.contains( this.element[ 0 ], this.active[ 0 ] ) ) {
9526
+ this.blur();
9527
+ }
9528
+ },
9529
+
9530
+ _itemRole: function() {
9531
+ return {
9532
+ menu: "menuitem",
9533
+ listbox: "option"
9534
+ }[ this.options.role ];
9535
+ },
9536
+
9537
+ focus: function( event, item ) {
9538
+ var nested, focused;
9539
+ this.blur( event, event && event.type === "focus" );
9540
+
9541
+ this._scrollIntoView( item );
9542
+
9543
+ this.active = item.first();
9544
+ focused = this.active.children( "a" ).addClass( "ui-state-focus" );
9545
+ // Only update aria-activedescendant if there's a role
9546
+ // otherwise we assume focus is managed elsewhere
9547
+ if ( this.options.role ) {
9548
+ this.element.attr( "aria-activedescendant", focused.attr( "id" ) );
9549
+ }
9550
+
9551
+ // Highlight active parent menu item, if any
9552
+ this.active
9553
+ .parent()
9554
+ .closest( ".ui-menu-item" )
9555
+ .children( "a:first" )
9556
+ .addClass( "ui-state-active" );
9557
+
9558
+ if ( event && event.type === "keydown" ) {
9559
+ this._close();
9560
+ } else {
9561
+ this.timer = this._delay(function() {
9562
+ this._close();
9563
+ }, this.delay );
9564
+ }
9565
+
9566
+ nested = item.children( ".ui-menu" );
9567
+ if ( nested.length && ( /^mouse/.test( event.type ) ) ) {
9568
+ this._startOpening(nested);
9569
+ }
9570
+ this.activeMenu = item.parent();
9571
+
9572
+ this._trigger( "focus", event, { item: item } );
9573
+ },
9574
+
9575
+ _scrollIntoView: function( item ) {
9576
+ var borderTop, paddingTop, offset, scroll, elementHeight, itemHeight;
9577
+ if ( this._hasScroll() ) {
9578
+ borderTop = parseFloat( $.css( this.activeMenu[0], "borderTopWidth" ) ) || 0;
9579
+ paddingTop = parseFloat( $.css( this.activeMenu[0], "paddingTop" ) ) || 0;
9580
+ offset = item.offset().top - this.activeMenu.offset().top - borderTop - paddingTop;
9581
+ scroll = this.activeMenu.scrollTop();
9582
+ elementHeight = this.activeMenu.height();
9583
+ itemHeight = item.height();
9584
+
9585
+ if ( offset < 0 ) {
9586
+ this.activeMenu.scrollTop( scroll + offset );
9587
+ } else if ( offset + itemHeight > elementHeight ) {
9588
+ this.activeMenu.scrollTop( scroll + offset - elementHeight + itemHeight );
9589
+ }
9590
+ }
9591
+ },
9592
+
9593
+ blur: function( event, fromFocus ) {
9594
+ if ( !fromFocus ) {
9595
+ clearTimeout( this.timer );
9596
+ }
9597
+
9598
+ if ( !this.active ) {
9599
+ return;
9600
+ }
9601
+
9602
+ this.active.children( "a" ).removeClass( "ui-state-focus" );
9603
+ this.active = null;
9604
+
9605
+ this._trigger( "blur", event, { item: this.active } );
9606
+ },
9607
+
9608
+ _startOpening: function( submenu ) {
9609
+ clearTimeout( this.timer );
9610
+
9611
+ // Don't open if already open fixes a Firefox bug that caused a .5 pixel
9612
+ // shift in the submenu position when mousing over the carat icon
9613
+ if ( submenu.attr( "aria-hidden" ) !== "true" ) {
9614
+ return;
9615
+ }
9616
+
9617
+ this.timer = this._delay(function() {
9618
+ this._close();
9619
+ this._open( submenu );
9620
+ }, this.delay );
9621
+ },
9622
+
9623
+ _open: function( submenu ) {
9624
+ var position = $.extend({
9625
+ of: this.active
9626
+ }, this.options.position );
9627
+
9628
+ clearTimeout( this.timer );
9629
+ this.element.find( ".ui-menu" ).not( submenu.parents( ".ui-menu" ) )
9630
+ .hide()
9631
+ .attr( "aria-hidden", "true" );
9632
+
9633
+ submenu
9634
+ .show()
9635
+ .removeAttr( "aria-hidden" )
9636
+ .attr( "aria-expanded", "true" )
9637
+ .position( position );
9638
+ },
9639
+
9640
+ collapseAll: function( event, all ) {
9641
+ clearTimeout( this.timer );
9642
+ this.timer = this._delay(function() {
9643
+ // If we were passed an event, look for the submenu that contains the event
9644
+ var currentMenu = all ? this.element :
9645
+ $( event && event.target ).closest( this.element.find( ".ui-menu" ) );
9646
+
9647
+ // If we found no valid submenu ancestor, use the main menu to close all sub menus anyway
9648
+ if ( !currentMenu.length ) {
9649
+ currentMenu = this.element;
9650
+ }
9651
+
9652
+ this._close( currentMenu );
9653
+
9654
+ this.blur( event );
9655
+ this.activeMenu = currentMenu;
9656
+ }, this.delay );
9657
+ },
9658
+
9659
+ // With no arguments, closes the currently active menu - if nothing is active
9660
+ // it closes all menus. If passed an argument, it will search for menus BELOW
9661
+ _close: function( startMenu ) {
9662
+ if ( !startMenu ) {
9663
+ startMenu = this.active ? this.active.parent() : this.element;
9664
+ }
9665
+
9666
+ startMenu
9667
+ .find( ".ui-menu" )
9668
+ .hide()
9669
+ .attr( "aria-hidden", "true" )
9670
+ .attr( "aria-expanded", "false" )
9671
+ .end()
9672
+ .find( "a.ui-state-active" )
9673
+ .removeClass( "ui-state-active" );
9674
+ },
9675
+
9676
+ collapse: function( event ) {
9677
+ var newItem = this.active &&
9678
+ this.active.parent().closest( ".ui-menu-item", this.element );
9679
+ if ( newItem && newItem.length ) {
9680
+ this._close();
9681
+ this.focus( event, newItem );
9682
+ }
9683
+ },
9684
+
9685
+ expand: function( event ) {
9686
+ var newItem = this.active &&
9687
+ this.active
9688
+ .children( ".ui-menu " )
9689
+ .children( ".ui-menu-item" )
9690
+ .first();
9691
+
9692
+ if ( newItem && newItem.length ) {
9693
+ this._open( newItem.parent() );
9694
+
9695
+ // Delay so Firefox will not hide activedescendant change in expanding submenu from AT
9696
+ this._delay(function() {
9697
+ this.focus( event, newItem );
9698
+ });
9699
+ }
9700
+ },
9701
+
9702
+ next: function( event ) {
9703
+ this._move( "next", "first", event );
9704
+ },
9705
+
9706
+ previous: function( event ) {
9707
+ this._move( "prev", "last", event );
9708
+ },
9709
+
9710
+ isFirstItem: function() {
9711
+ return this.active && !this.active.prevAll( ".ui-menu-item" ).length;
9712
+ },
9713
+
9714
+ isLastItem: function() {
9715
+ return this.active && !this.active.nextAll( ".ui-menu-item" ).length;
9716
+ },
9717
+
9718
+ _move: function( direction, filter, event ) {
9719
+ var next;
9720
+ if ( this.active ) {
9721
+ if ( direction === "first" || direction === "last" ) {
9722
+ next = this.active
9723
+ [ direction === "first" ? "prevAll" : "nextAll" ]( ".ui-menu-item" )
9724
+ .eq( -1 );
9725
+ } else {
9726
+ next = this.active
9727
+ [ direction + "All" ]( ".ui-menu-item" )
9728
+ .eq( 0 );
9729
+ }
9730
+ }
9731
+ if ( !next || !next.length || !this.active ) {
9732
+ next = this.activeMenu.children( ".ui-menu-item" )[ filter ]();
9733
+ }
9734
+
9735
+ this.focus( event, next );
9736
+ },
9737
+
9738
+ nextPage: function( event ) {
9739
+ var item, base, height;
9740
+
9741
+ if ( !this.active ) {
9742
+ this.next( event );
9743
+ return;
9744
+ }
9745
+ if ( this.isLastItem() ) {
9746
+ return;
9747
+ }
9748
+ if ( this._hasScroll() ) {
9749
+ base = this.active.offset().top;
9750
+ height = this.element.height();
9751
+ this.active.nextAll( ".ui-menu-item" ).each(function() {
9752
+ item = $( this );
9753
+ return item.offset().top - base - height < 0;
9754
+ });
9755
+
9756
+ this.focus( event, item );
9757
+ } else {
9758
+ this.focus( event, this.activeMenu.children( ".ui-menu-item" )
9759
+ [ !this.active ? "first" : "last" ]() );
9760
+ }
9761
+ },
9762
+
9763
+ previousPage: function( event ) {
9764
+ var item, base, height;
9765
+ if ( !this.active ) {
9766
+ this.next( event );
9767
+ return;
9768
+ }
9769
+ if ( this.isFirstItem() ) {
9770
+ return;
9771
+ }
9772
+ if ( this._hasScroll() ) {
9773
+ base = this.active.offset().top;
9774
+ height = this.element.height();
9775
+ this.active.prevAll( ".ui-menu-item" ).each(function() {
9776
+ item = $( this );
9777
+ return item.offset().top - base + height > 0;
9778
+ });
9779
+
9780
+ this.focus( event, item );
9781
+ } else {
9782
+ this.focus( event, this.activeMenu.children( ".ui-menu-item" ).first() );
9783
+ }
9784
+ },
9785
+
9786
+ _hasScroll: function() {
9787
+ return this.element.outerHeight() < this.element.prop( "scrollHeight" );
9788
+ },
9789
+
9790
+ select: function( event ) {
9791
+ // TODO: It should never be possible to not have an active item at this
9792
+ // point, but the tests don't trigger mouseenter before click.
9793
+ this.active = this.active || $( event.target ).closest( ".ui-menu-item" );
9794
+ var ui = { item: this.active };
9795
+ if ( !this.active.has( ".ui-menu" ).length ) {
9796
+ this.collapseAll( event, true );
9797
+ }
9798
+ this._trigger( "select", event, ui );
9799
+ }
9800
+ });
9801
+
9802
+ }( jQuery ));
9803
+ (function( $, undefined ) {
9804
+
9805
+ $.widget( "ui.progressbar", {
9806
+ version: "1.9.1",
9807
+ options: {
9808
+ value: 0,
9809
+ max: 100
9810
+ },
9811
+
9812
+ min: 0,
9813
+
9814
+ _create: function() {
9815
+ this.element
9816
+ .addClass( "ui-progressbar ui-widget ui-widget-content ui-corner-all" )
9817
+ .attr({
9818
+ role: "progressbar",
9819
+ "aria-valuemin": this.min,
9820
+ "aria-valuemax": this.options.max,
9821
+ "aria-valuenow": this._value()
9822
+ });
9823
+
9824
+ this.valueDiv = $( "<div class='ui-progressbar-value ui-widget-header ui-corner-left'></div>" )
9825
+ .appendTo( this.element );
9826
+
9827
+ this.oldValue = this._value();
9828
+ this._refreshValue();
9829
+ },
9830
+
9831
+ _destroy: function() {
9832
+ this.element
9833
+ .removeClass( "ui-progressbar ui-widget ui-widget-content ui-corner-all" )
9834
+ .removeAttr( "role" )
9835
+ .removeAttr( "aria-valuemin" )
9836
+ .removeAttr( "aria-valuemax" )
9837
+ .removeAttr( "aria-valuenow" );
9838
+
9839
+ this.valueDiv.remove();
9840
+ },
9841
+
9842
+ value: function( newValue ) {
9843
+ if ( newValue === undefined ) {
9844
+ return this._value();
9845
+ }
9846
+
9847
+ this._setOption( "value", newValue );
9848
+ return this;
9849
+ },
9850
+
9851
+ _setOption: function( key, value ) {
9852
+ if ( key === "value" ) {
9853
+ this.options.value = value;
9854
+ this._refreshValue();
9855
+ if ( this._value() === this.options.max ) {
9856
+ this._trigger( "complete" );
9857
+ }
9858
+ }
9859
+
9860
+ this._super( key, value );
9861
+ },
9862
+
9863
+ _value: function() {
9864
+ var val = this.options.value;
9865
+ // normalize invalid value
9866
+ if ( typeof val !== "number" ) {
9867
+ val = 0;
9868
+ }
9869
+ return Math.min( this.options.max, Math.max( this.min, val ) );
9870
+ },
9871
+
9872
+ _percentage: function() {
9873
+ return 100 * this._value() / this.options.max;
9874
+ },
9875
+
9876
+ _refreshValue: function() {
9877
+ var value = this.value(),
9878
+ percentage = this._percentage();
9879
+
9880
+ if ( this.oldValue !== value ) {
9881
+ this.oldValue = value;
9882
+ this._trigger( "change" );
9883
+ }
9884
+
9885
+ this.valueDiv
9886
+ .toggle( value > this.min )
9887
+ .toggleClass( "ui-corner-right", value === this.options.max )
9888
+ .width( percentage.toFixed(0) + "%" );
9889
+ this.element.attr( "aria-valuenow", value );
9890
+ }
9891
+ });
9892
+
9893
+ })( jQuery );
9894
+ (function( $, undefined ) {
9895
+
9896
+ $.widget("ui.resizable", $.ui.mouse, {
9897
+ version: "1.9.1",
9898
+ widgetEventPrefix: "resize",
9899
+ options: {
9900
+ alsoResize: false,
9901
+ animate: false,
9902
+ animateDuration: "slow",
9903
+ animateEasing: "swing",
9904
+ aspectRatio: false,
9905
+ autoHide: false,
9906
+ containment: false,
9907
+ ghost: false,
9908
+ grid: false,
9909
+ handles: "e,s,se",
9910
+ helper: false,
9911
+ maxHeight: null,
9912
+ maxWidth: null,
9913
+ minHeight: 10,
9914
+ minWidth: 10,
9915
+ zIndex: 1000
9916
+ },
9917
+ _create: function() {
9918
+
9919
+ var that = this, o = this.options;
9920
+ this.element.addClass("ui-resizable");
9921
+
9922
+ $.extend(this, {
9923
+ _aspectRatio: !!(o.aspectRatio),
9924
+ aspectRatio: o.aspectRatio,
9925
+ originalElement: this.element,
9926
+ _proportionallyResizeElements: [],
9927
+ _helper: o.helper || o.ghost || o.animate ? o.helper || 'ui-resizable-helper' : null
9928
+ });
9929
+
9930
+ //Wrap the element if it cannot hold child nodes
9931
+ if(this.element[0].nodeName.match(/canvas|textarea|input|select|button|img/i)) {
9932
+
9933
+ //Create a wrapper element and set the wrapper to the new current internal element
9934
+ this.element.wrap(
9935
+ $('<div class="ui-wrapper" style="overflow: hidden;"></div>').css({
9936
+ position: this.element.css('position'),
9937
+ width: this.element.outerWidth(),
9938
+ height: this.element.outerHeight(),
9939
+ top: this.element.css('top'),
9940
+ left: this.element.css('left')
9941
+ })
9942
+ );
9943
+
9944
+ //Overwrite the original this.element
9945
+ this.element = this.element.parent().data(
9946
+ "resizable", this.element.data('resizable')
9947
+ );
9948
+
9949
+ this.elementIsWrapper = true;
9950
+
9951
+ //Move margins to the wrapper
9952
+ this.element.css({ marginLeft: this.originalElement.css("marginLeft"), marginTop: this.originalElement.css("marginTop"), marginRight: this.originalElement.css("marginRight"), marginBottom: this.originalElement.css("marginBottom") });
9953
+ this.originalElement.css({ marginLeft: 0, marginTop: 0, marginRight: 0, marginBottom: 0});
9954
+
9955
+ //Prevent Safari textarea resize
9956
+ this.originalResizeStyle = this.originalElement.css('resize');
9957
+ this.originalElement.css('resize', 'none');
9958
+
9959
+ //Push the actual element to our proportionallyResize internal array
9960
+ this._proportionallyResizeElements.push(this.originalElement.css({ position: 'static', zoom: 1, display: 'block' }));
9961
+
9962
+ // avoid IE jump (hard set the margin)
9963
+ this.originalElement.css({ margin: this.originalElement.css('margin') });
9964
+
9965
+ // fix handlers offset
9966
+ this._proportionallyResize();
9967
+
9968
+ }
9969
+
9970
+ 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' });
9971
+ if(this.handles.constructor == String) {
9972
+
9973
+ if(this.handles == 'all') this.handles = 'n,e,s,w,se,sw,ne,nw';
9974
+ var n = this.handles.split(","); this.handles = {};
9975
+
9976
+ for(var i = 0; i < n.length; i++) {
9977
+
9978
+ var handle = $.trim(n[i]), hname = 'ui-resizable-'+handle;
9979
+ var axis = $('<div class="ui-resizable-handle ' + hname + '"></div>');
9980
+
9981
+ // Apply zIndex to all handles - see #7960
9982
+ axis.css({ zIndex: o.zIndex });
9983
+
9984
+ //TODO : What's going on here?
9985
+ if ('se' == handle) {
9986
+ axis.addClass('ui-icon ui-icon-gripsmall-diagonal-se');
9987
+ };
9988
+
9989
+ //Insert into internal handles object and append to element
9990
+ this.handles[handle] = '.ui-resizable-'+handle;
9991
+ this.element.append(axis);
9992
+ }
9993
+
9994
+ }
9995
+
9996
+ this._renderAxis = function(target) {
9997
+
9998
+ target = target || this.element;
9999
+
10000
+ for(var i in this.handles) {
10001
+
10002
+ if(this.handles[i].constructor == String)
10003
+ this.handles[i] = $(this.handles[i], this.element).show();
10004
+
10005
+ //Apply pad to wrapper element, needed to fix axis position (textarea, inputs, scrolls)
10006
+ if (this.elementIsWrapper && this.originalElement[0].nodeName.match(/textarea|input|select|button/i)) {
10007
+
10008
+ var axis = $(this.handles[i], this.element), padWrapper = 0;
10009
+
10010
+ //Checking the correct pad and border
10011
+ padWrapper = /sw|ne|nw|se|n|s/.test(i) ? axis.outerHeight() : axis.outerWidth();
10012
+
10013
+ //The padding type i have to apply...
10014
+ var padPos = [ 'padding',
10015
+ /ne|nw|n/.test(i) ? 'Top' :
10016
+ /se|sw|s/.test(i) ? 'Bottom' :
10017
+ /^e$/.test(i) ? 'Right' : 'Left' ].join("");
10018
+
10019
+ target.css(padPos, padWrapper);
10020
+
10021
+ this._proportionallyResize();
10022
+
10023
+ }
10024
+
10025
+ //TODO: What's that good for? There's not anything to be executed left
10026
+ if(!$(this.handles[i]).length)
10027
+ continue;
10028
+
10029
+ }
10030
+ };
10031
+
10032
+ //TODO: make renderAxis a prototype function
10033
+ this._renderAxis(this.element);
10034
+
10035
+ this._handles = $('.ui-resizable-handle', this.element)
10036
+ .disableSelection();
10037
+
10038
+ //Matching axis name
10039
+ this._handles.mouseover(function() {
10040
+ if (!that.resizing) {
10041
+ if (this.className)
10042
+ var axis = this.className.match(/ui-resizable-(se|sw|ne|nw|n|e|s|w)/i);
10043
+ //Axis, default = se
10044
+ that.axis = axis && axis[1] ? axis[1] : 'se';
10045
+ }
10046
+ });
10047
+
10048
+ //If we want to auto hide the elements
10049
+ if (o.autoHide) {
10050
+ this._handles.hide();
10051
+ $(this.element)
10052
+ .addClass("ui-resizable-autohide")
10053
+ .mouseenter(function() {
10054
+ if (o.disabled) return;
10055
+ $(this).removeClass("ui-resizable-autohide");
10056
+ that._handles.show();
10057
+ })
10058
+ .mouseleave(function(){
10059
+ if (o.disabled) return;
10060
+ if (!that.resizing) {
10061
+ $(this).addClass("ui-resizable-autohide");
10062
+ that._handles.hide();
10063
+ }
10064
+ });
10065
+ }
10066
+
10067
+ //Initialize the mouse interaction
10068
+ this._mouseInit();
10069
+
10070
+ },
10071
+
10072
+ _destroy: function() {
10073
+
10074
+ this._mouseDestroy();
10075
+
10076
+ var _destroy = function(exp) {
10077
+ $(exp).removeClass("ui-resizable ui-resizable-disabled ui-resizable-resizing")
10078
+ .removeData("resizable").removeData("ui-resizable").unbind(".resizable").find('.ui-resizable-handle').remove();
10079
+ };
10080
+
10081
+ //TODO: Unwrap at same DOM position
10082
+ if (this.elementIsWrapper) {
10083
+ _destroy(this.element);
10084
+ var wrapper = this.element;
10085
+ this.originalElement.css({
10086
+ position: wrapper.css('position'),
10087
+ width: wrapper.outerWidth(),
10088
+ height: wrapper.outerHeight(),
10089
+ top: wrapper.css('top'),
10090
+ left: wrapper.css('left')
10091
+ }).insertAfter( wrapper );
10092
+ wrapper.remove();
10093
+ }
10094
+
10095
+ this.originalElement.css('resize', this.originalResizeStyle);
10096
+ _destroy(this.originalElement);
10097
+
10098
+ return this;
10099
+ },
10100
+
10101
+ _mouseCapture: function(event) {
10102
+ var handle = false;
10103
+ for (var i in this.handles) {
10104
+ if ($(this.handles[i])[0] == event.target) {
10105
+ handle = true;
10106
+ }
10107
+ }
10108
+
10109
+ return !this.options.disabled && handle;
10110
+ },
10111
+
10112
+ _mouseStart: function(event) {
10113
+
10114
+ var o = this.options, iniPos = this.element.position(), el = this.element;
10115
+
10116
+ this.resizing = true;
10117
+ this.documentScroll = { top: $(document).scrollTop(), left: $(document).scrollLeft() };
10118
+
10119
+ // bugfix for http://dev.jquery.com/ticket/1749
10120
+ if (el.is('.ui-draggable') || (/absolute/).test(el.css('position'))) {
10121
+ el.css({ position: 'absolute', top: iniPos.top, left: iniPos.left });
10122
+ }
10123
+
10124
+ this._renderProxy();
10125
+
10126
+ var curleft = num(this.helper.css('left')), curtop = num(this.helper.css('top'));
10127
+
10128
+ if (o.containment) {
10129
+ curleft += $(o.containment).scrollLeft() || 0;
10130
+ curtop += $(o.containment).scrollTop() || 0;
10131
+ }
10132
+
10133
+ //Store needed variables
10134
+ this.offset = this.helper.offset();
10135
+ this.position = { left: curleft, top: curtop };
10136
+ this.size = this._helper ? { width: el.outerWidth(), height: el.outerHeight() } : { width: el.width(), height: el.height() };
10137
+ this.originalSize = this._helper ? { width: el.outerWidth(), height: el.outerHeight() } : { width: el.width(), height: el.height() };
10138
+ this.originalPosition = { left: curleft, top: curtop };
10139
+ this.sizeDiff = { width: el.outerWidth() - el.width(), height: el.outerHeight() - el.height() };
10140
+ this.originalMousePosition = { left: event.pageX, top: event.pageY };
10141
+
10142
+ //Aspect Ratio
10143
+ this.aspectRatio = (typeof o.aspectRatio == 'number') ? o.aspectRatio : ((this.originalSize.width / this.originalSize.height) || 1);
10144
+
10145
+ var cursor = $('.ui-resizable-' + this.axis).css('cursor');
10146
+ $('body').css('cursor', cursor == 'auto' ? this.axis + '-resize' : cursor);
10147
+
10148
+ el.addClass("ui-resizable-resizing");
10149
+ this._propagate("start", event);
10150
+ return true;
10151
+ },
10152
+
10153
+ _mouseDrag: function(event) {
10154
+
10155
+ //Increase performance, avoid regex
10156
+ var el = this.helper, o = this.options, props = {},
10157
+ that = this, smp = this.originalMousePosition, a = this.axis;
10158
+
10159
+ var dx = (event.pageX-smp.left)||0, dy = (event.pageY-smp.top)||0;
10160
+ var trigger = this._change[a];
10161
+ if (!trigger) return false;
10162
+
10163
+ // Calculate the attrs that will be change
10164
+ var data = trigger.apply(this, [event, dx, dy]);
10165
+
10166
+ // Put this in the mouseDrag handler since the user can start pressing shift while resizing
10167
+ this._updateVirtualBoundaries(event.shiftKey);
10168
+ if (this._aspectRatio || event.shiftKey)
10169
+ data = this._updateRatio(data, event);
10170
+
10171
+ data = this._respectSize(data, event);
10172
+
10173
+ // plugins callbacks need to be called first
10174
+ this._propagate("resize", event);
10175
+
10176
+ el.css({
10177
+ top: this.position.top + "px", left: this.position.left + "px",
10178
+ width: this.size.width + "px", height: this.size.height + "px"
10179
+ });
10180
+
10181
+ if (!this._helper && this._proportionallyResizeElements.length)
10182
+ this._proportionallyResize();
10183
+
10184
+ this._updateCache(data);
10185
+
10186
+ // calling the user callback at the end
10187
+ this._trigger('resize', event, this.ui());
10188
+
10189
+ return false;
10190
+ },
10191
+
10192
+ _mouseStop: function(event) {
10193
+
10194
+ this.resizing = false;
10195
+ var o = this.options, that = this;
10196
+
10197
+ if(this._helper) {
10198
+ var pr = this._proportionallyResizeElements, ista = pr.length && (/textarea/i).test(pr[0].nodeName),
10199
+ soffseth = ista && $.ui.hasScroll(pr[0], 'left') /* TODO - jump height */ ? 0 : that.sizeDiff.height,
10200
+ soffsetw = ista ? 0 : that.sizeDiff.width;
10201
+
10202
+ var s = { width: (that.helper.width() - soffsetw), height: (that.helper.height() - soffseth) },
10203
+ left = (parseInt(that.element.css('left'), 10) + (that.position.left - that.originalPosition.left)) || null,
10204
+ top = (parseInt(that.element.css('top'), 10) + (that.position.top - that.originalPosition.top)) || null;
10205
+
10206
+ if (!o.animate)
10207
+ this.element.css($.extend(s, { top: top, left: left }));
10208
+
10209
+ that.helper.height(that.size.height);
10210
+ that.helper.width(that.size.width);
10211
+
10212
+ if (this._helper && !o.animate) this._proportionallyResize();
10213
+ }
10214
+
10215
+ $('body').css('cursor', 'auto');
10216
+
10217
+ this.element.removeClass("ui-resizable-resizing");
10218
+
10219
+ this._propagate("stop", event);
10220
+
10221
+ if (this._helper) this.helper.remove();
10222
+ return false;
10223
+
10224
+ },
10225
+
10226
+ _updateVirtualBoundaries: function(forceAspectRatio) {
10227
+ var o = this.options, pMinWidth, pMaxWidth, pMinHeight, pMaxHeight, b;
10228
+
10229
+ b = {
10230
+ minWidth: isNumber(o.minWidth) ? o.minWidth : 0,
10231
+ maxWidth: isNumber(o.maxWidth) ? o.maxWidth : Infinity,
10232
+ minHeight: isNumber(o.minHeight) ? o.minHeight : 0,
10233
+ maxHeight: isNumber(o.maxHeight) ? o.maxHeight : Infinity
10234
+ };
10235
+
10236
+ if(this._aspectRatio || forceAspectRatio) {
10237
+ // We want to create an enclosing box whose aspect ration is the requested one
10238
+ // First, compute the "projected" size for each dimension based on the aspect ratio and other dimension
10239
+ pMinWidth = b.minHeight * this.aspectRatio;
10240
+ pMinHeight = b.minWidth / this.aspectRatio;
10241
+ pMaxWidth = b.maxHeight * this.aspectRatio;
10242
+ pMaxHeight = b.maxWidth / this.aspectRatio;
10243
+
10244
+ if(pMinWidth > b.minWidth) b.minWidth = pMinWidth;
10245
+ if(pMinHeight > b.minHeight) b.minHeight = pMinHeight;
10246
+ if(pMaxWidth < b.maxWidth) b.maxWidth = pMaxWidth;
10247
+ if(pMaxHeight < b.maxHeight) b.maxHeight = pMaxHeight;
10248
+ }
10249
+ this._vBoundaries = b;
10250
+ },
10251
+
10252
+ _updateCache: function(data) {
10253
+ var o = this.options;
10254
+ this.offset = this.helper.offset();
10255
+ if (isNumber(data.left)) this.position.left = data.left;
10256
+ if (isNumber(data.top)) this.position.top = data.top;
10257
+ if (isNumber(data.height)) this.size.height = data.height;
10258
+ if (isNumber(data.width)) this.size.width = data.width;
10259
+ },
10260
+
10261
+ _updateRatio: function(data, event) {
10262
+
10263
+ var o = this.options, cpos = this.position, csize = this.size, a = this.axis;
10264
+
10265
+ if (isNumber(data.height)) data.width = (data.height * this.aspectRatio);
10266
+ else if (isNumber(data.width)) data.height = (data.width / this.aspectRatio);
10267
+
10268
+ if (a == 'sw') {
10269
+ data.left = cpos.left + (csize.width - data.width);
10270
+ data.top = null;
10271
+ }
10272
+ if (a == 'nw') {
10273
+ data.top = cpos.top + (csize.height - data.height);
10274
+ data.left = cpos.left + (csize.width - data.width);
10275
+ }
10276
+
10277
+ return data;
10278
+ },
10279
+
10280
+ _respectSize: function(data, event) {
10281
+
10282
+ var el = this.helper, o = this._vBoundaries, pRatio = this._aspectRatio || event.shiftKey, a = this.axis,
10283
+ ismaxw = isNumber(data.width) && o.maxWidth && (o.maxWidth < data.width), ismaxh = isNumber(data.height) && o.maxHeight && (o.maxHeight < data.height),
10284
+ isminw = isNumber(data.width) && o.minWidth && (o.minWidth > data.width), isminh = isNumber(data.height) && o.minHeight && (o.minHeight > data.height);
10285
+
10286
+ if (isminw) data.width = o.minWidth;
10287
+ if (isminh) data.height = o.minHeight;
10288
+ if (ismaxw) data.width = o.maxWidth;
10289
+ if (ismaxh) data.height = o.maxHeight;
10290
+
10291
+ var dw = this.originalPosition.left + this.originalSize.width, dh = this.position.top + this.size.height;
10292
+ var cw = /sw|nw|w/.test(a), ch = /nw|ne|n/.test(a);
10293
+
10294
+ if (isminw && cw) data.left = dw - o.minWidth;
10295
+ if (ismaxw && cw) data.left = dw - o.maxWidth;
10296
+ if (isminh && ch) data.top = dh - o.minHeight;
10297
+ if (ismaxh && ch) data.top = dh - o.maxHeight;
10298
+
10299
+ // fixing jump error on top/left - bug #2330
10300
+ var isNotwh = !data.width && !data.height;
10301
+ if (isNotwh && !data.left && data.top) data.top = null;
10302
+ else if (isNotwh && !data.top && data.left) data.left = null;
10303
+
10304
+ return data;
10305
+ },
10306
+
10307
+ _proportionallyResize: function() {
10308
+
10309
+ var o = this.options;
10310
+ if (!this._proportionallyResizeElements.length) return;
10311
+ var element = this.helper || this.element;
10312
+
10313
+ for (var i=0; i < this._proportionallyResizeElements.length; i++) {
10314
+
10315
+ var prel = this._proportionallyResizeElements[i];
10316
+
10317
+ if (!this.borderDif) {
10318
+ var b = [prel.css('borderTopWidth'), prel.css('borderRightWidth'), prel.css('borderBottomWidth'), prel.css('borderLeftWidth')],
10319
+ p = [prel.css('paddingTop'), prel.css('paddingRight'), prel.css('paddingBottom'), prel.css('paddingLeft')];
10320
+
10321
+ this.borderDif = $.map(b, function(v, i) {
10322
+ var border = parseInt(v,10)||0, padding = parseInt(p[i],10)||0;
10323
+ return border + padding;
10324
+ });
10325
+ }
10326
+
10327
+ prel.css({
10328
+ height: (element.height() - this.borderDif[0] - this.borderDif[2]) || 0,
10329
+ width: (element.width() - this.borderDif[1] - this.borderDif[3]) || 0
10330
+ });
10331
+
10332
+ };
10333
+
10334
+ },
10335
+
10336
+ _renderProxy: function() {
10337
+
10338
+ var el = this.element, o = this.options;
10339
+ this.elementOffset = el.offset();
10340
+
10341
+ if(this._helper) {
10342
+
10343
+ this.helper = this.helper || $('<div style="overflow:hidden;"></div>');
10344
+
10345
+ // fix ie6 offset TODO: This seems broken
10346
+ var ie6offset = ($.ui.ie6 ? 1 : 0),
10347
+ pxyoffset = ( $.ui.ie6 ? 2 : -1 );
10348
+
10349
+ this.helper.addClass(this._helper).css({
10350
+ width: this.element.outerWidth() + pxyoffset,
10351
+ height: this.element.outerHeight() + pxyoffset,
10352
+ position: 'absolute',
10353
+ left: this.elementOffset.left - ie6offset +'px',
10354
+ top: this.elementOffset.top - ie6offset +'px',
10355
+ zIndex: ++o.zIndex //TODO: Don't modify option
10356
+ });
10357
+
10358
+ this.helper
10359
+ .appendTo("body")
10360
+ .disableSelection();
10361
+
10362
+ } else {
10363
+ this.helper = this.element;
10364
+ }
10365
+
10366
+ },
10367
+
10368
+ _change: {
10369
+ e: function(event, dx, dy) {
10370
+ return { width: this.originalSize.width + dx };
10371
+ },
10372
+ w: function(event, dx, dy) {
10373
+ var o = this.options, cs = this.originalSize, sp = this.originalPosition;
10374
+ return { left: sp.left + dx, width: cs.width - dx };
10375
+ },
10376
+ n: function(event, dx, dy) {
10377
+ var o = this.options, cs = this.originalSize, sp = this.originalPosition;
10378
+ return { top: sp.top + dy, height: cs.height - dy };
10379
+ },
10380
+ s: function(event, dx, dy) {
10381
+ return { height: this.originalSize.height + dy };
10382
+ },
10383
+ se: function(event, dx, dy) {
10384
+ return $.extend(this._change.s.apply(this, arguments), this._change.e.apply(this, [event, dx, dy]));
10385
+ },
10386
+ sw: function(event, dx, dy) {
10387
+ return $.extend(this._change.s.apply(this, arguments), this._change.w.apply(this, [event, dx, dy]));
10388
+ },
10389
+ ne: function(event, dx, dy) {
10390
+ return $.extend(this._change.n.apply(this, arguments), this._change.e.apply(this, [event, dx, dy]));
10391
+ },
10392
+ nw: function(event, dx, dy) {
10393
+ return $.extend(this._change.n.apply(this, arguments), this._change.w.apply(this, [event, dx, dy]));
10394
+ }
10395
+ },
10396
+
10397
+ _propagate: function(n, event) {
10398
+ $.ui.plugin.call(this, n, [event, this.ui()]);
10399
+ (n != "resize" && this._trigger(n, event, this.ui()));
10400
+ },
10401
+
10402
+ plugins: {},
10403
+
10404
+ ui: function() {
10405
+ return {
10406
+ originalElement: this.originalElement,
10407
+ element: this.element,
10408
+ helper: this.helper,
10409
+ position: this.position,
10410
+ size: this.size,
10411
+ originalSize: this.originalSize,
10412
+ originalPosition: this.originalPosition
10413
+ };
10414
+ }
10415
+
10416
+ });
10417
+
10418
+ /*
10419
+ * Resizable Extensions
10420
+ */
10421
+
10422
+ $.ui.plugin.add("resizable", "alsoResize", {
10423
+
10424
+ start: function (event, ui) {
10425
+ var that = $(this).data("resizable"), o = that.options;
10426
+
10427
+ var _store = function (exp) {
10428
+ $(exp).each(function() {
10429
+ var el = $(this);
10430
+ el.data("resizable-alsoresize", {
10431
+ width: parseInt(el.width(), 10), height: parseInt(el.height(), 10),
10432
+ left: parseInt(el.css('left'), 10), top: parseInt(el.css('top'), 10)
10433
+ });
10434
+ });
10435
+ };
10436
+
10437
+ if (typeof(o.alsoResize) == 'object' && !o.alsoResize.parentNode) {
10438
+ if (o.alsoResize.length) { o.alsoResize = o.alsoResize[0]; _store(o.alsoResize); }
10439
+ else { $.each(o.alsoResize, function (exp) { _store(exp); }); }
10440
+ }else{
10441
+ _store(o.alsoResize);
10442
+ }
10443
+ },
10444
+
10445
+ resize: function (event, ui) {
10446
+ var that = $(this).data("resizable"), o = that.options, os = that.originalSize, op = that.originalPosition;
10447
+
10448
+ var delta = {
10449
+ height: (that.size.height - os.height) || 0, width: (that.size.width - os.width) || 0,
10450
+ top: (that.position.top - op.top) || 0, left: (that.position.left - op.left) || 0
10451
+ },
10452
+
10453
+ _alsoResize = function (exp, c) {
10454
+ $(exp).each(function() {
10455
+ var el = $(this), start = $(this).data("resizable-alsoresize"), style = {},
10456
+ css = c && c.length ? c : el.parents(ui.originalElement[0]).length ? ['width', 'height'] : ['width', 'height', 'top', 'left'];
10457
+
10458
+ $.each(css, function (i, prop) {
10459
+ var sum = (start[prop]||0) + (delta[prop]||0);
10460
+ if (sum && sum >= 0)
10461
+ style[prop] = sum || null;
10462
+ });
10463
+
10464
+ el.css(style);
10465
+ });
10466
+ };
10467
+
10468
+ if (typeof(o.alsoResize) == 'object' && !o.alsoResize.nodeType) {
10469
+ $.each(o.alsoResize, function (exp, c) { _alsoResize(exp, c); });
10470
+ }else{
10471
+ _alsoResize(o.alsoResize);
10472
+ }
10473
+ },
10474
+
10475
+ stop: function (event, ui) {
10476
+ $(this).removeData("resizable-alsoresize");
10477
+ }
10478
+ });
10479
+
10480
+ $.ui.plugin.add("resizable", "animate", {
10481
+
10482
+ stop: function(event, ui) {
10483
+ var that = $(this).data("resizable"), o = that.options;
10484
+
10485
+ var pr = that._proportionallyResizeElements, ista = pr.length && (/textarea/i).test(pr[0].nodeName),
10486
+ soffseth = ista && $.ui.hasScroll(pr[0], 'left') /* TODO - jump height */ ? 0 : that.sizeDiff.height,
10487
+ soffsetw = ista ? 0 : that.sizeDiff.width;
10488
+
10489
+ var style = { width: (that.size.width - soffsetw), height: (that.size.height - soffseth) },
10490
+ left = (parseInt(that.element.css('left'), 10) + (that.position.left - that.originalPosition.left)) || null,
10491
+ top = (parseInt(that.element.css('top'), 10) + (that.position.top - that.originalPosition.top)) || null;
10492
+
10493
+ that.element.animate(
10494
+ $.extend(style, top && left ? { top: top, left: left } : {}), {
10495
+ duration: o.animateDuration,
10496
+ easing: o.animateEasing,
10497
+ step: function() {
10498
+
10499
+ var data = {
10500
+ width: parseInt(that.element.css('width'), 10),
10501
+ height: parseInt(that.element.css('height'), 10),
10502
+ top: parseInt(that.element.css('top'), 10),
10503
+ left: parseInt(that.element.css('left'), 10)
10504
+ };
10505
+
10506
+ if (pr && pr.length) $(pr[0]).css({ width: data.width, height: data.height });
10507
+
10508
+ // propagating resize, and updating values for each animation step
10509
+ that._updateCache(data);
10510
+ that._propagate("resize", event);
10511
+
10512
+ }
10513
+ }
10514
+ );
10515
+ }
10516
+
10517
+ });
10518
+
10519
+ $.ui.plugin.add("resizable", "containment", {
10520
+
10521
+ start: function(event, ui) {
10522
+ var that = $(this).data("resizable"), o = that.options, el = that.element;
10523
+ var oc = o.containment, ce = (oc instanceof $) ? oc.get(0) : (/parent/.test(oc)) ? el.parent().get(0) : oc;
10524
+ if (!ce) return;
10525
+
10526
+ that.containerElement = $(ce);
10527
+
10528
+ if (/document/.test(oc) || oc == document) {
10529
+ that.containerOffset = { left: 0, top: 0 };
10530
+ that.containerPosition = { left: 0, top: 0 };
10531
+
10532
+ that.parentData = {
10533
+ element: $(document), left: 0, top: 0,
10534
+ width: $(document).width(), height: $(document).height() || document.body.parentNode.scrollHeight
10535
+ };
10536
+ }
10537
+
10538
+ // i'm a node, so compute top, left, right, bottom
10539
+ else {
10540
+ var element = $(ce), p = [];
10541
+ $([ "Top", "Right", "Left", "Bottom" ]).each(function(i, name) { p[i] = num(element.css("padding" + name)); });
10542
+
10543
+ that.containerOffset = element.offset();
10544
+ that.containerPosition = element.position();
10545
+ that.containerSize = { height: (element.innerHeight() - p[3]), width: (element.innerWidth() - p[1]) };
10546
+
10547
+ var co = that.containerOffset, ch = that.containerSize.height, cw = that.containerSize.width,
10548
+ width = ($.ui.hasScroll(ce, "left") ? ce.scrollWidth : cw ), height = ($.ui.hasScroll(ce) ? ce.scrollHeight : ch);
10549
+
10550
+ that.parentData = {
10551
+ element: ce, left: co.left, top: co.top, width: width, height: height
10552
+ };
10553
+ }
10554
+ },
10555
+
10556
+ resize: function(event, ui) {
10557
+ var that = $(this).data("resizable"), o = that.options,
10558
+ ps = that.containerSize, co = that.containerOffset, cs = that.size, cp = that.position,
10559
+ pRatio = that._aspectRatio || event.shiftKey, cop = { top:0, left:0 }, ce = that.containerElement;
10560
+
10561
+ if (ce[0] != document && (/static/).test(ce.css('position'))) cop = co;
10562
+
10563
+ if (cp.left < (that._helper ? co.left : 0)) {
10564
+ that.size.width = that.size.width + (that._helper ? (that.position.left - co.left) : (that.position.left - cop.left));
10565
+ if (pRatio) that.size.height = that.size.width / that.aspectRatio;
10566
+ that.position.left = o.helper ? co.left : 0;
10567
+ }
10568
+
10569
+ if (cp.top < (that._helper ? co.top : 0)) {
10570
+ that.size.height = that.size.height + (that._helper ? (that.position.top - co.top) : that.position.top);
10571
+ if (pRatio) that.size.width = that.size.height * that.aspectRatio;
10572
+ that.position.top = that._helper ? co.top : 0;
10573
+ }
10574
+
10575
+ that.offset.left = that.parentData.left+that.position.left;
10576
+ that.offset.top = that.parentData.top+that.position.top;
10577
+
10578
+ var woset = Math.abs( (that._helper ? that.offset.left - cop.left : (that.offset.left - cop.left)) + that.sizeDiff.width ),
10579
+ hoset = Math.abs( (that._helper ? that.offset.top - cop.top : (that.offset.top - co.top)) + that.sizeDiff.height );
10580
+
10581
+ var isParent = that.containerElement.get(0) == that.element.parent().get(0),
10582
+ isOffsetRelative = /relative|absolute/.test(that.containerElement.css('position'));
10583
+
10584
+ if(isParent && isOffsetRelative) woset -= that.parentData.left;
10585
+
10586
+ if (woset + that.size.width >= that.parentData.width) {
10587
+ that.size.width = that.parentData.width - woset;
10588
+ if (pRatio) that.size.height = that.size.width / that.aspectRatio;
10589
+ }
10590
+
10591
+ if (hoset + that.size.height >= that.parentData.height) {
10592
+ that.size.height = that.parentData.height - hoset;
10593
+ if (pRatio) that.size.width = that.size.height * that.aspectRatio;
10594
+ }
10595
+ },
10596
+
10597
+ stop: function(event, ui){
10598
+ var that = $(this).data("resizable"), o = that.options, cp = that.position,
10599
+ co = that.containerOffset, cop = that.containerPosition, ce = that.containerElement;
10600
+
10601
+ var helper = $(that.helper), ho = helper.offset(), w = helper.outerWidth() - that.sizeDiff.width, h = helper.outerHeight() - that.sizeDiff.height;
10602
+
10603
+ if (that._helper && !o.animate && (/relative/).test(ce.css('position')))
10604
+ $(this).css({ left: ho.left - cop.left - co.left, width: w, height: h });
10605
+
10606
+ if (that._helper && !o.animate && (/static/).test(ce.css('position')))
10607
+ $(this).css({ left: ho.left - cop.left - co.left, width: w, height: h });
10608
+
10609
+ }
10610
+ });
10611
+
10612
+ $.ui.plugin.add("resizable", "ghost", {
10613
+
10614
+ start: function(event, ui) {
10615
+
10616
+ var that = $(this).data("resizable"), o = that.options, cs = that.size;
10617
+
10618
+ that.ghost = that.originalElement.clone();
10619
+ that.ghost
10620
+ .css({ opacity: .25, display: 'block', position: 'relative', height: cs.height, width: cs.width, margin: 0, left: 0, top: 0 })
10621
+ .addClass('ui-resizable-ghost')
10622
+ .addClass(typeof o.ghost == 'string' ? o.ghost : '');
10623
+
10624
+ that.ghost.appendTo(that.helper);
10625
+
10626
+ },
10627
+
10628
+ resize: function(event, ui){
10629
+ var that = $(this).data("resizable"), o = that.options;
10630
+ if (that.ghost) that.ghost.css({ position: 'relative', height: that.size.height, width: that.size.width });
10631
+ },
10632
+
10633
+ stop: function(event, ui){
10634
+ var that = $(this).data("resizable"), o = that.options;
10635
+ if (that.ghost && that.helper) that.helper.get(0).removeChild(that.ghost.get(0));
10636
+ }
10637
+
10638
+ });
10639
+
10640
+ $.ui.plugin.add("resizable", "grid", {
10641
+
10642
+ resize: function(event, ui) {
10643
+ var that = $(this).data("resizable"), o = that.options, cs = that.size, os = that.originalSize, op = that.originalPosition, a = that.axis, ratio = o._aspectRatio || event.shiftKey;
10644
+ o.grid = typeof o.grid == "number" ? [o.grid, o.grid] : o.grid;
10645
+ var ox = Math.round((cs.width - os.width) / (o.grid[0]||1)) * (o.grid[0]||1), oy = Math.round((cs.height - os.height) / (o.grid[1]||1)) * (o.grid[1]||1);
10646
+
10647
+ if (/^(se|s|e)$/.test(a)) {
10648
+ that.size.width = os.width + ox;
10649
+ that.size.height = os.height + oy;
10650
+ }
10651
+ else if (/^(ne)$/.test(a)) {
10652
+ that.size.width = os.width + ox;
10653
+ that.size.height = os.height + oy;
10654
+ that.position.top = op.top - oy;
10655
+ }
10656
+ else if (/^(sw)$/.test(a)) {
10657
+ that.size.width = os.width + ox;
10658
+ that.size.height = os.height + oy;
10659
+ that.position.left = op.left - ox;
10660
+ }
10661
+ else {
10662
+ that.size.width = os.width + ox;
10663
+ that.size.height = os.height + oy;
10664
+ that.position.top = op.top - oy;
10665
+ that.position.left = op.left - ox;
10666
+ }
10667
+ }
10668
+
10669
+ });
10670
+
10671
+ var num = function(v) {
10672
+ return parseInt(v, 10) || 0;
10673
+ };
10674
+
10675
+ var isNumber = function(value) {
10676
+ return !isNaN(parseInt(value, 10));
10677
+ };
10678
+
10679
+ })(jQuery);
10680
+ (function( $, undefined ) {
10681
+
10682
+ $.widget("ui.selectable", $.ui.mouse, {
10683
+ version: "1.9.1",
10684
+ options: {
10685
+ appendTo: 'body',
10686
+ autoRefresh: true,
10687
+ distance: 0,
10688
+ filter: '*',
10689
+ tolerance: 'touch'
10690
+ },
10691
+ _create: function() {
10692
+ var that = this;
10693
+
10694
+ this.element.addClass("ui-selectable");
10695
+
10696
+ this.dragged = false;
10697
+
10698
+ // cache selectee children based on filter
10699
+ var selectees;
10700
+ this.refresh = function() {
10701
+ selectees = $(that.options.filter, that.element[0]);
10702
+ selectees.addClass("ui-selectee");
10703
+ selectees.each(function() {
10704
+ var $this = $(this);
10705
+ var pos = $this.offset();
10706
+ $.data(this, "selectable-item", {
10707
+ element: this,
10708
+ $element: $this,
10709
+ left: pos.left,
10710
+ top: pos.top,
10711
+ right: pos.left + $this.outerWidth(),
10712
+ bottom: pos.top + $this.outerHeight(),
10713
+ startselected: false,
10714
+ selected: $this.hasClass('ui-selected'),
10715
+ selecting: $this.hasClass('ui-selecting'),
10716
+ unselecting: $this.hasClass('ui-unselecting')
10717
+ });
10718
+ });
10719
+ };
10720
+ this.refresh();
10721
+
10722
+ this.selectees = selectees.addClass("ui-selectee");
10723
+
10724
+ this._mouseInit();
10725
+
10726
+ this.helper = $("<div class='ui-selectable-helper'></div>");
10727
+ },
10728
+
10729
+ _destroy: function() {
10730
+ this.selectees
10731
+ .removeClass("ui-selectee")
10732
+ .removeData("selectable-item");
10733
+ this.element
10734
+ .removeClass("ui-selectable ui-selectable-disabled");
10735
+ this._mouseDestroy();
10736
+ },
10737
+
10738
+ _mouseStart: function(event) {
10739
+ var that = this;
10740
+
10741
+ this.opos = [event.pageX, event.pageY];
10742
+
10743
+ if (this.options.disabled)
10744
+ return;
10745
+
10746
+ var options = this.options;
10747
+
10748
+ this.selectees = $(options.filter, this.element[0]);
10749
+
10750
+ this._trigger("start", event);
10751
+
10752
+ $(options.appendTo).append(this.helper);
10753
+ // position helper (lasso)
10754
+ this.helper.css({
10755
+ "left": event.clientX,
10756
+ "top": event.clientY,
10757
+ "width": 0,
10758
+ "height": 0
10759
+ });
10760
+
10761
+ if (options.autoRefresh) {
10762
+ this.refresh();
10763
+ }
10764
+
10765
+ this.selectees.filter('.ui-selected').each(function() {
10766
+ var selectee = $.data(this, "selectable-item");
10767
+ selectee.startselected = true;
10768
+ if (!event.metaKey && !event.ctrlKey) {
10769
+ selectee.$element.removeClass('ui-selected');
10770
+ selectee.selected = false;
10771
+ selectee.$element.addClass('ui-unselecting');
10772
+ selectee.unselecting = true;
10773
+ // selectable UNSELECTING callback
10774
+ that._trigger("unselecting", event, {
10775
+ unselecting: selectee.element
10776
+ });
10777
+ }
10778
+ });
10779
+
10780
+ $(event.target).parents().andSelf().each(function() {
10781
+ var selectee = $.data(this, "selectable-item");
10782
+ if (selectee) {
10783
+ var doSelect = (!event.metaKey && !event.ctrlKey) || !selectee.$element.hasClass('ui-selected');
10784
+ selectee.$element
10785
+ .removeClass(doSelect ? "ui-unselecting" : "ui-selected")
10786
+ .addClass(doSelect ? "ui-selecting" : "ui-unselecting");
10787
+ selectee.unselecting = !doSelect;
10788
+ selectee.selecting = doSelect;
10789
+ selectee.selected = doSelect;
10790
+ // selectable (UN)SELECTING callback
10791
+ if (doSelect) {
10792
+ that._trigger("selecting", event, {
10793
+ selecting: selectee.element
10794
+ });
10795
+ } else {
10796
+ that._trigger("unselecting", event, {
10797
+ unselecting: selectee.element
10798
+ });
10799
+ }
10800
+ return false;
10801
+ }
10802
+ });
10803
+
10804
+ },
10805
+
10806
+ _mouseDrag: function(event) {
10807
+ var that = this;
10808
+ this.dragged = true;
10809
+
10810
+ if (this.options.disabled)
10811
+ return;
10812
+
10813
+ var options = this.options;
10814
+
10815
+ var x1 = this.opos[0], y1 = this.opos[1], x2 = event.pageX, y2 = event.pageY;
10816
+ if (x1 > x2) { var tmp = x2; x2 = x1; x1 = tmp; }
10817
+ if (y1 > y2) { var tmp = y2; y2 = y1; y1 = tmp; }
10818
+ this.helper.css({left: x1, top: y1, width: x2-x1, height: y2-y1});
10819
+
10820
+ this.selectees.each(function() {
10821
+ var selectee = $.data(this, "selectable-item");
10822
+ //prevent helper from being selected if appendTo: selectable
10823
+ if (!selectee || selectee.element == that.element[0])
10824
+ return;
10825
+ var hit = false;
10826
+ if (options.tolerance == 'touch') {
10827
+ hit = ( !(selectee.left > x2 || selectee.right < x1 || selectee.top > y2 || selectee.bottom < y1) );
10828
+ } else if (options.tolerance == 'fit') {
10829
+ hit = (selectee.left > x1 && selectee.right < x2 && selectee.top > y1 && selectee.bottom < y2);
10830
+ }
10831
+
10832
+ if (hit) {
10833
+ // SELECT
10834
+ if (selectee.selected) {
10835
+ selectee.$element.removeClass('ui-selected');
10836
+ selectee.selected = false;
10837
+ }
10838
+ if (selectee.unselecting) {
10839
+ selectee.$element.removeClass('ui-unselecting');
10840
+ selectee.unselecting = false;
10841
+ }
10842
+ if (!selectee.selecting) {
10843
+ selectee.$element.addClass('ui-selecting');
10844
+ selectee.selecting = true;
10845
+ // selectable SELECTING callback
10846
+ that._trigger("selecting", event, {
10847
+ selecting: selectee.element
10848
+ });
10849
+ }
10850
+ } else {
10851
+ // UNSELECT
10852
+ if (selectee.selecting) {
10853
+ if ((event.metaKey || event.ctrlKey) && selectee.startselected) {
10854
+ selectee.$element.removeClass('ui-selecting');
10855
+ selectee.selecting = false;
10856
+ selectee.$element.addClass('ui-selected');
10857
+ selectee.selected = true;
10858
+ } else {
10859
+ selectee.$element.removeClass('ui-selecting');
10860
+ selectee.selecting = false;
10861
+ if (selectee.startselected) {
10862
+ selectee.$element.addClass('ui-unselecting');
10863
+ selectee.unselecting = true;
10864
+ }
10865
+ // selectable UNSELECTING callback
10866
+ that._trigger("unselecting", event, {
10867
+ unselecting: selectee.element
10868
+ });
10869
+ }
10870
+ }
10871
+ if (selectee.selected) {
10872
+ if (!event.metaKey && !event.ctrlKey && !selectee.startselected) {
10873
+ selectee.$element.removeClass('ui-selected');
10874
+ selectee.selected = false;
10875
+
10876
+ selectee.$element.addClass('ui-unselecting');
10877
+ selectee.unselecting = true;
10878
+ // selectable UNSELECTING callback
10879
+ that._trigger("unselecting", event, {
10880
+ unselecting: selectee.element
10881
+ });
10882
+ }
10883
+ }
10884
+ }
10885
+ });
10886
+
10887
+ return false;
10888
+ },
10889
+
10890
+ _mouseStop: function(event) {
10891
+ var that = this;
10892
+
10893
+ this.dragged = false;
10894
+
10895
+ var options = this.options;
10896
+
10897
+ $('.ui-unselecting', this.element[0]).each(function() {
10898
+ var selectee = $.data(this, "selectable-item");
10899
+ selectee.$element.removeClass('ui-unselecting');
10900
+ selectee.unselecting = false;
10901
+ selectee.startselected = false;
10902
+ that._trigger("unselected", event, {
10903
+ unselected: selectee.element
10904
+ });
10905
+ });
10906
+ $('.ui-selecting', this.element[0]).each(function() {
10907
+ var selectee = $.data(this, "selectable-item");
10908
+ selectee.$element.removeClass('ui-selecting').addClass('ui-selected');
10909
+ selectee.selecting = false;
10910
+ selectee.selected = true;
10911
+ selectee.startselected = true;
10912
+ that._trigger("selected", event, {
10913
+ selected: selectee.element
10914
+ });
10915
+ });
10916
+ this._trigger("stop", event);
10917
+
10918
+ this.helper.remove();
10919
+
10920
+ return false;
10921
+ }
10922
+
10923
+ });
10924
+
10925
+ })(jQuery);
10926
+ (function( $, undefined ) {
10927
+
10928
+ // number of pages in a slider
10929
+ // (how many times can you page up/down to go through the whole range)
10930
+ var numPages = 5;
10931
+
10932
+ $.widget( "ui.slider", $.ui.mouse, {
10933
+ version: "1.9.1",
10934
+ widgetEventPrefix: "slide",
10935
+
10936
+ options: {
10937
+ animate: false,
10938
+ distance: 0,
10939
+ max: 100,
10940
+ min: 0,
10941
+ orientation: "horizontal",
10942
+ range: false,
10943
+ step: 1,
10944
+ value: 0,
10945
+ values: null
10946
+ },
10947
+
10948
+ _create: function() {
10949
+ var i, handleCount,
10950
+ o = this.options,
10951
+ existingHandles = this.element.find( ".ui-slider-handle" ).addClass( "ui-state-default ui-corner-all" ),
10952
+ handle = "<a class='ui-slider-handle ui-state-default ui-corner-all' href='#'></a>",
10953
+ handles = [];
10954
+
10955
+ this._keySliding = false;
10956
+ this._mouseSliding = false;
10957
+ this._animateOff = true;
10958
+ this._handleIndex = null;
10959
+ this._detectOrientation();
10960
+ this._mouseInit();
10961
+
10962
+ this.element
10963
+ .addClass( "ui-slider" +
10964
+ " ui-slider-" + this.orientation +
10965
+ " ui-widget" +
10966
+ " ui-widget-content" +
10967
+ " ui-corner-all" +
10968
+ ( o.disabled ? " ui-slider-disabled ui-disabled" : "" ) );
10969
+
10970
+ this.range = $([]);
10971
+
10972
+ if ( o.range ) {
10973
+ if ( o.range === true ) {
10974
+ if ( !o.values ) {
10975
+ o.values = [ this._valueMin(), this._valueMin() ];
10976
+ }
10977
+ if ( o.values.length && o.values.length !== 2 ) {
10978
+ o.values = [ o.values[0], o.values[0] ];
10979
+ }
10980
+ }
10981
+
10982
+ this.range = $( "<div></div>" )
10983
+ .appendTo( this.element )
10984
+ .addClass( "ui-slider-range" +
10985
+ // note: this isn't the most fittingly semantic framework class for this element,
10986
+ // but worked best visually with a variety of themes
10987
+ " ui-widget-header" +
10988
+ ( ( o.range === "min" || o.range === "max" ) ? " ui-slider-range-" + o.range : "" ) );
10989
+ }
10990
+
10991
+ handleCount = ( o.values && o.values.length ) || 1;
10992
+
10993
+ for ( i = existingHandles.length; i < handleCount; i++ ) {
10994
+ handles.push( handle );
10995
+ }
10996
+
10997
+ this.handles = existingHandles.add( $( handles.join( "" ) ).appendTo( this.element ) );
10998
+
10999
+ this.handle = this.handles.eq( 0 );
11000
+
11001
+ this.handles.add( this.range ).filter( "a" )
11002
+ .click(function( event ) {
11003
+ event.preventDefault();
11004
+ })
11005
+ .mouseenter(function() {
11006
+ if ( !o.disabled ) {
11007
+ $( this ).addClass( "ui-state-hover" );
11008
+ }
11009
+ })
11010
+ .mouseleave(function() {
11011
+ $( this ).removeClass( "ui-state-hover" );
11012
+ })
11013
+ .focus(function() {
11014
+ if ( !o.disabled ) {
11015
+ $( ".ui-slider .ui-state-focus" ).removeClass( "ui-state-focus" );
11016
+ $( this ).addClass( "ui-state-focus" );
11017
+ } else {
11018
+ $( this ).blur();
11019
+ }
11020
+ })
11021
+ .blur(function() {
11022
+ $( this ).removeClass( "ui-state-focus" );
11023
+ });
11024
+
11025
+ this.handles.each(function( i ) {
11026
+ $( this ).data( "ui-slider-handle-index", i );
11027
+ });
11028
+
11029
+ this._on( this.handles, {
11030
+ keydown: function( event ) {
11031
+ var allowed, curVal, newVal, step,
11032
+ index = $( event.target ).data( "ui-slider-handle-index" );
11033
+
11034
+ switch ( event.keyCode ) {
11035
+ case $.ui.keyCode.HOME:
11036
+ case $.ui.keyCode.END:
11037
+ case $.ui.keyCode.PAGE_UP:
11038
+ case $.ui.keyCode.PAGE_DOWN:
11039
+ case $.ui.keyCode.UP:
11040
+ case $.ui.keyCode.RIGHT:
11041
+ case $.ui.keyCode.DOWN:
11042
+ case $.ui.keyCode.LEFT:
11043
+ event.preventDefault();
11044
+ if ( !this._keySliding ) {
11045
+ this._keySliding = true;
11046
+ $( event.target ).addClass( "ui-state-active" );
11047
+ allowed = this._start( event, index );
11048
+ if ( allowed === false ) {
11049
+ return;
11050
+ }
11051
+ }
11052
+ break;
11053
+ }
11054
+
11055
+ step = this.options.step;
11056
+ if ( this.options.values && this.options.values.length ) {
11057
+ curVal = newVal = this.values( index );
11058
+ } else {
11059
+ curVal = newVal = this.value();
11060
+ }
11061
+
11062
+ switch ( event.keyCode ) {
11063
+ case $.ui.keyCode.HOME:
11064
+ newVal = this._valueMin();
11065
+ break;
11066
+ case $.ui.keyCode.END:
11067
+ newVal = this._valueMax();
11068
+ break;
11069
+ case $.ui.keyCode.PAGE_UP:
11070
+ newVal = this._trimAlignValue( curVal + ( (this._valueMax() - this._valueMin()) / numPages ) );
11071
+ break;
11072
+ case $.ui.keyCode.PAGE_DOWN:
11073
+ newVal = this._trimAlignValue( curVal - ( (this._valueMax() - this._valueMin()) / numPages ) );
11074
+ break;
11075
+ case $.ui.keyCode.UP:
11076
+ case $.ui.keyCode.RIGHT:
11077
+ if ( curVal === this._valueMax() ) {
11078
+ return;
11079
+ }
11080
+ newVal = this._trimAlignValue( curVal + step );
11081
+ break;
11082
+ case $.ui.keyCode.DOWN:
11083
+ case $.ui.keyCode.LEFT:
11084
+ if ( curVal === this._valueMin() ) {
11085
+ return;
11086
+ }
11087
+ newVal = this._trimAlignValue( curVal - step );
11088
+ break;
11089
+ }
11090
+
11091
+ this._slide( event, index, newVal );
11092
+ },
11093
+ keyup: function( event ) {
11094
+ var index = $( event.target ).data( "ui-slider-handle-index" );
11095
+
11096
+ if ( this._keySliding ) {
11097
+ this._keySliding = false;
11098
+ this._stop( event, index );
11099
+ this._change( event, index );
11100
+ $( event.target ).removeClass( "ui-state-active" );
11101
+ }
11102
+ }
11103
+ });
11104
+
11105
+ this._refreshValue();
11106
+
11107
+ this._animateOff = false;
11108
+ },
11109
+
11110
+ _destroy: function() {
11111
+ this.handles.remove();
11112
+ this.range.remove();
11113
+
11114
+ this.element
11115
+ .removeClass( "ui-slider" +
11116
+ " ui-slider-horizontal" +
11117
+ " ui-slider-vertical" +
11118
+ " ui-slider-disabled" +
11119
+ " ui-widget" +
11120
+ " ui-widget-content" +
11121
+ " ui-corner-all" );
11122
+
11123
+ this._mouseDestroy();
11124
+ },
11125
+
11126
+ _mouseCapture: function( event ) {
11127
+ var position, normValue, distance, closestHandle, index, allowed, offset, mouseOverHandle,
11128
+ that = this,
11129
+ o = this.options;
11130
+
11131
+ if ( o.disabled ) {
11132
+ return false;
11133
+ }
11134
+
11135
+ this.elementSize = {
11136
+ width: this.element.outerWidth(),
11137
+ height: this.element.outerHeight()
11138
+ };
11139
+ this.elementOffset = this.element.offset();
11140
+
11141
+ position = { x: event.pageX, y: event.pageY };
11142
+ normValue = this._normValueFromMouse( position );
11143
+ distance = this._valueMax() - this._valueMin() + 1;
11144
+ this.handles.each(function( i ) {
11145
+ var thisDistance = Math.abs( normValue - that.values(i) );
11146
+ if ( distance > thisDistance ) {
11147
+ distance = thisDistance;
11148
+ closestHandle = $( this );
11149
+ index = i;
11150
+ }
11151
+ });
11152
+
11153
+ // workaround for bug #3736 (if both handles of a range are at 0,
11154
+ // the first is always used as the one with least distance,
11155
+ // and moving it is obviously prevented by preventing negative ranges)
11156
+ if( o.range === true && this.values(1) === o.min ) {
11157
+ index += 1;
11158
+ closestHandle = $( this.handles[index] );
11159
+ }
11160
+
11161
+ allowed = this._start( event, index );
11162
+ if ( allowed === false ) {
11163
+ return false;
11164
+ }
11165
+ this._mouseSliding = true;
11166
+
11167
+ this._handleIndex = index;
11168
+
11169
+ closestHandle
11170
+ .addClass( "ui-state-active" )
11171
+ .focus();
11172
+
11173
+ offset = closestHandle.offset();
11174
+ mouseOverHandle = !$( event.target ).parents().andSelf().is( ".ui-slider-handle" );
11175
+ this._clickOffset = mouseOverHandle ? { left: 0, top: 0 } : {
11176
+ left: event.pageX - offset.left - ( closestHandle.width() / 2 ),
11177
+ top: event.pageY - offset.top -
11178
+ ( closestHandle.height() / 2 ) -
11179
+ ( parseInt( closestHandle.css("borderTopWidth"), 10 ) || 0 ) -
11180
+ ( parseInt( closestHandle.css("borderBottomWidth"), 10 ) || 0) +
11181
+ ( parseInt( closestHandle.css("marginTop"), 10 ) || 0)
11182
+ };
11183
+
11184
+ if ( !this.handles.hasClass( "ui-state-hover" ) ) {
11185
+ this._slide( event, index, normValue );
11186
+ }
11187
+ this._animateOff = true;
11188
+ return true;
11189
+ },
11190
+
11191
+ _mouseStart: function() {
11192
+ return true;
11193
+ },
11194
+
11195
+ _mouseDrag: function( event ) {
11196
+ var position = { x: event.pageX, y: event.pageY },
11197
+ normValue = this._normValueFromMouse( position );
11198
+
11199
+ this._slide( event, this._handleIndex, normValue );
11200
+
11201
+ return false;
11202
+ },
11203
+
11204
+ _mouseStop: function( event ) {
11205
+ this.handles.removeClass( "ui-state-active" );
11206
+ this._mouseSliding = false;
11207
+
11208
+ this._stop( event, this._handleIndex );
11209
+ this._change( event, this._handleIndex );
11210
+
11211
+ this._handleIndex = null;
11212
+ this._clickOffset = null;
11213
+ this._animateOff = false;
11214
+
11215
+ return false;
11216
+ },
11217
+
11218
+ _detectOrientation: function() {
11219
+ this.orientation = ( this.options.orientation === "vertical" ) ? "vertical" : "horizontal";
11220
+ },
11221
+
11222
+ _normValueFromMouse: function( position ) {
11223
+ var pixelTotal,
11224
+ pixelMouse,
11225
+ percentMouse,
11226
+ valueTotal,
11227
+ valueMouse;
11228
+
11229
+ if ( this.orientation === "horizontal" ) {
11230
+ pixelTotal = this.elementSize.width;
11231
+ pixelMouse = position.x - this.elementOffset.left - ( this._clickOffset ? this._clickOffset.left : 0 );
11232
+ } else {
11233
+ pixelTotal = this.elementSize.height;
11234
+ pixelMouse = position.y - this.elementOffset.top - ( this._clickOffset ? this._clickOffset.top : 0 );
11235
+ }
11236
+
11237
+ percentMouse = ( pixelMouse / pixelTotal );
11238
+ if ( percentMouse > 1 ) {
11239
+ percentMouse = 1;
11240
+ }
11241
+ if ( percentMouse < 0 ) {
11242
+ percentMouse = 0;
11243
+ }
11244
+ if ( this.orientation === "vertical" ) {
11245
+ percentMouse = 1 - percentMouse;
11246
+ }
11247
+
11248
+ valueTotal = this._valueMax() - this._valueMin();
11249
+ valueMouse = this._valueMin() + percentMouse * valueTotal;
11250
+
11251
+ return this._trimAlignValue( valueMouse );
11252
+ },
11253
+
11254
+ _start: function( event, index ) {
11255
+ var uiHash = {
11256
+ handle: this.handles[ index ],
11257
+ value: this.value()
11258
+ };
11259
+ if ( this.options.values && this.options.values.length ) {
11260
+ uiHash.value = this.values( index );
11261
+ uiHash.values = this.values();
11262
+ }
11263
+ return this._trigger( "start", event, uiHash );
11264
+ },
11265
+
11266
+ _slide: function( event, index, newVal ) {
11267
+ var otherVal,
11268
+ newValues,
11269
+ allowed;
11270
+
11271
+ if ( this.options.values && this.options.values.length ) {
11272
+ otherVal = this.values( index ? 0 : 1 );
11273
+
11274
+ if ( ( this.options.values.length === 2 && this.options.range === true ) &&
11275
+ ( ( index === 0 && newVal > otherVal) || ( index === 1 && newVal < otherVal ) )
11276
+ ) {
11277
+ newVal = otherVal;
11278
+ }
11279
+
11280
+ if ( newVal !== this.values( index ) ) {
11281
+ newValues = this.values();
11282
+ newValues[ index ] = newVal;
11283
+ // A slide can be canceled by returning false from the slide callback
11284
+ allowed = this._trigger( "slide", event, {
11285
+ handle: this.handles[ index ],
11286
+ value: newVal,
11287
+ values: newValues
11288
+ } );
11289
+ otherVal = this.values( index ? 0 : 1 );
11290
+ if ( allowed !== false ) {
11291
+ this.values( index, newVal, true );
11292
+ }
11293
+ }
11294
+ } else {
11295
+ if ( newVal !== this.value() ) {
11296
+ // A slide can be canceled by returning false from the slide callback
11297
+ allowed = this._trigger( "slide", event, {
11298
+ handle: this.handles[ index ],
11299
+ value: newVal
11300
+ } );
11301
+ if ( allowed !== false ) {
11302
+ this.value( newVal );
11303
+ }
11304
+ }
11305
+ }
11306
+ },
11307
+
11308
+ _stop: function( event, index ) {
11309
+ var uiHash = {
11310
+ handle: this.handles[ index ],
11311
+ value: this.value()
11312
+ };
11313
+ if ( this.options.values && this.options.values.length ) {
11314
+ uiHash.value = this.values( index );
11315
+ uiHash.values = this.values();
11316
+ }
11317
+
11318
+ this._trigger( "stop", event, uiHash );
11319
+ },
11320
+
11321
+ _change: function( event, index ) {
11322
+ if ( !this._keySliding && !this._mouseSliding ) {
11323
+ var uiHash = {
11324
+ handle: this.handles[ index ],
11325
+ value: this.value()
11326
+ };
11327
+ if ( this.options.values && this.options.values.length ) {
11328
+ uiHash.value = this.values( index );
11329
+ uiHash.values = this.values();
11330
+ }
11331
+
11332
+ this._trigger( "change", event, uiHash );
11333
+ }
11334
+ },
11335
+
11336
+ value: function( newValue ) {
11337
+ if ( arguments.length ) {
11338
+ this.options.value = this._trimAlignValue( newValue );
11339
+ this._refreshValue();
11340
+ this._change( null, 0 );
11341
+ return;
11342
+ }
11343
+
11344
+ return this._value();
11345
+ },
11346
+
11347
+ values: function( index, newValue ) {
11348
+ var vals,
11349
+ newValues,
11350
+ i;
11351
+
11352
+ if ( arguments.length > 1 ) {
11353
+ this.options.values[ index ] = this._trimAlignValue( newValue );
11354
+ this._refreshValue();
11355
+ this._change( null, index );
11356
+ return;
11357
+ }
11358
+
11359
+ if ( arguments.length ) {
11360
+ if ( $.isArray( arguments[ 0 ] ) ) {
11361
+ vals = this.options.values;
11362
+ newValues = arguments[ 0 ];
11363
+ for ( i = 0; i < vals.length; i += 1 ) {
11364
+ vals[ i ] = this._trimAlignValue( newValues[ i ] );
11365
+ this._change( null, i );
11366
+ }
11367
+ this._refreshValue();
11368
+ } else {
11369
+ if ( this.options.values && this.options.values.length ) {
11370
+ return this._values( index );
11371
+ } else {
11372
+ return this.value();
11373
+ }
11374
+ }
11375
+ } else {
11376
+ return this._values();
11377
+ }
11378
+ },
11379
+
11380
+ _setOption: function( key, value ) {
11381
+ var i,
11382
+ valsLength = 0;
11383
+
11384
+ if ( $.isArray( this.options.values ) ) {
11385
+ valsLength = this.options.values.length;
11386
+ }
11387
+
11388
+ $.Widget.prototype._setOption.apply( this, arguments );
11389
+
11390
+ switch ( key ) {
11391
+ case "disabled":
11392
+ if ( value ) {
11393
+ this.handles.filter( ".ui-state-focus" ).blur();
11394
+ this.handles.removeClass( "ui-state-hover" );
11395
+ this.handles.prop( "disabled", true );
11396
+ this.element.addClass( "ui-disabled" );
11397
+ } else {
11398
+ this.handles.prop( "disabled", false );
11399
+ this.element.removeClass( "ui-disabled" );
11400
+ }
11401
+ break;
11402
+ case "orientation":
11403
+ this._detectOrientation();
11404
+ this.element
11405
+ .removeClass( "ui-slider-horizontal ui-slider-vertical" )
11406
+ .addClass( "ui-slider-" + this.orientation );
11407
+ this._refreshValue();
11408
+ break;
11409
+ case "value":
11410
+ this._animateOff = true;
11411
+ this._refreshValue();
11412
+ this._change( null, 0 );
11413
+ this._animateOff = false;
11414
+ break;
11415
+ case "values":
11416
+ this._animateOff = true;
11417
+ this._refreshValue();
11418
+ for ( i = 0; i < valsLength; i += 1 ) {
11419
+ this._change( null, i );
11420
+ }
11421
+ this._animateOff = false;
11422
+ break;
11423
+ case "min":
11424
+ case "max":
11425
+ this._animateOff = true;
11426
+ this._refreshValue();
11427
+ this._animateOff = false;
11428
+ break;
11429
+ }
11430
+ },
11431
+
11432
+ //internal value getter
11433
+ // _value() returns value trimmed by min and max, aligned by step
11434
+ _value: function() {
11435
+ var val = this.options.value;
11436
+ val = this._trimAlignValue( val );
11437
+
11438
+ return val;
11439
+ },
11440
+
11441
+ //internal values getter
11442
+ // _values() returns array of values trimmed by min and max, aligned by step
11443
+ // _values( index ) returns single value trimmed by min and max, aligned by step
11444
+ _values: function( index ) {
11445
+ var val,
11446
+ vals,
11447
+ i;
11448
+
11449
+ if ( arguments.length ) {
11450
+ val = this.options.values[ index ];
11451
+ val = this._trimAlignValue( val );
11452
+
11453
+ return val;
11454
+ } else {
11455
+ // .slice() creates a copy of the array
11456
+ // this copy gets trimmed by min and max and then returned
11457
+ vals = this.options.values.slice();
11458
+ for ( i = 0; i < vals.length; i+= 1) {
11459
+ vals[ i ] = this._trimAlignValue( vals[ i ] );
11460
+ }
11461
+
11462
+ return vals;
11463
+ }
11464
+ },
11465
+
11466
+ // returns the step-aligned value that val is closest to, between (inclusive) min and max
11467
+ _trimAlignValue: function( val ) {
11468
+ if ( val <= this._valueMin() ) {
11469
+ return this._valueMin();
11470
+ }
11471
+ if ( val >= this._valueMax() ) {
11472
+ return this._valueMax();
11473
+ }
11474
+ var step = ( this.options.step > 0 ) ? this.options.step : 1,
11475
+ valModStep = (val - this._valueMin()) % step,
11476
+ alignValue = val - valModStep;
11477
+
11478
+ if ( Math.abs(valModStep) * 2 >= step ) {
11479
+ alignValue += ( valModStep > 0 ) ? step : ( -step );
11480
+ }
11481
+
11482
+ // Since JavaScript has problems with large floats, round
11483
+ // the final value to 5 digits after the decimal point (see #4124)
11484
+ return parseFloat( alignValue.toFixed(5) );
11485
+ },
11486
+
11487
+ _valueMin: function() {
11488
+ return this.options.min;
11489
+ },
11490
+
11491
+ _valueMax: function() {
11492
+ return this.options.max;
11493
+ },
11494
+
11495
+ _refreshValue: function() {
11496
+ var lastValPercent, valPercent, value, valueMin, valueMax,
11497
+ oRange = this.options.range,
11498
+ o = this.options,
11499
+ that = this,
11500
+ animate = ( !this._animateOff ) ? o.animate : false,
11501
+ _set = {};
11502
+
11503
+ if ( this.options.values && this.options.values.length ) {
11504
+ this.handles.each(function( i ) {
11505
+ valPercent = ( that.values(i) - that._valueMin() ) / ( that._valueMax() - that._valueMin() ) * 100;
11506
+ _set[ that.orientation === "horizontal" ? "left" : "bottom" ] = valPercent + "%";
11507
+ $( this ).stop( 1, 1 )[ animate ? "animate" : "css" ]( _set, o.animate );
11508
+ if ( that.options.range === true ) {
11509
+ if ( that.orientation === "horizontal" ) {
11510
+ if ( i === 0 ) {
11511
+ that.range.stop( 1, 1 )[ animate ? "animate" : "css" ]( { left: valPercent + "%" }, o.animate );
11512
+ }
11513
+ if ( i === 1 ) {
11514
+ that.range[ animate ? "animate" : "css" ]( { width: ( valPercent - lastValPercent ) + "%" }, { queue: false, duration: o.animate } );
11515
+ }
11516
+ } else {
11517
+ if ( i === 0 ) {
11518
+ that.range.stop( 1, 1 )[ animate ? "animate" : "css" ]( { bottom: ( valPercent ) + "%" }, o.animate );
11519
+ }
11520
+ if ( i === 1 ) {
11521
+ that.range[ animate ? "animate" : "css" ]( { height: ( valPercent - lastValPercent ) + "%" }, { queue: false, duration: o.animate } );
11522
+ }
11523
+ }
11524
+ }
11525
+ lastValPercent = valPercent;
11526
+ });
11527
+ } else {
11528
+ value = this.value();
11529
+ valueMin = this._valueMin();
11530
+ valueMax = this._valueMax();
11531
+ valPercent = ( valueMax !== valueMin ) ?
11532
+ ( value - valueMin ) / ( valueMax - valueMin ) * 100 :
11533
+ 0;
11534
+ _set[ this.orientation === "horizontal" ? "left" : "bottom" ] = valPercent + "%";
11535
+ this.handle.stop( 1, 1 )[ animate ? "animate" : "css" ]( _set, o.animate );
11536
+
11537
+ if ( oRange === "min" && this.orientation === "horizontal" ) {
11538
+ this.range.stop( 1, 1 )[ animate ? "animate" : "css" ]( { width: valPercent + "%" }, o.animate );
11539
+ }
11540
+ if ( oRange === "max" && this.orientation === "horizontal" ) {
11541
+ this.range[ animate ? "animate" : "css" ]( { width: ( 100 - valPercent ) + "%" }, { queue: false, duration: o.animate } );
11542
+ }
11543
+ if ( oRange === "min" && this.orientation === "vertical" ) {
11544
+ this.range.stop( 1, 1 )[ animate ? "animate" : "css" ]( { height: valPercent + "%" }, o.animate );
11545
+ }
11546
+ if ( oRange === "max" && this.orientation === "vertical" ) {
11547
+ this.range[ animate ? "animate" : "css" ]( { height: ( 100 - valPercent ) + "%" }, { queue: false, duration: o.animate } );
11548
+ }
11549
+ }
11550
+ }
11551
+
11552
+ });
11553
+
11554
+ }(jQuery));
11555
+ (function( $, undefined ) {
11556
+
11557
+ $.widget("ui.sortable", $.ui.mouse, {
11558
+ version: "1.9.1",
11559
+ widgetEventPrefix: "sort",
11560
+ ready: false,
11561
+ options: {
11562
+ appendTo: "parent",
11563
+ axis: false,
11564
+ connectWith: false,
11565
+ containment: false,
11566
+ cursor: 'auto',
11567
+ cursorAt: false,
11568
+ dropOnEmpty: true,
11569
+ forcePlaceholderSize: false,
11570
+ forceHelperSize: false,
11571
+ grid: false,
11572
+ handle: false,
11573
+ helper: "original",
11574
+ items: '> *',
11575
+ opacity: false,
11576
+ placeholder: false,
11577
+ revert: false,
11578
+ scroll: true,
11579
+ scrollSensitivity: 20,
11580
+ scrollSpeed: 20,
11581
+ scope: "default",
11582
+ tolerance: "intersect",
11583
+ zIndex: 1000
11584
+ },
11585
+ _create: function() {
11586
+
11587
+ var o = this.options;
11588
+ this.containerCache = {};
11589
+ this.element.addClass("ui-sortable");
11590
+
11591
+ //Get the items
11592
+ this.refresh();
11593
+
11594
+ //Let's determine if the items are being displayed horizontally
11595
+ this.floating = this.items.length ? o.axis === 'x' || (/left|right/).test(this.items[0].item.css('float')) || (/inline|table-cell/).test(this.items[0].item.css('display')) : false;
11596
+
11597
+ //Let's determine the parent's offset
11598
+ this.offset = this.element.offset();
11599
+
11600
+ //Initialize mouse events for interaction
11601
+ this._mouseInit();
11602
+
11603
+ //We're ready to go
11604
+ this.ready = true
11605
+
11606
+ },
11607
+
11608
+ _destroy: function() {
11609
+ this.element
11610
+ .removeClass("ui-sortable ui-sortable-disabled");
11611
+ this._mouseDestroy();
11612
+
11613
+ for ( var i = this.items.length - 1; i >= 0; i-- )
11614
+ this.items[i].item.removeData(this.widgetName + "-item");
11615
+
11616
+ return this;
11617
+ },
11618
+
11619
+ _setOption: function(key, value){
11620
+ if ( key === "disabled" ) {
11621
+ this.options[ key ] = value;
11622
+
11623
+ this.widget().toggleClass( "ui-sortable-disabled", !!value );
11624
+ } else {
11625
+ // Don't call widget base _setOption for disable as it adds ui-state-disabled class
11626
+ $.Widget.prototype._setOption.apply(this, arguments);
11627
+ }
11628
+ },
11629
+
11630
+ _mouseCapture: function(event, overrideHandle) {
11631
+ var that = this;
11632
+
11633
+ if (this.reverting) {
11634
+ return false;
11635
+ }
11636
+
11637
+ if(this.options.disabled || this.options.type == 'static') return false;
11638
+
11639
+ //We have to refresh the items data once first
11640
+ this._refreshItems(event);
11641
+
11642
+ //Find out if the clicked node (or one of its parents) is a actual item in this.items
11643
+ var currentItem = null, nodes = $(event.target).parents().each(function() {
11644
+ if($.data(this, that.widgetName + '-item') == that) {
11645
+ currentItem = $(this);
11646
+ return false;
11647
+ }
11648
+ });
11649
+ if($.data(event.target, that.widgetName + '-item') == that) currentItem = $(event.target);
11650
+
11651
+ if(!currentItem) return false;
11652
+ if(this.options.handle && !overrideHandle) {
11653
+ var validHandle = false;
11654
+
11655
+ $(this.options.handle, currentItem).find("*").andSelf().each(function() { if(this == event.target) validHandle = true; });
11656
+ if(!validHandle) return false;
11657
+ }
11658
+
11659
+ this.currentItem = currentItem;
11660
+ this._removeCurrentsFromItems();
11661
+ return true;
11662
+
11663
+ },
11664
+
11665
+ _mouseStart: function(event, overrideHandle, noActivation) {
11666
+
11667
+ var o = this.options;
11668
+ this.currentContainer = this;
11669
+
11670
+ //We only need to call refreshPositions, because the refreshItems call has been moved to mouseCapture
11671
+ this.refreshPositions();
11672
+
11673
+ //Create and append the visible helper
11674
+ this.helper = this._createHelper(event);
11675
+
11676
+ //Cache the helper size
11677
+ this._cacheHelperProportions();
11678
+
11679
+ /*
11680
+ * - Position generation -
11681
+ * This block generates everything position related - it's the core of draggables.
11682
+ */
11683
+
11684
+ //Cache the margins of the original element
11685
+ this._cacheMargins();
11686
+
11687
+ //Get the next scrolling parent
11688
+ this.scrollParent = this.helper.scrollParent();
11689
+
11690
+ //The element's absolute position on the page minus margins
11691
+ this.offset = this.currentItem.offset();
11692
+ this.offset = {
11693
+ top: this.offset.top - this.margins.top,
11694
+ left: this.offset.left - this.margins.left
11695
+ };
11696
+
11697
+ $.extend(this.offset, {
11698
+ click: { //Where the click happened, relative to the element
11699
+ left: event.pageX - this.offset.left,
11700
+ top: event.pageY - this.offset.top
11701
+ },
11702
+ parent: this._getParentOffset(),
11703
+ relative: this._getRelativeOffset() //This is a relative to absolute position minus the actual position calculation - only used for relative positioned helper
11704
+ });
11705
+
11706
+ // Only after we got the offset, we can change the helper's position to absolute
11707
+ // TODO: Still need to figure out a way to make relative sorting possible
11708
+ this.helper.css("position", "absolute");
11709
+ this.cssPosition = this.helper.css("position");
11710
+
11711
+ //Generate the original position
11712
+ this.originalPosition = this._generatePosition(event);
11713
+ this.originalPageX = event.pageX;
11714
+ this.originalPageY = event.pageY;
11715
+
11716
+ //Adjust the mouse offset relative to the helper if 'cursorAt' is supplied
11717
+ (o.cursorAt && this._adjustOffsetFromHelper(o.cursorAt));
11718
+
11719
+ //Cache the former DOM position
11720
+ this.domPosition = { prev: this.currentItem.prev()[0], parent: this.currentItem.parent()[0] };
11721
+
11722
+ //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
11723
+ if(this.helper[0] != this.currentItem[0]) {
11724
+ this.currentItem.hide();
11725
+ }
11726
+
11727
+ //Create the placeholder
11728
+ this._createPlaceholder();
11729
+
11730
+ //Set a containment if given in the options
11731
+ if(o.containment)
11732
+ this._setContainment();
11733
+
11734
+ if(o.cursor) { // cursor option
11735
+ if ($('body').css("cursor")) this._storedCursor = $('body').css("cursor");
11736
+ $('body').css("cursor", o.cursor);
11737
+ }
11738
+
11739
+ if(o.opacity) { // opacity option
11740
+ if (this.helper.css("opacity")) this._storedOpacity = this.helper.css("opacity");
11741
+ this.helper.css("opacity", o.opacity);
11742
+ }
11743
+
11744
+ if(o.zIndex) { // zIndex option
11745
+ if (this.helper.css("zIndex")) this._storedZIndex = this.helper.css("zIndex");
11746
+ this.helper.css("zIndex", o.zIndex);
11747
+ }
11748
+
11749
+ //Prepare scrolling
11750
+ if(this.scrollParent[0] != document && this.scrollParent[0].tagName != 'HTML')
11751
+ this.overflowOffset = this.scrollParent.offset();
11752
+
11753
+ //Call callbacks
11754
+ this._trigger("start", event, this._uiHash());
11755
+
11756
+ //Recache the helper size
11757
+ if(!this._preserveHelperProportions)
11758
+ this._cacheHelperProportions();
11759
+
11760
+
11761
+ //Post 'activate' events to possible containers
11762
+ if(!noActivation) {
11763
+ for (var i = this.containers.length - 1; i >= 0; i--) { this.containers[i]._trigger("activate", event, this._uiHash(this)); }
11764
+ }
11765
+
11766
+ //Prepare possible droppables
11767
+ if($.ui.ddmanager)
11768
+ $.ui.ddmanager.current = this;
11769
+
11770
+ if ($.ui.ddmanager && !o.dropBehaviour)
11771
+ $.ui.ddmanager.prepareOffsets(this, event);
11772
+
11773
+ this.dragging = true;
11774
+
11775
+ this.helper.addClass("ui-sortable-helper");
11776
+ this._mouseDrag(event); //Execute the drag once - this causes the helper not to be visible before getting its correct position
11777
+ return true;
11778
+
11779
+ },
11780
+
11781
+ _mouseDrag: function(event) {
11782
+
11783
+ //Compute the helpers position
11784
+ this.position = this._generatePosition(event);
11785
+ this.positionAbs = this._convertPositionTo("absolute");
11786
+
11787
+ if (!this.lastPositionAbs) {
11788
+ this.lastPositionAbs = this.positionAbs;
11789
+ }
11790
+
11791
+ //Do scrolling
11792
+ if(this.options.scroll) {
11793
+ var o = this.options, scrolled = false;
11794
+ if(this.scrollParent[0] != document && this.scrollParent[0].tagName != 'HTML') {
11795
+
11796
+ if((this.overflowOffset.top + this.scrollParent[0].offsetHeight) - event.pageY < o.scrollSensitivity)
11797
+ this.scrollParent[0].scrollTop = scrolled = this.scrollParent[0].scrollTop + o.scrollSpeed;
11798
+ else if(event.pageY - this.overflowOffset.top < o.scrollSensitivity)
11799
+ this.scrollParent[0].scrollTop = scrolled = this.scrollParent[0].scrollTop - o.scrollSpeed;
11800
+
11801
+ if((this.overflowOffset.left + this.scrollParent[0].offsetWidth) - event.pageX < o.scrollSensitivity)
11802
+ this.scrollParent[0].scrollLeft = scrolled = this.scrollParent[0].scrollLeft + o.scrollSpeed;
11803
+ else if(event.pageX - this.overflowOffset.left < o.scrollSensitivity)
11804
+ this.scrollParent[0].scrollLeft = scrolled = this.scrollParent[0].scrollLeft - o.scrollSpeed;
11805
+
11806
+ } else {
11807
+
11808
+ if(event.pageY - $(document).scrollTop() < o.scrollSensitivity)
11809
+ scrolled = $(document).scrollTop($(document).scrollTop() - o.scrollSpeed);
11810
+ else if($(window).height() - (event.pageY - $(document).scrollTop()) < o.scrollSensitivity)
11811
+ scrolled = $(document).scrollTop($(document).scrollTop() + o.scrollSpeed);
11812
+
11813
+ if(event.pageX - $(document).scrollLeft() < o.scrollSensitivity)
11814
+ scrolled = $(document).scrollLeft($(document).scrollLeft() - o.scrollSpeed);
11815
+ else if($(window).width() - (event.pageX - $(document).scrollLeft()) < o.scrollSensitivity)
11816
+ scrolled = $(document).scrollLeft($(document).scrollLeft() + o.scrollSpeed);
11817
+
11818
+ }
11819
+
11820
+ if(scrolled !== false && $.ui.ddmanager && !o.dropBehaviour)
11821
+ $.ui.ddmanager.prepareOffsets(this, event);
11822
+ }
11823
+
11824
+ //Regenerate the absolute position used for position checks
11825
+ this.positionAbs = this._convertPositionTo("absolute");
11826
+
11827
+ //Set the helper position
11828
+ if(!this.options.axis || this.options.axis != "y") this.helper[0].style.left = this.position.left+'px';
11829
+ if(!this.options.axis || this.options.axis != "x") this.helper[0].style.top = this.position.top+'px';
11830
+
11831
+ //Rearrange
11832
+ for (var i = this.items.length - 1; i >= 0; i--) {
11833
+
11834
+ //Cache variables and intersection, continue if no intersection
11835
+ var item = this.items[i], itemElement = item.item[0], intersection = this._intersectsWithPointer(item);
11836
+ if (!intersection) continue;
11837
+
11838
+ // Only put the placeholder inside the current Container, skip all
11839
+ // items form other containers. This works because when moving
11840
+ // an item from one container to another the
11841
+ // currentContainer is switched before the placeholder is moved.
11842
+ //
11843
+ // Without this moving items in "sub-sortables" can cause the placeholder to jitter
11844
+ // beetween the outer and inner container.
11845
+ if (item.instance !== this.currentContainer) continue;
11846
+
11847
+ if (itemElement != this.currentItem[0] //cannot intersect with itself
11848
+ && this.placeholder[intersection == 1 ? "next" : "prev"]()[0] != itemElement //no useless actions that have been done before
11849
+ && !$.contains(this.placeholder[0], itemElement) //no action if the item moved is the parent of the item checked
11850
+ && (this.options.type == 'semi-dynamic' ? !$.contains(this.element[0], itemElement) : true)
11851
+ //&& itemElement.parentNode == this.placeholder[0].parentNode // only rearrange items within the same container
11852
+ ) {
11853
+
11854
+ this.direction = intersection == 1 ? "down" : "up";
11855
+
11856
+ if (this.options.tolerance == "pointer" || this._intersectsWithSides(item)) {
11857
+ this._rearrange(event, item);
11858
+ } else {
11859
+ break;
11860
+ }
11861
+
11862
+ this._trigger("change", event, this._uiHash());
11863
+ break;
11864
+ }
11865
+ }
11866
+
11867
+ //Post events to containers
11868
+ this._contactContainers(event);
11869
+
11870
+ //Interconnect with droppables
11871
+ if($.ui.ddmanager) $.ui.ddmanager.drag(this, event);
11872
+
11873
+ //Call callbacks
11874
+ this._trigger('sort', event, this._uiHash());
11875
+
11876
+ this.lastPositionAbs = this.positionAbs;
11877
+ return false;
11878
+
11879
+ },
11880
+
11881
+ _mouseStop: function(event, noPropagation) {
11882
+
11883
+ if(!event) return;
11884
+
11885
+ //If we are using droppables, inform the manager about the drop
11886
+ if ($.ui.ddmanager && !this.options.dropBehaviour)
11887
+ $.ui.ddmanager.drop(this, event);
11888
+
11889
+ if(this.options.revert) {
11890
+ var that = this;
11891
+ var cur = this.placeholder.offset();
11892
+
11893
+ this.reverting = true;
11894
+
11895
+ $(this.helper).animate({
11896
+ left: cur.left - this.offset.parent.left - this.margins.left + (this.offsetParent[0] == document.body ? 0 : this.offsetParent[0].scrollLeft),
11897
+ top: cur.top - this.offset.parent.top - this.margins.top + (this.offsetParent[0] == document.body ? 0 : this.offsetParent[0].scrollTop)
11898
+ }, parseInt(this.options.revert, 10) || 500, function() {
11899
+ that._clear(event);
11900
+ });
11901
+ } else {
11902
+ this._clear(event, noPropagation);
11903
+ }
11904
+
11905
+ return false;
11906
+
11907
+ },
11908
+
11909
+ cancel: function() {
11910
+
11911
+ if(this.dragging) {
11912
+
11913
+ this._mouseUp({ target: null });
11914
+
11915
+ if(this.options.helper == "original")
11916
+ this.currentItem.css(this._storedCSS).removeClass("ui-sortable-helper");
11917
+ else
11918
+ this.currentItem.show();
11919
+
11920
+ //Post deactivating events to containers
11921
+ for (var i = this.containers.length - 1; i >= 0; i--){
11922
+ this.containers[i]._trigger("deactivate", null, this._uiHash(this));
11923
+ if(this.containers[i].containerCache.over) {
11924
+ this.containers[i]._trigger("out", null, this._uiHash(this));
11925
+ this.containers[i].containerCache.over = 0;
11926
+ }
11927
+ }
11928
+
11929
+ }
11930
+
11931
+ if (this.placeholder) {
11932
+ //$(this.placeholder[0]).remove(); would have been the jQuery way - unfortunately, it unbinds ALL events from the original node!
11933
+ if(this.placeholder[0].parentNode) this.placeholder[0].parentNode.removeChild(this.placeholder[0]);
11934
+ if(this.options.helper != "original" && this.helper && this.helper[0].parentNode) this.helper.remove();
11935
+
11936
+ $.extend(this, {
11937
+ helper: null,
11938
+ dragging: false,
11939
+ reverting: false,
11940
+ _noFinalSort: null
11941
+ });
11942
+
11943
+ if(this.domPosition.prev) {
11944
+ $(this.domPosition.prev).after(this.currentItem);
11945
+ } else {
11946
+ $(this.domPosition.parent).prepend(this.currentItem);
11947
+ }
11948
+ }
11949
+
11950
+ return this;
11951
+
11952
+ },
11953
+
11954
+ serialize: function(o) {
11955
+
11956
+ var items = this._getItemsAsjQuery(o && o.connected);
11957
+ var str = []; o = o || {};
11958
+
11959
+ $(items).each(function() {
11960
+ var res = ($(o.item || this).attr(o.attribute || 'id') || '').match(o.expression || (/(.+)[-=_](.+)/));
11961
+ if(res) str.push((o.key || res[1]+'[]')+'='+(o.key && o.expression ? res[1] : res[2]));
11962
+ });
11963
+
11964
+ if(!str.length && o.key) {
11965
+ str.push(o.key + '=');
11966
+ }
11967
+
11968
+ return str.join('&');
11969
+
11970
+ },
11971
+
11972
+ toArray: function(o) {
11973
+
11974
+ var items = this._getItemsAsjQuery(o && o.connected);
11975
+ var ret = []; o = o || {};
11976
+
11977
+ items.each(function() { ret.push($(o.item || this).attr(o.attribute || 'id') || ''); });
11978
+ return ret;
11979
+
11980
+ },
11981
+
11982
+ /* Be careful with the following core functions */
11983
+ _intersectsWith: function(item) {
11984
+
11985
+ var x1 = this.positionAbs.left,
11986
+ x2 = x1 + this.helperProportions.width,
11987
+ y1 = this.positionAbs.top,
11988
+ y2 = y1 + this.helperProportions.height;
11989
+
11990
+ var l = item.left,
11991
+ r = l + item.width,
11992
+ t = item.top,
11993
+ b = t + item.height;
11994
+
11995
+ var dyClick = this.offset.click.top,
11996
+ dxClick = this.offset.click.left;
11997
+
11998
+ var isOverElement = (y1 + dyClick) > t && (y1 + dyClick) < b && (x1 + dxClick) > l && (x1 + dxClick) < r;
11999
+
12000
+ if( this.options.tolerance == "pointer"
12001
+ || this.options.forcePointerForContainers
12002
+ || (this.options.tolerance != "pointer" && this.helperProportions[this.floating ? 'width' : 'height'] > item[this.floating ? 'width' : 'height'])
12003
+ ) {
12004
+ return isOverElement;
12005
+ } else {
12006
+
12007
+ return (l < x1 + (this.helperProportions.width / 2) // Right Half
12008
+ && x2 - (this.helperProportions.width / 2) < r // Left Half
12009
+ && t < y1 + (this.helperProportions.height / 2) // Bottom Half
12010
+ && y2 - (this.helperProportions.height / 2) < b ); // Top Half
12011
+
12012
+ }
12013
+ },
12014
+
12015
+ _intersectsWithPointer: function(item) {
12016
+
12017
+ var isOverElementHeight = (this.options.axis === 'x') || $.ui.isOverAxis(this.positionAbs.top + this.offset.click.top, item.top, item.height),
12018
+ isOverElementWidth = (this.options.axis === 'y') || $.ui.isOverAxis(this.positionAbs.left + this.offset.click.left, item.left, item.width),
12019
+ isOverElement = isOverElementHeight && isOverElementWidth,
12020
+ verticalDirection = this._getDragVerticalDirection(),
12021
+ horizontalDirection = this._getDragHorizontalDirection();
12022
+
12023
+ if (!isOverElement)
12024
+ return false;
12025
+
12026
+ return this.floating ?
12027
+ ( ((horizontalDirection && horizontalDirection == "right") || verticalDirection == "down") ? 2 : 1 )
12028
+ : ( verticalDirection && (verticalDirection == "down" ? 2 : 1) );
12029
+
12030
+ },
12031
+
12032
+ _intersectsWithSides: function(item) {
12033
+
12034
+ var isOverBottomHalf = $.ui.isOverAxis(this.positionAbs.top + this.offset.click.top, item.top + (item.height/2), item.height),
12035
+ isOverRightHalf = $.ui.isOverAxis(this.positionAbs.left + this.offset.click.left, item.left + (item.width/2), item.width),
12036
+ verticalDirection = this._getDragVerticalDirection(),
12037
+ horizontalDirection = this._getDragHorizontalDirection();
12038
+
12039
+ if (this.floating && horizontalDirection) {
12040
+ return ((horizontalDirection == "right" && isOverRightHalf) || (horizontalDirection == "left" && !isOverRightHalf));
12041
+ } else {
12042
+ return verticalDirection && ((verticalDirection == "down" && isOverBottomHalf) || (verticalDirection == "up" && !isOverBottomHalf));
12043
+ }
12044
+
12045
+ },
12046
+
12047
+ _getDragVerticalDirection: function() {
12048
+ var delta = this.positionAbs.top - this.lastPositionAbs.top;
12049
+ return delta != 0 && (delta > 0 ? "down" : "up");
12050
+ },
12051
+
12052
+ _getDragHorizontalDirection: function() {
12053
+ var delta = this.positionAbs.left - this.lastPositionAbs.left;
12054
+ return delta != 0 && (delta > 0 ? "right" : "left");
12055
+ },
12056
+
12057
+ refresh: function(event) {
12058
+ this._refreshItems(event);
12059
+ this.refreshPositions();
12060
+ return this;
12061
+ },
12062
+
12063
+ _connectWith: function() {
12064
+ var options = this.options;
12065
+ return options.connectWith.constructor == String
12066
+ ? [options.connectWith]
12067
+ : options.connectWith;
12068
+ },
12069
+
12070
+ _getItemsAsjQuery: function(connected) {
12071
+
12072
+ var items = [];
12073
+ var queries = [];
12074
+ var connectWith = this._connectWith();
12075
+
12076
+ if(connectWith && connected) {
12077
+ for (var i = connectWith.length - 1; i >= 0; i--){
12078
+ var cur = $(connectWith[i]);
12079
+ for (var j = cur.length - 1; j >= 0; j--){
12080
+ var inst = $.data(cur[j], this.widgetName);
12081
+ if(inst && inst != this && !inst.options.disabled) {
12082
+ 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]);
12083
+ }
12084
+ };
12085
+ };
12086
+ }
12087
+
12088
+ 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]);
12089
+
12090
+ for (var i = queries.length - 1; i >= 0; i--){
12091
+ queries[i][0].each(function() {
12092
+ items.push(this);
12093
+ });
12094
+ };
12095
+
12096
+ return $(items);
12097
+
12098
+ },
12099
+
12100
+ _removeCurrentsFromItems: function() {
12101
+
12102
+ var list = this.currentItem.find(":data(" + this.widgetName + "-item)");
12103
+
12104
+ this.items = $.grep(this.items, function (item) {
12105
+ for (var j=0; j < list.length; j++) {
12106
+ if(list[j] == item.item[0])
12107
+ return false;
12108
+ };
12109
+ return true;
12110
+ });
12111
+
12112
+ },
12113
+
12114
+ _refreshItems: function(event) {
12115
+
12116
+ this.items = [];
12117
+ this.containers = [this];
12118
+ var items = this.items;
12119
+ var queries = [[$.isFunction(this.options.items) ? this.options.items.call(this.element[0], event, { item: this.currentItem }) : $(this.options.items, this.element), this]];
12120
+ var connectWith = this._connectWith();
12121
+
12122
+ if(connectWith && this.ready) { //Shouldn't be run the first time through due to massive slow-down
12123
+ for (var i = connectWith.length - 1; i >= 0; i--){
12124
+ var cur = $(connectWith[i]);
12125
+ for (var j = cur.length - 1; j >= 0; j--){
12126
+ var inst = $.data(cur[j], this.widgetName);
12127
+ if(inst && inst != this && !inst.options.disabled) {
12128
+ queries.push([$.isFunction(inst.options.items) ? inst.options.items.call(inst.element[0], event, { item: this.currentItem }) : $(inst.options.items, inst.element), inst]);
12129
+ this.containers.push(inst);
12130
+ }
12131
+ };
12132
+ };
12133
+ }
12134
+
12135
+ for (var i = queries.length - 1; i >= 0; i--) {
12136
+ var targetData = queries[i][1];
12137
+ var _queries = queries[i][0];
12138
+
12139
+ for (var j=0, queriesLength = _queries.length; j < queriesLength; j++) {
12140
+ var item = $(_queries[j]);
12141
+
12142
+ item.data(this.widgetName + '-item', targetData); // Data for target checking (mouse manager)
12143
+
12144
+ items.push({
12145
+ item: item,
12146
+ instance: targetData,
12147
+ width: 0, height: 0,
12148
+ left: 0, top: 0
12149
+ });
12150
+ };
12151
+ };
12152
+
12153
+ },
12154
+
12155
+ refreshPositions: function(fast) {
12156
+
12157
+ //This has to be redone because due to the item being moved out/into the offsetParent, the offsetParent's position will change
12158
+ if(this.offsetParent && this.helper) {
12159
+ this.offset.parent = this._getParentOffset();
12160
+ }
12161
+
12162
+ for (var i = this.items.length - 1; i >= 0; i--){
12163
+ var item = this.items[i];
12164
+
12165
+ //We ignore calculating positions of all connected containers when we're not over them
12166
+ if(item.instance != this.currentContainer && this.currentContainer && item.item[0] != this.currentItem[0])
12167
+ continue;
12168
+
12169
+ var t = this.options.toleranceElement ? $(this.options.toleranceElement, item.item) : item.item;
12170
+
12171
+ if (!fast) {
12172
+ item.width = t.outerWidth();
12173
+ item.height = t.outerHeight();
12174
+ }
12175
+
12176
+ var p = t.offset();
12177
+ item.left = p.left;
12178
+ item.top = p.top;
12179
+ };
12180
+
12181
+ if(this.options.custom && this.options.custom.refreshContainers) {
12182
+ this.options.custom.refreshContainers.call(this);
12183
+ } else {
12184
+ for (var i = this.containers.length - 1; i >= 0; i--){
12185
+ var p = this.containers[i].element.offset();
12186
+ this.containers[i].containerCache.left = p.left;
12187
+ this.containers[i].containerCache.top = p.top;
12188
+ this.containers[i].containerCache.width = this.containers[i].element.outerWidth();
12189
+ this.containers[i].containerCache.height = this.containers[i].element.outerHeight();
12190
+ };
12191
+ }
12192
+
12193
+ return this;
12194
+ },
12195
+
12196
+ _createPlaceholder: function(that) {
12197
+ that = that || this;
12198
+ var o = that.options;
12199
+
12200
+ if(!o.placeholder || o.placeholder.constructor == String) {
12201
+ var className = o.placeholder;
12202
+ o.placeholder = {
12203
+ element: function() {
12204
+
12205
+ var el = $(document.createElement(that.currentItem[0].nodeName))
12206
+ .addClass(className || that.currentItem[0].className+" ui-sortable-placeholder")
12207
+ .removeClass("ui-sortable-helper")[0];
12208
+
12209
+ if(!className)
12210
+ el.style.visibility = "hidden";
12211
+
12212
+ return el;
12213
+ },
12214
+ update: function(container, p) {
12215
+
12216
+ // 1. If a className is set as 'placeholder option, we don't force sizes - the class is responsible for that
12217
+ // 2. The option 'forcePlaceholderSize can be enabled to force it even if a class name is specified
12218
+ if(className && !o.forcePlaceholderSize) return;
12219
+
12220
+ //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
12221
+ if(!p.height()) { p.height(that.currentItem.innerHeight() - parseInt(that.currentItem.css('paddingTop')||0, 10) - parseInt(that.currentItem.css('paddingBottom')||0, 10)); };
12222
+ if(!p.width()) { p.width(that.currentItem.innerWidth() - parseInt(that.currentItem.css('paddingLeft')||0, 10) - parseInt(that.currentItem.css('paddingRight')||0, 10)); };
12223
+ }
12224
+ };
12225
+ }
12226
+
12227
+ //Create the placeholder
12228
+ that.placeholder = $(o.placeholder.element.call(that.element, that.currentItem));
12229
+
12230
+ //Append it after the actual current item
12231
+ that.currentItem.after(that.placeholder);
12232
+
12233
+ //Update the size of the placeholder (TODO: Logic to fuzzy, see line 316/317)
12234
+ o.placeholder.update(that, that.placeholder);
12235
+
12236
+ },
12237
+
12238
+ _contactContainers: function(event) {
12239
+
12240
+ // get innermost container that intersects with item
12241
+ var innermostContainer = null, innermostIndex = null;
12242
+
12243
+
12244
+ for (var i = this.containers.length - 1; i >= 0; i--){
12245
+
12246
+ // never consider a container that's located within the item itself
12247
+ if($.contains(this.currentItem[0], this.containers[i].element[0]))
12248
+ continue;
12249
+
12250
+ if(this._intersectsWith(this.containers[i].containerCache)) {
12251
+
12252
+ // if we've already found a container and it's more "inner" than this, then continue
12253
+ if(innermostContainer && $.contains(this.containers[i].element[0], innermostContainer.element[0]))
12254
+ continue;
12255
+
12256
+ innermostContainer = this.containers[i];
12257
+ innermostIndex = i;
12258
+
12259
+ } else {
12260
+ // container doesn't intersect. trigger "out" event if necessary
12261
+ if(this.containers[i].containerCache.over) {
12262
+ this.containers[i]._trigger("out", event, this._uiHash(this));
12263
+ this.containers[i].containerCache.over = 0;
12264
+ }
12265
+ }
12266
+
12267
+ }
12268
+
12269
+ // if no intersecting containers found, return
12270
+ if(!innermostContainer) return;
12271
+
12272
+ // move the item into the container if it's not there already
12273
+ if(this.containers.length === 1) {
12274
+ this.containers[innermostIndex]._trigger("over", event, this._uiHash(this));
12275
+ this.containers[innermostIndex].containerCache.over = 1;
12276
+ } else {
12277
+
12278
+ //When entering a new container, we will find the item with the least distance and append our item near it
12279
+ var dist = 10000; var itemWithLeastDistance = null;
12280
+ var posProperty = this.containers[innermostIndex].floating ? 'left' : 'top';
12281
+ var sizeProperty = this.containers[innermostIndex].floating ? 'width' : 'height';
12282
+ var base = this.positionAbs[posProperty] + this.offset.click[posProperty];
12283
+ for (var j = this.items.length - 1; j >= 0; j--) {
12284
+ if(!$.contains(this.containers[innermostIndex].element[0], this.items[j].item[0])) continue;
12285
+ if(this.items[j].item[0] == this.currentItem[0]) continue;
12286
+ var cur = this.items[j].item.offset()[posProperty];
12287
+ var nearBottom = false;
12288
+ if(Math.abs(cur - base) > Math.abs(cur + this.items[j][sizeProperty] - base)){
12289
+ nearBottom = true;
12290
+ cur += this.items[j][sizeProperty];
12291
+ }
12292
+
12293
+ if(Math.abs(cur - base) < dist) {
12294
+ dist = Math.abs(cur - base); itemWithLeastDistance = this.items[j];
12295
+ this.direction = nearBottom ? "up": "down";
12296
+ }
12297
+ }
12298
+
12299
+ if(!itemWithLeastDistance && !this.options.dropOnEmpty) //Check if dropOnEmpty is enabled
12300
+ return;
12301
+
12302
+ this.currentContainer = this.containers[innermostIndex];
12303
+ itemWithLeastDistance ? this._rearrange(event, itemWithLeastDistance, null, true) : this._rearrange(event, null, this.containers[innermostIndex].element, true);
12304
+ this._trigger("change", event, this._uiHash());
12305
+ this.containers[innermostIndex]._trigger("change", event, this._uiHash(this));
12306
+
12307
+ //Update the placeholder
12308
+ this.options.placeholder.update(this.currentContainer, this.placeholder);
12309
+
12310
+ this.containers[innermostIndex]._trigger("over", event, this._uiHash(this));
12311
+ this.containers[innermostIndex].containerCache.over = 1;
12312
+ }
12313
+
12314
+
12315
+ },
12316
+
12317
+ _createHelper: function(event) {
12318
+
12319
+ var o = this.options;
12320
+ var helper = $.isFunction(o.helper) ? $(o.helper.apply(this.element[0], [event, this.currentItem])) : (o.helper == 'clone' ? this.currentItem.clone() : this.currentItem);
12321
+
12322
+ if(!helper.parents('body').length) //Add the helper to the DOM if that didn't happen already
12323
+ $(o.appendTo != 'parent' ? o.appendTo : this.currentItem[0].parentNode)[0].appendChild(helper[0]);
12324
+
12325
+ if(helper[0] == this.currentItem[0])
12326
+ 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") };
12327
+
12328
+ if(helper[0].style.width == '' || o.forceHelperSize) helper.width(this.currentItem.width());
12329
+ if(helper[0].style.height == '' || o.forceHelperSize) helper.height(this.currentItem.height());
12330
+
12331
+ return helper;
12332
+
12333
+ },
12334
+
12335
+ _adjustOffsetFromHelper: function(obj) {
12336
+ if (typeof obj == 'string') {
12337
+ obj = obj.split(' ');
12338
+ }
12339
+ if ($.isArray(obj)) {
12340
+ obj = {left: +obj[0], top: +obj[1] || 0};
12341
+ }
12342
+ if ('left' in obj) {
12343
+ this.offset.click.left = obj.left + this.margins.left;
12344
+ }
12345
+ if ('right' in obj) {
12346
+ this.offset.click.left = this.helperProportions.width - obj.right + this.margins.left;
12347
+ }
12348
+ if ('top' in obj) {
12349
+ this.offset.click.top = obj.top + this.margins.top;
12350
+ }
12351
+ if ('bottom' in obj) {
12352
+ this.offset.click.top = this.helperProportions.height - obj.bottom + this.margins.top;
12353
+ }
12354
+ },
12355
+
12356
+ _getParentOffset: function() {
12357
+
12358
+
12359
+ //Get the offsetParent and cache its position
12360
+ this.offsetParent = this.helper.offsetParent();
12361
+ var po = this.offsetParent.offset();
12362
+
12363
+ // This is a special case where we need to modify a offset calculated on start, since the following happened:
12364
+ // 1. The position of the helper is absolute, so it's position is calculated based on the next positioned parent
12365
+ // 2. The actual offset parent is a child of the scroll parent, and the scroll parent isn't the document, which means that
12366
+ // the scroll is included in the initial calculation of the offset of the parent, and never recalculated upon drag
12367
+ if(this.cssPosition == 'absolute' && this.scrollParent[0] != document && $.contains(this.scrollParent[0], this.offsetParent[0])) {
12368
+ po.left += this.scrollParent.scrollLeft();
12369
+ po.top += this.scrollParent.scrollTop();
12370
+ }
12371
+
12372
+ if((this.offsetParent[0] == document.body) //This needs to be actually done for all browsers, since pageX/pageY includes this information
12373
+ || (this.offsetParent[0].tagName && this.offsetParent[0].tagName.toLowerCase() == 'html' && $.ui.ie)) //Ugly IE fix
12374
+ po = { top: 0, left: 0 };
12375
+
12376
+ return {
12377
+ top: po.top + (parseInt(this.offsetParent.css("borderTopWidth"),10) || 0),
12378
+ left: po.left + (parseInt(this.offsetParent.css("borderLeftWidth"),10) || 0)
12379
+ };
12380
+
12381
+ },
12382
+
12383
+ _getRelativeOffset: function() {
12384
+
12385
+ if(this.cssPosition == "relative") {
12386
+ var p = this.currentItem.position();
12387
+ return {
12388
+ top: p.top - (parseInt(this.helper.css("top"),10) || 0) + this.scrollParent.scrollTop(),
12389
+ left: p.left - (parseInt(this.helper.css("left"),10) || 0) + this.scrollParent.scrollLeft()
12390
+ };
12391
+ } else {
12392
+ return { top: 0, left: 0 };
12393
+ }
12394
+
12395
+ },
12396
+
12397
+ _cacheMargins: function() {
12398
+ this.margins = {
12399
+ left: (parseInt(this.currentItem.css("marginLeft"),10) || 0),
12400
+ top: (parseInt(this.currentItem.css("marginTop"),10) || 0)
12401
+ };
12402
+ },
12403
+
12404
+ _cacheHelperProportions: function() {
12405
+ this.helperProportions = {
12406
+ width: this.helper.outerWidth(),
12407
+ height: this.helper.outerHeight()
12408
+ };
12409
+ },
12410
+
12411
+ _setContainment: function() {
12412
+
12413
+ var o = this.options;
12414
+ if(o.containment == 'parent') o.containment = this.helper[0].parentNode;
12415
+ if(o.containment == 'document' || o.containment == 'window') this.containment = [
12416
+ 0 - this.offset.relative.left - this.offset.parent.left,
12417
+ 0 - this.offset.relative.top - this.offset.parent.top,
12418
+ $(o.containment == 'document' ? document : window).width() - this.helperProportions.width - this.margins.left,
12419
+ ($(o.containment == 'document' ? document : window).height() || document.body.parentNode.scrollHeight) - this.helperProportions.height - this.margins.top
12420
+ ];
12421
+
12422
+ if(!(/^(document|window|parent)$/).test(o.containment)) {
12423
+ var ce = $(o.containment)[0];
12424
+ var co = $(o.containment).offset();
12425
+ var over = ($(ce).css("overflow") != 'hidden');
12426
+
12427
+ this.containment = [
12428
+ co.left + (parseInt($(ce).css("borderLeftWidth"),10) || 0) + (parseInt($(ce).css("paddingLeft"),10) || 0) - this.margins.left,
12429
+ co.top + (parseInt($(ce).css("borderTopWidth"),10) || 0) + (parseInt($(ce).css("paddingTop"),10) || 0) - this.margins.top,
12430
+ 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,
12431
+ 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
12432
+ ];
12433
+ }
12434
+
12435
+ },
12436
+
12437
+ _convertPositionTo: function(d, pos) {
12438
+
12439
+ if(!pos) pos = this.position;
12440
+ var mod = d == "absolute" ? 1 : -1;
12441
+ var o = this.options, 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);
12442
+
12443
+ return {
12444
+ top: (
12445
+ pos.top // The absolute mouse position
12446
+ + this.offset.relative.top * mod // Only for relative positioned nodes: Relative offset from element to offset parent
12447
+ + this.offset.parent.top * mod // The offsetParent's offset without borders (offset + border)
12448
+ - ( ( this.cssPosition == 'fixed' ? -this.scrollParent.scrollTop() : ( scrollIsRootNode ? 0 : scroll.scrollTop() ) ) * mod)
12449
+ ),
12450
+ left: (
12451
+ pos.left // The absolute mouse position
12452
+ + this.offset.relative.left * mod // Only for relative positioned nodes: Relative offset from element to offset parent
12453
+ + this.offset.parent.left * mod // The offsetParent's offset without borders (offset + border)
12454
+ - ( ( this.cssPosition == 'fixed' ? -this.scrollParent.scrollLeft() : scrollIsRootNode ? 0 : scroll.scrollLeft() ) * mod)
12455
+ )
12456
+ };
12457
+
12458
+ },
12459
+
12460
+ _generatePosition: function(event) {
12461
+
12462
+ var o = this.options, 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);
12463
+
12464
+ // This is another very weird special case that only happens for relative elements:
12465
+ // 1. If the css position is relative
12466
+ // 2. and the scroll parent is the document or similar to the offset parent
12467
+ // we have to refresh the relative offset during the scroll so there are no jumps
12468
+ if(this.cssPosition == 'relative' && !(this.scrollParent[0] != document && this.scrollParent[0] != this.offsetParent[0])) {
12469
+ this.offset.relative = this._getRelativeOffset();
12470
+ }
12471
+
12472
+ var pageX = event.pageX;
12473
+ var pageY = event.pageY;
12474
+
12475
+ /*
12476
+ * - Position constraining -
12477
+ * Constrain the position to a mix of grid, containment.
12478
+ */
12479
+
12480
+ if(this.originalPosition) { //If we are not dragging yet, we won't check for options
12481
+
12482
+ if(this.containment) {
12483
+ if(event.pageX - this.offset.click.left < this.containment[0]) pageX = this.containment[0] + this.offset.click.left;
12484
+ if(event.pageY - this.offset.click.top < this.containment[1]) pageY = this.containment[1] + this.offset.click.top;
12485
+ if(event.pageX - this.offset.click.left > this.containment[2]) pageX = this.containment[2] + this.offset.click.left;
12486
+ if(event.pageY - this.offset.click.top > this.containment[3]) pageY = this.containment[3] + this.offset.click.top;
12487
+ }
12488
+
12489
+ if(o.grid) {
12490
+ var top = this.originalPageY + Math.round((pageY - this.originalPageY) / o.grid[1]) * o.grid[1];
12491
+ 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;
12492
+
12493
+ var left = this.originalPageX + Math.round((pageX - this.originalPageX) / o.grid[0]) * o.grid[0];
12494
+ 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;
12495
+ }
12496
+
12497
+ }
12498
+
12499
+ return {
12500
+ top: (
12501
+ pageY // The absolute mouse position
12502
+ - this.offset.click.top // Click offset (relative to the element)
12503
+ - this.offset.relative.top // Only for relative positioned nodes: Relative offset from element to offset parent
12504
+ - this.offset.parent.top // The offsetParent's offset without borders (offset + border)
12505
+ + ( ( this.cssPosition == 'fixed' ? -this.scrollParent.scrollTop() : ( scrollIsRootNode ? 0 : scroll.scrollTop() ) ))
12506
+ ),
12507
+ left: (
12508
+ pageX // The absolute mouse position
12509
+ - this.offset.click.left // Click offset (relative to the element)
12510
+ - this.offset.relative.left // Only for relative positioned nodes: Relative offset from element to offset parent
12511
+ - this.offset.parent.left // The offsetParent's offset without borders (offset + border)
12512
+ + ( ( this.cssPosition == 'fixed' ? -this.scrollParent.scrollLeft() : scrollIsRootNode ? 0 : scroll.scrollLeft() ))
12513
+ )
12514
+ };
12515
+
12516
+ },
12517
+
12518
+ _rearrange: function(event, i, a, hardRefresh) {
12519
+
12520
+ 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));
12521
+
12522
+ //Various things done here to improve the performance:
12523
+ // 1. we create a setTimeout, that calls refreshPositions
12524
+ // 2. on the instance, we have a counter variable, that get's higher after every append
12525
+ // 3. on the local scope, we copy the counter variable, and check in the timeout, if it's still the same
12526
+ // 4. this lets only the last addition to the timeout stack through
12527
+ this.counter = this.counter ? ++this.counter : 1;
12528
+ var counter = this.counter;
12529
+
12530
+ this._delay(function() {
12531
+ if(counter == this.counter) this.refreshPositions(!hardRefresh); //Precompute after each DOM insertion, NOT on mousemove
12532
+ });
12533
+
12534
+ },
12535
+
12536
+ _clear: function(event, noPropagation) {
12537
+
12538
+ this.reverting = false;
12539
+ // We delay all events that have to be triggered to after the point where the placeholder has been removed and
12540
+ // everything else normalized again
12541
+ var delayedTriggers = [];
12542
+
12543
+ // We first have to update the dom position of the actual currentItem
12544
+ // Note: don't do it if the current item is already removed (by a user), or it gets reappended (see #4088)
12545
+ if(!this._noFinalSort && this.currentItem.parent().length) this.placeholder.before(this.currentItem);
12546
+ this._noFinalSort = null;
12547
+
12548
+ if(this.helper[0] == this.currentItem[0]) {
12549
+ for(var i in this._storedCSS) {
12550
+ if(this._storedCSS[i] == 'auto' || this._storedCSS[i] == 'static') this._storedCSS[i] = '';
12551
+ }
12552
+ this.currentItem.css(this._storedCSS).removeClass("ui-sortable-helper");
12553
+ } else {
12554
+ this.currentItem.show();
12555
+ }
12556
+
12557
+ if(this.fromOutside && !noPropagation) delayedTriggers.push(function(event) { this._trigger("receive", event, this._uiHash(this.fromOutside)); });
12558
+ 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
12559
+
12560
+ // Check if the items Container has Changed and trigger appropriate
12561
+ // events.
12562
+ if (this !== this.currentContainer) {
12563
+ if(!noPropagation) {
12564
+ delayedTriggers.push(function(event) { this._trigger("remove", event, this._uiHash()); });
12565
+ delayedTriggers.push((function(c) { return function(event) { c._trigger("receive", event, this._uiHash(this)); }; }).call(this, this.currentContainer));
12566
+ delayedTriggers.push((function(c) { return function(event) { c._trigger("update", event, this._uiHash(this)); }; }).call(this, this.currentContainer));
12567
+ }
12568
+ }
12569
+
12570
+
12571
+ //Post events to containers
12572
+ for (var i = this.containers.length - 1; i >= 0; i--){
12573
+ if(!noPropagation) delayedTriggers.push((function(c) { return function(event) { c._trigger("deactivate", event, this._uiHash(this)); }; }).call(this, this.containers[i]));
12574
+ if(this.containers[i].containerCache.over) {
12575
+ delayedTriggers.push((function(c) { return function(event) { c._trigger("out", event, this._uiHash(this)); }; }).call(this, this.containers[i]));
12576
+ this.containers[i].containerCache.over = 0;
12577
+ }
12578
+ }
12579
+
12580
+ //Do what was originally in plugins
12581
+ if(this._storedCursor) $('body').css("cursor", this._storedCursor); //Reset cursor
12582
+ if(this._storedOpacity) this.helper.css("opacity", this._storedOpacity); //Reset opacity
12583
+ if(this._storedZIndex) this.helper.css("zIndex", this._storedZIndex == 'auto' ? '' : this._storedZIndex); //Reset z-index
12584
+
12585
+ this.dragging = false;
12586
+ if(this.cancelHelperRemoval) {
12587
+ if(!noPropagation) {
12588
+ this._trigger("beforeStop", event, this._uiHash());
12589
+ for (var i=0; i < delayedTriggers.length; i++) { delayedTriggers[i].call(this, event); }; //Trigger all delayed events
12590
+ this._trigger("stop", event, this._uiHash());
12591
+ }
12592
+
12593
+ this.fromOutside = false;
12594
+ return false;
12595
+ }
12596
+
12597
+ if(!noPropagation) this._trigger("beforeStop", event, this._uiHash());
12598
+
12599
+ //$(this.placeholder[0]).remove(); would have been the jQuery way - unfortunately, it unbinds ALL events from the original node!
12600
+ this.placeholder[0].parentNode.removeChild(this.placeholder[0]);
12601
+
12602
+ if(this.helper[0] != this.currentItem[0]) this.helper.remove(); this.helper = null;
12603
+
12604
+ if(!noPropagation) {
12605
+ for (var i=0; i < delayedTriggers.length; i++) { delayedTriggers[i].call(this, event); }; //Trigger all delayed events
12606
+ this._trigger("stop", event, this._uiHash());
12607
+ }
12608
+
12609
+ this.fromOutside = false;
12610
+ return true;
12611
+
12612
+ },
12613
+
12614
+ _trigger: function() {
12615
+ if ($.Widget.prototype._trigger.apply(this, arguments) === false) {
12616
+ this.cancel();
12617
+ }
12618
+ },
12619
+
12620
+ _uiHash: function(_inst) {
12621
+ var inst = _inst || this;
12622
+ return {
12623
+ helper: inst.helper,
12624
+ placeholder: inst.placeholder || $([]),
12625
+ position: inst.position,
12626
+ originalPosition: inst.originalPosition,
12627
+ offset: inst.positionAbs,
12628
+ item: inst.currentItem,
12629
+ sender: _inst ? _inst.element : null
12630
+ };
12631
+ }
12632
+
12633
+ });
12634
+
12635
+ })(jQuery);
12636
+ (function( $ ) {
12637
+
12638
+ function modifier( fn ) {
12639
+ return function() {
12640
+ var previous = this.element.val();
12641
+ fn.apply( this, arguments );
12642
+ this._refresh();
12643
+ if ( previous !== this.element.val() ) {
12644
+ this._trigger( "change" );
12645
+ }
12646
+ };
12647
+ }
12648
+
12649
+ $.widget( "ui.spinner", {
12650
+ version: "1.9.1",
12651
+ defaultElement: "<input>",
12652
+ widgetEventPrefix: "spin",
12653
+ options: {
12654
+ culture: null,
12655
+ icons: {
12656
+ down: "ui-icon-triangle-1-s",
12657
+ up: "ui-icon-triangle-1-n"
12658
+ },
12659
+ incremental: true,
12660
+ max: null,
12661
+ min: null,
12662
+ numberFormat: null,
12663
+ page: 10,
12664
+ step: 1,
12665
+
12666
+ change: null,
12667
+ spin: null,
12668
+ start: null,
12669
+ stop: null
12670
+ },
12671
+
12672
+ _create: function() {
12673
+ // handle string values that need to be parsed
12674
+ this._setOption( "max", this.options.max );
12675
+ this._setOption( "min", this.options.min );
12676
+ this._setOption( "step", this.options.step );
12677
+
12678
+ // format the value, but don't constrain
12679
+ this._value( this.element.val(), true );
12680
+
12681
+ this._draw();
12682
+ this._on( this._events );
12683
+ this._refresh();
12684
+
12685
+ // turning off autocomplete prevents the browser from remembering the
12686
+ // value when navigating through history, so we re-enable autocomplete
12687
+ // if the page is unloaded before the widget is destroyed. #7790
12688
+ this._on( this.window, {
12689
+ beforeunload: function() {
12690
+ this.element.removeAttr( "autocomplete" );
12691
+ }
12692
+ });
12693
+ },
12694
+
12695
+ _getCreateOptions: function() {
12696
+ var options = {},
12697
+ element = this.element;
12698
+
12699
+ $.each( [ "min", "max", "step" ], function( i, option ) {
12700
+ var value = element.attr( option );
12701
+ if ( value !== undefined && value.length ) {
12702
+ options[ option ] = value;
12703
+ }
12704
+ });
12705
+
12706
+ return options;
12707
+ },
12708
+
12709
+ _events: {
12710
+ keydown: function( event ) {
12711
+ if ( this._start( event ) && this._keydown( event ) ) {
12712
+ event.preventDefault();
12713
+ }
12714
+ },
12715
+ keyup: "_stop",
12716
+ focus: function() {
12717
+ this.previous = this.element.val();
12718
+ },
12719
+ blur: function( event ) {
12720
+ if ( this.cancelBlur ) {
12721
+ delete this.cancelBlur;
12722
+ return;
12723
+ }
12724
+
12725
+ this._refresh();
12726
+ if ( this.previous !== this.element.val() ) {
12727
+ this._trigger( "change", event );
12728
+ }
12729
+ },
12730
+ mousewheel: function( event, delta ) {
12731
+ if ( !delta ) {
12732
+ return;
12733
+ }
12734
+ if ( !this.spinning && !this._start( event ) ) {
12735
+ return false;
12736
+ }
12737
+
12738
+ this._spin( (delta > 0 ? 1 : -1) * this.options.step, event );
12739
+ clearTimeout( this.mousewheelTimer );
12740
+ this.mousewheelTimer = this._delay(function() {
12741
+ if ( this.spinning ) {
12742
+ this._stop( event );
12743
+ }
12744
+ }, 100 );
12745
+ event.preventDefault();
12746
+ },
12747
+ "mousedown .ui-spinner-button": function( event ) {
12748
+ var previous;
12749
+
12750
+ // We never want the buttons to have focus; whenever the user is
12751
+ // interacting with the spinner, the focus should be on the input.
12752
+ // If the input is focused then this.previous is properly set from
12753
+ // when the input first received focus. If the input is not focused
12754
+ // then we need to set this.previous based on the value before spinning.
12755
+ previous = this.element[0] === this.document[0].activeElement ?
12756
+ this.previous : this.element.val();
12757
+ function checkFocus() {
12758
+ var isActive = this.element[0] === this.document[0].activeElement;
12759
+ if ( !isActive ) {
12760
+ this.element.focus();
12761
+ this.previous = previous;
12762
+ // support: IE
12763
+ // IE sets focus asynchronously, so we need to check if focus
12764
+ // moved off of the input because the user clicked on the button.
12765
+ this._delay(function() {
12766
+ this.previous = previous;
12767
+ });
12768
+ }
12769
+ }
12770
+
12771
+ // ensure focus is on (or stays on) the text field
12772
+ event.preventDefault();
12773
+ checkFocus.call( this );
12774
+
12775
+ // support: IE
12776
+ // IE doesn't prevent moving focus even with event.preventDefault()
12777
+ // so we set a flag to know when we should ignore the blur event
12778
+ // and check (again) if focus moved off of the input.
12779
+ this.cancelBlur = true;
12780
+ this._delay(function() {
12781
+ delete this.cancelBlur;
12782
+ checkFocus.call( this );
12783
+ });
12784
+
12785
+ if ( this._start( event ) === false ) {
12786
+ return;
12787
+ }
12788
+
12789
+ this._repeat( null, $( event.currentTarget ).hasClass( "ui-spinner-up" ) ? 1 : -1, event );
12790
+ },
12791
+ "mouseup .ui-spinner-button": "_stop",
12792
+ "mouseenter .ui-spinner-button": function( event ) {
12793
+ // button will add ui-state-active if mouse was down while mouseleave and kept down
12794
+ if ( !$( event.currentTarget ).hasClass( "ui-state-active" ) ) {
12795
+ return;
12796
+ }
12797
+
12798
+ if ( this._start( event ) === false ) {
12799
+ return false;
12800
+ }
12801
+ this._repeat( null, $( event.currentTarget ).hasClass( "ui-spinner-up" ) ? 1 : -1, event );
12802
+ },
12803
+ // TODO: do we really want to consider this a stop?
12804
+ // shouldn't we just stop the repeater and wait until mouseup before
12805
+ // we trigger the stop event?
12806
+ "mouseleave .ui-spinner-button": "_stop"
12807
+ },
12808
+
12809
+ _draw: function() {
12810
+ var uiSpinner = this.uiSpinner = this.element
12811
+ .addClass( "ui-spinner-input" )
12812
+ .attr( "autocomplete", "off" )
12813
+ .wrap( this._uiSpinnerHtml() )
12814
+ .parent()
12815
+ // add buttons
12816
+ .append( this._buttonHtml() );
12817
+
12818
+ this.element.attr( "role", "spinbutton" );
12819
+
12820
+ // button bindings
12821
+ this.buttons = uiSpinner.find( ".ui-spinner-button" )
12822
+ .attr( "tabIndex", -1 )
12823
+ .button()
12824
+ .removeClass( "ui-corner-all" );
12825
+
12826
+ // IE 6 doesn't understand height: 50% for the buttons
12827
+ // unless the wrapper has an explicit height
12828
+ if ( this.buttons.height() > Math.ceil( uiSpinner.height() * 0.5 ) &&
12829
+ uiSpinner.height() > 0 ) {
12830
+ uiSpinner.height( uiSpinner.height() );
12831
+ }
12832
+
12833
+ // disable spinner if element was already disabled
12834
+ if ( this.options.disabled ) {
12835
+ this.disable();
12836
+ }
12837
+ },
12838
+
12839
+ _keydown: function( event ) {
12840
+ var options = this.options,
12841
+ keyCode = $.ui.keyCode;
12842
+
12843
+ switch ( event.keyCode ) {
12844
+ case keyCode.UP:
12845
+ this._repeat( null, 1, event );
12846
+ return true;
12847
+ case keyCode.DOWN:
12848
+ this._repeat( null, -1, event );
12849
+ return true;
12850
+ case keyCode.PAGE_UP:
12851
+ this._repeat( null, options.page, event );
12852
+ return true;
12853
+ case keyCode.PAGE_DOWN:
12854
+ this._repeat( null, -options.page, event );
12855
+ return true;
12856
+ }
12857
+
12858
+ return false;
12859
+ },
12860
+
12861
+ _uiSpinnerHtml: function() {
12862
+ return "<span class='ui-spinner ui-widget ui-widget-content ui-corner-all'></span>";
12863
+ },
12864
+
12865
+ _buttonHtml: function() {
12866
+ return "" +
12867
+ "<a class='ui-spinner-button ui-spinner-up ui-corner-tr'>" +
12868
+ "<span class='ui-icon " + this.options.icons.up + "'>&#9650;</span>" +
12869
+ "</a>" +
12870
+ "<a class='ui-spinner-button ui-spinner-down ui-corner-br'>" +
12871
+ "<span class='ui-icon " + this.options.icons.down + "'>&#9660;</span>" +
12872
+ "</a>";
12873
+ },
12874
+
12875
+ _start: function( event ) {
12876
+ if ( !this.spinning && this._trigger( "start", event ) === false ) {
12877
+ return false;
12878
+ }
12879
+
12880
+ if ( !this.counter ) {
12881
+ this.counter = 1;
12882
+ }
12883
+ this.spinning = true;
12884
+ return true;
12885
+ },
12886
+
12887
+ _repeat: function( i, steps, event ) {
12888
+ i = i || 500;
12889
+
12890
+ clearTimeout( this.timer );
12891
+ this.timer = this._delay(function() {
12892
+ this._repeat( 40, steps, event );
12893
+ }, i );
12894
+
12895
+ this._spin( steps * this.options.step, event );
12896
+ },
12897
+
12898
+ _spin: function( step, event ) {
12899
+ var value = this.value() || 0;
12900
+
12901
+ if ( !this.counter ) {
12902
+ this.counter = 1;
12903
+ }
12904
+
12905
+ value = this._adjustValue( value + step * this._increment( this.counter ) );
12906
+
12907
+ if ( !this.spinning || this._trigger( "spin", event, { value: value } ) !== false) {
12908
+ this._value( value );
12909
+ this.counter++;
12910
+ }
12911
+ },
12912
+
12913
+ _increment: function( i ) {
12914
+ var incremental = this.options.incremental;
12915
+
12916
+ if ( incremental ) {
12917
+ return $.isFunction( incremental ) ?
12918
+ incremental( i ) :
12919
+ Math.floor( i*i*i/50000 - i*i/500 + 17*i/200 + 1 );
12920
+ }
12921
+
12922
+ return 1;
12923
+ },
12924
+
12925
+ _precision: function() {
12926
+ var precision = this._precisionOf( this.options.step );
12927
+ if ( this.options.min !== null ) {
12928
+ precision = Math.max( precision, this._precisionOf( this.options.min ) );
12929
+ }
12930
+ return precision;
12931
+ },
12932
+
12933
+ _precisionOf: function( num ) {
12934
+ var str = num.toString(),
12935
+ decimal = str.indexOf( "." );
12936
+ return decimal === -1 ? 0 : str.length - decimal - 1;
12937
+ },
12938
+
12939
+ _adjustValue: function( value ) {
12940
+ var base, aboveMin,
12941
+ options = this.options;
12942
+
12943
+ // make sure we're at a valid step
12944
+ // - find out where we are relative to the base (min or 0)
12945
+ base = options.min !== null ? options.min : 0;
12946
+ aboveMin = value - base;
12947
+ // - round to the nearest step
12948
+ aboveMin = Math.round(aboveMin / options.step) * options.step;
12949
+ // - rounding is based on 0, so adjust back to our base
12950
+ value = base + aboveMin;
12951
+
12952
+ // fix precision from bad JS floating point math
12953
+ value = parseFloat( value.toFixed( this._precision() ) );
12954
+
12955
+ // clamp the value
12956
+ if ( options.max !== null && value > options.max) {
12957
+ return options.max;
12958
+ }
12959
+ if ( options.min !== null && value < options.min ) {
12960
+ return options.min;
12961
+ }
12962
+
12963
+ return value;
12964
+ },
12965
+
12966
+ _stop: function( event ) {
12967
+ if ( !this.spinning ) {
12968
+ return;
12969
+ }
12970
+
12971
+ clearTimeout( this.timer );
12972
+ clearTimeout( this.mousewheelTimer );
12973
+ this.counter = 0;
12974
+ this.spinning = false;
12975
+ this._trigger( "stop", event );
12976
+ },
12977
+
12978
+ _setOption: function( key, value ) {
12979
+ if ( key === "culture" || key === "numberFormat" ) {
12980
+ var prevValue = this._parse( this.element.val() );
12981
+ this.options[ key ] = value;
12982
+ this.element.val( this._format( prevValue ) );
12983
+ return;
12984
+ }
12985
+
12986
+ if ( key === "max" || key === "min" || key === "step" ) {
12987
+ if ( typeof value === "string" ) {
12988
+ value = this._parse( value );
12989
+ }
12990
+ }
12991
+
12992
+ this._super( key, value );
12993
+
12994
+ if ( key === "disabled" ) {
12995
+ if ( value ) {
12996
+ this.element.prop( "disabled", true );
12997
+ this.buttons.button( "disable" );
12998
+ } else {
12999
+ this.element.prop( "disabled", false );
13000
+ this.buttons.button( "enable" );
13001
+ }
13002
+ }
13003
+ },
13004
+
13005
+ _setOptions: modifier(function( options ) {
13006
+ this._super( options );
13007
+ this._value( this.element.val() );
13008
+ }),
13009
+
13010
+ _parse: function( val ) {
13011
+ if ( typeof val === "string" && val !== "" ) {
13012
+ val = window.Globalize && this.options.numberFormat ?
13013
+ Globalize.parseFloat( val, 10, this.options.culture ) : +val;
13014
+ }
13015
+ return val === "" || isNaN( val ) ? null : val;
13016
+ },
13017
+
13018
+ _format: function( value ) {
13019
+ if ( value === "" ) {
13020
+ return "";
13021
+ }
13022
+ return window.Globalize && this.options.numberFormat ?
13023
+ Globalize.format( value, this.options.numberFormat, this.options.culture ) :
13024
+ value;
13025
+ },
13026
+
13027
+ _refresh: function() {
13028
+ this.element.attr({
13029
+ "aria-valuemin": this.options.min,
13030
+ "aria-valuemax": this.options.max,
13031
+ // TODO: what should we do with values that can't be parsed?
13032
+ "aria-valuenow": this._parse( this.element.val() )
13033
+ });
13034
+ },
13035
+
13036
+ // update the value without triggering change
13037
+ _value: function( value, allowAny ) {
13038
+ var parsed;
13039
+ if ( value !== "" ) {
13040
+ parsed = this._parse( value );
13041
+ if ( parsed !== null ) {
13042
+ if ( !allowAny ) {
13043
+ parsed = this._adjustValue( parsed );
13044
+ }
13045
+ value = this._format( parsed );
13046
+ }
13047
+ }
13048
+ this.element.val( value );
13049
+ this._refresh();
13050
+ },
13051
+
13052
+ _destroy: function() {
13053
+ this.element
13054
+ .removeClass( "ui-spinner-input" )
13055
+ .prop( "disabled", false )
13056
+ .removeAttr( "autocomplete" )
13057
+ .removeAttr( "role" )
13058
+ .removeAttr( "aria-valuemin" )
13059
+ .removeAttr( "aria-valuemax" )
13060
+ .removeAttr( "aria-valuenow" );
13061
+ this.uiSpinner.replaceWith( this.element );
13062
+ },
13063
+
13064
+ stepUp: modifier(function( steps ) {
13065
+ this._stepUp( steps );
13066
+ }),
13067
+ _stepUp: function( steps ) {
13068
+ this._spin( (steps || 1) * this.options.step );
13069
+ },
13070
+
13071
+ stepDown: modifier(function( steps ) {
13072
+ this._stepDown( steps );
13073
+ }),
13074
+ _stepDown: function( steps ) {
13075
+ this._spin( (steps || 1) * -this.options.step );
13076
+ },
13077
+
13078
+ pageUp: modifier(function( pages ) {
13079
+ this._stepUp( (pages || 1) * this.options.page );
13080
+ }),
13081
+
13082
+ pageDown: modifier(function( pages ) {
13083
+ this._stepDown( (pages || 1) * this.options.page );
13084
+ }),
13085
+
13086
+ value: function( newVal ) {
13087
+ if ( !arguments.length ) {
13088
+ return this._parse( this.element.val() );
13089
+ }
13090
+ modifier( this._value ).call( this, newVal );
13091
+ },
13092
+
13093
+ widget: function() {
13094
+ return this.uiSpinner;
13095
+ }
13096
+ });
13097
+
13098
+ }( jQuery ) );
13099
+ (function( $, undefined ) {
13100
+
13101
+ var tabId = 0,
13102
+ rhash = /#.*$/;
13103
+
13104
+ function getNextTabId() {
13105
+ return ++tabId;
13106
+ }
13107
+
13108
+ function isLocal( anchor ) {
13109
+ return anchor.hash.length > 1 &&
13110
+ anchor.href.replace( rhash, "" ) === location.href.replace( rhash, "" );
13111
+ }
13112
+
13113
+ $.widget( "ui.tabs", {
13114
+ version: "1.9.1",
13115
+ delay: 300,
13116
+ options: {
13117
+ active: null,
13118
+ collapsible: false,
13119
+ event: "click",
13120
+ heightStyle: "content",
13121
+ hide: null,
13122
+ show: null,
13123
+
13124
+ // callbacks
13125
+ activate: null,
13126
+ beforeActivate: null,
13127
+ beforeLoad: null,
13128
+ load: null
13129
+ },
13130
+
13131
+ _create: function() {
13132
+ var that = this,
13133
+ options = this.options,
13134
+ active = options.active,
13135
+ locationHash = location.hash.substring( 1 );
13136
+
13137
+ this.running = false;
13138
+
13139
+ this.element
13140
+ .addClass( "ui-tabs ui-widget ui-widget-content ui-corner-all" )
13141
+ .toggleClass( "ui-tabs-collapsible", options.collapsible )
13142
+ // Prevent users from focusing disabled tabs via click
13143
+ .delegate( ".ui-tabs-nav > li", "mousedown" + this.eventNamespace, function( event ) {
13144
+ if ( $( this ).is( ".ui-state-disabled" ) ) {
13145
+ event.preventDefault();
13146
+ }
13147
+ })
13148
+ // support: IE <9
13149
+ // Preventing the default action in mousedown doesn't prevent IE
13150
+ // from focusing the element, so if the anchor gets focused, blur.
13151
+ // We don't have to worry about focusing the previously focused
13152
+ // element since clicking on a non-focusable element should focus
13153
+ // the body anyway.
13154
+ .delegate( ".ui-tabs-anchor", "focus" + this.eventNamespace, function() {
13155
+ if ( $( this ).closest( "li" ).is( ".ui-state-disabled" ) ) {
13156
+ this.blur();
13157
+ }
13158
+ });
13159
+
13160
+ this._processTabs();
13161
+
13162
+ if ( active === null ) {
13163
+ // check the fragment identifier in the URL
13164
+ if ( locationHash ) {
13165
+ this.tabs.each(function( i, tab ) {
13166
+ if ( $( tab ).attr( "aria-controls" ) === locationHash ) {
13167
+ active = i;
13168
+ return false;
13169
+ }
13170
+ });
13171
+ }
13172
+
13173
+ // check for a tab marked active via a class
13174
+ if ( active === null ) {
13175
+ active = this.tabs.index( this.tabs.filter( ".ui-tabs-active" ) );
13176
+ }
13177
+
13178
+ // no active tab, set to false
13179
+ if ( active === null || active === -1 ) {
13180
+ active = this.tabs.length ? 0 : false;
13181
+ }
13182
+ }
13183
+
13184
+ // handle numbers: negative, out of range
13185
+ if ( active !== false ) {
13186
+ active = this.tabs.index( this.tabs.eq( active ) );
13187
+ if ( active === -1 ) {
13188
+ active = options.collapsible ? false : 0;
13189
+ }
13190
+ }
13191
+ options.active = active;
13192
+
13193
+ // don't allow collapsible: false and active: false
13194
+ if ( !options.collapsible && options.active === false && this.anchors.length ) {
13195
+ options.active = 0;
13196
+ }
13197
+
13198
+ // Take disabling tabs via class attribute from HTML
13199
+ // into account and update option properly.
13200
+ if ( $.isArray( options.disabled ) ) {
13201
+ options.disabled = $.unique( options.disabled.concat(
13202
+ $.map( this.tabs.filter( ".ui-state-disabled" ), function( li ) {
13203
+ return that.tabs.index( li );
13204
+ })
13205
+ ) ).sort();
13206
+ }
13207
+
13208
+ // check for length avoids error when initializing empty list
13209
+ if ( this.options.active !== false && this.anchors.length ) {
13210
+ this.active = this._findActive( this.options.active );
13211
+ } else {
13212
+ this.active = $();
13213
+ }
13214
+
13215
+ this._refresh();
13216
+
13217
+ if ( this.active.length ) {
13218
+ this.load( options.active );
13219
+ }
13220
+ },
13221
+
13222
+ _getCreateEventData: function() {
13223
+ return {
13224
+ tab: this.active,
13225
+ panel: !this.active.length ? $() : this._getPanelForTab( this.active )
13226
+ };
13227
+ },
13228
+
13229
+ _tabKeydown: function( event ) {
13230
+ var focusedTab = $( this.document[0].activeElement ).closest( "li" ),
13231
+ selectedIndex = this.tabs.index( focusedTab ),
13232
+ goingForward = true;
13233
+
13234
+ if ( this._handlePageNav( event ) ) {
13235
+ return;
13236
+ }
13237
+
13238
+ switch ( event.keyCode ) {
13239
+ case $.ui.keyCode.RIGHT:
13240
+ case $.ui.keyCode.DOWN:
13241
+ selectedIndex++;
13242
+ break;
13243
+ case $.ui.keyCode.UP:
13244
+ case $.ui.keyCode.LEFT:
13245
+ goingForward = false;
13246
+ selectedIndex--;
13247
+ break;
13248
+ case $.ui.keyCode.END:
13249
+ selectedIndex = this.anchors.length - 1;
13250
+ break;
13251
+ case $.ui.keyCode.HOME:
13252
+ selectedIndex = 0;
13253
+ break;
13254
+ case $.ui.keyCode.SPACE:
13255
+ // Activate only, no collapsing
13256
+ event.preventDefault();
13257
+ clearTimeout( this.activating );
13258
+ this._activate( selectedIndex );
13259
+ return;
13260
+ case $.ui.keyCode.ENTER:
13261
+ // Toggle (cancel delayed activation, allow collapsing)
13262
+ event.preventDefault();
13263
+ clearTimeout( this.activating );
13264
+ // Determine if we should collapse or activate
13265
+ this._activate( selectedIndex === this.options.active ? false : selectedIndex );
13266
+ return;
13267
+ default:
13268
+ return;
13269
+ }
13270
+
13271
+ // Focus the appropriate tab, based on which key was pressed
13272
+ event.preventDefault();
13273
+ clearTimeout( this.activating );
13274
+ selectedIndex = this._focusNextTab( selectedIndex, goingForward );
13275
+
13276
+ // Navigating with control key will prevent automatic activation
13277
+ if ( !event.ctrlKey ) {
13278
+ // Update aria-selected immediately so that AT think the tab is already selected.
13279
+ // Otherwise AT may confuse the user by stating that they need to activate the tab,
13280
+ // but the tab will already be activated by the time the announcement finishes.
13281
+ focusedTab.attr( "aria-selected", "false" );
13282
+ this.tabs.eq( selectedIndex ).attr( "aria-selected", "true" );
13283
+
13284
+ this.activating = this._delay(function() {
13285
+ this.option( "active", selectedIndex );
13286
+ }, this.delay );
13287
+ }
13288
+ },
13289
+
13290
+ _panelKeydown: function( event ) {
13291
+ if ( this._handlePageNav( event ) ) {
13292
+ return;
13293
+ }
13294
+
13295
+ // Ctrl+up moves focus to the current tab
13296
+ if ( event.ctrlKey && event.keyCode === $.ui.keyCode.UP ) {
13297
+ event.preventDefault();
13298
+ this.active.focus();
13299
+ }
13300
+ },
13301
+
13302
+ // Alt+page up/down moves focus to the previous/next tab (and activates)
13303
+ _handlePageNav: function( event ) {
13304
+ if ( event.altKey && event.keyCode === $.ui.keyCode.PAGE_UP ) {
13305
+ this._activate( this._focusNextTab( this.options.active - 1, false ) );
13306
+ return true;
13307
+ }
13308
+ if ( event.altKey && event.keyCode === $.ui.keyCode.PAGE_DOWN ) {
13309
+ this._activate( this._focusNextTab( this.options.active + 1, true ) );
13310
+ return true;
13311
+ }
13312
+ },
13313
+
13314
+ _findNextTab: function( index, goingForward ) {
13315
+ var lastTabIndex = this.tabs.length - 1;
13316
+
13317
+ function constrain() {
13318
+ if ( index > lastTabIndex ) {
13319
+ index = 0;
13320
+ }
13321
+ if ( index < 0 ) {
13322
+ index = lastTabIndex;
13323
+ }
13324
+ return index;
13325
+ }
13326
+
13327
+ while ( $.inArray( constrain(), this.options.disabled ) !== -1 ) {
13328
+ index = goingForward ? index + 1 : index - 1;
13329
+ }
13330
+
13331
+ return index;
13332
+ },
13333
+
13334
+ _focusNextTab: function( index, goingForward ) {
13335
+ index = this._findNextTab( index, goingForward );
13336
+ this.tabs.eq( index ).focus();
13337
+ return index;
13338
+ },
13339
+
13340
+ _setOption: function( key, value ) {
13341
+ if ( key === "active" ) {
13342
+ // _activate() will handle invalid values and update this.options
13343
+ this._activate( value );
13344
+ return;
13345
+ }
13346
+
13347
+ if ( key === "disabled" ) {
13348
+ // don't use the widget factory's disabled handling
13349
+ this._setupDisabled( value );
13350
+ return;
13351
+ }
13352
+
13353
+ this._super( key, value);
13354
+
13355
+ if ( key === "collapsible" ) {
13356
+ this.element.toggleClass( "ui-tabs-collapsible", value );
13357
+ // Setting collapsible: false while collapsed; open first panel
13358
+ if ( !value && this.options.active === false ) {
13359
+ this._activate( 0 );
13360
+ }
13361
+ }
13362
+
13363
+ if ( key === "event" ) {
13364
+ this._setupEvents( value );
13365
+ }
13366
+
13367
+ if ( key === "heightStyle" ) {
13368
+ this._setupHeightStyle( value );
13369
+ }
13370
+ },
13371
+
13372
+ _tabId: function( tab ) {
13373
+ return tab.attr( "aria-controls" ) || "ui-tabs-" + getNextTabId();
13374
+ },
13375
+
13376
+ _sanitizeSelector: function( hash ) {
13377
+ return hash ? hash.replace( /[!"$%&'()*+,.\/:;<=>?@\[\]\^`{|}~]/g, "\\$&" ) : "";
13378
+ },
13379
+
13380
+ refresh: function() {
13381
+ var options = this.options,
13382
+ lis = this.tablist.children( ":has(a[href])" );
13383
+
13384
+ // get disabled tabs from class attribute from HTML
13385
+ // this will get converted to a boolean if needed in _refresh()
13386
+ options.disabled = $.map( lis.filter( ".ui-state-disabled" ), function( tab ) {
13387
+ return lis.index( tab );
13388
+ });
13389
+
13390
+ this._processTabs();
13391
+
13392
+ // was collapsed or no tabs
13393
+ if ( options.active === false || !this.anchors.length ) {
13394
+ options.active = false;
13395
+ this.active = $();
13396
+ // was active, but active tab is gone
13397
+ } else if ( this.active.length && !$.contains( this.tablist[ 0 ], this.active[ 0 ] ) ) {
13398
+ // all remaining tabs are disabled
13399
+ if ( this.tabs.length === options.disabled.length ) {
13400
+ options.active = false;
13401
+ this.active = $();
13402
+ // activate previous tab
13403
+ } else {
13404
+ this._activate( this._findNextTab( Math.max( 0, options.active - 1 ), false ) );
13405
+ }
13406
+ // was active, active tab still exists
13407
+ } else {
13408
+ // make sure active index is correct
13409
+ options.active = this.tabs.index( this.active );
13410
+ }
13411
+
13412
+ this._refresh();
13413
+ },
13414
+
13415
+ _refresh: function() {
13416
+ this._setupDisabled( this.options.disabled );
13417
+ this._setupEvents( this.options.event );
13418
+ this._setupHeightStyle( this.options.heightStyle );
13419
+
13420
+ this.tabs.not( this.active ).attr({
13421
+ "aria-selected": "false",
13422
+ tabIndex: -1
13423
+ });
13424
+ this.panels.not( this._getPanelForTab( this.active ) )
13425
+ .hide()
13426
+ .attr({
13427
+ "aria-expanded": "false",
13428
+ "aria-hidden": "true"
13429
+ });
13430
+
13431
+ // Make sure one tab is in the tab order
13432
+ if ( !this.active.length ) {
13433
+ this.tabs.eq( 0 ).attr( "tabIndex", 0 );
13434
+ } else {
13435
+ this.active
13436
+ .addClass( "ui-tabs-active ui-state-active" )
13437
+ .attr({
13438
+ "aria-selected": "true",
13439
+ tabIndex: 0
13440
+ });
13441
+ this._getPanelForTab( this.active )
13442
+ .show()
13443
+ .attr({
13444
+ "aria-expanded": "true",
13445
+ "aria-hidden": "false"
13446
+ });
13447
+ }
13448
+ },
13449
+
13450
+ _processTabs: function() {
13451
+ var that = this;
13452
+
13453
+ this.tablist = this._getList()
13454
+ .addClass( "ui-tabs-nav ui-helper-reset ui-helper-clearfix ui-widget-header ui-corner-all" )
13455
+ .attr( "role", "tablist" );
13456
+
13457
+ this.tabs = this.tablist.find( "> li:has(a[href])" )
13458
+ .addClass( "ui-state-default ui-corner-top" )
13459
+ .attr({
13460
+ role: "tab",
13461
+ tabIndex: -1
13462
+ });
13463
+
13464
+ this.anchors = this.tabs.map(function() {
13465
+ return $( "a", this )[ 0 ];
13466
+ })
13467
+ .addClass( "ui-tabs-anchor" )
13468
+ .attr({
13469
+ role: "presentation",
13470
+ tabIndex: -1
13471
+ });
13472
+
13473
+ this.panels = $();
13474
+
13475
+ this.anchors.each(function( i, anchor ) {
13476
+ var selector, panel, panelId,
13477
+ anchorId = $( anchor ).uniqueId().attr( "id" ),
13478
+ tab = $( anchor ).closest( "li" ),
13479
+ originalAriaControls = tab.attr( "aria-controls" );
13480
+
13481
+ // inline tab
13482
+ if ( isLocal( anchor ) ) {
13483
+ selector = anchor.hash;
13484
+ panel = that.element.find( that._sanitizeSelector( selector ) );
13485
+ // remote tab
13486
+ } else {
13487
+ panelId = that._tabId( tab );
13488
+ selector = "#" + panelId;
13489
+ panel = that.element.find( selector );
13490
+ if ( !panel.length ) {
13491
+ panel = that._createPanel( panelId );
13492
+ panel.insertAfter( that.panels[ i - 1 ] || that.tablist );
13493
+ }
13494
+ panel.attr( "aria-live", "polite" );
13495
+ }
13496
+
13497
+ if ( panel.length) {
13498
+ that.panels = that.panels.add( panel );
13499
+ }
13500
+ if ( originalAriaControls ) {
13501
+ tab.data( "ui-tabs-aria-controls", originalAriaControls );
13502
+ }
13503
+ tab.attr({
13504
+ "aria-controls": selector.substring( 1 ),
13505
+ "aria-labelledby": anchorId
13506
+ });
13507
+ panel.attr( "aria-labelledby", anchorId );
13508
+ });
13509
+
13510
+ this.panels
13511
+ .addClass( "ui-tabs-panel ui-widget-content ui-corner-bottom" )
13512
+ .attr( "role", "tabpanel" );
13513
+ },
13514
+
13515
+ // allow overriding how to find the list for rare usage scenarios (#7715)
13516
+ _getList: function() {
13517
+ return this.element.find( "ol,ul" ).eq( 0 );
13518
+ },
13519
+
13520
+ _createPanel: function( id ) {
13521
+ return $( "<div>" )
13522
+ .attr( "id", id )
13523
+ .addClass( "ui-tabs-panel ui-widget-content ui-corner-bottom" )
13524
+ .data( "ui-tabs-destroy", true );
13525
+ },
13526
+
13527
+ _setupDisabled: function( disabled ) {
13528
+ if ( $.isArray( disabled ) ) {
13529
+ if ( !disabled.length ) {
13530
+ disabled = false;
13531
+ } else if ( disabled.length === this.anchors.length ) {
13532
+ disabled = true;
13533
+ }
13534
+ }
13535
+
13536
+ // disable tabs
13537
+ for ( var i = 0, li; ( li = this.tabs[ i ] ); i++ ) {
13538
+ if ( disabled === true || $.inArray( i, disabled ) !== -1 ) {
13539
+ $( li )
13540
+ .addClass( "ui-state-disabled" )
13541
+ .attr( "aria-disabled", "true" );
13542
+ } else {
13543
+ $( li )
13544
+ .removeClass( "ui-state-disabled" )
13545
+ .removeAttr( "aria-disabled" );
13546
+ }
13547
+ }
13548
+
13549
+ this.options.disabled = disabled;
13550
+ },
13551
+
13552
+ _setupEvents: function( event ) {
13553
+ var events = {
13554
+ click: function( event ) {
13555
+ event.preventDefault();
13556
+ }
13557
+ };
13558
+ if ( event ) {
13559
+ $.each( event.split(" "), function( index, eventName ) {
13560
+ events[ eventName ] = "_eventHandler";
13561
+ });
13562
+ }
13563
+
13564
+ this._off( this.anchors.add( this.tabs ).add( this.panels ) );
13565
+ this._on( this.anchors, events );
13566
+ this._on( this.tabs, { keydown: "_tabKeydown" } );
13567
+ this._on( this.panels, { keydown: "_panelKeydown" } );
13568
+
13569
+ this._focusable( this.tabs );
13570
+ this._hoverable( this.tabs );
13571
+ },
13572
+
13573
+ _setupHeightStyle: function( heightStyle ) {
13574
+ var maxHeight, overflow,
13575
+ parent = this.element.parent();
13576
+
13577
+ if ( heightStyle === "fill" ) {
13578
+ // IE 6 treats height like minHeight, so we need to turn off overflow
13579
+ // in order to get a reliable height
13580
+ // we use the minHeight support test because we assume that only
13581
+ // browsers that don't support minHeight will treat height as minHeight
13582
+ if ( !$.support.minHeight ) {
13583
+ overflow = parent.css( "overflow" );
13584
+ parent.css( "overflow", "hidden");
13585
+ }
13586
+ maxHeight = parent.height();
13587
+ this.element.siblings( ":visible" ).each(function() {
13588
+ var elem = $( this ),
13589
+ position = elem.css( "position" );
13590
+
13591
+ if ( position === "absolute" || position === "fixed" ) {
13592
+ return;
13593
+ }
13594
+ maxHeight -= elem.outerHeight( true );
13595
+ });
13596
+ if ( overflow ) {
13597
+ parent.css( "overflow", overflow );
13598
+ }
13599
+
13600
+ this.element.children().not( this.panels ).each(function() {
13601
+ maxHeight -= $( this ).outerHeight( true );
13602
+ });
13603
+
13604
+ this.panels.each(function() {
13605
+ $( this ).height( Math.max( 0, maxHeight -
13606
+ $( this ).innerHeight() + $( this ).height() ) );
13607
+ })
13608
+ .css( "overflow", "auto" );
13609
+ } else if ( heightStyle === "auto" ) {
13610
+ maxHeight = 0;
13611
+ this.panels.each(function() {
13612
+ maxHeight = Math.max( maxHeight, $( this ).height( "" ).height() );
13613
+ }).height( maxHeight );
13614
+ }
13615
+ },
13616
+
13617
+ _eventHandler: function( event ) {
13618
+ var options = this.options,
13619
+ active = this.active,
13620
+ anchor = $( event.currentTarget ),
13621
+ tab = anchor.closest( "li" ),
13622
+ clickedIsActive = tab[ 0 ] === active[ 0 ],
13623
+ collapsing = clickedIsActive && options.collapsible,
13624
+ toShow = collapsing ? $() : this._getPanelForTab( tab ),
13625
+ toHide = !active.length ? $() : this._getPanelForTab( active ),
13626
+ eventData = {
13627
+ oldTab: active,
13628
+ oldPanel: toHide,
13629
+ newTab: collapsing ? $() : tab,
13630
+ newPanel: toShow
13631
+ };
13632
+
13633
+ event.preventDefault();
13634
+
13635
+ if ( tab.hasClass( "ui-state-disabled" ) ||
13636
+ // tab is already loading
13637
+ tab.hasClass( "ui-tabs-loading" ) ||
13638
+ // can't switch durning an animation
13639
+ this.running ||
13640
+ // click on active header, but not collapsible
13641
+ ( clickedIsActive && !options.collapsible ) ||
13642
+ // allow canceling activation
13643
+ ( this._trigger( "beforeActivate", event, eventData ) === false ) ) {
13644
+ return;
13645
+ }
13646
+
13647
+ options.active = collapsing ? false : this.tabs.index( tab );
13648
+
13649
+ this.active = clickedIsActive ? $() : tab;
13650
+ if ( this.xhr ) {
13651
+ this.xhr.abort();
13652
+ }
13653
+
13654
+ if ( !toHide.length && !toShow.length ) {
13655
+ $.error( "jQuery UI Tabs: Mismatching fragment identifier." );
13656
+ }
13657
+
13658
+ if ( toShow.length ) {
13659
+ this.load( this.tabs.index( tab ), event );
13660
+ }
13661
+ this._toggle( event, eventData );
13662
+ },
13663
+
13664
+ // handles show/hide for selecting tabs
13665
+ _toggle: function( event, eventData ) {
13666
+ var that = this,
13667
+ toShow = eventData.newPanel,
13668
+ toHide = eventData.oldPanel;
13669
+
13670
+ this.running = true;
13671
+
13672
+ function complete() {
13673
+ that.running = false;
13674
+ that._trigger( "activate", event, eventData );
13675
+ }
13676
+
13677
+ function show() {
13678
+ eventData.newTab.closest( "li" ).addClass( "ui-tabs-active ui-state-active" );
13679
+
13680
+ if ( toShow.length && that.options.show ) {
13681
+ that._show( toShow, that.options.show, complete );
13682
+ } else {
13683
+ toShow.show();
13684
+ complete();
13685
+ }
13686
+ }
13687
+
13688
+ // start out by hiding, then showing, then completing
13689
+ if ( toHide.length && this.options.hide ) {
13690
+ this._hide( toHide, this.options.hide, function() {
13691
+ eventData.oldTab.closest( "li" ).removeClass( "ui-tabs-active ui-state-active" );
13692
+ show();
13693
+ });
13694
+ } else {
13695
+ eventData.oldTab.closest( "li" ).removeClass( "ui-tabs-active ui-state-active" );
13696
+ toHide.hide();
13697
+ show();
13698
+ }
13699
+
13700
+ toHide.attr({
13701
+ "aria-expanded": "false",
13702
+ "aria-hidden": "true"
13703
+ });
13704
+ eventData.oldTab.attr( "aria-selected", "false" );
13705
+ // If we're switching tabs, remove the old tab from the tab order.
13706
+ // If we're opening from collapsed state, remove the previous tab from the tab order.
13707
+ // If we're collapsing, then keep the collapsing tab in the tab order.
13708
+ if ( toShow.length && toHide.length ) {
13709
+ eventData.oldTab.attr( "tabIndex", -1 );
13710
+ } else if ( toShow.length ) {
13711
+ this.tabs.filter(function() {
13712
+ return $( this ).attr( "tabIndex" ) === 0;
13713
+ })
13714
+ .attr( "tabIndex", -1 );
13715
+ }
13716
+
13717
+ toShow.attr({
13718
+ "aria-expanded": "true",
13719
+ "aria-hidden": "false"
13720
+ });
13721
+ eventData.newTab.attr({
13722
+ "aria-selected": "true",
13723
+ tabIndex: 0
13724
+ });
13725
+ },
13726
+
13727
+ _activate: function( index ) {
13728
+ var anchor,
13729
+ active = this._findActive( index );
13730
+
13731
+ // trying to activate the already active panel
13732
+ if ( active[ 0 ] === this.active[ 0 ] ) {
13733
+ return;
13734
+ }
13735
+
13736
+ // trying to collapse, simulate a click on the current active header
13737
+ if ( !active.length ) {
13738
+ active = this.active;
13739
+ }
13740
+
13741
+ anchor = active.find( ".ui-tabs-anchor" )[ 0 ];
13742
+ this._eventHandler({
13743
+ target: anchor,
13744
+ currentTarget: anchor,
13745
+ preventDefault: $.noop
13746
+ });
13747
+ },
13748
+
13749
+ _findActive: function( index ) {
13750
+ return index === false ? $() : this.tabs.eq( index );
13751
+ },
13752
+
13753
+ _getIndex: function( index ) {
13754
+ // meta-function to give users option to provide a href string instead of a numerical index.
13755
+ if ( typeof index === "string" ) {
13756
+ index = this.anchors.index( this.anchors.filter( "[href$='" + index + "']" ) );
13757
+ }
13758
+
13759
+ return index;
13760
+ },
13761
+
13762
+ _destroy: function() {
13763
+ if ( this.xhr ) {
13764
+ this.xhr.abort();
13765
+ }
13766
+
13767
+ this.element.removeClass( "ui-tabs ui-widget ui-widget-content ui-corner-all ui-tabs-collapsible" );
13768
+
13769
+ this.tablist
13770
+ .removeClass( "ui-tabs-nav ui-helper-reset ui-helper-clearfix ui-widget-header ui-corner-all" )
13771
+ .removeAttr( "role" );
13772
+
13773
+ this.anchors
13774
+ .removeClass( "ui-tabs-anchor" )
13775
+ .removeAttr( "role" )
13776
+ .removeAttr( "tabIndex" )
13777
+ .removeData( "href.tabs" )
13778
+ .removeData( "load.tabs" )
13779
+ .removeUniqueId();
13780
+
13781
+ this.tabs.add( this.panels ).each(function() {
13782
+ if ( $.data( this, "ui-tabs-destroy" ) ) {
13783
+ $( this ).remove();
13784
+ } else {
13785
+ $( this )
13786
+ .removeClass( "ui-state-default ui-state-active ui-state-disabled " +
13787
+ "ui-corner-top ui-corner-bottom ui-widget-content ui-tabs-active ui-tabs-panel" )
13788
+ .removeAttr( "tabIndex" )
13789
+ .removeAttr( "aria-live" )
13790
+ .removeAttr( "aria-busy" )
13791
+ .removeAttr( "aria-selected" )
13792
+ .removeAttr( "aria-labelledby" )
13793
+ .removeAttr( "aria-hidden" )
13794
+ .removeAttr( "aria-expanded" )
13795
+ .removeAttr( "role" );
13796
+ }
13797
+ });
13798
+
13799
+ this.tabs.each(function() {
13800
+ var li = $( this ),
13801
+ prev = li.data( "ui-tabs-aria-controls" );
13802
+ if ( prev ) {
13803
+ li.attr( "aria-controls", prev );
13804
+ } else {
13805
+ li.removeAttr( "aria-controls" );
13806
+ }
13807
+ });
13808
+
13809
+ if ( this.options.heightStyle !== "content" ) {
13810
+ this.panels.css( "height", "" );
13811
+ }
13812
+ },
13813
+
13814
+ enable: function( index ) {
13815
+ var disabled = this.options.disabled;
13816
+ if ( disabled === false ) {
13817
+ return;
13818
+ }
13819
+
13820
+ if ( index === undefined ) {
13821
+ disabled = false;
13822
+ } else {
13823
+ index = this._getIndex( index );
13824
+ if ( $.isArray( disabled ) ) {
13825
+ disabled = $.map( disabled, function( num ) {
13826
+ return num !== index ? num : null;
13827
+ });
13828
+ } else {
13829
+ disabled = $.map( this.tabs, function( li, num ) {
13830
+ return num !== index ? num : null;
13831
+ });
13832
+ }
13833
+ }
13834
+ this._setupDisabled( disabled );
13835
+ },
13836
+
13837
+ disable: function( index ) {
13838
+ var disabled = this.options.disabled;
13839
+ if ( disabled === true ) {
13840
+ return;
13841
+ }
13842
+
13843
+ if ( index === undefined ) {
13844
+ disabled = true;
13845
+ } else {
13846
+ index = this._getIndex( index );
13847
+ if ( $.inArray( index, disabled ) !== -1 ) {
13848
+ return;
13849
+ }
13850
+ if ( $.isArray( disabled ) ) {
13851
+ disabled = $.merge( [ index ], disabled ).sort();
13852
+ } else {
13853
+ disabled = [ index ];
13854
+ }
13855
+ }
13856
+ this._setupDisabled( disabled );
13857
+ },
13858
+
13859
+ load: function( index, event ) {
13860
+ index = this._getIndex( index );
13861
+ var that = this,
13862
+ tab = this.tabs.eq( index ),
13863
+ anchor = tab.find( ".ui-tabs-anchor" ),
13864
+ panel = this._getPanelForTab( tab ),
13865
+ eventData = {
13866
+ tab: tab,
13867
+ panel: panel
13868
+ };
13869
+
13870
+ // not remote
13871
+ if ( isLocal( anchor[ 0 ] ) ) {
13872
+ return;
13873
+ }
13874
+
13875
+ this.xhr = $.ajax( this._ajaxSettings( anchor, event, eventData ) );
13876
+
13877
+ // support: jQuery <1.8
13878
+ // jQuery <1.8 returns false if the request is canceled in beforeSend,
13879
+ // but as of 1.8, $.ajax() always returns a jqXHR object.
13880
+ if ( this.xhr && this.xhr.statusText !== "canceled" ) {
13881
+ tab.addClass( "ui-tabs-loading" );
13882
+ panel.attr( "aria-busy", "true" );
13883
+
13884
+ this.xhr
13885
+ .success(function( response ) {
13886
+ // support: jQuery <1.8
13887
+ // http://bugs.jquery.com/ticket/11778
13888
+ setTimeout(function() {
13889
+ panel.html( response );
13890
+ that._trigger( "load", event, eventData );
13891
+ }, 1 );
13892
+ })
13893
+ .complete(function( jqXHR, status ) {
13894
+ // support: jQuery <1.8
13895
+ // http://bugs.jquery.com/ticket/11778
13896
+ setTimeout(function() {
13897
+ if ( status === "abort" ) {
13898
+ that.panels.stop( false, true );
13899
+ }
13900
+
13901
+ tab.removeClass( "ui-tabs-loading" );
13902
+ panel.removeAttr( "aria-busy" );
13903
+
13904
+ if ( jqXHR === that.xhr ) {
13905
+ delete that.xhr;
13906
+ }
13907
+ }, 1 );
13908
+ });
13909
+ }
13910
+ },
13911
+
13912
+ // TODO: Remove this function in 1.10 when ajaxOptions is removed
13913
+ _ajaxSettings: function( anchor, event, eventData ) {
13914
+ var that = this;
13915
+ return {
13916
+ url: anchor.attr( "href" ),
13917
+ beforeSend: function( jqXHR, settings ) {
13918
+ return that._trigger( "beforeLoad", event,
13919
+ $.extend( { jqXHR : jqXHR, ajaxSettings: settings }, eventData ) );
13920
+ }
13921
+ };
13922
+ },
13923
+
13924
+ _getPanelForTab: function( tab ) {
13925
+ var id = $( tab ).attr( "aria-controls" );
13926
+ return this.element.find( this._sanitizeSelector( "#" + id ) );
13927
+ }
13928
+ });
13929
+
13930
+ // DEPRECATED
13931
+ if ( $.uiBackCompat !== false ) {
13932
+
13933
+ // helper method for a lot of the back compat extensions
13934
+ $.ui.tabs.prototype._ui = function( tab, panel ) {
13935
+ return {
13936
+ tab: tab,
13937
+ panel: panel,
13938
+ index: this.anchors.index( tab )
13939
+ };
13940
+ };
13941
+
13942
+ // url method
13943
+ $.widget( "ui.tabs", $.ui.tabs, {
13944
+ url: function( index, url ) {
13945
+ this.anchors.eq( index ).attr( "href", url );
13946
+ }
13947
+ });
13948
+
13949
+ // TODO: Remove _ajaxSettings() method when removing this extension
13950
+ // ajaxOptions and cache options
13951
+ $.widget( "ui.tabs", $.ui.tabs, {
13952
+ options: {
13953
+ ajaxOptions: null,
13954
+ cache: false
13955
+ },
13956
+
13957
+ _create: function() {
13958
+ this._super();
13959
+
13960
+ var that = this;
13961
+
13962
+ this._on({ tabsbeforeload: function( event, ui ) {
13963
+ // tab is already cached
13964
+ if ( $.data( ui.tab[ 0 ], "cache.tabs" ) ) {
13965
+ event.preventDefault();
13966
+ return;
13967
+ }
13968
+
13969
+ ui.jqXHR.success(function() {
13970
+ if ( that.options.cache ) {
13971
+ $.data( ui.tab[ 0 ], "cache.tabs", true );
13972
+ }
13973
+ });
13974
+ }});
13975
+ },
13976
+
13977
+ _ajaxSettings: function( anchor, event, ui ) {
13978
+ var ajaxOptions = this.options.ajaxOptions;
13979
+ return $.extend( {}, ajaxOptions, {
13980
+ error: function( xhr, status ) {
13981
+ try {
13982
+ // Passing index avoid a race condition when this method is
13983
+ // called after the user has selected another tab.
13984
+ // Pass the anchor that initiated this request allows
13985
+ // loadError to manipulate the tab content panel via $(a.hash)
13986
+ ajaxOptions.error(
13987
+ xhr, status, ui.tab.closest( "li" ).index(), ui.tab[ 0 ] );
13988
+ }
13989
+ catch ( error ) {}
13990
+ }
13991
+ }, this._superApply( arguments ) );
13992
+ },
13993
+
13994
+ _setOption: function( key, value ) {
13995
+ // reset cache if switching from cached to not cached
13996
+ if ( key === "cache" && value === false ) {
13997
+ this.anchors.removeData( "cache.tabs" );
13998
+ }
13999
+ this._super( key, value );
14000
+ },
14001
+
14002
+ _destroy: function() {
14003
+ this.anchors.removeData( "cache.tabs" );
14004
+ this._super();
14005
+ },
14006
+
14007
+ url: function( index ){
14008
+ this.anchors.eq( index ).removeData( "cache.tabs" );
14009
+ this._superApply( arguments );
14010
+ }
14011
+ });
14012
+
14013
+ // abort method
14014
+ $.widget( "ui.tabs", $.ui.tabs, {
14015
+ abort: function() {
14016
+ if ( this.xhr ) {
14017
+ this.xhr.abort();
14018
+ }
14019
+ }
14020
+ });
14021
+
14022
+ // spinner
14023
+ $.widget( "ui.tabs", $.ui.tabs, {
14024
+ options: {
14025
+ spinner: "<em>Loading&#8230;</em>"
14026
+ },
14027
+ _create: function() {
14028
+ this._super();
14029
+ this._on({
14030
+ tabsbeforeload: function( event, ui ) {
14031
+ // Don't react to nested tabs or tabs that don't use a spinner
14032
+ if ( event.target !== this.element[ 0 ] ||
14033
+ !this.options.spinner ) {
14034
+ return;
14035
+ }
14036
+
14037
+ var span = ui.tab.find( "span" ),
14038
+ html = span.html();
14039
+ span.html( this.options.spinner );
14040
+ ui.jqXHR.complete(function() {
14041
+ span.html( html );
14042
+ });
14043
+ }
14044
+ });
14045
+ }
14046
+ });
14047
+
14048
+ // enable/disable events
14049
+ $.widget( "ui.tabs", $.ui.tabs, {
14050
+ options: {
14051
+ enable: null,
14052
+ disable: null
14053
+ },
14054
+
14055
+ enable: function( index ) {
14056
+ var options = this.options,
14057
+ trigger;
14058
+
14059
+ if ( index && options.disabled === true ||
14060
+ ( $.isArray( options.disabled ) && $.inArray( index, options.disabled ) !== -1 ) ) {
14061
+ trigger = true;
14062
+ }
14063
+
14064
+ this._superApply( arguments );
14065
+
14066
+ if ( trigger ) {
14067
+ this._trigger( "enable", null, this._ui( this.anchors[ index ], this.panels[ index ] ) );
14068
+ }
14069
+ },
14070
+
14071
+ disable: function( index ) {
14072
+ var options = this.options,
14073
+ trigger;
14074
+
14075
+ if ( index && options.disabled === false ||
14076
+ ( $.isArray( options.disabled ) && $.inArray( index, options.disabled ) === -1 ) ) {
14077
+ trigger = true;
14078
+ }
14079
+
14080
+ this._superApply( arguments );
14081
+
14082
+ if ( trigger ) {
14083
+ this._trigger( "disable", null, this._ui( this.anchors[ index ], this.panels[ index ] ) );
14084
+ }
14085
+ }
14086
+ });
14087
+
14088
+ // add/remove methods and events
14089
+ $.widget( "ui.tabs", $.ui.tabs, {
14090
+ options: {
14091
+ add: null,
14092
+ remove: null,
14093
+ tabTemplate: "<li><a href='#{href}'><span>#{label}</span></a></li>"
14094
+ },
14095
+
14096
+ add: function( url, label, index ) {
14097
+ if ( index === undefined ) {
14098
+ index = this.anchors.length;
14099
+ }
14100
+
14101
+ var doInsertAfter, panel,
14102
+ options = this.options,
14103
+ li = $( options.tabTemplate
14104
+ .replace( /#\{href\}/g, url )
14105
+ .replace( /#\{label\}/g, label ) ),
14106
+ id = !url.indexOf( "#" ) ?
14107
+ url.replace( "#", "" ) :
14108
+ this._tabId( li );
14109
+
14110
+ li.addClass( "ui-state-default ui-corner-top" ).data( "ui-tabs-destroy", true );
14111
+ li.attr( "aria-controls", id );
14112
+
14113
+ doInsertAfter = index >= this.tabs.length;
14114
+
14115
+ // try to find an existing element before creating a new one
14116
+ panel = this.element.find( "#" + id );
14117
+ if ( !panel.length ) {
14118
+ panel = this._createPanel( id );
14119
+ if ( doInsertAfter ) {
14120
+ if ( index > 0 ) {
14121
+ panel.insertAfter( this.panels.eq( -1 ) );
14122
+ } else {
14123
+ panel.appendTo( this.element );
14124
+ }
14125
+ } else {
14126
+ panel.insertBefore( this.panels[ index ] );
14127
+ }
14128
+ }
14129
+ panel.addClass( "ui-tabs-panel ui-widget-content ui-corner-bottom" ).hide();
14130
+
14131
+ if ( doInsertAfter ) {
14132
+ li.appendTo( this.tablist );
14133
+ } else {
14134
+ li.insertBefore( this.tabs[ index ] );
14135
+ }
14136
+
14137
+ options.disabled = $.map( options.disabled, function( n ) {
14138
+ return n >= index ? ++n : n;
14139
+ });
14140
+
14141
+ this.refresh();
14142
+ if ( this.tabs.length === 1 && options.active === false ) {
14143
+ this.option( "active", 0 );
14144
+ }
14145
+
14146
+ this._trigger( "add", null, this._ui( this.anchors[ index ], this.panels[ index ] ) );
14147
+ return this;
14148
+ },
14149
+
14150
+ remove: function( index ) {
14151
+ index = this._getIndex( index );
14152
+ var options = this.options,
14153
+ tab = this.tabs.eq( index ).remove(),
14154
+ panel = this._getPanelForTab( tab ).remove();
14155
+
14156
+ // If selected tab was removed focus tab to the right or
14157
+ // in case the last tab was removed the tab to the left.
14158
+ // We check for more than 2 tabs, because if there are only 2,
14159
+ // then when we remove this tab, there will only be one tab left
14160
+ // so we don't need to detect which tab to activate.
14161
+ if ( tab.hasClass( "ui-tabs-active" ) && this.anchors.length > 2 ) {
14162
+ this._activate( index + ( index + 1 < this.anchors.length ? 1 : -1 ) );
14163
+ }
14164
+
14165
+ options.disabled = $.map(
14166
+ $.grep( options.disabled, function( n ) {
14167
+ return n !== index;
14168
+ }),
14169
+ function( n ) {
14170
+ return n >= index ? --n : n;
14171
+ });
14172
+
14173
+ this.refresh();
14174
+
14175
+ this._trigger( "remove", null, this._ui( tab.find( "a" )[ 0 ], panel[ 0 ] ) );
14176
+ return this;
14177
+ }
14178
+ });
14179
+
14180
+ // length method
14181
+ $.widget( "ui.tabs", $.ui.tabs, {
14182
+ length: function() {
14183
+ return this.anchors.length;
14184
+ }
14185
+ });
14186
+
14187
+ // panel ids (idPrefix option + title attribute)
14188
+ $.widget( "ui.tabs", $.ui.tabs, {
14189
+ options: {
14190
+ idPrefix: "ui-tabs-"
14191
+ },
14192
+
14193
+ _tabId: function( tab ) {
14194
+ var a = tab.is( "li" ) ? tab.find( "a[href]" ) : tab;
14195
+ a = a[0];
14196
+ return $( a ).closest( "li" ).attr( "aria-controls" ) ||
14197
+ a.title && a.title.replace( /\s/g, "_" ).replace( /[^\w\u00c0-\uFFFF\-]/g, "" ) ||
14198
+ this.options.idPrefix + getNextTabId();
14199
+ }
14200
+ });
14201
+
14202
+ // _createPanel method
14203
+ $.widget( "ui.tabs", $.ui.tabs, {
14204
+ options: {
14205
+ panelTemplate: "<div></div>"
14206
+ },
14207
+
14208
+ _createPanel: function( id ) {
14209
+ return $( this.options.panelTemplate )
14210
+ .attr( "id", id )
14211
+ .addClass( "ui-tabs-panel ui-widget-content ui-corner-bottom" )
14212
+ .data( "ui-tabs-destroy", true );
14213
+ }
14214
+ });
14215
+
14216
+ // selected option
14217
+ $.widget( "ui.tabs", $.ui.tabs, {
14218
+ _create: function() {
14219
+ var options = this.options;
14220
+ if ( options.active === null && options.selected !== undefined ) {
14221
+ options.active = options.selected === -1 ? false : options.selected;
14222
+ }
14223
+ this._super();
14224
+ options.selected = options.active;
14225
+ if ( options.selected === false ) {
14226
+ options.selected = -1;
14227
+ }
14228
+ },
14229
+
14230
+ _setOption: function( key, value ) {
14231
+ if ( key !== "selected" ) {
14232
+ return this._super( key, value );
14233
+ }
14234
+
14235
+ var options = this.options;
14236
+ this._super( "active", value === -1 ? false : value );
14237
+ options.selected = options.active;
14238
+ if ( options.selected === false ) {
14239
+ options.selected = -1;
14240
+ }
14241
+ },
14242
+
14243
+ _eventHandler: function() {
14244
+ this._superApply( arguments );
14245
+ this.options.selected = this.options.active;
14246
+ if ( this.options.selected === false ) {
14247
+ this.options.selected = -1;
14248
+ }
14249
+ }
14250
+ });
14251
+
14252
+ // show and select event
14253
+ $.widget( "ui.tabs", $.ui.tabs, {
14254
+ options: {
14255
+ show: null,
14256
+ select: null
14257
+ },
14258
+ _create: function() {
14259
+ this._super();
14260
+ if ( this.options.active !== false ) {
14261
+ this._trigger( "show", null, this._ui(
14262
+ this.active.find( ".ui-tabs-anchor" )[ 0 ],
14263
+ this._getPanelForTab( this.active )[ 0 ] ) );
14264
+ }
14265
+ },
14266
+ _trigger: function( type, event, data ) {
14267
+ var ret = this._superApply( arguments );
14268
+ if ( !ret ) {
14269
+ return false;
14270
+ }
14271
+ if ( type === "beforeActivate" && data.newTab.length ) {
14272
+ ret = this._super( "select", event, {
14273
+ tab: data.newTab.find( ".ui-tabs-anchor" )[ 0],
14274
+ panel: data.newPanel[ 0 ],
14275
+ index: data.newTab.closest( "li" ).index()
14276
+ });
14277
+ } else if ( type === "activate" && data.newTab.length ) {
14278
+ ret = this._super( "show", event, {
14279
+ tab: data.newTab.find( ".ui-tabs-anchor" )[ 0 ],
14280
+ panel: data.newPanel[ 0 ],
14281
+ index: data.newTab.closest( "li" ).index()
14282
+ });
14283
+ }
14284
+ return ret;
14285
+ }
14286
+ });
14287
+
14288
+ // select method
14289
+ $.widget( "ui.tabs", $.ui.tabs, {
14290
+ select: function( index ) {
14291
+ index = this._getIndex( index );
14292
+ if ( index === -1 ) {
14293
+ if ( this.options.collapsible && this.options.selected !== -1 ) {
14294
+ index = this.options.selected;
14295
+ } else {
14296
+ return;
14297
+ }
14298
+ }
14299
+ this.anchors.eq( index ).trigger( this.options.event + this.eventNamespace );
14300
+ }
14301
+ });
14302
+
14303
+ // cookie option
14304
+ (function() {
14305
+
14306
+ var listId = 0;
14307
+
14308
+ $.widget( "ui.tabs", $.ui.tabs, {
14309
+ options: {
14310
+ cookie: null // e.g. { expires: 7, path: '/', domain: 'jquery.com', secure: true }
14311
+ },
14312
+ _create: function() {
14313
+ var options = this.options,
14314
+ active;
14315
+ if ( options.active == null && options.cookie ) {
14316
+ active = parseInt( this._cookie(), 10 );
14317
+ if ( active === -1 ) {
14318
+ active = false;
14319
+ }
14320
+ options.active = active;
14321
+ }
14322
+ this._super();
14323
+ },
14324
+ _cookie: function( active ) {
14325
+ var cookie = [ this.cookie ||
14326
+ ( this.cookie = this.options.cookie.name || "ui-tabs-" + (++listId) ) ];
14327
+ if ( arguments.length ) {
14328
+ cookie.push( active === false ? -1 : active );
14329
+ cookie.push( this.options.cookie );
14330
+ }
14331
+ return $.cookie.apply( null, cookie );
14332
+ },
14333
+ _refresh: function() {
14334
+ this._super();
14335
+ if ( this.options.cookie ) {
14336
+ this._cookie( this.options.active, this.options.cookie );
14337
+ }
14338
+ },
14339
+ _eventHandler: function() {
14340
+ this._superApply( arguments );
14341
+ if ( this.options.cookie ) {
14342
+ this._cookie( this.options.active, this.options.cookie );
14343
+ }
14344
+ },
14345
+ _destroy: function() {
14346
+ this._super();
14347
+ if ( this.options.cookie ) {
14348
+ this._cookie( null, this.options.cookie );
14349
+ }
14350
+ }
14351
+ });
14352
+
14353
+ })();
14354
+
14355
+ // load event
14356
+ $.widget( "ui.tabs", $.ui.tabs, {
14357
+ _trigger: function( type, event, data ) {
14358
+ var _data = $.extend( {}, data );
14359
+ if ( type === "load" ) {
14360
+ _data.panel = _data.panel[ 0 ];
14361
+ _data.tab = _data.tab.find( ".ui-tabs-anchor" )[ 0 ];
14362
+ }
14363
+ return this._super( type, event, _data );
14364
+ }
14365
+ });
14366
+
14367
+ // fx option
14368
+ // The new animation options (show, hide) conflict with the old show callback.
14369
+ // The old fx option wins over show/hide anyway (always favor back-compat).
14370
+ // If a user wants to use the new animation API, they must give up the old API.
14371
+ $.widget( "ui.tabs", $.ui.tabs, {
14372
+ options: {
14373
+ fx: null // e.g. { height: "toggle", opacity: "toggle", duration: 200 }
14374
+ },
14375
+
14376
+ _getFx: function() {
14377
+ var hide, show,
14378
+ fx = this.options.fx;
14379
+
14380
+ if ( fx ) {
14381
+ if ( $.isArray( fx ) ) {
14382
+ hide = fx[ 0 ];
14383
+ show = fx[ 1 ];
14384
+ } else {
14385
+ hide = show = fx;
14386
+ }
14387
+ }
14388
+
14389
+ return fx ? { show: show, hide: hide } : null;
14390
+ },
14391
+
14392
+ _toggle: function( event, eventData ) {
14393
+ var that = this,
14394
+ toShow = eventData.newPanel,
14395
+ toHide = eventData.oldPanel,
14396
+ fx = this._getFx();
14397
+
14398
+ if ( !fx ) {
14399
+ return this._super( event, eventData );
14400
+ }
14401
+
14402
+ that.running = true;
14403
+
14404
+ function complete() {
14405
+ that.running = false;
14406
+ that._trigger( "activate", event, eventData );
14407
+ }
14408
+
14409
+ function show() {
14410
+ eventData.newTab.closest( "li" ).addClass( "ui-tabs-active ui-state-active" );
14411
+
14412
+ if ( toShow.length && fx.show ) {
14413
+ toShow
14414
+ .animate( fx.show, fx.show.duration, function() {
14415
+ complete();
14416
+ });
14417
+ } else {
14418
+ toShow.show();
14419
+ complete();
14420
+ }
14421
+ }
14422
+
14423
+ // start out by hiding, then showing, then completing
14424
+ if ( toHide.length && fx.hide ) {
14425
+ toHide.animate( fx.hide, fx.hide.duration, function() {
14426
+ eventData.oldTab.closest( "li" ).removeClass( "ui-tabs-active ui-state-active" );
14427
+ show();
14428
+ });
14429
+ } else {
14430
+ eventData.oldTab.closest( "li" ).removeClass( "ui-tabs-active ui-state-active" );
14431
+ toHide.hide();
14432
+ show();
14433
+ }
14434
+ }
14435
+ });
14436
+ }
14437
+
14438
+ })( jQuery );
14439
+ (function( $ ) {
14440
+
14441
+ var increments = 0;
14442
+
14443
+ function addDescribedBy( elem, id ) {
14444
+ var describedby = (elem.attr( "aria-describedby" ) || "").split( /\s+/ );
14445
+ describedby.push( id );
14446
+ elem
14447
+ .data( "ui-tooltip-id", id )
14448
+ .attr( "aria-describedby", $.trim( describedby.join( " " ) ) );
14449
+ }
14450
+
14451
+ function removeDescribedBy( elem ) {
14452
+ var id = elem.data( "ui-tooltip-id" ),
14453
+ describedby = (elem.attr( "aria-describedby" ) || "").split( /\s+/ ),
14454
+ index = $.inArray( id, describedby );
14455
+ if ( index !== -1 ) {
14456
+ describedby.splice( index, 1 );
14457
+ }
14458
+
14459
+ elem.removeData( "ui-tooltip-id" );
14460
+ describedby = $.trim( describedby.join( " " ) );
14461
+ if ( describedby ) {
14462
+ elem.attr( "aria-describedby", describedby );
14463
+ } else {
14464
+ elem.removeAttr( "aria-describedby" );
14465
+ }
14466
+ }
14467
+
14468
+ $.widget( "ui.tooltip", {
14469
+ version: "1.9.1",
14470
+ options: {
14471
+ content: function() {
14472
+ return $( this ).attr( "title" );
14473
+ },
14474
+ hide: true,
14475
+ // Disabled elements have inconsistent behavior across browsers (#8661)
14476
+ items: "[title]:not([disabled])",
14477
+ position: {
14478
+ my: "left top+15",
14479
+ at: "left bottom",
14480
+ collision: "flipfit flipfit"
14481
+ },
14482
+ show: true,
14483
+ tooltipClass: null,
14484
+ track: false,
14485
+
14486
+ // callbacks
14487
+ close: null,
14488
+ open: null
14489
+ },
14490
+
14491
+ _create: function() {
14492
+ this._on({
14493
+ mouseover: "open",
14494
+ focusin: "open"
14495
+ });
14496
+
14497
+ // IDs of generated tooltips, needed for destroy
14498
+ this.tooltips = {};
14499
+ // IDs of parent tooltips where we removed the title attribute
14500
+ this.parents = {};
14501
+
14502
+ if ( this.options.disabled ) {
14503
+ this._disable();
14504
+ }
14505
+ },
14506
+
14507
+ _setOption: function( key, value ) {
14508
+ var that = this;
14509
+
14510
+ if ( key === "disabled" ) {
14511
+ this[ value ? "_disable" : "_enable" ]();
14512
+ this.options[ key ] = value;
14513
+ // disable element style changes
14514
+ return;
14515
+ }
14516
+
14517
+ this._super( key, value );
14518
+
14519
+ if ( key === "content" ) {
14520
+ $.each( this.tooltips, function( id, element ) {
14521
+ that._updateContent( element );
14522
+ });
14523
+ }
14524
+ },
14525
+
14526
+ _disable: function() {
14527
+ var that = this;
14528
+
14529
+ // close open tooltips
14530
+ $.each( this.tooltips, function( id, element ) {
14531
+ var event = $.Event( "blur" );
14532
+ event.target = event.currentTarget = element[0];
14533
+ that.close( event, true );
14534
+ });
14535
+
14536
+ // remove title attributes to prevent native tooltips
14537
+ this.element.find( this.options.items ).andSelf().each(function() {
14538
+ var element = $( this );
14539
+ if ( element.is( "[title]" ) ) {
14540
+ element
14541
+ .data( "ui-tooltip-title", element.attr( "title" ) )
14542
+ .attr( "title", "" );
14543
+ }
14544
+ });
14545
+ },
14546
+
14547
+ _enable: function() {
14548
+ // restore title attributes
14549
+ this.element.find( this.options.items ).andSelf().each(function() {
14550
+ var element = $( this );
14551
+ if ( element.data( "ui-tooltip-title" ) ) {
14552
+ element.attr( "title", element.data( "ui-tooltip-title" ) );
14553
+ }
14554
+ });
14555
+ },
14556
+
14557
+ open: function( event ) {
14558
+ var that = this,
14559
+ target = $( event ? event.target : this.element )
14560
+ // we need closest here due to mouseover bubbling,
14561
+ // but always pointing at the same event target
14562
+ .closest( this.options.items );
14563
+
14564
+ // No element to show a tooltip for
14565
+ if ( !target.length ) {
14566
+ return;
14567
+ }
14568
+
14569
+ // If the tooltip is open and we're tracking then reposition the tooltip.
14570
+ // This makes sure that a tracking tooltip doesn't obscure a focused element
14571
+ // if the user was hovering when the element gained focused.
14572
+ if ( this.options.track && target.data( "ui-tooltip-id" ) ) {
14573
+ this._find( target ).position( $.extend({
14574
+ of: target
14575
+ }, this.options.position ) );
14576
+ // Stop tracking (#8622)
14577
+ this._off( this.document, "mousemove" );
14578
+ return;
14579
+ }
14580
+
14581
+ if ( target.attr( "title" ) ) {
14582
+ target.data( "ui-tooltip-title", target.attr( "title" ) );
14583
+ }
14584
+
14585
+ target.data( "tooltip-open", true );
14586
+
14587
+ // kill parent tooltips, custom or native, for hover
14588
+ if ( event && event.type === "mouseover" ) {
14589
+ target.parents().each(function() {
14590
+ var blurEvent;
14591
+ if ( $( this ).data( "tooltip-open" ) ) {
14592
+ blurEvent = $.Event( "blur" );
14593
+ blurEvent.target = blurEvent.currentTarget = this;
14594
+ that.close( blurEvent, true );
14595
+ }
14596
+ if ( this.title ) {
14597
+ $( this ).uniqueId();
14598
+ that.parents[ this.id ] = {
14599
+ element: this,
14600
+ title: this.title
14601
+ };
14602
+ this.title = "";
14603
+ }
14604
+ });
14605
+ }
14606
+
14607
+ this._updateContent( target, event );
14608
+ },
14609
+
14610
+ _updateContent: function( target, event ) {
14611
+ var content,
14612
+ contentOption = this.options.content,
14613
+ that = this;
14614
+
14615
+ if ( typeof contentOption === "string" ) {
14616
+ return this._open( event, target, contentOption );
14617
+ }
14618
+
14619
+ content = contentOption.call( target[0], function( response ) {
14620
+ // ignore async response if tooltip was closed already
14621
+ if ( !target.data( "tooltip-open" ) ) {
14622
+ return;
14623
+ }
14624
+ // IE may instantly serve a cached response for ajax requests
14625
+ // delay this call to _open so the other call to _open runs first
14626
+ that._delay(function() {
14627
+ this._open( event, target, response );
14628
+ });
14629
+ });
14630
+ if ( content ) {
14631
+ this._open( event, target, content );
14632
+ }
14633
+ },
14634
+
14635
+ _open: function( event, target, content ) {
14636
+ var tooltip, events, delayedShow,
14637
+ positionOption = $.extend( {}, this.options.position );
14638
+
14639
+ if ( !content ) {
14640
+ return;
14641
+ }
14642
+
14643
+ // Content can be updated multiple times. If the tooltip already
14644
+ // exists, then just update the content and bail.
14645
+ tooltip = this._find( target );
14646
+ if ( tooltip.length ) {
14647
+ tooltip.find( ".ui-tooltip-content" ).html( content );
14648
+ return;
14649
+ }
14650
+
14651
+ // if we have a title, clear it to prevent the native tooltip
14652
+ // we have to check first to avoid defining a title if none exists
14653
+ // (we don't want to cause an element to start matching [title])
14654
+ //
14655
+ // We use removeAttr only for key events, to allow IE to export the correct
14656
+ // accessible attributes. For mouse events, set to empty string to avoid
14657
+ // native tooltip showing up (happens only when removing inside mouseover).
14658
+ if ( target.is( "[title]" ) ) {
14659
+ if ( event && event.type === "mouseover" ) {
14660
+ target.attr( "title", "" );
14661
+ } else {
14662
+ target.removeAttr( "title" );
14663
+ }
14664
+ }
14665
+
14666
+ tooltip = this._tooltip( target );
14667
+ addDescribedBy( target, tooltip.attr( "id" ) );
14668
+ tooltip.find( ".ui-tooltip-content" ).html( content );
14669
+
14670
+ function position( event ) {
14671
+ positionOption.of = event;
14672
+ if ( tooltip.is( ":hidden" ) ) {
14673
+ return;
14674
+ }
14675
+ tooltip.position( positionOption );
14676
+ }
14677
+ if ( this.options.track && event && /^mouse/.test( event.originalEvent.type ) ) {
14678
+ this._on( this.document, {
14679
+ mousemove: position
14680
+ });
14681
+ // trigger once to override element-relative positioning
14682
+ position( event );
14683
+ } else {
14684
+ tooltip.position( $.extend({
14685
+ of: target
14686
+ }, this.options.position ) );
14687
+ }
14688
+
14689
+ tooltip.hide();
14690
+
14691
+ this._show( tooltip, this.options.show );
14692
+ // Handle tracking tooltips that are shown with a delay (#8644). As soon
14693
+ // as the tooltip is visible, position the tooltip using the most recent
14694
+ // event.
14695
+ if ( this.options.show && this.options.show.delay ) {
14696
+ delayedShow = setInterval(function() {
14697
+ if ( tooltip.is( ":visible" ) ) {
14698
+ position( positionOption.of );
14699
+ clearInterval( delayedShow );
14700
+ }
14701
+ }, $.fx.interval );
14702
+ }
14703
+
14704
+ this._trigger( "open", event, { tooltip: tooltip } );
14705
+
14706
+ events = {
14707
+ keyup: function( event ) {
14708
+ if ( event.keyCode === $.ui.keyCode.ESCAPE ) {
14709
+ var fakeEvent = $.Event(event);
14710
+ fakeEvent.currentTarget = target[0];
14711
+ this.close( fakeEvent, true );
14712
+ }
14713
+ },
14714
+ remove: function() {
14715
+ this._removeTooltip( tooltip );
14716
+ }
14717
+ };
14718
+ if ( !event || event.type === "mouseover" ) {
14719
+ events.mouseleave = "close";
14720
+ }
14721
+ if ( !event || event.type === "focusin" ) {
14722
+ events.focusout = "close";
14723
+ }
14724
+ this._on( target, events );
14725
+ },
14726
+
14727
+ close: function( event ) {
14728
+ var that = this,
14729
+ target = $( event ? event.currentTarget : this.element ),
14730
+ tooltip = this._find( target );
14731
+
14732
+ // disabling closes the tooltip, so we need to track when we're closing
14733
+ // to avoid an infinite loop in case the tooltip becomes disabled on close
14734
+ if ( this.closing ) {
14735
+ return;
14736
+ }
14737
+
14738
+ // only set title if we had one before (see comment in _open())
14739
+ if ( target.data( "ui-tooltip-title" ) ) {
14740
+ target.attr( "title", target.data( "ui-tooltip-title" ) );
14741
+ }
14742
+
14743
+ removeDescribedBy( target );
14744
+
14745
+ tooltip.stop( true );
14746
+ this._hide( tooltip, this.options.hide, function() {
14747
+ that._removeTooltip( $( this ) );
14748
+ });
14749
+
14750
+ target.removeData( "tooltip-open" );
14751
+ this._off( target, "mouseleave focusout keyup" );
14752
+ // Remove 'remove' binding only on delegated targets
14753
+ if ( target[0] !== this.element[0] ) {
14754
+ this._off( target, "remove" );
14755
+ }
14756
+ this._off( this.document, "mousemove" );
14757
+
14758
+ if ( event && event.type === "mouseleave" ) {
14759
+ $.each( this.parents, function( id, parent ) {
14760
+ parent.element.title = parent.title;
14761
+ delete that.parents[ id ];
14762
+ });
14763
+ }
14764
+
14765
+ this.closing = true;
14766
+ this._trigger( "close", event, { tooltip: tooltip } );
14767
+ this.closing = false;
14768
+ },
14769
+
14770
+ _tooltip: function( element ) {
14771
+ var id = "ui-tooltip-" + increments++,
14772
+ tooltip = $( "<div>" )
14773
+ .attr({
14774
+ id: id,
14775
+ role: "tooltip"
14776
+ })
14777
+ .addClass( "ui-tooltip ui-widget ui-corner-all ui-widget-content " +
14778
+ ( this.options.tooltipClass || "" ) );
14779
+ $( "<div>" )
14780
+ .addClass( "ui-tooltip-content" )
14781
+ .appendTo( tooltip );
14782
+ tooltip.appendTo( this.document[0].body );
14783
+ if ( $.fn.bgiframe ) {
14784
+ tooltip.bgiframe();
14785
+ }
14786
+ this.tooltips[ id ] = element;
14787
+ return tooltip;
14788
+ },
14789
+
14790
+ _find: function( target ) {
14791
+ var id = target.data( "ui-tooltip-id" );
14792
+ return id ? $( "#" + id ) : $();
14793
+ },
14794
+
14795
+ _removeTooltip: function( tooltip ) {
14796
+ tooltip.remove();
14797
+ delete this.tooltips[ tooltip.attr( "id" ) ];
14798
+ },
14799
+
14800
+ _destroy: function() {
14801
+ var that = this;
14802
+
14803
+ // close open tooltips
14804
+ $.each( this.tooltips, function( id, element ) {
14805
+ // Delegate to close method to handle common cleanup
14806
+ var event = $.Event( "blur" );
14807
+ event.target = event.currentTarget = element[0];
14808
+ that.close( event, true );
14809
+
14810
+ // Remove immediately; destroying an open tooltip doesn't use the
14811
+ // hide animation
14812
+ $( "#" + id ).remove();
14813
+
14814
+ // Restore the title
14815
+ if ( element.data( "ui-tooltip-title" ) ) {
14816
+ element.attr( "title", element.data( "ui-tooltip-title" ) );
14817
+ element.removeData( "ui-tooltip-title" );
14818
+ }
14819
+ });
14820
+ }
14821
+ });
14822
+
14823
+ }( jQuery ) );
js/productlookbook/jquery.annotate.js ADDED
@@ -0,0 +1,536 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ /// <reference path="jquery-1.2.6-vsdoc.js" />
2
+ (function($) {
3
+
4
+ $.fn.annotateImage = function(options) {
5
+ /// <summary>
6
+ /// Creates annotations on the given image.
7
+ /// Images are loaded from the "getUrl" propety passed into the options.
8
+ /// </summary>
9
+ var opts = $.extend({}, $.fn.annotateImage.defaults, options);
10
+ var image = this;
11
+
12
+ this.image = this;
13
+ this.mode = 'view';
14
+
15
+ // Assign defaults
16
+ this.input_field_id = opts.input_field_id;
17
+ this.getUrl = opts.getUrl;
18
+ this.saveUrl = opts.saveUrl;
19
+ this.deleteUrl = opts.deleteUrl;
20
+ this.editable = opts.editable;
21
+ this.useAjax = opts.useAjax;
22
+ this.notes = opts.notes;
23
+
24
+ // Add the canvas
25
+ this.canvas = $('<div class="image-annotate-canvas"><div class="image-annotate-view"></div><div class="image-annotate-edit"><div class="image-annotate-edit-area"></div></div></div>');
26
+ this.canvas.children('.image-annotate-edit').hide();
27
+ this.canvas.children('.image-annotate-view').hide();
28
+ this.image.after(this.canvas);
29
+
30
+ // Give the canvas and the container their size and background
31
+ this.canvas.height(this.height());
32
+ this.canvas.width(this.width());
33
+ this.canvas.css('background-image', 'url("' + this.attr('src') + '")');
34
+ this.canvas.children('.image-annotate-view, .image-annotate-edit').height(this.height());
35
+ this.canvas.children('.image-annotate-view, .image-annotate-edit').width(this.width());
36
+
37
+ // Add the behavior: hide/show the notes when hovering the picture
38
+ this.canvas.hover(function() {
39
+ if ($(this).children('.image-annotate-edit').css('display') == 'none') {
40
+ $(this).children('.image-annotate-view').show();
41
+ }
42
+ }, function() {
43
+ $(this).children('.image-annotate-view').hide();
44
+ });
45
+
46
+ this.canvas.children('.image-annotate-view').hover(function() {
47
+ $(this).show();
48
+ }, function() {
49
+ $(this).hide();
50
+ });
51
+
52
+ // load the notes
53
+ if (this.useAjax) {
54
+ $.fn.annotateImage.ajaxLoad(this);
55
+ } else {
56
+ $.fn.annotateImage.load(this);
57
+ }
58
+
59
+ // Add the "Add a note" button
60
+ if (this.editable) {
61
+ this.button = $('<button class="image-annotate-add" id="image-annotate-add" onclick="javascript: return false;"><span>Add Hotspot</span></button>');
62
+ this.button.click(function() {
63
+ if (image.notes.length==15) {
64
+ alert('Only up to 15 hotspots could be added in Productlookbook extension.');
65
+ return false;
66
+ }
67
+ $.fn.annotateImage.add(image);
68
+ });
69
+ this.canvas.after(this.button);
70
+ }
71
+
72
+ // Hide the original
73
+ this.hide();
74
+
75
+ return this;
76
+ };
77
+
78
+ /**
79
+ * Plugin Defaults
80
+ **/
81
+ $.fn.annotateImage.defaults = {
82
+ getUrl: 'your-get.rails',
83
+ saveUrl: 'your-save.rails',
84
+ deleteUrl: 'your-delete.rails',
85
+ editable: true,
86
+ useAjax: true,
87
+ notes: new Array()
88
+ };
89
+
90
+ $.fn.annotateImage.clear = function(image) {
91
+ /// <summary>
92
+ /// Clears all existing annotations from the image.
93
+ /// </summary>
94
+ for (var i = 0; i < image.notes.length; i++) {
95
+ image.notes[image.notes[i]].destroy();
96
+ }
97
+ image.notes = new Array();
98
+ };
99
+
100
+ $.fn.annotateImage.ajaxLoad = function(image) {
101
+ /// <summary>
102
+ /// Loads the annotations from the "getUrl" property passed in on the
103
+ /// options object.
104
+ /// </summary>
105
+ $.getJSON(image.getUrl + '?ticks=' + $.fn.annotateImage.getTicks(), function(data) {
106
+ image.notes = data;
107
+ $.fn.annotateImage.load(image);
108
+ });
109
+ };
110
+
111
+ $.fn.annotateImage.load = function(image) {
112
+ /// <summary>
113
+ /// Loads the annotations from the notes property passed in on the
114
+ /// options object.
115
+ /// </summary>
116
+ for (var i = 0; i < image.notes.length; i++) {
117
+ image.notes[image.notes[i]] = new $.fn.annotateView(image, image.notes[i]);
118
+ }
119
+ };
120
+
121
+ $.fn.annotateImage.getTicks = function() {
122
+ /// <summary>
123
+ /// Gets a count og the ticks for the current date.
124
+ /// This is used to ensure that URLs are always unique and not cached by the browser.
125
+ /// </summary>
126
+ var now = new Date();
127
+ return now.getTime();
128
+ };
129
+
130
+ $.fn.annotateImage.add = function(image) {
131
+ /// <summary>
132
+ /// Adds a note to the image.
133
+ /// </summary>
134
+ if (image.mode == 'view') {
135
+ image.mode = 'edit';
136
+
137
+ // Create/prepare the editable note elements
138
+ var editable = new $.fn.annotateEdit(image);
139
+
140
+ $.fn.annotateImage.createSaveButton(editable, image);
141
+ $.fn.annotateImage.createCancelButton(editable, image);
142
+ $("#image-annotate-edit-ok").css('float', 'right').css('margin-right', '25px');
143
+ $(".image-annotate-edit-close").css('margin-left', '25px');
144
+ }
145
+
146
+ };
147
+
148
+ $.fn.annotateImage.createSaveButton = function(editable, image, note) {
149
+ /// <summary>
150
+ /// Creates a Save button on the editable note.
151
+ /// </summary>
152
+ var ok = $('<button class="image-annotate-edit-ok" id="image-annotate-edit-ok" onclick="javascript: return false;"><span>OK</span></button>');
153
+
154
+ ok.click(function() {
155
+ var form = $('#image-annotate-edit-form form');
156
+ var text = $('#image-annotate-text').val();
157
+
158
+ $.fn.annotateImage.appendPosition(form, editable)
159
+ image.mode = 'view';
160
+
161
+ // Save via AJAX
162
+ if (image.useAjax) {
163
+ $.ajax({
164
+ url: image.saveUrl,
165
+ data: form.serialize(),
166
+ error: function(e) { alert("An error occured saving that note.") },
167
+ success: function(data) {
168
+ if (data.annotation_id != undefined) {
169
+ editable.note.id = data.annotation_id;
170
+ }
171
+ },
172
+ dataType: "json"
173
+ });
174
+ }
175
+
176
+ var test_area = Object();
177
+ test_area.id = editable.note.id;
178
+ test_area.height = editable.area.height();
179
+ test_area.width = editable.area.width();
180
+ test_area.left = editable.area.position().left;
181
+ test_area.top = editable.area.position().top;
182
+
183
+ if (!CheckPosition(test_area,image.notes)) {
184
+ alert('Areas should not overlap For Hotspots');
185
+ return false;
186
+ }
187
+
188
+ if ($.trim(text)=='') {
189
+ alert('Please, enter product SKU');
190
+ return false;
191
+ }
192
+
193
+ var response = checkSKU();
194
+ if (response!=1) {
195
+ alert('The product with SKU="'+text+'" ' + response);
196
+ return false;
197
+ }
198
+ // Add to canvas
199
+ if (note) {
200
+ note.resetPosition(editable, text);
201
+ } else {
202
+ editable.note.editable = true;
203
+ note = new $.fn.annotateView(image, editable.note);
204
+ note.resetPosition(editable, text);
205
+ image.notes.push(editable.note);
206
+ }
207
+
208
+ $('#'+image.input_field_id).val(JSON.stringify(image.notes));
209
+ editable.destroy();
210
+ });
211
+ editable.form.append(ok);
212
+ };
213
+
214
+ $.fn.annotateImage.createCancelButton = function(editable, image) {
215
+ /// <summary>
216
+ /// Creates a Cancel button on the editable note.
217
+ /// </summary>
218
+ var cancel = $('<button class="image-annotate-edit-close" onclick="javascript: return false;"><span>Cancel</span></button>');
219
+ cancel.click(function() {
220
+ editable.destroy();
221
+ image.mode = 'view';
222
+ });
223
+ editable.form.append(cancel);
224
+ };
225
+
226
+ $.fn.annotateImage.saveAsHtml = function(image, target) {
227
+ var element = $(target);
228
+ var html = "";
229
+ for (var i = 0; i < image.notes.length; i++) {
230
+ html += $.fn.annotateImage.createHiddenField("text_" + i, image.notes[i].text);
231
+ html += $.fn.annotateImage.createHiddenField("top_" + i, image.notes[i].top);
232
+ html += $.fn.annotateImage.createHiddenField("left_" + i, image.notes[i].left);
233
+ html += $.fn.annotateImage.createHiddenField("height_" + i, image.notes[i].height);
234
+ html += $.fn.annotateImage.createHiddenField("width_" + i, image.notes[i].width);
235
+ }
236
+ element.html(html);
237
+ };
238
+
239
+ $.fn.annotateImage.createHiddenField = function(name, value) {
240
+ return '&lt;input type="hidden" name="' + name + '" value="' + value + '" /&gt;<br />';
241
+ };
242
+
243
+ $.fn.annotateEdit = function(image, note) {
244
+ /// <summary>
245
+ /// Defines an editable annotation area.
246
+ /// </summary>
247
+ this.image = image;
248
+
249
+ if (note) {
250
+ this.note = note;
251
+ } else {
252
+ var newNote = new Object();
253
+ newNote.id = ""+new Date().getTime();
254
+ newNote.top = 30;
255
+ newNote.left = 30;
256
+ newNote.width = 30;
257
+ newNote.height = 30;
258
+ newNote.text = "";
259
+ this.note = newNote;
260
+ }
261
+
262
+ // Set area
263
+ var area = image.canvas.children('.image-annotate-edit').children('.image-annotate-edit-area');
264
+ this.area = area;
265
+ this.area.css('height', this.note.height + 'px');
266
+ this.area.css('width', this.note.width + 'px');
267
+ this.area.css('left', this.note.left + 'px');
268
+ this.area.css('top', this.note.top + 'px');
269
+
270
+ // Show the edition canvas and hide the view canvas
271
+ image.canvas.children('.image-annotate-view').hide();
272
+ image.canvas.children('.image-annotate-edit').show();
273
+
274
+ // Add the note (which we'll load with the form afterwards)
275
+ var form = $('<div id="image-annotate-edit-form"><form id="annotate-edit-form"><label for="image-annotate-text">Product SKU: </label> <input id="image-annotate-text" value="'+this.note.text+'" name="text" type="text"/></form></div>');
276
+ this.form = form;
277
+
278
+ $('body').append(this.form);
279
+ this.form.css('left', this.area.offset().left + 'px');
280
+ this.form.css('top', (parseInt(this.area.offset().top) + parseInt(this.area.height()) + 7) + 'px');
281
+
282
+ // Set the area as a draggable/resizable element contained in the image canvas.
283
+ // Would be better to use the containment option for resizable but buggy
284
+ area.resizable({
285
+ handles: 'all',
286
+
287
+ stop: function(e, ui) {
288
+ form.css('left', area.offset().left + 'px');
289
+ form.css('top', (parseInt(area.offset().top) + parseInt(area.height()) + 2) + 'px');
290
+ }
291
+ })
292
+ .draggable({
293
+ containment: image.canvas,
294
+ drag: function(e, ui) {
295
+ form.css('left', area.offset().left + 'px');
296
+ form.css('top', (parseInt(area.offset().top) + parseInt(area.height()) + 2) + 'px');
297
+ },
298
+ stop: function(e, ui) {
299
+ form.css('left', area.offset().left + 'px');
300
+ form.css('top', (parseInt(area.offset().top) + parseInt(area.height()) + 2) + 'px');
301
+ }
302
+ });
303
+
304
+ return this;
305
+ };
306
+
307
+ $.fn.annotateEdit.prototype.destroy = function() {
308
+ /// <summary>
309
+ /// Destroys an editable annotation area.
310
+ /// </summary>
311
+ this.image.canvas.children('.image-annotate-edit').hide();
312
+ this.area.resizable('destroy');
313
+ this.area.draggable('destroy');
314
+ this.area.css('height', '');
315
+ this.area.css('width', '');
316
+ this.area.css('left', '');
317
+ this.area.css('top', '');
318
+ this.form.remove();
319
+ ShowHideHotspotsMsg();
320
+ }
321
+
322
+ $.fn.annotateView = function(image, note) {
323
+ /// <summary>
324
+ /// Defines a annotation area.
325
+ /// </summary>
326
+ this.image = image;
327
+
328
+ this.note = note;
329
+
330
+ this.editable = (note.editable && image.editable);
331
+
332
+ // Add the area
333
+ this.area = $('<div class="image-annotate-area' + (this.editable ? ' image-annotate-area-editable' : '') + '"><div></div></div>');
334
+ image.canvas.children('.image-annotate-view').prepend(this.area);
335
+
336
+ // Add the note
337
+ this.form = $('<div class="image-annotate-note">' + note.text + '</div>');
338
+ this.form.hide();
339
+ image.canvas.children('.image-annotate-view').append(this.form);
340
+ this.form.children('span.actions').hide();
341
+
342
+ // Set the position and size of the note
343
+ this.setPosition();
344
+
345
+ // Add the behavior: hide/display the note when hovering the area
346
+ var annotation = this;
347
+ this.area.hover(function() {
348
+ annotation.show();
349
+ }, function() {
350
+ annotation.hide();
351
+ });
352
+
353
+ // Edit a note feature
354
+ if (this.editable) {
355
+ var form = this;
356
+ this.area.click(function() {
357
+ form.edit();
358
+ });
359
+ }
360
+ };
361
+
362
+ $.fn.annotateView.prototype.setPosition = function() {
363
+ /// <summary>
364
+ /// Sets the position of an annotation.
365
+ /// </summary>
366
+ this.area.children('div').height((parseInt(this.note.height) - 2) + 'px');
367
+ this.area.children('div').width((parseInt(this.note.width) - 2) + 'px');
368
+ this.area.css('left', (this.note.left) + 'px');
369
+ this.area.css('top', (this.note.top) + 'px');
370
+ this.form.css('left', (this.note.left) + 'px');
371
+ this.form.css('top', (parseInt(this.note.top) + parseInt(this.note.height) + 7) + 'px');
372
+ };
373
+
374
+ $.fn.annotateView.prototype.show = function() {
375
+ /// <summary>
376
+ /// Highlights the annotation
377
+ /// </summary>
378
+ this.form.fadeIn(250);
379
+ if (!this.editable) {
380
+ this.area.addClass('image-annotate-area-hover');
381
+ } else {
382
+ this.area.addClass('image-annotate-area-editable-hover');
383
+ }
384
+ };
385
+
386
+ $.fn.annotateView.prototype.hide = function() {
387
+ /// <summary>
388
+ /// Removes the highlight from the annotation.
389
+ /// </summary>
390
+ this.form.fadeOut(250);
391
+ this.area.removeClass('image-annotate-area-hover');
392
+ this.area.removeClass('image-annotate-area-editable-hover');
393
+ };
394
+
395
+ $.fn.annotateView.prototype.destroy = function() {
396
+ /// <summary>
397
+ /// Destroys the annotation.
398
+ /// </summary>
399
+ this.area.remove();
400
+ this.form.remove();
401
+ }
402
+
403
+ $.fn.annotateView.prototype.edit = function() {
404
+ /// <summary>
405
+ /// Edits the annotation.
406
+ /// </summary>
407
+ if (this.image.mode == 'view') {
408
+ this.image.mode = 'edit';
409
+ var annotation = this;
410
+
411
+ // Create/prepare the editable note elements
412
+ var editable = new $.fn.annotateEdit(this.image, this.note);
413
+
414
+ $.fn.annotateImage.createSaveButton(editable, this.image, annotation);
415
+
416
+ // Add the delete button
417
+ var del = $('<button class="image-annotate-edit-delete" onclick="javascript: return false;"><span>Delete</span></button>');
418
+ del.click(function() {
419
+ var form = $('#image-annotate-edit-form form');
420
+
421
+ $.fn.annotateImage.appendPosition(form, editable)
422
+
423
+ if (annotation.image.useAjax) {
424
+ $.ajax({
425
+ url: annotation.image.deleteUrl,
426
+ data: form.serialize(),
427
+ error: function(e) { alert("An error occured deleting that note.") }
428
+ });
429
+ }
430
+
431
+ for (var i = 0; i < annotation.image.notes.length; i++) {
432
+ if (annotation.image.notes[i]==editable.note)
433
+ {
434
+ annotation.image.notes.splice(i,1);
435
+ }
436
+ }
437
+
438
+ $('#'+annotation.image.input_field_id).val(JSON.stringify(annotation.image.notes));
439
+
440
+ annotation.image.mode = 'view';
441
+ editable.destroy();
442
+ annotation.destroy();
443
+
444
+ });
445
+ editable.form.append(del);
446
+
447
+ $.fn.annotateImage.createCancelButton(editable, this.image);
448
+ }
449
+ };
450
+
451
+ $.fn.annotateImage.appendPosition = function(form, editable) {
452
+ /// <summary>
453
+ /// Appends the annotations coordinates to the given form that is posted to the server.
454
+ /// </summary>
455
+ var areaFields = $('<input type="hidden" value="' + editable.area.height() + '" name="height"/>' +
456
+ '<input type="hidden" value="' + editable.area.width() + '" name="width"/>' +
457
+ '<input type="hidden" value="' + editable.area.position().top + '" name="top"/>' +
458
+ '<input type="hidden" value="' + editable.area.position().left + '" name="left"/>' +
459
+ '<input type="hidden" value="' + editable.note.id + '" name="id"/>');
460
+ form.append(areaFields);
461
+ }
462
+
463
+ $.fn.annotateView.prototype.resetPosition = function(editable, text) {
464
+ /// <summary>
465
+ /// Sets the position of an annotation.
466
+ /// </summary>
467
+ this.form.html(text);
468
+ this.form.hide();
469
+
470
+ // Resize
471
+ this.area.children('div').height(editable.area.height() + 'px');
472
+ this.area.children('div').width((editable.area.width() - 2) + 'px');
473
+ this.area.css('left', (editable.area.position().left) + 'px');
474
+ this.area.css('top', (editable.area.position().top) + 'px');
475
+ this.form.css('left', (editable.area.position().left) + 'px');
476
+ this.form.css('top', (parseInt(editable.area.position().top) + parseInt(editable.area.height()) + 7) + 'px');
477
+
478
+ // Save new position to note
479
+ this.note.top = editable.area.position().top;
480
+ this.note.left = editable.area.position().left;
481
+ this.note.height = editable.area.height();
482
+ this.note.width = editable.area.width();
483
+ this.note.text = text;
484
+ this.note.id = editable.note.id;
485
+ this.editable = true;
486
+ };
487
+
488
+ intersects = function(X1, Y1, H1, L1, X2, Y2, H2, L2) {
489
+ X1 = parseInt(X1);
490
+ Y1 = parseInt(Y1);
491
+ H1 = parseInt(H1);
492
+ L1 = parseInt(L1);
493
+ X2 = parseInt(X2);
494
+ Y2 = parseInt(Y2);
495
+ H2 = parseInt(H2);
496
+ L2 = parseInt(L2);
497
+ a = X1 + L1 < X2;
498
+ b = X1 > X2 + L2;
499
+ c = Y1 + H1 < Y2;
500
+ d = Y1 > Y2 + H2;
501
+ if ((a || b || c || d)) {
502
+ return false;
503
+ }
504
+ else
505
+ {
506
+ return true;
507
+ }
508
+ };
509
+
510
+ ShowHideHotspotsMsg = function() {
511
+ view_is_visible = $(".image-annotate-canvas").find(".image-annotate-view").is(":visible");
512
+ edit_is_visible = $(".image-annotate-canvas").find(".image-annotate-edit").is(":visible");
513
+ if (view_is_visible || edit_is_visible) {
514
+ $(".hotspots-msg").hide();
515
+ }
516
+ else
517
+ {
518
+ $(".hotspots-msg").show();
519
+ }
520
+ }
521
+
522
+ CheckPosition = function(note, notes) {
523
+ i=0;
524
+ res = true;
525
+ notes.each(function() {
526
+ if (note.id!=notes[i].id) {
527
+ if (intersects(note.left, note.top, note.height, note.width, notes[i].left, notes[i].top, notes[i].height, notes[i].width)){
528
+ res = false;
529
+ }
530
+ }
531
+ i++;
532
+ });
533
+ return res;
534
+ };
535
+
536
+ })(jQuery);
js/productlookbook/jquery.mobile.customized.min.js ADDED
@@ -0,0 +1,10 @@
 
 
 
 
 
 
 
 
 
 
1
+ // jQuery Mobile framework customized for Camera slideshow, made by
2
+ // 'jquery.mobile.define.js',
3
+ // 'jquery.ui.widget.js',
4
+ // 'jquery.mobile.widget.js',
5
+ // 'jquery.mobile.media.js',
6
+ // 'jquery.mobile.support.js',
7
+ // 'jquery.mobile.vmouse.js',
8
+ // 'jquery.mobile.event.js',
9
+ // 'jquery.mobile.core.js'
10
+ window.define=function(){Array.prototype.slice.call(arguments).pop()(window.jQuery)};define(["jquery"],function(a){(function(a,b){if(a.cleanData){var c=a.cleanData;a.cleanData=function(b){for(var d=0,e;(e=b[d])!=null;d++){a(e).triggerHandler("remove")}c(b)}}else{var d=a.fn.remove;a.fn.remove=function(b,c){return this.each(function(){if(!c){if(!b||a.filter(b,[this]).length){a("*",this).add([this]).each(function(){a(this).triggerHandler("remove")})}}return d.call(a(this),b,c)})}}a.widget=function(b,c,d){var e=b.split(".")[0],f;b=b.split(".")[1];f=e+"-"+b;if(!d){d=c;c=a.Widget}a.expr[":"][f]=function(c){return!!a.data(c,b)};a[e]=a[e]||{};a[e][b]=function(a,b){if(arguments.length){this._createWidget(a,b)}};var g=new c;g.options=a.extend(true,{},g.options);a[e][b].prototype=a.extend(true,g,{namespace:e,widgetName:b,widgetEventPrefix:a[e][b].prototype.widgetEventPrefix||b,widgetBaseClass:f},d);a.widget.bridge(b,a[e][b])};a.widget.bridge=function(c,d){a.fn[c]=function(e){var f=typeof e==="string",g=Array.prototype.slice.call(arguments,1),h=this;e=!f&&g.length?a.extend.apply(null,[true,e].concat(g)):e;if(f&&e.charAt(0)==="_"){return h}if(f){this.each(function(){var d=a.data(this,c);if(!d){throw"cannot call methods on "+c+" prior to initialization; "+"attempted to call method '"+e+"'"}if(!a.isFunction(d[e])){throw"no such method '"+e+"' for "+c+" widget instance"}var f=d[e].apply(d,g);if(f!==d&&f!==b){h=f;return false}})}else{this.each(function(){var b=a.data(this,c);if(b){b.option(e||{})._init()}else{a.data(this,c,new d(e,this))}})}return h}};a.Widget=function(a,b){if(arguments.length){this._createWidget(a,b)}};a.Widget.prototype={widgetName:"widget",widgetEventPrefix:"",options:{disabled:false},_createWidget:function(b,c){a.data(c,this.widgetName,this);this.element=a(c);this.options=a.extend(true,{},this.options,this._getCreateOptions(),b);var d=this;this.element.bind("remove."+this.widgetName,function(){d.destroy()});this._create();this._trigger("create");this._init()},_getCreateOptions:function(){var b={};if(a.metadata){b=a.metadata.get(element)[this.widgetName]}return b},_create:function(){},_init:function(){},destroy:function(){this.element.unbind("."+this.widgetName).removeData(this.widgetName);this.widget().unbind("."+this.widgetName).removeAttr("aria-disabled").removeClass(this.widgetBaseClass+"-disabled "+"ui-state-disabled")},widget:function(){return this.element},option:function(c,d){var e=c;if(arguments.length===0){return a.extend({},this.options)}if(typeof c==="string"){if(d===b){return this.options[c]}e={};e[c]=d}this._setOptions(e);return this},_setOptions:function(b){var c=this;a.each(b,function(a,b){c._setOption(a,b)});return this},_setOption:function(a,b){this.options[a]=b;if(a==="disabled"){this.widget()[b?"addClass":"removeClass"](this.widgetBaseClass+"-disabled"+" "+"ui-state-disabled").attr("aria-disabled",b)}return this},enable:function(){return this._setOption("disabled",false)},disable:function(){return this._setOption("disabled",true)},_trigger:function(b,c,d){var e=this.options[b];c=a.Event(c);c.type=(b===this.widgetEventPrefix?b:this.widgetEventPrefix+b).toLowerCase();d=d||{};if(c.originalEvent){for(var f=a.event.props.length,g;f;){g=a.event.props[--f];c[g]=c.originalEvent[g]}}this.element.trigger(c,d);return!(a.isFunction(e)&&e.call(this.element[0],c,d)===false||c.isDefaultPrevented())}}})(jQuery)});define(["jquery","./jquery.ui.widget"],function(a){(function(a,b){a.widget("mobile.widget",{_createWidget:function(){a.Widget.prototype._createWidget.apply(this,arguments);this._trigger("init")},_getCreateOptions:function(){var c=this.element,d={};a.each(this.options,function(a){var e=c.jqmData(a.replace(/[A-Z]/g,function(a){return"-"+a.toLowerCase()}));if(e!==b){d[a]=e}});return d},enhanceWithin:function(b){var c=a.mobile.closestPageData(a(b)),d=c&&c.keepNativeSelector()||"";a(this.options.initSelector,b).not(d)[this.widgetName]()}})})(jQuery)});define(["jquery","./jquery.mobile.core"],function(a){(function(a,b){var c=a(window),d=a("html");a.mobile.media=function(){var b={},c=a("<div id='jquery-mediatest'>"),e=a("<body>").append(c);return function(a){if(!(a in b)){var f=document.createElement("style"),g="@media "+a+" { #jquery-mediatest { position:absolute; } }";f.type="text/css";if(f.styleSheet){f.styleSheet.cssText=g}else{f.appendChild(document.createTextNode(g))}d.prepend(e).prepend(f);b[a]=c.css("position")==="absolute";e.add(f).remove()}return b[a]}}()})(jQuery)});define(["jquery","./jquery.mobile.media"],function(a){(function(a,b){function m(){var b=location.protocol+"//"+location.host+location.pathname+"ui-dir/",d=a("head base"),e=null,f="",g,h;if(!d.length){d=e=a("<base>",{href:b}).appendTo("head")}else{f=d.attr("href")}g=a("<a href='testurl' />").prependTo(c);h=g[0].href;d[0].href=f||location.pathname;if(e){e.remove()}return h.indexOf(b)===0}function l(){var b="transform-3d";return k("perspective","10px","moz")||a.mobile.media("(-"+e.join("-"+b+"),(-")+"-"+b+"),("+b+")")}function k(a,b,c){var d=document.createElement("div"),f=function(a){return a.charAt(0).toUpperCase()+a.substr(1)},g=function(a){return"-"+a.charAt(0).toLowerCase()+a.substr(1)+"-"},h=function(c){var e=g(c)+a+": "+b+";",h=f(c),i=h+f(a);d.setAttribute("style",e);if(!!d.style[i]){k=true}},j=c?[c]:e,k;for(i=0;i<j.length;i++){h(j[i])}return!!k}function j(a){var c=a.charAt(0).toUpperCase()+a.substr(1),f=(a+" "+e.join(c+" ")+c).split(" ");for(var g in f){if(d[f[g]]!==b){return true}}}var c=a("<body>").prependTo("html"),d=c[0].style,e=["Webkit","Moz","O"],f="palmGetResource"in window,g=window.operamini&&{}.toString.call(window.operamini)==="[object OperaMini]",h=window.blackberry;a.extend(a.mobile,{browser:{}});a.mobile.browser.ie=function(){var a=3,b=document.createElement("div"),c=b.all||[];while(b.innerHTML="<!--[if gt IE "+ ++a+"]><br><![endif]-->",c[0]){}return a>4?a:!a}();a.extend(a.support,{orientation:"orientation"in window&&"onorientationchange"in window,touch:"ontouchend"in document,cssTransitions:"WebKitTransitionEvent"in window||k("transition","height 100ms linear"),pushState:"pushState"in history&&"replaceState"in history,mediaquery:a.mobile.media("only all"),cssPseudoElement:!!j("content"),touchOverflow:!!j("overflowScrolling"),cssTransform3d:l(),boxShadow:!!j("boxShadow")&&!h,scrollTop:("pageXOffset"in window||"scrollTop"in document.documentElement||"scrollTop"in c[0])&&!f&&!g,dynamicBaseTag:m()});c.remove();var n=function(){var a=window.navigator.userAgent;return a.indexOf("Nokia")>-1&&(a.indexOf("Symbian/3")>-1||a.indexOf("Series60/5")>-1)&&a.indexOf("AppleWebKit")>-1&&a.match(/(BrowserNG|NokiaBrowser)\/7\.[0-3]/)}();a.mobile.ajaxBlacklist=window.blackberry&&!window.WebKitPoint||g||n;if(n){a(function(){a("head link[rel='stylesheet']").attr("rel","alternate stylesheet").attr("rel","stylesheet")})}if(!a.support.boxShadow){a("html").addClass("ui-mobile-nosupport-boxshadow")}})(jQuery)});define(["jquery"],function(a){(function(a,b,c,d){function O(b){var c=b.substr(1);return{setup:function(d,f){if(!M(this)){a.data(this,e,{})}var g=a.data(this,e);g[b]=true;k[b]=(k[b]||0)+1;if(k[b]===1){t.bind(c,H)}a(this).bind(c,N);if(s){k["touchstart"]=(k["touchstart"]||0)+1;if(k["touchstart"]===1){t.bind("touchstart",I).bind("touchend",L).bind("touchmove",K).bind("scroll",J)}}},teardown:function(d,f){--k[b];if(!k[b]){t.unbind(c,H)}if(s){--k["touchstart"];if(!k["touchstart"]){t.unbind("touchstart",I).unbind("touchmove",K).unbind("touchend",L).unbind("scroll",J)}}var g=a(this),h=a.data(this,e);if(h){h[b]=false}g.unbind(c,N);if(!M(this)){g.removeData(e)}}}}function N(){}function M(b){var c=a.data(b,e),d;if(c){for(d in c){if(c[d]){return true}}}return false}function L(a){if(r){return}B();var b=y(a.target),c;G("vmouseup",a,b);if(!o){var d=G("vclick",a,b);if(d&&d.isDefaultPrevented()){c=w(a).changedTouches[0];p.push({touchID:v,x:c.clientX,y:c.clientY});q=true}}G("vmouseout",a,b);o=false;E()}function K(b){if(r){return}var c=w(b).touches[0],d=o,e=a.vmouse.moveDistanceThreshold;o=o||Math.abs(c.pageX-m)>e||Math.abs(c.pageY-n)>e,flags=y(b.target);if(o&&!d){G("vmousecancel",b,flags)}G("vmousemove",b,flags);E()}function J(a){if(r){return}if(!o){G("vmousecancel",a,y(a.target))}o=true;E()}function I(b){var c=w(b).touches,d,e;if(c&&c.length===1){d=b.target;e=y(d);if(e.hasVirtualBinding){v=u++;a.data(d,f,v);F();D();o=false;var g=w(b).touches[0];m=g.pageX;n=g.pageY;G("vmouseover",b,e);G("vmousedown",b,e)}}}function H(b){var c=a.data(b.target,f);if(!q&&(!v||v!==c)){var d=G("v"+b.type,b);if(d){if(d.isDefaultPrevented()){b.preventDefault()}if(d.isPropagationStopped()){b.stopPropagation()}if(d.isImmediatePropagationStopped()){b.stopImmediatePropagation()}}}}function G(b,c,d){var e;if(d&&d[b]||!d&&z(c.target,b)){e=x(c,b);a(c.target).trigger(e)}return e}function F(){if(l){clearTimeout(l);l=0}}function E(){F();l=setTimeout(function(){l=0;C()},a.vmouse.resetTimerDuration)}function D(){A()}function C(){v=0;p.length=0;q=false;B()}function B(){r=true}function A(){r=false}function z(b,c){var d;while(b){d=a.data(b,e);if(d&&(!c||d[c])){return b}b=b.parentNode}return null}function y(b){var c={},d,f;while(b){d=a.data(b,e);for(f in d){if(d[f]){c[f]=c.hasVirtualBinding=true}}b=b.parentNode}return c}function x(b,c){var e=b.type,f,g,i,k,l,m,n,o;b=a.Event(b);b.type=c;f=b.originalEvent;g=a.event.props;if(e.search(/mouse/)>-1){g=j}if(f){for(n=g.length,k;n;){k=g[--n];b[k]=f[k]}}if(e.search(/mouse(down|up)|click/)>-1&&!b.which){b.which=1}if(e.search(/^touch/)!==-1){i=w(f);e=i.touches;l=i.changedTouches;m=e&&e.length?e[0]:l&&l.length?l[0]:d;if(m){for(o=0,len=h.length;o<len;o++){k=h[o];b[k]=m[k]}}}return b}function w(a){while(a&&typeof a.originalEvent!=="undefined"){a=a.originalEvent}return a}var e="virtualMouseBindings",f="virtualTouchID",g="vmouseover vmousedown vmousemove vmouseup vclick vmouseout vmousecancel".split(" "),h="clientX clientY pageX pageY screenX screenY".split(" "),i=a.event.mouseHooks?a.event.mouseHooks.props:[],j=a.event.props.concat(i),k={},l=0,m=0,n=0,o=false,p=[],q=false,r=false,s="addEventListener"in c,t=a(c),u=1,v=0;a.vmouse={moveDistanceThreshold:10,clickDistanceThreshold:10,resetTimerDuration:1500};for(var P=0;P<g.length;P++){a.event.special[g[P]]=O(g[P])}if(s){c.addEventListener("click",function(b){var c=p.length,d=b.target,e,g,h,i,j,k;if(c){e=b.clientX;g=b.clientY;threshold=a.vmouse.clickDistanceThreshold;h=d;while(h){for(i=0;i<c;i++){j=p[i];k=0;if(h===d&&Math.abs(j.x-e)<threshold&&Math.abs(j.y-g)<threshold||a.data(h,f)===j.touchID){b.preventDefault();b.stopPropagation();return}}h=h.parentNode}}},true)}})(jQuery,window,document)});define(["jquery","./jquery.mobile.core","./jquery.mobile.media","./jquery.mobile.support","./jquery.mobile.vmouse"],function(a){(function(a,b,c){function i(b,c,d){var e=d.type;d.type=c;a.event.handle.call(b,d);d.type=e}a.each(("touchstart touchmove touchend orientationchange throttledresize "+"tap taphold swipe swipeleft swiperight scrollstart scrollstop").split(" "),function(b,c){a.fn[c]=function(a){return a?this.bind(c,a):this.trigger(c)};a.attrFn[c]=true});var d=a.support.touch,e="touchmove scroll",f=d?"touchstart":"mousedown",g=d?"touchend":"mouseup",h=d?"touchmove":"mousemove";a.event.special.scrollstart={enabled:true,setup:function(){function g(a,c){d=c;i(b,d?"scrollstart":"scrollstop",a)}var b=this,c=a(b),d,f;c.bind(e,function(b){if(!a.event.special.scrollstart.enabled){return}if(!d){g(b,true)}clearTimeout(f);f=setTimeout(function(){g(b,false)},50)})}};a.event.special.tap={setup:function(){var b=this,c=a(b);c.bind("vmousedown",function(d){function k(a){j();if(e==a.target){i(b,"tap",a)}}function j(){h();c.unbind("vclick",k).unbind("vmouseup",h);a(document).unbind("vmousecancel",j)}function h(){clearTimeout(g)}if(d.which&&d.which!==1){return false}var e=d.target,f=d.originalEvent,g;c.bind("vmouseup",h).bind("vclick",k);a(document).bind("vmousecancel",j);g=setTimeout(function(){i(b,"taphold",a.Event("taphold"))},750)})}};a.event.special.swipe={scrollSupressionThreshold:10,durationThreshold:1e3,horizontalDistanceThreshold:30,verticalDistanceThreshold:75,setup:function(){var b=this,d=a(b);d.bind(f,function(b){function j(b){if(!f){return}var c=b.originalEvent.touches?b.originalEvent.touches[0]:b;i={time:(new Date).getTime(),coords:[c.pageX,c.pageY]};if(Math.abs(f.coords[0]-i.coords[0])>a.event.special.swipe.scrollSupressionThreshold){b.preventDefault()}}var e=b.originalEvent.touches?b.originalEvent.touches[0]:b,f={time:(new Date).getTime(),coords:[e.pageX,e.pageY],origin:a(b.target)},i;d.bind(h,j).one(g,function(b){d.unbind(h,j);if(f&&i){if(i.time-f.time<a.event.special.swipe.durationThreshold&&Math.abs(f.coords[0]-i.coords[0])>a.event.special.swipe.horizontalDistanceThreshold&&Math.abs(f.coords[1]-i.coords[1])<a.event.special.swipe.verticalDistanceThreshold){f.origin.trigger("swipe").trigger(f.coords[0]>i.coords[0]?"swipeleft":"swiperight")}}f=i=c})})}};(function(a,b){function j(){var a=e();if(a!==f){f=a;c.trigger("orientationchange")}}var c=a(b),d,e,f,g,h,i={0:true,180:true};if(a.support.orientation){g=a.mobile.media("all and (orientation: landscape)");h=i[b.orientation];if(g&&h||!g&&!h){i={"-90":true,90:true}}}a.event.special.orientationchange=d={setup:function(){if(a.support.orientation&&a.mobile.orientationChangeEnabled){return false}f=e();c.bind("throttledresize",j)},teardown:function(){if(a.support.orientation&&a.mobile.orientationChangeEnabled){return false}c.unbind("throttledresize",j)},add:function(a){var b=a.handler;a.handler=function(a){a.orientation=e();return b.apply(this,arguments)}}};a.event.special.orientationchange.orientation=e=function(){var c=true,d=document.documentElement;if(a.support.orientation){c=i[b.orientation]}else{c=d&&d.clientWidth/d.clientHeight<1.1}return c?"portrait":"landscape"}})(jQuery,b);(function(){a.event.special.throttledresize={setup:function(){a(this).bind("resize",c)},teardown:function(){a(this).unbind("resize",c)}};var b=250,c=function(){f=(new Date).getTime();g=f-d;if(g>=b){d=f;a(this).trigger("throttledresize")}else{if(e){clearTimeout(e)}e=setTimeout(c,b-g)}},d=0,e,f,g})();a.each({scrollstop:"scrollstart",taphold:"tap",swipeleft:"swipe",swiperight:"swipe"},function(b,c){a.event.special[b]={setup:function(){a(this).bind(c,a.noop)}}})})(jQuery,this)});define(["jquery","../external/requirejs/text!../version.txt","./jquery.mobile.widget"],function(a,b){(function(a,c,d){var e={};a.mobile=a.extend({},{version:b,ns:"",subPageUrlKey:"ui-page",activePageClass:"ui-page-active",activeBtnClass:"ui-btn-active",focusClass:"ui-focus",ajaxEnabled:true,hashListeningEnabled:true,linkBindingEnabled:true,defaultPageTransition:"fade",maxTransitionWidth:false,minScrollBack:10,touchOverflowEnabled:false,defaultDialogTransition:"pop",loadingMessage:"loading",pageLoadErrorMessage:"Error Loading Page",loadingMessageTextVisible:false,loadingMessageTheme:"a",pageLoadErrorMessageTheme:"e",autoInitializePage:true,pushStateEnabled:true,orientationChangeEnabled:true,gradeA:function(){return a.support.mediaquery||a.mobile.browser.ie&&a.mobile.browser.ie>=7},keyCode:{ALT:18,BACKSPACE:8,CAPS_LOCK:20,COMMA:188,COMMAND:91,COMMAND_LEFT:91,COMMAND_RIGHT:93,CONTROL:17,DELETE:46,DOWN:40,END:35,ENTER:13,ESCAPE:27,HOME:36,INSERT:45,LEFT:37,MENU:93,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,SHIFT:16,SPACE:32,TAB:9,UP:38,WINDOWS:91},silentScroll:function(b){if(a.type(b)!=="number"){b=a.mobile.defaultHomeScroll}a.event.special.scrollstart.enabled=false;setTimeout(function(){c.scrollTo(0,b);a(document).trigger("silentscroll",{x:0,y:b})},20);setTimeout(function(){a.event.special.scrollstart.enabled=true},150)},nsNormalizeDict:e,nsNormalize:function(b){if(!b){return}return e[b]||(e[b]=a.camelCase(a.mobile.ns+b))},getInheritedTheme:function(a,b){var c=a[0],d="",e=/ui-(bar|body)-([a-z])\b/,f,g;while(c){var f=c.className||"";if((g=e.exec(f))&&(d=g[2])){break}c=c.parentNode}return d||b||"a"},closestPageData:function(a){return a.closest(':jqmData(role="page"), :jqmData(role="dialog")').data("page")}},a.mobile);a.fn.jqmData=function(b,c){var d;if(typeof b!="undefined"){d=this.data(b?a.mobile.nsNormalize(b):b,c)}return d};a.jqmData=function(b,c,d){var e;if(typeof c!="undefined"){e=a.data(b,c?a.mobile.nsNormalize(c):c,d)}return e};a.fn.jqmRemoveData=function(b){return this.removeData(a.mobile.nsNormalize(b))};a.jqmRemoveData=function(b,c){return a.removeData(b,a.mobile.nsNormalize(c))};a.fn.removeWithDependents=function(){a.removeWithDependents(this)};a.removeWithDependents=function(b){var c=a(b);(c.jqmData("dependents")||a()).remove();c.remove()};a.fn.addDependents=function(b){a.addDependents(a(this),b)};a.addDependents=function(b,c){var d=a(b).jqmData("dependents")||a();a(b).jqmData("dependents",a.merge(d,c))};a.fn.getEncodedText=function(){return a("<div/>").text(a(this).text()).html()};var f=a.find,g=/:jqmData\(([^)]*)\)/g;a.find=function(b,c,d,e){b=b.replace(g,"[data-"+(a.mobile.ns||"")+"$1]");return f.call(this,b,c,d,e)};a.extend(a.find,f);a.find.matches=function(b,c){return a.find(b,null,null,c)};a.find.matchesSelector=function(b,c){return a.find(c,null,null,[b]).length>0}})(jQuery,this)})
js/productlookbook/json2.min.js ADDED
@@ -0,0 +1 @@
 
1
+ var JSON;if(!JSON){JSON={}}(function(){'use strict';function f(n){return n<10?'0'+n:n}if(typeof Date.prototype.toJSON!=='function'){Date.prototype.toJSON=function(key){return isFinite(this.valueOf())?this.getUTCFullYear()+'-'+f(this.getUTCMonth()+1)+'-'+f(this.getUTCDate())+'T'+f(this.getUTCHours())+':'+f(this.getUTCMinutes())+':'+f(this.getUTCSeconds())+'Z':null};String.prototype.toJSON=Number.prototype.toJSON=Boolean.prototype.toJSON=function(key){return this.valueOf()}}var cx=/[\u0000\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g,escapable=/[\\\"\x00-\x1f\x7f-\x9f\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g,gap,indent,meta={'\b':'\\b','\t':'\\t','\n':'\\n','\f':'\\f','\r':'\\r','"':'\\"','\\':'\\\\'},rep;function quote(string){escapable.lastIndex=0;return escapable.test(string)?'"'+string.replace(escapable,function(a){var c=meta[a];return typeof c==='string'?c:'\\u'+('0000'+a.charCodeAt(0).toString(16)).slice(-4)})+'"':'"'+string+'"'}function str(key,holder){var i,k,v,length,mind=gap,partial,value=holder[key];if(value&&typeof value==='object'&&typeof value.toJSON==='function'){value=value.toJSON(key)}if(typeof rep==='function'){value=rep.call(holder,key,value)}switch(typeof value){case'string':return quote(value);case'number':return isFinite(value)?String(value):'null';case'boolean':case'null':return String(value);case'object':if(!value){return'null'}gap+=indent;partial=[];if(Object.prototype.toString.apply(value)==='[object Array]'){length=value.length;for(i=0;i<length;i+=1){partial[i]=str(i,value)||'null'}v=partial.length===0?'[]':gap?'[\n'+gap+partial.join(',\n'+gap)+'\n'+mind+']':'['+partial.join(',')+']';gap=mind;return v}if(rep&&typeof rep==='object'){length=rep.length;for(i=0;i<length;i+=1){if(typeof rep[i]==='string'){k=rep[i];v=str(k,value);if(v){partial.push(quote(k)+(gap?': ':':')+v)}}}}else{for(k in value){if(Object.prototype.hasOwnProperty.call(value,k)){v=str(k,value);if(v){partial.push(quote(k)+(gap?': ':':')+v)}}}}v=partial.length===0?'{}':gap?'{\n'+gap+partial.join(',\n'+gap)+'\n'+mind+'}':'{'+partial.join(',')+'}';gap=mind;return v}}if(typeof JSON.stringify!=='function'){JSON.stringify=function(value,replacer,space){var i;gap='';indent='';if(typeof space==='number'){for(i=0;i<space;i+=1){indent+=' '}}else if(typeof space==='string'){indent=space}rep=replacer;if(replacer&&typeof replacer!=='function'&&(typeof replacer!=='object'||typeof replacer.length!=='number')){throw new Error('JSON.stringify')}return str('',{'':value})}}if(typeof JSON.parse!=='function'){JSON.parse=function(text,reviver){var j;function walk(holder,key){var k,v,value=holder[key];if(value&&typeof value==='object'){for(k in value){if(Object.prototype.hasOwnProperty.call(value,k)){v=walk(value,k);if(v!==undefined){value[k]=v}else{delete value[k]}}}}return reviver.call(holder,key,value)}text=String(text);cx.lastIndex=0;if(cx.test(text)){text=text.replace(cx,function(a){return'\\u'+('0000'+a.charCodeAt(0).toString(16)).slice(-4)})}if(/^[\],:{}\s]*$/.test(text.replace(/\\(?:["\\\/bfnrt]|u[0-9a-fA-F]{4})/g,'@').replace(/"[^"\\\n\r]*"|true|false|null|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?/g,']').replace(/(?:^|:|,)(?:\s*\[)+/g,''))){j=eval('('+text+')');return typeof reviver==='function'?walk({'':j},''):j}throw new SyntaxError('JSON.parse')}}}());
media/productlookbook/100X100/53be81b791bde.JPG ADDED
Binary file
media/productlookbook/100X100/53be81db38e27.JPG ADDED
Binary file
media/productlookbook/100X100/53be820cd989e.JPG ADDED
Binary file
media/productlookbook/100X100/53be86dff2a40.JPG ADDED
Binary file
media/productlookbook/100X100/53be86f283a61.JPG ADDED
Binary file
media/productlookbook/100X100/53be870222845.JPG ADDED
Binary file
media/productlookbook/100X100/53be8956c4665.JPG ADDED
Binary file
media/productlookbook/100X100/53be8aa8f1366.JPG ADDED
Binary file
media/productlookbook/100X100/53be909503fcd.JPG ADDED
Binary file
media/productlookbook/100X100/53be90b4ba6b7.JPG ADDED
Binary file
media/productlookbook/100X100/53be90c2b9acb.JPG ADDED
Binary file
media/productlookbook/100X100/53bfc454e7037.JPG ADDED
Binary file
media/productlookbook/450X600/53be81b791bde.JPG ADDED
Binary file
media/productlookbook/450X600/53be81db38e27.JPG ADDED
Binary file
media/productlookbook/450X600/53be820cd989e.JPG ADDED
Binary file
media/productlookbook/450X600/53be86dff2a40.JPG ADDED
Binary file
media/productlookbook/450X600/53be86f283a61.JPG ADDED
Binary file
media/productlookbook/450X600/53be870222845.JPG ADDED
Binary file
media/productlookbook/450X600/53be8956c4665.JPG ADDED
Binary file
media/productlookbook/450X600/53be8aa8f1366.JPG ADDED
Binary file
media/productlookbook/450X600/53be909503fcd.JPG ADDED
Binary file
media/productlookbook/450X600/53be90b4ba6b7.JPG ADDED
Binary file
media/productlookbook/450X600/53be90c2b9acb.JPG ADDED
Binary file
media/productlookbook/450X600/53bfc454e7037.JPG ADDED
Binary file
media/productlookbook/53be81b791bde.JPG ADDED
Binary file
media/productlookbook/53be81db38e27.JPG ADDED
Binary file
media/productlookbook/53be820cd989e.JPG ADDED
Binary file
media/productlookbook/53be86dff2a40.JPG ADDED
Binary file
media/productlookbook/53be86f283a61.JPG ADDED
Binary file
media/productlookbook/53be870222845.JPG ADDED
Binary file
media/productlookbook/53be8956c4665.JPG ADDED
Binary file
media/productlookbook/53be8aa8f1366.JPG ADDED
Binary file
media/productlookbook/53be909503fcd.JPG ADDED
Binary file
media/productlookbook/53be90b4ba6b7.JPG ADDED
Binary file
media/productlookbook/53be90c2b9acb.JPG ADDED
Binary file
media/productlookbook/53bfc454e7037.JPG ADDED
Binary file
media/productlookbook/75X75/53be81b791bde.JPG ADDED
Binary file
media/productlookbook/75X75/53be81db38e27.JPG ADDED
Binary file
media/productlookbook/75X75/53be820cd989e.JPG ADDED
Binary file
media/productlookbook/75X75/53be86dff2a40.JPG ADDED
Binary file
media/productlookbook/75X75/53be86f283a61.JPG ADDED
Binary file
media/productlookbook/75X75/53be870222845.JPG ADDED
Binary file
media/productlookbook/75X75/53be8956c4665.JPG ADDED
Binary file
media/productlookbook/75X75/53be8aa8f1366.JPG ADDED
Binary file
media/productlookbook/75X75/53be909503fcd.JPG ADDED
Binary file
media/productlookbook/75X75/53be90b4ba6b7.JPG ADDED
Binary file
media/productlookbook/75X75/53be90c2b9acb.JPG ADDED
Binary file
media/productlookbook/75X75/53bfc454e7037.JPG ADDED
Binary file
media/productlookbook/Thumbs.db ADDED
Binary file
media/productlookbook/icons/default/QuickIcon.png ADDED
Binary file
media/productlookbook/icons/default/ebs.jpg ADDED
Binary file
media/productlookbook/icons/default/hotspot-icon.png ADDED
Binary file
media/productlookbook/icons/default/logo1.PNG ADDED
Binary file
media/productlookbook/icons/default/logo2.PNG ADDED
Binary file
media/productlookbook/icons/default/logo2_1.PNG ADDED
Binary file
media/productlookbook/icons/stores/1/1234.PNG ADDED
Binary file
media/productlookbook/icons/stores/1/1234_1.PNG ADDED
Binary file
media/productlookbook/icons/websites/default/DSC00140.JPG ADDED
Binary file
media/productlookbook/icons/websites/default/Thumbs.db ADDED
Binary file
package.xml ADDED
@@ -0,0 +1,18 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?xml version="1.0"?>
2
+ <package>
3
+ <name>Techinflo_Productlookbook</name>
4
+ <version>1.0.0</version>
5
+ <stability>stable</stability>
6
+ <license uri="http://opensource.org/licenses/OSL-3.0">Open Software License v. 3.0 (OSL-3.0)</license>
7
+ <channel>community</channel>
8
+ <extends/>
9
+ <summary>This extension allows a vendor to upload Images with the popular styles /trend and then customer can click on a particular part of the image, like Dress, Accessories, footwear etc, to view the matching products.</summary>
10
+ <description>This extension allows a vendor to upload Images with the popular styles /trend and then customer can click on a particular part of the image, like Dress, Accessories, footwear etc, to view the matching products. Allow customers to view/purchase products of a matching look.</description>
11
+ <notes>This extension allows a vendor to upload Images with the popular styles /trend and then customer can click on a particular part of the image, like Dress, Accessories, footwear etc, to view the matching products. Allow customers to view/purchase products of a matching look.</notes>
12
+ <authors><author><name>Techinflo</name><user>Techinflo</user><email>contact@techinflo.com</email></author></authors>
13
+ <date>2014-07-11</date>
14
+ <time>11:44:16</time>
15
+ <contents><target name="mageetc"><dir name="modules"><file name="Techinflo_Productlookbook.xml" hash="7000b2dae2570ed0787a96d172f2725b"/></dir></target><target name="magelocal"><dir name="Techinflo"><dir name="Productlookbook"><dir name="Block"><dir name="Adminhtml"><dir name="Productlookbook"><dir name="Edit"><dir name="Form"><dir name="Element"><file name="Hotspots.php" hash="dbd4a22a304586f89ac18ad836c56f7c"/><file name="Productlookbookimage.php" hash="a2816fb11de52e85d50ae1aa1171af1e"/></dir></dir><file name="Form.php" hash="4b1e495dc2717ec4197307f634a0a7a6"/><dir name="Tab"><file name="Form.php" hash="ec0646f8207212d68abd0c081eb263f8"/></dir><file name="Tabs.php" hash="5db6af56766ef5fe1bcc27e6f1accbc9"/></dir><file name="Edit.php" hash="01f6f8ac6e66782ae5dd3accfc5ea6a5"/><file name="Grid.php" hash="e9630843eac007a2cb9be524a50c1ef0"/></dir><file name="Productlookbook.php" hash="ca379b75d50874393076ad3ab0b5ff60"/><dir name="System"><dir name="Config"><dir name="Form"><dir name="Field"><file name="Categories.php" hash="8b059fbaa993e7a8fb678af6fe695750"/></dir></dir><dir name="Template"><dir name="Renderer"><file name="Category.php" hash="67e7ffcc2e0cf591da607cfd72b89fee"/></dir></dir></dir></dir><dir name="Template"><dir name="Grid"><dir name="Renderer"><file name="Image.php" hash="5eeb1abd1755421d0e1ef1eed52c847a"/></dir></dir></dir></dir><file name="Productlookbook.php" hash="dfc4f836897ba4e1ce242cd8361a9c96"/></dir><dir name="Helper"><file name="Data.php" hash="3c873beee8cae5876d57cba51a0dc0e0"/></dir><dir name="Model"><dir name="Config"><dir name="Source"><file name="Effect.php" hash="c6c40f0815cf35515d5f57ec3f545f5f"/></dir></dir><file name="Fileuploader.php" hash="b73c8f56b7c3ac0cb4320e4bfaeb60ee"/><dir name="Layout"><dir name="Generate"><file name="Observer.php" hash="1226dacb97497f7d25e3310e425f8cd9"/></dir></dir><dir name="Mysql4"><dir name="Productlookbook"><file name="Collection.php" hash="378213b135d05c673999a7e595aba52b"/></dir><file name="Productlookbook.php" hash="11e7ee7e1bea83a34b07ec7a84e6c923"/></dir><file name="Productlookbook.php" hash="af00fdf2001fe1becad7324442426472"/><file name="Status.php" hash="f5670902a5de2b9cc9885219d0acccf8"/><file name="Uploadedfileform.php" hash="766b3baf8b4c2fca39fa77927b00e530"/><file name="Uploadedfilexhr.php" hash="d5d311850b4c1419d32fdc398ee76fe7"/></dir><dir name="controllers"><dir name="Adminhtml"><file name="ProductlookbookController.php" hash="98216e31655cb5ec9d5d0888a1dca2b5"/></dir><file name="IndexController.php" hash="b053be9944b999d3baf7ffdf0516362e"/></dir><dir name="etc"><file name="config.xml" hash="00ff5c633de32e91bf8472d8f4afaa8c"/><file name="system.xml" hash="ad5b643d22c2d0a23dd3415e3a2e9500"/></dir><dir name="sql"><dir name="productlookbook_setup"><file name="mysql4-install-1.0.2.php" hash="441fe15ce06a16e2a750408d0352a751"/><file name="mysql4-upgrade-1.0.2-1.0.3.php" hash="79173da618315a8c2ef12b0e28b47138"/></dir></dir></dir></dir></target><target name="magedesign"><dir name="adminhtml"><dir name="default"><dir name="default"><dir name="layout"><file name="productlookbook.xml" hash="f458a9c4bce9db0fb93d2f28b4a4c21a"/></dir></dir></dir></dir><dir name="frontend"><dir name="default"><dir name="default"><dir name="layout"><file name="productlookbook.xml" hash="aed4bea25650349135dfd1372c3a1795"/></dir><dir name="template"><dir name="productlookbook"><file name="productlookbook.phtml" hash="7e4918013dd6afdd4b731aa1e2b49196"/></dir></dir></dir></dir></dir></target><target name="magemedia"><dir name="productlookbook"><dir><dir name="100X100"><file name="53be81b791bde.JPG" hash="c0c3ed5e650be6740b3d094198b7ac14"/><file name="53be81db38e27.JPG" hash="c0c3ed5e650be6740b3d094198b7ac14"/><file name="53be820cd989e.JPG" hash="c0c3ed5e650be6740b3d094198b7ac14"/><file name="53be86dff2a40.JPG" hash="c0c3ed5e650be6740b3d094198b7ac14"/><file name="53be86f283a61.JPG" hash="c0c3ed5e650be6740b3d094198b7ac14"/><file name="53be870222845.JPG" hash="c0c3ed5e650be6740b3d094198b7ac14"/><file name="53be8956c4665.JPG" hash="c0c3ed5e650be6740b3d094198b7ac14"/><file name="53be8aa8f1366.JPG" hash="c0c3ed5e650be6740b3d094198b7ac14"/><file name="53be909503fcd.JPG" hash="c0c3ed5e650be6740b3d094198b7ac14"/><file name="53be90b4ba6b7.JPG" hash="c0c3ed5e650be6740b3d094198b7ac14"/><file name="53be90c2b9acb.JPG" hash="c0c3ed5e650be6740b3d094198b7ac14"/><file name="53bfc454e7037.JPG" hash="c0c3ed5e650be6740b3d094198b7ac14"/></dir><dir name="450X600"><file name="53be81b791bde.JPG" hash="1393fba62c5128e72fe04fb7c35c8020"/><file name="53be81db38e27.JPG" hash="1393fba62c5128e72fe04fb7c35c8020"/><file name="53be820cd989e.JPG" hash="1393fba62c5128e72fe04fb7c35c8020"/><file name="53be86dff2a40.JPG" hash="1393fba62c5128e72fe04fb7c35c8020"/><file name="53be86f283a61.JPG" hash="1393fba62c5128e72fe04fb7c35c8020"/><file name="53be870222845.JPG" hash="1393fba62c5128e72fe04fb7c35c8020"/><file name="53be8956c4665.JPG" hash="1393fba62c5128e72fe04fb7c35c8020"/><file name="53be8aa8f1366.JPG" hash="1393fba62c5128e72fe04fb7c35c8020"/><file name="53be909503fcd.JPG" hash="1393fba62c5128e72fe04fb7c35c8020"/><file name="53be90b4ba6b7.JPG" hash="1393fba62c5128e72fe04fb7c35c8020"/><file name="53be90c2b9acb.JPG" hash="1393fba62c5128e72fe04fb7c35c8020"/><file name="53bfc454e7037.JPG" hash="1393fba62c5128e72fe04fb7c35c8020"/></dir><dir name="75X75"><file name="53be81b791bde.JPG" hash="73c28977bc9a9d43d7c630ab3fc9fa27"/><file name="53be81db38e27.JPG" hash="73c28977bc9a9d43d7c630ab3fc9fa27"/><file name="53be820cd989e.JPG" hash="73c28977bc9a9d43d7c630ab3fc9fa27"/><file name="53be86dff2a40.JPG" hash="73c28977bc9a9d43d7c630ab3fc9fa27"/><file name="53be86f283a61.JPG" hash="73c28977bc9a9d43d7c630ab3fc9fa27"/><file name="53be870222845.JPG" hash="73c28977bc9a9d43d7c630ab3fc9fa27"/><file name="53be8956c4665.JPG" hash="73c28977bc9a9d43d7c630ab3fc9fa27"/><file name="53be8aa8f1366.JPG" hash="73c28977bc9a9d43d7c630ab3fc9fa27"/><file name="53be909503fcd.JPG" hash="73c28977bc9a9d43d7c630ab3fc9fa27"/><file name="53be90b4ba6b7.JPG" hash="73c28977bc9a9d43d7c630ab3fc9fa27"/><file name="53be90c2b9acb.JPG" hash="73c28977bc9a9d43d7c630ab3fc9fa27"/><file name="53bfc454e7037.JPG" hash="73c28977bc9a9d43d7c630ab3fc9fa27"/></dir><dir name="icons"><dir name="default"><file name="QuickIcon.png" hash="30e86ddc55992b9a294c6dafbcddb66f"/><file name="ebs.jpg" hash="c9cea6b5ea4cfb021eea07b03aaad8f6"/><file name="hotspot-icon.png" hash="95336e1e788e3f88f29019eacbac2041"/><file name="logo1.PNG" hash="feaaf2b174712f9c1cb52cd1a1f8ab5c"/><file name="logo2.PNG" hash="22d07e8e1bf1d65ab8b05a0f1f08cd74"/><file name="logo2_1.PNG" hash="22d07e8e1bf1d65ab8b05a0f1f08cd74"/></dir><dir name="stores"><dir name="1"><file name="1234.PNG" hash="d8daf50ee01ed3bba9ff67d89fb4ff17"/><file name="1234_1.PNG" hash="d8daf50ee01ed3bba9ff67d89fb4ff17"/></dir></dir><dir name="websites"><dir name="default"><file name="DSC00140.JPG" hash="8d32b2a9145bf92d093a0f4fd8fa179f"/><file name="Thumbs.db" hash="7b35dee49abd794873f6e2ad52a4dd1f"/></dir></dir></dir></dir><file name="53be81b791bde.JPG" hash="f1ff6725f07779b7d767d4d5d0742f7a"/><file name="53be81db38e27.JPG" hash="f1ff6725f07779b7d767d4d5d0742f7a"/><file name="53be820cd989e.JPG" hash="f1ff6725f07779b7d767d4d5d0742f7a"/><file name="53be86dff2a40.JPG" hash="f1ff6725f07779b7d767d4d5d0742f7a"/><file name="53be86f283a61.JPG" hash="f1ff6725f07779b7d767d4d5d0742f7a"/><file name="53be870222845.JPG" hash="f1ff6725f07779b7d767d4d5d0742f7a"/><file name="53be8956c4665.JPG" hash="f1ff6725f07779b7d767d4d5d0742f7a"/><file name="53be8aa8f1366.JPG" hash="f1ff6725f07779b7d767d4d5d0742f7a"/><file name="53be909503fcd.JPG" hash="f1ff6725f07779b7d767d4d5d0742f7a"/><file name="53be90b4ba6b7.JPG" hash="f1ff6725f07779b7d767d4d5d0742f7a"/><file name="53be90c2b9acb.JPG" hash="f1ff6725f07779b7d767d4d5d0742f7a"/><file name="53bfc454e7037.JPG" hash="f1ff6725f07779b7d767d4d5d0742f7a"/><file name="Thumbs.db" hash="7997575f4d3fa2ba367a36ad9425f8b5"/></dir></target><target name="mageweb"><dir name="js"><dir name="jquery"><file name="jquery-1.8.2.min.js" hash="cfa9051cc0b05eb519f1e16b2a6645d7"/><file name="jquery.noconflict.js" hash="3179f2255b046d5f2e9a71e365287bef"/></dir><dir name="productlookbook"><file name="fileuploader.js" hash="64cb3de32e4a6cc1710dd08bb0da582a"/><file name="jquery-ui-1.9.1.js" hash="e3afa2a5c2ef212277864dfd43408ce4"/><file name="jquery.annotate.js" hash="cb071818bb157c179babe9744e4e1d98"/><file name="jquery.mobile.customized.min.js" hash="ea59fe8222cc61ffdbd41119ce23fd25"/><file name="json2.min.js" hash="041eedd4d7676d33b6ccd2056734e4b3"/></dir></dir></target><target name="mageskin"><dir name="frontend"><dir name="base"><dir name="default"><dir name="productlookbook"><dir name="css"><file name="hotspots.css" hash="4791b35974cafcf1c0ffed272fa44ab3"/></dir><dir name="images"><file name="Thumbs.db" hash="3e8dbef4870dd848b6d35addfff4b60d"/><file name="adv-bg.png" hash="06af9432757479345a304c8d8b8b3939"/><file name="camera-loader.gif" hash="cd2e13291ecdcac7f575beea6d84b099"/><file name="camera_skins.png" hash="44234b21bebe6b318aab47d9e9bbbee9"/><file name="caption-bg.png" hash="b09e2b8f7382607b51b0392ba46f5963"/><file name="info-bg.png" hash="6b2e3b329380a9bf3c298e3a6c34a7fa"/><dir><dir name="patterns"><file name="Thumbs.db" hash="44a0f4358c024ff7edab2b112d2b00f8"/><file name="overlay1.png" hash="1f146c3ca45b7de58990fe35674f3c12"/><file name="overlay10.png" hash="e1eb49ee07e74a2c4fee9dad5f17a513"/><file name="overlay2.png" hash="ddcf42fed3bf5234b7846a74bf17fc6d"/><file name="overlay3.png" hash="d3deed31d1eed4f17432ff93aefd9daf"/><file name="overlay4.png" hash="8df992721519d21ba39626a8615393c4"/><file name="overlay5.png" hash="a839858206fe25a686265e5868a00fbf"/><file name="overlay6.png" hash="de8c31ab33ca41114addad876a7d057b"/><file name="overlay7.png" hash="8475f8c4b675c531f5fca9d0f8266889"/><file name="overlay8.png" hash="a13c787a719e0619ce82ba73bacd9498"/><file name="overlay9.png" hash="06b734ded54bbe1761e3b67acd2575e5"/></dir></dir></dir><dir name="js"><file name="camera.min.js" hash="fb5074c5cf40020f7d0ab68a6d96db97"/><file name="hotspots.js" hash="0ff6d4acc3dc5611e0c74306be8cc3bb"/><file name="jquery.easing.1.3.js" hash="6516449ed5089677ed3d7e2f11fc8942"/></dir></dir></dir></dir></dir><dir name="adminhtml"><dir name="default"><dir name="default"><dir name="productlookbook"><dir name="css"><file name="annotation.css" hash="9cc51acc1cde04e4353c1d60fd7de8eb"/><file name="fileuploader.css" hash="a61b9fbe095acfb8f55a59f081367c09"/></dir><dir name="images"><file name="Thumbs.db" hash="bbe7dd1a07173dc61a8f4f732904b4b7"/><file name="btn_bg.gif" hash="37c51a4d48a92da9648dcd3ca011039f"/><file name="btn_gray_bg.gif" hash="8be512788b8044fe31aa8d00cc16ba7b"/><file name="btn_over_bg.gif" hash="f91641168454c03d1fa72731ec97a2b3"/><file name="cancel_btn_icon.png" hash="343e0534818e33d4e3886aa4694602d7"/><file name="cross.png" hash="42492684e24356a4081134894eabeb9e"/><file name="delete_btn_icon.png" hash="04485bbcca5d645427061365185b4a76"/><file name="icon_btn_add.png" hash="3a99c7c227e5e6feb656e1649a8264ab"/><file name="link_external.png" hash="7cc8feaca790904979edda0ba930d6cd"/><file name="loading.gif" hash="2da0807814ad64841cd597c4e8a653d1"/><file name="ok_btn_icon.png" hash="bf2b8c5bb1c784e8d907f5d6345f0e5e"/><file name="upload_btn_icon.png" hash="1ede630273613ffe452dede682e5e028"/></dir></dir></dir></dir></dir></target></contents>
16
+ <compatible/>
17
+ <dependencies><required><php><min>5.1.0</min><max>6.1.0</max></php></required></dependencies>
18
+ </package>
skin/adminhtml/default/default/productlookbook/css/annotation.css ADDED
@@ -0,0 +1,292 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ button.image-annotate-add {
2
+ background: url("../images/btn_gray_bg.gif") repeat-x scroll 0 100% #FFFFFF;
3
+ border-color: #CCCCCC #AAAAAA #AAAAAA #CCCCCC;
4
+ color: #555555;
5
+ border-style: solid;
6
+ border-width: 1px;
7
+ cursor: pointer;
8
+ font: bold 12px arial,helvetica,sans-serif;
9
+ text-align: center !important;
10
+ white-space: nowrap;
11
+ float:right;
12
+ margin-top: 5px;
13
+ padding-top:1px;
14
+ padding-left:4px;
15
+ }
16
+
17
+ .image-annotate-add span {
18
+ padding: 5px 0px 5px 35px;
19
+ background-repeat: no-repeat;
20
+ line-height: 1.6em;
21
+ background-image: url("../images/icon_btn_add.png");
22
+ }
23
+
24
+ .image-annotate-canvas {
25
+ border: solid 1px #ccc;
26
+ background-position: left top;
27
+ background-repeat: no-repeat;
28
+ display: block;
29
+ margin: 0;
30
+ position: relative;
31
+ }
32
+ .image-annotate-view {
33
+ display: none;
34
+ position: relative;
35
+ }
36
+ .image-annotate-area {
37
+ border: 1px solid #000000;
38
+ position: absolute;
39
+ }
40
+ .image-annotate-area div {
41
+ border: 1px solid #FFFFFF;
42
+ display: block;
43
+ background-size: 30px,30px !important;
44
+ }
45
+ .image-annotate-area-hover div {
46
+ border-color: yellow !important;
47
+ }
48
+ .image-annotate-area-editable {
49
+ cursor: pointer;background-size: 30px,30px !important;
50
+ }
51
+ .image-annotate-area-editable-hover div {
52
+ border-color: #00AD00 !important;
53
+ }
54
+ .image-annotate-note {
55
+ background: #E7FFE7 none repeat scroll 0 0;
56
+ border: solid 1px #397F39;
57
+ color: #000;
58
+ display: none;
59
+ font-family: Verdana, Sans-Serif;
60
+ font-size: 12px;
61
+ max-width: 200px;
62
+ padding: 3px 7px;
63
+ position: absolute;
64
+ }
65
+ .image-annotate-note .actions {
66
+ display: block;
67
+ font-size: 80%;
68
+ }
69
+ .image-annotate-edit {
70
+ display: none;
71
+ }
72
+ #image-annotate-edit-form {
73
+ background: #FFFEE3 none repeat scroll 0 0;
74
+ border: 1px solid #000000;
75
+ padding: 15px 7px;
76
+ position: absolute;
77
+ width: 265px;
78
+ text-align: center;
79
+ }
80
+ #image-annotate-edit-form form {
81
+ clear: right;
82
+ margin: 0 !important;
83
+ padding: 5px 0 5px 0;
84
+ z-index: 999;
85
+ }
86
+ #image-annotate-edit-form .box {
87
+ margin: 0;
88
+ }
89
+ #image-annotate-edit-form input.form-text, #image-annotate-edit-form #edit-comment-wrapper textarea {
90
+ width: 90%;
91
+ }
92
+ #image-annotate-edit-form textarea {
93
+ height: 50px;
94
+ font-family: Verdana, Sans-Serif;
95
+ font-size: 12px;
96
+ width: 248px;
97
+ }
98
+ #image-annotate-edit-form fieldset {
99
+ background: transparent none repeat scroll 0 0;
100
+ }
101
+ #image-annotate-edit-form .form-item {
102
+ margin: 0 0 5px;
103
+ }
104
+ #image-annotate-edit-form .form-button, #image-annotate-edit-form .form-submit {
105
+ margin: 0;
106
+ }
107
+ /*
108
+ #image-annotate-edit-form a {
109
+ background-color: #fff;
110
+ background-repeat: no-repeat;
111
+ background-position: 3px 3px;
112
+ border: solid 1px #ccc;
113
+ color: #333;
114
+ cursor: pointer;
115
+ display: block;
116
+ float: left;
117
+ font-family: Verdana, Sans-Serif;
118
+ font-size: 12px;
119
+ height: 18px;
120
+ line-height: 18px;
121
+ padding: 2px 6px 2px 24px;
122
+ margin: 6px 0px 6px 6px;
123
+ }
124
+
125
+ #image-annotate-edit-form a:hover {
126
+ background-color: #eee;
127
+ }*/
128
+
129
+ .image-annotate-edit-area {
130
+ border: 1px solid #000;
131
+ cursor: move;
132
+ display: block;
133
+ height: 60px;
134
+ left: 10px;
135
+ margin: 0;
136
+ padding: 0;
137
+ position: absolute;
138
+ top: 10px;
139
+ width: 60px;
140
+ }
141
+ .image-annotate-edit-area .ui-resizable-handle {
142
+ opacity: 0.8;
143
+ }
144
+
145
+ .image-annotate-edit-area:before {
146
+ position:absolute;
147
+ display:block;
148
+ content:'';
149
+ border:1px solid #FFF;
150
+ height:100%;
151
+ width:100%;
152
+ box-sizing: border-box;
153
+ -moz-box-sizing: border-box;
154
+ -webkit-box-sizing: border-box;
155
+ }
156
+ #image-annotate-edit-form button {
157
+ background: url("../images/btn_gray_bg.gif") repeat-x scroll 0 100% #FFFFFF;
158
+ border-color: #CCCCCC #AAAAAA #AAAAAA #CCCCCC;
159
+ color: #555555;
160
+ float:left;
161
+ border-style: solid;
162
+ border-width: 1px;
163
+ cursor: pointer;
164
+ font: bold 12px arial,helvetica,sans-serif;
165
+ text-align: center !important;
166
+ white-space: nowrap;
167
+ margin-top: 10px;
168
+ margin-left:10px;
169
+ margin-right:0px;
170
+ padding-top:1px;
171
+ padding-left:4px;
172
+ }
173
+
174
+ #image-annotate-edit-form button span {
175
+ padding: 0px 0px 5px 20px;
176
+ background-repeat: no-repeat;
177
+ line-height: 1.35em;
178
+ }
179
+
180
+ .image-annotate-edit-ok span {
181
+ background: url("../images/ok_btn_icon.png") no-repeat;
182
+ }
183
+ #image-annotate-edit-form button.image-annotate-edit-delete span{
184
+ padding: 1px 0px 5px 20px;
185
+ background: url(../images/delete_btn_icon.png) no-repeat;
186
+ }
187
+ .image-annotate-edit-close span {
188
+ background: url(../images/cancel_btn_icon.png) no-repeat;
189
+ }
190
+ .ui-resizable {
191
+ position: relative;
192
+ }
193
+ .ui-resizable-handle {
194
+ position: absolute;
195
+ font-size: 0.1px;
196
+ z-index: 99999;
197
+ display: block;
198
+ }
199
+ .ui-resizable-disabled .ui-resizable-handle, .ui-resizable- autohide .ui-resizable-handle {
200
+ display: block;
201
+ }
202
+ .ui-resizable-n {
203
+ cursor: n-resize;
204
+ height: 7px;
205
+ width: 100%;
206
+ top: -5px;
207
+ left: 0px;
208
+ }
209
+ .ui-resizable-s {
210
+ cursor: s-resize;
211
+ height: 7px;
212
+ width: 100%;
213
+ bottom: -5px;
214
+ left: 0px;
215
+ }
216
+ .ui-resizable-e {
217
+ cursor: e-resize;
218
+ width: 7px;
219
+ right: -5px;
220
+ top: 0px;
221
+ height: 100%;
222
+ }
223
+ .ui-resizable-w {
224
+ cursor: w-resize;
225
+ width: 7px;
226
+ left: -5px;
227
+ top: 0px;
228
+ height: 100%;
229
+ }
230
+ .ui-resizable-se {
231
+ cursor: se-resize;
232
+ width: 12px;
233
+ height: 12px;
234
+ right: 1px;
235
+ bottom: 1px;
236
+ }
237
+ .ui-resizable-sw {
238
+ cursor: sw-resize;
239
+ width: 9px;
240
+ height: 9px;
241
+ left: -5px;
242
+ bottom: -5px;
243
+ }
244
+ .ui-resizable-nw {
245
+ cursor: nw-resize;
246
+ width: 9px;
247
+ height: 9px;
248
+ left: -5px;
249
+ top: -5px;
250
+ }
251
+ .ui-resizable-ne {
252
+ cursor: ne-resize;
253
+ width: 9px;
254
+ height: 9px;
255
+ right: -5px;
256
+ top: -5px;
257
+ }
258
+
259
+ .hotspots-msg {
260
+ display:block;
261
+ position:absolute;
262
+ width:100%;
263
+ font-weight: bold;
264
+ text-align:center;
265
+ font-size:14px;
266
+ color: #FFFFFF;
267
+ text-shadow: #000000 2px 2px 6px;
268
+ }
269
+
270
+ .products-link{
271
+ display:block;
272
+ width:100%;
273
+ font-weight: bold;
274
+ text-align:center;
275
+ font-size:14px;
276
+ color: #FFFFFF;
277
+ padding-top: 10px;
278
+ padding-bottom: 30px;
279
+ }
280
+
281
+ .products-link a {
282
+ float:right;
283
+ padding-right: 16px;
284
+ background-image: url("../images/link_external.png");
285
+ background-repeat: no-repeat;
286
+ background-position: right center;
287
+ font-weight: normal;
288
+ color:#EA7601;
289
+ }
290
+ .image-annotate-area, .image-annotate-edit-area {
291
+ background-size: 30px,30px !important;
292
+ }
skin/adminhtml/default/default/productlookbook/css/fileuploader.css ADDED
@@ -0,0 +1,75 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ .qq-uploader { position:relative; display:block; float:left;}
2
+
3
+ .qq-upload-button {
4
+ background: url("../images/btn_bg.gif") repeat-x scroll 0 100% #FFAC47;
5
+ border-color: #ED6502 #A04300 #A04300 #ED6502;
6
+ border-style: solid;
7
+ border-width: 1px;
8
+ float:left;
9
+ color: #FFFFFF;
10
+ cursor: pointer;
11
+ font: bold 12px arial,helvetica,sans-serif;
12
+ padding: 4px 7px 3px 7px;
13
+ text-align: center !important;
14
+ white-space: nowrap;
15
+ }
16
+
17
+ .qq-upload-button span {
18
+ padding-left: 20px;
19
+ background-image: url("../images/upload_btn_icon.png");
20
+ background-repeat: no-repeat;
21
+ }
22
+
23
+ .qq-upload-button:hover {
24
+ background:#f77c16 url(../images/btn_over_bg.gif) repeat-x 0 0;
25
+ }
26
+
27
+ .qq-upload-button input {
28
+ cursor: pointer !important;
29
+ width:auto !important;
30
+ }
31
+
32
+ .qq-upload-drop-area {
33
+ position:absolute; top:0; left:0; width:100%; height:100%; min-height: 70px; z-index:2;
34
+ background:#FF9797; text-align:center;
35
+ }
36
+ .qq-upload-drop-area span {
37
+ display:block; position:absolute; top: 50%; width:100%; margin-top:-8px; font-size:16px;
38
+ }
39
+ .qq-upload-drop-area-active {background:#FF7171;}
40
+
41
+ .qq-upload-list {margin:6px; padding:0; list-style:none; float:left;}
42
+ .qq-upload-list li {font-size:12px;}
43
+ .qq-upload-file, .qq-upload-spinner, .qq-upload-remove, .qq-upload-size, .qq-upload-cancel, .qq-upload-failed-text {
44
+ margin-right: 7px;
45
+ }
46
+
47
+ .qq-upload-spinner {display:inline-block; background: url("../images/loading.gif"); width:15px; height:15px; vertical-align:text-bottom;}
48
+ .qq-upload-remove {display:none; background: url("../images/cancel.png"); width:17px; height:17px; vertical-align:text-bottom;}
49
+ .qq-upload-size,
50
+ .qq-upload-cancel {font-size:11px;}
51
+
52
+ .qq-upload-failed-text {display:none;}
53
+ .qq-upload-fail .qq-upload-failed-text {display:inline;}
54
+
55
+
56
+ #ProductlookbookImageBlock {
57
+ position:relative;
58
+ }
59
+ #maket_image {
60
+ margin-top:5px !important;
61
+ margin-bottom:5px !important;
62
+ position:relative;
63
+ float:left;
64
+ }
65
+
66
+ #productlookbook_form {
67
+ padding:30px 50px;
68
+ }
69
+ #productlookbook_form .form-list td.label {
70
+ width: 100px;
71
+ }
72
+
73
+ #productlookbook_form .form-list td.label label {
74
+ width: 75px;
75
+ }
skin/adminhtml/default/default/productlookbook/images/Thumbs.db ADDED
Binary file
skin/adminhtml/default/default/productlookbook/images/btn_bg.gif ADDED
Binary file
skin/adminhtml/default/default/productlookbook/images/btn_gray_bg.gif ADDED
Binary file
skin/adminhtml/default/default/productlookbook/images/btn_over_bg.gif ADDED
Binary file
skin/adminhtml/default/default/productlookbook/images/cancel_btn_icon.png ADDED
Binary file
skin/adminhtml/default/default/productlookbook/images/cross.png ADDED
Binary file
skin/adminhtml/default/default/productlookbook/images/delete_btn_icon.png ADDED
Binary file
skin/adminhtml/default/default/productlookbook/images/icon_btn_add.png ADDED
Binary file
skin/adminhtml/default/default/productlookbook/images/link_external.png ADDED
Binary file
skin/adminhtml/default/default/productlookbook/images/loading.gif ADDED
Binary file
skin/adminhtml/default/default/productlookbook/images/ok_btn_icon.png ADDED
Binary file
skin/adminhtml/default/default/productlookbook/images/upload_btn_icon.png ADDED
Binary file
skin/frontend/base/default/productlookbook/css/hotspots.css ADDED
@@ -0,0 +1,608 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ /**************************
2
+ *
3
+ * GENERAL
4
+ *
5
+ **************************/
6
+ .camera_wrap a, .camera_wrap img,
7
+ .camera_wrap ol, .camera_wrap ul, .camera_wrap li,
8
+ .camera_wrap table, .camera_wrap tbody, .camera_wrap tfoot, .camera_wrap thead, .camera_wrap tr, .camera_wrap th, .camera_wrap td
9
+ .camera_thumbs_wrap a, .camera_thumbs_wrap img,
10
+ .camera_thumbs_wrap ol, .camera_thumbs_wrap ul, .camera_thumbs_wrap li,
11
+ .camera_thumbs_wrap table, .camera_thumbs_wrap tbody, .camera_thumbs_wrap tfoot, .camera_thumbs_wrap thead, .camera_thumbs_wrap tr, .camera_thumbs_wrap th, .camera_thumbs_wrap td {
12
+ background: none;
13
+ border: 0;
14
+ font: inherit;
15
+ font-size: 100%;
16
+ margin: 0;
17
+ padding: 0;
18
+ vertical-align: baseline;
19
+ list-style: none
20
+ }
21
+ .camera_wrap {
22
+ display: none;
23
+ float: left;
24
+ position: relative;
25
+ z-index: 0;
26
+ }
27
+ .camera_wrap img {
28
+ max-width: none!important;
29
+ }
30
+ .camera_fakehover {
31
+ height: 100%;
32
+ min-height: 60px;
33
+ position: relative;
34
+ width: 100%;
35
+ z-index: 1;
36
+ }
37
+ .camera_wrap {
38
+ width: 100%;
39
+ }
40
+ .camera_src {
41
+ display: none;
42
+ }
43
+ .cameraCont, .cameraContents {
44
+ height: 100%;
45
+ position: relative;
46
+ width: 100%;
47
+ z-index: 1;
48
+ }
49
+ .cameraSlide {
50
+ bottom: 0;
51
+ left: 0;
52
+ position: absolute;
53
+ right: 0;
54
+ top: 0;
55
+ width: 100%;
56
+ }
57
+ .cameraContent {
58
+ bottom: 0;
59
+ display: none;
60
+ left: 0;
61
+ position: absolute;
62
+ right: 0;
63
+ top: 0;
64
+ width: 100%;
65
+ }
66
+ .camera_target {
67
+ bottom: 0;
68
+ height: 100%;
69
+ left: 0;
70
+ overflow: hidden;
71
+ position: absolute;
72
+ right: 0;
73
+ text-align: left;
74
+ top: 0;
75
+ width: 100%;
76
+ z-index: 0;
77
+ }
78
+ .camera_overlayer {
79
+ bottom: 0;
80
+ height: 100%;
81
+ left: 0;
82
+ overflow: hidden;
83
+ position: absolute;
84
+ right: 0;
85
+ top: 0;
86
+ width: 100%;
87
+ z-index: 0;
88
+ }
89
+ .camera_target_content {
90
+ bottom: 0;
91
+ left: 0;
92
+ overflow: hidden;
93
+ position: absolute;
94
+ right: 0;
95
+ top: 0;
96
+ z-index: 2;
97
+ }
98
+ .camera_target_content .camera_link {
99
+ background: url(../images/blank.gif);
100
+ display: block;
101
+ height: 100%;
102
+ text-decoration: none;
103
+ }
104
+ .camera_loader {
105
+ background: #fff url(../images/camera-loader.gif) no-repeat center;
106
+ background: rgba(255, 255, 255, 0.9) url(../images/camera-loader.gif) no-repeat center;
107
+ border: 1px solid #ffffff;
108
+ -webkit-border-radius: 18px;
109
+ -moz-border-radius: 18px;
110
+ border-radius: 18px;
111
+ height: 36px;
112
+ left: 50%;
113
+ overflow: hidden;
114
+ position: absolute;
115
+ margin: -18px 0 0 -18px;
116
+ top: 50%;
117
+ width: 36px;
118
+ z-index: 3;
119
+ }
120
+ .camera_bar {
121
+ bottom: 0;
122
+ left: 0;
123
+ overflow: hidden;
124
+ position: absolute;
125
+ right: 0;
126
+ top: 0;
127
+ z-index: 3;
128
+ }
129
+ .camera_thumbs_wrap.camera_left .camera_bar, .camera_thumbs_wrap.camera_right .camera_bar {
130
+ height: 100%;
131
+ position: absolute;
132
+ width: auto;
133
+ }
134
+ .camera_thumbs_wrap.camera_bottom .camera_bar, .camera_thumbs_wrap.camera_top .camera_bar {
135
+ height: auto;
136
+ position: absolute;
137
+ width: 100%;
138
+ }
139
+ .camera_nav_cont {
140
+ height: 65px;
141
+ overflow: hidden;
142
+ position: absolute;
143
+ right: 9px;
144
+ top: 15px;
145
+ width: 120px;
146
+ z-index: 4;
147
+ }
148
+ .camera_caption {
149
+ bottom: 0;
150
+ display: block;
151
+ position: absolute;
152
+ width: 100%;
153
+ }
154
+ .camera_caption > div {
155
+ padding: 10px 20px;
156
+ }
157
+ .camerarelative {
158
+ overflow: hidden;
159
+ position: relative;
160
+ }
161
+ .imgFake {
162
+ cursor: pointer;
163
+ }
164
+ .camera_prevThumbs {
165
+ bottom: 4px;
166
+ cursor: pointer;
167
+ left: 0;
168
+ position: absolute;
169
+ top: 4px;
170
+ visibility: hidden;
171
+ width: 30px;
172
+ z-index: 10;
173
+ }
174
+ .camera_prevThumbs div {
175
+ background: url(../images/camera_skins.png) no-repeat -160px 0;
176
+ display: block;
177
+ height: 40px;
178
+ margin-top: -20px;
179
+ position: absolute;
180
+ top: 50%;
181
+ width: 30px;
182
+ }
183
+ .camera_nextThumbs {
184
+ bottom: 4px;
185
+ cursor: pointer;
186
+ position: absolute;
187
+ right: 0;
188
+ top: 4px;
189
+ visibility: hidden;
190
+ width: 30px;
191
+ z-index: 10;
192
+ }
193
+ .camera_nextThumbs div {
194
+ background: url(../images/camera_skins.png) no-repeat -190px 0;
195
+ display: block;
196
+ height: 40px;
197
+ margin-top: -20px;
198
+ position: absolute;
199
+ top: 50%;
200
+ width: 30px;
201
+ }
202
+ .camera_command_wrap .hideNav {
203
+ display: none;
204
+ }
205
+ .camera_command_wrap {
206
+ left: 0;
207
+ position: relative;
208
+ right:0;
209
+ z-index: 4;
210
+ }
211
+ .camera_wrap .camera_pag .camera_pag_ul {
212
+ list-style: none;
213
+ margin: 0;
214
+ padding: 0;
215
+ text-align: right;
216
+ }
217
+ .camera_wrap .camera_pag .camera_pag_ul li {
218
+ -webkit-border-radius: 8px;
219
+ -moz-border-radius: 8px;
220
+ border-radius: 8px;
221
+ cursor: pointer;
222
+ display: inline-block;
223
+ height: 16px;
224
+ margin: 20px 5px;
225
+ position: relative;
226
+ text-align: left;
227
+ text-indent: -9999px;
228
+ width: 16px;
229
+ }
230
+ .camera_commands_emboss .camera_pag .camera_pag_ul li {
231
+ -moz-box-shadow:
232
+ 0px 1px 0px rgba(255,255,255,1),
233
+ inset 0px 1px 1px rgba(0,0,0,0.2);
234
+ -webkit-box-shadow:
235
+ 0px 1px 0px rgba(255,255,255,1),
236
+ inset 0px 1px 1px rgba(0,0,0,0.2);
237
+ box-shadow:
238
+ 0px 1px 0px rgba(255,255,255,1),
239
+ inset 0px 1px 1px rgba(0,0,0,0.2);
240
+ }
241
+ .camera_wrap .camera_pag .camera_pag_ul li > span {
242
+ -webkit-border-radius: 5px;
243
+ -moz-border-radius: 5px;
244
+ border-radius: 5px;
245
+ height: 8px;
246
+ left: 4px;
247
+ overflow: hidden;
248
+ position: absolute;
249
+ top: 4px;
250
+ width: 8px;
251
+ }
252
+ .camera_commands_emboss .camera_pag .camera_pag_ul li:hover > span {
253
+ -moz-box-shadow:
254
+ 0px 1px 0px rgba(255,255,255,1),
255
+ inset 0px 1px 1px rgba(0,0,0,0.2);
256
+ -webkit-box-shadow:
257
+ 0px 1px 0px rgba(255,255,255,1),
258
+ inset 0px 1px 1px rgba(0,0,0,0.2);
259
+ box-shadow:
260
+ 0px 1px 0px rgba(255,255,255,1),
261
+ inset 0px 1px 1px rgba(0,0,0,0.2);
262
+ }
263
+ .camera_wrap .camera_pag .camera_pag_ul li.cameracurrent > span {
264
+ -moz-box-shadow: 0;
265
+ -webkit-box-shadow: 0;
266
+ box-shadow: 0;
267
+ }
268
+ .camera_pag_ul li img {
269
+ display: none;
270
+ position: absolute;
271
+ }
272
+ .camera_pag_ul .thumb_arrow {
273
+ border-left: 4px solid transparent;
274
+ border-right: 4px solid transparent;
275
+ border-top: 4px solid;
276
+ top: 0;
277
+ left: 50%;
278
+ margin-left: -4px;
279
+ position: absolute;
280
+ }
281
+ .camera_prev, .camera_next, .camera_commands {
282
+ cursor: pointer;
283
+ height: 40px;
284
+ margin-top: -20px;
285
+ position: absolute;
286
+ top: 50%;
287
+ width: 40px;
288
+ z-index: 2;
289
+ }
290
+ .camera_prev {
291
+ left: 0;
292
+ }
293
+ .camera_prev > span {
294
+ background: url(../images/camera_skins.png) no-repeat 0 0;
295
+ display: block;
296
+ height: 40px;
297
+ width: 40px;
298
+ }
299
+ .camera_next {
300
+ right: 0;
301
+ }
302
+ .camera_next > span {
303
+ background: url(../images/camera_skins.png) no-repeat -40px 0;
304
+ display: block;
305
+ height: 40px;
306
+ width: 40px;
307
+ }
308
+ .camera_commands {
309
+ right: 41px;
310
+ }
311
+ .camera_commands > .camera_play {
312
+ background: url(../images/camera_skins.png) no-repeat -80px 0;
313
+ height: 40px;
314
+ width: 40px;
315
+ }
316
+ .camera_commands > .camera_stop {
317
+ background: url(../images/camera_skins.png) no-repeat -120px 0;
318
+ display: block;
319
+ height: 40px;
320
+ width: 40px;
321
+ }
322
+ .camera_wrap .camera_pag .camera_pag_ul li {
323
+ -webkit-border-radius: 8px;
324
+ -moz-border-radius: 8px;
325
+ border-radius: 8px;
326
+ cursor: pointer;
327
+ display: inline-block;
328
+ height: 16px;
329
+ margin: 20px 5px;
330
+ position: relative;
331
+ text-indent: -9999px;
332
+ width: 16px;
333
+ }
334
+ .camera_thumbs_cont {
335
+ -webkit-border-bottom-right-radius: 4px;
336
+ -webkit-border-bottom-left-radius: 4px;
337
+ -moz-border-radius-bottomright: 4px;
338
+ -moz-border-radius-bottomleft: 4px;
339
+ border-bottom-right-radius: 4px;
340
+ border-bottom-left-radius: 4px;
341
+ overflow: hidden;
342
+ position: relative;
343
+ width: 100%;
344
+ }
345
+ .camera_commands_emboss .camera_thumbs_cont {
346
+ -moz-box-shadow:
347
+ 0px 1px 0px rgba(255,255,255,1),
348
+ inset 0px 1px 1px rgba(0,0,0,0.2);
349
+ -webkit-box-shadow:
350
+ 0px 1px 0px rgba(255,255,255,1),
351
+ inset 0px 1px 1px rgba(0,0,0,0.2);
352
+ box-shadow:
353
+ 0px 1px 0px rgba(255,255,255,1),
354
+ inset 0px 1px 1px rgba(0,0,0,0.2);
355
+ }
356
+ .camera_thumbs_cont > div {
357
+ float: left;
358
+ width: 100%;
359
+ }
360
+ .camera_thumbs_cont ul {
361
+ overflow: hidden;
362
+ padding: 3px 4px 8px;
363
+ position: relative;
364
+ text-align: center;
365
+ }
366
+ .camera_thumbs_cont ul li {
367
+ display: inline;
368
+ padding: 0 4px;
369
+ }
370
+ .camera_thumbs_cont ul li > img {
371
+ border: 1px solid;
372
+ cursor: pointer;
373
+ margin-top: 5px;
374
+ vertical-align:bottom;
375
+ }
376
+ .camera_clear {
377
+ display: block;
378
+ clear: both;
379
+ }
380
+ .showIt {
381
+ display: none;
382
+ }
383
+ .camera_clear {
384
+ clear: both;
385
+ display: block;
386
+ height: 1px;
387
+ margin: -1px 0 25px;
388
+ position: relative;
389
+ }
390
+ /**************************
391
+ *
392
+ * COLORS & SKINS
393
+ *
394
+ **************************/
395
+ .pattern_1 .camera_overlayer {
396
+ background: url(../images/patterns/overlay1.png) repeat;
397
+ }
398
+ .pattern_2 .camera_overlayer {
399
+ background: url(../images/patterns/overlay2.png) repeat;
400
+ }
401
+ .pattern_3 .camera_overlayer {
402
+ background: url(../images/patterns/overlay3.png) repeat;
403
+ }
404
+ .pattern_4 .camera_overlayer {
405
+ background: url(../images/patterns/overlay4.png) repeat;
406
+ }
407
+ .pattern_5 .camera_overlayer {
408
+ background: url(../images/patterns/overlay5.png) repeat;
409
+ }
410
+ .pattern_6 .camera_overlayer {
411
+ background: url(../images/patterns/overlay6.png) repeat;
412
+ }
413
+ .pattern_7 .camera_overlayer {
414
+ background: url(../images/patterns/overlay7.png) repeat;
415
+ }
416
+ .pattern_8 .camera_overlayer {
417
+ background: url(../images/patterns/overlay8.png) repeat;
418
+ }
419
+ .pattern_9 .camera_overlayer {
420
+ background: url(../images/patterns/overlay9.png) repeat;
421
+ }
422
+ .pattern_10 .camera_overlayer {
423
+ background: url(../images/patterns/overlay10.png) repeat;
424
+ }
425
+ .camera_caption {
426
+ color: #fff;
427
+ }
428
+ .camera_caption > div {
429
+ background: #000;
430
+ background: rgba(0, 0, 0, 0.8);
431
+ }
432
+ .camera_wrap .camera_pag .camera_pag_ul li {
433
+ background: #b7b7b7;
434
+ }
435
+ .camera_wrap .camera_pag .camera_pag_ul li:hover > span {
436
+ background: #b7b7b7;
437
+ }
438
+ .camera_wrap .camera_pag .camera_pag_ul li.cameracurrent > span {
439
+ background: #434648;
440
+ }
441
+ .camera_pag_ul li img {
442
+ border: 4px solid #e6e6e6;
443
+ -moz-box-shadow: 0px 3px 6px rgba(0,0,0,.5);
444
+ -webkit-box-shadow: 0px 3px 6px rgba(0,0,0,.5);
445
+ box-shadow: 0px 3px 6px rgba(0,0,0,.5);
446
+ }
447
+ .camera_pag_ul .thumb_arrow {
448
+ border-top-color: #e6e6e6;
449
+ }
450
+ .camera_prevThumbs, .camera_nextThumbs, .camera_prev, .camera_next, .camera_commands, .camera_thumbs_cont {
451
+ background: #d8d8d8;
452
+ background: rgba(216, 216, 216, 0.85);
453
+ }
454
+ .camera_wrap .camera_pag .camera_pag_ul li {
455
+ background: #b7b7b7;
456
+ }
457
+ .camera_thumbs_cont ul li > img {
458
+ border-color: 1px solid #000;
459
+ }
460
+ /*BLACK SKIN*/
461
+ .camera_black_skin .camera_prevThumbs div {
462
+ background-position: -160px -40px;
463
+ }
464
+ .camera_black_skin .camera_nextThumbs div {
465
+ background-position: -190px -40px;
466
+ }
467
+ .camera_black_skin .camera_prev > span {
468
+ background-position: 0 -40px;
469
+ }
470
+ .camera_black_skin .camera_next > span {
471
+ background-position: -40px -40px;
472
+ }
473
+ .camera_black_skin .camera_commands > .camera_play {
474
+ background-position: -80px -40px;
475
+ }
476
+ .camera_black_skin .camera_commands > .camera_stop {
477
+ background-position: -120px -40px;
478
+ }
479
+
480
+ /*Hotspots*/
481
+ .content-before, .content-after {
482
+ display: block;
483
+ clear:both;
484
+ }
485
+ .hotspot {
486
+ position:absolute;
487
+ }
488
+
489
+ .hotspot:hover .product-info {
490
+ display:block;
491
+ }
492
+
493
+ .hotspot:hover .hotspot-icon {
494
+ z-index:101;
495
+ }
496
+
497
+ .product-info {
498
+ background: url(../images/info-bg.png) repeat 0 0 transparent;
499
+ border-top: 2px solid #FFFFFF;
500
+ color: #686767;
501
+ overflow:hidden;
502
+ font: normal 12px Tahoma,Arial;
503
+ min-width: 100px;
504
+ max-width: 200px;
505
+ padding: 12px;
506
+ position: absolute;
507
+ display:none;
508
+ z-index:100;
509
+
510
+ -webkit-border-radius: 4px;
511
+ -moz-border-radius: 4px;
512
+ border-radius: 4px;
513
+ -webkit-box-shadow: #666 2px 2px 3px;
514
+ -moz-box-shadow: #666 2px 2px 3px;
515
+ box-shadow: #666 2px 2px 3px;
516
+ }
517
+
518
+ #productlookbook {
519
+ position:relative;
520
+ }
521
+
522
+ #adv_link {
523
+ position:absolute;
524
+ background : url(../images/adv-bg.png) no-repeat 0 0;
525
+ width:188px;
526
+ height: 76px;
527
+ right: 0px;
528
+ top: 0px;
529
+ display:block;
530
+ color: #e6d3cc;
531
+ font-size: 12px;
532
+ font-family: Arial;
533
+ text-align: right;
534
+ display:none;
535
+ }
536
+
537
+ #adv_link div{
538
+ margin-top: 8px;
539
+ margin-right: 12px;
540
+ position: absolute;
541
+ z-index: 105;
542
+ top: 0px;
543
+ right: 0px;
544
+ }
545
+
546
+ #adv_link a{
547
+ color: #e6d3cc;
548
+ font-size: 12px;
549
+ font-family: Arial;
550
+ }
551
+
552
+ .hotspot {
553
+ position:absolute;
554
+ }
555
+
556
+ .hotspot:hover .product-info {
557
+ display:block;
558
+ }
559
+
560
+ .hotspot:hover .hotspot-icon {
561
+ z-index:101;
562
+ }
563
+
564
+ .product-info {
565
+ background: url(../images/info-bg.png) repeat 0 0 transparent;
566
+ border-top: 2px solid #FFFFFF;
567
+ color: #686767;
568
+ overflow:hidden;
569
+ font: normal 12px Tahoma,Arial;
570
+ min-width: 100px;
571
+ max-width: 200px;
572
+ padding: 12px;
573
+ position: absolute;
574
+ display:none;
575
+ z-index:100;
576
+
577
+ -webkit-border-radius: 4px;
578
+ -moz-border-radius: 4px;
579
+ border-radius: 4px;
580
+ -webkit-box-shadow: #666 2px 2px 3px;
581
+ -moz-box-shadow: #666 2px 2px 3px;
582
+ box-shadow: #666 2px 2px 3px;
583
+ }
584
+
585
+ .product-info a {
586
+ color: #686767;
587
+ font: normal 12px Tahoma,Arial;
588
+ }
589
+
590
+ .product-info .price {
591
+ font: bold 12px Tahoma,Arial;
592
+ color: #7dad01;
593
+ padding-top: 8px;
594
+ }
595
+ .product-info .price .old-price{
596
+ font: bold 11px Tahoma,Arial;
597
+ color: #686767;
598
+ text-decoration: line-through;
599
+ }
600
+
601
+ .product-info .out-of-stock {
602
+ margin-top:5px;
603
+ color: #D83820;
604
+ }
605
+
606
+ .hotspot-icon {
607
+ position: absolute;
608
+ }
skin/frontend/base/default/productlookbook/images/Thumbs.db ADDED
Binary file
skin/frontend/base/default/productlookbook/images/adv-bg.png ADDED
Binary file
skin/frontend/base/default/productlookbook/images/camera-loader.gif ADDED
Binary file
skin/frontend/base/default/productlookbook/images/camera_skins.png ADDED
Binary file
skin/frontend/base/default/productlookbook/images/caption-bg.png ADDED
Binary file
skin/frontend/base/default/productlookbook/images/info-bg.png ADDED
Binary file
skin/frontend/base/default/productlookbook/images/patterns/Thumbs.db ADDED
Binary file
skin/frontend/base/default/productlookbook/images/patterns/overlay1.png ADDED
Binary file
skin/frontend/base/default/productlookbook/images/patterns/overlay10.png ADDED
Binary file
skin/frontend/base/default/productlookbook/images/patterns/overlay2.png ADDED
Binary file
skin/frontend/base/default/productlookbook/images/patterns/overlay3.png ADDED
Binary file
skin/frontend/base/default/productlookbook/images/patterns/overlay4.png ADDED
Binary file
skin/frontend/base/default/productlookbook/images/patterns/overlay5.png ADDED
Binary file
skin/frontend/base/default/productlookbook/images/patterns/overlay6.png ADDED
Binary file
skin/frontend/base/default/productlookbook/images/patterns/overlay7.png ADDED
Binary file
skin/frontend/base/default/productlookbook/images/patterns/overlay8.png ADDED
Binary file
skin/frontend/base/default/productlookbook/images/patterns/overlay9.png ADDED
Binary file
skin/frontend/base/default/productlookbook/js/camera.min.js ADDED
@@ -0,0 +1,4 @@
 
 
 
 
1
+ // Camera slideshow v1.3.3 - a jQuery slideshow with many effects, transitions, easy to customize, using canvas and mobile ready, based on jQuery 1.4+
2
+ // Copyright (c) 2012 by Manuel Masia - www.pixedelic.com
3
+ // Licensed under the MIT license: http://www.opensource.org/licenses/mit-license.php
4
+ ;(function(a){a.fn.camera=function(b,c){function e(){if(navigator.userAgent.match(/Android/i)||navigator.userAgent.match(/webOS/i)||navigator.userAgent.match(/iPad/i)||navigator.userAgent.match(/iPhone/i)||navigator.userAgent.match(/iPod/i)){return true}}function H(){var b=a(s).width();a("li",s).removeClass("camera_visThumb");a("li",s).each(function(){var c=a(this).position(),d=a("ul",s).outerWidth(),e=a("ul",s).offset().left,f=a("> div",s).offset().left,g=f-e;if(g>0){a(".camera_prevThumbs",V).removeClass("hideNav")}else{a(".camera_prevThumbs",V).addClass("hideNav")}if(d-g>b){a(".camera_nextThumbs",V).removeClass("hideNav")}else{a(".camera_nextThumbs",V).addClass("hideNav")}var h=c.left,i=c.left+a(this).width();if(i-g<=b&&h-g>=0){a(this).addClass("camera_visThumb")}})}function K(){function d(){t=f.width();if(b.height.indexOf("%")!=-1){var c=Math.round(t/(100/parseFloat(b.height)));if(b.minHeight!=""&&c<parseFloat(b.minHeight)){u=parseFloat(b.minHeight)}else{u=c}f.css({height:u})}else if(b.height=="auto"){u=f.height()}else{u=parseFloat(b.height);f.css({height:u})}a(".camerarelative",k).css({width:t,height:u});a(".imgLoaded",k).each(function(){var c=a(this),d=c.attr("width"),e=c.attr("height"),f=c.index(),g,h,i=c.attr("data-alignment"),j=c.attr("data-portrait");if(typeof i==="undefined"||i===false||i===""){i=b.alignment}if(typeof j==="undefined"||j===false||j===""){j=b.portrait}if(j==false||j=="false"){if(d/e<t/u){var k=t/d;var l=Math.abs(u-e*k)*.5;switch(i){case"topLeft":g=0;break;case"topCenter":g=0;break;case"topRight":g=0;break;case"centerLeft":g="-"+l+"px";break;case"center":g="-"+l+"px";break;case"centerRight":g="-"+l+"px";break;case"bottomLeft":g="-"+l*2+"px";break;case"bottomCenter":g="-"+l*2+"px";break;case"bottomRight":g="-"+l*2+"px";break}c.css({height:e*k,"margin-left":0,"margin-top":g,position:"absolute",visibility:"visible",width:t})}else{var k=u/e;var l=Math.abs(t-d*k)*.5;switch(i){case"topLeft":h=0;break;case"topCenter":h="-"+l+"px";break;case"topRight":h="-"+l*2+"px";break;case"centerLeft":h=0;break;case"center":h="-"+l+"px";break;case"centerRight":h="-"+l*2+"px";break;case"bottomLeft":h=0;break;case"bottomCenter":h="-"+l+"px";break;case"bottomRight":h="-"+l*2+"px";break}c.css({height:u,"margin-left":h,"margin-top":0,position:"absolute",visibility:"visible",width:d*k})}}else{if(d/e<t/u){var k=u/e;var l=Math.abs(t-d*k)*.5;switch(i){case"topLeft":h=0;break;case"topCenter":h=l+"px";break;case"topRight":h=l*2+"px";break;case"centerLeft":h=0;break;case"center":h=l+"px";break;case"centerRight":h=l*2+"px";break;case"bottomLeft":h=0;break;case"bottomCenter":h=l+"px";break;case"bottomRight":h=l*2+"px";break}c.css({height:u,"margin-left":h,"margin-top":0,position:"absolute",visibility:"visible",width:d*k})}else{var k=t/d;var l=Math.abs(u-e*k)*.5;switch(i){case"topLeft":g=0;break;case"topCenter":g=0;break;case"topRight":g=0;break;case"centerLeft":g=l+"px";break;case"center":g=l+"px";break;case"centerRight":g=l+"px";break;case"bottomLeft":g=l*2+"px";break;case"bottomCenter":g=l*2+"px";break;case"bottomRight":g=l*2+"px";break}c.css({height:e*k,"margin-left":0,"margin-top":g,position:"absolute",visibility:"visible",width:t})}}})}var c;if(I==true){clearTimeout(c);c=setTimeout(d,200)}else{d()}I=true}function X(a){for(var b,c,d=a.length;d;b=parseInt(Math.random()*d),c=a[--d],a[d]=a[b],a[b]=c);return a}function Y(a){return Math.ceil(a)==Math.floor(a)}function hb(){if(a(s).length&&!a(r).length){var b=a(s).outerWidth(),c=a("ul > li",s).outerWidth(),d=a("li.cameracurrent",s).length?a("li.cameracurrent",s).position():"",e=a("ul > li",s).length*a("ul > li",s).outerWidth(),g=a("ul",s).offset().left,h=a("> div",s).offset().left,i;if(g<0){i="-"+(h-g)}else{i=h-g}if(gb==true){a("ul",s).width(a("ul > li",s).length*a("ul > li",s).outerWidth());if(a(s).length&&!a(r).lenght){f.css({marginBottom:a(s).outerHeight()})}H();a("ul",s).width(a("ul > li",s).length*a("ul > li",s).outerWidth());if(a(s).length&&!a(r).lenght){f.css({marginBottom:a(s).outerHeight()})}}gb=false;var j=a("li.cameracurrent",s).length?d.left:"",k=a("li.cameracurrent",s).length?d.left+a("li.cameracurrent",s).outerWidth():"";if(j<a("li.cameracurrent",s).outerWidth()){j=0}if(k-i>b){if(j+b<e){a("ul",s).animate({"margin-left":"-"+j+"px"},500,H)}else{a("ul",s).animate({"margin-left":"-"+(a("ul",s).outerWidth()-b)+"px"},500,H)}}else if(j-i<0){a("ul",s).animate({"margin-left":"-"+j+"px"},500,H)}else{a("ul",s).css({"margin-left":"auto","margin-right":"auto"});setTimeout(H,100)}}}function ib(){bb=0;var c=a(".camera_bar_cont",V).width(),d=a(".camera_bar_cont",V).height();if(h!="pie"){switch(U){case"leftToRight":a("#"+i).css({right:c});break;case"rightToLeft":a("#"+i).css({left:c});break;case"topToBottom":a("#"+i).css({bottom:d});break;case"bottomToTop":a("#"+i).css({top:d});break}}else{db.clearRect(0,0,b.pieDiameter,b.pieDiameter)}}function jb(c){j.addClass("camerasliding");R=false;var d=parseFloat(a("div.cameraSlide.cameracurrent",k).index());if(c>0){var l=c-1}else if(d==B-1){var l=0}else{var l=d+1}var m=a(".cameraSlide:eq("+l+")",k);var n=a(".cameraSlide:eq("+(l+1)+")",k).addClass("cameranext");if(d!=l+1){n.hide()}a(".cameraContent",g).fadeOut(600);a(".camera_caption",g).show();a(".camerarelative",m).append(a("> div ",j).eq(l).find("> div.camera_effected"));a(".camera_target_content .cameraContent:eq("+l+")",f).append(a("> div ",j).eq(l).find("> div"));if(!a(".imgLoaded",m).length){var o=v[l];var p=new Image;p.src=o+"?"+(new Date).getTime();m.css("visibility","hidden");m.prepend(a(p).attr("class","imgLoaded").css("visibility","hidden"));var q,w;if(!a(p).get(0).complete||q=="0"||w=="0"||typeof q==="undefined"||q===false||typeof w==="undefined"||w===false){a(".camera_loader",f).delay(500).fadeIn(400);p.onload=function(){q=p.naturalWidth;w=p.naturalHeight;a(p).attr("data-alignment",z[l]).attr("data-portrait",y[l]);a(p).attr("width",q);a(p).attr("height",w);k.find(".cameraSlide_"+l).hide().css("visibility","visible");K();jb(l+1)}}}else{if(v.length>l+1&&!a(".imgLoaded",n).length){var x=v[l+1];var A=new Image;A.src=x+"?"+(new Date).getTime();n.prepend(a(A).attr("class","imgLoaded").css("visibility","hidden"));A.onload=function(){q=A.naturalWidth;w=A.naturalHeight;a(A).attr("data-alignment",z[l+1]).attr("data-portrait",y[l+1]);a(A).attr("width",q);a(A).attr("height",w);K()}}b.onLoaded.call(this);if(a(".camera_loader",f).is(":visible")){a(".camera_loader",f).fadeOut(400)}else{a(".camera_loader",f).css({visibility:"hidden"});a(".camera_loader",f).fadeOut(400,function(){a(".camera_loader",f).css({visibility:"visible"})})}var C=b.rows,D=b.cols,F=1,G=0,H,I,J,N,O,P=new Array("simpleFade","curtainTopLeft","curtainTopRight","curtainBottomLeft","curtainBottomRight","curtainSliceLeft","curtainSliceRight","blindCurtainTopLeft","blindCurtainTopRight","blindCurtainBottomLeft","blindCurtainBottomRight","blindCurtainSliceBottom","blindCurtainSliceTop","stampede","mosaic","mosaicReverse","mosaicRandom","mosaicSpiral","mosaicSpiralReverse","topLeftBottomRight","bottomRightTopLeft","bottomLeftTopRight","topRightBottomLeft","scrollLeft","scrollRight","scrollTop","scrollBottom","scrollHorz");marginLeft=0,marginTop=0,opacityOnGrid=0;if(b.opacityOnGrid==true){opacityOnGrid=0}else{opacityOnGrid=1}var Q=a(" > div",j).eq(l).attr("data-fx");if(e()&&b.mobileFx!=""&&b.mobileFx!="default"){N=b.mobileFx}else{if(typeof Q!=="undefined"&&Q!==false&&Q!=="default"){N=Q}else{N=b.fx}}if(N=="random"){N=X(P);N=N[0]}else{N=N;if(N.indexOf(",")>0){N=N.replace(/ /g,"");N=N.split(",");N=X(N);N=N[0]}}dataEasing=a(" > div",j).eq(l).attr("data-easing");mobileEasing=a(" > div",j).eq(l).attr("data-mobileEasing");if(e()&&b.mobileEasing!=""&&b.mobileEasing!="default"){if(typeof mobileEasing!=="undefined"&&mobileEasing!==false&&mobileEasing!=="default"){O=mobileEasing}else{O=b.mobileEasing}}else{if(typeof dataEasing!=="undefined"&&dataEasing!==false&&dataEasing!=="default"){O=dataEasing}else{O=b.easing}}H=a(" > div",j).eq(l).attr("data-slideOn");if(typeof H!=="undefined"&&H!==false){T=H}else{if(b.slideOn=="random"){var T=new Array("next","prev");T=X(T);T=T[0]}else{T=b.slideOn}}var Y=a(" > div",j).eq(l).attr("data-time");if(typeof Y!=="undefined"&&Y!==false&&Y!==""){I=parseFloat(Y)}else{I=b.time}var Z=a(" > div",j).eq(l).attr("data-transPeriod");if(typeof Z!=="undefined"&&Z!==false&&Z!==""){J=parseFloat(Z)}else{J=b.transPeriod}if(!a(j).hasClass("camerastarted")){N="simpleFade";T="next";O="";J=400;a(j).addClass("camerastarted")}switch(N){case"simpleFade":D=1;C=1;break;case"curtainTopLeft":if(b.slicedCols==0){D=b.cols}else{D=b.slicedCols}C=1;break;case"curtainTopRight":if(b.slicedCols==0){D=b.cols}else{D=b.slicedCols}C=1;break;case"curtainBottomLeft":if(b.slicedCols==0){D=b.cols}else{D=b.slicedCols}C=1;break;case"curtainBottomRight":if(b.slicedCols==0){D=b.cols}else{D=b.slicedCols}C=1;break;case"curtainSliceLeft":if(b.slicedCols==0){D=b.cols}else{D=b.slicedCols}C=1;break;case"curtainSliceRight":if(b.slicedCols==0){D=b.cols}else{D=b.slicedCols}C=1;break;case"blindCurtainTopLeft":if(b.slicedRows==0){C=b.rows}else{C=b.slicedRows}D=1;break;case"blindCurtainTopRight":if(b.slicedRows==0){C=b.rows}else{C=b.slicedRows}D=1;break;case"blindCurtainBottomLeft":if(b.slicedRows==0){C=b.rows}else{C=b.slicedRows}D=1;break;case"blindCurtainBottomRight":if(b.slicedRows==0){C=b.rows}else{C=b.slicedRows}D=1;break;case"blindCurtainSliceTop":if(b.slicedRows==0){C=b.rows}else{C=b.slicedRows}D=1;break;case"blindCurtainSliceBottom":if(b.slicedRows==0){C=b.rows}else{C=b.slicedRows}D=1;break;case"stampede":G="-"+J;break;case"mosaic":G=b.gridDifference;break;case"mosaicReverse":G=b.gridDifference;break;case"mosaicRandom":break;case"mosaicSpiral":G=b.gridDifference;F=1.7;break;case"mosaicSpiralReverse":G=b.gridDifference;F=1.7;break;case"topLeftBottomRight":G=b.gridDifference;F=6;break;case"bottomRightTopLeft":G=b.gridDifference;F=6;break;case"bottomLeftTopRight":G=b.gridDifference;F=6;break;case"topRightBottomLeft":G=b.gridDifference;F=6;break;case"scrollLeft":D=1;C=1;break;case"scrollRight":D=1;C=1;break;case"scrollTop":D=1;C=1;break;case"scrollBottom":D=1;C=1;break;case"scrollHorz":D=1;C=1;break}var _=0;var ab=C*D;var eb=t-Math.floor(t/D)*D;var fb=u-Math.floor(u/C)*C;var gb;var kb;var lb=0;var mb=0;var nb=new Array;var ob=new Array;var pb=new Array;while(_<ab){nb.push(_);ob.push(_);E.append('<div class="cameraappended" style="display:none; overflow:hidden; position:absolute; z-index:1000" />');var qb=a(".cameraappended:eq("+_+")",k);if(N=="scrollLeft"||N=="scrollRight"||N=="scrollTop"||N=="scrollBottom"||N=="scrollHorz"){S.eq(l).clone().show().appendTo(qb)}else{if(T=="next"){S.eq(l).clone().show().appendTo(qb)}else{S.eq(d).clone().show().appendTo(qb)}}if(_%D<eb){gb=1}else{gb=0}if(_%D==0){lb=0}if(Math.floor(_/D)<fb){kb=1}else{kb=0}qb.css({height:Math.floor(u/C+kb+1),left:lb,top:mb,width:Math.floor(t/D+gb+1)});a("> .cameraSlide",qb).css({height:u,"margin-left":"-"+lb+"px","margin-top":"-"+mb+"px",width:t});lb=lb+qb.width()-1;if(_%D==D-1){mb=mb+qb.height()-1}_++}switch(N){case"curtainTopLeft":break;case"curtainBottomLeft":break;case"curtainSliceLeft":break;case"curtainTopRight":nb=nb.reverse();break;case"curtainBottomRight":nb=nb.reverse();break;case"curtainSliceRight":nb=nb.reverse();break;case"blindCurtainTopLeft":break;case"blindCurtainBottomLeft":nb=nb.reverse();break;case"blindCurtainSliceTop":break;case"blindCurtainTopRight":break;case"blindCurtainBottomRight":nb=nb.reverse();break;case"blindCurtainSliceBottom":nb=nb.reverse();break;case"stampede":nb=X(nb);break;case"mosaic":break;case"mosaicReverse":nb=nb.reverse();break;case"mosaicRandom":nb=X(nb);break;case"mosaicSpiral":var rb=C/2,sb,tb,ub,vb=0;for(ub=0;ub<rb;ub++){tb=ub;for(sb=ub;sb<D-ub-1;sb++){pb[vb++]=tb*D+sb}sb=D-ub-1;for(tb=ub;tb<C-ub-1;tb++){pb[vb++]=tb*D+sb}tb=C-ub-1;for(sb=D-ub-1;sb>ub;sb--){pb[vb++]=tb*D+sb}sb=ub;for(tb=C-ub-1;tb>ub;tb--){pb[vb++]=tb*D+sb}}nb=pb;break;case"mosaicSpiralReverse":var rb=C/2,sb,tb,ub,vb=ab-1;for(ub=0;ub<rb;ub++){tb=ub;for(sb=ub;sb<D-ub-1;sb++){pb[vb--]=tb*D+sb}sb=D-ub-1;for(tb=ub;tb<C-ub-1;tb++){pb[vb--]=tb*D+sb}tb=C-ub-1;for(sb=D-ub-1;sb>ub;sb--){pb[vb--]=tb*D+sb}sb=ub;for(tb=C-ub-1;tb>ub;tb--){pb[vb--]=tb*D+sb}}nb=pb;break;case"topLeftBottomRight":for(var tb=0;tb<C;tb++)for(var sb=0;sb<D;sb++){pb.push(sb+tb)}ob=pb;break;case"bottomRightTopLeft":for(var tb=0;tb<C;tb++)for(var sb=0;sb<D;sb++){pb.push(sb+tb)}ob=pb.reverse();break;case"bottomLeftTopRight":for(var tb=C;tb>0;tb--)for(var sb=0;sb<D;sb++){pb.push(sb+tb)}ob=pb;break;case"topRightBottomLeft":for(var tb=0;tb<C;tb++)for(var sb=D;sb>0;sb--){pb.push(sb+tb)}ob=pb;break}a.each(nb,function(c,e){function o(){a(this).addClass("cameraeased");if(a(".cameraeased",k).length>=0){a(s).css({visibility:"visible"})}if(a(".cameraeased",k).length==ab){hb();a(".moveFromLeft, .moveFromRight, .moveFromTop, .moveFromBottom, .fadeIn, .fadeFromLeft, .fadeFromRight, .fadeFromTop, .fadeFromBottom",g).each(function(){a(this).css("visibility","hidden")});S.eq(l).show().css("z-index","999").removeClass("cameranext").addClass("cameracurrent");S.eq(d).css("z-index","1").removeClass("cameracurrent");a(".cameraContent",g).eq(l).addClass("cameracurrent");if(d>=0){a(".cameraContent",g).eq(d).removeClass("cameracurrent")}b.onEndTransition.call(this);if(a("> div",j).eq(l).attr("data-video")!="hide"&&a(".cameraContent.cameracurrent .imgFake",g).length){a(".cameraContent.cameracurrent .imgFake",g).click()}var c=S.eq(l).find(".fadeIn").length;var e=a(".cameraContent",g).eq(l).find(".moveFromLeft, .moveFromRight, .moveFromTop, .moveFromBottom, .fadeIn, .fadeFromLeft, .fadeFromRight, .fadeFromTop, .fadeFromBottom").length;if(c!=0){a(".cameraSlide.cameracurrent .fadeIn",g).each(function(){if(a(this).attr("data-easing")!=""){var b=a(this).attr("data-easing")}else{var b=O}var d=a(this);if(typeof d.attr("data-outerWidth")==="undefined"||d.attr("data-outerWidth")===false||d.attr("data-outerWidth")===""){var e=d.outerWidth();d.attr("data-outerWidth",e)}else{var e=d.attr("data-outerWidth")}if(typeof d.attr("data-outerHeight")==="undefined"||d.attr("data-outerHeight")===false||d.attr("data-outerHeight")===""){var f=d.outerHeight();d.attr("data-outerHeight",f)}else{var f=d.attr("data-outerHeight")}var g=d.position();var h=g.left;var i=g.top;var j=d.attr("class");var k=d.index();var l=d.parents(".camerarelative").outerHeight();var m=d.parents(".camerarelative").outerWidth();if(j.indexOf("fadeIn")!=-1){d.animate({opacity:0},0).css("visibility","visible").delay(I/c*.1*(k-1)).animate({opacity:1},I/c*.15,b)}else{d.css("visibility","visible")}})}a(".cameraContent.cameracurrent",g).show();if(e!=0){a(".cameraContent.cameracurrent .moveFromLeft, .cameraContent.cameracurrent .moveFromRight, .cameraContent.cameracurrent .moveFromTop, .cameraContent.cameracurrent .moveFromBottom, .cameraContent.cameracurrent .fadeIn, .cameraContent.cameracurrent .fadeFromLeft, .cameraContent.cameracurrent .fadeFromRight, .cameraContent.cameracurrent .fadeFromTop, .cameraContent.cameracurrent .fadeFromBottom",g).each(function(){if(a(this).attr("data-easing")!=""){var b=a(this).attr("data-easing")}else{var b=O}var c=a(this);var d=c.position();var f=d.left;var g=d.top;var h=c.attr("class");var i=c.index();var j=c.outerHeight();if(h.indexOf("moveFromLeft")!=-1){c.css({left:"-"+t+"px",right:"auto"});c.css("visibility","visible").delay(I/e*.1*(i-1)).animate({left:d.left},I/e*.15,b)}else if(h.indexOf("moveFromRight")!=-1){c.css({left:t+"px",right:"auto"});c.css("visibility","visible").delay(I/e*.1*(i-1)).animate({left:d.left},I/e*.15,b)}else if(h.indexOf("moveFromTop")!=-1){c.css({top:"-"+u+"px",bottom:"auto"});c.css("visibility","visible").delay(I/e*.1*(i-1)).animate({top:d.top},I/e*.15,b,function(){c.css({top:"auto",bottom:0})})}else if(h.indexOf("moveFromBottom")!=-1){c.css({top:u+"px",bottom:"auto"});c.css("visibility","visible").delay(I/e*.1*(i-1)).animate({top:d.top},I/e*.15,b)}else if(h.indexOf("fadeFromLeft")!=-1){c.animate({opacity:0},0).css({left:"-"+t+"px",right:"auto"});c.css("visibility","visible").delay(I/e*.1*(i-1)).animate({left:d.left,opacity:1},I/e*.15,b)}else if(h.indexOf("fadeFromRight")!=-1){c.animate({opacity:0},0).css({left:t+"px",right:"auto"});c.css("visibility","visible").delay(I/e*.1*(i-1)).animate({left:d.left,opacity:1},I/e*.15,b)}else if(h.indexOf("fadeFromTop")!=-1){c.animate({opacity:0},0).css({top:"-"+u+"px",bottom:"auto"});c.css("visibility","visible").delay(I/e*.1*(i-1)).animate({top:d.top,opacity:1},I/e*.15,b,function(){c.css({top:"auto",bottom:0})})}else if(h.indexOf("fadeFromBottom")!=-1){c.animate({opacity:0},0).css({bottom:"-"+j+"px"});c.css("visibility","visible").delay(I/e*.1*(i-1)).animate({bottom:"0",opacity:1},I/e*.15,b)}else if(h.indexOf("fadeIn")!=-1){c.animate({opacity:0},0).css("visibility","visible").delay(I/e*.1*(i-1)).animate({opacity:1},I/e*.15,b)}else{c.css("visibility","visible")}})}a(".cameraappended",k).remove();j.removeClass("camerasliding");S.eq(d).hide();var f=a(".camera_bar_cont",V).width(),m=a(".camera_bar_cont",V).height(),o;if(h!="pie"){o=.05}else{o=.005}a("#"+i).animate({opacity:b.loaderOpacity},200);L=setInterval(function(){if(j.hasClass("stopped")){clearInterval(L)}if(h!="pie"){if(bb<=1.002&&!j.hasClass("stopped")&&!j.hasClass("paused")&&!j.hasClass("hovered")){bb=bb+o}else if(bb<=1&&(j.hasClass("stopped")||j.hasClass("paused")||j.hasClass("stopped")||j.hasClass("hovered"))){bb=bb}else{if(!j.hasClass("stopped")&&!j.hasClass("paused")&&!j.hasClass("hovered")){clearInterval(L);W();a("#"+i).animate({opacity:0},200,function(){clearTimeout(M);M=setTimeout(ib,n);jb();b.onStartLoading.call(this)})}}switch(U){case"leftToRight":a("#"+i).animate({right:f-f*bb},I*o,"linear");break;case"rightToLeft":a("#"+i).animate({left:f-f*bb},I*o,"linear");break;case"topToBottom":a("#"+i).animate({bottom:m-m*bb},I*o,"linear");break;case"bottomToTop":a("#"+i).animate({bottom:m-m*bb},I*o,"linear");break}}else{cb=bb;db.clearRect(0,0,b.pieDiameter,b.pieDiameter);db.globalCompositeOperation="destination-over";db.beginPath();db.arc(b.pieDiameter/2,b.pieDiameter/2,b.pieDiameter/2-b.loaderStroke,0,Math.PI*2,false);db.lineWidth=b.loaderStroke;db.strokeStyle=b.loaderBgColor;db.stroke();db.closePath();db.globalCompositeOperation="source-over";db.beginPath();db.arc(b.pieDiameter/2,b.pieDiameter/2,b.pieDiameter/2-b.loaderStroke,0,Math.PI*2*cb,false);db.lineWidth=b.loaderStroke-b.loaderPadding*2;db.strokeStyle=b.loaderColor;db.stroke();db.closePath();if(bb<=1.002&&!j.hasClass("stopped")&&!j.hasClass("paused")&&!j.hasClass("hovered")){bb=bb+o}else if(bb<=1&&(j.hasClass("stopped")||j.hasClass("paused")||j.hasClass("hovered"))){bb=bb}else{if(!j.hasClass("stopped")&&!j.hasClass("paused")&&!j.hasClass("hovered")){clearInterval(L);W();a("#"+i+", .camera_canvas_wrap",V).animate({opacity:0},200,function(){clearTimeout(M);M=setTimeout(ib,n);jb();b.onStartLoading.call(this)})}}}},I*o)}}if(e%D<eb){gb=1}else{gb=0}if(e%D==0){lb=0}if(Math.floor(e/D)<fb){kb=1}else{kb=0}switch(N){case"simpleFade":height=u;width=t;opacityOnGrid=0;break;case"curtainTopLeft":height=0,width=Math.floor(t/D+gb+1),marginTop="-"+Math.floor(u/C+kb+1)+"px";break;case"curtainTopRight":height=0,width=Math.floor(t/D+gb+1),marginTop="-"+Math.floor(u/C+kb+1)+"px";break;case"curtainBottomLeft":height=0,width=Math.floor(t/D+gb+1),marginTop=Math.floor(u/C+kb+1)+"px";break;case"curtainBottomRight":height=0,width=Math.floor(t/D+gb+1),marginTop=Math.floor(u/C+kb+1)+"px";break;case"curtainSliceLeft":height=0,width=Math.floor(t/D+gb+1);if(e%2==0){marginTop=Math.floor(u/C+kb+1)+"px"}else{marginTop="-"+Math.floor(u/C+kb+1)+"px"}break;case"curtainSliceRight":height=0,width=Math.floor(t/D+gb+1);if(e%2==0){marginTop=Math.floor(u/C+kb+1)+"px"}else{marginTop="-"+Math.floor(u/C+kb+1)+"px"}break;case"blindCurtainTopLeft":height=Math.floor(u/C+kb+1),width=0,marginLeft="-"+Math.floor(t/D+gb+1)+"px";break;case"blindCurtainTopRight":height=Math.floor(u/C+kb+1),width=0,marginLeft=Math.floor(t/D+gb+1)+"px";break;case"blindCurtainBottomLeft":height=Math.floor(u/C+kb+1),width=0,marginLeft="-"+Math.floor(t/D+gb+1)+"px";break;case"blindCurtainBottomRight":height=Math.floor(u/C+kb+1),width=0,marginLeft=Math.floor(t/D+gb+1)+"px";break;case"blindCurtainSliceBottom":height=Math.floor(u/C+kb+1),width=0;if(e%2==0){marginLeft="-"+Math.floor(t/D+gb+1)+"px"}else{marginLeft=Math.floor(t/D+gb+1)+"px"}break;case"blindCurtainSliceTop":height=Math.floor(u/C+kb+1),width=0;if(e%2==0){marginLeft="-"+Math.floor(t/D+gb+1)+"px"}else{marginLeft=Math.floor(t/D+gb+1)+"px"}break;case"stampede":height=0;width=0;marginLeft=t*.2*(c%D-(D-Math.floor(D/2)))+"px";marginTop=u*.2*(Math.floor(c/D)+1-(C-Math.floor(C/2)))+"px";break;case"mosaic":height=0;width=0;break;case"mosaicReverse":height=0;width=0;marginLeft=Math.floor(t/D+gb+1)+"px";marginTop=Math.floor(u/C+kb+1)+"px";break;case"mosaicRandom":height=0;width=0;marginLeft=Math.floor(t/D+gb+1)*.5+"px";marginTop=Math.floor(u/C+kb+1)*.5+"px";break;case"mosaicSpiral":height=0;width=0;marginLeft=Math.floor(t/D+gb+1)*.5+"px";marginTop=Math.floor(u/C+kb+1)*.5+"px";break;case"mosaicSpiralReverse":height=0;width=0;marginLeft=Math.floor(t/D+gb+1)*.5+"px";marginTop=Math.floor(u/C+kb+1)*.5+"px";break;case"topLeftBottomRight":height=0;width=0;break;case"bottomRightTopLeft":height=0;width=0;marginLeft=Math.floor(t/D+gb+1)+"px";marginTop=Math.floor(u/C+kb+1)+"px";break;case"bottomLeftTopRight":height=0;width=0;marginLeft=0;marginTop=Math.floor(u/C+kb+1)+"px";break;case"topRightBottomLeft":height=0;width=0;marginLeft=Math.floor(t/D+gb+1)+"px";marginTop=0;break;case"scrollRight":height=u;width=t;marginLeft=-t;break;case"scrollLeft":height=u;width=t;marginLeft=t;break;case"scrollTop":height=u;width=t;marginTop=u;break;case"scrollBottom":height=u;width=t;marginTop=-u;break;case"scrollHorz":height=u;width=t;if(d==0&&l==B-1){marginLeft=-t}else if(d<l||d==B-1&&l==0){marginLeft=t}else{marginLeft=-t}break}var m=a(".cameraappended:eq("+e+")",k);if(typeof L!=="undefined"){clearInterval(L);clearTimeout(M);M=setTimeout(ib,J+G)}if(a(r).length){a(".camera_pag li",f).removeClass("cameracurrent");a(".camera_pag li",f).eq(l).addClass("cameracurrent")}if(a(s).length){a("li",s).removeClass("cameracurrent");a("li",s).eq(l).addClass("cameracurrent");a("li",s).not(".cameracurrent").find("img").animate({opacity:.5},0);a("li.cameracurrent img",s).animate({opacity:1},0);a("li",s).hover(function(){a("img",this).stop(true,false).animate({opacity:1},150)},function(){if(!a(this).hasClass("cameracurrent")){a("img",this).stop(true,false).animate({opacity:.5},150)}})}var n=parseFloat(J)+parseFloat(G);if(N=="scrollLeft"||N=="scrollRight"||N=="scrollTop"||N=="scrollBottom"||N=="scrollHorz"){b.onStartTransition.call(this);n=0;m.delay((J+G)/ab*ob[c]*F*.5).css({display:"block",height:height,"margin-left":marginLeft,"margin-top":marginTop,width:width}).animate({height:Math.floor(u/C+kb+1),"margin-top":0,"margin-left":0,width:Math.floor(t/D+gb+1)},J-G,O,o);S.eq(d).delay((J+G)/ab*ob[c]*F*.5).animate({"margin-left":marginLeft*-1,"margin-top":marginTop*-1},J-G,O,function(){a(this).css({"margin-top":0,"margin-left":0})})}else{b.onStartTransition.call(this);n=parseFloat(J)+parseFloat(G);if(T=="next"){m.delay((J+G)/ab*ob[c]*F*.5).css({display:"block",height:height,"margin-left":marginLeft,"margin-top":marginTop,width:width,opacity:opacityOnGrid}).animate({height:Math.floor(u/C+kb+1),"margin-top":0,"margin-left":0,opacity:1,width:Math.floor(t/D+gb+1)},J-G,O,o)}else{S.eq(l).show().css("z-index","999").addClass("cameracurrent");S.eq(d).css("z-index","1").removeClass("cameracurrent");a(".cameraContent",g).eq(l).addClass("cameracurrent");a(".cameraContent",g).eq(d).removeClass("cameracurrent");m.delay((J+G)/ab*ob[c]*F*.5).css({display:"block",height:Math.floor(u/C+kb+1),"margin-top":0,"margin-left":0,opacity:1,width:Math.floor(t/D+gb+1)}).animate({height:height,"margin-left":marginLeft,"margin-top":marginTop,width:width,opacity:opacityOnGrid},J-G,O,o)}}})}}var d={alignment:"center",autoAdvance:true,mobileAutoAdvance:true,barDirection:"leftToRight",barPosition:"bottom",cols:6,easing:"easeInOutExpo",mobileEasing:"",fx:"random",mobileFx:"",gridDifference:250,height:"50%",imagePath:"images/",hover:true,loader:"pie",loaderColor:"#eeeeee",loaderBgColor:"#222222",loaderOpacity:.8,loaderPadding:2,loaderStroke:7,minHeight:"200px",navigation:true,navigationHover:true,mobileNavHover:true,opacityOnGrid:false,overlayer:true,pagination:true,playPause:true,pauseOnClick:true,pieDiameter:38,piePosition:"rightTop",portrait:false,rows:4,slicedCols:12,slicedRows:8,slideOn:"random",thumbnails:false,time:7e3,transPeriod:1500,onEndTransition:function(){},onLoaded:function(){},onStartLoading:function(){},onStartTransition:function(){}};var b=a.extend({},d,b);var f=a(this).addClass("camera_wrap");f.wrapInner('<div class="camera_src" />').wrapInner('<div class="camera_fakehover" />');var g=a(".camera_fakehover",f);g.append('<div class="camera_target"></div>');if(b.overlayer==true){g.append('<div class="camera_overlayer"></div>')}g.append('<div class="camera_target_content"></div>');var h;if(b.loader=="pie"&&a.browser.msie&&a.browser.version<9){h="bar"}else{h=b.loader}if(h=="pie"){g.append('<div class="camera_pie"></div>')}else if(h=="bar"){g.append('<div class="camera_bar"></div>')}else{g.append('<div class="camera_bar" style="display:none"></div>')}if(b.playPause==true){g.append('<div class="camera_commands"></div>')}if(b.navigation==true){g.append('<div class="camera_prev"><span></span></div>').append('<div class="camera_next"><span></span></div>')}if(b.thumbnails==true){f.append('<div class="camera_thumbs_cont" />')}if(b.thumbnails==true&&b.pagination!=true){a(".camera_thumbs_cont",f).wrap("<div />").wrap('<div class="camera_thumbs" />').wrap("<div />").wrap('<div class="camera_command_wrap" />')}if(b.pagination==true){f.append('<div class="camera_pag"></div>')}f.append('<div class="camera_loader"></div>');a(".camera_caption",f).each(function(){a(this).wrapInner("<div />")});var i="pie_"+f.index(),j=a(".camera_src",f),k=a(".camera_target",f),l=a(".camera_target_content",f),m=a(".camera_pie",f),n=a(".camera_bar",f),o=a(".camera_prev",f),p=a(".camera_next",f),q=a(".camera_commands",f),r=a(".camera_pag",f),s=a(".camera_thumbs_cont",f);var t,u;var v=new Array;a("> div",j).each(function(){v.push(a(this).attr("data-src"))});var w=new Array;a("> div",j).each(function(){if(a(this).attr("data-link")){w.push(a(this).attr("data-link"))}else{w.push("")}});var x=new Array;a("> div",j).each(function(){if(a(this).attr("data-target")){x.push(a(this).attr("data-target"))}else{x.push("")}});var y=new Array;a("> div",j).each(function(){if(a(this).attr("data-portrait")){y.push(a(this).attr("data-portrait"))}else{y.push("")}});var z=new Array;a("> div",j).each(function(){if(a(this).attr("data-alignment")){z.push(a(this).attr("data-alignment"))}else{z.push("")}});var A=new Array;a("> div",j).each(function(){if(a(this).attr("data-thumb")){A.push(a(this).attr("data-thumb"))}else{A.push("")}});var B=v.length;a(l).append('<div class="cameraContents" />');var C;for(C=0;C<B;C++){a(".cameraContents",l).append('<div class="cameraContent" />');if(w[C]!=""){var D=a("> div ",j).eq(C).attr("data-box");if(typeof D!=="undefined"&&D!==false&&D!=""){D='data-box="'+a("> div ",j).eq(C).attr("data-box")+'"'}else{D=""}a(".camera_target_content .cameraContent:eq("+C+")",f).append('<a class="camera_link" href="'+w[C]+'" '+D+' target="'+x[C]+'"></a>')}}a(".camera_caption",f).each(function(){var b=a(this).parent().index(),c=f.find(".cameraContent").eq(b);a(this).appendTo(c)});k.append('<div class="cameraCont" />');var E=a(".cameraCont",f);var F;for(F=0;F<B;F++){E.append('<div class="cameraSlide cameraSlide_'+F+'" />');var G=a("> div:eq("+F+")",j);k.find(".cameraSlide_"+F).clone(G)}a(window).bind("load resize pageshow",function(){hb();H()});E.append('<div class="cameraSlide cameraSlide_'+F+'" />');var I;f.show();var t=k.width();var u=k.height();var J;a(window).bind("resize pageshow",function(){if(I==true){K()}a("ul",s).animate({"margin-top":0},0,hb);if(!j.hasClass("paused")){j.addClass("paused");if(a(".camera_stop",V).length){a(".camera_stop",V).hide();a(".camera_play",V).show();if(h!="none"){a("#"+i).hide()}}else{if(h!="none"){a("#"+i).hide()}}clearTimeout(J);J=setTimeout(function(){j.removeClass("paused");if(a(".camera_play",V).length){a(".camera_play",V).hide();a(".camera_stop",V).show();if(h!="none"){a("#"+i).fadeIn()}}else{if(h!="none"){a("#"+i).fadeIn()}}},1500)}});var L,M;var N,O,P,q,r;var Q,R;if(e()&&b.mobileAutoAdvance!=""){O=b.mobileAutoAdvance}else{O=b.autoAdvance}if(O==false){j.addClass("paused")}if(e()&&b.mobileNavHover!=""){P=b.mobileNavHover}else{P=b.navigationHover}if(j.length!=0){var S=a(".cameraSlide",k);S.wrapInner('<div class="camerarelative" />');var T;var U=b.barDirection;var V=f;a("iframe",g).each(function(){var b=a(this);var c=b.attr("src");b.attr("data-src",c);var d=b.parent().index(".camera_src > div");a(".camera_target_content .cameraContent:eq("+d+")",f).append(b)});function W(){a("iframe",g).each(function(){a(".camera_caption",g).show();var c=a(this);var d=c.attr("data-src");c.attr("src",d);var e=b.imagePath+"blank.gif";var h=new Image;h.src=e;if(b.height.indexOf("%")!=-1){var i=Math.round(t/(100/parseFloat(b.height)));if(b.minHeight!=""&&i<parseFloat(b.minHeight)){u=parseFloat(b.minHeight)}else{u=i}}else if(b.height=="auto"){u=f.height()}else{u=parseFloat(b.height)}c.after(a(h).attr({"class":"imgFake",width:t,height:u}));var j=c.clone();c.remove();a(h).bind("click",function(){if(a(this).css("position")=="absolute"){a(this).remove();if(d.indexOf("vimeo")!=-1||d.indexOf("youtube")!=-1){if(d.indexOf("?")!=-1){autoplay="&autoplay=1"}else{autoplay="?autoplay=1"}}else if(d.indexOf("dailymotion")!=-1){if(d.indexOf("?")!=-1){autoplay="&autoPlay=1"}else{autoplay="?autoPlay=1"}}j.attr("src",d+autoplay);R=true}else{a(this).css({position:"absolute",top:0,left:0,zIndex:10}).after(j);j.css({position:"absolute",top:0,left:0,zIndex:9})}})})}W();if(b.hover==true){if(!e()){g.hover(function(){j.addClass("hovered")},function(){j.removeClass("hovered")})}}if(P==true){a(o,f).animate({opacity:0},0);a(p,f).animate({opacity:0},0);a(q,f).animate({opacity:0},0);if(e()){g.live("vmouseover",function(){a(o,f).animate({opacity:1},200);a(p,f).animate({opacity:1},200);a(q,f).animate({opacity:1},200)});g.live("vmouseout",function(){a(o,f).delay(500).animate({opacity:0},200);a(p,f).delay(500).animate({opacity:0},200);a(q,f).delay(500).animate({opacity:0},200)})}else{g.hover(function(){a(o,f).animate({opacity:1},200);a(p,f).animate({opacity:1},200);a(q,f).animate({opacity:1},200)},function(){a(o,f).animate({opacity:0},200);a(p,f).animate({opacity:0},200);a(q,f).animate({opacity:0},200)})}}a(".camera_stop",V).live("click",function(){O=false;j.addClass("paused");if(a(".camera_stop",V).length){a(".camera_stop",V).hide();a(".camera_play",V).show();if(h!="none"){a("#"+i).hide()}}else{if(h!="none"){a("#"+i).hide()}}});a(".camera_play",V).live("click",function(){O=true;j.removeClass("paused");if(a(".camera_play",V).length){a(".camera_play",V).hide();a(".camera_stop",V).show();if(h!="none"){a("#"+i).show()}}else{if(h!="none"){a("#"+i).show()}}});if(b.pauseOnClick==true){a(".camera_target_content",g).mouseup(function(){O=false;j.addClass("paused");a(".camera_stop",V).hide();a(".camera_play",V).show();a("#"+i).hide()})}a(".cameraContent, .imgFake",g).hover(function(){Q=true},function(){Q=false});a(".cameraContent, .imgFake",g).bind("click",function(){if(R==true&&Q==true){O=false;a(".camera_caption",g).hide();j.addClass("paused");a(".camera_stop",V).hide();a(".camera_play",V).show();a("#"+i).hide()}})}if(h!="pie"){n.append('<span class="camera_bar_cont" />');a(".camera_bar_cont",n).animate({opacity:b.loaderOpacity},0).css({position:"absolute",left:0,right:0,top:0,bottom:0,"background-color":b.loaderBgColor}).append('<span id="'+i+'" />');a("#"+i).animate({opacity:0},0);var Z=a("#"+i);Z.css({position:"absolute","background-color":b.loaderColor});switch(b.barPosition){case"left":n.css({right:"auto",width:b.loaderStroke});break;case"right":n.css({left:"auto",width:b.loaderStroke});break;case"top":n.css({bottom:"auto",height:b.loaderStroke});break;case"bottom":n.css({top:"auto",height:b.loaderStroke});break}switch(U){case"leftToRight":Z.css({left:0,right:0,top:b.loaderPadding,bottom:b.loaderPadding});break;case"rightToLeft":Z.css({left:0,right:0,top:b.loaderPadding,bottom:b.loaderPadding});break;case"topToBottom":Z.css({left:b.loaderPadding,right:b.loaderPadding,top:0,bottom:0});break;case"bottomToTop":Z.css({left:b.loaderPadding,right:b.loaderPadding,top:0,bottom:0});break}}else{m.append('<canvas id="'+i+'"></canvas>');var _;var Z=document.getElementById(i);Z.setAttribute("width",b.pieDiameter);Z.setAttribute("height",b.pieDiameter);var ab;switch(b.piePosition){case"leftTop":ab="left:0; top:0;";break;case"rightTop":ab="right:0; top:0;";break;case"leftBottom":ab="left:0; bottom:0;";break;case"rightBottom":ab="right:0; bottom:0;";break}Z.setAttribute("style","position:absolute; z-index:1002; "+ab);var bb;var cb;if(Z&&Z.getContext){var db=Z.getContext("2d");db.rotate(Math.PI*(3/2));db.translate(-b.pieDiameter,0)}}if(h=="none"||O==false){a("#"+i).hide();a(".camera_canvas_wrap",V).hide()}if(a(r).length){a(r).append('<ul class="camera_pag_ul" />');var eb;for(eb=0;eb<B;eb++){a(".camera_pag_ul",f).append('<li class="pag_nav_'+eb+'" style="position:relative; z-index:1002"><span><span>'+eb+"</span></span></li>")}a(".camera_pag_ul li",f).hover(function(){a(this).addClass("camera_hover");if(a(".camera_thumb",this).length){var b=a(".camera_thumb",this).outerWidth(),c=a(".camera_thumb",this).outerHeight(),d=a(this).outerWidth();a(".camera_thumb",this).show().css({top:"-"+c+"px",left:"-"+(b-d)/2+"px"}).animate({opacity:1,"margin-top":"-3px"},200);a(".thumb_arrow",this).show().animate({opacity:1,"margin-top":"-3px"},200)}},function(){a(this).removeClass("camera_hover");a(".camera_thumb",this).animate({"margin-top":"-20px",opacity:0},200,function(){a(this).css({marginTop:"5px"}).hide()});a(".thumb_arrow",this).animate({"margin-top":"-20px",opacity:0},200,function(){a(this).css({marginTop:"5px"}).hide()})})}if(a(s).length){var fb;if(!a(r).length){a(s).append("<div />");a(s).before('<div class="camera_prevThumbs hideNav"><div></div></div>').before('<div class="camera_nextThumbs hideNav"><div></div></div>');a("> div",s).append("<ul />");a.each(A,function(b,c){if(a("> div",j).eq(b).attr("data-thumb")!=""){var d=a("> div",j).eq(b).attr("data-thumb"),e=new Image;e.src=d;a("ul",s).append('<li class="pix_thumb pix_thumb_'+b+'" />');a("li.pix_thumb_"+b,s).append(a(e).attr("class","camera_thumb"))}})}else{a.each(A,function(b,c){if(a("> div",j).eq(b).attr("data-thumb")!=""){var d=a("> div",j).eq(b).attr("data-thumb"),e=new Image;e.src=d;a("li.pag_nav_"+b,r).append(a(e).attr("class","camera_thumb").css({position:"absolute"}).animate({opacity:0},0));a("li.pag_nav_"+b+" > img",r).after('<div class="thumb_arrow" />');a("li.pag_nav_"+b+" > .thumb_arrow",r).animate({opacity:0},0)}});f.css({marginBottom:a(r).outerHeight()})}}else if(!a(s).length&&a(r).length){f.css({marginBottom:a(r).outerHeight()})}var gb=true;if(a(q).length){a(q).append('<div class="camera_play"></div>').append('<div class="camera_stop"></div>');if(O==true){a(".camera_play",V).hide();a(".camera_stop",V).show()}else{a(".camera_stop",V).hide();a(".camera_play",V).show()}}ib();a(".moveFromLeft, .moveFromRight, .moveFromTop, .moveFromBottom, .fadeIn, .fadeFromLeft, .fadeFromRight, .fadeFromTop, .fadeFromBottom",g).each(function(){a(this).css("visibility","hidden")});b.onStartLoading.call(this);jb();if(a(o).length){a(o).click(function(){if(!j.hasClass("camerasliding")){var c=parseFloat(a(".cameraSlide.cameracurrent",k).index());clearInterval(L);W();a("#"+i+", .camera_canvas_wrap",f).animate({opacity:0},0);ib();if(c!=0){jb(c)}else{jb(B)}b.onStartLoading.call(this)}})}if(a(p).length){a(p).click(function(){if(!j.hasClass("camerasliding")){var c=parseFloat(a(".cameraSlide.cameracurrent",k).index());clearInterval(L);W();a("#"+i+", .camera_canvas_wrap",V).animate({opacity:0},0);ib();if(c==B-1){jb(1)}else{jb(c+2)}b.onStartLoading.call(this)}})}if(e()){g.bind("swipeleft",function(c){if(!j.hasClass("camerasliding")){var d=parseFloat(a(".cameraSlide.cameracurrent",k).index());clearInterval(L);W();a("#"+i+", .camera_canvas_wrap",V).animate({opacity:0},0);ib();if(d==B-1){jb(1)}else{jb(d+2)}b.onStartLoading.call(this)}});g.bind("swiperight",function(c){if(!j.hasClass("camerasliding")){var d=parseFloat(a(".cameraSlide.cameracurrent",k).index());clearInterval(L);W();a("#"+i+", .camera_canvas_wrap",V).animate({opacity:0},0);ib();if(d!=0){jb(d)}else{jb(B)}b.onStartLoading.call(this)}})}if(a(r).length){a(".camera_pag li",f).click(function(){if(!j.hasClass("camerasliding")){var c=parseFloat(a(this).index());var d=parseFloat(a(".cameraSlide.cameracurrent",k).index());if(c!=d){clearInterval(L);W();a("#"+i+", .camera_canvas_wrap",V).animate({opacity:0},0);ib();jb(c+1);b.onStartLoading.call(this)}}})}if(a(s).length){a(".pix_thumb img",s).click(function(){if(!j.hasClass("camerasliding")){var c=parseFloat(a(this).parents("li").index());var d=parseFloat(a(".cameracurrent",k).index());if(c!=d){clearInterval(L);W();a("#"+i+", .camera_canvas_wrap",V).animate({opacity:0},0);a(".pix_thumb",s).removeClass("cameracurrent");a(this).parents("li").addClass("cameracurrent");ib();jb(c+1);hb();b.onStartLoading.call(this)}}});a(".camera_thumbs_cont .camera_prevThumbs",V).hover(function(){a(this).stop(true,false).animate({opacity:1},250)},function(){a(this).stop(true,false).animate({opacity:.7},250)});a(".camera_prevThumbs",V).click(function(){var b=0,c=a(s).outerWidth(),d=a("ul",s).offset().left,e=a("> div",s).offset().left,f=e-d;a(".camera_visThumb",s).each(function(){var c=a(this).outerWidth();b=b+c});if(f-b>0){a("ul",s).animate({"margin-left":"-"+(f-b)+"px"},500,H)}else{a("ul",s).animate({"margin-left":0},500,H)}});a(".camera_thumbs_cont .camera_nextThumbs",V).hover(function(){a(this).stop(true,false).animate({opacity:1},250)},function(){a(this).stop(true,false).animate({opacity:.7},250)});a(".camera_nextThumbs",V).click(function(){var b=0,c=a(s).outerWidth(),d=a("ul",s).outerWidth(),e=a("ul",s).offset().left,f=a("> div",s).offset().left,g=f-e;a(".camera_visThumb",s).each(function(){var c=a(this).outerWidth();b=b+c});if(g+b+b<d){a("ul",s).animate({"margin-left":"-"+(g+b)+"px"},500,H)}else{a("ul",s).animate({"margin-left":"-"+(d-c)+"px"},500,H)}})}}})(jQuery);(function(a){a.fn.cameraStop=function(){var b=a(this),c=a(".camera_src",b),d="pie_"+b.index();c.addClass("stopped");if(a(".camera_showcommands").length){var e=a(".camera_thumbs_wrap",b)}else{var e=b}}})(jQuery);(function(a){a.fn.cameraPause=function(){var b=a(this);var c=a(".camera_src",b);c.addClass("paused")}})(jQuery);(function(a){a.fn.cameraResume=function(){var b=a(this);var c=a(".camera_src",b);if(typeof autoAdv==="undefined"||autoAdv!==true){c.removeClass("paused")}}})(jQuery);
skin/frontend/base/default/productlookbook/js/hotspots.js ADDED
@@ -0,0 +1,85 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ jQuery.extend({
2
+ setHotspots : function(slide, hotspots) {
3
+ if (!hotspots) return;
4
+ var i=0;
5
+ hotspots.each(function() {
6
+ if (!document.getElementById(hotspots[i].id)) {
7
+ slide.append('<div class="hotspot" id="'+hotspots[i].id+'" style="left:'+hotspots[i].left+'px; top:'+hotspots[i].top+'px; width:'+hotspots[i].width+'px; height:'+hotspots[i].height+'px;">'+hotspots[i].text+'</div>');
8
+ var infoblock = slide.find('#'+hotspots[i].id +' .product-info');
9
+ var imgwidth = slide.width();
10
+ var infowidth = infoblock.width();
11
+ var hspt_width_hf = parseInt(hotspots[i].width/2);
12
+ var leftposition = hotspots[i].left+hspt_width_hf+7;
13
+ infoblock.find('.info-icon').css('left',hspt_width_hf+'px');
14
+ if (((leftposition + infowidth + 10)> imgwidth) && (leftposition>(imgwidth-leftposition)))
15
+ {
16
+ if ( jQuery.browser.msie && jQuery.browser.version=='8.0') {
17
+ if (leftposition-5<infowidth) {
18
+ infoblock.css('width', leftposition-20 +'px');
19
+ infowidth = infoblock.width();
20
+ }
21
+ infoblock.css('left', hspt_width_hf-7-infowidth-2*parseInt(infoblock.css('padding-left'))+'px');
22
+ }
23
+ else
24
+ {
25
+ infoblock.css('left', '');
26
+ infoblock.css('right', hspt_width_hf+7+'px');
27
+ }
28
+
29
+ if (leftposition-5<infowidth) {
30
+ infoblock.css('width', leftposition-20 +'px');
31
+ infowidth = infoblock.width();
32
+ }
33
+ }
34
+ else
35
+ {
36
+ infoblock.css('left', hspt_width_hf+7 + 'px');
37
+ if ((imgwidth-leftposition-5)<infowidth) {
38
+ infoblock.css('width', imgwidth-leftposition-20 +'px');
39
+ infowidth = infoblock.width();
40
+ }
41
+ }
42
+ var imgheight = slide.height();
43
+ var infoheight = infoblock.height();
44
+ var hspt_height_hf = parseInt(hotspots[i].height/2);
45
+ var topposition = hotspots[i].top+hspt_height_hf;
46
+ if (((topposition + infoheight + 30)> imgheight) && (topposition>(imgheight-topposition)))
47
+ {
48
+ if ( jQuery.browser.msie && jQuery.browser.version=='8.0') {
49
+ if (topposition-5<infoheight) {
50
+ infoblock.css('height', topposition-10 +'px');
51
+ infoheight = infoblock.height();
52
+ }
53
+ infoblock.css('top', hspt_height_hf-infoheight-2*parseInt(infoblock.css('padding-top'))+'px');
54
+ }
55
+ else
56
+ {
57
+ infoblock.css('top', '');
58
+ infoblock.css('bottom', hspt_height_hf+'px');
59
+ }
60
+ if (topposition-5<infoheight) {
61
+ infoblock.css('height', topposition-10 +'px');
62
+ infoheight = infoblock.height();
63
+ }
64
+ }
65
+ else
66
+ {
67
+ infoblock.css('top', hspt_height_hf + 'px');
68
+ if ((imgheight-topposition-5)<infoheight) {
69
+ infoblock.css('height', imgheight-topposition-10 +'px');
70
+ infoheight = infoblock.height();
71
+ }
72
+ }
73
+ i++;
74
+ }
75
+ });
76
+ }
77
+ });
78
+
79
+ jQuery(document).ready(function() {
80
+ jQuery('.product-info a').on('click touchend', function(e) {
81
+ var el = jQuery(this);
82
+ var link = el.attr('href');
83
+ window.location = link;
84
+ });
85
+ });
skin/frontend/base/default/productlookbook/js/jquery.easing.1.3.js ADDED
@@ -0,0 +1,205 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ /*
2
+ * jQuery Easing v1.3 - http://gsgd.co.uk/sandbox/jquery/easing/
3
+ *
4
+ * Uses the built in easing capabilities added In jQuery 1.1
5
+ * to offer multiple easing options
6
+ *
7
+ * TERMS OF USE - jQuery Easing
8
+ *
9
+ * Open source under the BSD License.
10
+ *
11
+ * Copyright © 2008 George McGinley Smith
12
+ * All rights reserved.
13
+ *
14
+ * Redistribution and use in source and binary forms, with or without modification,
15
+ * are permitted provided that the following conditions are met:
16
+ *
17
+ * Redistributions of source code must retain the above copyright notice, this list of
18
+ * conditions and the following disclaimer.
19
+ * Redistributions in binary form must reproduce the above copyright notice, this list
20
+ * of conditions and the following disclaimer in the documentation and/or other materials
21
+ * provided with the distribution.
22
+ *
23
+ * Neither the name of the author nor the names of contributors may be used to endorse
24
+ * or promote products derived from this software without specific prior written permission.
25
+ *
26
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY
27
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
28
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
29
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
30
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
31
+ * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
32
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
33
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
34
+ * OF THE POSSIBILITY OF SUCH DAMAGE.
35
+ *
36
+ */
37
+
38
+ // t: current time, b: begInnIng value, c: change In value, d: duration
39
+ jQuery.easing['jswing'] = jQuery.easing['swing'];
40
+
41
+ jQuery.extend( jQuery.easing,
42
+ {
43
+ def: 'easeOutQuad',
44
+ swing: function (x, t, b, c, d) {
45
+ //alert(jQuery.easing.default);
46
+ return jQuery.easing[jQuery.easing.def](x, t, b, c, d);
47
+ },
48
+ easeInQuad: function (x, t, b, c, d) {
49
+ return c*(t/=d)*t + b;
50
+ },
51
+ easeOutQuad: function (x, t, b, c, d) {
52
+ return -c *(t/=d)*(t-2) + b;
53
+ },
54
+ easeInOutQuad: function (x, t, b, c, d) {
55
+ if ((t/=d/2) < 1) return c/2*t*t + b;
56
+ return -c/2 * ((--t)*(t-2) - 1) + b;
57
+ },
58
+ easeInCubic: function (x, t, b, c, d) {
59
+ return c*(t/=d)*t*t + b;
60
+ },
61
+ easeOutCubic: function (x, t, b, c, d) {
62
+ return c*((t=t/d-1)*t*t + 1) + b;
63
+ },
64
+ easeInOutCubic: function (x, t, b, c, d) {
65
+ if ((t/=d/2) < 1) return c/2*t*t*t + b;
66
+ return c/2*((t-=2)*t*t + 2) + b;
67
+ },
68
+ easeInQuart: function (x, t, b, c, d) {
69
+ return c*(t/=d)*t*t*t + b;
70
+ },
71
+ easeOutQuart: function (x, t, b, c, d) {
72
+ return -c * ((t=t/d-1)*t*t*t - 1) + b;
73
+ },
74
+ easeInOutQuart: function (x, t, b, c, d) {
75
+ if ((t/=d/2) < 1) return c/2*t*t*t*t + b;
76
+ return -c/2 * ((t-=2)*t*t*t - 2) + b;
77
+ },
78
+ easeInQuint: function (x, t, b, c, d) {
79
+ return c*(t/=d)*t*t*t*t + b;
80
+ },
81
+ easeOutQuint: function (x, t, b, c, d) {
82
+ return c*((t=t/d-1)*t*t*t*t + 1) + b;
83
+ },
84
+ easeInOutQuint: function (x, t, b, c, d) {
85
+ if ((t/=d/2) < 1) return c/2*t*t*t*t*t + b;
86
+ return c/2*((t-=2)*t*t*t*t + 2) + b;
87
+ },
88
+ easeInSine: function (x, t, b, c, d) {
89
+ return -c * Math.cos(t/d * (Math.PI/2)) + c + b;
90
+ },
91
+ easeOutSine: function (x, t, b, c, d) {
92
+ return c * Math.sin(t/d * (Math.PI/2)) + b;
93
+ },
94
+ easeInOutSine: function (x, t, b, c, d) {
95
+ return -c/2 * (Math.cos(Math.PI*t/d) - 1) + b;
96
+ },
97
+ easeInExpo: function (x, t, b, c, d) {
98
+ return (t==0) ? b : c * Math.pow(2, 10 * (t/d - 1)) + b;
99
+ },
100
+ easeOutExpo: function (x, t, b, c, d) {
101
+ return (t==d) ? b+c : c * (-Math.pow(2, -10 * t/d) + 1) + b;
102
+ },
103
+ easeInOutExpo: function (x, t, b, c, d) {
104
+ if (t==0) return b;
105
+ if (t==d) return b+c;
106
+ if ((t/=d/2) < 1) return c/2 * Math.pow(2, 10 * (t - 1)) + b;
107
+ return c/2 * (-Math.pow(2, -10 * --t) + 2) + b;
108
+ },
109
+ easeInCirc: function (x, t, b, c, d) {
110
+ return -c * (Math.sqrt(1 - (t/=d)*t) - 1) + b;
111
+ },
112
+ easeOutCirc: function (x, t, b, c, d) {
113
+ return c * Math.sqrt(1 - (t=t/d-1)*t) + b;
114
+ },
115
+ easeInOutCirc: function (x, t, b, c, d) {
116
+ if ((t/=d/2) < 1) return -c/2 * (Math.sqrt(1 - t*t) - 1) + b;
117
+ return c/2 * (Math.sqrt(1 - (t-=2)*t) + 1) + b;
118
+ },
119
+ easeInElastic: function (x, t, b, c, d) {
120
+ var s=1.70158;var p=0;var a=c;
121
+ if (t==0) return b; if ((t/=d)==1) return b+c; if (!p) p=d*.3;
122
+ if (a < Math.abs(c)) { a=c; var s=p/4; }
123
+ else var s = p/(2*Math.PI) * Math.asin (c/a);
124
+ return -(a*Math.pow(2,10*(t-=1)) * Math.sin( (t*d-s)*(2*Math.PI)/p )) + b;
125
+ },
126
+ easeOutElastic: function (x, t, b, c, d) {
127
+ var s=1.70158;var p=0;var a=c;
128
+ if (t==0) return b; if ((t/=d)==1) return b+c; if (!p) p=d*.3;
129
+ if (a < Math.abs(c)) { a=c; var s=p/4; }
130
+ else var s = p/(2*Math.PI) * Math.asin (c/a);
131
+ return a*Math.pow(2,-10*t) * Math.sin( (t*d-s)*(2*Math.PI)/p ) + c + b;
132
+ },
133
+ easeInOutElastic: function (x, t, b, c, d) {
134
+ var s=1.70158;var p=0;var a=c;
135
+ if (t==0) return b; if ((t/=d/2)==2) return b+c; if (!p) p=d*(.3*1.5);
136
+ if (a < Math.abs(c)) { a=c; var s=p/4; }
137
+ else var s = p/(2*Math.PI) * Math.asin (c/a);
138
+ if (t < 1) return -.5*(a*Math.pow(2,10*(t-=1)) * Math.sin( (t*d-s)*(2*Math.PI)/p )) + b;
139
+ return a*Math.pow(2,-10*(t-=1)) * Math.sin( (t*d-s)*(2*Math.PI)/p )*.5 + c + b;
140
+ },
141
+ easeInBack: function (x, t, b, c, d, s) {
142
+ if (s == undefined) s = 1.70158;
143
+ return c*(t/=d)*t*((s+1)*t - s) + b;
144
+ },
145
+ easeOutBack: function (x, t, b, c, d, s) {
146
+ if (s == undefined) s = 1.70158;
147
+ return c*((t=t/d-1)*t*((s+1)*t + s) + 1) + b;
148
+ },
149
+ easeInOutBack: function (x, t, b, c, d, s) {
150
+ if (s == undefined) s = 1.70158;
151
+ if ((t/=d/2) < 1) return c/2*(t*t*(((s*=(1.525))+1)*t - s)) + b;
152
+ return c/2*((t-=2)*t*(((s*=(1.525))+1)*t + s) + 2) + b;
153
+ },
154
+ easeInBounce: function (x, t, b, c, d) {
155
+ return c - jQuery.easing.easeOutBounce (x, d-t, 0, c, d) + b;
156
+ },
157
+ easeOutBounce: function (x, t, b, c, d) {
158
+ if ((t/=d) < (1/2.75)) {
159
+ return c*(7.5625*t*t) + b;
160
+ } else if (t < (2/2.75)) {
161
+ return c*(7.5625*(t-=(1.5/2.75))*t + .75) + b;
162
+ } else if (t < (2.5/2.75)) {
163
+ return c*(7.5625*(t-=(2.25/2.75))*t + .9375) + b;
164
+ } else {
165
+ return c*(7.5625*(t-=(2.625/2.75))*t + .984375) + b;
166
+ }
167
+ },
168
+ easeInOutBounce: function (x, t, b, c, d) {
169
+ if (t < d/2) return jQuery.easing.easeInBounce (x, t*2, 0, c, d) * .5 + b;
170
+ return jQuery.easing.easeOutBounce (x, t*2-d, 0, c, d) * .5 + c*.5 + b;
171
+ }
172
+ });
173
+
174
+ /*
175
+ *
176
+ * TERMS OF USE - EASING EQUATIONS
177
+ *
178
+ * Open source under the BSD License.
179
+ *
180
+ * Copyright © 2001 Robert Penner
181
+ * All rights reserved.
182
+ *
183
+ * Redistribution and use in source and binary forms, with or without modification,
184
+ * are permitted provided that the following conditions are met:
185
+ *
186
+ * Redistributions of source code must retain the above copyright notice, this list of
187
+ * conditions and the following disclaimer.
188
+ * Redistributions in binary form must reproduce the above copyright notice, this list
189
+ * of conditions and the following disclaimer in the documentation and/or other materials
190
+ * provided with the distribution.
191
+ *
192
+ * Neither the name of the author nor the names of contributors may be used to endorse
193
+ * or promote products derived from this software without specific prior written permission.
194
+ *
195
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY
196
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
197
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
198
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
199
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
200
+ * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
201
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
202
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
203
+ * OF THE POSSIBILITY OF SUCH DAMAGE.
204
+ *
205
+ */