narf 0.5.1

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