xmt_froala 0.3.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (203) hide show
  1. checksums.yaml +7 -0
  2. data/MIT-LICENSE +20 -0
  3. data/README.md +28 -0
  4. data/Rakefile +2 -0
  5. data/app/assets/javascripts/xmt_froala.js +31 -0
  6. data/app/assets/stylesheets/xmt_froala.css +17 -0
  7. data/app/controllers/xmt_froala/application_controller.rb +5 -0
  8. data/app/controllers/xmt_froala/assets_controller.rb +94 -0
  9. data/app/models/xmt_froala/asset_uploader.rb +107 -0
  10. data/app/models/xmt_froala/file_uploader.rb +10 -0
  11. data/app/models/xmt_froala/flash_uploader.rb +10 -0
  12. data/app/models/xmt_froala/image_uploader.rb +10 -0
  13. data/app/models/xmt_froala/media_uploader.rb +10 -0
  14. data/config/routes.rb +6 -0
  15. data/lib/generators/xmt_froala/install/USAGE +10 -0
  16. data/lib/generators/xmt_froala/install/install_generator.rb +23 -0
  17. data/lib/generators/xmt_froala/install/templates/application.js +17 -0
  18. data/lib/generators/xmt_froala/install/templates/xmt_froala.rb +29 -0
  19. data/lib/generators/xmt_froala/migration/USAGE +14 -0
  20. data/lib/generators/xmt_froala/migration/migration_generator.rb +36 -0
  21. data/lib/generators/xmt_froala/migration/templates/migration/migration.rb +18 -0
  22. data/lib/generators/xmt_froala/migration/templates/models/active_record/xmt_froala/asset.rb +14 -0
  23. data/lib/generators/xmt_froala/migration/templates/models/active_record/xmt_froala/file.rb +3 -0
  24. data/lib/generators/xmt_froala/migration/templates/models/active_record/xmt_froala/flash.rb +3 -0
  25. data/lib/generators/xmt_froala/migration/templates/models/active_record/xmt_froala/image.rb +3 -0
  26. data/lib/generators/xmt_froala/migration/templates/models/active_record/xmt_froala/media.rb +3 -0
  27. data/lib/generators/xmt_froala/migration/templates/models/mongoid/xmt_froala/asset.rb +27 -0
  28. data/lib/generators/xmt_froala/migration/templates/models/mongoid/xmt_froala/file.rb +3 -0
  29. data/lib/generators/xmt_froala/migration/templates/models/mongoid/xmt_froala/flash.rb +3 -0
  30. data/lib/generators/xmt_froala/migration/templates/models/mongoid/xmt_froala/image.rb +3 -0
  31. data/lib/generators/xmt_froala/migration/templates/models/mongoid/xmt_froala/media.rb +3 -0
  32. data/lib/tasks/xmt_froala_tasks.rake +9 -0
  33. data/lib/xmt_froala.rb +65 -0
  34. data/lib/xmt_froala/active_record.rb +14 -0
  35. data/lib/xmt_froala/engine.rb +32 -0
  36. data/lib/xmt_froala/formtastic.rb +12 -0
  37. data/lib/xmt_froala/helper.rb +105 -0
  38. data/lib/xmt_froala/simple_form.rb +11 -0
  39. data/lib/xmt_froala/version.rb +3 -0
  40. data/vendor/assets/javascripts/xmt_froala/froala_editor.js +0 -0
  41. data/vendor/assets/javascripts/xmt_froala/languages/ar.js +318 -0
  42. data/vendor/assets/javascripts/xmt_froala/languages/bs.js +318 -0
  43. data/vendor/assets/javascripts/xmt_froala/languages/cs.js +318 -0
  44. data/vendor/assets/javascripts/xmt_froala/languages/da.js +318 -0
  45. data/vendor/assets/javascripts/xmt_froala/languages/de.js +318 -0
  46. data/vendor/assets/javascripts/xmt_froala/languages/en_ca.js +262 -0
  47. data/vendor/assets/javascripts/xmt_froala/languages/en_gb.js +262 -0
  48. data/vendor/assets/javascripts/xmt_froala/languages/es.js +318 -0
  49. data/vendor/assets/javascripts/xmt_froala/languages/et.js +318 -0
  50. data/vendor/assets/javascripts/xmt_froala/languages/fa.js +318 -0
  51. data/vendor/assets/javascripts/xmt_froala/languages/fi.js +318 -0
  52. data/vendor/assets/javascripts/xmt_froala/languages/fr.js +318 -0
  53. data/vendor/assets/javascripts/xmt_froala/languages/he.js +318 -0
  54. data/vendor/assets/javascripts/xmt_froala/languages/hr.js +318 -0
  55. data/vendor/assets/javascripts/xmt_froala/languages/hu.js +318 -0
  56. data/vendor/assets/javascripts/xmt_froala/languages/id.js +319 -0
  57. data/vendor/assets/javascripts/xmt_froala/languages/it.js +318 -0
  58. data/vendor/assets/javascripts/xmt_froala/languages/ja.js +318 -0
  59. data/vendor/assets/javascripts/xmt_froala/languages/ko.js +318 -0
  60. data/vendor/assets/javascripts/xmt_froala/languages/me.js +318 -0
  61. data/vendor/assets/javascripts/xmt_froala/languages/nb.js +318 -0
  62. data/vendor/assets/javascripts/xmt_froala/languages/nl.js +318 -0
  63. data/vendor/assets/javascripts/xmt_froala/languages/pl.js +318 -0
  64. data/vendor/assets/javascripts/xmt_froala/languages/pt_br.js +318 -0
  65. data/vendor/assets/javascripts/xmt_froala/languages/pt_pt.js +318 -0
  66. data/vendor/assets/javascripts/xmt_froala/languages/ro.js +319 -0
  67. data/vendor/assets/javascripts/xmt_froala/languages/ru.js +318 -0
  68. data/vendor/assets/javascripts/xmt_froala/languages/sk.js +318 -0
  69. data/vendor/assets/javascripts/xmt_froala/languages/sr.js +318 -0
  70. data/vendor/assets/javascripts/xmt_froala/languages/sv.js +318 -0
  71. data/vendor/assets/javascripts/xmt_froala/languages/th.js +318 -0
  72. data/vendor/assets/javascripts/xmt_froala/languages/tr.js +318 -0
  73. data/vendor/assets/javascripts/xmt_froala/languages/uk.js +318 -0
  74. data/vendor/assets/javascripts/xmt_froala/languages/vi.js +258 -0
  75. data/vendor/assets/javascripts/xmt_froala/languages/zh_cn.js +320 -0
  76. data/vendor/assets/javascripts/xmt_froala/languages/zh_tw.js +318 -0
  77. data/vendor/assets/javascripts/xmt_froala/plugins/align.js +139 -0
  78. data/vendor/assets/javascripts/xmt_froala/plugins/align.min.js +7 -0
  79. data/vendor/assets/javascripts/xmt_froala/plugins/char_counter.js +154 -0
  80. data/vendor/assets/javascripts/xmt_froala/plugins/char_counter.min.js +7 -0
  81. data/vendor/assets/javascripts/xmt_froala/plugins/code_beautifier.js +3270 -0
  82. data/vendor/assets/javascripts/xmt_froala/plugins/code_beautifier.min.js +7 -0
  83. data/vendor/assets/javascripts/xmt_froala/plugins/code_view.js +393 -0
  84. data/vendor/assets/javascripts/xmt_froala/plugins/code_view.min.js +7 -0
  85. data/vendor/assets/javascripts/xmt_froala/plugins/colors.js +492 -0
  86. data/vendor/assets/javascripts/xmt_froala/plugins/colors.min.js +7 -0
  87. data/vendor/assets/javascripts/xmt_froala/plugins/draggable.js +459 -0
  88. data/vendor/assets/javascripts/xmt_froala/plugins/draggable.min.js +7 -0
  89. data/vendor/assets/javascripts/xmt_froala/plugins/emoticons.js +509 -0
  90. data/vendor/assets/javascripts/xmt_froala/plugins/emoticons.min.js +7 -0
  91. data/vendor/assets/javascripts/xmt_froala/plugins/entities.js +121 -0
  92. data/vendor/assets/javascripts/xmt_froala/plugins/entities.min.js +7 -0
  93. data/vendor/assets/javascripts/xmt_froala/plugins/file.js +736 -0
  94. data/vendor/assets/javascripts/xmt_froala/plugins/file.min.js +239 -0
  95. data/vendor/assets/javascripts/xmt_froala/plugins/font_family.js +182 -0
  96. data/vendor/assets/javascripts/xmt_froala/plugins/font_family.min.js +7 -0
  97. data/vendor/assets/javascripts/xmt_froala/plugins/font_size.js +118 -0
  98. data/vendor/assets/javascripts/xmt_froala/plugins/font_size.min.js +7 -0
  99. data/vendor/assets/javascripts/xmt_froala/plugins/forms.js +430 -0
  100. data/vendor/assets/javascripts/xmt_froala/plugins/forms.min.js +7 -0
  101. data/vendor/assets/javascripts/xmt_froala/plugins/fullscreen.js +274 -0
  102. data/vendor/assets/javascripts/xmt_froala/plugins/fullscreen.min.js +7 -0
  103. data/vendor/assets/javascripts/xmt_froala/plugins/help.js +216 -0
  104. data/vendor/assets/javascripts/xmt_froala/plugins/help.min.js +7 -0
  105. data/vendor/assets/javascripts/xmt_froala/plugins/image.js +3323 -0
  106. data/vendor/assets/javascripts/xmt_froala/plugins/image.min.js +7 -0
  107. data/vendor/assets/javascripts/xmt_froala/plugins/image_manager.js +1056 -0
  108. data/vendor/assets/javascripts/xmt_froala/plugins/image_manager.min.js +7 -0
  109. data/vendor/assets/javascripts/xmt_froala/plugins/inline_style.js +94 -0
  110. data/vendor/assets/javascripts/xmt_froala/plugins/inline_style.min.js +7 -0
  111. data/vendor/assets/javascripts/xmt_froala/plugins/line_breaker.js +537 -0
  112. data/vendor/assets/javascripts/xmt_froala/plugins/line_breaker.min.js +7 -0
  113. data/vendor/assets/javascripts/xmt_froala/plugins/link.js +1157 -0
  114. data/vendor/assets/javascripts/xmt_froala/plugins/link.min.js +7 -0
  115. data/vendor/assets/javascripts/xmt_froala/plugins/lists.js +462 -0
  116. data/vendor/assets/javascripts/xmt_froala/plugins/lists.min.js +7 -0
  117. data/vendor/assets/javascripts/xmt_froala/plugins/paragraph_format.js +290 -0
  118. data/vendor/assets/javascripts/xmt_froala/plugins/paragraph_format.min.js +7 -0
  119. data/vendor/assets/javascripts/xmt_froala/plugins/paragraph_style.js +144 -0
  120. data/vendor/assets/javascripts/xmt_froala/plugins/paragraph_style.min.js +7 -0
  121. data/vendor/assets/javascripts/xmt_froala/plugins/plain_paste.js +96 -0
  122. data/vendor/assets/javascripts/xmt_froala/plugins/print.js +137 -0
  123. data/vendor/assets/javascripts/xmt_froala/plugins/print.min.js +7 -0
  124. data/vendor/assets/javascripts/xmt_froala/plugins/quick_format.js +89 -0
  125. data/vendor/assets/javascripts/xmt_froala/plugins/quick_insert.js +478 -0
  126. data/vendor/assets/javascripts/xmt_froala/plugins/quick_insert.min.js +7 -0
  127. data/vendor/assets/javascripts/xmt_froala/plugins/quote.js +141 -0
  128. data/vendor/assets/javascripts/xmt_froala/plugins/quote.min.js +7 -0
  129. data/vendor/assets/javascripts/xmt_froala/plugins/save.js +189 -0
  130. data/vendor/assets/javascripts/xmt_froala/plugins/save.min.js +7 -0
  131. data/vendor/assets/javascripts/xmt_froala/plugins/special_characters.js +781 -0
  132. data/vendor/assets/javascripts/xmt_froala/plugins/special_characters.min.js +7 -0
  133. data/vendor/assets/javascripts/xmt_froala/plugins/table.js +4194 -0
  134. data/vendor/assets/javascripts/xmt_froala/plugins/table.min.js +7 -0
  135. data/vendor/assets/javascripts/xmt_froala/plugins/url.js +194 -0
  136. data/vendor/assets/javascripts/xmt_froala/plugins/url.min.js +7 -0
  137. data/vendor/assets/javascripts/xmt_froala/plugins/video.js +2342 -0
  138. data/vendor/assets/javascripts/xmt_froala/plugins/video.min.js +7 -0
  139. data/vendor/assets/javascripts/xmt_froala/plugins/word_paste.js +1403 -0
  140. data/vendor/assets/javascripts/xmt_froala/plugins/word_paste.min.js +7 -0
  141. data/vendor/assets/javascripts/xmt_froala/third_party/embedly.js +543 -0
  142. data/vendor/assets/javascripts/xmt_froala/third_party/embedly.min.js +7 -0
  143. data/vendor/assets/javascripts/xmt_froala/third_party/image_aviary.js +163 -0
  144. data/vendor/assets/javascripts/xmt_froala/third_party/image_aviary.min.js +7 -0
  145. data/vendor/assets/javascripts/xmt_froala/third_party/spell_checker.js +222 -0
  146. data/vendor/assets/javascripts/xmt_froala/third_party/spell_checker.min.js +7 -0
  147. data/vendor/assets/javascripts/xmt_froala/xmt_froala.js +15172 -0
  148. data/vendor/assets/stylesheets/xmt_froala/css/font-awesome.css +2546 -0
  149. data/vendor/assets/stylesheets/xmt_froala/css/froala_editor.min.css +7 -0
  150. data/vendor/assets/stylesheets/xmt_froala/css/froala_editor.pkgd.css +2902 -0
  151. data/vendor/assets/stylesheets/xmt_froala/css/froala_editor.pkgd.min.css +7 -0
  152. data/vendor/assets/stylesheets/xmt_froala/css/froala_style.css +413 -0
  153. data/vendor/assets/stylesheets/xmt_froala/css/froala_style.min.css +7 -0
  154. data/vendor/assets/stylesheets/xmt_froala/css/plugins/char_counter.css +57 -0
  155. data/vendor/assets/stylesheets/xmt_froala/css/plugins/char_counter.min.css +7 -0
  156. data/vendor/assets/stylesheets/xmt_froala/css/plugins/code_view.css +112 -0
  157. data/vendor/assets/stylesheets/xmt_froala/css/plugins/code_view.min.css +7 -0
  158. data/vendor/assets/stylesheets/xmt_froala/css/plugins/colors.css +155 -0
  159. data/vendor/assets/stylesheets/xmt_froala/css/plugins/colors.min.css +7 -0
  160. data/vendor/assets/stylesheets/xmt_froala/css/plugins/draggable.css +43 -0
  161. data/vendor/assets/stylesheets/xmt_froala/css/plugins/draggable.min.css +7 -0
  162. data/vendor/assets/stylesheets/xmt_froala/css/plugins/emoticons.css +42 -0
  163. data/vendor/assets/stylesheets/xmt_froala/css/plugins/emoticons.min.css +7 -0
  164. data/vendor/assets/stylesheets/xmt_froala/css/plugins/file.css +146 -0
  165. data/vendor/assets/stylesheets/xmt_froala/css/plugins/file.min.css +7 -0
  166. data/vendor/assets/stylesheets/xmt_froala/css/plugins/fullscreen.css +28 -0
  167. data/vendor/assets/stylesheets/xmt_froala/css/plugins/fullscreen.min.css +7 -0
  168. data/vendor/assets/stylesheets/xmt_froala/css/plugins/help.css +52 -0
  169. data/vendor/assets/stylesheets/xmt_froala/css/plugins/help.min.css +7 -0
  170. data/vendor/assets/stylesheets/xmt_froala/css/plugins/image.css +244 -0
  171. data/vendor/assets/stylesheets/xmt_froala/css/plugins/image.min.css +7 -0
  172. data/vendor/assets/stylesheets/xmt_froala/css/plugins/image_manager.css +266 -0
  173. data/vendor/assets/stylesheets/xmt_froala/css/plugins/image_manager.min.css +7 -0
  174. data/vendor/assets/stylesheets/xmt_froala/css/plugins/line_breaker.css +37 -0
  175. data/vendor/assets/stylesheets/xmt_froala/css/plugins/line_breaker.min.css +7 -0
  176. data/vendor/assets/stylesheets/xmt_froala/css/plugins/quick_insert.css +70 -0
  177. data/vendor/assets/stylesheets/xmt_froala/css/plugins/quick_insert.min.css +7 -0
  178. data/vendor/assets/stylesheets/xmt_froala/css/plugins/special_characters.css +51 -0
  179. data/vendor/assets/stylesheets/xmt_froala/css/plugins/special_characters.min.css +7 -0
  180. data/vendor/assets/stylesheets/xmt_froala/css/plugins/table.css +181 -0
  181. data/vendor/assets/stylesheets/xmt_froala/css/plugins/table.min.css +7 -0
  182. data/vendor/assets/stylesheets/xmt_froala/css/plugins/video.css +231 -0
  183. data/vendor/assets/stylesheets/xmt_froala/css/plugins/video.min.css +7 -0
  184. data/vendor/assets/stylesheets/xmt_froala/css/themes/dark.css +1281 -0
  185. data/vendor/assets/stylesheets/xmt_froala/css/themes/dark.min.css +7 -0
  186. data/vendor/assets/stylesheets/xmt_froala/css/themes/gray.css +1281 -0
  187. data/vendor/assets/stylesheets/xmt_froala/css/themes/gray.min.css +7 -0
  188. data/vendor/assets/stylesheets/xmt_froala/css/themes/red.css +1281 -0
  189. data/vendor/assets/stylesheets/xmt_froala/css/themes/red.min.css +7 -0
  190. data/vendor/assets/stylesheets/xmt_froala/css/themes/royal.css +1281 -0
  191. data/vendor/assets/stylesheets/xmt_froala/css/themes/royal.min.css +7 -0
  192. data/vendor/assets/stylesheets/xmt_froala/css/third_party/embedly.css +64 -0
  193. data/vendor/assets/stylesheets/xmt_froala/css/third_party/embedly.min.css +7 -0
  194. data/vendor/assets/stylesheets/xmt_froala/css/third_party/spell_checker.css +72 -0
  195. data/vendor/assets/stylesheets/xmt_froala/css/third_party/spell_checker.min.css +7 -0
  196. data/vendor/assets/stylesheets/xmt_froala/css/xmt_froala.css +1423 -0
  197. data/vendor/assets/stylesheets/xmt_froala/fonts/FontAwesome.otf +0 -0
  198. data/vendor/assets/stylesheets/xmt_froala/fonts/fontawesome-webfont.eot +0 -0
  199. data/vendor/assets/stylesheets/xmt_froala/fonts/fontawesome-webfont.svg +2671 -0
  200. data/vendor/assets/stylesheets/xmt_froala/fonts/fontawesome-webfont.ttf +0 -0
  201. data/vendor/assets/stylesheets/xmt_froala/fonts/fontawesome-webfont.woff +0 -0
  202. data/vendor/assets/stylesheets/xmt_froala/fonts/fontawesome-webfont.woff2 +0 -0
  203. metadata +273 -0
@@ -0,0 +1,7 @@
1
+ /*!
2
+ * froala_editor v2.8.1 (https://www.froala.com/wysiwyg-editor)
3
+ * License https://froala.com/wysiwyg-editor/terms/
4
+ * Copyright 2014-2018 Froala Labs
5
+ */
6
+
7
+ !function(o){"function"==typeof define&&define.amd?define(["jquery"],o):"object"==typeof module&&module.exports?module.exports=function(e,t){return t===undefined&&(t="undefined"!=typeof window?require("jquery"):require("jquery")(e)),o(t)}:o(window.jQuery)}(function(c){c.FE.PLUGINS.fullscreen=function(o){var t,r,s,n;function i(){return o.$box.hasClass("fr-fullscreen")}function e(){if(o.helpers.isIOS()&&o.core.hasFocus())return o.$el.blur(),setTimeout(a,250),!1;t=o.helpers.scrollTop(),o.$box.toggleClass("fr-fullscreen"),c("body:first").toggleClass("fr-fullscreen"),o.helpers.isMobile()&&(o.$tb.data("parent",o.$tb.parent()),o.$tb.prependTo(o.$box),o.$tb.data("sticky-dummy")&&o.$tb.after(o.$tb.data("sticky-dummy"))),r=o.opts.height,s=o.opts.heightMax,n=o.opts.zIndex,o.position.refresh(),o.opts.height=o.o_win.innerHeight-(o.opts.toolbarInline?0:o.$tb.outerHeight()),o.opts.zIndex=2147483641,o.opts.heightMax=null,o.size.refresh(),o.opts.toolbarInline&&o.toolbar.showInline();for(var e=o.$box.parent();!e.is("body:first");)e.data("z-index",e.css("z-index")).data("overflow",e.css("overflow")).css("z-index","2147483640").css("overflow","visible"),e=e.parent();o.opts.toolbarContainer&&o.$box.prepend(o.$tb),o.events.trigger("charCounter.update"),o.events.trigger("codeView.update"),o.$win.trigger("scroll")}function l(){if(o.helpers.isIOS()&&o.core.hasFocus())return o.$el.blur(),setTimeout(a,250),!1;o.$box.toggleClass("fr-fullscreen"),c("body:first").toggleClass("fr-fullscreen"),o.$tb.prependTo(o.$tb.data("parent")),o.$tb.data("sticky-dummy")&&o.$tb.after(o.$tb.data("sticky-dummy")),o.opts.height=r,o.opts.heightMax=s,o.opts.zIndex=n,o.size.refresh(),c(o.o_win).scrollTop(t),o.opts.toolbarInline&&o.toolbar.showInline(),o.events.trigger("charCounter.update"),o.opts.toolbarSticky&&o.opts.toolbarStickyOffset&&(o.opts.toolbarBottom?o.$tb.css("bottom",o.opts.toolbarStickyOffset).data("bottom",o.opts.toolbarStickyOffset):o.$tb.css("top",o.opts.toolbarStickyOffset).data("top",o.opts.toolbarStickyOffset));for(var e=o.$box.parent();!e.is("body:first");)e.data("z-index")&&(e.css("z-index",""),e.css("z-index")!=e.data("z-index")&&e.css("z-index",e.data("z-index")),e.removeData("z-index")),e.data("overflow")?(e.css("overflow",""),e.css("overflow")!=e.data("overflow")&&e.css("overflow",e.data("overflow"))):e.css("overflow",""),e.removeData("overflow"),e=e.parent();o.opts.toolbarContainer&&c(o.opts.toolbarContainer).append(o.$tb),c(o.o_win).trigger("scroll"),o.events.trigger("codeView.update")}function a(){i()?l():e(),f(o.$tb.find('.fr-command[data-cmd="fullscreen"]'))}function f(e){var t=i();e.toggleClass("fr-active",t).attr("aria-pressed",t),e.find("> *:not(.fr-sr-only)").replaceWith(t?o.icon.create("fullscreenCompress"):o.icon.create("fullscreen"))}return{_init:function(){if(!o.$wp)return!1;o.events.$on(c(o.o_win),"resize",function(){i()&&(l(),e())}),o.events.on("toolbar.hide",function(){if(i()&&o.helpers.isMobile())return!1}),o.events.on("position.refresh",function(){if(o.helpers.isIOS())return!i()}),o.events.on("destroy",function(){i()&&l()},!0)},toggle:a,refresh:f,isActive:i}},c.FE.RegisterCommand("fullscreen",{title:"Fullscreen",undo:!1,focus:!1,accessibilityFocus:!0,forcedRefresh:!0,toggle:!0,callback:function(){this.fullscreen.toggle()},refresh:function(e){this.fullscreen.refresh(e)},plugin:"fullscreen"}),c.FE.DefineIcon("fullscreen",{NAME:"expand"}),c.FE.DefineIcon("fullscreenCompress",{NAME:"compress"})});
@@ -0,0 +1,216 @@
1
+ /*!
2
+ * froala_editor v2.8.1 (https://www.froala.com/wysiwyg-editor)
3
+ * License https://froala.com/wysiwyg-editor/terms/
4
+ * Copyright 2014-2018 Froala Labs
5
+ */
6
+
7
+ (function (factory) {
8
+ if (typeof define === 'function' && define.amd) {
9
+ // AMD. Register as an anonymous module.
10
+ define(['jquery'], factory);
11
+ } else if (typeof module === 'object' && module.exports) {
12
+ // Node/CommonJS
13
+ module.exports = function( root, jQuery ) {
14
+ if ( jQuery === undefined ) {
15
+ // require('jQuery') returns a factory that requires window to
16
+ // build a jQuery instance, we normalize how we use modules
17
+ // that require this pattern but the window provided is a noop
18
+ // if it's defined (how jquery works)
19
+ if ( typeof window !== 'undefined' ) {
20
+ jQuery = require('jquery');
21
+ }
22
+ else {
23
+ jQuery = require('jquery')(root);
24
+ }
25
+ }
26
+ return factory(jQuery);
27
+ };
28
+ } else {
29
+ // Browser globals
30
+ factory(window.jQuery);
31
+ }
32
+ }(function ($) {
33
+
34
+
35
+
36
+ // Extend defaults.
37
+ $.extend($.FE.DEFAULTS, {
38
+ helpSets: [
39
+ {
40
+ title: 'Inline Editor',
41
+ commands: [
42
+ { val: 'OSkeyE', desc: 'Show the editor' }
43
+ ]
44
+ },
45
+ {
46
+ title: 'Common actions',
47
+ commands: [
48
+ { val: 'OSkeyC', desc: 'Copy' },
49
+ { val: 'OSkeyX', desc: 'Cut' },
50
+ { val: 'OSkeyV', desc: 'Paste' },
51
+ { val: 'OSkeyZ', desc: 'Undo' },
52
+ { val: 'OSkeyShift+Z', desc: 'Redo' },
53
+ { val: 'OSkeyK', desc: 'Insert Link' },
54
+ { val: 'OSkeyP', desc: 'Insert Image' }
55
+ ]
56
+ },
57
+ {
58
+ title: 'Basic Formatting',
59
+ commands: [
60
+ { val: 'OSkeyA', desc: 'Select All' },
61
+ { val: 'OSkeyB', desc: 'Bold' },
62
+ { val: 'OSkeyI', desc: 'Italic' },
63
+ { val: 'OSkeyU', desc: 'Underline' },
64
+ { val: 'OSkeyS', desc: 'Strikethrough' },
65
+ { val: 'OSkey]', desc: 'Increase Indent' },
66
+ { val: 'OSkey[', desc: 'Decrease Indent' }
67
+ ]
68
+ },
69
+ {
70
+ title: 'Quote',
71
+ commands: [
72
+ { val: 'OSkey\'', desc: 'Increase quote level' },
73
+ { val: 'OSkeyShift+\'', desc: 'Decrease quote level' }
74
+ ]
75
+ },
76
+ {
77
+ title: 'Image / Video',
78
+ commands: [
79
+ { val: 'OSkey+', desc: 'Resize larger' },
80
+ { val: 'OSkey-', desc: 'Resize smaller' }
81
+ ]
82
+ },
83
+ {
84
+ title: 'Table',
85
+ commands: [
86
+ { val: 'Alt+Space', desc: 'Select table cell' },
87
+ { val: 'Shift+Left/Right arrow', desc: 'Extend selection one cell' },
88
+ { val: 'Shift+Up/Down arrow', desc: 'Extend selection one row' }
89
+ ]
90
+ },
91
+ {
92
+ title: 'Navigation',
93
+ commands: [
94
+ { val: 'OSkey/', desc: 'Shortcuts' },
95
+ { val: 'Alt+F10', desc: 'Focus popup / toolbar' },
96
+ { val: 'Esc', desc: 'Return focus to previous position' }
97
+ ]
98
+ }
99
+ ]
100
+ });
101
+
102
+ $.FE.PLUGINS.help = function (editor) {
103
+ var $modal;
104
+ var modal_id = 'help';
105
+
106
+ var $head;
107
+ var $body;
108
+
109
+ /*
110
+ * Init Help.
111
+ */
112
+ function _init () {
113
+
114
+ }
115
+
116
+ /*
117
+ * Build html body.
118
+ */
119
+ function _buildBody () {
120
+
121
+ // Begin body.
122
+ var body = '<div class="fr-help-modal">';
123
+
124
+ for (var i = 0; i < editor.opts.helpSets.length; i++) {
125
+ var set = editor.opts.helpSets[i];
126
+
127
+ // Set shortcuts table.
128
+ // Begin Table.
129
+ var group = '<table>';
130
+
131
+ // Set title.
132
+ group += '<thead><tr><th>' + editor.language.translate(set.title) + '</th></tr></thead>';
133
+ group += '<tbody>';
134
+
135
+ // Build commands table.
136
+ for (var j = 0; j < set.commands.length; j++) {
137
+ var command = set.commands[j];
138
+ group += '<tr>';
139
+
140
+ group += '<td>' + editor.language.translate(command.desc) + '</td>';
141
+ group += '<td>' + command.val.replace('OSkey', editor.helpers.isMac() ? '&#8984;' : 'Ctrl+') + '</td>';
142
+
143
+ group += '</tr>';
144
+ }
145
+
146
+ // End table.
147
+ group += '</tbody></table>';
148
+
149
+ // Append group to body.
150
+ body += group;
151
+ }
152
+
153
+ // End body.
154
+ body += '</div>';
155
+
156
+ return body;
157
+ }
158
+
159
+ /*
160
+ * Show help.
161
+ */
162
+ function show () {
163
+ if (!$modal) {
164
+ var head = '<h4>' + editor.language.translate('Shortcuts') + '</h4>';
165
+ var body = _buildBody();
166
+
167
+ var modalHash = editor.modals.create(modal_id, head, body);
168
+ $modal = modalHash.$modal;
169
+ $head = modalHash.$head;
170
+ $body = modalHash.$body;
171
+
172
+ // Resize help modal on window resize.
173
+ editor.events.$on($(editor.o_win), 'resize', function () {
174
+ editor.modals.resize(modal_id);
175
+ })
176
+ }
177
+
178
+ // Show modal.
179
+ editor.modals.show(modal_id);
180
+
181
+ // Modal may not fit window size.
182
+ editor.modals.resize(modal_id);
183
+ }
184
+
185
+ /*
186
+ * Hide help.
187
+ */
188
+ function hide () {
189
+ editor.modals.hide(modal_id);
190
+ }
191
+
192
+ return {
193
+ _init: _init,
194
+ show: show,
195
+ hide: hide
196
+ };
197
+ };
198
+
199
+ $.FroalaEditor.DefineIcon('help', { NAME: 'question' })
200
+
201
+ $.FE.RegisterShortcut($.FE.KEYCODE.SLASH, 'help', null, '/');
202
+
203
+ $.FE.RegisterCommand('help', {
204
+ title: 'Help',
205
+ icon: 'help',
206
+ undo: false,
207
+ focus: false,
208
+ modal: true,
209
+ callback: function () {
210
+ this.help.show();
211
+ },
212
+ plugin: 'help',
213
+ showOnMobile: false
214
+ });
215
+
216
+ }));
@@ -0,0 +1,7 @@
1
+ /*!
2
+ * froala_editor v2.8.1 (https://www.froala.com/wysiwyg-editor)
3
+ * License https://froala.com/wysiwyg-editor/terms/
4
+ * Copyright 2014-2018 Froala Labs
5
+ */
6
+
7
+ !function(l){"function"==typeof define&&define.amd?define(["jquery"],l):"object"==typeof module&&module.exports?module.exports=function(e,t){return t===undefined&&(t="undefined"!=typeof window?require("jquery"):require("jquery")(e)),l(t)}:l(window.jQuery)}(function(n){n.extend(n.FE.DEFAULTS,{helpSets:[{title:"Inline Editor",commands:[{val:"OSkeyE",desc:"Show the editor"}]},{title:"Common actions",commands:[{val:"OSkeyC",desc:"Copy"},{val:"OSkeyX",desc:"Cut"},{val:"OSkeyV",desc:"Paste"},{val:"OSkeyZ",desc:"Undo"},{val:"OSkeyShift+Z",desc:"Redo"},{val:"OSkeyK",desc:"Insert Link"},{val:"OSkeyP",desc:"Insert Image"}]},{title:"Basic Formatting",commands:[{val:"OSkeyA",desc:"Select All"},{val:"OSkeyB",desc:"Bold"},{val:"OSkeyI",desc:"Italic"},{val:"OSkeyU",desc:"Underline"},{val:"OSkeyS",desc:"Strikethrough"},{val:"OSkey]",desc:"Increase Indent"},{val:"OSkey[",desc:"Decrease Indent"}]},{title:"Quote",commands:[{val:"OSkey'",desc:"Increase quote level"},{val:"OSkeyShift+'",desc:"Decrease quote level"}]},{title:"Image / Video",commands:[{val:"OSkey+",desc:"Resize larger"},{val:"OSkey-",desc:"Resize smaller"}]},{title:"Table",commands:[{val:"Alt+Space",desc:"Select table cell"},{val:"Shift+Left/Right arrow",desc:"Extend selection one cell"},{val:"Shift+Up/Down arrow",desc:"Extend selection one row"}]},{title:"Navigation",commands:[{val:"OSkey/",desc:"Shortcuts"},{val:"Alt+F10",desc:"Focus popup / toolbar"},{val:"Esc",desc:"Return focus to previous position"}]}]}),n.FE.PLUGINS.help=function(s){var o,a="help";return{_init:function(){},show:function(){if(!o){var e="<h4>"+s.language.translate("Shortcuts")+"</h4>",t=function(){for(var e='<div class="fr-help-modal">',t=0;t<s.opts.helpSets.length;t++){var l=s.opts.helpSets[t],o="<table>";o+="<thead><tr><th>"+s.language.translate(l.title)+"</th></tr></thead>",o+="<tbody>";for(var a=0;a<l.commands.length;a++){var n=l.commands[a];o+="<tr>",o+="<td>"+s.language.translate(n.desc)+"</td>",o+="<td>"+n.val.replace("OSkey",s.helpers.isMac()?"&#8984;":"Ctrl+")+"</td>",o+="</tr>"}e+=o+="</tbody></table>"}return e+="</div>"}(),l=s.modals.create(a,e,t);o=l.$modal,l.$head,l.$body,s.events.$on(n(s.o_win),"resize",function(){s.modals.resize(a)})}s.modals.show(a),s.modals.resize(a)},hide:function(){s.modals.hide(a)}}},n.FroalaEditor.DefineIcon("help",{NAME:"question"}),n.FE.RegisterShortcut(n.FE.KEYCODE.SLASH,"help",null,"/"),n.FE.RegisterCommand("help",{title:"Help",icon:"help",undo:!1,focus:!1,modal:!0,callback:function(){this.help.show()},plugin:"help",showOnMobile:!1})});
@@ -0,0 +1,3323 @@
1
+ /*!
2
+ * froala_editor v2.8.1 (https://www.froala.com/wysiwyg-editor)
3
+ * License https://froala.com/wysiwyg-editor/terms/
4
+ * Copyright 2014-2018 Froala Labs
5
+ */
6
+
7
+ (function (factory) {
8
+ if (typeof define === 'function' && define.amd) {
9
+ // AMD. Register as an anonymous module.
10
+ define(['jquery'], factory);
11
+ } else if (typeof module === 'object' && module.exports) {
12
+ // Node/CommonJS
13
+ module.exports = function( root, jQuery ) {
14
+ if ( jQuery === undefined ) {
15
+ // require('jQuery') returns a factory that requires window to
16
+ // build a jQuery instance, we normalize how we use modules
17
+ // that require this pattern but the window provided is a noop
18
+ // if it's defined (how jquery works)
19
+ if ( typeof window !== 'undefined' ) {
20
+ jQuery = require('jquery');
21
+ }
22
+ else {
23
+ jQuery = require('jquery')(root);
24
+ }
25
+ }
26
+ return factory(jQuery);
27
+ };
28
+ } else {
29
+ // Browser globals
30
+ factory(window.jQuery);
31
+ }
32
+ }(function ($) {
33
+
34
+
35
+
36
+
37
+ $.extend($.FE.POPUP_TEMPLATES, {
38
+ 'image.insert': '[_BUTTONS_][_UPLOAD_LAYER_][_BY_URL_LAYER_][_PROGRESS_BAR_]',
39
+ 'image.edit': '[_BUTTONS_]',
40
+ 'image.alt': '[_BUTTONS_][_ALT_LAYER_]',
41
+ 'image.size': '[_BUTTONS_][_SIZE_LAYER_]'
42
+ })
43
+
44
+ $.extend($.FE.DEFAULTS, {
45
+ imageInsertButtons: ['imageBack', '|', 'imageUpload', 'imageByURL'],
46
+ imageEditButtons: ['imageReplace', 'imageAlign', 'imageCaption', 'imageRemove', '|', 'imageLink', 'linkOpen', 'linkEdit', 'linkRemove', '-', 'imageDisplay', 'imageStyle', 'imageAlt', 'imageSize'],
47
+ imageAltButtons: ['imageBack', '|'],
48
+ imageSizeButtons: ['imageBack', '|'],
49
+ imageUpload: true,
50
+ imageUploadURL: 'https://i.froala.com/upload',
51
+ imageCORSProxy: 'https://cors-anywhere.froala.com',
52
+ imageUploadRemoteUrls: true,
53
+ imageUploadParam: 'file',
54
+ imageUploadParams: {},
55
+ imageUploadToS3: false,
56
+ imageUploadMethod: 'POST',
57
+ imageMaxSize: 10 * 1024 * 1024,
58
+ imageAllowedTypes: ['jpeg', 'jpg', 'png', 'gif'],
59
+ imageResize: true,
60
+ imageResizeWithPercent: false,
61
+ imageRoundPercent: false,
62
+ imageDefaultWidth: 300,
63
+ imageDefaultAlign: 'center',
64
+ imageDefaultDisplay: 'block',
65
+ imageSplitHTML: false,
66
+ imageStyles: {
67
+ 'fr-rounded': 'Rounded',
68
+ 'fr-bordered': 'Bordered',
69
+ 'fr-shadow': 'Shadow'
70
+ },
71
+ imageMove: true,
72
+ imageMultipleStyles: true,
73
+ imageTextNear: true,
74
+ imagePaste: true,
75
+ imagePasteProcess: false,
76
+ imageMinWidth: 16,
77
+ imageOutputSize: false,
78
+ imageDefaultMargin: 5
79
+ });
80
+
81
+ $.FE.PLUGINS.image = function (editor) {
82
+ var $current_image;
83
+ var $image_resizer;
84
+ var $handler;
85
+ var $overlay;
86
+ var mousedown = false;
87
+
88
+ var BAD_LINK = 1;
89
+ var MISSING_LINK = 2;
90
+ var ERROR_DURING_UPLOAD = 3;
91
+ var BAD_RESPONSE = 4;
92
+ var MAX_SIZE_EXCEEDED = 5;
93
+ var BAD_FILE_TYPE = 6;
94
+ var NO_CORS_IE = 7;
95
+ var CORRUPTED_IMAGE = 8;
96
+
97
+ var error_messages = {};
98
+ error_messages[BAD_LINK] = 'Image cannot be loaded from the passed link.',
99
+ error_messages[MISSING_LINK] = 'No link in upload response.',
100
+ error_messages[ERROR_DURING_UPLOAD] = 'Error during file upload.',
101
+ error_messages[BAD_RESPONSE] = 'Parsing response failed.',
102
+ error_messages[MAX_SIZE_EXCEEDED] = 'File is too large.',
103
+ error_messages[BAD_FILE_TYPE] = 'Image file type is invalid.',
104
+ error_messages[NO_CORS_IE] = 'Files can be uploaded only to same domain in IE 8 and IE 9.'
105
+ error_messages[CORRUPTED_IMAGE] = 'Image file is corrupted.'
106
+
107
+ /**
108
+ * Refresh the image insert popup.
109
+ */
110
+
111
+ function _refreshInsertPopup() {
112
+ var $popup = editor.popups.get('image.insert');
113
+
114
+ var $url_input = $popup.find('.fr-image-by-url-layer input');
115
+ $url_input.val('');
116
+
117
+ if ($current_image) {
118
+ $url_input.val($current_image.attr('src'));
119
+ }
120
+
121
+ $url_input.trigger('change');
122
+ }
123
+
124
+ /**
125
+ * Show the image upload popup.
126
+ */
127
+
128
+ function showInsertPopup() {
129
+ var $btn = editor.$tb.find('.fr-command[data-cmd="insertImage"]');
130
+
131
+ var $popup = editor.popups.get('image.insert');
132
+
133
+ if (!$popup) $popup = _initInsertPopup();
134
+ hideProgressBar();
135
+
136
+ if (!$popup.hasClass('fr-active')) {
137
+ editor.popups.refresh('image.insert');
138
+ editor.popups.setContainer('image.insert', editor.$tb);
139
+
140
+ if ($btn.is(':visible')) {
141
+ var left = $btn.offset().left + $btn.outerWidth() / 2;
142
+ var top = $btn.offset().top + (editor.opts.toolbarBottom ? 10 : $btn.outerHeight() - 10);
143
+ editor.popups.show('image.insert', left, top, $btn.outerHeight());
144
+ }
145
+ else {
146
+ editor.position.forSelection($popup);
147
+ editor.popups.show('image.insert');
148
+ }
149
+ }
150
+ }
151
+
152
+ /**
153
+ * Show the image edit popup.
154
+ */
155
+
156
+ function _showEditPopup() {
157
+ var $popup = editor.popups.get('image.edit');
158
+
159
+ if (!$popup) $popup = _initEditPopup();
160
+
161
+ if ($popup) {
162
+ var $el = getEl();
163
+
164
+ if (hasCaption()) {
165
+ $el = $el.find('.fr-img-wrap');
166
+ }
167
+
168
+ editor.popups.setContainer('image.edit', editor.$sc);
169
+ editor.popups.refresh('image.edit');
170
+ var left = $el.offset().left + $el.outerWidth() / 2;
171
+ var top = $el.offset().top + $el.outerHeight();
172
+
173
+ editor.popups.show('image.edit', left, top, $el.outerHeight());
174
+ }
175
+ }
176
+
177
+ /**
178
+ * Hide image upload popup.
179
+ */
180
+
181
+ function _hideInsertPopup() {
182
+ hideProgressBar();
183
+ }
184
+
185
+ /**
186
+ * Convert style to classes.
187
+ */
188
+ function _convertStyleToClasses($img) {
189
+ if ($img.parents('.fr-img-caption').length > 0) {
190
+ $img = $img.parents('.fr-img-caption:first');
191
+ }
192
+
193
+ if (!$img.hasClass('fr-dii') && !$img.hasClass('fr-dib')) {
194
+ $img.addClass('fr-fi' + getAlign($img)[0]);
195
+ $img.addClass('fr-di' + getDisplay($img)[0]);
196
+
197
+ // Reset inline style.
198
+ $img.css('margin', '');
199
+ $img.css('float', '');
200
+ $img.css('display', '');
201
+ $img.css('z-index', '');
202
+ $img.css('position', '');
203
+ $img.css('overflow', '');
204
+ $img.css('vertical-align', '');
205
+ }
206
+ }
207
+
208
+ /**
209
+ * Convert classes to style.
210
+ */
211
+ function _convertClassesToStyle($img) {
212
+ if ($img.parents('.fr-img-caption').length > 0) {
213
+ $img = $img.parents('.fr-img-caption:first');
214
+ }
215
+
216
+ var d = $img.hasClass('fr-dib') ? 'block' : $img.hasClass('fr-dii') ? 'inline' : null;
217
+ var a = $img.hasClass('fr-fil') ? 'left' : $img.hasClass('fr-fir') ? 'right' : getAlign($img);
218
+
219
+ _setStyle($img, d, a);
220
+
221
+ $img.removeClass('fr-dib fr-dii fr-fir fr-fil');
222
+ }
223
+
224
+ /**
225
+ * Refresh the image list.
226
+ */
227
+ function _refreshImageList() {
228
+ var images = editor.el.tagName == 'IMG' ? [editor.el] : editor.el.querySelectorAll('img');
229
+
230
+ for (var i = 0; i < images.length; i++) {
231
+ var $img = $(images[i]);
232
+
233
+ if (!editor.opts.htmlUntouched && editor.opts.useClasses) {
234
+ if (editor.opts.imageDefaultAlign || editor.opts.imageDefaultDisplay) {
235
+ _convertStyleToClasses($img);
236
+ }
237
+
238
+ // Do not allow text near image.
239
+ if (!editor.opts.imageTextNear) {
240
+ if ($img.parents('.fr-img-caption').length > 0) {
241
+ $img.parents('.fr-img-caption:first').removeClass('fr-dii').addClass('fr-dib');
242
+ }
243
+ else {
244
+ $img.removeClass('fr-dii').addClass('fr-dib');
245
+ }
246
+ }
247
+ }
248
+ else if (!editor.opts.htmlUntouched && !editor.opts.useClasses) {
249
+ if (editor.opts.imageDefaultAlign || editor.opts.imageDefaultDisplay) {
250
+ _convertClassesToStyle($img);
251
+ }
252
+ }
253
+
254
+ if (editor.opts.iframe) {
255
+ $img.on('load', editor.size.syncIframe);
256
+ }
257
+ }
258
+ }
259
+
260
+ /**
261
+ * Keep images in sync when content changed.
262
+ */
263
+ var images;
264
+
265
+ function _syncImages(loaded) {
266
+
267
+ if (typeof loaded === 'undefined') loaded = true;
268
+
269
+ // Get current images.
270
+ var c_images = Array.prototype.slice.call(editor.el.querySelectorAll('img'));
271
+
272
+ // Current images src.
273
+ var image_srcs = [];
274
+ var i;
275
+
276
+ for (i = 0; i < c_images.length; i++) {
277
+ image_srcs.push(c_images[i].getAttribute('src'));
278
+
279
+ $(c_images[i]).toggleClass('fr-draggable', editor.opts.imageMove);
280
+
281
+ if (c_images[i].getAttribute('class') === '') c_images[i].removeAttribute('class');
282
+
283
+ if (c_images[i].getAttribute('style') === '') c_images[i].removeAttribute('style');
284
+
285
+ if (c_images[i].parentNode && c_images[i].parentNode.parentNode && editor.node.hasClass(c_images[i].parentNode.parentNode, 'fr-img-caption')) {
286
+ var p_node = c_images[i].parentNode.parentNode;
287
+
288
+ if (!editor.browser.mozilla) {
289
+ p_node.setAttribute('contenteditable', false);
290
+ }
291
+
292
+ p_node.setAttribute('draggable', false);
293
+ p_node.classList.add('fr-draggable');
294
+
295
+ var n_node = c_images[i].nextSibling;
296
+
297
+ if (n_node) {
298
+ n_node.setAttribute('contenteditable', true);
299
+ }
300
+ }
301
+ }
302
+
303
+ // Loop previous images and check their src.
304
+ if (images) {
305
+ for (i = 0; i < images.length; i++) {
306
+ if (image_srcs.indexOf(images[i].getAttribute('src')) < 0) {
307
+ editor.events.trigger('image.removed', [$(images[i])]);
308
+ }
309
+ }
310
+ }
311
+
312
+ // Loop new images and see which were not int the old ones.
313
+ if (images && loaded) {
314
+ var old_images_srcs = [];
315
+
316
+ for (i = 0; i < images.length; i++) {
317
+ old_images_srcs.push(images[i].getAttribute('src'));
318
+ }
319
+
320
+ for (i = 0; i < c_images.length; i++) {
321
+ if (old_images_srcs.indexOf(c_images[i].getAttribute('src')) < 0) {
322
+ editor.events.trigger('image.loaded', [$(c_images[i])]);
323
+ }
324
+ }
325
+ }
326
+
327
+ // Current images are the old ones.
328
+ images = c_images;
329
+ }
330
+
331
+ /**
332
+ * Reposition resizer.
333
+ */
334
+
335
+ function _repositionResizer() {
336
+ if (!$image_resizer) _initImageResizer();
337
+
338
+ if (!$current_image) return false;
339
+
340
+ var $container = editor.$wp || editor.$sc;
341
+
342
+ $container.append($image_resizer);
343
+ $image_resizer.data('instance', editor);
344
+
345
+ var wrap_correction_top = $container.scrollTop() - (($container.css('position') != 'static' ? $container.offset().top : 0));
346
+ var wrap_correction_left = $container.scrollLeft() - (($container.css('position') != 'static' ? $container.offset().left : 0));
347
+
348
+ wrap_correction_left -= editor.helpers.getPX($container.css('border-left-width'));
349
+ wrap_correction_top -= editor.helpers.getPX($container.css('border-top-width'));
350
+
351
+ if (editor.$el.is('img') && editor.$sc.is('body')) {
352
+ wrap_correction_top = 0;
353
+ wrap_correction_left = 0;
354
+ }
355
+
356
+ var $el = getEl();
357
+
358
+ if (hasCaption()) {
359
+ $el = $el.find('.fr-img-wrap');
360
+ }
361
+
362
+ $image_resizer
363
+ .css('top', (editor.opts.iframe ? $el.offset().top : $el.offset().top + wrap_correction_top) - 1)
364
+ .css('left', (editor.opts.iframe ? $el.offset().left : $el.offset().left + wrap_correction_left) - 1)
365
+ .css('width', $el.get(0).getBoundingClientRect().width)
366
+ .css('height', $el.get(0).getBoundingClientRect().height)
367
+ .addClass('fr-active');
368
+ }
369
+
370
+ /**
371
+ * Create resize handler.
372
+ */
373
+
374
+ function _getHandler(pos) {
375
+
376
+ return '<div class="fr-handler fr-h' + pos + '"></div>';
377
+ }
378
+
379
+ /**
380
+ * Set the image with
381
+ */
382
+ function _setWidth(width) {
383
+ if (hasCaption()) {
384
+ $current_image.parents('.fr-img-caption').css('width', width);
385
+ }
386
+ else {
387
+ $current_image.css('width', width);
388
+ }
389
+ }
390
+
391
+ /**
392
+ * Mouse down to start resize.
393
+ */
394
+ function _handlerMousedown(e) {
395
+ // Check if resizer belongs to current instance.
396
+ if (!editor.core.sameInstance($image_resizer)) return true;
397
+
398
+ e.preventDefault();
399
+ e.stopPropagation();
400
+
401
+ if (editor.$el.find('img.fr-error').left) return false;
402
+
403
+ if (!editor.undo.canDo()) editor.undo.saveStep();
404
+
405
+ // Get offset.
406
+ var start_x = e.pageX || e.originalEvent.touches[0].pageX;
407
+
408
+ // Only on mousedown. This function could be called from keydown on accessibility.
409
+ if (e.type == 'mousedown') {
410
+ // See if the entire editor is inside iframe to adjust starting offset.
411
+ var oel = editor.$oel.get(0);
412
+ var doc = oel.ownerDocument;
413
+ var win = doc.defaultView || doc.parentWindow;
414
+ var editor_inside_iframe = false;
415
+
416
+ try {
417
+ editor_inside_iframe = (win.location != win.parent.location && !(win.$ && win.$.FE));
418
+ }
419
+ catch (ex) {}
420
+
421
+ if (editor_inside_iframe && win.frameElement) {
422
+ start_x += editor.helpers.getPX($(win.frameElement).offset().left) + win.frameElement.clientLeft;
423
+ }
424
+ }
425
+
426
+ $handler = $(this);
427
+ $handler.data('start-x', start_x);
428
+ $handler.data('start-width', $current_image.width());
429
+ $handler.data('start-height', $current_image.height());
430
+
431
+ // Set current width.
432
+ var width = $current_image.width();
433
+
434
+ // Update width value if resizing with percent.
435
+ if (editor.opts.imageResizeWithPercent) {
436
+ var p_node = $current_image.parentsUntil(editor.$el, editor.html.blockTagsQuery()).get(0) || editor.el;
437
+ width = (width / $(p_node).outerWidth() * 100).toFixed(2) + '%';
438
+ }
439
+
440
+ // Set the image width.
441
+ _setWidth(width);
442
+
443
+ $overlay.show();
444
+
445
+ editor.popups.hideAll();
446
+
447
+ _unmarkExit();
448
+ }
449
+
450
+ /**
451
+ * Do resize.
452
+ */
453
+ function _handlerMousemove(e) {
454
+ // Check if resizer belongs to current instance.
455
+ if (!editor.core.sameInstance($image_resizer)) return true;
456
+ var real_image_size;
457
+
458
+ if ($handler && $current_image) {
459
+ e.preventDefault()
460
+
461
+ if (editor.$el.find('img.fr-error').left) return false;
462
+
463
+ var c_x = e.pageX || (e.originalEvent.touches ? e.originalEvent.touches[0].pageX : null);
464
+
465
+ if (!c_x) return false;
466
+
467
+ var s_x = $handler.data('start-x');
468
+ var diff_x = c_x - s_x;
469
+ var width = $handler.data('start-width');
470
+
471
+ if ($handler.hasClass('fr-hnw') || $handler.hasClass('fr-hsw')) {
472
+ diff_x = 0 - diff_x;
473
+ }
474
+
475
+ if (editor.opts.imageResizeWithPercent) {
476
+ var p_node = $current_image.parentsUntil(editor.$el, editor.html.blockTagsQuery()).get(0) || editor.el;
477
+ width = ((width + diff_x) / $(p_node).outerWidth() * 100).toFixed(2);
478
+
479
+ if (editor.opts.imageRoundPercent) width = Math.round(width);
480
+
481
+ // Set the image width.
482
+ _setWidth(width + '%')
483
+
484
+ // Get the real image width after resize.
485
+ if (hasCaption()) {
486
+ real_image_size = (editor.helpers.getPX($current_image.parents('.fr-img-caption').css('width')) / $(p_node).outerWidth() * 100).toFixed(2);
487
+ }
488
+ else {
489
+ real_image_size = (editor.helpers.getPX($current_image.css('width')) / $(p_node).outerWidth() * 100).toFixed(2);
490
+ }
491
+
492
+ // If the width is not contained within editor use the real image size.
493
+ if (real_image_size !== width && !editor.opts.imageRoundPercent) {
494
+ _setWidth(real_image_size + '%')
495
+ }
496
+
497
+ $current_image.css('height', '').removeAttr('height');
498
+ }
499
+
500
+ else {
501
+ if (width + diff_x >= editor.opts.imageMinWidth) {
502
+ // Set width for image parent node as well.
503
+ _setWidth(width + diff_x)
504
+
505
+ // Get the real image width after resize.
506
+ if (hasCaption()) {
507
+ real_image_size = editor.helpers.getPX($current_image.parents('.fr-img-caption').css('width'));
508
+ }
509
+ else {
510
+ real_image_size = editor.helpers.getPX($current_image.css('width'));
511
+ }
512
+ }
513
+
514
+ // If the width is not contained within editor use the real image size.
515
+ if (real_image_size !== width + diff_x) {
516
+ _setWidth(real_image_size)
517
+ }
518
+
519
+ // https://github.com/froala/wysiwyg-editor/issues/1963.
520
+ if (($current_image.attr('style') || '').match(/(^height:)|(; *height:)/) || $current_image.attr('height')) {
521
+ $current_image.css('height', $handler.data('start-height') * $current_image.width() / $handler.data('start-width'));
522
+ $current_image.removeAttr('height');
523
+ }
524
+ }
525
+
526
+ _repositionResizer();
527
+
528
+ editor.events.trigger('image.resize', [get()]);
529
+ }
530
+ }
531
+
532
+ /**
533
+ * Stop resize.
534
+ */
535
+
536
+ function _handlerMouseup(e) {
537
+
538
+ // Check if resizer belongs to current instance.
539
+ if (!editor.core.sameInstance($image_resizer)) return true;
540
+
541
+ if ($handler && $current_image) {
542
+ if (e) e.stopPropagation();
543
+
544
+ if (editor.$el.find('img.fr-error').left) return false;
545
+
546
+ $handler = null;
547
+ $overlay.hide();
548
+ _repositionResizer();
549
+ _showEditPopup();
550
+
551
+ editor.undo.saveStep();
552
+
553
+ editor.events.trigger('image.resizeEnd', [get()]);
554
+ }
555
+ }
556
+
557
+ /**
558
+ * Throw an image error.
559
+ */
560
+
561
+ function _throwError(code, response, $img) {
562
+ editor.edit.on();
563
+
564
+ if ($current_image) $current_image.addClass('fr-error');
565
+ _showErrorMessage(editor.language.translate('Something went wrong. Please try again.'));
566
+
567
+ // Remove image if it exists.
568
+ if (!$current_image && $img) remove($img);
569
+
570
+ editor.events.trigger('image.error', [{
571
+ code: code,
572
+ message: error_messages[code]
573
+ },
574
+ response,
575
+ $img
576
+ ]);
577
+ }
578
+
579
+ /**
580
+ * Init the image edit popup.
581
+ */
582
+
583
+ function _initEditPopup(delayed) {
584
+ if (delayed) {
585
+ if (editor.$wp) {
586
+ editor.events.$on(editor.$wp, 'scroll', function () {
587
+ if ($current_image && editor.popups.isVisible('image.edit')) {
588
+ editor.events.disableBlur();
589
+ _editImg($current_image);
590
+ }
591
+ });
592
+ }
593
+
594
+ return true;
595
+ }
596
+
597
+ // Image buttons.
598
+ var image_buttons = '';
599
+
600
+ if (editor.opts.imageEditButtons.length > 0) {
601
+ image_buttons += '<div class="fr-buttons">';
602
+ image_buttons += editor.button.buildList(editor.opts.imageEditButtons);
603
+ image_buttons += '</div>';
604
+
605
+ var template = {
606
+ buttons: image_buttons
607
+ };
608
+
609
+ var $popup = editor.popups.create('image.edit', template);
610
+
611
+ return $popup;
612
+ }
613
+
614
+ return false;
615
+ }
616
+
617
+ /**
618
+ * Show progress bar.
619
+ */
620
+
621
+ function showProgressBar(no_message) {
622
+ var $popup = editor.popups.get('image.insert');
623
+
624
+ if (!$popup) $popup = _initInsertPopup();
625
+
626
+ $popup.find('.fr-layer.fr-active').removeClass('fr-active').addClass('fr-pactive');
627
+ $popup.find('.fr-image-progress-bar-layer').addClass('fr-active');
628
+ $popup.find('.fr-buttons').hide();
629
+
630
+ if ($current_image) {
631
+ var $el = getEl();
632
+
633
+ editor.popups.setContainer('image.insert', editor.$sc);
634
+ var left = $el.offset().left + $el.width() / 2;
635
+ var top = $el.offset().top + $el.height();
636
+
637
+ editor.popups.show('image.insert', left, top, $el.outerHeight());
638
+ }
639
+
640
+ if (typeof no_message == 'undefined') {
641
+ _setProgressMessage(editor.language.translate('Uploading'), 0);
642
+ }
643
+ }
644
+
645
+ /**
646
+ * Hide progress bar.
647
+ */
648
+ function hideProgressBar(dismiss) {
649
+ var $popup = editor.popups.get('image.insert');
650
+
651
+ if ($popup) {
652
+ $popup.find('.fr-layer.fr-pactive').addClass('fr-active').removeClass('fr-pactive');
653
+ $popup.find('.fr-image-progress-bar-layer').removeClass('fr-active');
654
+ $popup.find('.fr-buttons').show();
655
+
656
+ // Dismiss error message.
657
+ if (dismiss || editor.$el.find('img.fr-error').length) {
658
+ editor.events.focus();
659
+
660
+ if (editor.$el.find('img.fr-error').length) {
661
+ editor.$el.find('img.fr-error').remove();
662
+ editor.undo.saveStep();
663
+ editor.undo.run();
664
+ editor.undo.dropRedo();
665
+ }
666
+
667
+ if (!editor.$wp && $current_image) {
668
+ var $img = $current_image;
669
+ _exitEdit(true);
670
+ editor.selection.setAfter($img.get(0));
671
+ editor.selection.restore();
672
+ }
673
+ editor.popups.hide('image.insert');
674
+ }
675
+ }
676
+ }
677
+
678
+ /**
679
+ * Set a progress message.
680
+ */
681
+
682
+ function _setProgressMessage(message, progress) {
683
+ var $popup = editor.popups.get('image.insert');
684
+
685
+ if ($popup) {
686
+ var $layer = $popup.find('.fr-image-progress-bar-layer');
687
+ $layer.find('h3').text(message + (progress ? ' ' + progress + '%' : ''));
688
+
689
+ $layer.removeClass('fr-error');
690
+
691
+ if (progress) {
692
+ $layer.find('div').removeClass('fr-indeterminate');
693
+ $layer.find('div > span').css('width', progress + '%');
694
+ }
695
+ else {
696
+ $layer.find('div').addClass('fr-indeterminate');
697
+ }
698
+ }
699
+ }
700
+
701
+ /**
702
+ * Show error message to the user.
703
+ */
704
+
705
+ function _showErrorMessage(message) {
706
+ showProgressBar();
707
+ var $popup = editor.popups.get('image.insert');
708
+ var $layer = $popup.find('.fr-image-progress-bar-layer');
709
+ $layer.addClass('fr-error');
710
+ var $message_header = $layer.find('h3');
711
+ $message_header.text(message);
712
+ editor.events.disableBlur();
713
+ $message_header.focus();
714
+ }
715
+
716
+ /**
717
+ * Insert image using URL callback.
718
+ */
719
+
720
+ function insertByURL() {
721
+ var $popup = editor.popups.get('image.insert');
722
+ var $input = $popup.find('.fr-image-by-url-layer input');
723
+
724
+ if ($input.val().length > 0) {
725
+ showProgressBar();
726
+ _setProgressMessage(editor.language.translate('Loading image'));
727
+
728
+ var img_url = $input.val();
729
+
730
+ // Upload images if we should upload them.
731
+ if (editor.opts.imageUploadRemoteUrls && editor.opts.imageCORSProxy && editor.opts.imageUpload) {
732
+ var xhr = new XMLHttpRequest();
733
+ xhr.onload = function () {
734
+
735
+ if (this.status == 200) {
736
+
737
+ upload([new Blob([this.response], {
738
+ type: this.response.type || 'image/png'
739
+ })], $current_image);
740
+ }
741
+ else {
742
+ _throwError(BAD_LINK);
743
+ }
744
+ };
745
+
746
+ // If image couldn't be uploaded, insert as it is.
747
+ xhr.onerror = function () {
748
+ insert(img_url, true, [], $current_image);
749
+ }
750
+
751
+ xhr.open('GET', editor.opts.imageCORSProxy + '/' + img_url, true);
752
+ xhr.responseType = 'blob';
753
+
754
+ xhr.send();
755
+ }
756
+
757
+ else {
758
+ insert(img_url, true, [], $current_image);
759
+ }
760
+
761
+ $input.val('');
762
+ $input.blur();
763
+ }
764
+ }
765
+
766
+ function _editImg($img) {
767
+ _edit.call($img.get(0));
768
+ }
769
+
770
+ function _loadedCallback() {
771
+ var $img = $(this);
772
+
773
+ editor.popups.hide('image.insert');
774
+
775
+ $img.removeClass('fr-uploading');
776
+
777
+ // Select the image.
778
+ if ($img.next().is('br')) {
779
+ $img.next().remove();
780
+ }
781
+
782
+ _editImg($img);
783
+
784
+ editor.events.trigger('image.loaded', [$img]);
785
+ }
786
+
787
+ /**
788
+ * Insert image into the editor.
789
+ */
790
+
791
+ function insert(link, sanitize, data, $existing_img, response) {
792
+ editor.edit.off();
793
+ _setProgressMessage(editor.language.translate('Loading image'));
794
+
795
+ if (sanitize) link = editor.helpers.sanitizeURL(link);
796
+
797
+ var image = new Image();
798
+
799
+ image.onload = function () {
800
+ var $img;
801
+ var attr;
802
+
803
+ if ($existing_img) {
804
+ if (!editor.undo.canDo() && !$existing_img.hasClass('fr-uploading')) editor.undo.saveStep();
805
+
806
+ var old_src = $existing_img.data('fr-old-src');
807
+
808
+ if ($existing_img.data('fr-image-pasted')) {
809
+ old_src = null;
810
+ }
811
+
812
+ if (editor.$wp) {
813
+
814
+ // Clone existing image.
815
+ $img = $existing_img.clone()
816
+ .removeData('fr-old-src')
817
+ .removeClass('fr-uploading')
818
+ .removeAttr('data-fr-image-pasted');
819
+
820
+ // Remove load event.
821
+ $img.off('load');
822
+
823
+ // Set new SRC.
824
+ if (old_src) $existing_img.attr('src', old_src);
825
+
826
+ // Replace existing image with its clone.
827
+ $existing_img.replaceWith($img);
828
+
829
+ }
830
+ else {
831
+ $img = $existing_img;
832
+ }
833
+
834
+ // Remove old data.
835
+ var atts = $img.get(0).attributes;
836
+
837
+ for (var i = 0; i < atts.length; i++) {
838
+ var att = atts[i];
839
+
840
+ if (att.nodeName.indexOf('data-') === 0) {
841
+ $img.removeAttr(att.nodeName);
842
+ }
843
+ }
844
+
845
+ // Set new data.
846
+ if (typeof data != 'undefined') {
847
+ for (attr in data) {
848
+ if (data.hasOwnProperty(attr)) {
849
+ if (attr != 'link') {
850
+ $img.attr('data-' + attr, data[attr]);
851
+ }
852
+ }
853
+ }
854
+ }
855
+
856
+ $img.on('load', _loadedCallback);
857
+ $img.attr('src', link);
858
+ editor.edit.on();
859
+ _syncImages(false);
860
+ editor.undo.saveStep();
861
+
862
+ // Cursor will not appear if we don't make blur.
863
+ editor.events.disableBlur();
864
+ editor.$el.blur();
865
+ editor.events.trigger(old_src ? 'image.replaced' : 'image.inserted', [$img, response]);
866
+ }
867
+ else {
868
+ $img = _addImage(link, data, _loadedCallback);
869
+ _syncImages(false);
870
+ editor.undo.saveStep();
871
+
872
+ // Cursor will not appear if we don't make blur.
873
+ editor.$el.blur();
874
+ editor.events.trigger('image.inserted', [$img, response]);
875
+ }
876
+ }
877
+
878
+ image.onerror = function () {
879
+ _throwError(BAD_LINK);
880
+ }
881
+
882
+ showProgressBar(editor.language.translate('Loading image'));
883
+
884
+ image.src = link;
885
+ }
886
+
887
+ /**
888
+ * Parse image response.
889
+ */
890
+
891
+ function _parseResponse(response) {
892
+ try {
893
+ if (editor.events.trigger('image.uploaded', [response], true) === false) {
894
+ editor.edit.on();
895
+
896
+ return false;
897
+ }
898
+ var resp = JSON.parse(response);
899
+
900
+ if (resp.link) {
901
+
902
+ return resp;
903
+ }
904
+ else {
905
+
906
+ // No link in upload request.
907
+ _throwError(MISSING_LINK, response);
908
+
909
+ return false;
910
+ }
911
+ }
912
+ catch (ex) {
913
+
914
+ // Bad response.
915
+ _throwError(BAD_RESPONSE, response);
916
+
917
+ return false;
918
+ }
919
+ }
920
+
921
+ /**
922
+ * Parse image response.
923
+ */
924
+
925
+ function _parseXMLResponse(response) {
926
+ try {
927
+ var link = $(response).find('Location').text();
928
+ var key = $(response).find('Key').text();
929
+
930
+ if (editor.events.trigger('image.uploadedToS3', [link, key, response], true) === false) {
931
+ editor.edit.on();
932
+
933
+ return false;
934
+ }
935
+
936
+ return link;
937
+ }
938
+ catch (ex) {
939
+
940
+ // Bad response.
941
+ _throwError(BAD_RESPONSE, response);
942
+
943
+ return false;
944
+ }
945
+ }
946
+
947
+ /**
948
+ * Image was uploaded to the server and we have a response.
949
+ */
950
+
951
+ function _imageUploaded($img) {
952
+ _setProgressMessage(editor.language.translate('Loading image'));
953
+ var status = this.status;
954
+ var response = this.response;
955
+ var responseXML = this.responseXML;
956
+ var responseText = this.responseText;
957
+
958
+ try {
959
+ if (editor.opts.imageUploadToS3) {
960
+ if (status == 201) {
961
+ var link = _parseXMLResponse(responseXML);
962
+
963
+ if (link) {
964
+ insert(link, false, [], $img, response || responseXML);
965
+ }
966
+ }
967
+ else {
968
+ _throwError(BAD_RESPONSE, response || responseXML, $img);
969
+ }
970
+ }
971
+ else {
972
+ if (status >= 200 && status < 300) {
973
+ var resp = _parseResponse(responseText);
974
+
975
+ if (resp) {
976
+ insert(resp.link, false, resp, $img, response || responseText);
977
+ }
978
+ }
979
+ else {
980
+ _throwError(ERROR_DURING_UPLOAD, response || responseText, $img);
981
+ }
982
+ }
983
+ }
984
+ catch (ex) {
985
+
986
+ // Bad response.
987
+ _throwError(BAD_RESPONSE, response || responseText, $img);
988
+ }
989
+ }
990
+
991
+ /**
992
+ * Image upload error.
993
+ */
994
+
995
+ function _imageUploadError() {
996
+ _throwError(BAD_RESPONSE, this.response || this.responseText || this.responseXML);
997
+ }
998
+
999
+ /**
1000
+ * Image upload progress.
1001
+ */
1002
+
1003
+ function _imageUploadProgress(e) {
1004
+ if (e.lengthComputable) {
1005
+ var complete = (e.loaded / e.total * 100 | 0);
1006
+ _setProgressMessage(editor.language.translate('Uploading'), complete);
1007
+ }
1008
+ }
1009
+
1010
+ function _addImage(link, data, loadCallback) {
1011
+
1012
+ // Build image data string.
1013
+ var data_str = '';
1014
+ var attr;
1015
+
1016
+ if (data && typeof data != 'undefined') {
1017
+ for (attr in data) {
1018
+ if (data.hasOwnProperty(attr)) {
1019
+ if (attr != 'link') {
1020
+ data_str += ' data-' + attr + '="' + data[attr] + '"';
1021
+ }
1022
+ }
1023
+ }
1024
+ }
1025
+
1026
+ var width = editor.opts.imageDefaultWidth;
1027
+
1028
+ if (width && width != 'auto') {
1029
+ width = width + (editor.opts.imageResizeWithPercent ? '%' : 'px');
1030
+ }
1031
+
1032
+ // Create image object and set the load event.
1033
+ var $img = $('<img src="' + link + '"' + data_str + (width ? ' style="width: ' + width + ';"' : '') + '>');
1034
+ _setStyle($img, editor.opts.imageDefaultDisplay, editor.opts.imageDefaultAlign);
1035
+
1036
+ $img.on('load', loadCallback);
1037
+ $img.on('error', function () {
1038
+ $(this).addClass('fr-error');
1039
+ _throwError(CORRUPTED_IMAGE);
1040
+ })
1041
+
1042
+ // Make sure we have focus.
1043
+ // Call the event.
1044
+ editor.edit.on();
1045
+ editor.events.focus(true);
1046
+ editor.selection.restore();
1047
+ editor.undo.saveStep();
1048
+
1049
+ // Insert marker and then replace it with the image.
1050
+ if (editor.opts.imageSplitHTML) {
1051
+ editor.markers.split();
1052
+ }
1053
+ else {
1054
+ editor.markers.insert();
1055
+ }
1056
+
1057
+ editor.html.wrap();
1058
+ var $marker = editor.$el.find('.fr-marker');
1059
+
1060
+ if ($marker.length) {
1061
+
1062
+ // Do not insert image in HR.
1063
+ if ($marker.parent().is('hr')) {
1064
+ $marker.parent().after($marker);
1065
+ }
1066
+
1067
+ // Do not insert image inside emoticon.
1068
+ if (editor.node.isLastSibling($marker) && $marker.parent().hasClass('fr-deletable')) {
1069
+
1070
+ $marker.insertAfter($marker.parent());
1071
+ }
1072
+
1073
+ $marker.replaceWith($img);
1074
+ }
1075
+ else {
1076
+ editor.$el.append($img);
1077
+ }
1078
+
1079
+ editor.selection.clear();
1080
+
1081
+ return $img;
1082
+ }
1083
+
1084
+ /**
1085
+ * Image upload aborted.
1086
+ */
1087
+ function _imageUploadAborted() {
1088
+ editor.edit.on();
1089
+ hideProgressBar(true);
1090
+ }
1091
+
1092
+ /**
1093
+ * Start the uploading process.
1094
+ */
1095
+ function _startUpload(xhr, form_data, image, $image_placeholder) {
1096
+ function _sendRequest() {
1097
+ var $img = $(this);
1098
+ $img.off('load');
1099
+ $img.addClass('fr-uploading');
1100
+
1101
+ if ($img.next().is('br')) {
1102
+ $img.next().remove();
1103
+ }
1104
+
1105
+ editor.placeholder.refresh();
1106
+
1107
+ // Select the image.
1108
+ _editImg($img);
1109
+ _repositionResizer();
1110
+ showProgressBar();
1111
+ editor.edit.off();
1112
+
1113
+ // Set upload events.
1114
+ xhr.onload = function () {
1115
+ _imageUploaded.call(xhr, $img);
1116
+ };
1117
+ xhr.onerror = _imageUploadError;
1118
+ xhr.upload.onprogress = _imageUploadProgress;
1119
+ xhr.onabort = _imageUploadAborted;
1120
+
1121
+ // Set abort event.
1122
+ $img.off('abortUpload').on('abortUpload', function () {
1123
+ if (xhr.readyState != 4) {
1124
+ xhr.abort();
1125
+ }
1126
+ });
1127
+
1128
+ // Send data.
1129
+ xhr.send(form_data);
1130
+ }
1131
+
1132
+ var reader = new FileReader();
1133
+ var $img;
1134
+
1135
+ reader.addEventListener('load', function () {
1136
+ var link = reader.result;
1137
+
1138
+ if (reader.result.indexOf('svg+xml') < 0) {
1139
+
1140
+ // Convert image to local blob.
1141
+ var binary = atob(reader.result.split(',')[1]);
1142
+ var array = [];
1143
+
1144
+ for (var i = 0; i < binary.length; i++) {
1145
+ array.push(binary.charCodeAt(i));
1146
+ }
1147
+
1148
+ // Get local image link.
1149
+ link = window.URL.createObjectURL(new Blob([new Uint8Array(array)], {
1150
+ type: 'image/jpeg'
1151
+ }));
1152
+ }
1153
+
1154
+ // No image.
1155
+ if (!$image_placeholder) {
1156
+ $img = _addImage(link, null, _sendRequest);
1157
+ }
1158
+ else {
1159
+ $image_placeholder.on('load', _sendRequest);
1160
+ $image_placeholder.one('error', function () {
1161
+ $image_placeholder.off('load');
1162
+ $image_placeholder.attr('src', $image_placeholder.data('fr-old-src'));
1163
+ _throwError(CORRUPTED_IMAGE);
1164
+ })
1165
+ editor.edit.on();
1166
+ editor.undo.saveStep();
1167
+ $image_placeholder.data('fr-old-src', $image_placeholder.attr('src'));
1168
+ $image_placeholder.attr('src', link);
1169
+ }
1170
+ }, false);
1171
+
1172
+ reader.readAsDataURL(image);
1173
+ }
1174
+
1175
+ /**
1176
+ * Do image upload.
1177
+ */
1178
+
1179
+ function upload(images, $image_placeholder) {
1180
+
1181
+ // Make sure we have what to upload.
1182
+ if (typeof images != 'undefined' && images.length > 0) {
1183
+
1184
+ // Check if we should cancel the image upload.
1185
+ if (editor.events.trigger('image.beforeUpload', [images, $image_placeholder]) === false) {
1186
+
1187
+ return false;
1188
+ }
1189
+ var image = images[0];
1190
+
1191
+ // Check if there is image name set.
1192
+ if (!image.name) {
1193
+ image.name = (new Date()).getTime() + '.' + (image.type || 'image/jpeg').replace(/image\//g, '')
1194
+ }
1195
+
1196
+ // Check image max size.
1197
+ if (image.size > editor.opts.imageMaxSize) {
1198
+ _throwError(MAX_SIZE_EXCEEDED);
1199
+
1200
+ return false;
1201
+ }
1202
+
1203
+ // Check image types.
1204
+ if (editor.opts.imageAllowedTypes.indexOf(image.type.replace(/image\//g, '')) < 0) {
1205
+ _throwError(BAD_FILE_TYPE);
1206
+
1207
+ return false;
1208
+ }
1209
+
1210
+ // Create form Data.
1211
+ var form_data;
1212
+
1213
+ if (editor.drag_support.formdata) {
1214
+ form_data = editor.drag_support.formdata ? new FormData() : null;
1215
+ }
1216
+
1217
+ // Prepare form data for request.
1218
+ if (form_data) {
1219
+ var key;
1220
+
1221
+ // Upload to S3.
1222
+ if (editor.opts.imageUploadToS3 !== false) {
1223
+ form_data.append('key', editor.opts.imageUploadToS3.keyStart + (new Date()).getTime() + '-' + (image.name || 'untitled'));
1224
+ form_data.append('success_action_status', '201');
1225
+ form_data.append('X-Requested-With', 'xhr');
1226
+ form_data.append('Content-Type', image.type);
1227
+
1228
+ for (key in editor.opts.imageUploadToS3.params) {
1229
+ if (editor.opts.imageUploadToS3.params.hasOwnProperty(key)) {
1230
+ form_data.append(key, editor.opts.imageUploadToS3.params[key]);
1231
+ }
1232
+ }
1233
+ }
1234
+
1235
+ // Add upload params.
1236
+ for (key in editor.opts.imageUploadParams) {
1237
+ if (editor.opts.imageUploadParams.hasOwnProperty(key)) {
1238
+ form_data.append(key, editor.opts.imageUploadParams[key]);
1239
+ }
1240
+ }
1241
+
1242
+ // Set the image in the request.
1243
+ form_data.append(editor.opts.imageUploadParam, image, image.name);
1244
+
1245
+ // Create XHR request.
1246
+ var url = editor.opts.imageUploadURL;
1247
+
1248
+ if (editor.opts.imageUploadToS3) {
1249
+ if (editor.opts.imageUploadToS3.uploadURL) {
1250
+ url = editor.opts.imageUploadToS3.uploadURL;
1251
+ }
1252
+ else {
1253
+ url = 'https://' + editor.opts.imageUploadToS3.region + '.amazonaws.com/' + editor.opts.imageUploadToS3.bucket;
1254
+ }
1255
+ }
1256
+ var xhr = editor.core.getXHR(url, editor.opts.imageUploadMethod);
1257
+ _startUpload(xhr, form_data, image, $image_placeholder || $current_image);
1258
+ }
1259
+ }
1260
+ }
1261
+
1262
+ /**
1263
+ * Image drop inside the upload zone.
1264
+ */
1265
+
1266
+ function _bindInsertEvents($popup) {
1267
+
1268
+ // Drag over the dropable area.
1269
+ editor.events.$on($popup, 'dragover dragenter', '.fr-image-upload-layer', function () {
1270
+ $(this).addClass('fr-drop');
1271
+
1272
+ return false;
1273
+ }, true);
1274
+
1275
+ // Drag end.
1276
+ editor.events.$on($popup, 'dragleave dragend', '.fr-image-upload-layer', function () {
1277
+ $(this).removeClass('fr-drop');
1278
+
1279
+ return false;
1280
+ }, true);
1281
+
1282
+ // Drop.
1283
+ editor.events.$on($popup, 'drop', '.fr-image-upload-layer', function (e) {
1284
+ e.preventDefault();
1285
+ e.stopPropagation();
1286
+ $(this).removeClass('fr-drop');
1287
+ var dt = e.originalEvent.dataTransfer;
1288
+
1289
+ if (dt && dt.files) {
1290
+ var inst = $popup.data('instance') || editor;
1291
+ inst.events.disableBlur();
1292
+ inst.image.upload(dt.files);
1293
+ inst.events.enableBlur();
1294
+ }
1295
+ }, true);
1296
+
1297
+ if (editor.helpers.isIOS()) {
1298
+ editor.events.$on($popup, 'touchstart', '.fr-image-upload-layer input[type="file"]', function () {
1299
+ $(this).trigger('click');
1300
+ }, true);
1301
+ }
1302
+
1303
+ editor.events.$on($popup, 'change', '.fr-image-upload-layer input[type="file"]', function () {
1304
+ if (this.files) {
1305
+ var inst = $popup.data('instance') || editor;
1306
+
1307
+ inst.events.disableBlur();
1308
+ $popup.find('input:focus').blur();
1309
+ inst.events.enableBlur();
1310
+
1311
+ inst.image.upload(this.files, $current_image);
1312
+ }
1313
+
1314
+ // Else IE 9 case.
1315
+ // Chrome fix.
1316
+ $(this).val('');
1317
+ }, true);
1318
+ }
1319
+
1320
+ function _beforeElementDrop($el) {
1321
+ if ($el.is('img') && $el.parents('.fr-img-caption').length > 0) {
1322
+ return $el.parents('.fr-img-caption');
1323
+ }
1324
+ }
1325
+
1326
+ function _drop(e) {
1327
+
1328
+ // Check if we are dropping files.
1329
+ var dt = e.originalEvent.dataTransfer;
1330
+
1331
+ if (dt && dt.files && dt.files.length) {
1332
+ var img = dt.files[0];
1333
+
1334
+ if (img && img.type && img.type.indexOf('image') !== -1 && editor.opts.imageAllowedTypes.indexOf(img.type.replace(/image\//g, '')) >= 0) {
1335
+ if (!editor.opts.imageUpload) {
1336
+ e.preventDefault();
1337
+ e.stopPropagation();
1338
+
1339
+ return false;
1340
+ }
1341
+
1342
+ editor.markers.remove();
1343
+ editor.markers.insertAtPoint(e.originalEvent);
1344
+
1345
+ editor.$el.find('.fr-marker').replaceWith($.FE.MARKERS);
1346
+
1347
+ if (editor.$el.find('.fr-marker').length === 0) {
1348
+ editor.selection.setAtEnd(editor.el);
1349
+ }
1350
+
1351
+ // Hide popups.
1352
+ editor.popups.hideAll();
1353
+
1354
+ // Show the image insert popup.
1355
+ var $popup = editor.popups.get('image.insert');
1356
+
1357
+ if (!$popup) $popup = _initInsertPopup();
1358
+ editor.popups.setContainer('image.insert', editor.$sc);
1359
+
1360
+ var left = e.originalEvent.pageX;
1361
+ var top = e.originalEvent.pageY;
1362
+
1363
+ if (editor.opts.iframe) {
1364
+ top += editor.$iframe.offset().top;
1365
+ left += editor.$iframe.offset().left;
1366
+ }
1367
+
1368
+ editor.popups.show('image.insert', left, top);
1369
+ showProgressBar();
1370
+
1371
+ // Dropped file is an image that we allow.
1372
+ if (editor.opts.imageAllowedTypes.indexOf(img.type.replace(/image\//g, '')) >= 0) {
1373
+
1374
+ // Image might be selected.
1375
+ _exitEdit(true);
1376
+
1377
+ // Upload images.
1378
+ upload(dt.files);
1379
+ }
1380
+ else {
1381
+ _throwError(BAD_FILE_TYPE);
1382
+ }
1383
+
1384
+ // Cancel anything else.
1385
+ e.preventDefault();
1386
+ e.stopPropagation();
1387
+
1388
+ return false;
1389
+ }
1390
+ }
1391
+ }
1392
+
1393
+ function _initEvents() {
1394
+
1395
+ // Mouse down on image. It might start move.
1396
+ editor.events.$on(editor.$el, editor._mousedown, editor.el.tagName == 'IMG' ? null : 'img:not([contenteditable="false"])', function (e) {
1397
+ if ($(this).parents('[contenteditable]:not(.fr-element):not(.fr-img-caption):not(body):first').attr('contenteditable') == 'false') return true;
1398
+
1399
+ if (!editor.helpers.isMobile()) editor.selection.clear();
1400
+
1401
+ mousedown = true;
1402
+
1403
+ if (editor.popups.areVisible()) editor.events.disableBlur();
1404
+
1405
+ // Prevent the image resizing.
1406
+ if (editor.browser.msie) {
1407
+ editor.events.disableBlur();
1408
+ editor.$el.attr('contenteditable', false);
1409
+ }
1410
+
1411
+ if (!editor.draggable && e.type != 'touchstart') e.preventDefault();
1412
+
1413
+ e.stopPropagation();
1414
+ });
1415
+
1416
+ // Mouse up on an image prevent move.
1417
+ editor.events.$on(editor.$el, editor._mouseup, editor.el.tagName == 'IMG' ? null : 'img:not([contenteditable="false"])', function (e) {
1418
+ if ($(this).parents('[contenteditable]:not(.fr-element):not(.fr-img-caption):not(body):first').attr('contenteditable') == 'false') return true;
1419
+
1420
+ if (mousedown) {
1421
+ mousedown = false;
1422
+
1423
+ // Remove moving class.
1424
+ e.stopPropagation();
1425
+
1426
+ if (editor.browser.msie) {
1427
+ editor.$el.attr('contenteditable', true);
1428
+ editor.events.enableBlur();
1429
+ }
1430
+ }
1431
+ });
1432
+
1433
+ // Show image popup when it was selected.
1434
+ editor.events.on('keyup', function (e) {
1435
+ if (e.shiftKey && editor.selection.text().replace(/\n/g, '') === '' && editor.keys.isArrow(e.which)) {
1436
+ var s_el = editor.selection.element();
1437
+ var e_el = editor.selection.endElement();
1438
+
1439
+ if (s_el && s_el.tagName == 'IMG') {
1440
+ _editImg($(s_el));
1441
+ }
1442
+ else if (e_el && e_el.tagName == 'IMG') {
1443
+ _editImg($(e_el));
1444
+ }
1445
+ }
1446
+ }, true);
1447
+
1448
+ // Drop inside the editor.
1449
+ editor.events.on('drop', _drop);
1450
+ editor.events.on('element.beforeDrop', _beforeElementDrop);
1451
+
1452
+ editor.events.on('mousedown window.mousedown', _markExit);
1453
+ editor.events.on('window.touchmove', _unmarkExit);
1454
+
1455
+ editor.events.on('mouseup window.mouseup', function () {
1456
+ if ($current_image) {
1457
+ _exitEdit();
1458
+
1459
+ return false;
1460
+ }
1461
+
1462
+ _unmarkExit();
1463
+ });
1464
+ editor.events.on('commands.mousedown', function ($btn) {
1465
+ if ($btn.parents('.fr-toolbar').length > 0) {
1466
+ _exitEdit();
1467
+ }
1468
+ });
1469
+
1470
+ editor.events.on('blur image.hideResizer commands.undo commands.redo element.dropped', function () {
1471
+ mousedown = false;
1472
+ _exitEdit(true);
1473
+ });
1474
+
1475
+ editor.events.on('modals.hide', function () {
1476
+ if ($current_image) {
1477
+ _selectImage();
1478
+ editor.selection.clear();
1479
+ }
1480
+ });
1481
+ }
1482
+
1483
+ /**
1484
+ * Init the image upload popup.
1485
+ */
1486
+
1487
+ function _initInsertPopup(delayed) {
1488
+ if (delayed) {
1489
+ editor.popups.onRefresh('image.insert', _refreshInsertPopup);
1490
+ editor.popups.onHide('image.insert', _hideInsertPopup);
1491
+
1492
+ return true;
1493
+ }
1494
+
1495
+ var active;
1496
+
1497
+ // Image buttons.
1498
+ var image_buttons = '';
1499
+
1500
+ if (!editor.opts.imageUpload) {
1501
+ editor.opts.imageInsertButtons.splice(editor.opts.imageInsertButtons.indexOf('imageUpload'), 1);
1502
+ }
1503
+
1504
+ if (editor.opts.imageInsertButtons.length > 1) {
1505
+ image_buttons = '<div class="fr-buttons">' + editor.button.buildList(editor.opts.imageInsertButtons) + '</div>';
1506
+ }
1507
+
1508
+ var uploadIndex = editor.opts.imageInsertButtons.indexOf('imageUpload');
1509
+ var urlIndex = editor.opts.imageInsertButtons.indexOf('imageByURL');
1510
+
1511
+ // Image upload layer.
1512
+ var upload_layer = '';
1513
+
1514
+ if (uploadIndex >= 0) {
1515
+ active = ' fr-active';
1516
+
1517
+ if (urlIndex >= 0 && uploadIndex > urlIndex) {
1518
+ active = '';
1519
+ }
1520
+
1521
+ upload_layer = '<div class="fr-image-upload-layer' + active + ' fr-layer" id="fr-image-upload-layer-' + editor.id + '"><strong>' + editor.language.translate('Drop image') + '</strong><br>(' + editor.language.translate('or click') + ')<div class="fr-form"><input type="file" accept="image/' + editor.opts.imageAllowedTypes.join(', image/').toLowerCase() + '" tabIndex="-1" aria-labelledby="fr-image-upload-layer-' + editor.id + '" role="button"></div></div>'
1522
+ }
1523
+
1524
+ // Image by url layer.
1525
+ var by_url_layer = '';
1526
+
1527
+ if (urlIndex >= 0) {
1528
+ active = ' fr-active';
1529
+
1530
+ if (uploadIndex >= 0 && urlIndex > uploadIndex) {
1531
+ active = '';
1532
+ }
1533
+
1534
+ by_url_layer = '<div class="fr-image-by-url-layer' + active + ' fr-layer" id="fr-image-by-url-layer-' + editor.id + '"><div class="fr-input-line"><input id="fr-image-by-url-layer-text-' + editor.id + '" type="text" placeholder="http://" tabIndex="1" aria-required="true"></div><div class="fr-action-buttons"><button type="button" class="fr-command fr-submit" data-cmd="imageInsertByURL" tabIndex="2" role="button">' + editor.language.translate('Insert') + '</button></div></div>'
1535
+ }
1536
+
1537
+ // Progress bar.
1538
+ var progress_bar_layer = '<div class="fr-image-progress-bar-layer fr-layer"><h3 tabIndex="-1" class="fr-message">Uploading</h3><div class="fr-loader"><span class="fr-progress"></span></div><div class="fr-action-buttons"><button type="button" class="fr-command fr-dismiss" data-cmd="imageDismissError" tabIndex="2" role="button">OK</button></div></div>';
1539
+
1540
+ var template = {
1541
+ buttons: image_buttons,
1542
+ upload_layer: upload_layer,
1543
+ by_url_layer: by_url_layer,
1544
+ progress_bar: progress_bar_layer
1545
+ }
1546
+
1547
+ // Set the template in the popup.
1548
+ var $popup = editor.popups.create('image.insert', template);
1549
+
1550
+ if (editor.$wp) {
1551
+ editor.events.$on(editor.$wp, 'scroll', function () {
1552
+ if ($current_image && editor.popups.isVisible('image.insert')) {
1553
+ replace();
1554
+ }
1555
+ });
1556
+ }
1557
+
1558
+ _bindInsertEvents($popup);
1559
+
1560
+ return $popup;
1561
+ }
1562
+
1563
+ /**
1564
+ * Refresh the ALT popup.
1565
+ */
1566
+
1567
+ function _refreshAltPopup() {
1568
+ if ($current_image) {
1569
+ var $popup = editor.popups.get('image.alt');
1570
+ $popup.find('input').val($current_image.attr('alt') || '').trigger('change');
1571
+ }
1572
+ }
1573
+
1574
+ /**
1575
+ * Show the ALT popup.
1576
+ */
1577
+
1578
+ function showAltPopup() {
1579
+ var $popup = editor.popups.get('image.alt');
1580
+
1581
+ if (!$popup) $popup = _initAltPopup();
1582
+ hideProgressBar();
1583
+ editor.popups.refresh('image.alt');
1584
+ editor.popups.setContainer('image.alt', editor.$sc);
1585
+
1586
+ var $el = getEl();
1587
+
1588
+ if (hasCaption()) {
1589
+ $el = $el.find('.fr-img-wrap');
1590
+ }
1591
+
1592
+ var left = $el.offset().left + $el.outerWidth() / 2;
1593
+ var top = $el.offset().top + $el.outerHeight();
1594
+
1595
+ editor.popups.show('image.alt', left, top, $el.outerHeight());
1596
+ }
1597
+
1598
+ /**
1599
+ * Init the image upload popup.
1600
+ */
1601
+
1602
+ function _initAltPopup(delayed) {
1603
+ if (delayed) {
1604
+ editor.popups.onRefresh('image.alt', _refreshAltPopup);
1605
+
1606
+ return true;
1607
+ }
1608
+
1609
+ // Image buttons.
1610
+ var image_buttons = '';
1611
+ image_buttons = '<div class="fr-buttons">' + editor.button.buildList(editor.opts.imageAltButtons) + '</div>';
1612
+
1613
+ // Image by url layer.
1614
+ var alt_layer = '';
1615
+ alt_layer = '<div class="fr-image-alt-layer fr-layer fr-active" id="fr-image-alt-layer-' + editor.id + '"><div class="fr-input-line"><input id="fr-image-alt-layer-text-' + editor.id + '" type="text" placeholder="' + editor.language.translate('Alternate Text') + '" tabIndex="1"></div><div class="fr-action-buttons"><button type="button" class="fr-command fr-submit" data-cmd="imageSetAlt" tabIndex="2" role="button">' + editor.language.translate('Update') + '</button></div></div>'
1616
+
1617
+ var template = {
1618
+ buttons: image_buttons,
1619
+ alt_layer: alt_layer
1620
+ }
1621
+
1622
+ // Set the template in the popup.
1623
+ var $popup = editor.popups.create('image.alt', template);
1624
+
1625
+ if (editor.$wp) {
1626
+ editor.events.$on(editor.$wp, 'scroll.image-alt', function () {
1627
+ if ($current_image && editor.popups.isVisible('image.alt')) {
1628
+ showAltPopup();
1629
+ }
1630
+ });
1631
+ }
1632
+
1633
+ return $popup;
1634
+ }
1635
+
1636
+ /**
1637
+ * Set ALT based on the values from the popup.
1638
+ */
1639
+
1640
+ function setAlt(alt) {
1641
+ if ($current_image) {
1642
+ var $popup = editor.popups.get('image.alt');
1643
+ $current_image.attr('alt', alt || $popup.find('input').val() || '');
1644
+ $popup.find('input:focus').blur();
1645
+ _editImg($current_image);
1646
+ }
1647
+ }
1648
+
1649
+ /**
1650
+ * Refresh the size popup.
1651
+ */
1652
+
1653
+ function _refreshSizePopup() {
1654
+ if ($current_image) {
1655
+ var $popup = editor.popups.get('image.size');
1656
+ $popup.find('input[name="width"]').val($current_image.get(0).style.width).trigger('change');
1657
+ $popup.find('input[name="height"]').val($current_image.get(0).style.height).trigger('change');
1658
+ }
1659
+ }
1660
+
1661
+ /**
1662
+ * Show the size popup.
1663
+ */
1664
+
1665
+ function showSizePopup() {
1666
+ var $popup = editor.popups.get('image.size');
1667
+
1668
+ if (!$popup) $popup = _initSizePopup();
1669
+ hideProgressBar();
1670
+ editor.popups.refresh('image.size');
1671
+ editor.popups.setContainer('image.size', editor.$sc);
1672
+
1673
+ var $el = getEl();
1674
+
1675
+ if (hasCaption()) {
1676
+ $el = $el.find('.fr-img-wrap');
1677
+ }
1678
+
1679
+ var left = $el.offset().left + $el.outerWidth() / 2;
1680
+ var top = $el.offset().top + $el.outerHeight();
1681
+
1682
+ editor.popups.show('image.size', left, top, $el.outerHeight());
1683
+ }
1684
+
1685
+ /**
1686
+ * Init the image upload popup.
1687
+ */
1688
+
1689
+ function _initSizePopup(delayed) {
1690
+ if (delayed) {
1691
+ editor.popups.onRefresh('image.size', _refreshSizePopup);
1692
+
1693
+ return true;
1694
+ }
1695
+
1696
+ // Image buttons.
1697
+ var image_buttons = '';
1698
+ image_buttons = '<div class="fr-buttons">' + editor.button.buildList(editor.opts.imageSizeButtons) + '</div>';
1699
+
1700
+ // Size layer.
1701
+ var size_layer = '';
1702
+ size_layer = '<div class="fr-image-size-layer fr-layer fr-active" id="fr-image-size-layer-' + editor.id + '"><div class="fr-image-group"><div class="fr-input-line"><input id="fr-image-size-layer-width-' + editor.id + '" type="text" name="width" placeholder="' + editor.language.translate('Width') + '" tabIndex="1"></div><div class="fr-input-line"><input id="fr-image-size-layer-height' + editor.id + '" type="text" name="height" placeholder="' + editor.language.translate('Height') + '" tabIndex="1"></div></div><div class="fr-action-buttons"><button type="button" class="fr-command fr-submit" data-cmd="imageSetSize" tabIndex="2" role="button">' + editor.language.translate('Update') + '</button></div></div>'
1703
+
1704
+ var template = {
1705
+ buttons: image_buttons,
1706
+ size_layer: size_layer
1707
+ };
1708
+
1709
+ // Set the template in the popup.
1710
+ var $popup = editor.popups.create('image.size', template);
1711
+
1712
+ if (editor.$wp) {
1713
+ editor.events.$on(editor.$wp, 'scroll.image-size', function () {
1714
+ if ($current_image && editor.popups.isVisible('image.size')) {
1715
+ showSizePopup();
1716
+ }
1717
+ });
1718
+ }
1719
+
1720
+ return $popup;
1721
+ }
1722
+
1723
+ /**
1724
+ * Set size based on the current image size.
1725
+ */
1726
+
1727
+ function setSize(width, height) {
1728
+ if ($current_image) {
1729
+ var $popup = editor.popups.get('image.size');
1730
+ width = width || $popup.find('input[name="width"]').val() || '';
1731
+ height = height || $popup.find('input[name="height"]').val() || '';
1732
+ var regex = /^[\d]+((px)|%)*$/g;
1733
+
1734
+ $current_image.removeAttr('width').removeAttr('height');
1735
+
1736
+ if (width.match(regex)) $current_image.css('width', width);
1737
+ else $current_image.css('width', '');
1738
+
1739
+ if (height.match(regex)) $current_image.css('height', height);
1740
+ else $current_image.css('height', '');
1741
+
1742
+ if (hasCaption()) {
1743
+ $current_image.parent().removeAttr('width').removeAttr('height');
1744
+
1745
+ if (width.match(regex)) $current_image.parent().css('width', width);
1746
+ else $current_image.parent().css('width', '');
1747
+
1748
+ if (height.match(regex)) $current_image.parent().css('height', height);
1749
+ else $current_image.parent().css('height', '');
1750
+ }
1751
+
1752
+ $popup.find('input:focus').blur();
1753
+ _editImg($current_image);
1754
+ }
1755
+ }
1756
+
1757
+ /**
1758
+ * Show the image upload layer.
1759
+ */
1760
+
1761
+ function showLayer(name) {
1762
+ var $popup = editor.popups.get('image.insert');
1763
+
1764
+ var left;
1765
+ var top;
1766
+
1767
+ // Click on the button from the toolbar without image selected.
1768
+ if (!$current_image && !editor.opts.toolbarInline) {
1769
+ var $btn = editor.$tb.find('.fr-command[data-cmd="insertImage"]');
1770
+ left = $btn.offset().left + $btn.outerWidth() / 2;
1771
+ top = $btn.offset().top + (editor.opts.toolbarBottom ? 10 : $btn.outerHeight() - 10);
1772
+ }
1773
+
1774
+ // Image is selected.
1775
+ else if ($current_image) {
1776
+
1777
+ var $el = getEl();
1778
+
1779
+ if (hasCaption()) {
1780
+ $el = $el.find('.fr-img-wrap');
1781
+ }
1782
+
1783
+ // Set the top to the bottom of the image.
1784
+ top = $el.offset().top + $el.outerHeight();
1785
+ left = $el.offset().left + $el.outerWidth() / 2;
1786
+ }
1787
+
1788
+ // Image is selected and we are in inline mode.
1789
+ if (!$current_image && editor.opts.toolbarInline) {
1790
+
1791
+ // Set top to the popup top.
1792
+ top = $popup.offset().top - editor.helpers.getPX($popup.css('margin-top'));
1793
+
1794
+ // If the popup is above apply height correction.
1795
+ if ($popup.hasClass('fr-above')) {
1796
+ top += $popup.outerHeight();
1797
+ }
1798
+ }
1799
+
1800
+ // Show the new layer.
1801
+ $popup.find('.fr-layer').removeClass('fr-active');
1802
+ $popup.find('.fr-' + name + '-layer').addClass('fr-active');
1803
+
1804
+ editor.popups.show('image.insert', left, top, ($current_image ? $current_image.outerHeight() : 0));
1805
+ editor.accessibility.focusPopup($popup);
1806
+ }
1807
+
1808
+ /**
1809
+ * Refresh the upload image button.
1810
+ */
1811
+
1812
+ function refreshUploadButton($btn) {
1813
+ var $popup = editor.popups.get('image.insert');
1814
+
1815
+ if ($popup.find('.fr-image-upload-layer').hasClass('fr-active')) {
1816
+ $btn.addClass('fr-active').attr('aria-pressed', true);
1817
+ }
1818
+ }
1819
+
1820
+ /**
1821
+ * Refresh the insert by url button.
1822
+ */
1823
+
1824
+ function refreshByURLButton($btn) {
1825
+ var $popup = editor.popups.get('image.insert');
1826
+
1827
+ if ($popup.find('.fr-image-by-url-layer').hasClass('fr-active')) {
1828
+ $btn.addClass('fr-active').attr('aria-pressed', true);
1829
+ }
1830
+ }
1831
+
1832
+ function _resizeImage(e, initPageX, direction, step) {
1833
+ e.pageX = initPageX;
1834
+ _handlerMousedown.call(this, e);
1835
+ e.pageX = e.pageX + direction * Math.floor(Math.pow(1.1, step));
1836
+ _handlerMousemove.call(this, e);
1837
+ _handlerMouseup.call(this, e);
1838
+
1839
+ return ++step;
1840
+ }
1841
+
1842
+ /**
1843
+ * Init image resizer.
1844
+ */
1845
+ function _initImageResizer() {
1846
+ var doc;
1847
+
1848
+ // No shared image resizer.
1849
+ if (!editor.shared.$image_resizer) {
1850
+
1851
+ // Create shared image resizer.
1852
+ editor.shared.$image_resizer = $('<div class="fr-image-resizer"></div>');
1853
+ $image_resizer = editor.shared.$image_resizer;
1854
+
1855
+ // Bind mousedown event shared.
1856
+ editor.events.$on($image_resizer, 'mousedown', function (e) {
1857
+ e.stopPropagation();
1858
+ }, true);
1859
+
1860
+ // Image resize is enabled.
1861
+ if (editor.opts.imageResize) {
1862
+ $image_resizer.append(_getHandler('nw') + _getHandler('ne') + _getHandler('sw') + _getHandler('se'));
1863
+
1864
+ // Add image resizer overlay and set it.
1865
+ editor.shared.$img_overlay = $('<div class="fr-image-overlay"></div>');
1866
+ $overlay = editor.shared.$img_overlay;
1867
+ doc = $image_resizer.get(0).ownerDocument;
1868
+ $(doc).find('body:first').append($overlay);
1869
+ }
1870
+ }
1871
+ else {
1872
+ $image_resizer = editor.shared.$image_resizer;
1873
+ $overlay = editor.shared.$img_overlay;
1874
+
1875
+ editor.events.on('destroy', function () {
1876
+ $image_resizer.removeClass('fr-active').appendTo($('body:first'));
1877
+ }, true);
1878
+ }
1879
+
1880
+ // Shared destroy.
1881
+ editor.events.on('shared.destroy', function () {
1882
+ $image_resizer.html('').removeData().remove();
1883
+ $image_resizer = null;
1884
+
1885
+ if (editor.opts.imageResize) {
1886
+ $overlay.remove();
1887
+ $overlay = null;
1888
+ }
1889
+ }, true);
1890
+
1891
+ // Window resize. Exit from edit.
1892
+ if (!editor.helpers.isMobile()) {
1893
+ editor.events.$on($(editor.o_win), 'resize', function () {
1894
+ if ($current_image && !$current_image.hasClass('fr-uploading')) {
1895
+ _exitEdit(true);
1896
+ }
1897
+ else if ($current_image) {
1898
+ _repositionResizer();
1899
+ replace();
1900
+ showProgressBar(false);
1901
+ }
1902
+ });
1903
+ }
1904
+
1905
+ // Image resize is enabled.
1906
+ if (editor.opts.imageResize) {
1907
+ doc = $image_resizer.get(0).ownerDocument;
1908
+ editor.events.$on($image_resizer, editor._mousedown, '.fr-handler', _handlerMousedown);
1909
+ editor.events.$on($(doc), editor._mousemove, _handlerMousemove);
1910
+ editor.events.$on($(doc.defaultView || doc.parentWindow), editor._mouseup, _handlerMouseup);
1911
+ editor.events.$on($overlay, 'mouseleave', _handlerMouseup);
1912
+
1913
+ // Accessibility.
1914
+
1915
+ // Used for keys holing.
1916
+ var step = 1;
1917
+ var prevKey = null;
1918
+ var prevTimestamp = 0;
1919
+
1920
+ // Keydown event.
1921
+ editor.events.on('keydown', function (e) {
1922
+ if ($current_image) {
1923
+ var ctrlKey = navigator.userAgent.indexOf('Mac OS X') != -1 ? e.metaKey : e.ctrlKey;
1924
+ var keycode = e.which;
1925
+
1926
+ if (keycode !== prevKey || e.timeStamp - prevTimestamp > 200) {
1927
+ step = 1;
1928
+
1929
+ // Reset step. Known browser issue: Keyup does not trigger when ctrl is pressed.
1930
+ }
1931
+
1932
+ // Increase image size.
1933
+ if ((keycode == $.FE.KEYCODE.EQUALS || (editor.browser.mozilla && keycode == $.FE.KEYCODE.FF_EQUALS)) && ctrlKey && !e.altKey) {
1934
+ step = _resizeImage.call(this, e, 1, 1, step);
1935
+ }
1936
+
1937
+ // Decrease image size.
1938
+ else if ((keycode == $.FE.KEYCODE.HYPHEN || (editor.browser.mozilla && keycode == $.FE.KEYCODE.FF_HYPHEN)) && ctrlKey && !e.altKey) {
1939
+ step = _resizeImage.call(this, e, 2, -1, step);
1940
+ }
1941
+ else if (!editor.keys.ctrlKey(e) && keycode == $.FE.KEYCODE.ENTER) {
1942
+ $current_image.before('<br>');
1943
+ _editImg($current_image);
1944
+ }
1945
+
1946
+ // Save key code.
1947
+ prevKey = keycode;
1948
+
1949
+ // Save timestamp.
1950
+ prevTimestamp = e.timeStamp;
1951
+ }
1952
+ }, true);
1953
+
1954
+ // Reset the step on key up event.
1955
+ editor.events.on('keyup', function () {
1956
+ step = 1;
1957
+ });
1958
+ }
1959
+ }
1960
+
1961
+ /**
1962
+ * Remove the current image.
1963
+ */
1964
+ function remove($img) {
1965
+ $img = $img || getEl();
1966
+
1967
+ if ($img) {
1968
+ if (editor.events.trigger('image.beforeRemove', [$img]) !== false) {
1969
+ editor.popups.hideAll();
1970
+ _selectImage();
1971
+ _exitEdit(true);
1972
+
1973
+ if (!editor.undo.canDo()) editor.undo.saveStep();
1974
+
1975
+ if ($img.get(0) == editor.el) {
1976
+ $img.removeAttr('src');
1977
+ }
1978
+ else {
1979
+ if ($img.get(0).parentNode.tagName == 'A') {
1980
+ editor.selection.setBefore($img.get(0).parentNode) || editor.selection.setAfter($img.get(0).parentNode) || $img.parent().after($.FE.MARKERS);
1981
+ $($img.get(0).parentNode).remove();
1982
+ }
1983
+ else {
1984
+ editor.selection.setBefore($img.get(0)) || editor.selection.setAfter($img.get(0)) || $img.after($.FE.MARKERS);
1985
+ $img.remove();
1986
+ }
1987
+
1988
+ editor.html.fillEmptyBlocks();
1989
+ editor.selection.restore();
1990
+ }
1991
+
1992
+ editor.undo.saveStep();
1993
+ }
1994
+ }
1995
+ }
1996
+
1997
+ function _editorKeydownHandler(e) {
1998
+ var key_code = e.which;
1999
+
2000
+ if ($current_image && (key_code == $.FE.KEYCODE.BACKSPACE || key_code == $.FE.KEYCODE.DELETE)) {
2001
+ e.preventDefault();
2002
+ e.stopPropagation();
2003
+ remove();
2004
+
2005
+ return false;
2006
+ }
2007
+
2008
+ else if ($current_image && key_code == $.FE.KEYCODE.ESC) {
2009
+ var $img = $current_image;
2010
+ _exitEdit(true);
2011
+ editor.selection.setAfter($img.get(0));
2012
+ editor.selection.restore();
2013
+ e.preventDefault();
2014
+
2015
+ return false;
2016
+ }
2017
+
2018
+ // Move cursor if left and right arrows are used.
2019
+ else if ($current_image && (key_code == $.FE.KEYCODE.ARROW_LEFT || key_code == $.FE.KEYCODE.ARROW_RIGHT)) {
2020
+ var img = $current_image.get(0);
2021
+ _exitEdit(true);
2022
+
2023
+ if (key_code == $.FE.KEYCODE.ARROW_LEFT) {
2024
+ editor.selection.setBefore(img);
2025
+ }
2026
+ else {
2027
+ editor.selection.setAfter(img);
2028
+ }
2029
+
2030
+ editor.selection.restore();
2031
+ e.preventDefault();
2032
+
2033
+ return false;
2034
+ }
2035
+
2036
+ else if ($current_image && key_code != $.FE.KEYCODE.F10 && !editor.keys.isBrowserAction(e)) {
2037
+ e.preventDefault();
2038
+ e.stopPropagation();
2039
+
2040
+ return false;
2041
+ }
2042
+ }
2043
+
2044
+ /**
2045
+ * Do some cleanup on images.
2046
+ */
2047
+ function _cleanOnGet(el) {
2048
+
2049
+ // Tag is image.
2050
+ if (el && el.tagName == 'IMG') {
2051
+
2052
+ // Remove element if it has class fr-uploading or fr-error.
2053
+ if (editor.node.hasClass(el, 'fr-uploading') || editor.node.hasClass(el, 'fr-error')) {
2054
+ el.parentNode.removeChild(el);
2055
+ }
2056
+
2057
+ // Remove class if it is draggable.
2058
+ else if (editor.node.hasClass(el, 'fr-draggable')) {
2059
+ el.classList.remove('fr-draggable');
2060
+ }
2061
+
2062
+ if (el.parentNode && el.parentNode.parentNode && editor.node.hasClass(el.parentNode.parentNode, 'fr-img-caption')) {
2063
+ var p_node = el.parentNode.parentNode;
2064
+ p_node.removeAttribute('contenteditable');
2065
+ p_node.removeAttribute('draggable');
2066
+ p_node.classList.remove('fr-draggable');
2067
+
2068
+ var n_node = el.nextSibling;
2069
+
2070
+ if (n_node) {
2071
+ n_node.removeAttribute('contenteditable');
2072
+ }
2073
+ }
2074
+ }
2075
+
2076
+ // Look for inner nodes that might be in a similar case.
2077
+ else if (el && el.nodeType == Node.ELEMENT_NODE) {
2078
+ var imgs = el.querySelectorAll('img.fr-uploading, img.fr-error, img.fr-draggable');
2079
+
2080
+ for (var i = 0; i < imgs.length; i++) {
2081
+ _cleanOnGet(imgs[i]);
2082
+ }
2083
+ }
2084
+ }
2085
+
2086
+ /**
2087
+ * Initialization.
2088
+ */
2089
+ function _init() {
2090
+ _initEvents();
2091
+
2092
+ // Init on image.
2093
+ if (editor.el.tagName == 'IMG') {
2094
+ editor.$el.addClass('fr-view');
2095
+ }
2096
+
2097
+ editor.events.$on(editor.$el, editor.helpers.isMobile() && !editor.helpers.isWindowsPhone() ? 'touchend' : 'click', editor.el.tagName == 'IMG' ? null : 'img:not([contenteditable="false"])', _edit);
2098
+
2099
+ if (editor.helpers.isMobile()) {
2100
+ editor.events.$on(editor.$el, 'touchstart', editor.el.tagName == 'IMG' ? null : 'img:not([contenteditable="false"])', function () {
2101
+ touchScroll = false;
2102
+ })
2103
+
2104
+ editor.events.$on(editor.$el, 'touchmove', function () {
2105
+ touchScroll = true;
2106
+ });
2107
+ }
2108
+
2109
+ if (editor.$wp) {
2110
+ editor.events.on('window.keydown keydown', _editorKeydownHandler, true)
2111
+
2112
+ editor.events.on('keyup', function (e) {
2113
+ if ($current_image && e.which == $.FE.KEYCODE.ENTER) {
2114
+
2115
+ return false;
2116
+ }
2117
+ }, true);
2118
+ }
2119
+ else {
2120
+ editor.events.$on(editor.$win, 'keydown', _editorKeydownHandler);
2121
+ }
2122
+
2123
+ // ESC from accessibility.
2124
+ editor.events.on('toolbar.esc', function () {
2125
+ if ($current_image) {
2126
+ if (editor.$wp) {
2127
+ editor.events.disableBlur();
2128
+ editor.events.focus();
2129
+ }
2130
+ else {
2131
+ var $img = $current_image;
2132
+ _exitEdit(true);
2133
+ editor.selection.setAfter($img.get(0));
2134
+ editor.selection.restore();
2135
+ }
2136
+
2137
+ return false;
2138
+ }
2139
+ }, true);
2140
+
2141
+ // focusEditor from accessibility.
2142
+ editor.events.on('toolbar.focusEditor', function () {
2143
+ if ($current_image) {
2144
+
2145
+ return false;
2146
+ }
2147
+ }, true);
2148
+
2149
+ // Copy/cut image.
2150
+ editor.events.on('window.cut window.copy', function (e) {
2151
+ // Do copy only if image.edit popups is visible and not focused.
2152
+ if ($current_image && editor.popups.isVisible('image.edit') && !editor.popups.get('image.edit').find(':focus').length) {
2153
+
2154
+ var $el = getEl();
2155
+
2156
+ if (hasCaption()) {
2157
+ $el.before($.FE.START_MARKER);
2158
+ $el.after($.FE.END_MARKER);
2159
+ editor.selection.restore();
2160
+ editor.paste.saveCopiedText($el.get(0).outerHTML, $el.text());
2161
+ }
2162
+ else {
2163
+ _selectImage();
2164
+ editor.paste.saveCopiedText($current_image.get(0).outerHTML, $current_image.attr('alt'));
2165
+ }
2166
+
2167
+ if (e.type == 'copy') {
2168
+ setTimeout(function () {
2169
+ _editImg($current_image);
2170
+ });
2171
+ }
2172
+ else {
2173
+ _exitEdit(true);
2174
+ editor.undo.saveStep();
2175
+ setTimeout(function () {
2176
+ editor.undo.saveStep();
2177
+ }, 0);
2178
+ }
2179
+ }
2180
+ }, true);
2181
+
2182
+ // Fix IE copy not working when selection is collapsed.
2183
+ if (editor.browser.msie) {
2184
+ editor.events.on('keydown', function (e) {
2185
+ // Selection is collapsed and we have an image.
2186
+ if (!(editor.selection.isCollapsed() && $current_image)) return true;
2187
+
2188
+ var key_code = e.which;
2189
+
2190
+ // Copy.
2191
+ if (key_code == $.FE.KEYCODE.C && editor.keys.ctrlKey(e)) {
2192
+ editor.events.trigger('window.copy');
2193
+ }
2194
+
2195
+ // Cut.
2196
+ else if (key_code == $.FE.KEYCODE.X && editor.keys.ctrlKey(e)) {
2197
+ editor.events.trigger('window.cut');
2198
+ }
2199
+ });
2200
+ }
2201
+
2202
+ // Do not leave page while uploading.
2203
+ editor.events.$on($(editor.o_win), 'keydown', function (e) {
2204
+ var key_code = e.which;
2205
+
2206
+ if ($current_image && key_code == $.FE.KEYCODE.BACKSPACE) {
2207
+ e.preventDefault();
2208
+
2209
+ return false;
2210
+ }
2211
+ });
2212
+
2213
+ // Check if image is uploading to abort it.
2214
+ editor.events.$on(editor.$win, 'keydown', function (e) {
2215
+ var key_code = e.which;
2216
+
2217
+ if ($current_image && $current_image.hasClass('fr-uploading') && key_code == $.FE.KEYCODE.ESC) {
2218
+ $current_image.trigger('abortUpload');
2219
+ }
2220
+ });
2221
+
2222
+ editor.events.on('destroy', function () {
2223
+ if ($current_image && $current_image.hasClass('fr-uploading')) {
2224
+ $current_image.trigger('abortUpload');
2225
+ }
2226
+ });
2227
+
2228
+ editor.events.on('paste.before', _clipboardPaste);
2229
+ editor.events.on('paste.beforeCleanup', _clipboardPasteCleanup);
2230
+ editor.events.on('paste.after', _uploadPastedImages);
2231
+ editor.events.on('html.set', _refreshImageList);
2232
+ editor.events.on('html.inserted', _refreshImageList);
2233
+ _refreshImageList();
2234
+
2235
+ editor.events.on('destroy', function () {
2236
+ images = [];
2237
+ })
2238
+
2239
+ // Remove any fr-uploading / fr-error images.
2240
+ editor.events.on('html.processGet', _cleanOnGet);
2241
+
2242
+ if (editor.opts.imageOutputSize) {
2243
+ var imgs;
2244
+
2245
+ editor.events.on('html.beforeGet', function () {
2246
+ imgs = editor.el.querySelectorAll('img')
2247
+ for (var i = 0; i < imgs.length; i++) {
2248
+ var width = imgs[i].style.width || $(imgs[i]).width();
2249
+ var height = imgs[i].style.height || $(imgs[i]).height();
2250
+
2251
+ if (width) imgs[i].setAttribute('width', ('' + width).replace(/px/, ''));
2252
+
2253
+ if (height) imgs[i].setAttribute('height', ('' + height).replace(/px/, ''));
2254
+ }
2255
+ });
2256
+ }
2257
+
2258
+ if (editor.opts.iframe) {
2259
+ editor.events.on('image.loaded', editor.size.syncIframe);
2260
+ }
2261
+
2262
+ if (editor.$wp) {
2263
+ _syncImages();
2264
+ editor.events.on('contentChanged', _syncImages);
2265
+ }
2266
+
2267
+ editor.events.$on($(editor.o_win), 'orientationchange.image', function () {
2268
+ setTimeout(function () {
2269
+ if ($current_image) {
2270
+ _editImg($current_image);
2271
+ }
2272
+ }, 100);
2273
+ });
2274
+
2275
+ _initEditPopup(true);
2276
+ _initInsertPopup(true);
2277
+ _initSizePopup(true);
2278
+ _initAltPopup(true);
2279
+
2280
+ editor.events.on('node.remove', function ($node) {
2281
+ if ($node.get(0).tagName == 'IMG') {
2282
+ remove($node);
2283
+
2284
+ return false;
2285
+ }
2286
+ });
2287
+ }
2288
+
2289
+ function _processPastedImage(img) {
2290
+ if (editor.events.trigger('image.beforePasteUpload', [img]) === false) {
2291
+
2292
+ return false;
2293
+ }
2294
+
2295
+ // Show the progress bar.
2296
+ $current_image = $(img);
2297
+ _repositionResizer();
2298
+ _showEditPopup();
2299
+ replace();
2300
+ showProgressBar();
2301
+
2302
+ // Convert image to blob.
2303
+ var binary = atob($(img).attr('src').split(',')[1]);
2304
+ var array = [];
2305
+
2306
+ for (var i = 0; i < binary.length; i++) {
2307
+ array.push(binary.charCodeAt(i));
2308
+ }
2309
+
2310
+ var upload_img = new Blob([new Uint8Array(array)], {
2311
+ type: $(img).attr('src').split(',')[0].replace(/data\:/g, '').replace(/;base64/g, '')
2312
+ });
2313
+
2314
+ upload([upload_img], $current_image);
2315
+ }
2316
+
2317
+ function _uploadPastedImages() {
2318
+ if (!editor.opts.imagePaste) {
2319
+ editor.$el.find('img[data-fr-image-pasted]').remove();
2320
+ }
2321
+ else {
2322
+
2323
+ // Safari won't work https://bugs.webkit.org/show_bug.cgi?id=49141
2324
+ editor.$el.find('img[data-fr-image-pasted]').each(function (index, img) {
2325
+ if (editor.opts.imagePasteProcess) {
2326
+ var width = editor.opts.imageDefaultWidth;
2327
+
2328
+ if (width && width != 'auto') {
2329
+ width = width + (editor.opts.imageResizeWithPercent ? '%' : 'px');
2330
+ }
2331
+ $(img)
2332
+ .css('width', width)
2333
+ .removeClass('fr-dii fr-dib fr-fir fr-fil')
2334
+
2335
+ _setStyle($(img), editor.opts.imageDefaultDisplay, editor.opts.imageDefaultAlign);
2336
+ }
2337
+
2338
+ // Data images.
2339
+ if (img.src.indexOf('data:') === 0) {
2340
+ _processPastedImage(img);
2341
+ }
2342
+
2343
+ // New way Safari is pasting images.
2344
+ else if (img.src.indexOf('blob:') === 0 || (img.src.indexOf('http') === 0 && editor.opts.imageUploadRemoteUrls && editor.opts.imageCORSProxy)) {
2345
+ var _img = new Image();
2346
+ _img.crossOrigin = 'Anonymous';
2347
+ _img.onload = function () {
2348
+ // Create canvas.
2349
+ var canvas = editor.o_doc.createElement('CANVAS');
2350
+ var context = canvas.getContext('2d');
2351
+
2352
+ // Set height.
2353
+ canvas.height = this.naturalHeight;
2354
+ canvas.width = this.naturalWidth;
2355
+
2356
+ // Draw image.
2357
+ context.drawImage(this, 0, 0);
2358
+
2359
+ // Update image and process it.
2360
+ img.src = canvas.toDataURL('image/png');
2361
+ _processPastedImage(img);
2362
+ };
2363
+
2364
+ _img.src = (img.src.indexOf('blob:') === 0 ? '' : (editor.opts.imageCORSProxy + '/')) + img.src;
2365
+ }
2366
+
2367
+ // Images without http (Safari ones.).
2368
+ else if (img.src.indexOf('http') !== 0 || img.src.indexOf('https://mail.google.com/mail') === 0) {
2369
+ editor.selection.save();
2370
+ $(img).remove();
2371
+ editor.selection.restore();
2372
+ }
2373
+ else {
2374
+ $(img).removeAttr('data-fr-image-pasted');
2375
+ }
2376
+ });
2377
+ }
2378
+ }
2379
+
2380
+ function _clipboardImageLoaded(e) {
2381
+ var result = e.target.result;
2382
+
2383
+ // Default width.
2384
+ var width = editor.opts.imageDefaultWidth;
2385
+
2386
+ if (width && width != 'auto') {
2387
+ width = width + (editor.opts.imageResizeWithPercent ? '%' : 'px');
2388
+ }
2389
+
2390
+ editor.undo.saveStep();
2391
+
2392
+ editor.html.insert('<img data-fr-image-pasted="true" src="' + result + '"' + (width ? ' style="width: ' + width + ';"' : '') + '>');
2393
+
2394
+ var $img = editor.$el.find('img[data-fr-image-pasted="true"]');
2395
+
2396
+ if ($img) {
2397
+ _setStyle($img, editor.opts.imageDefaultDisplay, editor.opts.imageDefaultAlign);
2398
+ }
2399
+
2400
+ editor.events.trigger('paste.after');
2401
+ }
2402
+
2403
+ function _processsClipboardPaste(file) {
2404
+ var reader = new FileReader();
2405
+ reader.onload = _clipboardImageLoaded;
2406
+ reader.readAsDataURL(file);
2407
+ }
2408
+
2409
+ function _clipboardPaste(e) {
2410
+ if (e && e.clipboardData && e.clipboardData.items) {
2411
+
2412
+ var file = null;
2413
+
2414
+ if (!e.clipboardData.getData('text/html') && !e.clipboardData.getData('text/rtf')) {
2415
+ for (var i = 0; i < e.clipboardData.items.length; i++) {
2416
+ file = e.clipboardData.items[i].getAsFile();
2417
+
2418
+ if (file) {
2419
+ break;
2420
+ }
2421
+ }
2422
+ }
2423
+ else {
2424
+ file = e.clipboardData.items[0].getAsFile();
2425
+ }
2426
+
2427
+ if (file) {
2428
+ _processsClipboardPaste(file);
2429
+
2430
+ return false;
2431
+ }
2432
+ }
2433
+ }
2434
+
2435
+ function _clipboardPasteCleanup(clipboard_html) {
2436
+ clipboard_html = clipboard_html.replace(/<img /gi, '<img data-fr-image-pasted="true" ');
2437
+
2438
+ return clipboard_html;
2439
+ }
2440
+
2441
+ /**
2442
+ * Start edit.
2443
+ */
2444
+ var touchScroll;
2445
+
2446
+ function _edit(e) {
2447
+ if ($(this).parents('[contenteditable]:not(.fr-element):not(.fr-img-caption):not(body):first').attr('contenteditable') == 'false') return true;
2448
+
2449
+ if (e && e.type == 'touchend' && touchScroll) {
2450
+
2451
+ return true;
2452
+ }
2453
+
2454
+ if (e && editor.edit.isDisabled()) {
2455
+ e.stopPropagation();
2456
+ e.preventDefault();
2457
+
2458
+ return false;
2459
+ }
2460
+
2461
+ // Hide resizer for other instances.
2462
+ for (var i = 0; i < $.FE.INSTANCES.length; i++) {
2463
+ if ($.FE.INSTANCES[i] != editor) {
2464
+ $.FE.INSTANCES[i].events.trigger('image.hideResizer');
2465
+ }
2466
+ }
2467
+
2468
+ editor.toolbar.disable();
2469
+
2470
+ if (e) {
2471
+ e.stopPropagation();
2472
+ e.preventDefault();
2473
+ }
2474
+
2475
+ // Hide keyboard.
2476
+ if (editor.helpers.isMobile()) {
2477
+ editor.events.disableBlur();
2478
+ editor.$el.blur();
2479
+ editor.events.enableBlur();
2480
+ }
2481
+
2482
+ if (editor.opts.iframe) {
2483
+ editor.size.syncIframe();
2484
+ }
2485
+
2486
+ // Store current image.
2487
+ $current_image = $(this);
2488
+
2489
+ // Select image.
2490
+ _selectImage();
2491
+
2492
+ // Reposition resizer.
2493
+ _repositionResizer();
2494
+ _showEditPopup();
2495
+
2496
+ // Clear selection.
2497
+ if (!editor.browser.msie) {
2498
+ editor.selection.clear();
2499
+ }
2500
+
2501
+ // Fix for image remaining selected.
2502
+ if (editor.helpers.isIOS()) {
2503
+ editor.events.disableBlur();
2504
+ editor.$el.blur();
2505
+ }
2506
+
2507
+ // Refresh buttons.
2508
+ editor.button.bulkRefresh();
2509
+ editor.events.trigger('video.hideResizer');
2510
+ }
2511
+
2512
+ /**
2513
+ * Exit edit.
2514
+ */
2515
+
2516
+ function _exitEdit(force_exit) {
2517
+ if ($current_image && (_canExit() || force_exit === true)) {
2518
+ editor.toolbar.enable();
2519
+ $image_resizer.removeClass('fr-active');
2520
+ editor.popups.hide('image.edit');
2521
+ $current_image = null;
2522
+ _unmarkExit();
2523
+
2524
+ $handler = null;
2525
+
2526
+ if ($overlay) {
2527
+ $overlay.hide();
2528
+ }
2529
+ }
2530
+ }
2531
+
2532
+ var img_exit_flag = false;
2533
+
2534
+ function _markExit() {
2535
+ img_exit_flag = true;
2536
+ }
2537
+
2538
+ function _unmarkExit() {
2539
+ img_exit_flag = false;
2540
+ }
2541
+
2542
+ function _canExit() {
2543
+
2544
+ return img_exit_flag;
2545
+ }
2546
+
2547
+ /**
2548
+ * Set style for image.
2549
+ */
2550
+ function _setStyle($img, _display, _align) {
2551
+
2552
+ if (!editor.opts.htmlUntouched && editor.opts.useClasses) {
2553
+ $img.removeClass('fr-fil fr-fir fr-dib fr-dii');
2554
+
2555
+ if (_align) {
2556
+ $img.addClass('fr-fi' + _align[0]);
2557
+ }
2558
+
2559
+ if (_display) {
2560
+ $img.addClass('fr-di' + _display[0]);
2561
+ }
2562
+ }
2563
+ else {
2564
+ if (_display == 'inline') {
2565
+ $img.css({
2566
+ display: 'inline-block',
2567
+ verticalAlign: 'bottom',
2568
+ margin: editor.opts.imageDefaultMargin
2569
+ })
2570
+
2571
+ if (_align == 'center') {
2572
+ $img.css({
2573
+ 'float': 'none',
2574
+ marginBottom: '',
2575
+ marginTop: '',
2576
+ maxWidth: 'calc(100% - ' + (2 * editor.opts.imageDefaultMargin) + 'px)',
2577
+ textAlign: 'center'
2578
+ })
2579
+ }
2580
+ else if (_align == 'left') {
2581
+ $img.css({
2582
+ 'float': 'left',
2583
+ marginLeft: 0,
2584
+ maxWidth: 'calc(100% - ' + editor.opts.imageDefaultMargin + 'px)',
2585
+ textAlign: 'left'
2586
+ })
2587
+ }
2588
+ else {
2589
+ $img.css({
2590
+ 'float': 'right',
2591
+ marginRight: 0,
2592
+ maxWidth: 'calc(100% - ' + editor.opts.imageDefaultMargin + 'px)',
2593
+ textAlign: 'right'
2594
+ })
2595
+ }
2596
+ }
2597
+ else if (_display == 'block') {
2598
+ $img.css({
2599
+ display: 'block',
2600
+ 'float': 'none',
2601
+ verticalAlign: 'top',
2602
+ margin: editor.opts.imageDefaultMargin + 'px auto',
2603
+ textAlign: 'center'
2604
+ })
2605
+
2606
+ if (_align == 'left') {
2607
+ $img.css({
2608
+ marginLeft: 0,
2609
+ textAlign: 'left'
2610
+ })
2611
+ }
2612
+ else if (_align == 'right') {
2613
+ $img.css({
2614
+ marginRight: 0,
2615
+ textAlign: 'right'
2616
+ })
2617
+ }
2618
+ }
2619
+ }
2620
+ }
2621
+
2622
+ /**
2623
+ * Align image.
2624
+ */
2625
+ function align(val) {
2626
+ var $el = getEl();
2627
+
2628
+ $el.removeClass('fr-fir fr-fil');
2629
+
2630
+ // Easy case. Use classes.
2631
+ if (!editor.opts.htmlUntouched && editor.opts.useClasses) {
2632
+ if (val == 'left') {
2633
+ $el.addClass('fr-fil');
2634
+ }
2635
+ else if (val == 'right') {
2636
+ $el.addClass('fr-fir');
2637
+ }
2638
+ }
2639
+ else {
2640
+ _setStyle($el, getDisplay(), val);
2641
+ }
2642
+
2643
+ _selectImage();
2644
+ _repositionResizer();
2645
+ _showEditPopup();
2646
+ editor.selection.clear();
2647
+ }
2648
+
2649
+ /**
2650
+ * Get image alignment.
2651
+ */
2652
+ function getAlign($img) {
2653
+ if (typeof $img == 'undefined') $img = getEl();
2654
+
2655
+ if ($img) {
2656
+
2657
+ // Image has left class.
2658
+ if ($img.hasClass('fr-fil')) {
2659
+
2660
+ return 'left';
2661
+ }
2662
+
2663
+ // Image has right class.
2664
+ else if ($img.hasClass('fr-fir')) {
2665
+
2666
+ return 'right';
2667
+ }
2668
+
2669
+ // Image has display class set.
2670
+ else if ($img.hasClass('fr-dib') || $img.hasClass('fr-dii')) {
2671
+
2672
+ return 'center';
2673
+ }
2674
+ else {
2675
+ // Set float to none.
2676
+ var flt = $img.css('float');
2677
+
2678
+ $img.css('float', 'none');
2679
+
2680
+ // Image has display block.
2681
+ if ($img.css('display') == 'block') {
2682
+
2683
+ // Set float to the initial value.
2684
+ $img.css('float', '');
2685
+
2686
+ if ($img.css('float') != flt) $img.css('float', flt);
2687
+
2688
+ // Margin left is 0.
2689
+ // Margin right is auto.
2690
+ if (parseInt($img.css('margin-left'), 10) === 0) {
2691
+
2692
+ return 'left';
2693
+ }
2694
+
2695
+ // Margin left is auto.
2696
+ // Margin right is 0.
2697
+ else if (parseInt($img.css('margin-right'), 10) === 0) {
2698
+
2699
+ return 'right';
2700
+ }
2701
+ }
2702
+
2703
+ // Display inline.
2704
+ else {
2705
+
2706
+ // Set float.
2707
+ $img.css('float', '');
2708
+
2709
+ if ($img.css('float') != flt) $img.css('float', flt);
2710
+
2711
+ // Float left.
2712
+ if ($img.css('float') == 'left') {
2713
+
2714
+ return 'left';
2715
+ }
2716
+
2717
+ // Float right.
2718
+ else if ($img.css('float') == 'right') {
2719
+
2720
+ return 'right';
2721
+ }
2722
+ }
2723
+ }
2724
+ }
2725
+
2726
+ return 'center';
2727
+ }
2728
+
2729
+ /**
2730
+ * Get image display.
2731
+ */
2732
+ function getDisplay($img) {
2733
+ if (typeof $img == 'undefined') $img = getEl();
2734
+
2735
+ // Set float to none.
2736
+ var flt = $img.css('float');
2737
+ $img.css('float', 'none');
2738
+
2739
+ // Image has display block.
2740
+ if ($img.css('display') == 'block') {
2741
+
2742
+ // Set float to the initial value.
2743
+ $img.css('float', '');
2744
+
2745
+ if ($img.css('float') != flt) $img.css('float', flt);
2746
+
2747
+ return 'block';
2748
+ }
2749
+
2750
+ // Display inline.
2751
+ else {
2752
+
2753
+ // Set float.
2754
+ $img.css('float', '');
2755
+
2756
+ if ($img.css('float') != flt) $img.css('float', flt);
2757
+
2758
+ return 'inline';
2759
+ }
2760
+
2761
+ return 'inline';
2762
+ }
2763
+
2764
+ /**
2765
+ * Refresh the align icon.
2766
+ */
2767
+ function refreshAlign($btn) {
2768
+ if ($current_image) {
2769
+ $btn.find('> *:first').replaceWith(editor.icon.create('image-align-' + getAlign()));
2770
+ }
2771
+ }
2772
+
2773
+ /**
2774
+ * Refresh the align option from the dropdown.
2775
+ */
2776
+
2777
+ function refreshAlignOnShow($btn, $dropdown) {
2778
+ if ($current_image) {
2779
+ $dropdown.find('.fr-command[data-param1="' + getAlign() + '"]').addClass('fr-active').attr('aria-selected', true);
2780
+ }
2781
+ }
2782
+
2783
+ /**
2784
+ * Align image.
2785
+ */
2786
+
2787
+ function display(val) {
2788
+ var $el = getEl();
2789
+
2790
+ $el.removeClass('fr-dii fr-dib');
2791
+
2792
+ // Easy case. Use classes.
2793
+ if (!editor.opts.htmlUntouched && editor.opts.useClasses) {
2794
+ if (val == 'inline') {
2795
+ $el.addClass('fr-dii');
2796
+ }
2797
+ else if (val == 'block') {
2798
+ $el.addClass('fr-dib');
2799
+ }
2800
+ }
2801
+ else {
2802
+ _setStyle($el, val, getAlign());
2803
+ }
2804
+
2805
+ _selectImage();
2806
+ _repositionResizer();
2807
+ _showEditPopup();
2808
+ editor.selection.clear();
2809
+ }
2810
+
2811
+ /**
2812
+ * Refresh the image display selected option.
2813
+ */
2814
+
2815
+ function refreshDisplayOnShow($btn, $dropdown) {
2816
+ if ($current_image) {
2817
+ $dropdown.find('.fr-command[data-param1="' + getDisplay() + '"]').addClass('fr-active').attr('aria-selected', true);
2818
+ }
2819
+ }
2820
+
2821
+ /**
2822
+ * Show the replace popup.
2823
+ */
2824
+
2825
+ function replace() {
2826
+ var $popup = editor.popups.get('image.insert');
2827
+
2828
+ if (!$popup) $popup = _initInsertPopup();
2829
+
2830
+ if (!editor.popups.isVisible('image.insert')) {
2831
+ hideProgressBar();
2832
+ editor.popups.refresh('image.insert');
2833
+ editor.popups.setContainer('image.insert', editor.$sc);
2834
+ }
2835
+
2836
+ var $el = getEl();
2837
+
2838
+ if (hasCaption()) {
2839
+ $el = $el.find('.fr-img-wrap');
2840
+ }
2841
+
2842
+ var left = $el.offset().left + $el.outerWidth() / 2;
2843
+ var top = $el.offset().top + $el.outerHeight();
2844
+
2845
+ editor.popups.show('image.insert', left, top, $el.outerHeight(true));
2846
+ }
2847
+
2848
+ /**
2849
+ * Place selection around current image.
2850
+ */
2851
+ function _selectImage() {
2852
+ if ($current_image) {
2853
+ editor.events.disableBlur();
2854
+ editor.selection.clear();
2855
+ var range = editor.doc.createRange();
2856
+ range.selectNode($current_image.get(0));
2857
+
2858
+ // Collapse range in IE.
2859
+ if (editor.browser.msie) range.collapse(true);
2860
+
2861
+ var selection = editor.selection.get();
2862
+ selection.addRange(range);
2863
+ editor.events.enableBlur();
2864
+ }
2865
+ }
2866
+
2867
+ /**
2868
+ * Get back to the image main popup.
2869
+ */
2870
+ function back() {
2871
+ if ($current_image) {
2872
+ editor.events.disableBlur();
2873
+ $('.fr-popup input:focus').blur();
2874
+ _editImg($current_image);
2875
+ }
2876
+ else {
2877
+ editor.events.disableBlur();
2878
+ editor.selection.restore();
2879
+ editor.events.enableBlur();
2880
+
2881
+ editor.popups.hide('image.insert');
2882
+ editor.toolbar.showInline();
2883
+ }
2884
+ }
2885
+
2886
+ /**
2887
+ * Get the current image.
2888
+ */
2889
+
2890
+ function get() {
2891
+
2892
+ return $current_image;
2893
+ }
2894
+
2895
+ function getEl() {
2896
+ return hasCaption() ? $current_image.parents('.fr-img-caption:first') : $current_image;
2897
+ }
2898
+
2899
+ /**
2900
+ * Apply specific style.
2901
+ */
2902
+
2903
+ function applyStyle(val, imageStyles, multipleStyles) {
2904
+ if (typeof imageStyles == 'undefined') imageStyles = editor.opts.imageStyles;
2905
+
2906
+ if (typeof multipleStyles == 'undefined') multipleStyles = editor.opts.imageMultipleStyles;
2907
+
2908
+ if (!$current_image) return false;
2909
+
2910
+ var $img = getEl();
2911
+
2912
+ // Remove multiple styles.
2913
+ if (!multipleStyles) {
2914
+ var styles = Object.keys(imageStyles);
2915
+ styles.splice(styles.indexOf(val), 1);
2916
+ $img.removeClass(styles.join(' '));
2917
+ }
2918
+
2919
+ if (typeof imageStyles[val] == 'object') {
2920
+ $img.removeAttr('style');
2921
+ $img.css(imageStyles[val].style);
2922
+ }
2923
+ else {
2924
+ $img.toggleClass(val);
2925
+ }
2926
+
2927
+ _editImg($current_image);
2928
+ }
2929
+
2930
+ function hasCaption() {
2931
+ if ($current_image) {
2932
+ return $current_image.parents('.fr-img-caption').length > 0;
2933
+ }
2934
+
2935
+ return false;
2936
+ }
2937
+
2938
+ function toggleCaption() {
2939
+ var $el;
2940
+
2941
+ if ($current_image && !hasCaption()) {
2942
+ $el = $current_image;
2943
+
2944
+ // Check if there is a link wrapping the image.
2945
+ if ($current_image.parent().is('a')) {
2946
+ $el = $current_image.parent();
2947
+ }
2948
+
2949
+ $el.wrap('<span ' + (!editor.browser.mozilla ? 'contenteditable="false"' : '') + 'class="fr-img-caption ' + $current_image.attr('class') + '" style="' + ($current_image.attr('style') ? $current_image.attr('style') + ' ' : '') + 'width: ' + $current_image.width() + 'px;" draggable="false"></span>');
2950
+ $el.wrap('<span class="fr-img-wrap"></span>');
2951
+ $el.after('<span class="fr-inner" contenteditable="true">' + $.FE.START_MARKER + 'Image caption' + $.FE.END_MARKER + '</span>');
2952
+ $current_image.removeAttr('class').removeAttr('style').removeAttr('width');
2953
+
2954
+ _exitEdit(true);
2955
+
2956
+ editor.selection.restore();
2957
+ }
2958
+ else {
2959
+ $el = getEl();
2960
+ $current_image.insertAfter($el);
2961
+ $current_image
2962
+ .attr('class', $el.attr('class').replace('fr-img-caption', ''))
2963
+ .attr('style', $el.attr('style'));
2964
+ $el.remove();
2965
+
2966
+ _editImg($current_image);
2967
+ }
2968
+ }
2969
+
2970
+ return {
2971
+ _init: _init,
2972
+ showInsertPopup: showInsertPopup,
2973
+ showLayer: showLayer,
2974
+ refreshUploadButton: refreshUploadButton,
2975
+ refreshByURLButton: refreshByURLButton,
2976
+ upload: upload,
2977
+ insertByURL: insertByURL,
2978
+ align: align,
2979
+ refreshAlign: refreshAlign,
2980
+ refreshAlignOnShow: refreshAlignOnShow,
2981
+ display: display,
2982
+ refreshDisplayOnShow: refreshDisplayOnShow,
2983
+ replace: replace,
2984
+ back: back,
2985
+ get: get,
2986
+ getEl: getEl,
2987
+ insert: insert,
2988
+ showProgressBar: showProgressBar,
2989
+ remove: remove,
2990
+ hideProgressBar: hideProgressBar,
2991
+ applyStyle: applyStyle,
2992
+ showAltPopup: showAltPopup,
2993
+ showSizePopup: showSizePopup,
2994
+ setAlt: setAlt,
2995
+ setSize: setSize,
2996
+ toggleCaption: toggleCaption,
2997
+ hasCaption: hasCaption,
2998
+ exitEdit: _exitEdit,
2999
+ edit: _editImg
3000
+ }
3001
+ }
3002
+
3003
+ // Insert image button.
3004
+ $.FE.DefineIcon('insertImage', {
3005
+ NAME: 'image'
3006
+ });
3007
+ $.FE.RegisterShortcut($.FE.KEYCODE.P, 'insertImage', null, 'P');
3008
+ $.FE.RegisterCommand('insertImage', {
3009
+ title: 'Insert Image',
3010
+ undo: false,
3011
+ focus: true,
3012
+ refreshAfterCallback: false,
3013
+ popup: true,
3014
+ callback: function () {
3015
+ if (!this.popups.isVisible('image.insert')) {
3016
+ this.image.showInsertPopup();
3017
+ }
3018
+ else {
3019
+ if (this.$el.find('.fr-marker').length) {
3020
+ this.events.disableBlur();
3021
+ this.selection.restore();
3022
+ }
3023
+ this.popups.hide('image.insert');
3024
+ }
3025
+ },
3026
+ plugin: 'image'
3027
+ });
3028
+
3029
+ // Image upload button inside the insert image popup.
3030
+ $.FE.DefineIcon('imageUpload', {
3031
+ NAME: 'upload'
3032
+ });
3033
+ $.FE.RegisterCommand('imageUpload', {
3034
+ title: 'Upload Image',
3035
+ undo: false,
3036
+ focus: false,
3037
+ toggle: true,
3038
+ callback: function () {
3039
+ this.image.showLayer('image-upload');
3040
+ },
3041
+ refresh: function ($btn) {
3042
+ this.image.refreshUploadButton($btn);
3043
+ }
3044
+ });
3045
+
3046
+ // Image by URL button inside the insert image popup.
3047
+ $.FE.DefineIcon('imageByURL', {
3048
+ NAME: 'link'
3049
+ });
3050
+ $.FE.RegisterCommand('imageByURL', {
3051
+ title: 'By URL',
3052
+ undo: false,
3053
+ focus: false,
3054
+ toggle: true,
3055
+ callback: function () {
3056
+ this.image.showLayer('image-by-url');
3057
+ },
3058
+ refresh: function ($btn) {
3059
+ this.image.refreshByURLButton($btn);
3060
+ }
3061
+ })
3062
+
3063
+ // Insert image button inside the insert by URL layer.
3064
+ $.FE.RegisterCommand('imageInsertByURL', {
3065
+ title: 'Insert Image',
3066
+ undo: true,
3067
+ refreshAfterCallback: false,
3068
+ callback: function () {
3069
+ this.image.insertByURL();
3070
+ },
3071
+ refresh: function ($btn) {
3072
+ var $current_image = this.image.get();
3073
+
3074
+ if (!$current_image) {
3075
+ $btn.text(this.language.translate('Insert'));
3076
+ }
3077
+ else {
3078
+ $btn.text(this.language.translate('Replace'));
3079
+ }
3080
+ }
3081
+ })
3082
+
3083
+ // Image display.
3084
+ $.FE.DefineIcon('imageDisplay', {
3085
+ NAME: 'star'
3086
+ })
3087
+ $.FE.RegisterCommand('imageDisplay', {
3088
+ title: 'Display',
3089
+ type: 'dropdown',
3090
+ options: {
3091
+ inline: 'Inline',
3092
+ block: 'Break Text'
3093
+ },
3094
+ callback: function (cmd, val) {
3095
+ this.image.display(val);
3096
+ },
3097
+ refresh: function ($btn) {
3098
+ if (!this.opts.imageTextNear) $btn.addClass('fr-hidden');
3099
+ },
3100
+ refreshOnShow: function ($btn, $dropdown) {
3101
+ this.image.refreshDisplayOnShow($btn, $dropdown);
3102
+ }
3103
+ })
3104
+
3105
+ // Image align.
3106
+ $.FE.DefineIcon('image-align', {
3107
+ NAME: 'align-left'
3108
+ });
3109
+ $.FE.DefineIcon('image-align-left', {
3110
+ NAME: 'align-left'
3111
+ });
3112
+ $.FE.DefineIcon('image-align-right', {
3113
+ NAME: 'align-right'
3114
+ });
3115
+ $.FE.DefineIcon('image-align-center', {
3116
+ NAME: 'align-justify'
3117
+ });
3118
+
3119
+ $.FE.DefineIcon('imageAlign', {
3120
+ NAME: 'align-justify'
3121
+ })
3122
+ $.FE.RegisterCommand('imageAlign', {
3123
+ type: 'dropdown',
3124
+ title: 'Align',
3125
+ options: {
3126
+ left: 'Align Left',
3127
+ center: 'None',
3128
+ right: 'Align Right'
3129
+ },
3130
+ html: function () {
3131
+ var c = '<ul class="fr-dropdown-list" role="presentation">';
3132
+ var options = $.FE.COMMANDS.imageAlign.options;
3133
+
3134
+ for (var val in options) {
3135
+ if (options.hasOwnProperty(val)) {
3136
+ c += '<li role="presentation"><a class="fr-command fr-title" tabIndex="-1" role="option" data-cmd="imageAlign" data-param1="' + val + '" title="' + this.language.translate(options[val]) + '">' + this.icon.create('image-align-' + val) + '<span class="fr-sr-only">' + this.language.translate(options[val]) + '</span></a></li>';
3137
+ }
3138
+ }
3139
+ c += '</ul>';
3140
+
3141
+ return c;
3142
+ },
3143
+ callback: function (cmd, val) {
3144
+ this.image.align(val);
3145
+ },
3146
+ refresh: function ($btn) {
3147
+ this.image.refreshAlign($btn);
3148
+ },
3149
+ refreshOnShow: function ($btn, $dropdown) {
3150
+ this.image.refreshAlignOnShow($btn, $dropdown);
3151
+ }
3152
+ })
3153
+
3154
+ // Image replace.
3155
+ $.FE.DefineIcon('imageReplace', {
3156
+ NAME: 'exchange',
3157
+ FA5NAME: 'exchange-alt'
3158
+ })
3159
+ $.FE.RegisterCommand('imageReplace', {
3160
+ title: 'Replace',
3161
+ undo: false,
3162
+ focus: false,
3163
+ popup: true,
3164
+ refreshAfterCallback: false,
3165
+ callback: function () {
3166
+ this.image.replace();
3167
+ }
3168
+ })
3169
+
3170
+ // Image remove.
3171
+ $.FE.DefineIcon('imageRemove', {
3172
+ NAME: 'trash'
3173
+ })
3174
+ $.FE.RegisterCommand('imageRemove', {
3175
+ title: 'Remove',
3176
+ callback: function () {
3177
+ this.image.remove();
3178
+ }
3179
+ })
3180
+
3181
+ // Image back.
3182
+ $.FE.DefineIcon('imageBack', {
3183
+ NAME: 'arrow-left'
3184
+ });
3185
+ $.FE.RegisterCommand('imageBack', {
3186
+ title: 'Back',
3187
+ undo: false,
3188
+ focus: false,
3189
+ back: true,
3190
+ callback: function () {
3191
+ this.image.back();
3192
+ },
3193
+ refresh: function ($btn) {
3194
+ var $current_image = this.image.get();
3195
+
3196
+ if (!$current_image && !this.opts.toolbarInline) {
3197
+ $btn.addClass('fr-hidden');
3198
+ $btn.next('.fr-separator').addClass('fr-hidden');
3199
+ }
3200
+ else {
3201
+ $btn.removeClass('fr-hidden');
3202
+ $btn.next('.fr-separator').removeClass('fr-hidden');
3203
+ }
3204
+ }
3205
+ });
3206
+
3207
+ $.FE.RegisterCommand('imageDismissError', {
3208
+ title: 'OK',
3209
+ undo: false,
3210
+ callback: function () {
3211
+ this.image.hideProgressBar(true);
3212
+ }
3213
+ })
3214
+
3215
+ // Image styles.
3216
+ $.FE.DefineIcon('imageStyle', {
3217
+ NAME: 'magic'
3218
+ })
3219
+ $.FE.RegisterCommand('imageStyle', {
3220
+ title: 'Style',
3221
+ type: 'dropdown',
3222
+ html: function () {
3223
+ var c = '<ul class="fr-dropdown-list" role="presentation">';
3224
+ var options = this.opts.imageStyles;
3225
+
3226
+ for (var cls in options) {
3227
+ if (options.hasOwnProperty(cls)) {
3228
+ var val = options[cls];
3229
+
3230
+ if (typeof val == 'object') val = val.title;
3231
+
3232
+ c += '<li role="presentation"><a class="fr-command" tabIndex="-1" role="option" data-cmd="imageStyle" data-param1="' + cls + '">' + this.language.translate(val) + '</a></li>';
3233
+ }
3234
+ }
3235
+ c += '</ul>';
3236
+
3237
+ return c;
3238
+ },
3239
+ callback: function (cmd, val) {
3240
+ this.image.applyStyle(val);
3241
+ },
3242
+ refreshOnShow: function ($btn, $dropdown) {
3243
+ var $current_image = this.image.getEl();
3244
+
3245
+ if ($current_image) {
3246
+ $dropdown.find('.fr-command').each(function () {
3247
+ var cls = $(this).data('param1');
3248
+ var active = $current_image.hasClass(cls);
3249
+ $(this).toggleClass('fr-active', active).attr('aria-selected', active);
3250
+ })
3251
+ }
3252
+ }
3253
+ })
3254
+
3255
+ // Image alt.
3256
+ $.FE.DefineIcon('imageAlt', {
3257
+ NAME: 'info'
3258
+ })
3259
+ $.FE.RegisterCommand('imageAlt', {
3260
+ undo: false,
3261
+ focus: false,
3262
+ popup: true,
3263
+ title: 'Alternate Text',
3264
+ callback: function () {
3265
+ this.image.showAltPopup();
3266
+ }
3267
+ });
3268
+
3269
+ $.FE.RegisterCommand('imageSetAlt', {
3270
+ undo: true,
3271
+ focus: false,
3272
+ title: 'Update',
3273
+ refreshAfterCallback: false,
3274
+ callback: function () {
3275
+ this.image.setAlt();
3276
+ }
3277
+ });
3278
+
3279
+ // Image size.
3280
+ $.FE.DefineIcon('imageSize', {
3281
+ NAME: 'arrows-alt'
3282
+ })
3283
+ $.FE.RegisterCommand('imageSize', {
3284
+ undo: false,
3285
+ focus: false,
3286
+ popup: true,
3287
+ title: 'Change Size',
3288
+ callback: function () {
3289
+ this.image.showSizePopup();
3290
+ }
3291
+ });
3292
+
3293
+ $.FE.RegisterCommand('imageSetSize', {
3294
+ undo: true,
3295
+ focus: false,
3296
+ title: 'Update',
3297
+ refreshAfterCallback: false,
3298
+ callback: function () {
3299
+ this.image.setSize();
3300
+ }
3301
+ });
3302
+
3303
+ $.FE.DefineIcon('imageCaption', {
3304
+ NAME: 'commenting',
3305
+ FA5NAME: 'comment-alt'
3306
+ })
3307
+
3308
+ $.FE.RegisterCommand('imageCaption', {
3309
+ undo: true,
3310
+ focus: false,
3311
+ title: 'Image Caption',
3312
+ refreshAfterCallback: true,
3313
+ callback: function () {
3314
+ this.image.toggleCaption();
3315
+ },
3316
+ refresh: function ($btn) {
3317
+ if (this.image.get()) {
3318
+ $btn.toggleClass('fr-active', this.image.hasCaption());
3319
+ }
3320
+ }
3321
+ })
3322
+
3323
+ }));