bootsy-rails3 2.0.5.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +15 -0
- data/MIT-LICENSE +20 -0
- data/README.md +155 -0
- data/Rakefile +38 -0
- data/app/assets/images/bootsy/gallery-loader.gif +0 -0
- data/app/assets/images/bootsy/upload-loader.gif +0 -0
- data/app/assets/javascripts/bootsy.js +8 -0
- data/app/assets/javascripts/bootsy/bootstrap-wysihtml5.js +530 -0
- data/app/assets/javascripts/bootsy/bootstrap.file-input.js +122 -0
- data/app/assets/javascripts/bootsy/bootsy.js +305 -0
- data/app/assets/javascripts/bootsy/editor_options.js +80 -0
- data/app/assets/javascripts/bootsy/init.js +31 -0
- data/app/assets/javascripts/bootsy/locales/bootstrap-wysihtml5.pt-BR.js +50 -0
- data/app/assets/javascripts/bootsy/locales/bootsy.pt-BR.js +9 -0
- data/app/assets/javascripts/bootsy/translations.js +8 -0
- data/app/assets/javascripts/bootsy/wysihtml5.js +9564 -0
- data/app/assets/stylesheets/bootsy.css +3 -0
- data/app/assets/stylesheets/bootsy/bootstrap-submenu.css +47 -0
- data/app/assets/stylesheets/bootsy/bootstrap-wysihtml5.css +102 -0
- data/app/assets/stylesheets/bootsy/bootsy.css +161 -0
- data/app/controllers/bootsy/application_controller.rb +7 -0
- data/app/controllers/bootsy/images_controller.rb +80 -0
- data/app/helpers/bootsy/application_helper.rb +11 -0
- data/app/uploaders/bootsy/image_uploader.rb +35 -0
- data/app/views/bootsy/images/_image.html.erb +43 -0
- data/app/views/bootsy/images/_modal.html.erb +28 -0
- data/app/views/bootsy/images/_new.html.erb +8 -0
- data/config/cucumber.yml +8 -0
- data/config/locales/en.yml +27 -0
- data/config/locales/pt-BR.yml +27 -0
- data/config/routes.rb +11 -0
- data/db/migrate/20120624171333_create_bootsy_images.rb +9 -0
- data/db/migrate/20120628124845_create_bootsy_image_galleries.rb +8 -0
- data/lib/bootsy-rails3.rb +66 -0
- data/lib/bootsy/activerecord/image.rb +11 -0
- data/lib/bootsy/activerecord/image_gallery.rb +8 -0
- data/lib/bootsy/container.rb +31 -0
- data/lib/bootsy/core_ext.rb +2 -0
- data/lib/bootsy/engine.rb +31 -0
- data/lib/bootsy/form_builder.rb +7 -0
- data/lib/bootsy/form_helper.rb +68 -0
- data/lib/bootsy/simple_form/bootsy_input.rb +11 -0
- data/lib/bootsy/version.rb +3 -0
- data/lib/generators/bootsy/USAGE +12 -0
- data/lib/generators/bootsy/install_generator.rb +50 -0
- data/lib/generators/bootsy/templates/bootsy.rb +64 -0
- data/lib/tasks/bootsy_tasks.rake +4 -0
- data/lib/tasks/cucumber.rake +65 -0
- metadata +137 -0
checksums.yaml
ADDED
@@ -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=
|
data/MIT-LICENSE
ADDED
@@ -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.
|
data/README.md
ADDED
@@ -0,0 +1,155 @@
|
|
1
|
+
# Bootsy
|
2
|
+
|
3
|
+
[](http://badge.fury.io/rb/bootsy)
|
4
|
+
[](http://travis-ci.org/volmer/bootsy)
|
5
|
+
[](https://gemnasium.com/volmer/bootsy)
|
6
|
+
[](https://codeclimate.com/github/volmer/bootsy)
|
7
|
+
[](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
|
+
[](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
|
data/Rakefile
ADDED
@@ -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
|
Binary file
|
Binary file
|
@@ -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> <span class='current-font'>" + locale.font_styles.normal + "</span> <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'>×</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'>×</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> <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);
|