qbrick 2.5.0.pre

Sign up to get free protection for your applications and to get access to all the features.
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