bootstrap_wysiwyg-rails 1.0.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 39a0b37f2e84eb19e09d6d0bc88ade6ec226470a
4
+ data.tar.gz: cc5ee0b9cf4532ec46fcdbf0339a13a23bacbd16
5
+ SHA512:
6
+ metadata.gz: 179d706dfb5e98be4556ee6e81a88ecb4d498095daf3db3eb05b429b48a34b6c86178e607886cf000242d11b11bf8c24429c7275780f534ab70ca7bf8707ddd3
7
+ data.tar.gz: 20d0cfba83c45bcf65dde00ab4dc4d21584d64148e5fb2675425c409c045f99fa61ce390c9b93f5e5062ba9adb4ab411acf626cf7485227c523192cd8b6d4655
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2014 ldewald
2
+
3
+ MIT License
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining
6
+ a copy of this software and associated documentation files (the
7
+ "Software"), to deal in the Software without restriction, including
8
+ without limitation the rights to use, copy, modify, merge, publish,
9
+ distribute, sublicense, and/or sell copies of the Software, and to
10
+ permit persons to whom the Software is furnished to do so, subject to
11
+ the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be
14
+ included in all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@@ -0,0 +1,26 @@
1
+ # bootstrap_wysiwyg-rails
2
+
3
+ bootstrap_wysiwyg-rails wraps the [bootstrap-wysiwyg](https://github.com/steveathon/bootstrap-wysiwyg) library in a Rails engine for use with Rails 3.1 or higher. bootstrap-wysiwyg is a "Tiny Bootstrap and JQuery Based WISWYG rich text editor based on browser execCommand."
4
+
5
+ ## Usage
6
+ Add the following to your gemfile:
7
+
8
+ gem "bootstrap_wysiwyg-rails"
9
+
10
+ In your JavaScript manifest file (application.js) include the following:
11
+
12
+ //= require jquery.hotkeys
13
+ //= require bootstrap-wysiwyg
14
+
15
+ For complete usage instructions, see [http://mindmup.github.com/bootstrap-wysiwyg/](http://mindmup.github.com/bootstrap-wysiwyg/)
16
+ ## Versioning
17
+ Versioning will attempt to match the current bootstrap-wysiwyg version.
18
+
19
+ ## What's included
20
+ * bootstrap-wysiwyg 1.0.1
21
+ * jquery.hotkeys 0.8
22
+
23
+ ## Dependencies
24
+ * [jQuery](http://jquery.com/)
25
+ * [jQuery HotKeys](https://github.com/jeresig/jquery.hotkeys)
26
+ * [Bootstrap](http://twitter.github.com/bootstrap/)
@@ -0,0 +1,8 @@
1
+ require "bootstrap_wysiwyg-rails/version"
2
+
3
+ module BootstrapWysiwyg
4
+ module Rails
5
+ class Engine < ::Rails::Engine
6
+ end
7
+ end
8
+ end
@@ -0,0 +1,5 @@
1
+ module BootstrapWysiwyg
2
+ module Rails
3
+ VERSION = "1.0.1"
4
+ end
5
+ end
@@ -0,0 +1,332 @@
1
+ /* @fileoverview
2
+ * Provides full bootstrap based, multi-instance WYSIWYG editor.
3
+ *
4
+ * "Name" = 'bootstrap-wysiwyg'
5
+ * "Author" = 'Various, see LICENCE'
6
+ * "Version" = '1.0.1'
7
+ * "About" = 'Tiny Bootstrap and JQuery Based WISWYG rich text editor.'
8
+ */
9
+ (function ($) {
10
+ 'use strict';
11
+ /** underscoreThrottle()
12
+ * From underscore http://underscorejs.org/docs/underscore.html
13
+ */
14
+ var underscoreThrottle = function(func, wait) {
15
+ var context, args, timeout, result;
16
+ var previous = 0;
17
+ var later = function() {
18
+ previous = new Date;
19
+ timeout = null;
20
+ result = func.apply(context, args);
21
+ };
22
+ return function() {
23
+ var now = new Date;
24
+ var remaining = wait - (now - previous);
25
+ context = this;
26
+ args = arguments;
27
+ if (remaining <= 0) {
28
+ clearTimeout(timeout);
29
+ timeout = null;
30
+ previous = now;
31
+ result = func.apply(context, args);
32
+ } else if (!timeout) {
33
+ timeout = setTimeout(later, remaining);
34
+ }
35
+ return result;
36
+ };
37
+ }
38
+ var readFileIntoDataUrl = function (fileInfo) {
39
+ var loader = $.Deferred(),
40
+ fReader = new FileReader();
41
+ fReader.onload = function (e) {
42
+ loader.resolve(e.target.result);
43
+ };
44
+ fReader.onerror = loader.reject;
45
+ fReader.onprogress = loader.notify;
46
+ fReader.readAsDataURL(fileInfo);
47
+ return loader.promise();
48
+ };
49
+ $.fn.cleanHtml = function (o) {
50
+ if ( $(this).data("wysiwyg-html-mode") === true ) {
51
+ $(this).html($(this).text());
52
+ $(this).attr('contenteditable',true);
53
+ $(this).data('wysiwyg-html-mode',false);
54
+ }
55
+
56
+ // Strip the images with src="data:image/.." out;
57
+ if ( o === true && $(this).parent().is("form") ) {
58
+ var gGal = $(this).html;
59
+ if ( $(gGal).has( "img" ).length ) {
60
+ var gImages = $( "img", $(gGal));
61
+ var gResults = [];
62
+ var gEditor = $(this).parent();
63
+ $.each(gImages, function(i,v) {
64
+ if ( $(v).attr('src').match(/^data:image\/.*$/) ) {
65
+ gResults.push(gImages[i]);
66
+ $(gEditor).prepend("<input value='"+$(v).attr('src')+"' type='hidden' name='postedimage/"+i+"' />");
67
+ $(v).attr('src', 'postedimage/'+i);
68
+ }});
69
+ }
70
+ }
71
+ var html = $(this).html();
72
+ return html && html.replace(/(<br>|\s|<div><br><\/div>|&nbsp;)*$/, '');
73
+ };
74
+ $.fn.wysiwyg = function (userOptions) {
75
+ var editor = this,
76
+ wrapper = $(editor).parent(),
77
+ selectedRange,
78
+ options,
79
+ toolbarBtnSelector,
80
+ updateToolbar = function () {
81
+ if (options.activeToolbarClass) {
82
+ $(options.toolbarSelector,wrapper).find(toolbarBtnSelector).each(underscoreThrottle(function () {
83
+ var commandArr = $(this).data(options.commandRole).split(' '),
84
+ command = commandArr[0];
85
+
86
+ // If the command has an argument and its value matches this button. == used for string/number comparison
87
+ if (commandArr.length > 1 && document.queryCommandEnabled(command) && document.queryCommandValue(command) == commandArr[1]) {
88
+ $(this).addClass(options.activeToolbarClass);
89
+ // Else if the command has no arguments and it is active
90
+ } else if (commandArr.length === 1 && document.queryCommandEnabled(command) && document.queryCommandState(command)) {
91
+ $(this).addClass(options.activeToolbarClass);
92
+ // Else the command is not active
93
+ } else {
94
+ $(this).removeClass(options.activeToolbarClass);
95
+ }
96
+ }, options.keypressTimeout));
97
+ }
98
+ },
99
+ execCommand = function (commandWithArgs, valueArg) {
100
+ var commandArr = commandWithArgs.split(' '),
101
+ command = commandArr.shift(),
102
+ args = commandArr.join(' ') + (valueArg || '');
103
+
104
+ var parts = commandWithArgs.split('-');
105
+
106
+ if ( parts.length == 1 ) {
107
+ document.execCommand(command, 0, args);
108
+ }
109
+ else if ( parts[0] == 'format' && parts.length == 2) {
110
+ document.execCommand('formatBlock', false, parts[1] );
111
+ }
112
+
113
+ editor.trigger('change');
114
+ updateToolbar();
115
+ },
116
+ bindHotkeys = function (hotKeys) {
117
+ $.each(hotKeys, function (hotkey, command) {
118
+ editor.keydown(hotkey, function (e) {
119
+ if (editor.attr('contenteditable') && editor.is(':visible')) {
120
+ e.preventDefault();
121
+ e.stopPropagation();
122
+ execCommand(command);
123
+ }
124
+ }).keyup(hotkey, function (e) {
125
+ if (editor.attr('contenteditable') && editor.is(':visible')) {
126
+ e.preventDefault();
127
+ e.stopPropagation();
128
+ }
129
+ });
130
+ });
131
+
132
+ editor.keyup(function(){ editor.trigger('change'); });
133
+ },
134
+ getCurrentRange = function () {
135
+ var sel, range;
136
+ if (window.getSelection) {
137
+ sel = window.getSelection();
138
+ if (sel.getRangeAt && sel.rangeCount) {
139
+ range = sel.getRangeAt(0);
140
+ }
141
+ } else if (document.selection) {
142
+ range = document.selection.createRange();
143
+ } return range;
144
+ },
145
+ saveSelection = function () {
146
+ selectedRange = getCurrentRange();
147
+ },
148
+ restoreSelection = function () {
149
+ var selection;
150
+ if (window.getSelection || document.createRange) {
151
+ selection = window.getSelection();
152
+ if (selectedRange) {
153
+ try {
154
+ selection.removeAllRanges();
155
+ } catch (ex) {
156
+ document.body.createTextRange().select();
157
+ document.selection.empty();
158
+ }
159
+ selection.addRange(selectedRange);
160
+ }
161
+ }
162
+ else if (document.selection && selectedRange) {
163
+ selectedRange.select()
164
+ }
165
+ },
166
+
167
+ // Adding Toggle HTML based on the work by @jd0000, but cleaned up a little to work in this context.
168
+ toggleHtmlEdit = function(a) {
169
+ if ( $(editor).data("wysiwyg-html-mode") !== true ) {
170
+ var oContent = $(editor).html();
171
+ var editorPre = $( "<pre />" )
172
+ $(editorPre).append( document.createTextNode( oContent ) );
173
+ $(editorPre).attr('contenteditable',true);
174
+ $(editor).html(' ');
175
+ $(editor).append($(editorPre));
176
+ $(editor).attr('contenteditable', false);
177
+ $(editor).data("wysiwyg-html-mode", true);
178
+ $(editorPre).focus();
179
+ }
180
+ else {
181
+ $(editor).html($(editor).text());
182
+ $(editor).attr('contenteditable',true);
183
+ $(editor).data('wysiwyg-html-mode',false);
184
+ $(editor).focus();
185
+ }
186
+ },
187
+
188
+ insertFiles = function (files) {
189
+ editor.focus();
190
+ $.each(files, function (idx, fileInfo) {
191
+ if (/^image\//.test(fileInfo.type)) {
192
+ $.when(readFileIntoDataUrl(fileInfo)).done(function (dataUrl) {
193
+ execCommand('insertimage', dataUrl);
194
+ editor.trigger('image-inserted');
195
+ }).fail(function (e) {
196
+ options.fileUploadError("file-reader", e);
197
+ });
198
+ } else {
199
+ options.fileUploadError("unsupported-file-type", fileInfo.type);
200
+ }
201
+ });
202
+ },
203
+ markSelection = function (input, color) {
204
+ restoreSelection();
205
+ if (document.queryCommandSupported('hiliteColor')) {
206
+ document.execCommand('hiliteColor', 0, color || 'transparent');
207
+ }
208
+ saveSelection();
209
+ input.data(options.selectionMarker, color);
210
+ },
211
+ bindToolbar = function (toolbar, options) {
212
+ toolbar.find(toolbarBtnSelector, wrapper).click(function () {
213
+ restoreSelection();
214
+ editor.focus();
215
+
216
+ if ($(this).data(options.commandRole) === 'html') {
217
+ toggleHtmlEdit();
218
+ }
219
+ else {
220
+ execCommand($(this).data(options.commandRole));
221
+ }
222
+ saveSelection();
223
+ });
224
+ toolbar.find('[data-toggle=dropdown]').click(restoreSelection);
225
+
226
+ toolbar.find('input[type=text][data-' + options.commandRole + ']').on('webkitspeechchange change', function () {
227
+ var newValue = this.value; /* ugly but prevents fake double-calls due to selection restoration */
228
+ this.value = '';
229
+ restoreSelection();
230
+ if (newValue) {
231
+ editor.focus();
232
+ execCommand($(this).data(options.commandRole), newValue);
233
+ }
234
+ saveSelection();
235
+ }).on('focus', function () {
236
+ var input = $(this);
237
+ if (!input.data(options.selectionMarker)) {
238
+ markSelection(input, options.selectionColor);
239
+ input.focus();
240
+ }
241
+ }).on('blur', function () {
242
+ var input = $(this);
243
+ if (input.data(options.selectionMarker)) {
244
+ markSelection(input, false);
245
+ }
246
+ });
247
+ toolbar.find('input[type=file][data-' + options.commandRole + ']').change(function () {
248
+ restoreSelection();
249
+ if (this.type === 'file' && this.files && this.files.length > 0) {
250
+ insertFiles(this.files);
251
+ }
252
+ saveSelection();
253
+ this.value = '';
254
+ });
255
+ },
256
+ initFileDrops = function () {
257
+ editor.on('dragenter dragover', false)
258
+ .on('drop', function (e) {
259
+ var dataTransfer = e.originalEvent.dataTransfer;
260
+ e.stopPropagation();
261
+ e.preventDefault();
262
+ if (dataTransfer && dataTransfer.files && dataTransfer.files.length > 0) {
263
+ insertFiles(dataTransfer.files);
264
+ }
265
+ });
266
+ };
267
+ options = $.extend(true, {}, $.fn.wysiwyg.defaults, userOptions);
268
+ toolbarBtnSelector = 'a[data-' + options.commandRole + '],button[data-' + options.commandRole + '],input[type=button][data-' + options.commandRole + ']';
269
+ bindHotkeys(options.hotKeys);
270
+
271
+ // Support placeholder attribute on the DIV
272
+ if ($(this).attr('placeholder') != '') {
273
+ $(this).addClass('placeholderText');
274
+ $(this).html($(this).attr('placeholder'));
275
+ $(this).bind('focus',function(e) {
276
+ if ( $(this).attr('placeholder') != '' && $(this).text() == $(this).attr('placeholder') ) {
277
+ $(this).removeClass('placeholderText');
278
+ $(this).html('');
279
+ }
280
+ });
281
+ $(this).bind('blur',function(e) {
282
+ if ( $(this).attr('placeholder') != '' && $(this).text() == '' ) {
283
+ $(this).addClass('placeholderText');
284
+ $(this).html($(this).attr('placeholder'));
285
+ }
286
+ })
287
+ }
288
+
289
+ if (options.dragAndDropImages) {
290
+ initFileDrops();
291
+ }
292
+ bindToolbar($(options.toolbarSelector), options);
293
+ editor.attr('contenteditable', true)
294
+ .on('mouseup keyup mouseout', function () {
295
+ saveSelection();
296
+ updateToolbar();
297
+ });
298
+ $(window).bind('touchend', function (e) {
299
+ var isInside = (editor.is(e.target) || editor.has(e.target).length > 0),
300
+ currentRange = getCurrentRange(),
301
+ clear = currentRange && (currentRange.startContainer === currentRange.endContainer && currentRange.startOffset === currentRange.endOffset);
302
+ if (!clear || isInside) {
303
+ saveSelection();
304
+ updateToolbar();
305
+ }
306
+ });
307
+ return this;
308
+ };
309
+ $.fn.wysiwyg.defaults = {
310
+ hotKeys: {
311
+ 'Ctrl+b meta+b': 'bold',
312
+ 'Ctrl+i meta+i': 'italic',
313
+ 'Ctrl+u meta+u': 'underline',
314
+ 'Ctrl+z': 'undo',
315
+ 'Ctrl+y meta+y meta+shift+z': 'redo',
316
+ 'Ctrl+l meta+l': 'justifyleft',
317
+ 'Ctrl+r meta+r': 'justifyright',
318
+ 'Ctrl+e meta+e': 'justifycenter',
319
+ 'Ctrl+j meta+j': 'justifyfull',
320
+ 'Shift+tab': 'outdent',
321
+ 'tab': 'indent'
322
+ },
323
+ toolbarSelector: '[data-role=editor-toolbar]',
324
+ commandRole: 'edit',
325
+ activeToolbarClass: 'btn-info',
326
+ selectionMarker: 'edit-focus-marker',
327
+ selectionColor: 'darkgrey',
328
+ dragAndDropImages: true,
329
+ keypressTimeout: 200,
330
+ fileUploadError: function (reason, detail) { console.log("File upload error", reason, detail); }
331
+ };
332
+ }(window.jQuery));
@@ -0,0 +1,99 @@
1
+ /*
2
+ * jQuery Hotkeys Plugin
3
+ * Copyright 2010, John Resig
4
+ * Dual licensed under the MIT or GPL Version 2 licenses.
5
+ *
6
+ * Based upon the plugin by Tzury Bar Yochay:
7
+ * http://github.com/tzuryby/hotkeys
8
+ *
9
+ * Original idea by:
10
+ * Binny V A, http://www.openjs.com/scripts/events/keyboard_shortcuts/
11
+ */
12
+
13
+ (function(jQuery){
14
+
15
+ jQuery.hotkeys = {
16
+ version: "0.8",
17
+
18
+ specialKeys: {
19
+ 8: "backspace", 9: "tab", 13: "return", 16: "shift", 17: "ctrl", 18: "alt", 19: "pause",
20
+ 20: "capslock", 27: "esc", 32: "space", 33: "pageup", 34: "pagedown", 35: "end", 36: "home",
21
+ 37: "left", 38: "up", 39: "right", 40: "down", 45: "insert", 46: "del",
22
+ 96: "0", 97: "1", 98: "2", 99: "3", 100: "4", 101: "5", 102: "6", 103: "7",
23
+ 104: "8", 105: "9", 106: "*", 107: "+", 109: "-", 110: ".", 111 : "/",
24
+ 112: "f1", 113: "f2", 114: "f3", 115: "f4", 116: "f5", 117: "f6", 118: "f7", 119: "f8",
25
+ 120: "f9", 121: "f10", 122: "f11", 123: "f12", 144: "numlock", 145: "scroll", 191: "/", 224: "meta"
26
+ },
27
+
28
+ shiftNums: {
29
+ "`": "~", "1": "!", "2": "@", "3": "#", "4": "$", "5": "%", "6": "^", "7": "&",
30
+ "8": "*", "9": "(", "0": ")", "-": "_", "=": "+", ";": ": ", "'": "\"", ",": "<",
31
+ ".": ">", "/": "?", "\\": "|"
32
+ }
33
+ };
34
+
35
+ function keyHandler( handleObj ) {
36
+ // Only care when a possible input has been specified
37
+ if ( typeof handleObj.data !== "string" ) {
38
+ return;
39
+ }
40
+
41
+ var origHandler = handleObj.handler,
42
+ keys = handleObj.data.toLowerCase().split(" ");
43
+
44
+ handleObj.handler = function( event ) {
45
+ // Don't fire in text-accepting inputs that we didn't directly bind to
46
+ if ( this !== event.target && (/textarea|select/i.test( event.target.nodeName ) ||
47
+ event.target.type === "text") ) {
48
+ return;
49
+ }
50
+
51
+ // Keypress represents characters, not special keys
52
+ var special = event.type !== "keypress" && jQuery.hotkeys.specialKeys[ event.which ],
53
+ character = String.fromCharCode( event.which ).toLowerCase(),
54
+ key, modif = "", possible = {};
55
+
56
+ // check combinations (alt|ctrl|shift+anything)
57
+ if ( event.altKey && special !== "alt" ) {
58
+ modif += "alt+";
59
+ }
60
+
61
+ if ( event.ctrlKey && special !== "ctrl" ) {
62
+ modif += "ctrl+";
63
+ }
64
+
65
+ // TODO: Need to make sure this works consistently across platforms
66
+ if ( event.metaKey && !event.ctrlKey && special !== "meta" ) {
67
+ modif += "meta+";
68
+ }
69
+
70
+ if ( event.shiftKey && special !== "shift" ) {
71
+ modif += "shift+";
72
+ }
73
+
74
+ if ( special ) {
75
+ possible[ modif + special ] = true;
76
+
77
+ } else {
78
+ possible[ modif + character ] = true;
79
+ possible[ modif + jQuery.hotkeys.shiftNums[ character ] ] = true;
80
+
81
+ // "$" can be triggered as "Shift+4" or "Shift+$" or just "$"
82
+ if ( modif === "shift+" ) {
83
+ possible[ jQuery.hotkeys.shiftNums[ character ] ] = true;
84
+ }
85
+ }
86
+
87
+ for ( var i = 0, l = keys.length; i < l; i++ ) {
88
+ if ( possible[ keys[i] ] ) {
89
+ return origHandler.apply( this, arguments );
90
+ }
91
+ }
92
+ };
93
+ }
94
+
95
+ jQuery.each([ "keydown", "keyup", "keypress" ], function() {
96
+ jQuery.event.special[ this ] = { add: keyHandler };
97
+ });
98
+
99
+ })( jQuery );
metadata ADDED
@@ -0,0 +1,92 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: bootstrap_wysiwyg-rails
3
+ version: !ruby/object:Gem::Version
4
+ version: 1.0.1
5
+ platform: ruby
6
+ authors:
7
+ - ldewald
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2014-12-25 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: bundler
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '1.7'
20
+ type: :development
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '1.7'
27
+ - !ruby/object:Gem::Dependency
28
+ name: rake
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: '10.0'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: '10.0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: railties
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - ">="
46
+ - !ruby/object:Gem::Version
47
+ version: '3.1'
48
+ type: :runtime
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - ">="
53
+ - !ruby/object:Gem::Version
54
+ version: '3.1'
55
+ description:
56
+ email:
57
+ - laurardewald@gmail.com
58
+ executables: []
59
+ extensions: []
60
+ extra_rdoc_files: []
61
+ files:
62
+ - LICENSE.txt
63
+ - README.md
64
+ - lib/bootstrap_wysiwyg-rails.rb
65
+ - lib/bootstrap_wysiwyg-rails/version.rb
66
+ - vendor/assets/javascripts/bootstrap-wysiwyg.js
67
+ - vendor/assets/javascripts/jquery.hotkeys.js
68
+ homepage: https://github.com/ldewald/bootstrap_wysiwyg-rails
69
+ licenses:
70
+ - MIT
71
+ metadata: {}
72
+ post_install_message:
73
+ rdoc_options: []
74
+ require_paths:
75
+ - lib
76
+ required_ruby_version: !ruby/object:Gem::Requirement
77
+ requirements:
78
+ - - ">="
79
+ - !ruby/object:Gem::Version
80
+ version: '0'
81
+ required_rubygems_version: !ruby/object:Gem::Requirement
82
+ requirements:
83
+ - - ">="
84
+ - !ruby/object:Gem::Version
85
+ version: '0'
86
+ requirements: []
87
+ rubyforge_project:
88
+ rubygems_version: 2.2.2
89
+ signing_key:
90
+ specification_version: 4
91
+ summary: bootstrap-wysiwyg packaged up for Rails
92
+ test_files: []