bootsy-rails3 2.0.5.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (49) hide show
  1. checksums.yaml +15 -0
  2. data/MIT-LICENSE +20 -0
  3. data/README.md +155 -0
  4. data/Rakefile +38 -0
  5. data/app/assets/images/bootsy/gallery-loader.gif +0 -0
  6. data/app/assets/images/bootsy/upload-loader.gif +0 -0
  7. data/app/assets/javascripts/bootsy.js +8 -0
  8. data/app/assets/javascripts/bootsy/bootstrap-wysihtml5.js +530 -0
  9. data/app/assets/javascripts/bootsy/bootstrap.file-input.js +122 -0
  10. data/app/assets/javascripts/bootsy/bootsy.js +305 -0
  11. data/app/assets/javascripts/bootsy/editor_options.js +80 -0
  12. data/app/assets/javascripts/bootsy/init.js +31 -0
  13. data/app/assets/javascripts/bootsy/locales/bootstrap-wysihtml5.pt-BR.js +50 -0
  14. data/app/assets/javascripts/bootsy/locales/bootsy.pt-BR.js +9 -0
  15. data/app/assets/javascripts/bootsy/translations.js +8 -0
  16. data/app/assets/javascripts/bootsy/wysihtml5.js +9564 -0
  17. data/app/assets/stylesheets/bootsy.css +3 -0
  18. data/app/assets/stylesheets/bootsy/bootstrap-submenu.css +47 -0
  19. data/app/assets/stylesheets/bootsy/bootstrap-wysihtml5.css +102 -0
  20. data/app/assets/stylesheets/bootsy/bootsy.css +161 -0
  21. data/app/controllers/bootsy/application_controller.rb +7 -0
  22. data/app/controllers/bootsy/images_controller.rb +80 -0
  23. data/app/helpers/bootsy/application_helper.rb +11 -0
  24. data/app/uploaders/bootsy/image_uploader.rb +35 -0
  25. data/app/views/bootsy/images/_image.html.erb +43 -0
  26. data/app/views/bootsy/images/_modal.html.erb +28 -0
  27. data/app/views/bootsy/images/_new.html.erb +8 -0
  28. data/config/cucumber.yml +8 -0
  29. data/config/locales/en.yml +27 -0
  30. data/config/locales/pt-BR.yml +27 -0
  31. data/config/routes.rb +11 -0
  32. data/db/migrate/20120624171333_create_bootsy_images.rb +9 -0
  33. data/db/migrate/20120628124845_create_bootsy_image_galleries.rb +8 -0
  34. data/lib/bootsy-rails3.rb +66 -0
  35. data/lib/bootsy/activerecord/image.rb +11 -0
  36. data/lib/bootsy/activerecord/image_gallery.rb +8 -0
  37. data/lib/bootsy/container.rb +31 -0
  38. data/lib/bootsy/core_ext.rb +2 -0
  39. data/lib/bootsy/engine.rb +31 -0
  40. data/lib/bootsy/form_builder.rb +7 -0
  41. data/lib/bootsy/form_helper.rb +68 -0
  42. data/lib/bootsy/simple_form/bootsy_input.rb +11 -0
  43. data/lib/bootsy/version.rb +3 -0
  44. data/lib/generators/bootsy/USAGE +12 -0
  45. data/lib/generators/bootsy/install_generator.rb +50 -0
  46. data/lib/generators/bootsy/templates/bootsy.rb +64 -0
  47. data/lib/tasks/bootsy_tasks.rake +4 -0
  48. data/lib/tasks/cucumber.rake +65 -0
  49. metadata +137 -0
@@ -0,0 +1,15 @@
1
+ ---
2
+ !binary "U0hBMQ==":
3
+ metadata.gz: !binary |-
4
+ YzRkNDkzMDhmYWMzYTYxMjFiODQyYjNkMTM2ZjAyNWQxYzFmOWZjOQ==
5
+ data.tar.gz: !binary |-
6
+ ZTE2ZjY2ZjM2OTFjZjUxZDkyMjc1MDg2NjkzMjZiNDlkMGNiMDA5Yw==
7
+ SHA512:
8
+ metadata.gz: !binary |-
9
+ NzljOWE4NWJjZjY4ZmNkMjcxZjgwN2M5NjU5YWJmNjdhMDZkMzhlMjk4ZGRj
10
+ ZDBkMjZhY2JlMzkxN2M0OGUzZjFkZWMzYTQ2ZGNjZTRlZTI4OGFkYjFkZjIy
11
+ YjI1YjJiN2I0ZTYzYWE1M2RkNjc2NjAzNDIwMWJhMGI1MDM0ODQ=
12
+ data.tar.gz: !binary |-
13
+ OTkxZGNjOTVhMTkwZmI3OWE5NmRhODY4M2IxYzM5MDU1MjFhZmUzNGQ3Y2Q5
14
+ MDE4NjkwMTFhN2EzMGYzNWI2ZDAxNDBmYTRjZDMwMTAwMGYwM2IyZGY2ZTJl
15
+ YWQ5NmY3NjU5OTMyYzE5MmIzODQwZmM2Mzk0ZmIyZTVkMDFhYjY=
@@ -0,0 +1,20 @@
1
+ Copyright 2012-2014 Volmer Soares
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@@ -0,0 +1,155 @@
1
+ # Bootsy
2
+
3
+ [![Gem Version](https://badge.fury.io/rb/bootsy.png)](http://badge.fury.io/rb/bootsy)
4
+ [![Build Status](https://secure.travis-ci.org/volmer/bootsy.png?branch=master)](http://travis-ci.org/volmer/bootsy)
5
+ [![Dependency Status](https://gemnasium.com/volmer/bootsy.png)](https://gemnasium.com/volmer/bootsy)
6
+ [![Code Climate](https://codeclimate.com/github/volmer/bootsy.png)](https://codeclimate.com/github/volmer/bootsy)
7
+ [![Coverage Status](https://coveralls.io/repos/volmer/bootsy/badge.png?branch=master)](https://coveralls.io/r/volmer/bootsy)
8
+
9
+ *Bootsy* is a WYSIWYG solution for Rails based on [Bootstrap-wysihtml5](https://github.com/jhollingworth/bootstrap-wysihtml5) which includes image uploads via [CarrierWave](https://github.com/carrierwaveuploader/carrierwave).
10
+
11
+ ### Live demo
12
+
13
+ * [bootsy-demo.herokuapp.com](http://bootsy-demo.herokuapp.com/)
14
+ [![image](https://f.cloud.github.com/assets/301187/1365250/e1b7ba80-3854-11e3-9bfe-8bd1e090aca8.png)](http://bootsy-demo.herokuapp.com/)
15
+
16
+
17
+ ## Requirements
18
+
19
+ * Ruby `2.0` or `1.9.3`;
20
+ * ImageMagick or GraphicsMagick (for MiniMagick);
21
+ * Rails `4.0`;
22
+ * [Bootstrap `3`](http://getbootstrap.com/) properly added to your application.
23
+
24
+
25
+ ## Installation
26
+
27
+ 1. Add Bootsy to your Gemfile:
28
+ ```ruby
29
+ gem 'bootsy'
30
+ ```
31
+
32
+ 2. Run the bundle command to install it:
33
+ ```console
34
+ bundle install
35
+ ```
36
+
37
+ 3. Run the install generator:
38
+ ```console
39
+ rails generate bootsy:install
40
+ ```
41
+ It will include the javascripts and stylesheets in the assets pipeline,
42
+ create the `bootsy.rb` initializer and add a copy of the english translations.
43
+
44
+ 4. Add and run migrations (if you're using ActiveRecord):
45
+ ```console
46
+ rake bootsy:install:migrations
47
+ rake db:migrate
48
+ ```
49
+
50
+
51
+ ## Usage
52
+
53
+ Just call the brand new method `bootsy_area` in your `FormBuilder` instances, the
54
+ same way you'd call the basic `textarea` method. Example:
55
+ ```erb
56
+ <%= form_for(@post) do |f| %>
57
+ <%= f.label :title %>
58
+ <%= f.text_field :title %>
59
+
60
+ <%= f.label :content %>
61
+ <%= f.bootsy_area :content %>
62
+
63
+ <%= f.submit %>
64
+ <% end %>
65
+ ```
66
+
67
+ Bootsy will group the uploaded images as galleries and associate them to one of
68
+ your models. For example, if you have a `Post` model and you want to use `bootsy_area`
69
+ with it, then you should include the `Bootsy::Container` module:
70
+ ```ruby
71
+ class Post < ActiveRecord::Base
72
+ include Bootsy::Container
73
+ end
74
+ ```
75
+
76
+ Don't forget to ensure the association of new instances of your model with Bootsy
77
+ image galleries. For `strong_parameters`, you must allow the parameter `bootsy_image_gallery_id`
78
+ in your controllers. Example:
79
+ ```ruby
80
+ private
81
+ # Never trust parameters from the scary internet, only allow the white list through.
82
+ def post_params
83
+ params.require(:post).permit(:title, :content, :bootsy_image_gallery_id)
84
+ end
85
+ ```
86
+
87
+
88
+ ## Bootsy with [Simple Form](https://github.com/plataformatec/simple_form) builders
89
+
90
+ Just use the brand new input type `bootsy` in your `SimpleForm::FormBuilder` instances,
91
+ in the same way you would use the basic `text` input. Example:
92
+ ```erb
93
+ <%= simple_form_for @post do |f| %>
94
+ <%= f.input :title %>
95
+
96
+ <%= f.input :content, as: :bootsy %>
97
+
98
+ <%= f.button :submit %>
99
+ <% end %>
100
+ ```
101
+
102
+
103
+ ## Editor options
104
+
105
+ It is possible to customize how the editor is displayed and its behavior by passing
106
+ a hash `editor_options` to your `bootsy_area`.
107
+
108
+
109
+ ### Buttons
110
+
111
+ You can enable/disable the buttons available on the editor. For example, if you
112
+ want to disable the link and color buttons:
113
+ ```erb
114
+ <%= f.bootsy_area :my_attribute, editor_options: {link: false, color: false} %>
115
+ ```
116
+ Available options are: `:font_styles`, `:emphasis`, `:lists`, `:html`, `:link`, `:image` and `:color`.
117
+
118
+
119
+ ### Alert for usaved changes
120
+
121
+ By default, Bootsy alerts for unsaved changes if the user attempts to unload
122
+ the window. You can disable this behaviour by doing:
123
+ ```erb
124
+ <%= f.bootsy_area :my_attribute, editor_options: {alert_unsaved: false} %>
125
+ ```
126
+
127
+ ## Uploader
128
+
129
+ It's also possible to use Bootsy without the image upload feature. Just call
130
+ `bootsy_area` in a form builder not associated to a `Bootsy::Container` model.
131
+ This way users can insert images in their texts by providing an image url.
132
+
133
+
134
+ ## Configuration
135
+
136
+ You can set the default editor options, image sizes available (small, medium,
137
+ large and/or its original), its dimensions and more. Take a look at the initalizer
138
+ file, `/config/initializers/bootsy.rb`.
139
+
140
+
141
+ ## I18n
142
+
143
+ Bootsy defines some i18n keys. The english translation is automatically added
144
+ to your `config/locales` directory as `bootsy.en.yml`. You can follow that template
145
+ in order to translate Bootsy to your language. You can find some examples
146
+ [here](https://github.com/volmer/bootsy/tree/master/config/locales). It is also
147
+ necessary to add a translation for Bootstrap-wysihtml5, the javascript editor, in
148
+ your assets pipeline. Instructions [here](https://github.com/jhollingworth/bootstrap-wysihtml5#i18n).
149
+ If you are using the alert for unsaved changes, you have to define a translation
150
+ for it as well. Just follow [this example](https://github.com/volmer/bootsy/tree/master/app/assets/bootsy/locales/bootsy.pt-BR.js).
151
+
152
+
153
+ ## License
154
+
155
+ MIT License. Copyright 2012-2014 Volmer Soares
@@ -0,0 +1,38 @@
1
+ #!/usr/bin/env rake
2
+ begin
3
+ require 'bundler/setup'
4
+ rescue LoadError
5
+ puts 'You must `gem install bundler` and `bundle install` to run rake tasks'
6
+ end
7
+ begin
8
+ require 'rdoc/task'
9
+ rescue LoadError
10
+ require 'rdoc/rdoc'
11
+ require 'rake/rdoctask'
12
+ RDoc::Task = Rake::RDocTask
13
+ end
14
+
15
+ RDoc::Task.new(:rdoc) do |rdoc|
16
+ rdoc.rdoc_dir = 'rdoc'
17
+ rdoc.title = 'Bootsy'
18
+ rdoc.options << '--line-numbers'
19
+ rdoc.rdoc_files.include('README.rdoc')
20
+ rdoc.rdoc_files.include('lib/**/*.rb')
21
+ end
22
+
23
+ Bundler::GemHelper.install_tasks
24
+
25
+ require 'cucumber/rake/task'
26
+ require 'rspec/core/rake_task'
27
+ require 'coveralls/rake/task'
28
+
29
+ Coveralls::RakeTask.new
30
+
31
+ task default: [:spec, :cucumber, 'coveralls:push']
32
+
33
+ RSpec::Core::RakeTask.new(:spec)
34
+
35
+ Cucumber::Rake::Task.new do |t|
36
+ # Uncomment this line when cucumber/multi_test work with minitest.
37
+ # t.cucumber_opts = %w{--format pretty -s}
38
+ end
@@ -0,0 +1,8 @@
1
+ //= require jquery.remotipart
2
+ //= require bootsy/wysihtml5
3
+ //= require bootsy/bootstrap-wysihtml5
4
+ //= require bootsy/bootsy
5
+ //= require bootsy/bootstrap.file-input.js
6
+ //= require bootsy/init
7
+ //= require bootsy/editor_options
8
+ //= require bootsy/translations
@@ -0,0 +1,530 @@
1
+ !function($, wysi) {
2
+ "use strict";
3
+
4
+ var tpl = {
5
+ "font-styles": function(locale, options) {
6
+ var size = (options && options.size) ? ' btn-'+options.size : '';
7
+ return "<li class='dropdown'>" +
8
+ "<a class='btn btn-default dropdown-toggle" + size + "' data-toggle='dropdown' href='#' title='" + locale.font_styles.title + "'>" +
9
+ "<i class='glyphicon glyphicon-font'></i>&nbsp;<span class='current-font'>" + locale.font_styles.normal + "</span>&nbsp;<b class='caret'></b>" +
10
+ "</a>" +
11
+ "<ul class='dropdown-menu'>" +
12
+ "<li><a data-wysihtml5-command='formatBlock' data-wysihtml5-command-value='div' tabindex='-1' role='menuitem'>" + locale.font_styles.normal + "</a></li>" +
13
+ "<li><a data-wysihtml5-command='formatBlock' data-wysihtml5-command-value='h1' tabindex='-1' role='menuitem'>" + locale.font_styles.h1 + "</a></li>" +
14
+ "<li><a data-wysihtml5-command='formatBlock' data-wysihtml5-command-value='h2' tabindex='-1' role='menuitem'>" + locale.font_styles.h2 + "</a></li>" +
15
+ "<li><a data-wysihtml5-command='formatBlock' data-wysihtml5-command-value='h3' tabindex='-1' role='menuitem'>" + locale.font_styles.h3 + "</a></li>" +
16
+ "</ul>" +
17
+ "</li>";
18
+ },
19
+
20
+ "emphasis": function(locale, options) {
21
+ var size = (options && options.size) ? ' btn-'+options.size : '';
22
+ return "<li>" +
23
+ "<div class='btn-group'>" +
24
+ "<a class='btn btn-default " + size + "' data-wysihtml5-command='bold' title='CTRL+B' tabindex='-1'>" + locale.emphasis.bold + "</a>" +
25
+ "<a class='btn btn-default " + size + "' data-wysihtml5-command='italic' title='CTRL+I' tabindex='-1'>" + locale.emphasis.italic + "</a>" +
26
+ "<a class='btn btn-default " + size + "' data-wysihtml5-command='underline' title='CTRL+U' tabindex='-1'>" + locale.emphasis.underline + "</a>" +
27
+ "</div>" +
28
+ "</li>";
29
+ },
30
+
31
+ "lists": function(locale, options) {
32
+ var size = (options && options.size) ? ' btn-'+options.size : '';
33
+ return "<li>" +
34
+ "<div class='btn-group'>" +
35
+ "<a class='btn btn-default " + size + "' data-wysihtml5-command='insertUnorderedList' title='" + locale.lists.unordered + "' tabindex='-1'><i class='glyphicon glyphicon-list'></i></a>" +
36
+ "<a class='btn btn-default " + size + "' data-wysihtml5-command='insertOrderedList' title='" + locale.lists.ordered + "' tabindex='-1'><i class='glyphicon glyphicon-th-list'></i></a>" +
37
+ "<a class='btn btn-default " + size + "' data-wysihtml5-command='Outdent' title='" + locale.lists.outdent + "' tabindex='-1'><i class='glyphicon glyphicon-indent-left'></i></a>" +
38
+ "<a class='btn btn-default " + size + "' data-wysihtml5-command='Indent' title='" + locale.lists.indent + "' tabindex='-1'><i class='glyphicon glyphicon-indent-right'></i></a>" +
39
+ "</div>" +
40
+ "</li>";
41
+ },
42
+
43
+ "link": function(locale, options) {
44
+ var size = (options && options.size) ? ' btn-'+options.size : '';
45
+ return "<li>" +
46
+ "<div class='bootstrap-wysihtml5-insert-link-modal modal fade' tabindex='-1' role='dialog' aria-hidden='true'>" +
47
+ "<div class='modal-dialog'>" +
48
+ "<div class='modal-content'>" +
49
+ "<div class='modal-header'>" +
50
+ "<button type='button' class='close' data-dismiss='modal' aria-hidden='true'>&times;</button>" +
51
+ "<h3 class='modal-title'>" + locale.link.insert + "</h3>" +
52
+ "</div>" +
53
+ "<div class='modal-body'>" +
54
+ "<input value='http://' class='bootstrap-wysihtml5-insert-link-url form-control input-lg'>" +
55
+ "</div>" +
56
+ "<div class='modal-footer'>" +
57
+ "<a href='#' class='btn btn-default' data-dismiss='modal'>" + locale.link.cancel + "</a>" +
58
+ "<a href='#' class='btn btn-primary' data-dismiss='modal'>" + locale.link.insert + "</a>" +
59
+ "</div>" +
60
+ "</div>" +
61
+ "</div>" +
62
+ "</div>" +
63
+ "<a class='btn btn-default " + size + "' data-wysihtml5-command='createLink' title='" + locale.link.insert + "' tabindex='-1'><i class='glyphicon glyphicon-share'></i></a>" +
64
+ "</li>";
65
+ },
66
+
67
+ "image": function(locale, options) {
68
+ var size = (options && options.size) ? ' btn-'+options.size : '';
69
+ return "<li>" +
70
+ "<div class='bootstrap-wysihtml5-insert-image-modal modal fade' tabindex='-1' role='dialog' aria-hidden='true'>" +
71
+ "<div class='modal-dialog'>" +
72
+ "<div class='modal-content'>" +
73
+ "<div class='modal-header'>" +
74
+ "<button type='button' class='close' data-dismiss='modal' aria-hidden='true'>&times;</button>" +
75
+ "<h3 class='modal-title'>" + locale.image.insert + "</h3>" +
76
+ "</div>" +
77
+ "<div class='modal-body'>" +
78
+ "<input value='http://' class='bootstrap-wysihtml5-insert-image-url form-control input-lg'>" +
79
+ "</div>" +
80
+ "<div class='modal-footer'>" +
81
+ "<a href='#' class='btn btn-default ' data-dismiss='modal'>" + locale.image.cancel + "</a>" +
82
+ "<a href='#' class='btn btn-primary' data-dismiss='modal'>" + locale.image.insert + "</a>" +
83
+ "</div>" +
84
+ "</div>" +
85
+ "</div>" +
86
+ "</div>" +
87
+ "<a class='btn btn-default " + size + "' data-wysihtml5-command='insertImage' title='" + locale.image.insert + "' tabindex='-1'><i class='glyphicon glyphicon-picture'></i></a>" +
88
+ "</li>";
89
+ },
90
+
91
+ "html": function(locale, options) {
92
+ var size = (options && options.size) ? ' btn-'+options.size : '';
93
+ return "<li>" +
94
+ "<div class='btn-group'>" +
95
+ "<a class='btn btn-default " + size + "' data-wysihtml5-action='change_view' title='" + locale.html.edit + "' tabindex='-1'><i class='glyphicon glyphicon-pencil'></i></a>" +
96
+ "</div>" +
97
+ "</li>";
98
+ },
99
+
100
+ "color": function(locale, options) {
101
+ var size = (options && options.size) ? ' btn-'+options.size : '';
102
+ return "<li class='dropdown'>" +
103
+ "<a class='btn btn-default dropdown-toggle" + size + "' data-toggle='dropdown' href='#' tabindex='-1' title='" + locale.colours.title + "'>" +
104
+ "<span class='current-color'>" + locale.colours.black + "</span>&nbsp;<b class='caret'></b>" +
105
+ "</a>" +
106
+ "<ul class='dropdown-menu'>" +
107
+ "<li><div class='wysihtml5-colors' data-wysihtml5-command-value='black'></div><a class='wysihtml5-colors-title' data-wysihtml5-command='foreColor' data-wysihtml5-command-value='black' role='menuitem'>" + locale.colours.black + "</a></li>" +
108
+ "<li><div class='wysihtml5-colors' data-wysihtml5-command-value='silver'></div><a class='wysihtml5-colors-title' data-wysihtml5-command='foreColor' data-wysihtml5-command-value='silver' role='menuitem'>" + locale.colours.silver + "</a></li>" +
109
+ "<li><div class='wysihtml5-colors' data-wysihtml5-command-value='gray'></div><a class='wysihtml5-colors-title' data-wysihtml5-command='foreColor' data-wysihtml5-command-value='gray' role='menuitem'>" + locale.colours.gray + "</a></li>" +
110
+ "<li><div class='wysihtml5-colors' data-wysihtml5-command-value='maroon'></div><a class='wysihtml5-colors-title' data-wysihtml5-command='foreColor' data-wysihtml5-command-value='maroon' role='menuitem'>" + locale.colours.maroon + "</a></li>" +
111
+ "<li><div class='wysihtml5-colors' data-wysihtml5-command-value='red'></div><a class='wysihtml5-colors-title' data-wysihtml5-command='foreColor' data-wysihtml5-command-value='red' role='menuitem'>" + locale.colours.red + "</a></li>" +
112
+ "<li><div class='wysihtml5-colors' data-wysihtml5-command-value='purple'></div><a class='wysihtml5-colors-title' data-wysihtml5-command='foreColor' data-wysihtml5-command-value='purple' role='menuitem'>" + locale.colours.purple + "</a></li>" +
113
+ "<li><div class='wysihtml5-colors' data-wysihtml5-command-value='green'></div><a class='wysihtml5-colors-title' data-wysihtml5-command='foreColor' data-wysihtml5-command-value='green' role='menuitem'>" + locale.colours.green + "</a></li>" +
114
+ "<li><div class='wysihtml5-colors' data-wysihtml5-command-value='olive'></div><a class='wysihtml5-colors-title' data-wysihtml5-command='foreColor' data-wysihtml5-command-value='olive' role='menuitem'>" + locale.colours.olive + "</a></li>" +
115
+ "<li><div class='wysihtml5-colors' data-wysihtml5-command-value='navy'></div><a class='wysihtml5-colors-title' data-wysihtml5-command='foreColor' data-wysihtml5-command-value='navy' role='menuitem'>" + locale.colours.navy + "</a></li>" +
116
+ "<li><div class='wysihtml5-colors' data-wysihtml5-command-value='blue'></div><a class='wysihtml5-colors-title' data-wysihtml5-command='foreColor' data-wysihtml5-command-value='blue' role='menuitem'>" + locale.colours.blue + "</a></li>" +
117
+ "<li><div class='wysihtml5-colors' data-wysihtml5-command-value='orange'></div><a class='wysihtml5-colors-title' data-wysihtml5-command='foreColor' data-wysihtml5-command-value='orange' role='menuitem'>" + locale.colours.orange + "</a></li>" +
118
+ "</ul>" +
119
+ "</li>";
120
+ }
121
+ };
122
+
123
+ var templates = function(key, locale, options) {
124
+ return tpl[key](locale, options);
125
+ };
126
+
127
+
128
+ var Wysihtml5 = function(el, options) {
129
+ this.el = el;
130
+ var toolbarOpts = options || defaultOptions;
131
+ for(var t in toolbarOpts.customTemplates) {
132
+ tpl[t] = toolbarOpts.customTemplates[t];
133
+ }
134
+ this.toolbar = this.createToolbar(el, toolbarOpts);
135
+ this.editor = this.createEditor(options);
136
+
137
+ window.editor = this.editor;
138
+
139
+ $('iframe.wysihtml5-sandbox').each(function(i, el){
140
+ $(el.contentWindow).off('focus.wysihtml5').on({
141
+ 'focus.wysihtml5' : function(){
142
+ $('li.dropdown').removeClass('open');
143
+ }
144
+ });
145
+ });
146
+ };
147
+
148
+ Wysihtml5.prototype = {
149
+
150
+ constructor: Wysihtml5,
151
+
152
+ createEditor: function(options) {
153
+ options = options || {};
154
+
155
+ // Add the toolbar to a clone of the options object so multiple instances
156
+ // of the WYISYWG don't break because "toolbar" is already defined
157
+ options = $.extend(true, {}, options);
158
+ options.toolbar = this.toolbar[0];
159
+
160
+ var editor = new wysi.Editor(this.el[0], options);
161
+
162
+ if(options && options.events) {
163
+ for(var eventName in options.events) {
164
+ editor.on(eventName, options.events[eventName]);
165
+ }
166
+ }
167
+ return editor;
168
+ },
169
+
170
+ createToolbar: function(el, options) {
171
+ var self = this;
172
+ var toolbar = $("<ul/>", {
173
+ 'class' : "wysihtml5-toolbar",
174
+ 'style': "display:none"
175
+ });
176
+ var culture = options.locale || defaultOptions.locale || "en";
177
+ for(var key in defaultOptions) {
178
+ var value = false;
179
+
180
+ if(options[key] !== undefined) {
181
+ if(options[key] === true) {
182
+ value = true;
183
+ }
184
+ } else {
185
+ value = defaultOptions[key];
186
+ }
187
+
188
+ if(value === true) {
189
+ toolbar.append(templates(key, locale[culture], options));
190
+
191
+ if(key === "html") {
192
+ this.initHtml(toolbar);
193
+ }
194
+
195
+ if(key === "link") {
196
+ this.initInsertLink(toolbar);
197
+ }
198
+
199
+ if(key === "image") {
200
+ this.initInsertImage(toolbar);
201
+ }
202
+
203
+ if(key == "customCommand") {
204
+ this.initCustomCommand(toolbar, options.customCommandCallback);
205
+ }
206
+ }
207
+ }
208
+
209
+ if(options.toolbar) {
210
+ for(key in options.toolbar) {
211
+ toolbar.append(options.toolbar[key]);
212
+ }
213
+ }
214
+
215
+ toolbar.find("a[data-wysihtml5-command='formatBlock']").click(function(e) {
216
+ var target = e.target || e.srcElement;
217
+ var el = $(target);
218
+ self.toolbar.find('.current-font').text(el.html());
219
+ });
220
+
221
+ toolbar.find("a[data-wysihtml5-command='foreColor']").click(function(e) {
222
+ var target = e.target || e.srcElement;
223
+ var el = $(target);
224
+ self.toolbar.find('.current-color').text(el.html());
225
+ });
226
+
227
+ this.el.before(toolbar);
228
+
229
+ return toolbar;
230
+ },
231
+
232
+ initHtml: function(toolbar) {
233
+ var changeViewSelector = "a[data-wysihtml5-action='change_view']";
234
+ toolbar.find(changeViewSelector).click(function(e) {
235
+ toolbar.find('a.btn').not(changeViewSelector).toggleClass('disabled');
236
+ });
237
+ },
238
+
239
+ initInsertImage: function(toolbar) {
240
+ var self = this;
241
+ var insertImageModal = toolbar.find('.bootstrap-wysihtml5-insert-image-modal');
242
+ var urlInput = insertImageModal.find('.bootstrap-wysihtml5-insert-image-url');
243
+ var insertButton = insertImageModal.find('a.btn-primary');
244
+ var initialValue = urlInput.val();
245
+ var caretBookmark;
246
+
247
+ var insertImage = function() {
248
+ var url = urlInput.val();
249
+ urlInput.val(initialValue);
250
+ self.editor.currentView.element.focus();
251
+ if (caretBookmark) {
252
+ self.editor.composer.selection.setBookmark(caretBookmark);
253
+ caretBookmark = null;
254
+ }
255
+ self.editor.composer.commands.exec("insertImage", url);
256
+ };
257
+
258
+ urlInput.keypress(function(e) {
259
+ if(e.which == 13) {
260
+ insertImage();
261
+ insertImageModal.modal('hide');
262
+ }
263
+ });
264
+
265
+ insertButton.click(insertImage);
266
+
267
+ insertImageModal.on('shown', function() {
268
+ urlInput.focus();
269
+ });
270
+
271
+ insertImageModal.on('hide', function() {
272
+ self.editor.currentView.element.focus();
273
+ });
274
+
275
+ toolbar.find('a[data-wysihtml5-command=insertImage]').click(function() {
276
+ var activeButton = $(this).hasClass("wysihtml5-command-active");
277
+
278
+ if (!activeButton) {
279
+ self.editor.currentView.element.focus(false);
280
+ caretBookmark = self.editor.composer.selection.getBookmark();
281
+ insertImageModal.appendTo('body').modal('show');
282
+ insertImageModal.on('click.dismiss.modal', '[data-dismiss="modal"]', function(e) {
283
+ e.stopPropagation();
284
+ });
285
+ return false;
286
+ }
287
+ else {
288
+ return true;
289
+ }
290
+ });
291
+ },
292
+
293
+ initCustomCommand: function(toolbar, callback) {
294
+ var self = this;
295
+
296
+ toolbar.find('a[data-wysihtml5-command=customCommand]').click(function() {
297
+ var activeButton = $(this).hasClass("wysihtml5-command-active");
298
+
299
+ if (!activeButton) {
300
+ callback(self.editor);
301
+ return false;
302
+ }
303
+ else {
304
+ return true;
305
+ }
306
+ });
307
+ },
308
+
309
+ initInsertLink: function(toolbar) {
310
+ var self = this;
311
+ var insertLinkModal = toolbar.find('.bootstrap-wysihtml5-insert-link-modal');
312
+ var urlInput = insertLinkModal.find('.bootstrap-wysihtml5-insert-link-url');
313
+ var insertButton = insertLinkModal.find('a.btn-primary');
314
+ var initialValue = urlInput.val();
315
+ var caretBookmark;
316
+
317
+ var insertLink = function() {
318
+ var url = urlInput.val();
319
+ urlInput.val(initialValue);
320
+ self.editor.currentView.element.focus();
321
+ if (caretBookmark) {
322
+ self.editor.composer.selection.setBookmark(caretBookmark);
323
+ caretBookmark = null;
324
+ }
325
+ self.editor.composer.commands.exec("createLink", {
326
+ href: url,
327
+ target: "_blank",
328
+ rel: "nofollow"
329
+ });
330
+ };
331
+ var pressedEnter = false;
332
+
333
+ urlInput.keypress(function(e) {
334
+ if(e.which == 13) {
335
+ insertLink();
336
+ insertLinkModal.modal('hide');
337
+ }
338
+ });
339
+
340
+ insertButton.click(insertLink);
341
+
342
+ insertLinkModal.on('shown', function() {
343
+ urlInput.focus();
344
+ });
345
+
346
+ insertLinkModal.on('hide', function() {
347
+ self.editor.currentView.element.focus();
348
+ });
349
+
350
+ toolbar.find('a[data-wysihtml5-command=createLink]').click(function() {
351
+ var activeButton = $(this).hasClass("wysihtml5-command-active");
352
+
353
+ if (!activeButton) {
354
+ self.editor.currentView.element.focus(false);
355
+ caretBookmark = self.editor.composer.selection.getBookmark();
356
+ insertLinkModal.appendTo('body').modal('show');
357
+ insertLinkModal.on('click.dismiss.modal', '[data-dismiss="modal"]', function(e) {
358
+ e.stopPropagation();
359
+ });
360
+ return false;
361
+ }
362
+ else {
363
+ return true;
364
+ }
365
+ });
366
+ }
367
+ };
368
+
369
+ // these define our public api
370
+ var methods = {
371
+ resetDefaults: function() {
372
+ $.fn.wysihtml5.defaultOptions = $.extend(true, {}, $.fn.wysihtml5.defaultOptionsCache);
373
+ },
374
+ bypassDefaults: function(options) {
375
+ return this.each(function () {
376
+ var $this = $(this);
377
+ $this.data('wysihtml5', new Wysihtml5($this, options));
378
+ });
379
+ },
380
+ shallowExtend: function (options) {
381
+ var settings = $.extend({}, $.fn.wysihtml5.defaultOptions, options || {});
382
+ var that = this;
383
+ return methods.bypassDefaults.apply(that, [settings]);
384
+ },
385
+ deepExtend: function(options) {
386
+ var settings = $.extend(true, {}, $.fn.wysihtml5.defaultOptions, options || {});
387
+ var that = this;
388
+ return methods.bypassDefaults.apply(that, [settings]);
389
+ },
390
+ init: function(options) {
391
+ var that = this;
392
+ return methods.shallowExtend.apply(that, [options]);
393
+ }
394
+ };
395
+
396
+ $.fn.wysihtml5 = function ( method ) {
397
+ if ( methods[method] ) {
398
+ return methods[method].apply( this, Array.prototype.slice.call( arguments, 1 ));
399
+ } else if ( typeof method === 'object' || ! method ) {
400
+ return methods.init.apply( this, arguments );
401
+ } else {
402
+ $.error( 'Method ' + method + ' does not exist on jQuery.wysihtml5' );
403
+ }
404
+ };
405
+
406
+ $.fn.wysihtml5.Constructor = Wysihtml5;
407
+
408
+ var defaultOptions = $.fn.wysihtml5.defaultOptions = {
409
+ "font-styles": true,
410
+ "color": false,
411
+ "emphasis": true,
412
+ "lists": true,
413
+ "html": false,
414
+ "link": true,
415
+ "image": true,
416
+ customCommand: false,
417
+ events: {},
418
+ parserRules: {
419
+ classes: {
420
+ // (path_to_project/lib/css/wysiwyg-color.css)
421
+ "wysiwyg-color-silver" : 1,
422
+ "wysiwyg-color-gray" : 1,
423
+ "wysiwyg-color-white" : 1,
424
+ "wysiwyg-color-maroon" : 1,
425
+ "wysiwyg-color-red" : 1,
426
+ "wysiwyg-color-purple" : 1,
427
+ "wysiwyg-color-fuchsia" : 1,
428
+ "wysiwyg-color-green" : 1,
429
+ "wysiwyg-color-lime" : 1,
430
+ "wysiwyg-color-olive" : 1,
431
+ "wysiwyg-color-yellow" : 1,
432
+ "wysiwyg-color-navy" : 1,
433
+ "wysiwyg-color-blue" : 1,
434
+ "wysiwyg-color-teal" : 1,
435
+ "wysiwyg-color-aqua" : 1,
436
+ "wysiwyg-color-orange" : 1
437
+ },
438
+ tags: {
439
+ "b": {},
440
+ "i": {},
441
+ "br": {},
442
+ "ol": {},
443
+ "ul": {},
444
+ "li": {},
445
+ "h1": {},
446
+ "h2": {},
447
+ "h3": {},
448
+ "blockquote": {},
449
+ "u": 1,
450
+ "img": {
451
+ "check_attributes": {
452
+ "width": "numbers",
453
+ "alt": "alt",
454
+ "src": "url",
455
+ "height": "numbers"
456
+ }
457
+ },
458
+ "a": {
459
+ set_attributes: {
460
+ target: "_blank",
461
+ rel: "nofollow"
462
+ },
463
+ check_attributes: {
464
+ href: "url" // important to avoid XSS
465
+ }
466
+ },
467
+ "span": 1,
468
+ "div": 1,
469
+ // to allow save and edit files with code tag hacks
470
+ "code": 1,
471
+ "pre": 1
472
+ }
473
+ },
474
+ stylesheets: ["./lib/css/wysiwyg-color.css"], // (path_to_project/lib/css/wysiwyg-color.css)
475
+ locale: "en"
476
+ };
477
+
478
+ if (typeof $.fn.wysihtml5.defaultOptionsCache === 'undefined') {
479
+ $.fn.wysihtml5.defaultOptionsCache = $.extend(true, {}, $.fn.wysihtml5.defaultOptions);
480
+ }
481
+
482
+ var locale = $.fn.wysihtml5.locale = {
483
+ en: {
484
+ font_styles: {
485
+ title: "Font style",
486
+ normal: "Normal text",
487
+ h1: "Heading 1",
488
+ h2: "Heading 2",
489
+ h3: "Heading 3"
490
+ },
491
+ emphasis: {
492
+ bold: "Bold",
493
+ italic: "Italic",
494
+ underline: "Underline"
495
+ },
496
+ lists: {
497
+ unordered: "Unordered list",
498
+ ordered: "Ordered list",
499
+ outdent: "Outdent",
500
+ indent: "Indent"
501
+ },
502
+ link: {
503
+ insert: "Insert link",
504
+ cancel: "Cancel"
505
+ },
506
+ image: {
507
+ insert: "Insert image",
508
+ cancel: "Cancel"
509
+ },
510
+ html: {
511
+ edit: "Edit HTML"
512
+ },
513
+ colours: {
514
+ title: "Text color",
515
+ black: "Black",
516
+ silver: "Silver",
517
+ gray: "Grey",
518
+ maroon: "Maroon",
519
+ red: "Red",
520
+ purple: "Purple",
521
+ green: "Green",
522
+ olive: "Olive",
523
+ navy: "Navy",
524
+ blue: "Blue",
525
+ orange: "Orange"
526
+ }
527
+ }
528
+ };
529
+
530
+ }(window.jQuery, window.wysihtml5);