glebtv-ckeditor 4.7.3 → 4.14.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (380) hide show
  1. checksums.yaml +5 -5
  2. data/Gemfile +13 -12
  3. data/README.md +358 -2
  4. data/Rakefile +17 -17
  5. data/app/assets/javascripts/ckeditor/config.js.erb +3 -3
  6. data/app/controllers/ckeditor/application_controller.rb +3 -0
  7. data/app/controllers/ckeditor/attachment_files_controller.rb +2 -0
  8. data/app/controllers/ckeditor/pictures_controller.rb +2 -0
  9. data/app/helpers/ckeditor/application_helper.rb +2 -0
  10. data/config/locales/bg.ckeditor.yml +9 -0
  11. data/config/locales/cs.ckeditor.yml +9 -0
  12. data/config/locales/da.ckeditor.yml +9 -0
  13. data/config/locales/de.ckeditor.yml +9 -0
  14. data/config/locales/el-GR.cdkeditor.yml +9 -0
  15. data/config/locales/es.ckeditor.yml +9 -0
  16. data/config/locales/fr.ckeditor.yml +9 -0
  17. data/config/locales/hu.ckeditor.yml +9 -0
  18. data/config/locales/it.ckeditor.yml +9 -0
  19. data/config/locales/ja.ckeditor.yml +9 -0
  20. data/config/locales/nb.ckeditor.yml +9 -0
  21. data/config/locales/nl.ckeditor.yml +9 -0
  22. data/config/locales/pl.ckeditor.yml +9 -0
  23. data/config/locales/pt-BR.ckeditor.yml +9 -0
  24. data/config/locales/pt-PT.ckeditor.yml +9 -0
  25. data/config/locales/pt.ckeditor.yml +9 -0
  26. data/config/locales/sq.ckeditor.yml +9 -0
  27. data/config/locales/sv-SE.ckeditor.yml +9 -0
  28. data/config/locales/tr.ckeditor.yml +9 -0
  29. data/config/locales/uk.ckeditor.yml +9 -0
  30. data/config/locales/zh-CN.ckeditor.yml +9 -0
  31. data/config/locales/zh-TW.ckeditor.yml +9 -0
  32. data/config/routes.rb +2 -0
  33. data/lib/ckeditor.rb +13 -16
  34. data/lib/ckeditor/asset_response.rb +15 -4
  35. data/lib/ckeditor/backend/active_storage.rb +68 -0
  36. data/lib/ckeditor/backend/carrierwave.rb +2 -12
  37. data/lib/ckeditor/backend/dragonfly.rb +2 -0
  38. data/lib/ckeditor/backend/paperclip.rb +2 -15
  39. data/lib/ckeditor/backend/shrine.rb +29 -0
  40. data/lib/ckeditor/helpers/controllers.rb +2 -0
  41. data/lib/ckeditor/helpers/form_builder.rb +2 -0
  42. data/lib/ckeditor/helpers/form_helper.rb +2 -0
  43. data/lib/ckeditor/helpers/view_helper.rb +2 -0
  44. data/lib/ckeditor/hooks/cancan.rb +4 -1
  45. data/lib/ckeditor/hooks/formtastic.rb +2 -0
  46. data/lib/ckeditor/hooks/pundit.rb +2 -0
  47. data/lib/ckeditor/hooks/simple_form.rb +2 -0
  48. data/lib/ckeditor/http.rb +8 -5
  49. data/lib/ckeditor/orm/active_record.rb +2 -0
  50. data/lib/ckeditor/orm/base.rb +11 -2
  51. data/lib/ckeditor/orm/mongoid.rb +2 -0
  52. data/lib/ckeditor/paginatable.rb +2 -0
  53. data/lib/ckeditor/rails.rb +2 -0
  54. data/lib/ckeditor/rails_admin/field.rb +16 -3
  55. data/lib/ckeditor/text_area.rb +2 -0
  56. data/lib/ckeditor/utils.rb +3 -16
  57. data/lib/ckeditor/utils/javascript_code.rb +1 -1
  58. data/lib/ckeditor/version.rb +4 -2
  59. data/lib/generators/ckeditor/install_generator.rb +16 -19
  60. data/lib/generators/ckeditor/pundit_policy_generator.rb +2 -0
  61. data/lib/generators/ckeditor/templates/active_record/active_storage/ckeditor/asset.rb +10 -0
  62. data/lib/generators/ckeditor/templates/active_record/{refile → active_storage}/ckeditor/attachment_file.rb +3 -1
  63. data/lib/generators/ckeditor/templates/active_record/active_storage/ckeditor/picture.rb +13 -0
  64. data/lib/generators/ckeditor/templates/active_record/{carrierwave/migration_versioned.rb → active_storage/migration.rb} +8 -5
  65. data/lib/generators/ckeditor/templates/active_record/carrierwave/ckeditor/asset.rb +2 -0
  66. data/lib/generators/ckeditor/templates/active_record/carrierwave/ckeditor/attachment_file.rb +2 -0
  67. data/lib/generators/ckeditor/templates/active_record/carrierwave/ckeditor/picture.rb +2 -0
  68. data/lib/generators/ckeditor/templates/active_record/carrierwave/migration.rb +7 -5
  69. data/lib/generators/ckeditor/templates/active_record/dragonfly/ckeditor/asset.rb +2 -0
  70. data/lib/generators/ckeditor/templates/active_record/dragonfly/ckeditor/attachment_file.rb +2 -0
  71. data/lib/generators/ckeditor/templates/active_record/dragonfly/ckeditor/picture.rb +2 -0
  72. data/lib/generators/ckeditor/templates/active_record/dragonfly/migration.rb +7 -5
  73. data/lib/generators/ckeditor/templates/active_record/paperclip/ckeditor/asset.rb +2 -0
  74. data/lib/generators/ckeditor/templates/active_record/paperclip/ckeditor/attachment_file.rb +2 -0
  75. data/lib/generators/ckeditor/templates/active_record/paperclip/ckeditor/picture.rb +2 -0
  76. data/lib/generators/ckeditor/templates/active_record/paperclip/migration.rb +8 -6
  77. data/lib/generators/ckeditor/templates/active_record/{refile → shrine}/ckeditor/asset.rb +3 -1
  78. data/lib/generators/ckeditor/templates/active_record/shrine/ckeditor/attachment_file.rb +21 -0
  79. data/lib/generators/ckeditor/templates/active_record/shrine/ckeditor/picture.rb +49 -0
  80. data/lib/generators/ckeditor/templates/active_record/shrine/migration.rb +22 -0
  81. data/lib/generators/ckeditor/templates/base/carrierwave/uploaders/ckeditor_attachment_file_uploader.rb +2 -1
  82. data/lib/generators/ckeditor/templates/base/carrierwave/uploaders/ckeditor_picture_uploader.rb +2 -3
  83. data/lib/generators/ckeditor/templates/base/dragonfly/initializer.rb +2 -0
  84. data/lib/generators/ckeditor/templates/base/shrine/initializer.rb +25 -0
  85. data/lib/generators/ckeditor/templates/ckeditor.rb +3 -6
  86. data/lib/generators/ckeditor/templates/mongoid/carrierwave/ckeditor/asset.rb +2 -0
  87. data/lib/generators/ckeditor/templates/mongoid/carrierwave/ckeditor/attachment_file.rb +2 -0
  88. data/lib/generators/ckeditor/templates/mongoid/carrierwave/ckeditor/picture.rb +2 -0
  89. data/lib/generators/ckeditor/templates/mongoid/paperclip/ckeditor/asset.rb +2 -0
  90. data/lib/generators/ckeditor/templates/mongoid/paperclip/ckeditor/attachment_file.rb +2 -0
  91. data/lib/generators/ckeditor/templates/mongoid/paperclip/ckeditor/picture.rb +2 -0
  92. data/lib/generators/ckeditor/templates/mongoid/shrine/ckeditor/asset.rb +8 -0
  93. data/lib/generators/ckeditor/templates/mongoid/shrine/ckeditor/attachment_file.rb +21 -0
  94. data/lib/generators/ckeditor/templates/mongoid/shrine/ckeditor/picture.rb +47 -0
  95. data/lib/generators/ckeditor/templates/pundit_policy/attachment_file_policy.rb +2 -0
  96. data/lib/generators/ckeditor/templates/pundit_policy/picture_policy.rb +2 -0
  97. data/lib/tasks/ckeditor.rake +2 -0
  98. data/test/controllers/attachment_files_controller_test.rb +17 -15
  99. data/test/controllers/pictures_controller_test.rb +17 -15
  100. data/test/dummy/Rakefile +2 -0
  101. data/test/dummy/app/assets/javascripts/application.js +0 -2
  102. data/test/dummy/app/controllers/application_controller.rb +2 -0
  103. data/test/dummy/app/controllers/posts_controller.rb +2 -0
  104. data/test/dummy/app/helpers/application_helper.rb +2 -0
  105. data/test/dummy/app/helpers/posts_helper.rb +2 -0
  106. data/test/dummy/app/models/post.rb +2 -0
  107. data/test/dummy/app/views/posts/index.html.erb +0 -3
  108. data/test/dummy/app/views/posts/show.html.erb +3 -0
  109. data/test/dummy/config.ru +2 -0
  110. data/test/dummy/config/application.rb +5 -1
  111. data/test/dummy/config/boot.rb +2 -0
  112. data/test/dummy/config/environment.rb +2 -0
  113. data/test/dummy/config/environments/development.rb +2 -0
  114. data/test/dummy/config/environments/production.rb +2 -0
  115. data/test/dummy/config/environments/test.rb +5 -3
  116. data/test/dummy/config/initializers/assets.rb +2 -0
  117. data/test/dummy/config/initializers/backtrace_silencers.rb +2 -0
  118. data/test/dummy/config/initializers/ckeditor.rb +2 -0
  119. data/test/dummy/config/initializers/cookies_serializer.rb +2 -0
  120. data/test/dummy/config/initializers/inflections.rb +2 -0
  121. data/test/dummy/config/initializers/mime_types.rb +2 -0
  122. data/test/dummy/config/initializers/paperclip.rb +2 -0
  123. data/test/dummy/config/initializers/session_store.rb +2 -0
  124. data/test/dummy/config/initializers/wrap_parameters.rb +2 -0
  125. data/test/dummy/config/routes.rb +2 -0
  126. data/test/dummy/config/storage.yml +3 -0
  127. data/test/dummy/db/migrate/20110623120047_create_posts.rb +5 -3
  128. data/test/dummy/db/migrate/20170806125915_create_active_storage_tables.rb +26 -0
  129. data/test/dummy/script/rails +2 -0
  130. data/test/functional/posts_controller_test.rb +18 -16
  131. data/test/generators/install_generator_test.rb +58 -56
  132. data/test/integration/navigation_test.rb +2 -0
  133. data/test/models/attachment_file_test.rb +4 -4
  134. data/test/models/ckeditor_test.rb +3 -21
  135. data/test/models/picture_test.rb +12 -10
  136. data/test/models/utils_test.rb +2 -0
  137. data/test/orm/active_record.rb +11 -1
  138. data/test/orm/mongoid.rb +2 -0
  139. data/test/support/helpers.rb +2 -0
  140. data/test/support/integration_case.rb +2 -0
  141. data/test/test_helper.rb +15 -9
  142. data/vendor/assets/javascripts/ckeditor/CHANGES.md +1404 -859
  143. data/vendor/assets/javascripts/ckeditor/LICENSE.md +8 -7
  144. data/vendor/assets/javascripts/ckeditor/README.md +5 -5
  145. data/vendor/assets/javascripts/ckeditor/adapters/jquery.js +7 -7
  146. data/vendor/assets/javascripts/ckeditor/build-config.js +12 -6
  147. data/vendor/assets/javascripts/ckeditor/ckeditor.js +1090 -907
  148. data/vendor/assets/javascripts/ckeditor/config.js +2 -2
  149. data/vendor/assets/javascripts/ckeditor/contents.css +7 -7
  150. data/vendor/assets/javascripts/ckeditor/lang/en.js +3 -3
  151. data/vendor/assets/javascripts/ckeditor/lang/ru.js +3 -3
  152. data/vendor/assets/javascripts/ckeditor/plugins/a11yhelp/dialogs/a11yhelp.js +7 -7
  153. data/vendor/assets/javascripts/ckeditor/plugins/a11yhelp/dialogs/lang/en.js +2 -2
  154. data/vendor/assets/javascripts/ckeditor/plugins/a11yhelp/dialogs/lang/ru.js +3 -3
  155. data/vendor/assets/javascripts/ckeditor/plugins/about/dialogs/about.js +5 -5
  156. data/vendor/assets/javascripts/ckeditor/plugins/about/dialogs/hidpi/logo_ckeditor.png +0 -0
  157. data/vendor/assets/javascripts/ckeditor/plugins/about/dialogs/logo_ckeditor.png +0 -0
  158. data/vendor/assets/javascripts/ckeditor/plugins/clipboard/dialogs/paste.js +11 -0
  159. data/vendor/assets/javascripts/ckeditor/plugins/codemirror/css/codemirror.min.css +1 -1
  160. data/vendor/assets/javascripts/ckeditor/plugins/codemirror/icons/autoformat.png +0 -0
  161. data/vendor/assets/javascripts/ckeditor/plugins/codemirror/icons/searchcode.png +0 -0
  162. data/vendor/assets/javascripts/ckeditor/plugins/codemirror/icons/uncommentselectedrange.png +0 -0
  163. data/vendor/assets/javascripts/ckeditor/plugins/codemirror/images/autocomplete.png +0 -0
  164. data/vendor/assets/javascripts/ckeditor/plugins/codemirror/images/autoformat.png +0 -0
  165. data/vendor/assets/javascripts/ckeditor/plugins/codemirror/images/commentselectedrange.png +0 -0
  166. data/vendor/assets/javascripts/ckeditor/plugins/codemirror/images/searchcode.png +0 -0
  167. data/vendor/assets/javascripts/ckeditor/plugins/codemirror/images/uncommentselectedrange.png +0 -0
  168. data/vendor/assets/javascripts/ckeditor/plugins/codemirror/js/beautify.min.js +2 -2
  169. data/vendor/assets/javascripts/ckeditor/plugins/codemirror/js/codemirror.addons.min.js +2 -2
  170. data/vendor/assets/javascripts/ckeditor/plugins/codemirror/js/codemirror.addons.search.min.js +1 -1
  171. data/vendor/assets/javascripts/ckeditor/plugins/codemirror/js/codemirror.min.js +1 -6
  172. data/vendor/assets/javascripts/ckeditor/plugins/codemirror/js/codemirror.mode.bbcodemixed.min.js +1 -1
  173. data/vendor/assets/javascripts/ckeditor/plugins/codemirror/js/codemirror.mode.handlebars.min.js +1 -0
  174. data/vendor/assets/javascripts/ckeditor/plugins/codemirror/js/codemirror.mode.htmlmixed.min.js +2 -2
  175. data/vendor/assets/javascripts/ckeditor/plugins/codemirror/js/codemirror.mode.javascript.min.js +1 -1
  176. data/vendor/assets/javascripts/ckeditor/plugins/codemirror/js/codemirror.mode.php.min.js +3 -3
  177. data/vendor/assets/javascripts/ckeditor/plugins/codemirror/js/codemirror.mode.twig.min.js +1 -1
  178. data/vendor/assets/javascripts/ckeditor/plugins/codemirror/plugin.js +236 -218
  179. data/vendor/assets/javascripts/ckeditor/plugins/codemirror/theme/base16-light.css +1 -1
  180. data/vendor/assets/javascripts/ckeditor/plugins/codemirror/theme/darcula.css +51 -0
  181. data/vendor/assets/javascripts/ckeditor/plugins/codemirror/theme/gruvbox-dark.css +37 -0
  182. data/vendor/assets/javascripts/ckeditor/plugins/codemirror/theme/idea.css +42 -0
  183. data/vendor/assets/javascripts/ckeditor/plugins/codemirror/theme/lesser-dark.css +2 -2
  184. data/vendor/assets/javascripts/ckeditor/plugins/codemirror/theme/lucario.css +37 -0
  185. data/vendor/assets/javascripts/ckeditor/plugins/codemirror/theme/monokai.css +5 -0
  186. data/vendor/assets/javascripts/ckeditor/plugins/codemirror/theme/nord.css +42 -0
  187. data/vendor/assets/javascripts/ckeditor/plugins/codemirror/theme/oceanic-next.css +44 -0
  188. data/vendor/assets/javascripts/ckeditor/plugins/codemirror/theme/panda-syntax.css +1 -1
  189. data/vendor/assets/javascripts/ckeditor/plugins/codemirror/theme/shadowfox.css +52 -0
  190. data/vendor/assets/javascripts/ckeditor/plugins/codemirror/theme/solarized.css +0 -1
  191. data/vendor/assets/javascripts/ckeditor/plugins/codemirror/theme/ssms.css +16 -0
  192. data/vendor/assets/javascripts/ckeditor/plugins/codemirror/theme/vibrant-ink.css +1 -1
  193. data/vendor/assets/javascripts/ckeditor/plugins/codemirror/theme/yonce.css +59 -0
  194. data/vendor/assets/javascripts/ckeditor/plugins/colordialog/dialogs/colordialog.css +2 -2
  195. data/vendor/assets/javascripts/ckeditor/plugins/colordialog/dialogs/colordialog.js +12 -12
  196. data/vendor/assets/javascripts/ckeditor/plugins/dialog/dialogDefinition.js +2 -2
  197. data/vendor/assets/javascripts/ckeditor/plugins/dialog/styles/dialog.css +18 -0
  198. data/vendor/assets/javascripts/ckeditor/plugins/div/dialogs/div.js +9 -8
  199. data/vendor/assets/javascripts/ckeditor/plugins/find/dialogs/find.js +23 -23
  200. data/vendor/assets/javascripts/ckeditor/plugins/flash/dialogs/flash.js +17 -17
  201. data/vendor/assets/javascripts/ckeditor/plugins/forms/dialogs/button.js +6 -6
  202. data/vendor/assets/javascripts/ckeditor/plugins/forms/dialogs/checkbox.js +5 -5
  203. data/vendor/assets/javascripts/ckeditor/plugins/forms/dialogs/form.js +3 -3
  204. data/vendor/assets/javascripts/ckeditor/plugins/forms/dialogs/hiddenfield.js +5 -5
  205. data/vendor/assets/javascripts/ckeditor/plugins/forms/dialogs/radio.js +7 -7
  206. data/vendor/assets/javascripts/ckeditor/plugins/forms/dialogs/select.js +17 -16
  207. data/vendor/assets/javascripts/ckeditor/plugins/forms/dialogs/textarea.js +7 -6
  208. data/vendor/assets/javascripts/ckeditor/plugins/forms/dialogs/textfield.js +9 -9
  209. data/vendor/assets/javascripts/ckeditor/plugins/icons.png +0 -0
  210. data/vendor/assets/javascripts/ckeditor/plugins/icons_hidpi.png +0 -0
  211. data/vendor/assets/javascripts/ckeditor/plugins/iframe/dialogs/iframe.js +9 -8
  212. data/vendor/assets/javascripts/ckeditor/plugins/image/dialogs/image.js +1271 -44
  213. data/vendor/assets/javascripts/ckeditor/plugins/image/icons/hidpi/image.png +0 -0
  214. data/vendor/assets/javascripts/ckeditor/plugins/image/icons/image.png +0 -0
  215. data/vendor/assets/javascripts/ckeditor/plugins/image/lang/en.js +25 -0
  216. data/vendor/assets/javascripts/ckeditor/plugins/image/lang/ru.js +25 -0
  217. data/vendor/assets/javascripts/ckeditor/plugins/image/plugin.js +184 -0
  218. data/vendor/assets/javascripts/ckeditor/plugins/image2/dev/assets/image1.jpg +0 -0
  219. data/vendor/assets/javascripts/ckeditor/plugins/image2/dev/assets/image2.jpg +0 -0
  220. data/vendor/assets/javascripts/ckeditor/plugins/image2/dev/contents.css +35 -0
  221. data/vendor/assets/javascripts/ckeditor/plugins/image2/dev/image2.html +339 -0
  222. data/vendor/assets/javascripts/ckeditor/plugins/image2/dialogs/image2.js +553 -0
  223. data/vendor/assets/javascripts/ckeditor/plugins/image2/icons/hidpi/image.png +0 -0
  224. data/vendor/assets/javascripts/ckeditor/plugins/image2/icons/image.png +0 -0
  225. data/vendor/assets/javascripts/ckeditor/plugins/image2/lang/en.js +21 -0
  226. data/vendor/assets/javascripts/ckeditor/plugins/image2/lang/ru.js +21 -0
  227. data/vendor/assets/javascripts/ckeditor/plugins/image2/plugin.js +1783 -0
  228. data/vendor/assets/javascripts/ckeditor/plugins/image2/samples/assets/image1.jpg +0 -0
  229. data/vendor/assets/javascripts/ckeditor/plugins/image2/samples/assets/image2.jpg +0 -0
  230. data/vendor/assets/javascripts/ckeditor/plugins/image2/samples/image2.html +69 -0
  231. data/vendor/assets/javascripts/ckeditor/plugins/lineheight/plugin.js +1 -1
  232. data/vendor/assets/javascripts/ckeditor/plugins/link/dialogs/anchor.js +5 -5
  233. data/vendor/assets/javascripts/ckeditor/plugins/link/dialogs/link.js +27 -25
  234. data/vendor/assets/javascripts/ckeditor/plugins/liststyle/dialogs/liststyle.js +8 -8
  235. data/vendor/assets/javascripts/ckeditor/plugins/loremipsum/lang/fr.js +8 -0
  236. data/vendor/assets/javascripts/ckeditor/plugins/loremipsum/plugin.js +2 -2
  237. data/vendor/assets/javascripts/ckeditor/plugins/pastefromword/filter/default.js +41 -51
  238. data/vendor/assets/javascripts/ckeditor/plugins/pastetools/filter/common.js +22 -0
  239. data/vendor/assets/javascripts/ckeditor/plugins/pastetools/filter/image.js +6 -0
  240. data/vendor/assets/javascripts/ckeditor/plugins/preview/images/pagebreak.gif +0 -0
  241. data/vendor/assets/javascripts/ckeditor/plugins/preview/styles/screen.css +10 -0
  242. data/vendor/assets/javascripts/ckeditor/plugins/scayt/CHANGELOG.md +1 -17
  243. data/vendor/assets/javascripts/ckeditor/plugins/scayt/README.md +63 -7
  244. data/vendor/assets/javascripts/ckeditor/plugins/scayt/dialogs/options.js +32 -33
  245. data/vendor/assets/javascripts/ckeditor/plugins/smiley/dialogs/smiley.js +2 -2
  246. data/vendor/assets/javascripts/ckeditor/plugins/specialchar/dialogs/lang/en.js +2 -2
  247. data/vendor/assets/javascripts/ckeditor/plugins/specialchar/dialogs/lang/ru.js +2 -2
  248. data/vendor/assets/javascripts/ckeditor/plugins/specialchar/dialogs/specialchar.js +12 -12
  249. data/vendor/assets/javascripts/ckeditor/plugins/stylesheetparser/plugin.js +10 -10
  250. data/vendor/assets/javascripts/ckeditor/plugins/stylesheetparser/samples/stylesheetparser.html +8 -7
  251. data/vendor/assets/javascripts/ckeditor/plugins/table/dialogs/table.js +20 -19
  252. data/vendor/assets/javascripts/ckeditor/plugins/tabletools/dialogs/tableCell.js +16 -15
  253. data/vendor/assets/javascripts/ckeditor/plugins/templates/dialogs/templates.css +2 -2
  254. data/vendor/assets/javascripts/ckeditor/plugins/templates/dialogs/templates.js +2 -2
  255. data/vendor/assets/javascripts/ckeditor/plugins/templates/templates/default.js +2 -2
  256. data/vendor/assets/javascripts/ckeditor/plugins/widget/images/handle.png +0 -0
  257. data/vendor/assets/javascripts/ckeditor/{samples/toolbarconfigurator/lib/codemirror/LICENSE → plugins/wordcount/LICENSE.md} +21 -19
  258. data/vendor/assets/javascripts/ckeditor/plugins/wordcount/README.md +106 -0
  259. data/vendor/assets/javascripts/ckeditor/plugins/wordcount/lang/en.js +1 -0
  260. data/vendor/assets/javascripts/ckeditor/plugins/wordcount/lang/ru.js +2 -1
  261. data/vendor/assets/javascripts/ckeditor/plugins/wordcount/plugin.js +475 -378
  262. data/vendor/assets/javascripts/ckeditor/plugins/wordcount/samples/maxParagraphs.html +26 -0
  263. data/vendor/assets/javascripts/ckeditor/plugins/wsc/README.md +62 -7
  264. data/vendor/assets/javascripts/ckeditor/plugins/wsc/dialogs/tmpFrameset.html +1 -1
  265. data/vendor/assets/javascripts/ckeditor/plugins/wsc/dialogs/wsc.js +82 -82
  266. data/vendor/assets/javascripts/ckeditor/plugins/youtube/LICENSE.md +15 -0
  267. data/vendor/assets/javascripts/ckeditor/plugins/youtube/README.md +156 -0
  268. data/vendor/assets/javascripts/ckeditor/plugins/youtube/plugin.js +8 -7
  269. data/vendor/assets/javascripts/ckeditor/skins/minimalist/editor.css +1 -1
  270. data/vendor/assets/javascripts/ckeditor/skins/minimalist/editor_gecko.css +1 -1
  271. data/vendor/assets/javascripts/ckeditor/skins/minimalist/editor_ie.css +1 -1
  272. data/vendor/assets/javascripts/ckeditor/skins/minimalist/editor_ie7.css +1 -1
  273. data/vendor/assets/javascripts/ckeditor/skins/minimalist/editor_ie8.css +1 -1
  274. data/vendor/assets/javascripts/ckeditor/skins/minimalist/editor_iequirks.css +1 -1
  275. data/vendor/assets/javascripts/ckeditor/skins/minimalist/icons.png +0 -0
  276. data/vendor/assets/javascripts/ckeditor/skins/minimalist/icons_hidpi.png +0 -0
  277. data/vendor/assets/javascripts/ckeditor/skins/moono-lisa/dialog.css +3 -3
  278. data/vendor/assets/javascripts/ckeditor/skins/moono-lisa/dialog_ie.css +3 -3
  279. data/vendor/assets/javascripts/ckeditor/skins/moono-lisa/dialog_ie8.css +3 -3
  280. data/vendor/assets/javascripts/ckeditor/skins/moono-lisa/dialog_iequirks.css +3 -3
  281. data/vendor/assets/javascripts/ckeditor/skins/moono-lisa/editor.css +3 -3
  282. data/vendor/assets/javascripts/ckeditor/skins/moono-lisa/editor_gecko.css +3 -3
  283. data/vendor/assets/javascripts/ckeditor/skins/moono-lisa/editor_ie.css +3 -3
  284. data/vendor/assets/javascripts/ckeditor/skins/moono-lisa/editor_ie8.css +3 -3
  285. data/vendor/assets/javascripts/ckeditor/skins/moono-lisa/editor_iequirks.css +3 -3
  286. data/vendor/assets/javascripts/ckeditor/skins/moono-lisa/readme.md +3 -3
  287. data/vendor/assets/javascripts/ckeditor/skins/moono-lisa/skin.js +2 -2
  288. data/vendor/assets/javascripts/ckeditor/skins/moono/dialog.css +3 -3
  289. data/vendor/assets/javascripts/ckeditor/skins/moono/dialog_ie.css +3 -3
  290. data/vendor/assets/javascripts/ckeditor/skins/moono/dialog_ie7.css +3 -3
  291. data/vendor/assets/javascripts/ckeditor/skins/moono/dialog_ie8.css +3 -3
  292. data/vendor/assets/javascripts/ckeditor/skins/moono/dialog_iequirks.css +3 -3
  293. data/vendor/assets/javascripts/ckeditor/skins/moono/editor.css +3 -3
  294. data/vendor/assets/javascripts/ckeditor/skins/moono/editor_gecko.css +3 -3
  295. data/vendor/assets/javascripts/ckeditor/skins/moono/editor_ie.css +3 -3
  296. data/vendor/assets/javascripts/ckeditor/skins/moono/editor_ie7.css +3 -3
  297. data/vendor/assets/javascripts/ckeditor/skins/moono/editor_ie8.css +3 -3
  298. data/vendor/assets/javascripts/ckeditor/skins/moono/editor_iequirks.css +3 -3
  299. data/vendor/assets/javascripts/ckeditor/skins/moono/readme.md +5 -5
  300. data/vendor/assets/javascripts/ckeditor/skins/moono/skin.js +2 -2
  301. data/vendor/assets/javascripts/ckeditor/styles.js +4 -4
  302. data/vendor/assets/javascripts/ckeditor/vendor/promise.js +13 -0
  303. metadata +143 -138
  304. data/lib/ckeditor/backend/refile.rb +0 -39
  305. data/lib/ckeditor/utils/content_type_detector.rb +0 -38
  306. data/lib/generators/ckeditor/templates/active_record/dragonfly/migration_versioned.rb +0 -23
  307. data/lib/generators/ckeditor/templates/active_record/paperclip/migration_versioned.rb +0 -23
  308. data/lib/generators/ckeditor/templates/active_record/refile/ckeditor/picture.rb +0 -11
  309. data/lib/generators/ckeditor/templates/active_record/refile/migration.rb +0 -23
  310. data/lib/generators/ckeditor/templates/active_record/refile/migration_versioned.rb +0 -23
  311. data/test/support/raw_post.rb +0 -9
  312. data/vendor/assets/javascripts/ckeditor/plugins/iframedialog/plugin.js +0 -169
  313. data/vendor/assets/javascripts/ckeditor/plugins/lineheight/lang/ru.js +0 -3
  314. data/vendor/assets/javascripts/ckeditor/plugins/loremipsum/lang/ru.js +0 -8
  315. data/vendor/assets/javascripts/ckeditor/plugins/notification/lang/en.js +0 -7
  316. data/vendor/assets/javascripts/ckeditor/plugins/notification/lang/ru.js +0 -7
  317. data/vendor/assets/javascripts/ckeditor/plugins/notification/plugin.js +0 -929
  318. data/vendor/assets/javascripts/ckeditor/samples/css/samples.css +0 -1632
  319. data/vendor/assets/javascripts/ckeditor/samples/img/github-top.png +0 -0
  320. data/vendor/assets/javascripts/ckeditor/samples/img/header-bg.png +0 -0
  321. data/vendor/assets/javascripts/ckeditor/samples/img/header-separator.png +0 -0
  322. data/vendor/assets/javascripts/ckeditor/samples/img/logo.png +0 -0
  323. data/vendor/assets/javascripts/ckeditor/samples/img/navigation-tip.png +0 -0
  324. data/vendor/assets/javascripts/ckeditor/samples/index.html +0 -128
  325. data/vendor/assets/javascripts/ckeditor/samples/js/sample.js +0 -53
  326. data/vendor/assets/javascripts/ckeditor/samples/js/sf.js +0 -17
  327. data/vendor/assets/javascripts/ckeditor/samples/old/ajax.html +0 -85
  328. data/vendor/assets/javascripts/ckeditor/samples/old/api.html +0 -210
  329. data/vendor/assets/javascripts/ckeditor/samples/old/appendto.html +0 -59
  330. data/vendor/assets/javascripts/ckeditor/samples/old/assets/inlineall/logo.png +0 -0
  331. data/vendor/assets/javascripts/ckeditor/samples/old/assets/outputxhtml/outputxhtml.css +0 -204
  332. data/vendor/assets/javascripts/ckeditor/samples/old/assets/posteddata.php +0 -59
  333. data/vendor/assets/javascripts/ckeditor/samples/old/assets/sample.jpg +0 -0
  334. data/vendor/assets/javascripts/ckeditor/samples/old/assets/uilanguages/languages.js +0 -7
  335. data/vendor/assets/javascripts/ckeditor/samples/old/datafiltering.html +0 -508
  336. data/vendor/assets/javascripts/ckeditor/samples/old/dialog/assets/my_dialog.js +0 -48
  337. data/vendor/assets/javascripts/ckeditor/samples/old/dialog/dialog.html +0 -190
  338. data/vendor/assets/javascripts/ckeditor/samples/old/divreplace.html +0 -144
  339. data/vendor/assets/javascripts/ckeditor/samples/old/enterkey/enterkey.html +0 -106
  340. data/vendor/assets/javascripts/ckeditor/samples/old/htmlwriter/assets/outputforflash/outputforflash.fla +0 -0
  341. data/vendor/assets/javascripts/ckeditor/samples/old/htmlwriter/assets/outputforflash/outputforflash.swf +0 -0
  342. data/vendor/assets/javascripts/ckeditor/samples/old/htmlwriter/assets/outputforflash/swfobject.js +0 -19
  343. data/vendor/assets/javascripts/ckeditor/samples/old/htmlwriter/outputforflash.html +0 -283
  344. data/vendor/assets/javascripts/ckeditor/samples/old/htmlwriter/outputhtml.html +0 -224
  345. data/vendor/assets/javascripts/ckeditor/samples/old/index.html +0 -131
  346. data/vendor/assets/javascripts/ckeditor/samples/old/inlineall.html +0 -314
  347. data/vendor/assets/javascripts/ckeditor/samples/old/inlinebycode.html +0 -124
  348. data/vendor/assets/javascripts/ckeditor/samples/old/inlinetextarea.html +0 -113
  349. data/vendor/assets/javascripts/ckeditor/samples/old/jquery.html +0 -103
  350. data/vendor/assets/javascripts/ckeditor/samples/old/magicline/magicline.html +0 -209
  351. data/vendor/assets/javascripts/ckeditor/samples/old/readonly.html +0 -76
  352. data/vendor/assets/javascripts/ckeditor/samples/old/replacebyclass.html +0 -60
  353. data/vendor/assets/javascripts/ckeditor/samples/old/replacebycode.html +0 -59
  354. data/vendor/assets/javascripts/ckeditor/samples/old/sample.css +0 -357
  355. data/vendor/assets/javascripts/ckeditor/samples/old/sample.js +0 -50
  356. data/vendor/assets/javascripts/ckeditor/samples/old/sample_posteddata.php +0 -16
  357. data/vendor/assets/javascripts/ckeditor/samples/old/tabindex.html +0 -78
  358. data/vendor/assets/javascripts/ckeditor/samples/old/toolbar/toolbar.html +0 -235
  359. data/vendor/assets/javascripts/ckeditor/samples/old/uicolor.html +0 -72
  360. data/vendor/assets/javascripts/ckeditor/samples/old/uilanguages.html +0 -122
  361. data/vendor/assets/javascripts/ckeditor/samples/old/wysiwygarea/fullpage.html +0 -80
  362. data/vendor/assets/javascripts/ckeditor/samples/old/xhtmlstyle.html +0 -234
  363. data/vendor/assets/javascripts/ckeditor/samples/toolbarconfigurator/css/fontello.css +0 -55
  364. data/vendor/assets/javascripts/ckeditor/samples/toolbarconfigurator/font/LICENSE.txt +0 -10
  365. data/vendor/assets/javascripts/ckeditor/samples/toolbarconfigurator/font/config.json +0 -28
  366. data/vendor/assets/javascripts/ckeditor/samples/toolbarconfigurator/font/fontello.eot +0 -0
  367. data/vendor/assets/javascripts/ckeditor/samples/toolbarconfigurator/font/fontello.svg +0 -14
  368. data/vendor/assets/javascripts/ckeditor/samples/toolbarconfigurator/font/fontello.ttf +0 -0
  369. data/vendor/assets/javascripts/ckeditor/samples/toolbarconfigurator/font/fontello.woff +0 -0
  370. data/vendor/assets/javascripts/ckeditor/samples/toolbarconfigurator/index.html +0 -446
  371. data/vendor/assets/javascripts/ckeditor/samples/toolbarconfigurator/js/abstracttoolbarmodifier.js +0 -13
  372. data/vendor/assets/javascripts/ckeditor/samples/toolbarconfigurator/js/fulltoolbareditor.js +0 -9
  373. data/vendor/assets/javascripts/ckeditor/samples/toolbarconfigurator/js/toolbarmodifier.js +0 -33
  374. data/vendor/assets/javascripts/ckeditor/samples/toolbarconfigurator/js/toolbartextmodifier.js +0 -14
  375. data/vendor/assets/javascripts/ckeditor/samples/toolbarconfigurator/lib/codemirror/codemirror.css +0 -325
  376. data/vendor/assets/javascripts/ckeditor/samples/toolbarconfigurator/lib/codemirror/codemirror.js +0 -288
  377. data/vendor/assets/javascripts/ckeditor/samples/toolbarconfigurator/lib/codemirror/javascript.js +0 -25
  378. data/vendor/assets/javascripts/ckeditor/samples/toolbarconfigurator/lib/codemirror/neo.css +0 -36
  379. data/vendor/assets/javascripts/ckeditor/samples/toolbarconfigurator/lib/codemirror/show-hint.css +0 -38
  380. data/vendor/assets/javascripts/ckeditor/samples/toolbarconfigurator/lib/codemirror/show-hint.js +0 -16
@@ -0,0 +1,21 @@
1
+ /*
2
+ Copyright (c) 2003-2020, CKSource - Frederico Knabben. All rights reserved.
3
+ For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
4
+ */
5
+ CKEDITOR.plugins.setLang( 'image2', 'en', {
6
+ alt: 'Alternative Text',
7
+ btnUpload: 'Send it to the Server',
8
+ captioned: 'Captioned image',
9
+ captionPlaceholder: 'Caption',
10
+ infoTab: 'Image Info',
11
+ lockRatio: 'Lock Ratio',
12
+ menu: 'Image Properties',
13
+ pathName: 'image',
14
+ pathNameCaption: 'caption',
15
+ resetSize: 'Reset Size',
16
+ resizer: 'Click and drag to resize',
17
+ title: 'Image Properties',
18
+ uploadTab: 'Upload',
19
+ urlMissing: 'Image source URL is missing.',
20
+ altMissing: 'Alternative text is missing.'
21
+ } );
@@ -0,0 +1,21 @@
1
+ /*
2
+ Copyright (c) 2003-2020, CKSource - Frederico Knabben. All rights reserved.
3
+ For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
4
+ */
5
+ CKEDITOR.plugins.setLang( 'image2', 'ru', {
6
+ alt: 'Альтернативный текст',
7
+ btnUpload: 'Загрузить на сервер',
8
+ captioned: 'Отображать название',
9
+ captionPlaceholder: 'Название',
10
+ infoTab: 'Данные об изображении',
11
+ lockRatio: 'Сохранять пропорции',
12
+ menu: 'Свойства изображения',
13
+ pathName: 'изображение',
14
+ pathNameCaption: 'название',
15
+ resetSize: 'Вернуть обычные размеры',
16
+ resizer: 'Нажмите и растяните',
17
+ title: 'Свойства изображения',
18
+ uploadTab: 'Загрузка файла',
19
+ urlMissing: 'Не указана ссылка на изображение.',
20
+ altMissing: 'Не задан альтернативный текст'
21
+ } );
@@ -0,0 +1,1783 @@
1
+ /**
2
+ * @license Copyright (c) 2003-2020, CKSource - Frederico Knabben. All rights reserved.
3
+ * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
4
+ */
5
+
6
+ 'use strict';
7
+
8
+ ( function() {
9
+
10
+ var template = '<img alt="" src="" />',
11
+ templateBlock = new CKEDITOR.template(
12
+ '<figure class="{captionedClass}">' +
13
+ template +
14
+ '<figcaption>{captionPlaceholder}</figcaption>' +
15
+ '</figure>' ),
16
+ alignmentsObj = { left: 0, center: 1, right: 2 },
17
+ regexPercent = /^\s*(\d+\%)\s*$/i;
18
+
19
+ CKEDITOR.plugins.add( 'image2', {
20
+ // jscs:disable maximumLineLength
21
+ lang: 'af,ar,az,bg,bn,bs,ca,cs,cy,da,de,de-ch,el,en,en-au,en-ca,en-gb,eo,es,es-mx,et,eu,fa,fi,fo,fr,fr-ca,gl,gu,he,hi,hr,hu,id,is,it,ja,ka,km,ko,ku,lt,lv,mk,mn,ms,nb,nl,no,oc,pl,pt,pt-br,ro,ru,si,sk,sl,sq,sr,sr-latn,sv,th,tr,tt,ug,uk,vi,zh,zh-cn', // %REMOVE_LINE_CORE%
22
+ // jscs:enable maximumLineLength
23
+ requires: 'widget,dialog',
24
+ icons: 'image',
25
+ hidpi: true,
26
+
27
+ onLoad: function() {
28
+ CKEDITOR.addCss(
29
+ '.cke_image_nocaption{' +
30
+ // This is to remove unwanted space so resize
31
+ // wrapper is displayed property.
32
+ 'line-height:0' +
33
+ '}' +
34
+ '.cke_editable.cke_image_sw, .cke_editable.cke_image_sw *{cursor:sw-resize !important}' +
35
+ '.cke_editable.cke_image_se, .cke_editable.cke_image_se *{cursor:se-resize !important}' +
36
+ '.cke_image_resizer{' +
37
+ 'display:none;' +
38
+ 'position:absolute;' +
39
+ 'width:10px;' +
40
+ 'height:10px;' +
41
+ 'bottom:-5px;' +
42
+ 'right:-5px;' +
43
+ 'background:#000;' +
44
+ 'outline:1px solid #fff;' +
45
+ // Prevent drag handler from being misplaced (https://dev.ckeditor.com/ticket/11207).
46
+ 'line-height:0;' +
47
+ 'cursor:se-resize;' +
48
+ '}' +
49
+ '.cke_image_resizer_wrapper{' +
50
+ 'position:relative;' +
51
+ 'display:inline-block;' +
52
+ 'line-height:0;' +
53
+ '}' +
54
+ // Bottom-left corner style of the resizer.
55
+ '.cke_image_resizer.cke_image_resizer_left{' +
56
+ 'right:auto;' +
57
+ 'left:-5px;' +
58
+ 'cursor:sw-resize;' +
59
+ '}' +
60
+ '.cke_widget_wrapper:hover .cke_image_resizer,' +
61
+ '.cke_image_resizer.cke_image_resizing{' +
62
+ 'display:block' +
63
+ '}' +
64
+ // Hide resizer in read only mode (#2816).
65
+ '.cke_editable[contenteditable="false"] .cke_image_resizer{' +
66
+ 'display:none;' +
67
+ '}' +
68
+ // Expand widget wrapper when linked inline image.
69
+ '.cke_widget_wrapper>a{' +
70
+ 'display:inline-block' +
71
+ '}' );
72
+ },
73
+
74
+ init: function( editor ) {
75
+ // Abort when Easyimage is to be loaded since this plugins
76
+ // share the same functionality (#1791).
77
+ if ( editor.plugins.detectConflict( 'image2', [ 'easyimage' ] ) ) {
78
+ return;
79
+ }
80
+
81
+ // Adapts configuration from original image plugin. Should be removed
82
+ // when we'll rename image2 to image.
83
+ var config = editor.config,
84
+ lang = editor.lang.image2,
85
+ image = widgetDef( editor );
86
+
87
+ // Since filebrowser plugin discovers config properties by dialog (plugin?)
88
+ // names (sic!), this hack will be necessary as long as Image2 is not named
89
+ // Image. And since Image2 will never be Image, for sure some filebrowser logic
90
+ // got to be refined.
91
+ config.filebrowserImage2BrowseUrl = config.filebrowserImageBrowseUrl;
92
+ config.filebrowserImage2UploadUrl = config.filebrowserImageUploadUrl;
93
+
94
+ // Add custom elementspath names to widget definition.
95
+ image.pathName = lang.pathName;
96
+ image.editables.caption.pathName = lang.pathNameCaption;
97
+
98
+ // Register the widget.
99
+ editor.widgets.add( 'image', image );
100
+
101
+ // Add toolbar button for this plugin.
102
+ editor.ui.addButton && editor.ui.addButton( 'Image', {
103
+ label: editor.lang.common.image,
104
+ command: 'image',
105
+ toolbar: 'insert,10'
106
+ } );
107
+
108
+ // Register context menu option for editing widget.
109
+ if ( editor.contextMenu ) {
110
+ editor.addMenuGroup( 'image', 10 );
111
+
112
+ editor.addMenuItem( 'image', {
113
+ label: lang.menu,
114
+ command: 'image',
115
+ group: 'image'
116
+ } );
117
+ }
118
+
119
+ CKEDITOR.dialog.add( 'image2', this.path + 'dialogs/image2.js' );
120
+ },
121
+
122
+ afterInit: function( editor ) {
123
+ // Integrate with align commands (justify plugin).
124
+ var align = { left: 1, right: 1, center: 1, block: 1 },
125
+ integrate = alignCommandIntegrator( editor );
126
+
127
+ for ( var value in align )
128
+ integrate( value );
129
+
130
+ // Integrate with link commands (link plugin).
131
+ linkCommandIntegrator( editor );
132
+ }
133
+ } );
134
+
135
+ // Wiget states (forms) depending on alignment and configuration.
136
+ //
137
+ // Non-captioned widget (inline styles)
138
+ // ┌──────┬───────────────────────────────┬─────────────────────────────┐
139
+ // │Align │Internal form │Data │
140
+ // ├──────┼───────────────────────────────┼─────────────────────────────┤
141
+ // │none │<wrapper> │<img /> │
142
+ // │ │ <img /> │ │
143
+ // │ │</wrapper> │ │
144
+ // ├──────┼───────────────────────────────┼─────────────────────────────┤
145
+ // │left │<wrapper style=”float:left”> │<img style=”float:left” /> │
146
+ // │ │ <img /> │ │
147
+ // │ │</wrapper> │ │
148
+ // ├──────┼───────────────────────────────┼─────────────────────────────┤
149
+ // │center│<wrapper> │<p style=”text-align:center”>│
150
+ // │ │ <p style=”text-align:center”> │ <img /> │
151
+ // │ │ <img /> │</p> │
152
+ // │ │ </p> │ │
153
+ // │ │</wrapper> │ │
154
+ // ├──────┼───────────────────────────────┼─────────────────────────────┤
155
+ // │right │<wrapper style=”float:right”> │<img style=”float:right” /> │
156
+ // │ │ <img /> │ │
157
+ // │ │</wrapper> │ │
158
+ // └──────┴───────────────────────────────┴─────────────────────────────┘
159
+ //
160
+ // Non-captioned widget (config.image2_alignClasses defined)
161
+ // ┌──────┬───────────────────────────────┬─────────────────────────────┐
162
+ // │Align │Internal form │Data │
163
+ // ├──────┼───────────────────────────────┼─────────────────────────────┤
164
+ // │none │<wrapper> │<img /> │
165
+ // │ │ <img /> │ │
166
+ // │ │</wrapper> │ │
167
+ // ├──────┼───────────────────────────────┼─────────────────────────────┤
168
+ // │left │<wrapper class=”left”> │<img class=”left” /> │
169
+ // │ │ <img /> │ │
170
+ // │ │</wrapper> │ │
171
+ // ├──────┼───────────────────────────────┼─────────────────────────────┤
172
+ // │center│<wrapper> │<p class=”center”> │
173
+ // │ │ <p class=”center”> │ <img /> │
174
+ // │ │ <img /> │</p> │
175
+ // │ │ </p> │ │
176
+ // │ │</wrapper> │ │
177
+ // ├──────┼───────────────────────────────┼─────────────────────────────┤
178
+ // │right │<wrapper class=”right”> │<img class=”right” /> │
179
+ // │ │ <img /> │ │
180
+ // │ │</wrapper> │ │
181
+ // └──────┴───────────────────────────────┴─────────────────────────────┘
182
+ //
183
+ // Captioned widget (inline styles)
184
+ // ┌──────┬────────────────────────────────────────┬────────────────────────────────────────┐
185
+ // │Align │Internal form │Data │
186
+ // ├──────┼────────────────────────────────────────┼────────────────────────────────────────┤
187
+ // │none │<wrapper> │<figure /> │
188
+ // │ │ <figure /> │ │
189
+ // │ │</wrapper> │ │
190
+ // ├──────┼────────────────────────────────────────┼────────────────────────────────────────┤
191
+ // │left │<wrapper style=”float:left”> │<figure style=”float:left” /> │
192
+ // │ │ <figure /> │ │
193
+ // │ │</wrapper> │ │
194
+ // ├──────┼────────────────────────────────────────┼────────────────────────────────────────┤
195
+ // │center│<wrapper style=”text-align:center”> │<div style=”text-align:center”> │
196
+ // │ │ <figure style=”display:inline-block” />│ <figure style=”display:inline-block” />│
197
+ // │ │</wrapper> │</p> │
198
+ // ├──────┼────────────────────────────────────────┼────────────────────────────────────────┤
199
+ // │right │<wrapper style=”float:right”> │<figure style=”float:right” /> │
200
+ // │ │ <figure /> │ │
201
+ // │ │</wrapper> │ │
202
+ // └──────┴────────────────────────────────────────┴────────────────────────────────────────┘
203
+ //
204
+ // Captioned widget (config.image2_alignClasses defined)
205
+ // ┌──────┬────────────────────────────────────────┬────────────────────────────────────────┐
206
+ // │Align │Internal form │Data │
207
+ // ├──────┼────────────────────────────────────────┼────────────────────────────────────────┤
208
+ // │none │<wrapper> │<figure /> │
209
+ // │ │ <figure /> │ │
210
+ // │ │</wrapper> │ │
211
+ // ├──────┼────────────────────────────────────────┼────────────────────────────────────────┤
212
+ // │left │<wrapper class=”left”> │<figure class=”left” /> │
213
+ // │ │ <figure /> │ │
214
+ // │ │</wrapper> │ │
215
+ // ├──────┼────────────────────────────────────────┼────────────────────────────────────────┤
216
+ // │center│<wrapper class=”center”> │<div class=”center”> │
217
+ // │ │ <figure /> │ <figure /> │
218
+ // │ │</wrapper> │</p> │
219
+ // ├──────┼────────────────────────────────────────┼────────────────────────────────────────┤
220
+ // │right │<wrapper class=”right”> │<figure class=”right” /> │
221
+ // │ │ <figure /> │ │
222
+ // │ │</wrapper> │ │
223
+ // └──────┴────────────────────────────────────────┴────────────────────────────────────────┘
224
+ //
225
+ // @param {CKEDITOR.editor}
226
+ // @returns {Object}
227
+ function widgetDef( editor ) {
228
+ var alignClasses = editor.config.image2_alignClasses,
229
+ captionedClass = editor.config.image2_captionedClass;
230
+
231
+ function deflate() {
232
+ if ( this.deflated )
233
+ return;
234
+
235
+ // Remember whether widget was focused before destroyed.
236
+ if ( editor.widgets.focused == this.widget )
237
+ this.focused = true;
238
+
239
+ editor.widgets.destroy( this.widget );
240
+
241
+ // Mark widget was destroyed.
242
+ this.deflated = true;
243
+ }
244
+
245
+ function inflate() {
246
+ var editable = editor.editable(),
247
+ doc = editor.document;
248
+
249
+ // Create a new widget. This widget will be either captioned
250
+ // non-captioned, block or inline according to what is the
251
+ // new state of the widget.
252
+ if ( this.deflated ) {
253
+ this.widget = editor.widgets.initOn( this.element, 'image', this.widget.data );
254
+
255
+ // Once widget was re-created, it may become an inline element without
256
+ // block wrapper (i.e. when unaligned, end not captioned). Let's do some
257
+ // sort of autoparagraphing here (https://dev.ckeditor.com/ticket/10853).
258
+ if ( this.widget.inline && !( new CKEDITOR.dom.elementPath( this.widget.wrapper, editable ).block ) ) {
259
+ var block = doc.createElement( editor.activeEnterMode == CKEDITOR.ENTER_P ? 'p' : 'div' );
260
+ block.replace( this.widget.wrapper );
261
+ this.widget.wrapper.move( block );
262
+ }
263
+
264
+ // The focus must be transferred from the old one (destroyed)
265
+ // to the new one (just created).
266
+ if ( this.focused ) {
267
+ this.widget.focus();
268
+ delete this.focused;
269
+ }
270
+
271
+ delete this.deflated;
272
+ }
273
+
274
+ // If now widget was destroyed just update wrapper's alignment.
275
+ // According to the new state.
276
+ else {
277
+ setWrapperAlign( this.widget, alignClasses );
278
+ }
279
+ }
280
+
281
+ return {
282
+ allowedContent: getWidgetAllowedContent( editor ),
283
+
284
+ requiredContent: 'img[src,alt]',
285
+
286
+ features: getWidgetFeatures( editor ),
287
+
288
+ styleableElements: 'img figure',
289
+
290
+ // This widget converts style-driven dimensions to attributes.
291
+ contentTransformations: [
292
+ [ 'img[width]: sizeToAttribute' ]
293
+ ],
294
+
295
+ // This widget has an editable caption.
296
+ editables: {
297
+ caption: {
298
+ selector: 'figcaption',
299
+ allowedContent: 'br em strong sub sup u s; a[!href,target]'
300
+ }
301
+ },
302
+
303
+ parts: {
304
+ image: 'img',
305
+ caption: 'figcaption'
306
+ // parts#link defined in widget#init
307
+ },
308
+
309
+ // The name of this widget's dialog.
310
+ dialog: 'image2',
311
+
312
+ // Template of the widget: plain image.
313
+ template: template,
314
+
315
+ data: function() {
316
+ var features = this.features;
317
+
318
+ // Image can't be captioned when figcaption is disallowed (https://dev.ckeditor.com/ticket/11004).
319
+ if ( this.data.hasCaption && !editor.filter.checkFeature( features.caption ) )
320
+ this.data.hasCaption = false;
321
+
322
+ // Image can't be aligned when floating is disallowed (https://dev.ckeditor.com/ticket/11004).
323
+ if ( this.data.align != 'none' && !editor.filter.checkFeature( features.align ) )
324
+ this.data.align = 'none';
325
+
326
+ // Convert the internal form of the widget from the old state to the new one.
327
+ this.shiftState( {
328
+ widget: this,
329
+ element: this.element,
330
+ oldData: this.oldData,
331
+ newData: this.data,
332
+ deflate: deflate,
333
+ inflate: inflate
334
+ } );
335
+
336
+ // Update widget.parts.link since it will not auto-update unless widget
337
+ // is destroyed and re-inited.
338
+ if ( !this.data.link ) {
339
+ if ( this.parts.link )
340
+ delete this.parts.link;
341
+ } else {
342
+ if ( !this.parts.link )
343
+ this.parts.link = this.parts.image.getParent();
344
+ }
345
+
346
+ this.parts.image.setAttributes( {
347
+ src: this.data.src,
348
+
349
+ // This internal is required by the editor.
350
+ 'data-cke-saved-src': this.data.src,
351
+
352
+ alt: this.data.alt
353
+ } );
354
+
355
+ // If shifting non-captioned -> captioned, remove classes
356
+ // related to styles from <img/>.
357
+ if ( this.oldData && !this.oldData.hasCaption && this.data.hasCaption ) {
358
+ for ( var c in this.data.classes )
359
+ this.parts.image.removeClass( c );
360
+ }
361
+
362
+ // Set dimensions of the image according to gathered data.
363
+ // Do it only when the attributes are allowed (https://dev.ckeditor.com/ticket/11004).
364
+ if ( editor.filter.checkFeature( features.dimension ) )
365
+ setDimensions( this );
366
+
367
+ // Cache current data.
368
+ this.oldData = CKEDITOR.tools.extend( {}, this.data );
369
+ },
370
+
371
+ init: function() {
372
+ var helpers = CKEDITOR.plugins.image2,
373
+ image = this.parts.image,
374
+ data = {
375
+ hasCaption: !!this.parts.caption,
376
+ src: image.getAttribute( 'src' ),
377
+ alt: image.getAttribute( 'alt' ) || '',
378
+ width: image.getAttribute( 'width' ) || '',
379
+ height: image.getAttribute( 'height' ) || '',
380
+
381
+ // Lock ratio is on by default (https://dev.ckeditor.com/ticket/10833).
382
+ lock: this.ready ? helpers.checkHasNaturalRatio( image ) : true
383
+ };
384
+
385
+ // If we used 'a' in widget#parts definition, it could happen that
386
+ // selected element is a child of widget.parts#caption. Since there's no clever
387
+ // way to solve it with CSS selectors, it's done like that. (https://dev.ckeditor.com/ticket/11783).
388
+ var link = image.getAscendant( 'a' );
389
+
390
+ if ( link && this.wrapper.contains( link ) )
391
+ this.parts.link = link;
392
+
393
+ // Depending on configuration, read style/class from element and
394
+ // then remove it. Removed style/class will be set on wrapper in #data listener.
395
+ // Note: Center alignment is detected during upcast, so only left/right cases
396
+ // are checked below.
397
+ if ( !data.align ) {
398
+ var alignElement = data.hasCaption ? this.element : image;
399
+
400
+ // Read the initial left/right alignment from the class set on element.
401
+ if ( alignClasses ) {
402
+ if ( alignElement.hasClass( alignClasses[ 0 ] ) ) {
403
+ data.align = 'left';
404
+ } else if ( alignElement.hasClass( alignClasses[ 2 ] ) ) {
405
+ data.align = 'right';
406
+ }
407
+
408
+ if ( data.align ) {
409
+ alignElement.removeClass( alignClasses[ alignmentsObj[ data.align ] ] );
410
+ } else {
411
+ data.align = 'none';
412
+ }
413
+ }
414
+ // Read initial float style from figure/image and then remove it.
415
+ else {
416
+ data.align = alignElement.getStyle( 'float' ) || 'none';
417
+ alignElement.removeStyle( 'float' );
418
+ }
419
+ }
420
+
421
+ // Update data.link object with attributes if the link has been discovered.
422
+ if ( editor.plugins.link && this.parts.link ) {
423
+ data.link = helpers.getLinkAttributesParser()( editor, this.parts.link );
424
+
425
+ // Get rid of cke_widget_* classes in data. Otherwise
426
+ // they might appear in link dialog.
427
+ var advanced = data.link.advanced;
428
+ if ( advanced && advanced.advCSSClasses ) {
429
+ advanced.advCSSClasses = CKEDITOR.tools.trim( advanced.advCSSClasses.replace( /cke_\S+/, '' ) );
430
+ }
431
+ }
432
+
433
+ // Get rid of extra vertical space when there's no caption.
434
+ // It will improve the look of the resizer.
435
+ this.wrapper[ ( data.hasCaption ? 'remove' : 'add' ) + 'Class' ]( 'cke_image_nocaption' );
436
+
437
+ this.setData( data );
438
+
439
+ // Setup dynamic image resizing with mouse.
440
+ // Don't initialize resizer when dimensions are disallowed (https://dev.ckeditor.com/ticket/11004).
441
+ if ( editor.filter.checkFeature( this.features.dimension ) && editor.config.image2_disableResizer !== true ) {
442
+ setupResizer( this );
443
+ }
444
+
445
+ this.shiftState = helpers.stateShifter( this.editor );
446
+
447
+ // Add widget editing option to its context menu.
448
+ this.on( 'contextMenu', function( evt ) {
449
+ evt.data.image = CKEDITOR.TRISTATE_OFF;
450
+
451
+ // Integrate context menu items for link.
452
+ // Note that widget may be wrapped in a link, which
453
+ // does not belong to that widget (https://dev.ckeditor.com/ticket/11814).
454
+ if ( this.parts.link || this.wrapper.getAscendant( 'a' ) )
455
+ evt.data.link = evt.data.unlink = CKEDITOR.TRISTATE_OFF;
456
+ } );
457
+ },
458
+
459
+ // Overrides default method to handle internal mutability of Image2.
460
+ // @see CKEDITOR.plugins.widget#addClass
461
+ addClass: function( className ) {
462
+ getStyleableElement( this ).addClass( className );
463
+ },
464
+
465
+ // Overrides default method to handle internal mutability of Image2.
466
+ // @see CKEDITOR.plugins.widget#hasClass
467
+ hasClass: function( className ) {
468
+ return getStyleableElement( this ).hasClass( className );
469
+ },
470
+
471
+ // Overrides default method to handle internal mutability of Image2.
472
+ // @see CKEDITOR.plugins.widget#removeClass
473
+ removeClass: function( className ) {
474
+ getStyleableElement( this ).removeClass( className );
475
+ },
476
+
477
+ // Overrides default method to handle internal mutability of Image2.
478
+ // @see CKEDITOR.plugins.widget#getClasses
479
+ getClasses: ( function() {
480
+ var classRegex = new RegExp( '^(' + [].concat( captionedClass, alignClasses ).join( '|' ) + ')$' );
481
+
482
+ return function() {
483
+ var classes = this.repository.parseElementClasses( getStyleableElement( this ).getAttribute( 'class' ) );
484
+
485
+ // Neither config.image2_captionedClass nor config.image2_alignClasses
486
+ // do not belong to style classes.
487
+ for ( var c in classes ) {
488
+ if ( classRegex.test( c ) )
489
+ delete classes[ c ];
490
+ }
491
+
492
+ return classes;
493
+ };
494
+ } )(),
495
+
496
+ upcast: upcastWidgetElement( editor ),
497
+ downcast: downcastWidgetElement( editor ),
498
+
499
+ getLabel: function() {
500
+ var label = ( this.data.alt || '' ) + ' ' + this.pathName;
501
+
502
+ return this.editor.lang.widget.label.replace( /%1/, label );
503
+ }
504
+ };
505
+ }
506
+
507
+ /**
508
+ * A set of Enhanced Image (image2) plugin helpers.
509
+ *
510
+ * @class
511
+ * @singleton
512
+ */
513
+ CKEDITOR.plugins.image2 = {
514
+ stateShifter: function( editor ) {
515
+ // Tag name used for centering non-captioned widgets.
516
+ var doc = editor.document,
517
+ alignClasses = editor.config.image2_alignClasses,
518
+ captionedClass = editor.config.image2_captionedClass,
519
+ editable = editor.editable(),
520
+
521
+ // The order that stateActions get executed. It matters!
522
+ shiftables = [ 'hasCaption', 'align', 'link' ];
523
+
524
+ // Atomic procedures, one per state variable.
525
+ var stateActions = {
526
+ align: function( shift, oldValue, newValue ) {
527
+ var el = shift.element;
528
+
529
+ // Alignment changed.
530
+ if ( shift.changed.align ) {
531
+ // No caption in the new state.
532
+ if ( !shift.newData.hasCaption ) {
533
+ // Changed to "center" (non-captioned).
534
+ if ( newValue == 'center' ) {
535
+ shift.deflate();
536
+ shift.element = wrapInCentering( editor, el );
537
+ }
538
+
539
+ // Changed to "non-center" from "center" while caption removed.
540
+ if ( !shift.changed.hasCaption && oldValue == 'center' && newValue != 'center' ) {
541
+ shift.deflate();
542
+ shift.element = unwrapFromCentering( el );
543
+ }
544
+ }
545
+ }
546
+
547
+ // Alignment remains and "center" removed caption.
548
+ else if ( newValue == 'center' && shift.changed.hasCaption && !shift.newData.hasCaption ) {
549
+ shift.deflate();
550
+ shift.element = wrapInCentering( editor, el );
551
+ }
552
+
553
+ // Finally set display for figure.
554
+ if ( !alignClasses && el.is( 'figure' ) ) {
555
+ if ( newValue == 'center' )
556
+ el.setStyle( 'display', 'inline-block' );
557
+ else
558
+ el.removeStyle( 'display' );
559
+ }
560
+ },
561
+
562
+ hasCaption: function( shift, oldValue, newValue ) {
563
+ // This action is for real state change only.
564
+ if ( !shift.changed.hasCaption )
565
+ return;
566
+
567
+ // Get <img/> or <a><img/></a> from widget. Note that widget element might itself
568
+ // be what we're looking for. Also element can be <p style="text-align:center"><a>...</a></p>.
569
+ var imageOrLink;
570
+ if ( shift.element.is( { img: 1, a: 1 } ) )
571
+ imageOrLink = shift.element;
572
+ else
573
+ imageOrLink = shift.element.findOne( 'a,img' );
574
+
575
+ // Switching hasCaption always destroys the widget.
576
+ shift.deflate();
577
+
578
+ // There was no caption, but the caption is to be added.
579
+ if ( newValue ) {
580
+ // Create new <figure> from widget template.
581
+ var figure = CKEDITOR.dom.element.createFromHtml( templateBlock.output( {
582
+ captionedClass: captionedClass,
583
+ captionPlaceholder: editor.lang.image2.captionPlaceholder
584
+ } ), doc );
585
+
586
+ // Replace element with <figure>.
587
+ replaceSafely( figure, shift.element );
588
+
589
+ // Use old <img/> or <a><img/></a> instead of the one from the template,
590
+ // so we won't lose additional attributes.
591
+ imageOrLink.replace( figure.findOne( 'img' ) );
592
+
593
+ // Update widget's element.
594
+ shift.element = figure;
595
+ }
596
+
597
+ // The caption was present, but now it's to be removed.
598
+ else {
599
+ // Unwrap <img/> or <a><img/></a> from figure.
600
+ imageOrLink.replace( shift.element );
601
+
602
+ // Update widget's element.
603
+ shift.element = imageOrLink;
604
+ }
605
+ },
606
+
607
+ link: function( shift, oldValue, newValue ) {
608
+ if ( shift.changed.link ) {
609
+ var img = shift.element.is( 'img' ) ?
610
+ shift.element : shift.element.findOne( 'img' ),
611
+ link = shift.element.is( 'a' ) ?
612
+ shift.element : shift.element.findOne( 'a' ),
613
+ // Why deflate:
614
+ // If element is <img/>, it will be wrapped into <a>,
615
+ // which becomes a new widget.element.
616
+ // If element is <a><img/></a>, it will be unlinked
617
+ // so <img/> becomes a new widget.element.
618
+ needsDeflate = ( shift.element.is( 'a' ) && !newValue ) || ( shift.element.is( 'img' ) && newValue ),
619
+ newEl;
620
+
621
+ if ( needsDeflate )
622
+ shift.deflate();
623
+
624
+ // If unlinked the image, returned element is <img>.
625
+ if ( !newValue )
626
+ newEl = unwrapFromLink( link );
627
+ else {
628
+ // If linked the image, returned element is <a>.
629
+ if ( !oldValue )
630
+ newEl = wrapInLink( img, shift.newData.link );
631
+
632
+ // Set and remove all attributes associated with this state.
633
+ var attributes = CKEDITOR.plugins.image2.getLinkAttributesGetter()( editor, newValue );
634
+
635
+ if ( !CKEDITOR.tools.isEmpty( attributes.set ) )
636
+ ( newEl || link ).setAttributes( attributes.set );
637
+
638
+ if ( attributes.removed.length )
639
+ ( newEl || link ).removeAttributes( attributes.removed );
640
+ }
641
+
642
+ if ( needsDeflate )
643
+ shift.element = newEl;
644
+ }
645
+ }
646
+ };
647
+
648
+ function wrapInCentering( editor, element ) {
649
+ var attribsAndStyles = {};
650
+
651
+ if ( alignClasses )
652
+ attribsAndStyles.attributes = { 'class': alignClasses[ 1 ] };
653
+ else
654
+ attribsAndStyles.styles = { 'text-align': 'center' };
655
+
656
+ // There's no gentle way to center inline element with CSS, so create p/div
657
+ // that wraps widget contents and does the trick either with style or class.
658
+ var center = doc.createElement(
659
+ editor.activeEnterMode == CKEDITOR.ENTER_P ? 'p' : 'div', attribsAndStyles );
660
+
661
+ // Replace element with centering wrapper.
662
+ replaceSafely( center, element );
663
+ element.move( center );
664
+
665
+ return center;
666
+ }
667
+
668
+ function unwrapFromCentering( element ) {
669
+ var imageOrLink = element.findOne( 'a,img' );
670
+
671
+ imageOrLink.replace( element );
672
+
673
+ return imageOrLink;
674
+ }
675
+
676
+ // Wraps <img/> -> <a><img/></a>.
677
+ // Returns reference to <a>.
678
+ //
679
+ // @param {CKEDITOR.dom.element} img
680
+ // @param {Object} linkData
681
+ // @returns {CKEDITOR.dom.element}
682
+ function wrapInLink( img, linkData ) {
683
+ var link = doc.createElement( 'a', {
684
+ attributes: {
685
+ href: linkData.url
686
+ }
687
+ } );
688
+
689
+ link.replace( img );
690
+ img.move( link );
691
+
692
+ return link;
693
+ }
694
+
695
+ // De-wraps <a><img/></a> -> <img/>.
696
+ // Returns the reference to <img/>
697
+ //
698
+ // @param {CKEDITOR.dom.element} link
699
+ // @returns {CKEDITOR.dom.element}
700
+ function unwrapFromLink( link ) {
701
+ var img = link.findOne( 'img' );
702
+
703
+ img.replace( link );
704
+
705
+ return img;
706
+ }
707
+
708
+ function replaceSafely( replacing, replaced ) {
709
+ if ( replaced.getParent() ) {
710
+ var range = editor.createRange();
711
+
712
+ range.moveToPosition( replaced, CKEDITOR.POSITION_BEFORE_START );
713
+
714
+ // Remove old element. Do it before insertion to avoid a case when
715
+ // element is moved from 'replaced' element before it, what creates
716
+ // a tricky case which insertElementIntorRange does not handle.
717
+ replaced.remove();
718
+
719
+ editable.insertElementIntoRange( replacing, range );
720
+ }
721
+ else {
722
+ replacing.replace( replaced );
723
+ }
724
+ }
725
+
726
+ return function( shift ) {
727
+ var name, i;
728
+
729
+ shift.changed = {};
730
+
731
+ for ( i = 0; i < shiftables.length; i++ ) {
732
+ name = shiftables[ i ];
733
+
734
+ shift.changed[ name ] = shift.oldData ?
735
+ shift.oldData[ name ] !== shift.newData[ name ] : false;
736
+ }
737
+
738
+ // Iterate over possible state variables.
739
+ for ( i = 0; i < shiftables.length; i++ ) {
740
+ name = shiftables[ i ];
741
+
742
+ stateActions[ name ]( shift,
743
+ shift.oldData ? shift.oldData[ name ] : null,
744
+ shift.newData[ name ] );
745
+ }
746
+
747
+ shift.inflate();
748
+ };
749
+ },
750
+
751
+ /**
752
+ * Checks whether the current image ratio matches the natural one
753
+ * by comparing dimensions.
754
+ *
755
+ * @param {CKEDITOR.dom.element} image
756
+ * @returns {Boolean}
757
+ */
758
+ checkHasNaturalRatio: function( image ) {
759
+ var $ = image.$,
760
+ natural = this.getNatural( image );
761
+
762
+ // The reason for two alternative comparisons is that the rounding can come from
763
+ // both dimensions, e.g. there are two cases:
764
+ // 1. height is computed as a rounded relation of the real height and the value of width,
765
+ // 2. width is computed as a rounded relation of the real width and the value of heigh.
766
+ return Math.round( $.clientWidth / natural.width * natural.height ) == $.clientHeight ||
767
+ Math.round( $.clientHeight / natural.height * natural.width ) == $.clientWidth;
768
+ },
769
+
770
+ /**
771
+ * Returns natural dimensions of the image. For modern browsers
772
+ * it uses natural(Width|Height). For old ones (IE8) it creates
773
+ * a new image and reads the dimensions.
774
+ *
775
+ * @param {CKEDITOR.dom.element} image
776
+ * @returns {Object}
777
+ */
778
+ getNatural: function( image ) {
779
+ var dimensions;
780
+
781
+ if ( image.$.naturalWidth ) {
782
+ dimensions = {
783
+ width: image.$.naturalWidth,
784
+ height: image.$.naturalHeight
785
+ };
786
+ } else {
787
+ var img = new Image();
788
+ img.src = image.getAttribute( 'src' );
789
+
790
+ dimensions = {
791
+ width: img.width,
792
+ height: img.height
793
+ };
794
+ }
795
+
796
+ return dimensions;
797
+ },
798
+
799
+ /**
800
+ * Returns an attribute getter function. Default getter comes from the Link plugin
801
+ * and is documented by {@link CKEDITOR.plugins.link#getLinkAttributes}.
802
+ *
803
+ * **Note:** It is possible to override this method and use a custom getter e.g.
804
+ * in the absence of the Link plugin.
805
+ *
806
+ * **Note:** If a custom getter is used, a data model format it produces
807
+ * must be compatible with {@link CKEDITOR.plugins.link#getLinkAttributes}.
808
+ *
809
+ * **Note:** A custom getter must understand the data model format produced by
810
+ * {@link #getLinkAttributesParser} to work correctly.
811
+ *
812
+ * @returns {Function} A function that gets (composes) link attributes.
813
+ * @since 4.5.5
814
+ */
815
+ getLinkAttributesGetter: function() {
816
+ // https://dev.ckeditor.com/ticket/13885
817
+ return CKEDITOR.plugins.link.getLinkAttributes;
818
+ },
819
+
820
+ /**
821
+ * Returns an attribute parser function. Default parser comes from the Link plugin
822
+ * and is documented by {@link CKEDITOR.plugins.link#parseLinkAttributes}.
823
+ *
824
+ * **Note:** It is possible to override this method and use a custom parser e.g.
825
+ * in the absence of the Link plugin.
826
+ *
827
+ * **Note:** If a custom parser is used, a data model format produced by the parser
828
+ * must be compatible with {@link #getLinkAttributesGetter}.
829
+ *
830
+ * **Note:** If a custom parser is used, it should be compatible with the
831
+ * {@link CKEDITOR.plugins.link#parseLinkAttributes} data model format. Otherwise the
832
+ * Link plugin dialog may not be populated correctly with parsed data. However
833
+ * as long as Enhanced Image is **not** used with the Link plugin dialog, any custom data model
834
+ * will work, being stored as an internal property of Enhanced Image widget's data only.
835
+ *
836
+ * @returns {Function} A function that parses attributes.
837
+ * @since 4.5.5
838
+ */
839
+ getLinkAttributesParser: function() {
840
+ // https://dev.ckeditor.com/ticket/13885
841
+ return CKEDITOR.plugins.link.parseLinkAttributes;
842
+ }
843
+ };
844
+
845
+ function setWrapperAlign( widget, alignClasses ) {
846
+ var wrapper = widget.wrapper,
847
+ align = widget.data.align,
848
+ hasCaption = widget.data.hasCaption;
849
+
850
+ if ( alignClasses ) {
851
+ // Remove all align classes first.
852
+ for ( var i = 3; i--; )
853
+ wrapper.removeClass( alignClasses[ i ] );
854
+
855
+ if ( align == 'center' ) {
856
+ // Avoid touching non-captioned, centered widgets because
857
+ // they have the class set on the element instead of wrapper:
858
+ //
859
+ // <div class="cke_widget_wrapper">
860
+ // <p class="center-class">
861
+ // <img />
862
+ // </p>
863
+ // </div>
864
+ if ( hasCaption ) {
865
+ wrapper.addClass( alignClasses[ 1 ] );
866
+ }
867
+ } else if ( align != 'none' ) {
868
+ wrapper.addClass( alignClasses[ alignmentsObj[ align ] ] );
869
+ }
870
+ } else {
871
+ if ( align == 'center' ) {
872
+ if ( hasCaption )
873
+ wrapper.setStyle( 'text-align', 'center' );
874
+ else
875
+ wrapper.removeStyle( 'text-align' );
876
+
877
+ wrapper.removeStyle( 'float' );
878
+ }
879
+ else {
880
+ if ( align == 'none' )
881
+ wrapper.removeStyle( 'float' );
882
+ else
883
+ wrapper.setStyle( 'float', align );
884
+
885
+ wrapper.removeStyle( 'text-align' );
886
+ }
887
+ }
888
+ }
889
+
890
+ // Returns a function that creates widgets from all <img> and
891
+ // <figure class="{config.image2_captionedClass}"> elements.
892
+ //
893
+ // @param {CKEDITOR.editor} editor
894
+ // @returns {Function}
895
+ function upcastWidgetElement( editor ) {
896
+ var isCenterWrapper = centerWrapperChecker( editor ),
897
+ captionedClass = editor.config.image2_captionedClass;
898
+
899
+ // @param {CKEDITOR.htmlParser.element} el
900
+ // @param {Object} data
901
+ return function( el, data ) {
902
+ var dimensions = { width: 1, height: 1 },
903
+ name = el.name,
904
+ image;
905
+
906
+ // https://dev.ckeditor.com/ticket/11110 Don't initialize on pasted fake objects.
907
+ if ( el.attributes[ 'data-cke-realelement' ] )
908
+ return;
909
+
910
+ // If a center wrapper is found, there are 3 possible cases:
911
+ //
912
+ // 1. <div style="text-align:center"><figure>...</figure></div>.
913
+ // In this case centering is done with a class set on widget.wrapper.
914
+ // Simply replace centering wrapper with figure (it's no longer necessary).
915
+ //
916
+ // 2. <p style="text-align:center"><img/></p>.
917
+ // Nothing to do here: <p> remains for styling purposes.
918
+ //
919
+ // 3. <div style="text-align:center"><img/></div>.
920
+ // Nothing to do here (2.) but that case is only possible in enterMode different
921
+ // than ENTER_P.
922
+ if ( isCenterWrapper( el ) ) {
923
+ if ( name == 'div' ) {
924
+ var figure = el.getFirst( 'figure' );
925
+
926
+ // Case #1.
927
+ if ( figure ) {
928
+ el.replaceWith( figure );
929
+ el = figure;
930
+ }
931
+ }
932
+ // Cases #2 and #3 (handled transparently)
933
+
934
+ // If there's a centering wrapper, save it in data.
935
+ data.align = 'center';
936
+
937
+ // Image can be wrapped in link <a><img/></a>.
938
+ image = el.getFirst( 'img' ) || el.getFirst( 'a' ).getFirst( 'img' );
939
+ }
940
+
941
+ // No center wrapper has been found.
942
+ else if ( name == 'figure' && el.hasClass( captionedClass ) ) {
943
+ image = el.find( function( child ) {
944
+ return child.name === 'img' &&
945
+ CKEDITOR.tools.array.indexOf( [ 'figure', 'a' ], child.parent.name ) !== -1;
946
+ }, true )[ 0 ];
947
+
948
+ // Upcast linked image like <a><img/></a>.
949
+ } else if ( isLinkedOrStandaloneImage( el ) ) {
950
+ image = el.name == 'a' ? el.children[ 0 ] : el;
951
+ }
952
+
953
+ if ( !image )
954
+ return;
955
+
956
+ // If there's an image, then cool, we got a widget.
957
+ // Now just remove dimension attributes expressed with %.
958
+ for ( var d in dimensions ) {
959
+ var dimension = image.attributes[ d ];
960
+
961
+ if ( dimension && dimension.match( regexPercent ) )
962
+ delete image.attributes[ d ];
963
+ }
964
+
965
+ return el;
966
+ };
967
+ }
968
+
969
+ // Returns a function which transforms the widget to the external format
970
+ // according to the current configuration.
971
+ //
972
+ // @param {CKEDITOR.editor}
973
+ function downcastWidgetElement( editor ) {
974
+ var alignClasses = editor.config.image2_alignClasses;
975
+
976
+ // @param {CKEDITOR.htmlParser.element} el
977
+ return function( el ) {
978
+ // In case of <a><img/></a>, <img/> is the element to hold
979
+ // inline styles or classes (image2_alignClasses).
980
+ var attrsHolder = el.name == 'a' ? el.getFirst() : el,
981
+ attrs = attrsHolder.attributes,
982
+ align = this.data.align;
983
+
984
+ // De-wrap the image from resize handle wrapper.
985
+ // Only block widgets have one.
986
+ if ( !this.inline ) {
987
+ var resizeWrapper = el.getFirst( 'span' );
988
+
989
+ if ( resizeWrapper )
990
+ resizeWrapper.replaceWith( resizeWrapper.getFirst( { img: 1, a: 1 } ) );
991
+ }
992
+
993
+ if ( align && align != 'none' ) {
994
+ var styles = CKEDITOR.tools.parseCssText( attrs.style || '' );
995
+
996
+ // When the widget is captioned (<figure>) and internally centering is done
997
+ // with widget's wrapper style/class, in the external data representation,
998
+ // <figure> must be wrapped with an element holding an style/class:
999
+ //
1000
+ // <div style="text-align:center">
1001
+ // <figure class="image" style="display:inline-block">...</figure>
1002
+ // </div>
1003
+ // or
1004
+ // <div class="some-center-class">
1005
+ // <figure class="image">...</figure>
1006
+ // </div>
1007
+ //
1008
+ if ( align == 'center' && el.name == 'figure' ) {
1009
+ el = el.wrapWith( new CKEDITOR.htmlParser.element( 'div',
1010
+ alignClasses ? { 'class': alignClasses[ 1 ] } : { style: 'text-align:center' } ) );
1011
+ }
1012
+
1013
+ // If left/right, add float style to the downcasted element.
1014
+ else if ( align in { left: 1, right: 1 } ) {
1015
+ if ( alignClasses )
1016
+ attrsHolder.addClass( alignClasses[ alignmentsObj[ align ] ] );
1017
+ else
1018
+ styles[ 'float' ] = align;
1019
+ }
1020
+
1021
+ // Update element styles.
1022
+ if ( !alignClasses && !CKEDITOR.tools.isEmpty( styles ) )
1023
+ attrs.style = CKEDITOR.tools.writeCssText( styles );
1024
+ }
1025
+
1026
+ return el;
1027
+ };
1028
+ }
1029
+
1030
+ // Returns a function that checks if an element is a centering wrapper.
1031
+ //
1032
+ // @param {CKEDITOR.editor} editor
1033
+ // @returns {Function}
1034
+ function centerWrapperChecker( editor ) {
1035
+ var captionedClass = editor.config.image2_captionedClass,
1036
+ alignClasses = editor.config.image2_alignClasses,
1037
+ validChildren = { figure: 1, a: 1, img: 1 };
1038
+
1039
+ return function( el ) {
1040
+ // Wrapper must be either <div> or <p>.
1041
+ if ( !( el.name in { div: 1, p: 1 } ) )
1042
+ return false;
1043
+
1044
+ var children = el.children;
1045
+
1046
+ // Centering wrapper can have only one child.
1047
+ if ( children.length !== 1 )
1048
+ return false;
1049
+
1050
+ var child = children[ 0 ];
1051
+
1052
+ // Only <figure> or <img /> can be first (only) child of centering wrapper,
1053
+ // regardless of its type.
1054
+ if ( !( child.name in validChildren ) )
1055
+ return false;
1056
+
1057
+ // If centering wrapper is <p>, only <img /> can be the child.
1058
+ // <p style="text-align:center"><img /></p>
1059
+ if ( el.name == 'p' ) {
1060
+ if ( !isLinkedOrStandaloneImage( child ) )
1061
+ return false;
1062
+ }
1063
+ // Centering <div> can hold <img/> or <figure>, depending on enterMode.
1064
+ else {
1065
+ // If a <figure> is the first (only) child, it must have a class.
1066
+ // <div style="text-align:center"><figure>...</figure><div>
1067
+ if ( child.name == 'figure' ) {
1068
+ if ( !child.hasClass( captionedClass ) )
1069
+ return false;
1070
+ } else {
1071
+ // Centering <div> can hold <img/> or <a><img/></a> only when enterMode
1072
+ // is ENTER_(BR|DIV).
1073
+ // <div style="text-align:center"><img /></div>
1074
+ // <div style="text-align:center"><a><img /></a></div>
1075
+ if ( editor.enterMode == CKEDITOR.ENTER_P )
1076
+ return false;
1077
+
1078
+ // Regardless of enterMode, a child which is not <figure> must be
1079
+ // either <img/> or <a><img/></a>.
1080
+ if ( !isLinkedOrStandaloneImage( child ) )
1081
+ return false;
1082
+ }
1083
+ }
1084
+
1085
+ // Centering wrapper got to be... centering. If image2_alignClasses are defined,
1086
+ // check for centering class. Otherwise, check the style.
1087
+ if ( alignClasses ? el.hasClass( alignClasses[ 1 ] ) :
1088
+ CKEDITOR.tools.parseCssText( el.attributes.style || '', true )[ 'text-align' ] == 'center' )
1089
+ return true;
1090
+
1091
+ return false;
1092
+ };
1093
+ }
1094
+
1095
+ // Checks whether element is <img/> or <a><img/></a>.
1096
+ //
1097
+ // @param {CKEDITOR.htmlParser.element}
1098
+ function isLinkedOrStandaloneImage( el ) {
1099
+ if ( el.name == 'img' )
1100
+ return true;
1101
+ else if ( el.name == 'a' )
1102
+ return el.children.length == 1 && el.getFirst( 'img' );
1103
+
1104
+ return false;
1105
+ }
1106
+
1107
+ // Sets width and height of the widget image according to current widget data.
1108
+ //
1109
+ // @param {CKEDITOR.plugins.widget} widget
1110
+ function setDimensions( widget ) {
1111
+ var data = widget.data,
1112
+ dimensions = { width: data.width, height: data.height },
1113
+ image = widget.parts.image;
1114
+
1115
+ for ( var d in dimensions ) {
1116
+ if ( dimensions[ d ] )
1117
+ image.setAttribute( d, dimensions[ d ] );
1118
+ else
1119
+ image.removeAttribute( d );
1120
+ }
1121
+ }
1122
+
1123
+ // Defines all features related to drag-driven image resizing.
1124
+ //
1125
+ // @param {CKEDITOR.plugins.widget} widget
1126
+ function setupResizer( widget ) {
1127
+ var editor = widget.editor,
1128
+ editable = editor.editable(),
1129
+ doc = editor.document,
1130
+
1131
+ // Store the resizer in a widget for testing (https://dev.ckeditor.com/ticket/11004).
1132
+ resizer = widget.resizer = doc.createElement( 'span' );
1133
+
1134
+ resizer.addClass( 'cke_image_resizer' );
1135
+ resizer.setAttribute( 'title', editor.lang.image2.resizer );
1136
+ resizer.append( new CKEDITOR.dom.text( '\u200b', doc ) );
1137
+
1138
+ // Inline widgets don't need a resizer wrapper as an image spans the entire widget.
1139
+ if ( !widget.inline ) {
1140
+ var imageOrLink = widget.parts.link || widget.parts.image,
1141
+ oldResizeWrapper = imageOrLink.getParent(),
1142
+ resizeWrapper = doc.createElement( 'span' );
1143
+
1144
+ resizeWrapper.addClass( 'cke_image_resizer_wrapper' );
1145
+ resizeWrapper.append( imageOrLink );
1146
+ resizeWrapper.append( resizer );
1147
+ widget.element.append( resizeWrapper, true );
1148
+
1149
+ // Remove the old wrapper which could came from e.g. pasted HTML
1150
+ // and which could be corrupted (e.g. resizer span has been lost).
1151
+ if ( oldResizeWrapper.is( 'span' ) )
1152
+ oldResizeWrapper.remove();
1153
+ } else {
1154
+ widget.wrapper.append( resizer );
1155
+ }
1156
+
1157
+ // Calculate values of size variables and mouse offsets.
1158
+ resizer.on( 'mousedown', function( evt ) {
1159
+ var image = widget.parts.image,
1160
+
1161
+ // Don't update attributes if less than 15.
1162
+ // This is to prevent images to visually disappear.
1163
+ min = {
1164
+ width: 15,
1165
+ height: 15
1166
+ },
1167
+
1168
+ max = getMaxSize(),
1169
+
1170
+ // "factor" can be either 1 or -1. I.e.: For right-aligned images, we need to
1171
+ // subtract the difference to get proper width, etc. Without "factor",
1172
+ // resizer starts working the opposite way.
1173
+ factor = widget.data.align == 'right' ? -1 : 1,
1174
+
1175
+ // The x-coordinate of the mouse relative to the screen
1176
+ // when button gets pressed.
1177
+ startX = evt.data.$.screenX,
1178
+ startY = evt.data.$.screenY,
1179
+
1180
+ // The initial dimensions and aspect ratio of the image.
1181
+ startWidth = image.$.clientWidth,
1182
+ startHeight = image.$.clientHeight,
1183
+ ratio = startWidth / startHeight,
1184
+
1185
+ listeners = [],
1186
+
1187
+ // A class applied to editable during resizing.
1188
+ cursorClass = 'cke_image_s' + ( !~factor ? 'w' : 'e' ),
1189
+
1190
+ nativeEvt, newWidth, newHeight, updateData,
1191
+ moveDiffX, moveDiffY, moveRatio;
1192
+
1193
+ // Save the undo snapshot first: before resizing.
1194
+ editor.fire( 'saveSnapshot' );
1195
+
1196
+ // Mousemove listeners are removed on mouseup.
1197
+ attachToDocuments( 'mousemove', onMouseMove, listeners );
1198
+
1199
+ // Clean up the mousemove listener. Update widget data if valid.
1200
+ attachToDocuments( 'mouseup', onMouseUp, listeners );
1201
+
1202
+ // The entire editable will have the special cursor while resizing goes on.
1203
+ editable.addClass( cursorClass );
1204
+
1205
+ // This is to always keep the resizer element visible while resizing.
1206
+ resizer.addClass( 'cke_image_resizing' );
1207
+
1208
+ // Attaches an event to a global document if inline editor.
1209
+ // Additionally, if classic (`iframe`-based) editor, also attaches the same event to `iframe`'s document.
1210
+ function attachToDocuments( name, callback, collection ) {
1211
+ var globalDoc = CKEDITOR.document,
1212
+ listeners = [];
1213
+
1214
+ if ( !doc.equals( globalDoc ) )
1215
+ listeners.push( globalDoc.on( name, callback ) );
1216
+
1217
+ listeners.push( doc.on( name, callback ) );
1218
+
1219
+ if ( collection ) {
1220
+ for ( var i = listeners.length; i--; )
1221
+ collection.push( listeners.pop() );
1222
+ }
1223
+ }
1224
+
1225
+ // Calculate with first, and then adjust height, preserving ratio.
1226
+ function adjustToX() {
1227
+ newWidth = startWidth + factor * moveDiffX;
1228
+ newHeight = Math.round( newWidth / ratio );
1229
+ }
1230
+
1231
+ // Calculate height first, and then adjust width, preserving ratio.
1232
+ function adjustToY() {
1233
+ newHeight = startHeight - moveDiffY;
1234
+ newWidth = Math.round( newHeight * ratio );
1235
+ }
1236
+
1237
+ // This is how variables refer to the geometry.
1238
+ // Note: x corresponds to moveOffset, this is the position of mouse
1239
+ // Note: o corresponds to [startX, startY].
1240
+ //
1241
+ // +--------------+--------------+
1242
+ // | | |
1243
+ // | I | II |
1244
+ // | | |
1245
+ // +------------- o -------------+ _ _ _
1246
+ // | | | ^
1247
+ // | VI | III | | moveDiffY
1248
+ // | | x _ _ _ _ _ v
1249
+ // +--------------+---------|----+
1250
+ // | |
1251
+ // <------->
1252
+ // moveDiffX
1253
+ function onMouseMove( evt ) {
1254
+ nativeEvt = evt.data.$;
1255
+
1256
+ // This is how far the mouse is from the point the button was pressed.
1257
+ moveDiffX = nativeEvt.screenX - startX;
1258
+ moveDiffY = startY - nativeEvt.screenY;
1259
+
1260
+ // This is the aspect ratio of the move difference.
1261
+ moveRatio = Math.abs( moveDiffX / moveDiffY );
1262
+
1263
+ // Left, center or none-aligned widget.
1264
+ if ( factor == 1 ) {
1265
+ if ( moveDiffX <= 0 ) {
1266
+ // Case: IV.
1267
+ if ( moveDiffY <= 0 )
1268
+ adjustToX();
1269
+
1270
+ // Case: I.
1271
+ else {
1272
+ if ( moveRatio >= ratio )
1273
+ adjustToX();
1274
+ else
1275
+ adjustToY();
1276
+ }
1277
+ } else {
1278
+ // Case: III.
1279
+ if ( moveDiffY <= 0 ) {
1280
+ if ( moveRatio >= ratio )
1281
+ adjustToY();
1282
+ else
1283
+ adjustToX();
1284
+ }
1285
+
1286
+ // Case: II.
1287
+ else {
1288
+ adjustToY();
1289
+ }
1290
+ }
1291
+ }
1292
+
1293
+ // Right-aligned widget. It mirrors behaviours, so I becomes II,
1294
+ // IV becomes III and vice-versa.
1295
+ else {
1296
+ if ( moveDiffX <= 0 ) {
1297
+ // Case: IV.
1298
+ if ( moveDiffY <= 0 ) {
1299
+ if ( moveRatio >= ratio )
1300
+ adjustToY();
1301
+ else
1302
+ adjustToX();
1303
+ }
1304
+
1305
+ // Case: I.
1306
+ else {
1307
+ adjustToY();
1308
+ }
1309
+ } else {
1310
+ // Case: III.
1311
+ if ( moveDiffY <= 0 )
1312
+ adjustToX();
1313
+
1314
+ // Case: II.
1315
+ else {
1316
+ if ( moveRatio >= ratio ) {
1317
+ adjustToX();
1318
+ } else {
1319
+ adjustToY();
1320
+ }
1321
+ }
1322
+ }
1323
+ }
1324
+
1325
+ if ( isAllowedSize( newWidth, newHeight ) ) {
1326
+ updateData = { width: newWidth, height: newHeight };
1327
+ image.setAttributes( updateData );
1328
+ }
1329
+ }
1330
+
1331
+ function onMouseUp() {
1332
+ var l;
1333
+
1334
+ while ( ( l = listeners.pop() ) )
1335
+ l.removeListener();
1336
+
1337
+ // Restore default cursor by removing special class.
1338
+ editable.removeClass( cursorClass );
1339
+
1340
+ // This is to bring back the regular behaviour of the resizer.
1341
+ resizer.removeClass( 'cke_image_resizing' );
1342
+
1343
+ if ( updateData ) {
1344
+ widget.setData( updateData );
1345
+
1346
+ // Save another undo snapshot: after resizing.
1347
+ editor.fire( 'saveSnapshot' );
1348
+ }
1349
+
1350
+ // Don't update data twice or more.
1351
+ updateData = false;
1352
+ }
1353
+
1354
+ function getMaxSize() {
1355
+ var maxSize = editor.config.image2_maxSize,
1356
+ natural;
1357
+
1358
+ if ( !maxSize ) {
1359
+ return null;
1360
+ }
1361
+
1362
+ maxSize = CKEDITOR.tools.copy( maxSize );
1363
+ natural = CKEDITOR.plugins.image2.getNatural( image );
1364
+
1365
+ maxSize.width = Math.max( maxSize.width === 'natural' ? natural.width : maxSize.width, min.width );
1366
+ maxSize.height = Math.max( maxSize.height === 'natural' ? natural.height : maxSize.height, min.width );
1367
+
1368
+ return maxSize;
1369
+ }
1370
+
1371
+ function isAllowedSize( width, height ) {
1372
+ var isTooSmall = width < min.width || height < min.height,
1373
+ isTooBig = max && ( width > max.width || height > max.height );
1374
+ return !isTooSmall && !isTooBig;
1375
+ }
1376
+ } );
1377
+
1378
+ // Change the position of the widget resizer when data changes.
1379
+ widget.on( 'data', function() {
1380
+ resizer[ widget.data.align == 'right' ? 'addClass' : 'removeClass' ]( 'cke_image_resizer_left' );
1381
+ } );
1382
+ }
1383
+
1384
+ // Integrates widget alignment setting with justify
1385
+ // plugin's commands (execution and refreshment).
1386
+ // @param {CKEDITOR.editor} editor
1387
+ // @param {String} value 'left', 'right', 'center' or 'block'
1388
+ function alignCommandIntegrator( editor ) {
1389
+ var execCallbacks = [],
1390
+ enabled;
1391
+
1392
+ return function( value ) {
1393
+ var command = editor.getCommand( 'justify' + value );
1394
+
1395
+ // Most likely, the justify plugin isn't loaded.
1396
+ if ( !command )
1397
+ return;
1398
+
1399
+ // This command will be manually refreshed along with
1400
+ // other commands after exec.
1401
+ execCallbacks.push( function() {
1402
+ command.refresh( editor, editor.elementPath() );
1403
+ } );
1404
+
1405
+ if ( value in { right: 1, left: 1, center: 1 } ) {
1406
+ command.on( 'exec', function( evt ) {
1407
+ var widget = getFocusedWidget( editor );
1408
+
1409
+ if ( widget ) {
1410
+ widget.setData( 'align', value );
1411
+
1412
+ // Once the widget changed its align, all the align commands
1413
+ // must be refreshed: the event is to be cancelled.
1414
+ for ( var i = execCallbacks.length; i--; )
1415
+ execCallbacks[ i ]();
1416
+
1417
+ evt.cancel();
1418
+ }
1419
+ } );
1420
+ }
1421
+
1422
+ command.on( 'refresh', function( evt ) {
1423
+ var widget = getFocusedWidget( editor ),
1424
+ allowed = { right: 1, left: 1, center: 1 };
1425
+
1426
+ if ( !widget )
1427
+ return;
1428
+
1429
+ // Cache "enabled" on first use. This is because filter#checkFeature may
1430
+ // not be available during plugin's afterInit in the future — a moment when
1431
+ // alignCommandIntegrator is called.
1432
+ if ( enabled === undefined )
1433
+ enabled = editor.filter.checkFeature( editor.widgets.registered.image.features.align );
1434
+
1435
+ // Don't allow justify commands when widget alignment is disabled (https://dev.ckeditor.com/ticket/11004).
1436
+ if ( !enabled )
1437
+ this.setState( CKEDITOR.TRISTATE_DISABLED );
1438
+ else {
1439
+ this.setState(
1440
+ ( widget.data.align == value ) ? (
1441
+ CKEDITOR.TRISTATE_ON
1442
+ ) : (
1443
+ ( value in allowed ) ? CKEDITOR.TRISTATE_OFF : CKEDITOR.TRISTATE_DISABLED
1444
+ )
1445
+ );
1446
+ }
1447
+
1448
+ evt.cancel();
1449
+ } );
1450
+ };
1451
+ }
1452
+
1453
+ function linkCommandIntegrator( editor ) {
1454
+ // Nothing to integrate with if link is not loaded.
1455
+ if ( !editor.plugins.link )
1456
+ return;
1457
+
1458
+ var listener = CKEDITOR.on( 'dialogDefinition', function( evt ) {
1459
+ var dialog = evt.data;
1460
+
1461
+ if ( dialog.name == 'link' ) {
1462
+ var def = dialog.definition;
1463
+
1464
+ var onShow = def.onShow,
1465
+ onOk = def.onOk;
1466
+
1467
+ def.onShow = function() {
1468
+ var widget = getFocusedWidget( editor ),
1469
+ displayTextField = this.getContentElement( 'info', 'linkDisplayText' ).getElement().getParent().getParent();
1470
+
1471
+ // Widget cannot be enclosed in a link, i.e.
1472
+ // <a>foo<inline widget/>bar</a>
1473
+ if ( widget && ( widget.inline ? !widget.wrapper.getAscendant( 'a' ) : 1 ) ) {
1474
+ this.setupContent( widget.data.link || {} );
1475
+
1476
+ // Hide the display text in case of linking image2 widget.
1477
+ displayTextField.hide();
1478
+ } else {
1479
+ // Make sure that display text is visible, as it might be hidden by image2 integration
1480
+ // before.
1481
+ displayTextField.show();
1482
+ onShow.apply( this, arguments );
1483
+ }
1484
+ };
1485
+
1486
+ // Set widget data if linking the widget using
1487
+ // link dialog (instead of default action).
1488
+ // State shifter handles data change and takes
1489
+ // care of internal DOM structure of linked widget.
1490
+ def.onOk = function() {
1491
+ var widget = getFocusedWidget( editor );
1492
+
1493
+ // Widget cannot be enclosed in a link, i.e.
1494
+ // <a>foo<inline widget/>bar</a>
1495
+ if ( widget && ( widget.inline ? !widget.wrapper.getAscendant( 'a' ) : 1 ) ) {
1496
+ var data = {};
1497
+
1498
+ // Collect data from fields.
1499
+ this.commitContent( data );
1500
+
1501
+ // Set collected data to widget.
1502
+ widget.setData( 'link', data );
1503
+ } else {
1504
+ onOk.apply( this, arguments );
1505
+ }
1506
+ };
1507
+ }
1508
+ } );
1509
+ // Listener has to be removed due to leaking the editor reference (#589).
1510
+ editor.on( 'destroy', function() {
1511
+ listener.removeListener();
1512
+ } );
1513
+
1514
+ // Overwrite the default behavior of unlink command.
1515
+ editor.getCommand( 'unlink' ).on( 'exec', function( evt ) {
1516
+ var widget = getFocusedWidget( editor );
1517
+
1518
+ // Override unlink only when link truly belongs to the widget.
1519
+ // If wrapped inline widget in a link, let default unlink work (https://dev.ckeditor.com/ticket/11814).
1520
+ if ( !widget || !widget.parts.link )
1521
+ return;
1522
+
1523
+ widget.setData( 'link', null );
1524
+
1525
+ // Selection (which is fake) may not change if unlinked image in focused widget,
1526
+ // i.e. if captioned image. Let's refresh command state manually here.
1527
+ this.refresh( editor, editor.elementPath() );
1528
+
1529
+ evt.cancel();
1530
+ } );
1531
+
1532
+ // Overwrite default refresh of unlink command.
1533
+ editor.getCommand( 'unlink' ).on( 'refresh', function( evt ) {
1534
+ var widget = getFocusedWidget( editor );
1535
+
1536
+ if ( !widget )
1537
+ return;
1538
+
1539
+ // Note that widget may be wrapped in a link, which
1540
+ // does not belong to that widget (https://dev.ckeditor.com/ticket/11814).
1541
+ this.setState( widget.data.link || widget.wrapper.getAscendant( 'a' ) ?
1542
+ CKEDITOR.TRISTATE_OFF : CKEDITOR.TRISTATE_DISABLED );
1543
+
1544
+ evt.cancel();
1545
+ } );
1546
+ }
1547
+
1548
+ // Returns the focused widget, if of the type specific for this plugin.
1549
+ // If no widget is focused, `null` is returned.
1550
+ //
1551
+ // @param {CKEDITOR.editor}
1552
+ // @returns {CKEDITOR.plugins.widget}
1553
+ function getFocusedWidget( editor ) {
1554
+ var widget = editor.widgets.focused;
1555
+
1556
+ if ( widget && widget.name == 'image' )
1557
+ return widget;
1558
+
1559
+ return null;
1560
+ }
1561
+
1562
+ // Returns a set of widget allowedContent rules, depending
1563
+ // on configurations like config#image2_alignClasses or
1564
+ // config#image2_captionedClass.
1565
+ //
1566
+ // @param {CKEDITOR.editor}
1567
+ // @returns {Object}
1568
+ function getWidgetAllowedContent( editor ) {
1569
+ var alignClasses = editor.config.image2_alignClasses,
1570
+ rules = {
1571
+ // Widget may need <div> or <p> centering wrapper.
1572
+ div: {
1573
+ match: centerWrapperChecker( editor )
1574
+ },
1575
+ p: {
1576
+ match: centerWrapperChecker( editor )
1577
+ },
1578
+ img: {
1579
+ attributes: '!src,alt,width,height'
1580
+ },
1581
+ figure: {
1582
+ classes: '!' + editor.config.image2_captionedClass
1583
+ },
1584
+ figcaption: true
1585
+ };
1586
+
1587
+ if ( alignClasses ) {
1588
+ // Centering class from the config.
1589
+ rules.div.classes = alignClasses[ 1 ];
1590
+ rules.p.classes = rules.div.classes;
1591
+
1592
+ // Left/right classes from the config.
1593
+ rules.img.classes = alignClasses[ 0 ] + ',' + alignClasses[ 2 ];
1594
+ rules.figure.classes += ',' + rules.img.classes;
1595
+ } else {
1596
+ // Centering with text-align.
1597
+ rules.div.styles = 'text-align';
1598
+ rules.p.styles = 'text-align';
1599
+
1600
+ rules.img.styles = 'float';
1601
+ rules.figure.styles = 'float,display';
1602
+ }
1603
+
1604
+ return rules;
1605
+ }
1606
+
1607
+ // Returns a set of widget feature rules, depending
1608
+ // on editor configuration. Note that the following may not cover
1609
+ // all the possible cases since requiredContent supports a single
1610
+ // tag only.
1611
+ //
1612
+ // @param {CKEDITOR.editor}
1613
+ // @returns {Object}
1614
+ function getWidgetFeatures( editor ) {
1615
+ var alignClasses = editor.config.image2_alignClasses,
1616
+ features = {
1617
+ dimension: {
1618
+ requiredContent: 'img[width,height]'
1619
+ },
1620
+ align: {
1621
+ requiredContent: 'img' +
1622
+ ( alignClasses ? '(' + alignClasses[ 0 ] + ')' : '{float}' )
1623
+ },
1624
+ caption: {
1625
+ requiredContent: 'figcaption'
1626
+ }
1627
+ };
1628
+
1629
+ return features;
1630
+ }
1631
+
1632
+ // Returns element which is styled, considering current
1633
+ // state of the widget.
1634
+ //
1635
+ // @see CKEDITOR.plugins.widget#applyStyle
1636
+ // @param {CKEDITOR.plugins.widget} widget
1637
+ // @returns {CKEDITOR.dom.element}
1638
+ function getStyleableElement( widget ) {
1639
+ return widget.data.hasCaption ? widget.element : widget.parts.image;
1640
+ }
1641
+ } )();
1642
+
1643
+ /**
1644
+ * A CSS class applied to the `<figure>` element of a captioned image.
1645
+ *
1646
+ * Read more in the {@glink features/image2 documentation} and see the
1647
+ * {@glink examples/image2 example}.
1648
+ *
1649
+ * // Changes the class to "captionedImage".
1650
+ * config.image2_captionedClass = 'captionedImage';
1651
+ *
1652
+ * @cfg {String} [image2_captionedClass='image']
1653
+ * @member CKEDITOR.config
1654
+ */
1655
+ CKEDITOR.config.image2_captionedClass = 'image';
1656
+
1657
+ /**
1658
+ * Determines whether dimension inputs should be automatically filled when the image URL changes in the Enhanced Image
1659
+ * plugin dialog window.
1660
+ *
1661
+ * Read more in the {@glink features/image2 documentation} and see the
1662
+ * {@glink examples/image2 example}.
1663
+ *
1664
+ * config.image2_prefillDimensions = false;
1665
+ *
1666
+ * @since 4.5.0
1667
+ * @cfg {Boolean} [image2_prefillDimensions=true]
1668
+ * @member CKEDITOR.config
1669
+ */
1670
+
1671
+ /**
1672
+ * Disables the image resizer. By default the resizer is enabled.
1673
+ *
1674
+ * Read more in the {@glink features/image2 documentation} and see the
1675
+ * {@glink examples/image2 example}.
1676
+ *
1677
+ * config.image2_disableResizer = true;
1678
+ *
1679
+ * @since 4.5.0
1680
+ * @cfg {Boolean} [image2_disableResizer=false]
1681
+ * @member CKEDITOR.config
1682
+ */
1683
+
1684
+ /**
1685
+ * CSS classes applied to aligned images. Useful to take control over the way
1686
+ * the images are aligned, i.e. to customize output HTML and integrate external stylesheets.
1687
+ *
1688
+ * Classes should be defined in an array of three elements, containing left, center, and right
1689
+ * alignment classes, respectively. For example:
1690
+ *
1691
+ * config.image2_alignClasses = [ 'align-left', 'align-center', 'align-right' ];
1692
+ *
1693
+ * **Note**: Once this configuration option is set, the plugin will no longer produce inline
1694
+ * styles for alignment. It means that e.g. the following HTML will be produced:
1695
+ *
1696
+ * <img alt="My image" class="custom-center-class" src="foo.png" />
1697
+ *
1698
+ * instead of:
1699
+ *
1700
+ * <img alt="My image" style="float:left" src="foo.png" />
1701
+ *
1702
+ * **Note**: Once this configuration option is set, corresponding style definitions
1703
+ * must be supplied to the editor:
1704
+ *
1705
+ * * For {@glink guide/dev_framed classic editor} it can be done by defining additional
1706
+ * styles in the {@link CKEDITOR.config#contentsCss stylesheets loaded by the editor}. The same
1707
+ * styles must be provided on the target page where the content will be loaded.
1708
+ * * For {@glink guide/dev_inline inline editor} the styles can be defined directly
1709
+ * with `<style> ... <style>` or `<link href="..." rel="stylesheet">`, i.e. within the `<head>`
1710
+ * of the page.
1711
+ *
1712
+ * For example, considering the following configuration:
1713
+ *
1714
+ * config.image2_alignClasses = [ 'align-left', 'align-center', 'align-right' ];
1715
+ *
1716
+ * CSS rules can be defined as follows:
1717
+ *
1718
+ * .align-left {
1719
+ * float: left;
1720
+ * }
1721
+ *
1722
+ * .align-right {
1723
+ * float: right;
1724
+ * }
1725
+ *
1726
+ * .align-center {
1727
+ * text-align: center;
1728
+ * }
1729
+ *
1730
+ * .align-center > figure {
1731
+ * display: inline-block;
1732
+ * }
1733
+ *
1734
+ * Read more in the {@glink features/image2 documentation} and see the
1735
+ * {@glink examples/image2 example}.
1736
+ *
1737
+ * @since 4.4.0
1738
+ * @cfg {String[]} [image2_alignClasses=null]
1739
+ * @member CKEDITOR.config
1740
+ */
1741
+
1742
+ /**
1743
+ * Determines whether alternative text is required for the captioned image.
1744
+ *
1745
+ * config.image2_altRequired = true;
1746
+ *
1747
+ * Read more in the {@glink features/image2 documentation} and see the
1748
+ * {@glink examples/image2 example}.
1749
+ *
1750
+ * @since 4.6.0
1751
+ * @cfg {Boolean} [image2_altRequired=false]
1752
+ * @member CKEDITOR.config
1753
+ */
1754
+
1755
+ /**
1756
+ * Determines the maximum size that an image can be resized to with the resize handle.
1757
+ *
1758
+ * It stores two properties: `width` and `height`. They can be set with one of the two types:
1759
+ *
1760
+ * * A number representing a value that limits the maximum size in pixel units:
1761
+ *
1762
+ * ```js
1763
+ * config.image2_maxSize = {
1764
+ * height: 300,
1765
+ * width: 250
1766
+ * };
1767
+ * ```
1768
+ *
1769
+ * * A string representing the natural image size, so each image resize operation is limited to its own natural height or width:
1770
+ *
1771
+ * ```js
1772
+ * config.image2_maxSize = {
1773
+ * height: 'natural',
1774
+ * width: 'natural'
1775
+ * }
1776
+ * ```
1777
+ *
1778
+ * Note: An image can still be resized to bigger dimensions when using the image dialog.
1779
+ *
1780
+ * @since 4.12.0
1781
+ * @cfg {Object.<String, Number/String>} [image2_maxSize]
1782
+ * @member CKEDITOR.config
1783
+ */