st-rich 1.5.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (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
+ */