SABIOinstaller - Version 1.0.0

Version Notes

First stable version

Download this release

Release Info

Developer Patryk Grudniewski
Extension SABIOinstaller
Version 1.0.0
Comparing to
See all releases


Version 1.0.0

Files changed (35) hide show
  1. app/code/community/SabioSystem/Installer/Block/Adminhtml/Extension.php +20 -0
  2. app/code/community/SabioSystem/Installer/Block/Adminhtml/Extension/Column/Renderer/Action.php +103 -0
  3. app/code/community/SabioSystem/Installer/Block/Adminhtml/Extension/Edit/Form.php +35 -0
  4. app/code/community/SabioSystem/Installer/Block/Adminhtml/Extension/Form.php +29 -0
  5. app/code/community/SabioSystem/Installer/Block/Adminhtml/Extension/Grid.php +85 -0
  6. app/code/community/SabioSystem/Installer/Helper/Data.php +4 -0
  7. app/code/community/SabioSystem/Installer/Model/Cron.php +7 -0
  8. app/code/community/SabioSystem/Installer/Model/Extension.php +39 -0
  9. app/code/community/SabioSystem/Installer/Model/Resource/Extension.php +171 -0
  10. app/code/community/SabioSystem/Installer/Model/Resource/Extension/Collection.php +23 -0
  11. app/code/community/SabioSystem/Installer/Model/Resource/Setup.php +4 -0
  12. app/code/community/SabioSystem/Installer/Model/XmlRpc.php +35 -0
  13. app/code/community/SabioSystem/Installer/controllers/Adminhtml/ExtensionController.php +117 -0
  14. app/code/community/SabioSystem/Installer/etc/adminhtml.xml +51 -0
  15. app/code/community/SabioSystem/Installer/etc/config.xml +96 -0
  16. app/code/community/SabioSystem/Installer/etc/system.xml +49 -0
  17. app/code/community/SabioSystem/Installer/sql/sabio_installer_setup/mysql4-install-1.0.0.php +49 -0
  18. app/code/community/SabioSystem/Utilities/Block/Adminhtml/System/Config/Color.php +8 -0
  19. app/code/community/SabioSystem/Utilities/Helper/Data.php +3 -0
  20. app/code/community/SabioSystem/Utilities/Model/Adminhtml/System/Config/Backend/Color.php +18 -0
  21. app/code/community/SabioSystem/Utilities/Model/Adminhtml/System/Config/Source/Style/Align/Horizontal.php +14 -0
  22. app/code/community/SabioSystem/Utilities/Model/Resource/Db/Abstract.php +21 -0
  23. app/code/community/SabioSystem/Utilities/etc/config.xml +33 -0
  24. app/code/community/SabioSystem/Utilities/etc/system.xml +8 -0
  25. app/design/adminhtml/default/default/layout/installer.xml +12 -0
  26. app/design/adminhtml/default/default/layout/sabio.xml +12 -0
  27. app/etc/modules/SabioSystem_Installer.xml +8 -0
  28. app/etc/modules/SabioSystem_Utilities.xml +8 -0
  29. js/sabiosystem/core/colorpicker/arrow.gif +0 -0
  30. js/sabiosystem/core/colorpicker/cross.gif +0 -0
  31. js/sabiosystem/core/colorpicker/hs.png +0 -0
  32. js/sabiosystem/core/colorpicker/hv.png +0 -0
  33. js/sabiosystem/core/colorpicker/jscolor.js +997 -0
  34. js/sabiosystem/core/validation/color.js +5 -0
  35. package.xml +24 -0
app/code/community/SabioSystem/Installer/Block/Adminhtml/Extension.php ADDED
@@ -0,0 +1,20 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ class SabioSystem_Installer_Block_Adminhtml_Extension extends Mage_Adminhtml_Block_Widget_Grid_Container{
3
+
4
+ protected $_blockGroup = 'sabio_installer';
5
+ protected $_controller = 'adminhtml_extension';
6
+
7
+ public function __construct(){
8
+ parent::__construct();
9
+ }
10
+
11
+ public function _construct(){
12
+ $this->_headerText = Mage::helper('sabio_installer')->__('SABIO extension');
13
+ parent::_construct();
14
+ }
15
+
16
+ public function getCreateUrl()
17
+ {
18
+ return $this->getUrl('*/*/form');
19
+ }
20
+ }
app/code/community/SabioSystem/Installer/Block/Adminhtml/Extension/Column/Renderer/Action.php ADDED
@@ -0,0 +1,103 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ class SabioSystem_Installer_Block_Adminhtml_Extension_Column_Renderer_Action extends Mage_Adminhtml_Block_Widget_Grid_Column_Renderer_Action{
3
+ public function _getValue(Varien_Object $row)
4
+ {
5
+
6
+ $format = ( $this->getColumn()->getFormat() ) ? $this->getColumn()->getFormat() : null;
7
+ $defaultValue = $this->getColumn()->getDefault();
8
+ if (is_null($format)) {
9
+ // If no format and it column not filtered specified return data as is.
10
+ $data = parent::_getValue($row);
11
+ $string = is_null($data) ? $defaultValue : $data;
12
+ return $this->escapeHtml($string);
13
+ }
14
+ elseif (preg_match_all($this->_variablePattern, $format, $matches)) {
15
+
16
+ // Parsing of format string
17
+ $formattedString = $format;
18
+ foreach ($matches[0] as $matchIndex=>$match) {
19
+ $value = $row->getData($matches[1][$matchIndex]);
20
+ $formattedString = str_replace($match, $value, $formattedString);
21
+ }
22
+ return $formattedString;
23
+ } else {
24
+ preg_match("/^http/", $format , $theSame );
25
+ if( !isset($theSame[0]) && $format != "Delete" && $format != "Uninstall" ){
26
+ $currentVersion = $row->getData('current_version');
27
+ $newsetVersion = $row->getData('newest_version');
28
+ if(!$currentVersion){
29
+ $format = "Install";
30
+ }
31
+ else if(version_compare($currentVersion, $newsetVersion , '<')){
32
+ $format = "Update";
33
+ }
34
+ else if(version_compare($currentVersion, $newsetVersion , '=')){
35
+ $format = "Check for updates";
36
+ }
37
+ }
38
+ return $this->escapeHtml($format);
39
+ }
40
+ }
41
+
42
+
43
+ public function render(Varien_Object $row)
44
+ {
45
+ $actions = $this->getColumn()->getActions();
46
+ if ( empty($actions) || !is_array($actions) ) {
47
+ return '&nbsp;';
48
+ }
49
+
50
+ if(sizeof($actions)==1 && !$this->getColumn()->getNoLink()) {
51
+ foreach ($actions as $action) {
52
+ if ( is_array($action) ) {
53
+ $currentVersion = $row->getData('current_version');
54
+ $newsetVersion = $row->getData('newest_version');
55
+ if($action['url']['base'] != "*/*/delete" && $action['url']['base'] != "*/*/uninstall"){
56
+ if(!$currentVersion){
57
+ $action['url']['base']="*/*/install";
58
+ }
59
+ else if(version_compare($currentVersion, $newsetVersion , '<')){
60
+ $action['url']['base']="*/*/update";
61
+ }
62
+ else if(version_compare($currentVersion, $newsetVersion , '=')){
63
+ $action['url']['base']="*/*/check";
64
+ }
65
+ }
66
+ if ($action['url']['base'] != "*/*/uninstall" && $install == 1){
67
+
68
+ }
69
+ return $this->_toLinkHtml($action, $row);
70
+ }
71
+ }
72
+ }
73
+
74
+ $i = 0;
75
+ foreach ($actions as $action){
76
+ $i++;
77
+ if ( is_array($action) ) {
78
+ $currentVersion = $row->getData('current_version');
79
+ $newsetVersion = $row->getData('newest_version');
80
+ if($action['url']['base'] != "*/*/delete" && $action['url']['base'] != "*/*/uninstall"){
81
+ if( !$currentVersion){
82
+ $action['url']['base']="*/*/install";
83
+ //return $this->_toLinkHtml($action, $row);
84
+ $install=1;
85
+ }
86
+ else if(version_compare($currentVersion, $newsetVersion , '<')){
87
+ $action['url']['base']="*/*/update";
88
+ }
89
+ else if(version_compare($currentVersion, $newsetVersion , '=')){
90
+ $action['url']['base']="*/*/check";
91
+ }
92
+ }
93
+ if ($action['url']['base'] == "*/*/uninstall" && $install == 1){
94
+ $install=0;
95
+ } else {
96
+ $out .= $this->_toLinkHtml($action, $row). "</br> ";
97
+ }
98
+ }
99
+ }
100
+ return $out;
101
+ }
102
+
103
+ }
app/code/community/SabioSystem/Installer/Block/Adminhtml/Extension/Edit/Form.php ADDED
@@ -0,0 +1,35 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ class SabioSystem_Installer_Block_Adminhtml_Extension_Edit_Form extends
4
+ Mage_Adminhtml_Block_Widget_Form
5
+ {
6
+ protected function _prepareForm()
7
+ {
8
+ $form = new Varien_Data_Form(array(
9
+ 'id' => 'edit_form',
10
+ 'action' => $this->getUrl('*/*/save', array('id' => $this->getRequest()->getParam('id'))),
11
+ 'method' => 'post',
12
+ )
13
+ );
14
+
15
+ $form->setUseContainer(true);
16
+ $this->setForm($form);
17
+ $fieldset = $form->addFieldset('extension_form',
18
+ array('legend'=>$this->__("Information")));
19
+ $fieldset->addField('key', 'text',
20
+ array(
21
+ 'label' => $this->__("Key"),
22
+ 'class' => 'required-entry',
23
+ 'required' => true,
24
+ 'name' => 'key',
25
+ ));
26
+
27
+
28
+ if ( Mage::registry('extension_data') )
29
+ {
30
+ $form->setValues(Mage::registry('extension_data')->getData());
31
+ }
32
+
33
+ return parent::_prepareForm();
34
+ }
35
+ }
app/code/community/SabioSystem/Installer/Block/Adminhtml/Extension/Form.php ADDED
@@ -0,0 +1,29 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ class SabioSystem_Installer_Block_Adminhtml_Extension_Form extends
4
+ Mage_Adminhtml_Block_Widget_Form_Container{
5
+ public function __construct()
6
+ {
7
+ $data = array(
8
+ 'label' => 'Back',
9
+ 'onclick' => 'setLocation(\'' . $this->getUrl('*/*/grid') . '\')',
10
+ 'class' => 'back'
11
+ );
12
+ $this->addButton ('my_back', $data, 100);
13
+ parent::__construct();
14
+ //$this->_objectId = 'id';
15
+ //vwe assign the same blockGroup as the Grid Container
16
+ $this->_blockGroup = 'sabio_installer';
17
+ //and the same controller
18
+ $this->_controller = 'adminhtml_extension';
19
+ //define the label for the save and delete button
20
+
21
+ $this->_updateButton('save', 'label','Save item');
22
+ $this->_updateButton('delete', 'label', 'Delete item');
23
+ $this->_headerText = Mage::helper('sabio_installer')->__('Sabio Edit Products');
24
+ $this->_removeButton('back');
25
+ }
26
+ /* Here, we're looking if we have transmitted a form object,
27
+ to update the good text in the header of the page (edit or add) */
28
+
29
+ }
app/code/community/SabioSystem/Installer/Block/Adminhtml/Extension/Grid.php ADDED
@@ -0,0 +1,85 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /*
4
+ * To change this license header, choose License Headers in Project Properties.
5
+ * To change this template file, choose Tools | Templates
6
+ * and open the template in the editor.
7
+ */
8
+
9
+ class SabioSystem_Installer_Block_Adminhtml_Extension_Grid extends Mage_Adminhtml_Block_Widget_Grid{
10
+ protected function _construct() {
11
+ parent::_construct();
12
+ //$this->setId('cservice_history_grid');
13
+ $this->setDefaultDir('ASC');
14
+ $this->setDefaultSort('id');
15
+ $this->setSaveParametersInSession(true);
16
+ $this->setUseAjax(true);
17
+ }
18
+
19
+ protected function _prepareCollection(){
20
+ $collection = Mage::getModel('sabio_installer/extension')->getCollection();
21
+ $this->setCollection($collection);
22
+ return parent::_prepareCollection();
23
+ }
24
+
25
+ protected function _prepareColumns(){
26
+ $helper = Mage::helper('sabio_installer');
27
+
28
+ $this->addColumn('name',array(
29
+ 'header' => $helper->__('Name'),
30
+ 'index' => 'name',
31
+ 'align' => 'left'
32
+ ))
33
+ ->addColumn('key',array(
34
+ 'header' => $helper->__('Key'),
35
+ 'index' => 'key'
36
+ ))
37
+ ->addColumn('current_version ',array(
38
+ 'header' => $helper->__('Current Version'),
39
+ 'index' => 'current_version'
40
+ ))
41
+ ->addColumn('newest_version',array(
42
+ 'header' => $helper->__('Newest Version'),
43
+ 'index' => 'newest_version'
44
+ ));
45
+
46
+ $this->addColumn('action',
47
+ array(
48
+ 'header' => $helper->__('Action'),
49
+ 'width' => '100px',
50
+ 'type' => 'action',
51
+ 'getter' => 'getId',
52
+ 'actions' => array(
53
+ array(
54
+ 'caption' => $helper->__('Edit'),
55
+ 'url' => array(
56
+ 'base' =>'*/*/edit',
57
+ 'params' =>array('store'=>$this->getRequest()->getParam('store'))
58
+ ),
59
+ 'field' => 'id'
60
+ ),
61
+ array(
62
+ 'caption' => $helper->__('Uninstall'),
63
+ 'url' => array(
64
+ 'base' =>'*/*/uninstall',
65
+ 'params' =>array('store'=>$this->getRequest()->getParam('store'))
66
+ ),
67
+ 'field' => 'id'
68
+ ),
69
+ array(
70
+ 'caption' => $helper->__('Delete'),
71
+ 'url' => array(
72
+ 'base' =>'*/*/delete',
73
+ 'params' =>array('store'=>$this->getRequest()->getParam('store'))
74
+ ),
75
+ 'field' => 'id'
76
+ )
77
+ ),
78
+ 'filter' => false,
79
+ 'renderer' => 'sabio_installer/adminhtml_extension_column_renderer_action',
80
+ 'sortable' => false,
81
+ 'index' => 'stores',
82
+ ));
83
+
84
+ }
85
+ }
app/code/community/SabioSystem/Installer/Helper/Data.php ADDED
@@ -0,0 +1,4 @@
 
 
 
 
1
+ <?php
2
+ class SabioSystem_Installer_Helper_Data extends Mage_Core_Helper_Data{
3
+ }
4
+ ?>
app/code/community/SabioSystem/Installer/Model/Cron.php ADDED
@@ -0,0 +1,7 @@
 
 
 
 
 
 
 
1
+ <?php
2
+ class SabioSystem_Installer_Model_Cron{
3
+ public function checkForUpdates(){
4
+ Mage::getResourceModel('sabio_installer/extension_collection')->checkForUpdates();
5
+ }
6
+ }
7
+ ?>
app/code/community/SabioSystem/Installer/Model/Extension.php ADDED
@@ -0,0 +1,39 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ class SabioSystem_Installer_Model_Extension extends Mage_Core_Model_Abstract{
3
+ const REPORT_PRIORITY_NOTICE = 4;
4
+ const REPORT_PRIORITY_MINOR = 3;
5
+ const REPORT_PRIORITY_MAJOR = 2;
6
+ const REPORT_PRIORITY_CRITICAL = 1;
7
+
8
+ protected function _construct(){
9
+ $this->_init('sabio_installer/extension');
10
+ return parent::_construct();
11
+ }
12
+
13
+ public function checkForUpdates(){
14
+ $this->getResource()->checkForUpdates($this);
15
+ return $this;
16
+ }
17
+
18
+ public function update(){
19
+ $this->getResource()->update($this);
20
+ return $this;
21
+ }
22
+
23
+ public function install(){
24
+ $this->getResource()->install($this);
25
+ }
26
+
27
+ public function uninstall(){
28
+ $this->getResource()->uninstall($this);
29
+ }
30
+
31
+ public function report($priority,$message){
32
+ $this->getResource()->report($this,$priority,$message);
33
+ }
34
+
35
+ public function loadByKey($key){
36
+ return $this->load($key,'key');
37
+ }
38
+ }
39
+ ?>
app/code/community/SabioSystem/Installer/Model/Resource/Extension.php ADDED
@@ -0,0 +1,171 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ class SabioSystem_Installer_Model_Resource_Extension extends Mage_Core_Model_Resource_Db_Abstract{
3
+ const TMP_DIR = '/ext_manager';
4
+
5
+ protected $_extensionMap=array();
6
+
7
+ protected function _construct(){
8
+ $this->_init('sabio_installer/extension','id');
9
+ $this->_serializableFields['map'] = array(null,array());
10
+ }
11
+ protected function _addExtension($object){
12
+ $xmlRpc = Mage::getSingleton('sabio_installer/xmlRpc');
13
+ $object->setName($xmlRpc->getName($object->getKey()));
14
+ $object->setNewestVersion($xmlRpc->getVersion($object->getKey()));
15
+
16
+ return $this;
17
+ }
18
+ protected function _merge($parent=null,$target=null){
19
+ $dir = opendir($parent);
20
+ while($name = readdir($dir)){
21
+ if ($name == '..' || $name == '.'){
22
+ continue;
23
+ }
24
+ $entry = $parent.$name;
25
+ $entry_target = $target.$name;
26
+ if ($_isDir=is_dir($entry)){
27
+ $entry = $entry.'/';
28
+ $entry_target = $entry_target.'/';
29
+ }
30
+
31
+ if($_isDir){
32
+ if(!is_dir($entry_target)){
33
+ mkdir($entry_target);
34
+ }
35
+ }else{
36
+ if(is_file($entry_target)){
37
+ unlink($entry_target);
38
+ }
39
+ rename($entry,$entry_target);
40
+ }
41
+ $this->_extensionMap[] = $entry_target;
42
+
43
+ if ($_isDir){
44
+ $this->_merge($entry,$entry_target);
45
+ rmdir($entry);
46
+ }
47
+
48
+ }
49
+
50
+ rmdir(Mage::getBaseUrl().self::TMP_DIR);
51
+
52
+ return $this;
53
+ }
54
+ protected function _unpack($archive){
55
+ $dir = Mage::getBaseDir().'/tmp.tgz';
56
+
57
+ $f = fopen($dir,'w');
58
+ fwrite($f,$archive);
59
+ fclose($f);
60
+ $p = new PharData($dir);
61
+ $p->decompress();
62
+ unlink($dir);
63
+ $dir = Mage::getBaseDir().'/tmp.tar';
64
+ $p = new PharData($dir);
65
+ $p->extractTo(Mage::getBaseDir().self::TMP_DIR);
66
+ unlink($dir);
67
+
68
+ $this->_extensionMap = array();
69
+
70
+ return $this;
71
+ }
72
+ protected function _beforeSave($object){
73
+ if(!$object->getId()){
74
+ $this->_addExtension($object);
75
+ }
76
+ if($object->getMap()){
77
+ $object->setMap(serialize($object->getMap()));
78
+ }
79
+ return parent::_beforeSave();
80
+ }
81
+ protected function _beforeDelete($object){
82
+ if($object->getCurrentVersion()){
83
+ $this->uninstall($object);
84
+ }
85
+ return parent::_beforeDelete();
86
+ }
87
+
88
+ public function excludeUsedFromMap($object){
89
+ $map = unserialize($object->getMap());
90
+ foreach ($map as $path){
91
+ if(($key=array_search($path,$this->_extensionMap)) !== false){
92
+ unset($this->_extensionMap[$key]);
93
+ }
94
+ }
95
+
96
+ return $this;
97
+ }
98
+
99
+ public function install($object){
100
+ $xmlRpc = Mage::getSingleton('sabio_installer/xmlRpc');
101
+ $object->setNewestVersion($xmlRpc->getVersion($object->getKey()));
102
+
103
+ $this->_unpack(base64_decode($xmlRpc->install($object->getKey(),Mage::getBaseUrl())))
104
+ ->_merge(Mage::getBaseDir().self::TMP_DIR.'/',Mage::getBaseDir().'/');
105
+
106
+ $object->setCurrentVersion($object->getNewestVersion());
107
+ $object->setMap($this->_extensionMap);
108
+ $object->save();
109
+
110
+ return $this;
111
+ }
112
+
113
+ public function update($object){
114
+ $this->checkForUpdates($object);
115
+ if(version_compare($object->getNewestVersion(),$object->getCurrentVersion(),'>')){
116
+ $xmlRpc = Mage::getSingleton('sabio_installer/xmlRpc');
117
+ $this->_unpack(base64_decode($xmlRpc->update($object->getKey(),Mage::getBaseUrl())))
118
+ ->_merge(Mage::getBaseDir().self::TMP_DIR.'/',Mage::getBaseDir().'/');
119
+
120
+ $object->setCurrentVersion($object->getNewestVersion());
121
+ $object->setMap($this->_extensionMap);
122
+ $object->save();
123
+ }
124
+
125
+ return $this;
126
+ }
127
+
128
+ public function checkForUpdates($object){
129
+ $xmlRpc = Mage::getSingleton('sabio_installer/xmlRpc');
130
+
131
+ $newest = $xmlRpc->checkForUpdates($object->getKey(),Mage::getBaseUrl());
132
+ if(version_compare($newest,$object->getNewestVersion(),'>')){
133
+ $object->setNewestVersion($newest);
134
+ $object->save();
135
+ }
136
+
137
+ return $this;
138
+ }
139
+
140
+ public function uninstall($object){
141
+ if(true || $object->getCurrentVersion()){
142
+ $xmlRpc = Mage::getSingleton('sabio_installer/xmlRpc');
143
+ $xmlRpc->uninstall($object->getKey(),Mage::getBaseUrl());
144
+
145
+ $this->_extensionMap = $object->getMap();
146
+
147
+ Mage::getResourceModel($this->_resourceModel.'/'.$this->_mainTable.'_collection')
148
+ ->addFieldToFilter('id',array('neq'=>$object->getId()))
149
+ ->walk(array($this,'excludeUsedFromMap'));
150
+
151
+ foreach($this->_extensionMap as $path){
152
+ if(is_file($path)){
153
+ unlink($path);
154
+ }
155
+ }
156
+
157
+ $object->setMap(null);
158
+ $object->setCurrentVersion(null);
159
+ $object->save();
160
+ }
161
+ return $this;
162
+ }
163
+
164
+ public function report($object,$priority,$message){
165
+ $xmlRpc = Mage::getSingleton('sabio_installer/xmlRpc');
166
+ $xmlRpc->reportError($object->getKey(),Mage::getBaseUrl(),$priority,$message);
167
+
168
+ return $this;
169
+ }
170
+ }
171
+ ?>
app/code/community/SabioSystem/Installer/Model/Resource/Extension/Collection.php ADDED
@@ -0,0 +1,23 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ class SabioSystem_Installer_Model_Resource_Extension_Collection extends Mage_Core_Model_Resource_Db_Collection_Abstract{
3
+ protected function _construct(){
4
+ $this->_init('sabio_installer/extension');
5
+ parent::_construct();
6
+ }
7
+
8
+ public function update(){
9
+ $this->walk('update');
10
+ return $this;
11
+ }
12
+
13
+ public function checkForUpdates(){
14
+ $this->walk('checkForUpdates');
15
+ return $this;
16
+ }
17
+
18
+ public function loadUpgradeable(){
19
+ $this->getSelect()->where('`main_table`.`current_version` <> `main_table`.`newest_version`');
20
+ return $this;
21
+ }
22
+ }
23
+ ?>
app/code/community/SabioSystem/Installer/Model/Resource/Setup.php ADDED
@@ -0,0 +1,4 @@
 
 
 
 
1
+ <?php
2
+ class SabioSystem_Installer_Model_Resource_Setup extends Mage_Core_Model_Resource_Setup{
3
+ }
4
+ ?>
app/code/community/SabioSystem/Installer/Model/XmlRpc.php ADDED
@@ -0,0 +1,35 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ class SabioSystem_Installer_Model_XmlRpc{
3
+ const API_CONTROLLER = 'ext_manager';
4
+
5
+ protected $_client;
6
+ protected $_session;
7
+
8
+ protected function _underscore($cameled){
9
+ return implode('_',array_map('strtolower',preg_split('/([A-Z]{1}[^A-Z]*)/',$cameled,-1,PREG_SPLIT_DELIM_CAPTURE|PREG_SPLIT_NO_EMPTY)));
10
+ }
11
+
12
+ public function __construct(){
13
+ try{
14
+ $this->_client = new Zend_XmlRpc_Client(Mage::getStoreConfig('sabio_installer/api_config/url'));
15
+ $this->_session = $this->_client->call('login',array(Mage::getStoreConfig('sabio_installer/api_config/login'),Mage::getStoreConfig('sabio_installer/api_config/password')));
16
+ }catch(Zend_XmlRpc_Client_HttpException $e){
17
+ Mage::throwException(Mage::helper('sabio_installer')->__('Wrong API URL. Please check SABIOinstaller\'s configuration'));
18
+ }catch(Zend_XmlRpc_Client_FaultException $e){
19
+ Mage::throwException(Mage::helper('sabio_installer')->__('Access to API denied. Please check SABIOinstaller\'s configuration'));
20
+ }
21
+ }
22
+
23
+ public function __call($name, $args){
24
+ try{
25
+ return $this->_client->call('call',array(
26
+ $this->_session,
27
+ self::API_CONTROLLER.'.'.$this->_underscore($name),
28
+ $args
29
+ ));
30
+ }catch(Zend_XmlRpc_Client_FaultException $e){
31
+ Mage::throwException(Mage::helper('sabio_installer')->__($e->getMessage()));
32
+ }
33
+ }
34
+ }
35
+ ?>
app/code/community/SabioSystem/Installer/controllers/Adminhtml/ExtensionController.php ADDED
@@ -0,0 +1,117 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ class SabioSystem_Installer_Adminhtml_ExtensionController extends Mage_Adminhtml_Controller_Action{
3
+
4
+ public function gridAction()
5
+ {
6
+
7
+ $this->loadLayout();
8
+ $this->_title($this->__('Extensions list'))->_title($this->__('SABIOinstaller'));
9
+ $this->_setActiveMenu('sabio/instaler');
10
+ $this->renderLayout();
11
+ }
12
+
13
+ public function updateAction()
14
+ {
15
+ $id = $this->getRequest()->getParam('id');
16
+ Mage::getModel('sabio_installer/extension')->load($id)->update();
17
+
18
+ $this->_getSession()->addSuccess($this->__('Extension id %s updated successfully',$id));
19
+
20
+ $this->_redirect('*/*/grid');
21
+ return;
22
+ }
23
+
24
+ public function checkAction()
25
+ {
26
+ $id = $this->getRequest()->getParam('id');
27
+ Mage::getModel('sabio_installer/extension')->load($id)->checkForUpdates();
28
+
29
+ $this->_redirect('*/*/grid');
30
+ return;
31
+ }
32
+ public function installAction()
33
+ {
34
+ $id = $this->getRequest()->getParam('id');
35
+ Mage::getModel('sabio_installer/extension')->load($id)->install();
36
+
37
+ $this->_getSession()->addSuccess($this->__('Extension id %s installed successfully',$id));
38
+
39
+ $this->_redirect('*/*/grid');
40
+ return;
41
+ }
42
+ public function deleteAction()
43
+ {
44
+ $id = $this->getRequest()->getParam('id');
45
+ Mage::getModel('sabio_installer/extension')->load($id)->delete();
46
+
47
+ $this->_getSession()->addSuccess($this->__('Extension id %s deleted successfully',$id));
48
+
49
+ $this->_redirect('*/*/grid');
50
+ return;
51
+ }
52
+ public function uninstallAction(){
53
+ $id = $this->getRequest()->getParam('id');
54
+ Mage::getModel('sabio_installer/extension')->load($id)->uninstall();
55
+
56
+ $this->_getSession()->addSuccess($this->__('Extension id %s uninstalled successfully',$id));
57
+
58
+ $this->_redirect('*/*/grid');
59
+ return;
60
+ }
61
+
62
+ public function formAction(){
63
+ $testId = $this->getRequest()->getParam('id');
64
+ $testModel = Mage::getModel('sabio_installer/extension')->load($testId);
65
+ if ($testModel->getId() || $testId == 0)
66
+ {
67
+
68
+ Mage::register('extension_data', $testModel);
69
+ $this->loadLayout();
70
+ $this->_setActiveMenu('sabio/instaler');
71
+ $this->renderLayout();
72
+ }
73
+ else
74
+ {
75
+ Mage::getSingleton('adminhtml/session')
76
+ ->addError('Test does not exist');
77
+ $this->_redirect('*/*/grid');
78
+ }
79
+ }
80
+
81
+ public function saveAction()
82
+ {
83
+ if ($this->getRequest()->getPost())
84
+ {
85
+ try {
86
+ $postData = $this->getRequest()->getPost();
87
+ $testModel = Mage::getModel('sabio_installer/extension');
88
+ $testModel
89
+ ->addData($postData)
90
+ ->save();
91
+ Mage::getSingleton('adminhtml/session')
92
+ ->addSuccess('successfully saved');
93
+ Mage::getSingleton('adminhtml/session')
94
+ ->settestData(false);
95
+ $this->_redirect('*/*/grid');
96
+ return;
97
+ } catch (Exception $e){
98
+ Mage::getSingleton('adminhtml/session')
99
+ ->addError($e->getMessage());
100
+ Mage::getSingleton('adminhtml/session')
101
+ ->settestData($this->getRequest()
102
+ ->getPost()
103
+ );
104
+ $this->_redirect('*/*/form',
105
+ array('id' => $this->getRequest()
106
+ ->getParam('id')));
107
+ return;
108
+ }
109
+ }
110
+ $this->_redirect('*/*/grid');
111
+ }
112
+
113
+ public function newAction()
114
+ {
115
+ $this->_forward('edit');
116
+ }
117
+ }
app/code/community/SabioSystem/Installer/etc/adminhtml.xml ADDED
@@ -0,0 +1,51 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <config>
2
+ <acl>
3
+ <resources>
4
+ <admin>
5
+ <children>
6
+ <system>
7
+ <children>
8
+ <config>
9
+ <children>
10
+ <sabio_installer title="title">
11
+ <title>SABIOsystem Installer</title>
12
+ <sort_order>100</sort_order>
13
+ </sabio_installer>
14
+ </children>
15
+ </config>
16
+ </children>
17
+ </system>
18
+ </children>
19
+ </admin>
20
+ </resources>
21
+ </acl>
22
+ <menu>
23
+ <sabio>
24
+ <title>SABIOsystem</title>
25
+ <sort_order>90</sort_order>
26
+ <children>
27
+ <installer translate="title" module="sabio_installer">
28
+ <title>Installer</title>
29
+ <sort_order>0</sort_order>
30
+ <children>
31
+ <grid translate="title" module="sabio_installer">
32
+ <title>Extensions list</title>
33
+ <sort_order>100</sort_order>
34
+ <action>sabio_installer/extension/grid</action>
35
+ </grid>
36
+ <form translate="title" module="sabio_installer">
37
+ <title>Add new extension</title>
38
+ <sort_order>200</sort_order>
39
+ <action>sabio_installer/extension/form</action>
40
+ </form>
41
+ <config translate="title" module="sabio_installer">
42
+ <title>Configuration</title>
43
+ <sort_order>300</sort_order>
44
+ <action>adminhtml/system_config/edit/section/sabio_installer</action>
45
+ </config>
46
+ </children>
47
+ </installer>
48
+ </children>
49
+ </sabio>
50
+ </menu>
51
+ </config>
app/code/community/SabioSystem/Installer/etc/config.xml ADDED
@@ -0,0 +1,96 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <config>
2
+ <modules>
3
+ <SabioSystem_Installer>
4
+ <version>1.0.0</version>
5
+ </SabioSystem_Installer>
6
+ </modules>
7
+ <global>
8
+ <models>
9
+ <sabio_installer>
10
+ <class>SabioSystem_Installer_Model</class>
11
+ <resourceModel>sabio_installer_resource</resourceModel>
12
+ </sabio_installer>
13
+ <sabio_installer_resource>
14
+ <class>SabioSystem_Installer_Model_Resource</class>
15
+ <entities>
16
+ <extension>
17
+ <table>sabio_installer_extension</table>
18
+ </extension>
19
+ </entities>
20
+ </sabio_installer_resource>
21
+ </models>
22
+ <blocks>
23
+ <sabio_installer>
24
+ <class>SabioSystem_Installer_Block</class>
25
+ </sabio_installer>
26
+ </blocks>
27
+ <resources>
28
+ <sabio_installer_write>
29
+ <connection>
30
+ <use>core_write</use>
31
+ </connection>
32
+ </sabio_installer_write>
33
+ <sabio_installer_read>
34
+ <connection>
35
+ <use>core_read</use>
36
+ </connection>
37
+ </sabio_installer_read>
38
+ <sabio_installer_setup>
39
+ <setup>
40
+ <module>SabioSystem_Installer</module>
41
+ <class>SabioSystem_Installer_Model_Resource_Setup</class>
42
+ </setup>
43
+ <connection>
44
+ <use>core_setup</use>
45
+ </connection>
46
+ </sabio_installer_setup>
47
+ </resources>
48
+ <helpers>
49
+ <sabio_installer>
50
+ <class>SabioSystem_Installer_Helper</class>
51
+ </sabio_installer>
52
+ </helpers>
53
+ </global>
54
+ <crontab>
55
+ <jobs>
56
+ <sabio_installer>
57
+ <schedule>
58
+ <cron_expr>0 1 * * 0</cron_expr>
59
+ </schedule>
60
+ <run>
61
+ <model>sabio_installer/cron::checkForUpdates</model>
62
+ </run>
63
+ </sabio_installer>
64
+ </jobs>
65
+ </crontab>
66
+ <default>
67
+ <sabio_installer>
68
+ <api_config>
69
+ <url>http://www.sabioshop.com/api/xmlrpc/</url>
70
+ <login>ext_manager</login>
71
+ <password>V5ACXHR5NdeQ7BU</password>
72
+ </api_config>
73
+ </sabio_installer>
74
+ </default>
75
+
76
+ <admin>
77
+ <routers>
78
+ <sabio_installer>
79
+ <use>admin</use>
80
+ <args>
81
+ <module>SabioSystem_Installer_Adminhtml</module>
82
+ <frontName>sabio_installer</frontName>
83
+ </args>
84
+ </sabio_installer>
85
+ </routers>
86
+ </admin>
87
+ <adminhtml>
88
+ <layout>
89
+ <updates>
90
+ <sabio_installer>
91
+ <file>installer.xml</file>
92
+ </sabio_installer>
93
+ </updates>
94
+ </layout>
95
+ </adminhtml>
96
+ </config>
app/code/community/SabioSystem/Installer/etc/system.xml ADDED
@@ -0,0 +1,49 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <config>
2
+ <sections>
3
+ <sabio_installer translate="label" module="sabio_installer">
4
+ <label>Installer</label>
5
+ <tab>sabio</tab>
6
+ <frontend_type>text</frontend_type>
7
+ <sort_order>100</sort_order>
8
+ <show_in_default>1</show_in_default>
9
+ <show_in_website>0</show_in_website>
10
+ <show_in_store>0</show_in_store>
11
+ <groups>
12
+ <api_config translate="label" module="sabio_installer">
13
+ <label>API Configuration</label>
14
+ <frontend_type>text</frontend_type>
15
+ <sort_order>120</sort_order>
16
+ <show_in_default>1</show_in_default>
17
+ <show_in_website>0</show_in_website>
18
+ <show_in_store>0</show_in_store>
19
+ <fields>
20
+ <url translate="label" module="sabio_installer">
21
+ <label>URL</label>
22
+ <frontend_type>text</frontend_type>
23
+ <sort_order>100</sort_order>
24
+ <show_in_default>1</show_in_default>
25
+ <show_in_website>0</show_in_website>
26
+ <show_in_store>0</show_in_store>
27
+ </url>
28
+ <login translate="label" module="sabio_installer">
29
+ <label>Login</label>
30
+ <frontend_type>text</frontend_type>
31
+ <sort_order>200</sort_order>
32
+ <show_in_default>1</show_in_default>
33
+ <show_in_website>0</show_in_website>
34
+ <show_in_store>0</show_in_store>
35
+ </login>
36
+ <password translate="label" module="sabio_installer">
37
+ <label>Password</label>
38
+ <frontend_type>password</frontend_type>
39
+ <sort_order>300</sort_order>
40
+ <show_in_default>1</show_in_default>
41
+ <show_in_website>0</show_in_website>
42
+ <show_in_store>0</show_in_store>
43
+ </password>
44
+ </fields>
45
+ </api_config>
46
+ </groups>
47
+ </sabio_installer>
48
+ </sections>
49
+ </config>
app/code/community/SabioSystem/Installer/sql/sabio_installer_setup/mysql4-install-1.0.0.php ADDED
@@ -0,0 +1,49 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ $installer = $this;
3
+ $connection = $installer->getConnection();
4
+
5
+ $_table = $installer->getTable('sabio_installer/extension');
6
+
7
+ if(!$connection->isTableExists($_table)){
8
+ $table = $connection->newTable($_table)
9
+ ->addColumn('id',Varien_Db_Ddl_Table::TYPE_INTEGER,10,array(
10
+ 'identity' => true,
11
+ 'unsigned' => true,
12
+ 'nullable' => false,
13
+ 'primary' => true
14
+ ),'ID')
15
+
16
+ ->addColumn('name',Varien_Db_Ddl_Table::TYPE_VARCHAR,255,array(
17
+ 'nullable' => false
18
+ ),'Name')
19
+
20
+ ->addColumn('key',Varien_Db_Ddl_Table::TYPE_CHAR,40,array(
21
+ 'nullable' => false
22
+ ),'Key')
23
+ ->addIndex('IDX_KEY',array(
24
+ array(
25
+ 'name' => 'key',
26
+ 'size' => 40
27
+ )),array(
28
+ 'type' => Varien_db_Adapter_Interface::INDEX_TYPE_UNIQUE
29
+ ))
30
+
31
+ ->addColumn('current_version',Varien_Db_Ddl_Table::TYPE_VARCHAR,15,array(
32
+ 'nullable' => true,
33
+ 'default' => null
34
+ ),'Current Version')
35
+
36
+ ->addColumn('newest_version',Varien_Db_Ddl_Table::TYPE_VARCHAR,15,array(
37
+ 'nullable' => true,
38
+ 'default' => null
39
+ ),'Newest Version')
40
+
41
+ ->addColumn('map',Varien_Db_Ddl_Table::TYPE_TEXT,null,array(
42
+ 'nullable' => true,
43
+ 'default' => null
44
+ ),'Extension Map');
45
+ $connection->createTable($table);
46
+ }
47
+
48
+ $installer->endSetup();
49
+ ?>
app/code/community/SabioSystem/Utilities/Block/Adminhtml/System/Config/Color.php ADDED
@@ -0,0 +1,8 @@
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ class SabioSystem_Utilities_Block_Adminhtml_System_Config_Color extends Mage_Adminhtml_Block_System_Config_Form_Field{
4
+ protected function _getElementHtml(Varien_Data_Form_Element_Abstract $element)
5
+ {
6
+ return $element->addClass('colorpicker')->getElementHtml();
7
+ }
8
+ }
app/code/community/SabioSystem/Utilities/Helper/Data.php ADDED
@@ -0,0 +1,3 @@
 
 
 
1
+ <?php
2
+ class SabioSystem_Utilities_Helper_Data extends Mage_Core_Helper_Data{
3
+ }
app/code/community/SabioSystem/Utilities/Model/Adminhtml/System/Config/Backend/Color.php ADDED
@@ -0,0 +1,18 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ class SabioSystem_Utilities_Model_Adminhtml_System_Config_Backend_Color extends Mage_Core_Model_Config_Data{
4
+
5
+ public function _beforeSave() {
6
+
7
+ $color = $this->getValue(); //get colour value from config
8
+ $match = preg_match('/[0-9A-F]+$/i', $color);
9
+
10
+ if((strlen($color) == 3 || strlen($color) == 6) && $match){
11
+ parent::_beforeSave();
12
+ }
13
+ else{
14
+ Mage::throwException(Mage::helper('sabio_util')->__('Color number contains from 4 or 7 chars. Should strt from "#", and then digits from 0 to 9 and letters from a to f. '));
15
+ }
16
+
17
+ }
18
+ }
app/code/community/SabioSystem/Utilities/Model/Adminhtml/System/Config/Source/Style/Align/Horizontal.php ADDED
@@ -0,0 +1,14 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ class SabioSystem_Utilities_Model_Adminhtml_System_Config_Source_Style_Align_Horizontal {
4
+ public function toOptionArray(){
5
+ return array(
6
+ array('value'=> 'left' , 'label'=>Mage::helper('sabio_util')->__('Left')),
7
+ array('value'=> 'right' , 'label'=>Mage::helper('sabio_util')->__('Right')),
8
+ array('value'=> 'center' , 'label'=>Mage::helper('sabio_util')->__('Center')),
9
+ array('value'=> 'justyfy', 'label'=>Mage::helper('sabio_util')->__('Justify'))
10
+ );
11
+ }
12
+ }
13
+
14
+ ?>
app/code/community/SabioSystem/Utilities/Model/Resource/Db/Abstract.php ADDED
@@ -0,0 +1,21 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ abstract class SabioSystem_Utilities_Model_Resource_Db_Abstract extends Mage_Core_Model_Resource_Db_Abstract{
3
+ protected function _getLoadSelect($field,$value,$object){
4
+ if (!is_array($field)){
5
+ $field = array($field);
6
+ }
7
+ if (!is_array($value)){
8
+ $value = array($field[0]=>$value);
9
+ }
10
+ if (count($value) != count($field)){
11
+ Mage::throwException('Field and value arrays have different length');
12
+ }
13
+ $select = $this->_getReadAdapter()->select()
14
+ ->from($this->getMainTable());
15
+ foreach($field as $k=>$f){
16
+ $quote = $this->_getReadAdapter()->quoteIdentifier(sprintf('%s.%s', $this->getMainTable(), $f));
17
+ $select->where($quote.'=?',$value[$f]);
18
+ }
19
+ return $select;
20
+ }
21
+ }
app/code/community/SabioSystem/Utilities/etc/config.xml ADDED
@@ -0,0 +1,33 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <config>
2
+ <modules>
3
+ <SabioSystem_Utilities>
4
+ <version>1.0.0</version>
5
+ </SabioSystem_Utilities>
6
+ </modules>
7
+ <global>
8
+ <helpers>
9
+ <sabio_util>
10
+ <class>SabioSystem_Utilities_Helper</class>
11
+ </sabio_util>
12
+ </helpers>
13
+ <blocks>
14
+ <sabio_util>
15
+ <class>SabioSystem_Utilities_Block</class>
16
+ </sabio_util>
17
+ </blocks>
18
+ <models>
19
+ <sabio_util>
20
+ <class>SabioSystem_Utilities_Model</class>
21
+ </sabio_util>
22
+ </models>
23
+ </global>
24
+ <adminhtml>
25
+ <layout>
26
+ <updates>
27
+ <sabio_util>
28
+ <file>sabio_util.xml</file>
29
+ </sabio_util>
30
+ </updates>
31
+ </layout>
32
+ </adminhtml>
33
+ </config>
app/code/community/SabioSystem/Utilities/etc/system.xml ADDED
@@ -0,0 +1,8 @@
 
 
 
 
 
 
 
 
1
+ <config>
2
+ <tabs>
3
+ <sabio module="sabio_util">
4
+ <label>SabioSystem</label>
5
+ <sort_order>100</sort_order>
6
+ </sabio>
7
+ </tabs>
8
+ </config>
app/design/adminhtml/default/default/layout/installer.xml ADDED
@@ -0,0 +1,12 @@
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <layout>
2
+ <sabio_installer_extension_grid>
3
+ <reference name="content">
4
+ <block type="sabio_installer/adminhtml_extension" name="grid_container"/>
5
+ </reference>
6
+ </sabio_installer_extension_grid>
7
+ <sabio_installer_extension_form>
8
+ <reference name="content">
9
+ <block type="sabio_installer/adminhtml_extension_form" name="form_container"/>
10
+ </reference>
11
+ </sabio_installer_extension_form>
12
+ </layout>
app/design/adminhtml/default/default/layout/sabio.xml ADDED
@@ -0,0 +1,12 @@
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <layout>
2
+ <adminhtml_system_config_edit>
3
+ <reference name="head">
4
+ <action method="addJs">
5
+ <script>sabiosystem/core/validation/color.js</script>
6
+ </action>
7
+ <action method="addJs">
8
+ <script>sabiosystem/core/colorpicker/jscolor.js</script>
9
+ </action>
10
+ </reference>
11
+ </adminhtml_system_config_edit>
12
+ </layout>
app/etc/modules/SabioSystem_Installer.xml ADDED
@@ -0,0 +1,8 @@
 
 
 
 
 
 
 
 
1
+ <config>
2
+ <modules>
3
+ <SabioSystem_Installer>
4
+ <active>true</active>
5
+ <codePool>community</codePool>
6
+ </SabioSystem_Installer>
7
+ </modules>
8
+ </config>
app/etc/modules/SabioSystem_Utilities.xml ADDED
@@ -0,0 +1,8 @@
 
 
 
 
 
 
 
 
1
+ <config>
2
+ <modules>
3
+ <SabioSystem_Utilities>
4
+ <active>true</active>
5
+ <codePool>community</codePool>
6
+ </SabioSystem_Utilities>
7
+ </modules>
8
+ </config>
js/sabiosystem/core/colorpicker/arrow.gif ADDED
Binary file
js/sabiosystem/core/colorpicker/cross.gif ADDED
Binary file
js/sabiosystem/core/colorpicker/hs.png ADDED
Binary file
js/sabiosystem/core/colorpicker/hv.png ADDED
Binary file
js/sabiosystem/core/colorpicker/jscolor.js ADDED
@@ -0,0 +1,997 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ /**
2
+ * jscolor, JavaScript Color Picker
3
+ *
4
+ * @version 1.4.3
5
+ * @license GNU Lesser General Public License, http://www.gnu.org/copyleft/lesser.html
6
+ * @author Jan Odvarko, http://odvarko.cz
7
+ * @created 2008-06-15
8
+ * @updated 2014-07-16
9
+ * @link http://jscolor.com
10
+ */
11
+
12
+
13
+ var jscolor = {
14
+
15
+
16
+ dir : '', // location of jscolor directory (leave empty to autodetect)
17
+ bindClass : 'colorpicker', // class name
18
+ binding : true, // automatic binding via <input class="...">
19
+ preloading : true, // use image preloading?
20
+
21
+
22
+ install : function() {
23
+ jscolor.addEvent(window, 'load', jscolor.init);
24
+ },
25
+
26
+
27
+ init : function() {
28
+ if(jscolor.binding) {
29
+ jscolor.bind();
30
+ }
31
+ if(jscolor.preloading) {
32
+ jscolor.preload();
33
+ }
34
+ },
35
+
36
+
37
+ getDir : function() {
38
+ if(!jscolor.dir) {
39
+ var detected = jscolor.detectDir();
40
+ jscolor.dir = detected!==false ? detected : 'jscolor/';
41
+ }
42
+ return jscolor.dir;
43
+ },
44
+
45
+
46
+ detectDir : function() {
47
+ var base = location.href;
48
+
49
+ var e = document.getElementsByTagName('base');
50
+ for(var i=0; i<e.length; i+=1) {
51
+ if(e[i].href) { base = e[i].href; }
52
+ }
53
+
54
+ var e = document.getElementsByTagName('script');
55
+ for(var i=0; i<e.length; i+=1) {
56
+ if(e[i].src && /(^|\/)jscolor\.js([?#].*)?$/i.test(e[i].src)) {
57
+ var src = new jscolor.URI(e[i].src);
58
+ var srcAbs = src.toAbsolute(base);
59
+ srcAbs.path = srcAbs.path.replace(/[^\/]+$/, ''); // remove filename
60
+ srcAbs.query = null;
61
+ srcAbs.fragment = null;
62
+ return srcAbs.toString();
63
+ }
64
+ }
65
+ return false;
66
+ },
67
+
68
+
69
+ bind : function() {
70
+ var matchClass = new RegExp('(^|\\s)('+jscolor.bindClass+')(\\s*(\\{[^}]*\\})|\\s|$)', 'i');
71
+ var e = document.getElementsByTagName('input');
72
+ for(var i=0; i<e.length; i+=1) {
73
+ var m;
74
+ if(!e[i].color && e[i].className && (m = e[i].className.match(matchClass))) {
75
+ var prop = {};
76
+ if(m[4]) {
77
+ try {
78
+ prop = (new Function ('return (' + m[4] + ')'))();
79
+ } catch(eInvalidProp) {}
80
+ }
81
+ e[i].color = new jscolor.color(e[i], prop);
82
+ }
83
+ }
84
+ },
85
+
86
+
87
+ preload : function() {
88
+ for(var fn in jscolor.imgRequire) {
89
+ if(jscolor.imgRequire.hasOwnProperty(fn)) {
90
+ jscolor.loadImage(fn);
91
+ }
92
+ }
93
+ },
94
+
95
+
96
+ images : {
97
+ pad : [ 181, 101 ],
98
+ sld : [ 16, 101 ],
99
+ cross : [ 15, 15 ],
100
+ arrow : [ 7, 11 ]
101
+ },
102
+
103
+
104
+ imgRequire : {},
105
+ imgLoaded : {},
106
+
107
+
108
+ requireImage : function(filename) {
109
+ jscolor.imgRequire[filename] = true;
110
+ },
111
+
112
+
113
+ loadImage : function(filename) {
114
+ if(!jscolor.imgLoaded[filename]) {
115
+ jscolor.imgLoaded[filename] = new Image();
116
+ jscolor.imgLoaded[filename].src = jscolor.getDir()+filename;
117
+ }
118
+ },
119
+
120
+
121
+ fetchElement : function(mixed) {
122
+ return typeof mixed === 'string' ? document.getElementById(mixed) : mixed;
123
+ },
124
+
125
+
126
+ addEvent : function(el, evnt, func) {
127
+ if(el.addEventListener) {
128
+ el.addEventListener(evnt, func, false);
129
+ } else if(el.attachEvent) {
130
+ el.attachEvent('on'+evnt, func);
131
+ }
132
+ },
133
+
134
+
135
+ fireEvent : function(el, evnt) {
136
+ if(!el) {
137
+ return;
138
+ }
139
+ if(document.createEvent) {
140
+ var ev = document.createEvent('HTMLEvents');
141
+ ev.initEvent(evnt, true, true);
142
+ el.dispatchEvent(ev);
143
+ } else if(document.createEventObject) {
144
+ var ev = document.createEventObject();
145
+ el.fireEvent('on'+evnt, ev);
146
+ } else if(el['on'+evnt]) { // alternatively use the traditional event model (IE5)
147
+ el['on'+evnt]();
148
+ }
149
+ },
150
+
151
+
152
+ getElementPos : function(e) {
153
+ var e1=e, e2=e;
154
+ var x=0, y=0;
155
+ if(e1.offsetParent) {
156
+ do {
157
+ x += e1.offsetLeft;
158
+ y += e1.offsetTop;
159
+ } while(e1 = e1.offsetParent);
160
+ }
161
+ while((e2 = e2.parentNode) && e2.nodeName.toUpperCase() !== 'BODY') {
162
+ x -= e2.scrollLeft;
163
+ y -= e2.scrollTop;
164
+ }
165
+ return [x, y];
166
+ },
167
+
168
+
169
+ getElementSize : function(e) {
170
+ return [e.offsetWidth, e.offsetHeight];
171
+ },
172
+
173
+
174
+ getRelMousePos : function(e) {
175
+ var x = 0, y = 0;
176
+ if (!e) { e = window.event; }
177
+ if (typeof e.offsetX === 'number') {
178
+ x = e.offsetX;
179
+ y = e.offsetY;
180
+ } else if (typeof e.layerX === 'number') {
181
+ x = e.layerX;
182
+ y = e.layerY;
183
+ }
184
+ return { x: x, y: y };
185
+ },
186
+
187
+
188
+ getViewPos : function() {
189
+ if(typeof window.pageYOffset === 'number') {
190
+ return [window.pageXOffset, window.pageYOffset];
191
+ } else if(document.body && (document.body.scrollLeft || document.body.scrollTop)) {
192
+ return [document.body.scrollLeft, document.body.scrollTop];
193
+ } else if(document.documentElement && (document.documentElement.scrollLeft || document.documentElement.scrollTop)) {
194
+ return [document.documentElement.scrollLeft, document.documentElement.scrollTop];
195
+ } else {
196
+ return [0, 0];
197
+ }
198
+ },
199
+
200
+
201
+ getViewSize : function() {
202
+ if(typeof window.innerWidth === 'number') {
203
+ return [window.innerWidth, window.innerHeight];
204
+ } else if(document.body && (document.body.clientWidth || document.body.clientHeight)) {
205
+ return [document.body.clientWidth, document.body.clientHeight];
206
+ } else if(document.documentElement && (document.documentElement.clientWidth || document.documentElement.clientHeight)) {
207
+ return [document.documentElement.clientWidth, document.documentElement.clientHeight];
208
+ } else {
209
+ return [0, 0];
210
+ }
211
+ },
212
+
213
+
214
+ URI : function(uri) { // See RFC3986
215
+
216
+ this.scheme = null;
217
+ this.authority = null;
218
+ this.path = '';
219
+ this.query = null;
220
+ this.fragment = null;
221
+
222
+ this.parse = function(uri) {
223
+ var m = uri.match(/^(([A-Za-z][0-9A-Za-z+.-]*)(:))?((\/\/)([^\/?#]*))?([^?#]*)((\?)([^#]*))?((#)(.*))?/);
224
+ this.scheme = m[3] ? m[2] : null;
225
+ this.authority = m[5] ? m[6] : null;
226
+ this.path = m[7];
227
+ this.query = m[9] ? m[10] : null;
228
+ this.fragment = m[12] ? m[13] : null;
229
+ return this;
230
+ };
231
+
232
+ this.toString = function() {
233
+ var result = '';
234
+ if(this.scheme !== null) { result = result + this.scheme + ':'; }
235
+ if(this.authority !== null) { result = result + '//' + this.authority; }
236
+ if(this.path !== null) { result = result + this.path; }
237
+ if(this.query !== null) { result = result + '?' + this.query; }
238
+ if(this.fragment !== null) { result = result + '#' + this.fragment; }
239
+ return result;
240
+ };
241
+
242
+ this.toAbsolute = function(base) {
243
+ var base = new jscolor.URI(base);
244
+ var r = this;
245
+ var t = new jscolor.URI;
246
+
247
+ if(base.scheme === null) { return false; }
248
+
249
+ if(r.scheme !== null && r.scheme.toLowerCase() === base.scheme.toLowerCase()) {
250
+ r.scheme = null;
251
+ }
252
+
253
+ if(r.scheme !== null) {
254
+ t.scheme = r.scheme;
255
+ t.authority = r.authority;
256
+ t.path = removeDotSegments(r.path);
257
+ t.query = r.query;
258
+ } else {
259
+ if(r.authority !== null) {
260
+ t.authority = r.authority;
261
+ t.path = removeDotSegments(r.path);
262
+ t.query = r.query;
263
+ } else {
264
+ if(r.path === '') {
265
+ t.path = base.path;
266
+ if(r.query !== null) {
267
+ t.query = r.query;
268
+ } else {
269
+ t.query = base.query;
270
+ }
271
+ } else {
272
+ if(r.path.substr(0,1) === '/') {
273
+ t.path = removeDotSegments(r.path);
274
+ } else {
275
+ if(base.authority !== null && base.path === '') {
276
+ t.path = '/'+r.path;
277
+ } else {
278
+ t.path = base.path.replace(/[^\/]+$/,'')+r.path;
279
+ }
280
+ t.path = removeDotSegments(t.path);
281
+ }
282
+ t.query = r.query;
283
+ }
284
+ t.authority = base.authority;
285
+ }
286
+ t.scheme = base.scheme;
287
+ }
288
+ t.fragment = r.fragment;
289
+
290
+ return t;
291
+ };
292
+
293
+ function removeDotSegments(path) {
294
+ var out = '';
295
+ while(path) {
296
+ if(path.substr(0,3)==='../' || path.substr(0,2)==='./') {
297
+ path = path.replace(/^\.+/,'').substr(1);
298
+ } else if(path.substr(0,3)==='/./' || path==='/.') {
299
+ path = '/'+path.substr(3);
300
+ } else if(path.substr(0,4)==='/../' || path==='/..') {
301
+ path = '/'+path.substr(4);
302
+ out = out.replace(/\/?[^\/]*$/, '');
303
+ } else if(path==='.' || path==='..') {
304
+ path = '';
305
+ } else {
306
+ var rm = path.match(/^\/?[^\/]*/)[0];
307
+ path = path.substr(rm.length);
308
+ out = out + rm;
309
+ }
310
+ }
311
+ return out;
312
+ }
313
+
314
+ if(uri) {
315
+ this.parse(uri);
316
+ }
317
+
318
+ },
319
+
320
+
321
+ //
322
+ // Usage example:
323
+ // var myColor = new jscolor.color(myInputElement)
324
+ //
325
+
326
+ color : function(target, prop) {
327
+
328
+
329
+ this.required = true; // refuse empty values?
330
+ this.adjust = true; // adjust value to uniform notation?
331
+ this.hash = false; // prefix color with # symbol?
332
+ this.caps = true; // uppercase?
333
+ this.slider = true; // show the value/saturation slider?
334
+ this.valueElement = target; // value holder
335
+ this.styleElement = target; // where to reflect current color
336
+ this.onImmediateChange = null; // onchange callback (can be either string or function)
337
+ this.hsv = [0, 0, 1]; // read-only 0-6, 0-1, 0-1
338
+ this.rgb = [1, 1, 1]; // read-only 0-1, 0-1, 0-1
339
+ this.minH = 0; // read-only 0-6
340
+ this.maxH = 6; // read-only 0-6
341
+ this.minS = 0; // read-only 0-1
342
+ this.maxS = 1; // read-only 0-1
343
+ this.minV = 0; // read-only 0-1
344
+ this.maxV = 1; // read-only 0-1
345
+
346
+ this.pickerOnfocus = true; // display picker on focus?
347
+ this.pickerMode = 'HSV'; // HSV | HVS
348
+ this.pickerPosition = 'bottom'; // left | right | top | bottom
349
+ this.pickerSmartPosition = true; // automatically adjust picker position when necessary
350
+ this.pickerButtonHeight = 20; // px
351
+ this.pickerClosable = false;
352
+ this.pickerCloseText = 'Close';
353
+ this.pickerButtonColor = 'ButtonText'; // px
354
+ this.pickerFace = 10; // px
355
+ this.pickerFaceColor = 'ThreeDFace'; // CSS color
356
+ this.pickerBorder = 1; // px
357
+ this.pickerBorderColor = 'ThreeDHighlight ThreeDShadow ThreeDShadow ThreeDHighlight'; // CSS color
358
+ this.pickerInset = 1; // px
359
+ this.pickerInsetColor = 'ThreeDShadow ThreeDHighlight ThreeDHighlight ThreeDShadow'; // CSS color
360
+ this.pickerZIndex = 10000;
361
+
362
+
363
+ for(var p in prop) {
364
+ if(prop.hasOwnProperty(p)) {
365
+ this[p] = prop[p];
366
+ }
367
+ }
368
+
369
+
370
+ this.hidePicker = function() {
371
+ if(isPickerOwner()) {
372
+ removePicker();
373
+ }
374
+ };
375
+
376
+
377
+ this.showPicker = function() {
378
+ if(!isPickerOwner()) {
379
+ var tp = jscolor.getElementPos(target); // target pos
380
+ var ts = jscolor.getElementSize(target); // target size
381
+ var vp = jscolor.getViewPos(); // view pos
382
+ var vs = jscolor.getViewSize(); // view size
383
+ var ps = getPickerDims(this); // picker size
384
+ var a, b, c;
385
+ switch(this.pickerPosition.toLowerCase()) {
386
+ case 'left': a=1; b=0; c=-1; break;
387
+ case 'right':a=1; b=0; c=1; break;
388
+ case 'top': a=0; b=1; c=-1; break;
389
+ default: a=0; b=1; c=1; break;
390
+ }
391
+ var l = (ts[b]+ps[b])/2;
392
+
393
+ // picker pos
394
+ if (!this.pickerSmartPosition) {
395
+ var pp = [
396
+ tp[a],
397
+ tp[b]+ts[b]-l+l*c
398
+ ];
399
+ } else {
400
+ var pp = [
401
+ -vp[a]+tp[a]+ps[a] > vs[a] ?
402
+ (-vp[a]+tp[a]+ts[a]/2 > vs[a]/2 && tp[a]+ts[a]-ps[a] >= 0 ? tp[a]+ts[a]-ps[a] : tp[a]) :
403
+ tp[a],
404
+ -vp[b]+tp[b]+ts[b]+ps[b]-l+l*c > vs[b] ?
405
+ (-vp[b]+tp[b]+ts[b]/2 > vs[b]/2 && tp[b]+ts[b]-l-l*c >= 0 ? tp[b]+ts[b]-l-l*c : tp[b]+ts[b]-l+l*c) :
406
+ (tp[b]+ts[b]-l+l*c >= 0 ? tp[b]+ts[b]-l+l*c : tp[b]+ts[b]-l-l*c)
407
+ ];
408
+ }
409
+ drawPicker(pp[a], pp[b]);
410
+ }
411
+ };
412
+
413
+
414
+ this.importColor = function() {
415
+ if(!valueElement) {
416
+ this.exportColor();
417
+ } else {
418
+ if(!this.adjust) {
419
+ if(!this.fromString(valueElement.value, leaveValue)) {
420
+ styleElement.style.backgroundImage = styleElement.jscStyle.backgroundImage;
421
+ styleElement.style.backgroundColor = styleElement.jscStyle.backgroundColor;
422
+ styleElement.style.color = styleElement.jscStyle.color;
423
+ this.exportColor(leaveValue | leaveStyle);
424
+ }
425
+ } else if(!this.required && /^\s*$/.test(valueElement.value)) {
426
+ valueElement.value = '';
427
+ styleElement.style.backgroundImage = styleElement.jscStyle.backgroundImage;
428
+ styleElement.style.backgroundColor = styleElement.jscStyle.backgroundColor;
429
+ styleElement.style.color = styleElement.jscStyle.color;
430
+ this.exportColor(leaveValue | leaveStyle);
431
+
432
+ } else if(this.fromString(valueElement.value)) {
433
+ // OK
434
+ } else {
435
+ this.exportColor();
436
+ }
437
+ }
438
+ };
439
+
440
+
441
+ this.exportColor = function(flags) {
442
+ if(!(flags & leaveValue) && valueElement) {
443
+ var value = this.toString();
444
+ if(this.caps) { value = value.toUpperCase(); }
445
+ if(this.hash) { value = '#'+value; }
446
+ valueElement.value = value;
447
+ }
448
+ if(!(flags & leaveStyle) && styleElement) {
449
+ styleElement.style.backgroundImage = "none";
450
+ styleElement.style.backgroundColor =
451
+ '#'+this.toString();
452
+ styleElement.style.color =
453
+ 0.213 * this.rgb[0] +
454
+ 0.715 * this.rgb[1] +
455
+ 0.072 * this.rgb[2]
456
+ < 0.5 ? '#FFF' : '#000';
457
+ }
458
+ if(!(flags & leavePad) && isPickerOwner()) {
459
+ redrawPad();
460
+ }
461
+ if(!(flags & leaveSld) && isPickerOwner()) {
462
+ redrawSld();
463
+ }
464
+ };
465
+
466
+
467
+ this.fromHSV = function(h, s, v, flags) { // null = don't change
468
+ if(h !== null) { h = Math.max(0.0, this.minH, Math.min(6.0, this.maxH, h)); }
469
+ if(s !== null) { s = Math.max(0.0, this.minS, Math.min(1.0, this.maxS, s)); }
470
+ if(v !== null) { v = Math.max(0.0, this.minV, Math.min(1.0, this.maxV, v)); }
471
+
472
+ this.rgb = HSV_RGB(
473
+ h===null ? this.hsv[0] : (this.hsv[0]=h),
474
+ s===null ? this.hsv[1] : (this.hsv[1]=s),
475
+ v===null ? this.hsv[2] : (this.hsv[2]=v)
476
+ );
477
+
478
+ this.exportColor(flags);
479
+ };
480
+
481
+
482
+ this.fromRGB = function(r, g, b, flags) { // null = don't change
483
+ if(r !== null) { r = Math.max(0.0, Math.min(1.0, r)); }
484
+ if(g !== null) { g = Math.max(0.0, Math.min(1.0, g)); }
485
+ if(b !== null) { b = Math.max(0.0, Math.min(1.0, b)); }
486
+
487
+ var hsv = RGB_HSV(
488
+ r===null ? this.rgb[0] : r,
489
+ g===null ? this.rgb[1] : g,
490
+ b===null ? this.rgb[2] : b
491
+ );
492
+ if(hsv[0] !== null) {
493
+ this.hsv[0] = Math.max(0.0, this.minH, Math.min(6.0, this.maxH, hsv[0]));
494
+ }
495
+ if(hsv[2] !== 0) {
496
+ this.hsv[1] = hsv[1]===null ? null : Math.max(0.0, this.minS, Math.min(1.0, this.maxS, hsv[1]));
497
+ }
498
+ this.hsv[2] = hsv[2]===null ? null : Math.max(0.0, this.minV, Math.min(1.0, this.maxV, hsv[2]));
499
+
500
+ // update RGB according to final HSV, as some values might be trimmed
501
+ var rgb = HSV_RGB(this.hsv[0], this.hsv[1], this.hsv[2]);
502
+ this.rgb[0] = rgb[0];
503
+ this.rgb[1] = rgb[1];
504
+ this.rgb[2] = rgb[2];
505
+
506
+ this.exportColor(flags);
507
+ };
508
+
509
+
510
+ this.fromString = function(hex, flags) {
511
+ var m = hex.match(/^\W*([0-9A-F]{3}([0-9A-F]{3})?)\W*$/i);
512
+ if(!m) {
513
+ return false;
514
+ } else {
515
+ if(m[1].length === 6) { // 6-char notation
516
+ this.fromRGB(
517
+ parseInt(m[1].substr(0,2),16) / 255,
518
+ parseInt(m[1].substr(2,2),16) / 255,
519
+ parseInt(m[1].substr(4,2),16) / 255,
520
+ flags
521
+ );
522
+ } else { // 3-char notation
523
+ this.fromRGB(
524
+ parseInt(m[1].charAt(0)+m[1].charAt(0),16) / 255,
525
+ parseInt(m[1].charAt(1)+m[1].charAt(1),16) / 255,
526
+ parseInt(m[1].charAt(2)+m[1].charAt(2),16) / 255,
527
+ flags
528
+ );
529
+ }
530
+ return true;
531
+ }
532
+ };
533
+
534
+
535
+ this.toString = function() {
536
+ return (
537
+ (0x100 | Math.round(255*this.rgb[0])).toString(16).substr(1) +
538
+ (0x100 | Math.round(255*this.rgb[1])).toString(16).substr(1) +
539
+ (0x100 | Math.round(255*this.rgb[2])).toString(16).substr(1)
540
+ );
541
+ };
542
+
543
+
544
+ function RGB_HSV(r, g, b) {
545
+ var n = Math.min(Math.min(r,g),b);
546
+ var v = Math.max(Math.max(r,g),b);
547
+ var m = v - n;
548
+ if(m === 0) { return [ null, 0, v ]; }
549
+ var h = r===n ? 3+(b-g)/m : (g===n ? 5+(r-b)/m : 1+(g-r)/m);
550
+ return [ h===6?0:h, m/v, v ];
551
+ }
552
+
553
+
554
+ function HSV_RGB(h, s, v) {
555
+ if(h === null) { return [ v, v, v ]; }
556
+ var i = Math.floor(h);
557
+ var f = i%2 ? h-i : 1-(h-i);
558
+ var m = v * (1 - s);
559
+ var n = v * (1 - s*f);
560
+ switch(i) {
561
+ case 6:
562
+ case 0: return [v,n,m];
563
+ case 1: return [n,v,m];
564
+ case 2: return [m,v,n];
565
+ case 3: return [m,n,v];
566
+ case 4: return [n,m,v];
567
+ case 5: return [v,m,n];
568
+ }
569
+ }
570
+
571
+
572
+ function removePicker() {
573
+ delete jscolor.picker.owner;
574
+ document.getElementsByTagName('body')[0].removeChild(jscolor.picker.boxB);
575
+ }
576
+
577
+
578
+ function drawPicker(x, y) {
579
+ if(!jscolor.picker) {
580
+ jscolor.picker = {
581
+ box : document.createElement('div'),
582
+ boxB : document.createElement('div'),
583
+ pad : document.createElement('div'),
584
+ padB : document.createElement('div'),
585
+ padM : document.createElement('div'),
586
+ sld : document.createElement('div'),
587
+ sldB : document.createElement('div'),
588
+ sldM : document.createElement('div'),
589
+ btn : document.createElement('div'),
590
+ btnS : document.createElement('span'),
591
+ btnT : document.createTextNode(THIS.pickerCloseText)
592
+ };
593
+ for(var i=0,segSize=4; i<jscolor.images.sld[1]; i+=segSize) {
594
+ var seg = document.createElement('div');
595
+ seg.style.height = segSize+'px';
596
+ seg.style.fontSize = '1px';
597
+ seg.style.lineHeight = '0';
598
+ jscolor.picker.sld.appendChild(seg);
599
+ }
600
+ jscolor.picker.sldB.appendChild(jscolor.picker.sld);
601
+ jscolor.picker.box.appendChild(jscolor.picker.sldB);
602
+ jscolor.picker.box.appendChild(jscolor.picker.sldM);
603
+ jscolor.picker.padB.appendChild(jscolor.picker.pad);
604
+ jscolor.picker.box.appendChild(jscolor.picker.padB);
605
+ jscolor.picker.box.appendChild(jscolor.picker.padM);
606
+ jscolor.picker.btnS.appendChild(jscolor.picker.btnT);
607
+ jscolor.picker.btn.appendChild(jscolor.picker.btnS);
608
+ jscolor.picker.box.appendChild(jscolor.picker.btn);
609
+ jscolor.picker.boxB.appendChild(jscolor.picker.box);
610
+ }
611
+
612
+ var p = jscolor.picker;
613
+
614
+ // controls interaction
615
+ p.box.onmouseup =
616
+ p.box.onmouseout = function() { target.focus(); };
617
+ p.box.onmousedown = function() { abortBlur=true; };
618
+ p.box.onmousemove = function(e) {
619
+ if (holdPad || holdSld) {
620
+ holdPad && setPad(e);
621
+ holdSld && setSld(e);
622
+ if (document.selection) {
623
+ document.selection.empty();
624
+ } else if (window.getSelection) {
625
+ window.getSelection().removeAllRanges();
626
+ }
627
+ dispatchImmediateChange();
628
+ }
629
+ };
630
+ if('ontouchstart' in window) { // if touch device
631
+ var handle_touchmove = function(e) {
632
+ var event={
633
+ 'offsetX': e.touches[0].pageX-touchOffset.X,
634
+ 'offsetY': e.touches[0].pageY-touchOffset.Y
635
+ };
636
+ if (holdPad || holdSld) {
637
+ holdPad && setPad(event);
638
+ holdSld && setSld(event);
639
+ dispatchImmediateChange();
640
+ }
641
+ e.stopPropagation(); // prevent move "view" on broswer
642
+ e.preventDefault(); // prevent Default - Android Fix (else android generated only 1-2 touchmove events)
643
+ };
644
+ p.box.removeEventListener('touchmove', handle_touchmove, false)
645
+ p.box.addEventListener('touchmove', handle_touchmove, false)
646
+ }
647
+ p.padM.onmouseup =
648
+ p.padM.onmouseout = function() { if(holdPad) { holdPad=false; jscolor.fireEvent(valueElement,'change'); } };
649
+ p.padM.onmousedown = function(e) {
650
+ // if the slider is at the bottom, move it up
651
+ switch(modeID) {
652
+ case 0: if (THIS.hsv[2] === 0) { THIS.fromHSV(null, null, 1.0); }; break;
653
+ case 1: if (THIS.hsv[1] === 0) { THIS.fromHSV(null, 1.0, null); }; break;
654
+ }
655
+ holdSld=false;
656
+ holdPad=true;
657
+ setPad(e);
658
+ dispatchImmediateChange();
659
+ };
660
+ if('ontouchstart' in window) {
661
+ p.padM.addEventListener('touchstart', function(e) {
662
+ touchOffset={
663
+ 'X': e.target.offsetParent.offsetLeft,
664
+ 'Y': e.target.offsetParent.offsetTop
665
+ };
666
+ this.onmousedown({
667
+ 'offsetX':e.touches[0].pageX-touchOffset.X,
668
+ 'offsetY':e.touches[0].pageY-touchOffset.Y
669
+ });
670
+ });
671
+ }
672
+ p.sldM.onmouseup =
673
+ p.sldM.onmouseout = function() { if(holdSld) { holdSld=false; jscolor.fireEvent(valueElement,'change'); } };
674
+ p.sldM.onmousedown = function(e) {
675
+ holdPad=false;
676
+ holdSld=true;
677
+ setSld(e);
678
+ dispatchImmediateChange();
679
+ };
680
+ if('ontouchstart' in window) {
681
+ p.sldM.addEventListener('touchstart', function(e) {
682
+ touchOffset={
683
+ 'X': e.target.offsetParent.offsetLeft,
684
+ 'Y': e.target.offsetParent.offsetTop
685
+ };
686
+ this.onmousedown({
687
+ 'offsetX':e.touches[0].pageX-touchOffset.X,
688
+ 'offsetY':e.touches[0].pageY-touchOffset.Y
689
+ });
690
+ });
691
+ }
692
+
693
+ // picker
694
+ var dims = getPickerDims(THIS);
695
+ p.box.style.width = dims[0] + 'px';
696
+ p.box.style.height = dims[1] + 'px';
697
+
698
+ // picker border
699
+ p.boxB.style.position = 'absolute';
700
+ p.boxB.style.clear = 'both';
701
+ p.boxB.style.left = x+'px';
702
+ p.boxB.style.top = y+'px';
703
+ p.boxB.style.zIndex = THIS.pickerZIndex;
704
+ p.boxB.style.border = THIS.pickerBorder+'px solid';
705
+ p.boxB.style.borderColor = THIS.pickerBorderColor;
706
+ p.boxB.style.background = THIS.pickerFaceColor;
707
+
708
+ // pad image
709
+ p.pad.style.width = jscolor.images.pad[0]+'px';
710
+ p.pad.style.height = jscolor.images.pad[1]+'px';
711
+
712
+ // pad border
713
+ p.padB.style.position = 'absolute';
714
+ p.padB.style.left = THIS.pickerFace+'px';
715
+ p.padB.style.top = THIS.pickerFace+'px';
716
+ p.padB.style.border = THIS.pickerInset+'px solid';
717
+ p.padB.style.borderColor = THIS.pickerInsetColor;
718
+
719
+ // pad mouse area
720
+ p.padM.style.position = 'absolute';
721
+ p.padM.style.left = '0';
722
+ p.padM.style.top = '0';
723
+ p.padM.style.width = THIS.pickerFace + 2*THIS.pickerInset + jscolor.images.pad[0] + jscolor.images.arrow[0] + 'px';
724
+ p.padM.style.height = p.box.style.height;
725
+ p.padM.style.cursor = 'crosshair';
726
+
727
+ // slider image
728
+ p.sld.style.overflow = 'hidden';
729
+ p.sld.style.width = jscolor.images.sld[0]+'px';
730
+ p.sld.style.height = jscolor.images.sld[1]+'px';
731
+
732
+ // slider border
733
+ p.sldB.style.display = THIS.slider ? 'block' : 'none';
734
+ p.sldB.style.position = 'absolute';
735
+ p.sldB.style.right = THIS.pickerFace+'px';
736
+ p.sldB.style.top = THIS.pickerFace+'px';
737
+ p.sldB.style.border = THIS.pickerInset+'px solid';
738
+ p.sldB.style.borderColor = THIS.pickerInsetColor;
739
+
740
+ // slider mouse area
741
+ p.sldM.style.display = THIS.slider ? 'block' : 'none';
742
+ p.sldM.style.position = 'absolute';
743
+ p.sldM.style.right = '0';
744
+ p.sldM.style.top = '0';
745
+ p.sldM.style.width = jscolor.images.sld[0] + jscolor.images.arrow[0] + THIS.pickerFace + 2*THIS.pickerInset + 'px';
746
+ p.sldM.style.height = p.box.style.height;
747
+ try {
748
+ p.sldM.style.cursor = 'pointer';
749
+ } catch(eOldIE) {
750
+ p.sldM.style.cursor = 'hand';
751
+ }
752
+
753
+ // "close" button
754
+ function setBtnBorder() {
755
+ var insetColors = THIS.pickerInsetColor.split(/\s+/);
756
+ var pickerOutsetColor = insetColors.length < 2 ? insetColors[0] : insetColors[1] + ' ' + insetColors[0] + ' ' + insetColors[0] + ' ' + insetColors[1];
757
+ p.btn.style.borderColor = pickerOutsetColor;
758
+ }
759
+ p.btn.style.display = THIS.pickerClosable ? 'block' : 'none';
760
+ p.btn.style.position = 'absolute';
761
+ p.btn.style.left = THIS.pickerFace + 'px';
762
+ p.btn.style.bottom = THIS.pickerFace + 'px';
763
+ p.btn.style.padding = '0 15px';
764
+ p.btn.style.height = '18px';
765
+ p.btn.style.border = THIS.pickerInset + 'px solid';
766
+ setBtnBorder();
767
+ p.btn.style.color = THIS.pickerButtonColor;
768
+ p.btn.style.font = '12px sans-serif';
769
+ p.btn.style.textAlign = 'center';
770
+ try {
771
+ p.btn.style.cursor = 'pointer';
772
+ } catch(eOldIE) {
773
+ p.btn.style.cursor = 'hand';
774
+ }
775
+ p.btn.onmousedown = function () {
776
+ THIS.hidePicker();
777
+ };
778
+ p.btnS.style.lineHeight = p.btn.style.height;
779
+
780
+ // load images in optimal order
781
+ switch(modeID) {
782
+ case 0: var padImg = 'hs.png'; break;
783
+ case 1: var padImg = 'hv.png'; break;
784
+ }
785
+ p.padM.style.backgroundImage = "url('"+jscolor.getDir()+"cross.gif')";
786
+ p.padM.style.backgroundRepeat = "no-repeat";
787
+ p.sldM.style.backgroundImage = "url('"+jscolor.getDir()+"arrow.gif')";
788
+ p.sldM.style.backgroundRepeat = "no-repeat";
789
+ p.pad.style.backgroundImage = "url('"+jscolor.getDir()+padImg+"')";
790
+ p.pad.style.backgroundRepeat = "no-repeat";
791
+ p.pad.style.backgroundPosition = "0 0";
792
+
793
+ // place pointers
794
+ redrawPad();
795
+ redrawSld();
796
+
797
+ jscolor.picker.owner = THIS;
798
+ document.getElementsByTagName('body')[0].appendChild(p.boxB);
799
+ }
800
+
801
+
802
+ function getPickerDims(o) {
803
+ var dims = [
804
+ 2*o.pickerInset + 2*o.pickerFace + jscolor.images.pad[0] +
805
+ (o.slider ? 2*o.pickerInset + 2*jscolor.images.arrow[0] + jscolor.images.sld[0] : 0),
806
+ o.pickerClosable ?
807
+ 4*o.pickerInset + 3*o.pickerFace + jscolor.images.pad[1] + o.pickerButtonHeight :
808
+ 2*o.pickerInset + 2*o.pickerFace + jscolor.images.pad[1]
809
+ ];
810
+ return dims;
811
+ }
812
+
813
+
814
+ function redrawPad() {
815
+ // redraw the pad pointer
816
+ switch(modeID) {
817
+ case 0: var yComponent = 1; break;
818
+ case 1: var yComponent = 2; break;
819
+ }
820
+ var x = Math.round((THIS.hsv[0]/6) * (jscolor.images.pad[0]-1));
821
+ var y = Math.round((1-THIS.hsv[yComponent]) * (jscolor.images.pad[1]-1));
822
+ jscolor.picker.padM.style.backgroundPosition =
823
+ (THIS.pickerFace+THIS.pickerInset+x - Math.floor(jscolor.images.cross[0]/2)) + 'px ' +
824
+ (THIS.pickerFace+THIS.pickerInset+y - Math.floor(jscolor.images.cross[1]/2)) + 'px';
825
+
826
+ // redraw the slider image
827
+ var seg = jscolor.picker.sld.childNodes;
828
+
829
+ switch(modeID) {
830
+ case 0:
831
+ var rgb = HSV_RGB(THIS.hsv[0], THIS.hsv[1], 1);
832
+ for(var i=0; i<seg.length; i+=1) {
833
+ seg[i].style.backgroundColor = 'rgb('+
834
+ (rgb[0]*(1-i/seg.length)*100)+'%,'+
835
+ (rgb[1]*(1-i/seg.length)*100)+'%,'+
836
+ (rgb[2]*(1-i/seg.length)*100)+'%)';
837
+ }
838
+ break;
839
+ case 1:
840
+ var rgb, s, c = [ THIS.hsv[2], 0, 0 ];
841
+ var i = Math.floor(THIS.hsv[0]);
842
+ var f = i%2 ? THIS.hsv[0]-i : 1-(THIS.hsv[0]-i);
843
+ switch(i) {
844
+ case 6:
845
+ case 0: rgb=[0,1,2]; break;
846
+ case 1: rgb=[1,0,2]; break;
847
+ case 2: rgb=[2,0,1]; break;
848
+ case 3: rgb=[2,1,0]; break;
849
+ case 4: rgb=[1,2,0]; break;
850
+ case 5: rgb=[0,2,1]; break;
851
+ }
852
+ for(var i=0; i<seg.length; i+=1) {
853
+ s = 1 - 1/(seg.length-1)*i;
854
+ c[1] = c[0] * (1 - s*f);
855
+ c[2] = c[0] * (1 - s);
856
+ seg[i].style.backgroundColor = 'rgb('+
857
+ (c[rgb[0]]*100)+'%,'+
858
+ (c[rgb[1]]*100)+'%,'+
859
+ (c[rgb[2]]*100)+'%)';
860
+ }
861
+ break;
862
+ }
863
+ }
864
+
865
+
866
+ function redrawSld() {
867
+ // redraw the slider pointer
868
+ switch(modeID) {
869
+ case 0: var yComponent = 2; break;
870
+ case 1: var yComponent = 1; break;
871
+ }
872
+ var y = Math.round((1-THIS.hsv[yComponent]) * (jscolor.images.sld[1]-1));
873
+ jscolor.picker.sldM.style.backgroundPosition =
874
+ '0 ' + (THIS.pickerFace+THIS.pickerInset+y - Math.floor(jscolor.images.arrow[1]/2)) + 'px';
875
+ }
876
+
877
+
878
+ function isPickerOwner() {
879
+ return jscolor.picker && jscolor.picker.owner === THIS;
880
+ }
881
+
882
+
883
+ function blurTarget() {
884
+ if(valueElement === target) {
885
+ THIS.importColor();
886
+ }
887
+ if(THIS.pickerOnfocus) {
888
+ THIS.hidePicker();
889
+ }
890
+ }
891
+
892
+
893
+ function blurValue() {
894
+ if(valueElement !== target) {
895
+ THIS.importColor();
896
+ }
897
+ }
898
+
899
+
900
+ function setPad(e) {
901
+ var mpos = jscolor.getRelMousePos(e);
902
+ var x = mpos.x - THIS.pickerFace - THIS.pickerInset;
903
+ var y = mpos.y - THIS.pickerFace - THIS.pickerInset;
904
+ switch(modeID) {
905
+ case 0: THIS.fromHSV(x*(6/(jscolor.images.pad[0]-1)), 1 - y/(jscolor.images.pad[1]-1), null, leaveSld); break;
906
+ case 1: THIS.fromHSV(x*(6/(jscolor.images.pad[0]-1)), null, 1 - y/(jscolor.images.pad[1]-1), leaveSld); break;
907
+ }
908
+ }
909
+
910
+
911
+ function setSld(e) {
912
+ var mpos = jscolor.getRelMousePos(e);
913
+ var y = mpos.y - THIS.pickerFace - THIS.pickerInset;
914
+ switch(modeID) {
915
+ case 0: THIS.fromHSV(null, null, 1 - y/(jscolor.images.sld[1]-1), leavePad); break;
916
+ case 1: THIS.fromHSV(null, 1 - y/(jscolor.images.sld[1]-1), null, leavePad); break;
917
+ }
918
+ }
919
+
920
+
921
+ function dispatchImmediateChange() {
922
+ if (THIS.onImmediateChange) {
923
+ var callback;
924
+ if (typeof THIS.onImmediateChange === 'string') {
925
+ callback = new Function (THIS.onImmediateChange);
926
+ } else {
927
+ callback = THIS.onImmediateChange;
928
+ }
929
+ callback.call(THIS);
930
+ }
931
+ }
932
+
933
+
934
+ var THIS = this;
935
+ var modeID = this.pickerMode.toLowerCase()==='hvs' ? 1 : 0;
936
+ var abortBlur = false;
937
+ var
938
+ valueElement = jscolor.fetchElement(this.valueElement),
939
+ styleElement = jscolor.fetchElement(this.styleElement);
940
+ var
941
+ holdPad = false,
942
+ holdSld = false,
943
+ touchOffset = {};
944
+ var
945
+ leaveValue = 1<<0,
946
+ leaveStyle = 1<<1,
947
+ leavePad = 1<<2,
948
+ leaveSld = 1<<3;
949
+
950
+ // target
951
+ jscolor.addEvent(target, 'focus', function() {
952
+ if(THIS.pickerOnfocus) { THIS.showPicker(); }
953
+ });
954
+ jscolor.addEvent(target, 'blur', function() {
955
+ if(!abortBlur) {
956
+ window.setTimeout(function(){ abortBlur || blurTarget(); abortBlur=false; }, 0);
957
+ } else {
958
+ abortBlur = false;
959
+ }
960
+ });
961
+
962
+ // valueElement
963
+ if(valueElement) {
964
+ var updateField = function() {
965
+ THIS.fromString(valueElement.value, leaveValue);
966
+ dispatchImmediateChange();
967
+ };
968
+ jscolor.addEvent(valueElement, 'keyup', updateField);
969
+ jscolor.addEvent(valueElement, 'input', updateField);
970
+ jscolor.addEvent(valueElement, 'blur', blurValue);
971
+ valueElement.setAttribute('autocomplete', 'off');
972
+ }
973
+
974
+ // styleElement
975
+ if(styleElement) {
976
+ styleElement.jscStyle = {
977
+ backgroundImage : styleElement.style.backgroundImage,
978
+ backgroundColor : styleElement.style.backgroundColor,
979
+ color : styleElement.style.color
980
+ };
981
+ }
982
+
983
+ // require images
984
+ switch(modeID) {
985
+ case 0: jscolor.requireImage('hs.png'); break;
986
+ case 1: jscolor.requireImage('hv.png'); break;
987
+ }
988
+ jscolor.requireImage('cross.gif');
989
+ jscolor.requireImage('arrow.gif');
990
+
991
+ this.importColor();
992
+ }
993
+
994
+ };
995
+
996
+
997
+ jscolor.install();
js/sabiosystem/core/validation/color.js ADDED
@@ -0,0 +1,5 @@
 
 
 
 
 
1
+ Validation.add('validate-color','__(Error. Insert 3 or 6 numbers and letters.)',function(value){
2
+
3
+ return !(Validation.get('IsEmpty').test(value)) && /[0-9A-F]+$/i.test(value) && (value.length != 3 || value.length != 6);
4
+ }
5
+ );
package.xml ADDED
@@ -0,0 +1,24 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?xml version="1.0"?>
2
+ <package>
3
+ <name>SABIOinstaller</name>
4
+ <version>1.0.0</version>
5
+ <stability>stable</stability>
6
+ <license>WTFPL</license>
7
+ <channel>community</channel>
8
+ <extends/>
9
+ <summary>Thanks to this app you will be able to install any of our extensions into your shop faster and a whole ton easier than in case of other suppliers.</summary>
10
+ <description>Integration with a Magneto shop made easy. Thanks to this app you will be able to install any of our extensions into your shop faster and a whole ton easier than in case of other suppliers.&#xD;
11
+ &#xD;
12
+ When you choose one of our extensions, then go to the installer, enter a unique code, click install button and you are all set. With our installer you will easily update or uninstall a given extension.&#xD;
13
+ &#xD;
14
+ All you have to do is download it for free directly from our site or go to Magento Connect.&#xD;
15
+ &#xD;
16
+ Easy integration of your extensions is a just a click away.</description>
17
+ <notes>First stable version</notes>
18
+ <authors><author><name>Patryk Grudniewski</name><user>pgrudniewski</user><email>patryk.grudniewski@sabiosystem.com</email></author><author><name>Dariusz Guzik</name><user>dguzik</user><email>dariusz.guzik@sabiosystem.com</email></author></authors>
19
+ <date>2015-01-15</date>
20
+ <time>11:04:11</time>
21
+ <contents><target name="magecommunity"><dir name="SabioSystem"><dir name="Installer"><dir name="Block"><dir name="Adminhtml"><dir name="Extension"><dir name="Column"><dir name="Renderer"><file name="Action.php" hash="ba749b456c6aef60205c3608fa01ab87"/></dir></dir><dir name="Edit"><file name="Form.php" hash="013f082d7739d8238e51c87000f9fd40"/></dir><file name="Form.php" hash="7662d6a2217d85857ba1577326e0c4bd"/><file name="Grid.php" hash="0b6fd12285b724d2e63c8dbd2f404e3d"/></dir><file name="Extension.php" hash="28cf7808f354745ed57bfa8fd9bd4b2d"/></dir></dir><dir name="Helper"><file name="Data.php" hash="f6d1d9f54d281c0f74e30cc1420835e2"/></dir><dir name="Model"><file name="Cron.php" hash="4f933c9d82bdd586587dab0729790517"/><file name="Extension.php" hash="dfaf5ad4ddc5ee990900ea3c3878b6eb"/><dir name="Resource"><dir name="Extension"><file name="Collection.php" hash="1d3719b09a808730657d282dd1abcf5d"/></dir><file name="Extension.php" hash="7190c858452c6d5acf05fbcb2bac9b4c"/><file name="Setup.php" hash="d4e3022142dfa98929ee74cac310cd2c"/></dir><file name="XmlRpc.php" hash="95801c002f7dd4e2be5a2c45e775272c"/></dir><dir name="controllers"><dir name="Adminhtml"><file name="ExtensionController.php" hash="dc127823f8e7504dda552e81d7eb1a43"/></dir></dir><dir name="etc"><file name="adminhtml.xml" hash="886f5971417b2b7df63e2b96e14c2d63"/><file name="config.xml" hash="bbaec6560756edb6e1bb131f0bc61375"/><file name="system.xml" hash="d77010ad513d583b99fd5863961fc948"/></dir><dir name="sql"><dir name="sabio_installer_setup"><file name="mysql4-install-1.0.0.php" hash="428ce3e92b58827097f70c79981a91d5"/></dir></dir></dir><dir name="Utilities"><dir name="Block"><dir name="Adminhtml"><dir name="System"><dir name="Config"><file name="Color.php" hash="aad1f60d98812e80a9afe6ee39204ab8"/></dir></dir></dir></dir><dir name="Helper"><file name="Data.php" hash="5ac78969d298f454bd968a5b3b77a1a6"/></dir><dir name="Model"><dir name="Adminhtml"><dir name="System"><dir name="Config"><dir name="Backend"><file name="Color.php" hash="ea76875202a2a0beab29e3fb1e8fd189"/></dir><dir name="Source"><dir name="Style"><dir name="Align"><file name="Horizontal.php" hash="bae2cccf56d6d5e324e432b673b51bea"/></dir></dir></dir></dir></dir></dir><dir name="Resource"><dir name="Db"><file name="Abstract.php" hash="15fe915b5998825d2b3b5dc8d7144cff"/></dir></dir></dir><dir name="etc"><file name="config.xml" hash="ddffefdbbbd86c22e5ceafb408164253"/><file name="system.xml" hash="aea2b090cd52ff4660e6de950760326f"/></dir></dir></dir></target><target name="magedesign"><dir name="adminhtml"><dir name="default"><dir name="default"><dir name="layout"><file name="installer.xml" hash="e60864c39c1e2827318d916560539c7f"/><file name="sabio.xml" hash="69035eb025e8d6b5f2dd8541eb700f1a"/></dir></dir></dir></dir></target><target name="mageetc"><dir name="modules"><file name="SabioSystem_Installer.xml" hash="0c760a08a6e0b2c5833bdc02e6e2c65c"/><file name="SabioSystem_Utilities.xml" hash="2dded78cb89877e4dc883f1875024293"/></dir></target><target name="mageweb"><dir name="js"><dir name="sabiosystem"><dir name="core"><dir name="colorpicker"><file name="arrow.gif" hash="5034704a76cd55c1cbcbc58ea6bf523f"/><file name="cross.gif" hash="ba9a274b9323753cd95bc3b1eb2f4e5f"/><file name="hs.png" hash="fefa1a03d92ebad25c88dca94a0b63db"/><file name="hv.png" hash="990d71cada17da100653636cf8490884"/><file name="jscolor.js" hash="623eb54bf0273cc8f4ccb0873ee90c66"/></dir><dir name="validation"><file name="color.js" hash="9d4a6975aca097867076073489d5128e"/></dir></dir></dir></dir></target></contents>
22
+ <compatible/>
23
+ <dependencies><required><php><min>5.3.0</min><max>6.0.0</max></php><extension><name>Phar</name><min>2.0.0</min><max/></extension></required></dependencies>
24
+ </package>