ui_bibz 3.0.13 → 4.0.0.beta3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (294) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/ci.yml +3 -3
  3. data/.github/workflows/linter.yml +13 -12
  4. data/.overcommit.yml +6 -0
  5. data/.rubocop.yml +6 -0
  6. data/.ruby-version +1 -1
  7. data/Gemfile +19 -12
  8. data/Gemfile.lock +178 -138
  9. data/app/assets/config/ui_bibz.js +12 -0
  10. data/app/assets/javascripts/forms/formula.js +82 -0
  11. data/app/assets/javascripts/forms/input-connected.js +132 -0
  12. data/app/assets/javascripts/forms/jquery.multi-select-extend.js +52 -0
  13. data/app/assets/javascripts/forms.js +160 -0
  14. data/app/assets/javascripts/interfaces.js +56 -0
  15. data/app/assets/javascripts/tables.js +49 -0
  16. data/app/assets/javascripts/ui_bibz_js.js +37 -0
  17. data/app/assets/stylesheets/navigations/_nav.sass +2 -0
  18. data/app/assets/stylesheets/navigations/_navbar.sass +12 -0
  19. data/app/assets/stylesheets/navigations/_progress_bar.sass +2 -0
  20. data/app/assets/stylesheets/navigations/_toolbar.sass +3 -0
  21. data/app/assets/stylesheets/sass/_boxes.sass +1 -0
  22. data/app/assets/stylesheets/sass/_containers.sass +2 -0
  23. data/app/assets/stylesheets/sass/_fixes.sass +2 -0
  24. data/app/assets/stylesheets/sass/_forms.sass +8 -0
  25. data/app/assets/stylesheets/sass/_navigations.sass +4 -0
  26. data/app/assets/stylesheets/sass/_notifications.sass +4 -0
  27. data/app/assets/stylesheets/sass/_tables.sass +2 -0
  28. data/app/assets/stylesheets/sass/_variables_mixins_functions.sass +3 -0
  29. data/app/assets/stylesheets/sass/boxes/_card.sass +4 -0
  30. data/app/assets/stylesheets/sass/containers/_panel.scss +330 -0
  31. data/app/assets/stylesheets/sass/forms/_bootstrap_select.sass +5 -0
  32. data/app/assets/stylesheets/sass/forms/_button.sass +3 -0
  33. data/app/assets/stylesheets/sass/forms/_date_picker.sass +3 -0
  34. data/app/assets/stylesheets/sass/forms/_form_check.sass +10 -0
  35. data/app/assets/stylesheets/sass/forms/_formula_field.sass +17 -0
  36. data/app/assets/stylesheets/sass/forms/_multiselect.sass +44 -0
  37. data/app/assets/stylesheets/sass/forms/_range.sass +44 -0
  38. data/app/assets/stylesheets/sass/forms/_slider.sass +136 -0
  39. data/app/assets/stylesheets/sass/forms/_surround_field.sass +25 -0
  40. data/app/assets/stylesheets/sass/notifications/_badge.sass +5 -0
  41. data/app/assets/stylesheets/sass/notifications/_glyph.sass +3 -0
  42. data/app/assets/stylesheets/sass/notifications/_star.sass +2 -0
  43. data/app/assets/stylesheets/sass/notifications/_toast.sass +3 -0
  44. data/app/assets/stylesheets/sass/tables/_table.sass +39 -0
  45. data/app/assets/stylesheets/sass/tables/_table_card.sass +39 -0
  46. data/app/assets/stylesheets/ui_bibz.sass +26 -0
  47. data/bin/test +3 -5
  48. data/config/importmap.rb +19 -0
  49. data/config/initializers/assets.rb +5 -0
  50. data/config/initializers/will_paginate.rb +1 -3
  51. data/lib/ui_bibz/builders/data_html_options_builder.rb +118 -0
  52. data/lib/ui_bibz/builders/html_classes_builder.rb +89 -0
  53. data/lib/ui_bibz/builders/html_options_builder.rb +22 -0
  54. data/lib/ui_bibz/factory_methods/component_initialize_factory_method.rb +33 -0
  55. data/lib/ui_bibz/helpers/ui/core/boxes_helper.rb +12 -12
  56. data/lib/ui_bibz/helpers/ui/core/forms_helper.rb +50 -50
  57. data/lib/ui_bibz/helpers/ui/core/icons_helper.rb +6 -6
  58. data/lib/ui_bibz/helpers/ui/core/layouts_helper.rb +2 -2
  59. data/lib/ui_bibz/helpers/ui/core/lists_helper.rb +2 -2
  60. data/lib/ui_bibz/helpers/ui/core/navigations_helper.rb +12 -12
  61. data/lib/ui_bibz/helpers/ui/core/notifications_helper.rb +4 -4
  62. data/lib/ui_bibz/helpers/ui/core/windows_helper.rb +10 -2
  63. data/lib/ui_bibz/helpers/ui/ux_helper.rb +2 -2
  64. data/lib/ui_bibz/helpers/utils_helper.rb +2 -2
  65. data/lib/ui_bibz/infos.rb +3 -3
  66. data/lib/ui_bibz/inputs/ui_bibz_form/ui_bibz_form_builder.rb +12 -12
  67. data/lib/ui_bibz/inputs/ui_bibz_inputs/collection_input.rb +1 -1
  68. data/lib/ui_bibz/rails/engine.rb +21 -4
  69. data/lib/ui_bibz/strategies/component_initialize_abstract_strategy.rb +27 -0
  70. data/lib/ui_bibz/strategies/component_initialize_block_strategy.rb +31 -0
  71. data/lib/ui_bibz/strategies/component_initialize_hash_strategy.rb +18 -0
  72. data/lib/ui_bibz/strategies/component_initialize_standard_strategy.rb +18 -0
  73. data/lib/ui_bibz/ui/concerns/card_itemable_concern.rb +4 -4
  74. data/lib/ui_bibz/ui/concerns/notification_concern.rb +1 -1
  75. data/lib/ui_bibz/ui/core/boxes/card.rb +1 -1
  76. data/lib/ui_bibz/ui/core/boxes/card_accordion.rb +4 -4
  77. data/lib/ui_bibz/ui/core/boxes/card_column.rb +1 -1
  78. data/lib/ui_bibz/ui/core/boxes/card_deck.rb +1 -1
  79. data/lib/ui_bibz/ui/core/boxes/card_grid.rb +0 -3
  80. data/lib/ui_bibz/ui/core/boxes/card_group.rb +1 -1
  81. data/lib/ui_bibz/ui/core/boxes/components/card_body.rb +9 -9
  82. data/lib/ui_bibz/ui/core/boxes/components/card_col.rb +2 -2
  83. data/lib/ui_bibz/ui/core/boxes/components/card_list_group.rb +1 -1
  84. data/lib/ui_bibz/ui/core/boxes/components/card_row.rb +1 -1
  85. data/lib/ui_bibz/ui/core/component.rb +13 -62
  86. data/lib/ui_bibz/ui/core/forms/buttons/button.rb +3 -1
  87. data/lib/ui_bibz/ui/core/forms/buttons/button_group.rb +11 -11
  88. data/lib/ui_bibz/ui/core/forms/choices/box_switch_field.rb +7 -7
  89. data/lib/ui_bibz/ui/core/forms/choices/checkbox_field.rb +2 -2
  90. data/lib/ui_bibz/ui/core/forms/choices/choice_group.rb +5 -6
  91. data/lib/ui_bibz/ui/core/forms/choices/components/choice.rb +1 -1
  92. data/lib/ui_bibz/ui/core/forms/dates/date_picker_field.rb +15 -15
  93. data/lib/ui_bibz/ui/core/forms/dropdowns/components/dropdown_link.rb +1 -1
  94. data/lib/ui_bibz/ui/core/forms/dropdowns/dropdown.rb +5 -5
  95. data/lib/ui_bibz/ui/core/forms/numbers/slider_field.rb +1 -1
  96. data/lib/ui_bibz/ui/core/forms/selects/dropdown_select_field.rb +10 -10
  97. data/lib/ui_bibz/ui/core/forms/selects/multi_column_field.rb +2 -2
  98. data/lib/ui_bibz/ui/core/forms/surrounds/surround_field.rb +32 -32
  99. data/lib/ui_bibz/ui/core/forms/textareas/markdown_editor_field.rb +7 -8
  100. data/lib/ui_bibz/ui/core/icons/components/glyph_text.rb +1 -1
  101. data/lib/ui_bibz/ui/core/icons/glyph.rb +4 -3
  102. data/lib/ui_bibz/ui/core/layouts/row.rb +2 -2
  103. data/lib/ui_bibz/ui/core/lists/components/list.rb +4 -4
  104. data/lib/ui_bibz/ui/core/lists/list_group.rb +1 -1
  105. data/lib/ui_bibz/ui/core/navigations/breadcrumb.rb +6 -4
  106. data/lib/ui_bibz/ui/core/navigations/components/nav_link_span.rb +1 -2
  107. data/lib/ui_bibz/ui/core/navigations/components/navbar_form.rb +6 -5
  108. data/lib/ui_bibz/ui/core/navigations/components/toolbar_form.rb +2 -2
  109. data/lib/ui_bibz/ui/core/navigations/nav.rb +10 -6
  110. data/lib/ui_bibz/ui/core/navigations/navbar.rb +21 -19
  111. data/lib/ui_bibz/ui/core/navigations/pagination.rb +3 -3
  112. data/lib/ui_bibz/ui/core/navigations/toolbar.rb +5 -5
  113. data/lib/ui_bibz/ui/core/notifications/alert.rb +4 -5
  114. data/lib/ui_bibz/ui/core/notifications/badge.rb +6 -2
  115. data/lib/ui_bibz/ui/core/notifications/components/toast_header.rb +1 -1
  116. data/lib/ui_bibz/ui/core/notifications/progress_bar.rb +3 -3
  117. data/lib/ui_bibz/ui/core/notifications/toast.rb +8 -9
  118. data/lib/ui_bibz/ui/core/windows/components/offcanvas_body.rb +47 -0
  119. data/lib/ui_bibz/ui/core/windows/components/offcanvas_header.rb +54 -0
  120. data/lib/ui_bibz/ui/core/windows/modal.rb +9 -9
  121. data/lib/ui_bibz/ui/core/windows/offcanvas.rb +84 -0
  122. data/lib/ui_bibz/ui/extensions/core/component/glyph_extension.rb +4 -20
  123. data/lib/ui_bibz/ui/extensions/core/component/klass_extension.rb +11 -19
  124. data/lib/ui_bibz/ui/extensions/core/forms/connect_extension.rb +1 -1
  125. data/lib/ui_bibz/ui/ux/containers/components/panel_column.rb +3 -3
  126. data/lib/ui_bibz/ui/ux/containers/components/panel_deck.rb +3 -3
  127. data/lib/ui_bibz/ui/ux/containers/components/panel_group.rb +3 -3
  128. data/lib/ui_bibz/ui/ux/containers/components/panel_header.rb +4 -4
  129. data/lib/ui_bibz/ui/ux/containers/panel.rb +13 -13
  130. data/lib/ui_bibz/ui/ux/tables/components/actions.rb +4 -4
  131. data/lib/ui_bibz/ui/ux/tables/components/column.rb +1 -1
  132. data/lib/ui_bibz/ui/ux/tables/components/columns.rb +2 -2
  133. data/lib/ui_bibz/ui/ux/tables/extensions/sortable.rb +1 -1
  134. data/lib/ui_bibz/ui/ux/tables/table.rb +5 -5
  135. data/lib/ui_bibz/ui/ux/tables/table_card.rb +6 -6
  136. data/lib/ui_bibz/ui/ux/tables/table_search_field.rb +1 -1
  137. data/lib/ui_bibz/utils/breakdown_class_name_generator.rb +3 -3
  138. data/lib/ui_bibz/utils/screwdriver.rb +1 -1
  139. data/lib/ui_bibz/view_objects/glyph_component_view_object.rb +38 -0
  140. data/lib/ui_bibz.rb +25 -0
  141. data/test/builders/data_html_classes_builder_test.rb +37 -0
  142. data/test/builders/html_classes_builder_test.rb +76 -0
  143. data/test/dummy/Rakefile +1 -1
  144. data/test/dummy/app/assets/stylesheets/application.css +1 -15
  145. data/test/dummy/app/channels/application_cable/channel.rb +6 -0
  146. data/test/dummy/app/channels/application_cable/connection.rb +6 -0
  147. data/test/dummy/app/jobs/application_job.rb +9 -0
  148. data/test/dummy/app/mailers/application_mailer.rb +6 -0
  149. data/test/dummy/app/views/layouts/application.html.erb +10 -12
  150. data/test/dummy/app/views/layouts/mailer.html.erb +13 -0
  151. data/test/dummy/app/views/layouts/mailer.text.erb +1 -0
  152. data/test/dummy/bin/rails +3 -3
  153. data/test/dummy/bin/rake +2 -2
  154. data/test/dummy/bin/setup +12 -12
  155. data/test/dummy/config/application.rb +13 -17
  156. data/test/dummy/config/boot.rb +3 -3
  157. data/test/dummy/config/database.yml +2 -2
  158. data/test/dummy/config/environment.rb +1 -1
  159. data/test/dummy/config/environments/development.rb +21 -16
  160. data/test/dummy/config/environments/production.rb +16 -41
  161. data/test/dummy/config/environments/test.rb +19 -8
  162. data/test/dummy/config/importmap.rb +11 -0
  163. data/test/dummy/config/initializers/content_security_policy.rb +21 -24
  164. data/test/dummy/config/initializers/filter_parameter_logging.rb +6 -2
  165. data/test/dummy/config/initializers/inflections.rb +4 -4
  166. data/test/dummy/config/initializers/permissions_policy.rb +12 -0
  167. data/test/dummy/config/locales/en.yml +13 -3
  168. data/test/dummy/config/puma.rb +7 -2
  169. data/test/dummy/config/storage.yml +5 -5
  170. data/test/dummy/config.ru +2 -1
  171. data/test/simple_form_test.rb +24 -24
  172. data/test/ui/core/boxes/card_test.rb +2 -1
  173. data/test/ui/core/component_test.rb +2 -2
  174. data/test/ui/core/forms/buttons/button_group_test.rb +1 -1
  175. data/test/ui/core/forms/buttons/button_link_test.rb +1 -1
  176. data/test/ui/core/forms/buttons/button_refresh_test.rb +1 -1
  177. data/test/ui/core/forms/buttons/button_test.rb +2 -2
  178. data/test/ui/core/forms/choices/box_switch_field_test.rb +10 -10
  179. data/test/ui/core/forms/choices/checkbox_field_test.rb +1 -1
  180. data/test/ui/core/forms/choices/choice_group_test.rb +1 -1
  181. data/test/ui/core/forms/dropdowns/dropdown_test.rb +1 -1
  182. data/test/ui/core/forms/numbers/formula_field_test.rb +1 -1
  183. data/test/ui/core/forms/selects/dropdown_select_field_test.rb +2 -2
  184. data/test/ui/core/forms/selects/select_field_test.rb +1 -1
  185. data/test/ui/core/forms/surrounds/surround_field_test.rb +4 -4
  186. data/test/ui/core/forms/texts/auto_complete_field_test.rb +2 -2
  187. data/test/ui/core/icons/glyph_test.rb +8 -4
  188. data/test/ui/core/icons/star_test.rb +12 -6
  189. data/test/ui/core/navigations/breadcrumb_test.rb +1 -1
  190. data/test/ui/core/navigations/link_test.rb +1 -1
  191. data/test/ui/core/navigations/nav_test.rb +11 -0
  192. data/test/ui/core/notifications/alert_test.rb +1 -1
  193. data/test/ui/core/notifications/badge_test.rb +3 -3
  194. data/test/ui/core/notifications/popover_test.rb +4 -4
  195. data/test/ui/core/notifications/spinner_test.rb +1 -1
  196. data/test/ui/core/notifications/toast_test.rb +1 -1
  197. data/test/ui/core/notifications/tooltip_test.rb +4 -4
  198. data/test/ui/core/windows/offcanvas_test.rb +27 -0
  199. data/test/ui/ux/containers/panel_test.rb +1 -1
  200. data/test/ui/ux/tables/table_test.rb +3 -3
  201. data/test/view_objects/glyph_component_view_object_test.rb +17 -0
  202. data/ui_bibz.gemspec +6 -20
  203. data/vendor/assets/fonts/fontawesome/fa-brands-400.ttf +0 -0
  204. data/vendor/assets/fonts/fontawesome/fa-brands-400.woff2 +0 -0
  205. data/vendor/assets/fonts/fontawesome/fa-regular-400.ttf +0 -0
  206. data/vendor/assets/fonts/fontawesome/fa-regular-400.woff2 +0 -0
  207. data/vendor/assets/fonts/fontawesome/fa-solid-900.ttf +0 -0
  208. data/vendor/assets/fonts/fontawesome/fa-solid-900.woff2 +0 -0
  209. data/vendor/assets/fonts/fontawesome/fa-v4compatibility.ttf +0 -0
  210. data/vendor/assets/fonts/fontawesome/fa-v4compatibility.woff2 +0 -0
  211. data/vendor/assets/javascripts/bootstrap-markdown.js +1 -1555
  212. data/vendor/assets/javascripts/bootstrap-multiselect.min.js +40 -1176
  213. data/vendor/assets/javascripts/bootstrap-switch.min.js +9 -21
  214. data/vendor/assets/javascripts/bs-custom-file-input.min.js +0 -1
  215. data/vendor/assets/javascripts/fontawesome/all.js +5977 -0
  216. data/vendor/assets/javascripts/fontawesome/all.min.js +6 -0
  217. data/vendor/assets/javascripts/fontawesome/brands.js +749 -0
  218. data/vendor/assets/javascripts/fontawesome/brands.min.js +6 -0
  219. data/vendor/assets/javascripts/fontawesome/conflict-detection.js +1138 -0
  220. data/vendor/assets/javascripts/fontawesome/conflict-detection.min.js +6 -0
  221. data/vendor/assets/javascripts/fontawesome/fontawesome.js +3126 -0
  222. data/vendor/assets/javascripts/fontawesome/fontawesome.min.js +6 -0
  223. data/vendor/assets/javascripts/fontawesome/regular.js +445 -0
  224. data/vendor/assets/javascripts/fontawesome/regular.min.js +6 -0
  225. data/vendor/assets/javascripts/fontawesome/solid.js +1672 -0
  226. data/vendor/assets/javascripts/fontawesome/solid.min.js +6 -0
  227. data/vendor/assets/javascripts/fontawesome/v4-shims.js +225 -0
  228. data/vendor/assets/javascripts/fontawesome/v4-shims.min.js +6 -0
  229. data/vendor/assets/javascripts/fuzzysort.js +562 -0
  230. data/vendor/assets/javascripts/jquery-3.7.0.min.js +2 -0
  231. data/vendor/assets/javascripts/jquery.multi-select.min.js +725 -1
  232. data/vendor/assets/stylesheets/bootstrap-multiselect.sass +115 -0
  233. data/vendor/assets/stylesheets/bootstrap-switch.scss +211 -0
  234. data/vendor/assets/stylesheets/fontawesome/_animated.scss +142 -9
  235. data/vendor/assets/stylesheets/fontawesome/_bordered-pulled.scss +13 -13
  236. data/vendor/assets/stylesheets/fontawesome/_core.scss +28 -6
  237. data/vendor/assets/stylesheets/fontawesome/_fixed-width.scss +2 -1
  238. data/vendor/assets/stylesheets/fontawesome/_functions.scss +57 -0
  239. data/vendor/assets/stylesheets/fontawesome/_icons.scss +7 -1438
  240. data/vendor/assets/stylesheets/fontawesome/_list.scss +4 -4
  241. data/vendor/assets/stylesheets/fontawesome/_mixins.scss +53 -34
  242. data/vendor/assets/stylesheets/fontawesome/_rotated-flipped.scss +25 -18
  243. data/vendor/assets/stylesheets/fontawesome/_screen-reader.scss +12 -3
  244. data/vendor/assets/stylesheets/fontawesome/_shims.scss +640 -664
  245. data/vendor/assets/stylesheets/fontawesome/_sizing.scss +16 -0
  246. data/vendor/assets/stylesheets/fontawesome/_stacked.scss +5 -4
  247. data/vendor/assets/stylesheets/fontawesome/_variables.scss +4896 -1393
  248. data/vendor/assets/stylesheets/fontawesome/brands.scss +17 -10
  249. data/vendor/assets/stylesheets/fontawesome/fontawesome.scss +7 -2
  250. data/vendor/assets/stylesheets/fontawesome/regular.scss +13 -10
  251. data/vendor/assets/stylesheets/fontawesome/solid.scss +13 -11
  252. data/vendor/assets/stylesheets/fontawesome/v4-shims.scss +6 -1
  253. data/vendor/assets/stylesheets/multi-select.css +92 -0
  254. metadata +120 -348
  255. data/.gitlab-ci.yml +0 -17
  256. data/.travis.yml +0 -24
  257. data/lib/ui_bibz/ui/extensions/core/component/popover_extension.rb +0 -70
  258. data/structure.md +0 -68
  259. data/test/dummy/README.rdoc +0 -28
  260. data/test/dummy/app/assets/javascripts/application.js +0 -13
  261. data/test/dummy/app/javascripts/packs/index.js +0 -3
  262. data/test/dummy/config/initializers/application_controller_renderer.rb +0 -9
  263. data/test/dummy/config/initializers/assets.rb +0 -14
  264. data/test/dummy/config/initializers/backtrace_silencers.rb +0 -8
  265. data/test/dummy/config/initializers/cookies_serializer.rb +0 -7
  266. data/test/dummy/config/initializers/mime_types.rb +0 -5
  267. data/test/dummy/config/initializers/session_store.rb +0 -5
  268. data/test/dummy/config/initializers/ui_bibz.rb +0 -5
  269. data/test/dummy/config/initializers/wrap_parameters.rb +0 -16
  270. data/test/dummy/config/secrets.yml +0 -22
  271. data/test/dummy/config/spring.rb +0 -8
  272. data/test/dummy/test/models/user_test.rb +0 -9
  273. data/vendor/assets/fonts/fa-brands-400.eot +0 -0
  274. data/vendor/assets/fonts/fa-brands-400.svg +0 -3570
  275. data/vendor/assets/fonts/fa-brands-400.ttf +0 -0
  276. data/vendor/assets/fonts/fa-brands-400.woff +0 -0
  277. data/vendor/assets/fonts/fa-brands-400.woff2 +0 -0
  278. data/vendor/assets/fonts/fa-regular-400.eot +0 -0
  279. data/vendor/assets/fonts/fa-regular-400.svg +0 -803
  280. data/vendor/assets/fonts/fa-regular-400.ttf +0 -0
  281. data/vendor/assets/fonts/fa-regular-400.woff +0 -0
  282. data/vendor/assets/fonts/fa-regular-400.woff2 +0 -0
  283. data/vendor/assets/fonts/fa-solid-900.eot +0 -0
  284. data/vendor/assets/fonts/fa-solid-900.svg +0 -4938
  285. data/vendor/assets/fonts/fa-solid-900.ttf +0 -0
  286. data/vendor/assets/fonts/fa-solid-900.woff +0 -0
  287. data/vendor/assets/fonts/fa-solid-900.woff2 +0 -0
  288. data/vendor/assets/javascripts/all.js +0 -4441
  289. data/vendor/assets/javascripts/all.min.js +0 -5
  290. data/vendor/assets/stylesheets/all.min.css +0 -5
  291. data/vendor/assets/stylesheets/fontawesome/_larger.scss +0 -23
  292. data/vendor/assets/stylesheets/svg-with-js.css +0 -5
  293. /data/{test/dummy/app/mailers/.keep → app/assets/stylesheets/sass/forms/_dropdown.sass} +0 -0
  294. /data/{test/dummy/app/views/users/index.html.erb → app/assets/stylesheets/sass/forms/_input_refresh_button.sass} +0 -0
@@ -16,1558 +16,4 @@
16
16
  * See the License for the specific language governing permissions and
17
17
  * limitations under the License.
18
18
  * ========================================================== */
19
- (function(factory) {
20
- if (typeof define === "function" && define.amd) {
21
- // RequireJS
22
- define(["jquery"], factory);
23
- } else if (typeof exports === 'object') {
24
- // Backbone.js
25
- factory(require('jquery'));
26
- } else {
27
- // jQuery plugin
28
- factory(jQuery);
29
- }
30
- }(function($) {
31
- "use strict";
32
-
33
- /* MARKDOWN CLASS DEFINITION
34
- * ========================== */
35
-
36
- var Markdown = function(element, options) {
37
- // @TODO : remove this BC on next major release
38
- // @see : https://github.com/toopay/bootstrap-markdown/issues/109
39
- var opts = ['autofocus', 'savable', 'hideable', 'width',
40
- 'height', 'resize', 'iconlibrary', 'language',
41
- 'footer', 'fullscreen', 'hiddenButtons', 'disabledButtons'
42
- ];
43
- $.each(opts, function(_, opt) {
44
- if (typeof $(element).data(opt) !== 'undefined') {
45
- options = typeof options == 'object' ? options : {};
46
- options[opt] = $(element).data(opt);
47
- }
48
- });
49
- // End BC
50
-
51
- // Class Properties
52
- this.$ns = 'bootstrap-markdown';
53
- this.$element = $(element);
54
- this.$editable = {
55
- el: null,
56
- type: null,
57
- attrKeys: [],
58
- attrValues: [],
59
- content: null
60
- };
61
- this.$options = $.extend(true, {}, $.fn.markdown.defaults, options, this.$element.data('options'));
62
- this.$oldContent = null;
63
- this.$isPreview = false;
64
- this.$isFullscreen = false;
65
- this.$editor = null;
66
- this.$textarea = null;
67
- this.$handler = [];
68
- this.$callback = [];
69
- this.$nextTab = [];
70
-
71
- this.showEditor();
72
- };
73
-
74
- Markdown.prototype = {
75
-
76
- constructor: Markdown,
77
- __alterButtons: function(name, alter) {
78
- var handler = this.$handler,
79
- isAll = (name == 'all'),
80
- that = this;
81
-
82
- $.each(handler, function(k, v) {
83
- var halt = true;
84
- if (isAll) {
85
- halt = false;
86
- } else {
87
- halt = v.indexOf(name) < 0;
88
- }
89
-
90
- if (halt === false) {
91
- alter(that.$editor.find('button[data-handler="' + v + '"]'));
92
- }
93
- });
94
- },
95
- __buildButtons: function(buttonsArray, container) {
96
- var i,
97
- ns = this.$ns,
98
- handler = this.$handler,
99
- callback = this.$callback;
100
-
101
- for (i = 0; i < buttonsArray.length; i++) {
102
- // Build each group container
103
- var y, btnGroups = buttonsArray[i];
104
- for (y = 0; y < btnGroups.length; y++) {
105
- // Build each button group
106
- var z,
107
- buttons = btnGroups[y].data,
108
- btnGroupContainer = $('<div/>', {
109
- 'class': 'btn-group'
110
- });
111
-
112
- for (z = 0; z < buttons.length; z++) {
113
- var button = buttons[z],
114
- buttonContainer, buttonIconContainer,
115
- buttonHandler = ns + '-' + button.name,
116
- buttonIcon = this.__getIcon(button),
117
- btnText = button.btnText ? button.btnText : '',
118
- btnClass = button.btnClass ? button.btnClass : 'btn',
119
- tabIndex = button.tabIndex ? button.tabIndex : '-1',
120
- hotkey = typeof button.hotkey !== 'undefined' ? button.hotkey : '',
121
- hotkeyCaption = typeof jQuery.hotkeys !== 'undefined' && hotkey !== '' ? ' (' + hotkey + ')' : '';
122
-
123
- // Construct the button object
124
- buttonContainer = $('<button></button>');
125
- buttonContainer.text(' ' + this.__localize(btnText)).addClass('btn-default btn-sm').addClass(btnClass);
126
- if (btnClass.match(/btn\-(primary|success|info|warning|danger|link)/)) {
127
- buttonContainer.removeClass('btn-default');
128
- }
129
- buttonContainer.attr({
130
- 'type': 'button',
131
- 'title': this.__localize(button.title) + hotkeyCaption,
132
- 'tabindex': tabIndex,
133
- 'data-provider': ns,
134
- 'data-handler': buttonHandler,
135
- 'data-hotkey': hotkey
136
- });
137
- if (button.toggle === true) {
138
- buttonContainer.attr('data-toggle', 'button');
139
- }
140
- buttonIconContainer = $('<span/>');
141
- buttonIconContainer.addClass(buttonIcon);
142
- buttonIconContainer.prependTo(buttonContainer);
143
-
144
- // Attach the button object
145
- btnGroupContainer.append(buttonContainer);
146
-
147
- // Register handler and callback
148
- handler.push(buttonHandler);
149
- callback.push(button.callback);
150
- }
151
-
152
- // Attach the button group into container DOM
153
- container.append(btnGroupContainer);
154
- }
155
- }
156
-
157
- return container;
158
- },
159
- __setListener: function() {
160
- // Set size and resizable Properties
161
- var hasRows = typeof this.$textarea.attr('rows') !== 'undefined',
162
- maxRows = this.$textarea.val().split("\n").length > 5 ? this.$textarea.val().split("\n").length : '5',
163
- rowsVal = hasRows ? this.$textarea.attr('rows') : maxRows;
164
-
165
- this.$textarea.attr('rows', rowsVal);
166
- if (this.$options.resize) {
167
- this.$textarea.css('resize', this.$options.resize);
168
- }
169
-
170
- // Re-attach markdown data
171
- this.$textarea.data('markdown', this);
172
- },
173
- __setEventListeners: function() {
174
- this.$textarea.on({
175
- 'focus': $.proxy(this.focus, this),
176
- 'keyup': $.proxy(this.keyup, this),
177
- 'change': $.proxy(this.change, this),
178
- 'select': $.proxy(this.select, this)
179
- });
180
-
181
- if (this.eventSupported('keydown')) {
182
- this.$textarea.on('keydown', $.proxy(this.keydown, this));
183
- }
184
-
185
- if (this.eventSupported('keypress')) {
186
- this.$textarea.on('keypress', $.proxy(this.keypress, this));
187
- }
188
- },
189
- __handle: function(e) {
190
- var target = $(e.currentTarget),
191
- handler = this.$handler,
192
- callback = this.$callback,
193
- handlerName = target.attr('data-handler'),
194
- callbackIndex = handler.indexOf(handlerName),
195
- callbackHandler = callback[callbackIndex];
196
-
197
- // Trigger the focusin
198
- $(e.currentTarget).focus();
199
-
200
- callbackHandler(this);
201
-
202
- // Trigger onChange for each button handle
203
- this.change(this);
204
-
205
- // Unless it was the save handler,
206
- // focusin the textarea
207
- if (handlerName.indexOf('cmdSave') < 0) {
208
- this.$textarea.focus();
209
- }
210
-
211
- e.preventDefault();
212
- },
213
- __localize: function(string) {
214
- var messages = $.fn.markdown.messages,
215
- language = this.$options.language;
216
- if (
217
- typeof messages !== 'undefined' &&
218
- typeof messages[language] !== 'undefined' &&
219
- typeof messages[language][string] !== 'undefined'
220
- ) {
221
- return messages[language][string];
222
- }
223
- return string;
224
- },
225
- __getIcon: function(src) {
226
- if(typeof src == 'object'){
227
- var customIcon = this.$options.customIcons[src.name];
228
- // console.log(customIcon)
229
- // console.log(this.$options)
230
- return typeof customIcon == 'undefined' ? src.icon[this.$options.iconlibrary] : customIcon;
231
- } else {
232
- return src;
233
- }
234
- },
235
- setFullscreen: function(mode) {
236
- var $editor = this.$editor,
237
- $textarea = this.$textarea;
238
-
239
- if (mode === true) {
240
- $editor.addClass('md-fullscreen-mode');
241
- $('body').addClass('md-nooverflow');
242
- this.$options.onFullscreen(this);
243
- } else {
244
- $editor.removeClass('md-fullscreen-mode');
245
- $('body').removeClass('md-nooverflow');
246
- this.$options.onFullscreenExit(this);
247
-
248
- if (this.$isPreview === true)
249
- this.hidePreview().showPreview();
250
- }
251
-
252
- this.$isFullscreen = mode;
253
- $textarea.focus();
254
- },
255
- showEditor: function() {
256
- var instance = this,
257
- textarea,
258
- ns = this.$ns,
259
- container = this.$element,
260
- originalHeigth = container.css('height'),
261
- originalWidth = container.css('width'),
262
- editable = this.$editable,
263
- handler = this.$handler,
264
- callback = this.$callback,
265
- options = this.$options,
266
- editor = $('<div/>', {
267
- 'class': 'md-editor',
268
- click: function() {
269
- instance.focus();
270
- }
271
- });
272
-
273
- // Prepare the editor
274
- if (this.$editor === null) {
275
- // Create the panel
276
- var editorHeader = $('<div/>', {
277
- 'class': 'md-header btn-toolbar'
278
- });
279
-
280
- // Merge the main & additional button groups together
281
- var allBtnGroups = [];
282
- if (options.buttons.length > 0) allBtnGroups = allBtnGroups.concat(options.buttons[0]);
283
- if (options.additionalButtons.length > 0) {
284
- // iterate the additional button groups
285
- $.each(options.additionalButtons[0], function(idx, buttonGroup) {
286
-
287
- // see if the group name of the additional group matches an existing group
288
- var matchingGroups = $.grep(allBtnGroups, function(allButtonGroup, allIdx) {
289
- return allButtonGroup.name === buttonGroup.name;
290
- });
291
-
292
- // if it matches add the additional buttons to that group, if not just add it to the all buttons group
293
- if (matchingGroups.length > 0) {
294
- matchingGroups[0].data = matchingGroups[0].data.concat(buttonGroup.data);
295
- } else {
296
- allBtnGroups.push(options.additionalButtons[0][idx]);
297
- }
298
-
299
- });
300
- }
301
-
302
- // Reduce and/or reorder the button groups
303
- if (options.reorderButtonGroups.length > 0) {
304
- allBtnGroups = allBtnGroups
305
- .filter(function(btnGroup) {
306
- return options.reorderButtonGroups.indexOf(btnGroup.name) > -1;
307
- })
308
- .sort(function(a, b) {
309
- if (options.reorderButtonGroups.indexOf(a.name) < options.reorderButtonGroups.indexOf(b.name)) return -1;
310
- if (options.reorderButtonGroups.indexOf(a.name) > options.reorderButtonGroups.indexOf(b.name)) return 1;
311
- return 0;
312
- });
313
- }
314
-
315
- // Build the buttons
316
- if (allBtnGroups.length > 0) {
317
- editorHeader = this.__buildButtons([allBtnGroups], editorHeader);
318
- }
319
-
320
- if (options.fullscreen.enable) {
321
- editorHeader.append('<div class="md-controls"><a class="md-control md-control-fullscreen" href="#"><span class="' + this.__getIcon(options.fullscreen.icons.fullscreenOn) + '"></span></a></div>').on('click', '.md-control-fullscreen', function(e) {
322
- e.preventDefault();
323
- instance.setFullscreen(true);
324
- });
325
- }
326
-
327
- editor.append(editorHeader);
328
-
329
- // Wrap the textarea
330
- if (container.is('textarea')) {
331
- container.before(editor);
332
- textarea = container;
333
- textarea.addClass('md-input');
334
- editor.append(textarea);
335
- } else {
336
- var rawContent = (typeof toMarkdown == 'function') ? toMarkdown(container.html()) : container.html(),
337
- currentContent = $.trim(rawContent);
338
-
339
- // This is some arbitrary content that could be edited
340
- textarea = $('<textarea/>', {
341
- 'class': 'md-input',
342
- 'val': currentContent
343
- });
344
-
345
- editor.append(textarea);
346
-
347
- // Save the editable
348
- editable.el = container;
349
- editable.type = container.prop('tagName').toLowerCase();
350
- editable.content = container.html();
351
-
352
- $(container[0].attributes).each(function() {
353
- editable.attrKeys.push(this.nodeName);
354
- editable.attrValues.push(this.nodeValue);
355
- });
356
-
357
- // Set editor to block the original container
358
- container.replaceWith(editor);
359
- }
360
-
361
- var editorFooter = $('<div/>', {
362
- 'class': 'md-footer'
363
- }),
364
- createFooter = false,
365
- footer = '';
366
- // Create the footer if savable
367
- if (options.savable) {
368
- createFooter = true;
369
- var saveHandler = 'cmdSave';
370
-
371
- // Register handler and callback
372
- handler.push(saveHandler);
373
- callback.push(options.onSave);
374
-
375
- editorFooter.append('<button class="btn btn-success" data-provider="' +
376
- ns +
377
- '" data-handler="' +
378
- saveHandler +
379
- '"><i class="icon icon-white icon-ok"></i> ' +
380
- this.__localize('Save') +
381
- '</button>');
382
-
383
-
384
- }
385
-
386
- footer = typeof options.footer === 'function' ? options.footer(this) : options.footer;
387
-
388
- if ($.trim(footer) !== '') {
389
- createFooter = true;
390
- editorFooter.append(footer);
391
- }
392
-
393
- if (createFooter) editor.append(editorFooter);
394
-
395
- // Set width
396
- if (options.width && options.width !== 'inherit') {
397
- if (jQuery.isNumeric(options.width)) {
398
- editor.css('display', 'table');
399
- textarea.css('width', options.width + 'px');
400
- } else {
401
- editor.addClass(options.width);
402
- }
403
- }
404
-
405
- // Set height
406
- if (options.height && options.height !== 'inherit') {
407
- if (jQuery.isNumeric(options.height)) {
408
- var height = options.height;
409
- if (editorHeader) height = Math.max(0, height - editorHeader.outerHeight());
410
- if (editorFooter) height = Math.max(0, height - editorFooter.outerHeight());
411
- textarea.css('height', height + 'px');
412
- } else {
413
- editor.addClass(options.height);
414
- }
415
- }
416
-
417
- // Reference
418
- this.$editor = editor;
419
- this.$textarea = textarea;
420
- this.$editable = editable;
421
- this.$oldContent = this.getContent();
422
-
423
- this.__setListener();
424
- this.__setEventListeners();
425
-
426
- // Set editor attributes, data short-hand API and listener
427
- this.$editor.attr('id', (new Date()).getTime());
428
- this.$editor.on('click', '[data-provider="bootstrap-markdown"]', $.proxy(this.__handle, this));
429
-
430
- if (this.$element.is(':disabled') || this.$element.is('[readonly]')) {
431
- this.$editor.addClass('md-editor-disabled');
432
- this.disableButtons('all');
433
- }
434
-
435
- if (this.eventSupported('keydown') && typeof jQuery.hotkeys === 'object') {
436
- editorHeader.find('[data-provider="bootstrap-markdown"]').each(function() {
437
- var $button = $(this),
438
- hotkey = $button.attr('data-hotkey');
439
- if (hotkey.toLowerCase() !== '') {
440
- textarea.bind('keydown', hotkey, function() {
441
- $button.trigger('click');
442
- return false;
443
- });
444
- }
445
- });
446
- }
447
-
448
- if (options.initialstate === 'preview') {
449
- this.showPreview();
450
- } else if (options.initialstate === 'fullscreen' && options.fullscreen.enable) {
451
- this.setFullscreen(true);
452
- }
453
-
454
- } else {
455
- this.$editor.show();
456
- }
457
-
458
- if (options.autofocus) {
459
- this.$textarea.focus();
460
- this.$editor.addClass('active');
461
- }
462
-
463
- if (options.fullscreen.enable && options.fullscreen !== false) {
464
- this.$editor.append('<div class="md-fullscreen-controls">' +
465
- '<a href="#" class="exit-fullscreen" title="Exit fullscreen"><span class="' + this.__getIcon(options.fullscreen.icons.fullscreenOff) + '">' +
466
- '</span></a>' +
467
- '</div>');
468
- this.$editor.on('click', '.exit-fullscreen', function(e) {
469
- e.preventDefault();
470
- instance.setFullscreen(false);
471
- });
472
- }
473
-
474
- // hide hidden buttons from options
475
- this.hideButtons(options.hiddenButtons);
476
-
477
- // disable disabled buttons from options
478
- this.disableButtons(options.disabledButtons);
479
-
480
- // enable dropZone if available and configured
481
- if (options.dropZoneOptions) {
482
- if (this.$editor.dropzone) {
483
- if(!options.dropZoneOptions.init) {
484
- options.dropZoneOptions.init = function() {
485
- var caretPos = 0;
486
- this.on('drop', function(e) {
487
- caretPos = textarea.prop('selectionStart');
488
- });
489
- this.on('success', function(file, path) {
490
- var text = textarea.val();
491
- textarea.val(text.substring(0, caretPos) + '\n![description](' + path + ')\n' + text.substring(caretPos));
492
- });
493
- this.on('error', function(file, error, xhr) {
494
- console.log('Error:', error);
495
- });
496
- };
497
- }
498
- this.$editor.addClass('dropzone');
499
- this.$editor.dropzone(options.dropZoneOptions);
500
- } else {
501
- console.log('dropZoneOptions was configured, but DropZone was not detected.');
502
- }
503
- }
504
-
505
- // enable data-uris via drag and drop
506
- if (options.enableDropDataUri === true) {
507
- this.$editor.on('drop', function(e) {
508
- var caretPos = textarea.prop('selectionStart');
509
- e.stopPropagation();
510
- e.preventDefault();
511
- $.each(e.originalEvent.dataTransfer.files, function(index, file){
512
- var fileReader = new FileReader();
513
- fileReader.onload = (function(file) {
514
- var type = file.type.split('/')[0];
515
- return function(e) {
516
- var text = textarea.val();
517
- if (type === 'image')
518
- textarea.val(text.substring(0, caretPos) + '\n<img src="'+ e.target.result +'" />\n' + text.substring(caretPos) );
519
- else
520
- textarea.val(text.substring(0, caretPos) + '\n<a href="'+ e.target.result +'">Download ' + file.name + '</a>\n' + text.substring(caretPos) );
521
- };
522
- })(file);
523
- fileReader.readAsDataURL(file);
524
- });
525
- });
526
- }
527
-
528
- // Trigger the onShow hook
529
- options.onShow(this);
530
-
531
- return this;
532
- },
533
- parseContent: function(val) {
534
- var content;
535
-
536
- // parse with supported markdown parser
537
- val = val || this.$textarea.val();
538
-
539
- if (this.$options.parser) {
540
- content = this.$options.parser(val);
541
- } else if (typeof markdown == 'object') {
542
- content = markdown.toHTML(val);
543
- } else if (typeof marked == 'function') {
544
- content = marked(val);
545
- } else {
546
- content = val;
547
- }
548
-
549
- return content;
550
- },
551
- showPreview: function() {
552
- var options = this.$options,
553
- container = this.$textarea,
554
- afterContainer = container.next(),
555
- replacementContainer = $('<div/>', {
556
- 'class': 'md-preview',
557
- 'data-provider': 'markdown-preview'
558
- }),
559
- content,
560
- callbackContent;
561
-
562
- if (this.$isPreview === true) {
563
- // Avoid sequenced element creation on misused scenario
564
- // @see https://github.com/toopay/bootstrap-markdown/issues/170
565
- return this;
566
- }
567
-
568
- // Give flag that tells the editor to enter preview mode
569
- this.$isPreview = true;
570
- // Disable all buttons
571
- this.disableButtons('all').enableButtons('cmdPreview');
572
-
573
- // Try to get the content from callback
574
- callbackContent = options.onPreview(this, replacementContainer);
575
- // Set the content based on the callback content if string, otherwise parse value from textarea
576
- content = typeof callbackContent == 'string' ? callbackContent : this.parseContent();
577
-
578
- // Build preview element
579
- replacementContainer.html(content);
580
-
581
- if (afterContainer && afterContainer.attr('class') == 'md-footer') {
582
- // If there is footer element, insert the preview container before it
583
- replacementContainer.insertBefore(afterContainer);
584
- } else {
585
- // Otherwise, just append it after textarea
586
- container.parent().append(replacementContainer);
587
- }
588
-
589
- // Set the preview element dimensions
590
- replacementContainer.css({
591
- "width": container.outerWidth() + 'px',
592
- "min-height": container.outerHeight() + 'px',
593
- "height": "auto"
594
- });
595
-
596
- if (this.$options.resize) {
597
- replacementContainer.css('resize', this.$options.resize);
598
- }
599
-
600
- // Hide the last-active textarea
601
- container.hide();
602
-
603
- // Attach the editor instances
604
- replacementContainer.data('markdown', this);
605
-
606
- if (this.$element.is(':disabled') || this.$element.is('[readonly]')) {
607
- this.$editor.addClass('md-editor-disabled');
608
- this.disableButtons('all');
609
- }
610
-
611
- return this;
612
- },
613
- hidePreview: function() {
614
- // Give flag that tells the editor to quit preview mode
615
- this.$isPreview = false;
616
-
617
- // Obtain the preview container
618
- var container = this.$editor.find('div[data-provider="markdown-preview"]');
619
-
620
- // Remove the preview container
621
- container.remove();
622
-
623
- // Enable all buttons
624
- this.enableButtons('all');
625
- // Disable configured disabled buttons
626
- this.disableButtons(this.$options.disabledButtons);
627
-
628
- // Perform any callbacks
629
- this.$options.onPreviewEnd(this);
630
-
631
- // Back to the editor
632
- this.$textarea.show();
633
- this.__setListener();
634
-
635
- return this;
636
- },
637
- isDirty: function() {
638
- return this.$oldContent != this.getContent();
639
- },
640
- getContent: function() {
641
- return this.$textarea.val();
642
- },
643
- setContent: function(content) {
644
- this.$textarea.val(content);
645
-
646
- return this;
647
- },
648
- findSelection: function(chunk) {
649
- var content = this.getContent(),
650
- startChunkPosition;
651
-
652
- if (startChunkPosition = content.indexOf(chunk), startChunkPosition >= 0 && chunk.length > 0) {
653
- var oldSelection = this.getSelection(),
654
- selection;
655
-
656
- this.setSelection(startChunkPosition, startChunkPosition + chunk.length);
657
- selection = this.getSelection();
658
-
659
- this.setSelection(oldSelection.start, oldSelection.end);
660
-
661
- return selection;
662
- } else {
663
- return null;
664
- }
665
- },
666
- getSelection: function() {
667
-
668
- var e = this.$textarea[0];
669
-
670
- return (
671
-
672
- ('selectionStart' in e && function() {
673
- var l = e.selectionEnd - e.selectionStart;
674
- return {
675
- start: e.selectionStart,
676
- end: e.selectionEnd,
677
- length: l,
678
- text: e.value.substr(e.selectionStart, l)
679
- };
680
- }) ||
681
-
682
- /* browser not supported */
683
- function() {
684
- return null;
685
- }
686
-
687
- )();
688
-
689
- },
690
- setSelection: function(start, end) {
691
-
692
- var e = this.$textarea[0];
693
-
694
- return (
695
-
696
- ('selectionStart' in e && function() {
697
- e.selectionStart = start;
698
- e.selectionEnd = end;
699
- return;
700
- }) ||
701
-
702
- /* browser not supported */
703
- function() {
704
- return null;
705
- }
706
-
707
- )();
708
-
709
- },
710
- replaceSelection: function(text) {
711
-
712
- var e = this.$textarea[0];
713
-
714
- return (
715
-
716
- ('selectionStart' in e && function() {
717
- e.value = e.value.substr(0, e.selectionStart) + text + e.value.substr(e.selectionEnd, e.value.length);
718
- // Set cursor to the last replacement end
719
- e.selectionStart = e.value.length;
720
- return this;
721
- }) ||
722
-
723
- /* browser not supported */
724
- function() {
725
- e.value += text;
726
- return jQuery(e);
727
- }
728
-
729
- )();
730
- },
731
- getNextTab: function() {
732
- // Shift the nextTab
733
- if (this.$nextTab.length === 0) {
734
- return null;
735
- } else {
736
- var nextTab, tab = this.$nextTab.shift();
737
-
738
- if (typeof tab == 'function') {
739
- nextTab = tab();
740
- } else if (typeof tab == 'object' && tab.length > 0) {
741
- nextTab = tab;
742
- }
743
-
744
- return nextTab;
745
- }
746
- },
747
- setNextTab: function(start, end) {
748
- // Push new selection into nextTab collections
749
- if (typeof start == 'string') {
750
- var that = this;
751
- this.$nextTab.push(function() {
752
- return that.findSelection(start);
753
- });
754
- } else if (typeof start == 'number' && typeof end == 'number') {
755
- var oldSelection = this.getSelection();
756
-
757
- this.setSelection(start, end);
758
- this.$nextTab.push(this.getSelection());
759
-
760
- this.setSelection(oldSelection.start, oldSelection.end);
761
- }
762
-
763
- return;
764
- },
765
- __parseButtonNameParam: function(names) {
766
- return typeof names == 'string' ?
767
- names.split(' ') :
768
- names;
769
-
770
- },
771
- enableButtons: function(name) {
772
- var buttons = this.__parseButtonNameParam(name),
773
- that = this;
774
-
775
- $.each(buttons, function(i, v) {
776
- that.__alterButtons(buttons[i], function(el) {
777
- el.removeAttr('disabled');
778
- });
779
- });
780
-
781
- return this;
782
- },
783
- disableButtons: function(name) {
784
- var buttons = this.__parseButtonNameParam(name),
785
- that = this;
786
-
787
- $.each(buttons, function(i, v) {
788
- that.__alterButtons(buttons[i], function(el) {
789
- el.attr('disabled', 'disabled');
790
- });
791
- });
792
-
793
- return this;
794
- },
795
- hideButtons: function(name) {
796
- var buttons = this.__parseButtonNameParam(name),
797
- that = this;
798
-
799
- $.each(buttons, function(i, v) {
800
- that.__alterButtons(buttons[i], function(el) {
801
- el.addClass('hidden');
802
- });
803
- });
804
-
805
- return this;
806
- },
807
- showButtons: function(name) {
808
- var buttons = this.__parseButtonNameParam(name),
809
- that = this;
810
-
811
- $.each(buttons, function(i, v) {
812
- that.__alterButtons(buttons[i], function(el) {
813
- el.removeClass('hidden');
814
- });
815
- });
816
-
817
- return this;
818
- },
819
- eventSupported: function(eventName) {
820
- var isSupported = eventName in this.$element;
821
- if (!isSupported) {
822
- this.$element.setAttribute(eventName, 'return;');
823
- isSupported = typeof this.$element[eventName] === 'function';
824
- }
825
- return isSupported;
826
- },
827
- keyup: function(e) {
828
- var blocked = false;
829
- switch (e.keyCode) {
830
- case 40: // down arrow
831
- case 38: // up arrow
832
- case 16: // shift
833
- case 17: // ctrl
834
- case 18: // alt
835
- break;
836
-
837
- case 9: // tab
838
- var nextTab;
839
- if (nextTab = this.getNextTab(), nextTab !== null) {
840
- // Get the nextTab if exists
841
- var that = this;
842
- setTimeout(function() {
843
- that.setSelection(nextTab.start, nextTab.end);
844
- }, 500);
845
-
846
- blocked = true;
847
- } else {
848
- // The next tab's memory contains nothing...
849
- // check the cursor position to determine tab action
850
- var cursor = this.getSelection();
851
-
852
- if (cursor.start == cursor.end && cursor.end == this.getContent().length) {
853
- // The cursor has reached the end of the content
854
- blocked = false;
855
- } else {
856
- // Put the cursor to the end
857
- this.setSelection(this.getContent().length, this.getContent().length);
858
-
859
- blocked = true;
860
- }
861
- }
862
-
863
- break;
864
-
865
- case 13: // enter
866
- blocked = false;
867
- var chars = this.getContent().split('');
868
- var enterIndex = this.getSelection().start;
869
- var priorNewlineIndex = -1; // initial line break at before index 0
870
-
871
- // traverse backwards through chars to check if last line break was num/bullet item
872
- for (var i = enterIndex - 2; i >= 0; i--) {
873
- if (chars[i] === '\n') {
874
- priorNewlineIndex = i;
875
- break;
876
- }
877
- }
878
-
879
- var charFollowingLastLineBreak = chars[priorNewlineIndex + 1];
880
- if (charFollowingLastLineBreak === '-') {
881
- this.addBullet(enterIndex);
882
- } else if ($.isNumeric(charFollowingLastLineBreak)) {
883
- var numBullet = this.getBulletNumber(priorNewlineIndex + 1);
884
- if (numBullet) {
885
- this.addNumberedBullet(enterIndex, numBullet);
886
- }
887
- }
888
- break;
889
-
890
- case 27: // escape
891
- if (this.$isFullscreen) this.setFullscreen(false);
892
- blocked = false;
893
- break;
894
-
895
- default:
896
- blocked = false;
897
- }
898
-
899
- if (blocked) {
900
- e.stopPropagation();
901
- e.preventDefault();
902
- }
903
-
904
- this.$options.onChange(this);
905
- },
906
- insertContent: function(index, content) {
907
- var firstHalf = this.getContent().slice(0, index);
908
- var secondHalf = this.getContent().slice(index + 1);
909
- this.setContent(firstHalf.concat(content).concat(secondHalf));
910
- },
911
- addBullet: function(index) {
912
- this.insertContent(index, '- \n');
913
- this.setSelection(index + 2, index + 2); // Put the cursor after the bullet
914
- },
915
- addNumberedBullet: function(index, num) {
916
- var numBullet = (num + 1) + '. \n';
917
- this.insertContent(index, numBullet);
918
-
919
- var prefixLength = num.toString().length + 2;
920
- this.setSelection(index + prefixLength, index + prefixLength); // Put the cursor after the number
921
- },
922
- getBulletNumber: function(startIndex) {
923
- var bulletNum = this.getContent().slice(startIndex).split('.')[0];
924
- return $.isNumeric(bulletNum) ? parseInt(bulletNum) : null;
925
- },
926
- change: function(e) {
927
- this.$options.onChange(this);
928
- return this;
929
- },
930
- select: function(e) {
931
- this.$options.onSelect(this);
932
- return this;
933
- },
934
- focus: function(e) {
935
- var options = this.$options,
936
- isHideable = options.hideable,
937
- editor = this.$editor;
938
-
939
- editor.addClass('active');
940
-
941
- // Blur other markdown(s)
942
- $(document).find('.md-editor').each(function() {
943
- if ($(this).attr('id') !== editor.attr('id')) {
944
- var attachedMarkdown;
945
-
946
- if (attachedMarkdown = $(this).find('textarea').data('markdown'),
947
- attachedMarkdown === null) {
948
- attachedMarkdown = $(this).find('div[data-provider="markdown-preview"]').data('markdown');
949
- }
950
-
951
- if (attachedMarkdown) {
952
- attachedMarkdown.blur();
953
- }
954
- }
955
- });
956
-
957
- // Trigger the onFocus hook
958
- options.onFocus(this);
959
-
960
- return this;
961
- },
962
- blur: function(e) {
963
- var options = this.$options,
964
- isHideable = options.hideable,
965
- editor = this.$editor,
966
- editable = this.$editable;
967
-
968
- if (editor.hasClass('active') || this.$element.parent().length === 0) {
969
- editor.removeClass('active');
970
-
971
- if (isHideable) {
972
- // Check for editable elements
973
- if (editable.el !== null) {
974
- // Build the original element
975
- var oldElement = $('<' + editable.type + '/>'),
976
- content = this.getContent(),
977
- currentContent = this.parseContent(content);
978
-
979
- $(editable.attrKeys).each(function(k, v) {
980
- oldElement.attr(editable.attrKeys[k], editable.attrValues[k]);
981
- });
982
-
983
- // Get the editor content
984
- oldElement.html(currentContent);
985
-
986
- editor.replaceWith(oldElement);
987
- } else {
988
- editor.hide();
989
- }
990
- }
991
-
992
- // Trigger the onBlur hook
993
- options.onBlur(this);
994
- }
995
-
996
- return this;
997
- }
998
-
999
- };
1000
-
1001
- /* MARKDOWN PLUGIN DEFINITION
1002
- * ========================== */
1003
-
1004
- var old = $.fn.markdown;
1005
-
1006
- $.fn.markdown = function(option) {
1007
- return this.each(function() {
1008
- var $this = $(this),
1009
- data = $this.data('markdown'),
1010
- options = typeof option == 'object' && option;
1011
- if (!data)
1012
- $this.data('markdown', (data = new Markdown(this, options)));
1013
- });
1014
- };
1015
-
1016
- $.fn.markdown.messages = {};
1017
-
1018
- $.fn.markdown.defaults = {
1019
- /* Editor Properties */
1020
- autofocus: false,
1021
- hideable: false,
1022
- savable: false,
1023
- width: 'inherit',
1024
- height: 'inherit',
1025
- resize: 'none',
1026
- iconlibrary: 'glyph',
1027
- language: 'en',
1028
- initialstate: 'editor',
1029
- parser: null,
1030
- dropZoneOptions: null,
1031
- enableDropDataUri: false,
1032
-
1033
- /* Buttons Properties */
1034
- buttons: [
1035
- [{
1036
- name: 'groupFont',
1037
- data: [{
1038
- name: 'cmdBold',
1039
- hotkey: 'Ctrl+B',
1040
- title: 'Bold',
1041
- icon: {
1042
- glyph: 'glyphicon glyphicon-bold',
1043
- fa: 'fa fa-bold',
1044
- 'fa-3': 'icon-bold',
1045
- 'fa-5': 'fas fa-bold',
1046
- octicons: 'octicon octicon-bold'
1047
- },
1048
- callback: function(e) {
1049
- // Give/remove ** surround the selection
1050
- var chunk, cursor, selected = e.getSelection(),
1051
- content = e.getContent();
1052
-
1053
- if (selected.length === 0) {
1054
- // Give extra word
1055
- chunk = e.__localize('strong text');
1056
- } else {
1057
- chunk = selected.text;
1058
- }
1059
-
1060
- // transform selection and set the cursor into chunked text
1061
- if (content.substr(selected.start - 2, 2) === '**' &&
1062
- content.substr(selected.end, 2) === '**') {
1063
- e.setSelection(selected.start - 2, selected.end + 2);
1064
- e.replaceSelection(chunk);
1065
- cursor = selected.start - 2;
1066
- } else {
1067
- e.replaceSelection('**' + chunk + '**');
1068
- cursor = selected.start + 2;
1069
- }
1070
-
1071
- // Set the cursor
1072
- e.setSelection(cursor, cursor + chunk.length);
1073
- }
1074
- }, {
1075
- name: 'cmdItalic',
1076
- title: 'Italic',
1077
- hotkey: 'Ctrl+I',
1078
- icon: {
1079
- glyph: 'glyphicon glyphicon-italic',
1080
- fa: 'fa fa-italic',
1081
- 'fa-3': 'icon-italic',
1082
- 'fa-5': 'fas fa-italic',
1083
- octicons: 'octicon octicon-italic'
1084
- },
1085
- callback: function(e) {
1086
- // Give/remove * surround the selection
1087
- var chunk, cursor, selected = e.getSelection(),
1088
- content = e.getContent();
1089
-
1090
- if (selected.length === 0) {
1091
- // Give extra word
1092
- chunk = e.__localize('emphasized text');
1093
- } else {
1094
- chunk = selected.text;
1095
- }
1096
-
1097
- // transform selection and set the cursor into chunked text
1098
- if (content.substr(selected.start - 1, 1) === '_' &&
1099
- content.substr(selected.end, 1) === '_') {
1100
- e.setSelection(selected.start - 1, selected.end + 1);
1101
- e.replaceSelection(chunk);
1102
- cursor = selected.start - 1;
1103
- } else {
1104
- e.replaceSelection('_' + chunk + '_');
1105
- cursor = selected.start + 1;
1106
- }
1107
-
1108
- // Set the cursor
1109
- e.setSelection(cursor, cursor + chunk.length);
1110
- }
1111
- }, {
1112
- name: 'cmdHeading',
1113
- title: 'Heading',
1114
- hotkey: 'Ctrl+H',
1115
- icon: {
1116
- glyph: 'glyphicon glyphicon-header',
1117
- fa: 'fa fa-header',
1118
- 'fa-3': 'icon-font',
1119
- 'fa-5': 'fas fa-heading',
1120
- octicons: 'octicon octicon-text-size'
1121
- },
1122
- callback: function(e) {
1123
- // Append/remove ### surround the selection
1124
- var chunk, cursor, selected = e.getSelection(),
1125
- content = e.getContent(),
1126
- pointer, prevChar;
1127
-
1128
- if (selected.length === 0) {
1129
- // Give extra word
1130
- chunk = e.__localize('heading text');
1131
- } else {
1132
- chunk = selected.text + '\n';
1133
- }
1134
-
1135
- // transform selection and set the cursor into chunked text
1136
- if ((pointer = 4, content.substr(selected.start - pointer, pointer) === '### ') ||
1137
- (pointer = 3, content.substr(selected.start - pointer, pointer) === '###')) {
1138
- e.setSelection(selected.start - pointer, selected.end);
1139
- e.replaceSelection(chunk);
1140
- cursor = selected.start - pointer;
1141
- } else if (selected.start > 0 && (prevChar = content.substr(selected.start - 1, 1), !!prevChar && prevChar != '\n')) {
1142
- e.replaceSelection('\n\n### ' + chunk);
1143
- cursor = selected.start + 6;
1144
- } else {
1145
- // Empty string before element
1146
- e.replaceSelection('### ' + chunk);
1147
- cursor = selected.start + 4;
1148
- }
1149
-
1150
- // Set the cursor
1151
- e.setSelection(cursor, cursor + chunk.length);
1152
- }
1153
- }]
1154
- }, {
1155
- name: 'groupLink',
1156
- data: [{
1157
- name: 'cmdUrl',
1158
- title: 'URL/Link',
1159
- hotkey: 'Ctrl+L',
1160
- icon: {
1161
- glyph: 'glyphicon glyphicon-link',
1162
- fa: 'fa fa-link',
1163
- 'fa-3': 'icon-link',
1164
- 'fa-5': 'fas fa-link',
1165
- octicons: 'octicon octicon-link'
1166
- },
1167
- callback: function(e) {
1168
- // Give [] surround the selection and prepend the link
1169
- var chunk, cursor, selected = e.getSelection(),
1170
- content = e.getContent(),
1171
- link;
1172
-
1173
- if (selected.length === 0) {
1174
- // Give extra word
1175
- chunk = e.__localize('enter link description here');
1176
- } else {
1177
- chunk = selected.text;
1178
- }
1179
-
1180
- link = prompt(e.__localize('Insert Hyperlink'), 'http://');
1181
-
1182
- var urlRegex = new RegExp('^((http|https)://|(mailto:)|(//))[a-z0-9]', 'i');
1183
- if (link !== null && link !== '' && link !== 'http://' && urlRegex.test(link)) {
1184
- var sanitizedLink = $('<div>' + link + '</div>').text();
1185
-
1186
- // transform selection and set the cursor into chunked text
1187
- e.replaceSelection('[' + chunk + '](' + sanitizedLink + ')');
1188
- cursor = selected.start + 1;
1189
-
1190
- // Set the cursor
1191
- e.setSelection(cursor, cursor + chunk.length);
1192
- }
1193
- }
1194
- }, {
1195
- name: 'cmdImage',
1196
- title: 'Image',
1197
- hotkey: 'Ctrl+G',
1198
- icon: {
1199
- glyph: 'glyphicon glyphicon-picture',
1200
- fa: 'fa fa-picture-o',
1201
- 'fa-3': 'icon-picture',
1202
- 'fa-5': 'far fa-image',
1203
- octicons: 'octicon octicon-file-media'
1204
- },
1205
- callback: function(e) {
1206
- // Give ![] surround the selection and prepend the image link
1207
- var chunk, cursor, selected = e.getSelection(),
1208
- content = e.getContent(),
1209
- link;
1210
-
1211
- if (selected.length === 0) {
1212
- // Give extra word
1213
- chunk = e.__localize('enter image description here');
1214
- } else {
1215
- chunk = selected.text;
1216
- }
1217
-
1218
- link = prompt(e.__localize('Insert Image Hyperlink'), 'http://');
1219
-
1220
- var urlRegex = new RegExp('^((http|https)://|(//))[a-z0-9]', 'i');
1221
- if (link !== null && link !== '' && link !== 'http://' && urlRegex.test(link)) {
1222
- var sanitizedLink = $('<div>' + link + '</div>').text();
1223
-
1224
- // transform selection and set the cursor into chunked text
1225
- e.replaceSelection('![' + chunk + '](' + sanitizedLink + ' "' + e.__localize('enter image title here') + '")');
1226
- cursor = selected.start + 2;
1227
-
1228
- // Set the next tab
1229
- e.setNextTab(e.__localize('enter image title here'));
1230
-
1231
- // Set the cursor
1232
- e.setSelection(cursor, cursor + chunk.length);
1233
- }
1234
- }
1235
- }]
1236
- }, {
1237
- name: 'groupMisc',
1238
- data: [{
1239
- name: 'cmdList',
1240
- hotkey: 'Ctrl+U',
1241
- title: 'Unordered List',
1242
- icon: {
1243
- glyph: 'glyphicon glyphicon-list',
1244
- fa: 'fa fa-list',
1245
- 'fa-3': 'icon-list-ul',
1246
- 'fa-5': 'fas fa-list-ul',
1247
- octicons: 'octicon octicon-list-unordered'
1248
- },
1249
- callback: function(e) {
1250
- // Prepend/Give - surround the selection
1251
- var chunk, cursor, selected = e.getSelection(),
1252
- content = e.getContent();
1253
-
1254
- // transform selection and set the cursor into chunked text
1255
- if (selected.length === 0) {
1256
- // Give extra word
1257
- chunk = e.__localize('list text here');
1258
-
1259
- e.replaceSelection('- ' + chunk);
1260
- // Set the cursor
1261
- cursor = selected.start + 2;
1262
- } else {
1263
- if (selected.text.indexOf('\n') < 0) {
1264
- chunk = selected.text;
1265
-
1266
- e.replaceSelection('- ' + chunk);
1267
-
1268
- // Set the cursor
1269
- cursor = selected.start + 2;
1270
- } else {
1271
- var list = [];
1272
-
1273
- list = selected.text.split('\n');
1274
- chunk = list[0];
1275
-
1276
- $.each(list, function(k, v) {
1277
- list[k] = '- ' + v;
1278
- });
1279
-
1280
- e.replaceSelection('\n\n' + list.join('\n'));
1281
-
1282
- // Set the cursor
1283
- cursor = selected.start + 4;
1284
- }
1285
- }
1286
-
1287
- // Set the cursor
1288
- e.setSelection(cursor, cursor + chunk.length);
1289
- }
1290
- }, {
1291
- name: 'cmdListO',
1292
- hotkey: 'Ctrl+O',
1293
- title: 'Ordered List',
1294
- icon: {
1295
- glyph: 'glyphicon glyphicon-th-list',
1296
- fa: 'fa fa-list-ol',
1297
- 'fa-3': 'icon-list-ol',
1298
- 'fa-5': 'fas fa-list-ol',
1299
- octicons: 'octicon octicon-list-ordered'
1300
- },
1301
- callback: function(e) {
1302
-
1303
- // Prepend/Give - surround the selection
1304
- var chunk, cursor, selected = e.getSelection(),
1305
- content = e.getContent();
1306
-
1307
- // transform selection and set the cursor into chunked text
1308
- if (selected.length === 0) {
1309
- // Give extra word
1310
- chunk = e.__localize('list text here');
1311
- e.replaceSelection('1. ' + chunk);
1312
- // Set the cursor
1313
- cursor = selected.start + 3;
1314
- } else {
1315
- if (selected.text.indexOf('\n') < 0) {
1316
- chunk = selected.text;
1317
-
1318
- e.replaceSelection('1. ' + chunk);
1319
-
1320
- // Set the cursor
1321
- cursor = selected.start + 3;
1322
- } else {
1323
- var i = 1;
1324
- var list = [];
1325
-
1326
- list = selected.text.split('\n');
1327
- chunk = list[0];
1328
-
1329
- $.each(list, function(k, v) {
1330
- list[k] = i + '. ' + v;
1331
- i++;
1332
- });
1333
-
1334
- e.replaceSelection('\n\n' + list.join('\n'));
1335
-
1336
- // Set the cursor
1337
- cursor = selected.start + 5;
1338
- }
1339
- }
1340
-
1341
- // Set the cursor
1342
- e.setSelection(cursor, cursor + chunk.length);
1343
- }
1344
- }, {
1345
- name: 'cmdCode',
1346
- hotkey: 'Ctrl+K',
1347
- title: 'Code',
1348
- icon: {
1349
- glyph: 'glyphicon glyphicon-console',
1350
- fa: 'fa fa-code',
1351
- 'fa-3': 'icon-code',
1352
- 'fa-5': 'fas fa-code',
1353
- octicons: 'octicon octicon-code'
1354
- },
1355
- callback: function(e) {
1356
- // Give/remove ** surround the selection
1357
- var chunk, cursor, selected = e.getSelection(),
1358
- content = e.getContent();
1359
-
1360
- if (selected.length === 0) {
1361
- // Give extra word
1362
- chunk = e.__localize('code text here');
1363
- } else {
1364
- chunk = selected.text;
1365
- }
1366
-
1367
- // transform selection and set the cursor into chunked text
1368
- if (content.substr(selected.start - 4, 4) === '```\n' &&
1369
- content.substr(selected.end, 4) === '\n```') {
1370
- e.setSelection(selected.start - 4, selected.end + 4);
1371
- e.replaceSelection(chunk);
1372
- cursor = selected.start - 4;
1373
- } else if (content.substr(selected.start - 1, 1) === '`' &&
1374
- content.substr(selected.end, 1) === '`') {
1375
- e.setSelection(selected.start - 1, selected.end + 1);
1376
- e.replaceSelection(chunk);
1377
- cursor = selected.start - 1;
1378
- } else if (content.indexOf('\n') > -1) {
1379
- e.replaceSelection('```\n' + chunk + '\n```');
1380
- cursor = selected.start + 4;
1381
- } else {
1382
- e.replaceSelection('`' + chunk + '`');
1383
- cursor = selected.start + 1;
1384
- }
1385
-
1386
- // Set the cursor
1387
- e.setSelection(cursor, cursor + chunk.length);
1388
- }
1389
- }, {
1390
- name: 'cmdQuote',
1391
- hotkey: 'Ctrl+Q',
1392
- title: 'Quote',
1393
- icon: {
1394
- glyph: 'glyphicon glyphicon-comment',
1395
- fa: 'fa fa-quote-left',
1396
- 'fa-3': 'icon-quote-left',
1397
- 'fa-5': 'fas fa-quote-left',
1398
- octicons: 'octicon octicon-quote'
1399
- },
1400
- callback: function(e) {
1401
- // Prepend/Give - surround the selection
1402
- var chunk, cursor, selected = e.getSelection(),
1403
- content = e.getContent();
1404
-
1405
- // transform selection and set the cursor into chunked text
1406
- if (selected.length === 0) {
1407
- // Give extra word
1408
- chunk = e.__localize('quote here');
1409
-
1410
- e.replaceSelection('> ' + chunk);
1411
-
1412
- // Set the cursor
1413
- cursor = selected.start + 2;
1414
- } else {
1415
- if (selected.text.indexOf('\n') < 0) {
1416
- chunk = selected.text;
1417
-
1418
- e.replaceSelection('> ' + chunk);
1419
-
1420
- // Set the cursor
1421
- cursor = selected.start + 2;
1422
- } else {
1423
- var list = [];
1424
-
1425
- list = selected.text.split('\n');
1426
- chunk = list[0];
1427
-
1428
- $.each(list, function(k, v) {
1429
- list[k] = '> ' + v;
1430
- });
1431
-
1432
- e.replaceSelection('\n\n' + list.join('\n'));
1433
-
1434
- // Set the cursor
1435
- cursor = selected.start + 4;
1436
- }
1437
- }
1438
-
1439
- // Set the cursor
1440
- e.setSelection(cursor, cursor + chunk.length);
1441
- }
1442
- }]
1443
- }, {
1444
- name: 'groupUtil',
1445
- data: [{
1446
- name: 'cmdPreview',
1447
- toggle: true,
1448
- hotkey: 'Ctrl+P',
1449
- title: 'Preview',
1450
- btnText: 'Preview',
1451
- btnClass: 'btn btn-primary btn-sm',
1452
- icon: {
1453
- glyph: 'glyphicon glyphicon-search',
1454
- fa: 'fa fa-search',
1455
- 'fa-3': 'icon-search',
1456
- 'fa-5': 'fas fa-search',
1457
- octicons: 'octicon octicon-search'
1458
- },
1459
- callback: function(e) {
1460
- // Check the preview mode and toggle based on this flag
1461
- var isPreview = e.$isPreview,
1462
- content;
1463
-
1464
- if (isPreview === false) {
1465
- // Give flag that tells the editor to enter preview mode
1466
- e.showPreview();
1467
- } else {
1468
- e.hidePreview();
1469
- }
1470
- }
1471
- }]
1472
- }]
1473
- ],
1474
- customIcons: {},
1475
- additionalButtons: [], // Place to hook more buttons by code
1476
- reorderButtonGroups: [],
1477
- hiddenButtons: [], // Default hidden buttons
1478
- disabledButtons: [], // Default disabled buttons
1479
- footer: '',
1480
- fullscreen: {
1481
- enable: true,
1482
- icons: {
1483
- fullscreenOn: {
1484
- name: "fullscreenOn",
1485
- icon: {
1486
- fa: 'fa fa-expand',
1487
- glyph: 'glyphicon glyphicon-fullscreen',
1488
- 'fa-3': 'icon-resize-full',
1489
- 'fa-5': 'fas fa-expand-arrows-alt',
1490
- octicons: 'octicon octicon-link-external'
1491
- }
1492
- },
1493
- fullscreenOff: {
1494
- name: "fullscreenOff",
1495
- icon: {
1496
- fa: 'fa fa-compress',
1497
- glyph: 'glyphicon glyphicon-fullscreen',
1498
- 'fa-3': 'icon-resize-small',
1499
- 'fa-5': 'fas fa-compress',
1500
- octicons: 'octicon octicon-browser'
1501
- }
1502
- }
1503
- }
1504
- },
1505
-
1506
- /* Events hook */
1507
- onShow: function(e) {},
1508
- onPreview: function(e) {},
1509
- onPreviewEnd: function(e) {},
1510
- onSave: function(e) {},
1511
- onBlur: function(e) {},
1512
- onFocus: function(e) {},
1513
- onChange: function(e) {},
1514
- onFullscreen: function(e) {},
1515
- onFullscreenExit: function(e) {},
1516
- onSelect: function(e) {}
1517
- };
1518
-
1519
- $.fn.markdown.Constructor = Markdown;
1520
-
1521
-
1522
- /* MARKDOWN NO CONFLICT
1523
- * ==================== */
1524
-
1525
- $.fn.markdown.noConflict = function() {
1526
- $.fn.markdown = old;
1527
- return this;
1528
- };
1529
-
1530
- /* MARKDOWN GLOBAL FUNCTION & DATA-API
1531
- * ==================================== */
1532
- var initMarkdown = function(el) {
1533
- var $this = el;
1534
-
1535
- if ($this.data('markdown')) {
1536
- $this.data('markdown').showEditor();
1537
- return;
1538
- }
1539
-
1540
- $this.markdown();
1541
- };
1542
-
1543
- var blurNonFocused = function(e) {
1544
- var $activeElement = $(document.activeElement);
1545
-
1546
- // Blur event
1547
- $(document).find('.md-editor').each(function() {
1548
- var $this = $(this),
1549
- focused = $activeElement.closest('.md-editor')[0] === this,
1550
- attachedMarkdown = $this.find('textarea').data('markdown') ||
1551
- $this.find('div[data-provider="markdown-preview"]').data('markdown');
1552
-
1553
- if (attachedMarkdown && !focused) {
1554
- attachedMarkdown.blur();
1555
- }
1556
- });
1557
- };
1558
-
1559
- $(document)
1560
- .on('click.markdown.data-api', '[data-provide="markdown-editable"]', function(e) {
1561
- initMarkdown($(this));
1562
- e.preventDefault();
1563
- })
1564
- .on('click focusin', function(e) {
1565
- blurNonFocused(e);
1566
- })
1567
- .ready(function() {
1568
- $('textarea[data-provide="markdown"]').each(function() {
1569
- initMarkdown($(this));
1570
- });
1571
- });
1572
-
1573
- }));
19
+ !function(t){"function"==typeof define&&define.amd?define(["jquery"],t):t("object"==typeof exports?require("jquery"):jQuery)}(function(t){"use strict";var e=function(e,n){t.each(["autofocus","savable","hideable","width","height","resize","iconlibrary","language","footer","fullscreen","hiddenButtons","disabledButtons"],function(i,o){void 0!==t(e).data(o)&&((n="object"==typeof n?n:{})[o]=t(e).data(o))}),this.$ns="bootstrap-markdown",this.$element=t(e),this.$editable={el:null,type:null,attrKeys:[],attrValues:[],content:null},this.$options=t.extend(!0,{},t.fn.markdown.defaults,n,this.$element.data("options")),this.$oldContent=null,this.$isPreview=!1,this.$isFullscreen=!1,this.$editor=null,this.$textarea=null,this.$handler=[],this.$callback=[],this.$nextTab=[],this.showEditor()};e.prototype={constructor:e,__alterButtons:function(e,n){var i=this.$handler,o="all"==e,a=this;t.each(i,function(t,i){var s=!0;!1==(s=!o&&0>i.indexOf(e))&&n(a.$editor.find('button[data-handler="'+i+'"]'))})},__buildButtons:function(e,n){var i,o=this.$ns,a=this.$handler,s=this.$callback;for(i=0;i<e.length;i++){var r,l=e[i];for(r=0;r<l.length;r++){var c,h=l[r].data,d=t("<div/>",{class:"btn-group"});for(c=0;c<h.length;c++){var u,f,p=h[c],g=o+"-"+p.name,v=this.__getIcon(p),m=p.btnText?p.btnText:"",b=p.btnClass?p.btnClass:"btn",y=p.tabIndex?p.tabIndex:"-1",x=void 0!==p.hotkey?p.hotkey:"",w=void 0!==jQuery.hotkeys&&""!==x?" ("+x+")":"";(u=t("<button></button>")).text(" "+this.__localize(m)).addClass("btn-default btn-sm").addClass(b),b.match(/btn\-(primary|success|info|warning|danger|link)/)&&u.removeClass("btn-default"),u.attr({type:"button",title:this.__localize(p.title)+w,tabindex:y,"data-provider":o,"data-handler":g,"data-hotkey":x}),!0===p.toggle&&u.attr("data-toggle","button"),(f=t("<span/>")).addClass(v),f.prependTo(u),d.append(u),a.push(g),s.push(p.callback)}n.append(d)}}return n},__setListener:function(){var t=void 0!==this.$textarea.attr("rows"),e=this.$textarea.val().split("\n").length>5?this.$textarea.val().split("\n").length:"5",n=t?this.$textarea.attr("rows"):e;this.$textarea.attr("rows",n),this.$options.resize&&this.$textarea.css("resize",this.$options.resize),this.$textarea.data("markdown",this)},__setEventListeners:function(){this.$textarea.on({focus:t.proxy(this.focus,this),keyup:t.proxy(this.keyup,this),change:t.proxy(this.change,this),select:t.proxy(this.select,this)}),this.eventSupported("keydown")&&this.$textarea.on("keydown",t.proxy(this.keydown,this)),this.eventSupported("keypress")&&this.$textarea.on("keypress",t.proxy(this.keypress,this))},__handle:function(e){var n=t(e.currentTarget),i=this.$handler,o=this.$callback,a=n.attr("data-handler"),s=o[i.indexOf(a)];t(e.currentTarget).focus(),s(this),this.change(this),0>a.indexOf("cmdSave")&&this.$textarea.focus(),e.preventDefault()},__localize:function(e){var n=t.fn.markdown.messages,i=this.$options.language;return void 0!==n&&void 0!==n[i]&&void 0!==n[i][e]?n[i][e]:e},__getIcon:function(t){if("object"!=typeof t)return t;var e=this.$options.customIcons[t.name];return void 0===e?t.icon[this.$options.iconlibrary]:e},setFullscreen:function(e){var n=this.$editor,i=this.$textarea;!0===e?(n.addClass("md-fullscreen-mode"),t("body").addClass("md-nooverflow"),this.$options.onFullscreen(this)):(n.removeClass("md-fullscreen-mode"),t("body").removeClass("md-nooverflow"),this.$options.onFullscreenExit(this),!0===this.$isPreview&&this.hidePreview().showPreview()),this.$isFullscreen=e,i.focus()},showEditor:function(){var e,n=this,i=this.$ns,o=this.$element,a=(o.css("height"),o.css("width"),this.$editable),s=this.$handler,r=this.$callback,l=this.$options,c=t("<div/>",{class:"md-editor",click:function(){n.focus()}});if(null===this.$editor){var h=t("<div/>",{class:"md-header btn-toolbar"}),d=[];if(l.buttons.length>0&&(d=d.concat(l.buttons[0])),l.additionalButtons.length>0&&t.each(l.additionalButtons[0],function(e,n){var i=t.grep(d,function(t,e){return t.name===n.name});i.length>0?i[0].data=i[0].data.concat(n.data):d.push(l.additionalButtons[0][e])}),l.reorderButtonGroups.length>0&&(d=d.filter(function(t){return l.reorderButtonGroups.indexOf(t.name)>-1}).sort(function(t,e){return l.reorderButtonGroups.indexOf(t.name)<l.reorderButtonGroups.indexOf(e.name)?-1:l.reorderButtonGroups.indexOf(t.name)>l.reorderButtonGroups.indexOf(e.name)?1:0})),d.length>0&&(h=this.__buildButtons([d],h)),l.fullscreen.enable&&h.append('<div class="md-controls"><a class="md-control md-control-fullscreen" href="#"><span class="'+this.__getIcon(l.fullscreen.icons.fullscreenOn)+'"></span></a></div>').on("click",".md-control-fullscreen",function(t){t.preventDefault(),n.setFullscreen(!0)}),c.append(h),o.is("textarea"))o.before(c),(e=o).addClass("md-input"),c.append(e);else{var u="function"==typeof toMarkdown?toMarkdown(o.html()):o.html(),f=t.trim(u);e=t("<textarea/>",{class:"md-input",val:f}),c.append(e),a.el=o,a.type=o.prop("tagName").toLowerCase(),a.content=o.html(),t(o[0].attributes).each(function(){a.attrKeys.push(this.nodeName),a.attrValues.push(this.nodeValue)}),o.replaceWith(c)}var p=t("<div/>",{class:"md-footer"}),g=!1,v="";if(l.savable){g=!0;var m="cmdSave";s.push(m),r.push(l.onSave),p.append('<button class="btn btn-success" data-provider="'+i+'" data-handler="'+m+'"><i class="icon icon-white icon-ok"></i> '+this.__localize("Save")+"</button>")}if(v="function"==typeof l.footer?l.footer(this):l.footer,""!==t.trim(v)&&(g=!0,p.append(v)),g&&c.append(p),l.width&&"inherit"!==l.width&&(jQuery.isNumeric(l.width)?(c.css("display","table"),e.css("width",l.width+"px")):c.addClass(l.width)),l.height&&"inherit"!==l.height){if(jQuery.isNumeric(l.height)){var b=l.height;h&&(b=Math.max(0,b-h.outerHeight())),p&&(b=Math.max(0,b-p.outerHeight())),e.css("height",b+"px")}else c.addClass(l.height)}this.$editor=c,this.$textarea=e,this.$editable=a,this.$oldContent=this.getContent(),this.__setListener(),this.__setEventListeners(),this.$editor.attr("id",new Date().getTime()),this.$editor.on("click",'[data-provider="bootstrap-markdown"]',t.proxy(this.__handle,this)),(this.$element.is(":disabled")||this.$element.is("[readonly]"))&&(this.$editor.addClass("md-editor-disabled"),this.disableButtons("all")),this.eventSupported("keydown")&&"object"==typeof jQuery.hotkeys&&h.find('[data-provider="bootstrap-markdown"]').each(function(){var n=t(this),i=n.attr("data-hotkey");""!==i.toLowerCase()&&e.bind("keydown",i,function(){return n.trigger("click"),!1})}),"preview"===l.initialstate?this.showPreview():"fullscreen"===l.initialstate&&l.fullscreen.enable&&this.setFullscreen(!0)}else this.$editor.show();return l.autofocus&&(this.$textarea.focus(),this.$editor.addClass("active")),l.fullscreen.enable&&!1!==l.fullscreen&&(this.$editor.append('<div class="md-fullscreen-controls"><a href="#" class="exit-fullscreen" title="Exit fullscreen"><span class="'+this.__getIcon(l.fullscreen.icons.fullscreenOff)+'"></span></a></div>'),this.$editor.on("click",".exit-fullscreen",function(t){t.preventDefault(),n.setFullscreen(!1)})),this.hideButtons(l.hiddenButtons),this.disableButtons(l.disabledButtons),l.dropZoneOptions&&(this.$editor.dropzone?(l.dropZoneOptions.init||(l.dropZoneOptions.init=function(){var t=0;this.on("drop",function(n){t=e.prop("selectionStart")}),this.on("success",function(n,i){var o=e.val();e.val(o.substring(0,t)+"\n![description]("+i+")\n"+o.substring(t))}),this.on("error",function(t,e,n){console.log("Error:",e)})}),this.$editor.addClass("dropzone"),this.$editor.dropzone(l.dropZoneOptions)):console.log("dropZoneOptions was configured, but DropZone was not detected.")),!0===l.enableDropDataUri&&this.$editor.on("drop",function(n){var i=e.prop("selectionStart");n.stopPropagation(),n.preventDefault(),t.each(n.originalEvent.dataTransfer.files,function(t,n){var o,a,s=new FileReader;s.onload=(a=(o=n).type.split("/")[0],function(t){var n=e.val();"image"===a?e.val(n.substring(0,i)+'\n<img src="'+t.target.result+'" />\n'+n.substring(i)):e.val(n.substring(0,i)+'\n<a href="'+t.target.result+'">Download '+o.name+"</a>\n"+n.substring(i))}),s.readAsDataURL(n)})}),l.onShow(this),this},parseContent:function(t){var e;return t=t||this.$textarea.val(),e=this.$options.parser?this.$options.parser(t):"object"==typeof markdown?markdown.toHTML(t):"function"==typeof marked?marked(t):t},showPreview:function(){var e,n,i=this.$options,o=this.$textarea,a=o.next(),s=t("<div/>",{class:"md-preview","data-provider":"markdown-preview"});return!0===this.$isPreview||(this.$isPreview=!0,this.disableButtons("all").enableButtons("cmdPreview"),e="string"==typeof(n=i.onPreview(this,s))?n:this.parseContent(),s.html(e),a&&"md-footer"==a.attr("class")?s.insertBefore(a):o.parent().append(s),s.css({width:o.outerWidth()+"px","min-height":o.outerHeight()+"px",height:"auto"}),this.$options.resize&&s.css("resize",this.$options.resize),o.hide(),s.data("markdown",this),(this.$element.is(":disabled")||this.$element.is("[readonly]"))&&(this.$editor.addClass("md-editor-disabled"),this.disableButtons("all"))),this},hidePreview:function(){return this.$isPreview=!1,this.$editor.find('div[data-provider="markdown-preview"]').remove(),this.enableButtons("all"),this.disableButtons(this.$options.disabledButtons),this.$options.onPreviewEnd(this),this.$textarea.show(),this.__setListener(),this},isDirty:function(){return this.$oldContent!=this.getContent()},getContent:function(){return this.$textarea.val()},setContent:function(t){return this.$textarea.val(t),this},findSelection:function(t){if(!((e=this.getContent().indexOf(t))>=0)||!(t.length>0))return null;var e,n,i=this.getSelection();return this.setSelection(e,e+t.length),n=this.getSelection(),this.setSelection(i.start,i.end),n},getSelection:function(){var t=this.$textarea[0];return("selectionStart"in t&&function(){var e=t.selectionEnd-t.selectionStart;return{start:t.selectionStart,end:t.selectionEnd,length:e,text:t.value.substr(t.selectionStart,e)}}||function(){return null})()},setSelection:function(t,e){var n=this.$textarea[0];return("selectionStart"in n&&function(){n.selectionStart=t,n.selectionEnd=e}||function(){return null})()},replaceSelection:function(t){var e=this.$textarea[0];return("selectionStart"in e&&function(){return e.value=e.value.substr(0,e.selectionStart)+t+e.value.substr(e.selectionEnd,e.value.length),e.selectionStart=e.value.length,this}||function(){return e.value+=t,jQuery(e)})()},getNextTab:function(){if(0===this.$nextTab.length)return null;var t,e=this.$nextTab.shift();return"function"==typeof e?t=e():"object"==typeof e&&e.length>0&&(t=e),t},setNextTab:function(t,e){if("string"==typeof t){var n=this;this.$nextTab.push(function(){return n.findSelection(t)})}else if("number"==typeof t&&"number"==typeof e){var i=this.getSelection();this.setSelection(t,e),this.$nextTab.push(this.getSelection()),this.setSelection(i.start,i.end)}},__parseButtonNameParam:function(t){return"string"==typeof t?t.split(" "):t},enableButtons:function(e){var n=this.__parseButtonNameParam(e),i=this;return t.each(n,function(t,e){i.__alterButtons(n[t],function(t){t.removeAttr("disabled")})}),this},disableButtons:function(e){var n=this.__parseButtonNameParam(e),i=this;return t.each(n,function(t,e){i.__alterButtons(n[t],function(t){t.attr("disabled","disabled")})}),this},hideButtons:function(e){var n=this.__parseButtonNameParam(e),i=this;return t.each(n,function(t,e){i.__alterButtons(n[t],function(t){t.addClass("hidden")})}),this},showButtons:function(e){var n=this.__parseButtonNameParam(e),i=this;return t.each(n,function(t,e){i.__alterButtons(n[t],function(t){t.removeClass("hidden")})}),this},eventSupported:function(t){var e=t in this.$element;return e||(this.$element.setAttribute(t,"return;"),e="function"==typeof this.$element[t]),e},keyup:function(e){var n,i=!1;switch(e.keyCode){case 40:case 38:case 16:case 17:case 18:break;case 9:if(null!==(n=this.getNextTab())){var o=this;setTimeout(function(){o.setSelection(n.start,n.end)},500),i=!0}else{var a=this.getSelection();a.start==a.end&&a.end==this.getContent().length?i=!1:(this.setSelection(this.getContent().length,this.getContent().length),i=!0)}break;case 13:i=!1;for(var s=this.getContent().split(""),r=this.getSelection().start,l=-1,c=r-2;c>=0;c--)if("\n"===s[c]){l=c;break}var h=s[l+1];if("-"===h)this.addBullet(r);else if(t.isNumeric(h)){var d=this.getBulletNumber(l+1);d&&this.addNumberedBullet(r,d)}break;case 27:this.$isFullscreen&&this.setFullscreen(!1),i=!1;break;default:i=!1}i&&(e.stopPropagation(),e.preventDefault()),this.$options.onChange(this)},insertContent:function(t,e){var n=this.getContent().slice(0,t),i=this.getContent().slice(t+1);this.setContent(n.concat(e).concat(i))},addBullet:function(t){this.insertContent(t,"- \n"),this.setSelection(t+2,t+2)},addNumberedBullet:function(t,e){this.insertContent(t,e+1+". \n");var n=e.toString().length+2;this.setSelection(t+n,t+n)},getBulletNumber:function(e){var n=this.getContent().slice(e).split(".")[0];return t.isNumeric(n)?parseInt(n):null},change:function(t){return this.$options.onChange(this),this},select:function(t){return this.$options.onSelect(this),this},focus:function(e){var n=this.$options,i=(n.hideable,this.$editor);return i.addClass("active"),t(document).find(".md-editor").each(function(){if(t(this).attr("id")!==i.attr("id")){var e;null===(e=t(this).find("textarea").data("markdown"))&&(e=t(this).find('div[data-provider="markdown-preview"]').data("markdown")),e&&e.blur()}}),n.onFocus(this),this},blur:function(e){var n=this.$options,i=n.hideable,o=this.$editor,a=this.$editable;if(o.hasClass("active")||0===this.$element.parent().length){if(o.removeClass("active"),i){if(null!==a.el){var s=t("<"+a.type+"/>"),r=this.getContent(),l=this.parseContent(r);t(a.attrKeys).each(function(t,e){s.attr(a.attrKeys[t],a.attrValues[t])}),s.html(l),o.replaceWith(s)}else o.hide()}n.onBlur(this)}return this}};var n=t.fn.markdown;t.fn.markdown=function(n){return this.each(function(){var i=t(this),o=i.data("markdown");o||i.data("markdown",o=new e(this,"object"==typeof n&&n))})},t.fn.markdown.messages={},t.fn.markdown.defaults={autofocus:!1,hideable:!1,savable:!1,width:"inherit",height:"inherit",resize:"none",iconlibrary:"glyph",language:"en",initialstate:"editor",parser:null,dropZoneOptions:null,enableDropDataUri:!1,buttons:[[{name:"groupFont",data:[{name:"cmdBold",hotkey:"Ctrl+B",title:"Bold",icon:{glyph:"glyphicon glyphicon-bold",fa:"fa fa-bold","fa-3":"icon-bold","fa-5":"fa-solid fa-bold",octicons:"octicon octicon-bold"},callback:function(t){var e,n,i=t.getSelection(),o=t.getContent();e=0===i.length?t.__localize("strong text"):i.text,"**"===o.substr(i.start-2,2)&&"**"===o.substr(i.end,2)?(t.setSelection(i.start-2,i.end+2),t.replaceSelection(e),n=i.start-2):(t.replaceSelection("**"+e+"**"),n=i.start+2),t.setSelection(n,n+e.length)}},{name:"cmdItalic",title:"Italic",hotkey:"Ctrl+I",icon:{glyph:"glyphicon glyphicon-italic",fa:"fa fa-italic","fa-3":"icon-italic","fa-5":"fa-solid fa-italic",octicons:"octicon octicon-italic"},callback:function(t){var e,n,i=t.getSelection(),o=t.getContent();e=0===i.length?t.__localize("emphasized text"):i.text,"_"===o.substr(i.start-1,1)&&"_"===o.substr(i.end,1)?(t.setSelection(i.start-1,i.end+1),t.replaceSelection(e),n=i.start-1):(t.replaceSelection("_"+e+"_"),n=i.start+1),t.setSelection(n,n+e.length)}},{name:"cmdHeading",title:"Heading",hotkey:"Ctrl+H",icon:{glyph:"glyphicon glyphicon-header",fa:"fa fa-header","fa-3":"icon-font","fa-5":"fa-solid fa-heading",octicons:"octicon octicon-text-size"},callback:function(t){var e,n,i,o,a=t.getSelection(),s=t.getContent();e=0===a.length?t.__localize("heading text"):a.text+"\n",(i=4,"### "===s.substr(a.start-i,i)||(i=3,"###"===s.substr(a.start-i,i)))?(t.setSelection(a.start-i,a.end),t.replaceSelection(e),n=a.start-i):a.start>0&&(o=s.substr(a.start-1,1))&&"\n"!=o?(t.replaceSelection("\n\n### "+e),n=a.start+6):(t.replaceSelection("### "+e),n=a.start+4),t.setSelection(n,n+e.length)}}]},{name:"groupLink",data:[{name:"cmdUrl",title:"URL/Link",hotkey:"Ctrl+L",icon:{glyph:"glyphicon glyphicon-link",fa:"fa fa-link","fa-3":"icon-link","fa-5":"fa-solid fa-link",octicons:"octicon octicon-link"},callback:function(e){var n,i,o,a=e.getSelection();e.getContent(),n=0===a.length?e.__localize("enter link description here"):a.text,o=prompt(e.__localize("Insert Hyperlink"),"http://");var s=RegExp("^((http|https)://|(mailto:)|(//))[a-z0-9]","i");if(null!==o&&""!==o&&"http://"!==o&&s.test(o)){var r=t("<div>"+o+"</div>").text();e.replaceSelection("["+n+"]("+r+")"),i=a.start+1,e.setSelection(i,i+n.length)}}},{name:"cmdImage",title:"Image",hotkey:"Ctrl+G",icon:{glyph:"glyphicon glyphicon-picture",fa:"fa fa-picture-o","fa-3":"icon-picture","fa-5":"fa-regular fa-image",octicons:"octicon octicon-file-media"},callback:function(e){var n,i,o,a=e.getSelection();e.getContent(),n=0===a.length?e.__localize("enter image description here"):a.text,o=prompt(e.__localize("Insert Image Hyperlink"),"http://");var s=RegExp("^((http|https)://|(//))[a-z0-9]","i");if(null!==o&&""!==o&&"http://"!==o&&s.test(o)){var r=t("<div>"+o+"</div>").text();e.replaceSelection("!["+n+"]("+r+' "'+e.__localize("enter image title here")+'")'),i=a.start+2,e.setNextTab(e.__localize("enter image title here")),e.setSelection(i,i+n.length)}}}]},{name:"groupMisc",data:[{name:"cmdList",hotkey:"Ctrl+U",title:"Unordered List",icon:{glyph:"glyphicon glyphicon-list",fa:"fa fa-list","fa-3":"icon-list-ul","fa-5":"fa-solid fa-list-ul",octicons:"octicon octicon-list-unordered"},callback:function(e){var n,i,o=e.getSelection();if(e.getContent(),0===o.length)n=e.__localize("list text here"),e.replaceSelection("- "+n),i=o.start+2;else if(0>o.text.indexOf("\n"))n=o.text,e.replaceSelection("- "+n),i=o.start+2;else{var a=[];n=(a=o.text.split("\n"))[0],t.each(a,function(t,e){a[t]="- "+e}),e.replaceSelection("\n\n"+a.join("\n")),i=o.start+4}e.setSelection(i,i+n.length)}},{name:"cmdListO",hotkey:"Ctrl+O",title:"Ordered List",icon:{glyph:"glyphicon glyphicon-th-list",fa:"fa fa-list-ol","fa-3":"icon-list-ol","fa-5":"fa-solid fa-list-ol",octicons:"octicon octicon-list-ordered"},callback:function(e){var n,i,o=e.getSelection();if(e.getContent(),0===o.length)n=e.__localize("list text here"),e.replaceSelection("1. "+n),i=o.start+3;else if(0>o.text.indexOf("\n"))n=o.text,e.replaceSelection("1. "+n),i=o.start+3;else{var a=1,s=[];n=(s=o.text.split("\n"))[0],t.each(s,function(t,e){s[t]=a+". "+e,a++}),e.replaceSelection("\n\n"+s.join("\n")),i=o.start+5}e.setSelection(i,i+n.length)}},{name:"cmdCode",hotkey:"Ctrl+K",title:"Code",icon:{glyph:"glyphicon glyphicon-console",fa:"fa fa-code","fa-3":"icon-code","fa-5":"fa-solid fa-code",octicons:"octicon octicon-code"},callback:function(t){var e,n,i=t.getSelection(),o=t.getContent();e=0===i.length?t.__localize("code text here"):i.text,"```\n"===o.substr(i.start-4,4)&&"\n```"===o.substr(i.end,4)?(t.setSelection(i.start-4,i.end+4),t.replaceSelection(e),n=i.start-4):"`"===o.substr(i.start-1,1)&&"`"===o.substr(i.end,1)?(t.setSelection(i.start-1,i.end+1),t.replaceSelection(e),n=i.start-1):o.indexOf("\n")>-1?(t.replaceSelection("```\n"+e+"\n```"),n=i.start+4):(t.replaceSelection("`"+e+"`"),n=i.start+1),t.setSelection(n,n+e.length)}},{name:"cmdQuote",hotkey:"Ctrl+Q",title:"Quote",icon:{glyph:"glyphicon glyphicon-comment",fa:"fa fa-quote-left","fa-3":"icon-quote-left","fa-5":"fa-solid fa-quote-left",octicons:"octicon octicon-quote"},callback:function(e){var n,i,o=e.getSelection();if(e.getContent(),0===o.length)n=e.__localize("quote here"),e.replaceSelection("> "+n),i=o.start+2;else if(0>o.text.indexOf("\n"))n=o.text,e.replaceSelection("> "+n),i=o.start+2;else{var a=[];n=(a=o.text.split("\n"))[0],t.each(a,function(t,e){a[t]="> "+e}),e.replaceSelection("\n\n"+a.join("\n")),i=o.start+4}e.setSelection(i,i+n.length)}}]},{name:"groupUtil",data:[{name:"cmdPreview",toggle:!0,hotkey:"Ctrl+P",title:"Preview",btnText:"Preview",btnClass:"btn btn-primary btn-sm",icon:{glyph:"glyphicon glyphicon-search",fa:"fa fa-search","fa-3":"icon-search","fa-5":"fa-solid fa-search",octicons:"octicon octicon-search"},callback:function(t){!1===t.$isPreview?t.showPreview():t.hidePreview()}}]}]],customIcons:{},additionalButtons:[],reorderButtonGroups:[],hiddenButtons:[],disabledButtons:[],footer:"",fullscreen:{enable:!0,icons:{fullscreenOn:{name:"fullscreenOn",icon:{fa:"fa fa-expand",glyph:"glyphicon glyphicon-fullscreen","fa-3":"icon-resize-full","fa-5":"fa-solid fa-expand-arrows-alt",octicons:"octicon octicon-link-external"}},fullscreenOff:{name:"fullscreenOff",icon:{fa:"fa fa-compress",glyph:"glyphicon glyphicon-fullscreen","fa-3":"icon-resize-small","fa-5":"fa-solid fa-compress",octicons:"octicon octicon-browser"}}}},onShow:function(t){},onPreview:function(t){},onPreviewEnd:function(t){},onSave:function(t){},onBlur:function(t){},onFocus:function(t){},onChange:function(t){},onFullscreen:function(t){},onFullscreenExit:function(t){},onSelect:function(t){}},t.fn.markdown.Constructor=e,t.fn.markdown.noConflict=function(){return t.fn.markdown=n,this};var i=function(t){var e=t;if(e.data("markdown")){e.data("markdown").showEditor();return}e.markdown()},o=function(e){var n=t(document.activeElement);t(document).find(".md-editor").each(function(){var e=t(this),i=n.closest(".md-editor")[0]===this,o=e.find("textarea").data("markdown")||e.find('div[data-provider="markdown-preview"]').data("markdown");o&&!i&&o.blur()})};t(document).on("click.markdown.data-api",'[data-provide="markdown-editable"]',function(e){i(t(this)),e.preventDefault()}).on("click focusin",function(t){o(t)}).ready(function(){t('textarea[data-provide="markdown"]').each(function(){i(t(this))})})});