milksteak 0.0.1 → 0.0.2

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