qbrick 2.5.0.pre

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (297) hide show
  1. checksums.yaml +7 -0
  2. data/README.md +423 -0
  3. data/Rakefile +82 -0
  4. data/app/assets/javascripts/ckeditor/plugins/adv_link/LICENSE.txt +674 -0
  5. data/app/assets/javascripts/ckeditor/plugins/adv_link/README.md +62 -0
  6. data/app/assets/javascripts/ckeditor/plugins/adv_link/dialogs/anchor.js.coffee +81 -0
  7. data/app/assets/javascripts/ckeditor/plugins/adv_link/dialogs/link.js.coffee +1353 -0
  8. data/app/assets/javascripts/ckeditor/plugins/adv_link/images/anchor.png +0 -0
  9. data/app/assets/javascripts/ckeditor/plugins/adv_link/images/hidpi/anchor.png +0 -0
  10. data/app/assets/javascripts/ckeditor/plugins/adv_link/lang/de.js +68 -0
  11. data/app/assets/javascripts/ckeditor/plugins/adv_link/lang/en.js +68 -0
  12. data/app/assets/javascripts/ckeditor/plugins/adv_link/plugin.js.coffee +282 -0
  13. data/app/assets/javascripts/kuhsaft/application.js.coffee +7 -0
  14. data/app/assets/javascripts/kuhsaft/cms/application.js.coffee.erb +136 -0
  15. data/app/assets/javascripts/kuhsaft/views/read_more_view.js.coffee +17 -0
  16. data/app/assets/stylesheets/kuhsaft/application.css.sass +1 -0
  17. data/app/assets/stylesheets/kuhsaft/cms/application.css.sass +204 -0
  18. data/app/assets/stylesheets/kuhsaft/modules/_text_brick.css.sass +16 -0
  19. data/app/controllers/kuhsaft/api/pages_controller.rb +14 -0
  20. data/app/controllers/kuhsaft/cms/admin_controller.rb +18 -0
  21. data/app/controllers/kuhsaft/cms/assets_controller.rb +38 -0
  22. data/app/controllers/kuhsaft/cms/bricks_controller.rb +61 -0
  23. data/app/controllers/kuhsaft/cms/ckimages_controller.rb +26 -0
  24. data/app/controllers/kuhsaft/cms/pages_controller.rb +71 -0
  25. data/app/controllers/kuhsaft/pages_controller.rb +38 -0
  26. data/app/controllers/kuhsaft/sitemaps_controller.rb +12 -0
  27. data/app/helpers/cms_helper.rb +27 -0
  28. data/app/helpers/kuhsaft/admin_helper.rb +20 -0
  29. data/app/helpers/kuhsaft/cms/admin_helper.rb +21 -0
  30. data/app/helpers/kuhsaft/cms/pages_helper.rb +17 -0
  31. data/app/helpers/pages_helper.rb +49 -0
  32. data/app/helpers/sitemaps_helper.rb +12 -0
  33. data/app/models/kuhsaft/accordion_brick.rb +15 -0
  34. data/app/models/kuhsaft/accordion_item_brick.rb +21 -0
  35. data/app/models/kuhsaft/anchor_brick.rb +17 -0
  36. data/app/models/kuhsaft/asset.rb +29 -0
  37. data/app/models/kuhsaft/asset_brick.rb +26 -0
  38. data/app/models/kuhsaft/brick.rb +137 -0
  39. data/app/models/kuhsaft/brick_type.rb +7 -0
  40. data/app/models/kuhsaft/brick_type_filter.rb +18 -0
  41. data/app/models/kuhsaft/ckimage.rb +5 -0
  42. data/app/models/kuhsaft/cms.rb +7 -0
  43. data/app/models/kuhsaft/column_brick.rb +22 -0
  44. data/app/models/kuhsaft/image_brick.rb +16 -0
  45. data/app/models/kuhsaft/image_size.rb +51 -0
  46. data/app/models/kuhsaft/link_brick.rb +21 -0
  47. data/app/models/kuhsaft/page.rb +160 -0
  48. data/app/models/kuhsaft/page_type.rb +11 -0
  49. data/app/models/kuhsaft/partition.rb +18 -0
  50. data/app/models/kuhsaft/placeholder_brick.rb +23 -0
  51. data/app/models/kuhsaft/publish_state.rb +24 -0
  52. data/app/models/kuhsaft/slider_brick.rb +18 -0
  53. data/app/models/kuhsaft/text_brick.rb +23 -0
  54. data/app/models/kuhsaft/two_column_brick.rb +46 -0
  55. data/app/models/kuhsaft/video_brick.rb +22 -0
  56. data/app/uploaders/kuhsaft/asset_brick_asset_uploader.rb +43 -0
  57. data/app/uploaders/kuhsaft/asset_uploader.rb +50 -0
  58. data/app/uploaders/kuhsaft/ckimage_uploader.rb +16 -0
  59. data/app/uploaders/kuhsaft/image_brick_image_uploader.rb +35 -0
  60. data/app/views/kuhsaft/accordion_bricks/_accordion_brick.html.haml +3 -0
  61. data/app/views/kuhsaft/accordion_bricks/accordion_brick/_edit.html.haml +0 -0
  62. data/app/views/kuhsaft/accordion_item_bricks/_accordion_item_brick.html.haml +8 -0
  63. data/app/views/kuhsaft/accordion_item_bricks/accordion_item_brick/_edit.html.haml +1 -0
  64. data/app/views/kuhsaft/anchor_bricks/_anchor_brick.html.haml +1 -0
  65. data/app/views/kuhsaft/anchor_bricks/anchor_brick/_edit.html.haml +1 -0
  66. data/app/views/kuhsaft/asset_bricks/_asset_brick.html.haml +2 -0
  67. data/app/views/kuhsaft/asset_bricks/asset_brick/_edit.html.haml +8 -0
  68. data/app/views/kuhsaft/cms/admin/_brick_type_dropdown.html.haml +14 -0
  69. data/app/views/kuhsaft/cms/admin/_content_language_switch.html.haml +7 -0
  70. data/app/views/kuhsaft/cms/admin/_empty_state.html.haml +5 -0
  71. data/app/views/kuhsaft/cms/admin/_flash.html.haml +7 -0
  72. data/app/views/kuhsaft/cms/admin/_main_navigation.html.haml +6 -0
  73. data/app/views/kuhsaft/cms/assets/_form.html.haml +15 -0
  74. data/app/views/kuhsaft/cms/assets/_list.html.haml +11 -0
  75. data/app/views/kuhsaft/cms/assets/edit.html.haml +2 -0
  76. data/app/views/kuhsaft/cms/assets/index.html.haml +3 -0
  77. data/app/views/kuhsaft/cms/assets/new.html.haml +2 -0
  78. data/app/views/kuhsaft/cms/bricks/_brick_header.html.haml +43 -0
  79. data/app/views/kuhsaft/cms/bricks/_brick_item.html.haml +25 -0
  80. data/app/views/kuhsaft/cms/bricks/_brick_list.html.haml +4 -0
  81. data/app/views/kuhsaft/cms/bricks/_new.html.haml +41 -0
  82. data/app/views/kuhsaft/cms/bricks/_sort_form.html.haml +3 -0
  83. data/app/views/kuhsaft/cms/bricks/create.js.erb +11 -0
  84. data/app/views/kuhsaft/cms/bricks/destroy.js.erb +10 -0
  85. data/app/views/kuhsaft/cms/bricks/new.js.erb +14 -0
  86. data/app/views/kuhsaft/cms/bricks/update.js.erb +8 -0
  87. data/app/views/kuhsaft/cms/ckimages/create.html.haml +11 -0
  88. data/app/views/kuhsaft/cms/ckimages/destroy.js.erb +2 -0
  89. data/app/views/kuhsaft/cms/ckimages/index.html.haml +13 -0
  90. data/app/views/kuhsaft/cms/pages/_branch.html.haml +19 -0
  91. data/app/views/kuhsaft/cms/pages/_form.html.haml +45 -0
  92. data/app/views/kuhsaft/cms/pages/edit.html.haml +16 -0
  93. data/app/views/kuhsaft/cms/pages/index.html.haml +14 -0
  94. data/app/views/kuhsaft/cms/pages/new.html.haml +1 -0
  95. data/app/views/kuhsaft/cms/pages/show.html.haml +0 -0
  96. data/app/views/kuhsaft/cms/pages/sort.js.erb +0 -0
  97. data/app/views/kuhsaft/column_bricks/_column_brick.html.haml +3 -0
  98. data/app/views/kuhsaft/column_bricks/column_brick/_edit.html.haml +0 -0
  99. data/app/views/kuhsaft/image_bricks/_image_brick.html.haml +11 -0
  100. data/app/views/kuhsaft/image_bricks/image_brick/_edit.html.haml +13 -0
  101. data/app/views/kuhsaft/link_bricks/_link_brick.html.haml +2 -0
  102. data/app/views/kuhsaft/link_bricks/link_brick/_edit.html.haml +4 -0
  103. data/app/views/kuhsaft/pages/index.html.haml +7 -0
  104. data/app/views/kuhsaft/pages/show.html.haml +11 -0
  105. data/app/views/kuhsaft/placeholder_bricks/_placeholder_brick.html.haml +2 -0
  106. data/app/views/kuhsaft/placeholder_bricks/placeholder_brick/_edit.html.haml +1 -0
  107. data/app/views/kuhsaft/search/_form.html.haml +2 -0
  108. data/app/views/kuhsaft/search/_results.html.haml +8 -0
  109. data/app/views/kuhsaft/search/_results_entry.html.haml +13 -0
  110. data/app/views/kuhsaft/sitemaps/index.xml.haml +9 -0
  111. data/app/views/kuhsaft/slider_bricks/_slider_brick.html.haml +10 -0
  112. data/app/views/kuhsaft/slider_bricks/slider_brick/_edit.html.haml +0 -0
  113. data/app/views/kuhsaft/text_bricks/_text_brick.html.haml +11 -0
  114. data/app/views/kuhsaft/text_bricks/text_brick/_edit.html.haml +2 -0
  115. data/app/views/kuhsaft/two_column_bricks/_two_column_brick.html.haml +3 -0
  116. data/app/views/kuhsaft/two_column_bricks/two_column_brick/_childs.html.haml +5 -0
  117. data/app/views/kuhsaft/two_column_bricks/two_column_brick/_edit.html.haml +1 -0
  118. data/app/views/kuhsaft/video_bricks/_video_brick.html.haml +9 -0
  119. data/app/views/kuhsaft/video_bricks/video_brick/_edit.html.haml +8 -0
  120. data/app/views/layouts/kuhsaft/cms/application.html.haml +25 -0
  121. data/app/views/layouts/kuhsaft/cms/ckimages.html.haml +18 -0
  122. data/config/initializers/simple_form.rb +142 -0
  123. data/config/initializers/simple_form_bootstrap.rb +45 -0
  124. data/config/locales/de.yml +207 -0
  125. data/config/locales/en.yml +211 -0
  126. data/config/locales/models/kuhsaft/accordion_brick/de.yml +4 -0
  127. data/config/locales/models/kuhsaft/accordion_brick/en.yml +4 -0
  128. data/config/locales/models/kuhsaft/accordion_item_brick/de.yml +7 -0
  129. data/config/locales/models/kuhsaft/accordion_item_brick/en.yml +7 -0
  130. data/config/locales/models/kuhsaft/anchor_brick/de.yml +7 -0
  131. data/config/locales/models/kuhsaft/anchor_brick/en.yml +7 -0
  132. data/config/locales/models/kuhsaft/asset_brick/de.yml +9 -0
  133. data/config/locales/models/kuhsaft/asset_brick/en.yml +9 -0
  134. data/config/locales/models/kuhsaft/brick/de.yml +5 -0
  135. data/config/locales/models/kuhsaft/brick/en.yml +5 -0
  136. data/config/locales/models/kuhsaft/column_brick/de.yml +4 -0
  137. data/config/locales/models/kuhsaft/column_brick/en.yml +4 -0
  138. data/config/locales/models/kuhsaft/image_brick/de.yml +11 -0
  139. data/config/locales/models/kuhsaft/image_brick/en.yml +11 -0
  140. data/config/locales/models/kuhsaft/image_size/de.yml +13 -0
  141. data/config/locales/models/kuhsaft/image_size/en.yml +13 -0
  142. data/config/locales/models/kuhsaft/link_brick/de.yml +10 -0
  143. data/config/locales/models/kuhsaft/link_brick/en.yml +10 -0
  144. data/config/locales/models/kuhsaft/page/de.yml +19 -0
  145. data/config/locales/models/kuhsaft/page/en.yml +19 -0
  146. data/config/locales/models/kuhsaft/placeholder_brick/de.yml +8 -0
  147. data/config/locales/models/kuhsaft/placeholder_brick/en.yml +8 -0
  148. data/config/locales/models/kuhsaft/slider_brick/de.yml +4 -0
  149. data/config/locales/models/kuhsaft/slider_brick/en.yml +4 -0
  150. data/config/locales/models/kuhsaft/text_brick/de.yml +11 -0
  151. data/config/locales/models/kuhsaft/text_brick/en.yml +11 -0
  152. data/config/locales/models/kuhsaft/two_column_brick/de.yml +7 -0
  153. data/config/locales/models/kuhsaft/two_column_brick/en.yml +7 -0
  154. data/config/locales/models/kuhsaft/video_brick/de.yml +9 -0
  155. data/config/locales/models/kuhsaft/video_brick/en.yml +9 -0
  156. data/config/locales/simple_form.en.yml +26 -0
  157. data/config/locales/views/kuhsaft/cms/admin/de.yml +13 -0
  158. data/config/locales/views/kuhsaft/cms/admin/en.yml +12 -0
  159. data/config/locales/views/kuhsaft/cms/bricks/de.yml +18 -0
  160. data/config/locales/views/kuhsaft/cms/bricks/en.yml +18 -0
  161. data/config/locales/views/kuhsaft/cms/pages/de.yml +31 -0
  162. data/config/locales/views/kuhsaft/cms/pages/en.yml +31 -0
  163. data/config/locales/views/kuhsaft/image_brick/de.yml +6 -0
  164. data/config/locales/views/kuhsaft/image_brick/en.yml +6 -0
  165. data/config/locales/views/kuhsaft/search/de.yml +12 -0
  166. data/config/locales/views/kuhsaft/search/en.yml +12 -0
  167. data/config/locales/views/kuhsaft/text_brick/de.yml +6 -0
  168. data/config/locales/views/kuhsaft/text_brick/en.yml +6 -0
  169. data/config/locales/views/kuhsaft/video_brick/de.yml +7 -0
  170. data/config/locales/views/kuhsaft/video_brick/en.yml +7 -0
  171. data/config/routes.rb +30 -0
  172. data/db/migrate/01_create_kuhsaft_pages.rb +31 -0
  173. data/db/migrate/02_create_kuhsaft_bricks.rb +23 -0
  174. data/db/migrate/03_create_kuhsaft_brick_types.rb +12 -0
  175. data/db/migrate/04_create_kuhsaft_assets.rb +10 -0
  176. data/db/migrate/05_remove_cms_admin.rb +9 -0
  177. data/db/migrate/06_add_template_name_to_kuhsaft_bricks.rb +7 -0
  178. data/db/migrate/07_add_default_value_to_brick_type_enabled.rb +6 -0
  179. data/db/migrate/08_add_display_styles_to_bricks.rb +5 -0
  180. data/db/migrate/09_add_additional_fields_to_kuhsaft_bricks.rb +6 -0
  181. data/db/migrate/10_add_redirect_url_to_kuhsaft_pages.rb +7 -0
  182. data/db/migrate/11_update_url_and_redirect_url_value.rb +45 -0
  183. data/db/migrate/12_regenerate_fulltext.rb +12 -0
  184. data/db/migrate/13_add_page_title_to_pages.rb +7 -0
  185. data/db/migrate/14_move_kuhsaft_assets.rb +22 -0
  186. data/db/migrate/15_add_alt_text_to_bricks.rb +5 -0
  187. data/db/migrate/16_update_default_value_for_page_type.rb +9 -0
  188. data/db/migrate/17_set_page_type_to_content_for_empty_fields.rb +7 -0
  189. data/db/migrate/18_add_identifier_to_kuhsaft_pages.rb +6 -0
  190. data/db/migrate/19_add_col_count_to_bricks.rb +5 -0
  191. data/db/migrate/20_create_kuhsaft_ckimages.rb +9 -0
  192. data/db/seeds.rb +20 -0
  193. data/lib/generators/kuhsaft/assets/install_generator.rb +25 -0
  194. data/lib/generators/kuhsaft/translations/add_generator.rb +41 -0
  195. data/lib/kuhsaft.rb +22 -0
  196. data/lib/kuhsaft/brick_list.rb +87 -0
  197. data/lib/kuhsaft/engine.rb +27 -0
  198. data/lib/kuhsaft/gridded.rb +20 -0
  199. data/lib/kuhsaft/image_uploader_mounting.rb +22 -0
  200. data/lib/kuhsaft/orderable.rb +71 -0
  201. data/lib/kuhsaft/page_tree.rb +14 -0
  202. data/lib/kuhsaft/partial_extractor.rb +21 -0
  203. data/lib/kuhsaft/searchable.rb +69 -0
  204. data/lib/kuhsaft/touch_placeholders.rb +31 -0
  205. data/lib/kuhsaft/translatable.rb +54 -0
  206. data/lib/kuhsaft/version.rb +3 -0
  207. data/lib/tasks/kuhsaft_tasks.rake +22 -0
  208. data/lib/templates/kuhsaft/assets/ck-config.js.coffee +48 -0
  209. data/lib/templates/kuhsaft/assets/customizations.css.sass +0 -0
  210. data/lib/templates/kuhsaft/assets/customizations.js.coffee +0 -0
  211. data/lib/templates/kuhsaft/translations/add_translation.erb +8 -0
  212. data/spec/controllers/kuhsaft/api/pages_controller_spec.rb +70 -0
  213. data/spec/controllers/kuhsaft/pages_controller_spec.rb +90 -0
  214. data/spec/controllers/kuhsaft/sitemaps_controller_spec.rb +13 -0
  215. data/spec/dummy/Rakefile +7 -0
  216. data/spec/dummy/app/assets/images/spec-image.png +0 -0
  217. data/spec/dummy/app/assets/javascripts/application.js +15 -0
  218. data/spec/dummy/app/assets/javascripts/kuhsaft/cms/ck-config.js.coffee +48 -0
  219. data/spec/dummy/app/assets/javascripts/kuhsaft/cms/customizations.js.coffee +0 -0
  220. data/spec/dummy/app/assets/stylesheets/application.css +13 -0
  221. data/spec/dummy/app/assets/stylesheets/kuhsaft/cms/customizations.css.sass +0 -0
  222. data/spec/dummy/app/controllers/application_controller.rb +4 -0
  223. data/spec/dummy/app/helpers/application_helper.rb +2 -0
  224. data/spec/dummy/app/views/layouts/application.html.erb +14 -0
  225. data/spec/dummy/bin/bundle +3 -0
  226. data/spec/dummy/bin/rails +4 -0
  227. data/spec/dummy/bin/rake +4 -0
  228. data/spec/dummy/config.ru +4 -0
  229. data/spec/dummy/config/application.rb +26 -0
  230. data/spec/dummy/config/boot.rb +3 -0
  231. data/spec/dummy/config/database.yml +19 -0
  232. data/spec/dummy/config/environment.rb +5 -0
  233. data/spec/dummy/config/environments/development.rb +29 -0
  234. data/spec/dummy/config/environments/production.rb +81 -0
  235. data/spec/dummy/config/environments/test.rb +36 -0
  236. data/spec/dummy/config/initializers/backtrace_silencers.rb +7 -0
  237. data/spec/dummy/config/initializers/filter_parameter_logging.rb +4 -0
  238. data/spec/dummy/config/initializers/inflections.rb +16 -0
  239. data/spec/dummy/config/initializers/kuhsaft.rb +5 -0
  240. data/spec/dummy/config/initializers/mime_types.rb +5 -0
  241. data/spec/dummy/config/initializers/secret_token.rb +12 -0
  242. data/spec/dummy/config/initializers/session_store.rb +3 -0
  243. data/spec/dummy/config/initializers/wrap_parameters.rb +14 -0
  244. data/spec/dummy/config/locales/en.yml +23 -0
  245. data/spec/dummy/config/routes.rb +3 -0
  246. data/spec/dummy/db/.gitkeep +0 -0
  247. data/spec/dummy/lib/assets/.gitkeep +0 -0
  248. data/spec/dummy/log/.gitkeep +0 -0
  249. data/spec/dummy/public/404.html +26 -0
  250. data/spec/dummy/public/422.html +26 -0
  251. data/spec/dummy/public/500.html +25 -0
  252. data/spec/dummy/public/favicon.ico +0 -0
  253. data/spec/dummy/public/stylesheets/.gitkeep +0 -0
  254. data/spec/dummy/script/rails +6 -0
  255. data/spec/factories.rb +26 -0
  256. data/spec/features/cms_pages_spec.rb +76 -0
  257. data/spec/features/search_spec.rb +78 -0
  258. data/spec/helpers/kuhsaft/cms/admin_helper_spec.rb +25 -0
  259. data/spec/helpers/kuhsaft/cms/pages_helper_spec.rb +46 -0
  260. data/spec/helpers/kuhsaft/pages_helper_spec.rb +21 -0
  261. data/spec/kuhsaft_spec.rb +7 -0
  262. data/spec/lib/brick_list_spec.rb +50 -0
  263. data/spec/lib/engine_spec.rb +25 -0
  264. data/spec/lib/gridded_spec.rb +24 -0
  265. data/spec/lib/image_uploader_mounting_spec.rb +14 -0
  266. data/spec/lib/page_tree_spec.rb +38 -0
  267. data/spec/lib/searchable_spec.rb +30 -0
  268. data/spec/lib/touch_placeholders_spec.rb +44 -0
  269. data/spec/lib/translatable_spec.rb +155 -0
  270. data/spec/models/accordion_brick_spec.rb +38 -0
  271. data/spec/models/accordion_item_brick_spec.rb +50 -0
  272. data/spec/models/anchor_brick_spec.rb +26 -0
  273. data/spec/models/asset_brick_spec.rb +45 -0
  274. data/spec/models/asset_spec.rb +41 -0
  275. data/spec/models/brick_spec.rb +134 -0
  276. data/spec/models/brick_type_filter_spec.rb +64 -0
  277. data/spec/models/column_brick_spec.rb +32 -0
  278. data/spec/models/image_brick_spec.rb +49 -0
  279. data/spec/models/image_size_spec.rb +36 -0
  280. data/spec/models/link_brick_spec.rb +51 -0
  281. data/spec/models/page_spec.rb +472 -0
  282. data/spec/models/placeholder_brick_spec.rb +46 -0
  283. data/spec/models/publish_state_spec.rb +33 -0
  284. data/spec/models/slider_brick_spec.rb +26 -0
  285. data/spec/models/text_brick_spec.rb +30 -0
  286. data/spec/models/two_column_brick_spec.rb +82 -0
  287. data/spec/models/video_brick_spec.rb +32 -0
  288. data/spec/spec_helper.rb +81 -0
  289. data/spec/support/kuhsaft_spec_helper.rb +8 -0
  290. data/spec/support/write_expectation.rb +57 -0
  291. data/spec/views/kuhsaft/sitemaps/index.xml.haml_spec.rb +67 -0
  292. data/vendor/assets/javascripts/bootstrap-modal-v2.js +376 -0
  293. data/vendor/assets/javascripts/bootstrap-modalmanager.js +423 -0
  294. data/vendor/assets/javascripts/jquery.nestable.js +485 -0
  295. data/vendor/assets/stylesheets/bootstrap_modal.css +214 -0
  296. data/vendor/assets/stylesheets/nestable.css +84 -0
  297. metadata +870 -0
@@ -0,0 +1,62 @@
1
+ ckeditor-adv_link
2
+ =================
3
+
4
+ A CKEditor4 link plugin adding the ability to link to local (CMS) pages. Rely on jQuery for ajax calls (un-intrusive).
5
+ This implementation supports internationalisation (see below).
6
+
7
+
8
+ Disclaimer
9
+ ----------
10
+
11
+ I developed that script for my needs and inspired by this [blog post](http://blog.xoundboy.com/?p=393) and this StackOverflow [answer](http://stackoverflow.com/questions/5293920/ckeditor-dynamic-select-in-a-dialog). I want people to be able to use it but I don't pretend to do any support regarding installation or use. It works well with CKEditor v 4.2.2. You want to make it work with other versions? Just do it and share it back.
12
+
13
+
14
+ Enhancement
15
+ -----------
16
+
17
+ I really think it would be great to replace the select input by a list of links contained in a HTML div or even better an input text with ajax call (like in WP). I do not have time now to do that. If you want to involve yourself, you're more than welcome.
18
+
19
+
20
+ How to install it ?
21
+ --------------------
22
+
23
+ 1) Download and extract `adv_link` folder into CKEditor plugins folder
24
+
25
+ 2) Disable default link plugin and enable the new one. To do so, in your config.js file :
26
+
27
+ ```javascript
28
+ CKEDITOR.editorConfig = function( config )
29
+ {
30
+ // Define changes to default configuration here.
31
+
32
+ config.removePlugins = 'link';
33
+ config.extraPlugins = 'adv_link';
34
+
35
+ // whatever
36
+
37
+ };
38
+ ```
39
+
40
+ 3) In `dialogs/links.js` file, set the URL of the page which generates inputs to populate the plugin. It is located around line 377. A PHP script sample is given in `sample` folder and can be a good start.
41
+
42
+ 4) Test your installation by using the plugin.
43
+
44
+ 5) It should be working, adapt your script to get the rights inputs.
45
+
46
+ 6) If it does not work, use javascript debugging tool.
47
+
48
+
49
+ Internationalization ready
50
+ --------------------------
51
+
52
+ All languages are embedded in the source code. They are just copies of the default `link` plugin. But few of them are translated.
53
+
54
+ 3 new vars are defined in language files (at the top) :
55
+
56
+ ```javascript
57
+ localPages:'Local pages',
58
+ selectPageLabel:'Select a page',
59
+ selectPageTitle:'Select the page you want to link to',
60
+ ```
61
+
62
+ If you can't see them in the selected language file, you'll have to copy-paste from `en.js` file. Please, share your translation with others users.
@@ -0,0 +1,81 @@
1
+ #
2
+ # Copyright (c) 2003-2013, CKSource - Frederico Knabben. All rights reserved.
3
+ # For licensing, see LICENSE.md or http://ckeditor.com/license
4
+ #
5
+ CKEDITOR.dialog.add "anchor", (c) ->
6
+ d = (a) ->
7
+ @_.selectedElement = a
8
+ @setValueOf "info", "txtName", a.data("cke-saved-name") or ""
9
+ return
10
+
11
+ title: c.lang.link.anchor.title
12
+ minWidth: 300
13
+ minHeight: 60
14
+ onOk: ->
15
+ a = CKEDITOR.tools.trim(@getValueOf("info", "txtName"))
16
+ a =
17
+ id: a
18
+ name: a
19
+ "data-cke-saved-name": a
20
+
21
+ if @_.selectedElement
22
+ (if @_.selectedElement.data("cke-realelement") then (a = c.document.createElement("a",
23
+ attributes: a
24
+ )
25
+ c.createFakeElement(a, "cke_anchor", "anchor").replace(@_.selectedElement)
26
+ ) else @_.selectedElement.setAttributes(a))
27
+ else
28
+ b = c.getSelection()
29
+ b = b and b.getRanges()[0]
30
+ (if b.collapsed then (CKEDITOR.plugins.link.synAnchorSelector and (a["class"] = "cke_anchor_empty")
31
+ CKEDITOR.plugins.link.emptyAnchorFix and (a.contenteditable = "false"
32
+ a["data-cke-editable"] = 1
33
+ )
34
+ a = c.document.createElement("a",
35
+ attributes: a
36
+ )
37
+ CKEDITOR.plugins.link.fakeAnchor and (a = c.createFakeElement(a, "cke_anchor", "anchor"))
38
+ b.insertNode(a)
39
+ ) else (CKEDITOR.env.ie and 9 > CKEDITOR.env.version and (a["class"] = "cke_anchor")
40
+ a = new CKEDITOR.style(
41
+ element: "a"
42
+ attributes: a
43
+ )
44
+ a.type = CKEDITOR.STYLE_INLINE
45
+ c.applyStyle(a)
46
+ ))
47
+ return
48
+
49
+ onHide: ->
50
+ delete @_.selectedElement
51
+
52
+ return
53
+
54
+ onShow: ->
55
+ a = c.getSelection()
56
+ b = a.getSelectedElement()
57
+ if b
58
+ (if CKEDITOR.plugins.link.fakeAnchor then ((a = CKEDITOR.plugins.link.tryRestoreFakeAnchor(c, b)) and d.call(this, a)
59
+ @_.selectedElement = b
60
+ ) else b.is("a") and b.hasAttribute("name") and d.call(this, b))
61
+ else if b = CKEDITOR.plugins.link.getSelectedLink(c)
62
+ d.call(this, b)
63
+ a.selectElement(b)
64
+ @getContentElement("info", "txtName").focus()
65
+ return
66
+
67
+ contents: [
68
+ id: "info"
69
+ label: c.lang.link.anchor.title
70
+ accessKey: "I"
71
+ elements: [
72
+ type: "text"
73
+ id: "txtName"
74
+ label: c.lang.link.anchor.name
75
+ required: not 0
76
+ validate: ->
77
+ (if not @getValue() then (alert(c.lang.link.anchor.errorName)
78
+ not 1
79
+ ) else not 0)
80
+ ]
81
+ ]
@@ -0,0 +1,1353 @@
1
+ ###
2
+ @license Copyright (c) 2003-2013, CKSource - Frederico Knabben. All rights reserved.
3
+ For licensing, see LICENSE.md or http://ckeditor.com/license
4
+ ###
5
+
6
+ #
7
+ # Function to get current content locale
8
+ #
9
+ getParameterByName = (name, href) ->
10
+ name = name.replace(/[\[]/, "\\[").replace(/[\]]/, "\\]")
11
+ regexS = "[\\?&]" + name + "=([^&#]*)"
12
+ regex = new RegExp(regexS)
13
+ results = regex.exec(href)
14
+ unless results?
15
+ ""
16
+ else
17
+ decodeURIComponent results[1].replace(/\+/g, " ")
18
+
19
+ CKEDITOR.dialog.add "link", (editor) ->
20
+
21
+ unescapeSingleQuote = (str) ->
22
+ str.replace /\\'/g, "'"
23
+
24
+ escapeSingleQuote = (str) ->
25
+ str.replace /'/g, "\\$&"
26
+
27
+ # Compile the protection function pattern.
28
+ protectEmailLinkAsFunction = (email) ->
29
+ retval = undefined
30
+ name = compiledProtectionFunction.name
31
+ params = compiledProtectionFunction.params
32
+ paramName = undefined
33
+ paramValue = undefined
34
+ retval = [
35
+ name
36
+ "("
37
+ ]
38
+ i = 0
39
+
40
+ while i < params.length
41
+ paramName = params[i].toLowerCase()
42
+ paramValue = email[paramName]
43
+ i > 0 and retval.push(",")
44
+ retval.push "'", (if paramValue then escapeSingleQuote(encodeURIComponent(email[paramName])) else ""), "'"
45
+ i++
46
+ retval.push ")"
47
+ retval.join ""
48
+
49
+ protectEmailAddressAsEncodedString = (address) ->
50
+ charCode = undefined
51
+ length = address.length
52
+ encodedChars = []
53
+ i = 0
54
+
55
+ while i < length
56
+ charCode = address.charCodeAt(i)
57
+ encodedChars.push charCode
58
+ i++
59
+ "String.fromCharCode(" + encodedChars.join(",") + ")"
60
+
61
+ getLinkClass = (ele) ->
62
+ className = ele.getAttribute("class")
63
+ (if className then className.replace(/\s*(?:cke_anchor_empty|cke_anchor)(?:\s*$)?/g, "") else "")
64
+
65
+ plugin = CKEDITOR.plugins.link
66
+
67
+ targetChanged = ->
68
+ dialog = @getDialog()
69
+ popupFeatures = dialog.getContentElement("target", "popupFeatures")
70
+ targetName = dialog.getContentElement("target", "linkTargetName")
71
+ value = @getValue()
72
+ return if not popupFeatures or not targetName
73
+ popupFeatures = popupFeatures.getElement()
74
+ popupFeatures.hide()
75
+ targetName.setValue ""
76
+ switch value
77
+ when "frame"
78
+ targetName.setLabel editor.lang.link.targetFrameName
79
+ targetName.getElement().show()
80
+ when "popup"
81
+ popupFeatures.show()
82
+ targetName.setLabel editor.lang.link.targetPopupName
83
+ targetName.getElement().show()
84
+ else
85
+ targetName.setValue value
86
+ targetName.getElement().hide()
87
+
88
+ # Handles the event when the "Target" selection box is changed.
89
+ linkTypeChanged = ->
90
+ dialog = @getDialog()
91
+ partIds = [
92
+ "urlOptions"
93
+ "localPageOptions"
94
+ "anchorOptions"
95
+ "emailOptions"
96
+ ]
97
+ typeValue = @getValue()
98
+ uploadTab = dialog.definition.getContents("upload")
99
+ uploadInitiallyHidden = uploadTab and uploadTab.hidden
100
+ if typeValue is "url"
101
+ dialog.showPage "target" if editor.config.linkShowTargetTab
102
+ dialog.showPage "upload" unless uploadInitiallyHidden
103
+ else
104
+ dialog.hidePage "target"
105
+ dialog.hidePage "upload" unless uploadInitiallyHidden
106
+ i = 0
107
+
108
+ while i < partIds.length
109
+ element = dialog.getContentElement("info", partIds[i])
110
+ continue unless element
111
+ element = element.getElement().getParent().getParent()
112
+ if partIds[i] is typeValue + "Options"
113
+ element.show()
114
+ else
115
+ element.hide()
116
+ i++
117
+ dialog.layout()
118
+ return
119
+
120
+ javascriptProtocolRegex = /^javascript:/
121
+ emailRegex = /^mailto:([^?]+)(?:\?(.+))?$/
122
+ emailSubjectRegex = /subject=([^;?:@&=$,\/]*)/
123
+ emailBodyRegex = /body=([^;?:@&=$,\/]*)/
124
+ anchorRegex = /^#(.*)$/
125
+ urlRegex = /^((?:http|https|ftp|news):\/\/)?(.*)$/
126
+ selectableTargets = /^(_(?:self|top|parent|blank))$/
127
+ encodedEmailLinkRegex = /^javascript:void\(location\.href='mailto:'\+String\.fromCharCode\(([^)]+)\)(?:\+'(.*)')?\)$/
128
+ functionCallProtectedEmailLinkRegex = /^javascript:([^(]+)\(([^)]+)\)$/
129
+ popupRegex = /\s*window.open\(\s*this\.href\s*,\s*(?:'([^']*)'|null)\s*,\s*'([^']*)'\s*\)\s*;\s*return\s*false;*\s*/
130
+ popupFeaturesRegex = /(?:^|,)([^=]+)=(\d+|yes|no)/g
131
+ parseLink = (editor, element) ->
132
+ href = (element and (element.data("cke-saved-href") or element.getAttribute("href"))) or ""
133
+ javascriptMatch = undefined
134
+ emailMatch = undefined
135
+ anchorMatch = undefined
136
+ urlMatch = undefined
137
+ retval = {}
138
+ if javascriptMatch = href.match(javascriptProtocolRegex)
139
+ if emailProtection is "encode"
140
+ href = href.replace(encodedEmailLinkRegex, (match, protectedAddress, rest) ->
141
+ "mailto:" + String.fromCharCode.apply(String, protectedAddress.split(",")) + (rest and unescapeSingleQuote(rest))
142
+ )
143
+ else if emailProtection
144
+ href.replace functionCallProtectedEmailLinkRegex, (match, funcName, funcArgs) ->
145
+ if funcName is compiledProtectionFunction.name
146
+ retval.type = "email"
147
+ email = retval.email = {}
148
+ paramRegex = /[^,\s]+/g
149
+ paramQuoteRegex = /(^')|('$)/g
150
+ paramsMatch = funcArgs.match(paramRegex)
151
+ paramsMatchLength = paramsMatch.length
152
+ paramName = undefined
153
+ paramVal = undefined
154
+ i = 0
155
+
156
+ while i < paramsMatchLength
157
+ paramVal = decodeURIComponent(unescapeSingleQuote(paramsMatch[i].replace(paramQuoteRegex, "")))
158
+ paramName = compiledProtectionFunction.params[i].toLowerCase()
159
+ email[paramName] = paramVal
160
+ i++
161
+ email.address = [
162
+ email.name
163
+ email.domain
164
+ ].join("@")
165
+ return
166
+
167
+ unless retval.type
168
+ if anchorMatch = href.match(anchorRegex)
169
+ retval.type = "anchor"
170
+ retval.anchor = {}
171
+ retval.anchor.name = retval.anchor.id = anchorMatch[1]
172
+ else if emailMatch = href.match(emailRegex)
173
+ subjectMatch = href.match(emailSubjectRegex)
174
+ bodyMatch = href.match(emailBodyRegex)
175
+ retval.type = "email"
176
+ email = (retval.email = {})
177
+ email.address = emailMatch[1]
178
+ subjectMatch and (email.subject = decodeURIComponent(subjectMatch[1]))
179
+ bodyMatch and (email.body = decodeURIComponent(bodyMatch[1]))
180
+ else if href and (urlMatch = href.match(urlRegex))
181
+ retval.type = "url"
182
+ retval.url = {}
183
+ retval.url.protocol = urlMatch[1]
184
+ retval.url.url = urlMatch[2]
185
+ else
186
+ retval.type = "url"
187
+ if element
188
+ target = element.getAttribute("target")
189
+ retval.target = {}
190
+ retval.adv = {}
191
+ unless target
192
+ onclick = element.data("cke-pa-onclick") or element.getAttribute("onclick")
193
+ onclickMatch = onclick and onclick.match(popupRegex)
194
+ if onclickMatch
195
+ retval.target.type = "popup"
196
+ retval.target.name = onclickMatch[1]
197
+ featureMatch = undefined
198
+ while (featureMatch = popupFeaturesRegex.exec(onclickMatch[2]))
199
+ if (featureMatch[2] is "yes" or featureMatch[2] is "1") and (featureMatch[1] of
200
+ height: 1
201
+ width: 1
202
+ top: 1
203
+ left: 1
204
+ )
205
+ retval.target[featureMatch[1]] = true
206
+ else retval.target[featureMatch[1]] = featureMatch[2] if isFinite(featureMatch[2])
207
+ else
208
+ targetMatch = target.match(selectableTargets)
209
+ if targetMatch
210
+ retval.target.type = retval.target.name = target
211
+ else
212
+ retval.target.type = "frame"
213
+ retval.target.name = target
214
+ me = this
215
+ advAttr = (inputName, attrName) ->
216
+ value = element.getAttribute(attrName)
217
+ retval.adv[inputName] = value or "" if value isnt null
218
+ return
219
+
220
+ advAttr "advId", "id"
221
+ advAttr "advLangDir", "dir"
222
+ advAttr "advAccessKey", "accessKey"
223
+ retval.adv.advName = element.data("cke-saved-name") or element.getAttribute("name") or ""
224
+ advAttr "advLangCode", "lang"
225
+ advAttr "advTabIndex", "tabindex"
226
+ advAttr "advTitle", "title"
227
+ advAttr "advContentType", "type"
228
+ (if CKEDITOR.plugins.link.synAnchorSelector then retval.adv.advCSSClasses = getLinkClass(element) else advAttr("advCSSClasses", "class"))
229
+ advAttr "advCharset", "charset"
230
+ advAttr "advStyles", "style"
231
+ advAttr "advRel", "rel"
232
+ anchors = retval.anchors = []
233
+ i = undefined
234
+ count = undefined
235
+ item = undefined
236
+ if CKEDITOR.plugins.link.emptyAnchorFix
237
+ links = editor.document.getElementsByTag("a")
238
+ i = 0
239
+ count = links.count()
240
+
241
+ while i < count
242
+ item = links.getItem(i)
243
+ if item.data("cke-saved-name") or item.hasAttribute("name")
244
+ anchors.push
245
+ name: item.data("cke-saved-name") or item.getAttribute("name")
246
+ id: item.getAttribute("id")
247
+
248
+ i++
249
+ else
250
+ anchorList = new CKEDITOR.dom.nodeList(editor.document.$.anchors)
251
+ i = 0
252
+ count = anchorList.count()
253
+
254
+ while i < count
255
+ item = anchorList.getItem(i)
256
+ anchors[i] =
257
+ name: item.getAttribute("name")
258
+ id: item.getAttribute("id")
259
+ i++
260
+ if CKEDITOR.plugins.link.fakeAnchor
261
+ imgs = editor.document.getElementsByTag("img")
262
+ i = 0
263
+ count = imgs.count()
264
+
265
+ while i < count
266
+ if item = CKEDITOR.plugins.link.tryRestoreFakeAnchor(editor, imgs.getItem(i))
267
+ anchors.push
268
+ name: item.getAttribute("name")
269
+ id: item.getAttribute("id")
270
+
271
+ i++
272
+ @_.selectedElement = element
273
+ retval
274
+
275
+ setupParams = (page, data) ->
276
+ @setValue data[page][@id] or "" if data[page]
277
+ return
278
+
279
+ setupPopupParams = (data) ->
280
+ setupParams.call this, "target", data
281
+
282
+ setupAdvParams = (data) ->
283
+ setupParams.call this, "adv", data
284
+
285
+ commitParams = (page, data) ->
286
+ data[page] = {} unless data[page]
287
+ data[page][@id] = @getValue() or ""
288
+ return
289
+
290
+ commitPopupParams = (data) ->
291
+ commitParams.call this, "target", data
292
+
293
+ commitAdvParams = (data) ->
294
+ commitParams.call this, "adv", data
295
+
296
+ emailProtection = editor.config.emailProtection or ""
297
+ if emailProtection and emailProtection isnt "encode"
298
+ compiledProtectionFunction = {}
299
+ emailProtection.replace /^([^(]+)\(([^)]+)\)$/, (match, funcName, params) ->
300
+ compiledProtectionFunction.name = funcName
301
+ compiledProtectionFunction.params = []
302
+ params.replace /[^,\s]+/g, (param) ->
303
+ compiledProtectionFunction.params.push param
304
+ return
305
+
306
+ return
307
+
308
+ commonLang = editor.lang.common
309
+ linkLang = editor.lang.adv_link # modified by simo
310
+ title: linkLang.title
311
+ minWidth: 350
312
+ minHeight: 230
313
+ contents: [
314
+ {
315
+ id: "info"
316
+ label: linkLang.info
317
+ title: linkLang.info
318
+ elements: [
319
+ {
320
+ id: "linkType"
321
+ type: "select"
322
+ label: linkLang.type
323
+ default: "url"
324
+ items: [
325
+ [
326
+ linkLang.toUrl
327
+ "url"
328
+ ]
329
+ [ # added by @simo - http://blog.xoundboy.com/?p=393
330
+ linkLang.localPages
331
+ "localPage"
332
+ ]
333
+ [
334
+ linkLang.toAnchor
335
+ "anchor"
336
+ ]
337
+ [
338
+ linkLang.toEmail
339
+ "email"
340
+ ]
341
+ ]
342
+ onChange: linkTypeChanged
343
+ setup: (data) ->
344
+ @setValue data.type if data.type
345
+ return
346
+
347
+ commit: (data) ->
348
+ data.type = @getValue()
349
+ return
350
+ }
351
+ {
352
+
353
+ # added by @simo - http://blog.xoundboy.com/?p=393
354
+ # see also : http://docs.ckeditor.com/source/dialogDefinition.html#CKEDITOR-dialog-definition-uiElement-property-type
355
+ # http://docs.ckeditor.com/#!/guide/plugin_sdk_sample_1
356
+ type: "vbox"
357
+ id: "localPageOptions"
358
+ children: [
359
+ type: "select"
360
+ label: linkLang.selectPageLabel
361
+ id: "localPage"
362
+ title: linkLang.selectPageTitle
363
+
364
+ # items: eval(decodeURIComponent(document.getElementById("pageListJSON").value)),
365
+ items: []
366
+ onLoad: (element) ->
367
+ element_id = "#" + @getInputElement().$.id
368
+
369
+ # ajax call indpired from http://stackoverflow.com/questions/5293920/ckeditor-dynamic-select-in-a-dialog
370
+ $.ajax
371
+ type: "GET"
372
+
373
+ #contentType: 'application/json; charset=utf-8',
374
+ url: "/" + getParameterByName("content_locale", document.location.href) + "/api/pages.json"
375
+ dataType: "json"
376
+ async: false
377
+ success: (data) ->
378
+ $.each data, (index, item) ->
379
+ $(element_id).get(0).options[$(element_id).get(0).options.length] = new Option(decodeURIComponent(item.title) + ': ' + item.pretty_url, item.url)
380
+ return
381
+
382
+ return
383
+
384
+ error: (xhr, ajaxOptions, thrownError) ->
385
+ alert xhr.status
386
+ alert thrownError
387
+ return
388
+
389
+ return
390
+
391
+ commit: (data) ->
392
+ data.localPage = {} unless data.localPage
393
+ data.localPage = @getValue()
394
+ return
395
+ ]
396
+ }
397
+ {
398
+
399
+ # added by @simo - end
400
+ type: "vbox"
401
+ id: "urlOptions"
402
+ children: [
403
+ {
404
+ type: "hbox"
405
+ widths: [
406
+ "25%"
407
+ "75%"
408
+ ]
409
+ children: [
410
+ {
411
+ id: "protocol"
412
+ type: "select"
413
+ label: commonLang.protocol
414
+ default: "http://"
415
+ items: [
416
+
417
+ # Force 'ltr' for protocol names in BIDI. (#5433)
418
+ [
419
+ "http://‎"
420
+ "http://"
421
+ ]
422
+ [
423
+ "https://‎"
424
+ "https://"
425
+ ]
426
+ [
427
+ "ftp://‎"
428
+ "ftp://"
429
+ ]
430
+ [
431
+ "news://‎"
432
+ "news://"
433
+ ]
434
+ [
435
+ linkLang.other
436
+ ""
437
+ ]
438
+ ]
439
+ setup: (data) ->
440
+ @setValue data.url.protocol or "" if data.url
441
+ return
442
+
443
+ commit: (data) ->
444
+ data.url = {} unless data.url
445
+ data.url.protocol = @getValue()
446
+ return
447
+ }
448
+ {
449
+ type: "text"
450
+ id: "url"
451
+ label: commonLang.url
452
+ required: true
453
+ onLoad: ->
454
+ @allowOnChange = true
455
+ return
456
+
457
+ onKeyUp: ->
458
+ @allowOnChange = false
459
+ protocolCmb = @getDialog().getContentElement("info", "protocol")
460
+ url = @getValue()
461
+ urlOnChangeProtocol = /^(http|https|ftp|news):\/\/(?=.)/i
462
+ urlOnChangeTestOther = /^((javascript:)|[#\/\.\?])/i
463
+ protocol = urlOnChangeProtocol.exec(url)
464
+ if protocol
465
+ @setValue url.substr(protocol[0].length)
466
+ protocolCmb.setValue protocol[0].toLowerCase()
467
+ else protocolCmb.setValue "" if urlOnChangeTestOther.test(url)
468
+ @allowOnChange = true
469
+ return
470
+
471
+ onChange: ->
472
+ # Dont't call on dialog load.
473
+ @onKeyUp() if @allowOnChange
474
+ return
475
+
476
+ validate: ->
477
+ dialog = @getDialog()
478
+ return true if dialog.getContentElement("info", "linkType") and dialog.getValueOf("info", "linkType") isnt "url"
479
+ if (/javascript\:/).test(@getValue())
480
+ alert commonLang.invalidValue
481
+ return false
482
+ # Edit Anchor.
483
+ return true if @getDialog().fakeObj
484
+ func = CKEDITOR.dialog.validate.notEmpty(linkLang.noUrl)
485
+ func.apply this
486
+
487
+ setup: (data) ->
488
+ @allowOnChange = false
489
+ @setValue data.url.url if data.url
490
+ @allowOnChange = true
491
+ return
492
+
493
+ commit: (data) ->
494
+
495
+ # IE will not trigger the onChange event if the mouse has been used
496
+ # to carry all the operations #4724
497
+ @onChange()
498
+ data.url = {} unless data.url
499
+ data.url.url = @getValue()
500
+ @allowOnChange = false
501
+ return
502
+ }
503
+ ]
504
+ setup: (data) ->
505
+ @getElement().show() unless @getDialog().getContentElement("info", "linkType")
506
+ return
507
+ }
508
+ {
509
+ type: "button"
510
+ id: "browse"
511
+ hidden: "true"
512
+ filebrowser: "info:url"
513
+ label: commonLang.browseServer
514
+ }
515
+ ]
516
+ }
517
+ {
518
+ type: "vbox"
519
+ id: "anchorOptions"
520
+ width: 260
521
+ align: "center"
522
+ padding: 0
523
+ children: [
524
+ {
525
+ type: "fieldset"
526
+ id: "selectAnchorText"
527
+ label: linkLang.selectAnchor
528
+ setup: (data) ->
529
+ if data.anchors.length > 0
530
+ @getElement().show()
531
+ else
532
+ @getElement().hide()
533
+ return
534
+
535
+ children: [
536
+ type: "hbox"
537
+ id: "selectAnchor"
538
+ children: [
539
+ {
540
+ type: "select"
541
+ id: "anchorName"
542
+ default: ""
543
+ label: linkLang.anchorName
544
+ style: "width: 100%;"
545
+ items: [[""]]
546
+ setup: (data) ->
547
+ @clear()
548
+ @add ""
549
+ i = 0
550
+
551
+ while i < data.anchors.length
552
+ @add data.anchors[i].name if data.anchors[i].name
553
+ i++
554
+ @setValue data.anchor.name if data.anchor
555
+ linkType = @getDialog().getContentElement("info", "linkType")
556
+ @focus() if linkType and linkType.getValue() is "email"
557
+ return
558
+
559
+ commit: (data) ->
560
+ data.anchor = {} unless data.anchor
561
+ data.anchor.name = @getValue()
562
+ return
563
+ }
564
+ {
565
+ type: "select"
566
+ id: "anchorId"
567
+ default: ""
568
+ label: linkLang.anchorId
569
+ style: "width: 100%;"
570
+ items: [[""]]
571
+ setup: (data) ->
572
+ @clear()
573
+ @add ""
574
+ i = 0
575
+
576
+ while i < data.anchors.length
577
+ @add data.anchors[i].id if data.anchors[i].id
578
+ i++
579
+ @setValue data.anchor.id if data.anchor
580
+ return
581
+
582
+ commit: (data) ->
583
+ data.anchor = {} unless data.anchor
584
+ data.anchor.id = @getValue()
585
+ return
586
+ }
587
+ ]
588
+ setup: (data) ->
589
+ if data.anchors.length > 0
590
+ @getElement().show()
591
+ else
592
+ @getElement().hide()
593
+ return
594
+ ]
595
+ }
596
+ {
597
+ type: "html"
598
+ id: "noAnchors"
599
+ style: "text-align: center;"
600
+ html: "<div role=\"note\" tabIndex=\"-1\">" + CKEDITOR.tools.htmlEncode(linkLang.noAnchors) + "</div>"
601
+
602
+ # Focus the first element defined in above html.
603
+ focus: true
604
+ setup: (data) ->
605
+ if data.anchors.length < 1
606
+ @getElement().show()
607
+ else
608
+ @getElement().hide()
609
+ return
610
+ }
611
+ ]
612
+ setup: (data) ->
613
+ @getElement().hide() unless @getDialog().getContentElement("info", "linkType")
614
+ return
615
+ }
616
+ {
617
+ type: "vbox"
618
+ id: "emailOptions"
619
+ padding: 1
620
+ children: [
621
+ {
622
+ type: "text"
623
+ id: "emailAddress"
624
+ label: linkLang.emailAddress
625
+ required: true
626
+ validate: ->
627
+ dialog = @getDialog()
628
+ return true if not dialog.getContentElement("info", "linkType") or dialog.getValueOf("info", "linkType") isnt "email"
629
+ func = CKEDITOR.dialog.validate.notEmpty(linkLang.noEmail)
630
+ func.apply this
631
+
632
+ setup: (data) ->
633
+ @setValue data.email.address if data.email
634
+ linkType = @getDialog().getContentElement("info", "linkType")
635
+ @select() if linkType and linkType.getValue() is "email"
636
+ return
637
+
638
+ commit: (data) ->
639
+ data.email = {} unless data.email
640
+ data.email.address = @getValue()
641
+ return
642
+ }
643
+ {
644
+ type: "text"
645
+ id: "emailSubject"
646
+ label: linkLang.emailSubject
647
+ setup: (data) ->
648
+ @setValue data.email.subject if data.email
649
+ return
650
+
651
+ commit: (data) ->
652
+ data.email = {} unless data.email
653
+ data.email.subject = @getValue()
654
+ return
655
+ }
656
+ {
657
+ type: "textarea"
658
+ id: "emailBody"
659
+ label: linkLang.emailBody
660
+ rows: 3
661
+ default: ""
662
+ setup: (data) ->
663
+ @setValue data.email.body if data.email
664
+ return
665
+
666
+ commit: (data) ->
667
+ data.email = {} unless data.email
668
+ data.email.body = @getValue()
669
+ return
670
+ }
671
+ ]
672
+ setup: (data) ->
673
+ @getElement().hide() unless @getDialog().getContentElement("info", "linkType")
674
+ return
675
+ }
676
+ ]
677
+ }
678
+ {
679
+ id: "target"
680
+ requiredContent: "a[target]" # This is not fully correct, because some target option requires JS.
681
+ label: linkLang.target
682
+ title: linkLang.target
683
+ elements: [
684
+ {
685
+ type: "hbox"
686
+ widths: [
687
+ "50%"
688
+ "50%"
689
+ ]
690
+ children: [
691
+ {
692
+ type: "select"
693
+ id: "linkTargetType"
694
+ label: commonLang.target
695
+ default: "notSet"
696
+ style: "width : 100%;"
697
+ items: [
698
+ [
699
+ commonLang.notSet
700
+ "notSet"
701
+ ]
702
+ [
703
+ linkLang.targetFrame
704
+ "frame"
705
+ ]
706
+ [
707
+ linkLang.targetPopup
708
+ "popup"
709
+ ]
710
+ [
711
+ commonLang.targetNew
712
+ "_blank"
713
+ ]
714
+ [
715
+ commonLang.targetTop
716
+ "_top"
717
+ ]
718
+ [
719
+ commonLang.targetSelf
720
+ "_self"
721
+ ]
722
+ [
723
+ commonLang.targetParent
724
+ "_parent"
725
+ ]
726
+ ]
727
+ onChange: targetChanged
728
+ setup: (data) ->
729
+ @setValue data.target.type or "notSet" if data.target
730
+ targetChanged.call this
731
+ return
732
+
733
+ commit: (data) ->
734
+ data.target = {} unless data.target
735
+ data.target.type = @getValue()
736
+ return
737
+ }
738
+ {
739
+ type: "text"
740
+ id: "linkTargetName"
741
+ label: linkLang.targetFrameName
742
+ default: ""
743
+ setup: (data) ->
744
+ @setValue data.target.name if data.target
745
+ return
746
+
747
+ commit: (data) ->
748
+ data.target = {} unless data.target
749
+ data.target.name = @getValue().replace(/\W/g, "")
750
+ return
751
+ }
752
+ ]
753
+ }
754
+ {
755
+ type: "vbox"
756
+ width: "100%"
757
+ align: "center"
758
+ padding: 2
759
+ id: "popupFeatures"
760
+ children: [
761
+ type: "fieldset"
762
+ label: linkLang.popupFeatures
763
+ children: [
764
+ {
765
+ type: "hbox"
766
+ children: [
767
+ {
768
+ type: "checkbox"
769
+ id: "resizable"
770
+ label: linkLang.popupResizable
771
+ setup: setupPopupParams
772
+ commit: commitPopupParams
773
+ }
774
+ {
775
+ type: "checkbox"
776
+ id: "status"
777
+ label: linkLang.popupStatusBar
778
+ setup: setupPopupParams
779
+ commit: commitPopupParams
780
+ }
781
+ ]
782
+ }
783
+ {
784
+ type: "hbox"
785
+ children: [
786
+ {
787
+ type: "checkbox"
788
+ id: "location"
789
+ label: linkLang.popupLocationBar
790
+ setup: setupPopupParams
791
+ commit: commitPopupParams
792
+ }
793
+ {
794
+ type: "checkbox"
795
+ id: "toolbar"
796
+ label: linkLang.popupToolbar
797
+ setup: setupPopupParams
798
+ commit: commitPopupParams
799
+ }
800
+ ]
801
+ }
802
+ {
803
+ type: "hbox"
804
+ children: [
805
+ {
806
+ type: "checkbox"
807
+ id: "menubar"
808
+ label: linkLang.popupMenuBar
809
+ setup: setupPopupParams
810
+ commit: commitPopupParams
811
+ }
812
+ {
813
+ type: "checkbox"
814
+ id: "fullscreen"
815
+ label: linkLang.popupFullScreen
816
+ setup: setupPopupParams
817
+ commit: commitPopupParams
818
+ }
819
+ ]
820
+ }
821
+ {
822
+ type: "hbox"
823
+ children: [
824
+ {
825
+ type: "checkbox"
826
+ id: "scrollbars"
827
+ label: linkLang.popupScrollBars
828
+ setup: setupPopupParams
829
+ commit: commitPopupParams
830
+ }
831
+ {
832
+ type: "checkbox"
833
+ id: "dependent"
834
+ label: linkLang.popupDependent
835
+ setup: setupPopupParams
836
+ commit: commitPopupParams
837
+ }
838
+ ]
839
+ }
840
+ {
841
+ type: "hbox"
842
+ children: [
843
+ {
844
+ type: "text"
845
+ widths: [
846
+ "50%"
847
+ "50%"
848
+ ]
849
+ labelLayout: "horizontal"
850
+ label: commonLang.width
851
+ id: "width"
852
+ setup: setupPopupParams
853
+ commit: commitPopupParams
854
+ }
855
+ {
856
+ type: "text"
857
+ labelLayout: "horizontal"
858
+ widths: [
859
+ "50%"
860
+ "50%"
861
+ ]
862
+ label: linkLang.popupLeft
863
+ id: "left"
864
+ setup: setupPopupParams
865
+ commit: commitPopupParams
866
+ }
867
+ ]
868
+ }
869
+ {
870
+ type: "hbox"
871
+ children: [
872
+ {
873
+ type: "text"
874
+ labelLayout: "horizontal"
875
+ widths: [
876
+ "50%"
877
+ "50%"
878
+ ]
879
+ label: commonLang.height
880
+ id: "height"
881
+ setup: setupPopupParams
882
+ commit: commitPopupParams
883
+ }
884
+ {
885
+ type: "text"
886
+ labelLayout: "horizontal"
887
+ label: linkLang.popupTop
888
+ widths: [
889
+ "50%"
890
+ "50%"
891
+ ]
892
+ id: "top"
893
+ setup: setupPopupParams
894
+ commit: commitPopupParams
895
+ }
896
+ ]
897
+ }
898
+ ]
899
+ ]
900
+ }
901
+ ]
902
+ }
903
+ {
904
+ id: "upload"
905
+ label: linkLang.upload
906
+ title: linkLang.upload
907
+ hidden: true
908
+ filebrowser: "uploadButton"
909
+ elements: [
910
+ {
911
+ type: "file"
912
+ id: "upload"
913
+ label: commonLang.upload
914
+ style: "height:40px"
915
+ size: 29
916
+ }
917
+ {
918
+ type: "fileButton"
919
+ id: "uploadButton"
920
+ label: commonLang.uploadSubmit
921
+ filebrowser: "info:url"
922
+ for: [
923
+ "upload"
924
+ "upload"
925
+ ]
926
+ }
927
+ ]
928
+ }
929
+ {
930
+ id: "advanced"
931
+ label: linkLang.advanced
932
+ title: linkLang.advanced
933
+ elements: [
934
+ {
935
+ type: "vbox"
936
+ padding: 1
937
+ children: [
938
+ {
939
+ type: "hbox"
940
+ widths: [
941
+ "45%"
942
+ "35%"
943
+ "20%"
944
+ ]
945
+ children: [
946
+ {
947
+ type: "text"
948
+ id: "advId"
949
+ requiredContent: "a[id]"
950
+ label: linkLang.id
951
+ setup: setupAdvParams
952
+ commit: commitAdvParams
953
+ }
954
+ {
955
+ type: "select"
956
+ id: "advLangDir"
957
+ requiredContent: "a[dir]"
958
+ label: linkLang.langDir
959
+ default: ""
960
+ style: "width:110px"
961
+ items: [
962
+ [
963
+ commonLang.notSet
964
+ ""
965
+ ]
966
+ [
967
+ linkLang.langDirLTR
968
+ "ltr"
969
+ ]
970
+ [
971
+ linkLang.langDirRTL
972
+ "rtl"
973
+ ]
974
+ ]
975
+ setup: setupAdvParams
976
+ commit: commitAdvParams
977
+ }
978
+ {
979
+ type: "text"
980
+ id: "advAccessKey"
981
+ requiredContent: "a[accesskey]"
982
+ width: "80px"
983
+ label: linkLang.acccessKey
984
+ maxLength: 1
985
+ setup: setupAdvParams
986
+ commit: commitAdvParams
987
+ }
988
+ ]
989
+ }
990
+ {
991
+ type: "hbox"
992
+ widths: [
993
+ "45%"
994
+ "35%"
995
+ "20%"
996
+ ]
997
+ children: [
998
+ {
999
+ type: "text"
1000
+ label: linkLang.name
1001
+ id: "advName"
1002
+ requiredContent: "a[name]"
1003
+ setup: setupAdvParams
1004
+ commit: commitAdvParams
1005
+ }
1006
+ {
1007
+ type: "text"
1008
+ label: linkLang.langCode
1009
+ id: "advLangCode"
1010
+ requiredContent: "a[lang]"
1011
+ width: "110px"
1012
+ default: ""
1013
+ setup: setupAdvParams
1014
+ commit: commitAdvParams
1015
+ }
1016
+ {
1017
+ type: "text"
1018
+ label: linkLang.tabIndex
1019
+ id: "advTabIndex"
1020
+ requiredContent: "a[tabindex]"
1021
+ width: "80px"
1022
+ maxLength: 5
1023
+ setup: setupAdvParams
1024
+ commit: commitAdvParams
1025
+ }
1026
+ ]
1027
+ }
1028
+ ]
1029
+ }
1030
+ {
1031
+ type: "vbox"
1032
+ padding: 1
1033
+ children: [
1034
+ {
1035
+ type: "hbox"
1036
+ widths: [
1037
+ "45%"
1038
+ "55%"
1039
+ ]
1040
+ children: [
1041
+ {
1042
+ type: "text"
1043
+ label: linkLang.advisoryTitle
1044
+ requiredContent: "a[title]"
1045
+ default: ""
1046
+ id: "advTitle"
1047
+ setup: setupAdvParams
1048
+ commit: commitAdvParams
1049
+ }
1050
+ {
1051
+ type: "text"
1052
+ label: linkLang.advisoryContentType
1053
+ requiredContent: "a[type]"
1054
+ default: ""
1055
+ id: "advContentType"
1056
+ setup: setupAdvParams
1057
+ commit: commitAdvParams
1058
+ }
1059
+ ]
1060
+ }
1061
+ {
1062
+ type: "hbox"
1063
+ widths: [
1064
+ "45%"
1065
+ "55%"
1066
+ ]
1067
+ children: [
1068
+ {
1069
+ type: "text"
1070
+ label: linkLang.cssClasses
1071
+ requiredContent: "a(cke-xyz)" # Random text like 'xyz' will check if all are allowed.
1072
+ default: ""
1073
+ id: "advCSSClasses"
1074
+ setup: setupAdvParams
1075
+ commit: commitAdvParams
1076
+ }
1077
+ {
1078
+ type: "text"
1079
+ label: linkLang.charset
1080
+ requiredContent: "a[charset]"
1081
+ default: ""
1082
+ id: "advCharset"
1083
+ setup: setupAdvParams
1084
+ commit: commitAdvParams
1085
+ }
1086
+ ]
1087
+ }
1088
+ {
1089
+ type: "hbox"
1090
+ widths: [
1091
+ "45%"
1092
+ "55%"
1093
+ ]
1094
+ children: [
1095
+ {
1096
+ type: "text"
1097
+ label: linkLang.rel
1098
+ requiredContent: "a[rel]"
1099
+ default: ""
1100
+ id: "advRel"
1101
+ setup: setupAdvParams
1102
+ commit: commitAdvParams
1103
+ }
1104
+ {
1105
+ type: "text"
1106
+ label: linkLang.styles
1107
+ requiredContent: "a{cke-xyz}" # Random text like 'xyz' will check if all are allowed.
1108
+ default: ""
1109
+ id: "advStyles"
1110
+ validate: CKEDITOR.dialog.validate.inlineStyle(editor.lang.common.invalidInlineStyle)
1111
+ setup: setupAdvParams
1112
+ commit: commitAdvParams
1113
+ }
1114
+ ]
1115
+ }
1116
+ ]
1117
+ }
1118
+ ]
1119
+ }
1120
+ ]
1121
+ onShow: ->
1122
+ editor = @getParentEditor()
1123
+ selection = editor.getSelection()
1124
+ element = null
1125
+
1126
+ # Fill in all the relevant fields if there's already one link selected.
1127
+ if (element = plugin.getSelectedLink(editor)) and element.hasAttribute("href")
1128
+ selection.selectElement element
1129
+ else
1130
+ element = null
1131
+ @setupContent parseLink.apply(this, [
1132
+ editor
1133
+ element
1134
+ ])
1135
+ return
1136
+
1137
+ onOk: ->
1138
+ attributes = {}
1139
+ removeAttributes = []
1140
+ data = {}
1141
+ me = this
1142
+ editor = @getParentEditor()
1143
+ @commitContent data
1144
+
1145
+ # Compose the URL.
1146
+ switch data.type or "url"
1147
+ when "url"
1148
+ protocol = (if (data.url and data.url.protocol isnt `undefined`) then data.url.protocol else "http://")
1149
+ url = (data.url and CKEDITOR.tools.trim(data.url.url)) or ""
1150
+ attributes["data-cke-saved-href"] = (if (url.indexOf("/") is 0) then url else protocol + url)
1151
+ when "localPage" # added by @simo - http://blog.xoundboy.com/?p=393
1152
+ attributes["data-cke-saved-href"] = data.localPage
1153
+ when "anchor"
1154
+ name = (data.anchor and data.anchor.name)
1155
+ id = (data.anchor and data.anchor.id)
1156
+ attributes["data-cke-saved-href"] = "#" + (name or id or "")
1157
+ when "email"
1158
+ linkHref = undefined
1159
+ email = data.email
1160
+ address = email.address
1161
+ switch emailProtection
1162
+ when "", "encode"
1163
+ subject = encodeURIComponent(email.subject or "")
1164
+ body = encodeURIComponent(email.body or "")
1165
+
1166
+ # Build the e-mail parameters first.
1167
+ argList = []
1168
+ subject and argList.push("subject=" + subject)
1169
+ body and argList.push("body=" + body)
1170
+ argList = (if argList.length then "?" + argList.join("&") else "")
1171
+ if emailProtection is "encode"
1172
+ linkHref = [
1173
+ "javascript:void(location.href='mailto:'+"
1174
+ protectEmailAddressAsEncodedString(address)
1175
+ ]
1176
+
1177
+ # parameters are optional.
1178
+ argList and linkHref.push("+'", escapeSingleQuote(argList), "'")
1179
+ linkHref.push ")"
1180
+ else
1181
+ linkHref = [
1182
+ "mailto:"
1183
+ address
1184
+ argList
1185
+ ]
1186
+ break
1187
+ else
1188
+
1189
+ # Separating name and domain.
1190
+ nameAndDomain = address.split("@", 2)
1191
+ email.name = nameAndDomain[0]
1192
+ email.domain = nameAndDomain[1]
1193
+ linkHref = [
1194
+ "javascript:"
1195
+ protectEmailLinkAsFunction(email)
1196
+ ]
1197
+ attributes["data-cke-saved-href"] = linkHref.join("")
1198
+
1199
+ # Popups and target.
1200
+ if data.target
1201
+ if data.target.type is "popup"
1202
+ onclickList = [
1203
+ "window.open(this.href, '"
1204
+ data.target.name or ""
1205
+ "', '"
1206
+ ]
1207
+ featureList = [
1208
+ "resizable"
1209
+ "status"
1210
+ "location"
1211
+ "toolbar"
1212
+ "menubar"
1213
+ "fullscreen"
1214
+ "scrollbars"
1215
+ "dependent"
1216
+ ]
1217
+ featureLength = featureList.length
1218
+ addFeature = (featureName) ->
1219
+ featureList.push featureName + "=" + data.target[featureName] if data.target[featureName]
1220
+ return
1221
+
1222
+ i = 0
1223
+
1224
+ while i < featureLength
1225
+ featureList[i] = featureList[i] + ((if data.target[featureList[i]] then "=yes" else "=no"))
1226
+ i++
1227
+ addFeature "width"
1228
+ addFeature "left"
1229
+ addFeature "height"
1230
+ addFeature "top"
1231
+ onclickList.push featureList.join(","), "'); return false;"
1232
+ attributes["data-cke-pa-onclick"] = onclickList.join("")
1233
+
1234
+ # Add the "target" attribute. (#5074)
1235
+ removeAttributes.push "target"
1236
+ else
1237
+ if data.target.type isnt "notSet" and data.target.name
1238
+ attributes.target = data.target.name
1239
+ else
1240
+ removeAttributes.push "target"
1241
+ removeAttributes.push "data-cke-pa-onclick", "onclick"
1242
+
1243
+ # Advanced attributes.
1244
+ if data.adv
1245
+ advAttr = (inputName, attrName) ->
1246
+ value = data.adv[inputName]
1247
+ if value
1248
+ attributes[attrName] = value
1249
+ else
1250
+ removeAttributes.push attrName
1251
+ return
1252
+
1253
+ advAttr "advId", "id"
1254
+ advAttr "advLangDir", "dir"
1255
+ advAttr "advAccessKey", "accessKey"
1256
+ if data.adv["advName"]
1257
+ attributes["name"] = attributes["data-cke-saved-name"] = data.adv["advName"]
1258
+ else
1259
+ removeAttributes = removeAttributes.concat([
1260
+ "data-cke-saved-name"
1261
+ "name"
1262
+ ])
1263
+ advAttr "advLangCode", "lang"
1264
+ advAttr "advTabIndex", "tabindex"
1265
+ advAttr "advTitle", "title"
1266
+ advAttr "advContentType", "type"
1267
+ advAttr "advCSSClasses", "class"
1268
+ advAttr "advCharset", "charset"
1269
+ advAttr "advStyles", "style"
1270
+ advAttr "advRel", "rel"
1271
+ selection = editor.getSelection()
1272
+
1273
+ # Browser need the "href" fro copy/paste link to work. (#6641)
1274
+ attributes.href = attributes["data-cke-saved-href"]
1275
+ unless @_.selectedElement
1276
+ range = selection.getRanges(1)[0]
1277
+
1278
+ # Use link URL as text with a collapsed cursor.
1279
+ if range.collapsed
1280
+
1281
+ # Short mailto link text view (#5736).
1282
+ text = new CKEDITOR.dom.text((if data.type is "email" then data.email.address else attributes["data-cke-saved-href"]), editor.document)
1283
+ range.insertNode text
1284
+ range.selectNodeContents text
1285
+
1286
+ # Apply style.
1287
+ style = new CKEDITOR.style(
1288
+ element: "a"
1289
+ attributes: attributes
1290
+ )
1291
+ style.type = CKEDITOR.STYLE_INLINE # need to override... dunno why.
1292
+ style.applyToRange range
1293
+ range.select()
1294
+ else
1295
+
1296
+ # We're only editing an existing link, so just overwrite the attributes.
1297
+ element = @_.selectedElement
1298
+ href = element.data("cke-saved-href")
1299
+ textView = element.getHtml()
1300
+ element.setAttributes attributes
1301
+ element.removeAttributes removeAttributes
1302
+ element.addClass (if element.getChildCount() then "cke_anchor" else "cke_anchor_empty") if data.adv and data.adv.advName and CKEDITOR.plugins.link.synAnchorSelector
1303
+
1304
+ # Update text view when user changes protocol (#4612).
1305
+
1306
+ # Short mailto link text view (#5736).
1307
+ element.setHtml (if data.type is "email" then data.email.address else attributes["data-cke-saved-href"]) if href is textView or data.type is "email" and textView.indexOf("@") isnt -1
1308
+ selection.selectElement element
1309
+ delete @_.selectedElement
1310
+ return
1311
+
1312
+ onLoad: ->
1313
+ @hidePage "advanced" unless editor.config.linkShowAdvancedTab #Hide Advanded tab.
1314
+ @hidePage "target" unless editor.config.linkShowTargetTab #Hide Target tab.
1315
+ return
1316
+
1317
+
1318
+ # Inital focus on 'url' field if link is of type URL.
1319
+ onFocus: ->
1320
+ linkType = @getContentElement("info", "linkType")
1321
+ urlField = undefined
1322
+ if linkType and linkType.getValue() is "url"
1323
+ urlField = @getContentElement("info", "url")
1324
+ urlField.select()
1325
+ return
1326
+
1327
+
1328
+ # The e-mail address anti-spam protection option. The protection will be
1329
+ # applied when creating or modifying e-mail links through the editor interface.
1330
+ #
1331
+ # Two methods of protection can be choosed:
1332
+ #
1333
+ # 1. The e-mail parts (name, domain and any other query string) are
1334
+ # assembled into a function call pattern. Such function must be
1335
+ # provided by the developer in the pages that will use the contents.
1336
+ # 2. Only the e-mail address is obfuscated into a special string that
1337
+ # has no meaning for humans or spam bots, but which is properly
1338
+ # rendered and accepted by the browser.
1339
+ #
1340
+ # Both approaches require JavaScript to be enabled.
1341
+ #
1342
+ # // href="mailto:tester@ckeditor.com?subject=subject&body=body"
1343
+ # config.emailProtection = '';
1344
+ #
1345
+ # // href="<a href=\"javascript:void(location.href=\'mailto:\'+String.fromCharCode(116,101,115,116,101,114,64,99,107,101,100,105,116,111,114,46,99,111,109)+\'?subject=subject&body=body\')\">e-mail</a>"
1346
+ # config.emailProtection = 'encode';
1347
+ #
1348
+ # // href="javascript:mt('tester','ckeditor.com','subject','body')"
1349
+ # config.emailProtection = 'mt(NAME,DOMAIN,SUBJECT,BODY)';
1350
+ #
1351
+ # @since 3.1
1352
+ # @cfg {String} [emailProtection='' (empty string = disabled)]
1353
+ # @member CKEDITOR.config