Catalin_Seo - Version 2.0.0

Version Notes

- Fixed the issue: in attribute values "," (comma) and "/" (slash) cannot be used.
- Disabled History for browsers HTML4 browsers.

Download this release

Release Info

Developer Catalin Ciobanu
Extension Catalin_Seo
Version 2.0.0
Comparing to
See all releases


Code changes from version 1.2.1 to 2.0.0

Files changed (26) hide show
  1. app/code/community/Catalin/SEO/Block/Catalog/Layer/Filter/Attribute.php +1 -1
  2. app/code/community/Catalin/SEO/Block/Catalog/Layer/Filter/Price.php +1 -1
  3. app/code/community/Catalin/SEO/Block/Catalog/Layer/State.php +1 -1
  4. app/code/community/Catalin/SEO/Block/Catalog/Product/List/Pager.php +1 -1
  5. app/code/community/Catalin/SEO/Block/Catalog/Product/List/Toolbar.php +1 -1
  6. app/code/community/Catalin/SEO/Block/CatalogSearch/Layer/Filter/Attribute.php +1 -1
  7. app/code/community/Catalin/SEO/Controller/Router.php +1 -1
  8. app/code/community/Catalin/SEO/Helper/Data.php +2 -2
  9. app/code/community/Catalin/SEO/Model/Catalog/Layer.php +36 -0
  10. app/code/community/Catalin/SEO/Model/Catalog/Layer/Filter/Attribute.php +9 -4
  11. app/code/community/Catalin/SEO/Model/Catalog/Layer/Filter/Category.php +1 -1
  12. app/code/community/Catalin/SEO/Model/Catalog/Layer/Filter/Item.php +3 -1
  13. app/code/community/Catalin/SEO/Model/Catalog/Resource/Layer/Filter/Attribute.php +4 -7
  14. app/code/community/Catalin/SEO/Model/CatalogSearch/Layer.php +116 -0
  15. app/code/community/Catalin/SEO/Model/CatalogSearch/Layer/Filter/Attribute.php +1 -1
  16. app/code/community/Catalin/SEO/Model/Indexer/Attribute.php +75 -0
  17. app/code/community/Catalin/SEO/Model/Resource/Attribute/Urlkey.php +139 -0
  18. app/code/community/Catalin/SEO/Model/Resource/Indexer/Attribute.php +204 -0
  19. app/code/community/Catalin/SEO/Model/System/Config/Backend/Seo/Catalog.php +1 -1
  20. app/code/community/Catalin/SEO/Model/System/Config/Source/Slider/Submit/Type.php +16 -2
  21. app/code/community/Catalin/SEO/controllers/CategoryController.php +2 -2
  22. app/code/community/Catalin/SEO/controllers/ResultController.php +1 -1
  23. app/code/community/Catalin/SEO/etc/config.xml +30 -5
  24. app/code/community/Catalin/SEO/sql/catalin_seo_setup/install-2.0.0.php +42 -0
  25. package.xml +13 -169
  26. skin/frontend/default/default/js/catalin_seo/native.history.js +1 -1
app/code/community/Catalin/SEO/Block/Catalog/Layer/Filter/Attribute.php CHANGED
@@ -11,7 +11,7 @@
11
  * http://opensource.org/licenses/osl-3.0.php
12
  *
13
  * @package Catalin_Seo
14
- * @copyright Copyright (c) 2012 Catalin Ciobanu
15
  * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0)
16
  */
17
  class Catalin_SEO_Block_Catalog_Layer_Filter_Attribute extends Mage_Catalog_Block_Layer_Filter_Attribute
11
  * http://opensource.org/licenses/osl-3.0.php
12
  *
13
  * @package Catalin_Seo
14
+ * @copyright Copyright (c) 2013 Catalin Ciobanu
15
  * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0)
16
  */
17
  class Catalin_SEO_Block_Catalog_Layer_Filter_Attribute extends Mage_Catalog_Block_Layer_Filter_Attribute
app/code/community/Catalin/SEO/Block/Catalog/Layer/Filter/Price.php CHANGED
@@ -11,7 +11,7 @@
11
  * http://opensource.org/licenses/osl-3.0.php
12
  *
13
  * @package Catalin_Seo
14
- * @copyright Copyright (c) 2012 Catalin Ciobanu
15
  * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0)
16
  */
17
  class Catalin_SEO_Block_Catalog_Layer_Filter_Price extends Mage_Catalog_Block_Layer_Filter_Price
11
  * http://opensource.org/licenses/osl-3.0.php
12
  *
13
  * @package Catalin_Seo
14
+ * @copyright Copyright (c) 2013 Catalin Ciobanu
15
  * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0)
16
  */
17
  class Catalin_SEO_Block_Catalog_Layer_Filter_Price extends Mage_Catalog_Block_Layer_Filter_Price
app/code/community/Catalin/SEO/Block/Catalog/Layer/State.php CHANGED
@@ -11,7 +11,7 @@
11
  * http://opensource.org/licenses/osl-3.0.php
12
  *
13
  * @package Catalin_Seo
14
- * @copyright Copyright (c) 2012 Catalin Ciobanu
15
  * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0)
16
  */
17
  class Catalin_SEO_Block_Catalog_Layer_State extends Mage_Catalog_Block_Layer_State
11
  * http://opensource.org/licenses/osl-3.0.php
12
  *
13
  * @package Catalin_Seo
14
+ * @copyright Copyright (c) 2013 Catalin Ciobanu
15
  * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0)
16
  */
17
  class Catalin_SEO_Block_Catalog_Layer_State extends Mage_Catalog_Block_Layer_State
app/code/community/Catalin/SEO/Block/Catalog/Product/List/Pager.php CHANGED
@@ -11,7 +11,7 @@
11
  * http://opensource.org/licenses/osl-3.0.php
12
  *
13
  * @package Catalin_Seo
14
- * @copyright Copyright (c) 2012 Catalin Ciobanu
15
  * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0)
16
  */
17
  class Catalin_SEO_Block_Catalog_Product_List_Pager extends Mage_Page_Block_Html_Pager
11
  * http://opensource.org/licenses/osl-3.0.php
12
  *
13
  * @package Catalin_Seo
14
+ * @copyright Copyright (c) 2013 Catalin Ciobanu
15
  * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0)
16
  */
17
  class Catalin_SEO_Block_Catalog_Product_List_Pager extends Mage_Page_Block_Html_Pager
app/code/community/Catalin/SEO/Block/Catalog/Product/List/Toolbar.php CHANGED
@@ -11,7 +11,7 @@
11
  * http://opensource.org/licenses/osl-3.0.php
12
  *
13
  * @package Catalin_Seo
14
- * @copyright Copyright (c) 2012 Catalin Ciobanu
15
  * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0)
16
  */
17
  class Catalin_SEO_Block_Catalog_Product_List_Toolbar extends Mage_Catalog_Block_Product_List_Toolbar
11
  * http://opensource.org/licenses/osl-3.0.php
12
  *
13
  * @package Catalin_Seo
14
+ * @copyright Copyright (c) 2013 Catalin Ciobanu
15
  * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0)
16
  */
17
  class Catalin_SEO_Block_Catalog_Product_List_Toolbar extends Mage_Catalog_Block_Product_List_Toolbar
app/code/community/Catalin/SEO/Block/CatalogSearch/Layer/Filter/Attribute.php CHANGED
@@ -11,7 +11,7 @@
11
  * http://opensource.org/licenses/osl-3.0.php
12
  *
13
  * @package Catalin_Seo
14
- * @copyright Copyright (c) 2012 Catalin Ciobanu
15
  * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0)
16
  */
17
  class Catalin_SEO_Block_CatalogSearch_Layer_Filter_Attribute extends Catalin_SEO_Block_Catalog_Layer_Filter_Attribute
11
  * http://opensource.org/licenses/osl-3.0.php
12
  *
13
  * @package Catalin_Seo
14
+ * @copyright Copyright (c) 2013 Catalin Ciobanu
15
  * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0)
16
  */
17
  class Catalin_SEO_Block_CatalogSearch_Layer_Filter_Attribute extends Catalin_SEO_Block_Catalog_Layer_Filter_Attribute
app/code/community/Catalin/SEO/Controller/Router.php CHANGED
@@ -11,7 +11,7 @@
11
  * http://opensource.org/licenses/osl-3.0.php
12
  *
13
  * @package Catalin_Seo
14
- * @copyright Copyright (c) 2012 Catalin Ciobanu
15
  * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0)
16
  */
17
  class Catalin_SEO_Controller_Router extends Mage_Core_Controller_Varien_Router_Standard
11
  * http://opensource.org/licenses/osl-3.0.php
12
  *
13
  * @package Catalin_Seo
14
+ * @copyright Copyright (c) 2013 Catalin Ciobanu
15
  * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0)
16
  */
17
  class Catalin_SEO_Controller_Router extends Mage_Core_Controller_Varien_Router_Standard
app/code/community/Catalin/SEO/Helper/Data.php CHANGED
@@ -11,10 +11,10 @@
11
  * http://opensource.org/licenses/osl-3.0.php
12
  *
13
  * @package Catalin_Seo
14
- * @copyright Copyright (c) 2012 Catalin Ciobanu
15
  * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0)
16
  */
17
- class Catalin_SEO_Helper_Data extends Mage_Core_Helper_Abstract
18
  {
19
  /**
20
  * Delimiter for multiple filters
11
  * http://opensource.org/licenses/osl-3.0.php
12
  *
13
  * @package Catalin_Seo
14
+ * @copyright Copyright (c) 2013 Catalin Ciobanu
15
  * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0)
16
  */
17
+ class Catalin_SEO_Helper_Data extends Mage_Core_Helper_Data
18
  {
19
  /**
20
  * Delimiter for multiple filters
app/code/community/Catalin/SEO/Model/Catalog/Layer.php ADDED
@@ -0,0 +1,36 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /**
4
+ * Catalin Ciobanu
5
+ *
6
+ * NOTICE OF LICENSE
7
+ *
8
+ * This source file is subject to the Open Software License (OSL 3.0)
9
+ * that is bundled with this package in the file LICENSE.txt.
10
+ * It is also available through the world-wide-web at this URL:
11
+ * http://opensource.org/licenses/osl-3.0.php
12
+ *
13
+ * @package Catalin_Seo
14
+ * @copyright Copyright (c) 2013 Catalin Ciobanu
15
+ * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0)
16
+ */
17
+ class Catalin_SEO_Model_Catalog_Layer extends Mage_Catalog_Model_Layer
18
+ {
19
+
20
+ /**
21
+ * Get collection of all filterable attributes for layer products set
22
+ *
23
+ * @return Mage_Catalog_Model_Resource_Eav_Mysql4_Attribute_Collection
24
+ */
25
+ public function getFilterableAttributes()
26
+ {
27
+ $collection = parent::getFilterableAttributes();
28
+
29
+ // Load them at once - one query at once not multiple
30
+ $attrUrlKeyModel = Mage::getResourceModel('catalin_seo/attribute_urlkey');
31
+ $attrUrlKeyModel->preloadAttributesOptions($collection);
32
+
33
+ return $collection;
34
+ }
35
+
36
+ }
app/code/community/Catalin/SEO/Model/Catalog/Layer/Filter/Attribute.php CHANGED
@@ -11,7 +11,7 @@
11
  * http://opensource.org/licenses/osl-3.0.php
12
  *
13
  * @package Catalin_Seo
14
- * @copyright Copyright (c) 2012 Catalin Ciobanu
15
  * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0)
16
  */
17
  class Catalin_SEO_Model_Catalog_Layer_Filter_Attribute extends Mage_Catalog_Model_Layer_Filter_Attribute
@@ -49,9 +49,12 @@ class Catalin_SEO_Model_Catalog_Layer_Filter_Attribute extends Mage_Catalog_Mode
49
  $this->_values = explode(Catalin_SEO_Helper_Data::MULTIPLE_FILTERS_DELIMITER, $filter);
50
 
51
  if (!empty($this->_values)) {
 
52
  $this->_getResource()->applyFilterToCollection($this, $this->_values);
53
  foreach ($this->_values as $filter) {
54
- $this->getLayer()->getState()->addFilter($this->_createItem($filter, $filter));
 
 
55
  // process all items if multiple choice is enabled
56
  if (!Mage::helper('catalin_seo')->isMultipleChoiceFiltersEnabled()) {
57
  $this->_items = array();
@@ -80,6 +83,7 @@ class Catalin_SEO_Model_Catalog_Layer_Filter_Attribute extends Mage_Catalog_Mode
80
  $data = $this->getLayer()->getAggregator()->getCacheData($key);
81
 
82
  if ($data === null) {
 
83
  $options = $attribute->getFrontend()->getSelectOptions();
84
  $optionsCount = $this->_getResource()->getCount($this);
85
  $data = array();
@@ -93,14 +97,14 @@ class Catalin_SEO_Model_Catalog_Layer_Filter_Attribute extends Mage_Catalog_Mode
93
  if (!empty($optionsCount[$option['value']])) {
94
  $data[] = array(
95
  'label' => $option['label'],
96
- 'value' => $option['label'],
97
  'count' => $optionsCount[$option['value']],
98
  );
99
  }
100
  } else {
101
  $data[] = array(
102
  'label' => $option['label'],
103
- 'value' => $option['label'],
104
  'count' => isset($optionsCount[$option['value']]) ? $optionsCount[$option['value']] : 0,
105
  );
106
  }
@@ -114,6 +118,7 @@ class Catalin_SEO_Model_Catalog_Layer_Filter_Attribute extends Mage_Catalog_Mode
114
  $tags = $this->getLayer()->getStateTags($tags);
115
  $this->getLayer()->getAggregator()->saveCacheData($data, $key, $tags);
116
  }
 
117
  return $data;
118
  }
119
 
11
  * http://opensource.org/licenses/osl-3.0.php
12
  *
13
  * @package Catalin_Seo
14
+ * @copyright Copyright (c) 2013 Catalin Ciobanu
15
  * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0)
16
  */
17
  class Catalin_SEO_Model_Catalog_Layer_Filter_Attribute extends Mage_Catalog_Model_Layer_Filter_Attribute
49
  $this->_values = explode(Catalin_SEO_Helper_Data::MULTIPLE_FILTERS_DELIMITER, $filter);
50
 
51
  if (!empty($this->_values)) {
52
+ $attrUrlKeyModel = Mage::getResourceModel('catalin_seo/attribute_urlkey');
53
  $this->_getResource()->applyFilterToCollection($this, $this->_values);
54
  foreach ($this->_values as $filter) {
55
+ $optionId = $attrUrlKeyModel->getOptionId($this->getAttributeModel()->getId(), $filter);
56
+ $text = $this->_getOptionText($optionId);
57
+ $this->getLayer()->getState()->addFilter($this->_createItem($text, $filter));
58
  // process all items if multiple choice is enabled
59
  if (!Mage::helper('catalin_seo')->isMultipleChoiceFiltersEnabled()) {
60
  $this->_items = array();
83
  $data = $this->getLayer()->getAggregator()->getCacheData($key);
84
 
85
  if ($data === null) {
86
+ $attrUrlKeyModel = Mage::getResourceModel('catalin_seo/attribute_urlkey');
87
  $options = $attribute->getFrontend()->getSelectOptions();
88
  $optionsCount = $this->_getResource()->getCount($this);
89
  $data = array();
97
  if (!empty($optionsCount[$option['value']])) {
98
  $data[] = array(
99
  'label' => $option['label'],
100
+ 'value' => $attrUrlKeyModel->getUrlKey($attribute->getId(), $option['value']),
101
  'count' => $optionsCount[$option['value']],
102
  );
103
  }
104
  } else {
105
  $data[] = array(
106
  'label' => $option['label'],
107
+ 'value' => $attrUrlKeyModel->getUrlKey($attribute->getId(), $option['value']),
108
  'count' => isset($optionsCount[$option['value']]) ? $optionsCount[$option['value']] : 0,
109
  );
110
  }
118
  $tags = $this->getLayer()->getStateTags($tags);
119
  $this->getLayer()->getAggregator()->saveCacheData($data, $key, $tags);
120
  }
121
+
122
  return $data;
123
  }
124
 
app/code/community/Catalin/SEO/Model/Catalog/Layer/Filter/Category.php CHANGED
@@ -11,7 +11,7 @@
11
  * http://opensource.org/licenses/osl-3.0.php
12
  *
13
  * @package Catalin_Seo
14
- * @copyright Copyright (c) 2012 Catalin Ciobanu
15
  * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0)
16
  */
17
  class Catalin_SEO_Model_Catalog_Layer_Filter_Category extends Mage_Catalog_Model_Layer_Filter_Category
11
  * http://opensource.org/licenses/osl-3.0.php
12
  *
13
  * @package Catalin_Seo
14
+ * @copyright Copyright (c) 2013 Catalin Ciobanu
15
  * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0)
16
  */
17
  class Catalin_SEO_Model_Catalog_Layer_Filter_Category extends Mage_Catalog_Model_Layer_Filter_Category
app/code/community/Catalin/SEO/Model/Catalog/Layer/Filter/Item.php CHANGED
@@ -11,7 +11,7 @@
11
  * http://opensource.org/licenses/osl-3.0.php
12
  *
13
  * @package Catalin_Seo
14
- * @copyright Copyright (c) 2012 Catalin Ciobanu
15
  * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0)
16
  */
17
  class Catalin_SEO_Model_Catalog_Layer_Filter_Item extends Mage_Catalog_Model_Layer_Filter_Item
@@ -41,6 +41,8 @@ class Catalin_SEO_Model_Catalog_Layer_Filter_Item extends Mage_Catalog_Model_Lay
41
  $values = $this->getFilter()->getValues();
42
  if (!empty($values)) {
43
  $tmp = array_merge($values, array($this->getValue()));
 
 
44
  $values = implode(Catalin_SEO_Helper_Data::MULTIPLE_FILTERS_DELIMITER, $tmp);
45
  } else {
46
  $values = $this->getValue();
11
  * http://opensource.org/licenses/osl-3.0.php
12
  *
13
  * @package Catalin_Seo
14
+ * @copyright Copyright (c) 2013 Catalin Ciobanu
15
  * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0)
16
  */
17
  class Catalin_SEO_Model_Catalog_Layer_Filter_Item extends Mage_Catalog_Model_Layer_Filter_Item
41
  $values = $this->getFilter()->getValues();
42
  if (!empty($values)) {
43
  $tmp = array_merge($values, array($this->getValue()));
44
+ // Sort filters - small SEO improvement
45
+ asort($tmp);
46
  $values = implode(Catalin_SEO_Helper_Data::MULTIPLE_FILTERS_DELIMITER, $tmp);
47
  } else {
48
  $values = $this->getValue();
app/code/community/Catalin/SEO/Model/Catalog/Resource/Layer/Filter/Attribute.php CHANGED
@@ -11,7 +11,7 @@
11
  * http://opensource.org/licenses/osl-3.0.php
12
  *
13
  * @package Catalin_Seo
14
- * @copyright Copyright (c) 2012 Catalin Ciobanu
15
  * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0)
16
  */
17
  class Catalin_SEO_Model_Catalog_Resource_Layer_Filter_Attribute extends Mage_Catalog_Model_Resource_Layer_Filter_Attribute
@@ -40,7 +40,8 @@ class Catalin_SEO_Model_Catalog_Resource_Layer_Filter_Attribute extends Mage_Cat
40
  $connection->quoteInto("{$tableAlias}.store_id = ?", $collection->getStoreId()),
41
  );
42
 
43
- $options = $attribute->getSource()->getAllOptions(false);
 
44
  if (!is_array($value)) {
45
  foreach ($options as $option) {
46
  if ($option['label'] == $value) {
@@ -51,11 +52,7 @@ class Catalin_SEO_Model_Catalog_Resource_Layer_Filter_Attribute extends Mage_Cat
51
  } else {
52
  $conditions[] = "{$tableAlias}.value in ( ";
53
  foreach ($value as $v) {
54
- foreach ($options as $option) {
55
- if ($option['label'] == $v) {
56
- $v = $option['value'];
57
- }
58
- }
59
  $conditions[count($conditions) - 1] .= $connection->quoteInto("?", $v) . ' ,';
60
  }
61
  $conditions[count($conditions) - 1] = rtrim($conditions[count($conditions) - 1], ',');
11
  * http://opensource.org/licenses/osl-3.0.php
12
  *
13
  * @package Catalin_Seo
14
+ * @copyright Copyright (c) 2013 Catalin Ciobanu
15
  * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0)
16
  */
17
  class Catalin_SEO_Model_Catalog_Resource_Layer_Filter_Attribute extends Mage_Catalog_Model_Resource_Layer_Filter_Attribute
40
  $connection->quoteInto("{$tableAlias}.store_id = ?", $collection->getStoreId()),
41
  );
42
 
43
+ $attrUrlKeyModel = Mage::getResourceModel('catalin_seo/attribute_urlkey');
44
+ //$options = $attribute->getSource()->getAllOptions(false);
45
  if (!is_array($value)) {
46
  foreach ($options as $option) {
47
  if ($option['label'] == $value) {
52
  } else {
53
  $conditions[] = "{$tableAlias}.value in ( ";
54
  foreach ($value as $v) {
55
+ $v = $attrUrlKeyModel->getOptionId($attribute->getId(), $v);
 
 
 
 
56
  $conditions[count($conditions) - 1] .= $connection->quoteInto("?", $v) . ' ,';
57
  }
58
  $conditions[count($conditions) - 1] = rtrim($conditions[count($conditions) - 1], ',');
app/code/community/Catalin/SEO/Model/CatalogSearch/Layer.php ADDED
@@ -0,0 +1,116 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /**
4
+ * Catalin Ciobanu
5
+ *
6
+ * NOTICE OF LICENSE
7
+ *
8
+ * This source file is subject to the Open Software License (OSL 3.0)
9
+ * that is bundled with this package in the file LICENSE.txt.
10
+ * It is also available through the world-wide-web at this URL:
11
+ * http://opensource.org/licenses/osl-3.0.php
12
+ *
13
+ * @package Catalin_Seo
14
+ * @copyright Copyright (c) 2013 Catalin Ciobanu
15
+ * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0)
16
+ */
17
+ class Catalin_SEO_Model_CatalogSearch_Layer extends Catalin_SEO_Model_Catalog_Layer
18
+ {
19
+
20
+ const XML_PATH_DISPLAY_LAYER_COUNT = 'catalog/search/use_layered_navigation_count';
21
+
22
+ /**
23
+ * Get current layer product collection
24
+ *
25
+ * @return Mage_Catalog_Model_Resource_Eav_Resource_Product_Collection
26
+ */
27
+ public function getProductCollection()
28
+ {
29
+ if (isset($this->_productCollections[$this->getCurrentCategory()->getId()])) {
30
+ $collection = $this->_productCollections[$this->getCurrentCategory()->getId()];
31
+ } else {
32
+ $collection = Mage::getResourceModel('catalogsearch/fulltext_collection');
33
+ $this->prepareProductCollection($collection);
34
+ $this->_productCollections[$this->getCurrentCategory()->getId()] = $collection;
35
+ }
36
+ return $collection;
37
+ }
38
+
39
+ /**
40
+ * Prepare product collection
41
+ *
42
+ * @param Mage_Catalog_Model_Resource_Eav_Resource_Product_Collection $collection
43
+ * @return Mage_Catalog_Model_Layer
44
+ */
45
+ public function prepareProductCollection($collection)
46
+ {
47
+ $collection
48
+ ->addAttributeToSelect(Mage::getSingleton('catalog/config')->getProductAttributes())
49
+ ->addSearchFilter(Mage::helper('catalogsearch')->getQuery()->getQueryText())
50
+ ->setStore(Mage::app()->getStore())
51
+ ->addMinimalPrice()
52
+ ->addFinalPrice()
53
+ ->addTaxPercents()
54
+ ->addStoreFilter()
55
+ ->addUrlRewrite();
56
+
57
+ Mage::getSingleton('catalog/product_status')->addVisibleFilterToCollection($collection);
58
+ Mage::getSingleton('catalog/product_visibility')->addVisibleInSearchFilterToCollection($collection);
59
+
60
+ return $this;
61
+ }
62
+
63
+ /**
64
+ * Get layer state key
65
+ *
66
+ * @return string
67
+ */
68
+ public function getStateKey()
69
+ {
70
+ if ($this->_stateKey === null) {
71
+ $this->_stateKey = 'Q_' . Mage::helper('catalogsearch')->getQuery()->getId()
72
+ . '_' . parent::getStateKey();
73
+ }
74
+ return $this->_stateKey;
75
+ }
76
+
77
+ /**
78
+ * Get default tags for current layer state
79
+ *
80
+ * @param array $additionalTags
81
+ * @return array
82
+ */
83
+ public function getStateTags(array $additionalTags = array())
84
+ {
85
+ $additionalTags = parent::getStateTags($additionalTags);
86
+ $additionalTags[] = Mage_CatalogSearch_Model_Query::CACHE_TAG;
87
+ return $additionalTags;
88
+ }
89
+
90
+ /**
91
+ * Add filters to attribute collection
92
+ *
93
+ * @param Mage_Catalog_Model_Resource_Eav_Resource_Product_Attribute_Collection $collection
94
+ * @return Mage_Catalog_Model_Resource_Eav_Resource_Product_Attribute_Collection
95
+ */
96
+ protected function _prepareAttributeCollection($collection)
97
+ {
98
+ $collection->addIsFilterableInSearchFilter()
99
+ ->addVisibleFilter();
100
+ return $collection;
101
+ }
102
+
103
+ /**
104
+ * Prepare attribute for use in layered navigation
105
+ *
106
+ * @param Mage_Eav_Model_Entity_Attribute $attribute
107
+ * @return Mage_Eav_Model_Entity_Attribute
108
+ */
109
+ protected function _prepareAttribute($attribute)
110
+ {
111
+ $attribute = parent::_prepareAttribute($attribute);
112
+ $attribute->setIsFilterable(Mage_Catalog_Model_Layer_Filter_Attribute::OPTIONS_ONLY_WITH_RESULTS);
113
+ return $attribute;
114
+ }
115
+
116
+ }
app/code/community/Catalin/SEO/Model/CatalogSearch/Layer/Filter/Attribute.php CHANGED
@@ -11,7 +11,7 @@
11
  * http://opensource.org/licenses/osl-3.0.php
12
  *
13
  * @package Catalin_Seo
14
- * @copyright Copyright (c) 2012 Catalin Ciobanu
15
  * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0)
16
  */
17
  class Catalin_SEO_Model_CatalogSearch_Layer_Filter_Attribute extends Catalin_SEO_Model_Catalog_Layer_Filter_Attribute
11
  * http://opensource.org/licenses/osl-3.0.php
12
  *
13
  * @package Catalin_Seo
14
+ * @copyright Copyright (c) 2013 Catalin Ciobanu
15
  * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0)
16
  */
17
  class Catalin_SEO_Model_CatalogSearch_Layer_Filter_Attribute extends Catalin_SEO_Model_Catalog_Layer_Filter_Attribute
app/code/community/Catalin/SEO/Model/Indexer/Attribute.php ADDED
@@ -0,0 +1,75 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /**
4
+ * Catalin Ciobanu
5
+ *
6
+ * NOTICE OF LICENSE
7
+ *
8
+ * This source file is subject to the Open Software License (OSL 3.0)
9
+ * that is bundled with this package in the file LICENSE.txt.
10
+ * It is also available through the world-wide-web at this URL:
11
+ * http://opensource.org/licenses/osl-3.0.php
12
+ *
13
+ * @package Catalin_Seo
14
+ * @copyright Copyright (c) 2013 Catalin Ciobanu
15
+ * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0)
16
+ */
17
+ class Catalin_SEO_Model_Indexer_Attribute extends Mage_Index_Model_Indexer_Abstract
18
+ {
19
+
20
+ protected $_matchedEntities = array(
21
+ Mage_Catalog_Model_Resource_Eav_Attribute::ENTITY => array(
22
+ Mage_Index_Model_Event::TYPE_SAVE,
23
+ ),
24
+ );
25
+
26
+ /**
27
+ * Initialize model
28
+ *
29
+ */
30
+ protected function _construct()
31
+ {
32
+ $this->_init('catalin_seo/indexer_attribute');
33
+ }
34
+
35
+ /**
36
+ * Process event based on event state data
37
+ *
38
+ * @param Mage_Index_Model_Event $event
39
+ */
40
+ protected function _processEvent(Mage_Index_Model_Event $event)
41
+ {
42
+ $this->callEventHandler($event);
43
+ }
44
+
45
+ /**
46
+ * Register indexer required data inside event object
47
+ *
48
+ * @param Mage_Index_Model_Event $event
49
+ */
50
+ protected function _registerEvent(Mage_Index_Model_Event $event)
51
+ {
52
+ return $this;
53
+ }
54
+
55
+ /**
56
+ * Get Indexer name
57
+ *
58
+ * @return string
59
+ */
60
+ public function getName()
61
+ {
62
+ return Mage::helper('catalin_seo')->__('Catalin SEO');
63
+ }
64
+
65
+ /**
66
+ * Get Indexer description
67
+ *
68
+ * @return string
69
+ */
70
+ public function getDescription()
71
+ {
72
+ return Mage::helper('catalin_seo')->__('Index attribute options for layered navigation filters');
73
+ }
74
+
75
+ }
app/code/community/Catalin/SEO/Model/Resource/Attribute/Urlkey.php ADDED
@@ -0,0 +1,139 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /**
4
+ * Catalin Ciobanu
5
+ *
6
+ * NOTICE OF LICENSE
7
+ *
8
+ * This source file is subject to the Open Software License (OSL 3.0)
9
+ * that is bundled with this package in the file LICENSE.txt.
10
+ * It is also available through the world-wide-web at this URL:
11
+ * http://opensource.org/licenses/osl-3.0.php
12
+ *
13
+ * @package Catalin_Seo
14
+ * @copyright Copyright (c) 2013 Catalin Ciobanu
15
+ * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0)
16
+ */
17
+ class Catalin_SEO_Model_Resource_Attribute_Urlkey extends Mage_Core_Model_Resource_Db_Abstract
18
+ {
19
+
20
+ protected static $_cachedResults;
21
+
22
+ /**
23
+ * Initialize resource model
24
+ *
25
+ */
26
+ protected function _construct()
27
+ {
28
+ $this->_init('catalin_seo/attribute_url_key', 'id');
29
+ }
30
+
31
+ /**
32
+ * Retrieve urk_key for specific option
33
+ *
34
+ * @param int $attributeId
35
+ * @param int $optionId
36
+ * @param int $storeId
37
+ * @return int|string
38
+ */
39
+ public function getUrlKey($attributeId, $optionId, $storeId = null)
40
+ {
41
+ foreach ($this->_getOptions($attributeId, $storeId) as $result) {
42
+ if ($result['option_id'] == $optionId) {
43
+ return $result['url_key'];
44
+ }
45
+ }
46
+
47
+ return $optionId;
48
+ }
49
+
50
+ /**
51
+ * Retrieve option_id for specific url_key
52
+ *
53
+ * @param int $attributeId
54
+ * @param string $urlKey
55
+ * @param int $storeId
56
+ * @return int|string
57
+ */
58
+ public function getOptionId($attributeId, $urlKey, $storeId = null)
59
+ {
60
+ foreach ($this->_getOptions($attributeId, $storeId) as $result) {
61
+ if ($result['url_key'] == $urlKey) {
62
+ return $result['option_id'];
63
+ }
64
+ }
65
+
66
+ return $urlKey;
67
+ }
68
+
69
+ /**
70
+ * Retrieve options url keys for specific attribute
71
+ * Use this as it caches for each attribute all possible values
72
+ *
73
+ * @todo Implement a method to detect all available filters and
74
+ * the ones used so we can do just one query - Ideal case
75
+ *
76
+ * @param int $attributeId
77
+ * @param int $storeId
78
+ * @return array
79
+ */
80
+ protected function _getOptions($attributeId, $storeId)
81
+ {
82
+ if ($storeId === null) {
83
+ $storeId = Mage::app()->getStore()->getId();
84
+ }
85
+
86
+ if (!isset(self::$_cachedResults[$attributeId][$storeId])) {
87
+ $readAdapter = $this->_getReadAdapter();
88
+ $select = $readAdapter->select()
89
+ ->from($this->getMainTable())
90
+ ->where('`store_id` = ?', $storeId)
91
+ ->where("`attribute_id` = ?", $attributeId);
92
+ $data = $readAdapter->fetchAll($select);
93
+
94
+ self::$_cachedResults[$attributeId][$storeId] = $data;
95
+ }
96
+
97
+ return self::$_cachedResults[$attributeId][$storeId];
98
+ }
99
+
100
+ /**
101
+ * Load attributes options from the database
102
+ *
103
+ * @param Mage_Catalog_Model_Resource_Product_Attribute_Collection $collection
104
+ * @return Catalin_SEO_Model_Resource_Attribute_Urlkey
105
+ */
106
+ public function preloadAttributesOptions(Mage_Catalog_Model_Resource_Product_Attribute_Collection $collection, $storeId = null)
107
+ {
108
+ if ($storeId === null) {
109
+ $storeId = Mage::app()->getStore()->getId();
110
+ }
111
+
112
+ $attributesIds = array();
113
+ foreach ($collection as $attribute) {
114
+ $attributesIds[] = $attribute->getId();
115
+ }
116
+
117
+ $readAdapter = $this->_getReadAdapter();
118
+ $select = $readAdapter->select()
119
+ ->from($this->getMainTable())
120
+ ->where('`store_id` = ?', $storeId)
121
+ ->where('`attribute_id` IN (?)', array('in' => $attributesIds));
122
+
123
+ $data = $readAdapter->fetchAll($select);
124
+ foreach ($data as $attr) {
125
+ self::$_cachedResults[$attr['attribute_id']][$attr['store_id']][] = $attr;
126
+ }
127
+
128
+ // Fill with empty array for the attributes ids that have no values in database
129
+ // Prevents from doing suplimentary querys
130
+ foreach ($attributesIds as $attributeId) {
131
+ if (!isset(self::$_cachedResults[$attributeId][$storeId])) {
132
+ self::$_cachedResults[$attributeId][$storeId] = array();
133
+ }
134
+ }
135
+
136
+ return $this;
137
+ }
138
+
139
+ }
app/code/community/Catalin/SEO/Model/Resource/Indexer/Attribute.php ADDED
@@ -0,0 +1,204 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /**
4
+ * Catalin Ciobanu
5
+ *
6
+ * NOTICE OF LICENSE
7
+ *
8
+ * This source file is subject to the Open Software License (OSL 3.0)
9
+ * that is bundled with this package in the file LICENSE.txt.
10
+ * It is also available through the world-wide-web at this URL:
11
+ * http://opensource.org/licenses/osl-3.0.php
12
+ *
13
+ * @package Catalin_Seo
14
+ * @copyright Copyright (c) 2013 Catalin Ciobanu
15
+ * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0)
16
+ */
17
+ class Catalin_SEO_Model_Resource_Indexer_Attribute extends Mage_Index_Model_Resource_Abstract
18
+ {
19
+
20
+ protected $_storesIds;
21
+ protected $_helper;
22
+
23
+ /**
24
+ * Initialize resource model
25
+ *
26
+ */
27
+ protected function _construct()
28
+ {
29
+ $this->_init('catalin_seo/attribute_url_key', 'id');
30
+ }
31
+
32
+ /**
33
+ * Reindex all
34
+ *
35
+ * @return Catalin_SEO_Model_Resource_Indexer_Attribute
36
+ */
37
+ public function reindexAll()
38
+ {
39
+ $this->reindexSeoUrlKeys();
40
+ return $this;
41
+ }
42
+
43
+ /**
44
+ * Generate SEO values for catalog product attributes options
45
+ *
46
+ * @param int $attributeId - transmit this to limit processing to one specific attribute
47
+ * @return Catalin_SEO_Model_Resource_Indexer_Attribute
48
+ */
49
+ public function reindexSeoUrlKeys($attributeId = null)
50
+ {
51
+ $attributes = $this->_getAttributes($attributeId);
52
+ $stores = $this->_getAllStoresIds();
53
+
54
+ $data = array();
55
+ foreach ($attributes as $attribute) {
56
+ if ($attribute->usesSource()) {
57
+ foreach ($stores as $storeId) {
58
+ $result = $this->_getInsertValues($attribute, $storeId);
59
+ $data = array_merge($data, $result);
60
+ }
61
+ }
62
+ }
63
+
64
+ if (!empty($attributeId)) {
65
+ $this->_saveData($data, array("`attribute_id` = ?" => $attributeId));
66
+ } else {
67
+ $this->_saveData($data);
68
+ }
69
+
70
+ return $this;
71
+ }
72
+
73
+ /**
74
+ * Save data into database
75
+ *
76
+ * @param array $data
77
+ * @param array $deleteWhere
78
+ */
79
+ protected function _saveData(array $data, array $deleteWhere = array())
80
+ {
81
+ // Continue only if we have something to insert
82
+ if (empty($data)) {
83
+ return $this;
84
+ }
85
+
86
+ // Do it in one transaction
87
+ $this->beginTransaction();
88
+
89
+ try {
90
+ $writeAdapter = $this->_getWriteAdapter();
91
+ $writeAdapter->delete($this->getMainTable(), $deleteWhere);
92
+ $writeAdapter->insertMultiple($this->getMainTable(), $data);
93
+
94
+ $this->commit();
95
+ } catch (Exception $e) {
96
+ $this->rollBack();
97
+ throw $e;
98
+ }
99
+ }
100
+
101
+ /**
102
+ * Retrieve product attributes with frontend input type 'select' and 'multiselect'
103
+ *
104
+ * @return Mage_Eav_Model_Resource_Entity_Attribute_Collection
105
+ */
106
+ protected function _getAttributes($attributeId = null)
107
+ {
108
+ $collection = Mage::getSingleton('eav/config')
109
+ ->getEntityType(Mage_Catalog_Model_Product::ENTITY)
110
+ ->getAttributeCollection()
111
+ ->addFieldToFilter('`main_table`.`frontend_input`', array('in' => array('select', 'multiselect')));
112
+ //->addSetInfo();
113
+ if (!empty($attributeId)) {
114
+ $collection->addFieldToFilter('`main_table`.`attribute_id`', $attributeId);
115
+ }
116
+
117
+ return $collection;
118
+ }
119
+
120
+ /**
121
+ * Retrieve data to be insterted after processing attribute
122
+ *
123
+ * @param Mage_Catalog_Model_Resource_Eav_Attribute $attribute
124
+ * @param int $storeId
125
+ * @return array
126
+ */
127
+ protected function _getInsertValues($attribute, $storeId)
128
+ {
129
+
130
+ $collection = Mage::getResourceModel('eav/entity_attribute_option_collection')
131
+ ->setStoreFilter($storeId)
132
+ ->setPositionOrder('asc')
133
+ ->setAttributeFilter($attribute->getId())
134
+ ->load();
135
+ $options = $collection->toOptionArray();
136
+
137
+ $data = array();
138
+ foreach ($options as $option) {
139
+ // Replace accents and remove all non-aplhanumerical characters
140
+ $urlKey = $this->_getHelper()->removeAccents($option['label']);
141
+ $urlKey = strtolower($urlKey);
142
+ $urlKey = preg_replace('/([^a-zA-Z0-9])/', '-', $urlKey);
143
+ $urlKey = preg_replace('/([-]{2,})/', '-', $urlKey);
144
+ $urlKey = trim($urlKey, '-');
145
+
146
+ $data[] = array(
147
+ 'attribute_code' => $attribute->getAttributeCode(),
148
+ 'attribute_id' => $attribute->getId(),
149
+ 'store_id' => $storeId,
150
+ 'option_id' => $option['value'],
151
+ 'url_key' => $urlKey
152
+ );
153
+ }
154
+
155
+ return $data;
156
+ }
157
+
158
+ /**
159
+ * Retrieve all stores ids
160
+ *
161
+ * @return array
162
+ */
163
+ protected function _getAllStoresIds()
164
+ {
165
+ if ($this->_storesIds === null) {
166
+ $this->_storesIds = array();
167
+ $stores = Mage::app()->getStores();
168
+ foreach ($stores as $storeId => $store) {
169
+ $this->_storesIds[] = $storeId;
170
+ }
171
+ }
172
+
173
+ return $this->_storesIds;
174
+ }
175
+
176
+ /**
177
+ * Retrieve helper object
178
+ *
179
+ * @return Catalin_SEO_Helper_Data
180
+ */
181
+ protected function _getHelper()
182
+ {
183
+ if ($this->_helper === null) {
184
+ $this->_helper = Mage::helper('catalin_seo');
185
+ }
186
+
187
+ return $this->_helper;
188
+ }
189
+
190
+ /**
191
+ * Reindex attribute options on attribute save event
192
+ *
193
+ * @param Mage_Index_Model_Event $event
194
+ * @return Catalin_SEO_Model_Resource_Indexer_Attribute
195
+ */
196
+ public function catalogEavAttributeSave(Mage_Index_Model_Event $event)
197
+ {
198
+ $attribute = $event->getDataObject();
199
+ $this->reindexSeoUrlKeys($attribute->getId());
200
+
201
+ return $this;
202
+ }
203
+
204
+ }
app/code/community/Catalin/SEO/Model/System/Config/Backend/Seo/Catalog.php CHANGED
@@ -11,7 +11,7 @@
11
  * http://opensource.org/licenses/osl-3.0.php
12
  *
13
  * @package Catalin_Seo
14
- * @copyright Copyright (c) 2012 Catalin Ciobanu
15
  * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0)
16
  */
17
  class Catalin_SEO_Model_System_Config_Backend_Seo_Catalog extends Mage_Core_Model_Config_Data
11
  * http://opensource.org/licenses/osl-3.0.php
12
  *
13
  * @package Catalin_Seo
14
+ * @copyright Copyright (c) 2013 Catalin Ciobanu
15
  * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0)
16
  */
17
  class Catalin_SEO_Model_System_Config_Backend_Seo_Catalog extends Mage_Core_Model_Config_Data
app/code/community/Catalin/SEO/Model/System/Config/Source/Slider/Submit/Type.php CHANGED
@@ -1,5 +1,19 @@
1
  <?php
2
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
3
  class Catalin_SEO_Model_System_Config_Source_Slider_Submit_Type
4
  {
5
 
@@ -22,8 +36,8 @@ class Catalin_SEO_Model_System_Config_Source_Slider_Submit_Type
22
  self::SUBMIT_BUTTON => $helper->__('Submit button')
23
  );
24
  }
25
-
26
- return $this->_options;
27
  }
28
 
29
  }
1
  <?php
2
 
3
+ /**
4
+ * Catalin Ciobanu
5
+ *
6
+ * NOTICE OF LICENSE
7
+ *
8
+ * This source file is subject to the Open Software License (OSL 3.0)
9
+ * that is bundled with this package in the file LICENSE.txt.
10
+ * It is also available through the world-wide-web at this URL:
11
+ * http://opensource.org/licenses/osl-3.0.php
12
+ *
13
+ * @package Catalin_Seo
14
+ * @copyright Copyright (c) 2013 Catalin Ciobanu
15
+ * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0)
16
+ */
17
  class Catalin_SEO_Model_System_Config_Source_Slider_Submit_Type
18
  {
19
 
36
  self::SUBMIT_BUTTON => $helper->__('Submit button')
37
  );
38
  }
39
+
40
+ return $this->_options;
41
  }
42
 
43
  }
app/code/community/Catalin/SEO/controllers/CategoryController.php CHANGED
@@ -11,7 +11,7 @@
11
  * http://opensource.org/licenses/osl-3.0.php
12
  *
13
  * @package Catalin_Seo
14
- * @copyright Copyright (c) 2012 Catalin Ciobanu
15
  * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0)
16
  */
17
  require_once 'Mage/Catalog/controllers/CategoryController.php';
@@ -65,7 +65,7 @@ class Catalin_Seo_CategoryController extends Mage_Catalog_CategoryController
65
 
66
  if (($root = $this->getLayout()->getBlock('root'))) {
67
  $root->addBodyClass('categorypath-' . $category->getUrlPath())
68
- ->addBodyClass('category-' . $category->getUrlKey());
69
  }
70
 
71
  $this->_initLayoutMessages('catalog/session');
11
  * http://opensource.org/licenses/osl-3.0.php
12
  *
13
  * @package Catalin_Seo
14
+ * @copyright Copyright (c) 2013 Catalin Ciobanu
15
  * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0)
16
  */
17
  require_once 'Mage/Catalog/controllers/CategoryController.php';
65
 
66
  if (($root = $this->getLayout()->getBlock('root'))) {
67
  $root->addBodyClass('categorypath-' . $category->getUrlPath())
68
+ ->addBodyClass('category-' . $category->getUrlKey());
69
  }
70
 
71
  $this->_initLayoutMessages('catalog/session');
app/code/community/Catalin/SEO/controllers/ResultController.php CHANGED
@@ -11,7 +11,7 @@
11
  * http://opensource.org/licenses/osl-3.0.php
12
  *
13
  * @package Catalin_Seo
14
- * @copyright Copyright (c) 2012 Catalin Ciobanu
15
  * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0)
16
  */
17
  require_once 'Mage/CatalogSearch/controllers/ResultController.php';
11
  * http://opensource.org/licenses/osl-3.0.php
12
  *
13
  * @package Catalin_Seo
14
+ * @copyright Copyright (c) 2013 Catalin Ciobanu
15
  * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0)
16
  */
17
  require_once 'Mage/CatalogSearch/controllers/ResultController.php';
app/code/community/Catalin/SEO/etc/config.xml CHANGED
@@ -1,14 +1,15 @@
1
  <?xml version="1.0" encoding="UTF-8"?>
2
  <config>
 
 
 
 
 
3
  <global>
4
- <modules>
5
- <Catalin_SEO>
6
- <version>1.0.0</version>
7
- </Catalin_SEO>
8
- </modules>
9
  <models>
10
  <catalog>
11
  <rewrite>
 
12
  <layer_filter_item>Catalin_SEO_Model_Catalog_Layer_Filter_Item</layer_filter_item>
13
  <layer_filter_category>Catalin_SEO_Model_Catalog_Layer_Filter_Category</layer_filter_category>
14
  <layer_filter_attribute>Catalin_SEO_Model_Catalog_Layer_Filter_Attribute</layer_filter_attribute>
@@ -16,6 +17,7 @@
16
  </catalog>
17
  <catalogsearch>
18
  <rewrite>
 
19
  <layer_filter_attribute>Catalin_SEO_Model_CatalogSearch_Layer_Filter_Attribute</layer_filter_attribute>
20
  </rewrite>
21
  </catalogsearch>
@@ -26,8 +28,24 @@
26
  </catalog_resource>
27
  <catalin_seo>
28
  <class>Catalin_SEO_Model</class>
 
29
  </catalin_seo>
 
 
 
 
 
 
 
 
30
  </models>
 
 
 
 
 
 
 
31
  <blocks>
32
  <catalog>
33
  <rewrite>
@@ -61,6 +79,13 @@
61
  </observers>
62
  </controller_front_init_routers>
63
  </events>
 
 
 
 
 
 
 
64
  </global>
65
  <frontend>
66
  <routers>
1
  <?xml version="1.0" encoding="UTF-8"?>
2
  <config>
3
+ <modules>
4
+ <Catalin_SEO>
5
+ <version>2.0.0</version>
6
+ </Catalin_SEO>
7
+ </modules>
8
  <global>
 
 
 
 
 
9
  <models>
10
  <catalog>
11
  <rewrite>
12
+ <layer>Catalin_SEO_Model_Catalog_Layer</layer>
13
  <layer_filter_item>Catalin_SEO_Model_Catalog_Layer_Filter_Item</layer_filter_item>
14
  <layer_filter_category>Catalin_SEO_Model_Catalog_Layer_Filter_Category</layer_filter_category>
15
  <layer_filter_attribute>Catalin_SEO_Model_Catalog_Layer_Filter_Attribute</layer_filter_attribute>
17
  </catalog>
18
  <catalogsearch>
19
  <rewrite>
20
+ <layer>Catalin_SEO_Model_CatalogSearch_Layer</layer>
21
  <layer_filter_attribute>Catalin_SEO_Model_CatalogSearch_Layer_Filter_Attribute</layer_filter_attribute>
22
  </rewrite>
23
  </catalogsearch>
28
  </catalog_resource>
29
  <catalin_seo>
30
  <class>Catalin_SEO_Model</class>
31
+ <resourceModel>catalin_seo_resource</resourceModel>
32
  </catalin_seo>
33
+ <catalin_seo_resource>
34
+ <class>Catalin_SEO_Model_Resource</class>
35
+ <entities>
36
+ <attribute_url_key>
37
+ <table>catalin_seo_attribute_url_key</table>
38
+ </attribute_url_key>
39
+ </entities>
40
+ </catalin_seo_resource>
41
  </models>
42
+ <resources>
43
+ <catalin_seo_setup>
44
+ <setup>
45
+ <module>Catalin_SEO</module>
46
+ </setup>
47
+ </catalin_seo_setup>
48
+ </resources>
49
  <blocks>
50
  <catalog>
51
  <rewrite>
79
  </observers>
80
  </controller_front_init_routers>
81
  </events>
82
+ <index>
83
+ <indexer>
84
+ <catalin_seo_attribute>
85
+ <model>catalin_seo/indexer_attribute</model>
86
+ </catalin_seo_attribute>
87
+ </indexer>
88
+ </index>
89
  </global>
90
  <frontend>
91
  <routers>
app/code/community/Catalin/SEO/sql/catalin_seo_setup/install-2.0.0.php ADDED
@@ -0,0 +1,42 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /* @var $installer Mage_Core_Model_Resource_Setup */
4
+ $installer = $this;
5
+
6
+ $installer->startSetup();
7
+
8
+ $tableName = $installer->getTable('catalin_seo/attribute_url_key');
9
+
10
+ /**
11
+ * Drop table - needed for reinstall to work
12
+ */
13
+ $installer->getConnection()->dropTable($tableName);
14
+
15
+ /**
16
+ * Create table 'catalin_seo/attribute_url_key'
17
+ */
18
+ $table = $installer->getConnection()
19
+ ->newTable($tableName)
20
+ ->addColumn('id', Varien_Db_Ddl_Table::TYPE_INTEGER, null, array(
21
+ 'unsigned' => true,
22
+ 'nullable' => false,
23
+ 'primary' => true,
24
+ 'auto_increment' => true,
25
+ ), 'Id')
26
+ ->addColumn('attribute_code', Varien_Db_Ddl_Table::TYPE_TEXT, 255, array(
27
+ ), 'Attribute Code')
28
+ ->addColumn('attribute_id', Varien_Db_Ddl_Table::TYPE_INTEGER, null, array(
29
+ 'unsigned' => true,
30
+ ), 'Attribute Id')
31
+ ->addColumn('store_id', Varien_Db_Ddl_Table::TYPE_INTEGER, null, array(
32
+ 'unsigned' => true,
33
+ ), 'Store Id')
34
+ ->addColumn('option_id', Varien_Db_Ddl_Table::TYPE_INTEGER, null, array(
35
+ 'unsigned' => true,
36
+ ), 'Option Id')
37
+ ->addColumn('url_key', Varien_Db_Ddl_Table::TYPE_TEXT, 255, array(
38
+ ), 'Url Key')
39
+ ->setComment('Tag');
40
+ $installer->getConnection()->createTable($table);
41
+
42
+ $installer->endSetup();
package.xml CHANGED
@@ -1,183 +1,27 @@
1
  <?xml version="1.0"?>
2
  <package>
3
  <name>Catalin_Seo</name>
4
- <version>1.2.1</version>
5
  <stability>stable</stability>
6
  <license uri="http://opensource.org/licenses/osl-3.0.php">OSL</license>
7
  <channel>community</channel>
8
  <extends/>
9
- <summary>ajax, seo urls, price slider, multiple selection for the same attribute.</summary>
10
- <description>&lt;h2&gt;Layered Navigation SEO&lt;/h2&gt;&#xD;
11
- &lt;p&gt;ajax, seo urls, price slider, multiple selection for the same attribute.&lt;/p&gt;&#xD;
12
  &lt;h2&gt;Features&lt;/h2&gt;&#xD;
13
  &lt;ul&gt;&#xD;
14
- &lt;li&gt;ajax navigation&lt;/li&gt;&#xD;
15
- &lt;li&gt;simple price slider&lt;/li&gt;&#xD;
16
  &lt;li&gt;SEO URLs (http://www.example.com/apparel/shoes/list/color/Brown,Blue/shoe_type/Sandal.html)&lt;/li&gt;&#xD;
17
  &lt;li&gt;multiple filters for the same attribute&lt;/li&gt;&#xD;
18
  &lt;/ul&gt;&#xD;
19
- &lt;p&gt;All the above features can be enabled/disabled from backend from "System -&gt; Configuration -&gt; Catalin SEO -&gt; Catalog Layered Navigation"&lt;/p&gt;&#xD;
20
- &lt;h2&gt;Known Issues&lt;/h2&gt;&#xD;
21
- &lt;ul&gt;&#xD;
22
- &lt;li&gt;In the attribute values "," (comma) and "/" (slash) cannot be used.&lt;/li&gt;&#xD;
23
- &lt;/ul&gt;
24
- </description>
25
- <notes>ajax, seo urls, price slider, multiple selection for the same attribute.</notes>
26
- <authors>
27
- <author>
28
- <name>Catalin Ciobanu</name>
29
- <user>catalin_ciobanu</user>
30
- <email>ciobanu.catalin@yahoo.com</email>
31
- </author>
32
- </authors>
33
- <date>2012-12-14</date>
34
- <time>18:31:03</time>
35
- <contents>
36
- <target name="magecommunity">
37
- <dir name="Catalin">
38
- <dir name="SEO">
39
- <dir name="Block">
40
- <dir name="Catalog">
41
- <dir name="Layer">
42
- <dir name="Filter">
43
- <file name="Attribute.php" hash="b0fb7deaeec0d46bc170e510c3d6f73a"/>
44
- <file name="Price.php" hash="73fe2b9d21dab816474ee8d662a530bd"/>
45
- </dir>
46
- <file name="State.php" hash="fece6cd5534ae48f0f9f9233a7f714af"/>
47
- </dir>
48
- <dir name="Product">
49
- <dir name="List">
50
- <file name="Pager.php" hash="5f41fc06bddb70fc2f7de3792c933879"/>
51
- <file name="Toolbar.php" hash="6db34892e1937dd1e527c8ac2fda4746"/>
52
- </dir>
53
- </dir>
54
- </dir>
55
- <dir name="CatalogSearch">
56
- <dir name="Layer">
57
- <dir name="Filter">
58
- <file name="Attribute.php" hash="120da8cc984bf1d55428ee4cfeaedca5"/>
59
- </dir>
60
- </dir>
61
- </dir>
62
- </dir>
63
- <dir name="Controller">
64
- <file name="Router.php" hash="71c67346a0c3e89775e5d7762c8a3588"/>
65
- </dir>
66
- <dir name="Helper">
67
- <file name="Data.php" hash="47a5e37ea96a12615ad1818f919d634f"/>
68
- </dir>
69
- <dir name="Model">
70
- <dir name="Catalog">
71
- <dir name="Layer">
72
- <dir name="Filter">
73
- <file name="Attribute.php" hash="cd5ef92601544ed236617881b0dd6352"/>
74
- <file name="Category.php" hash="bc5df542ef28c4e7a9583ae441c550c8"/>
75
- <file name="Item.php" hash="9d89a99bebad467ca14e50333c556649"/>
76
- </dir>
77
- </dir>
78
- <dir name="Resource">
79
- <dir name="Layer">
80
- <dir name="Filter">
81
- <file name="Attribute.php" hash="ab59cb798f1069786a98408f6ebaf948"/>
82
- </dir>
83
- </dir>
84
- </dir>
85
- </dir>
86
- <dir name="CatalogSearch">
87
- <dir name="Layer">
88
- <dir name="Filter">
89
- <file name="Attribute.php" hash="137c0b3795d3eea4da8442db3e05e7a0"/>
90
- </dir>
91
- </dir>
92
- </dir>
93
- <dir name="System">
94
- <dir name="Config">
95
- <dir name="Backend">
96
- <dir name="Seo">
97
- <file name="Catalog.php" hash="ea4cd41cf4e919935919585a22dfea29"/>
98
- </dir>
99
- </dir>
100
- <dir name="Source">
101
- <dir name="Slider">
102
- <dir name="Submit">
103
- <file name="Type.php" hash="6d656f04657b303f989022ee305e6b00"/>
104
- </dir>
105
- </dir>
106
- </dir>
107
- </dir>
108
- </dir>
109
- </dir>
110
- <dir name="controllers">
111
- <file name="CategoryController.php" hash="3f3404592e64ffc3d3e302a92e76dc06"/>
112
- <file name="ResultController.php" hash="660c07990539e5605112cb42e24c02d6"/>
113
- </dir>
114
- <dir name="etc">
115
- <file name="adminhtml.xml" hash="240f607b0156d1de84667b382ba3f73c"/>
116
- <file name="config.xml" hash="9e2487e6c0eb5b09c43f65c01db3d882"/>
117
- <file name="system.xml" hash="9fd01148901e15950868e312b96dbfde"/>
118
- </dir>
119
- </dir>
120
- </dir>
121
- </target>
122
- <target name="mageskin">
123
- <dir name="frontend">
124
- <dir name="default">
125
- <dir name="default">
126
- <dir name="css">
127
- <dir name="price_slider">
128
- <file name="style.css" hash="61d0b59ed239bc64deaf4aed969652cd"/>
129
- </dir>
130
- </dir>
131
- <dir name="images">
132
- <dir name="price_slider">
133
- <file name="bkg_slider.png" hash="1b7a1eb7add1d2b2002501f4602c3d3e"/>
134
- <file name="slider.png" hash="d77b417b68ba91402c3b7180b165110c"/>
135
- </dir>
136
- </dir>
137
- </dir>
138
- </dir>
139
- </dir>
140
- </target>
141
- <target name="mageetc">
142
- <dir name="modules">
143
- <file name="Catalin_SEO.xml" hash="e0ad01abfe976aefb6587fcfb3bf0d2b"/>
144
- </dir>
145
- </target>
146
- <target name="magedesign">
147
- <dir name="frontend">
148
- <dir name="default">
149
- <dir name="default">
150
- <dir name="template">
151
- <dir name="catalin_seo">
152
- <dir>
153
- <dir name="catalog">
154
- <dir name="layer">
155
- <file name="filter.phtml" hash="dd1d3278e691814f0cd242179e5bf53f"/>
156
- <file name="price.phtml" hash="19f1583df9e7f14d81318c633b334a88"/>
157
- <file name="view.phtml" hash="bc5f21109be4dab996b152e7a756fe03"/>
158
- </dir>
159
- <dir name="product">
160
- <file name="list.phtml" hash="bd332a192ed36c56c00968e13b599cd3"/>
161
- </dir>
162
- </dir>
163
- </dir>
164
- </dir>
165
- </dir>
166
- <dir name="layout">
167
- <file name="catalin_seo.xml" hash="61db4d9d696f2d12c562ae70a5164e4c"/>
168
- </dir>
169
- </dir>
170
- </dir>
171
- </dir>
172
- </target>
173
- </contents>
174
  <compatible/>
175
- <dependencies>
176
- <required>
177
- <php>
178
- <min>5.2.0</min>
179
- <max>6.0.0</max>
180
- </php>
181
- </required>
182
- </dependencies>
183
  </package>
1
  <?xml version="1.0"?>
2
  <package>
3
  <name>Catalin_Seo</name>
4
+ <version>2.0.0</version>
5
  <stability>stable</stability>
6
  <license uri="http://opensource.org/licenses/osl-3.0.php">OSL</license>
7
  <channel>community</channel>
8
  <extends/>
9
+ <summary>Layered Navigation SEO: ajax, seo urls, price slider, multiple filters for the same attribute.</summary>
10
+ <description>&lt;p&gt;ajax, seo urls, price slider, multiple selection for the same attribute.&lt;/p&gt;&#xD;
 
11
  &lt;h2&gt;Features&lt;/h2&gt;&#xD;
12
  &lt;ul&gt;&#xD;
13
+ &lt;li&gt;ajax navigation using history pushState/popState (only for HTML5 browsers)&lt;/li&gt;&#xD;
14
+ &lt;li&gt;price slider with auto update or submit button&lt;/li&gt;&#xD;
15
  &lt;li&gt;SEO URLs (http://www.example.com/apparel/shoes/list/color/Brown,Blue/shoe_type/Sandal.html)&lt;/li&gt;&#xD;
16
  &lt;li&gt;multiple filters for the same attribute&lt;/li&gt;&#xD;
17
  &lt;/ul&gt;&#xD;
18
+ &lt;p&gt;All the above features can be enabled/disabled from backend from "System -&gt; Configuration -&gt; Catalin SEO -&gt; Catalog Layered Navigation"&lt;/p&gt;</description>
19
+ <notes>- Fixed the issue: in attribute values "," (comma) and "/" (slash) cannot be used.&#xD;
20
+ - Disabled History for browsers HTML4 browsers.</notes>
21
+ <authors><author><name>Catalin Ciobanu</name><user>catalin_ciobanu</user><email>ciobanu.catalin@yahoo.com</email></author></authors>
22
+ <date>2013-01-26</date>
23
+ <time>13:46:10</time>
24
+ <contents><target name="magecommunity"><dir name="Catalin"><dir name="SEO"><dir name="Block"><dir name="Catalog"><dir name="Layer"><dir name="Filter"><file name="Attribute.php" hash="decdc5633827964ff7aba28f8e8f89ff"/><file name="Price.php" hash="fb413c30cfd742818757beb88264fd68"/></dir><file name="State.php" hash="fd21c5a6603427ae81e7eddbef3d827f"/></dir><dir name="Product"><dir name="List"><file name="Pager.php" hash="7720a417475b5a512d383fd06242e43a"/><file name="Toolbar.php" hash="1624c89efb4f94ed1f35622c70fd3d9a"/></dir></dir></dir><dir name="CatalogSearch"><dir name="Layer"><dir name="Filter"><file name="Attribute.php" hash="008e737de084f5a400518bda4dda09f8"/></dir></dir></dir></dir><dir name="Controller"><file name="Router.php" hash="959ddeb429ee3ce85c5b8d9e24e01dc0"/></dir><dir name="Helper"><file name="Data.php" hash="fe35a0e29057133e6e9d2ca1a7dbddc6"/></dir><dir name="Model"><dir name="Catalog"><dir name="Layer"><dir name="Filter"><file name="Attribute.php" hash="17dde650381b5a65dd1c3fc6d942bb2a"/><file name="Category.php" hash="5a5b4213e521b0fd33cc7623435dd3aa"/><file name="Item.php" hash="293783ab05520a197ff02ad44bdd9ed6"/></dir></dir><file name="Layer.php" hash="32e0397c7eea8dacc421f3f2e1b5273a"/><dir name="Resource"><dir name="Layer"><dir name="Filter"><file name="Attribute.php" hash="7f235b63e342d77b18da3ffffd97de10"/></dir></dir></dir></dir><dir name="CatalogSearch"><dir name="Layer"><dir name="Filter"><file name="Attribute.php" hash="9dda0e593ace29efbba4c84b683d9377"/></dir></dir><file name="Layer.php" hash="3f980ee1a82354d0bd65edde410a2818"/></dir><dir name="Indexer"><file name="Attribute.php" hash="9d5bd74b9c9204c4aee3fd6f0478688b"/></dir><dir name="Resource"><dir name="Attribute"><file name="Urlkey.php" hash="485538d19fad7b7b5b647feb220e5c03"/></dir><dir name="Indexer"><file name="Attribute.php" hash="645ebc0fe5ee7a461c06d805a529b678"/></dir></dir><dir name="System"><dir name="Config"><dir name="Backend"><dir name="Seo"><file name="Catalog.php" hash="233ca11b938d6198b5a4400a2c5e1d61"/></dir></dir><dir name="Source"><dir name="Slider"><dir name="Submit"><file name="Type.php" hash="cb2383c3568982b09e4878735e598fca"/></dir></dir></dir></dir></dir></dir><dir name="controllers"><file name="CategoryController.php" hash="64cf21a1dfef461a2bf52c7a184192c8"/><file name="ResultController.php" hash="fdecd53c83673edf32e768737492aee4"/></dir><dir name="etc"><file name="adminhtml.xml" hash="240f607b0156d1de84667b382ba3f73c"/><file name="config.xml" hash="f492966665665d3594f5a84ace4b4abd"/><file name="system.xml" hash="92e698eebc986af7d98f9676138730cd"/></dir><dir name="sql"><dir name="catalin_seo_setup"><file name="install-2.0.0.php" hash="1f1e47269b9658b4a3f53cb17ba728e1"/></dir></dir></dir></dir></target><target name="magedesign"><dir name="frontend"><dir name="default"><dir name="default"><dir name="layout"><file name="catalin_seo.xml" hash="17f80ca298cc0093ef29f69d02e8117b"/></dir><dir name="template"><dir name="catalin_seo"><dir><dir name="catalog"><dir name="layer"><file name="filter.phtml" hash="dd1d3278e691814f0cd242179e5bf53f"/><file name="price.phtml" hash="e853f8d1045abd7fa45051eb87fc1ba0"/><file name="view.phtml" hash="bc5f21109be4dab996b152e7a756fe03"/></dir><dir name="product"><file name="list.phtml" hash="9dd7e5ffd7a994a5036bf4eb378c8178"/></dir></dir></dir></dir></dir></dir></dir></dir></target><target name="mageskin"><dir name="frontend"><dir name="default"><dir name="default"><dir name="css"><dir name="price_slider"><file name="style.css" hash="61d0b59ed239bc64deaf4aed969652cd"/></dir></dir><dir name="images"><dir name="price_slider"><file name="bkg_slider.png" hash="1b7a1eb7add1d2b2002501f4602c3d3e"/><file name="slider.png" hash="d77b417b68ba91402c3b7180b165110c"/></dir></dir><dir name="js"><dir name="catalin_seo"><file name="native.history.js" hash="ee04bc106db73bdbe17a0eac44497df1"/></dir></dir></dir></dir></dir></target><target name="mageetc"><dir name="modules"><file name="Catalin_SEO.xml" hash="e0ad01abfe976aefb6587fcfb3bf0d2b"/></dir></target></contents>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
25
  <compatible/>
26
+ <dependencies><required><php><min>5.2.0</min><max>6.0.0</max></php></required></dependencies>
 
 
 
 
 
 
 
27
  </package>
skin/frontend/default/default/js/catalin_seo/native.history.js CHANGED
@@ -1 +1 @@
1
- window.JSON||(window.JSON={}),function(){function f(a){return a<10?"0"+a:a}function quote(a){return escapable.lastIndex=0,escapable.test(a)?'"'+a.replace(escapable,function(a){var b=meta[a];return typeof b=="string"?b:"\\u"+("0000"+a.charCodeAt(0).toString(16)).slice(-4)})+'"':'"'+a+'"'}function str(a,b){var c,d,e,f,g=gap,h,i=b[a];i&&typeof i=="object"&&typeof i.toJSON=="function"&&(i=i.toJSON(a)),typeof rep=="function"&&(i=rep.call(b,a,i));switch(typeof i){case"string":return quote(i);case"number":return isFinite(i)?String(i):"null";case"boolean":case"null":return String(i);case"object":if(!i)return"null";gap+=indent,h=[];if(Object.prototype.toString.apply(i)==="[object Array]"){f=i.length;for(c=0;c<f;c+=1)h[c]=str(c,i)||"null";return e=h.length===0?"[]":gap?"[\n"+gap+h.join(",\n"+gap)+"\n"+g+"]":"["+h.join(",")+"]",gap=g,e}if(rep&&typeof rep=="object"){f=rep.length;for(c=0;c<f;c+=1)d=rep[c],typeof d=="string"&&(e=str(d,i),e&&h.push(quote(d)+(gap?": ":":")+e))}else for(d in i)Object.hasOwnProperty.call(i,d)&&(e=str(d,i),e&&h.push(quote(d)+(gap?": ":":")+e));return e=h.length===0?"{}":gap?"{\n"+gap+h.join(",\n"+gap)+"\n"+g+"}":"{"+h.join(",")+"}",gap=g,e}}"use strict",typeof Date.prototype.toJSON!="function"&&(Date.prototype.toJSON=function(a){return isFinite(this.valueOf())?this.getUTCFullYear()+"-"+f(this.getUTCMonth()+1)+"-"+f(this.getUTCDate())+"T"+f(this.getUTCHours())+":"+f(this.getUTCMinutes())+":"+f(this.getUTCSeconds())+"Z":null},String.prototype.toJSON=Number.prototype.toJSON=Boolean.prototype.toJSON=function(a){return this.valueOf()});var JSON=window.JSON,cx=/[\u0000\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g,escapable=/[\\\"\x00-\x1f\x7f-\x9f\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g,gap,indent,meta={"\b":"\\b","\t":"\\t","\n":"\\n","\f":"\\f","\r":"\\r",'"':'\\"',"\\":"\\\\"},rep;typeof JSON.stringify!="function"&&(JSON.stringify=function(a,b,c){var d;gap="",indent="";if(typeof c=="number")for(d=0;d<c;d+=1)indent+=" ";else typeof c=="string"&&(indent=c);rep=b;if(!b||typeof b=="function"||typeof b=="object"&&typeof b.length=="number")return str("",{"":a});throw new Error("JSON.stringify")}),typeof JSON.parse!="function"&&(JSON.parse=function(text,reviver){function walk(a,b){var c,d,e=a[b];if(e&&typeof e=="object")for(c in e)Object.hasOwnProperty.call(e,c)&&(d=walk(e,c),d!==undefined?e[c]=d:delete e[c]);return reviver.call(a,b,e)}var j;text=String(text),cx.lastIndex=0,cx.test(text)&&(text=text.replace(cx,function(a){return"\\u"+("0000"+a.charCodeAt(0).toString(16)).slice(-4)}));if(/^[\],:{}\s]*$/.test(text.replace(/\\(?:["\\\/bfnrt]|u[0-9a-fA-F]{4})/g,"@").replace(/"[^"\\\n\r]*"|true|false|null|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?/g,"]").replace(/(?:^|:|,)(?:\s*\[)+/g,"")))return j=eval("("+text+")"),typeof reviver=="function"?walk({"":j},""):j;throw new SyntaxError("JSON.parse")})}(),function(a,b){"use strict";var c=a.History=a.History||{};if(typeof c.Adapter!="undefined")throw new Error("History.js Adapter has already been loaded...");c.Adapter={handlers:{},_uid:1,uid:function(a){return a._uid||(a._uid=c.Adapter._uid++)},bind:function(a,b,d){var e=c.Adapter.uid(a);c.Adapter.handlers[e]=c.Adapter.handlers[e]||{},c.Adapter.handlers[e][b]=c.Adapter.handlers[e][b]||[],c.Adapter.handlers[e][b].push(d),a["on"+b]=function(a,b){return function(d){c.Adapter.trigger(a,b,d)}}(a,b)},trigger:function(a,b,d){d=d||{};var e=c.Adapter.uid(a),f,g;c.Adapter.handlers[e]=c.Adapter.handlers[e]||{},c.Adapter.handlers[e][b]=c.Adapter.handlers[e][b]||[];for(f=0,g=c.Adapter.handlers[e][b].length;f<g;++f)c.Adapter.handlers[e][b][f].apply(this,[d])},extractEventData:function(a,c){var d=c&&c[a]||b;return d},onDomLoad:function(b){var c=a.setTimeout(function(){b()},2e3);a.onload=function(){clearTimeout(c),b()}}},typeof c.init!="undefined"&&c.init()}(window),function(a,b){"use strict";var c=a.document,d=a.setTimeout||d,e=a.clearTimeout||e,f=a.setInterval||f,g=a.History=a.History||{};if(typeof g.initHtml4!="undefined")throw new Error("History.js HTML4 Support has already been loaded...");g.initHtml4=function(){if(typeof g.initHtml4.initialized!="undefined")return!1;g.initHtml4.initialized=!0,g.enabled=!0,g.savedHashes=[],g.isLastHash=function(a){var b=g.getHashByIndex(),c;return c=a===b,c},g.saveHash=function(a){return g.isLastHash(a)?!1:(g.savedHashes.push(a),!0)},g.getHashByIndex=function(a){var b=null;return typeof a=="undefined"?b=g.savedHashes[g.savedHashes.length-1]:a<0?b=g.savedHashes[g.savedHashes.length+a]:b=g.savedHashes[a],b},g.discardedHashes={},g.discardedStates={},g.discardState=function(a,b,c){var d=g.getHashByState(a),e;return e={discardedState:a,backState:c,forwardState:b},g.discardedStates[d]=e,!0},g.discardHash=function(a,b,c){var d={discardedHash:a,backState:c,forwardState:b};return g.discardedHashes[a]=d,!0},g.discardedState=function(a){var b=g.getHashByState(a),c;return c=g.discardedStates[b]||!1,c},g.discardedHash=function(a){var b=g.discardedHashes[a]||!1;return b},g.recycleState=function(a){var b=g.getHashByState(a);return g.discardedState(a)&&delete g.discardedStates[b],!0},g.emulated.hashChange&&(g.hashChangeInit=function(){g.checkerFunction=null;var b="",d,e,h,i;return g.isInternetExplorer()?(d="historyjs-iframe",e=c.createElement("iframe"),e.setAttribute("id",d),e.style.display="none",c.body.appendChild(e),e.contentWindow.document.open(),e.contentWindow.document.close(),h="",i=!1,g.checkerFunction=function(){if(i)return!1;i=!0;var c=g.getHash()||"",d=g.unescapeHash(e.contentWindow.document.location.hash)||"";return c!==b?(b=c,d!==c&&(h=d=c,e.contentWindow.document.open(),e.contentWindow.document.close(),e.contentWindow.document.location.hash=g.escapeHash(c)),g.Adapter.trigger(a,"hashchange")):d!==h&&(h=d,g.setHash(d,!1)),i=!1,!0}):g.checkerFunction=function(){var c=g.getHash();return c!==b&&(b=c,g.Adapter.trigger(a,"hashchange")),!0},g.intervalList.push(f(g.checkerFunction,g.options.hashChangeInterval)),!0},g.Adapter.onDomLoad(g.hashChangeInit)),g.emulated.pushState&&(g.onHashChange=function(b){var d=b&&b.newURL||c.location.href,e=g.getHashByUrl(d),f=null,h=null,i=null,j;return g.isLastHash(e)?(g.busy(!1),!1):(g.doubleCheckComplete(),g.saveHash(e),e&&g.isTraditionalAnchor(e)?(g.Adapter.trigger(a,"anchorchange"),g.busy(!1),!1):(f=g.extractState(g.getFullUrl(e||c.location.href,!1),!0),g.isLastSavedState(f)?(g.busy(!1),!1):(h=g.getHashByState(f),j=g.discardedState(f),j?(g.getHashByIndex(-2)===g.getHashByState(j.forwardState)?g.back(!1):g.forward(!1),!1):(g.pushState(f.data,f.title,f.url,!1),!0))))},g.Adapter.bind(a,"hashchange",g.onHashChange),g.pushState=function(b,d,e,f){if(g.getHashByUrl(e))throw new Error("History.js does not support states with fragement-identifiers (hashes/anchors).");if(f!==!1&&g.busy())return g.pushQueue({scope:g,callback:g.pushState,args:arguments,queue:f}),!1;g.busy(!0);var h=g.createStateObject(b,d,e),i=g.getHashByState(h),j=g.getState(!1),k=g.getHashByState(j),l=g.getHash();return g.storeState(h),g.expectedStateId=h.id,g.recycleState(h),g.setTitle(h),i===k?(g.busy(!1),!1):i!==l&&i!==g.getShortUrl(c.location.href)?(g.setHash(i,!1),!1):(g.saveState(h),g.Adapter.trigger(a,"statechange"),g.busy(!1),!0)},g.replaceState=function(a,b,c,d){if(g.getHashByUrl(c))throw new Error("History.js does not support states with fragement-identifiers (hashes/anchors).");if(d!==!1&&g.busy())return g.pushQueue({scope:g,callback:g.replaceState,args:arguments,queue:d}),!1;g.busy(!0);var e=g.createStateObject(a,b,c),f=g.getState(!1),h=g.getStateByIndex(-2);return g.discardState(f,e,h),g.pushState(e.data,e.title,e.url,!1),!0}),g.emulated.pushState&&g.getHash()&&!g.emulated.hashChange&&g.Adapter.onDomLoad(function(){g.Adapter.trigger(a,"hashchange")})},typeof g.init!="undefined"&&g.init()}(window),function(a,b){"use strict";var c=a.console||b,d=a.document,e=a.navigator,f=a.sessionStorage||!1,g=a.setTimeout,h=a.clearTimeout,i=a.setInterval,j=a.clearInterval,k=a.JSON,l=a.alert,m=a.History=a.History||{},n=a.history;k.stringify=k.stringify||k.encode,k.parse=k.parse||k.decode;if(typeof m.init!="undefined")throw new Error("History.js Core has already been loaded...");m.init=function(){return typeof m.Adapter=="undefined"?!1:(typeof m.initCore!="undefined"&&m.initCore(),typeof m.initHtml4!="undefined"&&m.initHtml4(),!0)},m.initCore=function(){if(typeof m.initCore.initialized!="undefined")return!1;m.initCore.initialized=!0,m.options=m.options||{},m.options.hashChangeInterval=m.options.hashChangeInterval||100,m.options.safariPollInterval=m.options.safariPollInterval||500,m.options.doubleCheckInterval=m.options.doubleCheckInterval||500,m.options.storeInterval=m.options.storeInterval||1e3,m.options.busyDelay=m.options.busyDelay||250,m.options.debug=m.options.debug||!1,m.options.initialTitle=m.options.initialTitle||d.title,m.intervalList=[],m.clearAllIntervals=function(){var a,b=m.intervalList;if(typeof b!="undefined"&&b!==null){for(a=0;a<b.length;a++)j(b[a]);m.intervalList=null}},m.debug=function(){(m.options.debug||!1)&&m.log.apply(m,arguments)},m.log=function(){var a=typeof c!="undefined"&&typeof c.log!="undefined"&&typeof c.log.apply!="undefined",b=d.getElementById("log"),e,f,g,h,i;a?(h=Array.prototype.slice.call(arguments),e=h.shift(),typeof c.debug!="undefined"?c.debug.apply(c,[e,h]):c.log.apply(c,[e,h])):e="\n"+arguments[0]+"\n";for(f=1,g=arguments.length;f<g;++f){i=arguments[f];if(typeof i=="object"&&typeof k!="undefined")try{i=k.stringify(i)}catch(j){}e+="\n"+i+"\n"}return b?(b.value+=e+"\n-----\n",b.scrollTop=b.scrollHeight-b.clientHeight):a||l(e),!0},m.getInternetExplorerMajorVersion=function(){var a=m.getInternetExplorerMajorVersion.cached=typeof m.getInternetExplorerMajorVersion.cached!="undefined"?m.getInternetExplorerMajorVersion.cached:function(){var a=3,b=d.createElement("div"),c=b.getElementsByTagName("i");while((b.innerHTML="<!--[if gt IE "+ ++a+"]><i></i><![endif]-->")&&c[0]);return a>4?a:!1}();return a},m.isInternetExplorer=function(){var a=m.isInternetExplorer.cached=typeof m.isInternetExplorer.cached!="undefined"?m.isInternetExplorer.cached:Boolean(m.getInternetExplorerMajorVersion());return a},m.emulated={pushState:!Boolean(a.history&&a.history.pushState&&a.history.replaceState&&!/ Mobile\/([1-7][a-z]|(8([abcde]|f(1[0-8]))))/i.test(e.userAgent)&&!/AppleWebKit\/5([0-2]|3[0-2])/i.test(e.userAgent)),hashChange:Boolean(!("onhashchange"in a||"onhashchange"in d)||m.isInternetExplorer()&&m.getInternetExplorerMajorVersion()<8)},m.enabled=!m.emulated.pushState,m.bugs={setHash:Boolean(!m.emulated.pushState&&e.vendor==="Apple Computer, Inc."&&/AppleWebKit\/5([0-2]|3[0-3])/.test(e.userAgent)),safariPoll:Boolean(!m.emulated.pushState&&e.vendor==="Apple Computer, Inc."&&/AppleWebKit\/5([0-2]|3[0-3])/.test(e.userAgent)),ieDoubleCheck:Boolean(m.isInternetExplorer()&&m.getInternetExplorerMajorVersion()<8),hashEscape:Boolean(m.isInternetExplorer()&&m.getInternetExplorerMajorVersion()<7)},m.isEmptyObject=function(a){for(var b in a)return!1;return!0},m.cloneObject=function(a){var b,c;return a?(b=k.stringify(a),c=k.parse(b)):c={},c},m.getRootUrl=function(){var a=d.location.protocol+"//"+(d.location.hostname||d.location.host);if(d.location.port||!1)a+=":"+d.location.port;return a+="/",a},m.getBaseHref=function(){var a=d.getElementsByTagName("base"),b=null,c="";return a.length===1&&(b=a[0],c=b.href.replace(/[^\/]+$/,"")),c=c.replace(/\/+$/,""),c&&(c+="/"),c},m.getBaseUrl=function(){var a=m.getBaseHref()||m.getBasePageUrl()||m.getRootUrl();return a},m.getPageUrl=function(){var a=m.getState(!1,!1),b=(a||{}).url||d.location.href,c;return c=b.replace(/\/+$/,"").replace(/[^\/]+$/,function(a,b,c){return/\./.test(a)?a:a+"/"}),c},m.getBasePageUrl=function(){var a=d.location.href.replace(/[#\?].*/,"").replace(/[^\/]+$/,function(a,b,c){return/[^\/]$/.test(a)?"":a}).replace(/\/+$/,"")+"/";return a},m.getFullUrl=function(a,b){var c=a,d=a.substring(0,1);return b=typeof b=="undefined"?!0:b,/[a-z]+\:\/\//.test(a)||(d==="/"?c=m.getRootUrl()+a.replace(/^\/+/,""):d==="#"?c=m.getPageUrl().replace(/#.*/,"")+a:d==="?"?c=m.getPageUrl().replace(/[\?#].*/,"")+a:b?c=m.getBaseUrl()+a.replace(/^(\.\/)+/,""):c=m.getBasePageUrl()+a.replace(/^(\.\/)+/,"")),c.replace(/\#$/,"")},m.getShortUrl=function(a){var b=a,c=m.getBaseUrl(),d=m.getRootUrl();return m.emulated.pushState&&(b=b.replace(c,"")),b=b.replace(d,"/"),m.isTraditionalAnchor(b)&&(b="./"+b),b=b.replace(/^(\.\/)+/g,"./").replace(/\#$/,""),b},m.store={},m.idToState=m.idToState||{},m.stateToId=m.stateToId||{},m.urlToId=m.urlToId||{},m.storedStates=m.storedStates||[],m.savedStates=m.savedStates||[],m.normalizeStore=function(){m.store.idToState=m.store.idToState||{},m.store.urlToId=m.store.urlToId||{},m.store.stateToId=m.store.stateToId||{}},m.getState=function(a,b){typeof a=="undefined"&&(a=!0),typeof b=="undefined"&&(b=!0);var c=m.getLastSavedState();return!c&&b&&(c=m.createStateObject()),a&&(c=m.cloneObject(c),c.url=c.cleanUrl||c.url),c},m.getIdByState=function(a){var b=m.extractId(a.url),c;if(!b){c=m.getStateString(a);if(typeof m.stateToId[c]!="undefined")b=m.stateToId[c];else if(typeof m.store.stateToId[c]!="undefined")b=m.store.stateToId[c];else{for(;;){b=(new Date).getTime()+String(Math.random()).replace(/\D/g,"");if(typeof m.idToState[b]=="undefined"&&typeof m.store.idToState[b]=="undefined")break}m.stateToId[c]=b,m.idToState[b]=a}}return b},m.normalizeState=function(a){var b,c;if(!a||typeof a!="object")a={};if(typeof a.normalized!="undefined")return a;if(!a.data||typeof a.data!="object")a.data={};b={},b.normalized=!0,b.title=a.title||"",b.url=m.getFullUrl(m.unescapeString(a.url||d.location.href)),b.hash=m.getShortUrl(b.url),b.data=m.cloneObject(a.data),b.id=m.getIdByState(b),b.cleanUrl=b.url.replace(/\??\&_suid.*/,""),b.url=b.cleanUrl,c=!m.isEmptyObject(b.data);if(b.title||c)b.hash=m.getShortUrl(b.url).replace(/\??\&_suid.*/,""),/\?/.test(b.hash)||(b.hash+="?"),b.hash+="&_suid="+b.id;return b.hashedUrl=m.getFullUrl(b.hash),(m.emulated.pushState||m.bugs.safariPoll)&&m.hasUrlDuplicate(b)&&(b.url=b.hashedUrl),b},m.createStateObject=function(a,b,c){var d={data:a,title:b,url:c};return d=m.normalizeState(d),d},m.getStateById=function(a){a=String(a);var c=m.idToState[a]||m.store.idToState[a]||b;return c},m.getStateString=function(a){var b,c,d;return b=m.normalizeState(a),c={data:b.data,title:a.title,url:a.url},d=k.stringify(c),d},m.getStateId=function(a){var b,c;return b=m.normalizeState(a),c=b.id,c},m.getHashByState=function(a){var b,c;return b=m.normalizeState(a),c=b.hash,c},m.extractId=function(a){var b,c,d;return c=/(.*)\&_suid=([0-9]+)$/.exec(a),d=c?c[1]||a:a,b=c?String(c[2]||""):"",b||!1},m.isTraditionalAnchor=function(a){var b=!/[\/\?\.]/.test(a);return b},m.extractState=function(a,b){var c=null,d,e;return b=b||!1,d=m.extractId(a),d&&(c=m.getStateById(d)),c||(e=m.getFullUrl(a),d=m.getIdByUrl(e)||!1,d&&(c=m.getStateById(d)),!c&&b&&!m.isTraditionalAnchor(a)&&(c=m.createStateObject(null,null,e))),c},m.getIdByUrl=function(a){var c=m.urlToId[a]||m.store.urlToId[a]||b;return c},m.getLastSavedState=function(){return m.savedStates[m.savedStates.length-1]||b},m.getLastStoredState=function(){return m.storedStates[m.storedStates.length-1]||b},m.hasUrlDuplicate=function(a){var b=!1,c;return c=m.extractState(a.url),b=c&&c.id!==a.id,b},m.storeState=function(a){return m.urlToId[a.url]=a.id,m.storedStates.push(m.cloneObject(a)),a},m.isLastSavedState=function(a){var b=!1,c,d,e;return m.savedStates.length&&(c=a.id,d=m.getLastSavedState(),e=d.id,b=c===e),b},m.saveState=function(a){return m.isLastSavedState(a)?!1:(m.savedStates.push(m.cloneObject(a)),!0)},m.getStateByIndex=function(a){var b=null;return typeof a=="undefined"?b=m.savedStates[m.savedStates.length-1]:a<0?b=m.savedStates[m.savedStates.length+a]:b=m.savedStates[a],b},m.getHash=function(){var a=m.unescapeHash(d.location.hash);return a},m.unescapeString=function(b){var c=b,d;for(;;){d=a.unescape(c);if(d===c)break;c=d}return c},m.unescapeHash=function(a){var b=m.normalizeHash(a);return b=m.unescapeString(b),b},m.normalizeHash=function(a){var b=a.replace(/[^#]*#/,"").replace(/#.*/,"");return b},m.setHash=function(a,b){var c,e,f;return b!==!1&&m.busy()?(m.pushQueue({scope:m,callback:m.setHash,args:arguments,queue:b}),!1):(c=m.escapeHash(a),m.busy(!0),e=m.extractState(a,!0),e&&!m.emulated.pushState?m.pushState(e.data,e.title,e.url,!1):d.location.hash!==c&&(m.bugs.setHash?(f=m.getPageUrl(),m.pushState(null,null,f+"#"+c,!1)):d.location.hash=c),m)},m.escapeHash=function(b){var c=m.normalizeHash(b);return c=a.escape(c),m.bugs.hashEscape||(c=c.replace(/\%21/g,"!").replace(/\%26/g,"&").replace(/\%3D/g,"=").replace(/\%3F/g,"?")),c},m.getHashByUrl=function(a){var b=String(a).replace(/([^#]*)#?([^#]*)#?(.*)/,"$2");return b=m.unescapeHash(b),b},m.setTitle=function(a){var b=a.title,c;b||(c=m.getStateByIndex(0),c&&c.url===a.url&&(b=c.title||m.options.initialTitle));try{d.getElementsByTagName("title")[0].innerHTML=b.replace("<","&lt;").replace(">","&gt;").replace(" & "," &amp; ")}catch(e){}return d.title=b,m},m.queues=[],m.busy=function(a){typeof a!="undefined"?m.busy.flag=a:typeof m.busy.flag=="undefined"&&(m.busy.flag=!1);if(!m.busy.flag){h(m.busy.timeout);var b=function(){var a,c,d;if(m.busy.flag)return;for(a=m.queues.length-1;a>=0;--a){c=m.queues[a];if(c.length===0)continue;d=c.shift(),m.fireQueueItem(d),m.busy.timeout=g(b,m.options.busyDelay)}};m.busy.timeout=g(b,m.options.busyDelay)}return m.busy.flag},m.busy.flag=!1,m.fireQueueItem=function(a){return a.callback.apply(a.scope||m,a.args||[])},m.pushQueue=function(a){return m.queues[a.queue||0]=m.queues[a.queue||0]||[],m.queues[a.queue||0].push(a),m},m.queue=function(a,b){return typeof a=="function"&&(a={callback:a}),typeof b!="undefined"&&(a.queue=b),m.busy()?m.pushQueue(a):m.fireQueueItem(a),m},m.clearQueue=function(){return m.busy.flag=!1,m.queues=[],m},m.stateChanged=!1,m.doubleChecker=!1,m.doubleCheckComplete=function(){return m.stateChanged=!0,m.doubleCheckClear(),m},m.doubleCheckClear=function(){return m.doubleChecker&&(h(m.doubleChecker),m.doubleChecker=!1),m},m.doubleCheck=function(a){return m.stateChanged=!1,m.doubleCheckClear(),m.bugs.ieDoubleCheck&&(m.doubleChecker=g(function(){return m.doubleCheckClear(),m.stateChanged||a(),!0},m.options.doubleCheckInterval)),m},m.safariStatePoll=function(){var b=m.extractState(d.location.href),c;if(!m.isLastSavedState(b))c=b;else return;return c||(c=m.createStateObject()),m.Adapter.trigger(a,"popstate"),m},m.back=function(a){return a!==!1&&m.busy()?(m.pushQueue({scope:m,callback:m.back,args:arguments,queue:a}),!1):(m.busy(!0),m.doubleCheck(function(){m.back(!1)}),n.go(-1),!0)},m.forward=function(a){return a!==!1&&m.busy()?(m.pushQueue({scope:m,callback:m.forward,args:arguments,queue:a}),!1):(m.busy(!0),m.doubleCheck(function(){m.forward(!1)}),n.go(1),!0)},m.go=function(a,b){var c;if(a>0)for(c=1;c<=a;++c)m.forward(b);else{if(!(a<0))throw new Error("History.go: History.go requires a positive or negative integer passed.");for(c=-1;c>=a;--c)m.back(b)}return m};if(m.emulated.pushState){var o=function(){};m.pushState=m.pushState||o,m.replaceState=m.replaceState||o}else m.onPopState=function(b,c){var e=!1,f=!1,g,h;return m.doubleCheckComplete(),g=m.getHash(),g?(h=m.extractState(g||d.location.href,!0),h?m.replaceState(h.data,h.title,h.url,!1):(m.Adapter.trigger(a,"anchorchange"),m.busy(!1)),m.expectedStateId=!1,!1):(e=m.Adapter.extractEventData("state",b,c)||!1,e?f=m.getStateById(e):m.expectedStateId?f=m.getStateById(m.expectedStateId):f=m.extractState(d.location.href),f||(f=m.createStateObject(null,null,d.location.href)),m.expectedStateId=!1,m.isLastSavedState(f)?(m.busy(!1),!1):(m.storeState(f),m.saveState(f),m.setTitle(f),m.Adapter.trigger(a,"statechange"),m.busy(!1),!0))},m.Adapter.bind(a,"popstate",m.onPopState),m.pushState=function(b,c,d,e){if(m.getHashByUrl(d)&&m.emulated.pushState)throw new Error("History.js does not support states with fragement-identifiers (hashes/anchors).");if(e!==!1&&m.busy())return m.pushQueue({scope:m,callback:m.pushState,args:arguments,queue:e}),!1;m.busy(!0);var f=m.createStateObject(b,c,d);return m.isLastSavedState(f)?m.busy(!1):(m.storeState(f),m.expectedStateId=f.id,n.pushState(f.id,f.title,f.url),m.Adapter.trigger(a,"popstate")),!0},m.replaceState=function(b,c,d,e){if(m.getHashByUrl(d)&&m.emulated.pushState)throw new Error("History.js does not support states with fragement-identifiers (hashes/anchors).");if(e!==!1&&m.busy())return m.pushQueue({scope:m,callback:m.replaceState,args:arguments,queue:e}),!1;m.busy(!0);var f=m.createStateObject(b,c,d);return m.isLastSavedState(f)?m.busy(!1):(m.storeState(f),m.expectedStateId=f.id,n.replaceState(f.id,f.title,f.url),m.Adapter.trigger(a,"popstate")),!0};if(f){try{m.store=k.parse(f.getItem("History.store"))||{}}catch(p){m.store={}}m.normalizeStore()}else m.store={},m.normalizeStore();m.Adapter.bind(a,"beforeunload",m.clearAllIntervals),m.Adapter.bind(a,"unload",m.clearAllIntervals),m.saveState(m.storeState(m.extractState(d.location.href,!0))),f&&(m.onUnload=function(){var a,b;try{a=k.parse(f.getItem("History.store"))||{}}catch(c){a={}}a.idToState=a.idToState||{},a.urlToId=a.urlToId||{},a.stateToId=a.stateToId||{};for(b in m.idToState){if(!m.idToState.hasOwnProperty(b))continue;a.idToState[b]=m.idToState[b]}for(b in m.urlToId){if(!m.urlToId.hasOwnProperty(b))continue;a.urlToId[b]=m.urlToId[b]}for(b in m.stateToId){if(!m.stateToId.hasOwnProperty(b))continue;a.stateToId[b]=m.stateToId[b]}m.store=a,m.normalizeStore(),f.setItem("History.store",k.stringify(a))},m.intervalList.push(i(m.onUnload,m.options.storeInterval)),m.Adapter.bind(a,"beforeunload",m.onUnload),m.Adapter.bind(a,"unload",m.onUnload));if(!m.emulated.pushState){m.bugs.safariPoll&&m.intervalList.push(i(m.safariStatePoll,m.options.safariPollInterval));if(e.vendor==="Apple Computer, Inc."||(e.appCodeName||"")==="Mozilla")m.Adapter.bind(a,"hashchange",function(){m.Adapter.trigger(a,"popstate")}),m.getHash()&&m.Adapter.onDomLoad(function(){m.Adapter.trigger(a,"hashchange")})}},m.init()}(window)
1
+ (function(a,b){"use strict";var c=a.History=a.History||{};if(typeof c.Adapter!="undefined")throw new Error("History.js Adapter has already been loaded...");c.Adapter={handlers:{},_uid:1,uid:function(a){return a._uid||(a._uid=c.Adapter._uid++)},bind:function(a,b,d){var e=c.Adapter.uid(a);c.Adapter.handlers[e]=c.Adapter.handlers[e]||{},c.Adapter.handlers[e][b]=c.Adapter.handlers[e][b]||[],c.Adapter.handlers[e][b].push(d),a["on"+b]=function(a,b){return function(d){c.Adapter.trigger(a,b,d)}}(a,b)},trigger:function(a,b,d){d=d||{};var e=c.Adapter.uid(a),f,g;c.Adapter.handlers[e]=c.Adapter.handlers[e]||{},c.Adapter.handlers[e][b]=c.Adapter.handlers[e][b]||[];for(f=0,g=c.Adapter.handlers[e][b].length;f<g;++f)c.Adapter.handlers[e][b][f].apply(this,[d])},extractEventData:function(a,c){var d=c&&c[a]||b;return d},onDomLoad:function(b){var c=a.setTimeout(function(){b()},2e3);a.onload=function(){clearTimeout(c),b()}}},typeof c.init!="undefined"&&c.init()})(window),function(a,b){"use strict";var c=a.console||b,d=a.document,e=a.navigator,f=a.sessionStorage||!1,g=a.setTimeout,h=a.clearTimeout,i=a.setInterval,j=a.clearInterval,k=a.JSON,l=a.alert,m=a.History=a.History||{},n=a.history;k.stringify=k.stringify||k.encode,k.parse=k.parse||k.decode;if(typeof m.init!="undefined")throw new Error("History.js Core has already been loaded...");m.init=function(){return typeof m.Adapter=="undefined"?!1:(typeof m.initCore!="undefined"&&m.initCore(),typeof m.initHtml4!="undefined"&&m.initHtml4(),!0)},m.initCore=function(){if(typeof m.initCore.initialized!="undefined")return!1;m.initCore.initialized=!0,m.options=m.options||{},m.options.hashChangeInterval=m.options.hashChangeInterval||100,m.options.safariPollInterval=m.options.safariPollInterval||500,m.options.doubleCheckInterval=m.options.doubleCheckInterval||500,m.options.storeInterval=m.options.storeInterval||1e3,m.options.busyDelay=m.options.busyDelay||250,m.options.debug=m.options.debug||!1,m.options.initialTitle=m.options.initialTitle||d.title,m.intervalList=[],m.clearAllIntervals=function(){var a,b=m.intervalList;if(typeof b!="undefined"&&b!==null){for(a=0;a<b.length;a++)j(b[a]);m.intervalList=null}},m.debug=function(){(m.options.debug||!1)&&m.log.apply(m,arguments)},m.log=function(){var a=typeof c!="undefined"&&typeof c.log!="undefined"&&typeof c.log.apply!="undefined",b=d.getElementById("log"),e,f,g,h,i;a?(h=Array.prototype.slice.call(arguments),e=h.shift(),typeof c.debug!="undefined"?c.debug.apply(c,[e,h]):c.log.apply(c,[e,h])):e="\n"+arguments[0]+"\n";for(f=1,g=arguments.length;f<g;++f){i=arguments[f];if(typeof i=="object"&&typeof k!="undefined")try{i=k.stringify(i)}catch(j){}e+="\n"+i+"\n"}return b?(b.value+=e+"\n-----\n",b.scrollTop=b.scrollHeight-b.clientHeight):a||l(e),!0},m.getInternetExplorerMajorVersion=function(){var a=m.getInternetExplorerMajorVersion.cached=typeof m.getInternetExplorerMajorVersion.cached!="undefined"?m.getInternetExplorerMajorVersion.cached:function(){var a=3,b=d.createElement("div"),c=b.getElementsByTagName("i");while((b.innerHTML="<!--[if gt IE "+ ++a+"]><i></i><![endif]-->")&&c[0]);return a>4?a:!1}();return a},m.isInternetExplorer=function(){var a=m.isInternetExplorer.cached=typeof m.isInternetExplorer.cached!="undefined"?m.isInternetExplorer.cached:Boolean(m.getInternetExplorerMajorVersion());return a},m.emulated={pushState:!Boolean(a.history&&a.history.pushState&&a.history.replaceState&&!/ Mobile\/([1-7][a-z]|(8([abcde]|f(1[0-8]))))/i.test(e.userAgent)&&!/AppleWebKit\/5([0-2]|3[0-2])/i.test(e.userAgent)),hashChange:Boolean(!("onhashchange"in a||"onhashchange"in d)||m.isInternetExplorer()&&m.getInternetExplorerMajorVersion()<8)},m.enabled=!m.emulated.pushState,m.bugs={setHash:Boolean(!m.emulated.pushState&&e.vendor==="Apple Computer, Inc."&&/AppleWebKit\/5([0-2]|3[0-3])/.test(e.userAgent)),safariPoll:Boolean(!m.emulated.pushState&&e.vendor==="Apple Computer, Inc."&&/AppleWebKit\/5([0-2]|3[0-3])/.test(e.userAgent)),ieDoubleCheck:Boolean(m.isInternetExplorer()&&m.getInternetExplorerMajorVersion()<8),hashEscape:Boolean(m.isInternetExplorer()&&m.getInternetExplorerMajorVersion()<7)},m.isEmptyObject=function(a){for(var b in a)return!1;return!0},m.cloneObject=function(a){var b,c;return a?(b=k.stringify(a),c=k.parse(b)):c={},c},m.getRootUrl=function(){var a=d.location.protocol+"//"+(d.location.hostname||d.location.host);if(d.location.port||!1)a+=":"+d.location.port;return a+="/",a},m.getBaseHref=function(){var a=d.getElementsByTagName("base"),b=null,c="";return a.length===1&&(b=a[0],c=b.href.replace(/[^\/]+$/,"")),c=c.replace(/\/+$/,""),c&&(c+="/"),c},m.getBaseUrl=function(){var a=m.getBaseHref()||m.getBasePageUrl()||m.getRootUrl();return a},m.getPageUrl=function(){var a=m.getState(!1,!1),b=(a||{}).url||d.location.href,c;return c=b.replace(/\/+$/,"").replace(/[^\/]+$/,function(a,b,c){return/\./.test(a)?a:a+"/"}),c},m.getBasePageUrl=function(){var a=d.location.href.replace(/[#\?].*/,"").replace(/[^\/]+$/,function(a,b,c){return/[^\/]$/.test(a)?"":a}).replace(/\/+$/,"")+"/";return a},m.getFullUrl=function(a,b){var c=a,d=a.substring(0,1);return b=typeof b=="undefined"?!0:b,/[a-z]+\:\/\//.test(a)||(d==="/"?c=m.getRootUrl()+a.replace(/^\/+/,""):d==="#"?c=m.getPageUrl().replace(/#.*/,"")+a:d==="?"?c=m.getPageUrl().replace(/[\?#].*/,"")+a:b?c=m.getBaseUrl()+a.replace(/^(\.\/)+/,""):c=m.getBasePageUrl()+a.replace(/^(\.\/)+/,"")),c.replace(/\#$/,"")},m.getShortUrl=function(a){var b=a,c=m.getBaseUrl(),d=m.getRootUrl();return m.emulated.pushState&&(b=b.replace(c,"")),b=b.replace(d,"/"),m.isTraditionalAnchor(b)&&(b="./"+b),b=b.replace(/^(\.\/)+/g,"./").replace(/\#$/,""),b},m.store={},m.idToState=m.idToState||{},m.stateToId=m.stateToId||{},m.urlToId=m.urlToId||{},m.storedStates=m.storedStates||[],m.savedStates=m.savedStates||[],m.normalizeStore=function(){m.store.idToState=m.store.idToState||{},m.store.urlToId=m.store.urlToId||{},m.store.stateToId=m.store.stateToId||{}},m.getState=function(a,b){typeof a=="undefined"&&(a=!0),typeof b=="undefined"&&(b=!0);var c=m.getLastSavedState();return!c&&b&&(c=m.createStateObject()),a&&(c=m.cloneObject(c),c.url=c.cleanUrl||c.url),c},m.getIdByState=function(a){var b=m.extractId(a.url),c;if(!b){c=m.getStateString(a);if(typeof m.stateToId[c]!="undefined")b=m.stateToId[c];else if(typeof m.store.stateToId[c]!="undefined")b=m.store.stateToId[c];else{for(;;){b=(new Date).getTime()+String(Math.random()).replace(/\D/g,"");if(typeof m.idToState[b]=="undefined"&&typeof m.store.idToState[b]=="undefined")break}m.stateToId[c]=b,m.idToState[b]=a}}return b},m.normalizeState=function(a){var b,c;if(!a||typeof a!="object")a={};if(typeof a.normalized!="undefined")return a;if(!a.data||typeof a.data!="object")a.data={};b={},b.normalized=!0,b.title=a.title||"",b.url=m.getFullUrl(m.unescapeString(a.url||d.location.href)),b.hash=m.getShortUrl(b.url),b.data=m.cloneObject(a.data),b.id=m.getIdByState(b),b.cleanUrl=b.url.replace(/\??\&_suid.*/,""),b.url=b.cleanUrl,c=!m.isEmptyObject(b.data);if(b.title||c)b.hash=m.getShortUrl(b.url).replace(/\??\&_suid.*/,""),/\?/.test(b.hash)||(b.hash+="?"),b.hash+="&_suid="+b.id;return b.hashedUrl=m.getFullUrl(b.hash),(m.emulated.pushState||m.bugs.safariPoll)&&m.hasUrlDuplicate(b)&&(b.url=b.hashedUrl),b},m.createStateObject=function(a,b,c){var d={data:a,title:b,url:c};return d=m.normalizeState(d),d},m.getStateById=function(a){a=String(a);var c=m.idToState[a]||m.store.idToState[a]||b;return c},m.getStateString=function(a){var b,c,d;return b=m.normalizeState(a),c={data:b.data,title:a.title,url:a.url},d=k.stringify(c),d},m.getStateId=function(a){var b,c;return b=m.normalizeState(a),c=b.id,c},m.getHashByState=function(a){var b,c;return b=m.normalizeState(a),c=b.hash,c},m.extractId=function(a){var b,c,d;return c=/(.*)\&_suid=([0-9]+)$/.exec(a),d=c?c[1]||a:a,b=c?String(c[2]||""):"",b||!1},m.isTraditionalAnchor=function(a){var b=!/[\/\?\.]/.test(a);return b},m.extractState=function(a,b){var c=null,d,e;return b=b||!1,d=m.extractId(a),d&&(c=m.getStateById(d)),c||(e=m.getFullUrl(a),d=m.getIdByUrl(e)||!1,d&&(c=m.getStateById(d)),!c&&b&&!m.isTraditionalAnchor(a)&&(c=m.createStateObject(null,null,e))),c},m.getIdByUrl=function(a){var c=m.urlToId[a]||m.store.urlToId[a]||b;return c},m.getLastSavedState=function(){return m.savedStates[m.savedStates.length-1]||b},m.getLastStoredState=function(){return m.storedStates[m.storedStates.length-1]||b},m.hasUrlDuplicate=function(a){var b=!1,c;return c=m.extractState(a.url),b=c&&c.id!==a.id,b},m.storeState=function(a){return m.urlToId[a.url]=a.id,m.storedStates.push(m.cloneObject(a)),a},m.isLastSavedState=function(a){var b=!1,c,d,e;return m.savedStates.length&&(c=a.id,d=m.getLastSavedState(),e=d.id,b=c===e),b},m.saveState=function(a){return m.isLastSavedState(a)?!1:(m.savedStates.push(m.cloneObject(a)),!0)},m.getStateByIndex=function(a){var b=null;return typeof a=="undefined"?b=m.savedStates[m.savedStates.length-1]:a<0?b=m.savedStates[m.savedStates.length+a]:b=m.savedStates[a],b},m.getHash=function(){var a=m.unescapeHash(d.location.hash);return a},m.unescapeString=function(b){var c=b,d;for(;;){d=a.unescape(c);if(d===c)break;c=d}return c},m.unescapeHash=function(a){var b=m.normalizeHash(a);return b=m.unescapeString(b),b},m.normalizeHash=function(a){var b=a.replace(/[^#]*#/,"").replace(/#.*/,"");return b},m.setHash=function(a,b){var c,e,f;return b!==!1&&m.busy()?(m.pushQueue({scope:m,callback:m.setHash,args:arguments,queue:b}),!1):(c=m.escapeHash(a),m.busy(!0),e=m.extractState(a,!0),e&&!m.emulated.pushState?m.pushState(e.data,e.title,e.url,!1):d.location.hash!==c&&(m.bugs.setHash?(f=m.getPageUrl(),m.pushState(null,null,f+"#"+c,!1)):d.location.hash=c),m)},m.escapeHash=function(b){var c=m.normalizeHash(b);return c=a.escape(c),m.bugs.hashEscape||(c=c.replace(/\%21/g,"!").replace(/\%26/g,"&").replace(/\%3D/g,"=").replace(/\%3F/g,"?")),c},m.getHashByUrl=function(a){var b=String(a).replace(/([^#]*)#?([^#]*)#?(.*)/,"$2");return b=m.unescapeHash(b),b},m.setTitle=function(a){var b=a.title,c;b||(c=m.getStateByIndex(0),c&&c.url===a.url&&(b=c.title||m.options.initialTitle));try{d.getElementsByTagName("title")[0].innerHTML=b.replace("<","&lt;").replace(">","&gt;").replace(" & "," &amp; ")}catch(e){}return d.title=b,m},m.queues=[],m.busy=function(a){typeof a!="undefined"?m.busy.flag=a:typeof m.busy.flag=="undefined"&&(m.busy.flag=!1);if(!m.busy.flag){h(m.busy.timeout);var b=function(){var a,c,d;if(m.busy.flag)return;for(a=m.queues.length-1;a>=0;--a){c=m.queues[a];if(c.length===0)continue;d=c.shift(),m.fireQueueItem(d),m.busy.timeout=g(b,m.options.busyDelay)}};m.busy.timeout=g(b,m.options.busyDelay)}return m.busy.flag},m.busy.flag=!1,m.fireQueueItem=function(a){return a.callback.apply(a.scope||m,a.args||[])},m.pushQueue=function(a){return m.queues[a.queue||0]=m.queues[a.queue||0]||[],m.queues[a.queue||0].push(a),m},m.queue=function(a,b){return typeof a=="function"&&(a={callback:a}),typeof b!="undefined"&&(a.queue=b),m.busy()?m.pushQueue(a):m.fireQueueItem(a),m},m.clearQueue=function(){return m.busy.flag=!1,m.queues=[],m},m.stateChanged=!1,m.doubleChecker=!1,m.doubleCheckComplete=function(){return m.stateChanged=!0,m.doubleCheckClear(),m},m.doubleCheckClear=function(){return m.doubleChecker&&(h(m.doubleChecker),m.doubleChecker=!1),m},m.doubleCheck=function(a){return m.stateChanged=!1,m.doubleCheckClear(),m.bugs.ieDoubleCheck&&(m.doubleChecker=g(function(){return m.doubleCheckClear(),m.stateChanged||a(),!0},m.options.doubleCheckInterval)),m},m.safariStatePoll=function(){var b=m.extractState(d.location.href),c;if(!m.isLastSavedState(b))c=b;else return;return c||(c=m.createStateObject()),m.Adapter.trigger(a,"popstate"),m},m.back=function(a){return a!==!1&&m.busy()?(m.pushQueue({scope:m,callback:m.back,args:arguments,queue:a}),!1):(m.busy(!0),m.doubleCheck(function(){m.back(!1)}),n.go(-1),!0)},m.forward=function(a){return a!==!1&&m.busy()?(m.pushQueue({scope:m,callback:m.forward,args:arguments,queue:a}),!1):(m.busy(!0),m.doubleCheck(function(){m.forward(!1)}),n.go(1),!0)},m.go=function(a,b){var c;if(a>0)for(c=1;c<=a;++c)m.forward(b);else{if(!(a<0))throw new Error("History.go: History.go requires a positive or negative integer passed.");for(c=-1;c>=a;--c)m.back(b)}return m};if(m.emulated.pushState){var o=function(){};m.pushState=m.pushState||o,m.replaceState=m.replaceState||o}else m.onPopState=function(b,c){var e=!1,f=!1,g,h;return m.doubleCheckComplete(),g=m.getHash(),g?(h=m.extractState(g||d.location.href,!0),h?m.replaceState(h.data,h.title,h.url,!1):(m.Adapter.trigger(a,"anchorchange"),m.busy(!1)),m.expectedStateId=!1,!1):(e=m.Adapter.extractEventData("state",b,c)||!1,e?f=m.getStateById(e):m.expectedStateId?f=m.getStateById(m.expectedStateId):f=m.extractState(d.location.href),f||(f=m.createStateObject(null,null,d.location.href)),m.expectedStateId=!1,m.isLastSavedState(f)?(m.busy(!1),!1):(m.storeState(f),m.saveState(f),m.setTitle(f),m.Adapter.trigger(a,"statechange"),m.busy(!1),!0))},m.Adapter.bind(a,"popstate",m.onPopState),m.pushState=function(b,c,d,e){if(m.getHashByUrl(d)&&m.emulated.pushState)throw new Error("History.js does not support states with fragement-identifiers (hashes/anchors).");if(e!==!1&&m.busy())return m.pushQueue({scope:m,callback:m.pushState,args:arguments,queue:e}),!1;m.busy(!0);var f=m.createStateObject(b,c,d);return m.isLastSavedState(f)?m.busy(!1):(m.storeState(f),m.expectedStateId=f.id,n.pushState(f.id,f.title,f.url),m.Adapter.trigger(a,"popstate")),!0},m.replaceState=function(b,c,d,e){if(m.getHashByUrl(d)&&m.emulated.pushState)throw new Error("History.js does not support states with fragement-identifiers (hashes/anchors).");if(e!==!1&&m.busy())return m.pushQueue({scope:m,callback:m.replaceState,args:arguments,queue:e}),!1;m.busy(!0);var f=m.createStateObject(b,c,d);return m.isLastSavedState(f)?m.busy(!1):(m.storeState(f),m.expectedStateId=f.id,n.replaceState(f.id,f.title,f.url),m.Adapter.trigger(a,"popstate")),!0};if(f){try{m.store=k.parse(f.getItem("History.store"))||{}}catch(p){m.store={}}m.normalizeStore()}else m.store={},m.normalizeStore();m.Adapter.bind(a,"beforeunload",m.clearAllIntervals),m.Adapter.bind(a,"unload",m.clearAllIntervals),m.saveState(m.storeState(m.extractState(d.location.href,!0))),f&&(m.onUnload=function(){var a,b;try{a=k.parse(f.getItem("History.store"))||{}}catch(c){a={}}a.idToState=a.idToState||{},a.urlToId=a.urlToId||{},a.stateToId=a.stateToId||{};for(b in m.idToState){if(!m.idToState.hasOwnProperty(b))continue;a.idToState[b]=m.idToState[b]}for(b in m.urlToId){if(!m.urlToId.hasOwnProperty(b))continue;a.urlToId[b]=m.urlToId[b]}for(b in m.stateToId){if(!m.stateToId.hasOwnProperty(b))continue;a.stateToId[b]=m.stateToId[b]}m.store=a,m.normalizeStore(),f.setItem("History.store",k.stringify(a))},m.intervalList.push(i(m.onUnload,m.options.storeInterval)),m.Adapter.bind(a,"beforeunload",m.onUnload),m.Adapter.bind(a,"unload",m.onUnload));if(!m.emulated.pushState){m.bugs.safariPoll&&m.intervalList.push(i(m.safariStatePoll,m.options.safariPollInterval));if(e.vendor==="Apple Computer, Inc."||(e.appCodeName||"")==="Mozilla")m.Adapter.bind(a,"hashchange",function(){m.Adapter.trigger(a,"popstate")}),m.getHash()&&m.Adapter.onDomLoad(function(){m.Adapter.trigger(a,"hashchange")})}},m.init()}(window)