ab_admin 0.3.6 → 0.4.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (419) hide show
  1. checksums.yaml +7 -0
  2. data/{LICENSE.txt → MIT-LICENSE} +2 -4
  3. data/README.md +3 -3
  4. data/Rakefile +21 -3
  5. data/app/assets/images/admin/flags/b_de.png +0 -0
  6. data/app/assets/images/admin/flags/b_es.png +0 -0
  7. data/app/assets/images/admin/flags/b_fr.png +0 -0
  8. data/app/assets/images/admin/flags/flag_de.gif +0 -0
  9. data/app/assets/images/admin/flags/flag_de_nonact.gif +0 -0
  10. data/app/assets/images/admin/flags/flag_es.gif +0 -0
  11. data/app/assets/images/admin/flags/flag_es_nonact.gif +0 -0
  12. data/app/assets/images/admin/flags/flag_fr.gif +0 -0
  13. data/app/assets/images/admin/flags/flag_fr_nonact.gif +0 -0
  14. data/app/assets/javascripts/ab_admin/components/admin_assets.js.coffee +50 -60
  15. data/app/assets/javascripts/ab_admin/components/base_assets.js.coffee +86 -0
  16. data/app/assets/javascripts/ab_admin/components/croppable_image.js.coffee +4 -4
  17. data/app/assets/javascripts/ab_admin/components/gmaps.js.coffee +5 -0
  18. data/app/assets/javascripts/ab_admin/components/google_translate.js.coffee +0 -1
  19. data/app/assets/javascripts/ab_admin/components/in_place_edit.js.coffee +7 -3
  20. data/app/assets/javascripts/ab_admin/components/locator.js.coffee +1 -1
  21. data/app/assets/javascripts/ab_admin/components/select2_bridge.js.coffee +152 -0
  22. data/app/assets/javascripts/ab_admin/components/sortable_tree.js.coffee +1 -1
  23. data/app/assets/javascripts/ab_admin/core/batch_actions.js.coffee +5 -4
  24. data/app/assets/javascripts/ab_admin/core/columns_hider.js.coffee +4 -11
  25. data/app/assets/javascripts/ab_admin/core/confirmation.js.coffee +4 -43
  26. data/app/assets/javascripts/ab_admin/core/deprecated_utils.js.coffee +44 -0
  27. data/app/assets/javascripts/ab_admin/core/init.js.coffee +8 -25
  28. data/app/assets/javascripts/ab_admin/core/pjax.js.coffee +18 -4
  29. data/app/assets/javascripts/ab_admin/core/search_form.js.coffee +5 -5
  30. data/app/assets/javascripts/ab_admin/core/ui_utils.js.coffee +15 -86
  31. data/app/assets/javascripts/ab_admin/core/utils.js.coffee +38 -51
  32. data/app/assets/javascripts/ab_admin/core/view_layout.js.coffee +1 -1
  33. data/app/assets/javascripts/ab_admin/inputs/datetime_input.js.coffee +16 -18
  34. data/app/assets/javascripts/ab_admin/main.js +7 -7
  35. data/app/assets/stylesheets/ab_admin/bootstrap_and_overrides.css.scss +21 -8
  36. data/app/assets/stylesheets/ab_admin/components/_admin_comments.css.scss +17 -5
  37. data/app/assets/stylesheets/ab_admin/components/_base.css.scss +4 -0
  38. data/app/assets/stylesheets/ab_admin/components/_colored_tabs.css.scss +1 -4
  39. data/app/assets/stylesheets/ab_admin/components/_columns_hider.css.scss +5 -0
  40. data/app/assets/stylesheets/ab_admin/components/_form.css.scss +45 -16
  41. data/app/assets/stylesheets/ab_admin/components/_grid_view.css.scss +11 -0
  42. data/app/assets/stylesheets/ab_admin/components/_locale_tabs.css.scss +1 -1
  43. data/app/assets/stylesheets/ab_admin/components/_navigation.css.scss +11 -9
  44. data/app/assets/stylesheets/ab_admin/components/_table_view.css.scss +1 -1
  45. data/app/assets/stylesheets/ab_admin/components/_translations.css.scss +1 -0
  46. data/app/assets/stylesheets/ab_admin/components/{_sortable_tree.css.scss → _tree_view.css.scss} +8 -3
  47. data/app/assets/stylesheets/ab_admin/fileupload.css.scss +51 -43
  48. data/app/assets/stylesheets/ab_admin/main.css.scss +1 -3
  49. data/app/controllers/admin/admin_comments_controller.rb +14 -4
  50. data/app/controllers/admin/assets_controller.rb +44 -35
  51. data/app/controllers/admin/base_controller.rb +93 -38
  52. data/app/controllers/admin/locators_controller.rb +3 -2
  53. data/app/controllers/admin/manager_controller.rb +20 -9
  54. data/app/controllers/admin/structures_controller.rb +9 -1
  55. data/app/controllers/admin/users_controller.rb +1 -2
  56. data/app/views/ab_admin/devise/sessions/new.html.slim +1 -1
  57. data/app/views/admin/admin_comments/_comment.html.slim +21 -7
  58. data/app/views/admin/admin_comments/_comments.html.slim +1 -1
  59. data/app/views/admin/admin_comments/_form.html.slim +8 -3
  60. data/app/views/admin/admin_comments/_list_block.html.slim +7 -0
  61. data/app/views/admin/admin_comments/create.js.erb +3 -2
  62. data/app/views/admin/admin_comments/destroy.js.erb +1 -1
  63. data/app/views/admin/admin_comments/index.js.erb +14 -0
  64. data/app/views/admin/assets/batch_edit.html.slim +14 -0
  65. data/app/views/admin/base/_modal_form_layout.html.slim +12 -0
  66. data/app/views/admin/base/_search_layout.html.slim +4 -3
  67. data/app/views/admin/base/_table.html.slim +2 -2
  68. data/app/views/admin/base/create.js.erb +13 -8
  69. data/app/views/admin/base/history.html.slim +18 -0
  70. data/app/views/admin/base/index.html.slim +3 -3
  71. data/app/views/admin/base/new.js.erb +14 -8
  72. data/app/views/admin/base/show.html.slim +1 -2
  73. data/app/views/admin/base/show.js.erb +7 -0
  74. data/app/views/admin/fileupload/_asset_templates.html.slim +29 -0
  75. data/app/views/admin/fileupload/_container.html.slim +13 -12
  76. data/app/views/admin/fileupload/_file.html.slim +2 -2
  77. data/app/views/admin/fileupload/_image.html.slim +8 -0
  78. data/app/views/admin/fileupload/_video.html.slim +2 -2
  79. data/app/views/admin/headers/_form.html.slim +2 -0
  80. data/app/views/admin/locators/edit.html.slim +1 -1
  81. data/app/views/admin/locators/show.html.slim +1 -2
  82. data/app/views/admin/manager/_form.html.slim +17 -3
  83. data/app/views/admin/manager/_modal_form.html.slim +19 -0
  84. data/app/views/admin/manager/_table.html.slim +3 -3
  85. data/app/views/admin/manager/show.html.slim +1 -0
  86. data/app/views/admin/shared/_content_actions.html.slim +39 -0
  87. data/app/views/admin/shared/_locale_tabs.html.slim +3 -3
  88. data/app/views/admin/shared/inputs/_checkbox_tree.html.slim +9 -3
  89. data/app/views/admin/structures/_form.html.slim +4 -7
  90. data/app/views/admin/users/_form.html.slim +2 -4
  91. data/app/views/admin/users/_search_form.html.slim +0 -1
  92. data/app/views/admin/users/_table.html.slim +8 -10
  93. data/app/views/layouts/admin/_footer.html.slim +3 -4
  94. data/app/views/layouts/admin/_navigation.html.slim +2 -2
  95. data/app/views/layouts/admin/application.html.slim +7 -9
  96. data/app/views/layouts/admin/devise.html.slim +3 -4
  97. data/config/locales/de.yml +319 -0
  98. data/config/locales/en.devise.yml +44 -31
  99. data/config/locales/en.yml +166 -143
  100. data/config/locales/it.devise.yml +54 -41
  101. data/config/locales/it.yml +178 -163
  102. data/config/locales/ru.devise.yml +70 -56
  103. data/config/locales/ru.yml +280 -264
  104. data/config/routes.rb +6 -3
  105. data/db/migrate/20130101000001_create_users.rb +7 -11
  106. data/db/migrate/20130101000003_create_assets.rb +5 -5
  107. data/db/migrate/20130101000004_create_headers.rb +2 -6
  108. data/db/migrate/20130101000005_create_static_pages.rb +1 -5
  109. data/db/migrate/20130101000006_create_structures.rb +5 -9
  110. data/db/migrate/20130101000007_base_translations.rb +3 -1
  111. data/db/migrate/20130101000008_create_admin_comments.rb +5 -5
  112. data/db/migrate/20130101000009_create_tracks.rb +20 -0
  113. data/lib/ab_admin.rb +36 -4
  114. data/lib/ab_admin/abstract_resource.rb +28 -7
  115. data/lib/ab_admin/carrierwave/base_uploader.rb +85 -5
  116. data/lib/ab_admin/carrierwave/glue.rb +6 -1
  117. data/lib/ab_admin/concerns/admin_addition.rb +26 -9
  118. data/lib/ab_admin/concerns/asset_human_names.rb +23 -0
  119. data/lib/ab_admin/concerns/fileuploads.rb +102 -0
  120. data/lib/ab_admin/concerns/has_tracking.rb +32 -0
  121. data/lib/ab_admin/concerns/nested_set.rb +9 -9
  122. data/lib/ab_admin/concerns/silencer.rb +5 -5
  123. data/lib/ab_admin/concerns/utilities.rb +28 -16
  124. data/lib/ab_admin/concerns/validations.rb +1 -1
  125. data/lib/ab_admin/config/base.rb +10 -2
  126. data/lib/ab_admin/controllers/callbacks.rb +2 -2
  127. data/lib/ab_admin/controllers/can_can_manager_resource.rb +3 -2
  128. data/lib/ab_admin/controllers/fv.rb +16 -0
  129. data/lib/ab_admin/controllers/head_options.rb +6 -4
  130. data/lib/ab_admin/core_ext/hash.rb +25 -70
  131. data/lib/ab_admin/core_ext/string.rb +17 -4
  132. data/lib/ab_admin/engine.rb +2 -8
  133. data/lib/ab_admin/hooks.rb +8 -3
  134. data/lib/ab_admin/hooks/active_model_hooks.rb +1 -1
  135. data/lib/ab_admin/hooks/globalize_hooks.rb +35 -0
  136. data/lib/ab_admin/hooks/paginate_hooks.rb +3 -1
  137. data/lib/ab_admin/i18n_tools/model_translator.rb +1 -1
  138. data/lib/ab_admin/menu/abstract_builder.rb +14 -0
  139. data/lib/ab_admin/menu/base_group.rb +26 -0
  140. data/lib/ab_admin/menu/builder.rb +16 -0
  141. data/lib/ab_admin/menu/group.rb +24 -0
  142. data/lib/ab_admin/menu/item.rb +23 -0
  143. data/lib/ab_admin/models/admin_comment.rb +68 -0
  144. data/lib/ab_admin/models/asset.rb +30 -19
  145. data/lib/ab_admin/models/attachment_file.rb +2 -1
  146. data/lib/ab_admin/models/header.rb +15 -0
  147. data/lib/ab_admin/models/locator.rb +1 -3
  148. data/lib/ab_admin/models/settings.rb +10 -10
  149. data/lib/ab_admin/models/structure.rb +20 -9
  150. data/lib/ab_admin/models/track.rb +61 -0
  151. data/lib/ab_admin/models/type_model.rb +30 -17
  152. data/lib/ab_admin/models/user.rb +18 -49
  153. data/lib/ab_admin/utils.rb +16 -7
  154. data/lib/ab_admin/utils/logger.rb +11 -7
  155. data/lib/ab_admin/utils/mysql.rb +10 -0
  156. data/lib/ab_admin/version.rb +1 -1
  157. data/lib/ab_admin/views/admin_helpers.rb +20 -9
  158. data/lib/ab_admin/views/admin_navigation_helpers.rb +44 -21
  159. data/lib/ab_admin/views/content_only_wrapper.rb +14 -0
  160. data/lib/ab_admin/views/form_builder.rb +27 -89
  161. data/lib/ab_admin/views/helpers.rb +1 -28
  162. data/lib/ab_admin/views/inputs/capture_block_input.rb +16 -0
  163. data/lib/ab_admin/views/inputs/date_time_picker_input.rb +45 -0
  164. data/lib/ab_admin/views/inputs/token_input.rb +2 -1
  165. data/lib/ab_admin/views/inputs/uploader_input.rb +101 -0
  166. data/lib/ab_admin/views/manager_helpers.rb +12 -0
  167. data/lib/ab_admin/views/search_form_builder.rb +36 -13
  168. data/lib/generators/ab_admin/ckeditor_assets/ckeditor_assets_generator.rb +1 -1
  169. data/lib/generators/ab_admin/install/install_generator.rb +3 -2
  170. data/lib/generators/ab_admin/install/templates/config/ab_admin.rb.erb +1 -1
  171. data/lib/generators/ab_admin/install/templates/config/admin_menu.rb +1 -1
  172. data/lib/generators/ab_admin/install/templates/config/i18n-js.yml +1 -1
  173. data/lib/generators/ab_admin/install/templates/config/nginx.conf +22 -9
  174. data/lib/generators/ab_admin/install/templates/config/robots.txt +7 -0
  175. data/lib/generators/ab_admin/install/templates/config/seeds.rb +2 -1
  176. data/lib/generators/ab_admin/install/templates/models/ability.rb +2 -7
  177. data/lib/generators/ab_admin/install/templates/models/admin_comment.rb +3 -28
  178. data/lib/generators/ab_admin/install/templates/models/asset.rb +4 -2
  179. data/lib/generators/ab_admin/install/templates/models/attachment_file.rb +1 -1
  180. data/lib/generators/ab_admin/install/templates/models/avatar.rb +2 -2
  181. data/lib/generators/ab_admin/install/templates/models/gender_type.rb +1 -1
  182. data/lib/generators/ab_admin/install/templates/models/header.rb +2 -2
  183. data/lib/generators/ab_admin/install/templates/models/locator.rb +0 -1
  184. data/lib/generators/ab_admin/install/templates/models/picture.rb +1 -1
  185. data/lib/generators/ab_admin/install/templates/models/settings.rb +1 -1
  186. data/lib/generators/ab_admin/install/templates/models/structure.rb +6 -8
  187. data/lib/generators/ab_admin/install/templates/models/track.rb +5 -0
  188. data/lib/generators/ab_admin/install/templates/models/user.rb +2 -3
  189. data/lib/generators/ab_admin/install/templates/script/unicorn.sh +0 -2
  190. data/lib/generators/ab_admin/install/templates/spec/factories/user_factory.rb +1 -2
  191. data/lib/generators/ab_admin/install/templates/uploaders/attachment_file_uploader.rb +1 -1
  192. data/lib/generators/ab_admin/install/templates/uploaders/avatar_uploader.rb +1 -1
  193. data/lib/generators/ab_admin/install/templates/uploaders/picture_uploader.rb +1 -1
  194. data/lib/generators/ab_admin/model/templates/resource.erb +1 -1
  195. data/lib/generators/ab_admin/resource/templates/_form.slim.erb +49 -45
  196. data/lib/generators/ab_admin/resource/templates/_table.slim.erb +1 -1
  197. data/lib/generators/template.rb +32 -56
  198. data/lib/tasks/assets.rake +1 -0
  199. metadata +197 -698
  200. data/.gitignore +0 -41
  201. data/Gemfile +0 -77
  202. data/Guardfile +0 -35
  203. data/TODO +0 -4
  204. data/ab_admin.gemspec +0 -59
  205. data/app/views/admin/fileupload/_asset.html.slim +0 -8
  206. data/app/views/admin/fileupload/_ftmpl.html.slim +0 -6
  207. data/app/views/admin/fileupload/_tmpl.html.slim +0 -9
  208. data/app/views/admin/fileupload/_vtmpl.html.slim +0 -10
  209. data/app/views/admin/shared/_batch_actions.html.slim +0 -27
  210. data/cucumber.yml +0 -10
  211. data/features/dsl/action_items.feature +0 -79
  212. data/features/dsl/admin_comments.feature +0 -30
  213. data/features/dsl/batch_actions.feature +0 -69
  214. data/features/dsl/config.feature +0 -44
  215. data/features/dsl/custom_actions.feature +0 -62
  216. data/features/dsl/export.feature +0 -42
  217. data/features/dsl/form.feature +0 -77
  218. data/features/dsl/in_place_edit.feature +0 -26
  219. data/features/dsl/list_edit.feature +0 -46
  220. data/features/dsl/parent_resource.feature +0 -18
  221. data/features/dsl/resource_action_items.feature +0 -40
  222. data/features/dsl/search.feature +0 -41
  223. data/features/dsl/show.feature +0 -37
  224. data/features/dsl/table.feature +0 -71
  225. data/features/dsl/tree.feature +0 -37
  226. data/features/index_views/table.feature +0 -20
  227. data/features/locators.feature +0 -40
  228. data/features/menu.feature +0 -35
  229. data/features/settings.feature +0 -36
  230. data/features/step_definitions/configuration_steps.rb +0 -94
  231. data/features/step_definitions/dsl/action_items_steps.rb +0 -13
  232. data/features/step_definitions/dsl/admin_comments_steps.rb +0 -12
  233. data/features/step_definitions/dsl/batch_actions_steps.rb +0 -27
  234. data/features/step_definitions/dsl/in_place_edit_steps.rb +0 -7
  235. data/features/step_definitions/dsl/parent_resource_steps.rb +0 -8
  236. data/features/step_definitions/dsl/resource_action_items_steps.rb +0 -14
  237. data/features/step_definitions/dsl/show_steps.rb +0 -8
  238. data/features/step_definitions/dsl/table_steps.rb +0 -38
  239. data/features/step_definitions/dsl/tree_steps.rb +0 -28
  240. data/features/step_definitions/menu_steps.rb +0 -20
  241. data/features/step_definitions/settings_steps.rb +0 -7
  242. data/features/step_definitions/structure_steps.rb +0 -7
  243. data/features/step_definitions/table_steps.rb +0 -23
  244. data/features/step_definitions/user_steps.rb +0 -72
  245. data/features/step_definitions/web_steps/browsing_steps.rb +0 -108
  246. data/features/step_definitions/web_steps/debug_steps.rb +0 -6
  247. data/features/step_definitions/web_steps/form_steps.rb +0 -190
  248. data/features/step_definitions/web_steps/i18n_steps.rb +0 -8
  249. data/features/step_definitions/web_steps/step_scoper.rb +0 -9
  250. data/features/step_definitions/web_steps/transforms_steps.rb +0 -3
  251. data/features/structure/tree.feature +0 -21
  252. data/features/support/capybara_helpers.rb +0 -15
  253. data/features/support/carrierwave.rb +0 -21
  254. data/features/support/env.rb +0 -40
  255. data/features/support/paths.rb +0 -55
  256. data/features/support/selector_helpers.rb +0 -9
  257. data/features/support/selectors.rb +0 -43
  258. data/features/support/tolerance_for_selenium_sync_issues.rb +0 -27
  259. data/features/user/sign_in.feature +0 -27
  260. data/features/user/sign_out.feature +0 -11
  261. data/features/user/user_edit.feature +0 -19
  262. data/features/user/user_show.feature +0 -9
  263. data/lib/ab_admin/hooks/quiet_scope_page.rb +0 -16
  264. data/lib/ab_admin/hooks/simple_form_hooks.rb +0 -31
  265. data/lib/ab_admin/menu_builder.rb +0 -89
  266. data/lib/ab_admin/views/inputs/date_time_input.rb +0 -65
  267. data/lib/generators/ab_admin/install/templates/models/user_state.rb +0 -6
  268. data/lib/generators/ab_admin/resource/templates/_form.haml.erb +0 -71
  269. data/lib/generators/ab_admin/resource/templates/_search_form.haml.erb +0 -35
  270. data/lib/generators/ab_admin/resource/templates/_table.haml.erb +0 -33
  271. data/spec/ab_admin_spec.rb +0 -23
  272. data/spec/dummy/Rakefile +0 -7
  273. data/spec/dummy/app/assets/images/rails.png +0 -0
  274. data/spec/dummy/app/assets/javascripts/application.js +0 -15
  275. data/spec/dummy/app/assets/stylesheets/application.css +0 -13
  276. data/spec/dummy/app/controllers/application_controller.rb +0 -3
  277. data/spec/dummy/app/controllers/products_controller.rb +0 -5
  278. data/spec/dummy/app/controllers/welcome_controller.rb +0 -5
  279. data/spec/dummy/app/mailers/.gitkeep +0 -0
  280. data/spec/dummy/app/models/ab_admin/ab_admin_catalogue.rb +0 -5
  281. data/spec/dummy/app/models/ab_admin/ab_admin_collection.rb +0 -35
  282. data/spec/dummy/app/models/ab_admin/ab_admin_product.rb +0 -74
  283. data/spec/dummy/app/models/admin_menu.rb +0 -18
  284. data/spec/dummy/app/models/catalogue.rb +0 -10
  285. data/spec/dummy/app/models/ckeditor/asset.rb +0 -7
  286. data/spec/dummy/app/models/ckeditor/attachment_file.rb +0 -7
  287. data/spec/dummy/app/models/ckeditor/picture.rb +0 -7
  288. data/spec/dummy/app/models/collection.rb +0 -20
  289. data/spec/dummy/app/models/product.rb +0 -32
  290. data/spec/dummy/app/uploaders/ckeditor_attachment_file_uploader.rb +0 -42
  291. data/spec/dummy/app/uploaders/ckeditor_picture_uploader.rb +0 -53
  292. data/spec/dummy/app/views/admin/collections/_form.html.slim +0 -24
  293. data/spec/dummy/app/views/layouts/application.html.erb +0 -14
  294. data/spec/dummy/app/views/products/show.html.erb +0 -2
  295. data/spec/dummy/app/views/welcome/index.html.erb +0 -2
  296. data/spec/dummy/config.ru +0 -4
  297. data/spec/dummy/config/application.rb +0 -82
  298. data/spec/dummy/config/boot.rb +0 -10
  299. data/spec/dummy/config/database.yml +0 -26
  300. data/spec/dummy/config/environment.rb +0 -5
  301. data/spec/dummy/config/environments/development.rb +0 -37
  302. data/spec/dummy/config/environments/production.rb +0 -67
  303. data/spec/dummy/config/environments/test.rb +0 -37
  304. data/spec/dummy/config/i18n-js.yml +0 -21
  305. data/spec/dummy/config/initializers/ab_admin.rb +0 -15
  306. data/spec/dummy/config/initializers/backtrace_silencers.rb +0 -7
  307. data/spec/dummy/config/initializers/ckeditor.rb +0 -18
  308. data/spec/dummy/config/initializers/devise.rb +0 -232
  309. data/spec/dummy/config/initializers/inflections.rb +0 -15
  310. data/spec/dummy/config/initializers/mime_types.rb +0 -5
  311. data/spec/dummy/config/initializers/secret_token.rb +0 -7
  312. data/spec/dummy/config/initializers/session_store.rb +0 -8
  313. data/spec/dummy/config/initializers/simple_form.rb +0 -142
  314. data/spec/dummy/config/initializers/simple_form_bootstrap.rb +0 -45
  315. data/spec/dummy/config/initializers/wrap_parameters.rb +0 -14
  316. data/spec/dummy/config/locales/devise.en.yml +0 -60
  317. data/spec/dummy/config/locales/en.yml +0 -5
  318. data/spec/dummy/config/locales/simple_form.en.yml +0 -26
  319. data/spec/dummy/config/routes.rb +0 -14
  320. data/spec/dummy/config/settings/development.local.yml +0 -9
  321. data/spec/dummy/config/settings/development.yml +0 -7
  322. data/spec/dummy/db/migrate/20130129151853_create_ckeditor_assets.rb +0 -26
  323. data/spec/dummy/db/migrate/20130130161853_create_collections.rb +0 -10
  324. data/spec/dummy/db/migrate/20130130162046_create_products.rb +0 -13
  325. data/spec/dummy/db/migrate/20130130175446_create_globalize_collection_product.rb +0 -11
  326. data/spec/dummy/db/migrate/20130207224516_create_catalogues.rb +0 -16
  327. data/spec/dummy/db/migrate/20130209223506_add_lat_lon_zoom_to_products.rb +0 -7
  328. data/spec/dummy/db/seeds.rb +0 -46
  329. data/spec/dummy/lib/assets/.gitkeep +0 -0
  330. data/spec/dummy/lib/capybara_irb.rb +0 -42
  331. data/spec/dummy/lib/tasks/.gitkeep +0 -0
  332. data/spec/dummy/lib/tasks/cucumber.rake +0 -65
  333. data/spec/dummy/lib/templates/slim/scaffold/_form.html.slim +0 -10
  334. data/spec/dummy/log/.gitkeep +0 -0
  335. data/spec/dummy/public/404.html +0 -26
  336. data/spec/dummy/public/422.html +0 -26
  337. data/spec/dummy/public/500.html +0 -25
  338. data/spec/dummy/public/favicon.ico +0 -0
  339. data/spec/dummy/script/cucumber +0 -10
  340. data/spec/dummy/script/rails +0 -6
  341. data/spec/factories/assets.rb +0 -52
  342. data/spec/factories/catalogues.rb +0 -7
  343. data/spec/factories/collections.rb +0 -8
  344. data/spec/factories/files/rails.png +0 -0
  345. data/spec/factories/products.rb +0 -17
  346. data/spec/factories/sequences.rb +0 -7
  347. data/spec/factories/structures.rb +0 -17
  348. data/spec/factories/users.rb +0 -30
  349. data/spec/generators/ckeditor_assets_generator_spec.rb +0 -19
  350. data/spec/generators/install_generator_spec.rb +0 -48
  351. data/spec/generators/model_generator_spec.rb +0 -31
  352. data/spec/generators/resource_generator_spec.rb +0 -36
  353. data/spec/models/ab_admin/abstract_resource_spec.rb +0 -5
  354. data/spec/models/avatar_spec.rb +0 -162
  355. data/spec/models/picture_uploader_spec.rb +0 -49
  356. data/spec/models/structure_spec.rb +0 -69
  357. data/spec/models/user_spec.rb +0 -159
  358. data/spec/shared_behaviors/concerns.rb +0 -20
  359. data/spec/spec_helper.rb +0 -96
  360. data/spec/support/controller_macros.rb +0 -52
  361. data/spec/support/custom_capybara_matchers.rb +0 -58
  362. data/spec/support/mailer_macros.rb +0 -17
  363. data/spec/support/shared_connection.rb +0 -11
  364. data/vendor/assets/images/ab_admin/clear.png +0 -0
  365. data/vendor/assets/images/ab_admin/loading.gif +0 -0
  366. data/vendor/assets/javascripts/ab_admin/bootstrap-datepicker/core.js +0 -899
  367. data/vendor/assets/javascripts/ab_admin/bootstrap-datepicker/index.js +0 -2
  368. data/vendor/assets/javascripts/ab_admin/bootstrap-datepicker/locales/bootstrap-datepicker.bg.js +0 -14
  369. data/vendor/assets/javascripts/ab_admin/bootstrap-datepicker/locales/bootstrap-datepicker.br.js +0 -13
  370. data/vendor/assets/javascripts/ab_admin/bootstrap-datepicker/locales/bootstrap-datepicker.cs.js +0 -14
  371. data/vendor/assets/javascripts/ab_admin/bootstrap-datepicker/locales/bootstrap-datepicker.da.js +0 -14
  372. data/vendor/assets/javascripts/ab_admin/bootstrap-datepicker/locales/bootstrap-datepicker.de.js +0 -14
  373. data/vendor/assets/javascripts/ab_admin/bootstrap-datepicker/locales/bootstrap-datepicker.es.js +0 -14
  374. data/vendor/assets/javascripts/ab_admin/bootstrap-datepicker/locales/bootstrap-datepicker.fi.js +0 -14
  375. data/vendor/assets/javascripts/ab_admin/bootstrap-datepicker/locales/bootstrap-datepicker.fr.js +0 -14
  376. data/vendor/assets/javascripts/ab_admin/bootstrap-datepicker/locales/bootstrap-datepicker.id.js +0 -13
  377. data/vendor/assets/javascripts/ab_admin/bootstrap-datepicker/locales/bootstrap-datepicker.is.js +0 -14
  378. data/vendor/assets/javascripts/ab_admin/bootstrap-datepicker/locales/bootstrap-datepicker.it.js +0 -14
  379. data/vendor/assets/javascripts/ab_admin/bootstrap-datepicker/locales/bootstrap-datepicker.ja.js +0 -13
  380. data/vendor/assets/javascripts/ab_admin/bootstrap-datepicker/locales/bootstrap-datepicker.kr.js +0 -13
  381. data/vendor/assets/javascripts/ab_admin/bootstrap-datepicker/locales/bootstrap-datepicker.lt.js +0 -15
  382. data/vendor/assets/javascripts/ab_admin/bootstrap-datepicker/locales/bootstrap-datepicker.lv.js +0 -16
  383. data/vendor/assets/javascripts/ab_admin/bootstrap-datepicker/locales/bootstrap-datepicker.ms.js +0 -14
  384. data/vendor/assets/javascripts/ab_admin/bootstrap-datepicker/locales/bootstrap-datepicker.nb.js +0 -14
  385. data/vendor/assets/javascripts/ab_admin/bootstrap-datepicker/locales/bootstrap-datepicker.nl.js +0 -14
  386. data/vendor/assets/javascripts/ab_admin/bootstrap-datepicker/locales/bootstrap-datepicker.pl.js +0 -14
  387. data/vendor/assets/javascripts/ab_admin/bootstrap-datepicker/locales/bootstrap-datepicker.pt-BR.js +0 -14
  388. data/vendor/assets/javascripts/ab_admin/bootstrap-datepicker/locales/bootstrap-datepicker.pt.js +0 -14
  389. data/vendor/assets/javascripts/ab_admin/bootstrap-datepicker/locales/bootstrap-datepicker.ro.js +0 -15
  390. data/vendor/assets/javascripts/ab_admin/bootstrap-datepicker/locales/bootstrap-datepicker.ru.js +0 -14
  391. data/vendor/assets/javascripts/ab_admin/bootstrap-datepicker/locales/bootstrap-datepicker.sk.js +0 -14
  392. data/vendor/assets/javascripts/ab_admin/bootstrap-datepicker/locales/bootstrap-datepicker.sl.js +0 -14
  393. data/vendor/assets/javascripts/ab_admin/bootstrap-datepicker/locales/bootstrap-datepicker.sv.js +0 -14
  394. data/vendor/assets/javascripts/ab_admin/bootstrap-datepicker/locales/bootstrap-datepicker.th.js +0 -14
  395. data/vendor/assets/javascripts/ab_admin/bootstrap-datepicker/locales/bootstrap-datepicker.tr.js +0 -15
  396. data/vendor/assets/javascripts/ab_admin/bootstrap-datepicker/locales/bootstrap-datepicker.zh-CN.js +0 -14
  397. data/vendor/assets/javascripts/ab_admin/bootstrap-datepicker/locales/bootstrap-datepicker.zh-TW.js +0 -13
  398. data/vendor/assets/javascripts/ab_admin/bootstrap-editable-inline.js +0 -2895
  399. data/vendor/assets/javascripts/ab_admin/bootstrap-editable.js +0 -4523
  400. data/vendor/assets/javascripts/ab_admin/bootstrap-tab-multi.js +0 -135
  401. data/vendor/assets/javascripts/ab_admin/bootstrap-timepicker.js +0 -377
  402. data/vendor/assets/javascripts/ab_admin/fileupload/admin-fileuploader.js.coffee +0 -111
  403. data/vendor/assets/javascripts/ab_admin/fileupload/fileuploader.js +0 -1301
  404. data/vendor/assets/javascripts/ab_admin/jquery.Jcrop.js +0 -1083
  405. data/vendor/assets/javascripts/ab_admin/jquery_nested_form.js.coffee +0 -66
  406. data/vendor/assets/javascripts/bootstrap-wysihtml5/locales/ru.js +0 -48
  407. data/vendor/assets/javascripts/handlebars.min.js +0 -1
  408. data/vendor/assets/javascripts/jquery.cookie.js +0 -42
  409. data/vendor/assets/javascripts/jquery.hotkeys.js +0 -106
  410. data/vendor/assets/javascripts/jquery.pjax.js +0 -688
  411. data/vendor/assets/javascripts/jquery.tmpl.min.js +0 -10
  412. data/vendor/assets/javascripts/jquery.ui.nestedSortable.js +0 -356
  413. data/vendor/assets/javascripts/jquery/jquery-ui.min.js +0 -15
  414. data/vendor/assets/javascripts/jquery/jquery.min.js +0 -4
  415. data/vendor/assets/javascripts/underscore.min.js +0 -5
  416. data/vendor/assets/stylesheets/ab_admin/bootstrap-datepicker.css.scss +0 -274
  417. data/vendor/assets/stylesheets/ab_admin/bootstrap-editable.scss +0 -461
  418. data/vendor/assets/stylesheets/ab_admin/bootstrap-timepicker.css.scss +0 -88
  419. data/vendor/assets/stylesheets/ab_admin/jquery.Jcrop.min.css.scss +0 -28
@@ -1,111 +0,0 @@
1
- qq.FileUploader.instances = new Object()
2
- qq.FileUploaderInput = (o) ->
3
- qq.FileUploaderBasic.apply this, arguments
4
- qq.extend @_options,
5
- element: null
6
- listElement: null
7
- template_id: "#fileupload_tmpl"
8
- classes:
9
- button: "fileupload-button"
10
- drop: "fileupload-drop-area"
11
- dropActive: "fileupload-drop-area-active"
12
- list: "fileupload-list"
13
- preview: "fileupload-preview"
14
- file: "fileupload-file"
15
- spinner: "fileupload-spinner"
16
- size: "fileupload-size"
17
- cancel: "fileupload-cancel"
18
- success: "fileupload-success"
19
- fail: "fileupload-fail"
20
-
21
- qq.extend @_options, o
22
- @_element = document.getElementById(@_options.element)
23
- @_listElement = @_options.listElement or @_find(@_element, "list")
24
- @_classes = @_options.classes
25
- @_button = @_createUploadButton(@_find(@_element, "button"))
26
- qq.FileUploader.instances[@_element.id] = this
27
-
28
- qq.extend qq.FileUploaderInput::, qq.FileUploaderBasic::
29
- qq.extend qq.FileUploaderInput::,
30
- _find: (parent, type) ->
31
- element = qq.getByClass(parent, @_options.classes[type])[0]
32
- throw new Error("element not found " + type) unless element
33
- element
34
-
35
- _setupDragDrop: ->
36
- self = this
37
- dropArea = @_find(@_element, "drop")
38
- dz = new qq.UploadDropZone(
39
- element: dropArea
40
- onEnter: (e) ->
41
- qq.addClass dropArea, self._classes.dropActive
42
- e.stopPropagation()
43
-
44
- onLeave: (e) ->
45
- e.stopPropagation()
46
-
47
- onLeaveNotDescendants: (e) ->
48
- qq.removeClass dropArea, self._classes.dropActive
49
-
50
- onDrop: (e) ->
51
- dropArea.style.display = "none"
52
- qq.removeClass dropArea, self._classes.dropActive
53
- self._uploadFileList e.dataTransfer.files
54
- )
55
- dropArea.style.display = "none"
56
- qq.attach document, "dragenter", (e) ->
57
- return unless dz._isValidFileDrag(e)
58
- dropArea.style.display = "block"
59
-
60
- qq.attach document, "dragleave", (e) ->
61
- return unless dz._isValidFileDrag(e)
62
- relatedTarget = document.elementFromPoint(e.clientX, e.clientY)
63
- dropArea.style.display = "none" if not relatedTarget or relatedTarget.nodeName is "HTML"
64
-
65
- _onSubmit: (id, fileName) ->
66
- qq.FileUploaderBasic::_onSubmit.apply this, arguments
67
- @_addToList id, fileName
68
-
69
- _onProgress: (id, fileName, loaded, total) ->
70
- qq.FileUploaderBasic::_onProgress.apply this, arguments
71
-
72
- _onComplete: (id, fileName, result) ->
73
- qq.FileUploaderBasic::_onComplete.apply this, arguments
74
- item = @_getItemByFileId(id)
75
- asset = result.asset
76
- if asset and asset.id
77
- qq.addClass item, @_classes.success
78
- $(item).replaceWith $(@_options.template_id).tmpl(asset)
79
- @_trigger_event asset
80
- else
81
- qq.addClass item, @_classes.fail
82
- $('.fileupload-drop-area').hide()
83
-
84
- _trigger_event: (asset) ->
85
- $("#" + @_options.element).trigger
86
- type: "fileupload:onComplete"
87
- asset: asset
88
-
89
- _addToList: (id, fileName) ->
90
- if @_listElement
91
- $(@_listElement).empty() if @_options.multiple is false
92
- asset =
93
- id: 0
94
- filename: @_formatFileName(fileName)
95
- url: "/assets/admin/preloader.gif"
96
- thumb_url: "/assets/admin/preloader.gif"
97
-
98
- item = $(@_options.template_id).tmpl(asset).attr("qqfileid", id).appendTo(@_listElement)
99
- @_bindCancelEvent item
100
-
101
- _getItemByFileId: (id) ->
102
- $(@_listElement).find("div[qqfileid=" + id + "]").get 0
103
-
104
- _bindCancelEvent: (element) ->
105
- self = this
106
- item = $(element)
107
- item.find("a." + @_classes.cancel).bind "click", (e) ->
108
- self._handler.cancel item.attr("qqfileid")
109
- item.remove()
110
- qq.preventDefault e
111
- false
@@ -1,1301 +0,0 @@
1
- /**
2
- * http://github.com/valums/file-uploader
3
- *
4
- * Multiple file upload component with progress-bar, drag-and-drop.
5
- * © 2010 Andrew Valums ( andrew(at)valums.com )
6
- *
7
- * Licensed under GNU GPL 2 or later, see license.txt.
8
- */
9
-
10
- //
11
- // Helper functions
12
- //
13
-
14
- var qq = qq || {};
15
-
16
- /**
17
- * Adds all missing properties from second obj to first obj
18
- */
19
- qq.extend = function(first, second){
20
- for (var prop in second){
21
- first[prop] = second[prop];
22
- }
23
- };
24
-
25
- /**
26
- * Searches for a given element in the array, returns -1 if it is not present.
27
- * @param {Number} [from] The index at which to begin the search
28
- */
29
- qq.indexOf = function(arr, elt, from){
30
- if (arr.indexOf) return arr.indexOf(elt, from);
31
-
32
- from = from || 0;
33
- var len = arr.length;
34
-
35
- if (from < 0) from += len;
36
-
37
- for (; from < len; from++){
38
- if (from in arr && arr[from] === elt){
39
- return from;
40
- }
41
- }
42
- return -1;
43
- };
44
-
45
- qq.getUniqueId = (function(){
46
- var id = 0;
47
- return function(){ return id++; };
48
- })();
49
-
50
- //
51
- // Events
52
-
53
- qq.attach = function(element, type, fn){
54
- if (element.addEventListener){
55
- element.addEventListener(type, fn, false);
56
- } else if (element.attachEvent){
57
- element.attachEvent('on' + type, fn);
58
- }
59
- };
60
- qq.detach = function(element, type, fn){
61
- if (element.removeEventListener){
62
- element.removeEventListener(type, fn, false);
63
- } else if (element.attachEvent){
64
- element.detachEvent('on' + type, fn);
65
- }
66
- };
67
-
68
- qq.preventDefault = function(e){
69
- if (e.preventDefault){
70
- e.preventDefault();
71
- } else{
72
- e.returnValue = false;
73
- }
74
- };
75
-
76
- //
77
- // Node manipulations
78
-
79
- /**
80
- * Insert node a before node b.
81
- */
82
- qq.insertBefore = function(a, b){
83
- b.parentNode.insertBefore(a, b);
84
- };
85
- qq.remove = function(element){
86
- element.parentNode.removeChild(element);
87
- };
88
-
89
- qq.contains = function(parent, descendant){
90
- // compareposition returns false in this case
91
- if (parent == descendant) return true;
92
-
93
- if (parent.contains){
94
- return parent.contains(descendant);
95
- } else {
96
- return !!(descendant.compareDocumentPosition(parent) & 8);
97
- }
98
- };
99
-
100
- /**
101
- * Creates and returns element from html string
102
- * Uses innerHTML to create an element
103
- */
104
- qq.toElement = (function(){
105
- var div = document.createElement('div');
106
- return function(html){
107
- div.innerHTML = html;
108
- var element = div.firstChild;
109
- div.removeChild(element);
110
- return element;
111
- };
112
- })();
113
-
114
- //
115
- // Node properties and attributes
116
-
117
- /**
118
- * Sets styles for an element.
119
- * Fixes opacity in IE6-8.
120
- */
121
- qq.css = function(element, styles){
122
- if (styles.opacity != null){
123
- if (typeof element.style.opacity != 'string' && typeof(element.filters) != 'undefined'){
124
- styles.filter = 'alpha(opacity=' + Math.round(100 * styles.opacity) + ')';
125
- }
126
- }
127
- qq.extend(element.style, styles);
128
- };
129
- qq.hasClass = function(element, name){
130
- var re = new RegExp('(^| )' + name + '( |$)');
131
- return re.test(element.className);
132
- };
133
- qq.addClass = function(element, name){
134
- if (!qq.hasClass(element, name)){
135
- element.className += ' ' + name;
136
- }
137
- };
138
- qq.removeClass = function(element, name){
139
- var re = new RegExp('(^| )' + name + '( |$)');
140
- element.className = element.className.replace(re, ' ').replace(/^\s+|\s+$/g, "");
141
- };
142
- qq.setText = function(element, text){
143
- element.innerText = text;
144
- element.textContent = text;
145
- };
146
-
147
- //
148
- // Selecting elements
149
-
150
- qq.children = function(element){
151
- var children = [],
152
- child = element.firstChild;
153
-
154
- while (child){
155
- if (child.nodeType == 1){
156
- children.push(child);
157
- }
158
- child = child.nextSibling;
159
- }
160
-
161
- return children;
162
- };
163
-
164
- qq.getByClass = function(element, className){
165
- if (element.querySelectorAll){
166
- return element.querySelectorAll('.' + className);
167
- }
168
-
169
- var result = [];
170
- var candidates = element.getElementsByTagName("*");
171
- var len = candidates.length;
172
-
173
- for (var i = 0; i < len; i++){
174
- if (qq.hasClass(candidates[i], className)){
175
- result.push(candidates[i]);
176
- }
177
- }
178
- return result;
179
- };
180
-
181
- /**
182
- * obj2url() takes a json-object as argument and generates
183
- * a querystring. pretty much like jQuery.param()
184
- *
185
- * how to use:
186
- *
187
- * `qq.obj2url({a:'b',c:'d'},'http://any.url/upload?otherParam=value');`
188
- *
189
- * will result in:
190
- *
191
- * `http://any.url/upload?otherParam=value&a=b&c=d`
192
- *
193
- * @param Object JSON-Object
194
- * @param String current querystring-part
195
- * @return String encoded querystring
196
- */
197
- qq.obj2url = function(obj, temp, prefixDone){
198
- var uristrings = [],
199
- prefix = '&',
200
- add = function(nextObj, i){
201
- var nextTemp = temp
202
- ? (/\[\]$/.test(temp)) // prevent double-encoding
203
- ? temp
204
- : temp+'['+i+']'
205
- : i;
206
- if ((nextTemp != 'undefined') && (i != 'undefined')) {
207
- uristrings.push(
208
- (typeof nextObj === 'object')
209
- ? qq.obj2url(nextObj, nextTemp, true)
210
- : (Object.prototype.toString.call(nextObj) === '[object Function]')
211
- ? encodeURIComponent(nextTemp) + '=' + encodeURIComponent(nextObj())
212
- : encodeURIComponent(nextTemp) + '=' + encodeURIComponent(nextObj)
213
- );
214
- }
215
- };
216
-
217
- if (!prefixDone && temp) {
218
- prefix = (/\?/.test(temp)) ? (/\?$/.test(temp)) ? '' : '&' : '?';
219
- uristrings.push(temp);
220
- uristrings.push(qq.obj2url(obj));
221
- } else if ((Object.prototype.toString.call(obj) === '[object Array]') && (typeof obj != 'undefined') ) {
222
- // we wont use a for-in-loop on an array (performance)
223
- for (var i = 0, len = obj.length; i < len; ++i){
224
- add(obj[i], i);
225
- }
226
- } else if ((typeof obj != 'undefined') && (obj !== null) && (typeof obj === "object")){
227
- // for anything else but a scalar, we will use for-in-loop
228
- for (var i in obj){
229
- add(obj[i], i);
230
- }
231
- } else {
232
- uristrings.push(encodeURIComponent(temp) + '=' + encodeURIComponent(obj));
233
- }
234
-
235
- return uristrings.join(prefix)
236
- .replace(/^&/, '')
237
- .replace(/%20/g, '+');
238
- };
239
-
240
- //
241
- //
242
- // Uploader Classes
243
- //
244
- //
245
-
246
- var qq = qq || {};
247
-
248
- /**
249
- * Creates upload button, validates upload, but doesn't create file list or dd.
250
- */
251
- qq.FileUploaderBasic = function(o){
252
- this._options = {
253
- // set to true to see the server response
254
- debug: false,
255
- action: '/server/upload',
256
- params: {},
257
- button: null,
258
- multiple: true,
259
- maxConnections: 3,
260
- method: 'POST',
261
- fieldName: 'qqfile',
262
- // validation
263
- allowedExtensions: [],
264
- sizeLimit: 0,
265
- minSizeLimit: 0,
266
- maxFilesCount: 0, // 0 - no limit, works only in multiple mode
267
- minFilesCount: 0, // 0 - no limit, works only in multiple mode
268
- // events
269
- // return false to cancel submit
270
- onSubmit: function(id, fileName){},
271
- onProgress: function(id, fileName, loaded, total){},
272
- onComplete: function(id, fileName, responseJSON){},
273
- onCancel: function(id, fileName){},
274
- // messages
275
- messages: {
276
- typeError: "{file} has invalid extension. Only {extensions} are allowed.",
277
- sizeError: "{file} is too large, maximum file size is {sizeLimit}.",
278
- minSizeError: "{file} is too small, minimum file size is {minSizeLimit}.",
279
- emptyError: "{file} is empty, please select files again without it.",
280
- onLeave: "The files are being uploaded, if you leave now the upload will be cancelled.",
281
- maxFilesError: "You must select less then {maxFilesCount} files.",
282
- minFilesError: "You must select more then {minFilesCount} files."
283
- },
284
- showMessage: function(message){
285
- alert(message);
286
- }
287
- };
288
- qq.extend(this._options, o);
289
-
290
- // number of files being uploaded
291
- this._filesInProgress = 0;
292
- // number of files was processed
293
- this._filesUploaded = 0;
294
- this._handler = this._createUploadHandler();
295
-
296
- if (this._options.button){
297
- this._button = this._createUploadButton(this._options.button);
298
- }
299
-
300
- this._preventLeaveInProgress();
301
- };
302
-
303
- qq.FileUploaderBasic.prototype = {
304
- setParams: function(params){
305
- this._options.params = params;
306
- },
307
- getInProgress: function(){
308
- return this._filesInProgress;
309
- },
310
- _createUploadButton: function(element){
311
- var self = this;
312
-
313
- return new qq.UploadButton({
314
- element: element,
315
- multiple: this._options.multiple && qq.UploadHandlerXhr.isSupported(),
316
- onChange: function(input){
317
- self._onInputChange(input);
318
- }
319
- });
320
- },
321
- _createUploadHandler: function(){
322
- var self = this,
323
- handlerClass;
324
-
325
- if(qq.UploadHandlerXhr.isSupported()){
326
- handlerClass = 'UploadHandlerXhr';
327
- } else {
328
- handlerClass = 'UploadHandlerForm';
329
- }
330
-
331
- var handler = new qq[handlerClass]({
332
- debug: this._options.debug,
333
- action: this._options.action,
334
- maxConnections: this._options.maxConnections,
335
- fieldName: this._options.fieldName,
336
- method: this._options.method,
337
- onProgress: function(id, fileName, loaded, total){
338
- self._onProgress(id, fileName, loaded, total);
339
- self._options.onProgress(id, fileName, loaded, total);
340
- },
341
- onComplete: function(id, fileName, result){
342
- self._onComplete(id, fileName, result);
343
- self._options.onComplete(id, fileName, result);
344
- },
345
- onCancel: function(id, fileName){
346
- self._onCancel(id, fileName);
347
- self._options.onCancel(id, fileName);
348
- }
349
- });
350
-
351
- return handler;
352
- },
353
- _preventLeaveInProgress: function(){
354
- var self = this;
355
-
356
- qq.attach(window, 'beforeunload', function(e){
357
- if (!self._filesInProgress){return;}
358
-
359
- var e = e || window.event;
360
- // for ie, ff
361
- e.returnValue = self._options.messages.onLeave;
362
- // for webkit
363
- return self._options.messages.onLeave;
364
- });
365
- },
366
- _onSubmit: function(id, fileName){
367
- this._filesInProgress++;
368
- },
369
- _onProgress: function(id, fileName, loaded, total){
370
- },
371
- _onComplete: function(id, fileName, result){
372
- this._filesInProgress--;
373
- if (result.error){
374
- this._options.showMessage(result.error);
375
- } else {
376
- this._filesUploaded++;
377
- }
378
- },
379
- _onCancel: function(id, fileName){
380
- this._filesInProgress--;
381
- },
382
- _onInputChange: function(input){
383
- if (this._handler instanceof qq.UploadHandlerXhr){
384
- this._uploadFileList(input.files);
385
- } else {
386
- if (this._validateFile(input)){
387
- this._uploadFile(input);
388
- }
389
- }
390
- this._button.reset();
391
- },
392
- _uploadFileList: function(files){
393
- if ( this._validateFiles(files) ) {
394
- for (var i=0; i<files.length; i++){
395
- this._uploadFile(files[i]);
396
- }
397
- }
398
- },
399
- _uploadFile: function(fileContainer){
400
- var id = this._handler.add(fileContainer);
401
- var fileName = this._handler.getName(id);
402
-
403
- if (this._options.onSubmit(id, fileName) !== false){
404
- this._onSubmit(id, fileName);
405
- this._handler.upload(id, this._options.params);
406
- }
407
- },
408
- _validateFiles: function(files){
409
- var uploadedCount = this._filesUploaded + files.length;
410
-
411
- if (this._options.maxFilesCount > 0) {
412
- if ( uploadedCount > this._options.maxFilesCount) {
413
- this._error('maxFilesError', 'name');
414
- return false;
415
- }
416
- }
417
-
418
- if (this._options.minFilesCount > 0) {
419
- if ( uploadedCount < this._options.minFilesCount) {
420
- this._error('minFilesError', 'name');
421
- return false;
422
- }
423
- }
424
-
425
- for (var i=0; i<files.length; i++){
426
- if ( !this._validateFile(files[i])){
427
- return false;
428
- }
429
- }
430
-
431
- return true;
432
- },
433
- _validateFile: function(file){
434
- var name, size;
435
-
436
- if (file.value){
437
- // it is a file input
438
- // get input value and remove path to normalize
439
- name = file.value.replace(/.*(\/|\\)/, "");
440
- } else {
441
- // fix missing properties in Safari
442
- name = file.fileName != null ? file.fileName : file.name;
443
- size = file.fileSize != null ? file.fileSize : file.size;
444
- }
445
-
446
- if (! this._isAllowedExtension(name)){
447
- this._error('typeError', name);
448
- return false;
449
-
450
- } else if (size === 0){
451
- this._error('emptyError', name);
452
- return false;
453
-
454
- } else if (size && this._options.sizeLimit && size > this._options.sizeLimit){
455
- this._error('sizeError', name);
456
- return false;
457
-
458
- } else if (size && size < this._options.minSizeLimit){
459
- this._error('minSizeError', name);
460
- return false;
461
- }
462
-
463
- return true;
464
- },
465
- _error: function(code, fileName){
466
- var message = this._options.messages[code];
467
- function r(name, replacement){ message = message.replace(name, replacement); }
468
-
469
- r('{file}', this._formatFileName(fileName));
470
- r('{extensions}', this._options.allowedExtensions.join(', '));
471
- r('{sizeLimit}', this._formatSize(this._options.sizeLimit));
472
- r('{minSizeLimit}', this._formatSize(this._options.minSizeLimit));
473
- r('{maxFilesCount}', this._options.maxFilesCount);
474
- r('{minFilesCount}', this._options.minFilesCount);
475
-
476
- this._options.showMessage(message);
477
- },
478
- _formatFileName: function(name){
479
- if (name.length > 33){
480
- name = name.slice(0, 19) + '...' + name.slice(-13);
481
- }
482
- return name;
483
- },
484
- _isAllowedExtension: function(fileName){
485
- var ext = (-1 !== fileName.indexOf('.')) ? fileName.replace(/.*[.]/, '').toLowerCase() : '';
486
- var allowed = this._options.allowedExtensions;
487
-
488
- if (!allowed.length){return true;}
489
-
490
- for (var i=0; i<allowed.length; i++){
491
- if (allowed[i].toLowerCase() == ext){ return true;}
492
- }
493
-
494
- return false;
495
- },
496
- _formatSize: function(bytes){
497
- var i = -1;
498
- do {
499
- bytes = bytes / 1024;
500
- i++;
501
- } while (bytes > 99);
502
-
503
- return Math.max(bytes, 0.1).toFixed(1) + ['kB', 'MB', 'GB', 'TB', 'PB', 'EB'][i];
504
- }
505
- };
506
-
507
-
508
- /**
509
- * Class that creates upload widget with drag-and-drop and file list
510
- * @inherits qq.FileUploaderBasic
511
- */
512
- qq.FileUploader = function(o){
513
- // call parent constructor
514
- qq.FileUploaderBasic.apply(this, arguments);
515
-
516
- // additional options
517
- qq.extend(this._options, {
518
- element: null,
519
- // if set, will be used instead of qq-upload-list in template
520
- listElement: null,
521
-
522
- template: '<div class="qq-uploader">' +
523
- '<div class="qq-upload-drop-area"><span>Drop files here to upload</span></div>' +
524
- '<div class="qq-upload-button">Upload a file</div>' +
525
- '<ul class="qq-upload-list"></ul>' +
526
- '</div>',
527
-
528
- // template for one item in file list
529
- fileTemplate: '<li>' +
530
- '<span class="qq-upload-file"></span>' +
531
- '<span class="qq-upload-spinner"></span>' +
532
- '<span class="qq-upload-size"></span>' +
533
- '<a class="qq-upload-cancel" href="#">Cancel</a>' +
534
- '<span class="qq-upload-failed-text">Failed</span>' +
535
- '</li>',
536
-
537
- classes: {
538
- // used to get elements from templates
539
- button: 'qq-upload-button',
540
- drop: 'qq-upload-drop-area',
541
- dropActive: 'qq-upload-drop-area-active',
542
- list: 'qq-upload-list',
543
-
544
- file: 'qq-upload-file',
545
- spinner: 'qq-upload-spinner',
546
- size: 'qq-upload-size',
547
- cancel: 'qq-upload-cancel',
548
-
549
- // added to list item when upload completes
550
- // used in css to hide progress spinner
551
- success: 'qq-upload-success',
552
- fail: 'qq-upload-fail'
553
- }
554
- });
555
- // overwrite options with user supplied
556
- qq.extend(this._options, o);
557
-
558
- this._element = this._options.element;
559
- this._element.innerHTML = this._options.template;
560
- this._listElement = this._options.listElement || this._find(this._element, 'list');
561
-
562
- this._classes = this._options.classes;
563
-
564
- this._button = this._createUploadButton(this._find(this._element, 'button'));
565
-
566
- this._bindCancelEvent();
567
- this._setupDragDrop();
568
- };
569
-
570
- // inherit from Basic Uploader
571
- qq.extend(qq.FileUploader.prototype, qq.FileUploaderBasic.prototype);
572
-
573
- qq.extend(qq.FileUploader.prototype, {
574
- /**
575
- * Gets one of the elements listed in this._options.classes
576
- **/
577
- _find: function(parent, type){
578
- var element = qq.getByClass(parent, this._options.classes[type])[0];
579
- if (!element){
580
- throw new Error('element not found ' + type);
581
- }
582
-
583
- return element;
584
- },
585
- _setupDragDrop: function(){
586
- var self = this,
587
- dropArea = this._find(this._element, 'drop');
588
-
589
- var dz = new qq.UploadDropZone({
590
- element: dropArea,
591
- onEnter: function(e){
592
- qq.addClass(dropArea, self._classes.dropActive);
593
- e.stopPropagation();
594
- },
595
- onLeave: function(e){
596
- e.stopPropagation();
597
- },
598
- onLeaveNotDescendants: function(e){
599
- qq.removeClass(dropArea, self._classes.dropActive);
600
- },
601
- onDrop: function(e){
602
- dropArea.style.display = 'none';
603
- qq.removeClass(dropArea, self._classes.dropActive);
604
- self._uploadFileList(e.dataTransfer.files);
605
- }
606
- });
607
-
608
- dropArea.style.display = 'none';
609
-
610
- qq.attach(document, 'dragenter', function(e){
611
- if (!dz._isValidFileDrag(e)) return;
612
-
613
- dropArea.style.display = 'block';
614
- });
615
- qq.attach(document, 'dragleave', function(e){
616
- if (!dz._isValidFileDrag(e)) return;
617
-
618
- var relatedTarget = document.elementFromPoint(e.clientX, e.clientY);
619
- // only fire when leaving document out
620
- if ( ! relatedTarget || relatedTarget.nodeName == "HTML"){
621
- dropArea.style.display = 'none';
622
- }
623
- });
624
- },
625
- _onSubmit: function(id, fileName){
626
- qq.FileUploaderBasic.prototype._onSubmit.apply(this, arguments);
627
- this._addToList(id, fileName);
628
- },
629
- _onProgress: function(id, fileName, loaded, total){
630
- qq.FileUploaderBasic.prototype._onProgress.apply(this, arguments);
631
-
632
- var item = this._getItemByFileId(id);
633
- var size = this._find(item, 'size');
634
- size.style.display = 'inline';
635
-
636
- var text;
637
- if (loaded != total){
638
- text = Math.round(loaded / total * 100) + '% from ' + this._formatSize(total);
639
- } else {
640
- text = this._formatSize(total);
641
- }
642
-
643
- qq.setText(size, text);
644
- },
645
- _onComplete: function(id, fileName, result){
646
- qq.FileUploaderBasic.prototype._onComplete.apply(this, arguments);
647
-
648
- // mark completed
649
- var item = this._getItemByFileId(id);
650
- qq.remove(this._find(item, 'cancel'));
651
- qq.remove(this._find(item, 'spinner'));
652
-
653
- if (result.success){
654
- qq.addClass(item, this._classes.success);
655
- } else {
656
- qq.addClass(item, this._classes.fail);
657
- }
658
- },
659
- _addToList: function(id, fileName){
660
- var item = qq.toElement(this._options.fileTemplate);
661
- item.qqFileId = id;
662
-
663
- var fileElement = this._find(item, 'file');
664
- qq.setText(fileElement, this._formatFileName(fileName));
665
- this._find(item, 'size').style.display = 'none';
666
-
667
- this._listElement.appendChild(item);
668
- },
669
- _getItemByFileId: function(id){
670
- var item = this._listElement.firstChild;
671
-
672
- // there can't be txt nodes in dynamically created list
673
- // and we can use nextSibling
674
- while (item){
675
- if (item.qqFileId == id) return item;
676
- item = item.nextSibling;
677
- }
678
- },
679
- /**
680
- * delegate click event for cancel link
681
- **/
682
- _bindCancelEvent: function(){
683
- var self = this,
684
- list = this._listElement;
685
-
686
- qq.attach(list, 'click', function(e){
687
- e = e || window.event;
688
- var target = e.target || e.srcElement;
689
-
690
- if (qq.hasClass(target, self._classes.cancel)){
691
- qq.preventDefault(e);
692
-
693
- var item = target.parentNode;
694
- self._handler.cancel(item.qqFileId);
695
- qq.remove(item);
696
- }
697
- });
698
- }
699
- });
700
-
701
- qq.UploadDropZone = function(o){
702
- this._options = {
703
- element: null,
704
- onEnter: function(e){},
705
- onLeave: function(e){},
706
- // is not fired when leaving element by hovering descendants
707
- onLeaveNotDescendants: function(e){},
708
- onDrop: function(e){}
709
- };
710
- qq.extend(this._options, o);
711
-
712
- this._element = this._options.element;
713
-
714
- this._disableDropOutside();
715
- this._attachEvents();
716
- };
717
-
718
- qq.UploadDropZone.prototype = {
719
- _disableDropOutside: function(e){
720
- // run only once for all instances
721
- if (!qq.UploadDropZone.dropOutsideDisabled ){
722
-
723
- qq.attach(document, 'dragover', function(e){
724
- if (e.dataTransfer){
725
- e.dataTransfer.dropEffect = 'none';
726
- e.preventDefault();
727
- }
728
- });
729
-
730
- qq.UploadDropZone.dropOutsideDisabled = true;
731
- }
732
- },
733
- _attachEvents: function(){
734
- var self = this;
735
-
736
- qq.attach(self._element, 'dragover', function(e){
737
- if (!self._isValidFileDrag(e)) return;
738
-
739
- var effect = e.dataTransfer.effectAllowed;
740
- if (effect == 'move' || effect == 'linkMove'){
741
- e.dataTransfer.dropEffect = 'move'; // for FF (only move allowed)
742
- } else {
743
- e.dataTransfer.dropEffect = 'copy'; // for Chrome
744
- }
745
-
746
- e.stopPropagation();
747
- e.preventDefault();
748
- });
749
-
750
- qq.attach(self._element, 'dragenter', function(e){
751
- if (!self._isValidFileDrag(e)) return;
752
-
753
- self._options.onEnter(e);
754
- });
755
-
756
- qq.attach(self._element, 'dragleave', function(e){
757
- if (!self._isValidFileDrag(e)) return;
758
-
759
- self._options.onLeave(e);
760
-
761
- var relatedTarget = document.elementFromPoint(e.clientX, e.clientY);
762
- // do not fire when moving a mouse over a descendant
763
- if (qq.contains(this, relatedTarget)) return;
764
-
765
- self._options.onLeaveNotDescendants(e);
766
- });
767
-
768
- qq.attach(self._element, 'drop', function(e){
769
- if (!self._isValidFileDrag(e)) return;
770
-
771
- e.preventDefault();
772
- self._options.onDrop(e);
773
- });
774
- },
775
- _isValidFileDrag: function(e){
776
- var dt = e.dataTransfer,
777
- // do not check dt.types.contains in webkit, because it crashes safari 4
778
- isWebkit = navigator.userAgent.indexOf("AppleWebKit") > -1;
779
-
780
- // dt.effectAllowed is none in Safari 5
781
- // dt.types.contains check is for firefox
782
- return dt && dt.effectAllowed != 'none' &&
783
- (dt.files || (!isWebkit && dt.types.contains && dt.types.contains('Files')));
784
-
785
- }
786
- };
787
-
788
- qq.UploadButton = function(o){
789
- this._options = {
790
- element: null,
791
- // if set to true adds multiple attribute to file input
792
- multiple: false,
793
- // name attribute of file input
794
- name: 'file',
795
- onChange: function(input){},
796
- hoverClass: 'qq-upload-button-hover',
797
- focusClass: 'qq-upload-button-focus'
798
- };
799
-
800
- qq.extend(this._options, o);
801
-
802
- this._element = this._options.element;
803
-
804
- // make button suitable container for input
805
- qq.css(this._element, {
806
- position: 'relative',
807
- overflow: 'hidden',
808
- // Make sure browse button is in the right side
809
- // in Internet Explorer
810
- direction: 'ltr'
811
- });
812
-
813
- this._input = this._createInput();
814
- };
815
-
816
- qq.UploadButton.prototype = {
817
- /* returns file input element */
818
- getInput: function(){
819
- return this._input;
820
- },
821
- /* cleans/recreates the file input */
822
- reset: function(){
823
- if (this._input.parentNode){
824
- qq.remove(this._input);
825
- }
826
-
827
- qq.removeClass(this._element, this._options.focusClass);
828
- this._input = this._createInput();
829
- },
830
- _createInput: function(){
831
- var input = document.createElement("input");
832
-
833
- if (this._options.multiple){
834
- input.setAttribute("multiple", "multiple");
835
- }
836
-
837
- input.setAttribute("type", "file");
838
- input.setAttribute("name", this._options.name);
839
-
840
- qq.css(input, {
841
- position: 'absolute',
842
- // in Opera only 'browse' button
843
- // is clickable and it is located at
844
- // the right side of the input
845
- right: 0,
846
- top: 0,
847
- fontFamily: 'Arial',
848
- // 4 persons reported this, the max values that worked for them were 243, 236, 236, 118
849
- fontSize: '118px',
850
- margin: 0,
851
- padding: 0,
852
- cursor: 'pointer',
853
- opacity: 0
854
- });
855
-
856
- this._element.appendChild(input);
857
-
858
- var self = this;
859
- qq.attach(input, 'change', function(){
860
- self._options.onChange(input);
861
- });
862
-
863
- qq.attach(input, 'mouseover', function(){
864
- qq.addClass(self._element, self._options.hoverClass);
865
- });
866
- qq.attach(input, 'mouseout', function(){
867
- qq.removeClass(self._element, self._options.hoverClass);
868
- });
869
- qq.attach(input, 'focus', function(){
870
- qq.addClass(self._element, self._options.focusClass);
871
- });
872
- qq.attach(input, 'blur', function(){
873
- qq.removeClass(self._element, self._options.focusClass);
874
- });
875
-
876
- // IE and Opera, unfortunately have 2 tab stops on file input
877
- // which is unacceptable in our case, disable keyboard access
878
- if (window.attachEvent){
879
- // it is IE or Opera
880
- input.setAttribute('tabIndex', "-1");
881
- }
882
-
883
- return input;
884
- }
885
- };
886
-
887
- /**
888
- * Class for uploading files, uploading itself is handled by child classes
889
- */
890
- qq.UploadHandlerAbstract = function(o){
891
- this._options = {
892
- debug: false,
893
- action: '/upload.php',
894
- method: 'POST',
895
- fieldName: 'qqfile',
896
- // maximum number of concurrent uploads
897
- maxConnections: 999,
898
- onProgress: function(id, fileName, loaded, total){},
899
- onComplete: function(id, fileName, response){},
900
- onCancel: function(id, fileName){}
901
- };
902
- qq.extend(this._options, o);
903
-
904
- this._queue = [];
905
- // params for files in queue
906
- this._params = [];
907
- };
908
- qq.UploadHandlerAbstract.prototype = {
909
- log: function(str){
910
- if (this._options.debug && window.console) console.log('[uploader] ' + str);
911
- },
912
- /**
913
- * Adds file or file input to the queue
914
- * @returns id
915
- **/
916
- add: function(file){},
917
- /**
918
- * Sends the file identified by id and additional query params to the server
919
- */
920
- upload: function(id, params){
921
- var len = this._queue.push(id);
922
-
923
- var copy = {};
924
- qq.extend(copy, params);
925
- this._params[id] = copy;
926
-
927
- // if too many active uploads, wait...
928
- if (len <= this._options.maxConnections){
929
- this._upload(id, this._params[id]);
930
- }
931
- },
932
- /**
933
- * Cancels file upload by id
934
- */
935
- cancel: function(id){
936
- this._cancel(id);
937
- this._dequeue(id);
938
- },
939
- /**
940
- * Cancells all uploads
941
- */
942
- cancelAll: function(){
943
- for (var i=0; i<this._queue.length; i++){
944
- this._cancel(this._queue[i]);
945
- }
946
- this._queue = [];
947
- },
948
- /**
949
- * Returns name of the file identified by id
950
- */
951
- getName: function(id){},
952
- /**
953
- * Returns size of the file identified by id
954
- */
955
- getSize: function(id){},
956
- /**
957
- * Returns id of files being uploaded or
958
- * waiting for their turn
959
- */
960
- getQueue: function(){
961
- return this._queue;
962
- },
963
- /**
964
- * Actual upload method
965
- */
966
- _upload: function(id){},
967
- /**
968
- * Actual cancel method
969
- */
970
- _cancel: function(id){},
971
- /**
972
- * Removes element from queue, starts upload of next
973
- */
974
- _dequeue: function(id){
975
- var i = qq.indexOf(this._queue, id);
976
- this._queue.splice(i, 1);
977
-
978
- var max = this._options.maxConnections;
979
-
980
- if (this._queue.length >= max && i < max){
981
- var nextId = this._queue[max-1];
982
- this._upload(nextId, this._params[nextId]);
983
- }
984
- }
985
- };
986
-
987
- /**
988
- * Class for uploading files using form and iframe
989
- * @inherits qq.UploadHandlerAbstract
990
- */
991
- qq.UploadHandlerForm = function(o){
992
- qq.UploadHandlerAbstract.apply(this, arguments);
993
-
994
- this._inputs = {};
995
- };
996
- // @inherits qq.UploadHandlerAbstract
997
- qq.extend(qq.UploadHandlerForm.prototype, qq.UploadHandlerAbstract.prototype);
998
-
999
- qq.extend(qq.UploadHandlerForm.prototype, {
1000
- add: function(fileInput){
1001
- fileInput.setAttribute('name', this._options.fieldName);
1002
- var id = 'qq-upload-handler-iframe' + qq.getUniqueId();
1003
-
1004
- this._inputs[id] = fileInput;
1005
-
1006
- // remove file input from DOM
1007
- if (fileInput.parentNode){
1008
- qq.remove(fileInput);
1009
- }
1010
-
1011
- return id;
1012
- },
1013
- getName: function(id){
1014
- // get input value and remove path to normalize
1015
- return this._inputs[id].value.replace(/.*(\/|\\)/, "");
1016
- },
1017
- _cancel: function(id){
1018
- this._options.onCancel(id, this.getName(id));
1019
-
1020
- delete this._inputs[id];
1021
-
1022
- var iframe = document.getElementById(id);
1023
- if (iframe){
1024
- // to cancel request set src to something else
1025
- // we use src="javascript:false;" because it doesn't
1026
- // trigger ie6 prompt on https
1027
- iframe.setAttribute('src', 'javascript:false;');
1028
-
1029
- qq.remove(iframe);
1030
- }
1031
- },
1032
- _upload: function(id, params){
1033
- var input = this._inputs[id];
1034
-
1035
- if (!input){
1036
- throw new Error('file with passed id was not added, or already uploaded or cancelled');
1037
- }
1038
-
1039
- var fileName = this.getName(id);
1040
-
1041
- var iframe = this._createIframe(id);
1042
- var form = this._createForm(iframe, params);
1043
- form.appendChild(input);
1044
-
1045
- var self = this;
1046
- this._attachLoadEvent(iframe, function(){
1047
- self.log('iframe loaded');
1048
-
1049
- var response = self._getIframeContentJSON(iframe);
1050
-
1051
- self._options.onComplete(id, fileName, response);
1052
- self._dequeue(id);
1053
-
1054
- delete self._inputs[id];
1055
- // timeout added to fix busy state in FF3.6
1056
- setTimeout(function(){
1057
- qq.remove(iframe);
1058
- }, 1);
1059
- });
1060
-
1061
- form.submit();
1062
- qq.remove(form);
1063
-
1064
- return id;
1065
- },
1066
- _attachLoadEvent: function(iframe, callback){
1067
- qq.attach(iframe, 'load', function(){
1068
- // when we remove iframe from dom
1069
- // the request stops, but in IE load
1070
- // event fires
1071
- if (!iframe.parentNode){
1072
- return;
1073
- }
1074
-
1075
- // fixing Opera 10.53
1076
- if (iframe.contentDocument &&
1077
- iframe.contentDocument.body &&
1078
- iframe.contentDocument.body.innerHTML == "false"){
1079
- // In Opera event is fired second time
1080
- // when body.innerHTML changed from false
1081
- // to server response approx. after 1 sec
1082
- // when we upload file with iframe
1083
- return;
1084
- }
1085
-
1086
- callback();
1087
- });
1088
- },
1089
- /**
1090
- * Returns json object received by iframe from server.
1091
- */
1092
- _getIframeContentJSON: function(iframe){
1093
- // iframe.contentWindow.document - for IE<7
1094
- var doc = iframe.contentDocument ? iframe.contentDocument: iframe.contentWindow.document,
1095
- response;
1096
-
1097
- this.log("converting iframe's innerHTML to JSON");
1098
- this.log("innerHTML = " + doc.body.innerHTML);
1099
-
1100
- try {
1101
- response = eval("(" + doc.body.innerHTML + ")");
1102
- } catch(err){
1103
- response = {};
1104
- }
1105
-
1106
- return response;
1107
- },
1108
- /**
1109
- * Creates iframe with unique name
1110
- */
1111
- _createIframe: function(id){
1112
- // We can't use following code as the name attribute
1113
- // won't be properly registered in IE6, and new window
1114
- // on form submit will open
1115
- // var iframe = document.createElement('iframe');
1116
- // iframe.setAttribute('name', id);
1117
-
1118
- var iframe = qq.toElement('<iframe src="javascript:false;" name="' + id + '" />');
1119
- // src="javascript:false;" removes ie6 prompt on https
1120
-
1121
- iframe.setAttribute('id', id);
1122
-
1123
- iframe.style.display = 'none';
1124
- document.body.appendChild(iframe);
1125
-
1126
- return iframe;
1127
- },
1128
- /**
1129
- * Creates form, that will be submitted to iframe
1130
- */
1131
- _createForm: function(iframe, params){
1132
- // We can't use the following code in IE6
1133
- // var form = document.createElement('form');
1134
- // form.setAttribute('method', 'post');
1135
- // form.setAttribute('enctype', 'multipart/form-data');
1136
- // Because in this case file won't be attached to request
1137
- var form = qq.toElement('<form enctype="multipart/form-data"></form>');
1138
-
1139
- var queryString = qq.obj2url(params, this._options.action);
1140
-
1141
- form.setAttribute('method', this._options.method);
1142
- form.setAttribute('action', queryString);
1143
- form.setAttribute('target', iframe.name);
1144
- form.style.display = 'none';
1145
-
1146
- // Rails CSRFProtection
1147
- var token = $('meta[name="csrf-token"]').attr('content');
1148
- var param = $('meta[name="csrf-param"]').attr('content');
1149
- var input = qq.toElement('<input type="hidden" />');
1150
-
1151
- input.setAttribute('name', param);
1152
- input.setAttribute('value', token);
1153
-
1154
- form.appendChild(input);
1155
- document.body.appendChild(form);
1156
-
1157
- return form;
1158
- }
1159
- });
1160
-
1161
- /**
1162
- * Class for uploading files using xhr
1163
- * @inherits qq.UploadHandlerAbstract
1164
- */
1165
- qq.UploadHandlerXhr = function(o){
1166
- qq.UploadHandlerAbstract.apply(this, arguments);
1167
-
1168
- this._files = [];
1169
- this._xhrs = [];
1170
-
1171
- // current loaded size in bytes for each file
1172
- this._loaded = [];
1173
- };
1174
-
1175
- // static method
1176
- qq.UploadHandlerXhr.isSupported = function(){
1177
- var input = document.createElement('input');
1178
- input.type = 'file';
1179
-
1180
- return (
1181
- 'multiple' in input &&
1182
- typeof File != "undefined" &&
1183
- typeof (new XMLHttpRequest()).upload != "undefined" );
1184
- };
1185
-
1186
- // @inherits qq.UploadHandlerAbstract
1187
- qq.extend(qq.UploadHandlerXhr.prototype, qq.UploadHandlerAbstract.prototype)
1188
-
1189
- qq.extend(qq.UploadHandlerXhr.prototype, {
1190
- /**
1191
- * Adds file to the queue
1192
- * Returns id to use with upload, cancel
1193
- **/
1194
- add: function(file){
1195
- if (!(file instanceof File)){
1196
- throw new Error('Passed obj in not a File (in qq.UploadHandlerXhr)');
1197
- }
1198
-
1199
- return this._files.push(file) - 1;
1200
- },
1201
- getName: function(id){
1202
- var file = this._files[id];
1203
- // fix missing name in Safari 4
1204
- return file.fileName != null ? file.fileName : file.name;
1205
- },
1206
- getSize: function(id){
1207
- var file = this._files[id];
1208
- return file.fileSize != null ? file.fileSize : file.size;
1209
- },
1210
- /**
1211
- * Returns uploaded bytes for file identified by id
1212
- */
1213
- getLoaded: function(id){
1214
- return this._loaded[id] || 0;
1215
- },
1216
- /**
1217
- * Sends the file identified by id and additional query params to the server
1218
- * @param {Object} params name-value string pairs
1219
- */
1220
- _upload: function(id, params){
1221
- var file = this._files[id],
1222
- name = this.getName(id),
1223
- size = this.getSize(id);
1224
-
1225
- this._loaded[id] = 0;
1226
-
1227
- var xhr = this._xhrs[id] = new XMLHttpRequest();
1228
- var self = this;
1229
-
1230
- xhr.upload.onprogress = function(e){
1231
- if (e.lengthComputable){
1232
- self._loaded[id] = e.loaded;
1233
- self._options.onProgress(id, name, e.loaded, e.total);
1234
- }
1235
- };
1236
-
1237
- xhr.onreadystatechange = function(){
1238
- if (xhr.readyState == 4){
1239
- self._onComplete(id, xhr);
1240
- }
1241
- };
1242
-
1243
- // build query string
1244
- params = params || {};
1245
- params[this._options.fieldName] = name;
1246
- var queryString = qq.obj2url(params, this._options.action);
1247
-
1248
- xhr.open(this._options.method, queryString, true);
1249
- xhr.setRequestHeader("X-Requested-With", "XMLHttpRequest");
1250
- xhr.setRequestHeader("X-File-Name", encodeURIComponent(name));
1251
- xhr.setRequestHeader('X-File-Size', size);
1252
- xhr.setRequestHeader('X-File-Type', file.type);
1253
- xhr.setRequestHeader("Content-Type", "application/octet-stream");
1254
-
1255
- // Rails CSRFProtection
1256
- if ($.rails) $.rails.CSRFProtection(xhr);
1257
-
1258
- xhr.send(file);
1259
- },
1260
- _onComplete: function(id, xhr){
1261
- // the request was aborted/cancelled
1262
- if (!this._files[id]) return;
1263
-
1264
- var name = this.getName(id);
1265
- var size = this.getSize(id);
1266
-
1267
- this._options.onProgress(id, name, size, size);
1268
-
1269
- if ([200, 201].indexOf( xhr.status ) > -1){
1270
- this.log("xhr - server response received");
1271
- this.log("responseText = " + xhr.responseText);
1272
-
1273
- var response;
1274
-
1275
- try {
1276
- response = eval("(" + xhr.responseText + ")");
1277
- } catch(err){
1278
- response = {};
1279
- }
1280
-
1281
- this._options.onComplete(id, name, response);
1282
-
1283
- } else {
1284
- this._options.onComplete(id, name, {});
1285
- }
1286
-
1287
- this._files[id] = null;
1288
- this._xhrs[id] = null;
1289
- this._dequeue(id);
1290
- },
1291
- _cancel: function(id){
1292
- this._options.onCancel(id, this.getName(id));
1293
-
1294
- this._files[id] = null;
1295
-
1296
- if (this._xhrs[id]){
1297
- this._xhrs[id].abort();
1298
- this._xhrs[id] = null;
1299
- }
1300
- }
1301
- });