From b5a6d40cbc059c63bbf00a45f5edaf2f36b07e12 Mon Sep 17 00:00:00 2001 From: Tanel Jakobsoo Date: Tue, 10 Dec 2013 16:47:54 +0200 Subject: [PATCH] Initial commit with wysihtml5x v0.4.0-beta2 --- .gitignore | 18 + Gemfile | 4 + LICENSE.txt | 22 + README.md | 78 + Rakefile | 1 + lib/wysihtml5x/rails.rb | 9 + lib/wysihtml5x/rails/version.rb | 5 + .../javascripts/parser_rules/advanced.js | 553 + .../parser_rules/advanced_unwrap.js | 649 ++ .../assets/javascripts/parser_rules/simple.js | 32 + .../assets/javascripts/wysihtml5x-wotools.js | 8198 +++++++++++++++ vendor/assets/javascripts/wysihtml5x.js | 8889 +++++++++++++++++ vendor/assets/stylesheets/wysihtml5x.css | 133 + wysihtml5x-rails.gemspec | 25 + 14 files changed, 18616 insertions(+) create mode 100644 .gitignore create mode 100644 Gemfile create mode 100644 LICENSE.txt create mode 100644 README.md create mode 100644 Rakefile create mode 100644 lib/wysihtml5x/rails.rb create mode 100644 lib/wysihtml5x/rails/version.rb create mode 100644 vendor/assets/javascripts/parser_rules/advanced.js create mode 100644 vendor/assets/javascripts/parser_rules/advanced_unwrap.js create mode 100644 vendor/assets/javascripts/parser_rules/simple.js create mode 100644 vendor/assets/javascripts/wysihtml5x-wotools.js create mode 100644 vendor/assets/javascripts/wysihtml5x.js create mode 100644 vendor/assets/stylesheets/wysihtml5x.css create mode 100644 wysihtml5x-rails.gemspec diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..a955cfa --- /dev/null +++ b/.gitignore @@ -0,0 +1,18 @@ +*.gem +*.rbc +.bundle +.config +.yardoc +Gemfile.lock +InstalledFiles +_yardoc +coverage +doc/ +lib/bundler/man +pkg +rdoc +spec/reports +test/tmp +test/version_tmp +tmp +.DS_Store diff --git a/Gemfile b/Gemfile new file mode 100644 index 0000000..afe860f --- /dev/null +++ b/Gemfile @@ -0,0 +1,4 @@ +source 'https://rubygems.org' + +# Specify your gem's dependencies in wysihtml5x-rails.gemspec +gemspec diff --git a/LICENSE.txt b/LICENSE.txt new file mode 100644 index 0000000..31620d6 --- /dev/null +++ b/LICENSE.txt @@ -0,0 +1,22 @@ +Copyright (c) 2013 Tanel Jakobsoo + +MIT License + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/README.md b/README.md new file mode 100644 index 0000000..7632af1 --- /dev/null +++ b/README.md @@ -0,0 +1,78 @@ +# wysihtml5x for Rails + +[Edicy/wysihtml5x](http://edicy.github.io/wysihtml5/) is an extended and less strict approach on [xing/wysihtml5](http://xing.github.io/wysihtml5/) open source rich text editor based on HTML5 technology. + +This gem adds wysihtml5x to Rails assets pipeline. + +## Installation + +Add this line to your application's Gemfile: + +```ruby +gem 'wysihtml5x-rails' +``` + +Or you can install from latest build: + +```ruby +gem 'wysihtml5x-rails', :git => 'https://github.com/Edicy/wysihtml5x-rails.git' +``` + +And then execute: + +```sh +bundle +``` + +Or install it yourself as: + +```sh +$ gem install wysihtml5x-rails +``` + +## Usage + +Require it in your JS manifest's file `application.js`: + +```js +//= require wysihtml5x +``` + +or if you need pure wysihtml functionality without toolbar: + +```js +//= require wysihtml5x-wotools +``` + +Additionally include predefined `simple`, `advanced` or `advanced_unwrap` parsing rules in your `application.js`: + +```js +//= require parser_rules/advanced_unwrap +``` + +Additionally include predefined `wysihtml5x` stiles in your `application.css.scss` file: + +```scss +*= require wysihtml5x +``` + +The simple initialise: + +```html + +``` + +## Contributing + +1. Fork it +2. Create your feature branch (`git checkout -b my-new-feature`) +3. Commit your changes (`git commit -am 'Add some feature'`) +4. Push to the branch (`git push origin my-new-feature`) +5. Create new Pull Request diff --git a/Rakefile b/Rakefile new file mode 100644 index 0000000..2995527 --- /dev/null +++ b/Rakefile @@ -0,0 +1 @@ +require "bundler/gem_tasks" diff --git a/lib/wysihtml5x/rails.rb b/lib/wysihtml5x/rails.rb new file mode 100644 index 0000000..ae551a5 --- /dev/null +++ b/lib/wysihtml5x/rails.rb @@ -0,0 +1,9 @@ +require "wysihtml5x/rails/version" + +module Wysihtml5x + module Rails + class Engine < ::Rails::Engine + isolate_namespace Wysihtml5x::Rails + end + end +end diff --git a/lib/wysihtml5x/rails/version.rb b/lib/wysihtml5x/rails/version.rb new file mode 100644 index 0000000..1c02fdf --- /dev/null +++ b/lib/wysihtml5x/rails/version.rb @@ -0,0 +1,5 @@ +module Wysihtml5x + module Rails + VERSION = "0.4.0" + end +end diff --git a/vendor/assets/javascripts/parser_rules/advanced.js b/vendor/assets/javascripts/parser_rules/advanced.js new file mode 100644 index 0000000..bcbea6b --- /dev/null +++ b/vendor/assets/javascripts/parser_rules/advanced.js @@ -0,0 +1,553 @@ +/** + * Full HTML5 compatibility rule set + * These rules define which tags and CSS classes are supported and which tags should be specially treated. + * + * Examples based on this rule set: + * + * foo + * ... becomes ... + * foo + * + * + * ... becomes ... + * + * + *
foo
+ * ... becomes ... + *
foo
+ * + * foo + * ... becomes ... + * foo + * + * foo
bar + * ... becomes ... + * foo
bar + * + *
hello
+ * ... becomes ... + *
hello
+ * + *
hello
+ * ... becomes ... + *
hello
+ */ +var wysihtml5ParserRules = { + /** + * CSS Class white-list + * Following CSS classes won't be removed when parsed by the wysihtml5 HTML parser + */ + "classes": { + "wysiwyg-clear-both": 1, + "wysiwyg-clear-left": 1, + "wysiwyg-clear-right": 1, + "wysiwyg-color-aqua": 1, + "wysiwyg-color-black": 1, + "wysiwyg-color-blue": 1, + "wysiwyg-color-fuchsia": 1, + "wysiwyg-color-gray": 1, + "wysiwyg-color-green": 1, + "wysiwyg-color-lime": 1, + "wysiwyg-color-maroon": 1, + "wysiwyg-color-navy": 1, + "wysiwyg-color-olive": 1, + "wysiwyg-color-purple": 1, + "wysiwyg-color-red": 1, + "wysiwyg-color-silver": 1, + "wysiwyg-color-teal": 1, + "wysiwyg-color-white": 1, + "wysiwyg-color-yellow": 1, + "wysiwyg-float-left": 1, + "wysiwyg-float-right": 1, + "wysiwyg-font-size-large": 1, + "wysiwyg-font-size-larger": 1, + "wysiwyg-font-size-medium": 1, + "wysiwyg-font-size-small": 1, + "wysiwyg-font-size-smaller": 1, + "wysiwyg-font-size-x-large": 1, + "wysiwyg-font-size-x-small": 1, + "wysiwyg-font-size-xx-large": 1, + "wysiwyg-font-size-xx-small": 1, + "wysiwyg-text-align-center": 1, + "wysiwyg-text-align-justify": 1, + "wysiwyg-text-align-left": 1, + "wysiwyg-text-align-right": 1 + }, + /** + * Tag list + * + * The following options are available: + * + * - add_class: converts and deletes the given HTML4 attribute (align, clear, ...) via the given method to a css class + * The following methods are implemented in wysihtml5.dom.parse: + * - align_text: converts align attribute values (right/left/center/justify) to their corresponding css class "wysiwyg-text-align-*") + *

foo

... becomes ...

class="wysiwyg-text-align-center">foo

+ * - clear_br: converts clear attribute values left/right/all/both to their corresponding css class "wysiwyg-clear-*" + *
... becomes ...
+ * - align_img: converts align attribute values (right/left) on to their corresponding css class "wysiwyg-float-*" + * + * - remove: removes the element and its content + * + * - rename_tag: renames the element to the given tag + * + * - set_class: adds the given class to the element (note: make sure that the class is in the "classes" white list above) + * + * - set_attributes: sets/overrides the given attributes + * + * - check_attributes: checks the given HTML attribute via the given method + * - url: allows only valid urls (starting with http:// or https://) + * - src: allows something like "/foobar.jpg", "http://google.com", ... + * - href: allows something like "mailto:bert@foo.com", "http://google.com", "/foobar.jpg" + * - alt: strips unwanted characters. if the attribute is not set, then it gets set (to ensure valid and compatible HTML) + * - numbers: ensures that the attribute only contains numeric characters + */ + "tags": { + "tr": { + "add_class": { + "align": "align_text" + } + }, + "strike": { + "remove": 1 + }, + "form": { + "rename_tag": "div" + }, + "rt": { + "rename_tag": "span" + }, + "code": {}, + "acronym": { + "rename_tag": "span" + }, + "br": { + "add_class": { + "clear": "clear_br" + } + }, + "details": { + "rename_tag": "div" + }, + "h4": { + "add_class": { + "align": "align_text" + } + }, + "em": {}, + "title": { + "remove": 1 + }, + "multicol": { + "rename_tag": "div" + }, + "figure": { + "rename_tag": "div" + }, + "xmp": { + "rename_tag": "span" + }, + "small": { + "rename_tag": "span", + "set_class": "wysiwyg-font-size-smaller" + }, + "area": { + "remove": 1 + }, + "time": { + "rename_tag": "span" + }, + "dir": { + "rename_tag": "ul" + }, + "bdi": { + "rename_tag": "span" + }, + "command": { + "remove": 1 + }, + "ul": {}, + "progress": { + "rename_tag": "span" + }, + "dfn": { + "rename_tag": "span" + }, + "iframe": { + "remove": 1 + }, + "figcaption": { + "rename_tag": "div" + }, + "a": { + "check_attributes": { + "href": "url" // if you compiled master manually then change this from 'url' to 'href' + }, + "set_attributes": { + "rel": "nofollow", + "target": "_blank" + } + }, + "img": { + "check_attributes": { + "width": "numbers", + "alt": "alt", + "src": "url", // if you compiled master manually then change this from 'url' to 'src' + "height": "numbers" + }, + "add_class": { + "align": "align_img" + } + }, + "rb": { + "rename_tag": "span" + }, + "footer": { + "rename_tag": "div" + }, + "noframes": { + "remove": 1 + }, + "abbr": { + "rename_tag": "span" + }, + "u": {}, + "bgsound": { + "remove": 1 + }, + "sup": { + "rename_tag": "span" + }, + "address": { + "rename_tag": "div" + }, + "basefont": { + "remove": 1 + }, + "nav": { + "rename_tag": "div" + }, + "h1": { + "add_class": { + "align": "align_text" + } + }, + "head": { + "remove": 1 + }, + "tbody": { + "add_class": { + "align": "align_text" + } + }, + "dd": { + "rename_tag": "div" + }, + "s": { + "rename_tag": "span" + }, + "li": {}, + "td": { + "check_attributes": { + "rowspan": "numbers", + "colspan": "numbers" + }, + "add_class": { + "align": "align_text" + } + }, + "object": { + "remove": 1 + }, + "div": { + "add_class": { + "align": "align_text" + } + }, + "option": { + "rename_tag": "span" + }, + "select": { + "rename_tag": "span" + }, + "i": {}, + "track": { + "remove": 1 + }, + "wbr": { + "remove": 1 + }, + "fieldset": { + "rename_tag": "div" + }, + "big": { + "rename_tag": "span", + "set_class": "wysiwyg-font-size-larger" + }, + "button": { + "rename_tag": "span" + }, + "noscript": { + "remove": 1 + }, + "svg": { + "remove": 1 + }, + "input": { + "remove": 1 + }, + "table": {}, + "keygen": { + "remove": 1 + }, + "h5": { + "add_class": { + "align": "align_text" + } + }, + "meta": { + "remove": 1 + }, + "map": { + "rename_tag": "div" + }, + "isindex": { + "remove": 1 + }, + "mark": { + "rename_tag": "span" + }, + "caption": { + "add_class": { + "align": "align_text" + } + }, + "tfoot": { + "add_class": { + "align": "align_text" + } + }, + "base": { + "remove": 1 + }, + "video": { + "remove": 1 + }, + "strong": {}, + "canvas": { + "remove": 1 + }, + "output": { + "rename_tag": "span" + }, + "marquee": { + "rename_tag": "span" + }, + "b": {}, + "q": { + "check_attributes": { + "cite": "url" + } + }, + "applet": { + "remove": 1 + }, + "span": {}, + "rp": { + "rename_tag": "span" + }, + "spacer": { + "remove": 1 + }, + "source": { + "remove": 1 + }, + "aside": { + "rename_tag": "div" + }, + "frame": { + "remove": 1 + }, + "section": { + "rename_tag": "div" + }, + "body": { + "rename_tag": "div" + }, + "ol": {}, + "nobr": { + "rename_tag": "span" + }, + "html": { + "rename_tag": "div" + }, + "summary": { + "rename_tag": "span" + }, + "var": { + "rename_tag": "span" + }, + "del": { + "remove": 1 + }, + "blockquote": { + "check_attributes": { + "cite": "url" + } + }, + "style": { + "remove": 1 + }, + "device": { + "remove": 1 + }, + "meter": { + "rename_tag": "span" + }, + "h3": { + "add_class": { + "align": "align_text" + } + }, + "textarea": { + "rename_tag": "span" + }, + "embed": { + "remove": 1 + }, + "hgroup": { + "rename_tag": "div" + }, + "font": { + "rename_tag": "span", + "add_class": { + "size": "size_font" + } + }, + "tt": { + "rename_tag": "span" + }, + "noembed": { + "remove": 1 + }, + "thead": { + "add_class": { + "align": "align_text" + } + }, + "blink": { + "rename_tag": "span" + }, + "plaintext": { + "rename_tag": "span" + }, + "xml": { + "remove": 1 + }, + "h6": { + "add_class": { + "align": "align_text" + } + }, + "param": { + "remove": 1 + }, + "th": { + "check_attributes": { + "rowspan": "numbers", + "colspan": "numbers" + }, + "add_class": { + "align": "align_text" + } + }, + "legend": { + "rename_tag": "span" + }, + "hr": {}, + "label": { + "rename_tag": "span" + }, + "dl": { + "rename_tag": "div" + }, + "kbd": { + "rename_tag": "span" + }, + "listing": { + "rename_tag": "div" + }, + "dt": { + "rename_tag": "span" + }, + "nextid": { + "remove": 1 + }, + "pre": {}, + "center": { + "rename_tag": "div", + "set_class": "wysiwyg-text-align-center" + }, + "audio": { + "remove": 1 + }, + "datalist": { + "rename_tag": "span" + }, + "samp": { + "rename_tag": "span" + }, + "col": { + "remove": 1 + }, + "article": { + "rename_tag": "div" + }, + "cite": {}, + "link": { + "remove": 1 + }, + "script": { + "remove": 1 + }, + "bdo": { + "rename_tag": "span" + }, + "menu": { + "rename_tag": "ul" + }, + "colgroup": { + "remove": 1 + }, + "ruby": { + "rename_tag": "span" + }, + "h2": { + "add_class": { + "align": "align_text" + } + }, + "ins": { + "rename_tag": "span" + }, + "p": { + "add_class": { + "align": "align_text" + } + }, + "sub": { + "rename_tag": "span" + }, + "comment": { + "remove": 1 + }, + "frameset": { + "remove": 1 + }, + "optgroup": { + "rename_tag": "span" + }, + "header": { + "rename_tag": "div" + } + } +}; \ No newline at end of file diff --git a/vendor/assets/javascripts/parser_rules/advanced_unwrap.js b/vendor/assets/javascripts/parser_rules/advanced_unwrap.js new file mode 100644 index 0000000..69e523e --- /dev/null +++ b/vendor/assets/javascripts/parser_rules/advanced_unwrap.js @@ -0,0 +1,649 @@ +/** + * Full HTML5 compatibility rule set + * These rules define which tags and CSS classes are supported and which tags should be specially treated. + * + * Examples based on this rule set: + * + * foo + * ... becomes ... + * foo + * + * + * ... becomes ... + * + * + *
foo
+ * ... becomes ... + *
foo
+ * + * foo + * ... becomes ... + * foo + * + * foo
bar + * ... becomes ... + * foo
bar + * + *
hello
+ * ... becomes ... + *
hello
+ * + *
hello
+ * ... becomes ... + *
hello
+ */ +var wysihtml5ParserRules = { + /** + * CSS Class white-list + * Following CSS classes won't be removed when parsed by the wysihtml5 HTML parser + */ + "classes": { + "wysiwyg-clear-both": 1, + "wysiwyg-clear-left": 1, + "wysiwyg-clear-right": 1, + "wysiwyg-color-aqua": 1, + "wysiwyg-color-black": 1, + "wysiwyg-color-blue": 1, + "wysiwyg-color-fuchsia": 1, + "wysiwyg-color-gray": 1, + "wysiwyg-color-green": 1, + "wysiwyg-color-lime": 1, + "wysiwyg-color-maroon": 1, + "wysiwyg-color-navy": 1, + "wysiwyg-color-olive": 1, + "wysiwyg-color-purple": 1, + "wysiwyg-color-red": 1, + "wysiwyg-color-silver": 1, + "wysiwyg-color-teal": 1, + "wysiwyg-color-white": 1, + "wysiwyg-color-yellow": 1, + "wysiwyg-float-left": 1, + "wysiwyg-float-right": 1, + "wysiwyg-font-size-large": 1, + "wysiwyg-font-size-larger": 1, + "wysiwyg-font-size-medium": 1, + "wysiwyg-font-size-small": 1, + "wysiwyg-font-size-smaller": 1, + "wysiwyg-font-size-x-large": 1, + "wysiwyg-font-size-x-small": 1, + "wysiwyg-font-size-xx-large": 1, + "wysiwyg-font-size-xx-small": 1, + "wysiwyg-text-align-center": 1, + "wysiwyg-text-align-justify": 1, + "wysiwyg-text-align-left": 1, + "wysiwyg-text-align-right": 1 + }, + + + "type_definitions": { + + "alignment_object": { + "classes": { + "wysiwyg-text-align-center": 1, + "wysiwyg-text-align-justify": 1, + "wysiwyg-text-align-left": 1, + "wysiwyg-text-align-right": 1, + "wysiwyg-float-left": 1, + "wysiwyg-float-right": 1 + }, + "styles": { + "float": ["left", "right"], + "textAlign": ["left", "right", "center"] + } + }, + + "valid_image_src": { + "attrs": { + "src": /^[^data\:]/i + } + }, + + "text_color_object": { + "styles": { + "color": true, + "background-color": true + } + }, + + "text_fontsize_object": { + "styles": { + "font-size": true + } + }, + + "text_formatting_object": { + "classes": { + "wysiwyg-color-aqua": 1, + "wysiwyg-color-black": 1, + "wysiwyg-color-blue": 1, + "wysiwyg-color-fuchsia": 1, + "wysiwyg-color-gray": 1, + "wysiwyg-color-green": 1, + "wysiwyg-color-lime": 1, + "wysiwyg-color-maroon": 1, + "wysiwyg-color-navy": 1, + "wysiwyg-color-olive": 1, + "wysiwyg-color-purple": 1, + "wysiwyg-color-red": 1, + "wysiwyg-color-silver": 1, + "wysiwyg-color-teal": 1, + "wysiwyg-color-white": 1, + "wysiwyg-color-yellow": 1, + "wysiwyg-font-size-large": 1, + "wysiwyg-font-size-larger": 1, + "wysiwyg-font-size-medium": 1, + "wysiwyg-font-size-small": 1, + "wysiwyg-font-size-smaller": 1, + "wysiwyg-font-size-x-large": 1, + "wysiwyg-font-size-x-small": 1, + "wysiwyg-font-size-xx-large": 1, + "wysiwyg-font-size-xx-small": 1 + } + } + }, + + /** + * Tag list + * + * The following options are available: + * + * - add_class: converts and deletes the given HTML4 attribute (align, clear, ...) via the given method to a css class + * The following methods are implemented in wysihtml5.dom.parse: + * - align_text: converts align attribute values (right/left/center/justify) to their corresponding css class "wysiwyg-text-align-*") + *

foo

... becomes ...

class="wysiwyg-text-align-center">foo

+ * - clear_br: converts clear attribute values left/right/all/both to their corresponding css class "wysiwyg-clear-*" + *
... becomes ...
+ * - align_img: converts align attribute values (right/left) on to their corresponding css class "wysiwyg-float-*" + * + * - remove: removes the element and its content + * + * - unwrap removes element but leaves content + * + * - rename_tag: renames the element to the given tag + * + * - set_class: adds the given class to the element (note: make sure that the class is in the "classes" white list above) + * + * - set_attributes: sets/overrides the given attributes + * + * - check_attributes: checks the given HTML attribute via the given method + * - url: allows only valid urls (starting with http:// or https://) + * - src: allows something like "/foobar.jpg", "http://google.com", ... + * - href: allows something like "mailto:bert@foo.com", "http://google.com", "/foobar.jpg" + * - alt: strips unwanted characters. if the attribute is not set, then it gets set (to ensure valid and compatible HTML) + * - numbers: ensures that the attribute only contains numeric characters + */ + "tags": { + "tr": { + "add_class": { + "align": "align_text" + } + }, + "strike": { + "unwrap": 1 + }, + "form": { + "unwrap": 1 + }, + "rt": { + "rename_tag": "span" + }, + "code": {}, + "acronym": { + "rename_tag": "span" + }, + "br": { + "add_class": { + "clear": "clear_br" + } + }, + "details": { + "unwrap": 1 + }, + "h4": { + "add_class": { + "align": "align_text" + } + }, + "em": {}, + "title": { + "remove": 1 + }, + "multicol": { + "unwrap": 1 + }, + "figure": { + "unwrap": 1 + }, + "xmp": { + "unwrap": 1 + }, + "small": { + "rename_tag": "span", + "set_class": "wysiwyg-font-size-smaller" + }, + "area": { + "remove": 1 + }, + "time": { + "unwrap": 1 + }, + "dir": { + "rename_tag": "ul" + }, + "bdi": { + "unwrap": 1 + }, + "command": { + "unwrap": 1 + }, + "ul": {}, + "progress": { + "rename_tag": "span" + }, + "dfn": { + "unwrap": 1 + }, + "iframe": { + "remove": 1 + }, + "figcaption": { + "unwrap": 1 + }, + "a": { + "check_attributes": { + "href": "href" // if you compiled master manually then change this from 'url' to 'href' + }, + "set_attributes": { + "rel": "nofollow", + "target": "_blank" + } + }, + "img": { + "one_of_type": { + "valid_image_src": 1 + }, + "check_attributes": { + "width": "numbers", + "alt": "alt", + "src": "src", // if you compiled master manually then change this from 'url' to 'src' + "height": "numbers" + }, + "add_class": { + "align": "align_img" + } + }, + "rb": { + "unwrap": 1 + }, + "footer": { + "rename_tag": "div" + }, + "noframes": { + "remove": 1 + }, + "abbr": { + "unwrap": 1 + }, + "u": {}, + "bgsound": { + "remove": 1 + }, + "sup": { + "unwrap": 1 + }, + "address": { + "unwrap": 1 + }, + "basefont": { + "remove": 1 + }, + "nav": { + "unwrap": 1 + }, + "h1": { + "add_class": { + "align": "align_text" + } + }, + "head": { + "unwrap": 1 + }, + "tbody": { + "add_class": { + "align": "align_text" + } + }, + "dd": { + "unwrap": 1 + }, + "s": { + "unwrap": 1 + }, + "li": {}, + "td": { + "check_attributes": { + "rowspan": "numbers", + "colspan": "numbers" + }, + "add_class": { + "align": "align_text" + } + }, + "object": { + "remove": 1 + }, + + "div": { + "one_of_type": { + "alignment_object": 1, + }, + "remove_action": "unwrap", + "keep_styles": { + "textAlign": 1, + "float": 1 + }, + "add_class": { + "align": "align_text" + } + }, + + "option": { + "remove":1 + }, + "select": { + "remove":1 + }, + "i": {}, + "track": { + "remove": 1 + }, + "wbr": { + "remove": 1 + }, + "fieldset": { + "unwrap": 1 + }, + "big": { + "rename_tag": "span", + "set_class": "wysiwyg-font-size-larger" + }, + "button": { + "unwrap": 1 + }, + "noscript": { + "remove": 1 + }, + "svg": { + "remove": 1 + }, + "input": { + "remove": 1 + }, + "table": {}, + "keygen": { + "remove": 1 + }, + "h5": { + "add_class": { + "align": "align_text" + } + }, + "meta": { + "remove": 1 + }, + "map": { + "remove": 1 + }, + "isindex": { + "remove": 1 + }, + "mark": { + "unwrap": 1 + }, + "caption": { + "add_class": { + "align": "align_text" + } + }, + "tfoot": { + "add_class": { + "align": "align_text" + } + }, + "base": { + "remove": 1 + }, + "video": { + "remove": 1 + }, + "strong": {}, + "canvas": { + "remove": 1 + }, + "output": { + "unwrap": 1 + }, + "marquee": { + "unwrap": 1 + }, + "b": {}, + "q": { + "check_attributes": { + "cite": "url" + } + }, + "applet": { + "remove": 1 + }, + "span": { + "one_of_type": { + "text_formatting_object": 1, + "text_color_object": 1, + "text_fontsize_object": 1 + }, + "keep_styles": { + "color": 1, + "backgroundColor": 1, + "fontSize": 1 + }, + "remove_action": "unwrap" + }, + "rp": { + "unwrap": 1 + }, + "spacer": { + "remove": 1 + }, + "source": { + "remove": 1 + }, + "aside": { + "rename_tag": "div" + }, + "frame": { + "remove": 1 + }, + "section": { + "rename_tag": "div" + }, + "body": { + "unwrap": 1 + }, + "ol": {}, + "nobr": { + "unwrap": 1 + }, + "html": { + "unwrap": 1 + }, + "summary": { + "unwrap": 1 + }, + "var": { + "unwrap": 1 + }, + "del": { + "unwrap": 1 + }, + "blockquote": { + "check_attributes": { + "cite": "url" + } + }, + "style": { + "remove": 1 + }, + "device": { + "remove": 1 + }, + "meter": { + "unwrap": 1 + }, + "h3": { + "add_class": { + "align": "align_text" + } + }, + "textarea": { + "unwrap": 1 + }, + "embed": { + "remove": 1 + }, + "hgroup": { + "unwrap": 1 + }, + "font": { + "rename_tag": "span", + "add_class": { + "size": "size_font" + } + }, + "tt": { + "unwrap": 1 + }, + "noembed": { + "remove": 1 + }, + "thead": { + "add_class": { + "align": "align_text" + } + }, + "blink": { + "unwrap": 1 + }, + "plaintext": { + "unwrap": 1 + }, + "xml": { + "remove": 1 + }, + "h6": { + "add_class": { + "align": "align_text" + } + }, + "param": { + "remove": 1 + }, + "th": { + "check_attributes": { + "rowspan": "numbers", + "colspan": "numbers" + }, + "add_class": { + "align": "align_text" + } + }, + "legend": { + "unwrap": 1 + }, + "hr": {}, + "label": { + "unwrap": 1 + }, + "dl": { + "unwrap": 1 + }, + "kbd": { + "unwrap": 1 + }, + "listing": { + "unwrap": 1 + }, + "dt": { + "unwrap": 1 + }, + "nextid": { + "remove": 1 + }, + "pre": {}, + "center": { + "rename_tag": "div", + "set_class": "wysiwyg-text-align-center" + }, + "audio": { + "remove": 1 + }, + "datalist": { + "unwrap": 1 + }, + "samp": { + "unwrap": 1 + }, + "col": { + "remove": 1 + }, + "article": { + "rename_tag": "div" + }, + "cite": {}, + "link": { + "remove": 1 + }, + "script": { + "remove": 1 + }, + "bdo": { + "unwrap": 1 + }, + "menu": { + "rename_tag": "ul" + }, + "colgroup": { + "remove": 1 + }, + "ruby": { + "unwrap": 1 + }, + "h2": { + "add_class": { + "align": "align_text" + } + }, + "ins": { + "unwrap": 1 + }, + "p": { + "add_class": { + "align": "align_text" + } + }, + "sub": { + "unwrap": 1 + }, + "comment": { + "remove": 1 + }, + "frameset": { + "remove": 1 + }, + "optgroup": { + "unwrap": 1 + }, + "header": { + "rename_tag": "div" + } + } +}; \ No newline at end of file diff --git a/vendor/assets/javascripts/parser_rules/simple.js b/vendor/assets/javascripts/parser_rules/simple.js new file mode 100644 index 0000000..63a2e8b --- /dev/null +++ b/vendor/assets/javascripts/parser_rules/simple.js @@ -0,0 +1,32 @@ +/** + * Very simple basic rule set + * + * Allows + * , , , ,

,

, ,
, ,
    ,
      ,
    • + * + * For a proper documentation of the format check advanced.js + */ +var wysihtml5ParserRules = { + tags: { + strong: {}, + b: {}, + i: {}, + em: {}, + br: {}, + p: {}, + div: {}, + span: {}, + ul: {}, + ol: {}, + li: {}, + a: { + set_attributes: { + target: "_blank", + rel: "nofollow" + }, + check_attributes: { + href: "url" // important to avoid XSS + } + } + } +}; \ No newline at end of file diff --git a/vendor/assets/javascripts/wysihtml5x-wotools.js b/vendor/assets/javascripts/wysihtml5x-wotools.js new file mode 100644 index 0000000..bb46fd7 --- /dev/null +++ b/vendor/assets/javascripts/wysihtml5x-wotools.js @@ -0,0 +1,8198 @@ +/** + * @license wysihtml5x v0.4.0-beta2 + * https://github.com/Edicy/wysihtml5 + * + * Author: Christopher Blum (https://github.com/tiff) + * Secondary author of extended features: Oliver Pulges (https://github.com/pulges) + * + * Copyright (C) 2012 XING AG + * Licensed under the MIT license (MIT) + * + */ +var wysihtml5 = { + version: "0.4.0-beta2", + + // namespaces + commands: {}, + dom: {}, + quirks: {}, + toolbar: {}, + lang: {}, + selection: {}, + views: {}, + + INVISIBLE_SPACE: "\uFEFF", + + EMPTY_FUNCTION: function() {}, + + ELEMENT_NODE: 1, + TEXT_NODE: 3, + + BACKSPACE_KEY: 8, + ENTER_KEY: 13, + ESCAPE_KEY: 27, + SPACE_KEY: 32, + DELETE_KEY: 46 +};/* + Rangy, a cross-browser JavaScript range and selection library + http://code.google.com/p/rangy/ + + Copyright 2012, Tim Down + Licensed under the MIT license. + Version: 1.2.3 + Build date: 26 February 2012 +*/ +window.rangy=function(){function l(p,u){var w=typeof p[u];return w=="function"||!!(w=="object"&&p[u])||w=="unknown"}function K(p,u){return!!(typeof p[u]=="object"&&p[u])}function H(p,u){return typeof p[u]!="undefined"}function I(p){return function(u,w){for(var B=w.length;B--;)if(!p(u,w[B]))return false;return true}}function z(p){return p&&A(p,x)&&v(p,t)}function C(p){window.alert("Rangy not supported in your browser. Reason: "+p);c.initialized=true;c.supported=false}function N(){if(!c.initialized){var p, +u=false,w=false;if(l(document,"createRange")){p=document.createRange();if(A(p,n)&&v(p,i))u=true;p.detach()}if((p=K(document,"body")?document.body:document.getElementsByTagName("body")[0])&&l(p,"createTextRange")){p=p.createTextRange();if(z(p))w=true}!u&&!w&&C("Neither Range nor TextRange are implemented");c.initialized=true;c.features={implementsDomRange:u,implementsTextRange:w};u=k.concat(f);w=0;for(p=u.length;w["+c.childNodes.length+"]":c.nodeName}function n(c){this._next=this.root=c}function t(c,f){this.node=c;this.offset=f}function x(c){this.code=this[c]; +this.codeName=c;this.message="DOMException: "+this.codeName}var A=l.util;A.areHostMethods(document,["createDocumentFragment","createElement","createTextNode"])||K.fail("document missing a Node creation method");A.isHostMethod(document,"getElementsByTagName")||K.fail("document missing getElementsByTagName method");var q=document.createElement("div");A.areHostMethods(q,["insertBefore","appendChild","cloneNode"])||K.fail("Incomplete Element implementation");A.isHostProperty(q,"innerHTML")||K.fail("Element is missing innerHTML property"); +q=document.createTextNode("test");A.areHostMethods(q,["splitText","deleteData","insertData","appendData","cloneNode"])||K.fail("Incomplete Text Node implementation");var v=function(c,f){for(var k=c.length;k--;)if(c[k]===f)return true;return false};n.prototype={_current:null,hasNext:function(){return!!this._next},next:function(){var c=this._current=this._next,f;if(this._current)if(f=c.firstChild)this._next=f;else{for(f=null;c!==this.root&&!(f=c.nextSibling);)c=c.parentNode;this._next=f}return this._current}, +detach:function(){this._current=this._next=this.root=null}};t.prototype={equals:function(c){return this.node===c.node&this.offset==c.offset},inspect:function(){return"[DomPosition("+i(this.node)+":"+this.offset+")]"}};x.prototype={INDEX_SIZE_ERR:1,HIERARCHY_REQUEST_ERR:3,WRONG_DOCUMENT_ERR:4,NO_MODIFICATION_ALLOWED_ERR:7,NOT_FOUND_ERR:8,NOT_SUPPORTED_ERR:9,INVALID_STATE_ERR:11};x.prototype.toString=function(){return this.message};l.dom={arrayContains:v,isHtmlNamespace:function(c){var f;return typeof c.namespaceURI== +"undefined"||(f=c.namespaceURI)===null||f=="http://www.w3.org/1999/xhtml"},parentElement:function(c){c=c.parentNode;return c.nodeType==1?c:null},getNodeIndex:H,getNodeLength:function(c){var f;return C(c)?c.length:(f=c.childNodes)?f.length:0},getCommonAncestor:I,isAncestorOf:function(c,f,k){for(f=k?f:f.parentNode;f;)if(f===c)return true;else f=f.parentNode;return false},getClosestAncestorIn:z,isCharacterDataNode:C,insertAfter:N,splitDataNode:function(c,f){var k=c.cloneNode(false);k.deleteData(0,f); +c.deleteData(f,c.length-f);N(k,c);return k},getDocument:O,getWindow:function(c){c=O(c);if(typeof c.defaultView!="undefined")return c.defaultView;else if(typeof c.parentWindow!="undefined")return c.parentWindow;else throw Error("Cannot get a window object for node");},getIframeWindow:function(c){if(typeof c.contentWindow!="undefined")return c.contentWindow;else if(typeof c.contentDocument!="undefined")return c.contentDocument.defaultView;else throw Error("getIframeWindow: No Window object found for iframe element"); +},getIframeDocument:function(c){if(typeof c.contentDocument!="undefined")return c.contentDocument;else if(typeof c.contentWindow!="undefined")return c.contentWindow.document;else throw Error("getIframeWindow: No Document object found for iframe element");},getBody:function(c){return A.isHostObject(c,"body")?c.body:c.getElementsByTagName("body")[0]},getRootContainer:function(c){for(var f;f=c.parentNode;)c=f;return c},comparePoints:function(c,f,k,r){var L;if(c==k)return f===r?0:f=e.childNodes.length?e.appendChild(a):e.insertBefore(a,e.childNodes[j]);return o}function O(a){for(var e,j,o=H(a.range).createDocumentFragment();j=a.next();){e=a.isPartiallySelectedSubtree();j=j.cloneNode(!e);if(e){e=a.getSubtreeIterator();j.appendChild(O(e));e.detach(true)}if(j.nodeType==10)throw new S("HIERARCHY_REQUEST_ERR");o.appendChild(j)}return o}function i(a,e,j){var o,E;for(j=j||{stop:false};o=a.next();)if(a.isPartiallySelectedSubtree())if(e(o)=== +false){j.stop=true;return}else{o=a.getSubtreeIterator();i(o,e,j);o.detach(true);if(j.stop)return}else for(o=g.createIterator(o);E=o.next();)if(e(E)===false){j.stop=true;return}}function n(a){for(var e;a.next();)if(a.isPartiallySelectedSubtree()){e=a.getSubtreeIterator();n(e);e.detach(true)}else a.remove()}function t(a){for(var e,j=H(a.range).createDocumentFragment(),o;e=a.next();){if(a.isPartiallySelectedSubtree()){e=e.cloneNode(false);o=a.getSubtreeIterator();e.appendChild(t(o));o.detach(true)}else a.remove(); +if(e.nodeType==10)throw new S("HIERARCHY_REQUEST_ERR");j.appendChild(e)}return j}function x(a,e,j){var o=!!(e&&e.length),E,T=!!j;if(o)E=RegExp("^("+e.join("|")+")$");var m=[];i(new q(a,false),function(s){if((!o||E.test(s.nodeType))&&(!T||j(s)))m.push(s)});return m}function A(a){return"["+(typeof a.getName=="undefined"?"Range":a.getName())+"("+g.inspectNode(a.startContainer)+":"+a.startOffset+", "+g.inspectNode(a.endContainer)+":"+a.endOffset+")]"}function q(a,e){this.range=a;this.clonePartiallySelectedTextNodes= +e;if(!a.collapsed){this.sc=a.startContainer;this.so=a.startOffset;this.ec=a.endContainer;this.eo=a.endOffset;var j=a.commonAncestorContainer;if(this.sc===this.ec&&g.isCharacterDataNode(this.sc)){this.isSingleCharacterDataNode=true;this._first=this._last=this._next=this.sc}else{this._first=this._next=this.sc===j&&!g.isCharacterDataNode(this.sc)?this.sc.childNodes[this.so]:g.getClosestAncestorIn(this.sc,j,true);this._last=this.ec===j&&!g.isCharacterDataNode(this.ec)?this.ec.childNodes[this.eo-1]:g.getClosestAncestorIn(this.ec, +j,true)}}}function v(a){this.code=this[a];this.codeName=a;this.message="RangeException: "+this.codeName}function c(a,e,j){this.nodes=x(a,e,j);this._next=this.nodes[0];this._position=0}function f(a){return function(e,j){for(var o,E=j?e:e.parentNode;E;){o=E.nodeType;if(g.arrayContains(a,o))return E;E=E.parentNode}return null}}function k(a,e){if(G(a,e))throw new v("INVALID_NODE_TYPE_ERR");}function r(a){if(!a.startContainer)throw new S("INVALID_STATE_ERR");}function L(a,e){if(!g.arrayContains(e,a.nodeType))throw new v("INVALID_NODE_TYPE_ERR"); +}function p(a,e){if(e<0||e>(g.isCharacterDataNode(a)?a.length:a.childNodes.length))throw new S("INDEX_SIZE_ERR");}function u(a,e){if(h(a,true)!==h(e,true))throw new S("WRONG_DOCUMENT_ERR");}function w(a){if(D(a,true))throw new S("NO_MODIFICATION_ALLOWED_ERR");}function B(a,e){if(!a)throw new S(e);}function V(a){return!!a.startContainer&&!!a.endContainer&&!(!g.arrayContains(ba,a.startContainer.nodeType)&&!h(a.startContainer,true))&&!(!g.arrayContains(ba,a.endContainer.nodeType)&&!h(a.endContainer, +true))&&a.startOffset<=(g.isCharacterDataNode(a.startContainer)?a.startContainer.length:a.startContainer.childNodes.length)&&a.endOffset<=(g.isCharacterDataNode(a.endContainer)?a.endContainer.length:a.endContainer.childNodes.length)}function J(a){r(a);if(!V(a))throw Error("Range error: Range is no longer valid after DOM mutation ("+a.inspect()+")");}function ca(){}function Y(a){a.START_TO_START=ia;a.START_TO_END=la;a.END_TO_END=ra;a.END_TO_START=ma;a.NODE_BEFORE=na;a.NODE_AFTER=oa;a.NODE_BEFORE_AND_AFTER= +pa;a.NODE_INSIDE=ja}function W(a){Y(a);Y(a.prototype)}function da(a,e){return function(){J(this);var j=this.startContainer,o=this.startOffset,E=this.commonAncestorContainer,T=new q(this,true);if(j!==E){j=g.getClosestAncestorIn(j,E,true);o=C(j);j=o.node;o=o.offset}i(T,w);T.reset();E=a(T);T.detach();e(this,j,o,j,o);return E}}function fa(a,e,j){function o(m,s){return function(y){r(this);L(y,$);L(d(y),ba);y=(m?z:C)(y);(s?E:T)(this,y.node,y.offset)}}function E(m,s,y){var F=m.endContainer,Q=m.endOffset; +if(s!==m.startContainer||y!==m.startOffset){if(d(s)!=d(F)||g.comparePoints(s,y,F,Q)==1){F=s;Q=y}e(m,s,y,F,Q)}}function T(m,s,y){var F=m.startContainer,Q=m.startOffset;if(s!==m.endContainer||y!==m.endOffset){if(d(s)!=d(F)||g.comparePoints(s,y,F,Q)==-1){F=s;Q=y}e(m,F,Q,s,y)}}a.prototype=new ca;l.util.extend(a.prototype,{setStart:function(m,s){r(this);k(m,true);p(m,s);E(this,m,s)},setEnd:function(m,s){r(this);k(m,true);p(m,s);T(this,m,s)},setStartBefore:o(true,true),setStartAfter:o(false,true),setEndBefore:o(true, +false),setEndAfter:o(false,false),collapse:function(m){J(this);m?e(this,this.startContainer,this.startOffset,this.startContainer,this.startOffset):e(this,this.endContainer,this.endOffset,this.endContainer,this.endOffset)},selectNodeContents:function(m){r(this);k(m,true);e(this,m,0,m,g.getNodeLength(m))},selectNode:function(m){r(this);k(m,false);L(m,$);var s=z(m);m=C(m);e(this,s.node,s.offset,m.node,m.offset)},extractContents:da(t,e),deleteContents:da(n,e),canSurroundContents:function(){J(this);w(this.startContainer); +w(this.endContainer);var m=new q(this,true),s=m._first&&K(m._first,this)||m._last&&K(m._last,this);m.detach();return!s},detach:function(){j(this)},splitBoundaries:function(){J(this);var m=this.startContainer,s=this.startOffset,y=this.endContainer,F=this.endOffset,Q=m===y;g.isCharacterDataNode(y)&&F>0&&F0&&s=g.getNodeIndex(m)&&F++;s=0}e(this,m,s,y,F)},normalizeBoundaries:function(){J(this); +var m=this.startContainer,s=this.startOffset,y=this.endContainer,F=this.endOffset,Q=function(U){var R=U.nextSibling;if(R&&R.nodeType==U.nodeType){y=U;F=U.length;U.appendData(R.data);R.parentNode.removeChild(R)}},qa=function(U){var R=U.previousSibling;if(R&&R.nodeType==U.nodeType){m=U;var sa=U.length;s=R.length;U.insertData(0,R.data);R.parentNode.removeChild(R);if(m==y){F+=s;y=m}else if(y==U.parentNode){R=g.getNodeIndex(U);if(F==R){y=U;F=sa}else F>R&&F--}}},ga=true;if(g.isCharacterDataNode(y))y.length== +F&&Q(y);else{if(F>0)(ga=y.childNodes[F-1])&&g.isCharacterDataNode(ga)&&Q(ga);ga=!this.collapsed}if(ga)if(g.isCharacterDataNode(m))s==0&&qa(m);else{if(sx";X=P.firstChild.nodeType==3}catch(ta){}l.features.htmlParsingConforms=X;var ka=["startContainer","startOffset","endContainer","endOffset", +"collapsed","commonAncestorContainer"],ia=0,la=1,ra=2,ma=3,na=0,oa=1,pa=2,ja=3;ca.prototype={attachListener:function(a,e){this._listeners[a].push(e)},compareBoundaryPoints:function(a,e){J(this);u(this.startContainer,e.startContainer);var j=a==ma||a==ia?"start":"end",o=a==la||a==ia?"start":"end";return g.comparePoints(this[j+"Container"],this[j+"Offset"],e[o+"Container"],e[o+"Offset"])},insertNode:function(a){J(this);L(a,aa);w(this.startContainer);if(g.isAncestorOf(a,this.startContainer,true))throw new S("HIERARCHY_REQUEST_ERR"); +this.setStartBefore(N(a,this.startContainer,this.startOffset))},cloneContents:function(){J(this);var a,e;if(this.collapsed)return H(this).createDocumentFragment();else{if(this.startContainer===this.endContainer&&g.isCharacterDataNode(this.startContainer)){a=this.startContainer.cloneNode(true);a.data=a.data.slice(this.startOffset,this.endOffset);e=H(this).createDocumentFragment();e.appendChild(a);return e}else{e=new q(this,true);a=O(e);e.detach()}return a}},canSurroundContents:function(){J(this);w(this.startContainer); +w(this.endContainer);var a=new q(this,true),e=a._first&&K(a._first,this)||a._last&&K(a._last,this);a.detach();return!e},surroundContents:function(a){L(a,b);if(!this.canSurroundContents())throw new v("BAD_BOUNDARYPOINTS_ERR");var e=this.extractContents();if(a.hasChildNodes())for(;a.lastChild;)a.removeChild(a.lastChild);N(a,this.startContainer,this.startOffset);a.appendChild(e);this.selectNode(a)},cloneRange:function(){J(this);for(var a=new M(H(this)),e=ka.length,j;e--;){j=ka[e];a[j]=this[j]}return a}, +toString:function(){J(this);var a=this.startContainer;if(a===this.endContainer&&g.isCharacterDataNode(a))return a.nodeType==3||a.nodeType==4?a.data.slice(this.startOffset,this.endOffset):"";else{var e=[];a=new q(this,true);i(a,function(j){if(j.nodeType==3||j.nodeType==4)e.push(j.data)});a.detach();return e.join("")}},compareNode:function(a){J(this);var e=a.parentNode,j=g.getNodeIndex(a);if(!e)throw new S("NOT_FOUND_ERR");a=this.comparePoint(e,j);e=this.comparePoint(e,j+1);return a<0?e>0?pa:na:e>0? +oa:ja},comparePoint:function(a,e){J(this);B(a,"HIERARCHY_REQUEST_ERR");u(a,this.startContainer);if(g.comparePoints(a,e,this.startContainer,this.startOffset)<0)return-1;else if(g.comparePoints(a,e,this.endContainer,this.endOffset)>0)return 1;return 0},createContextualFragment:X?function(a){var e=this.startContainer,j=g.getDocument(e);if(!e)throw new S("INVALID_STATE_ERR");var o=null;if(e.nodeType==1)o=e;else if(g.isCharacterDataNode(e))o=g.parentElement(e);o=o===null||o.nodeName=="HTML"&&g.isHtmlNamespace(g.getDocument(o).documentElement)&& +g.isHtmlNamespace(o)?j.createElement("body"):o.cloneNode(false);o.innerHTML=a;return g.fragmentFromNodeChildren(o)}:function(a){r(this);var e=H(this).createElement("body");e.innerHTML=a;return g.fragmentFromNodeChildren(e)},toHtml:function(){J(this);var a=H(this).createElement("div");a.appendChild(this.cloneContents());return a.innerHTML},intersectsNode:function(a,e){J(this);B(a,"NOT_FOUND_ERR");if(g.getDocument(a)!==H(this))return false;var j=a.parentNode,o=g.getNodeIndex(a);B(j,"NOT_FOUND_ERR"); +var E=g.comparePoints(j,o,this.endContainer,this.endOffset);j=g.comparePoints(j,o+1,this.startContainer,this.startOffset);return e?E<=0&&j>=0:E<0&&j>0},isPointInRange:function(a,e){J(this);B(a,"HIERARCHY_REQUEST_ERR");u(a,this.startContainer);return g.comparePoints(a,e,this.startContainer,this.startOffset)>=0&&g.comparePoints(a,e,this.endContainer,this.endOffset)<=0},intersectsRange:function(a,e){J(this);if(H(a)!=H(this))throw new S("WRONG_DOCUMENT_ERR");var j=g.comparePoints(this.startContainer, +this.startOffset,a.endContainer,a.endOffset),o=g.comparePoints(this.endContainer,this.endOffset,a.startContainer,a.startOffset);return e?j<=0&&o>=0:j<0&&o>0},intersection:function(a){if(this.intersectsRange(a)){var e=g.comparePoints(this.startContainer,this.startOffset,a.startContainer,a.startOffset),j=g.comparePoints(this.endContainer,this.endOffset,a.endContainer,a.endOffset),o=this.cloneRange();e==-1&&o.setStart(a.startContainer,a.startOffset);j==1&&o.setEnd(a.endContainer,a.endOffset);return o}return null}, +union:function(a){if(this.intersectsRange(a,true)){var e=this.cloneRange();g.comparePoints(a.startContainer,a.startOffset,this.startContainer,this.startOffset)==-1&&e.setStart(a.startContainer,a.startOffset);g.comparePoints(a.endContainer,a.endOffset,this.endContainer,this.endOffset)==1&&e.setEnd(a.endContainer,a.endOffset);return e}else throw new v("Ranges do not intersect");},containsNode:function(a,e){return e?this.intersectsNode(a,false):this.compareNode(a)==ja},containsNodeContents:function(a){return this.comparePoint(a, +0)>=0&&this.comparePoint(a,g.getNodeLength(a))<=0},containsRange:function(a){return this.intersection(a).equals(a)},containsNodeText:function(a){var e=this.cloneRange();e.selectNode(a);var j=e.getNodes([3]);if(j.length>0){e.setStart(j[0],0);a=j.pop();e.setEnd(a,a.length);a=this.containsRange(e);e.detach();return a}else return this.containsNodeContents(a)},createNodeIterator:function(a,e){J(this);return new c(this,a,e)},getNodes:function(a,e){J(this);return x(this,a,e)},getDocument:function(){return H(this)}, +collapseBefore:function(a){r(this);this.setEndBefore(a);this.collapse(false)},collapseAfter:function(a){r(this);this.setStartAfter(a);this.collapse(true)},getName:function(){return"DomRange"},equals:function(a){return M.rangesEqual(this,a)},isValid:function(){return V(this)},inspect:function(){return A(this)}};fa(M,ha,function(a){r(a);a.startContainer=a.startOffset=a.endContainer=a.endOffset=null;a.collapsed=a.commonAncestorContainer=null;I(a,"detach",null);a._listeners=null});l.rangePrototype=ca.prototype; +M.rangeProperties=ka;M.RangeIterator=q;M.copyComparisonConstants=W;M.createPrototypeRange=fa;M.inspect=A;M.getRangeDocument=H;M.rangesEqual=function(a,e){return a.startContainer===e.startContainer&&a.startOffset===e.startOffset&&a.endContainer===e.endContainer&&a.endOffset===e.endOffset};l.DomRange=M;l.RangeException=v}); +rangy.createModule("WrappedRange",function(l){function K(i,n,t,x){var A=i.duplicate();A.collapse(t);var q=A.parentElement();z.isAncestorOf(n,q,true)||(q=n);if(!q.canHaveHTML)return new C(q.parentNode,z.getNodeIndex(q));n=z.getDocument(q).createElement("span");var v,c=t?"StartToStart":"StartToEnd";do{q.insertBefore(n,n.previousSibling);A.moveToElementText(n)}while((v=A.compareEndPoints(c,i))>0&&n.previousSibling);c=n.nextSibling;if(v==-1&&c&&z.isCharacterDataNode(c)){A.setEndPoint(t?"EndToStart":"EndToEnd", +i);if(/[\r\n]/.test(c.data)){q=A.duplicate();t=q.text.replace(/\r\n/g,"\r").length;for(t=q.moveStart("character",t);q.compareEndPoints("StartToEnd",q)==-1;){t++;q.moveStart("character",1)}}else t=A.text.length;q=new C(c,t)}else{c=(x||!t)&&n.previousSibling;q=(t=(x||t)&&n.nextSibling)&&z.isCharacterDataNode(t)?new C(t,0):c&&z.isCharacterDataNode(c)?new C(c,c.length):new C(q,z.getNodeIndex(n))}n.parentNode.removeChild(n);return q}function H(i,n){var t,x,A=i.offset,q=z.getDocument(i.node),v=q.body.createTextRange(), +c=z.isCharacterDataNode(i.node);if(c){t=i.node;x=t.parentNode}else{t=i.node.childNodes;t=A12");d.close();var h=c.getIframeWindow(b).getSelection(),D=d.documentElement.lastChild.firstChild;d=d.createRange();d.setStart(D,1);d.collapse(true);h.addRange(d);ha=h.rangeCount==1;h.removeAllRanges();var G=d.cloneRange();d.setStart(D,0);G.setEnd(D,2);h.addRange(d);h.addRange(G);ea=h.rangeCount==2;d.detach();G.detach();Y.removeChild(b)}();l.features.selectionSupportsMultipleRanges=ea; +l.features.collapsedNonEditableSelectionsSupported=ha;var M=false,g;if(Y&&f.isHostMethod(Y,"createControlRange")){g=Y.createControlRange();if(f.areHostProperties(g,["item","add"]))M=true}l.features.implementsControlRange=M;w=W?function(b){return b.anchorNode===b.focusNode&&b.anchorOffset===b.focusOffset}:function(b){return b.rangeCount?b.getRangeAt(b.rangeCount-1).collapsed:false};var Z;if(f.isHostMethod(B,"getRangeAt"))Z=function(b,d){try{return b.getRangeAt(d)}catch(h){return null}};else if(W)Z= +function(b){var d=c.getDocument(b.anchorNode);d=l.createRange(d);d.setStart(b.anchorNode,b.anchorOffset);d.setEnd(b.focusNode,b.focusOffset);if(d.collapsed!==this.isCollapsed){d.setStart(b.focusNode,b.focusOffset);d.setEnd(b.anchorNode,b.anchorOffset)}return d};l.getSelection=function(b){b=b||window;var d=b._rangySelection,h=u(b),D=V?I(b):null;if(d){d.nativeSelection=h;d.docSelection=D;d.refresh(b)}else{d=new x(h,D,b);b._rangySelection=d}return d};l.getIframeSelection=function(b){return l.getSelection(c.getIframeWindow(b))}; +g=x.prototype;if(!J&&W&&f.areHostMethods(B,["removeAllRanges","addRange"])){g.removeAllRanges=function(){this.nativeSelection.removeAllRanges();C(this)};var S=function(b,d){var h=k.getRangeDocument(d);h=l.createRange(h);h.collapseToPoint(d.endContainer,d.endOffset);b.nativeSelection.addRange(N(h));b.nativeSelection.extend(d.startContainer,d.startOffset);b.refresh()};g.addRange=fa?function(b,d){if(M&&V&&this.docSelection.type=="Control")t(this,b);else if(d&&da)S(this,b);else{var h;if(ea)h=this.rangeCount; +else{this.removeAllRanges();h=0}this.nativeSelection.addRange(N(b));this.rangeCount=this.nativeSelection.rangeCount;if(this.rangeCount==h+1){if(l.config.checkSelectionRanges)if((h=Z(this.nativeSelection,this.rangeCount-1))&&!k.rangesEqual(h,b))b=new r(h);this._ranges[this.rangeCount-1]=b;z(this,b,aa(this.nativeSelection));this.isCollapsed=w(this)}else this.refresh()}}:function(b,d){if(d&&da)S(this,b);else{this.nativeSelection.addRange(N(b));this.refresh()}};g.setRanges=function(b){if(M&&b.length> +1)A(this,b);else{this.removeAllRanges();for(var d=0,h=b.length;d1)A(this,b);else d&&this.addRange(b[0])}}else{K.fail("No means of selecting a Range or TextRange was found");return false}g.getRangeAt=function(b){if(b<0||b>=this.rangeCount)throw new L("INDEX_SIZE_ERR");else return this._ranges[b]}; +var $;if(J)$=function(b){var d;if(l.isSelectionValid(b.win))d=b.docSelection.createRange();else{d=c.getBody(b.win.document).createTextRange();d.collapse(true)}if(b.docSelection.type=="Control")n(b);else d&&typeof d.text!="undefined"?i(b,d):C(b)};else if(f.isHostMethod(B,"getRangeAt")&&typeof B.rangeCount=="number")$=function(b){if(M&&V&&b.docSelection.type=="Control")n(b);else{b._ranges.length=b.rangeCount=b.nativeSelection.rangeCount;if(b.rangeCount){for(var d=0,h=b.rangeCount;d 1) { // extending with a name/value pair + var ancestor = this[source]; + if (ancestor && (typeof value == "function") && // overriding a method? + // the valueOf() comparison is to avoid circular references + (!ancestor.valueOf || ancestor.valueOf() != value.valueOf()) && + /\bbase\b/.test(value)) { + // get the underlying method + var method = value.valueOf(); + // override + value = function() { + var previous = this.base || Base.prototype.base; + this.base = ancestor; + var returnValue = method.apply(this, arguments); + this.base = previous; + return returnValue; + }; + // point to the underlying method + value.valueOf = function(type) { + return (type == "object") ? value : method; + }; + value.toString = Base.toString; + } + this[source] = value; + } else if (source) { // extending with an object literal + var extend = Base.prototype.extend; + // if this object has a customised extend method then use it + if (!Base._prototyping && typeof this != "function") { + extend = this.extend || extend; + } + var proto = {toSource: null}; + // do the "toString" and other methods manually + var hidden = ["constructor", "toString", "valueOf"]; + // if we are prototyping then include the constructor + var i = Base._prototyping ? 0 : 1; + while (key = hidden[i++]) { + if (source[key] != proto[key]) { + extend.call(this, key, source[key]); + + } + } + // copy each of the source object's properties to this object + for (var key in source) { + if (!proto[key]) extend.call(this, key, source[key]); + } + } + return this; + } +}; + +// initialise +Base = Base.extend({ + constructor: function() { + this.extend(arguments[0]); + } +}, { + ancestor: Object, + version: "1.1", + + forEach: function(object, block, context) { + for (var key in object) { + if (this.prototype[key] === undefined) { + block.call(context, object[key], key, object); + } + } + }, + + implement: function() { + for (var i = 0; i < arguments.length; i++) { + if (typeof arguments[i] == "function") { + // if it's a function, call it + arguments[i](this.prototype); + } else { + // add the interface using the extend method + this.prototype.extend(arguments[i]); + } + } + return this; + }, + + toString: function() { + return String(this.valueOf()); + } +});/** + * Detect browser support for specific features + */ +wysihtml5.browser = (function() { + var userAgent = navigator.userAgent, + testElement = document.createElement("div"), + // Browser sniffing is unfortunately needed since some behaviors are impossible to feature detect + isIE = userAgent.indexOf("MSIE") !== -1 && userAgent.indexOf("Opera") === -1, + isGecko = userAgent.indexOf("Gecko") !== -1 && userAgent.indexOf("KHTML") === -1, + isWebKit = userAgent.indexOf("AppleWebKit/") !== -1, + isChrome = userAgent.indexOf("Chrome/") !== -1, + isOpera = userAgent.indexOf("Opera/") !== -1; + + function iosVersion(userAgent) { + return +((/ipad|iphone|ipod/.test(userAgent) && userAgent.match(/ os (\d+).+? like mac os x/)) || [undefined, 0])[1]; + } + + function androidVersion(userAgent) { + return +(userAgent.match(/android (\d+)/) || [undefined, 0])[1]; + } + + return { + // Static variable needed, publicly accessible, to be able override it in unit tests + USER_AGENT: userAgent, + + /** + * Exclude browsers that are not capable of displaying and handling + * contentEditable as desired: + * - iPhone, iPad (tested iOS 4.2.2) and Android (tested 2.2) refuse to make contentEditables focusable + * - IE < 8 create invalid markup and crash randomly from time to time + * + * @return {Boolean} + */ + supported: function() { + var userAgent = this.USER_AGENT.toLowerCase(), + // Essential for making html elements editable + hasContentEditableSupport = "contentEditable" in testElement, + // Following methods are needed in order to interact with the contentEditable area + hasEditingApiSupport = document.execCommand && document.queryCommandSupported && document.queryCommandState, + // document selector apis are only supported by IE 8+, Safari 4+, Chrome and Firefox 3.5+ + hasQuerySelectorSupport = document.querySelector && document.querySelectorAll, + // contentEditable is unusable in mobile browsers (tested iOS 4.2.2, Android 2.2, Opera Mobile, WebOS 3.05) + isIncompatibleMobileBrowser = (this.isIos() && iosVersion(userAgent) < 5) || (this.isAndroid() && androidVersion(userAgent) < 4) || userAgent.indexOf("opera mobi") !== -1 || userAgent.indexOf("hpwos/") !== -1; + return hasContentEditableSupport + && hasEditingApiSupport + && hasQuerySelectorSupport + && !isIncompatibleMobileBrowser; + }, + + isTouchDevice: function() { + return this.supportsEvent("touchmove"); + }, + + isIos: function() { + return (/ipad|iphone|ipod/i).test(this.USER_AGENT); + }, + + isAndroid: function() { + return this.USER_AGENT.indexOf("Android") !== -1; + }, + + /** + * Whether the browser supports sandboxed iframes + * Currently only IE 6+ offers such feature