AJAX_ZOOM - Version 1.0.0

Version Notes

Add zoom & pan functionality to your high resolution product images without flash.

Download this release

Release Info

Developer AJAX-ZOOM
Extension AJAX_ZOOM
Version 1.0.0
Comparing to
See all releases


Version 1.0.0

Files changed (50) hide show
  1. app/code/local/Ax/Zoom/Block/Adminhtml/System/Config/Fieldset/License.php +65 -0
  2. app/code/local/Ax/Zoom/Block/Adminhtml/Tabs.php +27 -0
  3. app/code/local/Ax/Zoom/Block/Adminhtml/Tabs/Tabid.php +35 -0
  4. app/code/local/Ax/Zoom/Helper/Data.php +4 -0
  5. app/code/local/Ax/Zoom/Helper/Head.php +34 -0
  6. app/code/local/Ax/Zoom/Model/Ax360.php +210 -0
  7. app/code/local/Ax/Zoom/Model/Ax360set.php +39 -0
  8. app/code/local/Ax/Zoom/Model/Axproducts.php +9 -0
  9. app/code/local/Ax/Zoom/Model/Observer.php +91 -0
  10. app/code/local/Ax/Zoom/Model/Position.php +14 -0
  11. app/code/local/Ax/Zoom/Model/Resource/Ax360.php +8 -0
  12. app/code/local/Ax/Zoom/Model/Resource/Ax360/Collection.php +9 -0
  13. app/code/local/Ax/Zoom/Model/Resource/Ax360set.php +8 -0
  14. app/code/local/Ax/Zoom/Model/Resource/Ax360set/Collection.php +9 -0
  15. app/code/local/Ax/Zoom/Model/Resource/Axproducts.php +8 -0
  16. app/code/local/Ax/Zoom/Model/Resource/Axproducts/Collection.php +9 -0
  17. app/code/local/Ax/Zoom/Model/Words.php +14 -0
  18. app/code/local/Ax/Zoom/Model/Yesno.php +12 -0
  19. app/code/local/Ax/Zoom/controllers/IndexController.php +387 -0
  20. app/code/local/Ax/Zoom/etc/config.xml +349 -0
  21. app/code/local/Ax/Zoom/etc/system.xml +1148 -0
  22. app/code/local/Ax/Zoom/sql/axzoom_setup/install-0.0.1.php +33 -0
  23. app/design/adminhtml/default/default/layout/axzoom.xml +25 -0
  24. app/design/adminhtml/default/default/template/axzoom/tab.phtml +38 -0
  25. app/design/adminhtml/default/default/template/axzoom/tab360-sets.phtml +323 -0
  26. app/design/adminhtml/default/default/template/axzoom/tab360-settings.phtml +280 -0
  27. app/design/adminhtml/default/default/template/axzoom/tab360.phtml +135 -0
  28. app/design/adminhtml/default/default/template/axzoom/uploader.phtml +179 -0
  29. app/design/frontend/default/default/layout/axzoom.xml +59 -0
  30. app/design/frontend/rwd/default/layout/axzoom.xml +65 -0
  31. app/design/frontend/rwd/default/template/ax_zoom/catalog/product/view/media.phtml +423 -0
  32. app/etc/modules/Ax_Zoom.xml +9 -0
  33. app/locale/ru_RU/Ax_Zoom.csv +150 -0
  34. js/axzoom/.htaccess +1 -0
  35. js/axzoom/check_jquery.js +4 -0
  36. js/axzoom/image_path.gif +0 -0
  37. js/axzoom/jquery-1.11.0.min.js +6 -0
  38. js/axzoom/jquery-migrate-1.2.1.min.js +2 -0
  39. js/axzoom/jquery.fileupload-process.js +164 -0
  40. js/axzoom/jquery.fileupload-validate.js +117 -0
  41. js/axzoom/jquery.fileupload.js +1368 -0
  42. js/axzoom/jquery.ui.widget.min.js +4 -0
  43. js/axzoom/lic.php +30 -0
  44. js/axzoom/no_image-100x100.jpg +0 -0
  45. js/axzoom/pic/readme.txt +1 -0
  46. js/axzoom/preview/index.php +11 -0
  47. js/axzoom/preview/preview.php +273 -0
  48. js/axzoom/tmp/readme.txt +1 -0
  49. js/axzoom/zip/readme.txt +1 -0
  50. package.xml +25 -0
app/code/local/Ax/Zoom/Block/Adminhtml/System/Config/Fieldset/License.php ADDED
@@ -0,0 +1,65 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ class Ax_Zoom_Block_Adminhtml_System_Config_Fieldset_License extends Mage_Adminhtml_Block_System_Config_Form_Field_Array_Abstract
3
+ {
4
+ public function _prepareToRender()
5
+ {
6
+ $this->addColumn('domain', array(
7
+ 'label' => Mage::helper('axzoom')->__('Domain'),
8
+ 'style' => 'width:100px',
9
+ ));
10
+ $this->addColumn('type', array(
11
+ 'label' => Mage::helper('axzoom')->__('License Type'),
12
+ 'style' => 'width:100px',
13
+ 'renderer' => 'bla'
14
+ ));
15
+
16
+ $this->addColumn('license', array(
17
+ 'label' => Mage::helper('axzoom')->__('License Key'),
18
+ 'style' => 'width:100px',
19
+ ));
20
+
21
+ $this->addColumn('error200', array(
22
+ 'label' => Mage::helper('axzoom')->__('Error200'),
23
+ 'style' => 'width:100px',
24
+ ));
25
+
26
+ $this->addColumn('error300', array(
27
+ 'label' => Mage::helper('axzoom')->__('Error300'),
28
+ 'style' => 'width:100px',
29
+ ));
30
+
31
+ $this->_addAfter = false;
32
+ $this->_addButtonLabel = Mage::helper('axzoom')->__('Add');
33
+ }
34
+
35
+ protected function _renderCellTemplate($columnName)
36
+ {
37
+ if ($columnName == 'type') {
38
+ $el = $this->getElement();
39
+
40
+ $inputName = $this->getElement()->getName() . '[#{_id}][' . $columnName . ']';
41
+ $rendered = '<select id="licType" name="' . $inputName . '">';
42
+ $rendered .= '<option value="evaluation" #{option_extra_attr_evaluation}>evaluation</option>';
43
+ $rendered .= '<option value="developer" #{option_extra_attr_developer}>developer</option>';
44
+ $rendered .= '<option value="basic" #{option_extra_attr_basic}>basic</option>';
45
+ $rendered .= '<option value="standard" #{option_extra_attr_standard}>standard</option>';
46
+ $rendered .= '<option value="business" #{option_extra_attr_business}>business</option>';
47
+ $rendered .= '<option value="corporate" #{option_extra_attr_corporate}>corporate</option>';
48
+ $rendered .= '<option value="enterprise" #{option_extra_attr_enterprise}>enterprise</option>';
49
+ $rendered .= '<option value="unlimited" #{option_extra_attr_unlimited}>unlimited</option>';
50
+ $rendered .= '</select>';
51
+
52
+ return $rendered;
53
+ }
54
+ return parent::_renderCellTemplate($columnName);
55
+ }
56
+
57
+ protected function _prepareArrayRow(Varien_Object $row)
58
+ {
59
+ $row->setData(
60
+ 'option_extra_attr_' . $row->getData('type'),
61
+ 'selected="selected"'
62
+ );
63
+ }
64
+ }
65
+ ?>
app/code/local/Ax/Zoom/Block/Adminhtml/Tabs.php ADDED
@@ -0,0 +1,27 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ class Ax_Zoom_Block_Adminhtml_Tabs extends Mage_Adminhtml_Block_Catalog_Product_Edit_Tabs
4
+ {
5
+ private $parent;
6
+
7
+ protected function _prepareLayout()
8
+ {
9
+
10
+ $productId = Mage::app()->getRequest()->getParam('id');
11
+
12
+ //get all existing tabs
13
+ $this->parent = parent::_prepareLayout();
14
+
15
+ if (!empty($productId)) {
16
+ //add new tab
17
+ $this->addTab(
18
+ 'tabid', array(
19
+ 'label' => Mage::helper('catalog')->__('AJAX ZOOM'),
20
+ 'content' => $this->getLayout()
21
+ ->createBlock('zoom/adminhtml_tabs_tabid')->toHtml(),
22
+ ));
23
+ }
24
+
25
+ return $this->parent;
26
+ }
27
+ }
app/code/local/Ax/Zoom/Block/Adminhtml/Tabs/Tabid.php ADDED
@@ -0,0 +1,35 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ class Ax_Zoom_Block_Adminhtml_Tabs_Tabid extends Mage_Adminhtml_Block_Widget
4
+ {
5
+ public function __construct()
6
+ {
7
+ parent::__construct();
8
+
9
+ $productId = Mage::app()->getRequest()->getParam('id');
10
+
11
+ if (!empty($productId)) {
12
+ $this->assign(array(
13
+ 'files' => $this->getArcList()
14
+ ));
15
+ $this->setTemplate('axzoom/tab.phtml');
16
+ }
17
+ }
18
+
19
+ public function getArcList() {
20
+
21
+ $baseDir = Mage::getBaseDir();
22
+ $files = array();
23
+
24
+ if ($handle = opendir($baseDir . '/js/axzoom/zip/')) {
25
+ while (false !== ($entry = readdir($handle))) {
26
+ if ($entry != '.' && $entry != '..' && strtolower(substr($entry, -3)) == 'zip') {
27
+ array_push($files, $entry);
28
+ }
29
+ }
30
+ closedir($handle);
31
+ }
32
+
33
+ return $files;
34
+ }
35
+ }
app/code/local/Ax/Zoom/Helper/Data.php ADDED
@@ -0,0 +1,4 @@
 
 
 
 
1
+ <?php
2
+ class Ax_Zoom_Helper_Data extends Mage_Core_Helper_Abstract
3
+ {
4
+ }
app/code/local/Ax/Zoom/Helper/Head.php ADDED
@@ -0,0 +1,34 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ class Ax_Zoom_Helper_Head extends Mage_Core_Helper_Abstract
3
+ {
4
+ public function getFancyboxCSS()
5
+ {
6
+ if (Mage::getStoreConfig('axzoom_options/main/ajaxZoomOpenMode') == 'fancyboxFullscreen' || Mage::getStoreConfig('axzoom_options/main/ajaxZoomOpenMode') == 'fancybox') {
7
+ return 'axzoom/axZm/plugins/demo/jquery.fancybox/jquery.fancybox-1.3.4.css';
8
+ }
9
+ }
10
+ public function getFancyboxJS()
11
+ {
12
+ if (Mage::getStoreConfig('axzoom_options/main/ajaxZoomOpenMode') == 'fancyboxFullscreen' || Mage::getStoreConfig('axzoom_options/main/ajaxZoomOpenMode') == 'fancybox') {
13
+ return 'axzoom/axZm/plugins/demo/jquery.fancybox/jquery.fancybox-1.3.4.pack.js';
14
+ }
15
+ }
16
+ public function getFancyboxJSAX()
17
+ {
18
+ if (Mage::getStoreConfig('axzoom_options/main/ajaxZoomOpenMode') == 'fancyboxFullscreen' || Mage::getStoreConfig('axzoom_options/main/ajaxZoomOpenMode') == 'fancybox') {
19
+ return 'axzoom/axZm/extensions/jquery.axZm.openAjaxZoomInFancyBox.js';
20
+ }
21
+ }
22
+ public function getColorboxCSS()
23
+ {
24
+ if (Mage::getStoreConfig('axzoom_options/main/ajaxZoomOpenMode') == 'colorbox') {
25
+ return 'axzoom/axZm/plugins/demo/colorbox/example2/colorbox.css';
26
+ }
27
+ }
28
+ public function getColorboxJS()
29
+ {
30
+ if (Mage::getStoreConfig('axzoom_options/main/ajaxZoomOpenMode') == 'colorbox') {
31
+ return 'axzoom/axZm/plugins/demo/colorbox/jquery.colorbox-min.js';
32
+ }
33
+ }
34
+ }
app/code/local/Ax/Zoom/Model/Ax360.php ADDED
@@ -0,0 +1,210 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ class Ax_Zoom_Model_Ax360 extends Mage_Core_Model_Abstract
3
+ {
4
+ static $axZmH;
5
+ static $zoom;
6
+
7
+ protected function _construct()
8
+ {
9
+ parent::_construct();
10
+ $this->_init('axzoom/ax360');
11
+ }
12
+
13
+ public function getSetsGroups($productId)
14
+ {
15
+ $tblItems = Mage::getSingleton('core/resource')->getTableName('ajaxzoom360set');
16
+ $collection = Mage::getModel('axzoom/ax360')->getCollection();
17
+ $collection->getSelect()->join(array('i' => $tblItems),
18
+ 'main_table.id_360 = i.id_360',
19
+ array('qty' => 'COUNT(i.id_360)', 'id_360set' => 'id_360set'));
20
+
21
+ $collection->getSelect()->group('main_table.id_360');
22
+ return $collection->addFieldToFilter('id_product', $productId)->getData();
23
+ }
24
+
25
+ public function getSetsGroup($id360)
26
+ {
27
+ $tblItems = Mage::getSingleton('core/resource')->getTableName('ajaxzoom360set');
28
+ $collection = Mage::getModel('axzoom/ax360')->getCollection();
29
+ $collection->getSelect()->join(array('i' => $tblItems),
30
+ 'main_table.id_360 = i.id_360',
31
+ array('qty' => 'COUNT(i.id_360)', 'id_360set' => 'id_360set'));
32
+
33
+ $collection->getSelect()->group('main_table.id_360');
34
+ return $collection->addFieldToFilter('main_table.id_360', $id360)->getData();
35
+ }
36
+
37
+ public function images360Json($productId, $extraGroups = array())
38
+ {
39
+
40
+ $extraGroups = array_unique($extraGroups);
41
+
42
+ $json = '{';
43
+ $cnt = 1;
44
+
45
+ if (!is_array($productId)) {
46
+ $products = array($productId);
47
+ } else {
48
+ $products = $productId;
49
+ }
50
+
51
+ foreach ($products as $productId) {
52
+ $setsGroups = $this->getSetsGroups($productId);
53
+ foreach ($setsGroups as $group) {
54
+
55
+ if ($group['status'] == 0)
56
+ continue;
57
+
58
+ $settings = $this->prepareSettings($group['settings']);
59
+ if (!empty($settings)) $settings = ", $settings";
60
+
61
+ if ($group['qty'] > 0) {
62
+ if ($group['qty'] == 1) {
63
+ $json .= "'" . $group['id_360'] . "'" . ": {'path': '" . $this->rootFolder() . "js/axzoom/pic/360/" . $productId . "/" . $group['id_360'] . "/" . $group['id_360set'] . "'" . $settings . ", 'combinations': [" . $group['combinations'] . "]}";
64
+ } else {
65
+ $json .= "'" . $group['id_360'] . "'" . ": {'path': '" . $this->rootFolder() . "js/axzoom/pic/360/" . $productId . "/" . $group['id_360'] . "'" . $settings . ", 'combinations': [" . $group['combinations'] . "]}";
66
+ }
67
+ $cnt++;
68
+ if ($cnt != count($setsGroups)+1) $json .= ',';
69
+ }
70
+ }
71
+ }
72
+
73
+ $cnt = 1;
74
+ if ($extraGroups) foreach ($extraGroups as $id360) {
75
+
76
+ $setsGroup = $this->getSetsGroup($id360);
77
+ $group = $setsGroup[0];
78
+
79
+ if ($group['status'] == 0)
80
+ continue;
81
+
82
+ $settings = $this->prepareSettings($group['settings']);
83
+ if (!empty($settings)) $settings = ", $settings";
84
+
85
+ if ($group['qty'] > 0) {
86
+ if ($group['qty'] == 1) {
87
+ $json .= "'" . $group['id_360'] . "'" . ": {'path': '" . $this->rootFolder() . "js/axzoom/pic/360/" . $group['id_product'] . "/" . $group['id_360'] . "/" . $group['id_360set'] . "'" . $settings . ", 'combinations': [" . $group['combinations'] . "]}";
88
+ } else {
89
+ $json .= "'" . $group['id_360'] . "'" . ": {'path': '" . $this->rootFolder() . "js/axzoom/pic/360/" . $group['id_product'] . "/" . $group['id_360'] . "'" . $settings . ", 'combinations': [" . $group['combinations'] . "]}";
90
+ }
91
+ $cnt++;
92
+ if ($cnt != count($extraGroups)+1) $json .= ',';
93
+ }
94
+
95
+ }
96
+
97
+ $json .= '}';
98
+
99
+ return $json;
100
+ }
101
+
102
+ public function prepareSettings($str)
103
+ {
104
+ $res = array();
105
+ $settings = (array)Mage::helper('core')->jsonDecode($str);
106
+ foreach ($settings as $key => $value) {
107
+ if ($value == 'false' || $value == 'true' || $value == 'null' || is_numeric($value) || substr($value, 0, 1) == '{' || substr($value, 0, 1) == '[') {
108
+ $res[] = "'$key': $value";
109
+ } else {
110
+ $res[] = "'$key': '$value'";
111
+ }
112
+ }
113
+ return implode(', ', $res);
114
+ }
115
+
116
+ public function get360Images($productId, $id360set = '')
117
+ {
118
+ $files = array();
119
+ $id360 = Mage::getModel('axzoom/ax360set')->load($id360set)->getId_360();
120
+
121
+ $dir = Mage::getBaseDir() . '/js/axzoom/pic/360/' . $productId . '/' . $id360 . '/' . $id360set;
122
+ if (file_exists($dir) && $handle = opendir($dir)) {
123
+ while (false !== ($entry = readdir($handle))) {
124
+ if ($entry != "." && $entry != "..") {
125
+ $files[] = $entry;
126
+ }
127
+ }
128
+ closedir($handle);
129
+ }
130
+ sort($files);
131
+
132
+ $res = array();
133
+ foreach ($files as $entry) {
134
+ $tmp = explode('.', $entry);
135
+ $ext = end($tmp);
136
+ $name = preg_replace('|\.' . $ext . '$|', '', $entry);
137
+ $res[] = array(
138
+ 'thumb' => Mage::getBaseUrl('js') . 'axzoom/axZm/zoomLoad.php?azImg=' . $this->rootFolder() . 'js/axzoom/pic/360/' . $productId . '/' . $id360 . '/' . $id360set . '/' . $entry . '&width=100&height=100&qual=90',
139
+ 'filename' => $entry,
140
+ 'id' => $name,
141
+ 'ext' => $ext
142
+ );
143
+ }
144
+
145
+ return $res;
146
+ }
147
+
148
+ public function deleteImageAZcache($file)
149
+ {
150
+
151
+ // Include all classes
152
+ include_once (Mage::getBaseDir() . '/js/axzoom/axZm/zoomInc.inc.php');
153
+ //error_reporting(E_ALL);
154
+ if (!Ax_Zoom_Model_Ax360::$axZmH){
155
+ Ax_Zoom_Model_Ax360::$axZmH = $axZmH;
156
+ Ax_Zoom_Model_Ax360::$zoom = $zoom;
157
+ }
158
+
159
+ // What to delete
160
+ $arrDel = array('In' => true, 'Th' => true, 'tC' => true, 'mO' => true, 'Ti' => true);
161
+
162
+ // Remove all cache
163
+ Ax_Zoom_Model_Ax360::$axZmH->removeAxZm(Ax_Zoom_Model_Ax360::$zoom, $file, $arrDel, false);
164
+ }
165
+
166
+ public function rootFolder()
167
+ {
168
+ $p = parse_url(Mage::getBaseUrl());
169
+ return str_replace('index.php/', '', $p['path']);
170
+ }
171
+
172
+ public function isProductActive($productId)
173
+ {
174
+ return !Mage::getModel('axzoom/axproducts')->getCollection()->addFieldToFilter('id_product', $productId)->count();
175
+ }
176
+
177
+ public function getCSV($input, $delimiter = ",", $enclosure = '"', $escape = "\\")
178
+ {
179
+ if (function_exists('str_getcsv')) {
180
+ return str_getcsv($input, $delimiter, $enclosure, $escape);
181
+ }
182
+ else {
183
+ $temp = fopen('php://memory', 'rw');
184
+ fwrite($temp, $input);
185
+ fseek($temp, 0);
186
+ $r = fgetcsv($temp, 0, $delimiter, $enclosure);
187
+ fclose($temp);
188
+ return $r;
189
+ }
190
+ }
191
+
192
+ public function isOnlyProductActive($productId)
193
+ {
194
+
195
+ $products = Mage::getStoreConfig('axzoom_options/products/displayOnlyForThisProductID');
196
+
197
+ if (empty($products)) {
198
+ return true;
199
+ }
200
+
201
+ $arr = $this->getCSV($products);
202
+ if (in_array($productId, $arr)) {
203
+ return true;
204
+ }
205
+ return false;
206
+ }
207
+ }
208
+
209
+ Ax_Zoom_Model_Ax360::$axZmH;
210
+ Ax_Zoom_Model_Ax360::$zoom;
app/code/local/Ax/Zoom/Model/Ax360set.php ADDED
@@ -0,0 +1,39 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ class Ax_Zoom_Model_Ax360set extends Mage_Core_Model_Abstract
3
+ {
4
+ protected function _construct()
5
+ {
6
+ parent::_construct();
7
+ $this->_init('axzoom/ax360set');
8
+ }
9
+
10
+ public function getSets($productId)
11
+ {
12
+
13
+ $model = Mage::getModel('axzoom/ax360set');
14
+ $setsCollection = $model->getCollection();
15
+
16
+ $tbl_set_group = Mage::getSingleton('core/resource')->getTableName('ajaxzoom360');
17
+ $setsCollection->getSelect()->join(array('t2' => $tbl_set_group), 'main_table.id_360 = t2.id_360 AND t2.id_product = ' . $productId, array('t2.name', 't2.status'));
18
+ $sets = $setsCollection->getData();
19
+
20
+ $baseDir = Mage::getBaseDir();
21
+ $baseUrlJs = Mage::getBaseUrl('js');
22
+
23
+ foreach ($sets as &$set) {
24
+ if (file_exists($baseDir . '/js/axzoom/pic/360/' . $productId . '/' . $set['id_360'] . '/' . $set['id_360set'])) {
25
+ $set['path'] = $baseUrlJs . 'axzoom/axZm/zoomLoad.php?qq=1&azImg360=' . $this->rootFolder() . 'js/axzoom/pic/360/' . $productId . '/' . $set['id_360'] . '/' . $set['id_360set'] . '&width=100&height=100&thumbMode=contain';
26
+ } else {
27
+ $set['path'] = $baseUrlJs . 'axzoom/no_image-100x100.jpg';
28
+ }
29
+ }
30
+
31
+ return $sets;
32
+ }
33
+
34
+ public function rootFolder()
35
+ {
36
+ $p = parse_url(Mage::getBaseUrl());
37
+ return str_replace('index.php/', '', $p['path']);
38
+ }
39
+ }
app/code/local/Ax/Zoom/Model/Axproducts.php ADDED
@@ -0,0 +1,9 @@
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ class Ax_Zoom_Model_Axproducts extends Mage_Core_Model_Abstract
3
+ {
4
+ protected function _construct()
5
+ {
6
+ parent::_construct();
7
+ $this->_init('axzoom/axproducts');
8
+ }
9
+ }
app/code/local/Ax/Zoom/Model/Observer.php ADDED
@@ -0,0 +1,91 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ class Ax_Zoom_Model_Observer {
3
+ public function coreBlockBefore($observer)
4
+ {
5
+
6
+ if ($observer->getBlock() instanceof Mage_Catalog_Block_Product_View_Media) {
7
+
8
+ // if AJAX ZOOM is enabled for exact product then replace the product/view/media block
9
+ $productId = Mage::app()->getRequest()->getParam('id');
10
+
11
+ $ax = Mage::getModel('axzoom/ax360');
12
+ $active = $ax->isProductActive($productId);
13
+
14
+ if($active && $ax->isOnlyProductActive($productId)) {
15
+ $observer->getBlock()->setTemplate('ax_zoom/catalog/product/view/media.phtml');
16
+ }
17
+ }
18
+ }
19
+
20
+
21
+ public function productBefore($observer)
22
+ {
23
+ }
24
+
25
+ public function productSaveBefore($observer)
26
+ {
27
+ }
28
+
29
+ public function productSaveAfter($observer)
30
+ {
31
+ }
32
+
33
+ public function deleteProduct($observer)
34
+ {
35
+ $product = $observer->getProduct();
36
+ $model = Mage::getModel('axzoom/ax360');
37
+ $sets = Mage::getModel('axzoom/ax360set')->getSets($product->entity_id);
38
+
39
+ // clear AZ cache
40
+ foreach ($sets as $set) {
41
+ $images = $model->get360Images($product->entity_id, $set['id_360set']);
42
+
43
+ foreach ($images as $image) {
44
+ $model->deleteImageAZcache($image['filename']);
45
+ }
46
+ }
47
+
48
+ if ($images = $product->getMediaGalleryImages()) foreach ($images as $image) {
49
+ $model->deleteImageAZcache(basename($image->getFile()));
50
+ }
51
+ }
52
+
53
+ public function save360($observer)
54
+ {
55
+ $productId = $observer->product->entity_id;
56
+ $postData = Mage::app()->getRequest()->getPost();
57
+
58
+ // remove images from Ax cache if image checked as remove
59
+ $images = Mage::helper('core')->jsonDecode($postData['product']['media_gallery']['images']);
60
+ foreach ($images as $image) {
61
+ if(isset($image['removed']) && $image['removed'] == 1) {
62
+ Mage::getModel('axzoom/ax360')->deleteImageAZcache(basename($image['file']));
63
+ }
64
+ }
65
+
66
+ // save status
67
+ if (isset($postData['az_active']) && $postData['az_active'] == 1) {
68
+ $this->activateAx($productId);
69
+ } else {
70
+ Mage::getModel('axzoom/axproducts')->setData(array('id_product' => $productId))->save();
71
+ }
72
+
73
+ // save settings
74
+ if(isset($postData['settings'])) foreach ($postData['settings'] as $id_360 => $string) {
75
+
76
+ Mage::getModel('axzoom/ax360')->load($id_360)->addData(array(
77
+ 'settings' => urldecode($string),
78
+ 'combinations' => urldecode($postData['comb'][$id_360])
79
+ ))->setId($id_360)->save();
80
+ }
81
+ }
82
+
83
+ public function activateAx($productId)
84
+ {
85
+ $res = Mage::getSingleton('core/resource');
86
+ $con = $res->getConnection('core_write');
87
+ $table = $res->getTableName('axzoom/table_axproducts');
88
+ $query = "DELETE FROM {$table} WHERE id_product = " . (int)$productId;
89
+ $con->query($query);
90
+ }
91
+ }
app/code/local/Ax/Zoom/Model/Position.php ADDED
@@ -0,0 +1,14 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ class Ax_Zoom_Model_Position
3
+ {
4
+ public function toOptionArray()
5
+ {
6
+ return array(
7
+ array('value'=>'inside', 'label'=>Mage::helper('axzoom')->__('inside')),
8
+ array('value'=>'top', 'label'=>Mage::helper('axzoom')->__('top')),
9
+ array('value'=>'right', 'label'=>Mage::helper('axzoom')->__('right')),
10
+ array('value'=>'bottom', 'label'=>Mage::helper('axzoom')->__('bottom')),
11
+ array('value'=>'left', 'label'=>Mage::helper('axzoom')->__('left'))
12
+ );
13
+ }
14
+ }
app/code/local/Ax/Zoom/Model/Resource/Ax360.php ADDED
@@ -0,0 +1,8 @@
 
 
 
 
 
 
 
 
1
+ <?php
2
+ class Ax_Zoom_Model_Resource_Ax360 extends Mage_Core_Model_Mysql4_Abstract
3
+ {
4
+ public function _construct()
5
+ {
6
+ $this->_init('axzoom/table_ax360', 'id_360');
7
+ }
8
+ }
app/code/local/Ax/Zoom/Model/Resource/Ax360/Collection.php ADDED
@@ -0,0 +1,9 @@
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ class Ax_Zoom_Model_Resource_Ax360_Collection extends Mage_Core_Model_Mysql4_Collection_Abstract
3
+ {
4
+ public function _construct()
5
+ {
6
+ parent::_construct();
7
+ $this->_init('axzoom/ax360');
8
+ }
9
+ }
app/code/local/Ax/Zoom/Model/Resource/Ax360set.php ADDED
@@ -0,0 +1,8 @@
 
 
 
 
 
 
 
 
1
+ <?php
2
+ class Ax_Zoom_Model_Resource_Ax360set extends Mage_Core_Model_Mysql4_Abstract
3
+ {
4
+ public function _construct()
5
+ {
6
+ $this->_init('axzoom/table_ax360set', 'id_360set');
7
+ }
8
+ }
app/code/local/Ax/Zoom/Model/Resource/Ax360set/Collection.php ADDED
@@ -0,0 +1,9 @@
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ class Ax_Zoom_Model_Resource_Ax360set_Collection extends Mage_Core_Model_Mysql4_Collection_Abstract
3
+ {
4
+ public function _construct()
5
+ {
6
+ parent::_construct();
7
+ $this->_init('axzoom/ax360set');
8
+ }
9
+ }
app/code/local/Ax/Zoom/Model/Resource/Axproducts.php ADDED
@@ -0,0 +1,8 @@
 
 
 
 
 
 
 
 
1
+ <?php
2
+ class Ax_Zoom_Model_Resource_Axproducts extends Mage_Core_Model_Mysql4_Abstract
3
+ {
4
+ public function _construct()
5
+ {
6
+ $this->_init('axzoom/table_axproducts', null);
7
+ }
8
+ }
app/code/local/Ax/Zoom/Model/Resource/Axproducts/Collection.php ADDED
@@ -0,0 +1,9 @@
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ class Ax_Zoom_Model_Resource_Axproducts_Collection extends Mage_Core_Model_Mysql4_Collection_Abstract
3
+ {
4
+ public function _construct()
5
+ {
6
+ parent::_construct();
7
+ $this->_init('axzoom/axproducts');
8
+ }
9
+ }
app/code/local/Ax/Zoom/Model/Words.php ADDED
@@ -0,0 +1,14 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ class Ax_Zoom_Model_Words
3
+ {
4
+ public function toOptionArray()
5
+ {
6
+ return array(
7
+ array('value'=>1, 'label'=>Mage::helper('axzoom')->__('Hello')),
8
+ array('value'=>2, 'label'=>Mage::helper('axzoom')->__('Goodbye')),
9
+ array('value'=>3, 'label'=>Mage::helper('axzoom')->__('Yes')),
10
+ array('value'=>4, 'label'=>Mage::helper('axzoom')->__('No')),
11
+ );
12
+ }
13
+
14
+ }
app/code/local/Ax/Zoom/Model/Yesno.php ADDED
@@ -0,0 +1,12 @@
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ class Ax_Zoom_Model_Yesno
3
+ {
4
+ public function toOptionArray()
5
+ {
6
+ return array(
7
+ array('value'=>0, 'label'=>Mage::helper('axzoom')->__('No')),
8
+ array('value'=>1, 'label'=>Mage::helper('axzoom')->__('Yes'))
9
+ );
10
+ }
11
+
12
+ }
app/code/local/Ax/Zoom/controllers/IndexController.php ADDED
@@ -0,0 +1,387 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ class Ax_Zoom_IndexController extends Mage_Core_Controller_Front_Action
3
+ {
4
+ public function AddProductImage360Action()
5
+ {
6
+
7
+ $productId = Mage::app()->getRequest()->getParam('id_product');
8
+ $id360set = $this->getRequest()->getPost('id_360set');
9
+ $id360 = Mage::getModel('axzoom/ax360set')->load($id360set)->getId_360();
10
+ $folder = $this->createProduct360Folder($productId, $id360set);
11
+
12
+ if (isset($_FILES['file360']['name'][0]) && $_FILES['file360']['name'][0] != '') {
13
+ try {
14
+ $fileName = $_FILES['file360']['name'][0];
15
+ $fileExt = strtolower(substr(strrchr($fileName, '.'), 1));
16
+ $fileNamewoe = $productId . '_' . $id360set . '_' . $this->imgNameFilter(rtrim($fileName, '.' . $fileExt));
17
+ $fileName = $fileNamewoe . '.' . $fileExt;
18
+
19
+ $uploader = new Varien_File_Uploader(array(
20
+ 'name' => $_FILES['file360']['name'][0],
21
+ 'type' => $_FILES['file360']['type'][0],
22
+ 'tmp_name' => $_FILES['file360']['tmp_name'][0],
23
+ 'error' => $_FILES['file360']['error'][0],
24
+ 'size' => $_FILES['file360']['size'][0]
25
+ ));
26
+ $uploader->setAllowedExtensions(array('png', 'jpg')); //allowed extensions
27
+ $uploader->setAllowRenameFiles(false);
28
+ $uploader->setFilesDispersion(false);
29
+
30
+ $uploader->save($folder, $fileName );
31
+ } catch (Exception $e) {
32
+ echo $e->getMessage();
33
+ exit;
34
+ }
35
+ }
36
+
37
+ die(Mage::helper('core')->jsonEncode(array(
38
+ 'file360' => array(array(
39
+ 'status' => 'ok',
40
+ 'name' => $fileName,
41
+ 'id' => $fileNamewoe,
42
+ 'id_product' => $productId,
43
+ 'id_360' => $id360,
44
+ 'id_360set' => $id360set,
45
+ 'path' => Mage::getBaseUrl('js') . 'axzoom/axZm/zoomLoad.php?qq=1&azImg=' . $this->rootFolder() . 'js/axzoom/pic/360/' . $productId . '/' . $id360 . '/' . $id360set . '/' . $fileName . '&width=100&height=100&qual=90'
46
+ )))));
47
+ exit;
48
+ }
49
+
50
+ public function DeleteProductImage360Action()
51
+ {
52
+ $get = Mage::app()->getRequest();
53
+ $imageId = $get->getParam('id_image');
54
+ $productId = $get->getParam('id_product');
55
+ $id360set = $get->getParam('id_360set');
56
+ $id360 = Mage::getModel('axzoom/ax360set')->load($id360set)->getId_360();
57
+ $tmp = explode('&', $get->getParam('ext'));
58
+ $ext = reset($tmp);
59
+ $filename = $imageId . '.' . $ext;
60
+
61
+ $dst = Mage::getBaseDir() . '/js/axzoom/pic/360/' . $productId . '/' . $id360 . '/' . $id360set . '/' . $filename;
62
+ unlink($dst);
63
+
64
+ Mage::getModel('axzoom/ax360')->deleteImageAZcache($filename);
65
+
66
+ die(Mage::helper('core')->jsonEncode(array(
67
+ 'status' => 'ok',
68
+ 'content' => (object)array('id' => $imageId),
69
+ 'confirmations' => array('The image was successfully deleted.')
70
+ )));
71
+ }
72
+
73
+ public function ClearAzImageCacheAction()
74
+ {
75
+ $filename = (int)(Mage::app()->getRequest()->getParam('deletedImgID')) . '.jpg';
76
+ Mage::getModel('axzoom/ax360')->deleteImageAZcache($filename);
77
+ die(Mage::helper('core')->jsonEncode(array(
78
+ 'status' => 'ok',
79
+ 'confirmations' => array('AJAX-ZOOM cache has been deleted for image with ID ' . (int)(Mage::app()->getRequest()->getParam('deletedImgID')))
80
+ )));
81
+ }
82
+
83
+ public function GetImagesAction()
84
+ {
85
+ $get = Mage::app()->getRequest();
86
+ $productId = $get->getParam('id_product');
87
+ $id360set = $get->getParam('id_360set');
88
+ $images = Mage::getModel('axzoom/ax360')->get360Images($productId, $id360set);
89
+
90
+ die(Mage::helper('core')->jsonEncode(array(
91
+ 'status' => 'ok',
92
+ 'id_product' => $productId,
93
+ 'id_360set' => $id360set,
94
+ 'images' => $images
95
+ )));
96
+ }
97
+
98
+ public function DeleteSetAction()
99
+ {
100
+ $get = Mage::app()->getRequest();
101
+ $productId = $get->getParam('id_product');
102
+ $id360set = $get->getParam('id_360set');
103
+ $id360 = Mage::getModel('axzoom/ax360set')->load($id360set)->getId_360();
104
+
105
+ // clear AZ cache
106
+ $images = Mage::getModel('axzoom/ax360')->get360Images($productId, $id360set);
107
+
108
+ foreach ($images as $image) {
109
+ Mage::getModel('axzoom/ax360')->deleteImageAZcache($image['filename']);
110
+ }
111
+
112
+ Mage::getModel('axzoom/ax360set')->setId($id360set)->delete();
113
+
114
+ if (!Mage::getModel('axzoom/ax360set')->getCollection()->addFieldToFilter('id_360', $id360)->getData()) {
115
+ Mage::getModel('axzoom/ax360')->setId($id360)->delete();
116
+ }
117
+
118
+ $path = Mage::getBaseDir() . '/js/axzoom/pic/360/' . $productId . '/' . $id360 . '/' . $id360set;
119
+ $this->deleteDirectory($path);
120
+
121
+ die(Mage::helper('core')->jsonEncode(array(
122
+ 'id_360set' => $id360set,
123
+ 'id_360' => $id360,
124
+ 'path' => $path,
125
+ 'removed' => (!Mage::getModel('axzoom/ax360')->load($id360)->getData() ? 1 : 0),
126
+ 'confirmations' => array('The 360 image set was successfully removed.')
127
+ )));
128
+ }
129
+
130
+ public function Set360StatusAction()
131
+ {
132
+ $get = Mage::app()->getRequest();
133
+ $productId = $get->getParam('id_product');
134
+ $id360 = $get->getParam('id_360');
135
+ $status = $get->getParam('status');
136
+
137
+ Mage::getModel('axzoom/ax360')->load($id360)->addData(array('status' => $status))->setId($id360)->save();
138
+
139
+ die(Mage::helper('core')->jsonEncode(array(
140
+ 'status' => 'ok',
141
+ 'confirmations' => array('The status has been updated.' . $status . '-' . $id360)
142
+ )));
143
+ }
144
+
145
+ public function AddSetAction()
146
+ {
147
+ $get = Mage::app()->getRequest();
148
+ $productId = $get->getParam('id_product');
149
+ $name = $get->getParam('name');
150
+ $existing = $get->getParam('existing');
151
+ $zip = $get->getParam('zip');
152
+ $arcfile = $get->getParam('arcfile');
153
+ $newId = '';
154
+ $newName = '';
155
+ $newSettings = '';
156
+ $status = ($zip == 'true' ? 1 : 0);
157
+
158
+ if (!empty($existing)) {
159
+ $id360 = $existing;
160
+ $name = Mage::getModel('axzoom/ax360')->load($id360)->getName();
161
+ } else {
162
+ $newSettings = $settings = '{"position":"first","spinReverse":"true","spinBounce":"false","spinDemoRounds":"3","spinDemoTime":"4500"}';
163
+ $data = array(
164
+ 'id_product' => $productId,
165
+ 'name' => $name,
166
+ 'settings' => $settings,
167
+ 'status' => $status
168
+ );
169
+ $id360 = $newId = Mage::getModel('axzoom/ax360')->setData($data)->save()->getId();
170
+ $newName = $name;
171
+ }
172
+
173
+ $id360set = Mage::getModel('axzoom/ax360set')->setData(array('id_360' => $id360, 'sort_order' => 0))->save()->getId();
174
+
175
+ $sets = array();
176
+
177
+ if ($zip == 'true') {
178
+ $sets = $this->addImagesArc($arcfile, $productId, $id360, $id360set);
179
+ }
180
+
181
+ die(Mage::helper('core')->jsonEncode(array(
182
+ 'status' => $status,
183
+ 'name' => $name,
184
+ 'path' => Mage::getBaseUrl('js') . 'axzoom/no_image-100x100.jpg',
185
+ 'sets' => $sets,
186
+ 'id_360' => $id360,
187
+ 'id_product' => $productId,
188
+ 'id_360set' => $id360set,
189
+ 'confirmations' => array('The image set was successfully added.'),
190
+ 'new_id' => $newId,
191
+ 'new_name' => $newName,
192
+ 'new_settings' => urlencode($newSettings)
193
+ )));
194
+ }
195
+
196
+
197
+ public function addImagesArc($arcfile, $productId, $id360, $id360set)
198
+ {
199
+ set_time_limit(0);
200
+
201
+ $baseDir = Mage::getBaseDir();
202
+ $baseUrlJs = Mage::getBaseUrl('js');
203
+
204
+ $path = $baseDir . '/js/axzoom/zip/' . $arcfile;
205
+ $dst = $this->extractArc($path);
206
+ $data = $this->getFolderData($dst);
207
+
208
+ $name = Mage::getModel('axzoom/ax360')->load($id360)->getName();
209
+
210
+ $sets = array(array(
211
+ 'name' => $name,
212
+ 'path' => $baseUrlJs . 'axzoom/axZm/zoomLoad.php?qq=1&azImg360=' . $this->rootFolder() . 'js/axzoom/pic/360/' . $productId . '/' . $id360 . '/' . $id360set . '&width=100&height=100&thumbMode=contain',
213
+ 'id_360set' => $id360set,
214
+ 'id_360' => $id360,
215
+ 'status' => '1'
216
+ ));
217
+
218
+ if (count($data['folders']) == 0) { // files (360)
219
+ $this->copyImages($productId, $id360, $id360set, $dst);
220
+ } elseif (count($data['folders']) == 1) { // 1 folder (360)
221
+ $this->copyImages($productId, $id360, $id360set, $dst . '/' . $data['folders'][0]);
222
+ } else { // 3d
223
+ $this->copyImages($productId, $id360, $id360set, $dst . '/' . $data['folders'][0]);
224
+ for ($i=1; $i < count($data['folders']); $i++) {
225
+ $id360set = Mage::getModel('axzoom/ax360set')->setData(array('id_360' => $id360, 'sort_order' => 0))->save()->getId();
226
+ $this->copyImages($productId, $id360, $id360set, $dst . '/' . $data['folders'][$i]);
227
+
228
+ $sets[] = array(
229
+ 'name' => $name,
230
+ 'path' => $baseUrlJs . 'axzoom/axZm/zoomLoad.php?qq=1&azImg360=' . $this->rootFolder() . 'js/axzoom/pic/360/' . $productId . '/' . $id360 . '/' . $id360set . '&width=100&height=100&thumbMode=contain',
231
+ 'id_360set' => $id360set
232
+ );
233
+ }
234
+ }
235
+
236
+ $this->deleteDirectory($dst);
237
+ return $sets;
238
+ }
239
+
240
+ public function extractArc($file)
241
+ {
242
+
243
+ $baseDir = Mage::getBaseDir();
244
+
245
+ $zip = new ZipArchive;
246
+ $res = $zip->open($file);
247
+ if ($res === TRUE) {
248
+ $folder = uniqid(getmypid());
249
+ $path = $baseDir . '/js/axzoom/tmp/' . $folder;
250
+ mkdir($path, 0777);
251
+ $zip->extractTo($path);
252
+ $zip->close();
253
+ return $path;
254
+ } else {
255
+ return false;
256
+ }
257
+ }
258
+
259
+ public function getFolderData($path)
260
+ {
261
+ $files = array();
262
+ $folders = array();
263
+ if ($handle = opendir($path)) {
264
+ while (false !== ($entry = readdir($handle))) {
265
+ if ($entry != '.' && $entry != '..') {
266
+ if (is_dir($path . '/' . $entry)) {
267
+ array_push($folders, $entry);
268
+ } else {
269
+ array_push($files, $entry);
270
+ }
271
+ }
272
+ }
273
+ closedir($handle);
274
+ }
275
+
276
+ sort($folders);
277
+ sort($files);
278
+
279
+ return array(
280
+ 'folders' => $folders,
281
+ 'files' => $files
282
+ );
283
+ }
284
+
285
+ public function copyImages($productId, $id360, $id360set, $path)
286
+ {
287
+ $files = $this->getFilesFromFolder($path);
288
+ $folder = $this->createProduct360Folder($productId, $id360set);
289
+
290
+ foreach ($files as $file)
291
+ {
292
+ $name = $productId . '_' . $id360set . '_' . $this->imgNameFilter($file);
293
+ $tmp = explode('.', $name);
294
+ $ext = end($tmp);
295
+ $dst = $folder . '/' . $name;
296
+ rename($path . '/' . $file, $dst);
297
+ }
298
+ }
299
+
300
+
301
+ public function getFilesFromFolder($path)
302
+ {
303
+ $files = array();
304
+ if ($handle = opendir($path)) {
305
+ while (false !== ($entry = readdir($handle))) {
306
+ if ($entry != '.' && $entry != '..') {
307
+ $files[] = $entry;
308
+ }
309
+ }
310
+ closedir($handle);
311
+ }
312
+
313
+ return $files;
314
+ }
315
+
316
+ public function createProduct360Folder($productId, $id360set)
317
+ {
318
+ $productId = (int)($productId);
319
+ $id360set = (int)($id360set);
320
+ $id360 = Mage::getModel('axzoom/ax360set')->load($id360set)->getId_360();
321
+
322
+ $imgPath = Mage::getBaseDir() . '/js/axzoom/pic/360/';
323
+ @chmod(rtrim($imgPath, '/'), 0777);
324
+
325
+ if (!file_exists($imgPath . '.htaccess')) {
326
+ file_put_contents($imgPath . '.htaccess', 'deny from all');
327
+ }
328
+
329
+ if (!file_exists($imgPath . $productId)) {
330
+ mkdir($imgPath . $productId, 0777);
331
+ }
332
+
333
+ if (!file_exists($imgPath . $productId . '/' . $id360)) {
334
+ mkdir($imgPath . $productId . '/' . $id360, 0777);
335
+ }
336
+
337
+ $folder = $imgPath . $productId . '/' . $id360 . '/' . $id360set;
338
+
339
+ if (!file_exists($folder)) {
340
+ mkdir($folder, 0777);
341
+ } else {
342
+ chmod($folder, 0777);
343
+ }
344
+
345
+ return $folder;
346
+ }
347
+
348
+ public function deleteDirectory($dirname, $delete_self = true)
349
+ {
350
+ $dirname = rtrim($dirname, '/') . '/';
351
+ if (file_exists($dirname))
352
+ if ($files = scandir($dirname))
353
+ {
354
+ foreach ($files as $file)
355
+ if ($file != '.' && $file != '..' && $file != '.svn')
356
+ {
357
+ if (is_dir($dirname.$file))
358
+ $this->deleteDirectory($dirname.$file, true);
359
+ elseif (file_exists($dirname.$file))
360
+ {
361
+ @chmod($dirname.$file, 0777); // NT ?
362
+ unlink($dirname.$file);
363
+ }
364
+ }
365
+ if ($delete_self && file_exists($dirname))
366
+ if (!rmdir($dirname))
367
+ {
368
+ @chmod($dirname, 0777); // NT ?
369
+ return false;
370
+ }
371
+ return true;
372
+ }
373
+ return false;
374
+ }
375
+
376
+ public function imgNameFilter($filename)
377
+ {
378
+ $filename = preg_replace('/[^A-Za-z0-9_\.-]/', '-', $filename);
379
+ return $filename;
380
+ }
381
+
382
+ public function rootFolder()
383
+ {
384
+ $p = parse_url(Mage::getBaseUrl());
385
+ return str_replace('index.php/', '', $p['path']);
386
+ }
387
+ }
app/code/local/Ax/Zoom/etc/config.xml ADDED
@@ -0,0 +1,349 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?xml version="1.0"?>
2
+ <config>
3
+
4
+ <modules>
5
+ <Ax_Zoom>
6
+ <version>0.0.1</version>
7
+ </Ax_Zoom>
8
+ </modules>
9
+
10
+ <global>
11
+ <helpers>
12
+ <axzoom>
13
+ <class>Ax_Zoom_Helper</class>
14
+ </axzoom>
15
+ </helpers>
16
+ <models>
17
+ <axzoom>
18
+ <class>Ax_Zoom_Model</class>
19
+ <resourceModel>axzoom_resource</resourceModel>
20
+ </axzoom>
21
+ <axzoom_resource>
22
+ <class>Ax_Zoom_Model_Resource</class>
23
+ <entities>
24
+ <table_ax360set>
25
+ <table>ajaxzoom360set</table>
26
+ </table_ax360set>
27
+ <table_ax360>
28
+ <table>ajaxzoom360</table>
29
+ </table_ax360>
30
+ <table_axproducts>
31
+ <table>ajaxzoomproducts</table>
32
+ </table_axproducts>
33
+ </entities>
34
+ </axzoom_resource>
35
+ </models>
36
+ <blocks>
37
+ <zoom>
38
+ <class>Ax_Zoom_Block</class>
39
+ </zoom>
40
+ <adminhtml>
41
+ <rewrite>
42
+ <catalog_product_edit_tabs>Ax_Zoom_Block_Adminhtml_Tabs</catalog_product_edit_tabs>
43
+ </rewrite>
44
+ </adminhtml>
45
+ </blocks>
46
+ <resources>
47
+ <axzoom_setup>
48
+ <setup>
49
+ <module>Ax_Zoom</module>
50
+ </setup>
51
+ </axzoom_setup>
52
+ </resources>
53
+ </global>
54
+
55
+ <frontend>
56
+ <translate>
57
+ <modules>
58
+ <Ax_Zoom>
59
+ <files>
60
+ <default>Ax_Zoom.csv</default>
61
+ </files>
62
+ </Ax_Zoom>
63
+ </modules>
64
+ </translate>
65
+
66
+ <routers>
67
+ <axzoom>
68
+ <use>standard</use>
69
+ <args>
70
+ <module>Ax_Zoom</module>
71
+ <frontName>axzoom</frontName>
72
+ </args>
73
+ </axzoom>
74
+ </routers>
75
+
76
+ <layout>
77
+ <updates>
78
+ <ax_zoom>
79
+ <file>axzoom.xml</file>
80
+ </ax_zoom>
81
+ </updates>
82
+ </layout>
83
+
84
+ <events>
85
+ <catalog_controller_product_init>
86
+ <observers>
87
+ <ax_zoom_model_observer>
88
+ <type>singleton</type>
89
+ <class>Ax_Zoom_Model_Observer</class>
90
+ <method>productBefore</method>
91
+ </ax_zoom_model_observer>
92
+ </observers>
93
+ </catalog_controller_product_init>
94
+
95
+ <core_block_abstract_to_html_before>
96
+ <observers>
97
+ <ax_zoom_model_observer>
98
+ <type>singleton</type>
99
+ <class>Ax_Zoom_Model_Observer</class>
100
+ <method>coreBlockBefore</method>
101
+ </ax_zoom_model_observer>
102
+ </observers>
103
+ </core_block_abstract_to_html_before>
104
+ </events>
105
+ </frontend>
106
+
107
+
108
+ <adminhtml>
109
+ <translate>
110
+ <modules>
111
+ <Ax_Zoom>
112
+ <files>
113
+ <default>Ax_Zoom.csv</default>
114
+ </files>
115
+ </Ax_Zoom>
116
+ </modules>
117
+ </translate>
118
+
119
+ <layout>
120
+ <updates>
121
+ <ax_zoom>
122
+ <file>axzoom.xml</file>
123
+ </ax_zoom>
124
+ </updates>
125
+ </layout>
126
+
127
+ <events>
128
+ <catalog_product_prepare_save>
129
+ <observers>
130
+ <ax_zoom_model_observer>
131
+ <type>singleton</type>
132
+ <class>Ax_Zoom_Model_Observer</class>
133
+ <method>save360</method>
134
+ </ax_zoom_model_observer>
135
+ </observers>
136
+ </catalog_product_prepare_save>
137
+
138
+ <catalog_product_delete_before>
139
+ <observers>
140
+ <ax_zoom_model_observer>
141
+ <type>singleton</type>
142
+ <class>Ax_Zoom_Model_Observer</class>
143
+ <method>deleteProduct</method>
144
+ </ax_zoom_model_observer>
145
+ </observers>
146
+ </catalog_product_delete_before>
147
+
148
+ <catalog_product_save_before>
149
+ <observers>
150
+ <ax_zoom_model_observer>
151
+ <type>singleton</type>
152
+ <class>Ax_Zoom_Model_Observer</class>
153
+ <method>productSaveBefore</method>
154
+ </ax_zoom_model_observer>
155
+ </observers>
156
+ </catalog_product_save_before>
157
+
158
+ <catalog_product_save_after>
159
+ <observers>
160
+ <ax_zoom_model_observer>
161
+ <type>singleton</type>
162
+ <class>Ax_Zoom_Model_Observer</class>
163
+ <method>productSaveAfter</method>
164
+ </ax_zoom_model_observer>
165
+ </observers>
166
+ </catalog_product_save_after>
167
+
168
+ </events>
169
+
170
+ <acl>
171
+ <resources>
172
+ <admin>
173
+ <children>
174
+ <system>
175
+ <children>
176
+ <config>
177
+ <children>
178
+ <axzoom_options>
179
+ <title>AJAX ZOOM Settings</title>
180
+ </axzoom_options>
181
+ </children>
182
+ </config>
183
+ </children>
184
+ </system>
185
+ </children>
186
+ </admin>
187
+ </resources>
188
+ </acl>
189
+
190
+ </adminhtml>
191
+
192
+ <default>
193
+ <axzoom_options>
194
+ <main>
195
+ <divid>az_mouseOverZoomContainer</divid>
196
+ <galleryDivID>az_mouseOverZoomGallery</galleryDivID>
197
+ <hideGalleryOneImage>1</hideGalleryOneImage>
198
+ <disableAllMsg >0</disableAllMsg >
199
+ <galleryHover></galleryHover>
200
+ <galleryAxZmThumbSlider>1</galleryAxZmThumbSlider>
201
+ <galleryAxZmThumbSliderParam>
202
+ {
203
+ orientation: "horizontal",
204
+ scrollBy: 1,
205
+ btn: true,
206
+ btnClass: "axZmThumbSlider_button_new",
207
+ btnBwdStyle: {
208
+ marginLeft: 0,
209
+ marginRight: 0
210
+ },
211
+ btnFwdStyle: {
212
+ marginLeft: 0,
213
+ marginRight: 0
214
+ },
215
+ btnLeftText: null,
216
+ btnRightText: null,
217
+ btnHidden: true,
218
+ pressScrollSnap: true,
219
+ centerNoScroll: true,
220
+ wrapStyle: {
221
+ borderWidth: 0
222
+ },
223
+ thumbImgStyle: {
224
+ maxHeight: "58px",
225
+ maxWidth: "58px"
226
+ },
227
+ thumbLiStyle: {
228
+ width: 58,
229
+ height: 58,
230
+ lineHeight: "56px",
231
+ marginBottom: 2,
232
+ marginLeft: 3,
233
+ marginRight: 3,
234
+ borderRadius: 3
235
+ }
236
+ }
237
+ </galleryAxZmThumbSliderParam>
238
+ <thumbW>58</thumbW>
239
+ <thumbH>58</thumbH>
240
+ <thumbRetina>1</thumbRetina>
241
+ <firstImageToLoad>1</firstImageToLoad>
242
+ <images360firstToLoad>0</images360firstToLoad>
243
+ <images360Opt>["spinReverse", "spinReverseZ", "spinBounce", "spinDemoRounds", "spinDemoTime", "spinWhilePreload"]</images360Opt>
244
+ <images360Thumb>1</images360Thumb>
245
+ <images360Preview>1</images360Preview>
246
+ <images360PreviewResponsive>1</images360PreviewResponsive>
247
+ <images360examplePreview>mouseOverExtension360</images360examplePreview>
248
+ <zoomMsg360>Drag to spin 360°, scroll to zoom in and out</zoomMsg360>
249
+ <preloadMouseOverImages>0</preloadMouseOverImages>
250
+ <noImageAvailableClass>axZm_mouseOverNoImage</noImageAvailableClass>
251
+ <width>auto</width>
252
+ <height>auto</height>
253
+ <responsive>1</responsive>
254
+ <oneSrcImg>0</oneSrcImg>
255
+ <heightRatio>1.0</heightRatio>
256
+ <heightMaxWidthRatio>["960|0.8", "700|0.7"]</heightMaxWidthRatio>
257
+ <widthRatio>false</widthRatio>
258
+ <widthMaxHeightRatio>false</widthMaxHeightRatio>
259
+ <maxSizePrc>1.0</maxSizePrc>
260
+ <mouseOverZoomWidth>1200</mouseOverZoomWidth>
261
+ <mouseOverZoomHeight>1200</mouseOverZoomHeight>
262
+ <ajaxZoomOpenMode>fancyboxFullscreen</ajaxZoomOpenMode>
263
+ <fancyBoxParam>{}</fancyBoxParam>
264
+ <colorBoxParam>{}</colorBoxParam>
265
+ <example>mouseOverExtension</example>
266
+ <exampleFancyboxFullscreen>mouseOverExtension</exampleFancyboxFullscreen>
267
+ <exampleFancybox>modal</exampleFancybox>
268
+ <exampleColorbox>modal</exampleColorbox>
269
+ <disableScrollAnm>1</disableScrollAnm>
270
+ <fullScreenApi>0</fullScreenApi>
271
+ <axZmCallBacks>{}</axZmCallBacks>
272
+ <azOptions>{}</azOptions>
273
+ <azOptions360>{}</azOptions360>
274
+ <qualityThumb>100</qualityThumb>
275
+ <quality>90</quality>
276
+ <qualityZoom>80</qualityZoom>
277
+ <onLoad>null</onLoad>
278
+ <onImageChange>null</onImageChange>
279
+ <onMouseOver>null</onMouseOver>
280
+ <onMouseOut>null</onMouseOut>
281
+ <spinner>1</spinner>
282
+ <spinnerParam>{}</spinnerParam>
283
+ </main>
284
+ <pinterest>
285
+ <enabled>1</enabled>
286
+ <build>parsePinBtns</build>
287
+ <wrapClass>axZm_mouseOverPinterest</wrapClass>
288
+ <href>//en.pinterest.com/pin/create/button/</href>
289
+ <description>null</description>
290
+ <url>null</url>
291
+ <media>null</media>
292
+ <btnSrc>//assets.pinterest.com/images/pidgets/pinit_fg_en_rect_gray_20.png</btnSrc>
293
+ <data>{}</data>
294
+ </pinterest>
295
+ <mouseOverZoomParam>
296
+ <position>right</position>
297
+ <posAutoInside>150</posAutoInside>
298
+ <posInsideArea>0.2</posInsideArea>
299
+ <autoFlip>120</autoFlip>
300
+ <biggestSpace>0</biggestSpace>
301
+ <zoomFullSpace>0</zoomFullSpace>
302
+ <zoomWidth>.product-shop|+2</zoomWidth>
303
+ <zoomHeight>.product-img-box</zoomHeight>
304
+ <autoMargin>15</autoMargin>
305
+ <adjustX>13</adjustX>
306
+ <adjustY>-1</adjustY>
307
+ <lensOpacity>0.30</lensOpacity>
308
+ <lensStyle>{}</lensStyle>
309
+ <lensClass>false</lensClass>
310
+ <zoomAreaBorderWidth>1</zoomAreaBorderWidth>
311
+ <galleryFade>300</galleryFade>
312
+ <shutterSpeed>150</shutterSpeed>
313
+ <showFade>300</showFade>
314
+ <hideFade>300</hideFade>
315
+ <flyOutSpeed>false</flyOutSpeed>
316
+ <flyOutTransition>linear</flyOutTransition>
317
+ <flyOutOpacity>0.6</flyOutOpacity>
318
+ <flyBackSpeed>false</flyBackSpeed>
319
+ <flyBackTransition>linear</flyBackTransition>
320
+ <flyBackOpacity>0.2</flyBackOpacity>
321
+ <autoScroll>0</autoScroll>
322
+ <smoothMove>6</smoothMove>
323
+ <tint>false</tint>
324
+ <tintOpacity>0.3</tintOpacity>
325
+ <tintFilter>false</tintFilter>
326
+ <tintLensBack>1</tintLensBack>
327
+ <showTitle>1</showTitle>
328
+ <titleOpacity>0.5</titleOpacity>
329
+ <titlePosition>top</titlePosition>
330
+ <cursorPositionX>0.5</cursorPositionX>
331
+ <cursorPositionY>0.55</cursorPositionY>
332
+ <touchClickAbort>500</touchClickAbort>
333
+ <loading>1</loading>
334
+ <loadingMessage>Loading...</loadingMessage>
335
+ <loadingWidth>90</loadingWidth>
336
+ <loadingHeight>20</loadingHeight>
337
+ <loadingOpacity>1.0</loadingOpacity>
338
+ <zoomHintEnable>1</zoomHintEnable>
339
+ <zoomHintText>Zoom</zoomHintText>
340
+ <zoomMsgHover>Roll over image to zoom in, click to view expanded</zoomMsgHover>
341
+ <zoomMsgClick>Click to open expanded view</zoomMsgClick>
342
+ </mouseOverZoomParam>
343
+ <products>
344
+ <displayOnlyForThisProductID></displayOnlyForThisProductID>
345
+ </products>
346
+ </axzoom_options>
347
+ </default>
348
+
349
+ </config>
app/code/local/Ax/Zoom/etc/system.xml ADDED
@@ -0,0 +1,1148 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?xml version="1.0"?>
2
+ <config>
3
+ <sections>
4
+ <axzoom_options translate="label" module="axzoom">
5
+ <label>AJAX-ZOOM</label>
6
+ <tab>catalog</tab>
7
+ <frontend_type>text</frontend_type>
8
+ <sort_order>1000</sort_order>
9
+ <show_in_default>1</show_in_default>
10
+ <show_in_website>1</show_in_website>
11
+ <show_in_store>1</show_in_store>
12
+ <groups>
13
+ <general translate="label">
14
+ <label>About</label>
15
+ <sort_order>0</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
+ <comment>
20
+ <![CDATA[
21
+ <style>
22
+ .importantAZoption{
23
+ color: #eb5e00;
24
+ font-weight: bolder;
25
+ background-position: 0 0 !important;
26
+ padding-left: 24px;
27
+ background-color: transparent !important;
28
+ border-width: 0 !important;
29
+ word-break: break-all;
30
+ }
31
+ </style>
32
+ <ul style="list-style: square">
33
+ <li>AJAX-ZOOM is a multipurpose library for displaying (high resolution) images and 360°/3D spins.
34
+ This Magento module integrates only one particular implementation (example) from AJAX-ZOOM library into Magento.
35
+ In raw form this example can be found here:
36
+ <a target="_blank" href="http://www.ajax-zoom.com/examples/example32_responsive.php">
37
+ http://www.ajax-zoom.com/examples/example32_responsive.php
38
+ </a>
39
+ There you will also find some subtle detailes about the options which you can configure below.
40
+ These options mainly refere to this one implementation / example.
41
+ </li>
42
+ <li>However AJAX-ZOOM has many other options which can be set manually in /js/axzoom/axZm/zoomConfigCustom.inc.php
43
+ after <br> <code>elseif ($_GET['example'] == 'mouseOverExtension360')</code> for 360° views and
44
+ <br><code>elseif ($_GET['example'] == 'mouseOverExtension')</code>
45
+ for regular images views <br> or if you do not want to edit PHP files - most of the options can be also set in these
46
+ formfields as JS plain object in:
47
+ <ol>
48
+ <li>azOptions - for 2D zoom</li>
49
+ <li>azOptions360 - for 360/3D zoom</li>
50
+ </ol>
51
+ </li>
52
+ <li>Depending on the template used you might need to adjust especially these two options:
53
+ <ol>
54
+ <li>zoomWidth - width of the mouseover flyout window</li>
55
+ <li>zoomHeight - height of the mouseover flyout window</li>
56
+ </ol>
57
+ If you will be not able to adjust these options on your own please
58
+ <a target="_blank" "http://www.ajax-zoom.com/index.php?cid=contact">ask for support</a>
59
+ </li>
60
+ <li>Other useful / most common options are marked yellow or with this symbol: <span class="notice-msg importantAZoption"></span>
61
+ </li>
62
+ </ul>
63
+ ]]>
64
+ </comment>
65
+ </general>
66
+ <license translate="label">
67
+ <label>AJAX-ZOOM license(s)</label>
68
+ <frontend_type>text</frontend_type>
69
+ <sort_order>1</sort_order>
70
+ <show_in_default>1</show_in_default>
71
+ <show_in_website>1</show_in_website>
72
+ <show_in_store>1</show_in_store>
73
+ <fields>
74
+ <lic>
75
+ <label>License</label>
76
+ <comment><![CDATA[<a href="http://www.ajax-zoom.com/index.php?cid=contact" target="_blank">Ask for support</a>&nbsp;&nbsp;&nbsp;<a href="http://www.ajax-zoom.com/index.php?cid=download#heading_3" target="_blank">Buy a license</a>]]></comment>
77
+
78
+ <frontend_model>zoom/adminhtml_system_config_fieldset_license</frontend_model>
79
+ <backend_model>adminhtml/system_config_backend_serialized_array</backend_model>
80
+
81
+ <sort_order>1</sort_order>
82
+ <show_in_default>1</show_in_default>
83
+ <show_in_website>1</show_in_website>
84
+ <show_in_store>1</show_in_store>
85
+ </lic>
86
+ </fields>
87
+ </license>
88
+ <mouseOverZoomParam translate="comment">
89
+ <label>mouseOverZoomParam - JS object containing specific options to this mouseover zoom</label>
90
+ <frontend_type>text</frontend_type>
91
+ <sort_order>2</sort_order>
92
+ <show_in_default>1</show_in_default>
93
+ <show_in_website>1</show_in_website>
94
+ <show_in_store>1</show_in_store>
95
+ <fields>
96
+ <position>
97
+ <label><![CDATA[<div class="notice-msg importantAZoption">position</div>]]></label>
98
+ <comment>Position of the flyout zoom window, possible values: 'inside', 'top', 'right', 'bottom', 'left'</comment>
99
+ <frontend_type>select</frontend_type>
100
+ <source_model>axzoom/position</source_model>
101
+ <sort_order>1</sort_order>
102
+ <show_in_default>1</show_in_default>
103
+ <show_in_website>1</show_in_website>
104
+ <show_in_store>1</show_in_store>
105
+ </position>
106
+ <posAutoInside>
107
+ <label>posAutoInside</label>
108
+ <comment>applies when width (left, right) or height (top, bottom) of zoom window are less than this px value (zoomWidth || zoomHeight are set to auto); if zoomWidth || zoomHeight are fixed, applies when zoom window is out of page border</comment>
109
+ <frontend_type>text</frontend_type>
110
+ <sort_order>2</sort_order>
111
+ <show_in_default>1</show_in_default>
112
+ <show_in_website>1</show_in_website>
113
+ <show_in_store>1</show_in_store>
114
+ </posAutoInside>
115
+ <posInsideArea>
116
+ <label>posInsideArea</label>
117
+ <comment>When "posAutoInside" is enabled and inner zoom fires or "position" option is set to 'inside' right away - there is no lens. However you will notice that the reaction to mouse movements occure somewhere in the middle of the image; at the edges mostly nothing happens in simmilar scripts. With this option you can adjust how far from the edge mouse movements should be captured. The range is between 0 and 0.5;</comment>
118
+ <frontend_type>text</frontend_type>
119
+ <sort_order>3</sort_order>
120
+ <show_in_default>1</show_in_default>
121
+ <show_in_website>1</show_in_website>
122
+ <show_in_store>1</show_in_store>
123
+ </posInsideArea>
124
+ <autoFlip>
125
+ <label>autoFlip</label>
126
+ <comment>Flip right to left and bottom to top if less than int px value or false to disable</comment>
127
+ <frontend_type>text</frontend_type>
128
+ <sort_order>4</sort_order>
129
+ <show_in_default>1</show_in_default>
130
+ <show_in_website>1</show_in_website>
131
+ <show_in_store>1</show_in_store>
132
+ </autoFlip>
133
+ <biggestSpace>
134
+ <label>biggestSpace</label>
135
+ <comment>Overrides position option and instantly chooses the direction, disables autoFlip; playes nicely when zoomWidth and zoomHeight are set to 'auto'</comment>
136
+ <frontend_type>select</frontend_type>
137
+ <source_model>axzoom/yesno</source_model>
138
+ <sort_order>5</sort_order>
139
+ <show_in_default>1</show_in_default>
140
+ <show_in_website>1</show_in_website>
141
+ <show_in_store>1</show_in_store>
142
+ </biggestSpace>
143
+ <zoomFullSpace>
144
+ <label>zoomFullSpace</label>
145
+ <comment>Uses full screen height (does not align to the map / disables adjustY) if position is right or left || uses full screen width (does not align to the map / disables adjustX) if position is top or bottom</comment>
146
+ <frontend_type>select</frontend_type>
147
+ <source_model>axzoom/yesno</source_model>
148
+ <sort_order>6</sort_order>
149
+ <show_in_default>1</show_in_default>
150
+ <show_in_website>1</show_in_website>
151
+ <show_in_store>1</show_in_store>
152
+ </zoomFullSpace>
153
+ <zoomWidth>
154
+ <label>zoomWidth</label>
155
+ <comment>Width of the zoom window e.g. 540 or 'auto' or jQuery selector|correction value, e.g. '#refWidthTest|+20';
156
+ so if you want to have a width of the zoom window same as for example a responsive container to the right
157
+ (so it is fully covered) and max possible height, then define the id of this container to the right,
158
+ e.g. 'myArticleData', set "zoomWidth" to '#myArticleData|+10' and "zoomHeight" to 'auto'.
159
+ New in Ver. b4: if you have a three column design and want to cover both containers to the right,
160
+ then just define both containers in the jQuery selector, e.g. '.pb-center-column,.pb-right-column|+20';
161
+ the margin between the containers is not taken into account but you can adjust the result with the second value after vertical bar.
162
+ </comment>
163
+ <frontend_type>text</frontend_type>
164
+ <sort_order>7</sort_order>
165
+ <show_in_default>1</show_in_default>
166
+ <show_in_website>1</show_in_website>
167
+ <show_in_store>1</show_in_store>
168
+ </zoomWidth>
169
+ <zoomHeight>
170
+ <label>zoomHeight</label>
171
+ <comment>Height of the zoom window e.g. 375, or 'auto' or jQuery selector|correction value,
172
+ e.g. '#refWidthTest|+20'; if your selector matches more than one element, e.g. '.pb-center-column,.pb-right-column|+20',
173
+ then the highest value will be choosen. This is different from the multiple selector in "zoomWidth", where the values are added.
174
+ </comment>
175
+ <frontend_type>text</frontend_type>
176
+ <sort_order>8</sort_order>
177
+ <show_in_default>1</show_in_default>
178
+ <show_in_website>1</show_in_website>
179
+ <show_in_store>1</show_in_store>
180
+ </zoomHeight>
181
+ <autoMargin>
182
+ <label>autoMargin</label>
183
+ <comment>If zoomWidth or zoomHeight are set to 'auto', the margin to the edge of the screen</comment>
184
+ <frontend_type>text</frontend_type>
185
+ <sort_order>9</sort_order>
186
+ <show_in_default>1</show_in_default>
187
+ <show_in_website>1</show_in_website>
188
+ <show_in_store>1</show_in_store>
189
+ </autoMargin>
190
+ <adjustX>
191
+ <label>adjustX</label>
192
+ <comment>Horizontal margin of the zoom window</comment>
193
+ <frontend_type>text</frontend_type>
194
+ <sort_order>10</sort_order>
195
+ <show_in_default>1</show_in_default>
196
+ <show_in_website>1</show_in_website>
197
+ <show_in_store>1</show_in_store>
198
+ </adjustX>
199
+ <adjustY>
200
+ <label>adjustY</label>
201
+ <comment>Vertical margin of the zoom window</comment>
202
+ <frontend_type>text</frontend_type>
203
+ <sort_order>11</sort_order>
204
+ <show_in_default>1</show_in_default>
205
+ <show_in_website>1</show_in_website>
206
+ <show_in_store>1</show_in_store>
207
+ </adjustY>
208
+ <lensOpacity>
209
+ <label><![CDATA[<div class="notice-msg importantAZoption">lensOpacity</div>]]></label>
210
+ <comment>Opacity of the selector lens</comment>
211
+ <frontend_type>text</frontend_type>
212
+ <sort_order>12</sort_order>
213
+ <show_in_default>1</show_in_default>
214
+ <show_in_website>1</show_in_website>
215
+ <show_in_store>1</show_in_store>
216
+ </lensOpacity>
217
+ <lensStyle>
218
+ <label>lensStyle</label>
219
+ <comment>Quickly override css of the lens</comment>
220
+ <frontend_type>text</frontend_type>
221
+ <sort_order>13</sort_order>
222
+ <show_in_default>1</show_in_default>
223
+ <show_in_website>1</show_in_website>
224
+ <show_in_store>1</show_in_store>
225
+ </lensStyle>
226
+ <lensClass>
227
+ <label>lensClass</label>
228
+ <comment>Set css class for the lens</comment>
229
+ <frontend_type>text</frontend_type>
230
+ <sort_order>14</sort_order>
231
+ <show_in_default>1</show_in_default>
232
+ <show_in_website>1</show_in_website>
233
+ <show_in_store>1</show_in_store>
234
+ </lensClass>
235
+ <zoomAreaBorderWidth>
236
+ <label>zoomAreaBorderWidth</label>
237
+ <comment>Border thickness of the zoom window</comment>
238
+ <frontend_type>text</frontend_type>
239
+ <sort_order>15</sort_order>
240
+ <show_in_default>1</show_in_default>
241
+ <show_in_website>1</show_in_website>
242
+ <show_in_store>1</show_in_store>
243
+ </zoomAreaBorderWidth>
244
+ <galleryFade>
245
+ <label>galleryFade</label>
246
+ <comment>Speed of inner fade or false</comment>
247
+ <frontend_type>text</frontend_type>
248
+ <sort_order>16</sort_order>
249
+ <show_in_default>1</show_in_default>
250
+ <show_in_website>1</show_in_website>
251
+ <show_in_store>1</show_in_store>
252
+ </galleryFade>
253
+ <shutterSpeed>
254
+ <label>shutterSpeed</label>
255
+ <comment>Speed of shutter fadein or false; applies only if image proportions are different from container</comment>
256
+ <frontend_type>text</frontend_type>
257
+ <sort_order>17</sort_order>
258
+ <show_in_default>1</show_in_default>
259
+ <show_in_website>1</show_in_website>
260
+ <show_in_store>1</show_in_store>
261
+ </shutterSpeed>
262
+ <showFade>
263
+ <label>showFade</label>
264
+ <comment>Speed of fade in for mouse over</comment>
265
+ <frontend_type>text</frontend_type>
266
+ <sort_order>18</sort_order>
267
+ <show_in_default>1</show_in_default>
268
+ <show_in_website>1</show_in_website>
269
+ <show_in_store>1</show_in_store>
270
+ </showFade>
271
+ <hideFade>
272
+ <label>hideFade</label>
273
+ <comment>Speed of fade out for mouse over</comment>
274
+ <frontend_type>text</frontend_type>
275
+ <sort_order>19</sort_order>
276
+ <show_in_default>1</show_in_default>
277
+ <show_in_website>1</show_in_website>
278
+ <show_in_store>1</show_in_store>
279
+ </hideFade>
280
+ <flyOutSpeed>
281
+ <label>flyOutSpeed</label>
282
+ <comment>Speed for flyout or false to disable</comment>
283
+ <frontend_type>text</frontend_type>
284
+ <sort_order>20</sort_order>
285
+ <show_in_default>1</show_in_default>
286
+ <show_in_website>1</show_in_website>
287
+ <show_in_store>1</show_in_store>
288
+ </flyOutSpeed>
289
+ <flyOutTransition>
290
+ <label>flyOutTransition</label>
291
+ <comment>Transition of the flyout</comment>
292
+ <frontend_type>text</frontend_type>
293
+ <sort_order>21</sort_order>
294
+ <show_in_default>1</show_in_default>
295
+ <show_in_website>1</show_in_website>
296
+ <show_in_store>1</show_in_store>
297
+ </flyOutTransition>
298
+ <flyOutOpacity>
299
+ <label>flyOutOpacity</label>
300
+ <comment>Initial opacity for flyout</comment>
301
+ <frontend_type>text</frontend_type>
302
+ <sort_order>22</sort_order>
303
+ <show_in_default>1</show_in_default>
304
+ <show_in_website>1</show_in_website>
305
+ <show_in_store>1</show_in_store>
306
+ </flyOutOpacity>
307
+ <flyBackSpeed>
308
+ <label>flyBackSpeed</label>
309
+ <comment>Speed for fly back or false to disable</comment>
310
+ <frontend_type>text</frontend_type>
311
+ <sort_order>23</sort_order>
312
+ <show_in_default>1</show_in_default>
313
+ <show_in_website>1</show_in_website>
314
+ <show_in_store>1</show_in_store>
315
+ </flyBackSpeed>
316
+ <flyBackTransition>
317
+ <label>flyBackTransition</label>
318
+ <comment>Transition type of the fly back</comment>
319
+ <frontend_type>text</frontend_type>
320
+ <sort_order>24</sort_order>
321
+ <show_in_default>1</show_in_default>
322
+ <show_in_website>1</show_in_website>
323
+ <show_in_store>1</show_in_store>
324
+ </flyBackTransition>
325
+ <flyBackOpacity>
326
+ <label>flyBackOpacity</label>
327
+ <comment>Final opacity of fly back</comment>
328
+ <frontend_type>text</frontend_type>
329
+ <sort_order>25</sort_order>
330
+ <show_in_default>1</show_in_default>
331
+ <show_in_website>1</show_in_website>
332
+ <show_in_store>1</show_in_store>
333
+ </flyBackOpacity>
334
+ <autoScroll>
335
+ <label>autoScroll</label>
336
+ <comment>Scroll page when clicked on the thumb and the mouse over preview image is not fully visible</comment>
337
+ <frontend_type>select</frontend_type>
338
+ <source_model>axzoom/yesno</source_model>
339
+ <sort_order>26</sort_order>
340
+ <show_in_default>1</show_in_default>
341
+ <show_in_website>1</show_in_website>
342
+ <show_in_store>1</show_in_store>
343
+ </autoScroll>
344
+ <smoothMove>
345
+ <label><![CDATA[<div class="notice-msg importantAZoption">smoothMove</div>]]></label>
346
+ <comment>Integer bigger than 1 indicates smoother movements; set 0 to disable</comment>
347
+ <frontend_type>text</frontend_type>
348
+ <sort_order>27</sort_order>
349
+ <show_in_default>1</show_in_default>
350
+ <show_in_website>1</show_in_website>
351
+ <show_in_store>1</show_in_store>
352
+ </smoothMove>
353
+ <tint>
354
+ <label>tint</label>
355
+ <comment>Color value around the lens or false</comment>
356
+ <frontend_type>text</frontend_type>
357
+ <sort_order>28</sort_order>
358
+ <show_in_default>1</show_in_default>
359
+ <show_in_website>1</show_in_website>
360
+ <show_in_store>1</show_in_store>
361
+ </tint>
362
+ <tintOpacity>
363
+ <label>tintOpacity</label>
364
+ <comment>Opacity of the area around the lens when "tint" option is set to some color value</comment>
365
+ <frontend_type>text</frontend_type>
366
+ <sort_order>29</sort_order>
367
+ <show_in_default>1</show_in_default>
368
+ <show_in_website>1</show_in_website>
369
+ <show_in_store>1</show_in_store>
370
+ </tintOpacity>
371
+ <tintFilter>
372
+ <label>tintFilter</label>
373
+ <comment>Apply filter to the image, e.g. "blur", "grayscale", "sepia", "invert", "saturate"; see also .axZm_mouseOverEffect>img CSS</comment>
374
+ <frontend_type>text</frontend_type>
375
+ <sort_order>30</sort_order>
376
+ <show_in_default>1</show_in_default>
377
+ <show_in_website>1</show_in_website>
378
+ <show_in_store>1</show_in_store>
379
+ </tintFilter>
380
+ <tintLensBack>
381
+ <label>tintLensBack</label>
382
+ <comment>Show background image in the lens</comment>
383
+ <frontend_type>select</frontend_type>
384
+ <source_model>axzoom/yesno</source_model>
385
+ <sort_order>31</sort_order>
386
+ <show_in_default>1</show_in_default>
387
+ <show_in_website>1</show_in_website>
388
+ <show_in_store>1</show_in_store>
389
+ </tintLensBack>
390
+ <showTitle>
391
+ <label>showTitle</label>
392
+ <comment>Enable / disable title on zoom window</comment>
393
+ <frontend_type>select</frontend_type>
394
+ <source_model>axzoom/yesno</source_model>
395
+ <sort_order>32</sort_order>
396
+ <show_in_default>1</show_in_default>
397
+ <show_in_website>1</show_in_website>
398
+ <show_in_store>1</show_in_store>
399
+ </showTitle>
400
+ <titleOpacity>
401
+ <label>titleOpacity</label>
402
+ <comment>Opacity of the title container</comment>
403
+ <frontend_type>text</frontend_type>
404
+ <sort_order>33</sort_order>
405
+ <show_in_default>1</show_in_default>
406
+ <show_in_website>1</show_in_website>
407
+ <show_in_store>1</show_in_store>
408
+ </titleOpacity>
409
+ <titlePosition>
410
+ <label>titlePosition</label>
411
+ <comment>Position of the title, top or bottom</comment>
412
+ <frontend_type>text</frontend_type>
413
+ <sort_order>34</sort_order>
414
+ <show_in_default>1</show_in_default>
415
+ <show_in_website>1</show_in_website>
416
+ <show_in_store>1</show_in_store>
417
+ </titlePosition>
418
+ <cursorPositionX>
419
+ <label>cursorPositionX</label>
420
+ <comment>Cursor over lens horizontal offset, 0.5 is middle</comment>
421
+ <frontend_type>text</frontend_type>
422
+ <sort_order>35</sort_order>
423
+ <show_in_default>1</show_in_default>
424
+ <show_in_website>1</show_in_website>
425
+ <show_in_store>1</show_in_store>
426
+ </cursorPositionX>
427
+ <cursorPositionY>
428
+ <label>cursorPositionY</label>
429
+ <comment>Cursor over lens vertical offset, 0.5 is middle</comment>
430
+ <frontend_type>text</frontend_type>
431
+ <sort_order>36</sort_order>
432
+ <show_in_default>1</show_in_default>
433
+ <show_in_website>1</show_in_website>
434
+ <show_in_store>1</show_in_store>
435
+ </cursorPositionY>
436
+ <touchClickAbort>
437
+ <label>touchClickAbort</label>
438
+ <comment>Time in ms after which click is aborted without touch movement and mousehover is initialized</comment>
439
+ <frontend_type>text</frontend_type>
440
+ <sort_order>37</sort_order>
441
+ <show_in_default>1</show_in_default>
442
+ <show_in_website>1</show_in_website>
443
+ <show_in_store>1</show_in_store>
444
+ </touchClickAbort>
445
+ <loading>
446
+ <label>loading</label>
447
+ <comment>Display loading information, CSS .mouseOverLoading</comment>
448
+ <frontend_type>select</frontend_type>
449
+ <source_model>axzoom/yesno</source_model>
450
+ <sort_order>38</sort_order>
451
+ <show_in_default>1</show_in_default>
452
+ <show_in_website>1</show_in_website>
453
+ <show_in_store>1</show_in_store>
454
+ </loading>
455
+ <loadingMessage>
456
+ <label>loadingMessage</label>
457
+ <comment>Loading message, not needed, can be just the spinner - see below</comment>
458
+ <frontend_type>text</frontend_type>
459
+ <sort_order>39</sort_order>
460
+ <show_in_default>1</show_in_default>
461
+ <show_in_website>1</show_in_website>
462
+ <show_in_store>1</show_in_store>
463
+ </loadingMessage>
464
+ <loadingWidth>
465
+ <label>loadingWidth</label>
466
+ <comment>Width of loading container</comment>
467
+ <frontend_type>text</frontend_type>
468
+ <sort_order>40</sort_order>
469
+ <show_in_default>1</show_in_default>
470
+ <show_in_website>1</show_in_website>
471
+ <show_in_store>1</show_in_store>
472
+ </loadingWidth>
473
+ <loadingHeight>
474
+ <label>loadingHeight</label>
475
+ <comment>Height of loading container</comment>
476
+ <frontend_type>text</frontend_type>
477
+ <sort_order>41</sort_order>
478
+ <show_in_default>1</show_in_default>
479
+ <show_in_website>1</show_in_website>
480
+ <show_in_store>1</show_in_store>
481
+ </loadingHeight>
482
+ <loadingOpacity>
483
+ <label>loadingOpacity</label>
484
+ <comment>Opacity of the loading container (the transparent background is set via png image on default, see css class)</comment>
485
+ <frontend_type>text</frontend_type>
486
+ <sort_order>42</sort_order>
487
+ <show_in_default>1</show_in_default>
488
+ <show_in_website>1</show_in_website>
489
+ <show_in_store>1</show_in_store>
490
+ </loadingOpacity>
491
+ <zoomHintEnable>
492
+ <label>zoomHintEnable</label>
493
+ <comment>Enable zoom icon which disappears on mouse hover; css class: .axZm_mouseOverZoomHint; If you want to change the position or the icon simply change the css class;</comment>
494
+ <frontend_type>text</frontend_type>
495
+ <sort_order>43</sort_order>
496
+ <show_in_default>1</show_in_default>
497
+ <show_in_website>1</show_in_website>
498
+ <show_in_store>1</show_in_store>
499
+ </zoomHintEnable>
500
+ <zoomHintText>
501
+ <label>zoomHintText</label>
502
+ <comment>Text which will be appended next to the icon enabled by "zoomHintEnable"</comment>
503
+ <frontend_type>text</frontend_type>
504
+ <sort_order>44</sort_order>
505
+ <show_in_default>1</show_in_default>
506
+ <show_in_website>1</show_in_website>
507
+ <show_in_store>1</show_in_store>
508
+ </zoomHintText>
509
+ <zoomMsgHover>
510
+ <label>zoomMsgHover</label>
511
+ <comment>Message which can appear under the mouse over zoom, css class: .axZm_mouseOverZoomMsg</comment>
512
+ <frontend_type>text</frontend_type>
513
+ <sort_order>45</sort_order>
514
+ <show_in_default>1</show_in_default>
515
+ <show_in_website>1</show_in_website>
516
+ <show_in_store>1</show_in_store>
517
+ </zoomMsgHover>
518
+ <zoomMsgClick>
519
+ <label>zoomMsgClick</label>
520
+ <comment>Message which can appear under the mouse over zoom when the mouse enters it.</comment>
521
+ <frontend_type>text</frontend_type>
522
+ <sort_order>46</sort_order>
523
+ <show_in_default>1</show_in_default>
524
+ <show_in_website>1</show_in_website>
525
+ <show_in_store>1</show_in_store>
526
+ </zoomMsgClick>
527
+ </fields>
528
+ </mouseOverZoomParam>
529
+ <main translate="label">
530
+ <label>General Settings</label>
531
+ <frontend_type>text</frontend_type>
532
+ <sort_order>3</sort_order>
533
+ <show_in_default>1</show_in_default>
534
+ <show_in_website>1</show_in_website>
535
+ <show_in_store>1</show_in_store>
536
+ <fields>
537
+ <disableAllMsg>
538
+ <label>disableAllMsg</label>
539
+ <comment>Instantly hide gallery if there is only one image or one 360/3D</comment>
540
+ <frontend_type>select</frontend_type>
541
+ <source_model>axzoom/yesno</source_model>
542
+ <sort_order>0</sort_order>
543
+ <show_in_default>1</show_in_default>
544
+ <show_in_website>1</show_in_website>
545
+ <show_in_store>1</show_in_store>
546
+ </disableAllMsg>
547
+ <divid>
548
+ <label>divID</label>
549
+ <comment>DIV (container) ID for mouseover zoom</comment>
550
+ <frontend_type>text</frontend_type>
551
+ <sort_order>1</sort_order>
552
+ <show_in_default>1</show_in_default>
553
+ <show_in_website>1</show_in_website>
554
+ <show_in_store>1</show_in_store>
555
+ </divid>
556
+ <galleryDivID>
557
+ <label>galleryDivID</label>
558
+ <comment>DIV (container) id of the gallery, set to false to disable gallery</comment>
559
+ <frontend_type>text</frontend_type>
560
+ <sort_order>2</sort_order>
561
+ <show_in_default>1</show_in_default>
562
+ <show_in_website>1</show_in_website>
563
+ <show_in_store>1</show_in_store>
564
+ </galleryDivID>
565
+ <hideGalleryOneImage>
566
+ <label>hideGalleryOneImage</label>
567
+ <comment>Instantly hide gallery if there is only one image or one 360/3D</comment>
568
+ <frontend_type>select</frontend_type>
569
+ <source_model>axzoom/yesno</source_model>
570
+ <sort_order>3</sort_order>
571
+ <show_in_default>1</show_in_default>
572
+ <show_in_website>1</show_in_website>
573
+ <show_in_store>1</show_in_store>
574
+ </hideGalleryOneImage>
575
+ <galleryHover>
576
+ <label>galleryHover</label>
577
+ <comment>Use mouseenter (mouseover) for switching between images.
578
+ You can specify an integer which will represent the time in ms to wait for switching after the mouse enters the thumb;
579
+ true defaults to 200
580
+ </comment>
581
+ <frontend_type>text</frontend_type>
582
+ <sort_order>4</sort_order>
583
+ <show_in_default>1</show_in_default>
584
+ <show_in_website>1</show_in_website>
585
+ <show_in_store>1</show_in_store>
586
+ </galleryHover>
587
+ <galleryAxZmThumbSlider>
588
+ <label><![CDATA[<div class="notice-msg importantAZoption">galleryAxZmThumbSlider</div>]]></label>
589
+ <comment>Use $.axZmThumbSlider on gallery thumbnails or not</comment>
590
+ <frontend_type>select</frontend_type>
591
+ <source_model>axzoom/yesno</source_model>
592
+ <sort_order>5</sort_order>
593
+ <show_in_default>1</show_in_default>
594
+ <show_in_website>1</show_in_website>
595
+ <show_in_store>1</show_in_store>
596
+ </galleryAxZmThumbSlider>
597
+ <galleryAxZmThumbSliderParam>
598
+ <label><![CDATA[<div class="notice-msg importantAZoption">galleryAxZmThumbSliderParam</div>]]></label>
599
+ <comment>
600
+ <![CDATA[<div class="validation-advice">Attention: you are editing JavaScript object! Errors will lead to AJAX-ZOOM not working properly.</div>
601
+ <p class="preference_description note">$.axZmThumbSlider parametrs if "galleryAxZmThumbSlider" is enabled; for full list of options see under:
602
+ <a href="http://www.ajax-zoom.com/axZm/extensions/axZmThumbSlider/" target="_blank">http://www.ajax-zoom.com/axZm/extensions/axZmThumbSlider/</a></p>
603
+ ]]>
604
+ </comment>
605
+ <frontend_type>textarea</frontend_type>
606
+ <sort_order>6</sort_order>
607
+ <show_in_default>1</show_in_default>
608
+ <show_in_website>1</show_in_website>
609
+ <show_in_store>1</show_in_store>
610
+ </galleryAxZmThumbSliderParam>
611
+ <thumbW>
612
+ <label><![CDATA[<div class="notice-msg importantAZoption">thumbW</div>]]></label>
613
+ <comment>Gallery thumb width</comment>
614
+ <frontend_type>text</frontend_type>
615
+ <sort_order>7</sort_order>
616
+ <show_in_default>1</show_in_default>
617
+ <show_in_website>1</show_in_website>
618
+ <show_in_store>1</show_in_store>
619
+ </thumbW>
620
+ <thumbH>
621
+ <label><![CDATA[<div class="notice-msg importantAZoption">thumbH</div>]]></label>
622
+ <comment>Gallery thumb height</comment>
623
+ <frontend_type>text</frontend_type>
624
+ <sort_order>8</sort_order>
625
+ <show_in_default>1</show_in_default>
626
+ <show_in_website>1</show_in_website>
627
+ <show_in_store>1</show_in_store>
628
+ </thumbH>
629
+ <thumbRetina>
630
+ <label>thumbRetina</label>
631
+ <comment>Double resolution of the thumb image</comment>
632
+ <frontend_type>select</frontend_type>
633
+ <source_model>axzoom/yesno</source_model>
634
+ <sort_order>9</sort_order>
635
+ <show_in_default>1</show_in_default>
636
+ <show_in_website>1</show_in_website>
637
+ <show_in_store>1</show_in_store>
638
+ </thumbRetina>
639
+ <firstImageToLoad>
640
+ <label>firstImageToLoad</label>
641
+ <comment>Image from "images" option which should be loaded at first; see also "images360firstToLoad" option below</comment>
642
+ <frontend_type>text</frontend_type>
643
+ <sort_order>10</sort_order>
644
+ <show_in_default>1</show_in_default>
645
+ <show_in_website>1</show_in_website>
646
+ <show_in_store>1</show_in_store>
647
+ </firstImageToLoad>
648
+ <images360firstToLoad>
649
+ <label>images360firstToLoad</label>
650
+ <comment>In case present load 360 from "images360" first and not an image from "images"</comment>
651
+ <frontend_type>select</frontend_type>
652
+ <source_model>axzoom/yesno</source_model>
653
+ <sort_order>11</sort_order>
654
+ <show_in_default>1</show_in_default>
655
+ <show_in_website>1</show_in_website>
656
+ <show_in_store>1</show_in_store>
657
+ </images360firstToLoad>
658
+ <images360Opt>
659
+ <label>images360Opt</label>
660
+ <comment>Some (not all) options from '/axZm/zoomConfig.inc.php' and '/axZm/zoomConfigCustom.inc.php' can be set during runtime or in 'onBeforeStart' AJAX-ZOOM callback. "images360Opt" is a list of what possibly could be set in "images360" objects, e.g. ['spinReverseZ', 'spinWhilePreload'] and so on. Default is: ['spinReverse', 'spinReverseZ', 'spinBounce', 'spinDemoRounds', 'spinDemoTime', 'spinWhilePreload']</comment>
661
+ <frontend_type>text</frontend_type>
662
+ <sort_order>12</sort_order>
663
+ <show_in_default>1</show_in_default>
664
+ <show_in_website>1</show_in_website>
665
+ <show_in_store>1</show_in_store>
666
+ </images360Opt>
667
+ <images360Thumb>
668
+ <label>images360Thumb</label>
669
+ <comment>Show first image of the spin as thumb</comment>
670
+ <frontend_type>select</frontend_type>
671
+ <source_model>axzoom/yesno</source_model>
672
+ <sort_order>13</sort_order>
673
+ <show_in_default>1</show_in_default>
674
+ <show_in_website>1</show_in_website>
675
+ <show_in_store>1</show_in_store>
676
+ </images360Thumb>
677
+ <images360Preview>
678
+ <label>images360Preview</label>
679
+ <comment>Normally plain images are opened in some kind of lightbox or fullscreen; By setting this option to true the 360's will load into "divID" at first and can be expanded to fullscreen.</comment>
680
+ <frontend_type>select</frontend_type>
681
+ <source_model>axzoom/yesno</source_model>
682
+ <sort_order>14</sort_order>
683
+ <show_in_default>1</show_in_default>
684
+ <show_in_website>1</show_in_website>
685
+ <show_in_store>1</show_in_store>
686
+ </images360Preview>
687
+ <images360PreviewResponsive>
688
+ <label>images360PreviewResponsive</label>
689
+ <comment>This option is set to true for convinience reasons; In case your "divID" has fixed width and height, set $zoom['config']['picDim'] option in '/axZm/zoomConfigCustom.inc.php' after elseif ($_GET['example'] == 'mouseOverExtension360')</comment>
690
+ <frontend_type>select</frontend_type>
691
+ <source_model>axzoom/yesno</source_model>
692
+ <sort_order>15</sort_order>
693
+ <show_in_default>1</show_in_default>
694
+ <show_in_website>1</show_in_website>
695
+ <show_in_store>1</show_in_store>
696
+ </images360PreviewResponsive>
697
+ <images360examplePreview>
698
+ <label>images360examplePreview</label>
699
+ <comment>In case "images360Preview" is set to true, the value of this parameter will be sent to AJAX-ZOOM as "options set" (example=mouseOverExtension360)</comment>
700
+ <frontend_type>text</frontend_type>
701
+ <sort_order>16</sort_order>
702
+ <show_in_default>1</show_in_default>
703
+ <show_in_website>1</show_in_website>
704
+ <show_in_store>1</show_in_store>
705
+ </images360examplePreview>
706
+ <zoomMsg360>
707
+ <label>zoomMsg360</label>
708
+ <comment>Message displayed under mouse over zoom when 360 is loaded, e.g. "Drag to spin 360, scroll to zoom"</comment>
709
+ <frontend_type>text</frontend_type>
710
+ <sort_order>17</sort_order>
711
+ <show_in_default>1</show_in_default>
712
+ <show_in_website>1</show_in_website>
713
+ <show_in_store>1</show_in_store>
714
+ </zoomMsg360>
715
+ <preloadMouseOverImages>
716
+ <label>preloadMouseOverImages</label>
717
+ <comment>Preload all preview and mouseover images, possible values: false, true, 'oneByOne'</comment>
718
+ <frontend_type>select</frontend_type>
719
+ <source_model>axzoom/yesno</source_model>
720
+ <sort_order>18</sort_order>
721
+ <show_in_default>1</show_in_default>
722
+ <show_in_website>1</show_in_website>
723
+ <show_in_store>1</show_in_store>
724
+ </preloadMouseOverImages>
725
+ <noImageAvailableClass>
726
+ <label>noImageAvailableClass</label>
727
+ <comment>In case there are no images in "images", nor there are any in "images360", a div with some image as background can be appended to the container and receive this options value as css class</comment>
728
+ <frontend_type>text</frontend_type>
729
+ <sort_order>19</sort_order>
730
+ <show_in_default>1</show_in_default>
731
+ <show_in_website>1</show_in_website>
732
+ <show_in_store>1</show_in_store>
733
+ </noImageAvailableClass>
734
+
735
+ <width>
736
+ <label>width</label>
737
+ <comment>Width of the preview image or 'auto' (depending on parent container size - "divID", see above); this is also the value which will be passed to your AJAX-ZOOM imaging server to generate this image on-the-fly.</comment>
738
+ <frontend_type>text</frontend_type>
739
+ <sort_order>20</sort_order>
740
+ <show_in_default>1</show_in_default>
741
+ <show_in_website>1</show_in_website>
742
+ <show_in_store>1</show_in_store>
743
+ </width>
744
+ <height>
745
+ <label>height</label>
746
+ <comment>Height of the preview image or 'auto' (depending on parent container size - "divID", see above); this is also the value which will be passed to your AJAX-ZOOM imaging server to generate this image on-the-fly.</comment>
747
+ <frontend_type>text</frontend_type>
748
+ <sort_order>21</sort_order>
749
+ <show_in_default>1</show_in_default>
750
+ <show_in_website>1</show_in_website>
751
+ <show_in_store>1</show_in_store>
752
+ </height>
753
+ <responsive>
754
+ <label>responsive</label>
755
+ <comment>Set this to true for responsive layouts</comment>
756
+ <frontend_type>select</frontend_type>
757
+ <source_model>axzoom/yesno</source_model>
758
+ <sort_order>22</sort_order>
759
+ <show_in_default>1</show_in_default>
760
+ <show_in_website>1</show_in_website>
761
+ <show_in_store>1</show_in_store>
762
+ </responsive>
763
+
764
+ <oneSrcImg>
765
+ <label>oneSrcImg</label>
766
+ <comment>Use single image as "preview image" - the image which is hovered and the big "flyout image".</comment>
767
+ <frontend_type>select</frontend_type>
768
+ <source_model>axzoom/yesno</source_model>
769
+ <sort_order>23</sort_order>
770
+ <show_in_default>1</show_in_default>
771
+ <show_in_website>1</show_in_website>
772
+ <show_in_store>1</show_in_store>
773
+ </oneSrcImg>
774
+ <heightRatio>
775
+ <label><![CDATA[<div class="notice-msg importantAZoption">heightRatio</div>]]></label>
776
+ <comment>If "responsive" option is enabled, "heightRatio" with instantly adjust the height of mouseover container depending on width calculated by the browser, e.g. 1.0 will always (only limited by "maxSizePrc" option) make height same as width; a value of 1.5 will make the preview like a portrait. You can also set "heightRatio" to 'auto'. In this case the height will be adjusted to cover available space instantly! Please note that when your images are not always same proportion, then the container will also change the size when the user switches to a different image.</comment>
777
+ <frontend_type>text</frontend_type>
778
+ <sort_order>24</sort_order>
779
+ <show_in_default>1</show_in_default>
780
+ <show_in_website>1</show_in_website>
781
+ <show_in_store>1</show_in_store>
782
+ </heightRatio>
783
+
784
+ <heightMaxWidthRatio>
785
+ <label>heightMaxWidthRatio</label>
786
+ <comment>Similar as you would set max-width: someValue @media only screen condition you can define "heightRatio" depending on the width of the browser, e.g. ["960|0.8", "700|0.7"]</comment>
787
+ <frontend_type>text</frontend_type>
788
+ <sort_order>25</sort_order>
789
+ <show_in_default>1</show_in_default>
790
+ <show_in_website>1</show_in_website>
791
+ <show_in_store>1</show_in_store>
792
+ </heightMaxWidthRatio>
793
+ <widthRatio>
794
+ <label>widthRatio</label>
795
+ <comment>Oposit of "heightRatio"</comment>
796
+ <frontend_type>text</frontend_type>
797
+ <sort_order>26</sort_order>
798
+ <show_in_default>1</show_in_default>
799
+ <show_in_website>1</show_in_website>
800
+ <show_in_store>1</show_in_store>
801
+ </widthRatio>
802
+ <widthMaxHeightRatio>
803
+ <label>widthMaxHeightRatio</label>
804
+ <comment>Oposit of "heightMaxWidthRatio"</comment>
805
+ <frontend_type>text</frontend_type>
806
+ <sort_order>27</sort_order>
807
+ <show_in_default>1</show_in_default>
808
+ <show_in_website>1</show_in_website>
809
+ <show_in_store>1</show_in_store>
810
+ </widthMaxHeightRatio>
811
+
812
+ <maxSizePrc>
813
+ <label><![CDATA[<div class="notice-msg importantAZoption">maxSizePrc</div>]]></label>
814
+ <comment>Limit the height if "responsive" and "heightRatio" options are set. Setting "heightRatio" option may result in that the height of the mouseover zoom is bigger than window height and the image is not fully visible. To prevent this you can limit the calculated height with this "maxSizePrc" option. The value of 1.0 would limit the height to 100% of window height; a value of 0.8 to 80% of window height; you can also define two values, e.g. '1.0|-120' which would be window height minus 120px.</comment>
815
+ <frontend_type>text</frontend_type>
816
+ <sort_order>28</sort_order>
817
+ <show_in_default>1</show_in_default>
818
+ <show_in_website>1</show_in_website>
819
+ <show_in_store>1</show_in_store>
820
+ </maxSizePrc>
821
+ <mouseOverZoomWidth>
822
+ <label><![CDATA[<div class="notice-msg importantAZoption">mouseOverZoomWidth</div>]]></label>
823
+ <comment>Max width of the image that will be shown in the zoom window; this is the value which will be passed to your AJAX-ZOOM imaging server to generate this image on-the-fly. Please note that the size is limited by $zoom['config']['allowDynamicThumbsMaxSize'] which is can be set in '/axZm/zoomConfig.inc.php'. You can also specify a link to the image, see "images" option above. To set the width of the fly out window see "zoomWidth" under "mouseOverZoomParam".</comment>
824
+ <frontend_type>text</frontend_type>
825
+ <sort_order>29</sort_order>
826
+ <show_in_default>1</show_in_default>
827
+ <show_in_website>1</show_in_website>
828
+ <show_in_store>1</show_in_store>
829
+ </mouseOverZoomWidth>
830
+ <mouseOverZoomHeight>
831
+ <label><![CDATA[<div class="notice-msg importantAZoption">mouseOverZoomHeight</div>]]></label>
832
+ <comment>Max height of the image that will be shown in the zoom window; this is the value which will be passed to your AJAX-ZOOM imaging server to generate this image on-the-fly. Please note that the size is limited by $zoom['config']['allowDynamicThumbsMaxSize'] which is can be set in '/axZm/zoomConfig.inc.php'. You can also specify a link to the image, see "images" option above. To set the height of the fly out window see "zoomHeight" under "mouseOverZoomParam".</comment>
833
+ <frontend_type>text</frontend_type>
834
+ <sort_order>30</sort_order>
835
+ <show_in_default>1</show_in_default>
836
+ <show_in_website>1</show_in_website>
837
+ <show_in_store>1</show_in_store>
838
+ </mouseOverZoomHeight>
839
+ <ajaxZoomOpenMode>
840
+ <label><![CDATA[<div class="notice-msg importantAZoption">ajaxZoomOpenMode</div>]]></label>
841
+ <comment>Determines how AJAX-ZOOM is opened when the user clicks on preview images / lens, possible values: 'fullscreen' (see also "fullScreenApi" option below), 'fancyboxFullscreen', 'fancybox', 'colorbox'; By editing $.mouseOverZoomInit you can extend the plugin to be used with different types of modal boxes to load AJAX-ZOOM into.</comment>
842
+ <frontend_type>text</frontend_type>
843
+ <sort_order>31</sort_order>
844
+ <show_in_default>1</show_in_default>
845
+ <show_in_website>1</show_in_website>
846
+ <show_in_store>1</show_in_store>
847
+ </ajaxZoomOpenMode>
848
+ <fancyBoxParam>
849
+ <label>fancyBoxParam</label>
850
+ <comment>If fancybox is used in "ajaxZoomOpenMode" option, Fancybox options</comment>
851
+ <frontend_type>text</frontend_type>
852
+ <sort_order>32</sort_order>
853
+ <show_in_default>1</show_in_default>
854
+ <show_in_website>1</show_in_website>
855
+ <show_in_store>1</show_in_store>
856
+ </fancyBoxParam>
857
+ <colorBoxParam>
858
+ <label>colorBoxParam</label>
859
+ <comment>If colorbox is used in "ajaxZoomOpenMode" option, Colorbox options</comment>
860
+ <frontend_type>text</frontend_type>
861
+ <sort_order>33</sort_order>
862
+ <show_in_default>1</show_in_default>
863
+ <show_in_website>1</show_in_website>
864
+ <show_in_store>1</show_in_store>
865
+ </colorBoxParam>
866
+ <example>
867
+ <label>example</label>
868
+ <comment>Configuration set which is passed to ajax-zoom when ajaxZoomOpenMode is 'fullscreen'</comment>
869
+ <frontend_type>text</frontend_type>
870
+ <sort_order>34</sort_order>
871
+ <show_in_default>1</show_in_default>
872
+ <show_in_website>1</show_in_website>
873
+ <show_in_store>1</show_in_store>
874
+ </example>
875
+ <exampleFancyboxFullscreen>
876
+ <label>exampleFancyboxFullscreen</label>
877
+ <comment>Configuration set which is passed to ajax-zoom when ajaxZoomOpenMode is 'fancyboxFullscreen'</comment>
878
+ <frontend_type>text</frontend_type>
879
+ <sort_order>35</sort_order>
880
+ <show_in_default>1</show_in_default>
881
+ <show_in_website>1</show_in_website>
882
+ <show_in_store>1</show_in_store>
883
+ </exampleFancyboxFullscreen>
884
+ <exampleFancybox>
885
+ <label>exampleFancybox</label>
886
+ <comment>Configuration set which is passed to ajax-zoom when ajaxZoomOpenMode is 'fancybox'</comment>
887
+ <frontend_type>text</frontend_type>
888
+ <sort_order>36</sort_order>
889
+ <show_in_default>1</show_in_default>
890
+ <show_in_website>1</show_in_website>
891
+ <show_in_store>1</show_in_store>
892
+ </exampleFancybox>
893
+ <exampleColorbox>
894
+ <label>exampleColorbox</label>
895
+ <comment>Configuration set which is passed to ajax-zoom when ajaxZoomOpenMode is 'colorbox'</comment>
896
+ <frontend_type>text</frontend_type>
897
+ <sort_order>37</sort_order>
898
+ <show_in_default>1</show_in_default>
899
+ <show_in_website>1</show_in_website>
900
+ <show_in_store>1</show_in_store>
901
+ </exampleColorbox>
902
+ <disableScrollAnm>
903
+ <label>disableScrollAnm</label>
904
+ <comment>Disable animation while zooming with AJAX-ZOOM</comment>
905
+ <frontend_type>select</frontend_type>
906
+ <source_model>axzoom/yesno</source_model>
907
+ <sort_order>38</sort_order>
908
+ <show_in_default>1</show_in_default>
909
+ <show_in_website>1</show_in_website>
910
+ <show_in_store>1</show_in_store>
911
+ </disableScrollAnm>
912
+
913
+ <fullScreenApi>
914
+ <label>fullScreenApi</label>
915
+ <comment>Try to open AJAX-ZOOM at browsers fullscreen mode, possible on modern browsers except IE &lt; 10 and mobile</comment>
916
+ <frontend_type>select</frontend_type>
917
+ <source_model>axzoom/yesno</source_model>
918
+ <sort_order>39</sort_order>
919
+ <show_in_default>1</show_in_default>
920
+ <show_in_website>1</show_in_website>
921
+ <show_in_store>1</show_in_store>
922
+ </fullScreenApi>
923
+
924
+ <axZmCallBacks>
925
+ <label>axZmCallBacks</label>
926
+ <comment><![CDATA[<div class="validation-advice">Attention: you are editing JavaScript object! Errors will lead to AJAX-ZOOM not working properly.</div><p class="note">AJAX-ZOOM has several callbacks, http://www.ajax-zoom.com/index.php?cid=docs#onBeforeStart</p>]]></comment>
927
+ <frontend_type>textarea</frontend_type>
928
+ <sort_order>39</sort_order>
929
+ <show_in_default>1</show_in_default>
930
+ <show_in_website>1</show_in_website>
931
+ <show_in_store>1</show_in_store>
932
+ </axZmCallBacks>
933
+ <azOptions>
934
+ <label><![CDATA[<div class="notice-msg importantAZoption">azOptions</div>]]></label>
935
+ <comment><![CDATA[<div class="validation-advice">Attention: you are editing JavaScript object! Errors will lead to AJAX-ZOOM not working properly.</div><p class="note">AJAX-ZOOM options can be set with JS when AJAX-ZOOM is inited. Normally you would be defining them in /axZm/zoomConfig.inc.php or /axZm/zoomConfigCustom.inc.php; this field is for convinience reasons. Example: {fullScreenCornerButton: false} - this would disable the button for fullscreen</p>]]></comment>
936
+ <frontend_type>textarea</frontend_type>
937
+ <sort_order>40</sort_order>
938
+ <show_in_default>1</show_in_default>
939
+ <show_in_website>1</show_in_website>
940
+ <show_in_store>1</show_in_store>
941
+ </azOptions>
942
+ <azOptions360>
943
+ <label><![CDATA[<div class="notice-msg importantAZoption">azOptions360</div>]]></label>
944
+ <comment><![CDATA[<div class="validation-advice">Attention: you are editing JavaScript object! Errors will lead to AJAX-ZOOM not working properly.</div><p class="note">Same as above but specifically for 360/3D</p>]]></comment>
945
+ <frontend_type>textarea</frontend_type>
946
+ <sort_order>41</sort_order>
947
+ <show_in_default>1</show_in_default>
948
+ <show_in_website>1</show_in_website>
949
+ <show_in_store>1</show_in_store>
950
+ </azOptions360>
951
+ <qualityThumb>
952
+ <label>qualityThumb</label>
953
+ <comment>Jpeg quality of the gallery thumbs</comment>
954
+ <frontend_type>text</frontend_type>
955
+ <sort_order>42</sort_order>
956
+ <show_in_default>1</show_in_default>
957
+ <show_in_website>1</show_in_website>
958
+ <show_in_store>1</show_in_store>
959
+ </qualityThumb>
960
+ <quality>
961
+ <label>quality</label>
962
+ <comment>Jpeg quality of the preview image</comment>
963
+ <frontend_type>text</frontend_type>
964
+ <sort_order>42</sort_order>
965
+ <show_in_default>1</show_in_default>
966
+ <show_in_website>1</show_in_website>
967
+ <show_in_store>1</show_in_store>
968
+ </quality>
969
+ <qualityZoom>
970
+ <label>qualityZoom</label>
971
+ <comment>Jpeg quality of the zoom image shown in the flyout window</comment>
972
+ <frontend_type>text</frontend_type>
973
+ <sort_order>43</sort_order>
974
+ <show_in_default>1</show_in_default>
975
+ <show_in_website>1</show_in_website>
976
+ <show_in_store>1</show_in_store>
977
+ </qualityZoom>
978
+ <onLoad>
979
+ <label>onLoad</label>
980
+ <comment>Callback function</comment>
981
+ <frontend_type>text</frontend_type>
982
+ <sort_order>44</sort_order>
983
+ <show_in_default>1</show_in_default>
984
+ <show_in_website>1</show_in_website>
985
+ <show_in_store>1</show_in_store>
986
+ </onLoad>
987
+ <onImageChange>
988
+ <label>onImageChange</label>
989
+ <comment>Callback function</comment>
990
+ <frontend_type>text</frontend_type>
991
+ <sort_order>45</sort_order>
992
+ <show_in_default>1</show_in_default>
993
+ <show_in_website>1</show_in_website>
994
+ <show_in_store>1</show_in_store>
995
+ </onImageChange>
996
+ <onMouseOver>
997
+ <label>onMouseOver</label>
998
+ <comment>Callback function</comment>
999
+ <frontend_type>text</frontend_type>
1000
+ <sort_order>46</sort_order>
1001
+ <show_in_default>1</show_in_default>
1002
+ <show_in_website>1</show_in_website>
1003
+ <show_in_store>1</show_in_store>
1004
+ </onMouseOver>
1005
+ <onMouseOut>
1006
+ <label>onMouseOut</label>
1007
+ <comment>Callback function</comment>
1008
+ <frontend_type>text</frontend_type>
1009
+ <sort_order>47</sort_order>
1010
+ <show_in_default>1</show_in_default>
1011
+ <show_in_website>1</show_in_website>
1012
+ <show_in_store>1</show_in_store>
1013
+ </onMouseOut>
1014
+ <spinner>
1015
+ <label>spinner</label>
1016
+ <comment>Use ajax loading spinner without gif files etc</comment>
1017
+ <frontend_type>text</frontend_type>
1018
+ <sort_order>48</sort_order>
1019
+ <show_in_default>1</show_in_default>
1020
+ <show_in_website>1</show_in_website>
1021
+ <show_in_store>1</show_in_store>
1022
+ </spinner>
1023
+ <spinnerParam>
1024
+ <label>spinnerParam</label>
1025
+ <comment>Spinner options, for more info see: http://fgnass.github.com/spin.js/</comment>
1026
+ <frontend_type>text</frontend_type>
1027
+ <sort_order>49</sort_order>
1028
+ <show_in_default>1</show_in_default>
1029
+ <show_in_website>1</show_in_website>
1030
+ <show_in_store>1</show_in_store>
1031
+ </spinnerParam>
1032
+ </fields>
1033
+ </main>
1034
+ <pinterest translate="label">
1035
+ <label>Settings for pinterest button</label>
1036
+ <frontend_type>text</frontend_type>
1037
+ <sort_order>4</sort_order>
1038
+ <show_in_default>1</show_in_default>
1039
+ <show_in_website>1</show_in_website>
1040
+ <show_in_store>1</show_in_store>
1041
+ <fields>
1042
+ <enabled>
1043
+ <label><![CDATA[<div class="notice-msg importantAZoption">enabled</div>]]></label>
1044
+ <comment>Experimental feature - enable Pinterest button. Pinterest allows to collect visual bookmarks in the form of images collected on the internet.</comment>
1045
+ <frontend_type>select</frontend_type>
1046
+ <source_model>axzoom/yesno</source_model>
1047
+ <sort_order>50</sort_order>
1048
+ <show_in_default>1</show_in_default>
1049
+ <show_in_website>1</show_in_website>
1050
+ <show_in_store>1</show_in_store>
1051
+ </enabled>
1052
+ <build>
1053
+ <label>build</label>
1054
+ <comment>Since images are changed the button needs to be repainted [...] In order to accomplish this the Pinterest API should be exposed to window object. This is done by setting data-pin-build attribute value in the script tag when pinterest JavaScript is included. &lt;script data-pin-build="parsePinBtns" type="text/javascript" src="//assets.pinterest.com/js/pinit.js"&gt;&lt;/script&gt; So if you do not have the data-pin-build, please add it to the script tag and if it is different from default ('parsePinBtns'), then change this "build" value. Otherwise the pinterest button will not work.</comment>
1055
+ <frontend_type>text</frontend_type>
1056
+ <sort_order>51</sort_order>
1057
+ <show_in_default>1</show_in_default>
1058
+ <show_in_website>1</show_in_website>
1059
+ <show_in_store>1</show_in_store>
1060
+ </build>
1061
+ <wrapClass>
1062
+ <label>wrapClass</label>
1063
+ <comment>This is the class of the container where the button will be put into. On default it is at bottom right. To place the button somewhere else you can either change the css of the default class or define a different class.</comment>
1064
+ <frontend_type>text</frontend_type>
1065
+ <sort_order>52</sort_order>
1066
+ <show_in_default>1</show_in_default>
1067
+ <show_in_website>1</show_in_website>
1068
+ <show_in_store>1</show_in_store>
1069
+ </wrapClass>
1070
+ <href>
1071
+ <label>href</label>
1072
+ <comment>href attribute before the button is build.</comment>
1073
+ <frontend_type>text</frontend_type>
1074
+ <sort_order>53</sort_order>
1075
+ <show_in_default>1</show_in_default>
1076
+ <show_in_website>1</show_in_website>
1077
+ <show_in_store>1</show_in_store>
1078
+ </href>
1079
+ <description>
1080
+ <label>description</label>
1081
+ <comment>Page title if null</comment>
1082
+ <frontend_type>text</frontend_type>
1083
+ <sort_order>54</sort_order>
1084
+ <show_in_default>1</show_in_default>
1085
+ <show_in_website>1</show_in_website>
1086
+ <show_in_store>1</show_in_store>
1087
+ </description>
1088
+ <url>
1089
+ <label>url</label>
1090
+ <comment>Will be set instantly if null</comment>
1091
+ <frontend_type>text</frontend_type>
1092
+ <sort_order>55</sort_order>
1093
+ <show_in_default>1</show_in_default>
1094
+ <show_in_website>1</show_in_website>
1095
+ <show_in_store>1</show_in_store>
1096
+ </url>
1097
+ <media>
1098
+ <label>media</label>
1099
+ <comment>Will be set to current selected image if null</comment>
1100
+ <frontend_type>text</frontend_type>
1101
+ <sort_order>56</sort_order>
1102
+ <show_in_default>1</show_in_default>
1103
+ <show_in_website>1</show_in_website>
1104
+ <show_in_store>1</show_in_store>
1105
+ </media>
1106
+ <btnSrc>
1107
+ <label>btnSrc</label>
1108
+ <comment>Source for the button</comment>
1109
+ <frontend_type>text</frontend_type>
1110
+ <sort_order>57</sort_order>
1111
+ <show_in_default>1</show_in_default>
1112
+ <show_in_website>1</show_in_website>
1113
+ <show_in_store>1</show_in_store>
1114
+ </btnSrc>
1115
+ <data>
1116
+ <label>data</label>
1117
+ <comment>Data attributes attached to the button before it is built. See pinterest API...</comment>
1118
+ <frontend_type>text</frontend_type>
1119
+ <sort_order>58</sort_order>
1120
+ <show_in_default>1</show_in_default>
1121
+ <show_in_website>1</show_in_website>
1122
+ <show_in_store>1</show_in_store>
1123
+ </data>
1124
+ </fields>
1125
+ </pinterest>
1126
+ <products translate="label">
1127
+ <label>DISPLAY ONLY IN THESE PRODUCTS</label>
1128
+ <frontend_type>text</frontend_type>
1129
+ <sort_order>5</sort_order>
1130
+ <show_in_default>1</show_in_default>
1131
+ <show_in_website>1</show_in_website>
1132
+ <show_in_store>1</show_in_store>
1133
+ <fields>
1134
+ <displayOnlyForThisProductID>
1135
+ <label>displayOnlyForThisProductID</label>
1136
+ <comment>CSV with product IDs for which AJAX-ZOOM will be only enabled. Leave blank to have it enabled for all products! This option can be usefull e.g. if you want to make A/B tests and enable AJAX-ZOOM only for certain products, e.g. 7,15 would enable AJAX-ZOOM only for products with ID 7 and 15</comment>
1137
+ <frontend_type>textarea</frontend_type>
1138
+ <sort_order>47</sort_order>
1139
+ <show_in_default>1</show_in_default>
1140
+ <show_in_website>1</show_in_website>
1141
+ <show_in_store>1</show_in_store>
1142
+ </displayOnlyForThisProductID>
1143
+ </fields>
1144
+ </products>
1145
+ </groups>
1146
+ </axzoom_options>
1147
+ </sections>
1148
+ </config>
app/code/local/Ax/Zoom/sql/axzoom_setup/install-0.0.1.php ADDED
@@ -0,0 +1,33 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ //die('AJAX ZOOM module setup');
4
+
5
+ $installer = $this;
6
+ $installer->startSetup();
7
+ $installer->run("
8
+ CREATE TABLE IF NOT EXISTS `ajaxzoom360` (`id_360` int(11) NOT NULL AUTO_INCREMENT, `id_product` int(11) NOT NULL, `name` varchar(255) NOT NULL, `num` int(11) NOT NULL DEFAULT '1', `settings` text NOT NULL, `status` tinyint(1) NOT NULL DEFAULT '0', `combinations` text NOT NULL, PRIMARY KEY (`id_360`)) ENGINE=InnoDB DEFAULT CHARSET=utf8 ;
9
+ CREATE TABLE IF NOT EXISTS `ajaxzoom360set` (`id_360set` int(11) NOT NULL AUTO_INCREMENT, `id_360` int(11) NOT NULL, `sort_order` int(11) NOT NULL, PRIMARY KEY (`id_360set`)) ENGINE=InnoDB DEFAULT CHARSET=utf8 AUTO_INCREMENT=1 ;
10
+ CREATE TABLE IF NOT EXISTS `ajaxzoomproducts` (`id_product` int(11) NOT NULL) ENGINE=InnoDB DEFAULT CHARSET=utf8;
11
+ ");
12
+
13
+ $installer->endSetup();
14
+
15
+ $io = new Varien_Io_File();
16
+ foreach (array('360', 'cache', 'zoomgallery', 'zoommap', 'zoomthumb', 'zoomtiles_80', 'tmp') as $folder) {
17
+ $io->checkAndCreateFolder(Mage::getBaseDir() . '/js/axzoom/pic/' . $folder);
18
+ }
19
+
20
+ // download axZm if not exists
21
+ if (!file_exists(Mage::getBaseDir() . '/js/axzoom/axZm') && ini_get('allow_url_fopen') ) {
22
+ $remoteFileContents = file_get_contents('http://www.ajax-zoom.com/download.php?ver=latest');
23
+ $localFilePath = Mage::getBaseDir() . '/js/axzoom/pic/tmp/jquery.ajaxZoom_ver_latest.zip';
24
+
25
+ file_put_contents($localFilePath, $remoteFileContents);
26
+
27
+ $zip = new ZipArchive;
28
+ $res = $zip->open($localFilePath);
29
+ $zip->extractTo(Mage::getBaseDir() . '/js/axzoom/pic/tmp/');
30
+ $zip->close();
31
+
32
+ rename(Mage::getBaseDir() . '/js/axzoom/pic/tmp/axZm', Mage::getBaseDir() . '/js/axzoom/axZm');
33
+ }
app/design/adminhtml/default/default/layout/axzoom.xml ADDED
@@ -0,0 +1,25 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <layout>
2
+ <adminhtml_catalog_product_edit>
3
+ <reference name="head">
4
+ <!--<action method="removeItem"><type>js</type><name>prototype/prototype.js</name></action>-->
5
+ <action method="addJs"><script>axzoom/jquery-1.11.0.min.js</script></action>
6
+ <action method="addJs"><script>axzoom/jquery-migrate-1.2.1.min.js</script></action>
7
+ <action method="addJs"><script>axzoom/axZm/extensions/jquery.axZm.openAjaxZoomInFancyBox.js</script></action>
8
+ <action method="addJs"><script>axzoom/axZm/plugins/demo/jquery.fancybox/jquery.fancybox-1.3.4.pack.js</script></action>
9
+
10
+ <action method="addJs"><script>axzoom/jquery.ui.widget.min.js</script></action>
11
+ <action method="addJs"><script>axzoom/jquery.fileupload.js</script></action>
12
+ <action method="addJs"><script>axzoom/jquery.fileupload-process.js</script></action>
13
+ <action method="addJs"><script>axzoom/jquery.fileupload-validate.js</script></action>
14
+
15
+
16
+
17
+ <action method="addCss">
18
+ <stylesheet>../../../../js/axzoom/axZm/plugins/demo/jquery.fancybox/jquery.fancybox-1.3.4.css</stylesheet>
19
+ </action>
20
+
21
+ <!--<action method="addJs"><script>axzoom/colorpicker.js</script></action>-->
22
+ <!--<action method="addJs"><script>prototype/prototype.js</script></action>-->
23
+ </reference>
24
+ </adminhtml_catalog_product_edit>
25
+ </layout>
app/design/adminhtml/default/default/template/axzoom/tab.phtml ADDED
@@ -0,0 +1,38 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <script type="text/javascript">
2
+ function showSuccessMessage(message)
3
+ {
4
+ //console.log(message);
5
+ }
6
+
7
+ function doAdminAjax360(url, data, success_func, error_func)
8
+ {
9
+ jQuery.ajax(
10
+ {
11
+ url : url,
12
+ data : data,
13
+ type : 'GET',
14
+ success : function(data){
15
+ if (success_func)
16
+ return success_func(data);
17
+
18
+ data = jQuery.parseJSON(data);
19
+ if (data.confirmations.length != 0)
20
+ showSuccessMessage(data.confirmations);
21
+ else
22
+ showErrorMessage(data.error);
23
+ },
24
+ error : function(data){
25
+ if (error_func)
26
+ return error_func(data);
27
+
28
+ alert("[TECHNICAL ERROR]");
29
+ }
30
+ });
31
+ }
32
+ </script>
33
+
34
+ <?php $productId = (int)Mage::app()->getRequest()->getParam('id'); ?>
35
+
36
+ <?php require 'tab360-settings.phtml'; ?>
37
+ <?php require 'tab360-sets.phtml'; ?>
38
+ <?php require 'tab360.phtml'; ?>
app/design/adminhtml/default/default/template/axzoom/tab360-sets.phtml ADDED
@@ -0,0 +1,323 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ $model = Mage::getModel('axzoom/ax360');
3
+ $setsGroups = $model->getCollection()->addFieldToFilter('id_product', $productId)->getData();
4
+
5
+ $model = Mage::getModel('axzoom/ax360set');
6
+ $sets = $model->getSets($productId);
7
+ ?>
8
+ <style type="text/css">
9
+ .hide {
10
+ display: none !important;
11
+ }
12
+ #imageTableSetsRows .active td {
13
+ background-color: #FFFFE0 !important;
14
+ }
15
+ </style>
16
+
17
+
18
+
19
+ <div id="product-images360sets" class="entry-edit">
20
+ <div class="entry-edit-head">
21
+ <h4 class="icon-head head-edit-form fieldset-legend"><?php echo $this->__('360/3D Views') ?></h4>
22
+ </div>
23
+ <div class="fieldset fieldset-wide" id="group_fields9">
24
+ <div class="hor-scroll">
25
+ <div>
26
+ <a class="link_add" href="#"> <i class="icon-plus"></i> <?php echo $this->__('Add a new 360/3D view') ?></a>
27
+ </div>
28
+ <br>
29
+
30
+ <div class="row" id="newForm" style="display:none">
31
+ <table cellspacing="0" class="form-list">
32
+ <tbody>
33
+ <tr>
34
+ <td class="label"><label for="set_name"><?php echo $this->__('Create a new') ?></label></td>
35
+ <td class="value">
36
+ <input type="text" id="set_name" name="set_name" value="" />
37
+ <p class="note"><?php echo $this->__('Please enter any name') ?></p>
38
+ </td>
39
+ <td class="scope-label"><span class="nobr"></span></td>
40
+ </tr>
41
+ <?php if ($setsGroups): ?>
42
+ <tr>
43
+ <td colspan="3"><b><?php echo $this->__('OR') ?></b></td>
44
+ </tr>
45
+ <tr>
46
+ <td class="label"><label for="existing"><?php echo $this->__('Add to existing 3D as next row') ?></label></td>
47
+ <td class="value">
48
+ <select name="existing" id="existing">
49
+ <option value="" style="min-width: 100px"><?php echo $this->__('Select') ?></option>
50
+ <?php foreach ($setsGroups as $group): ?>
51
+ <option value="<?php echo $group['id_360'] ?>"><?php echo $group['name'] ?></option>
52
+ <?php endforeach ?>
53
+ </select>
54
+ <p class="note"><?php echo $this->__('You should not select anything here unless you want to create 3D (not 360) which contains more than one row!') ?></p>
55
+ </td>
56
+ <td class="scope-label"><span class="nobr"></span></td>
57
+ </tr>
58
+ <?php endif; ?>
59
+
60
+ <tr>
61
+ <td class="label"><label for="zip"><?php echo $this->__('Add images from ZIP archive') ?></label></td>
62
+ <td class="value">
63
+ <input type="checkbox" id="zip" name="zip" value="1" />
64
+ <p class="note"><?php echo $this->__('This is the most easy and quick way of adding 360 views to your product! Upload over FTP your 360\'s zipped (each images set in one zip file) to /modules/ajaxzoom/zip/ directory. After you did so these zip files will instantly appear in the select field below. All you have to do then is select one of the zip files and press \'add\' button. Images from the selected zip file will be instantly imported.') ?></p>
65
+ </td>
66
+ <td class="scope-label"><span class="nobr"></span></td>
67
+ </tr>
68
+ <tr class="field-arcfile" style="display:none;">
69
+ <td class="label"><label for="arcfile"><?php echo $this->__('Select ZIP archive') ?></label></td>
70
+ <td class="value">
71
+ <?php if ($files): ?>
72
+ <select name="arcfile" id="arcfile">
73
+ <option value=""><?php echo $this->__('Select') ?></option>
74
+ <? foreach ($files as $file): ?>
75
+ <option value="<?php echo $file ?>"><?php echo $file ?></option>
76
+ <? endforeach; ?>
77
+ </select>
78
+ <?php else: ?>
79
+ <p><b><?php echo $this->__('There are no files found in the "js/axzoom/zip" folder') ?></b></p>
80
+ <?php endif; ?>
81
+ </td>
82
+ <td class="scope-label"><span class="nobr"></span></td>
83
+ </tr>
84
+
85
+ <tr>
86
+ <td></td>
87
+ <td>
88
+ <button type="button" class="scalable save save_set" >
89
+ <span><span><span><?php echo $this->__('Add') ?></span></span></span>
90
+ </button>
91
+ </td>
92
+ <td></td>
93
+ </tr>
94
+ </tbody>
95
+ </table>
96
+ </div>
97
+ <br>
98
+ <div class="row">
99
+ <div class="grid">
100
+ <table class="data border" id="imageTableSets" >
101
+ <thead>
102
+ <tr class="headings">
103
+ <th><?php echo $this->__('Cover Image') ?></th>
104
+ <th><?php echo $this->__('Name') ?></th>
105
+ <th><?php echo $this->__('Active') ?></th>
106
+ <th class="last" style="width:240px;"><?php echo $this->__('Actions') ?></th>
107
+ </tr>
108
+ </thead>
109
+ <tbody id="imageTableSetsRows">
110
+ </tbody>
111
+ </table>
112
+ </div>
113
+
114
+ <table id="lineSet" style="display:none;">
115
+ <tr id="set_id" data-group="group_id">
116
+ <td><img src="../modules/ajaxzoom/views/img/image_path.gif" alt="legend" title="legend" class="img-thumbnail" /></td>
117
+ <td>legend</td>
118
+ <td>
119
+ <span class="switch prestashop-switch fixed-width-lg hide_class switch-status">
120
+ <input type="radio" name="status_field" id="status_field_on" value="1" checked_on />
121
+ <label class="t" for="status_field_on"><?php echo $this->__('Yes') ?></label>
122
+ <input type="radio" name="status_field" id="status_field_off" value="0" checked_off />
123
+ <label class="t" for="status_field_off"><?php echo $this->__('No') ?></label>
124
+ <a class="slide-button btn"></a>
125
+ </span>
126
+ </td>
127
+ <td>
128
+ <button class="delete_set scalable delete" ><?php echo $this->__('Delete') ?></button>
129
+ <button class="images_set scalable" ><?php echo $this->__('Images') ?></button>
130
+ <button class="scalable preview_set hide_class" ><?php echo $this->__('Preview') ?></button>
131
+ </td>
132
+ </tr>
133
+ </table>
134
+ </div>
135
+ </div>
136
+ </div>
137
+ </div>
138
+
139
+
140
+ <script>
141
+ var id_product = '<?php echo $productId ?>';
142
+
143
+ jQuery(document).ready(function($){
144
+
145
+ function setLine(id, path, position, legend, status, group_id)
146
+ {
147
+ line = $("#lineSet").html();
148
+ line = line.replace(/set_id/g, id);
149
+ line = line.replace(/group_id/g, group_id);
150
+ line = line.replace(/legend/g, legend);
151
+ line = line.replace(/status_field/g, 'status_' + id);
152
+ line = line.replace(/\.\.\/modules\/ajaxzoom\/views\/img\/image_path\.gif/g, path);
153
+ line = line.replace(/<tbody>/gi, "");
154
+ line = line.replace(/<\/tbody>/gi, "");
155
+
156
+ if(status == '1') {
157
+ line = line.replace(/checked_on/g, 'checked');
158
+ line = line.replace(/checked_off/g, '');
159
+ } else {
160
+ line = line.replace(/checked_on/g, '');
161
+ line = line.replace(/checked_off/g, 'checked');
162
+ }
163
+
164
+ if($('tr[data-group=' + group_id + ']').length) {
165
+ line = line.replace(/hide_class/g, 'hide');
166
+ }
167
+
168
+ $("#imageTableSetsRows").append(line);
169
+ }
170
+
171
+ function afterUpdateStatus(data) {
172
+ data = $.parseJSON(data);
173
+ showSuccessMessage(data.confirmations);
174
+ }
175
+
176
+ function afterDeleteSet(data) {
177
+ var data = $.parseJSON(data);
178
+ $('tr#' + data.id_360set).remove();
179
+ showSuccessMessage(data.confirmations);
180
+
181
+ // remove set option from the dropdowns
182
+ if(data.removed == '1') {
183
+ $("select#id_360 option[value='" + data.id_360 + "']").remove();
184
+ $("select#existing option[value='" + data.id_360 + "']").remove();
185
+ }
186
+ }
187
+
188
+ function afterAddSet(data) {
189
+ var data = $.parseJSON(data);
190
+
191
+ if(data.sets.length > 0) {
192
+ for (var i = 0; i < data.sets.length; i++) {
193
+ var set = data.sets[i];
194
+ setLine(set.id_360set, set.path, "", set.name, set.status, set.id_360);
195
+ };
196
+ } else {
197
+ setLine(data.id_360set, data.path, "", data.name, data.status, data.id_360);
198
+ }
199
+
200
+ $('.link_add').find('i').removeClass('icon-minus').addClass('icon-plus');
201
+ $('#newForm').hide();
202
+ $('#set_name').val('');
203
+ $('#existing').val('');
204
+
205
+ if(data.new_id != '') {
206
+ $('select#id_360')
207
+ .append($("<option></option>")
208
+ .attr("value", data.new_id)
209
+ .attr('data-settings', data.new_settings)
210
+ .attr('data-combinations', '[]')
211
+ .text(data.new_name));
212
+ $('select#existing').append($("<option></option>").attr("value", data.new_id).text(data.new_name));
213
+ }
214
+ showSuccessMessage(data.confirmations);
215
+ }
216
+
217
+ function afterGetImages(data) {
218
+ var data = $.parseJSON(data);
219
+
220
+ for (var i = 0; i < data.images.length; i++) {
221
+ imageLine360(data.images[i]['id'], data.images[i]['thumb'], '', "", "", "");
222
+ };
223
+
224
+ }
225
+
226
+
227
+ $('#zip').change(function () {
228
+ if($(this).is(':checked')) {
229
+ $('.field-arcfile').show();
230
+ } else {
231
+ $('.field-arcfile').hide();
232
+ }
233
+ });
234
+
235
+ $('.link_add').click(function (e) {
236
+ e.preventDefault();
237
+
238
+ var icon = $(this).find('i');
239
+
240
+ if(icon.hasClass('icon-plus')) {
241
+ icon.removeClass('icon-plus').addClass('icon-minus');
242
+ $('#newForm').show();
243
+ } else {
244
+ icon.removeClass('icon-minus').addClass('icon-plus');
245
+ $('#newForm').hide();
246
+ }
247
+ });
248
+
249
+ $('.switch-status input').die().live('change', function(e) {
250
+ e.preventDefault();
251
+ var status = $(this).val();
252
+ var group_id = $(this).parent().parent().parent().data('group');
253
+
254
+ doAdminAjax360('<?php echo Mage::helper("adminhtml")->getUrl("axzoom/index/set360Status") ?>', {
255
+ "id_product" : <?php echo $productId ?>,
256
+ "id_360" : group_id,
257
+ "status" : status}, afterUpdateStatus
258
+ );
259
+
260
+ });
261
+
262
+ $('.preview_set').die().live('click', function(e) {
263
+ e.preventDefault();
264
+
265
+ var id360 = $(this).parent().parent().data('group');
266
+ var id360set = $(this).parent().parent().attr('id');
267
+
268
+ $.openAjaxZoomInFancyBox({href: '<?php echo Mage::getBaseUrl('js') ?>axzoom/preview/preview.php?3dDir=<?php echo Mage::getModel('axzoom/ax360')->rootFolder() ?>js/axzoom/pic/360/' + id_product + '/' + id360+'&group='+id360+'&id='+id360set, iframe: true});
269
+ });
270
+
271
+ $('.images_set').die().live('click', function(e) {
272
+ e.preventDefault();
273
+
274
+ $('#imageTableSetsRows').find('tr').removeClass('active');
275
+ $(this).parent().parent().addClass('active');
276
+ $('#imageList360').html('');
277
+ $('#file360-success').parent().hide();
278
+
279
+ var id = $(this).parent().parent().attr('id');
280
+
281
+ doAdminAjax360('<?php echo Mage::helper("adminhtml")->getUrl("axzoom/index/getImages") ?>', {
282
+ "id_product" : <?php echo $productId ?>,
283
+ "id_360set" : id}, afterGetImages
284
+ );
285
+
286
+ $('#id_360set').val(id);
287
+ $('#product-images360').show();
288
+ });
289
+
290
+
291
+ $('.save_set').click(function (e) {
292
+ e.preventDefault();
293
+
294
+ doAdminAjax360('<?php echo Mage::helper("adminhtml")->getUrl("axzoom/index/addSet") ?>', {
295
+ "name":$('#set_name').val(),
296
+ "existing":$('#existing').val(),
297
+ "zip":$('#zip').is(':checked'),
298
+ "arcfile":$('#arcfile').val(),
299
+ "id_product" : <?php echo $productId ?>}, afterAddSet
300
+ );
301
+ });
302
+
303
+
304
+ $('.delete_set').die().live('click', function(e)
305
+ {
306
+ e.preventDefault();
307
+
308
+ $('#product-images360').hide();
309
+ $('#imageList360').html('');
310
+
311
+ var id = $(this).parent().parent().attr('id');
312
+ if (confirm("<?php echo $this->__('Are you sure?') ?>"))
313
+ doAdminAjax360('<?php echo Mage::helper("adminhtml")->getUrl("axzoom/index/deleteSet") ?>', {
314
+ "id_360set":id,
315
+ "id_product" : <?php echo $productId ?>}, afterDeleteSet
316
+ );
317
+ });
318
+
319
+ <?php foreach ($sets as $set): ?>
320
+ setLine("<?php echo $set['id_360set'] ?>", "<?php echo $set['path'] ?>", "", "<?php echo $set['name'] ?>", "<?php echo $set['status'] ?>", "<?php echo $set['id_360'] ?>");
321
+ <?php endforeach; ?>
322
+ });
323
+ </script>
app/design/adminhtml/default/default/template/axzoom/tab360-settings.phtml ADDED
@@ -0,0 +1,280 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ $model = Mage::getModel('axzoom/ax360');
3
+ $groups = $model->getCollection()->addFieldToFilter('id_product', $productId)->getData();
4
+ $active = !Mage::getModel('axzoom/axproducts')->getCollection()->addFieldToFilter('id_product', $productId)->count();
5
+
6
+ // associated products
7
+ $associated = array();
8
+ $product = Mage::getModel('catalog/product')->load($productId);
9
+ if ($product->isConfigurable()) {
10
+ $childProducts = Mage::getModel('catalog/product_type_configurable')
11
+ ->getUsedProducts(null,$product);
12
+
13
+ foreach ($childProducts as $child) {
14
+ $p = Mage::getModel('catalog/product')->load($child->getId());
15
+ $associated[$child->getId()] = $p->getName() . ' (' . $child->getSku() . ')';
16
+ }
17
+ }
18
+ ?>
19
+ <style type="text/css">
20
+ .pull-right {
21
+ float: right;
22
+ }
23
+ #pairRows input, #pairRows textarea{
24
+ margin-bottom: 3px;
25
+ }
26
+
27
+ #pairRows textarea{
28
+ resize:vertical;
29
+ }
30
+ </style>
31
+
32
+
33
+ <div class="entry-edit">
34
+ <div class="entry-edit-head">
35
+ <h4 class="icon-head head-edit-form fieldset-legend"><?php echo $this->__('Enable / Disable AJAX-ZOOM for this product') ?></h4>
36
+ </div>
37
+ <div class="fieldset fieldset-wide" id="group_fields9">
38
+ <div class="hor-scroll">
39
+ <table cellspacing="0" class="form-list">
40
+ <tbody>
41
+ <tr>
42
+ <td class="label"><label for="meta_title"><?php echo $this->__('AJAX ZOOM enabled for this product\'s detail view') ?></label></td>
43
+ <td class="value">
44
+ <input type="radio" name="az_active" id="az_active_on" value="1" <? if($active == 1):?>checked="checked"<? endif ?>/>
45
+ <label class="t" for="az_active_on"><?php echo $this->__('Yes') ?></label>
46
+ <input type="radio" name="az_active" id="az_active_off" value="0" <? if($active == 0):?>checked="checked"<? endif ?>/>
47
+ <label class="t" for="az_active_off"><?php echo $this->__('No') ?></label>
48
+ </td>
49
+ <td class="scope-label"><span class="nobr"></span></td>
50
+ </tr>
51
+ </tbody>
52
+ </table>
53
+ </div>
54
+ </div>
55
+ </div>
56
+
57
+
58
+ <div class="entry-edit">
59
+ <div class="entry-edit-head">
60
+ <h4 class="icon-head head-edit-form fieldset-legend"><?php echo $this->__('SETTINGS FOR EXISTING 360/3D') ?></h4>
61
+ </div>
62
+ <div class="fieldset fieldset-wide" id="group_fields9">
63
+ <div class="hor-scroll">
64
+ <table cellspacing="0" class="form-list">
65
+ <tbody>
66
+ <tr>
67
+ <td class="label"><label for="meta_title"><?php echo $this->__('360/3D View') ?></label></td>
68
+ <td class="value">
69
+ <?php foreach ($groups as $group): ?>
70
+ <input type="hidden" name="settings[<?php echo $group['id_360'] ?>]" id="settings_<?php echo $group['id_360'] ?>" value="<?php echo urlencode($group['settings']) ?>">
71
+ <input type="hidden" name="comb[<?php echo $group['id_360'] ?>]" id="settings_comb_<?php echo $group['id_360'] ?>" value="<?php echo urlencode($group['combinations']) ?>">
72
+
73
+ <?php endforeach; ?>
74
+ <select id="id_360" name="id_360" style="min-width: 100px">
75
+ <option value=""><?php echo $this->__('Select') ?></option>
76
+ <?php foreach ($groups as $group): ?>
77
+ <option value="<?php echo $group['id_360'] ?>" data-settings="<?php echo urlencode($group['settings']) ?>" data-combinations="[<?php echo urlencode($group['combinations']) ?>]"><?php echo $group['name'] ?></option>
78
+ <?php endforeach; ?>
79
+ </select>
80
+ </td>
81
+ <td class="scope-label"><span class="nobr"></span></td>
82
+ </tr>
83
+ <tr id="pairs" style="display:none;">
84
+ <td class="label"><label for="meta_title"><?php echo $this->__('Settings') ?></label></td>
85
+ <td class="value">
86
+ <table>
87
+ <thead>
88
+ <tr>
89
+ <th><?php echo $this->__('Name') ?></th>
90
+ <th></th>
91
+ <th style="width: 220px"><?php echo $this->__('Value') ?></th>
92
+ <th></th>
93
+ </tr>
94
+ </thead>
95
+ <tbody id="pairRows">
96
+ </tbody>
97
+ <tfoot>
98
+ <tr>
99
+ <td colspan="4">
100
+ <div class="row_">
101
+ <button class="scalable add link_add_option">
102
+ <span><span><span><?php echo $this->__('Add an option') ?></span></span></span>
103
+ </button>
104
+ </div>
105
+ </td>
106
+ </tr>
107
+ </tfoot>
108
+ </table>
109
+ <table id="pairTemplate" style="display: none">
110
+ <tr>
111
+ <td><input type="text" name="name[]" value="name_placeholder" class="pair-names"></td>
112
+ <td>&nbsp; : &nbsp;</td>
113
+ <td><input type="text" name="value[]" value="value_placeholder" class="pair-values"></td>
114
+ <td>
115
+ <a class="link_textarea_option" href="#">
116
+ <?php echo $this->__('Edit') ?>
117
+ </a>
118
+ &nbsp;&nbsp;
119
+ <a class="link_remove_option" href="#">
120
+ <?php echo $this->__('Delete') ?>
121
+ </a>
122
+ </td>
123
+ </tr>
124
+ </table>
125
+ </td>
126
+ </tr>
127
+
128
+ <?php if (count($associated)): ?>
129
+ <tr id="comb" style="display:none;">
130
+ <td class="label"><label for="meta_title"><?php echo $this->__('Associated products') ?></label></td>
131
+ <td class="value">
132
+ <button class="comb-check-all" style="margin-bottom: 10px;" value="check all" >check all</button><br>
133
+
134
+ <?php foreach ($associated as $id => $name): ?>
135
+ <input type="checkbox" name="combinations[]" value="<?php echo $id ?>" class="settings-combinations"> <?php echo $name ?><br>
136
+ <? endforeach; ?>
137
+
138
+ <div class="" style="display: block; margin-top: 10px;">
139
+ <?php echo $this->__('Same as with images you can define which 360 should be shown in conjunction with which combinations.') ?>
140
+ <?php echo $this->__('If you do not select any this 360 will be shown for all combinations.') ?>
141
+ </div>
142
+ </td>
143
+ </tr>
144
+ <? endif; ?>
145
+ </tbody>
146
+ </table>
147
+ </div>
148
+ </div>
149
+ </div>
150
+
151
+
152
+ <script type="text/javascript">
153
+ jQuery(function ($) {
154
+
155
+ function pairLine(name, value)
156
+ {
157
+ var line = $("#pairTemplate").html();
158
+ line = line.replace(/name_placeholder/g, name);
159
+ line = line.replace(/value_placeholder/g, value);
160
+ line = line.replace(/<tbody>/gi, "");
161
+ line = line.replace(/<\/tbody>/gi, "");
162
+ $("#pairRows").append(line);
163
+ }
164
+
165
+ function afterSaveSettings(data) {
166
+ var data = $.parseJSON(data);
167
+
168
+ $('#id_360').replaceWith(data.select);
169
+ $('#pairs').hide();
170
+ $('#comb').hide();
171
+ $('select#id_360').val('');
172
+ showSuccessMessage(data.confirmations);
173
+ }
174
+
175
+ function getFieldValues(class1) {
176
+ var inputs = document.getElementsByClassName( class1 );
177
+ var res = [];
178
+ for (var i = 0; i < inputs.length; i++) {
179
+ res.push(inputs[i].value);
180
+ };
181
+ return res;
182
+ }
183
+
184
+ function setPairString() {
185
+ var names = getFieldValues('pair-names');
186
+ var values = getFieldValues('pair-values');
187
+ var res = {};
188
+ for (var i = 0; i < names.length; i++) {
189
+ if(names[i] == 'name_placeholder') continue;
190
+ res[names[i]] = values[i];
191
+ };
192
+
193
+ $('#settings_' + $('select#id_360').val()).val(encodeURIComponent(JSON.stringify(res)));
194
+ }
195
+
196
+ function setComb() {
197
+
198
+ var values = [];
199
+ $('.settings-combinations:checked').each(function () {
200
+ values.push($(this).val());
201
+ });
202
+
203
+ $('#settings_comb_' + $('select#id_360').val()).val(encodeURIComponent(JSON.stringify(values)));
204
+ }
205
+
206
+ $('.pair-names, .pair-values').die()
207
+ .live('change', function(e) {
208
+ setPairString();
209
+ } );
210
+
211
+ $('.settings-combinations').die()
212
+ .live('change', function(e) {
213
+ setComb();
214
+ } );
215
+
216
+
217
+ $('.link_add_option').click(function (e) {
218
+ e.preventDefault();
219
+ pairLine('', '');
220
+ } );
221
+
222
+ $('.link_remove_option').die()
223
+ .live('click', function(e) {
224
+ e.preventDefault();
225
+ $(this).parent().parent().remove();
226
+ setPairString();
227
+ } );
228
+
229
+ $('.link_textarea_option').die()
230
+ .live('click', function(e) {
231
+ e.preventDefault();
232
+ var td = $(this).parent().prev();
233
+ if ($('input', td).length == 1) {
234
+ var Val = $('input', td).val();
235
+ $('input', td).replaceWith('<textarea class="pair-values" type="text" name="value[]">'+Val+'</textarea>');
236
+ } else if ($('textarea', td).length == 1) {
237
+ var Val = $('textarea', td).val();
238
+ $('textarea', td).replaceWith('<input class="pair-values" type="text" value="'+Val+'" name="value[]">');
239
+ }
240
+ } );
241
+
242
+ $('select#id_360').die().live('change', function(e) {
243
+
244
+ $('#pairRows').html('');
245
+
246
+ if($(this).val() != '') {
247
+
248
+ // set pairs name:value
249
+ var settings = $.parseJSON(unescape($('option:selected', $(this)).attr('data-settings')));
250
+ for(var k in settings) {
251
+ pairLine(k, settings[k])
252
+ }
253
+
254
+ // set combinations checkboxes
255
+ var combinations = $.parseJSON(unescape($('option:selected', $(this)).attr('data-combinations')))[0];
256
+
257
+ $('input.settings-combinations').attr('checked', false);
258
+ if(combinations && combinations.length) {
259
+ for (var i = combinations.length - 1; i >= 0; i--) {
260
+ $('input.settings-combinations[value=' + combinations[i] + ']').attr('checked', true);
261
+ };
262
+ }
263
+
264
+ $('#pairs').show();
265
+ $('#comb').show();
266
+ } else {
267
+ $('#pairs').hide();
268
+ $('#comb').hide();
269
+ }
270
+ });
271
+
272
+ $('.comb-check-all:button').toggle(function() {
273
+ $('input.settings-combinations').attr('checked','checked');
274
+ $(this).val('uncheck all')
275
+ } ,function() {
276
+ $('input.settings-combinations').removeAttr('checked');
277
+ $(this).val('check all');
278
+ } );
279
+ });
280
+ </script>
app/design/adminhtml/default/default/template/axzoom/tab360.phtml ADDED
@@ -0,0 +1,135 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php $maxImageSize = ini_get('upload_max_filesize'); ?>
2
+
3
+ <input type="hidden" name="id_360set" id="id_360set" value="" />
4
+
5
+ <div id="product-images360" class="entry-edit" style="display:none">
6
+ <div class="entry-edit-head">
7
+ <h4 class="icon-head head-edit-form fieldset-legend"><?php echo $this->__('Images') ?></h4>
8
+ </div>
9
+ <div class="fieldset fieldset-wide" id="group_fields9">
10
+ <div class="hor-scroll">
11
+ <input type="hidden" name="submitted_tabs[]" value="Images360" />
12
+
13
+ <div class="row">
14
+ <div class="form-group">
15
+ <label class="control-label col-lg-3 file_upload_label">
16
+ <span class="label-tooltip" data-toggle="tooltip" title="<?php echo $this->__('Format: JPG, GIF, PNG. Filesize: %s MB max', $maxImageSize) ?>">
17
+ <?php echo $this->__('Add a new image to this image set') ?>
18
+ </span>
19
+ </label>
20
+ <div class="col-lg-9">
21
+ <?php require "uploader.phtml"; ?>
22
+ </div>
23
+ </div>
24
+ </div>
25
+ <div class="grid">
26
+ <table class="data border" id="imageTable360">
27
+ <thead>
28
+ <tr class="headings">
29
+ <th><?php echo $this->__('Image') ?></th>
30
+ <th><?php echo $this->__('Actions') ?></th>
31
+ </tr>
32
+ </thead>
33
+ <tbody id="imageList360">
34
+ </tbody>
35
+ </table>
36
+ </div>
37
+ <table id="lineType360" style="display:none;">
38
+ <tr id="image_id">
39
+ <td>
40
+ <img src="<?php echo Mage::getModel('axzoom/ax360')->rootFolder() ?>js/axzoom/image_path.gif" alt="legend" title="legend" class="img-thumbnail" />
41
+ </td>
42
+ <td style="width:75px;">
43
+ <button type="button" class="delete_product_image360 scalable delete" >
44
+ <span><span><?php echo $this->__('Delete this image') ?><span></span></span></span>
45
+ </button>
46
+ </td>
47
+ </tr>
48
+ </table>
49
+ <div class="panel-footer">
50
+ <button class="btn_cancel"><?php echo $this->__('Cancel') ?></button>
51
+ </div>
52
+ </div>
53
+ </div>
54
+ </div>
55
+
56
+ <script type="text/javascript">
57
+ /*
58
+ var hookGetUrlParam = function(name, url) {
59
+ if (!url) {
60
+ url = window.location.href;
61
+ }
62
+ var results = new RegExp('[\\?&]' + name + '=([^&#]*)').exec(url);
63
+ if (!results) {
64
+ return undefined;
65
+ }
66
+ return results[1] || undefined;
67
+ }
68
+
69
+ jQuery( document ).bind('ajaxComplete.azHook', function( event, xhr, settings ) {
70
+ var dataString = '?'+settings.data;
71
+ if (hookGetUrlParam('action', dataString) == 'deleteProductImage') {
72
+ var id_image = hookGetUrlParam('id_image', dataString);
73
+ //console.log('Send request to delete AJAX-ZOOM cache for this image ID: '+id_image);
74
+ doAdminAjax360('<?php echo Mage::helper("adminhtml")->getUrl("axzoom/index/clearAzImageCache") ?>', {
75
+ "deletedImgID" : id_image
76
+ } );
77
+ }
78
+ } );
79
+ */
80
+
81
+ function imageLine360(id, path, position, cover, shops, legend)
82
+ {
83
+ line = jQuery("#lineType360").html();
84
+ line = line.replace(/image_id/g, id);
85
+ line = line.replace(/"(.*?)path\.gif"/g, path);
86
+ line = line.replace(/icon-check-empty/g, cover);
87
+ line = line.replace(/<tbody>/gi, "");
88
+ line = line.replace(/<\/tbody>/gi, "");
89
+
90
+ jQuery("#imageList360").append(line);
91
+ }
92
+
93
+ jQuery(document).ready(function($){
94
+
95
+ function afterDeleteProductImage360(data)
96
+ {
97
+ data = $.parseJSON(data);
98
+ if (data)
99
+ {
100
+ id = data.content.id;
101
+ if (data.status == 'ok')
102
+ {
103
+ $("#" + id).remove();
104
+ }
105
+
106
+ showSuccessMessage(data.confirmations);
107
+ }
108
+ }
109
+
110
+ $('.btn_cancel').die().live('click', function(e)
111
+ {
112
+ e.preventDefault();
113
+ $('#product-images360').hide();
114
+ });
115
+
116
+
117
+ $('.delete_product_image360').die().live('click', function(e)
118
+ {
119
+ e.preventDefault();
120
+ id = $(this).parent().parent().attr('id');
121
+ var id_360set = $('#id_360set').val();
122
+ var ext = $(this).parent().parent().find('img').attr('src').split('.').pop();
123
+ if (confirm("<?php echo $this->__('Are you sure?') ?>"))
124
+ doAdminAjax360('<?php echo Mage::helper("adminhtml")->getUrl("axzoom/index/deleteProductImage360") ?>', {
125
+ "id_image":id,
126
+ 'id_360set': id_360set,
127
+ "ext":ext,
128
+ "id_product" : <?php echo $productId ?>
129
+ }, afterDeleteProductImage360
130
+ );
131
+ });
132
+
133
+ $('.fancybox').fancybox();
134
+ });
135
+ </script>
app/design/adminhtml/default/default/template/axzoom/uploader.phtml ADDED
@@ -0,0 +1,179 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ $id = 'file360';
3
+ $name = 'file360';
4
+ $url = Mage::helper("adminhtml")->getUrl("axzoom/index/addProductImage360", array('id_product' => $productId));
5
+ $postMaxSize = return_bytes(ini_get('post_max_size'));
6
+ $maxFiles = 100;
7
+
8
+ function return_bytes($val) {
9
+ $val = trim($val);
10
+ $last = strtolower($val[strlen($val)-1]);
11
+ switch ($last) {
12
+ case 'g':
13
+ $val *= 1024;
14
+ case 'm':
15
+ $val *= 1024;
16
+ case 'k':
17
+ $val *= 1024;
18
+ }
19
+ return $val;
20
+ }
21
+ ?>
22
+
23
+ <div class="form-group">
24
+ <div class="col-lg-12">
25
+ <input id="<?php echo $id ?>" type="file" name="<?php echo $name ?>[]" data-url="<?php echo $url ?>" multiple="multiple" style="width:0px;height:0px;" />
26
+ <button class="btn btn-default" data-style="expand-right" data-size="s" type="button" id="<?php echo $id ?>-add-button">
27
+ <i class="icon-folder-open"></i> <?php echo $this->__('Add files...') ?>
28
+ </button>
29
+ </div>
30
+ </div>
31
+ <div class="well" style="display:none">
32
+ <div id="<?php echo $id ?>-files-list"></div>
33
+ <button class="ladda-button btn btn-primary" data-style="expand-right" type="button" id="<?php echo $id ?>-upload-button" style="display:none;">
34
+ <span class="ladda-label"><i class="icon-check"></i> <?php echo $this->__('Upload files') ?></span>
35
+ </button>
36
+ </div>
37
+ <div class="row" style="display:none">
38
+ <div class="alert alert-success" id="<?php echo $id ?>-success"></div>
39
+ </div>
40
+ <div class="row" style="display:none">
41
+ <div class="alert alert-danger" id="<?php echo $id ?>-errors"></div>
42
+ </div>
43
+
44
+ <script type="text/javascript">
45
+ function humanizeSize(bytes)
46
+ {
47
+ if (typeof bytes !== 'number') {
48
+ return '';
49
+ }
50
+
51
+ if (bytes >= 1000000000) {
52
+ return (bytes / 1000000000).toFixed(2) + ' GB';
53
+ }
54
+
55
+ if (bytes >= 1000000) {
56
+ return (bytes / 1000000).toFixed(2) + ' MB';
57
+ }
58
+
59
+ return (bytes / 1000).toFixed(2) + ' KB';
60
+ }
61
+
62
+ jQuery( document ).ready(function($) {
63
+
64
+ <?php if (isset($files) && $files): ?>
65
+ $('#<?php echo $id ?>-images-thumbnails').parent().show();
66
+ <? endif; ?>
67
+
68
+ var <?php echo $id ?>_total_files = 0;
69
+
70
+ $('#<?php echo $id ?>').fileupload({
71
+ dataType: 'json',
72
+ async: false,
73
+ autoUpload: false,
74
+ singleFileUploads: true,
75
+ maxFileSize: <?php echo $postMaxSize ?>,
76
+ start: function (e) {
77
+ $('#<?php echo $id ?>-upload-button').unbind('click'); //Important as we bind it for every elements in add function
78
+ },
79
+ fail: function (e, data) {
80
+ $('#<?php echo $id ?>-errors').html(data.errorThrown.message).parent().show();
81
+ $('#<?php echo $id ?>-files-list').html('').parent().hide();
82
+ },
83
+ done: function (e, data) {
84
+ if (data.result) {
85
+ if (typeof data.result.<?php echo $name ?> !== 'undefined') {
86
+ for (var i=0; i<data.result.<?php echo $name ?>.length; i++) {
87
+ if (typeof data.result.<?php echo $name ?>[i].error !== 'undefined' && data.result.<?php echo $name ?>[i].error != '') {
88
+ $('#<?php echo $id ?>-errors').html('<strong>'+data.result.<?php echo $name ?>[i].name+'</strong> : '+data.result.<?php echo $name ?>[i].error).parent().show();
89
+ $('#<?php echo $id ?>-files-list').html('').parent().hide();
90
+ }
91
+ else
92
+ {
93
+ $(data.context).appendTo($('#<?php echo $id ?>-success'));
94
+ $('#<?php echo $id ?>-success').parent().show();
95
+
96
+
97
+ if (data.result.<?php echo $name ?>[i] !== null && data.result.<?php echo $name ?>[i].status == 'ok')
98
+ {
99
+
100
+ var response = data.result.<?php echo $name ?>[i];
101
+ var cover = "icon-check-empty";
102
+ var legend = '';
103
+
104
+ imageLine360(response.id, response.path, response.position, cover, response.shops, legend);
105
+ $("#countImage").html(parseInt($("#countImage").html()) + 1);
106
+ $("#img" + id).remove();
107
+ $('#legend_1').val('');
108
+ }
109
+ }
110
+
111
+ }
112
+ }
113
+ $(data.context).find('button').remove();
114
+ }
115
+ },
116
+ }).on('fileuploadalways', function (e, data) {
117
+ <?php echo $id ?>_total_files--;
118
+
119
+ if (<?php echo $id ?>_total_files == 0)
120
+ {
121
+ $('#<?php echo $id ?>-upload-button').unbind('click');
122
+ $('#<?php echo $id ?>-files-list').parent().hide();
123
+ }
124
+ }).on('fileuploadadd', function(e, data) {
125
+ if (typeof <?php echo $id ?>_max_files !== 'undefined') {
126
+ if (<?php echo $id ?>_total_files >= <?php echo $id ?>_max_files) {
127
+ e.preventDefault();
128
+ alert('You can upload a maximum of <?php echo $maxFiles ?> files');
129
+ return;
130
+ }
131
+ }
132
+
133
+ data.context = $('<div/>').addClass('form-group').appendTo($('#<?php echo $id ?>-files-list'));
134
+ var file_name = $('<span/>').append('<i class="icon-picture-o"></i> <strong>'+data.files[0].name+'</strong> ('+humanizeSize(data.files[0].size)+')').appendTo(data.context);
135
+
136
+ var button = $('<button/>').addClass('btn btn-default pull-right').prop('type', 'button').html('<i class="icon-trash"></i> Remove file').appendTo(data.context).on('click', function() {
137
+ <?php echo $id ?>_total_files--;
138
+ data.files = null;
139
+
140
+ var total_elements = $(this).parent().siblings('div.form-group').length;
141
+ $(this).parent().remove();
142
+
143
+ if (total_elements == 0) {
144
+ $('#<?php echo $id ?>-files-list').html('').parent().hide();
145
+ }
146
+ });
147
+
148
+ $('#<?php echo $id ?>-files-list').parent().show();
149
+ $('#<?php echo $id ?>-upload-button').show().bind('click', function () {
150
+ if (data.files != null)
151
+ data.submit();
152
+ });
153
+
154
+ <?php echo $id ?>_total_files++;
155
+ }).on('fileuploadprocessalways', function (e, data) {
156
+ var index = data.index, file = data.files[index];
157
+
158
+ if (file.error) {
159
+ $('#<?php echo $id ?>-errors').append('<div class="form-group"><i class="icon-picture-o"></i> <strong>'+file.name+'</strong> ('+humanizeSize(file.size)+') : '+file.error+'</div>').parent().show();
160
+ $('#<?php echo $id ?>-files-list').html('').parent().hide();
161
+ $(data.context).find('button').trigger('click');
162
+ }
163
+ }).on('fileuploadsubmit', function (e, data) {
164
+ var params = new Object();
165
+
166
+ params['id_360set'] = $('#id_360set').val();
167
+
168
+ data.formData = params;
169
+ }).on('fileuploadstop', function (e, data) {
170
+
171
+ });
172
+
173
+ $('#<?php echo $id ?>-add-button').on('click', function() {
174
+ $('#<?php echo $id ?>-success').html('').parent().hide();
175
+ $('#<?php echo $id ?>-errors').html('').parent().hide();
176
+ $('#<?php echo $id ?>').trigger('click');
177
+ });
178
+ });
179
+ </script>
app/design/frontend/default/default/layout/axzoom.xml ADDED
@@ -0,0 +1,59 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?xml version="1.0"?>
2
+
3
+ <layout version="0.1.0">
4
+ <catalog_product_view>
5
+ <reference name="head">
6
+ <action method="addJs">
7
+ <script>axzoom/check_jquery.js</script>
8
+ </action>
9
+ <action method="addCss">
10
+ <stylesheet>../../../../js/axzoom/axZm/axZm.css</stylesheet>
11
+ </action>
12
+ <action method="addJs">
13
+ <script>axzoom/axZm/jquery.axZm.js</script>
14
+ </action>
15
+ <action method="addJs">
16
+ <script>axzoom/axZm/extensions/axZmThumbSlider/lib/jquery.mousewheel.min.js</script>
17
+ </action>
18
+ <action method="addCss">
19
+ <stylesheet>../../../../js/axzoom/axZm/extensions/axZmThumbSlider/skins/default/jquery.axZm.thumbSlider.css</stylesheet>
20
+ </action>
21
+ <action method="addJs">
22
+ <script>axzoom/axZm/extensions/axZmThumbSlider/lib/jquery.axZm.thumbSlider.js</script>
23
+ </action>
24
+ <action method="addJs">
25
+ <script>axzoom/axZm/plugins/spin/spin.min.js</script>
26
+ </action>
27
+ <action method="addCss">
28
+ <stylesheet>../../../../js/axzoom/axZm/extensions/axZmMouseOverZoom/jquery.axZm.mouseOverZoom.4.css</stylesheet>
29
+ </action>
30
+ <action method="addCss">
31
+ <stylesheet>../../../../js/axzoom/axZm/extensions/axZmMouseOverZoom/mods/jquery.axZm.mouseOverZoomPrestashop.4.css</stylesheet>
32
+ </action>
33
+ <action method="addJs">
34
+ <script>axzoom/axZm/extensions/axZmMouseOverZoom/jquery.axZm.mouseOverZoom.4.js</script>
35
+ </action>
36
+ <action method="addJs">
37
+ <script>axzoom/axZm/extensions/axZmMouseOverZoom/jquery.axZm.mouseOverZoomInit.4.js</script>
38
+ </action>
39
+ <action method="addCss">
40
+ <stylesheet>../../../../js/axzoom/axZm/plugins/demo/jquery.fancybox/jquery.fancybox-1.3.4.css</stylesheet>
41
+ </action>
42
+ <action method="addJs">
43
+ <script>axzoom/axZm/plugins/demo/jquery.fancybox/jquery.fancybox-1.3.4.js</script>
44
+ </action>
45
+ <action method="addJs">
46
+ <script>axzoom/axZm/extensions/jquery.axZm.openAjaxZoomInFancyBox.js</script>
47
+ </action>
48
+ <action method="addCss">
49
+ <stylesheet>../../../../js/axzoom/axZm/plugins/demo/colorbox/example2/colorbox.css</stylesheet>
50
+ </action>
51
+ <action method="addJs">
52
+ <script>axzoom/axZm/plugins/demo/colorbox/jquery.colorbox-min.js</script>
53
+ </action>
54
+ <action method="addJs">
55
+ <script>axzoom/axZm/plugins/JSON/jquery.json-2.3.min.js</script>
56
+ </action>
57
+ </reference>
58
+ </catalog_product_view>
59
+ </layout>
app/design/frontend/rwd/default/layout/axzoom.xml ADDED
@@ -0,0 +1,65 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?xml version="1.0"?>
2
+
3
+ <layout version="0.1.0">
4
+ <catalog_product_view>
5
+ <reference name="head">
6
+ <action method="addJs">
7
+ <script>axzoom/check_jquery.js</script>
8
+ </action>
9
+ <action method="addItem">
10
+ <type>js_css</type>
11
+ <name>axzoom/axZm/axZm.css</name>
12
+ </action>
13
+ <action method="addJs">
14
+ <script>axzoom/axZm/jquery.axZm.js</script>
15
+ </action>
16
+ <action ifconfig="axzoom_options/main/galleryAxZmThumbSlider" method="addJs">
17
+ <script>axzoom/axZm/extensions/axZmThumbSlider/lib/jquery.mousewheel.min.js</script>
18
+ </action>
19
+ <action ifconfig="axzoom_options/main/galleryAxZmThumbSlider" method="addItem">
20
+ <type>js_css</type>
21
+ <name>axzoom/axZm/extensions/axZmThumbSlider/skins/default/jquery.axZm.thumbSlider.css</name>
22
+ </action>
23
+ <action ifconfig="axzoom_options/main/galleryAxZmThumbSlider" method="addJs">
24
+ <script>axzoom/axZm/extensions/axZmThumbSlider/lib/jquery.axZm.thumbSlider.js</script>
25
+ </action>
26
+ <action ifconfig="axzoom_options/main/spinner" method="addJs">
27
+ <script>axzoom/axZm/plugins/spin/spin.min.js</script>
28
+ </action>
29
+ <action method="addItem">
30
+ <type>js_css</type>
31
+ <name>axzoom/axZm/extensions/axZmMouseOverZoom/jquery.axZm.mouseOverZoom.4.css</name>
32
+ </action>
33
+ <action method="addItem">
34
+ <type>js_css</type>
35
+ <name>axzoom/axZm/extensions/axZmMouseOverZoom/mods/jquery.axZm.mouseOverZoomPrestashop.4.css</name>
36
+ </action>
37
+ <action method="addJs">
38
+ <script>axzoom/axZm/extensions/axZmMouseOverZoom/jquery.axZm.mouseOverZoom.4.js</script>
39
+ </action>
40
+ <action method="addJs">
41
+ <script>axzoom/axZm/extensions/axZmMouseOverZoom/jquery.axZm.mouseOverZoomInit.4.js</script>
42
+ </action>
43
+ <action method="addItem">
44
+ <type>js_css</type>
45
+ <file helper="axzoom/Head/getFancyboxCss" />
46
+ </action>
47
+ <action method="addJs">
48
+ <file helper="axzoom/Head/getFancyboxJS" />
49
+ </action>
50
+ <action method="addJs">
51
+ <file helper="axzoom/Head/getFancyboxJSAX" />
52
+ </action>
53
+ <action method="addItem">
54
+ <type>js_css</type>
55
+ <file helper="axzoom/Head/getColorboxCss" />
56
+ </action>
57
+ <action method="addJs">
58
+ <file helper="axzoom/Head/getColorboxJS" />
59
+ </action>
60
+ <action method="addJs">
61
+ <script>axzoom/axZm/plugins/JSON/jquery.json-2.3.min.js</script>
62
+ </action>
63
+ </reference>
64
+ </catalog_product_view>
65
+ </layout>
app/design/frontend/rwd/default/template/ax_zoom/catalog/product/view/media.phtml ADDED
@@ -0,0 +1,423 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ $productId = Mage::app()->getRequest()->getParam('id');
3
+ $ax = Mage::getModel('axzoom/ax360');
4
+
5
+ $conf = Mage::getStoreConfig('axzoom_options');
6
+ $tmp = parse_url(Mage::getBaseUrl());
7
+ $axZmPath = str_replace('index.php/', '', $tmp['path']) . 'js/axzoom/axZm/';
8
+ $product = Mage::getModel('catalog/product')->load($productId); //product id here
9
+ $images360Json = $ax->images360Json($productId);
10
+
11
+
12
+
13
+
14
+ // 360 assigned from configurable products to Simple products
15
+ $map = array();
16
+ if ($groups = $ax->getCollection()->addFieldToFilter('id_product', $productId)->getData()) foreach ($groups as $group) {
17
+ $comp = Mage::helper('core')->jsonDecode($group['combinations']);
18
+ if ($comp) {
19
+ foreach ($comp as $pid) {
20
+ if (!isset($map[$pid])) {
21
+ $map[$pid] = array();
22
+ }
23
+ array_push($map[$pid], $group['id_360']);
24
+ }
25
+
26
+ }
27
+ }
28
+
29
+
30
+ // all attributes map
31
+ $mapAttributesCodeId = array();
32
+ $attributes = Mage::getResourceModel('catalog/product_attribute_collection')->getItems();
33
+ foreach ($attributes as $attribute){
34
+ $mapAttributesCodeId[$attribute->getAttributecode()] = $attribute->getId();
35
+ }
36
+ $mapAttributesIdCode = array_flip($mapAttributesCodeId);
37
+
38
+ // get configurable options
39
+ if ($product->type_id == 'configurable') {
40
+ $attributesCodes = array();
41
+ $productAttributesOptions = $product->getTypeInstance(true)->getConfigurableOptions($product);
42
+ foreach ($productAttributesOptions as $productAttributeId => $productAttributeOption) {
43
+ $attributesCodes[] = $mapAttributesIdCode[$productAttributeId];
44
+ }
45
+ }
46
+
47
+
48
+ // get associated products
49
+ $res = array();
50
+ if ($product->isConfigurable()) {
51
+ $childProducts = Mage::getModel('catalog/product_type_configurable')
52
+ ->getUsedProducts(null,$product);
53
+ foreach ($childProducts as $child) {
54
+
55
+ $data = $child->getData();
56
+ $p = Mage::getModel('catalog/product')->load($data['entity_id']);
57
+
58
+ $pairs = array();
59
+ $labels = array();
60
+ foreach ($attributesCodes as $code) {
61
+ $pairs[] = $mapAttributesCodeId[$code] . ':' . $data[$code];
62
+
63
+ $attr = $product->getResource()->getAttribute($code);
64
+ $option_label = $attr->getSource()->getOptionText($data[$code]);
65
+ array_push($labels, trim($option_label));
66
+ }
67
+
68
+ $idx = implode(',', $pairs);
69
+ $res[$idx] = array();
70
+
71
+ $obj = null;
72
+ $cnt = 0;
73
+ // add native images
74
+ foreach ($p->getMediaGalleryImages() as $image) {
75
+
76
+ $tmp = parse_url($image->getUrl());
77
+ if (!$obj) $obj = new stdClass;
78
+ $params = new stdClass;
79
+ $params->img = $tmp['path'];
80
+ $params->title = '';
81
+ $obj->$cnt = $params;
82
+ $cnt++;
83
+ }
84
+
85
+ // add related images via labels
86
+ foreach ($product->getMediaGalleryImages() as $image) {
87
+ if ($image->label_default != '' && in_array(trim($image->label_default), $labels)) {
88
+ $tmp = parse_url($image->getUrl());
89
+ if (!$obj) $obj = new stdClass;
90
+ $params = new stdClass;
91
+ $params->img = $tmp['path'];
92
+ $params->title = '';
93
+ $obj->$cnt = $params;
94
+ $cnt++;
95
+ }
96
+ }
97
+
98
+ if ($obj != null){
99
+ $res[$idx]['images'] = $obj;
100
+ } else {
101
+ $res[$idx]['images'] = new stdClass();
102
+ }
103
+ $extraGroups = empty($map[$data['entity_id']]) ? array() : $map[$data['entity_id']];
104
+ $res[$idx]['images360'] = Mage::helper('core')->jsonDecode(str_replace("'", '"', $ax->images360Json($data['entity_id'], $extraGroups)));
105
+ }
106
+ }
107
+
108
+ //$helper = Mage::helper('configurableswatches/mediafallback');
109
+ //$imageFallback = $helper->getConfigurableImagesFallbackArray($product, array('image'), null);
110
+ //print_r($imageFallback);
111
+
112
+
113
+ /* OLD (based on labels)
114
+ // swatches
115
+ $swatches = array();
116
+ if (version_compare(Mage::getVersion(), '1.9.1') >= 0) {
117
+ $helper = Mage::helper('configurableswatches/mediafallback');
118
+ if ($labelMapping = $product->getChildAttributeLabelMapping() && $imageFallback = $helper->getConfigurableImagesFallbackArray($product, array('image'), null)) {
119
+
120
+ foreach ($imageFallback['option_labels'] as $label => $data) {
121
+ $swatches[$label] = array();
122
+ $cnt = 1;
123
+ $extraGroups = array();
124
+ foreach ($data['products'] as $pid) {
125
+ $p = Mage::getModel('catalog/product')->load($pid);
126
+ $obj = null;
127
+ foreach ($p->getMediaGalleryImages() as $image) {
128
+
129
+ $tmp = parse_url($image->getUrl());
130
+ $obj = new stdClass;
131
+ $params = new stdClass;
132
+ $params->img = $tmp['path'];
133
+ $params->title = '';
134
+ $obj->$cnt = $params;
135
+ $cnt++;
136
+ }
137
+ if ($obj != null){
138
+ $swatches[$label]['images'] = $obj;
139
+ }
140
+ if (isset($map[$pid])) {
141
+ $extraGroups = array_merge($extraGroups, $map[$pid]);
142
+ }
143
+ }
144
+ $swatches[$label]['images360'] = Mage::helper('core')->jsonDecode(str_replace("'", '"', $ax->images360Json($data['products'], $extraGroups)));
145
+ }
146
+ }
147
+ }
148
+ */
149
+
150
+
151
+ $cnt = 0;
152
+ $imagesJson = array();
153
+ if (count($this->getGalleryImages()) > 0) {
154
+
155
+ foreach ($this->getGalleryImages() as $image) {
156
+
157
+ $check_image = true;
158
+ if(method_exists($this, 'isGalleryImageVisible')) {
159
+ $check_image = $this->isGalleryImageVisible($image);
160
+ }
161
+
162
+ if ($check_image) {
163
+ $cnt++;
164
+ $tmp = parse_url($image->getUrl());
165
+ array_push($imagesJson, $cnt . ': {img: "' . $tmp['path'] . '", title: ""}');
166
+ }
167
+ }
168
+ } else {
169
+ if($image_url = $this->helper('catalog/image')->init($product, 'image')) {
170
+ $tmp = parse_url($image_url);
171
+ array_push($imagesJson, '1: {img: "' . $tmp['path'] . '", title: ""}');
172
+ }
173
+ }
174
+ ?>
175
+ <div id="az_mouseOverZoomParent" style="margin-bottom: 20px;">
176
+ <!-- Container for mouse over image -->
177
+ <div id="az_mouseOverZoomContainer" style="position: relative; border: #AAA 1px solid;">
178
+ Mouseover Zoom loading...
179
+ </div>
180
+
181
+ <!-- gallery with thumbs (will be filled with thumbs by javascript) -->
182
+ <div id="az_mouseOverZoomGallery" style="position: relative; margin-top: 20px; height: 76px; width: 100%; display: none;">
183
+ Gellery loading...
184
+ </div>
185
+ </div>
186
+
187
+ <?php echo $this->getChildHtml('after'); ?>
188
+
189
+ <script type="text/javascript">
190
+ <?php
191
+ $exclParArray = array('LICENSE_LIC');
192
+ foreach ($conf as $group => $data){
193
+ foreach ($data as $key => $value){
194
+ $groupKey = strtoupper($group . '_' . $key);
195
+ if (!in_array($groupKey, $exclParArray)){
196
+ if ($value == 'false' || $value == 'true' || $value == 'null' || is_numeric($value) || substr(trim($value), 0, 1) == '{' || substr(trim($value), 0, 1) == '['){
197
+ echo ' var AJAXZOOM_' . $groupKey . ' = ' . $value . '; ' . "\n";
198
+ } else {
199
+ echo ' var AJAXZOOM_' . $groupKey . ' = "' . str_replace('"', '&#34;', $value) . '"; ' . "\n";
200
+ }
201
+ }
202
+ }
203
+ }
204
+ ?>
205
+ var AXZMPATH = '<?php echo $axZmPath; ?>';
206
+
207
+ // colors
208
+ var axAssociated = jQuery.parseJSON('<?php echo Mage::helper('core')->jsonEncode($res); ?>');
209
+
210
+ // default 360
211
+ var IMAGES_360_JSON = <?php echo $images360Json; ?>;
212
+
213
+ // default plain images
214
+ var IMAGES_JSON = {<?php echo implode(',', $imagesJson);?>};
215
+
216
+ var zoomParams = {
217
+ disableAllMsg: AJAXZOOM_MAIN_DISABLEALLMSG,
218
+ axZmPath: AXZMPATH,
219
+ divID: AJAXZOOM_MAIN_DIVID,
220
+ galleryDivID: AJAXZOOM_MAIN_GALLERYDIVID,
221
+ images: IMAGES_JSON,
222
+ firstImageToLoad: AJAXZOOM_MAIN_FIRSTIMAGETOLOAD,
223
+ images360: IMAGES_360_JSON,
224
+ images360firstToLoad: AJAXZOOM_MAIN_IMAGES360FIRSTTOLOAD,
225
+ images360Opt: AJAXZOOM_MAIN_IMAGES360OPT,
226
+ images360Thumb: AJAXZOOM_MAIN_IMAGES360THUMB,
227
+ images360Preview: AJAXZOOM_MAIN_IMAGES360PREVIEW,
228
+ images360examplePreview: AJAXZOOM_MAIN_IMAGES360EXAMPLEPREVIEW,
229
+ zoomMsg360: AJAXZOOM_MAIN_ZOOMMSG360,
230
+ thumbW: AJAXZOOM_MAIN_THUMBW,
231
+ thumbH: AJAXZOOM_MAIN_THUMBH,
232
+ thumbRetina: AJAXZOOM_MAIN_THUMBRETINA,
233
+ galleryAxZmThumbSlider: AJAXZOOM_MAIN_GALLERYAXZMTHUMBSLIDER,
234
+ galleryAxZmThumbSliderParam: AJAXZOOM_MAIN_GALLERYAXZMTHUMBSLIDERPARAM,
235
+ preloadMouseOverImages: AJAXZOOM_MAIN_PRELOADMOUSEOVERIMAGES,
236
+ width: AJAXZOOM_MAIN_WIDTH,
237
+ height: AJAXZOOM_MAIN_HEIGHT,
238
+ responsive: AJAXZOOM_MAIN_RESPONSIVE,
239
+ heightRatio: AJAXZOOM_MAIN_HEIGHTRATIO,
240
+ heightMaxWidthRatio: AJAXZOOM_MAIN_HEIGHTMAXWIDTHRATIO,
241
+ maxSizePrc: AJAXZOOM_MAIN_MAXSIZEPRC,
242
+ mouseOverZoomWidth: AJAXZOOM_MAIN_MOUSEOVERZOOMWIDTH,
243
+ mouseOverZoomHeight: AJAXZOOM_MAIN_MOUSEOVERZOOMHEIGHT,
244
+ ajaxZoomOpenMode: AJAXZOOM_MAIN_AJAXZOOMOPENMODE,
245
+ example: AJAXZOOM_MAIN_EXAMPLE,
246
+ exampleFancyboxFullscreen: AJAXZOOM_MAIN_EXAMPLEFANCYBOXFULLSCREEN,
247
+ exampleFancybox: AJAXZOOM_MAIN_EXAMPLEFANCYBOX,
248
+ exampleColorbox: AJAXZOOM_MAIN_EXAMPLECOLORBOX,
249
+ fancyBoxParam: {
250
+ boxMargin: 0,
251
+ boxPadding: 0,
252
+ boxCenterOnScroll: true,
253
+ boxOverlayShow: true,
254
+ boxOverlayOpacity: 0.75,
255
+ boxOverlayColor: "#777",
256
+ boxTransitionIn: "fade",
257
+ boxTransitionOut: "fade",
258
+ boxSpeedIn: 300,
259
+ boxSpeedOut: 300,
260
+ boxEasingIn: "swing",
261
+ boxEasingOut: "swing",
262
+ boxShowCloseButton: true,
263
+ boxEnableEscapeButton: true,
264
+ boxTitleShow: true,
265
+ boxTitlePosition: "float",
266
+ boxTitleFormat: null
267
+ },
268
+ disableScrollAnm: AJAXZOOM_MAIN_DISABLESCROLLANM,
269
+ fullScreenApi: AJAXZOOM_MAIN_FULLSCREENAPI,
270
+ axZmCallBacks: AJAXZOOM_MAIN_AXZMCALLBACKS,
271
+
272
+ azOptions: AJAXZOOM_MAIN_AZOPTIONS,
273
+ azOptions360: AJAXZOOM_MAIN_AZOPTIONS360,
274
+
275
+ // Experimental
276
+ pinterest: {
277
+ enabled: AJAXZOOM_PINTEREST_ENABLED,
278
+ build: AJAXZOOM_PINTEREST_BUILD,
279
+ btnSrc: AJAXZOOM_PINTEREST_BTNSRC,
280
+ data: { // any data attributes
281
+ "pin-do" : "buttonPin",
282
+ "pin-shape": null,
283
+ "pin-config": "none",
284
+ "pin-color": null,
285
+ "pin-height": null
286
+ }
287
+ },
288
+
289
+ // Mouse hover zoom parameters
290
+ mouseOverZoomParam: {
291
+ position: AJAXZOOM_MOUSEOVERZOOMPARAM_POSITION,
292
+ posAutoInside: AJAXZOOM_MOUSEOVERZOOMPARAM_POSAUTOINSIDE,
293
+ autoFlip: AJAXZOOM_MOUSEOVERZOOMPARAM_AUTOFLIP,
294
+ biggestSpace: AJAXZOOM_MOUSEOVERZOOMPARAM_BIGGESTSPACE,
295
+ zoomFullSpace: AJAXZOOM_MOUSEOVERZOOMPARAM_ZOOMFULLSPACE,
296
+ zoomWidth: AJAXZOOM_MOUSEOVERZOOMPARAM_ZOOMWIDTH,
297
+ zoomHeight: AJAXZOOM_MOUSEOVERZOOMPARAM_ZOOMHEIGHT,
298
+ autoMargin: AJAXZOOM_MOUSEOVERZOOMPARAM_AUTOMARGIN,
299
+ adjustX: AJAXZOOM_MOUSEOVERZOOMPARAM_ADJUSTX,
300
+ adjustY: AJAXZOOM_MOUSEOVERZOOMPARAM_ADJUSTY,
301
+
302
+ lensOpacity: AJAXZOOM_MOUSEOVERZOOMPARAM_LENSOPACITY,
303
+ lensStyle: {},
304
+ lensClass: AJAXZOOM_MOUSEOVERZOOMPARAM_LENSCLASS,
305
+ zoomAreaBorderWidth: AJAXZOOM_MOUSEOVERZOOMPARAM_ZOOMAREABORDERWIDTH,
306
+ galleryFade: AJAXZOOM_MOUSEOVERZOOMPARAM_GALLERYFADE,
307
+ shutterSpeed: AJAXZOOM_MOUSEOVERZOOMPARAM_SHUTTERSPEED,
308
+ showFade: AJAXZOOM_MOUSEOVERZOOMPARAM_SHOWFADE,
309
+ hideFade: AJAXZOOM_MOUSEOVERZOOMPARAM_HIDEFADE,
310
+ autoScroll: AJAXZOOM_MOUSEOVERZOOMPARAM_AUTOSCROLL,
311
+
312
+ flyOutSpeed: AJAXZOOM_MOUSEOVERZOOMPARAM_FLYOUTSPEED,
313
+ flyOutTransition: AJAXZOOM_MOUSEOVERZOOMPARAM_FLYOUTTRANSITION,
314
+ flyOutOpacity: AJAXZOOM_MOUSEOVERZOOMPARAM_FLYOUTOPACITY,
315
+ flyBackSpeed: AJAXZOOM_MOUSEOVERZOOMPARAM_FLYBACKSPEED,
316
+ flyBackTransition: AJAXZOOM_MOUSEOVERZOOMPARAM_FLYBACKTRANSITION,
317
+ flyBackOpacity: AJAXZOOM_MOUSEOVERZOOMPARAM_FLYBACKOPACITY,
318
+
319
+ smoothMove: AJAXZOOM_MOUSEOVERZOOMPARAM_SMOOTHMOVE,
320
+
321
+ tint: AJAXZOOM_MOUSEOVERZOOMPARAM_TINT,
322
+ tintOpacity: AJAXZOOM_MOUSEOVERZOOMPARAM_TINTOPACITY,
323
+ tintFilter: AJAXZOOM_MOUSEOVERZOOMPARAM_TINTFILTER,
324
+ tintLensBack: AJAXZOOM_MOUSEOVERZOOMPARAM_TINTLENSBACK,
325
+
326
+ showTitle: AJAXZOOM_MOUSEOVERZOOMPARAM_SHOWTITLE,
327
+ titleOpacity: AJAXZOOM_MOUSEOVERZOOMPARAM_TITLEOPACITY,
328
+ titlePosition: AJAXZOOM_MOUSEOVERZOOMPARAM_TITLEPOSITION,
329
+ cursorPositionX: AJAXZOOM_MOUSEOVERZOOMPARAM_CURSORPOSITIONX,
330
+ cursorPositionY: AJAXZOOM_MOUSEOVERZOOMPARAM_CURSORPOSITIONY,
331
+ loading: AJAXZOOM_MOUSEOVERZOOMPARAM_LOADING,
332
+ loadingMessage: AJAXZOOM_MOUSEOVERZOOMPARAM_LOADINGMESSAGE,
333
+ loadingWidth: AJAXZOOM_MOUSEOVERZOOMPARAM_LOADINGWIDTH,
334
+ loadingHeight: AJAXZOOM_MOUSEOVERZOOMPARAM_LOADINGHEIGHT,
335
+ loadingOpacity: AJAXZOOM_MOUSEOVERZOOMPARAM_LOADINGOPACITY,
336
+ zoomHintEnable: AJAXZOOM_MOUSEOVERZOOMPARAM_ZOOMHINTENABLE,
337
+ zoomHintText: AJAXZOOM_MOUSEOVERZOOMPARAM_ZOOMHINTTEXT,
338
+ zoomMsgHover: AJAXZOOM_MOUSEOVERZOOMPARAM_ZOOMMSGHOVER,
339
+ zoomMsgClick: AJAXZOOM_MOUSEOVERZOOMPARAM_ZOOMMSGCLICK,
340
+ spinner: AJAXZOOM_MAIN_SPINNER
341
+ }
342
+
343
+ };
344
+
345
+ jQuery.mouseOverZoomInit(zoomParams);
346
+
347
+ jQuery.axZm_psh = { };
348
+ jQuery.axZm_psh.prevPid = null;
349
+ jQuery.axZm_psh.compVersions = function(strV1, strV2) {
350
+ var nRes = 0, parts1 = strV1.split('.'), parts2 = strV2.split('.'), nLen = Math.max(parts1.length, parts2.length);
351
+ for (var i = 0; i < nLen; i++) {
352
+ var nP1 = (i < parts1.length) ? parseInt(parts1[i], 10) : 0, nP2 = (i < parts2.length) ? parseInt(parts2[i], 10) : 0;
353
+ if (isNaN(nP1)) { nP1 = 0; } if (isNaN(nP2)) { nP2 = 0; }
354
+ if (nP1 != nP2) { nRes = (nP1 > nP2) ? 1 : -1; break; }
355
+ }
356
+ return nRes;
357
+ };
358
+
359
+ <?php //if (version_compare(Mage::getVersion(), '1.9.1') >= 0): ?>
360
+
361
+
362
+ // Swatches
363
+ jQuery(function($) {
364
+
365
+ var resetAxZoom = function() {
366
+ $.mouseOverZoomInit.replaceImages( {
367
+ divID: AJAXZOOM_MAIN_DIVID,
368
+ galleryDivID: AJAXZOOM_MAIN_GALLERYDIVID,
369
+ images: IMAGES_JSON,
370
+ images360: IMAGES_360_JSON
371
+ });
372
+ };
373
+
374
+ window.resetAxZoom = resetAxZoom;
375
+
376
+ var updateAxZoom = function(e) {
377
+
378
+ var obj = $(this);
379
+
380
+ setTimeout(function(){
381
+
382
+ if(e.type == 'change' && obj.val() == '') {
383
+ resetAxZoom();
384
+ return;
385
+ }
386
+
387
+ var pairs = [];
388
+ for (var k in spConfig.state){
389
+ if (typeof spConfig.state[k] !== 'function' && typeof spConfig.state[k] !== 'object' && spConfig.state[k] != false) {
390
+ pairs.push(k + ':' + spConfig.state[k]);
391
+ }
392
+ }
393
+ var idx = pairs.join(',');
394
+
395
+ //console.log(idx, axAssociated);
396
+
397
+ if(axAssociated[idx]) {
398
+
399
+ if( ($.isPlainObject(axAssociated[idx].images) && !$.isEmptyObject(axAssociated[idx].images))
400
+ ||
401
+ ($.isPlainObject(axAssociated[idx].images360) && !$.isEmptyObject(axAssociated[idx].images360))
402
+ ) {
403
+ $.mouseOverZoomInit.replaceImages( {
404
+ divID: AJAXZOOM_MAIN_DIVID,
405
+ galleryDivID: AJAXZOOM_MAIN_GALLERYDIVID,
406
+ images: axAssociated[idx].images,
407
+ images360: axAssociated[idx].images360
408
+ });
409
+ } else { // show initial images
410
+ resetAxZoom();
411
+ }
412
+ }
413
+
414
+ }, 100);
415
+
416
+ }
417
+
418
+ $('.swatch-label').click(updateAxZoom); // version 1.9.1 or more
419
+ $('.super-attribute-select').change(updateAxZoom);
420
+ });
421
+
422
+ <?php //endif; ?>
423
+ </script>
app/etc/modules/Ax_Zoom.xml ADDED
@@ -0,0 +1,9 @@
 
 
 
 
 
 
 
 
 
1
+ <?xml version="1.0" ?>
2
+ <config>
3
+ <modules>
4
+ <Ax_Zoom>
5
+ <active>true</active>
6
+ <codePool>local</codePool>
7
+ </Ax_Zoom>
8
+ </modules>
9
+ </config>
app/locale/ru_RU/Ax_Zoom.csv ADDED
@@ -0,0 +1,150 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ Enable / Disable AJAX-ZOOM for this product,Включить/Выключить AJAX-ZOOM для этого товара
2
+ AJAX ZOOM enabled for this product's detail view,AJAX ZOOM включен для страницы просмотра этого товара
3
+ Yes,Да
4
+ No,Нет
5
+ SETTINGS FOR EXISTING 360/3D,НАСТРОЙКИ ДЛЯ СУЩЕСТВУЮЩИХ 360/3D
6
+ 360/3D View,360/3D вид
7
+ Settings,Настройки
8
+ Name,Имя
9
+ Value,Значение
10
+ Add an option,Добавть опцию
11
+ Edit,Редактировать
12
+ Delete,Удалить
13
+ 360/3D Views,360/3D виды
14
+ Add a new 360/3D view,Добавить новый 360/3D вид
15
+ Create a new, Создать новый
16
+ Please enter any name,Пожалуйста введите имя
17
+ OR,ИЛИ
18
+ Add to existing 3D as next row,Добавить к существующемы 3D следющей строкой
19
+ Select,Выбрать
20
+ You should not select anything here unless you want to create 3D (not 360) which contains more than one row!,
21
+ Add images from ZIP archive,Добавить изображения из ZIP архива
22
+ This is the most easy and quick way of adding 360 views to your product! Upload over FTP your 360's zipped (each images set in one zip file) to /modules/ajaxzoom/zip/ directory. After you did so these zip files will instantly appear in the select field below. All you have to do then is select one of the zip files and press 'add' button. Images from the selected zip file will be instantly imported.,Это самый простой способ добавления 3D/360 видов для вашего товара! Upload over FTP your 360's zipped (each images set in one zip file) to /modules/ajaxzoom/zip/ directory. After you did so these zip files will instantly appear in the select field below. All you have to do then is select one of the zip files and press 'add' button. Images from the selected zip file will be instantly imported.
23
+ Select ZIP archive,Выберите ZIP архив
24
+ Add,Добавить
25
+ Cover Image,Основное изображение
26
+ Active,Активно
27
+ Actions,Действия
28
+ Delete,Удалить
29
+ Images,Изображения
30
+ Preview,Просмотр
31
+ Are you sure?,Вы уверены?
32
+ Add a new image to this image set,Добавить новое изображение к этому набору
33
+ Image,Изображение
34
+ Delete this image,Удалить изображение
35
+ Cancel,Отменить
36
+ Add files...,Добавить фалы...
37
+ Upload files,Загрузить файлы
38
+ License,Лицензия
39
+ Domain,Домен
40
+ License Type,Тип лицензии
41
+ License Key,Лицензионный ключ
42
+ Error200,Ошибка200
43
+ Error300, Ошибка300
44
+ Licenses,Лицензии
45
+ General Settings,Основные настройки
46
+ Settings for pinterest button,Настройки для кнопки Pinterest,
47
+ mouseOverZoomParam - JS object containing specific options to this mouseover zoom,mouseOverZoomParam - JS object containing specific options to this mouseover zoom
48
+ "DIV (container) ID for mouseover zoom","DIV (container) ID for mouseover zoom"
49
+ "DIV (container) id of the gallery, set to false to disable gallery","DIV (container) id of the gallery, set to false to disable gallery"
50
+ some...,описание...
51
+ "Instantly hide gallery if there is only one image or one 360/3D","Instantly hide gallery if there is only one image or one 360/3D"
52
+ "Use mouseenter (mouseover) for switching between images. You can specify an integer which will represent the time in ms to wait for switching after the mouse enters the thumb; true defaults to 200","Use mouseenter (mouseover) for switching between images. You can specify an integer which will represent the time in ms to wait for switching after the mouse enters the thumb; true defaults to 200"
53
+ "Use $.axZmThumbSlider on gallery thumbnails or not","Use $.axZmThumbSlider on gallery thumbnails or not"
54
+ "<p class=""preference_description"">$.axZmThumbSlider parametrs if ""galleryAxZmThumbSlider"" is enabled; for full list of options see under: <a href=""/modules/ajaxzoom/axZm/extensions/axZmThumbSlider/"" target=""_blank"">/modules/ajaxzoom/axZm/extensions/axZmThumbSlider/</a> or <a href=""http://www.ajax-zoom.com/axZm/extensions/axZmThumbSlider/"" target=""_blank"">http://www.ajax-zoom.com/axZm/extensions/axZmThumbSlider/</a></p>","<p class=""preference_description"">$.axZmThumbSlider parametrs if ""galleryAxZmThumbSlider"" is enabled; for full list of options see under: <a href=""/modules/ajaxzoom/axZm/extensions/axZmThumbSlider/"" target=""_blank"">/modules/ajaxzoom/axZm/extensions/axZmThumbSlider/</a> or <a href=""http://www.ajax-zoom.com/axZm/extensions/axZmThumbSlider/"" target=""_blank"">http://www.ajax-zoom.com/axZm/extensions/axZmThumbSlider/</a></p>"
55
+ "Gallery thumb widthGallery thumb height","Gallery thumb widthGallery thumb height"
56
+ "Double resolution of the thumb image","Double resolution of the thumb image"
57
+ "Image from ""images"" option which should be loaded at first; see also ""images360firstToLoad"" option below","Image from ""images"" option which should be loaded at first; see also ""images360firstToLoad"" option below"
58
+ "In case present load 360 from ""images360"" first and not an image from ""images""","In case present load 360 from ""images360"" first and not an image from ""images"""
59
+ "Some (not all) options from '/axZm/zoomConfig.inc.php' and '/axZm/zoomConfigCustom.inc.php' can be set during runtime or in 'onBeforeStart' AJAX-ZOOM callback. ""images360Opt"" is a list of what possibly could be set in ""images360"" objects, e.g. ['spinReverseZ', 'spinWhilePreload'] and so on. Default is: ['spinReverse', 'spinReverseZ', 'spinBounce', 'spinDemoRounds', 'spinDemoTime', 'spinWhilePreload']","Some (not all) options from '/axZm/zoomConfig.inc.php' and '/axZm/zoomConfigCustom.inc.php' can be set during runtime or in 'onBeforeStart' AJAX-ZOOM callback. ""images360Opt"" is a list of what possibly could be set in ""images360"" objects, e.g. ['spinReverseZ', 'spinWhilePreload'] and so on. Default is: ['spinReverse', 'spinReverseZ', 'spinBounce', 'spinDemoRounds', 'spinDemoTime', 'spinWhilePreload']"
60
+ "Show first image of the spin as thumb","Show first image of the spin as thumb"
61
+ "Normally plain images are opened in some kind of lightbox or fullscreen; By setting this option to true the 360's will load into ""divID"" at first and can be expanded to fullscreen.","Normally plain images are opened in some kind of lightbox or fullscreen; By setting this option to true the 360's will load into ""divID"" at first and can be expanded to fullscreen."
62
+ "This option is set to true for convinience reasons; In case your ""divID"" has fixed width and height, set $zoom['config']['picDim'] option in '/axZm/zoomConfigCustom.inc.php' after elseif ($_GET['example'] == 'mouseOverExtension360')","This option is set to true for convinience reasons; In case your ""divID"" has fixed width and height, set $zoom['config']['picDim'] option in '/axZm/zoomConfigCustom.inc.php' after elseif ($_GET['example'] == 'mouseOverExtension360')"
63
+ "In case ""images360Preview"" is set to true, the value of this parameter will be sent to AJAX-ZOOM as ""options set"" (example=mouseOverExtension360)","In case ""images360Preview"" is set to true, the value of this parameter will be sent to AJAX-ZOOM as ""options set"" (example=mouseOverExtension360)"
64
+ "Message displayed under mouse over zoom when 360 is loaded, e.g. ""Drag to spin 360, scroll to zoom""","Message displayed under mouse over zoom when 360 is loaded, e.g. ""Drag to spin 360, scroll to zoom"""
65
+ "Preload all preview and mouseover images, possible values: false, true, 'oneByOne'","Preload all preview and mouseover images, possible values: false, true, 'oneByOne'"
66
+ "In case there are no images in ""images"", nor there are any in ""images360"", a div with some image as background can be appended to the container and receive this options value as css class","In case there are no images in ""images"", nor there are any in ""images360"", a div with some image as background can be appended to the container and receive this options value as css class"
67
+ "Width of the preview image or 'auto' (depending on parent container size - ""divID"", see above); this is also the value which will be passed to your AJAX-ZOOM imaging server to generate this image on-the-fly.","Width of the preview image or 'auto' (depending on parent container size - ""divID"", see above); this is also the value which will be passed to your AJAX-ZOOM imaging server to generate this image on-the-fly."
68
+ "Height of the preview image or 'auto' (depending on parent container size - ""divID"", see above); this is also the value which will be passed to your AJAX-ZOOM imaging server to generate this image on-the-fly.","Height of the preview image or 'auto' (depending on parent container size - ""divID"", see above); this is also the value which will be passed to your AJAX-ZOOM imaging server to generate this image on-the-fly."
69
+ "Set this to true for responsive layouts","Set this to true for responsive layouts"
70
+ "Use single image as ""preview image"" - the image which is hovered and the big ""flyout image"".","Use single image as ""preview image"" - the image which is hovered and the big ""flyout image""."
71
+ "If ""responsive"" option is enabled, ""heightRatio"" with instantly adjust the height of mouseover container depending on width calculated by the browser, e.g. 1.0 will always (only limited by ""maxSizePrc"" option) make height same as width; a value of 1.5 will make the preview like a portrait. You can also set ""heightRatio"" to 'auto'. In this case the height will be adjusted to cover available space instantly! Please note that when your images are not always same proportion, then the container will also change the size when the user switches to a different image.","If ""responsive"" option is enabled, ""heightRatio"" with instantly adjust the height of mouseover container depending on width calculated by the browser, e.g. 1.0 will always (only limited by ""maxSizePrc"" option) make height same as width; a value of 1.5 will make the preview like a portrait. You can also set ""heightRatio"" to 'auto'. In this case the height will be adjusted to cover available space instantly! Please note that when your images are not always same proportion, then the container will also change the size when the user switches to a different image."
72
+ "Similar as you would set max-width: someValue @media only screen condition you can define ""heightRatio"" depending on the width of the browser, e.g. [""960|0.8"", ""700|0.7""]","Similar as you would set max-width: someValue @media only screen condition you can define ""heightRatio"" depending on the width of the browser, e.g. [""960|0.8"", ""700|0.7""]"
73
+ "Oposit of ""heightRatio""","Oposit of ""heightRatio"""
74
+ "Oposit of ""heightMaxWidthRatio""","Oposit of ""heightMaxWidthRatio"""
75
+ "Limit the height if ""responsive"" and ""heightRatio"" options are set. Setting ""heightRatio"" option may result in that the height of the mouseover zoom is bigger than window height and the image is not fully visible. To prevent this you can limit the calculated height with this ""maxSizePrc"" option. The value of 1.0 would limit the height to 100% of window height; a value of 0.8 to 80% of window height; you can also define two values, e.g. '1.0|-120' which would be window height minus 120px.","Limit the height if ""responsive"" and ""heightRatio"" options are set. Setting ""heightRatio"" option may result in that the height of the mouseover zoom is bigger than window height and the image is not fully visible. To prevent this you can limit the calculated height with this ""maxSizePrc"" option. The value of 1.0 would limit the height to 100% of window height; a value of 0.8 to 80% of window height; you can also define two values, e.g. '1.0|-120' which would be window height minus 120px."
76
+ "Max width of the image that will be shown in the zoom window; this is the value which will be passed to your AJAX-ZOOM imaging server to generate this image on-the-fly. Please note that the size is limited by $zoom['config']['allowDynamicThumbsMaxSize'] which is can be set in '/axZm/zoomConfig.inc.php'. You can also specify a link to the image, see ""images"" option above. To set the width of the fly out window see ""zoomWidth"" under ""mouseOverZoomParam"".","Max width of the image that will be shown in the zoom window; this is the value which will be passed to your AJAX-ZOOM imaging server to generate this image on-the-fly. Please note that the size is limited by $zoom['config']['allowDynamicThumbsMaxSize'] which is can be set in '/axZm/zoomConfig.inc.php'. You can also specify a link to the image, see ""images"" option above. To set the width of the fly out window see ""zoomWidth"" under ""mouseOverZoomParam""."
77
+ "Max height of the image that will be shown in the zoom window; this is the value which will be passed to your AJAX-ZOOM imaging server to generate this image on-the-fly. Please note that the size is limited by $zoom['config']['allowDynamicThumbsMaxSize'] which is can be set in '/axZm/zoomConfig.inc.php'. You can also specify a link to the image, see ""images"" option above. To set the height of the fly out window see ""zoomHeight"" under ""mouseOverZoomParam"".","Max height of the image that will be shown in the zoom window; this is the value which will be passed to your AJAX-ZOOM imaging server to generate this image on-the-fly. Please note that the size is limited by $zoom['config']['allowDynamicThumbsMaxSize'] which is can be set in '/axZm/zoomConfig.inc.php'. You can also specify a link to the image, see ""images"" option above. To set the height of the fly out window see ""zoomHeight"" under ""mouseOverZoomParam""."
78
+ "Determines how AJAX-ZOOM is opened when the user clicks on preview images / lens, possible values: 'fullscreen' (see also ""fullScreenApi"" option below), 'fancyboxFullscreen', 'fancybox', 'colorbox'; By editing $.mouseOverZoomInit you can extend the plugin to be used with different types of modal boxes to load AJAX-ZOOM into.","Determines how AJAX-ZOOM is opened when the user clicks on preview images / lens, possible values: 'fullscreen' (see also ""fullScreenApi"" option below), 'fancyboxFullscreen', 'fancybox', 'colorbox'; By editing $.mouseOverZoomInit you can extend the plugin to be used with different types of modal boxes to load AJAX-ZOOM into."
79
+ "If fancybox is used in ""ajaxZoomOpenMode"" option, Fancybox options","If fancybox is used in ""ajaxZoomOpenMode"" option, Fancybox options"
80
+ "If colorbox is used in ""ajaxZoomOpenMode"" option, Colorbox options","If colorbox is used in ""ajaxZoomOpenMode"" option, Colorbox options"
81
+ "Configuration set which is passed to ajax-zoom when ajaxZoomOpenMode is 'fullscreen'","Configuration set which is passed to ajax-zoom when ajaxZoomOpenMode is 'fullscreen'"
82
+ "Configuration set which is passed to ajax-zoom when ajaxZoomOpenMode is 'fancyboxFullscreen'","Configuration set which is passed to ajax-zoom when ajaxZoomOpenMode is 'fancyboxFullscreen'"
83
+ "Configuration set which is passed to ajax-zoom when ajaxZoomOpenMode is 'fancybox'","Configuration set which is passed to ajax-zoom when ajaxZoomOpenMode is 'fancybox'"
84
+ "Configuration set which is passed to ajax-zoom when ajaxZoomOpenMode is 'colorbox'","Configuration set which is passed to ajax-zoom when ajaxZoomOpenMode is 'colorbox'"
85
+ "Disable animation while zooming with AJAX-ZOOM","Disable animation while zooming with AJAX-ZOOM"
86
+ "Try to open AJAX-ZOOM at browsers fullscreen mode, possible on modern browsers except IE &lt; 10 and mobile","Try to open AJAX-ZOOM at browsers fullscreen mode, possible on modern browsers except IE &lt; 10 and mobile"
87
+ "AJAX-ZOOM has several callbacks, http://www.ajax-zoom.com/index.php?cid=docs#onBeforeStart","AJAX-ZOOM has several callbacks, http://www.ajax-zoom.com/index.php?cid=docs#onBeforeStart"
88
+ "Jpeg quality of the gallery thumbs","Jpeg quality of the gallery thumbs"
89
+ "Jpeg quality of the preview image","Jpeg quality of the preview image"
90
+ "Jpeg quality of the zoom image shown in the flyout window","Jpeg quality of the zoom image shown in the flyout window"
91
+ "Callback function","Callback function"
92
+ "Use ajax loading spinner without gif files etc","Use ajax loading spinner without gif files etc"
93
+ "Spinner options, for more info see: http://fgnass.github.com/spin.js/","Spinner options, for more info see: http://fgnass.github.com/spin.js/"
94
+ "Experimental feature - enable Pinterest button. Pinterest allows to collect visual bookmarks in the form of images collected on the internet.","Experimental feature - enable Pinterest button. Pinterest allows to collect visual bookmarks in the form of images collected on the internet."
95
+ "Since images are changed the button needs to be repainted [...] In order to accomplish this the Pinterest API should be exposed to window object. This is done by setting data-pin-build attribute value in the script tag when pinterest JavaScript is included. &lt;script data-pin-build=""parsePinBtns"" type=""text/javascript"" src=""//assets.pinterest.com/js/pinit.js""&gt;&lt;/script&gt; So if you do not have the data-pin-build, please add it to the script tag and if it is different from default ('parsePinBtns'), then change this ""build"" value. Otherwise the pinterest button will not work.","Since images are changed the button needs to be repainted [...] In order to accomplish this the Pinterest API should be exposed to window object. This is done by setting data-pin-build attribute value in the script tag when pinterest JavaScript is included. &lt;script data-pin-build=""parsePinBtns"" type=""text/javascript"" src=""//assets.pinterest.com/js/pinit.js""&gt;&lt;/script&gt; So if you do not have the data-pin-build, please add it to the script tag and if it is different from default ('parsePinBtns'), then change this ""build"" value. Otherwise the pinterest button will not work."
96
+ "This is the class of the container where the button will be put into. On default it is at bottom right. To place the button somewhere else you can either change the css of the default class or define a different class.","This is the class of the container where the button will be put into. On default it is at bottom right. To place the button somewhere else you can either change the css of the default class or define a different class."
97
+ "href attribute before the button is build.","href attribute before the button is build."
98
+ "Page title if null","Page title if null"
99
+ "Will be set instantly if null","Will be set instantly if null"
100
+ "Will be set to current selected image if null","Will be set to current selected image if null"
101
+ "Source for the button","Source for the button"
102
+ "Data attributes attached to the button before it is built. See pinterest API...","Data attributes attached to the button before it is built. See pinterest API..."
103
+ "Position of the flyout zoom window, possible values: 'inside', 'top', 'right', 'bottom', 'left'","Position of the flyout zoom window, possible values: 'inside', 'top', 'right', 'bottom', 'left'"
104
+ "applies when width (left, right) or height (top, bottom) of zoom window are less than this px value (zoomWidth || zoomHeight are set to auto); if zoomWidth || zoomHeight are fixed, applies when zoom window is out of page border","applies when width (left, right) or height (top, bottom) of zoom window are less than this px value (zoomWidth || zoomHeight are set to auto); if zoomWidth || zoomHeight are fixed, applies when zoom window is out of page border"
105
+ "When ""posAutoInside"" is enabled and inner zoom fires or ""position"" option is set to 'inside' right away - there is no lens. However you will notice that the reaction to mouse movements occure somewhere in the middle of the image; at the edges mostly nothing happens in simmilar scripts. With this option you can adjust how far from the edge mouse movements should be captured. The range is between 0 and 0.5;","When ""posAutoInside"" is enabled and inner zoom fires or ""position"" option is set to 'inside' right away - there is no lens. However you will notice that the reaction to mouse movements occure somewhere in the middle of the image; at the edges mostly nothing happens in simmilar scripts. With this option you can adjust how far from the edge mouse movements should be captured. The range is between 0 and 0.5;"
106
+ "Flip right to left and bottom to top if less than int px value or false to disable","Flip right to left and bottom to top if less than int px value or false to disable"
107
+ "Overrides position option and instantly chooses the direction, disables autoFlip; playes nicely when zoomWidth and zoomHeight are set to 'auto'","Overrides position option and instantly chooses the direction, disables autoFlip; playes nicely when zoomWidth and zoomHeight are set to 'auto'"
108
+ "Uses full screen height (does not align to the map / disables adjustY) if position is right or left || uses full screen width (does not align to the map / disables adjustX) if position is top or bottom","Uses full screen height (does not align to the map / disables adjustY) if position is right or left || uses full screen width (does not align to the map / disables adjustX) if position is top or bottom"
109
+ "Width of the zoom window e.g. 540 or 'auto' or jQuery selector|correction value, e.g. '#refWidthTest|+20'; so if you want to have a width of the zoom window same as for example a responsive container to the right (so it is fully covered) and max possible height, then define the id of this container to the right, e.g. 'myArticleData', set ""zoomWidth"" to '#myArticleData|+10' and ""zoomHeight"" to 'auto'. New in Ver. b4: if you have a three column design and want to cover both containers to the right, then just define both containers in the jQuery selector, e.g. '.pb-center-column,.pb-right-column|+20'; the margin between the containers is not taken into account but you can adjust the result with the second value after vertical bar.","Width of the zoom window e.g. 540 or 'auto' or jQuery selector|correction value, e.g. '#refWidthTest|+20'; so if you want to have a width of the zoom window same as for example a responsive container to the right (so it is fully covered) and max possible height, then define the id of this container to the right, e.g. 'myArticleData', set ""zoomWidth"" to '#myArticleData|+10' and ""zoomHeight"" to 'auto'. New in Ver. b4: if you have a three column design and want to cover both containers to the right, then just define both containers in the jQuery selector, e.g. '.pb-center-column,.pb-right-column|+20'; the margin between the containers is not taken into account but you can adjust the result with the second value after vertical bar."
110
+ "Height of the zoom window e.g. 375, or 'auto' or jQuery selector|correction value, e.g. '#refWidthTest|+20'","Height of the zoom window e.g. 375, or 'auto' or jQuery selector|correction value, e.g. '#refWidthTest|+20'"
111
+ "If zoomWidth or zoomHeight are set to 'auto', the margin to the edge of the screen","If zoomWidth or zoomHeight are set to 'auto', the margin to the edge of the screen"
112
+ "Horizontal margin of the zoom window","Horizontal margin of the zoom window"
113
+ "Vertical margin of the zoom window","Vertical margin of the zoom window"
114
+ "Opacity of the selector lens","Opacity of the selector lens"
115
+ "Quickly override css of the lens","Quickly override css of the lens"
116
+ "Set css class for the lens","Set css class for the lens"
117
+ "Border thickness of the zoom window","Border thickness of the zoom window"
118
+ "Speed of inner fade or false","Speed of inner fade or false"
119
+ "Speed of shutter fadein or false; applies only if image proportions are different from container","Speed of shutter fadein or false; applies only if image proportions are different from container"
120
+ "Speed of fade in for mouse over","Speed of fade in for mouse over"
121
+ "Speed of fade out for mouse over","Speed of fade out for mouse over"
122
+ "Speed for flyout or false to disable","Speed for flyout or false to disable"
123
+ "Transition of the flyout","Transition of the flyout"
124
+ "Initial opacity for flyout","Initial opacity for flyout"
125
+ "Speed for fly back or false to disable","Speed for fly back or false to disable"
126
+ "Transition type of the fly back","Transition type of the fly back"
127
+ "Final opacity of fly back","Final opacity of fly back"
128
+ "Scroll page when clicked on the thumb and the mouse over preview image is not fully visible","Scroll page when clicked on the thumb and the mouse over preview image is not fully visible"
129
+ "Integer bigger than 1 indicates smoother movements; set 0 to disable","Integer bigger than 1 indicates smoother movements; set 0 to disable"
130
+ "Color value around the lens or false","Color value around the lens or false"
131
+ "Opacity of the area around the lens when ""tint"" option is set to some color value","Opacity of the area around the lens when ""tint"" option is set to some color value"
132
+ "Apply filter to the image, e.g. ""blur"", ""grayscale"", ""sepia"", ""invert"", ""saturate""; see also .axZm_mouseOverEffect>img CSS","Apply filter to the image, e.g. ""blur"", ""grayscale"", ""sepia"", ""invert"", ""saturate""; see also .axZm_mouseOverEffect>img CSS"
133
+ "Show background image in the lens","Show background image in the lens"
134
+ "Enable / disable title on zoom window","Enable / disable title on zoom window"
135
+ "Opacity of the title container","Opacity of the title container"
136
+ "Position of the title, top or bottom","Position of the title, top or bottom"
137
+ "Cursor over lens horizontal offset, 0.5 is middle","Cursor over lens horizontal offset, 0.5 is middle"
138
+ "Cursor over lens vertical offset, 0.5 is middle","Cursor over lens vertical offset, 0.5 is middle"
139
+ "Time in ms after which click is aborted without touch movement and mousehover is initialized","Time in ms after which click is aborted without touch movement and mousehover is initialized"
140
+ "Display loading information, CSS .mouseOverLoading","Display loading information, CSS .mouseOverLoading"
141
+ "Loading message, not needed, can be just the spinner - see below","Loading message, not needed, can be just the spinner - see below"
142
+ "Width of loading container","Width of loading container"
143
+ "Height of loading container","Height of loading container"
144
+ "Opacity of the loading container (the transparent background is set via png image on default, see css class)","Opacity of the loading container (the transparent background is set via png image on default, see css class)"
145
+ "Enable zoom icon which disappears on mouse hover; css class: .axZm_mouseOverZoomHint; If you want to change the position or the icon simply change the css class;","Enable zoom icon which disappears on mouse hover; css class: .axZm_mouseOverZoomHint; If you want to change the position or the icon simply change the css class;"
146
+ "Text which will be appended next to the icon enabled by ""zoomHintEnable""","Text which will be appended next to the icon enabled by ""zoomHintEnable"""
147
+ "Message which can appear under the mouse over zoom, css class: .axZm_mouseOverZoomMsg","Message which can appear under the mouse over zoom, css class: .axZm_mouseOverZoomMsg"
148
+ "Message which can appear under the mouse over zoom when the mouse enters it.","Message which can appear under the mouse over zoom when the mouse enters it."
149
+ "DISPLAY ONLY IN THESE PRODUCTS","Показывать AJAX ZOOM только для укзанных продуктов"
150
+ "CSV with product IDs for which AJAX-ZOOM will be only enabled. Leave blank to have it enabled for all products! This option can be usefull e.g. if you want to make A/B tests and enable AJAX-ZOOM only for certain products, e.g. 7,15 would enable AJAX-ZOOM only for products with ID 7 and 15","CSV with product IDs for which AJAX-ZOOM will be only enabled. Leave blank to have it enabled for all products! This option can be usefull e.g. if you want to make A/B tests and enable AJAX-ZOOM only for certain products, e.g. 7,15 would enable AJAX-ZOOM only for products with ID 7 and 15"
js/axzoom/.htaccess ADDED
@@ -0,0 +1 @@
 
1
+ php_value session.name frontend
js/axzoom/check_jquery.js ADDED
@@ -0,0 +1,4 @@
 
 
 
 
1
+ if ( (typeof jQuery === 'undefined') && !window.jQuery ) {
2
+ document.write(unescape("%3Cscript type='text/javascript' src='//ajax.googleapis.com/ajax/libs/jquery/1.8.2/jquery.min.js'%3E%3C/script%3E"));
3
+ document.write(unescape("%3Cscript type='text/javascript' %3EjQuery.noConflict();%3C/script%3E"));
4
+ }
js/axzoom/image_path.gif ADDED
Binary file
js/axzoom/jquery-1.11.0.min.js ADDED
@@ -0,0 +1,6 @@
 
 
 
 
 
 
1
+ /*! jQuery v1.11.0 | (c) 2005, 2014 jQuery Foundation, Inc. | jquery.org/license */
2
+ !function(a,b){"object"==typeof module&&"object"==typeof module.exports?module.exports=a.document?b(a,!0):function(a){if(!a.document)throw new Error("jQuery requires a window with a document");return b(a)}:b(a)}("undefined"!=typeof window?window:this,function(a,b){var c=[],d=c.slice,e=c.concat,f=c.push,g=c.indexOf,h={},i=h.toString,j=h.hasOwnProperty,k="".trim,l={},m="1.11.0",n=function(a,b){return new n.fn.init(a,b)},o=/^[\s\uFEFF\xA0]+|[\s\uFEFF\xA0]+$/g,p=/^-ms-/,q=/-([\da-z])/gi,r=function(a,b){return b.toUpperCase()};n.fn=n.prototype={jquery:m,constructor:n,selector:"",length:0,toArray:function(){return d.call(this)},get:function(a){return null!=a?0>a?this[a+this.length]:this[a]:d.call(this)},pushStack:function(a){var b=n.merge(this.constructor(),a);return b.prevObject=this,b.context=this.context,b},each:function(a,b){return n.each(this,a,b)},map:function(a){return this.pushStack(n.map(this,function(b,c){return a.call(b,c,b)}))},slice:function(){return this.pushStack(d.apply(this,arguments))},first:function(){return this.eq(0)},last:function(){return this.eq(-1)},eq:function(a){var b=this.length,c=+a+(0>a?b:0);return this.pushStack(c>=0&&b>c?[this[c]]:[])},end:function(){return this.prevObject||this.constructor(null)},push:f,sort:c.sort,splice:c.splice},n.extend=n.fn.extend=function(){var a,b,c,d,e,f,g=arguments[0]||{},h=1,i=arguments.length,j=!1;for("boolean"==typeof g&&(j=g,g=arguments[h]||{},h++),"object"==typeof g||n.isFunction(g)||(g={}),h===i&&(g=this,h--);i>h;h++)if(null!=(e=arguments[h]))for(d in e)a=g[d],c=e[d],g!==c&&(j&&c&&(n.isPlainObject(c)||(b=n.isArray(c)))?(b?(b=!1,f=a&&n.isArray(a)?a:[]):f=a&&n.isPlainObject(a)?a:{},g[d]=n.extend(j,f,c)):void 0!==c&&(g[d]=c));return g},n.extend({expando:"jQuery"+(m+Math.random()).replace(/\D/g,""),isReady:!0,error:function(a){throw new Error(a)},noop:function(){},isFunction:function(a){return"function"===n.type(a)},isArray:Array.isArray||function(a){return"array"===n.type(a)},isWindow:function(a){return null!=a&&a==a.window},isNumeric:function(a){return a-parseFloat(a)>=0},isEmptyObject:function(a){var b;for(b in a)return!1;return!0},isPlainObject:function(a){var b;if(!a||"object"!==n.type(a)||a.nodeType||n.isWindow(a))return!1;try{if(a.constructor&&!j.call(a,"constructor")&&!j.call(a.constructor.prototype,"isPrototypeOf"))return!1}catch(c){return!1}if(l.ownLast)for(b in a)return j.call(a,b);for(b in a);return void 0===b||j.call(a,b)},type:function(a){return null==a?a+"":"object"==typeof a||"function"==typeof a?h[i.call(a)]||"object":typeof a},globalEval:function(b){b&&n.trim(b)&&(a.execScript||function(b){a.eval.call(a,b)})(b)},camelCase:function(a){return a.replace(p,"ms-").replace(q,r)},nodeName:function(a,b){return a.nodeName&&a.nodeName.toLowerCase()===b.toLowerCase()},each:function(a,b,c){var d,e=0,f=a.length,g=s(a);if(c){if(g){for(;f>e;e++)if(d=b.apply(a[e],c),d===!1)break}else for(e in a)if(d=b.apply(a[e],c),d===!1)break}else if(g){for(;f>e;e++)if(d=b.call(a[e],e,a[e]),d===!1)break}else for(e in a)if(d=b.call(a[e],e,a[e]),d===!1)break;return a},trim:k&&!k.call("\ufeff\xa0")?function(a){return null==a?"":k.call(a)}:function(a){return null==a?"":(a+"").replace(o,"")},makeArray:function(a,b){var c=b||[];return null!=a&&(s(Object(a))?n.merge(c,"string"==typeof a?[a]:a):f.call(c,a)),c},inArray:function(a,b,c){var d;if(b){if(g)return g.call(b,a,c);for(d=b.length,c=c?0>c?Math.max(0,d+c):c:0;d>c;c++)if(c in b&&b[c]===a)return c}return-1},merge:function(a,b){var c=+b.length,d=0,e=a.length;while(c>d)a[e++]=b[d++];if(c!==c)while(void 0!==b[d])a[e++]=b[d++];return a.length=e,a},grep:function(a,b,c){for(var d,e=[],f=0,g=a.length,h=!c;g>f;f++)d=!b(a[f],f),d!==h&&e.push(a[f]);return e},map:function(a,b,c){var d,f=0,g=a.length,h=s(a),i=[];if(h)for(;g>f;f++)d=b(a[f],f,c),null!=d&&i.push(d);else for(f in a)d=b(a[f],f,c),null!=d&&i.push(d);return e.apply([],i)},guid:1,proxy:function(a,b){var c,e,f;return"string"==typeof b&&(f=a[b],b=a,a=f),n.isFunction(a)?(c=d.call(arguments,2),e=function(){return a.apply(b||this,c.concat(d.call(arguments)))},e.guid=a.guid=a.guid||n.guid++,e):void 0},now:function(){return+new Date},support:l}),n.each("Boolean Number String Function Array Date RegExp Object Error".split(" "),function(a,b){h["[object "+b+"]"]=b.toLowerCase()});function s(a){var b=a.length,c=n.type(a);return"function"===c||n.isWindow(a)?!1:1===a.nodeType&&b?!0:"array"===c||0===b||"number"==typeof b&&b>0&&b-1 in a}var t=function(a){var b,c,d,e,f,g,h,i,j,k,l,m,n,o,p,q,r,s="sizzle"+-new Date,t=a.document,u=0,v=0,w=eb(),x=eb(),y=eb(),z=function(a,b){return a===b&&(j=!0),0},A="undefined",B=1<<31,C={}.hasOwnProperty,D=[],E=D.pop,F=D.push,G=D.push,H=D.slice,I=D.indexOf||function(a){for(var b=0,c=this.length;c>b;b++)if(this[b]===a)return b;return-1},J="checked|selected|async|autofocus|autoplay|controls|defer|disabled|hidden|ismap|loop|multiple|open|readonly|required|scoped",K="[\\x20\\t\\r\\n\\f]",L="(?:\\\\.|[\\w-]|[^\\x00-\\xa0])+",M=L.replace("w","w#"),N="\\["+K+"*("+L+")"+K+"*(?:([*^$|!~]?=)"+K+"*(?:(['\"])((?:\\\\.|[^\\\\])*?)\\3|("+M+")|)|)"+K+"*\\]",O=":("+L+")(?:\\(((['\"])((?:\\\\.|[^\\\\])*?)\\3|((?:\\\\.|[^\\\\()[\\]]|"+N.replace(3,8)+")*)|.*)\\)|)",P=new RegExp("^"+K+"+|((?:^|[^\\\\])(?:\\\\.)*)"+K+"+$","g"),Q=new RegExp("^"+K+"*,"+K+"*"),R=new RegExp("^"+K+"*([>+~]|"+K+")"+K+"*"),S=new RegExp("="+K+"*([^\\]'\"]*?)"+K+"*\\]","g"),T=new RegExp(O),U=new RegExp("^"+M+"$"),V={ID:new RegExp("^#("+L+")"),CLASS:new RegExp("^\\.("+L+")"),TAG:new RegExp("^("+L.replace("w","w*")+")"),ATTR:new RegExp("^"+N),PSEUDO:new RegExp("^"+O),CHILD:new RegExp("^:(only|first|last|nth|nth-last)-(child|of-type)(?:\\("+K+"*(even|odd|(([+-]|)(\\d*)n|)"+K+"*(?:([+-]|)"+K+"*(\\d+)|))"+K+"*\\)|)","i"),bool:new RegExp("^(?:"+J+")$","i"),needsContext:new RegExp("^"+K+"*[>+~]|:(even|odd|eq|gt|lt|nth|first|last)(?:\\("+K+"*((?:-\\d)?\\d*)"+K+"*\\)|)(?=[^-]|$)","i")},W=/^(?:input|select|textarea|button)$/i,X=/^h\d$/i,Y=/^[^{]+\{\s*\[native \w/,Z=/^(?:#([\w-]+)|(\w+)|\.([\w-]+))$/,$=/[+~]/,_=/'|\\/g,ab=new RegExp("\\\\([\\da-f]{1,6}"+K+"?|("+K+")|.)","ig"),bb=function(a,b,c){var d="0x"+b-65536;return d!==d||c?b:0>d?String.fromCharCode(d+65536):String.fromCharCode(d>>10|55296,1023&d|56320)};try{G.apply(D=H.call(t.childNodes),t.childNodes),D[t.childNodes.length].nodeType}catch(cb){G={apply:D.length?function(a,b){F.apply(a,H.call(b))}:function(a,b){var c=a.length,d=0;while(a[c++]=b[d++]);a.length=c-1}}}function db(a,b,d,e){var f,g,h,i,j,m,p,q,u,v;if((b?b.ownerDocument||b:t)!==l&&k(b),b=b||l,d=d||[],!a||"string"!=typeof a)return d;if(1!==(i=b.nodeType)&&9!==i)return[];if(n&&!e){if(f=Z.exec(a))if(h=f[1]){if(9===i){if(g=b.getElementById(h),!g||!g.parentNode)return d;if(g.id===h)return d.push(g),d}else if(b.ownerDocument&&(g=b.ownerDocument.getElementById(h))&&r(b,g)&&g.id===h)return d.push(g),d}else{if(f[2])return G.apply(d,b.getElementsByTagName(a)),d;if((h=f[3])&&c.getElementsByClassName&&b.getElementsByClassName)return G.apply(d,b.getElementsByClassName(h)),d}if(c.qsa&&(!o||!o.test(a))){if(q=p=s,u=b,v=9===i&&a,1===i&&"object"!==b.nodeName.toLowerCase()){m=ob(a),(p=b.getAttribute("id"))?q=p.replace(_,"\\$&"):b.setAttribute("id",q),q="[id='"+q+"'] ",j=m.length;while(j--)m[j]=q+pb(m[j]);u=$.test(a)&&mb(b.parentNode)||b,v=m.join(",")}if(v)try{return G.apply(d,u.querySelectorAll(v)),d}catch(w){}finally{p||b.removeAttribute("id")}}}return xb(a.replace(P,"$1"),b,d,e)}function eb(){var a=[];function b(c,e){return a.push(c+" ")>d.cacheLength&&delete b[a.shift()],b[c+" "]=e}return b}function fb(a){return a[s]=!0,a}function gb(a){var b=l.createElement("div");try{return!!a(b)}catch(c){return!1}finally{b.parentNode&&b.parentNode.removeChild(b),b=null}}function hb(a,b){var c=a.split("|"),e=a.length;while(e--)d.attrHandle[c[e]]=b}function ib(a,b){var c=b&&a,d=c&&1===a.nodeType&&1===b.nodeType&&(~b.sourceIndex||B)-(~a.sourceIndex||B);if(d)return d;if(c)while(c=c.nextSibling)if(c===b)return-1;return a?1:-1}function jb(a){return function(b){var c=b.nodeName.toLowerCase();return"input"===c&&b.type===a}}function kb(a){return function(b){var c=b.nodeName.toLowerCase();return("input"===c||"button"===c)&&b.type===a}}function lb(a){return fb(function(b){return b=+b,fb(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 mb(a){return a&&typeof a.getElementsByTagName!==A&&a}c=db.support={},f=db.isXML=function(a){var b=a&&(a.ownerDocument||a).documentElement;return b?"HTML"!==b.nodeName:!1},k=db.setDocument=function(a){var b,e=a?a.ownerDocument||a:t,g=e.defaultView;return e!==l&&9===e.nodeType&&e.documentElement?(l=e,m=e.documentElement,n=!f(e),g&&g!==g.top&&(g.addEventListener?g.addEventListener("unload",function(){k()},!1):g.attachEvent&&g.attachEvent("onunload",function(){k()})),c.attributes=gb(function(a){return a.className="i",!a.getAttribute("className")}),c.getElementsByTagName=gb(function(a){return a.appendChild(e.createComment("")),!a.getElementsByTagName("*").length}),c.getElementsByClassName=Y.test(e.getElementsByClassName)&&gb(function(a){return a.innerHTML="<div class='a'></div><div class='a i'></div>",a.firstChild.className="i",2===a.getElementsByClassName("i").length}),c.getById=gb(function(a){return m.appendChild(a).id=s,!e.getElementsByName||!e.getElementsByName(s).length}),c.getById?(d.find.ID=function(a,b){if(typeof b.getElementById!==A&&n){var c=b.getElementById(a);return c&&c.parentNode?[c]:[]}},d.filter.ID=function(a){var b=a.replace(ab,bb);return function(a){return a.getAttribute("id")===b}}):(delete d.find.ID,d.filter.ID=function(a){var b=a.replace(ab,bb);return function(a){var c=typeof a.getAttributeNode!==A&&a.getAttributeNode("id");return c&&c.value===b}}),d.find.TAG=c.getElementsByTagName?function(a,b){return typeof b.getElementsByTagName!==A?b.getElementsByTagName(a):void 0}:function(a,b){var c,d=[],e=0,f=b.getElementsByTagName(a);if("*"===a){while(c=f[e++])1===c.nodeType&&d.push(c);return d}return f},d.find.CLASS=c.getElementsByClassName&&function(a,b){return typeof b.getElementsByClassName!==A&&n?b.getElementsByClassName(a):void 0},p=[],o=[],(c.qsa=Y.test(e.querySelectorAll))&&(gb(function(a){a.innerHTML="<select t=''><option selected=''></option></select>",a.querySelectorAll("[t^='']").length&&o.push("[*^$]="+K+"*(?:''|\"\")"),a.querySelectorAll("[selected]").length||o.push("\\["+K+"*(?:value|"+J+")"),a.querySelectorAll(":checked").length||o.push(":checked")}),gb(function(a){var b=e.createElement("input");b.setAttribute("type","hidden"),a.appendChild(b).setAttribute("name","D"),a.querySelectorAll("[name=d]").length&&o.push("name"+K+"*[*^$|!~]?="),a.querySelectorAll(":enabled").length||o.push(":enabled",":disabled"),a.querySelectorAll("*,:x"),o.push(",.*:")})),(c.matchesSelector=Y.test(q=m.webkitMatchesSelector||m.mozMatchesSelector||m.oMatchesSelector||m.msMatchesSelector))&&gb(function(a){c.disconnectedMatch=q.call(a,"div"),q.call(a,"[s!='']:x"),p.push("!=",O)}),o=o.length&&new RegExp(o.join("|")),p=p.length&&new RegExp(p.join("|")),b=Y.test(m.compareDocumentPosition),r=b||Y.test(m.contains)?function(a,b){var c=9===a.nodeType?a.documentElement:a,d=b&&b.parentNode;return a===d||!(!d||1!==d.nodeType||!(c.contains?c.contains(d):a.compareDocumentPosition&&16&a.compareDocumentPosition(d)))}:function(a,b){if(b)while(b=b.parentNode)if(b===a)return!0;return!1},z=b?function(a,b){if(a===b)return j=!0,0;var d=!a.compareDocumentPosition-!b.compareDocumentPosition;return d?d:(d=(a.ownerDocument||a)===(b.ownerDocument||b)?a.compareDocumentPosition(b):1,1&d||!c.sortDetached&&b.compareDocumentPosition(a)===d?a===e||a.ownerDocument===t&&r(t,a)?-1:b===e||b.ownerDocument===t&&r(t,b)?1:i?I.call(i,a)-I.call(i,b):0:4&d?-1:1)}:function(a,b){if(a===b)return j=!0,0;var c,d=0,f=a.parentNode,g=b.parentNode,h=[a],k=[b];if(!f||!g)return a===e?-1:b===e?1:f?-1:g?1:i?I.call(i,a)-I.call(i,b):0;if(f===g)return ib(a,b);c=a;while(c=c.parentNode)h.unshift(c);c=b;while(c=c.parentNode)k.unshift(c);while(h[d]===k[d])d++;return d?ib(h[d],k[d]):h[d]===t?-1:k[d]===t?1:0},e):l},db.matches=function(a,b){return db(a,null,null,b)},db.matchesSelector=function(a,b){if((a.ownerDocument||a)!==l&&k(a),b=b.replace(S,"='$1']"),!(!c.matchesSelector||!n||p&&p.test(b)||o&&o.test(b)))try{var d=q.call(a,b);if(d||c.disconnectedMatch||a.document&&11!==a.document.nodeType)return d}catch(e){}return db(b,l,null,[a]).length>0},db.contains=function(a,b){return(a.ownerDocument||a)!==l&&k(a),r(a,b)},db.attr=function(a,b){(a.ownerDocument||a)!==l&&k(a);var e=d.attrHandle[b.toLowerCase()],f=e&&C.call(d.attrHandle,b.toLowerCase())?e(a,b,!n):void 0;return void 0!==f?f:c.attributes||!n?a.getAttribute(b):(f=a.getAttributeNode(b))&&f.specified?f.value:null},db.error=function(a){throw new Error("Syntax error, unrecognized expression: "+a)},db.uniqueSort=function(a){var b,d=[],e=0,f=0;if(j=!c.detectDuplicates,i=!c.sortStable&&a.slice(0),a.sort(z),j){while(b=a[f++])b===a[f]&&(e=d.push(f));while(e--)a.splice(d[e],1)}return i=null,a},e=db.getText=function(a){var b,c="",d=0,f=a.nodeType;if(f){if(1===f||9===f||11===f){if("string"==typeof a.textContent)return a.textContent;for(a=a.firstChild;a;a=a.nextSibling)c+=e(a)}else if(3===f||4===f)return a.nodeValue}else while(b=a[d++])c+=e(b);return c},d=db.selectors={cacheLength:50,createPseudo:fb,match:V,attrHandle:{},find:{},relative:{">":{dir:"parentNode",first:!0}," ":{dir:"parentNode"},"+":{dir:"previousSibling",first:!0},"~":{dir:"previousSibling"}},preFilter:{ATTR:function(a){return a[1]=a[1].replace(ab,bb),a[3]=(a[4]||a[5]||"").replace(ab,bb),"~="===a[2]&&(a[3]=" "+a[3]+" "),a.slice(0,4)},CHILD:function(a){return a[1]=a[1].toLowerCase(),"nth"===a[1].slice(0,3)?(a[3]||db.error(a[0]),a[4]=+(a[4]?a[5]+(a[6]||1):2*("even"===a[3]||"odd"===a[3])),a[5]=+(a[7]+a[8]||"odd"===a[3])):a[3]&&db.error(a[0]),a},PSEUDO:function(a){var b,c=!a[5]&&a[2];return V.CHILD.test(a[0])?null:(a[3]&&void 0!==a[4]?a[2]=a[4]:c&&T.test(c)&&(b=ob(c,!0))&&(b=c.indexOf(")",c.length-b)-c.length)&&(a[0]=a[0].slice(0,b),a[2]=c.slice(0,b)),a.slice(0,3))}},filter:{TAG:function(a){var b=a.replace(ab,bb).toLowerCase();return"*"===a?function(){return!0}:function(a){return a.nodeName&&a.nodeName.toLowerCase()===b}},CLASS:function(a){var b=w[a+" "];return b||(b=new RegExp("(^|"+K+")"+a+"("+K+"|$)"))&&w(a,function(a){return b.test("string"==typeof a.className&&a.className||typeof a.getAttribute!==A&&a.getAttribute("class")||"")})},ATTR:function(a,b,c){return function(d){var e=db.attr(d,a);return null==e?"!="===b:b?(e+="","="===b?e===c:"!="===b?e!==c:"^="===b?c&&0===e.indexOf(c):"*="===b?c&&e.indexOf(c)>-1:"$="===b?c&&e.slice(-c.length)===c:"~="===b?(" "+e+" ").indexOf(c)>-1:"|="===b?e===c||e.slice(0,c.length+1)===c+"-":!1):!0}},CHILD:function(a,b,c,d,e){var f="nth"!==a.slice(0,3),g="last"!==a.slice(-4),h="of-type"===b;return 1===d&&0===e?function(a){return!!a.parentNode}:function(b,c,i){var j,k,l,m,n,o,p=f!==g?"nextSibling":"previousSibling",q=b.parentNode,r=h&&b.nodeName.toLowerCase(),t=!i&&!h;if(q){if(f){while(p){l=b;while(l=l[p])if(h?l.nodeName.toLowerCase()===r:1===l.nodeType)return!1;o=p="only"===a&&!o&&"nextSibling"}return!0}if(o=[g?q.firstChild:q.lastChild],g&&t){k=q[s]||(q[s]={}),j=k[a]||[],n=j[0]===u&&j[1],m=j[0]===u&&j[2],l=n&&q.childNodes[n];while(l=++n&&l&&l[p]||(m=n=0)||o.pop())if(1===l.nodeType&&++m&&l===b){k[a]=[u,n,m];break}}else if(t&&(j=(b[s]||(b[s]={}))[a])&&j[0]===u)m=j[1];else while(l=++n&&l&&l[p]||(m=n=0)||o.pop())if((h?l.nodeName.toLowerCase()===r:1===l.nodeType)&&++m&&(t&&((l[s]||(l[s]={}))[a]=[u,m]),l===b))break;return m-=e,m===d||m%d===0&&m/d>=0}}},PSEUDO:function(a,b){var c,e=d.pseudos[a]||d.setFilters[a.toLowerCase()]||db.error("unsupported pseudo: "+a);return e[s]?e(b):e.length>1?(c=[a,a,"",b],d.setFilters.hasOwnProperty(a.toLowerCase())?fb(function(a,c){var d,f=e(a,b),g=f.length;while(g--)d=I.call(a,f[g]),a[d]=!(c[d]=f[g])}):function(a){return e(a,0,c)}):e}},pseudos:{not:fb(function(a){var b=[],c=[],d=g(a.replace(P,"$1"));return d[s]?fb(function(a,b,c,e){var f,g=d(a,null,e,[]),h=a.length;while(h--)(f=g[h])&&(a[h]=!(b[h]=f))}):function(a,e,f){return b[0]=a,d(b,null,f,c),!c.pop()}}),has:fb(function(a){return function(b){return db(a,b).length>0}}),contains:fb(function(a){return function(b){return(b.textContent||b.innerText||e(b)).indexOf(a)>-1}}),lang:fb(function(a){return U.test(a||"")||db.error("unsupported lang: "+a),a=a.replace(ab,bb).toLowerCase(),function(b){var c;do if(c=n?b.lang:b.getAttribute("xml:lang")||b.getAttribute("lang"))return c=c.toLowerCase(),c===a||0===c.indexOf(a+"-");while((b=b.parentNode)&&1===b.nodeType);return!1}}),target:function(b){var c=a.location&&a.location.hash;return c&&c.slice(1)===b.id},root:function(a){return a===m},focus:function(a){return a===l.activeElement&&(!l.hasFocus||l.hasFocus())&&!!(a.type||a.href||~a.tabIndex)},enabled:function(a){return a.disabled===!1},disabled:function(a){return a.disabled===!0},checked:function(a){var b=a.nodeName.toLowerCase();return"input"===b&&!!a.checked||"option"===b&&!!a.selected},selected:function(a){return a.parentNode&&a.parentNode.selectedIndex,a.selected===!0},empty:function(a){for(a=a.firstChild;a;a=a.nextSibling)if(a.nodeType<6)return!1;return!0},parent:function(a){return!d.pseudos.empty(a)},header:function(a){return X.test(a.nodeName)},input:function(a){return W.test(a.nodeName)},button:function(a){var b=a.nodeName.toLowerCase();return"input"===b&&"button"===a.type||"button"===b},text:function(a){var b;return"input"===a.nodeName.toLowerCase()&&"text"===a.type&&(null==(b=a.getAttribute("type"))||"text"===b.toLowerCase())},first:lb(function(){return[0]}),last:lb(function(a,b){return[b-1]}),eq:lb(function(a,b,c){return[0>c?c+b:c]}),even:lb(function(a,b){for(var c=0;b>c;c+=2)a.push(c);return a}),odd:lb(function(a,b){for(var c=1;b>c;c+=2)a.push(c);return a}),lt:lb(function(a,b,c){for(var d=0>c?c+b:c;--d>=0;)a.push(d);return a}),gt:lb(function(a,b,c){for(var d=0>c?c+b:c;++d<b;)a.push(d);return a})}},d.pseudos.nth=d.pseudos.eq;for(b in{radio:!0,checkbox:!0,file:!0,password:!0,image:!0})d.pseudos[b]=jb(b);for(b in{submit:!0,reset:!0})d.pseudos[b]=kb(b);function nb(){}nb.prototype=d.filters=d.pseudos,d.setFilters=new nb;function ob(a,b){var c,e,f,g,h,i,j,k=x[a+" "];if(k)return b?0:k.slice(0);h=a,i=[],j=d.preFilter;while(h){(!c||(e=Q.exec(h)))&&(e&&(h=h.slice(e[0].length)||h),i.push(f=[])),c=!1,(e=R.exec(h))&&(c=e.shift(),f.push({value:c,type:e[0].replace(P," ")}),h=h.slice(c.length));for(g in d.filter)!(e=V[g].exec(h))||j[g]&&!(e=j[g](e))||(c=e.shift(),f.push({value:c,type:g,matches:e}),h=h.slice(c.length));if(!c)break}return b?h.length:h?db.error(a):x(a,i).slice(0)}function pb(a){for(var b=0,c=a.length,d="";c>b;b++)d+=a[b].value;return d}function qb(a,b,c){var d=b.dir,e=c&&"parentNode"===d,f=v++;return b.first?function(b,c,f){while(b=b[d])if(1===b.nodeType||e)return a(b,c,f)}:function(b,c,g){var h,i,j=[u,f];if(g){while(b=b[d])if((1===b.nodeType||e)&&a(b,c,g))return!0}else while(b=b[d])if(1===b.nodeType||e){if(i=b[s]||(b[s]={}),(h=i[d])&&h[0]===u&&h[1]===f)return j[2]=h[2];if(i[d]=j,j[2]=a(b,c,g))return!0}}}function rb(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 sb(a,b,c,d,e){for(var f,g=[],h=0,i=a.length,j=null!=b;i>h;h++)(f=a[h])&&(!c||c(f,d,e))&&(g.push(f),j&&b.push(h));return g}function tb(a,b,c,d,e,f){return d&&!d[s]&&(d=tb(d)),e&&!e[s]&&(e=tb(e,f)),fb(function(f,g,h,i){var j,k,l,m=[],n=[],o=g.length,p=f||wb(b||"*",h.nodeType?[h]:h,[]),q=!a||!f&&b?p:sb(p,m,a,h,i),r=c?e||(f?a:o||d)?[]:g:q;if(c&&c(q,r,h,i),d){j=sb(r,n),d(j,[],h,i),k=j.length;while(k--)(l=j[k])&&(r[n[k]]=!(q[n[k]]=l))}if(f){if(e||a){if(e){j=[],k=r.length;while(k--)(l=r[k])&&j.push(q[k]=l);e(null,r=[],j,i)}k=r.length;while(k--)(l=r[k])&&(j=e?I.call(f,l):m[k])>-1&&(f[j]=!(g[j]=l))}}else r=sb(r===g?r.splice(o,r.length):r),e?e(null,g,r,i):G.apply(g,r)})}function ub(a){for(var b,c,e,f=a.length,g=d.relative[a[0].type],i=g||d.relative[" "],j=g?1:0,k=qb(function(a){return a===b},i,!0),l=qb(function(a){return I.call(b,a)>-1},i,!0),m=[function(a,c,d){return!g&&(d||c!==h)||((b=c).nodeType?k(a,c,d):l(a,c,d))}];f>j;j++)if(c=d.relative[a[j].type])m=[qb(rb(m),c)];else{if(c=d.filter[a[j].type].apply(null,a[j].matches),c[s]){for(e=++j;f>e;e++)if(d.relative[a[e].type])break;return tb(j>1&&rb(m),j>1&&pb(a.slice(0,j-1).concat({value:" "===a[j-2].type?"*":""})).replace(P,"$1"),c,e>j&&ub(a.slice(j,e)),f>e&&ub(a=a.slice(e)),f>e&&pb(a))}m.push(c)}return rb(m)}function vb(a,b){var c=b.length>0,e=a.length>0,f=function(f,g,i,j,k){var m,n,o,p=0,q="0",r=f&&[],s=[],t=h,v=f||e&&d.find.TAG("*",k),w=u+=null==t?1:Math.random()||.1,x=v.length;for(k&&(h=g!==l&&g);q!==x&&null!=(m=v[q]);q++){if(e&&m){n=0;while(o=a[n++])if(o(m,g,i)){j.push(m);break}k&&(u=w)}c&&((m=!o&&m)&&p--,f&&r.push(m))}if(p+=q,c&&q!==p){n=0;while(o=b[n++])o(r,s,g,i);if(f){if(p>0)while(q--)r[q]||s[q]||(s[q]=E.call(j));s=sb(s)}G.apply(j,s),k&&!f&&s.length>0&&p+b.length>1&&db.uniqueSort(j)}return k&&(u=w,h=t),r};return c?fb(f):f}g=db.compile=function(a,b){var c,d=[],e=[],f=y[a+" "];if(!f){b||(b=ob(a)),c=b.length;while(c--)f=ub(b[c]),f[s]?d.push(f):e.push(f);f=y(a,vb(e,d))}return f};function wb(a,b,c){for(var d=0,e=b.length;e>d;d++)db(a,b[d],c);return c}function xb(a,b,e,f){var h,i,j,k,l,m=ob(a);if(!f&&1===m.length){if(i=m[0]=m[0].slice(0),i.length>2&&"ID"===(j=i[0]).type&&c.getById&&9===b.nodeType&&n&&d.relative[i[1].type]){if(b=(d.find.ID(j.matches[0].replace(ab,bb),b)||[])[0],!b)return e;a=a.slice(i.shift().value.length)}h=V.needsContext.test(a)?0:i.length;while(h--){if(j=i[h],d.relative[k=j.type])break;if((l=d.find[k])&&(f=l(j.matches[0].replace(ab,bb),$.test(i[0].type)&&mb(b.parentNode)||b))){if(i.splice(h,1),a=f.length&&pb(i),!a)return G.apply(e,f),e;break}}}return g(a,m)(f,b,!n,e,$.test(a)&&mb(b.parentNode)||b),e}return c.sortStable=s.split("").sort(z).join("")===s,c.detectDuplicates=!!j,k(),c.sortDetached=gb(function(a){return 1&a.compareDocumentPosition(l.createElement("div"))}),gb(function(a){return a.innerHTML="<a href='#'></a>","#"===a.firstChild.getAttribute("href")})||hb("type|href|height|width",function(a,b,c){return c?void 0:a.getAttribute(b,"type"===b.toLowerCase()?1:2)}),c.attributes&&gb(function(a){return a.innerHTML="<input/>",a.firstChild.setAttribute("value",""),""===a.firstChild.getAttribute("value")})||hb("value",function(a,b,c){return c||"input"!==a.nodeName.toLowerCase()?void 0:a.defaultValue}),gb(function(a){return null==a.getAttribute("disabled")})||hb(J,function(a,b,c){var d;return c?void 0:a[b]===!0?b.toLowerCase():(d=a.getAttributeNode(b))&&d.specified?d.value:null}),db}(a);n.find=t,n.expr=t.selectors,n.expr[":"]=n.expr.pseudos,n.unique=t.uniqueSort,n.text=t.getText,n.isXMLDoc=t.isXML,n.contains=t.contains;var u=n.expr.match.needsContext,v=/^<(\w+)\s*\/?>(?:<\/\1>|)$/,w=/^.[^:#\[\.,]*$/;function x(a,b,c){if(n.isFunction(b))return n.grep(a,function(a,d){return!!b.call(a,d,a)!==c});if(b.nodeType)return n.grep(a,function(a){return a===b!==c});if("string"==typeof b){if(w.test(b))return n.filter(b,a,c);b=n.filter(b,a)}return n.grep(a,function(a){return n.inArray(a,b)>=0!==c})}n.filter=function(a,b,c){var d=b[0];return c&&(a=":not("+a+")"),1===b.length&&1===d.nodeType?n.find.matchesSelector(d,a)?[d]:[]:n.find.matches(a,n.grep(b,function(a){return 1===a.nodeType}))},n.fn.extend({find:function(a){var b,c=[],d=this,e=d.length;if("string"!=typeof a)return this.pushStack(n(a).filter(function(){for(b=0;e>b;b++)if(n.contains(d[b],this))return!0}));for(b=0;e>b;b++)n.find(a,d[b],c);return c=this.pushStack(e>1?n.unique(c):c),c.selector=this.selector?this.selector+" "+a:a,c},filter:function(a){return this.pushStack(x(this,a||[],!1))},not:function(a){return this.pushStack(x(this,a||[],!0))},is:function(a){return!!x(this,"string"==typeof a&&u.test(a)?n(a):a||[],!1).length}});var y,z=a.document,A=/^(?:\s*(<[\w\W]+>)[^>]*|#([\w-]*))$/,B=n.fn.init=function(a,b){var c,d;if(!a)return this;if("string"==typeof a){if(c="<"===a.charAt(0)&&">"===a.charAt(a.length-1)&&a.length>=3?[null,a,null]:A.exec(a),!c||!c[1]&&b)return!b||b.jquery?(b||y).find(a):this.constructor(b).find(a);if(c[1]){if(b=b instanceof n?b[0]:b,n.merge(this,n.parseHTML(c[1],b&&b.nodeType?b.ownerDocument||b:z,!0)),v.test(c[1])&&n.isPlainObject(b))for(c in b)n.isFunction(this[c])?this[c](b[c]):this.attr(c,b[c]);return this}if(d=z.getElementById(c[2]),d&&d.parentNode){if(d.id!==c[2])return y.find(a);this.length=1,this[0]=d}return this.context=z,this.selector=a,this}return a.nodeType?(this.context=this[0]=a,this.length=1,this):n.isFunction(a)?"undefined"!=typeof y.ready?y.ready(a):a(n):(void 0!==a.selector&&(this.selector=a.selector,this.context=a.context),n.makeArray(a,this))};B.prototype=n.fn,y=n(z);var C=/^(?:parents|prev(?:Until|All))/,D={children:!0,contents:!0,next:!0,prev:!0};n.extend({dir:function(a,b,c){var d=[],e=a[b];while(e&&9!==e.nodeType&&(void 0===c||1!==e.nodeType||!n(e).is(c)))1===e.nodeType&&d.push(e),e=e[b];return d},sibling:function(a,b){for(var c=[];a;a=a.nextSibling)1===a.nodeType&&a!==b&&c.push(a);return c}}),n.fn.extend({has:function(a){var b,c=n(a,this),d=c.length;return this.filter(function(){for(b=0;d>b;b++)if(n.contains(this,c[b]))return!0})},closest:function(a,b){for(var c,d=0,e=this.length,f=[],g=u.test(a)||"string"!=typeof a?n(a,b||this.context):0;e>d;d++)for(c=this[d];c&&c!==b;c=c.parentNode)if(c.nodeType<11&&(g?g.index(c)>-1:1===c.nodeType&&n.find.matchesSelector(c,a))){f.push(c);break}return this.pushStack(f.length>1?n.unique(f):f)},index:function(a){return a?"string"==typeof a?n.inArray(this[0],n(a)):n.inArray(a.jquery?a[0]:a,this):this[0]&&this[0].parentNode?this.first().prevAll().length:-1},add:function(a,b){return this.pushStack(n.unique(n.merge(this.get(),n(a,b))))},addBack:function(a){return this.add(null==a?this.prevObject:this.prevObject.filter(a))}});function E(a,b){do a=a[b];while(a&&1!==a.nodeType);return a}n.each({parent:function(a){var b=a.parentNode;return b&&11!==b.nodeType?b:null},parents:function(a){return n.dir(a,"parentNode")},parentsUntil:function(a,b,c){return n.dir(a,"parentNode",c)},next:function(a){return E(a,"nextSibling")},prev:function(a){return E(a,"previousSibling")},nextAll:function(a){return n.dir(a,"nextSibling")},prevAll:function(a){return n.dir(a,"previousSibling")},nextUntil:function(a,b,c){return n.dir(a,"nextSibling",c)},prevUntil:function(a,b,c){return n.dir(a,"previousSibling",c)},siblings:function(a){return n.sibling((a.parentNode||{}).firstChild,a)},children:function(a){return n.sibling(a.firstChild)},contents:function(a){return n.nodeName(a,"iframe")?a.contentDocument||a.contentWindow.document:n.merge([],a.childNodes)}},function(a,b){n.fn[a]=function(c,d){var e=n.map(this,b,c);return"Until"!==a.slice(-5)&&(d=c),d&&"string"==typeof d&&(e=n.filter(d,e)),this.length>1&&(D[a]||(e=n.unique(e)),C.test(a)&&(e=e.reverse())),this.pushStack(e)}});var F=/\S+/g,G={};function H(a){var b=G[a]={};return n.each(a.match(F)||[],function(a,c){b[c]=!0}),b}n.Callbacks=function(a){a="string"==typeof a?G[a]||H(a):n.extend({},a);var b,c,d,e,f,g,h=[],i=!a.once&&[],j=function(l){for(c=a.memory&&l,d=!0,f=g||0,g=0,e=h.length,b=!0;h&&e>f;f++)if(h[f].apply(l[0],l[1])===!1&&a.stopOnFalse){c=!1;break}b=!1,h&&(i?i.length&&j(i.shift()):c?h=[]:k.disable())},k={add:function(){if(h){var d=h.length;!function f(b){n.each(b,function(b,c){var d=n.type(c);"function"===d?a.unique&&k.has(c)||h.push(c):c&&c.length&&"string"!==d&&f(c)})}(arguments),b?e=h.length:c&&(g=d,j(c))}return this},remove:function(){return h&&n.each(arguments,function(a,c){var d;while((d=n.inArray(c,h,d))>-1)h.splice(d,1),b&&(e>=d&&e--,f>=d&&f--)}),this},has:function(a){return a?n.inArray(a,h)>-1:!(!h||!h.length)},empty:function(){return h=[],e=0,this},disable:function(){return h=i=c=void 0,this},disabled:function(){return!h},lock:function(){return i=void 0,c||k.disable(),this},locked:function(){return!i},fireWith:function(a,c){return!h||d&&!i||(c=c||[],c=[a,c.slice?c.slice():c],b?i.push(c):j(c)),this},fire:function(){return k.fireWith(this,arguments),this},fired:function(){return!!d}};return k},n.extend({Deferred:function(a){var b=[["resolve","done",n.Callbacks("once memory"),"resolved"],["reject","fail",n.Callbacks("once memory"),"rejected"],["notify","progress",n.Callbacks("memory")]],c="pending",d={state:function(){return c},always:function(){return e.done(arguments).fail(arguments),this},then:function(){var a=arguments;return n.Deferred(function(c){n.each(b,function(b,f){var g=n.isFunction(a[b])&&a[b];e[f[1]](function(){var a=g&&g.apply(this,arguments);a&&n.isFunction(a.promise)?a.promise().done(c.resolve).fail(c.reject).progress(c.notify):c[f[0]+"With"](this===d?c.promise():this,g?[a]:arguments)})}),a=null}).promise()},promise:function(a){return null!=a?n.extend(a,d):d}},e={};return d.pipe=d.then,n.each(b,function(a,f){var g=f[2],h=f[3];d[f[1]]=g.add,h&&g.add(function(){c=h},b[1^a][2].disable,b[2][2].lock),e[f[0]]=function(){return e[f[0]+"With"](this===e?d:this,arguments),this},e[f[0]+"With"]=g.fireWith}),d.promise(e),a&&a.call(e,e),e},when:function(a){var b=0,c=d.call(arguments),e=c.length,f=1!==e||a&&n.isFunction(a.promise)?e:0,g=1===f?a:n.Deferred(),h=function(a,b,c){return function(e){b[a]=this,c[a]=arguments.length>1?d.call(arguments):e,c===i?g.notifyWith(b,c):--f||g.resolveWith(b,c)}},i,j,k;if(e>1)for(i=new Array(e),j=new Array(e),k=new Array(e);e>b;b++)c[b]&&n.isFunction(c[b].promise)?c[b].promise().done(h(b,k,c)).fail(g.reject).progress(h(b,j,i)):--f;return f||g.resolveWith(k,c),g.promise()}});var I;n.fn.ready=function(a){return n.ready.promise().done(a),this},n.extend({isReady:!1,readyWait:1,holdReady:function(a){a?n.readyWait++:n.ready(!0)},ready:function(a){if(a===!0?!--n.readyWait:!n.isReady){if(!z.body)return setTimeout(n.ready);n.isReady=!0,a!==!0&&--n.readyWait>0||(I.resolveWith(z,[n]),n.fn.trigger&&n(z).trigger("ready").off("ready"))}}});function J(){z.addEventListener?(z.removeEventListener("DOMContentLoaded",K,!1),a.removeEventListener("load",K,!1)):(z.detachEvent("onreadystatechange",K),a.detachEvent("onload",K))}function K(){(z.addEventListener||"load"===event.type||"complete"===z.readyState)&&(J(),n.ready())}n.ready.promise=function(b){if(!I)if(I=n.Deferred(),"complete"===z.readyState)setTimeout(n.ready);else if(z.addEventListener)z.addEventListener("DOMContentLoaded",K,!1),a.addEventListener("load",K,!1);else{z.attachEvent("onreadystatechange",K),a.attachEvent("onload",K);var c=!1;try{c=null==a.frameElement&&z.documentElement}catch(d){}c&&c.doScroll&&!function e(){if(!n.isReady){try{c.doScroll("left")}catch(a){return setTimeout(e,50)}J(),n.ready()}}()}return I.promise(b)};var L="undefined",M;for(M in n(l))break;l.ownLast="0"!==M,l.inlineBlockNeedsLayout=!1,n(function(){var a,b,c=z.getElementsByTagName("body")[0];c&&(a=z.createElement("div"),a.style.cssText="border:0;width:0;height:0;position:absolute;top:0;left:-9999px;margin-top:1px",b=z.createElement("div"),c.appendChild(a).appendChild(b),typeof b.style.zoom!==L&&(b.style.cssText="border:0;margin:0;width:1px;padding:1px;display:inline;zoom:1",(l.inlineBlockNeedsLayout=3===b.offsetWidth)&&(c.style.zoom=1)),c.removeChild(a),a=b=null)}),function(){var a=z.createElement("div");if(null==l.deleteExpando){l.deleteExpando=!0;try{delete a.test}catch(b){l.deleteExpando=!1}}a=null}(),n.acceptData=function(a){var b=n.noData[(a.nodeName+" ").toLowerCase()],c=+a.nodeType||1;return 1!==c&&9!==c?!1:!b||b!==!0&&a.getAttribute("classid")===b};var N=/^(?:\{[\w\W]*\}|\[[\w\W]*\])$/,O=/([A-Z])/g;function P(a,b,c){if(void 0===c&&1===a.nodeType){var d="data-"+b.replace(O,"-$1").toLowerCase();if(c=a.getAttribute(d),"string"==typeof c){try{c="true"===c?!0:"false"===c?!1:"null"===c?null:+c+""===c?+c:N.test(c)?n.parseJSON(c):c}catch(e){}n.data(a,b,c)}else c=void 0}return c}function Q(a){var b;for(b in a)if(("data"!==b||!n.isEmptyObject(a[b]))&&"toJSON"!==b)return!1;return!0}function R(a,b,d,e){if(n.acceptData(a)){var f,g,h=n.expando,i=a.nodeType,j=i?n.cache:a,k=i?a[h]:a[h]&&h;if(k&&j[k]&&(e||j[k].data)||void 0!==d||"string"!=typeof b)return k||(k=i?a[h]=c.pop()||n.guid++:h),j[k]||(j[k]=i?{}:{toJSON:n.noop}),("object"==typeof b||"function"==typeof b)&&(e?j[k]=n.extend(j[k],b):j[k].data=n.extend(j[k].data,b)),g=j[k],e||(g.data||(g.data={}),g=g.data),void 0!==d&&(g[n.camelCase(b)]=d),"string"==typeof b?(f=g[b],null==f&&(f=g[n.camelCase(b)])):f=g,f
3
+ }}function S(a,b,c){if(n.acceptData(a)){var d,e,f=a.nodeType,g=f?n.cache:a,h=f?a[n.expando]:n.expando;if(g[h]){if(b&&(d=c?g[h]:g[h].data)){n.isArray(b)?b=b.concat(n.map(b,n.camelCase)):b in d?b=[b]:(b=n.camelCase(b),b=b in d?[b]:b.split(" ")),e=b.length;while(e--)delete d[b[e]];if(c?!Q(d):!n.isEmptyObject(d))return}(c||(delete g[h].data,Q(g[h])))&&(f?n.cleanData([a],!0):l.deleteExpando||g!=g.window?delete g[h]:g[h]=null)}}}n.extend({cache:{},noData:{"applet ":!0,"embed ":!0,"object ":"clsid:D27CDB6E-AE6D-11cf-96B8-444553540000"},hasData:function(a){return a=a.nodeType?n.cache[a[n.expando]]:a[n.expando],!!a&&!Q(a)},data:function(a,b,c){return R(a,b,c)},removeData:function(a,b){return S(a,b)},_data:function(a,b,c){return R(a,b,c,!0)},_removeData:function(a,b){return S(a,b,!0)}}),n.fn.extend({data:function(a,b){var c,d,e,f=this[0],g=f&&f.attributes;if(void 0===a){if(this.length&&(e=n.data(f),1===f.nodeType&&!n._data(f,"parsedAttrs"))){c=g.length;while(c--)d=g[c].name,0===d.indexOf("data-")&&(d=n.camelCase(d.slice(5)),P(f,d,e[d]));n._data(f,"parsedAttrs",!0)}return e}return"object"==typeof a?this.each(function(){n.data(this,a)}):arguments.length>1?this.each(function(){n.data(this,a,b)}):f?P(f,a,n.data(f,a)):void 0},removeData:function(a){return this.each(function(){n.removeData(this,a)})}}),n.extend({queue:function(a,b,c){var d;return a?(b=(b||"fx")+"queue",d=n._data(a,b),c&&(!d||n.isArray(c)?d=n._data(a,b,n.makeArray(c)):d.push(c)),d||[]):void 0},dequeue:function(a,b){b=b||"fx";var c=n.queue(a,b),d=c.length,e=c.shift(),f=n._queueHooks(a,b),g=function(){n.dequeue(a,b)};"inprogress"===e&&(e=c.shift(),d--),e&&("fx"===b&&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 n._data(a,c)||n._data(a,c,{empty:n.Callbacks("once memory").add(function(){n._removeData(a,b+"queue"),n._removeData(a,c)})})}}),n.fn.extend({queue:function(a,b){var c=2;return"string"!=typeof a&&(b=a,a="fx",c--),arguments.length<c?n.queue(this[0],a):void 0===b?this:this.each(function(){var c=n.queue(this,a,b);n._queueHooks(this,a),"fx"===a&&"inprogress"!==c[0]&&n.dequeue(this,a)})},dequeue:function(a){return this.each(function(){n.dequeue(this,a)})},clearQueue:function(a){return this.queue(a||"fx",[])},promise:function(a,b){var c,d=1,e=n.Deferred(),f=this,g=this.length,h=function(){--d||e.resolveWith(f,[f])};"string"!=typeof a&&(b=a,a=void 0),a=a||"fx";while(g--)c=n._data(f[g],a+"queueHooks"),c&&c.empty&&(d++,c.empty.add(h));return h(),e.promise(b)}});var T=/[+-]?(?:\d*\.|)\d+(?:[eE][+-]?\d+|)/.source,U=["Top","Right","Bottom","Left"],V=function(a,b){return a=b||a,"none"===n.css(a,"display")||!n.contains(a.ownerDocument,a)},W=n.access=function(a,b,c,d,e,f,g){var h=0,i=a.length,j=null==c;if("object"===n.type(c)){e=!0;for(h in c)n.access(a,b,h,c[h],!0,f,g)}else if(void 0!==d&&(e=!0,n.isFunction(d)||(g=!0),j&&(g?(b.call(a,d),b=null):(j=b,b=function(a,b,c){return j.call(n(a),c)})),b))for(;i>h;h++)b(a[h],c,g?d:d.call(a[h],h,b(a[h],c)));return e?a:j?b.call(a):i?b(a[0],c):f},X=/^(?:checkbox|radio)$/i;!function(){var a=z.createDocumentFragment(),b=z.createElement("div"),c=z.createElement("input");if(b.setAttribute("className","t"),b.innerHTML=" <link/><table></table><a href='/a'>a</a>",l.leadingWhitespace=3===b.firstChild.nodeType,l.tbody=!b.getElementsByTagName("tbody").length,l.htmlSerialize=!!b.getElementsByTagName("link").length,l.html5Clone="<:nav></:nav>"!==z.createElement("nav").cloneNode(!0).outerHTML,c.type="checkbox",c.checked=!0,a.appendChild(c),l.appendChecked=c.checked,b.innerHTML="<textarea>x</textarea>",l.noCloneChecked=!!b.cloneNode(!0).lastChild.defaultValue,a.appendChild(b),b.innerHTML="<input type='radio' checked='checked' name='t'/>",l.checkClone=b.cloneNode(!0).cloneNode(!0).lastChild.checked,l.noCloneEvent=!0,b.attachEvent&&(b.attachEvent("onclick",function(){l.noCloneEvent=!1}),b.cloneNode(!0).click()),null==l.deleteExpando){l.deleteExpando=!0;try{delete b.test}catch(d){l.deleteExpando=!1}}a=b=c=null}(),function(){var b,c,d=z.createElement("div");for(b in{submit:!0,change:!0,focusin:!0})c="on"+b,(l[b+"Bubbles"]=c in a)||(d.setAttribute(c,"t"),l[b+"Bubbles"]=d.attributes[c].expando===!1);d=null}();var Y=/^(?:input|select|textarea)$/i,Z=/^key/,$=/^(?:mouse|contextmenu)|click/,_=/^(?:focusinfocus|focusoutblur)$/,ab=/^([^.]*)(?:\.(.+)|)$/;function bb(){return!0}function cb(){return!1}function db(){try{return z.activeElement}catch(a){}}n.event={global:{},add:function(a,b,c,d,e){var f,g,h,i,j,k,l,m,o,p,q,r=n._data(a);if(r){c.handler&&(i=c,c=i.handler,e=i.selector),c.guid||(c.guid=n.guid++),(g=r.events)||(g=r.events={}),(k=r.handle)||(k=r.handle=function(a){return typeof n===L||a&&n.event.triggered===a.type?void 0:n.event.dispatch.apply(k.elem,arguments)},k.elem=a),b=(b||"").match(F)||[""],h=b.length;while(h--)f=ab.exec(b[h])||[],o=q=f[1],p=(f[2]||"").split(".").sort(),o&&(j=n.event.special[o]||{},o=(e?j.delegateType:j.bindType)||o,j=n.event.special[o]||{},l=n.extend({type:o,origType:q,data:d,handler:c,guid:c.guid,selector:e,needsContext:e&&n.expr.match.needsContext.test(e),namespace:p.join(".")},i),(m=g[o])||(m=g[o]=[],m.delegateCount=0,j.setup&&j.setup.call(a,d,p,k)!==!1||(a.addEventListener?a.addEventListener(o,k,!1):a.attachEvent&&a.attachEvent("on"+o,k))),j.add&&(j.add.call(a,l),l.handler.guid||(l.handler.guid=c.guid)),e?m.splice(m.delegateCount++,0,l):m.push(l),n.event.global[o]=!0);a=null}},remove:function(a,b,c,d,e){var f,g,h,i,j,k,l,m,o,p,q,r=n.hasData(a)&&n._data(a);if(r&&(k=r.events)){b=(b||"").match(F)||[""],j=b.length;while(j--)if(h=ab.exec(b[j])||[],o=q=h[1],p=(h[2]||"").split(".").sort(),o){l=n.event.special[o]||{},o=(d?l.delegateType:l.bindType)||o,m=k[o]||[],h=h[2]&&new RegExp("(^|\\.)"+p.join("\\.(?:.*\\.|)")+"(\\.|$)"),i=f=m.length;while(f--)g=m[f],!e&&q!==g.origType||c&&c.guid!==g.guid||h&&!h.test(g.namespace)||d&&d!==g.selector&&("**"!==d||!g.selector)||(m.splice(f,1),g.selector&&m.delegateCount--,l.remove&&l.remove.call(a,g));i&&!m.length&&(l.teardown&&l.teardown.call(a,p,r.handle)!==!1||n.removeEvent(a,o,r.handle),delete k[o])}else for(o in k)n.event.remove(a,o+b[j],c,d,!0);n.isEmptyObject(k)&&(delete r.handle,n._removeData(a,"events"))}},trigger:function(b,c,d,e){var f,g,h,i,k,l,m,o=[d||z],p=j.call(b,"type")?b.type:b,q=j.call(b,"namespace")?b.namespace.split("."):[];if(h=l=d=d||z,3!==d.nodeType&&8!==d.nodeType&&!_.test(p+n.event.triggered)&&(p.indexOf(".")>=0&&(q=p.split("."),p=q.shift(),q.sort()),g=p.indexOf(":")<0&&"on"+p,b=b[n.expando]?b:new n.Event(p,"object"==typeof b&&b),b.isTrigger=e?2:3,b.namespace=q.join("."),b.namespace_re=b.namespace?new RegExp("(^|\\.)"+q.join("\\.(?:.*\\.|)")+"(\\.|$)"):null,b.result=void 0,b.target||(b.target=d),c=null==c?[b]:n.makeArray(c,[b]),k=n.event.special[p]||{},e||!k.trigger||k.trigger.apply(d,c)!==!1)){if(!e&&!k.noBubble&&!n.isWindow(d)){for(i=k.delegateType||p,_.test(i+p)||(h=h.parentNode);h;h=h.parentNode)o.push(h),l=h;l===(d.ownerDocument||z)&&o.push(l.defaultView||l.parentWindow||a)}m=0;while((h=o[m++])&&!b.isPropagationStopped())b.type=m>1?i:k.bindType||p,f=(n._data(h,"events")||{})[b.type]&&n._data(h,"handle"),f&&f.apply(h,c),f=g&&h[g],f&&f.apply&&n.acceptData(h)&&(b.result=f.apply(h,c),b.result===!1&&b.preventDefault());if(b.type=p,!e&&!b.isDefaultPrevented()&&(!k._default||k._default.apply(o.pop(),c)===!1)&&n.acceptData(d)&&g&&d[p]&&!n.isWindow(d)){l=d[g],l&&(d[g]=null),n.event.triggered=p;try{d[p]()}catch(r){}n.event.triggered=void 0,l&&(d[g]=l)}return b.result}},dispatch:function(a){a=n.event.fix(a);var b,c,e,f,g,h=[],i=d.call(arguments),j=(n._data(this,"events")||{})[a.type]||[],k=n.event.special[a.type]||{};if(i[0]=a,a.delegateTarget=this,!k.preDispatch||k.preDispatch.call(this,a)!==!1){h=n.event.handlers.call(this,a,j),b=0;while((f=h[b++])&&!a.isPropagationStopped()){a.currentTarget=f.elem,g=0;while((e=f.handlers[g++])&&!a.isImmediatePropagationStopped())(!a.namespace_re||a.namespace_re.test(e.namespace))&&(a.handleObj=e,a.data=e.data,c=((n.event.special[e.origType]||{}).handle||e.handler).apply(f.elem,i),void 0!==c&&(a.result=c)===!1&&(a.preventDefault(),a.stopPropagation()))}return k.postDispatch&&k.postDispatch.call(this,a),a.result}},handlers:function(a,b){var c,d,e,f,g=[],h=b.delegateCount,i=a.target;if(h&&i.nodeType&&(!a.button||"click"!==a.type))for(;i!=this;i=i.parentNode||this)if(1===i.nodeType&&(i.disabled!==!0||"click"!==a.type)){for(e=[],f=0;h>f;f++)d=b[f],c=d.selector+" ",void 0===e[c]&&(e[c]=d.needsContext?n(c,this).index(i)>=0:n.find(c,this,null,[i]).length),e[c]&&e.push(d);e.length&&g.push({elem:i,handlers:e})}return h<b.length&&g.push({elem:this,handlers:b.slice(h)}),g},fix:function(a){if(a[n.expando])return a;var b,c,d,e=a.type,f=a,g=this.fixHooks[e];g||(this.fixHooks[e]=g=$.test(e)?this.mouseHooks:Z.test(e)?this.keyHooks:{}),d=g.props?this.props.concat(g.props):this.props,a=new n.Event(f),b=d.length;while(b--)c=d[b],a[c]=f[c];return a.target||(a.target=f.srcElement||z),3===a.target.nodeType&&(a.target=a.target.parentNode),a.metaKey=!!a.metaKey,g.filter?g.filter(a,f):a},props:"altKey bubbles cancelable ctrlKey currentTarget eventPhase metaKey relatedTarget shiftKey target timeStamp view which".split(" "),fixHooks:{},keyHooks:{props:"char charCode key keyCode".split(" "),filter:function(a,b){return null==a.which&&(a.which=null!=b.charCode?b.charCode:b.keyCode),a}},mouseHooks:{props:"button buttons clientX clientY fromElement offsetX offsetY pageX pageY screenX screenY toElement".split(" "),filter:function(a,b){var c,d,e,f=b.button,g=b.fromElement;return null==a.pageX&&null!=b.clientX&&(d=a.target.ownerDocument||z,e=d.documentElement,c=d.body,a.pageX=b.clientX+(e&&e.scrollLeft||c&&c.scrollLeft||0)-(e&&e.clientLeft||c&&c.clientLeft||0),a.pageY=b.clientY+(e&&e.scrollTop||c&&c.scrollTop||0)-(e&&e.clientTop||c&&c.clientTop||0)),!a.relatedTarget&&g&&(a.relatedTarget=g===a.target?b.toElement:g),a.which||void 0===f||(a.which=1&f?1:2&f?3:4&f?2:0),a}},special:{load:{noBubble:!0},focus:{trigger:function(){if(this!==db()&&this.focus)try{return this.focus(),!1}catch(a){}},delegateType:"focusin"},blur:{trigger:function(){return this===db()&&this.blur?(this.blur(),!1):void 0},delegateType:"focusout"},click:{trigger:function(){return n.nodeName(this,"input")&&"checkbox"===this.type&&this.click?(this.click(),!1):void 0},_default:function(a){return n.nodeName(a.target,"a")}},beforeunload:{postDispatch:function(a){void 0!==a.result&&(a.originalEvent.returnValue=a.result)}}},simulate:function(a,b,c,d){var e=n.extend(new n.Event,c,{type:a,isSimulated:!0,originalEvent:{}});d?n.event.trigger(e,null,b):n.event.dispatch.call(b,e),e.isDefaultPrevented()&&c.preventDefault()}},n.removeEvent=z.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]===L&&(a[d]=null),a.detachEvent(d,c))},n.Event=function(a,b){return this instanceof n.Event?(a&&a.type?(this.originalEvent=a,this.type=a.type,this.isDefaultPrevented=a.defaultPrevented||void 0===a.defaultPrevented&&(a.returnValue===!1||a.getPreventDefault&&a.getPreventDefault())?bb:cb):this.type=a,b&&n.extend(this,b),this.timeStamp=a&&a.timeStamp||n.now(),void(this[n.expando]=!0)):new n.Event(a,b)},n.Event.prototype={isDefaultPrevented:cb,isPropagationStopped:cb,isImmediatePropagationStopped:cb,preventDefault:function(){var a=this.originalEvent;this.isDefaultPrevented=bb,a&&(a.preventDefault?a.preventDefault():a.returnValue=!1)},stopPropagation:function(){var a=this.originalEvent;this.isPropagationStopped=bb,a&&(a.stopPropagation&&a.stopPropagation(),a.cancelBubble=!0)},stopImmediatePropagation:function(){this.isImmediatePropagationStopped=bb,this.stopPropagation()}},n.each({mouseenter:"mouseover",mouseleave:"mouseout"},function(a,b){n.event.special[a]={delegateType:b,bindType:b,handle:function(a){var c,d=this,e=a.relatedTarget,f=a.handleObj;return(!e||e!==d&&!n.contains(d,e))&&(a.type=f.origType,c=f.handler.apply(this,arguments),a.type=b),c}}}),l.submitBubbles||(n.event.special.submit={setup:function(){return n.nodeName(this,"form")?!1:void n.event.add(this,"click._submit keypress._submit",function(a){var b=a.target,c=n.nodeName(b,"input")||n.nodeName(b,"button")?b.form:void 0;c&&!n._data(c,"submitBubbles")&&(n.event.add(c,"submit._submit",function(a){a._submit_bubble=!0}),n._data(c,"submitBubbles",!0))})},postDispatch:function(a){a._submit_bubble&&(delete a._submit_bubble,this.parentNode&&!a.isTrigger&&n.event.simulate("submit",this.parentNode,a,!0))},teardown:function(){return n.nodeName(this,"form")?!1:void n.event.remove(this,"._submit")}}),l.changeBubbles||(n.event.special.change={setup:function(){return Y.test(this.nodeName)?(("checkbox"===this.type||"radio"===this.type)&&(n.event.add(this,"propertychange._change",function(a){"checked"===a.originalEvent.propertyName&&(this._just_changed=!0)}),n.event.add(this,"click._change",function(a){this._just_changed&&!a.isTrigger&&(this._just_changed=!1),n.event.simulate("change",this,a,!0)})),!1):void n.event.add(this,"beforeactivate._change",function(a){var b=a.target;Y.test(b.nodeName)&&!n._data(b,"changeBubbles")&&(n.event.add(b,"change._change",function(a){!this.parentNode||a.isSimulated||a.isTrigger||n.event.simulate("change",this.parentNode,a,!0)}),n._data(b,"changeBubbles",!0))})},handle:function(a){var b=a.target;return this!==b||a.isSimulated||a.isTrigger||"radio"!==b.type&&"checkbox"!==b.type?a.handleObj.handler.apply(this,arguments):void 0},teardown:function(){return n.event.remove(this,"._change"),!Y.test(this.nodeName)}}),l.focusinBubbles||n.each({focus:"focusin",blur:"focusout"},function(a,b){var c=function(a){n.event.simulate(b,a.target,n.event.fix(a),!0)};n.event.special[b]={setup:function(){var d=this.ownerDocument||this,e=n._data(d,b);e||d.addEventListener(a,c,!0),n._data(d,b,(e||0)+1)},teardown:function(){var d=this.ownerDocument||this,e=n._data(d,b)-1;e?n._data(d,b,e):(d.removeEventListener(a,c,!0),n._removeData(d,b))}}}),n.fn.extend({on:function(a,b,c,d,e){var f,g;if("object"==typeof a){"string"!=typeof b&&(c=c||b,b=void 0);for(f in a)this.on(f,b,c,a[f],e);return this}if(null==c&&null==d?(d=b,c=b=void 0):null==d&&("string"==typeof b?(d=c,c=void 0):(d=c,c=b,b=void 0)),d===!1)d=cb;else if(!d)return this;return 1===e&&(g=d,d=function(a){return n().off(a),g.apply(this,arguments)},d.guid=g.guid||(g.guid=n.guid++)),this.each(function(){n.event.add(this,a,d,c,b)})},one:function(a,b,c,d){return this.on(a,b,c,d,1)},off:function(a,b,c){var d,e;if(a&&a.preventDefault&&a.handleObj)return d=a.handleObj,n(a.delegateTarget).off(d.namespace?d.origType+"."+d.namespace:d.origType,d.selector,d.handler),this;if("object"==typeof a){for(e in a)this.off(e,b,a[e]);return this}return(b===!1||"function"==typeof b)&&(c=b,b=void 0),c===!1&&(c=cb),this.each(function(){n.event.remove(this,a,c,b)})},trigger:function(a,b){return this.each(function(){n.event.trigger(a,b,this)})},triggerHandler:function(a,b){var c=this[0];return c?n.event.trigger(a,b,c,!0):void 0}});function eb(a){var b=fb.split("|"),c=a.createDocumentFragment();if(c.createElement)while(b.length)c.createElement(b.pop());return c}var fb="abbr|article|aside|audio|bdi|canvas|data|datalist|details|figcaption|figure|footer|header|hgroup|mark|meter|nav|output|progress|section|summary|time|video",gb=/ jQuery\d+="(?:null|\d+)"/g,hb=new RegExp("<(?:"+fb+")[\\s/>]","i"),ib=/^\s+/,jb=/<(?!area|br|col|embed|hr|img|input|link|meta|param)(([\w:]+)[^>]*)\/>/gi,kb=/<([\w:]+)/,lb=/<tbody/i,mb=/<|&#?\w+;/,nb=/<(?:script|style|link)/i,ob=/checked\s*(?:[^=]|=\s*.checked.)/i,pb=/^$|\/(?:java|ecma)script/i,qb=/^true\/(.*)/,rb=/^\s*<!(?:\[CDATA\[|--)|(?:\]\]|--)>\s*$/g,sb={option:[1,"<select multiple='multiple'>","</select>"],legend:[1,"<fieldset>","</fieldset>"],area:[1,"<map>","</map>"],param:[1,"<object>","</object>"],thead:[1,"<table>","</table>"],tr:[2,"<table><tbody>","</tbody></table>"],col:[2,"<table><tbody></tbody><colgroup>","</colgroup></table>"],td:[3,"<table><tbody><tr>","</tr></tbody></table>"],_default:l.htmlSerialize?[0,"",""]:[1,"X<div>","</div>"]},tb=eb(z),ub=tb.appendChild(z.createElement("div"));sb.optgroup=sb.option,sb.tbody=sb.tfoot=sb.colgroup=sb.caption=sb.thead,sb.th=sb.td;function vb(a,b){var c,d,e=0,f=typeof a.getElementsByTagName!==L?a.getElementsByTagName(b||"*"):typeof a.querySelectorAll!==L?a.querySelectorAll(b||"*"):void 0;if(!f)for(f=[],c=a.childNodes||a;null!=(d=c[e]);e++)!b||n.nodeName(d,b)?f.push(d):n.merge(f,vb(d,b));return void 0===b||b&&n.nodeName(a,b)?n.merge([a],f):f}function wb(a){X.test(a.type)&&(a.defaultChecked=a.checked)}function xb(a,b){return n.nodeName(a,"table")&&n.nodeName(11!==b.nodeType?b:b.firstChild,"tr")?a.getElementsByTagName("tbody")[0]||a.appendChild(a.ownerDocument.createElement("tbody")):a}function yb(a){return a.type=(null!==n.find.attr(a,"type"))+"/"+a.type,a}function zb(a){var b=qb.exec(a.type);return b?a.type=b[1]:a.removeAttribute("type"),a}function Ab(a,b){for(var c,d=0;null!=(c=a[d]);d++)n._data(c,"globalEval",!b||n._data(b[d],"globalEval"))}function Bb(a,b){if(1===b.nodeType&&n.hasData(a)){var c,d,e,f=n._data(a),g=n._data(b,f),h=f.events;if(h){delete g.handle,g.events={};for(c in h)for(d=0,e=h[c].length;e>d;d++)n.event.add(b,c,h[c][d])}g.data&&(g.data=n.extend({},g.data))}}function Cb(a,b){var c,d,e;if(1===b.nodeType){if(c=b.nodeName.toLowerCase(),!l.noCloneEvent&&b[n.expando]){e=n._data(b);for(d in e.events)n.removeEvent(b,d,e.handle);b.removeAttribute(n.expando)}"script"===c&&b.text!==a.text?(yb(b).text=a.text,zb(b)):"object"===c?(b.parentNode&&(b.outerHTML=a.outerHTML),l.html5Clone&&a.innerHTML&&!n.trim(b.innerHTML)&&(b.innerHTML=a.innerHTML)):"input"===c&&X.test(a.type)?(b.defaultChecked=b.checked=a.checked,b.value!==a.value&&(b.value=a.value)):"option"===c?b.defaultSelected=b.selected=a.defaultSelected:("input"===c||"textarea"===c)&&(b.defaultValue=a.defaultValue)}}n.extend({clone:function(a,b,c){var d,e,f,g,h,i=n.contains(a.ownerDocument,a);if(l.html5Clone||n.isXMLDoc(a)||!hb.test("<"+a.nodeName+">")?f=a.cloneNode(!0):(ub.innerHTML=a.outerHTML,ub.removeChild(f=ub.firstChild)),!(l.noCloneEvent&&l.noCloneChecked||1!==a.nodeType&&11!==a.nodeType||n.isXMLDoc(a)))for(d=vb(f),h=vb(a),g=0;null!=(e=h[g]);++g)d[g]&&Cb(e,d[g]);if(b)if(c)for(h=h||vb(a),d=d||vb(f),g=0;null!=(e=h[g]);g++)Bb(e,d[g]);else Bb(a,f);return d=vb(f,"script"),d.length>0&&Ab(d,!i&&vb(a,"script")),d=h=e=null,f},buildFragment:function(a,b,c,d){for(var e,f,g,h,i,j,k,m=a.length,o=eb(b),p=[],q=0;m>q;q++)if(f=a[q],f||0===f)if("object"===n.type(f))n.merge(p,f.nodeType?[f]:f);else if(mb.test(f)){h=h||o.appendChild(b.createElement("div")),i=(kb.exec(f)||["",""])[1].toLowerCase(),k=sb[i]||sb._default,h.innerHTML=k[1]+f.replace(jb,"<$1></$2>")+k[2],e=k[0];while(e--)h=h.lastChild;if(!l.leadingWhitespace&&ib.test(f)&&p.push(b.createTextNode(ib.exec(f)[0])),!l.tbody){f="table"!==i||lb.test(f)?"<table>"!==k[1]||lb.test(f)?0:h:h.firstChild,e=f&&f.childNodes.length;while(e--)n.nodeName(j=f.childNodes[e],"tbody")&&!j.childNodes.length&&f.removeChild(j)}n.merge(p,h.childNodes),h.textContent="";while(h.firstChild)h.removeChild(h.firstChild);h=o.lastChild}else p.push(b.createTextNode(f));h&&o.removeChild(h),l.appendChecked||n.grep(vb(p,"input"),wb),q=0;while(f=p[q++])if((!d||-1===n.inArray(f,d))&&(g=n.contains(f.ownerDocument,f),h=vb(o.appendChild(f),"script"),g&&Ab(h),c)){e=0;while(f=h[e++])pb.test(f.type||"")&&c.push(f)}return h=null,o},cleanData:function(a,b){for(var d,e,f,g,h=0,i=n.expando,j=n.cache,k=l.deleteExpando,m=n.event.special;null!=(d=a[h]);h++)if((b||n.acceptData(d))&&(f=d[i],g=f&&j[f])){if(g.events)for(e in g.events)m[e]?n.event.remove(d,e):n.removeEvent(d,e,g.handle);j[f]&&(delete j[f],k?delete d[i]:typeof d.removeAttribute!==L?d.removeAttribute(i):d[i]=null,c.push(f))}}}),n.fn.extend({text:function(a){return W(this,function(a){return void 0===a?n.text(this):this.empty().append((this[0]&&this[0].ownerDocument||z).createTextNode(a))},null,a,arguments.length)},append:function(){return this.domManip(arguments,function(a){if(1===this.nodeType||11===this.nodeType||9===this.nodeType){var b=xb(this,a);b.appendChild(a)}})},prepend:function(){return this.domManip(arguments,function(a){if(1===this.nodeType||11===this.nodeType||9===this.nodeType){var b=xb(this,a);b.insertBefore(a,b.firstChild)}})},before:function(){return this.domManip(arguments,function(a){this.parentNode&&this.parentNode.insertBefore(a,this)})},after:function(){return this.domManip(arguments,function(a){this.parentNode&&this.parentNode.insertBefore(a,this.nextSibling)})},remove:function(a,b){for(var c,d=a?n.filter(a,this):this,e=0;null!=(c=d[e]);e++)b||1!==c.nodeType||n.cleanData(vb(c)),c.parentNode&&(b&&n.contains(c.ownerDocument,c)&&Ab(vb(c,"script")),c.parentNode.removeChild(c));return this},empty:function(){for(var a,b=0;null!=(a=this[b]);b++){1===a.nodeType&&n.cleanData(vb(a,!1));while(a.firstChild)a.removeChild(a.firstChild);a.options&&n.nodeName(a,"select")&&(a.options.length=0)}return this},clone:function(a,b){return a=null==a?!1:a,b=null==b?a:b,this.map(function(){return n.clone(this,a,b)})},html:function(a){return W(this,function(a){var b=this[0]||{},c=0,d=this.length;if(void 0===a)return 1===b.nodeType?b.innerHTML.replace(gb,""):void 0;if(!("string"!=typeof a||nb.test(a)||!l.htmlSerialize&&hb.test(a)||!l.leadingWhitespace&&ib.test(a)||sb[(kb.exec(a)||["",""])[1].toLowerCase()])){a=a.replace(jb,"<$1></$2>");try{for(;d>c;c++)b=this[c]||{},1===b.nodeType&&(n.cleanData(vb(b,!1)),b.innerHTML=a);b=0}catch(e){}}b&&this.empty().append(a)},null,a,arguments.length)},replaceWith:function(){var a=arguments[0];return this.domManip(arguments,function(b){a=this.parentNode,n.cleanData(vb(this)),a&&a.replaceChild(b,this)}),a&&(a.length||a.nodeType)?this:this.remove()},detach:function(a){return this.remove(a,!0)},domManip:function(a,b){a=e.apply([],a);var c,d,f,g,h,i,j=0,k=this.length,m=this,o=k-1,p=a[0],q=n.isFunction(p);if(q||k>1&&"string"==typeof p&&!l.checkClone&&ob.test(p))return this.each(function(c){var d=m.eq(c);q&&(a[0]=p.call(this,c,d.html())),d.domManip(a,b)});if(k&&(i=n.buildFragment(a,this[0].ownerDocument,!1,this),c=i.firstChild,1===i.childNodes.length&&(i=c),c)){for(g=n.map(vb(i,"script"),yb),f=g.length;k>j;j++)d=i,j!==o&&(d=n.clone(d,!0,!0),f&&n.merge(g,vb(d,"script"))),b.call(this[j],d,j);if(f)for(h=g[g.length-1].ownerDocument,n.map(g,zb),j=0;f>j;j++)d=g[j],pb.test(d.type||"")&&!n._data(d,"globalEval")&&n.contains(h,d)&&(d.src?n._evalUrl&&n._evalUrl(d.src):n.globalEval((d.text||d.textContent||d.innerHTML||"").replace(rb,"")));i=c=null}return this}}),n.each({appendTo:"append",prependTo:"prepend",insertBefore:"before",insertAfter:"after",replaceAll:"replaceWith"},function(a,b){n.fn[a]=function(a){for(var c,d=0,e=[],g=n(a),h=g.length-1;h>=d;d++)c=d===h?this:this.clone(!0),n(g[d])[b](c),f.apply(e,c.get());return this.pushStack(e)}});var Db,Eb={};function Fb(b,c){var d=n(c.createElement(b)).appendTo(c.body),e=a.getDefaultComputedStyle?a.getDefaultComputedStyle(d[0]).display:n.css(d[0],"display");return d.detach(),e}function Gb(a){var b=z,c=Eb[a];return c||(c=Fb(a,b),"none"!==c&&c||(Db=(Db||n("<iframe frameborder='0' width='0' height='0'/>")).appendTo(b.documentElement),b=(Db[0].contentWindow||Db[0].contentDocument).document,b.write(),b.close(),c=Fb(a,b),Db.detach()),Eb[a]=c),c}!function(){var a,b,c=z.createElement("div"),d="-webkit-box-sizing:content-box;-moz-box-sizing:content-box;box-sizing:content-box;display:block;padding:0;margin:0;border:0";c.innerHTML=" <link/><table></table><a href='/a'>a</a><input type='checkbox'/>",a=c.getElementsByTagName("a")[0],a.style.cssText="float:left;opacity:.5",l.opacity=/^0.5/.test(a.style.opacity),l.cssFloat=!!a.style.cssFloat,c.style.backgroundClip="content-box",c.cloneNode(!0).style.backgroundClip="",l.clearCloneStyle="content-box"===c.style.backgroundClip,a=c=null,l.shrinkWrapBlocks=function(){var a,c,e,f;if(null==b){if(a=z.getElementsByTagName("body")[0],!a)return;f="border:0;width:0;height:0;position:absolute;top:0;left:-9999px",c=z.createElement("div"),e=z.createElement("div"),a.appendChild(c).appendChild(e),b=!1,typeof e.style.zoom!==L&&(e.style.cssText=d+";width:1px;padding:1px;zoom:1",e.innerHTML="<div></div>",e.firstChild.style.width="5px",b=3!==e.offsetWidth),a.removeChild(c),a=c=e=null}return b}}();var Hb=/^margin/,Ib=new RegExp("^("+T+")(?!px)[a-z%]+$","i"),Jb,Kb,Lb=/^(top|right|bottom|left)$/;a.getComputedStyle?(Jb=function(a){return a.ownerDocument.defaultView.getComputedStyle(a,null)},Kb=function(a,b,c){var d,e,f,g,h=a.style;return c=c||Jb(a),g=c?c.getPropertyValue(b)||c[b]:void 0,c&&(""!==g||n.contains(a.ownerDocument,a)||(g=n.style(a,b)),Ib.test(g)&&Hb.test(b)&&(d=h.width,e=h.minWidth,f=h.maxWidth,h.minWidth=h.maxWidth=h.width=g,g=c.width,h.width=d,h.minWidth=e,h.maxWidth=f)),void 0===g?g:g+""}):z.documentElement.currentStyle&&(Jb=function(a){return a.currentStyle},Kb=function(a,b,c){var d,e,f,g,h=a.style;return c=c||Jb(a),g=c?c[b]:void 0,null==g&&h&&h[b]&&(g=h[b]),Ib.test(g)&&!Lb.test(b)&&(d=h.left,e=a.runtimeStyle,f=e&&e.left,f&&(e.left=a.currentStyle.left),h.left="fontSize"===b?"1em":g,g=h.pixelLeft+"px",h.left=d,f&&(e.left=f)),void 0===g?g:g+""||"auto"});function Mb(a,b){return{get:function(){var c=a();if(null!=c)return c?void delete this.get:(this.get=b).apply(this,arguments)}}}!function(){var b,c,d,e,f,g,h=z.createElement("div"),i="border:0;width:0;height:0;position:absolute;top:0;left:-9999px",j="-webkit-box-sizing:content-box;-moz-box-sizing:content-box;box-sizing:content-box;display:block;padding:0;margin:0;border:0";h.innerHTML=" <link/><table></table><a href='/a'>a</a><input type='checkbox'/>",b=h.getElementsByTagName("a")[0],b.style.cssText="float:left;opacity:.5",l.opacity=/^0.5/.test(b.style.opacity),l.cssFloat=!!b.style.cssFloat,h.style.backgroundClip="content-box",h.cloneNode(!0).style.backgroundClip="",l.clearCloneStyle="content-box"===h.style.backgroundClip,b=h=null,n.extend(l,{reliableHiddenOffsets:function(){if(null!=c)return c;var a,b,d,e=z.createElement("div"),f=z.getElementsByTagName("body")[0];if(f)return e.setAttribute("className","t"),e.innerHTML=" <link/><table></table><a href='/a'>a</a><input type='checkbox'/>",a=z.createElement("div"),a.style.cssText=i,f.appendChild(a).appendChild(e),e.innerHTML="<table><tr><td></td><td>t</td></tr></table>",b=e.getElementsByTagName("td"),b[0].style.cssText="padding:0;margin:0;border:0;display:none",d=0===b[0].offsetHeight,b[0].style.display="",b[1].style.display="none",c=d&&0===b[0].offsetHeight,f.removeChild(a),e=f=null,c},boxSizing:function(){return null==d&&k(),d},boxSizingReliable:function(){return null==e&&k(),e},pixelPosition:function(){return null==f&&k(),f},reliableMarginRight:function(){var b,c,d,e;if(null==g&&a.getComputedStyle){if(b=z.getElementsByTagName("body")[0],!b)return;c=z.createElement("div"),d=z.createElement("div"),c.style.cssText=i,b.appendChild(c).appendChild(d),e=d.appendChild(z.createElement("div")),e.style.cssText=d.style.cssText=j,e.style.marginRight=e.style.width="0",d.style.width="1px",g=!parseFloat((a.getComputedStyle(e,null)||{}).marginRight),b.removeChild(c)}return g}});function k(){var b,c,h=z.getElementsByTagName("body")[0];h&&(b=z.createElement("div"),c=z.createElement("div"),b.style.cssText=i,h.appendChild(b).appendChild(c),c.style.cssText="-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box;position:absolute;display:block;padding:1px;border:1px;width:4px;margin-top:1%;top:1%",n.swap(h,null!=h.style.zoom?{zoom:1}:{},function(){d=4===c.offsetWidth}),e=!0,f=!1,g=!0,a.getComputedStyle&&(f="1%"!==(a.getComputedStyle(c,null)||{}).top,e="4px"===(a.getComputedStyle(c,null)||{width:"4px"}).width),h.removeChild(b),c=h=null)}}(),n.swap=function(a,b,c,d){var e,f,g={};for(f in b)g[f]=a.style[f],a.style[f]=b[f];e=c.apply(a,d||[]);for(f in b)a.style[f]=g[f];return e};var Nb=/alpha\([^)]*\)/i,Ob=/opacity\s*=\s*([^)]*)/,Pb=/^(none|table(?!-c[ea]).+)/,Qb=new RegExp("^("+T+")(.*)$","i"),Rb=new RegExp("^([+-])=("+T+")","i"),Sb={position:"absolute",visibility:"hidden",display:"block"},Tb={letterSpacing:0,fontWeight:400},Ub=["Webkit","O","Moz","ms"];function Vb(a,b){if(b in a)return b;var c=b.charAt(0).toUpperCase()+b.slice(1),d=b,e=Ub.length;while(e--)if(b=Ub[e]+c,b in a)return b;return d}function Wb(a,b){for(var c,d,e,f=[],g=0,h=a.length;h>g;g++)d=a[g],d.style&&(f[g]=n._data(d,"olddisplay"),c=d.style.display,b?(f[g]||"none"!==c||(d.style.display=""),""===d.style.display&&V(d)&&(f[g]=n._data(d,"olddisplay",Gb(d.nodeName)))):f[g]||(e=V(d),(c&&"none"!==c||!e)&&n._data(d,"olddisplay",e?c:n.css(d,"display"))));for(g=0;h>g;g++)d=a[g],d.style&&(b&&"none"!==d.style.display&&""!==d.style.display||(d.style.display=b?f[g]||"":"none"));return a}function Xb(a,b,c){var d=Qb.exec(b);return d?Math.max(0,d[1]-(c||0))+(d[2]||"px"):b}function Yb(a,b,c,d,e){for(var f=c===(d?"border":"content")?4:"width"===b?1:0,g=0;4>f;f+=2)"margin"===c&&(g+=n.css(a,c+U[f],!0,e)),d?("content"===c&&(g-=n.css(a,"padding"+U[f],!0,e)),"margin"!==c&&(g-=n.css(a,"border"+U[f]+"Width",!0,e))):(g+=n.css(a,"padding"+U[f],!0,e),"padding"!==c&&(g+=n.css(a,"border"+U[f]+"Width",!0,e)));return g}function Zb(a,b,c){var d=!0,e="width"===b?a.offsetWidth:a.offsetHeight,f=Jb(a),g=l.boxSizing()&&"border-box"===n.css(a,"boxSizing",!1,f);if(0>=e||null==e){if(e=Kb(a,b,f),(0>e||null==e)&&(e=a.style[b]),Ib.test(e))return e;d=g&&(l.boxSizingReliable()||e===a.style[b]),e=parseFloat(e)||0}return e+Yb(a,b,c||(g?"border":"content"),d,f)+"px"}n.extend({cssHooks:{opacity:{get:function(a,b){if(b){var c=Kb(a,"opacity");return""===c?"1":c}}}},cssNumber:{columnCount:!0,fillOpacity:!0,fontWeight:!0,lineHeight:!0,opacity:!0,order:!0,orphans:!0,widows:!0,zIndex:!0,zoom:!0},cssProps:{"float":l.cssFloat?"cssFloat":"styleFloat"},style:function(a,b,c,d){if(a&&3!==a.nodeType&&8!==a.nodeType&&a.style){var e,f,g,h=n.camelCase(b),i=a.style;if(b=n.cssProps[h]||(n.cssProps[h]=Vb(i,h)),g=n.cssHooks[b]||n.cssHooks[h],void 0===c)return g&&"get"in g&&void 0!==(e=g.get(a,!1,d))?e:i[b];if(f=typeof c,"string"===f&&(e=Rb.exec(c))&&(c=(e[1]+1)*e[2]+parseFloat(n.css(a,b)),f="number"),null!=c&&c===c&&("number"!==f||n.cssNumber[h]||(c+="px"),l.clearCloneStyle||""!==c||0!==b.indexOf("background")||(i[b]="inherit"),!(g&&"set"in g&&void 0===(c=g.set(a,c,d)))))try{i[b]="",i[b]=c}catch(j){}}},css:function(a,b,c,d){var e,f,g,h=n.camelCase(b);return b=n.cssProps[h]||(n.cssProps[h]=Vb(a.style,h)),g=n.cssHooks[b]||n.cssHooks[h],g&&"get"in g&&(f=g.get(a,!0,c)),void 0===f&&(f=Kb(a,b,d)),"normal"===f&&b in Tb&&(f=Tb[b]),""===c||c?(e=parseFloat(f),c===!0||n.isNumeric(e)?e||0:f):f}}),n.each(["height","width"],function(a,b){n.cssHooks[b]={get:function(a,c,d){return c?0===a.offsetWidth&&Pb.test(n.css(a,"display"))?n.swap(a,Sb,function(){return Zb(a,b,d)}):Zb(a,b,d):void 0},set:function(a,c,d){var e=d&&Jb(a);return Xb(a,c,d?Yb(a,b,d,l.boxSizing()&&"border-box"===n.css(a,"boxSizing",!1,e),e):0)}}}),l.opacity||(n.cssHooks.opacity={get:function(a,b){return Ob.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=n.isNumeric(b)?"alpha(opacity="+100*b+")":"",f=d&&d.filter||c.filter||"";c.zoom=1,(b>=1||""===b)&&""===n.trim(f.replace(Nb,""))&&c.removeAttribute&&(c.removeAttribute("filter"),""===b||d&&!d.filter)||(c.filter=Nb.test(f)?f.replace(Nb,e):f+" "+e)}}),n.cssHooks.marginRight=Mb(l.reliableMarginRight,function(a,b){return b?n.swap(a,{display:"inline-block"},Kb,[a,"marginRight"]):void 0}),n.each({margin:"",padding:"",border:"Width"},function(a,b){n.cssHooks[a+b]={expand:function(c){for(var d=0,e={},f="string"==typeof c?c.split(" "):[c];4>d;d++)e[a+U[d]+b]=f[d]||f[d-2]||f[0];return e}},Hb.test(a)||(n.cssHooks[a+b].set=Xb)}),n.fn.extend({css:function(a,b){return W(this,function(a,b,c){var d,e,f={},g=0;if(n.isArray(b)){for(d=Jb(a),e=b.length;e>g;g++)f[b[g]]=n.css(a,b[g],!1,d);return f}return void 0!==c?n.style(a,b,c):n.css(a,b)
4
+ },a,b,arguments.length>1)},show:function(){return Wb(this,!0)},hide:function(){return Wb(this)},toggle:function(a){return"boolean"==typeof a?a?this.show():this.hide():this.each(function(){V(this)?n(this).show():n(this).hide()})}});function $b(a,b,c,d,e){return new $b.prototype.init(a,b,c,d,e)}n.Tween=$b,$b.prototype={constructor:$b,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||(n.cssNumber[c]?"":"px")},cur:function(){var a=$b.propHooks[this.prop];return a&&a.get?a.get(this):$b.propHooks._default.get(this)},run:function(a){var b,c=$b.propHooks[this.prop];return this.pos=b=this.options.duration?n.easing[this.easing](a,this.options.duration*a,0,1,this.options.duration):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):$b.propHooks._default.set(this),this}},$b.prototype.init.prototype=$b.prototype,$b.propHooks={_default:{get:function(a){var b;return null==a.elem[a.prop]||a.elem.style&&null!=a.elem.style[a.prop]?(b=n.css(a.elem,a.prop,""),b&&"auto"!==b?b:0):a.elem[a.prop]},set:function(a){n.fx.step[a.prop]?n.fx.step[a.prop](a):a.elem.style&&(null!=a.elem.style[n.cssProps[a.prop]]||n.cssHooks[a.prop])?n.style(a.elem,a.prop,a.now+a.unit):a.elem[a.prop]=a.now}}},$b.propHooks.scrollTop=$b.propHooks.scrollLeft={set:function(a){a.elem.nodeType&&a.elem.parentNode&&(a.elem[a.prop]=a.now)}},n.easing={linear:function(a){return a},swing:function(a){return.5-Math.cos(a*Math.PI)/2}},n.fx=$b.prototype.init,n.fx.step={};var _b,ac,bc=/^(?:toggle|show|hide)$/,cc=new RegExp("^(?:([+-])=|)("+T+")([a-z%]*)$","i"),dc=/queueHooks$/,ec=[jc],fc={"*":[function(a,b){var c=this.createTween(a,b),d=c.cur(),e=cc.exec(b),f=e&&e[3]||(n.cssNumber[a]?"":"px"),g=(n.cssNumber[a]||"px"!==f&&+d)&&cc.exec(n.css(c.elem,a)),h=1,i=20;if(g&&g[3]!==f){f=f||g[3],e=e||[],g=+d||1;do h=h||".5",g/=h,n.style(c.elem,a,g+f);while(h!==(h=c.cur()/d)&&1!==h&&--i)}return e&&(g=c.start=+g||+d||0,c.unit=f,c.end=e[1]?g+(e[1]+1)*e[2]:+e[2]),c}]};function gc(){return setTimeout(function(){_b=void 0}),_b=n.now()}function hc(a,b){var c,d={height:a},e=0;for(b=b?1:0;4>e;e+=2-b)c=U[e],d["margin"+c]=d["padding"+c]=a;return b&&(d.opacity=d.width=a),d}function ic(a,b,c){for(var d,e=(fc[b]||[]).concat(fc["*"]),f=0,g=e.length;g>f;f++)if(d=e[f].call(c,b,a))return d}function jc(a,b,c){var d,e,f,g,h,i,j,k,m=this,o={},p=a.style,q=a.nodeType&&V(a),r=n._data(a,"fxshow");c.queue||(h=n._queueHooks(a,"fx"),null==h.unqueued&&(h.unqueued=0,i=h.empty.fire,h.empty.fire=function(){h.unqueued||i()}),h.unqueued++,m.always(function(){m.always(function(){h.unqueued--,n.queue(a,"fx").length||h.empty.fire()})})),1===a.nodeType&&("height"in b||"width"in b)&&(c.overflow=[p.overflow,p.overflowX,p.overflowY],j=n.css(a,"display"),k=Gb(a.nodeName),"none"===j&&(j=k),"inline"===j&&"none"===n.css(a,"float")&&(l.inlineBlockNeedsLayout&&"inline"!==k?p.zoom=1:p.display="inline-block")),c.overflow&&(p.overflow="hidden",l.shrinkWrapBlocks()||m.always(function(){p.overflow=c.overflow[0],p.overflowX=c.overflow[1],p.overflowY=c.overflow[2]}));for(d in b)if(e=b[d],bc.exec(e)){if(delete b[d],f=f||"toggle"===e,e===(q?"hide":"show")){if("show"!==e||!r||void 0===r[d])continue;q=!0}o[d]=r&&r[d]||n.style(a,d)}if(!n.isEmptyObject(o)){r?"hidden"in r&&(q=r.hidden):r=n._data(a,"fxshow",{}),f&&(r.hidden=!q),q?n(a).show():m.done(function(){n(a).hide()}),m.done(function(){var b;n._removeData(a,"fxshow");for(b in o)n.style(a,b,o[b])});for(d in o)g=ic(q?r[d]:0,d,m),d in r||(r[d]=g.start,q&&(g.end=g.start,g.start="width"===d||"height"===d?1:0))}}function kc(a,b){var c,d,e,f,g;for(c in a)if(d=n.camelCase(c),e=b[d],f=a[c],n.isArray(f)&&(e=f[1],f=a[c]=f[0]),c!==d&&(a[d]=f,delete a[c]),g=n.cssHooks[d],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 lc(a,b,c){var d,e,f=0,g=ec.length,h=n.Deferred().always(function(){delete i.elem}),i=function(){if(e)return!1;for(var b=_b||gc(),c=Math.max(0,j.startTime+j.duration-b),d=c/j.duration||0,f=1-d,g=0,i=j.tweens.length;i>g;g++)j.tweens[g].run(f);return h.notifyWith(a,[j,f,c]),1>f&&i?c:(h.resolveWith(a,[j]),!1)},j=h.promise({elem:a,props:n.extend({},b),opts:n.extend(!0,{specialEasing:{}},c),originalProperties:b,originalOptions:c,startTime:_b||gc(),duration:c.duration,tweens:[],createTween:function(b,c){var d=n.Tween(a,j.opts,b,c,j.opts.specialEasing[b]||j.opts.easing);return j.tweens.push(d),d},stop:function(b){var c=0,d=b?j.tweens.length:0;if(e)return this;for(e=!0;d>c;c++)j.tweens[c].run(1);return b?h.resolveWith(a,[j,b]):h.rejectWith(a,[j,b]),this}}),k=j.props;for(kc(k,j.opts.specialEasing);g>f;f++)if(d=ec[f].call(j,a,k,j.opts))return d;return n.map(k,ic,j),n.isFunction(j.opts.start)&&j.opts.start.call(a,j),n.fx.timer(n.extend(i,{elem:a,anim:j,queue:j.opts.queue})),j.progress(j.opts.progress).done(j.opts.done,j.opts.complete).fail(j.opts.fail).always(j.opts.always)}n.Animation=n.extend(lc,{tweener:function(a,b){n.isFunction(a)?(b=a,a=["*"]):a=a.split(" ");for(var c,d=0,e=a.length;e>d;d++)c=a[d],fc[c]=fc[c]||[],fc[c].unshift(b)},prefilter:function(a,b){b?ec.unshift(a):ec.push(a)}}),n.speed=function(a,b,c){var d=a&&"object"==typeof a?n.extend({},a):{complete:c||!c&&b||n.isFunction(a)&&a,duration:a,easing:c&&b||b&&!n.isFunction(b)&&b};return d.duration=n.fx.off?0:"number"==typeof d.duration?d.duration:d.duration in n.fx.speeds?n.fx.speeds[d.duration]:n.fx.speeds._default,(null==d.queue||d.queue===!0)&&(d.queue="fx"),d.old=d.complete,d.complete=function(){n.isFunction(d.old)&&d.old.call(this),d.queue&&n.dequeue(this,d.queue)},d},n.fn.extend({fadeTo:function(a,b,c,d){return this.filter(V).css("opacity",0).show().end().animate({opacity:b},a,c,d)},animate:function(a,b,c,d){var e=n.isEmptyObject(a),f=n.speed(b,c,d),g=function(){var b=lc(this,n.extend({},a),f);(e||n._data(this,"finish"))&&b.stop(!0)};return g.finish=g,e||f.queue===!1?this.each(g):this.queue(f.queue,g)},stop:function(a,b,c){var d=function(a){var b=a.stop;delete a.stop,b(c)};return"string"!=typeof a&&(c=b,b=a,a=void 0),b&&a!==!1&&this.queue(a||"fx",[]),this.each(function(){var b=!0,e=null!=a&&a+"queueHooks",f=n.timers,g=n._data(this);if(e)g[e]&&g[e].stop&&d(g[e]);else for(e in g)g[e]&&g[e].stop&&dc.test(e)&&d(g[e]);for(e=f.length;e--;)f[e].elem!==this||null!=a&&f[e].queue!==a||(f[e].anim.stop(c),b=!1,f.splice(e,1));(b||!c)&&n.dequeue(this,a)})},finish:function(a){return a!==!1&&(a=a||"fx"),this.each(function(){var b,c=n._data(this),d=c[a+"queue"],e=c[a+"queueHooks"],f=n.timers,g=d?d.length:0;for(c.finish=!0,n.queue(this,a,[]),e&&e.stop&&e.stop.call(this,!0),b=f.length;b--;)f[b].elem===this&&f[b].queue===a&&(f[b].anim.stop(!0),f.splice(b,1));for(b=0;g>b;b++)d[b]&&d[b].finish&&d[b].finish.call(this);delete c.finish})}}),n.each(["toggle","show","hide"],function(a,b){var c=n.fn[b];n.fn[b]=function(a,d,e){return null==a||"boolean"==typeof a?c.apply(this,arguments):this.animate(hc(b,!0),a,d,e)}}),n.each({slideDown:hc("show"),slideUp:hc("hide"),slideToggle:hc("toggle"),fadeIn:{opacity:"show"},fadeOut:{opacity:"hide"},fadeToggle:{opacity:"toggle"}},function(a,b){n.fn[a]=function(a,c,d){return this.animate(b,a,c,d)}}),n.timers=[],n.fx.tick=function(){var a,b=n.timers,c=0;for(_b=n.now();c<b.length;c++)a=b[c],a()||b[c]!==a||b.splice(c--,1);b.length||n.fx.stop(),_b=void 0},n.fx.timer=function(a){n.timers.push(a),a()?n.fx.start():n.timers.pop()},n.fx.interval=13,n.fx.start=function(){ac||(ac=setInterval(n.fx.tick,n.fx.interval))},n.fx.stop=function(){clearInterval(ac),ac=null},n.fx.speeds={slow:600,fast:200,_default:400},n.fn.delay=function(a,b){return a=n.fx?n.fx.speeds[a]||a:a,b=b||"fx",this.queue(b,function(b,c){var d=setTimeout(b,a);c.stop=function(){clearTimeout(d)}})},function(){var a,b,c,d,e=z.createElement("div");e.setAttribute("className","t"),e.innerHTML=" <link/><table></table><a href='/a'>a</a><input type='checkbox'/>",a=e.getElementsByTagName("a")[0],c=z.createElement("select"),d=c.appendChild(z.createElement("option")),b=e.getElementsByTagName("input")[0],a.style.cssText="top:1px",l.getSetAttribute="t"!==e.className,l.style=/top/.test(a.getAttribute("style")),l.hrefNormalized="/a"===a.getAttribute("href"),l.checkOn=!!b.value,l.optSelected=d.selected,l.enctype=!!z.createElement("form").enctype,c.disabled=!0,l.optDisabled=!d.disabled,b=z.createElement("input"),b.setAttribute("value",""),l.input=""===b.getAttribute("value"),b.value="t",b.setAttribute("type","radio"),l.radioValue="t"===b.value,a=b=c=d=e=null}();var mc=/\r/g;n.fn.extend({val:function(a){var b,c,d,e=this[0];{if(arguments.length)return d=n.isFunction(a),this.each(function(c){var e;1===this.nodeType&&(e=d?a.call(this,c,n(this).val()):a,null==e?e="":"number"==typeof e?e+="":n.isArray(e)&&(e=n.map(e,function(a){return null==a?"":a+""})),b=n.valHooks[this.type]||n.valHooks[this.nodeName.toLowerCase()],b&&"set"in b&&void 0!==b.set(this,e,"value")||(this.value=e))});if(e)return b=n.valHooks[e.type]||n.valHooks[e.nodeName.toLowerCase()],b&&"get"in b&&void 0!==(c=b.get(e,"value"))?c:(c=e.value,"string"==typeof c?c.replace(mc,""):null==c?"":c)}}}),n.extend({valHooks:{option:{get:function(a){var b=n.find.attr(a,"value");return null!=b?b:n.text(a)}},select:{get:function(a){for(var b,c,d=a.options,e=a.selectedIndex,f="select-one"===a.type||0>e,g=f?null:[],h=f?e+1:d.length,i=0>e?h:f?e:0;h>i;i++)if(c=d[i],!(!c.selected&&i!==e||(l.optDisabled?c.disabled:null!==c.getAttribute("disabled"))||c.parentNode.disabled&&n.nodeName(c.parentNode,"optgroup"))){if(b=n(c).val(),f)return b;g.push(b)}return g},set:function(a,b){var c,d,e=a.options,f=n.makeArray(b),g=e.length;while(g--)if(d=e[g],n.inArray(n.valHooks.option.get(d),f)>=0)try{d.selected=c=!0}catch(h){d.scrollHeight}else d.selected=!1;return c||(a.selectedIndex=-1),e}}}}),n.each(["radio","checkbox"],function(){n.valHooks[this]={set:function(a,b){return n.isArray(b)?a.checked=n.inArray(n(a).val(),b)>=0:void 0}},l.checkOn||(n.valHooks[this].get=function(a){return null===a.getAttribute("value")?"on":a.value})});var nc,oc,pc=n.expr.attrHandle,qc=/^(?:checked|selected)$/i,rc=l.getSetAttribute,sc=l.input;n.fn.extend({attr:function(a,b){return W(this,n.attr,a,b,arguments.length>1)},removeAttr:function(a){return this.each(function(){n.removeAttr(this,a)})}}),n.extend({attr:function(a,b,c){var d,e,f=a.nodeType;if(a&&3!==f&&8!==f&&2!==f)return typeof a.getAttribute===L?n.prop(a,b,c):(1===f&&n.isXMLDoc(a)||(b=b.toLowerCase(),d=n.attrHooks[b]||(n.expr.match.bool.test(b)?oc:nc)),void 0===c?d&&"get"in d&&null!==(e=d.get(a,b))?e:(e=n.find.attr(a,b),null==e?void 0:e):null!==c?d&&"set"in d&&void 0!==(e=d.set(a,c,b))?e:(a.setAttribute(b,c+""),c):void n.removeAttr(a,b))},removeAttr:function(a,b){var c,d,e=0,f=b&&b.match(F);if(f&&1===a.nodeType)while(c=f[e++])d=n.propFix[c]||c,n.expr.match.bool.test(c)?sc&&rc||!qc.test(c)?a[d]=!1:a[n.camelCase("default-"+c)]=a[d]=!1:n.attr(a,c,""),a.removeAttribute(rc?c:d)},attrHooks:{type:{set:function(a,b){if(!l.radioValue&&"radio"===b&&n.nodeName(a,"input")){var c=a.value;return a.setAttribute("type",b),c&&(a.value=c),b}}}}}),oc={set:function(a,b,c){return b===!1?n.removeAttr(a,c):sc&&rc||!qc.test(c)?a.setAttribute(!rc&&n.propFix[c]||c,c):a[n.camelCase("default-"+c)]=a[c]=!0,c}},n.each(n.expr.match.bool.source.match(/\w+/g),function(a,b){var c=pc[b]||n.find.attr;pc[b]=sc&&rc||!qc.test(b)?function(a,b,d){var e,f;return d||(f=pc[b],pc[b]=e,e=null!=c(a,b,d)?b.toLowerCase():null,pc[b]=f),e}:function(a,b,c){return c?void 0:a[n.camelCase("default-"+b)]?b.toLowerCase():null}}),sc&&rc||(n.attrHooks.value={set:function(a,b,c){return n.nodeName(a,"input")?void(a.defaultValue=b):nc&&nc.set(a,b,c)}}),rc||(nc={set:function(a,b,c){var d=a.getAttributeNode(c);return d||a.setAttributeNode(d=a.ownerDocument.createAttribute(c)),d.value=b+="","value"===c||b===a.getAttribute(c)?b:void 0}},pc.id=pc.name=pc.coords=function(a,b,c){var d;return c?void 0:(d=a.getAttributeNode(b))&&""!==d.value?d.value:null},n.valHooks.button={get:function(a,b){var c=a.getAttributeNode(b);return c&&c.specified?c.value:void 0},set:nc.set},n.attrHooks.contenteditable={set:function(a,b,c){nc.set(a,""===b?!1:b,c)}},n.each(["width","height"],function(a,b){n.attrHooks[b]={set:function(a,c){return""===c?(a.setAttribute(b,"auto"),c):void 0}}})),l.style||(n.attrHooks.style={get:function(a){return a.style.cssText||void 0},set:function(a,b){return a.style.cssText=b+""}});var tc=/^(?:input|select|textarea|button|object)$/i,uc=/^(?:a|area)$/i;n.fn.extend({prop:function(a,b){return W(this,n.prop,a,b,arguments.length>1)},removeProp:function(a){return a=n.propFix[a]||a,this.each(function(){try{this[a]=void 0,delete this[a]}catch(b){}})}}),n.extend({propFix:{"for":"htmlFor","class":"className"},prop:function(a,b,c){var d,e,f,g=a.nodeType;if(a&&3!==g&&8!==g&&2!==g)return f=1!==g||!n.isXMLDoc(a),f&&(b=n.propFix[b]||b,e=n.propHooks[b]),void 0!==c?e&&"set"in e&&void 0!==(d=e.set(a,c,b))?d:a[b]=c:e&&"get"in e&&null!==(d=e.get(a,b))?d:a[b]},propHooks:{tabIndex:{get:function(a){var b=n.find.attr(a,"tabindex");return b?parseInt(b,10):tc.test(a.nodeName)||uc.test(a.nodeName)&&a.href?0:-1}}}}),l.hrefNormalized||n.each(["href","src"],function(a,b){n.propHooks[b]={get:function(a){return a.getAttribute(b,4)}}}),l.optSelected||(n.propHooks.selected={get:function(a){var b=a.parentNode;return b&&(b.selectedIndex,b.parentNode&&b.parentNode.selectedIndex),null}}),n.each(["tabIndex","readOnly","maxLength","cellSpacing","cellPadding","rowSpan","colSpan","useMap","frameBorder","contentEditable"],function(){n.propFix[this.toLowerCase()]=this}),l.enctype||(n.propFix.enctype="encoding");var vc=/[\t\r\n\f]/g;n.fn.extend({addClass:function(a){var b,c,d,e,f,g,h=0,i=this.length,j="string"==typeof a&&a;if(n.isFunction(a))return this.each(function(b){n(this).addClass(a.call(this,b,this.className))});if(j)for(b=(a||"").match(F)||[];i>h;h++)if(c=this[h],d=1===c.nodeType&&(c.className?(" "+c.className+" ").replace(vc," "):" ")){f=0;while(e=b[f++])d.indexOf(" "+e+" ")<0&&(d+=e+" ");g=n.trim(d),c.className!==g&&(c.className=g)}return this},removeClass:function(a){var b,c,d,e,f,g,h=0,i=this.length,j=0===arguments.length||"string"==typeof a&&a;if(n.isFunction(a))return this.each(function(b){n(this).removeClass(a.call(this,b,this.className))});if(j)for(b=(a||"").match(F)||[];i>h;h++)if(c=this[h],d=1===c.nodeType&&(c.className?(" "+c.className+" ").replace(vc," "):"")){f=0;while(e=b[f++])while(d.indexOf(" "+e+" ")>=0)d=d.replace(" "+e+" "," ");g=a?n.trim(d):"",c.className!==g&&(c.className=g)}return this},toggleClass:function(a,b){var c=typeof a;return"boolean"==typeof b&&"string"===c?b?this.addClass(a):this.removeClass(a):this.each(n.isFunction(a)?function(c){n(this).toggleClass(a.call(this,c,this.className,b),b)}:function(){if("string"===c){var b,d=0,e=n(this),f=a.match(F)||[];while(b=f[d++])e.hasClass(b)?e.removeClass(b):e.addClass(b)}else(c===L||"boolean"===c)&&(this.className&&n._data(this,"__className__",this.className),this.className=this.className||a===!1?"":n._data(this,"__className__")||"")})},hasClass:function(a){for(var b=" "+a+" ",c=0,d=this.length;d>c;c++)if(1===this[c].nodeType&&(" "+this[c].className+" ").replace(vc," ").indexOf(b)>=0)return!0;return!1}}),n.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){n.fn[b]=function(a,c){return arguments.length>0?this.on(b,null,a,c):this.trigger(b)}}),n.fn.extend({hover:function(a,b){return this.mouseenter(a).mouseleave(b||a)},bind:function(a,b,c){return this.on(a,null,b,c)},unbind:function(a,b){return this.off(a,null,b)},delegate:function(a,b,c,d){return this.on(b,a,c,d)},undelegate:function(a,b,c){return 1===arguments.length?this.off(a,"**"):this.off(b,a||"**",c)}});var wc=n.now(),xc=/\?/,yc=/(,)|(\[|{)|(}|])|"(?:[^"\\\r\n]|\\["\\\/bfnrt]|\\u[\da-fA-F]{4})*"\s*:?|true|false|null|-?(?!0\d)\d+(?:\.\d+|)(?:[eE][+-]?\d+|)/g;n.parseJSON=function(b){if(a.JSON&&a.JSON.parse)return a.JSON.parse(b+"");var c,d=null,e=n.trim(b+"");return e&&!n.trim(e.replace(yc,function(a,b,e,f){return c&&b&&(d=0),0===d?a:(c=e||b,d+=!f-!e,"")}))?Function("return "+e)():n.error("Invalid JSON: "+b)},n.parseXML=function(b){var c,d;if(!b||"string"!=typeof b)return null;try{a.DOMParser?(d=new DOMParser,c=d.parseFromString(b,"text/xml")):(c=new ActiveXObject("Microsoft.XMLDOM"),c.async="false",c.loadXML(b))}catch(e){c=void 0}return c&&c.documentElement&&!c.getElementsByTagName("parsererror").length||n.error("Invalid XML: "+b),c};var zc,Ac,Bc=/#.*$/,Cc=/([?&])_=[^&]*/,Dc=/^(.*?):[ \t]*([^\r\n]*)\r?$/gm,Ec=/^(?:about|app|app-storage|.+-extension|file|res|widget):$/,Fc=/^(?:GET|HEAD)$/,Gc=/^\/\//,Hc=/^([\w.+-]+:)(?:\/\/(?:[^\/?#]*@|)([^\/?#:]*)(?::(\d+)|)|)/,Ic={},Jc={},Kc="*/".concat("*");try{Ac=location.href}catch(Lc){Ac=z.createElement("a"),Ac.href="",Ac=Ac.href}zc=Hc.exec(Ac.toLowerCase())||[];function Mc(a){return function(b,c){"string"!=typeof b&&(c=b,b="*");var d,e=0,f=b.toLowerCase().match(F)||[];if(n.isFunction(c))while(d=f[e++])"+"===d.charAt(0)?(d=d.slice(1)||"*",(a[d]=a[d]||[]).unshift(c)):(a[d]=a[d]||[]).push(c)}}function Nc(a,b,c,d){var e={},f=a===Jc;function g(h){var i;return e[h]=!0,n.each(a[h]||[],function(a,h){var j=h(b,c,d);return"string"!=typeof j||f||e[j]?f?!(i=j):void 0:(b.dataTypes.unshift(j),g(j),!1)}),i}return g(b.dataTypes[0])||!e["*"]&&g("*")}function Oc(a,b){var c,d,e=n.ajaxSettings.flatOptions||{};for(d in b)void 0!==b[d]&&((e[d]?a:c||(c={}))[d]=b[d]);return c&&n.extend(!0,a,c),a}function Pc(a,b,c){var d,e,f,g,h=a.contents,i=a.dataTypes;while("*"===i[0])i.shift(),void 0===e&&(e=a.mimeType||b.getResponseHeader("Content-Type"));if(e)for(g in h)if(h[g]&&h[g].test(e)){i.unshift(g);break}if(i[0]in c)f=i[0];else{for(g in c){if(!i[0]||a.converters[g+" "+i[0]]){f=g;break}d||(d=g)}f=f||d}return f?(f!==i[0]&&i.unshift(f),c[f]):void 0}function Qc(a,b,c,d){var e,f,g,h,i,j={},k=a.dataTypes.slice();if(k[1])for(g in a.converters)j[g.toLowerCase()]=a.converters[g];f=k.shift();while(f)if(a.responseFields[f]&&(c[a.responseFields[f]]=b),!i&&d&&a.dataFilter&&(b=a.dataFilter(b,a.dataType)),i=f,f=k.shift())if("*"===f)f=i;else if("*"!==i&&i!==f){if(g=j[i+" "+f]||j["* "+f],!g)for(e in j)if(h=e.split(" "),h[1]===f&&(g=j[i+" "+h[0]]||j["* "+h[0]])){g===!0?g=j[e]:j[e]!==!0&&(f=h[0],k.unshift(h[1]));break}if(g!==!0)if(g&&a["throws"])b=g(b);else try{b=g(b)}catch(l){return{state:"parsererror",error:g?l:"No conversion from "+i+" to "+f}}}return{state:"success",data:b}}n.extend({active:0,lastModified:{},etag:{},ajaxSettings:{url:Ac,type:"GET",isLocal:Ec.test(zc[1]),global:!0,processData:!0,async:!0,contentType:"application/x-www-form-urlencoded; charset=UTF-8",accepts:{"*":Kc,text:"text/plain",html:"text/html",xml:"application/xml, text/xml",json:"application/json, text/javascript"},contents:{xml:/xml/,html:/html/,json:/json/},responseFields:{xml:"responseXML",text:"responseText",json:"responseJSON"},converters:{"* text":String,"text html":!0,"text json":n.parseJSON,"text xml":n.parseXML},flatOptions:{url:!0,context:!0}},ajaxSetup:function(a,b){return b?Oc(Oc(a,n.ajaxSettings),b):Oc(n.ajaxSettings,a)},ajaxPrefilter:Mc(Ic),ajaxTransport:Mc(Jc),ajax:function(a,b){"object"==typeof a&&(b=a,a=void 0),b=b||{};var c,d,e,f,g,h,i,j,k=n.ajaxSetup({},b),l=k.context||k,m=k.context&&(l.nodeType||l.jquery)?n(l):n.event,o=n.Deferred(),p=n.Callbacks("once memory"),q=k.statusCode||{},r={},s={},t=0,u="canceled",v={readyState:0,getResponseHeader:function(a){var b;if(2===t){if(!j){j={};while(b=Dc.exec(f))j[b[1].toLowerCase()]=b[2]}b=j[a.toLowerCase()]}return null==b?null:b},getAllResponseHeaders:function(){return 2===t?f:null},setRequestHeader:function(a,b){var c=a.toLowerCase();return t||(a=s[c]=s[c]||a,r[a]=b),this},overrideMimeType:function(a){return t||(k.mimeType=a),this},statusCode:function(a){var b;if(a)if(2>t)for(b in a)q[b]=[q[b],a[b]];else v.always(a[v.status]);return this},abort:function(a){var b=a||u;return i&&i.abort(b),x(0,b),this}};if(o.promise(v).complete=p.add,v.success=v.done,v.error=v.fail,k.url=((a||k.url||Ac)+"").replace(Bc,"").replace(Gc,zc[1]+"//"),k.type=b.method||b.type||k.method||k.type,k.dataTypes=n.trim(k.dataType||"*").toLowerCase().match(F)||[""],null==k.crossDomain&&(c=Hc.exec(k.url.toLowerCase()),k.crossDomain=!(!c||c[1]===zc[1]&&c[2]===zc[2]&&(c[3]||("http:"===c[1]?"80":"443"))===(zc[3]||("http:"===zc[1]?"80":"443")))),k.data&&k.processData&&"string"!=typeof k.data&&(k.data=n.param(k.data,k.traditional)),Nc(Ic,k,b,v),2===t)return v;h=k.global,h&&0===n.active++&&n.event.trigger("ajaxStart"),k.type=k.type.toUpperCase(),k.hasContent=!Fc.test(k.type),e=k.url,k.hasContent||(k.data&&(e=k.url+=(xc.test(e)?"&":"?")+k.data,delete k.data),k.cache===!1&&(k.url=Cc.test(e)?e.replace(Cc,"$1_="+wc++):e+(xc.test(e)?"&":"?")+"_="+wc++)),k.ifModified&&(n.lastModified[e]&&v.setRequestHeader("If-Modified-Since",n.lastModified[e]),n.etag[e]&&v.setRequestHeader("If-None-Match",n.etag[e])),(k.data&&k.hasContent&&k.contentType!==!1||b.contentType)&&v.setRequestHeader("Content-Type",k.contentType),v.setRequestHeader("Accept",k.dataTypes[0]&&k.accepts[k.dataTypes[0]]?k.accepts[k.dataTypes[0]]+("*"!==k.dataTypes[0]?", "+Kc+"; q=0.01":""):k.accepts["*"]);for(d in k.headers)v.setRequestHeader(d,k.headers[d]);if(k.beforeSend&&(k.beforeSend.call(l,v,k)===!1||2===t))return v.abort();u="abort";for(d in{success:1,error:1,complete:1})v[d](k[d]);if(i=Nc(Jc,k,b,v)){v.readyState=1,h&&m.trigger("ajaxSend",[v,k]),k.async&&k.timeout>0&&(g=setTimeout(function(){v.abort("timeout")},k.timeout));try{t=1,i.send(r,x)}catch(w){if(!(2>t))throw w;x(-1,w)}}else x(-1,"No Transport");function x(a,b,c,d){var j,r,s,u,w,x=b;2!==t&&(t=2,g&&clearTimeout(g),i=void 0,f=d||"",v.readyState=a>0?4:0,j=a>=200&&300>a||304===a,c&&(u=Pc(k,v,c)),u=Qc(k,u,v,j),j?(k.ifModified&&(w=v.getResponseHeader("Last-Modified"),w&&(n.lastModified[e]=w),w=v.getResponseHeader("etag"),w&&(n.etag[e]=w)),204===a||"HEAD"===k.type?x="nocontent":304===a?x="notmodified":(x=u.state,r=u.data,s=u.error,j=!s)):(s=x,(a||!x)&&(x="error",0>a&&(a=0))),v.status=a,v.statusText=(b||x)+"",j?o.resolveWith(l,[r,x,v]):o.rejectWith(l,[v,x,s]),v.statusCode(q),q=void 0,h&&m.trigger(j?"ajaxSuccess":"ajaxError",[v,k,j?r:s]),p.fireWith(l,[v,x]),h&&(m.trigger("ajaxComplete",[v,k]),--n.active||n.event.trigger("ajaxStop")))}return v},getJSON:function(a,b,c){return n.get(a,b,c,"json")},getScript:function(a,b){return n.get(a,void 0,b,"script")}}),n.each(["get","post"],function(a,b){n[b]=function(a,c,d,e){return n.isFunction(c)&&(e=e||d,d=c,c=void 0),n.ajax({url:a,type:b,dataType:e,data:c,success:d})}}),n.each(["ajaxStart","ajaxStop","ajaxComplete","ajaxError","ajaxSuccess","ajaxSend"],function(a,b){n.fn[b]=function(a){return this.on(b,a)}}),n._evalUrl=function(a){return n.ajax({url:a,type:"GET",dataType:"script",async:!1,global:!1,"throws":!0})},n.fn.extend({wrapAll:function(a){if(n.isFunction(a))return this.each(function(b){n(this).wrapAll(a.call(this,b))});if(this[0]){var b=n(a,this[0].ownerDocument).eq(0).clone(!0);this[0].parentNode&&b.insertBefore(this[0]),b.map(function(){var a=this;while(a.firstChild&&1===a.firstChild.nodeType)a=a.firstChild;return a}).append(this)}return this},wrapInner:function(a){return this.each(n.isFunction(a)?function(b){n(this).wrapInner(a.call(this,b))}:function(){var b=n(this),c=b.contents();c.length?c.wrapAll(a):b.append(a)})},wrap:function(a){var b=n.isFunction(a);return this.each(function(c){n(this).wrapAll(b?a.call(this,c):a)})},unwrap:function(){return this.parent().each(function(){n.nodeName(this,"body")||n(this).replaceWith(this.childNodes)}).end()}}),n.expr.filters.hidden=function(a){return a.offsetWidth<=0&&a.offsetHeight<=0||!l.reliableHiddenOffsets()&&"none"===(a.style&&a.style.display||n.css(a,"display"))},n.expr.filters.visible=function(a){return!n.expr.filters.hidden(a)};var Rc=/%20/g,Sc=/\[\]$/,Tc=/\r?\n/g,Uc=/^(?:submit|button|image|reset|file)$/i,Vc=/^(?:input|select|textarea|keygen)/i;function Wc(a,b,c,d){var e;if(n.isArray(b))n.each(b,function(b,e){c||Sc.test(a)?d(a,e):Wc(a+"["+("object"==typeof e?b:"")+"]",e,c,d)});else if(c||"object"!==n.type(b))d(a,b);else for(e in b)Wc(a+"["+e+"]",b[e],c,d)}n.param=function(a,b){var c,d=[],e=function(a,b){b=n.isFunction(b)?b():null==b?"":b,d[d.length]=encodeURIComponent(a)+"="+encodeURIComponent(b)};if(void 0===b&&(b=n.ajaxSettings&&n.ajaxSettings.traditional),n.isArray(a)||a.jquery&&!n.isPlainObject(a))n.each(a,function(){e(this.name,this.value)});else for(c in a)Wc(c,a[c],b,e);return d.join("&").replace(Rc,"+")},n.fn.extend({serialize:function(){return n.param(this.serializeArray())},serializeArray:function(){return this.map(function(){var a=n.prop(this,"elements");return a?n.makeArray(a):this}).filter(function(){var a=this.type;return this.name&&!n(this).is(":disabled")&&Vc.test(this.nodeName)&&!Uc.test(a)&&(this.checked||!X.test(a))}).map(function(a,b){var c=n(this).val();return null==c?null:n.isArray(c)?n.map(c,function(a){return{name:b.name,value:a.replace(Tc,"\r\n")}}):{name:b.name,value:c.replace(Tc,"\r\n")}}).get()}}),n.ajaxSettings.xhr=void 0!==a.ActiveXObject?function(){return!this.isLocal&&/^(get|post|head|put|delete|options)$/i.test(this.type)&&$c()||_c()}:$c;var Xc=0,Yc={},Zc=n.ajaxSettings.xhr();a.ActiveXObject&&n(a).on("unload",function(){for(var a in Yc)Yc[a](void 0,!0)}),l.cors=!!Zc&&"withCredentials"in Zc,Zc=l.ajax=!!Zc,Zc&&n.ajaxTransport(function(a){if(!a.crossDomain||l.cors){var b;return{send:function(c,d){var e,f=a.xhr(),g=++Xc;if(f.open(a.type,a.url,a.async,a.username,a.password),a.xhrFields)for(e in a.xhrFields)f[e]=a.xhrFields[e];a.mimeType&&f.overrideMimeType&&f.overrideMimeType(a.mimeType),a.crossDomain||c["X-Requested-With"]||(c["X-Requested-With"]="XMLHttpRequest");for(e in c)void 0!==c[e]&&f.setRequestHeader(e,c[e]+"");f.send(a.hasContent&&a.data||null),b=function(c,e){var h,i,j;if(b&&(e||4===f.readyState))if(delete Yc[g],b=void 0,f.onreadystatechange=n.noop,e)4!==f.readyState&&f.abort();else{j={},h=f.status,"string"==typeof f.responseText&&(j.text=f.responseText);try{i=f.statusText}catch(k){i=""}h||!a.isLocal||a.crossDomain?1223===h&&(h=204):h=j.text?200:404}j&&d(h,i,j,f.getAllResponseHeaders())},a.async?4===f.readyState?setTimeout(b):f.onreadystatechange=Yc[g]=b:b()},abort:function(){b&&b(void 0,!0)}}}});function $c(){try{return new a.XMLHttpRequest}catch(b){}}function _c(){try{return new a.ActiveXObject("Microsoft.XMLHTTP")}catch(b){}}n.ajaxSetup({accepts:{script:"text/javascript, application/javascript, application/ecmascript, application/x-ecmascript"},contents:{script:/(?:java|ecma)script/},converters:{"text script":function(a){return n.globalEval(a),a}}}),n.ajaxPrefilter("script",function(a){void 0===a.cache&&(a.cache=!1),a.crossDomain&&(a.type="GET",a.global=!1)}),n.ajaxTransport("script",function(a){if(a.crossDomain){var b,c=z.head||n("head")[0]||z.documentElement;return{send:function(d,e){b=z.createElement("script"),b.async=!0,a.scriptCharset&&(b.charset=a.scriptCharset),b.src=a.url,b.onload=b.onreadystatechange=function(a,c){(c||!b.readyState||/loaded|complete/.test(b.readyState))&&(b.onload=b.onreadystatechange=null,b.parentNode&&b.parentNode.removeChild(b),b=null,c||e(200,"success"))},c.insertBefore(b,c.firstChild)},abort:function(){b&&b.onload(void 0,!0)}}}});var ad=[],bd=/(=)\?(?=&|$)|\?\?/;n.ajaxSetup({jsonp:"callback",jsonpCallback:function(){var a=ad.pop()||n.expando+"_"+wc++;return this[a]=!0,a}}),n.ajaxPrefilter("json jsonp",function(b,c,d){var e,f,g,h=b.jsonp!==!1&&(bd.test(b.url)?"url":"string"==typeof b.data&&!(b.contentType||"").indexOf("application/x-www-form-urlencoded")&&bd.test(b.data)&&"data");return h||"jsonp"===b.dataTypes[0]?(e=b.jsonpCallback=n.isFunction(b.jsonpCallback)?b.jsonpCallback():b.jsonpCallback,h?b[h]=b[h].replace(bd,"$1"+e):b.jsonp!==!1&&(b.url+=(xc.test(b.url)?"&":"?")+b.jsonp+"="+e),b.converters["script json"]=function(){return g||n.error(e+" was not called"),g[0]},b.dataTypes[0]="json",f=a[e],a[e]=function(){g=arguments},d.always(function(){a[e]=f,b[e]&&(b.jsonpCallback=c.jsonpCallback,ad.push(e)),g&&n.isFunction(f)&&f(g[0]),g=f=void 0}),"script"):void 0}),n.parseHTML=function(a,b,c){if(!a||"string"!=typeof a)return null;"boolean"==typeof b&&(c=b,b=!1),b=b||z;var d=v.exec(a),e=!c&&[];return d?[b.createElement(d[1])]:(d=n.buildFragment([a],b,e),e&&e.length&&n(e).remove(),n.merge([],d.childNodes))};var cd=n.fn.load;n.fn.load=function(a,b,c){if("string"!=typeof a&&cd)return cd.apply(this,arguments);var d,e,f,g=this,h=a.indexOf(" ");return h>=0&&(d=a.slice(h,a.length),a=a.slice(0,h)),n.isFunction(b)?(c=b,b=void 0):b&&"object"==typeof b&&(f="POST"),g.length>0&&n.ajax({url:a,type:f,dataType:"html",data:b}).done(function(a){e=arguments,g.html(d?n("<div>").append(n.parseHTML(a)).find(d):a)}).complete(c&&function(a,b){g.each(c,e||[a.responseText,b,a])}),this},n.expr.filters.animated=function(a){return n.grep(n.timers,function(b){return a===b.elem}).length};var dd=a.document.documentElement;function ed(a){return n.isWindow(a)?a:9===a.nodeType?a.defaultView||a.parentWindow:!1}n.offset={setOffset:function(a,b,c){var d,e,f,g,h,i,j,k=n.css(a,"position"),l=n(a),m={};"static"===k&&(a.style.position="relative"),h=l.offset(),f=n.css(a,"top"),i=n.css(a,"left"),j=("absolute"===k||"fixed"===k)&&n.inArray("auto",[f,i])>-1,j?(d=l.position(),g=d.top,e=d.left):(g=parseFloat(f)||0,e=parseFloat(i)||0),n.isFunction(b)&&(b=b.call(a,c,h)),null!=b.top&&(m.top=b.top-h.top+g),null!=b.left&&(m.left=b.left-h.left+e),"using"in b?b.using.call(a,m):l.css(m)}},n.fn.extend({offset:function(a){if(arguments.length)return void 0===a?this:this.each(function(b){n.offset.setOffset(this,a,b)});var b,c,d={top:0,left:0},e=this[0],f=e&&e.ownerDocument;if(f)return b=f.documentElement,n.contains(b,e)?(typeof e.getBoundingClientRect!==L&&(d=e.getBoundingClientRect()),c=ed(f),{top:d.top+(c.pageYOffset||b.scrollTop)-(b.clientTop||0),left:d.left+(c.pageXOffset||b.scrollLeft)-(b.clientLeft||0)}):d},position:function(){if(this[0]){var a,b,c={top:0,left:0},d=this[0];return"fixed"===n.css(d,"position")?b=d.getBoundingClientRect():(a=this.offsetParent(),b=this.offset(),n.nodeName(a[0],"html")||(c=a.offset()),c.top+=n.css(a[0],"borderTopWidth",!0),c.left+=n.css(a[0],"borderLeftWidth",!0)),{top:b.top-c.top-n.css(d,"marginTop",!0),left:b.left-c.left-n.css(d,"marginLeft",!0)}}},offsetParent:function(){return this.map(function(){var a=this.offsetParent||dd;while(a&&!n.nodeName(a,"html")&&"static"===n.css(a,"position"))a=a.offsetParent;return a||dd})}}),n.each({scrollLeft:"pageXOffset",scrollTop:"pageYOffset"},function(a,b){var c=/Y/.test(b);n.fn[a]=function(d){return W(this,function(a,d,e){var f=ed(a);return void 0===e?f?b in f?f[b]:f.document.documentElement[d]:a[d]:void(f?f.scrollTo(c?n(f).scrollLeft():e,c?e:n(f).scrollTop()):a[d]=e)},a,d,arguments.length,null)}}),n.each(["top","left"],function(a,b){n.cssHooks[b]=Mb(l.pixelPosition,function(a,c){return c?(c=Kb(a,b),Ib.test(c)?n(a).position()[b]+"px":c):void 0})}),n.each({Height:"height",Width:"width"},function(a,b){n.each({padding:"inner"+a,content:b,"":"outer"+a},function(c,d){n.fn[d]=function(d,e){var f=arguments.length&&(c||"boolean"!=typeof d),g=c||(d===!0||e===!0?"margin":"border");return W(this,function(b,c,d){var e;return n.isWindow(b)?b.document.documentElement["client"+a]:9===b.nodeType?(e=b.documentElement,Math.max(b.body["scroll"+a],e["scroll"+a],b.body["offset"+a],e["offset"+a],e["client"+a])):void 0===d?n.css(b,c,g):n.style(b,c,d,g)},b,f?d:void 0,f,null)}})}),n.fn.size=function(){return this.length},n.fn.andSelf=n.fn.addBack,"function"==typeof define&&define.amd&&define("jquery",[],function(){return n});var fd=a.jQuery,gd=a.$;return n.noConflict=function(b){return a.$===n&&(a.$=gd),b&&a.jQuery===n&&(a.jQuery=fd),n},typeof b===L&&(a.jQuery=a.$=n),n});
5
+
6
+ jQuery.noConflict();
js/axzoom/jquery-migrate-1.2.1.min.js ADDED
@@ -0,0 +1,2 @@
 
 
1
+ /*! jQuery Migrate v1.2.1 | (c) 2005, 2013 jQuery Foundation, Inc. and other contributors | jquery.org/license */
2
+ jQuery.migrateMute===void 0&&(jQuery.migrateMute=!0),function(e,t,n){function r(n){var r=t.console;i[n]||(i[n]=!0,e.migrateWarnings.push(n),r&&r.warn&&!e.migrateMute&&(r.warn("JQMIGRATE: "+n),e.migrateTrace&&r.trace&&r.trace()))}function a(t,a,i,o){if(Object.defineProperty)try{return Object.defineProperty(t,a,{configurable:!0,enumerable:!0,get:function(){return r(o),i},set:function(e){r(o),i=e}}),n}catch(s){}e._definePropertyBroken=!0,t[a]=i}var i={};e.migrateWarnings=[],!e.migrateMute&&t.console&&t.console.log&&t.console.log("JQMIGRATE: Logging is active"),e.migrateTrace===n&&(e.migrateTrace=!0),e.migrateReset=function(){i={},e.migrateWarnings.length=0},"BackCompat"===document.compatMode&&r("jQuery is not compatible with Quirks Mode");var o=e("<input/>",{size:1}).attr("size")&&e.attrFn,s=e.attr,u=e.attrHooks.value&&e.attrHooks.value.get||function(){return null},c=e.attrHooks.value&&e.attrHooks.value.set||function(){return n},l=/^(?:input|button)$/i,d=/^[238]$/,p=/^(?:autofocus|autoplay|async|checked|controls|defer|disabled|hidden|loop|multiple|open|readonly|required|scoped|selected)$/i,f=/^(?:checked|selected)$/i;a(e,"attrFn",o||{},"jQuery.attrFn is deprecated"),e.attr=function(t,a,i,u){var c=a.toLowerCase(),g=t&&t.nodeType;return u&&(4>s.length&&r("jQuery.fn.attr( props, pass ) is deprecated"),t&&!d.test(g)&&(o?a in o:e.isFunction(e.fn[a])))?e(t)[a](i):("type"===a&&i!==n&&l.test(t.nodeName)&&t.parentNode&&r("Can't change the 'type' of an input or button in IE 6/7/8"),!e.attrHooks[c]&&p.test(c)&&(e.attrHooks[c]={get:function(t,r){var a,i=e.prop(t,r);return i===!0||"boolean"!=typeof i&&(a=t.getAttributeNode(r))&&a.nodeValue!==!1?r.toLowerCase():n},set:function(t,n,r){var a;return n===!1?e.removeAttr(t,r):(a=e.propFix[r]||r,a in t&&(t[a]=!0),t.setAttribute(r,r.toLowerCase())),r}},f.test(c)&&r("jQuery.fn.attr('"+c+"') may use property instead of attribute")),s.call(e,t,a,i))},e.attrHooks.value={get:function(e,t){var n=(e.nodeName||"").toLowerCase();return"button"===n?u.apply(this,arguments):("input"!==n&&"option"!==n&&r("jQuery.fn.attr('value') no longer gets properties"),t in e?e.value:null)},set:function(e,t){var a=(e.nodeName||"").toLowerCase();return"button"===a?c.apply(this,arguments):("input"!==a&&"option"!==a&&r("jQuery.fn.attr('value', val) no longer sets properties"),e.value=t,n)}};var g,h,v=e.fn.init,m=e.parseJSON,y=/^([^<]*)(<[\w\W]+>)([^>]*)$/;e.fn.init=function(t,n,a){var i;return t&&"string"==typeof t&&!e.isPlainObject(n)&&(i=y.exec(e.trim(t)))&&i[0]&&("<"!==t.charAt(0)&&r("$(html) HTML strings must start with '<' character"),i[3]&&r("$(html) HTML text after last tag is ignored"),"#"===i[0].charAt(0)&&(r("HTML string cannot start with a '#' character"),e.error("JQMIGRATE: Invalid selector string (XSS)")),n&&n.context&&(n=n.context),e.parseHTML)?v.call(this,e.parseHTML(i[2],n,!0),n,a):v.apply(this,arguments)},e.fn.init.prototype=e.fn,e.parseJSON=function(e){return e||null===e?m.apply(this,arguments):(r("jQuery.parseJSON requires a valid JSON string"),null)},e.uaMatch=function(e){e=e.toLowerCase();var t=/(chrome)[ \/]([\w.]+)/.exec(e)||/(webkit)[ \/]([\w.]+)/.exec(e)||/(opera)(?:.*version|)[ \/]([\w.]+)/.exec(e)||/(msie) ([\w.]+)/.exec(e)||0>e.indexOf("compatible")&&/(mozilla)(?:.*? rv:([\w.]+)|)/.exec(e)||[];return{browser:t[1]||"",version:t[2]||"0"}},e.browser||(g=e.uaMatch(navigator.userAgent),h={},g.browser&&(h[g.browser]=!0,h.version=g.version),h.chrome?h.webkit=!0:h.webkit&&(h.safari=!0),e.browser=h),a(e,"browser",e.browser,"jQuery.browser is deprecated"),e.sub=function(){function t(e,n){return new t.fn.init(e,n)}e.extend(!0,t,this),t.superclass=this,t.fn=t.prototype=this(),t.fn.constructor=t,t.sub=this.sub,t.fn.init=function(r,a){return a&&a instanceof e&&!(a instanceof t)&&(a=t(a)),e.fn.init.call(this,r,a,n)},t.fn.init.prototype=t.fn;var n=t(document);return r("jQuery.sub() is deprecated"),t},e.ajaxSetup({converters:{"text json":e.parseJSON}});var b=e.fn.data;e.fn.data=function(t){var a,i,o=this[0];return!o||"events"!==t||1!==arguments.length||(a=e.data(o,t),i=e._data(o,t),a!==n&&a!==i||i===n)?b.apply(this,arguments):(r("Use of jQuery.fn.data('events') is deprecated"),i)};var j=/\/(java|ecma)script/i,w=e.fn.andSelf||e.fn.addBack;e.fn.andSelf=function(){return r("jQuery.fn.andSelf() replaced by jQuery.fn.addBack()"),w.apply(this,arguments)},e.clean||(e.clean=function(t,a,i,o){a=a||document,a=!a.nodeType&&a[0]||a,a=a.ownerDocument||a,r("jQuery.clean() is deprecated");var s,u,c,l,d=[];if(e.merge(d,e.buildFragment(t,a).childNodes),i)for(c=function(e){return!e.type||j.test(e.type)?o?o.push(e.parentNode?e.parentNode.removeChild(e):e):i.appendChild(e):n},s=0;null!=(u=d[s]);s++)e.nodeName(u,"script")&&c(u)||(i.appendChild(u),u.getElementsByTagName!==n&&(l=e.grep(e.merge([],u.getElementsByTagName("script")),c),d.splice.apply(d,[s+1,0].concat(l)),s+=l.length));return d});var Q=e.event.add,x=e.event.remove,k=e.event.trigger,N=e.fn.toggle,T=e.fn.live,M=e.fn.die,S="ajaxStart|ajaxStop|ajaxSend|ajaxComplete|ajaxError|ajaxSuccess",C=RegExp("\\b(?:"+S+")\\b"),H=/(?:^|\s)hover(\.\S+|)\b/,A=function(t){return"string"!=typeof t||e.event.special.hover?t:(H.test(t)&&r("'hover' pseudo-event is deprecated, use 'mouseenter mouseleave'"),t&&t.replace(H,"mouseenter$1 mouseleave$1"))};e.event.props&&"attrChange"!==e.event.props[0]&&e.event.props.unshift("attrChange","attrName","relatedNode","srcElement"),e.event.dispatch&&a(e.event,"handle",e.event.dispatch,"jQuery.event.handle is undocumented and deprecated"),e.event.add=function(e,t,n,a,i){e!==document&&C.test(t)&&r("AJAX events should be attached to document: "+t),Q.call(this,e,A(t||""),n,a,i)},e.event.remove=function(e,t,n,r,a){x.call(this,e,A(t)||"",n,r,a)},e.fn.error=function(){var e=Array.prototype.slice.call(arguments,0);return r("jQuery.fn.error() is deprecated"),e.splice(0,0,"error"),arguments.length?this.bind.apply(this,e):(this.triggerHandler.apply(this,e),this)},e.fn.toggle=function(t,n){if(!e.isFunction(t)||!e.isFunction(n))return N.apply(this,arguments);r("jQuery.fn.toggle(handler, handler...) is deprecated");var a=arguments,i=t.guid||e.guid++,o=0,s=function(n){var r=(e._data(this,"lastToggle"+t.guid)||0)%o;return e._data(this,"lastToggle"+t.guid,r+1),n.preventDefault(),a[r].apply(this,arguments)||!1};for(s.guid=i;a.length>o;)a[o++].guid=i;return this.click(s)},e.fn.live=function(t,n,a){return r("jQuery.fn.live() is deprecated"),T?T.apply(this,arguments):(e(this.context).on(t,this.selector,n,a),this)},e.fn.die=function(t,n){return r("jQuery.fn.die() is deprecated"),M?M.apply(this,arguments):(e(this.context).off(t,this.selector||"**",n),this)},e.event.trigger=function(e,t,n,a){return n||C.test(e)||r("Global events are undocumented and deprecated"),k.call(this,e,t,n||document,a)},e.each(S.split("|"),function(t,n){e.event.special[n]={setup:function(){var t=this;return t!==document&&(e.event.add(document,n+"."+e.guid,function(){e.event.trigger(n,null,t,!0)}),e._data(this,n,e.guid++)),!1},teardown:function(){return this!==document&&e.event.remove(document,n+"."+e._data(this,n)),!1}}})}(jQuery,window);
js/axzoom/jquery.fileupload-process.js ADDED
@@ -0,0 +1,164 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ /*
2
+ * jQuery File Upload Processing Plugin 1.2.2
3
+ * https://github.com/blueimp/jQuery-File-Upload
4
+ *
5
+ * Copyright 2012, Sebastian Tschan
6
+ * https://blueimp.net
7
+ *
8
+ * Licensed under the MIT license:
9
+ * http://www.opensource.org/licenses/MIT
10
+ */
11
+
12
+ /*jslint nomen: true, unparam: true */
13
+ /*global define, window */
14
+
15
+ (function (factory) {
16
+ 'use strict';
17
+ if (typeof define === 'function' && define.amd) {
18
+ // Register as an anonymous AMD module:
19
+ define([
20
+ 'jquery',
21
+ './jquery.fileupload'
22
+ ], factory);
23
+ } else {
24
+ // Browser globals:
25
+ factory(
26
+ window.jQuery
27
+ );
28
+ }
29
+ }(function ($) {
30
+ 'use strict';
31
+
32
+ var originalAdd = $.blueimp.fileupload.prototype.options.add;
33
+
34
+ // The File Upload Processing plugin extends the fileupload widget
35
+ // with file processing functionality:
36
+ $.widget('blueimp.fileupload', $.blueimp.fileupload, {
37
+
38
+ options: {
39
+ // The list of processing actions:
40
+ processQueue: [
41
+ /*
42
+ {
43
+ action: 'log',
44
+ type: 'debug'
45
+ }
46
+ */
47
+ ],
48
+ add: function (e, data) {
49
+ var $this = $(this);
50
+ data.process(function () {
51
+ return $this.fileupload('process', data);
52
+ });
53
+ originalAdd.call(this, e, data);
54
+ }
55
+ },
56
+
57
+ processActions: {
58
+ /*
59
+ log: function (data, options) {
60
+ console[options.type](
61
+ 'Processing "' + data.files[data.index].name + '"'
62
+ );
63
+ }
64
+ */
65
+ },
66
+
67
+ _processFile: function (data) {
68
+ var that = this,
69
+ dfd = $.Deferred().resolveWith(that, [data]),
70
+ chain = dfd.promise();
71
+ this._trigger('process', null, data);
72
+ $.each(data.processQueue, function (i, settings) {
73
+ var func = function (data) {
74
+ return that.processActions[settings.action].call(
75
+ that,
76
+ data,
77
+ settings
78
+ );
79
+ };
80
+ chain = chain.pipe(func, settings.always && func);
81
+ });
82
+ chain
83
+ .done(function () {
84
+ that._trigger('processdone', null, data);
85
+ that._trigger('processalways', null, data);
86
+ })
87
+ .fail(function () {
88
+ that._trigger('processfail', null, data);
89
+ that._trigger('processalways', null, data);
90
+ });
91
+ return chain;
92
+ },
93
+
94
+ // Replaces the settings of each processQueue item that
95
+ // are strings starting with an "@", using the remaining
96
+ // substring as key for the option map,
97
+ // e.g. "@autoUpload" is replaced with options.autoUpload:
98
+ _transformProcessQueue: function (options) {
99
+ var processQueue = [];
100
+ $.each(options.processQueue, function () {
101
+ var settings = {},
102
+ action = this.action,
103
+ prefix = this.prefix === true ? action : this.prefix;
104
+ $.each(this, function (key, value) {
105
+ if ($.type(value) === 'string' &&
106
+ value.charAt(0) === '@') {
107
+ settings[key] = options[
108
+ value.slice(1) || (prefix ? prefix +
109
+ key.charAt(0).toUpperCase() + key.slice(1) : key)
110
+ ];
111
+ } else {
112
+ settings[key] = value;
113
+ }
114
+
115
+ });
116
+ processQueue.push(settings);
117
+ });
118
+ options.processQueue = processQueue;
119
+ },
120
+
121
+ // Returns the number of files currently in the processsing queue:
122
+ processing: function () {
123
+ return this._processing;
124
+ },
125
+
126
+ // Processes the files given as files property of the data parameter,
127
+ // returns a Promise object that allows to bind callbacks:
128
+ process: function (data) {
129
+ var that = this,
130
+ options = $.extend({}, this.options, data);
131
+ if (options.processQueue && options.processQueue.length) {
132
+ this._transformProcessQueue(options);
133
+ if (this._processing === 0) {
134
+ this._trigger('processstart');
135
+ }
136
+ $.each(data.files, function (index) {
137
+ var opts = index ? $.extend({}, options) : options,
138
+ func = function () {
139
+ return that._processFile(opts);
140
+ };
141
+ opts.index = index;
142
+ that._processing += 1;
143
+ that._processingQueue = that._processingQueue.pipe(func, func)
144
+ .always(function () {
145
+ that._processing -= 1;
146
+ if (that._processing === 0) {
147
+ that._trigger('processstop');
148
+ }
149
+ });
150
+ });
151
+ }
152
+ return this._processingQueue;
153
+ },
154
+
155
+ _create: function () {
156
+ this._super();
157
+ this._processing = 0;
158
+ this._processingQueue = $.Deferred().resolveWith(this)
159
+ .promise();
160
+ }
161
+
162
+ });
163
+
164
+ }));
js/axzoom/jquery.fileupload-validate.js ADDED
@@ -0,0 +1,117 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ /*
2
+ * jQuery File Upload Validation Plugin 1.1.1
3
+ * https://github.com/blueimp/jQuery-File-Upload
4
+ *
5
+ * Copyright 2013, Sebastian Tschan
6
+ * https://blueimp.net
7
+ *
8
+ * Licensed under the MIT license:
9
+ * http://www.opensource.org/licenses/MIT
10
+ */
11
+
12
+ /*jslint nomen: true, unparam: true, regexp: true */
13
+ /*global define, window */
14
+
15
+ (function (factory) {
16
+ 'use strict';
17
+ if (typeof define === 'function' && define.amd) {
18
+ // Register as an anonymous AMD module:
19
+ define([
20
+ 'jquery',
21
+ './jquery.fileupload-process'
22
+ ], factory);
23
+ } else {
24
+ // Browser globals:
25
+ factory(
26
+ window.jQuery
27
+ );
28
+ }
29
+ }(function ($) {
30
+ 'use strict';
31
+
32
+ // Append to the default processQueue:
33
+ $.blueimp.fileupload.prototype.options.processQueue.push(
34
+ {
35
+ action: 'validate',
36
+ // Always trigger this action,
37
+ // even if the previous action was rejected:
38
+ always: true,
39
+ // Options taken from the global options map:
40
+ acceptFileTypes: '@',
41
+ maxFileSize: '@',
42
+ minFileSize: '@',
43
+ maxNumberOfFiles: '@',
44
+ disabled: '@disableValidation'
45
+ }
46
+ );
47
+
48
+ // The File Upload Validation plugin extends the fileupload widget
49
+ // with file validation functionality:
50
+ $.widget('blueimp.fileupload', $.blueimp.fileupload, {
51
+
52
+ options: {
53
+ /*
54
+ // The regular expression for allowed file types, matches
55
+ // against either file type or file name:
56
+ acceptFileTypes: /(\.|\/)(gif|jpe?g|png)$/i,
57
+ // The maximum allowed file size in bytes:
58
+ maxFileSize: 10000000, // 10 MB
59
+ // The minimum allowed file size in bytes:
60
+ minFileSize: undefined, // No minimal file size
61
+ // The limit of files to be uploaded:
62
+ maxNumberOfFiles: 10,
63
+ */
64
+
65
+ // Function returning the current number of files,
66
+ // has to be overriden for maxNumberOfFiles validation:
67
+ getNumberOfFiles: $.noop,
68
+
69
+ // Error and info messages:
70
+ messages: {
71
+ maxNumberOfFiles: 'Maximum number of files exceeded',
72
+ acceptFileTypes: 'File type not allowed',
73
+ maxFileSize: 'File is too large',
74
+ minFileSize: 'File is too small'
75
+ }
76
+ },
77
+
78
+ processActions: {
79
+
80
+ validate: function (data, options) {
81
+ if (options.disabled) {
82
+ return data;
83
+ }
84
+ var dfd = $.Deferred(),
85
+ settings = this.options,
86
+ file = data.files[data.index];
87
+ if ($.type(options.maxNumberOfFiles) === 'number' &&
88
+ (settings.getNumberOfFiles() || 0) + data.files.length >
89
+ options.maxNumberOfFiles) {
90
+ file.error = settings.i18n('maxNumberOfFiles');
91
+ } else if (options.acceptFileTypes &&
92
+ !(options.acceptFileTypes.test(file.type) ||
93
+ options.acceptFileTypes.test(file.name))) {
94
+ file.error = settings.i18n('acceptFileTypes');
95
+ } else if (options.maxFileSize && file.size >
96
+ options.maxFileSize) {
97
+ file.error = settings.i18n('maxFileSize');
98
+ } else if ($.type(file.size) === 'number' &&
99
+ file.size < options.minFileSize) {
100
+ file.error = settings.i18n('minFileSize');
101
+ } else {
102
+ delete file.error;
103
+ }
104
+ if (file.error || data.files.error) {
105
+ data.files.error = true;
106
+ dfd.rejectWith(this, [data]);
107
+ } else {
108
+ dfd.resolveWith(this, [data]);
109
+ }
110
+ return dfd.promise();
111
+ }
112
+
113
+ }
114
+
115
+ });
116
+
117
+ }));
js/axzoom/jquery.fileupload.js ADDED
@@ -0,0 +1,1368 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ /*
2
+ * jQuery File Upload Plugin 5.34.0
3
+ * https://github.com/blueimp/jQuery-File-Upload
4
+ *
5
+ * Copyright 2010, Sebastian Tschan
6
+ * https://blueimp.net
7
+ *
8
+ * Licensed under the MIT license:
9
+ * http://www.opensource.org/licenses/MIT
10
+ */
11
+
12
+ /*jslint nomen: true, unparam: true, regexp: true */
13
+ /*global define, window, document, location, File, Blob, FormData */
14
+
15
+ (function (factory) {
16
+ 'use strict';
17
+ if (typeof define === 'function' && define.amd) {
18
+ // Register as an anonymous AMD module:
19
+ define([
20
+ 'jquery',
21
+ 'jquery.ui.widget'
22
+ ], factory);
23
+ } else {
24
+ // Browser globals:
25
+ factory(window.jQuery);
26
+ }
27
+ }(function ($) {
28
+ 'use strict';
29
+
30
+ // Detect file input support, based on
31
+ // http://viljamis.com/blog/2012/file-upload-support-on-mobile/
32
+ $.support.fileInput = !(new RegExp(
33
+ // Handle devices which give false positives for the feature detection:
34
+ '(Android (1\\.[0156]|2\\.[01]))' +
35
+ '|(Windows Phone (OS 7|8\\.0))|(XBLWP)|(ZuneWP)|(WPDesktop)' +
36
+ '|(w(eb)?OSBrowser)|(webOS)' +
37
+ '|(Kindle/(1\\.0|2\\.[05]|3\\.0))'
38
+ ).test(window.navigator.userAgent) ||
39
+ // Feature detection for all other devices:
40
+ $('<input type="file">').prop('disabled'));
41
+
42
+ // The FileReader API is not actually used, but works as feature detection,
43
+ // as e.g. Safari supports XHR file uploads via the FormData API,
44
+ // but not non-multipart XHR file uploads:
45
+ $.support.xhrFileUpload = !!(window.XMLHttpRequestUpload && window.FileReader);
46
+ $.support.xhrFormDataFileUpload = !!window.FormData;
47
+
48
+ // Detect support for Blob slicing (required for chunked uploads):
49
+ $.support.blobSlice = window.Blob && (Blob.prototype.slice ||
50
+ Blob.prototype.webkitSlice || Blob.prototype.mozSlice);
51
+
52
+ // The fileupload widget listens for change events on file input fields defined
53
+ // via fileInput setting and paste or drop events of the given dropZone.
54
+ // In addition to the default jQuery Widget methods, the fileupload widget
55
+ // exposes the "add" and "send" methods, to add or directly send files using
56
+ // the fileupload API.
57
+ // By default, files added via file input selection, paste, drag & drop or
58
+ // "add" method are uploaded immediately, but it is possible to override
59
+ // the "add" callback option to queue file uploads.
60
+ $.widget('blueimp.fileupload', {
61
+
62
+ options: {
63
+ // The drop target element(s), by the default the complete document.
64
+ // Set to null to disable drag & drop support:
65
+ dropZone: $(document),
66
+ // The paste target element(s), by the default the complete document.
67
+ // Set to null to disable paste support:
68
+ pasteZone: $(document),
69
+ // The file input field(s), that are listened to for change events.
70
+ // If undefined, it is set to the file input fields inside
71
+ // of the widget element on plugin initialization.
72
+ // Set to null to disable the change listener.
73
+ fileInput: undefined,
74
+ // By default, the file input field is replaced with a clone after
75
+ // each input field change event. This is required for iframe transport
76
+ // queues and allows change events to be fired for the same file
77
+ // selection, but can be disabled by setting the following option to false:
78
+ replaceFileInput: true,
79
+ // The parameter name for the file form data (the request argument name).
80
+ // If undefined or empty, the name property of the file input field is
81
+ // used, or "files[]" if the file input name property is also empty,
82
+ // can be a string or an array of strings:
83
+ paramName: undefined,
84
+ // By default, each file of a selection is uploaded using an individual
85
+ // request for XHR type uploads. Set to false to upload file
86
+ // selections in one request each:
87
+ singleFileUploads: true,
88
+ // To limit the number of files uploaded with one XHR request,
89
+ // set the following option to an integer greater than 0:
90
+ limitMultiFileUploads: undefined,
91
+ // Set the following option to true to issue all file upload requests
92
+ // in a sequential order:
93
+ sequentialUploads: false,
94
+ // To limit the number of concurrent uploads,
95
+ // set the following option to an integer greater than 0:
96
+ limitConcurrentUploads: undefined,
97
+ // Set the following option to true to force iframe transport uploads:
98
+ forceIframeTransport: false,
99
+ // Set the following option to the location of a redirect url on the
100
+ // origin server, for cross-domain iframe transport uploads:
101
+ redirect: undefined,
102
+ // The parameter name for the redirect url, sent as part of the form
103
+ // data and set to 'redirect' if this option is empty:
104
+ redirectParamName: undefined,
105
+ // Set the following option to the location of a postMessage window,
106
+ // to enable postMessage transport uploads:
107
+ postMessage: undefined,
108
+ // By default, XHR file uploads are sent as multipart/form-data.
109
+ // The iframe transport is always using multipart/form-data.
110
+ // Set to false to enable non-multipart XHR uploads:
111
+ multipart: true,
112
+ // To upload large files in smaller chunks, set the following option
113
+ // to a preferred maximum chunk size. If set to 0, null or undefined,
114
+ // or the browser does not support the required Blob API, files will
115
+ // be uploaded as a whole.
116
+ maxChunkSize: undefined,
117
+ // When a non-multipart upload or a chunked multipart upload has been
118
+ // aborted, this option can be used to resume the upload by setting
119
+ // it to the size of the already uploaded bytes. This option is most
120
+ // useful when modifying the options object inside of the "add" or
121
+ // "send" callbacks, as the options are cloned for each file upload.
122
+ uploadedBytes: undefined,
123
+ // By default, failed (abort or error) file uploads are removed from the
124
+ // global progress calculation. Set the following option to false to
125
+ // prevent recalculating the global progress data:
126
+ recalculateProgress: true,
127
+ // Interval in milliseconds to calculate and trigger progress events:
128
+ progressInterval: 100,
129
+ // Interval in milliseconds to calculate progress bitrate:
130
+ bitrateInterval: 500,
131
+ // By default, uploads are started automatically when adding files:
132
+ autoUpload: true,
133
+
134
+ // Error and info messages:
135
+ messages: {
136
+ uploadedBytes: 'Uploaded bytes exceed file size'
137
+ },
138
+
139
+ // Translation function, gets the message key to be translated
140
+ // and an object with context specific data as arguments:
141
+ i18n: function (message, context) {
142
+ message = this.messages[message] || message.toString();
143
+ if (context) {
144
+ $.each(context, function (key, value) {
145
+ message = message.replace('{' + key + '}', value);
146
+ });
147
+ }
148
+ return message;
149
+ },
150
+
151
+ // Additional form data to be sent along with the file uploads can be set
152
+ // using this option, which accepts an array of objects with name and
153
+ // value properties, a function returning such an array, a FormData
154
+ // object (for XHR file uploads), or a simple object.
155
+ // The form of the first fileInput is given as parameter to the function:
156
+ formData: function (form) {
157
+ return form.serializeArray();
158
+ },
159
+
160
+ // The add callback is invoked as soon as files are added to the fileupload
161
+ // widget (via file input selection, drag & drop, paste or add API call).
162
+ // If the singleFileUploads option is enabled, this callback will be
163
+ // called once for each file in the selection for XHR file uploads, else
164
+ // once for each file selection.
165
+ //
166
+ // The upload starts when the submit method is invoked on the data parameter.
167
+ // The data object contains a files property holding the added files
168
+ // and allows you to override plugin options as well as define ajax settings.
169
+ //
170
+ // Listeners for this callback can also be bound the following way:
171
+ // .bind('fileuploadadd', func);
172
+ //
173
+ // data.submit() returns a Promise object and allows to attach additional
174
+ // handlers using jQuery's Deferred callbacks:
175
+ // data.submit().done(func).fail(func).always(func);
176
+ add: function (e, data) {
177
+ if (e.isDefaultPrevented()) {
178
+ return false;
179
+ }
180
+ if (data.autoUpload || (data.autoUpload !== false &&
181
+ $(this).fileupload('option', 'autoUpload'))) {
182
+ data.process().done(function () {
183
+ data.submit();
184
+ });
185
+ }
186
+ },
187
+
188
+ // Other callbacks:
189
+
190
+ // Callback for the submit event of each file upload:
191
+ // submit: function (e, data) {}, // .bind('fileuploadsubmit', func);
192
+
193
+ // Callback for the start of each file upload request:
194
+ // send: function (e, data) {}, // .bind('fileuploadsend', func);
195
+
196
+ // Callback for successful uploads:
197
+ // done: function (e, data) {}, // .bind('fileuploaddone', func);
198
+
199
+ // Callback for failed (abort or error) uploads:
200
+ // fail: function (e, data) {}, // .bind('fileuploadfail', func);
201
+
202
+ // Callback for completed (success, abort or error) requests:
203
+ // always: function (e, data) {}, // .bind('fileuploadalways', func);
204
+
205
+ // Callback for upload progress events:
206
+ // progress: function (e, data) {}, // .bind('fileuploadprogress', func);
207
+
208
+ // Callback for global upload progress events:
209
+ // progressall: function (e, data) {}, // .bind('fileuploadprogressall', func);
210
+
211
+ // Callback for uploads start, equivalent to the global ajaxStart event:
212
+ // start: function (e) {}, // .bind('fileuploadstart', func);
213
+
214
+ // Callback for uploads stop, equivalent to the global ajaxStop event:
215
+ // stop: function (e) {}, // .bind('fileuploadstop', func);
216
+
217
+ // Callback for change events of the fileInput(s):
218
+ // change: function (e, data) {}, // .bind('fileuploadchange', func);
219
+
220
+ // Callback for paste events to the pasteZone(s):
221
+ // paste: function (e, data) {}, // .bind('fileuploadpaste', func);
222
+
223
+ // Callback for drop events of the dropZone(s):
224
+ // drop: function (e, data) {}, // .bind('fileuploaddrop', func);
225
+
226
+ // Callback for dragover events of the dropZone(s):
227
+ // dragover: function (e) {}, // .bind('fileuploaddragover', func);
228
+
229
+ // Callback for the start of each chunk upload request:
230
+ // chunksend: function (e, data) {}, // .bind('fileuploadchunksend', func);
231
+
232
+ // Callback for successful chunk uploads:
233
+ // chunkdone: function (e, data) {}, // .bind('fileuploadchunkdone', func);
234
+
235
+ // Callback for failed (abort or error) chunk uploads:
236
+ // chunkfail: function (e, data) {}, // .bind('fileuploadchunkfail', func);
237
+
238
+ // Callback for completed (success, abort or error) chunk upload requests:
239
+ // chunkalways: function (e, data) {}, // .bind('fileuploadchunkalways', func);
240
+
241
+ // The plugin options are used as settings object for the ajax calls.
242
+ // The following are jQuery ajax settings required for the file uploads:
243
+ processData: false,
244
+ contentType: false,
245
+ cache: false
246
+ },
247
+
248
+ // A list of options that require reinitializing event listeners and/or
249
+ // special initialization code:
250
+ _specialOptions: [
251
+ 'fileInput',
252
+ 'dropZone',
253
+ 'pasteZone',
254
+ 'multipart',
255
+ 'forceIframeTransport'
256
+ ],
257
+
258
+ _blobSlice: $.support.blobSlice && function () {
259
+ var slice = this.slice || this.webkitSlice || this.mozSlice;
260
+ return slice.apply(this, arguments);
261
+ },
262
+
263
+ _BitrateTimer: function () {
264
+ this.timestamp = ((Date.now) ? Date.now() : (new Date()).getTime());
265
+ this.loaded = 0;
266
+ this.bitrate = 0;
267
+ this.getBitrate = function (now, loaded, interval) {
268
+ var timeDiff = now - this.timestamp;
269
+ if (!this.bitrate || !interval || timeDiff > interval) {
270
+ this.bitrate = (loaded - this.loaded) * (1000 / timeDiff) * 8;
271
+ this.loaded = loaded;
272
+ this.timestamp = now;
273
+ }
274
+ return this.bitrate;
275
+ };
276
+ },
277
+
278
+ _isXHRUpload: function (options) {
279
+ return !options.forceIframeTransport &&
280
+ ((!options.multipart && $.support.xhrFileUpload) ||
281
+ $.support.xhrFormDataFileUpload);
282
+ },
283
+
284
+ _getFormData: function (options) {
285
+ var formData;
286
+ if (typeof options.formData === 'function') {
287
+ return options.formData(options.form);
288
+ }
289
+ if ($.isArray(options.formData)) {
290
+ return options.formData;
291
+ }
292
+ if ($.type(options.formData) === 'object') {
293
+ formData = [];
294
+ $.each(options.formData, function (name, value) {
295
+ formData.push({name: name, value: value});
296
+ });
297
+ return formData;
298
+ }
299
+ return [];
300
+ },
301
+
302
+ _getTotal: function (files) {
303
+ var total = 0;
304
+ $.each(files, function (index, file) {
305
+ total += file.size || 1;
306
+ });
307
+ return total;
308
+ },
309
+
310
+ _initProgressObject: function (obj) {
311
+ var progress = {
312
+ loaded: 0,
313
+ total: 0,
314
+ bitrate: 0
315
+ };
316
+ if (obj._progress) {
317
+ $.extend(obj._progress, progress);
318
+ } else {
319
+ obj._progress = progress;
320
+ }
321
+ },
322
+
323
+ _initResponseObject: function (obj) {
324
+ var prop;
325
+ if (obj._response) {
326
+ for (prop in obj._response) {
327
+ if (obj._response.hasOwnProperty(prop)) {
328
+ delete obj._response[prop];
329
+ }
330
+ }
331
+ } else {
332
+ obj._response = {};
333
+ }
334
+ },
335
+
336
+ _onProgress: function (e, data) {
337
+ if (e.lengthComputable) {
338
+ var now = ((Date.now) ? Date.now() : (new Date()).getTime()),
339
+ loaded;
340
+ if (data._time && data.progressInterval &&
341
+ (now - data._time < data.progressInterval) &&
342
+ e.loaded !== e.total) {
343
+ return;
344
+ }
345
+ data._time = now;
346
+ loaded = Math.floor(
347
+ e.loaded / e.total * (data.chunkSize || data._progress.total)
348
+ ) + (data.uploadedBytes || 0);
349
+ // Add the difference from the previously loaded state
350
+ // to the global loaded counter:
351
+ this._progress.loaded += (loaded - data._progress.loaded);
352
+ this._progress.bitrate = this._bitrateTimer.getBitrate(
353
+ now,
354
+ this._progress.loaded,
355
+ data.bitrateInterval
356
+ );
357
+ data._progress.loaded = data.loaded = loaded;
358
+ data._progress.bitrate = data.bitrate = data._bitrateTimer.getBitrate(
359
+ now,
360
+ loaded,
361
+ data.bitrateInterval
362
+ );
363
+ // Trigger a custom progress event with a total data property set
364
+ // to the file size(s) of the current upload and a loaded data
365
+ // property calculated accordingly:
366
+ this._trigger(
367
+ 'progress',
368
+ $.Event('progress', {delegatedEvent: e}),
369
+ data
370
+ );
371
+ // Trigger a global progress event for all current file uploads,
372
+ // including ajax calls queued for sequential file uploads:
373
+ this._trigger(
374
+ 'progressall',
375
+ $.Event('progressall', {delegatedEvent: e}),
376
+ this._progress
377
+ );
378
+ }
379
+ },
380
+
381
+ _initProgressListener: function (options) {
382
+ var that = this,
383
+ xhr = options.xhr ? options.xhr() : $.ajaxSettings.xhr();
384
+ // Accesss to the native XHR object is required to add event listeners
385
+ // for the upload progress event:
386
+ if (xhr.upload) {
387
+ $(xhr.upload).bind('progress', function (e) {
388
+ var oe = e.originalEvent;
389
+ // Make sure the progress event properties get copied over:
390
+ e.lengthComputable = oe.lengthComputable;
391
+ e.loaded = oe.loaded;
392
+ e.total = oe.total;
393
+ that._onProgress(e, options);
394
+ });
395
+ options.xhr = function () {
396
+ return xhr;
397
+ };
398
+ }
399
+ },
400
+
401
+ _isInstanceOf: function (type, obj) {
402
+ // Cross-frame instanceof check
403
+ return Object.prototype.toString.call(obj) === '[object ' + type + ']';
404
+ },
405
+
406
+ _initXHRData: function (options) {
407
+ var that = this,
408
+ formData,
409
+ file = options.files[0],
410
+ // Ignore non-multipart setting if not supported:
411
+ multipart = options.multipart || !$.support.xhrFileUpload,
412
+ paramName = options.paramName[0];
413
+ options.headers = $.extend({}, options.headers);
414
+ if (options.contentRange) {
415
+ options.headers['Content-Range'] = options.contentRange;
416
+ }
417
+ if (!multipart || options.blob || !this._isInstanceOf('File', file)) {
418
+ options.headers['Content-Disposition'] = 'attachment; filename="' +
419
+ encodeURI(file.name) + '"';
420
+ }
421
+ if (!multipart) {
422
+ options.contentType = file.type;
423
+ options.data = options.blob || file;
424
+ } else if ($.support.xhrFormDataFileUpload) {
425
+ if (options.postMessage) {
426
+ // window.postMessage does not allow sending FormData
427
+ // objects, so we just add the File/Blob objects to
428
+ // the formData array and let the postMessage window
429
+ // create the FormData object out of this array:
430
+ formData = this._getFormData(options);
431
+ if (options.blob) {
432
+ formData.push({
433
+ name: paramName,
434
+ value: options.blob
435
+ });
436
+ } else {
437
+ $.each(options.files, function (index, file) {
438
+ formData.push({
439
+ name: options.paramName[index] || paramName,
440
+ value: file
441
+ });
442
+ });
443
+ }
444
+ } else {
445
+ if (that._isInstanceOf('FormData', options.formData)) {
446
+ formData = options.formData;
447
+ } else {
448
+ formData = new FormData();
449
+ $.each(this._getFormData(options), function (index, field) {
450
+ formData.append(field.name, field.value);
451
+ });
452
+ }
453
+ if (options.blob) {
454
+ formData.append(paramName, options.blob, file.name);
455
+ } else {
456
+ $.each(options.files, function (index, file) {
457
+ // This check allows the tests to run with
458
+ // dummy objects:
459
+ if (that._isInstanceOf('File', file) ||
460
+ that._isInstanceOf('Blob', file)) {
461
+ formData.append(
462
+ options.paramName[index] || paramName,
463
+ file,
464
+ file.name
465
+ );
466
+ }
467
+ });
468
+ }
469
+ }
470
+ options.data = formData;
471
+ }
472
+ // Blob reference is not needed anymore, free memory:
473
+ options.blob = null;
474
+ },
475
+
476
+ _initIframeSettings: function (options) {
477
+ var targetHost = $('<a></a>').prop('href', options.url).prop('host');
478
+ // Setting the dataType to iframe enables the iframe transport:
479
+ options.dataType = 'iframe ' + (options.dataType || '');
480
+ // The iframe transport accepts a serialized array as form data:
481
+ options.formData = this._getFormData(options);
482
+ // Add redirect url to form data on cross-domain uploads:
483
+ if (options.redirect && targetHost && targetHost !== location.host) {
484
+ options.formData.push({
485
+ name: options.redirectParamName || 'redirect',
486
+ value: options.redirect
487
+ });
488
+ }
489
+ },
490
+
491
+ _initDataSettings: function (options) {
492
+ if (this._isXHRUpload(options)) {
493
+ if (!this._chunkedUpload(options, true)) {
494
+ if (!options.data) {
495
+ this._initXHRData(options);
496
+ }
497
+ this._initProgressListener(options);
498
+ }
499
+ if (options.postMessage) {
500
+ // Setting the dataType to postmessage enables the
501
+ // postMessage transport:
502
+ options.dataType = 'postmessage ' + (options.dataType || '');
503
+ }
504
+ } else {
505
+ this._initIframeSettings(options);
506
+ }
507
+ },
508
+
509
+ _getParamName: function (options) {
510
+ var fileInput = $(options.fileInput),
511
+ paramName = options.paramName;
512
+ if (!paramName) {
513
+ paramName = [];
514
+ fileInput.each(function () {
515
+ var input = $(this),
516
+ name = input.prop('name') || 'files[]',
517
+ i = (input.prop('files') || [1]).length;
518
+ while (i) {
519
+ paramName.push(name);
520
+ i -= 1;
521
+ }
522
+ });
523
+ if (!paramName.length) {
524
+ paramName = [fileInput.prop('name') || 'files[]'];
525
+ }
526
+ } else if (!$.isArray(paramName)) {
527
+ paramName = [paramName];
528
+ }
529
+ return paramName;
530
+ },
531
+
532
+ _initFormSettings: function (options) {
533
+ // Retrieve missing options from the input field and the
534
+ // associated form, if available:
535
+ if (!options.form || !options.form.length) {
536
+ options.form = $(options.fileInput.prop('form'));
537
+ // If the given file input doesn't have an associated form,
538
+ // use the default widget file input's form:
539
+ if (!options.form.length) {
540
+ options.form = $(this.options.fileInput.prop('form'));
541
+ }
542
+ }
543
+ options.paramName = this._getParamName(options);
544
+ if (!options.url) {
545
+ options.url = options.form.prop('action') || location.href;
546
+ }
547
+ // The HTTP request method must be "POST" or "PUT":
548
+ options.type = (options.type ||
549
+ ($.type(options.form.prop('method')) === 'string' &&
550
+ options.form.prop('method')) || ''
551
+ ).toUpperCase();
552
+ if (options.type !== 'POST' && options.type !== 'PUT' &&
553
+ options.type !== 'PATCH') {
554
+ options.type = 'POST';
555
+ }
556
+ if (!options.formAcceptCharset) {
557
+ options.formAcceptCharset = options.form.attr('accept-charset');
558
+ }
559
+ },
560
+
561
+ _getAJAXSettings: function (data) {
562
+ var options = $.extend({}, this.options, data);
563
+ this._initFormSettings(options);
564
+ this._initDataSettings(options);
565
+ options.url = options.url+'&rand=' + new Date().getTime();
566
+ return options;
567
+ },
568
+
569
+ // jQuery 1.6 doesn't provide .state(),
570
+ // while jQuery 1.8+ removed .isRejected() and .isResolved():
571
+ _getDeferredState: function (deferred) {
572
+ if (deferred.state) {
573
+ return deferred.state();
574
+ }
575
+ if (deferred.isResolved()) {
576
+ return 'resolved';
577
+ }
578
+ if (deferred.isRejected()) {
579
+ return 'rejected';
580
+ }
581
+ return 'pending';
582
+ },
583
+
584
+ // Maps jqXHR callbacks to the equivalent
585
+ // methods of the given Promise object:
586
+ _enhancePromise: function (promise) {
587
+ promise.success = promise.done;
588
+ promise.error = promise.fail;
589
+ promise.complete = promise.always;
590
+ return promise;
591
+ },
592
+
593
+ // Creates and returns a Promise object enhanced with
594
+ // the jqXHR methods abort, success, error and complete:
595
+ _getXHRPromise: function (resolveOrReject, context, args) {
596
+ var dfd = $.Deferred(),
597
+ promise = dfd.promise();
598
+ context = context || this.options.context || promise;
599
+ if (resolveOrReject === true) {
600
+ dfd.resolveWith(context, args);
601
+ } else if (resolveOrReject === false) {
602
+ dfd.rejectWith(context, args);
603
+ }
604
+ promise.abort = dfd.promise;
605
+ return this._enhancePromise(promise);
606
+ },
607
+
608
+ // Adds convenience methods to the data callback argument:
609
+ _addConvenienceMethods: function (e, data) {
610
+ var that = this,
611
+ getPromise = function (data) {
612
+ return $.Deferred().resolveWith(that, [data]).promise();
613
+ };
614
+ data.process = function (resolveFunc, rejectFunc) {
615
+ if (resolveFunc || rejectFunc) {
616
+ data._processQueue = this._processQueue =
617
+ (this._processQueue || getPromise(this))
618
+ .pipe(resolveFunc, rejectFunc);
619
+ }
620
+ return this._processQueue || getPromise(this);
621
+ };
622
+ data.submit = function () {
623
+ if (this.state() !== 'pending') {
624
+ data.jqXHR = this.jqXHR =
625
+ (that._trigger(
626
+ 'submit',
627
+ $.Event('submit', {delegatedEvent: e}),
628
+ this
629
+ ) !== false) && that._onSend(e, this);
630
+ }
631
+ return this.jqXHR || that._getXHRPromise();
632
+ };
633
+ data.abort = function () {
634
+ if (this.jqXHR) {
635
+ return this.jqXHR.abort();
636
+ }
637
+ return that._getXHRPromise();
638
+ };
639
+ data.state = function () {
640
+ if (this.jqXHR) {
641
+ return that._getDeferredState(this.jqXHR);
642
+ }
643
+ if (this._processQueue) {
644
+ return that._getDeferredState(this._processQueue);
645
+ }
646
+ };
647
+ data.progress = function () {
648
+ return this._progress;
649
+ };
650
+ data.response = function () {
651
+ return this._response;
652
+ };
653
+ },
654
+
655
+ // Parses the Range header from the server response
656
+ // and returns the uploaded bytes:
657
+ _getUploadedBytes: function (jqXHR) {
658
+ var range = jqXHR.getResponseHeader('Range'),
659
+ parts = range && range.split('-'),
660
+ upperBytesPos = parts && parts.length > 1 &&
661
+ parseInt(parts[1], 10);
662
+ return upperBytesPos && upperBytesPos + 1;
663
+ },
664
+
665
+ // Uploads a file in multiple, sequential requests
666
+ // by splitting the file up in multiple blob chunks.
667
+ // If the second parameter is true, only tests if the file
668
+ // should be uploaded in chunks, but does not invoke any
669
+ // upload requests:
670
+ _chunkedUpload: function (options, testOnly) {
671
+ options.uploadedBytes = options.uploadedBytes || 0;
672
+ var that = this,
673
+ file = options.files[0],
674
+ fs = file.size,
675
+ ub = options.uploadedBytes,
676
+ mcs = options.maxChunkSize || fs,
677
+ slice = this._blobSlice,
678
+ dfd = $.Deferred(),
679
+ promise = dfd.promise(),
680
+ jqXHR,
681
+ upload;
682
+ if (!(this._isXHRUpload(options) && slice && (ub || mcs < fs)) ||
683
+ options.data) {
684
+ return false;
685
+ }
686
+ if (testOnly) {
687
+ return true;
688
+ }
689
+ if (ub >= fs) {
690
+ file.error = options.i18n('uploadedBytes');
691
+ return this._getXHRPromise(
692
+ false,
693
+ options.context,
694
+ [null, 'error', file.error]
695
+ );
696
+ }
697
+ // The chunk upload method:
698
+ upload = function () {
699
+ // Clone the options object for each chunk upload:
700
+ var o = $.extend({}, options),
701
+ currentLoaded = o._progress.loaded;
702
+ o.blob = slice.call(
703
+ file,
704
+ ub,
705
+ ub + mcs,
706
+ file.type
707
+ );
708
+ // Store the current chunk size, as the blob itself
709
+ // will be dereferenced after data processing:
710
+ o.chunkSize = o.blob.size;
711
+ // Expose the chunk bytes position range:
712
+ o.contentRange = 'bytes ' + ub + '-' +
713
+ (ub + o.chunkSize - 1) + '/' + fs;
714
+ // Process the upload data (the blob and potential form data):
715
+ that._initXHRData(o);
716
+ // Add progress listeners for this chunk upload:
717
+ that._initProgressListener(o);
718
+ jqXHR = ((that._trigger('chunksend', null, o) !== false && $.ajax(o)) ||
719
+ that._getXHRPromise(false, o.context))
720
+ .done(function (result, textStatus, jqXHR) {
721
+ ub = that._getUploadedBytes(jqXHR) ||
722
+ (ub + o.chunkSize);
723
+ // Create a progress event if no final progress event
724
+ // with loaded equaling total has been triggered
725
+ // for this chunk:
726
+ if (currentLoaded + o.chunkSize - o._progress.loaded) {
727
+ that._onProgress($.Event('progress', {
728
+ lengthComputable: true,
729
+ loaded: ub - o.uploadedBytes,
730
+ total: ub - o.uploadedBytes
731
+ }), o);
732
+ }
733
+ options.uploadedBytes = o.uploadedBytes = ub;
734
+ o.result = result;
735
+ o.textStatus = textStatus;
736
+ o.jqXHR = jqXHR;
737
+ that._trigger('chunkdone', null, o);
738
+ that._trigger('chunkalways', null, o);
739
+ if (ub < fs) {
740
+ // File upload not yet complete,
741
+ // continue with the next chunk:
742
+ upload();
743
+ } else {
744
+ dfd.resolveWith(
745
+ o.context,
746
+ [result, textStatus, jqXHR]
747
+ );
748
+ }
749
+ })
750
+ .fail(function (jqXHR, textStatus, errorThrown) {
751
+ o.jqXHR = jqXHR;
752
+ o.textStatus = textStatus;
753
+ o.errorThrown = errorThrown;
754
+ that._trigger('chunkfail', null, o);
755
+ that._trigger('chunkalways', null, o);
756
+ dfd.rejectWith(
757
+ o.context,
758
+ [jqXHR, textStatus, errorThrown]
759
+ );
760
+ });
761
+ };
762
+ this._enhancePromise(promise);
763
+ promise.abort = function () {
764
+ return jqXHR.abort();
765
+ };
766
+ upload();
767
+ return promise;
768
+ },
769
+
770
+ _beforeSend: function (e, data) {
771
+ if (this._active === 0) {
772
+ // the start callback is triggered when an upload starts
773
+ // and no other uploads are currently running,
774
+ // equivalent to the global ajaxStart event:
775
+ this._trigger('start');
776
+ // Set timer for global bitrate progress calculation:
777
+ this._bitrateTimer = new this._BitrateTimer();
778
+ // Reset the global progress values:
779
+ this._progress.loaded = this._progress.total = 0;
780
+ this._progress.bitrate = 0;
781
+ }
782
+ // Make sure the container objects for the .response() and
783
+ // .progress() methods on the data object are available
784
+ // and reset to their initial state:
785
+ this._initResponseObject(data);
786
+ this._initProgressObject(data);
787
+ data._progress.loaded = data.loaded = data.uploadedBytes || 0;
788
+ data._progress.total = data.total = this._getTotal(data.files) || 1;
789
+ data._progress.bitrate = data.bitrate = 0;
790
+ this._active += 1;
791
+ // Initialize the global progress values:
792
+ this._progress.loaded += data.loaded;
793
+ this._progress.total += data.total;
794
+ },
795
+
796
+ _onDone: function (result, textStatus, jqXHR, options) {
797
+ var total = options._progress.total,
798
+ response = options._response;
799
+ if (options._progress.loaded < total) {
800
+ // Create a progress event if no final progress event
801
+ // with loaded equaling total has been triggered:
802
+ this._onProgress($.Event('progress', {
803
+ lengthComputable: true,
804
+ loaded: total,
805
+ total: total
806
+ }), options);
807
+ }
808
+ response.result = options.result = result;
809
+ response.textStatus = options.textStatus = textStatus;
810
+ response.jqXHR = options.jqXHR = jqXHR;
811
+ this._trigger('done', null, options);
812
+ },
813
+
814
+ _onFail: function (jqXHR, textStatus, errorThrown, options) {
815
+ var response = options._response;
816
+ if (options.recalculateProgress) {
817
+ // Remove the failed (error or abort) file upload from
818
+ // the global progress calculation:
819
+ this._progress.loaded -= options._progress.loaded;
820
+ this._progress.total -= options._progress.total;
821
+ }
822
+ response.jqXHR = options.jqXHR = jqXHR;
823
+ response.textStatus = options.textStatus = textStatus;
824
+ response.errorThrown = options.errorThrown = errorThrown;
825
+ this._trigger('fail', null, options);
826
+ },
827
+
828
+ _onAlways: function (jqXHRorResult, textStatus, jqXHRorError, options) {
829
+ // jqXHRorResult, textStatus and jqXHRorError are added to the
830
+ // options object via done and fail callbacks
831
+ this._trigger('always', null, options);
832
+ },
833
+
834
+ _onSend: function (e, data) {
835
+ if (!data.submit) {
836
+ this._addConvenienceMethods(e, data);
837
+ }
838
+ var that = this,
839
+ jqXHR,
840
+ aborted,
841
+ slot,
842
+ pipe,
843
+ options = that._getAJAXSettings(data),
844
+ send = function () {
845
+ that._sending += 1;
846
+ // Set timer for bitrate progress calculation:
847
+ options._bitrateTimer = new that._BitrateTimer();
848
+ jqXHR = jqXHR || (
849
+ ((aborted || that._trigger(
850
+ 'send',
851
+ $.Event('send', {delegatedEvent: e}),
852
+ options
853
+ ) === false) &&
854
+ that._getXHRPromise(false, options.context, aborted)) ||
855
+ that._chunkedUpload(options) || $.ajax(options)
856
+ ).done(function (result, textStatus, jqXHR) {
857
+ that._onDone(result, textStatus, jqXHR, options);
858
+ }).fail(function (jqXHR, textStatus, errorThrown) {
859
+ that._onFail(jqXHR, textStatus, errorThrown, options);
860
+ }).always(function (jqXHRorResult, textStatus, jqXHRorError) {
861
+ that._onAlways(
862
+ jqXHRorResult,
863
+ textStatus,
864
+ jqXHRorError,
865
+ options
866
+ );
867
+ that._sending -= 1;
868
+ that._active -= 1;
869
+ if (options.limitConcurrentUploads &&
870
+ options.limitConcurrentUploads > that._sending) {
871
+ // Start the next queued upload,
872
+ // that has not been aborted:
873
+ var nextSlot = that._slots.shift();
874
+ while (nextSlot) {
875
+ if (that._getDeferredState(nextSlot) === 'pending') {
876
+ nextSlot.resolve();
877
+ break;
878
+ }
879
+ nextSlot = that._slots.shift();
880
+ }
881
+ }
882
+ if (that._active === 0) {
883
+ // The stop callback is triggered when all uploads have
884
+ // been completed, equivalent to the global ajaxStop event:
885
+ that._trigger('stop');
886
+ }
887
+ });
888
+ return jqXHR;
889
+ };
890
+ this._beforeSend(e, options);
891
+ if (this.options.sequentialUploads ||
892
+ (this.options.limitConcurrentUploads &&
893
+ this.options.limitConcurrentUploads <= this._sending)) {
894
+ if (this.options.limitConcurrentUploads > 1) {
895
+ slot = $.Deferred();
896
+ this._slots.push(slot);
897
+ pipe = slot.pipe(send);
898
+ } else {
899
+ this._sequence = this._sequence.pipe(send, send);
900
+ pipe = this._sequence;
901
+ }
902
+ // Return the piped Promise object, enhanced with an abort method,
903
+ // which is delegated to the jqXHR object of the current upload,
904
+ // and jqXHR callbacks mapped to the equivalent Promise methods:
905
+ pipe.abort = function () {
906
+ aborted = [undefined, 'abort', 'abort'];
907
+ if (!jqXHR) {
908
+ if (slot) {
909
+ slot.rejectWith(options.context, aborted);
910
+ }
911
+ return send();
912
+ }
913
+ return jqXHR.abort();
914
+ };
915
+ return this._enhancePromise(pipe);
916
+ }
917
+ return send();
918
+ },
919
+
920
+ _onAdd: function (e, data) {
921
+ var that = this,
922
+ result = true,
923
+ options = $.extend({}, this.options, data),
924
+ limit = options.limitMultiFileUploads,
925
+ paramName = this._getParamName(options),
926
+ paramNameSet,
927
+ paramNameSlice,
928
+ fileSet,
929
+ i;
930
+ if (!(options.singleFileUploads || limit) ||
931
+ !this._isXHRUpload(options)) {
932
+ fileSet = [data.files];
933
+ paramNameSet = [paramName];
934
+ } else if (!options.singleFileUploads && limit) {
935
+ fileSet = [];
936
+ paramNameSet = [];
937
+ for (i = 0; i < data.files.length; i += limit) {
938
+ fileSet.push(data.files.slice(i, i + limit));
939
+ paramNameSlice = paramName.slice(i, i + limit);
940
+ if (!paramNameSlice.length) {
941
+ paramNameSlice = paramName;
942
+ }
943
+ paramNameSet.push(paramNameSlice);
944
+ }
945
+ } else {
946
+ paramNameSet = paramName;
947
+ }
948
+ data.originalFiles = data.files;
949
+ $.each(fileSet || data.files, function (index, element) {
950
+ var newData = $.extend({}, data);
951
+ newData.files = fileSet ? element : [element];
952
+ newData.paramName = paramNameSet[index];
953
+ that._initResponseObject(newData);
954
+ that._initProgressObject(newData);
955
+ that._addConvenienceMethods(e, newData);
956
+ result = that._trigger(
957
+ 'add',
958
+ $.Event('add', {delegatedEvent: e}),
959
+ newData
960
+ );
961
+ return result;
962
+ });
963
+ return result;
964
+ },
965
+
966
+ _replaceFileInput: function (input) {
967
+ var inputClone = input.clone(true);
968
+ $('<form></form>').append(inputClone)[0].reset();
969
+ // Detaching allows to insert the fileInput on another form
970
+ // without loosing the file input value:
971
+ input.after(inputClone).detach();
972
+ // Avoid memory leaks with the detached file input:
973
+ $.cleanData(input.unbind('remove'));
974
+ // Replace the original file input element in the fileInput
975
+ // elements set with the clone, which has been copied including
976
+ // event handlers:
977
+ this.options.fileInput = this.options.fileInput.map(function (i, el) {
978
+ if (el === input[0]) {
979
+ return inputClone[0];
980
+ }
981
+ return el;
982
+ });
983
+ // If the widget has been initialized on the file input itself,
984
+ // override this.element with the file input clone:
985
+ if (input[0] === this.element[0]) {
986
+ this.element = inputClone;
987
+ }
988
+ },
989
+
990
+ _handleFileTreeEntry: function (entry, path) {
991
+ var that = this,
992
+ dfd = $.Deferred(),
993
+ errorHandler = function (e) {
994
+ if (e && !e.entry) {
995
+ e.entry = entry;
996
+ }
997
+ // Since $.when returns immediately if one
998
+ // Deferred is rejected, we use resolve instead.
999
+ // This allows valid files and invalid items
1000
+ // to be returned together in one set:
1001
+ dfd.resolve([e]);
1002
+ },
1003
+ dirReader;
1004
+ path = path || '';
1005
+ if (entry.isFile) {
1006
+ if (entry._file) {
1007
+ // Workaround for Chrome bug #149735
1008
+ entry._file.relativePath = path;
1009
+ dfd.resolve(entry._file);
1010
+ } else {
1011
+ entry.file(function (file) {
1012
+ file.relativePath = path;
1013
+ dfd.resolve(file);
1014
+ }, errorHandler);
1015
+ }
1016
+ } else if (entry.isDirectory) {
1017
+ dirReader = entry.createReader();
1018
+ dirReader.readEntries(function (entries) {
1019
+ that._handleFileTreeEntries(
1020
+ entries,
1021
+ path + entry.name + '/'
1022
+ ).done(function (files) {
1023
+ dfd.resolve(files);
1024
+ }).fail(errorHandler);
1025
+ }, errorHandler);
1026
+ } else {
1027
+ // Return an empy list for file system items
1028
+ // other than files or directories:
1029
+ dfd.resolve([]);
1030
+ }
1031
+ return dfd.promise();
1032
+ },
1033
+
1034
+ _handleFileTreeEntries: function (entries, path) {
1035
+ var that = this;
1036
+ return $.when.apply(
1037
+ $,
1038
+ $.map(entries, function (entry) {
1039
+ return that._handleFileTreeEntry(entry, path);
1040
+ })
1041
+ ).pipe(function () {
1042
+ return Array.prototype.concat.apply(
1043
+ [],
1044
+ arguments
1045
+ );
1046
+ });
1047
+ },
1048
+
1049
+ _getDroppedFiles: function (dataTransfer) {
1050
+ dataTransfer = dataTransfer || {};
1051
+ var items = dataTransfer.items;
1052
+ if (items && items.length && (items[0].webkitGetAsEntry ||
1053
+ items[0].getAsEntry)) {
1054
+ return this._handleFileTreeEntries(
1055
+ $.map(items, function (item) {
1056
+ var entry;
1057
+ if (item.webkitGetAsEntry) {
1058
+ entry = item.webkitGetAsEntry();
1059
+ if (entry) {
1060
+ // Workaround for Chrome bug #149735:
1061
+ entry._file = item.getAsFile();
1062
+ }
1063
+ return entry;
1064
+ }
1065
+ return item.getAsEntry();
1066
+ })
1067
+ );
1068
+ }
1069
+ return $.Deferred().resolve(
1070
+ $.makeArray(dataTransfer.files)
1071
+ ).promise();
1072
+ },
1073
+
1074
+ _getSingleFileInputFiles: function (fileInput) {
1075
+ fileInput = $(fileInput);
1076
+ var entries = fileInput.prop('webkitEntries') ||
1077
+ fileInput.prop('entries'),
1078
+ files,
1079
+ value;
1080
+ if (entries && entries.length) {
1081
+ return this._handleFileTreeEntries(entries);
1082
+ }
1083
+ files = $.makeArray(fileInput.prop('files'));
1084
+ if (!files.length) {
1085
+ value = fileInput.prop('value');
1086
+ if (!value) {
1087
+ return $.Deferred().resolve([]).promise();
1088
+ }
1089
+ // If the files property is not available, the browser does not
1090
+ // support the File API and we add a pseudo File object with
1091
+ // the input value as name with path information removed:
1092
+ files = [{name: value.replace(/^.*\\/, '')}];
1093
+ } else if (files[0].name === undefined && files[0].fileName) {
1094
+ // File normalization for Safari 4 and Firefox 3:
1095
+ $.each(files, function (index, file) {
1096
+ file.name = file.fileName;
1097
+ file.size = file.fileSize;
1098
+ });
1099
+ }
1100
+ return $.Deferred().resolve(files).promise();
1101
+ },
1102
+
1103
+ _getFileInputFiles: function (fileInput) {
1104
+ if (!(fileInput instanceof $) || fileInput.length === 1) {
1105
+ return this._getSingleFileInputFiles(fileInput);
1106
+ }
1107
+ return $.when.apply(
1108
+ $,
1109
+ $.map(fileInput, this._getSingleFileInputFiles)
1110
+ ).pipe(function () {
1111
+ return Array.prototype.concat.apply(
1112
+ [],
1113
+ arguments
1114
+ );
1115
+ });
1116
+ },
1117
+
1118
+ _onChange: function (e) {
1119
+ var that = this,
1120
+ data = {
1121
+ fileInput: $(e.target),
1122
+ form: $(e.target.form)
1123
+ };
1124
+ this._getFileInputFiles(data.fileInput).always(function (files) {
1125
+ data.files = files;
1126
+ if (that.options.replaceFileInput) {
1127
+ that._replaceFileInput(data.fileInput);
1128
+ }
1129
+ if (that._trigger(
1130
+ 'change',
1131
+ $.Event('change', {delegatedEvent: e}),
1132
+ data
1133
+ ) !== false) {
1134
+ that._onAdd(e, data);
1135
+ }
1136
+ });
1137
+ },
1138
+
1139
+ _onPaste: function (e) {
1140
+ var items = e.originalEvent && e.originalEvent.clipboardData &&
1141
+ e.originalEvent.clipboardData.items,
1142
+ data = {files: []};
1143
+ if (items && items.length) {
1144
+ $.each(items, function (index, item) {
1145
+ var file = item.getAsFile && item.getAsFile();
1146
+ if (file) {
1147
+ data.files.push(file);
1148
+ }
1149
+ });
1150
+ if (this._trigger(
1151
+ 'paste',
1152
+ $.Event('paste', {delegatedEvent: e}),
1153
+ data
1154
+ ) !== false) {
1155
+ this._onAdd(e, data);
1156
+ }
1157
+ }
1158
+ },
1159
+
1160
+ _onDrop: function (e) {
1161
+ e.dataTransfer = e.originalEvent && e.originalEvent.dataTransfer;
1162
+ var that = this,
1163
+ dataTransfer = e.dataTransfer,
1164
+ data = {};
1165
+ if (dataTransfer && dataTransfer.files && dataTransfer.files.length) {
1166
+ e.preventDefault();
1167
+ this._getDroppedFiles(dataTransfer).always(function (files) {
1168
+ data.files = files;
1169
+ if (that._trigger(
1170
+ 'drop',
1171
+ $.Event('drop', {delegatedEvent: e}),
1172
+ data
1173
+ ) !== false) {
1174
+ that._onAdd(e, data);
1175
+ }
1176
+ });
1177
+ }
1178
+ },
1179
+
1180
+ _onDragOver: function (e) {
1181
+ e.dataTransfer = e.originalEvent && e.originalEvent.dataTransfer;
1182
+ var dataTransfer = e.dataTransfer;
1183
+ if (dataTransfer && $.inArray('Files', dataTransfer.types) !== -1 &&
1184
+ this._trigger(
1185
+ 'dragover',
1186
+ $.Event('dragover', {delegatedEvent: e})
1187
+ ) !== false) {
1188
+ e.preventDefault();
1189
+ dataTransfer.dropEffect = 'copy';
1190
+ }
1191
+ },
1192
+
1193
+ _initEventHandlers: function () {
1194
+ if (this._isXHRUpload(this.options)) {
1195
+ this._on(this.options.dropZone, {
1196
+ dragover: this._onDragOver,
1197
+ drop: this._onDrop
1198
+ });
1199
+ this._on(this.options.pasteZone, {
1200
+ paste: this._onPaste
1201
+ });
1202
+ }
1203
+ if ($.support.fileInput) {
1204
+ this._on(this.options.fileInput, {
1205
+ change: this._onChange
1206
+ });
1207
+ }
1208
+ },
1209
+
1210
+ _destroyEventHandlers: function () {
1211
+ this._off(this.options.dropZone, 'dragover drop');
1212
+ this._off(this.options.pasteZone, 'paste');
1213
+ this._off(this.options.fileInput, 'change');
1214
+ },
1215
+
1216
+ _setOption: function (key, value) {
1217
+ var reinit = $.inArray(key, this._specialOptions) !== -1;
1218
+ if (reinit) {
1219
+ this._destroyEventHandlers();
1220
+ }
1221
+ this._super(key, value);
1222
+ if (reinit) {
1223
+ this._initSpecialOptions();
1224
+ this._initEventHandlers();
1225
+ }
1226
+ },
1227
+
1228
+ _initSpecialOptions: function () {
1229
+ var options = this.options;
1230
+ if (options.fileInput === undefined) {
1231
+ options.fileInput = this.element.is('input[type="file"]') ?
1232
+ this.element : this.element.find('input[type="file"]');
1233
+ } else if (!(options.fileInput instanceof $)) {
1234
+ options.fileInput = $(options.fileInput);
1235
+ }
1236
+ if (!(options.dropZone instanceof $)) {
1237
+ options.dropZone = $(options.dropZone);
1238
+ }
1239
+ if (!(options.pasteZone instanceof $)) {
1240
+ options.pasteZone = $(options.pasteZone);
1241
+ }
1242
+ },
1243
+
1244
+ _getRegExp: function (str) {
1245
+ var parts = str.split('/'),
1246
+ modifiers = parts.pop();
1247
+ parts.shift();
1248
+ return new RegExp(parts.join('/'), modifiers);
1249
+ },
1250
+
1251
+ _isRegExpOption: function (key, value) {
1252
+ return key !== 'url' && $.type(value) === 'string' &&
1253
+ /^\/.*\/[igm]{0,3}$/.test(value);
1254
+ },
1255
+
1256
+ _initDataAttributes: function () {
1257
+ var that = this,
1258
+ options = this.options;
1259
+ // Initialize options set via HTML5 data-attributes:
1260
+ $.each(
1261
+ $(this.element[0].cloneNode(false)).data(),
1262
+ function (key, value) {
1263
+ if (that._isRegExpOption(key, value)) {
1264
+ value = that._getRegExp(value);
1265
+ }
1266
+ options[key] = value;
1267
+ }
1268
+ );
1269
+ },
1270
+
1271
+ _create: function () {
1272
+ this._initDataAttributes();
1273
+ this._initSpecialOptions();
1274
+ this._slots = [];
1275
+ this._sequence = this._getXHRPromise(true);
1276
+ this._sending = this._active = 0;
1277
+ this._initProgressObject(this);
1278
+ this._initEventHandlers();
1279
+ },
1280
+
1281
+ // This method is exposed to the widget API and allows to query
1282
+ // the number of active uploads:
1283
+ active: function () {
1284
+ return this._active;
1285
+ },
1286
+
1287
+ // This method is exposed to the widget API and allows to query
1288
+ // the widget upload progress.
1289
+ // It returns an object with loaded, total and bitrate properties
1290
+ // for the running uploads:
1291
+ progress: function () {
1292
+ return this._progress;
1293
+ },
1294
+
1295
+ // This method is exposed to the widget API and allows adding files
1296
+ // using the fileupload API. The data parameter accepts an object which
1297
+ // must have a files property and can contain additional options:
1298
+ // .fileupload('add', {files: filesList});
1299
+ add: function (data) {
1300
+ var that = this;
1301
+ if (!data || this.options.disabled) {
1302
+ return;
1303
+ }
1304
+ if (data.fileInput && !data.files) {
1305
+ this._getFileInputFiles(data.fileInput).always(function (files) {
1306
+ data.files = files;
1307
+ that._onAdd(null, data);
1308
+ });
1309
+ } else {
1310
+ data.files = $.makeArray(data.files);
1311
+ this._onAdd(null, data);
1312
+ }
1313
+ },
1314
+
1315
+ // This method is exposed to the widget API and allows sending files
1316
+ // using the fileupload API. The data parameter accepts an object which
1317
+ // must have a files or fileInput property and can contain additional options:
1318
+ // .fileupload('send', {files: filesList});
1319
+ // The method returns a Promise object for the file upload call.
1320
+ send: function (data) {
1321
+ if (data && !this.options.disabled) {
1322
+ if (data.fileInput && !data.files) {
1323
+ var that = this,
1324
+ dfd = $.Deferred(),
1325
+ promise = dfd.promise(),
1326
+ jqXHR,
1327
+ aborted;
1328
+ promise.abort = function () {
1329
+ aborted = true;
1330
+ if (jqXHR) {
1331
+ return jqXHR.abort();
1332
+ }
1333
+ dfd.reject(null, 'abort', 'abort');
1334
+ return promise;
1335
+ };
1336
+ this._getFileInputFiles(data.fileInput).always(
1337
+ function (files) {
1338
+ if (aborted) {
1339
+ return;
1340
+ }
1341
+ if (!files.length) {
1342
+ dfd.reject();
1343
+ return;
1344
+ }
1345
+ data.files = files;
1346
+ jqXHR = that._onSend(null, data).then(
1347
+ function (result, textStatus, jqXHR) {
1348
+ dfd.resolve(result, textStatus, jqXHR);
1349
+ },
1350
+ function (jqXHR, textStatus, errorThrown) {
1351
+ dfd.reject(jqXHR, textStatus, errorThrown);
1352
+ }
1353
+ );
1354
+ }
1355
+ );
1356
+ return this._enhancePromise(promise);
1357
+ }
1358
+ data.files = $.makeArray(data.files);
1359
+ if (data.files.length) {
1360
+ return this._onSend(null, data);
1361
+ }
1362
+ }
1363
+ return this._getXHRPromise(false, data && data.context);
1364
+ }
1365
+
1366
+ });
1367
+
1368
+ }));
js/axzoom/jquery.ui.widget.min.js ADDED
@@ -0,0 +1,4 @@
 
 
 
 
1
+ /*! jQuery UI - v1.10.3 - 2013-05-03
2
+ * http://jqueryui.com
3
+ * Copyright 2013 jQuery Foundation and other contributors; Licensed MIT */
4
+ (function(e,t){var i=0,s=Array.prototype.slice,n=e.cleanData;e.cleanData=function(t){for(var i,s=0;null!=(i=t[s]);s++)try{e(i).triggerHandler("remove")}catch(a){}n(t)},e.widget=function(i,s,n){var a,r,o,h,l={},u=i.split(".")[0];i=i.split(".")[1],a=u+"-"+i,n||(n=s,s=e.Widget),e.expr[":"][a.toLowerCase()]=function(t){return!!e.data(t,a)},e[u]=e[u]||{},r=e[u][i],o=e[u][i]=function(e,i){return this._createWidget?(arguments.length&&this._createWidget(e,i),t):new o(e,i)},e.extend(o,r,{version:n.version,_proto:e.extend({},n),_childConstructors:[]}),h=new s,h.options=e.widget.extend({},h.options),e.each(n,function(i,n){return e.isFunction(n)?(l[i]=function(){var e=function(){return s.prototype[i].apply(this,arguments)},t=function(e){return s.prototype[i].apply(this,e)};return function(){var i,s=this._super,a=this._superApply;return this._super=e,this._superApply=t,i=n.apply(this,arguments),this._super=s,this._superApply=a,i}}(),t):(l[i]=n,t)}),o.prototype=e.widget.extend(h,{widgetEventPrefix:r?h.widgetEventPrefix:i},l,{constructor:o,namespace:u,widgetName:i,widgetFullName:a}),r?(e.each(r._childConstructors,function(t,i){var s=i.prototype;e.widget(s.namespace+"."+s.widgetName,o,i._proto)}),delete r._childConstructors):s._childConstructors.push(o),e.widget.bridge(i,o)},e.widget.extend=function(i){for(var n,a,r=s.call(arguments,1),o=0,h=r.length;h>o;o++)for(n in r[o])a=r[o][n],r[o].hasOwnProperty(n)&&a!==t&&(i[n]=e.isPlainObject(a)?e.isPlainObject(i[n])?e.widget.extend({},i[n],a):e.widget.extend({},a):a);return i},e.widget.bridge=function(i,n){var a=n.prototype.widgetFullName||i;e.fn[i]=function(r){var o="string"==typeof r,h=s.call(arguments,1),l=this;return r=!o&&h.length?e.widget.extend.apply(null,[r].concat(h)):r,o?this.each(function(){var s,n=e.data(this,a);return n?e.isFunction(n[r])&&"_"!==r.charAt(0)?(s=n[r].apply(n,h),s!==n&&s!==t?(l=s&&s.jquery?l.pushStack(s.get()):s,!1):t):e.error("no such method '"+r+"' for "+i+" widget instance"):e.error("cannot call methods on "+i+" prior to initialization; "+"attempted to call method '"+r+"'")}):this.each(function(){var t=e.data(this,a);t?t.option(r||{})._init():e.data(this,a,new n(r,this))}),l}},e.Widget=function(){},e.Widget._childConstructors=[],e.Widget.prototype={widgetName:"widget",widgetEventPrefix:"",defaultElement:"<div>",options:{disabled:!1,create:null},_createWidget:function(t,s){s=e(s||this.defaultElement||this)[0],this.element=e(s),this.uuid=i++,this.eventNamespace="."+this.widgetName+this.uuid,this.options=e.widget.extend({},this.options,this._getCreateOptions(),t),this.bindings=e(),this.hoverable=e(),this.focusable=e(),s!==this&&(e.data(s,this.widgetFullName,this),this._on(!0,this.element,{remove:function(e){e.target===s&&this.destroy()}}),this.document=e(s.style?s.ownerDocument:s.document||s),this.window=e(this.document[0].defaultView||this.document[0].parentWindow)),this._create(),this._trigger("create",null,this._getCreateEventData()),this._init()},_getCreateOptions:e.noop,_getCreateEventData:e.noop,_create:e.noop,_init:e.noop,destroy:function(){this._destroy(),this.element.unbind(this.eventNamespace).removeData(this.widgetName).removeData(this.widgetFullName).removeData(e.camelCase(this.widgetFullName)),this.widget().unbind(this.eventNamespace).removeAttr("aria-disabled").removeClass(this.widgetFullName+"-disabled "+"ui-state-disabled"),this.bindings.unbind(this.eventNamespace),this.hoverable.removeClass("ui-state-hover"),this.focusable.removeClass("ui-state-focus")},_destroy:e.noop,widget:function(){return this.element},option:function(i,s){var n,a,r,o=i;if(0===arguments.length)return e.widget.extend({},this.options);if("string"==typeof i)if(o={},n=i.split("."),i=n.shift(),n.length){for(a=o[i]=e.widget.extend({},this.options[i]),r=0;n.length-1>r;r++)a[n[r]]=a[n[r]]||{},a=a[n[r]];if(i=n.pop(),s===t)return a[i]===t?null:a[i];a[i]=s}else{if(s===t)return this.options[i]===t?null:this.options[i];o[i]=s}return this._setOptions(o),this},_setOptions:function(e){var t;for(t in e)this._setOption(t,e[t]);return this},_setOption:function(e,t){return this.options[e]=t,"disabled"===e&&(this.widget().toggleClass(this.widgetFullName+"-disabled ui-state-disabled",!!t).attr("aria-disabled",t),this.hoverable.removeClass("ui-state-hover"),this.focusable.removeClass("ui-state-focus")),this},enable:function(){return this._setOption("disabled",!1)},disable:function(){return this._setOption("disabled",!0)},_on:function(i,s,n){var a,r=this;"boolean"!=typeof i&&(n=s,s=i,i=!1),n?(s=a=e(s),this.bindings=this.bindings.add(s)):(n=s,s=this.element,a=this.widget()),e.each(n,function(n,o){function h(){return i||r.options.disabled!==!0&&!e(this).hasClass("ui-state-disabled")?("string"==typeof o?r[o]:o).apply(r,arguments):t}"string"!=typeof o&&(h.guid=o.guid=o.guid||h.guid||e.guid++);var l=n.match(/^(\w+)\s*(.*)$/),u=l[1]+r.eventNamespace,c=l[2];c?a.delegate(c,u,h):s.bind(u,h)})},_off:function(e,t){t=(t||"").split(" ").join(this.eventNamespace+" ")+this.eventNamespace,e.unbind(t).undelegate(t)},_delay:function(e,t){function i(){return("string"==typeof e?s[e]:e).apply(s,arguments)}var s=this;return setTimeout(i,t||0)},_hoverable:function(t){this.hoverable=this.hoverable.add(t),this._on(t,{mouseenter:function(t){e(t.currentTarget).addClass("ui-state-hover")},mouseleave:function(t){e(t.currentTarget).removeClass("ui-state-hover")}})},_focusable:function(t){this.focusable=this.focusable.add(t),this._on(t,{focusin:function(t){e(t.currentTarget).addClass("ui-state-focus")},focusout:function(t){e(t.currentTarget).removeClass("ui-state-focus")}})},_trigger:function(t,i,s){var n,a,r=this.options[t];if(s=s||{},i=e.Event(i),i.type=(t===this.widgetEventPrefix?t:this.widgetEventPrefix+t).toLowerCase(),i.target=this.element[0],a=i.originalEvent)for(n in a)n in i||(i[n]=a[n]);return this.element.trigger(i,s),!(e.isFunction(r)&&r.apply(this.element[0],[i].concat(s))===!1||i.isDefaultPrevented())}},e.each({show:"fadeIn",hide:"fadeOut"},function(t,i){e.Widget.prototype["_"+t]=function(s,n,a){"string"==typeof n&&(n={effect:n});var r,o=n?n===!0||"number"==typeof n?i:n.effect||i:t;n=n||{},"number"==typeof n&&(n={duration:n}),r=!e.isEmptyObject(n),n.complete=a,n.delay&&s.delay(n.delay),r&&e.effects&&e.effects.effect[o]?s[t](n):o!==t&&s[o]?s[o](n.duration,n.easing,a):s.queue(function(i){e(this)[t](),a&&a.call(s[0]),i()})}})})(jQuery);
js/axzoom/lic.php ADDED
@@ -0,0 +1,30 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ $obj = SimpleXML_Load_String(implode('', file('../../../app/etc/local.xml')));
4
+ $mysqli = mysqli_connect(preg_replace('/:[0-9]{1,}$/', '', (string)$obj->global->resources->default_setup->connection->host), (string)$obj->global->resources->default_setup->connection->username, (string)$obj->global->resources->default_setup->connection->password, (string)$obj->global->resources->default_setup->connection->dbname);
5
+
6
+ $data_query = mysqli_query($mysqli, "SELECT `value` FROM `" . (string)$obj->global->resources->db->table_prefix . "core_config_data` WHERE `path` = 'axzoom_options/license/lic'");
7
+ $data = mysqli_fetch_array($data_query);
8
+ $tmp = unserialize($data['value']);
9
+
10
+ foreach ($tmp as $key => $l) {
11
+ $_SESSION['axZmLicenses'][$l['domain']] = array(
12
+ 'licenceType' => $l['type'],
13
+ 'licenceKey' => $l['license'],
14
+ 'error200' => $l['error200'],
15
+ 'error300' => $l['error300']
16
+ );
17
+ }
18
+
19
+
20
+ /*
21
+ $_SESSION['axZmLicenses'] = array(
22
+ 'magento.ajax-zoom.com' => array(
23
+ 'licenceType' => 'unlimited',
24
+ 'licenceKey' => 'FCEdPAkJUGgsPVJJByIhXAtdIC00',
25
+ 'error200' => '',
26
+ 'error300' => ''
27
+ ));
28
+ */
29
+
30
+
js/axzoom/no_image-100x100.jpg ADDED
Binary file
js/axzoom/pic/readme.txt ADDED
@@ -0,0 +1 @@
 
1
+ An all media files will be stored in the folder
js/axzoom/preview/index.php ADDED
@@ -0,0 +1,11 @@
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ header('Expires: Mon, 26 Jul 1997 05:00:00 GMT');
3
+ header('Last-Modified: '.gmdate('D, d M Y H:i:s').' GMT');
4
+
5
+ header('Cache-Control: no-store, no-cache, must-revalidate');
6
+ header('Cache-Control: post-check=0, pre-check=0', false);
7
+ header('Pragma: no-cache');
8
+
9
+ header('Location: ../');
10
+ exit;
11
+ ?>
js/axzoom/preview/preview.php ADDED
@@ -0,0 +1,273 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ require_once('../../../app/Mage.php');
3
+ umask(0);
4
+ Mage::app();
5
+
6
+
7
+ ini_set('display_errors', 1);
8
+ error_reporting(E_ALL);
9
+
10
+
11
+ function getIssetMod($par){
12
+ return isset($par);
13
+ }
14
+
15
+ function getValueMod($par){
16
+ return Mage::app()->getRequest()->getParam($par);
17
+ }
18
+
19
+ if (!( getIssetMod('3dDir') || getIssetMod('zoomData') || getIssetMod('zoomDir'))){
20
+ echo 'No parameters passed';
21
+ exit;
22
+ }
23
+
24
+ $conf = array();
25
+ $conf_array = Mage::getStoreConfig('axzoom_options');
26
+ foreach($conf_array as $group => $data) {
27
+ foreach($data as $key => $value) {
28
+ $conf['AJAXZOOM_' . strtoupper($group . '_' . $key)] = $value;
29
+ }
30
+ }
31
+
32
+ $conf360 = Mage::getModel('axzoom/ax360')->load((int)(getValueMod('group')))->getData();
33
+
34
+ $example = getValueMod('example');
35
+
36
+ if (!getIssetMod('example')){
37
+ if ($conf['AJAXZOOM_MAIN_IMAGES360PREVIEW']){
38
+ $example = $conf['AJAXZOOM_MAIN_IMAGES360EXAMPLEPREVIEW'];
39
+ }else{
40
+ $example = $conf['AJAXZOOM_MAIN_EXAMPLEFANCYBOXFULLSCREEN'];
41
+ }
42
+ }
43
+
44
+ ?>
45
+ <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
46
+ <html xmlns="http://www.w3.org/1999/xhtml">
47
+ <head>
48
+ <title>AJAX-ZOOM Preview</title>
49
+ <meta http-equiv="Content-Type" content="text/html; charset=utf-8">
50
+ <meta http-equiv="imagetoolbar" content="no">
51
+
52
+ <?php
53
+ // Set scale for iPhone and disable user scalability
54
+ if (strpos($_SERVER['HTTP_USER_AGENT'],"iPhone")){
55
+ echo "<meta name=\"viewport\" content=\"width=device-width, minimum-scale=0.5, maximum-scale=0.5, user-scalable=no\">";
56
+ }else{
57
+ echo "<meta name=\"viewport\" content=\"width=device-width, minimum-scale=1, maximum-scale=1, user-scalable=no\">";
58
+ }
59
+ ?>
60
+
61
+ <style type="text/css" media="screen">
62
+ html {height: 100%; width: 100%; font-family: Tahoma, Arial; font-size: 10pt; margin: 0; padding: 0;}
63
+ body {height: 100%; width: 100%; overflow: hidden; margin: 0; padding: 0;}
64
+ body:-webkit-fullscreen {width: 100%; height: 100%;}
65
+ body:-ms-fullscreen {width: 100%; height: 100%;}
66
+ a {color: blue; outline: 0; outline-style: none; text-decoration: none;} a:visited {color: blue;} a:hover {color: green;}
67
+ h2 {padding:0px; margin: 35px 0px 15px 0px; font-size: 22px;}
68
+ h3 {font-family: Arial; color: #1A4A7A; font-size: 18px; padding: 20px 0px 3px 0px; margin: 0;}
69
+ p {text-align: justify; text-justify: newspaper;}
70
+ </style>
71
+
72
+ <script src="http://ajax.googleapis.com/ajax/libs/jquery/1.8.3/jquery.min.js"></script>
73
+ <link rel="stylesheet" type="text/css" href="../axZm/axZm.css" media="all" />
74
+ <script type="text/javascript" src="../axZm/jquery.axZm.js"></script>
75
+ </head>
76
+ <body>
77
+ <div id="azTargetDiv" style="width: 100%; height: 100%;"></div>
78
+
79
+ <!-- Init AJAX-ZOOM player -->
80
+ <script type="text/javascript">
81
+
82
+ // Create empty jQuery object
83
+
84
+ var ajaxZoom = {};
85
+
86
+ // Parameters passed query string
87
+ var pathParameter = "<?php if (getIssetMod('3dDir')){echo '3dDir='.getValueMod('3dDir');} elseif (getIssetMod('zoomData')){echo 'zoomData='.getValueMod('zoomData');} elseif (getIssetMod('zoomDir')){echo 'zoomDir='.getValueMod('zoomDir');}?>";
88
+ pathParameter += "<?php if (getIssetMod('zoomFile')){echo '&zoomFile='.getValueMod('zoomFile');}?>";
89
+
90
+ var parseJsonTest = function(a){
91
+ try {return JSON.parse(a);}
92
+ catch(err) {return a;}}
93
+
94
+ // Define callbacks, for complete list check the docs
95
+ ajaxZoom.opt = {
96
+ onBeforeStart: function(){
97
+ // Set backgrounf color, can also be done in css file
98
+ $('.axZm_zoomContainer').css({backgroundColor: '#FFFFFF'});
99
+
100
+ // Do not display exit text
101
+ $.axZm.fullScreenExitText = false;
102
+
103
+ // Disable left/right buttons
104
+ $.axZm.gallerySlideNavi = false;
105
+
106
+ var fsSupport = document.documentElement.requestFullscreen || (document.documentElement.msRequestFullscreen && window == window.top) || document.documentElement.mozRequestFullScreen || document.documentElement.webkitRequestFullscreen;
107
+ var fullscreenEnabled = document.fullscreenEnabled || (document.msFullscreenEnabled && window == window.top) || document.mozFullScreenEnabled || document.webkitFullscreenEnabled;
108
+
109
+ // Enable fullscreen button depending on fullscreen support
110
+ $.axZm.fullScreenCornerButton = (fsSupport && fullscreenEnabled) ? true : false;
111
+ $.axZm.gallerySlideNaviMargin = 5;
112
+
113
+ <?php
114
+ // Enable left/right buttons in certain cases
115
+ if (getIssetMod('zoomDir') || (getIssetMod('zoomData') && count(explode('|', getValueMod('zoomData'))) > 1)){
116
+ echo '$.axZm.gallerySlideNavi=true;';
117
+ }else{
118
+ echo '$.axZm.gallerySlideNavi=false;';
119
+ }
120
+
121
+ // Enable spinmode of 3dDir is passed!
122
+ if (getIssetMod('3dDir')) {
123
+ echo '$.axZm.spinMode=true; ';
124
+ }else{
125
+ echo '$.axZm.spinMode=false; ';
126
+ }
127
+
128
+ // Some other parameters which can be passed over query string and set in onBeforeStart callback
129
+ if (getIssetMod('spinBounce')){
130
+ echo '$.axZm.spinBounce=\'bounce\'; ';
131
+ }
132
+
133
+ if (getIssetMod('spinReverse')){
134
+ echo '$.axZm.spinReverse=true; ';
135
+ }else{
136
+ echo '$.axZm.spinReverse=false; ';
137
+ }
138
+
139
+ if (getIssetMod('stepZoom')){
140
+ echo "
141
+ $.axZm.scrollAnm=false;
142
+ $.axZm.scrollZoom=11;
143
+ $.axZm.scrollAjax=200;
144
+ $.axZm.pyrTilesFadeInSpeed=300;
145
+ $.axZm.pyrTilesFadeLoad=30;
146
+ ";
147
+ }
148
+
149
+ if (getIssetMod('spinNoInit')){
150
+ echo "
151
+ $.axZm.spinNoInit.enabled=true;
152
+ ";
153
+ }
154
+ ?>
155
+
156
+ // mNavi hook
157
+ jQuery.axZm.mNavi = {
158
+ enabled: true,
159
+ gravity: 'bottomLeft', //topLeft, topRight, bottomRight, bottomLeft, bottom, top, right, left
160
+
161
+ offsetHorz: 5, // horizontal from player edge if parentID is not defined
162
+ offsetVert: 5, // vertical offset from player edge if parentID is not defined
163
+ offsetVertFS: 10, // vertical offset in fullscreen mode
164
+ offsetHorzFS: 10, // horizontal offset in fullscreen mode
165
+
166
+ parentID: false, // put mNavi in none fullscreen mode outside of the player
167
+ setParentWidth: false, // sets width of the parent container same as navi container
168
+ setParentHeight: false, // sets height of the parent container same as navi container
169
+ fullScreenShow: true, // append mNavi to the player in fullscreen mode; you can also enable fullScreenNaviBar option instead
170
+
171
+ hover: true, // looks for button like mPan.file + '_over' on mouse over or touch
172
+ down: true, // looks for button like mPan.file + '_down' on mouse over or touch
173
+
174
+ alignment: 'horz', // horz, vert (if gravity is 'right' or 'left' defaults to 'vert')
175
+ //padding: 0, // container padding (css class .axZm_zoomCustomNavi)
176
+ mouseOver: true, // hides when mouse is not over the player on not touch devices
177
+ firstEllMargin: 0, // margin left for first button in orderDefault / order
178
+ ellementRows: 1, // num raws of ellements, if > 1 alignment defaults to 'horz'
179
+ rowMargin: 5, // if ellementRows > 1 - margin between the rows
180
+
181
+ containerFixedWidth: false,
182
+ containerFixedHeight: false,
183
+
184
+ buttonDescr: false, // same behaviour as old navi for buttons description
185
+
186
+ alt: { // tooltip
187
+ enabled: false,
188
+ timeout: 300,
189
+ fadeIn: 200,
190
+ parentID: false,
191
+
192
+ gravity: 'bottom', // top, bottom
193
+ offset: 5,
194
+
195
+ pos: false, // false, topLeft, topRight, bottomRight, bottomLeft, bottom, top, right, left, center
196
+ posMarginX: 10,
197
+ posMarginY: 10,
198
+
199
+ opacity: 1.0,
200
+ mouseFollow: true
201
+ },
202
+
203
+ cssClass: 'zoomCustomNavi', // css class for container
204
+ cssClassFS: 'zoomCustomNaviFS', // css class fullscreen view
205
+ cssClassParentID: 'zoomCustomNaviParentID', // css class if parentID is defined
206
+
207
+ // Notes: mSpin is instantly removed if not spinMod or 3d; mSpin replaced by m3D when zAchsis is defined
208
+ // orderDefault is completly replaced with order if not empty object
209
+ orderDefault: {mZoomOut: 5, mZoomIn: 15, mReset: 15, mPan: 5, mSpin: 5, mCrop: 0}, // buttonName: distance to next button
210
+ order: {},
211
+
212
+ customPos: {
213
+ //mReset: {css: {left: 5, top: 5, position: 'absolute', zIndex: 123}, parentID: '', mouseOver: true}
214
+ },
215
+
216
+ // can be a stringified function if passed as JSON
217
+ mCustomBtn1: function(){jQuery.fn.axZm.fillArea();},
218
+ mCustomBtn2: function(){alert('Hello, I\'m custom button two.')}
219
+ };
220
+
221
+ <?php
222
+ if (getIssetMod('3dDir')){
223
+ echo 'jQuery.axZm.mNavi.order = {mPan: 5, mSpin: 0};';
224
+ }
225
+ elseif (getIssetMod('zoomDir'))
226
+ echo 'jQuery.axZm.mNavi.order = {mGallery: 5, mReset: 0};';
227
+ elseif (getIssetMod('zoomData')){
228
+ if (count(explode('|', getValueMod('zoomData'))) > 1){
229
+ echo 'jQuery.axZm.mNavi.order = {mGallery: 5, mReset: 0};';
230
+ }else{
231
+ echo 'jQuery.axZm.mNavi.order = {mReset: 0};';
232
+ }
233
+ }
234
+ ?>
235
+
236
+ var moduleSettings = <?php echo $conf360['settings']; ?>;
237
+ $.each(moduleSettings, function(k, v){
238
+ if ($.axZm[k] !== undefined){
239
+ $.axZm[k] = parseJsonTest(v);
240
+ }
241
+ });
242
+
243
+ }
244
+ };
245
+
246
+
247
+ var adjustHeight = function(){
248
+ //var a = (window.innerHeight ? window.innerHeight : $(window).height());
249
+ //$('#azTargetDiv').css('height', a);
250
+ window.scrollTo(0,0); // ios7
251
+ };
252
+
253
+ $(document).ready(function(){
254
+ adjustHeight();
255
+ $(document).bind('resize', adjustHeight);
256
+ });
257
+
258
+ // Define the path to the axZm folder, adjust the path if needed!
259
+ ajaxZoom.path = "../axZm/";
260
+
261
+ // Define your custom parameter query string
262
+ // example=spinIpad has many presets for 360 images
263
+ // 3dDir - best of all absolute path to the folder with 360/3D images
264
+ // ajaxZoom.parameter = "example=spinIpad&3dDir=/pic/zoom3d/Uvex_Occhiali";
265
+ ajaxZoom.parameter = "example=<?php echo $example ? $example : 'mouseOverExtension360'; ?>&"+pathParameter;
266
+
267
+ // Init fullscreen
268
+ $.fn.axZm.openFullScreen(ajaxZoom.path, ajaxZoom.parameter, ajaxZoom.opt, 'azTargetDiv', true);
269
+
270
+ </script>
271
+
272
+ </body>
273
+ </html>
js/axzoom/tmp/readme.txt ADDED
@@ -0,0 +1 @@
 
1
+ An all temporary files will be created in this folder
js/axzoom/zip/readme.txt ADDED
@@ -0,0 +1 @@
 
1
+ Put here zip files of 360/3d views
package.xml ADDED
@@ -0,0 +1,25 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?xml version="1.0"?>
2
+ <package>
3
+ <name>AJAX_ZOOM</name>
4
+ <version>1.0.0</version>
5
+ <stability>stable</stability>
6
+ <license>Commercial</license>
7
+ <channel>community</channel>
8
+ <extends/>
9
+ <summary>AJAX-ZOOM - Image Zoom &amp; Pan + 360&#xB0; Object Rotate (Spin), Fullscreen product image view, iPad</summary>
10
+ <description>&lt;p&gt;AJAX-ZOOM is a unique image pan &amp;amp; zoom + 360&#xB0; Object Rotate (Spin) interface written on top of jQuery &amp;amp; PHP - no Flash (works on iPad / iPhone). It uses image tiles to quickly generate a portion of an image (simmilar to google maps&lt;span&gt;&#xA9;&lt;/span&gt;). Can be viewed in fullscreen mode. Build in display mods for Magento integration: open in lightbox, open as fullscreen, embed the player in different ways and &amp;quot;&lt;a href="http://www.ajax-zoom.com/demo/magento/index.php/chair.html?displayModus=flyout"&gt;flyout zoom&lt;/a&gt;&amp;quot; (mouseover zoom with dynamic byloading of image tiles!). 360&#xB0; Objects and zoom on regular images are combineable in all mods, which can be seen at &lt;a href="http://www.ajax-zoom.com/demo/magento/index.php/chair.html"&gt;Magento demo store&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;Image tiles and all other thumbnails are created on the fly. This means that AJAX-ZOOM can be integrated into already productive Magento store filled with any number of products and images within a shortest period of time. AJAX-ZOOM has also the ability to watermark a zoomed portion on the fly adding protection to the source image. The program supports Gdlib and ImageMagick and has over 400 configuration options. Fully skinnable with css and config options! Ver. 4.x supports hotspots with online editor: &lt;a href="http://www.ajax-zoom.com/examples/example33.php"&gt;http://www.ajax-zoom.com/examples/example33.php&lt;/a&gt; Hotspots are easily loaded over a callback...&lt;br /&gt;&lt;br /&gt;&lt;/p&gt;&#xD;
11
+ &lt;p&gt;&lt;strong&gt;Light version can be freely downloaded and used even on commercial websites.&lt;/strong&gt;&lt;/p&gt;&#xD;
12
+ &lt;p&gt;Take a look at the general &lt;a href="http://www.ajax-zoom.com/index.php?cid=examples"&gt;examples&lt;/a&gt; and &lt;a href="http://www.ajax-zoom.com/demo/magento/index.php/couch.html"&gt;Magento demo store&lt;/a&gt;.&lt;/p&gt;&#xD;
13
+ &lt;p&gt;Installation guide: &lt;a href="http://www.ajax-zoom.com/index.php?cid=docs#heading_9"&gt;http://www.ajax-zoom.com/index.php?cid=docs#heading_9&lt;/a&gt;&lt;/p&gt;&#xD;
14
+ &lt;p&gt;Deutschsprachige Installationsanleitung vorhanden! (also in German language)&lt;/p&gt;&#xD;
15
+ &lt;p&gt;Download / Buy: &lt;a href="http://www.ajax-zoom.com/index.php?cid=download"&gt;http://www.ajax-zoom.com/index.php?cid=download&lt;/a&gt;&lt;/p&gt;&#xD;
16
+ &lt;p&gt;License price depends on number of images:&lt;/p&gt;&#xD;
17
+ &lt;p&gt;500 : &#x20AC;129&lt;br /&gt; 1,500 : &#x20AC;199&lt;br /&gt; 5,000 : &#x20AC;349&lt;br /&gt; 10,000 : &#x20AC;549&lt;br /&gt; 20,000 : &#x20AC;949&lt;br /&gt; Unlimited : &#x20AC;1499&lt;/p&gt;</description>
18
+ <notes>Add zoom &amp; pan functionality to your high resolution product images without flash.</notes>
19
+ <authors><author><name>vadus vadus</name><user>vadus</user><email>support@ajax-zoom.com</email></author></authors>
20
+ <date>2015-09-07</date>
21
+ <time>01:59:59</time>
22
+ <contents><target name="magelocal"><dir><dir name="Ax"><dir><dir name="Zoom"><dir name="Block"><dir name="Adminhtml"><dir name="System"><dir name="Config"><dir name="Fieldset"><file name="License.php" hash="cab77e3c8330de7508e0455494ebb00c"/></dir></dir></dir><dir name="Tabs"><file name="Tabid.php" hash="98dd27d79b9c7e5550c03b660dadf26b"/></dir><file name="Tabs.php" hash="da7864a9888b656e73478f789f64b9dd"/></dir></dir><dir name="Helper"><file name="Data.php" hash="01e845c60de3e05373db0ec0db8eab1b"/><file name="Head.php" hash="8b0a9c0cc1ebe67fd7a32c56499c191d"/></dir><dir name="Model"><file name="Ax360.php" hash="62424ea5bffb91788e81b9429fa549b5"/><file name="Ax360set.php" hash="5b17c167665fe269801c9dca9215d2c8"/><file name="Axproducts.php" hash="7cf68745c7d1e4f73e78e3b6df6fc8f4"/><file name="Observer.php" hash="9623653763e6c8f4cfc611e671fbb3bc"/><file name="Position.php" hash="1c4e3d0d1231fc398800cd4b3c4da7c9"/><dir name="Resource"><dir name="Ax360"><file name="Collection.php" hash="ef732d71a8c5660be2a7c494e7698958"/></dir><file name="Ax360.php" hash="487bfd370904bcd6686bc3da1b1e5158"/><dir name="Ax360set"><file name="Collection.php" hash="c2a387b65990a3cf38aa3ed183c8b147"/></dir><file name="Ax360set.php" hash="7052ad036b48fa91fcc4a6fb2ec2a3ef"/><dir name="Axproducts"><file name="Collection.php" hash="0112ef00782335a5cc57f08ee513aec5"/></dir><file name="Axproducts.php" hash="bdf85d9635e242c39df9676c62ef7712"/></dir><file name="Words.php" hash="eb8fb9b1aa96d7405d0aac4a3fb4b9c6"/><file name="Yesno.php" hash="4c27f7a5d223e53554a1e41a02d3366e"/></dir><dir name="controllers"><file name="IndexController.php" hash="bf4dfc5f9e2aaf5efbfeef941eb27119"/></dir><dir name="etc"><file name="config.xml" hash="1161865deea42da198374bfefcc4e39e"/><file name="system.xml" hash="f0d928563651e4633ce7a8446c256fd5"/></dir><dir name="sql"><dir name="axzoom_setup"><file name="install-0.0.1.php" hash="42a139d8e475fd83e4b6a0ed896f059c"/></dir></dir></dir></dir></dir></dir></target><target name="magedesign"><dir><dir name="adminhtml"><dir name="default"><dir name="default"><dir name="layout"><file name="axzoom.xml" hash="278bba66c17b57727e0ceea9e6c30c69"/></dir><dir name="template"><dir name="axzoom"><file name="tab.phtml" hash="63c7693e1e07d3992b07a60dfa98dfc3"/><file name="tab360-sets.phtml" hash="547c1c12bd7c25439ffe725097db18b6"/><file name="tab360-settings.phtml" hash="830a01b077c9e644855647c62b05c31c"/><file name="tab360.phtml" hash="2ceac556e2e793893e237533cdae6e9c"/><file name="uploader.phtml" hash="0f86f2c697a5eb5db2cbb624019f84bb"/></dir></dir></dir></dir></dir><dir name="frontend"><dir name="default"><dir name="default"><dir name="layout"><file name="axzoom.xml" hash="b41bbcf251fc5ff73f6531c93bdb50df"/></dir></dir></dir><dir name="rwd"><dir name="default"><dir name="layout"><file name="axzoom.xml" hash="32289fd6c594f625998851c521d48e41"/></dir><dir name="template"><dir name="ax_zoom"><dir><dir name="catalog"><dir name="product"><dir name="view"><file name="media.phtml" hash="7e04a905156c53ca6038efc0e8e67165"/></dir></dir></dir></dir></dir></dir></dir></dir></dir></dir></target><target name="mageetc"><dir><dir name="modules"><file name="Ax_Zoom.xml" hash="02791fdb29865f2c1813df08f189fe07"/></dir></dir></target><target name="magelocale"><dir><dir name="ru_RU"><file name="Ax_Zoom.csv" hash="ad9b1e1ad87a1187dbd076b43af97429"/></dir></dir></target><target name="mageweb"><dir><dir name="js"><dir name="axzoom"><file name="check_jquery.js" hash="118a99a417dd9a613b7b16c1f138b62c"/><file name="image_path.gif" hash="bf922e182e18a02613f26ca5eaa4c560"/><file name="jquery-1.11.0.min.js" hash="fb206f891cebdbbd8472a23f7c525cb2"/><file name="jquery-migrate-1.2.1.min.js" hash="eb05d8d73b5b13d8d84308a4751ece96"/><file name="jquery.fileupload-process.js" hash="0da6f8ef76956f6ce7842dcf8941d1fa"/><file name="jquery.fileupload-validate.js" hash="561d450d59e39724999629cae64cd80e"/><file name="jquery.fileupload.js" hash="d4b3a5c4f6e69185727cfe98f17f0239"/><file name="jquery.ui.widget.min.js" hash="2425a542e6dde093dd85ac0b5adc0141"/><file name="lic.php" hash="c89d13392a8360d41d4cc9fa4bea8842"/><file name="no_image-100x100.jpg" hash="ebbaa789d1a5e5b1bb6fdb9ccd683aa2"/><dir><dir name="pic"><file name="readme.txt" hash="763fdb72282a84d27d9a6c93e014775a"/></dir><dir name="preview"><file name="index.php" hash="c304cfb13785e145e95d5f21cc95bd12"/><file name="preview.php" hash="0ebbc68bf74927c95587decbe2f24626"/></dir><dir name="tmp"><file name="readme.txt" hash="b17a61b9642c5d472107ab7023c5c880"/></dir><dir name="zip"><file name="readme.txt" hash="2134ad018dd3da577df745a04d22899f"/></dir></dir><file name=".htaccess" hash="b974c32a345792b0bc2fad66c2236152"/></dir></dir></dir></target></contents>
23
+ <compatible/>
24
+ <dependencies><required><php><min>5.2.1</min><max>5.6.13</max></php><extension><name>gd</name><min/><max/></extension><extension><name>ionCube Loader</name><min/><max/></extension><extension><name>zip</name><min/><max/></extension></required></dependencies>
25
+ </package>