jacobat-refinerycms 0.9.6.14

Sign up to get free protection for your applications and to get access to all the features.
Files changed (547) hide show
  1. data/.gems +8 -0
  2. data/.gitignore +23 -0
  3. data/.yardopts +31 -0
  4. data/Gemfile +12 -0
  5. data/Rakefile +70 -0
  6. data/VERSION +1 -0
  7. data/app/controllers/admin/base_controller.rb +8 -0
  8. data/app/controllers/application.rb +3 -0
  9. data/app/controllers/application_controller.rb +7 -0
  10. data/app/helpers/application_helper.rb +7 -0
  11. data/bin/refinery +84 -0
  12. data/bin/refinery-override +76 -0
  13. data/bin/refinery-update-core +92 -0
  14. data/config/amazon_s3.yml.example +18 -0
  15. data/config/application.rb +88 -0
  16. data/config/boot.rb +110 -0
  17. data/config/database.yml.example +20 -0
  18. data/config/environment.rb +5 -0
  19. data/config/environments/development.rb +26 -0
  20. data/config/environments/production.rb +26 -0
  21. data/config/environments/test.rb +22 -0
  22. data/config/initializers/inflections.rb +10 -0
  23. data/config/initializers/mime_types.rb +5 -0
  24. data/config/preinitializer.rb +27 -0
  25. data/config/rackspace_cloudfiles.yml.example +14 -0
  26. data/config/routes.rb +20 -0
  27. data/contributors.md +20 -0
  28. data/db/migrate/20091029034951_remove_blurb_from_news_items.rb +9 -0
  29. data/db/migrate/20091109012126_add_missing_indexes.rb +25 -0
  30. data/db/migrate/20091130040711_add_down_for_maintenance_page.rb +15 -0
  31. data/db/migrate/20091207033335_add_superuser_to_users.rb +12 -0
  32. data/db/migrate/20100114092849_add_themes_table.rb +19 -0
  33. data/db/migrate/20100127004649_add_reset_code_to_users.rb +9 -0
  34. data/db/migrate/20100202034802_remove_custom_title_image_id_and_image_id_from_pages.rb +13 -0
  35. data/db/migrate/20100204011654_change_part_titles_to_titleized_version_for_new_format.rb +13 -0
  36. data/db/migrate/20100223211536_remove_themes_table.rb +17 -0
  37. data/db/schema.rb +150 -0
  38. data/db/seeds.rb +121 -0
  39. data/doc/.yardoc/checksums +0 -0
  40. data/doc/.yardoc/objects/root.dat +0 -0
  41. data/doc/.yardoc/proxy_types +0 -0
  42. data/lib/refinery_initializer.rb +23 -0
  43. data/license.md +21 -0
  44. data/public/.htaccess +40 -0
  45. data/public/404.html +29 -0
  46. data/public/422.html +30 -0
  47. data/public/500.html +29 -0
  48. data/public/favicon.ico +0 -0
  49. data/public/images/refinery/add.png +0 -0
  50. data/public/images/refinery/admin_bg.png +0 -0
  51. data/public/images/refinery/ajax-loader.gif +0 -0
  52. data/public/images/refinery/branch-end.gif +0 -0
  53. data/public/images/refinery/branch-start.gif +0 -0
  54. data/public/images/refinery/branch.gif +0 -0
  55. data/public/images/refinery/header_background.png +0 -0
  56. data/public/images/refinery/hover-gradient.jpg +0 -0
  57. data/public/images/refinery/icons/accept.png +0 -0
  58. data/public/images/refinery/icons/add.png +0 -0
  59. data/public/images/refinery/icons/application_edit.png +0 -0
  60. data/public/images/refinery/icons/application_go.png +0 -0
  61. data/public/images/refinery/icons/arrow_left.png +0 -0
  62. data/public/images/refinery/icons/arrow_switch.png +0 -0
  63. data/public/images/refinery/icons/arrow_up.png +0 -0
  64. data/public/images/refinery/icons/cancel.png +0 -0
  65. data/public/images/refinery/icons/cog_add.png +0 -0
  66. data/public/images/refinery/icons/cog_edit.png +0 -0
  67. data/public/images/refinery/icons/cross.png +0 -0
  68. data/public/images/refinery/icons/delete.png +0 -0
  69. data/public/images/refinery/icons/edit.png +0 -0
  70. data/public/images/refinery/icons/email_edit.png +0 -0
  71. data/public/images/refinery/icons/email_go.png +0 -0
  72. data/public/images/refinery/icons/email_open.png +0 -0
  73. data/public/images/refinery/icons/eye.png +0 -0
  74. data/public/images/refinery/icons/image_add.png +0 -0
  75. data/public/images/refinery/icons/image_edit.png +0 -0
  76. data/public/images/refinery/icons/layout_add.png +0 -0
  77. data/public/images/refinery/icons/layout_edit.png +0 -0
  78. data/public/images/refinery/icons/page_add.png +0 -0
  79. data/public/images/refinery/icons/page_edit.png +0 -0
  80. data/public/images/refinery/icons/page_white_edit.png +0 -0
  81. data/public/images/refinery/icons/page_white_put.png +0 -0
  82. data/public/images/refinery/icons/star.png +0 -0
  83. data/public/images/refinery/icons/tick.png +0 -0
  84. data/public/images/refinery/icons/user_add.png +0 -0
  85. data/public/images/refinery/icons/user_comment.png +0 -0
  86. data/public/images/refinery/icons/user_edit.png +0 -0
  87. data/public/images/refinery/logo-large.png +0 -0
  88. data/public/images/refinery/logo-medium.png +0 -0
  89. data/public/images/refinery/logo-small-medium.png +0 -0
  90. data/public/images/refinery/logo-small.png +0 -0
  91. data/public/images/refinery/logo.png +0 -0
  92. data/public/images/refinery/nav-3-background.gif +0 -0
  93. data/public/images/refinery/page_bg.png +0 -0
  94. data/public/images/refinery/resolve_digital_footer_logo.png +0 -0
  95. data/public/images/thickbox/cross.png +0 -0
  96. data/public/images/thickbox/loadingAnimation.gif +0 -0
  97. data/public/images/thickbox/macFFBgHack.png +0 -0
  98. data/public/images/wymeditor/skins/refinery/blockquote.png +0 -0
  99. data/public/images/wymeditor/skins/refinery/center.png +0 -0
  100. data/public/images/wymeditor/skins/refinery/css.png +0 -0
  101. data/public/images/wymeditor/skins/refinery/h1.png +0 -0
  102. data/public/images/wymeditor/skins/refinery/h2.png +0 -0
  103. data/public/images/wymeditor/skins/refinery/h3.png +0 -0
  104. data/public/images/wymeditor/skins/refinery/h4.png +0 -0
  105. data/public/images/wymeditor/skins/refinery/h5.png +0 -0
  106. data/public/images/wymeditor/skins/refinery/h6.png +0 -0
  107. data/public/images/wymeditor/skins/refinery/icons.png +0 -0
  108. data/public/images/wymeditor/skins/refinery/iframe/lbl-blockquote.png +0 -0
  109. data/public/images/wymeditor/skins/refinery/iframe/lbl-h1.png +0 -0
  110. data/public/images/wymeditor/skins/refinery/iframe/lbl-h2.png +0 -0
  111. data/public/images/wymeditor/skins/refinery/iframe/lbl-h3.png +0 -0
  112. data/public/images/wymeditor/skins/refinery/iframe/lbl-h4.png +0 -0
  113. data/public/images/wymeditor/skins/refinery/iframe/lbl-h5.png +0 -0
  114. data/public/images/wymeditor/skins/refinery/iframe/lbl-h6.png +0 -0
  115. data/public/images/wymeditor/skins/refinery/iframe/lbl-p.png +0 -0
  116. data/public/images/wymeditor/skins/refinery/iframe/lbl-pre.png +0 -0
  117. data/public/images/wymeditor/skins/refinery/justify.png +0 -0
  118. data/public/images/wymeditor/skins/refinery/left.png +0 -0
  119. data/public/images/wymeditor/skins/refinery/paragraph.png +0 -0
  120. data/public/images/wymeditor/skins/refinery/right.png +0 -0
  121. data/public/images/wymeditor/skins/wymeditor_icon.png +0 -0
  122. data/public/javascripts/admin.js +5 -0
  123. data/public/javascripts/application.js +1 -0
  124. data/public/javascripts/jquery/GPL-LICENSE.txt +278 -0
  125. data/public/javascripts/jquery/MIT-LICENSE.txt +20 -0
  126. data/public/javascripts/jquery-ui-1.8rc1.min.js +375 -0
  127. data/public/javascripts/jquery.js +6078 -0
  128. data/public/javascripts/refinery/admin.js +705 -0
  129. data/public/javascripts/refinery/boot_wym.js +154 -0
  130. data/public/javascripts/thickbox.js +350 -0
  131. data/public/javascripts/wymeditor/jquery.refinery.wymeditor.js +4975 -0
  132. data/public/javascripts/wymeditor/lang/ca.js +45 -0
  133. data/public/javascripts/wymeditor/lang/cs.js +45 -0
  134. data/public/javascripts/wymeditor/lang/de.js +45 -0
  135. data/public/javascripts/wymeditor/lang/en.js +48 -0
  136. data/public/javascripts/wymeditor/lang/es.js +45 -0
  137. data/public/javascripts/wymeditor/lang/fa.js +46 -0
  138. data/public/javascripts/wymeditor/lang/fr.js +45 -0
  139. data/public/javascripts/wymeditor/lang/he.js +45 -0
  140. data/public/javascripts/wymeditor/lang/hu.js +45 -0
  141. data/public/javascripts/wymeditor/lang/it.js +45 -0
  142. data/public/javascripts/wymeditor/lang/nb.js +45 -0
  143. data/public/javascripts/wymeditor/lang/nl.js +45 -0
  144. data/public/javascripts/wymeditor/lang/nn.js +45 -0
  145. data/public/javascripts/wymeditor/lang/pl.js +45 -0
  146. data/public/javascripts/wymeditor/lang/pt-br.js +45 -0
  147. data/public/javascripts/wymeditor/lang/pt.js +45 -0
  148. data/public/javascripts/wymeditor/lang/ru.js +45 -0
  149. data/public/javascripts/wymeditor/lang/sv.js +45 -0
  150. data/public/javascripts/wymeditor/lang/tr.js +45 -0
  151. data/public/javascripts/wymeditor/lang/zh_cn.js +47 -0
  152. data/public/javascripts/wymeditor/skins/refinery/skin.js +40 -0
  153. data/public/robots.txt +2 -0
  154. data/public/stylesheets/application.css +5 -0
  155. data/public/stylesheets/formatting.css +5 -0
  156. data/public/stylesheets/home.css +5 -0
  157. data/public/stylesheets/ie6.css +0 -0
  158. data/public/stylesheets/ie7.css +0 -0
  159. data/public/stylesheets/refinery/application.css +45 -0
  160. data/public/stylesheets/refinery/formatting.css +53 -0
  161. data/public/stylesheets/refinery/home.css +0 -0
  162. data/public/stylesheets/refinery/refinery.css +1233 -0
  163. data/public/stylesheets/refinery/theme.css +36 -0
  164. data/public/stylesheets/refinery/thickbox.css +165 -0
  165. data/public/stylesheets/refinery/tooltips.css +38 -0
  166. data/public/stylesheets/theme.css +1 -0
  167. data/public/stylesheets/wymeditor/skins/refinery/skin.css +218 -0
  168. data/public/stylesheets/wymeditor/skins/refinery/wymiframe.css +92 -0
  169. data/public/wymeditor/GPL-license.txt +278 -0
  170. data/public/wymeditor/MIT-license.txt +20 -0
  171. data/public/wymeditor/README +35 -0
  172. data/readme.md +181 -0
  173. data/script/about +3 -0
  174. data/script/console +3 -0
  175. data/script/dbconsole +3 -0
  176. data/script/destroy +3 -0
  177. data/script/generate +3 -0
  178. data/script/performance/benchmarker +3 -0
  179. data/script/performance/profiler +3 -0
  180. data/script/performance/request +3 -0
  181. data/script/plugin +3 -0
  182. data/script/process/inspector +3 -0
  183. data/script/process/reaper +3 -0
  184. data/script/process/spawner +3 -0
  185. data/script/runner +3 -0
  186. data/script/server +3 -0
  187. data/test/files/The world!.gif +0 -0
  188. data/test/files/car-wallpapers19.jpg +0 -0
  189. data/test/files/teng.pdf +0 -0
  190. data/test/fixtures/images.yml +14 -0
  191. data/test/fixtures/inquiries.yml +22 -0
  192. data/test/fixtures/news_items.yml +14 -0
  193. data/test/fixtures/page_parts.yml +9 -0
  194. data/test/fixtures/pages.yml +94 -0
  195. data/test/fixtures/refinery_settings.yml +3 -0
  196. data/test/fixtures/resources.yml +4 -0
  197. data/test/fixtures/users.yml +16 -0
  198. data/test/functional/dashboard_controller_test.rb +24 -0
  199. data/test/performance/browsing_test.rb +9 -0
  200. data/test/test_helper.rb +43 -0
  201. data/test/unit/image_test.rb +27 -0
  202. data/test/unit/inquiry_test.rb +41 -0
  203. data/test/unit/news_items_test.rb +33 -0
  204. data/test/unit/page_part_test.rb +19 -0
  205. data/test/unit/page_test.rb +133 -0
  206. data/test/unit/refinery_setting_test.rb +57 -0
  207. data/test/unit/resource_test.rb +33 -0
  208. data/themes/demolicious/LICENSE +21 -0
  209. data/themes/demolicious/README +1 -0
  210. data/themes/demolicious/images/footer_background.png +0 -0
  211. data/themes/demolicious/images/header_background.png +0 -0
  212. data/themes/demolicious/stylesheets/application.css +94 -0
  213. data/themes/demolicious/stylesheets/formatting.css +36 -0
  214. data/themes/demolicious/stylesheets/home.css +8 -0
  215. data/themes/demolicious/stylesheets/ie6.css +0 -0
  216. data/themes/demolicious/stylesheets/ie7.css +0 -0
  217. data/themes/demolicious/views/layouts/application.html.erb +20 -0
  218. data/themes/demolicious/views/pages/home.html.erb +1 -0
  219. data/themes/demolicious/views/pages/show.html.erb +1 -0
  220. data/themes/hemingway/LICENSE +7 -0
  221. data/themes/hemingway/README +3 -0
  222. data/themes/hemingway/images/archives.gif +0 -0
  223. data/themes/hemingway/images/footer_black.gif +0 -0
  224. data/themes/hemingway/images/kyle-header.jpg +0 -0
  225. data/themes/hemingway/images/readon_black.gif +0 -0
  226. data/themes/hemingway/images/search.gif +0 -0
  227. data/themes/hemingway/images/spinner.gif +0 -0
  228. data/themes/hemingway/images/trackback_pingback.gif +0 -0
  229. data/themes/hemingway/stylesheets/application.css +713 -0
  230. data/themes/hemingway/stylesheets/formatting.css +1 -0
  231. data/themes/hemingway/stylesheets/home.css +1 -0
  232. data/themes/hemingway/views/layouts/application.html.erb +55 -0
  233. data/todo.md +23 -0
  234. data/vendor/cache/aasm-2.1.3.gem +0 -0
  235. data/vendor/cache/actionmailer-2.3.5.gem +0 -0
  236. data/vendor/cache/actionpack-2.3.5.gem +0 -0
  237. data/vendor/cache/activerecord-2.3.5.gem +0 -0
  238. data/vendor/cache/activeresource-2.3.5.gem +0 -0
  239. data/vendor/cache/activesupport-2.3.5.gem +0 -0
  240. data/vendor/cache/friendly_id-2.3.1.gem +0 -0
  241. data/vendor/cache/hpricot-0.8.2.gem +0 -0
  242. data/vendor/cache/rack-1.0.1.gem +0 -0
  243. data/vendor/cache/rails-2.3.5.gem +0 -0
  244. data/vendor/cache/rake-0.8.7.gem +0 -0
  245. data/vendor/cache/rubyzip-0.9.1.gem +0 -0
  246. data/vendor/cache/slim_scrooge-1.0.3.gem +0 -0
  247. data/vendor/cache/will_paginate-2.3.11.gem +0 -0
  248. data/vendor/plugins/acts_as_indexed/CHANGELOG +74 -0
  249. data/vendor/plugins/acts_as_indexed/MIT-LICENSE +20 -0
  250. data/vendor/plugins/acts_as_indexed/README.rdoc +114 -0
  251. data/vendor/plugins/acts_as_indexed/Rakefile +35 -0
  252. data/vendor/plugins/acts_as_indexed/init.rb +2 -0
  253. data/vendor/plugins/acts_as_indexed/lib/acts_as_indexed.rb +224 -0
  254. data/vendor/plugins/acts_as_indexed/lib/search_atom.rb +107 -0
  255. data/vendor/plugins/acts_as_indexed/lib/search_index.rb +329 -0
  256. data/vendor/plugins/acts_as_indexed/lib/will_paginate_search.rb +29 -0
  257. data/vendor/plugins/acts_as_indexed/test/abstract_unit.rb +47 -0
  258. data/vendor/plugins/acts_as_indexed/test/acts_as_indexed_test.rb +102 -0
  259. data/vendor/plugins/acts_as_indexed/test/database.yml +10 -0
  260. data/vendor/plugins/acts_as_indexed/test/fixtures/post.rb +5 -0
  261. data/vendor/plugins/acts_as_indexed/test/fixtures/posts.yml +31 -0
  262. data/vendor/plugins/acts_as_indexed/test/schema.rb +6 -0
  263. data/vendor/plugins/acts_as_tree/README +26 -0
  264. data/vendor/plugins/acts_as_tree/Rakefile +22 -0
  265. data/vendor/plugins/acts_as_tree/init.rb +1 -0
  266. data/vendor/plugins/acts_as_tree/lib/active_record/acts/tree.rb +141 -0
  267. data/vendor/plugins/acts_as_tree/test/abstract_unit.rb +0 -0
  268. data/vendor/plugins/acts_as_tree/test/acts_as_tree_test.rb +219 -0
  269. data/vendor/plugins/acts_as_tree/test/database.yml +0 -0
  270. data/vendor/plugins/acts_as_tree/test/fixtures/mixin.rb +0 -0
  271. data/vendor/plugins/acts_as_tree/test/fixtures/mixins.yml +0 -0
  272. data/vendor/plugins/acts_as_tree/test/schema.rb +0 -0
  273. data/vendor/plugins/attachment_fu/CHANGELOG +35 -0
  274. data/vendor/plugins/attachment_fu/LICENSE +20 -0
  275. data/vendor/plugins/attachment_fu/README +193 -0
  276. data/vendor/plugins/attachment_fu/Rakefile +22 -0
  277. data/vendor/plugins/attachment_fu/amazon_s3.yml.tpl +17 -0
  278. data/vendor/plugins/attachment_fu/init.rb +16 -0
  279. data/vendor/plugins/attachment_fu/install.rb +7 -0
  280. data/vendor/plugins/attachment_fu/lib/geometry.rb +93 -0
  281. data/vendor/plugins/attachment_fu/lib/technoweenie/attachment_fu/backends/cloud_file_backend.rb +211 -0
  282. data/vendor/plugins/attachment_fu/lib/technoweenie/attachment_fu/backends/db_file_backend.rb +39 -0
  283. data/vendor/plugins/attachment_fu/lib/technoweenie/attachment_fu/backends/file_system_backend.rb +126 -0
  284. data/vendor/plugins/attachment_fu/lib/technoweenie/attachment_fu/backends/s3_backend.rb +394 -0
  285. data/vendor/plugins/attachment_fu/lib/technoweenie/attachment_fu/processors/core_image_processor.rb +59 -0
  286. data/vendor/plugins/attachment_fu/lib/technoweenie/attachment_fu/processors/gd2_processor.rb +54 -0
  287. data/vendor/plugins/attachment_fu/lib/technoweenie/attachment_fu/processors/image_science_processor.rb +61 -0
  288. data/vendor/plugins/attachment_fu/lib/technoweenie/attachment_fu/processors/mini_magick_processor.rb +132 -0
  289. data/vendor/plugins/attachment_fu/lib/technoweenie/attachment_fu/processors/rmagick_processor.rb +57 -0
  290. data/vendor/plugins/attachment_fu/lib/technoweenie/attachment_fu.rb +514 -0
  291. data/vendor/plugins/attachment_fu/rackspace_cloudfiles.yml.tpl +14 -0
  292. data/vendor/plugins/attachment_fu/test/backends/db_file_test.rb +16 -0
  293. data/vendor/plugins/attachment_fu/test/backends/file_system_test.rb +143 -0
  294. data/vendor/plugins/attachment_fu/test/backends/remote/cloudfiles_test.rb +102 -0
  295. data/vendor/plugins/attachment_fu/test/backends/remote/s3_test.rb +119 -0
  296. data/vendor/plugins/attachment_fu/test/base_attachment_tests.rb +77 -0
  297. data/vendor/plugins/attachment_fu/test/basic_test.rb +70 -0
  298. data/vendor/plugins/attachment_fu/test/database.yml +18 -0
  299. data/vendor/plugins/attachment_fu/test/extra_attachment_test.rb +67 -0
  300. data/vendor/plugins/attachment_fu/test/fixtures/attachment.rb +226 -0
  301. data/vendor/plugins/attachment_fu/test/fixtures/files/fake/rails.png +0 -0
  302. data/vendor/plugins/attachment_fu/test/fixtures/files/foo.txt +1 -0
  303. data/vendor/plugins/attachment_fu/test/fixtures/files/rails.png +0 -0
  304. data/vendor/plugins/attachment_fu/test/geometry_test.rb +108 -0
  305. data/vendor/plugins/attachment_fu/test/processors/core_image_test.rb +37 -0
  306. data/vendor/plugins/attachment_fu/test/processors/gd2_test.rb +31 -0
  307. data/vendor/plugins/attachment_fu/test/processors/image_science_test.rb +31 -0
  308. data/vendor/plugins/attachment_fu/test/processors/mini_magick_test.rb +103 -0
  309. data/vendor/plugins/attachment_fu/test/processors/rmagick_test.rb +255 -0
  310. data/vendor/plugins/attachment_fu/test/schema.rb +134 -0
  311. data/vendor/plugins/attachment_fu/test/test_helper.rb +150 -0
  312. data/vendor/plugins/attachment_fu/test/validation_test.rb +55 -0
  313. data/vendor/plugins/attachment_fu/vendor/red_artisan/core_image/filters/color.rb +27 -0
  314. data/vendor/plugins/attachment_fu/vendor/red_artisan/core_image/filters/effects.rb +31 -0
  315. data/vendor/plugins/attachment_fu/vendor/red_artisan/core_image/filters/perspective.rb +25 -0
  316. data/vendor/plugins/attachment_fu/vendor/red_artisan/core_image/filters/quality.rb +25 -0
  317. data/vendor/plugins/attachment_fu/vendor/red_artisan/core_image/filters/scale.rb +47 -0
  318. data/vendor/plugins/attachment_fu/vendor/red_artisan/core_image/filters/watermark.rb +32 -0
  319. data/vendor/plugins/attachment_fu/vendor/red_artisan/core_image/processor.rb +123 -0
  320. data/vendor/plugins/authentication/README +0 -0
  321. data/vendor/plugins/authentication/Rakefile +0 -0
  322. data/vendor/plugins/authentication/app/controllers/admin/users_controller.rb +67 -0
  323. data/vendor/plugins/authentication/app/controllers/sessions_controller.rb +36 -0
  324. data/vendor/plugins/authentication/app/controllers/users_controller.rb +101 -0
  325. data/vendor/plugins/authentication/app/helpers/sessions_helper.rb +2 -0
  326. data/vendor/plugins/authentication/app/helpers/users_helper.rb +2 -0
  327. data/vendor/plugins/authentication/app/models/user.rb +154 -0
  328. data/vendor/plugins/authentication/app/models/user_mailer.rb +18 -0
  329. data/vendor/plugins/authentication/app/models/user_plugin.rb +5 -0
  330. data/vendor/plugins/authentication/app/views/admin/users/_form.html.erb +38 -0
  331. data/vendor/plugins/authentication/app/views/admin/users/edit.html.erb +1 -0
  332. data/vendor/plugins/authentication/app/views/admin/users/index.html.erb +40 -0
  333. data/vendor/plugins/authentication/app/views/admin/users/new.html.erb +1 -0
  334. data/vendor/plugins/authentication/app/views/sessions/new.html.erb +24 -0
  335. data/vendor/plugins/authentication/app/views/user_mailer/reset_notification.html.erb +6 -0
  336. data/vendor/plugins/authentication/app/views/users/forgot.html.erb +13 -0
  337. data/vendor/plugins/authentication/app/views/users/new.html.erb +28 -0
  338. data/vendor/plugins/authentication/app/views/users/reset.html.erb +18 -0
  339. data/vendor/plugins/authentication/authentication.md +15 -0
  340. data/vendor/plugins/authentication/config/routes.rb +15 -0
  341. data/vendor/plugins/authentication/lib/authenticated_system.rb +115 -0
  342. data/vendor/plugins/authentication/lib/authenticated_test_helper.rb +10 -0
  343. data/vendor/plugins/authentication/rails/init.rb +13 -0
  344. data/vendor/plugins/authentication/test/fixtures/users.yml +19 -0
  345. data/vendor/plugins/authentication/test/functional/admin/base_controller_test.rb +8 -0
  346. data/vendor/plugins/authentication/test/functional/admin/dashboard_controller_test.rb +8 -0
  347. data/vendor/plugins/authentication/test/functional/admin/pages_controller_test.rb +8 -0
  348. data/vendor/plugins/authentication/test/functional/sessions_controller_test.rb +85 -0
  349. data/vendor/plugins/authentication/test/functional/users_controller_test.rb +99 -0
  350. data/vendor/plugins/authentication/test/test_helper.rb +38 -0
  351. data/vendor/plugins/authentication/test/unit/user_mailer_test.rb +31 -0
  352. data/vendor/plugins/authentication/test/unit/user_test.rb +164 -0
  353. data/vendor/plugins/dashboard/app/controllers/admin/dashboard_controller.rb +28 -0
  354. data/vendor/plugins/dashboard/app/helpers/admin/dashboard_helper.rb +19 -0
  355. data/vendor/plugins/dashboard/app/views/admin/dashboard/_recent_activity.html.erb +14 -0
  356. data/vendor/plugins/dashboard/app/views/admin/dashboard/index.html.erb +31 -0
  357. data/vendor/plugins/dashboard/config/routes.rb +5 -0
  358. data/vendor/plugins/dashboard/dashboard.md +22 -0
  359. data/vendor/plugins/dashboard/rails/init.rb +6 -0
  360. data/vendor/plugins/images/app/controllers/admin/images_controller.rb +98 -0
  361. data/vendor/plugins/images/app/helpers/admin/images_helper.rb +23 -0
  362. data/vendor/plugins/images/app/models/image.rb +57 -0
  363. data/vendor/plugins/images/app/views/admin/images/_form.html.erb +31 -0
  364. data/vendor/plugins/images/app/views/admin/images/_grid_view.html.erb +16 -0
  365. data/vendor/plugins/images/app/views/admin/images/_list_view.html.erb +12 -0
  366. data/vendor/plugins/images/app/views/admin/images/_list_view_image.html.erb +16 -0
  367. data/vendor/plugins/images/app/views/admin/images/edit.html.erb +1 -0
  368. data/vendor/plugins/images/app/views/admin/images/index.html.erb +42 -0
  369. data/vendor/plugins/images/app/views/admin/images/insert.html.erb +50 -0
  370. data/vendor/plugins/images/app/views/admin/images/new.html.erb +1 -0
  371. data/vendor/plugins/images/config/routes.rb +5 -0
  372. data/vendor/plugins/images/images.md +53 -0
  373. data/vendor/plugins/images/lib/tasks/images.rake +45 -0
  374. data/vendor/plugins/images/rails/init.rb +14 -0
  375. data/vendor/plugins/inquiries/app/controllers/admin/inquiries_controller.rb +29 -0
  376. data/vendor/plugins/inquiries/app/controllers/admin/inquiry_settings_controller.rb +16 -0
  377. data/vendor/plugins/inquiries/app/controllers/inquiries_controller.rb +41 -0
  378. data/vendor/plugins/inquiries/app/helpers/inquiries_helper.rb +13 -0
  379. data/vendor/plugins/inquiries/app/models/inquiry.rb +16 -0
  380. data/vendor/plugins/inquiries/app/models/inquiry_mailer.rb +20 -0
  381. data/vendor/plugins/inquiries/app/models/inquiry_setting.rb +11 -0
  382. data/vendor/plugins/inquiries/app/views/admin/inquiries/_inquiry.html.erb +20 -0
  383. data/vendor/plugins/inquiries/app/views/admin/inquiries/index.html.erb +43 -0
  384. data/vendor/plugins/inquiries/app/views/admin/inquiries/show.html.erb +62 -0
  385. data/vendor/plugins/inquiries/app/views/admin/inquiry_settings/_confirmation_email_form.html.erb +46 -0
  386. data/vendor/plugins/inquiries/app/views/admin/inquiry_settings/_notification_recipients_form.html.erb +18 -0
  387. data/vendor/plugins/inquiries/app/views/admin/inquiry_settings/edit.html.erb +5 -0
  388. data/vendor/plugins/inquiries/app/views/admin/inquiry_settings/index.html.erb +31 -0
  389. data/vendor/plugins/inquiries/app/views/inquiries/new.html.erb +31 -0
  390. data/vendor/plugins/inquiries/app/views/inquiries/thank_you.html.erb +1 -0
  391. data/vendor/plugins/inquiries/app/views/inquiry_mailer/confirmation.html.erb +1 -0
  392. data/vendor/plugins/inquiries/app/views/inquiry_mailer/notification.html.erb +18 -0
  393. data/vendor/plugins/inquiries/config/routes.rb +8 -0
  394. data/vendor/plugins/inquiries/inquiries.md +31 -0
  395. data/vendor/plugins/inquiries/rails/init.rb +13 -0
  396. data/vendor/plugins/news/app/controllers/admin/news_items_controller.rb +5 -0
  397. data/vendor/plugins/news/app/controllers/news_items_controller.rb +20 -0
  398. data/vendor/plugins/news/app/models/news_item.rb +22 -0
  399. data/vendor/plugins/news/app/views/admin/news_items/_form.html.erb +19 -0
  400. data/vendor/plugins/news/app/views/admin/news_items/_news_item.html.erb +15 -0
  401. data/vendor/plugins/news/app/views/admin/news_items/edit.html.erb +1 -0
  402. data/vendor/plugins/news/app/views/admin/news_items/index.html.erb +31 -0
  403. data/vendor/plugins/news/app/views/admin/news_items/new.html.erb +1 -0
  404. data/vendor/plugins/news/app/views/news_items/_recent_posts.html.erb +8 -0
  405. data/vendor/plugins/news/app/views/news_items/index.html.erb +17 -0
  406. data/vendor/plugins/news/app/views/news_items/index.rss.builder +26 -0
  407. data/vendor/plugins/news/app/views/news_items/show.html.erb +13 -0
  408. data/vendor/plugins/news/config/routes.rb +7 -0
  409. data/vendor/plugins/news/news.md +20 -0
  410. data/vendor/plugins/news/rails/init.rb +11 -0
  411. data/vendor/plugins/pages/app/controllers/admin/page_dialogs_controller.rb +49 -0
  412. data/vendor/plugins/pages/app/controllers/admin/page_parts_controller.rb +20 -0
  413. data/vendor/plugins/pages/app/controllers/admin/pages_controller.rb +18 -0
  414. data/vendor/plugins/pages/app/controllers/pages_controller.rb +22 -0
  415. data/vendor/plugins/pages/app/helpers/pages_helper.rb +2 -0
  416. data/vendor/plugins/pages/app/models/page.rb +162 -0
  417. data/vendor/plugins/pages/app/models/page_part.rb +10 -0
  418. data/vendor/plugins/pages/app/presenters/page_presenter.rb +3 -0
  419. data/vendor/plugins/pages/app/views/admin/page_dialogs/_page_link.html.erb +5 -0
  420. data/vendor/plugins/pages/app/views/admin/page_dialogs/link_to.html.erb +149 -0
  421. data/vendor/plugins/pages/app/views/admin/pages/_form.html.erb +140 -0
  422. data/vendor/plugins/pages/app/views/admin/pages/_list.html.erb +29 -0
  423. data/vendor/plugins/pages/app/views/admin/pages/_page_part_field.html.erb +4 -0
  424. data/vendor/plugins/pages/app/views/admin/pages/_sortable_list.html.erb +4 -0
  425. data/vendor/plugins/pages/app/views/admin/pages/edit.html.erb +1 -0
  426. data/vendor/plugins/pages/app/views/admin/pages/index.html.erb +41 -0
  427. data/vendor/plugins/pages/app/views/admin/pages/new.html.erb +1 -0
  428. data/vendor/plugins/pages/app/views/pages/home.html.erb +1 -0
  429. data/vendor/plugins/pages/app/views/pages/show.html.erb +1 -0
  430. data/vendor/plugins/pages/config/routes.rb +11 -0
  431. data/vendor/plugins/pages/pages.md +146 -0
  432. data/vendor/plugins/pages/rails/init.rb +13 -0
  433. data/vendor/plugins/rails_indexes/MIT-LICENSE +20 -0
  434. data/vendor/plugins/rails_indexes/README.textile +46 -0
  435. data/vendor/plugins/rails_indexes/Rakefile +23 -0
  436. data/vendor/plugins/rails_indexes/lib/indexer.rb +305 -0
  437. data/vendor/plugins/rails_indexes/tasks/indexer.rake +18 -0
  438. data/vendor/plugins/rails_indexes/test/fixtures/app/controllers/users_controller.rb +8 -0
  439. data/vendor/plugins/rails_indexes/test/fixtures/app/models/address.rb +5 -0
  440. data/vendor/plugins/rails_indexes/test/fixtures/app/models/company.rb +11 -0
  441. data/vendor/plugins/rails_indexes/test/fixtures/app/models/country.rb +4 -0
  442. data/vendor/plugins/rails_indexes/test/fixtures/app/models/freelancer.rb +3 -0
  443. data/vendor/plugins/rails_indexes/test/fixtures/app/models/gift.rb +10 -0
  444. data/vendor/plugins/rails_indexes/test/fixtures/app/models/god.rb +3 -0
  445. data/vendor/plugins/rails_indexes/test/fixtures/app/models/user.rb +17 -0
  446. data/vendor/plugins/rails_indexes/test/fixtures/app/sweepers/user_sweeper.rb +9 -0
  447. data/vendor/plugins/rails_indexes/test/fixtures/schema.rb +46 -0
  448. data/vendor/plugins/rails_indexes/test/rails_indexes_test.rb +83 -0
  449. data/vendor/plugins/rails_indexes/test/test_helper.rb +30 -0
  450. data/vendor/plugins/refinery/app/controllers/admin/refinery_core_controller.rb +14 -0
  451. data/vendor/plugins/refinery/app/views/admin/_head.html.erb +11 -0
  452. data/vendor/plugins/refinery/app/views/admin/_menu.html.erb +23 -0
  453. data/vendor/plugins/refinery/app/views/layouts/admin.html.erb +34 -0
  454. data/vendor/plugins/refinery/app/views/layouts/application.html.erb +20 -0
  455. data/vendor/plugins/refinery/app/views/shared/_content_page.html.erb +36 -0
  456. data/vendor/plugins/refinery/app/views/shared/_footer.html.erb +5 -0
  457. data/vendor/plugins/refinery/app/views/shared/_google_analytics.html.erb +13 -0
  458. data/vendor/plugins/refinery/app/views/shared/_head.html.erb +16 -0
  459. data/vendor/plugins/refinery/app/views/shared/_header.html.erb +4 -0
  460. data/vendor/plugins/refinery/app/views/shared/_ie6check.html.erb +11 -0
  461. data/vendor/plugins/refinery/app/views/shared/_menu.html.erb +8 -0
  462. data/vendor/plugins/refinery/app/views/shared/_menu_branch.html.erb +23 -0
  463. data/vendor/plugins/refinery/app/views/shared/_message.html.erb +5 -0
  464. data/vendor/plugins/refinery/app/views/shared/_submenu.html.erb +5 -0
  465. data/vendor/plugins/refinery/app/views/shared/_submenu_branch.html.erb +10 -0
  466. data/vendor/plugins/refinery/app/views/shared/admin/_continue_editing.html.erb +4 -0
  467. data/vendor/plugins/refinery/app/views/shared/admin/_error_messages_for.html.erb +2 -0
  468. data/vendor/plugins/refinery/app/views/shared/admin/_form_actions.html.erb +13 -0
  469. data/vendor/plugins/refinery/app/views/shared/admin/_head_before_javascript_libraries.html.erb +0 -0
  470. data/vendor/plugins/refinery/app/views/shared/admin/_image_picker.html.erb +48 -0
  471. data/vendor/plugins/refinery/app/views/shared/admin/_make_sortable.html.erb +10 -0
  472. data/vendor/plugins/refinery/app/views/shared/admin/_resource_picker.html.erb +57 -0
  473. data/vendor/plugins/refinery/app/views/shared/admin/_search.html.erb +5 -0
  474. data/vendor/plugins/refinery/app/views/shared/admin/_sortable_list.html.erb +9 -0
  475. data/vendor/plugins/refinery/app/views/welcome.html.erb +13 -0
  476. data/vendor/plugins/refinery/app/views/wymiframe.html.erb +8 -0
  477. data/vendor/plugins/refinery/config/routes.rb +10 -0
  478. data/vendor/plugins/refinery/crud.md +197 -0
  479. data/vendor/plugins/refinery/lib/crud.rb +222 -0
  480. data/vendor/plugins/refinery/lib/generators/refinery/README +29 -0
  481. data/vendor/plugins/refinery/lib/generators/refinery/Rakefile +12 -0
  482. data/vendor/plugins/refinery/lib/generators/refinery/USAGE +2 -0
  483. data/vendor/plugins/refinery/lib/generators/refinery/install.rb +2 -0
  484. data/vendor/plugins/refinery/lib/generators/refinery/refinery_generator.rb +65 -0
  485. data/vendor/plugins/refinery/lib/generators/refinery/templates/config/routes.rb +7 -0
  486. data/vendor/plugins/refinery/lib/generators/refinery/templates/controller.rb +5 -0
  487. data/vendor/plugins/refinery/lib/generators/refinery/templates/migration.rb +44 -0
  488. data/vendor/plugins/refinery/lib/generators/refinery/templates/model.rb +9 -0
  489. data/vendor/plugins/refinery/lib/generators/refinery/templates/public_controller.rb +30 -0
  490. data/vendor/plugins/refinery/lib/generators/refinery/templates/rails/init.rb +10 -0
  491. data/vendor/plugins/refinery/lib/generators/refinery/templates/views/admin/_form.html.erb +14 -0
  492. data/vendor/plugins/refinery/lib/generators/refinery/templates/views/admin/_singular_name.html.erb +15 -0
  493. data/vendor/plugins/refinery/lib/generators/refinery/templates/views/admin/_sortable_list.html.erb +2 -0
  494. data/vendor/plugins/refinery/lib/generators/refinery/templates/views/admin/edit.html.erb +1 -0
  495. data/vendor/plugins/refinery/lib/generators/refinery/templates/views/admin/index.html.erb +42 -0
  496. data/vendor/plugins/refinery/lib/generators/refinery/templates/views/admin/new.html.erb +1 -0
  497. data/vendor/plugins/refinery/lib/generators/refinery/templates/views/index.html.erb +11 -0
  498. data/vendor/plugins/refinery/lib/generators/refinery/templates/views/show.html.erb +25 -0
  499. data/vendor/plugins/refinery/lib/refinery/activity.rb +37 -0
  500. data/vendor/plugins/refinery/lib/refinery/admin_base_controller.rb +56 -0
  501. data/vendor/plugins/refinery/lib/refinery/application_controller.rb +80 -0
  502. data/vendor/plugins/refinery/lib/refinery/application_helper.rb +112 -0
  503. data/vendor/plugins/refinery/lib/refinery/attachment_fu_patch.rb +16 -0
  504. data/vendor/plugins/refinery/lib/refinery/base_presenter.rb +27 -0
  505. data/vendor/plugins/refinery/lib/refinery/form_helpers.rb +28 -0
  506. data/vendor/plugins/refinery/lib/refinery/html_truncation_helper.rb +110 -0
  507. data/vendor/plugins/refinery/lib/refinery/initializer.rb +80 -0
  508. data/vendor/plugins/refinery/lib/refinery/link_renderer.rb +45 -0
  509. data/vendor/plugins/refinery/lib/refinery/plugin.rb +47 -0
  510. data/vendor/plugins/refinery/lib/refinery/plugins.rb +53 -0
  511. data/vendor/plugins/refinery/lib/refinery.rb +11 -0
  512. data/vendor/plugins/refinery/lib/tasks/doc.rake +29 -0
  513. data/vendor/plugins/refinery/lib/tasks/refinery.rake +34 -0
  514. data/vendor/plugins/refinery/lib/tasks/yard.rake +32 -0
  515. data/vendor/plugins/refinery/plugins.md +205 -0
  516. data/vendor/plugins/refinery/rails/init.rb +14 -0
  517. data/vendor/plugins/refinery_dialogs/app/controllers/admin/dialogs_controller.rb +26 -0
  518. data/vendor/plugins/refinery_dialogs/app/views/admin/dialogs/show.html.erb +20 -0
  519. data/vendor/plugins/refinery_dialogs/app/views/layouts/admin_dialog.html.erb +24 -0
  520. data/vendor/plugins/refinery_dialogs/config/routes.rb +5 -0
  521. data/vendor/plugins/refinery_dialogs/rails/init.rb +7 -0
  522. data/vendor/plugins/refinery_settings/app/controllers/admin/refinery_settings_controller.rb +5 -0
  523. data/vendor/plugins/refinery_settings/app/models/refinery_setting.rb +88 -0
  524. data/vendor/plugins/refinery_settings/app/views/admin/refinery_settings/_form.html.erb +17 -0
  525. data/vendor/plugins/refinery_settings/app/views/admin/refinery_settings/_refinery_setting.html.erb +12 -0
  526. data/vendor/plugins/refinery_settings/app/views/admin/refinery_settings/edit.html.erb +4 -0
  527. data/vendor/plugins/refinery_settings/app/views/admin/refinery_settings/index.html.erb +27 -0
  528. data/vendor/plugins/refinery_settings/app/views/admin/refinery_settings/new.html.erb +1 -0
  529. data/vendor/plugins/refinery_settings/config/routes.rb +5 -0
  530. data/vendor/plugins/refinery_settings/rails/init.rb +13 -0
  531. data/vendor/plugins/refinery_settings/settings.md +55 -0
  532. data/vendor/plugins/resources/app/controllers/admin/resources_controller.rb +94 -0
  533. data/vendor/plugins/resources/app/models/resource.rb +55 -0
  534. data/vendor/plugins/resources/app/views/admin/resources/_form.html.erb +33 -0
  535. data/vendor/plugins/resources/app/views/admin/resources/_resource.html.erb +14 -0
  536. data/vendor/plugins/resources/app/views/admin/resources/edit.html.erb +1 -0
  537. data/vendor/plugins/resources/app/views/admin/resources/index.html.erb +41 -0
  538. data/vendor/plugins/resources/app/views/admin/resources/insert.html.erb +67 -0
  539. data/vendor/plugins/resources/app/views/admin/resources/new.html.erb +1 -0
  540. data/vendor/plugins/resources/config/routes.rb +9 -0
  541. data/vendor/plugins/resources/rails/init.rb +12 -0
  542. data/vendor/plugins/resources/resources.md +9 -0
  543. data/vendor/plugins/themes/app/helpers/themes_helper.rb +25 -0
  544. data/vendor/plugins/themes/lib/theme_server.rb +30 -0
  545. data/vendor/plugins/themes/rails/init.rb +24 -0
  546. data/vendor/plugins/themes/themes.md +113 -0
  547. metadata +625 -0
@@ -0,0 +1,4975 @@
1
+ /*
2
+ * WYMeditor : what you see is What You Mean web-based editor
3
+ * Copyright (c) 2008 Jean-Francois Hovinne, http://www.wymeditor.org/
4
+ * Dual licensed under the MIT (MIT-license.txt)
5
+ * and GPL (GPL-license.txt) licenses.
6
+ *
7
+ * For further information visit:
8
+ * http://www.wymeditor.org/
9
+ *
10
+ * File: jquery.refinery.wymeditor.js
11
+ *
12
+ * Main JS file with core classes and functions.
13
+ * See the documentation for more info.
14
+ *
15
+ * About: authors
16
+ *
17
+ * Jean-Francois Hovinne (jf.hovinne a-t wymeditor dotorg)
18
+ * Volker Mische (vmx a-t gmx dotde)
19
+ * Scott Lewis (lewiscot a-t gmail dotcom)
20
+ * Bermi Ferrer (wymeditor a-t bermi dotorg)
21
+ * Daniel Reszka (d.reszka a-t wymeditor dotorg)
22
+ * Jonatan Lundin (jonatan.lundin _at_ gmail.com)
23
+ */
24
+
25
+ /*
26
+ Namespace: WYMeditor
27
+ Global WYMeditor namespace.
28
+ */
29
+ if(!WYMeditor) var WYMeditor = {};
30
+
31
+ //Wrap the Firebug console in WYMeditor.console
32
+ (function() {
33
+ if ( !window.console || !console.firebug ) {
34
+ var names = ["log", "debug", "info", "warn", "error", "assert", "dir", "dirxml",
35
+ "group", "groupEnd", "time", "timeEnd", "count", "trace", "profile", "profileEnd"];
36
+
37
+ WYMeditor.console = {};
38
+ for (var i = 0; i < names.length; ++i)
39
+ WYMeditor.console[names[i]] = function() {}
40
+
41
+ } else WYMeditor.console = window.console;
42
+ })();
43
+ $.extend(WYMeditor, {
44
+
45
+ /*
46
+ Constants: Global WYMeditor constants.
47
+
48
+ VERSION - Defines WYMeditor version.
49
+ INSTANCES - An array of loaded WYMeditor.editor instances.
50
+ STRINGS - An array of loaded WYMeditor language pairs/values.
51
+ SKINS - An array of loaded WYMeditor skins.
52
+ NAME - The "name" attribute.
53
+ INDEX - A string replaced by the instance index.
54
+ WYM_INDEX - A string used to get/set the instance index.
55
+ BASE_PATH - A string replaced by WYMeditor's base path.
56
+ SKIN_PATH - A string replaced by WYMeditor's skin path.
57
+ WYM_PATH - A string replaced by WYMeditor's main JS file path.
58
+ SKINS_DEFAULT_PATH - The skins default base path.
59
+ SKINS_DEFAULT_CSS - The skins default CSS file.
60
+ LANG_DEFAULT_PATH - The language files default path.
61
+ IFRAME_BASE_PATH - A string replaced by the designmode iframe's base path.
62
+ IFRAME_DEFAULT - The iframe's default base path.
63
+ JQUERY_PATH - A string replaced by the computed jQuery path.
64
+ DIRECTION - A string replaced by the text direction (rtl or ltr).
65
+ LOGO - A string replaced by WYMeditor logo.
66
+ TOOLS - A string replaced by the toolbar's HTML.
67
+ TOOLS_ITEMS - A string replaced by the toolbar items.
68
+ TOOL_NAME - A string replaced by a toolbar item's name.
69
+ TOOL_TITLE - A string replaced by a toolbar item's title.
70
+ TOOL_CLASS - A string replaced by a toolbar item's class.
71
+ CLASSES - A string replaced by the classes panel's HTML.
72
+ CLASSES_ITEMS - A string replaced by the classes items.
73
+ CLASS_NAME - A string replaced by a class item's name.
74
+ CLASS_TITLE - A string replaced by a class item's title.
75
+ CONTAINERS - A string replaced by the containers panel's HTML.
76
+ CONTAINERS_ITEMS - A string replaced by the containers items.
77
+ CONTAINER_NAME - A string replaced by a container item's name.
78
+ CONTAINER_TITLE - A string replaced by a container item's title.
79
+ CONTAINER_CLASS - A string replaced by a container item's class.
80
+ HTML - A string replaced by the HTML view panel's HTML.
81
+ IFRAME - A string replaced by the designmode iframe.
82
+ STATUS - A string replaced by the status panel's HTML.
83
+ DIALOG_TITLE - A string replaced by a dialog's title.
84
+ DIALOG_BODY - A string replaced by a dialog's HTML body.
85
+ BODY - The BODY element.
86
+ STRING - The "string" type.
87
+ BODY,DIV,P,
88
+ H1,H2,H3,H4,H5,H6,
89
+ PRE,BLOCKQUOTE,
90
+ A,BR,IMG,
91
+ TABLE,TD,TH,
92
+ UL,OL,LI - HTML elements string representation.
93
+ CLASS,HREF,SRC,
94
+ TITLE,ALT - HTML attributes string representation.
95
+ DIALOG_LINK - A link dialog type.
96
+ DIALOG_IMAGE - An image dialog type.
97
+ DIALOG_TABLE - A table dialog type.
98
+ DIALOG_PASTE - A 'Paste from Word' dialog type.
99
+ BOLD - Command: (un)set selection to <strong>.
100
+ ITALIC - Command: (un)set selection to <em>.
101
+ CREATE_LINK - Command: open the link dialog or (un)set link.
102
+ INSERT_IMAGE - Command: open the image dialog or insert an image.
103
+ INSERT_TABLE - Command: open the table dialog.
104
+ PASTE - Command: open the paste dialog.
105
+ INDENT - Command: nest a list item.
106
+ OUTDENT - Command: unnest a list item.
107
+ TOGGLE_HTML - Command: display/hide the HTML view.
108
+ FORMAT_BLOCK - Command: set a block element to another type.
109
+ PREVIEW - Command: open the preview dialog.
110
+ UNLINK - Command: unset a link.
111
+ INSERT_UNORDEREDLIST- Command: insert an unordered list.
112
+ INSERT_ORDEREDLIST - Command: insert an ordered list.
113
+ MAIN_CONTAINERS - An array of the main HTML containers used in WYMeditor.
114
+ BLOCKS - An array of the HTML block elements.
115
+ KEY - Standard key codes.
116
+ NODE - Node types.
117
+
118
+ */
119
+
120
+ VERSION : "0.5-b2-refinery",
121
+ INSTANCES : [],
122
+ STRINGS : [],
123
+ SKINS : [],
124
+ NAME : "name",
125
+ INDEX : "{Wym_Index}",
126
+ WYM_INDEX : "wym_index",
127
+ BASE_PATH : "{Wym_Base_Path}",
128
+ CSS_PATH : "{Wym_Css_Path}",
129
+ WYM_PATH : "{Wym_Wym_Path}",
130
+ SKINS_DEFAULT_PATH : "/images/wymeditor/skins/",
131
+ SKINS_DEFAULT_CSS : "skin.css",
132
+ SKINS_DEFAULT_JS : "skin.js",
133
+ LANG_DEFAULT_PATH : "lang/",
134
+ IFRAME_BASE_PATH : "{Wym_Iframe_Base_Path}",
135
+ IFRAME_DEFAULT : "iframe/default/",
136
+ JQUERY_PATH : "{Wym_Jquery_Path}",
137
+ DIRECTION : "{Wym_Direction}",
138
+ LOGO : "{Wym_Logo}",
139
+ TOOLS : "{Wym_Tools}",
140
+ TOOLS_ITEMS : "{Wym_Tools_Items}",
141
+ TOOL_NAME : "{Wym_Tool_Name}",
142
+ TOOL_TITLE : "{Wym_Tool_Title}",
143
+ TOOL_CLASS : "{Wym_Tool_Class}",
144
+ CLASSES : "{Wym_Classes}",
145
+ CLASSES_ITEMS : "{Wym_Classes_Items}",
146
+ CLASS_NAME : "{Wym_Class_Name}",
147
+ CLASS_TITLE : "{Wym_Class_Title}",
148
+ CONTAINERS : "{Wym_Containers}",
149
+ CONTAINERS_ITEMS : "{Wym_Containers_Items}",
150
+ CONTAINER_NAME : "{Wym_Container_Name}",
151
+ CONTAINER_TITLE : "{Wym_Containers_Title}",
152
+ CONTAINER_CLASS : "{Wym_Container_Class}",
153
+ HTML : "{Wym_Html}",
154
+ IFRAME : "{Wym_Iframe}",
155
+ STATUS : "{Wym_Status}",
156
+ DIALOG_TITLE : "{Wym_Dialog_Title}",
157
+ DIALOG_BODY : "{Wym_Dialog_Body}",
158
+ STRING : "string",
159
+ BODY : "body",
160
+ DIV : "div",
161
+ P : "p",
162
+ H1 : "h1",
163
+ H2 : "h2",
164
+ H3 : "h3",
165
+ H4 : "h4",
166
+ H5 : "h5",
167
+ H6 : "h6",
168
+ PRE : "pre",
169
+ BLOCKQUOTE : "blockquote",
170
+ A : "a",
171
+ BR : "br",
172
+ IMG : "img",
173
+ TABLE : "table",
174
+ TD : "td",
175
+ TH : "th",
176
+ UL : "ul",
177
+ OL : "ol",
178
+ LI : "li",
179
+ CLASS : "class",
180
+ HREF : "href",
181
+ SRC : "src",
182
+ TITLE : "title",
183
+ TARGET : "target",
184
+ ALT : "alt",
185
+ DIALOG_LINK : "Link",
186
+ DIALOG_IMAGE : "Image",
187
+ DIALOG_TABLE : "Table",
188
+ DIALOG_PASTE : "Paste_From_Word",
189
+ DIALOG_CLASS : "Css_Class",
190
+ BOLD : "Bold",
191
+ ITALIC : "Italic",
192
+ CREATE_LINK : "CreateLink",
193
+ INSERT_IMAGE : "InsertImage",
194
+ INSERT_TABLE : "InsertTable",
195
+ INSERT_HTML : "InsertHTML",
196
+ APPLY_CLASS : "Apply_Style",
197
+ PASTE : "Paste",
198
+ INDENT : "Indent",
199
+ OUTDENT : "Outdent",
200
+ TOGGLE_HTML : "ToggleHtml",
201
+ FORMAT_BLOCK : "FormatBlock",
202
+ PREVIEW : "Preview",
203
+
204
+ UNLINK : "Unlink",
205
+ INSERT_UNORDEREDLIST : "InsertUnorderedList",
206
+ INSERT_ORDEREDLIST : "InsertOrderedList",
207
+
208
+ MAIN_CONTAINERS : new Array("p","h1","h2","h3","h4","h5","h6","pre","blockquote"),
209
+
210
+ BLOCKS : new Array("address", "blockquote", "div", "dl",
211
+ "fieldset", "form", "h1", "h2", "h3", "h4", "h5", "h6", "hr",
212
+ "noscript", "ol", "p", "pre", "table", "ul", "dd", "dt",
213
+ "li", "tbody", "td", "tfoot", "th", "thead", "tr"),
214
+
215
+ KEY : {
216
+ BACKSPACE: 8,
217
+ ENTER: 13,
218
+ END: 35,
219
+ HOME: 36,
220
+ LEFT: 37,
221
+ UP: 38,
222
+ RIGHT: 39,
223
+ DOWN: 40,
224
+ CURSOR: new Array(37, 38, 39, 40),
225
+ DELETE: 46
226
+ },
227
+
228
+ NODE : {
229
+ ELEMENT: 1,
230
+ ATTRIBUTE: 2,
231
+ TEXT: 3
232
+ },
233
+
234
+ /*
235
+ Class: WYMeditor.editor
236
+ WYMeditor editor main class, instanciated for each editor occurrence.
237
+ */
238
+
239
+ editor : function(elem, options) {
240
+ /*
241
+ Constructor: WYMeditor.editor
242
+
243
+ Initializes main values (index, elements, paths, ...)
244
+ and call WYMeditor.editor.init which initializes the editor.
245
+
246
+ Parameters:
247
+
248
+ elem - The HTML element to be replaced by the editor.
249
+ options - The hash of options.
250
+
251
+ Returns:
252
+
253
+ Nothing.
254
+
255
+ See Also:
256
+
257
+ <WYMeditor.editor.init>
258
+ */
259
+
260
+ //store the instance in the INSTANCES array and store the index
261
+ this._index = WYMeditor.INSTANCES.push(this) - 1;
262
+ //store the element replaced by the editor
263
+ this._element = elem;
264
+ //store the options
265
+ this._options = options;
266
+ //store the element's inner value
267
+ this._html = $(elem).val();
268
+
269
+ //store the HTML option, if any
270
+ if(this._options.html) this._html = this._options.html;
271
+ //get or compute the base path (where the main JS file is located)
272
+ this._options.basePath = this._options.basePath || this.computeBasePath();
273
+ //get or set the skin path (where the skin files are located)
274
+ this._options.skinPath = this._options.skinPath || this._options.basePath + WYMeditor.SKINS_DEFAULT_PATH + this._options.skin + '/';
275
+ // set css and js skin paths
276
+ this._options.cssSkinPath = (this._options.cssSkinPath || this._options.skinPath) + this._options.skin + "/";
277
+ this._options.jsSkinPath = (this._options.jsSkinPath || this._options.skinPath) + this._options.skin + "/";
278
+ //get or compute the main JS file location
279
+ this._options.wymPath = this._options.wymPath || this.computeWymPath();
280
+ //get or set the language files path
281
+ this._options.langPath = this._options.langPath || this._options.basePath + WYMeditor.LANG_DEFAULT_PATH;
282
+ //get or set the designmode iframe's base path
283
+ this._options.iframeBasePath = this._options.iframeBasePath || this._options.basePath + WYMeditor.IFRAME_DEFAULT;
284
+ //get or compute the jQuery JS file location
285
+ this._options.jQueryPath = this._options.jQueryPath || this.computeJqueryPath();
286
+
287
+ //initialize the editor instance
288
+ this.init();
289
+ }
290
+
291
+ });
292
+
293
+
294
+ /********** JQUERY **********/
295
+
296
+ /**
297
+ * Replace an HTML element by WYMeditor
298
+ *
299
+ * @example $(".wymeditor").wymeditor(
300
+ * {
301
+ *
302
+ * }
303
+ * );
304
+ * @desc Example description here
305
+ *
306
+ * @name WYMeditor
307
+ * @description WYMeditor is a web-based WYSIWYM XHTML editor
308
+ * @param Hash hash A hash of parameters
309
+ * @option Integer iExample Description here
310
+ * @option String sExample Description here
311
+ *
312
+ * @type jQuery
313
+ * @cat Plugins/WYMeditor
314
+ * @author Jean-Francois Hovinne
315
+ */
316
+ $.fn.wymeditor = function(options) {
317
+
318
+ options = $.extend({
319
+
320
+ html: "",
321
+
322
+ basePath: false,
323
+
324
+ skinPath: false,
325
+ jsSkinPath: false,
326
+ cssSkinPath: false,
327
+
328
+ wymPath: false,
329
+
330
+ iframeBasePath: false,
331
+
332
+ jQueryPath: false,
333
+
334
+ styles: false,
335
+
336
+ stylesheet: false,
337
+
338
+ skin: "default",
339
+ initSkin: true,
340
+ loadSkin: true,
341
+
342
+ lang: "en",
343
+
344
+ direction: "ltr",
345
+
346
+ boxHtml: "<div class='wym_box'>"
347
+ + "<div class='wym_area_top'>"
348
+ + WYMeditor.TOOLS
349
+ + "</div>"
350
+ + "<div class='wym_area_left'></div>"
351
+ + "<div class='wym_area_right'>"
352
+ + WYMeditor.CONTAINERS
353
+ + WYMeditor.CLASSES
354
+ + "</div>"
355
+ + "<div class='wym_area_main'>"
356
+ + WYMeditor.HTML
357
+ + WYMeditor.IFRAME
358
+ + WYMeditor.STATUS
359
+ + "</div>"
360
+ + "<div class='wym_area_bottom'>"
361
+ + WYMeditor.LOGO
362
+ + "</div>"
363
+ + "</div>",
364
+
365
+ logoHtml: "<a class='wym_wymeditor_link' "
366
+ + "href='http://www.wymeditor.org/'>WYMeditor</a>",
367
+
368
+ iframeHtml:"<div class='wym_iframe wym_section'>"
369
+ + "<iframe "
370
+ + "src='"
371
+ + WYMeditor.IFRAME_BASE_PATH
372
+ + "wymiframe.html' "
373
+ + "onload='this.contentWindow.parent.WYMeditor.INSTANCES["
374
+ + WYMeditor.INDEX + "].initIframe(this)'"
375
+ + "></iframe>"
376
+ + "</div>",
377
+
378
+ editorStyles: [],
379
+
380
+ toolsHtml: "<div class='wym_tools wym_section'>"
381
+ + "<h2>{Tools}</h2>"
382
+ + "<ul>"
383
+ + WYMeditor.TOOLS_ITEMS
384
+ + "</ul>"
385
+ + "</div>",
386
+
387
+ toolsItemHtml: "<li class='"
388
+ + WYMeditor.TOOL_CLASS
389
+ + "'><a href='#' name='"
390
+ + WYMeditor.TOOL_NAME
391
+ + "' title='"
392
+ + WYMeditor.TOOL_TITLE
393
+ + "'>"
394
+ + WYMeditor.TOOL_TITLE
395
+ + "</a></li>",
396
+
397
+ toolsItems: [
398
+ {'name': 'Bold', 'title': 'Strong', 'css': 'wym_tools_strong'},
399
+ {'name': 'Italic', 'title': 'Emphasis', 'css': 'wym_tools_emphasis'},
400
+ {'name': 'Superscript', 'title': 'Superscript',
401
+ 'css': 'wym_tools_superscript'},
402
+ {'name': 'Subscript', 'title': 'Subscript',
403
+ 'css': 'wym_tools_subscript'},
404
+ {'name': 'InsertOrderedList', 'title': 'Ordered_List',
405
+ 'css': 'wym_tools_ordered_list'},
406
+ {'name': 'InsertUnorderedList', 'title': 'Unordered_List',
407
+ 'css': 'wym_tools_unordered_list'},
408
+ {'name': 'Indent', 'title': 'Indent', 'css': 'wym_tools_indent'},
409
+ {'name': 'Outdent', 'title': 'Outdent', 'css': 'wym_tools_outdent'},
410
+ {'name': 'Undo', 'title': 'Undo', 'css': 'wym_tools_undo'},
411
+ {'name': 'Redo', 'title': 'Redo', 'css': 'wym_tools_redo'},
412
+ {'name': 'CreateLink', 'title': 'Link', 'css': 'wym_tools_link'},
413
+ {'name': 'Unlink', 'title': 'Unlink', 'css': 'wym_tools_unlink'},
414
+ {'name': 'InsertImage', 'title': 'Image', 'css': 'wym_tools_image'},
415
+ {'name': 'InsertTable', 'title': 'Table', 'css': 'wym_tools_table'},
416
+ {'name': 'Paste', 'title': 'Paste_From_Word',
417
+ 'css': 'wym_tools_paste'},
418
+ {'name': 'ToggleHtml', 'title': 'HTML', 'css': 'wym_tools_html'},
419
+ {'name': 'Preview', 'title': 'Preview', 'css': 'wym_tools_preview'}
420
+ ],
421
+
422
+ containersHtml: "<div class='wym_containers wym_section'>"
423
+ + "<h2>{Containers}</h2>"
424
+ + "<ul>"
425
+ + WYMeditor.CONTAINERS_ITEMS
426
+ + "</ul>"
427
+ + "</div>",
428
+
429
+ containersItemHtml:"<li class='"
430
+ + WYMeditor.CONTAINER_CLASS
431
+ + "'>"
432
+ + "<a href='#' name='"
433
+ + WYMeditor.CONTAINER_NAME
434
+ + "'>"
435
+ + WYMeditor.CONTAINER_TITLE
436
+ + "</a></li>",
437
+
438
+ containersItems: [
439
+ {'name': 'P', 'title': 'Paragraph', 'css': 'wym_containers_p'},
440
+ {'name': 'H1', 'title': 'Heading_1', 'css': 'wym_containers_h1'},
441
+ {'name': 'H2', 'title': 'Heading_2', 'css': 'wym_containers_h2'},
442
+ {'name': 'H3', 'title': 'Heading_3', 'css': 'wym_containers_h3'},
443
+ {'name': 'H4', 'title': 'Heading_4', 'css': 'wym_containers_h4'},
444
+ {'name': 'H5', 'title': 'Heading_5', 'css': 'wym_containers_h5'},
445
+ {'name': 'H6', 'title': 'Heading_6', 'css': 'wym_containers_h6'},
446
+ {'name': 'PRE', 'title': 'Preformatted', 'css': 'wym_containers_pre'},
447
+ {'name': 'BLOCKQUOTE', 'title': 'Blockquote',
448
+ 'css': 'wym_containers_blockquote'},
449
+ {'name': 'TH', 'title': 'Table_Header', 'css': 'wym_containers_th'}
450
+ ],
451
+
452
+ classesHtml: "<div class='wym_classes wym_section'>"
453
+ + "<h2>{Classes}</h2><ul>"
454
+ + WYMeditor.CLASSES_ITEMS
455
+ + "</ul></div>",
456
+
457
+ classesItemHtml: "<li><a href='#' name='"
458
+ + WYMeditor.CLASS_NAME
459
+ + "'>"
460
+ + WYMeditor.CLASS_TITLE
461
+ + "</a></li>",
462
+
463
+ classesItems: [],
464
+
465
+ statusHtml: "<div class='wym_status wym_section'>"
466
+ + "<h2>{Status}</h2>"
467
+ + "</div>",
468
+
469
+ htmlHtml: "<div class='wym_html wym_section'>"
470
+ + "<h2>{Source_Code}</h2>"
471
+ + "<textarea class='wym_html_val'></textarea>"
472
+ + "</div>",
473
+
474
+ boxSelector: ".wym_box",
475
+ toolsSelector: ".wym_tools",
476
+ toolsListSelector: " ul",
477
+ containersSelector:".wym_containers",
478
+ classesSelector: ".wym_classes",
479
+ htmlSelector: ".wym_html",
480
+ iframeSelector: ".wym_iframe iframe",
481
+ iframeBodySelector:".wym_iframe",
482
+ statusSelector: ".wym_status",
483
+ toolSelector: ".wym_tools a",
484
+ containerSelector: ".wym_containers a",
485
+ classSelector: ".wym_classes a",
486
+ classUnhiddenSelector: ".wym_classes",
487
+ classHiddenSelector: ".wym_classes_hidden",
488
+ htmlValSelector: ".wym_html_val",
489
+
490
+ hrefSelector: ".wym_href",
491
+ srcSelector: ".wym_src",
492
+ titleSelector: ".wym_title",
493
+ targetSelector: ".wym_target",
494
+ altSelector: ".wym_alt",
495
+ textSelector: ".wym_text",
496
+
497
+ rowsSelector: ".wym_rows",
498
+ colsSelector: ".wym_cols",
499
+ captionSelector: ".wym_caption",
500
+ summarySelector: ".wym_summary",
501
+
502
+ submitSelector: ".wym_submit",
503
+ cancelSelector: ".wym_cancel",
504
+ previewSelector: "",
505
+
506
+ dialogTypeSelector: ".wym_dialog_type",
507
+ dialogLinkSelector: ".wym_dialog_link",
508
+ dialogImageSelector: ".wym_dialog_image",
509
+ dialogTableSelector: ".wym_dialog_table",
510
+ dialogPasteSelector: ".wym_dialog_paste",
511
+ dialogPreviewSelector: ".wym_dialog_preview",
512
+
513
+ updateSelector: ".wymupdate",
514
+ updateEvent: "click",
515
+
516
+ dialogFeatures: "menubar=no,titlebar=no,toolbar=no,resizable=no"
517
+ + ",width=560,height=300,top=0,left=0",
518
+
519
+ dialogHtml: "<!DOCTYPE html PUBLIC '-//W3C//DTD XHTML 1.0 Strict//EN'"
520
+ + " 'http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd'>"
521
+ + "<html dir='"
522
+ + WYMeditor.DIRECTION
523
+ + "'><head>"
524
+ + "<link rel='stylesheet' type='text/css' media='screen'"
525
+ + " href='"
526
+ + WYMeditor.CSS_PATH
527
+ + "' />"
528
+ + "<title>"
529
+ + WYMeditor.DIALOG_TITLE
530
+ + "</title>"
531
+ + "<script type='text/javascript'"
532
+ + " src='"
533
+ + WYMeditor.JQUERY_PATH
534
+ + "'></script>"
535
+ + "<script type='text/javascript'"
536
+ + " src='"
537
+ + WYMeditor.WYM_PATH
538
+ + "'></script>"
539
+ + "</head>"
540
+ + WYMeditor.DIALOG_BODY
541
+ + "</html>",
542
+
543
+ dialogLinkHtml: "<div class='wym_dialog wym_dialog_link'>"
544
+ + "<form>"
545
+ + "<fieldset>"
546
+ + "<input type='hidden' id='wym_dialog_type' class='wym_dialog_type' value='"
547
+ + WYMeditor.DIALOG_LINK
548
+ + "' />"
549
+ + "<legend>{Link}</legend>"
550
+ + "<div class='row'>"
551
+ + "<label>{URL}</label>"
552
+ + "<input type='text' class='wym_href' value='' size='40' />"
553
+ + "</div>"
554
+ + "<div class='row'>"
555
+ + "<label>{Title}</label>"
556
+ + "<input type='text' class='wym_title' value='' size='40' />"
557
+ + "</div>"
558
+ + "<div class='row row-indent'>"
559
+ + "<input class='wym_submit' type='button'"
560
+ + " value='{Submit}' />"
561
+ + "<input class='wym_cancel' type='button'"
562
+ + "value='{Cancel}' />"
563
+ + "</div>"
564
+ + "</fieldset>"
565
+ + "</form>"
566
+ + "</div>",
567
+
568
+ dialogImageHtml: "<div class='wym_dialog wym_dialog_image'>"
569
+ + "<form>"
570
+ + "<fieldset>"
571
+ + "<input type='hidden' id='wym_dialog_type' class='wym_dialog_type' value='"
572
+ + WYMeditor.DIALOG_IMAGE
573
+ + "' />"
574
+ + "<legend>{Image}</legend>"
575
+ + "<div class='row'>"
576
+ + "<label>{URL}</label>"
577
+ + "<input type='text' class='wym_src' value='' size='40' />"
578
+ + "</div>"
579
+ + "<div class='row'>"
580
+ + "<label>{Alternative_Text}</label>"
581
+ + "<input type='text' class='wym_alt' value='' size='40' />"
582
+ + "</div>"
583
+ + "<div class='row'>"
584
+ + "<label>{Title}</label>"
585
+ + "<input type='text' class='wym_title' value='' size='40' />"
586
+ + "</div>"
587
+ + "<div class='row row-indent'>"
588
+ + "<input class='wym_submit' type='button'"
589
+ + " value='{Submit}' />"
590
+ + "<input class='wym_cancel' type='button'"
591
+ + "value='{Cancel}' />"
592
+ + "</div>"
593
+ + "</fieldset>"
594
+ + "</form>"
595
+ + "</div>",
596
+
597
+ dialogTableHtml: "<div class='wym_dialog wym_dialog_table'>"
598
+ + "<form>"
599
+ + "<input type='hidden' id='wym_dialog_type' class='wym_dialog_type' value='"
600
+ + WYMeditor.DIALOG_TABLE
601
+ + "' />"
602
+ + "<div class='row'>"
603
+ + "<label>{Caption}</label>"
604
+ + "<input type='text' class='wym_caption' value='' size='40' />"
605
+ + "</div>"
606
+ + "<div class='row'>"
607
+ + "<label>{Summary}</label>"
608
+ + "<input type='text' class='wym_summary' value='' size='40' />"
609
+ + "</div>"
610
+ + "<div class='row'>"
611
+ + "<label>{Number_Of_Rows}</label>"
612
+ + "<input type='text' class='wym_rows' value='3' size='3' />"
613
+ + "</div>"
614
+ + "<div class='row'>"
615
+ + "<label>{Number_Of_Cols}</label>"
616
+ + "<input type='text' class='wym_cols' value='2' size='3' />"
617
+ + "</div>"
618
+ + "<div class='row row-indent'>"
619
+ + "<input class='wym_submit' type='button'"
620
+ + " value='{Submit}' />"
621
+ + "<input class='wym_cancel' type='button'"
622
+ + "value='{Cancel}' />"
623
+ + "</div>"
624
+ + "</form>"
625
+ + "</div>",
626
+
627
+ dialogPasteHtml: "<div class='wym_dialog wym_dialog_paste'>"
628
+ + "<form>"
629
+ + "<input type='hidden' id='wym_dialog_type' class='wym_dialog_type' value='"
630
+ + WYMeditor.DIALOG_PASTE
631
+ + "' />"
632
+ + "<fieldset>"
633
+ + "<legend>{Paste_From_Word}</legend>"
634
+ + "<div class='row'>"
635
+ + "<textarea class='wym_text' rows='10' cols='50'></textarea>"
636
+ + "</div>"
637
+ + "<div class='row'>"
638
+ + "<input class='wym_submit' type='button'"
639
+ + " value='{Submit}' />"
640
+ + "<input class='wym_cancel' type='button'"
641
+ + "value='{Cancel}' />"
642
+ + "</div>"
643
+ + "</fieldset>"
644
+ + "</form>"
645
+ + "</div>",
646
+
647
+ dialogPreviewHtml: "<div class='wym_dialog wym_dialog_preview'></div>",
648
+
649
+ dialogStyles: [],
650
+
651
+ stringDelimiterLeft: "{",
652
+ stringDelimiterRight:"}",
653
+
654
+ preInit: null,
655
+ preBind: null,
656
+ postInit: null,
657
+
658
+ preInitDialog: null,
659
+ postInitDialog: null
660
+
661
+ }, options);
662
+
663
+ return this.each(function() {
664
+
665
+ new WYMeditor.editor($(this),options);
666
+ });
667
+ };
668
+
669
+ /* @name extend
670
+ * @description Returns the WYMeditor instance based on its index
671
+ */
672
+ $.extend({
673
+ wymeditors: function(i) {
674
+ return (WYMeditor.INSTANCES[i]);
675
+ }
676
+ });
677
+
678
+ /********** WYMeditor **********/
679
+
680
+ /* @name Wymeditor
681
+ * @description WYMeditor class
682
+ */
683
+
684
+ /* @name init
685
+ * @description Initializes a WYMeditor instance
686
+ */
687
+ WYMeditor.editor.prototype.init = function() {
688
+
689
+ //load subclass - browser specific
690
+ //unsupported browsers: do nothing
691
+
692
+ if ($.browser.msie) {
693
+ var WymClass = new WYMeditor.WymClassExplorer(this);
694
+ }
695
+ else if ($.browser.mozilla) {
696
+ var WymClass = new WYMeditor.WymClassMozilla(this);
697
+ }
698
+ else if ($.browser.opera) {
699
+ var WymClass = new WYMeditor.WymClassOpera(this);
700
+ }
701
+ else if ($.browser.safari) {
702
+ var WymClass = new WYMeditor.WymClassSafari(this);
703
+ }
704
+
705
+ if(WymClass) {
706
+
707
+ if($.isFunction(this._options.preInit)) this._options.preInit(this);
708
+
709
+ var SaxListener = new WYMeditor.XhtmlSaxListener();
710
+ $.extend(SaxListener, WymClass);
711
+ this.parser = new WYMeditor.XhtmlParser(SaxListener);
712
+
713
+ if(this._options.styles || this._options.stylesheet){
714
+ this.configureEditorUsingRawCss();
715
+ }
716
+
717
+ this.helper = new WYMeditor.XmlHelper();
718
+
719
+ //extend the Wymeditor object
720
+ //don't use $.extend since 1.1.4
721
+ //$.extend(this, WymClass);
722
+ for (var prop in WymClass) { this[prop] = WymClass[prop]; }
723
+
724
+ //load wymbox
725
+ this._box = $(this._element).hide().after(this._options.boxHtml).next();
726
+
727
+ //store the instance index in the wymbox element
728
+ //but keep it compatible with jQuery < 1.2.3, see #122
729
+ if( $.isFunction( $.fn.data ) )
730
+ $.data(this._box.get(0), WYMeditor.WYM_INDEX, this._index);
731
+
732
+ var h = WYMeditor.Helper;
733
+
734
+ //construct the iframe
735
+ var iframeHtml = this._options.iframeHtml;
736
+ iframeHtml = h.replaceAll(iframeHtml, WYMeditor.INDEX, this._index);
737
+ iframeHtml = h.replaceAll(iframeHtml, WYMeditor.IFRAME_BASE_PATH, this._options.iframeBasePath);
738
+
739
+ //construct wymbox
740
+ var boxHtml = $(this._box).html();
741
+
742
+ boxHtml = h.replaceAll(boxHtml, WYMeditor.LOGO, this._options.logoHtml);
743
+ boxHtml = h.replaceAll(boxHtml, WYMeditor.TOOLS, this._options.toolsHtml);
744
+ boxHtml = h.replaceAll(boxHtml, WYMeditor.CONTAINERS,this._options.containersHtml);
745
+ boxHtml = h.replaceAll(boxHtml, WYMeditor.CLASSES, this._options.classesHtml);
746
+ boxHtml = h.replaceAll(boxHtml, WYMeditor.HTML, this._options.htmlHtml);
747
+ boxHtml = h.replaceAll(boxHtml, WYMeditor.IFRAME, iframeHtml);
748
+ boxHtml = h.replaceAll(boxHtml, WYMeditor.STATUS, this._options.statusHtml);
749
+
750
+ //construct tools list
751
+ var aTools = eval(this._options.toolsItems);
752
+ var sTools = "";
753
+
754
+ for(var i = 0; i < aTools.length; i++) {
755
+ var oTool = aTools[i];
756
+ if(oTool.name && oTool.title)
757
+ var sTool = this._options.toolsItemHtml;
758
+ var sTool = h.replaceAll(sTool, WYMeditor.TOOL_NAME, oTool.name);
759
+ sTool = h.replaceAll(sTool, WYMeditor.TOOL_TITLE, this._options.stringDelimiterLeft
760
+ + oTool.title
761
+ + this._options.stringDelimiterRight);
762
+ sTool = h.replaceAll(sTool, WYMeditor.TOOL_CLASS, oTool.css);
763
+ sTools += sTool;
764
+ }
765
+
766
+ boxHtml = h.replaceAll(boxHtml, WYMeditor.TOOLS_ITEMS, sTools);
767
+
768
+ //construct classes list
769
+ var aClasses = eval(this._options.classesItems);
770
+ var sClasses = "";
771
+
772
+ for(var i = 0; i < aClasses.length; i++) {
773
+ var oClass = aClasses[i];
774
+ if(oClass.name) {
775
+ if (oClass.rules && oClass.rules.length > 0) {
776
+ var sRules = "";
777
+ var wym = this;
778
+ $.each(oClass.rules, function(index, rule) {
779
+ sClass = wym._options.classesItemHtml;
780
+ sClass = h.replaceAll(sClass, WYMeditor.CLASS_NAME, oClass.name + (oClass.join || "") + rule);
781
+ sClass = h.replaceAll(sClass, WYMeditor.CLASS_TITLE, rule.title || titleize(rule));
782
+ sRules += sClass;
783
+ });
784
+
785
+ var sClassMultiple = this._options.classesItemHtmlMultiple;
786
+ sClassMultiple = h.replaceAll(sClassMultiple, WYMeditor.CLASS_TITLE, oClass.title || titleize(oClass.name));
787
+ sClassMultiple = h.replaceAll(sClassMultiple, '{classesItemHtml}', sRules);
788
+ sClasses += sClassMultiple;
789
+ }
790
+ else {
791
+ sClass = this._options.classesItemHtml;
792
+ sClass = h.replaceAll(sClass, WYMeditor.CLASS_NAME, oClass.name);
793
+ sClass = h.replaceAll(sClass, WYMeditor.CLASS_TITLE, oClass.title || titleize(oClass.name));
794
+ sClasses += sClass;
795
+ }
796
+ }
797
+ }
798
+
799
+ boxHtml = h.replaceAll(boxHtml, WYMeditor.CLASSES_ITEMS, sClasses);
800
+
801
+ //construct containers list
802
+ var aContainers = eval(this._options.containersItems);
803
+ var sContainers = "";
804
+
805
+ for(var i = 0; i < aContainers.length; i++) {
806
+ var oContainer = aContainers[i];
807
+ if(oContainer.name && oContainer.title)
808
+ var sContainer = this._options.containersItemHtml;
809
+ sContainer = h.replaceAll(sContainer, WYMeditor.CONTAINER_NAME, oContainer.name);
810
+ sContainer = h.replaceAll(sContainer, WYMeditor.CONTAINER_TITLE,
811
+ this._options.stringDelimiterLeft
812
+ + oContainer.title
813
+ + this._options.stringDelimiterRight);
814
+ sContainer = h.replaceAll(sContainer, WYMeditor.CONTAINER_CLASS, oContainer.css);
815
+ sContainers += sContainer;
816
+ }
817
+
818
+ boxHtml = h.replaceAll(boxHtml, WYMeditor.CONTAINERS_ITEMS, sContainers);
819
+
820
+ //l10n
821
+ boxHtml = this.replaceStrings(boxHtml);
822
+
823
+ //load html in wymbox
824
+ $(this._box).html(boxHtml);
825
+
826
+ //hide the html value
827
+ $(this._box).find(this._options.htmlSelector).hide();
828
+
829
+ //enable the skin
830
+ this.loadSkin();
831
+
832
+ }
833
+ };
834
+
835
+ WYMeditor.editor.prototype.bindEvents = function() {
836
+
837
+ //copy the instance
838
+ var wym = this;
839
+
840
+ //handle click event on tools buttons
841
+ $(this._box).find(this._options.toolSelector).click(function() {
842
+ wym.exec($(this).attr(WYMeditor.NAME));
843
+ return(false);
844
+ });
845
+
846
+ //handle click event on containers buttons
847
+ $(this._box).find(this._options.containerSelector).click(function() {
848
+ wym.container($(this).attr(WYMeditor.NAME));
849
+ return(false);
850
+ });
851
+
852
+ //handle keyup event on html value: set the editor value
853
+ $(this._box).find(this._options.htmlValSelector).keyup(function() {
854
+ $(wym._doc.body).html($(this).val());
855
+ });
856
+
857
+ //handle click event on classes buttons
858
+ $(this._box).find(this._options.classSelector).click(function() {
859
+
860
+ var aClasses = eval(wym._options.classesItems);
861
+ var sName = $(this).attr(WYMeditor.NAME);
862
+ var oClass = WYMeditor.Helper.findByName(aClasses, sName);
863
+ var replacers = $([]);
864
+ if (oClass == null) {
865
+ $.each(aClasses, function(index, classRule){
866
+ if (oClass == null && classRule.rules && classRule.rules.length > 0){
867
+ if ((indexOf = $.inArray(sName.replace(classRule.name + (classRule.join || ""), ""), classRule.rules)) > -1) {
868
+ $.each(classRule.rules, function(i, rule) {
869
+ if (i != indexOf) {
870
+ replacers.push(classRule.name + (classRule.join || "") + rule);
871
+ }
872
+ });
873
+
874
+ oClass = {expr: (classRule.rules[indexOf].expr || null)}
875
+ }
876
+ }
877
+ });
878
+ }
879
+
880
+ if(oClass) {
881
+ // remove all related classes.
882
+ replacers.each(function(index, removable_class){
883
+ wym.removeClass(removable_class, oClass.expr);
884
+ });
885
+
886
+ wym.toggleClass(sName, oClass.expr);
887
+ }
888
+
889
+ // now hide the menu
890
+ wym.exec(WYMeditor.APPLY_CLASS);
891
+
892
+ return(false);
893
+ });
894
+
895
+ //handle event on update element
896
+ $(this._options.updateSelector).bind(this._options.updateEvent, function() {
897
+ wym.update();
898
+ });
899
+ };
900
+
901
+ WYMeditor.editor.prototype.ready = function() {
902
+ return(this._doc != null);
903
+ };
904
+
905
+
906
+ /********** METHODS **********/
907
+
908
+ /* @name box
909
+ * @description Returns the WYMeditor container
910
+ */
911
+ WYMeditor.editor.prototype.box = function() {
912
+ return(this._box);
913
+ };
914
+
915
+ /* @name html
916
+ * @description Get/Set the html value
917
+ */
918
+ WYMeditor.editor.prototype.html = function(html) {
919
+
920
+ if(typeof html === 'string') $(this._doc.body).html(html);
921
+ else return($(this._doc.body).html());
922
+ };
923
+
924
+ /* @name intercept_paste
925
+ * @description Catch the browser paste action and open the appropriate dialog instead
926
+ */
927
+ WYMeditor.editor.prototype.intercept_paste = function(e) {
928
+ var wym = WYMeditor.INSTANCES[this.title];
929
+ wym.exec(WYMeditor.PASTE);
930
+ e.preventDefault();
931
+ }
932
+
933
+ /* @name xhtml
934
+ * @description Cleans up the HTML
935
+ */
936
+ WYMeditor.editor.prototype.xhtml = function() {
937
+ return this.parser.parse(this.html());
938
+ };
939
+
940
+ /* @name exec
941
+ * @description Executes a button command
942
+ */
943
+ WYMeditor.editor.prototype.exec = function(cmd) {
944
+
945
+ //base function for execCommand
946
+ //open a dialog or exec
947
+ switch(cmd) {
948
+ case WYMeditor.CREATE_LINK:
949
+ if((container = this.container()) || this._selected_image) {
950
+ this.dialog(WYMeditor.DIALOG_LINK);
951
+ }
952
+ break;
953
+
954
+ case WYMeditor.INSERT_IMAGE:
955
+ this.dialog(WYMeditor.DIALOG_IMAGE);
956
+ break;
957
+
958
+ case WYMeditor.INSERT_TABLE:
959
+ this.dialog(WYMeditor.DIALOG_TABLE);
960
+ break;
961
+
962
+ case WYMeditor.PASTE:
963
+ this.dialog(WYMeditor.DIALOG_PASTE);
964
+ break;
965
+
966
+ case WYMeditor.TOGGLE_HTML:
967
+ this.update();
968
+ this.toggleHtml();
969
+
970
+ //partially fixes #121 when the user manually inserts an image
971
+ if(!$(this._box).find(this._options.htmlSelector).is(':visible')) {
972
+ this.listen();
973
+ }
974
+ break;
975
+
976
+ case WYMeditor.PREVIEW:
977
+ this.dialog(WYMeditor.PREVIEW);
978
+ break;
979
+
980
+ case WYMeditor.APPLY_CLASS:
981
+ wym = this;
982
+ $(wym._box).find(this._options.classUnhiddenSelector).toggleClass(this._options.classHiddenSelector.substring(1)); // substring(1) to remove the . at the start
983
+ $(wym._box).find("a[name=" + WYMeditor.APPLY_CLASS +"]").toggleClass('selected').parent().toggleClass('activated');
984
+ // determine whether any classes are already selected and add the enabled class to them.
985
+ $(wym._box).find(this._options.classUnhiddenSelector).find("a[name]").each(function(index, rule){
986
+ if ($(wym.selected()).hasClass($(rule).attr('name'))) {
987
+ $(rule).parent().addClass('enabled');
988
+ } else {
989
+ $(rule).parent().removeClass('enabled');
990
+ }
991
+ });
992
+ break;
993
+
994
+ default:
995
+ this._exec(cmd);
996
+ break;
997
+ }
998
+ };
999
+
1000
+ /* @name container
1001
+ * @description Get/Set the selected container
1002
+ */
1003
+ WYMeditor.editor.prototype.container = function(sType) {
1004
+
1005
+ if(sType) {
1006
+
1007
+ var container = null;
1008
+
1009
+ if(sType.toLowerCase() == WYMeditor.TH) {
1010
+
1011
+ container = this.container();
1012
+
1013
+ //find the TD or TH container
1014
+ switch(container.tagName.toLowerCase()) {
1015
+
1016
+ case WYMeditor.TD: case WYMeditor.TH:
1017
+ break;
1018
+ default:
1019
+ var aTypes = new Array(WYMeditor.TD,WYMeditor.TH);
1020
+ container = this.findUp(this.container(), aTypes);
1021
+ break;
1022
+ }
1023
+
1024
+ //if it exists, switch
1025
+ if(container!=null) {
1026
+
1027
+ sType = (container.tagName.toLowerCase() == WYMeditor.TD)? WYMeditor.TH: WYMeditor.TD;
1028
+ this.switchTo(container,sType);
1029
+ this.update();
1030
+ }
1031
+ } else {
1032
+
1033
+ //set the container type
1034
+ var aTypes=new Array(WYMeditor.P,WYMeditor.H1,WYMeditor.H2,WYMeditor.H3,WYMeditor.H4,WYMeditor.H5,
1035
+ WYMeditor.H6,WYMeditor.PRE,WYMeditor.BLOCKQUOTE);
1036
+
1037
+ container = this.findUp(this.container(), aTypes);
1038
+
1039
+ if(container) {
1040
+
1041
+ var newNode = null;
1042
+
1043
+ //blockquotes must contain a block level element
1044
+ if(sType.toLowerCase() == WYMeditor.BLOCKQUOTE) {
1045
+
1046
+ var blockquote = this.findUp(this.container(), WYMeditor.BLOCKQUOTE);
1047
+
1048
+ if(blockquote == null) {
1049
+
1050
+ newNode = this._doc.createElement(sType);
1051
+ container.parentNode.insertBefore(newNode,container);
1052
+ newNode.appendChild(container);
1053
+ this.setFocusToNode(newNode.firstChild);
1054
+
1055
+ } else {
1056
+
1057
+ var nodes = blockquote.childNodes;
1058
+ var lgt = nodes.length;
1059
+ var firstNode = null;
1060
+
1061
+ if(lgt > 0) firstNode = nodes.item(0);
1062
+ for(var x=0; x<lgt; x++) {
1063
+ blockquote.parentNode.insertBefore(nodes.item(0),blockquote);
1064
+ }
1065
+ blockquote.parentNode.removeChild(blockquote);
1066
+ if(firstNode) this.setFocusToNode(firstNode);
1067
+ }
1068
+ }
1069
+
1070
+ else
1071
+ {
1072
+ this.setFocusToNode(this.switchTo(container,sType));
1073
+ }
1074
+
1075
+ this.update();
1076
+ }
1077
+ }
1078
+ }
1079
+ else return(this.selected());
1080
+ };
1081
+
1082
+ /* @name toggleClass
1083
+ * @description Toggles class on selected element, or one of its parents
1084
+ */
1085
+ WYMeditor.editor.prototype.toggleClass = function(sClass, jqexpr) {
1086
+
1087
+ var container = $((this._selected_image ? this._selected_image : this.selected(true)));
1088
+ if (jqexpr != null) { container = $(container.parentsOrSelf(jqexpr)); }
1089
+ container.toggleClass(sClass);
1090
+ if(!container.attr(WYMeditor.CLASS)) container.removeAttr(this._class);
1091
+
1092
+ };
1093
+
1094
+ /* @name removeClass
1095
+ * @description Removes class on selected element, or one of its parents
1096
+ */
1097
+ WYMeditor.editor.prototype.removeClass = function(sClass, jqexpr) {
1098
+
1099
+ var container = $((this._selected_image ? this._selected_image : $(this.selected(true))));
1100
+ if (jqexpr != null) { container = $(container.parentsOrSelf(jqexpr)); }
1101
+ container.removeClass(sClass);
1102
+
1103
+ if(!container.attr(WYMeditor.CLASS)) container.removeAttr(this._class);
1104
+
1105
+ }
1106
+
1107
+ /* @name findUp
1108
+ * @description Returns the first parent or self container, based on its type
1109
+ */
1110
+ WYMeditor.editor.prototype.findUp = function(node, filter) {
1111
+
1112
+ //filter is a string or an array of strings
1113
+
1114
+ if(node) {
1115
+
1116
+ var tagname = node.tagName.toLowerCase();
1117
+
1118
+ if(typeof(filter) == WYMeditor.STRING) {
1119
+
1120
+ while(tagname != filter && tagname != WYMeditor.BODY) {
1121
+
1122
+ node = node.parentNode;
1123
+ tagname = node.tagName.toLowerCase();
1124
+ }
1125
+
1126
+ } else {
1127
+
1128
+ var bFound = false;
1129
+
1130
+ while(!bFound && tagname != WYMeditor.BODY) {
1131
+ for(var i = 0; i < filter.length; i++) {
1132
+ if(tagname == filter[i]) {
1133
+ bFound = true;
1134
+ break;
1135
+ }
1136
+ }
1137
+ if(!bFound) {
1138
+ node = node.parentNode;
1139
+ tagname = node.tagName.toLowerCase();
1140
+ }
1141
+ }
1142
+ }
1143
+
1144
+ if(tagname != WYMeditor.BODY) return(node);
1145
+ else return(null);
1146
+
1147
+ } else return(null);
1148
+ };
1149
+
1150
+ /* @name switchTo
1151
+ * @description Switch the node's type
1152
+ */
1153
+ WYMeditor.editor.prototype.switchTo = function(selectionOrNode,sType) {
1154
+
1155
+ if (selectionOrNode.getRangeAt) {
1156
+ // We have a selection object so we need to create a temporary node around it (bold is easy). This node will be replaced anyway.
1157
+ this.exec(WYMeditor.BOLD);
1158
+ selectionOrNode = selectionOrNode.focusNode.parentNode;
1159
+ }
1160
+
1161
+ // we have a node.
1162
+ var html = $(selectionOrNode).html();
1163
+ var newNode = this._doc.createElement(sType);
1164
+
1165
+ // copy across the css class names.
1166
+ $.each($(selectionOrNode).attr('class').split(" "), function(index, className) {
1167
+ $(newNode).addClass(className);
1168
+ });
1169
+
1170
+ selectionOrNode.parentNode.replaceChild(newNode,selectionOrNode);
1171
+
1172
+ $(newNode).html(html);
1173
+ this.setFocusToNode(newNode);
1174
+
1175
+ return newNode;
1176
+ };
1177
+
1178
+ WYMeditor.editor.prototype.replaceStrings = function(sVal) {
1179
+ //check if the language file has already been loaded
1180
+ //if not, get it via a synchronous ajax call
1181
+ var wym = this;
1182
+ if(!WYMeditor.STRINGS[wym._options.lang]) {
1183
+ try {
1184
+ eval($.ajax({url:wym._options.langPath + wym._options.lang + '.js', async:false}).responseText);
1185
+ } catch(e) {
1186
+ if (WYMeditor.console) {
1187
+ WYMeditor.console.error("WYMeditor: error while parsing language file.");
1188
+ }
1189
+ return sVal;
1190
+ }
1191
+ }
1192
+
1193
+ //replace all the strings in sVal and return it
1194
+ $.each(WYMeditor.STRINGS[wym._options.lang], function(key, value) {
1195
+ sVal = WYMeditor.Helper.replaceAll(sVal, wym.encloseString(key), value);
1196
+ })
1197
+
1198
+ return(sVal);
1199
+ };
1200
+
1201
+ WYMeditor.editor.prototype.encloseString = function(sVal) {
1202
+ return(this._options.stringDelimiterLeft + sVal + this._options.stringDelimiterRight);
1203
+ };
1204
+
1205
+ /* @name status
1206
+ * @description Prints a status message
1207
+ */
1208
+ WYMeditor.editor.prototype.status = function(sMessage) {
1209
+
1210
+ //print status message
1211
+ $(this._box).find(this._options.statusSelector).html(sMessage);
1212
+ };
1213
+
1214
+ /* @name update
1215
+ * @description Updates the element and textarea values
1216
+ */
1217
+ WYMeditor.editor.prototype.update = function() {
1218
+
1219
+ // the replace function below makes the HTML source code easier to read when end users need to use this view.
1220
+ var html = this.xhtml().replace(/<\/([A-Za-z0-9]*)></g, function(m){return m.split(">").join(">\n")});
1221
+ html = html.replace(/src=\"system\/images/, 'src="/system/images'); // make system/images calls absolute.
1222
+ html = html.replace(/(replace_me_with_wym-[0-9]*)/, ""); // get rid of replace_me_with_wym id tags that were forgotten about.
1223
+
1224
+ $(this._element).val(html);
1225
+ $(this._box).find(this._options.htmlValSelector).val(html);
1226
+ };
1227
+
1228
+ /* @name dialog
1229
+ * @description Opens a dialog box
1230
+ */
1231
+ WYMeditor.editor.prototype.dialog = function( dialogType ) {
1232
+ var path = this._wym._options.dialogPath + dialogType + this._wym._options.dialogFeatures;
1233
+
1234
+ this._current_unique_stamp = this.uniqueStamp();
1235
+ // change undo or redo on cancel to true to have this happen when a user closes (cancels) a dialogue
1236
+ this._undo_on_cancel = false;
1237
+ this._redo_on_cancel = false;
1238
+
1239
+ var selected = this.selected();
1240
+ //set to P if parent = BODY
1241
+ if ($.inArray(dialogType, [WYMeditor.DIALOG_TABLE, WYMeditor.DIALOG_PASTE]) == -1)
1242
+ {
1243
+ if (selected != null){
1244
+ if(selected.tagName.toLowerCase() == WYMeditor.BODY) {
1245
+ this._exec(WYMeditor.FORMAT_BLOCK, WYMeditor.P);
1246
+ }
1247
+ }
1248
+ else {
1249
+ // somehow select the wymeditor textarea or simulate a click or a keydown on it.
1250
+ }
1251
+ }
1252
+
1253
+ var wym = this;
1254
+ if (dialogType == WYMeditor.DIALOG_LINK && $.browser.mozilla) {
1255
+ selection = wym._iframe.contentWindow.getSelection();
1256
+ matches = $($(selected).html().match(new RegExp(selection.anchorNode.textContent + "(.*)" + selection.focusNode.textContent)));
1257
+ if (matches != null && matches.length > 0 && (possible_anchor_tag = matches.last()).length > 0) {
1258
+ if (((href_matches = possible_anchor_tag.get(0).match(/href="([^"]*)"/)) != null) && (href = $(href_matches).last().get(0)) != null) {
1259
+ $(wym._doc).find('a').each(function(index, possible_match) {
1260
+ if ($(possible_match).html() == selection) {
1261
+ selected = possible_match;
1262
+ }
1263
+ })
1264
+ }
1265
+ }
1266
+ }
1267
+
1268
+ // set up handlers.
1269
+ imageGroup = null;
1270
+ wym = this;
1271
+ ajax_loaded_callback = function(){wym.dialog_ajax_callback(selected)}
1272
+
1273
+ var parent_node = null;
1274
+ if (this._selected_image) {
1275
+ parent_node = this._selected_image.parentNode;
1276
+ }
1277
+ else {
1278
+ parent_node = selected;
1279
+ }
1280
+
1281
+ if ((parent_node != null) && (dialogType != WYMeditor.DIALOG_PASTE) && (parent_node.tagName.toLowerCase() != WYMeditor.A))
1282
+ {
1283
+ // wrap the current selection with a funky span (not required for safari)
1284
+ if (!this._selected_image && !$.browser.safari)
1285
+ {
1286
+ this.wrap("<span id='replace_me_with_" + this._current_unique_stamp + "'>", "</span>");
1287
+ }
1288
+ }
1289
+ else {
1290
+ if (!this._selected_image) {
1291
+ parent_node._id_before_replaceable = parent_node.id;
1292
+ parent_node.id = 'replace_me_with_' + this._current_unique_stamp;
1293
+ }
1294
+
1295
+ if (dialogType != WYMeditor.DIALOG_PASTE) {
1296
+ path += (this._wym._options.dialogFeatures.length == 0) ? "?" : "&";
1297
+ port = (window.location.port.length > 0 ? (":" + window.location.port) : "")
1298
+ path += "current_link=" + parent_node.href.replace(window.location.protocol + "//" + window.location.hostname + port, "");
1299
+ path += "&target_blank=" + (parent_node.target == "_blank" ? "true" : "false");
1300
+ }
1301
+ }
1302
+
1303
+ // launch thickbox
1304
+
1305
+ dialog_title = this.replaceStrings(this.encloseString( dialogType ));
1306
+ switch(dialogType) {
1307
+ case WYMeditor.DIALOG_TABLE: {
1308
+ dialog_container = document.createElement("div");
1309
+ dialog_container.id = 'inline_dialog_container';
1310
+ dialog_container.innerHTML = this.replaceStrings(this._options.dialogTableHtml);
1311
+ $(document.body).after(dialog_container);
1312
+
1313
+ tb_show(dialog_title, "#" + this._options.dialogInlineFeatures + "&inlineId=inline_dialog_container&TB_inline=true&modal=true", imageGroup);
1314
+ ajax_loaded_callback();
1315
+ break;
1316
+ }
1317
+ case WYMeditor.DIALOG_PASTE: {
1318
+ dialog_container = document.createElement("div");
1319
+ dialog_container.id = 'inline_dialog_container';
1320
+ dialog_container.innerHTML = this.replaceStrings(this._options.dialogPasteHtml);
1321
+ $(document.body).after(dialog_container);
1322
+
1323
+ tb_show(dialog_title, "#" + this._options.dialogInlineFeatures + "&inlineId=inline_dialog_container&TB_inline=true&modal=true", imageGroup);
1324
+ ajax_loaded_callback();
1325
+ break;
1326
+ }
1327
+ default:
1328
+ {
1329
+ tb_show(dialog_title, path, imageGroup, ajax_loaded_callback);
1330
+ break;
1331
+ }
1332
+ }
1333
+
1334
+ };
1335
+
1336
+ WYMeditor.editor.prototype.dialog_ajax_callback = function(selected) {
1337
+
1338
+ // look for iframes
1339
+ wym = this; _selected = selected;
1340
+ (iframes = $("#" + this._options.dialogId).find('iframe')).load(function() {
1341
+ WYMeditor.INIT_DIALOG(wym, _selected);
1342
+ $(this).unbind('load');
1343
+ });
1344
+
1345
+ if (iframes.length == 0) {
1346
+ WYMeditor.INIT_DIALOG(this, selected);
1347
+ }
1348
+ };
1349
+
1350
+ /* @name toggleHtml
1351
+ * @description Shows/Hides the HTML
1352
+ */
1353
+ WYMeditor.editor.prototype.toggleHtml = function() {
1354
+ $(this._box).find(this._options.htmlSelector).toggle();
1355
+ };
1356
+
1357
+ WYMeditor.editor.prototype.uniqueStamp = function() {
1358
+ return("wym-" + new Date().getTime());
1359
+ };
1360
+
1361
+ WYMeditor.editor.prototype.paste = function(sData) {
1362
+
1363
+ wym = this;
1364
+
1365
+ wym.format_block();
1366
+
1367
+ var sTmp;
1368
+ replaceable = $(wym._doc.body).find('#replace_me_with_' + wym._current_unique_stamp);
1369
+
1370
+ // replaceable doesn't actually get replaced here, it's just used as a marker for where the cursor was.
1371
+ var container = replaceable.get(0) || this.selected();
1372
+
1373
+ //split the data, using double newlines as the separator
1374
+ var aP = sData.split(wym._newLine + wym._newLine);
1375
+ var rExp = new RegExp(wym._newLine, "g");
1376
+
1377
+ //add a P for each item
1378
+ if(container && container.tagName.toLowerCase() != WYMeditor.BODY) {
1379
+ for(x = aP.length - 1; x >= 0; x--) {
1380
+ sTmp = aP[x];
1381
+ //simple newlines are replaced by a break
1382
+ sTmp = sTmp.replace(rExp, "<br />");
1383
+ if (x == 0 && $(container).html().replace(/<br\ ?\/?>/, "").length == 0) {
1384
+ $(container).html(sTmp);
1385
+ } else {
1386
+ $(container).after("<p>" + sTmp + "</p>");
1387
+ }
1388
+ }
1389
+ } else {
1390
+ for(x = 0; x < aP.length; x++) {
1391
+ sTmp = aP[x];
1392
+ //simple newlines are replaced by a break
1393
+ sTmp = sTmp.replace(rExp, "<br />");
1394
+ if (x == 0 && $(container).html().replace(/<br\ ?\/?>/, "").length == 0) {
1395
+ $(container).html(sTmp);
1396
+ } else {
1397
+ $(wym._doc.body).append("<p>" + sTmp + "</p>");
1398
+ }
1399
+ }
1400
+ }
1401
+
1402
+ if (replaceable.get(0) != null) {
1403
+ // set the id of the container back.
1404
+ replaceable.get(0).id = replaceable.get(0)._id_before_replaceable;
1405
+ }
1406
+ };
1407
+
1408
+ WYMeditor.editor.prototype.insert = function(html) {
1409
+ // Do we have a selection?
1410
+ if (this._iframe.contentWindow.getSelection().focusNode != null) {
1411
+ // Overwrite selection with provided html
1412
+ this._exec(WYMeditor.INSERT_HTML, html);
1413
+ } else {
1414
+ // Fall back to the internal paste function if there's no selection
1415
+ this.paste(html);
1416
+ }
1417
+ };
1418
+
1419
+ WYMeditor.editor.prototype.wrap = function(left, right, selection) {
1420
+ // Do we have a selection?
1421
+ if (selection == null) { selection = this._iframe.contentWindow.getSelection();}
1422
+ if (selection.focusNode != null) {
1423
+ // Wrap selection with provided html
1424
+ this._exec( WYMeditor.INSERT_HTML, left + selection.toString() + right);
1425
+ }
1426
+ };
1427
+
1428
+ WYMeditor.editor.prototype.unwrap = function(selection) {
1429
+ // Do we have a selection?
1430
+ if (selection == null) { selection = this._iframe.contentWindow.getSelection();}
1431
+ if (selection.focusNode != null) {
1432
+ // Unwrap selection
1433
+ this._exec( WYMeditor.INSERT_HTML, selection.toString() );
1434
+ }
1435
+ };
1436
+
1437
+ WYMeditor.editor.prototype.addCssRules = function(doc, aCss) {
1438
+ var styles = doc.styleSheets[0];
1439
+ if(styles) {
1440
+ for(var i = 0; i < aCss.length; i++) {
1441
+ var oCss = aCss[i];
1442
+ if(oCss.name && oCss.css) this.addCssRule(styles, oCss);
1443
+ }
1444
+ }
1445
+ };
1446
+
1447
+ WYMeditor.editor.prototype.format_block = function(selected) {
1448
+
1449
+ //'this' should be the wymeditor instance.
1450
+ var wym = this;
1451
+
1452
+ var container = selected || wym.selected();
1453
+
1454
+ wym._selected_image = null;
1455
+
1456
+ var name = container.tagName.toLowerCase();
1457
+
1458
+ //fix forbidden main containers
1459
+ if(
1460
+ name == "strong" ||
1461
+ name == "b" ||
1462
+ name == "em" ||
1463
+ name == "i" ||
1464
+ name == "sub" ||
1465
+ name == "sup" ||
1466
+ name == "a"
1467
+
1468
+ ) name = container.parentNode.tagName.toLowerCase();
1469
+
1470
+ if(name == WYMeditor.BODY) wym._exec(WYMeditor.FORMAT_BLOCK, WYMeditor.P);
1471
+ };
1472
+
1473
+ /********** CONFIGURATION **********/
1474
+
1475
+ WYMeditor.editor.prototype.computeBasePath = function() {
1476
+ if ((script_path = this.computeWymPath()) != null) {
1477
+ if ((src_parts = script_path.split('/')).length > 1) { src_parts.pop(); }
1478
+ return src_parts.join('/') + "/";
1479
+ }
1480
+ else {
1481
+ return null;
1482
+ }
1483
+ };
1484
+
1485
+ WYMeditor.editor.prototype.computeWymPath = function() {
1486
+ return $('script[src*=jquery.refinery.wymeditor]').attr('src');
1487
+ };
1488
+
1489
+ WYMeditor.editor.prototype.computeJqueryPath = function() {
1490
+ return $($.grep($('script'), function(s){
1491
+ return (s.src && s.src.match(/jquery(-(.*)){0,1}(\.pack|\.min|\.packed)?\.js(\?.*)?$/ ))
1492
+ })).attr('src');
1493
+ };
1494
+
1495
+ WYMeditor.editor.prototype.computeCssPath = function() {
1496
+ return $($.grep($('link'), function(s){
1497
+ return (s.href && s.href.match(/wymeditor\/skins\/(.*)screen\.css(\?.*)?$/ ))
1498
+ })).attr('href');
1499
+ };
1500
+
1501
+ WYMeditor.editor.prototype.configureEditorUsingRawCss = function() {
1502
+
1503
+ var CssParser = new WYMeditor.WymCssParser();
1504
+ if(this._options.stylesheet){
1505
+ CssParser.parse($.ajax({url: this._options.stylesheet,async:false}).responseText);
1506
+ }else{
1507
+ CssParser.parse(this._options.styles, false);
1508
+ }
1509
+
1510
+ if(this._options.classesItems.length == 0) {
1511
+ this._options.classesItems = CssParser.css_settings.classesItems;
1512
+ }
1513
+ if(this._options.editorStyles.length == 0) {
1514
+ this._options.editorStyles = CssParser.css_settings.editorStyles;
1515
+ }
1516
+ if(this._options.dialogStyles.length == 0) {
1517
+ this._options.dialogStyles = CssParser.css_settings.dialogStyles;
1518
+ }
1519
+ };
1520
+
1521
+ /********** EVENTS **********/
1522
+
1523
+ WYMeditor.editor.prototype.listen = function() {
1524
+
1525
+ //don't use $.find() on the iframe body
1526
+ //because of MSIE + jQuery + expando issue (#JQ1143)
1527
+ //$(this._doc.body).find("*").bind("mouseup", this.mouseup);
1528
+
1529
+ $(this._doc.body).bind("mousedown", this.mousedown);
1530
+ var images = this._doc.body.getElementsByTagName("img");
1531
+ for(var i=0; i < images.length; i++) {
1532
+ $(images[i]).bind("mousedown", this.mousedown);
1533
+ }
1534
+ };
1535
+
1536
+ WYMeditor.editor.prototype.mousedown = function(evt) {
1537
+
1538
+ var wym = WYMeditor.INSTANCES[this.ownerDocument.title];
1539
+ wym._selected_image = (this.tagName.toLowerCase() == WYMeditor.IMG) ? this : null;
1540
+ evt.stopPropagation();
1541
+ };
1542
+
1543
+ /********** SKINS **********/
1544
+
1545
+ /*
1546
+ * Function: WYMeditor.loadCss
1547
+ * Loads a stylesheet in the document.
1548
+ *
1549
+ * Parameters:
1550
+ * href - The CSS path.
1551
+ */
1552
+ WYMeditor.loadCss = function(href) {
1553
+
1554
+ var link = document.createElement('link');
1555
+ link.rel = 'stylesheet';
1556
+ link.href = href;
1557
+
1558
+ var head = $('head').get(0);
1559
+ head.appendChild(link);
1560
+ };
1561
+
1562
+ /*
1563
+ * Function: WYMeditor.editor.loadSkin
1564
+ * Loads the skin CSS and initialization script (if needed).
1565
+ */
1566
+ WYMeditor.editor.prototype.loadSkin = function() {
1567
+
1568
+ //does the user want to automatically load the CSS (default: yes)?
1569
+ //we also test if it hasn't been already loaded by another instance
1570
+ //see below for a better (second) test
1571
+ if(this._options.loadSkin && !WYMeditor.SKINS[this._options.skin]) {
1572
+
1573
+ //check if it hasn't been already loaded
1574
+ //so we don't load it more than once
1575
+ //(we check the existing <link> elements)
1576
+
1577
+ var found = false;
1578
+ var rExp = new RegExp(this._options.skin
1579
+ + '\/' + WYMeditor.SKINS_DEFAULT_CSS + '$');
1580
+
1581
+ $('link').each( function() {
1582
+ if(this.href.match(rExp)) found = true;
1583
+ });
1584
+
1585
+ //load it, using the skin path
1586
+ if(!found) WYMeditor.loadCss( this._options.cssSkinPath
1587
+ + WYMeditor.SKINS_DEFAULT_CSS );
1588
+ }
1589
+
1590
+ //put the classname (ex. wym_skin_default) on wym_box
1591
+ $(this._box).addClass( "wym_skin_" + this._options.skin );
1592
+
1593
+ //does the user want to use some JS to initialize the skin (default: yes)?
1594
+ //also check if it hasn't already been loaded by another instance
1595
+ if(this._options.initSkin && !WYMeditor.SKINS[this._options.skin]) {
1596
+
1597
+ eval($.ajax({url:this._options.jsSkinPath
1598
+ + WYMeditor.SKINS_DEFAULT_JS, async:false}).responseText);
1599
+ }
1600
+
1601
+ //init the skin, if needed
1602
+ if(WYMeditor.SKINS[this._options.skin] && WYMeditor.SKINS[this._options.skin].init)
1603
+ WYMeditor.SKINS[this._options.skin].init(this);
1604
+
1605
+ };
1606
+
1607
+
1608
+ /********** DIALOGS **********/
1609
+
1610
+ WYMeditor.INIT_DIALOG = function(wym, selected, isIframe) {
1611
+
1612
+ var selected = selected || wym.selected();
1613
+ var dialog = $("#"+wym._options.dialogId);
1614
+ var doc = (isIframe ? dialog.find('iframe').get(0).document() : document);
1615
+ var dialogType = dialog.find('#wym_dialog_type').val();
1616
+ var replaceable = wym._selected_image ? $(wym._selected_image) : $(wym._doc.body).find('#replace_me_with_' + wym._current_unique_stamp);
1617
+
1618
+ dialog.find(".close_dialog").click(function(e){
1619
+ wym.close_dialog(e, true);
1620
+ });
1621
+
1622
+ //pre-init functions
1623
+ if($.isFunction(wym._options.preInitDialog)) {
1624
+ wym._options.preInitDialog(wym, window);
1625
+ }
1626
+
1627
+ //auto populate image fields if selected image
1628
+ if(wym._selected_image) {
1629
+ $(wym._options.dialogImageSelector).find(wym._options.srcSelector).val($(wym._selected_image).attr(WYMeditor.SRC));
1630
+ $(wym._options.dialogImageSelector).find(wym._options.titleSelector).val($(wym._selected_image).attr(WYMeditor.TITLE));
1631
+ $(wym._options.dialogImageSelector).find(wym._options.altSelector).val($(wym._selected_image).attr(WYMeditor.ALT));
1632
+ }
1633
+
1634
+ $(wym._options.dialogLinkSelector).find(wym._options.submitSelector).click(function()
1635
+ {
1636
+ if ((sUrl = $(wym._options.hrefSelector).val()).length > 0)
1637
+ {
1638
+ if (replaceable.get(0) != null) {
1639
+ var link = $('<a></a>').attr({href:sUrl, title: $(wym._options.titleSelector).val()})
1640
+ if ((target = $(wym._options.targetSelector).val()) != null && target.length > 0) {
1641
+ link.attr('target', target);
1642
+ }
1643
+
1644
+ // now grab what was selected in the editor and chuck it inside the link.
1645
+ if (!wym._selected_image)
1646
+ {
1647
+ // ensure some attributes are copied across to the new link.
1648
+ link.attr({'style': replaceable.attr('style'), 'class': replaceable.attr('class')});
1649
+ replaceable.after(link);
1650
+ link.html(replaceable.html());
1651
+ replaceable.remove();
1652
+ }
1653
+ else
1654
+ {
1655
+ if ((parent = replaceable.get(0).parentNode) != null && parent.tagName.toUpperCase() == "A") {
1656
+ $(parent).attr({href: link.attr('href'), title: $(wym._options.titleSelector).val(), target: target});
1657
+ }
1658
+ else {
1659
+ replaceable.before(link);
1660
+ $(link).append(replaceable.get(0));
1661
+ }
1662
+ }
1663
+ }
1664
+ else {
1665
+ wym._exec(WYMeditor.CREATE_LINK, wym._current_unique_stamp);
1666
+
1667
+ $("a[href=" + wym._current_unique_stamp + "]", wym._doc.body)
1668
+ .attr(WYMeditor.HREF, sUrl)
1669
+ .attr(WYMeditor.TITLE, $(wym._options.titleSelector).val())
1670
+ .attr(WYMeditor.TARGET, $(wym._options.targetSelector).val());
1671
+ }
1672
+ }
1673
+ // fire a click event on the dialogs close button
1674
+ wym.close_dialog()
1675
+ });
1676
+
1677
+ $(wym._options.dialogImageSelector).find(wym._options.submitSelector).click(function() {
1678
+ form = $(this.form);
1679
+ if ((url = form.find(wym._options.srcSelector).val()) != null && url.length > 0) {
1680
+ wym._exec(WYMeditor.INSERT_IMAGE, wym._current_unique_stamp, selected);
1681
+
1682
+ var image = $(wym._doc.body).find("img[src*=" + wym._current_unique_stamp + "]");
1683
+
1684
+ if(image.length > 0) {
1685
+ image.attr(WYMeditor.SRC, url)
1686
+ .attr(WYMeditor.TITLE, form.find(wym._options.titleSelector).val())
1687
+ .attr(WYMeditor.ALT, form.find(wym._options.srcSelector).val());
1688
+
1689
+ if (!$.browser.safari && replaceable != null && (this._selected_image == null || (this._selected_image != null && replaceable.parentNode != null)))
1690
+ {
1691
+ replaceable.after(image).remove();
1692
+ }
1693
+ }
1694
+
1695
+ // fire a click event on the dialogs close button
1696
+ wym.close_dialog();
1697
+ }
1698
+ });
1699
+
1700
+ $(wym._options.dialogTableSelector).find(wym._options.submitSelector).click(function() {
1701
+ if((iRows = $(wym._options.rowsSelector).val()) > 0 && (iCols = $(wym._options.colsSelector).val()) > 0)
1702
+ {
1703
+ //create the table and the caption
1704
+ (table = wym._doc.createElement(WYMeditor.TABLE)).createCaption().innerHTML = $(wym._options.captionSelector).val();
1705
+
1706
+ //create the rows and cells
1707
+ for(x=0; x<iRows; x++) {
1708
+ newRow = table.insertRow(x);
1709
+ for(y=0; y<iCols; y++) {
1710
+ newRow.insertCell(y);
1711
+ }
1712
+ }
1713
+
1714
+ //append the table after the selected container
1715
+ var node = $(wym.findUp(wym.container(), WYMeditor.MAIN_CONTAINERS)).get(0);
1716
+ if(!node || !node.parentNode) $(wym._doc.body).append(table);
1717
+ else $(node).after(table);
1718
+ }
1719
+ // fire a click event on the dialogs close button
1720
+ wym.close_dialog();
1721
+ });
1722
+
1723
+ $(wym._options.dialogPasteSelector).find(wym._options.submitSelector).click(function() {
1724
+ wym.paste($(wym._options.textSelector).val());
1725
+
1726
+ wym.close_dialog();
1727
+ });
1728
+
1729
+ $(wym._options.dialogPreviewSelector).find(wym._options.previewSelector).html(wym.xhtml());
1730
+
1731
+ //post-init functions
1732
+ if($.isFunction(wym._options.postInitDialog)) {
1733
+ wym._options.postInitDialog(wym,window);
1734
+ }
1735
+ };
1736
+
1737
+ WYMeditor.editor.prototype.close_dialog = function(e, cancelled) {
1738
+ if (cancelled)
1739
+ {
1740
+ // if replaceable exists, replace it with its own html contents.
1741
+ if ((span = $(this._doc.body).find('span#replace_me_with_' + this._current_unique_stamp)).length > 0) {
1742
+ span.parent().html(span.parent().html().replace(new RegExp(["<span(.+?)", span.attr('id'), "(.+?)<\/span>"].join("")), span.html()));
1743
+ }
1744
+ (remove_id = $(this._doc.body).find('#replace_me_with_' + this._current_unique_stamp)).attr('id', (remove_id.attr('_id_before_replaceable') || ""));
1745
+
1746
+ if (this._undo_on_cancel == true) {
1747
+ this._exec("undo");
1748
+ }
1749
+ else if (this._redo_on_cancel == true) {
1750
+ this._exec("redo");
1751
+ }
1752
+ }
1753
+
1754
+ if ($.browser.msie && parseInt($.browser.version) < 8)
1755
+ {
1756
+ this._iframe.contentWindow.focus();
1757
+ }
1758
+
1759
+ $('#inline_dialog_container').remove();
1760
+
1761
+ tb_remove();
1762
+
1763
+ if (e) {
1764
+ e.preventDefault();
1765
+ }
1766
+ }
1767
+
1768
+ /********** XHTML LEXER/PARSER **********/
1769
+
1770
+ /*
1771
+ * @name xml
1772
+ * @description Use these methods to generate XML and XHTML compliant tags and
1773
+ * escape tag attributes correctly
1774
+ * @author Bermi Ferrer - http://bermi.org
1775
+ * @author David Heinemeier Hansson http://loudthinking.com
1776
+ */
1777
+ WYMeditor.XmlHelper = function()
1778
+ {
1779
+ this._entitiesDiv = document.createElement('div');
1780
+ return this;
1781
+ };
1782
+
1783
+
1784
+ /*
1785
+ * @name tag
1786
+ * @description
1787
+ * Returns an empty HTML tag of type *name* which by default is XHTML
1788
+ * compliant. Setting *open* to true will create an open tag compatible
1789
+ * with HTML 4.0 and below. Add HTML attributes by passing an attributes
1790
+ * array to *options*. For attributes with no value like (disabled and
1791
+ * readonly), give it a value of true in the *options* array.
1792
+ *
1793
+ * Examples:
1794
+ *
1795
+ * this.tag('br')
1796
+ * # => <br />
1797
+ * this.tag ('br', false, true)
1798
+ * # => <br>
1799
+ * this.tag ('input', $({type:'text',disabled:true }) )
1800
+ * # => <input type="text" disabled="disabled" />
1801
+ */
1802
+ WYMeditor.XmlHelper.prototype.tag = function(name, options, open)
1803
+ {
1804
+ options = options || false;
1805
+ open = open || false;
1806
+ return '<'+name+(options ? this.tagOptions(options) : '')+(open ? '>' : ' />');
1807
+ };
1808
+
1809
+ /*
1810
+ * @name contentTag
1811
+ * @description
1812
+ * Returns a XML block tag of type *name* surrounding the *content*. Add
1813
+ * XML attributes by passing an attributes array to *options*. For attributes
1814
+ * with no value like (disabled and readonly), give it a value of true in
1815
+ * the *options* array. You can use symbols or strings for the attribute names.
1816
+ *
1817
+ * this.contentTag ('p', 'Hello world!' )
1818
+ * # => <p>Hello world!</p>
1819
+ * this.contentTag('div', this.contentTag('p', "Hello world!"), $({class : "strong"}))
1820
+ * # => <div class="strong"><p>Hello world!</p></div>
1821
+ * this.contentTag("select", options, $({multiple : true}))
1822
+ * # => <select multiple="multiple">...options...</select>
1823
+ */
1824
+ WYMeditor.XmlHelper.prototype.contentTag = function(name, content, options)
1825
+ {
1826
+ options = options || false;
1827
+ return '<'+name+(options ? this.tagOptions(options) : '')+'>'+content+'</'+name+'>';
1828
+ };
1829
+
1830
+ /*
1831
+ * @name cdataSection
1832
+ * @description
1833
+ * Returns a CDATA section for the given +content+. CDATA sections
1834
+ * are used to escape blocks of text containing characters which would
1835
+ * otherwise be recognized as markup. CDATA sections begin with the string
1836
+ * <tt>&lt;![CDATA[</tt> and } with (and may not contain) the string
1837
+ * <tt>]]></tt>.
1838
+ */
1839
+ WYMeditor.XmlHelper.prototype.cdataSection = function(content)
1840
+ {
1841
+ return '<![CDATA['+content+']]>';
1842
+ };
1843
+
1844
+
1845
+ /*
1846
+ * @name escapeOnce
1847
+ * @description
1848
+ * Returns the escaped +xml+ without affecting existing escaped entities.
1849
+ *
1850
+ * this.escapeOnce( "1 > 2 &amp; 3")
1851
+ * # => "1 &gt; 2 &amp; 3"
1852
+ */
1853
+ WYMeditor.XmlHelper.prototype.escapeOnce = function(xml)
1854
+ {
1855
+ return this._fixDoubleEscape(this.escapeEntities(xml));
1856
+ };
1857
+
1858
+ /*
1859
+ * @name _fixDoubleEscape
1860
+ * @description
1861
+ * Fix double-escaped entities, such as &amp;amp;, &amp;#123;, etc.
1862
+ */
1863
+ WYMeditor.XmlHelper.prototype._fixDoubleEscape = function(escaped)
1864
+ {
1865
+ return escaped.replace(/&amp;([a-z]+|(#\d+));/ig, "&$1;");
1866
+ };
1867
+
1868
+ /*
1869
+ * @name tagOptions
1870
+ * @description
1871
+ * Takes an array like the one generated by Tag.parseAttributes
1872
+ * [["src", "http://www.editam.com/?a=b&c=d&amp;f=g"], ["title", "Editam, <Simplified> CMS"]]
1873
+ * or an object like {src:"http://www.editam.com/?a=b&c=d&amp;f=g", title:"Editam, <Simplified> CMS"}
1874
+ * and returns a string properly escaped like
1875
+ * ' src = "http://www.editam.com/?a=b&amp;c=d&amp;f=g" title = "Editam, &lt;Simplified&gt; CMS"'
1876
+ * which is valid for strict XHTML
1877
+ */
1878
+ WYMeditor.XmlHelper.prototype.tagOptions = function(options)
1879
+ {
1880
+ var xml = this;
1881
+ xml._formated_options = '';
1882
+
1883
+ for (var key in options) {
1884
+ var formated_options = '';
1885
+ var value = options[key];
1886
+ if(typeof value != 'function' && value.length > 0) {
1887
+
1888
+ if(parseInt(key) == key && typeof value == 'object'){
1889
+ key = value.shift();
1890
+ value = value.pop();
1891
+ }
1892
+ if(key != '' && value != ''){
1893
+ xml._formated_options += ' '+key+'="'+xml.escapeOnce(value)+'"';
1894
+ }
1895
+ }
1896
+ }
1897
+ return xml._formated_options;
1898
+ };
1899
+
1900
+ /*
1901
+ * @name escapeEntities
1902
+ * @description
1903
+ * Escapes XML/HTML entities <, >, & and ". If seccond parameter is set to false it
1904
+ * will not escape ". If set to true it will also escape '
1905
+ */
1906
+ WYMeditor.XmlHelper.prototype.escapeEntities = function(string, escape_quotes)
1907
+ {
1908
+ this._entitiesDiv.innerHTML = string;
1909
+ this._entitiesDiv.textContent = string;
1910
+ var result = this._entitiesDiv.innerHTML;
1911
+ if(typeof escape_quotes == 'undefined'){
1912
+ if(escape_quotes != false) result = result.replace('"', '&quot;');
1913
+ if(escape_quotes == true) result = result.replace('"', '&#039;');
1914
+ }
1915
+ return result;
1916
+ };
1917
+
1918
+ /*
1919
+ * Parses a string conatining tag attributes and values an returns an array formated like
1920
+ * [["src", "http://www.editam.com"], ["title", "Editam, Simplified CMS"]]
1921
+ */
1922
+ WYMeditor.XmlHelper.prototype.parseAttributes = function(tag_attributes)
1923
+ {
1924
+ // Use a compounded regex to match single quoted, double quoted and unquoted attribute pairs
1925
+ var result = [];
1926
+ var matches = tag_attributes.split(/((=\s*")(")("))|((=\s*\')(\')(\'))|((=\s*[^>\s]*))/g);
1927
+ if(matches.toString() != tag_attributes){
1928
+ for (var k in matches) {
1929
+ var v = matches[k];
1930
+ if(typeof v != 'function' && v.length != 0){
1931
+ var re = new RegExp('(\\w+)\\s*'+v);
1932
+ if(match = tag_attributes.match(re) ){
1933
+ var value = v.replace(/^[\s=]+/, "");
1934
+ var delimiter = value.charAt(0);
1935
+ delimiter = delimiter == '"' ? '"' : (delimiter=="'"?"'":'');
1936
+ if(delimiter != ''){
1937
+ value = delimiter == '"' ? value.replace(/^"|"+$/g, '') : value.replace(/^'|'+$/g, '');
1938
+ }
1939
+ tag_attributes = tag_attributes.replace(match[0],'');
1940
+ result.push([match[1] , value]);
1941
+ }
1942
+ }
1943
+ }
1944
+ }
1945
+ return result;
1946
+ };
1947
+
1948
+ /**
1949
+ * XhtmlValidator for validating tag attributes
1950
+ *
1951
+ * @author Bermi Ferrer - http://bermi.org
1952
+ */
1953
+ WYMeditor.XhtmlValidator = {
1954
+ "_attributes":
1955
+ {
1956
+ "core":
1957
+ {
1958
+ "except":[
1959
+ "base",
1960
+ "head",
1961
+ "html",
1962
+ "meta",
1963
+ "param",
1964
+ "script",
1965
+ "style",
1966
+ "title"
1967
+ ],
1968
+ "attributes":[
1969
+ "class",
1970
+ "id",
1971
+ "style",
1972
+ "title",
1973
+ "accesskey",
1974
+ "tabindex"
1975
+ ]
1976
+ },
1977
+ "language":
1978
+ {
1979
+ "except":[
1980
+ "base",
1981
+ "br",
1982
+ "hr",
1983
+ "iframe",
1984
+ "param",
1985
+ "script"
1986
+ ],
1987
+ "attributes":
1988
+ {
1989
+ "dir":[
1990
+ "ltr",
1991
+ "rtl"
1992
+ ],
1993
+ "0":"lang",
1994
+ "1":"xml:lang"
1995
+ }
1996
+ },
1997
+ "keyboard":
1998
+ {
1999
+ "attributes":
2000
+ {
2001
+ "accesskey":/^(\w){1}$/,
2002
+ "tabindex":/^(\d)+$/
2003
+ }
2004
+ }
2005
+ },
2006
+ "_events":
2007
+ {
2008
+ "window":
2009
+ {
2010
+ "only":[
2011
+ "body"
2012
+ ],
2013
+ "attributes":[
2014
+ "onload",
2015
+ "onunload"
2016
+ ]
2017
+ },
2018
+ "form":
2019
+ {
2020
+ "only":[
2021
+ "form",
2022
+ "input",
2023
+ "textarea",
2024
+ "select",
2025
+ "a",
2026
+ "label",
2027
+ "button"
2028
+ ],
2029
+ "attributes":[
2030
+ "onchange",
2031
+ "onsubmit",
2032
+ "onreset",
2033
+ "onselect",
2034
+ "onblur",
2035
+ "onfocus"
2036
+ ]
2037
+ },
2038
+ "keyboard":
2039
+ {
2040
+ "except":[
2041
+ "base",
2042
+ "bdo",
2043
+ "br",
2044
+ "frame",
2045
+ "frameset",
2046
+ "head",
2047
+ "html",
2048
+ "iframe",
2049
+ "meta",
2050
+ "param",
2051
+ "script",
2052
+ "style",
2053
+ "title"
2054
+ ],
2055
+ "attributes":[
2056
+ "onkeydown",
2057
+ "onkeypress",
2058
+ "onkeyup"
2059
+ ]
2060
+ },
2061
+ "mouse":
2062
+ {
2063
+ "except":[
2064
+ "base",
2065
+ "bdo",
2066
+ "br",
2067
+ "head",
2068
+ "html",
2069
+ "meta",
2070
+ "param",
2071
+ "script",
2072
+ "style",
2073
+ "title"
2074
+ ],
2075
+ "attributes":[
2076
+ "onclick",
2077
+ "ondblclick",
2078
+ "onmousedown",
2079
+ "onmousemove",
2080
+ "onmouseover",
2081
+ "onmouseout",
2082
+ "onmouseup"
2083
+ ]
2084
+ }
2085
+ },
2086
+ "_tags":
2087
+ {
2088
+ "a":
2089
+ {
2090
+ "attributes":
2091
+ {
2092
+ "0":"charset",
2093
+ "1":"coords",
2094
+ "2":"href",
2095
+ "3":"hreflang",
2096
+ "4":"name",
2097
+ "rel":/^(alternate|designates|stylesheet|start|next|prev|contents|index|glossary|copyright|chapter|section|subsection|appendix|help|bookmark| |shortcut|icon|moodalbox)+$/,
2098
+ "rev":/^(alternate|designates|stylesheet|start|next|prev|contents|index|glossary|copyright|chapter|section|subsection|appendix|help|bookmark| |shortcut|icon|moodalbox)+$/,
2099
+ "shape":/^(rect|rectangle|circ|circle|poly|polygon)$/,
2100
+ "5":"type",
2101
+ "target":/^(_blank)+$/
2102
+ }
2103
+ },
2104
+ "0":"abbr",
2105
+ "1":"acronym",
2106
+ "2":"address",
2107
+ "area":
2108
+ {
2109
+ "attributes":
2110
+ {
2111
+ "0":"alt",
2112
+ "1":"coords",
2113
+ "2":"href",
2114
+ "nohref":/^(true|false)$/,
2115
+ "shape":/^(rect|rectangle|circ|circle|poly|polygon)$/
2116
+ },
2117
+ "required":[
2118
+ "alt"
2119
+ ]
2120
+ },
2121
+ "3":"b",
2122
+ "base":
2123
+ {
2124
+ "attributes":[
2125
+ "href"
2126
+ ],
2127
+ "required":[
2128
+ "href"
2129
+ ]
2130
+ },
2131
+ "bdo":
2132
+ {
2133
+ "attributes":
2134
+ {
2135
+ "dir":/^(ltr|rtl)$/
2136
+ },
2137
+ "required":[
2138
+ "dir"
2139
+ ]
2140
+ },
2141
+ "4":"big",
2142
+ "blockquote":
2143
+ {
2144
+ "attributes":[
2145
+ "cite"
2146
+ ]
2147
+ },
2148
+ "5":"body",
2149
+ "6":"br",
2150
+ "button":
2151
+ {
2152
+ "attributes":
2153
+ {
2154
+ "disabled":/^(disabled)$/,
2155
+ "type":/^(button|reset|submit)$/,
2156
+ "0":"value"
2157
+ },
2158
+ "inside":"form"
2159
+ },
2160
+ "7":"caption",
2161
+ "8":"cite",
2162
+ "9":"code",
2163
+ "col":
2164
+ {
2165
+ "attributes":
2166
+ {
2167
+ "align":/^(right|left|center|justify)$/,
2168
+ "0":"char",
2169
+ "1":"charoff",
2170
+ "span":/^(\d)+$/,
2171
+ "valign":/^(top|middle|bottom|baseline)$/,
2172
+ "2":"width"
2173
+ },
2174
+ "inside":"colgroup"
2175
+ },
2176
+ "colgroup":
2177
+ {
2178
+ "attributes":
2179
+ {
2180
+ "align":/^(right|left|center|justify)$/,
2181
+ "0":"char",
2182
+ "1":"charoff",
2183
+ "span":/^(\d)+$/,
2184
+ "valign":/^(top|middle|bottom|baseline)$/,
2185
+ "2":"width"
2186
+ }
2187
+ },
2188
+ "10":"dd",
2189
+ "del":
2190
+ {
2191
+ "attributes":
2192
+ {
2193
+ "0":"cite",
2194
+ "datetime":/^([0-9]){8}/
2195
+ }
2196
+ },
2197
+ "11":"div",
2198
+ "12":"dfn",
2199
+ "13":"dl",
2200
+ "14":"dt",
2201
+ "15":"em",
2202
+ "fieldset":
2203
+ {
2204
+ "inside":"form"
2205
+ },
2206
+ "form":
2207
+ {
2208
+ "attributes":
2209
+ {
2210
+ "0":"action",
2211
+ "1":"accept",
2212
+ "2":"accept-charset",
2213
+ "3":"enctype",
2214
+ "method":/^(get|post)$/
2215
+ },
2216
+ "required":[
2217
+ "action"
2218
+ ]
2219
+ },
2220
+ "head":
2221
+ {
2222
+ "attributes":[
2223
+ "profile"
2224
+ ]
2225
+ },
2226
+ "16":"h1",
2227
+ "17":"h2",
2228
+ "18":"h3",
2229
+ "19":"h4",
2230
+ "20":"h5",
2231
+ "21":"h6",
2232
+ "22":"hr",
2233
+ "html":
2234
+ {
2235
+ "attributes":[
2236
+ "xmlns"
2237
+ ]
2238
+ },
2239
+ "23":"i",
2240
+ "iframe":
2241
+ {
2242
+ "attributes":[
2243
+ "src",
2244
+ "width",
2245
+ "height",
2246
+ "frameborder",
2247
+ "scrolling",
2248
+ "marginheight",
2249
+ "marginwidth"
2250
+ ],
2251
+ "required":[
2252
+ "src"
2253
+ ]
2254
+ },
2255
+ "img":
2256
+ {
2257
+ "attributes":{
2258
+ "align":/^(right|left|center|justify)$/,
2259
+ "0":"alt",
2260
+ "1":"src",
2261
+ "2":"height",
2262
+ "3":"ismap",
2263
+ "4":"longdesc",
2264
+ "5":"usemap",
2265
+ "6":"width"
2266
+ },
2267
+ "required":[
2268
+ "alt",
2269
+ "src"
2270
+ ]
2271
+ },
2272
+ "input":
2273
+ {
2274
+ "attributes":
2275
+ {
2276
+ "0":"accept",
2277
+ "1":"alt",
2278
+ "checked":/^(checked)$/,
2279
+ "disabled":/^(disabled)$/,
2280
+ "maxlength":/^(\d)+$/,
2281
+ "2":"name",
2282
+ "readonly":/^(readonly)$/,
2283
+ "size":/^(\d)+$/,
2284
+ "3":"src",
2285
+ "type":/^(button|checkbox|file|hidden|image|password|radio|reset|submit|text)$/,
2286
+ "4":"value"
2287
+ },
2288
+ "inside":"form"
2289
+ },
2290
+ "ins":
2291
+ {
2292
+ "attributes":
2293
+ {
2294
+ "0":"cite",
2295
+ "datetime":/^([0-9]){8}/
2296
+ }
2297
+ },
2298
+ "24":"kbd",
2299
+ "label":
2300
+ {
2301
+ "attributes":[
2302
+ "for"
2303
+ ],
2304
+ "inside":"form"
2305
+ },
2306
+ "25":"legend",
2307
+ "26":"li",
2308
+ "link":
2309
+ {
2310
+ "attributes":
2311
+ {
2312
+ "0":"charset",
2313
+ "1":"href",
2314
+ "2":"hreflang",
2315
+ "media":/^(all|braille|print|projection|screen|speech|,|;| )+$/i,
2316
+ //next comment line required by Opera!
2317
+ /*"rel":/^(alternate|appendix|bookmark|chapter|contents|copyright|glossary|help|home|index|next|prev|section|start|stylesheet|subsection| |shortcut|icon)+$/i,*/
2318
+ "rel":/^(alternate|appendix|bookmark|chapter|contents|copyright|glossary|help|home|index|next|prev|section|start|stylesheet|subsection| |shortcut|icon)+$/i,
2319
+ "rev":/^(alternate|appendix|bookmark|chapter|contents|copyright|glossary|help|home|index|next|prev|section|start|stylesheet|subsection| |shortcut|icon)+$/i,
2320
+ "3":"type"
2321
+ },
2322
+ "inside":"head"
2323
+ },
2324
+ "map":
2325
+ {
2326
+ "attributes":[
2327
+ "id",
2328
+ "name"
2329
+ ],
2330
+ "required":[
2331
+ "id"
2332
+ ]
2333
+ },
2334
+ "meta":
2335
+ {
2336
+ "attributes":
2337
+ {
2338
+ "0":"content",
2339
+ "http-equiv":/^(content\-type|expires|refresh|set\-cookie)$/i,
2340
+ "1":"name",
2341
+ "2":"scheme"
2342
+ },
2343
+ "required":[
2344
+ "content"
2345
+ ]
2346
+ },
2347
+ "27":"noscript",
2348
+ "28":"ol",
2349
+ "optgroup":
2350
+ {
2351
+ "attributes":
2352
+ {
2353
+ "0":"label",
2354
+ "disabled": /^(disabled)$/
2355
+ },
2356
+ "required":[
2357
+ "label"
2358
+ ]
2359
+ },
2360
+ "option":
2361
+ {
2362
+ "attributes":
2363
+ {
2364
+ "0":"label",
2365
+ "disabled":/^(disabled)$/,
2366
+ "selected":/^(selected)$/,
2367
+ "1":"value"
2368
+ },
2369
+ "inside":"select"
2370
+ },
2371
+ "29":"p",
2372
+ "param":
2373
+ {
2374
+ "attributes":
2375
+ [
2376
+ "type",
2377
+ "value",
2378
+ "name"
2379
+ ],
2380
+ "required":[
2381
+ "name"
2382
+ ],
2383
+ "inside":"object"
2384
+ },
2385
+ "embed":
2386
+ {
2387
+ "attributes":
2388
+ [
2389
+ "width",
2390
+ "height",
2391
+ "allowfullscreen",
2392
+ "allowscriptaccess",
2393
+ "wmode",
2394
+ "type",
2395
+ "src",
2396
+ "flashvars"
2397
+ ],
2398
+ "inside":"object"
2399
+ },
2400
+ "object":
2401
+ {
2402
+ "attributes":[
2403
+ "archive",
2404
+ "classid",
2405
+ "codebase",
2406
+ "codetype",
2407
+ "data",
2408
+ "declare",
2409
+ "height",
2410
+ "name",
2411
+ "standby",
2412
+ "type",
2413
+ "usemap",
2414
+ "width"
2415
+ ]
2416
+ },
2417
+ "30":"pre",
2418
+ "q":
2419
+ {
2420
+ "attributes":[
2421
+ "cite"
2422
+ ]
2423
+ },
2424
+ "31":"samp",
2425
+ "script":
2426
+ {
2427
+ "attributes":
2428
+ {
2429
+ "type":/^(text\/ecmascript|text\/javascript|text\/jscript|text\/vbscript|text\/vbs|text\/xml)$/,
2430
+ "0":"charset",
2431
+ "defer":/^(defer)$/,
2432
+ "1":"src"
2433
+ },
2434
+ "required":[
2435
+ "type"
2436
+ ]
2437
+ },
2438
+ "select":
2439
+ {
2440
+ "attributes":
2441
+ {
2442
+ "disabled":/^(disabled)$/,
2443
+ "multiple":/^(multiple)$/,
2444
+ "0":"name",
2445
+ "1":"size"
2446
+ },
2447
+ "inside":"form"
2448
+ },
2449
+ "32":"small",
2450
+ "33":"span",
2451
+ "34":"strong",
2452
+ "style":
2453
+ {
2454
+ "attributes":
2455
+ {
2456
+ "0":"type",
2457
+ "media":/^(screen|tty|tv|projection|handheld|print|braille|aural|all)$/
2458
+ },
2459
+ "required":[
2460
+ "type"
2461
+ ]
2462
+ },
2463
+ "35":"sub",
2464
+ "36":"sup",
2465
+ "table":
2466
+ {
2467
+ "attributes":
2468
+ {
2469
+ "0":"border",
2470
+ "1":"cellpadding",
2471
+ "2":"cellspacing",
2472
+ "frame":/^(void|above|below|hsides|lhs|rhs|vsides|box|border)$/,
2473
+ "rules":/^(none|groups|rows|cols|all)$/,
2474
+ "3":"summary",
2475
+ "4":"width"
2476
+ }
2477
+ },
2478
+ "tbody":
2479
+ {
2480
+ "attributes":
2481
+ {
2482
+ "align":/^(right|left|center|justify)$/,
2483
+ "0":"char",
2484
+ "1":"charoff",
2485
+ "valign":/^(top|middle|bottom|baseline)$/
2486
+ }
2487
+ },
2488
+ "td":
2489
+ {
2490
+ "attributes":
2491
+ {
2492
+ "0":"abbr",
2493
+ "align":/^(left|right|center|justify|char)$/,
2494
+ "1":"axis",
2495
+ "2":"char",
2496
+ "3":"charoff",
2497
+ "colspan":/^(\d)+$/,
2498
+ "4":"headers",
2499
+ "rowspan":/^(\d)+$/,
2500
+ "scope":/^(col|colgroup|row|rowgroup)$/,
2501
+ "valign":/^(top|middle|bottom|baseline)$/
2502
+ }
2503
+ },
2504
+ "textarea":
2505
+ {
2506
+ "attributes":[
2507
+ "cols",
2508
+ "rows",
2509
+ "disabled",
2510
+ "name",
2511
+ "readonly"
2512
+ ],
2513
+ "required":[
2514
+ "cols",
2515
+ "rows"
2516
+ ],
2517
+ "inside":"form"
2518
+ },
2519
+ "tfoot":
2520
+ {
2521
+ "attributes":
2522
+ {
2523
+ "align":/^(right|left|center|justify)$/,
2524
+ "0":"char",
2525
+ "1":"charoff",
2526
+ "valign":/^(top|middle|bottom)$/,
2527
+ "2":"baseline"
2528
+ }
2529
+ },
2530
+ "th":
2531
+ {
2532
+ "attributes":
2533
+ {
2534
+ "0":"abbr",
2535
+ "align":/^(left|right|center|justify|char)$/,
2536
+ "1":"axis",
2537
+ "2":"char",
2538
+ "3":"charoff",
2539
+ "colspan":/^(\d)+$/,
2540
+ "4":"headers",
2541
+ "rowspan":/^(\d)+$/,
2542
+ "scope":/^(col|colgroup|row|rowgroup)$/,
2543
+ "valign":/^(top|middle|bottom|baseline)$/
2544
+ }
2545
+ },
2546
+ "thead":
2547
+ {
2548
+ "attributes":
2549
+ {
2550
+ "align":/^(right|left|center|justify)$/,
2551
+ "0":"char",
2552
+ "1":"charoff",
2553
+ "valign":/^(top|middle|bottom|baseline)$/
2554
+ }
2555
+ },
2556
+ "37":"title",
2557
+ "tr":
2558
+ {
2559
+ "attributes":
2560
+ {
2561
+ "align":/^(right|left|center|justify|char)$/,
2562
+ "0":"char",
2563
+ "1":"charoff",
2564
+ "valign":/^(top|middle|bottom|baseline)$/
2565
+ }
2566
+ },
2567
+ "38":"tt",
2568
+ "39":"ul",
2569
+ "40":"var"
2570
+ },
2571
+
2572
+ // Temporary skiped attributes
2573
+ skiped_attributes : [],
2574
+ skiped_attribute_values : [],
2575
+
2576
+ getValidTagAttributes: function(tag, attributes)
2577
+ {
2578
+ var valid_attributes = {};
2579
+ var possible_attributes = this.getPossibleTagAttributes(tag);
2580
+ for(var attribute in attributes) {
2581
+ var value = attributes[attribute];
2582
+ var h = WYMeditor.Helper;
2583
+ if(!h.contains(this.skiped_attributes, attribute) && !h.contains(this.skiped_attribute_values, value)){
2584
+ if (typeof value != 'function' && h.contains(possible_attributes, attribute)) {
2585
+ if (this.doesAttributeNeedsValidation(tag, attribute)) {
2586
+ if(this.validateAttribute(tag, attribute, value)){
2587
+ valid_attributes[attribute] = value;
2588
+ }
2589
+ }else{
2590
+ valid_attributes[attribute] = value;
2591
+ }
2592
+ }
2593
+ }
2594
+ }
2595
+ return valid_attributes;
2596
+ },
2597
+ getUniqueAttributesAndEventsForTag : function(tag)
2598
+ {
2599
+ var result = [];
2600
+
2601
+ if (this._tags[tag] && this._tags[tag]['attributes']) {
2602
+ for (k in this._tags[tag]['attributes']) {
2603
+ result.push(parseInt(k) == k ? this._tags[tag]['attributes'][k] : k);
2604
+ }
2605
+ }
2606
+ return result;
2607
+ },
2608
+ getDefaultAttributesAndEventsForTags : function()
2609
+ {
2610
+ var result = [];
2611
+ for (var key in this._events){
2612
+ result.push(this._events[key]);
2613
+ }
2614
+ for (var key in this._attributes){
2615
+ result.push(this._attributes[key]);
2616
+ }
2617
+ return result;
2618
+ },
2619
+ isValidTag : function(tag)
2620
+ {
2621
+ if(this._tags[tag]){
2622
+ return true;
2623
+ }
2624
+ for(var key in this._tags){
2625
+ if(this._tags[key] == tag){
2626
+ return true;
2627
+ }
2628
+ }
2629
+ return false;
2630
+ },
2631
+ getDefaultAttributesAndEventsForTag : function(tag)
2632
+ {
2633
+ var default_attributes = [];
2634
+ if (this.isValidTag(tag)) {
2635
+ var default_attributes_and_events = this.getDefaultAttributesAndEventsForTags();
2636
+
2637
+ for(var key in default_attributes_and_events) {
2638
+ var defaults = default_attributes_and_events[key];
2639
+ if(typeof defaults == 'object'){
2640
+ var h = WYMeditor.Helper;
2641
+ if ((defaults['except'] && h.contains(defaults['except'], tag)) || (defaults['only'] && !h.contains(defaults['only'], tag))) {
2642
+ continue;
2643
+ }
2644
+
2645
+ var tag_defaults = defaults['attributes'] ? defaults['attributes'] : defaults['events'];
2646
+ for(var k in tag_defaults) {
2647
+ default_attributes.push(typeof tag_defaults[k] != 'string' ? k : tag_defaults[k]);
2648
+ }
2649
+ }
2650
+ }
2651
+ }
2652
+ return default_attributes;
2653
+ },
2654
+ doesAttributeNeedsValidation: function(tag, attribute)
2655
+ {
2656
+ return this._tags[tag] && ((this._tags[tag]['attributes'] && this._tags[tag]['attributes'][attribute]) || (this._tags[tag]['required'] &&
2657
+ WYMeditor.Helper.contains(this._tags[tag]['required'], attribute)));
2658
+ },
2659
+ validateAttribute : function(tag, attribute, value)
2660
+ {
2661
+ if ( this._tags[tag] &&
2662
+ (this._tags[tag]['attributes'] && this._tags[tag]['attributes'][attribute] && value.length > 0 && !value.match(this._tags[tag]['attributes'][attribute])) || // invalid format
2663
+ (this._tags[tag] && this._tags[tag]['required'] && WYMeditor.Helper.contains(this._tags[tag]['required'], attribute) && value.length == 0) // required attribute
2664
+ ) {
2665
+ return false;
2666
+ }
2667
+ return typeof this._tags[tag] != 'undefined';
2668
+ },
2669
+ getPossibleTagAttributes : function(tag)
2670
+ {
2671
+ if (!this._possible_tag_attributes) {
2672
+ this._possible_tag_attributes = {};
2673
+ }
2674
+ if (!this._possible_tag_attributes[tag]) {
2675
+ this._possible_tag_attributes[tag] = this.getUniqueAttributesAndEventsForTag(tag).concat(this.getDefaultAttributesAndEventsForTag(tag));
2676
+ }
2677
+ return this._possible_tag_attributes[tag];
2678
+ }
2679
+ };
2680
+
2681
+
2682
+ /**
2683
+ * Compounded regular expression. Any of
2684
+ * the contained patterns could match and
2685
+ * when one does, it's label is returned.
2686
+ *
2687
+ * Constructor. Starts with no patterns.
2688
+ * @param boolean case True for case sensitive, false
2689
+ * for insensitive.
2690
+ * @access public
2691
+ * @author Marcus Baker (http://lastcraft.com)
2692
+ * @author Bermi Ferrer (http://bermi.org)
2693
+ */
2694
+ WYMeditor.ParallelRegex = function(case_sensitive)
2695
+ {
2696
+ this._case = case_sensitive;
2697
+ this._patterns = [];
2698
+ this._labels = [];
2699
+ this._regex = null;
2700
+ return this;
2701
+ };
2702
+
2703
+
2704
+ /**
2705
+ * Adds a pattern with an optional label.
2706
+ * @param string pattern Perl style regex, but ( and )
2707
+ * lose the usual meaning.
2708
+ * @param string label Label of regex to be returned
2709
+ * on a match.
2710
+ * @access public
2711
+ */
2712
+ WYMeditor.ParallelRegex.prototype.addPattern = function(pattern, label)
2713
+ {
2714
+ label = label || true;
2715
+ var count = this._patterns.length;
2716
+ this._patterns[count] = pattern;
2717
+ this._labels[count] = label;
2718
+ this._regex = null;
2719
+ };
2720
+
2721
+ /**
2722
+ * Attempts to match all patterns at once against
2723
+ * a string.
2724
+ * @param string subject String to match against.
2725
+ *
2726
+ * @return boolean True on success.
2727
+ * @return string match First matched portion of
2728
+ * subject.
2729
+ * @access public
2730
+ */
2731
+ WYMeditor.ParallelRegex.prototype.match = function(subject)
2732
+ {
2733
+ if (this._patterns.length == 0) {
2734
+ return [false, ''];
2735
+ }
2736
+ var matches = subject.match(this._getCompoundedRegex());
2737
+
2738
+ if(!matches){
2739
+ return [false, ''];
2740
+ }
2741
+ var match = matches[0];
2742
+ for (var i = 1; i < matches.length; i++) {
2743
+ if (matches[i]) {
2744
+ return [this._labels[i-1], match];
2745
+ }
2746
+ }
2747
+ return [true, matches[0]];
2748
+ };
2749
+
2750
+ /**
2751
+ * Compounds the patterns into a single
2752
+ * regular expression separated with the
2753
+ * "or" operator. Caches the regex.
2754
+ * Will automatically escape (, ) and / tokens.
2755
+ * @param array patterns List of patterns in order.
2756
+ * @access private
2757
+ */
2758
+ WYMeditor.ParallelRegex.prototype._getCompoundedRegex = function()
2759
+ {
2760
+ if (this._regex == null) {
2761
+ for (var i = 0, count = this._patterns.length; i < count; i++) {
2762
+ this._patterns[i] = '(' + this._untokenizeRegex(this._tokenizeRegex(this._patterns[i]).replace(/([\/\(\)])/g,'\\$1')) + ')';
2763
+ }
2764
+ this._regex = new RegExp(this._patterns.join("|") ,this._getPerlMatchingFlags());
2765
+ }
2766
+ return this._regex;
2767
+ };
2768
+
2769
+ /**
2770
+ * Escape lookahead/lookbehind blocks
2771
+ */
2772
+ WYMeditor.ParallelRegex.prototype._tokenizeRegex = function(regex)
2773
+ {
2774
+ return regex.
2775
+ replace(/\(\?(i|m|s|x|U)\)/, '~~~~~~Tk1\$1~~~~~~').
2776
+ replace(/\(\?(\-[i|m|s|x|U])\)/, '~~~~~~Tk2\$1~~~~~~').
2777
+ replace(/\(\?\=(.*)\)/, '~~~~~~Tk3\$1~~~~~~').
2778
+ replace(/\(\?\!(.*)\)/, '~~~~~~Tk4\$1~~~~~~').
2779
+ replace(/\(\?\<\=(.*)\)/, '~~~~~~Tk5\$1~~~~~~').
2780
+ replace(/\(\?\<\!(.*)\)/, '~~~~~~Tk6\$1~~~~~~').
2781
+ replace(/\(\?\:(.*)\)/, '~~~~~~Tk7\$1~~~~~~');
2782
+ };
2783
+
2784
+ /**
2785
+ * Unscape lookahead/lookbehind blocks
2786
+ */
2787
+ WYMeditor.ParallelRegex.prototype._untokenizeRegex = function(regex)
2788
+ {
2789
+ return regex.
2790
+ replace(/~~~~~~Tk1(.{1})~~~~~~/, "(?\$1)").
2791
+ replace(/~~~~~~Tk2(.{2})~~~~~~/, "(?\$1)").
2792
+ replace(/~~~~~~Tk3(.*)~~~~~~/, "(?=\$1)").
2793
+ replace(/~~~~~~Tk4(.*)~~~~~~/, "(?!\$1)").
2794
+ replace(/~~~~~~Tk5(.*)~~~~~~/, "(?<=\$1)").
2795
+ replace(/~~~~~~Tk6(.*)~~~~~~/, "(?<!\$1)").
2796
+ replace(/~~~~~~Tk7(.*)~~~~~~/, "(?:\$1)");
2797
+ };
2798
+
2799
+
2800
+ /**
2801
+ * Accessor for perl regex mode flags to use.
2802
+ * @return string Perl regex flags.
2803
+ * @access private
2804
+ */
2805
+ WYMeditor.ParallelRegex.prototype._getPerlMatchingFlags = function()
2806
+ {
2807
+ return (this._case ? "m" : "mi");
2808
+ };
2809
+
2810
+
2811
+
2812
+ /**
2813
+ * States for a stack machine.
2814
+ *
2815
+ * Constructor. Starts in named state.
2816
+ * @param string start Starting state name.
2817
+ * @access public
2818
+ * @author Marcus Baker (http://lastcraft.com)
2819
+ * @author Bermi Ferrer (http://bermi.org)
2820
+ */
2821
+ WYMeditor.StateStack = function(start)
2822
+ {
2823
+ this._stack = [start];
2824
+ return this;
2825
+ };
2826
+
2827
+ /**
2828
+ * Accessor for current state.
2829
+ * @return string State.
2830
+ * @access public
2831
+ */
2832
+ WYMeditor.StateStack.prototype.getCurrent = function()
2833
+ {
2834
+ return this._stack[this._stack.length - 1];
2835
+ };
2836
+
2837
+ /**
2838
+ * Adds a state to the stack and sets it
2839
+ * to be the current state.
2840
+ * @param string state New state.
2841
+ * @access public
2842
+ */
2843
+ WYMeditor.StateStack.prototype.enter = function(state)
2844
+ {
2845
+ this._stack.push(state);
2846
+ };
2847
+
2848
+ /**
2849
+ * Leaves the current state and reverts
2850
+ * to the previous one.
2851
+ * @return boolean False if we drop off
2852
+ * the bottom of the list.
2853
+ * @access public
2854
+ */
2855
+ WYMeditor.StateStack.prototype.leave = function()
2856
+ {
2857
+ if (this._stack.length == 1) {
2858
+ return false;
2859
+ }
2860
+ this._stack.pop();
2861
+ return true;
2862
+ };
2863
+
2864
+
2865
+ // GLOBALS
2866
+ WYMeditor.LEXER_ENTER = 1;
2867
+ WYMeditor.LEXER_MATCHED = 2;
2868
+ WYMeditor.LEXER_UNMATCHED = 3;
2869
+ WYMeditor.LEXER_EXIT = 4;
2870
+ WYMeditor.LEXER_SPECIAL = 5;
2871
+
2872
+
2873
+ /**
2874
+ * Accepts text and breaks it into tokens.
2875
+ * Some optimisation to make the sure the
2876
+ * content is only scanned by the PHP regex
2877
+ * parser once. Lexer modes must not start
2878
+ * with leading underscores.
2879
+ *
2880
+ * Sets up the lexer in case insensitive matching
2881
+ * by default.
2882
+ * @param Parser parser Handling strategy by reference.
2883
+ * @param string start Starting handler.
2884
+ * @param boolean case True for case sensitive.
2885
+ * @access public
2886
+ * @author Marcus Baker (http://lastcraft.com)
2887
+ * @author Bermi Ferrer (http://bermi.org)
2888
+ */
2889
+ WYMeditor.Lexer = function(parser, start, case_sensitive)
2890
+ {
2891
+ start = start || 'accept';
2892
+ this._case = case_sensitive || false;
2893
+ this._regexes = {};
2894
+ this._parser = parser;
2895
+ this._mode = new WYMeditor.StateStack(start);
2896
+ this._mode_handlers = {};
2897
+ this._mode_handlers[start] = start;
2898
+ return this;
2899
+ };
2900
+
2901
+ /**
2902
+ * Adds a token search pattern for a particular
2903
+ * parsing mode. The pattern does not change the
2904
+ * current mode.
2905
+ * @param string pattern Perl style regex, but ( and )
2906
+ * lose the usual meaning.
2907
+ * @param string mode Should only apply this
2908
+ * pattern when dealing with
2909
+ * this type of input.
2910
+ * @access public
2911
+ */
2912
+ WYMeditor.Lexer.prototype.addPattern = function(pattern, mode)
2913
+ {
2914
+ var mode = mode || "accept";
2915
+ if (typeof this._regexes[mode] == 'undefined') {
2916
+ this._regexes[mode] = new WYMeditor.ParallelRegex(this._case);
2917
+ }
2918
+ this._regexes[mode].addPattern(pattern);
2919
+ if (typeof this._mode_handlers[mode] == 'undefined') {
2920
+ this._mode_handlers[mode] = mode;
2921
+ }
2922
+ };
2923
+
2924
+ /**
2925
+ * Adds a pattern that will enter a new parsing
2926
+ * mode. Useful for entering parenthesis, strings,
2927
+ * tags, etc.
2928
+ * @param string pattern Perl style regex, but ( and )
2929
+ * lose the usual meaning.
2930
+ * @param string mode Should only apply this
2931
+ * pattern when dealing with
2932
+ * this type of input.
2933
+ * @param string new_mode Change parsing to this new
2934
+ * nested mode.
2935
+ * @access public
2936
+ */
2937
+ WYMeditor.Lexer.prototype.addEntryPattern = function(pattern, mode, new_mode)
2938
+ {
2939
+ if (typeof this._regexes[mode] == 'undefined') {
2940
+ this._regexes[mode] = new WYMeditor.ParallelRegex(this._case);
2941
+ }
2942
+ this._regexes[mode].addPattern(pattern, new_mode);
2943
+ if (typeof this._mode_handlers[new_mode] == 'undefined') {
2944
+ this._mode_handlers[new_mode] = new_mode;
2945
+ }
2946
+ };
2947
+
2948
+ /**
2949
+ * Adds a pattern that will exit the current mode
2950
+ * and re-enter the previous one.
2951
+ * @param string pattern Perl style regex, but ( and )
2952
+ * lose the usual meaning.
2953
+ * @param string mode Mode to leave.
2954
+ * @access public
2955
+ */
2956
+ WYMeditor.Lexer.prototype.addExitPattern = function(pattern, mode)
2957
+ {
2958
+ if (typeof this._regexes[mode] == 'undefined') {
2959
+ this._regexes[mode] = new WYMeditor.ParallelRegex(this._case);
2960
+ }
2961
+ this._regexes[mode].addPattern(pattern, "__exit");
2962
+ if (typeof this._mode_handlers[mode] == 'undefined') {
2963
+ this._mode_handlers[mode] = mode;
2964
+ }
2965
+ };
2966
+
2967
+ /**
2968
+ * Adds a pattern that has a special mode. Acts as an entry
2969
+ * and exit pattern in one go, effectively calling a special
2970
+ * parser handler for this token only.
2971
+ * @param string pattern Perl style regex, but ( and )
2972
+ * lose the usual meaning.
2973
+ * @param string mode Should only apply this
2974
+ * pattern when dealing with
2975
+ * this type of input.
2976
+ * @param string special Use this mode for this one token.
2977
+ * @access public
2978
+ */
2979
+ WYMeditor.Lexer.prototype.addSpecialPattern = function(pattern, mode, special)
2980
+ {
2981
+ if (typeof this._regexes[mode] == 'undefined') {
2982
+ this._regexes[mode] = new WYMeditor.ParallelRegex(this._case);
2983
+ }
2984
+ this._regexes[mode].addPattern(pattern, '_'+special);
2985
+ if (typeof this._mode_handlers[special] == 'undefined') {
2986
+ this._mode_handlers[special] = special;
2987
+ }
2988
+ };
2989
+
2990
+ /**
2991
+ * Adds a mapping from a mode to another handler.
2992
+ * @param string mode Mode to be remapped.
2993
+ * @param string handler New target handler.
2994
+ * @access public
2995
+ */
2996
+ WYMeditor.Lexer.prototype.mapHandler = function(mode, handler)
2997
+ {
2998
+ this._mode_handlers[mode] = handler;
2999
+ };
3000
+
3001
+ /**
3002
+ * Splits the page text into tokens. Will fail
3003
+ * if the handlers report an error or if no
3004
+ * content is consumed. If successful then each
3005
+ * unparsed and parsed token invokes a call to the
3006
+ * held listener.
3007
+ * @param string raw Raw HTML text.
3008
+ * @return boolean True on success, else false.
3009
+ * @access public
3010
+ */
3011
+ WYMeditor.Lexer.prototype.parse = function(raw)
3012
+ {
3013
+ if (typeof this._parser == 'undefined') {
3014
+ return false;
3015
+ }
3016
+
3017
+ var length = raw.length;
3018
+ var parsed;
3019
+ while (typeof (parsed = this._reduce(raw)) == 'object') {
3020
+ var raw = parsed[0];
3021
+ var unmatched = parsed[1];
3022
+ var matched = parsed[2];
3023
+ var mode = parsed[3];
3024
+
3025
+ if (! this._dispatchTokens(unmatched, matched, mode)) {
3026
+ return false;
3027
+ }
3028
+
3029
+ if (raw == '') {
3030
+ return true;
3031
+ }
3032
+ if (raw.length == length) {
3033
+ return false;
3034
+ }
3035
+ length = raw.length;
3036
+ }
3037
+ if (! parsed ) {
3038
+ return false;
3039
+ }
3040
+
3041
+ return this._invokeParser(raw, WYMeditor.LEXER_UNMATCHED);
3042
+ };
3043
+
3044
+ /**
3045
+ * Sends the matched token and any leading unmatched
3046
+ * text to the parser changing the lexer to a new
3047
+ * mode if one is listed.
3048
+ * @param string unmatched Unmatched leading portion.
3049
+ * @param string matched Actual token match.
3050
+ * @param string mode Mode after match. A boolean
3051
+ * false mode causes no change.
3052
+ * @return boolean False if there was any error
3053
+ * from the parser.
3054
+ * @access private
3055
+ */
3056
+ WYMeditor.Lexer.prototype._dispatchTokens = function(unmatched, matched, mode)
3057
+ {
3058
+ mode = mode || false;
3059
+
3060
+ if (! this._invokeParser(unmatched, WYMeditor.LEXER_UNMATCHED)) {
3061
+ return false;
3062
+ }
3063
+
3064
+ if (typeof mode == 'boolean') {
3065
+ return this._invokeParser(matched, WYMeditor.LEXER_MATCHED);
3066
+ }
3067
+ if (this._isModeEnd(mode)) {
3068
+ if (! this._invokeParser(matched, WYMeditor.LEXER_EXIT)) {
3069
+ return false;
3070
+ }
3071
+ return this._mode.leave();
3072
+ }
3073
+ if (this._isSpecialMode(mode)) {
3074
+ this._mode.enter(this._decodeSpecial(mode));
3075
+ if (! this._invokeParser(matched, WYMeditor.LEXER_SPECIAL)) {
3076
+ return false;
3077
+ }
3078
+ return this._mode.leave();
3079
+ }
3080
+ this._mode.enter(mode);
3081
+
3082
+ return this._invokeParser(matched, WYMeditor.LEXER_ENTER);
3083
+ };
3084
+
3085
+ /**
3086
+ * Tests to see if the new mode is actually to leave
3087
+ * the current mode and pop an item from the matching
3088
+ * mode stack.
3089
+ * @param string mode Mode to test.
3090
+ * @return boolean True if this is the exit mode.
3091
+ * @access private
3092
+ */
3093
+ WYMeditor.Lexer.prototype._isModeEnd = function(mode)
3094
+ {
3095
+ return (mode === "__exit");
3096
+ };
3097
+
3098
+ /**
3099
+ * Test to see if the mode is one where this mode
3100
+ * is entered for this token only and automatically
3101
+ * leaves immediately afterwoods.
3102
+ * @param string mode Mode to test.
3103
+ * @return boolean True if this is the exit mode.
3104
+ * @access private
3105
+ */
3106
+ WYMeditor.Lexer.prototype._isSpecialMode = function(mode)
3107
+ {
3108
+ return (mode.substring(0,1) == "_");
3109
+ };
3110
+
3111
+ /**
3112
+ * Strips the magic underscore marking single token
3113
+ * modes.
3114
+ * @param string mode Mode to decode.
3115
+ * @return string Underlying mode name.
3116
+ * @access private
3117
+ */
3118
+ WYMeditor.Lexer.prototype._decodeSpecial = function(mode)
3119
+ {
3120
+ return mode.substring(1);
3121
+ };
3122
+
3123
+ /**
3124
+ * Calls the parser method named after the current
3125
+ * mode. Empty content will be ignored. The lexer
3126
+ * has a parser handler for each mode in the lexer.
3127
+ * @param string content Text parsed.
3128
+ * @param boolean is_match Token is recognised rather
3129
+ * than unparsed data.
3130
+ * @access private
3131
+ */
3132
+ WYMeditor.Lexer.prototype._invokeParser = function(content, is_match)
3133
+ {
3134
+
3135
+ if (!/ +/.test(content) && ((content === '') || (content === false))) {
3136
+ return true;
3137
+ }
3138
+ var current = this._mode.getCurrent();
3139
+ var handler = this._mode_handlers[current];
3140
+ var result;
3141
+ eval('result = this._parser.' + handler + '(content, is_match);');
3142
+ return result;
3143
+ };
3144
+
3145
+ /**
3146
+ * Tries to match a chunk of text and if successful
3147
+ * removes the recognised chunk and any leading
3148
+ * unparsed data. Empty strings will not be matched.
3149
+ * @param string raw The subject to parse. This is the
3150
+ * content that will be eaten.
3151
+ * @return array/boolean Three item list of unparsed
3152
+ * content followed by the
3153
+ * recognised token and finally the
3154
+ * action the parser is to take.
3155
+ * True if no match, false if there
3156
+ * is a parsing error.
3157
+ * @access private
3158
+ */
3159
+ WYMeditor.Lexer.prototype._reduce = function(raw)
3160
+ {
3161
+ var matched = this._regexes[this._mode.getCurrent()].match(raw);
3162
+ var match = matched[1];
3163
+ var action = matched[0];
3164
+ if (action) {
3165
+ var unparsed_character_count = raw.indexOf(match);
3166
+ var unparsed = raw.substr(0, unparsed_character_count);
3167
+ raw = raw.substring(unparsed_character_count + match.length);
3168
+ return [raw, unparsed, match, action];
3169
+ }
3170
+ return true;
3171
+ };
3172
+
3173
+
3174
+
3175
+ /**
3176
+ * This are the rules for breaking the XHTML code into events
3177
+ * handled by the provided parser.
3178
+ *
3179
+ * @author Marcus Baker (http://lastcraft.com)
3180
+ * @author Bermi Ferrer (http://bermi.org)
3181
+ */
3182
+ WYMeditor.XhtmlLexer = function(parser)
3183
+ {
3184
+ $.extend(this, new WYMeditor.Lexer(parser, 'Text'));
3185
+
3186
+ this.mapHandler('Text', 'Text');
3187
+
3188
+ this.addTokens();
3189
+
3190
+ this.init();
3191
+
3192
+ return this;
3193
+ };
3194
+
3195
+
3196
+ WYMeditor.XhtmlLexer.prototype.init = function()
3197
+ {
3198
+ };
3199
+
3200
+ WYMeditor.XhtmlLexer.prototype.addTokens = function()
3201
+ {
3202
+ this.addCommentTokens('Text');
3203
+ this.addScriptTokens('Text');
3204
+ this.addCssTokens('Text');
3205
+ this.addTagTokens('Text');
3206
+ };
3207
+
3208
+ WYMeditor.XhtmlLexer.prototype.addCommentTokens = function(scope)
3209
+ {
3210
+ this.addEntryPattern("<!--", scope, 'Comment');
3211
+ this.addExitPattern("-->", 'Comment');
3212
+ };
3213
+
3214
+ WYMeditor.XhtmlLexer.prototype.addScriptTokens = function(scope)
3215
+ {
3216
+ this.addEntryPattern("<script", scope, 'Script');
3217
+ this.addExitPattern("</script>", 'Script');
3218
+ };
3219
+
3220
+ WYMeditor.XhtmlLexer.prototype.addCssTokens = function(scope)
3221
+ {
3222
+ this.addEntryPattern("<style", scope, 'Css');
3223
+ this.addExitPattern("</style>", 'Css');
3224
+ };
3225
+
3226
+ WYMeditor.XhtmlLexer.prototype.addTagTokens = function(scope)
3227
+ {
3228
+ this.addSpecialPattern("<\\s*[a-z0-9:\-]+\\s*>", scope, 'OpeningTag');
3229
+ this.addEntryPattern("<[a-z0-9:\-]+"+'[\\\/ \\\>]+', scope, 'OpeningTag');
3230
+ this.addInTagDeclarationTokens('OpeningTag');
3231
+
3232
+ this.addSpecialPattern("</\\s*[a-z0-9:\-]+\\s*>", scope, 'ClosingTag');
3233
+
3234
+ };
3235
+
3236
+ WYMeditor.XhtmlLexer.prototype.addInTagDeclarationTokens = function(scope)
3237
+ {
3238
+ this.addSpecialPattern('\\s+', scope, 'Ignore');
3239
+
3240
+ this.addAttributeTokens(scope);
3241
+
3242
+ this.addExitPattern('/>', scope);
3243
+ this.addExitPattern('>', scope);
3244
+
3245
+ };
3246
+
3247
+ WYMeditor.XhtmlLexer.prototype.addAttributeTokens = function(scope)
3248
+ {
3249
+ this.addSpecialPattern("\\s*[a-z-_0-9]*:?[a-z-_0-9]+\\s*(?=\=)\\s*", scope, 'TagAttributes');
3250
+
3251
+ this.addEntryPattern('=\\s*"', scope, 'DoubleQuotedAttribute');
3252
+ this.addPattern("\\\\\"", 'DoubleQuotedAttribute');
3253
+ this.addExitPattern('"', 'DoubleQuotedAttribute');
3254
+
3255
+ this.addEntryPattern("=\\s*'", scope, 'SingleQuotedAttribute');
3256
+ this.addPattern("\\\\'", 'SingleQuotedAttribute');
3257
+ this.addExitPattern("'", 'SingleQuotedAttribute');
3258
+
3259
+ this.addSpecialPattern('=\\s*[^>\\s]*', scope, 'UnquotedAttribute');
3260
+ };
3261
+
3262
+
3263
+
3264
+ /**
3265
+ * XHTML Parser.
3266
+ *
3267
+ * This XHTML parser will trigger the events available on on
3268
+ * current SaxListener
3269
+ *
3270
+ * @author Bermi Ferrer (http://bermi.org)
3271
+ */
3272
+ WYMeditor.XhtmlParser = function(Listener, mode)
3273
+ {
3274
+ var mode = mode || 'Text';
3275
+ this._Lexer = new WYMeditor.XhtmlLexer(this);
3276
+ this._Listener = Listener;
3277
+ this._mode = mode;
3278
+ this._matches = [];
3279
+ this._last_match = '';
3280
+ this._current_match = '';
3281
+
3282
+ return this;
3283
+ };
3284
+
3285
+ WYMeditor.XhtmlParser.prototype.parse = function(raw)
3286
+ {
3287
+ this._Lexer.parse(this.beforeParsing(raw));
3288
+ return this.afterParsing(this._Listener.getResult());
3289
+ };
3290
+
3291
+ WYMeditor.XhtmlParser.prototype.beforeParsing = function(raw)
3292
+ {
3293
+ if(raw.match(/class="MsoNormal"/) || raw.match(/ns = "urn:schemas-microsoft-com/)){
3294
+ // Useful for cleaning up content pasted from other sources (MSWord)
3295
+ this._Listener.avoidStylingTagsAndAttributes();
3296
+ }
3297
+ return this._Listener.beforeParsing(raw);
3298
+ };
3299
+
3300
+ WYMeditor.XhtmlParser.prototype.afterParsing = function(parsed)
3301
+ {
3302
+ if(this._Listener._avoiding_tags_implicitly){
3303
+ this._Listener.allowStylingTagsAndAttributes();
3304
+ }
3305
+ return this._Listener.afterParsing(parsed);
3306
+ };
3307
+
3308
+
3309
+ WYMeditor.XhtmlParser.prototype.Ignore = function(match, state)
3310
+ {
3311
+ return true;
3312
+ };
3313
+
3314
+ WYMeditor.XhtmlParser.prototype.Text = function(text)
3315
+ {
3316
+ this._Listener.addContent(text);
3317
+ return true;
3318
+ };
3319
+
3320
+ WYMeditor.XhtmlParser.prototype.Comment = function(match, status)
3321
+ {
3322
+ return this._addNonTagBlock(match, status, 'addComment');
3323
+ };
3324
+
3325
+ WYMeditor.XhtmlParser.prototype.Script = function(match, status)
3326
+ {
3327
+ return this._addNonTagBlock(match, status, 'addScript');
3328
+ };
3329
+
3330
+ WYMeditor.XhtmlParser.prototype.Css = function(match, status)
3331
+ {
3332
+ return this._addNonTagBlock(match, status, 'addCss');
3333
+ };
3334
+
3335
+ WYMeditor.XhtmlParser.prototype._addNonTagBlock = function(match, state, type)
3336
+ {
3337
+ switch (state){
3338
+ case WYMeditor.LEXER_ENTER:
3339
+ this._non_tag = match;
3340
+ break;
3341
+ case WYMeditor.LEXER_UNMATCHED:
3342
+ this._non_tag += match;
3343
+ break;
3344
+ case WYMeditor.LEXER_EXIT:
3345
+ switch(type) {
3346
+ case 'addComment':
3347
+ this._Listener.addComment(this._non_tag+match);
3348
+ break;
3349
+ case 'addScript':
3350
+ this._Listener.addScript(this._non_tag+match);
3351
+ break;
3352
+ case 'addCss':
3353
+ this._Listener.addCss(this._non_tag+match);
3354
+ break;
3355
+ }
3356
+ }
3357
+ return true;
3358
+ };
3359
+
3360
+ WYMeditor.XhtmlParser.prototype.OpeningTag = function(match, state)
3361
+ {
3362
+ switch (state){
3363
+ case WYMeditor.LEXER_ENTER:
3364
+ this._tag = this.normalizeTag(match);
3365
+ this._tag_attributes = {};
3366
+ break;
3367
+ case WYMeditor.LEXER_SPECIAL:
3368
+ this._callOpenTagListener(this.normalizeTag(match));
3369
+ break;
3370
+ case WYMeditor.LEXER_EXIT:
3371
+ this._callOpenTagListener(this._tag, this._tag_attributes);
3372
+ }
3373
+ return true;
3374
+ };
3375
+
3376
+ WYMeditor.XhtmlParser.prototype.ClosingTag = function(match, state)
3377
+ {
3378
+ this._callCloseTagListener(this.normalizeTag(match));
3379
+ return true;
3380
+ };
3381
+
3382
+ WYMeditor.XhtmlParser.prototype._callOpenTagListener = function(tag, attributes)
3383
+ {
3384
+ var attributes = attributes || {};
3385
+ this.autoCloseUnclosedBeforeNewOpening(tag);
3386
+
3387
+ if(this._Listener.isBlockTag(tag)){
3388
+ this._Listener._tag_stack.push(tag);
3389
+ this._Listener.fixNestingBeforeOpeningBlockTag(tag, attributes);
3390
+ this._Listener.openBlockTag(tag, attributes);
3391
+ this._increaseOpenTagCounter(tag);
3392
+ }else if(this._Listener.isInlineTag(tag)){
3393
+ this._Listener.inlineTag(tag, attributes);
3394
+ }else{
3395
+ this._Listener.openUnknownTag(tag, attributes);
3396
+ this._increaseOpenTagCounter(tag);
3397
+ }
3398
+ this._Listener.last_tag = tag;
3399
+ this._Listener.last_tag_opened = true;
3400
+ this._Listener.last_tag_attributes = attributes;
3401
+ };
3402
+
3403
+ WYMeditor.XhtmlParser.prototype._callCloseTagListener = function(tag)
3404
+ {
3405
+ if(this._decreaseOpenTagCounter(tag)){
3406
+ this.autoCloseUnclosedBeforeTagClosing(tag);
3407
+
3408
+ if(this._Listener.isBlockTag(tag)){
3409
+ var expected_tag = this._Listener._tag_stack.pop();
3410
+ if(expected_tag == false){
3411
+ return;
3412
+ }else if(expected_tag != tag){
3413
+ tag = expected_tag;
3414
+ }
3415
+ this._Listener.closeBlockTag(tag);
3416
+ }else{
3417
+ this._Listener.closeUnknownTag(tag);
3418
+ }
3419
+ }else{
3420
+ this._Listener.closeUnopenedTag(tag);
3421
+ }
3422
+ this._Listener.last_tag = tag;
3423
+ this._Listener.last_tag_opened = false;
3424
+ };
3425
+
3426
+ WYMeditor.XhtmlParser.prototype._increaseOpenTagCounter = function(tag)
3427
+ {
3428
+ this._Listener._open_tags[tag] = this._Listener._open_tags[tag] || 0;
3429
+ this._Listener._open_tags[tag]++;
3430
+ };
3431
+
3432
+ WYMeditor.XhtmlParser.prototype._decreaseOpenTagCounter = function(tag)
3433
+ {
3434
+ if(this._Listener._open_tags[tag]){
3435
+ this._Listener._open_tags[tag]--;
3436
+ if(this._Listener._open_tags[tag] == 0){
3437
+ this._Listener._open_tags[tag] = undefined;
3438
+ }
3439
+ return true;
3440
+ }
3441
+ return false;
3442
+ };
3443
+
3444
+ WYMeditor.XhtmlParser.prototype.autoCloseUnclosedBeforeNewOpening = function(new_tag)
3445
+ {
3446
+ this._autoCloseUnclosed(new_tag, false);
3447
+ };
3448
+
3449
+ WYMeditor.XhtmlParser.prototype.autoCloseUnclosedBeforeTagClosing = function(tag)
3450
+ {
3451
+ this._autoCloseUnclosed(tag, true);
3452
+ };
3453
+
3454
+ WYMeditor.XhtmlParser.prototype._autoCloseUnclosed = function(new_tag, closing)
3455
+ {
3456
+ var closing = closing || false;
3457
+ if(this._Listener._open_tags){
3458
+ for (var tag in this._Listener._open_tags) {
3459
+ var counter = this._Listener._open_tags[tag];
3460
+ if(counter > 0 && this._Listener.shouldCloseTagAutomatically(tag, new_tag, closing)){
3461
+ this._callCloseTagListener(tag, true);
3462
+ }
3463
+ }
3464
+ }
3465
+ };
3466
+
3467
+ WYMeditor.XhtmlParser.prototype.getTagReplacements = function()
3468
+ {
3469
+ return this._Listener.getTagReplacements();
3470
+ };
3471
+
3472
+ WYMeditor.XhtmlParser.prototype.normalizeTag = function(tag)
3473
+ {
3474
+ tag = tag.replace(/^([\s<\/>]*)|([\s<\/>]*)$/gm,'').toLowerCase();
3475
+ var tags = this._Listener.getTagReplacements();
3476
+ if(tags[tag]){
3477
+ return tags[tag];
3478
+ }
3479
+ return tag;
3480
+ };
3481
+
3482
+ WYMeditor.XhtmlParser.prototype.TagAttributes = function(match, state)
3483
+ {
3484
+ if(WYMeditor.LEXER_SPECIAL == state){
3485
+ this._current_attribute = match;
3486
+ }
3487
+ return true;
3488
+ };
3489
+
3490
+ WYMeditor.XhtmlParser.prototype.DoubleQuotedAttribute = function(match, state)
3491
+ {
3492
+ if(WYMeditor.LEXER_UNMATCHED == state){
3493
+ this._tag_attributes[this._current_attribute] = match;
3494
+ }
3495
+ return true;
3496
+ };
3497
+
3498
+ WYMeditor.XhtmlParser.prototype.SingleQuotedAttribute = function(match, state)
3499
+ {
3500
+ if(WYMeditor.LEXER_UNMATCHED == state){
3501
+ this._tag_attributes[this._current_attribute] = match;
3502
+ }
3503
+ return true;
3504
+ };
3505
+
3506
+ WYMeditor.XhtmlParser.prototype.UnquotedAttribute = function(match, state)
3507
+ {
3508
+ this._tag_attributes[this._current_attribute] = match.replace(/^=/,'');
3509
+ return true;
3510
+ };
3511
+
3512
+
3513
+
3514
+ /**
3515
+ * XHTML Sax parser.
3516
+ *
3517
+ * @author Bermi Ferrer (http://bermi.org)
3518
+ */
3519
+ WYMeditor.XhtmlSaxListener = function()
3520
+ {
3521
+ this.output = '';
3522
+ this.helper = new WYMeditor.XmlHelper();
3523
+ this._open_tags = {};
3524
+ this.validator = WYMeditor.XhtmlValidator;
3525
+ this._tag_stack = [];
3526
+ this.avoided_tags = [];
3527
+
3528
+ this.entities = {
3529
+ '&nbsp;':'&#160;','&iexcl;':'&#161;','&cent;':'&#162;',
3530
+ '&pound;':'&#163;','&curren;':'&#164;','&yen;':'&#165;',
3531
+ '&brvbar;':'&#166;','&sect;':'&#167;','&uml;':'&#168;',
3532
+ '&copy;':'&#169;','&ordf;':'&#170;','&laquo;':'&#171;',
3533
+ '&not;':'&#172;','&shy;':'&#173;','&reg;':'&#174;',
3534
+ '&macr;':'&#175;','&deg;':'&#176;','&plusmn;':'&#177;',
3535
+ '&sup2;':'&#178;','&sup3;':'&#179;','&acute;':'&#180;',
3536
+ '&micro;':'&#181;','&para;':'&#182;','&middot;':'&#183;',
3537
+ '&cedil;':'&#184;','&sup1;':'&#185;','&ordm;':'&#186;',
3538
+ '&raquo;':'&#187;','&frac14;':'&#188;','&frac12;':'&#189;',
3539
+ '&frac34;':'&#190;','&iquest;':'&#191;','&Agrave;':'&#192;',
3540
+ '&Aacute;':'&#193;','&Acirc;':'&#194;','&Atilde;':'&#195;',
3541
+ '&Auml;':'&#196;','&Aring;':'&#197;','&AElig;':'&#198;',
3542
+ '&Ccedil;':'&#199;','&Egrave;':'&#200;','&Eacute;':'&#201;',
3543
+ '&Ecirc;':'&#202;','&Euml;':'&#203;','&Igrave;':'&#204;',
3544
+ '&Iacute;':'&#205;','&Icirc;':'&#206;','&Iuml;':'&#207;',
3545
+ '&ETH;':'&#208;','&Ntilde;':'&#209;','&Ograve;':'&#210;',
3546
+ '&Oacute;':'&#211;','&Ocirc;':'&#212;','&Otilde;':'&#213;',
3547
+ '&Ouml;':'&#214;','&times;':'&#215;','&Oslash;':'&#216;',
3548
+ '&Ugrave;':'&#217;','&Uacute;':'&#218;','&Ucirc;':'&#219;',
3549
+ '&Uuml;':'&#220;','&Yacute;':'&#221;','&THORN;':'&#222;',
3550
+ '&szlig;':'&#223;','&agrave;':'&#224;','&aacute;':'&#225;',
3551
+ '&acirc;':'&#226;','&atilde;':'&#227;','&auml;':'&#228;',
3552
+ '&aring;':'&#229;','&aelig;':'&#230;','&ccedil;':'&#231;',
3553
+ '&egrave;':'&#232;','&eacute;':'&#233;','&ecirc;':'&#234;',
3554
+ '&euml;':'&#235;','&igrave;':'&#236;','&iacute;':'&#237;',
3555
+ '&icirc;':'&#238;','&iuml;':'&#239;','&eth;':'&#240;',
3556
+ '&ntilde;':'&#241;','&ograve;':'&#242;','&oacute;':'&#243;',
3557
+ '&ocirc;':'&#244;','&otilde;':'&#245;','&ouml;':'&#246;',
3558
+ '&divide;':'&#247;','&oslash;':'&#248;','&ugrave;':'&#249;',
3559
+ '&uacute;':'&#250;','&ucirc;':'&#251;','&uuml;':'&#252;',
3560
+ '&yacute;':'&#253;','&thorn;':'&#254;','&yuml;':'&#255;',
3561
+ '&OElig;':'&#338;','&oelig;':'&#339;','&Scaron;':'&#352;',
3562
+ '&scaron;':'&#353;','&Yuml;':'&#376;','&fnof;':'&#402;',
3563
+ '&circ;':'&#710;','&tilde;':'&#732;','&Alpha;':'&#913;',
3564
+ '&Beta;':'&#914;','&Gamma;':'&#915;','&Delta;':'&#916;',
3565
+ '&Epsilon;':'&#917;','&Zeta;':'&#918;','&Eta;':'&#919;',
3566
+ '&Theta;':'&#920;','&Iota;':'&#921;','&Kappa;':'&#922;',
3567
+ '&Lambda;':'&#923;','&Mu;':'&#924;','&Nu;':'&#925;',
3568
+ '&Xi;':'&#926;','&Omicron;':'&#927;','&Pi;':'&#928;',
3569
+ '&Rho;':'&#929;','&Sigma;':'&#931;','&Tau;':'&#932;',
3570
+ '&Upsilon;':'&#933;','&Phi;':'&#934;','&Chi;':'&#935;',
3571
+ '&Psi;':'&#936;','&Omega;':'&#937;','&alpha;':'&#945;',
3572
+ '&beta;':'&#946;','&gamma;':'&#947;','&delta;':'&#948;',
3573
+ '&epsilon;':'&#949;','&zeta;':'&#950;','&eta;':'&#951;',
3574
+ '&theta;':'&#952;','&iota;':'&#953;','&kappa;':'&#954;',
3575
+ '&lambda;':'&#955;','&mu;':'&#956;','&nu;':'&#957;',
3576
+ '&xi;':'&#958;','&omicron;':'&#959;','&pi;':'&#960;',
3577
+ '&rho;':'&#961;','&sigmaf;':'&#962;','&sigma;':'&#963;',
3578
+ '&tau;':'&#964;','&upsilon;':'&#965;','&phi;':'&#966;',
3579
+ '&chi;':'&#967;','&psi;':'&#968;','&omega;':'&#969;',
3580
+ '&thetasym;':'&#977;','&upsih;':'&#978;','&piv;':'&#982;',
3581
+ '&ensp;':'&#8194;','&emsp;':'&#8195;','&thinsp;':'&#8201;',
3582
+ '&zwnj;':'&#8204;','&zwj;':'&#8205;','&lrm;':'&#8206;',
3583
+ '&rlm;':'&#8207;','&ndash;':'&#8211;','&mdash;':'&#8212;',
3584
+ '&lsquo;':'&#8216;','&rsquo;':'&#8217;','&sbquo;':'&#8218;',
3585
+ '&ldquo;':'&#8220;','&rdquo;':'&#8221;','&bdquo;':'&#8222;',
3586
+ '&dagger;':'&#8224;','&Dagger;':'&#8225;','&bull;':'&#8226;',
3587
+ '&hellip;':'&#8230;','&permil;':'&#8240;','&prime;':'&#8242;',
3588
+ '&Prime;':'&#8243;','&lsaquo;':'&#8249;','&rsaquo;':'&#8250;',
3589
+ '&oline;':'&#8254;','&frasl;':'&#8260;','&euro;':'&#8364;',
3590
+ '&image;':'&#8465;','&weierp;':'&#8472;','&real;':'&#8476;',
3591
+ '&trade;':'&#8482;','&alefsym;':'&#8501;','&larr;':'&#8592;',
3592
+ '&uarr;':'&#8593;','&rarr;':'&#8594;','&darr;':'&#8595;',
3593
+ '&harr;':'&#8596;','&crarr;':'&#8629;','&lArr;':'&#8656;',
3594
+ '&uArr;':'&#8657;','&rArr;':'&#8658;','&dArr;':'&#8659;',
3595
+ '&hArr;':'&#8660;','&forall;':'&#8704;','&part;':'&#8706;',
3596
+ '&exist;':'&#8707;','&empty;':'&#8709;','&nabla;':'&#8711;',
3597
+ '&isin;':'&#8712;','&notin;':'&#8713;','&ni;':'&#8715;',
3598
+ '&prod;':'&#8719;','&sum;':'&#8721;','&minus;':'&#8722;',
3599
+ '&lowast;':'&#8727;','&radic;':'&#8730;','&prop;':'&#8733;',
3600
+ '&infin;':'&#8734;','&ang;':'&#8736;','&and;':'&#8743;',
3601
+ '&or;':'&#8744;','&cap;':'&#8745;','&cup;':'&#8746;',
3602
+ '&int;':'&#8747;','&there4;':'&#8756;','&sim;':'&#8764;',
3603
+ '&cong;':'&#8773;','&asymp;':'&#8776;','&ne;':'&#8800;',
3604
+ '&equiv;':'&#8801;','&le;':'&#8804;','&ge;':'&#8805;',
3605
+ '&sub;':'&#8834;','&sup;':'&#8835;','&nsub;':'&#8836;',
3606
+ '&sube;':'&#8838;','&supe;':'&#8839;','&oplus;':'&#8853;',
3607
+ '&otimes;':'&#8855;','&perp;':'&#8869;','&sdot;':'&#8901;',
3608
+ '&lceil;':'&#8968;','&rceil;':'&#8969;','&lfloor;':'&#8970;',
3609
+ '&rfloor;':'&#8971;','&lang;':'&#9001;','&rang;':'&#9002;',
3610
+ '&loz;':'&#9674;','&spades;':'&#9824;','&clubs;':'&#9827;',
3611
+ '&hearts;':'&#9829;','&diams;':'&#9830;'};
3612
+
3613
+ this.block_tags = ["a", "abbr", "acronym", "address", "area", "b",
3614
+ "base", "bdo", "big", "blockquote", "body", "button",
3615
+ "caption", "cite", "code", "col", "colgroup", "dd", "del", "div",
3616
+ "dfn", "dl", "dt", "em", "fieldset", "form", "head", "h1", "h2",
3617
+ "h3", "h4", "h5", "h6", "html", "i", "iframe", "ins",
3618
+ "kbd", "label", "legend", "li", "map", "noscript",
3619
+ "object", "ol", "optgroup", "option", "p", "pre", "q",
3620
+ "samp", "script", "select", "small", "span", "strong", "style",
3621
+ "sub", "sup", "table", "tbody", "td", "textarea", "tfoot", "th",
3622
+ "thead", "title", "tr", "tt", "ul", "var", "extends"];
3623
+
3624
+
3625
+ this.inline_tags = ["br", "embed", "hr", "img", "input", "param"];
3626
+
3627
+ return this;
3628
+ };
3629
+
3630
+ WYMeditor.XhtmlSaxListener.prototype.shouldCloseTagAutomatically = function(tag, now_on_tag, closing)
3631
+ {
3632
+ var closing = closing || false;
3633
+ if(tag == 'td'){
3634
+ if((closing && now_on_tag == 'tr') || (!closing && now_on_tag == 'td')){
3635
+ return true;
3636
+ }
3637
+ }
3638
+ if(tag == 'option'){
3639
+ if((closing && now_on_tag == 'select') || (!closing && now_on_tag == 'option')){
3640
+ return true;
3641
+ }
3642
+ }
3643
+ return false;
3644
+ };
3645
+
3646
+ WYMeditor.XhtmlSaxListener.prototype.beforeParsing = function(raw)
3647
+ {
3648
+ this.output = '';
3649
+ return raw;
3650
+ };
3651
+
3652
+ WYMeditor.XhtmlSaxListener.prototype.afterParsing = function(xhtml)
3653
+ {
3654
+ xhtml = this.replaceNamedEntities(xhtml);
3655
+ xhtml = this.joinRepeatedEntities(xhtml);
3656
+ xhtml = this.removeEmptyTags(xhtml);
3657
+ return xhtml;
3658
+ };
3659
+
3660
+ WYMeditor.XhtmlSaxListener.prototype.replaceNamedEntities = function(xhtml)
3661
+ {
3662
+ for (var entity in this.entities) {
3663
+ xhtml = xhtml.replace(entity, this.entities[entity]);
3664
+ }
3665
+ return xhtml;
3666
+ };
3667
+
3668
+ WYMeditor.XhtmlSaxListener.prototype.joinRepeatedEntities = function(xhtml)
3669
+ {
3670
+ var tags = 'em|strong|sub|sup|acronym|pre|del|address';
3671
+ return xhtml.replace(new RegExp('<\/('+tags+')><\\1>' ,''),'').
3672
+ replace(new RegExp('(\s*<('+tags+')>\s*){2}(.*)(\s*<\/\\2>\s*){2}' ,''),'<\$2>\$3<\$2>');
3673
+ };
3674
+
3675
+ WYMeditor.XhtmlSaxListener.prototype.removeEmptyTags = function(xhtml)
3676
+ {
3677
+ return xhtml.replace(new RegExp('<('+this.block_tags.join("|").replace(/\|td/,'')+')>(<br \/>|&#160;|&nbsp;|\\s)*<\/\\1>' ,'g'),'');
3678
+ };
3679
+
3680
+ WYMeditor.XhtmlSaxListener.prototype.getResult = function()
3681
+ {
3682
+ return this.output;
3683
+ };
3684
+
3685
+ WYMeditor.XhtmlSaxListener.prototype.getTagReplacements = function()
3686
+ {
3687
+ return {'b':'strong', 'i':'em'};
3688
+ };
3689
+
3690
+ WYMeditor.XhtmlSaxListener.prototype.addContent = function(text)
3691
+ {
3692
+ this.output += text;
3693
+ };
3694
+
3695
+ WYMeditor.XhtmlSaxListener.prototype.addComment = function(text)
3696
+ {
3697
+ if(this.remove_comments){
3698
+ this.output += text;
3699
+ }
3700
+ };
3701
+
3702
+ WYMeditor.XhtmlSaxListener.prototype.addScript = function(text)
3703
+ {
3704
+ if(!this.remove_scripts){
3705
+ this.output += text;
3706
+ }
3707
+ };
3708
+
3709
+ WYMeditor.XhtmlSaxListener.prototype.addCss = function(text)
3710
+ {
3711
+ if(!this.remove_embeded_styles){
3712
+ this.output += text;
3713
+ }
3714
+ };
3715
+
3716
+ WYMeditor.XhtmlSaxListener.prototype.openBlockTag = function(tag, attributes)
3717
+ {
3718
+ this.output += this.helper.tag(tag, this.validator.getValidTagAttributes(tag, attributes), true);
3719
+ };
3720
+
3721
+ WYMeditor.XhtmlSaxListener.prototype.inlineTag = function(tag, attributes)
3722
+ {
3723
+ this.output += this.helper.tag(tag, this.validator.getValidTagAttributes(tag, attributes));
3724
+ };
3725
+
3726
+ WYMeditor.XhtmlSaxListener.prototype.openUnknownTag = function(tag, attributes)
3727
+ {
3728
+ //this.output += this.helper.tag(tag, attributes, true);
3729
+ };
3730
+
3731
+ WYMeditor.XhtmlSaxListener.prototype.closeBlockTag = function(tag)
3732
+ {
3733
+ this.output = this.output.replace(/<br \/>$/, '')+this._getClosingTagContent('before', tag)+"</"+tag+">"+this._getClosingTagContent('after', tag);
3734
+ };
3735
+
3736
+ WYMeditor.XhtmlSaxListener.prototype.closeUnknownTag = function(tag)
3737
+ {
3738
+ //this.output += "</"+tag+">";
3739
+ };
3740
+
3741
+ WYMeditor.XhtmlSaxListener.prototype.closeUnopenedTag = function(tag)
3742
+ {
3743
+ this.output += "</"+tag+">";
3744
+ };
3745
+
3746
+ WYMeditor.XhtmlSaxListener.prototype.avoidStylingTagsAndAttributes = function()
3747
+ {
3748
+ this.avoided_tags = ['div','span'];
3749
+ this.validator.skiped_attributes = ['style'];
3750
+ this.validator.skiped_attribute_values = ['MsoNormal','main1']; // MS Word attributes for class
3751
+ this._avoiding_tags_implicitly = true;
3752
+ };
3753
+
3754
+ WYMeditor.XhtmlSaxListener.prototype.allowStylingTagsAndAttributes = function()
3755
+ {
3756
+ this.avoided_tags = [];
3757
+ this.validator.skiped_attributes = [];
3758
+ this.validator.skiped_attribute_values = [];
3759
+ this._avoiding_tags_implicitly = false;
3760
+ };
3761
+
3762
+ WYMeditor.XhtmlSaxListener.prototype.isBlockTag = function(tag)
3763
+ {
3764
+ return !WYMeditor.Helper.contains(this.avoided_tags, tag) && WYMeditor.Helper.contains(this.block_tags, tag);
3765
+ };
3766
+
3767
+ WYMeditor.XhtmlSaxListener.prototype.isInlineTag = function(tag)
3768
+ {
3769
+ return !WYMeditor.Helper.contains(this.avoided_tags, tag) && WYMeditor.Helper.contains(this.inline_tags, tag);
3770
+ };
3771
+
3772
+ WYMeditor.XhtmlSaxListener.prototype.insertContentAfterClosingTag = function(tag, content)
3773
+ {
3774
+ this._insertContentWhenClosingTag('after', tag, content);
3775
+ };
3776
+
3777
+ WYMeditor.XhtmlSaxListener.prototype.insertContentBeforeClosingTag = function(tag, content)
3778
+ {
3779
+ this._insertContentWhenClosingTag('before', tag, content);
3780
+ };
3781
+
3782
+ WYMeditor.XhtmlSaxListener.prototype.fixNestingBeforeOpeningBlockTag = function(tag, attributes)
3783
+ {
3784
+ if(tag != 'li' && (tag == 'ul' || tag == 'ol') && this.last_tag && !this.last_tag_opened && this.last_tag == 'li'){
3785
+ this.output = this.output.replace(/<\/li>$/, '');
3786
+ this.insertContentAfterClosingTag(tag, '</li>');
3787
+ }
3788
+ };
3789
+
3790
+ WYMeditor.XhtmlSaxListener.prototype._insertContentWhenClosingTag = function(position, tag, content)
3791
+ {
3792
+ if(!this['_insert_'+position+'_closing']){
3793
+ this['_insert_'+position+'_closing'] = [];
3794
+ }
3795
+ if(!this['_insert_'+position+'_closing'][tag]){
3796
+ this['_insert_'+position+'_closing'][tag] = [];
3797
+ }
3798
+ this['_insert_'+position+'_closing'][tag].push(content);
3799
+ };
3800
+
3801
+ WYMeditor.XhtmlSaxListener.prototype._getClosingTagContent = function(position, tag)
3802
+ {
3803
+ if( this['_insert_'+position+'_closing'] &&
3804
+ this['_insert_'+position+'_closing'][tag] &&
3805
+ this['_insert_'+position+'_closing'][tag].length > 0){
3806
+ return this['_insert_'+position+'_closing'][tag].pop();
3807
+ }
3808
+ return '';
3809
+ };
3810
+
3811
+
3812
+ /********** CSS PARSER **********/
3813
+
3814
+
3815
+ WYMeditor.WymCssLexer = function(parser, only_wym_blocks)
3816
+ {
3817
+ var only_wym_blocks = (typeof only_wym_blocks == 'undefined' ? true : only_wym_blocks);
3818
+
3819
+ $.extend(this, new WYMeditor.Lexer(parser, (only_wym_blocks?'Ignore':'WymCss')));
3820
+
3821
+ this.mapHandler('WymCss', 'Ignore');
3822
+
3823
+ if(only_wym_blocks == true){
3824
+ this.addEntryPattern("/\\\x2a[<\\s]*WYMeditor[>\\s]*\\\x2a/", 'Ignore', 'WymCss');
3825
+ this.addExitPattern("/\\\x2a[<\/\\s]*WYMeditor[>\\s]*\\\x2a/", 'WymCss');
3826
+ }
3827
+
3828
+ this.addSpecialPattern("\\\x2e[a-z-_0-9]+[\\sa-z1-6]*", 'WymCss', 'WymCssStyleDeclaration');
3829
+
3830
+ this.addEntryPattern("/\\\x2a", 'WymCss', 'WymCssComment');
3831
+ this.addExitPattern("\\\x2a/", 'WymCssComment');
3832
+
3833
+ this.addEntryPattern("\x7b", 'WymCss', 'WymCssStyle');
3834
+ this.addExitPattern("\x7d", 'WymCssStyle');
3835
+
3836
+ this.addEntryPattern("/\\\x2a", 'WymCssStyle', 'WymCssFeddbackStyle');
3837
+ this.addExitPattern("\\\x2a/", 'WymCssFeddbackStyle');
3838
+
3839
+ return this;
3840
+ };
3841
+
3842
+ WYMeditor.WymCssParser = function()
3843
+ {
3844
+ this._in_style = false;
3845
+ this._has_title = false;
3846
+ this.only_wym_blocks = true;
3847
+ this.css_settings = {'classesItems':[], 'editorStyles':[], 'dialogStyles':[]};
3848
+ return this;
3849
+ };
3850
+
3851
+ WYMeditor.WymCssParser.prototype.parse = function(raw, only_wym_blocks)
3852
+ {
3853
+ var only_wym_blocks = (typeof only_wym_blocks == 'undefined' ? this.only_wym_blocks : only_wym_blocks);
3854
+ this._Lexer = new WYMeditor.WymCssLexer(this, only_wym_blocks);
3855
+ this._Lexer.parse(raw);
3856
+ };
3857
+
3858
+ WYMeditor.WymCssParser.prototype.Ignore = function(match, state)
3859
+ {
3860
+ return true;
3861
+ };
3862
+
3863
+ WYMeditor.WymCssParser.prototype.WymCssComment = function(text, status)
3864
+ {
3865
+ if(text.match(/end[a-z0-9\s]*wym[a-z0-9\s]*/mi)){
3866
+ return false;
3867
+ }
3868
+ if(status == WYMeditor.LEXER_UNMATCHED){
3869
+ if(!this._in_style){
3870
+ this._has_title = true;
3871
+ this._current_item = {'title':WYMeditor.Helper.trim(text)};
3872
+ }else{
3873
+ if(this._current_item[this._current_element]){
3874
+ if(!this._current_item[this._current_element].expressions){
3875
+ this._current_item[this._current_element].expressions = [text];
3876
+ }else{
3877
+ this._current_item[this._current_element].expressions.push(text);
3878
+ }
3879
+ }
3880
+ }
3881
+ this._in_style = true;
3882
+ }
3883
+ return true;
3884
+ };
3885
+
3886
+ WYMeditor.WymCssParser.prototype.WymCssStyle = function(match, status)
3887
+ {
3888
+ if(status == WYMeditor.LEXER_UNMATCHED){
3889
+ match = WYMeditor.Helper.trim(match);
3890
+ if(match != ''){
3891
+ this._current_item[this._current_element].style = match;
3892
+ }
3893
+ }else if (status == WYMeditor.LEXER_EXIT){
3894
+ this._in_style = false;
3895
+ this._has_title = false;
3896
+ this.addStyleSetting(this._current_item);
3897
+ }
3898
+ return true;
3899
+ };
3900
+
3901
+ WYMeditor.WymCssParser.prototype.WymCssFeddbackStyle = function(match, status)
3902
+ {
3903
+ if(status == WYMeditor.LEXER_UNMATCHED){
3904
+ this._current_item[this._current_element].feedback_style = match.replace(/^([\s\/\*]*)|([\s\/\*]*)$/gm,'');
3905
+ }
3906
+ return true;
3907
+ };
3908
+
3909
+ WYMeditor.WymCssParser.prototype.WymCssStyleDeclaration = function(match)
3910
+ {
3911
+ match = match.replace(/^([\s\.]*)|([\s\.*]*)$/gm, '');
3912
+
3913
+ var tag = '';
3914
+ if(match.indexOf(' ') > 0){
3915
+ var parts = match.split(' ');
3916
+ this._current_element = parts[0];
3917
+ var tag = parts[1];
3918
+ }else{
3919
+ this._current_element = match;
3920
+ }
3921
+
3922
+ if(!this._has_title){
3923
+ this._current_item = {'title':(!tag?'':tag.toUpperCase()+': ')+this._current_element};
3924
+ this._has_title = true;
3925
+ }
3926
+
3927
+ if(!this._current_item[this._current_element]){
3928
+ this._current_item[this._current_element] = {'name':this._current_element};
3929
+ }
3930
+ if(tag){
3931
+ if(!this._current_item[this._current_element].tags){
3932
+ this._current_item[this._current_element].tags = [tag];
3933
+ }else{
3934
+ this._current_item[this._current_element].tags.push(tag);
3935
+ }
3936
+ }
3937
+ return true;
3938
+ };
3939
+
3940
+ WYMeditor.WymCssParser.prototype.addStyleSetting = function(style_details)
3941
+ {
3942
+ for (var name in style_details){
3943
+ var details = style_details[name];
3944
+ if(typeof details == 'object' && name != 'title'){
3945
+
3946
+ this.css_settings.classesItems.push({
3947
+ 'name': WYMeditor.Helper.trim(details.name),
3948
+ 'title': style_details.title,
3949
+ 'expr' : WYMeditor.Helper.trim((details.expressions||details.tags).join(', '))
3950
+ });
3951
+ if(details.feedback_style){
3952
+ this.css_settings.editorStyles.push({
3953
+ 'name': '.'+ WYMeditor.Helper.trim(details.name),
3954
+ 'css': details.feedback_style
3955
+ });
3956
+ }
3957
+ if(details.style){
3958
+ this.css_settings.dialogStyles.push({
3959
+ 'name': '.'+ WYMeditor.Helper.trim(details.name),
3960
+ 'css': details.style
3961
+ });
3962
+ }
3963
+ }
3964
+ }
3965
+ };
3966
+
3967
+ /********** HELPERS **********/
3968
+
3969
+ // Returns true if it is a text node with whitespaces only
3970
+ $.fn.isPhantomNode = function() {
3971
+ if (this[0].nodeType == 3)
3972
+ return !(/[^\t\n\r ]/.test(this[0].data));
3973
+
3974
+ return false;
3975
+ };
3976
+
3977
+ WYMeditor.isPhantomNode = function(n) {
3978
+ if (n.nodeType == 3)
3979
+ return !(/[^\t\n\r ]/.test(n.data));
3980
+
3981
+ return false;
3982
+ };
3983
+
3984
+ WYMeditor.isPhantomString = function(str) {
3985
+ return !(/[^\t\n\r ]/.test(str));
3986
+ };
3987
+
3988
+ // Returns the Parents or the node itself
3989
+ // jqexpr = a jQuery expression
3990
+ $.fn.parentsOrSelf = function(jqexpr) {
3991
+ var n = this;
3992
+
3993
+ if (n[0].nodeType == 3)
3994
+ n = n.parents().slice(0,1);
3995
+
3996
+ // if (n.is(jqexpr)) // XXX should work, but doesn't (probably a jQuery bug)
3997
+ if (n.filter(jqexpr).size() == 1)
3998
+ return n;
3999
+ else
4000
+ return n.parents(jqexpr).slice(0,1);
4001
+ };
4002
+
4003
+ // String & array helpers
4004
+
4005
+ WYMeditor.Helper = {
4006
+
4007
+ //replace all instances of 'old' by 'rep' in 'str' string
4008
+ replaceAll: function(str, old, rep) {
4009
+ return(str.replace(new RegExp(old, "g"), rep));
4010
+ },
4011
+
4012
+ //insert 'inserted' at position 'pos' in 'str' string
4013
+ insertAt: function(str, inserted, pos) {
4014
+ return(str.substr(0,pos) + inserted + str.substring(pos));
4015
+ },
4016
+
4017
+ //trim 'str' string
4018
+ trim: function(str) {
4019
+ return str.replace(/^(\s*)|(\s*)$/gm,'');
4020
+ },
4021
+
4022
+ //return true if 'arr' array contains 'elem', or false
4023
+ contains: function(arr, elem) {
4024
+ for (var i = 0; i < arr.length; i++) {
4025
+ if (arr[i] === elem) return true;
4026
+ }
4027
+ return false;
4028
+ },
4029
+
4030
+ //return 'item' position in 'arr' array, or -1
4031
+ indexOf: function(arr, item) {
4032
+ var ret=-1;
4033
+ for(var i = 0; i < arr.length; i++) {
4034
+ if (arr[i] == item) {
4035
+ ret = i;
4036
+ break;
4037
+ }
4038
+ }
4039
+ return(ret);
4040
+ },
4041
+
4042
+ //return 'item' object in 'arr' array, checking its 'name' property, or null
4043
+ findByName: function(arr, name) {
4044
+ for(var i = 0; i < arr.length; i++) {
4045
+ var item = arr[i];
4046
+ if(item.name == name) return(item);
4047
+ }
4048
+ return(null);
4049
+ }
4050
+ };
4051
+
4052
+ function titleize(words) {
4053
+ parts = [];
4054
+ $.each(words.replace(/\./, '').replace(/[-_]/, ' ').split(' '), function(index, part){
4055
+ parts.push(part.substring(0,1).toUpperCase() + part.substring(1));
4056
+ });
4057
+ return parts.join(" ");
4058
+ }
4059
+
4060
+ /*
4061
+ * WYMeditor : what you see is What You Mean web-based editor
4062
+ * Copyright (c) 2008 Jean-Francois Hovinne, http://www.wymeditor.org/
4063
+ * Dual licensed under the MIT (MIT-license.txt)
4064
+ * and GPL (GPL-license.txt) licenses.
4065
+ *
4066
+ * For further information visit:
4067
+ * http://www.wymeditor.org/
4068
+ *
4069
+ * File Name:
4070
+ * jquery.wymeditor.explorer.js
4071
+ * MSIE specific class and functions.
4072
+ * See the documentation for more info.
4073
+ *
4074
+ * File Authors:
4075
+ * Jean-Francois Hovinne (jf.hovinne a-t wymeditor dotorg)
4076
+ * Bermi Ferrer (wymeditor a-t bermi dotorg)
4077
+ * Frédéric Palluel-Lafleur (fpalluel a-t gmail dotcom)
4078
+ * Jonatan Lundin (jonatan.lundin _at_ gmail.com)
4079
+ */
4080
+
4081
+ WYMeditor.WymClassExplorer = function(wym) {
4082
+ this._wym = wym;
4083
+ this._class = "className";
4084
+ this._newLine = "\r\n";
4085
+ };
4086
+
4087
+ WYMeditor.WymClassExplorer.prototype.initIframe = function(iframe) {
4088
+
4089
+ //This function is executed twice, though it is called once!
4090
+ //But MSIE needs that, otherwise designMode won't work.
4091
+ //Weird.
4092
+
4093
+ this._iframe = iframe;
4094
+ this._doc = iframe.contentWindow.document;
4095
+
4096
+ //add css rules from options
4097
+ var styles = this._doc.styleSheets[0];
4098
+ var aCss = eval(this._options.editorStyles);
4099
+
4100
+ this.addCssRules(this._doc, aCss);
4101
+
4102
+ this._doc.title = this._wym._index;
4103
+
4104
+ //set the text direction
4105
+ $('html', this._doc).attr('dir', this._options.direction);
4106
+
4107
+ //init html value
4108
+ $(this._doc.body).html(this._wym._html);
4109
+
4110
+ //handle events
4111
+ var wym = this;
4112
+
4113
+ this._doc.body.onfocus = function()
4114
+ {wym._doc.designMode = "on"; wym._doc = iframe.contentWindow.document;};
4115
+ this._doc.onbeforedeactivate = function() {wym.saveCaret();};
4116
+ this._doc.onkeyup = function() {
4117
+ wym.saveCaret();
4118
+ wym.keyup();
4119
+ };
4120
+ this._doc.onclick = function() {wym.saveCaret();};
4121
+
4122
+ this._doc.body.onbeforepaste = function() {
4123
+ wym._iframe.contentWindow.event.returnValue = false;
4124
+ };
4125
+
4126
+ this._doc.body.onpaste = function() {
4127
+ wym._iframe.contentWindow.event.returnValue = false;
4128
+ // Trident doesn't need to intercept the paste as it can access the clipboard easily.
4129
+ wym.paste(window.clipboardData.getData("Text"));
4130
+ };
4131
+
4132
+ //callback can't be executed twice, so we check
4133
+ if(this._initialized) {
4134
+
4135
+ //pre-bind functions
4136
+ if($.isFunction(this._options.preBind)) this._options.preBind(this);
4137
+
4138
+ //bind external events
4139
+ this._wym.bindEvents();
4140
+
4141
+ //post-init functions
4142
+ if($.isFunction(this._options.postInit)) this._options.postInit(this);
4143
+
4144
+ //add event listeners to doc elements, e.g. images
4145
+ this.listen();
4146
+ }
4147
+
4148
+ this._initialized = true;
4149
+
4150
+ //init designMode
4151
+ this._doc.designMode="on";
4152
+ try{
4153
+ // (bermi's note) noticed when running unit tests on IE6
4154
+ // Is this really needed, it trigger an unexisting property on IE6
4155
+ this._doc = iframe.contentWindow.document;
4156
+ }catch(e){}
4157
+ };
4158
+
4159
+ WYMeditor.WymClassExplorer.prototype._exec = function(cmd,param) {
4160
+ switch(cmd) {
4161
+ case WYMeditor.INDENT: case WYMeditor.OUTDENT:
4162
+ // determine whether we're in a list item.
4163
+ if (this.findUp(this.container(), WYMeditor.LI)) {
4164
+ this._doc.execCommand(cmd);
4165
+ }
4166
+ break;
4167
+ default:
4168
+ if(param) this._doc.execCommand(cmd,false,param);
4169
+ else this._doc.execCommand(cmd);
4170
+ break;
4171
+ }
4172
+
4173
+ this.listen();
4174
+ };
4175
+
4176
+ WYMeditor.WymClassExplorer.prototype.selected = function() {
4177
+ if((caretPos = this._iframe.contentWindow.document.caretPos)!=null && caretPos.parentElement!=undefined) {
4178
+ return(caretPos.parentElement());
4179
+ }
4180
+ };
4181
+
4182
+ WYMeditor.WymClassExplorer.prototype.saveCaret = function() {
4183
+ this._doc.caretPos = this._doc.selection.createRange();
4184
+ };
4185
+
4186
+ WYMeditor.WymClassExplorer.prototype.addCssRule = function(styles, oCss) {
4187
+ styles.addRule(oCss.name, oCss.css);
4188
+ };
4189
+
4190
+ WYMeditor.WymClassExplorer.prototype.insert = function(html) {
4191
+
4192
+ // Get the current selection
4193
+ var range = this._doc.selection.createRange();
4194
+
4195
+ // Check if the current selection is inside the editor
4196
+ if ( $(range.parentElement()).parents( this._options.iframeBodySelector ).is('*') ) {
4197
+ try {
4198
+ // Overwrite selection with provided html
4199
+ range.pasteHTML(html);
4200
+ } catch (e) { }
4201
+ } else {
4202
+ // Fall back to the internal paste function if there's no selection
4203
+ this.paste(html);
4204
+ }
4205
+ };
4206
+
4207
+ WYMeditor.WymClassExplorer.prototype.wrap = function(left, right) {
4208
+
4209
+ // Get the current selection
4210
+ var range = this._doc.selection.createRange();
4211
+
4212
+ // Check if the current selection is inside the editor
4213
+ if ( $(range.parentElement()).parents( this._options.iframeBodySelector ).is('*') ) {
4214
+ try {
4215
+ // Overwrite selection with provided html
4216
+ range.pasteHTML(left + range.text + right);
4217
+ } catch (e) { }
4218
+ }
4219
+ };
4220
+
4221
+ WYMeditor.WymClassExplorer.prototype.unwrap = function() {
4222
+
4223
+ // Get the current selection
4224
+ var range = this._doc.selection.createRange();
4225
+
4226
+ // Check if the current selection is inside the editor
4227
+ if ( $(range.parentElement()).parents( this._options.iframeBodySelector ).is('*') ) {
4228
+ try {
4229
+ // Unwrap selection
4230
+ var text = range.text;
4231
+ this._exec( 'Cut' );
4232
+ range.pasteHTML( text );
4233
+ } catch (e) { }
4234
+ }
4235
+ };
4236
+
4237
+ //keyup handler
4238
+ WYMeditor.WymClassExplorer.prototype.keyup = function() {
4239
+ this._selected_image = null;
4240
+ };
4241
+
4242
+ WYMeditor.WymClassExplorer.prototype.setFocusToNode = function(node) {
4243
+ var range = this._doc.selection.createRange();
4244
+ range.moveToElementText(node);
4245
+ range.collapse(false);
4246
+ range.move('character',-1);
4247
+ range.select();
4248
+ node.focus();
4249
+ };
4250
+
4251
+ /*
4252
+ * WYMeditor : what you see is What You Mean web-based editor
4253
+ * Copyright (c) 2008 Jean-Francois Hovinne, http://www.wymeditor.org/
4254
+ * Dual licensed under the MIT (MIT-license.txt)
4255
+ * and GPL (GPL-license.txt) licenses.
4256
+ *
4257
+ * For further information visit:
4258
+ * http://www.wymeditor.org/
4259
+ *
4260
+ * File Name:
4261
+ * jquery.wymeditor.mozilla.js
4262
+ * Gecko specific class and functions.
4263
+ * See the documentation for more info.
4264
+ *
4265
+ * File Authors:
4266
+ * Jean-Francois Hovinne (jf.hovinne a-t wymeditor dotorg)
4267
+ * Volker Mische (vmx a-t gmx dotde)
4268
+ * Bermi Ferrer (wymeditor a-t bermi dotorg)
4269
+ * Frédéric Palluel-Lafleur (fpalluel a-t gmail dotcom)
4270
+ */
4271
+
4272
+ WYMeditor.WymClassMozilla = function(wym) {
4273
+
4274
+ this._wym = wym;
4275
+ this._class = "class";
4276
+ this._newLine = "\n";
4277
+ };
4278
+
4279
+ WYMeditor.WymClassMozilla.prototype.initIframe = function(iframe) {
4280
+
4281
+ this._iframe = iframe;
4282
+ this._doc = iframe.contentDocument;
4283
+
4284
+ //add css rules from options
4285
+
4286
+ var styles = this._doc.styleSheets[0];
4287
+ var aCss = eval(this._options.editorStyles);
4288
+
4289
+ this.addCssRules(this._doc, aCss);
4290
+
4291
+ this._doc.title = this._wym._index;
4292
+
4293
+ //set the text direction
4294
+ $('html', this._doc).attr('dir', this._options.direction);
4295
+
4296
+ //init html value
4297
+ this.html(this._wym._html);
4298
+
4299
+ //init designMode
4300
+ this.enableDesignMode();
4301
+
4302
+ //pre-bind functions
4303
+ if($.isFunction(this._options.preBind)) this._options.preBind(this);
4304
+
4305
+ //bind external events
4306
+ this._wym.bindEvents();
4307
+
4308
+ //bind editor keydown events
4309
+ $(this._doc).bind("keydown", this.keydown);
4310
+
4311
+ //bind editor keyup events
4312
+ $(this._doc).bind("keyup", this.keyup);
4313
+
4314
+ //bind editor paste events
4315
+ $(this._doc).bind("paste", this.intercept_paste);
4316
+
4317
+ //bind editor focus events (used to reset designmode - Gecko bug)
4318
+ $(this._doc).bind("focus", this.enableDesignMode);
4319
+
4320
+ //post-init functions
4321
+ if($.isFunction(this._options.postInit)) this._options.postInit(this);
4322
+
4323
+ //add event listeners to doc elements, e.g. images
4324
+ this.listen();
4325
+ };
4326
+
4327
+ /* @name html
4328
+ * @description Get/Set the html value
4329
+ */
4330
+ WYMeditor.WymClassMozilla.prototype.html = function(html) {
4331
+
4332
+ if(typeof html === 'string') {
4333
+
4334
+ //disable designMode
4335
+ try { this._doc.designMode = "off"; } catch(e) { };
4336
+
4337
+ //replace em by i and strong by bold
4338
+ //(designMode issue)
4339
+ html = html.replace(/<em(\b[^>]*)>/gi, "<i$1>")
4340
+ .replace(/<\/em>/gi, "</i>")
4341
+ .replace(/<strong(\b[^>]*)>/gi, "<b$1>")
4342
+ .replace(/<\/strong>/gi, "</b>");
4343
+
4344
+ //update the html body
4345
+ $(this._doc.body).html(html);
4346
+
4347
+ //re-init designMode
4348
+ this.enableDesignMode();
4349
+ }
4350
+ else return($(this._doc.body).html());
4351
+ };
4352
+
4353
+ WYMeditor.WymClassMozilla.prototype._exec = function(cmd,param) {
4354
+
4355
+ if(!this.selected()) return(false);
4356
+
4357
+ switch(cmd) {
4358
+
4359
+ case WYMeditor.INDENT: case WYMeditor.OUTDENT:
4360
+ var focusNode = this.selected();
4361
+ var sel = this._iframe.contentWindow.getSelection();
4362
+ var anchorNode = sel.anchorNode;
4363
+ if(anchorNode.nodeName == "#text") anchorNode = anchorNode.parentNode;
4364
+
4365
+ focusNode = this.findUp(focusNode, WYMeditor.BLOCKS);
4366
+ anchorNode = this.findUp(anchorNode, WYMeditor.BLOCKS);
4367
+
4368
+ if(focusNode && focusNode == anchorNode && focusNode.tagName.toLowerCase() == WYMeditor.LI) {
4369
+ var ancestor = focusNode.parentNode.parentNode;
4370
+
4371
+ if(focusNode.parentNode.childNodes.length>1
4372
+ || ancestor.tagName.toLowerCase() == WYMeditor.OL
4373
+ || ancestor.tagName.toLowerCase() == WYMeditor.UL)
4374
+ this._doc.execCommand(cmd,'',null);
4375
+ }
4376
+ break;
4377
+
4378
+ default:
4379
+ if(param) this._doc.execCommand(cmd,'',param);
4380
+ else this._doc.execCommand(cmd,'',null);
4381
+ }
4382
+
4383
+ //set to P if parent = BODY
4384
+ var container = this.selected();
4385
+ if(container.tagName.toLowerCase() == WYMeditor.BODY)
4386
+ this._exec(WYMeditor.FORMAT_BLOCK, WYMeditor.P);
4387
+
4388
+ //add event handlers on doc elements
4389
+
4390
+ this.listen();
4391
+ };
4392
+
4393
+
4394
+
4395
+ /* @name selected
4396
+ * @description Returns the selected container
4397
+ */
4398
+ WYMeditor.WymClassMozilla.prototype.selected = function(upgrade_text_nodes) {
4399
+
4400
+ if (upgrade_text_nodes == null || upgrade_text_nodes.toString() != "true") { upgrade_text_nodes = false; }
4401
+ var sel = this._iframe.contentWindow.getSelection();
4402
+ var node = sel.focusNode;
4403
+ if(node) {
4404
+ if(node.nodeName == "#text"){
4405
+ if (upgrade_text_nodes && sel.toString().length > 0) {
4406
+ actual_node = null;
4407
+ parent_node = sel.focusNode.parentNode;
4408
+ if (parent_node != null) {
4409
+ for (i=0;i<parent_node.childNodes.length;i++){
4410
+ child_node = parent_node.childNodes[i];
4411
+ if (child_node.nodeName != "#text" && child_node.innerHTML == sel.toString()){
4412
+ actual_node = child_node;
4413
+ }
4414
+ }
4415
+ }
4416
+
4417
+ if (actual_node == null) {
4418
+ return this.switchTo(sel, 'span');
4419
+ } else {
4420
+ return actual_node;
4421
+ }
4422
+ }
4423
+ else {
4424
+ return node.parentNode;
4425
+ }
4426
+ }
4427
+ else return(node);
4428
+ }
4429
+ else return(null);
4430
+ };
4431
+
4432
+ WYMeditor.WymClassMozilla.prototype.addCssRule = function(styles, oCss) {
4433
+ styles.insertRule(oCss.name + " {" + oCss.css + "}", styles.cssRules.length);
4434
+ };
4435
+
4436
+
4437
+ //keydown handler, mainly used for keyboard shortcuts
4438
+ WYMeditor.WymClassMozilla.prototype.keydown = function(evt) {
4439
+
4440
+ //'this' is the doc
4441
+ var wym = WYMeditor.INSTANCES[this.title];
4442
+
4443
+ if(evt.ctrlKey){
4444
+ if(evt.keyCode == 66){
4445
+ //CTRL+b => STRONG
4446
+ wym._exec(WYMeditor.BOLD);
4447
+ return false;
4448
+ }
4449
+ if(evt.keyCode == 73){
4450
+ //CTRL+i => EMPHASIS
4451
+ wym._exec(WYMeditor.ITALIC);
4452
+ return false;
4453
+ }
4454
+ }
4455
+ };
4456
+
4457
+ //keyup handler, mainly used for cleanups
4458
+ WYMeditor.WymClassMozilla.prototype.keyup = function(evt) {
4459
+
4460
+ //'this' is the doc
4461
+ var wym = WYMeditor.INSTANCES[this.title];
4462
+ if (wym != null) {
4463
+ wym._selected_image = null;
4464
+ var container = null;
4465
+
4466
+ if(evt.keyCode == 13 && !evt.shiftKey) {
4467
+
4468
+ //RETURN key
4469
+ //cleanup <br><br> between paragraphs
4470
+ $(wym._doc.body).children(WYMeditor.BR).remove();
4471
+
4472
+ //fix PRE bug #73
4473
+ container = wym.selected();
4474
+ if(container && container.tagName.toLowerCase() == WYMeditor.PRE)
4475
+ wym._exec(WYMeditor.FORMAT_BLOCK, WYMeditor.P); //create P after PRE
4476
+ }
4477
+
4478
+ else if(evt.keyCode != 8
4479
+ && evt.keyCode != 17
4480
+ && evt.keyCode != 46
4481
+ && evt.keyCode != 224
4482
+ && !evt.metaKey
4483
+ && !evt.ctrlKey) {
4484
+ //NOT BACKSPACE, NOT DELETE, NOT CTRL, NOT COMMAND
4485
+ //text nodes replaced by P
4486
+
4487
+ wym.format_block();
4488
+ }
4489
+ }
4490
+ };
4491
+
4492
+ WYMeditor.WymClassMozilla.prototype.enableDesignMode = function() {
4493
+ if(this.designMode == "off") {
4494
+ try {
4495
+ this.designMode = "on";
4496
+ this.execCommand("styleWithCSS", '', false);
4497
+ } catch(e) { }
4498
+ }
4499
+ };
4500
+
4501
+ WYMeditor.WymClassMozilla.prototype.setFocusToNode = function(node) {
4502
+ var range = document.createRange();
4503
+ range.selectNode(node);
4504
+ var selected = this._iframe.contentWindow.getSelection();
4505
+ selected.addRange(range);
4506
+ selected.collapse(node, node.childNodes.length);
4507
+ this._iframe.contentWindow.focus();
4508
+ };
4509
+
4510
+ WYMeditor.WymClassMozilla.prototype.openBlockTag = function(tag, attributes)
4511
+ {
4512
+ var attributes = this.validator.getValidTagAttributes(tag, attributes);
4513
+
4514
+ // Handle Mozilla styled spans
4515
+ if(tag == 'span' && attributes.style){
4516
+ var new_tag = this.getTagForStyle(attributes.style);
4517
+ if(new_tag){
4518
+ this._tag_stack.pop();
4519
+ var tag = new_tag;
4520
+ this._tag_stack.push(new_tag);
4521
+ attributes.style = '';
4522
+ }else{
4523
+ return;
4524
+ }
4525
+ }
4526
+
4527
+ this.output += this.helper.tag(tag, attributes, true);
4528
+ };
4529
+
4530
+ WYMeditor.WymClassMozilla.prototype.getTagForStyle = function(style) {
4531
+
4532
+ if(/bold/.test(style)) return 'strong';
4533
+ if(/italic/.test(style)) return 'em';
4534
+ if(/sub/.test(style)) return 'sub';
4535
+ if(/sub/.test(style)) return 'super';
4536
+ return false;
4537
+ };
4538
+
4539
+ /*
4540
+ * WYMeditor : what you see is What You Mean web-based editor
4541
+ * Copyright (c) 2008 Jean-Francois Hovinne, http://www.wymeditor.org/
4542
+ * Dual licensed under the MIT (MIT-license.txt)
4543
+ * and GPL (GPL-license.txt) licenses.
4544
+ *
4545
+ * For further information visit:
4546
+ * http://www.wymeditor.org/
4547
+ *
4548
+ * File Name:
4549
+ * jquery.wymeditor.opera.js
4550
+ * Opera specific class and functions.
4551
+ * See the documentation for more info.
4552
+ *
4553
+ * File Authors:
4554
+ * Jean-Francois Hovinne (jf.hovinne a-t wymeditor dotorg)
4555
+ */
4556
+
4557
+ WYMeditor.WymClassOpera = function(wym) {
4558
+
4559
+ this._wym = wym;
4560
+ this._class = "class";
4561
+ this._newLine = "\r\n";
4562
+ };
4563
+
4564
+ WYMeditor.WymClassOpera.prototype.initIframe = function(iframe) {
4565
+
4566
+ this._iframe = iframe;
4567
+ this._doc = iframe.contentWindow.document;
4568
+
4569
+ //add css rules from options
4570
+ var styles = this._doc.styleSheets[0];
4571
+ var aCss = eval(this._options.editorStyles);
4572
+
4573
+ this.addCssRules(this._doc, aCss);
4574
+
4575
+ this._doc.title = this._wym._index;
4576
+
4577
+ //set the text direction
4578
+ $('html', this._doc).attr('dir', this._options.direction);
4579
+
4580
+ //init designMode
4581
+ this._doc.designMode = "on";
4582
+
4583
+ //init html value
4584
+ this.html(this._wym._html);
4585
+
4586
+ //pre-bind functions
4587
+ if($.isFunction(this._options.preBind)) this._options.preBind(this);
4588
+
4589
+ //bind external events
4590
+ this._wym.bindEvents();
4591
+
4592
+ //bind editor keydown events
4593
+ $(this._doc).bind("keydown", this.keydown);
4594
+
4595
+ //bind editor events
4596
+ $(this._doc).bind("keyup", this.keyup);
4597
+
4598
+ // bind paste events for when this is supported.
4599
+ $(this._doc).bind("paste", this.intercept_paste);
4600
+
4601
+ //post-init functions
4602
+ if($.isFunction(this._options.postInit)) this._options.postInit(this);
4603
+
4604
+ //add event listeners to doc elements, e.g. images
4605
+ this.listen();
4606
+ };
4607
+
4608
+ WYMeditor.WymClassOpera.prototype._exec = function(cmd,param) {
4609
+ if(param) this._doc.execCommand(cmd,false,param);
4610
+ else this._doc.execCommand(cmd);
4611
+
4612
+ this.listen();
4613
+ };
4614
+
4615
+ WYMeditor.WymClassOpera.prototype.selected = function() {
4616
+ var sel=this._iframe.contentWindow.getSelection();
4617
+ var node=sel.focusNode;
4618
+ if(node) {
4619
+ if(node.nodeName=="#text")return(node.parentNode);
4620
+ else return(node);
4621
+ } else {
4622
+ return(null);
4623
+ }
4624
+ };
4625
+
4626
+ WYMeditor.WymClassOpera.prototype.addCssRule = function(styles, oCss) {
4627
+ styles.insertRule(oCss.name + " {" + oCss.css + "}", styles.cssRules.length);
4628
+ };
4629
+
4630
+ //keydown handler
4631
+ WYMeditor.WymClassOpera.prototype.keydown = function(evt) {
4632
+
4633
+ //'this' is the doc
4634
+ var wym = WYMeditor.INSTANCES[this.title];
4635
+ var sel = wym._iframe.contentWindow.getSelection();
4636
+ startNode = sel.getRangeAt(0).startContainer;
4637
+
4638
+ //Get a P instead of no container
4639
+ if(!$(startNode).parentsOrSelf(
4640
+ WYMeditor.MAIN_CONTAINERS.join(","))[0]
4641
+ && !$(startNode).parentsOrSelf('li')
4642
+ && evt.keyCode != WYMeditor.KEY.ENTER
4643
+ && evt.keyCode != WYMeditor.KEY.LEFT
4644
+ && evt.keyCode != WYMeditor.KEY.UP
4645
+ && evt.keyCode != WYMeditor.KEY.RIGHT
4646
+ && evt.keyCode != WYMeditor.KEY.DOWN
4647
+ && evt.keyCode != WYMeditor.KEY.BACKSPACE
4648
+ && evt.keyCode != WYMeditor.KEY.DELETE)
4649
+ wym._exec(WYMeditor.FORMAT_BLOCK, WYMeditor.P);
4650
+
4651
+ };
4652
+
4653
+ //keyup handler
4654
+ WYMeditor.WymClassOpera.prototype.keyup = function(evt) {
4655
+
4656
+ //'this' is the doc
4657
+ var wym = WYMeditor.INSTANCES[this.title];
4658
+ wym._selected_image = null;
4659
+ };
4660
+
4661
+ // TODO: implement me
4662
+ WYMeditor.WymClassOpera.prototype.setFocusToNode = function(node) {
4663
+
4664
+ };
4665
+
4666
+ /*
4667
+ * WYMeditor : what you see is What You Mean web-based editor
4668
+ * Copyright (c) 2008 Jean-Francois Hovinne, http://www.wymeditor.org/
4669
+ * Dual licensed under the MIT (MIT-license.txt)
4670
+ * and GPL (GPL-license.txt) licenses.
4671
+ *
4672
+ * For further information visit:
4673
+ * http://www.wymeditor.org/
4674
+ *
4675
+ * File Name:
4676
+ * jquery.wymeditor.safari.js
4677
+ * Safari specific class and functions.
4678
+ * See the documentation for more info.
4679
+ *
4680
+ * File Authors:
4681
+ * Jean-Francois Hovinne (jf.hovinne a-t wymeditor dotorg)
4682
+ * Scott Lewis (lewiscot a-t gmail dotcom)
4683
+ */
4684
+
4685
+ WYMeditor.WymClassSafari = function(wym) {
4686
+
4687
+ this._wym = wym;
4688
+ this._class = "class";
4689
+ this._newLine = "\n";
4690
+ };
4691
+
4692
+ WYMeditor.WymClassSafari.prototype.initIframe = function(iframe) {
4693
+
4694
+ this._iframe = iframe;
4695
+ this._doc = iframe.contentDocument;
4696
+
4697
+ //add css rules from options
4698
+
4699
+ var styles = this._doc.styleSheets[0];
4700
+ var aCss = eval(this._options.editorStyles);
4701
+
4702
+ this.addCssRules(this._doc, aCss);
4703
+
4704
+ this._doc.title = this._wym._index;
4705
+
4706
+ //set the text direction
4707
+ $('html', this._doc).attr('dir', this._options.direction);
4708
+
4709
+ //init designMode
4710
+ this._doc.designMode = "on";
4711
+
4712
+ //init html value
4713
+ this.html(this._wym._html);
4714
+
4715
+ //pre-bind functions
4716
+ if($.isFunction(this._options.preBind)) this._options.preBind(this);
4717
+
4718
+ //bind external events
4719
+ this._wym.bindEvents();
4720
+
4721
+ //bind editor keydown events
4722
+ $(this._doc).bind("keydown", this.keydown);
4723
+
4724
+ //bind editor keyup events
4725
+ $(this._doc).bind("keyup", this.keyup);
4726
+
4727
+ // bind paste events
4728
+ $(this._doc).bind("paste", this.intercept_paste);
4729
+
4730
+ //post-init functions
4731
+ if($.isFunction(this._options.postInit)) this._options.postInit(this);
4732
+
4733
+ //add event listeners to doc elements, e.g. images
4734
+ this.listen();
4735
+ };
4736
+
4737
+ WYMeditor.WymClassSafari.prototype._exec = function(cmd,param) {
4738
+
4739
+ if(!this.selected()) return(false);
4740
+
4741
+ switch(cmd) {
4742
+
4743
+ case WYMeditor.INDENT: case WYMeditor.OUTDENT:
4744
+
4745
+ var focusNode = this.selected();
4746
+ var sel = this._iframe.contentWindow.getSelection();
4747
+ var anchorNode = sel.anchorNode;
4748
+ if(anchorNode.nodeName == "#text") anchorNode = anchorNode.parentNode;
4749
+
4750
+ focusNode = this.findUp(focusNode, WYMeditor.BLOCKS);
4751
+ anchorNode = this.findUp(anchorNode, WYMeditor.BLOCKS);
4752
+
4753
+ if(focusNode && focusNode == anchorNode
4754
+ && focusNode.tagName.toLowerCase() == WYMeditor.LI) {
4755
+
4756
+ var ancestor = focusNode.parentNode.parentNode;
4757
+
4758
+ if(focusNode.parentNode.childNodes.length>1
4759
+ || ancestor.tagName.toLowerCase() == WYMeditor.OL
4760
+ || ancestor.tagName.toLowerCase() == WYMeditor.UL)
4761
+ this._doc.execCommand(cmd,'',null);
4762
+ }
4763
+
4764
+ break;
4765
+
4766
+ case WYMeditor.INSERT_ORDEREDLIST: case WYMeditor.INSERT_UNORDEREDLIST:
4767
+
4768
+ this._doc.execCommand(cmd,'',null);
4769
+
4770
+ //Safari creates lists in e.g. paragraphs.
4771
+ //Find the container, and remove it.
4772
+ var focusNode = this.selected();
4773
+ var container = this.findUp(focusNode, WYMeditor.MAIN_CONTAINERS);
4774
+ if(container) $(container).replaceWith($(container).html());
4775
+
4776
+ break;
4777
+
4778
+ default:
4779
+
4780
+ if(param) this._doc.execCommand(cmd,'',param);
4781
+ else this._doc.execCommand(cmd,'',null);
4782
+ }
4783
+
4784
+ //set to P if parent = BODY
4785
+ var container = this.selected();
4786
+ if(container && container.tagName.toLowerCase() == WYMeditor.BODY)
4787
+ this._exec(WYMeditor.FORMAT_BLOCK, WYMeditor.P);
4788
+
4789
+ //add event handlers on doc elements
4790
+ this.listen();
4791
+ };
4792
+
4793
+ /* @name selected
4794
+ * @description Returns the selected container
4795
+ */
4796
+ WYMeditor.WymClassSafari.prototype.selected = function(upgrade_text_nodes) {
4797
+
4798
+ if (upgrade_text_nodes == null || upgrade_text_nodes.toString() != "true") { upgrade_text_nodes = false; }
4799
+ var sel = this._iframe.contentWindow.getSelection();
4800
+ var node = sel.focusNode;
4801
+ if(node) {
4802
+ if(node.nodeName == "#text"){
4803
+ if (upgrade_text_nodes && sel.toString().length > 0) {
4804
+ actual_node = null;
4805
+ parent_node = sel.focusNode.parentNode;
4806
+ if (parent_node != null) {
4807
+ for (i=0;i<parent_node.childNodes.length;i++){
4808
+ child_node = parent_node.childNodes[i];
4809
+ if (child_node.textContent == sel.toString()){
4810
+ actual_node = child_node.parentNode;
4811
+ }
4812
+ }
4813
+ }
4814
+
4815
+ if (actual_node == null) {
4816
+ this._selected_item = this.switchTo(sel, 'span');
4817
+ return this._selected_item;
4818
+ } else {
4819
+ return actual_node;
4820
+ }
4821
+ }
4822
+ else {
4823
+ return node.parentNode;
4824
+ }
4825
+ }
4826
+ else return(node);
4827
+ }
4828
+ else return(null);
4829
+ };
4830
+
4831
+ /* @name toggleClass
4832
+ * @description Toggles class on selected element, or one of its parents
4833
+ */
4834
+ WYMeditor.WymClassSafari.prototype.toggleClass = function(sClass, jqexpr) {
4835
+
4836
+ var container = null;
4837
+ if (this._selected_image) {
4838
+ container = $(this._selected_image);
4839
+ }
4840
+ else {
4841
+ container = $(this.selected(true) || this._selected_item);
4842
+ }
4843
+
4844
+ if (jqexpr != null) { container = $(container.parentsOrSelf(jqexpr)); }
4845
+ container.toggleClass(sClass);
4846
+ if(!container.attr(WYMeditor.CLASS)) container.removeAttr(this._class);
4847
+
4848
+ };
4849
+
4850
+ WYMeditor.WymClassSafari.prototype.addCssRule = function(styles, oCss) {
4851
+
4852
+ styles.insertRule(oCss.name + " {" + oCss.css + "}",
4853
+ styles.cssRules.length);
4854
+ };
4855
+
4856
+
4857
+ //keydown handler, mainly used for keyboard shortcuts
4858
+ WYMeditor.WymClassSafari.prototype.keydown = function(evt) {
4859
+
4860
+ //'this' is the doc
4861
+ var wym = WYMeditor.INSTANCES[this.title];
4862
+
4863
+ if(evt.ctrlKey){
4864
+ if(evt.keyCode == 66){
4865
+ //CTRL+b => STRONG
4866
+ wym._exec(WYMeditor.BOLD);
4867
+ return false;
4868
+ }
4869
+ if(evt.keyCode == 73){
4870
+ //CTRL+i => EMPHASIS
4871
+ wym._exec(WYMeditor.ITALIC);
4872
+ return false;
4873
+ }
4874
+ }
4875
+ };
4876
+
4877
+ //keyup handler, mainly used for cleanups
4878
+ WYMeditor.WymClassSafari.prototype.keyup = function(evt) {
4879
+
4880
+ //'this' is the doc
4881
+ var wym = WYMeditor.INSTANCES[this.title];
4882
+
4883
+ wym._selected_image = null;
4884
+ var container = null;
4885
+
4886
+ if(evt.keyCode == 13 && !evt.shiftKey) {
4887
+
4888
+ //RETURN key
4889
+ //cleanup <br><br> between paragraphs
4890
+ $(wym._doc.body).children(WYMeditor.BR).remove();
4891
+
4892
+ //fix PRE bug #73
4893
+ container = wym.selected();
4894
+ if(container && container.tagName.toLowerCase() == WYMeditor.PRE)
4895
+ wym._exec(WYMeditor.FORMAT_BLOCK, WYMeditor.P); //create P after PRE
4896
+ }
4897
+
4898
+ //fix #112
4899
+ if(evt.keyCode == 13 && evt.shiftKey) {
4900
+ wym._exec('InsertLineBreak');
4901
+ }
4902
+
4903
+ if(evt.keyCode != 8
4904
+ && evt.keyCode != 17
4905
+ && evt.keyCode != 46
4906
+ && evt.keyCode != 224
4907
+ && !evt.metaKey
4908
+ && !evt.ctrlKey) {
4909
+
4910
+ //NOT BACKSPACE, NOT DELETE, NOT CTRL, NOT COMMAND
4911
+ //text nodes replaced by P
4912
+
4913
+ container = wym.selected();
4914
+ var name = container.tagName.toLowerCase();
4915
+
4916
+ //fix forbidden main containers
4917
+ if(
4918
+ name == "strong" ||
4919
+ name == "b" ||
4920
+ name == "em" ||
4921
+ name == "i" ||
4922
+ name == "sub" ||
4923
+ name == "sup" ||
4924
+ name == "a" ||
4925
+ name == "span" //fix #110
4926
+
4927
+ ) name = container.parentNode.tagName.toLowerCase();
4928
+
4929
+ if(name == WYMeditor.BODY || name == WYMeditor.DIV) wym._exec(WYMeditor.FORMAT_BLOCK, WYMeditor.P); //fix #110 for DIV
4930
+ }
4931
+ };
4932
+
4933
+
4934
+ WYMeditor.WymClassSafari.prototype.setFocusToNode = function(node) {
4935
+ var range = this._iframe.contentDocument.createRange();
4936
+ range.selectNode(node);
4937
+ var selected = this._iframe.contentWindow.getSelection();
4938
+ selected.addRange(range);
4939
+ selected.collapse(node, node.childNodes.length);
4940
+ this._iframe.contentWindow.focus();
4941
+ };
4942
+
4943
+ WYMeditor.WymClassSafari.prototype.openBlockTag = function(tag, attributes)
4944
+ {
4945
+ var attributes = this.validator.getValidTagAttributes(tag, attributes);
4946
+
4947
+ // Handle Safari styled spans
4948
+ if(tag == 'span' && attributes.style) {
4949
+ var new_tag = this.getTagForStyle(attributes.style);
4950
+ if(new_tag){
4951
+ this._tag_stack.pop();
4952
+ var tag = new_tag;
4953
+ this._tag_stack.push(new_tag);
4954
+ attributes.style = '';
4955
+
4956
+ //should fix #125 - also removed the xhtml() override
4957
+ if(typeof attributes['class'] == 'string')
4958
+ attributes['class'] = attributes['class'].replace(/apple-style-span/gi, '');
4959
+
4960
+ } else {
4961
+ return;
4962
+ }
4963
+ }
4964
+
4965
+ this.output += this.helper.tag(tag, attributes, true);
4966
+ };
4967
+
4968
+ WYMeditor.WymClassSafari.prototype.getTagForStyle = function(style) {
4969
+
4970
+ if(/bold/.test(style)) return 'strong';
4971
+ if(/italic/.test(style)) return 'em';
4972
+ if(/sub/.test(style)) return 'sub';
4973
+ if(/super/.test(style)) return 'sup';
4974
+ return false;
4975
+ };