Blog4mails - Version 1.0.0

Version Notes

Custom Product Design Tools, No Support Provided

Download this release

Release Info

Developer blg4mail.com
Extension Blog4mails
Version 1.0.0
Comparing to
See all releases


Version 1.0.0

Files changed (248) hide show
  1. app/code/community/Blog4mail/Customproduct/Block/Customproduct.php +17 -0
  2. app/code/community/Blog4mail/Customproduct/Helper/Data.php +6 -0
  3. app/code/community/Blog4mail/Customproduct/Model/Customproduct.php +10 -0
  4. app/code/community/Blog4mail/Customproduct/Model/Mysql4/Customproduct.php +10 -0
  5. app/code/community/Blog4mail/Customproduct/Model/Mysql4/Customproduct/Collection.php +10 -0
  6. app/code/community/Blog4mail/Customproduct/Model/Status.php +15 -0
  7. app/code/community/Blog4mail/Customproduct/controllers/IndexController.php +617 -0
  8. app/code/community/Blog4mail/Customproduct/controllers/IndexController.php~ +617 -0
  9. app/code/community/Blog4mail/Customproduct/etc/config.xml +72 -0
  10. app/code/community/Blog4mail/Customproduct/etc/config.xml~ +72 -0
  11. app/code/community/Blog4mail/Customproduct/sql/customproduct_setup/mysql4-install-1.0.0.php +52 -0
  12. app/code/community/Blog4mail/Customproduct/sql/customproduct_setup/mysql4-install-1.0.0.php~ +52 -0
  13. app/code/community/Blog4mail/Customproduct/sql/customproduct_setup/mysql4-install-1.0.php~ +52 -0
  14. app/code/community/Blog4mail/Customproduct/sql/customproduct_setup/mysql4-upgrade-1.0-1.1.php~ +27 -0
  15. app/code/community/Blog4mail/Customproduct/sql/customproduct_setup/mysql4-upgrade-1.3.4-1.4.php~ +34 -0
  16. app/code/community/Blog4mail/Customproductadmin/Block/Customproduct.php +12 -0
  17. app/code/community/Blog4mail/Customproductadmin/Block/Customproduct/Edit.php +45 -0
  18. app/code/community/Blog4mail/Customproductadmin/Block/Customproduct/Edit/Form.php +19 -0
  19. app/code/community/Blog4mail/Customproductadmin/Block/Customproduct/Edit/Tab/Form.php +58 -0
  20. app/code/community/Blog4mail/Customproductadmin/Block/Customproduct/Edit/Tabs.php +24 -0
  21. app/code/community/Blog4mail/Customproductadmin/Block/Customproduct/Grid.php +116 -0
  22. app/code/community/Blog4mail/Customproductadmin/Helper/Data.php +6 -0
  23. app/code/community/Blog4mail/Customproductadmin/controllers/CustomproductController.php +214 -0
  24. app/code/community/Blog4mail/Customproductadmin/etc/config.xml +68 -0
  25. app/code/community/Blog4mail/customproduct_catalog.xml~ +93 -0
  26. app/design/frontend/base/default/layout/customproduct_catalog.xml +252 -0
  27. app/design/frontend/base/default/template/catalog/product/view/media_custom.phtml +115 -0
  28. app/design/frontend/base/default/template/catalog/product/view_custom.phtml +635 -0
  29. app/etc/modules/Blog4mail_Customproduct.xml +9 -0
  30. media/finalimages/2b0e7ecb7dffaca13b2be8c6f4e5f89e.jpg +0 -0
  31. media/finalimages/46c4f93a056c2e11c45c301a0dda1da4.jpg +0 -0
  32. media/finalimages/8605d98db258cb59cd4a0bc5e1374104.jpg +0 -0
  33. media/finalimages/upload/50ef9eafe2774image1.jpeg +0 -0
  34. media/finalimages/upload/50ef9ef6b49aeimage1.jpeg +0 -0
  35. media/finalimages/upload/50ef9fa951afcimage1.jpeg +0 -0
  36. media/finalimages/upload/50efa5be9c0a0image1.jpeg +0 -0
  37. media/finalimages/upload/50f4f56c28bfdimage1.jpeg +0 -0
  38. media/finalimages/upload/50f4f56caf383image1.jpeg +0 -0
  39. media/finalimages/upload/50f4f5e7aa803image1.jpeg +0 -0
  40. media/finalimages/upload/50f4f71c53eecimage1.jpeg +0 -0
  41. package.xml +25 -0
  42. skin/frontend/default/customproduct/css/oauth-simple.css +239 -0
  43. skin/frontend/default/customproduct/css/print.css +40 -0
  44. skin/frontend/default/customproduct/css/styles-ie.css +149 -0
  45. skin/frontend/default/customproduct/css/styles.css +1788 -0
  46. skin/frontend/default/customproduct/favicon.ico +0 -0
  47. skin/frontend/default/customproduct/images/addtext.png +0 -0
  48. skin/frontend/default/customproduct/images/best_selling_tr_even_bg.gif +0 -0
  49. skin/frontend/default/customproduct/images/best_selling_tr_odd_bg.gif +0 -0
  50. skin/frontend/default/customproduct/images/bgimage.png +0 -0
  51. skin/frontend/default/customproduct/images/bgimage7.png +0 -0
  52. skin/frontend/default/customproduct/images/bkg_account_box.gif +0 -0
  53. skin/frontend/default/customproduct/images/bkg_block-actions.gif +0 -0
  54. skin/frontend/default/customproduct/images/bkg_block-currency.gif +0 -0
  55. skin/frontend/default/customproduct/images/bkg_block-layered-dd.gif +0 -0
  56. skin/frontend/default/customproduct/images/bkg_block-layered-dt.gif +0 -0
  57. skin/frontend/default/customproduct/images/bkg_block-layered-label.gif +0 -0
  58. skin/frontend/default/customproduct/images/bkg_block-layered-li.gif +0 -0
  59. skin/frontend/default/customproduct/images/bkg_block-layered-title.gif +0 -0
  60. skin/frontend/default/customproduct/images/bkg_block-layered1.gif +0 -0
  61. skin/frontend/default/customproduct/images/bkg_block-title-account.gif +0 -0
  62. skin/frontend/default/customproduct/images/bkg_block-title.gif +0 -0
  63. skin/frontend/default/customproduct/images/bkg_body.gif +0 -0
  64. skin/frontend/default/customproduct/images/bkg_buttons-set1.gif +0 -0
  65. skin/frontend/default/customproduct/images/bkg_checkout.gif +0 -0
  66. skin/frontend/default/customproduct/images/bkg_collapse-gm.gif +0 -0
  67. skin/frontend/default/customproduct/images/bkg_collapse.gif +0 -0
  68. skin/frontend/default/customproduct/images/bkg_divider1.gif +0 -0
  69. skin/frontend/default/customproduct/images/bkg_form-search.gif +0 -0
  70. skin/frontend/default/customproduct/images/bkg_grand-total.gif +0 -0
  71. skin/frontend/default/customproduct/images/bkg_grid.gif +0 -0
  72. skin/frontend/default/customproduct/images/bkg_header.jpg +0 -0
  73. skin/frontend/default/customproduct/images/bkg_login-box.gif +0 -0
  74. skin/frontend/default/customproduct/images/bkg_main1.gif +0 -0
  75. skin/frontend/default/customproduct/images/bkg_main2.gif +0 -0
  76. skin/frontend/default/customproduct/images/bkg_nav0.jpg +0 -0
  77. skin/frontend/default/customproduct/images/bkg_nav1.gif +0 -0
  78. skin/frontend/default/customproduct/images/bkg_nav2.gif +0 -0
  79. skin/frontend/default/customproduct/images/bkg_opc-title-off.gif +0 -0
  80. skin/frontend/default/customproduct/images/bkg_pipe1.gif +0 -0
  81. skin/frontend/default/customproduct/images/bkg_pipe2.gif +0 -0
  82. skin/frontend/default/customproduct/images/bkg_pipe3.gif +0 -0
  83. skin/frontend/default/customproduct/images/bkg_product-view.gif +0 -0
  84. skin/frontend/default/customproduct/images/bkg_product_collateral.gif +0 -0
  85. skin/frontend/default/customproduct/images/bkg_rating.gif +0 -0
  86. skin/frontend/default/customproduct/images/bkg_sp-methods.gif +0 -0
  87. skin/frontend/default/customproduct/images/bkg_tfoot.gif +0 -0
  88. skin/frontend/default/customproduct/images/bkg_th-v.gif +0 -0
  89. skin/frontend/default/customproduct/images/bkg_th.gif +0 -0
  90. skin/frontend/default/customproduct/images/bkg_toolbar.gif +0 -0
  91. skin/frontend/default/customproduct/images/btn_checkout.gif +0 -0
  92. skin/frontend/default/customproduct/images/btn_edit.gif +0 -0
  93. skin/frontend/default/customproduct/images/btn_gm-close.gif +0 -0
  94. skin/frontend/default/customproduct/images/btn_google_checkout.gif +0 -0
  95. skin/frontend/default/customproduct/images/btn_paypal_checkout.gif +0 -0
  96. skin/frontend/default/customproduct/images/btn_place_order.gif +0 -0
  97. skin/frontend/default/customproduct/images/btn_previous.gif +0 -0
  98. skin/frontend/default/customproduct/images/btn_proceed_to_checkout.gif +0 -0
  99. skin/frontend/default/customproduct/images/btn_proceed_to_checkout_dis.gif +0 -0
  100. skin/frontend/default/customproduct/images/btn_remove.gif +0 -0
  101. skin/frontend/default/customproduct/images/btn_remove2.gif +0 -0
  102. skin/frontend/default/customproduct/images/btn_search.gif +0 -0
  103. skin/frontend/default/customproduct/images/btn_trash.gif +0 -0
  104. skin/frontend/default/customproduct/images/btn_window_close.gif +0 -0
  105. skin/frontend/default/customproduct/images/button1.png +0 -0
  106. skin/frontend/default/customproduct/images/button2.png +0 -0
  107. skin/frontend/default/customproduct/images/button3.png +0 -0
  108. skin/frontend/default/customproduct/images/calendar.gif +0 -0
  109. skin/frontend/default/customproduct/images/catalog/product/placeholder/image.jpg +0 -0
  110. skin/frontend/default/customproduct/images/catalog/product/placeholder/small_image.jpg +0 -0
  111. skin/frontend/default/customproduct/images/catalog/product/placeholder/thumbnail.jpg +0 -0
  112. skin/frontend/default/customproduct/images/cvv.gif +0 -0
  113. skin/frontend/default/customproduct/images/cvv.jpg +0 -0
  114. skin/frontend/default/customproduct/images/fam_book_open.png +0 -0
  115. skin/frontend/default/customproduct/images/free_shipping_callout.jpg +0 -0
  116. skin/frontend/default/customproduct/images/grid-cal.gif +0 -0
  117. skin/frontend/default/customproduct/images/home_left_callout.jpg +0 -0
  118. skin/frontend/default/customproduct/images/home_main_callout.jpg +0 -0
  119. skin/frontend/default/customproduct/images/i_arrow-top.gif +0 -0
  120. skin/frontend/default/customproduct/images/i_asc_arrow.gif +0 -0
  121. skin/frontend/default/customproduct/images/i_availability_only.gif +0 -0
  122. skin/frontend/default/customproduct/images/i_availability_only_arrow.gif +0 -0
  123. skin/frontend/default/customproduct/images/i_block-cart.gif +0 -0
  124. skin/frontend/default/customproduct/images/i_block-currency.gif +0 -0
  125. skin/frontend/default/customproduct/images/i_block-list.gif +0 -0
  126. skin/frontend/default/customproduct/images/i_block-poll.gif +0 -0
  127. skin/frontend/default/customproduct/images/i_block-related.gif +0 -0
  128. skin/frontend/default/customproduct/images/i_block-subscribe.gif +0 -0
  129. skin/frontend/default/customproduct/images/i_block-tags.gif +0 -0
  130. skin/frontend/default/customproduct/images/i_block-viewed.gif +0 -0
  131. skin/frontend/default/customproduct/images/i_block-wishlist.gif +0 -0
  132. skin/frontend/default/customproduct/images/i_desc_arrow.gif +0 -0
  133. skin/frontend/default/customproduct/images/i_discount.gif +0 -0
  134. skin/frontend/default/customproduct/images/i_folder-table.gif +0 -0
  135. skin/frontend/default/customproduct/images/i_ma-info.gif +0 -0
  136. skin/frontend/default/customproduct/images/i_ma-reviews.gif +0 -0
  137. skin/frontend/default/customproduct/images/i_ma-tags.gif +0 -0
  138. skin/frontend/default/customproduct/images/i_msg-error.gif +0 -0
  139. skin/frontend/default/customproduct/images/i_msg-note.gif +0 -0
  140. skin/frontend/default/customproduct/images/i_msg-success.gif +0 -0
  141. skin/frontend/default/customproduct/images/i_notice.gif +0 -0
  142. skin/frontend/default/customproduct/images/i_page1.gif +0 -0
  143. skin/frontend/default/customproduct/images/i_page2.gif +0 -0
  144. skin/frontend/default/customproduct/images/i_pager-next.gif +0 -0
  145. skin/frontend/default/customproduct/images/i_pager-prev.gif +0 -0
  146. skin/frontend/default/customproduct/images/i_print.gif +0 -0
  147. skin/frontend/default/customproduct/images/i_rss-big.png +0 -0
  148. skin/frontend/default/customproduct/images/i_rss.gif +0 -0
  149. skin/frontend/default/customproduct/images/i_search_criteria.gif +0 -0
  150. skin/frontend/default/customproduct/images/i_shipping.gif +0 -0
  151. skin/frontend/default/customproduct/images/i_tag_add.gif +0 -0
  152. skin/frontend/default/customproduct/images/i_tier.gif +0 -0
  153. skin/frontend/default/customproduct/images/i_type_grid.gif +0 -0
  154. skin/frontend/default/customproduct/images/i_type_list.gif +0 -0
  155. skin/frontend/default/customproduct/images/logo.gif +0 -0
  156. skin/frontend/default/customproduct/images/logo_email.gif +0 -0
  157. skin/frontend/default/customproduct/images/logo_print.gif +0 -0
  158. skin/frontend/default/customproduct/images/magnifier_handle.gif +0 -0
  159. skin/frontend/default/customproduct/images/map_popup_arrow.gif +0 -0
  160. skin/frontend/default/customproduct/images/media/404_callout1.jpg +0 -0
  161. skin/frontend/default/customproduct/images/media/404_callout2.jpg +0 -0
  162. skin/frontend/default/customproduct/images/media/about_us_img.jpg +0 -0
  163. skin/frontend/default/customproduct/images/media/best_selling_img01.jpg +0 -0
  164. skin/frontend/default/customproduct/images/media/best_selling_img02.jpg +0 -0
  165. skin/frontend/default/customproduct/images/media/best_selling_img03.jpg +0 -0
  166. skin/frontend/default/customproduct/images/media/best_selling_img04.jpg +0 -0
  167. skin/frontend/default/customproduct/images/media/best_selling_img05.jpg +0 -0
  168. skin/frontend/default/customproduct/images/media/best_selling_img06.jpg +0 -0
  169. skin/frontend/default/customproduct/images/media/cell_phone_landing_banner1.jpg +0 -0
  170. skin/frontend/default/customproduct/images/media/col_left_callout.jpg +0 -0
  171. skin/frontend/default/customproduct/images/media/col_right_callout.jpg +0 -0
  172. skin/frontend/default/customproduct/images/media/electronics_cellphones.jpg +0 -0
  173. skin/frontend/default/customproduct/images/media/electronics_digitalcameras.jpg +0 -0
  174. skin/frontend/default/customproduct/images/media/electronics_laptops.jpg +0 -0
  175. skin/frontend/default/customproduct/images/media/furniture_callout_spot.jpg +0 -0
  176. skin/frontend/default/customproduct/images/media/furnitures_bed_room.jpg +0 -0
  177. skin/frontend/default/customproduct/images/media/furnitures_living_room.jpg +0 -0
  178. skin/frontend/default/customproduct/images/media/head_electronics_cellphones.gif +0 -0
  179. skin/frontend/default/customproduct/images/media/head_electronics_digicamera.gif +0 -0
  180. skin/frontend/default/customproduct/images/media/head_electronics_laptops.gif +0 -0
  181. skin/frontend/default/customproduct/images/media/laptop_callout_mid1.jpg +0 -0
  182. skin/frontend/default/customproduct/images/media/laptop_callout_mid2.jpg +0 -0
  183. skin/frontend/default/customproduct/images/media/laptop_callout_mid3.jpg +0 -0
  184. skin/frontend/default/customproduct/images/media/laptop_callout_spot.jpg +0 -0
  185. skin/frontend/default/customproduct/images/media/shirts_landing_banner1.jpg +0 -0
  186. skin/frontend/default/customproduct/images/np_cart_thumb.gif +0 -0
  187. skin/frontend/default/customproduct/images/np_more_img.gif +0 -0
  188. skin/frontend/default/customproduct/images/np_product_main.gif +0 -0
  189. skin/frontend/default/customproduct/images/np_thumb.gif +0 -0
  190. skin/frontend/default/customproduct/images/np_thumb2.gif +0 -0
  191. skin/frontend/default/customproduct/images/opc-ajax-loader.gif +0 -0
  192. skin/frontend/default/customproduct/images/pager_arrow_left.gif +0 -0
  193. skin/frontend/default/customproduct/images/pager_arrow_right.gif +0 -0
  194. skin/frontend/default/customproduct/images/ph_callout_left_rebel.jpg +0 -0
  195. skin/frontend/default/customproduct/images/ph_callout_left_top.gif +0 -0
  196. skin/frontend/default/customproduct/images/product_zoom_overlay_magnif.gif +0 -0
  197. skin/frontend/default/customproduct/images/slider_bg.gif +0 -0
  198. skin/frontend/default/customproduct/images/slider_btn_zoom_in.gif +0 -0
  199. skin/frontend/default/customproduct/images/slider_btn_zoom_out.gif +0 -0
  200. skin/frontend/default/customproduct/images/spacer.gif +0 -0
  201. skin/frontend/default/customproduct/images/textimage.png +0 -0
  202. skin/frontend/default/customproduct/images/validation_advice_bg.gif +0 -0
  203. skin/frontend/default/customproduct/images/xmlconnect/catalog/category/placeholder/image.jpg +0 -0
  204. skin/frontend/default/customproduct/images/xmlconnect/catalog/category/placeholder/small_image.jpg +0 -0
  205. skin/frontend/default/customproduct/images/xmlconnect/catalog/category/placeholder/thumbnail.jpg +0 -0
  206. skin/frontend/default/customproduct/images/xmlconnect/tab_account.png +0 -0
  207. skin/frontend/default/customproduct/images/xmlconnect/tab_cart.png +0 -0
  208. skin/frontend/default/customproduct/images/xmlconnect/tab_home.png +0 -0
  209. skin/frontend/default/customproduct/images/xmlconnect/tab_more.png +0 -0
  210. skin/frontend/default/customproduct/images/xmlconnect/tab_page.png +0 -0
  211. skin/frontend/default/customproduct/images/xmlconnect/tab_search.png +0 -0
  212. skin/frontend/default/customproduct/images/xmlconnect/tab_shop.png +0 -0
  213. skin/frontend/default/customproduct/js/Uize.Array.Dupes.js +188 -0
  214. skin/frontend/default/customproduct/js/Uize.Array.Order.js +338 -0
  215. skin/frontend/default/customproduct/js/Uize.Array.Sort.js +510 -0
  216. skin/frontend/default/customproduct/js/Uize.Array.Util.js +206 -0
  217. skin/frontend/default/customproduct/js/Uize.Array.js +28 -0
  218. skin/frontend/default/customproduct/js/Uize.Build.All.js +68 -0
  219. skin/frontend/default/customproduct/js/Uize.Build.AuditStrings.js +215 -0
  220. skin/frontend/default/customproduct/js/Uize.Build.AutoScruncher.js +217 -0
  221. skin/frontend/default/customproduct/js/Uize.Build.ModuleInfo.js +104 -0
  222. skin/frontend/default/customproduct/js/Uize.Build.NeatenJsFiles.js +74 -0
  223. skin/frontend/default/customproduct/js/Uize.Build.RunUnitTest.js +41 -0
  224. skin/frontend/default/customproduct/js/Uize.Build.RunUnitTests.js +89 -0
  225. skin/frontend/default/customproduct/js/Uize.Build.Scruncher.js +515 -0
  226. skin/frontend/default/customproduct/js/Uize.Build.ServicesSetup.js +51 -0
  227. skin/frontend/default/customproduct/js/Uize.Build.UpdateCopyrightNotices.js +94 -0
  228. skin/frontend/default/customproduct/js/Uize.Build.Util.js +359 -0
  229. skin/frontend/default/customproduct/js/Uize.Build.js +28 -0
  230. skin/frontend/default/customproduct/js/Uize.Class.Value.js +44 -0
  231. skin/frontend/default/customproduct/js/Uize.Class.js +2288 -0
  232. skin/frontend/default/customproduct/js/Uize.Color.js +1515 -0
  233. skin/frontend/default/customproduct/js/Uize.Color.xCmyk.js +237 -0
  234. skin/frontend/default/customproduct/js/Uize.Color.xHsv.js +223 -0
  235. skin/frontend/default/customproduct/js/Uize.Color.xSvgColors.js +324 -0
  236. skin/frontend/default/customproduct/js/Uize.Color.xUtil.js +720 -0
  237. skin/frontend/default/customproduct/js/Uize.Comm.Ajax.js +108 -0
  238. skin/frontend/default/customproduct/js/Uize.Comm.Iframe.Upload.js +77 -0
  239. skin/frontend/default/customproduct/js/Uize.Comm.Iframe.js +106 -0
  240. skin/frontend/default/customproduct/js/Uize.Comm.Script.js +115 -0
  241. skin/frontend/default/customproduct/js/Uize.Comm.js +518 -0
  242. skin/frontend/default/customproduct/js/Uize.Cookie.js +115 -0
  243. skin/frontend/default/customproduct/js/Uize.Curve.Mod.js +522 -0
  244. skin/frontend/default/customproduct/js/Uize.Curve.Rubber.js +538 -0
  245. skin/frontend/default/customproduct/js/Uize.Curve.js +854 -0
  246. skin/frontend/default/customproduct/js/Uize.Data.Combinations.js +725 -0
  247. skin/frontend/default/customproduct/js/Uize.Data.Csv.js +1190 -0
  248. skin/frontend/default/customproduct/js/Uize.Data.Matches.js +210 -0
app/code/community/Blog4mail/Customproduct/Block/Customproduct.php ADDED
@@ -0,0 +1,17 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ class Blog4mail_Customproduct_Block_Customproduct extends Mage_Core_Block_Template
3
+ {
4
+ public function _prepareLayout()
5
+ {
6
+ return parent::_prepareLayout();
7
+ }
8
+
9
+ public function getCustomproduct()
10
+ {
11
+ if (!$this->hasData('customproduct')) {
12
+ $this->setData('customproduct', Mage::registry('customproduct'));
13
+ }
14
+ return $this->getData('customproduct');
15
+
16
+ }
17
+ }
app/code/community/Blog4mail/Customproduct/Helper/Data.php ADDED
@@ -0,0 +1,6 @@
 
 
 
 
 
 
1
+ <?php
2
+
3
+ class Blog4mail_Customproduct_Helper_Data extends Mage_Core_Helper_Abstract
4
+ {
5
+
6
+ }
app/code/community/Blog4mail/Customproduct/Model/Customproduct.php ADDED
@@ -0,0 +1,10 @@
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ class Blog4mail_Customproduct_Model_Customproduct extends Mage_Core_Model_Abstract
4
+ {
5
+ public function _construct()
6
+ {
7
+ parent::_construct();
8
+ $this->_init('customproduct/customproduct');
9
+ }
10
+ }
app/code/community/Blog4mail/Customproduct/Model/Mysql4/Customproduct.php ADDED
@@ -0,0 +1,10 @@
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ class Blog4mail_Customproduct_Model_Mysql4_Customproduct extends Mage_Core_Model_Mysql4_Abstract
4
+ {
5
+ public function _construct()
6
+ {
7
+ // Note that the customproduct_id refers to the key field in your database table.
8
+ $this->_init('customproduct/customproduct', 'customproduct_id');
9
+ }
10
+ }
app/code/community/Blog4mail/Customproduct/Model/Mysql4/Customproduct/Collection.php ADDED
@@ -0,0 +1,10 @@
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ class Blog4mail_Customproduct_Model_Mysql4_Customproduct_Collection extends Mage_Core_Model_Mysql4_Collection_Abstract
4
+ {
5
+ public function _construct()
6
+ {
7
+ parent::_construct();
8
+ $this->_init('customproduct/customproduct');
9
+ }
10
+ }
app/code/community/Blog4mail/Customproduct/Model/Status.php ADDED
@@ -0,0 +1,15 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ class Blog4mail_Customproduct_Model_Status extends Varien_Object
4
+ {
5
+ const STATUS_ENABLED = 1;
6
+ const STATUS_DISABLED = 2;
7
+
8
+ static public function getOptionArray()
9
+ {
10
+ return array(
11
+ self::STATUS_ENABLED => Mage::helper('customproduct')->__('Enabled'),
12
+ self::STATUS_DISABLED => Mage::helper('customproduct')->__('Disabled')
13
+ );
14
+ }
15
+ }
app/code/community/Blog4mail/Customproduct/controllers/IndexController.php ADDED
@@ -0,0 +1,617 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ class Blog4mail_Customproduct_IndexController extends Mage_Core_Controller_Front_Action
3
+ {
4
+ public function indexAction()
5
+ {
6
+ $this->loadLayout();
7
+ $this->renderLayout();
8
+ }
9
+
10
+ protected function set_file_name($new_name = '') { // this 'conversion' is used for unique/new filenames
11
+ if ($this->rename_file) {
12
+ if ($this->the_file == '') return;
13
+ $name = ($new_name == '') ? uniqid() : $new_name;
14
+ sleep(3);
15
+ $name = $name.$this->get_extension($this->the_file);
16
+ } else {
17
+ $name = str_replace(' ', '_', $this->the_file); // space will result in problems on linux systems
18
+ }
19
+ return $name;
20
+ }
21
+
22
+ public function uploadAction(){
23
+
24
+
25
+ $bsdir = Mage::getBaseDir('base');
26
+
27
+
28
+ $dest_dir = $bsdir.'/media/finalimages/upload/';
29
+ $source = $_FILES['userfile']['tmp_name'];
30
+ $filename = $_FILES['userfile']['name'];
31
+ $newfile = uniqid().$filename;
32
+ move_uploaded_file($source,$dest_dir.$newfile);
33
+ print $newfile;
34
+
35
+ }
36
+
37
+ public function ajaxoptionsAction()
38
+ {
39
+ $pid=$_REQUEST['product_id'];
40
+ $product = Mage::getModel('catalog/product')->load($pid);
41
+ $html=$this->getProductOptionsHtml($product);
42
+ print $html;
43
+ }
44
+
45
+ public function getProductOptionsHtml(Mage_Catalog_Model_Product $product)
46
+ {
47
+
48
+ $x = Mage::app()->getLayout()->createBlock("Mage_Core_Block_Template");
49
+
50
+ $x->setTemplate("catalog/product/view/options/js.phtml");
51
+ $a=$x->toHtml();
52
+
53
+ $y = Mage::app()->getLayout()->createBlock("Mage_Catalog_Block_Product_View_Options");
54
+ $y->setProduct($product);
55
+ $y->setTemplate("catalog/product/view/options.phtml");
56
+ $b=$y->toHtml();
57
+
58
+ $z = Mage::app()->getLayout()->createBlock("Mage_Core_Block_Html_Calendar");
59
+ $z->setProduct($product);
60
+ $z->setTemplate("page/js/calendar.phtml");
61
+ $c = $z->toHtml();
62
+
63
+
64
+ $blockOption = Mage::app()->getLayout()->createBlock("Mage_Catalog_Block_Product_View_Options");
65
+ $blockOption->addOptionRenderer("default","catalog/product_view_options_type_default","catalog/product/view/options/type/default.phtml");
66
+ $blockOption->addOptionRenderer("text","catalog/product_view_options_type_text","catalog/product/view/options/type/text.phtml");
67
+ $blockOption->addOptionRenderer("file","catalog/product_view_options_type_file","catalog/product/view/options/type/file.phtml");
68
+ $blockOption->addOptionRenderer("select","catalog/product_view_options_type_select","catalog/product/view/options/type/select.phtml");
69
+ $blockOption->addOptionRenderer("date","catalog/product_view_options_type_date","catalog/product/view/options/type/date.phtml") ;
70
+ $blockOptionsHtml = null;
71
+
72
+
73
+
74
+ if($product->getTypeId()=="simple"||$product->getTypeId()=="virtual"||$product->getTypeId()=="configurable")
75
+ {
76
+
77
+
78
+
79
+ $blockOption->setProduct($product);
80
+ if($product->getOptions())
81
+ {
82
+ foreach ($product->getOptions() as $o)
83
+ {
84
+ $h=$blockOption->getOptionHtml($o);
85
+
86
+ $blockOptionsHtml .= $blockOption->getOptionHtml($o);
87
+ };
88
+ }
89
+ }
90
+
91
+
92
+
93
+ if($product->getTypeId()=="configurable")
94
+ {
95
+ $blockViewType = Mage::app()->getLayout()->createBlock("Mage_Catalog_Block_Product_View_Type_Configurable");
96
+ $blockViewType->setProduct($product);
97
+ //$blockViewType->setTemplate("inchoo_catalog/product/view/type/options/configurable.phtml");
98
+ $blockViewType->setTemplate("mage_catalog/product/view/type/options/configurable.phtml");
99
+ $blockOptionsHtml .= $blockViewType->toHtml();
100
+ }
101
+ return $a.$b.$blockOptionsHtml.$c;
102
+ }
103
+
104
+ public function setMyCustomOption($productId, $title, array $optionData, array $values = array())
105
+ {
106
+ $product = Mage::getModel('catalog/product')->load($productId);
107
+
108
+ $data = array_merge( $optionData, array(
109
+ 'product_id' => (int)$productId,
110
+ 'title' => $title,
111
+ 'values' => $values,
112
+ ));
113
+
114
+
115
+ //$data=$optionData;
116
+
117
+ $product->setHasOptions(1)->save();
118
+ $option = Mage::getModel('catalog/product_option')->setData($data)->setProduct($product)->save();
119
+
120
+ return $option;
121
+ }
122
+
123
+
124
+ public function textAction(){
125
+ $spath1 = $_SERVER['DOCUMENT_ROOT'];
126
+
127
+ $spath = $_SERVER['SCRIPT_FILENAME'];
128
+
129
+
130
+ $spath = substr($spath,0,-9);
131
+ $ex=explode($spath1,$spath);
132
+
133
+ $host=$_SERVER['HTTP_HOST'];
134
+
135
+ $webpath = "http://".$host.$ex[1].'media/';
136
+ //print $webpath;
137
+ //return;
138
+
139
+ $mytext = $_REQUEST['mytext'];
140
+
141
+
142
+ /* Create some objects */
143
+ $image = new Imagick();
144
+ $draw = new ImagickDraw();
145
+
146
+ $pixel = new ImagickPixel('white');
147
+
148
+ $transparent = new ImagickPixel('white');
149
+
150
+
151
+ $w=strlen($mytext)*10;
152
+
153
+ /* New image */
154
+ $image->newImage($w,15,$pixel);
155
+ $image->paintTransparentImage($transparent, 0, 10);
156
+
157
+ /* Black text */
158
+ $draw->setFillColor('blue');
159
+
160
+ /* Font properties */
161
+ $draw->setFont('Bookman-DemiItalic');
162
+ $draw->setFontSize(11);
163
+
164
+ /* Create text */
165
+
166
+ $image->annotateImage($draw,15,10,0,$mytext);
167
+
168
+ /* Give image a format */
169
+
170
+ $x = md5($mytext.time()).'.png';
171
+ $filename = $spath.'media/'.$x;
172
+
173
+
174
+ $image->setImageFormat('png');
175
+ $image->writeImages($filename,true);
176
+
177
+ echo $webpath.$x;
178
+
179
+ //echo $filename;
180
+ /* Output the image with headers */
181
+ //header('Content-type: image/png');
182
+ //echo $image;
183
+ }
184
+
185
+ public function imageAction(){
186
+
187
+
188
+
189
+ $baseurl1 = Mage::getBaseUrl(Mage_Core_Model_Store::URL_TYPE_WEB);
190
+
191
+ $bsdir = Mage::getBaseDir('base');
192
+ $product_id = $_REQUEST['product'];
193
+ $filename = $bsdir.'/media/finalimages/'.md5(time().$product).'.jpg';
194
+
195
+ $filename1=$baseurl1.'media/finalimages/'.md5(time().$product).'.jpg';
196
+
197
+ $mainimage = $_REQUEST['mainimage'];
198
+
199
+ $image = $_REQUEST['image'];
200
+
201
+ $oldprice = trim(str_replace('$',' ',$_REQUEST['oldprice']));
202
+
203
+ $w = $_REQUEST['width'];
204
+ $h = $_REQUEST['height'];
205
+
206
+
207
+ /*$pos_left = $_REQUEST['left']=150;
208
+ $pos_top = $_REQUEST['top']=150;
209
+ */
210
+
211
+ $pos_left = $_REQUEST['left'];
212
+ $pos_top = $_REQUEST['top'];
213
+
214
+ $pos_left_text=$_REQUEST['left_text'];
215
+ $pos_top_text=$_REQUEST['top_text'];
216
+
217
+ $w_text=$_REQUEST['w_text'];
218
+ $h_text=$_REQUEST['h_text'];
219
+
220
+ $textimage=$_REQUEST['textimage'];
221
+
222
+ //center
223
+ //system("/var/www/cylinderize -m vertical -r 73 -l 120 -w 90 -p 5 -n 94 -e 2 -s 200 -a 100 -v background -b none -f none -o -15-15 /var/www/yellowpage/image1.jpeg /var/www/yellowpage/mug1.jpeg /var/www/yellowpage/im4.jpeg");
224
+
225
+ //Right
226
+ //system("/var/www/cylinderize -m vertical -r 73 -l 100 -w 100 -p 5 -n 94 -e 2 -s 200 -a -100 -v background -b none -f none -o +24+10 /var/www/yellowpage/image1.jpeg /var/www/yellowpage/mug1.jpeg /var/www/yellowpage/im4.jpeg");
227
+
228
+ //Left
229
+ //system("/var/www/cylinderize -m vertical -r 73 -l 100 -w 100 -p 5 -n 94 -e 2 -s 200 -a 100 -v background -b none -f none -o -24+10 /var/www/yellowpage/image1.jpeg /var/www/yellowpage/mug1.jpeg /var/www/yellowpage/im4.jpeg");
230
+
231
+ //system("/var/www/cylinderize -m vertical -r 73 -l 150 -w 150 -p 5 -n 94 -e 2 -s 200 -a -100 -v background -b none -f none -o -15+15 /var/www/yellowpage/image1.jpeg /var/www/yellowpage/mug1.jpeg /var/www/yellowpage/im4.jpeg");
232
+
233
+ $foundimage = strpos($mainimage,'bgimage.png');
234
+ $foundtextimage = strpos($textimage,'textimage.png');
235
+
236
+ if ($foundimage !== false && $foundtextimage !== false) {
237
+ $ar=array();
238
+ $ar['filename']=0;
239
+ $ar['opthtml']=0;
240
+ print json_encode($ar);
241
+ return;
242
+ }
243
+
244
+ $mug = new Imagick($image);
245
+
246
+ if ($foundimage === false) {
247
+ $im = new Imagick($mainimage);
248
+ $im->scaleImage($w,$h);
249
+ $im->setImageFormat('jpeg');
250
+ $im->setImageVirtualPixelMethod(Imagick::VIRTUALPIXELMETHOD_TRANSPARENT);
251
+ $im->setImageMatte(true);
252
+
253
+ //$im->setImageBackgroundColor('red');
254
+
255
+ $height = $im->getImageHeight();
256
+
257
+ $mug->compositeImage($im, $im->getImageCompose(),$pos_left, $pos_top);
258
+ }
259
+ //$im = new Imagick($bsdir.'/media/image1.jpeg');
260
+ //$mug = new Imagick($bsdir.'/media/mug1.jpeg');
261
+
262
+
263
+
264
+
265
+ if($foundtextimage === false) {
266
+ $im1 = new Imagick($textimage);
267
+ $mug->compositeImage($im1, $im1->getImageCompose(),$pos_left_text,$pos_top_text);
268
+ }
269
+
270
+ $persp="$mainimage,$w,$h,$pos_left,$pos_top|$textimage,$w_text,$h_text,$pos_left_text,$pos_top_text";
271
+
272
+
273
+ $mug->writeImages($filename,true);
274
+
275
+ $product = Mage::getModel('catalog/product')->load($product_id);
276
+ $magentoid = $product->getId();
277
+
278
+
279
+ $ctype=$product->getcustomproducttype();
280
+
281
+ $sku=$product->getSku();
282
+ $sku = $sku.'custom'.time();
283
+
284
+
285
+
286
+ if($magentoid && $ctype == 'designed'){
287
+ // UPDATE RECORDS
288
+ $data['id']=$product->getId();
289
+ $data['name']=$product->getName();
290
+ $data['desc']=$product->getDescription();
291
+ $data['shortdesc']=$product->getShortDescription();
292
+ $data['sku']=$sku;
293
+ $data['weight']=$product->getWeight();
294
+ $data['status']=$product->getStatus();
295
+
296
+ //$price = $product->getPrice();
297
+ //$data['price'] = $price;
298
+ $data['price'] = round($oldprice+($oldprice*5/100),2);
299
+ $data['designed']=$product->getcustomproducttype();
300
+ $data['image']=$filename;
301
+ $data['persp']=$persp;
302
+
303
+ $id=$this->_updateShopsProduct($data,$designedProduct='true',$magentoid);
304
+ $opthtml=$this->getProductOptionsHtml($product);
305
+ } else {
306
+ //print 'create';
307
+ //return;
308
+ // INSERT RECORDS
309
+ $data['id']=$product->getId();
310
+ $data['name']=$product->getName();
311
+ $data['desc']=$product->getDescription();
312
+ $data['shortdesc']=$product->getShortDescription();
313
+ $data['sku'] = $sku;
314
+ $data['weight']=$product->getWeight();
315
+ $data['status']=$product->getStatus();
316
+ //$price = $product->getPrice() + ($product->getPrice()*10/100);
317
+ //$data['price'] = $price;
318
+ $data['price'] = round($oldprice + ($oldprice*5/100),2);
319
+ $data['designed']='designed';
320
+ $data['image']=$filename;
321
+ $data['persp']=$persp;
322
+ $id = $this->createShopsProduct($data,$designedProduct='true');
323
+ $opthtml=$this->getProductOptionsHtml($product);
324
+ }
325
+
326
+
327
+
328
+ $ar=array();
329
+ $ar['filename']=$filename1;
330
+ $ar['opthtml']=$opthtml;
331
+ $ar['product_id']=$id;
332
+ $ar['price']=$data['price'];
333
+ print json_encode($ar);
334
+ }
335
+
336
+
337
+
338
+ protected function _updateShopsProduct($data,$designedProduct,$magentoid){
339
+ $serverurl = $data['image'];
340
+ try{
341
+ $_product = Mage::getModel('catalog/product');
342
+ $product = $_product->load($magentoid);
343
+
344
+ //
345
+ // foreach ($product->getOptions() as $opt)
346
+ // {
347
+ // $opt->delete();
348
+ // }
349
+ // $product->save();
350
+
351
+ $store = Mage::app()->getStore(Mage_Catalog_Model_Abstract::DEFAULT_STORE_ID);
352
+ $product->setStoreId($store->getId());
353
+
354
+ /*
355
+ $websiteIds = array();
356
+
357
+
358
+ if (Mage::app()->isSingleStoreMode()) {
359
+ $websites = Mage::app()->getWebsites();
360
+ foreach($websites as $curWebsite){
361
+ $websiteIds[] = $curWebsite->getId();
362
+ }
363
+
364
+ }
365
+ else {
366
+
367
+
368
+ $website = Mage::app()->getWebsite();
369
+ $websiteIds[] = $website->getId();
370
+ }
371
+
372
+ $product->setWebsiteIds($websiteIds);
373
+ */
374
+
375
+ $product->setName($data['name']);
376
+ $product->setDescription($data['desc']);
377
+ $product->setShortDescription($data['shortdesc']);
378
+ $product->setPrice($data['price']);
379
+ $product->setWeight($data['weight']);
380
+ $product->setSku($data['sku']);
381
+ $product->setcustomproducttype($designedProduct);
382
+ $product->setcustomperspective($data['persp']);
383
+
384
+ $mediaApi = Mage::getModel("catalog/product_attribute_media_api");
385
+ $items = $mediaApi->items($product->getId());
386
+
387
+ foreach($items as $item){
388
+ $mediaApi->remove($product->getId(), $item['file']);
389
+ }
390
+
391
+ $product->addImageToMediaGallery($serverurl,array('thumbnail','small_image','image'),false,false);
392
+
393
+ Mage::dispatchEvent('catalog_product_prepare_save',array('product' => $product, 'request' => null));
394
+ $product->save();
395
+ return $magentoid;
396
+ }
397
+ catch (Exception $e) {
398
+ Mage::logException($e);
399
+ return null;
400
+ }
401
+ }
402
+
403
+
404
+
405
+
406
+ public function customdesignAction(){
407
+
408
+ $ar['alias'] = 'Mugs - Good';
409
+ $ar['description']='Mugs - Good';
410
+ $ar['shortDescription']='Mugs - Good';
411
+ $ar['MSRP']='10.50';
412
+ $ar['weight']=1;
413
+ $ar['_id']=2;
414
+ $ar['clientSku']='A1';
415
+
416
+
417
+
418
+ $en=json_encode($ar);
419
+
420
+
421
+ $data = json_decode($en);
422
+
423
+
424
+ $this->createShopsProduct($data, $designedProduct='true');
425
+
426
+
427
+ print 'Helo';
428
+ }
429
+
430
+
431
+
432
+
433
+
434
+
435
+
436
+ public function createShopsProduct($data, $designedProduct='true'){
437
+
438
+
439
+ // Add or create new product magento through code with custom options, image and manage stock
440
+ // mmoves image and assigns to all three types image, small_image and thumbnail_image
441
+ //require_once 'app/Mage.php';
442
+ //umask(0);
443
+
444
+ //$app = Mage::app();
445
+ //$session = Mage::getSingleton('customer/session', array('name'=>'frontend'));
446
+
447
+
448
+
449
+ //create a new product
450
+
451
+ try {
452
+
453
+ //$serverurl = $_SERVER['DOCUMENT_ROOT'].'/yellowpage/image6.jpeg';
454
+ $serverurl=$data['image'];
455
+ $product = Mage::getModel('catalog/product');
456
+
457
+ $stockData = $product->getStockData();
458
+
459
+ $stockData['qty'] = 1;
460
+ $stockData['is_in_stock'] = 1;
461
+ $stockData['manage_stock'] = 1;
462
+ $stockData['use_config_manage_stock'] = 0;
463
+
464
+ $stockData['inventory_use_config_min_sale_qty'] = 1;
465
+ $stockData['inventory_use_config_max_sale_qty'] = 1;
466
+
467
+ $options = array();
468
+
469
+
470
+ $options['Colors']['opt']['type']='radio';
471
+ $options['Colors']['opt']['is_require']=0;
472
+ $options['Colors']['opt']['price']=0;
473
+ $options['Colors']['opt']['price_type']='fixed';
474
+
475
+
476
+ $options['Colors']['values'][0]['title']='Red';
477
+ $options['Colors']['values'][0]['price']=10.00;
478
+ $options['Colors']['values'][0]['price_type']='fixed';
479
+
480
+ $options['Colors']['values'][1]['title']='Green';
481
+ $options['Colors']['values'][1]['price']=11.00;
482
+ $options['Colors']['values'][1]['price_type']='fixed';
483
+
484
+ $options['Colors']['values'][2]['title']='Blue';
485
+ $options['Colors']['values'][2]['price']=12.00;
486
+ $options['Colors']['values'][2]['price_type']='fixed';
487
+
488
+
489
+ $options['Sizes']['opt']['type']='radio';
490
+ $options['Sizes']['opt']['is_require']=0;
491
+ $options['Sizes']['opt']['price']=0;
492
+ $options['Sizes']['opt']['price_type']='fixed';
493
+
494
+ $options['Sizes']['values'][0]['title']='L';
495
+ $options['Sizes']['values'][0]['price']=9.00;
496
+ $options['Sizes']['values'][0]['price_type']='fixed';
497
+
498
+ $options['Sizes']['values'][1]['title']='XL';
499
+ $options['Sizes']['values'][1]['price']=15.00;
500
+ $options['Sizes']['values'][1]['price_type']='fixed';
501
+
502
+
503
+
504
+ /*$options['title'] = array(
505
+ 'title' => 'Colors',
506
+ 'type' => 'radio',
507
+ 'is_require' => 1,
508
+ 'sort_order' => 0,
509
+ 'values' => array()
510
+ );
511
+
512
+ $options['values'][] = array(
513
+ 'title' => 'Red',
514
+ 'price' => 10.00,
515
+ 'price_type' => 'fixed',
516
+ 'sku' => '',
517
+ 'sort_order' => '1'
518
+ );
519
+
520
+ $options['values'][] = array(
521
+ 'title' => 'Green',
522
+ 'price' => 89.00,
523
+ 'price_type' => 'fixed',
524
+ 'sku' => '',
525
+ 'sort_order' => '1'
526
+ );
527
+
528
+ $options['values'][] = array(
529
+ 'title' => 'Blue',
530
+ 'price' => 89.00,
531
+ 'price_type' => 'fixed',
532
+ 'sku' => '',
533
+ 'sort_order' => '1'
534
+ );
535
+ */
536
+
537
+
538
+
539
+
540
+ $store = Mage::app()->getStore(Mage_Catalog_Model_Abstract::DEFAULT_STORE_ID);
541
+ // Save all product attributes under "default" store, no matter whether system is in single or multi-store mode
542
+ $product->setStoreId($store->getId());
543
+ // Build array of website ids
544
+ $websiteIds = array();
545
+
546
+ if (Mage::app()->isSingleStoreMode()) {
547
+ $websites = Mage::app()->getWebsites();
548
+ foreach($websites as $curWebsite){
549
+ $websiteIds[] = $curWebsite->getId();
550
+ }
551
+ }
552
+ else {
553
+ //set to specific website/store
554
+ $website = Mage::app()->getWebsite();
555
+ $websiteIds[] = $website->getId();
556
+ }
557
+
558
+ $product->setWebsiteIds($websiteIds);
559
+
560
+ $product->setAttributeSetId(Mage::getModel('catalog/product')->getResource()->getEntityType()->getDefaultAttributeSetId());
561
+
562
+ //->setAttributeSetId(4)
563
+ //$product->setStoreId('default')
564
+
565
+ $product->setTypeId('simple')
566
+ ->setName($data['name'])
567
+ ->setDescription($data['desc'])
568
+ ->setShortDescription($data['shortdesc'])
569
+ ->setSku($data['sku'])
570
+ ->setWeight($data['weight'])
571
+ ->setStatus($data['status'])
572
+ //->setVisibility(4)
573
+ ->setPrice($data['price'])
574
+ ->addImageToMediaGallery($serverurl,array('thumbnail','small_image','image'),false,false)
575
+ ->setTaxClassId(0)
576
+ ->setStockData($stockData)
577
+ ->setCategoryIds('3')
578
+ //->setHasOptions(1)
579
+ //->setProductOptions(array($opt))
580
+ //->setCanSaveCustomOptions(true)
581
+ //->setPageLayout('one_column')
582
+ ->setVisibility(Mage_Catalog_Model_Product_Visibility::VISIBILITY_BOTH)
583
+ ->setCreatedAt(strtotime('now'))
584
+ ->setcustomproducttype($data['designed'])
585
+ ->setcustomperspective($data['persp']);
586
+
587
+ Mage::dispatchEvent('catalog_product_prepare_save',array('product' => $product, 'request' => null));
588
+ Mage::log("setup product");
589
+
590
+ $product->save();
591
+ $product_id = $product->getId();
592
+
593
+ //echo 'OK Product ID: '.$product->getId();
594
+
595
+ foreach($options as $title=>$v){
596
+ $this->setMyCustomOption($product_id,$title,$optionData=$v['opt'],$values = $v['values']);
597
+ }
598
+
599
+ $cache = Mage::getSingleton('core/cache');
600
+ $cache->flush();
601
+
602
+ return $product->getId();
603
+ }
604
+ catch (Mage_Core_Exception $e) {
605
+ echo $e->getMessage();
606
+ }
607
+ catch (Exception $e) {
608
+ echo $e;
609
+ }
610
+
611
+
612
+
613
+ }
614
+
615
+
616
+ }
617
+ ?>
app/code/community/Blog4mail/Customproduct/controllers/IndexController.php~ ADDED
@@ -0,0 +1,617 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ class Blog4mail_Customproduct_IndexController extends Mage_Core_Controller_Front_Action
3
+ {
4
+ public function indexAction()
5
+ {
6
+ $this->loadLayout();
7
+ $this->renderLayout();
8
+ }
9
+
10
+ protected function set_file_name($new_name = '') { // this 'conversion' is used for unique/new filenames
11
+ if ($this->rename_file) {
12
+ if ($this->the_file == '') return;
13
+ $name = ($new_name == '') ? uniqid() : $new_name;
14
+ sleep(3);
15
+ $name = $name.$this->get_extension($this->the_file);
16
+ } else {
17
+ $name = str_replace(' ', '_', $this->the_file); // space will result in problems on linux systems
18
+ }
19
+ return $name;
20
+ }
21
+
22
+ public function uploadAction(){
23
+
24
+
25
+ $bsdir = Mage::getBaseDir('base');
26
+
27
+
28
+ $dest_dir = $bsdir.'/media/finalimages/upload/';
29
+ $source = $_FILES['userfile']['tmp_name'];
30
+ $filename = $_FILES['userfile']['name'];
31
+ $newfile = uniqid().$filename;
32
+ move_uploaded_file($source,$dest_dir.$newfile);
33
+ print $newfile;
34
+
35
+ }
36
+
37
+ public function ajaxoptionsAction()
38
+ {
39
+ $pid=$_REQUEST['product_id'];
40
+ $product = Mage::getModel('catalog/product')->load($pid);
41
+ $html=$this->getProductOptionsHtml($product);
42
+ print $html;
43
+ }
44
+
45
+ public function getProductOptionsHtml(Mage_Catalog_Model_Product $product)
46
+ {
47
+
48
+ $x = Mage::app()->getLayout()->createBlock("Mage_Core_Block_Template");
49
+
50
+ $x->setTemplate("catalog/product/view/options/js.phtml");
51
+ $a=$x->toHtml();
52
+
53
+ $y = Mage::app()->getLayout()->createBlock("Mage_Catalog_Block_Product_View_Options");
54
+ $y->setProduct($product);
55
+ $y->setTemplate("catalog/product/view/options.phtml");
56
+ $b=$y->toHtml();
57
+
58
+ $z = Mage::app()->getLayout()->createBlock("Mage_Core_Block_Html_Calendar");
59
+ $z->setProduct($product);
60
+ $z->setTemplate("page/js/calendar.phtml");
61
+ $c = $z->toHtml();
62
+
63
+
64
+ $blockOption = Mage::app()->getLayout()->createBlock("Mage_Catalog_Block_Product_View_Options");
65
+ $blockOption->addOptionRenderer("default","catalog/product_view_options_type_default","catalog/product/view/options/type/default.phtml");
66
+ $blockOption->addOptionRenderer("text","catalog/product_view_options_type_text","catalog/product/view/options/type/text.phtml");
67
+ $blockOption->addOptionRenderer("file","catalog/product_view_options_type_file","catalog/product/view/options/type/file.phtml");
68
+ $blockOption->addOptionRenderer("select","catalog/product_view_options_type_select","catalog/product/view/options/type/select.phtml");
69
+ $blockOption->addOptionRenderer("date","catalog/product_view_options_type_date","catalog/product/view/options/type/date.phtml") ;
70
+ $blockOptionsHtml = null;
71
+
72
+
73
+
74
+ if($product->getTypeId()=="simple"||$product->getTypeId()=="virtual"||$product->getTypeId()=="configurable")
75
+ {
76
+
77
+
78
+
79
+ $blockOption->setProduct($product);
80
+ if($product->getOptions())
81
+ {
82
+ foreach ($product->getOptions() as $o)
83
+ {
84
+ $h=$blockOption->getOptionHtml($o);
85
+
86
+ $blockOptionsHtml .= $blockOption->getOptionHtml($o);
87
+ };
88
+ }
89
+ }
90
+
91
+
92
+
93
+ if($product->getTypeId()=="configurable")
94
+ {
95
+ $blockViewType = Mage::app()->getLayout()->createBlock("Mage_Catalog_Block_Product_View_Type_Configurable");
96
+ $blockViewType->setProduct($product);
97
+ //$blockViewType->setTemplate("inchoo_catalog/product/view/type/options/configurable.phtml");
98
+ $blockViewType->setTemplate("mage_catalog/product/view/type/options/configurable.phtml");
99
+ $blockOptionsHtml .= $blockViewType->toHtml();
100
+ }
101
+ return $a.$b.$blockOptionsHtml.$c;
102
+ }
103
+
104
+ public function setMyCustomOption($productId, $title, array $optionData, array $values = array())
105
+ {
106
+ $product = Mage::getModel('catalog/product')->load($productId);
107
+
108
+ $data = array_merge( $optionData, array(
109
+ 'product_id' => (int)$productId,
110
+ 'title' => $title,
111
+ 'values' => $values,
112
+ ));
113
+
114
+
115
+ //$data=$optionData;
116
+
117
+ $product->setHasOptions(1)->save();
118
+ $option = Mage::getModel('catalog/product_option')->setData($data)->setProduct($product)->save();
119
+
120
+ return $option;
121
+ }
122
+
123
+
124
+ public function textAction(){
125
+ $spath1 = $_SERVER['DOCUMENT_ROOT'];
126
+
127
+ $spath = $_SERVER['SCRIPT_FILENAME'];
128
+
129
+
130
+ $spath = substr($spath,0,-9);
131
+ $ex=explode($spath1,$spath);
132
+
133
+ $host=$_SERVER['HTTP_HOST'];
134
+
135
+ $webpath = "http://".$host.$ex[1].'media/';
136
+ //print $webpath;
137
+ //return;
138
+
139
+ $mytext = $_REQUEST['mytext'];
140
+
141
+
142
+ /* Create some objects */
143
+ $image = new Imagick();
144
+ $draw = new ImagickDraw();
145
+
146
+ $pixel = new ImagickPixel('white');
147
+
148
+ $transparent = new ImagickPixel('white');
149
+
150
+
151
+ $w=strlen($mytext)*10;
152
+
153
+ /* New image */
154
+ $image->newImage($w,15,$pixel);
155
+ $image->paintTransparentImage($transparent, 0, 10);
156
+
157
+ /* Black text */
158
+ $draw->setFillColor('blue');
159
+
160
+ /* Font properties */
161
+ $draw->setFont('Bookman-DemiItalic');
162
+ $draw->setFontSize(11);
163
+
164
+ /* Create text */
165
+
166
+ $image->annotateImage($draw,15,10,0,$mytext);
167
+
168
+ /* Give image a format */
169
+
170
+ $x = md5($mytext.time()).'.png';
171
+ $filename = $spath.'media/'.$x;
172
+
173
+
174
+ $image->setImageFormat('png');
175
+ $image->writeImages($filename,true);
176
+
177
+ echo $webpath.$x;
178
+
179
+ //echo $filename;
180
+ /* Output the image with headers */
181
+ //header('Content-type: image/png');
182
+ //echo $image;
183
+ }
184
+
185
+ public function imageAction(){
186
+
187
+
188
+
189
+ $baseurl1 = Mage::getBaseUrl(Mage_Core_Model_Store::URL_TYPE_WEB);
190
+
191
+ $bsdir = Mage::getBaseDir('base');
192
+ $product_id = $_REQUEST['product'];
193
+ $filename = $bsdir.'/media/finalimages/'.md5(time().$product).'.jpg';
194
+
195
+ $filename1=$baseurl1.'media/finalimages/'.md5(time().$product).'.jpg';
196
+
197
+ $mainimage = $_REQUEST['mainimage'];
198
+
199
+ $image = $_REQUEST['image'];
200
+
201
+ $oldprice = trim(str_replace('$',' ',$_REQUEST['oldprice']));
202
+
203
+ $w = $_REQUEST['width'];
204
+ $h = $_REQUEST['height'];
205
+
206
+
207
+ /*$pos_left = $_REQUEST['left']=150;
208
+ $pos_top = $_REQUEST['top']=150;
209
+ */
210
+
211
+ $pos_left = $_REQUEST['left'];
212
+ $pos_top = $_REQUEST['top'];
213
+
214
+ $pos_left_text=$_REQUEST['left_text'];
215
+ $pos_top_text=$_REQUEST['top_text'];
216
+
217
+ $w_text=$_REQUEST['w_text'];
218
+ $h_text=$_REQUEST['h_text'];
219
+
220
+ $textimage=$_REQUEST['textimage'];
221
+
222
+ //center
223
+ //system("/var/www/cylinderize -m vertical -r 73 -l 120 -w 90 -p 5 -n 94 -e 2 -s 200 -a 100 -v background -b none -f none -o -15-15 /var/www/yellowpage/image1.jpeg /var/www/yellowpage/mug1.jpeg /var/www/yellowpage/im4.jpeg");
224
+
225
+ //Right
226
+ //system("/var/www/cylinderize -m vertical -r 73 -l 100 -w 100 -p 5 -n 94 -e 2 -s 200 -a -100 -v background -b none -f none -o +24+10 /var/www/yellowpage/image1.jpeg /var/www/yellowpage/mug1.jpeg /var/www/yellowpage/im4.jpeg");
227
+
228
+ //Left
229
+ //system("/var/www/cylinderize -m vertical -r 73 -l 100 -w 100 -p 5 -n 94 -e 2 -s 200 -a 100 -v background -b none -f none -o -24+10 /var/www/yellowpage/image1.jpeg /var/www/yellowpage/mug1.jpeg /var/www/yellowpage/im4.jpeg");
230
+
231
+ //system("/var/www/cylinderize -m vertical -r 73 -l 150 -w 150 -p 5 -n 94 -e 2 -s 200 -a -100 -v background -b none -f none -o -15+15 /var/www/yellowpage/image1.jpeg /var/www/yellowpage/mug1.jpeg /var/www/yellowpage/im4.jpeg");
232
+
233
+ $foundimage = strpos($mainimage,'bgimage.png');
234
+ $foundtextimage = strpos($textimage,'textimage.png');
235
+
236
+ if ($foundimage !== false && $foundtextimage !== false) {
237
+ $ar=array();
238
+ $ar['filename']=0;
239
+ $ar['opthtml']=0;
240
+ print json_encode($ar);
241
+ return;
242
+ }
243
+
244
+ $mug = new Imagick($image);
245
+
246
+ if ($foundimage === false) {
247
+ $im = new Imagick($mainimage);
248
+ $im->scaleImage($w,$h);
249
+ $im->setImageFormat('jpeg');
250
+ $im->setImageVirtualPixelMethod(Imagick::VIRTUALPIXELMETHOD_TRANSPARENT);
251
+ $im->setImageMatte(true);
252
+
253
+ //$im->setImageBackgroundColor('red');
254
+
255
+ $height = $im->getImageHeight();
256
+
257
+ $mug->compositeImage($im, $im->getImageCompose(),$pos_left, $pos_top);
258
+ }
259
+ //$im = new Imagick($bsdir.'/media/image1.jpeg');
260
+ //$mug = new Imagick($bsdir.'/media/mug1.jpeg');
261
+
262
+
263
+
264
+
265
+ if($foundtextimage === false) {
266
+ $im1 = new Imagick($textimage);
267
+ $mug->compositeImage($im1, $im1->getImageCompose(),$pos_left_text,$pos_top_text);
268
+ }
269
+
270
+ $persp="$mainimage,$w,$h,$pos_left,$pos_top|$textimage,$w_text,$h_text,$pos_left_text,$pos_top_text";
271
+
272
+
273
+ $mug->writeImages($filename,true);
274
+
275
+ $product = Mage::getModel('catalog/product')->load($product_id);
276
+ $magentoid = $product->getId();
277
+
278
+
279
+ $ctype=$product->getcustomproducttype();
280
+
281
+ $sku=$product->getSku();
282
+ $sku = $sku.'custom'.time();
283
+
284
+
285
+
286
+ if($magentoid && $ctype == 'designed'){
287
+ // UPDATE RECORDS
288
+ $data['id']=$product->getId();
289
+ $data['name']=$product->getName();
290
+ $data['desc']=$product->getDescription();
291
+ $data['shortdesc']=$product->getShortDescription();
292
+ $data['sku']=$sku;
293
+ $data['weight']=$product->getWeight();
294
+ $data['status']=$product->getStatus();
295
+
296
+ //$price = $product->getPrice();
297
+ //$data['price'] = $price;
298
+ $data['price'] = round($oldprice+($oldprice*5/100),2);
299
+ $data['designed']=$product->getcustomproducttype();
300
+ $data['image']=$filename;
301
+ $data['persp']=$persp;
302
+
303
+ $id=$this->_updateShopsProduct($data,$designedProduct='true',$magentoid);
304
+ $opthtml=$this->getProductOptionsHtml($product);
305
+ } else {
306
+ //print 'create';
307
+ //return;
308
+ // INSERT RECORDS
309
+ $data['id']=$product->getId();
310
+ $data['name']=$product->getName();
311
+ $data['desc']=$product->getDescription();
312
+ $data['shortdesc']=$product->getShortDescription();
313
+ $data['sku'] = $sku;
314
+ $data['weight']=$product->getWeight();
315
+ $data['status']=$product->getStatus();
316
+ //$price = $product->getPrice() + ($product->getPrice()*10/100);
317
+ //$data['price'] = $price;
318
+ $data['price'] = round($oldprice + ($oldprice*5/100),2);
319
+ $data['designed']='designed';
320
+ $data['image']=$filename;
321
+ $data['persp']=$persp;
322
+ $id = $this->createShopsProduct($data,$designedProduct='true');
323
+ $opthtml=$this->getProductOptionsHtml($product);
324
+ }
325
+
326
+
327
+
328
+ $ar=array();
329
+ $ar['filename']=$filename1;
330
+ $ar['opthtml']=$opthtml;
331
+ $ar['product_id']=$id;
332
+ $ar['price']=$data['price'];
333
+ print json_encode($ar);
334
+ }
335
+
336
+
337
+
338
+ protected function _updateShopsProduct($data,$designedProduct,$magentoid){
339
+ $serverurl = $data['image'];
340
+ try{
341
+ $_product = Mage::getModel('catalog/product');
342
+ $product = $_product->load($magentoid);
343
+
344
+ //
345
+ // foreach ($product->getOptions() as $opt)
346
+ // {
347
+ // $opt->delete();
348
+ // }
349
+ // $product->save();
350
+
351
+ $store = Mage::app()->getStore(Mage_Catalog_Model_Abstract::DEFAULT_STORE_ID);
352
+ $product->setStoreId($store->getId());
353
+
354
+ /*
355
+ $websiteIds = array();
356
+
357
+
358
+ if (Mage::app()->isSingleStoreMode()) {
359
+ $websites = Mage::app()->getWebsites();
360
+ foreach($websites as $curWebsite){
361
+ $websiteIds[] = $curWebsite->getId();
362
+ }
363
+
364
+ }
365
+ else {
366
+
367
+
368
+ $website = Mage::app()->getWebsite();
369
+ $websiteIds[] = $website->getId();
370
+ }
371
+
372
+ $product->setWebsiteIds($websiteIds);
373
+ */
374
+
375
+ $product->setName($data['name']);
376
+ $product->setDescription($data['desc']);
377
+ $product->setShortDescription($data['shortdesc']);
378
+ $product->setPrice($data['price']);
379
+ $product->setWeight($data['weight']);
380
+ $product->setSku($data['sku']);
381
+ $product->setcustomproducttype($designedProduct);
382
+ $product->setcustomperspective($data['persp']);
383
+
384
+ $mediaApi = Mage::getModel("catalog/product_attribute_media_api");
385
+ $items = $mediaApi->items($product->getId());
386
+
387
+ foreach($items as $item){
388
+ $mediaApi->remove($product->getId(), $item['file']);
389
+ }
390
+
391
+ $product->addImageToMediaGallery($serverurl,array('thumbnail','small_image','image'),false,false);
392
+
393
+ Mage::dispatchEvent('catalog_product_prepare_save',array('product' => $product, 'request' => null));
394
+ $product->save();
395
+ return $magentoid;
396
+ }
397
+ catch (Exception $e) {
398
+ Mage::logException($e);
399
+ return null;
400
+ }
401
+ }
402
+
403
+
404
+
405
+
406
+ public function customdesignAction(){
407
+
408
+ $ar['alias'] = 'Mugs - Good';
409
+ $ar['description']='Mugs - Good';
410
+ $ar['shortDescription']='Mugs - Good';
411
+ $ar['MSRP']='10.50';
412
+ $ar['weight']=1;
413
+ $ar['_id']=2;
414
+ $ar['clientSku']='A1';
415
+
416
+
417
+
418
+ $en=json_encode($ar);
419
+
420
+
421
+ $data = json_decode($en);
422
+
423
+
424
+ $this->createShopsProduct($data, $designedProduct='true');
425
+
426
+
427
+ print 'Helo';
428
+ }
429
+
430
+
431
+
432
+
433
+
434
+
435
+
436
+ public function createShopsProduct($data, $designedProduct='true'){
437
+
438
+
439
+ // Add or create new product magento through code with custom options, image and manage stock
440
+ // mmoves image and assigns to all three types image, small_image and thumbnail_image
441
+ //require_once 'app/Mage.php';
442
+ //umask(0);
443
+
444
+ //$app = Mage::app();
445
+ //$session = Mage::getSingleton('customer/session', array('name'=>'frontend'));
446
+
447
+
448
+
449
+ //create a new product
450
+
451
+ try {
452
+
453
+ //$serverurl = $_SERVER['DOCUMENT_ROOT'].'/yellowpage/image6.jpeg';
454
+ $serverurl=$data['image'];
455
+ $product = Mage::getModel('catalog/product');
456
+
457
+ $stockData = $product->getStockData();
458
+
459
+ $stockData['qty'] = 1;
460
+ $stockData['is_in_stock'] = 1;
461
+ $stockData['manage_stock'] = 1;
462
+ $stockData['use_config_manage_stock'] = 0;
463
+
464
+ $stockData['inventory_use_config_min_sale_qty'] = 1;
465
+ $stockData['inventory_use_config_max_sale_qty'] = 1;
466
+
467
+ $options = array();
468
+
469
+
470
+ $options['Colors']['opt']['type']='radio';
471
+ $options['Colors']['opt']['is_require']=0;
472
+ $options['Colors']['opt']['price']=0;
473
+ $options['Colors']['opt']['price_type']='fixed';
474
+
475
+
476
+ $options['Colors']['values'][0]['title']='Red';
477
+ $options['Colors']['values'][0]['price']=10.00;
478
+ $options['Colors']['values'][0]['price_type']='fixed';
479
+
480
+ $options['Colors']['values'][1]['title']='Green';
481
+ $options['Colors']['values'][1]['price']=11.00;
482
+ $options['Colors']['values'][1]['price_type']='fixed';
483
+
484
+ $options['Colors']['values'][2]['title']='Blue';
485
+ $options['Colors']['values'][2]['price']=12.00;
486
+ $options['Colors']['values'][2]['price_type']='fixed';
487
+
488
+
489
+ $options['Sizes']['opt']['type']='radio';
490
+ $options['Sizes']['opt']['is_require']=0;
491
+ $options['Sizes']['opt']['price']=0;
492
+ $options['Sizes']['opt']['price_type']='fixed';
493
+
494
+ $options['Sizes']['values'][0]['title']='L';
495
+ $options['Sizes']['values'][0]['price']=9.00;
496
+ $options['Sizes']['values'][0]['price_type']='fixed';
497
+
498
+ $options['Sizes']['values'][1]['title']='XL';
499
+ $options['Sizes']['values'][1]['price']=15.00;
500
+ $options['Sizes']['values'][1]['price_type']='fixed';
501
+
502
+
503
+
504
+ /*$options['title'] = array(
505
+ 'title' => 'Colors',
506
+ 'type' => 'radio',
507
+ 'is_require' => 1,
508
+ 'sort_order' => 0,
509
+ 'values' => array()
510
+ );
511
+
512
+ $options['values'][] = array(
513
+ 'title' => 'Red',
514
+ 'price' => 10.00,
515
+ 'price_type' => 'fixed',
516
+ 'sku' => '',
517
+ 'sort_order' => '1'
518
+ );
519
+
520
+ $options['values'][] = array(
521
+ 'title' => 'Green',
522
+ 'price' => 89.00,
523
+ 'price_type' => 'fixed',
524
+ 'sku' => '',
525
+ 'sort_order' => '1'
526
+ );
527
+
528
+ $options['values'][] = array(
529
+ 'title' => 'Blue',
530
+ 'price' => 89.00,
531
+ 'price_type' => 'fixed',
532
+ 'sku' => '',
533
+ 'sort_order' => '1'
534
+ );
535
+ */
536
+
537
+
538
+
539
+
540
+ $store = Mage::app()->getStore(Mage_Catalog_Model_Abstract::DEFAULT_STORE_ID);
541
+ // Save all product attributes under "default" store, no matter whether system is in single or multi-store mode
542
+ $product->setStoreId($store->getId());
543
+ // Build array of website ids
544
+ $websiteIds = array();
545
+
546
+ if (Mage::app()->isSingleStoreMode()) {
547
+ $websites = Mage::app()->getWebsites();
548
+ foreach($websites as $curWebsite){
549
+ $websiteIds[] = $curWebsite->getId();
550
+ }
551
+ }
552
+ else {
553
+ //set to specific website/store
554
+ $website = Mage::app()->getWebsite();
555
+ $websiteIds[] = $website->getId();
556
+ }
557
+
558
+ $product->setWebsiteIds($websiteIds);
559
+
560
+ $product->setAttributeSetId(Mage::getModel('catalog/product')->getResource()->getEntityType()->getDefaultAttributeSetId());
561
+
562
+ //->setAttributeSetId(4)
563
+ //$product->setStoreId('default')
564
+
565
+ $product->setTypeId('simple')
566
+ ->setName($data['name'])
567
+ ->setDescription($data['desc'])
568
+ ->setShortDescription($data['shortdesc'])
569
+ ->setSku($data['sku'])
570
+ ->setWeight($data['weight'])
571
+ ->setStatus($data['status'])
572
+ //->setVisibility(4)
573
+ ->setPrice($data['price'])
574
+ ->addImageToMediaGallery($serverurl,array('thumbnail','small_image','image'),false,false)
575
+ ->setTaxClassId(0)
576
+ ->setStockData($stockData)
577
+ ->setCategoryIds('3')
578
+ //->setHasOptions(1)
579
+ //->setProductOptions(array($opt))
580
+ //->setCanSaveCustomOptions(true)
581
+ //->setPageLayout('one_column')
582
+ ->setVisibility(Mage_Catalog_Model_Product_Visibility::VISIBILITY_BOTH)
583
+ ->setCreatedAt(strtotime('now'))
584
+ ->setcustomproducttype($data['designed'])
585
+ ->setcustomperspective($data['persp']);
586
+
587
+ Mage::dispatchEvent('catalog_product_prepare_save',array('product' => $product, 'request' => null));
588
+ Mage::log("setup product");
589
+
590
+ $product->save();
591
+ $product_id = $product->getId();
592
+
593
+ //echo 'OK Product ID: '.$product->getId();
594
+
595
+ foreach($options as $title=>$v){
596
+ $this->setMyCustomOption($product_id,$title,$optionData=$v['opt'],$values = $v['values']);
597
+ }
598
+
599
+ $cache = Mage::getSingleton('core/cache');
600
+ $cache->flush();
601
+
602
+ return $product->getId();
603
+ }
604
+ catch (Mage_Core_Exception $e) {
605
+ echo $e->getMessage();
606
+ }
607
+ catch (Exception $e) {
608
+ echo $e;
609
+ }
610
+
611
+
612
+
613
+ }
614
+
615
+
616
+ }
617
+ ?>
app/code/community/Blog4mail/Customproduct/etc/config.xml ADDED
@@ -0,0 +1,72 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?xml version="1.0"?>
2
+ <config>
3
+ <modules>
4
+ <Blog4mail_Customproduct>
5
+ <version>1.0.0</version>
6
+ </Blog4mail_Customproduct>
7
+ </modules>
8
+ <frontend>
9
+ <routers>
10
+ <customproduct>
11
+ <use>standard</use>
12
+ <args>
13
+ <module>Blog4mail_Customproduct</module>
14
+ <frontName>customproduct</frontName>
15
+ </args>
16
+ </customproduct>
17
+ </routers>
18
+ <layout>
19
+ <updates>
20
+ <catalog>
21
+ <file>customproduct_catalog.xml</file>
22
+ </catalog>
23
+ </updates>
24
+ </layout>
25
+ </frontend>
26
+ <global>
27
+ <models>
28
+ <customproduct>
29
+ <class>Blog4mail_Customproduct_Model</class>
30
+ <resourceModel>customproduct_mysql4</resourceModel>
31
+ </customproduct>
32
+ <customproduct_mysql4>
33
+ <class>Blog4mail_Customproduct_Model_Mysql4</class>
34
+ <entities>
35
+ <customproduct>
36
+ <table>customproduct</table>
37
+ </customproduct>
38
+ </entities>
39
+ </customproduct_mysql4>
40
+ </models>
41
+ <resources>
42
+ <customproduct_setup>
43
+ <setup>
44
+ <module>Blog4mail_Customproduct</module>
45
+ </setup>
46
+ <connection>
47
+ <use>core_setup</use>
48
+ </connection>
49
+ </customproduct_setup>
50
+ <customproduct_write>
51
+ <connection>
52
+ <use>core_write</use>
53
+ </connection>
54
+ </customproduct_write>
55
+ <customproduct_read>
56
+ <connection>
57
+ <use>core_read</use>
58
+ </connection>
59
+ </customproduct_read>
60
+ </resources>
61
+ <blocks>
62
+ <customproduct>
63
+ <class>Blog4mail_Customproduct_Block</class>
64
+ </customproduct>
65
+ </blocks>
66
+ <helpers>
67
+ <customproduct>
68
+ <class>Blog4mail_Customproduct_Helper</class>
69
+ </customproduct>
70
+ </helpers>
71
+ </global>
72
+ </config>
app/code/community/Blog4mail/Customproduct/etc/config.xml~ ADDED
@@ -0,0 +1,72 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?xml version="1.0"?>
2
+ <config>
3
+ <modules>
4
+ <Blog4mail_Customproduct>
5
+ <version>1.0.0</version>
6
+ </Blog4mail_Customproduct>
7
+ </modules>
8
+ <frontend>
9
+ <routers>
10
+ <customproduct>
11
+ <use>standard</use>
12
+ <args>
13
+ <module>Blog4mail_Customproduct</module>
14
+ <frontName>customproduct</frontName>
15
+ </args>
16
+ </customproduct>
17
+ </routers>
18
+ <layout>
19
+ <updates>
20
+ <catalog>
21
+ <file>customproduct_catalog.xml</file>
22
+ </catalog>
23
+ </updates>
24
+ </layout>
25
+ </frontend>
26
+ <global>
27
+ <models>
28
+ <customproduct>
29
+ <class>Blog4mail_Customproduct_Model</class>
30
+ <resourceModel>customproduct_mysql4</resourceModel>
31
+ </customproduct>
32
+ <customproduct_mysql4>
33
+ <class>Blog4mail_Customproduct_Model_Mysql4</class>
34
+ <entities>
35
+ <customproduct>
36
+ <table>customproduct</table>
37
+ </customproduct>
38
+ </entities>
39
+ </customproduct_mysql4>
40
+ </models>
41
+ <resources>
42
+ <customproduct_setup>
43
+ <setup>
44
+ <module>Blog4mail_Customproduct</module>
45
+ </setup>
46
+ <connection>
47
+ <use>core_setup</use>
48
+ </connection>
49
+ </customproduct_setup>
50
+ <customproduct_write>
51
+ <connection>
52
+ <use>core_write</use>
53
+ </connection>
54
+ </customproduct_write>
55
+ <customproduct_read>
56
+ <connection>
57
+ <use>core_read</use>
58
+ </connection>
59
+ </customproduct_read>
60
+ </resources>
61
+ <blocks>
62
+ <customproduct>
63
+ <class>Blog4mail_Customproduct_Block</class>
64
+ </customproduct>
65
+ </blocks>
66
+ <helpers>
67
+ <customproduct>
68
+ <class>Blog4mail_Customproduct_Helper</class>
69
+ </customproduct>
70
+ </helpers>
71
+ </global>
72
+ </config>
app/code/community/Blog4mail/Customproduct/sql/customproduct_setup/mysql4-install-1.0.0.php ADDED
@@ -0,0 +1,52 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Mashon Sync Update for Dabble Attributes
4
+ *
5
+ * @category Mashon
6
+ * @package Mashon_Sync
7
+ * @copyright Mashon
8
+ * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0)
9
+ */
10
+ $installer = $this;
11
+ $installer->startSetup();
12
+
13
+
14
+ /**
15
+ * Create the editable attribute in the General Attribute Group
16
+ * This determines which Pre-designed products (Magento attribute productType = designed) can be loaded and further edited in Dabble
17
+ */
18
+ $code = 'customperspective';
19
+
20
+ $attr = array(
21
+ 'entity_type_id' => 'catalog_product',
22
+ 'backend_type' => 'varchar',
23
+ 'is_user_defined' => 1,
24
+ 'frontend_input' => 'text',
25
+ 'is_visible' => 0,
26
+ 'label' => 'Custom Perspective',
27
+ 'required' => 0,
28
+ 'user_defined' => 1,
29
+ 'group' => 'General',
30
+ );
31
+
32
+ $setup = new Mage_Eav_Model_Entity_Setup('core_setup');
33
+ $setup->addAttribute('catalog_product', $code, $attr);
34
+
35
+ $code1 = 'customproducttype';
36
+
37
+ $attr1 = array(
38
+ 'entity_type_id' => 'catalog_product',
39
+ 'backend_type' => 'varchar',
40
+ 'is_user_defined' => 1,
41
+ 'frontend_input' => 'text',
42
+ 'is_visible' => 0,
43
+ 'label' => 'Custom Product Type',
44
+ 'required' => 0,
45
+ 'user_defined' => 1,
46
+ 'group' => 'General',
47
+ );
48
+
49
+ $setup1 = new Mage_Eav_Model_Entity_Setup('core_setup');
50
+ $setup1->addAttribute('catalog_product', $code1, $attr1);
51
+
52
+ $installer->endSetup();
app/code/community/Blog4mail/Customproduct/sql/customproduct_setup/mysql4-install-1.0.0.php~ ADDED
@@ -0,0 +1,52 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Mashon Sync Update for Dabble Attributes
4
+ *
5
+ * @category Mashon
6
+ * @package Mashon_Sync
7
+ * @copyright Mashon
8
+ * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0)
9
+ */
10
+ $installer = $this;
11
+ $installer->startSetup();
12
+
13
+
14
+ /**
15
+ * Create the editable attribute in the General Attribute Group
16
+ * This determines which Pre-designed products (Magento attribute productType = designed) can be loaded and further edited in Dabble
17
+ */
18
+ $code = 'customperspective';
19
+
20
+ $attr = array(
21
+ 'entity_type_id' => 'catalog_product',
22
+ 'backend_type' => 'varchar',
23
+ 'is_user_defined' => 1,
24
+ 'frontend_input' => 'text',
25
+ 'is_visible' => 0,
26
+ 'label' => 'Custom Perspective',
27
+ 'required' => 0,
28
+ 'user_defined' => 1,
29
+ 'group' => 'General',
30
+ );
31
+
32
+ $setup = new Mage_Eav_Model_Entity_Setup('core_setup');
33
+ $setup->addAttribute('catalog_product', $code, $attr);
34
+
35
+ $code1 = 'customproducttype';
36
+
37
+ $attr1 = array(
38
+ 'entity_type_id' => 'catalog_product',
39
+ 'backend_type' => 'varchar',
40
+ 'is_user_defined' => 1,
41
+ 'frontend_input' => 'text',
42
+ 'is_visible' => 0,
43
+ 'label' => 'Custom Product Type',
44
+ 'required' => 0,
45
+ 'user_defined' => 1,
46
+ 'group' => 'General',
47
+ );
48
+
49
+ $setup1 = new Mage_Eav_Model_Entity_Setup('core_setup');
50
+ $setup1->addAttribute('catalog_product', $code1, $attr1);
51
+
52
+ $installer->endSetup();
app/code/community/Blog4mail/Customproduct/sql/customproduct_setup/mysql4-install-1.0.php~ ADDED
@@ -0,0 +1,52 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Mashon Sync Update for Dabble Attributes
4
+ *
5
+ * @category Mashon
6
+ * @package Mashon_Sync
7
+ * @copyright Mashon
8
+ * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0)
9
+ */
10
+ $installer = $this;
11
+ $installer->startSetup();
12
+
13
+
14
+ /**
15
+ * Create the editable attribute in the General Attribute Group
16
+ * This determines which Pre-designed products (Magento attribute productType = designed) can be loaded and further edited in Dabble
17
+ */
18
+ $code = 'customperspective';
19
+
20
+ $attr = array(
21
+ 'entity_type_id' => 'catalog_product',
22
+ 'backend_type' => 'varchar',
23
+ 'is_user_defined' => 1,
24
+ 'frontend_input' => 'text',
25
+ 'is_visible' => 0,
26
+ 'label' => 'Custom Perspective',
27
+ 'required' => 0,
28
+ 'user_defined' => 1,
29
+ 'group' => 'General',
30
+ );
31
+
32
+ $setup = new Mage_Eav_Model_Entity_Setup('core_setup');
33
+ $installer->addAttribute('catalog_product', $code, $attr);
34
+
35
+ $code1 = 'customproducttype';
36
+
37
+ $attr1 = array(
38
+ 'entity_type_id' => 'catalog_product',
39
+ 'backend_type' => 'varchar',
40
+ 'is_user_defined' => 1,
41
+ 'frontend_input' => 'text',
42
+ 'is_visible' => 0,
43
+ 'label' => 'Custom Product Type',
44
+ 'required' => 0,
45
+ 'user_defined' => 1,
46
+ 'group' => 'General',
47
+ );
48
+
49
+ $setup1 = new Mage_Eav_Model_Entity_Setup('core_setup');
50
+ $installer->addAttribute('catalog_product', $code, $attr);
51
+
52
+ $installer->endSetup();
app/code/community/Blog4mail/Customproduct/sql/customproduct_setup/mysql4-upgrade-1.0-1.1.php~ ADDED
@@ -0,0 +1,27 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ $this->startSetup();
3
+
4
+
5
+ /**
6
+ * Create The productType attribute in the General Attribute Group
7
+ * This determines what to display on the Product View.phtml and is also needed for Dabble Order Processor
8
+ */
9
+ $code = 'customproducttype';
10
+
11
+ $attr = array(
12
+ 'entity_type_id' => 'catalog_product',
13
+ 'backend_type' => 'varchar',
14
+ 'is_user_defined' => 1,
15
+ 'frontend_input' => 'text',
16
+ 'is_visible' => 0,
17
+ 'label' => 'Custom Product Type',
18
+ 'required' => 0,
19
+ 'user_defined' => 1,
20
+ 'group' => 'General',
21
+ );
22
+
23
+ $setup = new Mage_Eav_Model_Entity_Setup('core_setup');
24
+ $setup->addAttribute('catalog_product', $code, $attr);
25
+
26
+
27
+ $this->endSetup();
app/code/community/Blog4mail/Customproduct/sql/customproduct_setup/mysql4-upgrade-1.3.4-1.4.php~ ADDED
@@ -0,0 +1,34 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Mashon Sync Update for Dabble Attributes
4
+ *
5
+ * @category Mashon
6
+ * @package Mashon_Sync
7
+ * @copyright Mashon
8
+ * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0)
9
+ */
10
+ $this->startSetup();
11
+
12
+
13
+ /**
14
+ * Create the editable attribute in the General Attribute Group
15
+ * This determines which Pre-designed products (Magento attribute productType = designed) can be loaded and further edited in Dabble
16
+ */
17
+ $code = 'customperspective';
18
+
19
+ $attr = array(
20
+ 'entity_type_id' => 'catalog_product',
21
+ 'backend_type' => 'varchar',
22
+ 'is_user_defined' => 1,
23
+ 'frontend_input' => 'text',
24
+ 'is_visible' => 0,
25
+ 'label' => 'Custom Perspective',
26
+ 'required' => 0,
27
+ 'user_defined' => 1,
28
+ 'group' => 'General',
29
+ );
30
+
31
+ $setup = new Mage_Eav_Model_Entity_Setup('core_setup');
32
+ $setup->addAttribute('catalog_product', $code, $attr);
33
+
34
+ $this->endSetup();
app/code/community/Blog4mail/Customproductadmin/Block/Customproduct.php ADDED
@@ -0,0 +1,12 @@
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ class Blog4mail_Customproductadmin_Block_Adminhtml_Customproduct extends Mage_Adminhtml_Block_Widget_Grid_Container
3
+ {
4
+ public function __construct()
5
+ {
6
+ $this->_controller = 'customproductadmin';
7
+ $this->_blockGroup = 'customproductadmin';
8
+ $this->_headerText = Mage::helper('customproductadmin')->__('Item Manager');
9
+ $this->_addButtonLabel = Mage::helper('customproductadmin')->__('Add Item');
10
+ parent::__construct();
11
+ }
12
+ }
app/code/community/Blog4mail/Customproductadmin/Block/Customproduct/Edit.php ADDED
@@ -0,0 +1,45 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ class Blog4mail_Customproductadmin_Block_Customproduct_Edit extends Mage_Adminhtml_Block_Widget_Form_Container
4
+ {
5
+ public function __construct()
6
+ {
7
+ parent::__construct();
8
+
9
+ $this->_objectId = 'id';
10
+ $this->_blockGroup = 'customproductadmin';
11
+ $this->_controller = 'customproductadmin';
12
+
13
+ $this->_updateButton('save', 'label', Mage::helper('customproduct')->__('Save Item'));
14
+ $this->_updateButton('delete', 'label', Mage::helper('customproduct')->__('Delete Item'));
15
+
16
+ $this->_addButton('saveandcontinue', array(
17
+ 'label' => Mage::helper('adminhtml')->__('Save And Continue Edit'),
18
+ 'onclick' => 'saveAndContinueEdit()',
19
+ 'class' => 'save',
20
+ ), -100);
21
+
22
+ $this->_formScripts[] = "
23
+ function toggleEditor() {
24
+ if (tinyMCE.getInstanceById('customproduct_content') == null) {
25
+ tinyMCE.execCommand('mceAddControl', false, 'customproduct_content');
26
+ } else {
27
+ tinyMCE.execCommand('mceRemoveControl', false, 'customproduct_content');
28
+ }
29
+ }
30
+
31
+ function saveAndContinueEdit(){
32
+ editForm.submit($('edit_form').action+'back/edit/');
33
+ }
34
+ ";
35
+ }
36
+
37
+ public function getHeaderText()
38
+ {
39
+ if( Mage::registry('customproduct_data') && Mage::registry('customproduct_data')->getId() ) {
40
+ return Mage::helper('customproduct')->__("Edit Item '%s'", $this->htmlEscape(Mage::registry('customproduct_data')->getTitle()));
41
+ } else {
42
+ return Mage::helper('customproduct')->__('Add Item');
43
+ }
44
+ }
45
+ }
app/code/community/Blog4mail/Customproductadmin/Block/Customproduct/Edit/Form.php ADDED
@@ -0,0 +1,19 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ class Blog4mail_Customproductadmin_Block_Customproduct_Edit_Form extends Mage_Adminhtml_Block_Widget_Form
4
+ {
5
+ protected function _prepareForm()
6
+ {
7
+ $form = new Varien_Data_Form(array(
8
+ 'id' => 'edit_form',
9
+ 'action' => $this->getUrl('*/*/save', array('id' => $this->getRequest()->getParam('id'))),
10
+ 'method' => 'post',
11
+ 'enctype' => 'multipart/form-data'
12
+ )
13
+ );
14
+
15
+ $form->setUseContainer(true);
16
+ $this->setForm($form);
17
+ return parent::_prepareForm();
18
+ }
19
+ }
app/code/community/Blog4mail/Customproductadmin/Block/Customproduct/Edit/Tab/Form.php ADDED
@@ -0,0 +1,58 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ class Blog4mail_Customproductadmin_Block_Customproduct_Edit_Tab_Form extends Mage_Adminhtml_Block_Widget_Form
4
+ {
5
+ protected function _prepareForm()
6
+ {
7
+ $form = new Varien_Data_Form();
8
+ $this->setForm($form);
9
+ $fieldset = $form->addFieldset('customproduct_form', array('legend'=>Mage::helper('customproduct')->__('Item information')));
10
+
11
+ $fieldset->addField('title', 'text', array(
12
+ 'label' => Mage::helper('customproduct')->__('Title'),
13
+ 'class' => 'required-entry',
14
+ 'required' => true,
15
+ 'name' => 'title',
16
+ ));
17
+
18
+ $fieldset->addField('filename', 'file', array(
19
+ 'label' => Mage::helper('customproduct')->__('File'),
20
+ 'required' => false,
21
+ 'name' => 'filename',
22
+ ));
23
+
24
+ $fieldset->addField('status', 'select', array(
25
+ 'label' => Mage::helper('customproduct')->__('Status'),
26
+ 'name' => 'status',
27
+ 'values' => array(
28
+ array(
29
+ 'value' => 1,
30
+ 'label' => Mage::helper('customproduct')->__('Enabled'),
31
+ ),
32
+
33
+ array(
34
+ 'value' => 2,
35
+ 'label' => Mage::helper('customproduct')->__('Disabled'),
36
+ ),
37
+ ),
38
+ ));
39
+
40
+ $fieldset->addField('content', 'editor', array(
41
+ 'name' => 'content',
42
+ 'label' => Mage::helper('customproduct')->__('Content'),
43
+ 'title' => Mage::helper('customproduct')->__('Content'),
44
+ 'style' => 'width:700px; height:500px;',
45
+ 'wysiwyg' => false,
46
+ 'required' => true,
47
+ ));
48
+
49
+ if ( Mage::getSingleton('adminhtml/session')->getCustomproductData() )
50
+ {
51
+ $form->setValues(Mage::getSingleton('adminhtml/session')->getCustomproductData());
52
+ Mage::getSingleton('adminhtml/session')->setCustomproductData(null);
53
+ } elseif ( Mage::registry('customproduct_data') ) {
54
+ $form->setValues(Mage::registry('customproduct_data')->getData());
55
+ }
56
+ return parent::_prepareForm();
57
+ }
58
+ }
app/code/community/Blog4mail/Customproductadmin/Block/Customproduct/Edit/Tabs.php ADDED
@@ -0,0 +1,24 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ class Blog4mail_Customproductadmin_Block_Customproduct_Edit_Tabs extends Mage_Adminhtml_Block_Widget_Tabs
4
+ {
5
+
6
+ public function __construct()
7
+ {
8
+ parent::__construct();
9
+ $this->setId('customproductadmin_tabs');
10
+ $this->setDestElementId('edit_form');
11
+ $this->setTitle(Mage::helper('customproduct')->__('Item Information'));
12
+ }
13
+
14
+ protected function _beforeToHtml()
15
+ {
16
+ $this->addTab('form_section', array(
17
+ 'label' => Mage::helper('customproduct')->__('Item Information'),
18
+ 'title' => Mage::helper('customproduct')->__('Item Information'),
19
+ 'content' => $this->getLayout()->createBlock('customproduct/adminhtml_customproduct_edit_tab_form')->toHtml(),
20
+ ));
21
+
22
+ return parent::_beforeToHtml();
23
+ }
24
+ }
app/code/community/Blog4mail/Customproductadmin/Block/Customproduct/Grid.php ADDED
@@ -0,0 +1,116 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ class Blog4mail_Customproductadmin_Block_Customproduct_Grid extends Mage_Adminhtml_Block_Widget_Grid
4
+ {
5
+ public function __construct()
6
+ {
7
+ parent::__construct();
8
+ $this->setId('customproductadminGrid');
9
+ $this->setDefaultSort('customproduct_id');
10
+ $this->setDefaultDir('ASC');
11
+ $this->setSaveParametersInSession(true);
12
+ }
13
+
14
+ protected function _prepareCollection()
15
+ {
16
+ $collection = Mage::getModel('customproduct/customproduct')->getCollection();
17
+ $this->setCollection($collection);
18
+ return parent::_prepareCollection();
19
+ }
20
+
21
+ protected function _prepareColumns()
22
+ {
23
+ $this->addColumn('customproduct_id', array(
24
+ 'header' => Mage::helper('customproduct')->__('ID'),
25
+ 'align' =>'right',
26
+ 'width' => '50px',
27
+ 'index' => 'customproduct_id',
28
+ ));
29
+
30
+ $this->addColumn('title', array(
31
+ 'header' => Mage::helper('customproduct')->__('Title'),
32
+ 'align' =>'left',
33
+ 'index' => 'title',
34
+ ));
35
+
36
+ /*
37
+ $this->addColumn('content', array(
38
+ 'header' => Mage::helper('customproduct')->__('Item Content'),
39
+ 'width' => '150px',
40
+ 'index' => 'content',
41
+ ));
42
+ */
43
+
44
+ $this->addColumn('status', array(
45
+ 'header' => Mage::helper('customproduct')->__('Status'),
46
+ 'align' => 'left',
47
+ 'width' => '80px',
48
+ 'index' => 'status',
49
+ 'type' => 'options',
50
+ 'options' => array(
51
+ 1 => 'Enabled',
52
+ 2 => 'Disabled',
53
+ ),
54
+ ));
55
+
56
+ $this->addColumn('action',
57
+ array(
58
+ 'header' => Mage::helper('customproduct')->__('Action'),
59
+ 'width' => '100',
60
+ 'type' => 'action',
61
+ 'getter' => 'getId',
62
+ 'actions' => array(
63
+ array(
64
+ 'caption' => Mage::helper('customproduct')->__('Edit'),
65
+ 'url' => array('base'=> '*/*/edit'),
66
+ 'field' => 'id'
67
+ )
68
+ ),
69
+ 'filter' => false,
70
+ 'sortable' => false,
71
+ 'index' => 'stores',
72
+ 'is_system' => true,
73
+ ));
74
+
75
+ $this->addExportType('*/*/exportCsv', Mage::helper('customproduct')->__('CSV'));
76
+ $this->addExportType('*/*/exportXml', Mage::helper('customproduct')->__('XML'));
77
+
78
+ return parent::_prepareColumns();
79
+ }
80
+
81
+ protected function _prepareMassaction()
82
+ {
83
+ $this->setMassactionIdField('customproduct_id');
84
+ $this->getMassactionBlock()->setFormFieldName('customproduct');
85
+
86
+ $this->getMassactionBlock()->addItem('delete', array(
87
+ 'label' => Mage::helper('customproduct')->__('Delete'),
88
+ 'url' => $this->getUrl('*/*/massDelete'),
89
+ 'confirm' => Mage::helper('customproduct')->__('Are you sure?')
90
+ ));
91
+
92
+ $statuses = Mage::getSingleton('customproduct/status')->getOptionArray();
93
+
94
+ array_unshift($statuses, array('label'=>'', 'value'=>''));
95
+ $this->getMassactionBlock()->addItem('status', array(
96
+ 'label'=> Mage::helper('customproduct')->__('Change status'),
97
+ 'url' => $this->getUrl('*/*/massStatus', array('_current'=>true)),
98
+ 'additional' => array(
99
+ 'visibility' => array(
100
+ 'name' => 'status',
101
+ 'type' => 'select',
102
+ 'class' => 'required-entry',
103
+ 'label' => Mage::helper('customproduct')->__('Status'),
104
+ 'values' => $statuses
105
+ )
106
+ )
107
+ ));
108
+ return $this;
109
+ }
110
+
111
+ public function getRowUrl($row)
112
+ {
113
+ return $this->getUrl('*/*/edit', array('id' => $row->getId()));
114
+ }
115
+
116
+ }
app/code/community/Blog4mail/Customproductadmin/Helper/Data.php ADDED
@@ -0,0 +1,6 @@
 
 
 
 
 
 
1
+ <?php
2
+
3
+ class Blog4mail_Customproductadmin_Helper_Data extends Mage_Core_Helper_Abstract
4
+ {
5
+
6
+ }
app/code/community/Blog4mail/Customproductadmin/controllers/CustomproductController.php ADDED
@@ -0,0 +1,214 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ class Blog4mail_Customproductadmin_CustomproductController extends Mage_Adminhtml_Controller_action
4
+ {
5
+
6
+ protected function _initAction() {
7
+ $this->loadLayout()
8
+ ->_setActiveMenu('customproductadmin/items')
9
+ ->_addBreadcrumb(Mage::helper('adminhtml')->__('Items Manager'), Mage::helper('adminhtml')->__('Item Manager'));
10
+
11
+ return $this;
12
+ }
13
+
14
+ public function indexAction() {
15
+ $this->_initAction()
16
+ ->renderLayout();
17
+ }
18
+
19
+ public function editAction() {
20
+ $id = $this->getRequest()->getParam('id');
21
+ $model = Mage::getModel('customproduct/customproduct')->load($id);
22
+
23
+ if ($model->getId() || $id == 0) {
24
+ $data = Mage::getSingleton('adminhtml/session')->getFormData(true);
25
+ if (!empty($data)) {
26
+ $model->setData($data);
27
+ }
28
+
29
+ Mage::register('customproduct_data', $model);
30
+
31
+ $this->loadLayout();
32
+ $this->_setActiveMenu('customproduct/items');
33
+
34
+ $this->_addBreadcrumb(Mage::helper('adminhtml')->__('Item Manager'), Mage::helper('adminhtml')->__('Item Manager'));
35
+ $this->_addBreadcrumb(Mage::helper('adminhtml')->__('Item News'), Mage::helper('adminhtml')->__('Item News'));
36
+
37
+ $this->getLayout()->getBlock('head')->setCanLoadExtJs(true);
38
+
39
+ $this->_addContent($this->getLayout()->createBlock('customproduct/adminhtml_customproduct_edit'))
40
+ ->_addLeft($this->getLayout()->createBlock('customproduct/adminhtml_customproduct_edit_tabs'));
41
+
42
+ $this->renderLayout();
43
+ } else {
44
+ Mage::getSingleton('adminhtml/session')->addError(Mage::helper('customproduct')->__('Item does not exist'));
45
+ $this->_redirect('*/*/');
46
+ }
47
+ }
48
+
49
+ public function newAction() {
50
+ $this->_forward('edit');
51
+ }
52
+
53
+ public function saveAction() {
54
+ if ($data = $this->getRequest()->getPost()) {
55
+
56
+ if(isset($_FILES['filename']['name']) && $_FILES['filename']['name'] != '') {
57
+ try {
58
+ /* Starting upload */
59
+ $uploader = new Varien_File_Uploader('filename');
60
+
61
+ // Any extention would work
62
+ $uploader->setAllowedExtensions(array('jpg','jpeg','gif','png'));
63
+ $uploader->setAllowRenameFiles(false);
64
+
65
+ // Set the file upload mode
66
+ // false -> get the file directly in the specified folder
67
+ // true -> get the file in the product like folders
68
+ // (file.jpg will go in something like /media/f/i/file.jpg)
69
+ $uploader->setFilesDispersion(false);
70
+
71
+ // We set media as the upload dir
72
+ $path = Mage::getBaseDir('media') . DS ;
73
+ $uploader->save($path, $_FILES['filename']['name'] );
74
+
75
+ } catch (Exception $e) {
76
+
77
+ }
78
+
79
+ //this way the name is saved in DB
80
+ $data['filename'] = $_FILES['filename']['name'];
81
+ }
82
+
83
+
84
+ $model = Mage::getModel('customproduct/customproduct');
85
+ $model->setData($data)
86
+ ->setId($this->getRequest()->getParam('id'));
87
+
88
+ try {
89
+ if ($model->getCreatedTime == NULL || $model->getUpdateTime() == NULL) {
90
+ $model->setCreatedTime(now())
91
+ ->setUpdateTime(now());
92
+ } else {
93
+ $model->setUpdateTime(now());
94
+ }
95
+
96
+ $model->save();
97
+ Mage::getSingleton('adminhtml/session')->addSuccess(Mage::helper('customproduct')->__('Item was successfully saved'));
98
+ Mage::getSingleton('adminhtml/session')->setFormData(false);
99
+
100
+ if ($this->getRequest()->getParam('back')) {
101
+ $this->_redirect('*/*/edit', array('id' => $model->getId()));
102
+ return;
103
+ }
104
+ $this->_redirect('*/*/');
105
+ return;
106
+ } catch (Exception $e) {
107
+ Mage::getSingleton('adminhtml/session')->addError($e->getMessage());
108
+ Mage::getSingleton('adminhtml/session')->setFormData($data);
109
+ $this->_redirect('*/*/edit', array('id' => $this->getRequest()->getParam('id')));
110
+ return;
111
+ }
112
+ }
113
+ Mage::getSingleton('adminhtml/session')->addError(Mage::helper('customproduct')->__('Unable to find item to save'));
114
+ $this->_redirect('*/*/');
115
+ }
116
+
117
+ public function deleteAction() {
118
+ if( $this->getRequest()->getParam('id') > 0 ) {
119
+ try {
120
+ $model = Mage::getModel('customproduct/customproduct');
121
+
122
+ $model->setId($this->getRequest()->getParam('id'))
123
+ ->delete();
124
+
125
+ Mage::getSingleton('adminhtml/session')->addSuccess(Mage::helper('adminhtml')->__('Item was successfully deleted'));
126
+ $this->_redirect('*/*/');
127
+ } catch (Exception $e) {
128
+ Mage::getSingleton('adminhtml/session')->addError($e->getMessage());
129
+ $this->_redirect('*/*/edit', array('id' => $this->getRequest()->getParam('id')));
130
+ }
131
+ }
132
+ $this->_redirect('*/*/');
133
+ }
134
+
135
+ public function massDeleteAction() {
136
+ $customproductIds = $this->getRequest()->getParam('customproduct');
137
+ if(!is_array($customproductIds)) {
138
+ Mage::getSingleton('adminhtml/session')->addError(Mage::helper('adminhtml')->__('Please select item(s)'));
139
+ } else {
140
+ try {
141
+ foreach ($customproductIds as $customproductId) {
142
+ $customproduct = Mage::getModel('customproduct/customproduct')->load($customproductId);
143
+ $customproduct->delete();
144
+ }
145
+ Mage::getSingleton('adminhtml/session')->addSuccess(
146
+ Mage::helper('adminhtml')->__(
147
+ 'Total of %d record(s) were successfully deleted', count($customproductIds)
148
+ )
149
+ );
150
+ } catch (Exception $e) {
151
+ Mage::getSingleton('adminhtml/session')->addError($e->getMessage());
152
+ }
153
+ }
154
+ $this->_redirect('*/*/index');
155
+ }
156
+
157
+ public function massStatusAction()
158
+ {
159
+ $customproductIds = $this->getRequest()->getParam('customproduct');
160
+ if(!is_array($customproductIds)) {
161
+ Mage::getSingleton('adminhtml/session')->addError($this->__('Please select item(s)'));
162
+ } else {
163
+ try {
164
+ foreach ($customproductIds as $customproductId) {
165
+ $customproduct = Mage::getSingleton('customproduct/customproduct')
166
+ ->load($customproductId)
167
+ ->setStatus($this->getRequest()->getParam('status'))
168
+ ->setIsMassupdate(true)
169
+ ->save();
170
+ }
171
+ $this->_getSession()->addSuccess(
172
+ $this->__('Total of %d record(s) were successfully updated', count($customproductIds))
173
+ );
174
+ } catch (Exception $e) {
175
+ $this->_getSession()->addError($e->getMessage());
176
+ }
177
+ }
178
+ $this->_redirect('*/*/index');
179
+ }
180
+
181
+ public function exportCsvAction()
182
+ {
183
+ $fileName = 'customproduct.csv';
184
+ $content = $this->getLayout()->createBlock('customproduct/adminhtml_customproduct_grid')
185
+ ->getCsv();
186
+
187
+ $this->_sendUploadResponse($fileName, $content);
188
+ }
189
+
190
+ public function exportXmlAction()
191
+ {
192
+ $fileName = 'customproduct.xml';
193
+ $content = $this->getLayout()->createBlock('customproduct/adminhtml_customproduct_grid')
194
+ ->getXml();
195
+
196
+ $this->_sendUploadResponse($fileName, $content);
197
+ }
198
+
199
+ protected function _sendUploadResponse($fileName, $content, $contentType='application/octet-stream')
200
+ {
201
+ $response = $this->getResponse();
202
+ $response->setHeader('HTTP/1.1 200 OK','');
203
+ $response->setHeader('Pragma', 'public', true);
204
+ $response->setHeader('Cache-Control', 'must-revalidate, post-check=0, pre-check=0', true);
205
+ $response->setHeader('Content-Disposition', 'attachment; filename='.$fileName);
206
+ $response->setHeader('Last-Modified', date('r'));
207
+ $response->setHeader('Accept-Ranges', 'bytes');
208
+ $response->setHeader('Content-Length', strlen($content));
209
+ $response->setHeader('Content-type', $contentType);
210
+ $response->setBody($content);
211
+ $response->sendResponse();
212
+ die;
213
+ }
214
+ }
app/code/community/Blog4mail/Customproductadmin/etc/config.xml ADDED
@@ -0,0 +1,68 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?xml version="1.0"?>
2
+ <config>
3
+ <modules>
4
+ <Blog4mail_Customproductadmin>
5
+ <version>0.1.0</version>
6
+ </Blog4mail_Customproductadmin>
7
+ </modules>
8
+ <admin>
9
+ <routers>
10
+ <customproductadmin>
11
+ <use>admin</use>
12
+ <args>
13
+ <module>Blog4mail_Customproductadmin</module>
14
+ <frontName>customproductadmin</frontName>
15
+ </args>
16
+ </customproductadmin>
17
+ </routers>
18
+ </admin>
19
+ <adminhtml>
20
+ <menu>
21
+ <customproductadmin module="customproductadmin">
22
+ <title>Customproduct</title>
23
+ <sort_order>71</sort_order>
24
+ <children>
25
+ <items module="customproductadmin">
26
+ <title>Manage Items</title>
27
+ <sort_order>0</sort_order>
28
+ <action>customproductadmin/customproduct</action>
29
+ </items>
30
+ </children>
31
+ </customproductadmin>
32
+ </menu>
33
+ <acl>
34
+ <resources>
35
+ <all>
36
+ <title>Allow Everything</title>
37
+ </all>
38
+ <admin>
39
+ <children>
40
+ <Blog4mail_Customproductadmin>
41
+ <title>Customproduct Module</title>
42
+ <sort_order>10</sort_order>
43
+ </Blog4mail_Customproductadmin>
44
+ </children>
45
+ </admin>
46
+ </resources>
47
+ </acl>
48
+ <layout>
49
+ <updates>
50
+ <customproductadmin>
51
+ <file>customproductadmin.xml</file>
52
+ </customproductadmin>
53
+ </updates>
54
+ </layout>
55
+ </adminhtml>
56
+ <global>
57
+ <blocks>
58
+ <customproductadmin>
59
+ <class>Blog4mail_Customproductadmin_Block</class>
60
+ </customproductadmin>
61
+ </blocks>
62
+ <helpers>
63
+ <customproductadmin>
64
+ <class>Blog4mail_Customproductadmin_Helper</class>
65
+ </customproductadmin>
66
+ </helpers>
67
+ </global>
68
+ </config>
app/code/community/Blog4mail/customproduct_catalog.xml~ ADDED
@@ -0,0 +1,93 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?xml version="1.0"?>
2
+ <layout version="0.1.0">
3
+ <catalog_product_view translate="label">
4
+ <label>Catalog Product View (Any)</label>
5
+ <!-- Mage_Catalog -->
6
+ <reference name="root">
7
+ <action method="setTemplate"><template>page/2columns-right.phtml</template></action>
8
+ </reference>
9
+ <reference name="head">
10
+ <action method="addJs"><script>varien/product.js</script></action>
11
+ <action method="addJs"><script>varien/configurable.js</script></action>
12
+
13
+ <action method="addItem"><type>js_css</type><name>calendar/calendar-win2k-1.css</name><params/><!--<if/><condition>can_load_calendar_js</condition>--></action>
14
+ <action method="addItem"><type>js</type><name>calendar/calendar.js</name><!--<params/><if/><condition>can_load_calendar_js</condition>--></action>
15
+ <action method="addItem"><type>js</type><name>calendar/calendar-setup.js</name><!--<params/><if/><condition>can_load_calendar_js</condition>--></action>
16
+ </reference>
17
+ <reference name="content">
18
+ <block type="catalog/product_view" name="product.info" template="catalog/product/view_custom.phtml">
19
+ <!--
20
+ <action method="addReviewSummaryTemplate"><type>default</type><template>review/helper/summary.phtml</template></action>
21
+ <action method="addReviewSummaryTemplate"><type>short</type><template>review/helper/summary_short.phtml</template></action>
22
+ <action method="addReviewSummaryTemplate"><type>...</type><template>...</template></action>
23
+ -->
24
+ <block type="catalog/product_view_media" name="product.info.media" as="media" template="catalog/product/view/media_custom.phtml"/>
25
+ <block type="core/text_list" name="alert.urls" as="alert_urls" translate="label">
26
+ <label>Alert Urls</label>
27
+ </block>
28
+
29
+ <action method="setTierPriceTemplate"><template>catalog/product/view/tierprices.phtml</template></action>
30
+
31
+ <block type="catalog/product_list_upsell" name="product.info.upsell" as="upsell_products" template="catalog/product/list/upsell.phtml">
32
+ <action method="setColumnCount"><columns>4</columns></action>
33
+ <action method="setItemLimit"><type>upsell</type><limit>4</limit></action>
34
+ </block>
35
+
36
+ <block type="catalog/product_view_additional" name="product.info.additional" as="product_additional_data" />
37
+ <block type="catalog/product_view_description" name="product.description" as="description" template="catalog/product/view/description.phtml">
38
+ <action method="addToParentGroup"><group>detailed_info</group></action>
39
+ </block>
40
+ <block type="catalog/product_view_attributes" name="product.attributes" as="additional" template="catalog/product/view/attributes.phtml">
41
+ <action method="addToParentGroup"><group>detailed_info</group></action>
42
+ </block>
43
+ <block type="catalog/product_view" name="product.info.addto" as="addto" template="catalog/product/view/addto.phtml"/>
44
+ <block type="catalog/product_view" name="product.info.addtocart" as="addtocart" template="catalog/product/view/addtocart.phtml"/>
45
+
46
+ <block type="core/text_list" name="product.info.extrahint" as="extrahint" translate="label">
47
+ <label>Product View Extra Hint</label>
48
+ </block>
49
+
50
+ <block type="catalog/product_view" name="product.info.options.wrapper" as="product_options_wrapper" template="catalog/product/view/options/wrapper.phtml" translate="label">
51
+ <label>Info Column Options Wrapper</label>
52
+ <block type="core/template" name="options_js" template="catalog/product/view/options/js.phtml"/>
53
+ <block type="catalog/product_view_options" name="product.info.options" as="product_options" template="catalog/product/view/options.phtml">
54
+ <action method="addOptionRenderer"><type>text</type><block>catalog/product_view_options_type_text</block><template>catalog/product/view/options/type/text.phtml</template></action>
55
+ <action method="addOptionRenderer"><type>file</type><block>catalog/product_view_options_type_file</block><template>catalog/product/view/options/type/file.phtml</template></action>
56
+ <action method="addOptionRenderer"><type>select</type><block>catalog/product_view_options_type_select</block><template>catalog/product/view/options/type/select.phtml</template></action>
57
+ <action method="addOptionRenderer"><type>date</type><block>catalog/product_view_options_type_date</block><template>catalog/product/view/options/type/date.phtml</template></action>
58
+ </block>
59
+ <block type="core/html_calendar" name="html_calendar" as="html_calendar" template="page/js/calendar.phtml"/>
60
+ </block>
61
+ <block type="catalog/product_view" name="product.info.options.wrapper.bottom" as="product_options_wrapper_bottom" template="catalog/product/view/options/wrapper/bottom.phtml" translate="label">
62
+ <label>Bottom Block Options Wrapper</label>
63
+ <action method="insert"><block>product.tierprices</block></action>
64
+ <block type="catalog/product_view" name="product.clone_prices" as="prices" template="catalog/product/view/price_clone.phtml"/>
65
+ <action method="append"><block>product.info.addtocart</block></action>
66
+ <action method="append"><block>product.info.addto</block></action>
67
+ </block>
68
+
69
+ <block type="core/template_facade" name="product.info.container1" as="container1">
70
+ <action method="setDataByKey"><key>alias_in_layout</key><value>container1</value></action>
71
+ <action method="setDataByKeyFromRegistry"><key>options_container</key><key_in_registry>product</key_in_registry></action>
72
+ <action method="append"><block>product.info.options.wrapper</block></action>
73
+ <action method="append"><block>product.info.options.wrapper.bottom</block></action>
74
+ </block>
75
+ <block type="core/template_facade" name="product.info.container2" as="container2">
76
+ <action method="setDataByKey"><key>alias_in_layout</key><value>container2</value></action>
77
+ <action method="setDataByKeyFromRegistry"><key>options_container</key><key_in_registry>product</key_in_registry></action>
78
+ <action method="append"><block>product.info.options.wrapper</block></action>
79
+ <action method="append"><block>product.info.options.wrapper.bottom</block></action>
80
+ </block>
81
+ <action method="unsetCallChild"><child>container1</child><call>ifEquals</call><if>0</if><key>alias_in_layout</key><key>options_container</key></action>
82
+ <action method="unsetCallChild"><child>container2</child><call>ifEquals</call><if>0</if><key>alias_in_layout</key><key>options_container</key></action>
83
+ </block>
84
+ </reference>
85
+ <reference name="right">
86
+ <block type="catalog/product_list_related" name="catalog.product.related" before="-" template="catalog/product/list/related.phtml"/>
87
+ </reference>
88
+ </catalog_product_view>
89
+
90
+ </layout>
91
+
92
+
93
+
app/design/frontend/base/default/layout/customproduct_catalog.xml ADDED
@@ -0,0 +1,252 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?xml version="1.0"?>
2
+
3
+ <layout version="0.1.0">
4
+ <!--
5
+ Product view
6
+ -->
7
+
8
+ <catalog_product_view translate="label">
9
+ <label>Catalog Product View (Any)</label>
10
+ <!-- Mage_Catalog -->
11
+ <reference name="root">
12
+ <action method="setTemplate"><template>page/2columns-right.phtml</template></action>
13
+ </reference>
14
+ <reference name="head">
15
+ <action method="addJs"><script>varien/product.js</script></action>
16
+ <action method="addJs"><script>varien/configurable.js</script></action>
17
+
18
+ <action method="addItem"><type>js_css</type><name>calendar/calendar-win2k-1.css</name><params/><!--<if/><condition>can_load_calendar_js</condition>--></action>
19
+ <action method="addItem"><type>js</type><name>calendar/calendar.js</name><!--<params/><if/><condition>can_load_calendar_js</condition>--></action>
20
+ <action method="addItem"><type>js</type><name>calendar/calendar-setup.js</name><!--<params/><if/><condition>can_load_calendar_js</condition>--></action>
21
+ </reference>
22
+ <reference name="content">
23
+ <block type="catalog/product_view" name="product.info" template="catalog/product/view_custom.phtml">
24
+
25
+ <!--
26
+ <action method="addReviewSummaryTemplate"><type>default</type><template>review/helper/summary.phtml</template></action>
27
+ <action method="addReviewSummaryTemplate"><type>short</type><template>review/helper/summary_short.phtml</template></action>
28
+ <action method="addReviewSummaryTemplate"><type>...</type><template>...</template></action>
29
+ -->
30
+ <block type="catalog/product_view_media" name="product.info.media" as="media" template="catalog/product/view/media_custom.phtml"/>
31
+ <block type="core/text_list" name="alert.urls" as="alert_urls" translate="label">
32
+ <label>Alert Urls</label>
33
+ </block>
34
+
35
+ <action method="setTierPriceTemplate"><template>catalog/product/view/tierprices.phtml</template></action>
36
+
37
+ <block type="catalog/product_list_upsell" name="product.info.upsell" as="upsell_products" template="catalog/product/list/upsell.phtml">
38
+ <action method="setColumnCount"><columns>4</columns></action>
39
+ <action method="setItemLimit"><type>upsell</type><limit>4</limit></action>
40
+ </block>
41
+
42
+ <block type="catalog/product_view_additional" name="product.info.additional" as="product_additional_data" />
43
+ <block type="catalog/product_view_description" name="product.description" as="description" template="catalog/product/view/description.phtml">
44
+ <action method="addToParentGroup"><group>detailed_info</group></action>
45
+ </block>
46
+ <block type="catalog/product_view_attributes" name="product.attributes" as="additional" template="catalog/product/view/attributes.phtml">
47
+ <action method="addToParentGroup"><group>detailed_info</group></action>
48
+ </block>
49
+ <block type="catalog/product_view" name="product.info.addto" as="addto" template="catalog/product/view/addto.phtml"/>
50
+ <block type="catalog/product_view" name="product.info.addtocart" as="addtocart" template="catalog/product/view/addtocart.phtml"/>
51
+
52
+ <block type="core/text_list" name="product.info.extrahint" as="extrahint" translate="label">
53
+ <label>Product View Extra Hint</label>
54
+ </block>
55
+
56
+ <block type="catalog/product_view" name="product.info.options.wrapper" as="product_options_wrapper" template="catalog/product/view/options/wrapper.phtml" translate="label">
57
+ <label>Info Column Options Wrapper</label>
58
+ <block type="core/template" name="options_js" template="catalog/product/view/options/js.phtml"/>
59
+ <block type="catalog/product_view_options" name="product.info.options" as="product_options" template="catalog/product/view/options.phtml">
60
+ <action method="addOptionRenderer"><type>text</type><block>catalog/product_view_options_type_text</block><template>catalog/product/view/options/type/text.phtml</template></action>
61
+ <action method="addOptionRenderer"><type>file</type><block>catalog/product_view_options_type_file</block><template>catalog/product/view/options/type/file.phtml</template></action>
62
+ <action method="addOptionRenderer"><type>select</type><block>catalog/product_view_options_type_select</block><template>catalog/product/view/options/type/select.phtml</template></action>
63
+ <action method="addOptionRenderer"><type>date</type><block>catalog/product_view_options_type_date</block><template>catalog/product/view/options/type/date.phtml</template></action>
64
+ </block>
65
+ <block type="core/html_calendar" name="html_calendar" as="html_calendar" template="page/js/calendar.phtml"/>
66
+ </block>
67
+ <block type="catalog/product_view" name="product.info.options.wrapper.bottom" as="product_options_wrapper_bottom" template="catalog/product/view/options/wrapper/bottom.phtml" translate="label">
68
+ <label>Bottom Block Options Wrapper</label>
69
+ <action method="insert"><block>product.tierprices</block></action>
70
+ <block type="catalog/product_view" name="product.clone_prices" as="prices" template="catalog/product/view/price_clone.phtml"/>
71
+ <action method="append"><block>product.info.addtocart</block></action>
72
+ <action method="append"><block>product.info.addto</block></action>
73
+ </block>
74
+
75
+ <block type="core/template_facade" name="product.info.container1" as="container1">
76
+ <action method="setDataByKey"><key>alias_in_layout</key><value>container1</value></action>
77
+ <action method="setDataByKeyFromRegistry"><key>options_container</key><key_in_registry>product</key_in_registry></action>
78
+ <action method="append"><block>product.info.options.wrapper</block></action>
79
+ <action method="append"><block>product.info.options.wrapper.bottom</block></action>
80
+ </block>
81
+ <block type="core/template_facade" name="product.info.container2" as="container2">
82
+ <action method="setDataByKey"><key>alias_in_layout</key><value>container2</value></action>
83
+ <action method="setDataByKeyFromRegistry"><key>options_container</key><key_in_registry>product</key_in_registry></action>
84
+ <action method="append"><block>product.info.options.wrapper</block></action>
85
+ <action method="append"><block>product.info.options.wrapper.bottom</block></action>
86
+ </block>
87
+ <action method="unsetCallChild"><child>container1</child><call>ifEquals</call><if>0</if><key>alias_in_layout</key><key>options_container</key></action>
88
+ <action method="unsetCallChild"><child>container2</child><call>ifEquals</call><if>0</if><key>alias_in_layout</key><key>options_container</key></action>
89
+ </block>
90
+ </reference>
91
+ <reference name="right">
92
+ <block type="catalog/product_list_related" name="catalog.product.related" before="-" template="catalog/product/list/related.phtml"/>
93
+ </reference>
94
+ </catalog_product_view>
95
+
96
+ <!--
97
+ Additional block dependant on product type
98
+ -->
99
+ <PRODUCT_TYPE_simple translate="label" module="catalog">
100
+ <label>Catalog Product View (Simple)</label>
101
+ <reference name="product.info">
102
+ <block type="catalog/product_view_type_simple" name="product.info.simple" as="product_type_data" template="catalog/product/view/type/default.phtml">
103
+ <block type="core/text_list" name="product.info.simple.extra" as="product_type_data_extra" translate="label">
104
+ <label>Product Extra Info</label>
105
+ </block>
106
+ </block>
107
+ </reference>
108
+ </PRODUCT_TYPE_simple>
109
+ <PRODUCT_TYPE_configurable translate="label" module="catalog">
110
+ <label>Catalog Product View (Configurable)</label>
111
+ <reference name="product.info">
112
+ <block type="catalog/product_view_type_configurable" name="product.info.configurable" as="product_type_data" template="catalog/product/view/type/default.phtml">
113
+ <block type="core/text_list" name="product.info.configurable.extra" as="product_type_data_extra" translate="label">
114
+ <label>Product Extra Info</label>
115
+ </block>
116
+ </block>
117
+ </reference>
118
+ <reference name="product.info.options.wrapper">
119
+ <block type="catalog/product_view_type_configurable" name="product.info.options.configurable" as="options_configurable" before="-" template="catalog/product/view/type/options/configurable.phtml"/>
120
+ </reference>
121
+ </PRODUCT_TYPE_configurable>
122
+ <PRODUCT_TYPE_grouped translate="label" module="catalog">
123
+ <label>Catalog Product View (Grouped)</label>
124
+ <reference name="product.info">
125
+ <block type="catalog/product_view_type_grouped" name="product.info.grouped" as="product_type_data" template="catalog/product/view/type/grouped.phtml">
126
+ <block type="core/text_list" name="product.info.grouped.extra" as="product_type_data_extra" translate="label">
127
+ <label>Product Extra Info</label>
128
+ </block>
129
+ </block>
130
+ </reference>
131
+ </PRODUCT_TYPE_grouped>
132
+ <PRODUCT_TYPE_virtual translate="label" module="catalog">
133
+ <label>Catalog Product View (Virtual)</label>
134
+ <reference name="product.info">
135
+ <block type="catalog/product_view_type_virtual" name="product.info.virtual" as="product_type_data" template="catalog/product/view/type/default.phtml">
136
+ <block type="core/text_list" name="product.info.virtual.extra" as="product_type_data_extra" translate="label">
137
+ <label>Product Extra Info</label>
138
+ </block>
139
+ </block>
140
+ </reference>
141
+ </PRODUCT_TYPE_virtual>
142
+
143
+
144
+
145
+ <!--
146
+ Product send to friend
147
+ -->
148
+
149
+ <catalog_product_send translate="label">
150
+ <label>Catalog Product Email to a Friend</label>
151
+ <!-- Mage_Catalog -->
152
+ <reference name="root">
153
+ <action method="setTemplate"><template>page/2columns-right.phtml</template></action>
154
+ </reference>
155
+ <reference name="head">
156
+ <action method="addJs"><script>varien/product.js</script></action>
157
+ </reference>
158
+ <reference name="content">
159
+ <block type="catalog/product_send" name="product.send" template="catalog/product/send.phtml">
160
+ </block>
161
+ </reference>
162
+ </catalog_product_send>
163
+
164
+ <!--
165
+ Product additional images gallery popup
166
+ -->
167
+
168
+ <catalog_product_gallery translate="label">
169
+ <label>Catalog Product Image Gallery Popup</label>
170
+ <!-- Mage_Catalog -->
171
+ <reference name="root">
172
+ <action method="setTemplate"><template>page/popup.phtml</template></action>
173
+ </reference>
174
+ <reference name="content">
175
+ <block type="catalog/product_gallery" name="catalog_product_gallery" template="catalog/product/gallery.phtml"/>
176
+ </reference>
177
+ </catalog_product_gallery>
178
+
179
+ <!--
180
+ SEO Site Map
181
+ -->
182
+
183
+ <catalog_seo_sitemap translate="label">
184
+ <label>Catalog Seo Sitemap (Common)</label>
185
+ <remove name="right"/>
186
+ <remove name="left"/>
187
+
188
+ <reference name="root">
189
+ <action method="setTemplate"><template>page/1column.phtml</template></action>
190
+ </reference>
191
+ <reference name="content">
192
+ <block type="page/template_container" name="seo.sitemap.container" template="catalog/seo/sitemap/container.phtml">
193
+ <block type="page/template_links" name="seo.sitemap.links" as="links" template="page/template/links.phtml"/>
194
+ <block type="page/html_pager" name="seo.sitemap.pager.top" as="pager_top" template="page/html/pager.phtml"/>
195
+ <block type="page/html_pager" name="seo.sitemap.pager.bottom" as="pager_bottom" template="page/html/pager.phtml"/>
196
+ </block>
197
+ </reference>
198
+ </catalog_seo_sitemap>
199
+
200
+ <catalog_seo_sitemap_category translate="label">
201
+ <label>Catalog Seo Sitemap (Category List)</label>
202
+ <reference name="head">
203
+ <action method="setTitle" translate="title" module="catalog"><title>Site Map</title></action>
204
+ </reference>
205
+ <update handle="catalog_seo_sitemap" />
206
+ <reference name="seo.sitemap.container">
207
+ <action method="setTitle" translate="title" module="catalog"><title>Categories</title></action>
208
+ <block type="catalog/seo_sitemap_category" name="seo.sitemap.sitemap" as="sitemap" after="pager_top" template="catalog/seo/sitemap.phtml">
209
+ <action method="bindPager"><pager>seo.sitemap.pager.top</pager></action>
210
+ <action method="bindPager"><pager>seo.sitemap.pager.bottom</pager></action>
211
+ <action method="setItemsTitle" translate="title" module="catalog"><title>categories</title></action>
212
+ </block>
213
+ </reference>
214
+ <reference name="seo.sitemap.links">
215
+ <action method="addLink" translate="label title" module="catalog"><label>Products Sitemap</label><url helper="catalog/map/getProductUrl"/><title>Products Sitemap</title></action>
216
+ </reference>
217
+ </catalog_seo_sitemap_category>
218
+
219
+ <catalog_seo_sitemap_category_tree translate="label">
220
+ <label>Catalog Seo Sitemap (Category Tree)</label>
221
+ <reference name="seo.sitemap.container">
222
+ <remove name="seo.sitemap.pager.top" />
223
+ <remove name="seo.sitemap.pager.bottom" />
224
+ <block type="catalog/seo_sitemap_tree_pager" name="seo.sitemap.tree.pager.top" as="pager_top" template="page/html/pager.phtml"/>
225
+ <block type="catalog/seo_sitemap_tree_pager" name="seo.sitemap.tree.pager.bottom" as="pager_bottom" template="page/html/pager.phtml"/>
226
+ <remove name="seo.sitemap.sitemap" />
227
+ <block type="catalog/seo_sitemap_tree_category" name="seo.sitemap.sitemap_tree" as="sitemap" after="pager_top" template="catalog/seo/tree.phtml">
228
+ <action method="bindPager"><pager>seo.sitemap.tree.pager.top</pager></action>
229
+ <action method="bindPager"><pager>seo.sitemap.tree.pager.bottom</pager></action>
230
+ </block>
231
+ </reference>
232
+ </catalog_seo_sitemap_category_tree>
233
+
234
+ <catalog_seo_sitemap_product translate="label">
235
+ <label>Catalog Seo Sitemap (Product List)</label>
236
+ <reference name="head">
237
+ <action method="setTitle" translate="title" module="catalog"><title>Site Map</title></action>
238
+ </reference>
239
+ <update handle="catalog_seo_sitemap" />
240
+ <reference name="seo.sitemap.container">
241
+ <action method="setTitle" translate="title" module="catalog"><title>Products</title></action>
242
+ <block type="catalog/seo_sitemap_product" name="seo.sitemap.sitemap" as="sitemap" after="pager_top" template="catalog/seo/sitemap.phtml">
243
+ <action method="bindPager"><pager>seo.sitemap.pager.top</pager></action>
244
+ <action method="bindPager"><pager>seo.sitemap.pager.bottom</pager></action>
245
+ <action method="setItemsTitle" translate="title" module="catalog"><title>products</title></action>
246
+ </block>
247
+ </reference>
248
+ <reference name="seo.sitemap.links">
249
+ <action method="addLink" translate="label title" module="catalog"><label>Categories Sitemap</label><url helper="catalog/map/getCategoryUrl"/><title>Categories Sitemap</title></action>
250
+ </reference>
251
+ </catalog_seo_sitemap_product>
252
+ </layout>
app/design/frontend/base/default/template/catalog/product/view/media_custom.phtml ADDED
@@ -0,0 +1,115 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ $baseurl = Mage::getBaseUrl(Mage_Core_Model_Store::URL_TYPE_WEB);
3
+ $skinurl = Mage::getBaseUrl(Mage_Core_Model_Store::URL_TYPE_SKIN);
4
+ /**
5
+ * Magento
6
+ *
7
+ * NOTICE OF LICENSE
8
+ *
9
+ * This source file is subject to the Academic Free License (AFL 3.0)
10
+ * that is bundled with this package in the file LICENSE_AFL.txt.
11
+ * It is also available through the world-wide-web at this URL:
12
+ * http://opensource.org/licenses/afl-3.0.php
13
+ * If you did not receive a copy of the license and are unable to
14
+ * obtain it through the world-wide-web, please send an email
15
+ * to license@magentocommerce.com so we can send you a copy immediately.
16
+ *
17
+ * DISCLAIMER
18
+ *
19
+ * Do not edit or add to this file if you wish to upgrade Magento to newer
20
+ * versions in the future. If you wish to customize Magento for your
21
+ * needs please refer to http://www.magentocommerce.com for more information.
22
+ *
23
+ * @category design
24
+ * @package base_default
25
+ * @copyright Copyright (c) 2012 Magento Inc. (http://www.magentocommerce.com)
26
+ * @license http://opensource.org/licenses/afl-3.0.php Academic Free License (AFL 3.0)
27
+ */
28
+
29
+ /**
30
+ * Product media data template
31
+ *
32
+ * @see Mage_Catalog_Block_Product_View_Media
33
+ */
34
+ ?>
35
+ <style>
36
+ #designs{
37
+ background:url('<?php print $skinurl?>frontend/default/customproduct/images/bgimage7.png');
38
+ }
39
+ </style>
40
+
41
+ <?php
42
+ $_product = $this->getProduct();
43
+ $_helper = $this->helper('catalog/output');
44
+ print '<input type="button" value="Product" id="idproduct"><input type="button" value="Design" id="iddesign">';
45
+ ?>
46
+ <?php if ($_product->getImage() != 'no_selection' && $_product->getImage()): ?>
47
+ <p id="products" class="product-image product-image-zoom">
48
+ <?php
49
+ $_img = '<img style="width:265px" id="image" src="'.$this->helper('catalog/image')->init($_product, 'image').'" alt="'.$this->htmlEscape($this->getImageLabel()).'" title="'.$this->htmlEscape($this->getImageLabel()).'" />';
50
+ echo $_helper->productAttribute($_product, $_img, 'image');
51
+ ?>
52
+ <input type="hidden" name="oldimage" value="<?php print $this->helper('catalog/image')->init($_product,'image'); ?>" id="oldimage"/>
53
+ <input type="hidden" name="oldprice" value="" id="oldprice"/>
54
+ <input type="hidden" name="oldproduct" value="" id="oldproduct"/>
55
+ </p>
56
+
57
+ <div id="designs" class="product-image product-image-zoom" style="display:none;position:relative; width:265px; height:400px;" class="darkInsetBackgroundColor">
58
+ <div id="page_imagePort" style="position:absolute; left:0px; top:0px; width:265px; height:400px; overflow:hidden;">
59
+ <img id="page_imagePort-image" src="<?php print $skinurl.'frontend/default/customproduct/images/'.'bgimage.png'; ?>" style="position:absolute; width:265px; height:200px;" alt=""/>
60
+ </div>
61
+ <div id="page_marquee" style="position:absolute; left:0px; top:0px; width:265px; height:400px;"></div>
62
+
63
+ <div id="page_imagePort1" style="position:absolute; left:0px; top:0px; width:265px; height:400px; overflow:hidden;">
64
+ <img id="page_imagePort1-image" src="<?php print $skinurl.'frontend/default/customproduct/images/'.'textimage.png'; ?>" style="position:absolute; width:265px; height:200px;" alt=""/>
65
+ </div>
66
+ <div id="page_marquee1" style="position:absolute; left:0px; top:0px; width:265px; height:400px;"></div>
67
+
68
+ </div>
69
+
70
+ <input id="page-marqueePositionLeft" type="hidden"/>
71
+ <input id="page-marqueePositionTop" type="hidden"/>
72
+ <input id="page-marqueePositionWidth" type="hidden"/>
73
+ <input id="page-marqueePositionHeight" type="hidden"/>
74
+
75
+ <input id="page-marqueePositionLeftT" type="hidden"/>
76
+ <input id="page-marqueePositionTopT" type="hidden"/>
77
+ <input id="page-marqueePositionWidthT" type="hidden"/>
78
+ <input id="page-marqueePositionHeightT" type="hidden"/>
79
+
80
+
81
+ <p class="zoom-notice" id="track_hint"><?php echo $this->__('Double click on above image to view full picture') ?></p>
82
+ <div class="zoom">
83
+ <img id="zoom_out" src="<?php echo $this->getSkinUrl('images/slider_btn_zoom_out.gif') ?>" alt="<?php echo $this->__('Zoom Out') ?>" title="<?php echo $this->__('Zoom Out') ?>" class="btn-zoom-out" />
84
+ <div id="track">
85
+ <div id="handle"></div>
86
+ </div>
87
+ <img id="zoom_in" src="<?php echo $this->getSkinUrl('images/slider_btn_zoom_in.gif') ?>" alt="<?php echo $this->__('Zoom In') ?>" title="<?php echo $this->__('Zoom In') ?>" class="btn-zoom-in" />
88
+ </div>
89
+ <script type="text/javascript">
90
+ //<![CDATA[
91
+ Event.observe(window, 'load', function() {
92
+ product_zoom = new Product.Zoom('image', 'track', 'handle', 'zoom_in', 'zoom_out', 'track_hint');
93
+ });
94
+ //]]>
95
+ </script>
96
+ <?php else: ?>
97
+ <p class="product-image">
98
+ <?php
99
+ $_img = '<img src="'.$this->helper('catalog/image')->init($_product, 'image')->resize(265).'" alt="'.$this->htmlEscape($this->getImageLabel()).'" title="'.$this->htmlEscape($this->getImageLabel()).'" />';
100
+ echo $_helper->productAttribute($_product, $_img, 'image');
101
+ ?>
102
+ </p>
103
+ <?php endif; ?>
104
+ <?php if (count($this->getGalleryImages()) > 0): ?>
105
+ <div class="more-views">
106
+ <h2><?php echo $this->__('More Views') ?></h2>
107
+ <ul>
108
+ <?php foreach ($this->getGalleryImages() as $_image): ?>
109
+ <li>
110
+ <a href="#" onclick="popWin('<?php echo $this->getGalleryUrl($_image) ?>', 'gallery', 'width=300,height=300,left=0,top=0,location=no,status=yes,scrollbars=yes,resizable=yes'); return false;" title="<?php echo $this->htmlEscape($_image->getLabel()) ?>"><img src="<?php echo $this->helper('catalog/image')->init($this->getProduct(), 'thumbnail', $_image->getFile())->resize(56); ?>" width="56" height="56" alt="<?php echo $this->htmlEscape($_image->getLabel()) ?>" /></a>
111
+ </li>
112
+ <?php endforeach; ?>
113
+ </ul>
114
+ </div>
115
+ <?php endif; ?>
app/design/frontend/base/default/template/catalog/product/view_custom.phtml ADDED
@@ -0,0 +1,635 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <script src="//ajax.googleapis.com/ajax/libs/jquery/1.8.3/jquery.min.js"></script>
2
+
3
+ <?php $skin_url = Mage::getBaseUrl(Mage_Core_Model_Store::URL_TYPE_SKIN); ?>
4
+ <?php $skin_url_uize = Mage::getBaseUrl(Mage_Core_Model_Store::URL_TYPE_SKIN).'frontend/default/customproduct/js/Uize.js'; ?>
5
+
6
+ <script src="<?php print $skin_url_uize;?>"></script>
7
+ <script>jQuery.noConflict();</script>
8
+
9
+ <?php
10
+ $baseurl = Mage::getBaseUrl(Mage_Core_Model_Store::URL_TYPE_WEB);
11
+ //$skin_url = Mage::getBaseUrl(Mage_Core_Model_Store::URL_TYPE_SKIN);
12
+ ?>
13
+ <style>
14
+ #main_container{
15
+ //margin-left:300px;
16
+ //margin-top:200px;
17
+ position:relative;
18
+ }
19
+
20
+ #toaddtext{
21
+ padding:2px;
22
+ }
23
+
24
+ .mytext{
25
+ height:30px;
26
+ }
27
+
28
+ .addtxt {
29
+ background:url('<?php echo $skin_url?>frontend/default/customproduct/images/button1.png') no-repeat;
30
+ width:113px;
31
+ height:30px;
32
+ }
33
+
34
+ .uploads{
35
+ height: 30px;
36
+ margin-left: 100px;
37
+ width: 113px;
38
+ background:url('<?php echo $skin_url?>frontend/default/customproduct/images/button3.png') no-repeat;
39
+ }
40
+
41
+ .fileUpload{
42
+ height: 30px;
43
+ }
44
+
45
+ </style>
46
+ <script type="text/javascript">
47
+
48
+ jQuery(document).ready(function(){
49
+
50
+ var p = jQuery('.price').html();
51
+ jQuery('#oldprice').val(p);
52
+
53
+ jQuery('#oldproduct').val(jQuery("input[name=product]").val());
54
+
55
+ jQuery('#product-essential').append('<div id="product-options-wrapper" class="product-options"></div>');
56
+
57
+ document.getElementById('userfiles').addEventListener('change', function(e) {
58
+ var url='<?print $baseurl; ?>customproduct/index/upload';
59
+ var file = this.files[0];
60
+ var xhr = new XMLHttpRequest();
61
+ xhr.file = file; // not necessary if you create scopes like this
62
+ xhr.addEventListener('progress', function(e) {
63
+ var done = e.position || e.loaded, total = e.totalSize || e.total;
64
+ console.log('xhr progress: ' + (Math.floor(done/total*1000)/10) + '%');
65
+ }, false);
66
+ if ( xhr.upload ) {
67
+ xhr.upload.onprogress = function(e) {
68
+ var done = e.position || e.loaded, total = e.totalSize || e.total;
69
+ console.log('xhr.upload progress: ' + done + ' / ' + total + ' = ' + (Math.floor(done/total*1000)/10) + '%');
70
+ };
71
+ }
72
+ xhr.onreadystatechange = function(e) {
73
+ if ( 4 == this.readyState ) {
74
+ this.response = this.response || this.responseText;
75
+ jQuery('#page_imagePort-image').attr('src','media/finalimages/upload/'+ this.response);
76
+
77
+ console.log(['xhr upload complete', e]);
78
+ }
79
+ };
80
+ xhr.open('post', url, true);
81
+ var formData = new FormData();
82
+ formData.append("userfile",file);
83
+ xhr.send(formData);
84
+ //xhr.send(file);
85
+ }, false);
86
+
87
+ //});
88
+
89
+ /*jQuery("input[type=file]").filestyle({
90
+ image: "http://localhost/magento/skin/frontend/base/default/toajax/images/button2.png",
91
+ imageheight : 30,
92
+ imagewidth : 113,
93
+ width : 200
94
+ });
95
+ */
96
+
97
+
98
+ var prod_id = jQuery("input[name=product]").val();
99
+ jQuery.post('<?print $baseurl; ?>customproduct/index/ajaxoptions',{'product_id':prod_id},function(data){
100
+ jQuery('#product-options-wrapper').html(data);
101
+ });
102
+
103
+ jQuery('#idproduct').click(function(){
104
+ jQuery('#designs').hide();
105
+ jQuery('#products').show();
106
+ });
107
+
108
+
109
+ jQuery('#iddesign').click(function(){
110
+
111
+ jQuery('#page_imagePort-image').attr('src','<?php echo $skin_url?>frontend/default/customproduct/images/bgimage.png');
112
+ jQuery('#page_imagePort1-image').attr('src','<?php echo $skin_url?>frontend/default/customproduct/images/textimage.png');
113
+
114
+ jQuery('#designs').show();
115
+ jQuery('#products').hide();
116
+
117
+
118
+ Uize.module ({
119
+ required:[
120
+ 'Uize.Widget.Page',
121
+ 'Uize.Node',
122
+ 'Uize.Widget.ImagePort',
123
+ 'Uize.Widget.Bar.Slider.xSkin',
124
+ 'Uize.Widget.Resizer.Marquee'
125
+ ],
126
+ builder:function () {
127
+ /*** create the example page widget ***/
128
+
129
+ var page = window.page = Uize.Widget.Page ();
130
+
131
+ /*** add the image port child widget ***/
132
+ var imagePort = page.addChild (
133
+ 'imagePort',
134
+ Uize.Widget.ImagePort,
135
+ {
136
+ sizingLowerBound:'0',
137
+ sizingUpperBound:'fill',
138
+ sizingValue:.5,
139
+ alignX:.5,
140
+ alignY:.5
141
+ }
142
+ );
143
+
144
+
145
+ var imagePort1 = page.addChild (
146
+ 'imagePort1',
147
+ Uize.Widget.ImagePort,
148
+ {
149
+ sizingLowerBound:'0',
150
+ sizingUpperBound:'fill',
151
+ sizingValue:.5,
152
+ alignX:.5,
153
+ alignY:.5
154
+ }
155
+ );
156
+
157
+ /*** code to update the image port instance based on user input values ***/
158
+ function updateImagePortSettings () {
159
+ imagePort.set ({
160
+ alignX:0.5,
161
+ alignY:0.5,
162
+ sizingUpperBound:'fill',
163
+ sizingLowerBound:'0',
164
+ sizingValue:'1'
165
+ });
166
+ }
167
+
168
+ function updateImagePortSettings1 () {
169
+ imagePort1.set ({
170
+ alignX:0.5,
171
+ alignY:0.5,
172
+ sizingUpperBound:'fill',
173
+ sizingLowerBound:'0',
174
+ sizingValue:'1'
175
+ });
176
+ }
177
+
178
+ /*** common values shared by alignX, alignY, and sizingValue sliders ***/
179
+ /*Uize.Widget.Bar.Slider.set ({
180
+ value:.5,
181
+ fullTintColor:'#9aa',
182
+ fullTintLevel:50,
183
+ emptyTintColor:'#9aa',
184
+ emptyTintLevel:50,
185
+ borderThickness:3,
186
+ borderTintColor:'#455',
187
+ borderTintLevel:50,
188
+ increments:0,
189
+ knobSize:28,
190
+ built:false
191
+ });*/
192
+
193
+ /*** add the alignX slider child widget ***/
194
+ /*var alignXSlider = page.addChild (
195
+ 'alignXSlider',
196
+ Uize.Widget.Bar.Slider,
197
+ {
198
+ minValue:0,
199
+ maxValue:1,
200
+ orientation:'horizontal'
201
+ }
202
+ );*/
203
+ /*alignXSlider.wire ('Changed.value',updateImagePortSettings);*/
204
+
205
+ /*** add the alignY slider child widget ***/
206
+ /*var alignYSlider = page.addChild (
207
+ 'alignYSlider',
208
+ Uize.Widget.Bar.Slider,
209
+ {
210
+ minValue:1,
211
+ maxValue:0,
212
+ orientation:'vertical'
213
+ }
214
+ );
215
+ alignYSlider.wire ('Changed.value',updateImagePortSettings);*/
216
+
217
+ /*** add the sizingValue slider child widget ***/
218
+ /*var sizingValueSlider = page.addChild (
219
+ 'sizingValueSlider',
220
+ Uize.Widget.Bar.Slider,
221
+ {
222
+ fullTintColor:'#fff',
223
+ fullTintLevel:70,
224
+ minValue:0,
225
+ maxValue:3,
226
+ value:1,
227
+ orientation:'vertical'
228
+ }
229
+ );
230
+ sizingValueSlider.wire ('Changed.value',updateImagePortSettings);*/
231
+
232
+ /*** add the marquee child widget ***/
233
+ function updateImagePortPos () {
234
+ imagePort.setNodeStyle ('',marquee.getCoords());
235
+ imagePort.updateUi ();
236
+ }
237
+
238
+ function updateImagePortPos1 () {
239
+ imagePort1.setNodeStyle ('',marquee1.getCoords());
240
+ imagePort1.updateUi ();
241
+ }
242
+
243
+
244
+
245
+ var marquee = page.addChild (
246
+ 'marquee',
247
+ Uize.Widget.Resizer.Marquee,
248
+ {
249
+ constrain:true,
250
+ minWidth:20,
251
+ minHeight:20,
252
+ built:false
253
+ }
254
+ );
255
+ marquee.wire ('Position Changed',updateImagePortPos);
256
+
257
+ var marquee1 = page.addChild (
258
+ 'marquee1',
259
+ Uize.Widget.Resizer.Marquee,
260
+ {
261
+ constrain:true,
262
+ minWidth:20,
263
+ minHeight:20,
264
+ built:false
265
+ }
266
+ );
267
+ marquee1.wire ('Position Changed',updateImagePortPos1);
268
+
269
+
270
+ /*** initialize the ImagePort instance ***/
271
+ updateImagePortSettings ();
272
+ updateImagePortSettings1 ();
273
+ updateImagePortPos ();
274
+ updateImagePortPos1 ();
275
+
276
+ /*** wire up the page widget ***/
277
+ page.wireUi ();
278
+
279
+ /*** watch for changes in sizing bound values ***/
280
+ page.wireNode ('sizingUpperBound','change',updateImagePortSettings);
281
+ page.wireNode ('sizingLowerBound','change',updateImagePortSettings1);
282
+
283
+
284
+ function displayMarqueePosition () {
285
+ page.setNodeValue ('marqueePositionLeft',marquee.get ('left'));
286
+ page.setNodeValue ('marqueePositionTop',marquee.get ('top'));
287
+ page.setNodeValue ('marqueePositionWidth',marquee.get ('width'));
288
+ page.setNodeValue ('marqueePositionHeight',marquee.get ('height'));
289
+ }
290
+
291
+ function displayMarqueePosition1 () {
292
+ page.setNodeValue ('marqueePositionLeftT',marquee1.get ('left'));
293
+ page.setNodeValue ('marqueePositionTopT',marquee1.get ('top'));
294
+ page.setNodeValue ('marqueePositionWidthT',marquee1.get ('width'));
295
+ page.setNodeValue ('marqueePositionHeightT',marquee1.get ('height'));
296
+ }
297
+
298
+ marquee.wire('Position Changed',displayMarqueePosition);
299
+ marquee1.wire('Position Changed',displayMarqueePosition1);
300
+
301
+ /*** display marquee's initial position ***/
302
+ displayMarqueePosition();
303
+
304
+ displayMarqueePosition1();
305
+
306
+ }
307
+ });
308
+
309
+
310
+
311
+
312
+ });
313
+
314
+
315
+ jQuery(".addtxt").click(function(){
316
+
317
+ var l_text = jQuery('#page-marqueePositionLeftT').val();
318
+ var t_text = jQuery('#page-marqueePositionTopT').val();
319
+ var w_text = jQuery('#page-marqueePositionWidthT').val();
320
+ var h_text = jQuery('#page-marqueePositionHeightT').val();
321
+
322
+ var mytext=jQuery('.mytext').val();
323
+
324
+ jQuery.post('<?print $baseurl; ?>customproduct/index/text',{'mytext':mytext,'width':w_text,'height':h_text,'left':l_text,'top':t_text},function(data){
325
+ jQuery('#page_imagePort1-image').attr('src',data);
326
+ });
327
+
328
+ });
329
+
330
+ jQuery('#idproduct').click(function(){
331
+
332
+ var left =jQuery('#page-marqueePositionLeft').val();
333
+ var top = jQuery('#page-marqueePositionTop').val();
334
+ var width = jQuery('#page-marqueePositionWidth').val();
335
+ var height =jQuery('#page-marqueePositionHeight').val();
336
+
337
+ var left_text =jQuery('#page-marqueePositionLeftT').val();
338
+ var top_text = jQuery('#page-marqueePositionTopT').val();
339
+ var w_text = jQuery('#page-marqueePositionWidthT').val();
340
+ var h_text =jQuery('#page-marqueePositionHeightT').val();
341
+
342
+ var product =jQuery("input[name=product]").val();
343
+
344
+ var textimage =jQuery('#page_imagePort1-image').attr('src');
345
+ var mainimage =jQuery('#page_imagePort-image').attr('src');
346
+
347
+ jQuery('#image').attr('src',jQuery('#oldimage').val());
348
+
349
+ var image = jQuery('#image').attr('src');
350
+
351
+ //var product =jQuery("input[name=product]").val();
352
+
353
+ var oldprice = jQuery('#oldprice').val();
354
+
355
+ jQuery.post('<?print $baseurl; ?>customproduct/index/image',{'oldprice':oldprice,'image':image,'mainimage':mainimage,'product':product,'textimage':textimage,'left':left,'top':top,'width':width,'height':height,'left_text':left_text,'top_text':top_text,'w_text':w_text,'h_text':h_text},function(data){
356
+
357
+ var data = JSON.parse(data);
358
+
359
+
360
+ if(data['filename']!=0){
361
+ jQuery('#image').attr('src',data['filename']);
362
+ var pid = data['product_id'];
363
+ jQuery(".price").html('$'+data['price']);
364
+ } else {
365
+ jQuery('#image').attr('src',jQuery('#oldimage').val());
366
+ var pid = jQuery('#oldproduct').val();
367
+ jQuery(".price").html(jQuery('#oldprice').val());
368
+ }
369
+
370
+ if(data['opthtml']!=0){
371
+ jQuery('#product-options-wrapper').html(data['opthtml']);
372
+ }
373
+
374
+
375
+
376
+
377
+
378
+
379
+ jQuery("input[name=product]").val(pid);
380
+
381
+
382
+ var addcart = jQuery("#product_addtocart_form").attr('action');
383
+ var addcart = addcart.split('product/');
384
+ var addcart_url = addcart[0]+'product/'+pid+'/'
385
+
386
+
387
+ var wish = jQuery(".link-wishlist").attr('href');
388
+ var wish = wish.split('product/');
389
+
390
+
391
+ var wish_url = wish[0]+'product/'+pid+'/'
392
+
393
+
394
+ var comp = jQuery(".link-compare").attr('href');
395
+ var comp = comp.split('uenc/');
396
+ var comp1 = comp[0].split('product/');
397
+
398
+ var comp_url = comp1[0]+'product/id/'+pid+'/uenc/'+comp[1];
399
+
400
+ /*var rv=jQuery(".no-rating a").attr('href');
401
+ var rv = rv.trim();
402
+ rv.split('/review');
403
+ var rev_url = rv[0]+'list/id/'+pid+'#review-form';*/
404
+
405
+ jQuery("#product_addtocart_form").attr('action',addcart_url);
406
+
407
+ jQuery(".link-wishlist").attr('href',wish_url);
408
+
409
+ jQuery(".link-compare").attr('href',comp_url);
410
+
411
+
412
+
413
+ var prod_id = jQuery("input[name=product]").val();
414
+ jQuery.post('<?print $baseurl; ?>customproduct/index/ajaxoptions',{'product_id':prod_id},function(data){
415
+ jQuery('#product-options-wrapper').html(data);
416
+ });
417
+
418
+
419
+ });
420
+
421
+
422
+
423
+
424
+
425
+
426
+
427
+ });
428
+
429
+
430
+ });
431
+
432
+
433
+
434
+
435
+ </script>
436
+
437
+ <?php
438
+ /**
439
+ * Magento
440
+ *
441
+ * NOTICE OF LICENSE
442
+ *
443
+ * This source file is subject to the Academic Free License (AFL 3.0)
444
+ * that is bundled with this package in the file LICENSE_AFL.txt.
445
+ * It is also available through the world-wide-web at this URL:
446
+ * http://opensource.org/licenses/afl-3.0.php
447
+ * If you did not receive a copy of the license and are unable to
448
+ * obtain it through the world-wide-web, please send an email
449
+ * to license@magentocommerce.com so we can send you a copy immediately.
450
+ *
451
+ * DISCLAIMER
452
+ *
453
+ * Do not edit or add to this file if you wish to upgrade Magento to newer
454
+ * versions in the future. If you wish to customize Magento for your
455
+ * needs please refer to http://www.magentocommerce.com for more information.
456
+ *
457
+ * @category design
458
+ * @package base_default
459
+ * @copyright Copyright (c) 2012 Magento Inc. (http://www.magentocommerce.com)
460
+ * @license http://opensource.org/licenses/afl-3.0.php Academic Free License (AFL 3.0)
461
+ */
462
+
463
+ /**
464
+ * Product view template
465
+ *
466
+ * @see Mage_Catalog_Block_Product_View
467
+ * @see Mage_Review_Block_Product_View
468
+ */
469
+ ?>
470
+ <?php $_helper = $this->helper('catalog/output'); ?>
471
+ <?php $_product = $this->getProduct(); ?>
472
+ <script type="text/javascript">
473
+ var optionsPrice = new Product.OptionsPrice(<?php echo $this->getJsonConfig() ?>);
474
+ </script>
475
+ <div id="messages_product_view"><?php echo $this->getMessagesBlock()->getGroupedHtml() ?></div>
476
+ <div class="product-view">
477
+ <div class="product-essential">
478
+
479
+
480
+
481
+
482
+
483
+ <form action="<?php echo $this->getSubmitUrl($_product) ?>" method="post" id="product_addtocart_form"<?php if($_product->getOptions()): ?> enctype="multipart/form-data"<?php endif; ?>>
484
+ <div class="no-display">
485
+ <input type="hidden" name="product" value="<?php echo $_product->getId() ?>" />
486
+ <input type="hidden" name="related_product" id="related-products-field" value="" />
487
+ </div>
488
+
489
+ <div class="product-shop">
490
+ <div class="product-name">
491
+ <h1><?php echo $_helper->productAttribute($_product, $_product->getName(), 'name') ?></h1>
492
+ </div>
493
+
494
+ <?php if ($this->canEmailToFriend()): ?>
495
+ <p class="email-friend"><a href="<?php echo $this->helper('catalog/product')->getEmailToFriendUrl($_product) ?>"><?php echo $this->__('Email to a Friend') ?></a></p>
496
+ <?php endif; ?>
497
+
498
+
499
+
500
+
501
+
502
+ <?php echo $this->getReviewsSummaryHtml($_product, false, true)?>
503
+ <?php echo $this->getChildHtml('alert_urls') ?>
504
+ <?php echo $this->getChildHtml('product_type_data') ?>
505
+ <?php echo $this->getTierPriceHtml() ?>
506
+ <?php echo $this->getChildHtml('extrahint') ?>
507
+
508
+ <?php if (!$this->hasOptions()):?>
509
+ <div class="add-to-box">
510
+ <?php if($_product->isSaleable()): ?>
511
+ <?php echo $this->getChildHtml('addtocart') ?>
512
+ <?php if( $this->helper('wishlist')->isAllow() || $_compareUrl=$this->helper('catalog/product_compare')->getAddUrl($_product)): ?>
513
+ <span class="or"><?php echo $this->__('OR') ?></span>
514
+ <?php endif; ?>
515
+ <?php endif; ?>
516
+ <?php echo $this->getChildHtml('addto') ?>
517
+ </div>
518
+ <?php echo $this->getChildHtml('extra_buttons') ?>
519
+ <?php elseif (!$_product->isSaleable()): ?>
520
+ <div class="add-to-box">
521
+ <?php echo $this->getChildHtml('addto') ?>
522
+ </div>
523
+ <?php endif; ?>
524
+
525
+ <?php if ($_product->getShortDescription()):?>
526
+ <div class="short-description">
527
+ <h2><?php echo $this->__('Quick Overview') ?></h2>
528
+ <div class="std"><?php echo $_helper->productAttribute($_product, nl2br($_product->getShortDescription()), 'short_description') ?></div>
529
+ </div>
530
+ <?php endif;?>
531
+
532
+
533
+ <div id="main_container">
534
+ <h2>Upload Image Files</h2>
535
+ <form id="uploadfile" action="<?print $baseurl; ?>customproduct/index/upload" enctype="multipart/form-data">
536
+ <input type="file" name="userfiles" id="userfiles" class="fileUpload" multiple>
537
+ <!--<input class="uploads" type="button" name="upload" id="upload">-->
538
+ </form>
539
+ <div id="mlist">
540
+ </div>
541
+
542
+
543
+ <div id="toaddtext">
544
+ <span><input type="button" name="addtxt" class="addtxt" value="Add text"></span><span><input type="text" name="mytext" id="mytext" class="mytext"/></span>
545
+ </div>
546
+ </div>
547
+
548
+
549
+
550
+ <?php echo $this->getChildHtml('other');?>
551
+
552
+ <?php if ($_product->isSaleable() && $this->hasOptions()):?>
553
+ <?php echo $this->getChildChildHtml('container1', '', true, true) ?>
554
+ <?php endif;?>
555
+
556
+ </div>
557
+
558
+ <div class="product-img-box">
559
+ <?php echo $this->getChildHtml('media') ?>
560
+ </div>
561
+
562
+ <div class="clearer"></div>
563
+ <?php if ($_product->isSaleable() && $this->hasOptions()):?>
564
+ <?php echo $this->getChildChildHtml('container2', '', true, true) ?>
565
+ <?php endif;?>
566
+ </form>
567
+
568
+
569
+
570
+ <script type="text/javascript">
571
+ //<![CDATA[
572
+ var productAddToCartForm = new VarienForm('product_addtocart_form');
573
+ productAddToCartForm.submit = function(button, url) {
574
+ if (this.validator.validate()) {
575
+ var form = this.form;
576
+ var oldUrl = form.action;
577
+
578
+ if (url) {
579
+ form.action = url;
580
+ }
581
+ var e = null;
582
+ try {
583
+ this.form.submit();
584
+ } catch (e) {
585
+ }
586
+ this.form.action = oldUrl;
587
+ if (e) {
588
+ throw e;
589
+ }
590
+
591
+ if (button && button != 'undefined') {
592
+ button.disabled = true;
593
+ }
594
+ }
595
+ }.bind(productAddToCartForm);
596
+
597
+ productAddToCartForm.submitLight = function(button, url){
598
+ if(this.validator) {
599
+ var nv = Validation.methods;
600
+ delete Validation.methods['required-entry'];
601
+ delete Validation.methods['validate-one-required'];
602
+ delete Validation.methods['validate-one-required-by-name'];
603
+ // Remove custom datetime validators
604
+ for (var methodName in Validation.methods) {
605
+ if (methodName.match(/^validate-datetime-.*/i)) {
606
+ delete Validation.methods[methodName];
607
+ }
608
+ }
609
+
610
+ if (this.validator.validate()) {
611
+ if (url) {
612
+ this.form.action = url;
613
+ }
614
+ this.form.submit();
615
+ }
616
+ Object.extend(Validation.methods, nv);
617
+ }
618
+ }.bind(productAddToCartForm);
619
+ //]]>
620
+ </script>
621
+ </div>
622
+
623
+ <div class="product-collateral">
624
+ <?php foreach ($this->getChildGroup('detailed_info', 'getChildHtml') as $alias => $html):?>
625
+ <div class="box-collateral <?php echo "box-{$alias}"?>">
626
+ <?php if ($title = $this->getChildData($alias, 'title')):?>
627
+ <h2><?php echo $this->escapeHtml($title); ?></h2>
628
+ <?php endif;?>
629
+ <?php echo $html; ?>
630
+ </div>
631
+ <?php endforeach;?>
632
+ <?php echo $this->getChildHtml('upsell_products') ?>
633
+ <?php echo $this->getChildHtml('product_additional_data') ?>
634
+ </div>
635
+ </div>
app/etc/modules/Blog4mail_Customproduct.xml ADDED
@@ -0,0 +1,9 @@
 
 
 
 
 
 
 
 
 
1
+ <?xml version="1.0"?>
2
+ <config>
3
+ <modules>
4
+ <Blog4mail_Customproduct>
5
+ <active>true</active>
6
+ <codePool>community</codePool>
7
+ </Blog4mail_Customproduct>
8
+ </modules>
9
+ </config>
media/finalimages/2b0e7ecb7dffaca13b2be8c6f4e5f89e.jpg ADDED
Binary file
media/finalimages/46c4f93a056c2e11c45c301a0dda1da4.jpg ADDED
Binary file
media/finalimages/8605d98db258cb59cd4a0bc5e1374104.jpg ADDED
Binary file
media/finalimages/upload/50ef9eafe2774image1.jpeg ADDED
Binary file
media/finalimages/upload/50ef9ef6b49aeimage1.jpeg ADDED
Binary file
media/finalimages/upload/50ef9fa951afcimage1.jpeg ADDED
Binary file
media/finalimages/upload/50efa5be9c0a0image1.jpeg ADDED
Binary file
media/finalimages/upload/50f4f56c28bfdimage1.jpeg ADDED
Binary file
media/finalimages/upload/50f4f56caf383image1.jpeg ADDED
Binary file
media/finalimages/upload/50f4f5e7aa803image1.jpeg ADDED
Binary file
media/finalimages/upload/50f4f71c53eecimage1.jpeg ADDED
Binary file
package.xml ADDED
@@ -0,0 +1,25 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?xml version="1.0"?>
2
+ <package>
3
+ <name>Blog4mails</name>
4
+ <version>1.0.0</version>
5
+ <stability>stable</stability>
6
+ <license uri="http://opensource.org/licenses/osl-3.0.php">Open Source</license>
7
+ <channel>community</channel>
8
+ <extends/>
9
+ <summary>Product design tools for online custom product development</summary>
10
+ <description>This custom product development tool helps in&#xD;
11
+ &#xD;
12
+ 1. Design the product image&#xD;
13
+ 2. Put some text on the image&#xD;
14
+ 3. It saves the perspective info of the product&#xD;
15
+ 4. Custom products created along with the custom options.&#xD;
16
+ &#xD;
17
+ No support will be provided.</description>
18
+ <notes>Custom Product Design Tools, No Support Provided</notes>
19
+ <authors><author><name>blg4mail.com</name><user>oklovein</user><email>lovein.sales@gmail.com</email></author></authors>
20
+ <date>2013-01-14</date>
21
+ <time>00:52:13</time>
22
+ <contents><target name="magecommunity"><dir name="Blog4mail"><dir name="Customproduct"><dir name="Block"><file name="Customproduct.php" hash="a4899e23da7d9dae771c83a24c52a88e"/></dir><dir name="Helper"><file name="Data.php" hash="08503e586d976bebfa5cd1514e75252a"/></dir><dir name="Model"><file name="Customproduct.php" hash="318f77d3897c7414d3dca31e6e85d40c"/><dir name="Mysql4"><dir name="Customproduct"><file name="Collection.php" hash="3cd16a4a839db77e030e460a99d262a1"/></dir><file name="Customproduct.php" hash="1c65e603f80c74332fbf5f8be0cb92b2"/></dir><file name="Status.php" hash="00c86b88578549ac14b07c38464bc712"/></dir><dir name="controllers"><file name="IndexController.php" hash="f96519394f5b20b83409f2ecddc133eb"/><file name="IndexController.php~" hash="f96519394f5b20b83409f2ecddc133eb"/></dir><dir name="etc"><file name="config.xml" hash="6e6e8474d3d9ef34df839a98dc99b78f"/><file name="config.xml~" hash="6e6e8474d3d9ef34df839a98dc99b78f"/></dir><dir name="sql"><dir name="customproduct_setup"><file name="mysql4-install-1.0.0.php" hash="0dc4a56f5e1df4d08114ef15aab664aa"/><file name="mysql4-install-1.0.0.php~" hash="0dc4a56f5e1df4d08114ef15aab664aa"/><file name="mysql4-install-1.0.php~" hash="9fde8f4568409cbbf213710d9d4e53a1"/><file name="mysql4-upgrade-1.0-1.1.php~" hash="5506677e7dc6193d133a3001efad33c0"/><file name="mysql4-upgrade-1.3.4-1.4.php~" hash="5e7ac5dcfafbe474a9abced425c4e392"/></dir></dir></dir><dir name="Customproductadmin"><dir name="Block"><dir name="Customproduct"><dir name="Edit"><file name="Form.php" hash="0a1e5440f3bf0ea5d2f9daab579f5cee"/><dir name="Tab"><file name="Form.php" hash="8424855b71f54d8cbb03f8e3a0f6fa8d"/></dir><file name="Tabs.php" hash="1c91af75536c3e0a96b192049df86c4f"/></dir><file name="Edit.php" hash="dcf43fa99a11aab5f27f5a252aca785a"/><file name="Grid.php" hash="aa2fa7575446737c60f59549bdae2631"/></dir><file name="Customproduct.php" hash="3df8149185c3d4a568db8ee0b438cdd7"/></dir><dir name="Helper"><file name="Data.php" hash="65e1bdc90e4c6c85145e6316f20fec16"/></dir><dir name="controllers"><file name="CustomproductController.php" hash="9ca7d9d04e17d49b6ad12cd4322ceb07"/></dir><dir name="etc"><file name="config.xml" hash="68304389a8476c574263f0f37b73c9a4"/></dir></dir><file name="customproduct_catalog.xml~" hash="e57cdd5f8b92ba63a29aac9518d8654e"/></dir></target><target name="magedesign"><dir name="frontend"><dir name="base"><dir name="default"><dir name="template"><dir name="catalog"><dir name="product"><file name="view_custom.phtml" hash="30fbe9a8b0c60f2d2dede2f7d7a84723"/><dir name="view"><file name="media_custom.phtml" hash="8e38f9fd6ab720ca0ad5ed12b7695d10"/></dir></dir></dir></dir><dir name="layout"><file name="customproduct_catalog.xml" hash="b45f0d4d29a0e01a32d5f9c7c260f2f7"/></dir></dir></dir></dir></target><target name="magemedia"><dir name="finalimages"><file name="2b0e7ecb7dffaca13b2be8c6f4e5f89e.jpg" hash="8a8f8dd682b3db6790368d5c030c4bbd"/><file name="46c4f93a056c2e11c45c301a0dda1da4.jpg" hash="0db5fea3c4efaca76f0040f915cb7fa1"/><file name="8605d98db258cb59cd4a0bc5e1374104.jpg" hash="e4f30c8ecdb88a7bab105179f610811b"/><dir name="upload"><file name="50ef9eafe2774image1.jpeg" hash="3f4cbd39c8b42c17b71cf980707e1768"/><file name="50ef9ef6b49aeimage1.jpeg" hash="3f4cbd39c8b42c17b71cf980707e1768"/><file name="50ef9fa951afcimage1.jpeg" hash="3f4cbd39c8b42c17b71cf980707e1768"/><file name="50efa5be9c0a0image1.jpeg" hash="3f4cbd39c8b42c17b71cf980707e1768"/><file name="50f4f56c28bfdimage1.jpeg" hash="3f4cbd39c8b42c17b71cf980707e1768"/><file name="50f4f56caf383image1.jpeg" hash="3f4cbd39c8b42c17b71cf980707e1768"/><file name="50f4f5e7aa803image1.jpeg" hash="3f4cbd39c8b42c17b71cf980707e1768"/><file name="50f4f71c53eecimage1.jpeg" hash="3f4cbd39c8b42c17b71cf980707e1768"/></dir></dir></target><target name="mageskin"><dir name="frontend"><dir name="default"><dir name="customproduct"><dir><dir name="css"><file name="oauth-simple.css" hash="bf193322afc4112a25ae99d1137053e1"/><file name="print.css" hash="aafa75a7a320ecf563e63b9098beba05"/><file name="styles-ie.css" hash="ffe623005339241d8748054baad4e831"/><file name="styles.css" hash="6b0b4807578427ef9404540d6386fe25"/></dir><dir name="images"><file name="addtext.png" hash="91a5ff8c60c0d0b41ff5e8ca17409180"/><file name="best_selling_tr_even_bg.gif" hash="5022d648379090e306f00cd64738b146"/><file name="best_selling_tr_odd_bg.gif" hash="926622704f53796801bb5d097e116c8e"/><file name="bgimage.png" hash="50ad0d6300ff1c745db2e4f4ad8274cc"/><file name="bgimage7.png" hash="4e26bd58bcda18cb45cd2920d1447008"/><file name="bkg_account_box.gif" hash="dd98174b6e3e5605a3f9551a59c66841"/><file name="bkg_block-actions.gif" hash="da2970eac0a22c850b19ee3680475d51"/><file name="bkg_block-currency.gif" hash="bfaad1b64557c05ad6f4b124ad3d3532"/><file name="bkg_block-layered-dd.gif" hash="6ae6f8184e87de496fb74eeec65737c9"/><file name="bkg_block-layered-dt.gif" hash="ba8229068657b80f2c42111c5a1a307e"/><file name="bkg_block-layered-label.gif" hash="14687dfa3921cfd12d2149c1497d9765"/><file name="bkg_block-layered-li.gif" hash="753ebb76a4fc2b5b6915c536fcf4d487"/><file name="bkg_block-layered-title.gif" hash="c92e29b30af7abf4e0bc3f714a246f55"/><file name="bkg_block-layered1.gif" hash="607167f198572e83a0e728b6b9383a70"/><file name="bkg_block-title-account.gif" hash="a64f1df5a7e3d0f6a58b017f74311cb1"/><file name="bkg_block-title.gif" hash="f8c1f130ad69464fe7aff2f589b2ec75"/><file name="bkg_body.gif" hash="82bfc5bfe346c8e974cd33b1314b0acf"/><file name="bkg_buttons-set1.gif" hash="2c641e927bc83156b7004ea37920513c"/><file name="bkg_checkout.gif" hash="11258fe49feff5513c9608f2ea486776"/><file name="bkg_collapse-gm.gif" hash="37418f23e65006dcfde07ce9b249e057"/><file name="bkg_collapse.gif" hash="2333c68e38163ed4656da82b9bcf362b"/><file name="bkg_divider1.gif" hash="260ebae91ffb1b7c663906b29a069925"/><file name="bkg_form-search.gif" hash="2ca36eb80ea705e063409153f3821f78"/><file name="bkg_grand-total.gif" hash="10f1c3d82d78170706fa3e9c4baa7e04"/><file name="bkg_grid.gif" hash="a6f64fedbac51fb1b86184cd488cc4e6"/><file name="bkg_header.jpg" hash="0211c47be1493bd0ec72949c47932b81"/><file name="bkg_login-box.gif" hash="5538675d7f1c35d96a2b8013948f42a6"/><file name="bkg_main1.gif" hash="a8f5717873dc6cf8f6bd22924b5838fe"/><file name="bkg_main2.gif" hash="cf18ba9f7c7e6b058b439cde1a897e9c"/><file name="bkg_nav0.jpg" hash="f9ac3f31e293cf075471d2d3fe07353a"/><file name="bkg_nav1.gif" hash="f4e26840c8cca0e74aba5b810341c5c0"/><file name="bkg_nav2.gif" hash="a64c8f5165b239e432d26a62ae5f79b6"/><file name="bkg_opc-title-off.gif" hash="f69b40b5331ab3760f54d038daf287eb"/><file name="bkg_pipe1.gif" hash="7852290f6a443000ead96b8cec5cd7c7"/><file name="bkg_pipe2.gif" hash="7da64eefaf4da3855ab6ee76dbced0c2"/><file name="bkg_pipe3.gif" hash="11bfac1e590f0c77fb12f37d7f05cd3c"/><file name="bkg_product-view.gif" hash="7078a7f2827156d5ae0a1cb59da3c418"/><file name="bkg_product_collateral.gif" hash="1d4d6b22e5108aefae52709d3934f397"/><file name="bkg_rating.gif" hash="0a8777c815350ddf1e316a537ad0c335"/><file name="bkg_sp-methods.gif" hash="17d68b5449adaa87dafc62ae0afa1b9a"/><file name="bkg_tfoot.gif" hash="da2970eac0a22c850b19ee3680475d51"/><file name="bkg_th-v.gif" hash="b0d17555dfc6060941e0c067718189df"/><file name="bkg_th.gif" hash="f249911b08f2822fc0b561b7f98575d2"/><file name="bkg_toolbar.gif" hash="fb7ed019476eaa1643af922b59ede4fb"/><file name="btn_checkout.gif" hash="d2060501e14e86c29e28137130e5726e"/><file name="btn_edit.gif" hash="df3565eb4e4d0dc578201df60de54b47"/><file name="btn_gm-close.gif" hash="346e26eece27449a2f224aef76ae372e"/><file name="btn_google_checkout.gif" hash="843d75249ce05b5d87ca5419f37b1c3b"/><file name="btn_paypal_checkout.gif" hash="6edd61270b7b5632eafad10557129114"/><file name="btn_place_order.gif" hash="d35219f86ae2c983ee1a31557e37b612"/><file name="btn_previous.gif" hash="63473a1520a73bb0c9b47b685d17cd21"/><file name="btn_proceed_to_checkout.gif" hash="4daac687b514fecfd1068539500ac3d7"/><file name="btn_proceed_to_checkout_dis.gif" hash="9e152c01d5d88f690dc52cb62428f3b6"/><file name="btn_remove.gif" hash="6182e723aa2a253dc6cf334a3dfaaa84"/><file name="btn_remove2.gif" hash="234bddc4c5878c5ef16407a944824236"/><file name="btn_search.gif" hash="2d93b43c0a1c1182358677661e26a978"/><file name="btn_trash.gif" hash="bcb22f558a0eb32243a2a36645189e9f"/><file name="btn_window_close.gif" hash="c83f3cbbb2aedfc580dff78d5cfb63ed"/><file name="button1.png" hash="64be81dcc268ed39513ebdf31c463fb3"/><file name="button2.png" hash="2eaa97c0181145ebcba44b7045314546"/><file name="button3.png" hash="de022547c9533a127256b41f972cd64f"/><file name="calendar.gif" hash="b1468e5239504974c689eea5d93f86d4"/><dir name="catalog"><dir name="product"><dir name="placeholder"><file name="image.jpg" hash="097ab8a3051bc037ea3de0e17f440540"/><file name="small_image.jpg" hash="f825d16f97a640453553c79c48ebaa73"/><file name="thumbnail.jpg" hash="b2b682d28a08a748a73d2cda70ab5a57"/></dir></dir></dir><file name="cvv.gif" hash="83cdd38bf110b0f9c52fe84b56f45298"/><file name="cvv.jpg" hash="e27210d810bbab732935d9410936ef87"/><file name="fam_book_open.png" hash="0ba89b9fbe7e88d4c6896ed0a1f495aa"/><file name="free_shipping_callout.jpg" hash="cbf2e494ef7ca50acf8826321d739559"/><file name="grid-cal.gif" hash="b1468e5239504974c689eea5d93f86d4"/><file name="home_left_callout.jpg" hash="ee99a5586cf52e85c986d1275958a7da"/><file name="home_main_callout.jpg" hash="e6d1c119d5b24a5916fe394cb4b5cdc3"/><file name="i_arrow-top.gif" hash="3dbb0584e8eb1d96cc3d3c40c17d7aaf"/><file name="i_asc_arrow.gif" hash="40aa554212d6a1f60593c27d78d85fa3"/><file name="i_availability_only.gif" hash="bca1f00a50864171ad98317b778e869c"/><file name="i_availability_only_arrow.gif" hash="0cf32b72fefc94b89b74e4f3f02c2e93"/><file name="i_block-cart.gif" hash="cc19e21f9c89b70cc10354ff588ca8ab"/><file name="i_block-currency.gif" hash="643024bcae5ece554fdbbc041aeb297c"/><file name="i_block-list.gif" hash="fe8424127ecbe4b0d893bcf6f253dc1a"/><file name="i_block-poll.gif" hash="52d778dddbf48b8d04226bee9370a7ef"/><file name="i_block-related.gif" hash="4e277173b6372b1a90b0f19e0388ad54"/><file name="i_block-subscribe.gif" hash="9e5fee06a543742045118a95f2debcb8"/><file name="i_block-tags.gif" hash="67d1255c2c3e9ed1a5c845f8d4e4a3ba"/><file name="i_block-viewed.gif" hash="67d1255c2c3e9ed1a5c845f8d4e4a3ba"/><file name="i_block-wishlist.gif" hash="8f8cda89ca20ba4a9b2f8c91f73fdff9"/><file name="i_desc_arrow.gif" hash="92fd194bfae4ce5ae3354e1e47d7ac7d"/><file name="i_discount.gif" hash="908d44da90de5e54185764d093bbdb77"/><file name="i_folder-table.gif" hash="bf006ddb591d8ac95d2e895bf2fdbc8d"/><file name="i_ma-info.gif" hash="91259557447ee80eb1110fe0c85cb3b5"/><file name="i_ma-reviews.gif" hash="859c97695ec396c0b284a0c3c7c416ad"/><file name="i_ma-tags.gif" hash="1e83e3b0b677c92b3aa8a252268f7b86"/><file name="i_msg-error.gif" hash="e4f28607f075a105e53fa3113d84bd26"/><file name="i_msg-note.gif" hash="e774ee481a2820789c1a77112377c4e0"/><file name="i_msg-success.gif" hash="834dfafd5f8b44c4b24a4c00add56fcf"/><file name="i_notice.gif" hash="ebd56dc80b8346e10e93628bc0e6c372"/><file name="i_page1.gif" hash="704f7d4eccbdf9cabbad7770f18856ff"/><file name="i_page2.gif" hash="57a04ca584e05e28dc94c7e68f0af62e"/><file name="i_pager-next.gif" hash="ed4d6640624c2b6edeab4c212314bd6d"/><file name="i_pager-prev.gif" hash="75973b020105dccbaf34e49d7852552d"/><file name="i_print.gif" hash="0aed138181495642e9ab29e55d194d40"/><file name="i_rss-big.png" hash="6cf70e7c52a3f3d7b833ccadb041a555"/><file name="i_rss.gif" hash="e5bbc388d818c142868b4a1df0b48793"/><file name="i_search_criteria.gif" hash="cf67b9cc5c311ae3f99e68cd29ae17be"/><file name="i_shipping.gif" hash="91a0d2cc2eb2391f90ec8a75c04b3183"/><file name="i_tag_add.gif" hash="a736baa992aa55b6fb71e8742a04dc82"/><file name="i_tier.gif" hash="c5189e25afeb7c1a8c4902a42832593e"/><file name="i_type_grid.gif" hash="a1e5d8ac36fb2891ea16e729b95c552c"/><file name="i_type_list.gif" hash="61333d383ec142b8d270abe77324aa5d"/><file name="logo.gif" hash="48b7eb03807fdf80bdfb19b872cf84b8"/><file name="logo_email.gif" hash="8de347192e0524cff7a69e4020182dbd"/><file name="logo_print.gif" hash="8de347192e0524cff7a69e4020182dbd"/><file name="magnifier_handle.gif" hash="238fbdd7959f517db11c6f57ee4daaf4"/><file name="map_popup_arrow.gif" hash="6383b40a9e7bd3c95260bef4fbb1b163"/><dir name="media"><file name="404_callout1.jpg" hash="834e53a03e2921a2fd3c135c0c7189df"/><file name="404_callout2.jpg" hash="016984b4a1579df34147f9407098db73"/><file name="about_us_img.jpg" hash="726f36dd75b5a709a1a14acab1660188"/><file name="best_selling_img01.jpg" hash="5e7337a4061a636df8ee4bf979a092ac"/><file name="best_selling_img02.jpg" hash="b9a49c0964938ec72fb834cb166b9352"/><file name="best_selling_img03.jpg" hash="e3581487fb4589baecc553f2ce8d5247"/><file name="best_selling_img04.jpg" hash="7e59bf99f5f813e327595c52d3320174"/><file name="best_selling_img05.jpg" hash="e396892daec7ffcf7244082b3e596911"/><file name="best_selling_img06.jpg" hash="2702839637efbe0fd0a4bad41cd6a551"/><file name="cell_phone_landing_banner1.jpg" hash="b25562360fc470f1091ca7ea014a3290"/><file name="col_left_callout.jpg" hash="5f762006021e046f9bd536f37ea7c463"/><file name="col_right_callout.jpg" hash="dae22f37a542da272a35195ec286ec25"/><file name="electronics_cellphones.jpg" hash="8f6badbc32ce806c6109c788df6ef5e9"/><file name="electronics_digitalcameras.jpg" hash="953b8d7db6f0bdcd53b1d6b1386962b9"/><file name="electronics_laptops.jpg" hash="e050e92d72000e6bdc763a7b5888ec8a"/><file name="furniture_callout_spot.jpg" hash="28edc7d72486ab2362324995550d87af"/><file name="furnitures_bed_room.jpg" hash="b8616c5bffc23a92d2a1c97dae57b262"/><file name="furnitures_living_room.jpg" hash="2663737f3997cb1a49ce24d07dc8aefb"/><file name="head_electronics_cellphones.gif" hash="a69425966444ea597fb7c629114d5165"/><file name="head_electronics_digicamera.gif" hash="bde3cec3fc16b2d0ae57e7783eb00652"/><file name="head_electronics_laptops.gif" hash="b2c55387ffa92277315bdedeb4cb9b8f"/><file name="laptop_callout_mid1.jpg" hash="4ffb50bd3b7b32a78fd059b1571c202e"/><file name="laptop_callout_mid2.jpg" hash="662cf3881b06b090e9500496b19b03e4"/><file name="laptop_callout_mid3.jpg" hash="22aa71ecfe0aa9b6936a1eddb62d889e"/><file name="laptop_callout_spot.jpg" hash="2e469d1bd871355eaef6076487a973db"/><file name="shirts_landing_banner1.jpg" hash="4acc8620b009d835e5c25587671ea25d"/></dir><file name="np_cart_thumb.gif" hash="e9fdd943e0947e15f0638506f477e358"/><file name="np_more_img.gif" hash="ace357bfe3e81ffb62137cd5b25ae5e1"/><file name="np_product_main.gif" hash="d0cccda76de50efa025215ce85dacb1c"/><file name="np_thumb.gif" hash="e46270c89358ecc8341d1565c14644b8"/><file name="np_thumb2.gif" hash="8502866cdabc5c74aca7d7bd32a06a03"/><file name="opc-ajax-loader.gif" hash="e805ea7eca1f34c75ba0f93780d32d38"/><file name="pager_arrow_left.gif" hash="75973b020105dccbaf34e49d7852552d"/><file name="pager_arrow_right.gif" hash="ed4d6640624c2b6edeab4c212314bd6d"/><file name="ph_callout_left_rebel.jpg" hash="0ce8ad0026d8b8a83ed7acdf6209129b"/><file name="ph_callout_left_top.gif" hash="f17a036d75e5065eb76bafbb2c8ad7ff"/><file name="product_zoom_overlay_magnif.gif" hash="83834893e162221d6d9257fe67847370"/><file name="slider_bg.gif" hash="87bc1b46d87de4f6252c7216216627c3"/><file name="slider_btn_zoom_in.gif" hash="ef0fc67f77f30827ee67f4e744b60781"/><file name="slider_btn_zoom_out.gif" hash="68b3d1c28dc5aec4f6b64d70a6996b6f"/><file name="spacer.gif" hash="df3e567d6f16d040326c7a0ea29a4f41"/><file name="textimage.png" hash="99cee6b4075cdc3f659cc170fc4cc6fb"/><file name="validation_advice_bg.gif" hash="b85432906de8985a8b14eeb2dc652d3c"/><dir name="xmlconnect"><dir name="catalog"><dir name="category"><dir name="placeholder"><file name="image.jpg" hash="097ab8a3051bc037ea3de0e17f440540"/><file name="small_image.jpg" hash="f825d16f97a640453553c79c48ebaa73"/><file name="thumbnail.jpg" hash="b2b682d28a08a748a73d2cda70ab5a57"/></dir></dir></dir><file name="tab_account.png" hash="0498d73e47ed47179e5546dc15c17dc7"/><file name="tab_cart.png" hash="9055ba76e256a51d3fee53a8c41d5226"/><file name="tab_home.png" hash="07d0af93e167b9366d3d4fb3d6cdb31c"/><file name="tab_more.png" hash="b9fc21feb8d7655bc9c2985c37b0de2f"/><file name="tab_page.png" hash="ca05dbc42f944b8d4255f6675f6dd93a"/><file name="tab_search.png" hash="25e880eb2a4d06828e2e1c3f32d22400"/><file name="tab_shop.png" hash="fe602fc2e7093efef5ecc0b027a32d91"/></dir></dir><dir name="js"><dir name="Uize"><file name="blank.gif" hash="c5091c08fa2020c5eb3bf99e5271ef15"/><file name="blank.html" hash="abdc3d57a6ec1616e365fb7689984706"/></dir><file name="Uize.Array.Dupes.js" hash="2605a034d727a868da9cc3fe33016e2f"/><file name="Uize.Array.Order.js" hash="f5b2346f5036f79fdaba676ddb7712d2"/><file name="Uize.Array.Sort.js" hash="786de5604d9b61931c50d23e3c60f5b7"/><file name="Uize.Array.Util.js" hash="ebee5eb7a7336df125c5bdbfcdb2acb2"/><file name="Uize.Array.js" hash="08c89711d5644c5aeffc606def98f415"/><file name="Uize.Build.All.js" hash="dbf1223c34786c2d3a5748957f929839"/><file name="Uize.Build.AuditStrings.js" hash="6c82e075540a43c151e63caf35e3fe40"/><file name="Uize.Build.AutoScruncher.js" hash="20eaddfa858c867b930f76964450b603"/><file name="Uize.Build.ModuleInfo.js" hash="e882b4c00743ef8064b7351149fa47e5"/><file name="Uize.Build.NeatenJsFiles.js" hash="54daf16efe901b16af839f7a9481712a"/><file name="Uize.Build.RunUnitTest.js" hash="7c0e59adfa5bdf7d2586cb62e5d01f84"/><file name="Uize.Build.RunUnitTests.js" hash="cc9b837278611120574b6ca77e0b0559"/><file name="Uize.Build.Scruncher.js" hash="8adb053e62f0aa16be1ec4158b49bd1c"/><file name="Uize.Build.ServicesSetup.js" hash="ad38e34dd57bc26f8da7f2e0a1de28e4"/><file name="Uize.Build.UpdateCopyrightNotices.js" hash="4ec086a4a3e16b68401469565fdd4d42"/><file name="Uize.Build.Util.js" hash="d4d3a91bc1fb777b5003d0a6c04a9586"/><file name="Uize.Build.js" hash="7042720907c23e8091e8fd8186a2f436"/><file name="Uize.Class.Value.js" hash="02801703e3053612b9a88f492d449ab6"/><file name="Uize.Class.js" hash="440c5c3e1a3ce4b0fde0d7a0d79da981"/><file name="Uize.Color.js" hash="b500bafac7a8ac7c486f98d398b7628b"/><file name="Uize.Color.xCmyk.js" hash="e369244304866560cd3f4213429fd041"/><file name="Uize.Color.xHsv.js" hash="67288511ed209463ba1786c8ba77ed3a"/><file name="Uize.Color.xSvgColors.js" hash="bbbab4fac2710ed9e8277717749e82e8"/><file name="Uize.Color.xUtil.js" hash="120830b9a3ec50220f499c13dffb9726"/><file name="Uize.Comm.Ajax.js" hash="e92f0af5c156f2c0e1749162466fc73e"/><file name="Uize.Comm.Iframe.Upload.js" hash="d140b00e21f7284868dcec4817e0f082"/><file name="Uize.Comm.Iframe.js" hash="5a006dd035374955d479624f32ca4a90"/><file name="Uize.Comm.Script.js" hash="8e639bc2c0ba30f13e77f45f2274e2a0"/><file name="Uize.Comm.js" hash="fc989966aa1fe24c0294de88317fe144"/><file name="Uize.Cookie.js" hash="4c12b969f764cb638cca43bf8de63c42"/><file name="Uize.Curve.Mod.js" hash="736846b970802e66b86be133a9bda036"/><file name="Uize.Curve.Rubber.js" hash="5b7ecf63eae301c373e408fc9545c1cf"/><file name="Uize.Curve.js" hash="dddb9779cb9c5895039bc5399c8db49a"/><file name="Uize.Data.Combinations.js" hash="e7a8fa8d9c51ced46a1b75fa4435f654"/><file name="Uize.Data.Csv.js" hash="75c2701cd1aa42c5b22a4be1a50bed10"/><file name="Uize.Data.Matches.js" hash="97c416cc604f06f77efe7f082b03eee4"/><file name="Uize.Data.NameValueRecords.js" hash="bfa797833bd498ca6ab6f8925fbc8e82"/><file name="Uize.Data.PathsTree.CompactString.js" hash="5079a25ced34efa6b6af81bea7565086"/><file name="Uize.Data.PathsTree.js" hash="703a0e513d2a865512ac7b4509cc7e2b"/><file name="Uize.Data.Simple.js" hash="6acb8b496b441fbb6b3780610ed97c2e"/><file name="Uize.Data.js" hash="08146010df94771ddc7c9172061ed6e8"/><file name="Uize.Date.Formatter.js" hash="e1177f9dd79e45fc39871bfb1f6948d4"/><file name="Uize.Date.js" hash="a0da3e5ea55550aa5e9102b71630f420"/><file name="Uize.Doc.Simple.js" hash="0aea30ecaaa8a8bdd1bf28d9bc17c8d6"/><file name="Uize.Doc.Sucker.js" hash="1b4831b080bfee5d9e4adee0a0d1ef92"/><file name="Uize.Doc.js" hash="b28e65a2fbdc35f3a89bfb4b3d21fc45"/><file name="Uize.Fade.js" hash="26f63a5b9c58f0f313e8eac2788d583b"/><file name="Uize.Fade.xFactory.js" hash="2c637988ebada46d666e11e74154f29d"/><file name="Uize.Fade.xSeries.js" hash="b97c53ffd42f57ba09bc91ead96a54aa"/><file name="Uize.Fx.js" hash="ac4ad1651ed09b867ff9281b9a176020"/><file name="Uize.Fx.xShadows.js" hash="24dc5bdafef6c296be48c7ea5e2bb605"/><file name="Uize.Fx.xTextShadow.js" hash="ca5b15caf68a41776464f09df3da06f3"/><file name="Uize.Json.js" hash="49debbc4b15d905aaa141d5aefb9f154"/><file name="Uize.Node.Classes.js" hash="5ab3c6a387e654034f6742949776cd15"/><file name="Uize.Node.Event.js" hash="8b28521a3b2bbab491b7bedc27fa41d0"/><file name="Uize.Node.Form.js" hash="4832a2e819f330541923e2735c6ba1a6"/><file name="Uize.Node.Tree.js" hash="46ee8fafe4fe68aa7db84b5d38a19275"/><file name="Uize.Node.Util.js" hash="128161cff9158aafe18b5a001ea1e8cb"/><file name="Uize.Node.VirtualEvent.Edge.js" hash="305ee1c644e6f4fa58010be65a339a57"/><file name="Uize.Node.VirtualEvent.js" hash="aab1c842a71af4efea79a3249a9ddd6f"/><file name="Uize.Node.js" hash="a57439c5827744de5d06ed96153a11bc"/><file name="Uize.Service.Adapter.js" hash="ec590ae504d4b6df6a08a0ee78fcfaa7"/><file name="Uize.Service.js" hash="c3d303d918ad5cf7d2ebaa412b1a5ffd"/><file name="Uize.Services.FileSystem.js" hash="2ae1bc0d6755fafd2952fe9f98b1b0c7"/><file name="Uize.Services.FileSystemAdapter.js" hash="6ad53d5a4b72fc45180caefd116fdfcf"/><file name="Uize.Services.FileSystemNode.js" hash="224f87e8b4fd094aa254759bebe4c81f"/><file name="Uize.Services.FileSystemWsh.js" hash="34244dc38e1f5fd882010b80e2391b94"/><file name="Uize.Services.Setup.js" hash="897a17a1681e884d83722a3662eca1cc"/><file name="Uize.Services.js" hash="1fd4c1cddefc0804173fd7fde21e8336"/><file name="Uize.String.Builder.js" hash="4e04a3dc29a72979c6a4e219febbc15a"/><file name="Uize.String.Discombobulator.js" hash="605d0f3be806c876cff09bc6fa5fd96a"/><file name="Uize.String.Lines.js" hash="4d5e9de5ff500808a0878b9ae53ba686"/><file name="Uize.String.js" hash="23f04e1313ae010595e81a94c0702f49"/><file name="Uize.Template.Module.js" hash="7b535d6a29dd28ad6f31bb74334ec082"/><file name="Uize.Template.js" hash="5e20bf981e4e1d0e59db0ac44cead6ed"/><file name="Uize.Templates.Calculator.js.jst" hash="ff933acad671517ea778558587fb4d14"/><file name="Uize.Templates.Calendar.js.jst" hash="a024dfd9f2cd718cd97408563dd95599"/><file name="Uize.Templates.Collection.js.jst" hash="8439ae77db09bcd632812c74079e9e37"/><file name="Uize.Templates.CollectionItem.js.jst" hash="fa6d9a7144228d1ebe1c956f93e599cb"/><file name="Uize.Templates.ColorInfo.js.jst" hash="eaa43fcbceb53558d58f7d9ce13ed833"/><file name="Uize.Templates.HashTable.js.jst" hash="135f6fc53f3974a13c376ef00cb5cfcd"/><file name="Uize.Templates.List.js" hash="5e53b3addddf7cbf6aab38eb8362c0a4"/><file name="Uize.Templates.Log.js.jst" hash="058643979139db8cdf9cc8ccebaf2455"/><file name="Uize.Templates.SevenSegmentDisplay.js.jst" hash="4837d0c3efa65af73c8bddcb09a8047c"/><file name="Uize.Templates.SevenSegmentDisplayDimsCss.js.jst" hash="7d6dcef72823c9a6b710b983a5f541aa"/><file name="Uize.Templates.SimpleDoc.js.jst" hash="a81759f6ee9310ba4bb24d051478f5c6"/><file name="Uize.Templates.js" hash="d87ba12d0c350277385e6d097039032c"/><file name="Uize.Test.Performance.ArrayBuildingStyles.js" hash="fa939b8eade778207fceabd196ac199e"/><file name="Uize.Test.Performance.js" hash="c0170839f61d96f1401b28430cd00874"/><file name="Uize.Test.Uize.Array.Dupes.js" hash="b380f4e0a0165e4c1faa2f75389b045c"/><file name="Uize.Test.Uize.Array.Order.js" hash="df5ac939d9a49295997de0ad68ec08d8"/><file name="Uize.Test.Uize.Array.Sort.js" hash="340fe288d1e292ca5d9185e3b18babcc"/><file name="Uize.Test.Uize.Array.Util.js" hash="8e96eb5330e1c40943476db427a621e3"/><file name="Uize.Test.Uize.Array.js" hash="dae49751b1e4184ae55667b97fd86acb"/><file name="Uize.Test.Uize.Class.js" hash="14643d943cd716a24878d441402842c7"/><file name="Uize.Test.Uize.Data.Combinations.js" hash="f078d471bae368aaae769c584da9ca02"/><file name="Uize.Test.Uize.Data.Csv.js" hash="c244f341c3df8fb66ec6ce914495798e"/><file name="Uize.Test.Uize.Data.Matches.js" hash="a23223cefcf7ce0ccd2a8ca850fb2555"/><file name="Uize.Test.Uize.Data.NameValueRecords.js" hash="d6badf14d873a3bb9dcf556020092a72"/><file name="Uize.Test.Uize.Data.PathsTree.CompactString.js" hash="f98dfe140dda4e31d3aef4b641318efc"/><file name="Uize.Test.Uize.Data.PathsTree.js" hash="30230c513fee2ca55d65ccb1c090f2c1"/><file name="Uize.Test.Uize.Data.js" hash="9e9dbd0511e8e10d81714a615a2519c2"/><file name="Uize.Test.Uize.Date.Formatter.js" hash="51dbbff18d1683583277ba70ce73aada"/><file name="Uize.Test.Uize.Date.js" hash="59b453fc47414978af4378155bdc1761"/><file name="Uize.Test.Uize.Doc.js" hash="398a92bc6c5de58134cc053ef7a55f21"/><file name="Uize.Test.Uize.Node.Classes.js" hash="aee8d643f7866cb8f74f05d213fa96c6"/><file name="Uize.Test.Uize.Node.js" hash="7bbcd5a3ae301f38a454ea5e35fe00b1"/><file name="Uize.Test.Uize.Service.js" hash="99d24009b03b96e8d7d1395175d1c3a9"/><file name="Uize.Test.Uize.Services.FileSystem.js" hash="e88fbd6a625bf3f3a5f0d1e3b868471a"/><file name="Uize.Test.Uize.Services.js" hash="09f2dfdd50938d4ab44423445eb36881"/><file name="Uize.Test.Uize.String.Builder.js" hash="1979b7fc6bb170d58b1ede48e093c68e"/><file name="Uize.Test.Uize.String.Lines.js" hash="0a9dd0e8ec4bb8f28c17945b7f96b71d"/><file name="Uize.Test.Uize.String.js" hash="6ccbe2f949c4aa90e94c172928e989f3"/><file name="Uize.Test.Uize.Template.js" hash="cdba1c44705e0a31a7cc9db8013d9011"/><file name="Uize.Test.Uize.Templates.Calculator.js" hash="48832202adeaf2fc4402137702f519b6"/><file name="Uize.Test.Uize.Templates.Calendar.js" hash="2ec44950a78f8ba837ee6d007a5aa26d"/><file name="Uize.Test.Uize.Templates.Collection.js" hash="3cb6f2da0eb99f3e54140a1aad934344"/><file name="Uize.Test.Uize.Templates.CollectionItem.js" hash="e8da8e17d7a60382b0cd1623038b9bb2"/><file name="Uize.Test.Uize.Templates.ColorInfo.js" hash="f90b2e79c87414b9b661a6f0086b02b3"/><file name="Uize.Test.Uize.Templates.HashTable.js" hash="7993d5d485f2a5b53b0ce2e8d4ae06e7"/><file name="Uize.Test.Uize.Templates.List.js" hash="00bc530d57c0a7b0c292beb0fe4c6c2d"/><file name="Uize.Test.Uize.Templates.SevenSegmentDisplay.js" hash="4bc8621104266fac09ca71428eac895d"/><file name="Uize.Test.Uize.Templates.js" hash="661104ed8e52a95c41d5be480a472227"/><file name="Uize.Test.Uize.Url.js" hash="aadca3277d202102a0f2f89a5160ffad"/><file name="Uize.Test.Uize.Util.PropertyAdapter.js" hash="f9e5ef83850959dd2f18a33921389c6f"/><file name="Uize.Test.Uize.Util.js" hash="419290980e88b45916ea20a139ad0342"/><file name="Uize.Test.Uize.Xml.js" hash="0989621e5780520fbde99621a26e5ca1"/><file name="Uize.Test.Uize.js" hash="c9488d6c4cf632813abd6e0f8c797d33"/><file name="Uize.Test.js" hash="4f67fa8a938b3dd735d6776e0e5955cb"/><file name="Uize.Tooltip.js" hash="1b6b8343404896bf49adc00aaa60ae31"/><file name="Uize.Url.js" hash="e17663294a5bd33fbd2c5d8f85b2ee90"/><file name="Uize.Util.Coupler.js" hash="1d1faf8d2a747addebc76cf12185b990"/><file name="Uize.Util.Cycle.js" hash="0a51605ebf5443e49d020391bcef56bb"/><file name="Uize.Util.Needs.js" hash="d7af6d2b6bb2bc3521d1652662a442f2"/><file name="Uize.Util.Oop.js" hash="1735ef9dafc942f271aee4c5ee6d7982"/><file name="Uize.Util.PropertyAdapter.js" hash="0ecd21e1277bf641aa83ad4ef170f838"/><file name="Uize.Util.js" hash="c106bcf2a60f9bc47bae1738bcc3bfca"/><file name="Uize.Widget.AutoSuggest.js" hash="684f837ce54816bf89c4325ce51543ec"/><file name="Uize.Widget.AutoTooltip.js" hash="719ae9de278152f4603cecc7f90a46fb"/><file name="Uize.Widget.Bar.Progress.js" hash="3444278a000c46351e8f2ad102d0a805"/><file name="Uize.Widget.Bar.Slider.Plus.js" hash="6000e4c16226f26abf60904fc8a5d59d"/><file name="Uize.Widget.Bar.Slider.js" hash="252ff86e11921a650f5d01725bee7d7d"/><file name="Uize.Widget.Bar.Slider.xSkin.js" hash="68792b3d7a8cafa88626befe6e03fb1c"/><file name="Uize.Widget.Bar.js" hash="fe1639e0e510aecbe7a37d52a5133128"/><file name="Uize.Widget.Beam.js" hash="4962697e7b57a6e48f678486d5673535"/><file name="Uize.Widget.Bevel.js" hash="f17228fd6a8c77103121c121b1277aa4"/><file name="Uize.Widget.Button.Checkbox.js" hash="2cc0a2399823897bab12ce88d1877c15"/><file name="Uize.Widget.Button.Filter.js" hash="ddbf73e8a4b84348ed59895a0e7b6f56"/><file name="Uize.Widget.Button.Toggle.js" hash="1c5ce73d92e0b0fdc1a757a05e14aac4"/><file name="Uize.Widget.Button.ValueDisplay.Selector.js" hash="90ac28149da53fae8c72cf3390f5287f"/><file name="Uize.Widget.Button.ValueDisplay.js" hash="7649d0fa4d283f072d0036cd2d01bf39"/><file name="Uize.Widget.Button.js" hash="c25f09c7cd6b99887bceca24a732f004"/><file name="Uize.Widget.Calculator.js" hash="32bc1716532407cd31bff64fed45ea65"/><file name="Uize.Widget.Calendar.js" hash="55fe75fa2b3a2560835c2ee049d1353c"/><file name="Uize.Widget.Captcha.Recaptcha.js" hash="3eaf5433a8c1651ce3cd9bd0a61d3a48"/><file name="Uize.Widget.Captcha.js" hash="49ae6bf10357e59aa036d1476020fb43"/><file name="Uize.Widget.Collapsy.js" hash="92944e5556cf882b74cdbc7575b36748"/><file name="Uize.Widget.Collection.Dynamic.Table.js" hash="74f90d0a468e30b78cc4a91ebd5376dd"/><file name="Uize.Widget.Collection.Dynamic.js" hash="7456607a00882cbcadd80adedb2aaafe"/><file name="Uize.Widget.Collection.js" hash="8af1a4f1cefc1e6bf1182e50ebe87312"/><file name="Uize.Widget.CollectionItem.Zooming.js" hash="a9cd61bc4095b87b3180143a2e8f3790"/><file name="Uize.Widget.CollectionItem.js" hash="e6da3fa827bc2b13a5601e6641c704e4"/><file name="Uize.Widget.ColorCube.Draggable.js" hash="dc20c853e1e9ad5e69b7a2b0f9575f9a"/><file name="Uize.Widget.ColorCube.js" hash="3567ef1524750b09181b6733e252d45a"/><file name="Uize.Widget.ColorInfo.js" hash="46b8e0aad370f09b73f62ca153b60b5c"/><file name="Uize.Widget.ColorPicker.js" hash="4b4c8f06f1e06e84e268fb3cc78611f0"/><file name="Uize.Widget.Committer.js" hash="6abb30292f21efa330f0e4752dde15af"/><file name="Uize.Widget.Count.js" hash="29b6da3a51ae92dc6d2c5359b4449c97"/><file name="Uize.Widget.Dialog.Confirm.js" hash="89d1372f3d41603b85f1248c657b0433"/><file name="Uize.Widget.Dialog.Form.js" hash="2d8cff680a722db651996e3087d89787"/><file name="Uize.Widget.Dialog.Iframe.js" hash="05f18bdd45441900ec142ec1a4aa67d0"/><file name="Uize.Widget.Dialog.Picker.Date.js" hash="9b24799b06785b50dbbb32ab2814ab31"/><file name="Uize.Widget.Dialog.Picker.Palette.Selector.js" hash="33eb4f8baa7199aefce51db621f65969"/><file name="Uize.Widget.Dialog.Picker.Palette.js" hash="246e59f4cb9d490790ba570f59ba7498"/><file name="Uize.Widget.Dialog.Picker.js" hash="1895d3d3373e7ed2e6b55db4297dc5b3"/><file name="Uize.Widget.Dialog.js" hash="07159f8a77b430a6d1d85f30884fcdcd"/><file name="Uize.Widget.Dialog.xResizable.js" hash="4793bedce60eb093efc2936a83ae430c"/><file name="Uize.Widget.DirectionalPad.js" hash="a3c211fa2dc9ecdb9bb90dddd399fbeb"/><file name="Uize.Widget.Drag.Move.js" hash="70388cd99ad0039cb6f8db756daca093"/><file name="Uize.Widget.Drag.js" hash="5eca863ed769a37c92d617982559d385"/><file name="Uize.Widget.EdgeHugger.js" hash="08639316c55e3950cd49edf5b19e182e"/><file name="Uize.Widget.EggTimer.js" hash="65b625bf808ad7d6640260bb67d381b7"/><file name="Uize.Widget.FilterGroups.js" hash="deaf92ec5fd8b21f725f51c884c09772"/><file name="Uize.Widget.Fleeting.js" hash="801831ec57eda9b18648bb1b29c141e5"/><file name="Uize.Widget.Flip.js" hash="346efea4d0ad5902c2cefff48c0ddef9"/><file name="Uize.Widget.Form.js" hash="d38c4f5cd52c50330f8b85d1343fea69"/><file name="Uize.Widget.FormDialog.js" hash="bba8a84c1d6d60720a7bb8a176b6549d"/><file name="Uize.Widget.FormElement.Select.js" hash="84894c896ce368c4b7febcf39f3fafd8"/><file name="Uize.Widget.FormElement.Text.js" hash="e938163c1171575e807ec1c6be48d892"/><file name="Uize.Widget.FormElement.js" hash="d071aa3a89aeb86f8a394c30057c7c00"/><file name="Uize.Widget.FormElements.js" hash="38a361a71c97a8f8836e85e9443f1fd6"/><file name="Uize.Widget.FormWarnings.js" hash="2842c364ffa4e57e58aa140aec06e7e0"/><file name="Uize.Widget.HoverFader.js" hash="c8934610725dfa495c1df2a91b56d19d"/><file name="Uize.Widget.ImagePort.Draggable.js" hash="55e3dba289c3a417f86289d536fef6c1"/><file name="Uize.Widget.ImagePort.js" hash="d72a64a1758954db790a7cc6c51e4f58"/><file name="Uize.Widget.ImageWipe.js" hash="64d29ab6065fe70ff398470e1448fadc"/><file name="Uize.Widget.ImageWipe.xPresets.js" hash="2651f07264ec8630a8d8340bf49779b6"/><file name="Uize.Widget.InlinePicker.Selector.js" hash="1e61b68e7d99b18d89d77e70e31cc0be"/><file name="Uize.Widget.InlinePicker.js" hash="f7f628c4df9e26b41aba70a66b32f33e"/><file name="Uize.Widget.ListEditor.js" hash="da54c3e56a209134bda67498e7b67f2e"/><file name="Uize.Widget.Log.InstanceEvents.js" hash="85be92792f3c8e8377cd332f9ba04c23"/><file name="Uize.Widget.Log.js" hash="af71b604f1272ef90146a9a493d0e697"/><file name="Uize.Widget.MagView.js" hash="ecbb8a678d77c3e0cd72b788adbacd3f"/><file name="Uize.Widget.Mask.js" hash="ee2df8f9bc6a44cd77f1c7d516b555c4"/><file name="Uize.Widget.Options.Accordion.js" hash="5265fcce6b35b4df23342ea54625fea0"/><file name="Uize.Widget.Options.FilterGroup.js" hash="65b760469990f5e481fd7af0c2edeed4"/><file name="Uize.Widget.Options.Popup.js" hash="60673eae63ff6e7c18bca0420fa0f184"/><file name="Uize.Widget.Options.Selector.js" hash="ce04206d428442a16bc01164ba8723b3"/><file name="Uize.Widget.Options.Tabbed.Fading.js" hash="73c10e9926ce9e88f0dafe6da8742789"/><file name="Uize.Widget.Options.Tabbed.js" hash="91ea8e9b656fdf0048a253c57ccc3934"/><file name="Uize.Widget.Options.js" hash="abe6d60b515c9d20eb544123ce3ecb26"/><file name="Uize.Widget.Page.js" hash="6bf51ac69d6f5fa68d43bea0e7238c96"/><file name="Uize.Widget.Page.xDeferredLinks.js" hash="e2a8bfadee11fed31d61334933371157"/><file name="Uize.Widget.Pagination.js" hash="4629555122deec93d4885c1faac607f5"/><file name="Uize.Widget.Picker.Date.js" hash="d7fcc4eeb850c6122375e294050d049e"/><file name="Uize.Widget.Picker.Palette.Selector.js" hash="b6a517dc7c84d6cd33b8d4a75239b1be"/><file name="Uize.Widget.Picker.Palette.js" hash="f7c5c349bd214d47ed9ebe142f280999"/><file name="Uize.Widget.Picker.js" hash="6011a6328439663f3ade3215b30afd69"/><file name="Uize.Widget.Population.js" hash="37007ef7605f181ec80d649008e9b7f9"/><file name="Uize.Widget.PopupPalette.js" hash="24218815109de31621056d3d4d63fea7"/><file name="Uize.Widget.Resizer.Marquee.js" hash="df1dc7450ca3e7fa77dab9bcd1d4f2a9"/><file name="Uize.Widget.Resizer.js" hash="d90f8d1d2934c3ded89e0845e66d8f5e"/><file name="Uize.Widget.Scrolly.js" hash="99b748d67a9e69916fdf90fdbb595773"/><file name="Uize.Widget.SegmentDisplay.Seven.js" hash="3378f8a477c9be9cd34883ae86e8e97b"/><file name="Uize.Widget.SegmentDisplay.js" hash="2d0dda6ed3e0fded8a1288f8cba1b8d6"/><file name="Uize.Widget.SlideShow.AutoAdvance.WithSlideSelectors.js" hash="b9f7e8e08598ac6c2aecaa75c8824305"/><file name="Uize.Widget.SlideShow.AutoAdvance.js" hash="be8a1324d41a006d21a388cd8ccc98a5"/><file name="Uize.Widget.SlideShow.js" hash="bc2322fab4c8ee05ba0e8a3195e35dab"/><file name="Uize.Widget.Stretchy.js" hash="a9ed34f8d946a0c17905991b23bfcdd7"/><file name="Uize.Widget.Swap.Deck.js" hash="fcd1ae4fcd09b974ee0665c44952b2eb"/><file name="Uize.Widget.Swap.Html.js" hash="3c3d4892a731748402a056e91636df78"/><file name="Uize.Widget.Swap.Image.Cycle.js" hash="a37da1b39eb21a4922a4bf28a2aa52b5"/><file name="Uize.Widget.Swap.Image.js" hash="660c2c34ca514130b56e19d66c70ded3"/><file name="Uize.Widget.Swap.js" hash="b112d3c4a50969f602e1d3e0e657b2c8"/><file name="Uize.Widget.Swap.xPresets.js" hash="8fef5910da00a9d46f7e8e3228979e7c"/><file name="Uize.Widget.TableSort.js" hash="db24df257dd616ab9e62112235a40f03"/><file name="Uize.Widget.TextInput.js" hash="1b0ad7b77f34c92b11ab6efbdd599699"/><file name="Uize.Widget.ThumbZoom.js" hash="18d4addfce77a82ae42481de2ef66835"/><file name="Uize.Widget.Tree.List.js" hash="3cf22a03c696c3a894b1ac47c2c53e0d"/><file name="Uize.Widget.Tree.Menu.js" hash="94c182930d698c5a91d0f44fd16a2b54"/><file name="Uize.Widget.Tree.Select.js" hash="d48930fcc10c2679fd70860aeb87ab14"/><file name="Uize.Widget.Tree.js" hash="3e820fc724b5253080ff94dcc836af0e"/><file name="Uize.Widget.js" hash="c4d3b1ac01cd56a39975b9f7f6ffc72d"/><file name="Uize.Wsh.js" hash="21999977b560b676b368ca77164a750e"/><file name="Uize.Xml.js" hash="3de665c5430178f968b5c858573cab7c"/><file name="Uize.js" hash="4e27541f196b1c81287a341cbde48c02"/><file name="UizeSite.Build.BuildCodeSitemap.js" hash="b900b903c86eb092fb2797961422ed81"/><file name="UizeSite.Build.BuildIndexPages.js" hash="65a712a864df07065a00b8dafd0ebddb"/><file name="UizeSite.Build.BuildJsModules.js" hash="94596ddc025c8a2345643746073771a0"/><file name="UizeSite.Build.BuildPagesFromSourceCode.js" hash="e1090e251ac76144527fea7017af71da"/><file name="UizeSite.Build.BuildSimpleDataPages.js" hash="56d81f810f7f24bd6f1c27c35ee54b8f"/><file name="UizeSite.Build.BuildSimpleDocPages.js" hash="3c28605e53f088a496b92cfd3a4a9b65"/><file name="UizeSite.Build.BuildSotu.js" hash="6dcfde7a3e3ece45fecad7f46420f2c9"/><file name="UizeSite.Build.BuildStaticPages.js" hash="573dc8bb2aacc4351d85241be66f5e60"/><file name="UizeSite.Build.BuildWidgetPages.js" hash="b89b34e208552248d614ec95f8ba279b"/><file name="UizeSite.Build.Deploy.js" hash="02380a33bfee11ff3b96f96e30cf486e"/><file name="UizeSite.Build.File.js" hash="93f00f0f505a44a85ce4a2ab35adb91c"/><file name="UizeSite.Build.FileBuilders.js" hash="4a86214937c9d53c0f6948f8af7c5bfc"/><file name="UizeSite.Build.WebServer.js" hash="8da4777dce575600b47c54a116a17e81"/><file name="UizeSite.Build.js" hash="1d1f605928a760ee54af860ea2e61e9c"/><file name="UizeSite.Delve.js" hash="3cd5e298dfe5b9b96923a5e15339de4f"/><file name="UizeSite.Delve.library.js" hash="f3829dcd37f1aa456a6434fa2a945b18"/><file name="UizeSite.DelvePageWriter.js" hash="eaa3e60d7c1afbd70582b8a2467f8a3b"/><file name="UizeSite.DialogConfirm.js" hash="f0ba9906eae16d702a20897939a21a47"/><file name="UizeSite.DialogDate.js" hash="682f3d5c9dd428b2fd4446752e0a791e"/><file name="UizeSite.Page.Doc.js" hash="e1295d7746c4b9a485d73460ea7fd193"/><file name="UizeSite.Page.Doc.library.js" hash="7acafea6f8095519de9f4fae62febfe2"/><file name="UizeSite.Page.Example.Test.js" hash="68fb11e1a6700bb9e6236b68bf6d71cc"/><file name="UizeSite.Page.Example.Test.library.js" hash="64073d2e6b572af05be05d76b76f7730"/><file name="UizeSite.Page.Example.js" hash="a2b2a7870a691b04bbd4f46503eebeae"/><file name="UizeSite.Page.Example.library.js" hash="73ae4ecd9eadbd4a1411ec26089d7fe6"/><file name="UizeSite.Page.Home.js" hash="eda2104d78ccc9486f673413f869d4bb"/><file name="UizeSite.Page.Home.library.js" hash="fb16fd1f63b09392e70d72b4ab375dcc"/><file name="UizeSite.Page.Index.js" hash="d229b0b851b132ee0751f309d714c639"/><file name="UizeSite.Page.js" hash="42218e09bff5b732f322d1d83958f761"/><file name="UizeSite.Page.library.js" hash="6722ca479156e5796c9f589b64d10050"/><file name="UizeSite.ParamsInspector.InlinePresets.js" hash="085965463872eb0f64bc3b4d87b860b5"/><file name="UizeSite.ParamsInspector.js" hash="b8bd6ddb3462a5c32da0630588a03ab4"/><file name="UizeSite.SiteMap.js" hash="595cac7426e97889b7ab7e60d1db5609"/><file name="UizeSite.Templates.DataBar.js.jst" hash="8195b580a2783b5ec7ea2aa3d40dbf83"/><file name="UizeSite.Templates.DelvePageHtml.js.jst" hash="93638d97888d91e75c9ac4b499855242"/><file name="UizeSite.Templates.DelveUiHtml.js.jst" hash="3ab43de151b84c51cce6a1a4b5c96d7b"/><file name="UizeSite.Templates.Dialog.Confirm.js.jst" hash="55fb4bc147e2aff1685b4f6362859859"/><file name="UizeSite.Templates.Dialog.Picker.Date.js.jst" hash="5f20e03bff02569b04c5aa84d1d030e8"/><file name="UizeSite.Templates.Dialog.Picker.js.jst" hash="a480ff32113567ac9e394f922600d5b1"/><file name="UizeSite.Templates.Dialog.js.jst" hash="bd6f120b476ebb134d84184ca5206fcf"/><file name="UizeSite.Templates.Footer.js.jst" hash="5e9f474caa60a8a479a8def9027cd62c"/><file name="UizeSite.Templates.IndexPage.js.jst" hash="751936b4aaeab3a55b9f4c4bf6235bb9"/><file name="UizeSite.Templates.JavaScriptSourceSample.js.jst" hash="025b6cb45cb7efe697a0f70aa30ef5c8"/><file name="UizeSite.Templates.ListingsPage.js.jst" hash="72cf2ea4455c06d8d0c1fc468c6c29b0"/><file name="UizeSite.Templates.ParamsInspector.js.jst" hash="d507f30c1dead90d5d245119c93b15e2"/><file name="UizeSite.Templates.ParamsTable.js.jst" hash="50b060a9a11b0efd74ac19d027b71a31"/><file name="UizeSite.Templates.ShareThisPanel.js.jst" hash="2c8c4f4ee470d1e94805b8accfd18af0"/><file name="UizeSite.Templates.SimpleDoc.js.jst" hash="b488d018a6bea5507f08d001fd24104c"/><file name="UizeSite.Templates.SimpleDocSample.js.jst" hash="bc3b993b3eb3621afa72e15e738d815f"/><file name="UizeSite.Templates.SlideShow.Basic.js.jst" hash="e29ed3a34c54bd1d13ed63a4c161f8ad"/><file name="UizeSite.Templates.SlideShow.Wipes.js.jst" hash="0930fba6a62535a89f37dea015de48a0"/><file name="UizeSite.Templates.SlideShow.js.jst" hash="66790a98d00ff2683f401f2ad10e419b"/><file name="UizeSite.Templates.Tour.js.jst" hash="343ddf547cabd928f05b7b4692255860"/><file name="UizeSite.Templates.WidgetToGoTitle.js.jst" hash="383cba3644faa15f7a843e97c674fd52"/><file name="UizeSite.Templates.js" hash="61ff069ddd54e428f5f248ef6a29cfd5"/><file name="UizeSite.TestDataFruits.js" hash="c69ba8bcb281353abb252f5367a02281"/><file name="UizeSite.TestDataObject.js" hash="7d89d2661d681569690fe4824e691008"/><file name="UizeSite.TestDataPhotos.js" hash="fb9adda89d62bc18b9e5bb67a9012e66"/><file name="UizeSite.TestWidget.js" hash="70393268e03823b20a1dc8bd6594ebdb"/><file name="UizeSite.WidgetToGoPage.Calculator.js" hash="6dce02e686f470a89a7f14d1c5d2ac16"/><file name="UizeSite.WidgetToGoPage.Calculator.library.js" hash="5ebe568c1c131e1d7222bd835522ebaf"/><file name="UizeSite.WidgetToGoPage.Calendar.js" hash="d76511565dc8639bba268463563586af"/><file name="UizeSite.WidgetToGoPage.Calendar.library.js" hash="f3fd0f26f700ab8041872a4e1e986fce"/><file name="UizeSite.WidgetToGoPage.js" hash="97c1132816dee96416f324f6724d31a8"/><file name="UizeSite.js" hash="9e6b627355f541b234d05dc9373dcd59"/><dir name="Uize_Widget_Bar_Progress"><file name="full-bg.gif" hash="771b349d415e4efe149d7d0393ac641b"/><file name="track-bg.gif" hash="ae26c0f7db8323ebe167781577ff2361"/></dir><dir name="Uize_Widget_Bar_Slider"><file name="border-bl.gif" hash="26009df3315fcef416b7dc6a7d0a1ea6"/><file name="border-br.gif" hash="f53897b011a9e1245e9af1252c8426d9"/><file name="border-h.gif" hash="b61aff88496caefae9d40434978f1374"/><file name="border-tl.gif" hash="099d6f0e268455c1b327d3036df85b7b"/><file name="border-tr.gif" hash="4b083197a22be7f3331f93b507dd3d5a"/><file name="border-v.gif" hash="0fc328534e92fc3dd88e8b35e7e8cba1"/><file name="knob-horizontal.gif" hash="a3cb25cc375aa5fe2fa9dd2ba23731c7"/><file name="knob-vertical.gif" hash="74b36a675fe0e9cba79b22df8e144905"/><file name="track-bg-horizontal.gif" hash="c511fa1939358cbbc545192ff437c9f8"/><file name="track-bg-vertical.gif" hash="6c02d3d38a721bf25a3f8d1c0cea08b0"/></dir><dir name="Uize_Widget_Beam"><file name="diamond-bottom-left.gif" hash="9f99d89a94b28b6ce0a4d3b21322f78a"/><file name="diamond-bottom-right.gif" hash="2e0285b25f22922728cca6d14d8ccaee"/><file name="diamond-top-left.gif" hash="aae2068b2a1f3ccfda34b01a9ae6cf6d"/><file name="diamond-top-right.gif" hash="6c4bb7095a189f91bcbbd88cb387961e"/></dir><dir name="Uize_Widget_Tree_List"><file name="arrows-black-bullet.gif" hash="e0469e86364796a97293816881c65167"/><file name="arrows-black-collapsed.gif" hash="06bfc006a6a15e1b1ba37145db355c35"/><file name="arrows-black-expanded.gif" hash="e7507eac6e97c5e3310ef611f769a1e3"/><file name="arrows-black-on-white-bullet.gif" hash="cede143c398ce59695e6d15410099bb7"/><file name="arrows-black-on-white-collapsed.gif" hash="288ab5cad56c766cbef52982c2449d13"/><file name="arrows-black-on-white-expanded.gif" hash="a105a8394ee6cd019b187acbbf23188d"/><file name="arrows-bullet.gif" hash="73ccd239e28174ecae099f6496294704"/><file name="arrows-collapsed.gif" hash="c48397d4ac1d824100b9d1062529b113"/><file name="arrows-expanded.gif" hash="116f72fc1738318f5d7b26672a13ad96"/><file name="arrows-orange-bullet.gif" hash="fdc145d3895c04eb83fa8aa6c8f42d01"/><file name="arrows-orange-collapsed.gif" hash="df912cf9c86bcf6347192c14042f506e"/><file name="arrows-orange-expanded.gif" hash="b21cb063c6322546f6ffc88fc1fc6f1c"/><file name="plus-minus-bullet.gif" hash="b4b7b5d624885f79482c54cb8a3a08a1"/><file name="plus-minus-collapsed.gif" hash="2f82f3804044ea6b630b4df55cee430a"/><file name="plus-minus-expanded.gif" hash="db2ae2f7aa3fe83c7e364df57cc3bb7b"/></dir><file name="animals.js" hash="7857aa71a4a9872bc9ab3a55dd75ef18"/><file name="bootstrap-image-gallery.min.js" hash="8d0476e61ea2d0c7a42b9af420d764fe"/><file name="bootstrap.min.js" hash="266ba64fb1c21e3c743d0cce42f955f3"/><file name="canvas-to-blob.min.js" hash="f1b353d74742a0d0d8dba4a82f07c050"/><dir name="cors"><file name="jquery.postmessage-transport.js" hash="11fe256b13a09546f7280198d8e98239"/><file name="jquery.xdr-transport.js" hash="0927262e8bbd59ec33eda07237e6f19a"/></dir><file name="html5.js" hash="69431f1ec831bacf31013dff2872cba0"/><file name="jquery.fileupload-fp.js" hash="ccadbaf7dc309e09950eb4c06677d356"/><file name="jquery.fileupload-ui.js" hash="6cd54f58a3953ee8849d93b665b5ab51"/><file name="jquery.fileupload.js" hash="a3eeecf59ed91a98880370c8385c869f"/><file name="jquery.iframe-transport.js" hash="64c4919f8d8d06d25f1174f11d7a14e4"/><file name="jquery183.js" hash="b25b0460d7ddea993dad32005f56d255"/><file name="load-image.min.js" hash="6d3317f8c6fe137a18e720dc0a79a8d1"/><file name="main.js" hash="f1ecba9477cc6e3242d26f751ddcbe8c"/><file name="plants.js" hash="d27d443afe7ecf25ea46cf6f0ad33989"/><file name="tmpl.min.js" hash="411df7e2bc659d35015f7fdb7432b331"/><dir name="vendor"><file name="jquery.ui.widget.js" hash="acc1687c624523c960fb56c5c67f1442"/></dir><dir name="~experimental"><file name="Uize.Color.xSvgColorNames.js" hash="8b33ca3ea12f3cf75190831be0eee1fd"/><file name="Uize.Widget.Button-touch1.js" hash="5df5bd3d608820c6a8d21c0eaa0197ec"/><file name="Uize.Widget.Button-touch2.js" hash="c92d3b3ea2c90fe1bcff889ed425cbb5"/><file name="Uize.Widget.Button-touch3.js" hash="3b2fd34fd2a7fec5f43d997185197a8c"/><file name="Uize.Widget.ImagePort.AutoPan.js" hash="0ea22a5e725f6aa5de970e494bf63362"/><file name="Uize.Widget.Page.js" hash="04ed8eb10923f070924bfb6635b59c5b"/><file name="Uize.Widget.Pagination.js" hash="c998fabad59bb27c7413c05d45f3cd7c"/><file name="Uize.Widget.js" hash="dc74ca75b94c8ef7d48126f4b188c27a"/></dir></dir></dir><file name="favicon.ico" hash="88733ee53676a47fc354a61c32516e82"/></dir></dir></dir></target><target name="mageetc"><dir name="modules"><file name="Blog4mail_Customproduct.xml" hash="453fb0d6f4a3fd6394b708d2c08bafed"/></dir></target></contents>
23
+ <compatible/>
24
+ <dependencies><required><php><min>5.2.0</min><max>6.0.0</max></php><package><name></name><channel>connect.magentocommerce.com/core</channel><min></min><max></max></package><extension><name>imagick</name><min></min><max></max></extension><extension><name>gd</name><min></min><max></max></extension></required></dependencies>
25
+ </package>
skin/frontend/default/customproduct/css/oauth-simple.css ADDED
@@ -0,0 +1,239 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ /**
2
+ * Magento
3
+ *
4
+ * NOTICE OF LICENSE
5
+ *
6
+ * This source file is subject to the Academic Free License (AFL 3.0)
7
+ * that is bundled with this package in the file LICENSE_AFL.txt.
8
+ * It is also available through the world-wide-web at this URL:
9
+ * http://opensource.org/licenses/afl-3.0.php
10
+ * If you did not receive a copy of the license and are unable to
11
+ * obtain it through the world-wide-web, please send an email
12
+ * to license@magentocommerce.com so we can send you a copy immediately.
13
+ *
14
+ * DISCLAIMER
15
+ *
16
+ * Do not edit or add to this file if you wish to upgrade Magento to newer
17
+ * versions in the future. If you wish to customize Magento for your
18
+ * needs please refer to http://www.magentocommerce.com for more information.
19
+ *
20
+ * @category design
21
+ * @package default_default
22
+ * @copyright Copyright (c) 2012 Magento Inc. (http://www.magentocommerce.com)
23
+ * @license http://opensource.org/licenses/afl-3.0.php Academic Free License (AFL 3.0)
24
+ */
25
+
26
+ /* Reset ================================================================================= */
27
+ * { margin:0; padding:0; }
28
+ body { background:#496778 50% 0 repeat-y; font:12px/1.55 Arial, Helvetica, sans-serif; color:#2f2f2f; text-align:center; }
29
+ img { border:0; vertical-align:top; }
30
+ a { color:#1e7ec8; text-decoration:underline; }
31
+ a:hover { text-decoration:none; }
32
+ :focus { outline:0; }
33
+
34
+ /* Headings */
35
+ h1,h2,h3,
36
+ h4,h5,h6 { margin:0 0 5px; line-height:1.35; color:#0a263c; }
37
+ h1 { font-size:20px; font-weight:normal; }
38
+ h2 { font-size:18px; font-weight:normal; }
39
+ h3 { font-size:16px; font-weight:bold; }
40
+ h4 { font-size:14px; font-weight:bold; }
41
+ h5 { font-size:12px; font-weight:bold; }
42
+ h6 { font-size:11px; font-weight:bold; }
43
+
44
+ /* Forms */
45
+ form { display:inline; }
46
+ fieldset { border:0; }
47
+ legend { display:none; }
48
+
49
+ /* Table */
50
+ table { border:0; /*border-collapse:collapse;*/ border-spacing:0; empty-cells:show; font-size:100%; }
51
+ caption,th,td { vertical-align:top; text-align:left; font-weight:normal; }
52
+
53
+ /* Content */
54
+ p { margin:0 0 10px; }
55
+ strong { font-weight:bold; }
56
+ address { font-style:normal; line-height:1.35; }
57
+ cite { font-style:normal; }
58
+ q,
59
+ blockquote { quotes:none; }
60
+ q:before,
61
+ q:after { content:''; }
62
+ small,big { font-size:1em; }
63
+ /*sup { font-size:1em; vertical-align:top; }*/
64
+
65
+ /* Lists */
66
+ ul,ol { list-style:none; }
67
+
68
+ /* Tools */
69
+ .hidden { display:block !important; border:0 !important; margin:0 !important; padding:0 !important; font-size:0 !important; line-height:0 !important; width:0 !important; height:0 !important; overflow:hidden !important; }
70
+ .nobr { white-space:nowrap !important; }
71
+ .wrap { white-space:normal !important; }
72
+ .a-left { text-align:left !important; }
73
+ .a-center { text-align:center !important; }
74
+ .a-right { text-align:right !important; }
75
+ .v-top { vertical-align:top; }
76
+ .v-middle { vertical-align:middle; }
77
+ .f-left,
78
+ .left { float:left !important; }
79
+ .f-right,
80
+ .right { float:right !important; }
81
+ .f-none { float:none !important; }
82
+ .f-fix { float:left; width:100%; }
83
+ .no-display { display:none; }
84
+ .no-margin { margin:0 !important; }
85
+ .no-padding { padding:0 !important; }
86
+ .no-bg { background:none !important; }
87
+ /* ======================================================================================= */
88
+
89
+ /* Default styles ======================================================================== */
90
+ /* boxes.css*/
91
+ .notification-global {
92
+ background: url("./../images/error_msg_icon.gif") no-repeat scroll 27px 5px #FFF9E9;
93
+ border-bottom: 1px solid #EEE2BE;
94
+ border-top: 1px solid #EEE2BE;
95
+ color: #444444;
96
+ font-size: 11px;
97
+ line-height: 16px;
98
+ margin: 0 0 -3px;
99
+ padding: 5px 27px 5px 47px;
100
+ position: relative;
101
+ }
102
+ .notification-global-notice {
103
+ background-image: url("./../images/note_msg_icon.gif");
104
+ }
105
+ .notification-global .label {
106
+ color: #EB5E00;
107
+ }
108
+ .notification-global .clickable {
109
+ cursor: pointer;
110
+ }
111
+ .notification-global span.critical {
112
+ color: #D20000;
113
+ }
114
+ .notification-global a:hover {
115
+ text-decoration: none;
116
+ }
117
+ .error, a.error span, .required, .validation-advice {
118
+ color: #D40707 !important;
119
+ font-weight: bold !important;
120
+ }
121
+ .notice {
122
+ color: #EA7601;
123
+ }
124
+ .messages ul {
125
+ border: 0 none !important;
126
+ }
127
+ .messages li {
128
+ font-size: 0.95em !important;
129
+ font-weight: bold !important;
130
+ margin-bottom: 11px !important;
131
+ min-height: 23px !important;
132
+ padding: 8px 8px 2px 32px !important;
133
+ }
134
+ .messages ul li {
135
+ border: 0 none !important;
136
+ margin: 0 0 3px !important;
137
+ padding: 0 !important;
138
+ }
139
+ .error-msg {
140
+ background: url("./../images/error_msg_icon.gif") no-repeat scroll 10px 10px #FAEBE7 !important;
141
+ border: 1px solid #F16048 !important;
142
+ color: #DF280A !important;
143
+ }
144
+ .success-msg {
145
+ background: url("./../images/success_msg_icon.gif") no-repeat scroll 10px 10px #EFF5EA !important;
146
+ border: 1px solid #95A486 !important;
147
+ color: #3D6611 !important;
148
+ }
149
+ .notice-msg {
150
+ background: url("./../images/note_msg_icon.gif") no-repeat scroll 10px 10px #FFFBF0 !important;
151
+ border: 1px solid #FFD967 !important;
152
+ color: #3D6611 !important;
153
+ }
154
+ .warning-msg {
155
+ background: url("./../images/warning_msg_icon.gif") no-repeat scroll 10px 10px #E6E6E6 !important;
156
+ border: 1px solid #666E73 !important;
157
+ color: #000000 !important;
158
+ }
159
+
160
+ button:hover, .form-button:hover {
161
+ background: #F77C16;
162
+ }
163
+ button:active, .form-button:active {
164
+ background: #F77C16;
165
+ }
166
+ button span {
167
+ background-position: 0 50%;
168
+ background-repeat: no-repeat;
169
+ line-height: 1.35em;
170
+ }
171
+ button span span {
172
+ background: none repeat scroll 0 0 transparent !important;
173
+ display: inline !important;
174
+ margin: 0 !important;
175
+ padding: 0 !important;
176
+ }
177
+
178
+
179
+ input.input-text, textarea, select {
180
+ background: none repeat scroll 0 0 #FFFFFF;
181
+ border-color: #AAAAAA #C8C8C8 #C8C8C8 #AAAAAA;
182
+ border-style: solid;
183
+ border-width: 1px;
184
+ font: 12px arial,helvetica,sans-serif;
185
+ }
186
+ input.input-text, textarea {
187
+ padding: 2px;
188
+ }
189
+ button, .form-button {
190
+ background: #FFAC47;
191
+ border-color: #ED6502 #A04300 #A04300 #ED6502;
192
+ border-style: solid;
193
+ border-width: 1px;
194
+ color: #FFFFFF;
195
+ cursor: pointer;
196
+ font: bold 12px arial,helvetica,sans-serif;
197
+ padding: 0 7px 1px;
198
+ text-align: center !important;
199
+ white-space: nowrap;
200
+ }
201
+ /* ======================================================================================= */
202
+
203
+
204
+ *, html {text-align: left;}
205
+
206
+ h1 {
207
+ color: #D12C01;
208
+ font-size: 22px;
209
+ font-weight: normal;
210
+ margin: 0;
211
+ text-align: left;
212
+ }
213
+
214
+ h2 {
215
+ color: #444444;
216
+ font: 16px Arial,Helvetica,sans-serif;
217
+ margin: 0 0 5px;
218
+ text-align: left;
219
+ }
220
+
221
+ body,
222
+ .main-container,
223
+ .header-container {background: none;}
224
+
225
+ .header-simple {height: 60px; text-align: left; padding: 10px 10px 0 10px; border-bottom: 1px solid #CFCFCF;}
226
+ .header-top img {height: 60px;}
227
+
228
+ .login-box > div {padding: 10px;}
229
+ .page-title {margin-bottom: 0; border-bottom: 1px solid #CFCFCF;}
230
+
231
+ .form-box {border-bottom: 1px solid #CFCFCF;}
232
+ .form-box .fieldset, .form-box fieldset {width: 320px; margin: 0 auto;}
233
+
234
+ .input-box {margin-bottom: 10px;}
235
+ .input-box label {width: 95px; font-weight: bold; display: block; float: left; text-align: right; padding-right: 10px;}
236
+ .input-box input {width: 209px;}
237
+
238
+ .required {font-weight: normal; color: #D40707 !important; font-size: 11px;}
239
+ .form-buttons {text-align: right;}
skin/frontend/default/customproduct/css/print.css ADDED
@@ -0,0 +1,40 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ /**
2
+ * Magento
3
+ *
4
+ * NOTICE OF LICENSE
5
+ *
6
+ * This source file is subject to the Academic Free License (AFL 3.0)
7
+ * that is bundled with this package in the file LICENSE_AFL.txt.
8
+ * It is also available through the world-wide-web at this URL:
9
+ * http://opensource.org/licenses/afl-3.0.php
10
+ * If you did not receive a copy of the license and are unable to
11
+ * obtain it through the world-wide-web, please send an email
12
+ * to license@magentocommerce.com so we can send you a copy immediately.
13
+ *
14
+ * DISCLAIMER
15
+ *
16
+ * Do not edit or add to this file if you wish to upgrade Magento to newer
17
+ * versions in the future. If you wish to customize Magento for your
18
+ * needs please refer to http://www.magentocommerce.com for more information.
19
+ *
20
+ * @category design
21
+ * @package default_default
22
+ * @copyright Copyright (c) 2012 Magento Inc. (http://www.magentocommerce.com)
23
+ * @license http://opensource.org/licenses/afl-3.0.php Academic Free License (AFL 3.0)
24
+ */
25
+ * { background:none !important; text-align:left !important; }
26
+ html { margin:0 !important; padding:0 !important; }
27
+ body { background:#fff !important; font-size:9pt !important; padding:0 !important; margin:10px !important; }
28
+ a { color:#2976c9 !important; }
29
+ th,td { color:#2f2f2f !important; border-color:#ccc !important; }
30
+
31
+ .header-container,
32
+ .nav-container,
33
+ .footer-container,
34
+ .pager,
35
+ .toolbar,
36
+ .actions,
37
+ .buttons-set { display:none !important; }
38
+
39
+ .page-print .data-table .cart-tax-total { background-position:100% -54px; }
40
+ .page-print .data-table .cart-tax-info { display:block !important; }
skin/frontend/default/customproduct/css/styles-ie.css ADDED
@@ -0,0 +1,149 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ /**
2
+ * Magento
3
+ *
4
+ * NOTICE OF LICENSE
5
+ *
6
+ * This source file is subject to the Academic Free License (AFL 3.0)
7
+ * that is bundled with this package in the file LICENSE_AFL.txt.
8
+ * It is also available through the world-wide-web at this URL:
9
+ * http://opensource.org/licenses/afl-3.0.php
10
+ * If you did not receive a copy of the license and are unable to
11
+ * obtain it through the world-wide-web, please send an email
12
+ * to license@magentocommerce.com so we can send you a copy immediately.
13
+ *
14
+ * DISCLAIMER
15
+ *
16
+ * Do not edit or add to this file if you wish to upgrade Magento to newer
17
+ * versions in the future. If you wish to customize Magento for your
18
+ * needs please refer to http://www.magentocommerce.com for more information.
19
+ *
20
+ * @category design
21
+ * @package default_default
22
+ * @copyright Copyright (c) 2012 Magento Inc. (http://www.magentocommerce.com)
23
+ * @license http://opensource.org/licenses/afl-3.0.php Academic Free License (AFL 3.0)
24
+ */
25
+
26
+ /* IE 6 only */
27
+ * html .validation-advice { height:13px; }
28
+ * html .error-msg,
29
+ * html .success-msg,
30
+ * html .note-msg,
31
+ * html .notice-msg { height:24px; }
32
+ * html .main { height:400px; }
33
+ * html .account-login .content { height:240px; }
34
+ .block li.item,
35
+ .block-poll li,
36
+ .opc li.section { vertical-align:top; }
37
+ * html .window-overlay { background:#ccc; filter:alpha(opacity=50); }
38
+
39
+ /* Doubled Margin Fixes */
40
+ .product-view .product-img-box .more-views li,
41
+ .product-view .box-tags .form-add .input-box,
42
+ .sp-methods select.month { display:inline; }
43
+
44
+ /********** < Navigation styles */
45
+ #nav li,
46
+ #nav li a { zoom:1; }
47
+ #nav li { vertical-align:top; }
48
+ /********** < Navigation styles */
49
+
50
+ select { margin-bottom:1px; }
51
+ input.radio { width:13px; height:13px; }
52
+ input.checkbox { width:13px; height:13px; }
53
+ button.button { height:21px; }
54
+ button.button span { position:relative; }
55
+ button.btn-checkout { height:40px; }
56
+ #opc-review .sp-methods .input-box { float:left; }
57
+ .form-list label { position:relative; z-index:0; }
58
+ .form-list label.required em { position:absolute; top:0; right:-8px; }
59
+
60
+ table { scrollbar-face-color:expression(runtimeStyle.scrollbarFaceColor = '#fff', cellSpacing = 0); }
61
+
62
+ .product-view .product-img-box .zoom.disabled { filter:alpha(opacity=30); }
63
+
64
+ .gift-messages-form { position:relative; zoom:1; }
65
+
66
+ .tool-tip .btn-close a { margin:0; }
67
+
68
+ .product-view .box-tags .product-tags li,
69
+ .footer li { padding:0 4px 0 7px; }
70
+
71
+ .product-options dd .time-picker select { margin:0; padding:0; }
72
+
73
+ /* Clearer */
74
+ .clearer { display:block; clear:both; font-size:0; line-height:0; height:0; overflow:hidden; }
75
+
76
+ /* Clears and hasLayout fixes */
77
+ .header-container,
78
+ .header-container .top-container,
79
+ .header,
80
+ .header .quick-access,
81
+ #nav,
82
+ .main,
83
+ .footer,
84
+ .footer-container .bottom-container,
85
+ .col-main,
86
+ .col2-set,
87
+ .col3-set,
88
+ .col3-layout .product-options-bottom .price-box,
89
+ .col4-set,
90
+ .messages li,
91
+ .search-autocomplete li,
92
+ .block,
93
+ .block .block-content,
94
+ .block .actions,
95
+ .block li.item,
96
+ .block-poll li,
97
+ .block-poll .label,
98
+ .block-layered-nav .currently li,
99
+ .block-account .block-content li a,
100
+ .mini-products-list .product-details,
101
+ .page-title,
102
+ .rss-title h1,
103
+ .products-grid,
104
+ .products-list li.item,
105
+ .box-account .box-head,
106
+ .dashboard .box .box-title,
107
+ .box-reviews li.item,
108
+ .box-tags li.item,
109
+ .pager,
110
+ .sorter,
111
+ .ratings,
112
+ .add-to-box,
113
+ .add-to-cart,
114
+ .product-essential,
115
+ .product-collateral,
116
+ .product-view .product-img-box .more-views ul,
117
+ .product-view .box-tags .form-add,
118
+ .product-view .product-shop .short-description,
119
+ .product-view .box-description,
120
+ .product-options .options-list li,
121
+ .product-options,
122
+ .product-options-bottom,
123
+ .truncated,
124
+ .truncated .truncated_full_value,
125
+ .product-review,
126
+ .cart,
127
+ .cart-collaterals,
128
+ .cart .crosssell li.item,
129
+ .cart .discount,
130
+ .opc .step-title,
131
+ .opc .step,
132
+ .multiple-checkout,
133
+ .sp-methods,
134
+ .checkout-progress,
135
+ .multiple-checkout .place-order,
136
+ .form-list li,
137
+ .form-list .field,
138
+ .group-select li,
139
+ .buttons-set,
140
+ .page-print .print-head,
141
+ .cart-tax-total,
142
+ .advanced-search-summary,
143
+ .advanced-search-summary p,
144
+ .gift-messages-form .item,
145
+ .send-friend .form-list li p,
146
+ .centinel .authentication { zoom:1; }
147
+
148
+ /* Hover Fix */
149
+ iframe.hover-fix { position:absolute; left:-1px; top:-1px; z-index:-1; background:transparent; filter:progid:DXImageTransform.Microsoft.Alpha(style=0,opacity=0); }
skin/frontend/default/customproduct/css/styles.css ADDED
@@ -0,0 +1,1788 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ /**
2
+ * Magento
3
+ *
4
+ * NOTICE OF LICENSE
5
+ *
6
+ * This source file is subject to the Academic Free License (AFL 3.0)
7
+ * that is bundled with this package in the file LICENSE_AFL.txt.
8
+ * It is also available through the world-wide-web at this URL:
9
+ * http://opensource.org/licenses/afl-3.0.php
10
+ * If you did not receive a copy of the license and are unable to
11
+ * obtain it through the world-wide-web, please send an email
12
+ * to license@magentocommerce.com so we can send you a copy immediately.
13
+ *
14
+ * DISCLAIMER
15
+ *
16
+ * Do not edit or add to this file if you wish to upgrade Magento to newer
17
+ * versions in the future. If you wish to customize Magento for your
18
+ * needs please refer to http://www.magentocommerce.com for more information.
19
+ *
20
+ * @category design
21
+ * @package default_default
22
+ * @copyright Copyright (c) 2012 Magento Inc. (http://www.magentocommerce.com)
23
+ * @license http://opensource.org/licenses/afl-3.0.php Academic Free License (AFL 3.0)
24
+ */
25
+
26
+ /* Reset ================================================================================= */
27
+ * { margin:0; padding:0; }
28
+
29
+ body { background:#496778 url(../images/bkg_body.gif) 50% 0 repeat-y; font:12px/1.55 Arial, Helvetica, sans-serif; color:#2f2f2f; text-align:center; }
30
+
31
+ img { border:0; vertical-align:top; }
32
+
33
+ a { color:#1e7ec8; text-decoration:underline; }
34
+ a:hover { text-decoration:none; }
35
+ :focus { outline:0; }
36
+
37
+ /* Headings */
38
+ h1,h2,h3,
39
+ h4,h5,h6 { margin:0 0 5px; line-height:1.35; color:#0a263c; }
40
+ h1 { font-size:20px; font-weight:normal; }
41
+ h2 { font-size:18px; font-weight:normal; }
42
+ h3 { font-size:16px; font-weight:bold; }
43
+ h4 { font-size:14px; font-weight:bold; }
44
+ h5 { font-size:12px; font-weight:bold; }
45
+ h6 { font-size:11px; font-weight:bold; }
46
+
47
+ /* Forms */
48
+ form { display:inline; }
49
+ fieldset { border:0; }
50
+ legend { display:none; }
51
+
52
+ /* Table */
53
+ table { border:0; /*border-collapse:collapse;*/ border-spacing:0; empty-cells:show; font-size:100%; }
54
+ caption,th,td { vertical-align:top; text-align:left; font-weight:normal; }
55
+
56
+ /* Content */
57
+ p { margin:0 0 10px; }
58
+ strong { font-weight:bold; }
59
+ address { font-style:normal; line-height:1.35; }
60
+ cite { font-style:normal; }
61
+ q,
62
+ blockquote { quotes:none; }
63
+ q:before,
64
+ q:after { content:''; }
65
+ small,big { font-size:1em; }
66
+ /*sup { font-size:1em; vertical-align:top; }*/
67
+
68
+ /* Lists */
69
+ ul,ol { list-style:none; }
70
+
71
+ /* Tools */
72
+ .hidden { display:block !important; border:0 !important; margin:0 !important; padding:0 !important; font-size:0 !important; line-height:0 !important; width:0 !important; height:0 !important; overflow:hidden !important; }
73
+ .nobr { white-space:nowrap !important; }
74
+ .wrap { white-space:normal !important; }
75
+ .a-left { text-align:left !important; }
76
+ .a-center { text-align:center !important; }
77
+ .a-right { text-align:right !important; }
78
+ .v-top { vertical-align:top; }
79
+ .v-middle { vertical-align:middle; }
80
+ .f-left,
81
+ .left { float:left !important; }
82
+ .f-right,
83
+ .right { float:right !important; }
84
+ .f-none { float:none !important; }
85
+ .f-fix { float:left; width:100%; }
86
+ .no-display { display:none; }
87
+ .no-margin { margin:0 !important; }
88
+ .no-padding { padding:0 !important; }
89
+ .no-bg { background:none !important; }
90
+ /* ======================================================================================= */
91
+
92
+
93
+ /* Layout ================================================================================ */
94
+ .wrapper { min-width:954px; }
95
+ .page {}
96
+ .page-print { background:#fff; padding:25px 30px; text-align:left; }
97
+ .page-empty { background:#fff; padding:20px; text-align:left; }
98
+ .page-popup { background:#fff; padding:25px 30px; text-align:left; }
99
+ .main-container { background:#fbfaf6 url(../images/bkg_main1.gif) 50% 0 no-repeat; }
100
+ .main { width:900px; margin:0 auto; min-height:400px; padding:25px 25px 80px; background:#fffffe url(../images/bkg_main2.gif) 0 0 no-repeat; text-align:left; }
101
+
102
+ /* Base Columns */
103
+ .col-left { float:left; width:195px; padding:0 0 1px; }
104
+ .col-main { float:left; width:685px; padding:0 0 1px; }
105
+ .col-right { float:right; width:195px; padding:0 0 1px; }
106
+
107
+ /* 1 Column Layout */
108
+ .col1-layout .col-main { float:none; width:auto; }
109
+
110
+ /* 2 Columns Layout */
111
+ .col2-left-layout .col-main { float:right; }
112
+ .col2-right-layout .col-main {}
113
+
114
+ /* 3 Columns Layout */
115
+ .col3-layout .col-main { width:475px; margin-left:17px; }
116
+ .col3-layout .col-wrapper { float:left; width:687px; }
117
+ .col3-layout .col-wrapper .col-main { float:right; }
118
+
119
+ /* Content Columns */
120
+ .col2-set .col-1 { float:left; width:48.5%; }
121
+ .col2-set .col-2 { float:right; width:48.5%; }
122
+ .col2-set .col-narrow { width:32%; }
123
+ .col2-set .col-wide { width:65%; }
124
+
125
+ .col3-set .col-1 { float:left; width:32%; }
126
+ .col3-set .col-2 { float:left; width:32%; margin-left:2%; }
127
+ .col3-set .col-3 { float:right; width:32%; }
128
+
129
+ .col4-set .col-1 { float:left; width:23.5%; }
130
+ .col4-set .col-2 { float:left; width:23.5%; margin:0 2%; }
131
+ .col4-set .col-3 { float:left; width:23.5%; }
132
+ .col4-set .col-4 { float:right; width:23.5%; }
133
+ /* ======================================================================================= */
134
+
135
+
136
+ /* Global Styles ========================================================================= */
137
+ /* Form Elements */
138
+ input,select,textarea,button { font:12px/15px Arial, Helvetica, sans-serif; vertical-align:middle; color:#2f2f2f; }
139
+ input.input-text,select,textarea { background:#fff; border:1px solid #b6b6b6; }
140
+ input.input-text,textarea { padding:2px; }
141
+ select { padding:1px; }
142
+ select option { padding-right:10px; }
143
+ select.multiselect option { border-bottom:1px solid #b6b6b6; padding:2px 5px; }
144
+ select.multiselect option:last-child { border-bottom:0; }
145
+ textarea { overflow:auto; }
146
+ input.radio { margin-right:3px; }
147
+ input.checkbox { margin-right:3px; }
148
+ input.qty { width:2.5em !important; }
149
+ button.button::-moz-focus-inner { padding:0; border:0; } /* FF Fix */
150
+ button.button { -webkit-border-fit:lines; } /* <- Safari & Google Chrome Fix */
151
+ button.button { overflow:visible; width:auto; border:0; padding:0; margin:0; background:transparent; cursor:pointer; }
152
+ button.button span { display:block; height:19px; border:1px solid #de5400; background:#f18200; padding:0 8px; font:bold 12px/19px Arial, Helvetica, sans-serif; text-align:center; white-space:nowrap; color:#fff; }
153
+ button.button span span { border:0; padding:0; }
154
+ button.disabled span { border-color:#bbb !important; background:#bbb !important; }
155
+
156
+ button.btn-checkout span { height:40px; border:0; background:url(../images/btn_checkout.gif) 0 0 no-repeat; padding:0 0 0 9px; font:bold 15px/40px Arial, Helvetica, sans-serif; color:#fff; }
157
+ button.btn-checkout span span { background-position:100% 0; padding:0 25px 0 16px; }
158
+ button.btn-checkout.no-checkout span { background-position:0 100%; color:#b8baba; }
159
+ button.btn-checkout.no-checkout span span { background-position:100% 100%; }
160
+
161
+ p.control input.checkbox,
162
+ p.control input.radio { margin-right:6px; }
163
+ /* Form Highlight */
164
+ input.input-text:focus,select:focus,textarea:focus { background-color:#edf7fd; }
165
+ /*.highlight { background:#efefef; }*/
166
+
167
+ /* Form lists */
168
+ /* Grouped fields */
169
+ /*.form-list { width:535px; margin:0 auto; overflow:hidden; }*/
170
+ .form-list li { margin:0 0 8px; }
171
+ .form-list label { float:left; color:#666; font-weight:bold; position:relative; z-index:0; }
172
+ .form-list label.required {}
173
+ .form-list label.required em { float:right; font-style:normal; color:#eb340a; position:absolute; top:0; right:-8px; }
174
+ .form-list li.control label { float:none; }
175
+ .form-list li.control input.radio,
176
+ .form-list li.control input.checkbox { margin-right:6px; }
177
+ .form-list li.control .input-box { clear:none; display:inline; width:auto; }
178
+ /*.form-list li.fields { margin-right:-15px; }*/
179
+ .form-list .input-box { display:block; clear:both; width:260px; }
180
+ .form-list .field { float:left; width:275px; }
181
+ .form-list input.input-text { width:254px; }
182
+ .form-list textarea { width:254px; height:10em; }
183
+ .form-list select { width:260px; }
184
+ .form-list li.wide .input-box { width:535px; }
185
+ .form-list li.wide input.input-text { width:529px; }
186
+ .form-list li.wide textarea { width:529px; }
187
+ .form-list li.wide select { width:535px; }
188
+ .form-list li.additional-row { border-top:1px solid #ccc; margin-top:10px; padding-top:7px; }
189
+ .form-list li.additional-row .btn-remove { float:right; margin:5px 0 0; }
190
+ .form-list .input-range input.input-text { width:74px; }
191
+
192
+ .form-list-narrow li { margin-bottom:0; }
193
+ .form-list-narrow li .input-box { margin-bottom:6px; }
194
+ .form-list-narrow li.wide .input-box { width:260px; }
195
+ .form-list-narrow li.wide input.input-text,
196
+ .form-list-narrow li.wide textarea { width:254px }
197
+ .form-list-narrow li.wide select { width:260px; }
198
+
199
+ /* Customer */
200
+ .form-list .customer-name-prefix .input-box,
201
+ .form-list .customer-name-suffix .input-box,
202
+ .form-list .customer-name-prefix-suffix .input-box,
203
+ .form-list .customer-name-prefix-middlename .input-box,
204
+ .form-list .customer-name-middlename-suffix .input-box,
205
+ .form-list .customer-name-prefix-middlename-suffix .input-box { width:auto; }
206
+
207
+ .form-list .name-prefix { width:65px; }
208
+ .form-list .name-prefix select { width:55px; }
209
+ .form-list .name-prefix input.input-text { width:49px; }
210
+
211
+ .form-list .name-suffix { width:65px; }
212
+ .form-list .name-suffix select { width:55px; }
213
+ .form-list .name-suffix input.input-text { width:49px; }
214
+
215
+ .form-list .name-middlename { width:70px; }
216
+ .form-list .name-middlename input.input-text { width:49px; }
217
+
218
+ .form-list .customer-name-prefix-middlename-suffix .name-firstname,
219
+ .form-list .customer-name-prefix-middlename .name-firstname { width:140px; }
220
+ .form-list .customer-name-prefix-middlename-suffix .name-firstname input.input-text,
221
+ .form-list .customer-name-prefix-middlename .name-firstname input.input-text { width:124px; }
222
+ .form-list .customer-name-prefix-middlename-suffix .name-lastname { width:205px; }
223
+ .form-list .customer-name-prefix-middlename-suffix .name-lastname input.input-text { width:189px; }
224
+
225
+ .form-list .customer-name-prefix-suffix .name-firstname { width:210px; }
226
+ .form-list .customer-name-prefix-suffix .name-lastname { width:205px; }
227
+ .form-list .customer-name-prefix-suffix .name-firstname input.input-text,
228
+ .form-list .customer-name-prefix-suffix .name-lastname input.input-text { width:189px; }
229
+
230
+ .form-list .customer-name-prefix-suffix .name-firstname { width:210px; }
231
+ .form-list .customer-name-prefix-suffix .name-lastname { width:205px; }
232
+ .form-list .customer-name-prefix-suffix .name-firstname input.input-text,
233
+ .form-list .customer-name-prefix-suffix .name-lastname input.input-text { width:189px; }
234
+
235
+ .form-list .customer-name-prefix .name-firstname,
236
+ .form-list .customer-name-middlename .name-firstname { width:210px; }
237
+
238
+ .form-list .customer-name-suffix .name-lastname,
239
+ .form-list .customer-name-middlename .name-firstname,
240
+ .form-list .customer-name-middlename-suffix .name-firstname,
241
+ .form-list .customer-name-middlename-suffix .name-lastname { width:205px; }
242
+
243
+ .form-list .customer-name-prefix .name-firstname input.input-text,
244
+ .form-list .customer-name-suffix .name-lastname input.input-text,
245
+ .form-list .customer-name-middlename .name-firstname input.input-text,
246
+ .form-list .customer-name-middlename-suffix .name-firstname input.input-text,
247
+ .form-list .customer-name-middlename-suffix .name-lastname input.input-text { width:189px; }
248
+
249
+ .form-list .customer-dob .dob-month,
250
+ .form-list .customer-dob .dob-day,
251
+ .form-list .customer-dob .dob-year { float:left; width:85px; }
252
+ .form-list .customer-dob input.input-text { display:block; width:74px; }
253
+ .form-list .customer-dob label { font-size:10px; font-weight:normal; color:#888; }
254
+ .form-list .customer-dob .dob-day,
255
+ .form-list .customer-dob .dob-month { width:60px; }
256
+ .form-list .customer-dob .dob-day input.input-text,
257
+ .form-list .customer-dob .dob-month input.input-text { width:46px; }
258
+ .form-list .customer-dob .dob-year { width:140px; }
259
+ .form-list .customer-dob .dob-year input.input-text { width:134px; }
260
+
261
+ /* Independent fields */
262
+ /*.form-list li { margin:0 0 8px; }
263
+ .form-list li.fields { margin:0; }
264
+ .form-list .field { display:block; margin:0 0 8px; }
265
+ .form-list li.control {}
266
+ .form-list label { float:left; width:150px; padding:2px 10px 0 0; text-align:right; }
267
+ .form-list label.required { font-weight:bold; }
268
+ .form-list label.required em { font-variant:normal; color:#eb340a; margin-right:3px; }
269
+ .form-list .input-box { float:left; width:260px; }
270
+ .form-list input.input-text,
271
+ .form-list textarea { width:254px; }
272
+ .form-list select { width:260px; }
273
+ .form-list li.additional-row { border-top:1px solid #ddd; margin-top:10px; }
274
+ .form-list li.additional-row .btn-remove { float:right; margin:5px 5px 0 0; }
275
+ .form-list .input-range input.input-text { width:96px; }*/
276
+ /* Customer */
277
+ /*.form-list .customer-dob .dob-month,
278
+ .form-list .customer-dob .dob-day,
279
+ .form-list .customer-dob .dob-year { float:left; width:85px; }
280
+ .form-list .customer-dob input.input-text { display:block; width:74px; }
281
+ .form-list .customer-dob label { font-size:11px; font-weight:normal; color:#777; text-align:left; }
282
+ .form-list .customer-dob .dob-day,
283
+ .form-list .customer-dob .dob-month { width:60px; }
284
+ .form-list .customer-dob .dob-day input.input-text,
285
+ .form-list .customer-dob .dob-month input.input-text { width:46px; }
286
+ .form-list .customer-dob .dob-year { width:140px; }
287
+ .form-list .customer-dob .dob-year input.input-text { width:134px; }*/
288
+
289
+ .buttons-set { clear:both; margin:4em 0 0; padding:8px 0 0; border-top:1px solid #e4e4e4; text-align:right; }
290
+ .buttons-set p.required { margin:0 0 10px; }
291
+ .buttons-set .back-link { float:left; margin:0; }
292
+ .buttons-set button.button { float:right; margin-left:5px; }
293
+
294
+ .buttons-set-order { margin:10px 0 0; }
295
+ .buttons-set-order .please-wait { padding:12px 7px 0 0; }
296
+
297
+ .fieldset { border:1px solid #bbafa0; background:#fbfaf6; padding:22px 25px 12px 33px; margin:28px 0; }
298
+ .fieldset .legend { float:left; font-weight:bold; font-size:13px; border:1px solid #f19900; background:#f9f3e3; color:#e76200; margin:-33px 0 0 -10px; padding:0 8px; position:relative; }
299
+
300
+ /* Form Validation */
301
+ .validation-advice { clear:both; min-height:13px; margin:3px 0 0; padding-left:17px; font-size:11px; font-weight:bold; line-height:13px; background:url(../images/validation_advice_bg.gif) 2px 0 no-repeat; color:#eb340a; }
302
+ .validation-failed { border:1px dashed #eb340a !important; background:#faebe7 !important; }
303
+ .validation-passed {}
304
+ p.required { font-size:11px; text-align:right; color:#EB340A; }
305
+ /* Expiration date and CVV number validation fix */
306
+ .v-fix { float:left; }
307
+ .v-fix .validation-advice { display:block; width:12em; margin-right:-12em; position:relative; }
308
+
309
+ /* Global Messages */
310
+ .success { color:#3d6611; font-weight:bold; }
311
+ .error { color:#df280a; font-weight:bold; }
312
+ .notice { color:#e26703; }
313
+
314
+ .messages,
315
+ .messages ul { list-style:none !important; margin:0 !important; padding:0 !important; }
316
+ .messages { width:100%; overflow:hidden; }
317
+ .messages li { margin:0 0 10px !important; }
318
+ .messages li li { margin:0 0 3px !important; }
319
+ .error-msg,
320
+ .success-msg,
321
+ .note-msg,
322
+ .notice-msg { border-style:solid !important; border-width:1px !important; background-position:10px 9px !important; background-repeat:no-repeat !important; min-height:24px !important; padding:8px 8px 8px 32px !important; font-size:11px !important; font-weight:bold !important; }
323
+ .error-msg { border-color:#f16048; background-color:#faebe7; background-image:url(../images/i_msg-error.gif); color:#df280a; }
324
+ .success-msg { border-color:#446423; background-color:#eff5ea; background-image:url(../images/i_msg-success.gif); color:#3d6611; }
325
+ .note-msg,
326
+ .notice-msg { border-color:#fcd344; background-color:#fafaec; background-image:url(../images/i_msg-note.gif); color:#3d6611; }
327
+
328
+ /* BreadCrumbs */
329
+ .breadcrumbs { font-size:11px; line-height:1.25; margin:0 0 13px; }
330
+ .breadcrumbs li { display:inline; }
331
+ .breadcrumbs li strong { font-weight:bold; }
332
+
333
+ /* Page Heading */
334
+ .page-title { width:100%; overflow:hidden; border-bottom:1px solid #ccc; margin:0 0 25px; }
335
+ .page-title h1,
336
+ .page-title h2 { margin:0; font-size:20px; color:#0a263c; }
337
+ .page-title .separator { margin:0 3px; }
338
+ .page-title .link-rss { float:right; margin:7px 0 0; }
339
+ .title-buttons { text-align:right; }
340
+ .title-buttons h1,
341
+ .title-buttons h2,
342
+ .title-buttons h3,
343
+ .title-buttons h4,
344
+ .title-buttons h5,
345
+ .title-buttons h6 { float:left; }
346
+
347
+ .subtitle,
348
+ .sub-title { clear:both; padding:15px 0 0; font-size:15px; font-weight:bold; margin:0 0 6px; color:#e25203; }
349
+
350
+ /* Pager */
351
+ .pager { font-size:11px; background:#fff url(../images/bkg_toolbar.gif) 0 100% repeat-x; padding:4px 8px; border-top:1px solid #e2e2e2; text-align:center; }
352
+ .pager .amount { float:left; margin:0; }
353
+ .pager .limiter { float:right; }
354
+ .pager .limiter label { vertical-align:middle; }
355
+ .pager .limiter select { padding:0; margin:0 0 1px; vertical-align:middle; }
356
+ .pager .pages { margin:0 140px; }
357
+ .pager .pages ol { display:inline; }
358
+ .pager .pages li { display:inline; margin:0 2px; }
359
+ .pager .pages .current {}
360
+
361
+ /* Sorter */
362
+ .sorter { font-size:11px; background:#fff url(../images/bkg_toolbar.gif) 0 100% repeat-x; padding:3px 8px; border-top:1px solid #e2e2e2; }
363
+ .sorter .view-mode { float:left; margin:0; }
364
+ .sorter .sort-by { float:right; padding-right:36px; }
365
+ .sorter .sort-by label { vertical-align:middle; }
366
+ .sorter .sort-by select { padding:0; margin:0 0 1px; vertical-align:middle; }
367
+ .sorter .link-feed {}
368
+
369
+ /* Toolbar */
370
+ .toolbar {}
371
+ .toolbar .pager { padding:3px 8px; border-bottom:1px solid #fff; }
372
+ .toolbar .sorter { border-bottom:1px solid #fff; }
373
+ .toolbar-bottom {}
374
+
375
+ /* Data Table */
376
+ .data-table { width:100%; border:1px solid #bebcb7; }
377
+ .data-table .odd { background:#f8f7f5 }
378
+ .data-table .even { background:#eeeded; }
379
+ /*.data-table tr.odd:hover,
380
+ .data-table tr.even:hover { background:#ebf1f6; }*/
381
+ .data-table td.last,
382
+ .data-table th.last { border-right:0; }
383
+ .data-table tr.last th,
384
+ .data-table tr.last td { border-bottom:0 !important; }
385
+ .data-table th { padding:3px 8px; font-weight:bold; }
386
+ .data-table td { padding:3px 8px; }
387
+
388
+ .data-table thead th { font-weight:bold; border-right:1px solid #c2d3e0; padding:2px 8px; color:#0a263c; white-space:nowrap; vertical-align:middle; }
389
+ .data-table thead th.wrap { white-space:normal; }
390
+ .data-table thead th a,
391
+ .data-table thead th a:hover { color:#fff; }
392
+ .data-table thead th { background:url(../images/bkg_th.gif) repeat-x 0 100% #d9e5ee; }
393
+ .data-table thead th .tax-flag { font-size:11px; white-space:nowrap; }
394
+
395
+ .data-table tfoot { border-bottom:1px solid #d9dde3; }
396
+ .data-table tfoot tr.first td { background:url(../images/bkg_tfoot.gif) 0 0 repeat-x; }
397
+ .data-table tfoot tr { background-color:#dee5e8 !important; }
398
+ .data-table tfoot td { padding-top:1px; padding-bottom:1px; border-bottom:0; border-right:1px solid #d9dde3; }
399
+ .data-table tfoot strong { font-size:16px; }
400
+
401
+ .data-table tbody th,
402
+ .data-table tbody td { border-bottom:1px solid #d9dde3; border-right:1px solid #d9dde3; }
403
+ /* Bundle products tables */
404
+ .data-table tbody.odd tr { background:#f8f7f5 !important; }
405
+ .data-table tbody.even tr { background:#f6f6f6 !important; }
406
+ .data-table tbody.odd tr td,
407
+ .data-table tbody.even tr td { border-bottom:0; }
408
+ .data-table tbody.odd tr.border td,
409
+ .data-table tbody.even tr.border td { border-bottom:1px solid #d9dde3; }
410
+
411
+ .data-table tbody td .option-label { font-weight:bold; font-style:italic; }
412
+ .data-table tbody td .option-value { padding-left:10px; }
413
+
414
+ /* Generic Info Box */
415
+ .info-box { background:#fff url(../images/bkg_block-title.gif) 0 0 repeat-x; border:1px solid #d0cbc1; padding:12px 15px; margin:0 0 15px; }
416
+ .info-box h2 { font-weight:bold; font-size:13px; }
417
+
418
+ .info-table th { font-weight:bold; padding:2px 15px 2px 0; }
419
+ .info-table td { padding:2px 0; }
420
+
421
+ /* Shopping cart total summary row expandable to details */
422
+ tr.summary-total { cursor:pointer; }
423
+ tr.summary-total td {}
424
+ tr.summary-total .summary-collapse { float:right; text-align:right; padding-left:20px; background:url(../images/bkg_collapse.gif) 0 5px no-repeat; cursor:pointer; }
425
+ tr.show-details .summary-collapse { background-position:0 -52px; }
426
+ tr.show-details td {}
427
+ tr.summary-details td { font-size:11px; background-color:#dae1e4; color:#626465; }
428
+ tr.summary-details-first td { border-top:1px solid #d2d8db; }
429
+ tr.summary-details-excluded { font-style:italic; }
430
+
431
+ /* Shopping cart tax info */
432
+ .cart-tax-info { display:block; }
433
+ .cart-tax-info,
434
+ .cart-tax-info .cart-price { padding-right:20px; }
435
+ .cart-tax-total { display:block; padding-right:20px; background:url(../images/bkg_collapse.gif) 100% 5px no-repeat; cursor:pointer; }
436
+ .cart-tax-info .price,
437
+ .cart-tax-total .price { display:inline !important; font-weight:normal !important; }
438
+ .cart-tax-total-expanded { background-position:100% -52px; }
439
+
440
+ /* Class: std - styles for admin-controlled content */
441
+ .std .subtitle { padding:0; }
442
+ .std ol.ol { list-style:decimal outside; padding-left:1.5em; }
443
+ .std ul.disc { list-style:disc outside; padding-left:18px; margin:0 0 10px; }
444
+ .std dl dt { font-weight:bold; }
445
+ .std dl dd { margin:0 0 10px; }
446
+ .std ul,
447
+ .std ol,
448
+ .std dl,
449
+ .std p,
450
+ .std address,
451
+ .std blockquote { margin:0 0 1em; padding:0; }
452
+ .std ul { list-style:disc outside; padding-left:1.5em; }
453
+ .std ol { list-style:decimal outside; padding-left:1.5em; }
454
+ .std ul ul { list-style-type:circle; }
455
+ .std ul ul,
456
+ .std ol ol,
457
+ .std ul ol,
458
+ .std ol ul { margin:.5em 0; }
459
+ .std dt { font-weight:bold; }
460
+ .std dd { padding:0 0 0 1.5em; }
461
+ .std blockquote { font-style:italic; padding:0 0 0 1.5em; }
462
+ .std address { font-style:normal; }
463
+ .std b,
464
+ .std strong { font-weight:bold; }
465
+ .std i,
466
+ .std em { font-style:italic; }
467
+
468
+ /* Misc */
469
+ .links li { display:inline; }
470
+ .links li.first { padding-left:0 !important; }
471
+ .links li.last { background:none !important; padding-right:0 !important; }
472
+
473
+ .link-cart { color:#dc6809 !important; font-weight:bold; }
474
+ .link-wishlist { color:#dc6809 !important; font-weight:bold; }
475
+ .link-reorder { font-weight:bold; color:#dc6809 !important; }
476
+ .link-compare { font-weight:bold; }
477
+ .link-print { /*background:url(../images/i_print.gif) 0 2px no-repeat; padding:2px 0 2px 25px;*/ font-weight:bold; color:#dc6809; }
478
+ .link-rss { background:url(../images/i_rss.gif) 0 2px no-repeat; padding-left:18px; line-height:14px; white-space:nowrap; }
479
+ .btn-remove { display:block; width:11px; height:11px; font-size:0; line-height:0; background:url(../images/btn_remove.gif) 0 0 no-repeat; text-indent:-999em; overflow:hidden; }
480
+ .btn-previous { display:block; width:11px; height:11px; font-size:0; line-height:0; background:url(../images/btn_previous.gif) 0 0 no-repeat; text-indent:-999em; overflow:hidden; }
481
+ .btn-remove2 { display:block; width:16px; height:16px; font-size:0; line-height:0; background:url(../images/btn_trash.gif) 0 0 no-repeat; text-indent:-999em; overflow:hidden; }
482
+ .btn-edit { display:block; width:11px; height:11px; font-size:0; line-height:0; background:url(../images/btn_edit.gif) 0 0 no-repeat; text-indent:-999em; overflow:hidden; }
483
+
484
+ .cards-list dt { margin:5px 0 0; }
485
+ .cards-list .offset { padding:2px 0 2px 20px; }
486
+
487
+ .separator { margin:0 3px; }
488
+
489
+ .divider { clear:both; display:block; font-size:0; line-height:0; height:1px; margin:10px 0; background:url(../images/bkg_divider1.gif) 0 50% repeat-x; text-indent:-999em; overflow:hidden; }
490
+
491
+ /* Global site notices */
492
+ .global-site-notice { border:1px solid #cfcfcf; border-width:0 0 1px; background:#ffff90; font-size:12px; line-height:1.25; text-align:center; color:#2f2f2f; }
493
+ .global-site-notice .notice-inner { width:860px; margin:0 auto; padding:12px 0 12px 80px; background:url(../images/i_notice.gif) 20px 25px no-repeat; text-align:left; }
494
+ .global-site-notice .notice-inner p { margin:0; border:1px dotted #cccc73; padding:10px; }
495
+ .global-site-notice .notice-inner .actions { padding-top:10px; }
496
+
497
+ /* Cookie Notice */
498
+ .notice-cookie { }
499
+
500
+ /* Noscript Notice */
501
+ .noscript {}
502
+
503
+ /* Demo Notice */
504
+ .demo-notice { margin:0; padding:6px 10px; background:#d75f07; font-size:12px; line-height:1.15; border:0; text-align:center; color:#fff; }
505
+ .demo-notice .notice-inner { width:auto; padding:0; background:none; text-align:center; }
506
+ .demo-notice .notice-inner p { padding:0; border:0; }
507
+
508
+ /* ======================================================================================= */
509
+
510
+
511
+ /* Header ================================================================================ */
512
+ .logo { float:left; }
513
+ .header-container { border-top:5px solid #0d2131; border-bottom:1px solid #415966; background:url(../images/bkg_header.jpg) 50% 0 repeat; }
514
+ .header { width:930px; margin:0 auto; padding:10px; text-align:right; position:relative; z-index:10; }
515
+ .header .logo { float:left; margin:3px 0 10px 12px; text-decoration:none !important; }
516
+ .header .logo strong { position:absolute; top:-999em; left:-999em; width:0; height:0; font-size:0; line-height:0; text-indent:-999em; overflow:hidden; }
517
+ .header h1.logo { margin:0; }
518
+ .header .quick-access { float:right; width:600px; padding:28px 10px 0 0; }
519
+ .header .welcome-msg { margin:0; color:#fff; text-align:right; }
520
+ .header .welcome-msg a { color:#ebbc58; }
521
+ .header .form-search { position:absolute; top:0; right:29px; width:315px; height:30px; background:url(../images/bkg_form-search.gif) 0 0 no-repeat; padding:1px 0 0 16px; }
522
+ .header .form-search label { float:left; width:24px; height:21px; text-align:left; text-indent:-999em; overflow:hidden; }
523
+ .header .form-search input.input-text { float:left; border-color:#5c7989; width:209px; margin-right:4px; }
524
+ .header .form-search button.button { float:left; }
525
+ .header .form-search button.button span { border:0; height:21px; background:url(../images/btn_search.gif) 0 0 no-repeat; padding:0 0 0 3px; font:bold 11px/21px Tahoma, Verdana, Arial, sans-serif; }
526
+ .header .form-search button.button span span { background-position:100% 0; padding:0 6px 0 3px; }
527
+ .header .form-search .search-autocomplete { z-index:999; left:40px !important; top:22px !important; }
528
+ .header .form-search .search-autocomplete ul { border:1px solid #5c7989; background-color:#f9f5f0; }
529
+ .header .form-search .search-autocomplete li { text-align:left; border-bottom:1px solid #f4eee7; padding:2px 8px 1px 8px; cursor:pointer; }
530
+ .header .form-search .search-autocomplete li .amount { float:right; font-weight:bold; }
531
+ .header .form-search .search-autocomplete li.odd { background-color:#fffefb; }
532
+ .header .form-search .search-autocomplete li.selected { background-color:#f7e8dd; }
533
+ .header .form-language { clear:both; padding:5px 0 0; text-align:right; }
534
+ .header .form-language label { font-weight:bold; padding-right:5px; color:#a7c6dd; vertical-align:middle; }
535
+ .header .form-language select { padding:0; }
536
+ .header .form-language select.flags option { background-position:4px 50%; background-repeat:no-repeat; padding-left:25px; }
537
+ .header .links { float:right; margin:0 0 6px; }
538
+ .header .links li { float:left; font-size:11px; background:url(../images/bkg_pipe1.gif) 100% 60% no-repeat; padding:0 8px 0 7px; }
539
+ .header .links a { color:#ebbc58; }
540
+ .header-container .top-container { clear:both; padding:5px 10px 0 12px; text-align:right; }
541
+ .header-container .top-container a { font-size:11px; color:#ebbc58; }
542
+
543
+ /********** < Navigation */
544
+ .nav-container { background:#0a263d url(../images/bkg_nav0.jpg) 50% 0 repeat-y; }
545
+ #nav { width:918px; margin:0 auto; padding:0 16px; font-size:13px; }
546
+
547
+ /* All Levels */ /* Style consistent throughout all nav levels */
548
+ #nav li { position:relative; text-align:left; }
549
+ #nav li.over { z-index:998; }
550
+ #nav a,
551
+ #nav a:hover { display:block; line-height:1.3em; text-decoration:none; }
552
+ #nav span { display:block; cursor:pointer; white-space:nowrap; }
553
+ #nav li ul span {white-space:normal; }
554
+ #nav ul li.parent a { background:url(../images/bkg_nav2.gif) 100% 100% no-repeat; }
555
+ #nav ul li.parent li a { background-image:none; }
556
+
557
+ /* 0 Level */
558
+ #nav li { float:left; }
559
+ #nav li.active a { color:#d96708; }
560
+ #nav a { float:left; padding:5px 12px 6px 8px; color:#a7c6dd; font-weight:bold; }
561
+ #nav li.over a,
562
+ #nav a:hover { color:#d96708; }
563
+
564
+ /* 1st Level */
565
+ #nav ul li,
566
+ #nav ul li.active { float:none; margin:0; padding-bottom:1px; background:#ecf3f6 url(../images/bkg_nav1.gif) 0 100% repeat-x; }
567
+ #nav ul li.last { background:#ecf3f6; padding-bottom:0; }
568
+
569
+ #nav ul a,
570
+ #nav ul a:hover { float:none; padding:0; background:none; }
571
+ #nav ul li a { font-weight:normal !important; }
572
+
573
+ /* 2nd Level */
574
+ #nav ul,
575
+ #nav div { position:absolute; width:15em; top:27px; left:-10000px; border:1px solid #899ba5; }
576
+ #nav div ul { position:static; width:auto; border:none; }
577
+
578
+ /* 3rd+ Level */
579
+ #nav ul ul,
580
+ #nav ul div { top:5px; }
581
+
582
+ #nav ul li a { background:#ecf3f6; }
583
+ #nav ul li a:hover { background:#d5e4eb; }
584
+ #nav ul li a,
585
+ #nav ul li a:hover { color:#2f2f2f !important; }
586
+ #nav ul span,
587
+ #nav ul li.last li span { padding:3px 15px 4px 15px; }
588
+
589
+ /* Show menu */
590
+ #nav li ul.shown-sub,
591
+ #nav li div.shown-sub { left:0; z-index:999; }
592
+ #nav li .shown-sub ul.shown-sub,
593
+ #nav li .shown-sub li div.shown-sub { left:100px; }
594
+ /********** Navigation > */
595
+ /* ======================================================================================= */
596
+
597
+
598
+ /* Sidebar =============================================================================== */
599
+ .block { border:1px solid #c4c1bc; margin:0 0 15px; }
600
+ .block .block-title { background:url(../images/bkg_block-title.gif) 0 0 repeat-x; border-bottom:1px solid #ddd; padding:2px 9px; }
601
+ .block .block-title strong { display:block; font:bold 12px/16px Arial, Helvetica, sans-serif; min-height:16px; padding:1px 0 1px; text-transform:uppercase; color:#e26703; }
602
+ .block .block-title strong span {}
603
+ .block .block-title a { text-decoration:none !important; }
604
+ .block .block-subtitle { margin:0; padding:5px 9px; font-size:1em; font-weight:bold; color:#0a263c; }
605
+ .block .block-content { background:#f8f7f5; }
606
+ .block .block-content li.item { padding:7px 9px; }
607
+ .block .block-content .product-name { color:#1e7ec8; }
608
+ .block .btn-remove,
609
+ .block .btn-edit { float:right; margin:1px 0 2px 5px; }
610
+ .block .actions { background:#dee5e8 url(../images/bkg_block-actions.gif) 0 0 repeat-x; padding:6px 9px; text-align:right; }
611
+ .block .actions a { float:left; }
612
+ .block .actions button.button { float:right; }
613
+ .block .empty { margin:0; padding:5px 9px; }
614
+
615
+ .block li.odd { background-color:#f4f3f3; }
616
+ .block li.even { background-color:#fafafa; }
617
+
618
+ /* Mini Blocks */
619
+ .block-cart,
620
+ .block-wishlist,
621
+ .block-subscribe,
622
+ .block-compare,
623
+ .block-reorder,
624
+ .block-poll,
625
+ .block-viewed,
626
+ .block-compared,
627
+ .block-related,
628
+ .block-tags,
629
+ .block-login { font-size:11px; line-height:1.25; }
630
+ .block-cart .block-title strong,
631
+ .block-wishlist .block-title strong,
632
+ .block-subscribe .block-title strong,
633
+ .block-compare .block-title strong,
634
+ .block-reorder .block-title strong,
635
+ .block-poll .block-title strong,
636
+ .block-viewed .block-title strong,
637
+ .block-compared .block-title strong,
638
+ .block-related .block-title strong,
639
+ .block-tags .block-title strong,
640
+ .block-login .block-title strong { background-position:0 0; background-repeat:no-repeat; padding-left:21px; }
641
+
642
+ /* Mini Products List */
643
+ .mini-products-list .product-image { float:left; width:50px; border:1px solid #a9a9a9; }
644
+ .mini-products-list .product-details { margin-left:60px; }
645
+ .block-cart .mini-products-list .product-details .product-name,
646
+ .block-cart .mini-products-list .product-details .nobr small { word-wrap:break-word; }
647
+ .block-cart .mini-products-list .product-details .nobr { white-space:normal !important; }
648
+
649
+ /* Block: Account */
650
+ .block-account { border-color:#bbb; }
651
+ .block-account .block-title { background:#fc9d36 url(../images/bkg_block-title-account.gif) 0 100% repeat-x; border:0; padding:3px 10px; }
652
+ .block-account .block-title strong { font-size:13px; color:#fff; }
653
+ .block-account .block-content { background:#fbfaf6; padding:7px 10px 7px; }
654
+ .block-account .block-content li a { display:block; border-bottom:1px solid #ddd; padding:3px 0; color:#5f5d5c; text-decoration:none !important; }
655
+ .block-account .block-content li a:hover { color:#ea7900; }
656
+ .block-account .block-content li.last a { border-bottom:0; }
657
+ .block-account .block-content li.current { border-bottom:1px solid #ddd; padding:3px 0; color:#ea7900; }
658
+ .block-account .block-content li.current.last { border-bottom:0; }
659
+
660
+ /* Block: Currency Switcher */
661
+ .block-currency { border:0; background:url(../images/bkg_block-currency.gif) 0 0 no-repeat; padding:7px 12px 10px; height:51px; }
662
+ .block-currency .block-title { background:none; border:0; padding:0; margin:0 0 5px; }
663
+ .block-currency .block-title strong { font:bold 13px/21px Arial, Helvetica, sans-serif; background:url(../images/i_block-currency.gif) 0 50% no-repeat; padding:0 0 0 21px; text-transform:none; color:#fff; }
664
+ .block-currency .block-content { background:none; padding:0; }
665
+ .block-currency .block-content select { width:100%; padding:0; }
666
+
667
+ /* Block: Layered Navigation */
668
+ .block-layered-nav { border:0; }
669
+ .block-layered-nav .block-title { border:0; padding:0; height:24px; background:url(../images/bkg_block-layered-title.gif) 0 0 no-repeat; text-indent:-999em; overflow:hidden; }
670
+ .block-layered-nav .block-subtitle { line-height:1.35; background:#d5e8ff url(../images/bkg_block-layered1.gif) 0 50% repeat; padding:3px 9px; border:1px solid #b9ccdd; border-width:1px 0; text-transform:uppercase; color:#1f5070; }
671
+ .block-layered-nav .block-content { border:1px solid #a0b3c3; background:#e7f1f4; }
672
+ .block-layered-nav dt { background:url(../images/bkg_block-layered-dt.gif) 9px 11px no-repeat; padding:7px 10px 0 25px; font-weight:bold; text-transform:uppercase; }
673
+ .block-layered-nav dd { padding:0 12px 12px; background:url(../images/bkg_block-layered-dd.gif) 0 100% repeat-x; }
674
+ .block-layered-nav dd.last { background:none; }
675
+ .block-layered-nav .currently li { background:#fff url(../images/bkg_block-layered-li.gif) 0 100% repeat-x; padding:6px 24px 6px 10px; position:relative; z-index:1; line-height:1.5; }
676
+ .block-layered-nav .currently .label { font-weight:bold; padding-left:15px; background:url(../images/bkg_block-layered-label.gif) 0 4px no-repeat; text-transform:uppercase; display:inline-block; vertical-align:top; }
677
+ .block-layered-nav .currently .value { display:inline-block; vertical-align:top; }
678
+ .block-layered-nav .currently .btn-previous,
679
+ .block-layered-nav .currently .btn-remove { position:absolute; right:4px; top:9px; margin:0; }
680
+ .block-layered-nav .currently .btn-previous { right:17px; }
681
+ .block-layered-nav .actions { font-size:11px; padding:4px 5px 4px 9px; background:#cad6e4; border:1px solid #dee5e8; border-width:1px 0; text-align:right; }
682
+ .block-layered-nav .actions a { float:none; }
683
+
684
+ /* Block: Cart */
685
+ .block-cart .block-title { /*border-bottom:0;*/ }
686
+ .block-cart .block-title strong { background-image:url(../images/i_block-cart.gif); }
687
+ .block-cart .summary { background:#fff; padding:2px 8px 8px; margin:-1px 0 0; position:relative; z-index:1; }
688
+ .block-cart .amount { margin:0; }
689
+ .block-cart .amount a { font-weight:bold; }
690
+ .block-cart .subtotal { margin:5px 0 0; padding:2px 0; background:#fbebd9; text-align:center; }
691
+ .block-cart .subtotal .price { font-weight:bold; }
692
+ .block-cart .actions { border-bottom:1px solid #c2c2c2; }
693
+ .block-cart .actions .paypal-logo { float:left; width:100%; margin:3px 0 0; text-align:right; }
694
+ .block-cart .actions .paypal-logo .paypal-or { clear:both; display:block; padding:0 55px 8px 0; }
695
+
696
+ /* Block: Wishlist */
697
+ .block-wishlist .block-title strong { background-image:url(../images/i_block-wishlist.gif); }
698
+ .block-wishlist .actions { text-align:right; }
699
+ .block-wishlist .actions a { float:none; }
700
+
701
+ /* Block: Related */
702
+ .block-related .block-title strong { background-image:url(../images/i_block-related.gif); background-position:0 1px; }
703
+ .block-related input.checkbox { float:left; }
704
+ .block-related .product { margin-left:20px; }
705
+
706
+ /* Block: Compare Products */
707
+ .block-compare .block-title strong { background-image:url(../images/i_block-list.gif); background-position:0 1px; }
708
+ .block-compare button.button span { border-color:#406a83; background:#618499; }
709
+ .page-popup .link-print { background:url(../images/i_print.gif) 0 2px no-repeat; padding:2px 0 2px 25px; font-weight:bold; color:#1e7ec8; }
710
+ .compare-table { border:0; }
711
+ .compare-table thead tr.first th,
712
+ .compare-table thead tr.first td { border:0; background:none; padding:0; font-size:0; line-height:0; }
713
+ .compare-table .btn-remove { float:right; background-image:url(../images/btn_remove2.gif); width:72px; height:15px; }
714
+ .compare-table tbody th { background:#d9e5ee url(../images/bkg_th-v.gif) 100% 0 repeat-y; }
715
+ .compare-table tbody th,
716
+ .compare-table tbody td { padding:10px; border:0; border-top:1px solid #ccc; border-left:1px solid #ccc; }
717
+ .compare-table tbody td.last { border-right:1px solid #ccc; }
718
+ .compare-table tbody tr.last th,
719
+ .compare-table tbody tr.last td { border-bottom:1px solid #ccc !important; }
720
+ .compare-table tr.add-to-row td { background:#fffada; text-align:center; }
721
+ .compare-table tr.first td { text-align:center; }
722
+ .compare-table tr.first td .product-name { font-size:13px; font-weight:bold; margin:0 0 5px; color:#203548; }
723
+ .compare-table tr.first td .product-name a { color:#203548; }
724
+ .compare-table tr.first td .ratings { width:69px; margin:0 auto; }
725
+ .compare-table tr.first td p,
726
+ .compare-table tr.add-to-row td p { margin:0; }
727
+
728
+ /* Block: Recently Viewed */
729
+ .block-viewed .block-title strong { background-image:url(../images/i_block-viewed.gif); }
730
+
731
+ /* Block: Recently Compared */
732
+ .block-compared .block-title strong { background-image:url(../images/i_block-list.gif); background-position:0 1px; }
733
+
734
+ /* Block: Poll */
735
+ .block-poll .block-title strong { background-image:url(../images/i_block-poll.gif); }
736
+ .block-poll .block-subtitle { font-size:12px; }
737
+ .block-poll label { color:#777; font-weight:bold; }
738
+ .block-poll input.radio { float:left; margin:1px -18px 0 0; }
739
+ .block-poll .label { display:block; margin-left:18px; }
740
+ .block-poll li { padding:3px 9px; }
741
+ .block-poll .actions { margin:5px 0 0; }
742
+ .block-poll button.button span { border-color:#406a83; background:#618499; }
743
+ .block-poll .answer { font-weight:bold; }
744
+ .block-poll .votes { float:right; margin-left:10px; }
745
+
746
+ /* Block: Tags */
747
+ .block-tags .block-title strong { background-image:url(../images/i_block-tags.gif); }
748
+ .block-tags .block-content .tags-list { background:none; border:0; font-size:12px; }
749
+ .block-tags .block-content a { color:#1b2d3b; }
750
+ .block-tags .actions { text-align:right; }
751
+ .block-tags .actions a { float:none; }
752
+
753
+ /* Block: Subscribe */
754
+ .block-subscribe .block-content { padding:5px 10px; }
755
+ .block-subscribe .block-title strong { background-image:url(../images/i_block-subscribe.gif); }
756
+ .block-subscribe label { font-weight:bold; color:#666; }
757
+ .block-subscribe input.input-text { display:block; width:167px; margin:3px 0; }
758
+ .block-subscribe .actions { background:none; padding:0; margin:3px 0 0; text-align:left; }
759
+ .block-subscribe .actions button.button { float:none; }
760
+ .block-subscribe .actions button.button span { border-color:#406a83; background:#618499; }
761
+
762
+ /* Block: Reorder */
763
+ .block-reorder .block-title strong { background-image:url(../images/i_block-list.gif); }
764
+ .block-reorder input.checkbox { float:left; margin:2px -20px 0 0; }
765
+ .block-reorder .product-name { margin-left:20px; }
766
+ .block-reorder .validation-advice { margin:3px 9px 7px; }
767
+
768
+ /* Block: Banner */
769
+ .block-banner { border:0; }
770
+ .block-banner .block-content { padding:0; text-align:center; }
771
+
772
+ /* Block: Login */
773
+ .block-login .block-title strong { background-image:url(../images/i_ma-info.gif); }
774
+ .block-login .block-content { padding:5px 10px; }
775
+ .block-login label { font-weight:bold; color:#666; }
776
+ .block-login input.input-text { display:block; width:167px; margin:3px 0; }
777
+ .block-login .actions { background:none; padding:0; margin:3px 0 0; }
778
+ .block-login .actions button.button span { border-color:#406a83; background:#618499; }
779
+
780
+ /* Paypal */
781
+ .sidebar .paypal-logo { display:block; margin:10px 0; text-align:center; }
782
+ .sidebar .paypal-logo a { float:none; }
783
+ /* ======================================================================================= */
784
+
785
+
786
+ /* Category Page ========================================================================= */
787
+ .category-title { border:0; margin:0 0 7px; }
788
+ .category-image { width:100%; overflow:hidden; margin:0 0 10px; text-align:center; }
789
+ .category-image img {}
790
+ .category-description { margin:0 0 10px; }
791
+ .category-products {}
792
+
793
+ /* View Type: Grid */
794
+ .products-grid { border-bottom:1px solid #d9ddd3; background:url(../images/bkg_grid.gif) 0 0 repeat; position:relative; }
795
+ .products-grid.last { border-bottom:0; }
796
+ .products-grid li.item { float:left; width:138px; padding:12px 10px 80px; }
797
+ .products-grid .product-image { display:block; width:135px; height:135px; margin:0 0 10px; }
798
+ .products-grid .product-name { /*min-height:2.7em;*/ margin:0 0 5px; font-weight:bold; font-size:13px; color:#203548; }
799
+ .products-grid .product-name a { color:#203548; }
800
+ .products-grid .price-box { margin:5px 0; }
801
+ .products-grid .availability { line-height:21px; }
802
+ .products-grid .actions { position:absolute; bottom:12px; }
803
+ .col2-left-layout .products-grid,
804
+ .col2-right-layout .products-grid { width:632px; margin:0 auto; }
805
+ .col1-layout .products-grid { width:790px; margin:0 auto; }
806
+
807
+ /* View Type: List */
808
+ .products-list li.item { border-bottom:1px solid #d9ddd3; padding:12px 10px; }
809
+ .products-list li.item.last { border-bottom:0; }
810
+ .products-list .product-image { float:left; width:135px; height:135px; margin:0 0 10px; }
811
+ .products-list .product-shop { margin-left:150px; }
812
+ .products-list .product-name { margin:0 0 5px; font-weight:bold; font-size:13px; color:#203548; }
813
+ .products-list .product-name a { color:#203548; }
814
+ .products-list .price-box { float:left; margin:3px 13px 5px 0; }
815
+ .products-list .availability { float:left; margin:3px 0 0; }
816
+ .products-list .desc { clear:both; padding:6px 0 0; margin:0 0 15px; line-height:1.35; }
817
+ .products-list .desc .link-learn { font-size:11px; }
818
+ .products-list .add-to-links { clear:both; }
819
+ .products-list .add-to-links li { display:inline; }
820
+ .products-list .add-to-links .separator { display:inline; margin:0 2px; }
821
+ /* ======================================================================================= */
822
+
823
+
824
+ /* Product View ========================================================================== */
825
+ /* Rating */
826
+ .no-rating { margin:0; }
827
+
828
+ .ratings { font-size:11px; line-height:1.25; margin:7px 0; }
829
+ .ratings strong { float:left; margin:1px 3px 0 0; }
830
+ .ratings .rating-links { margin:0; }
831
+ .ratings .rating-links .separator { margin:0 2px; }
832
+ .ratings dt {}
833
+ .ratings dd {}
834
+ .rating-box { width:69px; height:13px; font-size:0; line-height:0; background:url(../images/bkg_rating.gif) 0 0 repeat-x; text-indent:-999em; overflow:hidden; }
835
+ .rating-box .rating { float:left; height:13px; background:url(../images/bkg_rating.gif) 0 100% repeat-x; }
836
+ .ratings .rating-box { float:left; margin-right:3px; }
837
+ .ratings .amount {}
838
+
839
+ .ratings-table th,
840
+ .ratings-table td { font-size:11px; line-height:1.15; padding:3px 0; }
841
+ .ratings-table th { font-weight:bold; padding-right:8px; }
842
+
843
+ /* Availability */
844
+ .availability { margin:0; }
845
+ .availability span { font-weight:bold; }
846
+ .availability.in-stock span {}
847
+ .availability.out-of-stock span { color:#d83820; }
848
+
849
+ .availability-only { margin:10px 0 7px; line-height:16px; background:url(../images/i_availability_only.gif) 0 50% no-repeat; padding-left:15px; }
850
+ .availability-only span,
851
+ .availability-only a { border-bottom:1px dashed #751d02; color:#000; }
852
+ .availability-only a { background:url(../images/i_availability_only_arrow.gif) 100% 0 no-repeat; cursor:pointer; padding-right:15px; text-decoration:none; }
853
+ .availability-only .expanded { background-position:100% -15px; }
854
+ .availability-only strong { color:#be2c00; }
855
+
856
+ .availability-only-details { margin:0 0 7px; }
857
+ .availability-only-details th { background:#d2d6d9; font-size:10px; padding:0 8px; }
858
+ .availability-only-details td { background:#ebf0f3; border-bottom:1px solid #fff; font-size:11px; padding:2px 8px 1px; }
859
+ .availability-only-details tr.odd td.last { color:#d95e00; font-weight:bold; }
860
+
861
+ .product-view .product-shop .availability { font-size:11px; }
862
+ .product-view .product-shop .availability span { font-weight:normal; }
863
+
864
+ /* Email to a Friend */
865
+ .email-friend { margin:0; }
866
+
867
+ /* Alerts */
868
+ .alert-price { margin:0; font-size:11px; }
869
+ .alert-stock { margin:0; font-size:11px; }
870
+
871
+ /********** < Product Prices */
872
+ .price { white-space:nowrap !important; }
873
+
874
+ .price-box { margin:5px 0; }
875
+ .price-box .price { font-weight:bold; color:#c76200; }
876
+
877
+ /* Regular price */
878
+ .regular-price { color:#c76200; }
879
+ .regular-price .price { font-weight:bold; font-size:13px; color:#c76200; }
880
+ .block .regular-price,
881
+ .block .regular-price .price { color:#2f2f2f; }
882
+
883
+ /* Old price */
884
+ .old-price { margin:0; }
885
+ .old-price .price-label { white-space:nowrap; color:#999; }
886
+ .old-price .price { font-weight:bold; color:#c76200; text-decoration:line-through; }
887
+
888
+ /* Special price */
889
+ .special-price { margin:0; padding:3px 0; }
890
+ .special-price .price-label { font-size:13px; font-weight:bold; white-space:nowrap; color:#cd5033; }
891
+ .special-price .price { font-size:13px; font-weight:bold; color:#c76200; }
892
+
893
+ /* Minimal price (as low as) */
894
+ .minimal-price { margin:0; }
895
+ .minimal-price .price-label { font-weight:bold; white-space:nowrap; }
896
+
897
+ .minimal-price-link { display:block; }
898
+ .minimal-price-link .label {color:#1e7ec8;}
899
+ .minimal-price-link .price { font-weight:normal; color:#1e7ec8; }
900
+
901
+ /* Excluding tax */
902
+ .price-excluding-tax { display:block; color:#999; }
903
+ .price-excluding-tax .label { white-space:nowrap; color:#999; }
904
+ .price-excluding-tax .price { font-size:13px; font-weight:normal; color:#c76200; }
905
+
906
+ /* Including tax */
907
+ .price-including-tax { display:block; color:#999; }
908
+ .price-including-tax .label { white-space:nowrap; color:#999; }
909
+ .price-including-tax .price { font-size:13px; font-weight:bold; color:#c76200; }
910
+
911
+ /* Configured price */
912
+ .configured-price { margin:0; }
913
+ .configured-price .price-label { font-weight:bold; white-space:nowrap; }
914
+ .configured-price .price { font-weight:bold; }
915
+
916
+ /* FPT */
917
+ .weee { display:block; font-size:11px; color:#444; }
918
+ .weee .price { font-size:11px; font-weight:normal; }
919
+
920
+ /* Excl tax (for order tables) */
921
+ .price-excl-tax { display:block; }
922
+ .price-excl-tax .label { display:block; white-space:nowrap; }
923
+ .price-excl-tax .price { display:block; }
924
+
925
+ /* Incl tax (for order tables) */
926
+ .price-incl-tax { display:block; }
927
+ .price-incl-tax .label { display:block; white-space:nowrap; }
928
+ .price-incl-tax .price { display:block; font-weight:bold; }
929
+
930
+ /* Price range */
931
+ .price-from { margin:0; }
932
+ .price-from .price-label { font-weight:bold; white-space:nowrap; }
933
+
934
+ .price-to { margin:0; }
935
+ .price-to .price-label { font-weight:bold; white-space:nowrap; }
936
+
937
+ /* Price notice next to the options */
938
+ .price-notice { padding-left:10px; color:#999; }
939
+ .price-notice .price { font-weight:bold; color:#2f2f2f; }
940
+
941
+ /* Price as configured */
942
+ .price-as-configured { margin:0; }
943
+ .price-as-configured .price-label { font-weight:bold; white-space:nowrap; }
944
+
945
+ .price-box-bundle { padding:0 0 10px 0; }
946
+ .price-box-bundle .price-box { margin:0 !important; padding:0 !important; }
947
+ .price-box-bundle .price { color:#555; }
948
+ /********** Product Prices > */
949
+
950
+ /* Tier Prices */
951
+ .product-pricing,
952
+ .tier-prices { margin:10px 0; padding:10px; background-color:#f4f7f7; border:1px solid #dadddd; color:#424242; }
953
+ .tier-prices li { line-height:1.4; background:url(../images/i_tier.gif) no-repeat 0 3px; padding:2px 0 2px 10px; }
954
+ .tier-prices .benefit { font-style:italic; font-weight:bold; color:#2f2f2f; }
955
+ .tier-prices .price { font-weight:bold; color:#2f2f2f; }
956
+
957
+ .tier-prices-grouped li { padding:2px 0; color:#e26703; }
958
+ .tier-prices-grouped li .price { font-weight:bold; }
959
+
960
+ /* Add to Links */
961
+ .add-to-links { font-size:11px; margin:5px 0 0; }
962
+ .add-to-links .separator { display:none; }
963
+
964
+ /* Add to Cart */
965
+ .add-to-cart label { float:left; margin-right:5px; font-weight:bold; color:#666; }
966
+ .add-to-cart .qty { float:left; margin-right:5px; }
967
+ .add-to-cart button.button { float:left; }
968
+ .add-to-cart .paypal-logo { clear:left; margin:0; text-align:right; }
969
+ .add-to-cart .paypal-logo .paypal-or { clear:both; display:block; margin:5px 60px 5px 0; }
970
+ .product-view .add-to-cart .paypal-logo { margin:0; }
971
+
972
+ /* Add to Links + Add to Cart */
973
+ .add-to-box { margin:10px 0; }
974
+ .add-to-box .add-to-cart { float:left; }
975
+ .add-to-box .or { float:left; font-weight:bold; margin:0 7px; color:#666; }
976
+ .add-to-box .add-to-links { float:left; margin:0; font-size:12px !important; line-height:1.25 !important; text-align:left !important; }
977
+ .add-to-box .add-to-links li { display:block !important; }
978
+ .add-to-box .add-to-links li .separator { display:none !important; }
979
+
980
+
981
+ .product-view { border:1px solid #c4c6c8; }
982
+
983
+ .product-essential { padding:25px; background:#fff url(../images/bkg_product-view.gif) 100% 0 no-repeat; }
984
+ .product-essential h2 { font:bold 13px/1.35 Arial, Helvetica, sans-serif; }
985
+
986
+ .product-collateral { background:#faf7ee url(../images/bkg_product_collateral.gif) 0 0 repeat-x; padding:25px; }
987
+ .product-collateral h2 { font-weight:bold; font-size:15px; color:#e26703; border-bottom:1px solid #e5dcc3; padding:0 0 1px; margin:0 0 15px; }
988
+ .product-collateral .box-collateral { margin:0 0 25px; }
989
+
990
+ /* Product Images */
991
+ .product-view .product-img-box { float:left; width:267px; }
992
+ .col3-layout .product-view .product-img-box { float:none; margin:0 auto; }
993
+ .product-view .product-img-box .product-image { margin:0 0 13px; }
994
+ .product-view .product-img-box .product-image-zoom { position:relative; width:265px; height:265px; overflow:hidden; z-index:9; }
995
+ .product-view .product-img-box .product-image-zoom img { position:absolute; left:0; top:0; cursor:move; }
996
+ .product-view .product-img-box .zoom-notice { font-size:11px; margin:0 0 5px; text-align:center; }
997
+ .product-view .product-img-box .zoom { position:relative; z-index:9; height:18px; margin:0 auto 13px; padding:0 28px; background:url(../images/slider_bg.gif) 50% 50% no-repeat; cursor:pointer; }
998
+ .product-view .product-img-box .zoom.disabled { -moz-opacity:.3; -webkit-opacity:.3; -ms-filter:"progid:DXImageTransform.Microsoft.Alpha(Opacity=30)";/*IE8*/ opacity:.3; }
999
+ .product-view .product-img-box .zoom #track { position:relative; height:18px; }
1000
+ .product-view .product-img-box .zoom #handle { position:absolute; left:0; top:-1px; width:9px; height:22px; background:url(../images/magnifier_handle.gif) 0 0 no-repeat; }
1001
+ .product-view .product-img-box .zoom .btn-zoom-out { position:absolute; left:2px; top:0; }
1002
+ .product-view .product-img-box .zoom .btn-zoom-in { position:absolute; right:2px; top:0; }
1003
+ .product-view .product-img-box .more-views h2 { font-size:11px; border-bottom:1px solid #ccc; margin:0 0 8px; text-transform:uppercase; }
1004
+ .product-view .product-img-box .more-views ul { margin-left:-9px }
1005
+ .product-view .product-img-box .more-views li { float:left; margin:0 0 8px 9px; }
1006
+ .product-view .product-img-box .more-views li a { float:left; width:56px; height:56px; border:2px solid #ddd; overflow:hidden; }
1007
+
1008
+ .product-image-popup { margin:0 auto; }
1009
+ .product-image-popup .buttons-set { float:right; clear:none; border:0; margin:0; padding:0; }
1010
+ .product-image-popup .nav { font-weight:bold; margin:0 100px; text-align:center; }
1011
+ .product-image-popup .image { display:block; margin:10px 0; }
1012
+ .product-image-popup .image-label { font-size:13px; font-weight:bold; margin:0 0 10px; color:#2f2f2f; }
1013
+
1014
+ /* Product Shop */
1015
+ .product-view .product-shop { float:right; width:330px; }
1016
+ .col1-layout .product-view .product-shop { float:right; width:545px; }
1017
+ .col3-layout .product-view .product-shop { float:none; width:auto; }
1018
+ .product-view .product-shop .product-name { margin:0 0 5px; }
1019
+ .product-view .product-shop .product-name h1 { margin:0; font:bold 15px/1.35 Arial, Helvetica, sans-serif; }
1020
+ .product-view .product-shop .availability { margin:10px 0; }
1021
+ .product-view .product-shop .short-description { margin:10px 0; background:url(../images/bkg_divider1.gif) 0 0 repeat-x; padding:10px 0 0; }
1022
+ .product-view .product-shop .price-box { margin:10px 0; }
1023
+ .product-view .product-shop .add-to-links { margin:0; }
1024
+ .product-view .product-shop .add-to-links { font-size:12px; text-align:right; }
1025
+ .product-view .product-shop .add-to-links li,
1026
+ .product-view .product-shop .add-to-links li .separator { display:inline; }
1027
+ .product-view .product-shop .add-to-links a { color:#1E7EC8 !important; font-weight:normal !important; }
1028
+
1029
+ /* Product Options */
1030
+ .product-options { margin:20px 0 0; padding:10px 15px 20px; position:relative; background-color:#f6f6f6; border:1px solid #e4e4e4; }
1031
+ .product-options dt { padding:10px 0 0; font-weight:normal; }
1032
+ .product-options dt label { font-weight:bold; color:#2f2f2f; }
1033
+ .product-options dt label.required em { color:#eb340a; margin-left:5px; }
1034
+ .product-options dd .qty-holder { display:block; padding:10px 0 0; }
1035
+ .product-options dd .qty-holder label { vertical-align:middle; }
1036
+ .product-options dt .qty-disabled { background:none; border:0; padding:3px; color:#2f2f2f; }
1037
+ .product-options dd { padding:5px 10px 15px; margin:0 0 5px; border-bottom:1px solid #e4e4e4; }
1038
+ .product-options dl.last dd.last { border-bottom:0; padding-bottom:5px; margin-bottom:0; }
1039
+ .product-options dd input.input-text { width:98%; }
1040
+ .product-options dd input.datetime-picker { width:150px; }
1041
+ .product-options dd .time-picker { display:-moz-inline-box; display:inline-block; padding:2px 0; vertical-align:middle; }
1042
+ .product-options dd textarea { width:98%; height:8em; }
1043
+ .product-options dd select { width:99%; }
1044
+ .product-options dd .multiselect option { border-bottom:1px dotted #d9e5ee; padding:2px 4px; }
1045
+ .product-options ul.options-list { margin-right:5px; }
1046
+ .product-options ul.options-list li { line-height:1.5; padding:2px 0; }
1047
+ .product-options ul.options-list input.radio { float:left; margin-top:3px; }
1048
+ .product-options ul.options-list input.checkbox { float:left; margin-top:3px; }
1049
+ .product-options ul.options-list .label { display:block; margin-left:18px; }
1050
+ .product-options ul.options-list label { font-weight:normal; }
1051
+ .product-options ul.validation-failed { padding:0 7px; }
1052
+ .product-options p.note { margin:0; font-size:11px; }
1053
+ .product-options p.required { position:absolute; right:20px; top:20px; }
1054
+
1055
+ .product-options-bottom { background-color:#fffada; padding:15px 20px; border:1px solid #e4e4e4; border-top:0; }
1056
+ .product-options-bottom .product-pricing,
1057
+ .product-options-bottom .tier-prices { margin:0; padding:0 0 10px; border:0; background:0; color:#e26703; }
1058
+ .product-options-bottom .tier-prices li { background:0; padding:2px 0; }
1059
+ .product-options-bottom .tier-prices .price,
1060
+ .product-options-bottom .tier-prices .benefit { color:#e26703; }
1061
+ .product-options-bottom .price-box { float:left; margin:0; padding:0; }
1062
+ .product-options-bottom .add-to-links { clear:both; padding:5px 0 0; text-align:right; }
1063
+ .col3-layout .product-options-bottom .price-box { float:none; padding:0 0 5px; }
1064
+ .product-options-bottom .price-label { float:left; padding-right:5px; }
1065
+ .product-options-bottom .price-tax { float:left; }
1066
+ .product-options-bottom .add-to-cart { float:right; }
1067
+ .product-shop .product-options-bottom { margin:0 0 10px; }
1068
+ .product-shop .product-options-bottom .price-box { float:none; margin:0 0 5px; }
1069
+ .product-shop .product-options-bottom .price-label { float:none; padding-right:0; }
1070
+ .product-shop .product-options-bottom .price-tax { float:none; }
1071
+ .product-shop .product-options-bottom .add-to-cart-box { clear:both; float:left; padding-top:12px; }
1072
+ .product-shop .product-options-bottom .add-to-links { clear:both; padding:5px 0 0; text-align:right; }
1073
+
1074
+ /* Grouped Product */
1075
+ .product-view .grouped-items-table .price-box { margin:0; padding:0; }
1076
+
1077
+ /* Block: Description */
1078
+ .product-view .box-description {}
1079
+
1080
+ /* Block: Additional */
1081
+ .product-view .box-additional .data-table th,
1082
+ .product-view .box-additional .data-table td { line-height:1.25; }
1083
+
1084
+ /* Block: Upsell */
1085
+ .product-view .box-up-sell h2 { border-bottom:0; padding:0; margin:0 0 8px; }
1086
+ .product-view .box-up-sell .products-grid { width:100%; border:1px solid #e5dcc3; }
1087
+ .product-view .box-up-sell .products-grid td { width:25%; background:#f6f2e7; border-right:1px solid #e5dcc3; border-bottom:1px solid #e5dcc3; padding:15px 10px 12px; line-height:1.6em; }
1088
+ .product-view .box-up-sell .products-grid tr.last td { border-bottom:0; }
1089
+ .product-view .box-up-sell .products-grid td.last { border-right:0; }
1090
+ .product-view .box-up-sell .products-grid td img { border:1px solid #e5dcc3; }
1091
+ .product-view .box-up-sell .products-grid .product-image { text-align:center; }
1092
+ .product-view .box-up-sell .products-grid td.empty { border-right:0; background:#f1ecdb; }
1093
+ .product-view .box-up-sell .products-grid .ratings .rating-box { float:none; display:block; margin:0 0 3px; }
1094
+
1095
+ /* Block: Tags */
1096
+ .product-view .box-tags { margin:0; }
1097
+ .product-view .box-tags h3 { font-size:13px; }
1098
+ .product-view .box-tags .product-tags { display:block; margin:0 0 15px; }
1099
+ .product-view .box-tags .product-tags li { display:inline; background:url(../images/bkg_pipe3.gif) 100% 4px no-repeat; padding:0 7px 0 4px; }
1100
+ .product-view .box-tags .product-tags li.first { padding-left:0; }
1101
+ .product-view .box-tags .product-tags li.last { background:none; padding-right:0; }
1102
+ .product-view .box-tags .form-add label { display:block; font-size:13px; font-weight:bold; margin:0 0 5px; color:#0a263c;}
1103
+ .product-view .box-tags .form-add .input-box { float:left; width:305px; margin:0 5px 0 0; background:url(../images/i_tag_add.gif) 0 2px no-repeat; padding:0 0 0 23px; }
1104
+ .product-view .box-tags .form-add input.input-text { width:299px; }
1105
+ .product-view .box-tags .form-add button.button span { border-color:#406a83; background:#618499; }
1106
+ .product-view .box-tags .note { margin:3px 0 0; padding:0 0 0 23px; font-size:11px; }
1107
+
1108
+ /* Block: Reviews */
1109
+ .product-view .box-reviews dl { margin:15px 0; }
1110
+ .product-view .box-reviews dt a,
1111
+ .product-view .box-reviews dt span { font-weight:bold; }
1112
+ .product-view .box-reviews dd { margin:0 0 15px; }
1113
+ .product-view .box-reviews dd small { font-style:italic; }
1114
+ .product-view .box-reviews .form-add { margin:15px 0 0; }
1115
+ .product-view .box-reviews .form-add h3 { font-size:13px; font-weight:normal; }
1116
+ .product-view .box-reviews .form-add h3 span { font-weight:bold; }
1117
+ .product-view .box-reviews .form-add h4 { font-size:12px; }
1118
+ .product-view .box-reviews .form-add .data-table td { text-align:center; }
1119
+ .product-view .box-reviews .form-add .form-list { margin:15px 0 0; }
1120
+ .product-view .box-reviews .form-add .form-list .input-box { width:360px; }
1121
+ .product-view .box-reviews .form-add .form-list input.input-text,
1122
+ .product-view .box-reviews .form-add .form-list textarea { width:354px; }
1123
+
1124
+ /* Send a Friend */
1125
+ .send-friend .form-list { width:615px; overflow:hidden; }
1126
+ .send-friend .form-list li { margin-right:-15px; }
1127
+ .send-friend .form-list li p { margin:0 15px 0 0; }
1128
+ .send-friend .form-list .field { width:315px; }
1129
+ .send-friend .form-list .input-box { width:300px; }
1130
+ .send-friend .form-list input.input-text,
1131
+ .send-friend .form-list textarea { width:294px; }
1132
+ .send-friend .form-list li.wide .input-box { width:612px; }
1133
+ .send-friend .form-list li.wide textarea { width:609px; }
1134
+ .send-friend .buttons-set .limit { float:right; margin:0 7px 0 0; font-size:11px; line-height:21px; }
1135
+ /* ======================================================================================= */
1136
+
1137
+
1138
+ /* Content Styles ================================================================= */
1139
+ .product-name { margin:0; font-size:1em; font-weight:normal; }
1140
+ .product-name a { color:#1e7ec8; }
1141
+
1142
+ /* Product Tags */
1143
+ .tags-list { display:block; font-size:13px; border:1px solid #c1c4bc; background:#f8f7f5; padding:10px; }
1144
+ .tags-list li { display:inline !important; margin:0 4px 0 0; }
1145
+ .tags-list li a { color:#1b2d3b; }
1146
+
1147
+ /* Advanced Search */
1148
+ .advanced-search .form-list label { width:160px; padding-right:10px; }
1149
+ .advanced-search .form-list .input-box,
1150
+ .advanced-search .form-list .input-range { float:left; clear:none; }
1151
+ .advanced-search-amount { margin:0 0 10px; }
1152
+ .advanced-search-summary { margin:10px 0; border:1px solid #e9d7c9; background:#fff6f1; padding:10px; }
1153
+ .advanced-search-summary ul { float:left; width:49%; }
1154
+ .advanced-search-summary strong { color:#E17C24; padding-left:15px; background:url(../images/i_search_criteria.gif) 0 3px no-repeat; }
1155
+ .advanced-search-summary p { clear:both; font-weight:bold; margin:0; }
1156
+
1157
+ /* CMS Home Page */
1158
+ .cms-home .subtitle {}
1159
+ .cms-index-index .subtitle {}
1160
+
1161
+ /* Sitemap */
1162
+ .page-sitemap .links { text-align:right; margin:0 8px -22px 0; }
1163
+ .page-sitemap .links a { text-decoration:none; position:relative; }
1164
+ .page-sitemap .links a:hover { text-decoration:underline; }
1165
+ .page-sitemap .sitemap { margin:12px; }
1166
+ .page-sitemap .sitemap a { color:#1b2d3b; }
1167
+ .page-sitemap .sitemap li { margin:3px 0; }
1168
+ .page-sitemap .sitemap li.level-0 { margin:10px 0 0; font-weight:bold; }
1169
+ .page-sitemap .sitemap li.level-0 a { color:#1e7ec8; }
1170
+
1171
+ /* RSS */
1172
+ .rss-title h1 { background:url(../images/i_rss-big.png) 0 4px no-repeat; padding-left:27px; }
1173
+ .rss-table .link-rss { display:block; line-height:1.55; background-position:0 4px; }
1174
+ /* ======================================================================================= */
1175
+
1176
+
1177
+ /* Shopping Cart ========================================================================= */
1178
+ .cart .page-title { border-bottom:0; margin:0 0 12px; }
1179
+ .cart .page-title h1 { margin:10px 0 0; }
1180
+
1181
+ /* Checkout Types */
1182
+ .cart .page-title .checkout-types li { margin:0 0 5px; }
1183
+ .cart .title-buttons .checkout-types { float:right; }
1184
+ .cart .title-buttons .checkout-types li { float:left; margin:0 0 5px 5px; }
1185
+ .cart .checkout-types .paypal-or { margin:0 8px; line-height:2.3; }
1186
+ .cart .totals .checkout-types .paypal-or { clear:both; display:block; padding:8px 55px 0 0; line-height:1.0; font-size:11px; }
1187
+
1188
+ /* Shopping Cart Table */
1189
+ .cart-table th { padding:2px 10px; }
1190
+ .cart-table td { padding:10px; }
1191
+ .cart-table .product-name { font-weight:bold; margin:0 0 5px; color:#2f2f2f; }
1192
+ .cart-table .item-msg { margin:5px 0; font-size:11px; font-weight:bold; color:#df280a; }
1193
+ .cart-table tfoot td { padding:5px 10px; }
1194
+ .cart-table .btn-continue { float:left; }
1195
+ .cart-table .btn-empty span,
1196
+ .cart-table .btn-continue span,
1197
+ .cart-table .btn-update span { border-color:#406a83; background:#618499; }
1198
+ .cart-table .btn-update,
1199
+ .cart-table .btn-empty { float:right; }
1200
+ .cart-table .btn-update { margin-left:10px; }
1201
+
1202
+ /* Shopping Cart Collateral boxes */
1203
+ .cart .cart-collaterals { padding:25px 0 0; }
1204
+ .cart .cart-collaterals .col2-set { float:left; width:605px; }
1205
+ .cart .cart-collaterals .col2-set .col-2 { width:294px; }
1206
+
1207
+ .cart .crosssell { border:1px solid #cec3b6; background:#fafaec; padding:12px 15px; }
1208
+ .cart .crosssell h2 { font-size:13px; font-weight:bold; }
1209
+ .cart .crosssell .product-image { float:left; width:75px; height:75px; border:1px solid #d0cdc9; }
1210
+ .cart .crosssell .product-details { margin-left:90px; }
1211
+ .cart .crosssell .product-name { font-weight:bold; }
1212
+ .cart .crosssell li.item { margin:12px 0; }
1213
+ .cart .crosssell .link-compare { font-weight:normal; }
1214
+
1215
+ /* Discount Codes & Estimate Shipping and Tax Boxes */
1216
+ .cart .discount,
1217
+ .cart .shipping { border:1px solid #d0cbc1; background:#fff url(../images/bkg_block-title.gif) 0 0 repeat-x; padding:12px 15px; margin:0 0 18px; }
1218
+ .cart .discount h2,
1219
+ .cart .shipping h2 { background-position:0 0; background-repeat:no-repeat; font:bold 13px/16px Arial, Helvetica, sans-serif; padding:0 0 0 21px; color:#e26703; text-transform:uppercase; }
1220
+ .cart .discount button span,
1221
+ .cart .shipping button span { border-color:#406a83; background:#618499; }
1222
+ .cart .discount .buttons-set,
1223
+ .cart .shipping .buttons-set { margin:10px 0 0; border:0; padding:0; text-align:left; }
1224
+ .cart .discount .buttons-set button.button,
1225
+ .cart .shipping .buttons-set button.button { float:none; margin-left:0; }
1226
+
1227
+ .cart .discount h2 { background-image:url(../images/i_discount.gif); }
1228
+ .cart .discount .input-box { margin:8px 0 0; width:260px; }
1229
+ .cart .discount input.input-text { width:254px; }
1230
+
1231
+ .cart .shipping h2 { background-image:url(../images/i_shipping.gif); }
1232
+ .cart .shipping .sp-methods { margin:10px 0 0; padding:5px 0 0; background:url(../images/bkg_divider1.gif) 0 0 repeat-x; }
1233
+
1234
+ /* Shopping Cart Totals */
1235
+ .cart .totals { float:right; width:268px; background:#dee5e8; border:1px solid #bebcb7; }
1236
+ .cart .totals table { width:100%; margin:7px 0; }
1237
+ .cart .totals td { padding:1px 15px 1px 7px; }
1238
+ .cart .totals tr.last td {}
1239
+ .cart .totals tfoot th { padding:5px 15px 5px 7px; }
1240
+ .cart .totals tfoot td { padding-top:5px; padding-bottom:5px; }
1241
+ .cart .totals tfoot th strong,
1242
+ .cart .totals tfoot td strong { font-size:15px; }
1243
+ .cart .totals .checkout-types { font-size:13px; padding:8px 15px 15px; text-align:right; }
1244
+ .cart .totals .checkout-types li { clear:both; margin:10px 0; }
1245
+
1246
+ /* Options Tool Tip */
1247
+ .item-options dt { font-weight:bold; font-style:italic; }
1248
+ .item-options dd { padding-left:10px; margin:0 0 6px; }
1249
+ .truncated { cursor:help; }
1250
+ .truncated a.dots { cursor:help; }
1251
+ .truncated a.details { cursor:help; }
1252
+ .truncated .truncated_full_value { position:relative; z-index:999; }
1253
+ .truncated .truncated_full_value .item-options { position:absolute; top:-99999em; left:-99999em; z-index:999; width:250px; padding:8px; border:1px solid #ddd; background-color:#f6f6f6; }
1254
+ .truncated .truncated_full_value .item-options > p { font-weight:bold; text-transform:uppercase; }
1255
+ .truncated .show .item-options { top:-20px; left:50%; }
1256
+ .col-left .truncated .show .item-options { left:15px; top:7px; }
1257
+ .col-right .truncated .show .item-options { left:-240px; top:7px; }
1258
+ /* ======================================================================================= */
1259
+
1260
+
1261
+ /* Checkout ============================================================================== */
1262
+ /********** < Common Checkout Styles */
1263
+ /* Shipping and Payment methods */
1264
+ .sp-methods { margin:0 0 8px; }
1265
+ .sp-methods dt { margin:13px 0 5px; font-weight:bold; }
1266
+ .sp-methods dd {}
1267
+ .sp-methods dd li { margin:5px 0; }
1268
+ .sp-methods label { font-weight:bold; color:#666; }
1269
+ .sp-methods .price { font-weight:bold; }
1270
+ .sp-methods .form-list { padding-left:20px; }
1271
+ .sp-methods .form-list li { margin:0 0 8px; }
1272
+ .sp-methods select.month { width:154px; margin-right:10px; }
1273
+ .sp-methods select.year { width:96px; }
1274
+ .sp-methods input.cvv { width:3em !important; }
1275
+
1276
+ .sp-methods .checkmo-list li { margin:0 0 5px; }
1277
+ .sp-methods .checkmo-list label { width:135px; padding-right:10px; text-align:right; }
1278
+ .sp-methods .checkmo-list address { float:left; }
1279
+
1280
+ .sp-methods .centinel-logos a { margin-right:3px; }
1281
+ .sp-methods .centinel-logos img { vertical-align:middle; }
1282
+
1283
+ .sp-methods .release-amounts { margin:0.5em 0; }
1284
+ .sp-methods .release-amounts button { float:left; margin:5px 10px 0 0; }
1285
+
1286
+ .please-wait { float:right; }
1287
+ .please-wait img { vertical-align:middle; }
1288
+ .cvv-what-is-this { font-size:11px; cursor:help; margin-left:10px; }
1289
+
1290
+ /* Tooltip */
1291
+ .tool-tip { border:1px solid #7BA7C9; background:#EAF6FF; padding:15px 20px; position:absolute; z-index:9999; }
1292
+ .tool-tip .btn-close { margin:-9px -14px 0; text-align:right; }
1293
+ .tool-tip .btn-close a { display:block; margin:0 0 0 auto; width:15px; height:15px; background:url(../images/btn_window_close.gif) 100% 0 no-repeat; text-align:left; text-indent:-999em; overflow:hidden; }
1294
+ .tool-tip .tool-tip-content { padding:5px; }
1295
+
1296
+ /* Gift Messages */
1297
+ .gift-messages h3 { font-size:12px; font-weight:bold; color:#e87403; }
1298
+ .gift-messages p.control { color:#8e8d8b; }
1299
+ .gift-messages-form { position:relative; }
1300
+ .gift-messages-form label { float:none !important; position:static !important; }
1301
+ .gift-messages-form h4 { font-size:12px; font-weight:bold; color:#e87403; }
1302
+ .gift-messages-form .whole-order { margin:0 0 25px; }
1303
+ .gift-messages-form .item { margin:0 0 10px; }
1304
+ .gift-messages-form .item .product-img-box { float:left; width:75px; }
1305
+ .gift-messages-form .item .product-image { margin:0 0 7px; }
1306
+ .gift-messages-form .item .number { margin:0; font-weight:bold; text-align:center; color:#8a8987; }
1307
+ .gift-messages-form .item .details { margin-left:90px; }
1308
+ .gift-messages-form .item .details .product-name { font-size:13px; font-weight:bold; margin:0 0 10px; }
1309
+ .gift-messages-form .item .details .form-list .field { width:255px; }
1310
+ .gift-messages-form .item .details .form-list .input-box { width:240px; }
1311
+ .gift-messages-form .item .details .form-list input.input-text { width:234px; }
1312
+ .gift-messages-form .item .details .form-list li.wide .input-box { width:500px; }
1313
+ .gift-messages-form .item .details .form-list li.wide textarea { width:494px; }
1314
+
1315
+ .gift-message-link { font-size:11px; background:url(../images/bkg_collapse-gm.gif) 100% 6px no-repeat; padding-right:7px; }
1316
+ .gift-message-link.expanded { background-position:100% -40px; }
1317
+ .gift-message-row { background:#f2efe9; }
1318
+ .gift-message-row .btn-close { float:right; width:16px; height:16px; background:url(../images/btn_gm-close.gif) 0 0 no-repeat; font-size:0; line-height:0; text-indent:-999em; overflow:hidden; }
1319
+
1320
+ /* Checkout Agreements */
1321
+ .checkout-agreements li { margin:30px 0; }
1322
+ .checkout-agreements .agreement-content { overflow:auto; height:12em; padding:10px; background-color:#fbfaf6; border:1px solid #bbb6a5; }
1323
+ .checkout-agreements .agree { margin:0; padding:10px 0 10px 11px; }
1324
+ .checkout-agreements .agree input.checkbox { margin-right:6px; }
1325
+ .checkout-agreements .agree label { font-weight:bold; color:#666; }
1326
+
1327
+ .opc .checkout-agreements { border:1px solid #d9dde3; border-width:0 1px; padding:5px 30px; }
1328
+ .opc .checkout-agreements li { margin:20px 0 0; }
1329
+ .opc .checkout-agreements .agreement-content { background-color:#fff; border-color:#e4e4e4; padding:5px; }
1330
+ .opc .checkout-agreements .agree { padding-left:6px; }
1331
+
1332
+ /* Centinel */
1333
+ .centinel {}
1334
+ .centinel .authentication { border:1px solid #ddd; background:#fff; }
1335
+ .centinel .authentication iframe { width:99%; height:400px; background:transparent !important; margin:0 !important; padding:0 !important; border:0 !important; }
1336
+
1337
+ .opc .centinel { border:1px solid #bbb6a5; border-width:0 1px 1px; padding:10px 30px; }
1338
+
1339
+ /* Generic Info Set */
1340
+ .info-set { background:#fbfaf6 url(../images/bkg_checkout.gif) 0 0 repeat-x; border:1px solid #bbb6a5; margin:0 0 25px; padding:20px; }
1341
+ .info-set h2 { font-size:13px; font-weight:bold; margin:0 0 10px; }
1342
+ .info-set h3,
1343
+ .info-set h4 { font-size:13px; font-weight:bold; color:#E26703; }
1344
+ .info-set h2 a,
1345
+ .info-set h3 a,
1346
+ .info-set h4 a { font-weight:normal; }
1347
+ .info-set h2.legend { margin:-20px -20px 15px; padding:5px 10px; background:#f9f3e3; border-bottom:1px solid #bbafa0; position:relative; }
1348
+ .info-set h3.legend { margin:0 0 10px; color:#0a263c; }
1349
+ .info-set .divider { margin:0 -20px; padding:25px 0; position:relative; }
1350
+ .info-set .box { margin:0 0 15px; }
1351
+ .info-set .box h2 { color:#e26703; }
1352
+ .info-set .data-table .product-name { font-size:1em !important; font-weight:bold !important; color:#1e7ec8 !important; }
1353
+ .info-set .data-table .product-name a { font-weight:bold !important; }
1354
+ .info-set .data-table .item-options { margin:5px 0 0; }
1355
+ /********** Common Checkout Styles > */
1356
+
1357
+ /* One Page Checkout */
1358
+ .block-progress { border:0; margin:0; }
1359
+ .block-progress .block-title { background:none; border:0; padding:0; margin:0 0 5px; }
1360
+ .block-progress .block-title strong { font-size:13px; color:#0a263c; }
1361
+ .block-progress .block-content { background:none; }
1362
+ .block-progress dt { font-size:13px; font-weight:bold; line-height:1.35; background:#eee; border:1px solid #a3aeb3; margin:0 0 6px; padding:2px 8px; color:#999; }
1363
+ .block-progress dd { background:#eee; border:1px solid #a3aeb3; border-top:0; padding:8px 13px; margin:0 0 6px; }
1364
+ .block-progress dt.complete { margin:0; background:#d0dce1; color:#5e8ab4; }
1365
+ .block-progress dd.complete {}
1366
+ .block-progress p { margin:0; }
1367
+ .block-progress .cards-list dt { background:none; border:0 none; color:inherit; font-size:12px; margin:5px 0; padding:0; }
1368
+ .block-progress .cards-list dd { border:0 none; margin:0; padding:0; }
1369
+ .block-progress .cards-list .info-table th { font-weight:normal; }
1370
+
1371
+ .opc .buttons-set { margin-top:0; padding-top:2em; }
1372
+ .opc .buttons-set p.required { margin:0; padding:0 0 10px; }
1373
+ .opc .buttons-set .back-link small { display:none; }
1374
+ .opc .buttons-set .back-link a { background:url(../images/i_arrow-top.gif) 0 50% no-repeat; padding-left:16px; }
1375
+ .opc .buttons-set.disabled button.button { display:none; }
1376
+ .opc .buttons-set .please-wait { height:21px; line-height:21px; }
1377
+ .opc .ul { list-style:disc outside; padding-left:18px; }
1378
+
1379
+ .opc { position:relative; }
1380
+ .opc li.section {}
1381
+
1382
+ .opc .step-title { border-width:0 1px; border-style:solid; border-color:#fff #d9dde3 #d9dde3; background:#eee url(../images/bkg_opc-title-off.gif) 0 100% repeat-x; padding:4px 8px 6px; text-align:right; }
1383
+ .opc .step-title .number { float:left; background:#fff; border:1px solid #fff; padding:0 4px; margin:0 5px 0 0; font:bold 11px/14px arial, helvetica, sans-serif; color:#999; }
1384
+ .opc .step-title h2 { float:left; margin:0; font:bold 13px/16px Arial, Helvetica, sans-serif; color:#999; }
1385
+ .opc .step-title a { display:none; float:right; font-size:11px; line-height:16px; }
1386
+
1387
+ .opc .allow .step-title { background:#d0dce1; border:1px solid #a3aeb3; border-bottom:0; color:#a4b3b9; cursor:pointer; }
1388
+ .opc .allow .step-title .number { background:#dbe6eb; border-color:#dbe6eb; color:#a4b3b9; }
1389
+ .opc .allow .step-title h2 { color:#a4b3b9; }
1390
+ /*.opc .allow .step-title a { display:block; }*/
1391
+
1392
+ .opc .active .step-title { background:#f9f3e3; border:1px solid #bbafa0; padding-bottom:5px; color:#f18200; cursor:default; }
1393
+ .opc .active .step-title .number { background:#f18200; border-color:#f19900; color:#fff; }
1394
+ .opc .active .step-title h2 { color:#f18200; }
1395
+ /*.opc .active .step-title a { display:none; }*/
1396
+
1397
+ .opc .step { border:1px solid #bbafa0; border-top:0; background:#fbfaf6 url(../images/bkg_checkout.gif) 0 0 repeat-x; padding:15px 30px; position:relative; }
1398
+ .opc .step .tool-tip { right:30px; }
1399
+
1400
+ #opc-login .buttons-set { border-top:0; }
1401
+ #opc-login h3 { font-size:13px; border-bottom:1px solid #e4e4e4; padding-bottom:2px; text-transform:uppercase; }
1402
+ #opc-login h4 { font-size:1em; font-weight:bold; margin:0; color:#2f2f2f; }
1403
+
1404
+ #opc-shipping_method .buttons-set { border-top:0; }
1405
+ .opc .gift-messages-form { margin:0 -30px; background:#f6f1eb; border:1px solid #e9e4de; border-width:1px 0; padding:22px 24px 22px 30px; }
1406
+ .opc .gift-messages-form .inner-box { padding:5px; height:260px; overflow:auto; }
1407
+
1408
+ #opc-review .step { border:0; padding:0; }
1409
+ #opc-review .product-name { font-weight:bold; color:#0a263c; }
1410
+ #opc-review .item-options { margin:5px 0 0; }
1411
+ #opc-review .buttons-set { padding:20px 30px; border:1px solid #d9dde3; border-width:0 1px 1px; }
1412
+ #opc-review .buttons-set p { margin:0; line-height:40px; }
1413
+ #opc-review .buttons-set .please-wait { height:40px; line-height:40px; }
1414
+ #opc-review .authentication { margin:0 auto; width:570px; }
1415
+ #opc-review .warning-message { color:#222; font-weight:bold; text-align:center; padding:10px 10px 0; }
1416
+
1417
+ /* Multiple Addresses Checkout */
1418
+ .checkout-progress { padding:0 90px; margin:0 0 20px; }
1419
+ .checkout-progress li { float:left; width:19%; margin:0 3px 0 0; border-top:10px solid #999; padding:2px 0 0; font-weight:bold; text-align:center; color:#abb5ba; }
1420
+ .checkout-progress li.active { border-top-color:#e96200; color:#e96200; }
1421
+
1422
+ .multiple-checkout h2 { font-size:13px; font-weight:bold; margin:0 0 10px; }
1423
+ .multiple-checkout h3,
1424
+ .multiple-checkout h4 { font-size:13px; font-weight:bold; color:#E26703; }
1425
+ .multiple-checkout h2 a,
1426
+ .multiple-checkout h3 a,
1427
+ .multiple-checkout h4 a { font-weight:normal; }
1428
+ .multiple-checkout .data-table .product-name { font-size:1em !important; font-weight:bold !important; color:#1e7ec8 !important; }
1429
+ .multiple-checkout .data-table .product-name a { font-weight:bold !important; }
1430
+ .multiple-checkout .data-table .item-options { margin:5px 0 0; }
1431
+
1432
+ .multiple-checkout .gift-messages { margin:15px 0 0; }
1433
+
1434
+ .multiple-checkout .tool-tip { top:50%; margin-top:-120px; right:20px; }
1435
+
1436
+ .multiple-checkout .col2-set,
1437
+ .multiple-checkout .col3-set { background:#fbfaf6 url(../images/bkg_checkout.gif) 0 0 repeat-x; border:1px solid #bbb6a5; margin:0 0 25px; padding:20px; }
1438
+ .multiple-checkout .col2-set h2.legend { margin:-20px -20px 15px; padding:5px 10px; background:#f9f3e3; border-bottom:1px solid #bbafa0; position:relative; }
1439
+ .multiple-checkout .col2-set h3.legend { margin:0 0 10px; color:#0a263c; }
1440
+ .multiple-checkout .col2-set .divider { margin:0 -20px; padding:25px 0; position:relative; }
1441
+ .multiple-checkout .box { margin:0 0 15px; }
1442
+ .multiple-checkout .box h2 { color:#e26703; }
1443
+
1444
+ .multiple-checkout .place-order .please-wait { float:right; padding:27px 7px 0 0; }
1445
+ .multiple-checkout .place-order .grand-total { float:right; height:71px; font-size:1.5em; padding:0 0 0 21px; background:url(../images/bkg_grand-total.gif) 0 0 no-repeat; overflow:hidden; }
1446
+ .multiple-checkout .place-order .grand-total .inner { float:left; height:57px; padding:14px 21px 0 0; background:url(../images/bkg_grand-total.gif) 100% 0 no-repeat; }
1447
+ .multiple-checkout .place-order .grand-total .inner div { display:inline; }
1448
+ .multiple-checkout .place-order .grand-total big { display:inline; margin-right:12px; }
1449
+ .multiple-checkout .place-order .grand-total .price { color:#E26703; }
1450
+ .multiple-checkout .place-order .grand-total button.button span { font-size:16px; }
1451
+ .multiple-checkout .place-order .grand-total button.button span span { padding:0 45px 0 36px; }
1452
+
1453
+ /* Step 1 */
1454
+ .multiple-checkout .title-buttons button.button span { border-color:#406a83; background:#618499; }
1455
+ #multiship-addresses-table td { padding:10px; }
1456
+ #multiship-addresses-table tfoot td { padding:5px 10px; }
1457
+ #multiship-addresses-table tfoot button.button span { border-color:#406a83; background:#618499; }
1458
+
1459
+ /* Step 2 */
1460
+ .multiple-checkout .gift-messages-form .item .details .form-list { width:100%; overflow:hidden; }
1461
+ .multiple-checkout .gift-messages-form .item .details .form-list li { margin-right:-15px; }
1462
+ .multiple-checkout .gift-messages-form .item .details .form-list .field { width:230px; }
1463
+ .multiple-checkout .gift-messages-form .item .details .form-list .input-box { width:215px; }
1464
+ .multiple-checkout .gift-messages-form .item .details .form-list input.input-text { width:209px; }
1465
+ .multiple-checkout .gift-messages-form .item .details .form-list li.wide .input-box { width:445px; }
1466
+ .multiple-checkout .gift-messages-form .item .details .form-list li.wide textarea { width:439px; }
1467
+ .checkout-multishipping-shipping .box-sp-methods { border:1px solid #d9d2be; background:#f9f3e3; padding:13px; position:relative; }
1468
+ .checkout-multishipping-shipping .box-sp-methods .pointer { position:absolute; top:-20px; right:-40px; width:178px; height:41px; background:url(../images/bkg_sp-methods.gif) 0 0 no-repeat; overflow:hidden; }
1469
+
1470
+ /* Step 3 */
1471
+ .checkout-multishipping-billing .multiple-checkout { position:relative; }
1472
+ /* ======================================================================================= */
1473
+
1474
+
1475
+ /* Account Login/Create Pages ============================================================ */
1476
+ .account-login .content { min-height:345px; padding:14px 21px; background:#faf7ee url(../images/bkg_login-box.gif) 0 0 repeat-x; border:1px solid #bbb6a5; border-bottom:0; }
1477
+ .account-login .content h2 { font-weight:bold; font-size:13px; margin:0 0 14px; padding:0 0 5px 23px; border-bottom:1px solid #ddd; background-position:0 1px; background-repeat:no-repeat; text-transform:uppercase; color:#e76200; }
1478
+ .account-login .new-users h2 { background-image:url(../images/i_page1.gif)}
1479
+ .account-login .registered-users h2 { background-image:url(../images/i_page2.gif); }
1480
+ .account-login .buttons-set { border:1px solid #bbb6a5; border-top:0; margin:0; padding:8px 13px; background:#dee5e8 url(../images/bkg_buttons-set1.gif) 0 0 repeat-x; }
1481
+
1482
+ .account-create {}
1483
+
1484
+ /* Captcha ================================================================================ */
1485
+ .captcha-note { clear:left; padding-top:5px; }
1486
+ .captcha-image { float:left; display:inline; margin:0; position:relative; width:258px; }
1487
+ .captcha-image .captcha-img { border:1px solid #b6b6b6; vertical-align:bottom; width:100%; }
1488
+ .registered-users .captcha-image { margin:0;}
1489
+ .captcha-reload { cursor:pointer; position:absolute; top:2px; right:2px;}
1490
+ .captcha-reload.refreshing { animation:rotate 1.5s infinite linear; -webkit-animation:rotate 1.5s infinite linear; -moz-animation:rotate 1.5s infinite linear; }
1491
+
1492
+ @-webkit-keyframes rotate {
1493
+ 0% { -webkit-transform:rotate(0); }
1494
+ 0% { -webkit-transform:rotate(-360deg); }
1495
+ }
1496
+ @-moz-keyframes rotate {
1497
+ 0% { -moz-transform:rotate(0); }
1498
+ 0% { -moz-transform:rotate(-360deg); }
1499
+ }
1500
+ @keyframes rotate {
1501
+ 0% { transform:rotate(0); }
1502
+ 0% { transform:rotate(-360deg); }
1503
+ }
1504
+
1505
+ /* Remember Me Popup ===================================================================== */
1506
+ .window-overlay { background:url(../images/window_overlay.png) repeat; background:rgba(0, 0, 0, 0.35); position:absolute; top:0; left:0; height:100%; width:100%; z-index:990; }
1507
+
1508
+ .remember-me label { float:none; margin:0 6px; }
1509
+ .remember-me-popup { background:#fff; border:1px solid #ccc; left:50%; top:50%; position:absolute; margin:-85px 0 0 -200px; width:400px; text-align:left; -moz-box-shadow:0 0 6px #ccc; -webkit-box-shadow:0 0 6px #ccc; -box-shadow:0 0 6px #ccc; z-index:1000; }
1510
+ .remember-me-popup h3 { background:#d9e5ee; border-bottom:1px solid #ccc; font-size:14px; padding:5px 10px; }
1511
+ .remember-me-popup .remember-me-popup-head { position:relative; }
1512
+ .remember-me-popup .remember-me-popup-head .remember-me-popup-close { background:url(../images/btn_window_close.gif) no-repeat; display:block; position:absolute; top:7px; right:7px; height:15px; width:15px; text-indent:-9999em; }
1513
+ .remember-me-popup .remember-me-popup-body { padding:10px; }
1514
+ .remember-me-popup .remember-me-popup-body a { display:inline-block; height:19px; border:1px solid #de5400; background:#f18200; padding:0 8px; font:bold 12px/19px Arial, Helvetica, sans-serif; text-align:center; text-decoration:none; white-space:nowrap; color:#fff; }
1515
+ /* Remember Me Popup ===================================================================== */
1516
+
1517
+
1518
+ /* My Account ============================================================================= */
1519
+ .my-account .title-buttons .link-rss { float:none; margin:0; }
1520
+
1521
+ /********** < Dashboard */
1522
+ .dashboard .welcome-msg { margin:0 8em 1.5em 0; }
1523
+ .dashboard .welcome-msg p { margin:0; }
1524
+ .dashboard .col2-set { margin:0 0 15px; }
1525
+
1526
+ /* General Box */
1527
+ .box-account { background:#fff url(../images/bkg_account_box.gif) 0 0 repeat-x; border:1px solid #ccc; border-color:#ccc #999 #999 #ccc; padding:15px; margin: 0 0 20px; }
1528
+ .box-account .box-head { border-bottom:1px solid #d9dde3; margin:0 0 10px; text-align:right; }
1529
+ .box-account .box-head h2 { float:left; margin:0; font-size:13px; font-weight:bold; text-transform:uppercase; background-position:0 0; background-repeat:no-repeat; padding-left:21px; color:#e65505; }
1530
+
1531
+ .dashboard .box .box-title { background:url(../images/bkg_divider1.gif) 0 100% repeat-x; padding:0 0 2px; margin:0 0 8px; text-align:right; }
1532
+ .dashboard .box .box-title h3,
1533
+ .dashboard .box .box-title h4 { float:left; font-size:13px; font-weight:bold; margin:0; }
1534
+
1535
+ /* Block: Recent Orders */
1536
+ .dashboard .box-recent .box-head h2 { background-image:url(../images/i_folder-table.gif); }
1537
+
1538
+ /* Block: Account Information */
1539
+ .dashboard .box-info .box-head h2 { background-image:url(../images/i_ma-info.gif); }
1540
+ .dashboard .box-info h4 { font-size:11px; font-weight:bold; text-transform:uppercase; }
1541
+
1542
+ /* Block: Reviews */
1543
+ .dashboard .box-reviews .box-head h2 { background-image:url(../images/i_ma-reviews.gif); }
1544
+ .dashboard .box-reviews .number { float:left; font-size:10px; font-weight:bold; line-height:1; color:#fff; margin:3px -20px 0 0; padding:2px 3px; background:#0a263c; }
1545
+ .dashboard .box-reviews .details { margin-left:20px; }
1546
+ .dashboard .box-reviews li.item { margin:0 0 7px; }
1547
+ .dashboard .box-reviews li.item.last { margin:0; }
1548
+ .dashboard .box-reviews .ratings { margin:7px 0 0; }
1549
+
1550
+ /* Block: Tags */
1551
+ .dashboard .box-tags .box-head h2 { background-image:url(../images/i_ma-tags.gif); }
1552
+ .dashboard .box-tags .number { float:left; font-size:10px; font-weight:bold; line-height:1; color:#fff; margin:3px -20px 0 0; padding:2px 3px; background:#0a263c; }
1553
+ .dashboard .box-tags .details { margin-left:20px; }
1554
+ .dashboard .box-tags li.item { margin:0 0 7px; }
1555
+ .dashboard .box-tags li.item.last { margin:0; }
1556
+ .dashboard .box-tags .tags strong,
1557
+ .dashboard .box-tags .tags ul,
1558
+ .dashboard .box-tags .tags ul li { display:inline; }
1559
+ /********** Dashboard > */
1560
+
1561
+ /* Address Book */
1562
+ .addresses-list h2 { font-weight:bold; font-size:13px; color:#e26703; text-transform:uppercase; }
1563
+ .addresses-list h3 { font-weight:bold; font-size:13px; }
1564
+ .addresses-list address { margin:0 0 3px; }
1565
+ .addresses-list p { margin:0; }
1566
+ .addresses-list a { font-weight:bold; }
1567
+ .addresses-list .link-remove { color:#646464; }
1568
+ .addresses-list .separator { margin:0 3px; }
1569
+ .addresses-list li.item { background:#fff url(../images/bkg_account_box.gif) 0 0 repeat-x; border:1px solid #ccc; padding:10px 13px; margin:0 0 10px; }
1570
+ .addresses-list li.empty { background:none; border:0; padding:0; }
1571
+ .addresses-list li.empty p { font-weight:bold; }
1572
+ .addresses-list .addresses-additional li.item { background:none; border:0; padding:0; }
1573
+
1574
+ /* Order View */
1575
+ .order-info { background:#dee5e8; border:1px solid #d0cbc1; padding:4px 8px; margin:0 0 8px; }
1576
+ .order-info dt,
1577
+ .order-info dd,
1578
+ .order-info ul,
1579
+ .order-info li { display:inline; }
1580
+ .order-info .current { font-weight:bold; }
1581
+ .order-info li { margin:0 3px; }
1582
+
1583
+ .order-date { margin:10px 0; }
1584
+
1585
+ .order-info-box { background:#fff url(../images/bkg_block-title.gif) 0 0 repeat-x; border:1px solid #d0cbc1; padding:12px 15px; margin:0 0 15px; }
1586
+ .order-info-box h2 { font-weight:bold; font-size:13px; }
1587
+ .order-info-box .box-payment p { margin:0 0 3px; }
1588
+ .order-info-box .box-payment th { font-weight:bold; padding-right:7px; }
1589
+
1590
+ .order-items { width:100%; overflow-x:auto; }
1591
+ .order-items h2,
1592
+ .order-items h3 { clear:none; font-weight:bold; font-size:13px; padding:0; margin:0 0 5px; color:#0a263c; }
1593
+ .order-items .product-name { font-size:1em !important; font-weight:bold !important; }
1594
+ .order-items .link-print { color:#1e7ec8; font-weight:normal; }
1595
+ .order-items .order-links { text-align:right; }
1596
+
1597
+ .order-additional { margin:15px 0; }
1598
+ /* Order Gift Message */
1599
+ .gift-message dt strong { color:#666; }
1600
+ .gift-message dd { font-size:13px; margin:5px 0 0; }
1601
+ /* Order Comments */
1602
+ .order-about dt { font-weight:bold; }
1603
+ .order-about dd { font-size:13px; margin:0 0 7px; }
1604
+
1605
+ .tracking-table { margin:0 0 15px; }
1606
+ .tracking-table th { font-weight:bold; white-space:nowrap; }
1607
+
1608
+ .tracking-table-popup { width:100%; }
1609
+ .tracking-table-popup th { font-weight:bold; white-space:nowrap; }
1610
+ .tracking-table-popup th,
1611
+ .tracking-table-popup td { padding:1px 8px; }
1612
+
1613
+ /* Order Print Pages */
1614
+ .page-print .print-head { margin:0 0 15px; }
1615
+ .page-print .print-head .logo { float:left; }
1616
+ .page-print .print-head address { float:left; margin-left:15px; }
1617
+ .page-print h1 { font-size:16px; font-weight:bold; }
1618
+ .page-print h2,
1619
+ .page-print h3 { font-size:13px; font-weight:bold; }
1620
+ .page-print h2.h2 { font-size:16px; font-weight:bold; }
1621
+ .page-print .order-date { background:url(../images/bkg_divider1.gif) 0 100% repeat-x; padding:0 0 10px; margin:0 0 10px; }
1622
+ .page-print .col2-set { margin:0 0 10px; }
1623
+ /* Price Rewrites */
1624
+ .page-print .gift-message-link { display:none; }
1625
+ .page-print .price-excl-tax,
1626
+ .page-print .price-incl-tax { display:block; white-space:nowrap; }
1627
+ .page-print .cart-price,
1628
+ .page-print .price-excl-tax .label,
1629
+ .page-print .price-incl-tax .label,
1630
+ .page-print .price-excl-tax .price,
1631
+ .page-print .price-incl-tax .price { display:inline; }
1632
+
1633
+ /* My Wishlist */
1634
+ .my-wishlist .data-table td { padding:10px; }
1635
+ .my-wishlist .product-image { display:block; width:113px; height:113px; margin:0 0 5px; }
1636
+ .my-wishlist textarea { display:block; width:97%; height:109px; }
1637
+ .my-wishlist .buttons-set { margin-top:2em; }
1638
+ .my-wishlist .buttons-set button.button { float:none; }
1639
+ .my-wishlist .buttons-set .btn-add span,
1640
+ .my-wishlist .buttons-set .btn-share span { border-color:#406a83; background:#618499; }
1641
+ #wishlist-table .add-to-links { white-space:nowrap; }
1642
+
1643
+ /* My Tags */
1644
+ .my-tag-edit { float:left; margin:0 0 10px; }
1645
+ .my-tag-edit .btn-remove { float:right; margin:4px 0 0 5px; }
1646
+ #my-tags-table { clear:both; }
1647
+ #my-tags-table td { padding:10px; }
1648
+ #my-tags-table .add-to-links { white-space:nowrap; }
1649
+
1650
+ /* My Reviews */
1651
+ #my-reviews-table td { padding:10px; }
1652
+
1653
+ .product-review .product-img-box { float:left; width:140px; }
1654
+ .product-review .product-img-box .product-image { display:block; width:125px; height:125px; }
1655
+ .product-review .product-img-box .label { font-size:11px; margin:0 0 3px; }
1656
+ .product-review .product-img-box .ratings .rating-box { float:none; display:block; margin:0 0 3px; }
1657
+ .product-review .product-details { margin-left:150px; }
1658
+ .product-review .product-name { font-size:16px; font-weight:bold; margin:0 0 10px; }
1659
+ .product-review h3 { font-size:12px; margin:0 0 3px; color:#2f2f2f; }
1660
+ .product-review .ratings-table { margin:0 0 10px; }
1661
+ .product-review dt { font-weight:bold; }
1662
+ .product-review dd { font-size:13px; margin:5px 0 0; }
1663
+
1664
+ /* Billing Agreements */
1665
+ .billing-agreements .info-box{ margin:15px 0; }
1666
+ .billing-agreements .form-list li select { float:left; }
1667
+ .billing-agreements .form-list li button.button { float:left; margin-left:10px; }
1668
+ .billing-agreements .table-caption { font-weight:bold; font-size:13px; }
1669
+ /* ======================================================================================= */
1670
+
1671
+
1672
+ /* MAP Popup============================================================================== */
1673
+ .cart-msrp-totals { color:red; font-size:12px !important; font-weight:bold; margin:10px 10px 0; padding:10px; text-align:right; text-transform:uppercase;}
1674
+ .map-cart-sidebar-total { color:red; display:block; font-size:10px; font-weight:bold; text-align:left; padding:2px 5px; text-shadow:0 1px 0 #fff; }
1675
+
1676
+ .map-popup { background:#fff; border:1px solid #aaa; margin:12px 0 0; position:absolute; -moz-box-shadow:0 0 6px #ccc; -webkit-box-shadow:0 0 6px #ccc; box-shadow:0 0 6px #ccc; text-align:left; width:300px; z-index:100; }
1677
+ .map-popup-heading { background:#d9e5ee; border-bottom:1px solid #ccc; padding:5px 30px 5px 10px; width:260px; }
1678
+ .map-popup-heading h2 { font-size:16px; margin:0; text-shadow:0 1px 0 #f6f6f6; overflow:hidden; white-space:nowrap; word-wrap:break-word; text-align:left; text-overflow:ellipsis; }
1679
+ .map-popup-arrow { background:url(../images/map_popup_arrow.gif) no-repeat; position:absolute; left:50%; top:-10px; height:10px; width:19px; }
1680
+ .map-popup-close { background:url(../images/btn_window_close.gif) no-repeat; display:block; position:absolute; top:8px; right:10px; height:15px; width:15px; text-indent:-9999em; -moz-box-shadow:0 0 3px #999; -webkit-box-shadow:0 0 3px #999; box-shadow:0 0 3px #999; -moz-border-radius:2px; -webkit-border-radius:2px; border-radius:2px; }
1681
+ .map-popup-content { border-top:1px solid #eee; padding:10px; overflow:hidden; text-align:left; width:280px; }
1682
+ .map-popup-checkout { display:inline; float:right; text-align:right; }
1683
+ .map-popup-checkout span { display:block; padding-right:30px; }
1684
+ .map-popup-checkout .paypal-logo { margin:0 0 5px; }
1685
+ .map-popup-price .price-box,
1686
+ .map-popup-price .price-box .special-price { margin:0; padding:0; }
1687
+ .map-popup-price { margin:5px 0 0; }
1688
+ .map-popup-text { clear:right; margin:0 10px; padding:10px 0; text-align:left; word-wrap:break-word; }
1689
+ .map-popup-only-text { border-top:1px solid #ddd; }
1690
+ /* ======================================================================================= */
1691
+
1692
+
1693
+ /* Footer ================================================================================ */
1694
+ .footer-container { border-top:15px solid #b6d1e2; }
1695
+ .footer { width:930px; margin:0 auto; padding:10px 10px 50px; }
1696
+ .footer .store-switcher { display:inline; margin:0 5px 0 0; color:#fff; }
1697
+ .footer .store-switcher label { font-weight:bold; vertical-align:middle; }
1698
+ .footer .store-switcher select { padding:0; vertical-align:middle; }
1699
+ .footer a { color:#fff; text-decoration:none; }
1700
+ .footer a:hover { text-decoration:underline; }
1701
+ .footer .bugs { margin:13px 0 0; color:#ecf3f6; }
1702
+ .footer .bugs a { color:#ecf3f6; text-decoration:underline; }
1703
+ .footer .bugs a:hover { text-decoration:none; }
1704
+ .footer address { margin:0 0 20px; color:#ecf3f6; }
1705
+ .footer address a { color:#ecf3f6; text-decoration:underline; }
1706
+ .footer address a:hover { text-decoration:none; }
1707
+ .footer ul { display:inline; }
1708
+ .footer ul.links { display:block; }
1709
+ .footer li { display:inline; background:url(../images/bkg_pipe2.gif) 100% 60% no-repeat; padding:0 7px 0 4px; }
1710
+ .footer li.last { background:none !important; padding-right:0 !important; }
1711
+ .footer-container .bottom-container { margin:0 0 5px; }
1712
+ /* ======================================================================================= */
1713
+
1714
+ /* Sample Data============================================================================ */
1715
+ .home-callout { margin-bottom:12px; }
1716
+ .home-callout img { display:block }
1717
+ .home-spot { float:left; width:470px; margin-left:20px; }
1718
+ .best-selling h3 { margin:12px 0 6px 0; color:#e25203; font-size:1.2em; }
1719
+ .best-selling table { border-top:1px solid #ccc; }
1720
+ .best-selling tr.odd { background:#eee url(../images/best_selling_tr_odd_bg.gif) 0 100% repeat-x; }
1721
+ .best-selling tr.even { background:#fff url(../images/best_selling_tr_even_bg.gif) 0 100% repeat-x; }
1722
+ .best-selling td { width:50%; border-bottom:1px solid #ccc; padding:8px 10px 8px 8px; font-size:11px; }
1723
+ .best-selling .product-img { float:left; border:2px solid #dcdcdc; }
1724
+ .best-selling .product-description { margin-left:107px; line-height:1.3em; }
1725
+ .best-selling a.product-name,
1726
+ .home-spot .best-selling a.product-name:hover { color:#203548; }
1727
+ /* ======================================================================================= */
1728
+
1729
+
1730
+ /* Clears ================================================================================ */
1731
+ .clearer:after,
1732
+ .header-container:after,
1733
+ .header-container .top-container:after,
1734
+ .header:after,
1735
+ .header .quick-access:after,
1736
+ #nav:after,
1737
+ .main:after,
1738
+ .footer:after,
1739
+ .footer-container .bottom-container:after,
1740
+ .col-main:after,
1741
+ .col2-set:after,
1742
+ .col3-set:after,
1743
+ .col3-layout .product-options-bottom .price-box:after,
1744
+ .col4-set:after,
1745
+ .search-autocomplete li:after,
1746
+ .block .block-content:after,
1747
+ .block .actions:after,
1748
+ .block li.item:after,
1749
+ .block-poll li:after,
1750
+ .block-layered-nav .currently li:after,
1751
+ .page-title:after,
1752
+ .products-grid:after,
1753
+ .products-list li.item:after,
1754
+ .box-account .box-head:after,
1755
+ .dashboard .box .box-title:after,
1756
+ .box-reviews li.item:after,
1757
+ .box-tags li.item:after,
1758
+ .pager:after,
1759
+ .sorter:after,
1760
+ .ratings:after,
1761
+ .add-to-box:after,
1762
+ .add-to-cart:after,
1763
+ .product-essential:after,
1764
+ .product-collateral:after,
1765
+ .product-view .product-img-box .more-views ul:after,
1766
+ .product-view .box-tags .form-add:after,
1767
+ .product-view .product-shop .short-description:after,
1768
+ .product-view .box-description:after,
1769
+ .product-options .options-list li:after,
1770
+ .product-options-bottom:after,
1771
+ .product-review:after,
1772
+ .cart:after,
1773
+ .cart-collaterals:after,
1774
+ .cart .crosssell li.item:after,
1775
+ .opc .step-title:after,
1776
+ .checkout-progress:after,
1777
+ .multiple-checkout .place-order:after,
1778
+ .group-select li:after,
1779
+ .form-list li:after,
1780
+ .form-list .field:after,
1781
+ .buttons-set:after,
1782
+ .page-print .print-head:after,
1783
+ .advanced-search-summary:after,
1784
+ .gift-messages-form .item:after,
1785
+ .send-friend .form-list li p:after { display:block; content:"."; clear:both; font-size:0; line-height:0; height:0; overflow:hidden; }
1786
+ /* ======================================================================================= */
1787
+
1788
+ .guest-select {width:305px !important;}
skin/frontend/default/customproduct/favicon.ico ADDED
Binary file
skin/frontend/default/customproduct/images/addtext.png ADDED
Binary file
skin/frontend/default/customproduct/images/best_selling_tr_even_bg.gif ADDED
Binary file
skin/frontend/default/customproduct/images/best_selling_tr_odd_bg.gif ADDED
Binary file
skin/frontend/default/customproduct/images/bgimage.png ADDED
Binary file
skin/frontend/default/customproduct/images/bgimage7.png ADDED
Binary file
skin/frontend/default/customproduct/images/bkg_account_box.gif ADDED
Binary file
skin/frontend/default/customproduct/images/bkg_block-actions.gif ADDED
Binary file
skin/frontend/default/customproduct/images/bkg_block-currency.gif ADDED
Binary file
skin/frontend/default/customproduct/images/bkg_block-layered-dd.gif ADDED
Binary file
skin/frontend/default/customproduct/images/bkg_block-layered-dt.gif ADDED
Binary file
skin/frontend/default/customproduct/images/bkg_block-layered-label.gif ADDED
Binary file
skin/frontend/default/customproduct/images/bkg_block-layered-li.gif ADDED
Binary file
skin/frontend/default/customproduct/images/bkg_block-layered-title.gif ADDED
Binary file
skin/frontend/default/customproduct/images/bkg_block-layered1.gif ADDED
Binary file
skin/frontend/default/customproduct/images/bkg_block-title-account.gif ADDED
Binary file
skin/frontend/default/customproduct/images/bkg_block-title.gif ADDED
Binary file
skin/frontend/default/customproduct/images/bkg_body.gif ADDED
Binary file
skin/frontend/default/customproduct/images/bkg_buttons-set1.gif ADDED
Binary file
skin/frontend/default/customproduct/images/bkg_checkout.gif ADDED
Binary file
skin/frontend/default/customproduct/images/bkg_collapse-gm.gif ADDED
Binary file
skin/frontend/default/customproduct/images/bkg_collapse.gif ADDED
Binary file
skin/frontend/default/customproduct/images/bkg_divider1.gif ADDED
Binary file
skin/frontend/default/customproduct/images/bkg_form-search.gif ADDED
Binary file
skin/frontend/default/customproduct/images/bkg_grand-total.gif ADDED
Binary file
skin/frontend/default/customproduct/images/bkg_grid.gif ADDED
Binary file
skin/frontend/default/customproduct/images/bkg_header.jpg ADDED
Binary file
skin/frontend/default/customproduct/images/bkg_login-box.gif ADDED
Binary file
skin/frontend/default/customproduct/images/bkg_main1.gif ADDED
Binary file
skin/frontend/default/customproduct/images/bkg_main2.gif ADDED
Binary file
skin/frontend/default/customproduct/images/bkg_nav0.jpg ADDED
Binary file
skin/frontend/default/customproduct/images/bkg_nav1.gif ADDED
Binary file
skin/frontend/default/customproduct/images/bkg_nav2.gif ADDED
Binary file
skin/frontend/default/customproduct/images/bkg_opc-title-off.gif ADDED
Binary file
skin/frontend/default/customproduct/images/bkg_pipe1.gif ADDED
Binary file
skin/frontend/default/customproduct/images/bkg_pipe2.gif ADDED
Binary file
skin/frontend/default/customproduct/images/bkg_pipe3.gif ADDED
Binary file
skin/frontend/default/customproduct/images/bkg_product-view.gif ADDED
Binary file
skin/frontend/default/customproduct/images/bkg_product_collateral.gif ADDED
Binary file
skin/frontend/default/customproduct/images/bkg_rating.gif ADDED
Binary file
skin/frontend/default/customproduct/images/bkg_sp-methods.gif ADDED
Binary file
skin/frontend/default/customproduct/images/bkg_tfoot.gif ADDED
Binary file
skin/frontend/default/customproduct/images/bkg_th-v.gif ADDED
Binary file
skin/frontend/default/customproduct/images/bkg_th.gif ADDED
Binary file
skin/frontend/default/customproduct/images/bkg_toolbar.gif ADDED
Binary file
skin/frontend/default/customproduct/images/btn_checkout.gif ADDED
Binary file
skin/frontend/default/customproduct/images/btn_edit.gif ADDED
Binary file
skin/frontend/default/customproduct/images/btn_gm-close.gif ADDED
Binary file
skin/frontend/default/customproduct/images/btn_google_checkout.gif ADDED
Binary file
skin/frontend/default/customproduct/images/btn_paypal_checkout.gif ADDED
Binary file
skin/frontend/default/customproduct/images/btn_place_order.gif ADDED
Binary file
skin/frontend/default/customproduct/images/btn_previous.gif ADDED
Binary file
skin/frontend/default/customproduct/images/btn_proceed_to_checkout.gif ADDED
Binary file
skin/frontend/default/customproduct/images/btn_proceed_to_checkout_dis.gif ADDED
Binary file
skin/frontend/default/customproduct/images/btn_remove.gif ADDED
Binary file
skin/frontend/default/customproduct/images/btn_remove2.gif ADDED
Binary file
skin/frontend/default/customproduct/images/btn_search.gif ADDED
Binary file
skin/frontend/default/customproduct/images/btn_trash.gif ADDED
Binary file
skin/frontend/default/customproduct/images/btn_window_close.gif ADDED
Binary file
skin/frontend/default/customproduct/images/button1.png ADDED
Binary file
skin/frontend/default/customproduct/images/button2.png ADDED
Binary file
skin/frontend/default/customproduct/images/button3.png ADDED
Binary file
skin/frontend/default/customproduct/images/calendar.gif ADDED
Binary file
skin/frontend/default/customproduct/images/catalog/product/placeholder/image.jpg ADDED
Binary file
skin/frontend/default/customproduct/images/catalog/product/placeholder/small_image.jpg ADDED
Binary file
skin/frontend/default/customproduct/images/catalog/product/placeholder/thumbnail.jpg ADDED
Binary file
skin/frontend/default/customproduct/images/cvv.gif ADDED
Binary file
skin/frontend/default/customproduct/images/cvv.jpg ADDED
Binary file
skin/frontend/default/customproduct/images/fam_book_open.png ADDED
Binary file
skin/frontend/default/customproduct/images/free_shipping_callout.jpg ADDED
Binary file
skin/frontend/default/customproduct/images/grid-cal.gif ADDED
Binary file
skin/frontend/default/customproduct/images/home_left_callout.jpg ADDED
Binary file
skin/frontend/default/customproduct/images/home_main_callout.jpg ADDED
Binary file
skin/frontend/default/customproduct/images/i_arrow-top.gif ADDED
Binary file
skin/frontend/default/customproduct/images/i_asc_arrow.gif ADDED
Binary file
skin/frontend/default/customproduct/images/i_availability_only.gif ADDED
Binary file
skin/frontend/default/customproduct/images/i_availability_only_arrow.gif ADDED
Binary file
skin/frontend/default/customproduct/images/i_block-cart.gif ADDED
Binary file
skin/frontend/default/customproduct/images/i_block-currency.gif ADDED
Binary file
skin/frontend/default/customproduct/images/i_block-list.gif ADDED
Binary file
skin/frontend/default/customproduct/images/i_block-poll.gif ADDED
Binary file
skin/frontend/default/customproduct/images/i_block-related.gif ADDED
Binary file
skin/frontend/default/customproduct/images/i_block-subscribe.gif ADDED
Binary file
skin/frontend/default/customproduct/images/i_block-tags.gif ADDED
Binary file
skin/frontend/default/customproduct/images/i_block-viewed.gif ADDED
Binary file
skin/frontend/default/customproduct/images/i_block-wishlist.gif ADDED
Binary file
skin/frontend/default/customproduct/images/i_desc_arrow.gif ADDED
Binary file
skin/frontend/default/customproduct/images/i_discount.gif ADDED
Binary file
skin/frontend/default/customproduct/images/i_folder-table.gif ADDED
Binary file
skin/frontend/default/customproduct/images/i_ma-info.gif ADDED
Binary file
skin/frontend/default/customproduct/images/i_ma-reviews.gif ADDED
Binary file
skin/frontend/default/customproduct/images/i_ma-tags.gif ADDED
Binary file
skin/frontend/default/customproduct/images/i_msg-error.gif ADDED
Binary file
skin/frontend/default/customproduct/images/i_msg-note.gif ADDED
Binary file
skin/frontend/default/customproduct/images/i_msg-success.gif ADDED
Binary file
skin/frontend/default/customproduct/images/i_notice.gif ADDED
Binary file
skin/frontend/default/customproduct/images/i_page1.gif ADDED
Binary file
skin/frontend/default/customproduct/images/i_page2.gif ADDED
Binary file
skin/frontend/default/customproduct/images/i_pager-next.gif ADDED
Binary file
skin/frontend/default/customproduct/images/i_pager-prev.gif ADDED
Binary file
skin/frontend/default/customproduct/images/i_print.gif ADDED
Binary file
skin/frontend/default/customproduct/images/i_rss-big.png ADDED
Binary file
skin/frontend/default/customproduct/images/i_rss.gif ADDED
Binary file
skin/frontend/default/customproduct/images/i_search_criteria.gif ADDED
Binary file
skin/frontend/default/customproduct/images/i_shipping.gif ADDED
Binary file
skin/frontend/default/customproduct/images/i_tag_add.gif ADDED
Binary file
skin/frontend/default/customproduct/images/i_tier.gif ADDED
Binary file
skin/frontend/default/customproduct/images/i_type_grid.gif ADDED
Binary file
skin/frontend/default/customproduct/images/i_type_list.gif ADDED
Binary file
skin/frontend/default/customproduct/images/logo.gif ADDED
Binary file
skin/frontend/default/customproduct/images/logo_email.gif ADDED
Binary file
skin/frontend/default/customproduct/images/logo_print.gif ADDED
Binary file
skin/frontend/default/customproduct/images/magnifier_handle.gif ADDED
Binary file
skin/frontend/default/customproduct/images/map_popup_arrow.gif ADDED
Binary file
skin/frontend/default/customproduct/images/media/404_callout1.jpg ADDED
Binary file
skin/frontend/default/customproduct/images/media/404_callout2.jpg ADDED
Binary file
skin/frontend/default/customproduct/images/media/about_us_img.jpg ADDED
Binary file
skin/frontend/default/customproduct/images/media/best_selling_img01.jpg ADDED
Binary file
skin/frontend/default/customproduct/images/media/best_selling_img02.jpg ADDED
Binary file
skin/frontend/default/customproduct/images/media/best_selling_img03.jpg ADDED
Binary file
skin/frontend/default/customproduct/images/media/best_selling_img04.jpg ADDED
Binary file
skin/frontend/default/customproduct/images/media/best_selling_img05.jpg ADDED
Binary file
skin/frontend/default/customproduct/images/media/best_selling_img06.jpg ADDED
Binary file
skin/frontend/default/customproduct/images/media/cell_phone_landing_banner1.jpg ADDED
Binary file
skin/frontend/default/customproduct/images/media/col_left_callout.jpg ADDED
Binary file
skin/frontend/default/customproduct/images/media/col_right_callout.jpg ADDED
Binary file
skin/frontend/default/customproduct/images/media/electronics_cellphones.jpg ADDED
Binary file
skin/frontend/default/customproduct/images/media/electronics_digitalcameras.jpg ADDED
Binary file
skin/frontend/default/customproduct/images/media/electronics_laptops.jpg ADDED
Binary file
skin/frontend/default/customproduct/images/media/furniture_callout_spot.jpg ADDED
Binary file
skin/frontend/default/customproduct/images/media/furnitures_bed_room.jpg ADDED
Binary file
skin/frontend/default/customproduct/images/media/furnitures_living_room.jpg ADDED
Binary file
skin/frontend/default/customproduct/images/media/head_electronics_cellphones.gif ADDED
Binary file
skin/frontend/default/customproduct/images/media/head_electronics_digicamera.gif ADDED
Binary file
skin/frontend/default/customproduct/images/media/head_electronics_laptops.gif ADDED
Binary file
skin/frontend/default/customproduct/images/media/laptop_callout_mid1.jpg ADDED
Binary file
skin/frontend/default/customproduct/images/media/laptop_callout_mid2.jpg ADDED
Binary file
skin/frontend/default/customproduct/images/media/laptop_callout_mid3.jpg ADDED
Binary file
skin/frontend/default/customproduct/images/media/laptop_callout_spot.jpg ADDED
Binary file
skin/frontend/default/customproduct/images/media/shirts_landing_banner1.jpg ADDED
Binary file
skin/frontend/default/customproduct/images/np_cart_thumb.gif ADDED
Binary file
skin/frontend/default/customproduct/images/np_more_img.gif ADDED
Binary file
skin/frontend/default/customproduct/images/np_product_main.gif ADDED
Binary file
skin/frontend/default/customproduct/images/np_thumb.gif ADDED
Binary file
skin/frontend/default/customproduct/images/np_thumb2.gif ADDED
Binary file
skin/frontend/default/customproduct/images/opc-ajax-loader.gif ADDED
Binary file
skin/frontend/default/customproduct/images/pager_arrow_left.gif ADDED
Binary file
skin/frontend/default/customproduct/images/pager_arrow_right.gif ADDED
Binary file
skin/frontend/default/customproduct/images/ph_callout_left_rebel.jpg ADDED
Binary file
skin/frontend/default/customproduct/images/ph_callout_left_top.gif ADDED
Binary file
skin/frontend/default/customproduct/images/product_zoom_overlay_magnif.gif ADDED
Binary file
skin/frontend/default/customproduct/images/slider_bg.gif ADDED
Binary file
skin/frontend/default/customproduct/images/slider_btn_zoom_in.gif ADDED
Binary file
skin/frontend/default/customproduct/images/slider_btn_zoom_out.gif ADDED
Binary file
skin/frontend/default/customproduct/images/spacer.gif ADDED
Binary file
skin/frontend/default/customproduct/images/textimage.png ADDED
Binary file
skin/frontend/default/customproduct/images/validation_advice_bg.gif ADDED
Binary file
skin/frontend/default/customproduct/images/xmlconnect/catalog/category/placeholder/image.jpg ADDED
Binary file
skin/frontend/default/customproduct/images/xmlconnect/catalog/category/placeholder/small_image.jpg ADDED
Binary file
skin/frontend/default/customproduct/images/xmlconnect/catalog/category/placeholder/thumbnail.jpg ADDED
Binary file
skin/frontend/default/customproduct/images/xmlconnect/tab_account.png ADDED
Binary file
skin/frontend/default/customproduct/images/xmlconnect/tab_cart.png ADDED
Binary file
skin/frontend/default/customproduct/images/xmlconnect/tab_home.png ADDED
Binary file
skin/frontend/default/customproduct/images/xmlconnect/tab_more.png ADDED
Binary file
skin/frontend/default/customproduct/images/xmlconnect/tab_page.png ADDED
Binary file
skin/frontend/default/customproduct/images/xmlconnect/tab_search.png ADDED
Binary file
skin/frontend/default/customproduct/images/xmlconnect/tab_shop.png ADDED
Binary file
skin/frontend/default/customproduct/js/Uize.Array.Dupes.js ADDED
@@ -0,0 +1,188 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ /*______________
2
+ | ______ | U I Z E J A V A S C R I P T F R A M E W O R K
3
+ | / / | ---------------------------------------------------
4
+ | / O / | MODULE : Uize.Array.Dupes Package
5
+ | / / / |
6
+ | / / / /| | ONLINE : http://www.uize.com
7
+ | /____/ /__/_| | COPYRIGHT : (c)2011-2012 UIZE
8
+ | /___ | LICENSE : Available under MIT License or GNU General Public License
9
+ |_______________| http://www.uize.com/license.html
10
+ */
11
+
12
+ /* Module Meta Data
13
+ type: Package
14
+ importance: 1
15
+ codeCompleteness: 50
16
+ testCompleteness: 0
17
+ docCompleteness: 0
18
+ */
19
+
20
+ /*?
21
+ Introduction
22
+ The =Uize.Array.Dupes= module provides functionality to deal with arrays containing duplicate values.
23
+
24
+ *DEVELOPERS:* `Chris van Rensburg`
25
+
26
+ ### Key Features
27
+ - high performance
28
+ - linear time complexity (even when removing object reference duplicates)
29
+ - can remove duplicates from source array, rather than always returning new array, and removes duplicates efficiently
30
+ - supports strict type checking
31
+ - supports object values
32
+ - supports optional target
33
+ - supports optional canonicalizer function, such as a lowercasing function for string values
34
+ */
35
+
36
+ Uize.module ({
37
+ name:'Uize.Array.Dupes',
38
+ required:'Uize.Data.Matches',
39
+ builder:function () {
40
+ /*** Variables for Scruncher Optimization ***/
41
+ var
42
+ _package = function () {},
43
+ _true = true,
44
+ _false = false,
45
+ _undefined,
46
+ _Uize = Uize
47
+ ;
48
+
49
+ /*** Utility Objects ***/
50
+ var _ValueIndexer = (
51
+ function () {
52
+ var
53
+ _objectTaggerValue = {},
54
+ _class = function (_canonicalizer) {
55
+ this._canonicalizer = _canonicalizer;
56
+ this._valuesLookup = _Uize.lookup (_undefined,1,_true);
57
+ },
58
+ _classPrototype = _class.prototype
59
+ ;
60
+
61
+ _classPrototype.isIn = function (_value,_addToIfNot) {
62
+ var
63
+ _this = this,
64
+ _canonicalizer = _this._canonicalizer,
65
+ _canonicalizedValue = _canonicalizer ? _canonicalizer (_value) : _value,
66
+ _wasIn = _false
67
+ ;
68
+ if (
69
+ _Uize.isPrimitive (_canonicalizedValue) ||
70
+ !(_Uize.isObject (_canonicalizedValue) || _Uize.isFunction (_canonicalizedValue))
71
+ ) {
72
+ var
73
+ _typeofCanonicalizedValue = typeof _canonicalizedValue,
74
+ _valuesLookup = _this._valuesLookup
75
+ ;
76
+ if (
77
+ (_valuesLookup [_canonicalizedValue] || (_valuesLookup [_canonicalizedValue] = {})) [
78
+ _typeofCanonicalizedValue
79
+ ]
80
+ ) {
81
+ _wasIn = _true;
82
+ } else if (_addToIfNot) {
83
+ _valuesLookup [_canonicalizedValue] [_typeofCanonicalizedValue] = _true;
84
+ }
85
+ } else {
86
+ if (_canonicalizedValue.tagged == _objectTaggerValue) {
87
+ _wasIn = _true;
88
+ } else if (_addToIfNot) {
89
+ (_this._taggedObjects || (_this._taggedObjects = [])).push ({
90
+ _object:_canonicalizedValue,
91
+ _hadTaggedProperty:_canonicalizedValue.hasOwnProperty ('tagged'),
92
+ _taggedPropertyOldValue:_canonicalizedValue.tagged
93
+ });
94
+ _canonicalizedValue.tagged = _objectTaggerValue;
95
+ }
96
+ }
97
+ return _wasIn;
98
+ };
99
+
100
+ _classPrototype.addTo = function (_value) {
101
+ return !this.isIn (_value,_true);
102
+ };
103
+
104
+ _classPrototype.cleanUp = function () {
105
+ var _taggedObjects = this._taggedObjects;
106
+ if (_taggedObjects) {
107
+ for (
108
+ var _taggedObjectNo = _taggedObjects.length, _taggedObject, _object;
109
+ --_taggedObjectNo >= 0;
110
+ ) {
111
+ _object = (_taggedObject = _taggedObjects [_taggedObjectNo])._object;
112
+ _taggedObject._hadTaggedProperty
113
+ ? (_object.tagged = _taggedObject._taggedPropertyOldValue)
114
+ : delete _object.tagged
115
+ ;
116
+ }
117
+ }
118
+ };
119
+
120
+ return _class;
121
+ }) ();
122
+
123
+ function _untagObjects (_taggedObjects) {
124
+ }
125
+
126
+ /*** Public Static Methods ***/
127
+ _package.dedupe = function (_source,_canonicalizer,_target) {
128
+ _target = _source;
129
+ /* TO DO
130
+ - support canonicalizers that can achieve the effect of loose type comparison
131
+ - one approach for a simple canonicalizer to perform loose type deduping would canonicalize primitive type values to strings, and map both null and undefined to a nully value object stand-in object
132
+
133
+ ...............................
134
+ var nullyValueStandin = {};
135
+ function (value) {
136
+ return (
137
+ Uize.isPrimitive (value)
138
+ ? value + ''
139
+ : Uize.isNully (value)
140
+ ? nullyValueStandin
141
+ : value
142
+ );
143
+ }
144
+ ...............................
145
+
146
+ - an alternative approach would allow a canonicalizer to return multiple equivalent canonical values
147
+ - when the canonicalizer sees a number value, it would return the number value, the string serialization of the number, and the boolean equivalent of the number
148
+ - when the canonicalizer sees a boolean value, it would return the number equivalent of the boolean, and the string serialization of the boolean
149
+ - when the canonicalizer sees the value null, it would return the value null, the value 0, and the value undefined
150
+ - problems with this approach are...
151
+ - canonicalizers should be able to return array values, so how would a canonicalizer that is to return multiple values differentiate that intent from simply returning an array as a canonicalized result? Perhaps the canonicalizer would have to have a property on it to indicate that it uses this signature, so that the return value would not have to be overloaded.
152
+ - if a canonicalizer could return multiple values, code that currently does the lookup and the insert would have to be wrapped in a loop to do multiple lookups and multiple inserts
153
+ */
154
+ var _valueIndexer = new _ValueIndexer (_canonicalizer);
155
+ _target = _Uize.Data.Matches.remove (
156
+ _source,function (_value) {return _valueIndexer.isIn (_value,_true)},null,_target
157
+ );
158
+ _valueIndexer.cleanUp ();
159
+ return _target;
160
+ };
161
+
162
+ function _removeOrRetainValues (_source,_valuesToRemove,_canonicalizer,_target,_retain) {
163
+ var _valueIndexer = new _ValueIndexer (_canonicalizer);
164
+ _Uize.forEach (
165
+ _valuesToRemove,
166
+ function (_valueToRemove) {_valueIndexer.isIn (_valueToRemove,_true)},
167
+ 0,
168
+ _true
169
+ );
170
+ _target = _Uize.Data.Matches.retain (
171
+ _source,function (_value) {return _valueIndexer.isIn (_value) == _retain},null,_target
172
+ );
173
+ _valueIndexer.cleanUp ();
174
+ return _target;
175
+ }
176
+
177
+ _package.removeValues = function (_source,_valuesToRemove,_canonicalizer,_target) {
178
+ return _removeOrRetainValues (_source,_valuesToRemove,_canonicalizer,_target,_false);
179
+ };
180
+
181
+ _package.retainValues = function (_source,_valuesToRemove,_canonicalizer,_target) {
182
+ return _removeOrRetainValues (_source,_valuesToRemove,_canonicalizer,_target,_true);
183
+ };
184
+
185
+ return _package;
186
+ }
187
+ });
188
+
skin/frontend/default/customproduct/js/Uize.Array.Order.js ADDED
@@ -0,0 +1,338 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ /*______________
2
+ | ______ | U I Z E J A V A S C R I P T F R A M E W O R K
3
+ | / / | ---------------------------------------------------
4
+ | / O / | MODULE : Uize.Array.Order Package
5
+ | / / / |
6
+ | / / / /| | ONLINE : http://www.uize.com
7
+ | /____/ /__/_| | COPYRIGHT : (c)2010-2012 UIZE
8
+ | /___ | LICENSE : Available under MIT License or GNU General Public License
9
+ |_______________| http://www.uize.com/license.html
10
+ */
11
+
12
+ /* Module Meta Data
13
+ type: Package
14
+ importance: 2
15
+ codeCompleteness: 100
16
+ testCompleteness: 100
17
+ docCompleteness: 100
18
+ */
19
+
20
+ /*?
21
+ Introduction
22
+ The =Uize.Array.Order= module provides utility methods for reordering the elements of arrays, with support for reversing, jumbling, inside to out, etc.
23
+
24
+ *DEVELOPERS:* `Chris van Rensburg`
25
+
26
+ In a Nutshell
27
+ Reordering Ins't Sorting
28
+ Unlike sorting an array based upon its elements' values, the methods of the =Uize.Array.Order= module allow you to reorder the elements according to different patterns - without respect to the element values.
29
+
30
+ As an example, the =Uize.Array.Order.reverse= method reverses the order of the elements in an array.
31
+
32
+ Types of Reordering
33
+ Reverse
34
+ The elements in an array can be reversed by using the =Uize.Array.Order.reverse= method, or by using the =Uize.Array.Order.reorder= method and specifying the value ='reverse'= for the method's =reorderingModeSTR= parameter.
35
+
36
+ EXAMPLE
37
+ ....................................................................................
38
+ Uize.Array.Order.reverse ([1,2,3,4,5,6,7,8]); // returns the array [8,7,6,5,4,3,2,1]
39
+ ....................................................................................
40
+
41
+ While JavaScript's built-in =Array= object *does* provide a =reverse= instance method, the =Uize.Array.Order.reverse= method offers a `Versatile Target` facility that is lacking with the built-in =reverse= method, which always modifies the source array.
42
+
43
+ For a more in-depth explanation, consult the reference for the =Uize.Array.Order.reverse= method.
44
+
45
+ Jumble
46
+ The elements of an array can be jumbled (randomly shuffled) by using the =Uize.Array.Order.jumble= static method, or by using the =Uize.Array.Order.reorder= method and specifying the value ='jumbled'= for the method's =reorderingModeSTR= parameter.
47
+
48
+ EXAMPLE
49
+ .......................................................................................
50
+ Uize.Array.Order.jumble ([1,2,3,4,5,6,7,8]); // returns an array like [2,8,4,1,6,3,7,5]
51
+ .......................................................................................
52
+
53
+ For a more in-depth explanation, consult the reference for the =Uize.Array.Order.jumble= method.
54
+
55
+ Inside to Out
56
+ The elements of an array can be reordered from inside to out by using the =Uize.Array.Order.insideOut= static method, or by using the =Uize.Array.Order.reorder= method and specifying the value ='inside out'= for the method's =reorderingModeSTR= parameter.
57
+
58
+ EXAMPLE
59
+ ......................................................................................
60
+ Uize.Array.Order.insideOut ([1,2,3,4,5,6,7,8]); // returns the array [4,5,3,6,2,7,1,8]
61
+ ......................................................................................
62
+
63
+ For a more in-depth explanation, consult the reference for the =Uize.Array.Order.insideOut= method.
64
+
65
+ Outside to In
66
+ The elements of an array can be reordered from outside to in by using the =Uize.Array.Order.insideOut= static method, or by using the =Uize.Array.Order.reorder= method and specifying the value ='outside in'= for the method's =reorderingModeSTR= parameter.
67
+
68
+ EXAMPLE
69
+ ......................................................................................
70
+ Uize.Array.Order.outsideIn ([1,2,3,4,5,6,7,8]); // returns the array [1,8,2,7,3,6,4,5]
71
+ ......................................................................................
72
+
73
+ For a more in-depth explanation, consult the reference for the =Uize.Array.Order.outsideIn= method.
74
+
75
+ Versatile Target
76
+ The methods of the =Uize.Array.Order= module support a versatile target facility that allows the processed elements of the source array to be targeted either to the source array, to a fresh array, or to a specified target array.
77
+
78
+ With JavaScript's built-in =Array= object, some instance methods will modify the source array while others will create a fresh array. For example, the =splice= and =reverse= methods will modify the source array. On the other hand, the =concat= and =slice= methods return new arrays. In contrast, the methods of the =Uize.Array.Order= module let you specify the target behavior for the processed elements of the source array. A target is specified using the optional =targetARRAYorBOOL= parameter. Essentially three behaviors are supported: 1) modify the source array, 2) create a fresh array, or 3) use a specified target array.
79
+
80
+ For a more in-depth discussion, consult the reference for the =targetARRAYorBOOL= value type.
81
+ */
82
+
83
+ Uize.module ({
84
+ name:'Uize.Array.Order',
85
+ builder:function () {
86
+ /*** Variables for Scruncher Optimization ***/
87
+ var _package = function () {};
88
+
89
+ /*** Utility Functions ***/
90
+ function _randomSorter () {return Math.random () - .5}
91
+
92
+ /*** Public Static Methods ***/
93
+ var _reorder = _package.reorder = function (_source,_reorderScheme,_target) {
94
+ if (typeof _target != 'object')
95
+ _target = _target === false ? _source : []
96
+ ;
97
+ if (
98
+ _target == _source &&
99
+ (_reorderScheme == 'normal' || _reorderScheme == 'reverse' || _reorderScheme == 'jumbled')
100
+ ) {
101
+ _reorderScheme == 'reverse'
102
+ ? _source.reverse ()
103
+ : _reorderScheme == 'jumbled'
104
+ ? _source.sort (_randomSorter)
105
+ : 0
106
+ ;
107
+ } else {
108
+ if (_target == _source) _source = _source.concat ();
109
+ var
110
+ _sourceLength = _source.length,
111
+ _sourceLengthMinus1 = _sourceLength - 1,
112
+ _indexMapper
113
+ ;
114
+ if (_reorderScheme == 'reverse') {
115
+ _indexMapper = function (_index) {return _sourceLengthMinus1 - _index};
116
+ } else if (_reorderScheme == 'inside out') {
117
+ var
118
+ _startLeft = _sourceLength % 2,
119
+ _rightInnerNo = Math.ceil (_sourceLengthMinus1 / 2)
120
+ ;
121
+ _indexMapper = function (_index) {
122
+ return (
123
+ _index % 2 == _startLeft
124
+ ? _rightInnerNo - 1 - (_index >> 1)
125
+ : _rightInnerNo + (_index >> 1)
126
+ );
127
+ };
128
+ } else if (_reorderScheme == 'outside in') {
129
+ _indexMapper = function (_index) {
130
+ return _index % 2 ? _sourceLengthMinus1 - (_index >> 1) : _index >> 1;
131
+ };
132
+ } else if (_reorderScheme == 'normal') {
133
+ _indexMapper = Uize.returnX;
134
+ } else {
135
+ var _jumbledOrder = Uize.map (_sourceLength,'key').sort (_randomSorter);
136
+ _indexMapper = function (_index) {return _jumbledOrder [_index]};
137
+ }
138
+ for (var _elementNo = -1; ++_elementNo <= _sourceLengthMinus1;)
139
+ _target [_elementNo] = _source [_indexMapper (_elementNo)]
140
+ ;
141
+ }
142
+ return _target;
143
+ /*?
144
+ Static Methods
145
+ Uize.Array.Order.reorder
146
+ Returns an array, being a reordered version of the specified source array, using the specified reordering mode.
147
+
148
+ SYNTAX
149
+ ..........................................................................
150
+ reorderedARRAY = Uize.Array.Order.reorder (sourceARRAY,reorderingModeSTR);
151
+ ..........................................................................
152
+
153
+ VARIATION 1
154
+ .............................................................................
155
+ reorderedARRAY =
156
+ Uize.Array.Order.reorder (sourceARRAY,reorderingModeSTR,targetARRAYorBOOL)
157
+ ;
158
+ .............................................................................
159
+
160
+ By default, the =Uize.Array.Order.reorder= method packages the reordered array elements into a new array and does not modify the source array (ie. it's non-destructive). Specifying the optional =targetARRAYorBOOL= parameter allows you to explicitly specify a target for the operation, into which the reordered elements will be packaged.
161
+
162
+ VARIATION 2
163
+ ......................................................
164
+ jumbledARRAY = Uize.Array.Order.reorder (sourceARRAY);
165
+ ......................................................
166
+
167
+ When only a =sourceARRAY= parameter is specified, then the default behavior is to reorder the source array using the ='jumble'= mode and package the results into a new array.
168
+
169
+ reorderingModeSTR
170
+ The =reorderingModeSTR= parameter is a string, specifying the reordering mode that should be employed, and can have the following values...
171
+
172
+ - ='jumbled'= (default) - reorders the specified source array in the same way as the =Uize.Array.Order.jumble= static method
173
+ - ='reverse'= - reorders the specified source array in the same way as the =Uize.Array.Order.reverse= static method
174
+ - ='inside out'= - reorders the specified source array in the same way as the =Uize.Array.Order.insideOut= static method
175
+ - ='outside in'= - reorders the specified source array in the same way as the =Uize.Array.Order.outsideIn= static method
176
+ - ='normal'= - leaves the order of elements unchanged
177
+
178
+ NOTES
179
+ - see the related =Uize.Array.Order.insideOut=, =Uize.Array.Order.jumble=, =Uize.Array.Order.outsideIn=, and =Uize.Array.Order.reverse= static methods
180
+ */
181
+ };
182
+
183
+ _package.insideOut = function (_elements,_target) {
184
+ return _reorder (_elements,'inside out',_target)
185
+ /*?
186
+ Static Methods
187
+ Uize.Array.Order.insideOut
188
+ Returns an array, being the specified source array reordered from inside to out.
189
+
190
+ SYNTAX
191
+ ..........................................................
192
+ reorderedARRAY = Uize.Array.Order.insideOut (sourceARRAY);
193
+ ..........................................................
194
+
195
+ When an array is reordered from inside to out, the new order is formed by starting with the inner elements and moving outwards in both directions to reach the start and the end of the array. Consider the following example...
196
+
197
+ EXAMPLE
198
+ ......................................................................................
199
+ Uize.Array.Order.insideOut ([1,2,3,4,5,6,7,8]); // returns the array [4,5,3,6,2,7,1,8]
200
+ ......................................................................................
201
+
202
+ In the above example, at the center of the array being reordered are the values =4= and =5=. These are the first two elements of the reordered array. Moving outwards in both directions, the next two values are =3= and =6=, so these are the next two elements in the reordered array. Moving outwards further, the next two values are =2= and =7=, which become the next two elements in the reordered array. Finally, we get to the first and last values in the array being reordered, =1= and =9=, which become the last two elements of the reordered array.
203
+
204
+ VARIATION
205
+ ............................................................................
206
+ reorderedARRAY = Uize.Array.Order.insideOut (sourceARRAY,targetARRAYorBOOL);
207
+ ............................................................................
208
+
209
+ When the optional =targetARRAYorBOOL= parameter is specified, the target destination for the reordered elements can be controlled (for more info, see the reference for the =targetARRAYorBOOL= value type).
210
+
211
+ NOTES
212
+ - see the related =Uize.Array.Order.jumble=, =Uize.Array.Order.outsideIn=, =Uize.Array.Order.reorder=, and =Uize.Array.Order.reverse= static methods
213
+ */
214
+ };
215
+
216
+ _package.jumble = function (_elements,_target) {
217
+ return _reorder (_elements,'jumbled',_target)
218
+ /*?
219
+ Static Methods
220
+ Uize.Array.Order.jumble
221
+ Returns an array, being a jumbled (randomly shuffled) version of the specified source array.
222
+
223
+ SYNTAX
224
+ .......................................................
225
+ reorderedARRAY = Uize.Array.Order.jumble (sourceARRAY);
226
+ .......................................................
227
+
228
+ EXAMPLE
229
+ .......................................................................................
230
+ Uize.Array.Order.jumble ([1,2,3,4,5,6,7,8]); // returns an array like [2,8,4,1,6,3,7,5]
231
+ .......................................................................................
232
+
233
+ In the above example, the order of the elements in the jumbled array will very likely be different for every different time that the =Uize.Array.Order.jumble= method is called.
234
+
235
+ VARIATION
236
+ .........................................................................
237
+ reorderedARRAY = Uize.Array.Order.jumble (sourceARRAY,targetARRAYorBOOL);
238
+ .........................................................................
239
+
240
+ When the optional =targetARRAYorBOOL= parameter is specified, the target destination for the jumbled elements can be controlled (for more info, see the reference for the =targetARRAYorBOOL= value type).
241
+
242
+ NOTES
243
+ - see the related =Uize.Array.Order.insideOut=, =Uize.Array.Order.outsideIn=, =Uize.Array.Order.reorder=, and =Uize.Array.Order.reverse= static methods
244
+ */
245
+ };
246
+
247
+ _package.outsideIn = function (_elements,_target) {
248
+ return _reorder (_elements,'outside in',_target)
249
+ /*?
250
+ Static Methods
251
+ Uize.Array.Order.outsideIn
252
+ Returns an array, being the specified source array reordered from outside to in.
253
+
254
+ SYNTAX
255
+ ..........................................................
256
+ reorderedARRAY = Uize.Array.Order.outsideIn (sourceARRAY);
257
+ ..........................................................
258
+
259
+ When an array is reordered from outside to in, the new order is formed by starting with the start and the end of the array and moving inwards in both directions to reach the inner elements. Consider the following example...
260
+
261
+ EXAMPLE
262
+ ......................................................................................
263
+ Uize.Array.Order.outsideIn ([1,2,3,4,5,6,7,8]); // returns the array [1,8,2,7,3,6,4,5]
264
+ ......................................................................................
265
+
266
+ In the above example, at the start and end of the array being reordered are the values =1= and =8=. These are the first two elements of the reordered array. Moving inwards in both directions, the next two values are =2= and =7=, so these are the next two elements in the reordered array. Moving inwards further, the next two values are =3= and =6=, which become the next two elements in the reordered array. Finally, we get to the inner values in the array being reordered, =4= and =5=, which become the last two elements of the reordered array.
267
+
268
+ VARIATION
269
+ ............................................................................
270
+ reorderedARRAY = Uize.Array.Order.outsideIn (sourceARRAY,targetARRAYorBOOL);
271
+ ............................................................................
272
+
273
+ When the optional =targetARRAYorBOOL= parameter is specified, the target destination for the reordered elements can be controlled (for more info, see the reference for the =targetARRAYorBOOL= value type).
274
+
275
+ NOTES
276
+ - see the related =Uize.Array.Order.insideOut=, =Uize.Array.Order.jumble=, =Uize.Array.Order.reorder=, and =Uize.Array.Order.reverse= static methods
277
+ */
278
+ };
279
+
280
+ _package.reverse = function (_elements,_target) {
281
+ return _reorder (_elements,'reverse',_target)
282
+ /*?
283
+ Static Methods
284
+ Uize.Array.Order.reverse
285
+ Returns an array, being a reversed version of the specified source array.
286
+
287
+ SYNTAX
288
+ ........................................................
289
+ reorderedARRAY = Uize.Array.Order.reverse (sourceARRAY);
290
+ ........................................................
291
+
292
+ EXAMPLE
293
+ ....................................................................................
294
+ Uize.Array.Order.reverse ([1,2,3,4,5,6,7,8]); // returns the array [8,7,6,5,4,3,2,1]
295
+ ....................................................................................
296
+
297
+ VARIATION
298
+ ..........................................................................
299
+ reorderedARRAY = Uize.Array.Order.reverse (sourceARRAY,targetARRAYorBOOL);
300
+ ..........................................................................
301
+
302
+ When the optional =targetARRAYorBOOL= parameter is specified, the target destination for the reversed elements can be controlled (for more info, see the reference for the =targetARRAYorBOOL= value type).
303
+
304
+ NOTES
305
+ - see the related =Uize.Array.Order.insideOut=, =Uize.Array.Order.jumble=, =Uize.Array.Order.outsideIn=, and =Uize.Array.Order.reorder= static methods
306
+ */
307
+ };
308
+
309
+ /*?
310
+ Value Types
311
+ For the sake of not redundantly describing the value types for certain method parameters and return values repeatedly, some common value types are described here.
312
+
313
+ sourceARRAY
314
+ An array reference, specifying an array that should be processed by an array method.
315
+
316
+ Values of this type can be accepted by the =Uize.Array.Order.insideOut=, =Uize.Array.Order.jumble=, =Uize.Array.Order.outsideIn=, =Uize.Array.Order.reorder=, and =Uize.Array.Order.reverse= static methods.
317
+
318
+ Array-like Values
319
+ Methods that accept parameters of the =sourceARRAY= value type can also support array-like objects, such as collections of DOM nodes - provided that the source array is not also specified as the target for reordered elements.
320
+
321
+ targetARRAYorBOOL
322
+ An array reference or boolean value, which lets you specify where the result of an array method's processing should be packaged.
323
+
324
+ Values of this type can be accepted by the =Uize.Array.Order.insideOut=, =Uize.Array.Order.jumble=, =Uize.Array.Order.outsideIn=, =Uize.Array.Order.reorder=, and =Uize.Array.Order.reverse= static methods.
325
+
326
+ VALUES
327
+
328
+ - When the *boolean* value =true= is specified (the default value for the =targetARRAYorBOOL= parameter if it is omitted), then the result of an array method's processing will be packaged into a new array.
329
+
330
+ - When the *boolean* value =false= is specified (not the same as not specifying a value), then the result of an array method's processing will be packaged into the source array that was supplied to the array method in its =sourceARRAY= parameter (ie. the method won't use a different target).
331
+
332
+ - When an *array* is explicitly specified, then the result of an array method's processing will be packaged into the specified target array. This is convenient if you already have an array into which you wish to package the result. Incidentally, specifying the source array that you supplied to an array method as also the target array has the same effect as specifying the value =false= for =targetARRAYorBOOL= (ie. use the source as the target, don't use a different target).
333
+ */
334
+
335
+ return _package;
336
+ }
337
+ });
338
+
skin/frontend/default/customproduct/js/Uize.Array.Sort.js ADDED
@@ -0,0 +1,510 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ /*______________
2
+ | ______ | U I Z E J A V A S C R I P T F R A M E W O R K
3
+ | / / | ---------------------------------------------------
4
+ | / O / | MODULE : Uize.Array.Sort Package
5
+ | / / / |
6
+ | / / / /| | ONLINE : http://www.uize.com
7
+ | /____/ /__/_| | COPYRIGHT : (c)2010-2012 UIZE
8
+ | /___ | LICENSE : Available under MIT License or GNU General Public License
9
+ |_______________| http://www.uize.com/license.html
10
+ */
11
+
12
+ /* Module Meta Data
13
+ type: Package
14
+ importance: 2
15
+ codeCompleteness: 100
16
+ testCompleteness: 100
17
+ docCompleteness: 100
18
+ */
19
+
20
+ /*?
21
+ Introduction
22
+ The =Uize.Array.Sort= module provides a powerful array sorting method that is very versatile and highly optimized for performance.
23
+
24
+ *DEVELOPERS:* `Chris van Rensburg`
25
+
26
+ Key Features
27
+ The =Uize.Array.Sort= module offers a number of important features, as outlined below...
28
+
29
+ Sort Value Generator
30
+ The =Uize.Array.Sort.sortBy= static method allows an array to be sorted by sort values that are generated for elements of the array by a sort value generator, which can be specified as either a `Sort Value Generator Expression` or a `Value Generator Function`.
31
+
32
+ Why a Sort Value Generator?
33
+ When one sorts an array using the =sort= instance method of JavaScript's =Array= object, the =sort= method compares the raw values of the array's elements - unless one specifies a custom comparison function.
34
+
35
+ When one *does* specify a comparison function, it may be called many times to compare the same value to some other value. If it is necessary to derive a value for use in the comparison, rather than simply using the raw value for an element, then the code to derive a value to be used in the comparison might be executed redundantly many times. This can be particularly costly when sorting a large array and where the code to derive a value for comparison involves more significant processing.
36
+
37
+ To illustrate this point, consider the example of a case-insensitive sort. If one simply uses the =Array= object's =sort= instance method, then one might write the sort code as follows...
38
+
39
+ POOR PERFORMANCE
40
+ .......................................................................................
41
+ firstNames.sort (function (a,b) {return a.toLowerCase () < b.toLowerCase () ? -1 : 1});
42
+ .......................................................................................
43
+
44
+ In the above example, the =toLowerCase= instance method of the =Array= object is being used to convert both string values being compared to lower case - this ensures that the case of individual characters in the two strings has no effect on the sort order, and the sort is thereby made case-insensitive. Problem is, the =toLowerCase= method may be called multiple times for the same element, just because of how the =sort= method is implemented. This could become a very serious performance problem when sorting large arrays of very long strings using this approach. This is where the =Uize.Array.Sort.sortBy= method comes in. Using this method, the above example could be rewritten as follows...
45
+
46
+ IMPROVED PERFORMANCE
47
+ ...........................................................
48
+ Uize.Array.Sort.sortBy (firstNames,'value.toLowerCase ()');
49
+ ...........................................................
50
+
51
+ Now that we're using the =Uize.Array.Sort.sortBy= method, we no longer specify a comparison function. Instead, we're specifying the string ='value.toLowerCase ()'= as a `Sort Value Generator Expression`. This expression will be used for every element of the array being sorted. The array will then be sorted using the sort values generated for each of the array's elements. Instead of using the array's element values in the comparison function, the =Uize.Array.Sort.sortBy= method will use the generated sort values. This means that the =toLowerCase= method is guaranteed to only be called once for every element of the array.
52
+
53
+ Sort Value Generator Function
54
+ A Sort Value Generator Function is a `Sort Value Generator` specified in the form of a function.
55
+
56
+ When a function is specified for the Sort Value Generator, it should expect to receive two parameters: the value for an element of the array being sorted, and the index / key for that element. The function should return the generated sort value. Generated sort values should be of a type that can be used with the boolean less than and greater than comparison operators - numbers and strings are the typical types that are appropriate for generated sort values. This is all illustrated well in the following example...
57
+
58
+ EXAMPLE
59
+ ..................................................................................
60
+ Uize.Array.Sort.sortBy (names,function (value,key) {return value.toLowerCase ()});
61
+ ..................................................................................
62
+
63
+ In the above example, the =names= array is an array of string values. It is being sorted in ASCIIbetical order, using a Sort Value Generator Function that renders the sort case-insensitive. The function accepts =value= and =key= parameters, using the =value= parameter to generate a sort value that is an element's value converted to all lower case. As you'll notice, the function is not actually using the =key= parameter, so it could just as well be omitted, as follows...
64
+
65
+ WITHOUT THE KEY PARAMETER
66
+ ..............................................................................
67
+ Uize.Array.Sort.sortBy (names,function (value) {return value.toLowerCase ()});
68
+ ..............................................................................
69
+
70
+ For an example of how an element's key might be used in generating sort values, see the section `Using an Element's Key To Generate a Sort Value`.
71
+
72
+ Sort Value Generator Expression
73
+ A Sort Value Generator Expression is a `Sort Value Generator` specified in the form of an expression string.
74
+
75
+ When an expression string is specified for the Sort Value Generator, it should expect two variables to be defined in the scope of the expression's code: the =value= variable contains the value for an element of the array being sorted, and the =key= variable contains that element's index / key. The expression should produce the generated sort value. Generated sort values should be of a type that can be used with the boolean less than and greater than comparison operators - numbers and strings are the typical types that are appropriate for generated sort values. This is all illustrated well in the following example...
76
+
77
+ EXAMPLE
78
+ ......................................................
79
+ Uize.Array.Sort.sortBy (names,'value.toLowerCase ()');
80
+ ......................................................
81
+
82
+ In the above example, the =names= array is an array of string values. It is being sorted in ASCIIbetical order, using a Sort Value Generator Expression that renders the sort case-insensitive. The expression is using the =value= variable to generate a sort value that is an element's value converted to all lower case. As you'll notice, using a `Sort Value Generator Expression` can be more concise than using a `Sort Value Generator Function`. And since you're just specifying a JavaScript expression and not defining a function, there is no =return= statement in the expression.
83
+
84
+ You'll also notice that the expression is not using the =key= variable in generating the sort value. For an example of how an element's key might be used in generating sort values, see the section `Using an Element's Key To Generate a Sort Value`.
85
+
86
+ Using an Element's Key To Generate a Sort Value
87
+ The key for an element is very seldom used when performing a sort using the =Uize.Array.Sort.sortBy= method, but the following hypothetical example demonstrates how it might be used...
88
+
89
+ USING THE KEY
90
+ .............................................................................
91
+ Uize.Array.Sort.sortBy (values,'key + (key % 2 ? ' + names.length + ' : 0)');
92
+ .............................................................................
93
+
94
+ In the above example, the =values= array is being "sorted" so that all even numbered elements are clumped at the beginning and all odd numbered elements are clumped at the end. So, if the contents of the values array was =['a','b','c','d','e','f','g','h']=, then the sorted values would be =['a','c','e','g','b','d','f','h']=. The reason this works is because the generated sort value is the key for even numbered elements, and the key plus the length of the array for odd numbered elements, achieved by using the =%= (mod) operator with a ternary operator expression. This preserves the order of the elements within the even numbered and odd numbered clumps of elements, but pushes all the odd numbered elements to after the even numbered elements. Generated sort values are not required to map in any way to the indexes of elements in the array being sorted, so it's ok than the sort values in this case extend beyond the length of the array, and that there are gaps between consecutive sort values.
95
+
96
+ When the values of an array's elements are not used when generating sort values, then what you're doing is more like a reordering algorithm than a sort. Of course, there's no saying you can't use both the value and the index / key for elements when generating sort values.
97
+
98
+ Sort Order Direction
99
+ As a convenience, the sort direction for sorts performed by the =Uize.Array.Sort.sortBy= method can be controlled via its optional =directionINT= parameter.
100
+
101
+ Specifying the value =-1= for the =directionINT= parameter will reverse the sort direction for a sort. Consider the following example...
102
+
103
+ EXAMPLE
104
+ .........................................................
105
+ Uize.Array.Sort.sortBy (names,'value.toLowerCase ()',-1);
106
+ .........................................................
107
+
108
+ In the above example, the =names= array is an array of string values. It is being sorted in descending ASCIIbetical order, using a `Sort Value Generator Expression` that renders the sort case-insensitive. Using the =directionINT= parameter when you want to perform a sort in descending order is more efficient than first performing the sort and then reversing the sorted array using the array's =reverse= instance method. This is because the =Uize.Array.Sort.sortBy= method takes the sort direction into account during the sort operation's reordering of the array's elements.
109
+
110
+ Easy Data Table Sorting
111
+ The =Uize.Array.Sort= module's =Uize.Array.Sort.sortBy= method makes it very easy to sort a data table by the values of a specific column, simply by the number of the column to sort the table by for the method's =sortColumnINT= parameter.
112
+
113
+ A data table is an array of arrays, where each array type element represents a row of data in the table. Consider the following example...
114
+
115
+ EXAMPLE
116
+ ..................................
117
+ var
118
+ fruits = [
119
+ ['Apples',52,13.81,2.4],
120
+ ['Avocados',160,8.53,6.7],
121
+ ['Bananas',89,22.84,2.6],
122
+ ['Dates',277,74.97,6.7],
123
+ ['Grapefruits',42,10.66,1.6]
124
+ ]
125
+ ;
126
+ Uize.Array.Sort.sortBy (fruits,1);
127
+ ..................................
128
+
129
+ In the above example, the =fruits= array is a data table array where each row contains data describing a fruit. Each row array contains information for fruit name, calorie count, total carbohydrates, and dietary fiber. We're using the =Uize.Array.Sort.sortBy= method to sort the fruits in order of their caloric content, from lowest calorie count to highest calorie count. Specifying the value =1= for the =sortColumnINT= parameter indicates that the values of the second column (column numbers are zero-based) should be used as the sort values, so the sort values used to drive the sort of the =fruits= array is an array of calorie count numbers.
130
+
131
+ Easy Record Array Sorting
132
+ With the use of a simple `Sort Value Generator Expression`, the =Uize.Array.Sort= module's =Uize.Array.Sort.sortBy= method makes it a very concise thing to sort an array of records by a specific record field.
133
+
134
+ A records array is an array of objects, where each object represents a record and contains properties that represent the fields of the record. Consider the following example...
135
+
136
+ EXAMPLE
137
+ .......................................................................
138
+ var
139
+ fruits = [
140
+ {name:'Apples',calories:52,totalCarbs:13.81,dietaryFiber:2.4},
141
+ {name:'Avocados',calories:160,totalCarbs:8.53,dietaryFiber:6.7},
142
+ {name:'Bananas',calories:89,totalCarbs:22.84,dietaryFiber:2.6},
143
+ {name:'Dates',calories:277,totalCarbs:74.97,dietaryFiber:6.7},
144
+ {name:'Grapefruits',calories:42,totalCarbs:10.66,dietaryFiber:1.6}
145
+ ]
146
+ ;
147
+ Uize.Array.Sort.sortBy (fruits,'value.calories');
148
+ .......................................................................
149
+
150
+ In the above example, the =fruits= array is a records array where each record describes a fruit and contains the fields =name=, =calories=, =totalCarbs=, and =dietaryFiber=. We're using the =Uize.Array.Sort.sortBy= method to sort the fruits in order of their caloric content, from lowest calorie count to highest calorie count. The `Sort Value Generator Expression` used here simply dereferences the =calories= property for a record, so the generated sort values used to drive the sort of the =fruits= array is an array of calorie count numbers.
151
+
152
+ Optimized For Performance
153
+ The =Uize.Array.Sort= method of the =Uize.Array.Sort= module is optimized for performance.
154
+
155
+ The =Uize.Array.Sort= method sorts an array based upon sort values that are generated for all of the array's elements. These sort values are generated in the first pass of the sorting operation, and as a one time operation, unlike the traditional approach of generating comparison values every time one element is compared to another. This is illustrated well in the classic example of performing a case-insensitive ASCIIbetical sort of an array of strings, where a typical use of the =sort= instance method of JavaScript's =Array= object would be quite inefficient. That's because the same string value may be lowercased repeatedly - each time a given element is compared to some other element. The typical, inefficient solution might look as follows...
156
+
157
+ INEFFICIENT CLASSIC SOLUTION
158
+ ..................................................................................
159
+ names.sort (function (a,b) {return a.toLowerCase () < b.toLowerCase () ? -1 : 1});
160
+ ..................................................................................
161
+
162
+ A more efficient solution is to use the =Uize.Array.Sort.sortBy= method, because it ensures that the lowercasing will only be performed once per element of the source array.
163
+
164
+ EFFICIENT SOLUTION
165
+ ......................................................
166
+ Uize.Array.Sort.sortBy (names,'value.toLowerCase ()');
167
+ ......................................................
168
+
169
+ Sorts Are More Concise
170
+ Besides being `Optimized For Performance`, the =Uize.Array.Sort.sortBy= method of the ==Uize.Array.Sort= module also produces more concise code than using the traditional approach.
171
+
172
+ To illustrate this point, consider the following before-and-after examples...
173
+
174
+ BEFORE-AFTER: Sort a Strings Array in Case-insensitive ASCIIbetical Order
175
+ BEFORE
176
+ .......................................................................................
177
+ firstNames.sort (function (a,b) {return a.toLowerCase () < b.toLowerCase () ? -1 : 1});
178
+ .......................................................................................
179
+
180
+ AFTER
181
+ ......................................................
182
+ Uize.Array.Sort.sortBy (names,'value.toLowerCase ()');
183
+ ......................................................
184
+
185
+ BEFORE-AFTER: Sort a Data Table Array By the Values of the Second Column
186
+ BEFORE
187
+ ............................................................
188
+ table.sort (function (a,b) {return a [1] < b [1] ? -1 : 1});
189
+ ............................................................
190
+
191
+ AFTER
192
+ .................................
193
+ Uize.Array.Sort.sortBy (table,1);
194
+ .................................
195
+
196
+ BEFORE-AFTER: Sort a Records Array by the name Field
197
+ BEFORE
198
+ ................................................................
199
+ records.sort (function (a,b) {return a.name < b.name ? -1 : 1});
200
+ ................................................................
201
+
202
+ AFTER
203
+ ..............................................
204
+ Uize.Array.Sort.sortBy (records,'value.name');
205
+ ..............................................
206
+ */
207
+
208
+ Uize.module ({
209
+ name:'Uize.Array.Sort',
210
+ builder:function () {
211
+ /*** Variables for Scruncher Optimization ***/
212
+ var _package = function () {};
213
+
214
+ /*** General Variables ***/
215
+ var
216
+ _sortValues = [],
217
+ _ascendingSort = new Function ('a','b','return a.v<b.v?-1:a.v>b.v?1:0'),
218
+ _descendingSort = new Function ('a','b','return a.v<b.v?1:a.v>b.v?-1:0'),
219
+ _ascendingSimpleSort = new Function ('a','b','return a<b?-1:a>b?1:0'),
220
+ _descendingSimpleSort = new Function ('a','b','return a<b?1:a>b?-1:0')
221
+ ;
222
+
223
+ /*** Public Static Methods ***/
224
+ _package.sortBy = function (_elements,_sortValueGenerator,_direction) {
225
+ var _elementsLength = _elements.length;
226
+ if (_elementsLength > 1) {
227
+ if (_sortValueGenerator != null) {
228
+ var _sortValue;
229
+ if (!Uize.isFunction (_sortValueGenerator)) {
230
+ if (typeof _sortValueGenerator == 'number')
231
+ _sortValueGenerator = 'value [' + _sortValueGenerator + ']'
232
+ ;
233
+ _sortValueGenerator = Uize.resolveTransformer (_sortValueGenerator);
234
+ };
235
+ /*** build sortValues array ***/
236
+ for (var _elementNo = _sortValues.length = _elementsLength; --_elementNo >= 0;) {
237
+ (_sortValue = _sortValues [_elementNo] || (_sortValues [_elementNo] = {})).v =
238
+ _sortValueGenerator (
239
+ _sortValue._element = _elements [_sortValue._elementNo = _elementNo],
240
+ _elementNo
241
+ )
242
+ ;
243
+ }
244
+
245
+ /*** sort sortValues array ***/
246
+ _sortValues.sort (_direction == -1 ? _descendingSort : _ascendingSort);
247
+
248
+ /*** re-populate array to be sorted, using sortValues array ***/
249
+ for (var _elementNo = _elementsLength; --_elementNo >= 0;) {
250
+ if (_elementNo != (_sortValue = _sortValues [_elementNo])._elementNo)
251
+ _elements [_elementNo] = _sortValue._element
252
+ ;
253
+ _sortValue._element = _sortValue.v = null;
254
+ }
255
+ } else {
256
+ _elements.sort (_direction == -1 ? _descendingSimpleSort : _ascendingSimpleSort);
257
+ }
258
+ }
259
+ return _elements;
260
+ /*?
261
+ Static Methods
262
+ Uize.Array.Sort.sortBy
263
+ Returns an array, being the specified source array sorted by the values generated by the specified value generator (the source array is modified by this method).
264
+
265
+ SYNTAX
266
+ ..........................................................................
267
+ sourceARRAY = Uize.Array.Sort.sortBy (sourceARRAY,sortValueGeneratorFUNC);
268
+ ..........................................................................
269
+
270
+ The =Uize.Array.Sort.sortBy= method is engineered for high performance when sorting arrays where the sort order is determined by values that are derived from the source array's element values (see `Optimized For Performance` for more details).
271
+
272
+ When the =Uize.Array.Sort.sortBy= method sorts an array, it first generates sort values for all the elements of the array, using a `Sort Value Generator` that can be specified either in the form of a `Sort Value Generator Function` or a `Sort Value Generator Expression`. The method then sorts the array of generated sort values, and then applies that sort order back to the elements of the source array. This lets you drive the sorting of the source array by something other than the exact values of the source array's elements.
273
+
274
+ To illustrate this, let's take the simple example of performing a case-insensitive ASCIIbetical sort...
275
+
276
+ EXAMPLE
277
+ ......................................................
278
+ Uize.Array.Sort.sortBy (names,'value.toLowerCase ()');
279
+ ......................................................
280
+
281
+ In the above example, when the =Uize.Array.Sort.sortBy= method is called, a sort values array is generated by iterating over the elements of the =names= array, and for each element executing the specified sort value generator. In this case, the sort value generator uses the value for an element of the names array and then produces the lowercased version of that string as the sort value. The lowercased names are then sorted, and the resulting sort order determines the new order for the elements of the source array.
282
+
283
+ Generated Sort Values Only For Determining Sort Order
284
+ It's worth emphasizing that the generated sort values are only used in determining the sort ordering of the elements of the source array.
285
+
286
+ Therefore, in the case-insensitive ASCIIbetical sort example, the sorted values would be the original, non-lowercased values - *NOT* the lowercased sort values.
287
+
288
+ Variations
289
+ The =Uize.Array.Sort.sortBy= method supports the following variations...
290
+
291
+ VARIATION 1
292
+ .........................................................................
293
+ sourceARRAY = Uize.Array.Sort.sortBy (sourceARRAY,sortValueGeneratorSTR);
294
+ .........................................................................
295
+
296
+ When a =sortValueGeneratorSTR= parameter is specified in place of the =sortValueGeneratorFUNC= parameter, then a more concise JavaScript expression string can be specified for the sort value generator. For a more in-depth discussion of this feature and to see an example, consult the section `Sort Value Generator Expression`.
297
+
298
+ VARIATION 2
299
+ .................................................................
300
+ sourceARRAY = Uize.Array.Sort.sortBy (sourceARRAY,sortColumnINT);
301
+ .................................................................
302
+
303
+ When a =sortColumnINT= parameter is specified in place of the =sortValueGeneratorFUNC= parameter, then a data table (an array of row arrays) can be easily sorted by the values in one of its columns, by specifying the number of the column to sort the table by for the =sortColumnINT= parameter. For an example of this, see the section `Easy Data Table Sorting`.
304
+
305
+ VARIATIONS 3 & 4
306
+ .............................................................
307
+ sourceARRAY = Uize.Array.Sort.sortBy (sourceARRAY,null);
308
+ sourceARRAY = Uize.Array.Sort.sortBy (sourceARRAY,undefined);
309
+ .............................................................
310
+
311
+ When the value =null= or =undefined= is specified in place of the =sortValueGeneratorFUNC= parameter, then the =Uize.Array.Sort.sortBy= method will sort the specified array using the raw values of the array's elements as the sort values.
312
+
313
+ VARIATIONS 5, 6, 7, 8 & 9
314
+ .......................................................................................
315
+ sourceARRAY = Uize.Array.Sort.sortBy (sourceARRAY,sortValueGeneratorFUNC,directionINT);
316
+ sourceARRAY = Uize.Array.Sort.sortBy (sourceARRAY,sortValueGeneratorSTR,directionINT);
317
+ sourceARRAY = Uize.Array.Sort.sortBy (sourceARRAY,sortColumnINT,directionINT);
318
+ sourceARRAY = Uize.Array.Sort.sortBy (sourceARRAY,null,directionINT);
319
+ sourceARRAY = Uize.Array.Sort.sortBy (sourceARRAY,undefined,directionINT);
320
+ .......................................................................................
321
+
322
+ By default, the sort direction of the =Uize.Array.Sort.sortBy= method is ascending. When the optional =directionINT= parameter is specified, the direction for a sort can be controlled. Specifying the value =-1= for the =directionINT= parameter will cause the sort direction to be descending (ie. reversed), while specifying the value =1= will cause the sort direction to be ascending (the default).
323
+
324
+ VARIATION 10
325
+ ...................................................
326
+ sourceARRAY = Uize.Array.Sort.sortBy (sourceARRAY);
327
+ ...................................................
328
+
329
+ When only a =sourceARRAY= parameter is specified, the =Uize.Array.Sort.sortBy= method behaves in the same way as when the value =null= or =undefined= is specified for the sort value generator and no optional =directionINT= parameter is specified, performing the sort using the raw values of the source array's elements as the sort values.
330
+
331
+ Examples
332
+ Sort an Array of Strings by Length, Shortest to Longest
333
+ An array of strings can be sorted by length with a simple `Sort Value Generator Expression` that returns the value of the =length= property of a value.
334
+
335
+ EXAMPLE
336
+ ................................................
337
+ Uize.Array.Sort.sortBy (strings,'value.length');
338
+ ................................................
339
+
340
+ Sort an Array of People Records by lastName Property
341
+ A records array, where each element is an object containing data for a person, can be sorted by last name with a simple `Sort Value Generator Expression` that returns the value of the =lastName= property of a value.
342
+
343
+ EXAMPLE
344
+ ........................................................
345
+ Uize.Array.Sort.sortBy (peopleRecords,'value.lastName');
346
+ ........................................................
347
+
348
+ Sort an Array of People Records in lastName,firstName Order
349
+ A records array, where each element is an object containing data for a person, can be sorted by last name and subsorted by first name, with a `Sort Value Generator Expression` that concatenates the values of the =lastName= and =firstName= properties of a value.
350
+
351
+ EXAMPLE
352
+ ................................................................................
353
+ Uize.Array.Sort.sortBy (peopleRecords,'value.lastName + "," + value.firstName');
354
+ ................................................................................
355
+
356
+ Notice that a "," (comma character) is used as a delimiter between last name and first name. This is in order to avoid ambiguities that may arise if a first segment of one person's last name is coincidentally a last segment of someone else's first name. The comma forces a reliable split between the sort and subsort, because nobody's first or last name will contain a comma.
357
+
358
+ Sort an Array of Row Arrays By The Second Column
359
+ A rows array, where each element is an array representing a row of data in a data table, can be sorted by a specific column simply by specifying the column number for the =Uize.Array.Sort.sortBy= method's =sortColumnINT= parameter.
360
+
361
+ EXAMPLE
362
+ ................................
363
+ Uize.Array.Sort.sortBy (rows,1);
364
+ ................................
365
+
366
+ Column indexes are zero based, so specifying the value =1= in the above example will sort the =rows= data table array by the values in the second column.
367
+
368
+ Sort an Array of Strings That Are Decimal Numbers
369
+ An array of strings that are decimal formatted numbers can be sorted numerically (rather than ASCIIbetically), by specifying a simple `Sort Value Generator Expression` that returns an element's value coerced to a number.
370
+
371
+ EXAMPLE
372
+ ................................................
373
+ Uize.Array.Sort.sortBy (numberStrings,'+value');
374
+ ................................................
375
+
376
+ Coercing the string type element values to numbers is accomplished quite easily by simply prefixing the "+" (plus) operator in the expression.
377
+
378
+ Sort an Array of Strings That are Hex Formatted Numbers
379
+ An array of strings that are hexadecimal formatted numbers can be sorted numerically (rather than ASCIIbetically), by specifying a simple `Sort Value Generator Expression` that returns an element's value coerced to a decimal number.
380
+
381
+ EXAMPLE
382
+ ............................................................
383
+ Uize.Array.Sort.sortBy (hexNumberStrings,'+("0x" + value)');
384
+ ............................................................
385
+
386
+ It is assumed in this example that the hex formatted numbers are *not* prefixed with any kind of hex formatting indicator (such as "0x" for programming languages, or "#" for RGB color values in CSS). The hex numbers are coerced to decimal by prepending the "0x" and then coercing the resulting string to a number by prefixing the "+" (plus) operator in the `Sort Value Generator Expression`.
387
+
388
+ Sort an Array of Date Strings
389
+ An array of correctly formatted date strings can be sorted into chronological order, by specifying a `Sort Value Generator Expression` that transforms a date string value into a number, representing the date as the number of milliseconds elapsed since January 1st, 1970 (ie. POSIX time).
390
+
391
+ EXAMPLE
392
+ ...........................................................
393
+ Uize.Array.Sort.sortBy (dateStrings,'+(new Date (value))');
394
+ ...........................................................
395
+
396
+ A date string value is transformed into a POSIX time number by first using JavaScript's built-in =Date= object to parse the date string and create a =Date= object instance. The =Date= object instance is then coerced to a number by using the "+" (plus) operator, which invokes the =Date= object's =valueOf Intrinsic Method=.
397
+
398
+ Sort an Array of Date Objects
399
+ An array of =Date= object instances can be sorted into chronological order, by specifying a `Sort Value Generator Expression` that transforms a =Date= object instance into a number, representing the date as the number of milliseconds elapsed since January 1st, 1970 (ie. POSIX time).
400
+
401
+ EXAMPLE
402
+ ..............................................
403
+ Uize.Array.Sort.sortBy (dateObjects,'+value');
404
+ ..............................................
405
+
406
+ A =Date= object instance is transformed into a POSIX time number by simply using the "+" (plus) operator, which invokes the =Date= object's =valueOf Intrinsic Method=.
407
+
408
+ Sort Cubes by Volume, Smallest to Largest
409
+ An array of objects representing geometric cubes can be sorted according to their volumes, from smallest volume to largest volume, by specifying a `Sort Value Generator Expression` that calculates the volume for a cube from its =width=, =height=, and =depth= properties.
410
+
411
+ EXAMPLE
412
+ ..........................................................................
413
+ Uize.Array.Sort.sortBy (cubes,'value.width * value.height * value.depth');
414
+ ..........................................................................
415
+
416
+ Each value of the =cubes= array is an object containing =width=, =height=, and =depth= properties that describe a cube's dimensions. A `Sort Value Generator Expression` can calculate the volume for an element of the =cubes= array by dereferencing the =width=, =height=, and =depth= properties on the =value= variable and multiplying them together.
417
+
418
+ Sort Rectangles by Squarest, Most Square to Least Square
419
+ An array of objects representing rectangles can be sorted according to their squareness, from most square to least square, by specifying a `Sort Value Generator Expression` that calculates an aspect ratio for a rectangle from its =width= and =height= properties.
420
+
421
+ EXAMPLE
422
+ ..............................................................................
423
+ Uize.Array.Sort.sortBy (
424
+ rectangles,
425
+ 'Math.max (value.width,value.height) / Math.min (value.width,value.height)'
426
+ );
427
+ ..............................................................................
428
+
429
+ Each value of the =rectangles= array is an object containing =width= and =height= properties that describe a rectangle's dimensions. A `Sort Value Generator Expression` can calculate the aspect ratio for an element of the =rectangles= array by dereferencing the =width= and =height= properties of the =value= variable and dividing the maximum axis dimension by the minimum axis dimension.
430
+
431
+ According to this calculation, a perfectly square rectangle will have an aspect ratio of =1=. The more unsquare a rectangle is, the higher the calculated aspect ratio value. By always dividing the maximum axis dimension by the minimum axis dimension, the aspect ratio is guaranteed to always be =1= or greater, rather than being less than =1= for rectangles whose =width= is smaller than their =height= (ie. where orientation is landscape rather than portrait). Now, sorting the generated sort values into ascending order, the elements of the =rectangles= array are sorted according to how close to square they are.
432
+
433
+ Sort Array of Numbers By Closeness to a Reference Number
434
+ An array of numbers can be sorted according to how close they are to a reference number, from closest to furthest away, by specifying a `Sort Value Generator Expression` that calculates for a number its absolute distance from the reference number.
435
+
436
+ EXAMPLE
437
+ ..............................................................................
438
+ Uize.Array.Sort.sortBy (numbers,'Math.abs (' + referenceNumber + ' - value)');
439
+ ..............................................................................
440
+
441
+ Because we are using a `Sort Value Generator Expression` rather than a `Sort Value Generator Function` in our example, we can fix the value of the =referenceNumber= variable into the expression using string concatenation. We use the =Math.abs= method of JavaScript's built-in =Math= object to ensure that the calculated distance is always positive - this ensures that numbers are sorted based on their closeness to the reference number, regardless of on which side of the reference number they fall. Now, sorting the generated sort values into ascending order, the elements of the =numbers= array are sorted according to how close they are to the reference number.
442
+
443
+ Sort Array of Names in Case-insensitive ASCIIbetical Order
444
+ An array of strings can be sorted into case-insensitive ASCIIbetical order, by specifying a `Sort Value Generator Expression` that generates a lower case version of a string value.
445
+
446
+ EXAMPLE
447
+ ......................................................
448
+ Uize.Array.Sort.sortBy (names,'value.toLowerCase ()');
449
+ ......................................................
450
+
451
+ In this example, when the elements of the =names= array are sorted according to the lower case, generated sort values, the elements are effectively sorted in a case-insensitive manner, since all the letters of all the sort value strings are guaranteed to be lower case.
452
+
453
+ Sort Array of RGB Color Objects By Blackness, Blackest to Whitest
454
+ An array of objects representing RGB colors can be sorted according to their blackness, from blackest to whitest, by specifying a `Sort Value Generator Function` that calculates the distance of a color from black in three dimensional RGB color space.
455
+
456
+ EXAMPLE
457
+ .................................................................................
458
+ Uize.Array.Sort.sortBy (
459
+ rgbColorObjects,
460
+ function (rgb) {
461
+ return Math.sqrt (
462
+ Math.pow (Math.sqrt (Math.pow (rgb.red,2) + Math.pow (rgb.green,2)),2) +
463
+ Math.pow (rgb.blue,2)
464
+ );
465
+ }
466
+ );
467
+ .................................................................................
468
+
469
+ Each value of the =rgbColorObjects= array is an object containing =red=, =green=, and =blue= properties that indicate the values of the three RGB color channels for a color. A `Sort Value Generator Function` can calculate a color's distance from black in three dimensional RGB color space by simply treating the color channels as dimensions like width, height, and depth.
470
+
471
+ Calculating distance in three dimensional space involves two successive hypotenuse-of-a-triangle calculations (square root of the sum of the squares) - the first calculates a distance in two of the three dimensions, and the second uses the first distance as one of the sides of a right angled triangle to calculate the final distance in three dimensional space. Our calculation in the `Sort Value Generator Function` is made simpler by the fact that our reference color is black, which is represented by zeros for each of the color channels, so there is no delta calculation needed for each of the color channels.
472
+
473
+ Randomly Shuffle the Elements in an Array
474
+ The order of the elements in an array can be randomly shuffled, by specifying a `Sort Value Generator Function` that generates a random number.
475
+
476
+ EXAMPLE
477
+ ..............................................
478
+ Uize.Array.Sort.sortBy (elements,Math.random);
479
+ ..............................................
480
+
481
+ Randomly shuffling the order of elements in an array is not influenced by the values of the elements, nor is this process influenced by the original order of the elements, so we use neither the =value= nor the =key= variable in our expression. Instead, we simply supply a `Sort Value Generator Function` that doesn't expect any input parameters and that always returns a random number. The =Math.random= method of JavaScript's built-in =Math= object fits the bill. Sorting the array using a set of randomly generated sort values has the effect of randomly shuffling the order of the elements in the array.
482
+
483
+ While the above technique works, it's worth noting that a better performing way of shuffling the elements of an array is to use the =Uize.Array.Order.jumble= static method of the =Uize.Array.Order= module.
484
+
485
+ Reverse the Elements in an Array
486
+ The order of the elements in an array can be reversed, by specifying a `Sort Value Generator Expression` that subtracts the index for an element from the length of the array.
487
+
488
+ EXAMPLE
489
+ .............................................................
490
+ Uize.Array.Sort.sortBy (elements,elements.length + ' - key');
491
+ .............................................................
492
+
493
+ Because we are using a `Sort Value Generator Expression` rather than a `Sort Value Generator Function` in our example, we can fix the array's length into the expression using string concatenation. Reversing the order of elements in an array is not influenced by the values of the elements, so we don't use the =value= variable in our expression. Instead, we use the =key= variable and subtract that from the array's length. This results in sort values that descend in value, starting from the length of the array for the first element, and ending with the value =1= for the last element. Sorting the array using these sort values has the effect of reversing the order of the elements.
494
+
495
+ While the above technique works, it's worth noting that a better performing way of reversing the order of the elements of an array is to use the =Uize.Array.Order.reverse= static method of the =Uize.Array.Order= module, or the =reverse= instance method of JavaScript's built-in =Array= object.
496
+
497
+ It should also be noted that the order of the elements in an array can be reversed by specifying the value =-1= for the =Uize.Array.Sort.sortBy= method's optional =directionINT= parameter, as follows...
498
+
499
+ ...........................................
500
+ Uize.Array.Sort.sortBy (elements,'key',-1);
501
+ ...........................................
502
+
503
+ When we use the =directionINT= parameter to reverse the sort direction, we no longer need to use the array's length in the `Sort Value Generator Expression`. Instead, we can have a simpler expression that simply returns the key / index.
504
+ */
505
+ };
506
+
507
+ return _package;
508
+ }
509
+ });
510
+
skin/frontend/default/customproduct/js/Uize.Array.Util.js ADDED
@@ -0,0 +1,206 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ /*______________
2
+ | ______ | U I Z E J A V A S C R I P T F R A M E W O R K
3
+ | / / | ---------------------------------------------------
4
+ | / O / | MODULE : Uize.Array.Util Package
5
+ | / / / |
6
+ | / / / /| | ONLINE : http://www.uize.com
7
+ | /____/ /__/_| | COPYRIGHT : (c)2011-2012 UIZE
8
+ | /___ | LICENSE : Available under MIT License or GNU General Public License
9
+ |_______________| http://www.uize.com/license.html
10
+ */
11
+
12
+ /* Module Meta Data
13
+ type: Package
14
+ importance: 1
15
+ codeCompleteness: 100
16
+ testCompleteness: 100
17
+ docCompleteness: 100
18
+ */
19
+
20
+ /*?
21
+ Introduction
22
+ The =Uize.Array.Util= module provides a number of miscellaneous utility methods for manipulating arrays.
23
+
24
+ *DEVELOPERS:* `Chris van Rensburg`
25
+ */
26
+
27
+ Uize.module ({
28
+ name:'Uize.Array.Util',
29
+ builder:function () {
30
+ /*** Variables for Scruncher Optimization ***/
31
+ var
32
+ _package = function () {},
33
+ _undefined = undefined,
34
+ _ArrayPrototype = Array.prototype,
35
+ _ArrayPush = _ArrayPrototype.push,
36
+ _ArrayConcat = _ArrayPrototype.concat,
37
+ _ArraySplice = _ArrayPrototype.splice,
38
+ _Infinity = Infinity,
39
+ _fullArraySpliceArgs = [0,_Infinity]
40
+ ;
41
+
42
+ /*** Public Static Methods ***/
43
+ _package.replaceContents = function (_array1,_array2) {
44
+ if (_array1 != _array2) {
45
+ _array1.length = 0;
46
+ _array2 && _array2.length && _ArrayPush.apply (_array1,_array2);
47
+ }
48
+ return _array1;
49
+ /*?
50
+ Static Methods
51
+ Uize.Array.Util.replaceContents
52
+ Replaces the contents of the first array with the contents of the second array, and returns a reference to the first array.
53
+
54
+ SYNTAX
55
+ ........................................................................
56
+ array1ARRAY = Uize.Array.Util.replaceContents (array1ARRAY,array2ARRAY);
57
+ ........................................................................
58
+
59
+ EXAMPLE
60
+ ............................................................
61
+ var
62
+ foods = ['bacon','sausage','omelette'],
63
+ vegetables = ['potato','beans','mushrooms']
64
+ ;
65
+ Uize.Array.Util.replaceContents (foods,vegetables);
66
+ alert (foods); // displays the text "potato,beans,mushrooms"
67
+ ............................................................
68
+
69
+ In the above example, the contents of the =foods= array (which clearly contains some rather unhealthy food types) is being replaced with the contents of the healthier =vegetables= array. When the value of the =foods= array is then alerted, we see the text "potato,beans,mushrooms".
70
+
71
+ VARIATION
72
+ ............................................................
73
+ array1ARRAY = Uize.Array.Util.replaceContents (array1ARRAY);
74
+ ............................................................
75
+
76
+ When no =array2ARRAY= parameter is specified, or if the value =undefined= or =null= is specified for the =array2ARRAY= parameter, then the array specified by the =array1ARRAY= parameter will be emptied out.
77
+
78
+ NOTES
79
+ - see the related =Uize.Array.Util.swapContents= static method
80
+ */
81
+ };
82
+
83
+ _package.swapContents = function (_array1,_array2) {
84
+ if (_array1 != _array2) {
85
+ _ArrayPush.apply (
86
+ _array1,
87
+ _ArraySplice.apply (_array2,_fullArraySpliceArgs.concat (_array1.splice (0,_Infinity)))
88
+ );
89
+ }
90
+ return _array1;
91
+ /*?
92
+ Static Methods
93
+ Uize.Array.Util.swapContents
94
+ Swaps the contents of the two specified arrays, and returns a reference to the first array.
95
+
96
+ SYNTAX
97
+ .....................................................................
98
+ array1ARRAY = Uize.Array.Util.swapContents (array1ARRAY,array2ARRAY);
99
+ .....................................................................
100
+
101
+ EXAMPLE
102
+ ......................................................................
103
+ var
104
+ healthyFoods = ['bacon','sausage','omelette'],
105
+ unhealthyFoods = ['potato','beans','mushrooms']
106
+ ;
107
+ Uize.Array.Util.swapContents (healthyFoods,unhealthyFoods);
108
+ alert (healthyFoods); // displays the text "potato,beans,mushrooms"
109
+ alert (unhealthyFoods); // displays the text "bacon,sausage,omelette"
110
+ ......................................................................
111
+
112
+ In the above example, the contents of the =healthyFoods= and =unhealthyFoods= arrays are clearly mixed up. In order to correct this, the contents of the two arrays can be swapped. We can't just swap the variable references around, since other code may already have references to the arrays. What we really want to do is fix their contents. We can do this using the =Uize.Array.Util.swapContents= method.
113
+
114
+ NOTES
115
+ - see the related =Uize.Array.Util.replaceContents= static method
116
+ */
117
+ };
118
+
119
+ _package.flatten = function (_sourceArray,_depth,_target) {
120
+ _depth = _depth == _undefined ? _Infinity : +_depth || 0;
121
+ var
122
+ _workingArray = _sourceArray,
123
+ _workingArrayPreviousLength,
124
+ _flattenedDepth = 0
125
+ ;
126
+ while (_flattenedDepth++ < _depth && _workingArray.length != _workingArrayPreviousLength) {
127
+ _workingArrayPreviousLength = _workingArray.length;
128
+ _workingArray = _ArrayConcat.apply ([],_workingArray);
129
+ }
130
+ return (
131
+ _target !== true
132
+ ? _package.replaceContents (_target || _sourceArray,_workingArray)
133
+ : _workingArray != _sourceArray
134
+ ? _workingArray
135
+ : _sourceArray.concat ()
136
+ );
137
+ /*?
138
+ Static Methods
139
+ Uize.Array.Util.flatten
140
+ Flattens the elements of the specified source array and returns the flattened array.
141
+
142
+ SYNTAX
143
+ ..................................................................................
144
+ flattenedARRAY = Uize.Array.Util.flatten (sourceARRAY,depthINT,targetARRAYorBOOL);
145
+ ..................................................................................
146
+
147
+ VARIATION 1
148
+ ................................................................
149
+ flattenedARRAY = Uize.Array.Util.flatten (sourceARRAY,depthINT);
150
+ ................................................................
151
+
152
+ When the optional =depthINT= parameter is specified, then the depth level to which the source array should be flattened can be controlled. When the value =0= is specified for this parameter, the source array will remain unflattened. When the value =1= is specified, then this method will `flatten an array to one level deep`. When the value =2= is specified, then this method will `flatten an array to two levels deep`. When the =depthINT= parameter is not specified, then this method will `flatten an array to infinite depth`.
153
+
154
+ VARIATION 2
155
+ ................................................................
156
+ flattenedARRAY = Uize.Array.Util.flatten (sourceARRAY,depthINT,targetARRAYorBOOL);
157
+ ................................................................
158
+
159
+ When the optional =targetARRAYorBOOL= parameter is specified, then the target for the flattened contents of the source array can be controlled. When the value =true= is specified for the =targetARRAYorBOOL= parameter, then the target for the flattened contents of the source array will be a new array and the source array will not be modified. When the =false= is specified for the =targetARRAYorBOOL= parameter, then the flattened contents of the source array will replace the unflattened contents of the source array. When an array is specified for the =targetARRAYorBOOL= parameter, then the flattened contents of the source array will replace the contents of the specified target array.
160
+
161
+ Examples
162
+ Flatten an Array to One Level Deep
163
+ When the value =1= is specified for the optional =depthINT= parameter, then the source array will be flattened one level deep.
164
+
165
+ EXAMPLE
166
+ ......................................................................
167
+ Uize.Array.Util.flatten ([0,[1,[2,[3,[4,[5,[6,6],5],4],3],2],1],0],1);
168
+ ......................................................................
169
+
170
+ RESULT
171
+ .......................................
172
+ [0,1,[2,[3,[4,[5,[6,6],5],4],3],2],1,0]
173
+ .......................................
174
+
175
+ Flatten an Array to Two Levels Deep
176
+ When the value =2= is specified for the optional =depthINT= parameter, then the source array will be flattened one level deep.
177
+
178
+ EXAMPLE
179
+ ......................................................................
180
+ Uize.Array.Util.flatten ([0,[1,[2,[3,[4,[5,[6,6],5],4],3],2],1],0],2);
181
+ ......................................................................
182
+
183
+ RESULT
184
+ .....................................
185
+ [0,1,2,[3,[4,[5,[6,6],5],4],3],2,1,0]
186
+ .....................................
187
+
188
+ Flatten an Array to Infinite Depth
189
+ When the optional =depthINT= parameter is not specified, then the source array will be flattened to infinite depth (ie. until all elements are no longer arrays).
190
+
191
+ EXAMPLE
192
+ ....................................................................
193
+ Uize.Array.Util.flatten ([0,[1,[2,[3,[4,[5,[6,6],5],4],3],2],1],0]);
194
+ ....................................................................
195
+
196
+ RESULT
197
+ .............................
198
+ [0,1,2,3,4,5,6,6,5,4,3,2,1,0]
199
+ .............................
200
+ */
201
+ };
202
+
203
+ return _package;
204
+ }
205
+ });
206
+
skin/frontend/default/customproduct/js/Uize.Array.js ADDED
@@ -0,0 +1,28 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ /*______________
2
+ | ______ | U I Z E J A V A S C R I P T F R A M E W O R K
3
+ | / / | ---------------------------------------------------
4
+ | / O / | MODULE : Uize.Array Package
5
+ | / / / |
6
+ | / / / /| | ONLINE : http://www.uize.com
7
+ | /____/ /__/_| | COPYRIGHT : (c)2010-2012 UIZE
8
+ | /___ | LICENSE : Available under MIT License or GNU General Public License
9
+ |_______________| http://www.uize.com/license.html
10
+ */
11
+
12
+ /* Module Meta Data
13
+ type: Package
14
+ importance: 4
15
+ codeCompleteness: 100
16
+ testCompleteness: 100
17
+ docCompleteness: 100
18
+ */
19
+
20
+ /*?
21
+ Introduction
22
+ The =Uize.Array= module defines a namespace for various modules that provide array specific functionality or utilities.
23
+
24
+ *DEVELOPERS:* `Chris van Rensburg`
25
+ */
26
+
27
+ Uize.module ({name:'Uize.Array'});
28
+
skin/frontend/default/customproduct/js/Uize.Build.All.js ADDED
@@ -0,0 +1,68 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ /*______________
2
+ | ______ | U I Z E J A V A S C R I P T F R A M E W O R K
3
+ | / / | ---------------------------------------------------
4
+ | / O / | MODULE : Uize.Build.All Package
5
+ | / / / |
6
+ | / / / /| | ONLINE : http://www.uize.com
7
+ | /____/ /__/_| | COPYRIGHT : (c)2010-2012 UIZE
8
+ | /___ | LICENSE : Available under MIT License or GNU General Public License
9
+ |_______________| http://www.uize.com/license.html
10
+ */
11
+
12
+ /* Module Meta Data
13
+ type: Package
14
+ importance: 7
15
+ codeCompleteness: 100
16
+ testCompleteness: 0
17
+ docCompleteness: 2
18
+ */
19
+
20
+ /*?
21
+ Introduction
22
+ The =Uize.Build.All= module provides a method for running all the build scripts necessary for building the UIZE JavaScript Framework in the correct sequence.
23
+
24
+ *DEVELOPERS:* `Chris van Rensburg`
25
+ */
26
+
27
+ Uize.module ({
28
+ name:'Uize.Build.All',
29
+ required:'Uize.Build.Util',
30
+ builder:function () {
31
+ var _package = function () {};
32
+
33
+ /*** Public Static Methods ***/
34
+ _package.perform = function (_params) {
35
+ var
36
+ _startTime = Uize.now (),
37
+ _buildSequence = _params.buildSequence,
38
+ _buildError
39
+ ;
40
+ Uize.require (
41
+ _buildSequence,
42
+ function () {
43
+ Uize.forEach (
44
+ _buildSequence,
45
+ function (_buildModuleName) {
46
+ eval (_buildModuleName).perform (
47
+ Uize.copyInto ({},_params,{logFilePath:'logs/' + _buildModuleName + '.log'})
48
+ );
49
+ }
50
+ );
51
+ if (_params.test == 'true')
52
+ _buildError = Uize.Build.Util.runScripts (_params.testSequence)
53
+ ;
54
+ _params.silent == 'true' ||
55
+ alert (
56
+ _buildError
57
+ ? ('BUILD FAILED IN THE FOLLOWING SCRIPT:\n\n' + _buildError.script)
58
+ : 'BUILD ALL COMPLETE!!! (duration: ' + Math.round ((Uize.now () - _startTime) / 1000) + 's)'
59
+ )
60
+ ;
61
+ }
62
+ );
63
+ };
64
+
65
+ return _package;
66
+ }
67
+ });
68
+
skin/frontend/default/customproduct/js/Uize.Build.AuditStrings.js ADDED
@@ -0,0 +1,215 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ /*______________
2
+ | ______ | U I Z E J A V A S C R I P T F R A M E W O R K
3
+ | / / | ---------------------------------------------------
4
+ | / O / | MODULE : Uize.Build.AuditStrings Package
5
+ | / / / |
6
+ | / / / /| | ONLINE : http://www.uize.com
7
+ | /____/ /__/_| | COPYRIGHT : (c)2009-2012 UIZE
8
+ | /___ | LICENSE : Available under MIT License or GNU General Public License
9
+ |_______________| http://www.uize.com/license.html
10
+ */
11
+
12
+ /* Module Meta Data
13
+ type: Package
14
+ importance: 1
15
+ codeCompleteness: 90
16
+ testCompleteness: 0
17
+ docCompleteness: 5
18
+ */
19
+
20
+ /*?
21
+ Introduction
22
+ The =Uize.Build.AuditStrings= package provides a method to audit all JavaScript files in a folder for literal strings - useful for internationalization.
23
+
24
+ *DEVELOPERS:* `Chris van Rensburg`
25
+
26
+ The =Uize.Build.AuditStrings= module is designed specifically to run in the context of Windows Script Host.
27
+ */
28
+
29
+ /*
30
+ TO DO:
31
+ What's still being missed that should be recognized as non-internationalizable...
32
+ 250x155 - width x height in pixels
33
+
34
+ imageTextSpacingX - not being recognized as camelCase identifier because last capital is not followed by any lowercase characters
35
+
36
+ disableGSDProducts, fixedPPI - consecutive caps
37
+
38
+ &amp; - any single entity should be filtered out
39
+
40
+ <zz:error_image_src> - just a tag, without contents should be detectable (open or close tags)
41
+ </tr><tr> - catch one or more just tags in a row (eg. <br/><br/><br/>)
42
+
43
+ Content-length, Content-type - specific HTTP headers
44
+
45
+ -1000px - /^(-?\d+)?px$/
46
+
47
+ womens_laceup_heel_womens5.5 - it looks like an identifier with underscores, but there's a period
48
+
49
+ sz500 - a word with multiple digits
50
+
51
+ top= - fragments of code (how to identify them?)
52
+
53
+ -jiggler - hyphen starts a word
54
+
55
+ pd - two or more adjacent letters with no vowels (lowercase or uppercase)
56
+
57
+ - ff00ff - six letter hex format strings should be filtered to LIKELY NON-INTERNATIONALIZABLE STRINGS
58
+
59
+ - miscellaneous
60
+ price?input=js&output=js
61
+ MultiProductFactory_form-designData
62
+ ?private=true
63
+ &end=
64
+ create/
65
+ icon_medium icon_medium-
66
+ .value
67
+ _ctgy_in.value
68
+ window.parent.parent.document.frmParms.mat
69
+ resizable=yes,status=no,scrollbars=yes,location=no,toolbar=no,directories=no,menubar=no,width=470,innerWidth=470,height=400,innerHeight=400
70
+
71
+ - switches
72
+ - a switch for levels of doubt
73
+ 1: show only LIKELY INTERNATIONALIZABLE STRINGS
74
+ 2: show LIKELY INTERNATIONALIZABLE STRINGS, POSSIBLY INTERNATIONALIZABLE STRINGS
75
+ 3: show LIKELY INTERNATIONALIZABLE STRINGS, POSSIBLY INTERNATIONALIZABLE STRINGS, LIKELY NON-INTERNATIONALIZABLE STRINGS
76
+ 4: show LIKELY INTERNATIONALIZABLE STRINGS, POSSIBLY INTERNATIONALIZABLE STRINGS, LIKELY NON-INTERNATIONALIZABLE STRINGS, NON-INTERNATIONALIZABLE STRINGS
77
+ - a switch for not showing headings for empty buckets
78
+ - a switch for not showing files for which all buckets that would be displayed are empty
79
+
80
+ - summary for overal totals for all buckets, per file, and for all files
81
+ - ability to supply additional dictionaries of known non-internationalizable strings and likely non-internationalizable strings, and regular expressions as well
82
+ - idea: summary for cases where creating a variable for a string that is repeatedly used would save some space when the file is scrunched
83
+ */
84
+
85
+ Uize.module ({
86
+ name:'Uize.Build.AuditStrings',
87
+ required:[
88
+ 'Uize.Build.Util',
89
+ 'Uize.Build.Scruncher',
90
+ 'Uize.String'
91
+ ],
92
+ builder:function () {
93
+ /*** Variables for Scruncher Optimization ***/
94
+ var _package = function () {};
95
+
96
+ /*** General Variables ***/
97
+ var
98
+ _eventNames = [
99
+ 'abort', 'activate', 'afterupdate', 'beforedeactivate', 'beforeeditfocus', 'beforeupdate', 'blur', 'cellchange', 'change', 'click', 'dblclick', 'deactivate', 'drag', 'dragend', 'dragenter', 'dragleave', 'dragover', 'drop', 'error', 'finish', 'focus', 'help', 'keydown', 'keypress', 'keyup', 'load', 'losecapture', 'mousedown', 'mousemove', 'mouseup', 'mouseout', 'mouseover', 'propertychange', 'readystatechange', 'rowenter', 'rowexit', 'rowsdelete', 'rowsinserted', 'scroll', 'submit', 'start', 'unload'
100
+ ],
101
+ _nonI18nStringsDictionary = [
102
+ /*** pretty JavaScript-specific value types ***/
103
+ 'function', 'object', 'string', 'undefined', // maybe these should be in a likely list?
104
+
105
+ /*** properties/attributes that are distinctive enough ***/
106
+ 'alt', 'href', 'src',
107
+
108
+ /*** JavaScript-specific acronyms ***/
109
+ 'ajax', 'json', 'CSS1Compat',
110
+
111
+ /*** HTML tag names that are distinctive enough ***/
112
+ 'div', 'DIV', 'hr', 'HR', 'iframe', 'IFRAME', 'img', 'IMG', 'li', 'LI', 'ol', 'OL', 'span', 'SPAN', 'td', 'TD', 'textarea', 'TEXTAREA', 'tr', 'TR', 'ul', 'UL',
113
+
114
+ /*** file extensions ***/
115
+ '.asp', '.ASP', '.gif', '.html', '.jpg', '.js', '.jst', '.png', '.PNG', '.txt', '.xhtml', '.xml' // this could be in a regular expression, with leading period optional, and case insensitive, perhaps it would be good to add a filename match, to catch things like, filename.gif, .gif, and gif (ie. patterns like [[filename].]gif|jpg|html)
116
+ ].concat (
117
+ _eventNames,
118
+ Uize.map (_eventNames,'\'on\' + value')
119
+ ),
120
+ _nonI18nStringsDictionaryLookup
121
+ ;
122
+
123
+ /*** Public Static Methods ***/
124
+ _package.perform = function (_params) {
125
+ var
126
+ _endsWithDotJsRegExp = /\.js$/,
127
+ _sourceFolderName = _params.sourceFolderName
128
+ ;
129
+ if (!_nonI18nStringsDictionaryLookup)
130
+ _nonI18nStringsDictionaryLookup = Uize.lookup (_nonI18nStringsDictionary)
131
+ ;
132
+ Uize.Build.Util.buildFiles (
133
+ Uize.copyInto (
134
+ {
135
+ targetFolderPathCreator:function (_folderPath) {
136
+ return Uize.String.endsWith (_folderPath,_sourceFolderName) ? _folderPath : null;
137
+ },
138
+ targetFilenameCreator:function (_sourceFileName) {
139
+ return _endsWithDotJsRegExp.test (_sourceFileName) ? _sourceFileName : null;
140
+ },
141
+ fileBuilder:function (_sourceFileName,_sourceFileText) {
142
+ var
143
+ _scruncherResult = Uize.Build.Scruncher.scrunch (_sourceFileText,{AUDITSTRINGS:true}),
144
+ _stringsMap = _scruncherResult.stringsMap,
145
+ _strings = Uize.keys (_stringsMap),
146
+ _nonI18nStrings = [],
147
+ _likelyNonI18nStrings = [],
148
+ _possibleI18nStrings = [],
149
+ _likelyI18nStrings = []
150
+ ;
151
+ _strings.sort ();
152
+ for (var _stringNo = -1, _stringsLength = _strings.length; ++_stringNo < _stringsLength;) {
153
+ var _string = _strings [_stringNo];
154
+ (
155
+ _nonI18nStringsDictionaryLookup [_string] ||
156
+ // ignore strings that are recognized as non-internationalizable strings
157
+ !/\S/.test (_string) ||
158
+ // ignore strings that are only whitespace (spaces, tabs, linebreaks, etc.)
159
+ !/[a-zA-Z]/.test (_string) ||
160
+ // ignore strings that have no letter characters
161
+ /^(#|0x)([0-9a-fA-F]{3}){1,2}$/.test (_string) ||
162
+ // ignore hex RGB color values
163
+ /^[A-Z][a-zA-Z0-9$_]*(\.[a-zA-Z0-9$_]+)+$/.test (_string) ||
164
+ // ignore what look like module names
165
+ /^Uize/i.test (_string) ||
166
+ // if it starts with "Uize", it's related to the framework
167
+ /^[a-zA-Z0-9$_]*_[a-zA-Z0-9$_]*$/.test (_string) ||
168
+ // ignore what look like underscore delimited identifiers
169
+ /^Changed\.(\*|[a-zA-Z0-1]+)$/.test (_string) ||
170
+ // ignore Changed.[propertyName] events
171
+ /^\S*[\/\\][\w_]+[\/\\]\S*$/.test (_string) ||
172
+ // ignore what look like URL paths
173
+ /^\$?[a-zA-Z][a-z0-9]*([A-Z][a-z0-9]+)+$/.test (_string)
174
+ // ignore what look obviously like camelCase identifiers
175
+ /* TO DO: catch strings that are only numbers */
176
+ ? _nonI18nStrings
177
+ : (
178
+ /[a-zA-Z]{2,}/.test (_string) &&
179
+ // string must have at least two consecutive word characters
180
+ !/^\S*[\w_]+[\/\\][\w_]+\S*$/.test (_string)
181
+ // ignore what could be short URL snippets
182
+ ? (
183
+ /\b[a-zA-Z][a-z]*\s[a-z]+\s[a-zA-Z][a-z]*\b/.test (_string)
184
+ ? _likelyI18nStrings
185
+ : _possibleI18nStrings
186
+ ) : _likelyNonI18nStrings
187
+ )
188
+ ).push (_string + ' --- ' + _stringsMap [_string]);
189
+ }
190
+ return {
191
+ logDetails:
192
+ '\t\tNON-INTERNATIONALIZABLE STRINGS\n' +
193
+ Uize.String.hugJoin (_nonI18nStrings,'\t\t\t','\n') + '\n' +
194
+ '\t\tLIKELY NON-INTERNATIONALIZABLE STRINGS\n' +
195
+ Uize.String.hugJoin (_likelyNonI18nStrings,'\t\t\t','\n') + '\n' +
196
+ '\t\tPOSSIBLY INTERNATIONALIZABLE STRINGS\n' +
197
+ Uize.String.hugJoin (_possibleI18nStrings,'\t\t\t','\n') + '\n' +
198
+ '\t\tLIKELY INTERNATIONALIZABLE STRINGS\n' +
199
+ Uize.String.hugJoin (_likelyI18nStrings,'\t\t\t','\n')
200
+ };
201
+ }
202
+ },
203
+ _params,
204
+ {
205
+ alwaysBuild:true,
206
+ dryRun:true
207
+ }
208
+ )
209
+ );
210
+ };
211
+
212
+ return _package;
213
+ }
214
+ });
215
+
skin/frontend/default/customproduct/js/Uize.Build.AutoScruncher.js ADDED
@@ -0,0 +1,217 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ /*______________
2
+ | ______ | U I Z E J A V A S C R I P T F R A M E W O R K
3
+ | / / | ---------------------------------------------------
4
+ | / O / | MODULE : Uize.Build.AutoScruncher Package
5
+ | / / / |
6
+ | / / / /| | ONLINE : http://www.uize.com
7
+ | /____/ /__/_| | COPYRIGHT : (c)2005-2012 UIZE
8
+ | /___ | LICENSE : Available under MIT License or GNU General Public License
9
+ |_______________| http://www.uize.com/license.html
10
+ */
11
+
12
+ /* Module Meta Data
13
+ type: Package
14
+ importance: 8
15
+ codeCompleteness: 100
16
+ testCompleteness: 0
17
+ docCompleteness: 2
18
+ */
19
+
20
+ /*?
21
+ Introduction
22
+ The =Uize.Build.AutoScruncher= package provides a method to recurse a folder structure and scrunch (minify / compress) and obfuscate JavaScript source.
23
+
24
+ *DEVELOPERS:* `Chris van Rensburg`
25
+
26
+ The =Uize.Build.AutoScruncher= module is designed specifically to run in the context of Windows Script Host.
27
+ */
28
+
29
+ Uize.module ({
30
+ name:'Uize.Build.AutoScruncher',
31
+ required:[
32
+ 'Uize.Wsh',
33
+ 'Uize.Build.Util',
34
+ 'Uize.Build.Scruncher',
35
+ 'Uize.Date',
36
+ 'Uize.String',
37
+ 'Uize.String.Lines',
38
+ 'Uize.Util.Oop'
39
+ ],
40
+ builder:function () {
41
+ /*** Variables for Scruncher Optimization ***/
42
+ var _package = function () {};
43
+
44
+ /*** Public Static Methods ***/
45
+ _package.perform = function (_params) {
46
+ var
47
+ _buildDate = Uize.Date.toIso8601 (),
48
+ _endsWithDotJsRegExp = /\.js$/,
49
+ _buildScriptName = WScript.ScriptName,
50
+ _scrunchedHeadComments = _params.scrunchedHeadComments || {},
51
+ _scruncherPrefixChars = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ',
52
+ _currentFolderPath,
53
+ _buildFolderPath = _params.buildFolderPath,
54
+ _sourceFolderName = _params.sourceFolderName,
55
+ _rootPath = Uize.Wsh.getScriptFolderPath (),
56
+ _fullModuleFolderPath = _rootPath + '\\' + _params.moduleFolderPath
57
+ ;
58
+ function _targetFolderPathCreator (_folderPath) {
59
+ var _sourceFolderNameLength = _sourceFolderName ? _sourceFolderName.length : 0;
60
+ return (
61
+ _sourceFolderNameLength
62
+ ? (
63
+ _folderPath.slice (-_sourceFolderNameLength) == _sourceFolderName
64
+ ? _folderPath.slice (0,-_sourceFolderNameLength - 1)
65
+ : null
66
+ )
67
+ : _buildFolderPath && _rootPath + '/' + _buildFolderPath + _folderPath.substr (_rootPath.length)
68
+ );
69
+ }
70
+
71
+ /*** scrunch eligible JavaScript files ***/
72
+ Uize.Wsh.buildFiles (
73
+ Uize.copyInto (
74
+ {
75
+ logFilePath:_buildScriptName.replace (_endsWithDotJsRegExp,'-js-files.log'),
76
+ targetFolderPathCreator:_targetFolderPathCreator,
77
+ targetFilenameCreator:function (_sourceFileName) {
78
+ return _endsWithDotJsRegExp.test (_sourceFileName) ? _sourceFileName : null;
79
+ },
80
+ fileBuilder:function (_sourceFileName,_sourceFileText) {
81
+ var
82
+ _moduleName = _sourceFileName.replace (_endsWithDotJsRegExp,''),
83
+ _scruncherSettings = {},
84
+ _headComment =
85
+ _scrunchedHeadComments [_sourceFileName.slice (0,_sourceFileName.indexOf ('.'))],
86
+ _keepHeadComment = _headComment == undefined
87
+ ;
88
+ if (!_keepHeadComment)
89
+ _scruncherSettings.KEEPHEADCOMMENT = 'FALSE'
90
+ ;
91
+ if (_currentFolderPath == _fullModuleFolderPath)
92
+ Uize.require (
93
+ _moduleName,
94
+ function (_module) {
95
+ var _inheritanceDepth = Uize.Util.Oop.getInheritanceChain (_module).length;
96
+ _scruncherSettings.MAPPINGS =
97
+ '=' +
98
+ (_inheritanceDepth ? _scruncherPrefixChars.charAt (_inheritanceDepth - 1) : '') +
99
+ ',' + _moduleName.replace (/\./g,'_')
100
+ ;
101
+ }
102
+ )
103
+ ;
104
+ var _scruncherResult = Uize.Build.Scruncher.scrunch (_sourceFileText,_scruncherSettings);
105
+ return {
106
+ outputText:
107
+ (
108
+ _keepHeadComment
109
+ ? ''
110
+ : Uize.substituteInto (
111
+ _headComment,
112
+ {buildDate:_buildDate,moduleName:_moduleName},
113
+ '{KEY}'
114
+ )
115
+ ) + _scruncherResult.scrunchedCode,
116
+ logDetails:Uize.String.Lines.indent (_scruncherResult.report,2) + '\n'
117
+ };
118
+ }
119
+ },
120
+ _params
121
+ )
122
+ );
123
+
124
+ /*** build .library.js files ***/
125
+ var
126
+ _contentsCommentRegExp = /\/\*\s*Library\s*Contents/i,
127
+ _lineStartsWithIdentifierCharRegExp = /^[a-zA-Z_$]/,
128
+ _scrunchedModuleFolderPath = _targetFolderPathCreator (_fullModuleFolderPath),
129
+ _libraryUsesUizeModulesHeader =
130
+ '/*______________\n' +
131
+ '| ______ | B U I L T O N U I Z E F R A M E W O R K\n' +
132
+ '| / / | ---------------------------------------------------\n' +
133
+ '| / O / | This JavaScript application is developed using the object\n' +
134
+ '| / / / | oriented UIZE JavaScript framework as its foundation.\n' +
135
+ '| / / / /| |\n' +
136
+ '| /____/ /__/_| | ONLINE : http://www.uize.com\n' +
137
+ '| /___ | LICENSE : Available under MIT License or GNU General Public License\n' +
138
+ '|_______________| http://www.uize.com/license.html\n' +
139
+ '*/\n\n'
140
+ ;
141
+ Uize.Wsh.buildFiles (
142
+ Uize.copyInto (
143
+ {
144
+ targetFolderPathCreator:_targetFolderPathCreator,
145
+ targetFilenameCreator:function (_sourceFileName) {
146
+ return /\.library.js$/.test (_sourceFileName) ? _sourceFileName : null;
147
+ },
148
+ fileBuilder:function (_sourceFileName,_sourceFileText) {
149
+ function _stripModuleHeaderComment (_moduleText) {
150
+ var _moduleHeaderCommentPos = _moduleText.indexOf ('/*');
151
+ return (
152
+ _moduleHeaderCommentPos > -1
153
+ ? (
154
+ _moduleText.slice (0,_moduleHeaderCommentPos) +
155
+ _moduleText.slice (_moduleText.indexOf ('*/',_moduleHeaderCommentPos + 2) + 2)
156
+ )
157
+ : _moduleText
158
+ );
159
+ }
160
+ var
161
+ _libraryContentsChunks = [],
162
+ _libraryUsesUizeModules
163
+ ;
164
+ for (
165
+ var
166
+ _moduleNo = -1,
167
+ _contentsCommentStartPos = _sourceFileText.search (_contentsCommentRegExp),
168
+ _contentsCommentEndPos = _sourceFileText.indexOf ('*/',_contentsCommentStartPos),
169
+ _modules = Uize.String.Lines.split (
170
+ _contentsCommentStartPos > -1
171
+ ?
172
+ _sourceFileText.slice (_contentsCommentStartPos,_contentsCommentEndPos)
173
+ .replace (_contentsCommentRegExp,'')
174
+ : _sourceFileText
175
+ ),
176
+ _modulesLength = _modules.length
177
+ ;
178
+ ++_moduleNo < _modulesLength;
179
+ ) {
180
+ var _moduleName = Uize.String.trim (_modules [_moduleNo]);
181
+ if (_moduleName && _lineStartsWithIdentifierCharRegExp.test (_moduleName)) {
182
+ if (!_libraryUsesUizeModules)
183
+ _libraryUsesUizeModules = Uize.String.startsWith (_moduleName,'Uize')
184
+ ;
185
+ _libraryContentsChunks.push (
186
+ '\n' +
187
+ _stripModuleHeaderComment (
188
+ Uize.Wsh.readFile (
189
+ _scrunchedModuleFolderPath + '\\' + _moduleName +
190
+ (_endsWithDotJsRegExp.test (_moduleName) ? '' : '.js')
191
+ )
192
+ )
193
+ );
194
+ }
195
+ }
196
+ return {
197
+ outputText:
198
+ (_libraryUsesUizeModules ? _libraryUsesUizeModulesHeader : '') +
199
+ _sourceFileText.slice (0,_contentsCommentStartPos) +
200
+ _libraryContentsChunks.join ('\n') +
201
+ _sourceFileText.slice (_contentsCommentEndPos + 2)
202
+ };
203
+ }
204
+ },
205
+ _params,
206
+ {
207
+ alwaysBuild:true,
208
+ logFilePath:_buildScriptName.replace (_endsWithDotJsRegExp,'-libraries.log')
209
+ }
210
+ )
211
+ );
212
+ };
213
+
214
+ return _package;
215
+ }
216
+ });
217
+
skin/frontend/default/customproduct/js/Uize.Build.ModuleInfo.js ADDED
@@ -0,0 +1,104 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ /*______________
2
+ | ______ | U I Z E J A V A S C R I P T F R A M E W O R K
3
+ | / / | ---------------------------------------------------
4
+ | / O / | MODULE : Uize.Build.ModuleInfo Package
5
+ | / / / |
6
+ | / / / /| | ONLINE : http://www.uize.com
7
+ | /____/ /__/_| | COPYRIGHT : (c)2012 UIZE
8
+ | /___ | LICENSE : Available under MIT License or GNU General Public License
9
+ |_______________| http://www.uize.com/license.html
10
+ */
11
+
12
+ /* Module Meta Data
13
+ type: Package
14
+ importance: 2
15
+ codeCompleteness: 0
16
+ testCompleteness: 0
17
+ docCompleteness: 0
18
+ */
19
+
20
+ /*?
21
+ Introduction
22
+ The =Uize.Build.ModuleInfo= module provides various methods for obtaining information about modules JavaScript modules.
23
+
24
+ *DEVELOPERS:* `Chris van Rensburg`
25
+ */
26
+
27
+ Uize.module ({
28
+ name:'Uize.Build.ModuleInfo',
29
+ required:'Uize.Services.FileSystem',
30
+ builder:function () {
31
+ /*** Variables for Scruncher Optimization ***/
32
+ var
33
+ _package = function () {},
34
+ _true = true,
35
+ _false = false,
36
+ _undefined,
37
+ _trueFlagValue = {},
38
+ _forEach = Uize.forEach
39
+ ;
40
+
41
+ /*** General Variables ***/
42
+ var _fileSystem = Uize.Services.FileSystem.singleton ();
43
+
44
+ /*** Public Static Methods ***/
45
+ _package.getDefinitionFromCode = function (_moduleCode) {
46
+ var
47
+ _result,
48
+ Uize = {module: function (_definition) {_result = _definition}}
49
+ ;
50
+ eval (_moduleCode);
51
+ return _result;
52
+ };
53
+
54
+ _package.getDefinition = function (_moduleName) {
55
+ var _definition = {name:_moduleName};
56
+ if (_moduleName != 'Uize') {
57
+ try {
58
+ Uize.moduleLoader (
59
+ _moduleName,
60
+ function (_moduleText) {_definition = _package.getDefinitionFromCode (_moduleText)}
61
+ );
62
+ } catch (_error) {
63
+ // if a module cannot be loaded because it is missing, ignore it
64
+ }
65
+ }
66
+ return _definition;
67
+ };
68
+
69
+ var _getDirectDependencies = _package.getDirectDependencies = function (_moduleName) {
70
+ var _definition = _package.getDefinition (_moduleName);
71
+ return _definition ? Uize.resolveModuleDefinition (_definition).required : [];
72
+ };
73
+
74
+ _package.traceDependencies = function (_modules,_excludeModules) {
75
+ var
76
+ _excludeModulesLookup = {},
77
+ _modulesNeeded = []
78
+ ;
79
+ _forEach (
80
+ _excludeModules,
81
+ function (_excludeModule) {_excludeModulesLookup [_excludeModule] = _trueFlagValue}
82
+ );
83
+
84
+ function _traceDependencies (_modules) {
85
+ _forEach (
86
+ _modules.sort (),
87
+ function (_moduleName) {
88
+ if (_excludeModulesLookup [_moduleName] != _trueFlagValue) {
89
+ _excludeModulesLookup [_moduleName] = _trueFlagValue;
90
+ _traceDependencies (_getDirectDependencies (_moduleName));
91
+ _modulesNeeded.push (_moduleName);
92
+ }
93
+ }
94
+ );
95
+ }
96
+ _traceDependencies (['Uize'].concat (typeof _modules == 'string' ? [_modules] : _modules));
97
+
98
+ return _modulesNeeded;
99
+ };
100
+
101
+ return _package;
102
+ }
103
+ });
104
+
skin/frontend/default/customproduct/js/Uize.Build.NeatenJsFiles.js ADDED
@@ -0,0 +1,74 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ /*______________
2
+ | ______ | U I Z E J A V A S C R I P T F R A M E W O R K
3
+ | / / | ---------------------------------------------------
4
+ | / O / | MODULE : Uize.Build.NeatenJsFiles Package
5
+ | / / / |
6
+ | / / / /| | ONLINE : http://www.uize.com
7
+ | /____/ /__/_| | COPYRIGHT : (c)2010-2012 UIZE
8
+ | /___ | LICENSE : Available under MIT License or GNU General Public License
9
+ |_______________| http://www.uize.com/license.html
10
+ */
11
+
12
+ /* Module Meta Data
13
+ type: Package
14
+ importance: 1
15
+ codeCompleteness: 100
16
+ testCompleteness: 0
17
+ docCompleteness: 4
18
+ */
19
+
20
+ /*?
21
+ Introduction
22
+ The =Uize.Build.NeatenJsFiles= package provides a way to recurse folder structures and neaten all JavaScript (.js) files by removing unnecessary trailing whitespace.
23
+
24
+ *DEVELOPERS:* `Chris van Rensburg`
25
+
26
+ The =Uize.Build.NeatenJsFiles= module is designed specifically to run in the context of Windows Script Host.
27
+ */
28
+
29
+ Uize.module ({
30
+ name:'Uize.Build.NeatenJsFiles',
31
+ required:[
32
+ 'Uize.Build.Util',
33
+ 'Uize.String.Lines',
34
+ 'Uize.Build.AutoScruncher'
35
+ ],
36
+ builder:function () {
37
+ /*** Variables for Scruncher Optimization ***/
38
+ var _package = function () {};
39
+
40
+ /*** Public Static Methods ***/
41
+ _package.perform = function (_params) {
42
+ Uize.Build.Util.buildFiles (
43
+ Uize.copyInto (
44
+ {
45
+ targetFolderPathCreator:function (_folderPath) {
46
+ return _folderPath;
47
+ },
48
+ targetFilenameCreator:function (_sourceFileName) {
49
+ return /\.js$/.test (_sourceFileName) ? _sourceFileName : null;
50
+ },
51
+ fileBuilder:function (_sourceFileName,_sourceFileText) {
52
+ var _neatenedSourceFileText = Uize.String.Lines.trimRight (_sourceFileText);
53
+ return (
54
+ _neatenedSourceFileText != _sourceFileText
55
+ ? {
56
+ outputText:_neatenedSourceFileText,
57
+ logDetails:
58
+ '\t\tTrailing Whitespace Characters Removed: ' +
59
+ (_sourceFileText.length - _neatenedSourceFileText.length) + '\n'
60
+ }
61
+ : {logDetails:'\t\tFILE ALREADY OK\n'}
62
+ );
63
+ }
64
+ },
65
+ _params,
66
+ {alwaysBuild:true}
67
+ )
68
+ );
69
+ };
70
+
71
+ return _package;
72
+ }
73
+ });
74
+
skin/frontend/default/customproduct/js/Uize.Build.RunUnitTest.js ADDED
@@ -0,0 +1,41 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ /*______________
2
+ | ______ | U I Z E J A V A S C R I P T F R A M E W O R K
3
+ | / / | ---------------------------------------------------
4
+ | / O / | MODULE : Uize.Build.RunUnitTest Package
5
+ | / / / |
6
+ | / / / /| | ONLINE : http://www.uize.com
7
+ | /____/ /__/_| | COPYRIGHT : (c)2012 UIZE
8
+ | /___ | LICENSE : Available under MIT License or GNU General Public License
9
+ |_______________| http://www.uize.com/license.html
10
+ */
11
+
12
+ /* Module Meta Data
13
+ type: Package
14
+ importance: 1
15
+ codeCompleteness: 100
16
+ testCompleteness: 0
17
+ docCompleteness: 2
18
+ */
19
+
20
+ /*?
21
+ Introduction
22
+ The =Uize.Build.RunUnitTest= module provides a method for testing a specified JavaScript module.
23
+
24
+ *DEVELOPERS:* `Chris van Rensburg`
25
+ */
26
+
27
+ Uize.module ({
28
+ name:'Uize.Build.RunUnitTest',
29
+ required:'Uize.Build.Util',
30
+ builder:function () {
31
+ var _package = function () {};
32
+
33
+ /*** Public Static Methods ***/
34
+ _package.perform = function (_params) {
35
+ Uize.Build.Util.runUnitTests (_params.testModule,_params.silent == 'true');
36
+ };
37
+
38
+ return _package;
39
+ }
40
+ });
41
+
skin/frontend/default/customproduct/js/Uize.Build.RunUnitTests.js ADDED
@@ -0,0 +1,89 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ /*______________
2
+ | ______ | U I Z E J A V A S C R I P T F R A M E W O R K
3
+ | / / | ---------------------------------------------------
4
+ | / O / | MODULE : Uize.Build.RunUnitTests Package
5
+ | / / / |
6
+ | / / / /| | ONLINE : http://www.uize.com
7
+ | /____/ /__/_| | COPYRIGHT : (c)2010-2012 UIZE
8
+ | /___ | LICENSE : Available under MIT License or GNU General Public License
9
+ |_______________| http://www.uize.com/license.html
10
+ */
11
+
12
+ /* Module Meta Data
13
+ type: Package
14
+ importance: 3
15
+ codeCompleteness: 100
16
+ testCompleteness: 0
17
+ docCompleteness: 2
18
+ */
19
+
20
+ /*?
21
+ Introduction
22
+ The =Uize.Build.RunUnitTests= module provides a method for testing all modules of the UIZE JavaScript Framework.
23
+
24
+ *DEVELOPERS:* `Chris van Rensburg`
25
+ */
26
+
27
+ Uize.module ({
28
+ name:'Uize.Build.RunUnitTests',
29
+ required:[
30
+ 'Uize.Services.FileSystem',
31
+ 'Uize.Test',
32
+ 'Uize.Build.Util',
33
+ 'Uize.Build.ModuleInfo',
34
+ 'Uize.Data.Matches'
35
+ ],
36
+ builder:function () {
37
+ /*** Variables for Scruncher Optimization ***/
38
+ var _package = function () {};
39
+
40
+ /*** General Variables ***/
41
+ var _fileSystem = Uize.Services.FileSystem.singleton ();
42
+
43
+ /*** Public Static Methods ***/
44
+ _package.perform = function (_params) {
45
+ var
46
+ _dotJsRegExp = /\.js$/i,
47
+ _dotLibraryDotJsRegExp = /\.library\.js$/i,
48
+ _modules = _fileSystem.getFiles ({
49
+ path:_params.moduleFolderPath,
50
+ pathMatcher:function (_filePath) {
51
+ return _dotJsRegExp.test (_filePath) && !_dotLibraryDotJsRegExp.test (_filePath)
52
+ },
53
+ pathTransformer:function (_filePath) {
54
+ return Uize.Url.from (_filePath).fileName;
55
+ }
56
+ }).sort (),
57
+ _modulesLookup = Uize.lookup (_modules),
58
+ _correspondingTestModuleName,
59
+ _testModuleRegExp = /^[a-zA-Z_\$][a-zA-Z0-9_\$]*\.Test($|\.)/,
60
+ _modulesInDependencyOrder = Uize.Build.ModuleInfo.traceDependencies (
61
+ Uize.Data.Matches.values (
62
+ _modules,
63
+ function (_moduleName) {return !_testModuleRegExp.test (_moduleName)} // ignore test modules
64
+ )
65
+ ),
66
+ _unitTestSuite = Uize.Test.declare ({
67
+ title:'Unit Tests Suite',
68
+ test:Uize.map (
69
+ _modulesInDependencyOrder,
70
+ function (_moduleName) {
71
+ return (
72
+ _modulesLookup [
73
+ _correspondingTestModuleName =
74
+ _moduleName.match (/([^\.]*)(\.|$)/) [1] + '.Test.' + _moduleName
75
+ ]
76
+ ? Uize.Test.testModuleTest (_correspondingTestModuleName)
77
+ : Uize.Test.requiredModulesTest (_moduleName)
78
+ );
79
+ }
80
+ )
81
+ })
82
+ ;
83
+ Uize.Build.Util.runUnitTests (_unitTestSuite,_params.silent == 'true',_params.logFilePath);
84
+ };
85
+
86
+ return _package;
87
+ }
88
+ });
89
+
skin/frontend/default/customproduct/js/Uize.Build.Scruncher.js ADDED
@@ -0,0 +1,515 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ /*______________
2
+ | ______ | U I Z E J A V A S C R I P T F R A M E W O R K
3
+ | / / | ---------------------------------------------------
4
+ | / O / | MODULE : Uize.Build.Scruncher Package
5
+ | / / / |
6
+ | / / / /| | ONLINE : http://www.uize.com
7
+ | /____/ /__/_| | COPYRIGHT : (c)1997-2012 UIZE
8
+ | /___ | LICENSE : Available under MIT License or GNU General Public License
9
+ |_______________| http://www.uize.com/license.html
10
+ */
11
+
12
+ /* Module Meta Data
13
+ type: Package
14
+ importance: 8
15
+ codeCompleteness: 100
16
+ testCompleteness: 0
17
+ docCompleteness: 100
18
+ */
19
+
20
+ /*?
21
+ Introduction
22
+ The =Uize.Build.Scruncher= package provides a method for scrunching (compressing / minifying) JavaScript source code into compact / obfuscated scrunched code.
23
+
24
+ *DEVELOPERS:* `Chris van Rensburg`
25
+ */
26
+
27
+ /* NOTES
28
+ - whitespace is regarded as being any continuous segment of tab and/or space characters
29
+ - for any amount of whitespace that is necessary for separating tokens, a single space will be substituted
30
+ - if whitespace is being used to separate identifiers and operators and is therefore not essential, it should be removed
31
+ - whitespace is considered necessary when it
32
+ - separates reserved words, identifiers, and literals
33
+ eg. function blah () {} BECOMES--> function blah(){}
34
+ - separates consecutive operators
35
+ eg. a += ++b; BECOMES--> a+= ++b;
36
+ - whitespace is considered unnecessary when it
37
+ - occurs at the start of a line, before any non-whitespace characters
38
+ eg.
39
+ function blah () {
40
+ a++;
41
+ }
42
+
43
+ BECOMES-->
44
+
45
+ function blah(){
46
+ a++;
47
+ }
48
+
49
+ - separates reserved words, identifiers, or literals from operators
50
+ eg. a += b; BECOMES--> a+=b;
51
+ - separates reserved words, identifiers, or literals from delimiters
52
+ eg. a += 2 * (b - 3) BECOMES--> a+=2*(b-3)
53
+ eg. myArray [5] BECOMES--> myArray[5]
54
+ eg. a++ ; BECOMES--> a++;
55
+ eg. myFunction ( 2 , 'hello' , 7 ); BECOMES--> myFunction(2,'hello',7);
56
+ - separates delimiters from each other
57
+ eg. myFunction () ; BECOMES--> myFunction();
58
+ eg. myArray1 [myArray2 [5] ] ; BECOMES--> myArray1[myArray2[5]];
59
+ - separates operators from delimiters
60
+ eg. a ++ ; BECOMES--> a++;
61
+ eg. myVariable += (myArray [a ++ ] - 5) ; BECOMES--> myVariable+=(myArray[a++]-5);
62
+ */
63
+
64
+ Uize.module({
65
+ name:'Uize.Build.Scruncher',
66
+ required:[
67
+ 'Uize.Xml',
68
+ 'Uize.String'
69
+ ],
70
+ builder:function () {
71
+ /*** Variables for Scruncher Optimization ***/
72
+ var
73
+ _package = function () {},
74
+ _true = true,
75
+ _false = false
76
+ ;
77
+
78
+ /*** Utility Functions ***/
79
+ function _makeCharLookup (_charsStr,_lookupValue) {
80
+ return Uize.lookup (_charsStr.split (''),_lookupValue != null ? _lookupValue : _true);
81
+ }
82
+
83
+ /*** General Variables ***/
84
+ var
85
+ /*** token types ***/
86
+ _NONE = 0,
87
+ _WORD = 1,
88
+ _NUMBER = 2,
89
+ _DELIMITER = 3,
90
+ _STRINGLITERAL = 4,
91
+ _COMMENT = 5,
92
+ _OPERATOR = 6,
93
+ _LINEBREAK = 7,
94
+
95
+ /*** char lookups ***/
96
+ _operatorCharsLookup = _makeCharLookup ('+-*/%&|^~<>=!?:',_OPERATOR),
97
+ _delimiterCharsLookup = _makeCharLookup ('.,()[]{};',_DELIMITER),
98
+ _quoteCharsLookup = _makeCharLookup ('"\'',_STRINGLITERAL),
99
+ _linebreakCharsLookup = _makeCharLookup ('\n\r',_LINEBREAK),
100
+ _wordStarterCharsLookup = _makeCharLookup (
101
+ 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ_$',
102
+ _WORD
103
+ ),
104
+ _digitsLookup = _makeCharLookup ('0123456789',_NUMBER),
105
+ _numberCharsLookup = Uize.copyInto (_digitsLookup,{x:_NUMBER}),
106
+ _tokenStarterCharsLookup = Uize.copyInto (
107
+ {},
108
+ _linebreakCharsLookup,
109
+ _operatorCharsLookup,
110
+ _delimiterCharsLookup,
111
+ _quoteCharsLookup,
112
+ _numberCharsLookup,
113
+ _wordStarterCharsLookup
114
+ ),
115
+ _wordCharsLookup = Uize.copyInto ({},_wordStarterCharsLookup,_numberCharsLookup),
116
+ _closeParenOrSquareBracketMap = _makeCharLookup (')]'),
117
+
118
+ _identifierChars = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789'.split (''),
119
+ _totalIdentifierChars = _identifierChars.length,
120
+ _invalidOperatorRegExp = /^(:|!+|\*|-|\+|\||\|\||&|&&|%|>|>>|<|<<|=|==|\?|\^)\/$/
121
+ /* EXAMPLES */
122
+ // object = {prop:/\w+/g}
123
+ // if (!/\w+/g.test (sourceStr)) {...}
124
+ // if (!!/\w+/g.test (sourceStr)) {...}
125
+ // 2*/\w+/g.test (sourceStr)
126
+ // 2-/\w+/g.test (sourceStr)
127
+ // 1+/\w+/g.test (sourceStr)
128
+ // 1|/\w+/g.test (sourceStr)
129
+ // bool||/\w+/g.test (sourceStr)
130
+ // 1&/\w+/g.test (sourceStr)
131
+ // bool&&/\w+/g.test (sourceStr)
132
+ // 10%/\w+/g.test (sourceStr)
133
+ // 1>/\w+/g.test (sourceStr)
134
+ // 1>>/\w+/g.test (sourceStr)
135
+ // 1</\w+/g.test (sourceStr)
136
+ // 1<</\w+/g.test (sourceStr)
137
+ // variable=/\w+/g.test (sourceStr)
138
+ // bool==/\w+/g.test (sourceStr)
139
+ // bool?/\w+/g.test (sourceStr):{}
140
+ // 1^/\w+/g.test (sourceStr):{}
141
+ /* TODO:
142
+ There might be a better way of handling this. Perhaps one builds up an operator as large as one can make it without it becoming not a valid operator, at which point one terminates the token. This approach would involve maintaining a list of valid operators, rather than a list of valid operator characters and an exception mechanism for detecting invalid operators.
143
+ */
144
+ ;
145
+
146
+ /*** Private Static Properties ***/
147
+ var _settings = {};
148
+
149
+ /*** Public Static Methods ***/
150
+ _package.scrunch = function (_sourceCode,_scruncherSettings) {
151
+ var
152
+ /*** report variables ***/
153
+ _uniqueIdentifiersScrunched = 0,
154
+ _incidencesOfIdentifiersScrunched = 0,
155
+ _savingsFromScrunchedIdentifiers = 0,
156
+ _savingsFromRemovedWhitespace = 0,
157
+ _savingsFromRemovedComments = 0,
158
+ _savingsFromRemovedLinebreaks = 0,
159
+ _totalCommentsRemoved = 0,
160
+
161
+ _mappings,
162
+ _endOfHeadComment = _false,
163
+ _lineNo = 1,
164
+ _scrunchedCode = _scrunchedCodeHeader = '',
165
+ _comments = [],
166
+ _stringsMap = {},
167
+ _leaveNextComment = _false,
168
+ _commentType,
169
+ _quoteChar,
170
+ _currentChar = '',
171
+ _previousChar,
172
+ _inEscape = _false,
173
+ _tokenType = _NONE,
174
+ _previousAddedToken = '',
175
+ _previousAddedTokenType = _NONE,
176
+ _currentToken = '',
177
+ _tokenTerminated = _false,
178
+ _currentBlock = '',
179
+ _currentLine = '',
180
+ _Uize_String_startsWith = Uize.String.startsWith
181
+ ;
182
+ /*** initialize settings ***/
183
+ /* IDEA:
184
+ make this switchable, so that it doesn't always have to be performed for each scrunch (and so that groups of files can be scrunched in the same namespace?)
185
+ */
186
+ _settings.LINECOMPACTING = 'TRUE';
187
+ _settings.MAXLINELENGTH = 1024;
188
+ _settings.MAPPINGS = '';
189
+ _settings.KEEPHEADCOMMENT = 'TRUE';
190
+ _settings.AUDITSTRINGS = 'FALSE';
191
+
192
+ function _Mapping (_sourcePrefix,_targetPrefix) {
193
+ /*** Constructor Properties ***/
194
+ this._sourcePrefix = _sourcePrefix;
195
+ this._targetPrefix = _targetPrefix || _sourcePrefix;
196
+
197
+ /*** Private Instance Properties ***/
198
+ this._scrunchMap = [];
199
+ this._totalIdentifiers = 0;
200
+ }
201
+
202
+ function _parseScruncherSettings (_scruncherSettings) {
203
+ function _stringToBoolean (_value) {
204
+ _value = (_value + '').toUpperCase ();
205
+ return _value == 'TRUE' || _value == 'ON' || _value == '1';
206
+ }
207
+
208
+ Uize.copyInto (
209
+ _settings,
210
+ typeof _scruncherSettings == 'string'
211
+ ? Uize.Xml.fromAttributes (_scruncherSettings,{nameCase:'upper'})
212
+ : _scruncherSettings
213
+ );
214
+
215
+ /*** update/resolve settings ***/
216
+ _settings.LINECOMPACTING = _stringToBoolean (_settings.LINECOMPACTING);
217
+ _settings.KEEPHEADCOMMENT = _stringToBoolean (_settings.KEEPHEADCOMMENT);
218
+ _settings.AUDITSTRINGS = _stringToBoolean (_settings.AUDITSTRINGS);
219
+
220
+ /*** parse mappings to create mapping objects ***/
221
+ _mappings = [];
222
+ var _mappingPairs = _settings.MAPPINGS.split (',');
223
+ for (var _pairNo = -1; ++_pairNo < _mappingPairs.length;) {
224
+ var _sourcePrefixAndTargetPrefix = Uize.String.splitInTwo (_mappingPairs [_pairNo],'=');
225
+ _mappings [_pairNo] = new _Mapping (
226
+ _sourcePrefixAndTargetPrefix [0],
227
+ _sourcePrefixAndTargetPrefix [1]
228
+ );
229
+ }
230
+ }
231
+ _parseScruncherSettings (_scruncherSettings);
232
+
233
+ for (
234
+ var
235
+ _charNo = -1,
236
+ _sourceCodeLength = _sourceCode.length,
237
+ _sourceCodeLengthMinus1 = _sourceCodeLength - 1
238
+ ;
239
+ ++_charNo <= _sourceCodeLength;
240
+ ) {
241
+ _previousChar = _currentChar;
242
+ if (_charNo > _sourceCodeLengthMinus1) {
243
+ _currentChar = '';
244
+ _tokenTerminated = _true;
245
+ } else {
246
+ _currentChar = _sourceCode.charAt (_charNo);
247
+ (_currentChar == '\r' || (_currentChar == '\n' && _previousChar != '\r')) &&
248
+ _lineNo++
249
+ ;
250
+ if (_tokenType == _WORD) {
251
+ if (!_wordCharsLookup [_currentChar]) _tokenTerminated = _true;
252
+ } else if (_tokenType == _NUMBER) {
253
+ if (!_numberCharsLookup [_currentChar]) _tokenTerminated = _true;
254
+ } else if (_tokenType == _DELIMITER) {
255
+ if (!_delimiterCharsLookup [_currentChar]) _tokenTerminated = _true;
256
+ } else if (_tokenType == _STRINGLITERAL) {
257
+ if (_inEscape) {
258
+ _inEscape = _false;
259
+ } else if (_currentChar == '\\') {
260
+ _inEscape = _true;
261
+ } else if (_currentChar == _quoteChar) {
262
+ if (_settings.AUDITSTRINGS && _quoteChar != '/') {
263
+ var
264
+ _string = _currentToken.slice (1),
265
+ _stringProfile = _stringsMap [_string]
266
+ ;
267
+ (_stringProfile instanceof Array ? _stringProfile : (_stringsMap [_string] = []))
268
+ .push (_lineNo) // must handle the case of the valueOf and toString natives
269
+ ;
270
+ }
271
+ _currentToken += _currentChar;
272
+ _currentChar = '';
273
+ _tokenTerminated = _true;
274
+ }
275
+ } else if (_tokenType == _COMMENT) {
276
+ if (_commentType == '//') {
277
+ if (_currentChar == '\n' || _currentChar == '\r') _tokenTerminated = _true;
278
+ } else if (_commentType == '/*') {
279
+ if (_currentToken.length > 2 && _previousChar + _currentChar == '*/') {
280
+ /* NOTE:
281
+ making sure the length is greater than 2 when evaluating the current character avoids terminating a comment that's a forward slash + star + forward slash, where technically there is a comment opener and a comment closer, but they both share a star
282
+ */
283
+ _currentToken += _currentChar;
284
+ _tokenTerminated = _true;
285
+ _currentChar = '';
286
+ }
287
+ }
288
+ } else if (_tokenType == _OPERATOR) {
289
+ if (_currentToken == '/' && (_currentChar == '/' || _currentChar == '*')) {
290
+ _tokenType = _COMMENT;
291
+ _commentType = _currentToken + _currentChar;
292
+ /* NOTE:
293
+ Following code is an optimization, to seek ahead to the end of the comment, rather than running through the characters one by one (which slows down scrunching dramatically).
294
+ */
295
+ var _commentCloserPos;
296
+ if (_currentChar == '*') {
297
+ _commentCloserPos = _sourceCode.indexOf ('*/',_charNo + 1);
298
+ if (_commentCloserPos < 0) _commentCloserPos = _sourceCodeLength;
299
+ } else {
300
+ var
301
+ _nextLineFeed = _sourceCode.indexOf ('\n',_charNo + 1),
302
+ _nextCarriageReturn = _sourceCode.indexOf ('\r',_charNo + 1)
303
+ ;
304
+ _commentCloserPos = Math.min (
305
+ _nextLineFeed < 0 ? _sourceCodeLength : _nextLineFeed,
306
+ _nextCarriageReturn < 0 ? _sourceCodeLength : _nextCarriageReturn
307
+ );
308
+ }
309
+ _currentToken = _sourceCode.slice (_charNo - 1,_commentCloserPos - 1);
310
+ _currentChar = _sourceCode.charAt (_charNo = _commentCloserPos - 1);
311
+ } else if (
312
+ _currentToken == '/' &&
313
+ (_previousAddedTokenType != _WORD || _previousAddedToken == 'return') &&
314
+ _previousAddedTokenType != _NUMBER &&
315
+ _previousAddedTokenType != _STRINGLITERAL &&
316
+ !(
317
+ _previousAddedTokenType == _DELIMITER &&
318
+ _closeParenOrSquareBracketMap [_previousAddedToken.slice (-1)]
319
+ )
320
+ ) {
321
+ /* regular expression handling
322
+ NOTE: by setting the _currentChar to an empty string and decrementing the _charNo counter, we force re-evualtion of the current character, now that we know we're in a regular expression
323
+ */
324
+ _tokenType = _STRINGLITERAL;
325
+ _quoteChar = '/';
326
+ _currentChar = '';
327
+ _charNo--;
328
+ } else if (
329
+ !_operatorCharsLookup [_currentChar] ||
330
+ _invalidOperatorRegExp.test (_currentToken + _currentChar)
331
+ ) {
332
+ _tokenTerminated = _true;
333
+ }
334
+ } else if (_tokenType == _LINEBREAK) {
335
+ if (_currentChar != '\n' && _currentChar != '\r') _tokenTerminated = _true;
336
+ }
337
+ _endOfHeadComment =
338
+ _endOfHeadComment ||
339
+ (_tokenType && _tokenType != _COMMENT && (_tokenType != _LINEBREAK || _currentToken.length > 1))
340
+ ;
341
+ }
342
+ if (_tokenTerminated) {
343
+ if (_tokenType == _WORD) {
344
+ for (var _mappingNo = -1; ++_mappingNo < _mappings.length;) {
345
+ var _mapping = _mappings [_mappingNo];
346
+ if (_Uize_String_startsWith (_currentToken,_mapping._sourcePrefix + '_')) {
347
+ _incidencesOfIdentifiersScrunched++;
348
+ var _scrunchedToken = _mapping._scrunchMap [_currentToken] || '';
349
+ if (!_scrunchedToken) {
350
+ _uniqueIdentifiersScrunched++;
351
+ var _numberToConvert = _mapping._totalIdentifiers++;
352
+ do {
353
+ _scrunchedToken =
354
+ _identifierChars [
355
+ _numberToConvert -
356
+ _totalIdentifierChars * (
357
+ _numberToConvert = Math.floor (_numberToConvert / _totalIdentifierChars)
358
+ )
359
+ ] + _scrunchedToken
360
+ ;
361
+ } while (_numberToConvert > 0);
362
+ _scrunchedToken =
363
+ _mapping._scrunchMap [_currentToken] = _mapping._targetPrefix + '_' + _scrunchedToken
364
+ ;
365
+ }
366
+ _savingsFromScrunchedIdentifiers +=
367
+ _currentToken.length - (_currentToken = _scrunchedToken).length
368
+ ;
369
+ break;
370
+ }
371
+ }
372
+ } else if (_tokenType == _COMMENT) {
373
+ _comments.push (_currentToken);
374
+ _savingsFromRemovedComments += _currentToken.length;
375
+ var _isScruncherDirective = _false;
376
+ if (/^\/[\*\/]\s*scruncher/i.test (_currentToken)) {
377
+ if (_currentToken.substr (2,17).toLowerCase () == 'scrunchersettings') {
378
+ _isScruncherDirective = _true;
379
+ _parseScruncherSettings (
380
+ _currentToken.slice (2,_currentToken.length - (_commentType == '/*') * 2)
381
+ );
382
+ _currentToken = '';
383
+ } else if (/^\/[\*\/]\s*scruncher:leave next comment/i.test (_currentToken)) {
384
+ _isScruncherDirective = _leaveNextComment = _true;
385
+ _currentToken = '';
386
+ }
387
+ }
388
+ if (!_isScruncherDirective) {
389
+ if ((_endOfHeadComment || !_settings.KEEPHEADCOMMENT) && !_leaveNextComment) {
390
+ _currentToken = '';
391
+ } else if (_commentType == '/*') {
392
+ if (_leaveNextComment) {
393
+ if (_settings.LINECOMPACTING) _currentToken = '\n' + _currentToken + '\n';
394
+ _leaveNextComment = _false;
395
+ }
396
+ _currentToken += '\n';
397
+ }
398
+ }
399
+ if (!_currentToken) _totalCommentsRemoved++;
400
+ _savingsFromRemovedComments -= _currentToken.length;
401
+ } else if (_tokenType == _LINEBREAK) {
402
+ _savingsFromRemovedLinebreaks += _currentToken.length;
403
+ _currentToken = '';
404
+ if (
405
+ !_settings.LINECOMPACTING ||
406
+ (_currentBlock.length + _currentLine.length > _settings.MAXLINELENGTH)
407
+ ) {
408
+ _scrunchedCode += _currentBlock + '\n';
409
+ _savingsFromRemovedLinebreaks--;
410
+ _currentBlock = '';
411
+ }
412
+ _currentBlock += _currentLine;
413
+ _currentLine = '';
414
+ }
415
+ if (
416
+ ((_tokenType == _WORD || _tokenType == _OPERATOR) && _previousAddedTokenType == _tokenType) ||
417
+ (
418
+ _tokenType == _NUMBER &&
419
+ _digitsLookup [_currentToken.charAt (0)] &&
420
+ _previousAddedTokenType == _WORD
421
+ )
422
+ ) {
423
+ /* NOTE: whitespace is necessary when it separates...
424
+ - two adjacent words (eg. function myFunction)
425
+ - two adjacent operators (eg. myVariable += ++ myOtherVariable)
426
+ - a word followed by a number that starts with a digit, rather than "+", "-", or "." (eg. return 1)
427
+ */
428
+ _currentToken = ' ' + _currentToken;
429
+ _savingsFromRemovedWhitespace--;
430
+ }
431
+ _tokenTerminated = _false;
432
+ if (_currentToken) {
433
+ _currentLine += _currentToken;
434
+ _previousAddedToken = _currentToken;
435
+ _previousAddedTokenType = _tokenType;
436
+ }
437
+ _currentToken = '';
438
+ _tokenType = _NONE;
439
+ }
440
+ if (!_tokenType && _currentChar) {
441
+ _tokenType = _tokenStarterCharsLookup [_currentChar];
442
+ if (_tokenType == _STRINGLITERAL)
443
+ _quoteChar = _currentChar
444
+ ;
445
+ }
446
+ _tokenType
447
+ ? (_currentToken += _currentChar)
448
+ : (_savingsFromRemovedWhitespace += _currentChar.length)
449
+ ;
450
+ }
451
+ return {
452
+ scrunchedCode:_scrunchedCode += _currentBlock + _currentLine,
453
+ comments:_comments,
454
+ stringsMap:_stringsMap,
455
+ report:
456
+ 'Unique Identifiers Scrunched: ' + _uniqueIdentifiersScrunched + '\n' +
457
+ 'Incidences of Identifiers Scrunched: ' + _incidencesOfIdentifiersScrunched + '\n' +
458
+ 'Savings From Scrunched Identifiers: ' + _savingsFromScrunchedIdentifiers + '\n' +
459
+ 'Savings From Removed Whitespace: ' + _savingsFromRemovedWhitespace + '\n' +
460
+ 'Total Comments Removed: ' + _totalCommentsRemoved + '\n' +
461
+ 'Savings From Removed Comments: ' + _savingsFromRemovedComments + '\n' +
462
+ 'Savings From Removed Linebreaks: ' + _savingsFromRemovedLinebreaks + '\n' +
463
+ 'Supposed Total Savings: ' + (_savingsFromScrunchedIdentifiers + _savingsFromRemovedWhitespace + _savingsFromRemovedComments + _savingsFromRemovedLinebreaks - _scrunchedCodeHeader.length) + '\n' +
464
+ 'Real Total Savings: ' + (_sourceCode.length - _scrunchedCode.length) + '\n\n' +
465
+ 'FINAL SIZE: ' + _scrunchedCode.length
466
+ };
467
+ /*?
468
+ Static Methods
469
+ Uize.Build.Scruncher.scrunch
470
+ Scrunches the specified source code string and returns an object, containing a string property for the scrunched form of the code, a string property with a report summarizing the savings from scrunching the code, and an array property containing all the comments from the source.
471
+
472
+ SYNTAX
473
+ ..................................................................
474
+ scruncherResultOBJ = Uize.Build.Scruncher.scrunch (sourceCodeSTR);
475
+ ..................................................................
476
+
477
+ The returned object has the following composition...
478
+
479
+ ..........................................................................
480
+ {
481
+ scrunchedCode:scrunchedCodeSTR, // the scrunched form of the code
482
+ report:reportSTR, // a multi-line summary of size savings
483
+ comments:commentsARRAY // an array of strings
484
+ }
485
+ ..........................................................................
486
+
487
+ The multi-line report contained in the =report= string property summarizes the file size savings from removed whitespace, removed comments, removed linebreaks, and scrunched identifiers. The comments array specified by the =comments= property can be used in the generation of comment-based documentation, as is done by the =Uize.Doc.Sucker= package.
488
+
489
+ VARIATION
490
+ .......................................................................................
491
+ scruncherResultOBJ = Uize.Build.Scruncher.scrunch (sourceCodeSTR,scruncherSettingsSTR);
492
+ .......................................................................................
493
+
494
+ When the optional =scruncherSettingsSTR= parameter is specified, the specified Scruncher settings string will be parsed and applied to the scrunching process. This is done after the Scruncher settings have been initialized and before any of the specified source file has been parsed, so before any Scruncher settings inside the source code are encountered. Therefore, Scruncher settings inside the code being scrunched will take precedence and will override any Scruncher settings specified in the =scruncherSettingsSTR= parameter.
495
+
496
+ The value of the =scruncherSettingsSTR= parameter should have the following syntax...
497
+
498
+ .................................................................
499
+ [setting0Name]="[setting0Value]" [settingNName]="[settingNValue]"
500
+ .................................................................
501
+
502
+ This parameter is useful for providing initial values for Scruncher settings that may not be specified inside a file (or files) being scrunched, and is particularly useful when using the Scruncher in build scripts.
503
+
504
+ EXAMPLE
505
+ ..........................................................................................
506
+ var scruncherResult = Uize.Build.Scruncher.scrunch (sourceCode,'KeepHeadComment="FALSE"');
507
+ ..........................................................................................
508
+
509
+ In the above example, the =scruncherSettingsSTR= parameter is being used to direct the Scruncher to omit the source code's head comment when scrunching it.
510
+ */
511
+ };
512
+
513
+ return _package;
514
+ }
515
+ });
skin/frontend/default/customproduct/js/Uize.Build.ServicesSetup.js ADDED
@@ -0,0 +1,51 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ /*______________
2
+ | ______ | U I Z E J A V A S C R I P T F R A M E W O R K
3
+ | / / | ---------------------------------------------------
4
+ | / O / | MODULE : Uize.Build.ServicesSetup Package
5
+ | / / / |
6
+ | / / / /| | ONLINE : http://www.uize.com
7
+ | /____/ /__/_| | COPYRIGHT : (c)2012 UIZE
8
+ | /___ | LICENSE : Available under MIT License or GNU General Public License
9
+ |_______________| http://www.uize.com/license.html
10
+ */
11
+
12
+ /* Module Meta Data
13
+ type: Package
14
+ importance: 5
15
+ codeCompleteness: 0
16
+ testCompleteness: 0
17
+ docCompleteness: 5
18
+ */
19
+
20
+ /*?
21
+ Introduction
22
+ The =Uize.Build.ServicesSetup= package....
23
+
24
+ *DEVELOPERS:* `Chris van Rensburg`
25
+ */
26
+
27
+ Uize.module ({
28
+ name:'Uize.Build.ServicesSetup',
29
+ required:'Uize.Services.Setup',
30
+ builder:function () {
31
+ /*** Variables for Scruncher Optimization ***/
32
+ var _package = function () {};
33
+
34
+ /*** Public Static Methods ***/
35
+ _package.setup = function () {
36
+ /*** provide setup for FileSystem service ***/
37
+ var _isWsh = typeof ActiveXObject != 'undefined';
38
+ Uize.Services.Setup.provideServiceSetup (
39
+ 'Uize.Services.FileSystem',
40
+ _isWsh ? 'Uize.Services.FileSystemWsh' : 'Uize.Services.FileSystemNode',
41
+ function (_service,_doneWithSetup) {
42
+ _service.init ();
43
+ _doneWithSetup ();
44
+ }
45
+ );
46
+ };
47
+
48
+ return _package;
49
+ }
50
+ });
51
+
skin/frontend/default/customproduct/js/Uize.Build.UpdateCopyrightNotices.js ADDED
@@ -0,0 +1,94 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ /*______________
2
+ | ______ | U I Z E J A V A S C R I P T F R A M E W O R K
3
+ | / / | ---------------------------------------------------
4
+ | / O / | MODULE : Uize.Build.UpdateCopyrightNotices Package
5
+ | / / / |
6
+ | / / / /| | ONLINE : http://www.uize.com
7
+ | /____/ /__/_| | COPYRIGHT : (c)2011-2012 UIZE
8
+ | /___ | LICENSE : Available under MIT License or GNU General Public License
9
+ |_______________| http://www.uize.com/license.html
10
+ */
11
+
12
+ /* Module Meta Data
13
+ type: Package
14
+ importance: 1
15
+ codeCompleteness: 100
16
+ testCompleteness: 0
17
+ docCompleteness: 4
18
+ */
19
+
20
+ /*?
21
+ Introduction
22
+ The =Uize.Build.UpdateCopyrightNotices= package provides a way to recurse folder structures and update the copyright notices for all JavaScript (.js) files to cover the current year.
23
+
24
+ *DEVELOPERS:* `Chris van Rensburg`
25
+
26
+ The =Uize.Build.UpdateCopyrightNotices= module is designed specifically to run in the context of Windows Script Host.
27
+ */
28
+
29
+ Uize.module ({
30
+ name:'Uize.Build.UpdateCopyrightNotices',
31
+ required:'Uize.Build.Util',
32
+ builder:function () {
33
+ /*** Variables for Scruncher Optimization ***/
34
+ var _package = function () {};
35
+
36
+ /*** General Variables ***/
37
+ var
38
+ _copyrightNoticeRegExp = /\(c\)\s*\d{4}(?:\s*-\s*(\d{4}))?/i,
39
+ _copyrightNoticeEndYearRegExp = /(-\s*)(\d{4})/
40
+ ;
41
+
42
+ /*** Public Static Methods ***/
43
+ _package.perform = function (_params) {
44
+ var _thisYear = (new Date).getFullYear ();
45
+ Uize.Build.Util.buildFiles (
46
+ Uize.copyInto (
47
+ {
48
+ targetFolderPathCreator:function (_folderPath) {
49
+ return _folderPath;
50
+ },
51
+ targetFilenameCreator:function (_sourceFileName) {
52
+ return /\.(js|jst)$/.test (_sourceFileName) ? _sourceFileName : null;
53
+ },
54
+ fileBuilder:function (_sourceFileName,_sourceFileText) {
55
+ var _copyrightNoticeMatch = _sourceFileText.match (_copyrightNoticeRegExp);
56
+ if (_copyrightNoticeMatch) {
57
+ var _oldCopyrightNotice = _copyrightNoticeMatch [0];
58
+ if (_oldCopyrightNotice == '(c)' + _thisYear) {
59
+ _copyrightNoticeMatch = null;
60
+ } else {
61
+ var
62
+ _endYearMatch = _oldCopyrightNotice.match (_copyrightNoticeEndYearRegExp),
63
+ _newCopyrightNotice = _endYearMatch
64
+ ? _oldCopyrightNotice.replace (_copyrightNoticeEndYearRegExp,'$1' + _thisYear)
65
+ : _oldCopyrightNotice + '-' + _thisYear,
66
+ _updatedaSourceFileText =
67
+ _sourceFileText.replace (_oldCopyrightNotice,_newCopyrightNotice)
68
+ ;
69
+ }
70
+ }
71
+ return (
72
+ _copyrightNoticeMatch &&
73
+ _updatedaSourceFileText != _sourceFileText
74
+ ? {
75
+ outputText:_updatedaSourceFileText,
76
+ logDetails:
77
+ '\t\tCopyright Notice Updated:\n' +
78
+ '\t\t\tWAS: ' + _oldCopyrightNotice + '\n' +
79
+ '\t\t\tNOW: ' + _newCopyrightNotice + '\n'
80
+ }
81
+ : {logDetails:'\t\tFILE ALREADY OK\n'}
82
+ );
83
+ }
84
+ },
85
+ _params,
86
+ {alwaysBuild:true}
87
+ )
88
+ );
89
+ };
90
+
91
+ return _package;
92
+ }
93
+ });
94
+
skin/frontend/default/customproduct/js/Uize.Build.Util.js ADDED
@@ -0,0 +1,359 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ /*______________
2
+ | ______ | U I Z E J A V A S C R I P T F R A M E W O R K
3
+ | / / | ---------------------------------------------------
4
+ | / O / | MODULE : Uize.Build.Util Package
5
+ | / / / |
6
+ | / / / /| | ONLINE : http://www.uize.com
7
+ | /____/ /__/_| | COPYRIGHT : (c)2010-2012 UIZE
8
+ | /___ | LICENSE : Available under MIT License or GNU General Public License
9
+ |_______________| http://www.uize.com/license.html
10
+ */
11
+
12
+ /* Module Meta Data
13
+ type: Package
14
+ importance: 3
15
+ codeCompleteness: 100
16
+ testCompleteness: 0
17
+ docCompleteness: 2
18
+ */
19
+
20
+ /*?
21
+ Introduction
22
+ The =Uize.Build.Util= package provides various utility methods to facilitate building of pages for a Web site project.
23
+
24
+ *DEVELOPERS:* `Chris van Rensburg`
25
+ */
26
+
27
+ Uize.module ({
28
+ name:'Uize.Build.Util',
29
+ required:[
30
+ 'Uize.Url',
31
+ 'Uize.Template',
32
+ 'Uize.Data.Simple',
33
+ 'Uize.String',
34
+ 'Uize.String.Lines',
35
+ 'Uize.Json',
36
+ 'Uize.Array.Sort',
37
+ 'Uize.Services.FileSystem'
38
+ ],
39
+ builder:function () {
40
+ /*** Variables for Scruncher Optimization ***/
41
+ var
42
+ _package = function () {},
43
+ _undefined
44
+ ;
45
+
46
+ /*** General Variables ***/
47
+ var
48
+ _fileSystem = Uize.Services.FileSystem.singleton (),
49
+ _compiledJstFilesByPath = {}
50
+ ;
51
+
52
+ /*** Public Static Methods ***/
53
+ _package.getHtmlFileInfo = function (_filePath,_titleExtractor) {
54
+ var
55
+ _fileText = _fileSystem.readFile ({path:_filePath}),
56
+ _keywordsMatch = _fileText.match (/<meta name="keywords" content="(.*?)"\/>/),
57
+ _descriptionMatch = _fileText.match (/<meta name="description" content="(.*?)"\/>/),
58
+ _imageSrcMatch = _fileText.match (/<link rel="image_src" href="(.*?)"\/>/)
59
+ ;
60
+ return {
61
+ path:_filePath,
62
+ title:_titleExtractor (_fileText.match (/<title>(.*?)<\/title>/) [1]),
63
+ keywords:_keywordsMatch ? _keywordsMatch [1] : '',
64
+ description:_descriptionMatch ? _descriptionMatch [1] : '',
65
+ imageSrc:_imageSrcMatch ? Uize.Url.toAbsolute (_folderToIndex,_imageSrcMatch [1]) : ''
66
+ };
67
+ };
68
+
69
+ _package.getHtmlFilesInfo = function (_folderToIndex,_titleExtractor) {
70
+ if (!_titleExtractor) _titleExtractor = Uize.returnX;
71
+ return Uize.Array.Sort.sortBy (
72
+ Uize.map (
73
+ _fileSystem.getFiles ({
74
+ path:_folderToIndex,
75
+ pathMatcher:function (_path) {
76
+ var _urlParts = Uize.Url.from (_path);
77
+ return _urlParts.fileType == 'html' && !Uize.String.startsWith (_urlParts.file,'~');
78
+ }
79
+ }),
80
+ function (_path) {
81
+ return _package.getHtmlFileInfo (
82
+ _folderToIndex + '/' + Uize.Url.from (_path).file,
83
+ _titleExtractor
84
+ );
85
+ }
86
+ ),
87
+ 'value.title.toLowerCase ()'
88
+ );
89
+ };
90
+
91
+ _package.readSimpleDataFile = function (_simpleDataFilePath) {
92
+ return Uize.Data.Simple.parse ({
93
+ simple:_fileSystem.readFile ({path:_simpleDataFilePath}),
94
+ collapseChildren:true
95
+ });
96
+ };
97
+
98
+ _package.compileJstFile = function (_jstTemplatePath) {
99
+ var _template = _compiledJstFilesByPath [_jstTemplatePath];
100
+ if (!_template) {
101
+ if (!_fileSystem.fileExists ({path:_jstTemplatePath})) return;
102
+ _template = _compiledJstFilesByPath [_jstTemplatePath] = Uize.Template.compile (
103
+ _fileSystem.readFile ({path:_jstTemplatePath}),
104
+ {result:'full'}
105
+ );
106
+ Uize.require (_template.required);
107
+ }
108
+ return _template.templateFunction;
109
+ };
110
+
111
+ _package.processJstFile = function (_jstTemplatePath,_input) {
112
+ var _template = _package.compileJstFile (_jstTemplatePath);
113
+ _template &&
114
+ _fileSystem.writeFile ({path:_jstTemplatePath.replace (/\.jst$/,''),contents:_template (_input)})
115
+ ;
116
+ };
117
+
118
+ _package.runScripts = function (_scripts) {
119
+ var _error;
120
+ if (!Uize.isArray (_scripts)) _scripts = [_scripts];
121
+ for (
122
+ var
123
+ _scriptNo = -1,
124
+ _scriptsLength = _scripts.length,
125
+ _wshShell = new ActiveXObject ('WScript.Shell'),
126
+ _errorCode
127
+ ;
128
+ ++_scriptNo < _scriptsLength && !_error;
129
+ )
130
+ if (_errorCode = _wshShell.Run ('WScript ' + _scripts [_scriptNo],0,true))
131
+ _error = {
132
+ script:_scripts [_scriptNo],
133
+ errorCode:_errorCode
134
+ }
135
+ ;
136
+ return _error;
137
+ };
138
+
139
+ _package.runUnitTests = function (_unitTestsClass,_silent,_logFilePath) {
140
+ function _runUnitTests (_unitTestsClass) {
141
+ var
142
+ _unitTests = new _unitTestsClass,
143
+ _logChunks = []
144
+ ;
145
+ _unitTests.wire ({
146
+ Start:
147
+ function (_event) {
148
+ _logChunks.push (
149
+ Uize.String.repeat ('\t',_event.source.getDepth ()) + _event.source.get ('title')
150
+ );
151
+ },
152
+ Done:
153
+ function (_event) {
154
+ var
155
+ _test = _event.source,
156
+ _reasonForFailure = _test.get ('reasonForFailure')
157
+ ;
158
+ /*** add to log ***/
159
+ _logChunks.push (
160
+ Uize.String.repeat ('\t',_test.getDepth () + 1) +
161
+ (
162
+ _test.get ('result')
163
+ ? ('PASSED!!! (duration: ' + _test.get ('duration') + 'ms)')
164
+ : ('*** FAILED *** ' + (_reasonForFailure || ''))
165
+ )
166
+ );
167
+ _reasonForFailure && _logChunks.push ('','',_test.getSynopsis ());
168
+
169
+ /*** finish up if the test fails or if unit tests complete ***/
170
+ if (_test == _unitTests || !_test.get ('result')) {
171
+ _silent || alert (_test.getSynopsis ());
172
+ _logFilePath &&
173
+ _fileSystem.writeFile ({path:_logFilePath,contents:_logChunks.join ('\n')})
174
+ ;
175
+ _test.get ('result') || WScript.Quit (1);
176
+ }
177
+ }
178
+ });
179
+ _unitTests.run ();
180
+ }
181
+ typeof _unitTestsClass == 'string'
182
+ ? Uize.require (_unitTestsClass,_runUnitTests)
183
+ : _runUnitTests (_unitTestsClass)
184
+ ;
185
+ };
186
+
187
+ _package.dataAsModule = function (_moduleName,_moduleData) {
188
+ return [
189
+ 'Uize.module ({',
190
+ ' name:\'' + _moduleName + '\',',
191
+ ' superclass:\'\',',
192
+ ' builder:function () {',
193
+ ' return function () {',
194
+ ' return ' + Uize.String.Lines.indent (Uize.Json.to (_moduleData),3,'\t',false) + ';',
195
+ ' };',
196
+ ' }',
197
+ '});'
198
+ ].join ('\n');
199
+ };
200
+
201
+ _package.writeDataModule = function (_moduleFolderPath,_moduleName,_moduleData) {
202
+ _fileSystem.writeFile ({
203
+ path:_moduleFolderPath + '/' + _moduleName + '.js',
204
+ contents:_package.dataAsModule (_moduleName,_moduleData)
205
+ });
206
+ };
207
+
208
+ _package.buildFiles = function (_params) {
209
+ var
210
+ _alwaysBuild = _params.alwaysBuild,
211
+ _dryRun = _params.dryRun,
212
+ _doNotEnter = _params.doNotEnter,
213
+ _logFilePath = _params.logFilePath,
214
+ _logChunks = []
215
+ ;
216
+ if (Uize.isArray (_doNotEnter))
217
+ _doNotEnter = new RegExp ('^(' + _doNotEnter.join ('|') + ')$')
218
+ ;
219
+ function _processFolder (_folderPath) {
220
+ var _targetFolderPath = _doNotEnter && _doNotEnter.test (_folderPath)
221
+ ? false
222
+ : _params.targetFolderPathCreator (_folderPath)
223
+ ;
224
+ if (typeof _targetFolderPath == 'string') {
225
+ Uize.forEach (
226
+ _fileSystem.getFiles ({path:_folderPath}),
227
+ function (_sourceFileName) {
228
+ var
229
+ _sourceFilePath = _folderPath + (_folderPath && '/') + _sourceFileName,
230
+ _targetFileName = _params.targetFilenameCreator (_sourceFileName)
231
+ ;
232
+ if (_targetFileName) {
233
+ var
234
+ _targetFilePath = _targetFolderPath + '/' + _targetFileName,
235
+ _buildReason = _alwaysBuild
236
+ ? 'ALWAYS BUILD'
237
+ : (
238
+ _fileSystem.fileExists ({path:_targetFilePath})
239
+ ? (
240
+ _fileSystem.getModifiedDate ({path:_sourceFilePath}) >
241
+ _fileSystem.getModifiedDate ({path:_targetFilePath})
242
+ ? 'WAS OUT OF DATE'
243
+ : ''
244
+ )
245
+ : 'DIDN\'T EXIST'
246
+ )
247
+ ,
248
+ _buildDuration,
249
+ _logDetails = ''
250
+ ;
251
+ if (_buildReason) {
252
+ var
253
+ _timeBeforeBuild = Uize.now (),
254
+ _processingResult = _params.fileBuilder (
255
+ _sourceFileName,
256
+ _fileSystem.readFile ({path:_sourceFilePath})
257
+ ),
258
+ _outputText = _processingResult.outputText
259
+ ;
260
+ _logDetails = _processingResult.logDetails || '';
261
+ !_dryRun && _outputText != _undefined &&
262
+ _fileSystem.writeFile ({path:_targetFilePath,contents:_outputText})
263
+ ;
264
+ _buildDuration = Uize.now () - _timeBeforeBuild;
265
+ }
266
+ _logChunks.push (
267
+ (_buildReason ? '***** ' : '') + _sourceFilePath + '\n' +
268
+ '\tTARGET FILE: ' + _targetFilePath + '\n' +
269
+ '\t' +
270
+ (
271
+ _buildReason
272
+ ? ('BUILT (' + _buildReason + '), BUILD DURATION: ' + _buildDuration + 'ms')
273
+ : 'no action, file is current'
274
+ ) + '\n' +
275
+ _logDetails +
276
+ '\n'
277
+ );
278
+ }
279
+ }
280
+ );
281
+ }
282
+ _targetFolderPath !== false &&
283
+ Uize.forEach (
284
+ _fileSystem.getFolders ({path:_folderPath}),
285
+ function (_folderName) {_processFolder (_folderPath + (_folderPath && '/') + _folderName)}
286
+ )
287
+ ;
288
+ }
289
+ _processFolder (_params.rootFolderPath);
290
+ _logFilePath && _fileSystem.writeFile ({path:_logFilePath,contents:_logChunks.join ('')});
291
+ /*?
292
+ Static Methods
293
+ Uize.Build.Util.buildFiles
294
+ Facilitates iterating through a folder hierarchy, processing specific files, and writing the results of processing to a specified log file.
295
+
296
+ SYNTAX
297
+ ....................................................................
298
+ Uize.Build.Util.buildFiles ({
299
+ targetFolderPathCreator:targetFolderPathCreatorFUNC, // REQUIRED
300
+ targetFilenameCreator:targetFilenameCreatorFUNC, // REQUIRED
301
+ fileBuilder:fileBuilderFUNC, // REQUIRED
302
+
303
+ rootFolderPath:rootFolderPathSTR, // optional
304
+ alwaysBuild:alwaysBuildBOOL, // optional
305
+ doNotEnter:doNotEnterARRAYorREGEXP, // optional
306
+ logFilePath:logFilePathSTR // optional
307
+ });
308
+ ....................................................................
309
+
310
+ This method starts iterating through files in the folder that contains the build script being executed and then recursively iterates through subfolders.
311
+
312
+ targetFolderPathCreator
313
+ A function reference, specifying a function that should be used to create a target folder path for the output of the files being built.
314
+
315
+ The function specified by this parameter should expect to receive one string parameter, being the folder path of the files being built. The function should return a string, being the path of the target folder where the built versions of the files should be written.
316
+
317
+ In a special case, if the function returns a boolean, then the files in the current folder being processed will not be built, and the boolean value will determine if the method recurses deeper into the current folder's subfolders. This provides a way to skip building the files in the current folder but recurse deeper, or to ignore a particular folder and all its contents - files *and* subfolders.
318
+
319
+ targetFilenameCreator
320
+ A function reference, specifying a function that should be used to create the target filenames for the output of the files being built.
321
+
322
+ The function specified by this parameter should expect to receive one string parameter, being the filename of the file being built. The function should return a string, being the target filename for where the built version of the file should be written. If the source file is not to be built, based upon interrogating the source filename (perhaps it's not a type of file that should be built), then the function should return an empty string or the value =false=.
323
+
324
+ fileBuilder
325
+ A function reference, specifying a function that should be used for processing the source file to create output that should be written as the target file.
326
+
327
+ The function specified by this parameter should expect to receive two string parameters, being the filename of the source file being built and the text contents of that file. The function should return an object containing the property =outputText=, being the output text for the built version of the file, and an optional =logDetails= property that can be used to specify any extra log information to summarize or describe how the file was built.
328
+
329
+ When a file is built, the output of the function specified by the =fileBuilder= parameter will be written as a file of the name determined by the =targetFilenameCreator= function, into a folder of the path determined by the =targetFolderPathCreator= function.
330
+
331
+ rootFolderPath
332
+ A string, specifying the path of a folder to serve as the root folder from which to start building files.
333
+
334
+ alwaysBuild
335
+ An optional boolean, indicating whether or not eligible files should always be built, or whether the need to build should be determined automatically.
336
+
337
+ For any file within the folder hierarchy that would be processed by the =Uize.Build.Util.buildFiles= method (given the configuration of this method by all its parameter values), a decision to build the file will normally be made automatically by this method, based upon the target file either not existing or having an older modified date than the source file. This is the behavior for the optional =alwaysBuild= parameter's default value of =false=. When the value =true= is specified, then the file will always be built, even if it is considered to have been previously built and up-to-date.
338
+
339
+ doNotEnter
340
+ An optional array or regular expression, specifying a folder (or folders) that should not be entered when recursing through the folder hierarchy.
341
+
342
+ Any folders specified by this parameter will terminate recursion at that point in the folder tree, and any folders contained inside these dead end folders will not be processed. If a regular expression is specified for this parameter, then this regular expression will be tested against the folder name currently being processed by the =Uize.Build.Util.buildFiles= method. If the regular expression matches, then the method will not enter the folder.
343
+
344
+ This parameter is useful for build scripts that should ignore files generated by the build script (or other build scripts) and that are stored in a special build directory. Your site project may also contain a folder of build scripts, and you may not wish any build script using the =Uize.Build.Util.buildFiles= method to process any of the files contained therein.
345
+
346
+ logFilePath
347
+ An optional string, specifying the filename of a file within the same folder as the build script that should be used for writing out the log of the build process.
348
+
349
+ Basic information is automatically placed into the log file by the =Uize.Build.Util.buildFiles= method, but additional information for each built file can be added by returning text for the optional =logDetails= property of your =fileBuilder= function's return object.
350
+
351
+ NOTES
352
+ - If no =logFilePath= parameter is specified, or if it's value is an empty string, =null=, or =undefined=, then the filename for the log file will be derived from the filename of the build script, with the ".js" file extension replaced with the extension ".log".
353
+ */
354
+ };
355
+
356
+ return _package;
357
+ }
358
+ });
359
+
skin/frontend/default/customproduct/js/Uize.Build.js ADDED
@@ -0,0 +1,28 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ /*______________
2
+ | ______ | U I Z E J A V A S C R I P T F R A M E W O R K
3
+ | / / | ---------------------------------------------------
4
+ | / O / | MODULE : Uize.Build Namespace
5
+ | / / / |
6
+ | / / / /| | ONLINE : http://www.uize.com
7
+ | /____/ /__/_| | COPYRIGHT : (c)2012 UIZE
8
+ | /___ | LICENSE : Available under MIT License or GNU General Public License
9
+ |_______________| http://www.uize.com/license.html
10
+ */
11
+
12
+ /* Module Meta Data
13
+ type: Namespace
14
+ importance: 1
15
+ codeCompleteness: 100
16
+ testCompleteness: 100
17
+ docCompleteness: 100
18
+ */
19
+
20
+ /*?
21
+ Introduction
22
+ The =Uize.Build= module defines a namespace for the various build scripts offered by the UIZE JavaScript Framework.
23
+
24
+ *DEVELOPERS:* `Chris van Rensburg`
25
+ */
26
+
27
+ Uize.module ({name:'Uize.Build'});
28
+
skin/frontend/default/customproduct/js/Uize.Class.Value.js ADDED
@@ -0,0 +1,44 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ /*______________
2
+ | ______ | U I Z E J A V A S C R I P T F R A M E W O R K
3
+ | / / | ---------------------------------------------------
4
+ | / O / | MODULE : Uize.Class.Value Class
5
+ | / / / |
6
+ | / / / /| | ONLINE : http://www.uize.com
7
+ | /____/ /__/_| | COPYRIGHT : (c)2012 UIZE
8
+ | /___ | LICENSE : Available under MIT License or GNU General Public License
9
+ |_______________| http://www.uize.com/license.html
10
+ */
11
+
12
+ /* Module Meta Data
13
+ type: Class
14
+ importance: 1
15
+ codeCompleteness: 100
16
+ testCompleteness: 0
17
+ docCompleteness: 100
18
+ */
19
+
20
+ /*?
21
+ Introduction
22
+ The =Uize.Class.Value= class is a simple class that merely implements the `value interface` (ie. it registers a =value= state property).
23
+
24
+ *DEVELOPERS:* `Chris van Rensburg`
25
+
26
+ Methods of a number of different UIZE modules implement special handling for parameter values that are instances of =Uize.Class= subclasses that support the `value interface`. The =Uize.Class.Value= class is intended primarily for use in various unit tests that test the behavior of such methods.
27
+ */
28
+
29
+ Uize.module ({
30
+ name:'Uize.Class.Value',
31
+ superclass:'Uize.Class',
32
+ builder:function (_superclass) {
33
+ /*** Class Constructor ***/
34
+ var _class = _superclass.subclass ();
35
+
36
+ /*** Register Properties ***/
37
+ _class.registerProperties ({
38
+ _value:'value'
39
+ });
40
+
41
+ return _class;
42
+ }
43
+ });
44
+
skin/frontend/default/customproduct/js/Uize.Class.js ADDED
@@ -0,0 +1,2288 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ /*______________
2
+ | ______ | U I Z E J A V A S C R I P T F R A M E W O R K
3
+ | / / | ---------------------------------------------------
4
+ | / O / | MODULE : Uize.Class Base Class
5
+ | / / / |
6
+ | / / / /| | ONLINE : http://www.uize.com
7
+ | /____/ /__/_| | COPYRIGHT : (c)2003-2012 UIZE
8
+ | /___ | LICENSE : Available under MIT License or GNU General Public License
9
+ |_______________| http://www.uize.com/license.html
10
+ */
11
+
12
+ /* Module Meta Data
13
+ type: Class
14
+ importance: 10
15
+ codeCompleteness: 100
16
+ testCompleteness: 40
17
+ docCompleteness: 100
18
+ */
19
+
20
+ /*?
21
+ Introduction
22
+ The =Uize.Class= module defines a base class from which many of the classes in the UIZE JavaScript Framework inherit.
23
+
24
+ *DEVELOPERS:* `Chris van Rensburg`
25
+
26
+ Key Features
27
+ Event System
28
+ The =Uize.Class= module implements a powerful and versatile event system, which can be used for application events outside the context of browser DOM events.
29
+
30
+ Event System Methods
31
+ The `event system` of the =Uize.Class= module is exposed through the following methods...
32
+
33
+ - =fire= - fires an event on an instance
34
+ - =unwire= - unwires handlers for one or more events on an instance
35
+ - =wire= - wires handlers for one or more events on an instance
36
+ - =Uize.Class.fire= - fires an event on a class
37
+ - =Uize.Class.unwire= - unwires handlers for one or more events on a class
38
+ - =Uize.Class.wire= - wires handlers for one or more events on a class
39
+
40
+ For an in-depth discussion of events, consult the [[../explainers/javascript-event-system.html][JavaScript Event System]] explainer.
41
+
42
+ Condition System
43
+ The =Uize.Class= module implements a condition system in the form of state properties combined with convenience methods that allow state properties to be treated semantically as conditions.
44
+
45
+ Condition System Methods
46
+ The `condition system` of the =Uize.Class= module is exposed through the following methods...
47
+
48
+ - =is= - returns whether or not a condition has been met
49
+ - =once= - registers code that is to be executed once a condition has been met
50
+ - =met= - sets a condition as having been met
51
+ - =unmet= - sets a condition as having not been met / no longer being met
52
+
53
+ The "no new" Mechanism
54
+ The JavaScript =new= operator is optional when creating instances of =Uize.Class= subclasses, and you can make the =new= operator optional for your own object constructors using the newly added =Uize.noNew= static method.
55
+
56
+ Creating Instances of Uize Classes
57
+ Because the =Uize.Class= base class utilizes `the "no new" mechanism`, one can create instances of any =Uize.Class= subclass either using the =new= operator or not.
58
+
59
+ EXAMPLE
60
+ ................................................................................
61
+ // this works
62
+ var mySlider1 = new Uize.Widget.Bar.Slider ({minValue:0,maxValue:100,value:50});
63
+
64
+ // Look ma, no "new"!!!
65
+ var mySlider2 = Uize.Widget.Bar.Slider ({minValue:0,maxValue:100,value:50});
66
+ ................................................................................
67
+
68
+ All Uize Classes Get the Benefit
69
+ Because of the way in which `the "no new" mechanism` is implemented in the =Uize.Class= base class, any class that is derived from a =Uize.Class= base class using the =subclass= method gets the same benefit, including classes that you create for your own applications.
70
+
71
+ This means, for example, that any widget class you create by subclassing the =Uize.Widget= class will get the same benefit. Consider the following example...
72
+
73
+ EXAMPLE
74
+ ..................................................
75
+ // we create a widget class
76
+ var MyWidgetClass = Uize.Widget.subclass ();
77
+
78
+ // this works
79
+ var myWidgetClassInstance1 = new MyWidgetClass ();
80
+
81
+ // Look ma, no "new"!!!
82
+ var myWidgetClassInstance2 = MyWidgetClass ();
83
+ ..................................................
84
+
85
+ Applies for Other Uize Objects
86
+ `The "no new" mechanism`, that is implemented in the =Uize.noNew= static method, has been applied to various other =Uize= objects (such as the =Uize.Color= object) that are lightweight objects rather than full =Uize.Class= subclasses.
87
+
88
+ So, for example, one can create instances of the =Uize.Color= object or the =Uize.String.Builder= object without needing to use the =new= operator. Consider the following example...
89
+
90
+ EXAMPLE
91
+ .........................................
92
+ // this works
93
+ var fuchsia = new Uize.Color ('#ff0fff');
94
+
95
+ // Look ma, no "new"!!!
96
+ var olive = Uize.Color ('#808000');
97
+ .........................................
98
+
99
+ Using the Uize.noNew Method
100
+ An object constructor that supports `the "no new" mechanism` can easily be created using the =Uize.noNew= static method.
101
+
102
+ In cases where you're creating =Uize.Class= subclasses, you don't need to worry about the =Uize.noNew= method because `the "no new" mechanism` is built right into the =Uize.Class= base class, so `all Uize classes get the benefit`. However, in cases where you're defining your own lightweight objects, you can use the =Uize.noNew= method to create an object constructor where the =new= operator is optional. Consider the following example...
103
+
104
+ EXAMPLE
105
+ ............................................................
106
+ // define the Food object
107
+ var Food = Uize.noNew (
108
+ function (name,type) {
109
+ this.name = name;
110
+ this.type = type;
111
+ }
112
+ );
113
+
114
+ // create an instance of Food using the new operator
115
+ var apple = new Food ('apple','fruit');
116
+ alert (apple.type); // alerts the text "fruit"
117
+
118
+ // create an instance of Food without using the new operator
119
+ var rice = Food ('rice','grain');
120
+ alert (rice.type); // alerts the text "grain"
121
+ ............................................................
122
+
123
+ What you'll notice from the above example is that the =Uize.noNew= method is quite simple - it takes a single parameter, which is the constructor function that initializes the new instance. This means that you can easily take an existing object constructor function and upgrade it to one that supports `the "no new" mechanism` by wrapping it inside a call to the =Uize.noNew= method, which then returns a wrapper constructor that becomes your new object constructor. Consider the following before-and-after example...
124
+
125
+ BEFORE
126
+ ..............................................
127
+ // must always use "new" with this constructor
128
+ function Food (name,type) {
129
+ this.name = name;
130
+ this.type = type;
131
+ }
132
+ ..............................................
133
+
134
+ AFTER
135
+ ..........................................
136
+ // "new" is optional with this constructor
137
+ var Food = Uize.noNew (
138
+ function (name,type) {
139
+ this.name = name;
140
+ this.type = type;
141
+ }
142
+ );
143
+ ..........................................
144
+
145
+ Notice that you need to assign the result of the =Uize.noNew= method call, and so your original constructor function no longer should have the name.
146
+ */
147
+
148
+ Uize.module ({
149
+ name:'Uize.Class',
150
+ builder:function (_superclass) {
151
+ /*** Variables for Scruncher Optimization ***/
152
+ var
153
+ _undefined,
154
+ _typeString = 'string',
155
+ _typeObject = 'object',
156
+
157
+ /*** references to utility methods of Uize ***/
158
+ _Uize = Uize,
159
+ _clone = _Uize.clone,
160
+ _copyInto = _Uize.copyInto,
161
+ _forEach = _Uize.forEach,
162
+ _map = _Uize.map,
163
+ _lookup = _Uize.lookup,
164
+ _getClass = _Uize.getClass,
165
+ _getGuid = _Uize.getGuid,
166
+ _globalEval = _Uize.globalEval,
167
+ _isArray = _Uize.isArray,
168
+ _isFunction = _Uize.isFunction,
169
+ _isInstance = _Uize.isInstance,
170
+ _isObject = _Uize.isObject,
171
+ _noNew = _Uize.noNew,
172
+ _pairUp = _Uize.pairUp
173
+ ;
174
+
175
+ /*** General Variables ***/
176
+ var
177
+ _sacredEmptyArray = [],
178
+ _sacredEmptyObject = {}
179
+ ;
180
+
181
+ /*** Class Constructor ***/
182
+ var
183
+ _class = _createSubclass (
184
+ function () {},
185
+ /*** alphastructor ***/
186
+ function () {
187
+ /*** Public Instance Properties ***/
188
+ this.instanceId = _getGuid ();
189
+ /*?
190
+ Instance Properties
191
+ instanceId
192
+ An automatically generated name, that can be used as a means of identifying the specific instance in other code.
193
+
194
+ When designing JavaScript classes, it is sometimes necessary in the class's implementation to set intervals, timeouts, or the event handlers of HTML nodes that make up an instance's user interface, so that they execute methods of the instance. Sometimes this must be done by generating JavaScript code that is to be interpreted. This generated code must, therefore, be able to reference its instance using a global identifier, because the code will be executed in a global context.
195
+
196
+ If the constructor of your class uses the automatically generated value of an instance's =instanceId= property to assign a global reference to the instance, with a statement like =window [_this.instanceId] &#61; _this=, then the =instanceId= property can be used when generating JavaScript code that is to execute methods on the instance. Consider the following example...
197
+
198
+ ..................................................................
199
+ MyClass.prototype.click = function () {
200
+ // do something when the button is clicked
201
+ };
202
+
203
+ MyClass.prototype.insertButton = function () {
204
+ document.writeln (
205
+ '<input ' +
206
+ 'type="button" ' +
207
+ 'onclick="' + this.instanceId + '.click (); return false"' +
208
+ '/>'
209
+ );
210
+ };
211
+ ..................................................................
212
+
213
+ In the above example, we see a segment of the implementation for a =Uize.Class= subclass named =MyClass=. The =insertButton= instance method is writing HTML into the document, and the =input= tag that is created has an =onclick= attribute that registers an event handler that will execute the =click= method of that instance when clicked. That's because the global identifier by the name stored in the =instanceId= property is a reference to the instance.
214
+
215
+ NOTES
216
+ - the =instanceId= property's value is guaranteed to be unique for all instances of all =Uize.Class= subclasses in a document, but not across frames in a frameset, or across multiple pages in a Web site
217
+ */
218
+ },
219
+ /*** omegastructor ***/
220
+ function (_properties) {
221
+ /*** Initialize Properties ***/
222
+ _properties || (_properties = _sacredEmptyObject);
223
+ var
224
+ _propertiesForSet = {},
225
+ _instancePropertyDefaults = this.Class._instancePropertyDefaults,
226
+ _property,
227
+ _propertyDefault
228
+ ;
229
+ for (_property in _instancePropertyDefaults) {
230
+ if (_property in _properties)
231
+ _propertiesForSet [_property] = _properties [_property];
232
+ else if ((_propertyDefault = _instancePropertyDefaults [_property]) !== _undefined)
233
+ _propertiesForSet [_property] = _propertyDefault
234
+ ;
235
+ }
236
+ for (_property in _properties)
237
+ _property in _propertiesForSet || (_propertiesForSet [_property] = _properties [_property])
238
+ ;
239
+ this.set (_propertiesForSet);
240
+ }
241
+ ),
242
+ _classPrototype = _class.prototype,
243
+ _classNonInheritableStatics = _class.nonInheritableStatics
244
+ ;
245
+
246
+ /*** Property System Support Code ***/
247
+ function _getPropertyProfile (_this,_propertyPublicOrPrivateName) {
248
+ var _class = _getClass (_this);
249
+ return (
250
+ _class._propertyProfilesByPublicNames [_propertyPublicOrPrivateName] ||
251
+ _class._propertyProfilesByPrivateNames [_propertyPublicOrPrivateName]
252
+ );
253
+ }
254
+
255
+ function _getPropertyPrivateName (_this,_propertyPublicOrPrivateName) {
256
+ var _propertyProfile = _getPropertyProfile (_this,_propertyPublicOrPrivateName);
257
+ return _propertyProfile ? _propertyProfile._privateName : _propertyPublicOrPrivateName;
258
+ }
259
+
260
+ /*** Private Instance-Static Methods ***/
261
+ /*** Event System Methods ***/
262
+ _class._abstractEventName = _classPrototype._abstractEventName = function (_eventName,_managementFunction) {
263
+ if (_eventName.charCodeAt (0) == 67 && !_eventName.indexOf ('Changed.')) {
264
+ var
265
+ _this = this,
266
+ _propertyPublicName = _eventName.slice (8),
267
+ _propertyProfile = _getPropertyProfile (_this,_propertyPublicName)
268
+ ;
269
+ if (_propertyProfile && _propertyPublicName != _propertyProfile._publicName)
270
+ // use the canonical public name, since a pseudonym could have been specified
271
+ _eventName = 'Changed.' + (_propertyPublicName = _propertyProfile._publicName)
272
+ ;
273
+ _managementFunction (_eventName);
274
+ (_this._hasChangedHandlers || (_this._hasChangedHandlers = {})) [_propertyPublicName] =
275
+ _this._eventHandlers && _this._eventHandlers [_eventName]
276
+ ;
277
+ } else {
278
+ _managementFunction (_eventName);
279
+ }
280
+ };
281
+
282
+ /*** Public Instance-Static Methods ***/
283
+ /*** Event System Methods ***/
284
+ _class.wire = _classPrototype.wire = function (_eventNameOrEventsMap,_handler) {
285
+ var _this = this;
286
+ if (arguments.length == 2) {
287
+ _this._abstractEventName (
288
+ _eventNameOrEventsMap,
289
+ function (_eventName) {
290
+ var _eventHandlers = _this._eventHandlers || (_this._eventHandlers = {});
291
+ (_eventHandlers [_eventName] || (_eventHandlers [_eventName] = [])).push (
292
+ {
293
+ _eventName:_eventName,
294
+ _handler:
295
+ _isFunction (_handler)
296
+ ? _handler
297
+ : typeof _handler == _typeString
298
+ ? new Function (_handler)
299
+ : function (_event) {_handler.fire (_event)},
300
+ _originalHandler:_handler
301
+ }
302
+ );
303
+ }
304
+ );
305
+ } else if (_isObject (_eventNameOrEventsMap)) {
306
+ for (var _eventName in _eventNameOrEventsMap)
307
+ this.wire (_eventName,_eventNameOrEventsMap [_eventName])
308
+ ;
309
+ }
310
+ /*?
311
+ Instance Methods
312
+ wire
313
+ Lets you wire a handler for a specific instance event, or handlers for multiple instance events.
314
+
315
+ SYNTAX
316
+ ........................................................
317
+ myInstance.wire (eventNameSTR,eventHandlerSTRorFNorOBJ);
318
+ ........................................................
319
+
320
+ Event handlers registered using this method will handle events fired for the instance using the =fire= instance method, and not those events fired using the =Uize.Class.fire= static method. A =Uize.Class= subclass may not provide any instance events, so you should consult the reference documentation for a class to learn more about its suite of events. Handlers specified by the =eventHandlerSTRorFNorOBJ= parameter may be of string, function, or object type.
321
+
322
+ EXAMPLE
323
+ ...........................................................
324
+ mySlider.wire (
325
+ 'Changed.value',
326
+ function () {Uize.Node.setValue ('valueField',mySlider)}
327
+ );
328
+ ...........................................................
329
+
330
+ VARIATION
331
+ .............................................
332
+ myInstance.wire (eventNamesToHandlersMapOBJ);
333
+ .............................................
334
+
335
+ When only a single =eventNamesToHandlersMapOBJ= parameter is specified, then event handlers for multiple events can be specified using an object hash. This variation is provided as a convenience and has the effect of iteratively calling the =wire= instance method for each event-name-to-handler mapping in the =eventNamesToHandlersMapOBJ= object.
336
+
337
+ EXAMPLE
338
+ ...................................................................................
339
+ mySlider.wire ({
340
+ 'Changed.value':
341
+ function () {Uize.Node.setValue ('valueField',mySlider)},
342
+ 'Changed.maxValue':
343
+ function () {Uize.Node.setValue ('maxValueField',mySlider.get ('maxValue'))},
344
+ 'Changed.minValue':
345
+ function () {Uize.Node.setValue ('minValueField',mySlider.get ('minValue'))}
346
+ });
347
+ ...................................................................................
348
+
349
+ SPECIAL VALUES
350
+ - the string value ="*"= acts as a wildcard when specified for the =eventNameSTR= parameter, meaning that the specified handler should be executed for all events of the instance
351
+
352
+ NOTES
353
+ - see the related =fire= and =unwire= instance methods
354
+ - compare to the =Uize.Class.fire=, =Uize.Class.wire=, and =Uize.Class.unwire= static methods
355
+
356
+ Static Methods
357
+ Uize.Class.wire
358
+ Lets you wire a handler for a static event of the class, or handlers for multiple static events.
359
+
360
+ SYNTAX
361
+ .....................................................
362
+ MyClass.wire (eventNameSTR,eventHandlerSTRorFNorOBJ);
363
+ .....................................................
364
+
365
+ Event handlers registered using this method will handle events fired for the class using the =Uize.Class.fire= static method, and not those events fired using the =fire= instance method. A =Uize.Class= subclass may not provide any static events, so you should consult the reference documentation for a class to learn more about its suite of events. Handlers specified by the =eventHandlerSTRorFNorOBJ= parameter may be of string, function, or object type.
366
+
367
+ VARIATION
368
+ ..........................................
369
+ MyClass.wire (eventNamesToHandlersMapOBJ);
370
+ ..........................................
371
+
372
+ When only a single =eventNamesToHandlersMapOBJ= parameter is specified, then event handlers for multiple events can be specified using an object hash. This variation is provided as a convenience and has the effect of iteratively calling the =Uize.Class.wire= static method for each event-name-to-handler mapping in the =eventNamesToHandlersMapOBJ= object.
373
+
374
+ SPECIAL VALUES
375
+ - the string value ="*"= acts as a wildcard when specified for the =eventNameSTR= parameter, meaning that the specified handler should be executed for all events of the class
376
+
377
+ NOTES
378
+ - see the related =Uize.Class.fire= and =Uize.Class.unwire= static methods
379
+ - compare to the =fire=, =wire=, and =unwire= instance methods
380
+
381
+ Parameters
382
+ eventHandlerSTRorFNorOBJ
383
+ All of the instance and static methods for adding and removing event handlers allow handlers to be specified in a number of different ways.
384
+
385
+ Function Type Handlers
386
+ By far the most common type of handler used when wiring event handlers is a function reference.
387
+
388
+ A function registered as a handler for an event should expect to receive one parameter, being a reference to the event object that is associated to the event.
389
+
390
+ String Type Handlers
391
+ When a string value is specified for the =eventHandlerSTRorFNorOBJ= parameter, a function object will be constructed from that string for the purpose of handling the event.
392
+
393
+ One limitation of this handler type is that, unlike `Function Type Handlers`, a code string specified by the =eventHandlerSTRorFNorOBJ= parameter cannot reference the event object.
394
+
395
+ Object Type Handlers
396
+ When a reference to a =Uize.Class= subclass or an instance of a =Uize.Class= subclass is specified for the =eventHandlerSTRorFNorOBJ= parameter, then the event for which the handler is registered will be fired on that instance or class.
397
+
398
+ This facility provides a means for "relaying" instance or class events to another instance or class.
399
+
400
+ EXAMPLE
401
+ .....................................................
402
+ myWidget.children.someButton.wire ('Click',myWidget);
403
+ .....................................................
404
+
405
+ In the above example, a handler is being registered for the ='Click'= event of a button (an instance of the =Uize.Widget.Button= class) that is a child widget of =myWidget=. By specifying =myWidget= as the handler for the =Click= event, that event will get relayed to =myWidget=. This means that other code can now register handlers on the =Click= event for =myWidget=, and those handlers will handle the =Click= event being relayed from the button widget.
406
+
407
+ Object handlers added in this way can be removed by using the =unwire= instance method and the =Uize.Class.unwire= static method, just as with any other type of handler, as in...
408
+
409
+ .......................................................
410
+ myWidget.children.someButton.unwire ('Click',myWidget);
411
+ .......................................................
412
+
413
+ Value for Removing Must Match Value Used for Adding
414
+ However a handler is specified when wiring an event, that is how it must be specified in order to unwire the event.
415
+
416
+ If you specified a function reference as the handler when wiring an event, then you must specify that same, identical function reference in order to unwire that event. If you specified a code string as the handler, then you must specify the exact same code string in order to unwire that event. If you specified a reference to a =Uize.Class= subclass or an instance of a =Uize.Class= subclass as the handler when wiring an event, then you must specify the exact same object reference in order to unwire the event.
417
+
418
+ eventNamesToHandlersMapOBJ
419
+ An object, specifying handlers for multiple events using event-name-to-handler mappings, where the key of each property is an event name and the value of each property is an event's corresponding handler.
420
+
421
+ The contents of this object should be of the form...
422
+
423
+ ........................................
424
+ {
425
+ event1Name:event1HandlerSTRorFNorOBJ,
426
+ event2Name:event2HandlerSTRorFNorOBJ,
427
+ ...
428
+ eventNName:eventNHandlerSTRorFNorOBJ
429
+ }
430
+ ........................................
431
+
432
+ The value for each property in this object should conform to the =eventHandlerSTRorFNorOBJ= parameter type.
433
+ */
434
+ };
435
+
436
+ _class.fire = _classPrototype.fire = function (_event) {
437
+ /* NOTES
438
+ - this code is deliberately optimized for performance and not code size, since event firing is a mechanism that is heavily utilized. This will explain some patterns here that may seem slightly out of character, with seemingly redundant code or a lack of typical factoring out.
439
+ */
440
+ if (typeof _event != _typeObject) _event = {name:_event};
441
+ var
442
+ _this = this,
443
+ _eventHandlers = _this._eventHandlers
444
+ ;
445
+ if (_eventHandlers) {
446
+ var
447
+ _handlersForThisEvent = _eventHandlers [_event.name],
448
+ _handlersForAnyEvent = _eventHandlers ['*']
449
+ ;
450
+ if (_handlersForThisEvent || _handlersForAnyEvent) {
451
+ _event.source || (_event.source = _this);
452
+ var
453
+ _handlers = _handlersForAnyEvent && _handlersForThisEvent
454
+ ? _handlersForAnyEvent.concat (_handlersForThisEvent)
455
+ : _handlersForAnyEvent || _handlersForThisEvent
456
+ ,
457
+ _totalHandlers = _handlers.length
458
+ ;
459
+ if (_totalHandlers == 1) {
460
+ _handlers [0]._handler (_event);
461
+ } else if (_totalHandlers == 2) {
462
+ /* NOTE:
463
+ Since we make a copy of the handlers array in the case of multiple handlers (in order to avoid issues where the handlers array may be modified by the handlers themselves), this optimization for two handlers catches most cases of multiple handlers in a complex application. This avoids copying an array and also the overhead of an iterator.
464
+ */
465
+ var
466
+ _handler0 = _handlers [0]._handler,
467
+ _handler1 = _handlers [1]._handler
468
+ ;
469
+ _handler0 (_event);
470
+ _handler1 (_event);
471
+ } else {
472
+ if (!_handlersForAnyEvent || !_handlersForThisEvent)
473
+ _handlers = _handlers.concat ()
474
+ ;
475
+ /* NOTE:
476
+ When executing multiple handlers, it is necessary to make a copy of the handlers array, since it is possible that one of the handlers might execute code that affects the handlers array (eg. by using the removeHandler method).
477
+
478
+ What this means is that when an event is fired, all the handlers registered for that event at the time that it fires will be executed. Event handlers for that event that are removed by one of its handlers will still be executed, and event handlers for that event that are added by one of its handlers will not be executed.
479
+ */
480
+ for (var _handlerNo = -1; ++_handlerNo < _totalHandlers;)
481
+ _handlers [_handlerNo]._handler (_event)
482
+ ;
483
+ }
484
+ }
485
+ }
486
+ if (_event.bubble && _this.parent && _isInstance (_this)) {
487
+ _event.source || (_event.source = _this);
488
+ _this.parent.fire (_event);
489
+ }
490
+ return _event;
491
+ /*?
492
+ Instance Methods
493
+ fire
494
+ Lets you fire an event for an instance of the class.
495
+
496
+ SYNTAX
497
+ ..........................................
498
+ eventOBJ = myInstance.fire (eventNameSTR);
499
+ ..........................................
500
+
501
+ VARIATION
502
+ ......................................
503
+ eventOBJ = myInstance.fire (eventOBJ);
504
+ ......................................
505
+
506
+ When an object is specified instead of a string value, then extra event properties can be bundled with the event and will then be available to all handlers that are executed. When using this form, the =eventOBJ= object must have a =name= property that specifies the name of the event being fired.
507
+
508
+ NOTES
509
+ - see the related =wire= and =unwire= instance methods
510
+ - compare to the =Uize.Class.fire=, =Uize.Class.wire=, and =Uize.Class.unwire= static methods
511
+
512
+ Static Methods
513
+ Uize.Class.fire
514
+ Lets you fire a static event for the class.
515
+
516
+ SYNTAX
517
+ .......................................
518
+ eventOBJ = MyClass.fire (eventNameSTR);
519
+ .......................................
520
+
521
+ VARIATION
522
+ ........................
523
+ MyClass.fire (eventOBJ);
524
+ ........................
525
+
526
+ When an object is specified instead of a string value, then extra event properties can be bundled with the event and will then be available to all handlers that are executed. When using this form, the =eventOBJ= object must have a =name= property that specifies the name of the event being fired.
527
+
528
+ NOTES
529
+ - see the related =Uize.Class.wire= and =Uize.Class.unwire= static methods
530
+ - compare to the =fire=, =wire=, and =unwire= instance methods
531
+ */
532
+ };
533
+
534
+ _class.unwire = _classPrototype.unwire = function (_eventNameOrEventsMap,_handler) {
535
+ var
536
+ _this = this,
537
+ _eventHandlers = _this._eventHandlers
538
+ ;
539
+ if (_eventHandlers) {
540
+ if (_isObject (_eventNameOrEventsMap)) {
541
+ for (var _eventName in _eventNameOrEventsMap)
542
+ _this.unwire (_eventName,_eventNameOrEventsMap [_eventName])
543
+ ;
544
+ } else {
545
+ _this._abstractEventName (
546
+ _eventNameOrEventsMap,
547
+ function (_eventName) {
548
+ var _handlersForEventName = _eventHandlers [_eventName];
549
+ if (_handlersForEventName) {
550
+ if (_handler) {
551
+ /* TO DO:
552
+ this is a candidate for factoring out as a generally useful array manipulation method: removeAllOfValue
553
+ */
554
+ for (var _handlerNo = _handlersForEventName.length; --_handlerNo >= 0;)
555
+ _handlersForEventName [_handlerNo]._originalHandler == _handler && _handlersForEventName.splice (_handlerNo,1)
556
+ ;
557
+ }
558
+ (_handler && _handlersForEventName.length) || delete _eventHandlers [_eventName];
559
+ }
560
+ }
561
+ );
562
+ }
563
+ }
564
+ /*?
565
+ Instance Methods
566
+ unwire
567
+ Lets you remove a handler previously wired to an instance event, or handlers wired for multiple instance events.
568
+
569
+ SYNTAX
570
+ ..........................................................
571
+ myInstance.unwire (eventNameSTR,eventHandlerSTRorFNorOBJ);
572
+ ..........................................................
573
+
574
+ VARIATION 1
575
+ .................................
576
+ myInstance.unwire (eventNameSTR);
577
+ .................................
578
+
579
+ When no =eventHandlerSTRorFNorOBJ= parameter is specified, then all handlers registered for the event specified in the =eventNameSTR= parameter will be removed.
580
+
581
+ VARIATION 2
582
+ ...............................................
583
+ myInstance.unwire (eventNamesToHandlersMapOBJ);
584
+ ...............................................
585
+
586
+ When only a single =eventNamesToHandlersMapOBJ= parameter is specified, then event handlers for multiple events can be specified using an object hash. This variation is provided as a convenience and has the effect of iteratively calling the =unwire= instance method for each event-name-to-handler mapping in the =eventNamesToHandlersMapOBJ= object.
587
+
588
+ NOTES
589
+ - see the related =fire= and =wire= instance methods
590
+ - compare to the =Uize.Class.fire=, =Uize.Class.wire=, and =Uize.Class.unwire= static methods
591
+
592
+ Static Methods
593
+ Uize.Class.unwire
594
+ Lets you remove a handler previously wired to a static event, or handlers wired for multiple static events.
595
+
596
+ SYNTAX
597
+ .......................................................
598
+ MyClass.unwire (eventNameSTR,eventHandlerSTRorFNorOBJ);
599
+ .......................................................
600
+
601
+ VARIATION 1
602
+ ..............................
603
+ MyClass.unwire (eventNameSTR);
604
+ ..............................
605
+
606
+ When no =eventHandlerSTRorFNorOBJ= parameter is specified, then all handlers registered for the event specified in the =eventNameSTR= parameter will be removed.
607
+
608
+ VARIATION 2
609
+ ............................................
610
+ MyClass.unwire (eventNamesToHandlersMapOBJ);
611
+ ............................................
612
+
613
+ When only a single =eventNamesToHandlersMapOBJ= parameter is specified, then event handlers for multiple events can be specified using an object hash. This variation is provided as a convenience and has the effect of iteratively calling the =Uize.Class.unwire= static method for each event-name-to-handler mapping in the =eventNamesToHandlersMapOBJ= object.
614
+
615
+ NOTES
616
+ - see the related =Uize.Class.fire= and =Uize.Class.wire= static methods
617
+ - compare to the =fire=, =wire=, and =unwire= instance methods
618
+ */
619
+ };
620
+
621
+
622
+ var _newFunction = new Function (
623
+ 'a', // arguments
624
+ 'b', // body
625
+ 'var f; return eval ("f = function (" + a.join (",") + ") {" + b + "}")'
626
+ );
627
+
628
+ var _derivationCache = {};
629
+ function _resolveDerivation (_derivation) {
630
+ /* NOTE: this code will eventually be used also for derived properties */
631
+ var
632
+ _derivationCacheKey = _derivation + '',
633
+ _resolvedDerivation = _derivationCache [_derivationCacheKey]
634
+ ;
635
+ function _getDeterminantsFromListStr (_determinantsStr) {
636
+ return _determinantsStr.replace (/\s+/g,'').split (',');
637
+ }
638
+ if (!_resolvedDerivation) {
639
+ var
640
+ _determinants,
641
+ _determiner
642
+ ;
643
+ if (Uize.isFunction (_derivation)) {
644
+ _determinants = _getDeterminantsFromListStr ((_derivation + '').match (/\(([^\)]*)\)/) [1]);
645
+ _determiner = _derivation;
646
+ } else {
647
+ if (typeof _derivation == 'string') {
648
+ var _separatorPos = _derivation.indexOf (':');
649
+ if (_separatorPos > -1) {
650
+ _determiner = _newFunction (
651
+ _determinants = _getDeterminantsFromListStr (_derivation.slice (0,_separatorPos)),
652
+ 'return ' + _derivation.slice (_separatorPos + 1)
653
+ );
654
+ } else {
655
+ _derivation = _getDeterminantsFromListStr (_derivation);
656
+ }
657
+ }
658
+ if (Uize.isArray (_derivation)) {
659
+ _determinants = [];
660
+ if (_derivation.length) {
661
+ var
662
+ _determinerArgs = [],
663
+ _determinerOperands = []
664
+ ;
665
+ _forEach (
666
+ _derivation,
667
+ function (_determinant,_determinantNo) {
668
+ var
669
+ _inverted = _determinant.charCodeAt (0) == 33,
670
+ _argName = 'a' + _determinantNo
671
+ ;
672
+ _determinants.push (_inverted ? _determinant.slice (1) : _determinant);
673
+ _determinerArgs.push (_argName);
674
+ _determinerOperands.push ((_inverted ? '!' : '') + _argName);
675
+ }
676
+ );
677
+ _determiner = _newFunction (_determinerArgs,'return ' + _determinerOperands.join (' && '));
678
+ } else {
679
+ _determiner = _Uize.returnTrue;
680
+ }
681
+ }
682
+ }
683
+ _resolvedDerivation = _derivationCache [_derivationCacheKey] = {
684
+ _determinants:_determinants,
685
+ _determinantsValuesHarvester:new Function (
686
+ 'return [' + _map (_determinants,'"this.get(\'" + value + "\')"').join (',') + ']'
687
+ ),
688
+ _determiner:_determiner,
689
+ _changedEventNames:_map (_determinants,'"Changed." + value')
690
+ };
691
+ }
692
+ return _resolvedDerivation;
693
+ }
694
+
695
+ _classPrototype.once = function (_condition,_handler) {
696
+ var
697
+ _this = this,
698
+ _derivation = _resolveDerivation (_condition),
699
+ _determinants = _derivation._determinants,
700
+ _determinantsValuesHarvester = _derivation._determinantsValuesHarvester,
701
+ _determiner = _derivation._determiner,
702
+ _wirings
703
+ ;
704
+ function _isConditionMet () {
705
+ var
706
+ _determinantsValues = _determinantsValuesHarvester.call (_this),
707
+ _conditionMet = _determiner.apply (0,_determinantsValues)
708
+ ;
709
+ if (_conditionMet) {
710
+ _wirings && _this.unwire (_wirings);
711
+ _handler.apply (0,_determinantsValues);
712
+ }
713
+ return _conditionMet;
714
+ }
715
+ if (_isConditionMet ()) {
716
+ _wirings = {};
717
+ } else {
718
+ _this.wire (_wirings = _lookup (_derivation._changedEventNames,_isConditionMet));
719
+ }
720
+ return _wirings;
721
+ /*?
722
+ Instance Methods
723
+ once
724
+ Lets you register a handler that should be executed only once a condition is met.
725
+
726
+ The =once= method is useful when using one or more state properties to form a condition, and where you wish to register code that should be executed once the condition has been met, and immediately if the condition is already met at the time that the =once= method is called.
727
+
728
+ DIFFERENT USAGES
729
+
730
+ `Execute Code Once a State Property is Truthy or Falsy`
731
+ ................................................................
732
+ wiringsOBJ = myInstance.once (propertyConditionSTR,handlerFUNC);
733
+ ................................................................
734
+
735
+ `Execute Code Once Multiple State Properties Are Truthy or Falsy`
736
+ .........................................................................
737
+ wiringsOBJ = myInstance.once (propertiesConditionARRAYorSTR,handlerFUNC);
738
+ .........................................................................
739
+
740
+ `Execute Code Once a Compound Condition is Met`
741
+ ......................................................................
742
+ wiringsOBJ = myInstance.once (compoundConditionSTRorFUNC,handlerFUNC);
743
+ ......................................................................
744
+
745
+ Execute Code Once a State Property is Truthy or Falsy
746
+ In its most basic usage, code can be registered to be executed once a single state property becomes truthy or falsy.
747
+
748
+ SYNTAX
749
+ ................................................................
750
+ wiringsOBJ = myInstance.once (propertyConditionSTR,handlerFUNC);
751
+ ................................................................
752
+
753
+ The =propertyConditionSTR= parameter specifies the name of a state property, with an optional "!" (exclamation mark) prefix for indicating `condition inversion`. If simply the name of a state property is specified, then the handler code specified by the =handlerFUNC= parameter will be executed once the property is truthy. If the optional "!" prefix is specified, then the handler code will be executed once the property is falsy.
754
+
755
+ EXAMPLE 1
756
+ ........................................................
757
+ myWidget.once (
758
+ 'wired',
759
+ function () {
760
+ // do something now that the widget has been wired
761
+ }
762
+ );
763
+ ........................................................
764
+
765
+ In the above example, a handler is being registered to be executed once the widget =myWidget= has been wired (ie. the value of its =wired= state property becomes =true=).
766
+
767
+ EXAMPLE 2
768
+ ................................................................
769
+ myCollectionWidget.once (
770
+ '!isEmpty',
771
+ function () {
772
+ // do something now that the collection is no longer empty
773
+ }
774
+ );
775
+ ................................................................
776
+
777
+ In the above example, code is being registered to execute once the =isEmpty= state property is =false=.
778
+
779
+ Execute Code Once Multiple State Properties Are Truthy or Falsy
780
+ Code can be registered to be executed once all properties in a set of state properties become truthy or falsy, by specifying the state properties as an array of property names or as a comma-separated list string.
781
+
782
+ SYNTAX
783
+ .........................................................................
784
+ wiringsOBJ = myInstance.once (propertiesConditionARRAYorSTR,handlerFUNC);
785
+ .........................................................................
786
+
787
+ propertiesConditionARRAYorSTR
788
+ The value specified for the =propertiesConditionARRAYorSTR= parameter may be an array of property names or a comma-separated list string.
789
+
790
+ Whichever form is used, any property name can be prefixed with a "!" (exclamation mark) to achieve `condition inversion` for the property.
791
+
792
+ Summary of different forms...
793
+
794
+ - array of property names: =['phase1Done','phase2Done','phase3Done']=
795
+ - array of property names with `condition inversion`: =['wired','!isEmpty']=
796
+ - comma-separated list string: ='phase1Done, phase2Done, phase3Done'=
797
+ - comma-separated list with `condition inversion`: ='wired, !isEmpty'=
798
+
799
+ Whitespace Ignored for Comma-separated List String
800
+ If a comma-separated list string is specified, all whitespace in the string is ignored.
801
+
802
+ This means that whitespace around the property names is ignored, so the value ='phase1Done,phase2Done,phase3Done'= is equivalent to the value ='phase1Done, phase2Done , phase3Done'=. This also means that whitespace around the optional "!" (exclamation mark) prefix is ignored, so the value ='wired, !isEmpty'= is equivalent to the value ='wired, ! isEmpty'=.
803
+
804
+ Examples
805
+ The following examples illustrate the different ways in which multiple properties can be specified.
806
+
807
+ EXAMPLE: Array of Property Names
808
+ Multiple state properties can be specified using an array of state property names.
809
+
810
+ EXAMPLE
811
+ ........................................................
812
+ myInstance.once (
813
+ ['phase1Done','phase2Done','phase3Done'],
814
+ function () {
815
+ // execute code now that all three phases are done
816
+ }
817
+ );
818
+ ........................................................
819
+
820
+ EXAMPLE: Comma-separated List String
821
+ Multiple state properties can be specified using a comma-separated list string.
822
+
823
+ EXAMPLE
824
+ ........................................................
825
+ myInstance.once (
826
+ 'phase1Done, phase2Done, phase3Done',
827
+ function () {
828
+ // execute code now that all three phases are done
829
+ }
830
+ );
831
+ ........................................................
832
+
833
+ EXAMPLE: Array of Property Names, with Condition Inversion
834
+ Multiple state properties can be specified using an array of state property names, where some of the property names in the array are prefixed with the optional "!" to indicate `condition inversion`.
835
+
836
+ EXAMPLE
837
+ .................................................................................
838
+ myCollection.once (
839
+ ['wired','!isEmpty'],
840
+ function () {
841
+ // execute code now that the collection widget is wired and no longer empty
842
+ }
843
+ );
844
+ .................................................................................
845
+
846
+ EXAMPLE: Comma-separated List String, with Condition Inversion
847
+ Multiple state properties can be specified using a comma-separated list string, where some of the property names in the list are prefixed with the optional "!" to indicate `condition inversion`.
848
+
849
+ EXAMPLE
850
+ .................................................................................
851
+ myCollection.once (
852
+ 'wired, !isEmpty',
853
+ function () {
854
+ // execute code now that the collection widget is wired and no longer empty
855
+ }
856
+ );
857
+ .................................................................................
858
+
859
+ Execute Code Once a Compound Condition is Met
860
+ Code can be registered to be executed once a compound condition is met, by specifying the compound condition in the form of a condition function or condition expression string.
861
+
862
+ SYNTAX
863
+ ......................................................................
864
+ wiringsOBJ = myInstance.once (compoundConditionSTRorFUNC,handlerFUNC);
865
+ ......................................................................
866
+
867
+ Condition Function
868
+ A compound condition can be specified as a function, where the names of the function's arguments indicate the state properties that affect the condition and where the function's body evaluates the condition.
869
+
870
+ EXAMPLE
871
+ ..............................................................................
872
+ myFishTankWater.once (
873
+ function (width,height,depth) {return width * height * depth > 1000},
874
+ function () {
875
+ // execute code, now that the water volume of the fish tank exceeds 1000
876
+ }
877
+ }
878
+ ..............................................................................
879
+
880
+ In the above example, a compound condition is specified using a function. The arguments of the function - =width=, =height=, and =depth= - indicate that the condition is affected by the =width=, =height=, and =depth= state properties of the =myFishTankWater= instance. The function's body, =return width &#42; height &#42; depth > 1000=, evaluates the condition to be =true= when the volume of the fish tank's water is greater than =1000=.
881
+
882
+ When code is registered to be executed once the product of the =width=, =height=, and =depth= properties is greater than =1000=, if this condition is not yet met when the =once= method is called, the method will wire handlers for the =Changed.width=, =Changed.height=, and =Changed.depth= events and will re-evaluate the condition function every time any of the properties that affect the condition change value. Once the condition function returns a truthy result, the handler for the compound condition will be executed and the handlers that were wired for the =Changed.*= events will be unwired.
883
+
884
+ Condition Expression String
885
+ A compound condition can be specified as an expression string, where the names of the state properties affecting the condition are specified along with an expression string for evaluating the condition.
886
+
887
+ A condition expression string is formatted with two parts separated by a ":" (colon) delimiter, where the part before the colon is a comma-separated list of the state properties affecting the condition, and the part after the colon is an expression to be used for evaluating the condition.
888
+
889
+ EXAMPLE
890
+ ..............................................................................
891
+ myFishTankWater.once (
892
+ 'width, height, depth : width * height * depth > 1000',
893
+ function () {
894
+ // execute code, now that the water volume of the fish tank exceeds 1000
895
+ }
896
+ }
897
+ ..............................................................................
898
+
899
+ In the above example, a compound condition is specified using a `condition expression string`. In this string, the part before the colon - "width, height, depth" - indicates that the condition is affected by the =width=, =height=, and =depth= state properties of the =myFishTankWater= instance. The part after the colon - "width &#42; height &#42; depth > 1000" - evaluates the condition to be =true= when the volume of the fish tank's water (ie. the product of the =width=, =height=, and =depth= properties) is greater than =1000=.
900
+
901
+ Immediate Execution if Condition Already Met
902
+ If the condition specified in the call to the =once= method is already met at the time that the method is called, then the handler specified by the =handlerFUNC= parameter will be executed immediately.
903
+
904
+ Otherwise, handlers will be wired for the =Changed.*= (value change) events for all the state properties that affect the condition. The condition evaluator will be executed each time any of the watched properties change value. As soon as the condition becomes met (ie. the condition evaluator produces a truthy result), the handlers wired to watch the value change events of the properties will be unwired and the handler function registered for the condition will be executed. By design, the handler is only executed for the first time that the condition becomes met.
905
+
906
+ Condition Inversion
907
+ As a convenience, the =once= method supports condition inversion through an optional "!" (logical not) prefix that can be placed before the condition name.
908
+
909
+ EXAMPLE
910
+ ................................................................
911
+ myCollectionWidget.once (
912
+ '!isEmpty',
913
+ function () {
914
+ // do something now that the collection is no longer empty
915
+ }
916
+ );
917
+ ................................................................
918
+
919
+ In the above example, code is being registered to execute once the =isEmpty= state property is =false=. This is done by prefixing the "isEmpty" condition name with a "!" (bang / exclamation) character to indicate that the code should execute only once the collection is not empty (ie. the value of the =isEmpty= state property becomes =false=). The `condition inversion` facility is convenient in situations like this where you wish to execute code only once a property's value becomes falsy, rather than once the property's value becomes truthy (which is the standard behavior for the =once= method).
920
+
921
+ Condition Inversion with Multiple Property Conditions
922
+ Condition inversion can be used both with single state property conditions as well as multiple property conditions.
923
+
924
+ EXAMPLE
925
+ ................................................................
926
+ myCollectionWidget.once (
927
+ ['wired','!isEmpty'],
928
+ function () {
929
+ // do something now that the collection is wired and no longer empty
930
+ }
931
+ );
932
+ ...........................................................................
933
+
934
+ In the above example, code is being registered to be executed once the =wired= state property is truthy and the =isEmpty= state property is falsy. Condition inversion can also be used when the state properties are specified as a comma-separated list string, so specifying the condition as =['wired','!isEmpty']= is equivalent to specifying it as ='wired, !isEmpty'=.
935
+
936
+ Wirings Object
937
+ The =once= method returns a wirings object that can be supplied to the =unwire= method in order to unwire the handler, in the unlikely event that one may wish to remove the handler before the condition becomes met.
938
+
939
+ This case is unlikely to arise except in exceptional situations, but the means is provided. In most cases, you will simply discard / ignore the return value of the =once= method. In the event that the condition is met when the =once= method is called, then the returned wirings object will be an empty object.
940
+
941
+ Handler Arguments
942
+ The handler code that is registered to be executed once a condition is met will be passed the values of all the state properties that affect the condition as arguments.
943
+
944
+ EXAMPLE
945
+ ...................................................................
946
+ myFishTankWater.once (
947
+ 'width, height, depth : width * height * depth > 1000',
948
+ function (width,height,depth) {
949
+ alert (width + '(W) x ' + height + '(H) x ' + depth + '(D)');
950
+ }
951
+ }
952
+
953
+ myFishTankWater.set ({
954
+ width:10,
955
+ height:11,
956
+ depth:12
957
+ });
958
+ ...................................................................
959
+
960
+ In the above example, code is being registered to be executed once the product of the =width=, =height=, and =depth= properties of the =myFishTankWater= instance exceeds =1000=. Once the call to the =set= method has been executed, the volume of the fish tank's water will be =1320= and the handler will be executed.
961
+
962
+ Now, because the properties affecting the condition have been specified as "width, height, depth", the value of these state properties will be passed as arguments to the handler in the order =width=, =height=, and =depth=. In this case, the handler function is choosing to declare these function arguments, using the same names for the sake of clarity - you could ignore the arguments if you didn't care about the specific values at the time the condition is met, or you could use the arguments but name them differently. In this example, the =alert= statement will alert the text "10(W) x 11(H) x 12(D)".
963
+
964
+ NOTES
965
+ - see the other `condition system methods`
966
+ */
967
+ };
968
+
969
+ _classPrototype.is = function (_property) {
970
+ return !!this [_getPropertyPrivateName (this,_property)];
971
+ /*?
972
+ Instance Methods
973
+ is
974
+ Returns a boolean, indicating whether or not the specified condition is met (ie. the specified condition state property's value is truthy).
975
+
976
+ SYNTAX
977
+ ................................
978
+ myInstance.is (propertyNameSTR);
979
+ ................................
980
+
981
+ The =is= method is offered as a convenience to improve the semantics of code that is using state properties to represent conditions, and is a very thin wrapper around the =get= instance method. The statement =myInstance.is ('myCondition')= is equivalent to the statement =!!myInstance.get ('myCondition')=.
982
+
983
+ EXAMPLE
984
+ ...........................................
985
+ if (myWidget.is ('enabled')) {
986
+ // do something if the widget is enabled
987
+ }
988
+ ...........................................
989
+
990
+ In the above example, some code is being executed conditionally, based upon whether or not a widget is enabled. The =Uize.Widget= base class provides an =enabled= state property, whose value is a boolean. One could use the =get= method in this code example to achieve the same effect, but using the =is= method make the code more readable.
991
+
992
+ NOTES
993
+ - see the other `condition system methods`
994
+ */
995
+ };
996
+
997
+ _classPrototype.met = function (_propertyOrProperties) {
998
+ this.set (_propertyOrProperties,true);
999
+ /*?
1000
+ Instance Methods
1001
+ met
1002
+ Sets the specified condition (or conditions) as having been met.
1003
+
1004
+ DIFFERENT USAGES
1005
+
1006
+ `Set a Single Condition as Having Been Met`
1007
+ .................................
1008
+ myInstance.met (propertyNameSTR);
1009
+ .................................
1010
+
1011
+ `Set Multiple Conditions as Having Been Met`
1012
+ ....................................
1013
+ myInstance.met (propertyNamesARRAY);
1014
+ ....................................
1015
+
1016
+ For Improved Semantics
1017
+ The =met= method is offered as a convenience to improve the semantics of code that is using state properties to represent conditions, and is a very thin wrapper around the =set= instance method.
1018
+
1019
+ The statement =myInstance.met ('myCondition')= is equivalent to the statement =myInstance.set ('myCondition',true)=. When using a state property to represent a condition, the =met= method is a semantically elegant way to set the value of the property to =true= to indicate that the condition represented by the property has been met.
1020
+
1021
+ EXAMPLE
1022
+ .............................................
1023
+ MyClass.prototype.initialize = function () {
1024
+ // some code here to do the initialization
1025
+ this.met ('initialized');
1026
+ };
1027
+ .............................................
1028
+
1029
+ In the above example, an =initialize= instance method is defined for the class =MyClass=. In the method's implementation, after all the initialization has been performed, the =met= method is being called to indicate that the =initialized= condition has been met, where =initialized= is the name of a state property provided in =MyClass=. Now, other code can be registered to be executed only once an instance has been initialized by using the =once= instance method, as follows...
1030
+
1031
+ .............................................................
1032
+ myInstance.once (
1033
+ 'initialized',
1034
+ function () {
1035
+ // do some stuff once the instance has been initialized
1036
+ }
1037
+ );
1038
+ .............................................................
1039
+
1040
+ Set a Single Condition as Having Been Met
1041
+ In its most typical usage, a single condition can be set as having been met by specifying the name of the condition for the =propertyNameSTR= parameter.
1042
+
1043
+ SYNTAX
1044
+ .................................
1045
+ myInstance.met (propertyNameSTR);
1046
+ .................................
1047
+
1048
+ EXAMPLE
1049
+ ..........................
1050
+ this.met ('someSelected');
1051
+ ..........................
1052
+
1053
+ Set Multiple Conditions as Having Been Met
1054
+ In cases where you wish to set multiple conditions as having been met, the names of those conditions can be supplied by specifying an array for the =propertyNamesARRAY= parameter.
1055
+
1056
+ SYNTAX
1057
+ ....................................
1058
+ myInstance.met (propertyNamesARRAY);
1059
+ ....................................
1060
+
1061
+ EXAMPLE
1062
+ ....................................
1063
+ this.met (['initialized', 'ready']);
1064
+ ....................................
1065
+
1066
+ NOTES
1067
+ - see the companion =unmet= instance method
1068
+ - see the other `condition system methods`
1069
+ */
1070
+ };
1071
+
1072
+ _classPrototype.unmet = function (_propertyOrProperties) {
1073
+ this.set (_propertyOrProperties,false);
1074
+ /*?
1075
+ Instance Methods
1076
+ unmet
1077
+ Sets the specified condition (or conditions) as being unmet.
1078
+
1079
+ DIFFERENT USAGES
1080
+
1081
+ `Set a Single Condition as Being Unmet`
1082
+ ...................................
1083
+ myInstance.unmet (propertyNameSTR);
1084
+ ...................................
1085
+
1086
+ `Set Multiple Conditions as Being Unmet`
1087
+ ......................................
1088
+ myInstance.unmet (propertyNamesARRAY);
1089
+ ......................................
1090
+
1091
+ For Improved Semantics
1092
+ The =unmet= method is offered as a convenience to improve the semantics of code that is using state properties to represent conditions, and is a very thin wrapper around the =set= instance method.
1093
+
1094
+ The statement =myInstance.unmet ('myCondition')= is equivalent to the statement =myInstance.set ('myCondition',false)=. When using a state property to represent a condition, the =unmet= method is a semantically elegant way to set the value of the property to =false= to indicate that the condition represented by the property is not met / no longer met.
1095
+
1096
+ EXAMPLE
1097
+ ..............................................
1098
+ MyClass.prototype.die = function () {
1099
+ // some code here to tear down the instance
1100
+ this.unmet ('initialized');
1101
+ };
1102
+ ..............................................
1103
+
1104
+ In the above example, a =die= instance method is defined for the class =MyClass=. In the method's implementation, after all the tear down steps have been performed, the =unmet= method is being called to indicate that the =initialized= condition is no longer met, where =initialized= is the name of a state property provided in =MyClass=. It is assumed that some other method, such as an =initialize= instance method for the class, is responsible for setting the condition as having been met with a statement like =this.met ('initialized')=.
1105
+
1106
+ Set a Single Condition as Being Unmet
1107
+ In its most typical usage, a single condition can be set as being unmet by specifying the name of the condition for the =propertyNameSTR= parameter.
1108
+
1109
+ SYNTAX
1110
+ ...................................
1111
+ myInstance.unmet (propertyNameSTR);
1112
+ ...................................
1113
+
1114
+ EXAMPLE
1115
+ ............................
1116
+ this.unmet ('someSelected');
1117
+ ............................
1118
+
1119
+ Set Multiple Conditions as Being Unmet
1120
+ In cases where you wish to set multiple conditions as being unmet, the names of those conditions can be supplied by specifying an array for the =propertyNamesARRAY= parameter.
1121
+
1122
+ SYNTAX
1123
+ ......................................
1124
+ myInstance.unmet (propertyNamesARRAY);
1125
+ ......................................
1126
+
1127
+ EXAMPLE
1128
+ ......................................
1129
+ this.unmet (['initialized', 'ready']);
1130
+ ......................................
1131
+
1132
+ NOTES
1133
+ - see the companion =met= instance method
1134
+ - see the other `condition system methods`
1135
+ */
1136
+ };
1137
+
1138
+ /*** State Property System Methods ***/
1139
+ _class.get = _classPrototype.get = function (_property) {
1140
+ if (typeof _property == _typeString) {
1141
+ /* NOTE:
1142
+ Because the get method gets hit so heavily, optimize it to do as little as possible in the most common use case (where parameter is a string, being the name of the property), so no creation of and assignment to local variables.
1143
+ */
1144
+ return this [_getPropertyPrivateName (this,_property)];
1145
+ } else {
1146
+ var
1147
+ _this = this,
1148
+ _result = {}
1149
+ ;
1150
+ if (!_property) {
1151
+ /* NOTE:
1152
+ Driven off of private names to ensure that there is only one property in the object for each actual state property, otherwise you can end up in bad situations.
1153
+ */
1154
+ var
1155
+ _class = _getClass (_this),
1156
+ _propertyProfilesByPrivateNames = _class._propertyProfilesByPrivateNames
1157
+ ;
1158
+ for (var _propertyPrivateName in _propertyProfilesByPrivateNames)
1159
+ _result [_propertyProfilesByPrivateNames [_propertyPrivateName]._publicName] =
1160
+ _this [_propertyPrivateName]
1161
+ ;
1162
+ } else if (_isArray (_property)) {
1163
+ for (
1164
+ var _subPropertyNo = -1, _totalSubProperties = _property.length;
1165
+ ++_subPropertyNo < _totalSubProperties;
1166
+ ) {
1167
+ var _subProperty = _property [_subPropertyNo];
1168
+ _result [_subProperty] = _this [_getPropertyPrivateName (_this,_subProperty)];
1169
+ }
1170
+ } else {
1171
+ for (var _subProperty in _property)
1172
+ _result [_subProperty] = _this [_getPropertyPrivateName (_this,_subProperty)]
1173
+ ;
1174
+ }
1175
+ return _result;
1176
+ }
1177
+ /*?
1178
+ Instance Methods
1179
+ get
1180
+ Lets you query the value of one of an instance's state properties.
1181
+
1182
+ DIFFERENT USAGES
1183
+
1184
+ `Get the Value of a Single Property`
1185
+ ........................................................
1186
+ propertyValueANYTYPE = myInstance.get (propertyNameSTR);
1187
+ ........................................................
1188
+
1189
+ `Get Values for Multiples Properties, by Specifying a Property Names Array`
1190
+ ........................................................
1191
+ propertyValuesOBJ = myInstance.get (propertyNamesARRAY);
1192
+ ........................................................
1193
+
1194
+ `Get Values for Multiples Properties, by Specifying a Properties Object`
1195
+ ...................................................
1196
+ propertyValuesOBJ = myInstance.get (propertiesOBJ);
1197
+ ...................................................
1198
+
1199
+ `Get Values for All Properties`
1200
+ .........................................
1201
+ allPropertyValuesOBJ = myInstance.get ();
1202
+ .........................................
1203
+
1204
+ Get the Value of a Single Property
1205
+ In the most typical usage of the =get= instance method, a =propertyNameSTR= parameter can be specified in order to get the value of a single state property.
1206
+
1207
+ SYNTAX
1208
+ ........................................................
1209
+ propertyValueANYTYPE = myInstance.get (propertyNameSTR);
1210
+ ........................................................
1211
+
1212
+ EXAMPLE
1213
+ ......................................................
1214
+ var mySlider = Uize.Widget.Bar.Slider ({
1215
+ minValue:0,
1216
+ maxValue:100,
1217
+ value:57
1218
+ });
1219
+
1220
+ alert (mySlider.get ('value')); // alerts the text "57
1221
+ ......................................................
1222
+
1223
+ Get Values for Multiples Properties, by Specifying a Property Names Array
1224
+ When a =propertyNamesARRAY= parameter is specified in place of the =propertyNameSTR= parameter, the values for the instance state properties specified in the array will be populated into an object and returned.
1225
+
1226
+ SYNTAX
1227
+ ........................................................
1228
+ propertyValuesOBJ = myInstance.get (propertyNamesARRAY);
1229
+ ........................................................
1230
+
1231
+ EXAMPLE
1232
+ .....................................................................
1233
+ mySlider.set ('minValue',0);
1234
+ mySlider.set ('maxValue,100);
1235
+ mySlider.set ('value',57);
1236
+
1237
+ sliderValueAndRange = mySlider.get (['minValue','maxValue','value']);
1238
+ .....................................................................
1239
+
1240
+ After the above code has been executed, the =sliderValueAndRange= variable would have the value ={minValue:0,maxValue:100,value:57}=.
1241
+
1242
+ Get Values for Multiples Properties, by Specifying a Properties Object
1243
+ When a =propertyNamesARRAY= parameter is specified in place of the =propertyNameSTR= parameter, the values for the instance state properties specified in the array will be populated into an object and returned.
1244
+
1245
+ SYNTAX
1246
+ ...................................................
1247
+ propertyValuesOBJ = myInstance.get (propertiesOBJ);
1248
+ ...................................................
1249
+
1250
+ EXAMPLE
1251
+ .....................................................................
1252
+ mySlider.set ('minValue',0);
1253
+ mySlider.set ('maxValue,100);
1254
+ mySlider.set ('value',57);
1255
+
1256
+ sliderValueAndRange = mySlider.get ({minValue:0,maxValue:0,value:0});
1257
+ .....................................................................
1258
+
1259
+ After the above code has been executed, the =sliderValueAndRange= variable would have the value ={minValue:0,maxValue:100,value:57}=. The values of the properties in the properties object, as specified by the =propertiesOBJ= parameter, are immaterial - for whatever properties exist in the object, the values for the corresponding state properties of the instance will be returned.
1260
+
1261
+ Get Values for All Properties
1262
+ When no parameter is specified, the =get= instance method will return an object containing values for all the state properties of the instance.
1263
+
1264
+ SYNTAX
1265
+ .........................................
1266
+ allPropertyValuesOBJ = myInstance.get ();
1267
+ .........................................
1268
+
1269
+ For one thing, this variation makes it easy to create a new instance of a class with the same state as an existing instance.
1270
+
1271
+ EXAMPLE
1272
+ .........................................
1273
+ copyOfMyFade = Uize.Fade (myFade.get ());
1274
+ .........................................
1275
+
1276
+ In this example, an instance of the class =Uize.Fade= is being created by passing the constructor all the state property values obtained from the =myFade= instance using the =get= method. The new instance created will then have the same state as the =myFade= instance.
1277
+
1278
+ NOTES
1279
+ - see also the =set= instance method
1280
+ - see also the =Uize.Class.get= and =Uize.Class.set= static methods
1281
+
1282
+ Static Methods
1283
+ Uize.Class.get
1284
+ Lets you query the initial value for one of the class's state properties.
1285
+
1286
+ SYNTAX
1287
+ ........................................................
1288
+ propertyValueANYTYPE = Uize.Class.get (propertyNameSTR);
1289
+ ........................................................
1290
+
1291
+ VARIATIONS
1292
+ ........................................................
1293
+ propertyValuesOBJ = Uize.Class.get (propertyNamesARRAY);
1294
+ ........................................................
1295
+
1296
+ When a =propertyNamesARRAY= parameter is specified in place of the =propertyNameSTR= parameter, the values for the class state properties specified in the array will be populated into an object and returned. So, for example =Uize.Widget.get (['enabled','busy','built'])= would return a result like ={enabled:'inherit',busy:'inherit',built:true}=.
1297
+
1298
+ .........................................
1299
+ allPropertyValuesOBJ = Uize.Class.get ();
1300
+ .........................................
1301
+
1302
+ When no parameter is specified, the =Uize.Class.get= static method will return an object containing values for all the registered state properties of the class.
1303
+
1304
+ NOTES
1305
+ - see also the =Uize.Class.set= static method
1306
+ - see also the =get= and =set= instance methods
1307
+ */
1308
+ };
1309
+
1310
+ _class.registerProperties = function (_propertyProfiles) {
1311
+ var
1312
+ _this = this,
1313
+ _propertyProfilesByPrivateNames = _this._propertyProfilesByPrivateNames,
1314
+ _propertyProfilesByPublicNames = _this._propertyProfilesByPublicNames
1315
+ ;
1316
+ for (var _propertyPrivateName in _propertyProfiles) {
1317
+ var
1318
+ _propertyData = _propertyProfiles [_propertyPrivateName],
1319
+ _propertyDataIsObject = _isObject (_propertyData),
1320
+ _propertyPublicName =
1321
+ (_propertyDataIsObject ? _propertyData.name : _propertyData) || _propertyPrivateName,
1322
+ _propertyPrimaryPublicName = _propertyPublicName,
1323
+ _propertyProfile = _propertyProfilesByPrivateNames [_propertyPrivateName] = {_privateName:_propertyPrivateName}
1324
+ ;
1325
+ if (_propertyPublicName.indexOf ('|') > -1) {
1326
+ var _pseudonyms = _propertyPublicName.split ('|');
1327
+ _propertyPrimaryPublicName = _pseudonyms [0];
1328
+ _lookup (_pseudonyms,_propertyProfile,_propertyProfilesByPublicNames);
1329
+ } else {
1330
+ _propertyProfilesByPublicNames [_propertyPublicName] = _propertyProfile;
1331
+ }
1332
+ _propertyProfile._publicName = _propertyPrimaryPublicName;
1333
+ if (_propertyDataIsObject) {
1334
+ if (_propertyData.onChange) _propertyProfile._onChange = _propertyData.onChange;
1335
+ if (_propertyData.conformer) _propertyProfile._conformer = _propertyData.conformer;
1336
+ _this [_propertyPrivateName] = _propertyData.value;
1337
+ }
1338
+ }
1339
+ _this._instancePropertyDefaults = this.get ();
1340
+ /*?
1341
+ Static Methods
1342
+ Uize.Class.registerProperties
1343
+ Lets you register properties for the class.
1344
+
1345
+ SYNTAX
1346
+ .....................................................
1347
+ MyClass.registerProperties (propertiesDefinitionOBJ);
1348
+ .....................................................
1349
+
1350
+ The object specified in =propertiesDefinitionOBJ= parameter must conform to a specific structure. Each property of this object represents a property to be registered for the class, where the property name specifies the internal name to be used for the class property and the property's string value specifies the class property's public name. As an alternative to a string value, the property's value can be an object whose =name= property specifies the class property's public name and where an optional =onChange= property specifies a handler function that should be executed every time the value of the class property changes. This is all best illustrated with an example...
1351
+
1352
+ EXAMPLE
1353
+ ...........................................................................
1354
+ MyClass.registerProperties (
1355
+ {
1356
+ _propertylName:'property1Name',
1357
+ _property2Name:'property2Name',
1358
+ _property3Name:{
1359
+ name:'property3Name',
1360
+ onChange:function () {
1361
+ // code to be performed when the value of this property changes
1362
+ }
1363
+ }
1364
+ }
1365
+ );
1366
+ ...........................................................................
1367
+
1368
+ NOTES
1369
+ - calls to this method are cumulative, so it is possible to register properties in multiple separate batches
1370
+ */
1371
+ };
1372
+
1373
+ _class.set = _classPrototype.set = function (_properties) {
1374
+ /* NOTE:
1375
+ Yes, there are functions _getClass and _getPropertyPrivateName that could be used (and were at one point), but this code needs to be tuned for performance since set is a touch point in so many places.
1376
+ */
1377
+ var
1378
+ _arguments = arguments,
1379
+ _argumentsLength = _arguments.length
1380
+ ;
1381
+ if (_argumentsLength > 1)
1382
+ /* NOTE:
1383
+ - support for...
1384
+ set (propertyNameSTR,propertyValueANYTYPE)
1385
+
1386
+ or...
1387
+
1388
+ set (
1389
+ property1NameSTR,property1ValueANYTYPE,
1390
+ property2NameSTR,property2ValueANYTYPE,
1391
+ ...
1392
+ propertyNNameSTR,propertyNValueANYTYPE
1393
+ )
1394
+
1395
+ or...
1396
+
1397
+ set (propertyNamesARRAY,propertyValueANYTYPE)
1398
+ */
1399
+ _properties = _argumentsLength > 2 || typeof _properties == _typeString
1400
+ ? _pairUp.apply (0,_arguments)
1401
+ : _lookup (_properties,_arguments [1])
1402
+ ;
1403
+ var
1404
+ _this = this,
1405
+ _thisIsInstance = _isInstance (_this),
1406
+ _class = _thisIsInstance ? _this.Class : _this,
1407
+ _propertyProfilesByPublicNames = _class._propertyProfilesByPublicNames,
1408
+ _propertyProfilesByPrivateNames = _class._propertyProfilesByPrivateNames,
1409
+ _propertyProfile,
1410
+ _onChangeHandlers,
1411
+ _onChangeHandlerAddedFlagName,
1412
+ _onChangeHandler,
1413
+ _hasChangedHandlers = _thisIsInstance && _this._hasChangedHandlers,
1414
+ _hasChangedDotStarHandlers = _hasChangedHandlers && _hasChangedHandlers ['*'],
1415
+ _propertiesForChangedDotStar,
1416
+ _changedEventsToFire,
1417
+ _propertyPrivateName,
1418
+ _propertyPublicName,
1419
+ _propertiesToRegister,
1420
+ _propertyValue,
1421
+ _propertiesBeingSet
1422
+ ;
1423
+ for (var _propertyPublicOrPrivateName in _properties) {
1424
+ _propertyValue = _properties [_propertyPublicOrPrivateName];
1425
+ if (
1426
+ _propertyProfile =
1427
+ _propertyProfilesByPublicNames [_propertyPublicOrPrivateName] ||
1428
+ _propertyProfilesByPrivateNames [_propertyPublicOrPrivateName]
1429
+ ) {
1430
+ _propertyPrivateName = _propertyProfile._privateName;
1431
+ _propertyPublicName = _propertyProfile._publicName;
1432
+ } else {
1433
+ (_propertiesToRegister || (_propertiesToRegister = {})) [
1434
+ _propertyPrivateName = _propertyPublicName = _propertyPublicOrPrivateName
1435
+ ] =
1436
+ _propertyProfile = _thisIsInstance ? {} : {value:_propertyValue}
1437
+ ;
1438
+ }
1439
+ if (_thisIsInstance)
1440
+ (_propertiesBeingSet || (_propertiesBeingSet = {})) [_propertyPublicName] =
1441
+ _propertyProfile._conformer
1442
+ ? (
1443
+ /*** if there's a registered conformer, execute it and adjust the value ***/
1444
+ _propertyValue = _propertyProfile._conformer.call (
1445
+ _this,_propertyValue,_this [_propertyPrivateName]
1446
+ )
1447
+ )
1448
+ : _propertyValue
1449
+ ;
1450
+
1451
+ if (_propertyValue !== _this [_propertyPrivateName]) {
1452
+ if (_thisIsInstance) {
1453
+ /*** build up list of events to fire for 'Changed.' event handlers ***/
1454
+ _hasChangedDotStarHandlers && (
1455
+ (_propertiesForChangedDotStar || (_propertiesForChangedDotStar = {}))
1456
+ [_propertyPublicName] = _propertyValue
1457
+ );
1458
+ _hasChangedHandlers && _hasChangedHandlers [_propertyPublicName] &&
1459
+ (_changedEventsToFire || (_changedEventsToFire = [])).push (_propertyPublicName)
1460
+ ;
1461
+ /*** build up list of onChange handlers to execute ***/
1462
+ function _processOnChangeHandler (_onChangeHandler) {
1463
+ if (_isFunction (_onChangeHandler)) {
1464
+ if (!_onChangeHandlers) {
1465
+ _onChangeHandlers = [];
1466
+ _onChangeHandlerAddedFlagName = _this.instanceId + '_handlerAlreadyAdded';
1467
+ }
1468
+ if (!_onChangeHandler [_onChangeHandlerAddedFlagName]) {
1469
+ _onChangeHandler [_onChangeHandlerAddedFlagName] = 1;
1470
+ _onChangeHandlers.push (_onChangeHandler);
1471
+ }
1472
+ } else if (typeof _onChangeHandler == _typeString) {
1473
+ _processOnChangeHandler (_this [_onChangeHandler]);
1474
+ } else if (_isArray (_onChangeHandler)) {
1475
+ _forEach (_onChangeHandler,_processOnChangeHandler);
1476
+ }
1477
+ }
1478
+ _propertyProfile._onChange && _processOnChangeHandler (_propertyProfile._onChange);
1479
+ }
1480
+ _this [_propertyPrivateName] = _propertyValue;
1481
+ }
1482
+ }
1483
+ _propertiesToRegister && _class.registerProperties (_propertiesToRegister);
1484
+ if (_thisIsInstance) {
1485
+ if (_onChangeHandlers) {
1486
+ for (
1487
+ var _handlerNo = -1, _onChangeHandlersLength = _onChangeHandlers.length;
1488
+ ++_handlerNo < _onChangeHandlersLength;
1489
+ ) {
1490
+ delete (_onChangeHandler = _onChangeHandlers [_handlerNo]) [_onChangeHandlerAddedFlagName];
1491
+ _onChangeHandler.call (_this,_propertiesBeingSet);
1492
+ }
1493
+ }
1494
+ _propertiesForChangedDotStar && _this.fire ({name:'Changed.*',properties:_propertiesForChangedDotStar});
1495
+ if (_changedEventsToFire) {
1496
+ for (
1497
+ var _changedEventNo = -1, _changedEventsToFireLength = _changedEventsToFire.length;
1498
+ ++_changedEventNo < _changedEventsToFireLength;
1499
+ )
1500
+ _this.fire ('Changed.' + _changedEventsToFire [_changedEventNo])
1501
+ ;
1502
+ /*?
1503
+ Instance Events
1504
+ Changed.*
1505
+ The =Changed.*= instance event is a wildcard event that is fired whenever one or more state properties change value as a result of a call to the =set= instance method.
1506
+
1507
+ This event will only be fired once for all state properties that have changed value during a call to the =set= method. The event object for this event will contain a =properties= property, which is an object indicating which state properties have changed value, being a mapping between the public names of state properties that have changed and their new values.
1508
+
1509
+ NOTES
1510
+ - compare to the related =Changed.[propertyName]= instance event
1511
+ - wiring a handler for the =Changed.*= event may have a slight performance impact, since this event will be fired any time that any state property changes value
1512
+
1513
+ Changed.[propertyName]
1514
+ The =Uize.Class= base class implements a generalized mechanism for firing events when the values of state properties are changed.
1515
+
1516
+ This means that for any state property that is registered through the =Uize.Class.registerProperties= static method, a handler can be registered for a change in the value of that property without having to write any additional code to fire an event.
1517
+
1518
+ Event Naming
1519
+ The name of a changed event that fires is of the form =Changed.[propertyName]=, where =propertyName= is the primary public name of the state property. For example, if you registered a state property named =value=, then a =Changed.value= event would fire each time this property is changed.
1520
+
1521
+ Property Aliases
1522
+ If a state property has aliases, handlers can be registered for the property's changed event using any of the aliases. However, the name of the event when it fires will always be derived from the primary public name (ie. first in the alias list) of the property. So, for example, if a state property was registered with the public names =color= and =hexRgb=, both =Changed.color= and =Changed.hexRgb= would be treated as equivalent.
1523
+
1524
+ EXAMPLE
1525
+ ..........................................................
1526
+ function handleColorChange () {
1527
+ // do stuff
1528
+ }
1529
+ myColorWidget.wire ('Changed.color',handleColorChange);
1530
+ myColorWidget.unwire ('Changed.hexRgb',handleColorChange);
1531
+ ..........................................................
1532
+
1533
+ In this example, the =handleColorChange= function would not be executed when the value of the =color= state property changes, because =Changed.color= and =Changed.hexRgb= are treated as equivalent and therefore the =unwire= statement effectively removes the handler registered in the previous statement.
1534
+
1535
+ Must Use the set Method
1536
+ The =Changed.[propertyName]= event will only fire for a particular state property if the value for that property is set using the =set= method, since it is within the =set= method that change detection occurs and the event is fired. If you simply assign a value by directly accessing the private name of the property, then the event will not fire.
1537
+
1538
+ Only On Change, Not Every Set
1539
+ The =Changed.[propertyName]= event only fires for a particular state property when the value for that property is *changed* by using the =set= method. So, if the =set= method is called but the value that is specified is already the value of the property, then there will be no change and no event will be fired.
1540
+
1541
+ Additionally, if a =conformer= is registered for the property and the action of the conformer results in the property value not being changed, then no event will be fired - even if the value specified in the =set= call is different to the current value of the property. This can be the case if the value is at an edge of its valid range, an attempt is made to set the value outside of its valid range, and the conformer has the action of constraining the value so that it remains at the same edge of its valid range.
1542
+
1543
+ NOTES
1544
+ - compare to the related =Changed.*= instance event
1545
+ */
1546
+ }
1547
+ } else {
1548
+ _class._instancePropertyDefaults = this.get ();
1549
+ }
1550
+ /*?
1551
+ Instance Methods
1552
+ set
1553
+ Lets you set values for one or more of an instance's state properties.
1554
+
1555
+ DIFFERENT USAGES
1556
+
1557
+ `Set Values for One or More Properties with a Names/Values Object`
1558
+ ........................................
1559
+ myInstance.set (propertyNamesValuesOBJ);
1560
+ ........................................
1561
+
1562
+ `Set the Value for a Property with Name and Value Arguments`
1563
+ ......................................................
1564
+ myInstance.set (propertyNameSTR,propertyValueANYTYPE);
1565
+ ......................................................
1566
+
1567
+ `Set Values for Multiple Properties with Multiple Name and Value Arguments`
1568
+ .........................................
1569
+ myInstance.set (
1570
+ property1NameSTR,property1ValueANYTYPE,
1571
+ property2NameSTR,property2ValueANYTYPE,
1572
+ ... ... ...
1573
+ propertyNNameSTR,propertyNValueANYTYPE
1574
+ );
1575
+ .........................................
1576
+
1577
+ `Set the Same Value for Multiple Properties`
1578
+ .........................................................
1579
+ myInstance.set (propertyNamesARRAY,propertyValueANYTYPE);
1580
+ .........................................................
1581
+
1582
+ Set Values for One or More Properties with a Names/Values Object
1583
+ In the standard usage, a single =propertyNamesValuesOBJ= parameter can be passed to the =set= method in order to set values for one or more properties.
1584
+
1585
+ SYNTAX
1586
+ ........................................
1587
+ myInstance.set (propertyNamesValuesOBJ);
1588
+ ........................................
1589
+
1590
+ Each key of the =propertyNamesValuesOBJ= object represents the name of a state property whose value should be set, and each corresponding value represents the value that a property should be set to.
1591
+
1592
+ EXAMPLE 1
1593
+ ...............................
1594
+ myWidget.set ({enabled:false});
1595
+ ...............................
1596
+
1597
+ In the above example, the =set= method is being used to set the value of just one property - the =enabled= property of a widget instance.
1598
+
1599
+ EXAMPLE 2
1600
+ ................
1601
+ mySlider.set ({
1602
+ maxValue:100,
1603
+ minValue:0,
1604
+ value:23
1605
+ });
1606
+ ................
1607
+
1608
+ In the above example, the =set= method is being used to set values for multiple properties - the =maxValue=, =minValue=, and =value= properties of a slider widget instance.
1609
+
1610
+ Set the Value for a Property with Name and Value Arguments
1611
+ The value of a state property can be set by providing two parameters to the =set= method: a string parameter specifying the name of a property, and a value parameter that can be of any type.
1612
+
1613
+ SYNTAX
1614
+ ......................................................
1615
+ myInstance.set (propertyNameSTR,propertyValueANYTYPE);
1616
+ ......................................................
1617
+
1618
+ This variation of the =set= method is particularly useful in cases where you wish to use a variable or an expression to determine the state property whose value should be set. Consider the following example...
1619
+
1620
+ EXAMPLE
1621
+ ..............................................................
1622
+ MyClass.prototype.increment = function (propertyName,amount) {
1623
+ this.set (propertyName,this.get (propertyName) + amount);
1624
+ }
1625
+ ..............................................................
1626
+
1627
+ In the above example, a generic incrementer instance method is being implemented. It receives a =propertyName= parameter that specifies the state property to increment, and it passes the value of this parameter as the first parameter in the call to the =set= method.
1628
+
1629
+ Slightly Less Performant
1630
+ This variation of the =set= method is very slightly less performant than the variation that accepts a single =propertyNamesValuesOBJ= parameter.
1631
+
1632
+ This variation is offered primarily as a convenience for when the names of properties to be set need to be supplied through variables or expressions. While there is not much cost to using this variation when not necessary, it is advised to generally use the form that accepts a =propertyNamesValuesOBJ= parameter whenever possible (see `Set Values for One or More Properties with a Names/Values Object`).
1633
+
1634
+ Set Values for Multiple Properties with Multiple Name and Value Arguments
1635
+ The values for an arbitrary number of state properties can be set by providing the names and values of the properties using an arbitrary number of name-value pair arguments, where even numbered arguments are property names and odd numbered arguments are property values.
1636
+
1637
+ SYNTAX
1638
+ .........................................
1639
+ myInstance.set (
1640
+ property1NameSTR,property1ValueANYTYPE,
1641
+ property2NameSTR,property2ValueANYTYPE,
1642
+ ... ... ...
1643
+ propertyNNameSTR,propertyNValueANYTYPE
1644
+ );
1645
+ .........................................
1646
+
1647
+ This variation of the =set= method is an extension of the variation that lets you `set the value for a property with name and value arguments`, and has the same benefits and performance considerations.
1648
+
1649
+ Set the Same Value for Multiple Properties
1650
+ The same value can be set for multiple state properties by specifying the names of the properties that should all be set to the same value in a =propertyNamesARRAY= parameter, and by specifying the value they should all be set to in a =propertyValueANYTYPE= parameter.
1651
+
1652
+ SYNTAX
1653
+ .........................................................
1654
+ myInstance.set (propertyNamesARRAY,propertyValueANYTYPE);
1655
+ .........................................................
1656
+
1657
+ EXAMPLE
1658
+ ..............................................................
1659
+ myWidget.set (['initialized','ready','enabled','busy'],false);
1660
+ ..............................................................
1661
+
1662
+ In the above example, the properties =initialized=, =ready=, =enabled=, and =busy= of a widget instance are all being set to =false=.
1663
+
1664
+ This variation of the =set= method can be useful in cases where you wish to set a good number of properties to the same value and where it would be more concise to use this form, or in cases where you are receiving an array of properties that should be set to some desired value. This variation can also be convenient when the value that you wish to set multiple properties to is the result of an expression and where you would otherwise need to create a local variable in order to avoid recalculating the expression for each property.
1665
+
1666
+ INSTEAD OF...
1667
+ .......................................................................................
1668
+ var initValue = env.config.hasOwnProperty ('initValue') ? env.config.initValue : false;
1669
+ myInstance.set ({
1670
+ foo:initValue,
1671
+ bar:initValue,
1672
+ baz:initValue
1673
+ });
1674
+ .......................................................................................
1675
+
1676
+ USE...
1677
+ .........................................................................
1678
+ myInstance.set (
1679
+ ['foo','bar','baz'],
1680
+ env.config.hasOwnProperty ('initValue') ? env.config.initValue : false
1681
+ );
1682
+ .........................................................................
1683
+
1684
+ NOTES
1685
+ - see the companion =get= instance method
1686
+ - see also the =Uize.Class.get= and =Uize.Class.set= static methods
1687
+
1688
+ Static Methods
1689
+ Uize.Class.set
1690
+ Lets you set initial values for one or more of a class's state properties.
1691
+
1692
+ DIFFERENT USAGES
1693
+
1694
+ `Set Initial Values for One or More Properties with a Names/Values Object`
1695
+ .....................................
1696
+ MyClass.set (propertyNamesValuesOBJ);
1697
+ .....................................
1698
+
1699
+ `Set the Initial Value for a Property with Name and Value Arguments`
1700
+ ...................................................
1701
+ MyClass.set (propertyNameSTR,propertyValueANYTYPE);
1702
+ ...................................................
1703
+
1704
+ `Set Initial Values for Multiple Properties with Multiple Name and Value Arguments`
1705
+ .........................................
1706
+ MyClass.set (
1707
+ property1NameSTR,property1ValueANYTYPE,
1708
+ property2NameSTR,property2ValueANYTYPE,
1709
+ ... ... ...
1710
+ propertyNNameSTR,propertyNValueANYTYPE
1711
+ );
1712
+ .........................................
1713
+
1714
+ `Set the Same Initial Value for Multiple Properties`
1715
+ ......................................................
1716
+ MyClass.set (propertyNamesARRAY,propertyValueANYTYPE);
1717
+ ......................................................
1718
+
1719
+ Set Initial Values for One or More Properties with a Names/Values Object
1720
+ In the standard usage, a single =propertyNamesValuesOBJ= parameter can be passed to the =Uize.Class.set= method in order to set initial values for one or more properties.
1721
+
1722
+ SYNTAX
1723
+ .....................................
1724
+ MyClass.set (propertyNamesValuesOBJ);
1725
+ .....................................
1726
+
1727
+ Each key of the =propertyNamesValuesOBJ= object represents the name of a state property whose initial value should be set, and each corresponding value represents the initial value that should be set for a property.
1728
+
1729
+ EXAMPLE 1
1730
+ ....................................
1731
+ MyWidgetClass.set ({enabled:false});
1732
+ ....................................
1733
+
1734
+ In the above example, the =Uize.Class.set= method is being used to set the initial value for just one property - the =enabled= property of a widget class.
1735
+
1736
+ EXAMPLE 2
1737
+ .............................
1738
+ Uize.Widget.Bar.Slider.set ({
1739
+ maxValue:100,
1740
+ minValue:0,
1741
+ value:0
1742
+ });
1743
+ .............................
1744
+
1745
+ In the above example, the =Uize.Class.set= method is being used to set initial values for multiple properties - the =maxValue=, =minValue=, and =value= properties of the =Uize.Widget.Bar.Slider= widget class.
1746
+
1747
+ Set the Initial Value for a Property with Name and Value Arguments
1748
+ The initial value for a state property can be set by providing two parameters to the =Uize.Class.set= method: a string parameter specifying the name of a property, and a value parameter that can be of any type.
1749
+
1750
+ SYNTAX
1751
+ ...................................................
1752
+ MyClass.set (propertyNameSTR,propertyValueANYTYPE);
1753
+ ...................................................
1754
+
1755
+ This variation of the =Uize.Class.set= method is particularly useful in cases where you wish to use a variable or an expression to determine the state property whose initial value should be set. Consider the following example...
1756
+
1757
+ EXAMPLE
1758
+ ............................................................
1759
+ MyClass.increment = function (propertyName,amount) {
1760
+ this.set (propertyName,this.get (propertyName) + amount);
1761
+ }
1762
+ ............................................................
1763
+
1764
+ In the above example, a generic incrementer static method is being implemented. It receives a =propertyName= parameter that specifies the state property whose initial value should be incremented, and it passes the value of this parameter as the first parameter in the call to the =Uize.Class.set= method.
1765
+
1766
+ Slightly Less Performant
1767
+ This variation of the =Uize.Class.set= method is very slightly less performant than the variation that accepts a single =propertyNamesValuesOBJ= parameter.
1768
+
1769
+ This variation is offered primarily as a convenience for when the names of properties whose initial values are to be set need to be supplied through variables or expressions. While there is not much cost to using this variation when not necessary, it is advised to generally use the form that accepts a =propertyNamesValuesOBJ= parameter whenever possible (see `Set Initial Values for One or More Properties with a Names/Values Object`).
1770
+
1771
+ Set Initial Values for Multiple Properties with Multiple Name and Value Arguments
1772
+ The initial values for an arbitrary number of state properties can be set by providing the names and values of the properties using an arbitrary number of name-value pair arguments, where even numbered arguments are property names and odd numbered arguments are property values.
1773
+
1774
+ SYNTAX
1775
+ .........................................
1776
+ MyClass.set (
1777
+ property1NameSTR,property1ValueANYTYPE,
1778
+ property2NameSTR,property2ValueANYTYPE,
1779
+ ... ... ...
1780
+ propertyNNameSTR,propertyNValueANYTYPE
1781
+ );
1782
+ .........................................
1783
+
1784
+ This variation of the =Uize.Class.set= method is an extension of the variation that lets you `set the initial value for a property with name and value arguments`, and has the same benefits and performance considerations.
1785
+
1786
+ Set the Same Initial Value for Multiple Properties
1787
+ The same initial value can be set for multiple state properties by specifying the names of the properties whose initial values should all be set to the same value in a =propertyNamesARRAY= parameter, and by specifying the initial value that should be set for them all in a =propertyValueANYTYPE= parameter.
1788
+
1789
+ SYNTAX
1790
+ ......................................................
1791
+ MyClass.set (propertyNamesARRAY,propertyValueANYTYPE);
1792
+ ......................................................
1793
+
1794
+ EXAMPLE
1795
+ ...................................................................
1796
+ MyWidgetClass.set (['initialized','ready','enabled','busy'],false);
1797
+ ...................................................................
1798
+
1799
+ In the above example, the initial value for the properties =initialized=, =ready=, =enabled=, and =busy= of a widget class is being set to =false=.
1800
+
1801
+ This variation of the =Uize.Class.set= method can be useful in cases where you wish to set the initial value for a good number of properties to the same value and where it would be more concise to use this form, or in cases where you are receiving an array of properties whose initial values should all be set to some desired value. This variation can also be convenient when the initial value that you wish to set for multiple properties is the result of an expression and where you would otherwise need to create a local variable in order to avoid recalculating the expression for each property.
1802
+
1803
+ INSTEAD OF...
1804
+ .......................................................................................
1805
+ var initValue = env.config.hasOwnProperty ('initValue') ? env.config.initValue : false;
1806
+ MyClass.set ({
1807
+ foo:initValue,
1808
+ bar:initValue,
1809
+ baz:initValue
1810
+ });
1811
+ .......................................................................................
1812
+
1813
+ USE...
1814
+ .........................................................................
1815
+ MyClass.set (
1816
+ ['foo','bar','baz'],
1817
+ env.config.hasOwnProperty ('initValue') ? env.config.initValue : false
1818
+ );
1819
+ .........................................................................
1820
+
1821
+ NOTES
1822
+ - see the companion =Uize.Class.get= static method
1823
+ - see also the =get= and =set= instance methods
1824
+
1825
+ */
1826
+ };
1827
+
1828
+ _class.toggle = _classPrototype.toggle = function (_propertyName) {
1829
+ var _value = !this.get (_propertyName);
1830
+ this.set (_propertyName,_value);
1831
+ return _value;
1832
+ /*?
1833
+ Instance Methods
1834
+ toggle
1835
+ Toggles the value of the specified boolean instance state property.
1836
+
1837
+ SYNTAX
1838
+ .......................................................
1839
+ toggledValueBOOL = myInstance.toggle (propertyNameSTR);
1840
+ .......................................................
1841
+
1842
+ The =toggle= instance method is provided purely as a convenience. The following two statements are equivalent...
1843
+
1844
+ .............................................................
1845
+ myInstance.toggle ('myProperty');
1846
+ myInstance.set ({myProperty:!myInstance.get ('myProperty')});
1847
+ .............................................................
1848
+
1849
+ As you can see, using the =toggle= method produces more concise code.
1850
+
1851
+ Static Methods
1852
+ Uize.Class.toggle
1853
+ Toggles the value of the specified boolean static state property.
1854
+
1855
+ SYNTAX
1856
+ .......................................................
1857
+ toggledValueBOOL = Uize.Class.toggle (propertyNameSTR);
1858
+ .......................................................
1859
+
1860
+ The =Uize.Class.toggle= static method is provided purely as a convenience. The following two statements are equivalent...
1861
+
1862
+ .............................................................
1863
+ Uize.Class.toggle ('myProperty');
1864
+ Uize.Class.set ({myProperty:!Uize.Class.get ('myProperty')});
1865
+ .............................................................
1866
+
1867
+ As you can see, using the =Uize.Class.toggle= method produces more concise code.
1868
+ */
1869
+ };
1870
+
1871
+ /*** Public Instance Methods ***/
1872
+ _classPrototype.kill = function () {
1873
+ var _instanceId = this.instanceId;
1874
+ _globalEval ('if(typeof ' + _instanceId + '!=\'undefined\')' + _instanceId + '=null');
1875
+ /*?
1876
+ Instance Methods
1877
+ kill
1878
+ Nulls out the global variable (or property of the =window= object) of the name =instanceId=.
1879
+
1880
+ This method may be useful if global (or window object level) references are made to instances of a class, usually for the purpose of group management, or the implementation of certain kinds of state exclusivity amongst instances of a class. This method is also intended to be overridden by subclasses where additional destructor style code may be desired.
1881
+ */
1882
+ };
1883
+
1884
+ /*** Inheritance Mechanism ***/
1885
+ function _createSubclass (_class,_alphastructor,_omegastructor) {
1886
+ function _toString () {
1887
+ var
1888
+ _propertiesLines = [],
1889
+ _Uize_toString = _Uize.toString
1890
+ ;
1891
+ _forEach (
1892
+ this.get (),
1893
+ function (_propertyValue,_propertyName) {
1894
+ _propertiesLines.push (
1895
+ _propertyName + ' : ' +
1896
+ (
1897
+ _propertyValue && (_isInstance (_propertyValue) || _isFunction (_propertyValue))
1898
+ ? _Uize_toString.call (_propertyValue)
1899
+ : _propertyValue
1900
+ )
1901
+ );
1902
+ }
1903
+ );
1904
+ return _Uize_toString.call (this) + '\n\n' + _propertiesLines.sort ().join ('\n');
1905
+ }
1906
+
1907
+ function _valueOf () {
1908
+ return this [_getPropertyPrivateName (this,'value')];
1909
+ /*?
1910
+ Instance Methods
1911
+ toString Intrinsic Method
1912
+ Returns a string, providing summary info for the instance on which the method is called.
1913
+
1914
+ SYNTAX
1915
+ ............................................
1916
+ instanceSummarySTR = myInstance.toString ();
1917
+ ............................................
1918
+
1919
+ The string returned by this method provides a summary that includes the instance's class name and the state of its state properties. Among other things, this method provides a convenient and lightweight way to gather information about instances of =Uize.Class= subclasses during debugging and troubleshooting. The =toString Intrinsic Method= is invoked automatically in certain contexts in order to convert an object to a string form, such as when alerting an object using the =alert= global function.
1920
+
1921
+ EXAMPLE
1922
+ .............................
1923
+ alert (page.children.slider);
1924
+ .............................
1925
+
1926
+ In the above example, if the =page= widget has a =slider= child widget that is an instance of the class =Uize.Widget.Bar.Slider=, then the output of the =alert= statement could look something like...
1927
+
1928
+ EXAMPLE OUTPUT
1929
+ ........................................
1930
+ [object Uize.Widget.Bar.Slider]
1931
+
1932
+ built : true
1933
+ busy : inherit
1934
+ busyInherited : false
1935
+ confirm : undefined
1936
+ container : undefined
1937
+ decimalPlacesToDisplay : undefined
1938
+ enabled : inherit
1939
+ enabledInherited : true
1940
+ html : undefined
1941
+ idPrefix : page_slider
1942
+ idPrefixConstruction : concatenated
1943
+ inDrag : false
1944
+ increments : 1
1945
+ inform : undefined
1946
+ insertionMode: undefined
1947
+ localized : undefined
1948
+ maxValidValue : undefined
1949
+ maxValue : 200
1950
+ minValidValue : undefined
1951
+ minValue : 0
1952
+ name : slider
1953
+ nodeMap : undefined
1954
+ orientation : vertical
1955
+ parent : [class UizeSite.Page.Example]
1956
+ restTime : 250
1957
+ scaleFunc : [object Function]
1958
+ value : 0
1959
+ valueFunc : [object Function]
1960
+ wired : true
1961
+ ........................................
1962
+
1963
+ In certain contexts, providing a reference to a =Uize.Class= subclass instance as a parameter to some method will result in the =valueOf Intrinsic Method= of that instance being invoked in order to coerce it to a simple value. If it is your desire to have the instance summary be used rather than the instance's value, then you should explicitly call the =toString Intrinsic Method=, as follows...
1964
+
1965
+ EXAMPLE
1966
+ ........................................................................................
1967
+ Uize.Node.setInnerHtml ('sliderWidgetSummaryForDebug',page.children.slider.toString ());
1968
+ Uize.Node.setInnerHtml ('sliderWidgetCurrentValue',page.children.slider);
1969
+ ........................................................................................
1970
+
1971
+ In this example, the =sliderWidgetSummaryForDebug= node will contain the summary info for the instance, while the =sliderWidgetCurrentValue= node will just show the slider widget's current value.
1972
+
1973
+ NOTES
1974
+ - see also the =Uize.toString= static intrinsic method
1975
+
1976
+ valueOf Intrinsic Method
1977
+ Returns the value of the instance's =value= state property.
1978
+
1979
+ SYNTAX
1980
+ .............................................
1981
+ instanceValueANYTYPE = myInstance.valueOf ();
1982
+ .............................................
1983
+
1984
+ The =valueOf Intrinsic Method= is invoked automatically in certain contexts in order to convert an object to a value, such as when using an object reference in an expression.
1985
+
1986
+ EXAMPLE
1987
+ ..........................................................................
1988
+ var markedUpPrice = price * (1 + page.children.markupPercentSlider / 100);
1989
+ ..........................................................................
1990
+
1991
+ In the above example, the page widget has a slider child widget that is an instance of the class =Uize.Widget.Bar.Slider= and that lets the user choose a markup percentage between =0= and =100=. In the above expression, the slider widget is being divided by 100. Rather than giving you a hundred *really* tiny slider widgets (not all that useful), JavaScript automatically invokes the =valueOf Intrinsic Method=. The implementation of this instance method in the =Uize.Class= base class results in the slider's current value being returned so that it can then be used in the expression.
1992
+
1993
+ The following three statements are equivalent...
1994
+
1995
+ ....................................................................................
1996
+ markedUpPrice = price * (1 + page.children.markupPercentSlider.get ('value') / 100);
1997
+ markedUpPrice = price * (1 + page.children.markupPercentSlider.valueOf () / 100);
1998
+ markedUpPrice = price * (1 + page.children.markupPercentSlider / 100);
1999
+ ....................................................................................
2000
+
2001
+ In certain contexts, providing a reference to a =Uize.Class= subclass instance as a parameter to some method will result in the =toString Intrinsic Method= of that instance being invoked in order to resolve it to a string value. If it is your desire to have the value used rather than the instance summary, then you should explicitly call the =valueOf Intrinsic Method=, as follows...
2002
+
2003
+ EXAMPLE
2004
+ .....................................................
2005
+ alert (page.children.markupPercentSlider.valueOf ());
2006
+ .....................................................
2007
+
2008
+ In this example, the current value of the =markupPercentSlider= widget will be displayed in the alert dialog, rather than the instance summary. You can also use shortcuts, as follows...
2009
+
2010
+ COERCE TO NUMBER
2011
+ ...........................................
2012
+ alert (+page.children.markupPercentSlider);
2013
+ ...........................................
2014
+
2015
+ COERCE TO STRING
2016
+ ................................................
2017
+ alert (page.children.titleTextInputWidget + '');
2018
+ ................................................
2019
+
2020
+ Both of the above examples will cause JavaScript to invoke the =valueOf Intrinsic Method= rather than the =toString Intrinsic Method=, but the first will coerce the value to a number type, while the second will coerce the value to a string type.
2021
+
2022
+ NOTES
2023
+ - compare to the =toString Intrinsic Method=, and the =Uize.toString= static intrinsic method
2024
+ - see also the =Uize.Class.valueOf= static intrinsic method
2025
+ - if the instance's class does not register a =value= state property, then this method will return the value of the instance's =value= property, and if the instance has no =value= property, then this method will simply return =undefined=
2026
+
2027
+ Static Methods
2028
+ Uize.Class.valueOf
2029
+ Returns the value of the class' =value= state property.
2030
+
2031
+ SYNTAX
2032
+ .......................................
2033
+ classValueANYTYPE = MyClass.valueOf ();
2034
+ .......................................
2035
+
2036
+ The =Uize.Class.valueOf= static intrinsic method is invoked automatically in certain contexts in order to convert a class to a value, such as when using a class reference in an expression (eg. =Uize.Widget.Bar.Slider + 0=). This static method is implemented primarily to provide parity with the =valueOf Intrinsic Method=. Its behavior is largely equivalent to that of the instance method, excepting that it applies to the static value of the =value= state property.
2037
+
2038
+ NOTES
2039
+ - compare to the =toString Intrinsic Method=, and the =Uize.toString= static intrinsic method
2040
+ - see also the =valueOf Intrinsic Method=
2041
+ - if the class does not register a =value= state property, then this method will return the value of the class' =value= property, and if the class has no =value= property, then this method will simply return =undefined=
2042
+ */
2043
+ }
2044
+
2045
+ var
2046
+ _classPrototype = _class.prototype,
2047
+ _subclass = _noNew (
2048
+ function () {
2049
+ for (
2050
+ var _alphastructorNo = -1, _alphastructorsLength = _alphastructors.length;
2051
+ ++_alphastructorNo < _alphastructorsLength;
2052
+ )
2053
+ _alphastructors [_alphastructorNo].apply (this,arguments)
2054
+ ;
2055
+ for (
2056
+ var _omegastructorNo = -1, _omegastructorsLength = _omegastructors.length;
2057
+ ++_omegastructorNo < _omegastructorsLength;
2058
+ )
2059
+ _omegastructors [_omegastructorNo].apply (this,arguments)
2060
+ ;
2061
+ }
2062
+ ),
2063
+ _subclassPrototype = _subclass.prototype
2064
+ ;
2065
+
2066
+ /*** Inherit static properties (excluding prototype) and methods from base class ***/
2067
+ var
2068
+ _propertyValue,
2069
+ _nonInheritableStatics = _class.nonInheritableStatics || _sacredEmptyObject
2070
+ ;
2071
+ for (var _property in _class)
2072
+ if (
2073
+ !_nonInheritableStatics [_property] &&
2074
+ (_propertyValue = _class [_property]) != _classPrototype &&
2075
+ !(
2076
+ _isFunction (_propertyValue) &&
2077
+ _propertyValue.moduleName &&
2078
+ /[A-Z]/.test (_property.charAt (0))
2079
+ )
2080
+ )
2081
+ _subclass [_property] = _clone (_propertyValue)
2082
+ ;
2083
+
2084
+ /*** Prepare instance properties and methods ***/
2085
+ /*** Inherit instance properties and methods from base class (from prototype) ***/
2086
+ _copyInto (_subclassPrototype,_classPrototype);
2087
+
2088
+ /*** Make sure toString and valueOf are copied ***/
2089
+ /* NOTE: in IE, toString and valueOf aren't enumerable properties of the prototype object */
2090
+ _subclassPrototype.toString = _toString;
2091
+ _subclassPrototype.valueOf = _valueOf;
2092
+
2093
+ /*** Non-inherited Public Instance Properties ***/
2094
+ _subclassPrototype.Class = _subclass;
2095
+ /*?
2096
+ Instance Properties
2097
+ Class
2098
+ A reference to the class's constructor.
2099
+
2100
+ You can use this to interrogate an object instance to see if it is of a certain class, as illustrated in the following example...
2101
+
2102
+ EXAMPLE
2103
+ .......................................................
2104
+ if (myInstance.Class == Uize.Widget.Bar.Slider) {
2105
+ // do something for sliders
2106
+ } else if (myInstance.Class == Uize.Widget.Tree.Menu) {
2107
+ // do something for tree menus
2108
+ } else if (myInstance.Class == Uize.Widget.ImageWipe) {
2109
+ // do something for wipes
2110
+ }
2111
+ .......................................................
2112
+
2113
+ The above example is admittedly a little abstract. It is hard to imagine the exact scenario that may come up where some code is handed object instances where their class will not be known. But, when such a case comes up, the =Class= property has got your back.
2114
+ */
2115
+
2116
+ /*** Non-inherited Public Static Properties ***/
2117
+ _subclass.nonInheritableStatics = {_singletons:1,nonInheritableStatics:1,toString:0,valueOf:0};
2118
+ /*?
2119
+ Static Properties
2120
+ Uize.Class.nonInheritableStatics
2121
+ A lookup object, automatically created for a class, in which you can register the static features (methods or properties) of the class that should *not* be inherited when that class is subclassed.
2122
+
2123
+ Each property of the =Uize.Class.nonInheritableStatics= lookup object represents a single static feature of the class that should not be inherited by subclasses, where the name of each property should be the name of a static feature (excluding the module name), and the value of each property should be a truthy value (such as =true=, =1=, ='foo'=, =[]=, ={}=, etc.). After a class has been created, non-inheritable statics can be registered for that class by assigning properties to the class' =MyClass.nonInheritableStatics= static property, as shown in the example below...
2124
+
2125
+ EXAMPLE
2126
+ ...........................................................................
2127
+ MyClass = Uize.Class.subclass ();
2128
+ MyClass.someUtilityFunction = function () {
2129
+ // do something of great utility
2130
+ };
2131
+ MyClass.nonInheritableStatics.someUtilityFunction = 1;
2132
+
2133
+ MyClassSubclass = MyClass.subclass ();
2134
+ alert (MyClassSubclass.someUtilityFunction); // alerts the text "undefined"
2135
+ ...........................................................................
2136
+
2137
+ In the above example, the =MyClass.someUtilityFunction= static method of the class =MyClass= has been registered as a non-inheritable static. This is done by the statement =MyClass.nonInheritableStatics.someUtilityFunction &#61; 1=. Now, when the =MyClassSubclass= class is created by calling the =MyClass.subclass= method, the new subclass that is created does not get the =someUtilityFunction= static feature. Therefore, the =alert= statement displays the text "undefined" in the alert dialog.
2138
+
2139
+ nonInheritableStatics is a Non-inheritable Static
2140
+ When a class is created, the =MyClass.nonInheritableStatics= static property is automatically initialized on that class to a fresh object with the value ={nonInheritableStatics:1}=.
2141
+
2142
+ This initial mapping means that the =MyClass.nonInheritableStatics= static property is, itself, not inheritable by subclasses - subclasses get their own fresh object. So, in our example, when the =MyClassSubclass= subclass is created, its fresh =MyClassSubclass.nonInheritableStatics= property does *not* have an entry for the =someUtilityFunction= static feature, because it does not have that static feature and the contents of the =MyClass.someUtilityFunction= object is not inherited by the =MyClassSubclass= class.
2143
+ */
2144
+
2145
+ _subclass.superclass = _class;
2146
+ /*?
2147
+ Static Properties
2148
+ Uize.Class.superclass
2149
+ A reference to the class' superclass.
2150
+
2151
+ SYNTAX
2152
+ ....................................
2153
+ superclassOBJ = classOBJ.superclass;
2154
+ ....................................
2155
+
2156
+ EXAMPLE
2157
+ ............................................................................
2158
+ var MyWidgetClass = Uize.Widget.subclass ();
2159
+ alert (MyWidgetClass.superclass == Uize.Widget); // displays the text "true"
2160
+ ............................................................................
2161
+ */
2162
+
2163
+ /*** Non-inherited Public Static Methods ***/
2164
+ _subclass.toString = _toString;
2165
+ _subclass.valueOf = _valueOf;
2166
+
2167
+ /*** Initialize Alphastructors and Omegastructors ***/
2168
+ var
2169
+ _alphastructors = _subclass._alphastructors = (_class._alphastructors || _sacredEmptyArray).concat (),
2170
+ _omegastructors = _subclass._omegastructors = (_class._omegastructors || _sacredEmptyArray).concat ()
2171
+ ;
2172
+ _alphastructor && _alphastructors.push (_alphastructor);
2173
+ _omegastructor && _omegastructors.push (_omegastructor);
2174
+
2175
+ _subclass._propertyProfilesByPrivateNames || (_subclass._propertyProfilesByPrivateNames = {});
2176
+ _subclass._propertyProfilesByPublicNames || (_subclass._propertyProfilesByPublicNames = {});
2177
+
2178
+ return _subclass;
2179
+ };
2180
+
2181
+ _class.subclass = function (_alphastructor,_omegastructor) {
2182
+ return _createSubclass (this,_alphastructor,_omegastructor);
2183
+ /*?
2184
+ Static Methods
2185
+ Uize.Class.subclass
2186
+ Lets you subclass the =Uize.Class= base class or any subclass of =Uize.Class=.
2187
+
2188
+ SYNTAX
2189
+ ......................................................
2190
+ MyClass = Uize.Class.subclass (subclassConstructorFN);
2191
+ ......................................................
2192
+
2193
+ Consider the following example...
2194
+
2195
+ EXAMPLE
2196
+ .......................................
2197
+ MyClass = Uize.Class.subclass (
2198
+ function () {
2199
+ this.foo = 'How unoriginal!';
2200
+ }
2201
+ );
2202
+
2203
+ MySubclass = MyClass.subclass (
2204
+ function () {
2205
+ this.bar = this.foo + ' Indeed!';
2206
+ }
2207
+ );
2208
+ .......................................
2209
+
2210
+ In the above example, =MySubclass= is a subclass of =MyClass=, which is in turn a subclass of the =Uize.Class= base class. Now, when an instance of =MySubSubclass= gets created, the constructor of =MyClass= and then the constructor of =MySubSubclass= will be executed in the initialization of the instance, and the instance will have both =foo= and =bar= properties, where the =bar= property will have a value of "How unoriginal! Indeed!".
2211
+ */
2212
+ };
2213
+
2214
+ _class.singleton = function (_scope,_properties) {
2215
+ var
2216
+ _singletons = this._singletons || (this._singletons = {}),
2217
+ _singleton = _singletons [_scope || (_scope = '')]
2218
+ ;
2219
+ _singleton
2220
+ ? _properties && _singleton.set (_properties)
2221
+ : (_singleton = _singletons [_scope] = this (_properties))
2222
+ ;
2223
+ return _singleton;
2224
+ /*?
2225
+ Static Methods
2226
+ Uize.Class.singleton
2227
+ Returns a singleton for the class for the optionally specified scope (default is empty scope).
2228
+
2229
+ DIFFERENT USAGES
2230
+
2231
+ `Get a Singleton for a Class`
2232
+ ....................................
2233
+ singletonOBJ = MyClass.singleton ();
2234
+ ....................................
2235
+
2236
+ `Get a Singleton for a Class for a Specific Scope`
2237
+ ............................................
2238
+ singletonOBJ = MyClass.singleton (scopeSTR);
2239
+ ............................................
2240
+
2241
+ `Get a Singleton for a Class for a Specific Scope, Specifying Initial State`
2242
+ ..........................................................
2243
+ singletonOBJ = MyClass.singleton (scopeSTR,propertiesOBJ);
2244
+ ..........................................................
2245
+
2246
+ Get a Singleton for a Class
2247
+ When no parameters are specified, this method will return a singleton for the class in the default scope.
2248
+
2249
+ SYNTAX
2250
+ ....................................
2251
+ singletonOBJ = MyClass.singleton ();
2252
+ ....................................
2253
+
2254
+ When the =Uize.Class.singleton= static method is called on a class, if a singleton instance has already been created for the default scope, then that instance will be returned. Otherwise, a singleton instance will be created for the default scope and then returned.
2255
+
2256
+ Get a Singleton for a Class for a Specific Scope
2257
+ When the optional =scopeSTR= parameter is specified, this method will return a singleton for the class in the specified scope.
2258
+
2259
+ SYNTAX
2260
+ ............................................
2261
+ singletonOBJ = MyClass.singleton (scopeSTR);
2262
+ ............................................
2263
+
2264
+ When the =Uize.Class.singleton= static method is called on a class, if a singleton instance has already been created for the specified scope, then that instance will be returned. Otherwise, a singleton instance will be created for the specified scope and then returned.
2265
+
2266
+ Get a Singleton for a Class for a Specific Scope, Specifying Initial State
2267
+ When the optional =propertiesOBJ= parameter is specified, then this method will return a singleton for the class in the specified scope, and with the state of its state properties set using the =propertiesOBJ= object.
2268
+
2269
+ SYNTAX
2270
+ ..........................................................
2271
+ singletonOBJ = MyClass.singleton (scopeSTR,propertiesOBJ);
2272
+ ..........................................................
2273
+
2274
+ When the =Uize.Class.singleton= static method is called on a class, if a singleton instance has already been created for the specified scope, then that instance will be set to the state specified by the =propertiesOBJ= parameter and then returned. Otherwise, a singleton instance will be created for the specified scope, with its state initialized using the =propertiesOBJ= parameter, and then returned.
2275
+
2276
+ Singleton Scope
2277
+ As a convenience, the =Uize.Class.singleton= static method lets you optionally specify a scope when getting singleton instances, using the =scopeSTR= parameter.
2278
+
2279
+ If no =scopeSTR= parameter is specified when getting a singleton for a class, then the default scope (an empty string) will be used. Therefore, the statement =MyClass.singleton ()= is equivalent to the statement =MyClass.singleton ('')=.
2280
+
2281
+ A scope provides multiple different bits of related but distributed code to get a reference to the same singleton by specifying the same scope, while still allowing other code to share references to a different singleton created using a different scope.
2282
+ */
2283
+ };
2284
+
2285
+ return _class;
2286
+ }
2287
+ });
2288
+
skin/frontend/default/customproduct/js/Uize.Color.js ADDED
@@ -0,0 +1,1515 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ /*______________
2
+ | ______ | U I Z E J A V A S C R I P T F R A M E W O R K
3
+ | / / | ---------------------------------------------------
4
+ | / O / | MODULE : Uize.Color Package
5
+ | / / / |
6
+ | / / / /| | ONLINE : http://www.uize.com
7
+ | /____/ /__/_| | COPYRIGHT : (c)1997-2012 UIZE
8
+ | /___ | LICENSE : Available under MIT License or GNU General Public License
9
+ |_______________| http://www.uize.com/license.html
10
+ */
11
+
12
+ /* Module Meta Data
13
+ type: Object
14
+ importance: 7
15
+ codeCompleteness: 95
16
+ testCompleteness: 0
17
+ docCompleteness: 92
18
+ */
19
+
20
+ /*?
21
+ Introduction
22
+ The =Uize.Color= module provides support for `Color Spaces`, `Color Encodings`, `Named Colors`, the =sRGB= and =HSL= color spaces, and many color encodings.
23
+
24
+ *DEVELOPERS:* `Chris van Rensburg`
25
+
26
+ Not a Uize Subclass
27
+ First off, it's worth emphasizing that the =Uize.Color= object is not a =Uize.Class= subclass, but a very lightweight object.
28
+
29
+ As such, the =Uize.Color= object does not support events, does not provide state properties, does not inherit subclassing facilities from the =Uize.Class= base class, etc. This object is deliberately designed to be very lightweight and to have a really tiny footprint - in the spirit of JavaScript's native objects, such as =String=, =Number=, =Date=, and the like.
30
+
31
+ Key Features
32
+ The =Uize.Color= object provides the following key features...
33
+
34
+ A Framework for Defining Color Spaces
35
+ Colors can be represented using different color models and mapping functions. These are called [[http://en.wikipedia.org/wiki/Color_space][color spaces]]. Examples of color spaces include =sRGB=, =HSL=, =HSV=, and =CMYK=, but there are many more in existence.
36
+
37
+ A Framework for Defining Color Encodings
38
+ Colors can be represented using different formats and color models. In UIZE, the combination of a color space and format is called a color encoding.
39
+
40
+ The =Uize.Color= object supports a wide variety of built-in `Color Encodings`. Multiple encodings often exist for the same color space. For example, the =#hex= (eg. =#ff00ff=), =RGB string= (eg. =rgb(255,0,255)=), and =name= (eg. =fuchsia=) encodings are all encodings for the =sRGB= color space.
41
+
42
+ ............................................................
43
+ << table >>
44
+
45
+ title: EXAMPLES OF BUILT-IN ENCODINGS
46
+ data
47
+ :| ENCODING NAME | THE COLOR FUCHSIA IN THIS ENCODING |
48
+ :| color | Uize.Color ('fuchsia') |
49
+ :| hex | ff00ff |
50
+ :| #hex | #ff0fff |
51
+ :| name | fuchsia |
52
+ :| RGB array | [255,0,255] |
53
+ :| RGB int | 16711935 |
54
+ :| RGB object | {red:255,green:0,blue:255} |
55
+ :| RGB string | rgb(255,0,255) |
56
+ :| HSL array | [300,100,50] |
57
+ :| HSL object | {hue:300,saturation:100,lightness:50} |
58
+ :| HSL string | hsl(300,100%,50%) |
59
+ ............................................................
60
+
61
+ Beyond the built-in encodings, further encodings are available in extension modules, such as the =Uize.Color.xHsv= module that defines the =HSV= color space. Further color spaces can be defined - your own custom color spaces, or those not yet supported.
62
+
63
+ Methods for Manipulating Colors
64
+ Using the =Uize.Color= object, colors can be converted across color spaces and formats.
65
+
66
+ Further utilities for dealing with colors are available in extension module, such as the =Uize.Color.xUtil= module, which provides methods for blending between colors, mixing multiple colors together, testing for color equivalence, etc.
67
+
68
+ A Framework for Defining Named Colors
69
+ `Named Colors` can be defined, and these colors can then be used wherever colors can be specified using the methods of the =Uize.Color= object.
70
+
71
+ And because the =Uize.Color= module is used by other modules, such as the =Uize.Fx= module, it is possible to use color names when specifying the values of color CSS style properties for fade effects. The SVG 1.0 and CSS 3 specifications define over a hundred additional named colors, and these become available when using the =Uize.Color.xSvgColors= extension module. You can also define your own custom named colors (see the section `Defining New Named Colors`).
72
+
73
+ Creating Instances
74
+ There are actually three different ways that a new instance of the =Uize.Color= object can be created.
75
+
76
+ Using the Constructor
77
+ Typically, you will create a new instance of the =Uize.Color= object using its constructor, as follows...
78
+
79
+ .............................................................
80
+ var myColor = Uize.Color ('#f0f'); // initialized to fuchsia
81
+ .............................................................
82
+
83
+ Using the Uize.Color.from Static Method
84
+ The =Uize.Color.from= static method is a factory method that decodes the specified color value and produces an instance of the =Uize.Color= object as a result.
85
+
86
+ ..................................................................
87
+ var myColor = Uize.Color.from ('#f0f'); // initialized to fuchsia
88
+ ..................................................................
89
+
90
+ Using the Uize.Color.to Static Method
91
+ The =Uize.Color.to= static method decodes the specified color value and then encodes it using the specified encoding. Using the =color= encoding encodes the source color as an instance of the =Uize.Color= object.
92
+
93
+ ........................................................................
94
+ var myColor = Uize.Color.to ('#f0f','color'); // initialized to fuchsia
95
+ ........................................................................
96
+
97
+ ### to note
98
+ - decoding colors
99
+ - encoding colors
100
+ - doesn't modify internal tuple values, only for output
101
+ - similarly, encoding into a different color space doesn't modify internal tuple values
102
+ - changing color encoding / converting colors to different color spaces
103
+ - manipulating colors (eg. blending, mixing, sorting)
104
+
105
+ - defining custom encodings
106
+ - the tuplet string encoding naming scheme (eg. "RGB string")
107
+ - explain some things about blending...
108
+ - when blending two colors, first color is authority on encoding (and, therefore, color space)
109
+ - when blending colors, they are blended in the color space of the encoding (not the target encoding)
110
+
111
+ ### Specifying Color Values
112
+ Automatic Encoding Detection
113
+ document...
114
+
115
+ Disambiguating Encoding
116
+ SYNTAX
117
+ ...
118
+ {'encoding name':colorValueANYTYPE}
119
+ ...
120
+
121
+ So, for example, the =HSL= tuple for the color white, which would be =[0,0,100]=, can be specified in a disambiguated form as ={'HSL array':[0,0,100]}=. Without this disambiguation, the automatic encoding detection will default to the =RGB array= encoding.
122
+
123
+ An Example
124
+ If you had two tuple arrays that each represented the three color components - hue, saturation, and brightness - of the =HSL= color space, then you could blend them as =HSL= colors by using the disambiguation facility, as follows...
125
+
126
+ EXAMPLE
127
+ .........................................................................................
128
+ var
129
+ color1HslTuple = [0,0,0], // black as an HSL tuple
130
+ color2HslTuple = [0,0,100] // white as an HSL tuple
131
+ ;
132
+ alert (
133
+ Uize.Color.blend ({'HSL array':color1HslTuple},{'HSL array':color2HslTuple},.5,'name')
134
+ );
135
+ .........................................................................................
136
+
137
+ In the above example, the =alert= statement will display the text "grey" in the dialog.
138
+ */
139
+
140
+ Uize.module ({
141
+ name:'Uize.Color',
142
+ builder:function () {
143
+ /*** Variables for Scruncher Optimization ***/
144
+ var _undefined;
145
+
146
+ /*** General Variables ***/
147
+ var
148
+ _colorNamesLookup,
149
+ _tupleRegExp = /(\w+)\s*\(\s*([^,\)]+)\s*,\s*([^,\)]+)\s*,\s*([^,\)]+)\s*(?:,\s*([^,\)]+)\s*)?\)/i
150
+ ;
151
+
152
+ /*** Utility Functions ***/
153
+ function _byte (_value) {
154
+ return Uize.constrain (Math.round (_value),0,255) || 0;
155
+ }
156
+
157
+ function _updateColorNamesLookup (_colors) {
158
+ var _colorInt;
159
+ for (var _colorName in _colors)
160
+ (_colorInt = _colors [_colorName]) in _colorNamesLookup || (_colorNamesLookup [_colorInt] = _colorName)
161
+ ;
162
+ }
163
+
164
+ /*** Constructor ***/
165
+ var
166
+ _object = Uize.noNew (
167
+ function () {
168
+ /*** Public Instance Properties ***/
169
+ this.tuple = [];
170
+
171
+ _objectPrototype.from.apply (this,arguments);
172
+ }
173
+ /*?
174
+ Constructor
175
+ Lets you create an instance of the =Uize.Color= object.
176
+
177
+ SYNTAX
178
+ .....................................
179
+ colorOBJ = Uize.Color (colorANYTYPE);
180
+ .....................................
181
+
182
+ Initial color value can be specified in the =colorANYTYPE= parameter using any of the many `Color Encodings` supported by the =Uize.Color= module. The following examples illustrate this variety and flexibility...
183
+
184
+ EXAMPLES
185
+ ..................................................................
186
+ Uize.Color (Uize.Color (255,0,255)); // color
187
+ Uize.Color ('ff00ff'); // hex
188
+ Uize.Color ('#ff00ff'); // #hex
189
+ Uize.Color ('fuchsia'); // name
190
+ Uize.Color ([255,0,255]); // RGB array
191
+ Uize.Color (0xff00ff); // RGB int
192
+ Uize.Color ({red:255,green:0,blue:255}); // RGB object
193
+ Uize.Color ('Rgb(255,0,255)'); // RGB string
194
+ Uize.Color ({'HSL array':[300,100,50]}); // HSL array
195
+ Uize.Color ({hue:300,saturation:100,lightness:50}); // HSL object
196
+ Uize.Color ('Hsl(300,100%,50%)'); // HSL string
197
+ ..................................................................
198
+
199
+ VARIATION 1
200
+ .........................
201
+ colorOBJ = Uize.Color ();
202
+ .........................
203
+
204
+ When no parameter is specified, then the instance will be initialized to black (in the =sRGB= color space).
205
+
206
+ VARIATION 2
207
+ ................................................
208
+ colorOBJ = Uize.Color (redINT,greenINT,blueINT);
209
+ ................................................
210
+
211
+ When the three parameters =redINT=, =greenINT=, =blueINT= are specified, then the color will be initialized as though the arguments of the constructor represented an =RGB array= encoding.
212
+
213
+ EXAMPLE
214
+ ........................................
215
+ var
216
+ yellow = Uize.Color (255,255,0),
217
+ alsoYellow = Uize.Color ([255,255,0])
218
+ ;
219
+ ........................................
220
+
221
+ NOTES
222
+ - in addition to using the constructor, there are two other methods for `Creating Instances` of the =Uize.Color= object
223
+
224
+ Instance Properties
225
+ encoding
226
+ A string, reflecting the name of the color encoding that is set for the instance.
227
+
228
+ This is a read-only property. In order to change the color encoding for an instance, you should use the =setEncoding= instance method. The =setEncoding= method handles the conversions necessary when switching to an encoding in a different color space and will automatically transform the color component values contained inside the =tuple= array.
229
+
230
+ NOTES
231
+ - this is a read-only property
232
+ - see the related =setEncoding= instance method
233
+
234
+ tuple
235
+ An array, containing typically three, but up to four floating point number elements, representing the values for the color components of the instance.
236
+
237
+ This property can be accessed by code that wishes to perform color computations, or by code that wishes to encode a color value in a custom manner - not using any of the `Color Encodings` supported by the =Uize.Color= object. This property can also be useful when implementing extension modules.
238
+
239
+ NOTES
240
+ - for three component color spaces, the =tuple= array may still contain four elements, where the value of the fourth element is =NaN= or =undefined=
241
+ - see the related =getTuple= instance method
242
+ */
243
+ ),
244
+ _objectPrototype = _object.prototype
245
+ ;
246
+
247
+ /*** Public Instance Methods ***/
248
+ _objectPrototype.from = function (_color) {
249
+ var _this = this;
250
+ if (_color instanceof _object) {
251
+ _this.encoding = _color.encoding;
252
+ _setTupleFromArray (_color.tuple,_this.tuple);
253
+ } else {
254
+ var _encoding;
255
+ if (arguments.length == 3) {
256
+ _encoding = 'RGB array';
257
+ _color = _cloneTuple (arguments); // NOTE: can't just assign arguments to _color, since color is the first argument, and doing so will make the first argument a reference to arguments
258
+ } else {
259
+ if (_color == _undefined || typeof _color == 'number') {
260
+ _encoding = 'RGB int';
261
+ } else if (typeof _color == 'string') {
262
+ if (_colors [_color] != _undefined || _colors [_color.toLowerCase ()] != _undefined) {
263
+ _encoding = 'name';
264
+ } else {
265
+ var _tupleMatch = _color.match (_tupleRegExp);
266
+ _encoding = _tupleMatch
267
+ ? _tupleMatch [1].toUpperCase () + ' string'
268
+ : _color.charCodeAt (0) == 35 ? '#hex' : 'hex'
269
+ ;
270
+ }
271
+ } else if (typeof _color == 'object') {
272
+ if (_color.length) {
273
+ _encoding = 'RGB array';
274
+ } else if ('red' in _color) {
275
+ _encoding = 'RGB object';
276
+ } else if ('lightness' in _color) {
277
+ _encoding = 'HSL object';
278
+ } else {
279
+ for (_encoding in _color) break;
280
+ _color = _color [_encoding];
281
+ }
282
+ }
283
+ }
284
+ var _encodingProfile = _encodings [_encoding];
285
+ if (!_encodingProfile) {
286
+ _encodingProfile = _encodings [_encoding = 'RGB int'];
287
+ _color = 0;
288
+ }
289
+ _encodingProfile.from (_color,_this.tuple);
290
+ _this.encoding = _encoding;
291
+ }
292
+
293
+ return _this;
294
+ /*?
295
+ Instance Methods
296
+ from
297
+ Lets you set the color for the =Uize.Color= object instance from the specified color, by decoding the specified color as needed.
298
+
299
+ SYNTAX
300
+ ........................................
301
+ colorOBJ = colorOBJ.from (colorANYTYPE);
302
+ ........................................
303
+
304
+ The color specified by the =colorANYTYPE= parameter can be specified using any of the many `Color Encodings` supported by the =Uize.Color= module. The following examples illustrate this variety and flexibility...
305
+
306
+ EXAMPLES
307
+ ....................................................................
308
+ myColor.from (Uize.Color (255,0,255)); // color
309
+ myColor.from ('ff00ff'); // hex
310
+ myColor.from ('#ff00ff'); // #hex
311
+ myColor.from ('fuchsia'); // name
312
+ myColor.from ([255,0,255]); // RGB array
313
+ myColor.from (0xff00ff); // RGB int
314
+ myColor.from ({red:255,green:0,blue:255}); // RGB object
315
+ myColor.from ('Rgb(255,0,255)'); // RGB string
316
+ myColor.from ({hue:300,saturation:100,lightness:50}); // HSL object
317
+ myColor.from ('Hsl(300,100%,50%)'); // HSL string
318
+ ....................................................................
319
+
320
+ The above statements would all set the color of the instance =myColor= to the color "fuchsia" (=#ff00ff=).
321
+
322
+ VARIATION
323
+ .................
324
+ colorOBJ.from ();
325
+ .................
326
+
327
+ When no =colorANYTYPE= parameter is specified, the instance will be initialized to black (in the =sRGB= color space).
328
+
329
+ TIP
330
+
331
+ Because the =from= method returns the instance on which it is called, you can "daisy chain" method calls, as in...
332
+
333
+ ..............................................................
334
+ fuchsiaHslObject = myColor.from ('fuchsia').to ('HSL object');
335
+ ..............................................................
336
+
337
+ The above example first sets the =Uize.Color= object instance =myColor= to the color "fuchsia" and then encodes its value as =HSL object= and assigns that value to the variable =fuchsiaHslObject=.
338
+
339
+ NOTES
340
+ - see the related =Uize.Color.from= static method
341
+ */
342
+ };
343
+
344
+ _objectPrototype.getTuple = function (_encodingOrColorSpace) {
345
+ var
346
+ _oldEncodingColorSpaceProfile = _colorSpaces [_encodings [this.encoding].colorSpace],
347
+ _newEncodingColorSpaceProfile = _encodingOrColorSpace
348
+ ?
349
+ _colorSpaces [_encodingOrColorSpace] ||
350
+ _colorSpaces [_encodings [_encodingOrColorSpace].colorSpace]
351
+ :
352
+ _oldEncodingColorSpaceProfile
353
+ ;
354
+ return (
355
+ _newEncodingColorSpaceProfile != _oldEncodingColorSpaceProfile
356
+ ? _newEncodingColorSpaceProfile.fromHsl (_oldEncodingColorSpaceProfile.toHsl (this.tuple))
357
+ : this.tuple
358
+ );
359
+ /*?
360
+ Instance Methods
361
+ getTuple
362
+ Returns an array, being the the tuple of color components for the instance, transformed for the specified color encoding or color space.
363
+
364
+ SYNTAX
365
+ ........................................................
366
+ tupleARRAY = myColor.getTuple (encodingOrColorSpaceSTR);
367
+ ........................................................
368
+
369
+ If the color space of the instance's current encoding is the same as the color space defined by the =encodingOrColorSpaceSTR= parameter, then the value of the =tuple= instance property will be returned as is (ie. no transformation is performed). Otherwise, the necessary conversion functions will be employed to transform the instance's tuple for use in the desired color space.
370
+
371
+ This method can be used by other methods that wish to blend, mix, or otherwise process multiple tuples in a single color space.
372
+
373
+ VARIATION
374
+ .................................
375
+ tupleARRAY = myColor.getTuple ();
376
+ .................................
377
+
378
+ When no =encodingOrColorSpaceSTR= parameter is specified, then the value of the =tuple= instance property will be returned (ie. no transformation is performed).
379
+
380
+ EXAMPLE
381
+ ................................
382
+ myColor.getTuple ('HSL');
383
+ myColor.getTuple ('HSL array');
384
+ myColor.getTuple ('HSL string');
385
+ ................................
386
+
387
+ In the above example, the same =HSL= color space is implied by all statements, so all statements will return the same result. Note that the particular encoding has no bearing on how the tuple is returned - it is always an array of the components of the color. So, the value ='HSL string'= for =encodingOrColorSpaceSTR= still results in the tuple array being returned.
388
+
389
+ NOTES
390
+ - see the related =tuple= and =encoding= instance properties
391
+ */
392
+ };
393
+
394
+ _objectPrototype.setEncoding = function (_newEncoding) {
395
+ _setTupleFromArray (
396
+ this.getTuple (_newEncoding && _newEncoding != 'color' ? _newEncoding : (_newEncoding = 'hex')),
397
+ this.tuple
398
+ );
399
+ this.encoding = _newEncoding;
400
+ return this;
401
+ /*?
402
+ Instance Methods
403
+ setEncoding
404
+ Lets you change the encoding for an instance.
405
+
406
+ Changing the encoding for an instance will have no effect on the instance's =tuple= values if the new encoding is of the same color space as the current encoding. However, if the color spaces differ, then the =tuple= values will be converted to be in the color space of the new encoding.
407
+
408
+ SYNTAX
409
+ ..................................
410
+ myColor.setEncoding (encodingSTR);
411
+ ..................................
412
+
413
+ NOTES
414
+ - see the related =encoding= instance property
415
+ */
416
+ };
417
+
418
+ _objectPrototype.to = function (_newEncoding) {
419
+ return (
420
+ _newEncoding == 'color'
421
+ ? new _object (this)
422
+ : _encodings [_newEncoding || this.encoding].to (this.getTuple (_newEncoding))
423
+ );
424
+ /*?
425
+ Instance Methods
426
+ to
427
+ Returns the current color of the instance, encoded to the specified color encoding.
428
+
429
+ SYNTAX
430
+ .........................................
431
+ encodedColor = colorOBJ.to (encodingSTR);
432
+ .........................................
433
+
434
+ The =encodingSTR= parameter supports a wide variety of different `Color Encodings`.
435
+
436
+ EXAMPLES
437
+ .............................................................................
438
+ var fuchsia = Uize.Color ('fuchsia');
439
+ fuchsia.to ('color'); // produces a new Uize.Color object
440
+ fuchsia.to ('hex'); // produces 'ff00ff'
441
+ fuchsia.to ('#hex'); // produces '#ff00ff'
442
+ fuchsia.to ('name'); // produces 'fuchsia'
443
+ fuchsia.to ('RGB array'); // produces [255,0,255]
444
+ fuchsia.to ('RGB int'); // produces 16711935
445
+ fuchsia.to ('RGB object'); // produces {red:255,green:0,blue:255}
446
+ fuchsia.to ('RGB string'); // produces 'rgb(255,0,255)'
447
+ fuchsia.to ('HSL array'); // produces [300,100,50]
448
+ fuchsia.to ('HSL object'); // produces {hue:300,saturation:100,lightness:50}
449
+ fuchsia.to ('HSL string'); // produces 'hsl(300,100,50)'
450
+ .............................................................................
451
+
452
+ NOTES
453
+ - see the related =Uize.Color.to= static method
454
+ */
455
+ };
456
+
457
+ /*** Public Static Methods ***/
458
+ _object.adapter = function (_aEncoding,_bEncoding) {
459
+ return {
460
+ aToB:function (_value) {return Uize.Color.to (Uize.pairUp (_aEncoding,_value),_bEncoding)},
461
+ bToA:function (_value) {return Uize.Color.to (Uize.pairUp (_bEncoding,_value),_aEncoding)}
462
+ }
463
+ /*?
464
+ Static Methods
465
+ Uize.Color.adapter
466
+ Returns a value adapter object,
467
+
468
+ SYNTAX
469
+ .................................................................
470
+ valueAdapterOBJ = Uize.Color.adapter (aEncodingSTR,bEncodingSTR);
471
+ .................................................................
472
+ */
473
+ };
474
+
475
+ _object.defineColors = function (_colorsToDefine) {
476
+ Uize.copyInto (_colors,_colorsToDefine);
477
+ _colorNamesLookup && _updateColorNamesLookup (_colorsToDefine);
478
+ /*?
479
+ Static Methods
480
+ Uize.Color.defineColors
481
+ Lets you define an arbitrary number of custom `Named Colors`, which will then be accessible to code that uses the =Uize.Color= module.
482
+
483
+ SYNTAX
484
+ .......................................
485
+ Uize.Color.defineColors (colorsMapOBJ);
486
+ .......................................
487
+
488
+ When you extend this object with new named colors, it will then be possible to use the names of those colors when creating instances of the =Uize.Color= object, or when setting the color of =Uize.Color= instances using the =from= instance method.
489
+
490
+ For more information, see the section `Defining New Named Colors`.
491
+
492
+ NOTES
493
+ - see the related =Uize.Color.colors= static property
494
+ - over a hundred additional named colors - as defined in the SVG 1.0 and CSS 3 specifications - are defined in the =Uize.Color.xSvgColors= extension module
495
+ */
496
+ };
497
+
498
+ _object.from = function () {
499
+ return _objectPrototype.from.apply (new _object,arguments)
500
+ /*?
501
+ Static Methods
502
+ Uize.Color.from
503
+ Returns a freshly minted instance of the =Uize.Color= object, whose color is initialized to the specified color, by decoding the specified color as needed.
504
+
505
+ SYNTAX
506
+ ..........................................
507
+ colorOBJ = Uize.Color.from (colorANYTYPE);
508
+ ..........................................
509
+
510
+ The =Uize.Color.from= method is a factory method, is essentially equivalent to using the =Uize.Color= object's `Constructor`, and is mainly provided to have parity with the =Uize.Color.to= static method.
511
+
512
+ EXAMPLE
513
+ ...........................
514
+ Uize.Color ('ff00ff');
515
+ Uize.Color.from ('ff00ff');
516
+ ...........................
517
+
518
+ The above two statements would both return new instances of the =Uize.Color= object initialized to the color "fuchsia" (=#ff00ff=).
519
+
520
+ The color specified by the =colorANYTYPE= parameter can be specified using any of the many `Color Encodings` supported by the =Uize.Color= module. The following examples illustrate this variety and flexibility...
521
+
522
+ EXAMPLES
523
+ .......................................................................
524
+ Uize.Color.from (Uize.Color (255,0,255)); // color
525
+ Uize.Color.from ('ff00ff'); // hex
526
+ Uize.Color.from ('#ff00ff'); // #hex
527
+ Uize.Color.from ('fuchsia'); // name
528
+ Uize.Color.from ([255,0,255]); // RGB array
529
+ Uize.Color.from (0xff00ff); // RGB int
530
+ Uize.Color.from ({red:255,green:0,blue:255}); // RGB object
531
+ Uize.Color.from ('Rgb(255,0,255)'); // RGB string
532
+ Uize.Color.from ({hue:300,saturation:100,lightness:50}); // HSL object
533
+ Uize.Color.from ('Hsl(300,100%,50%)'); // HSL string
534
+ .......................................................................
535
+
536
+ The above statements would all return new instances of the =Uize.Color= object initialized to the color "fuchsia" (=#ff00ff=).
537
+
538
+ VARIATION
539
+ ...................
540
+ Uize.Color.from ();
541
+ ...................
542
+
543
+ When no =colorANYTYPE= parameter is specified, the new instance will be initialized to black (in the =sRGB= color space).
544
+
545
+ A Tip on Preserving Encoding
546
+ There might be times when you want to set the color value for an instance using a color that is specified in a different encoding - possibly even in a different color space - but you don't wish to change the encoding of the instance.
547
+
548
+ You can accomplish this by temporarily storing the instance's encoding, and then restoring it after setting the instance's color by using the =setEncoding= instance method, as in...
549
+
550
+ EXAMPLE
551
+ .......................................................
552
+ var oldEncoding = myColor.encoding;
553
+ myColor.from (newColorValue).setEncoding (oldEncoding);
554
+ .......................................................
555
+
556
+ Because the =from= instance method returns a reference to the instance, you can call the =setEncoding= method on the result.
557
+
558
+ NOTES
559
+ - see the related =from= instance method
560
+ */
561
+ };
562
+
563
+ var _cloneTuple = _object.cloneTuple = function (_tuple) {
564
+ var _component3 = _tuple [3];
565
+ return (
566
+ isNaN (_component3) || _component3 == _undefined
567
+ ? [_tuple [0],_tuple [1],_tuple [2]]
568
+ : [_tuple [0],_tuple [1],_tuple [2],_component3]
569
+ );
570
+ /*?
571
+ Static Methods
572
+ Uize.Color.cloneTuple
573
+ A method that is useful in the development of color space or encoding extensions, and that returns a tuple array, being a clone of the specified source tuple array.
574
+
575
+ SYNTAX
576
+ ......................................................
577
+ clonedTupleARRAY = Uize.Color.cloneTuple (tupleARRAY);
578
+ ......................................................
579
+
580
+ This method is intended primary for use in the implementation of `Color Encodings`.
581
+
582
+ NOTES
583
+ - see the related =Uize.Color.setTuple=, =Uize.Color.setTupleFromArray=, and =Uize.Color.setTupleFromString= static methods
584
+ */
585
+ };
586
+
587
+ var _setTuple = _object.setTuple = function (_tuple,_component0,_component1,_component2,_component3) {
588
+ _tuple [0] = +_component0;
589
+ _tuple [1] = +_component1;
590
+ _tuple [2] = +_component2;
591
+ _tuple [3] = +_component3;
592
+ /*?
593
+ Static Methods
594
+ Uize.Color.setTuple
595
+ A method that is useful in the development of color space or encoding extensions, and that copies the specified values for up to four components of a tuple into the specified tuple array.
596
+
597
+ SYNTAX
598
+ ..................................................................
599
+ Uize.Color.setTuple (
600
+ tupleARRAY,
601
+ component0FLOAT,component1FLOAT,component2FLOAT,component3FLOAT
602
+ );
603
+ ..................................................................
604
+
605
+ This method is intended primary for use in the implementation of `Color Encodings`.
606
+
607
+ NOTES
608
+ - see the related =Uize.Color.cloneTuple=, =Uize.Color.setTupleFromArray=, and =Uize.Color.setTupleFromString= static methods
609
+ */
610
+ };
611
+
612
+ var _setTupleFromArray = _object.setTupleFromArray = function (_array,_tuple) {
613
+ _setTuple (_tuple,_array [0],_array [1],_array [2],_array [3]);
614
+ /*?
615
+ Static Methods
616
+ Uize.Color.setTupleFromArray
617
+ A method that is useful in the development of color space or encoding extensions, and that copies the values of the first four elements of the specified source array into the specified tuple array.
618
+
619
+ SYNTAX
620
+ ......................................................
621
+ Uize.Color.setTupleFromArray (sourceARRAY,tupleARRAY);
622
+ ......................................................
623
+
624
+ This method is intended primary for use in the implementation of `Color Encodings`.
625
+
626
+ NOTES
627
+ - see the related =Uize.Color.cloneTuple=, =Uize.Color.setTuple=, and =Uize.Color.setTupleFromString= static methods
628
+ */
629
+ };
630
+
631
+ var _setTupleFromString = _object.setTupleFromString = function (_tupleStr,_tuple) {
632
+ var _tupleMatch = _tupleStr.match (_tupleRegExp);
633
+ _setTuple (
634
+ _tuple,
635
+ parseFloat (_tupleMatch [2]),
636
+ parseFloat (_tupleMatch [3]),
637
+ parseFloat (_tupleMatch [4]),
638
+ parseFloat (_tupleMatch [5])
639
+ );
640
+ /*?
641
+ Static Methods
642
+ Uize.Color.setTupleFromString
643
+ A method that is useful in the development of color space or encoding extensions, and that parses up to four color components from the specified source string and copies the values of those components into the specified tuple array.
644
+
645
+ SYNTAX
646
+ .....................................................
647
+ Uize.Color.setTupleFromString (sourceSTR,tupleARRAY);
648
+ .....................................................
649
+
650
+ This method is intended primary for use in the implementation of `Color Encodings`.
651
+
652
+ NOTES
653
+ - see the related =Uize.Color.cloneTuple=, =Uize.Color.setTuple=, and =Uize.Color.setTupleFromArray= static methods
654
+ */
655
+ };
656
+
657
+ _object.to = function (_colorValue,_encoding) {
658
+ return _dummyColor1.from (_colorValue).to (_encoding || 'hex')
659
+ /*?
660
+ Static Methods
661
+ Uize.Color.to
662
+ Encodes the specified color to the specified encoding / format.
663
+
664
+ SYNTAX
665
+ .......................................................................
666
+ encodedColorANYTYPE = Uize.Color.to (colorToEncodeANYTYPE,encodingSTR);
667
+ .......................................................................
668
+
669
+ This method's return value can be of any type, and is determined by the encoding specified in the =encodingSTR= parameter, which supports a wide variety of different `Color Encodings`. Moreover, the color to be encoded, as specified by the =colorToEncodeANYTYPE= parameter, can be specified in any of the supported encodings.
670
+
671
+ VARIATION
672
+ ..........................................................
673
+ encodedColorHexSTR = Uize.Color.to (colorToEncodeANYTYPE);
674
+ ..........................................................
675
+
676
+ When no =encodingSTR= parameter is specified, then the color specified by the =colorToEncodeANYTYPE= parameter will be encoded as =hex=.
677
+
678
+ EXAMPLES
679
+ ..................................................................................
680
+ Uize.Color.to ('fuchsia','color'); // produces a new Uize.Color object
681
+ Uize.Color.to ('#f0f','HSL object'); // {hue:300,saturation:100,lightness:50}
682
+ Uize.Color.to ('Rgb(255,0,255)','name'); // produces 'fuchsia'
683
+ Uize.Color.to ('hsl(300,100,50)','#hex'); // produces '#ff00ff'
684
+ Uize.Color.to ('ff00ff','HSL string'); // produces 'hsl(300,100,50)'
685
+ Uize.Color.to ('fuchsia,'RGB string'); // produces 'rgb(255,0,255)'
686
+ Uize.Color.to ([255,0,255],'hex'); // produces 'ff00ff'
687
+ Uize.Color.to ([255,0,255]); // produces 'ff00ff'
688
+ ..................................................................................
689
+
690
+ These are just a few examples to illustrate the versatility of this method. Given the wide variety of different `Color Encodings` supported by the =Uize.Color= module, there are a great many permutations to this method - too numerous to list.
691
+
692
+ NOTES
693
+ - see the related =to= instance method
694
+ */
695
+ };
696
+
697
+ /*** Public Static Properties ***/
698
+ /*** Color Spaces ***/
699
+ var _colorSpaces = _object.colorSpaces = {
700
+ /*?
701
+ Static Properties
702
+ Uize.Color.colorSpaces
703
+ An object, containing definitions for `Color Spaces` supported by the =Uize.Color= object.
704
+
705
+ In general, color spaces are not explicitly specified when working with =Uize.Color= instances. Instead, a color space is implied by a given color encoding. Encodings specify their associated color spaces, and the profile that defines a color space is utilized automatically when encoding across color spaces, such as when encoding a color object that was initialized in the =sRGB= color space as =HSL string=, as shown in the following example...
706
+
707
+ EXAMPLE
708
+ ................................................................................
709
+ var myRgbColor = Uize.Color ('#ff00ff');
710
+ alert (myRgbColor.to ('HSL string')); // displays "Hsl(300,100%,50%)" in dialog
711
+ ................................................................................
712
+
713
+ You can define your own color spaces by extending the =Uize.Color.colorSpaces= static property. For more information, see the section `Defining New Color Spaces`.
714
+
715
+ NOTES
716
+ - compare to the =Uize.Color.encodings= static property
717
+
718
+ Color Spaces
719
+ The =Uize.Color= object provides a foundation for supporting multiple color spaces, and supports two built-in color spaces: =sRGB= and =HSL=.
720
+
721
+ A [[http://en.wikipedia.org/wiki/Color_space][color space]] provides a way to represent colors, and is the combination of a [[http://en.wikipedia.org/wiki/Color_model][color model]] and a mapping function. Certain color spaces are better suited to specific applications, and a wide variety of color spaces exist. In the computer world, =sRGB= is the dominant color space and is based around an additive color model. In the print world, =CMYK= is a dominant color space and is based around a subtractive color model.
722
+
723
+
724
+ */
725
+ sRGB:{
726
+ fromHsl:function (_tuple) {
727
+ // http://en.wikipedia.org/wiki/HSL_color_space
728
+ var
729
+ _saturation = _tuple [1] / 100,
730
+ _lightness = _tuple [2] / 100
731
+ ;
732
+ if (_saturation) {
733
+ var
734
+ _temp1 = _lightness < .5
735
+ ? _lightness * (1 + _saturation)
736
+ : _lightness + _saturation - _lightness * _saturation,
737
+ _temp2 = 2 * _lightness - _temp1
738
+ ;
739
+ var _hue = _tuple [0] / 360;
740
+ function _computeChannel (_level) {
741
+ return (
742
+ (_level = (_level + 1) % 1) < 1 / 6
743
+ ? _temp2 + (_temp1 - _temp2) * 6 * _level
744
+ : _level < .5
745
+ ? _temp1
746
+ : _level < 2 / 3
747
+ ? _temp2 + (_temp1 - _temp2) * 6 * (2 / 3 - _level)
748
+ : _temp2
749
+ ) * 255;
750
+ }
751
+ return [_computeChannel (_hue + 1 / 3),_computeChannel (_hue),_computeChannel (_hue - 1 / 3)];
752
+ } else {
753
+ var _channelLevel = _lightness * 255;
754
+ return [_channelLevel,_channelLevel,_channelLevel];
755
+ }
756
+ },
757
+ toHsl:function (_tuple) {
758
+ // http://en.wikipedia.org/wiki/HSL_color_space
759
+ var
760
+ _redLevel = _tuple [0] / 255,
761
+ _greenLevel = _tuple [1] / 255,
762
+ _blueLevel = _tuple [2] / 255,
763
+ _maxLevel = Math.max (_redLevel,_greenLevel,_blueLevel),
764
+ _minLevel = Math.min (_redLevel,_greenLevel,_blueLevel),
765
+ _maxMinLevelSum = _maxLevel + _minLevel,
766
+ _maxMinLevelDelta = _maxLevel - _minLevel,
767
+ _hue = 0,
768
+ _saturation = 0,
769
+ _lightness = _maxMinLevelSum / 2
770
+ ;
771
+ if (_maxMinLevelDelta) {
772
+ _saturation = _maxMinLevelDelta / (_lightness < .5 ? _maxMinLevelSum : 2 - _maxMinLevelSum);
773
+ _hue =
774
+ (
775
+ (
776
+ _redLevel == _maxLevel
777
+ ? 6 + (_greenLevel - _blueLevel) / _maxMinLevelDelta
778
+ : _greenLevel == _maxLevel
779
+ ? 2 + (_blueLevel - _redLevel) / _maxMinLevelDelta
780
+ : 4 + (_redLevel - _greenLevel) / _maxMinLevelDelta
781
+ ) * 60
782
+ ) % 360
783
+ ;
784
+ }
785
+ function _levelToPercent (_level) {return Uize.constrain (_level * 100,0,100)}
786
+ return [_hue,_levelToPercent (_saturation),_levelToPercent (_lightness)];
787
+ },
788
+ tuple:[
789
+ {name:'red',min:0,max:255},
790
+ {name:'green',min:0,max:255},
791
+ {name:'green',min:0,max:255}
792
+ ]
793
+ /*?
794
+ Color Spaces
795
+ sRGB
796
+ The =Uize.Color.colorSpaces.sRGB= property defines the [[http://en.wikipedia.org/wiki/SRGB][sRGB]] (standard RGB) color space.
797
+
798
+ sRGB is the recommended color space for the Internet and is the color space used by the [[http://www.w3.org/TR/CSS21/colors.html][CSS 2.1 color specification]]. Because of this, it is also the default working color space for many digital cameras, phones, scanners, and other electronics devices.
799
+
800
+ */
801
+ },
802
+ HSL:{
803
+ fromHsl:Object, // when called as a function with an object argument, Object just returns argument
804
+ toHsl:Object,
805
+ tuple:[
806
+ {name:'hue',min:0,max:360},
807
+ {name:'saturation',min:0,max:100},
808
+ {name:'lightness',min:0,max:100}
809
+ ]
810
+ /*?
811
+ Color Spaces
812
+ HSL
813
+ The =Uize.Color.colorSpaces.HSL= property defines the [[http://en.wikipedia.org/wiki/HSL_color_space][HSL]] (Hue, Saturation, Lightness) color space.
814
+
815
+ The HSL color space is essentially an alternate representation / mapping of the =sRGB= color space, but might be considered to be a more intuitive representation of the qualities of color. Because of the benefits of this color space, it has been adopted in the [[http://www.w3.org/TR/css3-color/#hsl-color][CSS 3 color specification]] as another accepted way of specifying colors.
816
+ */
817
+ }
818
+ /*?
819
+ Color Spaces
820
+ Additional Color Spaces
821
+ Additional color spaces are made available through extension modules, such as the =Uize.Color.xHsv= module that defines the =HSV= color space.
822
+
823
+ Implementing color spaces in extension modules avoids burdening the core code with having to support less common / more esoteric color spaces that are not as frequently used. This also allows applications built on the UIZE JavaScript Framework to be better optimized for code size.
824
+
825
+ Defining New Color Spaces
826
+ You can extend the =Uize.Color.colorSpaces= object in order to define new `Color Spaces`.
827
+
828
+ This can be done quite easily by setting a new property on the =Uize.Color.colorSpaces= object, as follows...
829
+
830
+ EXAMPLE
831
+ ....................................................................
832
+ Uize.Color.colorSpaces.CMYK = {
833
+ fromHsl:function (_tuple) {
834
+ // this function should accept a tuple in the HSL colorspace
835
+ // and should return a new tuple that represents the color
836
+ // transformed to the CMYK color space
837
+ },
838
+ toHsl:function (_tuple) {
839
+ // this function should accept a tuple in the CMYK color space
840
+ // and should return a new tuple that represents the color
841
+ // transformed to the HSL color space
842
+ },
843
+ tuple:[
844
+ {name:'cyan',min:0,max:100},
845
+ {name:'magenta',min:0,max:100},
846
+ {name:'yellow',min:0,max:100},
847
+ {name:'black',min:0,max:100}
848
+ ]
849
+ }
850
+ ....................................................................
851
+
852
+ Typically one will define a new color space and also define new `Color Encodings` to accompany the new color space. The new encodings should specify the name of their associated color space in their =colorSpace= property.
853
+
854
+ The object that describes a color space is called a color space profile, and should have the following properties...
855
+
856
+ - =fromHsl= - This is a function that should accept a tuple in the =HSL= colorspace and should return a new tuple that represents the color transformed to your color space.
857
+
858
+ - =toHsl= - This function should accept a tuple in your color space and should return a new tuple that represents the color transformed to the =HSL= color space.
859
+
860
+ - =tuple (profile)= - This is an object that provides a profile for the tuple of color components of the color space - the "dimensions" of the color space, if you will. The tuple profile is an array of objects, one for each component of the color space, where each object is a profile for a component and should contain "name", "min", and "max" properties. The "name" property for a component profile is self-explanatory, and the "min" and "max" properties define the value range for the component.
861
+
862
+ The =fromHsl= and =toHsl= conversion functions that you provide as part of a color space profile are used for converting a tuple back and forth between your color space and the =HSL= color space. The =HSL= color space is essentially used as a canonical color space - a kind of "conduit" through which colors are converted in order to convert across `Color Spaces`. This avoids having to have an ever increasing number of cross conversion functions for every defined color space to every other. For example, if a =CMYK= color space were defined, then conversion from =sRGB= to =CMYK= would first involve conversion from =sRGB= to =HSL=, and then =HSL= to =CMYK=.
863
+ */
864
+ };
865
+
866
+ /*** Encodings ***/
867
+ function _setTupleFromRgbHex (_color,_tuple) {
868
+ if (_color.charCodeAt (0) == 35)
869
+ _color = _color.slice (1) // strip "#"
870
+ ;
871
+ var _hexDigits = _color.length;
872
+ _color = '0x' + _color - 0;
873
+ _hexDigits == 1
874
+ ? _setTuple (_tuple,_color *= 17,_color,_color)
875
+ : _hexDigits == 3
876
+ ? _setTuple (_tuple,((_color >> 8) & 15) * 17,((_color >> 4) & 15) * 17,(_color & 15) * 17)
877
+ : _setTuple (_tuple,(_color >> 16) & 255,(_color >> 8) & 255,_color & 255)
878
+ ;
879
+ }
880
+
881
+ var _encodings = _object.encodings = {
882
+ /*?
883
+ Color Encodings
884
+ The =Uize.Color= module supports a wide variety of different color encodings / formats.
885
+
886
+ For methods that have color parameters, color values for these parameters can be flexibly specified in any of the many supported encodings. Additionally, many of the methods that produce a color as a result allow an encoding to optionally be specified for that return value.
887
+
888
+ Supported encodings are as follows...
889
+
890
+ color
891
+ An instance of the =Uize.Color= object.
892
+
893
+ Encoding
894
+ When a color is encoded as =color=, an instance of the =Uize.Color= object is created with its color initialized to that of the encoding source.
895
+
896
+ ...........................................
897
+ << table >>
898
+
899
+ title: EXAMPLES
900
+ data
901
+ :| COLOR NAME | color |
902
+ :| fuchsia | Uize.Color ('fuchsia') |
903
+ :| yellow | Uize.Color ('yellow') |
904
+ :| blue | Uize.Color ('blue') |
905
+ :| white | Uize.Color ('white') |
906
+ ...........................................
907
+
908
+ Decoding
909
+ When a color is decoded from =color=, the value of the source =Uize.Color= object instance's =encoding= property and the component values in its =tuple= property are used for the resulting =Uize.Color= object.
910
+
911
+ Static Properties
912
+ Uize.Color.encodings
913
+ An object, containing definitions for color encodings supported by the =Uize.Color= object.
914
+
915
+ The =Uize.Color= object defines a wide variety of built-in encodings. For the full list, consult the section `Color Encodings`. You can also define your own color encoding by extending the =Uize.Color.encodings= static property. For more information, see the section `Defining New Color Encodings`.
916
+
917
+ NOTES
918
+ - see the related =Uize.Color.colorSpaces= static property
919
+ */
920
+ hex:{
921
+ colorSpace:'sRGB',
922
+ from:_setTupleFromRgbHex,
923
+ to:function (_tuple) {
924
+ return (0x1000000 + _encodings ['RGB int'].to (_tuple)).toString (16).slice (1);
925
+ }
926
+ /*?
927
+ Color Encodings
928
+ hex
929
+ A six digit, three digit, or one digit hexadecimal string (eg. the color chartreuse is encoded as ='7fff00'=).
930
+
931
+ Encoding
932
+ When a color is encoded as =hex=, the hexadecimal number always contains six digits and is all lowercase.
933
+
934
+ ...........................
935
+ << table >>
936
+
937
+ title: EXAMPLES
938
+ data
939
+ :| COLOR NAME | hex |
940
+ :| fuchsia | ff00ff |
941
+ :| yellow | ffff00 |
942
+ :| blue | 0000ff |
943
+ :| white | ffffff |
944
+ ...........................
945
+
946
+ Decoding
947
+ When a color is decoded from =hex=, the hexadecimal number may be specified using only one digit, three digits, or six digits, the "#" (pound) character is optional, and the digits may be in upper, lower, or mixed case (ie. *not* case sensitive).
948
+
949
+ .................................................................................
950
+ << table >>
951
+
952
+ title: WHITE
953
+ data
954
+ :| lowercase | UPPERCASE | #lowercase | #UPPERCASE | MiXeD | #MiXeD |
955
+ :| ffffff | FFFFFF | #ffffff | #FFFFFF | FfFfFf | #FfFfFf |
956
+ :| fff | FFF | #fff | #FFF | FfF | #FfF |
957
+ :| f | F | #f | #F | | |
958
+ .................................................................................
959
+ */
960
+ },
961
+ '#hex':{
962
+ colorSpace:'sRGB',
963
+ from:_setTupleFromRgbHex,
964
+ to:function (_tuple) {return '#' + _encodings ['hex'].to (_tuple)}
965
+ /*?
966
+ Color Encodings
967
+ #hex
968
+ A six digit, three digit, or one digit hexadecimal string, with a "#" (pound) character prefixed (eg. the color chartreuse is encoded as ='#7fff00'=).
969
+
970
+ Encoding
971
+ When a color is encoded as =#hex=, the hexadecimal number always contains six digits, is all lowercase, and is prefixed with a "#" (pound) character.
972
+
973
+ ............................
974
+ << table >>
975
+
976
+ title: EXAMPLES
977
+ data
978
+ :| COLOR NAME | #hex |
979
+ :| fuchsia | #ff00ff |
980
+ :| yellow | #ffff00 |
981
+ :| blue | #0000ff |
982
+ :| white | #ffffff |
983
+ ............................
984
+
985
+ Decoding
986
+ When a color is decoded from =#hex=, the hexadecimal number may be specified using only one digit, three digits, or six digits, the "#" (pound) character is optional, and the digits may be in upper, lower, or mixed case (ie. *not* case sensitive).
987
+
988
+ .................................................................................
989
+ << table >>
990
+
991
+ title: WHITE
992
+ data
993
+ :| lowercase | UPPERCASE | #lowercase | #UPPERCASE | MiXeD | #MiXeD |
994
+ :| ffffff | FFFFFF | #ffffff | #FFFFFF | FfFfFf | #FfFfFf |
995
+ :| fff | FFF | #fff | #FFF | FfF | #FfF |
996
+ :| f | F | #f | #F | | |
997
+ .................................................................................
998
+ */
999
+ },
1000
+ name:{
1001
+ colorSpace:'sRGB',
1002
+ from:function (_colorName,_tuple) {
1003
+ _encodings ['RGB int'].from (
1004
+ _colorName in _colors ? _colors [_colorName] : _colors [_colorName.toLowerCase ()],
1005
+ _tuple
1006
+ );
1007
+ },
1008
+ to:function (_tuple) {
1009
+ if (!_colorNamesLookup) {
1010
+ _colorNamesLookup = {};
1011
+ _updateColorNamesLookup (_colors);
1012
+ }
1013
+ return _colorNamesLookup [_encodings ['RGB int'].to (_tuple)] || _encodings ['hex'].to (_tuple);
1014
+ }
1015
+ /*?
1016
+ Color Encodings
1017
+ name
1018
+ A string, representing the name for a color (eg. the color chartreuse is encoded as ='chartreuse'=).
1019
+
1020
+ Encoding
1021
+ When a color is encoded as =name=, the name string is all lowercase. If no named color is defined that matches the color being encoded, then the encoding source will be encoded as =hex= as a fallback.
1022
+
1023
+ ............................
1024
+ << table >>
1025
+
1026
+ title: EXAMPLES
1027
+ data
1028
+ :| COLOR NAME | name |
1029
+ :| fuchsia | fuchsia |
1030
+ :| yellow | yellow |
1031
+ :| blue | blue |
1032
+ :| white | white |
1033
+ ............................
1034
+
1035
+ Decoding
1036
+ When a color is decoded from =name=, the name may be in upper, lower, or mixed case (ie. *not* case sensitive). If no named color is defined by the name specified, then the color will be decoded as black (in the =sRGB= color space).
1037
+
1038
+ EXAMPLES
1039
+ .......
1040
+ fuchsia
1041
+ YELLOW
1042
+ Blue
1043
+ whITE
1044
+ .......
1045
+
1046
+ NOTES
1047
+ - for a list of all the color names supported by the =Uize.Color= module, see the section `Named Colors`
1048
+ - further named colors may be defined using the =Uize.Color.defineColors= static method (see the section `Defining New Named Colors`)
1049
+ - over a hundred additional named colors - as defined in the SVG 1.0 and CSS 3 specifications - are defined in the =Uize.Color.xSvgColors= extension module
1050
+ */
1051
+ },
1052
+ 'RGB array':{
1053
+ colorSpace:'sRGB',
1054
+ from:_setTupleFromArray,
1055
+ to:_cloneTuple
1056
+ /*?
1057
+ Color Encodings
1058
+ RGB array
1059
+ An array, containing three elements for the red, green, and blue channels of an =sRGB= color, whose values are integers (eg. the color chartreuse is encoded as =[127,255,0]=).
1060
+
1061
+ Encoding
1062
+ When a color is encoded as =RGB array=, the resulting array is made up of three number type elements that represent the values of the source color's red, green, and blue channels, respectively.
1063
+
1064
+ ..................................
1065
+ << table >>
1066
+
1067
+ title: EXAMPLES
1068
+ data
1069
+ :| COLOR NAME | RGB array |
1070
+ :| fuchsia | [255,0,255] |
1071
+ :| yellow | [255,255,0] |
1072
+ :| blue | [0,0,255] |
1073
+ :| white | [255,255,255] |
1074
+ ..................................
1075
+
1076
+ Decoding
1077
+ When a color is decoded from =RGB array=, the values of the array's three elements may be numbers, strings, or any object that implements a =valueOf interface= (such as an instance of a =Uize.Class= subclass that implements the =value= state property).
1078
+
1079
+ EXAMPLES
1080
+ ..................................
1081
+ [255,0,255] // fuchsia
1082
+ [255.5,0.23,254.7] // fuchsia
1083
+ ['255','0','255'] // fuchsia
1084
+ [redSlider,greenSlider,blueSlider]
1085
+ ..................................
1086
+
1087
+ NOTES
1088
+ - the values of the color components will be coerced to number type by invoking the =valueOf Intrinsic Method=
1089
+ */
1090
+ },
1091
+ 'RGB int':{
1092
+ colorSpace:'sRGB',
1093
+ from:function (_rgbInt,_tuple) {
1094
+ _rgbInt = Uize.constrain (Math.round (_rgbInt),0,16777215);
1095
+ _setTuple (_tuple,(_rgbInt >> 16) & 255,(_rgbInt >> 8) & 255,_rgbInt & 255);
1096
+ },
1097
+ to:function (_tuple) {
1098
+ return (_byte (_tuple [0]) << 16) + (_byte (_tuple [1]) << 8) + _byte (_tuple [2]);
1099
+ }
1100
+ /*?
1101
+ Color Encodings
1102
+ RGB int
1103
+ An integer in the range of =0= to =16777215=, corresponding in value to the hexadecimal RGB representation of a color (eg. the color chartreuse is encoded as =8388352=, which is equivalent to the hex number representation =0x7fff00=).
1104
+
1105
+ Encoding
1106
+ When a color is encoded as =RGB int=, it is calculated as =red &#42; 65536 + green &#42; 255 + blue=.
1107
+
1108
+ .............................
1109
+ << table >>
1110
+
1111
+ title: EXAMPLES
1112
+ data
1113
+ :| COLOR NAME | RGB int |
1114
+ :| fuchsia | 16711935 |
1115
+ :| yellow | 16776960 |
1116
+ :| blue | 255 |
1117
+ :| white | 16777215 |
1118
+ .............................
1119
+
1120
+ Decoding
1121
+ When a color is decoded from =RGB int=, the value is first rounded and then constrained to the range of =0= to =16777215=.
1122
+
1123
+ EXAMPLES
1124
+ .....................
1125
+ 16711935 // fuchsia
1126
+ 0xff00ff // fuchsia
1127
+ .....................
1128
+
1129
+ *TIP:* When specifying colors as =RGB int=, you can use JavaScript's facility for specifying numbers in hexadecimal format using the "0x" prefix. This way, you're specifying an integer that looks exactly like a =hex= or =#hex= encoded RGB color value, but with the benefit of not using a more costly (in terms of performance) string.
1130
+ */
1131
+ },
1132
+ 'RGB object':{
1133
+ colorSpace:'sRGB',
1134
+ from:function (_rgbObject,_tuple) {
1135
+ _setTuple (_tuple,_rgbObject.red,_rgbObject.green,_rgbObject.blue);
1136
+ },
1137
+ to:function (_tuple) {return {red:_tuple [0],green:_tuple [1],blue:_tuple [2]}}
1138
+ /*?
1139
+ Color Encodings
1140
+ RGB object
1141
+ An object, containing =red=, =green=, and =blue= properties for the three =sRGB= channels, whose values are integers (eg. the color chartreuse is encoded as ={red:127,green:255,blue:0}=).
1142
+
1143
+ Encoding
1144
+ When a color is encoded as =RGB object=, the resulting object will contain the three number type properties =red=, =green=, and =blue=, reflecting the values of the source color's red, green, and blue channels.
1145
+
1146
+ .................................................
1147
+ << table >>
1148
+
1149
+ title: EXAMPLES
1150
+ data
1151
+ :| COLOR NAME | RGB object |
1152
+ :| fuchsia | {red:255,green:0,blue:255} |
1153
+ :| yellow | {red:255,green:255,blue:0} |
1154
+ :| blue | {red:0,green:0,blue:255} |
1155
+ :| white | {red:255,green:255,blue:255} |
1156
+ .................................................
1157
+
1158
+ Decoding
1159
+ When a color is decoded from =RGB object=, the values of the object's =red=, =green=, and =blue= properties may be numbers, strings, or any object that implements a =valueOf interface= interface (such as an instance of a =Uize.Class= subclass that implements the =value= state property).
1160
+
1161
+ EXAMPLES
1162
+ .................................................
1163
+ {red:255,green:0,blue:255} // fuchsia
1164
+ {red:255.5,green:0.23,blue:254.7} // fuchsia
1165
+ {red:'255',green:'0',blue:'255'} // fuchsia
1166
+ {red:redSlider,green:greenSlider,blue:blueSlider}
1167
+ .................................................
1168
+
1169
+ NOTES
1170
+ - the values of the color components will be coerced to number type by invoking the =valueOf Intrinsic Method=
1171
+ - the property names of the source =RGB object= must be all lowercase
1172
+ */
1173
+ },
1174
+ 'RGB string':{
1175
+ colorSpace:'sRGB',
1176
+ from:_setTupleFromString,
1177
+ to:function (_tuple) {
1178
+ return 'rgb(' + _byte (_tuple [0]) + ',' + _byte (_tuple [1]) + ',' + _byte (_tuple [2]) +')';
1179
+ }
1180
+ /*?
1181
+ Color Encodings
1182
+ RGB string
1183
+ An =Rgb(...)= formatted CSS color style property value (eg. the color chartreuse is encoded as ='rgb(127,255,0)'=)
1184
+
1185
+ Encoding
1186
+ When a color is encoded as =RGB string=, the resulting string will always be all lowercase, without any spaces, and the values of the red, green, and blue components will be rounded and constrained to the range of =0= to =255=.
1187
+
1188
+ .....................................
1189
+ << table >>
1190
+
1191
+ title: EXAMPLES
1192
+ data
1193
+ :| COLOR NAME | RGB string |
1194
+ :| fuchsia | rgb(255,0,255) |
1195
+ :| yellow | rgb(255,255,0) |
1196
+ :| blue | rgb(0,0,255) |
1197
+ :| white | rgb(255,255,255) |
1198
+ .....................................
1199
+
1200
+ Decoding
1201
+ When a color is decoded from =RGB string=, the string may contain separating spaces, and may be in upper, lower, or mixed case (ie. *not* case sensitive).
1202
+
1203
+ FUCHSIA
1204
+ .....................
1205
+ rgb(255,0,255)
1206
+ RGB(255,0,255)
1207
+ Rgb (255, 0, 255)
1208
+ RGB ( 255 , 0 , 255 )
1209
+ .....................
1210
+ */
1211
+ },
1212
+ 'HSL array':{
1213
+ colorSpace:'HSL',
1214
+ from:_setTupleFromArray,
1215
+ to:_cloneTuple
1216
+ /*?
1217
+ Color Encodings
1218
+ HSL array
1219
+ An array, containing three elements for hue, saturation, and lightness, whose values may be floating point numbers (eg. the color chartreuse is encoded as =[90.11764705882354,100,50]=), and that specifies a color in the =HSL= color space.
1220
+
1221
+ Encoding
1222
+ When a color is encoded as =HSL array=, the resulting array is made up of three number type elements that represent the values of the source color's hue, saturation, and lightness, respectively.
1223
+
1224
+ .................................
1225
+ << table >>
1226
+
1227
+ title: EXAMPLES
1228
+ data
1229
+ :| COLOR NAME | HSL array |
1230
+ :| fuchsia | [300,100,50] |
1231
+ :| yellow | [60,100,50] |
1232
+ :| blue | [240,100,50] |
1233
+ :| white | [0,0,100] |
1234
+ .................................
1235
+
1236
+ Decoding
1237
+ When a color is decoded from =HSL array=, the values of the array's three elements may be numbers, strings, or any object that implements a =valueOf interface= interface (such as an instance of a =Uize.Class= subclass that implements the =value= state property).
1238
+
1239
+ EXAMPLES
1240
+ ............................................
1241
+ [300,100,50] // fuchsia
1242
+ ['300','100','50'] // fuchsia
1243
+ [hueSlider,saturationSlider,lightnessSlider]
1244
+ ............................................
1245
+
1246
+ NOTES
1247
+ - the values of the color components will be coerced to number type by invoking the =valueOf Intrinsic Method=
1248
+ - string values for the saturation and lightness components in the array *may not* contain a "%" (percent) suffix
1249
+ */
1250
+ },
1251
+ 'HSL object':{
1252
+ colorSpace:'HSL',
1253
+ from:function (_hslObject,_tuple) {
1254
+ _setTuple (_tuple,_hslObject.hue,_hslObject.saturation,_hslObject.lightness);
1255
+ },
1256
+ to:function (_tuple) {return {hue:_tuple [0],saturation:_tuple [1],lightness:_tuple [2]}}
1257
+ /*?
1258
+ Color Encodings
1259
+ HSL object
1260
+ An object, containing =hue=, =saturation=, and =lightness= properties, whose values may be floating point numbers (eg. the color chartreuse is encoded as ={hue:90.11764705882354,saturation:100,lightness:50}=), and that specifies a color in the =HSL= color space.
1261
+
1262
+ Encoding
1263
+ When a color is encoded as =HSL object=, the resulting object will contain the three number type properties =hue=, =saturation=, and =lightness=, reflecting the values of the source color's hue, saturation, and lightness.
1264
+
1265
+ ..........................................................
1266
+ << table >>
1267
+
1268
+ title: EXAMPLES
1269
+ data
1270
+ :| COLOR NAME | HSL object |
1271
+ :| fuchsia | {hue:300,saturation:100,lightness:50} |
1272
+ :| yellow | {hue:60,saturation:100,lightness:50} |
1273
+ :| blue | {hue:240,saturation:100,lightness:50} |
1274
+ :| white | {hue:0,saturation:0,lightness:100} |
1275
+ ..........................................................
1276
+
1277
+ Decoding
1278
+ When a color is decoded from =HSL object=, the values of the object's =hue=, =saturation=, and =lightness= properties may be numbers, strings, or any object that implements a =valueOf interface= interface (such as an instance of a =Uize.Class= subclass that implements the =value= state property).
1279
+
1280
+ EXAMPLES
1281
+ .....................................................................
1282
+ {hue:300,saturation:100,lightness:50} // fuchsia
1283
+ {hue:'300',saturation:'100',lightness:'50'} // fuchsia
1284
+ {hue:hueSlider,saturation:saturationSlider,lightness:lightnessSlider}
1285
+ .....................................................................
1286
+
1287
+ NOTES
1288
+ - the values of the color components will be coerced to number type by invoking the =valueOf Intrinsic Method=
1289
+ - string values for the saturation and lightness components in the array *may not* contain a "%" (percent) suffix
1290
+ - the property names of the source =RGB object= must be all lowercase
1291
+ */
1292
+ },
1293
+ 'HSL string':{
1294
+ colorSpace:'HSL',
1295
+ from:_setTupleFromString,
1296
+ to:function (_tuple) {
1297
+ function _percentStr (_percent) {return Uize.constrain (Math.round (_percent),0,100) + '%'}
1298
+ return (
1299
+ 'hsl(' +
1300
+ Math.round (_tuple [0]) + ',' +
1301
+ _percentStr (_tuple [1]) + ',' +
1302
+ _percentStr (_tuple [2]) +
1303
+ ')'
1304
+ );
1305
+ }
1306
+ /*?
1307
+ Color Encodings
1308
+ HSL string
1309
+ An =Hsl(...)= formatted CSS color style property value (eg. the color chartreuse is encoded as ='hsl(90,100%,50%)'=) that specifies a color in the =HSL= color space.
1310
+
1311
+ Encoding
1312
+ When a color is encoded as =HSL string=, the resulting string will always be all lowercase, without any spaces.
1313
+
1314
+ Furthermore, the values for hue, saturation, and lightness will be rounded to the nearest integer, and a "%" (percent symbol) character will be appended to the values for saturation and lightness.
1315
+
1316
+ ......................................
1317
+ << table >>
1318
+
1319
+ title: EXAMPLES
1320
+ data
1321
+ :| COLOR NAME | HSL string |
1322
+ :| fuchsia | hsl(300,100%,50%) |
1323
+ :| yellow | hsl(60,100%,50%) |
1324
+ :| blue | hsl(240,100%,50%) |
1325
+ :| white | hsl(0,0%,100%) |
1326
+ ......................................
1327
+
1328
+ NOTES
1329
+ - because encoding as =HSL string= rounds the values for hue, saturation, and lightness, colors encoded as =HSL string= may not produce exactly the same original color when decoding the encoded =HSL string=
1330
+
1331
+ Decoding
1332
+ When a color is decoded from =HSL string=, the string may contain separating spaces, may be in upper, lower, or mixed case (ie. *not* case sensitive), and the "%" (percent symbol) character for the saturation and lightness values may be omitted.
1333
+
1334
+ FUCHSIA
1335
+ ........................
1336
+ hsl(300,100,50)
1337
+ hsl(300,100%,50%)
1338
+ HSL(300,100%,50%)
1339
+ Hsl (300, 100%, 50%)
1340
+ HSL ( 300 , 100% , 50% )
1341
+ Hsl ( 300 , 100 , 50 )
1342
+ ........................
1343
+ */
1344
+ }
1345
+ /*?
1346
+ Color Encodings
1347
+ Defining New Color Encodings
1348
+ You can extend the =Uize.Color.encodings= object in order to define new color encodings.
1349
+
1350
+ This can be done quite easily by setting a new property on the =Uize.Color.encodings= object, as follows...
1351
+
1352
+ EXAMPLE
1353
+ ..................................................................
1354
+ Uize.Color.encodings ['RGB float array'] = {
1355
+ colorSpace:'sRGB',
1356
+ from:function (_colorValue,_tuple) {
1357
+ _tuple [0] = _colorValue [0] * 255;
1358
+ _tuple [1] = _colorValue [1] * 255;
1359
+ _tuple [2] = _colorValue [2] * 255;
1360
+ },
1361
+ to:function (_tuple) {
1362
+ return [_tuple [0] / 255,_tuple [1] / 255,_tuple [2] / 255];
1363
+ }
1364
+ }
1365
+ ..................................................................
1366
+
1367
+ The above example defines an encoding named "RGB float aray", where the three elements of the array represent the values of the red, green, and blue channels as floating point numbers in the range of =0= to =1=. So, whereas the statement =Uize.Color.to ('purple','RGB array')= would produce the result =[128,0,128]=, the statement =Uize.Color.to ('purple','RGB float array')= would produce the result =[0.5019607843137255,0,0.5019607843137255]=. Conversely, the statement =Uize.Color.to ({'RGB float array':[.5,0,.5]},'name')= would produce the result ='purple'=.
1368
+
1369
+ The object that describes a color encoding is called a color encoding profile, and should have the following properties...
1370
+
1371
+ - =colorSpace= - This is the name of the color space that is associated with the encoding, and should be one of the `Color Spaces` defined in the =Uize.Color.colorSpaces= static property.
1372
+
1373
+ - =from (decoder function)= - This is a function that should set the values of the elements of the provided tuple array, based upon the provided color value. The function should expect two parameters: 1) the color value, and 2) the tuple. The function should decode (ie. process or parse) the color value as needed in order to set the appropriate values for the components of the color in the provided tuple array. The function does not need to return anything, and anything it returns will be ignored.
1374
+
1375
+ - =to (encoder function)= - This is a function that should use the values for the components of the color in the provided tuple array, and encode them as needed in order to produce a color value. The encoded color value should then be returned by the function.
1376
+ */
1377
+ };
1378
+
1379
+ /*** Colors ***/
1380
+ var _colors = _object.colors = {
1381
+ white: 16777215, // 0xffffff
1382
+ silver: 12632256, // 0xc0c0c0
1383
+ gray: 8421504, // 0x808080
1384
+ black: 0, // 0x000000
1385
+ navy: 128, // 0x000080
1386
+ blue: 255, // 0x0000ff
1387
+ aqua: 65535, // 0x00ffff
1388
+ teal: 32896, // 0x008080
1389
+ green: 32768, // 0x008000
1390
+ olive: 8421376, // 0x808000
1391
+ lime: 65280, // 0x00ff00
1392
+ maroon: 8388608, // 0x800000
1393
+ red: 16711680, // 0xff0000
1394
+ orange: 16753920, // 0xffa500
1395
+ yellow: 16776960, // 0xffff00
1396
+ purple: 8388736, // 0x800080
1397
+ fuchsia: 16711935 // 0xff00ff
1398
+ /*?
1399
+ Static Properties
1400
+ Uize.Color.colors
1401
+ An object, containing presets for the standard color names supported in the CSS 2.1 specification.
1402
+
1403
+ Named colors defined in the =Uize.Color.colors= object can be used wherever color values can be specified in the methods of the =Uize.Color= object, and other modules that use this object for resolving color values.
1404
+
1405
+ EXAMPLE
1406
+ .....................................................................
1407
+ Uize.Color ('yellow'); // source encoding is name
1408
+ Uize.Color (Uize.Color.colors.yellow); // source encoding is RGB int
1409
+ .....................................................................
1410
+
1411
+ In the above example, each of the statements would create a new instance of the =Uize.Color= object initialized to primary yellow. In the first statement, the color yellow is specified using the =name= encoding. In the second statement, however, the color is specified using the =RGB int= encoding. That's because the values of the properties of the =Uize.Color.colors= static property are actually integers representing the RGB values of the colors.
1412
+
1413
+ For more information, see the section `Named Colors`. You can also define your own named colors by extending the =Uize.Color.colors= static property. For more information, see the section `Defining New Named Colors`.
1414
+
1415
+ NOTES
1416
+ - see the related =Uize.Color.defineColors= static method
1417
+ - over a hundred additional named colors - as defined in the SVG 1.0 and CSS 3 specifications - are defined in the =Uize.Color.xSvgColors= extension module
1418
+
1419
+ Named Colors
1420
+ The =Uize.Color= object defines a set of seventeen standard named colors (as defined in the [[http://www.w3.org/TR/CSS21/syndata.html#value-def-color][CSS 2.1 color specification]]) in the =Uize.Color.colors= object.
1421
+
1422
+ .............................
1423
+ << table >>
1424
+
1425
+ title: NAMED COLORS
1426
+ data
1427
+ :| COLOR NAME | HEX VALUE |
1428
+ :| white | #ffffff |
1429
+ :| silver | #c0c0c0 |
1430
+ :| gray | #808080 |
1431
+ :| black | #000000 |
1432
+ :| navy | #000080 |
1433
+ :| blue | #0000ff |
1434
+ :| aqua | #00ffff |
1435
+ :| teal | #008080 |
1436
+ :| green | #008000 |
1437
+ :| olive | #808000 |
1438
+ :| lime | #00ff00 |
1439
+ :| maroon | #800000 |
1440
+ :| red | #ff0000 |
1441
+ :| orange | #ffa500 |
1442
+ :| yellow | #ffff00 |
1443
+ :| purple | #800080 |
1444
+ :| fuchsia | #ff00ff |
1445
+ .............................
1446
+
1447
+ Using Named Colors
1448
+ Named colors defined in the =Uize.Color.colors= object can be used wherever color values can be specified in the methods of the =Uize.Color= object, and other modules that use this object for resolving color values.
1449
+
1450
+ EXAMPLE 1
1451
+ .....................................
1452
+ var myColor = Uize.Color ('fuchsia');
1453
+ .....................................
1454
+
1455
+ In the above example, the =Uize.Color= instance =myColor= is being initialized to the color "fuchsia" (=#ff00ff=).
1456
+
1457
+ EXAMPLE 2
1458
+ ......................................................
1459
+ var fuchsiaAsHexStr = Uize.Color.to ('fuchsia','hex');
1460
+ ......................................................
1461
+
1462
+ In the above example, the color "fuchsia" is being converted to a hexadecimal string using the =hex= encoding.
1463
+
1464
+ EXAMPLE 3
1465
+ ..............................................................................
1466
+ Uize.Fx.fadeStyle ('myNodeId',{borderColor:'purple'},{borderColor:'fuchsia'});
1467
+ ..............................................................................
1468
+
1469
+ Because the =Uize.Color= module is used by other modules, such as the =Uize.Fx= module, it is also possible to use color names when specifying the values of color CSS style properties for fade effects.
1470
+
1471
+ Additional Named Colors
1472
+ Additional named colors are made available through extension modules, such as the =Uize.Color.xSvgColors= module that defines the SVG 1.0 / CSS 3 named colors.
1473
+
1474
+ Over a hundred additional named colors - as defined in the SVG 1.0 and CSS 3 specifications - are defined in the =Uize.Color.xSvgColors= extension module. Implementing further named colors in extension modules avoids burdening the core code with having to support less frequently used color sets. This also allows applications built on the UIZE JavaScript Framework to be better optimized for code size.
1475
+
1476
+ Defining New Named Colors
1477
+ You can extend the =Uize.Color.colors= object using the =Uize.Color.defineColors= static method in order to add your own named colors, which will then be accessible to code that uses the =Uize.Color= module.
1478
+
1479
+ EXAMPLE
1480
+ .............................................................................
1481
+ Uize.Color.defineColors ({darkmagenta:0x8b008b,lavenderblush:0xfff0f5});
1482
+ Uize.Fx.fadeStyle ('myNodeId',{color:'darkmagenta'},{color:'lavenderblush'});
1483
+ .............................................................................
1484
+
1485
+ When extending the =Uize.Color.colors= object, the names of added colors should be in all lowecase, and the values should be specified in the =RGB int= encoding (you can use JavaScript's hexadecimal notation for convenience, so that the =RGB int= encoding resembles the =hex= or =#hex= encodings).
1486
+
1487
+ INCORRECT
1488
+ .................................................................................
1489
+ Uize.Color.defineColors ({DarkMagenta:0x8b008b}); // DON'T USE MIXED CASE
1490
+ Uize.Color.defineColors ({lavenderblush:'#fff0f5'}); // DON'T USE OTHER ENCODING
1491
+ .................................................................................
1492
+
1493
+ CORRECT
1494
+ ......................................................................................
1495
+ Uize.Color.defineColors ({darkmagenta:0x8b008b}); // OK TO USE HEX FORMATTED NUMBER
1496
+ Uize.Color.defineColors ({lavenderblush:16773365}); // OK TO USE DECIMAL NUMBER
1497
+ ......................................................................................
1498
+
1499
+ NOTES
1500
+ - see the related =Uize.Color.colors= static property
1501
+ - see the related =Uize.Color.defineColors= static method
1502
+ - over a hundred additional named colors - as defined in the SVG 1.0 and CSS 3 specifications - are defined in the =Uize.Color.xSvgColors= extension module
1503
+ */
1504
+ };
1505
+
1506
+ /*** dummy color objects for mixing and conversion ***/
1507
+ var
1508
+ _dummyColor1 = new _object,
1509
+ _dummyColor2 = new _object
1510
+ ;
1511
+
1512
+ return _object;
1513
+ }
1514
+ });
1515
+
skin/frontend/default/customproduct/js/Uize.Color.xCmyk.js ADDED
@@ -0,0 +1,237 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ /*______________
2
+ | ______ | U I Z E J A V A S C R I P T F R A M E W O R K
3
+ | / / | ---------------------------------------------------
4
+ | / O / | MODULE : Uize.Color.xCmyk Object Extension
5
+ | / / / |
6
+ | / / / /| | ONLINE : http://www.uize.com
7
+ | /____/ /__/_| | COPYRIGHT : (c)2011-2012 UIZE
8
+ | /___ | LICENSE : Available under MIT License or GNU General Public License
9
+ |_______________| http://www.uize.com/license.html
10
+ */
11
+
12
+ /* Module Meta Data
13
+ type: Extension
14
+ importance: 1
15
+ codeCompleteness: 10
16
+ testCompleteness: 0
17
+ docCompleteness: 100
18
+ */
19
+
20
+ /*?
21
+ Introduction
22
+ The =Uize.Color.xCmyk= module extends the =Uize.Color= object by adding a profile for the =CMYK= color space, and by providing encodings for this color space.
23
+
24
+ *DEVELOPERS:* `Chris van Rensburg`
25
+
26
+ The =Uize.Color.colorSpaces.CMYK= property - defined in this extension - provides a profile for the [[http://en.wikipedia.org/wiki/Cmyk][CMYK]] (Cyan, Magenta, Yellow, Key) color space. The CMYK color model is a subtractive color model used to describe the printing process. Some examples of CMYK formatted colors can be viewed at [[http://www.december.com/html/spec/colorcmyk.html]].
27
+
28
+ Color Encodings
29
+ The =Uize.Color.xCmyk= extension implements support for the following color encodings / formats...
30
+ */
31
+
32
+ Uize.module ({
33
+ name:'Uize.Color.xCmyk',
34
+ builder:function (_Uize_Color) {
35
+ var _sRgbColorSpace = _Uize_Color.colorSpaces.sRGB;
36
+
37
+ /*** Color Profile ***/
38
+ _Uize_Color.colorSpaces.CMYK = {
39
+ fromHsl:function (_tuple) {
40
+ // HSL to RGB first, then RGB to CMYK
41
+ _tuple = _sRgbColorSpace.fromHsl (_tuple);
42
+ var
43
+ _red = _tuple [0] / 255,
44
+ _green = _tuple [1] / 255,
45
+ _blue = _tuple [2] / 255,
46
+ _key = Math.min (1 - _red,1 - _green,1 - _blue),
47
+ _1minusKey = 1 - _key
48
+ ;
49
+ return [
50
+ _1minusKey && ((_1minusKey - _red) / _1minusKey * 100),
51
+ _1minusKey && ((_1minusKey - _green) / _1minusKey * 100),
52
+ _1minusKey && ((_1minusKey - _blue) / _1minusKey * 100),
53
+ _key * 100
54
+ ];
55
+ },
56
+ toHsl:function (_tuple) {
57
+ // CMYK to RGB first, then RGB to HSL
58
+ var
59
+ _key = _tuple [3] / 100,
60
+ _1minusKey = 1 - _key
61
+ ;
62
+ return _sRgbColorSpace.toHsl ([
63
+ (1 - Math.min (1,_tuple [0] / 100 * _1minusKey + _key)) * 255,
64
+ (1 - Math.min (1,_tuple [1] / 100 * _1minusKey + _key)) * 255,
65
+ (1 - Math.min (1,_tuple [2] / 100 * _1minusKey + _key)) * 255
66
+ ]);
67
+ }
68
+ };
69
+
70
+ /*** Color Encodings ***/
71
+ Uize.copyInto (
72
+ _Uize_Color.encodings,
73
+ {
74
+ 'CMYK array':{
75
+ colorSpace:'CMYK',
76
+ from:_Uize_Color.setTupleFromArray,
77
+ to:_Uize_Color.cloneTuple
78
+ /*?
79
+ Color Encodings
80
+ CMYK array
81
+ An array, containing four elements for cyan, magenta, yellow, and key components of the color, whose values may be floating point numbers in the range of =0= to =100= (eg. the color chartreuse is encoded as =[50,0,100,0]=).
82
+
83
+ SYNTAX
84
+ ..........................................................................
85
+ [ cyan0to100FLOAT, magenta0to100FLOAT, yellow0to100FLOAT, key0to100FLOAT ]
86
+ ..........................................................................
87
+
88
+ Encoding
89
+ When a color is encoded as =CMYK array=, the resulting array is made up of four number type elements that represent the values of the source color's cyan, magenta, yellow, and key components, respectively.
90
+
91
+ ...............................
92
+ << table >>
93
+
94
+ title: EXAMPLES
95
+ data
96
+ :| COLOR NAME | CMYK array |
97
+ :| fuchsia | [0,100,0,0] |
98
+ :| yellow | [0,0,100,0] |
99
+ :| blue | [100,100,0,0] |
100
+ :| white | [0,0,0,0] |
101
+ ...............................
102
+
103
+ Decoding
104
+ When a color is decoded from =CMYK array=, the values of the array's four elements may be numbers, strings, or any object that implements a =valueOf= interface (such as an instance of a =Uize.Class= subclass that implements the =value= state property).
105
+
106
+ The values will be coerced to number type by invoking the =valueOf Intrinsic Method=.
107
+
108
+ EXAMPLES
109
+ .................................................
110
+ [0,100,0,0] // fuchsia
111
+ ['0','100','0','0'] // fuchsia
112
+ [cyanSlider,magentaSlider,yellowSlider,keySlider]
113
+ .................................................
114
+
115
+ NOTES
116
+ - string values for the elements of the array *may not* contain a "%" (percent) suffix
117
+ */
118
+ },
119
+ 'CMYK object':{
120
+ colorSpace:'CMYK',
121
+ from:function (_cmykObject,_tuple) {
122
+ _Uize_Color.setTuple (
123
+ _tuple,_cmykObject.cyan,_cmykObject.magenta,_cmykObject.yellow,_cmykObject.key
124
+ );
125
+ },
126
+ to:function (_tuple) {return {cyan:_tuple [0],magenta:_tuple [1],yellow:_tuple [2],key:_tuple [3]}}
127
+ /*?
128
+ Color Encodings
129
+ CMYK object
130
+ An object, containing =cyan=, =magenta=, =yellow=, and =key= properties, whose values may be floating point numbers in the range of =0= to =100= (eg. the color chartreuse is encoded as ={cyan:50,magenta:0,yellow:100,key:0}=).
131
+
132
+ SYNTAX
133
+ ................................
134
+ {
135
+ cyan : cyan0to100FLOAT,
136
+ magenta : magenta0to100FLOAT,
137
+ yellow : yellow0to100FLOAT,
138
+ key : key0to100FLOAT
139
+ }
140
+ ................................
141
+
142
+ Encoding
143
+ When a color is encoded as =CMYK object=, the resulting object will contain the four number type properties =cyan=, =magenta=, =yellow=, and =key=, reflecting the values of the source color's cyan, magenta, yellow, and key components, respectively.
144
+
145
+ .......................................................
146
+ << table >>
147
+
148
+ title: EXAMPLES
149
+ data
150
+ :| COLOR NAME | CMYK object |
151
+ :| fuchsia | {cyan:0,magenta:100,yellow:0,key:0} |
152
+ :| yellow | {cyan:0,magenta:0,yellow:100,key:0} |
153
+ :| blue | {cyan:100,magenta:100,yellow:0,key:0} |
154
+ :| white | {cyan:0,magenta:0,yellow:0,key:0} |
155
+ .......................................................
156
+
157
+ Decoding
158
+ When a color is decoded from =CMYK object=, the values of the object's =cyan=, =magenta=, =yellow=, and =key= properties may be numbers, strings, or any object that implements a =valueOf= interface (such as an instance of a =Uize.Class= subclass that implements the =value= state property).
159
+
160
+ The values will be coerced to number type by invoking the =valueOf Intrinsic Method=.
161
+
162
+ EXAMPLES
163
+ .........................................................................
164
+ {cyan:0,magenta:100,yellow:0,key:0} // fuchsia
165
+ {cyan:'0',magenta:'100',yellow:'0',key:'0'} // fuchsia
166
+ {cyan:cyanSlider,magenta:magentaSlider,yellow:yellowSlider,key:keySlider}
167
+ .........................................................................
168
+
169
+ NOTES
170
+ - string values for the properties of the object *may not* contain a "%" (percent) suffix
171
+ */
172
+ },
173
+ 'CMYK string':{
174
+ colorSpace:'CMYK',
175
+ from:_Uize_Color.setTupleFromString,
176
+ to:function (_tuple) {
177
+ function _roundAndConstrainComponent (_componentNo) {
178
+ return Uize.constrain (Math.round (_tuple [_componentNo]),0,100);
179
+ }
180
+ return (
181
+ 'cmyk(' +
182
+ _roundAndConstrainComponent (0) + '%,' +
183
+ _roundAndConstrainComponent (1) + '%,' +
184
+ _roundAndConstrainComponent (2) + '%,' +
185
+ _roundAndConstrainComponent (3) + '%' +
186
+ ')'
187
+ );
188
+ }
189
+ /*?
190
+ Color Encodings
191
+ CMYK string
192
+ A =Cmyk(...)= formatted 4-tuple string (eg. the color chartreuse is encoded as ='cmyk(50%,0%,100%,0%)'=).
193
+
194
+ SYNTAX
195
+ .................................................................
196
+ cmyk([cyan0to100]%,[magenta0to100]%,[yellow0to100]%,[key0to100]%)
197
+ .................................................................
198
+
199
+ Encoding
200
+ When a color is encoded as =CMYK string=, the resulting string will always be all lowercase, without any spaces.
201
+
202
+ Furthermore, the values for cyan, magenta, yellow, and key components of the tuple will be rounded to the nearest integer and constrained to a range of =0= to =100=, with a "%" (percent symbol) character appended to each.
203
+
204
+ .......................................
205
+ << table >>
206
+
207
+ title: EXAMPLES
208
+ data
209
+ :| COLOR NAME | CMYK string |
210
+ :| fuchsia | cmyk(0%,100%,0%,0%) |
211
+ :| yellow | cmyk(0%,0%,100%,0%) |
212
+ :| blue | cmyk(100%,100%,0%,0%) |
213
+ :| white | cmyk(0%,0%,0%,0%) |
214
+ .......................................
215
+
216
+ NOTES
217
+ - because encoding as =CMYK string= rounds the values for all four components of a color, colors encoded as =CMYK string= may not produce exactly the same original color when decoding the encoded =CMYK string=
218
+
219
+ Decoding
220
+ When a color is decoded from =CMYK string=, the string may contain separating spaces, may be in upper, lower, or mixed case (ie. *not* case sensitive), and the "%" (percent symbol) character for the saturation and value values may be omitted.
221
+
222
+ FUCHSIA
223
+ ............................
224
+ cmyk(0,100,0,0)
225
+ cmyk(0%,100%,0%,0%)
226
+ CMYK(0%,100%,0%,0%)
227
+ Cmyk (0%, 100%, 0%, 0%)
228
+ CMYK ( 0% , 100% , 0% , 0% )
229
+ Cmyk ( 0 , 100 , 0 , 0 )
230
+ ............................
231
+ */
232
+ }
233
+ }
234
+ );
235
+ }
236
+ });
237
+
skin/frontend/default/customproduct/js/Uize.Color.xHsv.js ADDED
@@ -0,0 +1,223 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ /*______________
2
+ | ______ | U I Z E J A V A S C R I P T F R A M E W O R K
3
+ | / / | ---------------------------------------------------
4
+ | / O / | MODULE : Uize.Color.xHsv Object Extension
5
+ | / / / |
6
+ | / / / /| | ONLINE : http://www.uize.com
7
+ | /____/ /__/_| | COPYRIGHT : (c)2009-2012 UIZE
8
+ | /___ | LICENSE : Available under MIT License or GNU General Public License
9
+ |_______________| http://www.uize.com/license.html
10
+ */
11
+
12
+ /* Module Meta Data
13
+ type: Extension
14
+ importance: 3
15
+ codeCompleteness: 100
16
+ testCompleteness: 0
17
+ docCompleteness: 100
18
+ */
19
+
20
+ /*?
21
+ Introduction
22
+ The =Uize.Color.xHsv= module extends the =Uize.Color= object by adding a profile for the =HSV= color space, and by providing encodings for this color space.
23
+
24
+ *DEVELOPERS:* `Chris van Rensburg`
25
+
26
+ The =Uize.Color.colorSpaces.HSV= property - defined in this extension - provides a profile for the [[http://en.wikipedia.org/wiki/HSL_color_space][HSV]] (Hue, Saturation, Value) color space. The HSV color space is essentially an alternate representation / mapping of the =sRGB= color space, but might be considered to be a more intuitive representation of the qualities of color.
27
+
28
+ Color Encodings
29
+ The =Uize.Color.xHsv= extension implements support for the following color encodings / formats...
30
+ */
31
+
32
+ Uize.module ({
33
+ name:'Uize.Color.xHsv',
34
+ builder:function (_Uize_Color) {
35
+ /*** Color Profile ***/
36
+ _Uize_Color.colorSpaces.HSV = {
37
+ fromHsl:function (_tuple) {
38
+ // http://en.wikipedia.org/wiki/HSL_color_space
39
+ var
40
+ _lightness = _tuple [2] / 100,
41
+ _maxMinLevelDelta = _tuple [1] / 50 * (_lightness < .5 ? _lightness : 1 - _lightness),
42
+ _maxLevel = _lightness + _maxMinLevelDelta / 2
43
+ ;
44
+ return [_tuple [0],_maxLevel ? _maxMinLevelDelta / _maxLevel * 100 : 0,_maxLevel * 100];
45
+ },
46
+ toHsl:function (_tuple) {
47
+ // http://en.wikipedia.org/wiki/HSL_color_space
48
+ var
49
+ _maxLevel = _tuple [2] / 100,
50
+ _minLevel = _maxLevel * (1 - _tuple [1] / 100),
51
+ _maxMinLevelDelta = _maxLevel - _minLevel,
52
+ _lightness = (_maxLevel + _minLevel) / 2
53
+ ;
54
+ return [
55
+ _tuple [0],
56
+ _maxMinLevelDelta
57
+ ? 50 * _maxMinLevelDelta / (_lightness < .5 ? _lightness : (1 - _lightness))
58
+ : 0,
59
+ _lightness * 100
60
+ ];
61
+ }
62
+ };
63
+
64
+ /*** Color Encodings ***/
65
+ Uize.copyInto (
66
+ _Uize_Color.encodings,
67
+ {
68
+ 'HSV array':{
69
+ colorSpace:'HSV',
70
+ from:_Uize_Color.setTupleFromArray,
71
+ to:_Uize_Color.cloneTuple
72
+ /*?
73
+ Color Encodings
74
+ HSV array
75
+ An array, containing three elements for hue, saturation, and value components of the color, whose values may be floating point numbers (eg. the color chartreuse is encoded as =[90,100,100]=).
76
+
77
+ SYNTAX
78
+ ...........................................................
79
+ [ hue0to360FLOAT, saturation0to100FLOAT, value0to100FLOAT ]
80
+ ...........................................................
81
+
82
+ Encoding
83
+ When a color is encoded as =HSV array=, the resulting array is made up of three number type elements that represent the values of the source color's hue, saturation, and value components, respectively.
84
+
85
+ ...............................
86
+ << table >>
87
+
88
+ title: EXAMPLES
89
+ data
90
+ :| COLOR NAME | HSV array |
91
+ :| fuchsia | [300,100,100] |
92
+ :| yellow | [60,100,100] |
93
+ :| blue | [240,100,100] |
94
+ :| white | [0,0,100] |
95
+ ...............................
96
+
97
+ Decoding
98
+ When a color is decoded from =HSV array=, the values of the array's three elements may be numbers, strings, or any object that implements a =valueOf= interface (such as an instance of a =Uize.Class= subclass that implements the =value= state property).
99
+
100
+ The values will be coerced to number type by invoking the =valueOf Intrinsic Method=.
101
+
102
+ EXAMPLES
103
+ ........................................
104
+ [300,100,100] // fuchsia
105
+ ['300','100','100'] // fuchsia
106
+ [hueSlider,saturationSlider,valueSlider]
107
+ ........................................
108
+
109
+ NOTES
110
+ - string values for the saturation and value components in the array *may not* contain a "%" (percent) suffix
111
+ */
112
+ },
113
+ 'HSV object':{
114
+ colorSpace:'HSV',
115
+ from:function (_hsvObject,_tuple) {
116
+ _Uize_Color.setTuple (_tuple,_hsvObject.hue,_hsvObject.saturation,_hsvObject.value);
117
+ },
118
+ to:function (_tuple) {return {hue:_tuple [0],saturation:_tuple [1],value:_tuple [2]}}
119
+ /*?
120
+ Color Encodings
121
+ HSV object
122
+ An object, containing =hue=, =saturation=, and =value= properties, whose values may be floating point numbers (eg. the color chartreuse is encoded as ={hue:90,saturation:100,value:100}=).
123
+
124
+ SYNTAX
125
+ ................................................................................
126
+ { hue:hue0to360FLOAT, saturation:saturation0to100FLOAT, value:value0to100FLOAT }
127
+ ................................................................................
128
+
129
+ Encoding
130
+ When a color is encoded as =HSV object=, the resulting object will contain the three number type properties =hue=, =saturation=, and =value=, reflecting the values of the source color's hue, saturation, and value.
131
+
132
+ ....................................................
133
+ << table >>
134
+
135
+ title: EXAMPLES
136
+ data
137
+ :| COLOR NAME | HSV object |
138
+ :| fuchsia | {hue:300,saturation:100,value:100} |
139
+ :| yellow | {hue:60,saturation:100,value:100} |
140
+ :| blue | {hue:240,saturation:100,value:100} |
141
+ :| white | {hue:0,saturation:0,value:100} |
142
+ ....................................................
143
+
144
+ Decoding
145
+ When a color is decoded from =HSV object=, the values of the object's =hue=, =saturation=, and =value= properties may be numbers, strings, or any object that implements a =valueOf= interface (such as an instance of a =Uize.Class= subclass that implements the =value= state property).
146
+
147
+ The values will be coerced to number type by invoking the =valueOf Intrinsic Method=.
148
+
149
+ EXAMPLES
150
+ .............................................................
151
+ {hue:300,saturation:100,value:100} // fuchsia
152
+ {hue:'300',saturation:'100',value:'100'} // fuchsia
153
+ {hue:hueSlider,saturation:saturationSlider,value:valueSlider}
154
+ .............................................................
155
+
156
+ NOTES
157
+ - string values for the =saturation= and =value= properties of the object *may not* contain a "%" (percent) suffix
158
+ */
159
+ },
160
+ 'HSV string':{
161
+ colorSpace:'HSV',
162
+ from:_Uize_Color.setTupleFromString,
163
+ to:function (_tuple) {
164
+ function _roundAndConstrainComponent (_componentNo,_minValue,_maxValue) {
165
+ return Uize.constrain (Math.round (_tuple [_componentNo]),_minValue,_maxValue);
166
+ }
167
+ return (
168
+ 'hsv(' +
169
+ _roundAndConstrainComponent (0,0,360) + ',' +
170
+ _roundAndConstrainComponent (1,0,100) + '%,' +
171
+ _roundAndConstrainComponent (2,0,100) + '%' +
172
+ ')'
173
+ );
174
+ }
175
+ /*?
176
+ Color Encodings
177
+ HSV string
178
+ An =Hsv(...)= formatted 3-tuple string (eg. the color chartreuse is encoded as ='hsv(90,100%,100%)'=).
179
+
180
+ SYNTAX
181
+ ...................................................
182
+ hsv([hue0to360],[saturation0to100]%,[value0to100]%)
183
+ ...................................................
184
+
185
+ Encoding
186
+ When a color is encoded as =HSV string=, the resulting string will always be all lowercase, without any spaces.
187
+
188
+ Furthermore, the values for hue, saturation, and value will be rounded to the nearest integer, the value for hue will be constrained to the range of =0= to =360=, and the values for saturation and value will be constrained to a range of =0= to =100= and a "%" (percent symbol) character will be appended to each.
189
+
190
+ .....................................
191
+ << table >>
192
+
193
+ title: EXAMPLES
194
+ data
195
+ :| COLOR NAME | HSV string |
196
+ :| fuchsia | hsv(300,100%,100%) |
197
+ :| yellow | hsv(60,100%,100%) |
198
+ :| blue | hsv(240,100%,100%) |
199
+ :| white | hsv(0,0%,100%) |
200
+ .....................................
201
+
202
+ NOTES
203
+ - because encoding as =HSV string= rounds the values for hue, saturation, and value, colors encoded as =HSV string= may not produce exactly the same original color when decoding the encoded =HSV string=
204
+
205
+ Decoding
206
+ When a color is decoded from =HSV string=, the string may contain separating spaces, may be in upper, lower, or mixed case (ie. *not* case sensitive), and the "%" (percent symbol) character for the saturation and value values may be omitted.
207
+
208
+ FUCHSIA
209
+ .........................
210
+ hsv(300,100,100)
211
+ hsv(300,100%,100%)
212
+ HSV(300,100%,100%)
213
+ Hsv (300, 100%, 100%)
214
+ HSV ( 300 , 100% , 100% )
215
+ Hsv ( 300 , 100 , 100 )
216
+ .........................
217
+ */
218
+ }
219
+ }
220
+ );
221
+ }
222
+ });
223
+
skin/frontend/default/customproduct/js/Uize.Color.xSvgColors.js ADDED
@@ -0,0 +1,324 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ /*______________
2
+ | ______ | U I Z E J A V A S C R I P T F R A M E W O R K
3
+ | / / | ---------------------------------------------------
4
+ | / O / | MODULE : Uize.Color.xSvgColors Object Extension
5
+ | / / / |
6
+ | / / / /| | ONLINE : http://www.uize.com
7
+ | /____/ /__/_| | COPYRIGHT : (c)2009-2012 UIZE
8
+ | /___ | LICENSE : Available under MIT License or GNU General Public License
9
+ |_______________| http://www.uize.com/license.html
10
+ */
11
+
12
+ /* Module Meta Data
13
+ type: Extension
14
+ importance: 2
15
+ codeCompleteness: 100
16
+ testCompleteness: 0
17
+ docCompleteness: 100
18
+ */
19
+
20
+ /*?
21
+ Introduction
22
+ The =Uize.Color.xSvgColors= extension module extends the =Uize.Color= object by adding SVG 1.0 / CSS 3 color definitions to the =Uize.Color.colors= object.
23
+
24
+ *DEVELOPERS:* `Chris van Rensburg`
25
+
26
+ Using the Colors
27
+ When you extend the =Uize.Color= object using the =Uize.Color.xSvgColors= extension module, it will then be possible to use the names of the colors defined in this extension when creating instances of the =Uize.Color= object, or when setting the color of =Uize.Color= instances using the =from= instance method.
28
+
29
+ EXAMPLE
30
+ ..............................................
31
+ Uize.Color ('#ffebcd');
32
+ Uize.Color ('BlanchedAlmond');
33
+ Uize.Color (Uize.Color.colors.blanchedalmond);
34
+ ..............................................
35
+
36
+ Each of the above three statements would create a new instance of the =Uize.Color= object initialized to the SVG color "BlanchedAlmond". And because the =Uize.Color= module is used by other modules, such as the =Uize.Fx= module, it is possible to use color names when specifying the values of color CSS style properties for fade effects, as in...
37
+
38
+ .............................................................................
39
+ Uize.Fx.fadeStyle ('myNodeId',{color:'DarkMagenta'},{color:'LavenderBlush'});
40
+ .............................................................................
41
+ */
42
+
43
+ Uize.module ({
44
+ name:'Uize.Color.xSvgColors',
45
+ builder:function (_Uize_Color) {
46
+ _Uize_Color.defineColors ({
47
+ aliceblue: 15792383, // 0xf0f8ff
48
+ antiquewhite: 16444375, // 0xfaebd7
49
+ aquamarine: 8388564, // 0x7fffd4
50
+ azure: 15794175, // 0xf0ffff
51
+ beige: 16119260, // 0xf5f5dc
52
+ bisque: 16770244, // 0xffe4c4
53
+ blanchedalmond: 16772045, // 0xffebcd
54
+ blueviolet: 9055202, // 0x8a2be2
55
+ brown: 10824234, // 0xa52a2a
56
+ burlywood: 14596231, // 0xdeb887
57
+ cadetblue: 6266528, // 0x5f9ea0
58
+ chartreuse: 8388352, // 0x7fff00
59
+ chocolate: 13789470, // 0xd2691e
60
+ coral: 16744272, // 0xff7f50
61
+ cornflowerblue: 6591981, // 0x6495ed
62
+ cornsilk: 16775388, // 0xfff8dc
63
+ crimson: 14423100, // 0xdc143c
64
+ cyan: 65535, // 0x00ffff
65
+ darkblue: 139, // 0x00008b
66
+ darkcyan: 35723, // 0x008b8b
67
+ darkgoldenrod: 12092939, // 0xb8860b
68
+ darkgray: 11119017, // 0xa9a9a9
69
+ darkgreen: 25600, // 0x006400
70
+ darkgrey: 11119017, // 0xa9a9a9
71
+ darkkhaki: 12433259, // 0xbdb76b
72
+ darkmagenta: 9109643, // 0x8b008b
73
+ darkolivegreen: 5597999, // 0x556b2f
74
+ darkorange: 16747520, // 0xff8c00
75
+ darkorchid: 10040012, // 0x9932cc
76
+ darkred: 9109504, // 0x8b0000
77
+ darksalmon: 15308410, // 0xe9967a
78
+ darkseagreen: 9419919, // 0x8fbc8f
79
+ darkslateblue: 4734347, // 0x483d8b
80
+ darkslategray: 3100495, // 0x2f4f4f
81
+ darkslategrey: 3100495, // 0x2f4f4f
82
+ darkturquoise: 52945, // 0x00ced1
83
+ darkviolet: 9699539, // 0x9400d3
84
+ deeppink: 16716947, // 0xff1493
85
+ deepskyblue: 49151, // 0x00bfff
86
+ dimgray: 6908265, // 0x696969
87
+ dimgrey: 6908265, // 0x696969
88
+ dodgerblue: 2003199, // 0x1e90ff
89
+ firebrick: 11674146, // 0xb22222
90
+ floralwhite: 16775920, // 0xfffaf0
91
+ forestgreen: 2263842, // 0x228b22
92
+ gainsboro: 14474460, // 0xdcdcdc
93
+ ghostwhite: 16316671, // 0xf8f8ff
94
+ gold: 16766720, // 0xffd700
95
+ goldenrod: 14329120, // 0xdaa520
96
+ greenyellow: 11403055, // 0xadff2f
97
+ grey: 8421504, // 0x808080
98
+ honeydew: 15794160, // 0xf0fff0
99
+ hotpink: 16738740, // 0xff69b4
100
+ indianred: 13458524, // 0xcd5c5c
101
+ indigo: 4915330, // 0x4b0082
102
+ ivory: 16777200, // 0xfffff0
103
+ khaki: 15787660, // 0xf0e68c
104
+ lavender: 15132410, // 0xe6e6fa
105
+ lavenderblush: 16773365, // 0xfff0f5
106
+ lawngreen: 8190976, // 0x7cfc00
107
+ lemonchiffon: 16775885, // 0xfffacd
108
+ lightblue: 11393254, // 0xadd8e6
109
+ lightcoral: 15761536, // 0xf08080
110
+ lightcyan: 14745599, // 0xe0ffff
111
+ lightgoldenrodyellow: 16448210, // 0xfafad2
112
+ lightgray: 13882323, // 0xd3d3d3
113
+ lightgreen: 9498256, // 0x90ee90
114
+ lightgrey: 13882323, // 0xd3d3d3
115
+ lightpink: 16758465, // 0xffb6c1
116
+ lightsalmon: 16752762, // 0xffa07a
117
+ lightseagreen: 2142890, // 0x20b2aa
118
+ lightskyblue: 8900346, // 0x87cefa
119
+ lightslategray: 7833753, // 0x778899
120
+ lightslategrey: 7833753, // 0x778899
121
+ lightsteelblue: 11584734, // 0xb0c4de
122
+ lightyellow: 16777184, // 0xffffe0
123
+ limegreen: 3329330, // 0x32cd32
124
+ linen: 16445670, // 0xfaf0e6
125
+ magenta: 16711935, // 0xff00ff
126
+ mediumaquamarine: 6737322, // 0x66cdaa
127
+ mediumblue: 205, // 0x0000cd
128
+ mediumorchid: 12211667, // 0xba55d3
129
+ mediumpurple: 9662683, // 0x9370db
130
+ mediumseagreen: 3978097, // 0x3cb371
131
+ mediumslateblue: 8087790, // 0x7b68ee
132
+ mediumspringgreen: 64154, // 0x00fa9a
133
+ mediumturquoise: 4772300, // 0x48d1cc
134
+ mediumvioletred: 13047173, // 0xc71585
135
+ midnightblue: 1644912, // 0x191970
136
+ mintcream: 16121850, // 0xf5fffa
137
+ mistyrose: 16770273, // 0xffe4e1
138
+ moccasin: 16770229, // 0xffe4b5
139
+ navajowhite: 16768685, // 0xffdead
140
+ oldlace: 16643558, // 0xfdf5e6
141
+ olivedrab: 7048739, // 0x6b8e23
142
+ orangered: 16729344, // 0xff4500
143
+ orchid: 14315734, // 0xda70d6
144
+ palegoldenrod: 15657130, // 0xeee8aa
145
+ palegreen: 10025880, // 0x98fb98
146
+ paleturquoise: 11529966, // 0xafeeee
147
+ palevioletred: 14381203, // 0xdb7093
148
+ papayawhip: 16773077, // 0xffefd5
149
+ peachpuff: 16767673, // 0xffdab9
150
+ peru: 13468991, // 0xcd853f
151
+ pink: 16761035, // 0xffc0cb
152
+ plum: 14524637, // 0xdda0dd
153
+ powderblue: 11591910, // 0xb0e0e6
154
+ rosybrown: 12357519, // 0xbc8f8f
155
+ royalblue: 4286945, // 0x4169e1
156
+ saddlebrown: 9127187, // 0x8b4513
157
+ salmon: 16416882, // 0xfa8072
158
+ sandybrown: 16032864, // 0xf4a460
159
+ seagreen: 3050327, // 0x2e8b57
160
+ seashell: 16774638, // 0xfff5ee
161
+ sienna: 10506797, // 0xa0522d
162
+ skyblue: 8900331, // 0x87ceeb
163
+ slateblue: 6970061, // 0x6a5acd
164
+ slategray: 7372944, // 0x708090
165
+ slategrey: 7372944, // 0x708090
166
+ snow: 16775930, // 0xfffafa
167
+ springgreen: 65407, // 0x00ff7f
168
+ steelblue: 4620980, // 0x4682b4
169
+ tan: 13808780, // 0xd2b48c
170
+ thistle: 14204888, // 0xd8bfd8
171
+ tomato: 16737095, // 0xff6347
172
+ turquoise: 4251856, // 0x40e0d0
173
+ violet: 15631086, // 0xee82ee
174
+ wheat: 16113331, // 0xf5deb3
175
+ whitesmoke: 16119285, // 0xf5f5f5
176
+ yellowgreen: 10145074 // 0x9acd32
177
+ });
178
+ /*?
179
+ The SVG 1.0 Colors
180
+ The =Uize.Color.xSvgColors= module defines over a hundred additional colors, as listed in the table below.
181
+
182
+ This is in addition to the seventeen standard CSS 2.1 colors defined in the =Uize.Color= module, which are =white=, =silver=, =gray=, =black=, =navy=, =blue=, =aqua=, =teal=, =green=, =olive=, =lime=, =maroon=, =red=, =orange=, =yellow=, =purple=, and =fuchsia=.
183
+
184
+ .........................................
185
+ << table >>
186
+
187
+ title: SVG 1.0 COLORS
188
+ data
189
+ :| COLOR NAME | HEX VALUE |
190
+ :| aliceblue | #f0f8ff |
191
+ :| antiquewhite | #faebd7 |
192
+ :| aquamarine | #7fffd4 |
193
+ :| azure | #f0ffff |
194
+ :| beige | #f5f5dc |
195
+ :| bisque | #ffe4c4 |
196
+ :| blanchedalmond | #ffebcd |
197
+ :| blueviolet | #8a2be2 |
198
+ :| brown | #a52a2a |
199
+ :| burlywood | #deb887 |
200
+ :| cadetblue | #5f9ea0 |
201
+ :| chartreuse | #7fff00 |
202
+ :| chocolate | #d2691e |
203
+ :| coral | #ff7f50 |
204
+ :| cornflowerblue | #6495ed |
205
+ :| cornsilk | #fff8dc |
206
+ :| crimson | #dc143c |
207
+ :| cyan | #00ffff |
208
+ :| darkblue | #00008b |
209
+ :| darkcyan | #008b8b |
210
+ :| darkgoldenrod | #b8860b |
211
+ :| darkgray | #a9a9a9 |
212
+ :| darkgreen | #006400 |
213
+ :| darkgrey | #a9a9a9 |
214
+ :| darkkhaki | #bdb76b |
215
+ :| darkmagenta | #8b008b |
216
+ :| darkolivegreen | #556b2f |
217
+ :| darkorange | #ff8c00 |
218
+ :| darkorchid | #9932cc |
219
+ :| darkred | #8b0000 |
220
+ :| darksalmon | #e9967a |
221
+ :| darkseagreen | #8fbc8f |
222
+ :| darkslateblue | #483d8b |
223
+ :| darkslategray | #2f4f4f |
224
+ :| darkslategrey | #2f4f4f |
225
+ :| darkturquoise | #00ced1 |
226
+ :| darkviolet | #9400d3 |
227
+ :| deeppink | #ff1493 |
228
+ :| deepskyblue | #00bfff |
229
+ :| dimgray | #696969 |
230
+ :| dimgrey | #696969 |
231
+ :| dodgerblue | #1e90ff |
232
+ :| firebrick | #b22222 |
233
+ :| floralwhite | #fffaf0 |
234
+ :| forestgreen | #228b22 |
235
+ :| gainsboro | #dcdcdc |
236
+ :| ghostwhite | #f8f8ff |
237
+ :| gold | #ffd700 |
238
+ :| goldenrod | #daa520 |
239
+ :| greenyellow | #adff2f |
240
+ :| grey | #808080 |
241
+ :| honeydew | #f0fff0 |
242
+ :| hotpink | #ff69b4 |
243
+ :| indianred | #cd5c5c |
244
+ :| indigo | #4b0082 |
245
+ :| ivory | #fffff0 |
246
+ :| khaki | #f0e68c |
247
+ :| lavender | #e6e6fa |
248
+ :| lavenderblush | #fff0f5 |
249
+ :| lawngreen | #7cfc00 |
250
+ :| lemonchiffon | #fffacd |
251
+ :| lightblue | #add8e6 |
252
+ :| lightcoral | #f08080 |
253
+ :| lightcyan | #e0ffff |
254
+ :| lightgoldenrodyellow | #fafad2 |
255
+ :| lightgray | #d3d3d3 |
256
+ :| lightgreen | #90ee90 |
257
+ :| lightgrey | #d3d3d3 |
258
+ :| lightpink | #ffb6c1 |
259
+ :| lightsalmon | #ffa07a |
260
+ :| lightseagreen | #20b2aa |
261
+ :| lightskyblue | #87cefa |
262
+ :| lightslategray | #778899 |
263
+ :| lightslategrey | #778899 |
264
+ :| lightsteelblue | #b0c4de |
265
+ :| lightyellow | #ffffe0 |
266
+ :| limegreen | #32cd32 |
267
+ :| linen | #faf0e6 |
268
+ :| magenta | #ff00ff |
269
+ :| mediumaquamarine | #66cdaa |
270
+ :| mediumblue | #0000cd |
271
+ :| mediumorchid | #ba55d3 |
272
+ :| mediumpurple | #9370db |
273
+ :| mediumseagreen | #3cb371 |
274
+ :| mediumslateblue | #7b68ee |
275
+ :| mediumspringgreen | #00fa9a |
276
+ :| mediumturquoise | #48d1cc |
277
+ :| mediumvioletred | #c71585 |
278
+ :| midnightblue | #191970 |
279
+ :| mintcream | #f5fffa |
280
+ :| mistyrose | #ffe4e1 |
281
+ :| moccasin | #ffe4b5 |
282
+ :| navajowhite | #ffdead |
283
+ :| oldlace | #fdf5e6 |
284
+ :| olivedrab | #6b8e23 |
285
+ :| orangered | #ff4500 |
286
+ :| orchid | #da70d6 |
287
+ :| palegoldenrod | #eee8aa |
288
+ :| palegreen | #98fb98 |
289
+ :| paleturquoise | #afeeee |
290
+ :| palevioletred | #db7093 |
291
+ :| papayawhip | #ffefd5 |
292
+ :| peachpuff | #ffdab9 |
293
+ :| peru | #cd853f |
294
+ :| pink | #ffc0cb |
295
+ :| plum | #dda0dd |
296
+ :| powderblue | #b0e0e6 |
297
+ :| rosybrown | #bc8f8f |
298
+ :| royalblue | #4169e1 |
299
+ :| saddlebrown | #8b4513 |
300
+ :| salmon | #fa8072 |
301
+ :| sandybrown | #f4a460 |
302
+ :| seagreen | #2e8b57 |
303
+ :| seashell | #fff5ee |
304
+ :| sienna | #a0522d |
305
+ :| skyblue | #87ceeb |
306
+ :| slateblue | #6a5acd |
307
+ :| slategray | #708090 |
308
+ :| slategrey | #708090 |
309
+ :| snow | #fffafa |
310
+ :| springgreen | #00ff7f |
311
+ :| steelblue | #4682b4 |
312
+ :| tan | #d2b48c |
313
+ :| thistle | #d8bfd8 |
314
+ :| tomato | #ff6347 |
315
+ :| turquoise | #40e0d0 |
316
+ :| violet | #ee82ee |
317
+ :| wheat | #f5deb3 |
318
+ :| whitesmoke | #f5f5f5 |
319
+ :| yellowgreen | #9acd32 |
320
+ .........................................
321
+ */
322
+ }
323
+ });
324
+
skin/frontend/default/customproduct/js/Uize.Color.xUtil.js ADDED
@@ -0,0 +1,720 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ /*______________
2
+ | ______ | U I Z E J A V A S C R I P T F R A M E W O R K
3
+ | / / | ---------------------------------------------------
4
+ | / O / | MODULE : Uize.Color.xUtil Object Extension
5
+ | / / / |
6
+ | / / / /| | ONLINE : http://www.uize.com
7
+ | /____/ /__/_| | COPYRIGHT : (c)1997-2012 UIZE
8
+ | /___ | LICENSE : Available under MIT License or GNU General Public License
9
+ |_______________| http://www.uize.com/license.html
10
+ */
11
+
12
+ /* Module Meta Data
13
+ type: Extension
14
+ importance: 2
15
+ codeCompleteness: 90
16
+ testCompleteness: 0
17
+ docCompleteness: 100
18
+ */
19
+
20
+ /*?
21
+ Introduction
22
+ The =Uize.Color.xUtil= module is an extension module that extends the =Uize.Color= object by adding various instance and static utility methods.
23
+
24
+ *DEVELOPERS:* `Chris van Rensburg`
25
+ */
26
+
27
+ Uize.module ({
28
+ name:'Uize.Color.xUtil',
29
+ required:'Uize.Array.Sort',
30
+ builder:function (_object) {
31
+ /*** Variables for Scruncher Optimization ***/
32
+ var
33
+ _undefined,
34
+ _objectPrototype = _object.prototype
35
+ ;
36
+
37
+ /*** General Variables ***/
38
+ var
39
+ _dummyColor1 = new _object,
40
+ _dummyColor2 = new _object,
41
+ _sacredEmptyObject = {}
42
+ ;
43
+
44
+ /*** Utility Functions ***/
45
+ function _blendValues (_valueA,_valueB,_blendAmount) {
46
+ return _valueA + (_valueB - _valueA) * _blendAmount
47
+ }
48
+
49
+ function _ensureSettingIsTuple (_setting,_default) {
50
+ if (_setting == _undefined) _setting = _default;
51
+ return Uize.isArray (_setting) ? _setting : [_setting,_setting,_setting,_setting];
52
+ }
53
+
54
+ /*** Public Instance Methods ***/
55
+ _objectPrototype.blend = function (_color1,_color2,_blendAmount) {
56
+ _blendAmount = Uize.toNumber (_blendAmount,.5);
57
+ _dummyColor1.from (_color1);
58
+ _dummyColor2.from (_color2);
59
+ var
60
+ _dummyColor1Tuple = _dummyColor1.tuple,
61
+ _dummyColor2Tuple = _dummyColor2.getTuple (_dummyColor1.encoding)
62
+ ;
63
+ _object.setTuple (
64
+ this.tuple,
65
+ _blendValues (_dummyColor1Tuple [0],_dummyColor2Tuple [0],_blendAmount),
66
+ _blendValues (_dummyColor1Tuple [1],_dummyColor2Tuple [1],_blendAmount),
67
+ _blendValues (_dummyColor1Tuple [2],_dummyColor2Tuple [2],_blendAmount),
68
+ _blendValues (_dummyColor1Tuple [3],_dummyColor2Tuple [3],_blendAmount)
69
+ );
70
+
71
+ return this;
72
+ /*?
73
+ Instance Methods
74
+ blend
75
+ Blends between the two specified colors using the specified blend amount, and sets the current color of the instance to the new blended color.
76
+
77
+ SYNTAX
78
+ ...........................................................
79
+ colorOBJ.blend (color1ANYTYPE,color2ANYTYPE,blendFRACTION);
80
+ ...........................................................
81
+
82
+ The =blendFRACTION= parameter should be a floating point number in the range of =0= to =1=, where a value of =0= will result in =colorOBJ= being set to the color represented by the =color1ANYTYPE= parameter, the value =1= will result in =colorOBJ= being set to the color represented by the =color2ANYTYPE= parameter, and the value =.5= will result in =colorOBJ= being set to a color that is an equal blend of the colors represented by the =color1ANYTYPE= and =color2ANYTYPE= parameters.
83
+
84
+ Different values between =0= and =1= for the =blendFRACTION= parameter give you different blends between color one and color two...
85
+
86
+ EXAMPLES
87
+ ..............................................................................
88
+ // a range of blends between black and white
89
+
90
+ myColor.blend ('000000','ffffff',0); // myColor now #000000, encoding "hex"
91
+ myColor.blend ('000000','ffffff',.25); // myColor now #404040, encoding "hex"
92
+ myColor.blend ('000000','ffffff',.5); // myColor now #808080, encoding "hex"
93
+ myColor.blend ('000000','ffffff',.75); // myColor now #bfbfbf, encoding "hex"
94
+ myColor.blend ('000000','ffffff',1); // myColor now #ffffff, encoding "hex"
95
+ ..............................................................................
96
+
97
+ VARIATION
98
+ .............................................
99
+ colorOBJ.blend (color1ANYTYPE,color2ANYTYPE);
100
+ .............................................
101
+
102
+ When no =blendFRACTION= parameter is specified, the value for this parameter is defaulted to =.5=, producing an equal mix between =color1ANYTYPE= and =color2ANYTYPE=.
103
+
104
+ EXAMPLE
105
+ ................................................................................
106
+ myColor.blend ('black','white'); // myColor now #808080 (gray), encoding "name"
107
+ ................................................................................
108
+
109
+ Color one and color two - the source colors for the blending operation - can be specified using any of the many supported `Color Encodings`...
110
+
111
+ EXAMPLES
112
+ ....................................................................................
113
+ // equal blend of black and white, specified using different encodings
114
+
115
+ myColor.blend ('000000','ffffff'); // myColor now #808080, encoding "hex"
116
+ myColor.blend ('black','white'); // myColor now #808080, encoding "name"
117
+ myColor.blend (0x000000,0xffffff); // myColor now #808080, encoding "RGB int"
118
+ myColor.blend ([0,0,0],[255,255,255]); // myColor now #808080, encoding "RGB array"
119
+ myColor.blend ('#000','#fff'); // myColor now #808080, encoding "#hex"
120
+ myColor.blend ('#0','#f'); // myColor now #808080, encoding "#hex"
121
+ ....................................................................................
122
+
123
+ The `Color Encodings` for color one and color two do not have to be the same...
124
+
125
+ EXAMPLES
126
+ ..................................................................................
127
+ // equal blend of black and white, using mixed encodings for source colors
128
+
129
+ myColor.blend ('#000000',0xffffff); // myColor now #808080, encoding "#hex"
130
+ myColor.blend ('black','#fff'); // myColor now #808080, encoding "name"
131
+ myColor.blend ([0,0,0],'ffffff'); // myColor now #808080, encoding "RGB array"
132
+ ..................................................................................
133
+
134
+ To blend the instance's current color value with a different color, simply pass a reference to the color object instance as one of the colors to blend, as in...
135
+
136
+ EXAMPLE
137
+ ................................................................................
138
+ myColor.blend (myColor,'white',.1); // blend in some white to lighten the color
139
+ ................................................................................
140
+
141
+ NOTES
142
+ - see the related =Uize.Color.blend= static method
143
+ */
144
+ };
145
+
146
+ _objectPrototype.equal = function (_color) {
147
+ _dummyColor1.from (_color).setEncoding (this.encoding);
148
+ var
149
+ _tuple = this.tuple,
150
+ _dummyColor1Tuple = _dummyColor1.tuple
151
+ ;
152
+ return (
153
+ !Math.round (_tuple [0] - _dummyColor1Tuple [0]) &&
154
+ !Math.round (_tuple [1] - _dummyColor1Tuple [1]) &&
155
+ !Math.round (_tuple [2] - _dummyColor1Tuple [2]) &&
156
+ !Math.round (_tuple [3] - _dummyColor1Tuple [3])
157
+ );
158
+ /*?
159
+ Instance Methods
160
+ equal
161
+ Returns a boolean, indicating whether or not the specified color is equivalent to the color of the instance.
162
+
163
+ SYNTAX
164
+ ...........................................
165
+ isEqualBOOL = myColor.equal (colorANYTYPE);
166
+ ...........................................
167
+
168
+ EXAMPLES
169
+ ........................................................................
170
+ var fuchsia = Uize.Color ('fuchsia');
171
+ fuchsia.equal (Uize.Color ('fuchsia')); // produces true
172
+ fuchsia.equal ('ff00ff'); // produces true
173
+ fuchsia.equal ('#ff00ff'); // produces true
174
+ fuchsia.equal ('fuchsia'); // produces true
175
+ fuchsia.equal ([255,0,255]); // produces true
176
+ fuchsia.equal (16711935); // produces true
177
+ fuchsia.equal ({red:255,green:0,blue:255}); // produces true
178
+ fuchsia.equal ('rgb(255,0,255)'); // produces true
179
+ fuchsia.equal ({'HSL array':[300,100,50]}); // produces true
180
+ fuchsia.equal ({hue:300,saturation:100,lightness:50}); // produces true
181
+ fuchsia.equal ('hsl(300,100,50)'); // produces true
182
+ ........................................................................
183
+
184
+ In the above example, all the statements produce the result =true=. That's because all the colors that the =fuchsia= color object is being compared to are equivalent to the color "fuchsia" - regardless of the encoding used to specify them.
185
+
186
+ MORE EXAMPLES
187
+ ..................................................................................
188
+ Uize.Color.blend ('red','black',.5,'color').equal ('maroon'); // produces true
189
+ Uize.Color.mix (['black','red']).equal ('maroon'); // produces true
190
+ Uize.Color.mix (['rgb(0,0,0)','#f00']).equal ('hsl(0,100%,25%)'); // produces true
191
+ ..................................................................................
192
+
193
+ NOTES
194
+ - see the companion =Uize.Color.equal= static method
195
+ */
196
+ };
197
+
198
+ _objectPrototype.random = function () {
199
+ for (
200
+ var
201
+ _components = _object.colorSpaces [_object.encodings [this.encoding].colorSpace].tuple,
202
+ _componentNo = _components.length,
203
+ _tuple = this.tuple
204
+ ;
205
+ --_componentNo >= 0;
206
+ ) {
207
+ var
208
+ _component = _components [_componentNo],
209
+ _componentMin = _component.min
210
+ ;
211
+ _tuple [_componentNo] = _componentMin + Math.random () * (_component.max - _componentMin);
212
+ }
213
+ return this;
214
+ /*?
215
+ Instance Methods
216
+ random
217
+ Randomizes the color of the instance in the color space of the instance's current encoding.
218
+
219
+ SYNTAX
220
+ ..................
221
+ myColor.random ();
222
+ ..................
223
+
224
+ NOTES
225
+ - see the related =Uize.Color.random= static method
226
+ */
227
+ };
228
+
229
+ /*** Public Static Methods ***/
230
+ _object.blend = function (_color1,_color2,_blendAmount,_encoding) {
231
+ return _dummyColor1.blend (_color1,_color2,_blendAmount).to (_encoding || _dummyColor1.encoding);
232
+ /*?
233
+ Static Methods
234
+ Uize.Color.blend
235
+ Blends between the two specified colors using the specified blend amount, and returns the blended color encoded using the specified encoding.
236
+
237
+ SYNTAX
238
+ ............................................................................
239
+ colorANYTYPE = Uize.Color.blend (color1ANYTYPE,color2ANYTYPE,blendFRACTION);
240
+ ............................................................................
241
+
242
+ The =blendFRACTION= parameter should be a floating point number in the range of =0= to =1=, where a value of =0= will result in returning the color represented by the =color1ANYTYPE= parameter, the value =1= will result in returning the color represented by the =color2ANYTYPE= parameter, and the value =.5= will result in returning a color that is an equal blend of the colors represented by the =color1ANYTYPE= and =color2ANYTYPE= parameters.
243
+
244
+ Different values between =0= and =1= for the =blendFRACTION= parameter give you different blends between color one and color two...
245
+
246
+ EXAMPLES
247
+ ....................................................................
248
+ // a range of blends between black and white
249
+
250
+ Uize.Color.blend ('000000','ffffff',0); // returns '000000'
251
+ Uize.Color.blend ('000000','ffffff',.25); // returns '404040'
252
+ Uize.Color.blend ('000000','ffffff',.5); // returns '808080'
253
+ Uize.Color.blend ('000000','ffffff',.75); // returns 'bfbfbf'
254
+ Uize.Color.blend ('000000','ffffff',1); // returns 'ffffff'
255
+ ....................................................................
256
+
257
+ VARIATION 1
258
+ ........................................................................................
259
+ colorANYTYPE = Uize.Color.blend (color1ANYTYPE,color2ANYTYPE,blendFRACTION,encodingSTR);
260
+ ........................................................................................
261
+
262
+ The resulting blended color can be encoded in any of the many supported `Color Encodings`, by using the optional =encodingSTR= parameter, as follows...
263
+
264
+ EXAMPLES
265
+ ........................................................................
266
+ // equal blend of black and white, different encodings for the result
267
+
268
+ Uize.Color.blend ('black','white',.5,'color'); // new Uize.Color
269
+ Uize.Color.blend ('black','white',.5,'hex'); // 808080
270
+ Uize.Color.blend ('black','white',.5,'#hex'); // #808080
271
+ Uize.Color.blend ('black','white',.5,'name'); // gray
272
+ Uize.Color.blend ('black','white',.5,'RGB array'); // [128,128,128]
273
+ Uize.Color.blend ('black','white',.5,'RGB int'); // 8421504
274
+ Uize.Color.blend ('black','white',.5,'RGB string'); // rgb(128,128,128}
275
+ ........................................................................
276
+
277
+ VARIATION 2
278
+ .............................................................
279
+ colorHexSTR = Uize.Color.blend (color1ANYTYPE,color2ANYTYPE);
280
+ .............................................................
281
+
282
+ When no =blendFRACTION= or =encodingSTR= parameters are specified, then the colors specified by the =color1ANYTYPE= and =color2ANYTYPE= parameters will be blended equally and the resulting color will be encoded using the encoding of the first color, as specified by the =color1ANYTYPE= parameter.
283
+
284
+ EXAMPLE
285
+ .................................................................................
286
+ var myColorHex = Uize.Color.blend ('fuchsia','olive'); // myColorHex is 'c04080'
287
+ .................................................................................
288
+
289
+ Color one and color two - the source colors for the blending operation - can be specified using any of the many supported `Color Encodings`...
290
+
291
+ EXAMPLES
292
+ ...................................................................................
293
+ // equal blend of black and white, specified using different encodings
294
+
295
+ Uize.Color.blend ('000000','ffffff'); // returns '808080'
296
+ Uize.Color.blend ('black','white'); // returns 'gray'
297
+ Uize.Color.blend (0x000000,0xffffff); // returns 8421504
298
+ Uize.Color.blend ([0,0,0],[255,255,255]); // returns [127.5,127.5,127.5]
299
+ Uize.Color.blend ('#000','#fff'); // returns '#808080'
300
+ Uize.Color.blend ('#0','#f'); // returns '#808080'
301
+ Uize.Color.blend ('hsl(0,0%,0%)','hsl(0,0%,100%)'); // returns 'hsl(0,0%,50%)'
302
+ ...................................................................................
303
+
304
+ The `Color Encodings` for color one and color two do not have to be the same...
305
+
306
+ EXAMPLES
307
+ ..........................................................................
308
+ // equal blend of black and white, using mixed encodings for source colors
309
+
310
+ Uize.Color.blend ('#000000',0xffffff); // returns '#808080'
311
+ Uize.Color.blend ('black','#fff'); // returns 'gray'
312
+ Uize.Color.blend ([0,0,0],'ffffff'); // returns [127.5,127.5,127.5]
313
+ ..........................................................................
314
+
315
+ In the above example, notice how the encoding of the first color is used for encoding the result.
316
+
317
+ NOTES
318
+ - see the related =blend= instance method
319
+ */
320
+ };
321
+
322
+ _object.equal = function (_color1,_color2) {
323
+ return _dummyColor2.from (_color1).equal (_color2);
324
+ /*?
325
+ Static Methods
326
+ Uize.Color.equal
327
+ Returns a boolean, indicating whether or not the two specified colors are equivalent.
328
+
329
+ SYNTAX
330
+ ..............................................................
331
+ areEqualBOOL = Uize.Color.equal (color1ANYTYPE,color2ANYTYPE);
332
+ ..............................................................
333
+
334
+ EXAMPLES
335
+ ............................................................................
336
+ Uize.Color.equal ('fuchsia',Uize.Color ('fuchsia')); // true
337
+ Uize.Color.equal ('ff00ff','#ff00ff'); // true
338
+ Uize.Color.equal ([255,0,255],'hsl(300,100,50)'); // true
339
+ Uize.Color.equal (16711935,{red:255,green:0,blue:255}); // true
340
+ Uize.Color.equal ('rgb(255,0,255)',{'HSL array':[300,100,50]}); // true
341
+ Uize.Color.equal ('fuchsia',{hue:300,saturation:100,lightness:50}); // true
342
+ ............................................................................
343
+
344
+ In the above example, all the statements produce the result =true=. That's because all of the colors specified for the =color1ANYTYPE= and =color2ANYTYPE= parameters are equivalent to the color "fuchsia" - regardless of the encoding used to specify them.
345
+
346
+ MORE EXAMPLES
347
+ ...............................................................................
348
+ Uize.Color.equal (Uize.Color.blend ('red','black'),'maroon'); // produces true
349
+ Uize.Color.equal (Uize.Color.blend ('white','black'),'gray'); // produces true
350
+ Uize.Color.equal (Uize.Color.blend ('red','blue'),'purple'); // produces true
351
+ ...............................................................................
352
+
353
+ NOTES
354
+ - see the companion =equal= instance method
355
+ */
356
+ };
357
+
358
+ _object.makeCombinations = function (_color1,_color2,_valuesPerComponent,_componentChaos,_outputEncoding) {
359
+ /*** default and conform settings ***/
360
+ _valuesPerComponent = _ensureSettingIsTuple (_valuesPerComponent,2);
361
+ _componentChaos = _ensureSettingIsTuple (_componentChaos,0);
362
+ _outputEncoding = _outputEncoding || 'color';
363
+
364
+ _dummyColor1.from (_color1);
365
+ _dummyColor2.from (_color2);
366
+ var
367
+ _result = [],
368
+ _dummyColor1Tuple = _dummyColor1.tuple,
369
+ _dummyColor2Tuple = _dummyColor2.getTuple (_dummyColor1.encoding),
370
+ _component0Divisions = _valuesPerComponent [0],
371
+ _component1Divisions = _valuesPerComponent [1],
372
+ _component2Divisions = _valuesPerComponent [2],
373
+ _color = Uize.Color (_dummyColor1),
374
+ _colorTuple = _color.tuple
375
+ ;
376
+
377
+ function _blendComponent (_componentNo,_blendAmount) {
378
+ _colorTuple [_componentNo] = _blendValues (
379
+ _dummyColor1Tuple [_componentNo],
380
+ _dummyColor2Tuple [_componentNo],
381
+ _componentChaos [_componentNo]
382
+ ? _blendValues (_blendAmount,Math.random (),_componentChaos [_componentNo])
383
+ : _blendAmount
384
+ );
385
+ }
386
+ for (var _component0ValueNo = -1; ++_component0ValueNo < _component0Divisions;) {
387
+ for (var _component1ValueNo = -1; ++_component1ValueNo < _component1Divisions;) {
388
+ for (var _component2ValueNo = -1; ++_component2ValueNo < _component2Divisions;) {
389
+ _blendComponent (0,_component0ValueNo / (_component0Divisions - 1));
390
+ _blendComponent (1,_component1ValueNo / (_component1Divisions - 1));
391
+ _blendComponent (2,_component2ValueNo / (_component2Divisions - 1));
392
+ _result.push (_color.to (_outputEncoding));
393
+ }
394
+ }
395
+ }
396
+ return _result;
397
+ /*?
398
+ Static Methods
399
+ Uize.Color.makeCombinations
400
+ Returns an array of colors, being a series of combinations produced from the two specified colors.
401
+
402
+ SYNTAX
403
+ ...........................................
404
+ colorsARRAY = Uize.Color.makeCombinations (
405
+ color1ANYTYPE,
406
+ color2ANYTYPE,
407
+ valuesPerComponentINTorARRAY
408
+ );
409
+ ...........................................
410
+
411
+ This method uses the two colors specified by the =color1ANYTYPE= and =color2ANYTYPE= parameters to produce a series of combination colors. A series of interpolated values is calculated for each component of the color space, with the first value being the value of the component for color 1, the last value being the value of the component for color 2, and a series of values calculated at intervals between the first value and the last value. Each value out of the series of values for each component is then combined with each other value for every other component, so producing a set of combinations in the color space of color 1.
412
+
413
+ The number of values per color component is specified by the =valuesPerComponentINTorARRAY= parameter. If an integer value is specified for this parameter, then there will be the same number of interpolated values for all components of the color space. For example, a value of =3= for the =valuesPerComponentINTorARRAY= parameter means that there will be three values for each of the red, green, and blue channels of the =sRGB= color space, producing a total of =27= combinations.
414
+
415
+ An array of integers can also be specified for the =valuesPerComponentINTorARRAY= parameter, in which case a desired number of interpolated values can be specified for each component of the color space. So, for example, the value =[2,3,4]= would specify two interpolated values for the red channel, three for the green channel, and four for the blue channel in the =sRGB= color space, producing a total of =24= combination colors.
416
+
417
+ VARIATION 1
418
+ ........................................................................
419
+ colorsARRAY = Uize.Color.makeCombinations (color1ANYTYPE,color2ANYTYPE);
420
+ ........................................................................
421
+
422
+ When no =valuesPerComponentINTorARRAY= parameter is specified, then there will be a default of two values per component, producing eight combinations for a three component color space (such as =sRGB=, =HSL=, =HSV=, etc.). The two values that are used for each component will be the value of that component for color 1 and the value of that component for color 2.
423
+
424
+ VARIATION 2
425
+ ...........................................
426
+ colorsARRAY = Uize.Color.makeCombinations (
427
+ color1ANYTYPE,
428
+ color2ANYTYPE,
429
+ valuesPerComponentINTorARRAY,
430
+ componentChaosFLOATorARRAY
431
+ );
432
+ ...........................................
433
+
434
+ When the optional =componentChaosFLOATorARRAY= parameter is specified, a certain amount of chaos can be introduced to the calculation of component values when making the combination colors. The value for =componentChaosFLOATorARRAY= can be a floating point number in the range of =0= to =1=, specifying the amount of chaos to be applied to all components of the color space, or it can be an array of floating point numbers in the range of =0= to =1=, specifying the amount of chaos to be applied to specific components.
435
+
436
+ A value of =0= means there will be no chaos, and values for a component will be calculated at regular intervals between the value of that component for color 1 and the value of that component for color 2. A value of =1= means that the calculation of values for a component will be completely chaotic, and chosen at random points between the value of that component for color 1 and the value of that component for color 2. A value of =.5= means that there will be an equal blend between regular intervals and chaos. Any degree of chaos - between none and total - can be introduced into the calculation of combination colors.
437
+
438
+ VARIATION 3
439
+ ...........................................
440
+ colorsARRAY = Uize.Color.makeCombinations (
441
+ color1ANYTYPE,
442
+ color2ANYTYPE,
443
+ valuesPerComponentINTorARRAY,
444
+ componentChaosFLOATorARRAY,
445
+ outputEncodingSTR
446
+ );
447
+ ...........................................
448
+
449
+ By default, this method generates its combination colors as an array of =Uize.Color= object instances. However, the optional =outputEncodingSTR= parameter lets you control the encoding of the color values in the generated array. You can specify any encoding - even an encoding that is not of the same color space as the colors specified by the =color1ANYTYPE= and =color2ANYTYPE= parameters. The output encoding will not, however, affect the color space in which the combination colors are generated, and this is determined by the encoding of the =color1ANYTYPE= parameter.
450
+
451
+ EXAMPLE
452
+ .....................................................................
453
+ var webSafeColors = Uize.Color.makeCombinations ('0','f',6,0,'#hex');
454
+ .....................................................................
455
+
456
+ In the above example, the =webSafeColors= variable will be an array containing all the [[http://en.wikipedia.org/wiki/Web_colors][web safe colors]], encoded in =#hex= format. The =Uize.Color.makeCombinations= method makes it easy to generate the web safe colors because they are defined as the combination colors with distinct 6 values per channel: =00=, =33=, =66=, =99=, =cc=, and =ff=. Now, if you wanted an array of =Uize.Color= instances instead, you could just specify the value ='color'= for the =outputEncodingSTR= parameter, instead of ='#hex'=.
457
+ */
458
+ };
459
+
460
+ _object.mix = function (_colors,_encoding) {
461
+ var _colorsLength = _colors.length;
462
+ if (!_colorsLength) return new _object;
463
+ var
464
+ _component0Total = 0,
465
+ _component1Total = 0,
466
+ _component2Total = 0,
467
+ _component3Total = 0,
468
+ _primaryEncoding = _dummyColor1.from (_colors [0]).encoding
469
+ ;
470
+ for (var _colorNo = _colorsLength; --_colorNo >= 0;) {
471
+ var _dummyColor1Tuple = _dummyColor1.from (_colors [_colorNo]).getTuple (_primaryEncoding);
472
+ _component0Total += _dummyColor1Tuple [0];
473
+ _component1Total += _dummyColor1Tuple [1];
474
+ _component2Total += _dummyColor1Tuple [2];
475
+ _component3Total += _dummyColor1Tuple [3];
476
+ }
477
+ _colorsLength = _colorsLength || 1;
478
+ _object.setTuple (
479
+ _dummyColor1.tuple,
480
+ _component0Total / _colorsLength,
481
+ _component1Total / _colorsLength,
482
+ _component2Total / _colorsLength,
483
+ _component3Total / _colorsLength
484
+ );
485
+ return _dummyColor1.to (_encoding || 'color');
486
+ /*?
487
+ Static Methods
488
+ Uize.Color.mix
489
+ Returns an instance of the =Uize.Color= object, whose color is initialized to the average of all the colors specified in the colors array.
490
+
491
+ SYNTAX
492
+ ........................................
493
+ colorOBJ = Uize.Color.mix (colorsARRAY);
494
+ ........................................
495
+
496
+ Color values specified in the =colorsARRAY= array can be specified in any of the many `Color Encodings` supported by the =Uize.Color= module, so the following statement is perfectly valid...
497
+
498
+ EXAMPLE
499
+ ...............................................................
500
+ var mixedColor = Uize.Color.mix ([
501
+ '#f5f5dc', // beige
502
+ [255,0,0], // red
503
+ 'fuchsia', // fuchsia
504
+ 'Rgb(64,224,208)', // turquoise
505
+ {red:255,green:255,blue:0}, // yellow
506
+ 0x808080, // gray
507
+ Uize.Color (245,255,250) // mintcream
508
+ ]);
509
+ alert (mixedColor.to ()); // displays the text "#cf9e98"
510
+ ...............................................................
511
+
512
+ The above example would produce a =Uize.Color= object set to the color with the =hex= RGB equivalent of =#cf9e98=. The expression =mixedColor.to ()= produces the output ='#cf9e98'= because the first color in the list is specified using the =#hex= encoding.
513
+
514
+ Primary Encoding
515
+ When mixing a series of colors, the color encoding of the first color in the series is used as the primary encoding for the mixing process.
516
+
517
+ This means that the =Uize.Color= object instance that is returned by this method will be set to that encoding. It also means that any color in the list that may be specified using an encoding that implies a color space other than that of the primary encoding will be automatically converted to the color space of the primary encoding.
518
+
519
+ VARIATION
520
+ ....................................................
521
+ colorOBJ = Uize.Color.mix (colorsARRAY,encodingSTR);
522
+ ....................................................
523
+
524
+ When the optional =encodingSTR= parameter is specified, rhe resulting mixed color can be encoded in any of the many supported `Color Encodings`.
525
+
526
+ EXAMPLE
527
+ ....................................................
528
+ alert (
529
+ Uize.Color.mix (
530
+ [
531
+ '#f5f5dc', // beige
532
+ [255,0,0], // red
533
+ 'fuchsia', // fuchsia
534
+ 'Rgb(64,224,208)', // turquoise
535
+ {red:255,green:255,blue:0}, // yellow
536
+ 0x808080, // gray
537
+ Uize.Color (245,255,250) // mintcream
538
+ ],
539
+ 'RGB string'
540
+ )
541
+ );
542
+ ....................................................
543
+
544
+ In the above example, the =alert= statement would display the text "rgb(207,158,152)".
545
+ */
546
+ };
547
+
548
+ _object.random = function (_encoding) {
549
+ return _dummyColor1.setEncoding (_encoding).random ().to (_encoding);
550
+ /*?
551
+ Static Methods
552
+ Uize.Color.random
553
+ Generates a random color with the specified encoding.
554
+
555
+ SYNTAX
556
+ ...............................................
557
+ colorANYTYPE = Uize.Color.random (encodingSTR);
558
+ ...............................................
559
+
560
+ EXAMPLE
561
+ ................................................................................
562
+ Uize.Node.setStyle (
563
+ 'myNodeId',
564
+ {color:Uize.Color.random ('#hex'),backgroundColor:Uize.Color.random ('#hex')}
565
+ );
566
+ ................................................................................
567
+
568
+ In the above example, the text color and background color for the DOM node with the id "myNodeId" are being randomized.
569
+
570
+ VARIATION
571
+ ......................................
572
+ colorRgbHexSTR = Uize.Color.random ();
573
+ ......................................
574
+
575
+ When no =encodingSTR= parameter is specified, the default value ='hex'= will be used and the method will return a string value, being a hex formatted random RGB color value.
576
+
577
+ NOTES
578
+ - when the value ='color'= is specified for the =encodingSTR= parameter, then this method will return an instance of the =Uize.Color= object with its encoding set to ='hex'= (ie. in the =sRGB= color space)
579
+ - see the related =random= instance method
580
+ */
581
+ };
582
+
583
+ var _returnTupleComponentAsIs = new Function ('tuple','componentNo','return tuple [componentNo]');
584
+ _object.sort = function (_colors,_referenceColor,_componentWeighting) {
585
+ if (_colors.length > 1) {
586
+ _componentWeighting = _ensureSettingIsTuple (_componentWeighting,1);
587
+ var
588
+ _getNormalizedComponent =
589
+ _componentWeighting [0] == 1 &&
590
+ _componentWeighting [1] == 1 &&
591
+ _componentWeighting [2] == 1 &&
592
+ (_componentWeighting [3] == 1 || _componentWeighting [3] === _undefined)
593
+ ? _returnTupleComponentAsIs
594
+ : function (_tuple,_componentNo) {
595
+ return (
596
+ _componentWeighting [_componentNo] *
597
+ (_tuple [_componentNo] - _componentMins [_componentNo]) / _componentRanges [_componentNo]
598
+ );
599
+ },
600
+ _encoding = _dummyColor1.from (_referenceColor).encoding,
601
+ _colorSpaceTuple = _object.colorSpaces [_object.encodings [_encoding].colorSpace].tuple,
602
+ _componentMins = [
603
+ _colorSpaceTuple [0].min,
604
+ _colorSpaceTuple [1].min,
605
+ _colorSpaceTuple [2].min,
606
+ (_colorSpaceTuple [3] || _sacredEmptyObject).min
607
+ ],
608
+ _componentRanges = [
609
+ _colorSpaceTuple [0].max - _componentMins [0],
610
+ _colorSpaceTuple [1].max - _componentMins [1],
611
+ _colorSpaceTuple [2].max - _componentMins [2],
612
+ (_colorSpaceTuple [3] || _sacredEmptyObject).max - _componentMins [3]
613
+ ],
614
+ _dummyColor1Tuple = _dummyColor1.tuple,
615
+ _dummyColor1Component0Normalized = _getNormalizedComponent (_dummyColor1Tuple,0),
616
+ _dummyColor1Component1Normalized = _getNormalizedComponent (_dummyColor1Tuple,1),
617
+ _dummyColor1Component2Normalized = _getNormalizedComponent (_dummyColor1Tuple,2)
618
+ ;
619
+ function _getDistanceBetweenCoords (_aX,_aY,_bX,_bY) {
620
+ return Math.sqrt ((_bX - _aX) * (_bX - _aX) + (_bY - _aY) * (_bY - _aY));
621
+ }
622
+ Uize.Array.Sort.sortBy (
623
+ _colors,
624
+ function (_color) {
625
+ var _dummyColor2Tuple = _dummyColor2.from (_color).getTuple (_encoding);
626
+ return _getDistanceBetweenCoords (
627
+ 0,
628
+ _dummyColor1Component2Normalized,
629
+ _getDistanceBetweenCoords (
630
+ _dummyColor1Component0Normalized,
631
+ _dummyColor1Component1Normalized,
632
+ _getNormalizedComponent (_dummyColor2Tuple,0),
633
+ _getNormalizedComponent (_dummyColor2Tuple,1)
634
+ ),
635
+ _getNormalizedComponent (_dummyColor2Tuple,2)
636
+ );
637
+
638
+ /* for sort with components as primary, secondary, and tertiary keys
639
+ return (
640
+ Math.round (
641
+ Math.abs (
642
+ _getNormalizedComponent (_dummyColor2Tuple,2) - _dummyColor1Component2Normalized
643
+ ) * 999
644
+ ) * 1000000 +
645
+ Math.round (
646
+ Math.abs (
647
+ _getNormalizedComponent (_dummyColor2Tuple,1) - _dummyColor1Component1Normalized
648
+ ) * 999
649
+ ) * 1000 +
650
+ Math.round (
651
+ Math.abs (
652
+ _getNormalizedComponent (_dummyColor2Tuple,0) - _dummyColor1Component0Normalized
653
+ ) * 999
654
+ )
655
+ );
656
+ */
657
+ }
658
+ )
659
+ }
660
+ return _colors;
661
+ /*?
662
+ Static Methods
663
+ Uize.Color.sort
664
+ Sorts the specified array of colors according to their proximity to a specified reference color, using the specified sort criteria.
665
+
666
+ SYNTAX
667
+ ..................................................................
668
+ colorsARRAY = Uize.Color.sort (colorsARRAY,referenceColorANYTYPE);
669
+ ..................................................................
670
+
671
+ This method sorts the colors specified by the =colorsARRAY= parameter, by how close they are to the reference color specified by the =referenceColorANYTYPE= parameter. Colors close to the head of the sorted array will be most like each other and most like the reference color, while colors towards the tail of the sorted array will be most unlike the reference color and will also tend to be most unlike one another. This will make the head of the sorted array appear more orderly, while making the tail appear more chaotic, since colors that are from the reference color may also be far from one another.
672
+
673
+ Color values in the array to sort can be specified using any of the `Color Encodings` supported by the =Uize.Color= object, but they will be sorted in the color space of the reference color, as specified by the =referenceColorANYTYPE= parameter. So, if the array of colors are specified using =sRGB= encodings and the reference color is specified using an =HSL= encoding, then the colors will be sorted in the =HSL= color space.
674
+
675
+ EXAMPLE
676
+ .......................................................................................
677
+ Uize.Color.sort (colors,'rgb(255,0,0)'); // sort redder colors to the head of the array
678
+ .......................................................................................
679
+
680
+ VARIATION 1
681
+ ...............................
682
+ colorsARRAY = Uize.Color.sort (
683
+ colorsARRAY,
684
+ referenceColorANYTYPE,
685
+ componentWeightingARRAY
686
+ );
687
+ ...............................
688
+
689
+ By default, the different components are normalized in order to give them equal weighting when calculating the proximity of colors being sorted to the reference color. However, specifying the optional =componentWeightingARRAY= parameter lets you specify a greater or lesser weighting for different components. For example, in the =HSL= color space, one may care more about how close colors are in terms of hue to the reference color than one cares about how close they are in terms of saturation or lightness.
690
+
691
+ The array specified by the =componentWeightingARRAY= parameter should contain a weighting factor for each component of the color space of the reference color. Each weighting factor should be a floating point number, where a value of =1= represents normal weighting, and a value of =0= means to effectively ignore the component. Weighting values greater than =1= may be specified. For example, a value for =componentWeightingARRAY= of =[2,1,1]= in the =HSL= color space means that hue is twice as important as saturation and lightness. And, for that matter, values of =[2,2,2]= and =[1,1,1]= for =componentWeightingARRAY= both indicate equal weighting for three components of a color space.
692
+
693
+ EXAMPLES
694
+ .................................................................................
695
+ Uize.Color.sort (colors,'hsl(0,0,0)',[0,0,1]); // darkest to lightest
696
+ Uize.Color.sort (colors,'hsl(0,0,100)',[0,0,1]); // lightest to darkest
697
+ Uize.Color.sort (colors,'hsl(0,100,0)',[0,1,0]); // most to least saturated
698
+ Uize.Color.sort (colors,'hsl(120,0,0)',[1,0,0]); // hue only, starting with green
699
+ .................................................................................
700
+
701
+ The above examples show different ways that different components in the color space can be completely ignored when sorting, simply by giving them a weight of =0=.
702
+
703
+ The "darkest to lightest" example sorts the array so that the darkest colors appear first. This is done by specifying a reference color in the =HSL= color space, with its lightness component set to =0= (ie. black), and with the components other than lightness given a weight of =0=. The "lightest to darkest" example operates in a similar way, excepting that the reference color for the sort has lightness set to =100= (ie. white). The "most to least saturated" example specifies weighting of =0= for hue and lightness so that only saturation affects the sort, and the saturation for the reference color is set to =100= (ie. most saturated first). The "hue only, starting with green" example makes hue the only component of importance, and the hue for the reference color is set to =120= (ie. green).
704
+
705
+ VARIATION 2
706
+ ............................................
707
+ colorsARRAY = Uize.Color.sort (colorsARRAY);
708
+ ............................................
709
+
710
+ When no =referenceColorANYTYPE= parameter is specified, then the reference color will be black in the RGB color space, and colors will be sorted on how close they are to black (so, essentially, darkest to lightest).
711
+
712
+ NOTES
713
+ - this method modifies the source array specified by the =colorsARRAY= parameter
714
+ - this method returns a reference to the array being sorted
715
+ */
716
+ };
717
+
718
+ }
719
+ });
720
+
skin/frontend/default/customproduct/js/Uize.Comm.Ajax.js ADDED
@@ -0,0 +1,108 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ /*______________
2
+ | ______ | U I Z E J A V A S C R I P T F R A M E W O R K
3
+ | / / | ---------------------------------------------------
4
+ | / O / | MODULE : Uize.Comm.Ajax Class
5
+ | / / / |
6
+ | / / / /| | ONLINE : http://www.uize.com
7
+ | /____/ /__/_| | COPYRIGHT : (c)2004-2012 UIZE
8
+ | /___ | LICENSE : Available under MIT License or GNU General Public License
9
+ |_______________| http://www.uize.com/license.html
10
+ */
11
+
12
+ /* Module Meta Data
13
+ type: Class
14
+ importance: 9
15
+ codeCompleteness: 95
16
+ testCompleteness: 0
17
+ docCompleteness: 80
18
+ */
19
+
20
+ /*?
21
+ Introduction
22
+ The =Uize.Comm.Ajax= class implements support for [[http://en.wikipedia.org/wiki/Ajax_(programming)][Ajax]] (Asynchronous JavaScript And XML) communication through the XMLHttpRequest (XHR) object.
23
+
24
+ *DEVELOPERS:* `Jan Borgersen`, `Chris van Rensburg`, `Ben Ilegbodu`, `Tim Carter`, original code donated by `Zazzle Inc.`
25
+
26
+ In order to implement support for communication through the XMLHttpRequest object, this class overrides the implementation of the =performRequest= instance method inherited from the =Uize.Comm= base class. There are no additional methods or properties provided by this class - all the interface is provided in the =Uize.Comm= superclass.
27
+ */
28
+
29
+ Uize.module ({
30
+ name:'Uize.Comm.Ajax',
31
+ required:'Uize.Url',
32
+ builder:function (_superclass) {
33
+ /*** Class Constructor ***/
34
+ var
35
+ _class = _superclass.subclass (),
36
+ _classPrototype = _class.prototype
37
+ ;
38
+
39
+ /*** General Variables ***/
40
+ var _nop = Uize.nop;
41
+
42
+ /*** Public Instance Methods ***/
43
+ _classPrototype.performRequest = function (_request,_callback) {
44
+ var
45
+ _this = this,
46
+ _returnType = _request.returnType,
47
+ _returnTypeIsObject = _returnType == 'object',
48
+ _origUrl = Uize.Url.fromParams(_request.url),
49
+ _requestUrl = Uize.Url.resolve (
50
+ _request.url,
51
+ Uize.copyInto (
52
+ {
53
+ rnd:_request.cache == 'never' ? Uize.Url.getCacheDefeatStr () : null
54
+ },
55
+ _origUrl.comm_mode ? null : {comm_mode:'ajax'},
56
+ _origUrl.output ? null : {output:'js'}
57
+ )
58
+ ),
59
+ _requestData = _request.data || '',
60
+ _requestMethod = _request.requestMethod,
61
+ _requestMethodIsPost = _requestMethod == 'POST'
62
+ ;
63
+ if (!_this._xmlHttpRequest)
64
+ _this._xmlHttpRequest = window.XMLHttpRequest
65
+ ? new XMLHttpRequest
66
+ : new ActiveXObject ('Microsoft.XMLHTTP')
67
+ ;
68
+ _this._xmlHttpRequest.onreadystatechange = function () {
69
+ if (_this._xmlHttpRequest.readyState == 4) {
70
+ _this._xmlHttpRequest.onreadystatechange = _nop;
71
+ if (_this._xmlHttpRequest.status == 200) {
72
+ var _responseText = _this._xmlHttpRequest.responseText;
73
+ if (_returnTypeIsObject || _returnType == 'xml')
74
+ _request.responseXml = _this._xmlHttpRequest.responseXML
75
+ ;
76
+ if (_returnTypeIsObject || _returnType == 'text')
77
+ _request.responseText = _responseText
78
+ ;
79
+ if (_returnTypeIsObject || _returnType == 'json')
80
+ _request.responseJson = _responseText
81
+ ? (new Function ('var a=[' + _responseText + '];return a.pop()')) ()
82
+ : null
83
+ ;
84
+ _this._xmlHttpRequest.abort ();
85
+ _callback ();
86
+ } else {
87
+ //alert ('There was a problem retrieving the data:\n' + _this._xmlHttpRequest.statusText);
88
+ _this._xmlHttpRequest.abort ();
89
+ }
90
+ }
91
+ };
92
+ if (_requestMethodIsPost && !_requestData) {
93
+ var _queryPos = _requestUrl.indexOf ('?');
94
+ _requestData = _requestUrl.substr (_queryPos + 1);
95
+ _requestUrl = _requestUrl.slice (0,_queryPos);
96
+ }
97
+ _this._xmlHttpRequest.open (_requestMethod,_requestUrl,true);
98
+ if (_requestMethodIsPost) {
99
+ _this._xmlHttpRequest.setRequestHeader('Content-type', 'application/x-www-form-urlencoded');
100
+ _this._xmlHttpRequest.setRequestHeader('Content-length', _requestData.length);
101
+ }
102
+ _this._xmlHttpRequest.send (_requestData);
103
+ };
104
+
105
+ return _class;
106
+ }
107
+ });
108
+
skin/frontend/default/customproduct/js/Uize.Comm.Iframe.Upload.js ADDED
@@ -0,0 +1,77 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ /*______________
2
+ | ______ | U I Z E J A V A S C R I P T F R A M E W O R K
3
+ | / / | ---------------------------------------------------
4
+ | / O / | MODULE : Uize.Comm.Iframe.Upload Class
5
+ | / / / |
6
+ | / / / /| | ONLINE : http://www.uize.com
7
+ | /____/ /__/_| | COPYRIGHT : (c)2004-2012 UIZE
8
+ | /___ | LICENSE : Available under MIT License or GNU General Public License
9
+ |_______________| http://www.uize.com/license.html
10
+ */
11
+
12
+ /* Module Meta Data
13
+ type: Class
14
+ importance: 4
15
+ codeCompleteness: 100
16
+ testCompleteness: 0
17
+ docCompleteness: 40
18
+ */
19
+
20
+ /*?
21
+ Introduction
22
+ The =Uize.Comm.Iframe.Upload= class implements support for file upload by submitting form data to a server and targeting its response back to an IFRAME.
23
+
24
+ *DEVELOPERS:* `Ben Ilegbodu`
25
+
26
+ In order to implement support for upload through an IFRAME, this class overrides the implementation of the =performRequest= instance method inherited from the =Uize.Comm.Iframe= base class. There are no additional methods or properties provided by this class - all the interface is provided in the =Uize.Comm= superclass.
27
+ */
28
+
29
+ Uize.module ({
30
+ name:'Uize.Comm.Iframe.Upload',
31
+ required:[
32
+ 'Uize.Node',
33
+ 'Uize.Url'
34
+ ],
35
+ builder:function (_superclass) {
36
+ /*** Class Constructor ***/
37
+ var
38
+ _class = _superclass.subclass (),
39
+ _classPrototype = _class.prototype
40
+ ;
41
+
42
+ /*** Public Instance Methods ***/
43
+ _classPrototype.performRequest = function (_request,_callback) {
44
+ var
45
+ _this = this,
46
+ _iframe = Uize.Node.getById(_this.iframeId),
47
+ _uploadForm = _request.uploadForm,
48
+ _uploadFormTarget = _uploadForm.target,
49
+ _returnType = _request.returnType,
50
+ _returnTypeIsObject = _returnType == 'object'
51
+ ;
52
+ handleResponse = function (_responseResult) {
53
+ if (_returnTypeIsObject || _returnType == 'json')
54
+ _request.responseJson = Uize.clone (_responseResult)
55
+ ;
56
+ Uize.Node.isIe && _iframe.contentWindow.history.go (-1);
57
+ _uploadForm.target = _uploadFormTarget;
58
+ _callback ();
59
+ };
60
+
61
+ _uploadForm.action = Uize.Url.resolve(
62
+ _uploadForm.action,
63
+ {
64
+ comm_mode:'iframe',
65
+ output:'js',
66
+ rnd:Uize.Url.getCacheDefeatStr ()
67
+ }
68
+ );
69
+
70
+ _uploadForm.target = _iframe.name;
71
+ _uploadForm.submit();
72
+ };
73
+
74
+ return _class;
75
+ }
76
+ });
77
+
skin/frontend/default/customproduct/js/Uize.Comm.Iframe.js ADDED
@@ -0,0 +1,106 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ /*______________
2
+ | ______ | U I Z E J A V A S C R I P T F R A M E W O R K
3
+ | / / | ---------------------------------------------------
4
+ | / O / | MODULE : Uize.Comm.Iframe Class
5
+ | / / / |
6
+ | / / / /| | ONLINE : http://www.uize.com
7
+ | /____/ /__/_| | COPYRIGHT : (c)2004-2012 UIZE
8
+ | /___ | LICENSE : Available under MIT License or GNU General Public License
9
+ |_______________| http://www.uize.com/license.html
10
+ */
11
+
12
+ /* Module Meta Data
13
+ type: Class
14
+ importance: 5
15
+ codeCompleteness: 100
16
+ testCompleteness: 0
17
+ docCompleteness: 50
18
+ */
19
+
20
+ /*?
21
+ Introduction
22
+ The =Uize.Comm.Iframe= class implements support for communication to a server by submitting form data to it and targeting its response to an IFRAME.
23
+
24
+ *DEVELOPERS:* `Chris van Rensburg`, `Jan Borgersen`, original code donated by `Zazzle Inc.`
25
+
26
+ In order to implement support for communication through an IFRAME, this class overrides the implementation of the =performRequest= instance method inherited from the =Uize.Comm= base class. There are no additional methods or properties provided by this class - all the interface is provided in the =Uize.Comm= superclass.
27
+ */
28
+
29
+ Uize.module ({
30
+ name:'Uize.Comm.Iframe',
31
+ required:[
32
+ 'Uize.Url',
33
+ 'Uize.Node'
34
+ ],
35
+ builder:function (_superclass) {
36
+ /*** Class Constructor ***/
37
+ var
38
+ _class = _superclass.subclass (),
39
+ _classPrototype = _class.prototype
40
+ ;
41
+
42
+ /*** General Variables ***/
43
+ var _iframeId;
44
+
45
+ /*** Public Instance Methods ***/
46
+ _classPrototype.performRequest = function (_request,_callback) {
47
+ var
48
+ _this = this,
49
+ _iframe = Uize.Node.getById (_iframeId),
50
+ _requestUrl = Uize.Url.resolve (
51
+ _request.url,
52
+ {
53
+ comm_mode:'ajax',
54
+ output:'js',
55
+ rnd:_request.cache == 'never' ? Uize.Url.getCacheDefeatStr () : null
56
+ }
57
+ ),
58
+ _returnType = _request.returnType,
59
+ _returnTypeIsObject = _returnType == 'object'
60
+ ;
61
+ handleResponse = function (_responseResult) {
62
+ if (_returnTypeIsObject || _returnType == 'json')
63
+ _request.responseJson = Uize.clone (_responseResult)
64
+ ;
65
+ Uize.Node.isIe && _iframe.contentWindow.history.go (-1);
66
+ _callback ();
67
+ };
68
+ if (_request.requestMethod == 'POST') {
69
+ var
70
+ _form = Uize.Node.getById ('CommIframe_form'),
71
+ _paramsField = Uize.Node.getById ('CommIframe_params'),
72
+ _queryPos = _requestUrl.indexOf ('?')
73
+ ;
74
+ _paramsField.value = _queryPos > -1 ? _requestUrl.substr (_queryPos + 1) : '';
75
+ _form.action = _requestUrl.slice (0,_queryPos);
76
+ _form.submit ();
77
+ } else {
78
+ _iframe.src = _requestUrl;
79
+ }
80
+ };
81
+
82
+ /*** Initialization ***/
83
+ if (typeof navigator != 'undefined') {
84
+ /* NOTE:
85
+ This puts the iframe in the page, but really the iframe should only be put into the page when the first instance of the class is created. Or, ideally, there should be a unique iframe per instance. The iframe insertion could even be deferred until the first request is performed.
86
+ */
87
+ _iframeId = _classPrototype.iframeId = 'Uize_Comm_Iframe_iframe' + Uize.Url.getCacheDefeatStr ();
88
+ Uize.Node.injectHtml (
89
+ Uize.Node.getById ('globalContent') || document.body,
90
+ '<form id="CommIframe_form" style="display:none;" target="' + _iframeId + '" method="POST" accept-charset="utf-8">' +
91
+ '<input id="CommIframe_params" name="params" type="hidden"/>' +
92
+ '</form>' +
93
+ '<iframe id="' + _iframeId + '" name="' + _iframeId + '" width="1" height="1" src="/z.2/js/library/Zazzle_CommIframe/blank.html" frameborder="1" style="position:absolute; visibility:hidden;" scrolling="no"></iframe>' /* NOTE: this code shouldn't make an assumption about the library being served from this place - initial src URL should */
94
+ );
95
+ }
96
+
97
+ handleResponse = function () {
98
+ /*
99
+ a dummy version of this function in case the user navigates back to a page using this code and a cached iframe server response tries to call this function (ie. no requests have been made yet)
100
+ */
101
+ };
102
+
103
+ return _class;
104
+ }
105
+ });
106
+
skin/frontend/default/customproduct/js/Uize.Comm.Script.js ADDED
@@ -0,0 +1,115 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ /*______________
2
+ | ______ | U I Z E J A V A S C R I P T F R A M E W O R K
3
+ | / / | ---------------------------------------------------
4
+ | / O / | MODULE : Uize.Comm.Script Class
5
+ | / / / |
6
+ | / / / /| | ONLINE : http://www.uize.com
7
+ | /____/ /__/_| | COPYRIGHT : (c)2008-2012 UIZE
8
+ | /___ | LICENSE : Available under MIT License or GNU General Public License
9
+ |_______________| http://www.uize.com/license.html
10
+ */
11
+
12
+ /* Module Meta Data
13
+ type: Class
14
+ importance: 7
15
+ codeCompleteness: 100
16
+ testCompleteness: 0
17
+ docCompleteness: 80
18
+ */
19
+
20
+ /*?
21
+ Introduction
22
+ The =Uize.Comm.Script= class implements support for communication with a server via [[http://en.wikipedia.org/wiki/Cross-site_scripting][cross-site scripting]] through the insertion of script tags into the document.
23
+
24
+ *DEVELOPERS:* `Tim Carter`
25
+
26
+ In order to implement support for communication through =script= tags, this class overrides the implementation of the =performRequest= instance method inherited from the =Uize.Comm= base class. There are no additional methods provided by this class - all the interface is provided in the =Uize.Comm= superclass.
27
+ */
28
+
29
+ Uize.module({
30
+ name:'Uize.Comm.Script',
31
+ required:'Uize.Url',
32
+ builder:function(_superclass) {
33
+ /*** Variables for Scruncher Optimization ***/
34
+ var _undefined;
35
+
36
+ /*** Constructor ***/
37
+ var
38
+ _class = _superclass.subclass(
39
+ function() {
40
+ for (this._callbackHashName in {_callbacks:1});
41
+ if (!_class._callbacks) _class._callbacks = [];
42
+ }
43
+ ),
44
+ _classPrototype = _class.prototype
45
+ ;
46
+
47
+ /*** Public Methods ***/
48
+ _classPrototype.performRequest = function(_request, _callback) {
49
+ var
50
+ _this = this,
51
+ _callbacks = _class._callbacks,
52
+ _serverHandlesCallback = _this._callbackMode == 'server',
53
+ _scriptNode = document.createElement('script')
54
+ ;
55
+ _callbacks.push(
56
+ function(_response) {
57
+ _request['response' + Uize.capFirstChar (_request.returnType)] = _response;
58
+ _callback();
59
+ }
60
+ );
61
+
62
+ var _callbackName = 'Uize.Comm.Script.' + _this._callbackHashName + '[' + (_callbacks.length - 1) + ']';
63
+
64
+ _scriptNode.src = Uize.Url.resolve([
65
+ _request.url,
66
+ {comm_mode:'script'},
67
+ _serverHandlesCallback ? {callback:_callbackName} : _undefined,
68
+ _request.cache == 'never' ? {rnd:Uize.Url.getCacheDefeatStr()} : _undefined
69
+ ]);
70
+
71
+ if (!_serverHandlesCallback) {
72
+ var _callbackFn = _class._callbacks[_callbacks.length - 1];
73
+ if (_scriptNode.readyState)
74
+ _scriptNode.onreadystatechange = function () {
75
+ if (_scriptNode.readyState == 'loaded' || _scriptNode.readyState == 'complete') {
76
+ _scriptNode.onreadystatechange = null;
77
+ _callbackFn ();
78
+ }
79
+ }
80
+ ;
81
+ else
82
+ _scriptNode.onload = _callbackFn;
83
+ }
84
+
85
+ document.body.appendChild(_scriptNode);
86
+ };
87
+
88
+ /*** Register properties ***/
89
+ _class.registerProperties ({
90
+ _callbackMode:{
91
+ name:'callbackMode',
92
+ value:'server'
93
+ /*?
94
+ State Properties
95
+ callbackMode
96
+ A string, indicating whether the callback function should be handled by the server or client.
97
+
98
+ While traditional xss techniques pass the name of the callback to the server so that it can be included in the response, certain situations may arise where the server is not capable of handling the callback. For example, this may occur when some client code wishes to query a service that is built by a third-party, and thus not under the control of the client developer. In the preceding example, the developer can set the value of =callbackMode= to ='client'= so that =Uize.Comm.Script= handles the callback itself.
99
+
100
+ =Uize.Comm.Script= does this by inserting two script nodes into the DOM each time a request is made. The first request queries the server. The second calls the callback. This implementation assumes that the script tags are written synchronously, ie., the first finishes before the second is written out; this is the case for most modern browsers. As a result, the callback only gets executed once all the data from the server is in memory.
101
+
102
+ This does place some restrictions on the callback function. Unlike most callbacks in the =Uize.Comm= class and subclasses, the callback in ='client'= mode does not receive any parameters. Once the ='client'= callback is called, the only certainty that exists with regard to the server request is that it completed. It is the responsibility of the callback developer to know the nature of that data.
103
+
104
+ Values
105
+ The possible values for the =callbackMode= state property are ='client'= or ='server'=. ='server'= mode means that the callback function will be passed to the server and it is the server's responsibility to call it upon completion of the task. If ='client'= mode is set, =Uize.Comm.Script= will call the callback function after each request is made.
106
+
107
+ NOTES
108
+ - the initial value is ='server'=
109
+ */
110
+ }
111
+ });
112
+ return _class;
113
+ }
114
+ });
115
+
skin/frontend/default/customproduct/js/Uize.Comm.js ADDED
@@ -0,0 +1,518 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ /*______________
2
+ | ______ | U I Z E J A V A S C R I P T F R A M E W O R K
3
+ | / / | ---------------------------------------------------
4
+ | / O / | MODULE : Uize.Comm Class
5
+ | / / / |
6
+ | / / / /| | ONLINE : http://www.uize.com
7
+ | /____/ /__/_| | COPYRIGHT : (c)2004-2012 UIZE
8
+ | /___ | LICENSE : Available under MIT License or GNU General Public License
9
+ |_______________| http://www.uize.com/license.html
10
+ */
11
+
12
+ /* Module Meta Data
13
+ type: Class
14
+ importance: 10
15
+ codeCompleteness: 90
16
+ testCompleteness: 0
17
+ docCompleteness: 80
18
+ */
19
+
20
+ /*?
21
+ Introduction
22
+ The =Uize.Comm= class provides functionality and interface that is shared by subclasses that implement support for specific communication protocols.
23
+
24
+ *DEVELOPERS:* `Chris van Rensburg`, `Jan Borgersen`, original code donated by `Zazzle Inc.`
25
+
26
+ The =Uize.Comm= class serves as the base class for subclasses that implement support for specific communication protocols (such as =Uize.Comm.Ajax=, =Uize.Comm.Iframe=, and =Uize.Comm.Script=). The =Uize.Comm= base class provides support for queuing subsequent calls to allow sequenced server requests.
27
+ */
28
+
29
+ Uize.module ({
30
+ name:'Uize.Comm',
31
+ superclass:'Uize.Class',
32
+ required:'Uize.Url',
33
+ builder:function (_superclass) {
34
+ /*** Variables for Scruncher Optimization ***/
35
+ var
36
+ _true = true,
37
+ _false = false,
38
+ _undefined
39
+ ;
40
+
41
+ /*** Class Constructor ***/
42
+ var
43
+ _class = _superclass.subclass (
44
+ function () {
45
+ var _this = this;
46
+
47
+ /*** Private Instance Properties ***/
48
+ _this._requestQueue = [];
49
+ _this._responseCache = {};
50
+
51
+ /*** Public Instance Properties ***/
52
+ _this.requestQueue = _this._requestQueue;
53
+ /*?
54
+ Instance Properties
55
+ requestQueue
56
+ An array, containing all pending requests that have been queued up and are waiting to be performed.
57
+
58
+ NOTES
59
+ - see also the =flush=, =queueRequest=, and =useQueue= instance methods
60
+ */
61
+ }
62
+ ),
63
+ _classPrototype = _class.prototype
64
+ ;
65
+
66
+ /*** Utility Functions ***/
67
+ function _getResponsePropertyNameForRequest (_request) {
68
+ return 'response' + Uize.capFirstChar (_request.returnType);
69
+ }
70
+
71
+ function _resolveRequestUrl (_request) {
72
+ _request.url = Uize.Url.resolve (_request.url) // resolves it, in case it's an array
73
+ }
74
+
75
+ /*** Private Instance Methods ***/
76
+ _classPrototype._getCachedResponse = function (_request) {
77
+ return _request.cache == 'memory' ? this._responseCache [_request.url] : null
78
+ };
79
+
80
+ _classPrototype._callResponseCallback = function (_request) {
81
+ var
82
+ _returnType = _request.returnType,
83
+ _requestCallback = _request.callback,
84
+ _cachedResponse = this._getCachedResponse (_request)
85
+ ;
86
+ if (_cachedResponse) {
87
+ var _returnTypeIsObject = _returnType == 'object';
88
+ if (_requestCallback) {
89
+ _request.responseText = '';
90
+ _request.responseJson = _request.responseXml = null;
91
+ if (_returnTypeIsObject || _returnType == 'xml')
92
+ _request.responseXml = Uize.clone (_cachedResponse.responseXml)
93
+ ;
94
+ if (_returnTypeIsObject || _returnType == 'text')
95
+ _request.responseText = _cachedResponse.responseText
96
+ ;
97
+ if (_returnTypeIsObject || _returnType == 'json')
98
+ _request.responseJson = Uize.clone (_cachedResponse.responseJson)
99
+ ;
100
+ }
101
+ } else {
102
+ if (_request.cache == 'memory')
103
+ this._responseCache [_request.url] = {
104
+ responseXml:Uize.clone (_request.responseXml),
105
+ responseJson:Uize.clone (_request.responseJson),
106
+ responseText:_request.responseText
107
+ }
108
+ ;
109
+ }
110
+ _requestCallback &&
111
+ _requestCallback (
112
+ _returnType == 'object' ? _request : _request [_getResponsePropertyNameForRequest (_request)]
113
+ )
114
+ ;
115
+ };
116
+
117
+ _classPrototype._fireRequestQueueUpdatedEvent = function () {
118
+ this.fire ('Request Queue Updated');
119
+ /*?
120
+ Instance Events
121
+ Request Queue Updated
122
+ The =Request Queue Updated= event is fired each time the =requestQueue= instance property is updated.
123
+ */
124
+ };
125
+
126
+ /*** Public Instance Methods ***/
127
+ _classPrototype.performRequest = function (_request,_callback) {
128
+ _callback ();
129
+ /*?
130
+ Instance Methods
131
+ performRequest
132
+ A method that should be overrided in subclasses that implement support for specific communication protocols.
133
+
134
+ SYNTAX
135
+ ...................................................
136
+ myInstance.performRequest (requestOBJ,callbackFUNC)
137
+ ...................................................
138
+
139
+ This method is not intended to be called by application code. It is only public so that it can be overrided in subclasses. When implementing this method in a subclass, your method should expect to receive the two parameters =requestOBJ= and =callbackFUNC=. The =requestOBJ= parameter will contain all the information necessary for performing the request.
140
+
141
+ Once the request has been sucessfully completed, your implementation should place request results into =requestOBJ= and then call the callback function specified in the =callbackFUNC= parameter. It is not necessary to pass any parameters when calling the =callbackFUNC= function, since the request results are placed into =requestOBJ=.
142
+ */
143
+ };
144
+
145
+ _classPrototype.flush = function () {
146
+ this._requestQueue.length = 0;
147
+ this._fireRequestQueueUpdatedEvent ();
148
+ /*?
149
+ Instance Methods
150
+ flush
151
+ A method that lets you flush the request queue.
152
+
153
+ SYNTAX
154
+ ....................
155
+ myInstance.flush ();
156
+ ....................
157
+
158
+ NOTES
159
+ - this method takes no parameters
160
+ - after flushing the request queue, the =Request Queue Updated= instance event will be fired
161
+ - see also the =queueRequest= and =useQueue= instance methods
162
+ - see also the =requestQueue= instance property
163
+ */
164
+ };
165
+
166
+ _classPrototype.flushCache = function (_requestOrUrl) {
167
+ arguments.length
168
+ ? delete this._responseCache [typeof _requestOrUrl == 'string' ? _requestOrUrl : _requestOrUrl.url]
169
+ : (this._responseCache = {})
170
+ ;
171
+ /*?
172
+ Instance Methods
173
+ flushCache
174
+ Lets you flush the cached response for a specific request, or lets you flush the entire response cache for the instance.
175
+
176
+ SYNTAX
177
+ ...................................
178
+ myInstance.flushCache (requestOBJ);
179
+ ...................................
180
+
181
+ VARIATION 1
182
+ ......................................
183
+ myInstance.flushCache (requestUrlSTR);
184
+ ......................................
185
+
186
+ As an alternative to specifying a request by request object, a request can be specified by its URL (ie. the value of the =url= property of the request object).
187
+
188
+ VARIATION 2
189
+ .........................
190
+ myInstance.flushCache ();
191
+ .........................
192
+
193
+ When no parameter is specified, then the =flushCache= method will flush the entire response cache for the instance.
194
+
195
+ NOTES
196
+ - don't confuse this method with the =flush= instance method that flushes the request queue
197
+ */
198
+ };
199
+
200
+ _classPrototype.request = function (_request) {
201
+ var _this = this;
202
+ _resolveRequestUrl (_request);
203
+ if (_this._getCachedResponse (_request)) {
204
+ setTimeout (function () {_this._callResponseCallback (_request)},0);
205
+ } else {
206
+ _this.queueRequest (_request);
207
+ _this.useQueue ();
208
+ }
209
+ /*?
210
+ Instance Methods
211
+ request
212
+ A method that lets you initiate a request.
213
+
214
+ SYNTAX
215
+ ................................
216
+ myInstance.request (requestOBJ);
217
+ ................................
218
+
219
+ All the information that governs the request is contained inside the =requestOBJ= parameter. The properties of this object will vary, depending on the communication protocol and are determined by the particular subclass =Uize.Comm= you are using.
220
+
221
+ SYNTAX (EXPLODED)
222
+ ................................................
223
+ myInstance.request ({
224
+ // ...properties specific to comm protocol...
225
+ // ...properties specific to comm protocol...
226
+ // ...properties specific to comm protocol...
227
+ returnType:returnTypeSTR,
228
+ cache:cacheBOOLorSTR,
229
+ callback:callbackFUNC
230
+ });
231
+ ................................................
232
+
233
+ requestOBJ Properties
234
+ The =Uize.Comm= base class handles the following properties of the =requestOBJ= parameter...
235
+
236
+ returnType
237
+ A string, specifying the data type that should be used when passing the response result to the callback function specified by the =callback= property.
238
+
239
+ VALUES
240
+ - ='text'= - the value of the =responseText= property of =requestOBJ= will be passed as the parameter to the =callback= function
241
+ - ='json'= - the value of the =responseJson= property of =requestOBJ= will be passed as the parameter to the =callback= function
242
+ - ='xml'= - the value of the =responseJson= property of =requestOBJ= will be passed as the parameter to the =callback= function
243
+ - ='object'= (default) - the =requestOBJ= object will be passed as the parameter to the =callback= function
244
+
245
+ NOTES
246
+ - the default value for this property is ='object'=
247
+
248
+ cache
249
+ A string, specifying the caching mode that should be employed when performing the request.
250
+
251
+ VALUES
252
+ - ='memory'= - a JavaScript memory based mechanism will be employed to cache the request's response. Using this caching mode, the browser's caching mechanism is preempted. Because this caching mode is memory based, the caching of responses in this mode is not persisted across page reloads or navigation. This mode is useful for requests that are likely to be hit heavily and repeatedly throughout a page session.
253
+ - ='browser'= - caching is left to the browser's built-in mechanism.
254
+ - ='never'= (default) - a cache defeat mechanism is employed to ensure that the request is never cached. This mode is useful for requests where the response will vary with repeated use - even with identical request parameters - because the response may be determined by data beyond that contained in the request, such as data contributed through community interaction with a Web application, or data that is updated in the user's session.
255
+
256
+ NOTES
257
+ - the default value for this property is ='never'=
258
+
259
+ callback
260
+ A function reference, specifying the function that should be called once the request has been performed.
261
+
262
+ The callback function you specify should expect to receive one parameter that will be of the type specified by the =returnType= property.
263
+
264
+ cutToHead
265
+ A boolean, specifying whether or not the request should cut to the head of the request queue.
266
+
267
+ If the value =false= is specified for the =cutToHead= property, or if this property is not specified, then the request is appended to the request queue. This is the default behavior. In some rare cases, such as when recovering from a request that returns a failure / error response, it might be desirable to push requests that are part of recovering from the failed request to the head of the queue. In such cases, such recovery requests can specify the value =true= for the =cutToHead= property.
268
+ */
269
+ };
270
+
271
+ _classPrototype.queueRequest = function (_request) {
272
+ var _this = this;
273
+ _resolveRequestUrl (_request);
274
+ delete _request.completed; // in case the request object was already used for a previous request and completed was set to true (we don't want the repeated request wrapped up prematurely)
275
+ if (!_request.requestMethod) _request.requestMethod = 'GET';
276
+ if (!_request.returnType) _request.returnType = 'object';
277
+ if (typeof _request.cache != 'string')
278
+ _request.cache = _request.cache ? 'memory' : 'never'
279
+ ;
280
+ _this._requestQueue [_request.cutToHead ? 'unshift' : 'push'] (_request);
281
+ _this._fireRequestQueueUpdatedEvent ();
282
+ };
283
+
284
+ _classPrototype.useQueue = function () {
285
+ var
286
+ _this = this,
287
+ _requestQueue = _this._requestQueue,
288
+ _requestQueueLength = _requestQueue.length
289
+ ;
290
+ if (!_this._usingQueue && _requestQueueLength) {
291
+ _this._usingQueue = _true;
292
+
293
+ function _cleanFromQueue () {
294
+ var _request;
295
+ while ((_request = _requestQueue [0]) && (_this._getCachedResponse (_request) || _request.completed))
296
+ _this._callResponseCallback (_requestQueue.shift ())
297
+ ;
298
+ _this._usingQueue = _false;
299
+ _this._fireRequestQueueUpdatedEvent ();
300
+
301
+ _requestQueue.length && setTimeout (function () {_this.useQueue ()},1);
302
+ /* TO DO:
303
+ - determine whether or not it's necessary and/or OK to set a timeout in the AJAX case
304
+ - determine if it's OK in the IFRAME case to do the location back before this timeout is set
305
+ */
306
+ }
307
+
308
+ function _handleSingleRequest (_request) {
309
+ if (_this._getCachedResponse (_request)) {
310
+ _cleanFromQueue ();
311
+ } else {
312
+ _this.fire ({name:'Perform Request',request:_request});
313
+ /*?
314
+ Instance Events
315
+ Perform Request
316
+ The =Perform Request= instance event fires each time before a request is performed - for both single requests as well as batch requests. The event object contains a "request" property, which is a reference to the request object for the request about to be performed.
317
+ */
318
+ _this.performRequest (
319
+ _request,
320
+ function () {
321
+ _request.completed = _true;
322
+ _cleanFromQueue ();
323
+ }
324
+ );
325
+ }
326
+ }
327
+
328
+ if (_requestQueueLength == 1) {
329
+ _handleSingleRequest (_requestQueue [0]);
330
+ } else {
331
+ var _requestsToBatch = [];
332
+
333
+ /*** determine list of requests to batch ***/
334
+ var _batchingAgent;
335
+ for (var _requestNo = -1; ++_requestNo < _requestQueueLength;) {
336
+ var
337
+ _request = _requestQueue [_requestNo],
338
+ _requestBatchingAgent = _request.batchingAgent
339
+ ;
340
+ if (
341
+ !_requestBatchingAgent ||
342
+ (_batchingAgent && _requestBatchingAgent != _batchingAgent) ||
343
+ _request.cache == 'browser'
344
+ ) {
345
+ break;
346
+ } else {
347
+ if (!_batchingAgent)
348
+ _batchingAgent = _requestBatchingAgent
349
+ ;
350
+ _requestsToBatch.push (_request);
351
+ }
352
+ }
353
+
354
+ var _requestsToBatchLength = _requestsToBatch.length;
355
+ if (_requestsToBatchLength > 1) {
356
+ /*** handle batch request ***/
357
+ /*** find all the requests in the batch that aren't already memory cached ***/
358
+ var _requestsInBatchRequest = [];
359
+ for (var _requestNo = -1; ++_requestNo < _requestsToBatchLength;) {
360
+ var _request = _requestsToBatch [_requestNo];
361
+ if (!_this._getCachedResponse (_request)) {
362
+ _request.completed = _false;
363
+ _requestsInBatchRequest.push (_request);
364
+ }
365
+ }
366
+
367
+ /*** perform batch request and handle responses ***/
368
+ var _requestsInBatchRequestLength = _requestsInBatchRequest.length;
369
+ if (_requestsInBatchRequestLength) {
370
+ if (_requestsInBatchRequestLength == 1) {
371
+ _handleSingleRequest (_requestsInBatchRequest [0]);
372
+ } else {
373
+ /* NOTE:
374
+ only package up as a batch request if there turn out to be more than one non-cached requests
375
+ */
376
+ var _batchRequest = _batchingAgent.buildRequest (_requestsInBatchRequest);
377
+ _this.fire ({name:'Perform Request',request:_batchRequest});
378
+ _this.performRequest (
379
+ _batchRequest,
380
+ function () {
381
+ var
382
+ _batchResponses = _batchingAgent.responseParser (_batchRequest),
383
+ _batchResponseNo = 0
384
+ ;
385
+ for (var _requestNo = -1; ++_requestNo < _requestsToBatchLength;) {
386
+ var _request = _requestsToBatch [_requestNo];
387
+ if (_request.completed !== _undefined) {
388
+ _request [_getResponsePropertyNameForRequest (_request)] =
389
+ _batchResponses [_batchResponseNo++]
390
+ ;
391
+ _request.completed = _true;
392
+ }
393
+ }
394
+ _cleanFromQueue ();
395
+ }
396
+ );
397
+ }
398
+ } else {
399
+ _cleanFromQueue ();
400
+ }
401
+ } else {
402
+ /*** handle single request ***/
403
+ _handleSingleRequest (_requestQueue [0]);
404
+ }
405
+ }
406
+ }
407
+ };
408
+
409
+ /*** Public Static Methods ***/
410
+ _class.processArrayAsync = function (_elements,_processElementAsync,_completion,_direction) {
411
+ if (!_direction) _direction = 1;
412
+ var
413
+ _elementsLengthMinus1 = _elements.length - 1,
414
+ _elementNo = (_direction > 0 ? 0 : _elementsLengthMinus1) - _direction
415
+ ;
416
+ function _processNextElement (_mustContinue) {
417
+ (_elementNo += _direction) >= 0 && _elementNo <= _elementsLengthMinus1 && _mustContinue !== _false
418
+ ? _processElementAsync (_elements [_elementNo],_processNextElement,_elementNo)
419
+ : _completion ? _completion (_elementsLengthMinus1 + 1) : 0
420
+ }
421
+ _processNextElement ();
422
+ /*?
423
+ Static Methods
424
+ Uize.Comm.processArrayAsync
425
+ A method that facilitates asynchronous iteration through and processing of the elements of an array.
426
+
427
+ SYNTAX
428
+ ...................................................................................
429
+ Uize.Comm.processArrayAsync (elementsARRAY,processElementAsyncFUNC,completionFUNC);
430
+ ...................................................................................
431
+
432
+ While asynchronous, the array specified by the =elementsARRAY= parameter is guaranteed to be iterated through sequentially. This method is useful for iterating through the elements of an array and using an asynchronous communication protocol, such as Ajax, in the processing of the elements.
433
+
434
+ The function you specify in the =processElementAsyncFUNC= parameter should be of the form...
435
+
436
+ ......................................................................................
437
+ myAsyncElementProcessor (elementToProcessANYTYPE,processNextElementFUNC,elementNoINT);
438
+ ......................................................................................
439
+
440
+ The value of the =elementToProcessANYTYPE= parameter will be the value of each successive element in the array that is being iterated through. In order to inform the =Uize.Comm.processArrayAsync= method that the asynchronous processing of the current element has been completed so that it can continue on with the iteration, the function specified by the =processNextElementFUNC= parameter should be called. This function does not need to be called with any parameters. However, if you call it with the value =false=, then the iteration will be terminated and any function that you specified for the =completionFUNC= parameter will be called.
441
+
442
+ Your processor function can optionally declare an =elementNoINT= parameter, to receive the array index of the current element being processed. This might be useful if you need to index into other corresponding support data structures, or use the number as part of the construction of some string or such. Naturally, your own element processor function can name these three parameters whatever it likes.
443
+
444
+ If you specified a value for the optional =completionFUNC= parameter, then your completion function will be called once the iteration is completed, with one parameter, being the length of the array that was processed.
445
+
446
+ TYPICAL USAGE SKELETON
447
+ ...................................................................
448
+ Uize.Comm.processArrayAsync (
449
+ _elementsToIterateThrough,
450
+ function (_currentElement,_continueIterating) {
451
+ _doSomethingAsynchronous (
452
+ function () { // the callback for _doSomethingAsynchronous
453
+ // further processing of element
454
+ _continueIterating ();
455
+ }
456
+ );
457
+ },
458
+ function () {
459
+ // done iterating, wrap it all up
460
+ }
461
+ );
462
+ ...................................................................
463
+
464
+ EXAMPLE
465
+ ........................................................................................
466
+ var imagesInfoHtml = '';
467
+ Uize.Comm.processArrayAsync (
468
+ myPhotoStream.getImageIds (),
469
+ function (_imageId,_addInfoHtmlForNextImage) {
470
+ myAjaxCommObject.request ({
471
+ url:'/svc/getimageinfo?id=' + _imageId,
472
+ returnType:'json',
473
+ requestMethod:'GET',
474
+ callback:function (resonseJson) {
475
+ imagesInfoHtml +=
476
+ 'title: ' + resonseJson.title + '<br/>' +
477
+ 'description: ' + resonseJson.description + '<br/>' +
478
+ 'dimensions: ' + resonseJson.width + 'x' + resonseJson.height + '<br/>' +
479
+ '<hr/>'
480
+ ;
481
+ _addInfoHtmlForNextImage ();
482
+ }
483
+ });
484
+ },
485
+ function () {
486
+ Uize.Node.setInnerHtml ('imagesInfo',imagesInfoHtml);
487
+ }
488
+ );
489
+ ........................................................................................
490
+
491
+ In this fictitious example, =Uize.Comm.processArrayAsync= is being used to iterate through an array of image IDs for a photo stream.
492
+
493
+ On each iteration, the processor function performs an asynchronous request, using an instance of =Uize.Comm.Ajax=, to the service "/svc/getimageinfo" in order to get info for each image. When the Ajax request returns with the image info, the callback registered for the request uses the image info to build image info HTML for the entire photo stream. After adding to the HTML string, the continuation function is called in order to continue the iteration. Once all the image IDs have been processed, the completion function is called, which spits out the constructed info HTML into the page.
494
+
495
+ One thing that this example demonstrates is that the parameters that your element processor function receives can be named to be semantically suitable to your application.
496
+
497
+ VARIATION 1
498
+ ....................................................................
499
+ Uize.Comm.processArrayAsync (
500
+ elementsARRAY,processElementAsyncFUNC,completionFUNC,directionINT
501
+ );
502
+ ....................................................................
503
+
504
+ The optional =directionINT= parameter lets you specify the increment (and, therefore, direction) of the asynchronous loop. By default, this method loops forward through the array - from the first element to the last element. Specifying a value of =-1= for the =directionINT= parameter will cause the iteration to start from the last element of the array and loop towards the first element - one element at a time. Specifying a value of =-2= will also result in a reverse loop, but will iterate backwards two elements at a time.
505
+
506
+ VARIATION 2
507
+ ....................................................................
508
+ Uize.Comm.processArrayAsync (elementsARRAY,processElementAsyncFUNC);
509
+ ....................................................................
510
+
511
+ When the optional =completionFUNC= parameter is not specified, then the caller of this method will not be notified when the process has been completed.
512
+ */
513
+ };
514
+
515
+ return _class;
516
+ }
517
+ });
518
+
skin/frontend/default/customproduct/js/Uize.Cookie.js ADDED
@@ -0,0 +1,115 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ /*______________
2
+ | ______ | U I Z E J A V A S C R I P T F R A M E W O R K
3
+ | / / | ---------------------------------------------------
4
+ | / O / | MODULE : Uize.Cookie Package
5
+ | / / / |
6
+ | / / / /| | ONLINE : http://www.uize.com
7
+ | /____/ /__/_| | COPYRIGHT : (c)2005-2012 UIZE
8
+ | /___ | LICENSE : Available under MIT License or GNU General Public License
9
+ |_______________| http://www.uize.com/license.html
10
+ */
11
+
12
+ /* Module Meta Data
13
+ type: Package
14
+ importance: 2
15
+ codeCompleteness: 100
16
+ testCompleteness: 0
17
+ docCompleteness: 20
18
+ */
19
+
20
+ /*?
21
+ Introduction
22
+ The =Uize.Cookie= module is a package under the =Uize= namespace, and provides a couple of methods for managing browser cookies.
23
+
24
+ *DEVELOPERS:* `Chris van Rensburg`
25
+ */
26
+
27
+ Uize.module ({
28
+ name:'Uize.Cookie',
29
+ builder:function () {
30
+ /*** Variables for Scruncher Optimization ***/
31
+ var
32
+ _undefined,
33
+ _null = null,
34
+ _package = function () {}
35
+ ;
36
+
37
+ /*** Public Static Methods ***/
38
+ _package.setCookie = function (_name,_value,_path,_expiration) {
39
+ if (_value === _undefined || _value == _null) {
40
+ _value = '';
41
+ _expiration = 'Mon, 1 Jan 1990 12:00:00 UTC';
42
+ } else {
43
+ if (_expiration === _undefined) {
44
+ var _expirationDate = new Date;
45
+ _expirationDate.setFullYear (_expirationDate.getFullYear () + 1);
46
+ _expiration = _expirationDate.toGMTString ();
47
+ }
48
+ }
49
+ document.cookie = escape (_name) + '=' + escape (_value) + ';' + ((_path !== _undefined && _path != _null) ? ('path=' + _path + ';') : '') + ((_expiration !== _null) ? ('expires=' + _expiration + ';') : '');
50
+ /*?
51
+ Static Methods
52
+ Uize.Cookie.setCookie
53
+ SYNTAX
54
+ ...........................................................................
55
+ Uize.Cookie.setCookie (cookieNameSTR,cookieValueSTR,pathSTR,expirationSTR);
56
+ ...........................................................................
57
+
58
+ VARIATIONS
59
+
60
+ .............................................................
61
+ Uize.Cookie.setCookie (cookieNameSTR,cookieValueSTR,pathSTR);
62
+ .............................................................
63
+
64
+ When no =expirationSTR= parameter is specified, the expiration will be set to one year from the time that the cookie value is set.
65
+
66
+ .....................................................
67
+ Uize.Cookie.setCookie (cookieNameSTR,cookieValueSTR);
68
+ .....................................................
69
+
70
+ When no =pathSTR= parameter is specified, then the path of the current page being used.
71
+
72
+ ......................................
73
+ Uize.Cookie.setCookie (cookieNameSTR);
74
+ ......................................
75
+
76
+ When only a =cookieNameSTR= parameter is specified, the cookie specified by that parameter will be cleared.
77
+ */
78
+ };
79
+
80
+ _package.getCookie = function (_name) {
81
+ var
82
+ _value = '',
83
+ _cookieStr = document.cookie
84
+ ;
85
+ if (typeof _cookieStr == 'string') {
86
+ _cookieStr = _cookieStr.replace (/ /g,'');
87
+ for (
88
+ var _cookieNo = -1, _cookies = _cookieStr.split (';'), _cookiesLength = _cookies.length;
89
+ ++_cookieNo < _cookiesLength;
90
+ ) {
91
+ var _cookie = _cookies [_cookieNo].split ('=');
92
+ if (unescape (_cookie [0]) == _name) {
93
+ _value = (typeof _cookie [1] == 'string') ? unescape (_cookie [1]) : '';
94
+ break;
95
+ }
96
+ }
97
+ }
98
+ return _value;
99
+ /*?
100
+ Static Methods
101
+ Uize.Cookie.getCookie
102
+ SYNTAX
103
+ .......................................................
104
+ cookieValueSTR = Uize.Cookie.getCookie (cookieNameSTR);
105
+ .......................................................
106
+
107
+ NOTES
108
+ - if there is no cookie stored by the specified name, then an empty string will be returned
109
+ */
110
+ };
111
+
112
+ return _package;
113
+ }
114
+ });
115
+
skin/frontend/default/customproduct/js/Uize.Curve.Mod.js ADDED
@@ -0,0 +1,522 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ /*______________
2
+ | ______ | U I Z E J A V A S C R I P T F R A M E W O R K
3
+ | / / | ---------------------------------------------------
4
+ | / O / | MODULE : Uize.Curve.Mod Package
5
+ | / / / |
6
+ | / / / /| | ONLINE : http://www.uize.com
7
+ | /____/ /__/_| | COPYRIGHT : (c)2009-2012 UIZE
8
+ | /___ | LICENSE : Available under MIT License or GNU General Public License
9
+ |_______________| http://www.uize.com/license.html
10
+ */
11
+
12
+ /* Module Meta Data
13
+ type: Package
14
+ importance: 4
15
+ codeCompleteness: 90
16
+ testCompleteness: 0
17
+ docCompleteness: 100
18
+ */
19
+
20
+ /*?
21
+ Introduction
22
+ The =Uize.Curve.Mod= module defines various curve function modifiers, to enable creation of new curve functions by combining existing curve functions.
23
+
24
+ *DEVELOPERS:* `Chris van Rensburg`
25
+
26
+ In A Nutshell
27
+ Curve function modifiers are curve function generators that accept curve functions as their primary inputs.
28
+
29
+ The =Uize.Curve.Mod= module provides a good selection of these curve function modifiers. Curve function modifiers operate on the curve functions they are provided in order to produce new, modified curve functions. You can consider them as operators that operate on curve functions to produce new curve functions. They could also be thought of as specialized parameterized curve function generators, where some - or all - of the parameters just happen to be curve functions. As an example, the =Uize.Curve.Mod.blend= static method blends the two specified curve functions to produce a new curve function, with blend parameters that let you specify the blend between the two curve functions.
30
+
31
+ "What does it mean to blend two functions?" you may ask. No, JavaScript doesn't support some crazy new math that allows you to add or multiply functions. Blending two curve functions is carried out by returning a new curve function that takes an input value, uses each of the two curve functions that are to be blended and obtains a remapped value from each, then blends between those two values to produce a new output value. This has the effect of blending the curves that would be produced by the two curve functions that are being blended - across their entire input value range. So, effectively, you are blending two curve functions to produce a new curve function.
32
+
33
+ EXAMPLE
34
+ ..............................................
35
+ // quickly to middle, hesitate, quickly to end
36
+
37
+ Uize.Curve.Mod.blend (
38
+ Uize.Curve.easeInSweetPow (1/6),
39
+ Uize.Curve.easeOutSweetPow (1/12),
40
+ Uize.Curve.line (0,1)
41
+ )
42
+ ..............................................
43
+
44
+ In the above example, the curve function generated by the statement =Uize.Curve.easeInSweetPow (1/6)= is being blended with the curve function generated by the statement =Uize.Curve.easeOutSweetPow (1/12)=, with the blend biased towards the first curve function at the lower input values, and biased towards the second curve function at the higher input values.
45
+
46
+ VISUALIZE IT
47
+
48
+ To better visualize how curve function modifiers work and how they affect motion, visit the interactive [[../examples/curve-explorer.html][Curve Explorer]] tool.
49
+
50
+ BACKGROUND READING
51
+
52
+ For an in-depth discussion on animation in the UIZE JavaScript Framework, and for a discussion on how this module fits into the larger picture, consult the explainer [[../explainers/javascript-animation-and-effects.html][JavaScript Animation and Effects]] and read through the section `Curves`.
53
+ */
54
+
55
+ Uize.module ({
56
+ name:'Uize.Curve.Mod',
57
+ builder:function (_host) {
58
+ /*** Variables for Scruncher Optimization ***/
59
+ var
60
+ _package = function () {},
61
+ _undefined,
62
+ _blendFloats = _host.blendFloats,
63
+ _resolve = _host.resolve,
64
+ _linear = _host.linear
65
+ ;
66
+
67
+ /*** Public Static Methods ***/
68
+ _package.band = function (_curveFunction,_sizeX,_alignX,_sizeY,_alignY) {
69
+ _curveFunction = _resolve (_curveFunction);
70
+ if (_sizeY == _undefined) _sizeY = 1;
71
+ var
72
+ _startX = (1 - _sizeX) * (_alignX || 0),
73
+ _endX = _startX + _sizeX,
74
+ _startY = (1 - _sizeY) * (_alignY || 0),
75
+ _endY = _startY + _sizeY
76
+ ;
77
+ return (
78
+ _sizeX == 1 && _sizeY == 1
79
+ ? _curveFunction
80
+ : !_sizeY
81
+ ? function () {return _startY}
82
+ : !_sizeX
83
+ ? function (_value) {return _value < _startX ? _startY : _endY}
84
+ : function (_value) {
85
+ return _startY + _sizeY * (
86
+ _value < _startX ? 0 : _value > _endX ? 1 : _curveFunction ((_value - _startX) / _sizeX)
87
+ )
88
+ }
89
+ );
90
+ /*?
91
+ Static Methods
92
+ Uize.Curve.Mod.band
93
+ Returns a curve function, that is the specified source curve function compressed into the specified horizontal and vertical band.
94
+
95
+ SYNTAX
96
+ .................................................................................
97
+ curveFUNC = Uize.Curve.Mod.band (
98
+ curveFUNCorFLOAT,sizeX0to1FLOAT,alignX0to1FLOAT,sizeY0to1FLOAT,alignY0to1FLOAT
99
+ );
100
+ .................................................................................
101
+
102
+ Parameters
103
+ curveFUNCorFLOAT
104
+ A function reference for a curve function, or a numerical value that will be resolved to a power curve function using the =Uize.Curve.resolve= method, specifying the source curve function that should be compressed into the specified band.
105
+
106
+ For a linear curve, the value =1= can be specified for this parameter.
107
+
108
+ sizeX0to1FLOAT
109
+ A floating point number in the range of =0= to =1=, specifying the width of the horizontal band.
110
+
111
+ alignX0to1FLOAT
112
+ A floating point number in the range of =0= to =1=, specifying the horizontal alignment of the band.
113
+
114
+ The value =0= represents left aligned, the value =.5= represents center aligned, and the value =1= represents right aligned. Other values between =0= and =1= represent continuous horizontal alignment between left and right. When the value =1= is specified for the =sizeX0to1FLOAT= parameter, then the =alignX0to1FLOAT= parameter has no effect.
115
+
116
+ sizeY0to1FLOAT
117
+ A floating point number in the range of =0= to =1=, specifying the height of the vertical band.
118
+
119
+ alignY0to1FLOAT
120
+ A floating point number in the range of =0= to =1=, specifying the vertical alignment of the band.
121
+
122
+ The value =0= represents bottom aligned, the value =.5= represents center aligned, and the value =1= represents top aligned. Other values between =0= and =1= represent continuous vertical alignment between bottom and top. When the value =1= is specified for the =sizeY0to1FLOAT= parameter, then the =alignY0to1FLOAT= parameter has no effect.
123
+
124
+ VARIATION
125
+ ..................................................................................
126
+ curveFUNC = Uize.Curve.Mod.band (curveFUNCorFLOAT,sizeX0to1FLOAT,alignX0to1FLOAT);
127
+ ..................................................................................
128
+
129
+ When the =sizeY0to1FLOAT= and =alignY0to1FLOAT= parameters are not specified, then no vertical banding will be performed. This is equivalent to specifying the value =1= for the =sizeY0to1FLOAT= parameter. In order to only perform vertical banding and no horizontal banding, you can specify the value =1= for the =sizeX0to1FLOAT= parameter.
130
+
131
+ NOTES
132
+ - numerical values for the =curveFUNCorFLOAT= parameter are resolved to curve functions using the =Uize.Curve.resolve= static method
133
+ */
134
+ };
135
+
136
+ _package.bend = function (_curveFunction,_horizontalBend,_verticalBend) {
137
+ _curveFunction = _resolve (_curveFunction);
138
+ var
139
+ _horizontalBendIsLinear = (_horizontalBend = _resolve (_horizontalBend,0,false,-1)) == _linear,
140
+ _verticalBendIsLinear = (_verticalBend = _resolve (_verticalBend,0)) == _linear
141
+ ;
142
+ return (
143
+ _horizontalBendIsLinear && _verticalBendIsLinear
144
+ ? _curveFunction
145
+ : !_horizontalBendIsLinear && !_verticalBendIsLinear
146
+ ? function (_value) {return _verticalBend (_curveFunction (_horizontalBend (_value)))}
147
+ : _horizontalBendIsLinear
148
+ ? function (_value) {return _verticalBend (_curveFunction (_value))}
149
+ : function (_value) {return _curveFunction (_horizontalBend (_value))}
150
+ );
151
+ /*?
152
+ Static Methods
153
+ Uize.Curve.Mod.bend
154
+ Returns a curve function, that is the specified source curve function bent in the specified manner in the x- and y-axes.
155
+
156
+ SYNTAX
157
+ .....................................................................................
158
+ curveFUNC = Uize.Curve.Mod.bend (curveFUNCorFLOAT,bendXFUNCorFLOAT,bendYFUNCorFLOAT);
159
+ .....................................................................................
160
+
161
+ Parameters
162
+ curveFUNCorFLOAT
163
+ A function reference for a curve function, or a numerical value that will be resolved to a power curve function using the =Uize.Curve.resolve= method.
164
+
165
+ For a linear curve, the value =1= can be specified for this parameter.
166
+
167
+ bendXFUNCorFLOAT
168
+ A function reference for a curve function, or a numerical value that will be resolved to a power curve function using the =Uize.Curve.resolve= method.
169
+
170
+ Values less than -1 will bend the curve towards the left. Values greater than =1= will bend the curve towards the right. When the value =null=, =undefined=, =1=, =0=, =-1=, or =Uize.Curve.linear= is specified, then there will be no bending in the x-axis. If a curve function is specified for =bendXFUNCorFLOAT=, then the source curve function will be bent horizontally according to the nature of the specified bend curve. An ease-in-out bend curve will pinch the source curve function towards the center horizontally. An ease-in-the-middle bend curve will squash the source curve function outwards horizontally towards the left and right sides.
171
+
172
+ bendYFUNCorFLOAT
173
+ A function reference for a curve function, or a numerical value that will be resolved to a power curve function using the =Uize.Curve.resolve= method.
174
+
175
+ Values less than -1 will bend the curve towards the bottom. Values greater than =1= will bend the curve towards the top. When the value =null=, =undefined=, =1=, =0=, =-1=, or =Uize.Curve.linear= is specified, then there will be no bending in the y-axis. If a curve function is specified for =bendYFUNCorFLOAT=, then the source curve function will be bent vertically according to the nature of the specified bend curve. An ease-in-out bend curve will pinch the source curve function towards the center vertically. An ease-in-the-middle bend curve will squash the source curve function outwards vertically towards the top and bottom sides.
176
+
177
+ VARIATION
178
+ ....................................................................
179
+ curveFUNC = Uize.Curve.Mod.bend (curveFUNCorFLOAT,bendXFUNCorFLOAT);
180
+ ....................................................................
181
+
182
+ When no =bendYFUNCorFLOAT= parameter is specified, there will be no bending in the y-axis.
183
+
184
+ NOTES
185
+ - numerical values for the =curveFUNCorFLOAT=, =bendXFUNCorFLOAT=, and =bendYFUNCorFLOAT= parameters are resolved to curve functions using the =Uize.Curve.resolve= static method
186
+ */
187
+ };
188
+
189
+ _package.blend = function (_curveFunctionA,_curveFunctionB,_blend) {
190
+ if (_blend == _undefined) _blend = .5;
191
+
192
+ return (
193
+ (_curveFunctionA = _resolve (_curveFunctionA)) == (_curveFunctionB = _resolve (_curveFunctionB))
194
+ ? _curveFunctionA
195
+ : _blend == .5
196
+ ? function (_value) {return (_curveFunctionA (_value) + _curveFunctionB (_value)) / 2}
197
+ : Uize.isFunction (_blend)
198
+ ?
199
+ function (_value) {
200
+ return _blendFloats (_curveFunctionA (_value),_curveFunctionB (_value),_blend (_value));
201
+ }
202
+ :
203
+ function (_value) {
204
+ return _blendFloats (_curveFunctionA (_value),_curveFunctionB (_value),_blend);
205
+ }
206
+ );
207
+ /*?
208
+ Static Methods
209
+ Uize.Curve.Mod.blend
210
+ Returns a curve function, that is a blend between the two specified source curve functions.
211
+
212
+ SYNTAX
213
+ ......................................................................................
214
+ curveFUNC = Uize.Curve.Mod.blend (curve1FUNCorFLOAT,curve2FUNCorFLOAT,blend0to1FLOAT);
215
+ ......................................................................................
216
+
217
+ When the value =0= is specified for the =blend0to1FLOAT= parameter, then the curve function
218
+ specified by the =curve1FUNCorFLOAT= parameter will be returned. Similarly, when the value =1= is specified, then the curve function specified by the =curve2FUNCorFLOAT= parameter will be returned. When the value =.5= is specified, the returned curve function will be an equal blend between the two specified source curve functions.
219
+
220
+ VARIATION 1
221
+ .......................................................................
222
+ curveFUNC = Uize.Curve.Mod.blend (curve1FUNCorFLOAT,curve2FUNCorFLOAT);
223
+ .......................................................................
224
+
225
+ When no =blend0to1FLOAT= parameter is specified, then the value =.5= will be used as the default for this parameter and the two curve functions specified by the =curve1FUNCorFLOAT= and =curve2FUNCorFLOAT= parameters will be blended equally.
226
+
227
+ VARIATION 2
228
+ ......................................................................................
229
+ curveFUNC = Uize.Curve.Mod.blend (curve1FUNCorFLOAT,curve2FUNCorFLOAT,blendCurveFUNC);
230
+ ......................................................................................
231
+
232
+ When the =blendCurveFUNC= parameter is specified in place of the =blend0to1FLOAT= parameter, then the blend between the two curve functions can vary across the range of input values. Consider the following example...
233
+
234
+ EXAMPLE
235
+ ........................................................................
236
+ Uize.Curve.Mod.blend (
237
+ Uize.Curve.easeOutPow (4), // ease-out power curve function
238
+ Uize.Curve.saw (20,.5), // sawtooth curve function with 20 teeth
239
+ Uize.Curve.line (.25,.75) // line starting at .25 and ending at .75
240
+ )
241
+ ........................................................................
242
+
243
+ In the above example, a quartic ease-out power curve function is being blended with a sawtooth curve function with twenty teeth. The =Uize.Curve.line= method is being used to create a value range from =.25= to =.75= to control the blend between the two curve functions across the range of input values. At the input value of =0=, the blend between the curves will be =.25=. At the input value of =1=, the blend between the curves will be =.75=. At the input value of =.5=, the blend between the curves will be =.5= (the midpoint value of the line curve).
244
+
245
+ Encapsulating a Curve
246
+ One useful technique that can employ the =Uize.Curve.Mod.blend= method is to encapsulate one curve between two other curves.
247
+
248
+ Basically, if you view the curve specified by the =curve1FUNCorFLOAT= parameter as being the ventral side of a "capsule", and view the curve specified by the =curve2FUNCorFLOAT= parameter as being the dorsal side of a "capsule", then a curve specified by the =blendCurveFUNC= parameter will essentially be fitted inbetween those two curves.
249
+
250
+ EXAMPLE
251
+ .............................................
252
+ // bouncing down the stairs
253
+
254
+ Uize.Curve.Mod.blend (
255
+ Uize.Curve.easeInPow (3),
256
+ Uize.Curve.easeOutPow (1.5),
257
+ Uize.Curve.Rubber.easeOutBounce (10,4,1.1)
258
+ )
259
+ .............................................
260
+
261
+ The above expression generates a curve function that can be used to produce a bouncing-down-the-stairs type of effect. The ease-out bounce curve is being encapsulated between the ease-in power curve and the ease-out power curve.
262
+
263
+ NOTES
264
+ - numerical values for the =curve1FUNCorFLOAT= and =curve2FUNCorFLOAT= parameters are resolved to curve functions using the =Uize.Curve.resolve= static method
265
+ */
266
+ };
267
+
268
+ _package.multiply = function (_curveFunctionA,_curveFunctionB) {
269
+ _curveFunctionA = _resolve (_curveFunctionA);
270
+ _curveFunctionB = _resolve (_curveFunctionB);
271
+ return function (_value) {return _curveFunctionA (_value) * _curveFunctionB (_value)}
272
+ /*?
273
+ Static Methods
274
+ Uize.Curve.Mod.multiply
275
+ Returns a curve function, that is the two specified source curve functions multiplied together.
276
+
277
+ SYNTAX
278
+ ..........................................................................
279
+ curveFUNC = Uize.Curve.Mod.multiply (curve1FUNCorFLOAT,curve2FUNCorFLOAT);
280
+ ..........................................................................
281
+
282
+ Because curve functions produce values in the scale of =0= to =1=, multiplying two curve functions together will tend to produce a new curve function that bends downwards more extremely.
283
+
284
+ NOTES
285
+ - numerical values for the =curve1FUNCorFLOAT= and =curve2FUNCorFLOAT= parameters are resolved to curve functions using the =Uize.Curve.resolve= static method
286
+ */
287
+ };
288
+
289
+ _package.quantize = function (_curveFunction,_steps,_stepCurveFunction) {
290
+ _curveFunction = _resolve (_curveFunction);
291
+ if (!_steps || _steps == Infinity) return _curveFunction;
292
+ if (typeof _stepCurveFunction == 'number') _stepCurveFunction = _package.band (1,0,_stepCurveFunction);
293
+ var _stepSize = 1 / _steps;
294
+ return function (_value) {
295
+ var _quantizedValue = Math.floor ((_value = _curveFunction (_value)) / _stepSize) * _stepSize;
296
+ return (
297
+ _stepCurveFunction
298
+ ? _quantizedValue + _stepCurveFunction ((_value - _quantizedValue) / _stepSize) * _stepSize
299
+ : _quantizedValue
300
+ );
301
+ };
302
+ /*?
303
+ Static Methods
304
+ Uize.Curve.Mod.quantize
305
+ Returns a new curve function, that is the specified curve function that has been quantized to have the specified number of steps.
306
+
307
+ SYNTAX
308
+ ................................................................
309
+ curveFUNC = Uize.Curve.Mod.quantize (curveFUNCorFLOAT,stepsINT);
310
+ ................................................................
311
+
312
+ VARIATION 1
313
+ ...................................................................................
314
+ curveFUNC = Uize.Curve.Mod.quantize (curveFUNCorFLOAT,stepsINT,stepAlign0to1FLOAT);
315
+ ...................................................................................
316
+
317
+ By default, quantization steps stay at the low side of their output value range throughout their input value range. When the optional =stepAlign0to1FLOAT= parameter is specified, this behavior can be controlled. When the value =0= is specified, the step up to the next step is aligned to the left side of the input value range. When the value =1= is specified, the step up to the next step is aligned to the right side of the input value range. When the value =.5= is specified, the step up to the next step is aligned in the center of the input value range. Other values between =0= and =1= represent continuous horizontal alignment of the step up point between the left and right of each step's input value range.
318
+
319
+ VARIATION 2
320
+ ..............................................................................
321
+ curveFUNC = Uize.Curve.Mod.quantize (curveFUNCorFLOAT,stepsINT,stepCurveFUNC);
322
+ ..............................................................................
323
+
324
+ When the =stepCurveFUNC= parameter is specified in place of the =stepAlign0to1FLOAT= parameter, then the value distortion within the vertical quantization segment can be controlled. Ease-in-out curve functions can be used to squash the output values towards the top and bottom sides of the quantization segments, and ease-in-the-middle curve functions can be used to pinch the output values towards the center of the quantization segments. Needless to say, this is easier to visualize with a graph than describe with words.
325
+
326
+ NOTES
327
+ - compare to the =Uize.Curve.Mod.redraw= static method
328
+ - numerical values for the =curveFUNCorFLOAT= parameter are resolved to curve functions using the =Uize.Curve.resolve= static method
329
+ */
330
+ };
331
+
332
+ _package.redraw = function (_curveFunction,_segments,_segmentCurveFunction,_alternatingRotate) {
333
+ _curveFunction = _resolve (_curveFunction);
334
+ if (!_segments || _segments == Infinity) return _curveFunction;
335
+ _segmentCurveFunction = _resolve (_segmentCurveFunction);
336
+ var _segmentSize = 1 / _segments;
337
+ return (
338
+ _segmentSize
339
+ ? function (_value) {
340
+ var
341
+ _segmentNoFloat = _value / _segmentSize,
342
+ _segmentNo = Math.floor (_segmentNoFloat)
343
+ ;
344
+ return _blendFloats (
345
+ _curveFunction (_segmentNo * _segmentSize),
346
+ _curveFunction (Math.ceil (_segmentNoFloat) * _segmentSize),
347
+ _alternatingRotate && _segmentNo % 2
348
+ ? 1 - _segmentCurveFunction (1 - _segmentNoFloat + _segmentNo)
349
+ : _segmentCurveFunction (_segmentNoFloat - _segmentNo)
350
+ );
351
+ }
352
+ : _curveFunction
353
+ );
354
+ /*?
355
+ Static Methods
356
+ Uize.Curve.Mod.redraw
357
+ Returns a curve function, that is a redrawn version of the specified source curve function.
358
+
359
+ SYNTAX
360
+ .........................................................................................
361
+ curveFUNC = Uize.Curve.Mod.redraw (curveFUNCorFLOAT,segmentsINT,segmentCurveFUNCorFLOAT);
362
+ .........................................................................................
363
+
364
+ The =Uize.Curve.Mod.redraw= method divides the specified curve function into a number of segments in the x-axis, as specified by the =segmentsINT= parameter. It then redraws the curve between the ends of each segment by connecting the values at each end of a segment using the segment curve specified by the =segmentCurveFUNCorFLOAT= parameter. So, redraw is a little bit like quantization, but in the x-axis.
365
+
366
+ The =Uize.Curve.Mod.redraw= method removes detail from the original curve function and replaces it with new detail, as determined by the =segmentCurveFUNCorFLOAT= value. This method can have the effect of producing a simpler curve than the original, or producing a more complex curve. For example, a complex elastic curve function could be simplified by redrawing it using a small number of segments and replacing a lot of the complexity within those segments by redrawing using a simple linear segment curve function. On the other hand, a simple linear curve function could be made more complex by redrawing it using an elastic curve function for the segments.
367
+
368
+ VARIATION 1
369
+ .................................................................
370
+ curveFUNC = Uize.Curve.Mod.redraw (curveFUNCorFLOAT,segmentsINT);
371
+ .................................................................
372
+
373
+ When the =segmentCurveFUNCorFLOAT= parameter is not specified, then a linear curve function will be used for redrawing the segments.
374
+
375
+ VARIATION 2
376
+ .............................................................................
377
+ curveFUNC = Uize.Curve.Mod.redraw (
378
+ curveFUNCorFLOAT,segmentsINT,segmentCurveFUNCorFLOAT,alternatingRotateBOOL
379
+ );
380
+ .............................................................................
381
+
382
+ When the value =true= is specified for the optional =alternatingRotateBOOL= parameter, then each alternating segment will be redrawn with a 180 degree rotated version of the curve function specified by the =segmentCurveFUNCorFLOAT= parameter. In other words, the first segment will be normal, the second segment will be rotated, the third segment will be normal, the fourth segment will be rotated, etc.
383
+
384
+ NOTES
385
+ - compare to the =Uize.Curve.Mod.quantize= static method
386
+ - numerical values for the =curveFUNCorFLOAT= and =segmentCurveFUNCorFLOAT= parameters are resolved to curve functions using the =Uize.Curve.resolve= static method
387
+ */
388
+ };
389
+
390
+ _package.repeat = function (_curveFunction,_repeats,_stairsDegree,_alternatingFlipHorz,_alternatingFlipVert) {
391
+ var
392
+ _curveFunctionLength = Uize.isArray (_curveFunction = _resolve (_curveFunction))
393
+ ? _curveFunction.length
394
+ : 0,
395
+ _repeatHeight = _blendFloats (1,1 / _repeats,_stairsDegree || (_stairsDegree = 0))
396
+ ;
397
+ return function (_value) {
398
+ var
399
+ _repeatNo = _value && Math.ceil (_value * _repeats) - 1,
400
+ _repeatPos = _repeatNo / _repeats,
401
+ _valueForRepeat = Uize.constrain ((_value - _repeatPos) * _repeats,0,1),
402
+ _isAlternate = _repeatNo % 2
403
+ ;
404
+ _valueForRepeat =
405
+ (_curveFunctionLength ? _curveFunction [_repeatNo % _curveFunctionLength] : _curveFunction) (
406
+ _isAlternate && _alternatingFlipHorz ? 1 - _valueForRepeat : _valueForRepeat
407
+ )
408
+ ;
409
+ if (_isAlternate && _alternatingFlipVert)
410
+ _valueForRepeat = 1 - _valueForRepeat
411
+ ;
412
+ return (
413
+ _repeatNo == _repeats - 1 && _valueForRepeat == 1
414
+ ? 1
415
+ : _repeatPos * _stairsDegree + _valueForRepeat * _repeatHeight
416
+ );
417
+ };
418
+ /*?
419
+ Static Methods
420
+ Uize.Curve.Mod.repeat
421
+ Returns a curve function, that is the specified curve function repeated the specified number of times.
422
+
423
+ SYNTAX
424
+ .......................................................................
425
+ curveFUNC = Uize.Curve.Mod.repeat (curveFUNCorFLOATorARRAY,repeatsINT);
426
+ .......................................................................
427
+
428
+ When an array is specified for the =curveFUNCorFLOATorARRAY= parameter, then the elements of the array should be curve functions, and these curve functions specified in the array will be cycled through for every successive repitition. There can be a different number of curve functions in the array than the value of the =repeatsINT= parameter. If the value of =repeatsINT= is greater than the length of the curve functions array, then the array will be cycled through more than once. If the value of =repeatsINT= is less than the length of array, then not all the curve functions in the array will be utilized.
429
+
430
+ VARIATION 1
431
+ ...........................................................
432
+ curveFUNC = Uize.Curve.Mod.repeat (
433
+ curveFUNCorFLOATorARRAY,repeatsINT,stairsDegree0to1FLOAT
434
+ );
435
+ ...........................................................
436
+
437
+ By default, the curve specified by the =curveFUNCorFLOATorARRAY= is repeated as thought it were a waveform, with each successive repitition occupying the full vertical range of =0= to =1=. Staircasing lets you stack the repititions along a diagonal line from left to right.
438
+
439
+ When the value =1= is specified for the =stairsDegree0to1FLOAT= parameter, the repititions are fully staircased, so that the top right of the previous repetition connects to the bottom left of the current repitition, allowing the curve line of the previous repitition to flow into the curve line of the next repitition. When ease-in-out or ease-in-the-middle curve functions are specified for the =curveFUNCorFLOATorARRAY= parameter, then the curve can be made seamless, because these types of curve functions are by design diagonally symmetrical.
440
+
441
+ When the value =0= is specified for the =stairsDegree0to1FLOAT= parameter, the repititions all occupy the full vertical range of =0= to =1=. This is the default behavior. Other values between =0= and =1= represent continuous degrees of staircasing, between no staircasing and complete staircasing.
442
+
443
+ VARIATION 2
444
+ ...................................................................................
445
+ curveFUNC = Uize.Curve.Mod.repeat (
446
+ curveFUNCorFLOATorARRAY,repeatsINT,stairsDegree0to1FLOAT,alternatingFlipHorzBOOL
447
+ );
448
+ ...................................................................................
449
+
450
+ When the optional =alternatingFlipHorzBOOL= parameter is specified, horizontal flipping for alternate repititions can be controlled. When the value =true= is specified for this parameter, the first repitition will be normal, the second repitition will be flipped, the third repitition will be normal, the fourth repitition will be flipped, etc.
451
+
452
+ VARIATION 3
453
+ ...................................
454
+ curveFUNC = Uize.Curve.Mod.repeat (
455
+ curveFUNCorFLOATorARRAY,
456
+ repeatsINT,
457
+ stairsDegree0to1FLOAT,
458
+ alternatingFlipHorzBOOL,
459
+ alternatingFlipVertBOOL
460
+ );
461
+ ...................................
462
+
463
+ When the optional =alternatingFlipVertBOOL= parameter is specified, vertical flipping for alternate repititions can be controlled. When the value =true= is specified for this parameter, the first repitition will be normal, the second repitition will be flipped, the third repitition will be normal, the fourth repitition will be flipped, etc. If you specify the value =true= for both the =alternatingFlipHorzBOOL= and =alternatingFlipVertBOOL= parameters, then alternating repititions will be rotated 180 degrees.
464
+
465
+ IMPORTANT
466
+
467
+ When not specifying the same value for both the =alternatingFlipHorzBOOL= and =alternatingFlipVertBOOL= parameters, you should be sure to specify an odd number for the =repeatsINT= parameter. Otherwise, you won't be able to guanrantee that the resulting curve function will end at the value =1=. By specifying an odd number of repeats you ensure that the last repitition will not be flipped horizontally or vertically, since only the alternating repititions are flipped.
468
+
469
+ NOTES
470
+ - numerical values for the =curveFUNCorFLOATorARRAY= parameter are resolved to curve functions using the =Uize.Curve.resolve= static method
471
+ */
472
+ };
473
+
474
+ _package.rotate = function (_curveFunction,_blendOfRotated) {
475
+ _curveFunction = _resolve (_curveFunction);
476
+ return (
477
+ _blendOfRotated == _undefined || _blendOfRotated == 1
478
+ ? _host.makeEaseOut (_curveFunction)
479
+ : _blendOfRotated
480
+ ? function (_value) {
481
+ return _blendFloats (_curveFunction (_value),1 - _curveFunction (1 - _value),_blendOfRotated)
482
+ }
483
+ : _curveFunction
484
+ )
485
+ /*?
486
+ Static Methods
487
+ Uize.Curve.Mod.rotate
488
+ Returns a curve function, that is the 180 degree rotated version of the specified source curve function, or a blend between the specified curve function and the 180 degree rotated version of it.
489
+
490
+ SYNTAX
491
+ .....................................................
492
+ curveFUNC = Uize.Curve.Mod.rotate (curveFUNCorFLOAT);
493
+ .....................................................
494
+
495
+ VARIATION
496
+ .............................................................................
497
+ curveFUNC = Uize.Curve.Mod.rotate (curveFUNCorFLOAT,blendOfRotated0to1FLOAT);
498
+ .............................................................................
499
+
500
+ When the optional =blendOfRotated0to1FLOAT= parameter is specified, this method will return a blend between the unrotated curve function and the rotated version.
501
+
502
+ INSTEAD OF...
503
+ .......................................................................
504
+ Uize.Curve.Mod.blend (Uize.Curve.makeEaseOut (Math.sqrt),Math.sqrt,.5);
505
+ .......................................................................
506
+
507
+ USE...
508
+ .....................................
509
+ Uize.Curve.Mod.rotate (Math.sqrt,.5);
510
+ .....................................
511
+
512
+ Calling the =Uize.Curve.Mod.rotate= method without specifying the =blendOfRotated0to1FLOAT= parameter is equivalent to using the =Uize.Curve.makeEaseOut= static method. So, it's when you use the =blendOfRotated0to1FLOAT= parameter that this method becomes compelling.
513
+
514
+ NOTES
515
+ - numerical values for the =curveFUNCorFLOAT= parameter are resolved to curve functions using the =Uize.Curve.resolve= static method
516
+ */
517
+ };
518
+
519
+ return _package;
520
+ }
521
+ });
522
+
skin/frontend/default/customproduct/js/Uize.Curve.Rubber.js ADDED
@@ -0,0 +1,538 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ /*______________
2
+ | ______ | U I Z E J A V A S C R I P T F R A M E W O R K
3
+ | / / | ---------------------------------------------------
4
+ | / O / | MODULE : Uize.Curve.Rubber Package
5
+ | / / / |
6
+ | / / / /| | ONLINE : http://www.uize.com
7
+ | /____/ /__/_| | COPYRIGHT : (c)2009-2012 UIZE
8
+ | /___ | LICENSE : Available under MIT License or GNU General Public License
9
+ |_______________| http://www.uize.com/license.html
10
+ */
11
+
12
+ /* Module Meta Data
13
+ type: Package
14
+ importance: 5
15
+ codeCompleteness: 100
16
+ testCompleteness: 0
17
+ docCompleteness: 100
18
+ */
19
+
20
+ /*?
21
+ Introduction
22
+ The =Uize.Curve.Rubber= module defines various "rubbery" easing curve function generators that emulate qualities of motion, like bounce and elasticity.
23
+
24
+ *DEVELOPERS:* `Chris van Rensburg`, with thanks to `Robert Penner` for his easing equations work
25
+
26
+ The =Uize.Curve.Rubber= module defines various "rubbery" easing curve function generators, some of which are based on the easing equations work of `Robert Penner`.
27
+
28
+ In A Nutshell
29
+ Whereas the =Uize.Curve= module provides some of the most commonly used ease-in, ease-out, ease-in-out, and ease-in-the-middle curve function generators, the =Uize.Curve.Rubber= module offers curve function generators for more exotic types of curves that emulate the complex properties of motion.
30
+
31
+ Credit Where Credit Is Due
32
+ Thanks go to `Robert Penner` for his work on [[http://www.robertpenner.com/easing/][his easing equations]], which provided a starting point and inspiration for work that has been done in the =Uize.Curve.Rubber= module.
33
+
34
+ In some cases, his original methods have merely been refactored, such as with the =Uize.Curve.Rubber.easeInElastic= method and related elastic easing curve function generators provided in this module. In other cases, the original implementations have been completely replaced, such as with the =Uize.Curve.Rubber.easeInBounce= method and related bounce easing curve function generators provided in this module, with the new implementation being much more versatile than the original. Either way, his excellent work has been an inspiration.
35
+
36
+ Using the Curve Function Generators
37
+ Using the curve function generators in the =Uize.Curve.Rubber= module is just as easy as using those contained inside the =Uize.Curve= module.
38
+
39
+ Simply call the curve function generator static method, supplying parameter values as needed in order to produce a curve with the desired properties, and then provide that curve function to an instance of the =Uize.Fade= class, an instance of the =Uize.Widget.HoverFader= class, a static method of the =Uize.Fx= module, or any method or instance of a class that uses the =Uize.Fade= class to drive its animation or value interpolation.
40
+
41
+ EXAMPLE
42
+ ..................................................................................
43
+ page.addChild (
44
+ 'hoverFader',
45
+ Uize.Widget.HoverFader,
46
+ {
47
+ defaultStyle:{width:150,marginLeft:90,letterSpacing:2,borderRightColor:'0'},
48
+ hoverStyle:{width:240,marginLeft:0,letterSpacing:9,borderRightColor:'f'},
49
+ fadeIn:{duration:1200,curve:Uize.Curve.Rubber.easeOutElastic (.2)},
50
+ fadeOut:{duration:1000,curve:Uize.Curve.Rubber.easeOutBounce (5,-2,1.5)}
51
+ }
52
+ );
53
+ ..................................................................................
54
+
55
+ In the above example, an instance of the =Uize.Widget.HoverFader= class is being added as a child widget of the page widget (which is assumed to already exist). For the =fadeIn= state property of the =Uize.Widget.HoverFader= instance, an elastic ease-out curve function is being supplied as a curve. For the =fadeOut= state property, a bounce ease-out curve function is being supplied as a curve. This will make the fade-in to the hover style have an elastic quality to it, and the fade-out to the default style have a bounce quality to it.
56
+
57
+ VISUALIZE IT
58
+
59
+ To better visualize how the "rubbery" easing curve function generators work and how they affect motion, visit the interactive [[../examples/curve-explorer.html][Curve Explorer]] tool.
60
+
61
+ BACKGROUND READING
62
+
63
+ For an in-depth discussion on animation in the UIZE JavaScript Framework, and for a discussion on how this module fits into the larger picture, consult the explainer [[../explainers/javascript-animation-and-effects.html][JavaScript Animation and Effects]] and read through the section `Curves`.
64
+ */
65
+
66
+ Uize.module ({
67
+ name:'Uize.Curve.Rubber',
68
+ builder:function (_host) {
69
+ var
70
+ _package = function () {},
71
+ _makeEasingCurveGenerators = _host.makeEasingCurveGenerators,
72
+ _resolve = _host.resolve
73
+ ;
74
+
75
+ /*** Curve Function Generators ***/
76
+ /*** elastic easing ***/
77
+ _makeEasingCurveGenerators (
78
+ 'elastic',
79
+ function (_period,_amplitude) {
80
+ /*** paramter defaulting ***/
81
+ if (!_period) _period = .3;
82
+ if (!_amplitude || _amplitude < 1) _amplitude = 1;
83
+
84
+ /*** capture some calculation results ***/
85
+ var
86
+ _2piDivPeriod = 2 * Math.PI / _period,
87
+ _someValueOffset = Math.asin (1 / _amplitude) / _2piDivPeriod
88
+ ;
89
+
90
+ return function (_value) {
91
+ return (
92
+ _value && _value != 1
93
+ ? (
94
+ -_amplitude * Math.pow (2,10 * (_value -= 1)) *
95
+ Math.sin ((_value - _someValueOffset) * _2piDivPeriod)
96
+ )
97
+ : _value
98
+ )
99
+ }
100
+ },
101
+ _package
102
+ /*?
103
+ Static Methods
104
+ Uize.Curve.Rubber.easeInElastic
105
+ Elastic easing in - exponentially growing sine wave.
106
+
107
+ SYNTAX
108
+ .........................................................................
109
+ curveFUNC = Uize.Curve.Rubber.easeInElastic (periodFLOAT,amplitudeFLOAT);
110
+ .........................................................................
111
+
112
+ Parameters
113
+ periodFLOAT
114
+ A floating point number between =0= to =25=, representing the width of a single elastic stretch-past and spring-back cycle as a fraction of the total curve width.
115
+
116
+ A value of =.1=, for example, will produce a curve with =10= stretch-past and spring-back cycles, whereas a value of =.2= will produce five such cycles. Ever higher values above =1= make the curve progressively more like an exponential curve. The default value for this parameter is =.3=.
117
+
118
+ amplitudeFLOAT
119
+ A floating point number in the range of =1= to =Infinity=.
120
+
121
+ Values greater than =1= produce more springy elastic curves with more pronounced peaks and greater overshoot. The default value for this parameter is =1=.
122
+
123
+ Variations
124
+ VARIATION 1
125
+ ..........................................................
126
+ curveFUNC = Uize.Curve.Rubber.easeInElastic (periodFLOAT);
127
+ ..........................................................
128
+
129
+ When the optional =amplitudeFLOAT= parameter is not specified, its value will be defaulted to =1=.
130
+
131
+ VARIATION 2
132
+ ...............................................
133
+ curveFUNC = Uize.Curve.Rubber.easeInElastic ();
134
+ ...............................................
135
+
136
+ When the optional =periodFLOAT= parameter is not specified, its value will be defaulted to =.3=.
137
+
138
+ NOTES
139
+ - see also the companion =Uize.Curve.Rubber.easeOutElastic=, =Uize.Curve.Rubber.easeInOutElastic=, and =Uize.Curve.Rubber.easeMiddleElastic= static methods
140
+ - thanks to `Robert Penner` for his original implementation
141
+
142
+ Uize.Curve.Rubber.easeOutElastic
143
+ Elastic easing out - exponentially decaying sine wave.
144
+
145
+ SYNTAX
146
+ ..........................................................................
147
+ curveFUNC = Uize.Curve.Rubber.easeOutElastic (periodFLOAT,amplitudeFLOAT);
148
+ ..........................................................................
149
+
150
+ VARIATIONS
151
+ ...........................................................
152
+ curveFUNC = Uize.Curve.Rubber.easeOutElastic (periodFLOAT);
153
+ curveFUNC = Uize.Curve.Rubber.easeOutElastic ();
154
+ ...........................................................
155
+
156
+ For a more in-depth discussion of this method's parameters and variations, consult the reference for the related =Uize.Curve.Rubber.easeInElastic= static method.
157
+
158
+ NOTES
159
+ - see also the companion =Uize.Curve.Rubber.easeInElastic=, =Uize.Curve.Rubber.easeInOutElastic=, and =Uize.Curve.Rubber.easeMiddleElastic= static methods
160
+ - thanks to `Robert Penner` for his original implementation
161
+
162
+ Uize.Curve.Rubber.easeInOutElastic
163
+ Elastic easing in/out - exponentially building then decaying sine wave.
164
+
165
+ SYNTAX
166
+ ............................................................................
167
+ curveFUNC = Uize.Curve.Rubber.easeInOutElastic (periodFLOAT,amplitudeFLOAT);
168
+ ............................................................................
169
+
170
+ VARIATIONS
171
+ .............................................................
172
+ curveFUNC = Uize.Curve.Rubber.easeInOutElastic (periodFLOAT);
173
+ curveFUNC = Uize.Curve.Rubber.easeInOutElastic ();
174
+ .............................................................
175
+
176
+ For a more in-depth discussion of this method's parameters and variations, consult the reference for the related =Uize.Curve.Rubber.easeInElastic= static method.
177
+
178
+ NOTES
179
+ - see also the companion =Uize.Curve.Rubber.easeInElastic=, =Uize.Curve.Rubber.easeOutElastic=, and =Uize.Curve.Rubber.easeMiddleElastic= static methods
180
+ - thanks to `Robert Penner` for his original implementation
181
+
182
+ Uize.Curve.Rubber.easeMiddleElastic
183
+ Elastic easing in the middle - exponentially decaying then building sine wave.
184
+
185
+ SYNTAX
186
+ .............................................................................
187
+ curveFUNC = Uize.Curve.Rubber.easeMiddleElastic (periodFLOAT,amplitudeFLOAT);
188
+ .............................................................................
189
+
190
+ VARIATIONS
191
+ ..............................................................
192
+ curveFUNC = Uize.Curve.Rubber.easeMiddleElastic (periodFLOAT);
193
+ curveFUNC = Uize.Curve.Rubber.easeMiddleElastic ();
194
+ ..............................................................
195
+
196
+ For a more in-depth discussion of this method's parameters and variations, consult the reference for the related =Uize.Curve.Rubber.easeInElastic= static method.
197
+
198
+ NOTES
199
+ - see also the companion =Uize.Curve.Rubber.easeInElastic=, =Uize.Curve.Rubber.easeOutElastic=, and =Uize.Curve.Rubber.easeInOutElastic= static methods
200
+ - thanks to `Robert Penner` for his original implementation
201
+ */
202
+ );
203
+
204
+ /*** overshoot easing ***/
205
+ _makeEasingCurveGenerators (
206
+ 'back',
207
+ function (_overshoot) {
208
+ /*** paramter defaulting ***/
209
+ if (_overshoot == null) _overshoot = 1.70158;
210
+
211
+ /*** capture some calculation results ***/
212
+ var _overshootPlus1 = _overshoot + 1;
213
+
214
+ return function (_value) {return _value * _value * (_overshootPlus1 * _value - _overshoot)};
215
+ },
216
+ _package
217
+ /*?
218
+ Static Methods
219
+ Uize.Curve.Rubber.easeInBack
220
+ Back easing in - backtracking slightly, then reversing direction and moving to target.
221
+
222
+ SYNTAX
223
+ ..........................................................
224
+ curveFUNC = Uize.Curve.Rubber.easeInBack (overshootFLOAT);
225
+ ..........................................................
226
+
227
+ The =overshootFLOAT= parameter controls the amount of overshoot, and is typically a value in the range of =0= to =Infinity= (although negative values are also supported). Higher positive values for this parameter will produce greater overshoot. The default value of =1.70158= produces 10% overshoot. A value of =0= produces a cubic easing curve with no overshoot. Negative values lower than =-3= for this parameter will produce increasing amounts of overshoot on the opposite side of output value range.
228
+
229
+ VARIATION
230
+ ............................................
231
+ curveFUNC = Uize.Curve.Rubber.easeInBack ();
232
+ ............................................
233
+
234
+ When the optional =overshootFLOAT= parameter is not specified, its value will be defaulted to =1.70158=.
235
+
236
+ NOTES
237
+ - see also the companion =Uize.Curve.Rubber.easeOutBack=, =Uize.Curve.Rubber.easeInOutBack=, and =Uize.Curve.Rubber.easeMiddleBack= static methods
238
+ - thanks to `Robert Penner` for his original implementation
239
+
240
+ Uize.Curve.Rubber.easeOutBack
241
+ Back easing out - moving towards target, overshooting it slightly, then reversing and coming back to target.
242
+
243
+ SYNTAX
244
+ ...........................................................
245
+ curveFUNC = Uize.Curve.Rubber.easeOutBack (overshootFLOAT);
246
+ ...........................................................
247
+
248
+ For an in-depth discussion of the =overshootFLOAT= parameter, consult the reference for the related =Uize.Curve.Rubber.easeInBack= static method.
249
+
250
+ VARIATION
251
+ .............................................
252
+ curveFUNC = Uize.Curve.Rubber.easeOutBack ();
253
+ .............................................
254
+
255
+ When the optional =overshootFLOAT= parameter is not specified, its value will be defaulted to =1.70158=.
256
+
257
+ NOTES
258
+ - see also the companion =Uize.Curve.Rubber.easeInBack=, =Uize.Curve.Rubber.easeInOutBack=, and =Uize.Curve.Rubber.easeMiddleBack= static methods
259
+ - thanks to `Robert Penner` for his original implementation
260
+
261
+ Uize.Curve.Rubber.easeInOutBack
262
+ Back easing in/out - backtracking slightly, then reversing direction and moving to target, then overshooting target, reversing, and finally coming back to target.
263
+
264
+ SYNTAX
265
+ .............................................................
266
+ curveFUNC = Uize.Curve.Rubber.easeInOutBack (overshootFLOAT);
267
+ .............................................................
268
+
269
+ For an in-depth discussion of the =overshootFLOAT= parameter, consult the reference for the related =Uize.Curve.Rubber.easeInBack= static method.
270
+
271
+ VARIATION
272
+ ...............................................
273
+ curveFUNC = Uize.Curve.Rubber.easeInOutBack ();
274
+ ...............................................
275
+
276
+ When the optional =overshootFLOAT= parameter is not specified, its value will be defaulted to =1.70158=.
277
+
278
+ NOTES
279
+ - see also the companion =Uize.Curve.Rubber.easeInBack=, =Uize.Curve.Rubber.easeOutBack=, and =Uize.Curve.Rubber.easeMiddleBack= static methods
280
+ - thanks to `Robert Penner` for his original implementation
281
+
282
+ Uize.Curve.Rubber.easeMiddleBack
283
+ Back easing in the middle - overshooting the middle, backtracking to the middle, then backtracking even further towards the beginning, then finally moving to target.
284
+
285
+ SYNTAX
286
+ ..............................................................
287
+ curveFUNC = Uize.Curve.Rubber.easeMiddleBack (overshootFLOAT);
288
+ ..............................................................
289
+
290
+ For an in-depth discussion of the =overshootFLOAT= parameter, consult the reference for the related =Uize.Curve.Rubber.easeInBack= static method.
291
+
292
+ VARIATION
293
+ ................................................
294
+ curveFUNC = Uize.Curve.Rubber.easeMiddleBack ();
295
+ ................................................
296
+
297
+ When the optional =overshootFLOAT= parameter is not specified, its value will be defaulted to =1.70158=.
298
+
299
+ NOTES
300
+ - see also the companion =Uize.Curve.Rubber.easeInBack=, =Uize.Curve.Rubber.easeOutBack=, and =Uize.Curve.Rubber.easeInOutBack= static methods
301
+ - thanks to `Robert Penner` for his original implementation
302
+ */
303
+ );
304
+
305
+ /*** bounce easing ***/
306
+ var _defaultBouncePeakCurveFunction = _host.easeInSweetPow (1.76);
307
+ _makeEasingCurveGenerators (
308
+ 'bounce',
309
+ function (_bounces,_bouncePeakCurveFunction,_bounceWidthRatio,_bounceCurveFunction) {
310
+ /*** parameter defaulting ***/
311
+ if (!_bounces) _bounces = 4;
312
+ _bouncePeakCurveFunction =
313
+ _resolve (_bouncePeakCurveFunction,_defaultBouncePeakCurveFunction,true)
314
+ ;
315
+ _bounceWidthRatio = !_bounceWidthRatio
316
+ ? 2 // 0, null, or undefined, so default to 2
317
+ : _bounceWidthRatio * _bounceWidthRatio == 1
318
+ ? 1.0001 // 1 or -1, so make sure it's not 1, since 1 breaks formula
319
+ : _bounceWidthRatio < 0
320
+ ? -1 / _bounceWidthRatio // negative, so negate and invert
321
+ : _bounceWidthRatio
322
+ ;
323
+ _bounceCurveFunction = _resolve (_bounceCurveFunction,2);
324
+
325
+ /*** pre-calculate profiles for bounces ***/
326
+ function _cumulativeWidth (_bounces) {return (Math.pow (_base,_bounces) - 1) / (_base - 1)}
327
+ var
328
+ _base = _bounceWidthRatio,
329
+ _baseMinus1 = _base - 1,
330
+ _bouncesMinus1 = _bounces - 1,
331
+ _bouncesWidthShown =
332
+ _cumulativeWidth (_bounces) /* combined width of all bounces */ -
333
+ Math.pow (_base,_bouncesMinus1) /* width of widest bounce */ / 2,
334
+ _logBase = Math.log (_base),
335
+ _bounceProfiles = []
336
+ ;
337
+ for (var _bounceNo = -1; ++_bounceNo < _bounces;) {
338
+ var
339
+ _bounceStartPos = _cumulativeWidth (_bounceNo),
340
+ _widthDiv2 = (_cumulativeWidth (_bounceNo + 1) /* bounce end pos */ - _bounceStartPos) / 2,
341
+ _bounceMidPos = _bounceStartPos + _widthDiv2
342
+ ;
343
+ _bounceProfiles.push ({
344
+ _height:_bouncePeakCurveFunction (_bounceMidPos / _bouncesWidthShown),
345
+ _midPos:_bounceMidPos,
346
+ _widthDiv2:_widthDiv2
347
+ });
348
+ }
349
+
350
+ return function (_value) {
351
+ var
352
+ _pos = _value * _bouncesWidthShown,
353
+ _bounceProfile = _bounceProfiles [
354
+ Uize.constrain (Math.floor (Math.log (_pos * _baseMinus1 + 1) / _logBase),0,_bouncesMinus1)
355
+ ]
356
+ ;
357
+ return _bounceProfile._height * (
358
+ _bounceCurveFunction (1 - Math.abs (_pos - _bounceProfile._midPos) / _bounceProfile._widthDiv2)
359
+ );
360
+ }
361
+ },
362
+ _package
363
+ /*?
364
+ Static Methods
365
+ Uize.Curve.Rubber.easeInBounce
366
+ Bounce, easing in.
367
+
368
+ SYNTAX
369
+ .......................................................................................
370
+ curveFUNC = Uize.Curve.Rubber.easeInBounce (
371
+ bouncesINT, // number of bounces (optional)
372
+ bouncePeakCurveFUNCorFLOAT, // bounciness, essentially (optional)
373
+ bounceWidthRatioFLOAT, // ratio of current bounce width to previous (optional)
374
+ bounceCurveFUNCorFLOAT // the shape of the curve of a bounce (optional)
375
+ );
376
+ .......................................................................................
377
+
378
+ Parameters
379
+ bouncesINT
380
+ An integer, specifying the number of bounces in the curve, with the default number of bounces being =4=.
381
+
382
+ bouncePeakCurveFUNCorFLOAT
383
+ A function reference for a curve function, or a numerical value that will be resolved to a power curve function using the =Uize.Curve.resolve= method.
384
+
385
+ This paramter can be used to affect the bounciness or springiness of each bounce. Numerical values above =1= will produce progressively bouncier curves as the value of =bouncePeakCurveFUNCorFLOAT= is increased. Numerical values below =-1= will produce progressively more dampened curves as the value of =bouncePeakCurveFUNCorFLOAT= is decreased.
386
+
387
+ When determining the height of the peak of an individual bounce, a curve function specified for the =bouncePeakCurveFUNCorFLOAT= parameter will be used to obtain a value, using the position of the midpoint of the bounce along the x-axis as the input value to the bounce peak curve function. Because the specified bounce peak curve is only sampled at the bounce midpoints, bounce peak curves with high amounts of detail will not affect the shape of the bounces, but only the heights of the bounce peaks (so detail will be lost, in other words).
388
+
389
+ For a linear curve, the value =1= can be specified for this parameter. The default value for this parameter is =1.76=.
390
+
391
+ bounceWidthRatioFLOAT
392
+ A floating point number, specifying the ratio between the width of the current bounce and the width of the previous bounce.
393
+
394
+ The default value for this parameter is =2=, which means that each bounce will be twice as wide as the previous bounce. When the value =1= is specified for this parameter, all bounces will have the same width. When negative values are specified for this parameter, then ratio will be resolved to a positive number by negating it and inverting it (dividing it into =1=). In other words, the value =-2= will result in a resolved ratio of =.5=, which will result in each bounce being half the width of the previous bounce. You can think of the values in the negative scale as being the ratio of the width of the current bounce to the width of the next bounce (once negated, of course).
395
+
396
+ For values of this parameter greater than =1=, the higher the value, the less noticeable changing the number of bounces with the =bouncesINT= parameter will become. Similarly, on the opposite side of the spectrum, for values of =bounceWidthRatioFLOAT= less than =-1=, the lower the value, the less noticeable changing the number of bounces will become. If each bounce is much smaller or larger than the previous bounce, the bounces at one end of the curve will become very small and barely noticeable.
397
+
398
+ NOTE
399
+
400
+ It should be noted that for the ease-out version of this curve, and for the the ease-out phase of the ease-in-out and ease-in-the-middle versions of this curve, the bounce width ratio is actually the ratio of the width of the current bounce to the width of the next bounce. This is as a result of the curve being rotated 180 degrees.
401
+
402
+ bounceCurveFUNCorFLOAT
403
+ A function reference for a curve function, or a numerical value that will be resolved to a power curve function using the =Uize.Curve.resolve= method.
404
+
405
+ The curve specified by the =bounceCurveFUNCorFLOAT= parameter will be used to generate points along the curve of an individual bounce. The specified curve is used to produce both the left and right halves of a bounce curve, on either side of the bounce's midpoint on the x-axis. For the opposite half, the bounce curve is flipped horizontally. The default value for this parameter is =2=, which produces bounces using a quadratic ease-out power curve.
406
+
407
+ VARIATION 1
408
+ ..............................................................
409
+ curveFUNC = Uize.Curve.Rubber.easeInBounce (
410
+ bouncesINT,bouncePeakCurveFUNCorFLOAT,bounceWidthRatioFLOAT
411
+ );
412
+ ..............................................................
413
+
414
+ When no =bounceCurveFUNCorFLOAT= parameter is specified, its value will be defaulted to =2=, representing a quadratic ease-out curve function.
415
+
416
+ VARIATION 2
417
+ ...................................................................................
418
+ curveFUNC = Uize.Curve.Rubber.easeInBounce (bouncesINT,bouncePeakCurveFUNCorFLOAT);
419
+ ...................................................................................
420
+
421
+ When no =bounceWidthRatioFLOAT= parameter is specified, its value will be defaulted to =2= (each bounce will be twice the width of the previous bounce).
422
+
423
+ VARIATION 3
424
+ ........................................................
425
+ curveFUNC = Uize.Curve.Rubber.easeInBounce (bouncesINT);
426
+ ........................................................
427
+
428
+ When no =bouncePeakCurveFUNCorFLOAT= parameter is specified, its value will be defaulted to =1.76=.
429
+
430
+ VARIATION 4
431
+ ..............................................
432
+ curveFUNC = Uize.Curve.Rubber.easeInBounce ();
433
+ ..............................................
434
+
435
+ When no =bouncesINT= parameter is specified, its value will be defaulted to =4=.
436
+
437
+ NOTES
438
+ - see also the companion =Uize.Curve.Rubber.easeOutBounce=, =Uize.Curve.Rubber.easeInOutBounce=, and =Uize.Curve.Rubber.easeMiddleBounce= static methods
439
+
440
+ Uize.Curve.Rubber.easeOutBounce
441
+ Bounce, easing out.
442
+
443
+ SYNTAX
444
+ .......................................................................................
445
+ curveFUNC = Uize.Curve.Rubber.easeOutBounce (
446
+ bouncesINT, // number of bounces (optional)
447
+ bouncePeakCurveFUNCorFLOAT, // bounciness, essentially (optional)
448
+ bounceWidthRatioFLOAT, // ratio of current bounce width to next (optional)
449
+ bounceCurveFUNCorFLOAT // the shape of the curve of a bounce (optional)
450
+ );
451
+ .......................................................................................
452
+
453
+ VARIATIONS
454
+ ....................................................................................
455
+ curveFUNC = Uize.Curve.Rubber.easeOutBounce (
456
+ bouncesINT,bouncePeakCurveFUNCorFLOAT,bounceWidthRatioFLOAT
457
+ );
458
+
459
+ curveFUNC = Uize.Curve.Rubber.easeOutBounce (bouncesINT,bouncePeakCurveFUNCorFLOAT);
460
+
461
+ curveFUNC = Uize.Curve.Rubber.easeOutBounce (bouncesINT);
462
+
463
+ curveFUNC = Uize.Curve.Rubber.easeOutBounce ();
464
+ ....................................................................................
465
+
466
+ For a more in-depth discussion of this method's parameters and variations, consult the reference for the related =Uize.Curve.Rubber.easeInBounce= static method.
467
+
468
+ NOTES
469
+ - see also the companion =Uize.Curve.Rubber.easeInBounce=, =Uize.Curve.Rubber.easeInOutBounce=, and =Uize.Curve.Rubber.easeMiddleBounce= static methods
470
+
471
+ Uize.Curve.Rubber.easeInOutBounce
472
+ Bounce, easing in/out.
473
+
474
+ SYNTAX
475
+ .......................................................................................
476
+ curveFUNC = Uize.Curve.Rubber.easeInOutBounce (
477
+ bouncesINT, // number of bounces (optional)
478
+ bouncePeakCurveFUNCorFLOAT, // bounciness, essentially (optional)
479
+ bounceWidthRatioFLOAT, // ratio of current bounce width to previous (optional)
480
+ bounceCurveFUNCorFLOAT // the shape of the curve of a bounce (optional)
481
+ );
482
+ .......................................................................................
483
+
484
+ VARIATIONS
485
+ ......................................................................................
486
+ curveFUNC = Uize.Curve.Rubber.easeInOutBounce (
487
+ bouncesINT,bouncePeakCurveFUNCorFLOAT,bounceWidthRatioFLOAT
488
+ );
489
+
490
+ curveFUNC = Uize.Curve.Rubber.easeInOutBounce (bouncesINT,bouncePeakCurveFUNCorFLOAT);
491
+
492
+ curveFUNC = Uize.Curve.Rubber.easeInOutBounce (bouncesINT);
493
+
494
+ curveFUNC = Uize.Curve.Rubber.easeInOutBounce ();
495
+ ......................................................................................
496
+
497
+ For a more in-depth discussion of this method's parameters and variations, consult the reference for the related =Uize.Curve.Rubber.easeInBounce= static method.
498
+
499
+ NOTES
500
+ - see also the companion =Uize.Curve.Rubber.easeInBounce=, =Uize.Curve.Rubber.easeOutBounce=, and =Uize.Curve.Rubber.easeMiddleBounce= static methods
501
+
502
+ Uize.Curve.Rubber.easeMiddleBounce
503
+ Bounce, easing in the middle.
504
+
505
+ SYNTAX
506
+ .......................................................................................
507
+ curveFUNC = Uize.Curve.Rubber.easeMiddleBounce (
508
+ bouncesINT, // number of bounces (optional)
509
+ bouncePeakCurveFUNCorFLOAT, // bounciness, essentially (optional)
510
+ bounceWidthRatioFLOAT, // ratio of current bounce width to previous (optional)
511
+ bounceCurveFUNCorFLOAT // the shape of the curve of a bounce (optional)
512
+ );
513
+ .......................................................................................
514
+
515
+ VARIATIONS
516
+ .......................................................................................
517
+ curveFUNC = Uize.Curve.Rubber.easeMiddleBounce (
518
+ bouncesINT,bouncePeakCurveFUNCorFLOAT,bounceWidthRatioFLOAT
519
+ );
520
+
521
+ curveFUNC = Uize.Curve.Rubber.easeMiddleBounce (bouncesINT,bouncePeakCurveFUNCorFLOAT);
522
+
523
+ curveFUNC = Uize.Curve.Rubber.easeMiddleBounce (bouncesINT);
524
+
525
+ curveFUNC = Uize.Curve.Rubber.easeMiddleBounce ();
526
+ .......................................................................................
527
+
528
+ For a more in-depth discussion of this method's parameters and variations, consult the reference for the related =Uize.Curve.Rubber.easeInBounce= static method.
529
+
530
+ NOTES
531
+ - see also the companion =Uize.Curve.Rubber.easeInBounce=, =Uize.Curve.Rubber.easeOutBounce=, and =Uize.Curve.Rubber.easeInOutBounce= static methods
532
+ */
533
+ );
534
+
535
+ return _package;
536
+ }
537
+ });
538
+
skin/frontend/default/customproduct/js/Uize.Curve.js ADDED
@@ -0,0 +1,854 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ /*______________
2
+ | ______ | U I Z E J A V A S C R I P T F R A M E W O R K
3
+ | / / | ---------------------------------------------------
4
+ | / O / | MODULE : Uize.Curve Package
5
+ | / / / |
6
+ | / / / /| | ONLINE : http://www.uize.com
7
+ | /____/ /__/_| | COPYRIGHT : (c)2009-2012 UIZE
8
+ | /___ | LICENSE : Available under MIT License or GNU General Public License
9
+ |_______________| http://www.uize.com/license.html
10
+ */
11
+
12
+ /* Module Meta Data
13
+ type: Package
14
+ importance: 6
15
+ codeCompleteness: 100
16
+ testCompleteness: 0
17
+ docCompleteness: 100
18
+ */
19
+
20
+ /*?
21
+ Introduction
22
+ The =Uize.Curve= module provides a namespace and services for curve related modules, and provides a number of useful built-in curve function generators.
23
+
24
+ *DEVELOPERS:* `Chris van Rensburg`, with thanks to `Robert Penner` for his easing equations work
25
+
26
+ The =Uize.Curve= module defines a namespace for other curve related modules (such as the =Uize.Curve.Rubber= and =Uize.Curve.Mod= modules), that provides some basic services that are useful for creating such curve related modules, and that also provides a number of the more commonly used curve function generators as built-ins.
27
+
28
+ In a Nutshell
29
+ The =Uize.Curve= module provides built-in curve function generators for power easing curves, "sweetened" power easing curves, sinusoidal easing curves, circular easing curves, exponential easing curves, and basic straight line curves.
30
+
31
+ This module also provides curve function modifiers for making ease-out, ease-in-out, and ease-in-the-middle curve functions from ease-in curve functions, as well as a method for making ease-in, ease-out, ease-in-out, and ease-in-the-middle curve function generators from an ease-in curve function generator. Finally, miscellaneous services are provided that are useful for other curve related modules, such as the =Uize.Curve.linear= curve function, =Uize.Curve.resolve= static method, etc.
32
+
33
+ BACKGROUND READING
34
+
35
+ For an in-depth discussion on animation in the UIZE JavaScript Framework, and for a discussion on how this module fits into the larger picture, consult the explainer [[../explainers/javascript-animation-and-effects.html][JavaScript Animation and Effects]] and read through the section `Curves`.
36
+ */
37
+
38
+ Uize.module ({
39
+ name:'Uize.Curve',
40
+ builder:function () {
41
+ var _package = function () {};
42
+
43
+ /*** Variables for Scruncher Optimization ***/
44
+ var _undefined;
45
+
46
+ /*** Public Static Methods ***/
47
+ var
48
+ _blendFloats = _package.blendFloats = function (_valueA,_valueB,_blend) {
49
+ return _valueA + (_valueB - _valueA) * _blend
50
+ /*?
51
+ Static Methods
52
+ Uize.Curve.blendFloats
53
+ Returns a floating point number, that is the blend between the two specified floating point numbers, using the specified blend amount.
54
+
55
+ SYNTAX
56
+ ...............................................................................
57
+ blendedFLOAT = Uize.Curve.blendFloats (value1FLOAT,value2FLOAT,blend0to1FLOAT);
58
+ ...............................................................................
59
+
60
+ When the value =0= is specified for the =blend0to1FLOAT= parameter, the value of the =value1FLOAT= parameter will be returned. When the value =1= is specified for =blend0to1FLOAT=, then the value of =value2FLOAT= will be returned. And when the value =.5= is specified for =blend0to1FLOAT=, then the returned value will be an equal blend between the values of =value1FLOAT= and =value2FLOAT=. The blend between the values of =value1FLOAT= and =value2FLOAT=, as specified by the =blend0to1FLOAT= parameter, is a simple linear interpolation.
61
+
62
+ NOTES
63
+ - compare to the =Uize.Curve.makeBlender= static method
64
+ */
65
+ },
66
+ _linear = _package.linear = Uize.returnX,
67
+ /*?
68
+ Static Methods
69
+ Uize.Curve.linear
70
+ A simple linear curve function (ie. *NOT* a curve function generator) that merely returns the value that is passed into it.
71
+
72
+ SYNTAX
73
+ ................................................
74
+ valueANYTYPE = Uize.Curve.linear (valueANYTYPE);
75
+ ................................................
76
+
77
+ This method / curve function is useful for curve function modifiers that expect curve functions as parameters. One is not likely to call this method directly, but instead supply it - by reference - as a parameter to other methods.
78
+
79
+ NOTES
80
+ - compare to the =Uize.Curve.line= static method
81
+ */
82
+ _makeEaseOut = _package.makeEaseOut = function (_curveFunction) {
83
+ return function (_value) {return 1 - _curveFunction (1 - _value)}
84
+ /*?
85
+ Static Methods
86
+ Uize.Curve.makeEaseOut
87
+ Returns an ease-out curve function, that is the 180 degree rotated version of the specified ease-in curve function.
88
+
89
+ SYNTAX
90
+ ............................................................
91
+ easeOutCurveFUNC = Uize.Curve.makeEaseOut (easeInCurveFUNC);
92
+ ............................................................
93
+
94
+ Assuming that the curve function specified by the =easeInCurveFUNC= parameter is truly for an ease-in curve function, then the curve function that is returned by this method will effectively be an ease-out curve function.
95
+
96
+ NOTES
97
+ - see the related =Uize.Curve.makeEaseInOut=, =Uize.Curve.makeEaseMiddle=, and =Uize.Curve.makeEasingCurveGenerators= static methods
98
+ */
99
+ },
100
+ _makeEaseInOut = _package.makeEaseInOut = function (_curveFunction) {
101
+ return function (_value) {
102
+ return ((_value *= 2) < 1 ? _curveFunction (_value) : 2 - _curveFunction (2 - _value)) / 2;
103
+ }
104
+ /*?
105
+ Static Methods
106
+ Uize.Curve.makeEaseInOut
107
+ Returns an ease-in-out curve function, that uses the specified ease-in curve function to produce a two phase curve that has an ease-in phase followed by an ease-out phase.
108
+
109
+ SYNTAX
110
+ ................................................................
111
+ easeInOutCurveFUNC = Uize.Curve.makeEaseInOut (easeInCurveFUNC);
112
+ ................................................................
113
+
114
+ Assuming that the curve function specified by the =easeInCurveFUNC= parameter is truly for an ease-in curve function, then the curve function that is returned by this method will effectively be an ease-in-out curve function.
115
+
116
+ NOTES
117
+ - see the related =Uize.Curve.makeEaseOut=, =Uize.Curve.makeEaseMiddle=, and =Uize.Curve.makeEasingCurveGenerators= static methods
118
+ */
119
+ },
120
+ _makeEaseMiddle = _package.makeEaseMiddle = function (_curveFunction) {
121
+ return function (_value) {
122
+ return ((_value *= 2) < 1 ? 1 - _curveFunction (1 - _value) : 1 + _curveFunction (_value - 1)) / 2;
123
+ }
124
+ /*?
125
+ Static Methods
126
+ Uize.Curve.makeEaseMiddle
127
+ Returns an ease-in-the-middle curve function, that uses the specified ease-in curve function to produce a two phase curve that has an ease-out phase followed by an ease-in phase.
128
+
129
+ SYNTAX
130
+ ..................................................................
131
+ easeMiddleCurveFUNC = Uize.Curve.makeEaseMiddle (easeInCurveFUNC);
132
+ ..................................................................
133
+
134
+ Assuming that the curve function specified by the =easeInCurveFUNC= parameter is truly for an ease-in curve function, then the curve function that is returned by this method will effectively be an ease-in-the-middle curve function.
135
+
136
+ NOTES
137
+ - see the related =Uize.Curve.makeEaseOut=, =Uize.Curve.makeEaseInOut=, and =Uize.Curve.makeEasingCurveGenerators= static methods
138
+ */
139
+ },
140
+ _makeEasingCurveGenerators = _package.makeEasingCurveGenerators = function (
141
+ _methodNameSuffix,_easeInCurveGenerator,_context
142
+ ) {
143
+ var _paramless = {};
144
+ if (!_context) _context = _package;
145
+ _methodNameSuffix = Uize.capFirstChar (_methodNameSuffix);
146
+
147
+ function _makeCurveGenerator (_easeType,_easingCurveGeneratorMaker) {
148
+ _context ['ease' + _easeType + _methodNameSuffix] = function () {
149
+ return (
150
+ arguments.length
151
+ ? _easingCurveGeneratorMaker (_easeInCurveGenerator.apply (0,arguments))
152
+ :
153
+ _paramless [_easeType] ||
154
+ (
155
+ _paramless [_easeType] =
156
+ _easingCurveGeneratorMaker (
157
+ _paramless.In || (_paramless.In = _easeInCurveGenerator ()))
158
+ )
159
+ )
160
+ };
161
+ }
162
+ _makeCurveGenerator ('In',_linear);
163
+ _makeCurveGenerator ('Out',_makeEaseOut);
164
+ _makeCurveGenerator ('InOut',_makeEaseInOut);
165
+ _makeCurveGenerator ('Middle',_makeEaseMiddle);
166
+ /*?
167
+ Static Methods
168
+ Uize.Curve.makeEasingCurveGenerators
169
+ Makes static methods for generating an ease-in curve function, ease-out curve function, ease-in-out curve function, and ease-in-the-middle curve function, using the specified ease-in curve function generator.
170
+
171
+ SYNTAX
172
+ ......................................
173
+ Uize.Curve.makeEasingCurveGenerators (
174
+ methodNameSuffixSTR,
175
+ easeInCurveGeneratorFUNC,
176
+ contextOBJ
177
+ );
178
+ ......................................
179
+
180
+ This method is provided as a convenience to make it easier to spawn easing curve function generators for different types of curves. The =Uize.Curve= module, itself, uses this method to create its many curve function generator methods, as does the =Uize.Curve.Rubber= module.
181
+
182
+ Parameters
183
+ The =Uize.Curve.makeEasingCurveGenerators= method supports the following parameters...
184
+
185
+ methodNameSuffixSTR
186
+ A string, specifying the suffix of the method names for the four static methods that are created.
187
+
188
+ The static methods created by this method are named with the prefixes "easeIn", "easeOut", "easeInOut", and "easeMiddle". When creating easing curve function generators in a context that will have other curve function generators, the suffix allows you to distinguish between the curve function generators for different types of curves. The first letter of the specified suffix is uppercased before appending it to the method name prefixes.
189
+
190
+ For example, with the methods =Uize.Curve.easeInSine=, =Uize.Curve.easeOutSine=, =Uize.Curve.easeInOutSine=, and =Uize.Curve.easeMiddleSine=, the value used for =methodNameSuffixSTR= would be ='Sine'= (or ='sine'=). With the methods =Uize.Curve.easeInExpo=, =Uize.Curve.easeOutExpo=, =Uize.Curve.easeInOutExpo=, and =Uize.Curve.easeMiddleExpo=, the value used for =methodNameSuffixSTR= would be ='Expo'= (or ='expo'=).
191
+
192
+ easeInCurveGeneratorFUNC
193
+ A function, being the curve function generator for the ease-in curve function from which you would like to derive the ease-in, ease-out, ease-in-out, and ease-middle curve function generator static methods.
194
+
195
+ contextOBJ
196
+ An object, specifying the context for the curve function generators.
197
+
198
+ This parameter is optional - when a value is not specified for it, its value will be defaulted to =Uize.Curve=. Using this parameter, you could assign the curve function generators to a module other than =Uize.Curve=. For example, the =Uize.Curve.Rubber= module uses the =Uize.Curve.makeEasingCurveGenerators= method to create its curve function generators and specifies a reference to =Uize.Curve.Rubber= as the value for the =contextOBJ= parameter.
199
+
200
+ TIP
201
+
202
+ If you wish to assign the curve function generators on the actual ease-in curve function generator, then you can specify the curve function generator as the value for the =contextOBJ= parameter and then specify the value =''= (empty string) for the =methodNameSuffixSTR= parameter.
203
+
204
+ Examples
205
+ The following examples illustrate different uses of the =Uize.Curve.makeEasingCurveGenerators= method...
206
+
207
+ EXAMPLE 1
208
+ ..............................................................
209
+ Uize.Curve.makeEasingCurveGenerators (
210
+ 'Power',
211
+ function (power) {
212
+ if (power == null) power = 2;
213
+ return function (value) {return Math.pow (value,power)};
214
+ }
215
+ );
216
+
217
+ // now you can call the newly created static methods...
218
+
219
+ Uize.Curve.easeInPower ();
220
+ Uize.Curve.easeInPower (2);
221
+ Uize.Curve.easeOutPower (3);
222
+ Uize.Curve.easeInOutPower (2.5);
223
+ Uize.Curve.easeMiddlePower (3.1);
224
+ ..............................................................
225
+
226
+ In the above example, the traditional approach is being used to create easing curve function generators that are accessed off of the =Uize.Curve= module (the default context). Because the value ='Power'= is specified for the =methodNameSuffixSTR= parameter, the created methods names are =easeInPower=, =easeOutPower=, =easeInOutPower=, and =easeMiddlePower=.
227
+
228
+ EXAMPLE 2
229
+ ................................................................
230
+ function powerCurve (power) {
231
+ if (power == null) power = 2;
232
+ return function (value) {return Math.pow (value,power)};
233
+ };
234
+ Uize.Curve.makeEasingCurveGenerators ('',powerCurve,powerCurve);
235
+
236
+ // now you can call the newly created static methods...
237
+
238
+ powerCurve.easeIn (); // equivalent to powerCurve (2)
239
+ powerCurve.easeIn (2); // equivalent to powerCurve (2)
240
+ powerCurve.easeOut (3);
241
+ powerCurve.eastInOut (2.5);
242
+ powerCurve.easeMiddle (3.1);
243
+ ................................................................
244
+
245
+ In the above example, the ease-in curve function generator is being used as the context for the easing curve function generators. This is done by specifying the =powerCurve= function not only as the value for the =easeInCurveGeneratorFUNC= parameter, but also as the value for the =contextOBJ= parameter. Then, specifying the value =''= (empty string) for the =methodNameSuffixSTR= parameter means that the methods accessed off of =powerCurve= are named simply =easeIn=, =easeOut=, =easeInOut=, and =easeMiddle=.
246
+
247
+ Caching of Paramless Versions
248
+ As an optimization, the =Uize.Curve.makeEasingCurveGenerators= method caches the results of the paramless calls to the curve functions generators that it creates.
249
+
250
+ This means that the statement =Uize.Curve.easeOutPow ()= will always return a reference to the same curve function - for a quadratic ease-out curve. In contrast, the statement =Uize.Curve.easeOutPow (3)= will always return different curve functions - even though they will always do the same thing (ie. produce a cubic ease-out curve).
251
+
252
+ NOTES
253
+ - see the related =Uize.Curve.makeEaseOut=, =Uize.Curve.makeEaseInOut=, and =Uize.Curve.makeEaseMiddle= static methods
254
+ */
255
+ }
256
+ ;
257
+
258
+ _package.makeBlender = function (_curveFunction) {
259
+ _curveFunction = _package.resolve (_curveFunction);
260
+ return function (_valueA,_valueB,_blend) {return _blendFloats (_valueA,_valueB,_curveFunction (_blend))};
261
+ /*?
262
+ Static Methods
263
+ Uize.Curve.makeBlender
264
+ Return a blender function, that will use the specified curve function when blending between two values.
265
+
266
+ SYNTAX
267
+ ........................................................
268
+ blenderFUNC = Uize.Curve.makeBlender (curveFUNCorFLOAT);
269
+ ........................................................
270
+
271
+ The blender function that is returned by this method has the same signature as the =Uize.Curve.blendFloats= static method and accepts three parameters: =value1FLOAT=, =value2FLOAT=, and =blend0to1FLOAT=.
272
+
273
+ EXAMPLE
274
+ ..................................................................................
275
+ var
276
+ bouncyBlender = Uize.Curve.makeBlender (Uize.Curve.Rubber.easeOutBounce (4,2)),
277
+ middleOfBounceValue = bouncyBlender (0,255,.5) // result is 90.4438142188662
278
+ ;
279
+ ..................................................................................
280
+
281
+ In the above example, the =middleOfBounceValue= variable will be left with the value =90.4438142188662=, being the value halfway between =0= and =255= on an extra bouncy ease-out bounce curve with four bounces.
282
+
283
+ NOTES
284
+ - compare to the =Uize.Curve.blendFloats= static method
285
+ - numerical values for the =curveFUNCorFLOAT= parameter are resolved to curve functions using the =Uize.Curve.resolve= static method
286
+ */
287
+ };
288
+
289
+ _package.resolve = function (_curveFunction,_defaultCurveFunction,_sweet,_polarity) {
290
+ if (_curveFunction == _undefined) _curveFunction = _defaultCurveFunction;
291
+ return (
292
+ Uize.isFunction (_curveFunction) || Uize.isArray (_curveFunction)
293
+ ? _curveFunction
294
+ : !_curveFunction || _curveFunction * _curveFunction == 1
295
+ ? _linear
296
+ : _package [
297
+ (_curveFunction * (_polarity || 1) < 0 ? 'easeIn' : 'easeOut') + (_sweet ? 'Sweet' : '') + 'Pow'
298
+ ] (
299
+ Math.abs (_curveFunction)
300
+ )
301
+ )
302
+ /*?
303
+ Static Methods
304
+ Uize.Curve.resolve
305
+ Resolves the specified curve function or power curve value to a curve function and returns it.
306
+
307
+ SYNTAX
308
+ ...................................................................................
309
+ curveFUNC = Uize.Curve.resolve (
310
+ curveFUNCorFLOAT, // value to be resolved to a curve function (optional)
311
+ defaultCurveFUNCorFLOAT, // default curve function or power (optional)
312
+ sweetBOOL, // use sweetened power curve functions (optional)
313
+ polarityINT // polarity, in case negating is desired (optional)
314
+ );
315
+ ...................................................................................
316
+
317
+ This method can be useful when implementing your own curve function generators - for either complex curves or for curve function modifiers - and when such curve function generators wish to support the numerical shorthand for specifying power curve functions for parameters that are curve functions.
318
+
319
+ A good example of this is the =Uize.Curve.Mod.bend= static method of the =Uize.Curve.Mod= module. This method accepts a curve and then bends it horizontally and/or vertically, using specified curves for both horizontal and vertical bending. In most simple cases, power curve functions are effective for achieving smooth / regular bending. The =Uize.Curve.Mod.bend= method supports numerical values for its =horzBendFLOATorFUNC= and =vertBendFLOATorFUNC= parameters (a convenience provided to applications that wish to use the method), and its implementation uses the =Uize.Curve.resolve= method to resolve these numerical values to actual curve functions.
320
+
321
+ Parameters
322
+ The =Uize.Curve.resolve= method supports the following parameters...
323
+
324
+ curveFUNCorFLOAT
325
+ A curve function, or a number that should be used to generate a power curve function.
326
+
327
+ Handling for different types of values is as follows...
328
+
329
+ - *function* - When a function is specified, it will simply be returned as is.
330
+
331
+ - *array* - When an array is specified, it will simply be returned as is.
332
+
333
+ - *positive number* - When a positive number is specified, then an ease-out power curve function will be returned of that power. For example, the statement =Uize.Curve.resolve (3)= would be equivalent to the statement =Uize.Curve.easeOutPow (3)= (provided the value =true= is *not* specified for the optional =sweetBOOL= parameter, and the value =-1= is *not* specified for the optional =polarityINT= parameter).
334
+
335
+ - *negative number* - When a negative number is specified, then an ease-in power curve function will be returned of the negative of that power. For example, the statement =Uize.Curve.resolve (-3)= would be equivalent to the statement =Uize.Curve.easeInPow (3)= (provided the value =true= is *not* specified for the optional =sweetBOOL= parameter, and the value =-1= is *not* specified for the optional =polarityINT= parameter).
336
+
337
+ - *-1, 0, or 1* - When either of the values =-1=, =0=, or =1= is specified, then a reference to =Uize.Curve.linear= (a linear curve function) will be returned.
338
+
339
+ - *not defined* - When either of the values =null= or =undefined= is specified, then the =curveFUNCorFLOAT= parameter will be defaulted to the value of the optional =defaultCurveFUNCorFLOAT= parameter.
340
+
341
+ defaultCurveFUNCorFLOAT
342
+ A curve function, or a number that should be used to generate a power curve function, that should be used as the default curve if the value =null= or =undefined= is specified for the =curveFUNCorFLOAT= parameter.
343
+
344
+ When the optional =defaultCurveFUNCorFLOAT= parameter is specified, a curve other than a linear curve can be used as the default. When the =defaultCurveFUNCorFLOAT= parameter is not specified, =Uize.Curve.linear= (a linear curve function) will be used as the default curve.
345
+
346
+ sweetBOOL
347
+ A boolean, specifying whether or not the "sweetened" versions of the power curve functions should be used when a number is specified for the =curveFUNCorFLOAT= parameter.
348
+
349
+ - =false= - When the value =false= is specified, the =Uize.Curve.easeInPow= static method will be used for resolving negative number values of =curveFUNCorFLOAT=, and the =Uize.Curve.easeOutPow= static method will be used for resolving positive number values of =curveFUNCorFLOAT=.
350
+
351
+ - =true= - When the value =true= is specified, the =Uize.Curve.easeInSweetPow= static method will be used for resolving negative number values of =curveFUNCorFLOAT=, and the =Uize.Curve.easeOutSweetPow= static method will be used for resolving positive number values of =curveFUNCorFLOAT=.
352
+
353
+ When the optional =sweetBOOL= parameter is not specified, its value will be defaulted to =false=.
354
+
355
+ polarityINT
356
+ An integer, specifying whether or not numerical values for the =curveFUNCorFLOAT= parameter should be negated (ie. multiplied by =-1=).
357
+
358
+ - =1= - When the value =1= is specified, numerical values for =curveFUNCorFLOAT= will be unaltered.
359
+
360
+ - =-1= - When the value =-1= is specified, numerical values for =curveFUNCorFLOAT= will be negated.
361
+
362
+ When the optional =polarityINT= parameter is not specified, its value will be defaulted to =1=.
363
+
364
+ Variations
365
+ VARIATION 1
366
+ ...................................................................................
367
+ curveFUNC = Uize.Curve.resolve (curveFUNCorFLOAT,defaultCurveFUNCorFLOATsweetBOOL);
368
+ ...................................................................................
369
+
370
+ When the optional =polarityINT= parameter is not specified, its value will be defaulted to =1= and there will be no polarity inversion when a number is specified for the =curveFUNCorFLOAT= parameter.
371
+
372
+ VARIATION 2
373
+ ..........................................................................
374
+ curveFUNC = Uize.Curve.resolve (curveFUNCorFLOAT,defaultCurveFUNCorFLOAT);
375
+ ..........................................................................
376
+
377
+ When the optional =sweetBOOL= parameter is not specified, its value will be defaulted to =false= and the standard power curve function generators =Uize.Curve.easeInPow= and =Uize.Curve.easeOutPow= will be used when a number is specified for the =curveFUNCorFLOAT= parameter.
378
+
379
+ VARIATION 3
380
+ ..................................................
381
+ curveFUNC = Uize.Curve.resolve (curveFUNCorFLOAT);
382
+ ..................................................
383
+
384
+ When the optional =defaultCurveFUNCorFLOAT= parameter is not specified, its value will be defaulted to =Uize.Curve.linear= and a linear curve function will be returned when the values =null= or =undefined= are specified for the =curveFUNCorFLOAT= parameter.
385
+
386
+ VARIATION 4
387
+ ..................................
388
+ curveFUNC = Uize.Curve.resolve ();
389
+ ..................................
390
+
391
+ When no parameters are specified, then a linear curve function (a reference to =Uize.Curve.linear=) will be returned.
392
+ */
393
+ };
394
+
395
+ /*** Curve Function Generators ***/
396
+ var _optimizedPowerCurveMap = {
397
+ .5:Math.sqrt,
398
+ 1:_linear,
399
+ 2:function (_value) {return _value * _value * (_value > 0 || -1)},
400
+ 3:function (_value) {return _value * _value * _value},
401
+ 4:function (_value) {return _value * _value * _value * _value * (_value > 0 || -1)},
402
+ 5:function (_value) {return _value * _value * _value * _value * _value}
403
+ };
404
+ _makeEasingCurveGenerators (
405
+ 'pow',
406
+ function (_power) {
407
+ return (
408
+ _optimizedPowerCurveMap [_power || (_power = 2)] ||
409
+ function (_value) {return Math.pow (_value * (_value > 0 || -1),_power) * (_value > 0 || -1)}
410
+ );
411
+ },
412
+ _package
413
+ /*?
414
+ Static Methods
415
+ Uize.Curve.easeInPow
416
+ Power easing in - accelerating from zero velocity, where the power can be specified.
417
+
418
+ SYNTAX
419
+ ..............................................
420
+ curveFUNC = Uize.Curve.easeInPow (powerFLOAT);
421
+ ..............................................
422
+
423
+ This method returns optimized curve functions for the powers =.5= (square root), =1= (linear), =2= (squared / quadratic), =3= (cubic), =4= (quartic), and =5= (quintic).
424
+
425
+ NOTES
426
+ - compare to the =Uize.Curve.easeInSweetPow= curve function generator
427
+ - see also the companion =Uize.Curve.easeOutPow=, =Uize.Curve.easeInOutPow=, and =Uize.Curve.easeMiddlePow= static methods
428
+
429
+ Uize.Curve.easeOutPow
430
+ Power easing out - decelerating to zero velocity, where the power can be specified.
431
+
432
+ SYNTAX
433
+ ...............................................
434
+ curveFUNC = Uize.Curve.easeOutPow (powerFLOAT);
435
+ ...............................................
436
+
437
+ This method returns optimized curve functions for the powers =.5= (square root), =1= (linear), =2= (squared / quadratic), =3= (cubic), =4= (quartic), and =5= (quintic).
438
+
439
+ NOTES
440
+ - compare to the =Uize.Curve.easeOutSweetPow= curve function generator
441
+ - see also the companion =Uize.Curve.easeInPow=, =Uize.Curve.easeInOutPow=, and =Uize.Curve.easeMiddlePow= static methods
442
+
443
+ Uize.Curve.easeInOutPow
444
+ Power easing in/out - acceleration until halfway, then deceleration, where the power can be specified.
445
+
446
+ SYNTAX
447
+ .................................................
448
+ curveFUNC = Uize.Curve.easeInOutPow (powerFLOAT);
449
+ .................................................
450
+
451
+ This method returns optimized curve functions for the powers =.5= (square root), =1= (linear), =2= (squared / quadratic), =3= (cubic), =4= (quartic), and =5= (quintic).
452
+
453
+ NOTES
454
+ - compare to the =Uize.Curve.easeInOutSweetPow= curve function generator
455
+ - see also the companion =Uize.Curve.easeInPow=, =Uize.Curve.easeOutPow=, and =Uize.Curve.easeMiddlePow= static methods
456
+
457
+ Uize.Curve.easeMiddlePow
458
+ Power easing in the middle - deceleration until halfway, then acceleration, where the power can be specified.
459
+
460
+ SYNTAX
461
+ ..................................................
462
+ curveFUNC = Uize.Curve.easeMiddlePow (powerFLOAT);
463
+ ..................................................
464
+
465
+ This method returns optimized curve functions for the powers =.5= (square root), =1= (linear), =2= (squared / quadratic), =3= (cubic), =4= (quartic), and =5= (quintic).
466
+
467
+ NOTES
468
+ - compare to the =Uize.Curve.easeMiddleSweetPow= curve function generator
469
+ - see also the companion =Uize.Curve.easeInPow=, =Uize.Curve.easeOutPow=, and =Uize.Curve.easeInOutPow= static methods
470
+ */
471
+ );
472
+
473
+ _makeEasingCurveGenerators (
474
+ 'sweetPow',
475
+ function (_power) {
476
+ return function (_value) {
477
+ var
478
+ _inPow = _package.easeInPow (_power),
479
+ _inverseInPow = _package.easeInPow (1 / _power)
480
+ ;
481
+ return (_inPow (_value) + 1 - _inverseInPow (1 - _value)) / 2;
482
+ }
483
+ },
484
+ _package
485
+ /*?
486
+ Static Methods
487
+ Uize.Curve.easeInSweetPow
488
+ Sweetened power easing in - accelerating from zero velocity, where the power can be specified.
489
+
490
+ SYNTAX
491
+ ...................................................
492
+ curveFUNC = Uize.Curve.easeInSweetPow (powerFLOAT);
493
+ ...................................................
494
+
495
+ A standard power curve is "sweetened" by blending it equally with the 180 degree rotated version of its corresponding inverse power curve, producing a curve that is closer to being circular.
496
+
497
+ NOTES
498
+ - compare to the =Uize.Curve.easeInPow= curve function generator
499
+ - see also the companion =Uize.Curve.easeOutSweetPow=, =Uize.Curve.easeInOutSweetPow=, and =Uize.Curve.easeMiddleSweetPow= static methods
500
+
501
+ Uize.Curve.easeOutSweetPow
502
+ Sweetened power easing out - decelerating to zero velocity, where the power can be specified.
503
+
504
+ SYNTAX
505
+ ....................................................
506
+ curveFUNC = Uize.Curve.easeOutSweetPow (powerFLOAT);
507
+ ....................................................
508
+
509
+ A standard power curve is "sweetened" by blending it equally with the 180 degree rotated version of its corresponding inverse power curve, producing a curve that is closer to being circular.
510
+
511
+ NOTES
512
+ - compare to the =Uize.Curve.easeOutPow= curve function generator
513
+ - see also the companion =Uize.Curve.easeInSweetPow=, =Uize.Curve.easeInOutSweetPow=, and =Uize.Curve.easeMiddleSweetPow= static methods
514
+
515
+ Uize.Curve.easeInOutSweetPow
516
+ Sweetened power easing in/out - acceleration until halfway, then deceleration, where the power can be specified.
517
+
518
+ SYNTAX
519
+ ......................................................
520
+ curveFUNC = Uize.Curve.easeInOutSweetPow (powerFLOAT);
521
+ ......................................................
522
+
523
+ A standard power curve is "sweetened" by blending it equally with the 180 degree rotated version of its corresponding inverse power curve, producing a curve that is closer to being circular.
524
+
525
+ NOTES
526
+ - compare to the =Uize.Curve.easeInOutPow= curve function generator
527
+ - see also the companion =Uize.Curve.easeInSweetPow=, =Uize.Curve.easeOutSweetPow=, and =Uize.Curve.easeMiddleSweetPow= static methods
528
+
529
+ Uize.Curve.easeMiddleSweetPow
530
+ Sweetened power easing in the middle - deceleration until halfway, then acceleration, where the power can be specified.
531
+
532
+ SYNTAX
533
+ .......................................................
534
+ curveFUNC = Uize.Curve.easeMiddleSweetPow (powerFLOAT);
535
+ .......................................................
536
+
537
+ A standard power curve is "sweetened" by blending it equally with the 180 degree rotated version of its corresponding inverse power curve, producing a curve that is closer to being circular.
538
+
539
+ NOTES
540
+ - compare to the =Uize.Curve.easeMiddlePow= curve function generator
541
+ - see also the companion =Uize.Curve.easeInSweetPow=, =Uize.Curve.easeOutSweetPow=, and =Uize.Curve.easeInOutSweetPow= static methods
542
+ */
543
+ );
544
+
545
+ _makeEasingCurveGenerators (
546
+ 'expo',
547
+ function () {return function (_value) {return _value && Math.pow (2,10 * (_value - 1))}},
548
+ _package
549
+ /*?
550
+ Static Methods
551
+ Uize.Curve.easeInExpo
552
+ Exponential easing in - accelerating from zero velocity.
553
+
554
+ SYNTAX
555
+ .....................................
556
+ curveFUNC = Uize.Curve.easeInExpo ();
557
+ .....................................
558
+
559
+ NOTES
560
+ - see also the companion =Uize.Curve.easeOutExpo=, =Uize.Curve.easeInOutExpo=, and =Uize.Curve.easeMiddleExpo= static methods
561
+ - thanks to `Robert Penner` for his original implementation
562
+
563
+ Uize.Curve.easeOutExpo
564
+ Exponential easing out - decelerating to zero velocity.
565
+
566
+ SYNTAX
567
+ ......................................
568
+ curveFUNC = Uize.Curve.easeOutExpo ();
569
+ ......................................
570
+
571
+ NOTES
572
+ - see also the companion =Uize.Curve.easeInExpo=, =Uize.Curve.easeInOutExpo=, and =Uize.Curve.easeMiddleExpo= static methods
573
+ - thanks to `Robert Penner` for his original implementation
574
+
575
+ Uize.Curve.easeInOutExpo
576
+ Exponential easing in/out - accelerating until halfway, then decelerating.
577
+
578
+ SYNTAX
579
+ ........................................
580
+ curveFUNC = Uize.Curve.easeInOutExpo ();
581
+ ........................................
582
+
583
+ NOTES
584
+ - see also the companion =Uize.Curve.easeInExpo=, =Uize.Curve.easeOutExpo=, and =Uize.Curve.easeMiddleExpo= static methods
585
+ - thanks to `Robert Penner` for his original implementation
586
+
587
+ Uize.Curve.easeMiddleExpo
588
+ Exponential easing in the middle - decelerating until halfway, then accelerating.
589
+
590
+ SYNTAX
591
+ .........................................
592
+ curveFUNC = Uize.Curve.easeMiddleExpo ();
593
+ .........................................
594
+
595
+ NOTES
596
+ - see also the companion =Uize.Curve.easeInExpo=, =Uize.Curve.easeOutExpo=, and =Uize.Curve.easeInOutExpo= static methods
597
+ - thanks to `Robert Penner` for his original implementation
598
+ */
599
+ );
600
+
601
+ _makeEasingCurveGenerators (
602
+ 'circular',
603
+ function (_power) {
604
+ return (
605
+ _power == 1
606
+ ? _linear
607
+ : _power == _undefined || _power == 2
608
+ ?
609
+ function (_value) {
610
+ return 1 - Math.sqrt (Math.abs (_value = 1 - _value * _value)) * (_value > 0 || -1)
611
+ }
612
+ :
613
+ function (_value) {
614
+ return 1 - Math.pow (Math.abs (_value = 1 - Math.pow (_value,_power)),1 / _power) * (_value > 0 || -1);
615
+ }
616
+ );
617
+ },
618
+ _package
619
+ /*?
620
+ Static Methods
621
+ Uize.Curve.easeInCircular
622
+ Circular easing in - accelerating from zero velocity.
623
+
624
+ SYNTAX
625
+ .........................................
626
+ curveFUNC = Uize.Curve.easeInCircular ();
627
+ .........................................
628
+
629
+ VARIATION
630
+ ....................................................
631
+ curveFUNC = Uize.Curve.easeInCircular (powerFLOAT);
632
+ ....................................................
633
+
634
+ When the optional =powerFLOAT= parameter is specified, a curve function can be generated that is not perfectly circular but still has the property of being symmetrical with respect to the diagonal that runs from bottom left to top right. When the =powerFLOAT= parameter is not specified, the value =2= is used as its default. Values higher than =2= will produce curves that bend down towards the bottom right corner, and positive values lower than =2= will produce curves that bend upwards towards the top left corner (=0= being the most extreme). The value =1= will produce a linear curve, and values between =1= and =2= will produce curves that are between perfectly linear and perfectly circular.
635
+
636
+ NOTES
637
+ - see also the companion =Uize.Curve.easeOutCircular=, =Uize.Curve.easeInOutCircular=, and =Uize.Curve.easeMiddleCircular= static methods
638
+ - thanks to `Robert Penner` for his original implementation
639
+
640
+ Uize.Curve.easeOutCircular
641
+ Circular easing out - decelerating to zero velocity.
642
+
643
+ SYNTAX
644
+ ..........................................
645
+ curveFUNC = Uize.Curve.easeOutCircular ();
646
+ ..........................................
647
+
648
+ VARIATION
649
+ ....................................................
650
+ curveFUNC = Uize.Curve.easeOutCircular (powerFLOAT);
651
+ ....................................................
652
+
653
+ When the optional =powerFLOAT= parameter is specified, a curve function can be generated that is not perfectly circular but still has the property of being symmetrical with respect to the diagonal that runs from bottom left to top right. When the =powerFLOAT= parameter is not specified, the value =2= is used as its default. Values higher than =2= will produce curves that bend upwards towards the top left corner, and positive values lower than =2= will produce curves that bend downwards towards the bottom right corner (=0= being the most extreme). The value =1= will produce a linear curve, and values between =1= and =2= will produce curves that are between perfectly linear and perfectly circular.
654
+
655
+ NOTES
656
+ - see also the companion =Uize.Curve.easeInCircular=, =Uize.Curve.easeInOutCircular=, and =Uize.Curve.easeMiddleCircular= static methods
657
+ - thanks to `Robert Penner` for his original implementation
658
+
659
+ Uize.Curve.easeInOutCircular
660
+ Circular easing in/out - acceleration until halfway, then deceleration.
661
+
662
+ SYNTAX
663
+ ............................................
664
+ curveFUNC = Uize.Curve.easeInOutCircular ();
665
+ ............................................
666
+
667
+ VARIATION
668
+ ......................................................
669
+ curveFUNC = Uize.Curve.easeInOutCircular (powerFLOAT);
670
+ ......................................................
671
+
672
+ When the optional =powerFLOAT= parameter is specified, a curve function can be generated that is not perfectly circular but still has the property of being symmetrical with respect to the diagonal that runs from bottom left to top right. When the =powerFLOAT= parameter is not specified, the value =2= is used as its default. Values higher than =2= and positive values lower than =2= will produce curves that bend more extremely towards the corners. The value =1= will produce a linear curve, and values between =1= and =2= will produce curves that are between perfectly linear and perfectly circular.
673
+
674
+ NOTES
675
+ - see also the companion =Uize.Curve.easeInCircular=, =Uize.Curve.easeInCircular=, and =Uize.Curve.easeMiddleCircular= static methods
676
+ - thanks to `Robert Penner` for his original implementation
677
+
678
+ Uize.Curve.easeMiddleCircular
679
+ Circular easing in the middle - deceleration until halfway, then acceleration.
680
+
681
+ SYNTAX
682
+ .............................................
683
+ curveFUNC = Uize.Curve.easeMiddleCircular ();
684
+ .............................................
685
+
686
+ VARIATION
687
+ .......................................................
688
+ curveFUNC = Uize.Curve.easeMiddleCircular (powerFLOAT);
689
+ .......................................................
690
+
691
+ When the optional =powerFLOAT= parameter is specified, a curve function can be generated that is not perfectly circular but still has the property of being symmetrical with respect to the diagonal that runs from bottom left to top right. When the =powerFLOAT= parameter is not specified, the value =2= is used as its default. Values higher than =2= and positive values lower than =2= will produce curves that bend more extremely towards the corners. The value =1= will produce a linear curve, and values between =1= and =2= will produce curves that are between perfectly linear and perfectly circular.
692
+
693
+ NOTES
694
+ - see also the companion =Uize.Curve.easeInCircular=, =Uize.Curve.easeOutCircular=, and =Uize.Curve.easeInOutCircular= static methods
695
+ - thanks to `Robert Penner` for his original implementation
696
+ */
697
+ );
698
+
699
+ _makeEasingCurveGenerators (
700
+ 'sine',
701
+ function () {
702
+ var _piDiv2 = Math.PI / 2;
703
+ return function (_value) {return 1 - Math.cos (_value * _piDiv2)};
704
+ },
705
+ _package
706
+ /*?
707
+ Static Methods
708
+ Uize.Curve.easeInSine
709
+ Sinusoidal easing in - accelerating from zero velocity.
710
+
711
+ SYNTAX
712
+ .....................................
713
+ curveFUNC = Uize.Curve.easeInSine ();
714
+ .....................................
715
+
716
+ NOTES
717
+ - see also the companion =Uize.Curve.easeOutSine=, =Uize.Curve.easeInOutSine=, and =Uize.Curve.easeMiddleSine= static methods
718
+ - thanks to `Robert Penner` for his original implementation
719
+
720
+ Uize.Curve.easeOutSine
721
+ Sinusoidal easing out - decelerating to zero velocity.
722
+
723
+ SYNTAX
724
+ ......................................
725
+ curveFUNC = Uize.Curve.easeOutSine ();
726
+ ......................................
727
+
728
+ NOTES
729
+ - see also the companion =Uize.Curve.easeInSine=, =Uize.Curve.easeInOutSine=, and =Uize.Curve.easeMiddleSine= static methods
730
+ - thanks to `Robert Penner` for his original implementation
731
+
732
+ Uize.Curve.easeInOutSine
733
+ Sinusoidal easing in/out - accelerating until halfway, then decelerating.
734
+
735
+ SYNTAX
736
+ ........................................
737
+ curveFUNC = Uize.Curve.easeInOutSine ();
738
+ ........................................
739
+
740
+ NOTES
741
+ - see also the companion =Uize.Curve.easeInSine=, =Uize.Curve.easeOutSine=, and =Uize.Curve.easeMiddleSine= static methods
742
+ - thanks to `Robert Penner` for his original implementation
743
+
744
+ Uize.Curve.easeMiddleSine
745
+ Sinusoidal easing in the middle - decelerating until halfway, then accelerating.
746
+
747
+ SYNTAX
748
+ .........................................
749
+ curveFUNC = Uize.Curve.easeMiddleSine ();
750
+ .........................................
751
+
752
+ NOTES
753
+ - see also the companion =Uize.Curve.easeInSine=, =Uize.Curve.easeOutSine=, and =Uize.Curve.easeInOutSine= static methods
754
+ - thanks to `Robert Penner` for his original implementation
755
+ */
756
+ );
757
+
758
+ _package.line = function (_startValue,_endValue) {
759
+ if (_endValue == _undefined) {
760
+ if (_startValue == _undefined) {
761
+ _startValue = 0;
762
+ _endValue = 1;
763
+ } else {
764
+ _endValue = _startValue;
765
+ }
766
+ }
767
+ var _delta = _endValue - _startValue;
768
+ return (
769
+ !_startValue && _endValue == 1
770
+ ? _linear
771
+ : _delta
772
+ ? function (_value) {return _startValue + _delta * _value}
773
+ : function () {return _startValue}
774
+
775
+ );
776
+ /*?
777
+ Static Methods
778
+ Uize.Curve.line
779
+ Returns a curve function, being a linear curve between the specified start and end values.
780
+
781
+ SYNTAX
782
+ ....................................................................
783
+ curveFUNC = Uize.Curve.line (startValue0to1FLOAT,endValue0to1FLOAT);
784
+ ....................................................................
785
+
786
+ This method allows you to create curve functions that don't observe the `Start At 0, End At 1` rule of curve functions, so it is not always appropriate for use in controlling fades. This method is more useful for creating value ranges that can be supplied to curve function modifiers that accept value ranges for parameters. Consider the following example of using the =Uize.Curve.Mod.blend= static method...
787
+
788
+ EXAMPLE
789
+ ........................................................................
790
+ Uize.Curve.Mod.blend (
791
+ Uize.Curve.easeOutPow (4), // ease-out power curve function
792
+ Uize.Curve.saw (20,.5), // sawtooth curve function with 20 teeth
793
+ Uize.Curve.line (.25,.75) // line starting at .25 and ending at .75
794
+ )
795
+ ........................................................................
796
+
797
+ In the above example, a quartic ease-out power curve function is being blended with a sawtooth curve function with twenty teeth. The =Uize.Curve.line= method is being used to create a value range from =.25= to =.75= to control the blend between the two curve functions across the range of input values. At the input value of =0=, the blend between the curves will be =.25=. At the input value of =1=, the blend between the curves will be =.75=. At the input value of =.5=, the blend between the curves will be =.5= (the midpoint value of the line curve).
798
+
799
+ VARIATION 1
800
+ ..................................................
801
+ curveFUNC = Uize.Curve.line (startValue0to1FLOAT);
802
+ ..................................................
803
+
804
+ When no =endValue0to1FLOAT= parameter is specified (or if the same value is specified for both the =startValue0to1FLOAT= and =endValue0to1FLOAT= parameters), then the curve function returned will be for a flat line that is always at the specified start value (ie. it starts at the start value and ends at the start value).
805
+
806
+ VARIATION 2
807
+ ...............................
808
+ curveFUNC = Uize.Curve.line ();
809
+ ...............................
810
+
811
+ When no parameters are specified (or if the value =0= is specified for the =startValue0to1FLOAT= parameter and the value =1= is specified for the =endValue0to1FLOAT= parameter), then a reference to =Uize.Curve.linear= (a linear curve function) will be returned.
812
+
813
+ NOTES
814
+ - compare to the =Uize.Curve.linear= static method
815
+ */
816
+ };
817
+
818
+ _package.saw = function (_repeats,_amount) {
819
+ return (
820
+ _repeats == 1 || !(_amount = Uize.toNumber (_amount,1))
821
+ ? _linear
822
+ : function (_value) {
823
+ return _blendFloats (_value,_value && ((_value * _repeats) % 1 || 1),_amount)
824
+ }
825
+ );
826
+ /*?
827
+ Static Methods
828
+ Uize.Curve.saw
829
+ Returns a sawtooth curve function, where the number of teeth and the amount of the sawtooth effect can be specified.
830
+
831
+ SYNTAX
832
+ ........................................................
833
+ curveFUNC = Uize.Curve.saw (repeatsINT,amount0to1FLOAT);
834
+ ........................................................
835
+
836
+ PARAMETERS
837
+
838
+ - =repeatsINT= - controls the number of "teeth" in the sawtooth curve.
839
+
840
+ - =amount0to1FLOAT= - a floating point number in the range of =0= to =1=. Specifying the value =0= for this parameter will produce a curve function for a simple linear curve, specifying the value =1= will produce a curve function where each tooth reaches all the way from =0= up to =1=, and specifying the value =.5= will produce an equal blend between a linear curve and a harsh sawtooth pattern. Any other values will produce different blends between fully linear and fully sawtooth.
841
+
842
+ VARIATION
843
+ ........................................
844
+ curveFUNC = Uize.Curve.saw (repeatsINT);
845
+ ........................................
846
+
847
+ When no =amount0to1FLOAT= parameter is specified, the value =1= is used as the default. This produces a harsh sawtooth curve function, with each tooth using the full vertical range of =0= to =1=.
848
+ */
849
+ };
850
+
851
+ return _package;
852
+ }
853
+ });
854
+
skin/frontend/default/customproduct/js/Uize.Data.Combinations.js ADDED
@@ -0,0 +1,725 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ /*______________
2
+ | ______ | U I Z E J A V A S C R I P T F R A M E W O R K
3
+ | / / | ---------------------------------------------------
4
+ | / O / | MODULE : Uize.Data.Combinations Package
5
+ | / / / |
6
+ | / / / /| | ONLINE : http://www.uize.com
7
+ | /____/ /__/_| | COPYRIGHT : (c)2012 UIZE
8
+ | /___ | LICENSE : Available under MIT License or GNU General Public License
9
+ |_______________| http://www.uize.com/license.html
10
+ */
11
+
12
+ /* Module Meta Data
13
+ type: Package
14
+ importance: 1
15
+ codeCompleteness: 100
16
+ testCompleteness: 100
17
+ docCompleteness: 100
18
+ */
19
+
20
+ /*?
21
+ Introduction
22
+ The =Uize.Data.Combinations= module provides methods for generating object or array combinations from a `combination specifier`, with support for an optional combination transformer and combination matcher.
23
+
24
+ *DEVELOPERS:* `Chris van Rensburg`
25
+
26
+ In a Nutshell
27
+ The methods of the =Uize.Data.Combinations= module make it easy to produce a large set of combinations in a highly performant way.
28
+
29
+ Scalable
30
+ The =Uize.Data.Combinations= module is scalable in its ability to support an arbitrary number of combination properties.
31
+
32
+ Whereas a typical approach to producing combinations might involve nested =for= loop structures, this approach can only support a fixed number of properties and does not scale well to support an arbitrary or dynamic number of properties. The =Uize.Data.Combinations= module can support an arbitrary and also very large number of combination properties without trouble.
33
+
34
+ Performant
35
+ The =Uize.Data.Combinations= module is implemented to be highly performant, avoiding the use of recursion or the repeated creation and destruction of partial results sets.
36
+
37
+ The =Uize.Data.Combinations= module uses an approach much like generating all possible numbers up to a maximum number. In this way, the module can implement combination generation using just two levels of loop nesting, regardless of how many properties there are in the `combination specifier`. No recursion is used, thereby reducing function call overhead and call stack bloat.
38
+
39
+ The Methods
40
+ The =Uize.Data.Combinations= module provides the following static methods to deal with generated combinations...
41
+
42
+ - =Uize.Data.Combinations.forEach= - lets you iterate through generated combinations, executing the specified iteration handler function for each combination
43
+ - =Uize.Data.Combinations.generate= - produces an array containing the generated combinations
44
+
45
+ How Combinations Are Generated
46
+ Combinations are generated using a `combination specifier` that provides a template for the combinations, along with an `optional combination transformer` that can be used to modify the generated combinations, and an `optional combination matcher` that can be used to filter the combinations.
47
+
48
+ Combination Specifier
49
+ The `combination specifier` lets you specify a kind of template for the generated combinations, with possible values for each property or element.
50
+
51
+ When the Combination Specifier is an Object
52
+ If the `combination specifier` is an object, then each property of the object represents a property of the generated combinations, and the value for each property specifies the possible values for that property that should be iterated through when generating the combinations.
53
+
54
+ Consider the following example of generating combinations of car specifications...
55
+
56
+ EXAMPLE
57
+ .................................................
58
+ var cars = Uize.Data.Combinations.generate ({
59
+ headlights:['regular','xenon','LED'],
60
+ tires:['regular','low profile','fatty'],
61
+ roof:['regular','sun roof','convertible'],
62
+ upholstery:['regular','micro suede','leather']
63
+ });
64
+ .................................................
65
+
66
+ With the above `combination specifier`, the =Uize.Data.Combinations.generate= method would produce combinations as follows...
67
+
68
+ COMBINATIONS
69
+ ........................................................................................
70
+ [
71
+ {headlights:'regular',hubcaps:'regular',roof:'regular',upholstery:'regular'},
72
+ {headlights:'regular',hubcaps:'regular',roof:'regular',upholstery:'micro suede'},
73
+ {headlights:'regular',hubcaps:'regular',roof:'regular',upholstery:'leather'},
74
+ {headlights:'regular',hubcaps:'regular',roof:'sun roof',upholstery:'regular'},
75
+ {headlights:'regular',hubcaps:'regular',roof:'sun roof',upholstery:'micro suede'},
76
+ {headlights:'regular',hubcaps:'regular',roof:'sun roof',upholstery:'leather'},
77
+ {headlights:'regular',hubcaps:'regular',roof:'convertible',upholstery:'regular'},
78
+ {headlights:'regular',hubcaps:'regular',roof:'convertible',upholstery:'micro suede'},
79
+ {headlights:'regular',hubcaps:'regular',roof:'convertible',upholstery:'leather'},
80
+ ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ...
81
+ ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ...
82
+ ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ...
83
+ ]
84
+ ........................................................................................
85
+
86
+ As you may notice from the above sample of the output combinations, the combinations are produced by cycling through the possible values starting from the last property in the `combination specifier` (=upholstery= in this example), and then working steadily towards the first property in the `combination specifier` as the possible values "clock over". Looking at our example `combination specifier`, we can tell that the =Uize.Data.Combinations.generate= method would produce =81= combinations: three possible values for =headlights=, times three possible values for =tires=, times three possible values for =roof=, times three possible values for =upholstery=.
87
+
88
+ When the Combination Specifier is an Array
89
+ If the `combination specifier` is an array, then each element of the array represents an element of a generated combination array, and the value for each element specifies the possible values for that element that should be iterated through when generating the combinations.
90
+
91
+ Consider the following example of generating combinations of Web safe color tuples...
92
+
93
+ EXAMPLE
94
+ .................................................................................
95
+ Uize.Data.Combinations.generate ([
96
+ ['00','33','66','99','CC','FF'], // possible values for red channel element
97
+ ['00','33','66','99','CC','FF'], // possible values for green channel element
98
+ ['00','33','66','99','CC','FF'] // possible values for blue channel element
99
+ ]);
100
+ .................................................................................
101
+
102
+ With the above `combination specifier`, the =Uize.Data.Combinations.generate= method would produce combinations as follows...
103
+
104
+ COMBINATIONS
105
+ ......................
106
+ [
107
+ ['00','00','00'],
108
+ ['00','00','33'],
109
+ ['00','00','66'],
110
+ ['00','00','99'],
111
+ ['00','00','CC'],
112
+ ['00','00','FF'],
113
+ ['00','33','00'],
114
+ ['00','33','33'],
115
+ ['00','33','66'],
116
+ ['00','33','99'],
117
+ ['00','33','CC'],
118
+ ['00','33','FF'],
119
+ ... ... ... ... ...
120
+ ... ... ... ... ...
121
+ ... ... ... ... ...
122
+ ]
123
+ ......................
124
+
125
+ As is the case `when the combination specifier is an object`, the combinations are produced by cycling through the possible values starting from the last element in the `combination specifier` array (the blue channel's color value in this example), and then working steadily towards the first element in the `combination specifier` as the possible values "clock over". Looking at our example `combination specifier`, we can tell that the =Uize.Data.Combinations.generate= method would produce =216= combinations: six possible values for the red channel, times six possible values for the green channel, times six possible values for the blue channel.
126
+
127
+ More on Specifying Possible Values
128
+ When the Possible Values is Not an Array
129
+ If the value of a property in the `combination specifier` is anything other than a list of possible values, then the value is treated as the single possible value for the property in the generated combinations.
130
+
131
+ EXAMPLE
132
+ ..........................................
133
+ Uize.Data.Combinations.generate ({
134
+ headlights:'regular',
135
+ tires:['regular','low profile','fatty']
136
+ });
137
+ ..........................................
138
+
139
+ In the above example, the value ='regular'= is the only possible value for the =headlights= property of the generated combinations. It could be specified as an array with only a single element, as in =['regular']=, but this is not necessary with the =Uize.Data.Combinations= module. The above statement would produce the following result...
140
+
141
+ RESULT
142
+ ..............................................
143
+ [
144
+ {headlights:'regular',tires:'regular'},
145
+ {headlights:'regular',tires:'low profile'},
146
+ {headlights:'regular',tires:'fatty'}
147
+ ]
148
+ ..............................................
149
+
150
+ When There is Only One Possible Value
151
+ When there is only one possible value for a property in the generated combinations, the possible value can be specified as an array with only one element, or just the possible value can be specified.
152
+
153
+ However, if the single possible value is an array, then it must be specified wrapped inside an array. Consider the following example...
154
+
155
+ EXAMPLE
156
+ .............................................
157
+ Uize.Data.Combinations.generate ({
158
+ bodyColor:[[255,127,0]],
159
+ dashboardColor:[[245,132,0],[205,154,78]],
160
+ tires:'regular'
161
+ });
162
+ .............................................
163
+
164
+ In the above example, car configuration combinations are being generated. Colors are specified as RGB tuple arrays, and there is only one possible color for the =bodyColor= property. Therefore, the tuple must be wrapped in a possible values array, or otherwise the individual red, green, and blue color channel values would be confused for possible values. In contrast, there is only one possible value for the =tires= property, but the value is a string. Therefore, this one possible value does *not* need to be wrapped inside an array, because there is no ambiguity. The above statement would produce the following result...
165
+
166
+ RESULT
167
+ ......................................................................
168
+ [
169
+ {bodyColor:[255,127,0],dashboardColor:[245,132,0],tires:'regular'},
170
+ {bodyColor:[255,127,0],dashboardColor:[205,154,78],tires:'regular'}
171
+ ]
172
+ ......................................................................
173
+
174
+ When There Are No Possible Values
175
+ When the possible values array for a property in the `combination specifier` contains no elements, then this is regarded as there being no possible values for the property and that property is excluded from the generated combinations.
176
+
177
+ EXAMPLE
178
+ ...........................................
179
+ Uize.Data.Combinations.generate ({
180
+ headlights:'regular',
181
+ tires:['regular','low profile','fatty'],
182
+ racingStripes:[]
183
+ });
184
+ ...........................................
185
+
186
+ In the above example of a combination specifier for car configuration combinations, there is only one possible value for the =headlights= property, there are two possible values for the =tires= property, and there are no possible values for the =racingStripes= property. The =headlights= property is included in the generated combinations, with the same one value for each combination. In contrast, the =racingStripes= property is excluded from the generated combinations, since there are no possible values for it. The above statement would produce the following result...
187
+
188
+ RESULT
189
+ ..............................................
190
+ [
191
+ {headlights:'regular',tires:'regular'},
192
+ {headlights:'regular',tires:'low profile'},
193
+ {headlights:'regular',tires:'fatty'}
194
+ ]
195
+ ..............................................
196
+
197
+ Optional Combination Transformer
198
+ Both the =Uize.Data.Combinations.forEach= and =Uize.Data.Combinations.generate= static methods support an optional =combinationTransformerSTRorFUNC= parameter that lets you modify each combination.
199
+
200
+ Combination Transformer Function
201
+ When a function is specified for the optional =combinationTransformerSTRorFUNC= parameter, then the function will be executed for each generated combination.
202
+
203
+ The `combination transformer function` can expect two arguments: the combination and the combination number / index. The function can modify the combination passed to it, using the combination index if desired. The function does not need to return a value, however, if the function *does* return a value other than =undefined=, then that value will replace the generated combination. A value returned by the function does not need to be an object - it can be of any type. For example, the returned value could be the combination serialized to a string of some form (see the `Generate Web Safe Color Palette` example).
204
+
205
+ EXAMPLE
206
+ ............................................
207
+ Uize.Data.Combinations.generate (
208
+ {
209
+ width:[6,9],
210
+ length:[10,15],
211
+ height:[12,21]
212
+ },
213
+ function (room,roomNo) {
214
+ room.area = room.width * room.length;
215
+ room.volume = room.area * room.height;
216
+ room.roomNo = roomNo;
217
+ }
218
+ );
219
+ ............................................
220
+
221
+ In the above example, we are generating different room combinations, where there are two possible options for each of the room properties of =width=, =length=, and =height=. We have specified a custom `combination transformer function` that adds to each room combination object the computed properties =area= and =volume=, while also tagging each combination with a =roomNo= property that is based on the combination index. The above statement would produce the following result...
222
+
223
+ RESULT
224
+ ...............................................................
225
+ [
226
+ {width:6,length:10,height:12,area:60,volume:720,roomNo:0},
227
+ {width:6,length:10,height:21,area:60,volume:1260,roomNo:1},
228
+ {width:6,length:15,height:12,area:90,volume:1080,roomNo:2},
229
+ {width:6,length:15,height:21,area:90,volume:1890,roomNo:3},
230
+ {width:9,length:10,height:12,area:90,volume:1080,roomNo:4},
231
+ {width:9,length:10,height:21,area:90,volume:1890,roomNo:5},
232
+ {width:9,length:15,height:12,area:135,volume:1620,roomNo:6},
233
+ {width:9,length:15,height:21,area:135,volume:2835,roomNo:7}
234
+ ]
235
+ ...............................................................
236
+
237
+ Combination Transformer Expression String
238
+ When an expression string is specified for the optional =combinationTransformerSTRorFUNC= parameter, then the expression will be executed for each generated combination.
239
+
240
+ The `combination transformer expression string` can expect two variables to be defined in the scope of the expression: the =value= variable which represents the generated combination, and the =key= variable which represents the index of the generated combination. The expression can use these two variables to generate a transformed combination. The result of the expression does not need to be an object - it can be of any type - and this value will be used to replace the generated combination. For example, the returned value could be the combination serialized to a string of some form (see the `Generate Web Safe Color Palette` example).
241
+
242
+ EXAMPLE
243
+ ............................................................................
244
+ Uize.Data.Combinations.generate (
245
+ {
246
+ width:[6,9],
247
+ length:[10,15],
248
+ height:[12,21]
249
+ },
250
+ 'value.width + "(W) x " + value.length + "(L) x " + value.height + "(H)"'
251
+ );
252
+ ............................................................................
253
+
254
+ In the above example, we are generating different room combinations, where there are two possible options for each of the room properties of =width=, =length=, and =height=. We have specified a custom `combination transformer expression string` that serializes the room dimensions to a string of the form "6(W) x 10(L) x 12(H)". The above statement would produce the following result...
255
+
256
+ RESULT
257
+ ..........................
258
+ [
259
+ '6(W) x 10(L) x 12(H)',
260
+ '6(W) x 10(L) x 21(H)',
261
+ '6(W) x 15(L) x 12(H)',
262
+ '6(W) x 15(L) x 21(H)',
263
+ '9(W) x 10(L) x 12(H)',
264
+ '9(W) x 10(L) x 21(H)',
265
+ '9(W) x 15(L) x 12(H)',
266
+ '9(W) x 15(L) x 21(H)'
267
+ ]
268
+ ..........................
269
+
270
+ Optional Combination Matcher
271
+ Both the =Uize.Data.Combinations.forEach= and =Uize.Data.Combinations.generate= static methods support an optional =combinationMatcherSTRorFUNC= parameter that lets you filter the generated combinations.
272
+
273
+ Combination Matcher Function
274
+ When a function is specified for the optional =combinationMatcherSTRorFUNC= parameter, then the function will be executed for each generated combination.
275
+
276
+ The `combination matcher function` can expect two arguments: the combination and the combination number / index. The function should return a boolean value, indicating whether or not the combination passed to it should be included in the final set of generated combinations that is returned by the =Uize.Data.Combinations.generate= method or iterated over by the =Uize.Data.Combinations.forEach= method.
277
+
278
+ EXAMPLE
279
+ ...............................................
280
+ Uize.Data.Combinations.generate (
281
+ {
282
+ width:[6,9],
283
+ length:[10,15],
284
+ height:[12,21]
285
+ },
286
+ function (room,roomNo) {
287
+ room.area = room.width * room.length;
288
+ room.volume = room.area * room.height;
289
+ room.roomNo = roomNo;
290
+ },
291
+ function (room) {return room.volume >= 1500}
292
+ );
293
+ ...............................................
294
+
295
+ In the above example, we are generating different room combinations, where there are two possible options for each of the room properties of =width=, =length=, and =height=. Additionally, we have specified a custom `combination matcher function` that is filtering out all rooms whose volume is less than 1500 cubic feet. One interesting thing that you'll notice in this example is that the combination matcher is executed after the `optional combination transformer` (if specified), so it gets to match using the generated combination after the transformer has had its opportunity to modify it by changing or adding properties. The above statement would produce the following result...
296
+
297
+ RESULT
298
+ ...............................................................
299
+ [
300
+ {width:6,length:15,height:21,area:90,volume:1890,roomNo:3},
301
+ {width:9,length:10,height:21,area:90,volume:1890,roomNo:5},
302
+ {width:9,length:15,height:12,area:135,volume:1620,roomNo:6},
303
+ {width:9,length:15,height:21,area:135,volume:2835,roomNo:7}
304
+ ]
305
+ ...............................................................
306
+
307
+ Combination Matcher Expression String
308
+ When an expression string is specified for the optional =combinationMatcherSTRorFUNC= parameter, then the expression will be executed for each generated combination.
309
+
310
+ The `combination matcher expression string` can expect two variables to be defined in the scope of the expression: the =value= variable which represents the generated combination, and the =key= variable which represents the index of the generated combination. The expression can use these two variables to generate a boolean value, indicating whether or not the combination should be included in the final set of generated combinations that is returned by the =Uize.Data.Combinations.generate= method or iterated over by the =Uize.Data.Combinations.forEach= method.
311
+
312
+ EXAMPLE
313
+ ............................................
314
+ Uize.Data.Combinations.generate (
315
+ {
316
+ width:[6,9],
317
+ length:[10,15],
318
+ height:[12,21]
319
+ },
320
+ function (room,roomNo) {
321
+ room.area = room.width * room.length;
322
+ room.volume = room.area * room.height;
323
+ room.roomNo = roomNo;
324
+ },
325
+ 'value.volume >= 1500'
326
+ );
327
+ ............................................
328
+
329
+ In the above example, we are generating different room combinations, where there are two possible options for each of the room properties of =width=, =length=, and =height=. Additionally, we have specified a custom `combination matcher expression string` that is filtering out all rooms whose volume is less than 1500 cubic feet. The combination matcher is executed after the `optional combination transformer` (if specified), so it gets to match using the generated combination after the transformer has had its opportunity to modify it by changing or adding properties.
330
+
331
+ Worth pointing out in this example is that, while the `combination transformer function` can name its value and key arguments as it sees fit (=room= and =roomNo= in this case), the `combination matcher expression string` must use the reserved variable names =value= and =key=. The above statement would produce the following result...
332
+
333
+ RESULT
334
+ ...............................................................
335
+ [
336
+ {width:6,length:15,height:21,area:90,volume:1890,roomNo:3},
337
+ {width:9,length:10,height:21,area:90,volume:1890,roomNo:5},
338
+ {width:9,length:15,height:12,area:135,volume:1620,roomNo:6},
339
+ {width:9,length:15,height:21,area:135,volume:2835,roomNo:7}
340
+ ]
341
+ ...............................................................
342
+
343
+ Transformer, Then Matcher
344
+ When both an `optional combination transformer` and an `optional combination matcher` are specified, the combination transformer is executed first, before the combination matcher is executed.
345
+
346
+ This behavior allows each generated combination to be filtered, taking into account how the combination may have been altered or augmented by the combination transformer. Consider the following example...
347
+
348
+ EXAMPLE
349
+ ..........................................................................
350
+ Uize.Data.Combinations.generate (
351
+ {
352
+ firstName: ['Christopher', 'Jan', 'Jonathan', 'Charles', 'Anthony'],
353
+ lastName: ['Smith', 'von Breugelstein', 'Daniels', 'Pickenson']
354
+ },
355
+ function (person) {
356
+ person.fullName = firstName + ' ' + lastName;
357
+ },
358
+ function (person) {
359
+ return person.fullName.length <= 20;
360
+ }
361
+ );
362
+ ..........................................................................
363
+
364
+ In the above example, an array of person records is being generated by combining possible values for first name with possible values for last name. This set of person records could be used to feed as dummy data into an automated test process. In this case, we're specifying an `optional combination transformer` to add a =fullName= property to each generated combination. We're also specifying an `optional combination matcher` to filter out / exclude those generated people records where the full name that was constructed in the combination transformer is greater than twenty characters in length.
365
+
366
+ The above statement would allow the record with the full name of "Jan von Breugelstein" (exactly twenty characters long), but exclude the record with the full name of "Christopher Pickenson" (twenty one characters long). Importantly, because the `combination transformer function` is executed before the `combination matcher function`, the matcher can access and use the added =fullName= property in its determination.
367
+
368
+ Real World Examples
369
+ Generate Web Safe Color Palette
370
+ In this example, we are using the =Uize.Data.Combinations.generate= method to generate an array of hex RGB color strings for the full palette of [[http://en.wikipedia.org/wiki/Web_safe_colors#Web-safe_colors][Web safe colors]].
371
+
372
+ If we were to approach this problem the traditional way, we would write our code using three nested =for= loops - one for each of the three RGB color channels. This approach would produce code as follows...
373
+
374
+ THE TEDIOUS WAY
375
+ ....................................................................................
376
+ var
377
+ channelValues = ['00','33','66','99','CC','FF'],
378
+ webSafeColors = []
379
+ ;
380
+ for (var redValueNo = 0; redValueNo < channelValues.length; redValueNo++) {
381
+ for (var greenValueNo = 0; greenValueNo < channelValues.length; greenValueNo++) {
382
+ for (var blueValueNo = 0; blueValueNo < channelValues.length; blueValueNo++) {
383
+ webSafeColors.push (
384
+ '#' +
385
+ channelValues [redValueNo] +
386
+ channelValues [greenValueNo] +
387
+ channelValues [blueValueNo]
388
+ );
389
+ }
390
+ }
391
+ }
392
+ ....................................................................................
393
+
394
+ If we instead use the =Uize.Data.Combinations.generate= method, we can reduce our code down to something more concise and elegant, as follows...
395
+
396
+ THE CONCISE WAY
397
+ ....................................................
398
+ var
399
+ channelValues = ['00','33','66','99','CC','FF'],
400
+ webSafeColors = Uize.Data.Combinations.generate (
401
+ [channelValues,channelValues,channelValues],
402
+ '"#" + value.join ("")'
403
+ )
404
+ ;
405
+ ....................................................
406
+
407
+ In our solution, we create the variable =channelValues=, whose value is an array representing all the possible values for a color channel in a Web safe color. We then use this possible values array in a `combination specifier` that provides a template for an RGB color tuple. Then, to ensure that the array of generated values is an array of hex formatted RGB color strings, we specify a `combination transformer expression string` that takes a generated combination tuple and joins its three elements and adds a "#" (pound character) prefix.
408
+
409
+ Generate Style Combinations For Testing
410
+ In this example, we are generating a bunch of HTML divs to test various combinations of styling that can be applied using various CSS classes that are used by selectors in a stylesheet.
411
+
412
+ Now, given the way we have designed the CSS, we've effectively divided the styling into four different styling dimensions: any div can be styled using one of several possible CSS classes for decorating the border, the padding, the font characteristics, and the color theme. To easily preview and test all the possible styling variations that would be produced by using different combinations of values for these four styling dimensions, we could create four nested =for= loops to iterate through the possible values for each of the styling dimensions. This approach would produce code as follows...
413
+
414
+ THE TEDIOUS WAY
415
+ ...........................................................................................
416
+ var
417
+ borderClasses = ['noBorder','thinBorder','thickBorder','dottedBorder','fancyBorder'],
418
+ paddingClasses = ['noPadding','smallPadding','extraPadding'],
419
+ printClasses = ['finePrint','normalPrint','easilyReadable','printForVisionImpared'],
420
+ colorClasses = ['normalColors','subduedColors','brightColors','highContrastColors'],
421
+ htmlChunks = []
422
+ ;
423
+ for (var borderClassNo = 0; borderClassNo < borderClasses.length; borderClassNo++) {
424
+ for (var paddingClassNo = 0; paddingClassNo < paddingClasses.length; paddingClassNo++) {
425
+ for (var printClassNo = 0; printClassNo < printClasses.length; printClassNo++) {
426
+ for (var colorClassNo = 0; colorClassNo < colorClasses.length; colorClassNo++) {
427
+ htmlChunks.push (
428
+ '<div class="' +
429
+ borderClasses [borderClassNo] + ' ' +
430
+ paddingClasses [paddingClassNo] + ' ' +
431
+ printClasses [printClassNo] + ' ' +
432
+ colorClasses [colorClassNo] + ' ' +
433
+ '">some text</div>'
434
+ );
435
+ }
436
+ }
437
+ }
438
+ }
439
+ Uize.Node.setInnerHtml ('styleCombos',htmlChunks.join ('\n'));
440
+ ...........................................................................................
441
+
442
+ Of course, if we wanted a more concise and elegant solution - one that is more easily scalable when we want to add more styling dimensions - we could use the =Uize.Data.Combinations.generate= method as follows...
443
+
444
+ THE CONCISE WAY
445
+ ..............................................................................
446
+ Uize.Node.setInnerHtml (
447
+ 'styleCombos',
448
+ Uize.Data.Combinations.generate (
449
+ [
450
+ ['noBorder','thinBorder','thickBorder','dottedBorder','fancyBorder'],
451
+ ['noPadding','smallPadding','extraPadding'],
452
+ ['finePrint','normalPrint','easilyReadable','printForVisionImpared'],
453
+ ['normalColors','subduedColors','brightColors','highContrastColors']
454
+ ],
455
+ "'<div class=\"' + value.join (' ') + '\">some text</div>'"
456
+ ).join ('\n')
457
+ );
458
+ ..............................................................................
459
+
460
+ In this solution, the `combination specifier` is an array, where each element represents one of the four styling dimensions, and where the value for each element is an array of the possible CSS classes that provides different stylings for that styling dimension. Then, we are specifying a `combination transformer expression string` to take the generated CSS classes array, concatenate it with a " " (space character) delimiter, and wrap it in an HTML =div= tag prefix and suffix. As a result, the =Uize.Data.Combinations.generate= method will return an array of =div= tag strings, which we then join with a newline character to produce an HTML chunk that we insert as inner HTML into the DOM node with the =id= of "styleCombos".
461
+
462
+ With this improved approach, if we want to add a new styling dimension, all we need to do is add another element to the `combination specifier` - much cleaner than the alternative approach shown earlier.
463
+ */
464
+
465
+ Uize.module ({
466
+ name:'Uize.Data.Combinations',
467
+ builder:function () {
468
+ /*** Variables for Scruncher Optimization ***/
469
+ var
470
+ _package = function () {},
471
+ _undefined,
472
+ _isList = Uize.isList
473
+ ;
474
+
475
+ /*** Public Static Methods ***/
476
+ _package.generate = function (_combinationsSpecifier,_combinationTransformer,_combinationMatcher) {
477
+ var _combinations = [];
478
+ _package.forEach (
479
+ _combinationsSpecifier,
480
+ function (_combination) {_combinations.push (_combination)},
481
+ _combinationTransformer,
482
+ _combinationMatcher
483
+ );
484
+ return _combinations;
485
+ /*?
486
+ Static Methods
487
+ Uize.Data.Combinations.generate
488
+ Returns an array of generated combinations that are derived from a `combination specifier`, with support for optionally transforming and/or filtering the combinations.
489
+
490
+ DIFFERENT USAGES
491
+
492
+ `Generate an Array of Combinations from a Combination Specifier`
493
+ ......................................................................................
494
+ combinationsARRAY = Uize.Data.Combinations.generate (combinationsSpecifierOBJorARRAY);
495
+ ......................................................................................
496
+
497
+ `Generate an Array of Transformed Combinations`
498
+ .....................................................
499
+ combinationsARRAY = Uize.Data.Combinations.generate (
500
+ combinationsSpecifierOBJorARRAY,
501
+ combinationTransformerSTRorFUNC
502
+ );
503
+ .....................................................
504
+
505
+ `Generate a Filtered Array of Transformed Combinations`
506
+ .....................................................
507
+ combinationsARRAY = Uize.Data.Combinations.generate (
508
+ combinationsSpecifierOBJorARRAY,
509
+ combinationTransformerSTRorFUNC,
510
+ combinationMatcherSTRorFUNC
511
+ );
512
+ .....................................................
513
+
514
+ Generate an Array of Combinations from a Combination Specifier
515
+ In the most typical use case, an array of combinations can be generated by specifying just the =combinationsSpecifierOBJorARRAY= parameter.
516
+
517
+ SYNTAX
518
+ ......................................................................................
519
+ combinationsARRAY = Uize.Data.Combinations.generate (combinationsSpecifierOBJorARRAY);
520
+ ......................................................................................
521
+
522
+ The =combinationsSpecifierOBJorARRAY= parameter lets you specify the `combination specifier` from which the combinations will be generated. `When the combination specifier is an object`, an array of objects will be produced. `When the combination specifier is an array`, an array of arrays will be produced. For more information, refer to the section `How Combinations Are Generated`.
523
+
524
+ Generate an Array of Transformed Combinations
525
+ When the optional =combinationTransformerSTRorFUNC= second parameter is specified, the generated combinations can be transformed or replaced.
526
+
527
+ SYNTAX
528
+ .....................................................
529
+ combinationsARRAY = Uize.Data.Combinations.generate (
530
+ combinationsSpecifierOBJorARRAY,
531
+ combinationTransformerSTRorFUNC
532
+ );
533
+ .....................................................
534
+
535
+ For more information on combination transformers and to see examples, refer to the section `Optional Combination Transformer`.
536
+
537
+ Generate a Filtered Array of Transformed Combinations
538
+ When the optional =combinationMatcherSTRorFUNC= third parameter is specified, the generated (and optionally transformed) combinations can be filtered.
539
+
540
+ SYNTAX
541
+ .....................................................
542
+ combinationsARRAY = Uize.Data.Combinations.generate (
543
+ combinationsSpecifierOBJorARRAY,
544
+ combinationTransformerSTRorFUNC,
545
+ combinationMatcherSTRorFUNC
546
+ );
547
+ .....................................................
548
+
549
+ When a combination matcher is desired but a combination transformer is not desired, the value =null= or =undefined= can be specified for the =combinationTransformerSTRorFUNC= parameter. For more information on combination matchers and to see examples, refer to the section `Optional Combination Matcher`.
550
+
551
+ NOTES
552
+ - compare to the =Uize.Data.Combinations.forEach= static method
553
+ */
554
+ };
555
+
556
+ _package.forEach = function (
557
+ _combinationsSpecifier,_iterationHandler,_combinationTransformer,_combinationMatcher
558
+ ) {
559
+ if (Uize.isObject (_combinationsSpecifier)) {
560
+ /*** normalize parameters ***/
561
+ if (_combinationTransformer != _undefined)
562
+ _combinationTransformer = Uize.resolveTransformer (_combinationTransformer)
563
+ ;
564
+ if (_combinationMatcher != _undefined)
565
+ _combinationMatcher = Uize.resolveMatcher (_combinationMatcher)
566
+ ;
567
+
568
+ /*** preparation to optimize performance of iterating through combinations ***/
569
+ var
570
+ _keys = [],
571
+ _key,
572
+ _keyNo = -1,
573
+ _values,
574
+ _valuesPerKeyNo = [],
575
+ _valuesLengthPerKeyNo = [],
576
+ _valueNoPerKeyNo = [],
577
+ _combinationsAreArray = Uize.isArray (_combinationsSpecifier)
578
+ ;
579
+ Uize.forEach (
580
+ _combinationsSpecifier,
581
+ function (_values,_key) {
582
+ _values = _combinationsSpecifier [_key];
583
+ if (!_isList (_values)) _values = [_values]; // treat non-list value as only one possible value
584
+ if (_values.length) { // only include property if it has at least one possible value
585
+ _keys.push (_key);
586
+ _keyNo++;
587
+ _valuesLengthPerKeyNo [_keyNo] = (_valuesPerKeyNo [_keyNo] = _values).length;
588
+ _valueNoPerKeyNo [_keyNo] = 0;
589
+ }
590
+ }
591
+ );
592
+
593
+ /*** iterate through and produce combinations ***/
594
+ var
595
+ _combinationNo = -1,
596
+ _keysLength = _keyNo + 1,
597
+ _combinationTransformerResult
598
+ ;
599
+ while (_keyNo >= 0) {
600
+ _combinationNo++;
601
+
602
+ /*** build object for current combination ***/
603
+ var _combination = _combinationsAreArray ? [] : {};
604
+ for (_keyNo = -1; ++_keyNo < _keysLength;)
605
+ _combination [_keys [_keyNo]] = _valuesPerKeyNo [_keyNo] [_valueNoPerKeyNo [_keyNo]]
606
+ ;
607
+
608
+ /*** use combination transformer, if specified ***/
609
+ if (
610
+ _combinationTransformer &&
611
+ (
612
+ _combinationTransformerResult = _combinationTransformer (_combination,_combinationNo)
613
+ ) !== _undefined
614
+ )
615
+ _combination = _combinationTransformerResult
616
+ ;
617
+
618
+ /*** call iteration handler, if combination matcher permits ***/
619
+ (!_combinationMatcher || _combinationMatcher (_combination,_combinationNo)) &&
620
+ _iterationHandler (_combination)
621
+ ;
622
+
623
+ /*** advance to next combination ***/
624
+ _keyNo = _keysLength;
625
+ while (
626
+ --_keyNo >= 0 &&
627
+ !(
628
+ _valueNoPerKeyNo [_keyNo] =
629
+ (_valueNoPerKeyNo [_keyNo] + 1) % _valuesLengthPerKeyNo [_keyNo]
630
+ )
631
+ );
632
+ }
633
+ }
634
+ /*?
635
+ Static Methods
636
+ Uize.Data.Combinations.forEach
637
+ Iterates through the generated combinations, calling the specified iterator handler for each combination.
638
+
639
+ DIFFERENT USAGES
640
+
641
+ `Iterate Over a Set of Generated Combinations`
642
+ .....................................................................................
643
+ Uize.Data.Combinations.forEach (combinationsSpecifierOBJorARRAY,iteratorHandlerFUNC);
644
+ .....................................................................................
645
+
646
+ `Iterate Over a Set of Transformed Combinations`
647
+ ...................................
648
+ Uize.Data.Combinations.forEach (
649
+ combinationsSpecifierOBJorARRAY,
650
+ iteratorHandlerFUNC,
651
+ combinationTransformerSTRorFUNC
652
+ );
653
+ ...................................
654
+
655
+ `Iterate Over a Filtered Set of Combinations`
656
+ ...................................
657
+ Uize.Data.Combinations.forEach (
658
+ combinationsSpecifierOBJorARRAY,
659
+ iteratorHandlerFUNC,
660
+ combinationTransformerSTRorFUNC,
661
+ combinationMatcherSTRorFUNC
662
+ );
663
+ ...................................
664
+
665
+ Iterate Over a Set of Generated Combinations
666
+ In the most typical use case, an array of combinations can be iterated over by specifying just the =combinationsSpecifierOBJorARRAY= and =iteratorHandlerFUNC= parameters.
667
+
668
+ SYNTAX
669
+ .....................................................................................
670
+ Uize.Data.Combinations.forEach (combinationsSpecifierOBJorARRAY,iteratorHandlerFUNC);
671
+ .....................................................................................
672
+
673
+ The =combinationsSpecifierOBJorARRAY= parameter lets you specify the `combination specifier` from which the combinations will be generated. `When the combination specifier is an object`, the generated combinations will be objects. `When the combination specifier is an array`, the generated combinations will be arrays. For more information, refer to the section `How Combinations Are Generated`.
674
+
675
+ The =iteratorHandlerFUNC= parameter lets you specify the handler function that should be called for each iteration. The handler function will be called with a single argument, being the generated combination for the iteration.
676
+
677
+ EXAMPLE
678
+ .................................................................................
679
+ var channelValues = ['00','33','66','99','CC','FF'];
680
+ Uize.Data.Combinations.forEach (
681
+ [channelValues,channelValues,channelValues],
682
+ function (webSafeColorTuple) {console.log ('#' + webSafeColorTuple.join (''))}
683
+ );
684
+ .................................................................................
685
+
686
+ In the above example, the RGB hex values of all the Web safe colors are being logged to the console. In our iteration handler function, we are defining the single argument =webSafeColorTuple=. This argument is essentially the generated combination for the iteration, but we can call it whatever makes the most sense in our particular application. In this example, each generated combination is really a Web safe colo tuple, with values for the red, green, and blue color channels.
687
+
688
+ Iterate Over a Set of Transformed Combinations
689
+ When the optional =combinationTransformerSTRorFUNC= third parameter is specified, the generated combinations can be transformed before they are passed to the iteration handler.
690
+
691
+ SYNTAX
692
+ ...................................
693
+ Uize.Data.Combinations.forEach (
694
+ combinationsSpecifierOBJorARRAY,
695
+ iteratorHandlerFUNC,
696
+ combinationTransformerSTRorFUNC
697
+ );
698
+ ...................................
699
+
700
+ For more information on combination transformers and to see examples, refer to the section `Optional Combination Transformer`.
701
+
702
+ Iterate Over a Filtered Set of Combinations
703
+ When the optional =combinationMatcherSTRorFUNC= fourth parameter is specified, the generated (and optionally transformed) combinations can be filtered.
704
+
705
+ SYNTAX
706
+ ...................................
707
+ Uize.Data.Combinations.forEach (
708
+ combinationsSpecifierOBJorARRAY,
709
+ iteratorHandlerFUNC,
710
+ combinationTransformerSTRorFUNC,
711
+ combinationMatcherSTRorFUNC
712
+ );
713
+ ...................................
714
+
715
+ When a combination matcher is desired but a combination transformer is not desired, the value =null= or =undefined= can be specified for the =combinationTransformerSTRorFUNC= parameter. For more information on combination matchers and to see examples, refer to the section `Optional Combination Matcher`.
716
+
717
+ NOTES
718
+ - compare to the =Uize.Data.Combinations.generate= static method
719
+ */
720
+ };
721
+
722
+ return _package;
723
+ }
724
+ });
725
+
skin/frontend/default/customproduct/js/Uize.Data.Csv.js ADDED
@@ -0,0 +1,1190 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ /*______________
2
+ | ______ | U I Z E J A V A S C R I P T F R A M E W O R K
3
+ | / / | ---------------------------------------------------
4
+ | / O / | MODULE : Uize.Data.Csv Package
5
+ | / / / |
6
+ | / / / /| | ONLINE : http://www.uize.com
7
+ | /____/ /__/_| | COPYRIGHT : (c)2009-2012 UIZE
8
+ | /___ | LICENSE : Available under MIT License or GNU General Public License
9
+ |_______________| http://www.uize.com/license.html
10
+ */
11
+
12
+ /* Module Meta Data
13
+ type: Package
14
+ importance: 3
15
+ codeCompleteness: 100
16
+ testCompleteness: 100
17
+ docCompleteness: 100
18
+ */
19
+
20
+ /*?
21
+ Introduction
22
+ The =Uize.Data.Csv= module provides support for serializing to and parsing from [[http://en.wikipedia.org/wiki/Comma-separated_values][CSV (Comma Separated Values)]] formatted data, with configurable options.
23
+
24
+ *DEVELOPERS:* `Chris van Rensburg`
25
+
26
+ Key Features
27
+ The versatile =Uize.Data.Csv= module supports the following key features...
28
+
29
+ Multiline Column Values
30
+ Column values that contain linebreaks (either carriage return or linefeed characters) can be serialized *and* parsed using the methods of the =Uize.Data.Csv= module.
31
+
32
+ When data is serialized where column values contain linebreak characters, those column values are always quoted in the serialized CSV data string, and the values will span multiple lines. That's because the CSV format doesn't provide a dedicated way for escaping linebreak characters. When parsing CSV formatted data, the =Uize.Data.Csv.from= method automatically reads column values across multiple lines when they are quoted and contain linebreak characters.
33
+
34
+ Header Row
35
+ The CSV format allows for an optional header row that contains the names of the columns.
36
+
37
+ The =Uize.Data.Csv= module provides support for header rows when both serializing to and parsing from CSV data strings. Support for header rows is enabled by specifying the value =true= for the =hasHeader= option, available for both the =Uize.Data.Csv.from= and =Uize.Data.Csv.to= static methods.
38
+
39
+ Header Rows and Parsing from CSV
40
+ Header rows are supported when parsing from CSV data, both to arrays of arrays and to arrays of objects.
41
+
42
+ When parsing CSV data to an array of arrays, a header row that exists in the CSV data string can either just be "gobbled" and thrown away, or it can be gathered in an empty array that you supply using the =columns= decoding option. Either way, the column names in a header row are kept from getting into the records array that is returned by the =Uize.Data.Csv.from= method, because they are not part of the data set.
43
+
44
+ When parsing CSV data to an array of objects, the header row that exists in the CSV data string can be used for the key names for the objects in the returned records array. If there is no header row in the CSV data string and the value =false= is specified for the =hasHeader= option, the column names can still be supplied to the =Uize.Data.Csv.from= method using the =columns= decoding option when parsing to an array of objects.
45
+
46
+ Header Rows and Serializing to CSV
47
+ Header rows are supported when serializing to CSV data, both from arrays of arrays and from arrays of objects.
48
+
49
+ When serializing an array of arrays to a CSV data string, the column names to be used in the header row can be supplied to the =Uize.Data.Csv.to= method using the =columns= encoding option.
50
+
51
+ When serializing an array of objects to a CSV data string, the column names to be used in the header row can be taken directly from the key names of the first object in the records array, or they can be explicitly specified to the =Uize.Data.Csv.to= method using the =columns= encoding option. Using the =columns= option allows the column order to be controlled, or a subset of the columns to be serialized (see `Column Ordering And Filtering`).
52
+
53
+ Object or Array Type Rows
54
+ The =Uize.Data.Csv= module supports serializing from and parsing to a records array, where records are represented as either arrays or objects.
55
+
56
+ When records are represented as objects, each key represents the name of a column and each value is that column's value. When records are represented as arrays, then each element of a record's array is a column value.
57
+
58
+ The row type - array or object - can be controlled using the =rowType= option, available for both the =Uize.Data.Csv.from= and =Uize.Data.Csv.to= static methods. When the value ='auto'= (the default) is used for the =rowType= option when parsing CSV data, then array or object type will be chosen based upon the value of the =hasHeader= decoding option, with object type being chosen when =hasHeader= is =true=, and array type being chosen when =hasHeader= is =false=. When ='auto'= is used for the =rowType= option when serializing CSV data, then array or object type will be chosen based upon the type of the first element of the records array being serialized.
59
+
60
+ When serializing to a CSV data string from an array of objects, the =columns= option can be used to control the column order, or to serialize only a subset of the columns (see `Column Ordering And Filtering`). When parsing from a CSV data string to an array of objects, the key names for the record objects can be taken from the header row of the CSV data string (the value =true= is specified for the =hasHeader= option), or the key names can be supplied in the =columns= decoding option.
61
+
62
+ Configurable Quoting Character
63
+ While [[http://tools.ietf.org/html/rfc4180][RFC 4180]] only addresses quoting of values using the double quote character, the =Uize.Data.Csv= module provides the flexibility to use other quoting characters - both when serializing using the =Uize.Data.Csv.to= method and parsing using the =Uize.Data.Csv.from= method.
64
+
65
+ The quoting character is specified using the =quoteChar= option, available for both the =Uize.Data.Csv.from= and =Uize.Data.Csv.to= methods. The value specified for this option should be a string, specifying the *single* character used for quoting values in the serialized CSV data string.
66
+
67
+ When serializing data to CSV format using a quoting character other than double quotes, it is important to specify that character in the =quoteChar= option when later parsing that serialized data - the =Uize.Data.Csv.from= method cannot tell automatically from the CSV data string what the quoting character is. Whatever quoting character is specified, if a value contains that quote character, then that value will be quoted. As per the RFC 4180 rules, the quoting character is escaped by doubling it.
68
+
69
+ Configurable Quoting Behavior
70
+ By default, the =Uize.Data.Csv.to= method automatically chooses whether or not to quote individual values, based upon a number of different criteria.
71
+
72
+ This behavior can be controlled, though, using the =whenToQuoteValues= encoding option. When the value ='always'= is specified for this option, all column values in the serialized CSV data string will always be quoted. When this option is left in its default state of ='auto'=, then column values will be automatically quoted, only when they contain the quoting character (see the =quoteChar= option) or the value delimiter string (see the =valueDelimiter= option), if they contain linebreaks (either carriage return or linefeed characters), if they contain whitespace padding and the value =true= is specified for the =trimPaddingOnParse= option, or if the value delimiter (see the =valueDelimiter= option) contains whitespace padding and the value =false= is specified for the =trimPaddingOnParse= option.
73
+
74
+ Configurable Value Delimiter
75
+ While [[http://tools.ietf.org/html/rfc4180][RFC 4180]] only addresses separating values using the comma character, the =Uize.Data.Csv= module provides the flexibility to use other value delimiter characters - both when serializing using the =Uize.Data.Csv.to= method and parsing using the =Uize.Data.Csv.from= method.
76
+
77
+ The value delimiter is specified using the =valueDelimiter= option, available for both the =Uize.Data.Csv.from= and =Uize.Data.Csv.to= methods. The value specified for this option should be a string, specifying the delimiter used for separating column values in rows of CSV data string.
78
+
79
+ When serializing data to CSV format using a value delimiter character other than comma, it is important to specify that delimiter in the =valueDelimiter= option when later parsing that serialized data - the =Uize.Data.Csv.from= method cannot tell automatically from the CSV data string what the value delimiter is.
80
+
81
+ Whatever value delimiter string is specified, if a value contains that string, then that value will be quoted. Also, if the value delimiter has whitespace padding, then the column values will always be quoted to ensure that later parsing doesn't result in the value delimiter's padding becoming whitespace in the parsed column values.
82
+
83
+ Column Ordering And Filtering
84
+ When serializing an array of objects to a CSV data string, the =Uize.Data.Csv= module provides support for controlling the ordering of columns in the serialized data string, as well as serializing just a subset of the columns in the data set.
85
+
86
+ Column Order
87
+ The =columns= encoding option can be used to enforce an ordering for columns in the serialized CSV data string.
88
+
89
+ If you're serializing a records array where the records are of type object and you leave it up to the =Uize.Data.Csv.to= method to determine the columns, the column order will depend entirely on the order in which the keys were assigned to the first row's object in the records array. As long as the serialized CSV data string has a header row (the value =true= is specified for the =hasHeader= option) and the data is to be later parsed to an array of objects, one may not care about the column ordering. If column ordering is important, however, then the =columns= option can be used to control this.
90
+
91
+ Subset of Columns
92
+ In some cases you may wish to serialize an array of object records, but not include all of the columns in the serialized output.
93
+
94
+ In such cases you can use the =columns= encoding option to specify just the columns that you wish to have serialized, along with the exact order in which you wish them to be arranged in the serialized CSV data string.
95
+
96
+ Trimming of Value Padding
97
+ While whitespace around value separator characters is considered significant, and while trimming such whitespace is specifically prohibited according to [[http://tools.ietf.org/html/rfc4180][RFC 4180]], the =Uize.Data.Csv= module supports trimming of value padding - both when serializing using the =Uize.Data.Csv.to= method and parsing using the =Uize.Data.Csv.from= method.
98
+
99
+ When parsing CSV data, there might be real world situations where one is dealing with CSV data that is not serialized strictly according to the rules laid out in RFC 4180, and where there might be spaces after comma value separators. In such cases, the value =true= can be specified for the =trimPaddingOnParse= decoding option, which will cause the leading and trailing whitespace padding around the first and last non-whitespace characters of non-quoted values to be trimmed (for quoted values, this option will have no effect on the result).
100
+
101
+ When serializing CSV data, the data serialized by the =Uize.Data.Csv.to= method may at some point be parsed by code that doesn't strictly observe the rules laid out in RFC 4180 and which may strip padding around comma value separators. In such cases, the value =true= can be specified for the =trimPaddingOnParse= encoding option, which will cause values that contain leading and/or trailing whitespace padding around the first and last non-whitespace characters to be quoted in order to ensure that whitespace that is part of values is not accidentally stripped by a non-compliant CSV parser.
102
+ */
103
+
104
+ Uize.module ({
105
+ name:'Uize.Data.Csv',
106
+ required:'Uize.String',
107
+ builder:function () {
108
+ /*** Variables for Scruncher Optimization ***/
109
+ var
110
+ _package = function () {},
111
+ _true = true,
112
+ _false = false,
113
+ _undefined
114
+ ;
115
+
116
+ /*** General Variables ***/
117
+ var _optionDefaults = {
118
+ columns:'all', // 'all' | an array of column names
119
+ hasHeader:false, // true | false
120
+ trimPaddingOnParse:false, // true | false
121
+ quoteChar:'"', // '"' | '\'' | any single char
122
+ rowType:'auto', // 'array' | 'object' | 'auto'
123
+ valueDelimiter:',', // ',' | ';' | '\t' | any single char
124
+ whenToQuoteValues:'auto' // 'auto' | 'always'
125
+ };
126
+
127
+ /*** Utility Functions ***/
128
+ function _getDefaultedOption (_options,_optionName) {
129
+ var _optionValue = _options ? _options [_optionName] : _undefined;
130
+ return _optionValue == _undefined ? _optionDefaults [_optionName] : _optionValue;
131
+ }
132
+
133
+ function _getEscapedQuoteChar (_options) {
134
+ return Uize.String.repeat (_getDefaultedOption (_options,'quoteChar'),2);
135
+ }
136
+
137
+ function _globalLiteralRegExp (_replaceStr) {
138
+ return new RegExp (Uize.escapeRegExpLiteral (_replaceStr),'g');
139
+ }
140
+
141
+ /*** Public Static Methods ***/
142
+ _package.from = function (_toDecode,_decodingOptions) {
143
+ var
144
+ _columns = _getDefaultedOption (_decodingOptions,'columns'),
145
+ _hasHeader = _getDefaultedOption (_decodingOptions,'hasHeader'),
146
+ _trimPaddingOnParse = _getDefaultedOption (_decodingOptions,'trimPaddingOnParse'),
147
+ _quoteChar = _getDefaultedOption (_decodingOptions,'quoteChar'),
148
+ _rowType = _getDefaultedOption (_decodingOptions,'rowType'),
149
+ _valueDelimiter = _getDefaultedOption (_decodingOptions,'valueDelimiter'),
150
+ _escapedQuoteChar = _getEscapedQuoteChar (_decodingOptions),
151
+ _escapedQuoteCharRegExp = _globalLiteralRegExp (_escapedQuoteChar),
152
+ _columnsIsArray = Uize.isArray (_columns),
153
+ _rowTypeIsObject =
154
+ _rowType == 'object' || (_rowType == 'auto' && (_hasHeader || (_columnsIsArray && _columns.length))),
155
+ _rows = [],
156
+ _currentPos = 0,
157
+ _rowNo = _hasHeader ? -1 : 0,
158
+ _columnNo = 0,
159
+ _toDecodeLength = _toDecode.length,
160
+ _toDecodeLengthMinus1 = _toDecodeLength - 1
161
+ ;
162
+ _hasHeader && (_columnsIsArray ? (_columns.length = 0) : (_columns = []));
163
+ function _addColumn (_value) {
164
+ (
165
+ _rowNo < 0
166
+ ? _columns
167
+ : _rows [_rowNo] || (_rows [_rowNo] = _rowTypeIsObject ? {} : [])
168
+ ) [
169
+ _rowTypeIsObject && _rowNo > -1 ? _columns [_columnNo] : _columnNo
170
+ ] =
171
+ _trimPaddingOnParse ? Uize.String.trim (_value) : _value
172
+ ;
173
+ _columnNo++;
174
+ }
175
+ function _nextIndexOf (_char) {
176
+ var _result = _toDecode.indexOf (_char,_currentPos);
177
+ return _result < 0 ? _toDecodeLength : _result;
178
+ }
179
+ function _nextDelimiterPos () {
180
+ return Math.min (
181
+ _nextIndexOf ('\n'),
182
+ _nextIndexOf ('\r'),
183
+ _nextIndexOf (_valueDelimiter),
184
+ _nextIndexOf (_quoteChar)
185
+ );
186
+ }
187
+ var
188
+ _nextSignificantCharPos,
189
+ _nextSignificantChar,
190
+ _endFound,
191
+ _escapedQuotesFound,
192
+ _closingQuoteCharPos
193
+ ;
194
+ while (_currentPos < _toDecodeLength) {
195
+ _nextSignificantChar =
196
+ _toDecode.charAt (_closingQuoteCharPos = _nextSignificantCharPos = _nextDelimiterPos ())
197
+ ;
198
+ if (_nextSignificantChar == _quoteChar) {
199
+ /*** find end of value ***/
200
+ _endFound = _escapedQuotesFound = _false;
201
+ while (!_endFound) {
202
+ _closingQuoteCharPos = _toDecode.indexOf (_quoteChar,_closingQuoteCharPos + 1);
203
+ if (_closingQuoteCharPos < 0) _closingQuoteCharPos = _toDecodeLength;
204
+ _closingQuoteCharPos < _toDecodeLengthMinus1 &&
205
+ _toDecode.charAt (_closingQuoteCharPos + 1) == _quoteChar
206
+ ? (_closingQuoteCharPos += (_escapedQuotesFound = _true))
207
+ : (_endFound = _true)
208
+ ;
209
+ }
210
+
211
+ /*** add the column value ***/
212
+ var _columnValue = _toDecode.slice (_nextSignificantCharPos + 1,_closingQuoteCharPos);
213
+ _addColumn (
214
+ _escapedQuotesFound
215
+ ? _columnValue.replace (_escapedQuoteCharRegExp,_quoteChar)
216
+ : _columnValue
217
+ );
218
+
219
+ _currentPos = _closingQuoteCharPos + 1; // update _currentPos for _nextDelimiterPos call below
220
+ _currentPos = _nextDelimiterPos (); // find next delimiter
221
+ _currentPos += _toDecode.charAt (_currentPos) == _valueDelimiter; // advance by 1, if delimiter is value delimiter
222
+ } else if (
223
+ _nextSignificantCharPos == _currentPos &&
224
+ (_nextSignificantChar == '\n' || _nextSignificantChar == '\r')
225
+ ) {
226
+ _rowNo++;
227
+ _columnNo = 0;
228
+ _currentPos += 1 + (
229
+ _nextSignificantChar == '\r' &&
230
+ _currentPos < _toDecodeLengthMinus1 &&
231
+ _toDecode.charAt (_currentPos + 1) == '\n'
232
+ );
233
+ } else {
234
+ _addColumn (_toDecode.slice (_currentPos,_nextSignificantCharPos));
235
+ _currentPos = _nextSignificantCharPos + (_nextSignificantChar == _valueDelimiter);
236
+ }
237
+ }
238
+ return _rows;
239
+ /*?
240
+ Static Methods
241
+ Uize.Data.Csv.from
242
+ Returns an array, being the records parsed from the specified CSV formatted data string.
243
+
244
+ SYNTAX
245
+ ...............................................
246
+ recordsARRAY = Uize.Data.Csv.from (csvDataSTR);
247
+ ...............................................
248
+
249
+ VARIATION
250
+ ..................................................................
251
+ recordsARRAY = Uize.Data.Csv.from (csvDataSTR,decodingOptionsOBJ);
252
+ ..................................................................
253
+
254
+ When the optional =decodingOptionsOBJ= parameter is specified, then CSV data strings that have not been serialized in strict accordance with the rules laid out in RFC 4180 can be successfully parsed. If one uses the =encodingOptionsOBJ= parameter of the companion =Uize.Data.Csv.to= method to serialize data to CSV format in a way that deviates from the rules of RFC 4180, then you can specify those same options in the =decodingOptionsOBJ= parameter in order to successfully parse that non-standard serialized CSV data back into a records array.
255
+
256
+ The value of the =encodingOptionsOBJ= parameter should be an object, with properties as follows...
257
+
258
+ DECODING OPTIONS
259
+ ..............................................................................
260
+ {
261
+ columns:columnsARRAY, // optional
262
+ hasHeader:hasHeaderBOOL, // optional, defaults to false
263
+ trimPaddingOnParse:trimPaddingOnParseBOOL, // optional, defaults to false
264
+ quoteChar:quoteCharSTR, // optional, defaults to '"'
265
+ rowType:rowTypeSTR, // optional, defaults to 'auto'
266
+ valueDelimiter:valueDelimiterSTR // optional, defaults to ','
267
+ }
268
+ ..............................................................................
269
+
270
+ columns
271
+ An array, that will be used to store the column names for the CSV data if the value =true= is specified for the =hasHeader= option, or that can be used to supply the names of columns if the value =false= is specified for the =hasHeader= option and the value ='object'= is specified for the =rowType= option.
272
+
273
+ When Data Has Header Row
274
+ When parsing a CSV data string that contains a header row, to an array of arrays (ie. specifying the value ='array'= for the =rowType= option), and specifying the value =true= for the =hasHeader= option, the column names row doesn't make its way into the returned records array.
275
+
276
+ This is by design, because the column names are not part of the data set. In such cases, specifying an array value for the =columns= option provides a way for you to obtain the column names. Even when parsing such a CSV data string to an array of objects, where each record object has key names that reflect the column names obtained from the header row, it still may be useful to get back a separate array of the column names - especially for the occasional case where the CSV data string has no data, but just the column names header row.
277
+
278
+ NOTE
279
+
280
+ The contents of an array specified for the =columns= option will be replaced with the column names from the CSV data string's header row. Typically, you would supply an empty array, but you could reuse an array with existing contents.
281
+
282
+ When Data Doesn't Have Header Row
283
+ When parsing a CSV data string that doesn't contain a header row, to an array of objects (ie. specifying the value ='object'= for the =rowType= option), then the =columns= option lets you specify the names of the columns.
284
+
285
+ Column names supplied by the =columns= option will be used as the key names for the objects of the returned records array. In this case, the contents of the specified column names array will not be altered.
286
+
287
+ NOTES
288
+ - the default value for this option is ='all'= (not meaningful for the =Uize.Data.Csv.from= method)
289
+
290
+ hasHeader
291
+ A boolean, specifying whether or not the CSV data string to be parsed has a header row for the column names.
292
+
293
+ When the value =true= is specified for this option, the first row of CSV data will be used for the column names and will be "gobbled" (ie. won't make its way into the returned records array). If an array reference is specified as a value for the =columns= option, then the column names read from the header row will be populated into the specified array. If the value ='object'= is specified for the =rowType= option, then the column names obtained from the header row will be used as the key names for the objects of the returned records array.
294
+
295
+ NOTES
296
+ - the default value for this option is =false=
297
+
298
+ trimPaddingOnParse
299
+ A boolean, specifying whether or not padding around non-quoted values should be trimmed away.
300
+
301
+ While whitespace around value separator characters is considered significant, and while trimming such whitespace is specifically prohibited according to [[http://tools.ietf.org/html/rfc4180][RFC 4180]], there might be real world situations where one is dealing with CSV data that is not serialized strictly according to the rules laid out in RFC 4180, and where there might be spaces after comma value separators.
302
+
303
+ In such cases, the value =true= can be specified for the =trimPaddingOnParse= option, which will cause the leading and trailing whitespace padding around the first and last non-whitespace characters of non-quoted values to be trimmed (for quoted values, this option will have no effect on the result). Use this option with caution.
304
+
305
+ NOTES
306
+ - the default value for this option is =false=
307
+
308
+ quoteChar
309
+ A string, specifying the *single* character used for quoting values in the CSV data string to be parsed.
310
+
311
+ While [[http://tools.ietf.org/html/rfc4180][RFC 4180]] only addresses quoting of values using the double quote character, the =Uize.Data.Csv= module provides the flexibility to use other quoting characters - both when parsing using the =Uize.Data.Csv.from= method and serializing using the =Uize.Data.Csv.to= method.
312
+
313
+ If you are dealing with CSV formatted data that has not been serialized in strict compliance with the rules of RFC 4180 and a quoting character other than the double quote was used when serializing it, then you can specify that character for the =quoteChar= option in order to parse that data.
314
+
315
+ NOTES
316
+ - the value of the =quoteChar= option may not be the same as the =valueDelimiter= option
317
+ - the default value for this option is ='"'= (the double quote character)
318
+
319
+ rowType
320
+ A string, specifying the type for the records in the returned records array.
321
+
322
+ - ='array'= - Each row's record is represented by an array of values for the various columns.
323
+
324
+ - ='object'= - Each row's record is represented by an object, with keys named according to the column names.
325
+
326
+ - ='auto'= (default) - Array or object type will be chosen based upon the value of the =hasHeader= option, with object type being chosen when =hasHeader= is =true=, and array type being chosen when =hasHeader= is =false=.
327
+
328
+ If the value ='object'= is specified for the =rowType= option and the value =false= is specified for the =hasHeader= option, then the column names should be supplied in the =columns= option.
329
+
330
+ NOTES
331
+ - the default value for this option is ='auto'=
332
+
333
+ valueDelimiter
334
+ A string, specifying the delimiter that separates column values in rows of the CSV data string to be parsed.
335
+
336
+ While [[http://tools.ietf.org/html/rfc4180][RFC 4180]] only addresses separating values using the comma character, the =Uize.Data.Csv= module provides the flexibility to use other value delimiter characters - both when parsing using the =Uize.Data.Csv.from= method and serializing using the =Uize.Data.Csv.to= method.
337
+
338
+ If you are dealing with CSV formatted data that has not been serialized in strict compliance with the rules of RFC 4180 and a value delimiter string other than a single comma was used when serializing it, then you can specify that delimiter string for the =valueDelimiter= option in order to parse that data.
339
+
340
+ NOTES
341
+ - the value of the =valueDelimiter= option may not be the same as the =quoteChar= option, and may not contain the quoting character if it is a multi-character delimiter
342
+ - the default value for this option is =','= (the comma character)
343
+
344
+ Examples
345
+ Default Decoding Options
346
+ In this example, the CSV data string being parsed has been serialized in strict accordance to the rules laid out in RFC 4180, and is being parsed by the =Uize.Data.Csv.from= method using all the decoding option defaults (ie. no =decodingOptionsOBJ= parameter is being specified).
347
+
348
+ INPUT
349
+ ............................................
350
+ "John ""Willy""",Wilkey,(650) 123-4567
351
+ Marie, Stevenson ,"(415) 456-7890, Ext. 214"
352
+ Craig,Pollack,"(310) 987-6543
353
+ (650) 303-1000"
354
+ ............................................
355
+
356
+ PARSE
357
+ ...........................
358
+ Uize.Data.Csv.from (input);
359
+ ...........................
360
+
361
+ OUTPUT
362
+ .......................................................
363
+ [
364
+ ['John "Willy"','Wilkey','(650) 123-4567'],
365
+ ['Marie',' Stevenson ','(415) 456-7890, Ext. 214'],
366
+ ['Craig','Pollack','(310) 987-6543\n(650) 303-1000']
367
+ ]
368
+ .......................................................
369
+
370
+ Looking at the CSV data string, you'll notice a few things...
371
+
372
+ - The value ="John ""Willy"""= is quoted because it contains the double quote quoting character, and the double quotes in the value are escaped by doubling them up (ie. two double quotes for each double quote being escaped).
373
+ - The value ="(415) 456-7890, Ext. 214"= is quoted because it contains the comma value delimiter character.
374
+ - The phone number column for the last row is quoted because it contains a linebreak and spans two lines.
375
+
376
+ None of the above factors are a problem for the =Uize.Data.Csv.from= method, since all these behaviors comply with the rules of RFC 4180.
377
+
378
+ Padding After Value Separator Comma, Trim Padding On Parse
379
+ In this example, the CSV data string was originally serialized with a cosmetic space after the comma value delimiter.
380
+
381
+ We happen to know this about the source material, so we specify the value =true= for the =trimPaddingOnParse= option. This results in the whitespace padding around values being trimmed away. In the returned records array, therefore, the column values do not contain padding.
382
+
383
+ INPUT
384
+ ................................
385
+ John, Wilkey, (650) 123-4567
386
+ Marie, Stevenson, (415) 456-7890
387
+ Craig, Pollack, (310) 987-6543
388
+ ................................
389
+
390
+ PARSE
391
+ .....................................................
392
+ Uize.Data.Csv.from (input,{trimPaddingOnParse:true});
393
+ .....................................................
394
+
395
+ OUTPUT
396
+ ..........................................
397
+ [
398
+ ['John','Wilkey','(650) 123-4567'],
399
+ ['Marie','Stevenson','(415) 456-7890'],
400
+ ['Craig','Pollack','(310) 987-6543']
401
+ ]
402
+ ..........................................
403
+
404
+ No Header Row, Column Names Explicitly Specified
405
+ In this example, we're parsing a CSV data string to an array of records and supplying the column names.
406
+
407
+ INPUT
408
+ ..............................
409
+ John,Wilkey,(650) 123-4567
410
+ Marie,Stevenson,(415) 456-7890
411
+ Craig,Pollack,(310) 987-6543
412
+ ..............................
413
+
414
+ PARSE
415
+ ......................................................................
416
+ Uize.Data.Csv.from (input,{columns:['firstName','lastName','phone']});
417
+ ......................................................................
418
+
419
+ OUTPUT
420
+ ..................................................................
421
+ [
422
+ {firstName:'John',lastName:'Wilkey',phone:'(650) 123-4567'},
423
+ {firstName:'Marie',lastName:'Stevenson',phone:'(415) 456-7890'},
424
+ {firstName:'Craig',lastName:'Pollack',phone:'(310) 987-6543'}
425
+ ]
426
+ ..................................................................
427
+
428
+ As you'll notice from the CSV data string, there is no header row to indicate the column names. Therefore, when we parse the string we provide the column names using the =columns= option. Now, because we're specifying an array for the =columns= option, and because we're not specifying a value for the =rowType= option (so it defaults to ='auto'=), the =Uize.Data.Csv.from= method chooses object type for the records. The column names that we've provided are used as the keys for the record objects.
429
+
430
+ With Header Row
431
+ In this example, the CSV data string contains a header row and we're parsing the string to an array of objects.
432
+
433
+ INPUT
434
+ ..............................
435
+ firstName,lastName,phone
436
+ John,Wilkey,(650) 123-4567
437
+ Marie,Stevenson,(415) 456-7890
438
+ Craig,Pollack,(310) 987-6543
439
+ ..............................
440
+
441
+ PARSE
442
+ ............................................
443
+ Uize.Data.Csv.from (input,{hasHeader:true});
444
+ ............................................
445
+
446
+ OUTPUT
447
+ ..................................................................
448
+ [
449
+ {firstName:'John',lastName:'Wilkey',phone:'(650) 123-4567'},
450
+ {firstName:'Marie',lastName:'Stevenson',phone:'(415) 456-7890'},
451
+ {firstName:'Craig',lastName:'Pollack',phone:'(310) 987-6543'}
452
+ ]
453
+ ..................................................................
454
+
455
+ The =Uize.Data.Csv.from= method doesn't know that the CSV data string has a header row unless we tell it, so we specify the value =true= for the =hasHeader= option. Now, because we're specifying =true= for the =hasHeader= option, and because we're not specifying a value for the =rowType= option (so it defaults to ='auto'=), the =Uize.Data.Csv.from= method chooses object type for the records. The column names are obtained from the first row of the CSV data string and are used as the keys for the record objects.
456
+
457
+ With Header Row, Rows Are Arrays
458
+ In this example, the CSV data string contains a header row, but we want to parse the string to an array of arrays and don't want the column names in the data set.
459
+
460
+ INPUT
461
+ ..............................
462
+ firstName,lastName,phone
463
+ John,Wilkey,(650) 123-4567
464
+ Marie,Stevenson,(415) 456-7890
465
+ Craig,Pollack,(310) 987-6543
466
+ ..............................
467
+
468
+ PARSE
469
+ ............................................................
470
+ Uize.Data.Csv.from (input,{hasHeader:true,rowType:'array'});
471
+ ............................................................
472
+
473
+ OUTPUT
474
+ ..........................................
475
+ [
476
+ ['John','Wilkey','(650) 123-4567'],
477
+ ['Marie','Stevenson','(415) 456-7890'],
478
+ ['Craig','Pollack','(310) 987-6543']
479
+ ]
480
+ ..........................................
481
+
482
+ First off, the =Uize.Data.Csv.from= method doesn't know that the CSV data string has a header row unless we tell it, so we specify the value =true= for the =hasHeader= option. If we don't expicitly specify a value for the =rowType= option, this option will default to ='auto'=, and the =Uize.Data.Csv.from= method will decide to parse the CSV data string to an array of objects because we're specifying =true= for the =hasHeader= option. By specifying the value ='array'= for =rowType=, we override this automatic behavior. This results in the header row being "gobbled" up - it's not getting used as the keys for object records, and it doesn't belong in the data set.
483
+
484
+ With Header Row, Rows Are Arrays, Get Back Column Names
485
+ In this example, the CSV data string contains a header row, we want to parse the string to an array of arrays and don't want the column names in the data set, but we would like to know what the column names are.
486
+
487
+ INPUT
488
+ ..............................
489
+ firstName,lastName,phone
490
+ John,Wilkey,(650) 123-4567
491
+ Marie,Stevenson,(415) 456-7890
492
+ Craig,Pollack,(310) 987-6543
493
+ ..............................
494
+
495
+ PARSE
496
+ ................................................................................
497
+ var columnNames = [];
498
+ Uize.Data.Csv.from (input,{hasHeader:true,rowType:'array',columns:columnNames});
499
+ ................................................................................
500
+
501
+ OUTPUT
502
+ ..........................................
503
+ [
504
+ ['John','Wilkey','(650) 123-4567'],
505
+ ['Marie','Stevenson','(415) 456-7890'],
506
+ ['Craig','Pollack','(310) 987-6543']
507
+ ]
508
+ ..........................................
509
+
510
+ First off, the =Uize.Data.Csv.from= method doesn't know that the CSV data string has a header row unless we tell it, so we specify the value =true= for the =hasHeader= option. We specify the value ='array'= for the =rowType= option to override the automatic behaviour in this case of parsing the CSV data string to an array of objects. Finally, we specify a reference to an empty array for the =columns= option. This empty array will be populated with the column names obtained from the CSV data string's header row. We can then use these column names later in other code.
511
+
512
+ Values Quoted Using Single Quotes
513
+ In this example, the CSV data string was originally serialized using a single quote character for quoting values, rather than the standard double quote character.
514
+
515
+ We happen to know this about the source material, so we specify the value ='\''= for the =quoteChar= option. Our CSV data string parses correctly and life is good.
516
+
517
+ INPUT
518
+ ....................................
519
+ 'John','Wilkey','(650) 123-4567'
520
+ 'Marie','Stevenson','(415) 456-7890'
521
+ 'Craig','Pollack','(310) 987-6543'
522
+ ....................................
523
+
524
+ PARSE
525
+ ............................................
526
+ Uize.Data.Csv.from (input,{quoteChar:'\''});
527
+ ............................................
528
+
529
+ OUTPUT
530
+ ..........................................
531
+ [
532
+ ['John','Wilkey','(650) 123-4567'],
533
+ ['Marie','Stevenson','(415) 456-7890'],
534
+ ['Craig','Pollack','(310) 987-6543']
535
+ ]
536
+ ..........................................
537
+
538
+ Pipe Used As a Value Delimiter
539
+ In this example, the (obviously) eccentric software that originally serialized the CSV data string used a "|" (pipe) character for separating column values.
540
+
541
+ Fortunately, we happen to know this about the source material, so we specify the value ='|'= for the =valueDelimiter= option and the =Uize.Data.Csv.from= method saves the day.
542
+
543
+ INPUT
544
+ ..............................
545
+ John|Wilkey|(650) 123-4567
546
+ Marie|Stevenson|(415) 456-7890
547
+ Craig|Pollack|(310) 987-6543
548
+ ..............................
549
+
550
+ PARSE
551
+ ................................................
552
+ Uize.Data.Csv.from (input,{valueDelimiter:'|'});
553
+ ................................................
554
+
555
+ OUTPUT
556
+ ..........................................
557
+ [
558
+ ['John','Wilkey','(650) 123-4567'],
559
+ ['Marie','Stevenson','(415) 456-7890'],
560
+ ['Craig','Pollack','(310) 987-6543']
561
+ ]
562
+ ..........................................
563
+
564
+ Space As Value Delimiter, Values Quoted Using Hash
565
+ To one-up the software that serialized a CSV data string using a "|" (pipe) character for separating column values, some even crazier software decided to use the "#" (pound / hash) character for quoting column values and a single space for separating values.
566
+
567
+ We suspect as much about the source material, based upon our deep-seated suspicions of the provider of the data, so we specify the value ='#'= for the =quoteChar= option and the value =' '= (space) for the =valueDelimiter= option. Everything checks out, and we've dodged another bullet.
568
+
569
+ INPUT
570
+ ....................................
571
+ #John# #Wilkey# #(650) 123-4567#
572
+ #Marie# #Stevenson# #(415) 456-7890#
573
+ #Craig# #Pollack# #(310) 987-6543#
574
+ ....................................
575
+
576
+ PARSE
577
+ ..............................................................
578
+ Uize.Data.Csv.from (input,{quoteChar:'#',valueDelimiter:' '});
579
+ ..............................................................
580
+
581
+ OUTPUT
582
+ ..........................................
583
+ [
584
+ ['John','Wilkey','(650) 123-4567'],
585
+ ['Marie','Stevenson','(415) 456-7890'],
586
+ ['Craig','Pollack','(310) 987-6543']
587
+ ]
588
+ ..........................................
589
+
590
+ NOTES
591
+ - see the companion =Uize.Data.Csv.to= static method
592
+ */
593
+ };
594
+
595
+ _package.to = function (_toEncode,_encodingOptions) {
596
+ var
597
+ _csvChunks = [],
598
+ _firstRow = _toEncode [0],
599
+ _alwaysQuote = _getDefaultedOption (_encodingOptions,'whenToQuoteValues') == 'always',
600
+ _columns = _getDefaultedOption (_encodingOptions,'columns'),
601
+ _hasHeader = _getDefaultedOption (_encodingOptions,'hasHeader'),
602
+ _trimPaddingOnParse = _getDefaultedOption (_encodingOptions,'trimPaddingOnParse'),
603
+ _quoteChar = _getDefaultedOption (_encodingOptions,'quoteChar'),
604
+ _rowType = _getDefaultedOption (_encodingOptions,'rowType'),
605
+ _valueDelimiter = _getDefaultedOption (_encodingOptions,'valueDelimiter'),
606
+ _valueDelimiterHasPadding = Uize.String.hasPadding (_valueDelimiter),
607
+ _escapedQuoteChar = _getEscapedQuoteChar (_encodingOptions),
608
+ _quoteRegExp = _globalLiteralRegExp (_quoteChar),
609
+ _rowTypeIsObject = _rowType == 'object' || (_rowType == 'auto' && _firstRow && !Uize.isArray (_firstRow))
610
+ ;
611
+ if (_columns == 'all')
612
+ _columns = !_firstRow
613
+ ? []
614
+ : _rowTypeIsObject
615
+ ? Uize.keys (_firstRow)
616
+ : Uize.map (_firstRow.length,'key')
617
+ ;
618
+ var _totalColumns = _columns.length;
619
+ for (var _rowNo = -1 - _hasHeader, _totalRows = _toEncode.length; ++_rowNo < _totalRows;) {
620
+ var _row = _rowNo < 0 ? _columns : _toEncode [_rowNo];
621
+ for (var _columnNo = -1; ++_columnNo < _totalColumns;) {
622
+ var
623
+ _columnValue = _row [_rowNo < 0 || !_rowTypeIsObject ? _columnNo : _columns [_columnNo]] + '',
624
+ _valueHasQuoteChar = _columnValue.indexOf (_quoteChar) > -1,
625
+ _quoteCharForValue =
626
+ _valueHasQuoteChar ||
627
+ _alwaysQuote ||
628
+ (_trimPaddingOnParse ? Uize.String.hasPadding (_columnValue) : _valueDelimiterHasPadding) ||
629
+ _columnValue.indexOf (_valueDelimiter) > -1 ||
630
+ _columnValue.indexOf ('\n') > -1 ||
631
+ _columnValue.indexOf ('\r') > -1
632
+ ? _quoteChar
633
+ : ''
634
+ ;
635
+ _csvChunks.push (
636
+ (_columnNo ? _valueDelimiter : '') +
637
+ _quoteCharForValue +
638
+ (_valueHasQuoteChar ? _columnValue.replace (_quoteRegExp,_escapedQuoteChar) : _columnValue) +
639
+ _quoteCharForValue
640
+ );
641
+ }
642
+ _rowNo < _totalRows - 1 && _csvChunks.push ('\n');
643
+ }
644
+ return _csvChunks.join ('');
645
+ /*?
646
+ Static Methods
647
+ Uize.Data.Csv.to
648
+ Returns a string, being the specified array of records serialized to a CSV formatted data string.
649
+
650
+ SYNTAX
651
+ .............................................
652
+ csvDataSTR = Uize.Data.Csv.to (recordsARRAY);
653
+ .............................................
654
+
655
+ VARIATION
656
+ ................................................................
657
+ csvDataSTR = Uize.Data.Csv.to (recordsARRAY,encodingOptionsOBJ);
658
+ ................................................................
659
+
660
+ When the optional =encodingOptionsOBJ= parameter is specified, then the way in which the records array is serialized to CSV data format can be configured to produce wide ranging results - even non-standard serialized CSV data that is not in strict accordance with the rules laid out in RFC 4180. If you use this parameter to produce serialized data that deviates from the rules of RFC 4180, then you should specify the same options in the =decodingOptionsOBJ= parameter of the companion =Uize.Data.Csv.from= method in order to successfully parse the non-standard serialized CSV data back into a records array.
661
+
662
+ The value of the =encodingOptionsOBJ= parameter should be an object, with properties as follows...
663
+
664
+ ENCODING OPTIONS
665
+ ..............................................................................
666
+ {
667
+ columns:columnsSTRorARRAY, // optional, defaults to 'all'
668
+ hasHeader:hasHeaderBOOL, // optional, defaults to false
669
+ trimPaddingOnParse:trimPaddingOnParseBOOL, // optional, defaults to false
670
+ quoteChar:quoteCharSTR, // optional, defaults to '"'
671
+ rowType:rowTypeSTR, // optional, defaults to 'auto'
672
+ valueDelimiter:valueDelimiterSTR, // optional, defaults to ','
673
+ whenToQuoteValues:whenToQuoteValuesSTR // optional, defaults to 'auto'
674
+ }
675
+ ..............................................................................
676
+
677
+ columns
678
+ An array, that can be used to supply column names when the value of the =hasHeader= option is =true= and the records to be serialized are of type array, or that can be used to specify the order of columns or to specify a subset of columns when the records to be serialized are of type object, or a string with the value ='all'= specifying that all columns should be serialized.
679
+
680
+ If the value ='all'= is specified for the =columns= option, then the column names will be the keys from the first record if the records to be serialized are of type object, or the indices of the columns if the records to be serialized are of type array.
681
+
682
+ When serializing an array of objects to a CSV data string, the =Uize.Data.Csv.to= method provides support for controlling the ordering of columns in the serialized data string, as well as serializing just a subset of the columns in the data set. For more info, see the section `Column Ordering And Filtering`.
683
+
684
+ NOTES
685
+ - the default value for this option is ='all'=
686
+
687
+ hasHeader
688
+ A boolean, specifying whether or not the serialized CSV data string should contain a header row.
689
+
690
+ When the value =true= is specified for this option, the first row of the serialized CSV data will contain the names of the columns. This allows the CSV formatted data to be parsed later by code that may not know the column names for the data - the column names can be obtained from the serialized data. The column names for the first row will be obtained from the =columns= option.
691
+
692
+ NOTES
693
+ - the default value for this option is =false=
694
+
695
+ trimPaddingOnParse
696
+ A boolean, specifying whether or not padding around non-quoted values will be trimmed away when the serialized CSV data string is parsed at a later stage.
697
+
698
+ While whitespace around value separator characters is considered significant, and while trimming such whitespace is specifically prohibited according to [[http://tools.ietf.org/html/rfc4180][RFC 4180]], data serialized by the =Uize.Data.Csv.to= method may at some point be parsed by code that doesn't strictly observe the rules laid out in RFC 4180 and which may strip padding around comma value separators.
699
+
700
+ In such cases, the value =true= can be specified for the =trimPaddingOnParse= option, which will cause values that contain leading and/or trailing whitespace padding around the first and last non-whitespace characters to be quoted in order to ensure that whitespace that is part of values is not accidentally stripped by a non-compliant CSV parser.
701
+
702
+ NOTES
703
+ - the default value for this option is =false=
704
+
705
+ quoteChar
706
+ A string, specifying the *single* character that should be used for quoting values in the serialized CSV data string.
707
+
708
+ While [[http://tools.ietf.org/html/rfc4180][RFC 4180]] only addresses quoting of values using the double quote character, the =Uize.Data.Csv= module provides the flexibility to use other quoting characters - both when serializing using the =Uize.Data.Csv.to= method and parsing using the =Uize.Data.Csv.from= method.
709
+
710
+ When serializing data to CSV format using a quoting character other than double quotes, it is important to specify that character in the =quoteChar= option when later parsing that serialized data - the =Uize.Data.Csv.from= method cannot tell automatically from the CSV data string what the quoting character is. Whatever quoting character is specified, if a value contains that quote character, then that value will be quoted. As per the RFC 4180 rules, the quoting character is escaped by doubling it.
711
+
712
+ NOTES
713
+ - the value of the =quoteChar= option may not be the same as the =valueDelimiter= option
714
+ - the default value for this option is ='"'= (the double quote character)
715
+
716
+ rowType
717
+ A string, specifying the type for the records in the records array to be serialized to a CSV data string.
718
+
719
+ - ='array'= - Each row's record is represented by an array of values for the various columns.
720
+
721
+ - ='object'= - Each row's record is represented by an object, with key/value pairs for the various columns, where the key is the column name and the value is the column value.
722
+
723
+ - ='auto'= (default) - Array or object type will be chosen based upon the type of the first element of the records array being serialized.
724
+
725
+ If the row type is ='array'= and the value =true= is specified for the =hasHeader= option, then the column names should be supplied in the =columns= option.
726
+
727
+ IMPORTANT
728
+
729
+ Specifying ='array'= or ='object'= for this encoding option of the =Uize.Data.Csv.to= method has less meaning than specifying ='array'= or ='object'= for the companion decoding option of the =Uize.Data.Csv.from= method. When parsing a CSV data string, the =rowType= option lets you control the type of the generated records array. When specifying ='array'= or ='object'= for the =rowType= option with the =Uize.Data.Csv.to= method, the serialization could produce faulty results if the specified row type does not match the actual type of the elements of the records array. Therefore, one will generally not specify an explicit value for this encoding option of the =Uize.Data.Csv.to= method.
730
+
731
+ NOTES
732
+ - the default value for this option is ='auto'=
733
+
734
+ valueDelimiter
735
+ A string, specifying the delimiter that should be used to separate column values in rows of the serialized CSV data string.
736
+
737
+ While [[http://tools.ietf.org/html/rfc4180][RFC 4180]] only addresses separating values using the comma character, the =Uize.Data.Csv= module provides the flexibility to use other value delimiter characters - both when serializing using the =Uize.Data.Csv.to= method and parsing using the =Uize.Data.Csv.from= method.
738
+
739
+ When serializing data to CSV format using a value delimiter character other than comma, it is important to specify that delimiter in the =valueDelimiter= option when later parsing that serialized data - the =Uize.Data.Csv.from= method cannot tell automatically from the CSV data string what the value delimiter is.
740
+
741
+ Whatever value delimiter string is specified, if a value contains that string, then that value will be quoted. Also, if the value delimiter has whitespace padding, then the column values will always be quoted to ensure that later parsing doesn't result in the value delimiter's padding becoming whitespace in the parsed column values.
742
+
743
+ NOTES
744
+ - the value of the =valueDelimiter= option may not be the same as the =quoteChar= option, and may not contain the quoting character if it is a multi-character delimiter
745
+ - the default value for this option is =','= (the comma character)
746
+
747
+ whenToQuoteValues
748
+ A boolean, specifying the quoting behavior when serializing column values.
749
+
750
+ - ='always'= - Column values will always be quoted. When this value is specified for the =whenToQuoteValues= option, all column values in the serialized CSV data string will be quoted.
751
+
752
+ - ='auto'= (default) - Column values will be automatically quoted, only when necessary. When this value is specified for the =whenToQuoteValues= option, column values will be quoted if they contain the quoting character (see the =quoteChar= option) or the value delimiter string (see the =valueDelimiter= option), if they contain linebreaks (either carriage return or linefeed characters), if they contain whitespace padding and the value =true= is specified for the =trimPaddingOnParse= option, or if the value delimiter (see the =valueDelimiter= option) contains whitespace padding and the value =false= is specified for the =trimPaddingOnParse= option.
753
+
754
+ NOTES
755
+ - the default value for this option is ='auto'=
756
+
757
+ Examples
758
+ Default Encoding Options
759
+ In this example, we have some very plain vanilla data - in the form of an array of arrays - and we're serializing this data to a CSV data string in strict accordance with the rules laid out in RFC 4180.
760
+
761
+ INPUT
762
+ ..........................................
763
+ [
764
+ ['John','Wilkey','(650) 123-4567'],
765
+ ['Marie','Stevenson','(415) 456-7890'],
766
+ ['Craig','Pollack','(310) 987-6543']
767
+ ]
768
+ ..........................................
769
+
770
+ SERIALIZE
771
+ .........................
772
+ Uize.Data.Csv.to (input);
773
+ .........................
774
+
775
+ OUTPUT
776
+ ..............................
777
+ John,Wilkey,(650) 123-4567
778
+ Marie,Stevenson,(415) 456-7890
779
+ Craig,Pollack,(310) 987-6543
780
+ ..............................
781
+
782
+ There is nothing particulatly challenging about the source records array - none of the values have special characters that would cause them to need quoting. To serialize to strict CSV format, we don't need to specify any encoding options in the optional =encodingOptionsOBJ= parameter. Sometimes life is just too easy.
783
+
784
+ Default Encoding Options, Values Needing Quotes
785
+ In this example, we're serializing data to a CSV data string in strict accordance with the rules laid out in RFC 4180, but some of the column values contain special characters that require them to be quoted.
786
+
787
+ INPUT
788
+ .......................................................
789
+ [
790
+ ['John "Willy"','Wilkey','(650) 123-4567'],
791
+ ['Marie','Stevenson','(415) 456-7890, Ext. 214'],
792
+ ['Craig','Pollack','(310) 987-6543\n(650) 303-1000']
793
+ ]
794
+ .......................................................
795
+
796
+ SERIALIZE
797
+ .........................
798
+ Uize.Data.Csv.to (input);
799
+ .........................
800
+
801
+ OUTPUT
802
+ ..........................................
803
+ "John ""Willy""",Wilkey,(650) 123-4567
804
+ Marie,Stevenson,"(415) 456-7890, Ext. 214"
805
+ Craig,Pollack,"(310) 987-6543
806
+ (650) 303-1000"
807
+ ..........................................
808
+
809
+ Comparing the source records array to the serialized CSV data string, you'll notice a few things...
810
+
811
+ - The value ='John "Willy"'= had to be quoted as ="John ""Willy"""=, because it contains the double quote quoting character. Therefore, the serialized value has double quotes around it, and the double quotes in the value are escaped by doubling them up (ie. two double quotes for each double quote being escaped).
812
+ - The value ='(415) 456-7890, Ext. 214'= had to be quoted because it contains the comma value delimiter character.
813
+ - The value ='(650) 123-4567\n(650) 303-1000'= had to be quoted because it contains a linebreak and spans two lines.
814
+
815
+ None of the above factors are a problem for the =Uize.Data.Csv.to= method, since all these behaviors comply with the rules of RFC 4180, and no special encoding options needed to be specified.
816
+
817
+ Default Encoding Options, Values With Padding
818
+ In this example, we're serializing data to a CSV data string in strict accordance with the rules laid out in RFC 4180, where some of the column values contain whitespace padding.
819
+
820
+ INPUT
821
+ ............................................
822
+ [
823
+ ['John',' Wilkey ','(650) 123-4567'],
824
+ ['Marie',' Stevenson ','(415) 456-7890'],
825
+ ['Craig',' Pollack ','(310) 987-6543']
826
+ ]
827
+ ............................................
828
+
829
+ SERIALIZE
830
+ .........................
831
+ Uize.Data.Csv.to (input);
832
+ .........................
833
+
834
+ OUTPUT
835
+ ................................
836
+ John, Wilkey ,(650) 123-4567
837
+ Marie, Stevenson ,(415) 456-7890
838
+ Craig, Pollack ,(310) 987-6543
839
+ ................................
840
+
841
+ Because we're serializing to strict CSV format, none of the values that contain padding need to be quoted. This is because whitespace around the value separator is considered significant according to RFC 4180 and should not be stripped. Therefore, no special encoding options need to be specified when calling the =Uize.Data.Csv.to= method in this case.
842
+
843
+ Values With Padding, Trim Padding On Parse
844
+ In this example, we're serializing an array of arrays to a CSV data string, some of the values contain whitespace padding, and we know that the serialized CSV data string may at some point be parsed by code that trims padding around values.
845
+
846
+ In order to protect against the padding in our values being stripped out later, we let the =Uize.Data.Csv.to= method know that padding will be trimmed, by some parser in the future, by specifying the value =true= for the =trimPaddingOnParse= option. This results in the =Uize.Data.Csv.to= method quoting those values that contain padding.
847
+
848
+ INPUT
849
+ ............................................
850
+ [
851
+ ['John',' Wilkey ','(650) 123-4567'],
852
+ ['Marie',' Stevenson ','(415) 456-7890'],
853
+ ['Craig',' Pollack ','(310) 987-6543']
854
+ ]
855
+ ............................................
856
+
857
+ SERIALIZE
858
+ ...................................................
859
+ Uize.Data.Csv.to (input,{trimPaddingOnParse:true});
860
+ ...................................................
861
+
862
+ OUTPUT
863
+ ..................................
864
+ John," Wilkey ",(650) 123-4567
865
+ Marie," Stevenson ",(415) 456-7890
866
+ Craig," Pollack ",(310) 987-6543
867
+ ..................................
868
+
869
+ With Header Row, Column Names Explicitly Specified
870
+ In this example, we're serializing an array of arrays to a CSV data string that has a header row, so we're supplying the column names explicitly.
871
+
872
+ To make sure that the serialized CSV data string has a header row, we specify the value =true= for the =hasHeader= option. Problem is, the records array does not contain the column names. This is normal, since the column names really aren't part of the data set. To remedy this, we explicitly provide the =Uize.Data.Csv.to= method with the column names using the =columns= option.
873
+
874
+ INPUT
875
+ ..........................................
876
+ [
877
+ ['John','Wilkey','(650) 123-4567'],
878
+ ['Marie','Stevenson','(415) 456-7890'],
879
+ ['Craig','Pollack','(310) 987-6543']
880
+ ]
881
+ ..........................................
882
+
883
+ SERIALIZE
884
+ ..............................................
885
+ Uize.Data.Csv.to (
886
+ input,
887
+ {
888
+ hasHeader:true,
889
+ columns:['firstName','lastName','phone']
890
+ }
891
+ );
892
+ ..............................................
893
+
894
+ OUTPUT
895
+ ..............................
896
+ firstName,lastName,phone
897
+ John,Wilkey,(650) 123-4567
898
+ Marie,Stevenson,(415) 456-7890
899
+ Craig,Pollack,(310) 987-6543
900
+ ..............................
901
+
902
+ With Header Row, Rows Are Objects, Column Names From Object Keys
903
+ In this example, we're serializing an array of objects to a CSV data string that has a header row, where the keys of the first record object are used as the column names.
904
+
905
+ As you'll notice from the records array, the first record has the object keys defined in a different order to the other records. The =phone= key is first, followed by =lastName= and =firstName=. Because we're not explicitly specifying a column order, the columns' names and their ordering is all determined by the first record. If you're parsing the serialized CSV data string back to an array of objects later, then this shouldn't matter. If you care about the order, then refer to the example `With Header Row, Rows Are Objects, Column Order Specified`. To get the header row in the serialized CSV data string, we're specifying the value =true= for the =hasHeader= option.
906
+
907
+ INPUT
908
+ ...................................................................
909
+ [
910
+ {phone:'(650) 123-4567',lastName:'Wilkey',firstName:'John'},
911
+ {firstName:'Marie',lastName:'Stevenson',phone:'(415) 456-7890'},
912
+ {firstName:'Craig',lastName:'Pollack',phone:'(310) 987-6543'}
913
+ ]
914
+ ...................................................................
915
+
916
+ SERIALIZE
917
+ ..........................................
918
+ Uize.Data.Csv.to (input,{hasHeader:true});
919
+ ..........................................
920
+
921
+ OUTPUT
922
+ ..............................
923
+ phone,lastName,firstName
924
+ (650) 123-4567,Wilkey,John
925
+ (415) 456-7890,Stevenson,Marie
926
+ (310) 987-6543,Pollack,Craig
927
+ ..............................
928
+
929
+ With Header Row, Rows Are Objects, Column Order Specified
930
+ In this example, we're serializing an array of objects to a CSV data string that has a header row, and we're explicitly specifying the column order using the =columns= option.
931
+
932
+ Unlike the example `With Header Row, Rows Are Objects, Column Names From Object Keys`, here we actually care about the order of the columns in the serialized CSV data string. Therefore, we are using the =columns= option to control the ordering. If we didn't do this, the ordering would be determined by the order of the keys in the first record object.
933
+
934
+ To get the header row in the serialized CSV data string, we're specifying the value =true= for the =hasHeader= option. You could argue that controlling the column ordering would be even more important if the serialized CSV data string were to *not* contain a header row and was expected to be parsed at some later stage to an array of arrays, where there was an expected column ordering.
935
+
936
+ INPUT
937
+ ...................................................................
938
+ [
939
+ {phone:'(650) 123-4567',lastName:'Wilkey',firstName:'John'},
940
+ {firstName:'Marie',lastName:'Stevenson',phone:'(415) 456-7890'},
941
+ {firstName:'Craig',lastName:'Pollack',phone:'(310) 987-6543'}
942
+ ]
943
+ ...................................................................
944
+
945
+ SERIALIZE
946
+ ..............................................
947
+ Uize.Data.Csv.to (
948
+ input,
949
+ {
950
+ hasHeader:true,
951
+ columns:['firstName','lastName','phone']
952
+ }
953
+ );
954
+ ..............................................
955
+
956
+ OUTPUT
957
+ ..............................
958
+ firstName,lastName,phone
959
+ John,Wilkey,(650) 123-4567
960
+ Marie,Stevenson,(415) 456-7890
961
+ Craig,Pollack,(310) 987-6543
962
+ ..............................
963
+
964
+ With Header Row, Rows Are Objects, Subset of Columns
965
+ In this example, we're serializing an array of objects to a CSV data string that has a header row, and we're specifying a subset of the columns in the data set to be serialized.
966
+
967
+ Not only does the =columns= option let us control the ordering of columns in the serialized CSV data string (see the example `With Header Row, Rows Are Objects, Column Order Specified`), it also lets us specify just a subset of columns to serialize. In this example we're serializing just the =firstName= and =lastName= columns. To get the header row in the serialized CSV data string, we're specifying the value =true= for the =hasHeader= option.
968
+
969
+ INPUT
970
+ ...................................................................
971
+ [
972
+ {phone:'(650) 123-4567',lastName:'Wilkey',firstName:'John'},
973
+ {firstName:'Marie',lastName:'Stevenson',phone:'(415) 456-7890'},
974
+ {firstName:'Craig',lastName:'Pollack',phone:'(310) 987-6543'}
975
+ ]
976
+ ...................................................................
977
+
978
+ SERIALIZE
979
+ ......................................
980
+ Uize.Data.Csv.to (
981
+ input,
982
+ {
983
+ hasHeader:true,
984
+ columns:['firstName','lastName']
985
+ }
986
+ );
987
+ ......................................
988
+
989
+ OUTPUT
990
+ ..................
991
+ firstName,lastName
992
+ John,Wilkey
993
+ Marie,Stevenson
994
+ Craig,Pollack
995
+ ..................
996
+
997
+ With Header Row, Columns Are Indices
998
+ In this example, we're serializing an array of arrays to a CSV data string that has a header row, and since we're not explicitly specifying the column names using the =columns= option, the column indices are used instead.
999
+
1000
+ To get the header row in the serialized CSV data string, we're specifying the value =true= for the =hasHeader= option. To have the array indices be used for the column names, we simply don't specify a value for the =columns= option. The default value of ='all'= when the row type is array causes the column indices to be used as the column names. This may be an unusual and atypical case, but it illustrates the behavior when this combination of options is used.
1001
+
1002
+ INPUT
1003
+ ..........................................
1004
+ [
1005
+ ['John','Wilkey','(650) 123-4567'],
1006
+ ['Marie','Stevenson','(415) 456-7890'],
1007
+ ['Craig','Pollack','(310) 987-6543']
1008
+ ]
1009
+ ..........................................
1010
+
1011
+ SERIALIZE
1012
+ ..........................................
1013
+ Uize.Data.Csv.to (input,{hasHeader:true});
1014
+ ..........................................
1015
+
1016
+ OUTPUT
1017
+ ..............................
1018
+ 0,1,2
1019
+ John,Wilkey,(650) 123-4567
1020
+ Marie,Stevenson,(415) 456-7890
1021
+ Craig,Pollack,(310) 987-6543
1022
+ ..............................
1023
+
1024
+ Always Quote Values
1025
+ In this example, we're serializing an array of arrays to a CSV data string and forcing all values to be quoted by specifying the value ='always'= for the =whenToQuoteValues= option.
1026
+
1027
+ If we didn't specify a value for the =whenToQuoteValues= option in this example, then none of the values would be quoted. That's because none of the values contain special characters that would require them to be quoted. If it is anticipated that the CSV data string may be parsed by an inferior or non-RFC 4180 compliant parser that requires all values to be quoted, then we can used this facility. Alternatively, if the data set would likely cause a mix of quoting and not quoting, and we have an aesthetic preference for a consistent look / treatment, then we can force all values to be quoted using this option.
1028
+
1029
+ INPUT
1030
+ ..........................................
1031
+ [
1032
+ ['John','Wilkey','(650) 123-4567'],
1033
+ ['Marie','Stevenson','(415) 456-7890'],
1034
+ ['Craig','Pollack','(310) 987-6543']
1035
+ ]
1036
+ ..........................................
1037
+
1038
+ SERIALIZE
1039
+ ......................................................
1040
+ Uize.Data.Csv.to (input,{whenToQuoteValues:'always'});
1041
+ ......................................................
1042
+
1043
+ OUTPUT
1044
+ ....................................
1045
+ "John","Wilkey","(650) 123-4567"
1046
+ "Marie","Stevenson","(415) 456-7890"
1047
+ "Craig","Pollack","(310) 987-6543"
1048
+ ....................................
1049
+
1050
+ Always Quote Values, Using Single Quotes
1051
+ In this example, we're serializing an array of arrays to a CSV data string and forcing all values to be quoted using a single quote character.
1052
+
1053
+ We force all values to be quoted by specifying the value ='always'= for the =whenToQuoteValues= option, and we force single quotes to be used by specifying the value ='/''= for the =quoteChar= option. It is important, when serializing data using encoding options that don't conform to RFC 4180, that you specify the same options upon decoding data serialized in this way using the =Uize.Data.Csv.from= method. Compare this example to the example `Always Quote Values`, where all values are quoted, but using the RFC 4180 compliant double quote character.
1054
+
1055
+ INPUT
1056
+ ..........................................
1057
+ [
1058
+ ['John','Wilkey','(650) 123-4567'],
1059
+ ['Marie','Stevenson','(415) 456-7890'],
1060
+ ['Craig','Pollack','(310) 987-6543']
1061
+ ]
1062
+ ..........................................
1063
+
1064
+ SERIALIZE
1065
+ .....................................................................
1066
+ Uize.Data.Csv.to (input,{whenToQuoteValues:'always',quoteChar:'\''});
1067
+ .....................................................................
1068
+
1069
+ OUTPUT
1070
+ ....................................
1071
+ 'John','Wilkey','(650) 123-4567'
1072
+ 'Marie','Stevenson','(415) 456-7890'
1073
+ 'Craig','Pollack','(310) 987-6543'
1074
+ ....................................
1075
+
1076
+ Use Pipe As a Value Delimiter
1077
+ In this example, we're serializing an array of arrays to a CSV data string, using a non-standard "|" (pipe) character as a value delimiter.
1078
+
1079
+ This is an unusual case, but not quite as unusual as the example `Space As Value Delimiter, Quote Values Using Hash`. The =Uize.Data.Csv.to= method provides the flexibility to do some unusual things. It is important, when serializing data using encoding options that don't conform to RFC 4180, that you specify the same options upon decoding data serialized in this way using the =Uize.Data.Csv.from= method.
1080
+
1081
+ INPUT
1082
+ ..........................................
1083
+ [
1084
+ ['John','Wilkey','(650) 123-4567'],
1085
+ ['Marie','Stevenson','(415) 456-7890'],
1086
+ ['Craig','Pollack','(310) 987-6543']
1087
+ ]
1088
+ ..........................................
1089
+
1090
+ SERIALIZE
1091
+ ..............................................
1092
+ Uize.Data.Csv.to (input,{valueDelimiter:'|'});
1093
+ ..............................................
1094
+
1095
+ OUTPUT
1096
+ ..............................
1097
+ John|Wilkey|(650) 123-4567
1098
+ Marie|Stevenson|(415) 456-7890
1099
+ Craig|Pollack|(310) 987-6543
1100
+ ..............................
1101
+
1102
+ Space As Value Delimiter, Quote Values Using Hash
1103
+ In this example, a space is being used as a value delimiter and a "#" (pound / hash) character is being used as a quoting character.
1104
+
1105
+ This is a rather unusual case, and who's to say why this choice of options would be made. This example demonstrates, however, that the =Uize.Data.Csv.to= method provides the flexibility to do some unusual things. It is important, when serializing data using encoding options that don't conform to RFC 4180, that you specify the same options upon decoding data serialized in this way using the =Uize.Data.Csv.from= method.
1106
+
1107
+ INPUT
1108
+ ..........................................
1109
+ [
1110
+ ['John','Wilkey','(650) 123-4567'],
1111
+ ['Marie','Stevenson','(415) 456-7890'],
1112
+ ['Craig','Pollack','(310) 987-6543']
1113
+ ]
1114
+ ..........................................
1115
+
1116
+ SERIALIZE
1117
+ ............................................................
1118
+ Uize.Data.Csv.to (input,{quoteChar:'#',valueDelimiter:' '});
1119
+ ............................................................
1120
+
1121
+ OUTPUT
1122
+ ....................................
1123
+ #John# #Wilkey# #(650) 123-4567#
1124
+ #Marie# #Stevenson# #(415) 456-7890#
1125
+ #Craig# #Pollack# #(310) 987-6543#
1126
+ ....................................
1127
+
1128
+ Value Delimiter Contains Whitespace
1129
+ In this example, the value delimiter being specified in the =valueDelimiter= option is a comma with a trailing space.
1130
+
1131
+ This makes for a prettier CSV data string. We're not specifying a value for the =trimPaddingOnParse= option here, so it gets its default value of =false=. This means that the spaces introduced by the value delimiter could find their way into the column values when the CSV data string is parsed at a later stage. Therefore, the =Uize.Data.Csv.to= automatically quotes all the column values (as you'll see from the output) so that it is clear what's really inside the values and what's outside the values.
1132
+
1133
+ INPUT
1134
+ ..........................................
1135
+ [
1136
+ ['John','Wilkey','(650) 123-4567'],
1137
+ ['Marie','Stevenson','(415) 456-7890'],
1138
+ ['Craig','Pollack','(310) 987-6543']
1139
+ ]
1140
+ ..........................................
1141
+
1142
+ SERIALIZE
1143
+ ...............................................
1144
+ Uize.Data.Csv.to (input,{valueDelimiter:', '});
1145
+ ...............................................
1146
+
1147
+ OUTPUT
1148
+ ......................................
1149
+ "John", "Wilkey", "(650) 123-4567"
1150
+ "Marie", "Stevenson", "(415) 456-7890"
1151
+ "Craig", "Pollack", "(310) 987-6543"
1152
+ ......................................
1153
+
1154
+ Value Delimiter Contains Whitespace, Trim Padding on Parse
1155
+ In this example, the value delimiter being specified in the =valueDelimiter= option is a comma with a trailing space.
1156
+
1157
+ This makes for a prettier CSV data string. We don't mind that there appears to be an extra leading space before the second and third column values, because we know that the code that will parse this CSV data string later will trim whitespace padding around values, and we specify that fact using the =trimPaddingOnParse= option.
1158
+
1159
+ INPUT
1160
+ ..........................................
1161
+ [
1162
+ ['John','Wilkey','(650) 123-4567'],
1163
+ ['Marie','Stevenson','(415) 456-7890'],
1164
+ ['Craig',' Pollack ','(310) 987-6543']
1165
+ ]
1166
+ ..........................................
1167
+
1168
+ SERIALIZE
1169
+ .......................................................................
1170
+ Uize.Data.Csv.to (input,{valueDelimiter:', ',trimPaddingOnParse:true});
1171
+ .......................................................................
1172
+
1173
+ OUTPUT
1174
+ ..................................
1175
+ John, Wilkey, (650) 123-4567
1176
+ Marie, Stevenson, (415) 456-7890
1177
+ Craig, " Pollack ", (310) 987-6543
1178
+ ..................................
1179
+
1180
+ Notice in the output how the value =' Pollack '= is quoted, while all the other values aren't. This is because the value itself contains padding, and the =true= value for =trimPaddingOnParse= indicates that values containing padding should be quoted or there padding might be trimmed away in error during parsing at a later stage.
1181
+
1182
+ NOTES
1183
+ - see the companion =Uize.Data.Csv.from= static method
1184
+ */
1185
+ };
1186
+
1187
+ return _package;
1188
+ }
1189
+ });
1190
+
skin/frontend/default/customproduct/js/Uize.Data.Matches.js ADDED
@@ -0,0 +1,527 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ /*______________
2
+ | ______ | U I Z E J A V A S C R I P T F R A M E W O R K
3
+ | / / | ---------------------------------------------------
4
+ | / O / | MODULE : Uize.Data.Matches Package
5
+ | / / / |
6
+ | / / / /| | ONLINE : http://www.uize.com
7
+ | /____/ /__/_| | COPYRIGHT : (c)2012 UIZE
8
+ | /___ | LICENSE : Available under MIT License or GNU General Public License
9
+ |_______________| http://www.uize.com/license.html
10
+ */
11
+
12
+ /* Module Meta Data
13
+ type: Package
14
+ importance: 2
15
+ codeCompleteness: 100
16
+ testCompleteness: 100
17
+ docCompleteness: 5
18
+ */
19
+
20
+ /*?
21
+ Introduction
22
+ The =Uize.Data.Matches= module provides methods for finding matching elements in arrays or matching properties in objects.
23
+
24
+ *DEVELOPERS:* `Chris van Rensburg`
25
+
26
+ In a Nutshell
27
+ The =Uize.Data.Matches= module provides methods for performing the following types of matching operations...
28
+
29
+ - `iterating over matches`
30
+ - `removing or retaining matches`
31
+ - `counting matches`
32
+ - `getting the keys or values for all matches`
33
+ - `getting the key or value of the first match`
34
+
35
+ Iterating Over Matches
36
+ To make it easy to iterate over matches in a source array, object, or range, the =Uize.Data.Matches= module provides the =Uize.Data.Matches.forEach= static method.
37
+
38
+ The =Uize.Data.Matches.forEach= method can be used to `iterate over matching elements of an array`, `iterate over matching properties of an object`, or `iterate over matching values of a range`. In its most basic usage, the =Uize.Data.Matches.forEach= method lets you specify a source, a matcher, and an iterator.
39
+
40
+ TYPICAL USAGE
41
+ ..............................................................................................
42
+ Uize.Data.Matches.forEach (sourceARRAYorOBJorINT,matcherFUNCorSTRorREGEXPorBOOL,iteratorFUNC);
43
+ ..............................................................................................
44
+
45
+ EXAMPLE
46
+ ...
47
+ Uize.Data.Matches.forEach (
48
+ );
49
+ ...
50
+
51
+ The =Uize.Data.Matches.forEach= method is versatile and supports a number of different usages. For more in-depth info, consult the method's [[Uize.Data.Matches.forEach][reference documentation]].
52
+
53
+ Removing or Retaining Matches
54
+ The =Uize.Data.Matches= module offers methods for processing an array, object, or range, and either removing or retaining matches.
55
+
56
+ The =Uize.Data.Matches.remove= method can be used to remove matches, while the =Uize.Data.Matches.retain= method can be used to retain matches.
57
+
58
+ Both of these methods support...
59
+
60
+ - processing a source array, object, or range (see `Specifying a Source`)
61
+ - finding matches by value and/or key/index (see `Specifying a Matcher`)
62
+ - removing or retaining a maximum number of matches (see `Limiting the Number of Matches`)
63
+ - modifying the original source or outputting the result to a newly created or specified target (see `Specifying a Target`)
64
+
65
+ Removing Matches
66
+ Matches can be removed from an array, object, or number range, using the =Uize.Data.Matches.remove= method.
67
+
68
+ TYPICAL USAGE
69
+ .............................................................................................
70
+ var result = Uize.Data.Matches.remove (sourceARRAYorOBJorINT,matcherFUNCorSTRorREGEXPorBOOL);
71
+ .............................................................................................
72
+
73
+ EXAMPLE
74
+ ..............................................................................
75
+ var sparseArray = [];
76
+ sparseArray [1] = 'orange';
77
+ sparseArray [5] = 'peach';
78
+ sparseArray [8] = 'apple';
79
+ sparseArray [11] = 'pear';
80
+
81
+ var denseArray = Uize.Data.Matches.remove (sparseArray,'value === undefined'};
82
+ alert (denseArray.join ('|')); // alerts the text "orange|peach|apple|pear"
83
+ ..............................................................................
84
+
85
+ In the above example, the sparsely populated array named =sparseArray= is being created and populated with four elements. There are gaps between the assigned elements of =sparseArray=, and the elements in these gaps will all have the value =undefined=. The =Uize.Data.Matches.remove= method is being used to produce a densely populated array from the =sparseArray= by removing every element whose value is =undefined=. You'll notice that we're `matching items using a value matcher regular expression` rather than a function. This is nice and concise.
86
+
87
+ The =Uize.Data.Matches.remove= method is versatile and supports a number of different usages. For more in-depth info, consult the method's [[Uize.Data.Matches.remove][reference documentation]].
88
+
89
+ Retaining Matches
90
+ document...
91
+
92
+ EXAMPLE
93
+ ...
94
+ ...
95
+
96
+ Counting Matches
97
+ document...
98
+
99
+ EXAMPLE
100
+ ...
101
+ ...
102
+
103
+ Getting the Keys or Values of All Matches
104
+ documnt...
105
+
106
+ EXAMPLE
107
+ ...
108
+ ...
109
+
110
+ Getting the Key or Value of the First Match
111
+ document...
112
+
113
+ EXAMPLE
114
+ ...
115
+ ...
116
+
117
+ Specifying a Source
118
+ document...
119
+
120
+ Specifying an Array Source
121
+ document...
122
+
123
+ Specifying an Object Source
124
+ document...
125
+
126
+ Specifying a Range Source
127
+ document...
128
+
129
+ Specifying a Matcher
130
+ document...
131
+
132
+ Matching Items Using a Matcher Function
133
+ document...
134
+
135
+ Matching Items Using a Matcher Expression String
136
+ document...
137
+
138
+ Matching Items Using a Value Matcher Regular Expression
139
+ document...
140
+
141
+ Matching All Items
142
+ document...
143
+
144
+ Matching No Items
145
+ document...
146
+
147
+ Matching by Value
148
+ document...
149
+
150
+ Matching by Key / Index
151
+ document...
152
+
153
+ Matching by Key and Value
154
+ document...
155
+
156
+ Limiting the Number of Matches
157
+ document...
158
+
159
+ Specifying a Target
160
+ document...
161
+ */
162
+
163
+ Uize.module ({
164
+ name:'Uize.Data.Matches',
165
+ builder:function () {
166
+ /*** Variables for Scruncher Optimization ***/
167
+ var
168
+ _package = function () {},
169
+ _true = true,
170
+ _false = false,
171
+ _undefined,
172
+ _Uize = Uize,
173
+ _resolveMatcher = _Uize.resolveMatcher
174
+ ;
175
+
176
+ /*** Public Static Methods ***/
177
+ _package.forEach = function (_source,_matcher,_iterator,_maxMatches) {
178
+ if (_maxMatches == _undefined)
179
+ _maxMatches = Infinity
180
+ ;
181
+ if (_maxMatches > 0) {
182
+ _matcher = _resolveMatcher (_matcher);
183
+ var _totalMatches = 0;
184
+ _Uize.forEach (
185
+ _source,
186
+ function (_value,_key) {
187
+ if (_totalMatches < _maxMatches && _matcher (_value,_key)) {
188
+ _totalMatches++;
189
+ _iterator (_value,_key);
190
+ }
191
+ },
192
+ 0,
193
+ _true
194
+ );
195
+ }
196
+ /*?
197
+ Static Methods
198
+ Uize.Data.Matches.forEach
199
+ Iterates over elements in the specified source array, or properties in the specified source object, or values in the specified source range, that match the specified matching criteria.
200
+
201
+ DIFFERENT USAGES
202
+
203
+ `Iterate Over Matching Elements of an Array`
204
+ ....................................................................................
205
+ Uize.Data.Matches.forEach (sourceARRAY,matcherFUNCorSTRorREGEXPorBOOL,iteratorFUNC);
206
+ ....................................................................................
207
+
208
+ `Iterate Over Matching Properties of an Object`
209
+ ..................................................................................
210
+ Uize.Data.Matches.forEach (sourceOBJ,matcherFUNCorSTRorREGEXPorBO