lato_core 1.1.5 → 2.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (307) hide show
  1. checksums.yaml +4 -4
  2. data/MIT-LICENSE +20 -0
  3. data/README.md +29 -0
  4. data/Rakefile +1 -22
  5. data/app/assets/config/lato_core_manifest.js +2 -0
  6. data/app/assets/fonts/lato_core/fontawesome-webfont.eot +0 -0
  7. data/app/assets/fonts/lato_core/fontawesome-webfont.svg +2671 -0
  8. data/app/assets/fonts/lato_core/fontawesome-webfont.ttf +0 -0
  9. data/app/assets/fonts/lato_core/fontawesome-webfont.woff +0 -0
  10. data/app/assets/fonts/lato_core/fontawesome-webfont.woff2 +0 -0
  11. data/app/assets/fonts/lato_core/lato-bold-webfont.eot +0 -0
  12. data/app/assets/fonts/lato_core/lato-bold-webfont.svg +4551 -0
  13. data/app/assets/fonts/lato_core/lato-bold-webfont.ttf +0 -0
  14. data/app/assets/fonts/lato_core/lato-bold-webfont.woff +0 -0
  15. data/app/assets/fonts/lato_core/lato-bold-webfont.woff2 +0 -0
  16. data/app/assets/fonts/lato_core/lato-regular-webfont.eot +0 -0
  17. data/app/assets/fonts/lato_core/lato-regular-webfont.svg +4241 -0
  18. data/app/assets/fonts/lato_core/lato-regular-webfont.ttf +0 -0
  19. data/app/assets/fonts/lato_core/lato-regular-webfont.woff +0 -0
  20. data/app/assets/fonts/lato_core/lato-regular-webfont.woff2 +0 -0
  21. data/app/assets/images/lato_core/editor-icons.svg +1 -0
  22. data/app/assets/images/lato_core/logo-negative.svg +13 -0
  23. data/app/assets/images/lato_core/logo.svg +1 -0
  24. data/app/assets/images/lato_core/user.png +0 -0
  25. data/app/assets/javascripts/lato_core/application.js +28 -0
  26. data/app/assets/javascripts/lato_core/initializers/Charts.js +36 -0
  27. data/app/assets/javascripts/lato_core/initializers/Elements.js +67 -0
  28. data/app/assets/javascripts/lato_core/initializers/Inputs.js +201 -0
  29. data/app/assets/javascripts/lato_core/initializers/Layout.js +37 -0
  30. data/app/assets/javascripts/lato_core/initializers/SortableManager.js +66 -0
  31. data/app/assets/javascripts/lato_core/interfaces/Modal.js +28 -0
  32. data/app/assets/javascripts/lato_core/vendors/Sortable.min.js +2 -0
  33. data/app/assets/javascripts/lato_core/vendors/chart.bundle.js +17220 -0
  34. data/app/assets/javascripts/lato_core/vendors/dropzone.js +1767 -0
  35. data/app/assets/javascripts/lato_core/vendors/jquery.datetimepicker.full.js +3243 -0
  36. data/app/assets/javascripts/lato_core/vendors/jquery.floatThead.js +1106 -0
  37. data/app/assets/javascripts/lato_core/vendors/jquery.selectize.js +3829 -0
  38. data/app/assets/javascripts/lato_core/vendors/jquery.trumbowyg.js +1603 -0
  39. data/app/assets/stylesheets/lato_core/application.scss +23 -0
  40. data/app/assets/stylesheets/lato_core/base/_base.scss +35 -0
  41. data/app/assets/stylesheets/lato_core/base/_button.scss +23 -0
  42. data/app/assets/stylesheets/lato_core/base/_grid.scss +258 -0
  43. data/app/assets/stylesheets/lato_core/base/_helpers.scss +29 -0
  44. data/app/assets/stylesheets/lato_core/base/_mixin.scss +37 -0
  45. data/app/assets/stylesheets/lato_core/base/_normalize.scss +424 -0
  46. data/app/assets/stylesheets/lato_core/base/_table.scss +47 -0
  47. data/app/assets/stylesheets/lato_core/base/_typography.scss +23 -0
  48. data/app/assets/stylesheets/lato_core/cells/_cells.scss +4 -0
  49. data/app/assets/stylesheets/lato_core/cells/charts/_bar.scss +3 -0
  50. data/app/assets/stylesheets/lato_core/cells/charts/_charts.scss +2 -0
  51. data/app/assets/stylesheets/lato_core/cells/charts/_general.scss +7 -0
  52. data/app/assets/stylesheets/lato_core/cells/elements/_block.scss +12 -0
  53. data/app/assets/stylesheets/lato_core/cells/elements/_button.scss +132 -0
  54. data/app/assets/stylesheets/lato_core/cells/elements/_buttongroup.scss +25 -0
  55. data/app/assets/stylesheets/lato_core/cells/elements/_code.scss +8 -0
  56. data/app/assets/stylesheets/lato_core/cells/elements/_elements.scss +10 -0
  57. data/app/assets/stylesheets/lato_core/cells/elements/_flash.scss +74 -0
  58. data/app/assets/stylesheets/lato_core/cells/elements/_modal.scss +76 -0
  59. data/app/assets/stylesheets/lato_core/cells/elements/_pagination.scss +64 -0
  60. data/app/assets/stylesheets/lato_core/cells/elements/_row.scss +3 -0
  61. data/app/assets/stylesheets/lato_core/cells/elements/_table.scss +57 -0
  62. data/app/assets/stylesheets/lato_core/cells/elements/_title.scss +32 -0
  63. data/app/assets/stylesheets/lato_core/cells/inputs/_checkbox.scss +42 -0
  64. data/app/assets/stylesheets/lato_core/cells/inputs/_datetime.scss +23 -0
  65. data/app/assets/stylesheets/lato_core/cells/inputs/_dropzone.scss +12 -0
  66. data/app/assets/stylesheets/lato_core/cells/inputs/_editor.scss +3 -0
  67. data/app/assets/stylesheets/lato_core/cells/inputs/_email.scss +3 -0
  68. data/app/assets/stylesheets/lato_core/cells/inputs/_form.scss +3 -0
  69. data/app/assets/stylesheets/lato_core/cells/inputs/_general.scss +51 -0
  70. data/app/assets/stylesheets/lato_core/cells/inputs/_geolocalization.scss +12 -0
  71. data/app/assets/stylesheets/lato_core/cells/inputs/_inputs.scss +14 -0
  72. data/app/assets/stylesheets/lato_core/cells/inputs/_number.scss +3 -0
  73. data/app/assets/stylesheets/lato_core/cells/inputs/_password.scss +3 -0
  74. data/app/assets/stylesheets/lato_core/cells/inputs/_select.scss +47 -0
  75. data/app/assets/stylesheets/lato_core/cells/inputs/_sortableblock.scss +51 -0
  76. data/app/assets/stylesheets/lato_core/cells/inputs/_text.scss +3 -0
  77. data/app/assets/stylesheets/lato_core/cells/inputs/_textarea.scss +25 -0
  78. data/app/assets/stylesheets/lato_core/cells/widgets/_index.scss +74 -0
  79. data/app/assets/stylesheets/lato_core/cells/widgets/_widgets.scss +1 -0
  80. data/app/assets/stylesheets/lato_core/layouts/_admin.scss +352 -0
  81. data/app/assets/stylesheets/lato_core/layouts/_authentication.scss +10 -0
  82. data/app/assets/stylesheets/lato_core/layouts/_layouts.scss +2 -0
  83. data/app/assets/stylesheets/lato_core/pages/_dashboard.scss +35 -0
  84. data/app/assets/stylesheets/lato_core/pages/_login.scss +7 -0
  85. data/app/assets/stylesheets/lato_core/pages/_pages.scss +2 -0
  86. data/app/assets/stylesheets/lato_core/partials/_dynamic_data_to_js.scss +3 -0
  87. data/app/assets/stylesheets/lato_core/partials/_partials.scss +1 -0
  88. data/app/assets/stylesheets/lato_core/theme.scss.erb +127 -0
  89. data/app/assets/stylesheets/lato_core/vendors/_datetimepicker.css +568 -0
  90. data/app/assets/stylesheets/lato_core/vendors/_dropzone.css +388 -0
  91. data/app/assets/stylesheets/lato_core/vendors/_fontawesome.css +2341 -0
  92. data/app/assets/stylesheets/lato_core/vendors/_scrollbar.css +904 -0
  93. data/app/assets/stylesheets/lato_core/vendors/_selectize.css +324 -0
  94. data/app/assets/stylesheets/lato_core/vendors/_trumbowyg.css +584 -0
  95. data/app/assets/stylesheets/lato_core/vendors/_vendors.scss +6 -0
  96. data/app/assets/stylesheets/lato_core/widgets/_systeminfo.scss +21 -0
  97. data/app/assets/stylesheets/lato_core/widgets/_widgets.scss +1 -0
  98. data/app/cells/lato_core/charts/bar/vertical/cell.rb +57 -0
  99. data/app/cells/lato_core/charts/bar/vertical/views/show.html.erb +7 -0
  100. data/app/cells/lato_core/elements/block/cell.rb +39 -0
  101. data/app/cells/lato_core/elements/block/views/close.html.erb +1 -0
  102. data/app/cells/lato_core/elements/block/views/open.html.erb +4 -0
  103. data/app/cells/lato_core/elements/button/cell.rb +59 -0
  104. data/app/cells/lato_core/elements/button/views/button.html.erb +27 -0
  105. data/app/cells/lato_core/elements/button/views/link.html.erb +65 -0
  106. data/app/cells/lato_core/elements/buttongroup/cell.rb +33 -0
  107. data/app/cells/lato_core/elements/buttongroup/views/show.html.erb +7 -0
  108. data/app/cells/lato_core/elements/code/cell.rb +36 -0
  109. data/app/cells/lato_core/elements/code/views/close.html.erb +2 -0
  110. data/app/cells/lato_core/elements/code/views/open.html.erb +2 -0
  111. data/app/cells/lato_core/elements/flash/cell.rb +35 -0
  112. data/app/cells/lato_core/elements/flash/views/show.html.erb +11 -0
  113. data/app/cells/lato_core/elements/icon/cell.rb +31 -0
  114. data/app/cells/lato_core/elements/icon/views/show.html.erb +1 -0
  115. data/app/cells/lato_core/elements/modal/cell.rb +31 -0
  116. data/app/cells/lato_core/elements/modal/views/show.html.erb +21 -0
  117. data/app/cells/lato_core/elements/pagination/cell.rb +68 -0
  118. data/app/cells/lato_core/elements/pagination/views/show.html.erb +59 -0
  119. data/app/cells/lato_core/elements/row/cell.rb +37 -0
  120. data/app/cells/lato_core/elements/row/views/close.html.erb +1 -0
  121. data/app/cells/lato_core/elements/row/views/open.html.erb +3 -0
  122. data/app/cells/lato_core/elements/table/body/cell.rb +37 -0
  123. data/app/cells/lato_core/elements/table/body/views/close.html.erb +1 -0
  124. data/app/cells/lato_core/elements/table/body/views/open.html.erb +3 -0
  125. data/app/cells/lato_core/elements/table/container/cell.rb +41 -0
  126. data/app/cells/lato_core/elements/table/container/views/close.html.erb +2 -0
  127. data/app/cells/lato_core/elements/table/container/views/open.html.erb +7 -0
  128. data/app/cells/lato_core/elements/table/head/cell.rb +33 -0
  129. data/app/cells/lato_core/elements/table/head/views/show.html.erb +7 -0
  130. data/app/cells/lato_core/elements/table/row/cell.rb +49 -0
  131. data/app/cells/lato_core/elements/table/row/views/show.html.erb +35 -0
  132. data/app/cells/lato_core/elements/title/cell.rb +52 -0
  133. data/app/cells/lato_core/elements/title/views/show.html.erb +4 -0
  134. data/app/cells/lato_core/inputs/checkbox/cell.rb +38 -0
  135. data/app/cells/lato_core/inputs/checkbox/views/show.html.erb +20 -0
  136. data/app/cells/lato_core/inputs/datetime/cell.rb +53 -0
  137. data/app/cells/lato_core/inputs/datetime/views/show.html.erb +19 -0
  138. data/app/cells/lato_core/inputs/dropzone/cell.rb +37 -0
  139. data/app/cells/lato_core/inputs/dropzone/views/show.html.erb +24 -0
  140. data/app/cells/lato_core/inputs/editor/cell.rb +37 -0
  141. data/app/cells/lato_core/inputs/editor/views/show.html.erb +12 -0
  142. data/app/cells/lato_core/inputs/email/cell.rb +40 -0
  143. data/app/cells/lato_core/inputs/email/views/show.html.erb +19 -0
  144. data/app/cells/lato_core/inputs/form/cell.rb +39 -0
  145. data/app/cells/lato_core/inputs/form/views/close.html.erb +1 -0
  146. data/app/cells/lato_core/inputs/form/views/open.html.erb +12 -0
  147. data/app/cells/lato_core/inputs/geolocalization/cell.rb +51 -0
  148. data/app/cells/lato_core/inputs/geolocalization/views/show.html.erb +26 -0
  149. data/app/cells/lato_core/inputs/number/cell.rb +44 -0
  150. data/app/cells/lato_core/inputs/number/views/show.html.erb +25 -0
  151. data/app/cells/lato_core/inputs/password/cell.rb +42 -0
  152. data/app/cells/lato_core/inputs/password/views/show.html.erb +21 -0
  153. data/app/cells/lato_core/inputs/select/cell.rb +56 -0
  154. data/app/cells/lato_core/inputs/select/views/show.html.erb +25 -0
  155. data/app/cells/lato_core/inputs/shared/help.html.erb +7 -0
  156. data/app/cells/lato_core/inputs/shared/label.html.erb +11 -0
  157. data/app/cells/lato_core/inputs/sortableblock/cell.rb +39 -0
  158. data/app/cells/lato_core/inputs/sortableblock/views/show.html.erb +40 -0
  159. data/app/cells/lato_core/inputs/text/cell.rb +42 -0
  160. data/app/cells/lato_core/inputs/text/views/show.html.erb +21 -0
  161. data/app/cells/lato_core/inputs/textarea/cell.rb +41 -0
  162. data/app/cells/lato_core/inputs/textarea/views/show.html.erb +16 -0
  163. data/app/cells/lato_core/widgets/index/cell.rb +215 -0
  164. data/app/cells/lato_core/widgets/index/views/partials/new.html.erb +3 -0
  165. data/app/cells/lato_core/widgets/index/views/partials/pagination.html.erb +3 -0
  166. data/app/cells/lato_core/widgets/index/views/partials/search.html.erb +17 -0
  167. data/app/cells/lato_core/widgets/index/views/show.html.erb +45 -0
  168. data/app/controllers/lato_core/api/api_controller.rb +5 -0
  169. data/app/controllers/lato_core/application_controller.rb +9 -1
  170. data/app/controllers/lato_core/back/authentication_controller.rb +33 -99
  171. data/app/controllers/lato_core/back/back_controller.rb +5 -14
  172. data/app/controllers/lato_core/back/dashboard_controller.rb +13 -0
  173. data/app/controllers/lato_core/back/superusers_controller.rb +97 -113
  174. data/app/controllers/lato_core/doc/cells_charts_controller.rb +7 -0
  175. data/app/controllers/lato_core/doc/cells_elements_controller.rb +31 -0
  176. data/app/controllers/lato_core/doc/cells_inputs_controller.rb +33 -0
  177. data/app/controllers/lato_core/doc/cells_widgets_controller.rb +10 -0
  178. data/app/controllers/lato_core/doc/doc_controller.rb +17 -0
  179. data/app/controllers/lato_core/doc/general_controller.rb +13 -0
  180. data/app/helpers/lato_core/application_helper.rb +4 -0
  181. data/app/jobs/lato_core/application_job.rb +4 -0
  182. data/app/mailers/lato_core/application_mailer.rb +2 -5
  183. data/app/models/lato_core/application_record.rb +5 -0
  184. data/app/models/lato_core/superuser.rb +11 -16
  185. data/app/models/lato_core/superuser/entity_helpers.rb +29 -0
  186. data/app/views/lato_core/back/authentication/index.html.erb +25 -0
  187. data/app/views/lato_core/back/dashboard/index.html.erb +29 -0
  188. data/app/views/lato_core/back/superusers/edit.html.erb +10 -15
  189. data/app/views/lato_core/back/superusers/index.html.erb +16 -27
  190. data/app/views/lato_core/back/superusers/new.html.erb +8 -13
  191. data/app/views/lato_core/back/superusers/shared/_form.html.erb +47 -55
  192. data/app/views/lato_core/back/superusers/show.html.erb +65 -1
  193. data/app/views/lato_core/doc/cells_charts/bar_vertical.erb +64 -0
  194. data/app/views/lato_core/doc/cells_elements/block.html.erb +172 -0
  195. data/app/views/lato_core/doc/cells_elements/button.html.erb +375 -0
  196. data/app/views/lato_core/doc/cells_elements/buttongroup.html.erb +101 -0
  197. data/app/views/lato_core/doc/cells_elements/flash_messages.html.erb +123 -0
  198. data/app/views/lato_core/doc/cells_elements/icon.html.erb +58 -0
  199. data/app/views/lato_core/doc/cells_elements/modal.html.erb +89 -0
  200. data/app/views/lato_core/doc/cells_elements/pagination.html.erb +149 -0
  201. data/app/views/lato_core/doc/cells_elements/row.html.erb +62 -0
  202. data/app/views/lato_core/doc/cells_elements/table.html.erb +272 -0
  203. data/app/views/lato_core/doc/cells_elements/table_body.html.erb +118 -0
  204. data/app/views/lato_core/doc/cells_elements/table_head.html.erb +110 -0
  205. data/app/views/lato_core/doc/cells_elements/table_row.html.erb +212 -0
  206. data/app/views/lato_core/doc/cells_elements/title.html.erb +70 -0
  207. data/app/views/lato_core/doc/cells_inputs/checkbox.html.erb +101 -0
  208. data/app/views/lato_core/doc/cells_inputs/datetime.html.erb +178 -0
  209. data/app/views/lato_core/doc/cells_inputs/dropzone.html.erb +114 -0
  210. data/app/views/lato_core/doc/cells_inputs/editor.html.erb +59 -0
  211. data/app/views/lato_core/doc/cells_inputs/email.html.erb +79 -0
  212. data/app/views/lato_core/doc/cells_inputs/form.html.erb +242 -0
  213. data/app/views/lato_core/doc/cells_inputs/geolocalization.html.erb +157 -0
  214. data/app/views/lato_core/doc/cells_inputs/number.html.erb +100 -0
  215. data/app/views/lato_core/doc/cells_inputs/password.html.erb +79 -0
  216. data/app/views/lato_core/doc/cells_inputs/select.html.erb +124 -0
  217. data/app/views/lato_core/doc/cells_inputs/sortableblock.html.erb +72 -0
  218. data/app/views/lato_core/doc/cells_inputs/text.html.erb +204 -0
  219. data/app/views/lato_core/doc/cells_inputs/textarea.html.erb +104 -0
  220. data/app/views/lato_core/doc/cells_widgets/index.html.erb +163 -0
  221. data/app/views/lato_core/doc/doc/index.html.erb +95 -0
  222. data/app/views/lato_core/doc/general/generators.html.erb +60 -0
  223. data/app/views/lato_core/doc/general/installation.html.erb +49 -0
  224. data/app/views/lato_core/doc/general/languages.html.erb +67 -0
  225. data/app/views/lato_core/doc/general/personalization.html.erb +177 -0
  226. data/app/views/lato_core/doc/shared/_modal_content.html.erb +4 -0
  227. data/app/views/lato_core/doc/shared/_sortableblock_partial.html.erb +1 -0
  228. data/app/views/lato_core/partials/_dynamic_data_to_js.html.erb +3 -0
  229. data/app/views/lato_core/partials/_gmaps.html.erb +5 -0
  230. data/app/views/lato_core/widgets/_systeminfo.html.erb +15 -0
  231. data/app/views/layouts/lato_core/admin.html.erb +44 -0
  232. data/app/views/layouts/lato_core/authentication.html.erb +22 -0
  233. data/app/views/layouts/lato_core/partials/_back.html.erb +5 -0
  234. data/app/views/layouts/lato_core/partials/_load_javascript.html.erb +4 -0
  235. data/app/views/layouts/lato_core/partials/_load_partials.html.erb +5 -0
  236. data/app/views/layouts/lato_core/partials/_load_stylesheet.html.erb +4 -0
  237. data/app/views/layouts/lato_core/partials/_logo.html.erb +9 -0
  238. data/app/views/layouts/lato_core/partials/_menu.html.erb +67 -0
  239. data/app/views/layouts/lato_core/partials/_profile.html.erb +19 -0
  240. data/app/views/layouts/lato_core/partials/_title.html.erb +3 -0
  241. data/app/views/layouts/lato_core/partials/_widgets.html.erb +13 -0
  242. data/config/configs.yml +102 -0
  243. data/config/initializers/assets.rb +9 -0
  244. data/config/initializers/init_system.rb +39 -0
  245. data/config/languages/default.yml +63 -0
  246. data/config/languages/it.yml +63 -0
  247. data/config/routes.rb +10 -13
  248. data/config/routes/api.rb +3 -0
  249. data/config/routes/back.rb +10 -0
  250. data/config/routes/doc.rb +48 -0
  251. data/db/migrate/20160224181217_create_lato_core_superusers.rb +8 -2
  252. data/lib/generators/lato_core/crud_generator.rb +26 -0
  253. data/lib/generators/lato_core/initializer_generator.rb +46 -0
  254. data/lib/generators/lato_core/templates/assets/images/logo.svg +13 -0
  255. data/{config/initializers/lists.rb → lib/generators/lato_core/templates/assets/javascripts/application.js} +0 -0
  256. data/lib/generators/lato_core/templates/assets/stylesheets/application.scss +2 -0
  257. data/lib/generators/lato_core/templates/assets/stylesheets/theme.scss.erb +13 -0
  258. data/lib/generators/lato_core/templates/controllers/application_controller.rb +13 -0
  259. data/lib/generators/lato_core/templates/controllers/crud_controller.rb +87 -0
  260. data/lib/generators/lato_core/templates/views/application/index.html.erb +16 -0
  261. data/lib/generators/lato_core/templates/views/crud/edit.html.erb +18 -0
  262. data/lib/generators/lato_core/templates/views/crud/index.html.erb +29 -0
  263. data/lib/generators/lato_core/templates/views/crud/new.html.erb +18 -0
  264. data/lib/generators/lato_core/templates/views/crud/shared/_form.html.erb +25 -0
  265. data/lib/generators/lato_core/templates/views/crud/show.html.erb +16 -0
  266. data/lib/lato_core.rb +6 -5
  267. data/lib/lato_core/cell.rb +28 -0
  268. data/lib/lato_core/engine.rb +16 -13
  269. data/lib/lato_core/helper.rb +11 -0
  270. data/lib/lato_core/helpers/cells.rb +20 -0
  271. data/lib/lato_core/helpers/general.rb +16 -0
  272. data/lib/lato_core/interface.rb +17 -14
  273. data/lib/lato_core/interfaces/apihelpers.rb +39 -0
  274. data/lib/lato_core/interfaces/application.rb +65 -0
  275. data/lib/lato_core/interfaces/authentication.rb +41 -0
  276. data/lib/lato_core/interfaces/cells.rb +41 -0
  277. data/lib/lato_core/interfaces/general.rb +39 -0
  278. data/lib/lato_core/interfaces/layout.rb +213 -0
  279. data/lib/lato_core/interfaces/modules.rb +110 -0
  280. data/lib/lato_core/interfaces/token.rb +25 -0
  281. data/lib/lato_core/version.rb +3 -0
  282. data/lib/tasks/lato_core_tasks.rake +4 -8
  283. data/lib/tasks/lato_tasks.rake +83 -0
  284. metadata +407 -33
  285. data/app/controllers/lato_core/api/v1/api_controller.rb +0 -8
  286. data/app/mailers/lato_core/superusers_mailer.rb +0 -27
  287. data/app/views/lato_core/back/authentication/login.html.erb +0 -45
  288. data/app/views/lato_core/back/authentication/password_edit.html.erb +0 -45
  289. data/app/views/lato_core/back/authentication/password_forget.html.erb +0 -36
  290. data/app/views/lato_core/back/back/home.html.erb +0 -20
  291. data/app/views/lato_core/mailers/layouts/mailer.html.erb +0 -9
  292. data/app/views/lato_core/mailers/layouts/mailer.text.erb +0 -1
  293. data/app/views/lato_core/mailers/superusers/notify.html.erb +0 -2
  294. data/app/views/lato_core/mailers/superusers/recover_password.html.erb +0 -4
  295. data/config/config.yml +0 -8
  296. data/config/example.yml +0 -66
  297. data/config/initializers/init.rb +0 -15
  298. data/config/initializers/ram.rb +0 -14
  299. data/lang/default.yml +0 -61
  300. data/lang/en.yml +0 -61
  301. data/lib/lato_core/interface/authentication.rb +0 -26
  302. data/lib/lato_core/interface/cache.rb +0 -23
  303. data/lib/lato_core/interface/communication.rb +0 -87
  304. data/lib/lato_core/interface/languages.rb +0 -51
  305. data/lib/lato_core/interface/navigation.rb +0 -95
  306. data/lib/lato_core/interface/session.rb +0 -57
  307. data/lib/lato_core/interface/superusers.rb +0 -134
@@ -0,0 +1,1603 @@
1
+ /**
2
+ * Trumbowyg v2.5.1 - A lightweight WYSIWYG editor
3
+ * Trumbowyg core file
4
+ * ------------------------
5
+ * @link http://alex-d.github.io/Trumbowyg
6
+ * @license MIT
7
+ * @author Alexandre Demode (Alex-D)
8
+ * Twitter : @AlexandreDemode
9
+ * Website : alex-d.fr
10
+ */
11
+
12
+ jQuery.trumbowyg = {
13
+ langs: {
14
+ en: {
15
+ viewHTML: 'View HTML',
16
+
17
+ undo: 'Undo',
18
+ redo: 'Redo',
19
+
20
+ formatting: 'Formatting',
21
+ p: 'Paragraph',
22
+ blockquote: 'Quote',
23
+ code: 'Code',
24
+ header: 'Header',
25
+
26
+ bold: 'Bold',
27
+ italic: 'Italic',
28
+ strikethrough: 'Stroke',
29
+ underline: 'Underline',
30
+
31
+ strong: 'Strong',
32
+ em: 'Emphasis',
33
+ del: 'Deleted',
34
+
35
+ superscript: 'Superscript',
36
+ subscript: 'Subscript',
37
+
38
+ unorderedList: 'Unordered list',
39
+ orderedList: 'Ordered list',
40
+
41
+ insertImage: 'Insert Image',
42
+ link: 'Link',
43
+ createLink: 'Insert link',
44
+ unlink: 'Remove link',
45
+
46
+ justifyLeft: 'Align Left',
47
+ justifyCenter: 'Align Center',
48
+ justifyRight: 'Align Right',
49
+ justifyFull: 'Align Justify',
50
+
51
+ horizontalRule: 'Insert horizontal rule',
52
+ removeformat: 'Remove format',
53
+
54
+ fullscreen: 'Fullscreen',
55
+
56
+ close: 'Close',
57
+
58
+ submit: 'Confirm',
59
+ reset: 'Cancel',
60
+
61
+ required: 'Required',
62
+ description: 'Description',
63
+ title: 'Title',
64
+ text: 'Text',
65
+ target: 'Target'
66
+ }
67
+ },
68
+
69
+ // Plugins
70
+ plugins: {},
71
+
72
+ // SVG Path globally
73
+ svgPath: null,
74
+
75
+ hideButtonTexts: null
76
+ };
77
+
78
+
79
+ (function (navigator, window, document, $) {
80
+ 'use strict';
81
+
82
+ $.fn.trumbowyg = function (options, params) {
83
+ var trumbowygDataName = 'trumbowyg';
84
+ if (options === Object(options) || !options) {
85
+ return this.each(function () {
86
+ if (!$(this).data(trumbowygDataName)) {
87
+ $(this).data(trumbowygDataName, new Trumbowyg(this, options));
88
+ }
89
+ });
90
+ }
91
+ if (this.length === 1) {
92
+ try {
93
+ var t = $(this).data(trumbowygDataName);
94
+ switch (options) {
95
+ // Exec command
96
+ case 'execCmd':
97
+ return t.execCmd(params.cmd, params.param, params.forceCss);
98
+
99
+ // Modal box
100
+ case 'openModal':
101
+ return t.openModal(params.title, params.content);
102
+ case 'closeModal':
103
+ return t.closeModal();
104
+ case 'openModalInsert':
105
+ return t.openModalInsert(params.title, params.fields, params.callback);
106
+
107
+ // Range
108
+ case 'saveRange':
109
+ return t.saveRange();
110
+ case 'getRange':
111
+ return t.range;
112
+ case 'getRangeText':
113
+ return t.getRangeText();
114
+ case 'restoreRange':
115
+ return t.restoreRange();
116
+
117
+ // Enable/disable
118
+ case 'enable':
119
+ return t.toggleDisable(false);
120
+ case 'disable':
121
+ return t.toggleDisable(true);
122
+
123
+ // Destroy
124
+ case 'destroy':
125
+ return t.destroy();
126
+
127
+ // Empty
128
+ case 'empty':
129
+ return t.empty();
130
+
131
+ // HTML
132
+ case 'html':
133
+ return t.html(params);
134
+ }
135
+ } catch (c) {
136
+ }
137
+ }
138
+
139
+ return false;
140
+ };
141
+
142
+ // @param: editorElem is the DOM element
143
+ var Trumbowyg = function (editorElem, options) {
144
+ var t = this,
145
+ trumbowygIconsId = 'trumbowyg-icons';
146
+
147
+ // Get the document of the element. It use to makes the plugin
148
+ // compatible on iframes.
149
+ t.doc = editorElem.ownerDocument || document;
150
+
151
+ // jQuery object of the editor
152
+ t.$ta = $(editorElem); // $ta : Textarea
153
+ t.$c = $(editorElem); // $c : creator
154
+
155
+ options = options || {};
156
+
157
+ // Localization management
158
+ if (options.lang != null || $.trumbowyg.langs[options.lang] != null) {
159
+ t.lang = $.extend(true, {}, $.trumbowyg.langs.en, $.trumbowyg.langs[options.lang]);
160
+ } else {
161
+ t.lang = $.trumbowyg.langs.en;
162
+ }
163
+
164
+ t.hideButtonTexts = $.trumbowyg.hideButtonTexts != null ? $.trumbowyg.hideButtonTexts : options.hideButtonTexts;
165
+
166
+ // SVG path
167
+ var svgPathOption = $.trumbowyg.svgPath != null ? $.trumbowyg.svgPath : options.svgPath;
168
+ t.hasSvg = svgPathOption !== false;
169
+ t.svgPath = !!t.doc.querySelector('base') ? window.location.href.split('#')[0] : '';
170
+ if ($('#' + trumbowygIconsId, t.doc).length === 0 && svgPathOption !== false) {
171
+ if (svgPathOption == null) {
172
+ try {
173
+ throw new Error();
174
+ } catch (e) {
175
+ var stackLines = e.stack.split('\n');
176
+
177
+ for (var i in stackLines) {
178
+ if (!stackLines[i].match(/http[s]?:\/\//)) {
179
+ continue;
180
+ }
181
+ svgPathOption = stackLines[Number(i)].match(/((http[s]?:\/\/.+\/)([^\/]+\.js))(\?.*)?:/)[1].split('/');
182
+ svgPathOption.pop();
183
+ svgPathOption = svgPathOption.join('/') + '/cell-inputs-editor-icons.svg';
184
+ break;
185
+ }
186
+ }
187
+ }
188
+
189
+ var div = t.doc.createElement('div');
190
+ div.id = trumbowygIconsId;
191
+ t.doc.body.insertBefore(div, t.doc.body.childNodes[0]);
192
+ $.ajax({
193
+ async: true,
194
+ type: 'GET',
195
+ contentType: 'application/x-www-form-urlencoded; charset=UTF-8',
196
+ dataType: 'xml',
197
+ url: svgPathOption,
198
+ data: null,
199
+ beforeSend: null,
200
+ complete: null,
201
+ success: function (data) {
202
+ div.innerHTML = new XMLSerializer().serializeToString(data.documentElement);
203
+ }
204
+ });
205
+ }
206
+
207
+
208
+ /**
209
+ * When the button is associated to a empty object
210
+ * fn and title attributs are defined from the button key value
211
+ *
212
+ * For example
213
+ * foo: {}
214
+ * is equivalent to :
215
+ * foo: {
216
+ * fn: 'foo',
217
+ * title: this.lang.foo
218
+ * }
219
+ */
220
+ var h = t.lang.header, // Header translation
221
+ isBlinkFunction = function () {
222
+ return (window.chrome || (window.Intl && Intl.v8BreakIterator)) && 'CSS' in window;
223
+ };
224
+ t.btnsDef = {
225
+ viewHTML: {
226
+ fn: 'toggle'
227
+ },
228
+
229
+ undo: {
230
+ isSupported: isBlinkFunction,
231
+ key: 'Z'
232
+ },
233
+ redo: {
234
+ isSupported: isBlinkFunction,
235
+ key: 'Y'
236
+ },
237
+
238
+ p: {
239
+ fn: 'formatBlock'
240
+ },
241
+ blockquote: {
242
+ fn: 'formatBlock'
243
+ },
244
+ h1: {
245
+ fn: 'formatBlock',
246
+ title: h + ' 1'
247
+ },
248
+ h2: {
249
+ fn: 'formatBlock',
250
+ title: h + ' 2'
251
+ },
252
+ h3: {
253
+ fn: 'formatBlock',
254
+ title: h + ' 3'
255
+ },
256
+ h4: {
257
+ fn: 'formatBlock',
258
+ title: h + ' 4'
259
+ },
260
+ subscript: {
261
+ tag: 'sub'
262
+ },
263
+ superscript: {
264
+ tag: 'sup'
265
+ },
266
+
267
+ bold: {
268
+ key: 'B',
269
+ tag: 'b'
270
+ },
271
+ italic: {
272
+ key: 'I',
273
+ tag: 'i'
274
+ },
275
+ underline: {
276
+ tag: 'u'
277
+ },
278
+ strikethrough: {
279
+ tag: 'strike'
280
+ },
281
+
282
+ strong: {
283
+ fn: 'bold',
284
+ key: 'B'
285
+ },
286
+ em: {
287
+ fn: 'italic',
288
+ key: 'I'
289
+ },
290
+ del: {
291
+ fn: 'strikethrough'
292
+ },
293
+
294
+ createLink: {
295
+ key: 'K',
296
+ tag: 'a'
297
+ },
298
+ unlink: {},
299
+
300
+ insertImage: {},
301
+
302
+ justifyLeft: {
303
+ tag: 'left',
304
+ forceCss: true
305
+ },
306
+ justifyCenter: {
307
+ tag: 'center',
308
+ forceCss: true
309
+ },
310
+ justifyRight: {
311
+ tag: 'right',
312
+ forceCss: true
313
+ },
314
+ justifyFull: {
315
+ tag: 'justify',
316
+ forceCss: true
317
+ },
318
+
319
+ unorderedList: {
320
+ fn: 'insertUnorderedList',
321
+ tag: 'ul'
322
+ },
323
+ orderedList: {
324
+ fn: 'insertOrderedList',
325
+ tag: 'ol'
326
+ },
327
+
328
+ horizontalRule: {
329
+ fn: 'insertHorizontalRule'
330
+ },
331
+
332
+ removeformat: {},
333
+
334
+ fullscreen: {
335
+ class: 'trumbowyg-not-disable'
336
+ },
337
+ close: {
338
+ fn: 'destroy',
339
+ class: 'trumbowyg-not-disable'
340
+ },
341
+
342
+ // Dropdowns
343
+ formatting: {
344
+ dropdown: ['p', 'blockquote', 'h1', 'h2', 'h3', 'h4'],
345
+ ico: 'p'
346
+ },
347
+ link: {
348
+ dropdown: ['createLink', 'unlink']
349
+ }
350
+ };
351
+
352
+ // Defaults Options
353
+ t.o = $.extend(true, {}, {
354
+ lang: 'en',
355
+
356
+ fixedBtnPane: false,
357
+ fixedFullWidth: false,
358
+ autogrow: false,
359
+
360
+ prefix: 'trumbowyg-',
361
+
362
+ semantic: true,
363
+ resetCss: false,
364
+ removeformatPasted: false,
365
+ tagsToRemove: [],
366
+
367
+ btnsGrps: {
368
+ design: ['bold', 'italic', 'underline', 'strikethrough'],
369
+ semantic: ['strong', 'em', 'del'],
370
+ justify: ['justifyLeft', 'justifyCenter', 'justifyRight', 'justifyFull'],
371
+ lists: ['unorderedList', 'orderedList']
372
+ },
373
+ btns: [
374
+ ['viewHTML'],
375
+ ['undo', 'redo'],
376
+ ['formatting'],
377
+ 'btnGrp-semantic',
378
+ ['superscript', 'subscript'],
379
+ ['link'],
380
+ ['insertImage'],
381
+ 'btnGrp-justify',
382
+ 'btnGrp-lists',
383
+ ['horizontalRule'],
384
+ ['removeformat'],
385
+ ['fullscreen']
386
+ ],
387
+ // For custom button definitions
388
+ btnsDef: {},
389
+
390
+ 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',
391
+
392
+ pasteHandlers: [],
393
+
394
+ imgDblClickHandler: function () {
395
+ var $img = $(this),
396
+ src = $img.attr('src'),
397
+ base64 = '(Base64)';
398
+
399
+ if (src.indexOf('data:image') === 0) {
400
+ src = base64;
401
+ }
402
+
403
+ t.openModalInsert(t.lang.insertImage, {
404
+ url: {
405
+ label: 'URL',
406
+ value: src,
407
+ required: true
408
+ },
409
+ alt: {
410
+ label: t.lang.description,
411
+ value: $img.attr('alt')
412
+ }
413
+ }, function (v) {
414
+ if (v.src !== base64) {
415
+ $img.attr({
416
+ src: v.src
417
+ });
418
+ }
419
+ $img.attr({
420
+ alt: v.alt
421
+ });
422
+ return true;
423
+ });
424
+ return false;
425
+ },
426
+
427
+ plugins: {}
428
+ }, options);
429
+
430
+ t.disabled = t.o.disabled || (editorElem.nodeName === 'TEXTAREA' && editorElem.disabled);
431
+
432
+ if (options.btns) {
433
+ t.o.btns = options.btns;
434
+ } else if (!t.o.semantic) {
435
+ t.o.btns[4] = 'btnGrp-design';
436
+ }
437
+
438
+ $.each(t.o.btnsDef, function (btnName, btnDef) {
439
+ t.addBtnDef(btnName, btnDef);
440
+ });
441
+
442
+ // put this here in the event it would be merged in with options
443
+ t.eventNamespace = 'trumbowyg-event';
444
+
445
+ // Keyboard shortcuts are load in this array
446
+ t.keys = [];
447
+
448
+ // Tag to button dynamically hydrated
449
+ t.tagToButton = {};
450
+ t.tagHandlers = [];
451
+
452
+ // Admit multiple paste handlers
453
+ t.pasteHandlers = [].concat(t.o.pasteHandlers);
454
+
455
+ // Check if browser is IE
456
+ t.isIE = (navigator.userAgent.indexOf('MSIE') !== -1 || navigator.appVersion.indexOf('Trident/') !== -1);
457
+
458
+ t.init();
459
+ };
460
+
461
+ Trumbowyg.prototype = {
462
+ init: function () {
463
+ var t = this;
464
+ t.height = t.$ta.height();
465
+
466
+ t.initPlugins();
467
+
468
+ try {
469
+ // Disable image resize, try-catch for old IE
470
+ t.doc.execCommand('enableObjectResizing', false, false);
471
+ t.doc.execCommand('defaultParagraphSeparator', false, 'p');
472
+ } catch (e) {
473
+ }
474
+
475
+ t.buildEditor();
476
+ t.buildBtnPane();
477
+
478
+ t.fixedBtnPaneEvents();
479
+
480
+ t.buildOverlay();
481
+
482
+ setTimeout(function () {
483
+ if (t.disabled) {
484
+ t.toggleDisable(true);
485
+ }
486
+ t.$c.trigger('tbwinit');
487
+ });
488
+ },
489
+
490
+ addBtnDef: function (btnName, btnDef) {
491
+ this.btnsDef[btnName] = btnDef;
492
+ },
493
+
494
+ buildEditor: function () {
495
+ var t = this,
496
+ prefix = t.o.prefix,
497
+ html = '';
498
+
499
+ t.$box = $('<div/>', {
500
+ class: prefix + 'box ' + prefix + 'editor-visible ' + prefix + t.o.lang + ' trumbowyg'
501
+ });
502
+
503
+ // $ta = Textarea
504
+ // $ed = Editor
505
+ t.isTextarea = t.$ta.is('textarea');
506
+ if (t.isTextarea) {
507
+ html = t.$ta.val();
508
+ t.$ed = $('<div/>');
509
+ t.$box
510
+ .insertAfter(t.$ta)
511
+ .append(t.$ed, t.$ta);
512
+ } else {
513
+ t.$ed = t.$ta;
514
+ html = t.$ed.html();
515
+
516
+ t.$ta = $('<textarea/>', {
517
+ name: t.$ta.attr('id'),
518
+ height: t.height
519
+ }).val(html);
520
+
521
+ t.$box
522
+ .insertAfter(t.$ed)
523
+ .append(t.$ta, t.$ed);
524
+ t.syncCode();
525
+ }
526
+
527
+ t.$ta
528
+ .addClass(prefix + 'textarea')
529
+ .attr('tabindex', -1)
530
+ ;
531
+
532
+ t.$ed
533
+ .addClass(prefix + 'editor')
534
+ .attr({
535
+ contenteditable: true,
536
+ dir: t.lang._dir || 'ltr'
537
+ })
538
+ .html(html)
539
+ ;
540
+
541
+ if (t.o.tabindex) {
542
+ t.$ed.attr('tabindex', t.o.tabindex);
543
+ }
544
+
545
+ if (t.$c.is('[placeholder]')) {
546
+ t.$ed.attr('placeholder', t.$c.attr('placeholder'));
547
+ }
548
+
549
+ if (t.o.resetCss) {
550
+ t.$ed.addClass(prefix + 'reset-css');
551
+ }
552
+
553
+ if (!t.o.autogrow) {
554
+ t.$ta.add(t.$ed).css({
555
+ height: t.height
556
+ });
557
+ }
558
+
559
+ t.semanticCode();
560
+
561
+
562
+ var ctrl = false,
563
+ composition = false,
564
+ debounceButtonPaneStatus,
565
+ updateEventName = t.isIE ? 'keyup' : 'input';
566
+
567
+ t.$ed
568
+ .on('dblclick', 'img', t.o.imgDblClickHandler)
569
+ .on('keydown', function (e) {
570
+ if (e.ctrlKey) {
571
+ ctrl = true;
572
+ var key = t.keys[String.fromCharCode(e.which).toUpperCase()];
573
+
574
+ try {
575
+ t.execCmd(key.fn, key.param);
576
+ return false;
577
+ } catch (c) {
578
+ }
579
+ }
580
+ })
581
+ .on('compositionstart compositionupdate', function () {
582
+ composition = true;
583
+ })
584
+ .on(updateEventName + ' compositionend', function (e) {
585
+ if (e.type === 'compositionend') {
586
+ composition = false;
587
+ } else if(composition) {
588
+ return;
589
+ }
590
+
591
+ var keyCode = e.which;
592
+
593
+ if (keyCode >= 37 && keyCode <= 40) {
594
+ return;
595
+ }
596
+
597
+ if (e.ctrlKey && (keyCode === 89 || keyCode === 90)) {
598
+ t.$c.trigger('tbwchange');
599
+ } else if (!ctrl && keyCode !== 17) {
600
+ t.semanticCode(false, keyCode === 13);
601
+ t.$c.trigger('tbwchange');
602
+ } else if (typeof e.which === 'undefined') {
603
+ t.semanticCode(false, false, true);
604
+ }
605
+
606
+ setTimeout(function () {
607
+ ctrl = false;
608
+ }, 200);
609
+ })
610
+ .on('mouseup keydown keyup', function () {
611
+ clearTimeout(debounceButtonPaneStatus);
612
+ debounceButtonPaneStatus = setTimeout(function () {
613
+ t.updateButtonPaneStatus();
614
+ }, 50);
615
+ })
616
+ .on('focus blur', function (e) {
617
+ t.$c.trigger('tbw' + e.type);
618
+ if (e.type === 'blur') {
619
+ $('.' + prefix + 'active-button', t.$btnPane).removeClass(prefix + 'active-button ' + prefix + 'active');
620
+ }
621
+ })
622
+ .on('cut', function () {
623
+ setTimeout(function () {
624
+ t.semanticCode(false, true);
625
+ t.$c.trigger('tbwchange');
626
+ }, 0);
627
+ })
628
+ .on('paste', function (e) {
629
+ if (t.o.removeformatPasted) {
630
+ e.preventDefault();
631
+
632
+ try {
633
+ // IE
634
+ var text = window.clipboardData.getData('Text');
635
+
636
+ try {
637
+ // <= IE10
638
+ t.doc.selection.createRange().pasteHTML(text);
639
+ } catch (c) {
640
+ // IE 11
641
+ t.doc.getSelection().getRangeAt(0).insertNode(t.doc.createTextNode(text));
642
+ }
643
+ } catch (d) {
644
+ // Not IE
645
+ t.execCmd('insertText', (e.originalEvent || e).clipboardData.getData('text/plain'));
646
+ }
647
+ }
648
+
649
+ // Call pasteHandlers
650
+ $.each(t.pasteHandlers, function (i, pasteHandler) {
651
+ pasteHandler(e);
652
+ });
653
+
654
+ setTimeout(function () {
655
+ t.semanticCode(false, true);
656
+ t.$c.trigger('tbwpaste', e);
657
+ }, 0);
658
+ });
659
+ t.$ta.on('keyup paste', function () {
660
+ t.$c.trigger('tbwchange');
661
+ });
662
+
663
+ t.$box.on('keydown', function (e) {
664
+ if (e.which === 27 && $('.' + prefix + 'modal-box', t.$box).length === 1) {
665
+ t.closeModal();
666
+ return false;
667
+ }
668
+ });
669
+ },
670
+
671
+
672
+ // Build button pane, use o.btns option
673
+ buildBtnPane: function () {
674
+ var t = this,
675
+ prefix = t.o.prefix;
676
+
677
+ var $btnPane = t.$btnPane = $('<div/>', {
678
+ class: prefix + 'button-pane'
679
+ });
680
+
681
+ $.each(t.o.btns, function (i, btnGrps) {
682
+ // Managment of group of buttons
683
+ try {
684
+ var b = btnGrps.split('btnGrp-');
685
+ if (b[1] != null) {
686
+ btnGrps = t.o.btnsGrps[b[1]];
687
+ }
688
+ } catch (c) {
689
+ }
690
+
691
+ if (!$.isArray(btnGrps)) {
692
+ btnGrps = [btnGrps];
693
+ }
694
+
695
+ var $btnGroup = $('<div/>', {
696
+ class: prefix + 'button-group ' + ((btnGrps.indexOf('fullscreen') >= 0) ? prefix + 'right' : '')
697
+ });
698
+ $.each(btnGrps, function (i, btn) {
699
+ try { // Prevent buildBtn error
700
+ var $item;
701
+
702
+ if (t.isSupportedBtn(btn)) { // It's a supported button
703
+ $item = t.buildBtn(btn);
704
+ }
705
+
706
+ $btnGroup.append($item);
707
+ } catch (c) {
708
+ }
709
+ });
710
+ $btnPane.append($btnGroup);
711
+ });
712
+
713
+ t.$box.prepend($btnPane);
714
+ },
715
+
716
+
717
+ // Build a button and his action
718
+ buildBtn: function (btnName) { // btnName is name of the button
719
+ var t = this,
720
+ prefix = t.o.prefix,
721
+ btn = t.btnsDef[btnName],
722
+ isDropdown = btn.dropdown,
723
+ hasIcon = btn.hasIcon != null ? btn.hasIcon : true,
724
+ textDef = t.lang[btnName] || btnName,
725
+
726
+ $btn = $('<button/>', {
727
+ type: 'button',
728
+ class: prefix + btnName + '-button ' + (btn.class || '') + (!hasIcon ? ' ' + prefix + 'textual-button' : ''),
729
+ html: t.hasSvg && hasIcon ?
730
+ '<svg><use xlink:href="' + t.svgPath + '#' + prefix + (btn.ico || btnName).replace(/([A-Z]+)/g, '-$1').toLowerCase() + '"/></svg>' :
731
+ t.hideButtonTexts ? '' : (btn.text || btn.title || t.lang[btnName] || btnName),
732
+ title: (btn.title || btn.text || textDef) + ((btn.key) ? ' (Ctrl + ' + btn.key + ')' : ''),
733
+ tabindex: -1,
734
+ mousedown: function () {
735
+ if (!isDropdown || $('.' + btnName + '-' + prefix + 'dropdown', t.$box).is(':hidden')) {
736
+ $('body', t.doc).trigger('mousedown');
737
+ }
738
+
739
+ if (t.$btnPane.hasClass(prefix + 'disable') && !$(this).hasClass(prefix + 'active') && !$(this).hasClass(prefix + 'not-disable')) {
740
+ return false;
741
+ }
742
+
743
+ t.execCmd((isDropdown ? 'dropdown' : false) || btn.fn || btnName, btn.param || btnName, btn.forceCss || false);
744
+
745
+ return false;
746
+ }
747
+ });
748
+
749
+ if (isDropdown) {
750
+ $btn.addClass(prefix + 'open-dropdown');
751
+ var dropdownPrefix = prefix + 'dropdown',
752
+ $dropdown = $('<div/>', { // the dropdown
753
+ class: dropdownPrefix + '-' + btnName + ' ' + dropdownPrefix + ' ' + prefix + 'fixed-top',
754
+ 'data-dropdown': btnName
755
+ });
756
+ $.each(isDropdown, function (i, def) {
757
+ if (t.btnsDef[def] && t.isSupportedBtn(def)) {
758
+ $dropdown.append(t.buildSubBtn(def));
759
+ }
760
+ });
761
+ t.$box.append($dropdown.hide());
762
+ } else if (btn.key) {
763
+ t.keys[btn.key] = {
764
+ fn: btn.fn || btnName,
765
+ param: btn.param || btnName
766
+ };
767
+ }
768
+
769
+ if (!isDropdown) {
770
+ t.tagToButton[(btn.tag || btnName).toLowerCase()] = btnName;
771
+ }
772
+
773
+ return $btn;
774
+ },
775
+ // Build a button for dropdown menu
776
+ // @param n : name of the subbutton
777
+ buildSubBtn: function (btnName) {
778
+ var t = this,
779
+ prefix = t.o.prefix,
780
+ btn = t.btnsDef[btnName],
781
+ hasIcon = btn.hasIcon != null ? btn.hasIcon : true;
782
+
783
+ if (btn.key) {
784
+ t.keys[btn.key] = {
785
+ fn: btn.fn || btnName,
786
+ param: btn.param || btnName
787
+ };
788
+ }
789
+
790
+ t.tagToButton[(btn.tag || btnName).toLowerCase()] = btnName;
791
+
792
+ return $('<button/>', {
793
+ type: 'button',
794
+ class: prefix + btnName + '-dropdown-button' + (btn.ico ? ' ' + prefix + btn.ico + '-button' : ''),
795
+ 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),
796
+ title: ((btn.key) ? ' (Ctrl + ' + btn.key + ')' : null),
797
+ style: btn.style || null,
798
+ mousedown: function () {
799
+ $('body', t.doc).trigger('mousedown');
800
+
801
+ t.execCmd(btn.fn || btnName, btn.param || btnName, btn.forceCss || false);
802
+
803
+ return false;
804
+ }
805
+ });
806
+ },
807
+ // Check if button is supported
808
+ isSupportedBtn: function (b) {
809
+ try {
810
+ return this.btnsDef[b].isSupported();
811
+ } catch (c) {
812
+ }
813
+ return true;
814
+ },
815
+
816
+ // Build overlay for modal box
817
+ buildOverlay: function () {
818
+ var t = this;
819
+ t.$overlay = $('<div/>', {
820
+ class: t.o.prefix + 'overlay'
821
+ }).css({
822
+ top: t.$btnPane.outerHeight(),
823
+ height: (t.$ed.outerHeight() + 1) + 'px'
824
+ }).appendTo(t.$box);
825
+ return t.$overlay;
826
+ },
827
+ showOverlay: function () {
828
+ var t = this;
829
+ $(window).trigger('scroll');
830
+ t.$overlay.fadeIn(200);
831
+ t.$box.addClass(t.o.prefix + 'box-blur');
832
+ },
833
+ hideOverlay: function () {
834
+ var t = this;
835
+ t.$overlay.fadeOut(50);
836
+ t.$box.removeClass(t.o.prefix + 'box-blur');
837
+ },
838
+
839
+ // Management of fixed button pane
840
+ fixedBtnPaneEvents: function () {
841
+ var t = this,
842
+ fixedFullWidth = t.o.fixedFullWidth,
843
+ $box = t.$box;
844
+
845
+ if (!t.o.fixedBtnPane) {
846
+ return;
847
+ }
848
+
849
+ t.isFixed = false;
850
+
851
+ $(window)
852
+ .on('scroll.'+t.eventNamespace+' resize.'+t.eventNamespace, function () {
853
+ if (!$box) {
854
+ return;
855
+ }
856
+
857
+ t.syncCode();
858
+
859
+ var scrollTop = $(window).scrollTop(),
860
+ offset = $box.offset().top + 1,
861
+ bp = t.$btnPane,
862
+ oh = bp.outerHeight() - 2;
863
+
864
+ if ((scrollTop - offset > 0) && ((scrollTop - offset - t.height) < 0)) {
865
+ if (!t.isFixed) {
866
+ t.isFixed = true;
867
+ bp.css({
868
+ position: 'fixed',
869
+ top: 0,
870
+ left: fixedFullWidth ? '0' : 'auto',
871
+ zIndex: 7
872
+ });
873
+ $([t.$ta, t.$ed]).css({marginTop: bp.height()});
874
+ }
875
+ bp.css({
876
+ width: fixedFullWidth ? '100%' : (($box.width() - 1) + 'px')
877
+ });
878
+
879
+ $('.' + t.o.prefix + 'fixed-top', $box).css({
880
+ position: fixedFullWidth ? 'fixed' : 'absolute',
881
+ top: fixedFullWidth ? oh : oh + (scrollTop - offset) + 'px',
882
+ zIndex: 15
883
+ });
884
+ } else if (t.isFixed) {
885
+ t.isFixed = false;
886
+ bp.removeAttr('style');
887
+ $([t.$ta, t.$ed]).css({marginTop: 0});
888
+ $('.' + t.o.prefix + 'fixed-top', $box).css({
889
+ position: 'absolute',
890
+ top: oh
891
+ });
892
+ }
893
+ });
894
+ },
895
+
896
+ // Disable editor
897
+ toggleDisable: function (disable) {
898
+ var t = this,
899
+ prefix = t.o.prefix;
900
+
901
+ t.disabled = disable;
902
+
903
+ if (disable) {
904
+ t.$ta.attr('disabled', true);
905
+ } else {
906
+ t.$ta.removeAttr('disabled');
907
+ }
908
+ t.$box.toggleClass(prefix + 'disabled', disable);
909
+ t.$ed.attr('contenteditable', !disable);
910
+ },
911
+
912
+ // Destroy the editor
913
+ destroy: function () {
914
+ var t = this,
915
+ prefix = t.o.prefix,
916
+ height = t.height;
917
+
918
+ if (t.isTextarea) {
919
+ t.$box.after(
920
+ t.$ta
921
+ .css({height: height})
922
+ .val(t.html())
923
+ .removeClass(prefix + 'textarea')
924
+ .show()
925
+ );
926
+ } else {
927
+ t.$box.after(
928
+ t.$ed
929
+ .css({height: height})
930
+ .removeClass(prefix + 'editor')
931
+ .removeAttr('contenteditable')
932
+ .html(t.html())
933
+ .show()
934
+ );
935
+ }
936
+
937
+ t.$ed.off('dblclick', 'img');
938
+
939
+ t.destroyPlugins();
940
+
941
+ t.$box.remove();
942
+ t.$c.removeData('trumbowyg');
943
+ $('body').removeClass(prefix + 'body-fullscreen');
944
+ t.$c.trigger('tbwclose');
945
+ $(window).off('scroll.'+t.eventNamespace+' resize.'+t.eventNamespace);
946
+ },
947
+
948
+
949
+ // Empty the editor
950
+ empty: function () {
951
+ this.$ta.val('');
952
+ this.syncCode(true);
953
+ },
954
+
955
+
956
+ // Function call when click on viewHTML button
957
+ toggle: function () {
958
+ var t = this,
959
+ prefix = t.o.prefix;
960
+ t.semanticCode(false, true);
961
+ setTimeout(function () {
962
+ t.doc.activeElement.blur();
963
+ t.$box.toggleClass(prefix + 'editor-hidden ' + prefix + 'editor-visible');
964
+ t.$btnPane.toggleClass(prefix + 'disable');
965
+ $('.' + prefix + 'viewHTML-button', t.$btnPane).toggleClass(prefix + 'active');
966
+ if (t.$box.hasClass(prefix + 'editor-visible')) {
967
+ t.$ta.attr('tabindex', -1);
968
+ } else {
969
+ t.$ta.removeAttr('tabindex');
970
+ }
971
+ }, 0);
972
+ },
973
+
974
+ // Open dropdown when click on a button which open that
975
+ dropdown: function (name) {
976
+ var t = this,
977
+ d = t.doc,
978
+ prefix = t.o.prefix,
979
+ $dropdown = $('[data-dropdown=' + name + ']', t.$box),
980
+ $btn = $('.' + prefix + name + '-button', t.$btnPane),
981
+ show = $dropdown.is(':hidden');
982
+
983
+ $('body', d).trigger('mousedown');
984
+
985
+ if (show) {
986
+ var o = $btn.offset().left;
987
+ $btn.addClass(prefix + 'active');
988
+
989
+ $dropdown.css({
990
+ position: 'absolute',
991
+ top: $btn.offset().top - t.$btnPane.offset().top + $btn.outerHeight(),
992
+ left: (t.o.fixedFullWidth && t.isFixed) ? o + 'px' : (o - t.$btnPane.offset().left) + 'px'
993
+ }).show();
994
+
995
+ $(window).trigger('scroll');
996
+
997
+ $('body', d).on('mousedown.'+t.eventNamespace, function (e) {
998
+ if (!$dropdown.is(e.target)) {
999
+ $('.' + prefix + 'dropdown', d).hide();
1000
+ $('.' + prefix + 'active', d).removeClass(prefix + 'active');
1001
+ $('body', d).off('mousedown.'+t.eventNamespace);
1002
+ }
1003
+ });
1004
+ }
1005
+ },
1006
+
1007
+
1008
+ // HTML Code management
1009
+ html: function (html) {
1010
+ var t = this;
1011
+ if (html != null) {
1012
+ t.$ta.val(html);
1013
+ t.syncCode(true);
1014
+ return t;
1015
+ }
1016
+ return t.$ta.val();
1017
+ },
1018
+ syncTextarea: function () {
1019
+ var t = this;
1020
+ t.$ta.val(t.$ed.text().trim().length > 0 || t.$ed.find('hr,img,embed,iframe,input').length > 0 ? t.$ed.html() : '');
1021
+ },
1022
+ syncCode: function (force) {
1023
+ var t = this;
1024
+ if (!force && t.$ed.is(':visible')) {
1025
+ t.syncTextarea();
1026
+ } else {
1027
+ t.$ed.html(t.$ta.val());
1028
+ }
1029
+
1030
+ if (t.o.autogrow) {
1031
+ t.height = t.$ed.height();
1032
+ if (t.height !== t.$ta.css('height')) {
1033
+ t.$ta.css({height: t.height});
1034
+ t.$c.trigger('tbwresize');
1035
+ }
1036
+ }
1037
+ },
1038
+
1039
+ // Analyse and update to semantic code
1040
+ // @param force : force to sync code from textarea
1041
+ // @param full : wrap text nodes in <p>
1042
+ // @param keepRange : leave selection range as it is
1043
+ semanticCode: function (force, full, keepRange) {
1044
+ var t = this;
1045
+ t.saveRange();
1046
+ t.syncCode(force);
1047
+
1048
+ $(t.o.tagsToRemove.join(','), t.$ed).remove();
1049
+
1050
+ if (t.o.semantic) {
1051
+ t.semanticTag('b', 'strong');
1052
+ t.semanticTag('i', 'em');
1053
+
1054
+ if (full) {
1055
+ var inlineElementsSelector = t.o.inlineElementsSelector,
1056
+ blockElementsSelector = ':not(' + inlineElementsSelector + ')';
1057
+
1058
+ // Wrap text nodes in span for easier processing
1059
+ t.$ed.contents().filter(function () {
1060
+ return this.nodeType === 3 && this.nodeValue.trim().length > 0;
1061
+ }).wrap('<span data-tbw/>');
1062
+
1063
+ // Wrap groups of inline elements in paragraphs (recursive)
1064
+ var wrapInlinesInParagraphsFrom = function ($from) {
1065
+ if ($from.length !== 0) {
1066
+ var $finalParagraph = $from.nextUntil(blockElementsSelector).addBack().wrapAll('<p/>').parent(),
1067
+ $nextElement = $finalParagraph.nextAll(inlineElementsSelector).first();
1068
+ $finalParagraph.next('br').remove();
1069
+ wrapInlinesInParagraphsFrom($nextElement);
1070
+ }
1071
+ };
1072
+ wrapInlinesInParagraphsFrom(t.$ed.children(inlineElementsSelector).first());
1073
+
1074
+ t.semanticTag('div', 'p', true);
1075
+
1076
+ // Unwrap paragraphs content, containing nothing usefull
1077
+ t.$ed.find('p').filter(function () {
1078
+ // Don't remove currently being edited element
1079
+ if (t.range && this === t.range.startContainer) {
1080
+ return false;
1081
+ }
1082
+ return $(this).text().trim().length === 0 && $(this).children().not('br,span').length === 0;
1083
+ }).contents().unwrap();
1084
+
1085
+ // Get rid of temporial span's
1086
+ $('[data-tbw]', t.$ed).contents().unwrap();
1087
+
1088
+ // Remove empty <p>
1089
+ t.$ed.find('p:empty').remove();
1090
+ }
1091
+
1092
+ if (!keepRange) {
1093
+ t.restoreRange();
1094
+ }
1095
+
1096
+ t.syncTextarea();
1097
+ }
1098
+ },
1099
+
1100
+ semanticTag: function (oldTag, newTag, copyAttributes) {
1101
+ $(oldTag, this.$ed).each(function () {
1102
+ var $oldTag = $(this);
1103
+ $oldTag.wrap('<' + newTag + '/>');
1104
+ if (copyAttributes) {
1105
+ $.each($oldTag.prop('attributes'), function () {
1106
+ $oldTag.parent().attr(this.name, this.value);
1107
+ });
1108
+ }
1109
+ $oldTag.contents().unwrap();
1110
+ });
1111
+ },
1112
+
1113
+ // Function call when user click on "Insert Link"
1114
+ createLink: function () {
1115
+ var t = this,
1116
+ documentSelection = t.doc.getSelection(),
1117
+ node = documentSelection.focusNode,
1118
+ url,
1119
+ title,
1120
+ target;
1121
+
1122
+ while (['A', 'DIV'].indexOf(node.nodeName) < 0) {
1123
+ node = node.parentNode;
1124
+ }
1125
+
1126
+ if (node && node.nodeName === 'A') {
1127
+ var $a = $(node);
1128
+ url = $a.attr('href');
1129
+ title = $a.attr('title');
1130
+ target = $a.attr('target');
1131
+ var range = t.doc.createRange();
1132
+ range.selectNode(node);
1133
+ documentSelection.addRange(range);
1134
+ }
1135
+
1136
+ t.saveRange();
1137
+
1138
+ t.openModalInsert(t.lang.createLink, {
1139
+ url: {
1140
+ label: 'URL',
1141
+ required: true,
1142
+ value: url
1143
+ },
1144
+ title: {
1145
+ label: t.lang.title,
1146
+ value: title
1147
+ },
1148
+ text: {
1149
+ label: t.lang.text,
1150
+ value: t.getRangeText()
1151
+ },
1152
+ target: {
1153
+ label: t.lang.target,
1154
+ value: target
1155
+ }
1156
+ }, function (v) { // v is value
1157
+ var link = $(['<a href="', v.url, '">', v.text, '</a>'].join(''));
1158
+ if (v.title.length > 0) {
1159
+ link.attr('title', v.title);
1160
+ }
1161
+ if (v.target.length > 0) {
1162
+ link.attr('target', v.target);
1163
+ }
1164
+ t.range.deleteContents();
1165
+ t.range.insertNode(link[0]);
1166
+ return true;
1167
+ });
1168
+ },
1169
+ unlink: function () {
1170
+ var t = this,
1171
+ documentSelection = t.doc.getSelection(),
1172
+ node = documentSelection.focusNode;
1173
+
1174
+ if (documentSelection.isCollapsed) {
1175
+ while (['A', 'DIV'].indexOf(node.nodeName) < 0) {
1176
+ node = node.parentNode;
1177
+ }
1178
+
1179
+ if (node && node.nodeName === 'A') {
1180
+ var range = t.doc.createRange();
1181
+ range.selectNode(node);
1182
+ documentSelection.addRange(range);
1183
+ }
1184
+ }
1185
+ t.execCmd('unlink', undefined, undefined, true);
1186
+ },
1187
+ insertImage: function () {
1188
+ var t = this;
1189
+ t.saveRange();
1190
+ t.openModalInsert(t.lang.insertImage, {
1191
+ url: {
1192
+ label: 'URL',
1193
+ required: true
1194
+ },
1195
+ alt: {
1196
+ label: t.lang.description,
1197
+ value: t.getRangeText()
1198
+ }
1199
+ }, function (v) { // v are values
1200
+ t.execCmd('insertImage', v.url);
1201
+ $('img[src="' + v.url + '"]:not([alt])', t.$box).attr('alt', v.alt);
1202
+ return true;
1203
+ });
1204
+ },
1205
+ fullscreen: function () {
1206
+ var t = this,
1207
+ prefix = t.o.prefix,
1208
+ fullscreenCssClass = prefix + 'fullscreen',
1209
+ isFullscreen;
1210
+
1211
+ t.$box.toggleClass(fullscreenCssClass);
1212
+ isFullscreen = t.$box.hasClass(fullscreenCssClass);
1213
+ $('body').toggleClass(prefix + 'body-fullscreen', isFullscreen);
1214
+ $(window).trigger('scroll');
1215
+ t.$c.trigger('tbw' + (isFullscreen ? 'open' : 'close') + 'fullscreen');
1216
+ },
1217
+
1218
+
1219
+ /*
1220
+ * Call method of trumbowyg if exist
1221
+ * else try to call anonymous function
1222
+ * and finaly native execCommand
1223
+ */
1224
+ execCmd: function (cmd, param, forceCss, skipTrumbowyg) {
1225
+ var t = this;
1226
+ skipTrumbowyg = !!skipTrumbowyg || '';
1227
+
1228
+ if (cmd !== 'dropdown') {
1229
+ t.$ed.focus();
1230
+ }
1231
+
1232
+ try {
1233
+ t.doc.execCommand('styleWithCSS', false, forceCss || false);
1234
+ } catch (c) {
1235
+ }
1236
+
1237
+ try {
1238
+ t[cmd + skipTrumbowyg](param);
1239
+ } catch (c) {
1240
+ try {
1241
+ cmd(param);
1242
+ } catch (e2) {
1243
+ if (cmd === 'insertHorizontalRule') {
1244
+ param = undefined;
1245
+ } else if (cmd === 'formatBlock' && t.isIE) {
1246
+ param = '<' + param + '>';
1247
+ }
1248
+
1249
+ t.doc.execCommand(cmd, false, param);
1250
+
1251
+ t.syncCode();
1252
+ t.semanticCode(false, true);
1253
+ }
1254
+
1255
+ if (cmd !== 'dropdown') {
1256
+ t.updateButtonPaneStatus();
1257
+ t.$c.trigger('tbwchange');
1258
+ }
1259
+ }
1260
+ },
1261
+
1262
+
1263
+ // Open a modal box
1264
+ openModal: function (title, content) {
1265
+ var t = this,
1266
+ prefix = t.o.prefix;
1267
+
1268
+ // No open a modal box when exist other modal box
1269
+ if ($('.' + prefix + 'modal-box', t.$box).length > 0) {
1270
+ return false;
1271
+ }
1272
+
1273
+ t.saveRange();
1274
+ t.showOverlay();
1275
+
1276
+ // Disable all btnPane btns
1277
+ t.$btnPane.addClass(prefix + 'disable');
1278
+
1279
+ // Build out of ModalBox, it's the mask for animations
1280
+ var $modal = $('<div/>', {
1281
+ class: prefix + 'modal ' + prefix + 'fixed-top'
1282
+ }).css({
1283
+ top: t.$btnPane.height()
1284
+ }).appendTo(t.$box);
1285
+
1286
+ // Click on overlay close modal by cancelling them
1287
+ t.$overlay.one('click', function () {
1288
+ $modal.trigger('tbwcancel');
1289
+ return false;
1290
+ });
1291
+
1292
+ // Build the form
1293
+ var $form = $('<form/>', {
1294
+ action: '',
1295
+ html: content
1296
+ })
1297
+ .on('submit', function () {
1298
+ $modal.trigger('tbwconfirm');
1299
+ return false;
1300
+ })
1301
+ .on('reset', function () {
1302
+ $modal.trigger('tbwcancel');
1303
+ return false;
1304
+ });
1305
+
1306
+
1307
+ // Build ModalBox and animate to show them
1308
+ var $box = $('<div/>', {
1309
+ class: prefix + 'modal-box',
1310
+ html: $form
1311
+ })
1312
+ .css({
1313
+ top: '-' + t.$btnPane.outerHeight() + 'px',
1314
+ opacity: 0
1315
+ })
1316
+ .appendTo($modal)
1317
+ .animate({
1318
+ top: 0,
1319
+ opacity: 1
1320
+ }, 100);
1321
+
1322
+
1323
+ // Append title
1324
+ $('<span/>', {
1325
+ text: title,
1326
+ class: prefix + 'modal-title'
1327
+ }).prependTo($box);
1328
+
1329
+ $modal.height($box.outerHeight() + 10);
1330
+
1331
+
1332
+ // Focus in modal box
1333
+ $('input:first', $box).focus();
1334
+
1335
+
1336
+ // Append Confirm and Cancel buttons
1337
+ t.buildModalBtn('submit', $box);
1338
+ t.buildModalBtn('reset', $box);
1339
+
1340
+
1341
+ $(window).trigger('scroll');
1342
+
1343
+ return $modal;
1344
+ },
1345
+ // @param n is name of modal
1346
+ buildModalBtn: function (n, $modal) {
1347
+ var t = this,
1348
+ prefix = t.o.prefix;
1349
+
1350
+ return $('<button/>', {
1351
+ class: prefix + 'modal-button ' + prefix + 'modal-' + n,
1352
+ type: n,
1353
+ text: t.lang[n] || n
1354
+ }).appendTo($('form', $modal));
1355
+ },
1356
+ // close current modal box
1357
+ closeModal: function () {
1358
+ var t = this,
1359
+ prefix = t.o.prefix;
1360
+
1361
+ t.$btnPane.removeClass(prefix + 'disable');
1362
+ t.$overlay.off();
1363
+
1364
+ // Find the modal box
1365
+ var $modalBox = $('.' + prefix + 'modal-box', t.$box);
1366
+
1367
+ $modalBox.animate({
1368
+ top: '-' + $modalBox.height()
1369
+ }, 100, function () {
1370
+ $modalBox.parent().remove();
1371
+ t.hideOverlay();
1372
+ });
1373
+
1374
+ t.restoreRange();
1375
+ },
1376
+ // Preformated build and management modal
1377
+ openModalInsert: function (title, fields, cmd) {
1378
+ var t = this,
1379
+ prefix = t.o.prefix,
1380
+ lg = t.lang,
1381
+ html = '',
1382
+ CONFIRM_EVENT = 'tbwconfirm';
1383
+
1384
+ $.each(fields, function (fieldName, field) {
1385
+ var l = field.label,
1386
+ n = field.name || fieldName,
1387
+ a = field.attributes || {};
1388
+
1389
+ var attr = Object.keys(a).map(function (prop) {
1390
+ return prop + '="' + a[prop] + '"';
1391
+ }).join(' ');
1392
+
1393
+ html += '<label><input type="' + (field.type || 'text') + '" name="' + n + '" value="' + (field.value || '').replace(/"/g, '&quot;') + '"' + attr + '><span class="' + prefix + 'input-infos"><span>' +
1394
+ ((!l) ? (lg[fieldName] ? lg[fieldName] : fieldName) : (lg[l] ? lg[l] : l)) +
1395
+ '</span></span></label>';
1396
+ });
1397
+
1398
+ return t.openModal(title, html)
1399
+ .on(CONFIRM_EVENT, function () {
1400
+ var $form = $('form', $(this)),
1401
+ valid = true,
1402
+ values = {};
1403
+
1404
+ $.each(fields, function (fieldName, field) {
1405
+ var $field = $('input[name="' + fieldName + '"]', $form),
1406
+ inputType = $field.attr('type');
1407
+
1408
+ if (inputType.toLowerCase() === 'checkbox') {
1409
+ values[fieldName] = $field.is(':checked');
1410
+ } else {
1411
+ values[fieldName] = $.trim($field.val());
1412
+ }
1413
+ // Validate value
1414
+ if (field.required && values[fieldName] === '') {
1415
+ valid = false;
1416
+ t.addErrorOnModalField($field, t.lang.required);
1417
+ } else if (field.pattern && !field.pattern.test(values[fieldName])) {
1418
+ valid = false;
1419
+ t.addErrorOnModalField($field, field.patternError);
1420
+ }
1421
+ });
1422
+
1423
+ if (valid) {
1424
+ t.restoreRange();
1425
+
1426
+ if (cmd(values, fields)) {
1427
+ t.syncCode();
1428
+ t.$c.trigger('tbwchange');
1429
+ t.closeModal();
1430
+ $(this).off(CONFIRM_EVENT);
1431
+ }
1432
+ }
1433
+ })
1434
+ .one('tbwcancel', function () {
1435
+ $(this).off(CONFIRM_EVENT);
1436
+ t.closeModal();
1437
+ });
1438
+ },
1439
+ addErrorOnModalField: function ($field, err) {
1440
+ var prefix = this.o.prefix,
1441
+ $label = $field.parent();
1442
+
1443
+ $field
1444
+ .on('change keyup', function () {
1445
+ $label.removeClass(prefix + 'input-error');
1446
+ });
1447
+
1448
+ $label
1449
+ .addClass(prefix + 'input-error')
1450
+ .find('input+span')
1451
+ .append(
1452
+ $('<span/>', {
1453
+ class: prefix + 'msg-error',
1454
+ text: err
1455
+ })
1456
+ );
1457
+ },
1458
+
1459
+
1460
+ // Range management
1461
+ saveRange: function () {
1462
+ var t = this,
1463
+ documentSelection = t.doc.getSelection();
1464
+
1465
+ t.range = null;
1466
+
1467
+ if (documentSelection.rangeCount) {
1468
+ var savedRange = t.range = documentSelection.getRangeAt(0),
1469
+ range = t.doc.createRange(),
1470
+ rangeStart;
1471
+ range.selectNodeContents(t.$ed[0]);
1472
+ range.setEnd(savedRange.startContainer, savedRange.startOffset);
1473
+ rangeStart = (range + '').length;
1474
+ t.metaRange = {
1475
+ start: rangeStart,
1476
+ end: rangeStart + (savedRange + '').length
1477
+ };
1478
+ }
1479
+ },
1480
+ restoreRange: function () {
1481
+ var t = this,
1482
+ metaRange = t.metaRange,
1483
+ savedRange = t.range,
1484
+ documentSelection = t.doc.getSelection(),
1485
+ range;
1486
+
1487
+ if (!savedRange) {
1488
+ return;
1489
+ }
1490
+
1491
+ if (metaRange && metaRange.start !== metaRange.end) { // Algorithm from http://jsfiddle.net/WeWy7/3/
1492
+ var charIndex = 0,
1493
+ nodeStack = [t.$ed[0]],
1494
+ node,
1495
+ foundStart = false,
1496
+ stop = false;
1497
+
1498
+ range = t.doc.createRange();
1499
+
1500
+ while (!stop && (node = nodeStack.pop())) {
1501
+ if (node.nodeType === 3) {
1502
+ var nextCharIndex = charIndex + node.length;
1503
+ if (!foundStart && metaRange.start >= charIndex && metaRange.start <= nextCharIndex) {
1504
+ range.setStart(node, metaRange.start - charIndex);
1505
+ foundStart = true;
1506
+ }
1507
+ if (foundStart && metaRange.end >= charIndex && metaRange.end <= nextCharIndex) {
1508
+ range.setEnd(node, metaRange.end - charIndex);
1509
+ stop = true;
1510
+ }
1511
+ charIndex = nextCharIndex;
1512
+ } else {
1513
+ var cn = node.childNodes,
1514
+ i = cn.length;
1515
+
1516
+ while (i > 0) {
1517
+ i -= 1;
1518
+ nodeStack.push(cn[i]);
1519
+ }
1520
+ }
1521
+ }
1522
+ }
1523
+
1524
+ documentSelection.removeAllRanges();
1525
+ documentSelection.addRange(range || savedRange);
1526
+ },
1527
+ getRangeText: function () {
1528
+ return this.range + '';
1529
+ },
1530
+
1531
+ updateButtonPaneStatus: function () {
1532
+ var t = this,
1533
+ prefix = t.o.prefix,
1534
+ tags = t.getTagsRecursive(t.doc.getSelection().focusNode),
1535
+ activeClasses = prefix + 'active-button ' + prefix + 'active';
1536
+
1537
+ $('.' + prefix + 'active-button', t.$btnPane).removeClass(activeClasses);
1538
+ $.each(tags, function (i, tag) {
1539
+ var btnName = t.tagToButton[tag.toLowerCase()],
1540
+ $btn = $('.' + prefix + btnName + '-button', t.$btnPane);
1541
+
1542
+ if ($btn.length > 0) {
1543
+ $btn.addClass(activeClasses);
1544
+ } else {
1545
+ try {
1546
+ $btn = $('.' + prefix + 'dropdown .' + prefix + btnName + '-dropdown-button', t.$box);
1547
+ var dropdownBtnName = $btn.parent().data('dropdown');
1548
+ $('.' + prefix + dropdownBtnName + '-button', t.$box).addClass(activeClasses);
1549
+ } catch (e) {
1550
+ }
1551
+ }
1552
+ });
1553
+ },
1554
+ getTagsRecursive: function (element, tags) {
1555
+ var t = this;
1556
+ tags = tags || (element && element.tagName ? [element.tagName] : []);
1557
+
1558
+ if (element && element.parentNode) {
1559
+ element = element.parentNode;
1560
+ } else {
1561
+ return tags;
1562
+ }
1563
+
1564
+ var tag = element.tagName;
1565
+ if (tag === 'DIV') {
1566
+ return tags;
1567
+ }
1568
+ if (tag === 'P' && element.style.textAlign !== '') {
1569
+ tags.push(element.style.textAlign);
1570
+ }
1571
+
1572
+ $.each(t.tagHandlers, function (i, tagHandler) {
1573
+ tags = tags.concat(tagHandler(element, t));
1574
+ });
1575
+
1576
+ tags.push(tag);
1577
+
1578
+ return t.getTagsRecursive(element, tags);
1579
+ },
1580
+
1581
+ // Plugins
1582
+ initPlugins: function () {
1583
+ var t = this;
1584
+ t.loadedPlugins = [];
1585
+ $.each($.trumbowyg.plugins, function (name, plugin) {
1586
+ if (!plugin.shouldInit || plugin.shouldInit(t)) {
1587
+ plugin.init(t);
1588
+ if (plugin.tagHandler) {
1589
+ t.tagHandlers.push(plugin.tagHandler);
1590
+ }
1591
+ t.loadedPlugins.push(plugin);
1592
+ }
1593
+ });
1594
+ },
1595
+ destroyPlugins: function () {
1596
+ $.each(this.loadedPlugins, function (i, plugin) {
1597
+ if (plugin.destroy) {
1598
+ plugin.destroy();
1599
+ }
1600
+ });
1601
+ }
1602
+ };
1603
+ })(navigator, window, document, jQuery);