radiant-ck_editor_filter-extension 0.2.8 → 0.2.9

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