RocketWeb_CustomOptionValidator - Version 1.0.0

Version Notes

Initial release

Download this release

Release Info

Developer RocketWeb
Extension RocketWeb_CustomOptionValidator
Version 1.0.0
Comparing to
See all releases


Version 1.0.0

Files changed (23) hide show
  1. app/code/community/RocketWeb/All/Helper/Data.php +4 -0
  2. app/code/community/RocketWeb/All/Model/Feed.php +19 -0
  3. app/code/community/RocketWeb/All/Model/Observer.php +12 -0
  4. app/code/community/RocketWeb/All/etc/adminhtml.xml +23 -0
  5. app/code/community/RocketWeb/All/etc/config.xml +40 -0
  6. app/code/community/RocketWeb/All/etc/system.xml +42 -0
  7. app/code/community/RocketWeb/CustomOptionValidator/Block/Adminhtml/Validators.php +19 -0
  8. app/code/community/RocketWeb/CustomOptionValidator/Block/Rewrite/Adminhtml/Catalog/Product/Edit/Tab/Options/Option.php +23 -0
  9. app/code/community/RocketWeb/CustomOptionValidator/Helper/Data.php +4 -0
  10. app/code/community/RocketWeb/CustomOptionValidator/Model/Validator.php +6 -0
  11. app/code/community/RocketWeb/CustomOptionValidator/Model/Validator/List.php +6 -0
  12. app/code/community/RocketWeb/CustomOptionValidator/Model/Validator/Type.php +263 -0
  13. app/code/community/RocketWeb/CustomOptionValidator/etc/config.xml +49 -0
  14. app/code/community/RocketWeb/CustomOptionValidator/sql/rocketweb_cov_setup/mysql4-install-1.0.0.php +9 -0
  15. app/design/adminhtml/default/default/layout/rocketweb_cov.xml +19 -0
  16. app/design/adminhtml/default/default/template/catalog/product/edit/options/option.phtml +367 -0
  17. app/design/adminhtml/default/default/template/rocketweb_cov/adminhtml/validators.phtml +5 -0
  18. app/design/frontend/base/default/template/catalog/product/view/options/type/text.phtml +41 -0
  19. app/etc/modules/RocketWeb_All.xml +9 -0
  20. app/etc/modules/RocketWeb_CustomOptionValidator.xml +9 -0
  21. js/rocketweb/adminhtml/custom_option_validation.js +323 -0
  22. package.xml +18 -0
  23. skin/adminhtml/default/default/rocketweb/adminhtml/custom_option_validation.css +17 -0
app/code/community/RocketWeb/All/Helper/Data.php ADDED
@@ -0,0 +1,4 @@
 
 
 
 
1
+ <?php
2
+ class RocketWeb_All_Helper_Data extends Mage_Core_Helper_Data {
3
+
4
+ }
app/code/community/RocketWeb/All/Model/Feed.php ADDED
@@ -0,0 +1,19 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ class RocketWeb_All_Model_Feed extends Mage_AdminNotification_Model_Feed {
3
+ public function getFeedUrl() {
4
+ $url = (Mage::getStoreConfigFlag(self::XML_USE_HTTPS_PATH) ? 'https://':'http://').'www.rocketweb.com/media/rss-notification.xml';
5
+ return $url;
6
+ }
7
+
8
+
9
+ public function getLastUpdate()
10
+ {
11
+ return Mage::app()->loadCache('rocketweb_notifications_lastcheck');
12
+ }
13
+
14
+ public function setLastUpdate()
15
+ {
16
+ Mage::app()->saveCache(time(), 'rocketweb_notifications_lastcheck');
17
+ return $this;
18
+ }
19
+ }
app/code/community/RocketWeb/All/Model/Observer.php ADDED
@@ -0,0 +1,12 @@
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ class RocketWeb_All_Model_Observer {
3
+ public function updateNotifications($observer) {
4
+ if (Mage::getStoreConfig('rocketweb_all/general/enable_notifications')) {
5
+ try {
6
+ Mage::getModel('rocketweb_all/feed')->checkUpdate();
7
+ } catch (Exception $e) {
8
+ //silently ignore
9
+ }
10
+ }
11
+ }
12
+ }
app/code/community/RocketWeb/All/etc/adminhtml.xml ADDED
@@ -0,0 +1,23 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?xml version="1.0"?>
2
+ <config>
3
+ <acl>
4
+ <resources>
5
+ <admin>
6
+ <children>
7
+ <system>
8
+ <children>
9
+ <config>
10
+ <children>
11
+ <rocketweb_all translate="title" module="rocketweb_all">
12
+ <title>RocketWeb All</title>
13
+ <sort_order>1006000</sort_order>
14
+ </rocketweb_all>
15
+ </children>
16
+ </config>
17
+ </children>
18
+ </system>
19
+ </children>
20
+ </admin>
21
+ </resources>
22
+ </acl>
23
+ </config>
app/code/community/RocketWeb/All/etc/config.xml ADDED
@@ -0,0 +1,40 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?xml version="1.0"?>
2
+ <config>
3
+ <modules>
4
+ <RocketWeb_All>
5
+ <version>1.0.0</version>
6
+ </RocketWeb_All>
7
+ </modules>
8
+ <global>
9
+ <helpers>
10
+ <rocketweb_all>
11
+ <class>RocketWeb_All_Helper</class>
12
+ </rocketweb_all>
13
+ </helpers>
14
+ <models>
15
+ <rocketweb_all>
16
+ <class>RocketWeb_All_Model</class>
17
+ </rocketweb_all>
18
+ </models>
19
+ </global>
20
+ <adminhtml>
21
+ <events>
22
+ <controller_action_predispatch>
23
+ <observers>
24
+ <rocketweb_all>
25
+ <type>singleton</type>
26
+ <class>rocketweb_all/observer</class>
27
+ <method>updateNotifications</method>
28
+ </rocketweb_all>
29
+ </observers>
30
+ </controller_action_predispatch>
31
+ </events>
32
+ </adminhtml>
33
+ <default>
34
+ <rocketweb_all>
35
+ <general>
36
+ <enable_notifications>1</enable_notifications>
37
+ </general>
38
+ </rocketweb_all>
39
+ </default>
40
+ </config>
app/code/community/RocketWeb/All/etc/system.xml ADDED
@@ -0,0 +1,42 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?xml version="1.0"?>
2
+ <config>
3
+ <tabs>
4
+ <rocketweb_tab>
5
+ <label>Rocket Web Extensions</label>
6
+ <sort_order>1005001</sort_order>
7
+ </rocketweb_tab>
8
+ </tabs>
9
+ <sections>
10
+ <rocketweb_all translate="label" module="rocketweb_all">
11
+ <label>General</label>
12
+ <tab>rocketweb_tab</tab>
13
+ <frontend_type>text</frontend_type>
14
+ <sort_order>100</sort_order>
15
+ <show_in_default>1</show_in_default>
16
+ <show_in_website>1</show_in_website>
17
+ <show_in_store>1</show_in_store>
18
+ <groups>
19
+ <general translate="label">
20
+ <label>Settings</label>
21
+ <frontend_type>text</frontend_type>
22
+ <sort_order>10</sort_order>
23
+ <show_in_default>1</show_in_default>
24
+ <show_in_website>1</show_in_website>
25
+ <show_in_store>1</show_in_store>
26
+ <fields>
27
+ <enable_notifications translate="label comment">
28
+ <label>Enable notifications?</label>
29
+ <comment><![CDATA[]]></comment>
30
+ <frontend_type>select</frontend_type>
31
+ <source_model>adminhtml/system_config_source_yesno</source_model>
32
+ <sort_order>10</sort_order>
33
+ <show_in_default>1</show_in_default>
34
+ <show_in_website>1</show_in_website>
35
+ <show_in_store>1</show_in_store>
36
+ </enable_notifications>
37
+ </fields>
38
+ </general>
39
+ </groups>
40
+ </rocketweb_all>
41
+ </sections>
42
+ </config>
app/code/community/RocketWeb/CustomOptionValidator/Block/Adminhtml/Validators.php ADDED
@@ -0,0 +1,19 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ class RocketWeb_CustomOptionValidator_Block_Adminhtml_Validators extends Mage_Core_Block_Template {
3
+ public function getValidatorsInGroups() {
4
+ $ret = array();
5
+
6
+ $model = Mage::getModel('rocketweb_cov/validator_type');
7
+ $groups = $model->getGroups();
8
+ $items = $model->getTypes();
9
+
10
+ foreach($groups as $group) {
11
+ foreach($items as $key=>$data) {
12
+ if($group == $data['group']) {
13
+ $ret[$group][$key] = $data;
14
+ }
15
+ }
16
+ }
17
+ return json_encode($ret);
18
+ }
19
+ }
app/code/community/RocketWeb/CustomOptionValidator/Block/Rewrite/Adminhtml/Catalog/Product/Edit/Tab/Options/Option.php ADDED
@@ -0,0 +1,23 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ class RocketWeb_CustomOptionValidator_Block_Rewrite_Adminhtml_Catalog_Product_Edit_Tab_Options_Option
3
+ extends Mage_Adminhtml_Block_Catalog_Product_Edit_Tab_Options_Option {
4
+
5
+ public function getOptionValues()
6
+ {
7
+ parent::getOptionValues();
8
+
9
+
10
+ $optionsArr = array_reverse($this->getProduct()->getOptions(), true);
11
+ foreach ($optionsArr as $option) {
12
+ foreach($this->_values as &$value) {
13
+ if($value['id'] == $option->getOptionId()) {
14
+ $value['validators'] = $option->getValidators();
15
+ }
16
+ }
17
+ }
18
+
19
+
20
+ return $this->_values;
21
+ }
22
+
23
+ }
app/code/community/RocketWeb/CustomOptionValidator/Helper/Data.php ADDED
@@ -0,0 +1,4 @@
 
 
 
 
1
+ <?php
2
+ class RocketWeb_CustomOptionValidator_Helper_Data extends Mage_Core_Helper_Data {
3
+
4
+ }
app/code/community/RocketWeb/CustomOptionValidator/Model/Validator.php ADDED
@@ -0,0 +1,6 @@
 
 
 
 
 
 
1
+ <?php
2
+ class RocketWeb_CustomOptionValidator_Model_Validator {
3
+ private $_id = null;
4
+ private $_group = null;
5
+
6
+ }
app/code/community/RocketWeb/CustomOptionValidator/Model/Validator/List.php ADDED
@@ -0,0 +1,6 @@
 
 
 
 
 
 
1
+ <?php
2
+ class RocketWeb_CustomOptionValidator_Model_Validator_List {
3
+ public function getAllValidators() {
4
+
5
+ }
6
+ }
app/code/community/RocketWeb/CustomOptionValidator/Model/Validator/Type.php ADDED
@@ -0,0 +1,263 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ class RocketWeb_CustomOptionValidator_Model_Validator_Type {
3
+ const GROUP_OTHER = 'Other';
4
+ const GROUP_COMMON = 'Common';
5
+ const GROUP_NUMBERS = 'Numbers';
6
+ const GROUP_LOCATION = 'Location/phone';
7
+ const GROUP_TEXT = 'Text';
8
+ const GROUP_CC_SSN = 'Credit Card Validation/SSN';
9
+
10
+ const TYPE_TEXT = 'field';
11
+ const TYPE_TEXT_AREA = 'area';
12
+ const TYPE_FILE = 'file';
13
+ const TYPE_DROP_DOWN = 'drop_down';
14
+ const TYPE_CHECKBOX = 'checkbox';
15
+ const TYPE_RADIO = 'radio';
16
+ const TYPE_MULTI = 'multiple';
17
+ const TYPE_DATE = 'date';
18
+ const TYPE_DATE_TIME = 'date_time';
19
+ const TYPE_TIME = 'time';
20
+
21
+
22
+ public function getGroups() {
23
+ return array(
24
+ self::GROUP_COMMON,
25
+ self::GROUP_TEXT,
26
+ self::GROUP_NUMBERS,
27
+ self::GROUP_LOCATION,
28
+ self::GROUP_CC_SSN,
29
+ self::GROUP_OTHER,
30
+ );
31
+ }
32
+
33
+
34
+ public function getTypes() {
35
+ return array(
36
+ 'validate-no-html-tags' => array(
37
+ 'group' => self::GROUP_OTHER,
38
+ 'title' => 'No html tags',
39
+ 'description' => '',
40
+ 'for_types' => array(self::TYPE_TEXT,self::TYPE_TEXT_AREA),
41
+ ),
42
+ 'validate-number' => array(
43
+ 'group' => self::GROUP_NUMBERS,
44
+ 'title' => 'Number',
45
+ 'description' => '',
46
+ 'for_types' => array(self::TYPE_TEXT,self::TYPE_TEXT_AREA),
47
+ ),
48
+ 'validate-number-range' => array(
49
+ 'group' => self::GROUP_NUMBERS,
50
+ 'title' => 'Number in range',
51
+ 'description' => '',
52
+ 'for_types' => array(self::TYPE_TEXT,self::TYPE_TEXT_AREA),
53
+ 'extra' => array(
54
+ 'combined_prefix' => 1,
55
+ 'prefix' => 'number-range',
56
+ 'elements' => array(
57
+ 'n1' => array(
58
+ 'prefix' => 'number-range',
59
+ 'style' => 'width:30px',
60
+ 'label' => 'Min:',
61
+ 'required' => true
62
+ ),
63
+ 'n2' => array(
64
+ 'prefix' => 'number-range',
65
+ 'style' => 'width:30px',
66
+ 'label' => 'Max:',
67
+ 'required' => true
68
+ )
69
+ )
70
+ )
71
+ ),
72
+ 'validate-digits' => array(
73
+ 'group' => self::GROUP_NUMBERS,
74
+ 'title' => 'Digits',
75
+ 'description' => '',
76
+ 'for_types' => array(self::TYPE_TEXT,self::TYPE_TEXT_AREA),
77
+ ),
78
+ 'validate-digits-range' => array(
79
+ 'group' => self::GROUP_NUMBERS,
80
+ 'title' => 'Digits range',
81
+ 'description' => '',
82
+ 'for_types' => array(self::TYPE_TEXT,self::TYPE_TEXT_AREA),
83
+ 'extra' => array(
84
+ 'combined_prefix' => 1,
85
+ 'prefix' => 'digits-range',
86
+ 'elements' => array(
87
+ 'n1' => array(
88
+ 'prefix' => 'digits-range',
89
+ 'style' => 'width:30px',
90
+ 'label' => 'Min:',
91
+ 'required' => true
92
+ ),
93
+ 'n2' => array(
94
+ 'prefix' => 'digits-range',
95
+ 'style' => 'width:30px',
96
+ 'label' => 'Max:',
97
+ 'required' => true
98
+ )
99
+ )
100
+ )
101
+ ),
102
+ 'validate-alpha' => array(
103
+ 'group' => self::GROUP_TEXT,
104
+ 'title' => 'Letters only',
105
+ 'description' => 'Use letters only (a-z or A-Z) in this field',
106
+ 'for_types' => array(self::TYPE_TEXT,self::TYPE_TEXT_AREA),
107
+ ),
108
+ 'validate-code' => array(
109
+ 'group' => self::GROUP_TEXT,
110
+ 'title' => 'Code',
111
+ 'description' => 'Use only letters (a-z), numbers (0-9) or underscore(_) in this field, first character should be a letter.',
112
+ 'for_types' => array(self::TYPE_TEXT,self::TYPE_TEXT_AREA),
113
+ ),
114
+ 'validate-alphanum' => array(
115
+ 'group' => self::GROUP_TEXT,
116
+ 'title' => 'Alphanumeric',
117
+ 'description' => 'Use only letters (a-z or A-Z) or numbers (0-9) only in this field. No spaces or other characters are allowed.',
118
+ 'for_types' => array(self::TYPE_TEXT,self::TYPE_TEXT_AREA),
119
+ ),
120
+ 'validate-alphanum-with-spaces'=> array(
121
+ 'group' => self::GROUP_TEXT,
122
+ 'title' => 'Alphanumeric with spaces',
123
+ 'description' => 'Use only letters (a-z or A-Z), numbers (0-9) or spaces only in this field.',
124
+ 'for_types' => array(self::TYPE_TEXT,self::TYPE_TEXT_AREA),
125
+ ),
126
+ 'validate-street' => array(
127
+ 'group' => self::GROUP_LOCATION,
128
+ 'title' => 'Street address',
129
+ 'description' => 'Use only letters (a-z or A-Z) or numbers (0-9) or spaces and # only in this field.',
130
+ 'for_types' => array(self::TYPE_TEXT,self::TYPE_TEXT_AREA),
131
+ ),
132
+ 'validate-phoneStrict' => array(
133
+ 'group' => self::GROUP_LOCATION,
134
+ 'title' => 'Strict phone validation',
135
+ 'description' => '',
136
+ 'for_types' => array(self::TYPE_TEXT,self::TYPE_TEXT_AREA),
137
+ ),
138
+ 'validate-phoneLax' => array(
139
+ 'group' => self::GROUP_LOCATION,
140
+ 'title' => 'Lax phone validation',
141
+ 'description' => '',
142
+ 'for_types' => array(self::TYPE_TEXT,self::TYPE_TEXT_AREA),
143
+ ),
144
+ 'validate-fax' => array(
145
+ 'group' => self::GROUP_LOCATION,
146
+ 'title' => 'Fax',
147
+ 'description' => '',
148
+ 'for_types' => array(self::TYPE_TEXT,self::TYPE_TEXT_AREA),
149
+ ),
150
+ 'validate-date' => array(
151
+ 'group' => self::GROUP_COMMON,
152
+ 'title' => 'Date',
153
+ 'description' => '',
154
+ 'for_types' => array(self::TYPE_TEXT,self::TYPE_TEXT_AREA),
155
+ ),
156
+ 'validate-email' => array(
157
+ 'group' => self::GROUP_COMMON,
158
+ 'title' => 'E-mail',
159
+ 'description' => '',
160
+ 'for_types' => array(self::TYPE_TEXT,self::TYPE_TEXT_AREA),
161
+ ),
162
+ 'validate-emailSender' => array(
163
+ 'group' => self::GROUP_OTHER,
164
+ 'title' => 'E-mail sender',
165
+ 'description' => '',
166
+ 'for_types' => array(self::TYPE_TEXT,self::TYPE_TEXT_AREA),
167
+ ),
168
+ 'validate-password' => array(
169
+ 'group' => self::GROUP_OTHER,
170
+ 'title' => 'Password',
171
+ 'description' => '6 or more characters, leading or trailing spaces will be ignored',
172
+ 'for_types' => array(self::TYPE_TEXT,self::TYPE_TEXT_AREA),
173
+ ),
174
+ 'validate-url' => array(
175
+ 'group' => self::GROUP_OTHER,
176
+ 'title' => 'Url',
177
+ 'description' => 'valid URL, protocol is required (http://, https:// or ftp://)',
178
+ 'for_types' => array(self::TYPE_TEXT,self::TYPE_TEXT_AREA),
179
+ ),
180
+ 'validate-clean-url' => array(
181
+ 'group' => self::GROUP_OTHER,
182
+ 'title' => 'Clean url',
183
+ 'description' => 'Valid URL, for example http://www.example.com or www.example.com',
184
+ 'for_types' => array(self::TYPE_TEXT,self::TYPE_TEXT_AREA),
185
+ ),
186
+ 'validate-ssn' => array(
187
+ 'group' => self::GROUP_CC_SSN,
188
+ 'title' => 'Social Security Number',
189
+ 'description' => '',
190
+ 'for_types' => array(self::TYPE_TEXT,self::TYPE_TEXT_AREA),
191
+ ),
192
+ 'validate-zip' => array(
193
+ 'group' => self::GROUP_LOCATION,
194
+ 'title' => 'US zip code',
195
+ 'description' => '',
196
+ 'for_types' => array(self::TYPE_TEXT,self::TYPE_TEXT_AREA),
197
+ ),
198
+ 'validate-zip-international' => array(
199
+ 'group' => self::GROUP_LOCATION,
200
+ 'title' => 'International zip code',
201
+ 'description' => '',
202
+ 'for_types' => array(self::TYPE_TEXT,self::TYPE_TEXT_AREA),
203
+ ),
204
+ 'validate-not-negative-number' => array(
205
+ 'group' => self::GROUP_NUMBERS,
206
+ 'title' => 'Non-negative number',
207
+ 'description' => 'zero or grater',
208
+ 'for_types' => array(self::TYPE_TEXT,self::TYPE_TEXT_AREA),
209
+ ),
210
+ 'validate-greater-than-zero' => array(
211
+ 'group' => self::GROUP_NUMBERS,
212
+ 'title' => 'Positive number',
213
+ 'description' => '',
214
+ 'for_types' => array(self::TYPE_TEXT,self::TYPE_TEXT_AREA),
215
+ ),
216
+ 'validate-cc-number' => array(
217
+ 'group' => self::GROUP_CC_SSN,
218
+ 'title' => 'Credit Card number',
219
+ 'description' => '',
220
+ 'for_types' => array(self::TYPE_TEXT,self::TYPE_TEXT_AREA),
221
+ ),
222
+ 'validate-cc-exp' => array(
223
+ 'group' => self::GROUP_CC_SSN,
224
+ 'title' => 'Credit Card expiration date',
225
+ 'description' => '',
226
+ 'for_types' => array(self::TYPE_TEXT,self::TYPE_TEXT_AREA),
227
+ ),
228
+ 'validate-cc-cvn' => array(
229
+ 'group' => self::GROUP_CC_SSN,
230
+ 'title' => 'Credit Card verification number',
231
+ 'description' => '',
232
+ 'for_types' => array(self::TYPE_TEXT,self::TYPE_TEXT_AREA),
233
+ ),
234
+ 'validate-length' => array(
235
+ 'group' => self::GROUP_COMMON,
236
+ 'title' => 'Required Length',
237
+ 'description' => 'You can leave the min or max fields empty if you do not require a minimum/maximum',
238
+ 'for_types' => array(self::TYPE_TEXT,self::TYPE_TEXT_AREA),
239
+ 'extra' => array(
240
+ 'combined_prefix' => 0,
241
+ 'elements' => array(
242
+ 'n1' => array(
243
+ 'style' => 'width:30px',
244
+ 'label' => 'Min:',
245
+ 'prefix' => 'minimum-length'
246
+ ),
247
+ 'n2' => array(
248
+ 'style' => 'width:30px',
249
+ 'label' => 'Max:',
250
+ 'prefix' => 'maximum-length'
251
+ )
252
+ )
253
+ )
254
+ ),
255
+ 'validate-percents' => array(
256
+ 'group' => self::GROUP_NUMBERS,
257
+ 'title' => 'Percent value',
258
+ 'description' => '',
259
+ 'for_types' => array(self::TYPE_TEXT,self::TYPE_TEXT_AREA),
260
+ ),
261
+ );
262
+ }
263
+ }
app/code/community/RocketWeb/CustomOptionValidator/etc/config.xml ADDED
@@ -0,0 +1,49 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?xml version="1.0"?>
2
+ <config>
3
+ <modules>
4
+ <RocketWeb_CustomOptionValidator>
5
+ <version>1.0.0</version>
6
+ </RocketWeb_CustomOptionValidator>
7
+ </modules>
8
+ <global>
9
+ <helpers>
10
+ <rocketweb_cov>
11
+ <class>RocketWeb_CustomOptionValidator_Helper</class>
12
+ </rocketweb_cov>
13
+ </helpers>
14
+ <models>
15
+ <rocketweb_cov>
16
+ <class>RocketWeb_CustomOptionValidator_Model</class>
17
+ </rocketweb_cov>
18
+ </models>
19
+ <blocks>
20
+ <rocketweb_cov>
21
+ <class>RocketWeb_CustomOptionValidator_Block</class>
22
+ </rocketweb_cov>
23
+ <adminhtml>
24
+ <rewrite>
25
+ <catalog_product_edit_tab_options_option>RocketWeb_CustomOptionValidator_Block_Rewrite_Adminhtml_Catalog_Product_Edit_Tab_Options_Option</catalog_product_edit_tab_options_option>
26
+ </rewrite>
27
+ </adminhtml>
28
+ </blocks>
29
+ <resources>
30
+ <rocketweb_cov_setup>
31
+ <setup>
32
+ <module>RocketWeb_CustomOptionValidator</module>
33
+ </setup>
34
+ <connection>
35
+ <use>core_setup</use>
36
+ </connection>
37
+ </rocketweb_cov_setup>
38
+ </resources>
39
+ </global>
40
+ <adminhtml>
41
+ <layout>
42
+ <updates>
43
+ <rocketweb_cov>
44
+ <file>rocketweb_cov.xml</file>
45
+ </rocketweb_cov>
46
+ </updates>
47
+ </layout>
48
+ </adminhtml>
49
+ </config>
app/code/community/RocketWeb/CustomOptionValidator/sql/rocketweb_cov_setup/mysql4-install-1.0.0.php ADDED
@@ -0,0 +1,9 @@
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ $installer = $this;
4
+
5
+ $installer->startSetup();
6
+
7
+ $installer->run("ALTER TABLE `{$this->getTable('catalog/product_option')}` ADD `validators` TEXT NOT NULL");
8
+
9
+ $installer->endSetup();
app/design/adminhtml/default/default/layout/rocketweb_cov.xml ADDED
@@ -0,0 +1,19 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <layout>
2
+ <adminhtml_catalog_product_options>
3
+ <reference name="root">
4
+ <block type="rocketweb_cov/adminhtml_validators" name="rocketweb.cov.adminhtml_validators" template="rocketweb_cov/adminhtml/validators.phtml"/>
5
+ </reference>
6
+ </adminhtml_catalog_product_options>
7
+ <adminhtml_catalog_product_edit>
8
+ <reference name="head">
9
+ <action method="addCss"><name>rocketweb/adminhtml/custom_option_validation.css</name></action>
10
+ <action method="addJs"><script>rocketweb/adminhtml/custom_option_validation.js</script></action>
11
+ </reference>
12
+ </adminhtml_catalog_product_edit>
13
+ <adminhtml_catalog_product_new>
14
+ <reference name="head">
15
+ <action method="addCss"><name>rocketweb/adminhtml/custom_option_validation.css</name></action>
16
+ <action method="addJs"><script>rocketweb/adminhtml/custom_option_validation.js</script></action>
17
+ </reference>
18
+ </adminhtml_catalog_product_new>
19
+ </layout>
app/design/adminhtml/default/default/template/catalog/product/edit/options/option.phtml ADDED
@@ -0,0 +1,367 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Magento
4
+ *
5
+ * NOTICE OF LICENSE
6
+ *
7
+ * This source file is subject to the Academic Free License (AFL 3.0)
8
+ * that is bundled with this package in the file LICENSE_AFL.txt.
9
+ * It is also available through the world-wide-web at this URL:
10
+ * http://opensource.org/licenses/afl-3.0.php
11
+ * If you did not receive a copy of the license and are unable to
12
+ * obtain it through the world-wide-web, please send an email
13
+ * to license@magentocommerce.com so we can send you a copy immediately.
14
+ *
15
+ * DISCLAIMER
16
+ *
17
+ * Do not edit or add to this file if you wish to upgrade Magento to newer
18
+ * versions in the future. If you wish to customize Magento for your
19
+ * needs please refer to http://www.magentocommerce.com for more information.
20
+ *
21
+ * @category design
22
+ * @package default_default
23
+ * @copyright Copyright (c) 2012 Magento Inc. (http://www.magentocommerce.com)
24
+ * @license http://opensource.org/licenses/afl-3.0.php Academic Free License (AFL 3.0)
25
+ */
26
+ ?>
27
+ <?php echo $this->getTemplatesHtml() ?>
28
+ <script type="text/javascript">
29
+ //<![CDATA[
30
+ window.skinUrl = '<?php echo $this->getSkinUrl();?>';
31
+
32
+ var popupTemplate = '<div style="display:none" class="custom-option-validator-popup" id="validators_<?php echo $this->getFieldId() ?>_{{id}}">'+
33
+ '<div class="header">Configure Validators <a href="#" onclick="hideValidatorsPopup(\'validators_<?php echo $this->getFieldId() ?>_{{id}}\');return false;" class="close"></a></div>'+
34
+ '<div><dl class="popup-content accordion"></dl></div>'+
35
+ '<div class="buttons-set a-right">'+
36
+ '<button type="button" class="scalable" onclick="submitValidatorsPopup(\'validators_<?php echo $this->getFieldId() ?>_{{id}}\')"><span><span><span>OK</span></span></span></button>'+
37
+ '</div>'+
38
+ '<input type="hidden" id="custom_validators_<?php echo $this->getFieldId() ?>_{{id}}" name="product[options][{{id}}][validators]" value="{{validators}}"/>'+
39
+ '</div>';
40
+
41
+ var firstStepTemplate = '<div class="option-box" id="option_{{id}}">'+
42
+ '<table id="<?php echo $this->getFieldId() ?>_{{id}}" class="option-header" cellpadding="0" cellspacing="0">'+
43
+ '<input type="hidden" id="<?php echo $this->getFieldId() ?>_{{id}}_is_delete" name="<?php echo $this->getFieldName() ?>[{{id}}][is_delete]" value="" />'+
44
+ '<input type="hidden" id="<?php echo $this->getFieldId() ?>_{{id}}_previous_type" name="<?php echo $this->getFieldName() ?>[{{id}}][previous_type]" value="{{type}}" />'+
45
+ '<input type="hidden" id="<?php echo $this->getFieldId() ?>_{{id}}_previous_group" name="<?php echo $this->getFieldName() ?>[{{id}}][previous_group]" value="" />'+
46
+ '<input type="hidden" id="<?php echo $this->getFieldId() ?>_{{id}}_id" name="<?php echo $this->getFieldName() ?>[{{id}}][id]" value="{{id}}" />'+
47
+ '<input type="hidden" id="<?php echo $this->getFieldId() ?>_{{id}}_option_id" name="<?php echo $this->getFieldName() ?>[{{id}}][option_id]" value="{{option_id}}" />'+
48
+ '<thead>'+
49
+ '<tr>'+
50
+ '<th class="opt-title"><?php echo Mage::helper('catalog')->__('Title') ?> <span class="required">*</span></th>'+
51
+ '<th class="opt-type"><?php echo Mage::helper('catalog')->__('Input Type') ?> <span class="required">*</span></th>'+
52
+ '<th class="opt-req"><?php echo $this->jsQuoteEscape(Mage::helper('catalog')->__('Is Required')) ?></th>'+
53
+ '<th class="opt-order"><?php echo Mage::helper('catalog')->__('Sort Order') ?></th>'+
54
+ '<th class="opt-validate">&nbsp;</th>'+
55
+ '<th class="a-right"><?php echo $this->jsQuoteEscape($this->getDeleteButtonHtml()) ?></th>'+
56
+ '</tr>'+
57
+ '</thead>'+
58
+ '<tr>'+
59
+ '<td><input type="text" class="required-entry input-text" id="<?php echo $this->getFieldId() ?>_{{id}}_title" name="<?php echo $this->getFieldName() ?>[{{id}}][title]" value="{{title}}">{{checkboxScopeTitle}}</td>'+
60
+ '<td><?php echo $this->getTypeSelectHtml() ?></td>'+
61
+ '<td class="opt-req"><?php echo $this->getRequireSelectHtml() ?></td>'+
62
+ '<td><input type="text" class="validate-zero-or-greater input-text" name="<?php echo $this->getFieldName() ?>[{{id}}][sort_order]" value="{{sort_order}}"></td>'+
63
+ '<td style="padding-left:10px;"><button style="display:none" id="product_option_{{id}}_type_cfg_button" onclick="window.rwvalidators.populateValidatorPopup(\'<?php echo $this->getFieldId() ?>_{{id}}\');showValidatorsPopup(\'validators_<?php echo $this->getFieldId() ?>_{{id}}\',100,100);return false;"><span><span><?php echo Mage::helper('catalog')->__('Configure Validators') ?></span></span></button>'+popupTemplate+'</td>'+
64
+ '<td>&nbsp;</td>'+
65
+ '</tr></table></div>';
66
+
67
+ var productOption = {
68
+ div : $('product_options_container_top'),
69
+ templateSyntax : /(^|.|\r|\n)({{(\w+)}})/,
70
+ templateText : firstStepTemplate,
71
+ itemCount : 1,
72
+ add : function(data) {
73
+ this.template = new Template(this.templateText, this.templateSyntax);
74
+
75
+ if(!data.id){
76
+ data = {};
77
+ data.id = this.itemCount;
78
+ data.type = '';
79
+ data.option_id = 0;
80
+ data.validators = '';
81
+ } else {
82
+ this.itemCount = data.item_count;
83
+ }
84
+
85
+ Element.insert(this.div, {'after':this.template.evaluate(data)});
86
+
87
+ //set selected type
88
+ if (data.type) {
89
+ $A($('<?php echo $this->getFieldId() ?>_'+data.id+'_type').options).each(function(option){
90
+ if (option.value==data.type) option.selected = true;
91
+ });
92
+ }
93
+
94
+ //set selected is_require
95
+ if (data.is_require) {
96
+ $A($('<?php echo $this->getFieldId() ?>_'+data.id+'_is_require').options).each(function(option){
97
+ if (option.value==data.is_require) option.selected = true;
98
+ });
99
+ }
100
+
101
+ if (data.checkboxScopeTitle) {
102
+ //set disabled
103
+ if ($('<?php echo $this->getFieldId() ?>_'+data.option_id+'_title') && data.scopeTitleDisabled) {
104
+ $('<?php echo $this->getFieldId() ?>_'+data.option_id+'_title').disable();
105
+ }
106
+ }
107
+
108
+ this.itemCount++;
109
+ this.bindRemoveButtons();
110
+ productOptionType.bindSelectInputType();
111
+ },
112
+ remove : function(event){
113
+ var element = $(Event.findElement(event, 'div'));
114
+ if(element){
115
+ $('product_'+element.readAttribute('id')+'_'+'is_delete').value = '1';
116
+ element.addClassName('no-display');
117
+ element.addClassName('ignore-validate');
118
+ element.hide();
119
+ }
120
+ },
121
+ bindRemoveButtons : function(){
122
+ var buttons = $$('div.product-custom-options .delete-product-option');
123
+ for(var i=0;i<buttons.length;i++){
124
+ if(!$(buttons[i]).binded){
125
+ $(buttons[i]).binded = true;
126
+ Event.observe(buttons[i], 'click', this.remove.bind(this));
127
+ }
128
+ }
129
+ var inputs = $$('div.product-custom-options button', 'div.product-custom-options input', 'div.product-custom-options select', 'div.product-custom-options textarea');
130
+ <?php if ($this->isReadonly()):?>
131
+ for (var i=0, l = inputs.length; i < l; i ++) {
132
+ inputs[i].disabled = true;
133
+ if (inputs[i].tagName.toLowerCase()=='button') {
134
+ inputs[i].addClassName('disabled');
135
+ }
136
+ }
137
+ <?php else: ?>
138
+ inputs.each(function(el) { Event.observe(el, 'change', el.setHasChanges.bind(el)); } )
139
+ <?php endif;?>
140
+ }
141
+ }
142
+
143
+
144
+ var productOptionType = {
145
+ templateSyntax : /(^|.|\r|\n)({{(\w+)}})/,
146
+ loadStepTwo : function(event){
147
+ var element = $(Event.findElement(event, 'select'));
148
+
149
+ var group = '';
150
+ var previousGroupElm = $(element.readAttribute('id').sub('_type', '_previous_group'));
151
+
152
+ switch(element.getValue()){
153
+ case 'field':
154
+ case 'area':
155
+ template = OptionTemplateText;
156
+ group = 'text';
157
+ break;
158
+ case 'file':
159
+ template = OptionTemplateFile;
160
+ group = 'file';
161
+ break;
162
+ case 'drop_down':
163
+ case 'radio':
164
+ case 'checkbox':
165
+ case 'multiple':
166
+ template = OptionTemplateSelect;
167
+ group = 'select';
168
+ break;
169
+ case 'date':
170
+ case 'date_time':
171
+ case 'time':
172
+ template = OptionTemplateDate;
173
+ group = 'date';
174
+ break;
175
+ default:
176
+ template = '';
177
+ group = 'unknown';
178
+ break;
179
+ }
180
+
181
+ if (previousGroupElm.getValue() != group) {
182
+ if ($(element.readAttribute('id')+'_'+previousGroupElm.getValue())) {
183
+ formElm = $(element.readAttribute('id')+'_'+previousGroupElm.getValue()).descendants();
184
+ formElm.each(function(elm){
185
+ if (elm.tagName == 'input' || elm.tagName == 'select') {
186
+ elm.name = '__delete__'+elm.readAttribute('name');
187
+ }
188
+ });
189
+
190
+ $(element.readAttribute('id')+'_'+previousGroupElm.getValue()).addClassName('no-display');
191
+ $(element.readAttribute('id')+'_'+previousGroupElm.getValue()).addClassName('ignore-validate');
192
+ $(element.readAttribute('id')+'_'+previousGroupElm.getValue()).hide();
193
+ }
194
+
195
+ previousGroupElm.value = group;
196
+
197
+ if ($(element.readAttribute('id')+'_'+group)) {
198
+ formElm = $(element.readAttribute('id')+'_'+group).descendants();
199
+ formElm.each(function(elm){
200
+ if (elm.match('input') || elm.match('select')) {
201
+ elm.name = elm.readAttribute('name').sub('__delete__', '');
202
+ }
203
+ });
204
+ $(element.readAttribute('id')+'_'+group).removeClassName('no-display');
205
+ $(element.readAttribute('id')+'_'+group).removeClassName('ignore-validate');
206
+ $(element.readAttribute('id')+'_'+group).show();
207
+
208
+ } else {
209
+ template = '<div id="'+element.readAttribute('id')+'_'+group+'" class="grid tier form-list">'+template+'</div><div id="'+element.readAttribute('id')+'_'+group+'_advice"></div';
210
+ this.secondTemplate = new Template(template, this.templateSyntax);
211
+
212
+ data = {};
213
+ if (!data.option_id) {
214
+ data = {};
215
+ data.option_id = $(element.readAttribute('id').sub('_type', '_id')).getValue();
216
+ }
217
+
218
+ Element.insert(element.readAttribute('id').sub('_type', ''), {'after':this.secondTemplate.evaluate(data)});
219
+
220
+ switch(element.getValue()){
221
+ case 'drop_down':
222
+ case 'radio':
223
+ case 'checkbox':
224
+ case 'multiple':
225
+ selectOptionType.bindAddButton();
226
+ break;
227
+ }
228
+ }
229
+ }
230
+ },
231
+ addDataToValues : function(data){
232
+
233
+ switch(data.type){
234
+ case 'field':
235
+ case 'area':
236
+ template = OptionTemplateText;
237
+ group = 'text';
238
+ break;
239
+ case 'file':
240
+ template = OptionTemplateFile;
241
+ group = 'file';
242
+ break;
243
+ case 'drop_down':
244
+ case 'radio':
245
+ case 'checkbox':
246
+ case 'multiple':
247
+ template = OptionTemplateSelect;
248
+ group = 'select';
249
+ break;
250
+ case 'date':
251
+ case 'date_time':
252
+ case 'time':
253
+ template = OptionTemplateDate;
254
+ group = 'date';
255
+ break;
256
+ }
257
+
258
+ $('<?php echo $this->getFieldId() ?>_'+data.id+'_previous_group').value = group;
259
+
260
+ template = '<div id="<?php echo $this->getFieldId() ?>_{{id}}_type_'+group+'" class="grid tier form-list">'+template+'</div><div id="<?php echo $this->getFieldId() ?>_{{id}}_type_'+group+'_advice"></div>';
261
+
262
+ this.secondTemplate = new Template(template, this.templateSyntax);
263
+
264
+ Element.insert($('<?php echo $this->getFieldId() ?>_'+data.option_id), {'after':this.secondTemplate.evaluate(data)});
265
+
266
+ if (data.checkboxScopePrice) {
267
+ //set disabled
268
+ if ($('<?php echo $this->getFieldId() ?>_'+data.option_id+'_price') && data.scopePriceDisabled) {
269
+ $('<?php echo $this->getFieldId() ?>_'+data.option_id+'_price').disable();
270
+ $('<?php echo $this->getFieldId() ?>_'+data.option_id+'_price_type').disable();
271
+ }
272
+ }
273
+
274
+ switch(data.type){
275
+ case 'drop_down':
276
+ case 'radio':
277
+ case 'checkbox':
278
+ case 'multiple':
279
+ data.optionValues.each(function(value) {
280
+ selectOptionType.add(value);
281
+ });
282
+ selectOptionType.bindAddButton();
283
+ break;
284
+ }
285
+
286
+ if (data.price_type) {
287
+ $A($('<?php echo $this->getFieldId() ?>_'+data.option_id+'_price_type').options).each(function(option){
288
+ if (option.value==data.price_type) option.selected = true;
289
+ });
290
+ }
291
+
292
+ showHideConfigureValidatorsButtons();
293
+
294
+ },
295
+ bindSelectInputType : function(){
296
+ var types = $$('.select-product-option-type');
297
+ for(var i=0;i<types.length;i++){
298
+ if(!$(types[i]).binded){
299
+ $(types[i]).binded = true;
300
+ Event.observe(types[i], 'change', function(event){
301
+ productOptionType.loadStepTwo(event);
302
+ showHideConfigureValidatorsButtons();
303
+ });
304
+ }
305
+ }
306
+ }
307
+ }
308
+
309
+ var productOptionScope = {
310
+ addScope : function(event){
311
+ var element = $(Event.element(event));
312
+ fieldToDisable = $(element.readAttribute('id').sub('_use_default', ''));
313
+
314
+ if (fieldToDisable.disabled) {
315
+ if (fieldToDisable.hasClassName('product-option-price')) {//need change to cheking value of element
316
+ $(fieldToDisable.readAttribute('id')+'_type').enable();
317
+ }
318
+ fieldToDisable.enable();
319
+ } else {
320
+ if (fieldToDisable.hasClassName('product-option-price')) {//need change to cheking value of element
321
+ $(fieldToDisable.readAttribute('id')+'_type').disable();
322
+ }
323
+ fieldToDisable.disable();
324
+ }
325
+ },
326
+ bindScopeCheckbox : function(){
327
+ var checkboxes = $$('.product-option-scope-checkbox');
328
+ for (var i=0;i<checkboxes.length;i++) {
329
+ if (!$(checkboxes[i]).binded) {
330
+ $(checkboxes[i]).binded = true;
331
+ Event.observe(checkboxes[i], 'click', this.addScope.bind(this));
332
+ }
333
+ }
334
+ }
335
+ }
336
+
337
+ if($('option_panel')){
338
+ $('option_panel').remove();
339
+ }
340
+
341
+ productOption.bindRemoveButtons();
342
+
343
+ if($('<?php echo $this->getAddButtonId() ?>')){
344
+ Event.observe('<?php echo $this->getAddButtonId() ?>', 'click', productOption.add.bind(productOption));
345
+ }
346
+
347
+ //validation for selected input type
348
+ Validation.addAllThese([
349
+ ['required-option-select', <?php echo $this->helper('core')->jsonEncode(Mage::helper('catalog')->__('Select type of option')) ?>, function(v, elm) {
350
+ if (elm.getValue() == '') {
351
+ return false;
352
+ }
353
+ return true;
354
+ }]]);
355
+
356
+ //adding data to templates
357
+ <?php foreach ($this->getOptionValues() as $_value): ?>
358
+ productOption.add(<?php echo $_value->toJson() ?>);
359
+ productOptionType.addDataToValues(<?php echo $_value->toJson() ?>);
360
+ <?php endforeach; ?>
361
+
362
+ //bind scope checkboxes
363
+ productOptionScope.bindScopeCheckbox();
364
+ //]]>
365
+ </script>
366
+
367
+ <div><?php if (!$this->isReadonly()):?><input type="hidden" name="affect_product_custom_options" value="1" /><?php endif;?></div>
app/design/adminhtml/default/default/template/rocketweb_cov/adminhtml/validators.phtml ADDED
@@ -0,0 +1,5 @@
 
 
 
 
 
1
+ <div id="popup-window-mask" style="display:none;"></div>
2
+ <script type="text/javascript">
3
+ window.rwvalidators = new CustomOptionValidatorHolder(<?php echo $this->getValidatorsInGroups();?>);
4
+ </script>
5
+
app/design/frontend/base/default/template/catalog/product/view/options/type/text.phtml ADDED
@@ -0,0 +1,41 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Magento
4
+ *
5
+ * NOTICE OF LICENSE
6
+ *
7
+ * This source file is subject to the Academic Free License (AFL 3.0)
8
+ * that is bundled with this package in the file LICENSE_AFL.txt.
9
+ * It is also available through the world-wide-web at this URL:
10
+ * http://opensource.org/licenses/afl-3.0.php
11
+ * If you did not receive a copy of the license and are unable to
12
+ * obtain it through the world-wide-web, please send an email
13
+ * to license@magentocommerce.com so we can send you a copy immediately.
14
+ *
15
+ * DISCLAIMER
16
+ *
17
+ * Do not edit or add to this file if you wish to upgrade Magento to newer
18
+ * versions in the future. If you wish to customize Magento for your
19
+ * needs please refer to http://www.magentocommerce.com for more information.
20
+ *
21
+ * @category design
22
+ * @package base_default
23
+ * @copyright Copyright (c) 2012 Magento Inc. (http://www.magentocommerce.com)
24
+ * @license http://opensource.org/licenses/afl-3.0.php Academic Free License (AFL 3.0)
25
+ */
26
+ ?>
27
+ <?php $_option = $this->getOption(); ?>
28
+ <dt><label<?php if ($_option->getIsRequire()) echo ' class="required"' ?>><?php if ($_option->getIsRequire()) echo '<em>*</em>' ?><?php echo $this->htmlEscape($_option->getTitle()) ?></label>
29
+ <?php echo $this->getFormatedPrice() ?></dt>
30
+ <dd<?php if ($_option->decoratedIsLast){?> class="last"<?php }?>>
31
+ <div class="input-box">
32
+ <?php if ($_option->getType() == Mage_Catalog_Model_Product_Option::OPTION_TYPE_FIELD): ?>
33
+ <input type="text" onchange="opConfig.reloadPrice()" id="options_<?php echo $_option->getId() ?>_text" class="<?php echo $_option->getValidators()?> input-text<?php echo $_option->getIsRequire() ? ' required-entry' : '' ?> <?php echo $_option->getMaxCharacters() ? ' validate-length maximum-length-'.$_option->getMaxCharacters() : '' ?> product-custom-option" name="options[<?php echo $_option->getId() ?>]" value="<?php echo $this->escapeHtml($this->getDefaultValue()) ?>" />
34
+ <?php elseif ($_option->getType() == Mage_Catalog_Model_Product_Option::OPTION_TYPE_AREA): ?>
35
+ <textarea id="options_<?php echo $_option->getId() ?>_text" onchange="opConfig.reloadPrice()" class="<?php echo $_option->getValidators()?> <?php echo $_option->getIsRequire() ? ' required-entry' : '' ?> <?php echo $_option->getMaxCharacters() ? ' validate-length maximum-length-'.$_option->getMaxCharacters() : '' ?> product-custom-option" name="options[<?php echo $_option->getId() ?>]" rows="5" cols="25"><?php echo $this->escapeHtml($this->getDefaultValue()) ?></textarea>
36
+ <?php endif; ?>
37
+ <?php if ($_option->getMaxCharacters()): ?>
38
+ <p class="note"><?php echo Mage::helper('catalog')->__('Maximum number of characters:')?> <strong><?php echo $_option->getMaxCharacters() ?></strong></p>
39
+ <?php endif; ?>
40
+ </div>
41
+ </dd>
app/etc/modules/RocketWeb_All.xml ADDED
@@ -0,0 +1,9 @@
 
 
 
 
 
 
 
 
 
1
+ <?xml version="1.0"?>
2
+ <config>
3
+ <modules>
4
+ <RocketWeb_All>
5
+ <active>true</active>
6
+ <codePool>community</codePool>
7
+ </RocketWeb_All>
8
+ </modules>
9
+ </config>
app/etc/modules/RocketWeb_CustomOptionValidator.xml ADDED
@@ -0,0 +1,9 @@
 
 
 
 
 
 
 
 
 
1
+ <?xml version="1.0"?>
2
+ <config>
3
+ <modules>
4
+ <RocketWeb_CustomOptionValidator>
5
+ <active>true</active>
6
+ <codePool>community</codePool>
7
+ </RocketWeb_CustomOptionValidator>
8
+ </modules>
9
+ </config>
js/rocketweb/adminhtml/custom_option_validation.js ADDED
@@ -0,0 +1,323 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ function showValidatorsPopup(id,limitX,limitY) {
2
+ element = $(id);
3
+
4
+ var elementDims = element.getDimensions();
5
+ var viewPort = document.viewport.getDimensions();
6
+ var offsets = document.viewport.getScrollOffsets();
7
+ var centerX = viewPort.width / 2 + offsets.left - elementDims.width / 2;
8
+ var centerY = viewPort.height / 2 + offsets.top - elementDims.height / 2;
9
+ if ( limitX && centerX < limitX )
10
+ {
11
+ centerX = parseInt(limitX);
12
+ }
13
+ if ( limitY && centerY < limitY )
14
+ {
15
+ centerY = parseInt(limitY);
16
+ }
17
+
18
+
19
+ element.setStyle( { position: 'absolute', top: Math.floor(centerY) + 'px', left: Math.floor(centerX) + 'px' } ).show();
20
+ $('popup-window-mask').onclick = function(){hideValidatorsPopup(id);}
21
+ $('popup-window-mask').setStyle({
22
+ height: $('html-body').getHeight() + 'px'
23
+ }).show();
24
+
25
+ }
26
+
27
+
28
+ function hideValidatorsPopup(id) {
29
+ $(id).hide();
30
+ $(id).down('.popup-content').update('');
31
+ $('popup-window-mask').hide();
32
+ }
33
+
34
+ function submitValidatorsPopup(id) {
35
+ if(window.rwvalidators.validate()) {
36
+ window.rwvalidators.serializeCustomOptions();
37
+ hideValidatorsPopup(id);
38
+ }
39
+ }
40
+
41
+
42
+ var CustomOptionValidator = Class.create({
43
+ initialize: function(id, options) {
44
+ this.id = id;
45
+ this.options = options;
46
+ },
47
+ getExtraFieldId: function(extra_field_id,extra_field_data) {
48
+ if(this.options.extra.combined_prefix) {
49
+ return this.id+'-extra-field-'+extra_field_id;
50
+ }
51
+ else {
52
+ return this.id+'-extra-field-'+extra_field_data.prefix;
53
+ }
54
+ },
55
+ getHtml: function(inputType) {
56
+ validForInputType = false;
57
+ for(k=0;k<this.options.for_types.length;k++) {
58
+ if(this.options.for_types[k] == inputType) {
59
+ validForInputType = true;
60
+ break;
61
+ }
62
+ }
63
+
64
+ if(validForInputType) {
65
+ html = new Element('div',{'class':'validator-container validator-'+this.id});
66
+ html.insert(new Element('input',{'type':'checkbox','name':'custom_validator[]','value':this.id,'id':this.id,'class':'validator-checkbox'}))
67
+ html.insert(new Element('label',{'for':this.id}).update(this.options.title));
68
+
69
+ if(this.options.extra) {
70
+ for(var extra_id in this.options.extra.elements) {
71
+ if(this.options.extra.elements.hasOwnProperty(extra_id)) {
72
+ label = new Element('label',{'class':'extra-field-label','for' : this.getExtraFieldId(extra_id,this.options.extra.elements[extra_id])}).update(this.options.extra.elements[extra_id].label);
73
+ element = new Element('input',{ 'type':'text',
74
+ 'style':this.options.extra.elements[extra_id].style,
75
+ 'class':this.getExtraFieldId(extra_id,this.options.extra.elements[extra_id])+' extra-field',
76
+ 'id' : this.getExtraFieldId(extra_id,this.options.extra.elements[extra_id])
77
+ });
78
+ html.insert(label);
79
+ html.insert(element);
80
+ }
81
+ }
82
+ }
83
+
84
+ if(this.options.description) {
85
+ html.insert(new Element('p',{'class':'note'}).update(this.options.description))
86
+ }
87
+ return html;
88
+ }
89
+ else {
90
+ return '';
91
+ }
92
+ }
93
+ });
94
+
95
+ var CustomOptionValidatorGroup = Class.create({
96
+ initialize: function(group_name) {
97
+ this.group_name = group_name;
98
+ this.validators = new Array();
99
+ },
100
+
101
+ addValidator: function(validator) {
102
+ this.validators.push(validator);
103
+ },
104
+ getHtmlHeader: function(inputType) {
105
+ return new Element('dt',{'class':'validation-header'}).insert(new Element('a',{'href':'#'}).update(this.group_name));
106
+ return html;
107
+ },
108
+ getHtmlContent: function(inputType) {
109
+ content= new Element('dd');
110
+ validatorCount = 0;
111
+ for(j=0;j<this.validators.length;j++) {
112
+ validatorHtml = this.validators[j].getHtml(inputType);
113
+ if(validatorHtml) {
114
+ validatorCount++;
115
+ content.insert(validatorHtml);
116
+ }
117
+ }
118
+ if(validatorCount) {
119
+ return content;
120
+ }
121
+ else {
122
+ return '';
123
+ }
124
+ }
125
+
126
+ });
127
+
128
+ currentPopupId = '';
129
+ var CustomOptionValidatorHolder = Class.create({
130
+ initialize: function(validator_data) {
131
+ this.groups = new Array();
132
+ for(var group_name in validator_data) {
133
+ if(validator_data.hasOwnProperty(group_name)) {
134
+ group = new CustomOptionValidatorGroup(group_name);
135
+
136
+ for(var validator_id in validator_data[group_name]) {
137
+ if(validator_data[group_name].hasOwnProperty(validator_id)) {
138
+ validator = new CustomOptionValidator(validator_id, validator_data[group_name][validator_id]);
139
+ group.addValidator(validator);
140
+ }
141
+ }
142
+
143
+ this.groups.push(group);
144
+ }
145
+ }
146
+ },
147
+
148
+ populateValidatorPopup: function(id_part) {
149
+ this.id_part = id_part;
150
+ that = this;
151
+ currentPopupId = 'validators_'+id_part;
152
+
153
+ //create groups & checkboxes
154
+ validatorsDivContent = $(currentPopupId).down('.popup-content');
155
+ validatorsDivContent.update('');
156
+ inputType = $(id_part+'_type').options[$(id_part+'_type').selectedIndex].value;
157
+
158
+ hasContent = false;
159
+ for(i=0;i<this.groups.length;i++) {
160
+ content = this.groups[i].getHtmlContent(inputType);
161
+ if(content) {
162
+ hasContent = true;
163
+ validatorsDivContent.insert(this.groups[i].getHtmlHeader(inputType));
164
+ validatorsDivContent.insert(content);
165
+ }
166
+ }
167
+ if(hasContent) {
168
+ //listen to onclick events & populate the hidden field
169
+
170
+ accordion = new varienAccordion('validators_'+id_part, false);
171
+
172
+ //check selected values, populate extra fields & open accordions
173
+
174
+ selectedOptions = $('custom_validators_'+id_part).value.split(' ');
175
+ if(selectedOptions.length) {
176
+ for(i1=0;i1<selectedOptions.length;i1++) {
177
+ selectedOption = selectedOptions[i1];
178
+ $$('#validators_'+id_part+' .validator-checkbox').each(function(el){
179
+ if(el.value == selectedOption) {
180
+ el.checked = true;
181
+ validator = that.getValidatorForCheckboxId(el.id);
182
+ if(validator.options.extra) {
183
+ if(validator.options.extra.combined_prefix) {
184
+ prefix = validator.options.extra.prefix;
185
+ for(j1=0;j1<selectedOptions.length;j1++) {
186
+ if(selectedOptions[j1].indexOf(prefix) == 0) {
187
+ range = selectedOptions[j1].replace(prefix+'-','');
188
+ range = range.split('-');
189
+ currentPos = 0;
190
+ $$('#'+currentPopupId+' .validator-'+validator.id+' .extra-field').each(function(element){
191
+ element.value=range[currentPos];
192
+ currentPos++;
193
+ })
194
+ }
195
+ }
196
+ }
197
+ else {
198
+ for(var element_id in validator.options.extra.elements) {
199
+ if(validator.options.extra.elements.hasOwnProperty(element_id)) {
200
+ for(j1=0;j1<selectedOptions.length;j1++) {
201
+ if(selectedOptions[j1].indexOf(validator.options.extra.elements[element_id].prefix) != -1) {
202
+ elementValue = selectedOptions[j1].replace(validator.options.extra.elements[element_id].prefix+'-','');
203
+ $$('#'+currentPopupId+' #'+validator.getExtraFieldId(element_id,validator.options.extra.elements[element_id]))[0].value = elementValue;
204
+ }
205
+ }
206
+ }
207
+ }
208
+ }
209
+ }
210
+
211
+ accordion.showItem(el.up().up().previous());
212
+ }
213
+ });
214
+ }
215
+ }
216
+
217
+
218
+ }
219
+ else {
220
+ validatorsDivContent.insert(new Element('p',{'class':'no-validators'}).update('Validators are available only for text fields and text areas'));
221
+ }
222
+
223
+
224
+ },
225
+
226
+ getValidatorForCheckboxId: function(checkbox_id) {
227
+ for(i=0;i<this.groups.length;i++) {
228
+ for(j=0;j<this.groups[i].validators.length;j++) {
229
+ if(this.groups[i].validators[j].id == checkbox_id) {
230
+ return this.groups[i].validators[j];
231
+ }
232
+ }
233
+ }
234
+ } ,
235
+
236
+ validate: function() {
237
+ that = this;
238
+ hasErrors = false;
239
+ $$('#'+currentPopupId+' .validator-checkbox').each(function(el){
240
+ if(el.checked) {
241
+ validatorObject = that.getValidatorForCheckboxId(el.id);
242
+ if(validatorObject.options.extra) {
243
+ for(var extra_id in validatorObject.options.extra.elements) {
244
+ if(validatorObject.options.extra.elements.hasOwnProperty(extra_id)) {
245
+ extraFieldId = validatorObject.getExtraFieldId(extra_id,validatorObject.options.extra.elements[extra_id]);
246
+ extraFieldValue = parseInt($$('#'+currentPopupId+' #'+extraFieldId)[0].value);
247
+ $(extraFieldId).removeClassName('error-required');
248
+ if(validatorObject.options.extra.elements[extra_id].required && !extraFieldValue) {
249
+ $(extraFieldId).addClassName('error-required');
250
+ hasErrors = true;
251
+ }
252
+ }
253
+ }
254
+ }
255
+ }
256
+ })
257
+ if(hasErrors) {
258
+ alert("Please fill in all the required fields");
259
+ return false;
260
+ }
261
+ else {
262
+ return true;
263
+ }
264
+ },
265
+
266
+ serializeCustomOptions: function() {
267
+ that = this;
268
+ selectedOptions = '';
269
+ $$('#'+currentPopupId+' .validator-checkbox').each(function(el){
270
+ if(el.checked) {
271
+ selectedOptions+=el.value+' ';
272
+
273
+ //get extra values, if any
274
+ validatorObject = that.getValidatorForCheckboxId(el.id);
275
+ if(validatorObject.options.extra) {
276
+ value = '';
277
+ if(validatorObject.options.extra.combined_prefix) {
278
+ value = validatorObject.options.extra.prefix;
279
+ }
280
+ for(var extra_id in validatorObject.options.extra.elements) {
281
+ if(validatorObject.options.extra.elements.hasOwnProperty(extra_id)) {
282
+ extraFieldId = validatorObject.getExtraFieldId(extra_id,validatorObject.options.extra.elements[extra_id]);
283
+ extraFieldValue = parseInt($$('#'+currentPopupId+' #'+extraFieldId)[0].value);
284
+ if(validatorObject.options.extra.combined_prefix) {
285
+ if(isNaN(extraFieldValue)) {
286
+ extraFieldValue = 0;
287
+ }
288
+ value+='-'+extraFieldValue;
289
+ }
290
+ else {
291
+ if(!isNaN(extraFieldValue)) {
292
+ value = validatorObject.options.extra.elements[extra_id].prefix+'-'+extraFieldValue;
293
+ selectedOptions+=value+' ';
294
+ }
295
+ }
296
+ }
297
+ }
298
+ if(validatorObject.options.extra.combined_prefix) {
299
+ selectedOptions+=value+' ';
300
+ }
301
+ }
302
+ }
303
+ $('custom_validators_'+that.id_part).value = selectedOptions;
304
+ });
305
+ }
306
+ });
307
+
308
+
309
+ function showHideConfigureValidatorsButtons() {
310
+ $$('.select-product-option-type').each(function(el){
311
+ selectedOption = el.options[el.selectedIndex].value;
312
+ buttonId = el.id+'_cfg_button';
313
+ if(selectedOption == 'field' || selectedOption == 'area') {
314
+ $(buttonId).show();
315
+ }
316
+ else {
317
+ $(buttonId).hide();
318
+ }
319
+ });
320
+ }
321
+
322
+
323
+
package.xml ADDED
@@ -0,0 +1,18 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?xml version="1.0"?>
2
+ <package>
3
+ <name>RocketWeb_CustomOptionValidator</name>
4
+ <version>1.0.0</version>
5
+ <stability>stable</stability>
6
+ <license uri="http://www.opensource.org/licenses/osl-3.0.php">OSL v3.0</license>
7
+ <channel>community</channel>
8
+ <extends/>
9
+ <summary>Add validation to custom product options</summary>
10
+ <description>This module brings the power of Magento's form validation to the custom product options</description>
11
+ <notes>Initial release</notes>
12
+ <authors><author><name>RocketWeb</name><user>rocketweb</user><email>dev@rocketweb.com</email></author></authors>
13
+ <date>2012-12-12</date>
14
+ <time>10:27:20</time>
15
+ <contents><target name="magecommunity"><dir name="RocketWeb"><dir name="CustomOptionValidator"><dir name="Block"><dir name="Adminhtml"><file name="Validators.php" hash="a7348ceed96b90cf6f1ef7ac11d0792b"/></dir><dir name="Rewrite"><dir name="Adminhtml"><dir name="Catalog"><dir name="Product"><dir name="Edit"><dir name="Tab"><dir name="Options"><file name="Option.php" hash="794d415489e3530637626d46bad2cd6e"/></dir></dir></dir></dir></dir></dir></dir></dir><dir name="Helper"><file name="Data.php" hash="877e3b10b9b744d2d5c9a9fcb8844616"/></dir><dir name="Model"><dir name="Validator"><file name="List.php" hash="d17083cfc6094e8b25200d0144257f4e"/><file name="Type.php" hash="f2bbc9696d79d9ff7c487a8b134e071f"/></dir><file name="Validator.php" hash="4b48a10956b1c1ba2f4c7e3761c12213"/></dir><dir name="etc"><file name="config.xml" hash="5f7a4e6639c7f3f3dbb12f7db1219720"/></dir><dir name="sql"><dir name="rocketweb_cov_setup"><file name="mysql4-install-1.0.0.php" hash="fd2d5b23ed0339f12d07c67b99f0582c"/></dir></dir></dir><dir name="All"><dir name="Helper"><file name="Data.php" hash="e6dbd2a24db3d4d7861ef1c147c1fa76"/></dir><dir name="Model"><file name="Feed.php" hash="8e6a50942b3d1e5837a5ea989b9ef490"/><file name="Observer.php" hash="f6a9c8853b162372d9ed6c6bf7e3f86c"/></dir><dir name="etc"><file name="adminhtml.xml" hash="4fd75eb093ed58499256b0104018d523"/><file name="config.xml" hash="f0f72a5904f611a6c8e6d9c6cb074a5b"/><file name="system.xml" hash="90913e8ae8134bbe09c0f0a6552ff395"/></dir></dir></dir></target><target name="mageetc"><dir name="modules"><file name="RocketWeb_CustomOptionValidator.xml" hash="f1ce6a52c27861a4d544f357c2e8dc84"/><file name="RocketWeb_All.xml" hash="b1c635dc428097a7fca6c9a1da0b7e04"/></dir></target><target name="magedesign"><dir name="adminhtml"><dir name="default"><dir name="default"><dir name="layout"><file name="rocketweb_cov.xml" hash="9ac2f2898b730b38fedc376e25d84adf"/></dir><dir name="template"><dir name="catalog"><dir name="product"><dir name="edit"><dir name="options"><file name="option.phtml" hash="d0c9f251ac43ad7ef2ee69dec9b2bcfa"/></dir></dir></dir></dir><dir name="rocketweb_cov"><dir name="adminhtml"><file name="validators.phtml" hash="2f356f2ba5d7076985f85155168dba70"/></dir></dir></dir></dir></dir></dir><dir name="frontend"><dir name="base"><dir name="default"><dir name="template"><dir name="catalog"><dir name="product"><dir name="view"><dir name="options"><dir name="type"><file name="text.phtml" hash="524b03911b5e9766923784ba1cacb2e0"/></dir></dir></dir></dir></dir></dir></dir></dir></dir></target><target name="mageskin"><dir name="adminhtml"><dir name="default"><dir name="default"><dir name="rocketweb"><dir name="adminhtml"><file name="custom_option_validation.css" hash="b68a2e4596cff3260ae614bc7c1060be"/></dir></dir></dir></dir></dir></target><target name="mageweb"><dir name="js"><dir name="rocketweb"><dir name="adminhtml"><file name="custom_option_validation.js" hash="5b6afe6a66c384ca2227a8c7ccf6c936"/></dir></dir></dir></target></contents>
16
+ <compatible/>
17
+ <dependencies><required><php><min>4.2.0</min><max>6.0.0</max></php></required></dependencies>
18
+ </package>
skin/adminhtml/default/default/rocketweb/adminhtml/custom_option_validation.css ADDED
@@ -0,0 +1,17 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ .custom-option-validator-popup {z-index:999;position:absolute;background-color:#FAFAFA;padding-bottom:10px;width:400px;border:1px solid #D6D6D6; }
2
+ .custom-option-validator-popup .header {background: #6F8992;padding: 2px 10px;color:white;text-align:left;font-weight:bold;}
3
+ .custom-option-validator-popup .popup-content {margin-bottom:20px;padding:10px;}
4
+ .custom-option-validator-popup .popup-content dt { color:white;font-weight:bold;}
5
+ .custom-option-validator-popup .popup-content dt a {display:block;width:100%;}
6
+ .custom-option-validator-popup .popup-content dd {padding-bottom:15px;}
7
+ .custom-option-validator-popup .popup-content dd .validator-container {padding-left:10px;padding-right:10px;}
8
+ .custom-option-validator-popup .popup-content dd .validator-container .validator-checkbox {margin-right:5px;}
9
+ .custom-option-validator-popup .popup-content dd .validator-container .note {font-size:10px;line-height:11px;}
10
+ .custom-option-validator-popup .popup-content .no-validators {padding:10px;padding-bottom:0px;}
11
+ .custom-option-validator-popup .popup-content .buttons-set {margin-bottom:0px;}
12
+ .custom-option-validator-popup .popup-content .extra-field-label {margin-left:10px;font-size:11px;margin-right:5px;}
13
+ .custom-option-validator-popup .popup-content .extra-field {font-size:11px;height:12px;line-height:12px;}
14
+ .custom-option-validator-popup .close {background: url('../../images/dashboard-close.gif') no-repeat;height:13px;width:13px;display:block;float:right;position:relative;top:2px;right:-7px;}
15
+ .custom-option-validator-popup .error-required {border: 1px solid red;}
16
+
17
+