bootsy 1.2.0 → 2.0.0

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 06d4f6c3c4baaff130fb3321a969e1090706013e
4
- data.tar.gz: 75b66ce2924940d0d4b56a236adfac9de8651c0e
3
+ metadata.gz: 8b7b61a6335378da2590cdd884b0f7b5b7aa5840
4
+ data.tar.gz: c1f5549e531f7e423576602a0f611fb0ff96bb26
5
5
  SHA512:
6
- metadata.gz: e50200981071659ce01e15a40ab22f19b98c0910ec187ffb07cc41830b25f997071afacf374bfbc6532455d10af75a8b9ec3582b2729f5bb3ba87deba6ff1ac4
7
- data.tar.gz: 8e1dd14d053308773af5ca8db3cb7debe28ebf2619d8e7ac3f8f47063881cdcba67d79b5f8fab327246ac95f63871cb234f798c397694e122ff9044b4c2d2b80
6
+ metadata.gz: 6e9ff624b3d22b75b597c461b0161cbfc6346448a0e04dd2f21dc7c9b5ebb10c813ae780d8c00e2c477134c4b7cbbfe1736bad339991bc4e91db0df578ab3ecc
7
+ data.tar.gz: 02ac8fd962645345fac9236095a6ba41a64029706b13e467e1978318f0401356bb254100c56f78b3fbd9de2e0aaf636d15e6a2b3e8f907e2dac297fb8495c390
data/README.md CHANGED
@@ -8,13 +8,15 @@
8
8
 
9
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
10
 
11
+ ![image](https://f.cloud.github.com/assets/301187/1365250/e1b7ba80-3854-11e3-9bfe-8bd1e090aca8.png)
12
+
11
13
 
12
14
  ## Requirements
13
15
 
14
16
  * Ruby `2.0` or `1.9.3`;
15
17
  * ImageMagick or GraphicsMagick (for MiniMagick);
16
- * Rails `4.0` (you can get a *temporary* support for Rails `3.2` on [this branch](https://github.com/volmer/bootsy/tree/rails-3.2));
17
- * [Twitter Bootstrap](http://twitter.github.com/bootstrap/) properly added on your application.
18
+ * Rails `4.0`;
19
+ * [Bootstrap `3`](http://getbootstrap.com/) properly added to your application.
18
20
 
19
21
 
20
22
  ## Installation
@@ -31,8 +33,10 @@ bundle install
31
33
 
32
34
  3. Run the install generator:
33
35
  ```console
34
- rails g bootsy:install
36
+ rails generate bootsy:install
35
37
  ```
38
+ It will include the javascripts and stylesheets in the assets pipeline,
39
+ create the `bootsy.rb` initializer and add a copy of the english translations.
36
40
 
37
41
  4. Add and run migrations (if you're using ActiveRecord):
38
42
  ```console
@@ -43,7 +47,8 @@ rake db:migrate
43
47
 
44
48
  ## Usage
45
49
 
46
- Just call the brand new method `bootsy_area` in your `FormBuilder` instances, the same way you'd call the basic `textarea` method. Example:
50
+ Just call the brand new method `bootsy_area` in your `FormBuilder` instances, the
51
+ same way you'd call the basic `textarea` method. Example:
47
52
  ```erb
48
53
  <%= form_for(@post) do |f| %>
49
54
  <%= f.label :title %>
@@ -56,7 +61,9 @@ Just call the brand new method `bootsy_area` in your `FormBuilder` instances, th
56
61
  <% end %>
57
62
  ```
58
63
 
59
- Bootsy will group the uploaded images as galleries and associate them to one of your models. For example, if you have a `Post` model and you want to use `bootsy_area` with it, then you should include the `Bootsy::Container` module:
64
+ Bootsy will group the uploaded images as galleries and associate them to one of
65
+ your models. For example, if you have a `Post` model and you want to use `bootsy_area`
66
+ with it, then you should include the `Bootsy::Container` module:
60
67
  ```ruby
61
68
  class Post < ActiveRecord::Base
62
69
  include Bootsy::Container
@@ -65,7 +72,9 @@ class Post < ActiveRecord::Base
65
72
  end
66
73
  ```
67
74
 
68
- Don't forget to ensure the association of new instances of your model with Bootsy image galleries. For `strong_parameters`, you must allow the parameter `bootsy_image_gallery_id` in your controllers. Example:
75
+ Don't forget to ensure the association of new instances of your model with Bootsy
76
+ image galleries. For `strong_parameters`, you must allow the parameter `bootsy_image_gallery_id`
77
+ in your controllers. Example:
69
78
  ```ruby
70
79
  private
71
80
  # Never trust parameters from the scary internet, only allow the white list through.
@@ -75,9 +84,10 @@ end
75
84
  ```
76
85
 
77
86
 
78
- ## Bootsy with SimpleForm builders
87
+ ## Bootsy with [Simple Form](https://github.com/plataformatec/simple_form) builders
79
88
 
80
- Just use the brand new input type `bootsy` in your `SimpleForm::FormBuilder` instances, in the same way you would use the basic `text` input. Example:
89
+ Just use the brand new input type `bootsy` in your `SimpleForm::FormBuilder` instances,
90
+ in the same way you would use the basic `text` input. Example:
81
91
  ```erb
82
92
  <%= simple_form_for @post do |f| %>
83
93
  <%= f.input :title %>
@@ -91,12 +101,14 @@ Just use the brand new input type `bootsy` in your `SimpleForm::FormBuilder` ins
91
101
 
92
102
  ## Editor options
93
103
 
94
- It is possible to customize how the editor is displayed and its behavior by passing a hash `editor_options` to your `bootsy_area`.
104
+ It is possible to customize how the editor is displayed and its behavior by passing
105
+ a hash `editor_options` to your `bootsy_area`.
95
106
 
96
107
 
97
108
  ### Buttons
98
109
 
99
- You can enable/disable the buttons available on the editor. For example, if you want to disable the link and color buttons:
110
+ You can enable/disable the buttons available on the editor. For example, if you
111
+ want to disable the link and color buttons:
100
112
  ```erb
101
113
  <%= f.bootsy_area :my_attribute, editor_options: {link: false, color: false} %>
102
114
  ```
@@ -105,24 +117,36 @@ Available options are: `:font_styles`, `:emphasis`, `:lists`, `:html`, `:link`,
105
117
 
106
118
  ### Alert for usaved changes
107
119
 
108
- By default, Bootsy alerts for unsaved changes if the user attempts to unload the window. You can disable this behaviour by doing:
120
+ By default, Bootsy alerts for unsaved changes if the user attempts to unload
121
+ the window. You can disable this behaviour by doing:
109
122
  ```erb
110
123
  <%= f.bootsy_area :my_attribute, editor_options: {alert_unsaved: false} %>
111
124
  ```
112
125
 
113
126
  ## Uploader
114
127
 
115
- It's also possible to use Bootsy without the image upload feature. Just call `bootsy_area` in a form builder not associated to a `Bootsy::Container` model. This way users can insert images in their texts by providing an image url.
128
+ It's also possible to use Bootsy without the image upload feature. Just call
129
+ `bootsy_area` in a form builder not associated to a `Bootsy::Container` model.
130
+ This way users can insert images in their texts by providing an image url.
116
131
 
117
132
 
118
133
  ## Configuration
119
134
 
120
- You can set the default editor options, image sizes available (small, medium, large and/or its original), its dimensions and more. Take a look at the initalizer file, `/config/initializers/bootsy.rb`.
135
+ You can set the default editor options, image sizes available (small, medium,
136
+ large and/or its original), its dimensions and more. Take a look at the initalizer
137
+ file, `/config/initializers/bootsy.rb`.
121
138
 
122
139
 
123
140
  ## I18n
124
141
 
125
- Bootsy defines some i18n keys. The english translation is automatically added to your `config/locales` directory as `bootsy.en.yml`. You can follow that template in order to translate Bootsy to your language. You can find some examples [here](https://github.com/volmer/bootsy/tree/master/config/locales). It is also necessary to add a translation for Bootstrap-wysihtml5, the javascript editor, in your assets pipeline. Instructions [here](https://github.com/jhollingworth/bootstrap-wysihtml5#i18n). If you are using the alert for unsaved changes, you have to define a translation for it as well. Just follow [this example](https://github.com/volmer/bootsy/tree/master/app/assets/bootsy/locales/bootsy.pt-BR.js).
142
+ Bootsy defines some i18n keys. The english translation is automatically added
143
+ to your `config/locales` directory as `bootsy.en.yml`. You can follow that template
144
+ in order to translate Bootsy to your language. You can find some examples
145
+ [here](https://github.com/volmer/bootsy/tree/master/config/locales). It is also
146
+ necessary to add a translation for Bootstrap-wysihtml5, the javascript editor, in
147
+ your assets pipeline. Instructions [here](https://github.com/jhollingworth/bootstrap-wysihtml5#i18n).
148
+ If you are using the alert for unsaved changes, you have to define a translation
149
+ for it as well. Just follow [this example](https://github.com/volmer/bootsy/tree/master/app/assets/bootsy/locales/bootsy.pt-BR.js).
126
150
 
127
151
 
128
152
  ## License
@@ -5,14 +5,14 @@
5
5
  "font-styles": function(locale, options) {
6
6
  var size = (options && options.size) ? ' btn-'+options.size : '';
7
7
  return "<li class='dropdown'>" +
8
- "<a class='btn dropdown-toggle" + size + "' data-toggle='dropdown' href='#' title='" + locale.font_styles.title + "'>" +
8
+ "<a class='btn btn-default dropdown-toggle" + size + "' data-toggle='dropdown' href='#' title='" + locale.font_styles.title + "'>" +
9
9
  "<i class='icon-font'></i>&nbsp;<span class='current-font'>" + locale.font_styles.normal + "</span>&nbsp;<b class='caret'></b>" +
10
10
  "</a>" +
11
11
  "<ul class='dropdown-menu'>" +
12
- "<li><a data-wysihtml5-command='formatBlock' data-wysihtml5-command-value='div' tabindex='-1'>" + locale.font_styles.normal + "</a></li>" +
13
- "<li><a data-wysihtml5-command='formatBlock' data-wysihtml5-command-value='h1' tabindex='-1'>" + locale.font_styles.h1 + "</a></li>" +
14
- "<li><a data-wysihtml5-command='formatBlock' data-wysihtml5-command-value='h2' tabindex='-1'>" + locale.font_styles.h2 + "</a></li>" +
15
- "<li><a data-wysihtml5-command='formatBlock' data-wysihtml5-command-value='h3' tabindex='-1'>" + locale.font_styles.h3 + "</a></li>" +
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
16
  "</ul>" +
17
17
  "</li>";
18
18
  },
@@ -21,9 +21,9 @@
21
21
  var size = (options && options.size) ? ' btn-'+options.size : '';
22
22
  return "<li>" +
23
23
  "<div class='btn-group'>" +
24
- "<a class='btn" + size + "' data-wysihtml5-command='bold' title='CTRL+B' tabindex='-1'>" + locale.emphasis.bold + "</a>" +
25
- "<a class='btn" + size + "' data-wysihtml5-command='italic' title='CTRL+I' tabindex='-1'>" + locale.emphasis.italic + "</a>" +
26
- "<a class='btn" + size + "' data-wysihtml5-command='underline' title='CTRL+U' tabindex='-1'>" + locale.emphasis.underline + "</a>" +
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
27
  "</div>" +
28
28
  "</li>";
29
29
  },
@@ -32,10 +32,10 @@
32
32
  var size = (options && options.size) ? ' btn-'+options.size : '';
33
33
  return "<li>" +
34
34
  "<div class='btn-group'>" +
35
- "<a class='btn" + size + "' data-wysihtml5-command='insertUnorderedList' title='" + locale.lists.unordered + "' tabindex='-1'><i class='icon-list'></i></a>" +
36
- "<a class='btn" + size + "' data-wysihtml5-command='insertOrderedList' title='" + locale.lists.ordered + "' tabindex='-1'><i class='icon-th-list'></i></a>" +
37
- "<a class='btn" + size + "' data-wysihtml5-command='Outdent' title='" + locale.lists.outdent + "' tabindex='-1'><i class='icon-indent-left'></i></a>" +
38
- "<a class='btn" + size + "' data-wysihtml5-command='Indent' title='" + locale.lists.indent + "' tabindex='-1'><i class='icon-indent-right'></i></a>" +
35
+ "<a class='btn btn-default " + size + "' data-wysihtml5-command='insertUnorderedList' title='" + locale.lists.unordered + "' tabindex='-1'><i class='icon-list'></i></a>" +
36
+ "<a class='btn btn-default " + size + "' data-wysihtml5-command='insertOrderedList' title='" + locale.lists.ordered + "' tabindex='-1'><i class='icon-th-list'></i></a>" +
37
+ "<a class='btn btn-default " + size + "' data-wysihtml5-command='Outdent' title='" + locale.lists.outdent + "' tabindex='-1'><i class='icon-indent-left'></i></a>" +
38
+ "<a class='btn btn-default " + size + "' data-wysihtml5-command='Indent' title='" + locale.lists.indent + "' tabindex='-1'><i class='icon-indent-right'></i></a>" +
39
39
  "</div>" +
40
40
  "</li>";
41
41
  },
@@ -43,40 +43,48 @@
43
43
  "link": function(locale, options) {
44
44
  var size = (options && options.size) ? ' btn-'+options.size : '';
45
45
  return "<li>" +
46
- "<div class='bootstrap-wysihtml5-insert-link-modal modal hide fade'>" +
47
- "<div class='modal-header'>" +
48
- "<a class='close' data-dismiss='modal'>&times;</a>" +
49
- "<h3>" + locale.link.insert + "</h3>" +
50
- "</div>" +
51
- "<div class='modal-body'>" +
52
- "<input value='http://' class='bootstrap-wysihtml5-insert-link-url input-xlarge'>" +
53
- "</div>" +
54
- "<div class='modal-footer'>" +
55
- "<a href='#' class='btn' data-dismiss='modal'>" + locale.link.cancel + "</a>" +
56
- "<a href='#' class='btn btn-primary' data-dismiss='modal'>" + locale.link.insert + "</a>" +
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>" +
57
61
  "</div>" +
58
62
  "</div>" +
59
- "<a class='btn" + size + "' data-wysihtml5-command='createLink' title='" + locale.link.insert + "' tabindex='-1'><i class='icon-share'></i></a>" +
63
+ "<a class='btn btn-default " + size + "' data-wysihtml5-command='createLink' title='" + locale.link.insert + "' tabindex='-1'><i class='icon-share'></i></a>" +
60
64
  "</li>";
61
65
  },
62
66
 
63
67
  "image": function(locale, options) {
64
68
  var size = (options && options.size) ? ' btn-'+options.size : '';
65
69
  return "<li>" +
66
- "<div class='bootstrap-wysihtml5-insert-image-modal modal hide fade'>" +
67
- "<div class='modal-header'>" +
68
- "<a class='close' data-dismiss='modal'>&times;</a>" +
69
- "<h3>" + locale.image.insert + "</h3>" +
70
- "</div>" +
71
- "<div class='modal-body'>" +
72
- "<input value='http://' class='bootstrap-wysihtml5-insert-image-url input-xlarge'>" +
73
- "</div>" +
74
- "<div class='modal-footer'>" +
75
- "<a href='#' class='btn' data-dismiss='modal'>" + locale.image.cancel + "</a>" +
76
- "<a href='#' class='btn btn-primary' data-dismiss='modal'>" + locale.image.insert + "</a>" +
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>" +
77
85
  "</div>" +
78
86
  "</div>" +
79
- "<a class='btn" + size + "' data-wysihtml5-command='insertImage' title='" + locale.image.insert + "' tabindex='-1'><i class='icon-picture'></i></a>" +
87
+ "<a class='btn btn-default " + size + "' data-wysihtml5-command='insertImage' title='" + locale.image.insert + "' tabindex='-1'><i class='icon-picture'></i></a>" +
80
88
  "</li>";
81
89
  },
82
90
 
@@ -84,7 +92,7 @@
84
92
  var size = (options && options.size) ? ' btn-'+options.size : '';
85
93
  return "<li>" +
86
94
  "<div class='btn-group'>" +
87
- "<a class='btn" + size + "' data-wysihtml5-action='change_view' title='" + locale.html.edit + "' tabindex='-1'><i class='icon-pencil'></i></a>" +
95
+ "<a class='btn btn-default " + size + "' data-wysihtml5-action='change_view' title='" + locale.html.edit + "' tabindex='-1'><i class='icon-pencil'></i></a>" +
88
96
  "</div>" +
89
97
  "</li>";
90
98
  },
@@ -92,21 +100,21 @@
92
100
  "color": function(locale, options) {
93
101
  var size = (options && options.size) ? ' btn-'+options.size : '';
94
102
  return "<li class='dropdown'>" +
95
- "<a class='btn dropdown-toggle" + size + "' data-toggle='dropdown' href='#' tabindex='-1' title='" + locale.colours.title + "'>" +
103
+ "<a class='btn btn-default dropdown-toggle" + size + "' data-toggle='dropdown' href='#' tabindex='-1' title='" + locale.colours.title + "'>" +
96
104
  "<span class='current-color'>" + locale.colours.black + "</span>&nbsp;<b class='caret'></b>" +
97
105
  "</a>" +
98
106
  "<ul class='dropdown-menu'>" +
99
- "<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'>" + locale.colours.black + "</a></li>" +
100
- "<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'>" + locale.colours.silver + "</a></li>" +
101
- "<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'>" + locale.colours.gray + "</a></li>" +
102
- "<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'>" + locale.colours.maroon + "</a></li>" +
103
- "<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'>" + locale.colours.red + "</a></li>" +
104
- "<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'>" + locale.colours.purple + "</a></li>" +
105
- "<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'>" + locale.colours.green + "</a></li>" +
106
- "<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'>" + locale.colours.olive + "</a></li>" +
107
- "<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'>" + locale.colours.navy + "</a></li>" +
108
- "<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'>" + locale.colours.blue + "</a></li>" +
109
- "<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'>" + locale.colours.orange + "</a></li>" +
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>" +
110
118
  "</ul>" +
111
119
  "</li>";
112
120
  }
@@ -143,7 +151,7 @@
143
151
 
144
152
  createEditor: function(options) {
145
153
  options = options || {};
146
-
154
+
147
155
  // Add the toolbar to a clone of the options object so multiple instances
148
156
  // of the WYISYWG don't break because "toolbar" is already defined
149
157
  options = $.extend(true, {}, options);
@@ -392,7 +400,7 @@
392
400
  return methods.init.apply( this, arguments );
393
401
  } else {
394
402
  $.error( 'Method ' + method + ' does not exist on jQuery.wysihtml5' );
395
- }
403
+ }
396
404
  };
397
405
 
398
406
  $.fn.wysihtml5.Constructor = Wysihtml5;
@@ -41,7 +41,7 @@ $.fn.bootstrapFileInput = function() {
41
41
 
42
42
  // Now we're going to replace that input field with a Bootstrap button.
43
43
  // The input will actually still be there, it will just be float above and transparent (done with the CSS).
44
- $elem.replaceWith('<a class="file-input-wrapper btn' + className + '">'+buttonWord+input+'</a>');
44
+ $elem.replaceWith('<a class="file-input-wrapper btn btn-default ' + className + '">'+buttonWord+input+'</a>');
45
45
  })
46
46
 
47
47
  // After we have found all of the file inputs let's apply a listener for tracking the mouse movement.
@@ -1,221 +1,278 @@
1
1
  window.Bootsy = window.Bootsy || {};
2
2
 
3
- window.Bootsy.Area = function ($el) {
4
- var self = this;
5
- self.bootsyUploadInit = false; // this flag tells the refreshGallery method whether there was a new upload or not
3
+ Bootsy.Area = function($el) {
4
+ this.$el = $el;
5
+ this.modal = $el.siblings('.bootsy-modal');
6
+ this.locale = $el.data('bootsy-locale') || $('html').attr('lang') || 'en';
7
+ this.unsavedChanges = false;
6
8
 
7
- this.progressBar = function () {
8
- // Show loading spinner
9
- $('.bootsy-spinner img').fadeIn(200);
9
+ this.options = {
10
+ locale: this.locale,
11
+ alertUnsavedChanges: $el.data('bootsy-alert-unsaved'),
12
+ image: $el.data('bootsy-image'),
13
+ uploader: $el.data('bootsy-uploader'),
10
14
  };
11
15
 
12
- this.setImageGalleryId = function (id) {
13
- self.imageGalleryModal.data('bootsy-gallery-id', id)
14
- $('input.bootsy_image_gallery_id').val(id);
15
- };
16
+ if ($el.data('bootsy-font-styles') === false) this.options['font-styles'] = false;
17
+ if ($el.data('bootsy-emphasis') === false) this.options.emphasis = false;
18
+ if ($el.data('bootsy-lists') === false) this.options.lists = false;
19
+ if ($el.data('bootsy-html') === true) this.options.html = true;
20
+ if ($el.data('bootsy-link') === false) this.options.link = false;
21
+ if ($el.data('bootsy-color') === false) this.options.color = false;
16
22
 
17
- this.deleteImage = function (id) {
18
- self.imageGalleryModal.find("ul.thumbnails").find("[data-id='" + id + "']").hide(200, function(){
19
- $(this).remove();
20
- // Put message back if 0 images
21
- if ( self.imageGalleryModal.find('.thumbnails li').length == 0 ) {
22
- self.imageGalleryModal.find('.alert').fadeIn(200);
23
- }
24
- });
25
- };
23
+ // Delegate find to the modal
24
+ this.find = this.modal.find.bind(this.modal);
25
+ };
26
+
27
+
28
+ // Gallery loading
29
+ Bootsy.Area.prototype.showGalleryLoadingAnimation = function() {
30
+ this.find('.bootsy-gallery-loader').fadeIn(200);
31
+ };
32
+
33
+ Bootsy.Area.prototype.hideGalleryLoadingAnimation = function() {
34
+ this.find('.bootsy-gallery-loader').fadeOut(200);
35
+ };
26
36
 
27
- this.refreshGallery = function () {
28
- self.progressBar();
29
- $.ajax({
30
- url: '/bootsy/images',
31
- type: 'GET',
32
- cache: false,
33
- data: {
34
- image_gallery_id: self.imageGalleryModal.data('bootsy-gallery-id')
35
- },
36
- dataType: 'json',
37
- success: function (data) {
38
- // Hide loading spinner
39
- $('.bootsy-spinner img').fadeOut(200);
40
-
41
- // Cache the returned data
42
- var $data = $(data.partial);
43
-
44
- // Retrieve the last added li from the cached data
45
- img = $data.find('ul.thumbnails > li').last();
46
-
47
- if ( img.length ) {
48
- // Thumbnails currently exist in the retrieved data, so hide the message
49
- $('.alert').hide();
50
- } else {
51
- // Thumbnails do not exist in the retrieved data, so show the message
52
- $('.thumbnails li').hide();
53
- $('.alert').fadeIn(100);
54
- }
55
-
56
- if ( self.imageGalleryModal.find('.modal-body').children().length == 0 ) {
57
- // Init the modal content (only loads first time)
58
- self.imageGalleryModal.find('.modal-content').html($data).hide().fadeIn(200);
59
- // Nicer file input
60
- $('.modal-footer #image_image_file').bootstrapFileInput();
61
- } else if ( self.bootsyUploadInit == true ) {
62
- self.bootsyUploadInit = false;
63
- $(img).hide().appendTo(self.imageGalleryModal.find('.modal-body .thumbnails')).fadeIn(200);
64
- } else {
65
- // do nothing
66
- }
67
-
68
- self.imageGalleryModal.find('a.refresh-btn').hide();
69
- self.imageGalleryModal.find('#refresh-gallery').hide();
70
- self.imageGalleryModal.find('input#upload_submit').hide();
71
-
72
-
73
- // Autosubmit on image selection
74
- $('.modal-footer #image_image_file').on('change', function(){
75
- self.progressBar();
76
- self.bootsyUploadInit = true;
77
- $(this).closest('form').submit();
78
- });
79
-
80
- },
81
- error: function (e) {
82
- alert(Bootsy.translations[self.locale].error);
83
- self.imageGalleryModal.find('a.refresh-btn').show();
37
+
38
+ // Upload loading animation
39
+ Bootsy.Area.prototype.showUploadLoadingAnimation = function() {
40
+ this.find('.bootsy-upload-loader').fadeIn(200);
41
+ };
42
+
43
+ Bootsy.Area.prototype.hideUploadLoadingAnimation = function() {
44
+ this.find('.bootsy-upload-loader').fadeOut(200);
45
+ };
46
+
47
+ // Alert for empty gallery
48
+ Bootsy.Area.prototype.showEmptyAlert = function() {
49
+ this.find('.bootsy-empty-alert').fadeIn(200);
50
+ };
51
+
52
+ Bootsy.Area.prototype.hideEmptyAlert = function() {
53
+ this.find('.bootsy-empty-alert').fadeOut(200);
54
+ };
55
+
56
+ // Manual refresh button
57
+ Bootsy.Area.prototype.showRefreshButton = function() {
58
+ this.find('.refresh-btn').fadeIn(200);
59
+ };
60
+
61
+ Bootsy.Area.prototype.hideRefreshButton = function() {
62
+ this.find('.refresh-btn').fadeOut(200);
63
+ };
64
+
65
+
66
+ // Set upload form
67
+ Bootsy.Area.prototype.setUploadForm = function(html) {
68
+ var form;
69
+
70
+ this.find('.modal-footer').html(html);
71
+
72
+ this.hideUploadLoadingAnimation();
73
+
74
+ this.find('.bootsy-upload-form input[type="file"]').bootstrapFileInput();
75
+
76
+ this.uploadInput = this.find('.bootsy-upload-form input[type="file"]');
77
+
78
+ this.uploadInput.change(function() {
79
+ this.showUploadLoadingAnimation();
80
+
81
+ this.uploadInput.closest('form').submit();
82
+ }.bind(this));
83
+ };
84
+
85
+
86
+ // Set image gallery
87
+ Bootsy.Area.prototype.setImageGallery = function() {
88
+ this.showGalleryLoadingAnimation();
89
+
90
+ $.ajax({
91
+ url: '/bootsy/images',
92
+ type: 'GET',
93
+ cache: false,
94
+ data: {
95
+ image_gallery_id: this.modal.data('gallery-id')
96
+ },
97
+ dataType: 'json',
98
+ success: function(data) {
99
+ this.hideGalleryLoadingAnimation();
100
+
101
+ $.each(data.images, function(index, value) {
102
+ this.addImage(value);
103
+ }.bind(this));
104
+
105
+ if (data.images.length == 0) {
106
+ this.showEmptyAlert();
84
107
  }
85
- });
86
- };
87
108
 
88
- this.openImageGallery = function (editor) {
89
- editor.currentView.element.focus(false);
90
- self.caretBookmark = editor.composer.selection.getBookmark();
91
- $('#bootsy_image_gallery').modal('show');
92
- };
109
+ this.setUploadForm(data.form);
93
110
 
94
- this.insertImage = function (image) {
95
- $('#bootsy_image_gallery').modal('hide');
96
- self.editor.currentView.element.focus();
97
- if (self.caretBookmark) {
98
- self.editor.composer.selection.setBookmark(self.caretBookmark);
99
- self.caretBookmark = null;
100
- }
101
- self.editor.composer.commands.exec('insertImage', image);
102
- };
111
+ this.modal.data('gallery-loaded', true);
112
+ }.bind(this),
113
+ error: function(e) {
114
+ alert(Bootsy.translations[this.locale].error);
103
115
 
104
- this.on = function (eventName, callback) {
105
- self.eventCallbacks[eventName].push(callback);
106
- };
116
+ this.showRefreshButton();
117
+ }.bind(this)
118
+ });
119
+ };
107
120
 
108
- this.trigger = function (eventName) {
109
- var callbacks = self.eventCallbacks[eventName];
110
- for(i in callbacks) {
111
- callbacks[i]();
112
- }
113
- self.triggeredEvents.push(eventName);
114
- };
121
+ // Delete image
122
+ Bootsy.Area.prototype.deleteImage = function (id) {
123
+ var image = this.find('.bootsy-image[data-id="' + id + '"]');
115
124
 
116
- this.after = function (eventName, callback) {
117
- if(self.triggeredEvents.indexOf(eventName) != -1) {
118
- callback();
119
- }else{
120
- self.on(eventName, callback);
121
- }
122
- };
125
+ this.hideGalleryLoadingAnimation();
123
126
 
124
- this.alertUnsavedChanges = function () {
125
- if (self.unsavedChanges) {
126
- return Bootsy.translations[self.locale].alert_unsaved;
127
+ image.hide(200, function() {
128
+ image.remove();
129
+
130
+ // Put message back if 0 images
131
+ if (this.find('.bootsy-image').length == 0 ) {
132
+ this.showEmptyAlert();
127
133
  }
128
- };
134
+ }.bind(this));
135
+ };
129
136
 
130
- this.clear = function () {
131
- self.editor.clear();
132
- self.setImageGalleryId('');
133
- };
134
137
 
135
- this.locale = $el.data('bootsy-locale') || $('html').attr('lang') || 'en';
136
- this.caretBookmark = false;
137
- this.unsavedChanges = false;
138
- this.editor = false;
139
- this.eventCallbacks = {'loaded': []};
140
- this.triggeredEvents = [];
141
- this.editorOptions = {locale: this.locale};
142
-
143
- if ($el.data('bootsy-font-styles') === false) this.editorOptions['font-styles'] = false;
144
- if ($el.data('bootsy-emphasis') === false) this.editorOptions.emphasis = false;
145
- if ($el.data('bootsy-lists') === false) this.editorOptions.lists = false;
146
- if ($el.data('bootsy-html') === true) this.editorOptions.html = true;
147
- if ($el.data('bootsy-link') === false) this.editorOptions.link = false;
148
- if ($el.data('bootsy-color') === false) this.editorOptions.color = false;
149
-
150
- if ($el.data('bootsy-alert-unsaved') !== false) {
151
- window.onbeforeunload = this.alertUnsavedChanges;
138
+ // Add image to gallery
139
+ Bootsy.Area.prototype.addImage = function(html) {
140
+ this.hideEmptyAlert();
141
+
142
+ $(html).hide().appendTo(this.find('.bootsy-gallery')).fadeIn(200);
143
+ };
144
+
145
+ // Insert image in the text
146
+ Bootsy.Area.prototype.insertImage = function(image) {
147
+ this.modal.modal('hide');
148
+
149
+ this.editor.currentView.element.focus();
150
+
151
+ if (this.caretBookmark) {
152
+ this.editor.composer.selection.setBookmark(this.caretBookmark);
153
+ this.caretBookmark = null;
152
154
  }
153
155
 
154
- $el.closest('form').submit(function (e) {
155
- self.unsavedChanges = false;
156
- return true;
157
- });
156
+ this.editor.composer.commands.exec('insertImage', image);
157
+ };
158
+
159
+ // Open Bootsy modal
160
+ Bootsy.Area.prototype.openImagesModal = function(editor) {
161
+ editor.currentView.element.focus(false);
162
+
163
+ this.caretBookmark = editor.composer.selection.getBookmark();
164
+
165
+ this.modal.modal('show');
166
+ };
167
+
168
+ // Alert for unsaved changes
169
+ Bootsy.Area.prototype.unsavedChangesAlert = function () {
170
+ if (this.unsavedChanges) {
171
+ return Bootsy.translations[this.locale].alertUnsaved;
172
+ }
173
+ };
174
+
175
+ // Clear everything
176
+ Bootsy.Area.prototype.clear = function () {
177
+ this.editor.clear();
178
+ this.setImageGalleryId('');
179
+ this.modal.data('gallery-loaded', false);
180
+ };
181
+
182
+ // Set the image gallery id
183
+ Bootsy.Area.prototype.setImageGalleryId = function(id) {
184
+ this.modal.data('gallery-id', id);
185
+
186
+ this.$el.siblings('.bootsy_image_gallery_id').val(id);
187
+ };
188
+
189
+
190
+ // Init components
191
+ Bootsy.Area.prototype.init = function() {
192
+ var insert = this.insertImage.bind(this);
193
+
194
+ if ((this.options.image === true) && (this.options.uploader === true)) {
195
+ this.modal.on('click', '.bootsy-image .insert', function(e) {
196
+ var img, imageObject;
197
+ var imagePrefix = '/' + $(this).attr('data-image-size') + '_';
198
+
199
+ if ($(this).data('image-size') === 'original') {
200
+ imagePrefix = '/';
201
+ }
202
+
203
+ img = $(this).parents('.bootsy-image').find('img');
158
204
 
159
- if ($el.data('bootsy-image') !== false) {
160
- if ($el.data('bootsy-uploader') !== false) {
161
- this.editorOptions.image = false;
162
- this.editorOptions.customCommand = true;
163
- this.editorOptions.customCommandCallback = this.openImageGallery;
164
- this.editorOptions.customTemplates = {
165
- customCommand: function (locale, options) {
166
- var size = (options && options.size) ? ' btn-'+options.size : '';
167
- return "<li>" +
168
- "<a class='btn" + size + "' data-wysihtml5-command='customCommand' title='" + locale.image.insert + "' tabindex='-1'><i class='icon-picture'></i></a>" +
169
- "</li>";
170
- }
205
+ imageObject = {
206
+ src: img.attr('src').replace('/thumb_', imagePrefix),
207
+ alt: img.attr('alt').replace('Thumb_', '')
171
208
  };
172
209
 
173
- this.imageGalleryModal = $('#bootsy_image_gallery');
174
- this.imageGalleryModal.find('a.refresh-btn').hide();
210
+ imageObject.align = $(this).data('position');
175
211
 
176
- this.imageGalleryModal.parents('form').after(this.imageGalleryModal);
212
+ insert(imageObject);
213
+ });
177
214
 
178
- this.imageGalleryModal.on('click', 'a[href="#refresh-gallery"]', this.refreshGallery);
215
+ // Let's use the uploader, not the static image modal
216
+ this.options.image = false;
217
+ this.options.customCommand = true;
218
+ this.options.customCommandCallback = this.openImagesModal.bind(this);
219
+ this.options.customTemplates = {
220
+ customCommand: function(locale, options) {
221
+ var size = (options && options.size) ? ' btn-'+options.size : '';
222
+
223
+ return '<li>' +
224
+ '<a class="btn btn-default ' + size + '" data-wysihtml5-command="customCommand" title="' + locale.image.insert + '" tabindex="-1">' +
225
+ '<i class="icon-picture"></i>' +
226
+ '</a>' +
227
+ '</li>';
228
+ }
229
+ };
179
230
 
180
- this.imageGalleryModal.find('a.destroy_btn').click(this.progressBar);
231
+ // In order to avoid form nesting
232
+ this.modal.parents('form').after(this.modal);
181
233
 
182
- this.imageGalleryModal.modal({show: false});
183
- this.imageGalleryModal.on('shown', this.refreshGallery);
234
+ this.modal.on('click', 'a[href="#refresh-gallery"]', this.setImageGallery.bind(this));
184
235
 
185
- this.imageGalleryModal.on('hide', function () {
186
- self.progressBar();
187
- self.editor.currentView.element.focus();
188
- });
236
+ this.modal.on('ajax:before', '.destroy-btn', this.showGalleryLoadingAnimation.bind(this));
189
237
 
190
- this.imageGalleryModal.on('click.dismiss.modal', '[data-dismiss="modal"]', function (e) {
191
- e.stopPropagation();
192
- });
238
+ this.modal.on('ajax:success', '.destroy-btn', function(evt, data) {
239
+ this.deleteImage(data.id);
240
+ }.bind(this));
193
241
 
194
- this.imageGalleryModal.on('click', 'ul.dropdown-menu a.insert', function (e) {
195
- var imagePrefix = "/"+$(this).attr('data-image-size')+"_";
196
- if($(this).data('image-size') == 'original') {
197
- imagePrefix = '/';
198
- }
199
- var img = $(this).parents('li.dropdown').find('img');
200
- var obj = {
201
- src: img.attr('src').replace("/thumb_", imagePrefix),
202
- alt: img.attr('alt').replace("Thumb_", "")
203
- };
242
+ this.modal.on('ajax:success', '.bootsy-upload-form', function(evt, data) {
243
+ this.setImageGalleryId(data.gallery_id);
244
+ this.addImage(data.image);
245
+ this.setUploadForm(data.form);
246
+ }.bind(this));
247
+ }
204
248
 
205
- obj.align = $(this).data('position');
249
+ this.editor = this.$el.wysihtml5($.extend(Bootsy.options, this.options)).data('wysihtml5').editor;
206
250
 
207
- self.insertImage(obj);
208
- });
209
- }
210
- } else {
211
- this.editorOptions.image = false;
251
+ // Mechanism for unsaved changes alert
252
+ if (this.options.alertUnsavedChanges !== false) {
253
+ window.onbeforeunload = this.unsavedChangesAlert.bind(this);
212
254
  }
213
255
 
214
- this.editor = $el.wysihtml5($.extend(Bootsy.editorOptions, this.editorOptions)).data('wysihtml5').editor;
256
+ this.$el.closest('form').submit(function(e) {
257
+ this.unsavedChanges = false;
215
258
 
216
- this.editor.on('change', function () {
217
- self.unsavedChanges = true;
218
- });
259
+ return true;
260
+ }.bind(this));
261
+
262
+ this.editor.on('change', function() {
263
+ this.unsavedChanges = true;
264
+ }.bind(this));
265
+
266
+ this.modal.modal({ show: false });
267
+
268
+ this.modal.on('shown.bs.modal', function() {
269
+ if (this.modal.data('gallery-loaded') !== true) {
270
+ this.setImageGallery();
271
+ }
272
+ }.bind(this));
273
+
274
+ this.modal.on('hide.bs.modal', this.editor.currentView.element.focus);
219
275
 
220
- this.trigger('loaded');
276
+ this.hideRefreshButton();
277
+ this.hideEmptyAlert();
221
278
  };