st-rich 1.5.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (759) hide show
  1. checksums.yaml +7 -0
  2. data/MIT-LICENSE +20 -0
  3. data/README.rdoc +289 -0
  4. data/Rakefile +39 -0
  5. data/app/assets/images/rich/document-thumb.png +0 -0
  6. data/app/assets/images/rich/files.png +0 -0
  7. data/app/assets/images/rich/images.png +0 -0
  8. data/app/assets/images/rich/insert-many.png +0 -0
  9. data/app/assets/images/rich/insert-one.png +0 -0
  10. data/app/assets/images/rich/loading.png +0 -0
  11. data/app/assets/images/rich/menu-dash.png +0 -0
  12. data/app/assets/images/rich/plus-red.png +0 -0
  13. data/app/assets/images/rich/plus.png +0 -0
  14. data/app/assets/images/rich/rich.png +0 -0
  15. data/app/assets/images/rich/view-grid.png +0 -0
  16. data/app/assets/images/rich/view-list.png +0 -0
  17. data/app/assets/images/rich/x-red.png +0 -0
  18. data/app/assets/javascripts/rich/application.js +12 -0
  19. data/app/assets/javascripts/rich/base.js.erb +5 -0
  20. data/app/assets/javascripts/rich/browser/extensions.js +15 -0
  21. data/app/assets/javascripts/rich/browser/filebrowser.js +186 -0
  22. data/app/assets/javascripts/rich/browser/uploader.js +68 -0
  23. data/app/assets/javascripts/rich/editor/ckeditor_path.js.erb +1 -0
  24. data/app/assets/javascripts/rich/editor/rich_editor.js.erb +14 -0
  25. data/app/assets/javascripts/rich/editor/rich_picker.js +45 -0
  26. data/app/assets/stylesheets/rich/application.css.scss +365 -0
  27. data/app/assets/stylesheets/rich/editor.css +20 -0
  28. data/app/assets/stylesheets/rich/files.css +4 -0
  29. data/app/assets/stylesheets/rich/mixins/reset.css.scss +58 -0
  30. data/app/controllers/rich/files_controller.rb +82 -0
  31. data/app/helpers/rich/application_helper.rb +4 -0
  32. data/app/helpers/rich/files_helper.rb +13 -0
  33. data/app/inputs/rich_input.rb +19 -0
  34. data/app/inputs/rich_picker_input.rb +88 -0
  35. data/app/models/rich/rich_file.rb +75 -0
  36. data/app/views/layouts/rich/application.html.erb +14 -0
  37. data/app/views/rails_admin/main/_form_rich_picker.html.haml +7 -0
  38. data/app/views/rails_admin/main/_form_rich_text.html.haml +7 -0
  39. data/app/views/rich/files/_file.html.erb +11 -0
  40. data/app/views/rich/files/destroy.js.erb +1 -0
  41. data/app/views/rich/files/index.html.erb +38 -0
  42. data/app/views/rich/files/index.js.erb +1 -0
  43. data/app/views/rich/files/show.html.erb +1 -0
  44. data/config/locales/en.yml +19 -0
  45. data/config/locales/fr.yml +14 -0
  46. data/config/locales/it.yml +19 -0
  47. data/config/locales/nl.yml +14 -0
  48. data/config/locales/ru.yml +19 -0
  49. data/config/locales/sv.yml +14 -0
  50. data/config/locales/zh-CN.yml +19 -0
  51. data/config/routes.rb +5 -0
  52. data/db/migrate/20111002142937_create_rich_rich_images.rb +17 -0
  53. data/db/migrate/20111117202133_add_uri_cache_to_rich_image.rb +5 -0
  54. data/db/migrate/20111201095829_refactor_image_to_file.rb +12 -0
  55. data/lib/generators/rich/install/install_generator.rb +34 -0
  56. data/lib/generators/rich/install/templates/rich.js +1 -0
  57. data/lib/generators/rich/install/templates/rich.rb.erb +125 -0
  58. data/lib/rich.rb +195 -0
  59. data/lib/rich/authorize.rb +7 -0
  60. data/lib/rich/backends/carrierwave.rb +78 -0
  61. data/lib/rich/backends/paperclip.rb +79 -0
  62. data/lib/rich/backends/rich_file_uploader.rb +55 -0
  63. data/lib/rich/engine.rb +26 -0
  64. data/lib/rich/integrations/legacy_formtastic.rb +50 -0
  65. data/lib/rich/rails_admin/config/fields/types/rich_editor.rb +34 -0
  66. data/lib/rich/rails_admin/config/fields/types/rich_picker.rb +45 -0
  67. data/lib/rich/utils/file_size_validator.rb +68 -0
  68. data/lib/rich/version.rb +3 -0
  69. data/lib/tasks/rich_tasks.rake +24 -0
  70. data/test/dummy/Rakefile +7 -0
  71. data/test/dummy/app/admin/dashboards.rb +38 -0
  72. data/test/dummy/app/admin/posts.rb +11 -0
  73. data/test/dummy/app/assets/javascripts/active_admin.js +2 -0
  74. data/test/dummy/app/assets/javascripts/application.js +9 -0
  75. data/test/dummy/app/assets/javascripts/posts.js +2 -0
  76. data/test/dummy/app/assets/javascripts/rich.js +1 -0
  77. data/test/dummy/app/assets/stylesheets/active_admin.css.scss +10 -0
  78. data/test/dummy/app/assets/stylesheets/application.css +7 -0
  79. data/test/dummy/app/assets/stylesheets/posts.css +4 -0
  80. data/test/dummy/app/assets/stylesheets/rich/editor.css +20 -0
  81. data/test/dummy/app/assets/stylesheets/scaffold.css +56 -0
  82. data/test/dummy/app/controllers/application_controller.rb +3 -0
  83. data/test/dummy/app/controllers/posts_controller.rb +83 -0
  84. data/test/dummy/app/helpers/application_helper.rb +2 -0
  85. data/test/dummy/app/helpers/posts_helper.rb +2 -0
  86. data/test/dummy/app/models/admin_user.rb +9 -0
  87. data/test/dummy/app/models/post.rb +2 -0
  88. data/test/dummy/app/views/layouts/application.html.erb +14 -0
  89. data/test/dummy/app/views/posts/_form.html.erb +29 -0
  90. data/test/dummy/app/views/posts/_formtastic_form.html.erb +17 -0
  91. data/test/dummy/app/views/posts/edit.html.erb +6 -0
  92. data/test/dummy/app/views/posts/index.html.erb +27 -0
  93. data/test/dummy/app/views/posts/new.html.erb +5 -0
  94. data/test/dummy/app/views/posts/show.html.erb +20 -0
  95. data/test/dummy/config.ru +4 -0
  96. data/test/dummy/config/application.rb +48 -0
  97. data/test/dummy/config/boot.rb +19 -0
  98. data/test/dummy/config/database.yml +25 -0
  99. data/test/dummy/config/environment.rb +5 -0
  100. data/test/dummy/config/environments/development.rb +32 -0
  101. data/test/dummy/config/environments/production.rb +62 -0
  102. data/test/dummy/config/environments/test.rb +39 -0
  103. data/test/dummy/config/initializers/active_admin.rb +101 -0
  104. data/test/dummy/config/initializers/backtrace_silencers.rb +7 -0
  105. data/test/dummy/config/initializers/devise.rb +211 -0
  106. data/test/dummy/config/initializers/formtastic.rb +80 -0
  107. data/test/dummy/config/initializers/inflections.rb +10 -0
  108. data/test/dummy/config/initializers/mime_types.rb +5 -0
  109. data/test/dummy/config/initializers/rich.rb +29 -0
  110. data/test/dummy/config/initializers/secret_token.rb +7 -0
  111. data/test/dummy/config/initializers/session_store.rb +8 -0
  112. data/test/dummy/config/initializers/wrap_parameters.rb +14 -0
  113. data/test/dummy/config/locales/devise.en.yml +58 -0
  114. data/test/dummy/config/locales/en.yml +5 -0
  115. data/test/dummy/config/routes.rb +13 -0
  116. data/test/dummy/db/migrate/20111001122048_create_posts.rb +12 -0
  117. data/test/dummy/db/migrate/20111003150957_create_rich_rich_images.rb +17 -0
  118. data/test/dummy/db/migrate/20111014123344_devise_create_admin_users.rb +31 -0
  119. data/test/dummy/db/migrate/20111014143348_create_admin_notes.rb +16 -0
  120. data/test/dummy/db/migrate/20111014143349_move_admin_notes_to_comments.rb +25 -0
  121. data/test/dummy/db/migrate/20111117202523_add_uri_cache_to_rich_image.rb +5 -0
  122. data/test/dummy/db/migrate/20111201102914_refactor_image_to_file.rb +12 -0
  123. data/test/dummy/db/schema.rb +58 -0
  124. data/test/dummy/public/404.html +26 -0
  125. data/test/dummy/public/422.html +26 -0
  126. data/test/dummy/public/500.html +26 -0
  127. data/test/dummy/public/favicon.ico +0 -0
  128. data/test/dummy/script/rails +6 -0
  129. data/test/dummy/test/fixtures/admin_users.yml +11 -0
  130. data/test/dummy/test/fixtures/posts.yml +11 -0
  131. data/test/dummy/test/functional/posts_controller_test.rb +49 -0
  132. data/test/dummy/test/unit/admin_user_test.rb +7 -0
  133. data/test/dummy/test/unit/helpers/posts_helper_test.rb +4 -0
  134. data/test/dummy/test/unit/post_test.rb +7 -0
  135. data/test/fixtures/rich/rich_images.yml +11 -0
  136. data/test/functional/rich/files_controller_test.rb +9 -0
  137. data/test/integration/navigation_test.rb +10 -0
  138. data/test/rich_test.rb +7 -0
  139. data/test/test_helper.rb +10 -0
  140. data/test/unit/helpers/rich/files_helper_test.rb +6 -0
  141. data/test/unit/rich/rich_image_test.rb +9 -0
  142. data/vendor/assets/images/ckeditor/plugins/MediaEmbed/icons/mediaembed.png +0 -0
  143. data/vendor/assets/images/ckeditor/plugins/MediaEmbed/images/icon.png +0 -0
  144. data/vendor/assets/images/ckeditor/plugins/about/dialogs/hidpi/logo_ckeditor.png +0 -0
  145. data/vendor/assets/images/ckeditor/plugins/about/dialogs/logo_ckeditor.png +0 -0
  146. data/vendor/assets/images/ckeditor/plugins/fakeobjects/images/spacer.gif +0 -0
  147. data/vendor/assets/images/ckeditor/plugins/flash/images/placeholder.png +0 -0
  148. data/vendor/assets/images/ckeditor/plugins/forms/images/hiddenfield.gif +0 -0
  149. data/vendor/assets/images/ckeditor/plugins/icons.png +0 -0
  150. data/vendor/assets/images/ckeditor/plugins/icons_hidpi.png +0 -0
  151. data/vendor/assets/images/ckeditor/plugins/iframe/images/placeholder.png +0 -0
  152. data/vendor/assets/images/ckeditor/plugins/image/images/noimage.png +0 -0
  153. data/vendor/assets/images/ckeditor/plugins/link/images/anchor.png +0 -0
  154. data/vendor/assets/images/ckeditor/plugins/link/images/hidpi/anchor.png +0 -0
  155. data/vendor/assets/images/ckeditor/plugins/magicline/images/hidpi/icon.png +0 -0
  156. data/vendor/assets/images/ckeditor/plugins/magicline/images/icon.png +0 -0
  157. data/vendor/assets/images/ckeditor/plugins/maximize/icons/maximize.png +0 -0
  158. data/vendor/assets/images/ckeditor/plugins/pagebreak/images/pagebreak.gif +0 -0
  159. data/vendor/assets/images/ckeditor/plugins/showblocks/icons/hidpi/showblocks-rtl.png +0 -0
  160. data/vendor/assets/images/ckeditor/plugins/showblocks/icons/hidpi/showblocks.png +0 -0
  161. data/vendor/assets/images/ckeditor/plugins/showblocks/icons/showblocks-rtl.png +0 -0
  162. data/vendor/assets/images/ckeditor/plugins/showblocks/icons/showblocks.png +0 -0
  163. data/vendor/assets/images/ckeditor/plugins/showblocks/images/block_address.png +0 -0
  164. data/vendor/assets/images/ckeditor/plugins/showblocks/images/block_blockquote.png +0 -0
  165. data/vendor/assets/images/ckeditor/plugins/showblocks/images/block_div.png +0 -0
  166. data/vendor/assets/images/ckeditor/plugins/showblocks/images/block_h1.png +0 -0
  167. data/vendor/assets/images/ckeditor/plugins/showblocks/images/block_h2.png +0 -0
  168. data/vendor/assets/images/ckeditor/plugins/showblocks/images/block_h3.png +0 -0
  169. data/vendor/assets/images/ckeditor/plugins/showblocks/images/block_h4.png +0 -0
  170. data/vendor/assets/images/ckeditor/plugins/showblocks/images/block_h5.png +0 -0
  171. data/vendor/assets/images/ckeditor/plugins/showblocks/images/block_h6.png +0 -0
  172. data/vendor/assets/images/ckeditor/plugins/showblocks/images/block_p.png +0 -0
  173. data/vendor/assets/images/ckeditor/plugins/showblocks/images/block_pre.png +0 -0
  174. data/vendor/assets/images/ckeditor/plugins/smiley/images/angel_smile.gif +0 -0
  175. data/vendor/assets/images/ckeditor/plugins/smiley/images/angry_smile.gif +0 -0
  176. data/vendor/assets/images/ckeditor/plugins/smiley/images/broken_heart.gif +0 -0
  177. data/vendor/assets/images/ckeditor/plugins/smiley/images/confused_smile.gif +0 -0
  178. data/vendor/assets/images/ckeditor/plugins/smiley/images/cry_smile.gif +0 -0
  179. data/vendor/assets/images/ckeditor/plugins/smiley/images/devil_smile.gif +0 -0
  180. data/vendor/assets/images/ckeditor/plugins/smiley/images/embaressed_smile.gif +0 -0
  181. data/vendor/assets/images/ckeditor/plugins/smiley/images/embarrassed_smile.gif +0 -0
  182. data/vendor/assets/images/ckeditor/plugins/smiley/images/envelope.gif +0 -0
  183. data/vendor/assets/images/ckeditor/plugins/smiley/images/heart.gif +0 -0
  184. data/vendor/assets/images/ckeditor/plugins/smiley/images/kiss.gif +0 -0
  185. data/vendor/assets/images/ckeditor/plugins/smiley/images/lightbulb.gif +0 -0
  186. data/vendor/assets/images/ckeditor/plugins/smiley/images/omg_smile.gif +0 -0
  187. data/vendor/assets/images/ckeditor/plugins/smiley/images/regular_smile.gif +0 -0
  188. data/vendor/assets/images/ckeditor/plugins/smiley/images/sad_smile.gif +0 -0
  189. data/vendor/assets/images/ckeditor/plugins/smiley/images/shades_smile.gif +0 -0
  190. data/vendor/assets/images/ckeditor/plugins/smiley/images/teeth_smile.gif +0 -0
  191. data/vendor/assets/images/ckeditor/plugins/smiley/images/thumbs_down.gif +0 -0
  192. data/vendor/assets/images/ckeditor/plugins/smiley/images/thumbs_up.gif +0 -0
  193. data/vendor/assets/images/ckeditor/plugins/smiley/images/tongue_smile.gif +0 -0
  194. data/vendor/assets/images/ckeditor/plugins/smiley/images/tounge_smile.gif +0 -0
  195. data/vendor/assets/images/ckeditor/plugins/smiley/images/whatchutalkingabout_smile.gif +0 -0
  196. data/vendor/assets/images/ckeditor/plugins/smiley/images/wink_smile.gif +0 -0
  197. data/vendor/assets/images/ckeditor/plugins/templates/templates/images/template1.gif +0 -0
  198. data/vendor/assets/images/ckeditor/plugins/templates/templates/images/template2.gif +0 -0
  199. data/vendor/assets/images/ckeditor/plugins/templates/templates/images/template3.gif +0 -0
  200. data/vendor/assets/images/ckeditor/plugins/widget/images/handle.png +0 -0
  201. data/vendor/assets/images/ckeditor/skins/BootstrapCK/icons.png +0 -0
  202. data/vendor/assets/images/ckeditor/skins/BootstrapCK/images/dialog_sides.gif +0 -0
  203. data/vendor/assets/images/ckeditor/skins/BootstrapCK/images/dialog_sides.png +0 -0
  204. data/vendor/assets/images/ckeditor/skins/BootstrapCK/images/dialog_sides_rtl.png +0 -0
  205. data/vendor/assets/images/ckeditor/skins/BootstrapCK/images/mini.png +0 -0
  206. data/vendor/assets/images/ckeditor/skins/BootstrapCK/images/noimage.png +0 -0
  207. data/vendor/assets/images/ckeditor/skins/BootstrapCK/images/sprites.png +0 -0
  208. data/vendor/assets/images/ckeditor/skins/BootstrapCK/images/sprites_ie6.png +0 -0
  209. data/vendor/assets/images/ckeditor/skins/BootstrapCK/images/toolbar_start.gif +0 -0
  210. data/vendor/assets/images/ckeditor/skins/moono/icons.png +0 -0
  211. data/vendor/assets/images/ckeditor/skins/moono/images/arrow.png +0 -0
  212. data/vendor/assets/images/ckeditor/skins/moono/images/close.png +0 -0
  213. data/vendor/assets/images/ckeditor/skins/moono/images/mini.png +0 -0
  214. data/vendor/assets/javascripts/ckeditor/build-config.js +102 -0
  215. data/vendor/assets/javascripts/ckeditor/ckeditor.js +926 -0
  216. data/vendor/assets/javascripts/ckeditor/config.js +10 -0
  217. data/vendor/assets/javascripts/ckeditor/lang/af.js +5 -0
  218. data/vendor/assets/javascripts/ckeditor/lang/ar.js +5 -0
  219. data/vendor/assets/javascripts/ckeditor/lang/bg.js +5 -0
  220. data/vendor/assets/javascripts/ckeditor/lang/bn.js +5 -0
  221. data/vendor/assets/javascripts/ckeditor/lang/bs.js +5 -0
  222. data/vendor/assets/javascripts/ckeditor/lang/ca.js +5 -0
  223. data/vendor/assets/javascripts/ckeditor/lang/cs.js +5 -0
  224. data/vendor/assets/javascripts/ckeditor/lang/cy.js +5 -0
  225. data/vendor/assets/javascripts/ckeditor/lang/da.js +5 -0
  226. data/vendor/assets/javascripts/ckeditor/lang/de.js +5 -0
  227. data/vendor/assets/javascripts/ckeditor/lang/el.js +5 -0
  228. data/vendor/assets/javascripts/ckeditor/lang/en-au.js +5 -0
  229. data/vendor/assets/javascripts/ckeditor/lang/en-ca.js +5 -0
  230. data/vendor/assets/javascripts/ckeditor/lang/en-gb.js +5 -0
  231. data/vendor/assets/javascripts/ckeditor/lang/en.js +5 -0
  232. data/vendor/assets/javascripts/ckeditor/lang/eo.js +5 -0
  233. data/vendor/assets/javascripts/ckeditor/lang/es.js +5 -0
  234. data/vendor/assets/javascripts/ckeditor/lang/et.js +5 -0
  235. data/vendor/assets/javascripts/ckeditor/lang/eu.js +5 -0
  236. data/vendor/assets/javascripts/ckeditor/lang/fa.js +5 -0
  237. data/vendor/assets/javascripts/ckeditor/lang/fi.js +5 -0
  238. data/vendor/assets/javascripts/ckeditor/lang/fo.js +5 -0
  239. data/vendor/assets/javascripts/ckeditor/lang/fr-ca.js +5 -0
  240. data/vendor/assets/javascripts/ckeditor/lang/fr.js +5 -0
  241. data/vendor/assets/javascripts/ckeditor/lang/gl.js +5 -0
  242. data/vendor/assets/javascripts/ckeditor/lang/gu.js +5 -0
  243. data/vendor/assets/javascripts/ckeditor/lang/he.js +5 -0
  244. data/vendor/assets/javascripts/ckeditor/lang/hi.js +5 -0
  245. data/vendor/assets/javascripts/ckeditor/lang/hr.js +5 -0
  246. data/vendor/assets/javascripts/ckeditor/lang/hu.js +5 -0
  247. data/vendor/assets/javascripts/ckeditor/lang/id.js +5 -0
  248. data/vendor/assets/javascripts/ckeditor/lang/is.js +5 -0
  249. data/vendor/assets/javascripts/ckeditor/lang/it.js +5 -0
  250. data/vendor/assets/javascripts/ckeditor/lang/ja.js +5 -0
  251. data/vendor/assets/javascripts/ckeditor/lang/ka.js +5 -0
  252. data/vendor/assets/javascripts/ckeditor/lang/km.js +5 -0
  253. data/vendor/assets/javascripts/ckeditor/lang/ko.js +5 -0
  254. data/vendor/assets/javascripts/ckeditor/lang/ku.js +5 -0
  255. data/vendor/assets/javascripts/ckeditor/lang/lt.js +5 -0
  256. data/vendor/assets/javascripts/ckeditor/lang/lv.js +5 -0
  257. data/vendor/assets/javascripts/ckeditor/lang/mk.js +5 -0
  258. data/vendor/assets/javascripts/ckeditor/lang/mn.js +5 -0
  259. data/vendor/assets/javascripts/ckeditor/lang/ms.js +5 -0
  260. data/vendor/assets/javascripts/ckeditor/lang/nb.js +5 -0
  261. data/vendor/assets/javascripts/ckeditor/lang/nl.js +5 -0
  262. data/vendor/assets/javascripts/ckeditor/lang/no.js +5 -0
  263. data/vendor/assets/javascripts/ckeditor/lang/pl.js +5 -0
  264. data/vendor/assets/javascripts/ckeditor/lang/pt-br.js +5 -0
  265. data/vendor/assets/javascripts/ckeditor/lang/pt.js +5 -0
  266. data/vendor/assets/javascripts/ckeditor/lang/ro.js +5 -0
  267. data/vendor/assets/javascripts/ckeditor/lang/ru.js +5 -0
  268. data/vendor/assets/javascripts/ckeditor/lang/si.js +5 -0
  269. data/vendor/assets/javascripts/ckeditor/lang/sk.js +5 -0
  270. data/vendor/assets/javascripts/ckeditor/lang/sl.js +5 -0
  271. data/vendor/assets/javascripts/ckeditor/lang/sq.js +5 -0
  272. data/vendor/assets/javascripts/ckeditor/lang/sr-latn.js +5 -0
  273. data/vendor/assets/javascripts/ckeditor/lang/sr.js +5 -0
  274. data/vendor/assets/javascripts/ckeditor/lang/sv.js +5 -0
  275. data/vendor/assets/javascripts/ckeditor/lang/th.js +5 -0
  276. data/vendor/assets/javascripts/ckeditor/lang/tr.js +5 -0
  277. data/vendor/assets/javascripts/ckeditor/lang/tt.js +5 -0
  278. data/vendor/assets/javascripts/ckeditor/lang/ug.js +5 -0
  279. data/vendor/assets/javascripts/ckeditor/lang/uk.js +5 -0
  280. data/vendor/assets/javascripts/ckeditor/lang/vi.js +5 -0
  281. data/vendor/assets/javascripts/ckeditor/lang/zh-cn.js +5 -0
  282. data/vendor/assets/javascripts/ckeditor/lang/zh.js +5 -0
  283. data/vendor/assets/javascripts/ckeditor/plugins/MediaEmbed/plugin.js +65 -0
  284. data/vendor/assets/javascripts/ckeditor/plugins/a11yhelp/dialogs/a11yhelp.js +10 -0
  285. data/vendor/assets/javascripts/ckeditor/plugins/a11yhelp/dialogs/lang/_translationstatus.txt +25 -0
  286. data/vendor/assets/javascripts/ckeditor/plugins/a11yhelp/dialogs/lang/ar.js +11 -0
  287. data/vendor/assets/javascripts/ckeditor/plugins/a11yhelp/dialogs/lang/bg.js +11 -0
  288. data/vendor/assets/javascripts/ckeditor/plugins/a11yhelp/dialogs/lang/ca.js +13 -0
  289. data/vendor/assets/javascripts/ckeditor/plugins/a11yhelp/dialogs/lang/cs.js +13 -0
  290. data/vendor/assets/javascripts/ckeditor/plugins/a11yhelp/dialogs/lang/cy.js +11 -0
  291. data/vendor/assets/javascripts/ckeditor/plugins/a11yhelp/dialogs/lang/da.js +11 -0
  292. data/vendor/assets/javascripts/ckeditor/plugins/a11yhelp/dialogs/lang/de.js +12 -0
  293. data/vendor/assets/javascripts/ckeditor/plugins/a11yhelp/dialogs/lang/el.js +13 -0
  294. data/vendor/assets/javascripts/ckeditor/plugins/a11yhelp/dialogs/lang/en-gb.js +11 -0
  295. data/vendor/assets/javascripts/ckeditor/plugins/a11yhelp/dialogs/lang/en.js +11 -0
  296. data/vendor/assets/javascripts/ckeditor/plugins/a11yhelp/dialogs/lang/eo.js +13 -0
  297. data/vendor/assets/javascripts/ckeditor/plugins/a11yhelp/dialogs/lang/es.js +12 -0
  298. data/vendor/assets/javascripts/ckeditor/plugins/a11yhelp/dialogs/lang/et.js +11 -0
  299. data/vendor/assets/javascripts/ckeditor/plugins/a11yhelp/dialogs/lang/fa.js +11 -0
  300. data/vendor/assets/javascripts/ckeditor/plugins/a11yhelp/dialogs/lang/fi.js +12 -0
  301. data/vendor/assets/javascripts/ckeditor/plugins/a11yhelp/dialogs/lang/fr-ca.js +12 -0
  302. data/vendor/assets/javascripts/ckeditor/plugins/a11yhelp/dialogs/lang/fr.js +13 -0
  303. data/vendor/assets/javascripts/ckeditor/plugins/a11yhelp/dialogs/lang/gl.js +12 -0
  304. data/vendor/assets/javascripts/ckeditor/plugins/a11yhelp/dialogs/lang/gu.js +11 -0
  305. data/vendor/assets/javascripts/ckeditor/plugins/a11yhelp/dialogs/lang/he.js +11 -0
  306. data/vendor/assets/javascripts/ckeditor/plugins/a11yhelp/dialogs/lang/hi.js +11 -0
  307. data/vendor/assets/javascripts/ckeditor/plugins/a11yhelp/dialogs/lang/hr.js +11 -0
  308. data/vendor/assets/javascripts/ckeditor/plugins/a11yhelp/dialogs/lang/hu.js +13 -0
  309. data/vendor/assets/javascripts/ckeditor/plugins/a11yhelp/dialogs/lang/id.js +11 -0
  310. data/vendor/assets/javascripts/ckeditor/plugins/a11yhelp/dialogs/lang/it.js +13 -0
  311. data/vendor/assets/javascripts/ckeditor/plugins/a11yhelp/dialogs/lang/ja.js +9 -0
  312. data/vendor/assets/javascripts/ckeditor/plugins/a11yhelp/dialogs/lang/km.js +11 -0
  313. data/vendor/assets/javascripts/ckeditor/plugins/a11yhelp/dialogs/lang/ko.js +10 -0
  314. data/vendor/assets/javascripts/ckeditor/plugins/a11yhelp/dialogs/lang/ku.js +12 -0
  315. data/vendor/assets/javascripts/ckeditor/plugins/a11yhelp/dialogs/lang/lt.js +11 -0
  316. data/vendor/assets/javascripts/ckeditor/plugins/a11yhelp/dialogs/lang/lv.js +13 -0
  317. data/vendor/assets/javascripts/ckeditor/plugins/a11yhelp/dialogs/lang/mk.js +11 -0
  318. data/vendor/assets/javascripts/ckeditor/plugins/a11yhelp/dialogs/lang/mn.js +11 -0
  319. data/vendor/assets/javascripts/ckeditor/plugins/a11yhelp/dialogs/lang/nb.js +12 -0
  320. data/vendor/assets/javascripts/ckeditor/plugins/a11yhelp/dialogs/lang/nl.js +12 -0
  321. data/vendor/assets/javascripts/ckeditor/plugins/a11yhelp/dialogs/lang/no.js +11 -0
  322. data/vendor/assets/javascripts/ckeditor/plugins/a11yhelp/dialogs/lang/pl.js +13 -0
  323. data/vendor/assets/javascripts/ckeditor/plugins/a11yhelp/dialogs/lang/pt-br.js +11 -0
  324. data/vendor/assets/javascripts/ckeditor/plugins/a11yhelp/dialogs/lang/pt.js +12 -0
  325. data/vendor/assets/javascripts/ckeditor/plugins/a11yhelp/dialogs/lang/ro.js +12 -0
  326. data/vendor/assets/javascripts/ckeditor/plugins/a11yhelp/dialogs/lang/ru.js +11 -0
  327. data/vendor/assets/javascripts/ckeditor/plugins/a11yhelp/dialogs/lang/si.js +10 -0
  328. data/vendor/assets/javascripts/ckeditor/plugins/a11yhelp/dialogs/lang/sk.js +12 -0
  329. data/vendor/assets/javascripts/ckeditor/plugins/a11yhelp/dialogs/lang/sl.js +12 -0
  330. data/vendor/assets/javascripts/ckeditor/plugins/a11yhelp/dialogs/lang/sq.js +11 -0
  331. data/vendor/assets/javascripts/ckeditor/plugins/a11yhelp/dialogs/lang/sr-latn.js +11 -0
  332. data/vendor/assets/javascripts/ckeditor/plugins/a11yhelp/dialogs/lang/sr.js +11 -0
  333. data/vendor/assets/javascripts/ckeditor/plugins/a11yhelp/dialogs/lang/sv.js +12 -0
  334. data/vendor/assets/javascripts/ckeditor/plugins/a11yhelp/dialogs/lang/th.js +11 -0
  335. data/vendor/assets/javascripts/ckeditor/plugins/a11yhelp/dialogs/lang/tr.js +12 -0
  336. data/vendor/assets/javascripts/ckeditor/plugins/a11yhelp/dialogs/lang/tt.js +11 -0
  337. data/vendor/assets/javascripts/ckeditor/plugins/a11yhelp/dialogs/lang/ug.js +11 -0
  338. data/vendor/assets/javascripts/ckeditor/plugins/a11yhelp/dialogs/lang/uk.js +12 -0
  339. data/vendor/assets/javascripts/ckeditor/plugins/a11yhelp/dialogs/lang/vi.js +11 -0
  340. data/vendor/assets/javascripts/ckeditor/plugins/a11yhelp/dialogs/lang/zh-cn.js +9 -0
  341. data/vendor/assets/javascripts/ckeditor/plugins/a11yhelp/dialogs/lang/zh.js +10 -0
  342. data/vendor/assets/javascripts/ckeditor/plugins/about/dialogs/about.js +7 -0
  343. data/vendor/assets/javascripts/ckeditor/plugins/autogrow/plugin.js +178 -0
  344. data/vendor/assets/javascripts/ckeditor/plugins/clipboard/dialogs/paste.js +11 -0
  345. data/vendor/assets/javascripts/ckeditor/plugins/codemirror/js/addon/dialog/dialog.js +3 -0
  346. data/vendor/assets/javascripts/ckeditor/plugins/codemirror/js/addon/edit/closebrackets.js +2 -0
  347. data/vendor/assets/javascripts/ckeditor/plugins/codemirror/js/addon/edit/closetag.js +3 -0
  348. data/vendor/assets/javascripts/ckeditor/plugins/codemirror/js/addon/edit/continuelist.js +1 -0
  349. data/vendor/assets/javascripts/ckeditor/plugins/codemirror/js/addon/edit/matchbrackets.js +4 -0
  350. data/vendor/assets/javascripts/ckeditor/plugins/codemirror/js/addon/foldcode/foldcode.js +7 -0
  351. data/vendor/assets/javascripts/ckeditor/plugins/codemirror/js/addon/format/autoFormatAll.js +2 -0
  352. data/vendor/assets/javascripts/ckeditor/plugins/codemirror/js/addon/format/formatting.js +5 -0
  353. data/vendor/assets/javascripts/ckeditor/plugins/codemirror/js/addon/search/match-highlighter.js +2 -0
  354. data/vendor/assets/javascripts/ckeditor/plugins/codemirror/js/addon/search/search.js +5 -0
  355. data/vendor/assets/javascripts/ckeditor/plugins/codemirror/js/addon/search/searchcursor.js +5 -0
  356. data/vendor/assets/javascripts/ckeditor/plugins/codemirror/js/codemirror.addons.min.js +25 -0
  357. data/vendor/assets/javascripts/ckeditor/plugins/codemirror/js/codemirror.js +188 -0
  358. data/vendor/assets/javascripts/ckeditor/plugins/codemirror/js/codemirror.min.js +187 -0
  359. data/vendor/assets/javascripts/ckeditor/plugins/codemirror/js/codemirror.modes.min.js +25 -0
  360. data/vendor/assets/javascripts/ckeditor/plugins/codemirror/js/codemirror.search-addons.min.js +13 -0
  361. data/vendor/assets/javascripts/ckeditor/plugins/codemirror/js/mode/css.js +10 -0
  362. data/vendor/assets/javascripts/ckeditor/plugins/codemirror/js/mode/htmlmixed.js +5 -0
  363. data/vendor/assets/javascripts/ckeditor/plugins/codemirror/js/mode/javascript.js +14 -0
  364. data/vendor/assets/javascripts/ckeditor/plugins/codemirror/js/mode/xml.js +10 -0
  365. data/vendor/assets/javascripts/ckeditor/plugins/colordialog/dialogs/colordialog.js +13 -0
  366. data/vendor/assets/javascripts/ckeditor/plugins/dialog/dialogDefinition.js +4 -0
  367. data/vendor/assets/javascripts/ckeditor/plugins/div/dialogs/div.js +9 -0
  368. data/vendor/assets/javascripts/ckeditor/plugins/divarea/plugin.js +36 -0
  369. data/vendor/assets/javascripts/ckeditor/plugins/find/dialogs/find.js +24 -0
  370. data/vendor/assets/javascripts/ckeditor/plugins/flash/dialogs/flash.js +23 -0
  371. data/vendor/assets/javascripts/ckeditor/plugins/forms/dialogs/button.js +8 -0
  372. data/vendor/assets/javascripts/ckeditor/plugins/forms/dialogs/checkbox.js +8 -0
  373. data/vendor/assets/javascripts/ckeditor/plugins/forms/dialogs/form.js +8 -0
  374. data/vendor/assets/javascripts/ckeditor/plugins/forms/dialogs/hiddenfield.js +8 -0
  375. data/vendor/assets/javascripts/ckeditor/plugins/forms/dialogs/radio.js +8 -0
  376. data/vendor/assets/javascripts/ckeditor/plugins/forms/dialogs/select.js +20 -0
  377. data/vendor/assets/javascripts/ckeditor/plugins/forms/dialogs/textarea.js +8 -0
  378. data/vendor/assets/javascripts/ckeditor/plugins/forms/dialogs/textfield.js +10 -0
  379. data/vendor/assets/javascripts/ckeditor/plugins/iframe/dialogs/iframe.js +10 -0
  380. data/vendor/assets/javascripts/ckeditor/plugins/image/dialogs/image.js +43 -0
  381. data/vendor/assets/javascripts/ckeditor/plugins/lineutils/plugin.js +933 -0
  382. data/vendor/assets/javascripts/ckeditor/plugins/link/dialogs/anchor.js +7 -0
  383. data/vendor/assets/javascripts/ckeditor/plugins/link/dialogs/link.js +26 -0
  384. data/vendor/assets/javascripts/ckeditor/plugins/liststyle/dialogs/liststyle.js +10 -0
  385. data/vendor/assets/javascripts/ckeditor/plugins/maximize/lang/af.js +8 -0
  386. data/vendor/assets/javascripts/ckeditor/plugins/maximize/lang/ar.js +8 -0
  387. data/vendor/assets/javascripts/ckeditor/plugins/maximize/lang/bg.js +8 -0
  388. data/vendor/assets/javascripts/ckeditor/plugins/maximize/lang/bn.js +8 -0
  389. data/vendor/assets/javascripts/ckeditor/plugins/maximize/lang/bs.js +8 -0
  390. data/vendor/assets/javascripts/ckeditor/plugins/maximize/lang/ca.js +8 -0
  391. data/vendor/assets/javascripts/ckeditor/plugins/maximize/lang/cs.js +8 -0
  392. data/vendor/assets/javascripts/ckeditor/plugins/maximize/lang/cy.js +8 -0
  393. data/vendor/assets/javascripts/ckeditor/plugins/maximize/lang/da.js +8 -0
  394. data/vendor/assets/javascripts/ckeditor/plugins/maximize/lang/de.js +8 -0
  395. data/vendor/assets/javascripts/ckeditor/plugins/maximize/lang/el.js +8 -0
  396. data/vendor/assets/javascripts/ckeditor/plugins/maximize/lang/en-au.js +8 -0
  397. data/vendor/assets/javascripts/ckeditor/plugins/maximize/lang/en-ca.js +8 -0
  398. data/vendor/assets/javascripts/ckeditor/plugins/maximize/lang/en-gb.js +8 -0
  399. data/vendor/assets/javascripts/ckeditor/plugins/maximize/lang/en.js +8 -0
  400. data/vendor/assets/javascripts/ckeditor/plugins/maximize/lang/eo.js +8 -0
  401. data/vendor/assets/javascripts/ckeditor/plugins/maximize/lang/es.js +8 -0
  402. data/vendor/assets/javascripts/ckeditor/plugins/maximize/lang/et.js +8 -0
  403. data/vendor/assets/javascripts/ckeditor/plugins/maximize/lang/eu.js +8 -0
  404. data/vendor/assets/javascripts/ckeditor/plugins/maximize/lang/fa.js +8 -0
  405. data/vendor/assets/javascripts/ckeditor/plugins/maximize/lang/fi.js +8 -0
  406. data/vendor/assets/javascripts/ckeditor/plugins/maximize/lang/fo.js +8 -0
  407. data/vendor/assets/javascripts/ckeditor/plugins/maximize/lang/fr-ca.js +8 -0
  408. data/vendor/assets/javascripts/ckeditor/plugins/maximize/lang/fr.js +8 -0
  409. data/vendor/assets/javascripts/ckeditor/plugins/maximize/lang/gl.js +8 -0
  410. data/vendor/assets/javascripts/ckeditor/plugins/maximize/lang/gu.js +8 -0
  411. data/vendor/assets/javascripts/ckeditor/plugins/maximize/lang/he.js +8 -0
  412. data/vendor/assets/javascripts/ckeditor/plugins/maximize/lang/hi.js +8 -0
  413. data/vendor/assets/javascripts/ckeditor/plugins/maximize/lang/hr.js +8 -0
  414. data/vendor/assets/javascripts/ckeditor/plugins/maximize/lang/hu.js +8 -0
  415. data/vendor/assets/javascripts/ckeditor/plugins/maximize/lang/is.js +8 -0
  416. data/vendor/assets/javascripts/ckeditor/plugins/maximize/lang/it.js +8 -0
  417. data/vendor/assets/javascripts/ckeditor/plugins/maximize/lang/ja.js +8 -0
  418. data/vendor/assets/javascripts/ckeditor/plugins/maximize/lang/ka.js +8 -0
  419. data/vendor/assets/javascripts/ckeditor/plugins/maximize/lang/km.js +8 -0
  420. data/vendor/assets/javascripts/ckeditor/plugins/maximize/lang/ko.js +8 -0
  421. data/vendor/assets/javascripts/ckeditor/plugins/maximize/lang/ku.js +8 -0
  422. data/vendor/assets/javascripts/ckeditor/plugins/maximize/lang/lt.js +8 -0
  423. data/vendor/assets/javascripts/ckeditor/plugins/maximize/lang/lv.js +8 -0
  424. data/vendor/assets/javascripts/ckeditor/plugins/maximize/lang/mk.js +8 -0
  425. data/vendor/assets/javascripts/ckeditor/plugins/maximize/lang/mn.js +8 -0
  426. data/vendor/assets/javascripts/ckeditor/plugins/maximize/lang/ms.js +8 -0
  427. data/vendor/assets/javascripts/ckeditor/plugins/maximize/lang/nb.js +8 -0
  428. data/vendor/assets/javascripts/ckeditor/plugins/maximize/lang/nl.js +8 -0
  429. data/vendor/assets/javascripts/ckeditor/plugins/maximize/lang/no.js +8 -0
  430. data/vendor/assets/javascripts/ckeditor/plugins/maximize/lang/pl.js +8 -0
  431. data/vendor/assets/javascripts/ckeditor/plugins/maximize/lang/pt-br.js +8 -0
  432. data/vendor/assets/javascripts/ckeditor/plugins/maximize/lang/pt.js +8 -0
  433. data/vendor/assets/javascripts/ckeditor/plugins/maximize/lang/ro.js +8 -0
  434. data/vendor/assets/javascripts/ckeditor/plugins/maximize/lang/ru.js +8 -0
  435. data/vendor/assets/javascripts/ckeditor/plugins/maximize/lang/sk.js +8 -0
  436. data/vendor/assets/javascripts/ckeditor/plugins/maximize/lang/sl.js +8 -0
  437. data/vendor/assets/javascripts/ckeditor/plugins/maximize/lang/sr-latn.js +8 -0
  438. data/vendor/assets/javascripts/ckeditor/plugins/maximize/lang/sr.js +8 -0
  439. data/vendor/assets/javascripts/ckeditor/plugins/maximize/lang/sv.js +8 -0
  440. data/vendor/assets/javascripts/ckeditor/plugins/maximize/lang/th.js +8 -0
  441. data/vendor/assets/javascripts/ckeditor/plugins/maximize/lang/tr.js +8 -0
  442. data/vendor/assets/javascripts/ckeditor/plugins/maximize/lang/ug.js +8 -0
  443. data/vendor/assets/javascripts/ckeditor/plugins/maximize/lang/uk.js +8 -0
  444. data/vendor/assets/javascripts/ckeditor/plugins/maximize/lang/vi.js +8 -0
  445. data/vendor/assets/javascripts/ckeditor/plugins/maximize/lang/zh-cn.js +8 -0
  446. data/vendor/assets/javascripts/ckeditor/plugins/maximize/lang/zh.js +8 -0
  447. data/vendor/assets/javascripts/ckeditor/plugins/maximize/plugin.js +301 -0
  448. data/vendor/assets/javascripts/ckeditor/plugins/pastefromword/filter/default.js +31 -0
  449. data/vendor/assets/javascripts/ckeditor/plugins/richfile/plugin.js.erb +85 -0
  450. data/vendor/assets/javascripts/ckeditor/plugins/scayt/dialogs/options.js +17 -0
  451. data/vendor/assets/javascripts/ckeditor/plugins/scayt/dialogs/toolbar.css +71 -0
  452. data/vendor/assets/javascripts/ckeditor/plugins/showblocks/lang/af.js +7 -0
  453. data/vendor/assets/javascripts/ckeditor/plugins/showblocks/lang/ar.js +7 -0
  454. data/vendor/assets/javascripts/ckeditor/plugins/showblocks/lang/bg.js +7 -0
  455. data/vendor/assets/javascripts/ckeditor/plugins/showblocks/lang/bn.js +7 -0
  456. data/vendor/assets/javascripts/ckeditor/plugins/showblocks/lang/bs.js +7 -0
  457. data/vendor/assets/javascripts/ckeditor/plugins/showblocks/lang/ca.js +7 -0
  458. data/vendor/assets/javascripts/ckeditor/plugins/showblocks/lang/cs.js +7 -0
  459. data/vendor/assets/javascripts/ckeditor/plugins/showblocks/lang/cy.js +7 -0
  460. data/vendor/assets/javascripts/ckeditor/plugins/showblocks/lang/da.js +7 -0
  461. data/vendor/assets/javascripts/ckeditor/plugins/showblocks/lang/de.js +7 -0
  462. data/vendor/assets/javascripts/ckeditor/plugins/showblocks/lang/el.js +7 -0
  463. data/vendor/assets/javascripts/ckeditor/plugins/showblocks/lang/en-au.js +7 -0
  464. data/vendor/assets/javascripts/ckeditor/plugins/showblocks/lang/en-ca.js +7 -0
  465. data/vendor/assets/javascripts/ckeditor/plugins/showblocks/lang/en-gb.js +7 -0
  466. data/vendor/assets/javascripts/ckeditor/plugins/showblocks/lang/en.js +7 -0
  467. data/vendor/assets/javascripts/ckeditor/plugins/showblocks/lang/eo.js +7 -0
  468. data/vendor/assets/javascripts/ckeditor/plugins/showblocks/lang/es.js +7 -0
  469. data/vendor/assets/javascripts/ckeditor/plugins/showblocks/lang/et.js +7 -0
  470. data/vendor/assets/javascripts/ckeditor/plugins/showblocks/lang/eu.js +7 -0
  471. data/vendor/assets/javascripts/ckeditor/plugins/showblocks/lang/fa.js +7 -0
  472. data/vendor/assets/javascripts/ckeditor/plugins/showblocks/lang/fi.js +7 -0
  473. data/vendor/assets/javascripts/ckeditor/plugins/showblocks/lang/fo.js +7 -0
  474. data/vendor/assets/javascripts/ckeditor/plugins/showblocks/lang/fr-ca.js +7 -0
  475. data/vendor/assets/javascripts/ckeditor/plugins/showblocks/lang/fr.js +7 -0
  476. data/vendor/assets/javascripts/ckeditor/plugins/showblocks/lang/gl.js +7 -0
  477. data/vendor/assets/javascripts/ckeditor/plugins/showblocks/lang/gu.js +7 -0
  478. data/vendor/assets/javascripts/ckeditor/plugins/showblocks/lang/he.js +7 -0
  479. data/vendor/assets/javascripts/ckeditor/plugins/showblocks/lang/hi.js +7 -0
  480. data/vendor/assets/javascripts/ckeditor/plugins/showblocks/lang/hr.js +7 -0
  481. data/vendor/assets/javascripts/ckeditor/plugins/showblocks/lang/hu.js +7 -0
  482. data/vendor/assets/javascripts/ckeditor/plugins/showblocks/lang/id.js +7 -0
  483. data/vendor/assets/javascripts/ckeditor/plugins/showblocks/lang/is.js +7 -0
  484. data/vendor/assets/javascripts/ckeditor/plugins/showblocks/lang/it.js +7 -0
  485. data/vendor/assets/javascripts/ckeditor/plugins/showblocks/lang/ja.js +7 -0
  486. data/vendor/assets/javascripts/ckeditor/plugins/showblocks/lang/ka.js +7 -0
  487. data/vendor/assets/javascripts/ckeditor/plugins/showblocks/lang/km.js +7 -0
  488. data/vendor/assets/javascripts/ckeditor/plugins/showblocks/lang/ko.js +7 -0
  489. data/vendor/assets/javascripts/ckeditor/plugins/showblocks/lang/ku.js +7 -0
  490. data/vendor/assets/javascripts/ckeditor/plugins/showblocks/lang/lt.js +7 -0
  491. data/vendor/assets/javascripts/ckeditor/plugins/showblocks/lang/lv.js +7 -0
  492. data/vendor/assets/javascripts/ckeditor/plugins/showblocks/lang/mk.js +7 -0
  493. data/vendor/assets/javascripts/ckeditor/plugins/showblocks/lang/mn.js +7 -0
  494. data/vendor/assets/javascripts/ckeditor/plugins/showblocks/lang/ms.js +7 -0
  495. data/vendor/assets/javascripts/ckeditor/plugins/showblocks/lang/nb.js +7 -0
  496. data/vendor/assets/javascripts/ckeditor/plugins/showblocks/lang/nl.js +7 -0
  497. data/vendor/assets/javascripts/ckeditor/plugins/showblocks/lang/no.js +7 -0
  498. data/vendor/assets/javascripts/ckeditor/plugins/showblocks/lang/pl.js +7 -0
  499. data/vendor/assets/javascripts/ckeditor/plugins/showblocks/lang/pt-br.js +7 -0
  500. data/vendor/assets/javascripts/ckeditor/plugins/showblocks/lang/pt.js +7 -0
  501. data/vendor/assets/javascripts/ckeditor/plugins/showblocks/lang/ro.js +7 -0
  502. data/vendor/assets/javascripts/ckeditor/plugins/showblocks/lang/ru.js +7 -0
  503. data/vendor/assets/javascripts/ckeditor/plugins/showblocks/lang/si.js +7 -0
  504. data/vendor/assets/javascripts/ckeditor/plugins/showblocks/lang/sk.js +7 -0
  505. data/vendor/assets/javascripts/ckeditor/plugins/showblocks/lang/sl.js +7 -0
  506. data/vendor/assets/javascripts/ckeditor/plugins/showblocks/lang/sq.js +7 -0
  507. data/vendor/assets/javascripts/ckeditor/plugins/showblocks/lang/sr-latn.js +7 -0
  508. data/vendor/assets/javascripts/ckeditor/plugins/showblocks/lang/sr.js +7 -0
  509. data/vendor/assets/javascripts/ckeditor/plugins/showblocks/lang/sv.js +7 -0
  510. data/vendor/assets/javascripts/ckeditor/plugins/showblocks/lang/th.js +7 -0
  511. data/vendor/assets/javascripts/ckeditor/plugins/showblocks/lang/tr.js +7 -0
  512. data/vendor/assets/javascripts/ckeditor/plugins/showblocks/lang/tt.js +7 -0
  513. data/vendor/assets/javascripts/ckeditor/plugins/showblocks/lang/ug.js +7 -0
  514. data/vendor/assets/javascripts/ckeditor/plugins/showblocks/lang/uk.js +7 -0
  515. data/vendor/assets/javascripts/ckeditor/plugins/showblocks/lang/vi.js +7 -0
  516. data/vendor/assets/javascripts/ckeditor/plugins/showblocks/lang/zh-cn.js +7 -0
  517. data/vendor/assets/javascripts/ckeditor/plugins/showblocks/lang/zh.js +7 -0
  518. data/vendor/assets/javascripts/ckeditor/plugins/showblocks/plugin.js +153 -0
  519. data/vendor/assets/javascripts/ckeditor/plugins/smiley/dialogs/smiley.js +10 -0
  520. data/vendor/assets/javascripts/ckeditor/plugins/specialchar/dialogs/lang/_translationstatus.txt +20 -0
  521. data/vendor/assets/javascripts/ckeditor/plugins/specialchar/dialogs/lang/ar.js +13 -0
  522. data/vendor/assets/javascripts/ckeditor/plugins/specialchar/dialogs/lang/bg.js +13 -0
  523. data/vendor/assets/javascripts/ckeditor/plugins/specialchar/dialogs/lang/ca.js +14 -0
  524. data/vendor/assets/javascripts/ckeditor/plugins/specialchar/dialogs/lang/cs.js +13 -0
  525. data/vendor/assets/javascripts/ckeditor/plugins/specialchar/dialogs/lang/cy.js +14 -0
  526. data/vendor/assets/javascripts/ckeditor/plugins/specialchar/dialogs/lang/de.js +13 -0
  527. data/vendor/assets/javascripts/ckeditor/plugins/specialchar/dialogs/lang/el.js +13 -0
  528. data/vendor/assets/javascripts/ckeditor/plugins/specialchar/dialogs/lang/en-gb.js +13 -0
  529. data/vendor/assets/javascripts/ckeditor/plugins/specialchar/dialogs/lang/en.js +13 -0
  530. data/vendor/assets/javascripts/ckeditor/plugins/specialchar/dialogs/lang/eo.js +12 -0
  531. data/vendor/assets/javascripts/ckeditor/plugins/specialchar/dialogs/lang/es.js +13 -0
  532. data/vendor/assets/javascripts/ckeditor/plugins/specialchar/dialogs/lang/et.js +13 -0
  533. data/vendor/assets/javascripts/ckeditor/plugins/specialchar/dialogs/lang/fa.js +12 -0
  534. data/vendor/assets/javascripts/ckeditor/plugins/specialchar/dialogs/lang/fi.js +13 -0
  535. data/vendor/assets/javascripts/ckeditor/plugins/specialchar/dialogs/lang/fr-ca.js +10 -0
  536. data/vendor/assets/javascripts/ckeditor/plugins/specialchar/dialogs/lang/fr.js +11 -0
  537. data/vendor/assets/javascripts/ckeditor/plugins/specialchar/dialogs/lang/gl.js +13 -0
  538. data/vendor/assets/javascripts/ckeditor/plugins/specialchar/dialogs/lang/he.js +12 -0
  539. data/vendor/assets/javascripts/ckeditor/plugins/specialchar/dialogs/lang/hr.js +13 -0
  540. data/vendor/assets/javascripts/ckeditor/plugins/specialchar/dialogs/lang/hu.js +12 -0
  541. data/vendor/assets/javascripts/ckeditor/plugins/specialchar/dialogs/lang/id.js +13 -0
  542. data/vendor/assets/javascripts/ckeditor/plugins/specialchar/dialogs/lang/it.js +14 -0
  543. data/vendor/assets/javascripts/ckeditor/plugins/specialchar/dialogs/lang/ja.js +9 -0
  544. data/vendor/assets/javascripts/ckeditor/plugins/specialchar/dialogs/lang/km.js +13 -0
  545. data/vendor/assets/javascripts/ckeditor/plugins/specialchar/dialogs/lang/ku.js +13 -0
  546. data/vendor/assets/javascripts/ckeditor/plugins/specialchar/dialogs/lang/lv.js +13 -0
  547. data/vendor/assets/javascripts/ckeditor/plugins/specialchar/dialogs/lang/nb.js +11 -0
  548. data/vendor/assets/javascripts/ckeditor/plugins/specialchar/dialogs/lang/nl.js +13 -0
  549. data/vendor/assets/javascripts/ckeditor/plugins/specialchar/dialogs/lang/no.js +11 -0
  550. data/vendor/assets/javascripts/ckeditor/plugins/specialchar/dialogs/lang/pl.js +12 -0
  551. data/vendor/assets/javascripts/ckeditor/plugins/specialchar/dialogs/lang/pt-br.js +11 -0
  552. data/vendor/assets/javascripts/ckeditor/plugins/specialchar/dialogs/lang/pt.js +13 -0
  553. data/vendor/assets/javascripts/ckeditor/plugins/specialchar/dialogs/lang/ru.js +13 -0
  554. data/vendor/assets/javascripts/ckeditor/plugins/specialchar/dialogs/lang/si.js +13 -0
  555. data/vendor/assets/javascripts/ckeditor/plugins/specialchar/dialogs/lang/sk.js +13 -0
  556. data/vendor/assets/javascripts/ckeditor/plugins/specialchar/dialogs/lang/sl.js +12 -0
  557. data/vendor/assets/javascripts/ckeditor/plugins/specialchar/dialogs/lang/sq.js +13 -0
  558. data/vendor/assets/javascripts/ckeditor/plugins/specialchar/dialogs/lang/sv.js +11 -0
  559. data/vendor/assets/javascripts/ckeditor/plugins/specialchar/dialogs/lang/th.js +13 -0
  560. data/vendor/assets/javascripts/ckeditor/plugins/specialchar/dialogs/lang/tr.js +12 -0
  561. data/vendor/assets/javascripts/ckeditor/plugins/specialchar/dialogs/lang/tt.js +13 -0
  562. data/vendor/assets/javascripts/ckeditor/plugins/specialchar/dialogs/lang/ug.js +13 -0
  563. data/vendor/assets/javascripts/ckeditor/plugins/specialchar/dialogs/lang/uk.js +12 -0
  564. data/vendor/assets/javascripts/ckeditor/plugins/specialchar/dialogs/lang/vi.js +14 -0
  565. data/vendor/assets/javascripts/ckeditor/plugins/specialchar/dialogs/lang/zh-cn.js +9 -0
  566. data/vendor/assets/javascripts/ckeditor/plugins/specialchar/dialogs/lang/zh.js +12 -0
  567. data/vendor/assets/javascripts/ckeditor/plugins/specialchar/dialogs/specialchar.js +14 -0
  568. data/vendor/assets/javascripts/ckeditor/plugins/stylescombo/lang/af.js +11 -0
  569. data/vendor/assets/javascripts/ckeditor/plugins/stylescombo/lang/ar.js +11 -0
  570. data/vendor/assets/javascripts/ckeditor/plugins/stylescombo/lang/bg.js +11 -0
  571. data/vendor/assets/javascripts/ckeditor/plugins/stylescombo/lang/bn.js +11 -0
  572. data/vendor/assets/javascripts/ckeditor/plugins/stylescombo/lang/bs.js +11 -0
  573. data/vendor/assets/javascripts/ckeditor/plugins/stylescombo/lang/ca.js +11 -0
  574. data/vendor/assets/javascripts/ckeditor/plugins/stylescombo/lang/cs.js +11 -0
  575. data/vendor/assets/javascripts/ckeditor/plugins/stylescombo/lang/cy.js +11 -0
  576. data/vendor/assets/javascripts/ckeditor/plugins/stylescombo/lang/da.js +11 -0
  577. data/vendor/assets/javascripts/ckeditor/plugins/stylescombo/lang/de.js +11 -0
  578. data/vendor/assets/javascripts/ckeditor/plugins/stylescombo/lang/el.js +11 -0
  579. data/vendor/assets/javascripts/ckeditor/plugins/stylescombo/lang/en-au.js +11 -0
  580. data/vendor/assets/javascripts/ckeditor/plugins/stylescombo/lang/en-ca.js +11 -0
  581. data/vendor/assets/javascripts/ckeditor/plugins/stylescombo/lang/en-gb.js +11 -0
  582. data/vendor/assets/javascripts/ckeditor/plugins/stylescombo/lang/en.js +11 -0
  583. data/vendor/assets/javascripts/ckeditor/plugins/stylescombo/lang/eo.js +11 -0
  584. data/vendor/assets/javascripts/ckeditor/plugins/stylescombo/lang/es.js +11 -0
  585. data/vendor/assets/javascripts/ckeditor/plugins/stylescombo/lang/et.js +11 -0
  586. data/vendor/assets/javascripts/ckeditor/plugins/stylescombo/lang/eu.js +11 -0
  587. data/vendor/assets/javascripts/ckeditor/plugins/stylescombo/lang/fa.js +11 -0
  588. data/vendor/assets/javascripts/ckeditor/plugins/stylescombo/lang/fi.js +11 -0
  589. data/vendor/assets/javascripts/ckeditor/plugins/stylescombo/lang/fo.js +11 -0
  590. data/vendor/assets/javascripts/ckeditor/plugins/stylescombo/lang/fr-ca.js +11 -0
  591. data/vendor/assets/javascripts/ckeditor/plugins/stylescombo/lang/fr.js +11 -0
  592. data/vendor/assets/javascripts/ckeditor/plugins/stylescombo/lang/gl.js +11 -0
  593. data/vendor/assets/javascripts/ckeditor/plugins/stylescombo/lang/gu.js +11 -0
  594. data/vendor/assets/javascripts/ckeditor/plugins/stylescombo/lang/he.js +11 -0
  595. data/vendor/assets/javascripts/ckeditor/plugins/stylescombo/lang/hi.js +11 -0
  596. data/vendor/assets/javascripts/ckeditor/plugins/stylescombo/lang/hr.js +11 -0
  597. data/vendor/assets/javascripts/ckeditor/plugins/stylescombo/lang/hu.js +11 -0
  598. data/vendor/assets/javascripts/ckeditor/plugins/stylescombo/lang/is.js +11 -0
  599. data/vendor/assets/javascripts/ckeditor/plugins/stylescombo/lang/it.js +11 -0
  600. data/vendor/assets/javascripts/ckeditor/plugins/stylescombo/lang/ja.js +11 -0
  601. data/vendor/assets/javascripts/ckeditor/plugins/stylescombo/lang/ka.js +11 -0
  602. data/vendor/assets/javascripts/ckeditor/plugins/stylescombo/lang/km.js +11 -0
  603. data/vendor/assets/javascripts/ckeditor/plugins/stylescombo/lang/ko.js +11 -0
  604. data/vendor/assets/javascripts/ckeditor/plugins/stylescombo/lang/ku.js +11 -0
  605. data/vendor/assets/javascripts/ckeditor/plugins/stylescombo/lang/lt.js +11 -0
  606. data/vendor/assets/javascripts/ckeditor/plugins/stylescombo/lang/lv.js +11 -0
  607. data/vendor/assets/javascripts/ckeditor/plugins/stylescombo/lang/mk.js +11 -0
  608. data/vendor/assets/javascripts/ckeditor/plugins/stylescombo/lang/mn.js +11 -0
  609. data/vendor/assets/javascripts/ckeditor/plugins/stylescombo/lang/ms.js +11 -0
  610. data/vendor/assets/javascripts/ckeditor/plugins/stylescombo/lang/nb.js +11 -0
  611. data/vendor/assets/javascripts/ckeditor/plugins/stylescombo/lang/nl.js +11 -0
  612. data/vendor/assets/javascripts/ckeditor/plugins/stylescombo/lang/no.js +11 -0
  613. data/vendor/assets/javascripts/ckeditor/plugins/stylescombo/lang/pl.js +11 -0
  614. data/vendor/assets/javascripts/ckeditor/plugins/stylescombo/lang/pt-br.js +11 -0
  615. data/vendor/assets/javascripts/ckeditor/plugins/stylescombo/lang/pt.js +11 -0
  616. data/vendor/assets/javascripts/ckeditor/plugins/stylescombo/lang/ro.js +11 -0
  617. data/vendor/assets/javascripts/ckeditor/plugins/stylescombo/lang/ru.js +11 -0
  618. data/vendor/assets/javascripts/ckeditor/plugins/stylescombo/lang/sk.js +11 -0
  619. data/vendor/assets/javascripts/ckeditor/plugins/stylescombo/lang/sl.js +11 -0
  620. data/vendor/assets/javascripts/ckeditor/plugins/stylescombo/lang/sr-latn.js +11 -0
  621. data/vendor/assets/javascripts/ckeditor/plugins/stylescombo/lang/sr.js +11 -0
  622. data/vendor/assets/javascripts/ckeditor/plugins/stylescombo/lang/sv.js +11 -0
  623. data/vendor/assets/javascripts/ckeditor/plugins/stylescombo/lang/th.js +11 -0
  624. data/vendor/assets/javascripts/ckeditor/plugins/stylescombo/lang/tr.js +11 -0
  625. data/vendor/assets/javascripts/ckeditor/plugins/stylescombo/lang/ug.js +11 -0
  626. data/vendor/assets/javascripts/ckeditor/plugins/stylescombo/lang/uk.js +11 -0
  627. data/vendor/assets/javascripts/ckeditor/plugins/stylescombo/lang/vi.js +11 -0
  628. data/vendor/assets/javascripts/ckeditor/plugins/stylescombo/lang/zh-cn.js +11 -0
  629. data/vendor/assets/javascripts/ckeditor/plugins/stylescombo/lang/zh.js +11 -0
  630. data/vendor/assets/javascripts/ckeditor/plugins/stylescombo/plugin.js +186 -0
  631. data/vendor/assets/javascripts/ckeditor/plugins/stylesheetparser/plugin.js +152 -0
  632. data/vendor/assets/javascripts/ckeditor/plugins/table/dialogs/table.js +21 -0
  633. data/vendor/assets/javascripts/ckeditor/plugins/tabletools/dialogs/tableCell.js +17 -0
  634. data/vendor/assets/javascripts/ckeditor/plugins/templates/dialogs/templates.js +10 -0
  635. data/vendor/assets/javascripts/ckeditor/plugins/templates/templates/default.js +6 -0
  636. data/vendor/assets/javascripts/ckeditor/plugins/widget/dev/console.js +129 -0
  637. data/vendor/assets/javascripts/ckeditor/plugins/widget/dev/contents.css +23 -0
  638. data/vendor/assets/javascripts/ckeditor/plugins/widget/dev/widgetstyles.html +145 -0
  639. data/vendor/assets/javascripts/ckeditor/plugins/widget/images/handle.png +0 -0
  640. data/vendor/assets/javascripts/ckeditor/plugins/widget/lang/ar.js +7 -0
  641. data/vendor/assets/javascripts/ckeditor/plugins/widget/lang/ca.js +7 -0
  642. data/vendor/assets/javascripts/ckeditor/plugins/widget/lang/cs.js +7 -0
  643. data/vendor/assets/javascripts/ckeditor/plugins/widget/lang/cy.js +7 -0
  644. data/vendor/assets/javascripts/ckeditor/plugins/widget/lang/de.js +7 -0
  645. data/vendor/assets/javascripts/ckeditor/plugins/widget/lang/el.js +7 -0
  646. data/vendor/assets/javascripts/ckeditor/plugins/widget/lang/en-gb.js +7 -0
  647. data/vendor/assets/javascripts/ckeditor/plugins/widget/lang/en.js +7 -0
  648. data/vendor/assets/javascripts/ckeditor/plugins/widget/lang/eo.js +7 -0
  649. data/vendor/assets/javascripts/ckeditor/plugins/widget/lang/es.js +7 -0
  650. data/vendor/assets/javascripts/ckeditor/plugins/widget/lang/fa.js +7 -0
  651. data/vendor/assets/javascripts/ckeditor/plugins/widget/lang/fi.js +7 -0
  652. data/vendor/assets/javascripts/ckeditor/plugins/widget/lang/fr.js +7 -0
  653. data/vendor/assets/javascripts/ckeditor/plugins/widget/lang/gl.js +7 -0
  654. data/vendor/assets/javascripts/ckeditor/plugins/widget/lang/he.js +7 -0
  655. data/vendor/assets/javascripts/ckeditor/plugins/widget/lang/hr.js +7 -0
  656. data/vendor/assets/javascripts/ckeditor/plugins/widget/lang/hu.js +7 -0
  657. data/vendor/assets/javascripts/ckeditor/plugins/widget/lang/it.js +7 -0
  658. data/vendor/assets/javascripts/ckeditor/plugins/widget/lang/ja.js +7 -0
  659. data/vendor/assets/javascripts/ckeditor/plugins/widget/lang/km.js +7 -0
  660. data/vendor/assets/javascripts/ckeditor/plugins/widget/lang/ko.js +7 -0
  661. data/vendor/assets/javascripts/ckeditor/plugins/widget/lang/nb.js +7 -0
  662. data/vendor/assets/javascripts/ckeditor/plugins/widget/lang/nl.js +7 -0
  663. data/vendor/assets/javascripts/ckeditor/plugins/widget/lang/no.js +7 -0
  664. data/vendor/assets/javascripts/ckeditor/plugins/widget/lang/pl.js +7 -0
  665. data/vendor/assets/javascripts/ckeditor/plugins/widget/lang/pt-br.js +7 -0
  666. data/vendor/assets/javascripts/ckeditor/plugins/widget/lang/pt.js +7 -0
  667. data/vendor/assets/javascripts/ckeditor/plugins/widget/lang/ru.js +7 -0
  668. data/vendor/assets/javascripts/ckeditor/plugins/widget/lang/sl.js +7 -0
  669. data/vendor/assets/javascripts/ckeditor/plugins/widget/lang/sv.js +7 -0
  670. data/vendor/assets/javascripts/ckeditor/plugins/widget/lang/tt.js +7 -0
  671. data/vendor/assets/javascripts/ckeditor/plugins/widget/lang/uk.js +7 -0
  672. data/vendor/assets/javascripts/ckeditor/plugins/widget/lang/vi.js +7 -0
  673. data/vendor/assets/javascripts/ckeditor/plugins/widget/lang/zh-cn.js +7 -0
  674. data/vendor/assets/javascripts/ckeditor/plugins/widget/lang/zh.js +7 -0
  675. data/vendor/assets/javascripts/ckeditor/plugins/widget/plugin.js +3684 -0
  676. data/vendor/assets/javascripts/ckeditor/plugins/wsc/dialogs/ciframe.html +66 -0
  677. data/vendor/assets/javascripts/ckeditor/plugins/wsc/dialogs/tmpFrameset.html +52 -0
  678. data/vendor/assets/javascripts/ckeditor/plugins/wsc/dialogs/wsc.css +82 -0
  679. data/vendor/assets/javascripts/ckeditor/plugins/wsc/dialogs/wsc.js +74 -0
  680. data/vendor/assets/javascripts/ckeditor/plugins/wsc/dialogs/wsc_ie.js +11 -0
  681. data/vendor/assets/javascripts/ckeditor/skins/BootstrapCK/README.md +26 -0
  682. data/vendor/assets/javascripts/ckeditor/skins/BootstrapCK/dialog.css +616 -0
  683. data/vendor/assets/javascripts/ckeditor/skins/BootstrapCK/editor.css +1088 -0
  684. data/vendor/assets/javascripts/ckeditor/skins/BootstrapCK/icons.png +0 -0
  685. data/vendor/assets/javascripts/ckeditor/skins/BootstrapCK/images/dialog_sides.gif +0 -0
  686. data/vendor/assets/javascripts/ckeditor/skins/BootstrapCK/images/dialog_sides.png +0 -0
  687. data/vendor/assets/javascripts/ckeditor/skins/BootstrapCK/images/dialog_sides_rtl.png +0 -0
  688. data/vendor/assets/javascripts/ckeditor/skins/BootstrapCK/images/mini.png +0 -0
  689. data/vendor/assets/javascripts/ckeditor/skins/BootstrapCK/images/noimage.png +0 -0
  690. data/vendor/assets/javascripts/ckeditor/skins/BootstrapCK/images/sprites.png +0 -0
  691. data/vendor/assets/javascripts/ckeditor/skins/BootstrapCK/images/sprites_ie6.png +0 -0
  692. data/vendor/assets/javascripts/ckeditor/skins/BootstrapCK/images/toolbar_start.gif +0 -0
  693. data/vendor/assets/javascripts/ckeditor/skins/BootstrapCK/skin.js +7 -0
  694. data/vendor/assets/javascripts/ckeditor/skins/BootstrapCK/templates.css +54 -0
  695. data/vendor/assets/javascripts/ckeditor/skins/moono/dialog.css +5 -0
  696. data/vendor/assets/javascripts/ckeditor/skins/moono/dialog_ie.css +5 -0
  697. data/vendor/assets/javascripts/ckeditor/skins/moono/dialog_ie7.css +5 -0
  698. data/vendor/assets/javascripts/ckeditor/skins/moono/dialog_ie8.css +5 -0
  699. data/vendor/assets/javascripts/ckeditor/skins/moono/dialog_iequirks.css +5 -0
  700. data/vendor/assets/javascripts/ckeditor/skins/moono/editor.css +5 -0
  701. data/vendor/assets/javascripts/ckeditor/skins/moono/editor_gecko.css +5 -0
  702. data/vendor/assets/javascripts/ckeditor/skins/moono/editor_ie.css +5 -0
  703. data/vendor/assets/javascripts/ckeditor/skins/moono/editor_ie7.css +5 -0
  704. data/vendor/assets/javascripts/ckeditor/skins/moono/editor_ie8.css +5 -0
  705. data/vendor/assets/javascripts/ckeditor/skins/moono/editor_iequirks.css +5 -0
  706. data/vendor/assets/javascripts/ckeditor/skins/moono/icons.png +0 -0
  707. data/vendor/assets/javascripts/ckeditor/skins/moono/icons_hidpi.png +0 -0
  708. data/vendor/assets/javascripts/ckeditor/skins/moono/images/arrow.png +0 -0
  709. data/vendor/assets/javascripts/ckeditor/skins/moono/images/close.png +0 -0
  710. data/vendor/assets/javascripts/ckeditor/skins/moono/images/hidpi/close.png +0 -0
  711. data/vendor/assets/javascripts/ckeditor/skins/moono/images/hidpi/lock-open.png +0 -0
  712. data/vendor/assets/javascripts/ckeditor/skins/moono/images/hidpi/lock.png +0 -0
  713. data/vendor/assets/javascripts/ckeditor/skins/moono/images/hidpi/refresh.png +0 -0
  714. data/vendor/assets/javascripts/ckeditor/skins/moono/images/lock-open.png +0 -0
  715. data/vendor/assets/javascripts/ckeditor/skins/moono/images/lock.png +0 -0
  716. data/vendor/assets/javascripts/ckeditor/skins/moono/images/refresh.png +0 -0
  717. data/vendor/assets/javascripts/ckeditor/skins/moono/readme.md +51 -0
  718. data/vendor/assets/javascripts/ckeditor/styles.js +111 -0
  719. data/vendor/assets/javascripts/fileuploader.js +1247 -0
  720. data/vendor/assets/stylesheets/ckeditor/contents.css +99 -0
  721. data/vendor/assets/stylesheets/ckeditor/plugins/codemirror/css/codemirror.ckeditor.css +74 -0
  722. data/vendor/assets/stylesheets/ckeditor/plugins/codemirror/css/codemirror.css +245 -0
  723. data/vendor/assets/stylesheets/ckeditor/plugins/codemirror/css/codemirror.min.css +1 -0
  724. data/vendor/assets/stylesheets/ckeditor/plugins/codemirror/theme/ambiance-mobile.css +6 -0
  725. data/vendor/assets/stylesheets/ckeditor/plugins/codemirror/theme/ambiance.css +76 -0
  726. data/vendor/assets/stylesheets/ckeditor/plugins/codemirror/theme/blackboard.css +25 -0
  727. data/vendor/assets/stylesheets/ckeditor/plugins/codemirror/theme/cobalt.css +18 -0
  728. data/vendor/assets/stylesheets/ckeditor/plugins/codemirror/theme/eclipse.css +25 -0
  729. data/vendor/assets/stylesheets/ckeditor/plugins/codemirror/theme/elegant.css +10 -0
  730. data/vendor/assets/stylesheets/ckeditor/plugins/codemirror/theme/erlang-dark.css +21 -0
  731. data/vendor/assets/stylesheets/ckeditor/plugins/codemirror/theme/lesser-dark.css +44 -0
  732. data/vendor/assets/stylesheets/ckeditor/plugins/codemirror/theme/monokai.css +28 -0
  733. data/vendor/assets/stylesheets/ckeditor/plugins/codemirror/theme/neat.css +9 -0
  734. data/vendor/assets/stylesheets/ckeditor/plugins/codemirror/theme/night.css +21 -0
  735. data/vendor/assets/stylesheets/ckeditor/plugins/codemirror/theme/rubyblue.css +21 -0
  736. data/vendor/assets/stylesheets/ckeditor/plugins/codemirror/theme/solarized.css +207 -0
  737. data/vendor/assets/stylesheets/ckeditor/plugins/codemirror/theme/twilight.css +25 -0
  738. data/vendor/assets/stylesheets/ckeditor/plugins/codemirror/theme/vibrant-ink.css +27 -0
  739. data/vendor/assets/stylesheets/ckeditor/plugins/codemirror/theme/xq-dark.css +46 -0
  740. data/vendor/assets/stylesheets/ckeditor/plugins/scayt/dialogs/toolbar.css +71 -0
  741. data/vendor/assets/stylesheets/ckeditor/plugins/templates/dialogs/templates.css +84 -0
  742. data/vendor/assets/stylesheets/ckeditor/plugins/widget/dev/contents.css +23 -0
  743. data/vendor/assets/stylesheets/ckeditor/plugins/wsc/dialogs/wsc.css +82 -0
  744. data/vendor/assets/stylesheets/ckeditor/skins/BootstrapCK/dialog.css +616 -0
  745. data/vendor/assets/stylesheets/ckeditor/skins/BootstrapCK/editor.css +1088 -0
  746. data/vendor/assets/stylesheets/ckeditor/skins/BootstrapCK/templates.css +54 -0
  747. data/vendor/assets/stylesheets/ckeditor/skins/moono/dialog.css +5 -0
  748. data/vendor/assets/stylesheets/ckeditor/skins/moono/dialog_ie.css +5 -0
  749. data/vendor/assets/stylesheets/ckeditor/skins/moono/dialog_ie7.css +5 -0
  750. data/vendor/assets/stylesheets/ckeditor/skins/moono/dialog_ie8.css +5 -0
  751. data/vendor/assets/stylesheets/ckeditor/skins/moono/dialog_iequirks.css +5 -0
  752. data/vendor/assets/stylesheets/ckeditor/skins/moono/dialog_opera.css +5 -0
  753. data/vendor/assets/stylesheets/ckeditor/skins/moono/editor.css +5 -0
  754. data/vendor/assets/stylesheets/ckeditor/skins/moono/editor_gecko.css +5 -0
  755. data/vendor/assets/stylesheets/ckeditor/skins/moono/editor_ie.css +5 -0
  756. data/vendor/assets/stylesheets/ckeditor/skins/moono/editor_ie7.css +5 -0
  757. data/vendor/assets/stylesheets/ckeditor/skins/moono/editor_ie8.css +5 -0
  758. data/vendor/assets/stylesheets/ckeditor/skins/moono/editor_iequirks.css +5 -0
  759. metadata +955 -0
@@ -0,0 +1,7 @@
1
+ /**
2
+ * @license Copyright (c) 2003-2014, CKSource - Frederico Knabben. All rights reserved.
3
+ * For licensing, see LICENSE.md or http://ckeditor.com/license
4
+ */
5
+ CKEDITOR.plugins.setLang( 'widget', 'es', {
6
+ 'move': 'Dar clic y arrastrar para mover'
7
+ } );
@@ -0,0 +1,7 @@
1
+ /**
2
+ * @license Copyright (c) 2003-2014, CKSource - Frederico Knabben. All rights reserved.
3
+ * For licensing, see LICENSE.md or http://ckeditor.com/license
4
+ */
5
+ CKEDITOR.plugins.setLang( 'widget', 'fa', {
6
+ 'move': 'کلیک و کشیدن برای جابجایی'
7
+ } );
@@ -0,0 +1,7 @@
1
+ /**
2
+ * @license Copyright (c) 2003-2014, CKSource - Frederico Knabben. All rights reserved.
3
+ * For licensing, see LICENSE.md or http://ckeditor.com/license
4
+ */
5
+ CKEDITOR.plugins.setLang( 'widget', 'fi', {
6
+ 'move': 'Siirrä klikkaamalla ja raahaamalla'
7
+ } );
@@ -0,0 +1,7 @@
1
+ /**
2
+ * @license Copyright (c) 2003-2014, CKSource - Frederico Knabben. All rights reserved.
3
+ * For licensing, see LICENSE.md or http://ckeditor.com/license
4
+ */
5
+ CKEDITOR.plugins.setLang( 'widget', 'fr', {
6
+ 'move': 'Cliquer et glisser pour déplacer'
7
+ } );
@@ -0,0 +1,7 @@
1
+ /**
2
+ * @license Copyright (c) 2003-2014, CKSource - Frederico Knabben. All rights reserved.
3
+ * For licensing, see LICENSE.md or http://ckeditor.com/license
4
+ */
5
+ CKEDITOR.plugins.setLang( 'widget', 'gl', {
6
+ 'move': 'Prema e arrastre para mover'
7
+ } );
@@ -0,0 +1,7 @@
1
+ /**
2
+ * @license Copyright (c) 2003-2014, CKSource - Frederico Knabben. All rights reserved.
3
+ * For licensing, see LICENSE.md or http://ckeditor.com/license
4
+ */
5
+ CKEDITOR.plugins.setLang( 'widget', 'he', {
6
+ 'move': 'לחץ וגרור להזזה'
7
+ } );
@@ -0,0 +1,7 @@
1
+ /**
2
+ * @license Copyright (c) 2003-2014, CKSource - Frederico Knabben. All rights reserved.
3
+ * For licensing, see LICENSE.md or http://ckeditor.com/license
4
+ */
5
+ CKEDITOR.plugins.setLang( 'widget', 'hr', {
6
+ 'move': 'Klikni i povuci da pomakneš'
7
+ } );
@@ -0,0 +1,7 @@
1
+ /**
2
+ * @license Copyright (c) 2003-2014, CKSource - Frederico Knabben. All rights reserved.
3
+ * For licensing, see LICENSE.md or http://ckeditor.com/license
4
+ */
5
+ CKEDITOR.plugins.setLang( 'widget', 'hu', {
6
+ 'move': 'Kattints és húzd a mozgatáshoz'
7
+ } );
@@ -0,0 +1,7 @@
1
+ /**
2
+ * @license Copyright (c) 2003-2014, CKSource - Frederico Knabben. All rights reserved.
3
+ * For licensing, see LICENSE.md or http://ckeditor.com/license
4
+ */
5
+ CKEDITOR.plugins.setLang( 'widget', 'it', {
6
+ 'move': 'Fare clic e trascinare per spostare'
7
+ } );
@@ -0,0 +1,7 @@
1
+ /**
2
+ * @license Copyright (c) 2003-2014, CKSource - Frederico Knabben. All rights reserved.
3
+ * For licensing, see LICENSE.md or http://ckeditor.com/license
4
+ */
5
+ CKEDITOR.plugins.setLang( 'widget', 'ja', {
6
+ 'move': 'ドラッグして移動'
7
+ } );
@@ -0,0 +1,7 @@
1
+ /**
2
+ * @license Copyright (c) 2003-2014, CKSource - Frederico Knabben. All rights reserved.
3
+ * For licensing, see LICENSE.md or http://ckeditor.com/license
4
+ */
5
+ CKEDITOR.plugins.setLang( 'widget', 'km', {
6
+ 'move': 'ចុច​ហើយ​ទាញ​ដើម្បី​ផ្លាស់​ទី'
7
+ } );
@@ -0,0 +1,7 @@
1
+ /**
2
+ * @license Copyright (c) 2003-2014, CKSource - Frederico Knabben. All rights reserved.
3
+ * For licensing, see LICENSE.md or http://ckeditor.com/license
4
+ */
5
+ CKEDITOR.plugins.setLang( 'widget', 'ko', {
6
+ 'move': '움직이려면 클릭 후 드래그 하세요'
7
+ } );
@@ -0,0 +1,7 @@
1
+ /**
2
+ * @license Copyright (c) 2003-2014, CKSource - Frederico Knabben. All rights reserved.
3
+ * For licensing, see LICENSE.md or http://ckeditor.com/license
4
+ */
5
+ CKEDITOR.plugins.setLang( 'widget', 'nb', {
6
+ 'move': 'Klikk og dra for å flytte'
7
+ } );
@@ -0,0 +1,7 @@
1
+ /**
2
+ * @license Copyright (c) 2003-2014, CKSource - Frederico Knabben. All rights reserved.
3
+ * For licensing, see LICENSE.md or http://ckeditor.com/license
4
+ */
5
+ CKEDITOR.plugins.setLang( 'widget', 'nl', {
6
+ 'move': 'Klik en sleep om te verplaatsen'
7
+ } );
@@ -0,0 +1,7 @@
1
+ /**
2
+ * @license Copyright (c) 2003-2014, CKSource - Frederico Knabben. All rights reserved.
3
+ * For licensing, see LICENSE.md or http://ckeditor.com/license
4
+ */
5
+ CKEDITOR.plugins.setLang( 'widget', 'no', {
6
+ 'move': 'Klikk og dra for å flytte'
7
+ } );
@@ -0,0 +1,7 @@
1
+ /**
2
+ * @license Copyright (c) 2003-2014, CKSource - Frederico Knabben. All rights reserved.
3
+ * For licensing, see LICENSE.md or http://ckeditor.com/license
4
+ */
5
+ CKEDITOR.plugins.setLang( 'widget', 'pl', {
6
+ 'move': 'Kliknij i przeciągnij, by przenieść.'
7
+ } );
@@ -0,0 +1,7 @@
1
+ /**
2
+ * @license Copyright (c) 2003-2014, CKSource - Frederico Knabben. All rights reserved.
3
+ * For licensing, see LICENSE.md or http://ckeditor.com/license
4
+ */
5
+ CKEDITOR.plugins.setLang( 'widget', 'pt-br', {
6
+ 'move': 'Click e arraste para mover'
7
+ } );
@@ -0,0 +1,7 @@
1
+ /**
2
+ * @license Copyright (c) 2003-2014, CKSource - Frederico Knabben. All rights reserved.
3
+ * For licensing, see LICENSE.md or http://ckeditor.com/license
4
+ */
5
+ CKEDITOR.plugins.setLang( 'widget', 'pt', {
6
+ 'move': 'Clique e arraste para mover'
7
+ } );
@@ -0,0 +1,7 @@
1
+ /**
2
+ * @license Copyright (c) 2003-2014, CKSource - Frederico Knabben. All rights reserved.
3
+ * For licensing, see LICENSE.md or http://ckeditor.com/license
4
+ */
5
+ CKEDITOR.plugins.setLang( 'widget', 'ru', {
6
+ 'move': 'Нажмите и перетащите'
7
+ } );
@@ -0,0 +1,7 @@
1
+ /**
2
+ * @license Copyright (c) 2003-2014, CKSource - Frederico Knabben. All rights reserved.
3
+ * For licensing, see LICENSE.md or http://ckeditor.com/license
4
+ */
5
+ CKEDITOR.plugins.setLang( 'widget', 'sl', {
6
+ 'move': 'Kliknite in povlecite, da premaknete'
7
+ } );
@@ -0,0 +1,7 @@
1
+ /**
2
+ * @license Copyright (c) 2003-2014, CKSource - Frederico Knabben. All rights reserved.
3
+ * For licensing, see LICENSE.md or http://ckeditor.com/license
4
+ */
5
+ CKEDITOR.plugins.setLang( 'widget', 'sv', {
6
+ 'move': 'Klicka och drag för att flytta'
7
+ } );
@@ -0,0 +1,7 @@
1
+ /**
2
+ * @license Copyright (c) 2003-2014, CKSource - Frederico Knabben. All rights reserved.
3
+ * For licensing, see LICENSE.md or http://ckeditor.com/license
4
+ */
5
+ CKEDITOR.plugins.setLang( 'widget', 'tt', {
6
+ 'move': 'Күчереп куер өчен басып шудырыгыз'
7
+ } );
@@ -0,0 +1,7 @@
1
+ /**
2
+ * @license Copyright (c) 2003-2014, CKSource - Frederico Knabben. All rights reserved.
3
+ * For licensing, see LICENSE.md or http://ckeditor.com/license
4
+ */
5
+ CKEDITOR.plugins.setLang( 'widget', 'uk', {
6
+ 'move': 'Клікніть і потягніть для переміщення'
7
+ } );
@@ -0,0 +1,7 @@
1
+ /**
2
+ * @license Copyright (c) 2003-2014, CKSource - Frederico Knabben. All rights reserved.
3
+ * For licensing, see LICENSE.md or http://ckeditor.com/license
4
+ */
5
+ CKEDITOR.plugins.setLang( 'widget', 'vi', {
6
+ 'move': 'Nhấp chuột và kéo để di chuyển'
7
+ } );
@@ -0,0 +1,7 @@
1
+ /**
2
+ * @license Copyright (c) 2003-2014, CKSource - Frederico Knabben. All rights reserved.
3
+ * For licensing, see LICENSE.md or http://ckeditor.com/license
4
+ */
5
+ CKEDITOR.plugins.setLang( 'widget', 'zh-cn', {
6
+ 'move': '点击并拖拽以移动'
7
+ } );
@@ -0,0 +1,7 @@
1
+ /**
2
+ * @license Copyright (c) 2003-2014, CKSource - Frederico Knabben. All rights reserved.
3
+ * For licensing, see LICENSE.md or http://ckeditor.com/license
4
+ */
5
+ CKEDITOR.plugins.setLang( 'widget', 'zh', {
6
+ 'move': '拖曳以移動'
7
+ } );
@@ -0,0 +1,3684 @@
1
+ /**
2
+ * @license Copyright (c) 2003-2014, CKSource - Frederico Knabben. All rights reserved.
3
+ * For licensing, see LICENSE.md or http://ckeditor.com/license
4
+ */
5
+
6
+ /**
7
+ * @fileOverview [Widget](http://ckeditor.com/addon/widget) plugin.
8
+ */
9
+
10
+ 'use strict';
11
+
12
+ ( function() {
13
+
14
+ var DRAG_HANDLER_SIZE = 15;
15
+
16
+ CKEDITOR.plugins.add( 'widget', {
17
+ lang: 'ar,ca,cs,cy,de,el,en,en-gb,eo,es,fa,fi,fr,gl,he,hr,hu,it,ja,km,ko,nb,nl,no,pl,pt,pt-br,ru,sl,sv,tt,uk,vi,zh,zh-cn', // %REMOVE_LINE_CORE%
18
+ requires: 'lineutils,clipboard',
19
+ onLoad: function() {
20
+ CKEDITOR.addCss(
21
+ '.cke_widget_wrapper{' +
22
+ 'position:relative;' +
23
+ 'outline:none' +
24
+ '}' +
25
+ '.cke_widget_inline{' +
26
+ 'display:inline-block' +
27
+ '}' +
28
+ '.cke_widget_wrapper:hover>.cke_widget_element{' +
29
+ 'outline:2px solid yellow;' +
30
+ 'cursor:default' +
31
+ '}' +
32
+ '.cke_widget_wrapper:hover .cke_widget_editable{' +
33
+ 'outline:2px solid yellow' +
34
+ '}' +
35
+ '.cke_widget_wrapper.cke_widget_focused>.cke_widget_element,' +
36
+ // We need higher specificity than hover style.
37
+ '.cke_widget_wrapper .cke_widget_editable.cke_widget_editable_focused{' +
38
+ 'outline:2px solid #ace' +
39
+ '}' +
40
+ '.cke_widget_editable{' +
41
+ 'cursor:text' +
42
+ '}' +
43
+ '.cke_widget_drag_handler_container{' +
44
+ 'position:absolute;' +
45
+ 'width:' + DRAG_HANDLER_SIZE + 'px;' +
46
+ 'height:0;' +
47
+ // Initially drag handler should not be visible, until its position will be
48
+ // repositioned. #11177
49
+ 'left:-9999px;' +
50
+ 'opacity:0.75;' +
51
+ 'transition:height 0s 0.2s;' + // Delay hiding drag handler.
52
+ // Prevent drag handler from being misplaced (#11198).
53
+ 'line-height:0' +
54
+ '}' +
55
+ '.cke_widget_wrapper:hover>.cke_widget_drag_handler_container{' +
56
+ 'height:' + DRAG_HANDLER_SIZE + 'px;' +
57
+ 'transition:none' +
58
+ '}' +
59
+ '.cke_widget_drag_handler_container:hover{' +
60
+ 'opacity:1' +
61
+ '}'+
62
+ 'img.cke_widget_drag_handler{' +
63
+ 'cursor:move;' +
64
+ 'width:' + DRAG_HANDLER_SIZE + 'px;' +
65
+ 'height:' + DRAG_HANDLER_SIZE + 'px;' +
66
+ 'display:inline-block' +
67
+ '}' +
68
+ '.cke_widget_mask{' +
69
+ 'position:absolute;' +
70
+ 'top:0;' +
71
+ 'left:0;' +
72
+ 'width:100%;' +
73
+ 'height:100%;' +
74
+ 'display:block' +
75
+ '}' +
76
+ '.cke_editable.cke_widget_dragging, .cke_editable.cke_widget_dragging *{' +
77
+ 'cursor:move !important' +
78
+ '}'
79
+ );
80
+ },
81
+
82
+ beforeInit: function( editor ) {
83
+ /**
84
+ * An instance of widget repository. It contains all
85
+ * {@link CKEDITOR.plugins.widget.repository#registered registered widget definitions} and
86
+ * {@link CKEDITOR.plugins.widget.repository#instances initialized instances}.
87
+ *
88
+ * editor.widgets.add( 'someName', {
89
+ * // Widget definition...
90
+ * } );
91
+ *
92
+ * editor.widgets.registered.someName; // -> Widget definition
93
+ *
94
+ * @since 4.3
95
+ * @readonly
96
+ * @property {CKEDITOR.plugins.widget.repository} widgets
97
+ * @member CKEDITOR.editor
98
+ */
99
+ editor.widgets = new Repository( editor );
100
+ },
101
+
102
+ afterInit: function( editor ) {
103
+ addWidgetButtons( editor );
104
+ setupContextMenu( editor );
105
+ }
106
+ } );
107
+
108
+ /**
109
+ * Widget repository. It keeps track of all {@link #registered registered widget definitions} and
110
+ * {@link #instances initialized instances}. An instance of the repository is available under
111
+ * the {@link CKEDITOR.editor#widgets} property.
112
+ *
113
+ * @class CKEDITOR.plugins.widget.repository
114
+ * @mixins CKEDITOR.event
115
+ * @constructor Creates a widget repository instance. Note that the widget plugin automatically
116
+ * creates a repository instance which is available under the {@link CKEDITOR.editor#widgets} property.
117
+ * @param {CKEDITOR.editor} editor The editor instance for which the repository will be created.
118
+ */
119
+ function Repository( editor ) {
120
+ /**
121
+ * The editor instance for which this repository was created.
122
+ *
123
+ * @readonly
124
+ * @property {CKEDITOR.editor} editor
125
+ */
126
+ this.editor = editor;
127
+
128
+ /**
129
+ * A hash of registered widget definitions (definition name => {@link CKEDITOR.plugins.widget.definition}).
130
+ *
131
+ * To register a definition use the {@link #add} method.
132
+ *
133
+ * @readonly
134
+ */
135
+ this.registered = {};
136
+
137
+ /**
138
+ * An object containing initialized widget instances (widget id => {@link CKEDITOR.plugins.widget}).
139
+ *
140
+ * @readonly
141
+ */
142
+ this.instances = {};
143
+
144
+ /**
145
+ * An array of selected widget instances.
146
+ *
147
+ * @readonly
148
+ * @property {CKEDITOR.plugins.widget[]} selected
149
+ */
150
+ this.selected = [];
151
+
152
+ /**
153
+ * The focused widget instance. See also {@link CKEDITOR.plugins.widget#event-focus}
154
+ * and {@link CKEDITOR.plugins.widget#event-blur} events.
155
+ *
156
+ * editor.on( 'selectionChange', function() {
157
+ * if ( editor.widgets.focused ) {
158
+ * // Do something when a widget is focused...
159
+ * }
160
+ * } );
161
+ *
162
+ * @readonly
163
+ * @property {CKEDITOR.plugins.widget} focused
164
+ */
165
+ this.focused = null;
166
+
167
+ /**
168
+ * The widget instance that contains the nested editable which is currently focused.
169
+ *
170
+ * @readonly
171
+ * @property {CKEDITOR.plugins.widget} widgetHoldingFocusedEditable
172
+ */
173
+ this.widgetHoldingFocusedEditable = null;
174
+
175
+ this._ = {
176
+ nextId: 0,
177
+ upcasts: [],
178
+ upcastCallbacks: [],
179
+ filters: {}
180
+ };
181
+
182
+ setupWidgetsLifecycle( this );
183
+ setupSelectionObserver( this );
184
+ setupMouseObserver( this );
185
+ setupKeyboardObserver( this );
186
+ setupDragAndDrop( this );
187
+ setupNativeCutAndCopy( this );
188
+ }
189
+
190
+ Repository.prototype = {
191
+ /**
192
+ * Minimum interval between selection checks.
193
+ *
194
+ * @private
195
+ */
196
+ MIN_SELECTION_CHECK_INTERVAL: 500,
197
+
198
+ /**
199
+ * Adds a widget definition to the repository. Fires the {@link CKEDITOR.editor#widgetDefinition} event
200
+ * which allows to modify the widget definition which is going to be registered.
201
+ *
202
+ * @param {String} name The name of the widget definition.
203
+ * @param {CKEDITOR.plugins.widget.definition} widgetDef Widget definition.
204
+ * @returns {CKEDITOR.plugins.widget.definition}
205
+ */
206
+ add: function( name, widgetDef ) {
207
+ // Create prototyped copy of original widget definition, so we won't modify it.
208
+ widgetDef = CKEDITOR.tools.prototypedCopy( widgetDef );
209
+ widgetDef.name = name;
210
+
211
+ widgetDef._ = widgetDef._ || {};
212
+
213
+ this.editor.fire( 'widgetDefinition', widgetDef );
214
+
215
+ if ( widgetDef.template )
216
+ widgetDef.template = new CKEDITOR.template( widgetDef.template );
217
+
218
+ addWidgetCommand( this.editor, widgetDef );
219
+ addWidgetProcessors( this, widgetDef );
220
+
221
+ this.registered[ name ] = widgetDef;
222
+
223
+ return widgetDef;
224
+ },
225
+
226
+ /**
227
+ * Adds a callback for element upcasting. Each callback will be executed
228
+ * for every element which is later tested by upcast methods. If a callback
229
+ * returns `false`, the element will not be upcasted.
230
+ *
231
+ * // Images with the "banner" class will not be upcasted (e.g. to the image widget).
232
+ * editor.widgets.addUpcastCallback( function( element ) {
233
+ * if ( element.name == 'img' && element.hasClass( 'banner' ) )
234
+ * return false;
235
+ * } );
236
+ *
237
+ * @param {Function} callback
238
+ * @param {CKEDITOR.htmlParser.element} callback.element
239
+ */
240
+ addUpcastCallback: function( callback ) {
241
+ this._.upcastCallbacks.push( callback );
242
+ },
243
+
244
+ /**
245
+ * Checks the selection to update widget states (selection and focus).
246
+ *
247
+ * This method is triggered by the {@link #event-checkSelection} event.
248
+ */
249
+ checkSelection: function() {
250
+ var sel = this.editor.getSelection(),
251
+ selectedElement = sel.getSelectedElement(),
252
+ updater = stateUpdater( this ),
253
+ widget;
254
+
255
+ // Widget is focused so commit and finish checking.
256
+ if ( selectedElement && ( widget = this.getByElement( selectedElement, true ) ) )
257
+ return updater.focus( widget ).select( widget ).commit();
258
+
259
+ var range = sel.getRanges()[ 0 ];
260
+
261
+ // No ranges or collapsed range mean that nothing is selected, so commit and finish checking.
262
+ if ( !range || range.collapsed )
263
+ return updater.commit();
264
+
265
+ // Range is not empty, so create walker checking for wrappers.
266
+ var walker = new CKEDITOR.dom.walker( range ),
267
+ wrapper;
268
+
269
+ walker.evaluator = isDomWidgetWrapper;
270
+
271
+ while ( ( wrapper = walker.next() ) )
272
+ updater.select( this.getByElement( wrapper ) );
273
+
274
+ updater.commit();
275
+ },
276
+
277
+ /**
278
+ * Checks if all widget instances are still present in the DOM.
279
+ * Destroys those instances that are not present.
280
+ * Reinitializes widgets on widget wrappers for which widget instances
281
+ * cannot be found.
282
+ *
283
+ * This method triggers the {@link #event-checkWidgets} event whose listeners
284
+ * can cancel the method's execution or modify its options.
285
+ *
286
+ * @param [options] The options object.
287
+ * @param {Boolean} [options.initOnlyNew] Initializes widgets only on newly wrapped
288
+ * widget elements (those which still have the `cke_widget_new` class). When this option is
289
+ * set to `true`, widgets which were invalidated (e.g. by replacing with a cloned DOM structure)
290
+ * will not be reinitialized. This makes the check faster.
291
+ * @param {Boolean} [options.focusInited] If only one widget is initialized by
292
+ * the method, it will be focused.
293
+ */
294
+ checkWidgets: function( options ) {
295
+ this.fire( 'checkWidgets', CKEDITOR.tools.copy( options || {} ) );
296
+ },
297
+
298
+ /**
299
+ * Removes the widget from the editor and moves the selection to the closest
300
+ * editable position if the widget was focused before.
301
+ *
302
+ * @param {CKEDITOR.plugins.widget} widget The widget instance to be deleted.
303
+ */
304
+ del: function( widget ) {
305
+ if ( this.focused === widget ) {
306
+ var editor = widget.editor,
307
+ range = editor.createRange(),
308
+ found;
309
+
310
+ // If haven't found place for caret on the default side,
311
+ // try to find it on the other side.
312
+ if ( !( found = range.moveToClosestEditablePosition( widget.wrapper, true ) ) )
313
+ found = range.moveToClosestEditablePosition( widget.wrapper, false );
314
+
315
+ if ( found )
316
+ editor.getSelection().selectRanges( [ range ] );
317
+ }
318
+
319
+ widget.wrapper.remove();
320
+ this.destroy( widget, true );
321
+ },
322
+
323
+ /**
324
+ * Destroys the widget instance.
325
+ *
326
+ * @param {CKEDITOR.plugins.widget} widget The widget instance to be destroyed.
327
+ * @param {Boolean} [offline] Whether the widget is offline (detached from the DOM tree) —
328
+ * in this case the DOM (attributes, classes, etc.) will not be cleaned up.
329
+ */
330
+ destroy: function( widget, offline ) {
331
+ if ( this.widgetHoldingFocusedEditable === widget )
332
+ setFocusedEditable( this, widget, null, offline );
333
+
334
+ widget.destroy( offline );
335
+ delete this.instances[ widget.id ];
336
+ this.fire( 'instanceDestroyed', widget );
337
+ },
338
+
339
+ /**
340
+ * Destroys all widget instances.
341
+ *
342
+ * @param {Boolean} [offline] Whether the widgets are offline (detached from the DOM tree) —
343
+ * in this case the DOM (attributes, classes, etc.) will not be cleaned up.
344
+ */
345
+ destroyAll: function( offline ) {
346
+ var instances = this.instances,
347
+ widget;
348
+
349
+ for ( var id in instances ) {
350
+ widget = instances[ id ];
351
+ this.destroy( widget, offline );
352
+ }
353
+ },
354
+
355
+ /**
356
+ * Finalizes a process of widget creation. This includes:
357
+ *
358
+ * * inserting widget element into editor,
359
+ * * marking widget instance as ready (see {@link CKEDITOR.plugins.widget#event-ready}),
360
+ * * focusing widget instance.
361
+ *
362
+ * This method is used by the default widget's command and is called
363
+ * after widget's dialog (if set) is closed. It may also be used in a
364
+ * customized process of widget creation and insertion.
365
+ *
366
+ * widget.once( 'edit', function() {
367
+ * // Finalize creation only of not ready widgets.
368
+ * if ( widget.isReady() )
369
+ * return;
370
+ *
371
+ * // Cancel edit event to prevent automatic widget insertion.
372
+ * evt.cancel();
373
+ *
374
+ * CustomDialog.open( widget.data, function saveCallback( savedData ) {
375
+ * // Cache the container, because widget may be destroyed while saving data,
376
+ * // if this process will require some deep transformations.
377
+ * var container = widget.wrapper.getParent();
378
+ *
379
+ * widget.setData( savedData );
380
+ *
381
+ * // Widget will be retrieved from container and inserted into editor.
382
+ * editor.widgets.finalizeCreation( container );
383
+ * } );
384
+ * } );
385
+ *
386
+ * @param {CKEDITOR.dom.element/CKEDITOR.dom.documentFragment} container The element
387
+ * or document fragment which contains widget wrapper. The container is used, so before
388
+ * finalizing creation the widget can be freely transformed (even destroyed and reinitialized).
389
+ */
390
+ finalizeCreation: function( container ) {
391
+ var wrapper = container.getFirst();
392
+ if ( wrapper && isDomWidgetWrapper( wrapper ) ) {
393
+ this.editor.insertElement( wrapper );
394
+
395
+ var widget = this.getByElement( wrapper );
396
+ // Fire postponed #ready event.
397
+ widget.ready = true;
398
+ widget.fire( 'ready' );
399
+ widget.focus();
400
+ }
401
+ },
402
+
403
+ /**
404
+ * Finds a widget instance which contains a given element. The element will be the {@link CKEDITOR.plugins.widget#wrapper wrapper}
405
+ * of the returned widget or a descendant of this {@link CKEDITOR.plugins.widget#wrapper wrapper}.
406
+ *
407
+ * editor.widgets.getByElement( someWidget.wrapper ); // -> someWidget
408
+ * editor.widgets.getByElement( someWidget.parts.caption ); // -> someWidget
409
+ *
410
+ * // Check wrapper only:
411
+ * editor.widgets.getByElement( someWidget.wrapper, true ); // -> someWidget
412
+ * editor.widgets.getByElement( someWidget.parts.caption, true ); // -> null
413
+ *
414
+ * @param {CKEDITOR.dom.element} element The element to be checked.
415
+ * @param {Boolean} [checkWrapperOnly] If set to `true`, the method will not check wrappers' descendants.
416
+ * @returns {CKEDITOR.plugins.widget} The widget instance or `null`.
417
+ */
418
+ getByElement: function( element, checkWrapperOnly ) {
419
+ if ( !element )
420
+ return null;
421
+
422
+ var wrapper;
423
+
424
+ for ( var id in this.instances ) {
425
+ wrapper = this.instances[ id ].wrapper;
426
+ if ( wrapper.equals( element ) || ( !checkWrapperOnly && wrapper.contains( element ) ) )
427
+ return this.instances[ id ];
428
+ }
429
+
430
+ return null;
431
+ },
432
+
433
+ /**
434
+ * Initializes a widget on a given element if the widget has not been initialized on it yet.
435
+ *
436
+ * @param {CKEDITOR.dom.element} element The future widget element.
437
+ * @param {String/CKEDITOR.plugins.widget.definition} [widgetDef] Name of a widget or a widget definition.
438
+ * The widget definition should be previously registered by using the
439
+ * {@link CKEDITOR.plugins.widget.repository#add} method.
440
+ * @param [startupData] Widget startup data (has precedence over default one).
441
+ * @returns {CKEDITOR.plugins.widget} The widget instance or `null` if a widget could not be initialized on
442
+ * a given element.
443
+ */
444
+ initOn: function( element, widgetDef, startupData ) {
445
+ if ( !widgetDef )
446
+ widgetDef = this.registered[ element.data( 'widget' ) ];
447
+ else if ( typeof widgetDef == 'string' )
448
+ widgetDef = this.registered[ widgetDef ];
449
+
450
+ if ( !widgetDef )
451
+ return null;
452
+
453
+ // Wrap element if still wasn't wrapped (was added during runtime by method that skips dataProcessor).
454
+ var wrapper = this.wrapElement( element, widgetDef.name );
455
+
456
+ if ( wrapper ) {
457
+ // Check if widget wrapper is new (widget hasn't been initialized on it yet).
458
+ // This class will be removed by widget constructor to avoid locking snapshot twice.
459
+ if ( wrapper.hasClass( 'cke_widget_new' ) ) {
460
+ var widget = new Widget( this, this._.nextId++, element, widgetDef, startupData );
461
+
462
+ // Widget could be destroyed when initializing it.
463
+ if ( widget.isInited() ) {
464
+ this.instances[ widget.id ] = widget;
465
+
466
+ return widget;
467
+ } else
468
+ return null;
469
+ }
470
+
471
+ // Widget already has been initialized, so try to get widget by element.
472
+ // Note - it may happen that other instance will returned than the one created above,
473
+ // if for example widget was destroyed and reinitialized.
474
+ return this.getByElement( element );
475
+ }
476
+
477
+ // No wrapper means that there's no widget for this element.
478
+ return null;
479
+ },
480
+
481
+ /**
482
+ * Initializes widgets on all elements which were wrapped by {@link #wrapElement} and
483
+ * have not been initialized yet.
484
+ *
485
+ * @param {CKEDITOR.dom.element} [container=editor.editable()] The container which will be checked for not
486
+ * initialized widgets. Defaults to editor's {@link CKEDITOR.editor#editable editable} element.
487
+ * @returns {CKEDITOR.plugins.widget[]} Array of widget instances which have been initialized.
488
+ */
489
+ initOnAll: function( container ) {
490
+ var newWidgets = ( container || this.editor.editable() ).find( '.cke_widget_new' ),
491
+ newInstances = [],
492
+ instance;
493
+
494
+ for ( var i = newWidgets.count(); i--; ) {
495
+ instance = this.initOn( newWidgets.getItem( i ).getFirst( isDomWidgetElement ) );
496
+ if ( instance )
497
+ newInstances.push( instance );
498
+ }
499
+
500
+ return newInstances;
501
+ },
502
+
503
+ /**
504
+ * Parses element classes string and returns an object
505
+ * whose keys contain class names. Skips all `cke_*` classes.
506
+ *
507
+ * This method is used by the {@link CKEDITOR.plugins.widget#getClasses} method and
508
+ * may be used when overriding that method.
509
+ *
510
+ * @since 4.4
511
+ * @param {String} classes String (value of `class` attribute).
512
+ * @returns {Object} Object containing classes or `null` if no classes found.
513
+ */
514
+ parseElementClasses: function( classes ) {
515
+ if ( !classes )
516
+ return null;
517
+
518
+ classes = CKEDITOR.tools.trim( classes ).split( /\s+/ );
519
+
520
+ var cl,
521
+ obj = {},
522
+ hasClasses = 0;
523
+
524
+ while ( ( cl = classes.pop() ) ) {
525
+ if ( cl.indexOf( 'cke_' ) == -1 )
526
+ obj[ cl ] = hasClasses = 1;
527
+ }
528
+
529
+ return hasClasses ? obj : null;
530
+ },
531
+
532
+ /**
533
+ * Wraps an element with a widget's non-editable container.
534
+ *
535
+ * If this method is called on an {@link CKEDITOR.htmlParser.element}, then it will
536
+ * also take care of fixing the DOM after wrapping (the wrapper may not be allowed in element's parent).
537
+ *
538
+ * @param {CKEDITOR.dom.element/CKEDITOR.htmlParser.element} element The widget element to be wrapped.
539
+ * @param {String} [widgetName] The name of the widget definition. Defaults to element's `data-widget`
540
+ * attribute value.
541
+ * @returns {CKEDITOR.dom.element/CKEDITOR.htmlParser.element} The wrapper element or `null` if
542
+ * the widget definition of this name is not registered.
543
+ */
544
+ wrapElement: function( element, widgetName ) {
545
+ var wrapper = null,
546
+ widgetDef,
547
+ isInline;
548
+
549
+ if ( element instanceof CKEDITOR.dom.element ) {
550
+ widgetDef = this.registered[ widgetName || element.data( 'widget' ) ];
551
+ if ( !widgetDef )
552
+ return null;
553
+
554
+ // Do not wrap already wrapped element.
555
+ wrapper = element.getParent();
556
+ if ( wrapper && wrapper.type == CKEDITOR.NODE_ELEMENT && wrapper.data( 'cke-widget-wrapper' ) )
557
+ return wrapper;
558
+
559
+ // If attribute isn't already set (e.g. for pasted widget), set it.
560
+ if ( !element.hasAttribute( 'data-cke-widget-keep-attr' ) )
561
+ element.data( 'cke-widget-keep-attr', element.data( 'widget' ) ? 1 : 0 );
562
+ if ( widgetName )
563
+ element.data( 'widget', widgetName );
564
+
565
+ isInline = isWidgetInline( widgetDef, element.getName() );
566
+
567
+ wrapper = new CKEDITOR.dom.element( isInline ? 'span' : 'div' );
568
+ wrapper.setAttributes( getWrapperAttributes( isInline ) );
569
+
570
+ wrapper.data( 'cke-display-name', widgetDef.pathName ? widgetDef.pathName : element.getName() );
571
+
572
+ // Replace element unless it is a detached one.
573
+ if ( element.getParent( true ) )
574
+ wrapper.replace( element );
575
+ element.appendTo( wrapper );
576
+ }
577
+ else if ( element instanceof CKEDITOR.htmlParser.element ) {
578
+ widgetDef = this.registered[ widgetName || element.attributes[ 'data-widget' ] ];
579
+ if ( !widgetDef )
580
+ return null;
581
+
582
+ wrapper = element.parent;
583
+ if ( wrapper && wrapper.type == CKEDITOR.NODE_ELEMENT && wrapper.attributes[ 'data-cke-widget-wrapper' ] )
584
+ return wrapper;
585
+
586
+ // If attribute isn't already set (e.g. for pasted widget), set it.
587
+ if ( !( 'data-cke-widget-keep-attr' in element.attributes ) )
588
+ element.attributes[ 'data-cke-widget-keep-attr' ] = element.attributes[ 'data-widget' ] ? 1 : 0;
589
+ if ( widgetName )
590
+ element.attributes[ 'data-widget' ] = widgetName;
591
+
592
+ isInline = isWidgetInline( widgetDef, element.name );
593
+
594
+ wrapper = new CKEDITOR.htmlParser.element( isInline ? 'span' : 'div', getWrapperAttributes( isInline ) );
595
+
596
+ wrapper.attributes[ 'data-cke-display-name' ] = widgetDef.pathName ? widgetDef.pathName : element.name;
597
+
598
+ var parent = element.parent,
599
+ index;
600
+
601
+ // Don't detach already detached element.
602
+ if ( parent ) {
603
+ index = element.getIndex();
604
+ element.remove();
605
+ }
606
+
607
+ wrapper.add( element );
608
+
609
+ // Insert wrapper fixing DOM (splitting parents if wrapper is not allowed inside them).
610
+ parent && insertElement( parent, index, wrapper );
611
+ }
612
+
613
+ return wrapper;
614
+ },
615
+
616
+ // Expose for tests.
617
+ _tests_getNestedEditable: getNestedEditable,
618
+ _tests_createEditableFilter: createEditableFilter
619
+ };
620
+
621
+ CKEDITOR.event.implementOn( Repository.prototype );
622
+
623
+ /**
624
+ * An event fired when a widget instance is created, but before it is fully initialized.
625
+ *
626
+ * @event instanceCreated
627
+ * @param {CKEDITOR.plugins.widget} data The widget instance.
628
+ */
629
+
630
+ /**
631
+ * An event fired when a widget instance was destroyed.
632
+ *
633
+ * See also {@link CKEDITOR.plugins.widget#event-destroy}.
634
+ *
635
+ * @event instanceDestroyed
636
+ * @param {CKEDITOR.plugins.widget} data The widget instance.
637
+ */
638
+
639
+ /**
640
+ * An event fired to trigger the selection check.
641
+ *
642
+ * See the {@link #method-checkSelection} method.
643
+ *
644
+ * @event checkSelection
645
+ */
646
+
647
+ /**
648
+ * An event fired by the the {@link #method-checkWidgets} method.
649
+ *
650
+ * It can be canceled in order to stop the {@link #method-checkWidgets}
651
+ * method execution or the event listener can modify the method's options.
652
+ *
653
+ * @event checkWidgets
654
+ * @param [data]
655
+ * @param {Boolean} [data.initOnlyNew] Initialize widgets only on newly wrapped
656
+ * widget elements (those which still have the `cke_widget_new` class). When this option is
657
+ * set to `true`, widgets which were invalidated (e.g. by replacing with a cloned DOM structure)
658
+ * will not be reinitialized. This makes the check faster.
659
+ * @param {Boolean} [data.focusInited] If only one widget is initialized by
660
+ * the method, it will be focused.
661
+ */
662
+
663
+
664
+ /**
665
+ * An instance of a widget. Together with {@link CKEDITOR.plugins.widget.repository} these
666
+ * two classes constitute the core of the Widget System.
667
+ *
668
+ * Note that neither the repository nor the widget instances can be created by using their constructors.
669
+ * A repository instance is automatically set up by the Widget plugin and is accessible under
670
+ * {@link CKEDITOR.editor#widgets}, while widget instances are created and destroyed by the repository.
671
+ *
672
+ * To create a widget, first you need to {@link CKEDITOR.plugins.widget.repository#add register} its
673
+ * {@link CKEDITOR.plugins.widget.definition definition}:
674
+ *
675
+ * editor.widgets.add( 'simplebox', {
676
+ * upcast: function( element ) {
677
+ * // Defines which elements will become widgets.
678
+ * if ( element.hasClass( 'simplebox' ) )
679
+ * return true;
680
+ * },
681
+ * init: function() {
682
+ * // ...
683
+ * }
684
+ * } );
685
+ *
686
+ * Once the widget definition is registered, widgets will be automatically
687
+ * created when loading data:
688
+ *
689
+ * editor.setData( '<div class="simplebox">foo</div>', function() {
690
+ * console.log( editor.widgets.instances ); // -> An object containing one instance.
691
+ * } );
692
+ *
693
+ * It is also possible to create instances during runtime by using a command
694
+ * (if a {@link CKEDITOR.plugins.widget.definition#template} property was defined):
695
+ *
696
+ * // You can execute an automatically defined command to
697
+ * // insert a new simplebox widget or edit the one currently focused.
698
+ * editor.execCommand( 'simplebox' );
699
+ *
700
+ * Or in a completely custom way:
701
+ *
702
+ * var element = editor.createElement( 'div' );
703
+ * editor.insertElement( element );
704
+ * var widget = editor.widgets.initOn( element, 'simplebox' );
705
+ *
706
+ * @since 4.3
707
+ * @class CKEDITOR.plugins.widget
708
+ * @mixins CKEDITOR.event
709
+ * @extends CKEDITOR.plugins.widget.definition
710
+ * @constructor Creates an instance of the widget class. Do not use it directly, but instead initialize widgets
711
+ * by using the {@link CKEDITOR.plugins.widget.repository#initOn} method or by the upcasting system.
712
+ * @param {CKEDITOR.plugins.widget.repository} widgetsRepo
713
+ * @param {Number} id Unique ID of this widget instance.
714
+ * @param {CKEDITOR.dom.element} element The widget element.
715
+ * @param {CKEDITOR.plugins.widget.definition} widgetDef Widget's registered definition.
716
+ * @param [startupData] Initial widget data. This data object will overwrite the default data and
717
+ * the data loaded from the DOM.
718
+ */
719
+ function Widget( widgetsRepo, id, element, widgetDef, startupData ) {
720
+ var editor = widgetsRepo.editor;
721
+
722
+ // Extend this widget with widgetDef-specific methods and properties.
723
+ CKEDITOR.tools.extend( this, widgetDef, {
724
+ /**
725
+ * The editor instance.
726
+ *
727
+ * @readonly
728
+ * @property {CKEDITOR.editor}
729
+ */
730
+ editor: editor,
731
+
732
+ /**
733
+ * This widget's unique (per editor instance) ID.
734
+ *
735
+ * @readonly
736
+ * @property {Number}
737
+ */
738
+ id: id,
739
+
740
+ /**
741
+ * Whether this widget is an inline widget (based on an inline element unless
742
+ * forced otherwise by {@link CKEDITOR.plugins.widget.definition#inline}).
743
+ *
744
+ * **Note:** This option does not allow to turn a block element into an inline widget.
745
+ * However, it makes it possible to turn an inline element into a block widget or to
746
+ * force a correct type in case when automatic recognition fails.
747
+ *
748
+ * @readonly
749
+ * @property {Boolean}
750
+ */
751
+ inline: element.getParent().getName() == 'span',
752
+
753
+ /**
754
+ * The widget element &mdash; the element on which the widget was initialized.
755
+ *
756
+ * @readonly
757
+ * @property {CKEDITOR.dom.element} element
758
+ */
759
+ element: element,
760
+
761
+ /**
762
+ * Widget's data object.
763
+ *
764
+ * The data can only be set by using the {@link #setData} method.
765
+ * Changes made to the data fire the {@link #event-data} event.
766
+ *
767
+ * @readonly
768
+ */
769
+ data: CKEDITOR.tools.extend( {}, typeof widgetDef.defaults == 'function' ? widgetDef.defaults() : widgetDef.defaults ),
770
+
771
+ /**
772
+ * Indicates if a widget is data-ready. Set to `true` when data from all sources
773
+ * ({@link CKEDITOR.plugins.widget.definition#defaults}, set in the
774
+ * {@link #init} method, loaded from the widget's element and startup data coming from the constructor)
775
+ * are finally loaded. This is immediately followed by the first {@link #event-data}.
776
+ *
777
+ * @readonly
778
+ */
779
+ dataReady: false,
780
+
781
+ /**
782
+ * Whether a widget instance was initialized. This means that:
783
+ *
784
+ * * An instance was created,
785
+ * * Its properties were set,
786
+ * * The `init` method was executed.
787
+ *
788
+ * **Note**: The first {@link #event-data} event could not be fired yet which
789
+ * means that the widget's DOM has not been set up yet. Wait for the {@link #event-ready}
790
+ * event to be notified when a widget is fully initialized and ready.
791
+ *
792
+ * **Note**: Use the {@link #isInited} method to check whether a widget is initialized and
793
+ * has not been destroyed.
794
+ *
795
+ * @readonly
796
+ */
797
+ inited: false,
798
+
799
+ /**
800
+ * Whether a widget instance is ready. This means that the widget is {@link #inited} and
801
+ * that its DOM was finally set up.
802
+ *
803
+ * **Note:** Use the {@link #isReady} method to check whether a widget is ready and
804
+ * has not been destroyed.
805
+ *
806
+ * @readonly
807
+ */
808
+ ready: false,
809
+
810
+ // Revert what widgetDef could override (automatic #edit listener).
811
+ edit: Widget.prototype.edit,
812
+
813
+ /**
814
+ * The nested editable element which is currently focused.
815
+ *
816
+ * @readonly
817
+ * @property {CKEDITOR.plugins.widget.nestedEditable}
818
+ */
819
+ focusedEditable: null,
820
+
821
+ /**
822
+ * The widget definition from which this instance was created.
823
+ *
824
+ * @readonly
825
+ * @property {CKEDITOR.plugins.widget.definition} definition
826
+ */
827
+ definition: widgetDef,
828
+
829
+ /**
830
+ * Link to the widget repository which created this instance.
831
+ *
832
+ * @readonly
833
+ * @property {CKEDITOR.plugins.widget.repository} repository
834
+ */
835
+ repository: widgetsRepo,
836
+
837
+ draggable: widgetDef.draggable !== false,
838
+
839
+ // WAAARNING: Overwrite widgetDef's priv object, because otherwise violent unicorn's gonna visit you.
840
+ _: {
841
+ downcastFn: ( widgetDef.downcast && typeof widgetDef.downcast == 'string' ) ?
842
+ widgetDef.downcasts[ widgetDef.downcast ] : widgetDef.downcast
843
+ }
844
+ }, true );
845
+
846
+ /**
847
+ * An object of widget component elements.
848
+ *
849
+ * For every `partName => selector` pair in {@link CKEDITOR.plugins.widget.definition#parts},
850
+ * one `partName => element` pair is added to this object during the widget initialization.
851
+ *
852
+ * @readonly
853
+ * @property {Object} parts
854
+ */
855
+
856
+ /**
857
+ * The template which will be used to create a new widget element (when the widget's command is executed).
858
+ * It will be populated with {@link #defaults default values}.
859
+ *
860
+ * @readonly
861
+ * @property {CKEDITOR.template} template
862
+ */
863
+
864
+ /**
865
+ * The widget wrapper &mdash; a non-editable `div` or `span` element (depending on {@link #inline})
866
+ * which is a parent of the {@link #element} and widget compontents like the drag handler and the {@link #mask}.
867
+ * It is the outermost widget element.
868
+ *
869
+ * @readonly
870
+ * @property {CKEDITOR.dom.element} wrapper
871
+ */
872
+
873
+ widgetsRepo.fire( 'instanceCreated', this );
874
+
875
+ setupWidget( this, widgetDef );
876
+
877
+ this.init && this.init();
878
+
879
+ // Finally mark widget as inited.
880
+ this.inited = true;
881
+
882
+ setupWidgetData( this, startupData );
883
+
884
+ // If at some point (e.g. in #data listener) widget hasn't been destroyed
885
+ // and widget is already attached to document then fire #ready.
886
+ if ( this.isInited() && editor.editable().contains( this.wrapper ) ) {
887
+ this.ready = true;
888
+ this.fire( 'ready' );
889
+ }
890
+ }
891
+
892
+ Widget.prototype = {
893
+ /**
894
+ * Adds a class to the widget element. This method is used by
895
+ * the {@link #applyStyle} method and should be overriden by widgets
896
+ * which should handle classes differently (e.g. add them to other elements).
897
+ *
898
+ * **Note**: This method should not be used directly. Use the {@link #setData} method to
899
+ * set the `classes` property. Read more in the {@link #setData} documentation.
900
+ *
901
+ * See also: {@link #removeClass}, {@link #hasClass}, {@link #getClasses}.
902
+ *
903
+ * @since 4.4
904
+ * @param {String} className The class name to be added.
905
+ */
906
+ addClass: function( className ) {
907
+ this.element.addClass( className );
908
+ },
909
+
910
+ /**
911
+ * Applies the specified style to the widget. It is highly recommended to use the
912
+ * {@link CKEDITOR.editor#applyStyle} or {@link CKEDITOR.style#apply} methods instead of
913
+ * using this method directly, because unlike editor's and style's methods, this one
914
+ * does not perform any checks.
915
+ *
916
+ * By default this method handles only classes defined in the style. It clones existing
917
+ * classes which are stored in the {@link #property-data widget data}'s `classes` property,
918
+ * adds new classes, and calls the {@link #setData} method if at least one new class was added.
919
+ * Then, using the {@link #event-data} event listener widget applies modifications passing
920
+ * new classes to the {@link #addClass} method.
921
+ *
922
+ * If you need to handle classes differently than in the default way, you can override the
923
+ * {@link #addClass} and related methods. You can also handle other style properties than `classes`
924
+ * by overriding this method.
925
+ *
926
+ * See also: {@link #checkStyleActive}, {@link #removeStyle}.
927
+ *
928
+ * @since 4.4
929
+ * @param {CKEDITOR.style} style The custom widget style to be applied.
930
+ */
931
+ applyStyle: function( style ) {
932
+ applyRemoveStyle( this, style, 1 );
933
+ },
934
+
935
+ /**
936
+ * Checks if the specified style is applied to this widget. It is highly recommended to use the
937
+ * {@link CKEDITOR.style#checkActive} method instead of using this method directly,
938
+ * because unlike style's method, this one does not perform any checks.
939
+ *
940
+ * By default this method handles only classes defined in the style and passes
941
+ * them to the {@link #hasClass} method. You can override these methods to handle classes
942
+ * differently or to handle more of the style properties.
943
+ *
944
+ * See also: {@link #applyStyle}, {@link #removeStyle}.
945
+ *
946
+ * @since 4.4
947
+ * @param {CKEDITOR.style} style The custom widget style to be checked.
948
+ * @returns {Boolean} Whether the style is applied to this widget.
949
+ */
950
+ checkStyleActive: function( style ) {
951
+ var classes = getStyleClasses( style ),
952
+ cl;
953
+
954
+ if ( !classes )
955
+ return false;
956
+
957
+ while ( ( cl = classes.pop() ) ) {
958
+ if ( !this.hasClass( cl ) )
959
+ return false;
960
+ }
961
+ return true;
962
+ },
963
+
964
+ /**
965
+ * Destroys this widget instance.
966
+ *
967
+ * Use {@link CKEDITOR.plugins.widget.repository#destroy} when possible instead of this method.
968
+ *
969
+ * This method fires the {#event-destroy} event.
970
+ *
971
+ * @param {Boolean} [offline] Whether a widget is offline (detached from the DOM tree) &mdash;
972
+ * in this case the DOM (attributes, classes, etc.) will not be cleaned up.
973
+ */
974
+ destroy: function( offline ) {
975
+ var editor = this.editor;
976
+
977
+ this.fire( 'destroy' );
978
+
979
+ if ( this.editables ) {
980
+ for ( var name in this.editables )
981
+ this.destroyEditable( name, offline );
982
+ }
983
+
984
+ if ( !offline ) {
985
+ if ( this.element.data( 'cke-widget-keep-attr' ) == '0' )
986
+ this.element.removeAttribute( 'data-widget' );
987
+ this.element.removeAttributes( [ 'data-cke-widget-data', 'data-cke-widget-keep-attr' ] );
988
+ this.element.removeClass( 'cke_widget_element' );
989
+ this.element.replace( this.wrapper );
990
+ }
991
+
992
+ this.wrapper = null;
993
+ },
994
+
995
+ /**
996
+ * Destroys a nested editable.
997
+ *
998
+ * @param {String} editableName Nested editable name.
999
+ * @param {Boolean} [offline] See {@link #method-destroy} method.
1000
+ */
1001
+ destroyEditable: function( editableName, offline ) {
1002
+ var editable = this.editables[ editableName ];
1003
+
1004
+ editable.removeListener( 'focus', onEditableFocus );
1005
+ editable.removeListener( 'blur', onEditableBlur );
1006
+ this.editor.focusManager.remove( editable );
1007
+
1008
+ if ( !offline ) {
1009
+ editable.removeClass( 'cke_widget_editable' );
1010
+ editable.removeClass( 'cke_widget_editable_focused' );
1011
+ editable.removeAttributes( [ 'contenteditable', 'data-cke-widget-editable', 'data-cke-enter-mode' ] );
1012
+ }
1013
+
1014
+ delete this.editables[ editableName ];
1015
+ },
1016
+
1017
+ /**
1018
+ * Starts widget editing.
1019
+ *
1020
+ * This method fires the {@link CKEDITOR.plugins.widget#event-edit} event
1021
+ * which may be cancelled in order to prevent it from opening a dialog window.
1022
+ *
1023
+ * The dialog window name is obtained from the event's data `dialog` property or
1024
+ * from {@link CKEDITOR.plugins.widget.definition#dialog}.
1025
+ */
1026
+ edit: function() {
1027
+ var evtData = { dialog: this.dialog },
1028
+ that = this;
1029
+
1030
+ // Edit event was blocked, but there's no dialog to be automatically opened.
1031
+ if ( this.fire( 'edit', evtData ) === false || !evtData.dialog )
1032
+ return;
1033
+
1034
+ this.editor.openDialog( evtData.dialog, function( dialog ) {
1035
+ var showListener,
1036
+ okListener;
1037
+
1038
+ // Allow to add a custom dialog handler.
1039
+ if ( that.fire( 'dialog', dialog ) === false )
1040
+ return;
1041
+
1042
+ showListener = dialog.on( 'show', function() {
1043
+ dialog.setupContent( that );
1044
+ } );
1045
+
1046
+ okListener = dialog.on( 'ok', function() {
1047
+ // Commit dialog's fields, but prevent from
1048
+ // firing data event for every field. Fire only one,
1049
+ // bulk event at the end.
1050
+ var dataChanged,
1051
+ dataListener = that.on( 'data', function( evt ) {
1052
+ dataChanged = 1;
1053
+ evt.cancel();
1054
+ }, null, null, 0 );
1055
+
1056
+ // Create snapshot preceeding snapshot with changed widget...
1057
+ // TODO it should not be required, but it is and I found similar
1058
+ // code in dialog#ok listener in dialog/plugin.js.
1059
+ that.editor.fire( 'saveSnapshot' );
1060
+ dialog.commitContent( that );
1061
+
1062
+ dataListener.removeListener();
1063
+ if ( dataChanged ) {
1064
+ that.fire( 'data', that.data );
1065
+ that.editor.fire( 'saveSnapshot' );
1066
+ }
1067
+ } );
1068
+
1069
+ dialog.once( 'hide', function() {
1070
+ showListener.removeListener();
1071
+ okListener.removeListener();
1072
+ } );
1073
+ } );
1074
+ },
1075
+
1076
+ /**
1077
+ * Returns widget element classes parsed to an object. This method
1078
+ * is used to populate the `classes` property of widget's {@link #property-data}.
1079
+ *
1080
+ * This method reuses {@link CKEDITOR.plugins.widget.repository#parseElementClasses}.
1081
+ * It should be overriden if a widget should handle classes differently (e.g. on other elements).
1082
+ *
1083
+ * See also: {@link #removeClass}, {@link #addClass}, {@link #hasClass}.
1084
+ *
1085
+ * @since 4.4
1086
+ * @returns {Object}
1087
+ */
1088
+ getClasses: function() {
1089
+ return this.repository.parseElementClasses( this.element.getAttribute( 'class' ) );
1090
+ },
1091
+
1092
+ /**
1093
+ * Checks if the widget element has specified class. This method is used by
1094
+ * the {@link #checkStyleActive} method and should be overriden by widgets
1095
+ * which should handle classes differently (e.g. on other elements).
1096
+ *
1097
+ * See also: {@link #removeClass}, {@link #addClass}, {@link #getClasses}.
1098
+ *
1099
+ * @since 4.4
1100
+ * @param {String} className The class to be checked.
1101
+ * @param {Boolean} Whether a widget has specified class.
1102
+ */
1103
+ hasClass: function( className ) {
1104
+ return this.element.hasClass( className );
1105
+ },
1106
+
1107
+ /**
1108
+ * Initializes a nested editable.
1109
+ *
1110
+ * **Note**: Only elements from {@link CKEDITOR.dtd#$editable} may become editables.
1111
+ *
1112
+ * @param {String} editableName The nested editable name.
1113
+ * @param {CKEDITOR.plugins.widget.nestedEditable.definition} definition The definition of the nested editable.
1114
+ * @returns {Boolean} Whether an editable was successfully initialized.
1115
+ */
1116
+ initEditable: function( editableName, definition ) {
1117
+ var editable = this.wrapper.findOne( definition.selector );
1118
+
1119
+ if ( editable && editable.is( CKEDITOR.dtd.$editable ) ) {
1120
+ editable = new NestedEditable( this.editor, editable, {
1121
+ filter: createEditableFilter.call( this.repository, this.name, editableName, definition )
1122
+ } );
1123
+ this.editables[ editableName ] = editable;
1124
+
1125
+ editable.setAttributes( {
1126
+ contenteditable: 'true',
1127
+ 'data-cke-widget-editable': editableName,
1128
+ 'data-cke-enter-mode': editable.enterMode
1129
+ } );
1130
+
1131
+ if ( editable.filter )
1132
+ editable.data( 'cke-filter', editable.filter.id );
1133
+
1134
+ editable.addClass( 'cke_widget_editable' );
1135
+ // This class may be left when d&ding widget which
1136
+ // had focused editable. Clean this class here, not in
1137
+ // cleanUpWidgetElement for performance and code size reasons.
1138
+ editable.removeClass( 'cke_widget_editable_focused' );
1139
+
1140
+ if ( definition.pathName )
1141
+ editable.data( 'cke-display-name', definition.pathName );
1142
+
1143
+ this.editor.focusManager.add( editable );
1144
+ editable.on( 'focus', onEditableFocus, this );
1145
+ CKEDITOR.env.ie && editable.on( 'blur', onEditableBlur, this );
1146
+
1147
+ // Finally, process editable's data. This data wasn't processed when loading
1148
+ // editor's data, becuase they need to be processed separately, with its own filters and settings.
1149
+ editable.setData( editable.getHtml() );
1150
+
1151
+ return true;
1152
+ }
1153
+
1154
+ return false;
1155
+ },
1156
+
1157
+ /**
1158
+ * Checks if a widget has already been initialized and has not been destroyed yet.
1159
+ *
1160
+ * See {@link #inited} for more details.
1161
+ *
1162
+ * @returns {Boolean}
1163
+ */
1164
+ isInited: function() {
1165
+ return !!( this.wrapper && this.inited );
1166
+ },
1167
+
1168
+ /**
1169
+ * Checks if a widget is ready and has not been destroyed yet.
1170
+ *
1171
+ * See {@link #property-ready} for more details.
1172
+ *
1173
+ * @returns {Boolean}
1174
+ */
1175
+ isReady: function() {
1176
+ return this.isInited() && this.ready;
1177
+ },
1178
+
1179
+ /**
1180
+ * Focuses a widget by selecting it.
1181
+ */
1182
+ focus: function() {
1183
+ var sel = this.editor.getSelection();
1184
+
1185
+ // Fake the selection before focusing editor, to avoid unpreventable viewports scrolling
1186
+ // on Webkit/Blink/IE which is done because there's no selection or selection was somewhere else than widget.
1187
+ if ( sel )
1188
+ sel.fake( this.wrapper );
1189
+
1190
+ // Always focus editor (not only when focusManger.hasFocus is false) (because of #10483).
1191
+ this.editor.focus();
1192
+ },
1193
+
1194
+ /**
1195
+ * Removes a class from the widget element. This method is used by
1196
+ * the {@link #removeStyle} method and should be overriden by widgets
1197
+ * which should handle classes differently (e.g. on other elements).
1198
+ *
1199
+ * **Note**: This method should not be used directly. Use the {@link #setData} method to
1200
+ * set the `classes` property. Read more in the {@link #setData} documentation.
1201
+ *
1202
+ * See also: {@link #hasClass}, {@link #addClass}.
1203
+ *
1204
+ * @since 4.4
1205
+ * @param {String} className The class to be removed.
1206
+ */
1207
+ removeClass: function( className ) {
1208
+ this.element.removeClass( className );
1209
+ },
1210
+
1211
+ /**
1212
+ * Removes the specified style from the widget. It is highly recommended to use the
1213
+ * {@link CKEDITOR.editor#removeStyle} or {@link CKEDITOR.style#remove} methods instead of
1214
+ * using this method directly, because unlike editor's and style's methods, this one
1215
+ * does not perform any checks.
1216
+ *
1217
+ * Read more about how applying/removing styles works in the {@link #applyStyle} method documentation.
1218
+ *
1219
+ * See also {@link #checkStyleActive}, {@link #applyStyle}, {@link #getClasses}.
1220
+ *
1221
+ * @since 4.4
1222
+ * @param {CKEDITOR.style} style The custom widget style to be removed.
1223
+ */
1224
+ removeStyle: function( style ) {
1225
+ applyRemoveStyle( this, style, 0 );
1226
+ },
1227
+
1228
+ /**
1229
+ * Sets widget value(s) in the {@link #property-data} object.
1230
+ * If the given value(s) modifies current ones, the {@link #event-data} event is fired.
1231
+ *
1232
+ * this.setData( 'align', 'left' );
1233
+ * this.data.align; // -> 'left'
1234
+ *
1235
+ * this.setData( { align: 'right', opened: false } );
1236
+ * this.data.align; // -> 'right'
1237
+ * this.data.opened; // -> false
1238
+ *
1239
+ * Set values are stored in {@link #element}'s attribute (`data-cke-widget-data`),
1240
+ * in a JSON string, therefore {@link #property-data} should contain
1241
+ * only serializable data.
1242
+ *
1243
+ * **Note:** A special data property, `classes`, exists. It contains an object with
1244
+ * classes which were returned by the {@link #getClasses} method during the widget initialization.
1245
+ * This property is then used by the {@link #applyStyle} and {@link #removeStyle} methods.
1246
+ * When it is changed (the reference to object must be changed!), the widget updates its classes by
1247
+ * using the {@link #addClass} and {@link #removeClass} methods.
1248
+ *
1249
+ * // Adding a new class.
1250
+ * var classes = CKEDITOR.tools.clone( widget.data.classes );
1251
+ * classes.newClass = 1;
1252
+ * widget.setData( 'classes', classes );
1253
+ *
1254
+ * // Removing a class.
1255
+ * var classes = CKEDITOR.tools.clone( widget.data.classes );
1256
+ * delete classes.newClass;
1257
+ * widget.setData( 'classes', classes );
1258
+ *
1259
+ * @param {String/Object} keyOrData
1260
+ * @param {Object} value
1261
+ * @chainable
1262
+ */
1263
+ setData: function( key, value ) {
1264
+ var data = this.data,
1265
+ modified = 0;
1266
+
1267
+ if ( typeof key == 'string' ) {
1268
+ if ( data[ key ] !== value ) {
1269
+ data[ key ] = value;
1270
+ modified = 1;
1271
+ }
1272
+ }
1273
+ else {
1274
+ var newData = key;
1275
+
1276
+ for ( key in newData ) {
1277
+ if ( data[ key ] !== newData[ key ] ) {
1278
+ modified = 1;
1279
+ data[ key ] = newData[ key ];
1280
+ }
1281
+ }
1282
+ }
1283
+
1284
+ // Block firing data event and overwriting data element before setupWidgetData is executed.
1285
+ if ( modified && this.dataReady ) {
1286
+ writeDataToElement( this );
1287
+ this.fire( 'data', data );
1288
+ }
1289
+
1290
+ return this;
1291
+ },
1292
+
1293
+ /**
1294
+ * Changes the widget's focus state. This method is executed automatically after
1295
+ * a widget has been focused by the {@link #method-focus} method or a selection was moved
1296
+ * out of the widget.
1297
+ *
1298
+ * @param {Boolean} selected Whether to select or deselect this widget.
1299
+ * @chainable
1300
+ */
1301
+ setFocused: function( focused ) {
1302
+ this.wrapper[ focused ? 'addClass' : 'removeClass' ]( 'cke_widget_focused' );
1303
+ this.fire( focused ? 'focus' : 'blur' );
1304
+ return this;
1305
+ },
1306
+
1307
+ /**
1308
+ * Changes the widget's select state. This method is executed automatically after
1309
+ * a widget has been selected by the {@link #method-focus} method or the selection
1310
+ * was moved out of widget.
1311
+ *
1312
+ * @param {Boolean} selected Whether to select or deselect this widget.
1313
+ * @chainable
1314
+ */
1315
+ setSelected: function( selected ) {
1316
+ this.wrapper[ selected ? 'addClass' : 'removeClass' ]( 'cke_widget_selected' );
1317
+ this.fire( selected ? 'select' : 'deselect' );
1318
+ return this;
1319
+ },
1320
+
1321
+ /**
1322
+ * Repositions drag handler according to the widget's element position. Should be called from events, like mouseover.
1323
+ */
1324
+ updateDragHandlerPosition: function() {
1325
+ var editor = this.editor,
1326
+ domElement = this.element.$,
1327
+ oldPos = this._.dragHandlerOffset,
1328
+ newPos = {
1329
+ x: domElement.offsetLeft,
1330
+ y: domElement.offsetTop - DRAG_HANDLER_SIZE
1331
+ };
1332
+
1333
+ if ( oldPos && newPos.x == oldPos.x && newPos.y == oldPos.y )
1334
+ return;
1335
+
1336
+ // We need to make sure that dirty state is not changed (#11487).
1337
+ var initialDirty = editor.checkDirty();
1338
+
1339
+ editor.fire( 'lockSnapshot' );
1340
+ this.dragHandlerContainer.setStyles( {
1341
+ top: newPos.y + 'px',
1342
+ left: newPos.x + 'px'
1343
+ } );
1344
+ editor.fire( 'unlockSnapshot' );
1345
+ !initialDirty && editor.resetDirty();
1346
+
1347
+ this._.dragHandlerOffset = newPos;
1348
+ }
1349
+ };
1350
+
1351
+ CKEDITOR.event.implementOn( Widget.prototype );
1352
+
1353
+ /**
1354
+ * An event fired when a widget is ready (fully initialized). This event is fired after:
1355
+ *
1356
+ * * {@link #init} is called,
1357
+ * * The first {@link #event-data} event is fired,
1358
+ * * A widget is attached to the document.
1359
+ *
1360
+ * Therefore, in case of widget creation with a command which opens a dialog window, this event
1361
+ * will be delayed after the dialog window is closed and the widget is finally inserted into the document.
1362
+ *
1363
+ * **Note**: If your widget does not use automatic dialog window binding (i.e. you open the dialog window manually)
1364
+ * or another situation in which the widget wrapper is not attached to document at the time when it is
1365
+ * initialized occurs, you need to take care of firing {@link #event-ready} yourself.
1366
+ *
1367
+ * See also {@link #property-ready} and {@link #property-inited} properties, and
1368
+ * {@link #isReady} and {@link #isInited} methods.
1369
+ *
1370
+ * @event ready
1371
+ */
1372
+
1373
+ /**
1374
+ * An event fired when a widget is about to be destroyed, but before it is
1375
+ * fully torn down.
1376
+ *
1377
+ * @event destroy
1378
+ */
1379
+
1380
+ /**
1381
+ * An event fired when a widget is focused.
1382
+ *
1383
+ * Widget can be focused by executing {@link #method-focus}.
1384
+ *
1385
+ * @event focus
1386
+ */
1387
+
1388
+ /**
1389
+ * An event fired when a widget is blurred.
1390
+ *
1391
+ * @event blur
1392
+ */
1393
+
1394
+ /**
1395
+ * An event fired when a widget is selected.
1396
+ *
1397
+ * @event select
1398
+ */
1399
+
1400
+ /**
1401
+ * An event fired when a widget is deselected.
1402
+ *
1403
+ * @event deselect
1404
+ */
1405
+
1406
+ /**
1407
+ * An event fired by the {@link #method-edit} method. It can be canceled
1408
+ * in order to stop the default action (opening a dialog window and/or
1409
+ * {@link CKEDITOR.plugins.widget.repository#finalizeCreation finalizing widget creation}).
1410
+ *
1411
+ * @event edit
1412
+ * @param data
1413
+ * @param {String} data.dialog Defaults to {@link CKEDITOR.plugins.widget.definition#dialog}
1414
+ * and can be changed or set by the listener.
1415
+ */
1416
+
1417
+ /**
1418
+ * An event fired when a dialog window for widget editing is opened.
1419
+ * This event can be cancelled in order to handle the editing dialog in a custom manner.
1420
+ *
1421
+ * @event dialog
1422
+ * @param {CKEDITOR.dialog} data The opened dialog window instance.
1423
+ */
1424
+
1425
+ /**
1426
+ * An event fired when a key is pressed on a focused widget.
1427
+ * This event is forwarded from the {@link CKEDITOR.editor#key} event and
1428
+ * has the ability to block editor keystrokes if it is cancelled.
1429
+ *
1430
+ * @event key
1431
+ * @param data
1432
+ * @param {Number} data.keyCode A number representing the key code (or combination).
1433
+ */
1434
+
1435
+ /**
1436
+ * An event fired when a widget is double clicked.
1437
+ *
1438
+ * @event doubleclick
1439
+ * @param data
1440
+ * @param {CKEDITOR.dom.element} data.element The double clicked element.
1441
+ */
1442
+
1443
+ /**
1444
+ * An event fired when the context menu is opened for a widget.
1445
+ *
1446
+ * @event contextMenu
1447
+ * @param data The object containing context menu options to be added
1448
+ * for this widget. See {@link CKEDITOR.plugins.contextMenu#addListener}.
1449
+ */
1450
+
1451
+ /**
1452
+ * An event fired when the widget data changed. See the {@link #setData} method and the {@link #property-data} property.
1453
+ *
1454
+ * @event data
1455
+ */
1456
+
1457
+
1458
+
1459
+ /**
1460
+ * The wrapper class for editable elements inside widgets.
1461
+ *
1462
+ * Do not use directly. Use {@link CKEDITOR.plugins.widget.definition#editables} or
1463
+ * {@link CKEDITOR.plugins.widget#initEditable}.
1464
+ *
1465
+ * @class CKEDITOR.plugins.widget.nestedEditable
1466
+ * @extends CKEDITOR.dom.element
1467
+ * @constructor
1468
+ * @param {CKEDITOR.editor} editor
1469
+ * @param {CKEDITOR.dom.element} element
1470
+ * @param config
1471
+ * @param {CKEDITOR.filter} [config.filter]
1472
+ */
1473
+ function NestedEditable( editor, element, config ) {
1474
+ // Call the base constructor.
1475
+ CKEDITOR.dom.element.call( this, element.$ );
1476
+ this.editor = editor;
1477
+ var filter = this.filter = config.filter;
1478
+
1479
+ // If blockless editable - always use BR mode.
1480
+ if ( !CKEDITOR.dtd[ this.getName() ].p )
1481
+ this.enterMode = this.shiftEnterMode = CKEDITOR.ENTER_BR;
1482
+ else {
1483
+ this.enterMode = filter ? filter.getAllowedEnterMode( editor.enterMode ) : editor.enterMode;
1484
+ this.shiftEnterMode = filter ? filter.getAllowedEnterMode( editor.shiftEnterMode, true ) : editor.shiftEnterMode;
1485
+ }
1486
+ }
1487
+
1488
+ NestedEditable.prototype = CKEDITOR.tools.extend( CKEDITOR.tools.prototypedCopy( CKEDITOR.dom.element.prototype ), {
1489
+ /**
1490
+ * Sets the editable data. The data will be passed through the {@link CKEDITOR.editor#dataProcessor}
1491
+ * and the {@link CKEDITOR.editor#filter}. This ensures that the data was filtered and prepared to be
1492
+ * edited like the {@link CKEDITOR.editor#method-setData editor data}.
1493
+ *
1494
+ * @param {String} data
1495
+ */
1496
+ setData: function( data ) {
1497
+ data = this.editor.dataProcessor.toHtml( data, {
1498
+ context: this.getName(),
1499
+ filter: this.filter,
1500
+ enterMode: this.enterMode
1501
+ } );
1502
+ this.setHtml( data );
1503
+ },
1504
+
1505
+ /**
1506
+ * Gets the editable data. Like {@link #setData}, this method will process and filter the data.
1507
+ *
1508
+ * @returns {String}
1509
+ */
1510
+ getData: function() {
1511
+ return this.editor.dataProcessor.toDataFormat( this.getHtml(), {
1512
+ context: this.getName(),
1513
+ filter: this.filter,
1514
+ enterMode: this.enterMode
1515
+ } );
1516
+ }
1517
+ } );
1518
+
1519
+ /**
1520
+ * The editor instance.
1521
+ *
1522
+ * @readonly
1523
+ * @property {CKEDITOR.editor} editor
1524
+ */
1525
+
1526
+ /**
1527
+ * The filter instance if allowed content rules were defined.
1528
+ *
1529
+ * @readonly
1530
+ * @property {CKEDITOR.filter} filter
1531
+ */
1532
+
1533
+ /**
1534
+ * The enter mode active in this editable.
1535
+ * It is determined from editable's name (whether it is a blockless editable),
1536
+ * its allowed content rules (if defined) and the default editor's mode.
1537
+ *
1538
+ * @readonly
1539
+ * @property {Number} enterMode
1540
+ */
1541
+
1542
+ /**
1543
+ * The shift enter move active in this editable.
1544
+ *
1545
+ * @readonly
1546
+ * @property {Number} shiftEnterMode
1547
+ */
1548
+
1549
+
1550
+ //
1551
+ // REPOSITORY helpers -----------------------------------------------------
1552
+ //
1553
+
1554
+ function addWidgetButtons( editor ) {
1555
+ var widgets = editor.widgets.registered,
1556
+ widget,
1557
+ widgetName,
1558
+ widgetButton;
1559
+
1560
+ for ( widgetName in widgets ) {
1561
+ widget = widgets[ widgetName ];
1562
+
1563
+ // Create button if defined.
1564
+ widgetButton = widget.button;
1565
+ if ( widgetButton && editor.ui.addButton ) {
1566
+ editor.ui.addButton( CKEDITOR.tools.capitalize( widget.name, true ), {
1567
+ label: widgetButton,
1568
+ command: widget.name,
1569
+ toolbar: 'insert,10'
1570
+ } );
1571
+ }
1572
+ }
1573
+ }
1574
+
1575
+ // Create a command creating and editing widget.
1576
+ //
1577
+ // @param editor
1578
+ // @param {CKEDITOR.plugins.widget.definition} widgetDef
1579
+ function addWidgetCommand( editor, widgetDef ) {
1580
+ editor.addCommand( widgetDef.name, {
1581
+ exec: function() {
1582
+ var focused = editor.widgets.focused;
1583
+ // If a widget of the same type is focused, start editing.
1584
+ if ( focused && focused.name == widgetDef.name )
1585
+ focused.edit();
1586
+ // Otherwise...
1587
+ // ... use insert method is was defined.
1588
+ else if ( widgetDef.insert )
1589
+ widgetDef.insert();
1590
+ // ... or create a brand-new widget from template.
1591
+ else if ( widgetDef.template ) {
1592
+ var defaults = typeof widgetDef.defaults == 'function' ? widgetDef.defaults() : widgetDef.defaults,
1593
+ element = CKEDITOR.dom.element.createFromHtml( widgetDef.template.output( defaults ) ),
1594
+ instance,
1595
+ wrapper = editor.widgets.wrapElement( element, widgetDef.name ),
1596
+ temp = new CKEDITOR.dom.documentFragment( wrapper.getDocument() );
1597
+
1598
+ // Append wrapper to a temporary document. This will unify the environment
1599
+ // in which #data listeners work when creating and editing widget.
1600
+ temp.append( wrapper );
1601
+ instance = editor.widgets.initOn( element, widgetDef );
1602
+
1603
+ // Instance could be destroyed during initialization.
1604
+ // In this case finalize creation if some new widget
1605
+ // was left in temporary document fragment.
1606
+ if ( !instance ) {
1607
+ finalizeCreation();
1608
+ return;
1609
+ }
1610
+
1611
+ // Listen on edit to finalize widget insertion.
1612
+ //
1613
+ // * If dialog was set, then insert widget after dialog was successfully saved or destroy this
1614
+ // temporary instance.
1615
+ // * If dialog wasn't set and edit wasn't canceled, insert widget.
1616
+ var editListener = instance.once( 'edit', function( evt ) {
1617
+ if ( evt.data.dialog ) {
1618
+ instance.once( 'dialog', function( evt ) {
1619
+ var dialog = evt.data,
1620
+ okListener,
1621
+ cancelListener;
1622
+
1623
+ // Finalize creation AFTER (20) new data was set.
1624
+ okListener = dialog.once( 'ok', finalizeCreation, null, null, 20 );
1625
+
1626
+ cancelListener = dialog.once( 'cancel', function() {
1627
+ editor.widgets.destroy( instance, true );
1628
+ } );
1629
+
1630
+ dialog.once( 'hide', function() {
1631
+ okListener.removeListener();
1632
+ cancelListener.removeListener();
1633
+ } );
1634
+ } );
1635
+ }
1636
+ // Dialog hasn't been set, so insert widget now.
1637
+ else
1638
+ finalizeCreation();
1639
+ }, null, null, 999 );
1640
+
1641
+ instance.edit();
1642
+
1643
+ // Remove listener in case someone canceled it before this
1644
+ // listener was executed.
1645
+ editListener.removeListener();
1646
+ }
1647
+
1648
+ function finalizeCreation() {
1649
+ editor.widgets.finalizeCreation( temp );
1650
+ }
1651
+ },
1652
+
1653
+ refresh: function( editor, path ) {
1654
+ // Disable widgets' commands inside nested editables -
1655
+ // check if blockLimit is a nested editable or a descendant of any.
1656
+ this.setState( getNestedEditable( editor.editable(), path.blockLimit ) ? CKEDITOR.TRISTATE_DISABLED : CKEDITOR.TRISTATE_OFF );
1657
+ },
1658
+ // A hack to force command refreshing on context change.
1659
+ context: 'div',
1660
+
1661
+ allowedContent: widgetDef.allowedContent,
1662
+ requiredContent: widgetDef.requiredContent,
1663
+ contentForms: widgetDef.contentForms,
1664
+ contentTransformations: widgetDef.contentTransformations
1665
+ } );
1666
+ }
1667
+
1668
+ function addWidgetProcessors( widgetsRepo, widgetDef ) {
1669
+ var upcast = widgetDef.upcast,
1670
+ upcasts;
1671
+
1672
+ if ( !upcast )
1673
+ return;
1674
+
1675
+ // Multiple upcasts defined in string.
1676
+ if ( typeof upcast == 'string' ) {
1677
+ upcasts = upcast.split( ',' );
1678
+ while ( upcasts.length )
1679
+ widgetsRepo._.upcasts.push( [ widgetDef.upcasts[ upcasts.pop() ], widgetDef.name ] );
1680
+ }
1681
+ // Single rule which is automatically activated.
1682
+ else
1683
+ widgetsRepo._.upcasts.push( [ upcast, widgetDef.name ] );
1684
+ }
1685
+
1686
+ function blurWidget( widgetsRepo, widget ) {
1687
+ widgetsRepo.focused = null;
1688
+
1689
+ if ( widget.isInited() ) {
1690
+ // Widget could be destroyed in the meantime - e.g. data could be set.
1691
+ widgetsRepo.fire( 'widgetBlurred', { widget: widget } );
1692
+ widget.setFocused( false );
1693
+ }
1694
+ }
1695
+
1696
+ function checkWidgets( evt ) {
1697
+ var options = evt.data;
1698
+
1699
+ if ( this.editor.mode != 'wysiwyg' )
1700
+ return;
1701
+
1702
+ var editable = this.editor.editable(),
1703
+ instances = this.instances,
1704
+ newInstances, i, count, wrapper;
1705
+
1706
+ if ( !editable )
1707
+ return;
1708
+
1709
+ // Remove widgets which have no corresponding elements in DOM.
1710
+ for ( i in instances ) {
1711
+ if ( !editable.contains( instances[ i ].wrapper ) )
1712
+ this.destroy( instances[ i ], true );
1713
+ }
1714
+
1715
+ // Init on all (new) if initOnlyNew option was passed.
1716
+ if ( options && options.initOnlyNew )
1717
+ newInstances = this.initOnAll();
1718
+ else {
1719
+ var wrappers = editable.find( '.cke_widget_wrapper' );
1720
+ newInstances = [];
1721
+
1722
+ // Create widgets on existing wrappers if they do not exists.
1723
+ for ( i = 0, count = wrappers.count(); i < count; i++ ) {
1724
+ wrapper = wrappers.getItem( i );
1725
+
1726
+ // Check if there's no instance for this widget and that
1727
+ // wrapper is not inside some temporary element like copybin (#11088).
1728
+ if ( !this.getByElement( wrapper, true ) && !findParent( wrapper, isDomTemp ) ) {
1729
+ // Add cke_widget_new class because otherwise
1730
+ // widget will not be created on such wrapper.
1731
+ wrapper.addClass( 'cke_widget_new' );
1732
+ newInstances.push( this.initOn( wrapper.getFirst( isDomWidgetElement ) ) );
1733
+ }
1734
+ }
1735
+ }
1736
+
1737
+ // If only single widget was initialized and focusInited was passed, focus it.
1738
+ if ( options && options.focusInited && newInstances.length == 1 )
1739
+ newInstances[ 0 ].focus();
1740
+ }
1741
+
1742
+ // Unwraps widget element and clean up element.
1743
+ //
1744
+ // This function is used to clean up pasted widgets.
1745
+ // It should have similar result to widget#destroy plus
1746
+ // some additional adjustments, specific for pasting.
1747
+ //
1748
+ // @param {CKEDITOR.htmlParser.element} el
1749
+ function cleanUpWidgetElement( el ) {
1750
+ var parent = el.parent;
1751
+ if ( parent.type == CKEDITOR.NODE_ELEMENT && parent.attributes[ 'data-cke-widget-wrapper' ] )
1752
+ parent.replaceWith( el );
1753
+ }
1754
+
1755
+ // Similar to cleanUpWidgetElement, but works on DOM and finds
1756
+ // widget elements by its own.
1757
+ //
1758
+ // Unlike cleanUpWidgetElement it will wrap element back.
1759
+ //
1760
+ // @param {CKEDITOR.dom.element} container
1761
+ function cleanUpAllWidgetElements( widgetsRepo, container ) {
1762
+ var wrappers = container.find( '.cke_widget_wrapper' ),
1763
+ wrapper, element,
1764
+ i = 0,
1765
+ l = wrappers.count();
1766
+
1767
+ for ( ; i < l; ++i ) {
1768
+ wrapper = wrappers.getItem( i );
1769
+ element = wrapper.getFirst( isDomWidgetElement );
1770
+ // If wrapper contains widget element - unwrap it and wrap again.
1771
+ if ( element.type == CKEDITOR.NODE_ELEMENT && element.data( 'widget' ) ) {
1772
+ element.replace( wrapper );
1773
+ widgetsRepo.wrapElement( element );
1774
+ }
1775
+ // Otherwise - something is wrong... clean this up.
1776
+ else
1777
+ wrapper.remove();
1778
+ }
1779
+ }
1780
+
1781
+ // Creates {@link CKEDITOR.filter} instance for given widget, editable and rules.
1782
+ //
1783
+ // Once filter for widget-editable pair is created it is cached, so the same instance
1784
+ // will be returned when method is executed again.
1785
+ //
1786
+ // @param {String} widgetName
1787
+ // @param {String} editableName
1788
+ // @param {CKEDITOR.plugins.widget.nestedEditableDefinition} editableDefinition The nested editable definition.
1789
+ // @returns {CKEDITOR.filter} Filter instance or `null` if rules are not defined.
1790
+ // @context CKEDITOR.plugins.widget.repository
1791
+ function createEditableFilter( widgetName, editableName, editableDefinition ) {
1792
+ if ( !editableDefinition.allowedContent )
1793
+ return null;
1794
+
1795
+ var editables = this._.filters[ widgetName ];
1796
+
1797
+ if ( !editables )
1798
+ this._.filters[ widgetName ] = editables = {};
1799
+
1800
+ var filter = editables[ editableName ];
1801
+
1802
+ if ( !filter )
1803
+ editables[ editableName ] = filter = new CKEDITOR.filter( editableDefinition.allowedContent );
1804
+
1805
+ return filter;
1806
+ }
1807
+
1808
+ // Creates an iterator function which when executed on all
1809
+ // elements in DOM tree will gather elements that should be wrapped
1810
+ // and initialized as widgets.
1811
+ function createUpcastIterator( widgetsRepo ) {
1812
+ var toBeWrapped = [],
1813
+ upcasts = widgetsRepo._.upcasts,
1814
+ upcastCallbacks = widgetsRepo._.upcastCallbacks;
1815
+
1816
+ return {
1817
+ toBeWrapped: toBeWrapped,
1818
+
1819
+ iterator: function( element ) {
1820
+ var upcast, upcasted,
1821
+ data,
1822
+ i,
1823
+ upcastsLength,
1824
+ upcastCallbacksLength;
1825
+
1826
+ // Wrapper found - find widget element, add it to be
1827
+ // cleaned up (unwrapped) and wrapped and stop iterating in this branch.
1828
+ if ( 'data-cke-widget-wrapper' in element.attributes ) {
1829
+ element = element.getFirst( isParserWidgetElement );
1830
+
1831
+ if ( element )
1832
+ toBeWrapped.push( [ element ] );
1833
+
1834
+ // Do not iterate over descendants.
1835
+ return false;
1836
+ }
1837
+ // Widget element found - add it to be cleaned up (just in case)
1838
+ // and wrapped and stop iterating in this branch.
1839
+ else if ( 'data-widget' in element.attributes ) {
1840
+ toBeWrapped.push( [ element ] );
1841
+
1842
+ // Do not iterate over descendants.
1843
+ return false;
1844
+ }
1845
+ else if ( ( upcastsLength = upcasts.length ) ) {
1846
+ // Ignore elements with data-cke-widget-upcasted to avoid multiple upcasts (#11533).
1847
+ // Do not iterate over descendants.
1848
+ if ( element.attributes[ 'data-cke-widget-upcasted' ] )
1849
+ return false;
1850
+
1851
+ // Check element with upcast callbacks first.
1852
+ // If any of them return false abort upcasting.
1853
+ for ( i = 0, upcastCallbacksLength = upcastCallbacks.length; i < upcastCallbacksLength; ++i ) {
1854
+ if ( upcastCallbacks[ i ]( element ) === false )
1855
+ return;
1856
+ // Return nothing in order to continue iterating over ascendants.
1857
+ // See http://dev.ckeditor.com/ticket/11186#comment:6
1858
+ }
1859
+
1860
+ for ( i = 0; i < upcastsLength; ++i ) {
1861
+ upcast = upcasts[ i ];
1862
+ data = {};
1863
+
1864
+ if ( ( upcasted = upcast[ 0 ]( element, data ) ) ) {
1865
+ // If upcast function returned element, upcast this one.
1866
+ // It can be e.g. a new element wrapping the original one.
1867
+ if ( upcasted instanceof CKEDITOR.htmlParser.element )
1868
+ element = upcasted;
1869
+
1870
+ // Set initial data attr with data from upcast method.
1871
+ element.attributes[ 'data-cke-widget-data' ] = encodeURIComponent( JSON.stringify( data ) );
1872
+ element.attributes[ 'data-cke-widget-upcasted' ] = 1;
1873
+
1874
+ toBeWrapped.push( [ element, upcast[ 1 ] ] );
1875
+
1876
+ // Do not iterate over descendants.
1877
+ return false;
1878
+ }
1879
+ }
1880
+ }
1881
+ }
1882
+ };
1883
+ }
1884
+
1885
+ // Finds a first parent that matches query.
1886
+ //
1887
+ // @param {CKEDITOR.dom.element} element
1888
+ // @param {Function} query
1889
+ function findParent( element, query ) {
1890
+ var parent = element;
1891
+
1892
+ while ( ( parent = parent.getParent() ) ) {
1893
+ if ( query( parent ) )
1894
+ return true;
1895
+ }
1896
+ return false;
1897
+ }
1898
+
1899
+ // Gets nested editable if node is its descendant or the editable itself.
1900
+ //
1901
+ // @param {CKEDITOR.dom.element} guard Stop ancestor search on this node (usually editor's editable).
1902
+ // @param {CKEDITOR.dom.node} node Start search from this node.
1903
+ // @returns {CKEDITOR.dom.element} Element or null.
1904
+ function getNestedEditable( guard, node ) {
1905
+ if ( !node || node.equals( guard ) )
1906
+ return null;
1907
+
1908
+ if ( isDomNestedEditable( node ) )
1909
+ return node;
1910
+
1911
+ return getNestedEditable( guard, node.getParent() );
1912
+ }
1913
+
1914
+ function getWrapperAttributes( inlineWidget ) {
1915
+ return {
1916
+ // tabindex="-1" means that it can receive focus by code.
1917
+ tabindex: -1,
1918
+ contenteditable: 'false',
1919
+ 'data-cke-widget-wrapper': 1,
1920
+ 'data-cke-filter': 'off',
1921
+ // Class cke_widget_new marks widgets which haven't been initialized yet.
1922
+ 'class': 'cke_widget_wrapper cke_widget_new cke_widget_' +
1923
+ ( inlineWidget ? 'inline' : 'block' )
1924
+ };
1925
+ }
1926
+
1927
+ // Inserts element at given index.
1928
+ // It will check DTD and split ancestor elements up to the first
1929
+ // that can contain this element.
1930
+ //
1931
+ // @param {CKEDITOR.htmlParser.element} parent
1932
+ // @param {Number} index
1933
+ // @param {CKEDITOR.htmlParser.element} element
1934
+ function insertElement( parent, index, element ) {
1935
+ // Do not split doc fragment...
1936
+ if ( parent.type == CKEDITOR.NODE_ELEMENT ) {
1937
+ var parentAllows = CKEDITOR.dtd[ parent.name ];
1938
+ // Parent element is known (included in DTD) and cannot contain
1939
+ // this element.
1940
+ if ( parentAllows && !parentAllows[ element.name ] ) {
1941
+ var parent2 = parent.split( index ),
1942
+ parentParent = parent.parent;
1943
+
1944
+ // Element will now be inserted at right parent's index.
1945
+ index = parent2.getIndex();
1946
+
1947
+ // If left part of split is empty - remove it.
1948
+ if ( !parent.children.length ) {
1949
+ index -= 1;
1950
+ parent.remove();
1951
+ }
1952
+
1953
+ // If right part of split is empty - remove it.
1954
+ if ( !parent2.children.length )
1955
+ parent2.remove();
1956
+
1957
+ // Try inserting as grandpas' children.
1958
+ return insertElement( parentParent, index, element );
1959
+ }
1960
+ }
1961
+
1962
+ // Finally we can add this element.
1963
+ parent.add( element, index );
1964
+ }
1965
+
1966
+ // @param {CKEDITOR.htmlParser.element}
1967
+ function isParserWidgetElement( element ) {
1968
+ return element.type == CKEDITOR.NODE_ELEMENT && !!element.attributes[ 'data-widget' ];
1969
+ }
1970
+
1971
+ // @param {CKEDITOR.dom.element}
1972
+ function isDomWidgetElement( element ) {
1973
+ return element.type == CKEDITOR.NODE_ELEMENT && element.hasAttribute( 'data-widget' );
1974
+ }
1975
+
1976
+ // Whether for this definition and element widget should be created in inline or block mode.
1977
+ function isWidgetInline( widgetDef, elementName ) {
1978
+ return typeof widgetDef.inline == 'boolean' ? widgetDef.inline : !!CKEDITOR.dtd.$inline[ elementName ];
1979
+ }
1980
+
1981
+ // @param {CKEDITOR.htmlParser.element}
1982
+ function isParserWidgetWrapper( element ) {
1983
+ return element.type == CKEDITOR.NODE_ELEMENT && element.attributes[ 'data-cke-widget-wrapper' ];
1984
+ }
1985
+
1986
+ // @param {CKEDITOR.dom.element}
1987
+ function isDomWidgetWrapper( element ) {
1988
+ return element.type == CKEDITOR.NODE_ELEMENT && element.hasAttribute( 'data-cke-widget-wrapper' );
1989
+ }
1990
+
1991
+ // @param {CKEDITOR.dom.element}
1992
+ function isDomNestedEditable( node ) {
1993
+ return node.type == CKEDITOR.NODE_ELEMENT && node.hasAttribute( 'data-cke-widget-editable' );
1994
+ }
1995
+
1996
+ // @param {CKEDITOR.dom.element}
1997
+ function isDomTemp( element ) {
1998
+ return element.hasAttribute( 'data-cke-temp' );
1999
+ }
2000
+
2001
+ // @param {CKEDITOR.dom.element}
2002
+ function isDomDragHandler( element ) {
2003
+ return element.type == CKEDITOR.NODE_ELEMENT && element.hasAttribute( 'data-cke-widget-drag-handler' );
2004
+ }
2005
+
2006
+ function finalizeNativeDrop( editor, sourceWidget, range ) {
2007
+ // Save the snapshot with the state before moving widget.
2008
+ // Focus widget, so when we'll undo the DnD, widget will be focused.
2009
+ sourceWidget.focus();
2010
+ editor.fire( 'saveSnapshot' );
2011
+
2012
+ // Lock snapshot to group all steps of moving widget from the original place to the new one.
2013
+ editor.fire( 'lockSnapshot', { dontUpdate: true } );
2014
+
2015
+ range.select();
2016
+
2017
+ var widgetHtml = sourceWidget.wrapper.getOuterHtml();
2018
+ sourceWidget.wrapper.remove();
2019
+ editor.widgets.destroy( sourceWidget, true );
2020
+ editor.execCommand( 'paste', widgetHtml );
2021
+
2022
+ editor.fire( 'unlockSnapshot' );
2023
+ }
2024
+
2025
+ function getRangeAtDropPosition( editor, dropEvt ) {
2026
+ var $evt = dropEvt.data.$,
2027
+ $range,
2028
+ range = editor.createRange();
2029
+
2030
+ // Make testing possible.
2031
+ if ( dropEvt.data.testRange )
2032
+ return dropEvt.data.testRange;
2033
+
2034
+ // Webkits.
2035
+ if ( document.caretRangeFromPoint ) {
2036
+ $range = editor.document.$.caretRangeFromPoint( $evt.clientX, $evt.clientY );
2037
+ range.setStart( CKEDITOR.dom.node( $range.startContainer ), $range.startOffset );
2038
+ range.collapse( true );
2039
+ }
2040
+ // FF.
2041
+ else if ( $evt.rangeParent ) {
2042
+ range.setStart( CKEDITOR.dom.node( $evt.rangeParent ), $evt.rangeOffset );
2043
+ range.collapse( true );
2044
+ }
2045
+ // IEs.
2046
+ else if ( document.body.createTextRange ) {
2047
+ $range = editor.document.getBody().$.createTextRange();
2048
+ $range.moveToPoint( $evt.clientX, $evt.clientY );
2049
+ var id = 'cke-temp-' + ( new Date() ).getTime();
2050
+ $range.pasteHTML( '<span id="' + id + '">\u200b</span>' );
2051
+
2052
+ var span = editor.document.getById( id );
2053
+ range.moveToPosition( span, CKEDITOR.POSITION_BEFORE_START );
2054
+ span.remove();
2055
+ }
2056
+ else
2057
+ return null;
2058
+
2059
+ return range;
2060
+ }
2061
+
2062
+ function onEditableKey( widget, keyCode ) {
2063
+ var focusedEditable = widget.focusedEditable,
2064
+ range;
2065
+
2066
+ // CTRL+A.
2067
+ if ( keyCode == CKEDITOR.CTRL + 65 ) {
2068
+ var bogus = focusedEditable.getBogus();
2069
+
2070
+ range = widget.editor.createRange();
2071
+ range.selectNodeContents( focusedEditable );
2072
+ // Exclude bogus if exists.
2073
+ if ( bogus )
2074
+ range.setEndAt( bogus, CKEDITOR.POSITION_BEFORE_START );
2075
+
2076
+ range.select();
2077
+ // Cancel event - block default.
2078
+ return false;
2079
+ }
2080
+ // DEL or BACKSPACE.
2081
+ else if ( keyCode == 8 || keyCode == 46 ) {
2082
+ var ranges = widget.editor.getSelection().getRanges();
2083
+
2084
+ range = ranges[ 0 ];
2085
+
2086
+ // Block del or backspace if at editable's boundary.
2087
+ return !( ranges.length == 1 && range.collapsed &&
2088
+ range.checkBoundaryOfElement( focusedEditable, CKEDITOR[ keyCode == 8 ? 'START' : 'END' ] ) );
2089
+ }
2090
+ }
2091
+
2092
+ function setFocusedEditable( widgetsRepo, widget, editableElement, offline ) {
2093
+ var editor = widgetsRepo.editor;
2094
+
2095
+ editor.fire( 'lockSnapshot' );
2096
+
2097
+ if ( editableElement ) {
2098
+ var editableName = editableElement.data( 'cke-widget-editable' ),
2099
+ editableInstance = widget.editables[ editableName ];
2100
+
2101
+ widgetsRepo.widgetHoldingFocusedEditable = widget;
2102
+ widget.focusedEditable = editableInstance;
2103
+ editableElement.addClass( 'cke_widget_editable_focused' );
2104
+
2105
+ if ( editableInstance.filter )
2106
+ editor.setActiveFilter( editableInstance.filter );
2107
+ editor.setActiveEnterMode( editableInstance.enterMode, editableInstance.shiftEnterMode );
2108
+ } else {
2109
+ if ( !offline )
2110
+ widget.focusedEditable.removeClass( 'cke_widget_editable_focused' );
2111
+
2112
+ widget.focusedEditable = null;
2113
+ widgetsRepo.widgetHoldingFocusedEditable = null;
2114
+ editor.setActiveFilter( null );
2115
+ editor.setActiveEnterMode( null, null );
2116
+ }
2117
+
2118
+ editor.fire( 'unlockSnapshot' );
2119
+ }
2120
+
2121
+ function setupContextMenu( editor ) {
2122
+ if ( !editor.contextMenu )
2123
+ return;
2124
+
2125
+ editor.contextMenu.addListener( function( element ) {
2126
+ var widget = editor.widgets.getByElement( element, true );
2127
+
2128
+ if ( widget )
2129
+ return widget.fire( 'contextMenu', {} );
2130
+ } );
2131
+ }
2132
+
2133
+ // And now we've got two problems - original problem and RegExp.
2134
+ // Some softeners:
2135
+ // * FF tends to copy all blocks up to the copybin container.
2136
+ // * IE tends to copy only the copybin, without its container.
2137
+ // * We use spans on IE and blockless editors, but divs in other cases.
2138
+ var pasteReplaceRegex = new RegExp(
2139
+ '^' +
2140
+ '(?:<(?:div|span)(?: data-cke-temp="1")?(?: id="cke_copybin")?(?: data-cke-temp="1")?>)?' +
2141
+ '(?:<(?:div|span)(?: style="[^"]+")?>)?' +
2142
+ '<span [^>]*data-cke-copybin-start="1"[^>]*>.?</span>([\\s\\S]+)<span [^>]*data-cke-copybin-end="1"[^>]*>.?</span>' +
2143
+ '(?:</(?:div|span)>)?' +
2144
+ '(?:</(?:div|span)>)?' +
2145
+ '$'
2146
+ );
2147
+
2148
+ function pasteReplaceFn( match, wrapperHtml ) {
2149
+ // Avoid polluting pasted data with any whitspaces,
2150
+ // what's going to break check whether only one widget was pasted.
2151
+ return CKEDITOR.tools.trim( wrapperHtml );
2152
+ }
2153
+
2154
+ function setupDragAndDrop( widgetsRepo ) {
2155
+ var editor = widgetsRepo.editor,
2156
+ lineutils = CKEDITOR.plugins.lineutils;
2157
+
2158
+ editor.on( 'contentDom', function() {
2159
+ var editable = editor.editable(),
2160
+ // #11123 Firefox needs to listen on document, because otherwise event won't be fired.
2161
+ // #11086 IE8 cannot listen on document.
2162
+ dropTarget = ( CKEDITOR.env.ie && CKEDITOR.env.version < 9 ) || editable.isInline() ? editable : editor.document;
2163
+
2164
+ editable.attachListener( dropTarget, 'drop', function( evt ) {
2165
+ var dataStr = evt.data.$.dataTransfer.getData( 'text' ),
2166
+ dataObj,
2167
+ sourceWidget,
2168
+ range;
2169
+
2170
+ if ( !dataStr )
2171
+ return;
2172
+
2173
+ try {
2174
+ dataObj = JSON.parse( dataStr );
2175
+ } catch ( e ) {
2176
+ // Do nothing - data couldn't be parsed so it's not a CKEditor's data.
2177
+ return;
2178
+ }
2179
+
2180
+ if ( dataObj.type != 'cke-widget' )
2181
+ return;
2182
+
2183
+ evt.data.preventDefault();
2184
+
2185
+ // Something went wrong... maybe someone is dragging widgets between editors/windows/tabs/browsers/frames.
2186
+ if ( dataObj.editor != editor.name || !( sourceWidget = widgetsRepo.instances[ dataObj.id ] ) )
2187
+ return;
2188
+
2189
+ // Try to determine a DOM position at which drop happened. If none of methods
2190
+ // which we support succeeded abort.
2191
+ range = getRangeAtDropPosition( editor, evt );
2192
+ if ( !range )
2193
+ return;
2194
+
2195
+ // #11132 Hack to prevent cursor loss on Firefox. Without timeout widget is
2196
+ // correctly pasted but then cursor is invisible (although it works) and can be restored
2197
+ // only by blurring editable.
2198
+ if ( CKEDITOR.env.gecko )
2199
+ setTimeout( finalizeNativeDrop, 0, editor, sourceWidget, range );
2200
+ else
2201
+ finalizeNativeDrop( editor, sourceWidget, range );
2202
+ } );
2203
+
2204
+ // Register Lineutils's utilities as properties of repo.
2205
+ CKEDITOR.tools.extend( widgetsRepo, {
2206
+ finder: new lineutils.finder( editor, {
2207
+ lookups: {
2208
+ // Element is block but not list item and not in nested editable.
2209
+ 'default': function( el ) {
2210
+ if ( el.is( CKEDITOR.dtd.$listItem ) )
2211
+ return;
2212
+
2213
+ if ( !el.is( CKEDITOR.dtd.$block ) )
2214
+ return;
2215
+
2216
+ while ( el ) {
2217
+ if ( isDomNestedEditable( el ) )
2218
+ return;
2219
+
2220
+ el = el.getParent();
2221
+ }
2222
+
2223
+ return CKEDITOR.LINEUTILS_BEFORE | CKEDITOR.LINEUTILS_AFTER;
2224
+ }
2225
+ }
2226
+ } ),
2227
+ locator: new lineutils.locator( editor ),
2228
+ liner: new lineutils.liner( editor, {
2229
+ lineStyle: {
2230
+ cursor: 'move !important',
2231
+ 'border-top-color': '#666'
2232
+ },
2233
+ tipLeftStyle: {
2234
+ 'border-left-color': '#666'
2235
+ },
2236
+ tipRightStyle: {
2237
+ 'border-right-color': '#666'
2238
+ }
2239
+ } )
2240
+ }, true );
2241
+ } );
2242
+ }
2243
+
2244
+ // Setup mouse observer which will trigger:
2245
+ // * widget focus on widget click,
2246
+ // * widget#doubleclick forwarded from editor#doubleclick.
2247
+ function setupMouseObserver( widgetsRepo ) {
2248
+ var editor = widgetsRepo.editor;
2249
+
2250
+ editor.on( 'contentDom', function() {
2251
+ var editable = editor.editable(),
2252
+ evtRoot = editable.isInline() ? editable : editor.document,
2253
+ widget,
2254
+ mouseDownOnDragHandler;
2255
+
2256
+ editable.attachListener( evtRoot, 'mousedown', function( evt ) {
2257
+ var target = evt.data.getTarget();
2258
+
2259
+ // #10887 Clicking scrollbar in IE8 will invoke event with empty target object.
2260
+ if ( !target.type )
2261
+ return false;
2262
+
2263
+ widget = widgetsRepo.getByElement( target );
2264
+ mouseDownOnDragHandler = 0; // Reset.
2265
+
2266
+ // Widget was clicked, but not editable nested in it.
2267
+ if ( widget ) {
2268
+ // Ignore mousedown on drag and drop handler if the widget is inline.
2269
+ // Block widgets are handled by Lineutils.
2270
+ if ( widget.inline && target.type == CKEDITOR.NODE_ELEMENT && target.hasAttribute( 'data-cke-widget-drag-handler' ) ) {
2271
+ mouseDownOnDragHandler = 1;
2272
+ return;
2273
+ }
2274
+
2275
+ if ( !getNestedEditable( widget.wrapper, target ) ) {
2276
+ evt.data.preventDefault();
2277
+ if ( !CKEDITOR.env.ie )
2278
+ widget.focus();
2279
+ }
2280
+ // Reset widget so mouseup listener is not confused.
2281
+ else
2282
+ widget = null;
2283
+ }
2284
+ } );
2285
+
2286
+ // Focus widget on mouseup if mousedown was fired on drag handler.
2287
+ // Note: mouseup won't be fired at all if widget was dragged and dropped, so
2288
+ // this code will be executed only when drag handler was clicked.
2289
+ editable.attachListener( evtRoot, 'mouseup', function() {
2290
+ if ( widget && mouseDownOnDragHandler ) {
2291
+ mouseDownOnDragHandler = 0;
2292
+ widget.focus();
2293
+ }
2294
+ } );
2295
+
2296
+ // On IE it is not enough to block mousedown. If widget wrapper (element with
2297
+ // contenteditable=false attribute) is clicked directly (it is a target),
2298
+ // then after mouseup/click IE will select that element.
2299
+ // It is not possible to prevent that default action,
2300
+ // so we force fake selection after everything happened.
2301
+ if ( CKEDITOR.env.ie ) {
2302
+ editable.attachListener( evtRoot, 'mouseup', function( evt ) {
2303
+ if ( widget ) {
2304
+ setTimeout( function() {
2305
+ widget.focus();
2306
+ widget = null;
2307
+ } );
2308
+ }
2309
+ } );
2310
+ }
2311
+ } );
2312
+
2313
+ editor.on( 'doubleclick', function( evt ) {
2314
+ var widget = widgetsRepo.getByElement( evt.data.element );
2315
+
2316
+ // Not in widget or in nested editable.
2317
+ if ( !widget || getNestedEditable( widget.wrapper, evt.data.element ) )
2318
+ return;
2319
+
2320
+ return widget.fire( 'doubleclick', { element: evt.data.element } );
2321
+ }, null, null, 1 );
2322
+ }
2323
+
2324
+ // Setup editor#key observer which will forward it
2325
+ // to focused widget.
2326
+ function setupKeyboardObserver( widgetsRepo ) {
2327
+ var editor = widgetsRepo.editor;
2328
+
2329
+ editor.on( 'key', function( evt ) {
2330
+ var focused = widgetsRepo.focused,
2331
+ widgetHoldingFocusedEditable = widgetsRepo.widgetHoldingFocusedEditable,
2332
+ ret;
2333
+
2334
+ if ( focused )
2335
+ ret = focused.fire( 'key', { keyCode: evt.data.keyCode } );
2336
+ else if ( widgetHoldingFocusedEditable )
2337
+ ret = onEditableKey( widgetHoldingFocusedEditable, evt.data.keyCode );
2338
+
2339
+ return ret;
2340
+ }, null, null, 1 );
2341
+ }
2342
+
2343
+ // Setup copybin on native copy and cut events in order to handle copy and cut commands
2344
+ // if user accepted security alert on IEs.
2345
+ // Note: when copying or cutting using keystroke, copySingleWidget will be first executed
2346
+ // by the keydown listener. Conflict between two calls will be resolved by copy_bin existence check.
2347
+ function setupNativeCutAndCopy( widgetsRepo ) {
2348
+ var editor = widgetsRepo.editor;
2349
+
2350
+ editor.on( 'contentDom', function() {
2351
+ var editable = editor.editable();
2352
+
2353
+ editable.attachListener( editable, 'copy', eventListener );
2354
+ editable.attachListener( editable, 'cut', eventListener );
2355
+ } );
2356
+
2357
+ function eventListener( evt ) {
2358
+ if ( widgetsRepo.focused )
2359
+ copySingleWidget( widgetsRepo.focused, evt.name == 'cut' );
2360
+ }
2361
+ }
2362
+
2363
+ // Setup selection observer which will trigger:
2364
+ // * widget select & focus on selection change,
2365
+ // * nested editable focus (related properites and classes) on selection change,
2366
+ // * deselecting and blurring all widgets on data,
2367
+ // * blurring widget on editor blur.
2368
+ function setupSelectionObserver( widgetsRepo ) {
2369
+ var editor = widgetsRepo.editor;
2370
+
2371
+ editor.on( 'selectionCheck', function() {
2372
+ widgetsRepo.fire( 'checkSelection' );
2373
+ } );
2374
+
2375
+ widgetsRepo.on( 'checkSelection', widgetsRepo.checkSelection, widgetsRepo );
2376
+
2377
+ editor.on( 'selectionChange', function( evt ) {
2378
+ var nestedEditable = getNestedEditable( editor.editable(), evt.data.selection.getStartElement() ),
2379
+ newWidget = nestedEditable && widgetsRepo.getByElement( nestedEditable ),
2380
+ oldWidget = widgetsRepo.widgetHoldingFocusedEditable;
2381
+
2382
+ if ( oldWidget ) {
2383
+ if ( oldWidget !== newWidget || !oldWidget.focusedEditable.equals( nestedEditable ) ) {
2384
+ setFocusedEditable( widgetsRepo, oldWidget, null );
2385
+
2386
+ if ( newWidget && nestedEditable )
2387
+ setFocusedEditable( widgetsRepo, newWidget, nestedEditable );
2388
+ }
2389
+ }
2390
+ // It may happen that there's no widget even if editable was found -
2391
+ // e.g. if selection was automatically set in editable although widget wasn't initialized yet.
2392
+ else if ( newWidget && nestedEditable )
2393
+ setFocusedEditable( widgetsRepo, newWidget, nestedEditable );
2394
+ } );
2395
+
2396
+ // Invalidate old widgets early - immediately on dataReady.
2397
+ editor.on( 'dataReady', function( evt ) {
2398
+ // Deselect and blur all widgets.
2399
+ stateUpdater( widgetsRepo ).commit();
2400
+ } );
2401
+
2402
+ editor.on( 'blur', function() {
2403
+ var widget;
2404
+
2405
+ if ( ( widget = widgetsRepo.focused ) )
2406
+ blurWidget( widgetsRepo, widget );
2407
+
2408
+ if ( ( widget = widgetsRepo.widgetHoldingFocusedEditable ) )
2409
+ setFocusedEditable( widgetsRepo, widget, null );
2410
+ } );
2411
+ }
2412
+
2413
+ // Set up actions like:
2414
+ // * processing in toHtml/toDataFormat,
2415
+ // * pasting handling,
2416
+ // * insertion handling,
2417
+ // * editable reload handling (setData, mode switch, undo/redo),
2418
+ // * DOM invalidation handling,
2419
+ // * widgets checks.
2420
+ function setupWidgetsLifecycle( widgetsRepo ) {
2421
+ setupWidgetsLifecycleStart( widgetsRepo );
2422
+ setupWidgetsLifecycleEnd( widgetsRepo );
2423
+
2424
+ widgetsRepo.on( 'checkWidgets', checkWidgets );
2425
+ widgetsRepo.editor.on( 'contentDomInvalidated', widgetsRepo.checkWidgets, widgetsRepo );
2426
+ }
2427
+
2428
+ function setupWidgetsLifecycleEnd( widgetsRepo ) {
2429
+ var editor = widgetsRepo.editor,
2430
+ downcastingSessions = {},
2431
+ nestedEditableScope = false;
2432
+
2433
+ // Listen before htmlDP#htmlFilter is applied to cache all widgets, because we'll
2434
+ // loose data-cke-* attributes.
2435
+ editor.on( 'toDataFormat', function( evt ) {
2436
+ // To avoid conflicts between htmlDP#toDF calls done at the same time
2437
+ // (e.g. nestedEditable#getData called during downcasting some widget)
2438
+ // mark every toDataFormat event chain with the downcasting session id.
2439
+ var id = CKEDITOR.tools.getNextNumber(),
2440
+ toBeDowncasted = [];
2441
+ evt.data.downcastingSessionId = id;
2442
+ downcastingSessions[ id ] = toBeDowncasted;
2443
+
2444
+ evt.data.dataValue.forEach( function( element ) {
2445
+ var attrs = element.attributes,
2446
+ widget, widgetElement;
2447
+
2448
+ // Wrapper.
2449
+ // Perform first part of downcasting (cleanup) and cache widgets,
2450
+ // because after applying DP's filter all data-cke-* attributes will be gone.
2451
+ if ( 'data-cke-widget-id' in attrs ) {
2452
+ widget = widgetsRepo.instances[ attrs[ 'data-cke-widget-id' ] ];
2453
+ if ( widget ) {
2454
+ widgetElement = element.getFirst( isParserWidgetElement );
2455
+ toBeDowncasted.push( {
2456
+ wrapper: element,
2457
+ element: widgetElement,
2458
+ widget: widget,
2459
+ editables: {}
2460
+ } );
2461
+
2462
+ // If widget did not have data-cke-widget attribute before upcasting remove it.
2463
+ if ( widgetElement.attributes[ 'data-cke-widget-keep-attr' ] != '1' )
2464
+ delete widgetElement.attributes[ 'data-widget' ];
2465
+ }
2466
+ }
2467
+ // Nested editable.
2468
+ else if ( 'data-cke-widget-editable' in attrs ) {
2469
+ // Save the reference to this nested editable in the closest widget to be downcasted.
2470
+ // Nested editables are downcasted in the successive toDataFormat to create an opportunity
2471
+ // for dataFilter's "excludeNestedEditable" option to do its job (that option relies on
2472
+ // contenteditable="true" attribute) (#11372).
2473
+ toBeDowncasted[ toBeDowncasted.length - 1 ].editables[ attrs[ 'data-cke-widget-editable' ] ] = element;
2474
+
2475
+ // Don't check children - there won't be next wrapper or nested editable which we
2476
+ // should process in this session.
2477
+ return false;
2478
+ }
2479
+ }, CKEDITOR.NODE_ELEMENT, true );
2480
+ }, null, null, 8 );
2481
+
2482
+ // Listen after dataProcessor.htmlFilter and ACF were applied
2483
+ // so wrappers securing widgets' contents are removed after all filtering was done.
2484
+ editor.on( 'toDataFormat', function( evt ) {
2485
+ // Ignore some unmarked sessions.
2486
+ if ( !evt.data.downcastingSessionId )
2487
+ return;
2488
+
2489
+ var toBeDowncasted = downcastingSessions[ evt.data.downcastingSessionId ],
2490
+ toBe, widget, widgetElement, retElement, editableElement, e;
2491
+
2492
+ while ( ( toBe = toBeDowncasted.shift() ) ) {
2493
+ widget = toBe.widget;
2494
+ widgetElement = toBe.element;
2495
+ retElement = widget._.downcastFn && widget._.downcastFn.call( widget, widgetElement );
2496
+
2497
+ // Replace nested editables' content with their output data.
2498
+ for ( e in toBe.editables ) {
2499
+ editableElement = toBe.editables[ e ];
2500
+
2501
+ delete editableElement.attributes[ 'contenteditable' ];
2502
+ editableElement.setHtml( widget.editables[ e ].getData() );
2503
+ }
2504
+
2505
+ // Returned element always defaults to widgetElement.
2506
+ if ( !retElement )
2507
+ retElement = widgetElement;
2508
+
2509
+ toBe.wrapper.replaceWith( retElement );
2510
+ }
2511
+ }, null, null, 13 );
2512
+
2513
+
2514
+ editor.on( 'contentDomUnload', function() {
2515
+ widgetsRepo.destroyAll( true );
2516
+ } );
2517
+ }
2518
+
2519
+ function setupWidgetsLifecycleStart( widgetsRepo ) {
2520
+ var editor = widgetsRepo.editor,
2521
+ processedWidgetOnly,
2522
+ snapshotLoaded;
2523
+
2524
+ // Listen after ACF (so data are filtered),
2525
+ // but before dataProcessor.dataFilter was applied (so we can secure widgets' internals).
2526
+ editor.on( 'toHtml', function( evt ) {
2527
+ var upcastIterator = createUpcastIterator( widgetsRepo ),
2528
+ toBeWrapped;
2529
+
2530
+ evt.data.dataValue.forEach( upcastIterator.iterator, CKEDITOR.NODE_ELEMENT, true );
2531
+
2532
+ // Clean up and wrap all queued elements.
2533
+ while ( ( toBeWrapped = upcastIterator.toBeWrapped.pop() ) ) {
2534
+ cleanUpWidgetElement( toBeWrapped[ 0 ] );
2535
+ widgetsRepo.wrapElement( toBeWrapped[ 0 ], toBeWrapped[ 1 ] );
2536
+ }
2537
+
2538
+ // Used to determine whether only widget was pasted.
2539
+ processedWidgetOnly = evt.data.dataValue.children.length == 1 &&
2540
+ isParserWidgetWrapper( evt.data.dataValue.children[ 0 ] );
2541
+ }, null, null, 8 );
2542
+
2543
+ editor.on( 'dataReady', function() {
2544
+ // Clean up all widgets loaded from snapshot.
2545
+ if ( snapshotLoaded )
2546
+ cleanUpAllWidgetElements( widgetsRepo, editor.editable() );
2547
+ snapshotLoaded = 0;
2548
+
2549
+ // Some widgets were destroyed on contentDomUnload,
2550
+ // some on loadSnapshot, but that does not include
2551
+ // e.g. setHtml on inline editor or widgets removed just
2552
+ // before setting data.
2553
+ widgetsRepo.destroyAll( true );
2554
+ widgetsRepo.initOnAll();
2555
+ } );
2556
+
2557
+ // Set flag so dataReady will know that additional
2558
+ // cleanup is needed, because snapshot containing widgets was loaded.
2559
+ editor.on( 'loadSnapshot', function( evt ) {
2560
+ // Primitive but sufficient check which will prevent from executing
2561
+ // heavier cleanUpAllWidgetElements if not needed.
2562
+ if ( ( /data-cke-widget/ ).test( evt.data ) )
2563
+ snapshotLoaded = 1;
2564
+
2565
+ widgetsRepo.destroyAll( true );
2566
+ }, null, null, 9 );
2567
+
2568
+ // Handle pasted single widget.
2569
+ editor.on( 'paste', function( evt ) {
2570
+ evt.data.dataValue = evt.data.dataValue.replace( pasteReplaceRegex, pasteReplaceFn );
2571
+ } );
2572
+
2573
+ // Listen with high priority to check widgets after data was inserted.
2574
+ editor.on( 'insertText', checkNewWidgets, null, null, 999 );
2575
+ editor.on( 'insertHtml', checkNewWidgets, null, null, 999 );
2576
+
2577
+ function checkNewWidgets() {
2578
+ editor.fire( 'lockSnapshot' );
2579
+
2580
+ // Init only new for performance reason.
2581
+ // Focus inited if only widget was processed.
2582
+ widgetsRepo.checkWidgets( { initOnlyNew: true, focusInited: processedWidgetOnly } );
2583
+
2584
+ editor.fire( 'unlockSnapshot' );
2585
+ }
2586
+ }
2587
+
2588
+ // Helper for coordinating which widgets should be
2589
+ // selected/deselected and which one should be focused/blurred.
2590
+ function stateUpdater( widgetsRepo ) {
2591
+ var currentlySelected = widgetsRepo.selected,
2592
+ toBeSelected = [],
2593
+ toBeDeselected = currentlySelected.slice( 0 ),
2594
+ focused = null;
2595
+
2596
+ return {
2597
+ select: function( widget ) {
2598
+ if ( CKEDITOR.tools.indexOf( currentlySelected, widget ) < 0 )
2599
+ toBeSelected.push( widget );
2600
+
2601
+ var index = CKEDITOR.tools.indexOf( toBeDeselected, widget );
2602
+ if ( index >= 0 )
2603
+ toBeDeselected.splice( index, 1 );
2604
+
2605
+ return this;
2606
+ },
2607
+
2608
+ focus: function( widget ) {
2609
+ focused = widget;
2610
+ return this;
2611
+ },
2612
+
2613
+ commit: function() {
2614
+ var focusedChanged = widgetsRepo.focused !== focused,
2615
+ widget;
2616
+
2617
+ widgetsRepo.editor.fire( 'lockSnapshot' );
2618
+
2619
+ if ( focusedChanged && ( widget = widgetsRepo.focused ) )
2620
+ blurWidget( widgetsRepo, widget );
2621
+
2622
+ while ( ( widget = toBeDeselected.pop() ) ) {
2623
+ currentlySelected.splice( CKEDITOR.tools.indexOf( currentlySelected, widget ), 1 );
2624
+ // Widget could be destroyed in the meantime - e.g. data could be set.
2625
+ if ( widget.isInited() )
2626
+ widget.setSelected( false );
2627
+ }
2628
+
2629
+ if ( focusedChanged && focused ) {
2630
+ widgetsRepo.focused = focused;
2631
+ widgetsRepo.fire( 'widgetFocused', { widget: focused } );
2632
+ focused.setFocused( true );
2633
+ }
2634
+
2635
+ while ( ( widget = toBeSelected.pop() ) ) {
2636
+ currentlySelected.push( widget );
2637
+ widget.setSelected( true );
2638
+ }
2639
+
2640
+ widgetsRepo.editor.fire( 'unlockSnapshot' );
2641
+ }
2642
+ };
2643
+ }
2644
+
2645
+
2646
+ //
2647
+ // WIDGET helpers ---------------------------------------------------------
2648
+ //
2649
+
2650
+ // LEFT, RIGHT, UP, DOWN, DEL, BACKSPACE - unblock default fake sel handlers.
2651
+ var keystrokesNotBlockedByWidget = { 37: 1, 38: 1, 39: 1, 40: 1, 8: 1, 46: 1 };
2652
+
2653
+ // Applies or removes style's classes from widget.
2654
+ // @param {CKEDITOR.style} style Custom widget style.
2655
+ // @param {Boolean} apply Whether to apply or remove style.
2656
+ function applyRemoveStyle( widget, style, apply ) {
2657
+ var changed = 0,
2658
+ classes = getStyleClasses( style ),
2659
+ updatedClasses = widget.data.classes || {},
2660
+ cl;
2661
+
2662
+ // Ee... Something is wrong with this style.
2663
+ if ( !classes )
2664
+ return;
2665
+
2666
+ // Clone, because we need to break reference.
2667
+ updatedClasses = CKEDITOR.tools.clone( updatedClasses );
2668
+
2669
+ while ( ( cl = classes.pop() ) ) {
2670
+ if ( apply ) {
2671
+ if ( !updatedClasses[ cl ] )
2672
+ changed = updatedClasses[ cl ] = 1;
2673
+ } else {
2674
+ if ( updatedClasses[ cl ] ) {
2675
+ delete updatedClasses[ cl ];
2676
+ changed = 1;
2677
+ }
2678
+ }
2679
+ }
2680
+ if ( changed )
2681
+ widget.setData( 'classes', updatedClasses );
2682
+ }
2683
+
2684
+ function cancel( evt ) {
2685
+ evt.cancel();
2686
+ }
2687
+
2688
+ function copySingleWidget( widget, isCut ) {
2689
+ var editor = widget.editor,
2690
+ doc = editor.document;
2691
+
2692
+ // We're still handling previous copy/cut.
2693
+ // When keystroke is used to copy/cut this will also prevent
2694
+ // conflict with copySingleWidget called again for native copy/cut event.
2695
+ if ( doc.getById( 'cke_copybin' ) )
2696
+ return;
2697
+
2698
+ // [IE] Use span for copybin and its container to avoid bug with expanding editable height by
2699
+ // absolutely positioned element.
2700
+ var copybinName = ( editor.blockless || CKEDITOR.env.ie ) ? 'span' : 'div',
2701
+ copybin = doc.createElement( copybinName ),
2702
+ copybinContainer = doc.createElement( copybinName ),
2703
+ // IE8 always jumps to the end of document.
2704
+ needsScrollHack = CKEDITOR.env.ie && CKEDITOR.env.version < 9;
2705
+
2706
+ copybinContainer.setAttributes( {
2707
+ id: 'cke_copybin',
2708
+ 'data-cke-temp': '1'
2709
+ } );
2710
+
2711
+ // Position copybin element outside current viewport.
2712
+ copybin.setStyles( {
2713
+ position: 'absolute',
2714
+ width: '1px',
2715
+ height: '1px',
2716
+ overflow: 'hidden'
2717
+ } );
2718
+
2719
+ copybin.setStyle( editor.config.contentsLangDirection == 'ltr' ? 'left' : 'right', '-5000px' );
2720
+
2721
+ copybin.setHtml( '<span data-cke-copybin-start="1">\u200b</span>' + widget.wrapper.getOuterHtml() + '<span data-cke-copybin-end="1">\u200b</span>' );
2722
+
2723
+ // Save snapshot with the current state.
2724
+ editor.fire( 'saveSnapshot' );
2725
+
2726
+ // Ignore copybin.
2727
+ editor.fire( 'lockSnapshot' );
2728
+
2729
+ copybinContainer.append( copybin );
2730
+ editor.editable().append( copybinContainer );
2731
+
2732
+ var listener1 = editor.on( 'selectionChange', cancel, null, null, 0 ),
2733
+ listener2 = widget.repository.on( 'checkSelection', cancel, null, null, 0 );
2734
+
2735
+ if ( needsScrollHack ) {
2736
+ var docElement = doc.getDocumentElement().$,
2737
+ scrollTop = docElement.scrollTop;
2738
+ }
2739
+
2740
+ // Once the clone of the widget is inside of copybin, select
2741
+ // the entire contents. This selection will be copied by the
2742
+ // native browser's clipboard system.
2743
+ var range = editor.createRange();
2744
+ range.selectNodeContents( copybin );
2745
+ range.select();
2746
+
2747
+ if ( needsScrollHack )
2748
+ docElement.scrollTop = scrollTop;
2749
+
2750
+ setTimeout( function() {
2751
+ // [IE] Focus widget before removing copybin to avoid scroll jump.
2752
+ if ( !isCut )
2753
+ widget.focus();
2754
+
2755
+ copybinContainer.remove();
2756
+
2757
+ listener1.removeListener();
2758
+ listener2.removeListener();
2759
+
2760
+ editor.fire( 'unlockSnapshot' );
2761
+
2762
+ if ( isCut ) {
2763
+ widget.repository.del( widget );
2764
+ editor.fire( 'saveSnapshot' );
2765
+ }
2766
+ }, 100 ); // Use 100ms, so Chrome (@Mac) will be able to grab the content.
2767
+ }
2768
+
2769
+ // Extracts classes array from style instance.
2770
+ function getStyleClasses( style ) {
2771
+ var attrs = style.getDefinition().attributes,
2772
+ classes = attrs && attrs[ 'class' ];
2773
+
2774
+ return classes ? classes.split( /\s+/ ) : null;
2775
+ }
2776
+
2777
+ // [IE] Force keeping focus because IE sometimes forgets to fire focus on main editable
2778
+ // when blurring nested editable.
2779
+ // @context widget
2780
+ function onEditableBlur() {
2781
+ var active = CKEDITOR.document.getActive(),
2782
+ editor = this.editor,
2783
+ editable = editor.editable();
2784
+
2785
+ // If focus stays within editor override blur and set currentActive because it should be
2786
+ // automatically changed to editable on editable#focus but it is not fired.
2787
+ if ( ( editable.isInline() ? editable : editor.document.getWindow().getFrame() ).equals( active ) )
2788
+ editor.focusManager.focus( editable );
2789
+ }
2790
+
2791
+ // Force selectionChange when editable was focused.
2792
+ // Similar to hack in selection.js#~620.
2793
+ // @context widget
2794
+ function onEditableFocus() {
2795
+ // Gecko does not support 'DOMFocusIn' event on which we unlock selection
2796
+ // in selection.js to prevent selection locking when entering nested editables.
2797
+ if ( CKEDITOR.env.gecko )
2798
+ this.editor.unlockSelection();
2799
+
2800
+ // We don't need to force selectionCheck on Webkit, because on Webkit
2801
+ // we do that on DOMFocusIn in selection.js.
2802
+ if ( !CKEDITOR.env.webkit ) {
2803
+ this.editor.forceNextSelectionCheck();
2804
+ this.editor.selectionChange( 1 );
2805
+ }
2806
+ }
2807
+
2808
+ // Setup listener on widget#data which will update (remove/add) classes
2809
+ // by comparing newly set classes with the old ones.
2810
+ function setupDataClassesListener( widget ) {
2811
+ // Note: previousClasses and newClasses may be null!
2812
+ // Tip: for ( cl in null ) is correct.
2813
+ var previousClasses = null;
2814
+
2815
+ widget.on( 'data', function() {
2816
+ var newClasses = this.data.classes,
2817
+ cl;
2818
+
2819
+ // When setting new classes one need to remember
2820
+ // that he must break reference.
2821
+ if ( previousClasses == newClasses )
2822
+ return;
2823
+
2824
+ for ( cl in previousClasses ) {
2825
+ // Avoid removing and adding classes again.
2826
+ if ( !( newClasses && newClasses[ cl ] ) )
2827
+ this.removeClass( cl );
2828
+ }
2829
+ for ( cl in newClasses )
2830
+ this.addClass( cl );
2831
+
2832
+ previousClasses = newClasses;
2833
+ } );
2834
+ }
2835
+
2836
+ function setupDragHandler( widget ) {
2837
+ if ( !widget.draggable )
2838
+ return;
2839
+
2840
+ var editor = widget.editor,
2841
+ container = widget.wrapper.findOne( '.cke_widget_drag_handler_container' ),
2842
+ img;
2843
+
2844
+ // Reuse drag handler if already exists (#11281).
2845
+ if ( container )
2846
+ img = container.findOne( 'img' );
2847
+ else {
2848
+ container = new CKEDITOR.dom.element( 'span', editor.document );
2849
+ container.setAttributes( {
2850
+ 'class': 'cke_reset cke_widget_drag_handler_container',
2851
+ // Split background and background-image for IE8 which will break on rgba().
2852
+ style: 'background:rgba(220,220,220,0.5);background-image:url(' + editor.plugins.widget.path + 'images/handle.png)'
2853
+ } );
2854
+
2855
+ img = new CKEDITOR.dom.element( 'img', editor.document );
2856
+ img.setAttributes( {
2857
+ 'class': 'cke_reset cke_widget_drag_handler',
2858
+ 'data-cke-widget-drag-handler': '1',
2859
+ src: CKEDITOR.tools.transparentImageData,
2860
+ width: DRAG_HANDLER_SIZE,
2861
+ title: editor.lang.widget.move,
2862
+ height: DRAG_HANDLER_SIZE
2863
+ } );
2864
+ widget.inline && img.setAttribute( 'draggable', 'true' );
2865
+
2866
+ container.append( img );
2867
+ widget.wrapper.append( container );
2868
+ }
2869
+
2870
+ widget.wrapper.on( 'mouseenter', widget.updateDragHandlerPosition, widget );
2871
+ setTimeout( function() {
2872
+ widget.on( 'data', widget.updateDragHandlerPosition, widget );
2873
+ }, 50 );
2874
+
2875
+ if ( widget.inline ) {
2876
+ img.on( 'dragstart', function( evt ) {
2877
+ evt.data.$.dataTransfer.setData( 'text', JSON.stringify( { type: 'cke-widget', editor: editor.name, id: widget.id } ) );
2878
+ } );
2879
+ } else
2880
+ img.on( 'mousedown', onBlockWidgetDrag, widget );
2881
+
2882
+ widget.dragHandlerContainer = container;
2883
+ }
2884
+
2885
+ function onBlockWidgetDrag() {
2886
+ var finder = this.repository.finder,
2887
+ locator = this.repository.locator,
2888
+ liner = this.repository.liner,
2889
+ editor = this.editor,
2890
+ editable = editor.editable(),
2891
+ listeners = [],
2892
+ sorted = [],
2893
+
2894
+ // Harvest all possible relations and display some closest.
2895
+ relations = finder.greedySearch(),
2896
+
2897
+ buffer = CKEDITOR.tools.eventsBuffer( 50, function() {
2898
+ locations = locator.locate( relations );
2899
+
2900
+ // There's only a single line displayed for D&D.
2901
+ sorted = locator.sort( y, 1 );
2902
+
2903
+ if ( sorted.length ) {
2904
+ liner.prepare( relations, locations );
2905
+ liner.placeLine( sorted[ 0 ] );
2906
+ liner.cleanup();
2907
+ }
2908
+ } ),
2909
+
2910
+ locations, y;
2911
+
2912
+ // Let's have the "dragging cursor" over entire editable.
2913
+ editable.addClass( 'cke_widget_dragging' );
2914
+
2915
+ // Cache mouse position so it is re-used in events buffer.
2916
+ listeners.push( editable.on( 'mousemove', function( evt ) {
2917
+ y = evt.data.$.clientY;
2918
+ buffer.input();
2919
+ } ) );
2920
+
2921
+ function onMouseUp() {
2922
+ var l;
2923
+
2924
+ buffer.reset();
2925
+
2926
+ // Stop observing events.
2927
+ while ( ( l = listeners.pop() ) )
2928
+ l.removeListener();
2929
+
2930
+ onBlockWidgetDrop.call( this, sorted );
2931
+ }
2932
+
2933
+ // Mouseup means "drop". This is when the widget is being detached
2934
+ // from DOM and placed at range determined by the line (location).
2935
+ listeners.push( editor.document.once( 'mouseup', onMouseUp, this ) );
2936
+
2937
+ // Mouseup may occur when user hovers the line, which belongs to
2938
+ // the outer document. This is, of course, a valid listener too.
2939
+ listeners.push( CKEDITOR.document.once( 'mouseup', onMouseUp, this ) );
2940
+ }
2941
+
2942
+ function onBlockWidgetDrop( sorted ) {
2943
+ var finder = this.repository.finder,
2944
+ liner = this.repository.liner,
2945
+ editor = this.editor,
2946
+ editable = this.editor.editable();
2947
+
2948
+ if ( !CKEDITOR.tools.isEmpty( liner.visible ) ) {
2949
+ // Retrieve range for the closest location.
2950
+ var range = finder.getRange( sorted[ 0 ] );
2951
+
2952
+ // Focus widget (it could lost focus after mousedown+mouseup)
2953
+ // and save this state as the one where we want to be taken back when undoing.
2954
+ this.focus();
2955
+ editor.fire( 'saveSnapshot' );
2956
+ // Group all following operations in one snapshot.
2957
+ editor.fire( 'lockSnapshot', { dontUpdate: 1 } );
2958
+
2959
+ // Reset the fake selection, which will be invalidated by insertElementIntoRange.
2960
+ // This avoids a situation when getSelection() still returns a fake selection made
2961
+ // on widget which in the meantime has been moved to other place. That could cause
2962
+ // an error thrown e.g. by saveSnapshot or stateUpdater.
2963
+ editor.getSelection().reset();
2964
+
2965
+ // Attach widget at the place determined by range.
2966
+ editable.insertElementIntoRange( this.wrapper, range );
2967
+
2968
+ // Focus again the dropped widget.
2969
+ this.focus();
2970
+
2971
+ // Unlock snapshot and save new one, which will contain all changes done
2972
+ // in this method.
2973
+ editor.fire( 'unlockSnapshot' );
2974
+ editor.fire( 'saveSnapshot' );
2975
+ }
2976
+
2977
+ // Clean-up custom cursor for editable.
2978
+ editable.removeClass( 'cke_widget_dragging' );
2979
+
2980
+ // Clean-up all remaining lines.
2981
+ liner.hideVisible();
2982
+ }
2983
+
2984
+ function setupEditables( widget ) {
2985
+ var editableName,
2986
+ editableDef,
2987
+ definedEditables = widget.editables;
2988
+
2989
+ widget.editables = {};
2990
+
2991
+ if ( !widget.editables )
2992
+ return;
2993
+
2994
+ for ( editableName in definedEditables ) {
2995
+ editableDef = definedEditables[ editableName ];
2996
+ widget.initEditable( editableName, typeof editableDef == 'string' ? { selector: editableDef } : editableDef );
2997
+ }
2998
+ }
2999
+
3000
+ function setupMask( widget ) {
3001
+ if ( !widget.mask )
3002
+ return;
3003
+
3004
+ // Reuse mask if already exists (#11281).
3005
+ var img = widget.wrapper.findOne( '.cke_widget_mask' );
3006
+
3007
+ if ( !img ) {
3008
+ img = new CKEDITOR.dom.element( 'img', widget.editor.document );
3009
+ img.setAttributes( {
3010
+ src: CKEDITOR.tools.transparentImageData,
3011
+ 'class': 'cke_reset cke_widget_mask'
3012
+ } );
3013
+ widget.wrapper.append( img );
3014
+ }
3015
+
3016
+ widget.mask = img;
3017
+ }
3018
+
3019
+ // Replace parts object containing:
3020
+ // partName => selector pairs
3021
+ // with:
3022
+ // partName => element pairs
3023
+ function setupParts( widget ) {
3024
+ if ( widget.parts ) {
3025
+ var parts = {},
3026
+ el, partName;
3027
+
3028
+ for ( partName in widget.parts ) {
3029
+ el = widget.wrapper.findOne( widget.parts[ partName ] );
3030
+ parts[ partName ] = el;
3031
+ }
3032
+ widget.parts = parts;
3033
+ }
3034
+ }
3035
+
3036
+ function setupWidget( widget, widgetDef ) {
3037
+ setupWrapper( widget );
3038
+ setupParts( widget );
3039
+ setupEditables( widget );
3040
+ setupMask( widget );
3041
+ setupDragHandler( widget );
3042
+ setupDataClassesListener( widget );
3043
+
3044
+ // #11145: [IE8] Non-editable content of widget is draggable.
3045
+ if ( CKEDITOR.env.ie && CKEDITOR.env.version < 9 ) {
3046
+ widget.wrapper.on( 'dragstart', function( evt ) {
3047
+ var target = evt.data.getTarget();
3048
+
3049
+ // Allow text dragging inside nested editables or dragging inline widget's drag handler.
3050
+ if ( !getNestedEditable( widget, target ) && !( widget.inline && isDomDragHandler( target ) ) )
3051
+ evt.data.preventDefault();
3052
+ } );
3053
+ }
3054
+
3055
+ widget.wrapper.removeClass( 'cke_widget_new' );
3056
+ widget.element.addClass( 'cke_widget_element' );
3057
+
3058
+ widget.on( 'key', function( evt ) {
3059
+ var keyCode = evt.data.keyCode;
3060
+
3061
+ // ENTER.
3062
+ if ( keyCode == 13 )
3063
+ widget.edit();
3064
+ // CTRL+C or CTRL+X.
3065
+ else if ( keyCode == CKEDITOR.CTRL + 67 || keyCode == CKEDITOR.CTRL + 88 ) {
3066
+ copySingleWidget( widget, keyCode == CKEDITOR.CTRL + 88 );
3067
+ return; // Do not preventDefault.
3068
+ }
3069
+ // Pass chosen keystrokes to other plugins or default fake sel handlers.
3070
+ // Pass all CTRL/ALT keystrokes.
3071
+ else if ( keyCode in keystrokesNotBlockedByWidget || ( CKEDITOR.CTRL & keyCode ) || ( CKEDITOR.ALT & keyCode ) )
3072
+ return;
3073
+
3074
+ return false;
3075
+ }, null, null, 999 );
3076
+ // Listen with high priority so it's possible
3077
+ // to overwrite this callback.
3078
+
3079
+ widget.on( 'doubleclick', function( evt ) {
3080
+ widget.edit();
3081
+ } );
3082
+
3083
+ if ( widgetDef.data )
3084
+ widget.on( 'data', widgetDef.data );
3085
+
3086
+ if ( widgetDef.edit )
3087
+ widget.on( 'edit', widgetDef.edit );
3088
+ }
3089
+
3090
+ function setupWidgetData( widget, startupData ) {
3091
+ var widgetDataAttr = widget.element.data( 'cke-widget-data' );
3092
+
3093
+ if ( widgetDataAttr )
3094
+ widget.setData( JSON.parse( decodeURIComponent( widgetDataAttr ) ) );
3095
+ if ( startupData )
3096
+ widget.setData( startupData );
3097
+
3098
+ // Populate classes if they are not preset.
3099
+ if ( !widget.data.classes )
3100
+ widget.setData( 'classes', widget.getClasses() );
3101
+
3102
+ // Unblock data and...
3103
+ widget.dataReady = true;
3104
+
3105
+ // Write data to element because this was blocked when data wasn't ready.
3106
+ writeDataToElement( widget );
3107
+
3108
+ // Fire data event first time, because this was blocked when data wasn't ready.
3109
+ widget.fire( 'data', widget.data );
3110
+ }
3111
+
3112
+ function setupWrapper( widget ) {
3113
+ // Retrieve widget wrapper. Assign an id to it.
3114
+ var wrapper = widget.wrapper = widget.element.getParent();
3115
+ wrapper.setAttribute( 'data-cke-widget-id', widget.id );
3116
+ }
3117
+
3118
+ function writeDataToElement( widget ) {
3119
+ widget.element.data( 'cke-widget-data', encodeURIComponent( JSON.stringify( widget.data ) ) );
3120
+ }
3121
+
3122
+ //
3123
+ // WIDGET STYLE HANDLER ---------------------------------------------------
3124
+ //
3125
+
3126
+ ( function() {
3127
+
3128
+ /**
3129
+ * The class representing a widget style. It is an {@link CKEDITOR#STYLE_OBJECT object} like
3130
+ * the styles handler for widgets.
3131
+ *
3132
+ * **Note:** This custom style handler does not support all methods of the {@link CKEDITOR.style} class.
3133
+ * Not supported methods: {@link #applyToRange}, {@link #removeFromRange}, {@link #applyToObject}.
3134
+ *
3135
+ * @since 4.4
3136
+ * @class CKEDITOR.style.customHandlers.widget
3137
+ * @extends CKEDITOR.style
3138
+ */
3139
+ CKEDITOR.style.addCustomHandler( {
3140
+ type: 'widget',
3141
+
3142
+ setup: function( styleDefinition ) {
3143
+ /**
3144
+ * The name of widget to which this style can be applied.
3145
+ * It is extracted from style definition's `widget` property.
3146
+ *
3147
+ * @property {String} widget
3148
+ */
3149
+ this.widget = styleDefinition.widget;
3150
+ },
3151
+
3152
+ apply: function( editor ) {
3153
+ // Before CKEditor 4.4 wasn't a required argument, so we need to
3154
+ // handle a case when it wasn't provided.
3155
+ if ( !( editor instanceof CKEDITOR.editor ) )
3156
+ return;
3157
+
3158
+ // Theoretically we could bypass checkApplicable, get widget from
3159
+ // widgets.focused and check its name, what would be faster, but then
3160
+ // this custom style would work differently than the default style
3161
+ // which checks if it's applicable before applying or removeing itself.
3162
+ if ( this.checkApplicable( editor.elementPath(), editor ) )
3163
+ editor.widgets.focused.applyStyle( this );
3164
+ },
3165
+
3166
+ remove: function( editor ) {
3167
+ // Before CKEditor 4.4 wasn't a required argument, so we need to
3168
+ // handle a case when it wasn't provided.
3169
+ if ( !( editor instanceof CKEDITOR.editor ) )
3170
+ return;
3171
+
3172
+ if ( this.checkApplicable( editor.elementPath(), editor ) )
3173
+ editor.widgets.focused.removeStyle( this );
3174
+ },
3175
+
3176
+ checkActive: function( elementPath, editor ) {
3177
+ return this.checkElementMatch( elementPath.lastElement, 0, editor );
3178
+ },
3179
+
3180
+ checkApplicable: function( elementPath, editor, filter ) {
3181
+ // Before CKEditor 4.4 wasn't a required argument, so we need to
3182
+ // handle a case when it wasn't provided.
3183
+ if ( !( editor instanceof CKEDITOR.editor ) )
3184
+ return false;
3185
+
3186
+ return this.checkElement( elementPath.lastElement, editor );
3187
+ },
3188
+
3189
+ checkElementMatch: checkElementMatch,
3190
+
3191
+ checkElementRemovable: checkElementMatch,
3192
+
3193
+ /**
3194
+ * Checks if an element is a {@link CKEDITOR.plugins.widget#wrapper wrapper} of a
3195
+ * widget whose name matches the {@link #widget widget name} specified in the style definition.
3196
+ *
3197
+ * @param {CKEDITOR.dom.element} element
3198
+ * @param {CKEDITOR.editor} editor
3199
+ * @returns {Boolean}
3200
+ */
3201
+ checkElement: function( element, editor ) {
3202
+ if ( !isDomWidgetWrapper( element ) )
3203
+ return false;
3204
+
3205
+ var widgetElement = element.getFirst( isDomWidgetElement );
3206
+ return widgetElement && widgetElement.data( 'widget' ) == this.widget;
3207
+ },
3208
+
3209
+ buildPreview: function( label ) {
3210
+ return label || this._.definition.name;
3211
+ },
3212
+
3213
+ /**
3214
+ * Returns allowed content rules which should be registered for this style.
3215
+ * Uses widget's {@link CKEDITOR.plugins.widget.definition#styleableElements} to make a rule
3216
+ * allowing classes on specified elements or use widget's
3217
+ * {@link CKEDITOR.plugins.widget.definition#styleToAllowedContentRules} method to transform a style
3218
+ * into allowed content rules.
3219
+ *
3220
+ * @param {CKEDITOR.editor} The editor instance.
3221
+ * @returns {CKEDITOR.filter.allowedContentRules}
3222
+ */
3223
+ toAllowedContentRules: function( editor ) {
3224
+ if ( !editor )
3225
+ return null;
3226
+
3227
+ var widgetDef = editor.widgets.registered[ this.widget ],
3228
+ classes,
3229
+ rule = {};
3230
+
3231
+ if ( !widgetDef )
3232
+ return null;
3233
+
3234
+ if ( widgetDef.styleableElements ) {
3235
+ classes = this.getClassesArray();
3236
+ if ( !classes )
3237
+ return null;
3238
+
3239
+ rule[ widgetDef.styleableElements ] = {
3240
+ classes: classes,
3241
+ propertiesOnly: true
3242
+ };
3243
+ return rule;
3244
+ }
3245
+ if ( widgetDef.styleToAllowedContentRules )
3246
+ return widgetDef.styleToAllowedContentRules( this );
3247
+ return null;
3248
+ },
3249
+
3250
+ /**
3251
+ * Returns classes defined in the style in form of an array.
3252
+ *
3253
+ * @returns {String[]}
3254
+ */
3255
+ getClassesArray: function() {
3256
+ var classes = this._.definition.attributes && this._.definition.attributes[ 'class' ];
3257
+
3258
+ return classes ? CKEDITOR.tools.trim( classes ).split( /\s+/ ) : null;
3259
+ },
3260
+
3261
+ /**
3262
+ * Not implemented.
3263
+ *
3264
+ * @method applyToRange
3265
+ */
3266
+ applyToRange: notImplemented,
3267
+
3268
+ /**
3269
+ * Not implemented.
3270
+ *
3271
+ * @method removeFromRange
3272
+ */
3273
+ removeFromRange: notImplemented,
3274
+
3275
+ /**
3276
+ * Not implemented.
3277
+ *
3278
+ * @method applyToObject
3279
+ */
3280
+ applyToObject: notImplemented
3281
+ } );
3282
+
3283
+ function notImplemented() {}
3284
+
3285
+ // @context style
3286
+ function checkElementMatch( element, fullMatch, editor ) {
3287
+ // Before CKEditor 4.4 wasn't a required argument, so we need to
3288
+ // handle a case when it wasn't provided.
3289
+ if ( !editor )
3290
+ return false;
3291
+
3292
+ if ( !this.checkElement( element, editor ) )
3293
+ return false;
3294
+
3295
+ var widget = editor.widgets.getByElement( element, true );
3296
+ return widget && widget.checkStyleActive( this );
3297
+ }
3298
+
3299
+ } )();
3300
+
3301
+ //
3302
+ // EXPOSE PUBLIC API ------------------------------------------------------
3303
+ //
3304
+
3305
+ CKEDITOR.plugins.widget = Widget;
3306
+ Widget.repository = Repository;
3307
+ Widget.nestedEditable = NestedEditable;
3308
+ } )();
3309
+
3310
+ /**
3311
+ * An event fired when a widget definition is registered by the {@link CKEDITOR.plugins.widget.repository#add} method.
3312
+ * It is possible to modify the definition being registered.
3313
+ *
3314
+ * @event widgetDefinition
3315
+ * @member CKEDITOR.editor
3316
+ * @param {CKEDITOR.plugins.widget.definition} data Widget definition.
3317
+ */
3318
+
3319
+ /**
3320
+ * This is an abstract class that describes the definition of a widget.
3321
+ * It is a type of {@link CKEDITOR.plugins.widget.repository#add} method's second argument.
3322
+ *
3323
+ * Widget instances inherit from registered widget definitions, although not in a prototypal way.
3324
+ * They are simply extended with corresponding widget definitions. Note that not all properties of
3325
+ * the widget definition become properties of a widget. Some, like {@link #data} or {@link #edit}, become
3326
+ * widget's events listeners.
3327
+ *
3328
+ * @class CKEDITOR.plugins.widget.definition
3329
+ * @abstract
3330
+ * @mixins CKEDITOR.feature
3331
+ */
3332
+
3333
+ /**
3334
+ * Widget definition name. It is automatically set when the definition is
3335
+ * {@link CKEDITOR.plugins.widget.repository#add registered}.
3336
+ *
3337
+ * @property {String} name
3338
+ */
3339
+
3340
+ /**
3341
+ * The method executed while initializing a widget, after a widget instance
3342
+ * is created, but before it is ready. It is executed before the first
3343
+ * {@link CKEDITOR.plugins.widget#event-data} is fired so it is common to
3344
+ * use the `init` method to populate widget data with information loaded from
3345
+ * the DOM, like for exmaple:
3346
+ *
3347
+ * init: function() {
3348
+ * this.setData( 'width', this.element.getStyle( 'width' ) );
3349
+ *
3350
+ * if ( this.parts.caption.getStyle( 'display' ) != 'none' )
3351
+ * this.setData( 'showCaption', true );
3352
+ * }
3353
+ *
3354
+ * @property {Function} init
3355
+ */
3356
+
3357
+ /**
3358
+ * The function to be used to upcast an element to this widget or a
3359
+ * comma-separated list of upcast methods from the {@link #upcasts} object.
3360
+ *
3361
+ * The upcast function **is not** executed in the widget context (because the widget
3362
+ * does not exist yet) and two arguments are passed:
3363
+ *
3364
+ * * `element` ({@link CKEDITOR.htmlParser.element}) &ndash; The element to be checked.
3365
+ * * `data` (`Object`) &ndash; The object which can be extended with data which will then be passed to the widget.
3366
+ *
3367
+ * An element will be upcasted if a function returned `true` or an instance of
3368
+ * a {@link CKEDITOR.htmlParser.element} if upcasting meant DOM structure changes
3369
+ * (in this case the widget will be initialized on the returned element).
3370
+ *
3371
+ * @property {String/Function} upcast
3372
+ */
3373
+
3374
+ /**
3375
+ * The object containing functions which can be used to upcast this widget.
3376
+ * Only those pointed by the {@link #upcast} property will be used.
3377
+ *
3378
+ * In most cases it is appropriate to use {@link #upcast} directly,
3379
+ * because majority of widgets need just one method.
3380
+ * However, in some cases the widget author may want to expose more than one variant
3381
+ * and then this property may be used.
3382
+ *
3383
+ * upcasts: {
3384
+ * // This function may upcast only figure elements.
3385
+ * figure: function() {
3386
+ * // ...
3387
+ * },
3388
+ * // This function may upcast only image elements.
3389
+ * image: function() {
3390
+ * // ...
3391
+ * },
3392
+ * // More variants...
3393
+ * }
3394
+ *
3395
+ * // Then, widget user may choose which upcast methods will be enabled.
3396
+ * editor.on( 'widgetDefinition', function( evt ) {
3397
+ * if ( evt.data.name == 'image' )
3398
+ * evt.data.upcast = 'figure,image'; // Use both methods.
3399
+ * } );
3400
+ *
3401
+ * @property {Object} upcasts
3402
+ */
3403
+
3404
+ /**
3405
+ * The function to be used to downcast this widget or
3406
+ * a name of the downcast option from the {@link #downcasts} object.
3407
+ *
3408
+ * The downcast funciton will be executed in the {@link CKEDITOR.plugins.widget} context
3409
+ * and with `widgetElement` ({@link CKEDITOR.htmlParser.element}) argument which is
3410
+ * the widget's main element.
3411
+ *
3412
+ * The function may return an instance of the {@link CKEDITOR.htmlParser.node} class if the widget
3413
+ * needs to be downcasted to a different node than the widget's main element.
3414
+ *
3415
+ * @property {String/Function} downcast
3416
+ */
3417
+
3418
+ /**
3419
+ * The object containing functions which can be used to downcast this widget.
3420
+ * Only the one pointed by the {@link #downcast} property will be used.
3421
+ *
3422
+ * In most cases it is appropriate to use {@link #downcast} directly,
3423
+ * because majority of widgets have just one variant of downcasting (or none at all).
3424
+ * However, in some cases the widget author may want to expose more than one variant
3425
+ * and then this property may be used.
3426
+ *
3427
+ * downcasts: {
3428
+ * // This downcast may transform the widget into the figure element.
3429
+ * figure: function() {
3430
+ * // ...
3431
+ * },
3432
+ * // This downcast may transform the widget into the image element with data-* attributes.
3433
+ * image: function() {
3434
+ * // ...
3435
+ * }
3436
+ * }
3437
+ *
3438
+ * // Then, the widget user may choose one of the downcast options when setting up his editor.
3439
+ * editor.on( 'widgetDefinition', function( evt ) {
3440
+ * if ( evt.data.name == 'image' )
3441
+ * evt.data.downcast = 'figure';
3442
+ * } );
3443
+ *
3444
+ * @property downcasts
3445
+ */
3446
+
3447
+ /**
3448
+ * If set, it will be added as the {@link CKEDITOR.plugins.widget#event-edit} event listener.
3449
+ * This means that it will be executed when a widget is being edited.
3450
+ * See the {@link CKEDITOR.plugins.widget#method-edit} method.
3451
+ *
3452
+ * @property {Function} edit
3453
+ */
3454
+
3455
+ /**
3456
+ * If set, it will be added as the {@link CKEDITOR.plugins.widget#event-data} event listener.
3457
+ * This means that it will be executed every time the {@link CKEDITOR.plugins.widget#property-data widget data} changes.
3458
+ *
3459
+ * @property {Function} data
3460
+ */
3461
+
3462
+ /**
3463
+ * The method to be executed when the widget's command is executed in order to insert a new widget
3464
+ * (widget of this type is not focused). If not defined, then the default action will be
3465
+ * performed which means that:
3466
+ *
3467
+ * * An instance of the widget will be created in a detached {@link CKEDITOR.dom.documentFragment document fragment},
3468
+ * * The {@link CKEDITOR.plugins.widget#method-edit} method will be called to trigger widget editing,
3469
+ * * The widget element will be inserted into DOM.
3470
+ *
3471
+ * @property {Function} insert
3472
+ */
3473
+
3474
+ /**
3475
+ * The name of a dialog window which will be opened on {@link CKEDITOR.plugins.widget#method-edit}.
3476
+ * If not defined, then the {@link CKEDITOR.plugins.widget#method-edit} method will not perform any action and
3477
+ * widget's command will insert a new widget without opening a dialog window first.
3478
+ *
3479
+ * @property {String} dialog
3480
+ */
3481
+
3482
+ /**
3483
+ * The template which will be used to create a new widget element (when the widget's command is executed).
3484
+ * This string is populated with {@link #defaults default values} by using the {@link CKEDITOR.template} format.
3485
+ * Therefore it has to be a valid {@link CKEDITOR.template} argument.
3486
+ *
3487
+ * @property {String} template
3488
+ */
3489
+
3490
+ /**
3491
+ * The data object which will be used to populate the data of a newly created widget.
3492
+ * See {@link CKEDITOR.plugins.widget#property-data}.
3493
+ *
3494
+ * defaults: {
3495
+ * showCaption: true,
3496
+ * align: 'none'
3497
+ * }
3498
+ *
3499
+ * @property defaults
3500
+ */
3501
+
3502
+ /**
3503
+ * An object containing definitions of widget components (part name => CSS selector).
3504
+ *
3505
+ * parts: {
3506
+ * image: 'img',
3507
+ * caption: 'div.caption'
3508
+ * }
3509
+ *
3510
+ * @property parts
3511
+ */
3512
+
3513
+ /**
3514
+ * An object containing definitions of nested editables (editable name => {@link CKEDITOR.plugins.widget.nestedEditable.definition}).
3515
+ *
3516
+ * editables: {
3517
+ * header: 'h1',
3518
+ * content: {
3519
+ * selector: 'div.content',
3520
+ * allowedContent: 'p strong em; a[!href]'
3521
+ * }
3522
+ * }
3523
+ *
3524
+ * @property editables
3525
+ */
3526
+
3527
+ /**
3528
+ * Widget name displayed in elements path.
3529
+ *
3530
+ * @property {String} pathName
3531
+ */
3532
+
3533
+ /**
3534
+ * If set to `true`, the widget's element will be covered with a transparent mask.
3535
+ * This will prevent its content from being clickable, which matters in case
3536
+ * of special elements like embedded Flash or iframes that generate a separate "context".
3537
+ *
3538
+ * @property {Boolean} mask
3539
+ */
3540
+
3541
+ /**
3542
+ * If set to `true/false`, it will force the widget to be either an inline or a block widget.
3543
+ * If not set, the widget type will be determined from the widget element.
3544
+ *
3545
+ * Widget type influences whether a block (`div`) or an inline (`span`) element is used
3546
+ * for the wrapper.
3547
+ *
3548
+ * @property {Boolean} inline
3549
+ */
3550
+
3551
+ /**
3552
+ * The label for the widget toolbar button.
3553
+ *
3554
+ * editor.widgets.add( 'simplebox', {
3555
+ * button: 'Create a simple box'
3556
+ * } );
3557
+ *
3558
+ * editor.widgets.add( 'simplebox', {
3559
+ * button: editor.lang.simplebox.title
3560
+ * } );
3561
+ *
3562
+ * @property {String} button
3563
+ */
3564
+
3565
+ /**
3566
+ * Whether widget should be draggable. Defaults to `true`.
3567
+ * If set to `false` drag handler will not be displayed when hovering widget.
3568
+ *
3569
+ * @property {Boolean} draggable
3570
+ */
3571
+
3572
+ /**
3573
+ * Names of element(s) (separated by spaces) for which the {@link CKEDITOR.filter} should allow classes
3574
+ * defined in the widget styles. For example if your widget is upcasted from a simple `<div>`
3575
+ * element, then in order to make it styleable you can set:
3576
+ *
3577
+ * editor.widgets.add( 'customWidget', {
3578
+ * upcast: function( element ) {
3579
+ * return element.name == 'div';
3580
+ * },
3581
+ *
3582
+ * // ...
3583
+ *
3584
+ * styleableElements: 'div'
3585
+ * } );
3586
+ *
3587
+ * Then, when the following style is defined:
3588
+ *
3589
+ * {
3590
+ * name: 'Thick border', type: 'widget', widget: 'customWidget',
3591
+ * attributes: { 'class': 'thickBorder' }
3592
+ * }
3593
+ *
3594
+ * a rule allowing the `thickBorder` class for `div` elements will be registered in the {@link CKEDITOR.filter}.
3595
+ *
3596
+ * If you need to have more freedom when transforming widget style to allowed content rules,
3597
+ * you can use the {@link #styleToAllowedContentRules} callback.
3598
+ *
3599
+ * @since 4.4
3600
+ * @property {String} styleableElements
3601
+ */
3602
+
3603
+ /**
3604
+ * Function transforming custom widget's {@link CKEDITOR.style} instance into
3605
+ * {@link CKEDITOR.filter.allowedContentRules}. It may be used when a static
3606
+ * {@link #styleableElements} property is not enough to inform the {@link CKEDITOR.filter}
3607
+ * what HTML features should be enabled when allowing the given style.
3608
+ *
3609
+ * In most cases, when style's classes just have to be added to element name(s) used by
3610
+ * the widget element, it is recommended to use simpler {@link #styleableElements} property.
3611
+ *
3612
+ * In order to get parsed classes from the style definition you can use
3613
+ * {@link CKEDITOR.style.customHandlers.widget#getClassesArray}.
3614
+ *
3615
+ * For example, if you want to use the [object format of allowed content rules](#!/guide/dev_allowed_content_rules-section-object-format),
3616
+ * to specify `match` validator, your implementation could look like this:
3617
+ *
3618
+ * editor.widgets.add( 'customWidget', {
3619
+ * // ...
3620
+ *
3621
+ * styleToAllowedContentRules: funciton( style ) {
3622
+ * // Retrieve classes defined in the style.
3623
+ * var classes = style.getClassesArray();
3624
+ *
3625
+ * // Do something crazy - for example return allowed content rules in object format,
3626
+ * // with custom match property and propertiesOnly flag.
3627
+ * return {
3628
+ * h1: {
3629
+ * match: isWidgetElement,
3630
+ * propertiesOnly: true,
3631
+ * classes: classes
3632
+ * }
3633
+ * };
3634
+ * }
3635
+ * } );
3636
+ *
3637
+ * @since 4.4
3638
+ * @property {Function} styleToAllowedContentRules
3639
+ * @param {CKEDITOR.style.customHandlers.widget} style The style to be transformed.
3640
+ * @returns {CKEDITOR.filter.allowedContentRules}
3641
+ */
3642
+
3643
+ /**
3644
+ * This is an abstract class that describes the definition of a widget's nested editable.
3645
+ * It is a type of values in the {@link CKEDITOR.plugins.widget.definition#editables} object.
3646
+ *
3647
+ * In the simplest case the definition is a string which is a CSS selector used to
3648
+ * find an element that will become a nested editable inside the widget. Note that
3649
+ * the widget element can be a nested editable, too.
3650
+ *
3651
+ * In the more advanced case a definition is an object with a required `selector` property.
3652
+ *
3653
+ * editables: {
3654
+ * header: 'h1',
3655
+ * content: {
3656
+ * selector: 'div.content',
3657
+ * allowedContent: 'p strong em; a[!href]'
3658
+ * }
3659
+ * }
3660
+ *
3661
+ * @class CKEDITOR.plugins.widget.nestedEditable.definition
3662
+ * @abstract
3663
+ */
3664
+
3665
+ /**
3666
+ * The CSS selector used to find an element which will become a nested editable.
3667
+ *
3668
+ * @property {String} selector
3669
+ */
3670
+
3671
+ /**
3672
+ * The [Advanced Content Filter](#!/guide/dev_advanced_content_filter) rules
3673
+ * which will be used to limit the content allowed in this nested editable.
3674
+ * This option is similar to {@link CKEDITOR.config#allowedContent} and one can
3675
+ * use it to limit the editor features available in the nested editable.
3676
+ *
3677
+ * @property {CKEDITOR.filter.allowedContentRules} allowedContent
3678
+ */
3679
+
3680
+ /**
3681
+ * Nested editable name displayed in elements path.
3682
+ *
3683
+ * @property {String} pathName
3684
+ */