narf 0.5.1

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 (657) hide show
  1. data/ChangeLog +163 -0
  2. data/InstalledFiles +2227 -0
  3. data/README +124 -0
  4. data/TODO +88 -0
  5. data/bin/narftest +17 -0
  6. data/bug.rb +9 -0
  7. data/build.rb +314 -0
  8. data/build.rb~ +314 -0
  9. data/config.save +12 -0
  10. data/doc/apache_cgi.txt +17 -0
  11. data/doc/fastcgi.txt +19 -0
  12. data/doc/mod_ruby.txt +7 -0
  13. data/doc/rdoc/classes/Web.html +366 -0
  14. data/doc/rdoc/classes/Web.src/M000002.html +15 -0
  15. data/doc/rdoc/classes/Web.src/M000003.html +15 -0
  16. data/doc/rdoc/classes/Web.src/M000004.html +15 -0
  17. data/doc/rdoc/classes/Web.src/M000005.html +15 -0
  18. data/doc/rdoc/classes/Web.src/M000006.html +20 -0
  19. data/doc/rdoc/classes/Web.src/M000007.html +18 -0
  20. data/doc/rdoc/classes/Web.src/M000008.html +18 -0
  21. data/doc/rdoc/classes/Web.src/M000009.html +18 -0
  22. data/doc/rdoc/classes/Web.src/M000010.html +15 -0
  23. data/doc/rdoc/classes/Web.src/M000011.html +15 -0
  24. data/doc/rdoc/classes/Web.src/M000012.html +15 -0
  25. data/doc/rdoc/classes/Web/CGD.html +173 -0
  26. data/doc/rdoc/classes/Web/CGD.src/M000037.html +24 -0
  27. data/doc/rdoc/classes/Web/CGD.src/M000038.html +23 -0
  28. data/doc/rdoc/classes/Web/CGD.src/M000039.html +15 -0
  29. data/doc/rdoc/classes/Web/CGD.src/M000040.html +15 -0
  30. data/doc/rdoc/classes/Web/CGD.src/M000041.html +23 -0
  31. data/doc/rdoc/classes/Web/CGI.html +946 -0
  32. data/doc/rdoc/classes/Web/CGI.src/M000051.html +15 -0
  33. data/doc/rdoc/classes/Web/CGI.src/M000052.html +24 -0
  34. data/doc/rdoc/classes/Web/CGI.src/M000053.html +15 -0
  35. data/doc/rdoc/classes/Web/CGI.src/M000054.html +15 -0
  36. data/doc/rdoc/classes/Web/CGI.src/M000055.html +15 -0
  37. data/doc/rdoc/classes/Web/CGI.src/M000056.html +15 -0
  38. data/doc/rdoc/classes/Web/CGI.src/M000057.html +17 -0
  39. data/doc/rdoc/classes/Web/CGI.src/M000058.html +34 -0
  40. data/doc/rdoc/classes/Web/CGI.src/M000059.html +22 -0
  41. data/doc/rdoc/classes/Web/CGI.src/M000060.html +15 -0
  42. data/doc/rdoc/classes/Web/CGI.src/M000061.html +15 -0
  43. data/doc/rdoc/classes/Web/CGI.src/M000062.html +19 -0
  44. data/doc/rdoc/classes/Web/CGI.src/M000063.html +18 -0
  45. data/doc/rdoc/classes/Web/CGI.src/M000064.html +19 -0
  46. data/doc/rdoc/classes/Web/CGI.src/M000065.html +15 -0
  47. data/doc/rdoc/classes/Web/CGI.src/M000066.html +15 -0
  48. data/doc/rdoc/classes/Web/CGI.src/M000067.html +15 -0
  49. data/doc/rdoc/classes/Web/CGI.src/M000068.html +13 -0
  50. data/doc/rdoc/classes/Web/CGI.src/M000069.html +13 -0
  51. data/doc/rdoc/classes/Web/CGI.src/M000070.html +13 -0
  52. data/doc/rdoc/classes/Web/CGI.src/M000071.html +13 -0
  53. data/doc/rdoc/classes/Web/CGI.src/M000072.html +19 -0
  54. data/doc/rdoc/classes/Web/CGI.src/M000073.html +15 -0
  55. data/doc/rdoc/classes/Web/CGI.src/M000074.html +19 -0
  56. data/doc/rdoc/classes/Web/CGI.src/M000075.html +15 -0
  57. data/doc/rdoc/classes/Web/CGI.src/M000076.html +15 -0
  58. data/doc/rdoc/classes/Web/CGI.src/M000077.html +15 -0
  59. data/doc/rdoc/classes/Web/CGI.src/M000078.html +20 -0
  60. data/doc/rdoc/classes/Web/CGI.src/M000079.html +36 -0
  61. data/doc/rdoc/classes/Web/CGI.src/M000080.html +19 -0
  62. data/doc/rdoc/classes/Web/CGI.src/M000081.html +18 -0
  63. data/doc/rdoc/classes/Web/CGI.src/M000082.html +15 -0
  64. data/doc/rdoc/classes/Web/CGI.src/M000083.html +17 -0
  65. data/doc/rdoc/classes/Web/CGI.src/M000084.html +15 -0
  66. data/doc/rdoc/classes/Web/CGI.src/M000085.html +16 -0
  67. data/doc/rdoc/classes/Web/CGI.src/M000086.html +15 -0
  68. data/doc/rdoc/classes/Web/CGI.src/M000087.html +15 -0
  69. data/doc/rdoc/classes/Web/CGI.src/M000088.html +15 -0
  70. data/doc/rdoc/classes/Web/CGI.src/M000089.html +16 -0
  71. data/doc/rdoc/classes/Web/CGI.src/M000090.html +15 -0
  72. data/doc/rdoc/classes/Web/CGI.src/M000091.html +15 -0
  73. data/doc/rdoc/classes/Web/CGI.src/M000092.html +15 -0
  74. data/doc/rdoc/classes/Web/CGI.src/M000093.html +15 -0
  75. data/doc/rdoc/classes/Web/CGI.src/M000094.html +15 -0
  76. data/doc/rdoc/classes/Web/CGI.src/M000095.html +15 -0
  77. data/doc/rdoc/classes/Web/CGI.src/M000096.html +19 -0
  78. data/doc/rdoc/classes/Web/CGI.src/M000097.html +15 -0
  79. data/doc/rdoc/classes/Web/CGI.src/M000098.html +15 -0
  80. data/doc/rdoc/classes/Web/CGI.src/M000099.html +43 -0
  81. data/doc/rdoc/classes/Web/CGI.src/M000100.html +18 -0
  82. data/doc/rdoc/classes/Web/CGI.src/M000101.html +20 -0
  83. data/doc/rdoc/classes/Web/CGI.src/M000102.html +15 -0
  84. data/doc/rdoc/classes/Web/CGI.src/M000103.html +15 -0
  85. data/doc/rdoc/classes/Web/CGI.src/M000104.html +15 -0
  86. data/doc/rdoc/classes/Web/CGI.src/M000105.html +24 -0
  87. data/doc/rdoc/classes/Web/CGI.src/M000106.html +24 -0
  88. data/doc/rdoc/classes/Web/CGI.src/M000107.html +22 -0
  89. data/doc/rdoc/classes/Web/CaseInsensitiveHash.html +104 -0
  90. data/doc/rdoc/classes/Web/CaseInsensitiveHash.src/M000118.html +15 -0
  91. data/doc/rdoc/classes/Web/CaseInsensitiveHash.src/M000119.html +15 -0
  92. data/doc/rdoc/classes/Web/CaseInsensitiveHash.src/M000120.html +15 -0
  93. data/doc/rdoc/classes/Web/Mime.html +122 -0
  94. data/doc/rdoc/classes/Web/Mime.src/M000118.html +15 -0
  95. data/doc/rdoc/classes/Web/Mime.src/M000119.html +15 -0
  96. data/doc/rdoc/classes/Web/Mime.src/M000120.html +23 -0
  97. data/doc/rdoc/classes/Web/Mime.src/M000121.html +15 -0
  98. data/doc/rdoc/classes/Web/Mime.src/M000122.html +15 -0
  99. data/doc/rdoc/classes/Web/Mime.src/M000123.html +23 -0
  100. data/doc/rdoc/classes/Web/Mime.src/M000124.html +15 -0
  101. data/doc/rdoc/classes/Web/Narflates.html +132 -0
  102. data/doc/rdoc/classes/Web/Parser.html +219 -0
  103. data/doc/rdoc/classes/Web/Parser.src/M000013.html +21 -0
  104. data/doc/rdoc/classes/Web/Parser.src/M000014.html +19 -0
  105. data/doc/rdoc/classes/Web/Parser.src/M000015.html +21 -0
  106. data/doc/rdoc/classes/Web/Parser.src/M000016.html +15 -0
  107. data/doc/rdoc/classes/Web/Parser.src/M000017.html +30 -0
  108. data/doc/rdoc/classes/Web/Parser.src/M000018.html +15 -0
  109. data/doc/rdoc/classes/Web/Parser.src/M000019.html +19 -0
  110. data/doc/rdoc/classes/Web/Parser.src/M000020.html +27 -0
  111. data/doc/rdoc/classes/Web/Parser.src/M000021.html +15 -0
  112. data/doc/rdoc/classes/Web/Parser.src/M000022.html +16 -0
  113. data/doc/rdoc/classes/Web/Parser.src/M000023.html +18 -0
  114. data/doc/rdoc/classes/Web/Session.html +178 -0
  115. data/doc/rdoc/classes/Web/Session.src/M000042.html +20 -0
  116. data/doc/rdoc/classes/Web/Session.src/M000043.html +19 -0
  117. data/doc/rdoc/classes/Web/Session.src/M000044.html +21 -0
  118. data/doc/rdoc/classes/Web/Session.src/M000045.html +21 -0
  119. data/doc/rdoc/classes/Web/Session.src/M000046.html +15 -0
  120. data/doc/rdoc/classes/Web/Session.src/M000047.html +17 -0
  121. data/doc/rdoc/classes/Web/Session.src/M000048.html +15 -0
  122. data/doc/rdoc/classes/Web/Session.src/M000049.html +15 -0
  123. data/doc/rdoc/classes/Web/Session.src/M000050.html +16 -0
  124. data/doc/rdoc/classes/Web/Testing.html +474 -0
  125. data/doc/rdoc/classes/Web/Testing.src/M000024.html +15 -0
  126. data/doc/rdoc/classes/Web/Testing.src/M000025.html +25 -0
  127. data/doc/rdoc/classes/Web/Testing.src/M000026.html +15 -0
  128. data/doc/rdoc/classes/Web/Testing.src/M000027.html +28 -0
  129. data/doc/rdoc/classes/Web/Testing.src/M000028.html +58 -0
  130. data/doc/rdoc/classes/Web/Testing.src/M000029.html +15 -0
  131. data/doc/rdoc/classes/Web/Testing.src/M000030.html +15 -0
  132. data/doc/rdoc/classes/Web/Testing.src/M000031.html +15 -0
  133. data/doc/rdoc/classes/Web/Testing.src/M000032.html +15 -0
  134. data/doc/rdoc/classes/Web/Testing.src/M000033.html +15 -0
  135. data/doc/rdoc/classes/Web/Testing.src/M000034.html +15 -0
  136. data/doc/rdoc/classes/Web/Testing.src/M000035.html +15 -0
  137. data/doc/rdoc/classes/Web/Testing.src/M000036.html +18 -0
  138. data/doc/rdoc/classes/Web/Upload.html +160 -0
  139. data/doc/rdoc/classes/Web/Upload.src/M000108.html +25 -0
  140. data/doc/rdoc/classes/Web/Upload.src/M000109.html +18 -0
  141. data/doc/rdoc/classes/Web/Upload.src/M000110.html +16 -0
  142. data/doc/rdoc/classes/Web/Upload.src/M000111.html +16 -0
  143. data/doc/rdoc/classes/Web/Wiki.html +249 -0
  144. data/doc/rdoc/classes/Web/Wiki.src/M000112.html +25 -0
  145. data/doc/rdoc/classes/Web/Wiki.src/M000113.html +15 -0
  146. data/doc/rdoc/classes/Web/Wiki.src/M000114.html +26 -0
  147. data/doc/rdoc/classes/Web/Wiki.src/M000115.html +21 -0
  148. data/doc/rdoc/classes/Web/Wiki.src/M000116.html +18 -0
  149. data/doc/rdoc/classes/Web/Wiki.src/M000117.html +19 -0
  150. data/doc/rdoc/created.rid +1 -0
  151. data/doc/rdoc/files/README.html +226 -0
  152. data/doc/rdoc/files/doc/apache_cgi_txt.html +82 -0
  153. data/doc/rdoc/files/doc/fastcgi_txt.html +82 -0
  154. data/doc/rdoc/files/doc/mod_ruby_txt.html +62 -0
  155. data/doc/rdoc/files/doc/webrick_txt.html +79 -0
  156. data/doc/rdoc/files/examples/examples_rdoc.html +73 -0
  157. data/doc/rdoc/files/lib/web/cgi_rb.html +75 -0
  158. data/doc/rdoc/files/lib/web/mime_rb.html +67 -0
  159. data/doc/rdoc/files/lib/web/parser_rb.html +73 -0
  160. data/doc/rdoc/files/lib/web/session_rb.html +73 -0
  161. data/doc/rdoc/files/lib/web/template_rb.html +73 -0
  162. data/doc/rdoc/files/lib/web/testing_rb.html +67 -0
  163. data/doc/rdoc/files/lib/web/upload_rb.html +73 -0
  164. data/doc/rdoc/files/lib/web/wiki_rb.html +79 -0
  165. data/doc/rdoc/files/lib/web_rb.html +116 -0
  166. data/doc/rdoc/files/lib/web_rb.src/M000001.html +15 -0
  167. data/doc/rdoc/fr_class_index.html +47 -0
  168. data/doc/rdoc/fr_file_index.html +52 -0
  169. data/doc/rdoc/fr_method_index.html +158 -0
  170. data/doc/rdoc/index.html +22 -0
  171. data/doc/rdoc/rdoc-style.css +99 -0
  172. data/doc/webrick.txt +23 -0
  173. data/examples/admin.rb +8 -0
  174. data/examples/admin.rb~ +5 -0
  175. data/examples/cookbook.rdoc +247 -0
  176. data/examples/cookbook.rdoc~ +238 -0
  177. data/examples/examples.rdoc +19 -0
  178. data/examples/examples.rdoc~ +17 -0
  179. data/examples/hello.world.rb +5 -0
  180. data/examples/hello.world.rb~ +3 -0
  181. data/examples/session.rb +34 -0
  182. data/examples/session.rb~ +31 -0
  183. data/examples/test/test.hello.world.rb +9 -0
  184. data/examples/test/test.hello.world.rb~ +9 -0
  185. data/examples/test/test.session.rb +37 -0
  186. data/examples/test/test.session.rb~ +37 -0
  187. data/examples/webunit/COPYING +340 -0
  188. data/examples/webunit/Makefile +14 -0
  189. data/examples/webunit/TIPS-ja.html +126 -0
  190. data/examples/webunit/TIPS-ja.rd +154 -0
  191. data/examples/webunit/TODO-ja.html +35 -0
  192. data/examples/webunit/TODO-ja.rd +28 -0
  193. data/examples/webunit/changes.rd +185 -0
  194. data/examples/webunit/conv/digit-0.cgi +40 -0
  195. data/examples/webunit/conv/digit-0.rb +21 -0
  196. data/examples/webunit/conv/digit-1.cgi +44 -0
  197. data/examples/webunit/conv/digit-1.rb +17 -0
  198. data/examples/webunit/conv/digit.cgi +59 -0
  199. data/examples/webunit/conv/digit.rb +23 -0
  200. data/examples/webunit/conv/test_digit-0.rb +16 -0
  201. data/examples/webunit/conv/test_digit-1.rb +19 -0
  202. data/examples/webunit/conv/test_digit.rb +26 -0
  203. data/examples/webunit/conv/test_digit_view-0.rb +76 -0
  204. data/examples/webunit/conv/test_digit_view-1.rb +102 -0
  205. data/examples/webunit/conv/test_digit_view.rb +134 -0
  206. data/examples/webunit/example.rd +37 -0
  207. data/examples/webunit/index-en.html +263 -0
  208. data/examples/webunit/index-en.rd +60 -0
  209. data/examples/webunit/index-ja.html +263 -0
  210. data/examples/webunit/index-ja.rd +60 -0
  211. data/examples/wiki.rb +7 -0
  212. data/examples/wiki.rb~ +5 -0
  213. data/install.rb +1022 -0
  214. data/lib/web.rb +290 -0
  215. data/lib/web.rb~ +290 -0
  216. data/lib/web/#assertinclude.rb# +110 -0
  217. data/lib/web/action.rb +82 -0
  218. data/lib/web/assertinclude.rb +110 -0
  219. data/lib/web/assertinclude.rb~ +110 -0
  220. data/lib/web/buffer.rb +20 -0
  221. data/lib/web/cgi.rb +641 -0
  222. data/lib/web/cgi.rb~ +640 -0
  223. data/lib/web/formreader.rb +317 -0
  224. data/lib/web/forms.rb +104 -0
  225. data/lib/web/htmlparser/html-parser.rb +429 -0
  226. data/lib/web/htmlparser/html-parser.rb~ +429 -0
  227. data/lib/web/htmlparser/sgml-parser.rb +332 -0
  228. data/lib/web/htmlparser/sgml-parser.rb~ +332 -0
  229. data/lib/web/htmltools/element.rb +296 -0
  230. data/lib/web/htmltools/element.rb~ +296 -0
  231. data/lib/web/htmltools/stparser.rb +276 -0
  232. data/lib/web/htmltools/stparser.rb~ +276 -0
  233. data/lib/web/htmltools/tags.rb +286 -0
  234. data/lib/web/htmltools/tags.rb~ +286 -0
  235. data/lib/web/htmltools/tree.rb +139 -0
  236. data/lib/web/htmltools/tree.rb~ +139 -0
  237. data/lib/web/htmltools/xmltree.rb +160 -0
  238. data/lib/web/htmltools/xmltree.rb~ +160 -0
  239. data/lib/web/htmltools/xpath.rb +71 -0
  240. data/lib/web/htmltools/xpath.rb~ +71 -0
  241. data/lib/web/mime.rb +82 -0
  242. data/lib/web/parser.rb +266 -0
  243. data/lib/web/parser.rb~ +266 -0
  244. data/lib/web/request.rb~ +238 -0
  245. data/lib/web/resources/mime.types +483 -0
  246. data/lib/web/runner.rb +26 -0
  247. data/lib/web/runner.rb~ +26 -0
  248. data/lib/web/sapi/fastcgi.rb +26 -0
  249. data/lib/web/sapi/fastcgi.rb~ +25 -0
  250. data/lib/web/sapi/mod_ruby.rb +46 -0
  251. data/lib/web/sapi/mod_ruby.rb~ +46 -0
  252. data/lib/web/sapi/webrick.rb +91 -0
  253. data/lib/web/sapi/webrick.rb~ +89 -0
  254. data/lib/web/session.rb +75 -0
  255. data/lib/web/session.rb~ +75 -0
  256. data/lib/web/simpledispatcher.rb +155 -0
  257. data/lib/web/strscanparser.rb +24 -0
  258. data/lib/web/tagparser.rb +96 -0
  259. data/lib/web/tagparser.rb~ +96 -0
  260. data/lib/web/template.rb +613 -0
  261. data/lib/web/template.rb~ +613 -0
  262. data/lib/web/testing.rb +546 -0
  263. data/lib/web/testing.rb~ +546 -0
  264. data/lib/web/traceoutput.rb +32 -0
  265. data/lib/web/unit.rb +27 -0
  266. data/lib/web/unit/assert.rb +154 -0
  267. data/lib/web/unit/converter.rb +148 -0
  268. data/lib/web/unit/cookie.rb +120 -0
  269. data/lib/web/unit/domwalker.rb +187 -0
  270. data/lib/web/unit/exception.rb +15 -0
  271. data/lib/web/unit/form.rb +118 -0
  272. data/lib/web/unit/formatter.rb +314 -0
  273. data/lib/web/unit/frame.rb +39 -0
  274. data/lib/web/unit/html-parser.rb +432 -0
  275. data/lib/web/unit/htmlelem.rb +124 -0
  276. data/lib/web/unit/htmlrepair.rb +116 -0
  277. data/lib/web/unit/htmlsplit.rb +840 -0
  278. data/lib/web/unit/image.rb +27 -0
  279. data/lib/web/unit/jscript.rb +32 -0
  280. data/lib/web/unit/link.rb +35 -0
  281. data/lib/web/unit/params.rb +323 -0
  282. data/lib/web/unit/parser.rb +226 -0
  283. data/lib/web/unit/resources/assert.html +101 -0
  284. data/lib/web/unit/resources/auth/index.html +5 -0
  285. data/lib/web/unit/resources/badtags.html +7 -0
  286. data/lib/web/unit/resources/cookie.cgi +33 -0
  287. data/lib/web/unit/resources/document.xml +13 -0
  288. data/lib/web/unit/resources/form.html +150 -0
  289. data/lib/web/unit/resources/frame-0.html +10 -0
  290. data/lib/web/unit/resources/frame-1.html +10 -0
  291. data/lib/web/unit/resources/frame.html +10 -0
  292. data/lib/web/unit/resources/image.html +17 -0
  293. data/lib/web/unit/resources/images/x.gif +0 -0
  294. data/lib/web/unit/resources/images/y.gif +0 -0
  295. data/lib/web/unit/resources/jscript-0.html +10 -0
  296. data/lib/web/unit/resources/jscript-1.html +10 -0
  297. data/lib/web/unit/resources/jscript.html +19 -0
  298. data/lib/web/unit/resources/link.html +19 -0
  299. data/lib/web/unit/resources/multipart.cgi +28 -0
  300. data/lib/web/unit/resources/multipart.html +74 -0
  301. data/lib/web/unit/resources/params.html +65 -0
  302. data/lib/web/unit/resources/redirect.cgi +13 -0
  303. data/lib/web/unit/resources/response.html +67 -0
  304. data/lib/web/unit/resources/simple.cgi +14 -0
  305. data/lib/web/unit/resources/stock.cgi +35 -0
  306. data/lib/web/unit/resources/table.html +83 -0
  307. data/lib/web/unit/response.rb +469 -0
  308. data/lib/web/unit/response.rb~ +461 -0
  309. data/lib/web/unit/runtest.rb +44 -0
  310. data/lib/web/unit/sgml-parser.rb +336 -0
  311. data/lib/web/unit/table.rb +150 -0
  312. data/lib/web/unit/testcase.rb +49 -0
  313. data/lib/web/unit/ui/cui/testrunner.rb +52 -0
  314. data/lib/web/unit/ui/cui/testrunner.rb~ +50 -0
  315. data/lib/web/unit/utils.rb +70 -0
  316. data/lib/web/unit/webunit.rb +28 -0
  317. data/lib/web/upload.rb +55 -0
  318. data/lib/web/upload.rb~ +262 -0
  319. data/lib/web/wiki.rb +506 -0
  320. data/lib/web/wiki.rb~ +506 -0
  321. data/lib/web/wiki/linker.rb +72 -0
  322. data/lib/web/wiki/linker.rb~ +72 -0
  323. data/lib/web/wiki/mime.rb~ +68 -0
  324. data/lib/web/wiki/page.rb +192 -0
  325. data/lib/web/wiki/page.rb~ +192 -0
  326. data/lib/web/wiki/resources/#edit.html# +65 -0
  327. data/lib/web/wiki/resources/admin.html +13 -0
  328. data/lib/web/wiki/resources/admin.html~ +13 -0
  329. data/lib/web/wiki/resources/asset_history.html +3 -0
  330. data/lib/web/wiki/resources/basic.html +1 -0
  331. data/lib/web/wiki/resources/default-content_editor.html +1 -0
  332. data/lib/web/wiki/resources/default-content_editor.html~ +1 -0
  333. data/lib/web/wiki/resources/edit.html +1 -1
  334. data/lib/web/wiki/resources/edit.html~ +1 -1
  335. data/lib/web/wiki/resources/ekit-content_editor.html +1 -0
  336. data/lib/web/wiki/resources/home.html +10 -0
  337. data/lib/web/wiki/resources/home.html~ +10 -0
  338. data/lib/web/wiki/resources/htmlarea/ChangeLog +1185 -0
  339. data/lib/web/wiki/resources/htmlarea/dialog.js +72 -0
  340. data/lib/web/wiki/resources/htmlarea/examples/2-areas.cgi +16 -0
  341. data/lib/web/wiki/resources/htmlarea/examples/2-areas.html +158 -0
  342. data/lib/web/wiki/resources/htmlarea/examples/context-menu.html +95 -0
  343. data/lib/web/wiki/resources/htmlarea/examples/core.html +184 -0
  344. data/lib/web/wiki/resources/htmlarea/examples/css.html +88 -0
  345. data/lib/web/wiki/resources/htmlarea/examples/custom.css +29 -0
  346. data/lib/web/wiki/resources/htmlarea/examples/full-page.html +75 -0
  347. data/lib/web/wiki/resources/htmlarea/examples/fully-loaded.html +248 -0
  348. data/lib/web/wiki/resources/htmlarea/examples/index.html +40 -0
  349. data/lib/web/wiki/resources/htmlarea/examples/spell-checker.html +132 -0
  350. data/lib/web/wiki/resources/htmlarea/examples/table-operations.html +116 -0
  351. data/lib/web/wiki/resources/htmlarea/examples/test.cgi +21 -0
  352. data/lib/web/wiki/resources/htmlarea/htmlarea.css +180 -0
  353. data/lib/web/wiki/resources/htmlarea/htmlarea.js +2175 -0
  354. data/lib/web/wiki/resources/htmlarea/images/ed_about.gif +0 -0
  355. data/lib/web/wiki/resources/htmlarea/images/ed_align_center.gif +0 -0
  356. data/lib/web/wiki/resources/htmlarea/images/ed_align_justify.gif +0 -0
  357. data/lib/web/wiki/resources/htmlarea/images/ed_align_left.gif +0 -0
  358. data/lib/web/wiki/resources/htmlarea/images/ed_align_right.gif +0 -0
  359. data/lib/web/wiki/resources/htmlarea/images/ed_blank.gif +0 -0
  360. data/lib/web/wiki/resources/htmlarea/images/ed_charmap.gif +0 -0
  361. data/lib/web/wiki/resources/htmlarea/images/ed_color_bg.gif +0 -0
  362. data/lib/web/wiki/resources/htmlarea/images/ed_color_fg.gif +0 -0
  363. data/lib/web/wiki/resources/htmlarea/images/ed_copy.gif +0 -0
  364. data/lib/web/wiki/resources/htmlarea/images/ed_custom.gif +0 -0
  365. data/lib/web/wiki/resources/htmlarea/images/ed_cut.gif +0 -0
  366. data/lib/web/wiki/resources/htmlarea/images/ed_delete.gif +0 -0
  367. data/lib/web/wiki/resources/htmlarea/images/ed_format_bold.gif +0 -0
  368. data/lib/web/wiki/resources/htmlarea/images/ed_format_italic.gif +0 -0
  369. data/lib/web/wiki/resources/htmlarea/images/ed_format_strike.gif +0 -0
  370. data/lib/web/wiki/resources/htmlarea/images/ed_format_sub.gif +0 -0
  371. data/lib/web/wiki/resources/htmlarea/images/ed_format_sup.gif +0 -0
  372. data/lib/web/wiki/resources/htmlarea/images/ed_format_underline.gif +0 -0
  373. data/lib/web/wiki/resources/htmlarea/images/ed_help.gif +0 -0
  374. data/lib/web/wiki/resources/htmlarea/images/ed_hr.gif +0 -0
  375. data/lib/web/wiki/resources/htmlarea/images/ed_html.gif +0 -0
  376. data/lib/web/wiki/resources/htmlarea/images/ed_image.gif +0 -0
  377. data/lib/web/wiki/resources/htmlarea/images/ed_indent_less.gif +0 -0
  378. data/lib/web/wiki/resources/htmlarea/images/ed_indent_more.gif +0 -0
  379. data/lib/web/wiki/resources/htmlarea/images/ed_left_to_right.gif +0 -0
  380. data/lib/web/wiki/resources/htmlarea/images/ed_link.gif +0 -0
  381. data/lib/web/wiki/resources/htmlarea/images/ed_list_bullet.gif +0 -0
  382. data/lib/web/wiki/resources/htmlarea/images/ed_list_num.gif +0 -0
  383. data/lib/web/wiki/resources/htmlarea/images/ed_paste.gif +0 -0
  384. data/lib/web/wiki/resources/htmlarea/images/ed_redo.gif +0 -0
  385. data/lib/web/wiki/resources/htmlarea/images/ed_right_to_left.gif +0 -0
  386. data/lib/web/wiki/resources/htmlarea/images/ed_save.gif +0 -0
  387. data/lib/web/wiki/resources/htmlarea/images/ed_show_border.gif +0 -0
  388. data/lib/web/wiki/resources/htmlarea/images/ed_splitcel.gif +0 -0
  389. data/lib/web/wiki/resources/htmlarea/images/ed_undo.gif +0 -0
  390. data/lib/web/wiki/resources/htmlarea/images/fullscreen_maximize.gif +0 -0
  391. data/lib/web/wiki/resources/htmlarea/images/fullscreen_minimize.gif +0 -0
  392. data/lib/web/wiki/resources/htmlarea/images/insert_table.gif +0 -0
  393. data/lib/web/wiki/resources/htmlarea/index.html +199 -0
  394. data/lib/web/wiki/resources/htmlarea/lang/b5.js +36 -0
  395. data/lib/web/wiki/resources/htmlarea/lang/cz.js +63 -0
  396. data/lib/web/wiki/resources/htmlarea/lang/da.js +38 -0
  397. data/lib/web/wiki/resources/htmlarea/lang/de.js +54 -0
  398. data/lib/web/wiki/resources/htmlarea/lang/ee.js +63 -0
  399. data/lib/web/wiki/resources/htmlarea/lang/el.js +75 -0
  400. data/lib/web/wiki/resources/htmlarea/lang/en.js +88 -0
  401. data/lib/web/wiki/resources/htmlarea/lang/es.js +51 -0
  402. data/lib/web/wiki/resources/htmlarea/lang/fi.js +46 -0
  403. data/lib/web/wiki/resources/htmlarea/lang/fr.js +61 -0
  404. data/lib/web/wiki/resources/htmlarea/lang/gb.js +36 -0
  405. data/lib/web/wiki/resources/htmlarea/lang/he.js +63 -0
  406. data/lib/web/wiki/resources/htmlarea/lang/hu.js +63 -0
  407. data/lib/web/wiki/resources/htmlarea/lang/it.js +54 -0
  408. data/lib/web/wiki/resources/htmlarea/lang/ja-euc.js +37 -0
  409. data/lib/web/wiki/resources/htmlarea/lang/ja-jis.js +37 -0
  410. data/lib/web/wiki/resources/htmlarea/lang/ja-sjis.js +37 -0
  411. data/lib/web/wiki/resources/htmlarea/lang/ja-utf8.js +37 -0
  412. data/lib/web/wiki/resources/htmlarea/lang/lt.js +55 -0
  413. data/lib/web/wiki/resources/htmlarea/lang/lv.js +55 -0
  414. data/lib/web/wiki/resources/htmlarea/lang/nb.js +36 -0
  415. data/lib/web/wiki/resources/htmlarea/lang/nl.js +90 -0
  416. data/lib/web/wiki/resources/htmlarea/lang/no.js +79 -0
  417. data/lib/web/wiki/resources/htmlarea/lang/pl.js +36 -0
  418. data/lib/web/wiki/resources/htmlarea/lang/pt_br.js +37 -0
  419. data/lib/web/wiki/resources/htmlarea/lang/ro.js +80 -0
  420. data/lib/web/wiki/resources/htmlarea/lang/ru.js +63 -0
  421. data/lib/web/wiki/resources/htmlarea/lang/se.js +38 -0
  422. data/lib/web/wiki/resources/htmlarea/lang/si.js +63 -0
  423. data/lib/web/wiki/resources/htmlarea/lang/vn.js +51 -0
  424. data/lib/web/wiki/resources/htmlarea/license.txt +30 -0
  425. data/lib/web/wiki/resources/htmlarea/plugins/CSS/css.js +116 -0
  426. data/lib/web/wiki/resources/htmlarea/plugins/CSS/lang/en.js +2 -0
  427. data/lib/web/wiki/resources/htmlarea/plugins/ContextMenu/context-menu.js +416 -0
  428. data/lib/web/wiki/resources/htmlarea/plugins/ContextMenu/lang/de.js +59 -0
  429. data/lib/web/wiki/resources/htmlarea/plugins/ContextMenu/lang/el.js +57 -0
  430. data/lib/web/wiki/resources/htmlarea/plugins/ContextMenu/lang/en.js +66 -0
  431. data/lib/web/wiki/resources/htmlarea/plugins/ContextMenu/lang/nl.js +66 -0
  432. data/lib/web/wiki/resources/htmlarea/plugins/ContextMenu/menu.css +64 -0
  433. data/lib/web/wiki/resources/htmlarea/plugins/FullPage/full-page.js +143 -0
  434. data/lib/web/wiki/resources/htmlarea/plugins/FullPage/img/docprop.gif +0 -0
  435. data/lib/web/wiki/resources/htmlarea/plugins/FullPage/lang/en.js +25 -0
  436. data/lib/web/wiki/resources/htmlarea/plugins/FullPage/lang/ro.js +25 -0
  437. data/lib/web/wiki/resources/htmlarea/plugins/FullPage/popups/docprop.html +131 -0
  438. data/lib/web/wiki/resources/htmlarea/plugins/FullPage/test.html +89 -0
  439. data/lib/web/wiki/resources/htmlarea/plugins/SpellChecker/img/spell-check.gif +0 -0
  440. data/lib/web/wiki/resources/htmlarea/plugins/SpellChecker/lang/cz.js +37 -0
  441. data/lib/web/wiki/resources/htmlarea/plugins/SpellChecker/lang/da.js +37 -0
  442. data/lib/web/wiki/resources/htmlarea/plugins/SpellChecker/lang/de.js +28 -0
  443. data/lib/web/wiki/resources/htmlarea/plugins/SpellChecker/lang/en.js +38 -0
  444. data/lib/web/wiki/resources/htmlarea/plugins/SpellChecker/lang/hu.js +37 -0
  445. data/lib/web/wiki/resources/htmlarea/plugins/SpellChecker/lang/it.js +28 -0
  446. data/lib/web/wiki/resources/htmlarea/plugins/SpellChecker/lang/ro.js +37 -0
  447. data/lib/web/wiki/resources/htmlarea/plugins/SpellChecker/readme-tech.html +114 -0
  448. data/lib/web/wiki/resources/htmlarea/plugins/SpellChecker/spell-check-logic.cgi +210 -0
  449. data/lib/web/wiki/resources/htmlarea/plugins/SpellChecker/spell-check-style.css +10 -0
  450. data/lib/web/wiki/resources/htmlarea/plugins/SpellChecker/spell-check-ui.html +122 -0
  451. data/lib/web/wiki/resources/htmlarea/plugins/SpellChecker/spell-check-ui.js +397 -0
  452. data/lib/web/wiki/resources/htmlarea/plugins/SpellChecker/spell-checker.js +79 -0
  453. data/lib/web/wiki/resources/htmlarea/plugins/TableOperations/img/cell-delete.gif +0 -0
  454. data/lib/web/wiki/resources/htmlarea/plugins/TableOperations/img/cell-insert-after.gif +0 -0
  455. data/lib/web/wiki/resources/htmlarea/plugins/TableOperations/img/cell-insert-before.gif +0 -0
  456. data/lib/web/wiki/resources/htmlarea/plugins/TableOperations/img/cell-merge.gif +0 -0
  457. data/lib/web/wiki/resources/htmlarea/plugins/TableOperations/img/cell-prop.gif +0 -0
  458. data/lib/web/wiki/resources/htmlarea/plugins/TableOperations/img/cell-split.gif +0 -0
  459. data/lib/web/wiki/resources/htmlarea/plugins/TableOperations/img/col-delete.gif +0 -0
  460. data/lib/web/wiki/resources/htmlarea/plugins/TableOperations/img/col-insert-after.gif +0 -0
  461. data/lib/web/wiki/resources/htmlarea/plugins/TableOperations/img/col-insert-before.gif +0 -0
  462. data/lib/web/wiki/resources/htmlarea/plugins/TableOperations/img/col-split.gif +0 -0
  463. data/lib/web/wiki/resources/htmlarea/plugins/TableOperations/img/row-delete.gif +0 -0
  464. data/lib/web/wiki/resources/htmlarea/plugins/TableOperations/img/row-insert-above.gif +0 -0
  465. data/lib/web/wiki/resources/htmlarea/plugins/TableOperations/img/row-insert-under.gif +0 -0
  466. data/lib/web/wiki/resources/htmlarea/plugins/TableOperations/img/row-prop.gif +0 -0
  467. data/lib/web/wiki/resources/htmlarea/plugins/TableOperations/img/row-split.gif +0 -0
  468. data/lib/web/wiki/resources/htmlarea/plugins/TableOperations/img/table-prop.gif +0 -0
  469. data/lib/web/wiki/resources/htmlarea/plugins/TableOperations/lang/cz.js +90 -0
  470. data/lib/web/wiki/resources/htmlarea/plugins/TableOperations/lang/da.js +90 -0
  471. data/lib/web/wiki/resources/htmlarea/plugins/TableOperations/lang/de.js +81 -0
  472. data/lib/web/wiki/resources/htmlarea/plugins/TableOperations/lang/el.js +81 -0
  473. data/lib/web/wiki/resources/htmlarea/plugins/TableOperations/lang/en.js +90 -0
  474. data/lib/web/wiki/resources/htmlarea/plugins/TableOperations/lang/fi.js +66 -0
  475. data/lib/web/wiki/resources/htmlarea/plugins/TableOperations/lang/hu.js +63 -0
  476. data/lib/web/wiki/resources/htmlarea/plugins/TableOperations/lang/it.js +81 -0
  477. data/lib/web/wiki/resources/htmlarea/plugins/TableOperations/lang/nl.js +90 -0
  478. data/lib/web/wiki/resources/htmlarea/plugins/TableOperations/lang/no.js +91 -0
  479. data/lib/web/wiki/resources/htmlarea/plugins/TableOperations/lang/ro.js +90 -0
  480. data/lib/web/wiki/resources/htmlarea/plugins/TableOperations/table-operations.js +1160 -0
  481. data/lib/web/wiki/resources/htmlarea/popupdiv.js +369 -0
  482. data/lib/web/wiki/resources/htmlarea/popups/about.html +378 -0
  483. data/lib/web/wiki/resources/htmlarea/popups/blank.html +2 -0
  484. data/lib/web/wiki/resources/htmlarea/popups/custom2.html +35 -0
  485. data/lib/web/wiki/resources/htmlarea/popups/editor_help.html +16 -0
  486. data/lib/web/wiki/resources/htmlarea/popups/fullscreen.html +133 -0
  487. data/lib/web/wiki/resources/htmlarea/popups/insert_image.html +191 -0
  488. data/lib/web/wiki/resources/htmlarea/popups/insert_table.html +174 -0
  489. data/lib/web/wiki/resources/htmlarea/popups/link.html +142 -0
  490. data/lib/web/wiki/resources/htmlarea/popups/old-fullscreen.html +131 -0
  491. data/lib/web/wiki/resources/htmlarea/popups/old_insert_image.html +206 -0
  492. data/lib/web/wiki/resources/htmlarea/popups/popup.js +109 -0
  493. data/lib/web/wiki/resources/htmlarea/popups/select_color.html +347 -0
  494. data/lib/web/wiki/resources/htmlarea/popupwin.js +139 -0
  495. data/lib/web/wiki/resources/htmlarea/reference.html +523 -0
  496. data/lib/web/wiki/resources/htmlarea/release-notes.html +165 -0
  497. data/lib/web/wiki/resources/ie-content_editor.html +1 -0
  498. data/lib/web/wiki/resources/ie-content_editor.js +196 -0
  499. data/lib/web/wiki/resources/illustration.html +1 -0
  500. data/lib/web/wiki/resources/illustration.html~ +1 -0
  501. data/lib/web/wiki/resources/images.html +1 -0
  502. data/lib/web/wiki/resources/index.html +4 -0
  503. data/lib/web/wiki/resources/index.html~ +4 -0
  504. data/lib/web/wiki/resources/more_news.html +5 -0
  505. data/lib/web/wiki/resources/more_news.html~ +5 -0
  506. data/lib/web/wiki/resources/more_news_rss_0.91.html +23 -0
  507. data/lib/web/wiki/resources/narf-logo.gif +0 -0
  508. data/lib/web/wiki/resources/page_history.html +19 -0
  509. data/lib/web/wiki/resources/page_history.html~ +19 -0
  510. data/lib/web/wiki/resources/template.html +13 -0
  511. data/lib/web/wiki/resources/template.html~ +13 -0
  512. data/lib/web/wiki/resources/test_upload.gif +0 -0
  513. data/lib/web/wiki/resources/text-styles.css +1 -0
  514. data/lib/web/writableio.rb +33 -0
  515. data/narf-0.5.1.gem +0 -0
  516. data/narf.gemspec +40 -0
  517. data/narf.gemspec~ +52 -0
  518. data/pre-setup.rb +5 -0
  519. data/sapi/apache_cgi/INSTALL.txt~ +9 -0
  520. data/sapi/apache_cgi/README~ +0 -0
  521. data/sapi/apache_cgi/src/narf.c +13 -0
  522. data/sapi/fastcgi/INSTALL.txt~ +17 -0
  523. data/sapi/mod_ruby/INSTALL.txt~ +5 -0
  524. data/sapi/webrick/INSTALL.txt~ +21 -0
  525. data/sapi/webrick/run_webrick.rb~ +16 -0
  526. data/scripts/dump.rb +14 -0
  527. data/scripts/makedist.rb +49 -0
  528. data/scripts/upload.html +5 -0
  529. data/scripts/uri.rb +41 -0
  530. data/scripts/uri/common.rb +432 -0
  531. data/scripts/uri/ftp.rb +149 -0
  532. data/scripts/uri/generic.rb +1106 -0
  533. data/scripts/uri/http.rb +76 -0
  534. data/scripts/uri/https.rb +26 -0
  535. data/scripts/uri/ldap.rb +238 -0
  536. data/scripts/uri/mailto.rb +260 -0
  537. data/scripts/urireg.rb +174 -0
  538. data/test/bufferedtestrunner.rb +112 -0
  539. data/test/mod_ruby_stub.rb +39 -0
  540. data/test/mod_ruby_stub.rb~ +38 -0
  541. data/test/stringio.rb +2 -0
  542. data/test/test.action.rb +142 -0
  543. data/test/test.action.rb~ +142 -0
  544. data/test/test.app.rb +0 -0
  545. data/test/test.assertinclude.rb +109 -0
  546. data/test/test.assertinclude.rb~ +109 -0
  547. data/test/test.formreader-2.0.rb +352 -0
  548. data/test/test.formreader.rb +465 -0
  549. data/test/test.mime-type.rb +23 -0
  550. data/test/test.narf.cgi.rb +101 -0
  551. data/test/test.narf.cgi.rb~ +105 -0
  552. data/test/test.request.rb +328 -0
  553. data/test/test.request.rb~ +318 -0
  554. data/test/test.response.rb +565 -0
  555. data/test/test.response.rb~ +556 -0
  556. data/test/test.session.rb +50 -0
  557. data/test/test.simpledispatcher.rb +188 -0
  558. data/test/test.tagparser.rb +65 -0
  559. data/test/test.template.rb +831 -0
  560. data/test/test.template.rb~ +832 -0
  561. data/test/test.testing2.rb +341 -0
  562. data/test/test.web.test.rb +463 -0
  563. data/test/test.web.test.rb~ +461 -0
  564. data/test/testfiles/basictemplate.tpl +1 -0
  565. data/test/testfiles/explorer5.multipart.data +9 -0
  566. data/test/testfiles/form.html +7 -0
  567. data/test/testfiles/mozilla.multipart.data +9 -0
  568. data/test/testfiles/netscape4.multipart.data +9 -0
  569. data/test/testfiles/pic hydra.png +1 -0
  570. data/test/testfiles/post.data +1 -0
  571. data/test/testfiles/print.text +1 -0
  572. data/test/testfiles/text +1 -0
  573. data/test/webunit/dont_get_it.test_webunit.rb +27 -0
  574. data/test/webunit/ref +38 -0
  575. data/test/webunit/resources/uploadfile1.txt +1 -0
  576. data/test/webunit/resources/uploadfile2.txt +1 -0
  577. data/test/webunit/test_assert.rb +169 -0
  578. data/test/webunit/test_cookie.rb +128 -0
  579. data/test/webunit/test_cookie.rb~ +128 -0
  580. data/test/webunit/test_domwalker.rb +83 -0
  581. data/test/webunit/test_form.rb +43 -0
  582. data/test/webunit/test_form.rb~ +43 -0
  583. data/test/webunit/test_frame.rb +43 -0
  584. data/test/webunit/test_htmlelem.rb +75 -0
  585. data/test/webunit/test_image.rb +46 -0
  586. data/test/webunit/test_jscript.rb +58 -0
  587. data/test/webunit/test_link.rb +87 -0
  588. data/test/webunit/test_multipart.rb +53 -0
  589. data/test/webunit/test_multipart.rb~ +53 -0
  590. data/test/webunit/test_params.rb +212 -0
  591. data/test/webunit/test_params.rb~ +211 -0
  592. data/test/webunit/test_parser.rb +31 -0
  593. data/test/webunit/test_response.rb +145 -0
  594. data/test/webunit/test_response.rb~ +145 -0
  595. data/test/webunit/test_site/assert.html +101 -0
  596. data/test/webunit/test_site/assert.html~ +1 -0
  597. data/test/webunit/test_site/auth/index.html +5 -0
  598. data/test/webunit/test_site/auth/index.html~ +1 -0
  599. data/test/webunit/test_site/badtags.html +7 -0
  600. data/test/webunit/test_site/badtags.html~ +1 -0
  601. data/test/webunit/test_site/cookie.cgi +37 -0
  602. data/test/webunit/test_site/cookie.cgi~ +35 -0
  603. data/test/webunit/test_site/document.xml +13 -0
  604. data/test/webunit/test_site/document.xml~ +1 -0
  605. data/test/webunit/test_site/form.html +150 -0
  606. data/test/webunit/test_site/form.html~ +1 -0
  607. data/test/webunit/test_site/frame-0.html +10 -0
  608. data/test/webunit/test_site/frame-0.html~ +1 -0
  609. data/test/webunit/test_site/frame-1.html +10 -0
  610. data/test/webunit/test_site/frame-1.html~ +1 -0
  611. data/test/webunit/test_site/frame.html +10 -0
  612. data/test/webunit/test_site/frame.html~ +1 -0
  613. data/test/webunit/test_site/image.html +17 -0
  614. data/test/webunit/test_site/image.html~ +1 -0
  615. data/test/webunit/test_site/images/x.gif +0 -0
  616. data/test/webunit/test_site/images/y.gif +0 -0
  617. data/test/webunit/test_site/include.cgi~ +10 -0
  618. data/test/webunit/test_site/jscript-0.html +10 -0
  619. data/test/webunit/test_site/jscript-0.html~ +1 -0
  620. data/test/webunit/test_site/jscript-1.html +10 -0
  621. data/test/webunit/test_site/jscript-1.html~ +1 -0
  622. data/test/webunit/test_site/jscript.html +19 -0
  623. data/test/webunit/test_site/jscript.html~ +1 -0
  624. data/test/webunit/test_site/link.html +19 -0
  625. data/test/webunit/test_site/link.html~ +1 -0
  626. data/test/webunit/test_site/multipart.cgi +27 -0
  627. data/test/webunit/test_site/multipart.cgi~ +25 -0
  628. data/test/webunit/test_site/multipart.html +74 -0
  629. data/test/webunit/test_site/multipart.html~ +1 -0
  630. data/test/webunit/test_site/params.html +65 -0
  631. data/test/webunit/test_site/params.html~ +1 -0
  632. data/test/webunit/test_site/redirect.cgi +14 -0
  633. data/test/webunit/test_site/redirect.cgi~ +14 -0
  634. data/test/webunit/test_site/response.html +67 -0
  635. data/test/webunit/test_site/response.html~ +1 -0
  636. data/test/webunit/test_site/simple.cgi +17 -0
  637. data/test/webunit/test_site/simple.cgi~ +17 -0
  638. data/test/webunit/test_site/stock.cgi +36 -0
  639. data/test/webunit/test_site/stock.cgi~ +34 -0
  640. data/test/webunit/test_site/table.html +83 -0
  641. data/test/webunit/test_site/table.html~ +1 -0
  642. data/test/webunit/test_site/test.cgi~ +25 -0
  643. data/test/webunit/test_table.rb +70 -0
  644. data/test/webunit/test_utils.rb +107 -0
  645. data/test/wiki/test.history.rb +277 -0
  646. data/test/wiki/test.history.rb~ +254 -0
  647. data/test/wiki/test.illustration_page.rb +287 -0
  648. data/test/wiki/test.illustration_page.rb~ +287 -0
  649. data/test/wiki/test.linker.rb +197 -0
  650. data/test/wiki/test.tarpit.rb +40 -0
  651. data/test/wiki/test.wiki.rb +295 -0
  652. data/test/wiki/test.wiki.rb~ +295 -0
  653. data/test/wikitestroot/big_image.jpg +0 -0
  654. data/test/wikitestroot/mime.types +483 -0
  655. data/test/wikitestroot/test_upload.gif +0 -0
  656. data/vandals.test.txt +3 -0
  657. metadata +768 -0
@@ -0,0 +1,2175 @@
1
+ // htmlArea v3.0 - Copyright (c) 2002-2004 interactivetools.com, inc.
2
+ // This copyright notice MUST stay intact for use (see license.txt).
3
+ //
4
+ // Portions (c) dynarch.com, 2003-2004
5
+ //
6
+ // A free WYSIWYG editor replacement for <textarea> fields.
7
+ // For full source code and docs, visit http://www.interactivetools.com/
8
+ //
9
+ // Version 3.0 developed by Mihai Bazon.
10
+ // http://dynarch.com/mishoo
11
+ //
12
+ // $Id: htmlarea.js,v 1.59 2004/02/09 09:38:47 mishoo Exp $
13
+
14
+ if (typeof _editor_url == "string") {
15
+ // Leave exactly one backslash at the end of _editor_url
16
+ _editor_url = _editor_url.replace(/\x2f*$/, '/');
17
+ } else {
18
+ alert("WARNING: _editor_url is not set! You should set this variable to the editor files path; it should preferably be an absolute path, like in '/htmlarea', but it can be relative if you prefer. Further we will try to load the editor files correctly but we'll probably fail.");
19
+ _editor_url = '';
20
+ }
21
+
22
+ // make sure we have a language
23
+ if (typeof _editor_lang == "string") {
24
+ _editor_lang = _editor_lang.toLowerCase();
25
+ } else {
26
+ _editor_lang = "en";
27
+ }
28
+
29
+ // Creates a new HTMLArea object. Tries to replace the textarea with the given
30
+ // ID with it.
31
+ function HTMLArea(textarea, config) {
32
+ if (HTMLArea.checkSupportedBrowser()) {
33
+ if (typeof config == "undefined") {
34
+ this.config = new HTMLArea.Config();
35
+ } else {
36
+ this.config = config;
37
+ }
38
+ this._htmlArea = null;
39
+ this._textArea = textarea;
40
+ this._editMode = "wysiwyg";
41
+ this.plugins = {};
42
+ this._timerToolbar = null;
43
+ this._timerUndo = null;
44
+ this._undoQueue = new Array(this.config.undoSteps);
45
+ this._undoPos = -1;
46
+ this._customUndo = false;
47
+ this._mdoc = document; // cache the document, we need it in plugins
48
+ this.doctype = '';
49
+ }
50
+ };
51
+
52
+ // load some scripts
53
+ (function() {
54
+ var scripts = HTMLArea._scripts = [ _editor_url + "htmlarea.js",
55
+ _editor_url + "dialog.js",
56
+ _editor_url + "popupwin.js",
57
+ _editor_url + "lang/" + _editor_lang + ".js" ];
58
+ var head = document.getElementsByTagName("head")[0];
59
+ // start from 1, htmlarea.js is already loaded
60
+ for (var i = 1; i < scripts.length; ++i) {
61
+ var script = document.createElement("script");
62
+ script.src = scripts[i];
63
+ head.appendChild(script);
64
+ }
65
+ })();
66
+
67
+ // cache some regexps
68
+ HTMLArea.RE_tagName = /(<\/|<)\s*([^ \t\n>]+)/ig;
69
+ HTMLArea.RE_doctype = /(<!doctype((.|\n)*?)>)\n?/i;
70
+ HTMLArea.RE_head = /<head>((.|\n)*?)<\/head>/i;
71
+ HTMLArea.RE_body = /<body>((.|\n)*?)<\/body>/i;
72
+
73
+ HTMLArea.Config = function () {
74
+ this.version = "3.0";
75
+
76
+ this.width = "auto";
77
+ this.height = "auto";
78
+
79
+ // enable creation of a status bar?
80
+ this.statusBar = true;
81
+
82
+ // maximum size of the undo queue
83
+ this.undoSteps = 20;
84
+
85
+ // the time interval at which undo samples are taken
86
+ this.undoTimeout = 500; // 1/2 sec.
87
+
88
+ // the next parameter specifies whether the toolbar should be included
89
+ // in the size or not.
90
+ this.sizeIncludesToolbar = true;
91
+
92
+ // if true then HTMLArea will retrieve the full HTML, starting with the
93
+ // <HTML> tag.
94
+ this.fullPage = false;
95
+
96
+ // style included in the iframe document
97
+ this.pageStyle = "";
98
+
99
+ // set to true if you want Word code to be cleaned upon Paste
100
+ this.killWordOnPaste = false;
101
+
102
+ // BaseURL included in the iframe document
103
+ this.baseURL = document.baseURI || document.URL;
104
+ if (this.baseURL && this.baseURL.match(/(.*)\/([^\/]+)/))
105
+ this.baseURL = RegExp.$1 + "/";
106
+
107
+ // URL-s
108
+ this.imgURL = "images/";
109
+ this.popupURL = "popups/";
110
+
111
+ /** CUSTOMIZING THE TOOLBAR
112
+ * -------------------------
113
+ *
114
+ * It is recommended that you customize the toolbar contents in an
115
+ * external file (i.e. the one calling HTMLArea) and leave this one
116
+ * unchanged. That's because when we (InteractiveTools.com) release a
117
+ * new official version, it's less likely that you will have problems
118
+ * upgrading HTMLArea.
119
+ */
120
+ this.toolbar = [
121
+ [ "fontname", "space",
122
+ "fontsize", "space",
123
+ "formatblock", "space",
124
+ "bold", "italic", "underline", "strikethrough", "separator",
125
+ "subscript", "superscript", "separator",
126
+ "copy", "cut", "paste", "space", "undo", "redo" ],
127
+
128
+ [ "justifyleft", "justifycenter", "justifyright", "justifyfull", "separator",
129
+ "lefttoright", "righttoleft", "separator",
130
+ "insertorderedlist", "insertunorderedlist", "outdent", "indent", "separator",
131
+ "forecolor", "hilitecolor", "separator",
132
+ "inserthorizontalrule", "createlink", "insertimage", "inserttable", "htmlmode", "separator",
133
+ "popupeditor", "separator", "showhelp", "about" ]
134
+ ];
135
+
136
+ this.fontname = {
137
+ "Arial": 'arial,helvetica,sans-serif',
138
+ "Courier New": 'courier new,courier,monospace',
139
+ "Georgia": 'georgia,times new roman,times,serif',
140
+ "Tahoma": 'tahoma,arial,helvetica,sans-serif',
141
+ "Times New Roman": 'times new roman,times,serif',
142
+ "Verdana": 'verdana,arial,helvetica,sans-serif',
143
+ "impact": 'impact',
144
+ "WingDings": 'wingdings'
145
+ };
146
+
147
+ this.fontsize = {
148
+ "1 (8 pt)": "1",
149
+ "2 (10 pt)": "2",
150
+ "3 (12 pt)": "3",
151
+ "4 (14 pt)": "4",
152
+ "5 (18 pt)": "5",
153
+ "6 (24 pt)": "6",
154
+ "7 (36 pt)": "7"
155
+ };
156
+
157
+ this.formatblock = {
158
+ "Heading 1": "h1",
159
+ "Heading 2": "h2",
160
+ "Heading 3": "h3",
161
+ "Heading 4": "h4",
162
+ "Heading 5": "h5",
163
+ "Heading 6": "h6",
164
+ "Normal": "p",
165
+ "Address": "address",
166
+ "Formatted": "pre"
167
+ };
168
+
169
+ this.customSelects = {};
170
+
171
+ function cut_copy_paste(e, cmd, obj) {
172
+ e.execCommand(cmd);
173
+ };
174
+
175
+ // ADDING CUSTOM BUTTONS: please read below!
176
+ // format of the btnList elements is "ID: [ ToolTip, Icon, Enabled in text mode?, ACTION ]"
177
+ // - ID: unique ID for the button. If the button calls document.execCommand
178
+ // it's wise to give it the same name as the called command.
179
+ // - ACTION: function that gets called when the button is clicked.
180
+ // it has the following prototype:
181
+ // function(editor, buttonName)
182
+ // - editor is the HTMLArea object that triggered the call
183
+ // - buttonName is the ID of the clicked button
184
+ // These 2 parameters makes it possible for you to use the same
185
+ // handler for more HTMLArea objects or for more different buttons.
186
+ // - ToolTip: default tooltip, for cases when it is not defined in the -lang- file (HTMLArea.I18N)
187
+ // - Icon: path to an icon image file for the button (TODO: use one image for all buttons!)
188
+ // - Enabled in text mode: if false the button gets disabled for text-only mode; otherwise enabled all the time.
189
+ this.btnList = {
190
+ bold: [ "Bold", "ed_format_bold.gif", false, function(e) {e.execCommand("bold");} ],
191
+ italic: [ "Italic", "ed_format_italic.gif", false, function(e) {e.execCommand("italic");} ],
192
+ underline: [ "Underline", "ed_format_underline.gif", false, function(e) {e.execCommand("underline");} ],
193
+ strikethrough: [ "Strikethrough", "ed_format_strike.gif", false, function(e) {e.execCommand("strikethrough");} ],
194
+ subscript: [ "Subscript", "ed_format_sub.gif", false, function(e) {e.execCommand("subscript");} ],
195
+ superscript: [ "Superscript", "ed_format_sup.gif", false, function(e) {e.execCommand("superscript");} ],
196
+ justifyleft: [ "Justify Left", "ed_align_left.gif", false, function(e) {e.execCommand("justifyleft");} ],
197
+ justifycenter: [ "Justify Center", "ed_align_center.gif", false, function(e) {e.execCommand("justifycenter");} ],
198
+ justifyright: [ "Justify Right", "ed_align_right.gif", false, function(e) {e.execCommand("justifyright");} ],
199
+ justifyfull: [ "Justify Full", "ed_align_justify.gif", false, function(e) {e.execCommand("justifyfull");} ],
200
+ insertorderedlist: [ "Ordered List", "ed_list_num.gif", false, function(e) {e.execCommand("insertorderedlist");} ],
201
+ insertunorderedlist: [ "Bulleted List", "ed_list_bullet.gif", false, function(e) {e.execCommand("insertunorderedlist");} ],
202
+ outdent: [ "Decrease Indent", "ed_indent_less.gif", false, function(e) {e.execCommand("outdent");} ],
203
+ indent: [ "Increase Indent", "ed_indent_more.gif", false, function(e) {e.execCommand("indent");} ],
204
+ forecolor: [ "Font Color", "ed_color_fg.gif", false, function(e) {e.execCommand("forecolor");} ],
205
+ hilitecolor: [ "Background Color", "ed_color_bg.gif", false, function(e) {e.execCommand("hilitecolor");} ],
206
+ inserthorizontalrule: [ "Horizontal Rule", "ed_hr.gif", false, function(e) {e.execCommand("inserthorizontalrule");} ],
207
+ createlink: [ "Insert Web Link", "ed_link.gif", false, function(e) {e.execCommand("createlink", true);} ],
208
+ insertimage: [ "Insert/Modify Image", "ed_image.gif", false, function(e) {e.execCommand("insertimage");} ],
209
+ inserttable: [ "Insert Table", "insert_table.gif", false, function(e) {e.execCommand("inserttable");} ],
210
+ htmlmode: [ "Toggle HTML Source", "ed_html.gif", true, function(e) {e.execCommand("htmlmode");} ],
211
+ popupeditor: [ "Enlarge Editor", "fullscreen_maximize.gif", true, function(e) {e.execCommand("popupeditor");} ],
212
+ about: [ "About this editor", "ed_about.gif", true, function(e) {e.execCommand("about");} ],
213
+ showhelp: [ "Help using editor", "ed_help.gif", true, function(e) {e.execCommand("showhelp");} ],
214
+ undo: [ "Undoes your last action", "ed_undo.gif", false, function(e) {e.execCommand("undo");} ],
215
+ redo: [ "Redoes your last action", "ed_redo.gif", false, function(e) {e.execCommand("redo");} ],
216
+ cut: [ "Cut selection", "ed_cut.gif", false, cut_copy_paste ],
217
+ copy: [ "Copy selection", "ed_copy.gif", false, cut_copy_paste ],
218
+ paste: [ "Paste from clipboard", "ed_paste.gif", false, cut_copy_paste ],
219
+ lefttoright: [ "Direction left to right", "ed_left_to_right.gif", false, function(e) {e.execCommand("lefttoright");} ],
220
+ righttoleft: [ "Direction right to left", "ed_right_to_left.gif", false, function(e) {e.execCommand("righttoleft");} ]
221
+ };
222
+ /* ADDING CUSTOM BUTTONS
223
+ * ---------------------
224
+ *
225
+ * It is recommended that you add the custom buttons in an external
226
+ * file and leave this one unchanged. That's because when we
227
+ * (InteractiveTools.com) release a new official version, it's less
228
+ * likely that you will have problems upgrading HTMLArea.
229
+ *
230
+ * Example on how to add a custom button when you construct the HTMLArea:
231
+ *
232
+ * var editor = new HTMLArea("your_text_area_id");
233
+ * var cfg = editor.config; // this is the default configuration
234
+ * cfg.btnList["my-hilite"] =
235
+ * [ function(editor) { editor.surroundHTML('<span style="background:yellow">', '</span>'); }, // action
236
+ * "Highlight selection", // tooltip
237
+ * "my_hilite.gif", // image
238
+ * false // disabled in text mode
239
+ * ];
240
+ * cfg.toolbar.push(["linebreak", "my-hilite"]); // add the new button to the toolbar
241
+ *
242
+ * An alternate (also more convenient and recommended) way to
243
+ * accomplish this is to use the registerButton function below.
244
+ */
245
+ // initialize tooltips from the I18N module and generate correct image path
246
+ for (var i in this.btnList) {
247
+ var btn = this.btnList[i];
248
+ btn[1] = _editor_url + this.imgURL + btn[1];
249
+ if (typeof HTMLArea.I18N.tooltips[i] != "undefined") {
250
+ btn[0] = HTMLArea.I18N.tooltips[i];
251
+ }
252
+ }
253
+ };
254
+
255
+ /** Helper function: register a new button with the configuration. It can be
256
+ * called with all 5 arguments, or with only one (first one). When called with
257
+ * only one argument it must be an object with the following properties: id,
258
+ * tooltip, image, textMode, action. Examples:
259
+ *
260
+ * 1. config.registerButton("my-hilite", "Hilite text", "my-hilite.gif", false, function(editor) {...});
261
+ * 2. config.registerButton({
262
+ * id : "my-hilite", // the ID of your button
263
+ * tooltip : "Hilite text", // the tooltip
264
+ * image : "my-hilite.gif", // image to be displayed in the toolbar
265
+ * textMode : false, // disabled in text mode
266
+ * action : function(editor) { // called when the button is clicked
267
+ * editor.surroundHTML('<span class="hilite">', '</span>');
268
+ * },
269
+ * context : "p" // will be disabled if outside a <p> element
270
+ * });
271
+ */
272
+ HTMLArea.Config.prototype.registerButton = function(id, tooltip, image, textMode, action, context) {
273
+ var the_id;
274
+ if (typeof id == "string") {
275
+ the_id = id;
276
+ } else if (typeof id == "object") {
277
+ the_id = id.id;
278
+ } else {
279
+ alert("ERROR [HTMLArea.Config::registerButton]:\ninvalid arguments");
280
+ return false;
281
+ }
282
+ // check for existing id
283
+ if (typeof this.customSelects[the_id] != "undefined") {
284
+ // alert("WARNING [HTMLArea.Config::registerDropdown]:\nA dropdown with the same ID already exists.");
285
+ }
286
+ if (typeof this.btnList[the_id] != "undefined") {
287
+ // alert("WARNING [HTMLArea.Config::registerDropdown]:\nA button with the same ID already exists.");
288
+ }
289
+ switch (typeof id) {
290
+ case "string": this.btnList[id] = [ tooltip, image, textMode, action, context ]; break;
291
+ case "object": this.btnList[id.id] = [ id.tooltip, id.image, id.textMode, id.action, id.context ]; break;
292
+ }
293
+ };
294
+
295
+ /** The following helper function registers a dropdown box with the editor
296
+ * configuration. You still have to add it to the toolbar, same as with the
297
+ * buttons. Call it like this:
298
+ *
299
+ * FIXME: add example
300
+ */
301
+ HTMLArea.Config.prototype.registerDropdown = function(object) {
302
+ // check for existing id
303
+ if (typeof this.customSelects[object.id] != "undefined") {
304
+ // alert("WARNING [HTMLArea.Config::registerDropdown]:\nA dropdown with the same ID already exists.");
305
+ }
306
+ if (typeof this.btnList[object.id] != "undefined") {
307
+ // alert("WARNING [HTMLArea.Config::registerDropdown]:\nA button with the same ID already exists.");
308
+ }
309
+ this.customSelects[object.id] = object;
310
+ };
311
+
312
+ /** Call this function to remove some buttons/drop-down boxes from the toolbar.
313
+ * Pass as the only parameter a string containing button/drop-down names
314
+ * delimited by spaces. Note that the string should also begin with a space
315
+ * and end with a space. Example:
316
+ *
317
+ * config.hideSomeButtons(" fontname fontsize textindicator ");
318
+ *
319
+ * It's useful because it's easier to remove stuff from the defaul toolbar than
320
+ * create a brand new toolbar ;-)
321
+ */
322
+ HTMLArea.Config.prototype.hideSomeButtons = function(remove) {
323
+ var toolbar = this.toolbar;
324
+ for (var i in toolbar) {
325
+ var line = toolbar[i];
326
+ for (var j = line.length; --j >= 0; ) {
327
+ if (remove.indexOf(" " + line[j] + " ") >= 0) {
328
+ var len = 1;
329
+ if (/separator|space/.test(line[j + 1])) {
330
+ len = 2;
331
+ }
332
+ line.splice(j, len);
333
+ }
334
+ }
335
+ }
336
+ };
337
+
338
+ /** Helper function: replace all TEXTAREA-s in the document with HTMLArea-s. */
339
+ HTMLArea.replaceAll = function(config) {
340
+ var tas = document.getElementsByTagName("textarea");
341
+ for (var i = tas.length; i > 0; (new HTMLArea(tas[--i], config)).generate());
342
+ };
343
+
344
+ /** Helper function: replaces the TEXTAREA with the given ID with HTMLArea. */
345
+ HTMLArea.replace = function(id, config) {
346
+ var ta = HTMLArea.getElementById("textarea", id);
347
+ return ta ? (new HTMLArea(ta, config)).generate() : null;
348
+ };
349
+
350
+ // Creates the toolbar and appends it to the _htmlarea
351
+ HTMLArea.prototype._createToolbar = function () {
352
+ var editor = this; // to access this in nested functions
353
+
354
+ var toolbar = document.createElement("div");
355
+ this._toolbar = toolbar;
356
+ toolbar.className = "toolbar";
357
+ toolbar.unselectable = "1";
358
+ var tb_row = null;
359
+ var tb_objects = new Object();
360
+ this._toolbarObjects = tb_objects;
361
+
362
+ // creates a new line in the toolbar
363
+ function newLine() {
364
+ var table = document.createElement("table");
365
+ table.border = "0px";
366
+ table.cellSpacing = "0px";
367
+ table.cellPadding = "0px";
368
+ toolbar.appendChild(table);
369
+ // TBODY is required for IE, otherwise you don't see anything
370
+ // in the TABLE.
371
+ var tb_body = document.createElement("tbody");
372
+ table.appendChild(tb_body);
373
+ tb_row = document.createElement("tr");
374
+ tb_body.appendChild(tb_row);
375
+ }; // END of function: newLine
376
+ // init first line
377
+ newLine();
378
+
379
+ // updates the state of a toolbar element. This function is member of
380
+ // a toolbar element object (unnamed objects created by createButton or
381
+ // createSelect functions below).
382
+ function setButtonStatus(id, newval) {
383
+ var oldval = this[id];
384
+ var el = this.element;
385
+ if (oldval != newval) {
386
+ switch (id) {
387
+ case "enabled":
388
+ if (newval) {
389
+ HTMLArea._removeClass(el, "buttonDisabled");
390
+ el.disabled = false;
391
+ } else {
392
+ HTMLArea._addClass(el, "buttonDisabled");
393
+ el.disabled = true;
394
+ }
395
+ break;
396
+ case "active":
397
+ if (newval) {
398
+ HTMLArea._addClass(el, "buttonPressed");
399
+ } else {
400
+ HTMLArea._removeClass(el, "buttonPressed");
401
+ }
402
+ break;
403
+ }
404
+ this[id] = newval;
405
+ }
406
+ }; // END of function: setButtonStatus
407
+
408
+ // this function will handle creation of combo boxes. Receives as
409
+ // parameter the name of a button as defined in the toolBar config.
410
+ // This function is called from createButton, above, if the given "txt"
411
+ // doesn't match a button.
412
+ function createSelect(txt) {
413
+ var options = null;
414
+ var el = null;
415
+ var cmd = null;
416
+ var customSelects = editor.config.customSelects;
417
+ var context = null;
418
+ switch (txt) {
419
+ case "fontsize":
420
+ case "fontname":
421
+ case "formatblock":
422
+ // the following line retrieves the correct
423
+ // configuration option because the variable name
424
+ // inside the Config object is named the same as the
425
+ // button/select in the toolbar. For instance, if txt
426
+ // == "formatblock" we retrieve config.formatblock (or
427
+ // a different way to write it in JS is
428
+ // config["formatblock"].
429
+ options = editor.config[txt];
430
+ cmd = txt;
431
+ break;
432
+ default:
433
+ // try to fetch it from the list of registered selects
434
+ cmd = txt;
435
+ var dropdown = customSelects[cmd];
436
+ if (typeof dropdown != "undefined") {
437
+ options = dropdown.options;
438
+ context = dropdown.context;
439
+ } else {
440
+ alert("ERROR [createSelect]:\nCan't find the requested dropdown definition");
441
+ }
442
+ break;
443
+ }
444
+ if (options) {
445
+ el = document.createElement("select");
446
+ var obj = {
447
+ name : txt, // field name
448
+ element : el, // the UI element (SELECT)
449
+ enabled : true, // is it enabled?
450
+ text : false, // enabled in text mode?
451
+ cmd : cmd, // command ID
452
+ state : setButtonStatus, // for changing state
453
+ context : context
454
+ };
455
+ tb_objects[txt] = obj;
456
+ for (var i in options) {
457
+ var op = document.createElement("option");
458
+ op.appendChild(document.createTextNode(i));
459
+ op.value = options[i];
460
+ el.appendChild(op);
461
+ }
462
+ HTMLArea._addEvent(el, "change", function () {
463
+ editor._comboSelected(el, txt);
464
+ });
465
+ }
466
+ return el;
467
+ }; // END of function: createSelect
468
+
469
+ // appends a new button to toolbar
470
+ function createButton(txt) {
471
+ // the element that will be created
472
+ var el = null;
473
+ var btn = null;
474
+ switch (txt) {
475
+ case "separator":
476
+ el = document.createElement("div");
477
+ el.className = "separator";
478
+ break;
479
+ case "space":
480
+ el = document.createElement("div");
481
+ el.className = "space";
482
+ break;
483
+ case "linebreak":
484
+ newLine();
485
+ return false;
486
+ case "textindicator":
487
+ el = document.createElement("div");
488
+ el.appendChild(document.createTextNode("A"));
489
+ el.className = "indicator";
490
+ el.title = HTMLArea.I18N.tooltips.textindicator;
491
+ var obj = {
492
+ name : txt, // the button name (i.e. 'bold')
493
+ element : el, // the UI element (DIV)
494
+ enabled : true, // is it enabled?
495
+ active : false, // is it pressed?
496
+ text : false, // enabled in text mode?
497
+ cmd : "textindicator", // the command ID
498
+ state : setButtonStatus // for changing state
499
+ };
500
+ tb_objects[txt] = obj;
501
+ break;
502
+ default:
503
+ btn = editor.config.btnList[txt];
504
+ }
505
+ if (!el && btn) {
506
+ el = document.createElement("div");
507
+ el.title = btn[0];
508
+ el.className = "button";
509
+ // let's just pretend we have a button object, and
510
+ // assign all the needed information to it.
511
+ var obj = {
512
+ name : txt, // the button name (i.e. 'bold')
513
+ element : el, // the UI element (DIV)
514
+ enabled : true, // is it enabled?
515
+ active : false, // is it pressed?
516
+ text : btn[2], // enabled in text mode?
517
+ cmd : btn[3], // the command ID
518
+ state : setButtonStatus, // for changing state
519
+ context : btn[4] || null // enabled in a certain context?
520
+ };
521
+ tb_objects[txt] = obj;
522
+ // handlers to emulate nice flat toolbar buttons
523
+ HTMLArea._addEvent(el, "mouseover", function () {
524
+ if (obj.enabled) {
525
+ HTMLArea._addClass(el, "buttonHover");
526
+ }
527
+ });
528
+ HTMLArea._addEvent(el, "mouseout", function () {
529
+ if (obj.enabled) with (HTMLArea) {
530
+ _removeClass(el, "buttonHover");
531
+ _removeClass(el, "buttonActive");
532
+ (obj.active) && _addClass(el, "buttonPressed");
533
+ }
534
+ });
535
+ HTMLArea._addEvent(el, "mousedown", function (ev) {
536
+ if (obj.enabled) with (HTMLArea) {
537
+ _addClass(el, "buttonActive");
538
+ _removeClass(el, "buttonPressed");
539
+ _stopEvent(is_ie ? window.event : ev);
540
+ }
541
+ });
542
+ // when clicked, do the following:
543
+ HTMLArea._addEvent(el, "click", function (ev) {
544
+ if (obj.enabled) with (HTMLArea) {
545
+ _removeClass(el, "buttonActive");
546
+ _removeClass(el, "buttonHover");
547
+ obj.cmd(editor, obj.name, obj);
548
+ _stopEvent(is_ie ? window.event : ev);
549
+ }
550
+ });
551
+ var img = document.createElement("img");
552
+ img.src = btn[1];
553
+ img.style.width = "18px";
554
+ img.style.height = "18px";
555
+ el.appendChild(img);
556
+ } else if (!el) {
557
+ el = createSelect(txt);
558
+ }
559
+ if (el) {
560
+ var tb_cell = document.createElement("td");
561
+ tb_row.appendChild(tb_cell);
562
+ tb_cell.appendChild(el);
563
+ } else {
564
+ alert("FIXME: Unknown toolbar item: " + txt);
565
+ }
566
+ return el;
567
+ };
568
+
569
+ var first = true;
570
+ for (var i in this.config.toolbar) {
571
+ if (!first) {
572
+ createButton("linebreak");
573
+ } else {
574
+ first = false;
575
+ }
576
+ var group = this.config.toolbar[i];
577
+ for (var j in group) {
578
+ var code = group[j];
579
+ if (/^([IT])\[(.*?)\]/.test(code)) {
580
+ // special case, create text label
581
+ var l7ed = RegExp.$1 == "I"; // localized?
582
+ var label = RegExp.$2;
583
+ if (l7ed) {
584
+ label = HTMLArea.I18N.custom[label];
585
+ }
586
+ var tb_cell = document.createElement("td");
587
+ tb_row.appendChild(tb_cell);
588
+ tb_cell.className = "label";
589
+ tb_cell.innerHTML = label;
590
+ } else {
591
+ createButton(code);
592
+ }
593
+ }
594
+ }
595
+
596
+ this._htmlArea.appendChild(toolbar);
597
+ };
598
+
599
+ HTMLArea.prototype._createStatusBar = function() {
600
+ var statusbar = document.createElement("div");
601
+ statusbar.className = "statusBar";
602
+ this._htmlArea.appendChild(statusbar);
603
+ this._statusBar = statusbar;
604
+ // statusbar.appendChild(document.createTextNode(HTMLArea.I18N.msg["Path"] + ": "));
605
+ // creates a holder for the path view
606
+ div = document.createElement("span");
607
+ div.className = "statusBarTree";
608
+ div.innerHTML = HTMLArea.I18N.msg["Path"] + ": ";
609
+ this._statusBarTree = div;
610
+ this._statusBar.appendChild(div);
611
+ if (!this.config.statusBar) {
612
+ // disable it...
613
+ statusbar.style.display = "none";
614
+ }
615
+ };
616
+
617
+ // Creates the HTMLArea object and replaces the textarea with it.
618
+ HTMLArea.prototype.generate = function () {
619
+ var editor = this; // we'll need "this" in some nested functions
620
+ // get the textarea
621
+ var textarea = this._textArea;
622
+ if (typeof textarea == "string") {
623
+ // it's not element but ID
624
+ this._textArea = textarea = HTMLArea.getElementById("textarea", textarea);
625
+ }
626
+ this._ta_size = {
627
+ w: textarea.offsetWidth,
628
+ h: textarea.offsetHeight
629
+ };
630
+ textarea.style.display = "none";
631
+
632
+ // create the editor framework
633
+ var htmlarea = document.createElement("div");
634
+ htmlarea.className = "htmlarea";
635
+ this._htmlArea = htmlarea;
636
+
637
+ // insert the editor before the textarea.
638
+ textarea.parentNode.insertBefore(htmlarea, textarea);
639
+
640
+ if (textarea.form) {
641
+ // we have a form, on submit get the HTMLArea content and
642
+ // update original textarea.
643
+ var f = textarea.form;
644
+ if (typeof f.onsubmit == "function") {
645
+ var funcref = f.onsubmit;
646
+ if (typeof f.__msh_prevOnSubmit == "undefined") {
647
+ f.__msh_prevOnSubmit = [];
648
+ }
649
+ f.__msh_prevOnSubmit.push(funcref);
650
+ }
651
+ f.onsubmit = function() {
652
+ editor._textArea.value = editor.getHTML();
653
+ var a = this.__msh_prevOnSubmit;
654
+ // call previous submit methods if they were there.
655
+ if (typeof a != "undefined") {
656
+ for (var i in a) {
657
+ a[i]();
658
+ }
659
+ }
660
+ };
661
+ }
662
+
663
+ // add a handler for the "back/forward" case -- on body.unload we save
664
+ // the HTML content into the original textarea.
665
+ window.onunload = function() {
666
+ editor._textArea.value = editor.getHTML();
667
+ };
668
+
669
+ // creates & appends the toolbar
670
+ this._createToolbar();
671
+
672
+ // create the IFRAME
673
+ var iframe = document.createElement("iframe");
674
+ htmlarea.appendChild(iframe);
675
+
676
+ this._iframe = iframe;
677
+
678
+ // creates & appends the status bar, if the case
679
+ this._createStatusBar();
680
+
681
+ // remove the default border as it keeps us from computing correctly
682
+ // the sizes. (somebody tell me why doesn't this work in IE)
683
+
684
+ if (!HTMLArea.is_ie) {
685
+ iframe.style.borderWidth = "1px";
686
+ // iframe.frameBorder = "1";
687
+ // iframe.marginHeight = "0";
688
+ // iframe.marginWidth = "0";
689
+ }
690
+
691
+ // size the IFRAME according to user's prefs or initial textarea
692
+ var height = (this.config.height == "auto" ? (this._ta_size.h + "px") : this.config.height);
693
+ height = parseInt(height);
694
+ var width = (this.config.width == "auto" ? (this._ta_size.w + "px") : this.config.width);
695
+ width = parseInt(width);
696
+
697
+ if (!HTMLArea.is_ie) {
698
+ height -= 2;
699
+ width -= 2;
700
+ }
701
+
702
+ iframe.style.width = width + "px";
703
+ if (this.config.sizeIncludesToolbar) {
704
+ // substract toolbar height
705
+ height -= this._toolbar.offsetHeight;
706
+ height -= this._statusBar.offsetHeight;
707
+ }
708
+ if (height < 0) {
709
+ height = 0;
710
+ }
711
+ iframe.style.height = height + "px";
712
+
713
+ // the editor including the toolbar now have the same size as the
714
+ // original textarea.. which means that we need to reduce that a bit.
715
+ textarea.style.width = iframe.style.width;
716
+ textarea.style.height = iframe.style.height;
717
+
718
+ // IMPORTANT: we have to allow Mozilla a short time to recognize the
719
+ // new frame. Otherwise we get a stupid exception.
720
+ function initIframe() {
721
+ var doc = editor._iframe.contentWindow.document;
722
+ if (!doc) {
723
+ // Try again..
724
+ // FIXME: don't know what else to do here. Normally
725
+ // we'll never reach this point.
726
+ if (HTMLArea.is_gecko) {
727
+ setTimeout(initIframe, 100);
728
+ return false;
729
+ } else {
730
+ alert("ERROR: IFRAME can't be initialized.");
731
+ }
732
+ }
733
+ if (HTMLArea.is_gecko) {
734
+ // enable editable mode for Mozilla
735
+ doc.designMode = "on";
736
+ }
737
+ editor._doc = doc;
738
+ if (!editor.config.fullPage) {
739
+ doc.open();
740
+ var html = "<html>\n";
741
+ html += "<head>\n";
742
+ if (editor.config.baseURL)
743
+ html += '<base href="' + editor.config.baseURL + '" />';
744
+ html += "<style> html,body { border: 0px; } " +
745
+ editor.config.pageStyle + "</style>\n";
746
+ html += "</head>\n";
747
+ html += "<body>\n";
748
+ html += editor._textArea.value;
749
+ html += "</body>\n";
750
+ html += "</html>";
751
+ doc.write(html);
752
+ doc.close();
753
+ } else {
754
+ var html = editor._textArea.value;
755
+ if (html.match(HTMLArea.RE_doctype)) {
756
+ editor.setDoctype(RegExp.$1);
757
+ html = html.replace(HTMLArea.RE_doctype, "");
758
+ }
759
+ doc.open();
760
+ doc.write(html);
761
+ doc.close();
762
+ }
763
+
764
+ if (HTMLArea.is_ie) {
765
+ // enable editable mode for IE. For some reason this
766
+ // doesn't work if done in the same place as for Gecko
767
+ // (above).
768
+ doc.body.contentEditable = true;
769
+ }
770
+
771
+ editor.focusEditor();
772
+ // intercept some events; for updating the toolbar & keyboard handlers
773
+ HTMLArea._addEvents
774
+ (doc, ["keydown", "keypress", "mousedown", "mouseup", "drag"],
775
+ function (event) {
776
+ return editor._editorEvent(HTMLArea.is_ie ? editor._iframe.contentWindow.event : event);
777
+ });
778
+
779
+ // check if any plugins have registered refresh handlers
780
+ for (var i in editor.plugins) {
781
+ var plugin = editor.plugins[i].instance;
782
+ if (typeof plugin.onGenerate == "function")
783
+ plugin.onGenerate();
784
+ }
785
+
786
+ setTimeout(function() {
787
+ editor.updateToolbar();
788
+ }, 250);
789
+
790
+ if (typeof editor.onGenerate == "function")
791
+ editor.onGenerate();
792
+ };
793
+ setTimeout(initIframe, 100);
794
+ };
795
+
796
+ // Switches editor mode; parameter can be "textmode" or "wysiwyg". If no
797
+ // parameter was passed this function toggles between modes.
798
+ HTMLArea.prototype.setMode = function(mode) {
799
+ if (typeof mode == "undefined") {
800
+ mode = ((this._editMode == "textmode") ? "wysiwyg" : "textmode");
801
+ }
802
+ switch (mode) {
803
+ case "textmode":
804
+ this._textArea.value = this.getHTML();
805
+ this._iframe.style.display = "none";
806
+ this._textArea.style.display = "block";
807
+ if (this.config.statusBar) {
808
+ this._statusBar.innerHTML = HTMLArea.I18N.msg["TEXT_MODE"];
809
+ }
810
+ break;
811
+ case "wysiwyg":
812
+ if (HTMLArea.is_gecko) {
813
+ // disable design mode before changing innerHTML
814
+ try {
815
+ this._doc.designMode = "off";
816
+ } catch(e) {};
817
+ }
818
+ if (!this.config.fullPage)
819
+ this._doc.body.innerHTML = this.getHTML();
820
+ else
821
+ this.setFullHTML(this.getHTML());
822
+ this._iframe.style.display = "block";
823
+ this._textArea.style.display = "none";
824
+ if (HTMLArea.is_gecko) {
825
+ // we need to refresh that info for Moz-1.3a
826
+ try {
827
+ this._doc.designMode = "on";
828
+ } catch(e) {};
829
+ }
830
+ if (this.config.statusBar) {
831
+ this._statusBar.innerHTML = '';
832
+ this._statusBar.appendChild(document.createTextNode(HTMLArea.I18N.msg["Path"] + ": "));
833
+ this._statusBar.appendChild(this._statusBarTree);
834
+ }
835
+ break;
836
+ default:
837
+ alert("Mode <" + mode + "> not defined!");
838
+ return false;
839
+ }
840
+ this._editMode = mode;
841
+ this.focusEditor();
842
+ };
843
+
844
+ HTMLArea.prototype.setFullHTML = function(html) {
845
+ var save_multiline = RegExp.multiline;
846
+ RegExp.multiline = true;
847
+ if (html.match(HTMLArea.RE_doctype)) {
848
+ this.setDoctype(RegExp.$1);
849
+ html = html.replace(HTMLArea.RE_doctype, "");
850
+ }
851
+ RegExp.multiline = save_multiline;
852
+ if (!HTMLArea.is_ie) {
853
+ if (html.match(HTMLArea.RE_head))
854
+ this._doc.getElementsByTagName("head")[0].innerHTML = RegExp.$1;
855
+ if (html.match(HTMLArea.RE_body))
856
+ this._doc.getElementsByTagName("body")[0].innerHTML = RegExp.$1;
857
+ } else {
858
+ var html_re = /<html>((.|\n)*?)<\/html>/i;
859
+ html = html.replace(html_re, "$1");
860
+ this._doc.open();
861
+ this._doc.write(html);
862
+ this._doc.close();
863
+ this._doc.body.contentEditable = true;
864
+ return true;
865
+ }
866
+ };
867
+
868
+ /***************************************************
869
+ * Category: PLUGINS
870
+ ***************************************************/
871
+
872
+ // this is the variant of the function above where the plugin arguments are
873
+ // already packed in an array. Externally, it should be only used in the
874
+ // full-screen editor code, in order to initialize plugins with the same
875
+ // parameters as in the opener window.
876
+ HTMLArea.prototype.registerPlugin2 = function(plugin, args) {
877
+ if (typeof plugin == "string")
878
+ plugin = eval(plugin);
879
+ var obj = new plugin(this, args);
880
+ if (obj) {
881
+ var clone = {};
882
+ var info = plugin._pluginInfo;
883
+ for (var i in info)
884
+ clone[i] = info[i];
885
+ clone.instance = obj;
886
+ clone.args = args;
887
+ this.plugins[plugin._pluginInfo.name] = clone;
888
+ } else
889
+ alert("Can't register plugin " + plugin.toString() + ".");
890
+ };
891
+
892
+ // Create the specified plugin and register it with this HTMLArea
893
+ HTMLArea.prototype.registerPlugin = function() {
894
+ var plugin = arguments[0];
895
+ var args = [];
896
+ for (var i = 1; i < arguments.length; ++i)
897
+ args.push(arguments[i]);
898
+ this.registerPlugin2(plugin, args);
899
+ };
900
+
901
+ // static function that loads the required plugin and lang file, based on the
902
+ // language loaded already for HTMLArea. You better make sure that the plugin
903
+ // _has_ that language, otherwise shit might happen ;-)
904
+ HTMLArea.loadPlugin = function(pluginName) {
905
+ var dir = _editor_url + "plugins/" + pluginName;
906
+ var plugin = pluginName.replace(/([a-z])([A-Z])([a-z])/g,
907
+ function (str, l1, l2, l3) {
908
+ return l1 + "-" + l2.toLowerCase() + l3;
909
+ }).toLowerCase() + ".js";
910
+ var plugin_file = dir + "/" + plugin;
911
+ var plugin_lang = dir + "/lang/" + HTMLArea.I18N.lang + ".js";
912
+ HTMLArea._scripts.push(plugin_file, plugin_lang);
913
+ document.write("<script type='text/javascript' src='" + plugin_file + "'></script>");
914
+ document.write("<script type='text/javascript' src='" + plugin_lang + "'></script>");
915
+ };
916
+
917
+ HTMLArea.loadStyle = function(style, plugin) {
918
+ var url = _editor_url || '';
919
+ if (typeof plugin != "undefined") {
920
+ url += "plugins/" + plugin + "/";
921
+ }
922
+ url += style;
923
+ document.write("<style type='text/css'>@import url(" + url + ");</style>");
924
+ };
925
+ HTMLArea.loadStyle("htmlarea.css");
926
+
927
+ /***************************************************
928
+ * Category: EDITOR UTILITIES
929
+ ***************************************************/
930
+
931
+ // The following function is a slight variation of the word cleaner code posted
932
+ // by Weeezl (user @ InteractiveTools forums).
933
+ HTMLArea.prototype._wordClean = function() {
934
+ var D = this.getInnerHTML();
935
+ if (D.indexOf('class=Mso') >= 0) {
936
+
937
+ // make one line
938
+ D = D.replace(/\r\n/g, ' ').
939
+ replace(/\n/g, ' ').
940
+ replace(/\r/g, ' ').
941
+ replace(/\&nbsp\;/g,' ');
942
+
943
+ // keep tags, strip attributes
944
+ D = D.replace(/ class=[^\s|>]*/gi,'').
945
+ //replace(/<p [^>]*TEXT-ALIGN: justify[^>]*>/gi,'<p align="justify">').
946
+ replace(/ style=\"[^>]*\"/gi,'').
947
+ replace(/ align=[^\s|>]*/gi,'');
948
+
949
+ //clean up tags
950
+ D = D.replace(/<b [^>]*>/gi,'<b>').
951
+ replace(/<i [^>]*>/gi,'<i>').
952
+ replace(/<li [^>]*>/gi,'<li>').
953
+ replace(/<ul [^>]*>/gi,'<ul>');
954
+
955
+ // replace outdated tags
956
+ D = D.replace(/<b>/gi,'<strong>').
957
+ replace(/<\/b>/gi,'</strong>');
958
+
959
+ // mozilla doesn't like <em> tags
960
+ D = D.replace(/<em>/gi,'<i>').
961
+ replace(/<\/em>/gi,'</i>');
962
+
963
+ // kill unwanted tags
964
+ D = D.replace(/<\?xml:[^>]*>/g, ''). // Word xml
965
+ replace(/<\/?st1:[^>]*>/g,''). // Word SmartTags
966
+ replace(/<\/?[a-z]\:[^>]*>/g,''). // All other funny Word non-HTML stuff
967
+ replace(/<\/?font[^>]*>/gi,''). // Disable if you want to keep font formatting
968
+ replace(/<\/?span[^>]*>/gi,' ').
969
+ replace(/<\/?div[^>]*>/gi,' ').
970
+ replace(/<\/?pre[^>]*>/gi,' ').
971
+ replace(/<\/?h[1-6][^>]*>/gi,' ');
972
+
973
+ //remove empty tags
974
+ //D = D.replace(/<strong><\/strong>/gi,'').
975
+ //replace(/<i><\/i>/gi,'').
976
+ //replace(/<P[^>]*><\/P>/gi,'');
977
+
978
+ // nuke double tags
979
+ oldlen = D.length + 1;
980
+ while(oldlen > D.length) {
981
+ oldlen = D.length;
982
+ // join us now and free the tags, we'll be free hackers, we'll be free... ;-)
983
+ D = D.replace(/<([a-z][a-z]*)> *<\/\1>/gi,' ').
984
+ replace(/<([a-z][a-z]*)> *<([a-z][^>]*)> *<\/\1>/gi,'<$2>');
985
+ }
986
+ D = D.replace(/<([a-z][a-z]*)><\1>/gi,'<$1>').
987
+ replace(/<\/([a-z][a-z]*)><\/\1>/gi,'<\/$1>');
988
+
989
+ // nuke double spaces
990
+ D = D.replace(/ */gi,' ');
991
+
992
+ this.setHTML(D);
993
+ this.updateToolbar();
994
+ }
995
+ };
996
+
997
+ HTMLArea.prototype.forceRedraw = function() {
998
+ this._doc.body.style.visibility = "hidden";
999
+ this._doc.body.style.visibility = "visible";
1000
+ // this._doc.body.innerHTML = this.getInnerHTML();
1001
+ };
1002
+
1003
+ // focuses the iframe window. returns a reference to the editor document.
1004
+ HTMLArea.prototype.focusEditor = function() {
1005
+ switch (this._editMode) {
1006
+ case "wysiwyg" : this._iframe.contentWindow.focus(); break;
1007
+ case "textmode": this._textArea.focus(); break;
1008
+ default : alert("ERROR: mode " + this._editMode + " is not defined");
1009
+ }
1010
+ return this._doc;
1011
+ };
1012
+
1013
+ // takes a snapshot of the current text (for undo)
1014
+ HTMLArea.prototype._undoTakeSnapshot = function() {
1015
+ ++this._undoPos;
1016
+ if (this._undoPos >= this.config.undoSteps) {
1017
+ // remove the first element
1018
+ this._undoQueue.shift();
1019
+ --this._undoPos;
1020
+ }
1021
+ // use the fasted method (getInnerHTML);
1022
+ var take = true;
1023
+ var txt = this.getInnerHTML();
1024
+ if (this._undoPos > 0)
1025
+ take = (this._undoQueue[this._undoPos - 1] != txt);
1026
+ if (take) {
1027
+ this._undoQueue[this._undoPos] = txt;
1028
+ } else {
1029
+ this._undoPos--;
1030
+ }
1031
+ };
1032
+
1033
+ HTMLArea.prototype.undo = function() {
1034
+ if (this._undoPos > 0) {
1035
+ var txt = this._undoQueue[--this._undoPos];
1036
+ if (txt) this.setHTML(txt);
1037
+ else ++this._undoPos;
1038
+ }
1039
+ };
1040
+
1041
+ HTMLArea.prototype.redo = function() {
1042
+ if (this._undoPos < this._undoQueue.length - 1) {
1043
+ var txt = this._undoQueue[++this._undoPos];
1044
+ if (txt) this.setHTML(txt);
1045
+ else --this._undoPos;
1046
+ }
1047
+ };
1048
+
1049
+ // updates enabled/disable/active state of the toolbar elements
1050
+ HTMLArea.prototype.updateToolbar = function(noStatus) {
1051
+ var doc = this._doc;
1052
+ var text = (this._editMode == "textmode");
1053
+ var ancestors = null;
1054
+ if (!text) {
1055
+ ancestors = this.getAllAncestors();
1056
+ if (this.config.statusBar && !noStatus) {
1057
+ this._statusBarTree.innerHTML = HTMLArea.I18N.msg["Path"] + ": "; // clear
1058
+ for (var i = ancestors.length; --i >= 0;) {
1059
+ var el = ancestors[i];
1060
+ if (!el) {
1061
+ // hell knows why we get here; this
1062
+ // could be a classic example of why
1063
+ // it's good to check for conditions
1064
+ // that are impossible to happen ;-)
1065
+ continue;
1066
+ }
1067
+ var a = document.createElement("a");
1068
+ a.href = "#";
1069
+ a.el = el;
1070
+ a.editor = this;
1071
+ a.onclick = function() {
1072
+ this.blur();
1073
+ this.editor.selectNodeContents(this.el);
1074
+ this.editor.updateToolbar(true);
1075
+ return false;
1076
+ };
1077
+ a.oncontextmenu = function() {
1078
+ // TODO: add context menu here
1079
+ this.blur();
1080
+ var info = "Inline style:\n\n";
1081
+ info += this.el.style.cssText.split(/;\s*/).join(";\n");
1082
+ alert(info);
1083
+ return false;
1084
+ };
1085
+ var txt = el.tagName.toLowerCase();
1086
+ a.title = el.style.cssText;
1087
+ if (el.id) {
1088
+ txt += "#" + el.id;
1089
+ }
1090
+ if (el.className) {
1091
+ txt += "." + el.className;
1092
+ }
1093
+ a.appendChild(document.createTextNode(txt));
1094
+ this._statusBarTree.appendChild(a);
1095
+ if (i != 0) {
1096
+ this._statusBarTree.appendChild(document.createTextNode(String.fromCharCode(0xbb)));
1097
+ }
1098
+ }
1099
+ }
1100
+ }
1101
+ for (var i in this._toolbarObjects) {
1102
+ var btn = this._toolbarObjects[i];
1103
+ var cmd = i;
1104
+ var inContext = true;
1105
+ if (btn.context && !text) {
1106
+ inContext = false;
1107
+ var context = btn.context;
1108
+ var attrs = [];
1109
+ if (/(.*)\[(.*?)\]/.test(context)) {
1110
+ context = RegExp.$1;
1111
+ attrs = RegExp.$2.split(",");
1112
+ }
1113
+ context = context.toLowerCase();
1114
+ var match = (context == "*");
1115
+ for (var k in ancestors) {
1116
+ if (!ancestors[k]) {
1117
+ // the impossible really happens.
1118
+ continue;
1119
+ }
1120
+ if (match || (ancestors[k].tagName.toLowerCase() == context)) {
1121
+ inContext = true;
1122
+ for (var ka in attrs) {
1123
+ if (!eval("ancestors[k]." + attrs[ka])) {
1124
+ inContext = false;
1125
+ break;
1126
+ }
1127
+ }
1128
+ if (inContext) {
1129
+ break;
1130
+ }
1131
+ }
1132
+ }
1133
+ }
1134
+ btn.state("enabled", (!text || btn.text) && inContext);
1135
+ if (typeof cmd == "function") {
1136
+ continue;
1137
+ }
1138
+ // look-it-up in the custom dropdown boxes
1139
+ var dropdown = this.config.customSelects[cmd];
1140
+ if ((!text || btn.text) && (typeof dropdown != "undefined")) {
1141
+ dropdown.refresh(this);
1142
+ continue;
1143
+ }
1144
+ switch (cmd) {
1145
+ case "fontname":
1146
+ case "fontsize":
1147
+ case "formatblock":
1148
+ if (!text) try {
1149
+ var value = ("" + doc.queryCommandValue(cmd)).toLowerCase();
1150
+ if (!value) {
1151
+ // FIXME: what do we do here?
1152
+ break;
1153
+ }
1154
+ // HACK -- retrieve the config option for this
1155
+ // combo box. We rely on the fact that the
1156
+ // variable in config has the same name as
1157
+ // button name in the toolbar.
1158
+ var options = this.config[cmd];
1159
+ var k = 0;
1160
+ // btn.element.selectedIndex = 0;
1161
+ for (var j in options) {
1162
+ // FIXME: the following line is scary.
1163
+ if ((j.toLowerCase() == value) ||
1164
+ (options[j].substr(0, value.length).toLowerCase() == value)) {
1165
+ btn.element.selectedIndex = k;
1166
+ break;
1167
+ }
1168
+ ++k;
1169
+ }
1170
+ } catch(e) {};
1171
+ break;
1172
+ case "textindicator":
1173
+ if (!text) {
1174
+ try {with (btn.element.style) {
1175
+ backgroundColor = HTMLArea._makeColor(
1176
+ doc.queryCommandValue(HTMLArea.is_ie ? "backcolor" : "hilitecolor"));
1177
+ if (/transparent/i.test(backgroundColor)) {
1178
+ // Mozilla
1179
+ backgroundColor = HTMLArea._makeColor(doc.queryCommandValue("backcolor"));
1180
+ }
1181
+ color = HTMLArea._makeColor(doc.queryCommandValue("forecolor"));
1182
+ fontFamily = doc.queryCommandValue("fontname");
1183
+ fontWeight = doc.queryCommandState("bold") ? "bold" : "normal";
1184
+ fontStyle = doc.queryCommandState("italic") ? "italic" : "normal";
1185
+ }} catch (e) {
1186
+ // alert(e + "\n\n" + cmd);
1187
+ }
1188
+ }
1189
+ break;
1190
+ case "htmlmode": btn.state("active", text); break;
1191
+ case "lefttoright":
1192
+ case "righttoleft":
1193
+ var el = this.getParentElement();
1194
+ while (el && !HTMLArea.isBlockElement(el))
1195
+ el = el.parentNode;
1196
+ if (el)
1197
+ btn.state("active", (el.style.direction == ((cmd == "righttoleft") ? "rtl" : "ltr")));
1198
+ break;
1199
+ default:
1200
+ try {
1201
+ btn.state("active", (!text && doc.queryCommandState(cmd)));
1202
+ } catch (e) {}
1203
+ }
1204
+ }
1205
+ // take undo snapshots
1206
+ if (this._customUndo && !this._timerUndo) {
1207
+ this._undoTakeSnapshot();
1208
+ var editor = this;
1209
+ this._timerUndo = setTimeout(function() {
1210
+ editor._timerUndo = null;
1211
+ }, this.config.undoTimeout);
1212
+ }
1213
+ // check if any plugins have registered refresh handlers
1214
+ for (var i in this.plugins) {
1215
+ var plugin = this.plugins[i].instance;
1216
+ if (typeof plugin.onUpdateToolbar == "function")
1217
+ plugin.onUpdateToolbar();
1218
+ }
1219
+ };
1220
+
1221
+ /** Returns a node after which we can insert other nodes, in the current
1222
+ * selection. The selection is removed. It splits a text node, if needed.
1223
+ */
1224
+ HTMLArea.prototype.insertNodeAtSelection = function(toBeInserted) {
1225
+ if (!HTMLArea.is_ie) {
1226
+ var sel = this._getSelection();
1227
+ var range = this._createRange(sel);
1228
+ // remove the current selection
1229
+ sel.removeAllRanges();
1230
+ range.deleteContents();
1231
+ var node = range.startContainer;
1232
+ var pos = range.startOffset;
1233
+ switch (node.nodeType) {
1234
+ case 3: // Node.TEXT_NODE
1235
+ // we have to split it at the caret position.
1236
+ if (toBeInserted.nodeType == 3) {
1237
+ // do optimized insertion
1238
+ node.insertData(pos, toBeInserted.data);
1239
+ range = this._createRange();
1240
+ range.setEnd(node, pos + toBeInserted.length);
1241
+ range.setStart(node, pos + toBeInserted.length);
1242
+ sel.addRange(range);
1243
+ } else {
1244
+ node = node.splitText(pos);
1245
+ var selnode = toBeInserted;
1246
+ if (toBeInserted.nodeType == 11 /* Node.DOCUMENT_FRAGMENT_NODE */) {
1247
+ selnode = selnode.firstChild;
1248
+ }
1249
+ node.parentNode.insertBefore(toBeInserted, node);
1250
+ this.selectNodeContents(selnode);
1251
+ this.updateToolbar();
1252
+ }
1253
+ break;
1254
+ case 1: // Node.ELEMENT_NODE
1255
+ var selnode = toBeInserted;
1256
+ if (toBeInserted.nodeType == 11 /* Node.DOCUMENT_FRAGMENT_NODE */) {
1257
+ selnode = selnode.firstChild;
1258
+ }
1259
+ node.insertBefore(toBeInserted, node.childNodes[pos]);
1260
+ this.selectNodeContents(selnode);
1261
+ this.updateToolbar();
1262
+ break;
1263
+ }
1264
+ } else {
1265
+ return null; // this function not yet used for IE <FIXME>
1266
+ }
1267
+ };
1268
+
1269
+ // Returns the deepest node that contains both endpoints of the selection.
1270
+ HTMLArea.prototype.getParentElement = function() {
1271
+ var sel = this._getSelection();
1272
+ var range = this._createRange(sel);
1273
+ if (HTMLArea.is_ie) {
1274
+ switch (sel.type) {
1275
+ case "Text":
1276
+ case "None":
1277
+ // It seems that even for selection of type "None",
1278
+ // there _is_ a parent element and it's value is not
1279
+ // only correct, but very important to us. MSIE is
1280
+ // certainly the buggiest browser in the world and I
1281
+ // wonder, God, how can Earth stand it?
1282
+ return range.parentElement();
1283
+ case "Control":
1284
+ return range.item(0);
1285
+ default:
1286
+ return this._doc.body;
1287
+ }
1288
+ } else try {
1289
+ var p = range.commonAncestorContainer;
1290
+ if (!range.collapsed && range.startContainer == range.endContainer &&
1291
+ range.startOffset - range.endOffset <= 1 && range.startContainer.hasChildNodes())
1292
+ p = range.startContainer.childNodes[range.startOffset];
1293
+ /*
1294
+ alert(range.startContainer + ":" + range.startOffset + "\n" +
1295
+ range.endContainer + ":" + range.endOffset);
1296
+ */
1297
+ while (p.nodeType == 3) {
1298
+ p = p.parentNode;
1299
+ }
1300
+ return p;
1301
+ } catch (e) {
1302
+ return null;
1303
+ }
1304
+ };
1305
+
1306
+ // Returns an array with all the ancestor nodes of the selection.
1307
+ HTMLArea.prototype.getAllAncestors = function() {
1308
+ var p = this.getParentElement();
1309
+ var a = [];
1310
+ while (p && (p.nodeType == 1) && (p.tagName.toLowerCase() != 'body')) {
1311
+ a.push(p);
1312
+ p = p.parentNode;
1313
+ }
1314
+ a.push(this._doc.body);
1315
+ return a;
1316
+ };
1317
+
1318
+ // Selects the contents inside the given node
1319
+ HTMLArea.prototype.selectNodeContents = function(node, pos) {
1320
+ this.focusEditor();
1321
+ this.forceRedraw();
1322
+ var range;
1323
+ var collapsed = (typeof pos != "undefined");
1324
+ if (HTMLArea.is_ie) {
1325
+ range = this._doc.body.createTextRange();
1326
+ range.moveToElementText(node);
1327
+ (collapsed) && range.collapse(pos);
1328
+ range.select();
1329
+ } else {
1330
+ var sel = this._getSelection();
1331
+ range = this._doc.createRange();
1332
+ range.selectNodeContents(node);
1333
+ (collapsed) && range.collapse(pos);
1334
+ sel.removeAllRanges();
1335
+ sel.addRange(range);
1336
+ }
1337
+ };
1338
+
1339
+ /** Call this function to insert HTML code at the current position. It deletes
1340
+ * the selection, if any.
1341
+ */
1342
+ HTMLArea.prototype.insertHTML = function(html) {
1343
+ var sel = this._getSelection();
1344
+ var range = this._createRange(sel);
1345
+ if (HTMLArea.is_ie) {
1346
+ range.pasteHTML(html);
1347
+ } else {
1348
+ // construct a new document fragment with the given HTML
1349
+ var fragment = this._doc.createDocumentFragment();
1350
+ var div = this._doc.createElement("div");
1351
+ div.innerHTML = html;
1352
+ while (div.firstChild) {
1353
+ // the following call also removes the node from div
1354
+ fragment.appendChild(div.firstChild);
1355
+ }
1356
+ // this also removes the selection
1357
+ var node = this.insertNodeAtSelection(fragment);
1358
+ }
1359
+ };
1360
+
1361
+ /**
1362
+ * Call this function to surround the existing HTML code in the selection with
1363
+ * your tags. FIXME: buggy! This function will be deprecated "soon".
1364
+ */
1365
+ HTMLArea.prototype.surroundHTML = function(startTag, endTag) {
1366
+ var html = this.getSelectedHTML();
1367
+ // the following also deletes the selection
1368
+ this.insertHTML(startTag + html + endTag);
1369
+ };
1370
+
1371
+ /// Retrieve the selected block
1372
+ HTMLArea.prototype.getSelectedHTML = function() {
1373
+ var sel = this._getSelection();
1374
+ var range = this._createRange(sel);
1375
+ var existing = null;
1376
+ if (HTMLArea.is_ie) {
1377
+ existing = range.htmlText;
1378
+ } else {
1379
+ existing = HTMLArea.getHTML(range.cloneContents(), false, this);
1380
+ }
1381
+ return existing;
1382
+ };
1383
+
1384
+ /// Return true if we have some selection
1385
+ HTMLArea.prototype.hasSelectedText = function() {
1386
+ // FIXME: come _on_ mishoo, you can do better than this ;-)
1387
+ return this.getSelectedHTML() != '';
1388
+ };
1389
+
1390
+ HTMLArea.prototype._createLink = function(link) {
1391
+ var editor = this;
1392
+ var outparam = null;
1393
+ if (typeof link == "undefined") {
1394
+ link = this.getParentElement();
1395
+ if (link && !/^a$/i.test(link.tagName))
1396
+ link = null;
1397
+ }
1398
+ if (link) outparam = {
1399
+ f_href : HTMLArea.is_ie ? editor.stripBaseURL(link.href) : link.getAttribute("href"),
1400
+ f_title : link.title,
1401
+ f_target : link.target
1402
+ };
1403
+ this._popupDialog("link.html", function(param) {
1404
+ if (!param)
1405
+ return false;
1406
+ var a = link;
1407
+ if (!a) {
1408
+ editor._doc.execCommand("createlink", false, param.f_href);
1409
+ a = editor.getParentElement();
1410
+ var sel = editor._getSelection();
1411
+ var range = editor._createRange(sel);
1412
+ if (!HTMLArea.is_ie) {
1413
+ a = range.startContainer;
1414
+ if (!/^a$/i.test(a.tagName))
1415
+ a = a.nextSibling;
1416
+ }
1417
+ } else a.href = param.f_href.trim();
1418
+ if (!/^a$/i.test(a.tagName))
1419
+ return false;
1420
+ a.target = param.f_target.trim();
1421
+ a.title = param.f_title.trim();
1422
+ editor.selectNodeContents(a);
1423
+ editor.updateToolbar();
1424
+ }, outparam);
1425
+ };
1426
+
1427
+ // Called when the user clicks on "InsertImage" button. If an image is already
1428
+ // there, it will just modify it's properties.
1429
+ HTMLArea.prototype._insertImage = function(image) {
1430
+ var editor = this; // for nested functions
1431
+ var outparam = null;
1432
+ if (typeof image == "undefined") {
1433
+ image = this.getParentElement();
1434
+ if (image && !/^img$/i.test(image.tagName))
1435
+ image = null;
1436
+ }
1437
+ if (image) outparam = {
1438
+ f_url : HTMLArea.is_ie ? editor.stripBaseURL(image.src) : image.getAttribute("src"),
1439
+ f_alt : image.alt,
1440
+ f_border : image.border,
1441
+ f_align : image.align,
1442
+ f_vert : image.vspace,
1443
+ f_horiz : image.hspace
1444
+ };
1445
+ this._popupDialog("insert_image.html", function(param) {
1446
+ if (!param) { // user must have pressed Cancel
1447
+ return false;
1448
+ }
1449
+ var img = image;
1450
+ if (!img) {
1451
+ var sel = editor._getSelection();
1452
+ var range = editor._createRange(sel);
1453
+ editor._doc.execCommand("insertimage", false, param.f_url);
1454
+ if (HTMLArea.is_ie) {
1455
+ img = range.parentElement();
1456
+ // wonder if this works...
1457
+ if (img.tagName.toLowerCase() != "img") {
1458
+ img = img.previousSibling;
1459
+ }
1460
+ } else {
1461
+ img = range.startContainer.previousSibling;
1462
+ }
1463
+ } else {
1464
+ img.src = param.f_url;
1465
+ }
1466
+ for (field in param) {
1467
+ var value = param[field];
1468
+ switch (field) {
1469
+ case "f_alt" : img.alt = value; break;
1470
+ case "f_border" : img.border = parseInt(value || "0"); break;
1471
+ case "f_align" : img.align = value; break;
1472
+ case "f_vert" : img.vspace = parseInt(value || "0"); break;
1473
+ case "f_horiz" : img.hspace = parseInt(value || "0"); break;
1474
+ }
1475
+ }
1476
+ }, outparam);
1477
+ };
1478
+
1479
+ // Called when the user clicks the Insert Table button
1480
+ HTMLArea.prototype._insertTable = function() {
1481
+ var sel = this._getSelection();
1482
+ var range = this._createRange(sel);
1483
+ var editor = this; // for nested functions
1484
+ this._popupDialog("insert_table.html", function(param) {
1485
+ if (!param) { // user must have pressed Cancel
1486
+ return false;
1487
+ }
1488
+ var doc = editor._doc;
1489
+ // create the table element
1490
+ var table = doc.createElement("table");
1491
+ // assign the given arguments
1492
+ for (var field in param) {
1493
+ var value = param[field];
1494
+ if (!value) {
1495
+ continue;
1496
+ }
1497
+ switch (field) {
1498
+ case "f_width" : table.style.width = value + param["f_unit"]; break;
1499
+ case "f_align" : table.align = value; break;
1500
+ case "f_border" : table.border = parseInt(value); break;
1501
+ case "f_spacing" : table.cellspacing = parseInt(value); break;
1502
+ case "f_padding" : table.cellpadding = parseInt(value); break;
1503
+ }
1504
+ }
1505
+ var tbody = doc.createElement("tbody");
1506
+ table.appendChild(tbody);
1507
+ for (var i = 0; i < param["f_rows"]; ++i) {
1508
+ var tr = doc.createElement("tr");
1509
+ tbody.appendChild(tr);
1510
+ for (var j = 0; j < param["f_cols"]; ++j) {
1511
+ var td = doc.createElement("td");
1512
+ tr.appendChild(td);
1513
+ // Mozilla likes to see something inside the cell.
1514
+ (HTMLArea.is_gecko) && td.appendChild(doc.createElement("br"));
1515
+ }
1516
+ }
1517
+ if (HTMLArea.is_ie) {
1518
+ range.pasteHTML(table.outerHTML);
1519
+ } else {
1520
+ // insert the table
1521
+ editor.insertNodeAtSelection(table);
1522
+ }
1523
+ return true;
1524
+ }, null);
1525
+ };
1526
+
1527
+ /***************************************************
1528
+ * Category: EVENT HANDLERS
1529
+ ***************************************************/
1530
+
1531
+ // el is reference to the SELECT object
1532
+ // txt is the name of the select field, as in config.toolbar
1533
+ HTMLArea.prototype._comboSelected = function(el, txt) {
1534
+ this.focusEditor();
1535
+ var value = el.options[el.selectedIndex].value;
1536
+ switch (txt) {
1537
+ case "fontname":
1538
+ case "fontsize": this.execCommand(txt, false, value); break;
1539
+ case "formatblock":
1540
+ (HTMLArea.is_ie) && (value = "<" + value + ">");
1541
+ this.execCommand(txt, false, value);
1542
+ break;
1543
+ default:
1544
+ // try to look it up in the registered dropdowns
1545
+ var dropdown = this.config.customSelects[txt];
1546
+ if (typeof dropdown != "undefined") {
1547
+ dropdown.action(this);
1548
+ } else {
1549
+ alert("FIXME: combo box " + txt + " not implemented");
1550
+ }
1551
+ }
1552
+ };
1553
+
1554
+ // the execCommand function (intercepts some commands and replaces them with
1555
+ // our own implementation)
1556
+ HTMLArea.prototype.execCommand = function(cmdID, UI, param) {
1557
+ var editor = this; // for nested functions
1558
+ this.focusEditor();
1559
+ cmdID = cmdID.toLowerCase();
1560
+ switch (cmdID) {
1561
+ case "htmlmode" : this.setMode(); break;
1562
+ case "hilitecolor":
1563
+ (HTMLArea.is_ie) && (cmdID = "backcolor");
1564
+ case "forecolor":
1565
+ this._popupDialog("select_color.html", function(color) {
1566
+ if (color) { // selection not canceled
1567
+ editor._doc.execCommand(cmdID, false, "#" + color);
1568
+ }
1569
+ }, HTMLArea._colorToRgb(this._doc.queryCommandValue(cmdID)));
1570
+ break;
1571
+ case "createlink":
1572
+ this._createLink();
1573
+ break;
1574
+ case "popupeditor":
1575
+ // this object will be passed to the newly opened window
1576
+ HTMLArea._object = this;
1577
+ if (HTMLArea.is_ie) {
1578
+ //if (confirm(HTMLArea.I18N.msg["IE-sucks-full-screen"]))
1579
+ {
1580
+ window.open(this.popupURL("fullscreen.html"), "ha_fullscreen",
1581
+ "toolbar=no,location=no,directories=no,status=no,menubar=no," +
1582
+ "scrollbars=no,resizable=yes,width=640,height=480");
1583
+ }
1584
+ } else {
1585
+ window.open(this.popupURL("fullscreen.html"), "ha_fullscreen",
1586
+ "toolbar=no,menubar=no,personalbar=no,width=640,height=480," +
1587
+ "scrollbars=no,resizable=yes");
1588
+ }
1589
+ break;
1590
+ case "undo":
1591
+ case "redo":
1592
+ if (this._customUndo)
1593
+ this[cmdID]();
1594
+ else
1595
+ this._doc.execCommand(cmdID, UI, param);
1596
+ break;
1597
+ case "inserttable": this._insertTable(); break;
1598
+ case "insertimage": this._insertImage(); break;
1599
+ case "about" : this._popupDialog("about.html", null, this); break;
1600
+ case "showhelp" : window.open(_editor_url + "reference.html", "ha_help"); break;
1601
+
1602
+ case "killword": this._wordClean(); break;
1603
+
1604
+ case "cut":
1605
+ case "copy":
1606
+ case "paste":
1607
+ try {
1608
+ if (this.config.killWordOnPaste)
1609
+ this._wordClean();
1610
+ this._doc.execCommand(cmdID, UI, param);
1611
+ } catch (e) {
1612
+ if (HTMLArea.is_gecko) {
1613
+ if (confirm("Unprivileged scripts cannot access Cut/Copy/Paste programatically " +
1614
+ "for security reasons. Click OK to see a technical note at mozilla.org " +
1615
+ "which shows you how to allow a script to access the clipboard."))
1616
+ window.open("http://mozilla.org/editor/midasdemo/securityprefs.html");
1617
+ }
1618
+ }
1619
+ break;
1620
+ case "lefttoright":
1621
+ case "righttoleft":
1622
+ var dir = (cmdID == "righttoleft") ? "rtl" : "ltr";
1623
+ var el = this.getParentElement();
1624
+ while (el && !HTMLArea.isBlockElement(el))
1625
+ el = el.parentNode;
1626
+ if (el) {
1627
+ if (el.style.direction == dir)
1628
+ el.style.direction = "";
1629
+ else
1630
+ el.style.direction = dir;
1631
+ }
1632
+ break;
1633
+ default: this._doc.execCommand(cmdID, UI, param);
1634
+ }
1635
+ this.updateToolbar();
1636
+ return false;
1637
+ };
1638
+
1639
+ /** A generic event handler for things that happen in the IFRAME's document.
1640
+ * This function also handles key bindings. */
1641
+ HTMLArea.prototype._editorEvent = function(ev) {
1642
+ var editor = this;
1643
+ var keyEvent = (HTMLArea.is_ie && ev.type == "keydown") || (ev.type == "keypress");
1644
+ if (keyEvent) {
1645
+ for (var i in editor.plugins) {
1646
+ var plugin = editor.plugins[i].instance;
1647
+ if (typeof plugin.onKeyPress == "function") plugin.onKeyPress(ev);
1648
+ }
1649
+ }
1650
+ if (keyEvent && ev.ctrlKey) {
1651
+ var sel = null;
1652
+ var range = null;
1653
+ var key = String.fromCharCode(HTMLArea.is_ie ? ev.keyCode : ev.charCode).toLowerCase();
1654
+ var cmd = null;
1655
+ var value = null;
1656
+ switch (key) {
1657
+ case 'a':
1658
+ if (!HTMLArea.is_ie) {
1659
+ // KEY select all
1660
+ sel = this._getSelection();
1661
+ sel.removeAllRanges();
1662
+ range = this._createRange();
1663
+ range.selectNodeContents(this._doc.body);
1664
+ sel.addRange(range);
1665
+ HTMLArea._stopEvent(ev);
1666
+ }
1667
+ break;
1668
+
1669
+ // simple key commands follow
1670
+
1671
+ case 'b': cmd = "bold"; break;
1672
+ case 'i': cmd = "italic"; break;
1673
+ case 'u': cmd = "underline"; break;
1674
+ case 's': cmd = "strikethrough"; break;
1675
+ case 'l': cmd = "justifyleft"; break;
1676
+ case 'e': cmd = "justifycenter"; break;
1677
+ case 'r': cmd = "justifyright"; break;
1678
+ case 'j': cmd = "justifyfull"; break;
1679
+ case 'z': cmd = "undo"; break;
1680
+ case 'y': cmd = "redo"; break;
1681
+ case 'v': cmd = "paste"; break;
1682
+
1683
+ case '0': cmd = "killword"; break;
1684
+
1685
+ // headings
1686
+ case '1':
1687
+ case '2':
1688
+ case '3':
1689
+ case '4':
1690
+ case '5':
1691
+ case '6':
1692
+ cmd = "formatblock";
1693
+ value = "h" + key;
1694
+ if (HTMLArea.is_ie) {
1695
+ value = "<" + value + ">";
1696
+ }
1697
+ break;
1698
+ }
1699
+ if (cmd) {
1700
+ // execute simple command
1701
+ this.execCommand(cmd, false, value);
1702
+ HTMLArea._stopEvent(ev);
1703
+ }
1704
+ }
1705
+ /*
1706
+ else if (keyEvent) {
1707
+ // other keys here
1708
+ switch (ev.keyCode) {
1709
+ case 13: // KEY enter
1710
+ // if (HTMLArea.is_ie) {
1711
+ this.insertHTML("<br />");
1712
+ HTMLArea._stopEvent(ev);
1713
+ // }
1714
+ break;
1715
+ }
1716
+ }
1717
+ */
1718
+ // update the toolbar state after some time
1719
+ if (editor._timerToolbar) {
1720
+ clearTimeout(editor._timerToolbar);
1721
+ }
1722
+ editor._timerToolbar = setTimeout(function() {
1723
+ editor.updateToolbar();
1724
+ editor._timerToolbar = null;
1725
+ }, 50);
1726
+ };
1727
+
1728
+ // retrieve the HTML
1729
+ HTMLArea.prototype.getHTML = function() {
1730
+ switch (this._editMode) {
1731
+ case "wysiwyg" :
1732
+ if (!this.config.fullPage) {
1733
+ return HTMLArea.getHTML(this._doc.body, false, this);
1734
+ } else
1735
+ return this.doctype + "\n" + HTMLArea.getHTML(this._doc.documentElement, true, this);
1736
+ case "textmode" : return this._textArea.value;
1737
+ default : alert("Mode <" + mode + "> not defined!");
1738
+ }
1739
+ return false;
1740
+ };
1741
+
1742
+ // retrieve the HTML (fastest version, but uses innerHTML)
1743
+ HTMLArea.prototype.getInnerHTML = function() {
1744
+ switch (this._editMode) {
1745
+ case "wysiwyg" :
1746
+ if (!this.config.fullPage)
1747
+ return this._doc.body.innerHTML;
1748
+ else
1749
+ return this.doctype + "\n" + this._doc.documentElement.innerHTML;
1750
+ case "textmode" : return this._textArea.value;
1751
+ default : alert("Mode <" + mode + "> not defined!");
1752
+ }
1753
+ return false;
1754
+ };
1755
+
1756
+ // completely change the HTML inside
1757
+ HTMLArea.prototype.setHTML = function(html) {
1758
+ switch (this._editMode) {
1759
+ case "wysiwyg" :
1760
+ if (!this.config.fullPage)
1761
+ this._doc.body.innerHTML = html;
1762
+ else
1763
+ // this._doc.documentElement.innerHTML = html;
1764
+ this._doc.body.innerHTML = html;
1765
+ break;
1766
+ case "textmode" : this._textArea.value = html; break;
1767
+ default : alert("Mode <" + mode + "> not defined!");
1768
+ }
1769
+ return false;
1770
+ };
1771
+
1772
+ // sets the given doctype (useful when config.fullPage is true)
1773
+ HTMLArea.prototype.setDoctype = function(doctype) {
1774
+ this.doctype = doctype;
1775
+ };
1776
+
1777
+ /***************************************************
1778
+ * Category: UTILITY FUNCTIONS
1779
+ ***************************************************/
1780
+
1781
+ // browser identification
1782
+
1783
+ HTMLArea.agt = navigator.userAgent.toLowerCase();
1784
+ HTMLArea.is_ie = ((HTMLArea.agt.indexOf("msie") != -1) && (HTMLArea.agt.indexOf("opera") == -1));
1785
+ HTMLArea.is_opera = (HTMLArea.agt.indexOf("opera") != -1);
1786
+ HTMLArea.is_mac = (HTMLArea.agt.indexOf("mac") != -1);
1787
+ HTMLArea.is_mac_ie = (HTMLArea.is_ie && HTMLArea.is_mac);
1788
+ HTMLArea.is_win_ie = (HTMLArea.is_ie && !HTMLArea.is_mac);
1789
+ HTMLArea.is_gecko = (navigator.product == "Gecko");
1790
+
1791
+ // variable used to pass the object to the popup editor window.
1792
+ HTMLArea._object = null;
1793
+
1794
+ // function that returns a clone of the given object
1795
+ HTMLArea.cloneObject = function(obj) {
1796
+ var newObj = new Object;
1797
+
1798
+ // check for array objects
1799
+ if (obj.constructor.toString().indexOf("function Array(") == 1) {
1800
+ newObj = obj.constructor();
1801
+ }
1802
+
1803
+ // check for function objects (as usual, IE is fucked up)
1804
+ if (obj.constructor.toString().indexOf("function Function(") == 1) {
1805
+ newObj = obj; // just copy reference to it
1806
+ } else for (var n in obj) {
1807
+ var node = obj[n];
1808
+ if (typeof node == 'object') { newObj[n] = HTMLArea.cloneObject(node); }
1809
+ else { newObj[n] = node; }
1810
+ }
1811
+
1812
+ return newObj;
1813
+ };
1814
+
1815
+ // FIXME!!! this should return false for IE < 5.5
1816
+ HTMLArea.checkSupportedBrowser = function() {
1817
+ if (HTMLArea.is_gecko) {
1818
+ if (navigator.productSub < 20021201) {
1819
+ alert("You need at least Mozilla-1.3 Alpha.\n" +
1820
+ "Sorry, your Gecko is not supported.");
1821
+ return false;
1822
+ }
1823
+ if (navigator.productSub < 20030210) {
1824
+ alert("Mozilla < 1.3 Beta is not supported!\n" +
1825
+ "I'll try, though, but it might not work.");
1826
+ }
1827
+ }
1828
+ return HTMLArea.is_gecko || HTMLArea.is_ie;
1829
+ };
1830
+
1831
+ // selection & ranges
1832
+
1833
+ // returns the current selection object
1834
+ HTMLArea.prototype._getSelection = function() {
1835
+ if (HTMLArea.is_ie) {
1836
+ return this._doc.selection;
1837
+ } else {
1838
+ return this._iframe.contentWindow.getSelection();
1839
+ }
1840
+ };
1841
+
1842
+ // returns a range for the current selection
1843
+ HTMLArea.prototype._createRange = function(sel) {
1844
+ if (HTMLArea.is_ie) {
1845
+ return sel.createRange();
1846
+ } else {
1847
+ this.focusEditor();
1848
+ if (typeof sel != "undefined") {
1849
+ try {
1850
+ return sel.getRangeAt(0);
1851
+ } catch(e) {
1852
+ return this._doc.createRange();
1853
+ }
1854
+ } else {
1855
+ return this._doc.createRange();
1856
+ }
1857
+ }
1858
+ };
1859
+
1860
+ // event handling
1861
+
1862
+ HTMLArea._addEvent = function(el, evname, func) {
1863
+ if (HTMLArea.is_ie) {
1864
+ el.attachEvent("on" + evname, func);
1865
+ } else {
1866
+ el.addEventListener(evname, func, true);
1867
+ }
1868
+ };
1869
+
1870
+ HTMLArea._addEvents = function(el, evs, func) {
1871
+ for (var i in evs) {
1872
+ HTMLArea._addEvent(el, evs[i], func);
1873
+ }
1874
+ };
1875
+
1876
+ HTMLArea._removeEvent = function(el, evname, func) {
1877
+ if (HTMLArea.is_ie) {
1878
+ el.detachEvent("on" + evname, func);
1879
+ } else {
1880
+ el.removeEventListener(evname, func, true);
1881
+ }
1882
+ };
1883
+
1884
+ HTMLArea._removeEvents = function(el, evs, func) {
1885
+ for (var i in evs) {
1886
+ HTMLArea._removeEvent(el, evs[i], func);
1887
+ }
1888
+ };
1889
+
1890
+ HTMLArea._stopEvent = function(ev) {
1891
+ if (HTMLArea.is_ie) {
1892
+ ev.cancelBubble = true;
1893
+ ev.returnValue = false;
1894
+ } else {
1895
+ ev.preventDefault();
1896
+ ev.stopPropagation();
1897
+ }
1898
+ };
1899
+
1900
+ HTMLArea._removeClass = function(el, className) {
1901
+ if (!(el && el.className)) {
1902
+ return;
1903
+ }
1904
+ var cls = el.className.split(" ");
1905
+ var ar = new Array();
1906
+ for (var i = cls.length; i > 0;) {
1907
+ if (cls[--i] != className) {
1908
+ ar[ar.length] = cls[i];
1909
+ }
1910
+ }
1911
+ el.className = ar.join(" ");
1912
+ };
1913
+
1914
+ HTMLArea._addClass = function(el, className) {
1915
+ // remove the class first, if already there
1916
+ HTMLArea._removeClass(el, className);
1917
+ el.className += " " + className;
1918
+ };
1919
+
1920
+ HTMLArea._hasClass = function(el, className) {
1921
+ if (!(el && el.className)) {
1922
+ return false;
1923
+ }
1924
+ var cls = el.className.split(" ");
1925
+ for (var i = cls.length; i > 0;) {
1926
+ if (cls[--i] == className) {
1927
+ return true;
1928
+ }
1929
+ }
1930
+ return false;
1931
+ };
1932
+
1933
+ HTMLArea.isBlockElement = function(el) {
1934
+ var blockTags = " body form textarea fieldset ul ol dl li div " +
1935
+ "p h1 h2 h3 h4 h5 h6 quote pre table thead " +
1936
+ "tbody tfoot tr td iframe address ";
1937
+ return (blockTags.indexOf(" " + el.tagName.toLowerCase() + " ") != -1);
1938
+ };
1939
+
1940
+ HTMLArea.needsClosingTag = function(el) {
1941
+ var closingTags = " head script style div span tr td tbody table em strong font a title ";
1942
+ return (closingTags.indexOf(" " + el.tagName.toLowerCase() + " ") != -1);
1943
+ };
1944
+
1945
+ // performs HTML encoding of some given string
1946
+ HTMLArea.htmlEncode = function(str) {
1947
+ // we don't need regexp for that, but.. so be it for now.
1948
+ str = str.replace(/&/ig, "&amp;");
1949
+ str = str.replace(/</ig, "&lt;");
1950
+ str = str.replace(/>/ig, "&gt;");
1951
+ str = str.replace(/\x22/ig, "&quot;");
1952
+ // \x22 means '"' -- we use hex reprezentation so that we don't disturb
1953
+ // JS compressors (well, at least mine fails.. ;)
1954
+ return str;
1955
+ };
1956
+
1957
+ // Retrieves the HTML code from the given node. This is a replacement for
1958
+ // getting innerHTML, using standard DOM calls.
1959
+ HTMLArea.getHTML = function(root, outputRoot, editor) {
1960
+ var html = "";
1961
+ switch (root.nodeType) {
1962
+ case 1: // Node.ELEMENT_NODE
1963
+ case 11: // Node.DOCUMENT_FRAGMENT_NODE
1964
+ var closed;
1965
+ var i;
1966
+ var root_tag = (root.nodeType == 1) ? root.tagName.toLowerCase() : '';
1967
+ if (HTMLArea.is_ie && root_tag == "head") {
1968
+ if (outputRoot)
1969
+ html += "<head>";
1970
+ // lowercasize
1971
+ var save_multiline = RegExp.multiline;
1972
+ RegExp.multiline = true;
1973
+ var txt = root.innerHTML.replace(HTMLArea.RE_tagName, function(str, p1, p2) {
1974
+ return p1 + p2.toLowerCase();
1975
+ });
1976
+ RegExp.multiline = save_multiline;
1977
+ html += txt;
1978
+ if (outputRoot)
1979
+ html += "</head>";
1980
+ break;
1981
+ } else if (outputRoot) {
1982
+ closed = (!(root.hasChildNodes() || HTMLArea.needsClosingTag(root)));
1983
+ html = "<" + root.tagName.toLowerCase();
1984
+ var attrs = root.attributes;
1985
+ for (i = 0; i < attrs.length; ++i) {
1986
+ var a = attrs.item(i);
1987
+ if (!a.specified) {
1988
+ continue;
1989
+ }
1990
+ var name = a.nodeName.toLowerCase();
1991
+ if (/_moz|contenteditable|_msh/.test(name)) {
1992
+ // avoid certain attributes
1993
+ continue;
1994
+ }
1995
+ var value;
1996
+ if (name != "style") {
1997
+ // IE5.5 reports 25 when cellSpacing is
1998
+ // 1; other values might be doomed too.
1999
+ // For this reason we extract the
2000
+ // values directly from the root node.
2001
+ // I'm starting to HATE JavaScript
2002
+ // development. Browser differences
2003
+ // suck.
2004
+ //
2005
+ // Using Gecko the values of href and src are converted to absolute links
2006
+ // unless we get them using nodeValue()
2007
+ if (typeof root[a.nodeName] != "undefined" && name != "href" && name != "src") {
2008
+ value = root[a.nodeName];
2009
+ } else {
2010
+ value = a.nodeValue;
2011
+ // IE seems not willing to return the original values - it converts to absolute
2012
+ // links using a.nodeValue, a.value, a.stringValue, root.getAttribute("href")
2013
+ // So we have to strip the baseurl manually -/
2014
+ if (HTMLArea.is_ie && (name == "href" || name == "src")) {
2015
+ value = editor.stripBaseURL(value);
2016
+ }
2017
+ }
2018
+ } else { // IE fails to put style in attributes list
2019
+ // FIXME: cssText reported by IE is UPPERCASE
2020
+ value = root.style.cssText;
2021
+ }
2022
+ if (/(_moz|^$)/.test(value)) {
2023
+ // Mozilla reports some special tags
2024
+ // here; we don't need them.
2025
+ continue;
2026
+ }
2027
+ html += " " + name + '="' + value + '"';
2028
+ }
2029
+ html += closed ? " />" : ">";
2030
+ }
2031
+ for (i = root.firstChild; i; i = i.nextSibling) {
2032
+ html += HTMLArea.getHTML(i, true, editor);
2033
+ }
2034
+ if (outputRoot && !closed) {
2035
+ html += "</" + root.tagName.toLowerCase() + ">";
2036
+ }
2037
+ break;
2038
+ case 3: // Node.TEXT_NODE
2039
+ // If a text node is alone in an element and all spaces, replace it with an non breaking one
2040
+ // This partially undoes the damage done by moz, which translates '&nbsp;'s into spaces in the data element
2041
+ if ( !root.previousSibling && !root.nextSibling && root.data.match(/^\s*$/i) ) html = '&nbsp;';
2042
+ else html = HTMLArea.htmlEncode(root.data);
2043
+ break;
2044
+ case 8: // Node.COMMENT_NODE
2045
+ html = "<!--" + root.data + "-->";
2046
+ break; // skip comments, for now.
2047
+ }
2048
+ return html;
2049
+ };
2050
+
2051
+ HTMLArea.prototype.stripBaseURL = function(string) {
2052
+ var baseurl = this.config.baseURL;
2053
+
2054
+ // strip to last directory in case baseurl points to a file
2055
+ baseurl = baseurl.replace(/[^\/]+$/, '');
2056
+ var basere = new RegExp(baseurl);
2057
+ string = string.replace(basere, "");
2058
+
2059
+ // strip host-part of URL which is added by MSIE to links relative to server root
2060
+ baseurl = baseurl.replace(/^(https?:\/\/[^\/]+)(.*)$/, '$1');
2061
+ basere = new RegExp(baseurl);
2062
+ return string.replace(basere, "");
2063
+ };
2064
+
2065
+ String.prototype.trim = function() {
2066
+ a = this.replace(/^\s+/, '');
2067
+ return a.replace(/\s+$/, '');
2068
+ };
2069
+
2070
+ // creates a rgb-style color from a number
2071
+ HTMLArea._makeColor = function(v) {
2072
+ if (typeof v != "number") {
2073
+ // already in rgb (hopefully); IE doesn't get here.
2074
+ return v;
2075
+ }
2076
+ // IE sends number; convert to rgb.
2077
+ var r = v & 0xFF;
2078
+ var g = (v >> 8) & 0xFF;
2079
+ var b = (v >> 16) & 0xFF;
2080
+ return "rgb(" + r + "," + g + "," + b + ")";
2081
+ };
2082
+
2083
+ // returns hexadecimal color representation from a number or a rgb-style color.
2084
+ HTMLArea._colorToRgb = function(v) {
2085
+ if (!v)
2086
+ return '';
2087
+
2088
+ // returns the hex representation of one byte (2 digits)
2089
+ function hex(d) {
2090
+ return (d < 16) ? ("0" + d.toString(16)) : d.toString(16);
2091
+ };
2092
+
2093
+ if (typeof v == "number") {
2094
+ // we're talking to IE here
2095
+ var r = v & 0xFF;
2096
+ var g = (v >> 8) & 0xFF;
2097
+ var b = (v >> 16) & 0xFF;
2098
+ return "#" + hex(r) + hex(g) + hex(b);
2099
+ }
2100
+
2101
+ if (v.substr(0, 3) == "rgb") {
2102
+ // in rgb(...) form -- Mozilla
2103
+ var re = /rgb\s*\(\s*([0-9]+)\s*,\s*([0-9]+)\s*,\s*([0-9]+)\s*\)/;
2104
+ if (v.match(re)) {
2105
+ var r = parseInt(RegExp.$1);
2106
+ var g = parseInt(RegExp.$2);
2107
+ var b = parseInt(RegExp.$3);
2108
+ return "#" + hex(r) + hex(g) + hex(b);
2109
+ }
2110
+ // doesn't match RE?! maybe uses percentages or float numbers
2111
+ // -- FIXME: not yet implemented.
2112
+ return null;
2113
+ }
2114
+
2115
+ if (v.substr(0, 1) == "#") {
2116
+ // already hex rgb (hopefully :D )
2117
+ return v;
2118
+ }
2119
+
2120
+ // if everything else fails ;)
2121
+ return null;
2122
+ };
2123
+
2124
+ // modal dialogs for Mozilla (for IE we're using the showModalDialog() call).
2125
+
2126
+ // receives an URL to the popup dialog and a function that receives one value;
2127
+ // this function will get called after the dialog is closed, with the return
2128
+ // value of the dialog.
2129
+ HTMLArea.prototype._popupDialog = function(url, action, init) {
2130
+ Dialog(this.popupURL(url), action, init);
2131
+ };
2132
+
2133
+ // paths
2134
+
2135
+ HTMLArea.prototype.imgURL = function(file, plugin) {
2136
+ if (typeof plugin == "undefined")
2137
+ return _editor_url + file;
2138
+ else
2139
+ return _editor_url + "plugins/" + plugin + "/img/" + file;
2140
+ };
2141
+
2142
+ HTMLArea.prototype.popupURL = function(file) {
2143
+ var url = "";
2144
+ if (file.match(/^plugin:\/\/(.*?)\/(.*)/)) {
2145
+ var plugin = RegExp.$1;
2146
+ var popup = RegExp.$2;
2147
+ if (!/\.html$/.test(popup))
2148
+ popup += ".html";
2149
+ url = _editor_url + "plugins/" + plugin + "/popups/" + popup;
2150
+ } else
2151
+ url = _editor_url + this.config.popupURL + file;
2152
+ return url;
2153
+ };
2154
+
2155
+ /**
2156
+ * FIX: Internet Explorer returns an item having the _name_ equal to the given
2157
+ * id, even if it's not having any id. This way it can return a different form
2158
+ * field even if it's not a textarea. This workarounds the problem by
2159
+ * specifically looking to search only elements having a certain tag name.
2160
+ */
2161
+ HTMLArea.getElementById = function(tag, id) {
2162
+ var el, i, objs = document.getElementsByTagName(tag);
2163
+ for (i = objs.length; --i >= 0 && (el = objs[i]);)
2164
+ if (el.id == id)
2165
+ return el;
2166
+ return null;
2167
+ };
2168
+
2169
+
2170
+
2171
+ // EOF
2172
+ // Local variables: //
2173
+ // c-basic-offset:8 //
2174
+ // indent-tabs-mode:t //
2175
+ // End: //