narf 0.5.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/ChangeLog +163 -0
- data/InstalledFiles +2227 -0
- data/README +124 -0
- data/TODO +88 -0
- data/bin/narftest +17 -0
- data/bug.rb +9 -0
- data/build.rb +314 -0
- data/build.rb~ +314 -0
- data/config.save +12 -0
- data/doc/apache_cgi.txt +17 -0
- data/doc/fastcgi.txt +19 -0
- data/doc/mod_ruby.txt +7 -0
- data/doc/rdoc/classes/Web.html +366 -0
- data/doc/rdoc/classes/Web.src/M000002.html +15 -0
- data/doc/rdoc/classes/Web.src/M000003.html +15 -0
- data/doc/rdoc/classes/Web.src/M000004.html +15 -0
- data/doc/rdoc/classes/Web.src/M000005.html +15 -0
- data/doc/rdoc/classes/Web.src/M000006.html +20 -0
- data/doc/rdoc/classes/Web.src/M000007.html +18 -0
- data/doc/rdoc/classes/Web.src/M000008.html +18 -0
- data/doc/rdoc/classes/Web.src/M000009.html +18 -0
- data/doc/rdoc/classes/Web.src/M000010.html +15 -0
- data/doc/rdoc/classes/Web.src/M000011.html +15 -0
- data/doc/rdoc/classes/Web.src/M000012.html +15 -0
- data/doc/rdoc/classes/Web/CGD.html +173 -0
- data/doc/rdoc/classes/Web/CGD.src/M000037.html +24 -0
- data/doc/rdoc/classes/Web/CGD.src/M000038.html +23 -0
- data/doc/rdoc/classes/Web/CGD.src/M000039.html +15 -0
- data/doc/rdoc/classes/Web/CGD.src/M000040.html +15 -0
- data/doc/rdoc/classes/Web/CGD.src/M000041.html +23 -0
- data/doc/rdoc/classes/Web/CGI.html +946 -0
- data/doc/rdoc/classes/Web/CGI.src/M000051.html +15 -0
- data/doc/rdoc/classes/Web/CGI.src/M000052.html +24 -0
- data/doc/rdoc/classes/Web/CGI.src/M000053.html +15 -0
- data/doc/rdoc/classes/Web/CGI.src/M000054.html +15 -0
- data/doc/rdoc/classes/Web/CGI.src/M000055.html +15 -0
- data/doc/rdoc/classes/Web/CGI.src/M000056.html +15 -0
- data/doc/rdoc/classes/Web/CGI.src/M000057.html +17 -0
- data/doc/rdoc/classes/Web/CGI.src/M000058.html +34 -0
- data/doc/rdoc/classes/Web/CGI.src/M000059.html +22 -0
- data/doc/rdoc/classes/Web/CGI.src/M000060.html +15 -0
- data/doc/rdoc/classes/Web/CGI.src/M000061.html +15 -0
- data/doc/rdoc/classes/Web/CGI.src/M000062.html +19 -0
- data/doc/rdoc/classes/Web/CGI.src/M000063.html +18 -0
- data/doc/rdoc/classes/Web/CGI.src/M000064.html +19 -0
- data/doc/rdoc/classes/Web/CGI.src/M000065.html +15 -0
- data/doc/rdoc/classes/Web/CGI.src/M000066.html +15 -0
- data/doc/rdoc/classes/Web/CGI.src/M000067.html +15 -0
- data/doc/rdoc/classes/Web/CGI.src/M000068.html +13 -0
- data/doc/rdoc/classes/Web/CGI.src/M000069.html +13 -0
- data/doc/rdoc/classes/Web/CGI.src/M000070.html +13 -0
- data/doc/rdoc/classes/Web/CGI.src/M000071.html +13 -0
- data/doc/rdoc/classes/Web/CGI.src/M000072.html +19 -0
- data/doc/rdoc/classes/Web/CGI.src/M000073.html +15 -0
- data/doc/rdoc/classes/Web/CGI.src/M000074.html +19 -0
- data/doc/rdoc/classes/Web/CGI.src/M000075.html +15 -0
- data/doc/rdoc/classes/Web/CGI.src/M000076.html +15 -0
- data/doc/rdoc/classes/Web/CGI.src/M000077.html +15 -0
- data/doc/rdoc/classes/Web/CGI.src/M000078.html +20 -0
- data/doc/rdoc/classes/Web/CGI.src/M000079.html +36 -0
- data/doc/rdoc/classes/Web/CGI.src/M000080.html +19 -0
- data/doc/rdoc/classes/Web/CGI.src/M000081.html +18 -0
- data/doc/rdoc/classes/Web/CGI.src/M000082.html +15 -0
- data/doc/rdoc/classes/Web/CGI.src/M000083.html +17 -0
- data/doc/rdoc/classes/Web/CGI.src/M000084.html +15 -0
- data/doc/rdoc/classes/Web/CGI.src/M000085.html +16 -0
- data/doc/rdoc/classes/Web/CGI.src/M000086.html +15 -0
- data/doc/rdoc/classes/Web/CGI.src/M000087.html +15 -0
- data/doc/rdoc/classes/Web/CGI.src/M000088.html +15 -0
- data/doc/rdoc/classes/Web/CGI.src/M000089.html +16 -0
- data/doc/rdoc/classes/Web/CGI.src/M000090.html +15 -0
- data/doc/rdoc/classes/Web/CGI.src/M000091.html +15 -0
- data/doc/rdoc/classes/Web/CGI.src/M000092.html +15 -0
- data/doc/rdoc/classes/Web/CGI.src/M000093.html +15 -0
- data/doc/rdoc/classes/Web/CGI.src/M000094.html +15 -0
- data/doc/rdoc/classes/Web/CGI.src/M000095.html +15 -0
- data/doc/rdoc/classes/Web/CGI.src/M000096.html +19 -0
- data/doc/rdoc/classes/Web/CGI.src/M000097.html +15 -0
- data/doc/rdoc/classes/Web/CGI.src/M000098.html +15 -0
- data/doc/rdoc/classes/Web/CGI.src/M000099.html +43 -0
- data/doc/rdoc/classes/Web/CGI.src/M000100.html +18 -0
- data/doc/rdoc/classes/Web/CGI.src/M000101.html +20 -0
- data/doc/rdoc/classes/Web/CGI.src/M000102.html +15 -0
- data/doc/rdoc/classes/Web/CGI.src/M000103.html +15 -0
- data/doc/rdoc/classes/Web/CGI.src/M000104.html +15 -0
- data/doc/rdoc/classes/Web/CGI.src/M000105.html +24 -0
- data/doc/rdoc/classes/Web/CGI.src/M000106.html +24 -0
- data/doc/rdoc/classes/Web/CGI.src/M000107.html +22 -0
- data/doc/rdoc/classes/Web/CaseInsensitiveHash.html +104 -0
- data/doc/rdoc/classes/Web/CaseInsensitiveHash.src/M000118.html +15 -0
- data/doc/rdoc/classes/Web/CaseInsensitiveHash.src/M000119.html +15 -0
- data/doc/rdoc/classes/Web/CaseInsensitiveHash.src/M000120.html +15 -0
- data/doc/rdoc/classes/Web/Mime.html +122 -0
- data/doc/rdoc/classes/Web/Mime.src/M000118.html +15 -0
- data/doc/rdoc/classes/Web/Mime.src/M000119.html +15 -0
- data/doc/rdoc/classes/Web/Mime.src/M000120.html +23 -0
- data/doc/rdoc/classes/Web/Mime.src/M000121.html +15 -0
- data/doc/rdoc/classes/Web/Mime.src/M000122.html +15 -0
- data/doc/rdoc/classes/Web/Mime.src/M000123.html +23 -0
- data/doc/rdoc/classes/Web/Mime.src/M000124.html +15 -0
- data/doc/rdoc/classes/Web/Narflates.html +132 -0
- data/doc/rdoc/classes/Web/Parser.html +219 -0
- data/doc/rdoc/classes/Web/Parser.src/M000013.html +21 -0
- data/doc/rdoc/classes/Web/Parser.src/M000014.html +19 -0
- data/doc/rdoc/classes/Web/Parser.src/M000015.html +21 -0
- data/doc/rdoc/classes/Web/Parser.src/M000016.html +15 -0
- data/doc/rdoc/classes/Web/Parser.src/M000017.html +30 -0
- data/doc/rdoc/classes/Web/Parser.src/M000018.html +15 -0
- data/doc/rdoc/classes/Web/Parser.src/M000019.html +19 -0
- data/doc/rdoc/classes/Web/Parser.src/M000020.html +27 -0
- data/doc/rdoc/classes/Web/Parser.src/M000021.html +15 -0
- data/doc/rdoc/classes/Web/Parser.src/M000022.html +16 -0
- data/doc/rdoc/classes/Web/Parser.src/M000023.html +18 -0
- data/doc/rdoc/classes/Web/Session.html +178 -0
- data/doc/rdoc/classes/Web/Session.src/M000042.html +20 -0
- data/doc/rdoc/classes/Web/Session.src/M000043.html +19 -0
- data/doc/rdoc/classes/Web/Session.src/M000044.html +21 -0
- data/doc/rdoc/classes/Web/Session.src/M000045.html +21 -0
- data/doc/rdoc/classes/Web/Session.src/M000046.html +15 -0
- data/doc/rdoc/classes/Web/Session.src/M000047.html +17 -0
- data/doc/rdoc/classes/Web/Session.src/M000048.html +15 -0
- data/doc/rdoc/classes/Web/Session.src/M000049.html +15 -0
- data/doc/rdoc/classes/Web/Session.src/M000050.html +16 -0
- data/doc/rdoc/classes/Web/Testing.html +474 -0
- data/doc/rdoc/classes/Web/Testing.src/M000024.html +15 -0
- data/doc/rdoc/classes/Web/Testing.src/M000025.html +25 -0
- data/doc/rdoc/classes/Web/Testing.src/M000026.html +15 -0
- data/doc/rdoc/classes/Web/Testing.src/M000027.html +28 -0
- data/doc/rdoc/classes/Web/Testing.src/M000028.html +58 -0
- data/doc/rdoc/classes/Web/Testing.src/M000029.html +15 -0
- data/doc/rdoc/classes/Web/Testing.src/M000030.html +15 -0
- data/doc/rdoc/classes/Web/Testing.src/M000031.html +15 -0
- data/doc/rdoc/classes/Web/Testing.src/M000032.html +15 -0
- data/doc/rdoc/classes/Web/Testing.src/M000033.html +15 -0
- data/doc/rdoc/classes/Web/Testing.src/M000034.html +15 -0
- data/doc/rdoc/classes/Web/Testing.src/M000035.html +15 -0
- data/doc/rdoc/classes/Web/Testing.src/M000036.html +18 -0
- data/doc/rdoc/classes/Web/Upload.html +160 -0
- data/doc/rdoc/classes/Web/Upload.src/M000108.html +25 -0
- data/doc/rdoc/classes/Web/Upload.src/M000109.html +18 -0
- data/doc/rdoc/classes/Web/Upload.src/M000110.html +16 -0
- data/doc/rdoc/classes/Web/Upload.src/M000111.html +16 -0
- data/doc/rdoc/classes/Web/Wiki.html +249 -0
- data/doc/rdoc/classes/Web/Wiki.src/M000112.html +25 -0
- data/doc/rdoc/classes/Web/Wiki.src/M000113.html +15 -0
- data/doc/rdoc/classes/Web/Wiki.src/M000114.html +26 -0
- data/doc/rdoc/classes/Web/Wiki.src/M000115.html +21 -0
- data/doc/rdoc/classes/Web/Wiki.src/M000116.html +18 -0
- data/doc/rdoc/classes/Web/Wiki.src/M000117.html +19 -0
- data/doc/rdoc/created.rid +1 -0
- data/doc/rdoc/files/README.html +226 -0
- data/doc/rdoc/files/doc/apache_cgi_txt.html +82 -0
- data/doc/rdoc/files/doc/fastcgi_txt.html +82 -0
- data/doc/rdoc/files/doc/mod_ruby_txt.html +62 -0
- data/doc/rdoc/files/doc/webrick_txt.html +79 -0
- data/doc/rdoc/files/examples/examples_rdoc.html +73 -0
- data/doc/rdoc/files/lib/web/cgi_rb.html +75 -0
- data/doc/rdoc/files/lib/web/mime_rb.html +67 -0
- data/doc/rdoc/files/lib/web/parser_rb.html +73 -0
- data/doc/rdoc/files/lib/web/session_rb.html +73 -0
- data/doc/rdoc/files/lib/web/template_rb.html +73 -0
- data/doc/rdoc/files/lib/web/testing_rb.html +67 -0
- data/doc/rdoc/files/lib/web/upload_rb.html +73 -0
- data/doc/rdoc/files/lib/web/wiki_rb.html +79 -0
- data/doc/rdoc/files/lib/web_rb.html +116 -0
- data/doc/rdoc/files/lib/web_rb.src/M000001.html +15 -0
- data/doc/rdoc/fr_class_index.html +47 -0
- data/doc/rdoc/fr_file_index.html +52 -0
- data/doc/rdoc/fr_method_index.html +158 -0
- data/doc/rdoc/index.html +22 -0
- data/doc/rdoc/rdoc-style.css +99 -0
- data/doc/webrick.txt +23 -0
- data/examples/admin.rb +8 -0
- data/examples/admin.rb~ +5 -0
- data/examples/cookbook.rdoc +247 -0
- data/examples/cookbook.rdoc~ +238 -0
- data/examples/examples.rdoc +19 -0
- data/examples/examples.rdoc~ +17 -0
- data/examples/hello.world.rb +5 -0
- data/examples/hello.world.rb~ +3 -0
- data/examples/session.rb +34 -0
- data/examples/session.rb~ +31 -0
- data/examples/test/test.hello.world.rb +9 -0
- data/examples/test/test.hello.world.rb~ +9 -0
- data/examples/test/test.session.rb +37 -0
- data/examples/test/test.session.rb~ +37 -0
- data/examples/webunit/COPYING +340 -0
- data/examples/webunit/Makefile +14 -0
- data/examples/webunit/TIPS-ja.html +126 -0
- data/examples/webunit/TIPS-ja.rd +154 -0
- data/examples/webunit/TODO-ja.html +35 -0
- data/examples/webunit/TODO-ja.rd +28 -0
- data/examples/webunit/changes.rd +185 -0
- data/examples/webunit/conv/digit-0.cgi +40 -0
- data/examples/webunit/conv/digit-0.rb +21 -0
- data/examples/webunit/conv/digit-1.cgi +44 -0
- data/examples/webunit/conv/digit-1.rb +17 -0
- data/examples/webunit/conv/digit.cgi +59 -0
- data/examples/webunit/conv/digit.rb +23 -0
- data/examples/webunit/conv/test_digit-0.rb +16 -0
- data/examples/webunit/conv/test_digit-1.rb +19 -0
- data/examples/webunit/conv/test_digit.rb +26 -0
- data/examples/webunit/conv/test_digit_view-0.rb +76 -0
- data/examples/webunit/conv/test_digit_view-1.rb +102 -0
- data/examples/webunit/conv/test_digit_view.rb +134 -0
- data/examples/webunit/example.rd +37 -0
- data/examples/webunit/index-en.html +263 -0
- data/examples/webunit/index-en.rd +60 -0
- data/examples/webunit/index-ja.html +263 -0
- data/examples/webunit/index-ja.rd +60 -0
- data/examples/wiki.rb +7 -0
- data/examples/wiki.rb~ +5 -0
- data/install.rb +1022 -0
- data/lib/web.rb +290 -0
- data/lib/web.rb~ +290 -0
- data/lib/web/#assertinclude.rb# +110 -0
- data/lib/web/action.rb +82 -0
- data/lib/web/assertinclude.rb +110 -0
- data/lib/web/assertinclude.rb~ +110 -0
- data/lib/web/buffer.rb +20 -0
- data/lib/web/cgi.rb +641 -0
- data/lib/web/cgi.rb~ +640 -0
- data/lib/web/formreader.rb +317 -0
- data/lib/web/forms.rb +104 -0
- data/lib/web/htmlparser/html-parser.rb +429 -0
- data/lib/web/htmlparser/html-parser.rb~ +429 -0
- data/lib/web/htmlparser/sgml-parser.rb +332 -0
- data/lib/web/htmlparser/sgml-parser.rb~ +332 -0
- data/lib/web/htmltools/element.rb +296 -0
- data/lib/web/htmltools/element.rb~ +296 -0
- data/lib/web/htmltools/stparser.rb +276 -0
- data/lib/web/htmltools/stparser.rb~ +276 -0
- data/lib/web/htmltools/tags.rb +286 -0
- data/lib/web/htmltools/tags.rb~ +286 -0
- data/lib/web/htmltools/tree.rb +139 -0
- data/lib/web/htmltools/tree.rb~ +139 -0
- data/lib/web/htmltools/xmltree.rb +160 -0
- data/lib/web/htmltools/xmltree.rb~ +160 -0
- data/lib/web/htmltools/xpath.rb +71 -0
- data/lib/web/htmltools/xpath.rb~ +71 -0
- data/lib/web/mime.rb +82 -0
- data/lib/web/parser.rb +266 -0
- data/lib/web/parser.rb~ +266 -0
- data/lib/web/request.rb~ +238 -0
- data/lib/web/resources/mime.types +483 -0
- data/lib/web/runner.rb +26 -0
- data/lib/web/runner.rb~ +26 -0
- data/lib/web/sapi/fastcgi.rb +26 -0
- data/lib/web/sapi/fastcgi.rb~ +25 -0
- data/lib/web/sapi/mod_ruby.rb +46 -0
- data/lib/web/sapi/mod_ruby.rb~ +46 -0
- data/lib/web/sapi/webrick.rb +91 -0
- data/lib/web/sapi/webrick.rb~ +89 -0
- data/lib/web/session.rb +75 -0
- data/lib/web/session.rb~ +75 -0
- data/lib/web/simpledispatcher.rb +155 -0
- data/lib/web/strscanparser.rb +24 -0
- data/lib/web/tagparser.rb +96 -0
- data/lib/web/tagparser.rb~ +96 -0
- data/lib/web/template.rb +613 -0
- data/lib/web/template.rb~ +613 -0
- data/lib/web/testing.rb +546 -0
- data/lib/web/testing.rb~ +546 -0
- data/lib/web/traceoutput.rb +32 -0
- data/lib/web/unit.rb +27 -0
- data/lib/web/unit/assert.rb +154 -0
- data/lib/web/unit/converter.rb +148 -0
- data/lib/web/unit/cookie.rb +120 -0
- data/lib/web/unit/domwalker.rb +187 -0
- data/lib/web/unit/exception.rb +15 -0
- data/lib/web/unit/form.rb +118 -0
- data/lib/web/unit/formatter.rb +314 -0
- data/lib/web/unit/frame.rb +39 -0
- data/lib/web/unit/html-parser.rb +432 -0
- data/lib/web/unit/htmlelem.rb +124 -0
- data/lib/web/unit/htmlrepair.rb +116 -0
- data/lib/web/unit/htmlsplit.rb +840 -0
- data/lib/web/unit/image.rb +27 -0
- data/lib/web/unit/jscript.rb +32 -0
- data/lib/web/unit/link.rb +35 -0
- data/lib/web/unit/params.rb +323 -0
- data/lib/web/unit/parser.rb +226 -0
- data/lib/web/unit/resources/assert.html +101 -0
- data/lib/web/unit/resources/auth/index.html +5 -0
- data/lib/web/unit/resources/badtags.html +7 -0
- data/lib/web/unit/resources/cookie.cgi +33 -0
- data/lib/web/unit/resources/document.xml +13 -0
- data/lib/web/unit/resources/form.html +150 -0
- data/lib/web/unit/resources/frame-0.html +10 -0
- data/lib/web/unit/resources/frame-1.html +10 -0
- data/lib/web/unit/resources/frame.html +10 -0
- data/lib/web/unit/resources/image.html +17 -0
- data/lib/web/unit/resources/images/x.gif +0 -0
- data/lib/web/unit/resources/images/y.gif +0 -0
- data/lib/web/unit/resources/jscript-0.html +10 -0
- data/lib/web/unit/resources/jscript-1.html +10 -0
- data/lib/web/unit/resources/jscript.html +19 -0
- data/lib/web/unit/resources/link.html +19 -0
- data/lib/web/unit/resources/multipart.cgi +28 -0
- data/lib/web/unit/resources/multipart.html +74 -0
- data/lib/web/unit/resources/params.html +65 -0
- data/lib/web/unit/resources/redirect.cgi +13 -0
- data/lib/web/unit/resources/response.html +67 -0
- data/lib/web/unit/resources/simple.cgi +14 -0
- data/lib/web/unit/resources/stock.cgi +35 -0
- data/lib/web/unit/resources/table.html +83 -0
- data/lib/web/unit/response.rb +469 -0
- data/lib/web/unit/response.rb~ +461 -0
- data/lib/web/unit/runtest.rb +44 -0
- data/lib/web/unit/sgml-parser.rb +336 -0
- data/lib/web/unit/table.rb +150 -0
- data/lib/web/unit/testcase.rb +49 -0
- data/lib/web/unit/ui/cui/testrunner.rb +52 -0
- data/lib/web/unit/ui/cui/testrunner.rb~ +50 -0
- data/lib/web/unit/utils.rb +70 -0
- data/lib/web/unit/webunit.rb +28 -0
- data/lib/web/upload.rb +55 -0
- data/lib/web/upload.rb~ +262 -0
- data/lib/web/wiki.rb +506 -0
- data/lib/web/wiki.rb~ +506 -0
- data/lib/web/wiki/linker.rb +72 -0
- data/lib/web/wiki/linker.rb~ +72 -0
- data/lib/web/wiki/mime.rb~ +68 -0
- data/lib/web/wiki/page.rb +192 -0
- data/lib/web/wiki/page.rb~ +192 -0
- data/lib/web/wiki/resources/#edit.html# +65 -0
- data/lib/web/wiki/resources/admin.html +13 -0
- data/lib/web/wiki/resources/admin.html~ +13 -0
- data/lib/web/wiki/resources/asset_history.html +3 -0
- data/lib/web/wiki/resources/basic.html +1 -0
- data/lib/web/wiki/resources/default-content_editor.html +1 -0
- data/lib/web/wiki/resources/default-content_editor.html~ +1 -0
- data/lib/web/wiki/resources/edit.html +1 -1
- data/lib/web/wiki/resources/edit.html~ +1 -1
- data/lib/web/wiki/resources/ekit-content_editor.html +1 -0
- data/lib/web/wiki/resources/home.html +10 -0
- data/lib/web/wiki/resources/home.html~ +10 -0
- data/lib/web/wiki/resources/htmlarea/ChangeLog +1185 -0
- data/lib/web/wiki/resources/htmlarea/dialog.js +72 -0
- data/lib/web/wiki/resources/htmlarea/examples/2-areas.cgi +16 -0
- data/lib/web/wiki/resources/htmlarea/examples/2-areas.html +158 -0
- data/lib/web/wiki/resources/htmlarea/examples/context-menu.html +95 -0
- data/lib/web/wiki/resources/htmlarea/examples/core.html +184 -0
- data/lib/web/wiki/resources/htmlarea/examples/css.html +88 -0
- data/lib/web/wiki/resources/htmlarea/examples/custom.css +29 -0
- data/lib/web/wiki/resources/htmlarea/examples/full-page.html +75 -0
- data/lib/web/wiki/resources/htmlarea/examples/fully-loaded.html +248 -0
- data/lib/web/wiki/resources/htmlarea/examples/index.html +40 -0
- data/lib/web/wiki/resources/htmlarea/examples/spell-checker.html +132 -0
- data/lib/web/wiki/resources/htmlarea/examples/table-operations.html +116 -0
- data/lib/web/wiki/resources/htmlarea/examples/test.cgi +21 -0
- data/lib/web/wiki/resources/htmlarea/htmlarea.css +180 -0
- data/lib/web/wiki/resources/htmlarea/htmlarea.js +2175 -0
- data/lib/web/wiki/resources/htmlarea/images/ed_about.gif +0 -0
- data/lib/web/wiki/resources/htmlarea/images/ed_align_center.gif +0 -0
- data/lib/web/wiki/resources/htmlarea/images/ed_align_justify.gif +0 -0
- data/lib/web/wiki/resources/htmlarea/images/ed_align_left.gif +0 -0
- data/lib/web/wiki/resources/htmlarea/images/ed_align_right.gif +0 -0
- data/lib/web/wiki/resources/htmlarea/images/ed_blank.gif +0 -0
- data/lib/web/wiki/resources/htmlarea/images/ed_charmap.gif +0 -0
- data/lib/web/wiki/resources/htmlarea/images/ed_color_bg.gif +0 -0
- data/lib/web/wiki/resources/htmlarea/images/ed_color_fg.gif +0 -0
- data/lib/web/wiki/resources/htmlarea/images/ed_copy.gif +0 -0
- data/lib/web/wiki/resources/htmlarea/images/ed_custom.gif +0 -0
- data/lib/web/wiki/resources/htmlarea/images/ed_cut.gif +0 -0
- data/lib/web/wiki/resources/htmlarea/images/ed_delete.gif +0 -0
- data/lib/web/wiki/resources/htmlarea/images/ed_format_bold.gif +0 -0
- data/lib/web/wiki/resources/htmlarea/images/ed_format_italic.gif +0 -0
- data/lib/web/wiki/resources/htmlarea/images/ed_format_strike.gif +0 -0
- data/lib/web/wiki/resources/htmlarea/images/ed_format_sub.gif +0 -0
- data/lib/web/wiki/resources/htmlarea/images/ed_format_sup.gif +0 -0
- data/lib/web/wiki/resources/htmlarea/images/ed_format_underline.gif +0 -0
- data/lib/web/wiki/resources/htmlarea/images/ed_help.gif +0 -0
- data/lib/web/wiki/resources/htmlarea/images/ed_hr.gif +0 -0
- data/lib/web/wiki/resources/htmlarea/images/ed_html.gif +0 -0
- data/lib/web/wiki/resources/htmlarea/images/ed_image.gif +0 -0
- data/lib/web/wiki/resources/htmlarea/images/ed_indent_less.gif +0 -0
- data/lib/web/wiki/resources/htmlarea/images/ed_indent_more.gif +0 -0
- data/lib/web/wiki/resources/htmlarea/images/ed_left_to_right.gif +0 -0
- data/lib/web/wiki/resources/htmlarea/images/ed_link.gif +0 -0
- data/lib/web/wiki/resources/htmlarea/images/ed_list_bullet.gif +0 -0
- data/lib/web/wiki/resources/htmlarea/images/ed_list_num.gif +0 -0
- data/lib/web/wiki/resources/htmlarea/images/ed_paste.gif +0 -0
- data/lib/web/wiki/resources/htmlarea/images/ed_redo.gif +0 -0
- data/lib/web/wiki/resources/htmlarea/images/ed_right_to_left.gif +0 -0
- data/lib/web/wiki/resources/htmlarea/images/ed_save.gif +0 -0
- data/lib/web/wiki/resources/htmlarea/images/ed_show_border.gif +0 -0
- data/lib/web/wiki/resources/htmlarea/images/ed_splitcel.gif +0 -0
- data/lib/web/wiki/resources/htmlarea/images/ed_undo.gif +0 -0
- data/lib/web/wiki/resources/htmlarea/images/fullscreen_maximize.gif +0 -0
- data/lib/web/wiki/resources/htmlarea/images/fullscreen_minimize.gif +0 -0
- data/lib/web/wiki/resources/htmlarea/images/insert_table.gif +0 -0
- data/lib/web/wiki/resources/htmlarea/index.html +199 -0
- data/lib/web/wiki/resources/htmlarea/lang/b5.js +36 -0
- data/lib/web/wiki/resources/htmlarea/lang/cz.js +63 -0
- data/lib/web/wiki/resources/htmlarea/lang/da.js +38 -0
- data/lib/web/wiki/resources/htmlarea/lang/de.js +54 -0
- data/lib/web/wiki/resources/htmlarea/lang/ee.js +63 -0
- data/lib/web/wiki/resources/htmlarea/lang/el.js +75 -0
- data/lib/web/wiki/resources/htmlarea/lang/en.js +88 -0
- data/lib/web/wiki/resources/htmlarea/lang/es.js +51 -0
- data/lib/web/wiki/resources/htmlarea/lang/fi.js +46 -0
- data/lib/web/wiki/resources/htmlarea/lang/fr.js +61 -0
- data/lib/web/wiki/resources/htmlarea/lang/gb.js +36 -0
- data/lib/web/wiki/resources/htmlarea/lang/he.js +63 -0
- data/lib/web/wiki/resources/htmlarea/lang/hu.js +63 -0
- data/lib/web/wiki/resources/htmlarea/lang/it.js +54 -0
- data/lib/web/wiki/resources/htmlarea/lang/ja-euc.js +37 -0
- data/lib/web/wiki/resources/htmlarea/lang/ja-jis.js +37 -0
- data/lib/web/wiki/resources/htmlarea/lang/ja-sjis.js +37 -0
- data/lib/web/wiki/resources/htmlarea/lang/ja-utf8.js +37 -0
- data/lib/web/wiki/resources/htmlarea/lang/lt.js +55 -0
- data/lib/web/wiki/resources/htmlarea/lang/lv.js +55 -0
- data/lib/web/wiki/resources/htmlarea/lang/nb.js +36 -0
- data/lib/web/wiki/resources/htmlarea/lang/nl.js +90 -0
- data/lib/web/wiki/resources/htmlarea/lang/no.js +79 -0
- data/lib/web/wiki/resources/htmlarea/lang/pl.js +36 -0
- data/lib/web/wiki/resources/htmlarea/lang/pt_br.js +37 -0
- data/lib/web/wiki/resources/htmlarea/lang/ro.js +80 -0
- data/lib/web/wiki/resources/htmlarea/lang/ru.js +63 -0
- data/lib/web/wiki/resources/htmlarea/lang/se.js +38 -0
- data/lib/web/wiki/resources/htmlarea/lang/si.js +63 -0
- data/lib/web/wiki/resources/htmlarea/lang/vn.js +51 -0
- data/lib/web/wiki/resources/htmlarea/license.txt +30 -0
- data/lib/web/wiki/resources/htmlarea/plugins/CSS/css.js +116 -0
- data/lib/web/wiki/resources/htmlarea/plugins/CSS/lang/en.js +2 -0
- data/lib/web/wiki/resources/htmlarea/plugins/ContextMenu/context-menu.js +416 -0
- data/lib/web/wiki/resources/htmlarea/plugins/ContextMenu/lang/de.js +59 -0
- data/lib/web/wiki/resources/htmlarea/plugins/ContextMenu/lang/el.js +57 -0
- data/lib/web/wiki/resources/htmlarea/plugins/ContextMenu/lang/en.js +66 -0
- data/lib/web/wiki/resources/htmlarea/plugins/ContextMenu/lang/nl.js +66 -0
- data/lib/web/wiki/resources/htmlarea/plugins/ContextMenu/menu.css +64 -0
- data/lib/web/wiki/resources/htmlarea/plugins/FullPage/full-page.js +143 -0
- data/lib/web/wiki/resources/htmlarea/plugins/FullPage/img/docprop.gif +0 -0
- data/lib/web/wiki/resources/htmlarea/plugins/FullPage/lang/en.js +25 -0
- data/lib/web/wiki/resources/htmlarea/plugins/FullPage/lang/ro.js +25 -0
- data/lib/web/wiki/resources/htmlarea/plugins/FullPage/popups/docprop.html +131 -0
- data/lib/web/wiki/resources/htmlarea/plugins/FullPage/test.html +89 -0
- data/lib/web/wiki/resources/htmlarea/plugins/SpellChecker/img/spell-check.gif +0 -0
- data/lib/web/wiki/resources/htmlarea/plugins/SpellChecker/lang/cz.js +37 -0
- data/lib/web/wiki/resources/htmlarea/plugins/SpellChecker/lang/da.js +37 -0
- data/lib/web/wiki/resources/htmlarea/plugins/SpellChecker/lang/de.js +28 -0
- data/lib/web/wiki/resources/htmlarea/plugins/SpellChecker/lang/en.js +38 -0
- data/lib/web/wiki/resources/htmlarea/plugins/SpellChecker/lang/hu.js +37 -0
- data/lib/web/wiki/resources/htmlarea/plugins/SpellChecker/lang/it.js +28 -0
- data/lib/web/wiki/resources/htmlarea/plugins/SpellChecker/lang/ro.js +37 -0
- data/lib/web/wiki/resources/htmlarea/plugins/SpellChecker/readme-tech.html +114 -0
- data/lib/web/wiki/resources/htmlarea/plugins/SpellChecker/spell-check-logic.cgi +210 -0
- data/lib/web/wiki/resources/htmlarea/plugins/SpellChecker/spell-check-style.css +10 -0
- data/lib/web/wiki/resources/htmlarea/plugins/SpellChecker/spell-check-ui.html +122 -0
- data/lib/web/wiki/resources/htmlarea/plugins/SpellChecker/spell-check-ui.js +397 -0
- data/lib/web/wiki/resources/htmlarea/plugins/SpellChecker/spell-checker.js +79 -0
- data/lib/web/wiki/resources/htmlarea/plugins/TableOperations/img/cell-delete.gif +0 -0
- data/lib/web/wiki/resources/htmlarea/plugins/TableOperations/img/cell-insert-after.gif +0 -0
- data/lib/web/wiki/resources/htmlarea/plugins/TableOperations/img/cell-insert-before.gif +0 -0
- data/lib/web/wiki/resources/htmlarea/plugins/TableOperations/img/cell-merge.gif +0 -0
- data/lib/web/wiki/resources/htmlarea/plugins/TableOperations/img/cell-prop.gif +0 -0
- data/lib/web/wiki/resources/htmlarea/plugins/TableOperations/img/cell-split.gif +0 -0
- data/lib/web/wiki/resources/htmlarea/plugins/TableOperations/img/col-delete.gif +0 -0
- data/lib/web/wiki/resources/htmlarea/plugins/TableOperations/img/col-insert-after.gif +0 -0
- data/lib/web/wiki/resources/htmlarea/plugins/TableOperations/img/col-insert-before.gif +0 -0
- data/lib/web/wiki/resources/htmlarea/plugins/TableOperations/img/col-split.gif +0 -0
- data/lib/web/wiki/resources/htmlarea/plugins/TableOperations/img/row-delete.gif +0 -0
- data/lib/web/wiki/resources/htmlarea/plugins/TableOperations/img/row-insert-above.gif +0 -0
- data/lib/web/wiki/resources/htmlarea/plugins/TableOperations/img/row-insert-under.gif +0 -0
- data/lib/web/wiki/resources/htmlarea/plugins/TableOperations/img/row-prop.gif +0 -0
- data/lib/web/wiki/resources/htmlarea/plugins/TableOperations/img/row-split.gif +0 -0
- data/lib/web/wiki/resources/htmlarea/plugins/TableOperations/img/table-prop.gif +0 -0
- data/lib/web/wiki/resources/htmlarea/plugins/TableOperations/lang/cz.js +90 -0
- data/lib/web/wiki/resources/htmlarea/plugins/TableOperations/lang/da.js +90 -0
- data/lib/web/wiki/resources/htmlarea/plugins/TableOperations/lang/de.js +81 -0
- data/lib/web/wiki/resources/htmlarea/plugins/TableOperations/lang/el.js +81 -0
- data/lib/web/wiki/resources/htmlarea/plugins/TableOperations/lang/en.js +90 -0
- data/lib/web/wiki/resources/htmlarea/plugins/TableOperations/lang/fi.js +66 -0
- data/lib/web/wiki/resources/htmlarea/plugins/TableOperations/lang/hu.js +63 -0
- data/lib/web/wiki/resources/htmlarea/plugins/TableOperations/lang/it.js +81 -0
- data/lib/web/wiki/resources/htmlarea/plugins/TableOperations/lang/nl.js +90 -0
- data/lib/web/wiki/resources/htmlarea/plugins/TableOperations/lang/no.js +91 -0
- data/lib/web/wiki/resources/htmlarea/plugins/TableOperations/lang/ro.js +90 -0
- data/lib/web/wiki/resources/htmlarea/plugins/TableOperations/table-operations.js +1160 -0
- data/lib/web/wiki/resources/htmlarea/popupdiv.js +369 -0
- data/lib/web/wiki/resources/htmlarea/popups/about.html +378 -0
- data/lib/web/wiki/resources/htmlarea/popups/blank.html +2 -0
- data/lib/web/wiki/resources/htmlarea/popups/custom2.html +35 -0
- data/lib/web/wiki/resources/htmlarea/popups/editor_help.html +16 -0
- data/lib/web/wiki/resources/htmlarea/popups/fullscreen.html +133 -0
- data/lib/web/wiki/resources/htmlarea/popups/insert_image.html +191 -0
- data/lib/web/wiki/resources/htmlarea/popups/insert_table.html +174 -0
- data/lib/web/wiki/resources/htmlarea/popups/link.html +142 -0
- data/lib/web/wiki/resources/htmlarea/popups/old-fullscreen.html +131 -0
- data/lib/web/wiki/resources/htmlarea/popups/old_insert_image.html +206 -0
- data/lib/web/wiki/resources/htmlarea/popups/popup.js +109 -0
- data/lib/web/wiki/resources/htmlarea/popups/select_color.html +347 -0
- data/lib/web/wiki/resources/htmlarea/popupwin.js +139 -0
- data/lib/web/wiki/resources/htmlarea/reference.html +523 -0
- data/lib/web/wiki/resources/htmlarea/release-notes.html +165 -0
- data/lib/web/wiki/resources/ie-content_editor.html +1 -0
- data/lib/web/wiki/resources/ie-content_editor.js +196 -0
- data/lib/web/wiki/resources/illustration.html +1 -0
- data/lib/web/wiki/resources/illustration.html~ +1 -0
- data/lib/web/wiki/resources/images.html +1 -0
- data/lib/web/wiki/resources/index.html +4 -0
- data/lib/web/wiki/resources/index.html~ +4 -0
- data/lib/web/wiki/resources/more_news.html +5 -0
- data/lib/web/wiki/resources/more_news.html~ +5 -0
- data/lib/web/wiki/resources/more_news_rss_0.91.html +23 -0
- data/lib/web/wiki/resources/narf-logo.gif +0 -0
- data/lib/web/wiki/resources/page_history.html +19 -0
- data/lib/web/wiki/resources/page_history.html~ +19 -0
- data/lib/web/wiki/resources/template.html +13 -0
- data/lib/web/wiki/resources/template.html~ +13 -0
- data/lib/web/wiki/resources/test_upload.gif +0 -0
- data/lib/web/wiki/resources/text-styles.css +1 -0
- data/lib/web/writableio.rb +33 -0
- data/narf-0.5.1.gem +0 -0
- data/narf.gemspec +40 -0
- data/narf.gemspec~ +52 -0
- data/pre-setup.rb +5 -0
- data/sapi/apache_cgi/INSTALL.txt~ +9 -0
- data/sapi/apache_cgi/README~ +0 -0
- data/sapi/apache_cgi/src/narf.c +13 -0
- data/sapi/fastcgi/INSTALL.txt~ +17 -0
- data/sapi/mod_ruby/INSTALL.txt~ +5 -0
- data/sapi/webrick/INSTALL.txt~ +21 -0
- data/sapi/webrick/run_webrick.rb~ +16 -0
- data/scripts/dump.rb +14 -0
- data/scripts/makedist.rb +49 -0
- data/scripts/upload.html +5 -0
- data/scripts/uri.rb +41 -0
- data/scripts/uri/common.rb +432 -0
- data/scripts/uri/ftp.rb +149 -0
- data/scripts/uri/generic.rb +1106 -0
- data/scripts/uri/http.rb +76 -0
- data/scripts/uri/https.rb +26 -0
- data/scripts/uri/ldap.rb +238 -0
- data/scripts/uri/mailto.rb +260 -0
- data/scripts/urireg.rb +174 -0
- data/test/bufferedtestrunner.rb +112 -0
- data/test/mod_ruby_stub.rb +39 -0
- data/test/mod_ruby_stub.rb~ +38 -0
- data/test/stringio.rb +2 -0
- data/test/test.action.rb +142 -0
- data/test/test.action.rb~ +142 -0
- data/test/test.app.rb +0 -0
- data/test/test.assertinclude.rb +109 -0
- data/test/test.assertinclude.rb~ +109 -0
- data/test/test.formreader-2.0.rb +352 -0
- data/test/test.formreader.rb +465 -0
- data/test/test.mime-type.rb +23 -0
- data/test/test.narf.cgi.rb +101 -0
- data/test/test.narf.cgi.rb~ +105 -0
- data/test/test.request.rb +328 -0
- data/test/test.request.rb~ +318 -0
- data/test/test.response.rb +565 -0
- data/test/test.response.rb~ +556 -0
- data/test/test.session.rb +50 -0
- data/test/test.simpledispatcher.rb +188 -0
- data/test/test.tagparser.rb +65 -0
- data/test/test.template.rb +831 -0
- data/test/test.template.rb~ +832 -0
- data/test/test.testing2.rb +341 -0
- data/test/test.web.test.rb +463 -0
- data/test/test.web.test.rb~ +461 -0
- data/test/testfiles/basictemplate.tpl +1 -0
- data/test/testfiles/explorer5.multipart.data +9 -0
- data/test/testfiles/form.html +7 -0
- data/test/testfiles/mozilla.multipart.data +9 -0
- data/test/testfiles/netscape4.multipart.data +9 -0
- data/test/testfiles/pic hydra.png +1 -0
- data/test/testfiles/post.data +1 -0
- data/test/testfiles/print.text +1 -0
- data/test/testfiles/text +1 -0
- data/test/webunit/dont_get_it.test_webunit.rb +27 -0
- data/test/webunit/ref +38 -0
- data/test/webunit/resources/uploadfile1.txt +1 -0
- data/test/webunit/resources/uploadfile2.txt +1 -0
- data/test/webunit/test_assert.rb +169 -0
- data/test/webunit/test_cookie.rb +128 -0
- data/test/webunit/test_cookie.rb~ +128 -0
- data/test/webunit/test_domwalker.rb +83 -0
- data/test/webunit/test_form.rb +43 -0
- data/test/webunit/test_form.rb~ +43 -0
- data/test/webunit/test_frame.rb +43 -0
- data/test/webunit/test_htmlelem.rb +75 -0
- data/test/webunit/test_image.rb +46 -0
- data/test/webunit/test_jscript.rb +58 -0
- data/test/webunit/test_link.rb +87 -0
- data/test/webunit/test_multipart.rb +53 -0
- data/test/webunit/test_multipart.rb~ +53 -0
- data/test/webunit/test_params.rb +212 -0
- data/test/webunit/test_params.rb~ +211 -0
- data/test/webunit/test_parser.rb +31 -0
- data/test/webunit/test_response.rb +145 -0
- data/test/webunit/test_response.rb~ +145 -0
- data/test/webunit/test_site/assert.html +101 -0
- data/test/webunit/test_site/assert.html~ +1 -0
- data/test/webunit/test_site/auth/index.html +5 -0
- data/test/webunit/test_site/auth/index.html~ +1 -0
- data/test/webunit/test_site/badtags.html +7 -0
- data/test/webunit/test_site/badtags.html~ +1 -0
- data/test/webunit/test_site/cookie.cgi +37 -0
- data/test/webunit/test_site/cookie.cgi~ +35 -0
- data/test/webunit/test_site/document.xml +13 -0
- data/test/webunit/test_site/document.xml~ +1 -0
- data/test/webunit/test_site/form.html +150 -0
- data/test/webunit/test_site/form.html~ +1 -0
- data/test/webunit/test_site/frame-0.html +10 -0
- data/test/webunit/test_site/frame-0.html~ +1 -0
- data/test/webunit/test_site/frame-1.html +10 -0
- data/test/webunit/test_site/frame-1.html~ +1 -0
- data/test/webunit/test_site/frame.html +10 -0
- data/test/webunit/test_site/frame.html~ +1 -0
- data/test/webunit/test_site/image.html +17 -0
- data/test/webunit/test_site/image.html~ +1 -0
- data/test/webunit/test_site/images/x.gif +0 -0
- data/test/webunit/test_site/images/y.gif +0 -0
- data/test/webunit/test_site/include.cgi~ +10 -0
- data/test/webunit/test_site/jscript-0.html +10 -0
- data/test/webunit/test_site/jscript-0.html~ +1 -0
- data/test/webunit/test_site/jscript-1.html +10 -0
- data/test/webunit/test_site/jscript-1.html~ +1 -0
- data/test/webunit/test_site/jscript.html +19 -0
- data/test/webunit/test_site/jscript.html~ +1 -0
- data/test/webunit/test_site/link.html +19 -0
- data/test/webunit/test_site/link.html~ +1 -0
- data/test/webunit/test_site/multipart.cgi +27 -0
- data/test/webunit/test_site/multipart.cgi~ +25 -0
- data/test/webunit/test_site/multipart.html +74 -0
- data/test/webunit/test_site/multipart.html~ +1 -0
- data/test/webunit/test_site/params.html +65 -0
- data/test/webunit/test_site/params.html~ +1 -0
- data/test/webunit/test_site/redirect.cgi +14 -0
- data/test/webunit/test_site/redirect.cgi~ +14 -0
- data/test/webunit/test_site/response.html +67 -0
- data/test/webunit/test_site/response.html~ +1 -0
- data/test/webunit/test_site/simple.cgi +17 -0
- data/test/webunit/test_site/simple.cgi~ +17 -0
- data/test/webunit/test_site/stock.cgi +36 -0
- data/test/webunit/test_site/stock.cgi~ +34 -0
- data/test/webunit/test_site/table.html +83 -0
- data/test/webunit/test_site/table.html~ +1 -0
- data/test/webunit/test_site/test.cgi~ +25 -0
- data/test/webunit/test_table.rb +70 -0
- data/test/webunit/test_utils.rb +107 -0
- data/test/wiki/test.history.rb +277 -0
- data/test/wiki/test.history.rb~ +254 -0
- data/test/wiki/test.illustration_page.rb +287 -0
- data/test/wiki/test.illustration_page.rb~ +287 -0
- data/test/wiki/test.linker.rb +197 -0
- data/test/wiki/test.tarpit.rb +40 -0
- data/test/wiki/test.wiki.rb +295 -0
- data/test/wiki/test.wiki.rb~ +295 -0
- data/test/wikitestroot/big_image.jpg +0 -0
- data/test/wikitestroot/mime.types +483 -0
- data/test/wikitestroot/test_upload.gif +0 -0
- data/vandals.test.txt +3 -0
- 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(/\ \;/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, "&");
|
|
1949
|
+
str = str.replace(/</ig, "<");
|
|
1950
|
+
str = str.replace(/>/ig, ">");
|
|
1951
|
+
str = str.replace(/\x22/ig, """);
|
|
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 ' 's into spaces in the data element
|
|
2041
|
+
if ( !root.previousSibling && !root.nextSibling && root.data.match(/^\s*$/i) ) html = ' ';
|
|
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: //
|