bootsy 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (36) hide show
  1. data/MIT-LICENSE +20 -0
  2. data/README.md +79 -0
  3. data/Rakefile +27 -0
  4. data/app/assets/javascripts/bootsy/application.js +4 -0
  5. data/app/assets/javascripts/bootsy/bootstrap-wysihtml5.js +349 -0
  6. data/app/assets/javascripts/bootsy/bootsy.js +61 -0
  7. data/app/assets/javascripts/bootsy/wysihtml5.js +9521 -0
  8. data/app/assets/stylesheets/bootsy/application.css +4 -0
  9. data/app/assets/stylesheets/bootsy/bootstrap-wysihtml5.css +44 -0
  10. data/app/controllers/bootsy/application_controller.rb +4 -0
  11. data/app/controllers/bootsy/images_controller.rb +58 -0
  12. data/app/helpers/bootsy/application_helper.rb +8 -0
  13. data/app/helpers/bootsy/images_helper.rb +4 -0
  14. data/app/models/bootsy/image.rb +11 -0
  15. data/app/models/bootsy/image_gallery.rb +6 -0
  16. data/app/uploaders/image_uploader.rb +39 -0
  17. data/app/views/bootsy/images/_index.html.erb +22 -0
  18. data/app/views/bootsy/images/_modal.html.erb +12 -0
  19. data/app/views/bootsy/images/_new.html.erb +23 -0
  20. data/app/views/bootsy/images/create.js.erb +3 -0
  21. data/app/views/bootsy/images/destroy.js.erb +1 -0
  22. data/app/views/bootsy/images/index.js.erb +2 -0
  23. data/config/bootsy.yml +0 -0
  24. data/config/locales/en.yml +19 -0
  25. data/config/locales/pt-BR.yml +19 -0
  26. data/config/routes.rb +7 -0
  27. data/db/migrate/20120624171333_create_bootsy_images.rb +9 -0
  28. data/db/migrate/20120628124845_create_bootsy_image_galleries.rb +8 -0
  29. data/lib/bootsy.rb +8 -0
  30. data/lib/bootsy/core_ext.rb +34 -0
  31. data/lib/bootsy/engine.rb +16 -0
  32. data/lib/bootsy/media_container.rb +27 -0
  33. data/lib/bootsy/version.rb +3 -0
  34. data/lib/generators/install_generator.rb +27 -0
  35. data/lib/tasks/bootsy_tasks.rake +4 -0
  36. metadata +248 -0
data/MIT-LICENSE ADDED
@@ -0,0 +1,20 @@
1
+ Copyright 2012 YOURNAME
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,79 @@
1
+ Bootsy
2
+ ==========
3
+
4
+ *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/jnicklas/carrierwave).
5
+
6
+
7
+ ## Requirements
8
+
9
+ * Ruby MRI >= 1.9.3;
10
+ * Rails >= 3.2.6;
11
+ * Twitter Bootstrap properly integrated in your project's assets pipeline.
12
+
13
+
14
+ ## Installation
15
+
16
+ 1. Add Bootsy to your GemFile:
17
+
18
+ ```ruby
19
+ gem 'bootsy'
20
+ ```
21
+
22
+ 2. Run the bundle command to install it:
23
+
24
+ ```console
25
+ bundle install
26
+ ```
27
+
28
+ 3. Run the install generator:
29
+ ```console
30
+ rails g bootsy:install
31
+ ```
32
+
33
+ 4. Add and run migrations:
34
+ ```console
35
+ rake bootsy:install:migrations
36
+ rake db:migrate
37
+ ```
38
+
39
+
40
+ ## Usage
41
+
42
+ Just call the brand new method `bootsy_area` in your `FormBuilder` instances, in the same way that you call the basic `textarea` method. Example:
43
+
44
+ ```erb
45
+ <%= form_for(@post) do |f| %>
46
+ <%= f.label :title %><br />
47
+ <%= f.text_field :title %>
48
+
49
+ <%= f.label :content %><br />
50
+ <%= f.bootsy_area :content %>
51
+
52
+ <%= f.submit %>
53
+ <% end %>
54
+ ```
55
+
56
+ Bootsy will group the uploaded image files 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 `MediaContainer` module:
57
+
58
+ ```ruby
59
+ class Post < ActiveRecord::Base
60
+ include Bootsy::MediaContainer
61
+
62
+ attr_accessible :content, :title
63
+ end
64
+ ```
65
+
66
+
67
+ ## I18n
68
+
69
+ 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 for your language.
70
+
71
+
72
+ ## Mongoid support
73
+
74
+ Par default, Bootsy only supports ActiveRecord. A [Mongoid support](https://github.com/volmer/bootsy-mongoid) is currently in development.
75
+
76
+
77
+ ## License
78
+
79
+ MIT License. Copyright 2012 Volmer Soares
data/Rakefile ADDED
@@ -0,0 +1,27 @@
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
+
24
+
25
+
26
+ Bundler::GemHelper.install_tasks
27
+
@@ -0,0 +1,4 @@
1
+ //= require jquery.remotipart
2
+ //= require bootsy/wysihtml5
3
+ //= require bootsy/bootstrap-wysihtml5
4
+ //= require bootsy/bootsy
@@ -0,0 +1,349 @@
1
+ !function($, wysi) {
2
+ "use strict";
3
+
4
+ var templates = function(key, locale) {
5
+
6
+ var tpl = {
7
+ "font-styles": "<li class='dropdown'>" +
8
+ "<a class='btn dropdown-toggle' data-toggle='dropdown' href='#'>" +
9
+ "<i class='icon-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'>" + locale.font_styles.normal + "</a></li>" +
13
+ "<li><a data-wysihtml5-command='formatBlock' data-wysihtml5-command-value='h1'>" + locale.font_styles.h1 + "</a></li>" +
14
+ "<li><a data-wysihtml5-command='formatBlock' data-wysihtml5-command-value='h2'>" + locale.font_styles.h2 + "</a></li>" +
15
+ "</ul>" +
16
+ "</li>",
17
+ "emphasis": "<li>" +
18
+ "<div class='btn-group'>" +
19
+ "<a class='btn' data-wysihtml5-command='bold' title='CTRL+B'>" + locale.emphasis.bold + "</a>" +
20
+ "<a class='btn' data-wysihtml5-command='italic' title='CTRL+I'>" + locale.emphasis.italic + "</a>" +
21
+ "<a class='btn' data-wysihtml5-command='underline' title='CTRL+U'>" + locale.emphasis.underline + "</a>" +
22
+ "</div>" +
23
+ "</li>",
24
+ "lists": "<li>" +
25
+ "<div class='btn-group'>" +
26
+ "<a class='btn' data-wysihtml5-command='insertUnorderedList' title='" + locale.lists.unordered + "'><i class='icon-list'></i></a>" +
27
+ "<a class='btn' data-wysihtml5-command='insertOrderedList' title='" + locale.lists.ordered + "'><i class='icon-th-list'></i></a>" +
28
+ "<a class='btn' data-wysihtml5-command='Outdent' title='" + locale.lists.outdent + "'><i class='icon-indent-right'></i></a>" +
29
+ "<a class='btn' data-wysihtml5-command='Indent' title='" + locale.lists.indered + "'><i class='icon-indent-left'></i></a>" +
30
+ "</div>" +
31
+ "</li>",
32
+ "link": "<li>" +
33
+ "<div class='bootstrap-wysihtml5-insert-link-modal modal hide fade'>" +
34
+ "<div class='modal-header'>" +
35
+ "<a class='close' data-dismiss='modal'>&times;</a>" +
36
+ "<h3>" + locale.link.insert + "</h3>" +
37
+ "</div>" +
38
+ "<div class='modal-body'>" +
39
+ "<input value='http://' class='bootstrap-wysihtml5-insert-link-url input-xlarge'>" +
40
+ "</div>" +
41
+ "<div class='modal-footer'>" +
42
+ "<a href='#' class='btn' data-dismiss='modal'>" + locale.link.cancel + "</a>" +
43
+ "<a href='#' class='btn btn-primary' data-dismiss='modal'>" + locale.link.insert + "</a>" +
44
+ "</div>" +
45
+ "</div>" +
46
+ "<a class='btn' data-wysihtml5-command='createLink' title='" + locale.link.insert + "'><i class='icon-share'></i></a>" +
47
+ "</li>",
48
+ "image": "<li>" +
49
+ "<div class='bootstrap-wysihtml5-insert-image-modal modal hide fade'>" +
50
+ "<div class='modal-header'>" +
51
+ "<a class='close' data-dismiss='modal'>&times;</a>" +
52
+ "<h3>" + locale.image.insert + "</h3>" +
53
+ "</div>" +
54
+ "<div class='modal-body'>" +
55
+ "<input value='http://' class='bootstrap-wysihtml5-insert-image-url input-xlarge'>" +
56
+ "</div>" +
57
+ "<div class='modal-footer'>" +
58
+ "<a href='#' class='btn' data-dismiss='modal'>" + locale.image.cancel + "</a>" +
59
+ "<a href='#' class='btn btn-primary' data-dismiss='modal'>" + locale.image.insert + "</a>" +
60
+ "</div>" +
61
+ "</div>" +
62
+ "<a class='btn' data-wysihtml5-command='insertImage' title='" + locale.image.insert + "'><i class='icon-picture'></i></a>" +
63
+ "</li>",
64
+ "imageUpload": "<li>" +
65
+ "<a class='btn' data-wysihtml5-command='insertUploadedImage' title='" + locale.image.insert + "'><i class='icon-picture'></i></a>" +
66
+ "</li>",
67
+ "html":
68
+ "<li>" +
69
+ "<div class='btn-group'>" +
70
+ "<a class='btn' data-wysihtml5-action='change_view' title='" + locale.html.edit + "'><i class='icon-pencil'></i></a>" +
71
+ "</div>" +
72
+ "</li>"
73
+ };
74
+ return tpl[key];
75
+ };
76
+
77
+ var defaultOptions = {
78
+ "font-styles": true,
79
+ "emphasis": true,
80
+ "lists": true,
81
+ "html": false,
82
+ "link": true,
83
+ "image": true,
84
+ "imageUpload": false,
85
+ imageUploadCallback: undefined,
86
+ events: {},
87
+ parserRules: {
88
+ tags: {
89
+ "b": {},
90
+ "i": {},
91
+ "br": {},
92
+ "ol": {},
93
+ "ul": {},
94
+ "li": {},
95
+ "h1": {},
96
+ "h2": {},
97
+ "blockquote": {},
98
+ "u": 1,
99
+ "img": {
100
+ "check_attributes": {
101
+ "width": "numbers",
102
+ "alt": "alt",
103
+ "src": "url",
104
+ "height": "numbers"
105
+ }
106
+ },
107
+ "a": {
108
+ set_attributes: {
109
+ target: "_blank",
110
+ rel: "nofollow"
111
+ },
112
+ check_attributes: {
113
+ href: "url" // important to avoid XSS
114
+ }
115
+ }
116
+ }
117
+ },
118
+ stylesheets: [],
119
+ locale: "en"
120
+ };
121
+
122
+ var Wysihtml5 = function(el, options) {
123
+ this.el = el;
124
+ this.toolbar = this.createToolbar(el, options || defaultOptions);
125
+ this.editor = this.createEditor(options);
126
+
127
+ window.editor = this.editor;
128
+
129
+ $('iframe.wysihtml5-sandbox').each(function(i, el){
130
+ $(el.contentWindow).off('focus.wysihtml5').on({
131
+ 'focus.wysihtml5' : function(){
132
+ $('li.dropdown').removeClass('open');
133
+ }
134
+ });
135
+ });
136
+ };
137
+
138
+ Wysihtml5.prototype = {
139
+
140
+ constructor: Wysihtml5,
141
+
142
+ createEditor: function(options) {
143
+ options = $.extend(defaultOptions, options || {});
144
+ options.toolbar = this.toolbar[0];
145
+
146
+ var editor = new wysi.Editor(this.el[0], options);
147
+
148
+ if(options && options.events) {
149
+ for(var eventName in options.events) {
150
+ editor.on(eventName, options.events[eventName]);
151
+ }
152
+ }
153
+
154
+ return editor;
155
+ },
156
+
157
+ createToolbar: function(el, options) {
158
+ var self = this;
159
+ var toolbar = $("<ul/>", {
160
+ 'class' : "wysihtml5-toolbar",
161
+ 'style': "display:none"
162
+ });
163
+
164
+ console.log(options.locale);
165
+
166
+ for(var key in defaultOptions) {
167
+ var value = false;
168
+
169
+ if(options[key] !== undefined) {
170
+ if(options[key] === true) {
171
+ value = true;
172
+ }
173
+ } else {
174
+ value = defaultOptions[key];
175
+ }
176
+
177
+ if(value === true) {
178
+ toolbar.append(templates(key, locale[options.locale || "en"]));
179
+
180
+ if(key == "html") {
181
+ this.initHtml(toolbar);
182
+ }
183
+
184
+ if(key == "link") {
185
+ this.initInsertLink(toolbar);
186
+ }
187
+
188
+ if(key == "image") {
189
+ this.initInsertImage(toolbar);
190
+ }
191
+
192
+ if(key == "imageUpload") {
193
+ this.initInsertUploadedImage(toolbar, options.imageUploadCallback);
194
+ }
195
+ }
196
+ }
197
+
198
+ toolbar.find("a[data-wysihtml5-command='formatBlock']").click(function(e) {
199
+ var el = $(e.srcElement);
200
+ self.toolbar.find('.current-font').text(el.html());
201
+ });
202
+
203
+ this.el.before(toolbar);
204
+
205
+ return toolbar;
206
+ },
207
+
208
+ initHtml: function(toolbar) {
209
+ var changeViewSelector = "a[data-wysihtml5-action='change_view']";
210
+ toolbar.find(changeViewSelector).click(function(e) {
211
+ toolbar.find('a.btn').not(changeViewSelector).toggleClass('disabled');
212
+ });
213
+ },
214
+
215
+ initInsertImage: function(toolbar) {
216
+ var self = this;
217
+ var insertImageModal = toolbar.find('.bootstrap-wysihtml5-insert-image-modal');
218
+ var urlInput = insertImageModal.find('.bootstrap-wysihtml5-insert-image-url');
219
+ var insertButton = insertImageModal.find('a.btn-primary');
220
+ var initialValue = urlInput.val();
221
+
222
+ var insertImage = function() {
223
+ var url = urlInput.val();
224
+ urlInput.val(initialValue);
225
+ self.editor.composer.commands.exec("insertImage", url);
226
+ };
227
+
228
+ urlInput.keypress(function(e) {
229
+ if(e.which == 13) {
230
+ insertImage();
231
+ insertImageModal.modal('hide');
232
+ }
233
+ });
234
+
235
+ insertButton.click(insertImage);
236
+
237
+ insertImageModal.on('shown', function() {
238
+ urlInput.focus();
239
+ });
240
+
241
+ insertImageModal.on('hide', function() {
242
+ self.editor.currentView.element.focus();
243
+ });
244
+
245
+ toolbar.find('a[data-wysihtml5-command=insertImage]').click(function() {
246
+ insertImageModal.modal('show');
247
+ insertImageModal.on('click.dismiss.modal', '[data-dismiss="modal"]', function(e) {
248
+ e.stopPropagation();
249
+ });
250
+ return false;
251
+ });
252
+ },
253
+
254
+ initInsertUploadedImage: function(toolbar, callback) {
255
+ toolbar.find('a[data-wysihtml5-command=insertUploadedImage]').click(function() {
256
+ callback(this.editor);
257
+ return false;
258
+ });
259
+ },
260
+
261
+ initInsertLink: function(toolbar) {
262
+ var self = this;
263
+ var insertLinkModal = toolbar.find('.bootstrap-wysihtml5-insert-link-modal');
264
+ var urlInput = insertLinkModal.find('.bootstrap-wysihtml5-insert-link-url');
265
+ var insertButton = insertLinkModal.find('a.btn-primary');
266
+ var initialValue = urlInput.val();
267
+
268
+ var insertLink = function() {
269
+ var url = urlInput.val();
270
+ urlInput.val(initialValue);
271
+ self.editor.composer.commands.exec("createLink", {
272
+ href: url,
273
+ target: "_blank",
274
+ rel: "nofollow"
275
+ });
276
+ };
277
+ var pressedEnter = false;
278
+
279
+ urlInput.keypress(function(e) {
280
+ if(e.which == 13) {
281
+ insertLink();
282
+ insertLinkModal.modal('hide');
283
+ }
284
+ });
285
+
286
+ insertButton.click(insertLink);
287
+
288
+ insertLinkModal.on('shown', function() {
289
+ urlInput.focus();
290
+ });
291
+
292
+ insertLinkModal.on('hide', function() {
293
+ self.editor.currentView.element.focus();
294
+ });
295
+
296
+ toolbar.find('a[data-wysihtml5-command=createLink]').click(function() {
297
+ insertLinkModal.modal('show');
298
+ insertLinkModal.on('click.dismiss.modal', '[data-dismiss="modal"]', function(e) {
299
+ e.stopPropagation();
300
+ });
301
+ return false;
302
+ });
303
+
304
+
305
+ }
306
+ };
307
+
308
+ $.fn.wysihtml5 = function (options) {
309
+ return this.each(function () {
310
+ var $this = $(this);
311
+ $this.data('wysihtml5', new Wysihtml5($this, options));
312
+ });
313
+ };
314
+
315
+ $.fn.wysihtml5.Constructor = Wysihtml5;
316
+
317
+ var locale = $.fn.wysihtml5.locale = {
318
+ en: {
319
+ font_styles: {
320
+ normal: "Normal text",
321
+ h1: "Heading 1",
322
+ h2: "Heading 2"
323
+ },
324
+ emphasis: {
325
+ bold: "Bold",
326
+ italic: "Italic",
327
+ underline: "Underline"
328
+ },
329
+ lists: {
330
+ unordered: "Unordered list",
331
+ ordered: "Ordered list",
332
+ outdent: "Outdent",
333
+ indent: "Indent"
334
+ },
335
+ link: {
336
+ insert: "Insert link",
337
+ cancel: "Cancel"
338
+ },
339
+ image: {
340
+ insert: "Insert image",
341
+ cancel: "Cancel"
342
+ },
343
+ html: {
344
+ edit: "Edit HTML"
345
+ }
346
+ }
347
+ };
348
+
349
+ }(window.jQuery, window.wysihtml5);