mechanize_store 0.0.3

Sign up to get free protection for your applications and to get access to all the features.
Files changed (383) hide show
  1. checksums.yaml +15 -0
  2. data/MIT-LICENSE +20 -0
  3. data/README.rdoc +60 -0
  4. data/Rakefile +28 -0
  5. data/app/assets/javascripts/mechanize_store/application.js +22 -0
  6. data/app/assets/javascripts/mechanize_store/sb-admin/bootstrap.js +1951 -0
  7. data/app/assets/javascripts/mechanize_store/sb-admin/custom.js +58 -0
  8. data/app/assets/javascripts/mechanize_store/sb-admin/flot/excanvas.min.js +1 -0
  9. data/app/assets/javascripts/mechanize_store/sb-admin/flot/jquery.flot.js +3137 -0
  10. data/app/assets/javascripts/mechanize_store/sb-admin/flot/jquery.flot.pie.js +817 -0
  11. data/app/assets/javascripts/mechanize_store/sb-admin/flot/main.js +20 -0
  12. data/app/assets/javascripts/mechanize_store/sb-admin/jquery-file-upload/canvas-to-blob.min.js +1 -0
  13. data/app/assets/javascripts/mechanize_store/sb-admin/jquery-file-upload/jquery.blueimp-gallery.min.js +1 -0
  14. data/app/assets/javascripts/mechanize_store/sb-admin/jquery-file-upload/jquery.fileupload-angular.js +429 -0
  15. data/app/assets/javascripts/mechanize_store/sb-admin/jquery-file-upload/jquery.fileupload-audio.js +106 -0
  16. data/app/assets/javascripts/mechanize_store/sb-admin/jquery-file-upload/jquery.fileupload-image.js +309 -0
  17. data/app/assets/javascripts/mechanize_store/sb-admin/jquery-file-upload/jquery.fileupload-jquery-ui.js +152 -0
  18. data/app/assets/javascripts/mechanize_store/sb-admin/jquery-file-upload/jquery.fileupload-process.js +172 -0
  19. data/app/assets/javascripts/mechanize_store/sb-admin/jquery-file-upload/jquery.fileupload-ui.js +699 -0
  20. data/app/assets/javascripts/mechanize_store/sb-admin/jquery-file-upload/jquery.fileupload-validate.js +119 -0
  21. data/app/assets/javascripts/mechanize_store/sb-admin/jquery-file-upload/jquery.fileupload-video.js +106 -0
  22. data/app/assets/javascripts/mechanize_store/sb-admin/jquery-file-upload/jquery.fileupload.js +1426 -0
  23. data/app/assets/javascripts/mechanize_store/sb-admin/jquery-file-upload/jquery.iframe-transport.js +214 -0
  24. data/app/assets/javascripts/mechanize_store/sb-admin/jquery-file-upload/jquery.ui.widget.js +530 -0
  25. data/app/assets/javascripts/mechanize_store/sb-admin/jquery-file-upload/load-image.min.js +1 -0
  26. data/app/assets/javascripts/mechanize_store/sb-admin/jquery-file-upload/main.js +14 -0
  27. data/app/assets/javascripts/mechanize_store/sb-admin/jquery-file-upload/tmpl.min.js +1 -0
  28. data/app/assets/javascripts/mechanize_store/sb-admin/jquery-ui.js +2256 -0
  29. data/app/assets/javascripts/mechanize_store/sb-admin/jquery.activity-indicator-1.0.0.min.js +223 -0
  30. data/app/assets/javascripts/mechanize_store/sb-admin/plugins/dataTables/dataTables.bootstrap.js +245 -0
  31. data/app/assets/javascripts/mechanize_store/sb-admin/plugins/dataTables/jquery.dataTables.js +14013 -0
  32. data/app/assets/javascripts/mechanize_store/sb-admin/plugins/flot/excanvas.min.js +1 -0
  33. data/app/assets/javascripts/mechanize_store/sb-admin/plugins/flot/jquery.flot.js +2599 -0
  34. data/app/assets/javascripts/mechanize_store/sb-admin/plugins/flot/jquery.flot.pie.js +750 -0
  35. data/app/assets/javascripts/mechanize_store/sb-admin/plugins/flot/jquery.flot.resize.js +60 -0
  36. data/app/assets/javascripts/mechanize_store/sb-admin/plugins/flot/jquery.flot.tooltip.min.js +12 -0
  37. data/app/assets/javascripts/mechanize_store/sb-admin/plugins/metisMenu/jquery.metisMenu.js +45 -0
  38. data/app/assets/javascripts/mechanize_store/sb-admin/plugins/morris/morris.js +1888 -0
  39. data/app/assets/javascripts/mechanize_store/sb-admin/plugins/morris/raphael-2.1.0.min.js +10 -0
  40. data/app/assets/javascripts/mechanize_store/sb-admin/sb-admin.js +18 -0
  41. data/app/assets/stylesheets/mechanize_store/application.css +197 -0
  42. data/app/assets/stylesheets/mechanize_store/sb-admin/bootstrap.css +5831 -0
  43. data/app/assets/stylesheets/mechanize_store/sb-admin/plugins/dataTables/dataTables.bootstrap.css +233 -0
  44. data/app/assets/stylesheets/mechanize_store/sb-admin/plugins/morris/morris-0.4.3.min.css +2 -0
  45. data/app/assets/stylesheets/mechanize_store/sb-admin/plugins/social-buttons/social-buttons.css +68 -0
  46. data/app/assets/stylesheets/mechanize_store/sb-admin/plugins/timeline/timeline.css +144 -0
  47. data/app/assets/stylesheets/mechanize_store/sb-admin/sb-admin.css +307 -0
  48. data/app/controllers/mechanize_store/application_controller.rb +4 -0
  49. data/app/controllers/mechanize_store/flags_controller.rb +77 -0
  50. data/app/controllers/mechanize_store/order_statuses_controller.rb +77 -0
  51. data/app/controllers/mechanize_store/orders_controller.rb +28 -0
  52. data/app/controllers/mechanize_store/payment_statuses_controller.rb +77 -0
  53. data/app/controllers/mechanize_store/payment_types_controller.rb +77 -0
  54. data/app/controllers/mechanize_store/product_categories_controller.rb +77 -0
  55. data/app/controllers/mechanize_store/product_photos_controller.rb +49 -0
  56. data/app/controllers/mechanize_store/products_controller.rb +77 -0
  57. data/app/helpers/mechanize_store/application_helper.rb +7 -0
  58. data/app/models/mechanize_store/flag.rb +4 -0
  59. data/app/models/mechanize_store/freight.rb +5 -0
  60. data/app/models/mechanize_store/order.rb +47 -0
  61. data/app/models/mechanize_store/order_item.rb +10 -0
  62. data/app/models/mechanize_store/order_status.rb +10 -0
  63. data/app/models/mechanize_store/payment.rb +8 -0
  64. data/app/models/mechanize_store/payment_status.rb +19 -0
  65. data/app/models/mechanize_store/payment_type.rb +5 -0
  66. data/app/models/mechanize_store/product.rb +11 -0
  67. data/app/models/mechanize_store/product_category.rb +5 -0
  68. data/app/models/mechanize_store/product_photo.rb +16 -0
  69. data/app/views/mechanize_store/flags/_form.html.erb +11 -0
  70. data/app/views/mechanize_store/flags/edit.html.erb +12 -0
  71. data/app/views/mechanize_store/flags/index.html.erb +46 -0
  72. data/app/views/mechanize_store/flags/new.html.erb +9 -0
  73. data/app/views/mechanize_store/flags/show.html.erb +15 -0
  74. data/app/views/mechanize_store/order_statuses/_form.html.erb +11 -0
  75. data/app/views/mechanize_store/order_statuses/edit.html.erb +12 -0
  76. data/app/views/mechanize_store/order_statuses/index.html.erb +46 -0
  77. data/app/views/mechanize_store/order_statuses/new.html.erb +9 -0
  78. data/app/views/mechanize_store/order_statuses/show.html.erb +15 -0
  79. data/app/views/mechanize_store/orders/index.html.erb +84 -0
  80. data/app/views/mechanize_store/orders/show.html.erb +0 -0
  81. data/app/views/mechanize_store/payment_statuses/_form.html.erb +11 -0
  82. data/app/views/mechanize_store/payment_statuses/edit.html.erb +12 -0
  83. data/app/views/mechanize_store/payment_statuses/index.html.erb +46 -0
  84. data/app/views/mechanize_store/payment_statuses/new.html.erb +9 -0
  85. data/app/views/mechanize_store/payment_statuses/show.html.erb +15 -0
  86. data/app/views/mechanize_store/payment_types/_form.html.erb +11 -0
  87. data/app/views/mechanize_store/payment_types/edit.html.erb +12 -0
  88. data/app/views/mechanize_store/payment_types/index.html.erb +46 -0
  89. data/app/views/mechanize_store/payment_types/new.html.erb +9 -0
  90. data/app/views/mechanize_store/payment_types/show.html.erb +15 -0
  91. data/app/views/mechanize_store/product_categories/_form.html.erb +12 -0
  92. data/app/views/mechanize_store/product_categories/edit.html.erb +12 -0
  93. data/app/views/mechanize_store/product_categories/index.html.erb +46 -0
  94. data/app/views/mechanize_store/product_categories/new.html.erb +9 -0
  95. data/app/views/mechanize_store/product_categories/show.html.erb +19 -0
  96. data/app/views/mechanize_store/product_photos/create.json.jbuilder +9 -0
  97. data/app/views/mechanize_store/product_photos/index.json.jbuilder +9 -0
  98. data/app/views/mechanize_store/products/_form.html.erb +18 -0
  99. data/app/views/mechanize_store/products/edit.html.erb +12 -0
  100. data/app/views/mechanize_store/products/index.html.erb +50 -0
  101. data/app/views/mechanize_store/products/new.html.erb +9 -0
  102. data/app/views/mechanize_store/products/show.html.erb +197 -0
  103. data/app/views/shared/_flashes.html.erb +8 -0
  104. data/config/locales/mechanize_store.pt-BR.yml +65 -0
  105. data/config/routes.rb +11 -0
  106. data/db/migrate/20140401203200_create_mechanize_store_freights.rb +12 -0
  107. data/db/migrate/20140401203246_create_mechanize_store_order_statuses.rb +9 -0
  108. data/db/migrate/20140402140318_create_mechanize_store_payment_statuses.rb +9 -0
  109. data/db/migrate/20140402140325_create_mechanize_store_payment_types.rb +9 -0
  110. data/db/migrate/20140402140539_create_mechanize_store_payments.rb +15 -0
  111. data/db/migrate/20140402140549_create_mechanize_store_flags.rb +9 -0
  112. data/db/migrate/20140402140832_create_mechanize_store_products.rb +16 -0
  113. data/db/migrate/20140402140942_create_mechanize_store_product_photos.rb +10 -0
  114. data/db/migrate/20140402153139_create_mechanize_store_orders.rb +11 -0
  115. data/db/migrate/20140402192058_create_mechanize_store_product_categories.rb +10 -0
  116. data/db/migrate/20140407193412_add_width_to_mechanize_store_product.rb +6 -0
  117. data/db/migrate/20140409191426_create_mechanize_store_order_items.rb +12 -0
  118. data/db/migrate/20140416123100_add_payment_type_id_to_payment.rb +6 -0
  119. data/db/migrate/20140417200520_add_time_to_freight.rb +5 -0
  120. data/lib/mechanize_store.rb +4 -0
  121. data/lib/mechanize_store/engine.rb +17 -0
  122. data/lib/mechanize_store/version.rb +3 -0
  123. data/lib/tasks/mechanize_store_tasks.rake +4 -0
  124. data/lib/templates/erb/scaffold/_form.html.erb +13 -0
  125. data/lib/templates/erb/scaffold/edit.html.erb +12 -0
  126. data/lib/templates/erb/scaffold/index.html.erb +50 -0
  127. data/lib/templates/erb/scaffold/new.html.erb +9 -0
  128. data/lib/templates/erb/scaffold/show.html.erb +17 -0
  129. data/lib/templates/rails/scaffold_controller/controller.rb +79 -0
  130. data/spec/controllers/mechanize_store/flags_controller_spec.rb +138 -0
  131. data/spec/controllers/mechanize_store/order_statuses_controller_spec.rb +138 -0
  132. data/spec/controllers/mechanize_store/orders_controller_spec.rb +29 -0
  133. data/spec/controllers/mechanize_store/payment_statuses_controller_spec.rb +139 -0
  134. data/spec/controllers/mechanize_store/payment_types_controller_spec.rb +139 -0
  135. data/spec/controllers/mechanize_store/product_categories_controller_spec.rb +138 -0
  136. data/spec/controllers/mechanize_store/product_photos_controller_spec.rb +75 -0
  137. data/spec/controllers/mechanize_store/products_controller_spec.rb +135 -0
  138. data/spec/dummy/README.rdoc +28 -0
  139. data/spec/dummy/Rakefile +6 -0
  140. data/spec/dummy/app/assets/javascripts/application.js +13 -0
  141. data/spec/dummy/app/assets/stylesheets/application.css +13 -0
  142. data/spec/dummy/app/controllers/application_controller.rb +5 -0
  143. data/spec/dummy/app/helpers/application_helper.rb +2 -0
  144. data/spec/dummy/app/views/layouts/application.html.erb +14 -0
  145. data/spec/dummy/bin/bundle +3 -0
  146. data/spec/dummy/bin/rails +4 -0
  147. data/spec/dummy/bin/rake +4 -0
  148. data/spec/dummy/config.ru +4 -0
  149. data/spec/dummy/config/application.rb +25 -0
  150. data/spec/dummy/config/boot.rb +5 -0
  151. data/spec/dummy/config/database.yml +25 -0
  152. data/spec/dummy/config/environment.rb +5 -0
  153. data/spec/dummy/config/environments/development.rb +29 -0
  154. data/spec/dummy/config/environments/production.rb +80 -0
  155. data/spec/dummy/config/environments/test.rb +36 -0
  156. data/spec/dummy/config/initializers/backtrace_silencers.rb +7 -0
  157. data/spec/dummy/config/initializers/filter_parameter_logging.rb +4 -0
  158. data/spec/dummy/config/initializers/inflections.rb +16 -0
  159. data/spec/dummy/config/initializers/mime_types.rb +5 -0
  160. data/spec/dummy/config/initializers/secret_token.rb +12 -0
  161. data/spec/dummy/config/initializers/session_store.rb +3 -0
  162. data/spec/dummy/config/initializers/simple_form.rb +145 -0
  163. data/spec/dummy/config/initializers/wrap_parameters.rb +14 -0
  164. data/spec/dummy/config/locales/en.yml +23 -0
  165. data/spec/dummy/config/locales/pt-BR.yml +23 -0
  166. data/spec/dummy/config/routes.rb +3 -0
  167. data/spec/dummy/db/development.sqlite3 +0 -0
  168. data/spec/dummy/db/migrate/20140407144119_create_mechanize_store_freights.mechanize_store.rb +13 -0
  169. data/spec/dummy/db/migrate/20140407144120_create_mechanize_store_order_statuses.mechanize_store.rb +10 -0
  170. data/spec/dummy/db/migrate/20140407144121_create_mechanize_store_payment_statuses.mechanize_store.rb +10 -0
  171. data/spec/dummy/db/migrate/20140407144122_create_mechanize_store_payment_types.mechanize_store.rb +10 -0
  172. data/spec/dummy/db/migrate/20140407144123_create_mechanize_store_payments.mechanize_store.rb +17 -0
  173. data/spec/dummy/db/migrate/20140407144124_create_mechanize_store_flags.mechanize_store.rb +10 -0
  174. data/spec/dummy/db/migrate/20140407144125_create_mechanize_store_products.mechanize_store.rb +17 -0
  175. data/spec/dummy/db/migrate/20140407144126_create_mechanize_store_product_photos.mechanize_store.rb +11 -0
  176. data/spec/dummy/db/migrate/20140407144127_create_mechanize_store_orders.mechanize_store.rb +12 -0
  177. data/spec/dummy/db/migrate/20140407144128_create_mechanize_store_product_categories.mechanize_store.rb +11 -0
  178. data/spec/dummy/db/migrate/20140407193949_add_width_to_mechanize_store_product.mechanize_store.rb +7 -0
  179. data/spec/dummy/db/migrate/20140409191457_create_mechanize_store_order_items.mechanize_store.rb +13 -0
  180. data/spec/dummy/db/schema.rb +125 -0
  181. data/spec/dummy/db/test.sqlite3 +0 -0
  182. data/spec/dummy/log/development.log +24931 -0
  183. data/spec/dummy/log/test.log +42225 -0
  184. data/spec/dummy/public/404.html +58 -0
  185. data/spec/dummy/public/422.html +58 -0
  186. data/spec/dummy/public/500.html +57 -0
  187. data/spec/dummy/public/favicon.ico +0 -0
  188. data/spec/dummy/tmp/cache/assets/development/sprockets/015a50b3ac7ad70aa90ce0a95c99df04 +0 -0
  189. data/spec/dummy/tmp/cache/assets/development/sprockets/020540bcd9f6782692071f17f50f43b0 +0 -0
  190. data/spec/dummy/tmp/cache/assets/development/sprockets/0378e5799bf84efc4c9b8ac61252a081 +0 -0
  191. data/spec/dummy/tmp/cache/assets/development/sprockets/04032662bf2ebfb00b4218e459ab14bf +0 -0
  192. data/spec/dummy/tmp/cache/assets/development/sprockets/043663643ec7f44e8f7baeb7856605bb +0 -0
  193. data/spec/dummy/tmp/cache/assets/development/sprockets/059883583379e5e373caaa73ac8f18ca +0 -0
  194. data/spec/dummy/tmp/cache/assets/development/sprockets/05f7ba95ff1ffeab9cb378fcb7b0289f +0 -0
  195. data/spec/dummy/tmp/cache/assets/development/sprockets/069b62a9f82e145a95c6dbcada54860d +0 -0
  196. data/spec/dummy/tmp/cache/assets/development/sprockets/06ce3d4f3b99f90fa0ced1db38c5fb13 +0 -0
  197. data/spec/dummy/tmp/cache/assets/development/sprockets/0a70c895b23487214ec56a6cd4bd9552 +0 -0
  198. data/spec/dummy/tmp/cache/assets/development/sprockets/0e42ab04670f4d8017b5eeb5ec7f080b +0 -0
  199. data/spec/dummy/tmp/cache/assets/development/sprockets/0f2edd5bf10b0d769d20d28769abf705 +0 -0
  200. data/spec/dummy/tmp/cache/assets/development/sprockets/13fe41fee1fe35b49d145bcc06610705 +0 -0
  201. data/spec/dummy/tmp/cache/assets/development/sprockets/14464296f672d2910982229137d66535 +0 -0
  202. data/spec/dummy/tmp/cache/assets/development/sprockets/19456f04c83f78d9ab6e5d57031015ef +0 -0
  203. data/spec/dummy/tmp/cache/assets/development/sprockets/1a5faaf1e18d5f49d129459ae565f1af +0 -0
  204. data/spec/dummy/tmp/cache/assets/development/sprockets/1a78a9c2facea31464f84e54fdc36059 +0 -0
  205. data/spec/dummy/tmp/cache/assets/development/sprockets/1da2c163f7f6bbd029786010cd788bce +0 -0
  206. data/spec/dummy/tmp/cache/assets/development/sprockets/250ad25722c066145272032ad82f4561 +0 -0
  207. data/spec/dummy/tmp/cache/assets/development/sprockets/2593c6406f0e0ba8eb5271badc1fbef1 +0 -0
  208. data/spec/dummy/tmp/cache/assets/development/sprockets/262f77e6bb6c8e1453f5477c82a17b11 +0 -0
  209. data/spec/dummy/tmp/cache/assets/development/sprockets/27479abec405e7ea5ee309699b19c495 +0 -0
  210. data/spec/dummy/tmp/cache/assets/development/sprockets/2b16e3dfbce9d1bb0de91f424f03694a +0 -0
  211. data/spec/dummy/tmp/cache/assets/development/sprockets/2b89581781ce2529d6435ae4a831dcb9 +0 -0
  212. data/spec/dummy/tmp/cache/assets/development/sprockets/2c8d436d977e56045cd16cc55f33e24f +0 -0
  213. data/spec/dummy/tmp/cache/assets/development/sprockets/2d8950ff6bb73413e9deb6e196bfffd0 +0 -0
  214. data/spec/dummy/tmp/cache/assets/development/sprockets/2dc34152e91278da6990e448dccf297a +0 -0
  215. data/spec/dummy/tmp/cache/assets/development/sprockets/2e2c50f356deda30cee516e501b1eb70 +0 -0
  216. data/spec/dummy/tmp/cache/assets/development/sprockets/2ee1b9592bbe1ba628925e28b31fdc2a +0 -0
  217. data/spec/dummy/tmp/cache/assets/development/sprockets/2f378010bb54f8ca9c2a38c7df245b26 +0 -0
  218. data/spec/dummy/tmp/cache/assets/development/sprockets/2f5173deea6c795b8fdde723bb4b63af +0 -0
  219. data/spec/dummy/tmp/cache/assets/development/sprockets/357970feca3ac29060c1e3861e2c0953 +0 -0
  220. data/spec/dummy/tmp/cache/assets/development/sprockets/38aa872dea852cc952801236dfc073fc +0 -0
  221. data/spec/dummy/tmp/cache/assets/development/sprockets/3c562eb64c2c0fc045f18356d3ddd84e +0 -0
  222. data/spec/dummy/tmp/cache/assets/development/sprockets/3daa6dd7a3804d55f1896a2d40ccea5f +0 -0
  223. data/spec/dummy/tmp/cache/assets/development/sprockets/436e4923cef6508f9572309894ad3afb +0 -0
  224. data/spec/dummy/tmp/cache/assets/development/sprockets/43db98f3f4043e28dd241d4bcf40a382 +0 -0
  225. data/spec/dummy/tmp/cache/assets/development/sprockets/4517526bf21c2e0d4475812a0801ff73 +0 -0
  226. data/spec/dummy/tmp/cache/assets/development/sprockets/45e8f86d32c088635371e9d83d481ff0 +0 -0
  227. data/spec/dummy/tmp/cache/assets/development/sprockets/46c7525f809be6b9a6da46ec5281b90d +0 -0
  228. data/spec/dummy/tmp/cache/assets/development/sprockets/48710380827190cf4c297aeb8ff8f521 +0 -0
  229. data/spec/dummy/tmp/cache/assets/development/sprockets/48c25b92a4e1841bd519a77588afb5df +0 -0
  230. data/spec/dummy/tmp/cache/assets/development/sprockets/4b3b499b73fde3f086615d203a4cd9ee +0 -0
  231. data/spec/dummy/tmp/cache/assets/development/sprockets/4c1f9a5156d1c8724067d833a65dc486 +0 -0
  232. data/spec/dummy/tmp/cache/assets/development/sprockets/4e1d544283e15d5f8e7575f717a440a4 +0 -0
  233. data/spec/dummy/tmp/cache/assets/development/sprockets/54843f9a3a2ac75ad7ebde3307ce8606 +0 -0
  234. data/spec/dummy/tmp/cache/assets/development/sprockets/55116814eac2aaa3b60343e4269a18f9 +0 -0
  235. data/spec/dummy/tmp/cache/assets/development/sprockets/55d45208b6b824293fd70642ec435749 +0 -0
  236. data/spec/dummy/tmp/cache/assets/development/sprockets/593ece65492f611f990932db9d09f2c7 +0 -0
  237. data/spec/dummy/tmp/cache/assets/development/sprockets/59bb66920183998fcca5f2c787d0180e +0 -0
  238. data/spec/dummy/tmp/cache/assets/development/sprockets/5c19a1c0836acd88cf90128587c8a9f2 +0 -0
  239. data/spec/dummy/tmp/cache/assets/development/sprockets/5cbd47d1e56ce6ad12324dc100b18435 +0 -0
  240. data/spec/dummy/tmp/cache/assets/development/sprockets/5dd2138848e347d174c374d012420ae3 +0 -0
  241. data/spec/dummy/tmp/cache/assets/development/sprockets/5e2b19c7c137f093e3a17e2eed13b00e +0 -0
  242. data/spec/dummy/tmp/cache/assets/development/sprockets/5f29f414f1d3e6a4c8eacd4974e20369 +0 -0
  243. data/spec/dummy/tmp/cache/assets/development/sprockets/5fc8e81b247da7b93af8a2eb06017a5e +0 -0
  244. data/spec/dummy/tmp/cache/assets/development/sprockets/646c6b9465381d825591b427e65cfa6f +0 -0
  245. data/spec/dummy/tmp/cache/assets/development/sprockets/6554b2d6606c5f90f91a8a1f01ee5207 +0 -0
  246. data/spec/dummy/tmp/cache/assets/development/sprockets/662f5fc7888fcf74ff719aea443f1e0e +0 -0
  247. data/spec/dummy/tmp/cache/assets/development/sprockets/66c3c3a1daf01d2edc14fb56645814af +0 -0
  248. data/spec/dummy/tmp/cache/assets/development/sprockets/69f57e81929c085cfd164a7b30f9cb5f +0 -0
  249. data/spec/dummy/tmp/cache/assets/development/sprockets/6a7af764897e94acc0adc4f6855846ea +0 -0
  250. data/spec/dummy/tmp/cache/assets/development/sprockets/6ddd5e3587977e83d7dc7b7124cc4044 +0 -0
  251. data/spec/dummy/tmp/cache/assets/development/sprockets/70894d30d9a638ae5cb410c1bf51d436 +0 -0
  252. data/spec/dummy/tmp/cache/assets/development/sprockets/746b6834bc4167c8495578a1b7b05cd2 +0 -0
  253. data/spec/dummy/tmp/cache/assets/development/sprockets/748419e05355441fbf8b5177841a01ae +0 -0
  254. data/spec/dummy/tmp/cache/assets/development/sprockets/75b6e2b76634cd778e12a60b8862cc83 +0 -0
  255. data/spec/dummy/tmp/cache/assets/development/sprockets/75e995d7f41c3d87054f39654ee96276 +0 -0
  256. data/spec/dummy/tmp/cache/assets/development/sprockets/7a6ffbc3e76322931e50faa267bf2ccd +0 -0
  257. data/spec/dummy/tmp/cache/assets/development/sprockets/7dbc97a9be7f04dc0f5cb28337fe9f4c +0 -0
  258. data/spec/dummy/tmp/cache/assets/development/sprockets/7e908a7a32793f07298fa2f32f7a1da6 +0 -0
  259. data/spec/dummy/tmp/cache/assets/development/sprockets/80137a3a1ee5336154baaea4290aa0fa +0 -0
  260. data/spec/dummy/tmp/cache/assets/development/sprockets/80a4a7e08ffe3c1b0ad632a9f69dae61 +0 -0
  261. data/spec/dummy/tmp/cache/assets/development/sprockets/875373523edad14b9efdc32d30056b88 +0 -0
  262. data/spec/dummy/tmp/cache/assets/development/sprockets/8b2a3bdfdd87982dbcdf9beaa4883771 +0 -0
  263. data/spec/dummy/tmp/cache/assets/development/sprockets/8c29fc18ccf7320aa1f9d9fbc277adbc +0 -0
  264. data/spec/dummy/tmp/cache/assets/development/sprockets/8c48b01bb6fe5d3f87c3e2d8796bfe57 +0 -0
  265. data/spec/dummy/tmp/cache/assets/development/sprockets/8c880b8aef8a9168cf039ff966dde072 +0 -0
  266. data/spec/dummy/tmp/cache/assets/development/sprockets/8e1041b3a7abe8f1431f078dd04e52f2 +0 -0
  267. data/spec/dummy/tmp/cache/assets/development/sprockets/8e1509b014a325c41eb6d6d060697d5b +0 -0
  268. data/spec/dummy/tmp/cache/assets/development/sprockets/9295c97f3680de471db1138760883721 +0 -0
  269. data/spec/dummy/tmp/cache/assets/development/sprockets/932ff26d70c7f83db540941e70fbc256 +0 -0
  270. data/spec/dummy/tmp/cache/assets/development/sprockets/95d1184dee9d6ad8efbb18992ef7f3bd +0 -0
  271. data/spec/dummy/tmp/cache/assets/development/sprockets/9a57b3781439b98aa17111614be63659 +0 -0
  272. data/spec/dummy/tmp/cache/assets/development/sprockets/9a958d65f5d84cf81a860fe6b98f7586 +0 -0
  273. data/spec/dummy/tmp/cache/assets/development/sprockets/9ba78083ca4f55d2e3dbb4c16f5108a4 +0 -0
  274. data/spec/dummy/tmp/cache/assets/development/sprockets/9bf7f52d56b17c5fcacc89e0196ec9ec +0 -0
  275. data/spec/dummy/tmp/cache/assets/development/sprockets/9dcc41c3f740c89aa23972f9f0fb7682 +0 -0
  276. data/spec/dummy/tmp/cache/assets/development/sprockets/9dd69825bb5d22668e78fcadbcc384bf +0 -0
  277. data/spec/dummy/tmp/cache/assets/development/sprockets/9f7694dc7aa37365dca45aa754f46e75 +0 -0
  278. data/spec/dummy/tmp/cache/assets/development/sprockets/a119b32f75ff105e311edc0f31ca67f6 +0 -0
  279. data/spec/dummy/tmp/cache/assets/development/sprockets/a388745aef9974ea0f378a3b83f6f8e7 +0 -0
  280. data/spec/dummy/tmp/cache/assets/development/sprockets/a80b32eb0130473db70817a2464be54a +0 -0
  281. data/spec/dummy/tmp/cache/assets/development/sprockets/a97cfb7a9ba4204c2c02cb794e0b529e +0 -0
  282. data/spec/dummy/tmp/cache/assets/development/sprockets/a9d026eb5dcf44bbad77067be7ccc216 +0 -0
  283. data/spec/dummy/tmp/cache/assets/development/sprockets/ac2422a2e7c30bbcf41620f5eadf6c9a +0 -0
  284. data/spec/dummy/tmp/cache/assets/development/sprockets/aca81e68e9477c36988579e16d099f7a +0 -0
  285. data/spec/dummy/tmp/cache/assets/development/sprockets/ad821e6998f57556c2bbebeac574bbd3 +0 -0
  286. data/spec/dummy/tmp/cache/assets/development/sprockets/adc26899d70ead5b9321d6b6be5cb73a +0 -0
  287. data/spec/dummy/tmp/cache/assets/development/sprockets/ae2d91de359a9f7f39d93f379705b07c +0 -0
  288. data/spec/dummy/tmp/cache/assets/development/sprockets/b1909373f0eb96fc7eb1a16b13cf9d9c +0 -0
  289. data/spec/dummy/tmp/cache/assets/development/sprockets/b2d360ac92a3862e54a81752fac14f04 +0 -0
  290. data/spec/dummy/tmp/cache/assets/development/sprockets/b32edcdd838f74e3b0b694bb4fb78135 +0 -0
  291. data/spec/dummy/tmp/cache/assets/development/sprockets/b80b1d0da5126d78830d5cc9d33bb939 +0 -0
  292. data/spec/dummy/tmp/cache/assets/development/sprockets/b80ff122a6e6cb26a8726574c9ed9843 +0 -0
  293. data/spec/dummy/tmp/cache/assets/development/sprockets/b8788a2d9cd7867f9732a0d1218b3be3 +0 -0
  294. data/spec/dummy/tmp/cache/assets/development/sprockets/c01c09c7af2805825d421efe97369c92 +0 -0
  295. data/spec/dummy/tmp/cache/assets/development/sprockets/c096a28eb3fb4f6a5943814c1d83de28 +0 -0
  296. data/spec/dummy/tmp/cache/assets/development/sprockets/c1c5e3bf6b463ce593f544553cd61880 +0 -0
  297. data/spec/dummy/tmp/cache/assets/development/sprockets/c206d760825f5d60935bc162372aae5f +0 -0
  298. data/spec/dummy/tmp/cache/assets/development/sprockets/c276778eb885b31ac5c72899422f687b +0 -0
  299. data/spec/dummy/tmp/cache/assets/development/sprockets/c381ab6aead4f08abb9b7da1fd2c5cbe +0 -0
  300. data/spec/dummy/tmp/cache/assets/development/sprockets/c3fae7c3a4d1eb0934a03e3508994894 +0 -0
  301. data/spec/dummy/tmp/cache/assets/development/sprockets/c532dcbd254ee5454d453f8dca2ea356 +0 -0
  302. data/spec/dummy/tmp/cache/assets/development/sprockets/c5febc1300d6cd4c2f85a5dcc4ccca65 +0 -0
  303. data/spec/dummy/tmp/cache/assets/development/sprockets/c6337ac9ac53de67c5e4e0bbd8e0b98f +0 -0
  304. data/spec/dummy/tmp/cache/assets/development/sprockets/c63f6f599121de54f10407499bdeb95d +0 -0
  305. data/spec/dummy/tmp/cache/assets/development/sprockets/c6ccf7b3128d1693a850e8014129e21b +0 -0
  306. data/spec/dummy/tmp/cache/assets/development/sprockets/c884f6ae49a257a9b8218d60cddc22c1 +0 -0
  307. data/spec/dummy/tmp/cache/assets/development/sprockets/c9053dba65ec180c37b513c1e0a02953 +0 -0
  308. data/spec/dummy/tmp/cache/assets/development/sprockets/c9274eaf6338c910a014211f057bb10f +0 -0
  309. data/spec/dummy/tmp/cache/assets/development/sprockets/c9b7bfc895f9ef763149e886eed1c12a +0 -0
  310. data/spec/dummy/tmp/cache/assets/development/sprockets/ca5d6127a6b6cb20b3137c6ed1b086e4 +0 -0
  311. data/spec/dummy/tmp/cache/assets/development/sprockets/ca68d3d42cc489b72f5a9caa1bec8a0f +0 -0
  312. data/spec/dummy/tmp/cache/assets/development/sprockets/cbb3bbaeb5cbb28714fc2d854e55d759 +0 -0
  313. data/spec/dummy/tmp/cache/assets/development/sprockets/cbc8f4f72d68f84e285b14c13c615e94 +0 -0
  314. data/spec/dummy/tmp/cache/assets/development/sprockets/cbf5cac128a3b9fd8567cf02d8b5c7f4 +0 -0
  315. data/spec/dummy/tmp/cache/assets/development/sprockets/cf62df2949741a6dfcbdf6dae39a376e +0 -0
  316. data/spec/dummy/tmp/cache/assets/development/sprockets/cfe2122c3660d4bf29e621b13cc1e4c0 +0 -0
  317. data/spec/dummy/tmp/cache/assets/development/sprockets/cffd775d018f68ce5dba1ee0d951a994 +0 -0
  318. data/spec/dummy/tmp/cache/assets/development/sprockets/d1ebcb314c13703007e0a6e9c5604655 +0 -0
  319. data/spec/dummy/tmp/cache/assets/development/sprockets/d4db7fd1c1ad160335e9abc86e49a138 +0 -0
  320. data/spec/dummy/tmp/cache/assets/development/sprockets/d5a9b12dc73b0e530314f93a2e7d4270 +0 -0
  321. data/spec/dummy/tmp/cache/assets/development/sprockets/d771ace226fc8215a3572e0aa35bb0d6 +0 -0
  322. data/spec/dummy/tmp/cache/assets/development/sprockets/d84c8af9dd2dd84ac27282b753d2b33c +0 -0
  323. data/spec/dummy/tmp/cache/assets/development/sprockets/d86a26ce11fa0095e076b69ecd98fbf6 +0 -0
  324. data/spec/dummy/tmp/cache/assets/development/sprockets/dba3e0db21349797be91d79366b2e6d9 +0 -0
  325. data/spec/dummy/tmp/cache/assets/development/sprockets/dcfc0ac1daceac33f1f1d348341a8c75 +0 -0
  326. data/spec/dummy/tmp/cache/assets/development/sprockets/dd149c63c658dcacd022a8bbd0136c9f +0 -0
  327. data/spec/dummy/tmp/cache/assets/development/sprockets/de287cf9a2ea50ebc178bcc7cd8e0f4c +0 -0
  328. data/spec/dummy/tmp/cache/assets/development/sprockets/de35fa3c2360ca5a0479c6ec6c8c0d62 +0 -0
  329. data/spec/dummy/tmp/cache/assets/development/sprockets/dfc074e83f62650815ec91d5e6ae716a +0 -0
  330. data/spec/dummy/tmp/cache/assets/development/sprockets/e4806a3aea27283bdce20bcb1cc894a6 +0 -0
  331. data/spec/dummy/tmp/cache/assets/development/sprockets/e9075a2c21b7e2c0543aceff4975485a +0 -0
  332. data/spec/dummy/tmp/cache/assets/development/sprockets/e9c2ccf818891a7575ec2200367bbf52 +0 -0
  333. data/spec/dummy/tmp/cache/assets/development/sprockets/eb3496f8d86eed2469155f90f146a7bd +0 -0
  334. data/spec/dummy/tmp/cache/assets/development/sprockets/ec5d87f50983b6156db79eb4c4b0ae6d +0 -0
  335. data/spec/dummy/tmp/cache/assets/development/sprockets/f0bb04309f0742e927d269899c6b9a4a +0 -0
  336. data/spec/dummy/tmp/cache/assets/development/sprockets/f0fdb965c01e31547d9058c609918712 +0 -0
  337. data/spec/dummy/tmp/cache/assets/development/sprockets/f2de92b01852702a49c9e9e5cd3b320f +0 -0
  338. data/spec/dummy/tmp/cache/assets/development/sprockets/f478e4dc1bdfe5240e3ca48440488e32 +0 -0
  339. data/spec/dummy/tmp/cache/assets/development/sprockets/f51cc05ee2ec6ed667257568e527f522 +0 -0
  340. data/spec/dummy/tmp/cache/assets/development/sprockets/f535bdc9ad7f7f6ce6009b846c2fc2d7 +0 -0
  341. data/spec/dummy/tmp/cache/assets/development/sprockets/f61f3d9d282d0c092d604b8433071c77 +0 -0
  342. data/spec/dummy/tmp/cache/assets/development/sprockets/f7cbd26ba1d28d48de824f0e94586655 +0 -0
  343. data/spec/dummy/tmp/cache/assets/development/sprockets/f97dc728e6d15fb7ba9f14ad2b8b6bcb +0 -0
  344. data/spec/dummy/tmp/cache/assets/development/sprockets/faeec0db256cfb91ad104e66a9453bd9 +0 -0
  345. data/spec/dummy/tmp/cache/assets/development/sprockets/fbbf6a435d522871a2d29d97e370bfce +0 -0
  346. data/spec/dummy/tmp/cache/assets/development/sprockets/ffbf6316da17c85bd6bda4bdb1961baf +0 -0
  347. data/spec/factories/mechanize_store_order_items.rb +10 -0
  348. data/spec/factories/mechanize_store_products.rb +14 -0
  349. data/spec/factories/store_flags.rb +7 -0
  350. data/spec/factories/store_freights.rb +10 -0
  351. data/spec/factories/store_order_statuses.rb +7 -0
  352. data/spec/factories/store_orders.rb +8 -0
  353. data/spec/factories/store_payment_statuses.rb +7 -0
  354. data/spec/factories/store_payment_types.rb +7 -0
  355. data/spec/factories/store_payments.rb +14 -0
  356. data/spec/factories/store_product_categories.rb +8 -0
  357. data/spec/factories/store_product_photos.rb +8 -0
  358. data/spec/factories/store_stores.rb +10 -0
  359. data/spec/features/orders_flow_spec.rb +0 -0
  360. data/spec/features/products_flow_test.rb +68 -0
  361. data/spec/fixtures/rails.png +0 -0
  362. data/spec/models/mechanize_store/order_item_spec.rb +7 -0
  363. data/spec/models/store/flag_spec.rb +7 -0
  364. data/spec/models/store/freight_spec.rb +7 -0
  365. data/spec/models/store/order_spec.rb +7 -0
  366. data/spec/models/store/order_status_spec.rb +7 -0
  367. data/spec/models/store/payment_spec.rb +7 -0
  368. data/spec/models/store/payment_status_spec.rb +7 -0
  369. data/spec/models/store/payment_type_spec.rb +7 -0
  370. data/spec/models/store/product_category_spec.rb +7 -0
  371. data/spec/models/store/product_photo_spec.rb +7 -0
  372. data/spec/models/store/product_spec.rb +7 -0
  373. data/spec/models/store/store_spec.rb +7 -0
  374. data/spec/routing/store/flags_routing_spec.rb +39 -0
  375. data/spec/routing/store/order_statuses_routing_spec.rb +39 -0
  376. data/spec/routing/store/orders_routing_spec.rb +18 -0
  377. data/spec/routing/store/payment_statuses_routing_spec.rb +38 -0
  378. data/spec/routing/store/payment_types_routing_spec.rb +38 -0
  379. data/spec/routing/store/product_categories_routing_spec.rb +39 -0
  380. data/spec/routing/store/products_photos_routing_spec.rb +19 -0
  381. data/spec/routing/store/products_routing_spec.rb +39 -0
  382. data/spec/spec_helper.rb +22 -0
  383. metadata +876 -0
@@ -0,0 +1,119 @@
1
+ /*
2
+ * jQuery File Upload Validation Plugin 1.1.2
3
+ * https://github.com/blueimp/jQuery-File-Upload
4
+ *
5
+ * Copyright 2013, Sebastian Tschan
6
+ * https://blueimp.net
7
+ *
8
+ * Licensed under the MIT license:
9
+ * http://www.opensource.org/licenses/MIT
10
+ */
11
+
12
+ /* global define, window */
13
+
14
+ (function (factory) {
15
+ 'use strict';
16
+ if (typeof define === 'function' && define.amd) {
17
+ // Register as an anonymous AMD module:
18
+ define([
19
+ 'jquery',
20
+ './jquery.fileupload-process'
21
+ ], factory);
22
+ } else {
23
+ // Browser globals:
24
+ factory(
25
+ window.jQuery
26
+ );
27
+ }
28
+ }(function ($) {
29
+ 'use strict';
30
+
31
+ // Append to the default processQueue:
32
+ $.blueimp.fileupload.prototype.options.processQueue.push(
33
+ {
34
+ action: 'validate',
35
+ // Always trigger this action,
36
+ // even if the previous action was rejected:
37
+ always: true,
38
+ // Options taken from the global options map:
39
+ acceptFileTypes: '@',
40
+ maxFileSize: '@',
41
+ minFileSize: '@',
42
+ maxNumberOfFiles: '@',
43
+ disabled: '@disableValidation'
44
+ }
45
+ );
46
+
47
+ // The File Upload Validation plugin extends the fileupload widget
48
+ // with file validation functionality:
49
+ $.widget('blueimp.fileupload', $.blueimp.fileupload, {
50
+
51
+ options: {
52
+ /*
53
+ // The regular expression for allowed file types, matches
54
+ // against either file type or file name:
55
+ acceptFileTypes: /(\.|\/)(gif|jpe?g|png)$/i,
56
+ // The maximum allowed file size in bytes:
57
+ maxFileSize: 10000000, // 10 MB
58
+ // The minimum allowed file size in bytes:
59
+ minFileSize: undefined, // No minimal file size
60
+ // The limit of files to be uploaded:
61
+ maxNumberOfFiles: 10,
62
+ */
63
+
64
+ // Function returning the current number of files,
65
+ // has to be overriden for maxNumberOfFiles validation:
66
+ getNumberOfFiles: $.noop,
67
+
68
+ // Error and info messages:
69
+ messages: {
70
+ maxNumberOfFiles: 'Maximum number of files exceeded',
71
+ acceptFileTypes: 'File type not allowed',
72
+ maxFileSize: 'File is too large',
73
+ minFileSize: 'File is too small'
74
+ }
75
+ },
76
+
77
+ processActions: {
78
+
79
+ validate: function (data, options) {
80
+ if (options.disabled) {
81
+ return data;
82
+ }
83
+ var dfd = $.Deferred(),
84
+ settings = this.options,
85
+ file = data.files[data.index],
86
+ fileSize;
87
+ if (options.minFileSize || options.maxFileSize) {
88
+ fileSize = file.size;
89
+ }
90
+ if ($.type(options.maxNumberOfFiles) === 'number' &&
91
+ (settings.getNumberOfFiles() || 0) + data.files.length >
92
+ options.maxNumberOfFiles) {
93
+ file.error = settings.i18n('maxNumberOfFiles');
94
+ } else if (options.acceptFileTypes &&
95
+ !(options.acceptFileTypes.test(file.type) ||
96
+ options.acceptFileTypes.test(file.name))) {
97
+ file.error = settings.i18n('acceptFileTypes');
98
+ } else if (fileSize > options.maxFileSize) {
99
+ file.error = settings.i18n('maxFileSize');
100
+ } else if ($.type(fileSize) === 'number' &&
101
+ fileSize < options.minFileSize) {
102
+ file.error = settings.i18n('minFileSize');
103
+ } else {
104
+ delete file.error;
105
+ }
106
+ if (file.error || data.files.error) {
107
+ data.files.error = true;
108
+ dfd.rejectWith(this, [data]);
109
+ } else {
110
+ dfd.resolveWith(this, [data]);
111
+ }
112
+ return dfd.promise();
113
+ }
114
+
115
+ }
116
+
117
+ });
118
+
119
+ }));
@@ -0,0 +1,106 @@
1
+ /*
2
+ * jQuery File Upload Video Preview Plugin 1.0.3
3
+ * https://github.com/blueimp/jQuery-File-Upload
4
+ *
5
+ * Copyright 2013, Sebastian Tschan
6
+ * https://blueimp.net
7
+ *
8
+ * Licensed under the MIT license:
9
+ * http://www.opensource.org/licenses/MIT
10
+ */
11
+
12
+ /* jshint nomen:false */
13
+ /* global define, window, document */
14
+
15
+ (function (factory) {
16
+ 'use strict';
17
+ if (typeof define === 'function' && define.amd) {
18
+ // Register as an anonymous AMD module:
19
+ define([
20
+ 'jquery',
21
+ 'load-image',
22
+ './jquery.fileupload-process'
23
+ ], factory);
24
+ } else {
25
+ // Browser globals:
26
+ factory(
27
+ window.jQuery,
28
+ window.loadImage
29
+ );
30
+ }
31
+ }(function ($, loadImage) {
32
+ 'use strict';
33
+
34
+ // Prepend to the default processQueue:
35
+ $.blueimp.fileupload.prototype.options.processQueue.unshift(
36
+ {
37
+ action: 'loadVideo',
38
+ // Use the action as prefix for the "@" options:
39
+ prefix: true,
40
+ fileTypes: '@',
41
+ maxFileSize: '@',
42
+ disabled: '@disableVideoPreview'
43
+ },
44
+ {
45
+ action: 'setVideo',
46
+ name: '@videoPreviewName',
47
+ disabled: '@disableVideoPreview'
48
+ }
49
+ );
50
+
51
+ // The File Upload Video Preview plugin extends the fileupload widget
52
+ // with video preview functionality:
53
+ $.widget('blueimp.fileupload', $.blueimp.fileupload, {
54
+
55
+ options: {
56
+ // The regular expression for the types of video files to load,
57
+ // matched against the file type:
58
+ loadVideoFileTypes: /^video\/.*$/
59
+ },
60
+
61
+ _videoElement: document.createElement('video'),
62
+
63
+ processActions: {
64
+
65
+ // Loads the video file given via data.files and data.index
66
+ // as video element if the browser supports playing it.
67
+ // Accepts the options fileTypes (regular expression)
68
+ // and maxFileSize (integer) to limit the files to load:
69
+ loadVideo: function (data, options) {
70
+ if (options.disabled) {
71
+ return data;
72
+ }
73
+ var file = data.files[data.index],
74
+ url,
75
+ video;
76
+ if (this._videoElement.canPlayType &&
77
+ this._videoElement.canPlayType(file.type) &&
78
+ ($.type(options.maxFileSize) !== 'number' ||
79
+ file.size <= options.maxFileSize) &&
80
+ (!options.fileTypes ||
81
+ options.fileTypes.test(file.type))) {
82
+ url = loadImage.createObjectURL(file);
83
+ if (url) {
84
+ video = this._videoElement.cloneNode(false);
85
+ video.src = url;
86
+ video.controls = true;
87
+ data.video = video;
88
+ return data;
89
+ }
90
+ }
91
+ return data;
92
+ },
93
+
94
+ // Sets the video element as a property of the file object:
95
+ setVideo: function (data, options) {
96
+ if (data.video && !options.disabled) {
97
+ data.files[data.index][options.name || 'preview'] = data.video;
98
+ }
99
+ return data;
100
+ }
101
+
102
+ }
103
+
104
+ });
105
+
106
+ }));
@@ -0,0 +1,1426 @@
1
+ /*
2
+ * jQuery File Upload Plugin 5.40.1
3
+ * https://github.com/blueimp/jQuery-File-Upload
4
+ *
5
+ * Copyright 2010, Sebastian Tschan
6
+ * https://blueimp.net
7
+ *
8
+ * Licensed under the MIT license:
9
+ * http://www.opensource.org/licenses/MIT
10
+ */
11
+
12
+ /* jshint nomen:false */
13
+ /* global define, window, document, location, Blob, FormData */
14
+
15
+ (function (factory) {
16
+ 'use strict';
17
+ if (typeof define === 'function' && define.amd) {
18
+ // Register as an anonymous AMD module:
19
+ define([
20
+ 'jquery',
21
+ 'jquery.ui.widget'
22
+ ], factory);
23
+ } else {
24
+ // Browser globals:
25
+ factory(window.jQuery);
26
+ }
27
+ }(function ($) {
28
+ 'use strict';
29
+
30
+ // Detect file input support, based on
31
+ // http://viljamis.com/blog/2012/file-upload-support-on-mobile/
32
+ $.support.fileInput = !(new RegExp(
33
+ // Handle devices which give false positives for the feature detection:
34
+ '(Android (1\\.[0156]|2\\.[01]))' +
35
+ '|(Windows Phone (OS 7|8\\.0))|(XBLWP)|(ZuneWP)|(WPDesktop)' +
36
+ '|(w(eb)?OSBrowser)|(webOS)' +
37
+ '|(Kindle/(1\\.0|2\\.[05]|3\\.0))'
38
+ ).test(window.navigator.userAgent) ||
39
+ // Feature detection for all other devices:
40
+ $('<input type="file">').prop('disabled'));
41
+
42
+ // The FileReader API is not actually used, but works as feature detection,
43
+ // as some Safari versions (5?) support XHR file uploads via the FormData API,
44
+ // but not non-multipart XHR file uploads.
45
+ // window.XMLHttpRequestUpload is not available on IE10, so we check for
46
+ // window.ProgressEvent instead to detect XHR2 file upload capability:
47
+ $.support.xhrFileUpload = !!(window.ProgressEvent && window.FileReader);
48
+ $.support.xhrFormDataFileUpload = !!window.FormData;
49
+
50
+ // Detect support for Blob slicing (required for chunked uploads):
51
+ $.support.blobSlice = window.Blob && (Blob.prototype.slice ||
52
+ Blob.prototype.webkitSlice || Blob.prototype.mozSlice);
53
+
54
+ // The fileupload widget listens for change events on file input fields defined
55
+ // via fileInput setting and paste or drop events of the given dropZone.
56
+ // In addition to the default jQuery Widget methods, the fileupload widget
57
+ // exposes the "add" and "send" methods, to add or directly send files using
58
+ // the fileupload API.
59
+ // By default, files added via file input selection, paste, drag & drop or
60
+ // "add" method are uploaded immediately, but it is possible to override
61
+ // the "add" callback option to queue file uploads.
62
+ $.widget('blueimp.fileupload', {
63
+
64
+ options: {
65
+ // The drop target element(s), by the default the complete document.
66
+ // Set to null to disable drag & drop support:
67
+ dropZone: $(document),
68
+ // The paste target element(s), by the default the complete document.
69
+ // Set to null to disable paste support:
70
+ pasteZone: $(document),
71
+ // The file input field(s), that are listened to for change events.
72
+ // If undefined, it is set to the file input fields inside
73
+ // of the widget element on plugin initialization.
74
+ // Set to null to disable the change listener.
75
+ fileInput: undefined,
76
+ // By default, the file input field is replaced with a clone after
77
+ // each input field change event. This is required for iframe transport
78
+ // queues and allows change events to be fired for the same file
79
+ // selection, but can be disabled by setting the following option to false:
80
+ replaceFileInput: true,
81
+ // The parameter name for the file form data (the request argument name).
82
+ // If undefined or empty, the name property of the file input field is
83
+ // used, or "files[]" if the file input name property is also empty,
84
+ // can be a string or an array of strings:
85
+ paramName: undefined,
86
+ // By default, each file of a selection is uploaded using an individual
87
+ // request for XHR type uploads. Set to false to upload file
88
+ // selections in one request each:
89
+ singleFileUploads: true,
90
+ // To limit the number of files uploaded with one XHR request,
91
+ // set the following option to an integer greater than 0:
92
+ limitMultiFileUploads: undefined,
93
+ // The following option limits the number of files uploaded with one
94
+ // XHR request to keep the request size under or equal to the defined
95
+ // limit in bytes:
96
+ limitMultiFileUploadSize: undefined,
97
+ // Multipart file uploads add a number of bytes to each uploaded file,
98
+ // therefore the following option adds an overhead for each file used
99
+ // in the limitMultiFileUploadSize configuration:
100
+ limitMultiFileUploadSizeOverhead: 512,
101
+ // Set the following option to true to issue all file upload requests
102
+ // in a sequential order:
103
+ sequentialUploads: false,
104
+ // To limit the number of concurrent uploads,
105
+ // set the following option to an integer greater than 0:
106
+ limitConcurrentUploads: undefined,
107
+ // Set the following option to true to force iframe transport uploads:
108
+ forceIframeTransport: false,
109
+ // Set the following option to the location of a redirect url on the
110
+ // origin server, for cross-domain iframe transport uploads:
111
+ redirect: undefined,
112
+ // The parameter name for the redirect url, sent as part of the form
113
+ // data and set to 'redirect' if this option is empty:
114
+ redirectParamName: undefined,
115
+ // Set the following option to the location of a postMessage window,
116
+ // to enable postMessage transport uploads:
117
+ postMessage: undefined,
118
+ // By default, XHR file uploads are sent as multipart/form-data.
119
+ // The iframe transport is always using multipart/form-data.
120
+ // Set to false to enable non-multipart XHR uploads:
121
+ multipart: true,
122
+ // To upload large files in smaller chunks, set the following option
123
+ // to a preferred maximum chunk size. If set to 0, null or undefined,
124
+ // or the browser does not support the required Blob API, files will
125
+ // be uploaded as a whole.
126
+ maxChunkSize: undefined,
127
+ // When a non-multipart upload or a chunked multipart upload has been
128
+ // aborted, this option can be used to resume the upload by setting
129
+ // it to the size of the already uploaded bytes. This option is most
130
+ // useful when modifying the options object inside of the "add" or
131
+ // "send" callbacks, as the options are cloned for each file upload.
132
+ uploadedBytes: undefined,
133
+ // By default, failed (abort or error) file uploads are removed from the
134
+ // global progress calculation. Set the following option to false to
135
+ // prevent recalculating the global progress data:
136
+ recalculateProgress: true,
137
+ // Interval in milliseconds to calculate and trigger progress events:
138
+ progressInterval: 100,
139
+ // Interval in milliseconds to calculate progress bitrate:
140
+ bitrateInterval: 500,
141
+ // By default, uploads are started automatically when adding files:
142
+ autoUpload: true,
143
+
144
+ // Error and info messages:
145
+ messages: {
146
+ uploadedBytes: 'Uploaded bytes exceed file size'
147
+ },
148
+
149
+ // Translation function, gets the message key to be translated
150
+ // and an object with context specific data as arguments:
151
+ i18n: function (message, context) {
152
+ message = this.messages[message] || message.toString();
153
+ if (context) {
154
+ $.each(context, function (key, value) {
155
+ message = message.replace('{' + key + '}', value);
156
+ });
157
+ }
158
+ return message;
159
+ },
160
+
161
+ // Additional form data to be sent along with the file uploads can be set
162
+ // using this option, which accepts an array of objects with name and
163
+ // value properties, a function returning such an array, a FormData
164
+ // object (for XHR file uploads), or a simple object.
165
+ // The form of the first fileInput is given as parameter to the function:
166
+ formData: function (form) {
167
+ return form.serializeArray();
168
+ },
169
+
170
+ // The add callback is invoked as soon as files are added to the fileupload
171
+ // widget (via file input selection, drag & drop, paste or add API call).
172
+ // If the singleFileUploads option is enabled, this callback will be
173
+ // called once for each file in the selection for XHR file uploads, else
174
+ // once for each file selection.
175
+ //
176
+ // The upload starts when the submit method is invoked on the data parameter.
177
+ // The data object contains a files property holding the added files
178
+ // and allows you to override plugin options as well as define ajax settings.
179
+ //
180
+ // Listeners for this callback can also be bound the following way:
181
+ // .bind('fileuploadadd', func);
182
+ //
183
+ // data.submit() returns a Promise object and allows to attach additional
184
+ // handlers using jQuery's Deferred callbacks:
185
+ // data.submit().done(func).fail(func).always(func);
186
+ add: function (e, data) {
187
+ if (e.isDefaultPrevented()) {
188
+ return false;
189
+ }
190
+ if (data.autoUpload || (data.autoUpload !== false &&
191
+ $(this).fileupload('option', 'autoUpload'))) {
192
+ data.process().done(function () {
193
+ data.submit();
194
+ });
195
+ }
196
+ },
197
+
198
+ // Other callbacks:
199
+
200
+ // Callback for the submit event of each file upload:
201
+ // submit: function (e, data) {}, // .bind('fileuploadsubmit', func);
202
+
203
+ // Callback for the start of each file upload request:
204
+ // send: function (e, data) {}, // .bind('fileuploadsend', func);
205
+
206
+ // Callback for successful uploads:
207
+ // done: function (e, data) {}, // .bind('fileuploaddone', func);
208
+
209
+ // Callback for failed (abort or error) uploads:
210
+ // fail: function (e, data) {}, // .bind('fileuploadfail', func);
211
+
212
+ // Callback for completed (success, abort or error) requests:
213
+ // always: function (e, data) {}, // .bind('fileuploadalways', func);
214
+
215
+ // Callback for upload progress events:
216
+ // progress: function (e, data) {}, // .bind('fileuploadprogress', func);
217
+
218
+ // Callback for global upload progress events:
219
+ // progressall: function (e, data) {}, // .bind('fileuploadprogressall', func);
220
+
221
+ // Callback for uploads start, equivalent to the global ajaxStart event:
222
+ // start: function (e) {}, // .bind('fileuploadstart', func);
223
+
224
+ // Callback for uploads stop, equivalent to the global ajaxStop event:
225
+ // stop: function (e) {}, // .bind('fileuploadstop', func);
226
+
227
+ // Callback for change events of the fileInput(s):
228
+ // change: function (e, data) {}, // .bind('fileuploadchange', func);
229
+
230
+ // Callback for paste events to the pasteZone(s):
231
+ // paste: function (e, data) {}, // .bind('fileuploadpaste', func);
232
+
233
+ // Callback for drop events of the dropZone(s):
234
+ // drop: function (e, data) {}, // .bind('fileuploaddrop', func);
235
+
236
+ // Callback for dragover events of the dropZone(s):
237
+ // dragover: function (e) {}, // .bind('fileuploaddragover', func);
238
+
239
+ // Callback for the start of each chunk upload request:
240
+ // chunksend: function (e, data) {}, // .bind('fileuploadchunksend', func);
241
+
242
+ // Callback for successful chunk uploads:
243
+ // chunkdone: function (e, data) {}, // .bind('fileuploadchunkdone', func);
244
+
245
+ // Callback for failed (abort or error) chunk uploads:
246
+ // chunkfail: function (e, data) {}, // .bind('fileuploadchunkfail', func);
247
+
248
+ // Callback for completed (success, abort or error) chunk upload requests:
249
+ // chunkalways: function (e, data) {}, // .bind('fileuploadchunkalways', func);
250
+
251
+ // The plugin options are used as settings object for the ajax calls.
252
+ // The following are jQuery ajax settings required for the file uploads:
253
+ processData: false,
254
+ contentType: false,
255
+ cache: false
256
+ },
257
+
258
+ // A list of options that require reinitializing event listeners and/or
259
+ // special initialization code:
260
+ _specialOptions: [
261
+ 'fileInput',
262
+ 'dropZone',
263
+ 'pasteZone',
264
+ 'multipart',
265
+ 'forceIframeTransport'
266
+ ],
267
+
268
+ _blobSlice: $.support.blobSlice && function () {
269
+ var slice = this.slice || this.webkitSlice || this.mozSlice;
270
+ return slice.apply(this, arguments);
271
+ },
272
+
273
+ _BitrateTimer: function () {
274
+ this.timestamp = ((Date.now) ? Date.now() : (new Date()).getTime());
275
+ this.loaded = 0;
276
+ this.bitrate = 0;
277
+ this.getBitrate = function (now, loaded, interval) {
278
+ var timeDiff = now - this.timestamp;
279
+ if (!this.bitrate || !interval || timeDiff > interval) {
280
+ this.bitrate = (loaded - this.loaded) * (1000 / timeDiff) * 8;
281
+ this.loaded = loaded;
282
+ this.timestamp = now;
283
+ }
284
+ return this.bitrate;
285
+ };
286
+ },
287
+
288
+ _isXHRUpload: function (options) {
289
+ return !options.forceIframeTransport &&
290
+ ((!options.multipart && $.support.xhrFileUpload) ||
291
+ $.support.xhrFormDataFileUpload);
292
+ },
293
+
294
+ _getFormData: function (options) {
295
+ var formData;
296
+ if ($.type(options.formData) === 'function') {
297
+ return options.formData(options.form);
298
+ }
299
+ if ($.isArray(options.formData)) {
300
+ return options.formData;
301
+ }
302
+ if ($.type(options.formData) === 'object') {
303
+ formData = [];
304
+ $.each(options.formData, function (name, value) {
305
+ formData.push({name: name, value: value});
306
+ });
307
+ return formData;
308
+ }
309
+ return [];
310
+ },
311
+
312
+ _getTotal: function (files) {
313
+ var total = 0;
314
+ $.each(files, function (index, file) {
315
+ total += file.size || 1;
316
+ });
317
+ return total;
318
+ },
319
+
320
+ _initProgressObject: function (obj) {
321
+ var progress = {
322
+ loaded: 0,
323
+ total: 0,
324
+ bitrate: 0
325
+ };
326
+ if (obj._progress) {
327
+ $.extend(obj._progress, progress);
328
+ } else {
329
+ obj._progress = progress;
330
+ }
331
+ },
332
+
333
+ _initResponseObject: function (obj) {
334
+ var prop;
335
+ if (obj._response) {
336
+ for (prop in obj._response) {
337
+ if (obj._response.hasOwnProperty(prop)) {
338
+ delete obj._response[prop];
339
+ }
340
+ }
341
+ } else {
342
+ obj._response = {};
343
+ }
344
+ },
345
+
346
+ _onProgress: function (e, data) {
347
+ if (e.lengthComputable) {
348
+ var now = ((Date.now) ? Date.now() : (new Date()).getTime()),
349
+ loaded;
350
+ if (data._time && data.progressInterval &&
351
+ (now - data._time < data.progressInterval) &&
352
+ e.loaded !== e.total) {
353
+ return;
354
+ }
355
+ data._time = now;
356
+ loaded = Math.floor(
357
+ e.loaded / e.total * (data.chunkSize || data._progress.total)
358
+ ) + (data.uploadedBytes || 0);
359
+ // Add the difference from the previously loaded state
360
+ // to the global loaded counter:
361
+ this._progress.loaded += (loaded - data._progress.loaded);
362
+ this._progress.bitrate = this._bitrateTimer.getBitrate(
363
+ now,
364
+ this._progress.loaded,
365
+ data.bitrateInterval
366
+ );
367
+ data._progress.loaded = data.loaded = loaded;
368
+ data._progress.bitrate = data.bitrate = data._bitrateTimer.getBitrate(
369
+ now,
370
+ loaded,
371
+ data.bitrateInterval
372
+ );
373
+ // Trigger a custom progress event with a total data property set
374
+ // to the file size(s) of the current upload and a loaded data
375
+ // property calculated accordingly:
376
+ this._trigger(
377
+ 'progress',
378
+ $.Event('progress', {delegatedEvent: e}),
379
+ data
380
+ );
381
+ // Trigger a global progress event for all current file uploads,
382
+ // including ajax calls queued for sequential file uploads:
383
+ this._trigger(
384
+ 'progressall',
385
+ $.Event('progressall', {delegatedEvent: e}),
386
+ this._progress
387
+ );
388
+ }
389
+ },
390
+
391
+ _initProgressListener: function (options) {
392
+ var that = this,
393
+ xhr = options.xhr ? options.xhr() : $.ajaxSettings.xhr();
394
+ // Accesss to the native XHR object is required to add event listeners
395
+ // for the upload progress event:
396
+ if (xhr.upload) {
397
+ $(xhr.upload).bind('progress', function (e) {
398
+ var oe = e.originalEvent;
399
+ // Make sure the progress event properties get copied over:
400
+ e.lengthComputable = oe.lengthComputable;
401
+ e.loaded = oe.loaded;
402
+ e.total = oe.total;
403
+ that._onProgress(e, options);
404
+ });
405
+ options.xhr = function () {
406
+ return xhr;
407
+ };
408
+ }
409
+ },
410
+
411
+ _isInstanceOf: function (type, obj) {
412
+ // Cross-frame instanceof check
413
+ return Object.prototype.toString.call(obj) === '[object ' + type + ']';
414
+ },
415
+
416
+ _initXHRData: function (options) {
417
+ var that = this,
418
+ formData,
419
+ file = options.files[0],
420
+ // Ignore non-multipart setting if not supported:
421
+ multipart = options.multipart || !$.support.xhrFileUpload,
422
+ paramName = $.type(options.paramName) === 'array' ?
423
+ options.paramName[0] : options.paramName;
424
+ options.headers = $.extend({}, options.headers);
425
+ if (options.contentRange) {
426
+ options.headers['Content-Range'] = options.contentRange;
427
+ }
428
+ if (!multipart || options.blob || !this._isInstanceOf('File', file)) {
429
+ options.headers['Content-Disposition'] = 'attachment; filename="' +
430
+ encodeURI(file.name) + '"';
431
+ }
432
+ if (!multipart) {
433
+ options.contentType = file.type || 'application/octet-stream';
434
+ options.data = options.blob || file;
435
+ } else if ($.support.xhrFormDataFileUpload) {
436
+ if (options.postMessage) {
437
+ // window.postMessage does not allow sending FormData
438
+ // objects, so we just add the File/Blob objects to
439
+ // the formData array and let the postMessage window
440
+ // create the FormData object out of this array:
441
+ formData = this._getFormData(options);
442
+ if (options.blob) {
443
+ formData.push({
444
+ name: paramName,
445
+ value: options.blob
446
+ });
447
+ } else {
448
+ $.each(options.files, function (index, file) {
449
+ formData.push({
450
+ name: ($.type(options.paramName) === 'array' &&
451
+ options.paramName[index]) || paramName,
452
+ value: file
453
+ });
454
+ });
455
+ }
456
+ } else {
457
+ if (that._isInstanceOf('FormData', options.formData)) {
458
+ formData = options.formData;
459
+ } else {
460
+ formData = new FormData();
461
+ $.each(this._getFormData(options), function (index, field) {
462
+ formData.append(field.name, field.value);
463
+ });
464
+ }
465
+ if (options.blob) {
466
+ formData.append(paramName, options.blob, file.name);
467
+ } else {
468
+ $.each(options.files, function (index, file) {
469
+ // This check allows the tests to run with
470
+ // dummy objects:
471
+ if (that._isInstanceOf('File', file) ||
472
+ that._isInstanceOf('Blob', file)) {
473
+ formData.append(
474
+ ($.type(options.paramName) === 'array' &&
475
+ options.paramName[index]) || paramName,
476
+ file,
477
+ file.uploadName || file.name
478
+ );
479
+ }
480
+ });
481
+ }
482
+ }
483
+ options.data = formData;
484
+ }
485
+ // Blob reference is not needed anymore, free memory:
486
+ options.blob = null;
487
+ },
488
+
489
+ _initIframeSettings: function (options) {
490
+ var targetHost = $('<a></a>').prop('href', options.url).prop('host');
491
+ // Setting the dataType to iframe enables the iframe transport:
492
+ options.dataType = 'iframe ' + (options.dataType || '');
493
+ // The iframe transport accepts a serialized array as form data:
494
+ options.formData = this._getFormData(options);
495
+ // Add redirect url to form data on cross-domain uploads:
496
+ if (options.redirect && targetHost && targetHost !== location.host) {
497
+ options.formData.push({
498
+ name: options.redirectParamName || 'redirect',
499
+ value: options.redirect
500
+ });
501
+ }
502
+ },
503
+
504
+ _initDataSettings: function (options) {
505
+ if (this._isXHRUpload(options)) {
506
+ if (!this._chunkedUpload(options, true)) {
507
+ if (!options.data) {
508
+ this._initXHRData(options);
509
+ }
510
+ this._initProgressListener(options);
511
+ }
512
+ if (options.postMessage) {
513
+ // Setting the dataType to postmessage enables the
514
+ // postMessage transport:
515
+ options.dataType = 'postmessage ' + (options.dataType || '');
516
+ }
517
+ } else {
518
+ this._initIframeSettings(options);
519
+ }
520
+ },
521
+
522
+ _getParamName: function (options) {
523
+ var fileInput = $(options.fileInput),
524
+ paramName = options.paramName;
525
+ if (!paramName) {
526
+ paramName = [];
527
+ fileInput.each(function () {
528
+ var input = $(this),
529
+ name = input.prop('name') || 'files[]',
530
+ i = (input.prop('files') || [1]).length;
531
+ while (i) {
532
+ paramName.push(name);
533
+ i -= 1;
534
+ }
535
+ });
536
+ if (!paramName.length) {
537
+ paramName = [fileInput.prop('name') || 'files[]'];
538
+ }
539
+ } else if (!$.isArray(paramName)) {
540
+ paramName = [paramName];
541
+ }
542
+ return paramName;
543
+ },
544
+
545
+ _initFormSettings: function (options) {
546
+ // Retrieve missing options from the input field and the
547
+ // associated form, if available:
548
+ if (!options.form || !options.form.length) {
549
+ options.form = $(options.fileInput.prop('form'));
550
+ // If the given file input doesn't have an associated form,
551
+ // use the default widget file input's form:
552
+ if (!options.form.length) {
553
+ options.form = $(this.options.fileInput.prop('form'));
554
+ }
555
+ }
556
+ options.paramName = this._getParamName(options);
557
+ if (!options.url) {
558
+ options.url = options.form.prop('action') || location.href;
559
+ }
560
+ // The HTTP request method must be "POST" or "PUT":
561
+ options.type = (options.type ||
562
+ ($.type(options.form.prop('method')) === 'string' &&
563
+ options.form.prop('method')) || ''
564
+ ).toUpperCase();
565
+ if (options.type !== 'POST' && options.type !== 'PUT' &&
566
+ options.type !== 'PATCH') {
567
+ options.type = 'POST';
568
+ }
569
+ if (!options.formAcceptCharset) {
570
+ options.formAcceptCharset = options.form.attr('accept-charset');
571
+ }
572
+ },
573
+
574
+ _getAJAXSettings: function (data) {
575
+ var options = $.extend({}, this.options, data);
576
+ this._initFormSettings(options);
577
+ this._initDataSettings(options);
578
+ return options;
579
+ },
580
+
581
+ // jQuery 1.6 doesn't provide .state(),
582
+ // while jQuery 1.8+ removed .isRejected() and .isResolved():
583
+ _getDeferredState: function (deferred) {
584
+ if (deferred.state) {
585
+ return deferred.state();
586
+ }
587
+ if (deferred.isResolved()) {
588
+ return 'resolved';
589
+ }
590
+ if (deferred.isRejected()) {
591
+ return 'rejected';
592
+ }
593
+ return 'pending';
594
+ },
595
+
596
+ // Maps jqXHR callbacks to the equivalent
597
+ // methods of the given Promise object:
598
+ _enhancePromise: function (promise) {
599
+ promise.success = promise.done;
600
+ promise.error = promise.fail;
601
+ promise.complete = promise.always;
602
+ return promise;
603
+ },
604
+
605
+ // Creates and returns a Promise object enhanced with
606
+ // the jqXHR methods abort, success, error and complete:
607
+ _getXHRPromise: function (resolveOrReject, context, args) {
608
+ var dfd = $.Deferred(),
609
+ promise = dfd.promise();
610
+ context = context || this.options.context || promise;
611
+ if (resolveOrReject === true) {
612
+ dfd.resolveWith(context, args);
613
+ } else if (resolveOrReject === false) {
614
+ dfd.rejectWith(context, args);
615
+ }
616
+ promise.abort = dfd.promise;
617
+ return this._enhancePromise(promise);
618
+ },
619
+
620
+ // Adds convenience methods to the data callback argument:
621
+ _addConvenienceMethods: function (e, data) {
622
+ var that = this,
623
+ getPromise = function (args) {
624
+ return $.Deferred().resolveWith(that, args).promise();
625
+ };
626
+ data.process = function (resolveFunc, rejectFunc) {
627
+ if (resolveFunc || rejectFunc) {
628
+ data._processQueue = this._processQueue =
629
+ (this._processQueue || getPromise([this])).pipe(
630
+ function () {
631
+ if (data.errorThrown) {
632
+ return $.Deferred()
633
+ .rejectWith(that, [data]).promise();
634
+ }
635
+ return getPromise(arguments);
636
+ }
637
+ ).pipe(resolveFunc, rejectFunc);
638
+ }
639
+ return this._processQueue || getPromise([this]);
640
+ };
641
+ data.submit = function () {
642
+ if (this.state() !== 'pending') {
643
+ data.jqXHR = this.jqXHR =
644
+ (that._trigger(
645
+ 'submit',
646
+ $.Event('submit', {delegatedEvent: e}),
647
+ this
648
+ ) !== false) && that._onSend(e, this);
649
+ }
650
+ return this.jqXHR || that._getXHRPromise();
651
+ };
652
+ data.abort = function () {
653
+ if (this.jqXHR) {
654
+ return this.jqXHR.abort();
655
+ }
656
+ this.errorThrown = 'abort';
657
+ that._trigger('fail', null, this);
658
+ return that._getXHRPromise(false);
659
+ };
660
+ data.state = function () {
661
+ if (this.jqXHR) {
662
+ return that._getDeferredState(this.jqXHR);
663
+ }
664
+ if (this._processQueue) {
665
+ return that._getDeferredState(this._processQueue);
666
+ }
667
+ };
668
+ data.processing = function () {
669
+ return !this.jqXHR && this._processQueue && that
670
+ ._getDeferredState(this._processQueue) === 'pending';
671
+ };
672
+ data.progress = function () {
673
+ return this._progress;
674
+ };
675
+ data.response = function () {
676
+ return this._response;
677
+ };
678
+ },
679
+
680
+ // Parses the Range header from the server response
681
+ // and returns the uploaded bytes:
682
+ _getUploadedBytes: function (jqXHR) {
683
+ var range = jqXHR.getResponseHeader('Range'),
684
+ parts = range && range.split('-'),
685
+ upperBytesPos = parts && parts.length > 1 &&
686
+ parseInt(parts[1], 10);
687
+ return upperBytesPos && upperBytesPos + 1;
688
+ },
689
+
690
+ // Uploads a file in multiple, sequential requests
691
+ // by splitting the file up in multiple blob chunks.
692
+ // If the second parameter is true, only tests if the file
693
+ // should be uploaded in chunks, but does not invoke any
694
+ // upload requests:
695
+ _chunkedUpload: function (options, testOnly) {
696
+ options.uploadedBytes = options.uploadedBytes || 0;
697
+ var that = this,
698
+ file = options.files[0],
699
+ fs = file.size,
700
+ ub = options.uploadedBytes,
701
+ mcs = options.maxChunkSize || fs,
702
+ slice = this._blobSlice,
703
+ dfd = $.Deferred(),
704
+ promise = dfd.promise(),
705
+ jqXHR,
706
+ upload;
707
+ if (!(this._isXHRUpload(options) && slice && (ub || mcs < fs)) ||
708
+ options.data) {
709
+ return false;
710
+ }
711
+ if (testOnly) {
712
+ return true;
713
+ }
714
+ if (ub >= fs) {
715
+ file.error = options.i18n('uploadedBytes');
716
+ return this._getXHRPromise(
717
+ false,
718
+ options.context,
719
+ [null, 'error', file.error]
720
+ );
721
+ }
722
+ // The chunk upload method:
723
+ upload = function () {
724
+ // Clone the options object for each chunk upload:
725
+ var o = $.extend({}, options),
726
+ currentLoaded = o._progress.loaded;
727
+ o.blob = slice.call(
728
+ file,
729
+ ub,
730
+ ub + mcs,
731
+ file.type
732
+ );
733
+ // Store the current chunk size, as the blob itself
734
+ // will be dereferenced after data processing:
735
+ o.chunkSize = o.blob.size;
736
+ // Expose the chunk bytes position range:
737
+ o.contentRange = 'bytes ' + ub + '-' +
738
+ (ub + o.chunkSize - 1) + '/' + fs;
739
+ // Process the upload data (the blob and potential form data):
740
+ that._initXHRData(o);
741
+ // Add progress listeners for this chunk upload:
742
+ that._initProgressListener(o);
743
+ jqXHR = ((that._trigger('chunksend', null, o) !== false && $.ajax(o)) ||
744
+ that._getXHRPromise(false, o.context))
745
+ .done(function (result, textStatus, jqXHR) {
746
+ ub = that._getUploadedBytes(jqXHR) ||
747
+ (ub + o.chunkSize);
748
+ // Create a progress event if no final progress event
749
+ // with loaded equaling total has been triggered
750
+ // for this chunk:
751
+ if (currentLoaded + o.chunkSize - o._progress.loaded) {
752
+ that._onProgress($.Event('progress', {
753
+ lengthComputable: true,
754
+ loaded: ub - o.uploadedBytes,
755
+ total: ub - o.uploadedBytes
756
+ }), o);
757
+ }
758
+ options.uploadedBytes = o.uploadedBytes = ub;
759
+ o.result = result;
760
+ o.textStatus = textStatus;
761
+ o.jqXHR = jqXHR;
762
+ that._trigger('chunkdone', null, o);
763
+ that._trigger('chunkalways', null, o);
764
+ if (ub < fs) {
765
+ // File upload not yet complete,
766
+ // continue with the next chunk:
767
+ upload();
768
+ } else {
769
+ dfd.resolveWith(
770
+ o.context,
771
+ [result, textStatus, jqXHR]
772
+ );
773
+ }
774
+ })
775
+ .fail(function (jqXHR, textStatus, errorThrown) {
776
+ o.jqXHR = jqXHR;
777
+ o.textStatus = textStatus;
778
+ o.errorThrown = errorThrown;
779
+ that._trigger('chunkfail', null, o);
780
+ that._trigger('chunkalways', null, o);
781
+ dfd.rejectWith(
782
+ o.context,
783
+ [jqXHR, textStatus, errorThrown]
784
+ );
785
+ });
786
+ };
787
+ this._enhancePromise(promise);
788
+ promise.abort = function () {
789
+ return jqXHR.abort();
790
+ };
791
+ upload();
792
+ return promise;
793
+ },
794
+
795
+ _beforeSend: function (e, data) {
796
+ if (this._active === 0) {
797
+ // the start callback is triggered when an upload starts
798
+ // and no other uploads are currently running,
799
+ // equivalent to the global ajaxStart event:
800
+ this._trigger('start');
801
+ // Set timer for global bitrate progress calculation:
802
+ this._bitrateTimer = new this._BitrateTimer();
803
+ // Reset the global progress values:
804
+ this._progress.loaded = this._progress.total = 0;
805
+ this._progress.bitrate = 0;
806
+ }
807
+ // Make sure the container objects for the .response() and
808
+ // .progress() methods on the data object are available
809
+ // and reset to their initial state:
810
+ this._initResponseObject(data);
811
+ this._initProgressObject(data);
812
+ data._progress.loaded = data.loaded = data.uploadedBytes || 0;
813
+ data._progress.total = data.total = this._getTotal(data.files) || 1;
814
+ data._progress.bitrate = data.bitrate = 0;
815
+ this._active += 1;
816
+ // Initialize the global progress values:
817
+ this._progress.loaded += data.loaded;
818
+ this._progress.total += data.total;
819
+ },
820
+
821
+ _onDone: function (result, textStatus, jqXHR, options) {
822
+ var total = options._progress.total,
823
+ response = options._response;
824
+ if (options._progress.loaded < total) {
825
+ // Create a progress event if no final progress event
826
+ // with loaded equaling total has been triggered:
827
+ this._onProgress($.Event('progress', {
828
+ lengthComputable: true,
829
+ loaded: total,
830
+ total: total
831
+ }), options);
832
+ }
833
+ response.result = options.result = result;
834
+ response.textStatus = options.textStatus = textStatus;
835
+ response.jqXHR = options.jqXHR = jqXHR;
836
+ this._trigger('done', null, options);
837
+ },
838
+
839
+ _onFail: function (jqXHR, textStatus, errorThrown, options) {
840
+ var response = options._response;
841
+ if (options.recalculateProgress) {
842
+ // Remove the failed (error or abort) file upload from
843
+ // the global progress calculation:
844
+ this._progress.loaded -= options._progress.loaded;
845
+ this._progress.total -= options._progress.total;
846
+ }
847
+ response.jqXHR = options.jqXHR = jqXHR;
848
+ response.textStatus = options.textStatus = textStatus;
849
+ response.errorThrown = options.errorThrown = errorThrown;
850
+ this._trigger('fail', null, options);
851
+ },
852
+
853
+ _onAlways: function (jqXHRorResult, textStatus, jqXHRorError, options) {
854
+ // jqXHRorResult, textStatus and jqXHRorError are added to the
855
+ // options object via done and fail callbacks
856
+ this._trigger('always', null, options);
857
+ },
858
+
859
+ _onSend: function (e, data) {
860
+ if (!data.submit) {
861
+ this._addConvenienceMethods(e, data);
862
+ }
863
+ var that = this,
864
+ jqXHR,
865
+ aborted,
866
+ slot,
867
+ pipe,
868
+ options = that._getAJAXSettings(data),
869
+ send = function () {
870
+ that._sending += 1;
871
+ // Set timer for bitrate progress calculation:
872
+ options._bitrateTimer = new that._BitrateTimer();
873
+ jqXHR = jqXHR || (
874
+ ((aborted || that._trigger(
875
+ 'send',
876
+ $.Event('send', {delegatedEvent: e}),
877
+ options
878
+ ) === false) &&
879
+ that._getXHRPromise(false, options.context, aborted)) ||
880
+ that._chunkedUpload(options) || $.ajax(options)
881
+ ).done(function (result, textStatus, jqXHR) {
882
+ that._onDone(result, textStatus, jqXHR, options);
883
+ }).fail(function (jqXHR, textStatus, errorThrown) {
884
+ that._onFail(jqXHR, textStatus, errorThrown, options);
885
+ }).always(function (jqXHRorResult, textStatus, jqXHRorError) {
886
+ that._onAlways(
887
+ jqXHRorResult,
888
+ textStatus,
889
+ jqXHRorError,
890
+ options
891
+ );
892
+ that._sending -= 1;
893
+ that._active -= 1;
894
+ if (options.limitConcurrentUploads &&
895
+ options.limitConcurrentUploads > that._sending) {
896
+ // Start the next queued upload,
897
+ // that has not been aborted:
898
+ var nextSlot = that._slots.shift();
899
+ while (nextSlot) {
900
+ if (that._getDeferredState(nextSlot) === 'pending') {
901
+ nextSlot.resolve();
902
+ break;
903
+ }
904
+ nextSlot = that._slots.shift();
905
+ }
906
+ }
907
+ if (that._active === 0) {
908
+ // The stop callback is triggered when all uploads have
909
+ // been completed, equivalent to the global ajaxStop event:
910
+ that._trigger('stop');
911
+ }
912
+ });
913
+ return jqXHR;
914
+ };
915
+ this._beforeSend(e, options);
916
+ if (this.options.sequentialUploads ||
917
+ (this.options.limitConcurrentUploads &&
918
+ this.options.limitConcurrentUploads <= this._sending)) {
919
+ if (this.options.limitConcurrentUploads > 1) {
920
+ slot = $.Deferred();
921
+ this._slots.push(slot);
922
+ pipe = slot.pipe(send);
923
+ } else {
924
+ this._sequence = this._sequence.pipe(send, send);
925
+ pipe = this._sequence;
926
+ }
927
+ // Return the piped Promise object, enhanced with an abort method,
928
+ // which is delegated to the jqXHR object of the current upload,
929
+ // and jqXHR callbacks mapped to the equivalent Promise methods:
930
+ pipe.abort = function () {
931
+ aborted = [undefined, 'abort', 'abort'];
932
+ if (!jqXHR) {
933
+ if (slot) {
934
+ slot.rejectWith(options.context, aborted);
935
+ }
936
+ return send();
937
+ }
938
+ return jqXHR.abort();
939
+ };
940
+ return this._enhancePromise(pipe);
941
+ }
942
+ return send();
943
+ },
944
+
945
+ _onAdd: function (e, data) {
946
+ var that = this,
947
+ result = true,
948
+ options = $.extend({}, this.options, data),
949
+ files = data.files,
950
+ filesLength = files.length,
951
+ limit = options.limitMultiFileUploads,
952
+ limitSize = options.limitMultiFileUploadSize,
953
+ overhead = options.limitMultiFileUploadSizeOverhead,
954
+ batchSize = 0,
955
+ paramName = this._getParamName(options),
956
+ paramNameSet,
957
+ paramNameSlice,
958
+ fileSet,
959
+ i,
960
+ j = 0;
961
+ if (limitSize && (!filesLength || files[0].size === undefined)) {
962
+ limitSize = undefined;
963
+ }
964
+ if (!(options.singleFileUploads || limit || limitSize) ||
965
+ !this._isXHRUpload(options)) {
966
+ fileSet = [files];
967
+ paramNameSet = [paramName];
968
+ } else if (!(options.singleFileUploads || limitSize) && limit) {
969
+ fileSet = [];
970
+ paramNameSet = [];
971
+ for (i = 0; i < filesLength; i += limit) {
972
+ fileSet.push(files.slice(i, i + limit));
973
+ paramNameSlice = paramName.slice(i, i + limit);
974
+ if (!paramNameSlice.length) {
975
+ paramNameSlice = paramName;
976
+ }
977
+ paramNameSet.push(paramNameSlice);
978
+ }
979
+ } else if (!options.singleFileUploads && limitSize) {
980
+ fileSet = [];
981
+ paramNameSet = [];
982
+ for (i = 0; i < filesLength; i = i + 1) {
983
+ batchSize += files[i].size + overhead;
984
+ if (i + 1 === filesLength ||
985
+ ((batchSize + files[i + 1].size + overhead) > limitSize) ||
986
+ (limit && i + 1 - j >= limit)) {
987
+ fileSet.push(files.slice(j, i + 1));
988
+ paramNameSlice = paramName.slice(j, i + 1);
989
+ if (!paramNameSlice.length) {
990
+ paramNameSlice = paramName;
991
+ }
992
+ paramNameSet.push(paramNameSlice);
993
+ j = i + 1;
994
+ batchSize = 0;
995
+ }
996
+ }
997
+ } else {
998
+ paramNameSet = paramName;
999
+ }
1000
+ data.originalFiles = files;
1001
+ $.each(fileSet || files, function (index, element) {
1002
+ var newData = $.extend({}, data);
1003
+ newData.files = fileSet ? element : [element];
1004
+ newData.paramName = paramNameSet[index];
1005
+ that._initResponseObject(newData);
1006
+ that._initProgressObject(newData);
1007
+ that._addConvenienceMethods(e, newData);
1008
+ result = that._trigger(
1009
+ 'add',
1010
+ $.Event('add', {delegatedEvent: e}),
1011
+ newData
1012
+ );
1013
+ return result;
1014
+ });
1015
+ return result;
1016
+ },
1017
+
1018
+ _replaceFileInput: function (input) {
1019
+ var inputClone = input.clone(true);
1020
+ $('<form></form>').append(inputClone)[0].reset();
1021
+ // Detaching allows to insert the fileInput on another form
1022
+ // without loosing the file input value:
1023
+ input.after(inputClone).detach();
1024
+ // Avoid memory leaks with the detached file input:
1025
+ $.cleanData(input.unbind('remove'));
1026
+ // Replace the original file input element in the fileInput
1027
+ // elements set with the clone, which has been copied including
1028
+ // event handlers:
1029
+ this.options.fileInput = this.options.fileInput.map(function (i, el) {
1030
+ if (el === input[0]) {
1031
+ return inputClone[0];
1032
+ }
1033
+ return el;
1034
+ });
1035
+ // If the widget has been initialized on the file input itself,
1036
+ // override this.element with the file input clone:
1037
+ if (input[0] === this.element[0]) {
1038
+ this.element = inputClone;
1039
+ }
1040
+ },
1041
+
1042
+ _handleFileTreeEntry: function (entry, path) {
1043
+ var that = this,
1044
+ dfd = $.Deferred(),
1045
+ errorHandler = function (e) {
1046
+ if (e && !e.entry) {
1047
+ e.entry = entry;
1048
+ }
1049
+ // Since $.when returns immediately if one
1050
+ // Deferred is rejected, we use resolve instead.
1051
+ // This allows valid files and invalid items
1052
+ // to be returned together in one set:
1053
+ dfd.resolve([e]);
1054
+ },
1055
+ dirReader;
1056
+ path = path || '';
1057
+ if (entry.isFile) {
1058
+ if (entry._file) {
1059
+ // Workaround for Chrome bug #149735
1060
+ entry._file.relativePath = path;
1061
+ dfd.resolve(entry._file);
1062
+ } else {
1063
+ entry.file(function (file) {
1064
+ file.relativePath = path;
1065
+ dfd.resolve(file);
1066
+ }, errorHandler);
1067
+ }
1068
+ } else if (entry.isDirectory) {
1069
+ dirReader = entry.createReader();
1070
+ dirReader.readEntries(function (entries) {
1071
+ that._handleFileTreeEntries(
1072
+ entries,
1073
+ path + entry.name + '/'
1074
+ ).done(function (files) {
1075
+ dfd.resolve(files);
1076
+ }).fail(errorHandler);
1077
+ }, errorHandler);
1078
+ } else {
1079
+ // Return an empy list for file system items
1080
+ // other than files or directories:
1081
+ dfd.resolve([]);
1082
+ }
1083
+ return dfd.promise();
1084
+ },
1085
+
1086
+ _handleFileTreeEntries: function (entries, path) {
1087
+ var that = this;
1088
+ return $.when.apply(
1089
+ $,
1090
+ $.map(entries, function (entry) {
1091
+ return that._handleFileTreeEntry(entry, path);
1092
+ })
1093
+ ).pipe(function () {
1094
+ return Array.prototype.concat.apply(
1095
+ [],
1096
+ arguments
1097
+ );
1098
+ });
1099
+ },
1100
+
1101
+ _getDroppedFiles: function (dataTransfer) {
1102
+ dataTransfer = dataTransfer || {};
1103
+ var items = dataTransfer.items;
1104
+ if (items && items.length && (items[0].webkitGetAsEntry ||
1105
+ items[0].getAsEntry)) {
1106
+ return this._handleFileTreeEntries(
1107
+ $.map(items, function (item) {
1108
+ var entry;
1109
+ if (item.webkitGetAsEntry) {
1110
+ entry = item.webkitGetAsEntry();
1111
+ if (entry) {
1112
+ // Workaround for Chrome bug #149735:
1113
+ entry._file = item.getAsFile();
1114
+ }
1115
+ return entry;
1116
+ }
1117
+ return item.getAsEntry();
1118
+ })
1119
+ );
1120
+ }
1121
+ return $.Deferred().resolve(
1122
+ $.makeArray(dataTransfer.files)
1123
+ ).promise();
1124
+ },
1125
+
1126
+ _getSingleFileInputFiles: function (fileInput) {
1127
+ fileInput = $(fileInput);
1128
+ var entries = fileInput.prop('webkitEntries') ||
1129
+ fileInput.prop('entries'),
1130
+ files,
1131
+ value;
1132
+ if (entries && entries.length) {
1133
+ return this._handleFileTreeEntries(entries);
1134
+ }
1135
+ files = $.makeArray(fileInput.prop('files'));
1136
+ if (!files.length) {
1137
+ value = fileInput.prop('value');
1138
+ if (!value) {
1139
+ return $.Deferred().resolve([]).promise();
1140
+ }
1141
+ // If the files property is not available, the browser does not
1142
+ // support the File API and we add a pseudo File object with
1143
+ // the input value as name with path information removed:
1144
+ files = [{name: value.replace(/^.*\\/, '')}];
1145
+ } else if (files[0].name === undefined && files[0].fileName) {
1146
+ // File normalization for Safari 4 and Firefox 3:
1147
+ $.each(files, function (index, file) {
1148
+ file.name = file.fileName;
1149
+ file.size = file.fileSize;
1150
+ });
1151
+ }
1152
+ return $.Deferred().resolve(files).promise();
1153
+ },
1154
+
1155
+ _getFileInputFiles: function (fileInput) {
1156
+ if (!(fileInput instanceof $) || fileInput.length === 1) {
1157
+ return this._getSingleFileInputFiles(fileInput);
1158
+ }
1159
+ return $.when.apply(
1160
+ $,
1161
+ $.map(fileInput, this._getSingleFileInputFiles)
1162
+ ).pipe(function () {
1163
+ return Array.prototype.concat.apply(
1164
+ [],
1165
+ arguments
1166
+ );
1167
+ });
1168
+ },
1169
+
1170
+ _onChange: function (e) {
1171
+ var that = this,
1172
+ data = {
1173
+ fileInput: $(e.target),
1174
+ form: $(e.target.form)
1175
+ };
1176
+ this._getFileInputFiles(data.fileInput).always(function (files) {
1177
+ data.files = files;
1178
+ if (that.options.replaceFileInput) {
1179
+ that._replaceFileInput(data.fileInput);
1180
+ }
1181
+ if (that._trigger(
1182
+ 'change',
1183
+ $.Event('change', {delegatedEvent: e}),
1184
+ data
1185
+ ) !== false) {
1186
+ that._onAdd(e, data);
1187
+ }
1188
+ });
1189
+ },
1190
+
1191
+ _onPaste: function (e) {
1192
+ var items = e.originalEvent && e.originalEvent.clipboardData &&
1193
+ e.originalEvent.clipboardData.items,
1194
+ data = {files: []};
1195
+ if (items && items.length) {
1196
+ $.each(items, function (index, item) {
1197
+ var file = item.getAsFile && item.getAsFile();
1198
+ if (file) {
1199
+ data.files.push(file);
1200
+ }
1201
+ });
1202
+ if (this._trigger(
1203
+ 'paste',
1204
+ $.Event('paste', {delegatedEvent: e}),
1205
+ data
1206
+ ) !== false) {
1207
+ this._onAdd(e, data);
1208
+ }
1209
+ }
1210
+ },
1211
+
1212
+ _onDrop: function (e) {
1213
+ e.dataTransfer = e.originalEvent && e.originalEvent.dataTransfer;
1214
+ var that = this,
1215
+ dataTransfer = e.dataTransfer,
1216
+ data = {};
1217
+ if (dataTransfer && dataTransfer.files && dataTransfer.files.length) {
1218
+ e.preventDefault();
1219
+ this._getDroppedFiles(dataTransfer).always(function (files) {
1220
+ data.files = files;
1221
+ if (that._trigger(
1222
+ 'drop',
1223
+ $.Event('drop', {delegatedEvent: e}),
1224
+ data
1225
+ ) !== false) {
1226
+ that._onAdd(e, data);
1227
+ }
1228
+ });
1229
+ }
1230
+ },
1231
+
1232
+ _onDragOver: function (e) {
1233
+ e.dataTransfer = e.originalEvent && e.originalEvent.dataTransfer;
1234
+ var dataTransfer = e.dataTransfer;
1235
+ if (dataTransfer && $.inArray('Files', dataTransfer.types) !== -1 &&
1236
+ this._trigger(
1237
+ 'dragover',
1238
+ $.Event('dragover', {delegatedEvent: e})
1239
+ ) !== false) {
1240
+ e.preventDefault();
1241
+ dataTransfer.dropEffect = 'copy';
1242
+ }
1243
+ },
1244
+
1245
+ _initEventHandlers: function () {
1246
+ if (this._isXHRUpload(this.options)) {
1247
+ this._on(this.options.dropZone, {
1248
+ dragover: this._onDragOver,
1249
+ drop: this._onDrop
1250
+ });
1251
+ this._on(this.options.pasteZone, {
1252
+ paste: this._onPaste
1253
+ });
1254
+ }
1255
+ if ($.support.fileInput) {
1256
+ this._on(this.options.fileInput, {
1257
+ change: this._onChange
1258
+ });
1259
+ }
1260
+ },
1261
+
1262
+ _destroyEventHandlers: function () {
1263
+ this._off(this.options.dropZone, 'dragover drop');
1264
+ this._off(this.options.pasteZone, 'paste');
1265
+ this._off(this.options.fileInput, 'change');
1266
+ },
1267
+
1268
+ _setOption: function (key, value) {
1269
+ var reinit = $.inArray(key, this._specialOptions) !== -1;
1270
+ if (reinit) {
1271
+ this._destroyEventHandlers();
1272
+ }
1273
+ this._super(key, value);
1274
+ if (reinit) {
1275
+ this._initSpecialOptions();
1276
+ this._initEventHandlers();
1277
+ }
1278
+ },
1279
+
1280
+ _initSpecialOptions: function () {
1281
+ var options = this.options;
1282
+ if (options.fileInput === undefined) {
1283
+ options.fileInput = this.element.is('input[type="file"]') ?
1284
+ this.element : this.element.find('input[type="file"]');
1285
+ } else if (!(options.fileInput instanceof $)) {
1286
+ options.fileInput = $(options.fileInput);
1287
+ }
1288
+ if (!(options.dropZone instanceof $)) {
1289
+ options.dropZone = $(options.dropZone);
1290
+ }
1291
+ if (!(options.pasteZone instanceof $)) {
1292
+ options.pasteZone = $(options.pasteZone);
1293
+ }
1294
+ },
1295
+
1296
+ _getRegExp: function (str) {
1297
+ var parts = str.split('/'),
1298
+ modifiers = parts.pop();
1299
+ parts.shift();
1300
+ return new RegExp(parts.join('/'), modifiers);
1301
+ },
1302
+
1303
+ _isRegExpOption: function (key, value) {
1304
+ return key !== 'url' && $.type(value) === 'string' &&
1305
+ /^\/.*\/[igm]{0,3}$/.test(value);
1306
+ },
1307
+
1308
+ _initDataAttributes: function () {
1309
+ var that = this,
1310
+ options = this.options,
1311
+ clone = $(this.element[0].cloneNode(false));
1312
+ // Initialize options set via HTML5 data-attributes:
1313
+ $.each(
1314
+ clone.data(),
1315
+ function (key, value) {
1316
+ var dataAttributeName = 'data-' +
1317
+ // Convert camelCase to hyphen-ated key:
1318
+ key.replace(/([a-z])([A-Z])/g, '$1-$2').toLowerCase();
1319
+ if (clone.attr(dataAttributeName)) {
1320
+ if (that._isRegExpOption(key, value)) {
1321
+ value = that._getRegExp(value);
1322
+ }
1323
+ options[key] = value;
1324
+ }
1325
+ }
1326
+ );
1327
+ },
1328
+
1329
+ _create: function () {
1330
+ this._initDataAttributes();
1331
+ this._initSpecialOptions();
1332
+ this._slots = [];
1333
+ this._sequence = this._getXHRPromise(true);
1334
+ this._sending = this._active = 0;
1335
+ this._initProgressObject(this);
1336
+ this._initEventHandlers();
1337
+ },
1338
+
1339
+ // This method is exposed to the widget API and allows to query
1340
+ // the number of active uploads:
1341
+ active: function () {
1342
+ return this._active;
1343
+ },
1344
+
1345
+ // This method is exposed to the widget API and allows to query
1346
+ // the widget upload progress.
1347
+ // It returns an object with loaded, total and bitrate properties
1348
+ // for the running uploads:
1349
+ progress: function () {
1350
+ return this._progress;
1351
+ },
1352
+
1353
+ // This method is exposed to the widget API and allows adding files
1354
+ // using the fileupload API. The data parameter accepts an object which
1355
+ // must have a files property and can contain additional options:
1356
+ // .fileupload('add', {files: filesList});
1357
+ add: function (data) {
1358
+ var that = this;
1359
+ if (!data || this.options.disabled) {
1360
+ return;
1361
+ }
1362
+ if (data.fileInput && !data.files) {
1363
+ this._getFileInputFiles(data.fileInput).always(function (files) {
1364
+ data.files = files;
1365
+ that._onAdd(null, data);
1366
+ });
1367
+ } else {
1368
+ data.files = $.makeArray(data.files);
1369
+ this._onAdd(null, data);
1370
+ }
1371
+ },
1372
+
1373
+ // This method is exposed to the widget API and allows sending files
1374
+ // using the fileupload API. The data parameter accepts an object which
1375
+ // must have a files or fileInput property and can contain additional options:
1376
+ // .fileupload('send', {files: filesList});
1377
+ // The method returns a Promise object for the file upload call.
1378
+ send: function (data) {
1379
+ if (data && !this.options.disabled) {
1380
+ if (data.fileInput && !data.files) {
1381
+ var that = this,
1382
+ dfd = $.Deferred(),
1383
+ promise = dfd.promise(),
1384
+ jqXHR,
1385
+ aborted;
1386
+ promise.abort = function () {
1387
+ aborted = true;
1388
+ if (jqXHR) {
1389
+ return jqXHR.abort();
1390
+ }
1391
+ dfd.reject(null, 'abort', 'abort');
1392
+ return promise;
1393
+ };
1394
+ this._getFileInputFiles(data.fileInput).always(
1395
+ function (files) {
1396
+ if (aborted) {
1397
+ return;
1398
+ }
1399
+ if (!files.length) {
1400
+ dfd.reject();
1401
+ return;
1402
+ }
1403
+ data.files = files;
1404
+ jqXHR = that._onSend(null, data).then(
1405
+ function (result, textStatus, jqXHR) {
1406
+ dfd.resolve(result, textStatus, jqXHR);
1407
+ },
1408
+ function (jqXHR, textStatus, errorThrown) {
1409
+ dfd.reject(jqXHR, textStatus, errorThrown);
1410
+ }
1411
+ );
1412
+ }
1413
+ );
1414
+ return this._enhancePromise(promise);
1415
+ }
1416
+ data.files = $.makeArray(data.files);
1417
+ if (data.files.length) {
1418
+ return this._onSend(null, data);
1419
+ }
1420
+ }
1421
+ return this._getXHRPromise(false, data && data.context);
1422
+ }
1423
+
1424
+ });
1425
+
1426
+ }));