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