archangel 0.3.0 → 0.4.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (589) hide show
  1. checksums.yaml +4 -4
  2. data/.codeclimate.yml +5 -1
  3. data/.erb-lint.yml +23 -0
  4. data/.eslintrc.json +1 -1
  5. data/.nvmrc +1 -1
  6. data/.rubocop.yml +7 -1
  7. data/.rubocop_exclude.yml +0 -1
  8. data/.sass-lint.yml +8 -0
  9. data/.travis.yml +13 -5
  10. data/Gemfile +19 -13
  11. data/README.md +10 -6
  12. data/app/assets/javascripts/archangel/input/datetimepicker.js +31 -77
  13. data/app/assets/javascripts/archangel/input/meta_keywords.js +0 -12
  14. data/app/assets/javascripts/archangel/input/wysiwyg.js.erb +51 -36
  15. data/app/assets/javascripts/archangel/object/flash.js +11 -8
  16. data/app/assets/javascripts/archangel/object/routes/backend.js +10 -10
  17. data/app/controllers/archangel/application_controller.rb +23 -13
  18. data/app/controllers/archangel/auth/invitations_controller.rb +22 -0
  19. data/app/controllers/archangel/auth/registrations_controller.rb +7 -3
  20. data/app/controllers/archangel/auth_controller.rb +8 -3
  21. data/app/controllers/archangel/backend/assets_controller.rb +9 -11
  22. data/app/controllers/archangel/backend/collections_controller.rb +3 -3
  23. data/app/controllers/archangel/backend/dashboards_controller.rb +1 -1
  24. data/app/controllers/archangel/backend/designs_controller.rb +43 -0
  25. data/app/controllers/archangel/backend/entries_controller.rb +25 -40
  26. data/app/controllers/archangel/backend/pages_controller.rb +7 -5
  27. data/app/controllers/archangel/backend/profiles_controller.rb +3 -2
  28. data/app/controllers/archangel/backend/sites_controller.rb +8 -14
  29. data/app/controllers/archangel/backend/users_controller.rb +6 -11
  30. data/app/controllers/archangel/backend/widgets_controller.rb +3 -3
  31. data/app/controllers/archangel/backend_controller.rb +6 -4
  32. data/app/controllers/archangel/frontend/homepages_controller.rb +33 -0
  33. data/app/controllers/archangel/frontend/pages_controller.rb +32 -43
  34. data/app/controllers/archangel/frontend_controller.rb +25 -1
  35. data/app/controllers/concerns/archangel/controllers/authenticatable_concern.rb +19 -0
  36. data/app/controllers/concerns/archangel/controllers/authorizable_concern.rb +19 -0
  37. data/app/controllers/concerns/archangel/controllers/metatagable_concern.rb +45 -0
  38. data/app/controllers/concerns/archangel/controllers/paginatable_concern.rb +43 -0
  39. data/app/controllers/concerns/archangel/controllers/resourceful_concern.rb +63 -26
  40. data/app/controllers/concerns/archangel/controllers/skip_authorizable_concern.rb +19 -0
  41. data/app/controllers/concerns/archangel/controllers/themable_concern.rb +34 -0
  42. data/app/controllers/concerns/archangel/helpers/actionable_concern.rb +76 -0
  43. data/app/helpers/archangel/application_helper.rb +35 -1
  44. data/app/helpers/archangel/backend/metatags_helper.rb +52 -0
  45. data/app/models/archangel/asset.rb +1 -1
  46. data/app/models/archangel/collection.rb +4 -7
  47. data/app/models/archangel/{template.rb → design.rb} +5 -13
  48. data/app/models/archangel/entry.rb +8 -28
  49. data/app/models/archangel/field.rb +1 -1
  50. data/app/models/archangel/page.rb +12 -48
  51. data/app/models/archangel/site.rb +17 -11
  52. data/app/models/archangel/user.rb +14 -7
  53. data/app/models/archangel/widget.rb +4 -4
  54. data/app/models/concerns/archangel/models/entry_validatable_concern.rb +74 -0
  55. data/app/models/concerns/archangel/models/metatagable_concern.rb +22 -0
  56. data/app/models/concerns/archangel/models/publishable_concern.rb +57 -0
  57. data/app/{helpers/archangel/auth_helper.rb → policies/archangel/design_policy.rb} +2 -2
  58. data/app/policies/archangel/site_policy.rb +0 -9
  59. data/app/services/archangel/{template_render_service.rb → design_render_service.rb} +3 -3
  60. data/app/services/archangel/render_service.rb +1 -1
  61. data/app/themes/default/assets/javascripts/default/auth.js +10 -13
  62. data/app/themes/default/assets/javascripts/default/backend.js +16 -37
  63. data/app/themes/default/assets/javascripts/default/backend/archangel.js +25 -0
  64. data/app/themes/default/assets/javascripts/default/backend/entries/sorting.js +37 -0
  65. data/app/themes/default/assets/javascripts/default/backend/misc/metatags.js +16 -0
  66. data/app/themes/default/assets/javascripts/default/common/flash.js +4 -43
  67. data/app/themes/default/assets/javascripts/default/frontend.js +11 -13
  68. data/app/themes/default/assets/stylesheets/default/_theme.scss +13 -0
  69. data/app/themes/default/assets/stylesheets/default/_variables.scss +113 -0
  70. data/app/themes/default/assets/stylesheets/default/auth.css +15 -13
  71. data/app/themes/default/assets/stylesheets/default/auth/_flash.scss +9 -0
  72. data/app/themes/default/assets/stylesheets/default/auth/default.scss +7 -0
  73. data/app/themes/default/assets/stylesheets/default/backend.css +10 -9
  74. data/app/themes/default/assets/stylesheets/default/backend/_entries.scss +25 -0
  75. data/app/themes/default/assets/stylesheets/default/backend/_flash.scss +19 -0
  76. data/app/themes/default/assets/stylesheets/default/backend/_footer.scss +15 -0
  77. data/app/themes/default/assets/stylesheets/default/backend/_global.scss +22 -0
  78. data/app/themes/default/assets/stylesheets/default/backend/_sidebar.scss +60 -0
  79. data/app/themes/default/assets/stylesheets/default/backend/_tables.scss +18 -0
  80. data/app/themes/default/assets/stylesheets/default/backend/_top.scss +25 -0
  81. data/app/themes/default/assets/stylesheets/default/backend/default.scss +16 -0
  82. data/app/themes/default/assets/stylesheets/default/common/_borders.scss +7 -0
  83. data/app/themes/default/assets/stylesheets/default/common/_cards.scss +15 -0
  84. data/app/themes/default/assets/stylesheets/default/common/_forms.scss +5 -0
  85. data/app/themes/default/assets/stylesheets/default/common/_global.scss +8 -0
  86. data/app/themes/default/assets/stylesheets/default/common/_mixins.scss +38 -0
  87. data/app/themes/default/assets/stylesheets/default/common/_navbar.scss +90 -0
  88. data/app/themes/default/assets/stylesheets/default/frontend.css +15 -13
  89. data/app/themes/default/assets/stylesheets/default/frontend/default.scss +5 -0
  90. data/app/themes/default/views/layouts/auth.html.erb +10 -8
  91. data/app/themes/default/views/layouts/backend.html.erb +16 -9
  92. data/app/themes/default/views/layouts/backend/_footer.html.erb +10 -6
  93. data/app/themes/default/views/layouts/backend/_header.html.erb +28 -24
  94. data/app/themes/default/views/layouts/backend/_sidebar.html.erb +65 -45
  95. data/app/themes/default/views/layouts/frontend.html.erb +20 -0
  96. data/app/views/archangel/backend/assets/_asset.html.erb +14 -7
  97. data/app/views/archangel/backend/assets/_buttons.html.erb +7 -5
  98. data/app/views/archangel/backend/assets/_form.html.erb +1 -1
  99. data/app/views/archangel/backend/assets/edit.html.erb +8 -14
  100. data/app/views/archangel/backend/assets/index.html.erb +36 -44
  101. data/app/views/archangel/backend/assets/new.html.erb +8 -14
  102. data/app/views/archangel/backend/assets/show.html.erb +33 -39
  103. data/app/views/archangel/backend/collections/_buttons.html.erb +8 -6
  104. data/app/views/archangel/backend/collections/_collection.html.erb +5 -4
  105. data/app/views/archangel/backend/collections/_form.html.erb +1 -1
  106. data/app/views/archangel/backend/collections/edit.html.erb +8 -14
  107. data/app/views/archangel/backend/collections/index.html.erb +34 -42
  108. data/app/views/archangel/backend/collections/new.html.erb +8 -14
  109. data/app/views/archangel/backend/collections/show.html.erb +21 -27
  110. data/app/views/archangel/backend/dashboards/show.html.erb +7 -17
  111. data/app/views/archangel/backend/designs/_buttons.html.erb +20 -0
  112. data/app/views/archangel/backend/designs/_design.html.erb +11 -0
  113. data/app/views/archangel/backend/{templates → designs}/_form.html.erb +2 -2
  114. data/app/views/archangel/backend/designs/edit.html.erb +15 -0
  115. data/app/views/archangel/backend/designs/index.html.erb +43 -0
  116. data/app/views/archangel/backend/designs/new.html.erb +15 -0
  117. data/app/views/archangel/backend/designs/show.html.erb +23 -0
  118. data/app/views/archangel/backend/entries/_buttons.html.erb +8 -6
  119. data/app/views/archangel/backend/entries/_entry.html.erb +17 -9
  120. data/app/views/archangel/backend/entries/_form.html.erb +6 -11
  121. data/app/views/archangel/backend/entries/edit.html.erb +8 -14
  122. data/app/views/archangel/backend/entries/index.html.erb +39 -47
  123. data/app/views/archangel/backend/entries/new.html.erb +8 -14
  124. data/app/views/archangel/backend/entries/show.html.erb +14 -20
  125. data/app/views/archangel/backend/pages/_buttons.html.erb +7 -5
  126. data/app/views/archangel/backend/pages/_form.html.erb +4 -3
  127. data/app/views/archangel/backend/pages/_metatag_fields.html.erb +3 -3
  128. data/app/views/archangel/backend/pages/_page.html.erb +13 -8
  129. data/app/views/archangel/backend/pages/edit.html.erb +8 -14
  130. data/app/views/archangel/backend/pages/index.html.erb +35 -43
  131. data/app/views/archangel/backend/pages/new.html.erb +8 -14
  132. data/app/views/archangel/backend/pages/show.html.erb +15 -31
  133. data/app/views/archangel/backend/profiles/_buttons.html.erb +7 -2
  134. data/app/views/archangel/backend/profiles/_form.html.erb +4 -2
  135. data/app/views/archangel/backend/profiles/edit.html.erb +8 -14
  136. data/app/views/archangel/backend/profiles/show.html.erb +20 -26
  137. data/app/views/archangel/backend/sites/_buttons.html.erb +2 -2
  138. data/app/views/archangel/backend/sites/_form.html.erb +10 -2
  139. data/app/views/archangel/backend/sites/_metatag_fields.html.erb +3 -3
  140. data/app/views/archangel/backend/sites/edit.html.erb +8 -14
  141. data/app/views/archangel/backend/sites/show.html.erb +22 -28
  142. data/app/views/archangel/backend/users/_buttons.html.erb +7 -5
  143. data/app/views/archangel/backend/users/_form.html.erb +1 -1
  144. data/app/views/archangel/backend/users/_user.html.erb +10 -6
  145. data/app/views/archangel/backend/users/edit.html.erb +8 -14
  146. data/app/views/archangel/backend/users/index.html.erb +35 -43
  147. data/app/views/archangel/backend/users/new.html.erb +8 -14
  148. data/app/views/archangel/backend/users/show.html.erb +16 -27
  149. data/app/views/archangel/backend/widgets/_buttons.html.erb +7 -5
  150. data/app/views/archangel/backend/widgets/_form.html.erb +2 -2
  151. data/app/views/archangel/backend/widgets/_widget.html.erb +5 -4
  152. data/app/views/archangel/backend/widgets/edit.html.erb +8 -14
  153. data/app/views/archangel/backend/widgets/index.html.erb +34 -42
  154. data/app/views/archangel/backend/widgets/new.html.erb +8 -14
  155. data/app/views/archangel/backend/widgets/show.html.erb +20 -31
  156. data/app/views/archangel/frontend/pages/show.json.jbuilder +4 -3
  157. data/app/views/archangel/shared/_flash_messages.html.erb +5 -2
  158. data/app/views/devise/confirmations/new.html.erb +10 -8
  159. data/app/views/devise/invitations/edit.html.erb +17 -0
  160. data/app/views/devise/invitations/new.html.erb +15 -0
  161. data/app/views/devise/mailer/invitation_instructions.html.erb +11 -0
  162. data/app/views/devise/mailer/invitation_instructions.text.erb +11 -0
  163. data/app/views/devise/passwords/edit.html.erb +14 -18
  164. data/app/views/devise/passwords/new.html.erb +8 -8
  165. data/app/views/devise/registrations/edit.html.erb +18 -28
  166. data/app/views/devise/registrations/new.html.erb +19 -31
  167. data/app/views/devise/sessions/new.html.erb +11 -19
  168. data/app/views/devise/shared/_error_messages.html.erb +15 -0
  169. data/app/views/devise/shared/_links.html.erb +19 -35
  170. data/app/views/devise/unlocks/new.html.erb +9 -8
  171. data/archangel.gemspec +12 -14
  172. data/config/initializers/devise.rb +1 -1
  173. data/config/initializers/simple_form.rb +18 -6
  174. data/config/initializers/simple_form_bootstrap.rb +520 -88
  175. data/config/locales/active_record.en.yml +14 -10
  176. data/config/locales/en.yml +10 -43
  177. data/config/locales/simple_form.en.yml +8 -7
  178. data/config/routes.rb +27 -40
  179. data/db/migrate/20190408164034_rename_archangel_pages_path_to_permalink.rb +5 -0
  180. data/db/migrate/20190417194514_add_settings_to_archangel_sites.rb +5 -0
  181. data/db/migrate/20190418150532_rename_archangel_templates_to_archangel_designs.rb +5 -0
  182. data/db/migrate/20190418150533_rename_archangel_pages_template_id_to_design_id.rb +5 -0
  183. data/db/migrate/20190418150534_rename_archangel_widgets_template_id_to_design_id.rb +5 -0
  184. data/db/migrate/20190421165525_rename_archangel_entries_available_at_to_published_at.rb +5 -0
  185. data/db/seeds.rb +41 -46
  186. data/docs/Developers.md +9 -7
  187. data/docs/Extension/Controllers.md +1 -1
  188. data/docs/Extension/Uploaders.md +1 -1
  189. data/lib/archangel.rb +2 -11
  190. data/lib/archangel/commands/base_command.rb +4 -8
  191. data/lib/archangel/commands/extension_command.rb +14 -14
  192. data/lib/archangel/commands/templates/common/Gemfile +24 -0
  193. data/lib/archangel/commands/templates/{extension → common}/Rakefile +1 -1
  194. data/lib/archangel/commands/templates/{extension → common}/bin/rails.tt +0 -0
  195. data/lib/archangel/commands/templates/{extension → common}/lib/%extension_name%.rb.tt +0 -0
  196. data/lib/archangel/commands/templates/{extension → common}/lib/%extension_name%/engine.rb.tt +0 -0
  197. data/lib/archangel/commands/templates/{extension → common}/lib/%extension_name%/version.rb.tt +0 -0
  198. data/lib/archangel/commands/templates/common/spec/rails_helper.rb.tt +0 -4
  199. data/lib/archangel/commands/templates/extension/lib/generators/%extension_name%/install/install_generator.rb.tt +10 -10
  200. data/lib/archangel/commands/templates/theme/README.md +2 -2
  201. data/lib/archangel/commands/templates/theme/app/themes/%theme_base_name%/config/locales/en.yml.tt +1 -1
  202. data/lib/archangel/commands/templates/theme/app/themes/%theme_base_name%/views/layouts/frontend.html.erb +20 -0
  203. data/lib/archangel/commands/templates/theme/theme.gemspec.tt +3 -3
  204. data/lib/archangel/commands/theme_command.rb +30 -27
  205. data/lib/archangel/config.rb +1 -2
  206. data/lib/archangel/constants/theme.rb +1 -1
  207. data/lib/archangel/engine.rb +3 -1
  208. data/lib/archangel/i18n.rb +5 -1
  209. data/lib/archangel/liquid/drop.rb +3 -45
  210. data/lib/archangel/liquid/drops/page_drop.rb +4 -4
  211. data/lib/archangel/liquid/drops/site_drop.rb +1 -0
  212. data/lib/archangel/liquid/tags/asset_tag.rb +4 -5
  213. data/lib/archangel/liquid/tags/collection_tag.rb +3 -5
  214. data/lib/archangel/liquid/tags/collectionfor_tag.rb +3 -4
  215. data/lib/archangel/liquid/tags/gist_tag.rb +3 -3
  216. data/lib/archangel/liquid/tags/noembed_tag.rb +1 -1
  217. data/lib/archangel/liquid/tags/vimeo_tag.rb +15 -9
  218. data/lib/archangel/liquid/tags/widget_tag.rb +9 -12
  219. data/lib/archangel/liquid/tags/youtube_tag.rb +44 -30
  220. data/lib/archangel/testing_support/factories/{archangel_templates.rb → archangel_designs.rb} +4 -4
  221. data/lib/archangel/testing_support/factories/archangel_entries.rb +5 -5
  222. data/lib/archangel/testing_support/factories/archangel_pages.rb +3 -3
  223. data/lib/archangel/testing_support/factories/archangel_users.rb +6 -0
  224. data/lib/archangel/testing_support/factories/archangel_widgets.rb +3 -3
  225. data/lib/archangel/testing_support/helpers/authorization_helpers.rb +5 -29
  226. data/lib/archangel/testing_support/helpers/fill_in_auth_form_helpers.rb +34 -0
  227. data/lib/archangel/testing_support/helpers/fill_in_form_helpers.rb +21 -0
  228. data/lib/archangel/testing_support/support/capybara.rb +0 -3
  229. data/lib/archangel/testing_support/support/shoulda.rb +0 -1
  230. data/lib/archangel/version.rb +5 -1
  231. data/lib/generators/archangel/install/install_generator.rb +15 -33
  232. data/lib/generators/archangel/install/templates/config/archangel.yml +0 -5
  233. data/lib/templates/erb/scaffold/_form.html.erb +2 -2
  234. data/package.json +5 -12
  235. data/spec/features/auth/invitation_spec.rb +86 -0
  236. data/spec/features/auth/log_in/attempts_spec.rb +50 -0
  237. data/spec/features/auth/log_in/locked_spec.rb +29 -0
  238. data/spec/features/auth/log_in/log_in_spec.rb +51 -0
  239. data/spec/features/auth/log_in/unconfirmed_spec.rb +22 -0
  240. data/spec/features/auth/log_out_spec.rb +11 -4
  241. data/spec/features/auth/password_reset_spec.rb +28 -0
  242. data/spec/features/auth/registration_spec.rb +28 -16
  243. data/spec/features/backend/assets/create_spec.rb +68 -0
  244. data/spec/features/backend/assets/delete_spec.rb +32 -0
  245. data/spec/features/backend/assets/listing_spec.rb +83 -0
  246. data/spec/features/backend/assets/show_spec.rb +57 -0
  247. data/spec/features/backend/collections/create_spec.rb +97 -0
  248. data/spec/features/backend/collections/delete_spec.rb +32 -0
  249. data/spec/features/backend/collections/listing_spec.rb +93 -0
  250. data/spec/features/backend/collections/show_spec.rb +43 -0
  251. data/spec/features/backend/dashboard/show_spec.rb +17 -0
  252. data/spec/features/backend/designs/create_spec.rb +76 -0
  253. data/spec/features/backend/designs/delete_spec.rb +32 -0
  254. data/spec/features/backend/designs/listing_spec.rb +77 -0
  255. data/spec/features/backend/designs/show_spec.rb +48 -0
  256. data/spec/features/backend/entries/create_spec.rb +98 -0
  257. data/spec/features/backend/entries/delete_spec.rb +35 -0
  258. data/spec/features/backend/entries/listing_sorting_spec.rb +32 -0
  259. data/spec/features/backend/entries/listing_spec.rb +100 -0
  260. data/spec/features/backend/entries/show_spec.rb +62 -0
  261. data/spec/features/backend/pages/create_metatags_spec.rb +59 -0
  262. data/spec/features/backend/pages/create_spec.rb +143 -0
  263. data/spec/features/backend/pages/delete_spec.rb +32 -0
  264. data/spec/features/backend/pages/liquid_tags_spec.rb +159 -0
  265. data/spec/features/backend/pages/listing_spec.rb +75 -0
  266. data/spec/features/backend/pages/show_spec.rb +47 -0
  267. data/spec/features/backend/profile/delete_spec.rb +41 -0
  268. data/spec/features/backend/profile/show_spec.rb +46 -0
  269. data/spec/features/backend/profile/update_spec.rb +144 -0
  270. data/spec/features/backend/site/show_spec.rb +46 -0
  271. data/spec/features/backend/site/update_spec.rb +46 -0
  272. data/spec/features/backend/site/update_with_metatags_spec.rb +45 -0
  273. data/spec/features/backend/users/create_spec.rb +90 -0
  274. data/spec/features/backend/users/delete_spec.rb +32 -0
  275. data/spec/features/backend/users/listing_spec.rb +69 -0
  276. data/spec/features/backend/users/show_spec.rb +87 -0
  277. data/spec/features/backend/users/update_spec.rb +49 -0
  278. data/spec/features/backend/widgets/create_spec.rb +111 -0
  279. data/spec/features/backend/widgets/delete_spec.rb +42 -0
  280. data/spec/features/backend/widgets/listing_spec.rb +89 -0
  281. data/spec/features/backend/widgets/show_spec.rb +47 -0
  282. data/spec/features/frontend/liquid/filters/link_to_spec.rb +49 -0
  283. data/spec/features/frontend/liquid/tags/asset_spec.rb +81 -0
  284. data/spec/features/frontend/liquid/tags/collection_tag_spec.rb +94 -0
  285. data/spec/features/frontend/liquid/tags/collectionfor_tag_spec.rb +159 -0
  286. data/spec/features/frontend/liquid/tags/gist_spec.rb +57 -0
  287. data/spec/features/frontend/liquid/tags/noembed_tag_spec.rb +106 -0
  288. data/spec/features/frontend/liquid/tags/vimeo_spec.rb +79 -0
  289. data/spec/features/frontend/liquid/tags/widget_spec.rb +40 -0
  290. data/spec/features/frontend/liquid/tags/youtube_spec.rb +89 -0
  291. data/spec/features/frontend/liquid/variables/current_page_spec.rb +74 -0
  292. data/spec/features/frontend/liquid/variables/page_spec.rb +58 -0
  293. data/spec/features/frontend/liquid/variables/site_spec.rb +46 -0
  294. data/spec/features/frontend/liquid/variables/unknown_spec.rb +19 -0
  295. data/spec/features/frontend/metatags/default_spec.rb +46 -0
  296. data/spec/features/frontend/metatags/page_spec.rb +58 -0
  297. data/spec/features/frontend/metatags/site_spec.rb +42 -0
  298. data/spec/fixtures/schemas/backend/assets/wysiwyg_error.json +11 -0
  299. data/spec/fixtures/schemas/backend/assets/wysiwyg_url.json +11 -0
  300. data/spec/fixtures/schemas/frontend/errors/not_found.json +11 -0
  301. data/spec/fixtures/schemas/frontend/pages/show.json +25 -0
  302. data/spec/requests/backend/assets_spec.rb +81 -0
  303. data/spec/requests/backend/designs_spec.rb +115 -0
  304. data/spec/requests/backend/entries_spec.rb +32 -0
  305. data/spec/requests/backend/pages_spec.rb +113 -0
  306. data/spec/requests/backend/site_spec.rb +65 -0
  307. data/spec/requests/backend/widgets_spec.rb +109 -0
  308. data/spec/requests/frontend/html/homepage_spec.rb +70 -0
  309. data/spec/requests/frontend/html/nested_page_spec.rb +97 -0
  310. data/spec/requests/frontend/html/page_spec.rb +78 -0
  311. data/spec/requests/frontend/json/homepage_spec.rb +80 -0
  312. data/spec/requests/frontend/json/nested_page_spec.rb +111 -0
  313. data/spec/requests/frontend/json/page_spec.rb +92 -0
  314. data/spec/support/helpers/ajax_helpers.rb +27 -0
  315. data/spec/support/helpers/json_response.rb +18 -0
  316. data/{lib/archangel/testing_support → spec/support}/matchers/have_meta.rb +0 -0
  317. data/{lib/archangel/testing_support → spec/support}/matchers/have_title.rb +0 -0
  318. data/spec/support/matchers/match_response_schema.rb +12 -0
  319. data/spec/support/missing_translation.rb +13 -0
  320. data/spec/support/selenium.rb +26 -0
  321. data/spec/support/timecop.rb +15 -0
  322. data/spec/unit/helpers/archangel/application_helper_spec.rb +65 -0
  323. data/spec/unit/helpers/archangel/flash_helper_spec.rb +41 -0
  324. data/spec/{inputs → unit/inputs}/archangel/date_picker_input_spec.rb +0 -0
  325. data/spec/{inputs → unit/inputs}/archangel/date_time_picker_input_spec.rb +0 -0
  326. data/spec/{inputs → unit/inputs}/archangel/field_classification_input_spec.rb +0 -0
  327. data/spec/{inputs → unit/inputs}/archangel/language_input_spec.rb +0 -0
  328. data/spec/{inputs → unit/inputs}/archangel/meta_keywords_input_spec.rb +0 -0
  329. data/spec/{inputs → unit/inputs}/archangel/role_input_spec.rb +0 -0
  330. data/spec/{inputs → unit/inputs}/archangel/theme_input_spec.rb +0 -0
  331. data/spec/{inputs → unit/inputs}/archangel/time_picker_input_spec.rb +0 -0
  332. data/spec/{inputs → unit/inputs}/archangel/wysiwyg_input_spec.rb +0 -0
  333. data/spec/{jobs → unit/jobs}/archangel/application_job_spec.rb +0 -0
  334. data/spec/{lib → unit/lib}/archangel/commands/extension_command_spec.rb +11 -6
  335. data/spec/{lib → unit/lib}/archangel/commands/theme_command_spec.rb +11 -6
  336. data/spec/{lib → unit/lib}/tasks/archangel/version_task_spec.rb +0 -0
  337. data/spec/{mailers → unit/mailers}/archangel/application_mailer_spec.rb +0 -0
  338. data/spec/{models → unit/models}/archangel/asset_spec.rb +7 -15
  339. data/spec/{models → unit/models}/archangel/collection_spec.rb +3 -16
  340. data/spec/unit/models/archangel/design_spec.rb +22 -0
  341. data/spec/unit/models/archangel/entry_spec.rb +104 -0
  342. data/spec/{models → unit/models}/archangel/field_spec.rb +5 -7
  343. data/spec/{models → unit/models}/archangel/metatag_spec.rb +1 -5
  344. data/spec/{models → unit/models}/archangel/page_spec.rb +46 -44
  345. data/spec/{models → unit/models}/archangel/site_spec.rb +15 -8
  346. data/spec/{models → unit/models}/archangel/user_spec.rb +29 -39
  347. data/spec/{models → unit/models}/archangel/widget_spec.rb +5 -20
  348. data/spec/{policies → unit/policies}/archangel/asset_policy_spec.rb +0 -0
  349. data/spec/{policies → unit/policies}/archangel/collection_policy_spec.rb +0 -0
  350. data/spec/{policies/archangel/template_policy_spec.rb → unit/policies/archangel/design_policy_spec.rb} +2 -2
  351. data/spec/{policies → unit/policies}/archangel/entries_policy_spec.rb +0 -0
  352. data/spec/{policies → unit/policies}/archangel/page_policy_spec.rb +0 -0
  353. data/spec/{policies → unit/policies}/archangel/site_policy_spec.rb +2 -6
  354. data/spec/{policies → unit/policies}/archangel/user_policy_spec.rb +0 -0
  355. data/spec/{policies → unit/policies}/archangel/widget_policy_spec.rb +0 -0
  356. data/spec/unit/services/archangel/design_render_service_spec.rb +46 -0
  357. data/spec/unit/services/archangel/render_service_spec.rb +43 -0
  358. data/spec/{uploaders → unit/uploaders}/archangel/application_uploader_spec.rb +4 -2
  359. data/spec/{uploaders → unit/uploaders}/archangel/asset_uploader_spec.rb +5 -3
  360. data/vendor/assets/javascripts/flatpickr/flatpickr.js +2 -0
  361. data/vendor/assets/javascripts/jodit/jodit.js +9 -0
  362. data/vendor/assets/javascripts/select2/select2.js +5891 -0
  363. data/vendor/assets/javascripts/sortable/sortable.js +2 -2
  364. data/vendor/assets/stylesheets/flatpickr/flatpickr.css +13 -0
  365. data/vendor/assets/stylesheets/jodit/jodit.css +296 -0
  366. data/vendor/assets/stylesheets/select2/select2.css +480 -0
  367. metadata +227 -322
  368. data/.editorconfig +0 -19
  369. data/.hound.yml +0 -21
  370. data/.jshintignore +0 -5
  371. data/.jshintrc +0 -30
  372. data/.rubocop_todo.yml +0 -3
  373. data/.scss-lint.yml +0 -22
  374. data/app/assets/javascripts/archangel/object/translate/datetimepicker.js.erb +0 -41
  375. data/app/assets/javascripts/archangel/object/translate/sortable.js.erb +0 -10
  376. data/app/assets/javascripts/archangel/sortable.js +0 -72
  377. data/app/controllers/archangel/backend/templates_controller.rb +0 -43
  378. data/app/controllers/concerns/archangel/actionable_concern.rb +0 -161
  379. data/app/controllers/concerns/archangel/authenticatable_concern.rb +0 -14
  380. data/app/controllers/concerns/archangel/authorizable_concern.rb +0 -14
  381. data/app/controllers/concerns/archangel/controllers/backend/resourceful_concern.rb +0 -28
  382. data/app/controllers/concerns/archangel/paginatable_concern.rb +0 -36
  383. data/app/controllers/concerns/archangel/seoable_concern.rb +0 -40
  384. data/app/controllers/concerns/archangel/skip_authorizable_concern.rb +0 -14
  385. data/app/controllers/concerns/archangel/themable_concern.rb +0 -27
  386. data/app/helpers/archangel/backend/assets_helper.rb +0 -14
  387. data/app/helpers/archangel/backend/collections_helper.rb +0 -14
  388. data/app/helpers/archangel/backend/dashboards_helper.rb +0 -14
  389. data/app/helpers/archangel/backend/entries_helper.rb +0 -14
  390. data/app/helpers/archangel/backend/pages_helper.rb +0 -14
  391. data/app/helpers/archangel/backend/sites_helper.rb +0 -14
  392. data/app/helpers/archangel/backend/templates_helper.rb +0 -14
  393. data/app/helpers/archangel/backend/users_helper.rb +0 -14
  394. data/app/helpers/archangel/backend/widgets_helper.rb +0 -14
  395. data/app/helpers/archangel/backend_helper.rb +0 -9
  396. data/app/helpers/archangel/frontend/pages_helper.rb +0 -14
  397. data/app/helpers/archangel/frontend_helper.rb +0 -9
  398. data/app/policies/archangel/template_policy.rb +0 -9
  399. data/app/themes/default/assets/javascripts/default/backend/core.js +0 -76
  400. data/app/themes/default/assets/javascripts/default/backend/templates.js +0 -26
  401. data/app/themes/default/assets/javascripts/default/common/cards.js +0 -28
  402. data/app/themes/default/assets/stylesheets/default/auth/core.scss +0 -20
  403. data/app/themes/default/assets/stylesheets/default/backend/bootstrap/_tables.scss +0 -40
  404. data/app/themes/default/assets/stylesheets/default/backend/core.scss +0 -23
  405. data/app/themes/default/assets/stylesheets/default/common/_bootstrap.scss +0 -49
  406. data/app/themes/default/assets/stylesheets/default/common/_selectize.scss +0 -348
  407. data/app/themes/default/assets/stylesheets/default/common/_variables.scss +0 -82
  408. data/app/themes/default/assets/stylesheets/default/common/bootstrap/_animate.scss +0 -27
  409. data/app/themes/default/assets/stylesheets/default/common/bootstrap/_aside.scss +0 -67
  410. data/app/themes/default/assets/stylesheets/default/common/bootstrap/_avatars.scss +0 -42
  411. data/app/themes/default/assets/stylesheets/default/common/bootstrap/_badge.scss +0 -3
  412. data/app/themes/default/assets/stylesheets/default/common/bootstrap/_breadcrumb-menu.scss +0 -36
  413. data/app/themes/default/assets/stylesheets/default/common/bootstrap/_breadcrumb.scss +0 -4
  414. data/app/themes/default/assets/stylesheets/default/common/bootstrap/_buttons.scss +0 -408
  415. data/app/themes/default/assets/stylesheets/default/common/bootstrap/_callout.scss +0 -58
  416. data/app/themes/default/assets/stylesheets/default/common/bootstrap/_card.scss +0 -199
  417. data/app/themes/default/assets/stylesheets/default/common/bootstrap/_charts.scss +0 -9
  418. data/app/themes/default/assets/stylesheets/default/common/bootstrap/_dropdown-menu-right.scss +0 -8
  419. data/app/themes/default/assets/stylesheets/default/common/bootstrap/_dropdown.scss +0 -70
  420. data/app/themes/default/assets/stylesheets/default/common/bootstrap/_footer.scss +0 -9
  421. data/app/themes/default/assets/stylesheets/default/common/bootstrap/_forms.scss +0 -4
  422. data/app/themes/default/assets/stylesheets/default/common/bootstrap/_grid.scss +0 -15
  423. data/app/themes/default/assets/stylesheets/default/common/bootstrap/_input-group.scss +0 -5
  424. data/app/themes/default/assets/stylesheets/default/common/bootstrap/_layout.scss +0 -390
  425. data/app/themes/default/assets/stylesheets/default/common/bootstrap/_loading.scss +0 -128
  426. data/app/themes/default/assets/stylesheets/default/common/bootstrap/_mixins.scss +0 -1
  427. data/app/themes/default/assets/stylesheets/default/common/bootstrap/_mobile.scss +0 -0
  428. data/app/themes/default/assets/stylesheets/default/common/bootstrap/_modal.scss +0 -12
  429. data/app/themes/default/assets/stylesheets/default/common/bootstrap/_nav.scss +0 -39
  430. data/app/themes/default/assets/stylesheets/default/common/bootstrap/_navbar.scss +0 -122
  431. data/app/themes/default/assets/stylesheets/default/common/bootstrap/_others.scss +0 -4
  432. data/app/themes/default/assets/stylesheets/default/common/bootstrap/_progress.scss +0 -15
  433. data/app/themes/default/assets/stylesheets/default/common/bootstrap/_rtl.scss +0 -287
  434. data/app/themes/default/assets/stylesheets/default/common/bootstrap/_sidebar.scss +0 -462
  435. data/app/themes/default/assets/stylesheets/default/common/bootstrap/_switches.scss +0 -286
  436. data/app/themes/default/assets/stylesheets/default/common/bootstrap/_tables.scss +0 -20
  437. data/app/themes/default/assets/stylesheets/default/common/bootstrap/_temp.scss +0 -39
  438. data/app/themes/default/assets/stylesheets/default/common/bootstrap/_typography.scss +0 -36
  439. data/app/themes/default/assets/stylesheets/default/common/bootstrap/_utilities.scss +0 -3
  440. data/app/themes/default/assets/stylesheets/default/common/bootstrap/_variables.scss +0 -208
  441. data/app/themes/default/assets/stylesheets/default/common/bootstrap/_widgets.scss +0 -251
  442. data/app/themes/default/assets/stylesheets/default/common/bootstrap/mixins/_all.scss +0 -117
  443. data/app/themes/default/assets/stylesheets/default/common/bootstrap/utilities/_background.scss +0 -20
  444. data/app/themes/default/assets/stylesheets/default/common/bootstrap/utilities/_borders.scss +0 -17
  445. data/app/themes/default/assets/stylesheets/default/common/bootstrap/utilities/_display.scss +0 -14
  446. data/app/themes/default/assets/stylesheets/default/frontend/core.scss +0 -20
  447. data/app/themes/default/views/layouts/frontend.liquid +0 -22
  448. data/app/views/archangel/backend/dashboards/_buttons.html.erb +0 -3
  449. data/app/views/archangel/backend/sites/_additional_colors.html.erb +0 -49
  450. data/app/views/archangel/backend/sites/_alerts.html.erb +0 -130
  451. data/app/views/archangel/backend/sites/_badge.html.erb +0 -99
  452. data/app/views/archangel/backend/sites/_button.html.erb +0 -243
  453. data/app/views/archangel/backend/sites/_buttons_group.html.erb +0 -230
  454. data/app/views/archangel/backend/sites/_cards.html.erb +0 -441
  455. data/app/views/archangel/backend/sites/_carousel.html.erb +0 -159
  456. data/app/views/archangel/backend/sites/_colors.html.erb +0 -41
  457. data/app/views/archangel/backend/sites/_display_headings.html.erb +0 -41
  458. data/app/views/archangel/backend/sites/_dl.html.erb +0 -38
  459. data/app/views/archangel/backend/sites/_dropdowns.html.erb +0 -475
  460. data/app/views/archangel/backend/sites/_forms.html.erb +0 -1176
  461. data/app/views/archangel/backend/sites/_grays.html.erb +0 -21
  462. data/app/views/archangel/backend/sites/_headings.html.erb +0 -21
  463. data/app/views/archangel/backend/sites/_inline_text.html.erb +0 -45
  464. data/app/views/archangel/backend/sites/_jumbotron.html.erb +0 -45
  465. data/app/views/archangel/backend/sites/_list_group.html.erb +0 -254
  466. data/app/views/archangel/backend/sites/_modals.html.erb +0 -41
  467. data/app/views/archangel/backend/sites/_navs.html.erb +0 -389
  468. data/app/views/archangel/backend/sites/_pagination.html.erb +0 -160
  469. data/app/views/archangel/backend/sites/_social_buttons.html.erb +0 -746
  470. data/app/views/archangel/backend/sites/_tables.html.erb +0 -372
  471. data/app/views/archangel/backend/sites/sample.html.erb +0 -38
  472. data/app/views/archangel/backend/templates/_buttons.html.erb +0 -18
  473. data/app/views/archangel/backend/templates/_template.html.erb +0 -10
  474. data/app/views/archangel/backend/templates/edit.html.erb +0 -21
  475. data/app/views/archangel/backend/templates/index.html.erb +0 -49
  476. data/app/views/archangel/backend/templates/new.html.erb +0 -21
  477. data/app/views/archangel/backend/templates/show.html.erb +0 -34
  478. data/config/initializers/liquid.rb +0 -4
  479. data/lib/archangel/commands/templates/common/.editorconfig +0 -19
  480. data/lib/archangel/commands/templates/common/.rubocop.yml +0 -32
  481. data/lib/archangel/commands/templates/extension/Gemfile +0 -27
  482. data/lib/archangel/commands/templates/extension/app/assets/javascripts/archangel/auth/%extension_name%.js.tt +0 -3
  483. data/lib/archangel/commands/templates/extension/app/assets/javascripts/archangel/backend/%extension_name%.js.tt +0 -3
  484. data/lib/archangel/commands/templates/extension/app/assets/javascripts/archangel/frontend/%extension_name%.js.tt +0 -3
  485. data/lib/archangel/commands/templates/extension/app/assets/stylesheets/archangel/auth/%extension_name%.css.tt +0 -5
  486. data/lib/archangel/commands/templates/extension/app/assets/stylesheets/archangel/backend/%extension_name%.css.tt +0 -5
  487. data/lib/archangel/commands/templates/extension/app/assets/stylesheets/archangel/frontend/%extension_name%.css.tt +0 -5
  488. data/lib/archangel/commands/templates/theme/Gemfile +0 -27
  489. data/lib/archangel/commands/templates/theme/Rakefile +0 -29
  490. data/lib/archangel/commands/templates/theme/app/themes/%theme_base_name%/assets/javascripts/%theme_base_name%/auth.js +0 -2
  491. data/lib/archangel/commands/templates/theme/app/themes/%theme_base_name%/assets/javascripts/%theme_base_name%/backend.js +0 -2
  492. data/lib/archangel/commands/templates/theme/app/themes/%theme_base_name%/assets/stylesheets/%theme_base_name%/auth.css +0 -4
  493. data/lib/archangel/commands/templates/theme/app/themes/%theme_base_name%/assets/stylesheets/%theme_base_name%/backend.css +0 -4
  494. data/lib/archangel/commands/templates/theme/app/themes/%theme_base_name%/views/layouts/frontend.liquid +0 -18
  495. data/lib/archangel/commands/templates/theme/bin/rails.tt +0 -11
  496. data/lib/archangel/commands/templates/theme/lib/%theme_name%.rb.tt +0 -9
  497. data/lib/archangel/commands/templates/theme/lib/%theme_name%/engine.rb.tt +0 -29
  498. data/lib/archangel/commands/templates/theme/lib/%theme_name%/version.rb.tt +0 -5
  499. data/lib/archangel/liquid/tags/csrf_meta_tags_tag.rb +0 -29
  500. data/lib/archangel/liquid/tags/locale_tag.rb +0 -28
  501. data/lib/archangel/liquid/tags/meta_tags_tag.rb +0 -31
  502. data/lib/archangel/liquid/tags/text_direction_tag.rb +0 -29
  503. data/lib/archangel/liquid/tags/theme_javascript_tag.rb +0 -31
  504. data/lib/archangel/liquid/tags/theme_stylesheet_tag.rb +0 -31
  505. data/lib/archangel/liquid_view.rb +0 -68
  506. data/lib/archangel/testing_support/context/view_controller_context.rb +0 -55
  507. data/lib/archangel/testing_support/helpers/controller_helpers.rb +0 -20
  508. data/lib/archangel/testing_support/helpers/form_helpers.rb +0 -18
  509. data/lib/archangel/testing_support/helpers/routing_helpers.rb +0 -22
  510. data/lib/archangel/testing_support/support/controller.rb +0 -11
  511. data/lib/archangel/testing_support/support/liquid_filters.rb +0 -23
  512. data/lib/archangel/testing_support/support/liquid_tags.rb +0 -23
  513. data/lib/archangel/testing_support/support/verify_partial_doubles.rb +0 -21
  514. data/spec/controllers/archangel/application_controller_spec.rb +0 -183
  515. data/spec/controllers/archangel/auth/registrations_controller_spec.rb +0 -10
  516. data/spec/controllers/archangel/auth_controller_spec.rb +0 -8
  517. data/spec/controllers/archangel/backend/assets_controller_spec.rb +0 -226
  518. data/spec/controllers/archangel/backend/collections_controller_spec.rb +0 -252
  519. data/spec/controllers/archangel/backend/dashboards_controller_spec.rb +0 -27
  520. data/spec/controllers/archangel/backend/entries_controller_spec.rb +0 -273
  521. data/spec/controllers/archangel/backend/pages_controller_spec.rb +0 -220
  522. data/spec/controllers/archangel/backend/profiles_controller_spec.rb +0 -115
  523. data/spec/controllers/archangel/backend/sites_controller_spec.rb +0 -121
  524. data/spec/controllers/archangel/backend/templates_controller_spec.rb +0 -190
  525. data/spec/controllers/archangel/backend/users_controller_spec.rb +0 -181
  526. data/spec/controllers/archangel/backend/widgets_controller_spec.rb +0 -190
  527. data/spec/controllers/archangel/backend_controller_spec.rb +0 -8
  528. data/spec/controllers/archangel/frontend/pages_controller_spec.rb +0 -51
  529. data/spec/controllers/archangel/frontend_controller_spec.rb +0 -8
  530. data/spec/controllers/concerns/archangel/controllers/backend/resourceful_concern_spec.rb +0 -90
  531. data/spec/features/auth/log_in_spec.rb +0 -126
  532. data/spec/features/backend/pages/duplicate_slugs_spec.rb +0 -41
  533. data/spec/features/frontend/liquid_drop_variables_spec.rb +0 -133
  534. data/spec/features/frontend/pages/homepage_redirect_spec.rb +0 -15
  535. data/spec/features/frontend/pages/metatags_spec.rb +0 -73
  536. data/spec/helpers/archangel/application_helper_spec.rb +0 -30
  537. data/spec/helpers/archangel/auth_helper_spec.rb +0 -8
  538. data/spec/helpers/archangel/backend/assets_helper_spec.rb +0 -10
  539. data/spec/helpers/archangel/backend/collections_helper_spec.rb +0 -10
  540. data/spec/helpers/archangel/backend/dashboards_helper_spec.rb +0 -10
  541. data/spec/helpers/archangel/backend/entries_helper_spec.rb +0 -10
  542. data/spec/helpers/archangel/backend/pages_helper_spec.rb +0 -10
  543. data/spec/helpers/archangel/backend/sites_helper_spec.rb +0 -10
  544. data/spec/helpers/archangel/backend/templates_helper_spec.rb +0 -10
  545. data/spec/helpers/archangel/backend/users_helper_spec.rb +0 -10
  546. data/spec/helpers/archangel/backend/widgets_helper_spec.rb +0 -10
  547. data/spec/helpers/archangel/backend_helper_spec.rb +0 -8
  548. data/spec/helpers/archangel/flash_helper_spec.rb +0 -47
  549. data/spec/helpers/archangel/frontend/pages_helper_spec.rb +0 -10
  550. data/spec/helpers/archangel/frontend_helper_spec.rb +0 -8
  551. data/spec/lib/archangel/liquid/drop_spec.rb +0 -10
  552. data/spec/lib/archangel/liquid/drops/page_drop_spec.rb +0 -69
  553. data/spec/lib/archangel/liquid/drops/site_drop_spec.rb +0 -63
  554. data/spec/lib/archangel/liquid/filters/link_to_filter_spec.rb +0 -59
  555. data/spec/lib/archangel/liquid/tags/application_tag_spec.rb +0 -12
  556. data/spec/lib/archangel/liquid/tags/asset_tag_spec.rb +0 -91
  557. data/spec/lib/archangel/liquid/tags/collection_tag_spec.rb +0 -104
  558. data/spec/lib/archangel/liquid/tags/collectionfor_tag_spec.rb +0 -163
  559. data/spec/lib/archangel/liquid/tags/csrf_meta_tags_tag_spec.rb +0 -33
  560. data/spec/lib/archangel/liquid/tags/gist_tag_spec.rb +0 -42
  561. data/spec/lib/archangel/liquid/tags/locale_tag_spec.rb +0 -22
  562. data/spec/lib/archangel/liquid/tags/meta_tags_tag_spec.rb +0 -24
  563. data/spec/lib/archangel/liquid/tags/noembed_tag_spec.rb +0 -76
  564. data/spec/lib/archangel/liquid/tags/text_direction_tag_spec.rb +0 -32
  565. data/spec/lib/archangel/liquid/tags/theme_javascript_tag_spec.rb +0 -26
  566. data/spec/lib/archangel/liquid/tags/theme_stylesheet_tag_spec.rb +0 -28
  567. data/spec/lib/archangel/liquid/tags/vimeo_tag_spec.rb +0 -39
  568. data/spec/lib/archangel/liquid/tags/widget_tag_spec.rb +0 -59
  569. data/spec/lib/archangel/liquid/tags/youtube_tag_spec.rb +0 -39
  570. data/spec/models/archangel/entry_spec.rb +0 -62
  571. data/spec/models/archangel/template_spec.rb +0 -45
  572. data/spec/policies/archangel/application_policy_spec.rb +0 -8
  573. data/spec/services/archangel/render_service_spec.rb +0 -37
  574. data/spec/services/archangel/template_render_service_spec.rb +0 -42
  575. data/spec/support/.keep +0 -0
  576. data/spec/uploaders/archangel/avatar_uploader_spec.rb +0 -50
  577. data/spec/uploaders/archangel/logo_uploader_spec.rb +0 -50
  578. data/vendor/assets/icons/trumbowyg/icons.svg +0 -1
  579. data/vendor/assets/javascripts/daterangepicker/daterangepicker.js +0 -1529
  580. data/vendor/assets/javascripts/trumbowyg/plugins/allowtagsfrompaste/trumbowyg.allowtagsfrompaste.js +0 -143
  581. data/vendor/assets/javascripts/trumbowyg/plugins/base64/trumbowyg.base64.js +0 -129
  582. data/vendor/assets/javascripts/trumbowyg/plugins/cleanpaste/trumbowyg.cleanpaste.js +0 -110
  583. data/vendor/assets/javascripts/trumbowyg/plugins/colors/trumbowyg.colors.js +0 -183
  584. data/vendor/assets/javascripts/trumbowyg/plugins/noembed/trumbowyg.noembed.js +0 -104
  585. data/vendor/assets/javascripts/trumbowyg/plugins/upload/trumbowyg.upload.js +0 -261
  586. data/vendor/assets/javascripts/trumbowyg/trumbowyg.js +0 -1765
  587. data/vendor/assets/stylesheets/daterangepicker/_daterangepicker.scss +0 -405
  588. data/vendor/assets/stylesheets/trumbowyg/_trumbowyg.scss +0 -831
  589. data/vendor/assets/stylesheets/trumbowyg/plugins/colors/_trumbowyg.colors.scss +0 -38
@@ -1,104 +0,0 @@
1
- /* ===========================================================
2
- * trumbowyg.noembed.js v1.0
3
- * noEmbed plugin for Trumbowyg
4
- * http://alex-d.github.com/Trumbowyg
5
- * ===========================================================
6
- * Author : Jake Johns (jakejohns)
7
- */
8
-
9
- (function ($) {
10
- 'use strict';
11
-
12
- var defaultOptions = {
13
- proxy: 'https://noembed.com/embed?nowrap=on',
14
- urlFiled: 'url',
15
- data: [],
16
- success: undefined,
17
- error: undefined
18
- };
19
-
20
- $.extend(true, $.trumbowyg, {
21
- langs: {
22
- en: {
23
- noembed: 'Noembed',
24
- noembedError: 'Error'
25
- },
26
- sk: {
27
- noembedError: 'Chyba'
28
- },
29
- fr: {
30
- noembedError: 'Erreur'
31
- },
32
- cs: {
33
- noembedError: 'Chyba'
34
- },
35
- ru: {
36
- noembedError: 'Ошибка'
37
- },
38
- ja: {
39
- noembedError: 'エラー'
40
- },
41
- tr: {
42
- noembedError: 'Hata'
43
- }
44
- },
45
-
46
- plugins: {
47
- noembed: {
48
- init: function (trumbowyg) {
49
- trumbowyg.o.plugins.noembed = $.extend(true, {}, defaultOptions, trumbowyg.o.plugins.noembed || {});
50
-
51
- var btnDef = {
52
- fn: function () {
53
- var $modal = trumbowyg.openModalInsert(
54
- // Title
55
- trumbowyg.lang.noembed,
56
-
57
- // Fields
58
- {
59
- url: {
60
- label: 'URL',
61
- required: true
62
- }
63
- },
64
-
65
- // Callback
66
- function (data) {
67
- $.ajax({
68
- url: trumbowyg.o.plugins.noembed.proxy,
69
- type: 'GET',
70
- data: data,
71
- cache: false,
72
- dataType: 'json',
73
-
74
- success: trumbowyg.o.plugins.noembed.success || function (data) {
75
- if (data.html) {
76
- trumbowyg.execCmd('insertHTML', data.html);
77
- setTimeout(function () {
78
- trumbowyg.closeModal();
79
- }, 250);
80
- } else {
81
- trumbowyg.addErrorOnModalField(
82
- $('input[type=text]', $modal),
83
- data.error
84
- );
85
- }
86
- },
87
- error: trumbowyg.o.plugins.noembed.error || function () {
88
- trumbowyg.addErrorOnModalField(
89
- $('input[type=text]', $modal),
90
- trumbowyg.lang.noembedError
91
- );
92
- }
93
- });
94
- }
95
- );
96
- }
97
- };
98
-
99
- trumbowyg.addBtnDef('noembed', btnDef);
100
- }
101
- }
102
- }
103
- });
104
- })(jQuery);
@@ -1,261 +0,0 @@
1
- /* ===========================================================
2
- * trumbowyg.upload.js v1.2
3
- * Upload plugin for Trumbowyg
4
- * http://alex-d.github.com/Trumbowyg
5
- * ===========================================================
6
- * Author : Alexandre Demode (Alex-D)
7
- * Twitter : @AlexandreDemode
8
- * Website : alex-d.fr
9
- * Mod by : Aleksandr-ru
10
- * Twitter : @Aleksandr_ru
11
- * Website : aleksandr.ru
12
- */
13
-
14
- (function ($) {
15
- 'use strict';
16
-
17
- var defaultOptions = {
18
- serverPath: '',
19
- fileFieldName: 'fileToUpload',
20
- data: [], // Additional data for ajax [{name: 'key', value: 'value'}]
21
- headers: {}, // Additional headers
22
- xhrFields: {}, // Additional fields
23
- urlPropertyName: 'file', // How to get url from the json response (for instance 'url' for {url: ....})
24
- statusPropertyName: 'success', // How to get status from the json response
25
- success: undefined, // Success callback: function (data, trumbowyg, $modal, values) {}
26
- error: undefined, // Error callback: function () {}
27
- imageWidthModalEdit: false // Add ability to edit image width
28
- };
29
-
30
- function getDeep(object, propertyParts) {
31
- var mainProperty = propertyParts.shift(),
32
- otherProperties = propertyParts;
33
-
34
- if (object !== null) {
35
- if (otherProperties.length === 0) {
36
- return object[mainProperty];
37
- }
38
-
39
- if (typeof object === 'object') {
40
- return getDeep(object[mainProperty], otherProperties);
41
- }
42
- }
43
- return object;
44
- }
45
-
46
- addXhrProgressEvent();
47
-
48
- $.extend(true, $.trumbowyg, {
49
- langs: {
50
- // jshint camelcase:false
51
- en: {
52
- upload: 'Upload',
53
- file: 'File',
54
- uploadError: 'Error'
55
- },
56
- sk: {
57
- upload: 'Nahrať',
58
- file: 'Súbor',
59
- uploadError: 'Chyba'
60
- },
61
- fr: {
62
- upload: 'Envoi',
63
- file: 'Fichier',
64
- uploadError: 'Erreur'
65
- },
66
- cs: {
67
- upload: 'Nahrát obrázek',
68
- file: 'Soubor',
69
- uploadError: 'Chyba'
70
- },
71
- zh_cn: {
72
- upload: '上传',
73
- file: '文件',
74
- uploadError: '错误'
75
- },
76
- zh_tw: {
77
- upload: '上傳',
78
- file: '文件',
79
- uploadError: '錯誤'
80
- },
81
- ru: {
82
- upload: 'Загрузка',
83
- file: 'Файл',
84
- uploadError: 'Ошибка'
85
- },
86
- ja: {
87
- upload: 'アップロード',
88
- file: 'ファイル',
89
- uploadError: 'エラー'
90
- },
91
- pt_br: {
92
- upload: 'Enviar do local',
93
- file: 'Arquivo',
94
- uploadError: 'Erro'
95
- },
96
- tr: {
97
- upload: 'Yükle',
98
- file: 'Dosya',
99
- uploadError: 'Hata'
100
- }
101
- },
102
-
103
- // jshint camelcase:true
104
- plugins: {
105
- upload: {
106
- init: function (trumbowyg) {
107
- trumbowyg.o.plugins.upload = $.extend(true, {}, defaultOptions, trumbowyg.o.plugins.upload || {});
108
- var btnDef = {
109
- fn: function () {
110
- trumbowyg.saveRange();
111
-
112
- var file,
113
- prefix = trumbowyg.o.prefix;
114
-
115
- var fields = {
116
- file: {
117
- type: 'file',
118
- required: true,
119
- attributes: {
120
- accept: 'image/*'
121
- }
122
- },
123
- alt: {
124
- label: 'description',
125
- value: trumbowyg.getRangeText()
126
- }
127
- };
128
-
129
- if (trumbowyg.o.plugins.upload.imageWidthModalEdit) {
130
- fields.width = {
131
- value: ''
132
- };
133
- }
134
-
135
- var $modal = trumbowyg.openModalInsert(
136
- // Title
137
- trumbowyg.lang.upload,
138
-
139
- // Fields
140
- fields,
141
-
142
- // Callback
143
- function (values) {
144
- var data = new FormData();
145
- data.append(trumbowyg.o.plugins.upload.fileFieldName, file);
146
-
147
- trumbowyg.o.plugins.upload.data.map(function (cur) {
148
- data.append(cur.name, cur.value);
149
- });
150
-
151
- $.map(values, function (curr, key) {
152
- if (key !== 'file') {
153
- data.append(key, curr);
154
- }
155
- });
156
-
157
- if ($('.' + prefix + 'progress', $modal).length === 0) {
158
- $('.' + prefix + 'modal-title', $modal)
159
- .after(
160
- $('<div/>', {
161
- 'class': prefix + 'progress'
162
- }).append(
163
- $('<div/>', {
164
- 'class': prefix + 'progress-bar'
165
- })
166
- )
167
- );
168
- }
169
-
170
- $.ajax({
171
- url: trumbowyg.o.plugins.upload.serverPath,
172
- headers: trumbowyg.o.plugins.upload.headers,
173
- xhrFields: trumbowyg.o.plugins.upload.xhrFields,
174
- type: 'POST',
175
- data: data,
176
- cache: false,
177
- dataType: 'json',
178
- processData: false,
179
- contentType: false,
180
-
181
- progressUpload: function (e) {
182
- $('.' + prefix + 'progress-bar').css('width', Math.round(e.loaded * 100 / e.total) + '%');
183
- },
184
-
185
- success: function (data) {
186
- if (trumbowyg.o.plugins.upload.success) {
187
- trumbowyg.o.plugins.upload.success(data, trumbowyg, $modal, values);
188
- } else {
189
- if (!!getDeep(data, trumbowyg.o.plugins.upload.statusPropertyName.split('.'))) {
190
- var url = getDeep(data, trumbowyg.o.plugins.upload.urlPropertyName.split('.'));
191
- trumbowyg.execCmd('insertImage', url);
192
- var $img = $('img[src="' + url + '"]:not([alt])', trumbowyg.$box);
193
- $img.attr('alt', values.alt);
194
- if (trumbowyg.o.imageWidthModalEdit && parseInt(values.width) > 0) {
195
- $img.attr({
196
- width: values.width
197
- });
198
- }
199
- setTimeout(function () {
200
- trumbowyg.closeModal();
201
- }, 250);
202
- trumbowyg.$c.trigger('tbwuploadsuccess', [trumbowyg, data, url]);
203
- } else {
204
- trumbowyg.addErrorOnModalField(
205
- $('input[type=file]', $modal),
206
- trumbowyg.lang[data.message]
207
- );
208
- trumbowyg.$c.trigger('tbwuploaderror', [trumbowyg, data]);
209
- }
210
- }
211
- },
212
-
213
- error: trumbowyg.o.plugins.upload.error || function () {
214
- trumbowyg.addErrorOnModalField(
215
- $('input[type=file]', $modal),
216
- trumbowyg.lang.uploadError
217
- );
218
- trumbowyg.$c.trigger('tbwuploaderror', [trumbowyg]);
219
- }
220
- });
221
- }
222
- );
223
-
224
- $('input[type=file]').on('change', function (e) {
225
- try {
226
- // If multiple files allowed, we just get the first.
227
- file = e.target.files[0];
228
- } catch (err) {
229
- // In IE8, multiple files not allowed
230
- file = e.target.value;
231
- }
232
- });
233
- }
234
- };
235
-
236
- trumbowyg.addBtnDef('upload', btnDef);
237
- }
238
- }
239
- }
240
- });
241
-
242
- function addXhrProgressEvent() {
243
- if (!$.trumbowyg.addedXhrProgressEvent) { // Avoid adding progress event multiple times
244
- var originalXhr = $.ajaxSettings.xhr;
245
- $.ajaxSetup({
246
- xhr: function () {
247
- var req = originalXhr(),
248
- that = this;
249
- if (req && typeof req.upload === 'object' && that.progressUpload !== undefined) {
250
- req.upload.addEventListener('progress', function (e) {
251
- that.progressUpload(e);
252
- }, false);
253
- }
254
-
255
- return req;
256
- }
257
- });
258
- $.trumbowyg.addedXhrProgressEvent = true;
259
- }
260
- }
261
- })(jQuery);
@@ -1,1765 +0,0 @@
1
- jQuery.trumbowyg = {
2
- langs: {
3
- en: {
4
- viewHTML: 'View HTML',
5
-
6
- undo: 'Undo',
7
- redo: 'Redo',
8
-
9
- formatting: 'Formatting',
10
- p: 'Paragraph',
11
- blockquote: 'Quote',
12
- code: 'Code',
13
- header: 'Header',
14
-
15
- bold: 'Bold',
16
- italic: 'Italic',
17
- strikethrough: 'Stroke',
18
- underline: 'Underline',
19
-
20
- strong: 'Strong',
21
- em: 'Emphasis',
22
- del: 'Deleted',
23
-
24
- superscript: 'Superscript',
25
- subscript: 'Subscript',
26
-
27
- unorderedList: 'Unordered list',
28
- orderedList: 'Ordered list',
29
-
30
- insertImage: 'Insert Image',
31
- link: 'Link',
32
- createLink: 'Insert link',
33
- unlink: 'Remove link',
34
-
35
- justifyLeft: 'Align Left',
36
- justifyCenter: 'Align Center',
37
- justifyRight: 'Align Right',
38
- justifyFull: 'Align Justify',
39
-
40
- horizontalRule: 'Insert horizontal rule',
41
- removeformat: 'Remove format',
42
-
43
- fullscreen: 'Fullscreen',
44
-
45
- close: 'Close',
46
-
47
- submit: 'Confirm',
48
- reset: 'Cancel',
49
-
50
- required: 'Required',
51
- description: 'Description',
52
- title: 'Title',
53
- text: 'Text',
54
- target: 'Target',
55
- width: 'Width'
56
- }
57
- },
58
-
59
- // Plugins
60
- plugins: {},
61
-
62
- // SVG Path globally
63
- svgPath: null,
64
-
65
- hideButtonTexts: null
66
- };
67
-
68
- // Makes default options read-only
69
- Object.defineProperty(jQuery.trumbowyg, 'defaultOptions', {
70
- value: {
71
- lang: 'en',
72
-
73
- fixedBtnPane: false,
74
- fixedFullWidth: false,
75
- autogrow: false,
76
- autogrowOnEnter: false,
77
- imageWidthModalEdit: false,
78
-
79
- prefix: 'trumbowyg-',
80
-
81
- semantic: true,
82
- resetCss: false,
83
- removeformatPasted: false,
84
- tagsToRemove: [],
85
- btns: [
86
- ['viewHTML'],
87
- ['undo', 'redo'], // Only supported in Blink browsers
88
- ['formatting'],
89
- ['strong', 'em', 'del'],
90
- ['superscript', 'subscript'],
91
- ['link'],
92
- ['insertImage'],
93
- ['justifyLeft', 'justifyCenter', 'justifyRight', 'justifyFull'],
94
- ['unorderedList', 'orderedList'],
95
- ['horizontalRule'],
96
- ['removeformat'],
97
- ['fullscreen']
98
- ],
99
- // For custom button definitions
100
- btnsDef: {},
101
-
102
- inlineElementsSelector: 'a,abbr,acronym,b,caption,cite,code,col,dfn,dir,dt,dd,em,font,hr,i,kbd,li,q,span,strikeout,strong,sub,sup,u',
103
-
104
- pasteHandlers: [],
105
-
106
- // imgDblClickHandler: default is defined in constructor
107
-
108
- plugins: {}
109
- },
110
- writable: false,
111
- enumerable: true,
112
- configurable: false
113
- });
114
-
115
- (function (navigator, window, document, $) {
116
- 'use strict';
117
-
118
- var CONFIRM_EVENT = 'tbwconfirm',
119
- CANCEL_EVENT = 'tbwcancel';
120
-
121
- $.fn.trumbowyg = function (options, params) {
122
- var trumbowygDataName = 'trumbowyg';
123
- if (options === Object(options) || !options) {
124
- return this.each(function () {
125
- if (!$(this).data(trumbowygDataName)) {
126
- $(this).data(trumbowygDataName, new Trumbowyg(this, options));
127
- }
128
- });
129
- }
130
- if (this.length === 1) {
131
- try {
132
- var t = $(this).data(trumbowygDataName);
133
- switch (options) {
134
- // Exec command
135
- case 'execCmd':
136
- return t.execCmd(params.cmd, params.param, params.forceCss);
137
-
138
- // Modal box
139
- case 'openModal':
140
- return t.openModal(params.title, params.content);
141
- case 'closeModal':
142
- return t.closeModal();
143
- case 'openModalInsert':
144
- return t.openModalInsert(params.title, params.fields, params.callback);
145
-
146
- // Range
147
- case 'saveRange':
148
- return t.saveRange();
149
- case 'getRange':
150
- return t.range;
151
- case 'getRangeText':
152
- return t.getRangeText();
153
- case 'restoreRange':
154
- return t.restoreRange();
155
-
156
- // Enable/disable
157
- case 'enable':
158
- return t.setDisabled(false);
159
- case 'disable':
160
- return t.setDisabled(true);
161
-
162
- // Toggle
163
- case 'toggle':
164
- return t.toggle();
165
-
166
- // Destroy
167
- case 'destroy':
168
- return t.destroy();
169
-
170
- // Empty
171
- case 'empty':
172
- return t.empty();
173
-
174
- // HTML
175
- case 'html':
176
- return t.html(params);
177
- }
178
- } catch (c) {
179
- }
180
- }
181
-
182
- return false;
183
- };
184
-
185
- // @param: editorElem is the DOM element
186
- var Trumbowyg = function (editorElem, options) {
187
- var t = this,
188
- trumbowygIconsId = 'trumbowyg-icons',
189
- $trumbowyg = $.trumbowyg;
190
-
191
- // Get the document of the element. It use to makes the plugin
192
- // compatible on iframes.
193
- t.doc = editorElem.ownerDocument || document;
194
-
195
- // jQuery object of the editor
196
- t.$ta = $(editorElem); // $ta : Textarea
197
- t.$c = $(editorElem); // $c : creator
198
-
199
- options = options || {};
200
-
201
- // Localization management
202
- if (options.lang != null || $trumbowyg.langs[options.lang] != null) {
203
- t.lang = $.extend(true, {}, $trumbowyg.langs.en, $trumbowyg.langs[options.lang]);
204
- } else {
205
- t.lang = $trumbowyg.langs.en;
206
- }
207
-
208
- t.hideButtonTexts = $trumbowyg.hideButtonTexts != null ? $trumbowyg.hideButtonTexts : options.hideButtonTexts;
209
-
210
- // SVG path
211
- var svgPathOption = $trumbowyg.svgPath != null ? $trumbowyg.svgPath : options.svgPath;
212
- t.hasSvg = svgPathOption !== false;
213
- t.svgPath = !!t.doc.querySelector('base') ? window.location.href.split('#')[0] : '';
214
- if ($('#' + trumbowygIconsId, t.doc).length === 0 && svgPathOption !== false) {
215
- if (svgPathOption == null) {
216
- // Hack to get svgPathOption based on trumbowyg.js path
217
- var scriptElements = document.getElementsByTagName('script');
218
- for (var i = 0; i < scriptElements.length; i += 1) {
219
- var source = scriptElements[i].src;
220
- var matches = source.match('trumbowyg(\.min)?\.js');
221
- if (matches != null) {
222
- svgPathOption = source.substring(0, source.indexOf(matches[0])) + 'ui/icons.svg';
223
- }
224
- }
225
- if (svgPathOption == null) {
226
- console.warn('You must define svgPath: https://goo.gl/CfTY9U'); // jshint ignore:line
227
- }
228
- }
229
-
230
- var div = t.doc.createElement('div');
231
- div.id = trumbowygIconsId;
232
- t.doc.body.insertBefore(div, t.doc.body.childNodes[0]);
233
- $.ajax({
234
- async: true,
235
- type: 'GET',
236
- contentType: 'application/x-www-form-urlencoded; charset=UTF-8',
237
- dataType: 'xml',
238
- crossDomain: true,
239
- url: svgPathOption,
240
- data: null,
241
- beforeSend: null,
242
- complete: null,
243
- success: function (data) {
244
- div.innerHTML = new XMLSerializer().serializeToString(data.documentElement);
245
- }
246
- });
247
- }
248
-
249
- /**
250
- * When the button is associated to a empty object
251
- * fn and title attributs are defined from the button key value
252
- *
253
- * For example
254
- * foo: {}
255
- * is equivalent to :
256
- * foo: {
257
- * fn: 'foo',
258
- * title: this.lang.foo
259
- * }
260
- */
261
- var h = t.lang.header, // Header translation
262
- isBlinkFunction = function () {
263
- return (window.chrome || (window.Intl && Intl.v8BreakIterator)) && 'CSS' in window;
264
- };
265
- t.btnsDef = {
266
- viewHTML: {
267
- fn: 'toggle'
268
- },
269
-
270
- undo: {
271
- isSupported: isBlinkFunction,
272
- key: 'Z'
273
- },
274
- redo: {
275
- isSupported: isBlinkFunction,
276
- key: 'Y'
277
- },
278
-
279
- p: {
280
- fn: 'formatBlock'
281
- },
282
- blockquote: {
283
- fn: 'formatBlock'
284
- },
285
- h1: {
286
- fn: 'formatBlock',
287
- title: h + ' 1'
288
- },
289
- h2: {
290
- fn: 'formatBlock',
291
- title: h + ' 2'
292
- },
293
- h3: {
294
- fn: 'formatBlock',
295
- title: h + ' 3'
296
- },
297
- h4: {
298
- fn: 'formatBlock',
299
- title: h + ' 4'
300
- },
301
- subscript: {
302
- tag: 'sub'
303
- },
304
- superscript: {
305
- tag: 'sup'
306
- },
307
-
308
- bold: {
309
- key: 'B',
310
- tag: 'b'
311
- },
312
- italic: {
313
- key: 'I',
314
- tag: 'i'
315
- },
316
- underline: {
317
- tag: 'u'
318
- },
319
- strikethrough: {
320
- tag: 'strike'
321
- },
322
-
323
- strong: {
324
- fn: 'bold',
325
- key: 'B'
326
- },
327
- em: {
328
- fn: 'italic',
329
- key: 'I'
330
- },
331
- del: {
332
- fn: 'strikethrough'
333
- },
334
-
335
- createLink: {
336
- key: 'K',
337
- tag: 'a'
338
- },
339
- unlink: {},
340
-
341
- insertImage: {},
342
-
343
- justifyLeft: {
344
- tag: 'left',
345
- forceCss: true
346
- },
347
- justifyCenter: {
348
- tag: 'center',
349
- forceCss: true
350
- },
351
- justifyRight: {
352
- tag: 'right',
353
- forceCss: true
354
- },
355
- justifyFull: {
356
- tag: 'justify',
357
- forceCss: true
358
- },
359
-
360
- unorderedList: {
361
- fn: 'insertUnorderedList',
362
- tag: 'ul'
363
- },
364
- orderedList: {
365
- fn: 'insertOrderedList',
366
- tag: 'ol'
367
- },
368
-
369
- horizontalRule: {
370
- fn: 'insertHorizontalRule'
371
- },
372
-
373
- removeformat: {},
374
-
375
- fullscreen: {
376
- class: 'trumbowyg-not-disable'
377
- },
378
- close: {
379
- fn: 'destroy',
380
- class: 'trumbowyg-not-disable'
381
- },
382
-
383
- // Dropdowns
384
- formatting: {
385
- dropdown: ['p', 'blockquote', 'h1', 'h2', 'h3', 'h4'],
386
- ico: 'p'
387
- },
388
- link: {
389
- dropdown: ['createLink', 'unlink']
390
- }
391
- };
392
-
393
- // Defaults Options
394
- t.o = $.extend(true, {}, $trumbowyg.defaultOptions, options);
395
- if (!t.o.hasOwnProperty('imgDblClickHandler')) {
396
- t.o.imgDblClickHandler = t.getDefaultImgDblClickHandler();
397
- }
398
-
399
- t.disabled = t.o.disabled || (editorElem.nodeName === 'TEXTAREA' && editorElem.disabled);
400
-
401
- if (options.btns) {
402
- t.o.btns = options.btns;
403
- } else if (!t.o.semantic) {
404
- t.o.btns[3] = ['bold', 'italic', 'underline', 'strikethrough'];
405
- }
406
-
407
- $.each(t.o.btnsDef, function (btnName, btnDef) {
408
- t.addBtnDef(btnName, btnDef);
409
- });
410
-
411
- // put this here in the event it would be merged in with options
412
- t.eventNamespace = 'trumbowyg-event';
413
-
414
- // Keyboard shortcuts are load in this array
415
- t.keys = [];
416
-
417
- // Tag to button dynamically hydrated
418
- t.tagToButton = {};
419
- t.tagHandlers = [];
420
-
421
- // Admit multiple paste handlers
422
- t.pasteHandlers = [].concat(t.o.pasteHandlers);
423
-
424
- // Check if browser is IE
425
- t.isIE = (navigator.userAgent.indexOf('MSIE') !== -1 || navigator.appVersion.indexOf('Trident/') !== -1);
426
-
427
- t.init();
428
- };
429
-
430
- Trumbowyg.prototype = {
431
- DEFAULT_SEMANTIC_MAP: {
432
- 'b': 'strong',
433
- 'i': 'em',
434
- 's': 'del',
435
- 'strike': 'del',
436
- 'div': 'p'
437
- },
438
-
439
- init: function () {
440
- var t = this;
441
- t.height = t.$ta.height();
442
-
443
- t.initPlugins();
444
-
445
- try {
446
- // Disable image resize, try-catch for old IE
447
- t.doc.execCommand('enableObjectResizing', false, false);
448
- t.doc.execCommand('defaultParagraphSeparator', false, 'p');
449
- } catch (e) {
450
- }
451
-
452
- t.buildEditor();
453
- t.buildBtnPane();
454
-
455
- t.fixedBtnPaneEvents();
456
-
457
- t.buildOverlay();
458
-
459
- setTimeout(function () {
460
- if (t.disabled) {
461
- t.setDisabled(true);
462
- }
463
- t.$c.trigger('tbwinit');
464
- });
465
- },
466
-
467
- addBtnDef: function (btnName, btnDef) {
468
- this.btnsDef[btnName] = btnDef;
469
- },
470
-
471
- buildEditor: function () {
472
- var t = this,
473
- prefix = t.o.prefix,
474
- html = '';
475
-
476
- t.$box = $('<div/>', {
477
- class: prefix + 'box ' + prefix + 'editor-visible ' + prefix + t.o.lang + ' trumbowyg'
478
- });
479
-
480
- // $ta = Textarea
481
- // $ed = Editor
482
- t.isTextarea = t.$ta.is('textarea');
483
- if (t.isTextarea) {
484
- html = t.$ta.val();
485
- t.$ed = $('<div/>');
486
- t.$box
487
- .insertAfter(t.$ta)
488
- .append(t.$ed, t.$ta);
489
- } else {
490
- t.$ed = t.$ta;
491
- html = t.$ed.html();
492
-
493
- t.$ta = $('<textarea/>', {
494
- name: t.$ta.attr('id'),
495
- height: t.height
496
- }).val(html);
497
-
498
- t.$box
499
- .insertAfter(t.$ed)
500
- .append(t.$ta, t.$ed);
501
- t.syncCode();
502
- }
503
-
504
- t.$ta
505
- .addClass(prefix + 'textarea')
506
- .attr('tabindex', -1)
507
- ;
508
-
509
- t.$ed
510
- .addClass(prefix + 'editor')
511
- .attr({
512
- contenteditable: true,
513
- dir: t.lang._dir || 'ltr'
514
- })
515
- .html(html)
516
- ;
517
-
518
- if (t.o.tabindex) {
519
- t.$ed.attr('tabindex', t.o.tabindex);
520
- }
521
-
522
- if (t.$c.is('[placeholder]')) {
523
- t.$ed.attr('placeholder', t.$c.attr('placeholder'));
524
- }
525
-
526
- if (t.$c.is('[spellcheck]')) {
527
- t.$ed.attr('spellcheck', t.$c.attr('spellcheck'));
528
- }
529
-
530
- if (t.o.resetCss) {
531
- t.$ed.addClass(prefix + 'reset-css');
532
- }
533
-
534
- if (!t.o.autogrow) {
535
- t.$ta.add(t.$ed).css({
536
- height: t.height
537
- });
538
- }
539
-
540
- t.semanticCode();
541
-
542
- if (t.o.autogrowOnEnter) {
543
- t.$ed.addClass(prefix + 'autogrow-on-enter');
544
- }
545
-
546
- var ctrl = false,
547
- composition = false,
548
- debounceButtonPaneStatus,
549
- updateEventName = 'keyup';
550
-
551
- t.$ed
552
- .on('dblclick', 'img', t.o.imgDblClickHandler)
553
- .on('keydown', function (e) {
554
- if ((e.ctrlKey || e.metaKey) && !e.altKey) {
555
- ctrl = true;
556
- var key = t.keys[String.fromCharCode(e.which).toUpperCase()];
557
-
558
- try {
559
- t.execCmd(key.fn, key.param);
560
- return false;
561
- } catch (c) {
562
- }
563
- }
564
- })
565
- .on('compositionstart compositionupdate', function () {
566
- composition = true;
567
- })
568
- .on(updateEventName + ' compositionend', function (e) {
569
- if (e.type === 'compositionend') {
570
- composition = false;
571
- } else if (composition) {
572
- return;
573
- }
574
-
575
- var keyCode = e.which;
576
-
577
- if (keyCode >= 37 && keyCode <= 40) {
578
- return;
579
- }
580
-
581
- if ((e.ctrlKey || e.metaKey) && (keyCode === 89 || keyCode === 90)) {
582
- t.$c.trigger('tbwchange');
583
- } else if (!ctrl && keyCode !== 17) {
584
- var compositionEndIE = t.isIE ? e.type === 'compositionend' : true;
585
- t.semanticCode(false, compositionEndIE && keyCode === 13);
586
- t.$c.trigger('tbwchange');
587
- } else if (typeof e.which === 'undefined') {
588
- t.semanticCode(false, false, true);
589
- }
590
-
591
- setTimeout(function () {
592
- ctrl = false;
593
- }, 50);
594
- })
595
- .on('mouseup keydown keyup', function (e) {
596
- if ((!e.ctrlKey && !e.metaKey) || e.altKey) {
597
- setTimeout(function () { // "hold on" to the ctrl key for 50ms
598
- ctrl = false;
599
- }, 50);
600
- }
601
- clearTimeout(debounceButtonPaneStatus);
602
- debounceButtonPaneStatus = setTimeout(function () {
603
- t.updateButtonPaneStatus();
604
- }, 50);
605
- })
606
- .on('focus blur', function (e) {
607
- t.$c.trigger('tbw' + e.type);
608
- if (e.type === 'blur') {
609
- $('.' + prefix + 'active-button', t.$btnPane).removeClass(prefix + 'active-button ' + prefix + 'active');
610
- }
611
- if (t.o.autogrowOnEnter) {
612
- if (t.autogrowOnEnterDontClose) {
613
- return;
614
- }
615
- if (e.type === 'focus') {
616
- t.autogrowOnEnterWasFocused = true;
617
- t.autogrowEditorOnEnter();
618
- }
619
- else if (!t.o.autogrow) {
620
- t.$ed.css({height: t.$ed.css('min-height')});
621
- t.$c.trigger('tbwresize');
622
- }
623
- }
624
- })
625
- .on('cut', function () {
626
- setTimeout(function () {
627
- t.semanticCode(false, true);
628
- t.$c.trigger('tbwchange');
629
- }, 0);
630
- })
631
- .on('paste', function (e) {
632
- if (t.o.removeformatPasted) {
633
- e.preventDefault();
634
-
635
- if (window.getSelection && window.getSelection().deleteFromDocument) {
636
- window.getSelection().deleteFromDocument();
637
- }
638
-
639
- try {
640
- // IE
641
- var text = window.clipboardData.getData('Text');
642
-
643
- try {
644
- // <= IE10
645
- t.doc.selection.createRange().pasteHTML(text);
646
- } catch (c) {
647
- // IE 11
648
- t.doc.getSelection().getRangeAt(0).insertNode(t.doc.createTextNode(text));
649
- }
650
- t.$c.trigger('tbwchange', e);
651
- } catch (d) {
652
- // Not IE
653
- t.execCmd('insertText', (e.originalEvent || e).clipboardData.getData('text/plain'));
654
- }
655
- }
656
-
657
- // Call pasteHandlers
658
- $.each(t.pasteHandlers, function (i, pasteHandler) {
659
- pasteHandler(e);
660
- });
661
-
662
- setTimeout(function () {
663
- t.semanticCode(false, true);
664
- t.$c.trigger('tbwpaste', e);
665
- }, 0);
666
- });
667
-
668
- t.$ta
669
- .on('keyup', function () {
670
- t.$c.trigger('tbwchange');
671
- })
672
- .on('paste', function () {
673
- setTimeout(function () {
674
- t.$c.trigger('tbwchange');
675
- }, 0);
676
- });
677
-
678
- t.$box.on('keydown', function (e) {
679
- if (e.which === 27 && $('.' + prefix + 'modal-box', t.$box).length === 1) {
680
- t.closeModal();
681
- return false;
682
- }
683
- });
684
- },
685
-
686
- //autogrow when entering logic
687
- autogrowEditorOnEnter: function () {
688
- var t = this;
689
- t.$ed.removeClass('autogrow-on-enter');
690
- var oldHeight = t.$ed[0].clientHeight;
691
- t.$ed.height('auto');
692
- var totalHeight = t.$ed[0].scrollHeight;
693
- t.$ed.addClass('autogrow-on-enter');
694
- if (oldHeight !== totalHeight) {
695
- t.$ed.height(oldHeight);
696
- setTimeout(function () {
697
- t.$ed.css({height: totalHeight});
698
- t.$c.trigger('tbwresize');
699
- }, 0);
700
- }
701
- },
702
-
703
- // Build button pane, use o.btns option
704
- buildBtnPane: function () {
705
- var t = this,
706
- prefix = t.o.prefix;
707
-
708
- var $btnPane = t.$btnPane = $('<div/>', {
709
- class: prefix + 'button-pane'
710
- });
711
-
712
- $.each(t.o.btns, function (i, btnGrp) {
713
- if (!$.isArray(btnGrp)) {
714
- btnGrp = [btnGrp];
715
- }
716
-
717
- var $btnGroup = $('<div/>', {
718
- class: prefix + 'button-group ' + ((btnGrp.indexOf('fullscreen') >= 0) ? prefix + 'right' : '')
719
- });
720
- $.each(btnGrp, function (i, btn) {
721
- try { // Prevent buildBtn error
722
- if (t.isSupportedBtn(btn)) { // It's a supported button
723
- $btnGroup.append(t.buildBtn(btn));
724
- }
725
- } catch (c) {
726
- }
727
- });
728
-
729
- if ($btnGroup.html().trim().length > 0) {
730
- $btnPane.append($btnGroup);
731
- }
732
- });
733
-
734
- t.$box.prepend($btnPane);
735
- },
736
-
737
- // Build a button and his action
738
- buildBtn: function (btnName) { // btnName is name of the button
739
- var t = this,
740
- prefix = t.o.prefix,
741
- btn = t.btnsDef[btnName],
742
- isDropdown = btn.dropdown,
743
- hasIcon = btn.hasIcon != null ? btn.hasIcon : true,
744
- textDef = t.lang[btnName] || btnName,
745
-
746
- $btn = $('<button/>', {
747
- type: 'button',
748
- class: prefix + btnName + '-button ' + (btn.class || '') + (!hasIcon ? ' ' + prefix + 'textual-button' : ''),
749
- html: t.hasSvg && hasIcon ?
750
- '<svg><use xlink:href="' + t.svgPath + '#' + prefix + (btn.ico || btnName).replace(/([A-Z]+)/g, '-$1').toLowerCase() + '"/></svg>' :
751
- t.hideButtonTexts ? '' : (btn.text || btn.title || t.lang[btnName] || btnName),
752
- title: (btn.title || btn.text || textDef) + ((btn.key) ? ' (Ctrl + ' + btn.key + ')' : ''),
753
- tabindex: -1,
754
- mousedown: function () {
755
- if (!isDropdown || $('.' + btnName + '-' + prefix + 'dropdown', t.$box).is(':hidden')) {
756
- $('body', t.doc).trigger('mousedown');
757
- }
758
-
759
- if ((t.$btnPane.hasClass(prefix + 'disable') || t.$box.hasClass(prefix + 'disabled')) &&
760
- !$(this).hasClass(prefix + 'active') &&
761
- !$(this).hasClass(prefix + 'not-disable')) {
762
- return false;
763
- }
764
-
765
- t.execCmd((isDropdown ? 'dropdown' : false) || btn.fn || btnName, btn.param || btnName, btn.forceCss);
766
-
767
- return false;
768
- }
769
- });
770
-
771
- if (isDropdown) {
772
- $btn.addClass(prefix + 'open-dropdown');
773
- var dropdownPrefix = prefix + 'dropdown',
774
- dropdownOptions = { // the dropdown
775
- class: dropdownPrefix + '-' + btnName + ' ' + dropdownPrefix + ' ' + prefix + 'fixed-top'
776
- };
777
- dropdownOptions['data-' + dropdownPrefix] = btnName;
778
- var $dropdown = $('<div/>', dropdownOptions);
779
- $.each(isDropdown, function (i, def) {
780
- if (t.btnsDef[def] && t.isSupportedBtn(def)) {
781
- $dropdown.append(t.buildSubBtn(def));
782
- }
783
- });
784
- t.$box.append($dropdown.hide());
785
- } else if (btn.key) {
786
- t.keys[btn.key] = {
787
- fn: btn.fn || btnName,
788
- param: btn.param || btnName
789
- };
790
- }
791
-
792
- if (!isDropdown) {
793
- t.tagToButton[(btn.tag || btnName).toLowerCase()] = btnName;
794
- }
795
-
796
- return $btn;
797
- },
798
-
799
- // Build a button for dropdown menu
800
- // @param n : name of the subbutton
801
- buildSubBtn: function (btnName) {
802
- var t = this,
803
- prefix = t.o.prefix,
804
- btn = t.btnsDef[btnName],
805
- hasIcon = btn.hasIcon != null ? btn.hasIcon : true;
806
-
807
- if (btn.key) {
808
- t.keys[btn.key] = {
809
- fn: btn.fn || btnName,
810
- param: btn.param || btnName
811
- };
812
- }
813
-
814
- t.tagToButton[(btn.tag || btnName).toLowerCase()] = btnName;
815
-
816
- return $('<button/>', {
817
- type: 'button',
818
- class: prefix + btnName + '-dropdown-button' + (btn.ico ? ' ' + prefix + btn.ico + '-button' : ''),
819
- html: t.hasSvg && hasIcon ? '<svg><use xlink:href="' + t.svgPath + '#' + prefix + (btn.ico || btnName).replace(/([A-Z]+)/g, '-$1').toLowerCase() + '"/></svg>' + (btn.text || btn.title || t.lang[btnName] || btnName) : (btn.text || btn.title || t.lang[btnName] || btnName),
820
- title: ((btn.key) ? ' (Ctrl + ' + btn.key + ')' : null),
821
- style: btn.style || null,
822
- mousedown: function () {
823
- $('body', t.doc).trigger('mousedown');
824
-
825
- t.execCmd(btn.fn || btnName, btn.param || btnName, btn.forceCss);
826
-
827
- return false;
828
- }
829
- });
830
- },
831
-
832
- // Check if button is supported
833
- isSupportedBtn: function (b) {
834
- try {
835
- return this.btnsDef[b].isSupported();
836
- } catch (c) {
837
- }
838
- return true;
839
- },
840
-
841
- // Build overlay for modal box
842
- buildOverlay: function () {
843
- var t = this;
844
- t.$overlay = $('<div/>', {
845
- class: t.o.prefix + 'overlay'
846
- }).appendTo(t.$box);
847
- return t.$overlay;
848
- },
849
-
850
- showOverlay: function () {
851
- var t = this;
852
- $(window).trigger('scroll');
853
- t.$overlay.fadeIn(200);
854
- t.$box.addClass(t.o.prefix + 'box-blur');
855
- },
856
-
857
- hideOverlay: function () {
858
- var t = this;
859
- t.$overlay.fadeOut(50);
860
- t.$box.removeClass(t.o.prefix + 'box-blur');
861
- },
862
-
863
- // Management of fixed button pane
864
- fixedBtnPaneEvents: function () {
865
- var t = this,
866
- fixedFullWidth = t.o.fixedFullWidth,
867
- $box = t.$box;
868
-
869
- if (!t.o.fixedBtnPane) {
870
- return;
871
- }
872
-
873
- t.isFixed = false;
874
-
875
- $(window)
876
- .on('scroll.' + t.eventNamespace + ' resize.' + t.eventNamespace, function () {
877
- if (!$box) {
878
- return;
879
- }
880
-
881
- t.syncCode();
882
-
883
- var scrollTop = $(window).scrollTop(),
884
- offset = $box.offset().top + 1,
885
- bp = t.$btnPane,
886
- oh = bp.outerHeight() - 2;
887
-
888
- if ((scrollTop - offset > 0) && ((scrollTop - offset - t.height) < 0)) {
889
- if (!t.isFixed) {
890
- t.isFixed = true;
891
- bp.css({
892
- position: 'fixed',
893
- top: 0,
894
- left: fixedFullWidth ? '0' : 'auto',
895
- zIndex: 7
896
- });
897
- $([t.$ta, t.$ed]).css({marginTop: bp.height()});
898
- }
899
- bp.css({
900
- width: fixedFullWidth ? '100%' : (($box.width() - 1) + 'px')
901
- });
902
-
903
- $('.' + t.o.prefix + 'fixed-top', $box).css({
904
- position: fixedFullWidth ? 'fixed' : 'absolute',
905
- top: fixedFullWidth ? oh : oh + (scrollTop - offset) + 'px',
906
- zIndex: 15
907
- });
908
- } else if (t.isFixed) {
909
- t.isFixed = false;
910
- bp.removeAttr('style');
911
- $([t.$ta, t.$ed]).css({marginTop: 0});
912
- $('.' + t.o.prefix + 'fixed-top', $box).css({
913
- position: 'absolute',
914
- top: oh
915
- });
916
- }
917
- });
918
- },
919
-
920
- // Disable editor
921
- setDisabled: function (disable) {
922
- var t = this,
923
- prefix = t.o.prefix;
924
-
925
- t.disabled = disable;
926
-
927
- if (disable) {
928
- t.$ta.attr('disabled', true);
929
- } else {
930
- t.$ta.removeAttr('disabled');
931
- }
932
- t.$box.toggleClass(prefix + 'disabled', disable);
933
- t.$ed.attr('contenteditable', !disable);
934
- },
935
-
936
- // Destroy the editor
937
- destroy: function () {
938
- var t = this,
939
- prefix = t.o.prefix;
940
-
941
- if (t.isTextarea) {
942
- t.$box.after(
943
- t.$ta
944
- .css({height: ''})
945
- .val(t.html())
946
- .removeClass(prefix + 'textarea')
947
- .show()
948
- );
949
- } else {
950
- t.$box.after(
951
- t.$ed
952
- .css({height: ''})
953
- .removeClass(prefix + 'editor')
954
- .removeAttr('contenteditable')
955
- .removeAttr('dir')
956
- .html(t.html())
957
- .show()
958
- );
959
- }
960
-
961
- t.$ed.off('dblclick', 'img');
962
-
963
- t.destroyPlugins();
964
-
965
- t.$box.remove();
966
- t.$c.removeData('trumbowyg');
967
- $('body').removeClass(prefix + 'body-fullscreen');
968
- t.$c.trigger('tbwclose');
969
- $(window).off('scroll.' + t.eventNamespace + ' resize.' + t.eventNamespace);
970
- },
971
-
972
- // Empty the editor
973
- empty: function () {
974
- this.$ta.val('');
975
- this.syncCode(true);
976
- },
977
-
978
- // Function call when click on viewHTML button
979
- toggle: function () {
980
- var t = this,
981
- prefix = t.o.prefix;
982
-
983
- if (t.o.autogrowOnEnter) {
984
- t.autogrowOnEnterDontClose = !t.$box.hasClass(prefix + 'editor-hidden');
985
- }
986
-
987
- t.semanticCode(false, true);
988
-
989
- setTimeout(function () {
990
- t.doc.activeElement.blur();
991
- t.$box.toggleClass(prefix + 'editor-hidden ' + prefix + 'editor-visible');
992
- t.$btnPane.toggleClass(prefix + 'disable');
993
- $('.' + prefix + 'viewHTML-button', t.$btnPane).toggleClass(prefix + 'active');
994
- if (t.$box.hasClass(prefix + 'editor-visible')) {
995
- t.$ta.attr('tabindex', -1);
996
- } else {
997
- t.$ta.removeAttr('tabindex');
998
- }
999
-
1000
- if (t.o.autogrowOnEnter && !t.autogrowOnEnterDontClose) {
1001
- t.autogrowEditorOnEnter();
1002
- }
1003
- }, 0);
1004
- },
1005
-
1006
- // Open dropdown when click on a button which open that
1007
- dropdown: function (name) {
1008
- var t = this,
1009
- d = t.doc,
1010
- prefix = t.o.prefix,
1011
- $dropdown = $('[data-' + prefix + 'dropdown=' + name + ']', t.$box),
1012
- $btn = $('.' + prefix + name + '-button', t.$btnPane),
1013
- show = $dropdown.is(':hidden');
1014
-
1015
- $('body', d).trigger('mousedown');
1016
-
1017
- if (show) {
1018
- var o = $btn.offset().left;
1019
- $btn.addClass(prefix + 'active');
1020
-
1021
- $dropdown.css({
1022
- position: 'absolute',
1023
- top: $btn.offset().top - t.$btnPane.offset().top + $btn.outerHeight(),
1024
- left: (t.o.fixedFullWidth && t.isFixed) ? o + 'px' : (o - t.$btnPane.offset().left) + 'px'
1025
- }).show();
1026
-
1027
- $(window).trigger('scroll');
1028
-
1029
- $('body', d).on('mousedown.' + t.eventNamespace, function (e) {
1030
- if (!$dropdown.is(e.target)) {
1031
- $('.' + prefix + 'dropdown', t.$box).hide();
1032
- $('.' + prefix + 'active', t.$btnPane).removeClass(prefix + 'active');
1033
- $('body', d).off('mousedown.' + t.eventNamespace);
1034
- }
1035
- });
1036
- }
1037
- },
1038
-
1039
- // HTML Code management
1040
- html: function (html) {
1041
- var t = this;
1042
-
1043
- if (html != null) {
1044
- t.$ta.val(html);
1045
- t.syncCode(true);
1046
- t.$c.trigger('tbwchange');
1047
- return t;
1048
- }
1049
-
1050
- return t.$ta.val();
1051
- },
1052
-
1053
- syncTextarea: function () {
1054
- var t = this;
1055
- t.$ta.val(t.$ed.text().trim().length > 0 || t.$ed.find('hr,img,embed,iframe,input').length > 0 ? t.$ed.html() : '');
1056
- },
1057
-
1058
- syncCode: function (force) {
1059
- var t = this;
1060
- if (!force && t.$ed.is(':visible')) {
1061
- t.syncTextarea();
1062
- } else {
1063
- // wrap the content in a div it's easier to get the innerhtml
1064
- var html = $('<div>').html(t.$ta.val());
1065
- //scrub the html before loading into the doc
1066
- var safe = $('<div>').append(html);
1067
- $(t.o.tagsToRemove.join(','), safe).remove();
1068
- t.$ed.html(safe.contents().html());
1069
- }
1070
-
1071
- if (t.o.autogrow) {
1072
- t.height = t.$ed.height();
1073
- if (t.height !== t.$ta.css('height')) {
1074
- t.$ta.css({height: t.height});
1075
- t.$c.trigger('tbwresize');
1076
- }
1077
- }
1078
- if (t.o.autogrowOnEnter) {
1079
- // t.autogrowEditorOnEnter();
1080
- t.$ed.height('auto');
1081
- var totalheight = t.autogrowOnEnterWasFocused ? t.$ed[0].scrollHeight : t.$ed.css('min-height');
1082
- if (totalheight !== t.$ta.css('height')) {
1083
- t.$ed.css({height: totalheight});
1084
- t.$c.trigger('tbwresize');
1085
- }
1086
- }
1087
- },
1088
-
1089
- // Analyse and update to semantic code
1090
- // @param force : force to sync code from textarea
1091
- // @param full : wrap text nodes in <p>
1092
- // @param keepRange : leave selection range as it is
1093
- semanticCode: function (force, full, keepRange) {
1094
- var t = this;
1095
- t.saveRange();
1096
- t.syncCode(force);
1097
-
1098
- if (t.o.semantic) {
1099
- t.semanticTag('b');
1100
- t.semanticTag('i');
1101
- t.semanticTag('s');
1102
- t.semanticTag('strike');
1103
-
1104
- if (full) {
1105
- var inlineElementsSelector = t.o.inlineElementsSelector,
1106
- blockElementsSelector = ':not(' + inlineElementsSelector + ')';
1107
-
1108
- // Wrap text nodes in span for easier processing
1109
- t.$ed.contents().filter(function () {
1110
- return this.nodeType === 3 && this.nodeValue.trim().length > 0;
1111
- }).wrap('<span data-tbw/>');
1112
-
1113
- // Wrap groups of inline elements in paragraphs (recursive)
1114
- var wrapInlinesInParagraphsFrom = function ($from) {
1115
- if ($from.length !== 0) {
1116
- var $finalParagraph = $from.nextUntil(blockElementsSelector).addBack().wrapAll('<p/>').parent(),
1117
- $nextElement = $finalParagraph.nextAll(inlineElementsSelector).first();
1118
- $finalParagraph.next('br').remove();
1119
- wrapInlinesInParagraphsFrom($nextElement);
1120
- }
1121
- };
1122
- wrapInlinesInParagraphsFrom(t.$ed.children(inlineElementsSelector).first());
1123
-
1124
- t.semanticTag('div', true);
1125
-
1126
- // Unwrap paragraphs content, containing nothing usefull
1127
- t.$ed.find('p').filter(function () {
1128
- // Don't remove currently being edited element
1129
- if (t.range && this === t.range.startContainer) {
1130
- return false;
1131
- }
1132
- return $(this).text().trim().length === 0 && $(this).children().not('br,span').length === 0;
1133
- }).contents().unwrap();
1134
-
1135
- // Get rid of temporial span's
1136
- $('[data-tbw]', t.$ed).contents().unwrap();
1137
-
1138
- // Remove empty <p>
1139
- t.$ed.find('p:empty').remove();
1140
- }
1141
-
1142
- if (!keepRange) {
1143
- t.restoreRange();
1144
- }
1145
-
1146
- t.syncTextarea();
1147
- }
1148
- },
1149
-
1150
- semanticTag: function (oldTag, copyAttributes) {
1151
- var newTag;
1152
-
1153
- if (this.o.semantic != null && typeof this.o.semantic === 'object' && this.o.semantic.hasOwnProperty(oldTag)) {
1154
- newTag = this.o.semantic[oldTag];
1155
- } else if (this.o.semantic === true && this.DEFAULT_SEMANTIC_MAP.hasOwnProperty(oldTag)) {
1156
- newTag = this.DEFAULT_SEMANTIC_MAP[oldTag];
1157
- } else {
1158
- return;
1159
- }
1160
-
1161
- $(oldTag, this.$ed).each(function () {
1162
- var $oldTag = $(this);
1163
- $oldTag.wrap('<' + newTag + '/>');
1164
- if (copyAttributes) {
1165
- $.each($oldTag.prop('attributes'), function () {
1166
- $oldTag.parent().attr(this.name, this.value);
1167
- });
1168
- }
1169
- $oldTag.contents().unwrap();
1170
- });
1171
- },
1172
-
1173
- // Function call when user click on "Insert Link"
1174
- createLink: function () {
1175
- var t = this,
1176
- documentSelection = t.doc.getSelection(),
1177
- node = documentSelection.focusNode,
1178
- text = new XMLSerializer().serializeToString(documentSelection.getRangeAt(0).cloneContents()),
1179
- url,
1180
- title,
1181
- target;
1182
-
1183
- while (['A', 'DIV'].indexOf(node.nodeName) < 0) {
1184
- node = node.parentNode;
1185
- }
1186
-
1187
- if (node && node.nodeName === 'A') {
1188
- var $a = $(node);
1189
- text = $a.text();
1190
- url = $a.attr('href');
1191
- title = $a.attr('title');
1192
- target = $a.attr('target');
1193
- var range = t.doc.createRange();
1194
- range.selectNode(node);
1195
- documentSelection.removeAllRanges();
1196
- documentSelection.addRange(range);
1197
- }
1198
-
1199
- t.saveRange();
1200
-
1201
- t.openModalInsert(t.lang.createLink, {
1202
- url: {
1203
- label: 'URL',
1204
- required: true,
1205
- value: url
1206
- },
1207
- title: {
1208
- label: t.lang.title,
1209
- value: title
1210
- },
1211
- text: {
1212
- label: t.lang.text,
1213
- value: text
1214
- },
1215
- target: {
1216
- label: t.lang.target,
1217
- value: target
1218
- }
1219
- }, function (v) { // v is value
1220
- var link = $(['<a href="', v.url, '">', v.text || v.url, '</a>'].join(''));
1221
- if (v.title.length > 0) {
1222
- link.attr('title', v.title);
1223
- }
1224
- if (v.target.length > 0) {
1225
- link.attr('target', v.target);
1226
- }
1227
- t.range.deleteContents();
1228
- t.range.insertNode(link[0]);
1229
- t.syncCode();
1230
- t.$c.trigger('tbwchange');
1231
- return true;
1232
- });
1233
- },
1234
-
1235
- unlink: function () {
1236
- var t = this,
1237
- documentSelection = t.doc.getSelection(),
1238
- node = documentSelection.focusNode;
1239
-
1240
- if (documentSelection.isCollapsed) {
1241
- while (['A', 'DIV'].indexOf(node.nodeName) < 0) {
1242
- node = node.parentNode;
1243
- }
1244
-
1245
- if (node && node.nodeName === 'A') {
1246
- var range = t.doc.createRange();
1247
- range.selectNode(node);
1248
- documentSelection.removeAllRanges();
1249
- documentSelection.addRange(range);
1250
- }
1251
- }
1252
- t.execCmd('unlink', undefined, undefined, true);
1253
- },
1254
-
1255
- insertImage: function () {
1256
- var t = this;
1257
- t.saveRange();
1258
-
1259
- var options = {
1260
- url: {
1261
- label: 'URL',
1262
- required: true
1263
- },
1264
- alt: {
1265
- label: t.lang.description,
1266
- value: t.getRangeText()
1267
- }
1268
- };
1269
-
1270
- if (t.o.imageWidthModalEdit) {
1271
- options.width = {};
1272
- }
1273
-
1274
- t.openModalInsert(t.lang.insertImage, options, function (v) { // v are values
1275
- t.execCmd('insertImage', v.url);
1276
- var $img = $('img[src="' + v.url + '"]:not([alt])', t.$box);
1277
- $img.attr('alt', v.alt);
1278
-
1279
- if (t.o.imageWidthModalEdit) {
1280
- $img.attr({
1281
- width: v.width
1282
- });
1283
- }
1284
-
1285
- t.syncCode();
1286
- t.$c.trigger('tbwchange');
1287
-
1288
- return true;
1289
- });
1290
- },
1291
-
1292
- fullscreen: function () {
1293
- var t = this,
1294
- prefix = t.o.prefix,
1295
- fullscreenCssClass = prefix + 'fullscreen',
1296
- isFullscreen;
1297
-
1298
- t.$box.toggleClass(fullscreenCssClass);
1299
- isFullscreen = t.$box.hasClass(fullscreenCssClass);
1300
- $('body').toggleClass(prefix + 'body-fullscreen', isFullscreen);
1301
- $(window).trigger('scroll');
1302
- t.$c.trigger('tbw' + (isFullscreen ? 'open' : 'close') + 'fullscreen');
1303
- },
1304
-
1305
- /*
1306
- * Call method of trumbowyg if exist
1307
- * else try to call anonymous function
1308
- * and finaly native execCommand
1309
- */
1310
- execCmd: function (cmd, param, forceCss, skipTrumbowyg) {
1311
- var t = this;
1312
- skipTrumbowyg = !!skipTrumbowyg || '';
1313
-
1314
- if (cmd !== 'dropdown') {
1315
- t.$ed.focus();
1316
- }
1317
-
1318
- try {
1319
- t.doc.execCommand('styleWithCSS', false, forceCss || false);
1320
- } catch (c) {
1321
- }
1322
-
1323
- try {
1324
- t[cmd + skipTrumbowyg](param);
1325
- } catch (c) {
1326
- try {
1327
- cmd(param);
1328
- } catch (e2) {
1329
- if (cmd === 'insertHorizontalRule') {
1330
- param = undefined;
1331
- } else if (cmd === 'formatBlock' && t.isIE) {
1332
- param = '<' + param + '>';
1333
- }
1334
-
1335
- t.doc.execCommand(cmd, false, param);
1336
-
1337
- t.syncCode();
1338
- t.semanticCode(false, true);
1339
- }
1340
-
1341
- if (cmd !== 'dropdown') {
1342
- t.updateButtonPaneStatus();
1343
- t.$c.trigger('tbwchange');
1344
- }
1345
- }
1346
- },
1347
-
1348
- // Open a modal box
1349
- openModal: function (title, content) {
1350
- var t = this,
1351
- prefix = t.o.prefix;
1352
-
1353
- // No open a modal box when exist other modal box
1354
- if ($('.' + prefix + 'modal-box', t.$box).length > 0) {
1355
- return false;
1356
- }
1357
- if (t.o.autogrowOnEnter) {
1358
- t.autogrowOnEnterDontClose = true;
1359
- }
1360
-
1361
- t.saveRange();
1362
- t.showOverlay();
1363
-
1364
- // Disable all btnPane btns
1365
- t.$btnPane.addClass(prefix + 'disable');
1366
-
1367
- // Build out of ModalBox, it's the mask for animations
1368
- var $modal = $('<div/>', {
1369
- class: prefix + 'modal ' + prefix + 'fixed-top'
1370
- }).css({
1371
- top: t.$btnPane.height()
1372
- }).appendTo(t.$box);
1373
-
1374
- // Click on overlay close modal by cancelling them
1375
- t.$overlay.one('click', function () {
1376
- $modal.trigger(CANCEL_EVENT);
1377
- return false;
1378
- });
1379
-
1380
- // Build the form
1381
- var $form = $('<form/>', {
1382
- action: '',
1383
- html: content
1384
- })
1385
- .on('submit', function () {
1386
- $modal.trigger(CONFIRM_EVENT);
1387
- return false;
1388
- })
1389
- .on('reset', function () {
1390
- $modal.trigger(CANCEL_EVENT);
1391
- return false;
1392
- })
1393
- .on('submit reset', function () {
1394
- if (t.o.autogrowOnEnter) {
1395
- t.autogrowOnEnterDontClose = false;
1396
- }
1397
- });
1398
-
1399
- // Build ModalBox and animate to show them
1400
- var $box = $('<div/>', {
1401
- class: prefix + 'modal-box',
1402
- html: $form
1403
- })
1404
- .css({
1405
- top: '-' + t.$btnPane.outerHeight() + 'px',
1406
- opacity: 0
1407
- })
1408
- .appendTo($modal)
1409
- .animate({
1410
- top: 0,
1411
- opacity: 1
1412
- }, 100);
1413
-
1414
- // Append title
1415
- $('<span/>', {
1416
- text: title,
1417
- class: prefix + 'modal-title'
1418
- }).prependTo($box);
1419
-
1420
- $modal.height($box.outerHeight() + 10);
1421
-
1422
- // Focus in modal box
1423
- $('input:first', $box).focus();
1424
-
1425
- // Append Confirm and Cancel buttons
1426
- t.buildModalBtn('submit', $box);
1427
- t.buildModalBtn('reset', $box);
1428
-
1429
- $(window).trigger('scroll');
1430
-
1431
- return $modal;
1432
- },
1433
-
1434
- // @param n is name of modal
1435
- buildModalBtn: function (n, $modal) {
1436
- var t = this,
1437
- prefix = t.o.prefix;
1438
-
1439
- return $('<button/>', {
1440
- class: prefix + 'modal-button ' + prefix + 'modal-' + n,
1441
- type: n,
1442
- text: t.lang[n] || n
1443
- }).appendTo($('form', $modal));
1444
- },
1445
-
1446
- // close current modal box
1447
- closeModal: function () {
1448
- var t = this,
1449
- prefix = t.o.prefix;
1450
-
1451
- t.$btnPane.removeClass(prefix + 'disable');
1452
- t.$overlay.off();
1453
-
1454
- // Find the modal box
1455
- var $modalBox = $('.' + prefix + 'modal-box', t.$box);
1456
-
1457
- $modalBox.animate({
1458
- top: '-' + $modalBox.height()
1459
- }, 100, function () {
1460
- $modalBox.parent().remove();
1461
- t.hideOverlay();
1462
- });
1463
-
1464
- t.restoreRange();
1465
- },
1466
-
1467
- // Preformated build and management modal
1468
- openModalInsert: function (title, fields, cmd) {
1469
- var t = this,
1470
- prefix = t.o.prefix,
1471
- lg = t.lang,
1472
- html = '';
1473
-
1474
- $.each(fields, function (fieldName, field) {
1475
- var l = field.label || fieldName,
1476
- n = field.name || fieldName,
1477
- a = field.attributes || {};
1478
-
1479
- var attr = Object.keys(a).map(function (prop) {
1480
- return prop + '="' + a[prop] + '"';
1481
- }).join(' ');
1482
-
1483
- html += '<label><input type="' + (field.type || 'text') + '" name="' + n + '"' +
1484
- (field.type === 'checkbox' && field.value ? ' checked="checked"' : ' value="' + (field.value || '').replace(/"/g, '&quot;')) +
1485
- '"' + attr + '><span class="' + prefix + 'input-infos"><span>' +
1486
- (lg[l] ? lg[l] : l) +
1487
- '</span></span></label>';
1488
- });
1489
-
1490
- return t.openModal(title, html)
1491
- .on(CONFIRM_EVENT, function () {
1492
- var $form = $('form', $(this)),
1493
- valid = true,
1494
- values = {};
1495
-
1496
- $.each(fields, function (fieldName, field) {
1497
- var n = field.name || fieldName;
1498
-
1499
- var $field = $('input[name="' + n + '"]', $form),
1500
- inputType = $field.attr('type');
1501
-
1502
- switch (inputType.toLowerCase()) {
1503
- case 'checkbox':
1504
- values[n] = $field.is(':checked');
1505
- break;
1506
- case 'radio':
1507
- values[n] = $field.filter(':checked').val();
1508
- break;
1509
- default:
1510
- values[n] = $.trim($field.val());
1511
- break;
1512
- }
1513
- // Validate value
1514
- if (field.required && values[n] === '') {
1515
- valid = false;
1516
- t.addErrorOnModalField($field, t.lang.required);
1517
- } else if (field.pattern && !field.pattern.test(values[n])) {
1518
- valid = false;
1519
- t.addErrorOnModalField($field, field.patternError);
1520
- }
1521
- });
1522
-
1523
- if (valid) {
1524
- t.restoreRange();
1525
-
1526
- if (cmd(values, fields)) {
1527
- t.syncCode();
1528
- t.$c.trigger('tbwchange');
1529
- t.closeModal();
1530
- $(this).off(CONFIRM_EVENT);
1531
- }
1532
- }
1533
- })
1534
- .one(CANCEL_EVENT, function () {
1535
- $(this).off(CONFIRM_EVENT);
1536
- t.closeModal();
1537
- });
1538
- },
1539
-
1540
- addErrorOnModalField: function ($field, err) {
1541
- var prefix = this.o.prefix,
1542
- $label = $field.parent();
1543
-
1544
- $field
1545
- .on('change keyup', function () {
1546
- $label.removeClass(prefix + 'input-error');
1547
- });
1548
-
1549
- $label
1550
- .addClass(prefix + 'input-error')
1551
- .find('input+span')
1552
- .append(
1553
- $('<span/>', {
1554
- class: prefix + 'msg-error',
1555
- text: err
1556
- })
1557
- );
1558
- },
1559
-
1560
- getDefaultImgDblClickHandler: function () {
1561
- var t = this;
1562
-
1563
- return function () {
1564
- var $img = $(this),
1565
- src = $img.attr('src'),
1566
- base64 = '(Base64)';
1567
-
1568
- if (src.indexOf('data:image') === 0) {
1569
- src = base64;
1570
- }
1571
-
1572
- var options = {
1573
- url: {
1574
- label: 'URL',
1575
- value: src,
1576
- required: true
1577
- },
1578
- alt: {
1579
- label: t.lang.description,
1580
- value: $img.attr('alt')
1581
- }
1582
- };
1583
-
1584
- if (t.o.imageWidthModalEdit) {
1585
- options.width = {
1586
- value: $img.attr('width') ? $img.attr('width') : ''
1587
- };
1588
- }
1589
-
1590
- t.openModalInsert(t.lang.insertImage, options, function (v) {
1591
- if (v.src !== base64) {
1592
- $img.attr({
1593
- src: v.url
1594
- });
1595
- }
1596
- $img.attr({
1597
- alt: v.alt
1598
- });
1599
-
1600
- if (t.o.imageWidthModalEdit) {
1601
- if (parseInt(v.width) > 0) {
1602
- $img.attr({
1603
- width: v.width
1604
- });
1605
- } else {
1606
- $img.removeAttr('width');
1607
- }
1608
- }
1609
-
1610
- return true;
1611
- });
1612
- return false;
1613
- };
1614
- },
1615
-
1616
- // Range management
1617
- saveRange: function () {
1618
- var t = this,
1619
- documentSelection = t.doc.getSelection();
1620
-
1621
- t.range = null;
1622
-
1623
- if (documentSelection.rangeCount) {
1624
- var savedRange = t.range = documentSelection.getRangeAt(0),
1625
- range = t.doc.createRange(),
1626
- rangeStart;
1627
- range.selectNodeContents(t.$ed[0]);
1628
- range.setEnd(savedRange.startContainer, savedRange.startOffset);
1629
- rangeStart = (range + '').length;
1630
- t.metaRange = {
1631
- start: rangeStart,
1632
- end: rangeStart + (savedRange + '').length
1633
- };
1634
- }
1635
- },
1636
-
1637
- restoreRange: function () {
1638
- var t = this,
1639
- metaRange = t.metaRange,
1640
- savedRange = t.range,
1641
- documentSelection = t.doc.getSelection(),
1642
- range;
1643
-
1644
- if (!savedRange) {
1645
- return;
1646
- }
1647
-
1648
- if (metaRange && metaRange.start !== metaRange.end) { // Algorithm from http://jsfiddle.net/WeWy7/3/
1649
- var charIndex = 0,
1650
- nodeStack = [t.$ed[0]],
1651
- node,
1652
- foundStart = false,
1653
- stop = false;
1654
-
1655
- range = t.doc.createRange();
1656
-
1657
- while (!stop && (node = nodeStack.pop())) {
1658
- if (node.nodeType === 3) {
1659
- var nextCharIndex = charIndex + node.length;
1660
- if (!foundStart && metaRange.start >= charIndex && metaRange.start <= nextCharIndex) {
1661
- range.setStart(node, metaRange.start - charIndex);
1662
- foundStart = true;
1663
- }
1664
- if (foundStart && metaRange.end >= charIndex && metaRange.end <= nextCharIndex) {
1665
- range.setEnd(node, metaRange.end - charIndex);
1666
- stop = true;
1667
- }
1668
- charIndex = nextCharIndex;
1669
- } else {
1670
- var cn = node.childNodes,
1671
- i = cn.length;
1672
-
1673
- while (i > 0) {
1674
- i -= 1;
1675
- nodeStack.push(cn[i]);
1676
- }
1677
- }
1678
- }
1679
- }
1680
-
1681
- documentSelection.removeAllRanges();
1682
- documentSelection.addRange(range || savedRange);
1683
- },
1684
-
1685
- getRangeText: function () {
1686
- return this.range + '';
1687
- },
1688
-
1689
- updateButtonPaneStatus: function () {
1690
- var t = this,
1691
- prefix = t.o.prefix,
1692
- tags = t.getTagsRecursive(t.doc.getSelection().focusNode),
1693
- activeClasses = prefix + 'active-button ' + prefix + 'active';
1694
-
1695
- $('.' + prefix + 'active-button', t.$btnPane).removeClass(activeClasses);
1696
- $.each(tags, function (i, tag) {
1697
- var btnName = t.tagToButton[tag.toLowerCase()],
1698
- $btn = $('.' + prefix + btnName + '-button', t.$btnPane);
1699
-
1700
- if ($btn.length > 0) {
1701
- $btn.addClass(activeClasses);
1702
- } else {
1703
- try {
1704
- $btn = $('.' + prefix + 'dropdown .' + prefix + btnName + '-dropdown-button', t.$box);
1705
- var dropdownBtnName = $btn.parent().data('dropdown');
1706
- $('.' + prefix + dropdownBtnName + '-button', t.$box).addClass(activeClasses);
1707
- } catch (e) {
1708
- }
1709
- }
1710
- });
1711
- },
1712
-
1713
- getTagsRecursive: function (element, tags) {
1714
- var t = this;
1715
- tags = tags || (element && element.tagName ? [element.tagName] : []);
1716
-
1717
- if (element && element.parentNode) {
1718
- element = element.parentNode;
1719
- } else {
1720
- return tags;
1721
- }
1722
-
1723
- var tag = element.tagName;
1724
- if (tag === 'DIV') {
1725
- return tags;
1726
- }
1727
- if (tag === 'P' && element.style.textAlign !== '') {
1728
- tags.push(element.style.textAlign);
1729
- }
1730
-
1731
- $.each(t.tagHandlers, function (i, tagHandler) {
1732
- tags = tags.concat(tagHandler(element, t));
1733
- });
1734
-
1735
- tags.push(tag);
1736
-
1737
- return t.getTagsRecursive(element, tags).filter(function (tag) {
1738
- return tag != null;
1739
- });
1740
- },
1741
-
1742
- // Plugins
1743
- initPlugins: function () {
1744
- var t = this;
1745
- t.loadedPlugins = [];
1746
- $.each($.trumbowyg.plugins, function (name, plugin) {
1747
- if (!plugin.shouldInit || plugin.shouldInit(t)) {
1748
- plugin.init(t);
1749
- if (plugin.tagHandler) {
1750
- t.tagHandlers.push(plugin.tagHandler);
1751
- }
1752
- t.loadedPlugins.push(plugin);
1753
- }
1754
- });
1755
- },
1756
-
1757
- destroyPlugins: function () {
1758
- $.each(this.loadedPlugins, function (i, plugin) {
1759
- if (plugin.destroy) {
1760
- plugin.destroy();
1761
- }
1762
- });
1763
- }
1764
- };
1765
- })(navigator, window, document, jQuery);