atomic_cms 0.2.1 → 0.2.2
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.eslintrc +16 -0
- data/.gitignore +11 -0
- data/.rspec +2 -0
- data/.rubocop.yml +5 -0
- data/.ruby-version +1 -0
- data/Gemfile +2 -0
- data/Gemfile.lock +243 -0
- data/README.md +175 -0
- data/Rakefile +15 -0
- data/app/assets/images/icon_add_component.png +0 -0
- data/app/assets/images/icon_add_component@2x.png +0 -0
- data/app/assets/javascripts/atomic_cms.js +286 -0
- data/app/assets/stylesheets/atomic_cms.css.scss +135 -0
- data/app/components/array_component.rb +11 -0
- data/app/controllers/atomic_cms/components_controller.rb +7 -0
- data/app/controllers/atomic_cms/media_controller.rb +18 -0
- data/app/controllers/concerns/media_scrubber.rb +28 -0
- data/app/helpers/component_helper.rb +21 -0
- data/app/models/atomic_cms/image.rb +6 -0
- data/app/models/atomic_cms/media.rb +12 -0
- data/app/views/components/_children_field.html.slim +6 -0
- data/app/views/components/_edit.html.slim +2 -0
- data/app/views/components/_file_field.slim +5 -0
- data/app/views/components/_markdown_field.slim +5 -0
- data/app/views/components/_select_field.slim +5 -0
- data/app/views/components/_template_field.slim +1 -0
- data/app/views/components/_text_area_field.slim +4 -0
- data/app/views/components/_text_field.slim +3 -0
- data/atomic_cms.gemspec +30 -0
- data/bin/rails +12 -0
- data/config/routes.rb +4 -0
- data/db/migrate/20151013175254_create_media.rb +9 -0
- data/lib/generators/atomic_cms/assets/assets_generator.rb +33 -7
- data/lib/generators/atomic_cms/scaffold/scaffold_generator.rb +76 -0
- data/lib/generators/atomic_cms/templates/admin.erb +79 -0
- data/lib/generators/atomic_cms/templates/controller.erb +16 -0
- data/lib/generators/atomic_cms/templates/model.erb +4 -0
- data/lib/generators/atomic_cms/templates/show.html.slim +1 -0
- data/vendor/assets/javascripts/angular-markdown.js +19 -0
- data/vendor/assets/javascripts/showdown.min.js +2 -0
- metadata +40 -21
@@ -0,0 +1,286 @@
|
|
1
|
+
//= require angular-markdown
|
2
|
+
//= require showdown.min
|
3
|
+
|
4
|
+
(function() {
|
5
|
+
'use strict';
|
6
|
+
var findElementIndex, page, positionEditBox, scrollTo, cmsType;
|
7
|
+
|
8
|
+
findElementIndex = function(node) {
|
9
|
+
var i = 0;
|
10
|
+
while (node.previousSibling) {
|
11
|
+
node = node.previousSibling;
|
12
|
+
if (node.nodeType === 1) {
|
13
|
+
i += 1;
|
14
|
+
}
|
15
|
+
}
|
16
|
+
return i;
|
17
|
+
};
|
18
|
+
|
19
|
+
scrollTo = function(node) {
|
20
|
+
return $('html, body').animate({
|
21
|
+
scrollTop: $(node).offset().top
|
22
|
+
}, 0);
|
23
|
+
};
|
24
|
+
|
25
|
+
positionEditBox = function(node) {
|
26
|
+
var minTop, top;
|
27
|
+
minTop = $('#edit-' + cmsType()).offset().top + $('#edit-' + cmsType()).height() + 25;
|
28
|
+
top = Math.max(minTop, $(node).offset().top);
|
29
|
+
top -= $('#edit-node-column').offset().top;
|
30
|
+
return $('#edit-node').css({
|
31
|
+
top: top
|
32
|
+
}).show();
|
33
|
+
};
|
34
|
+
|
35
|
+
cmsType = function(node) {
|
36
|
+
var cms_type = angular.element(document.querySelector('#cms_type')).val();
|
37
|
+
return (cms_type !== undefined) ? cms_type : 'page';
|
38
|
+
};
|
39
|
+
|
40
|
+
page = angular.module('page', ['markdown', 'ngSanitize']);
|
41
|
+
|
42
|
+
page.filter('vimeo_url', [
|
43
|
+
'$sce', function($sce) {
|
44
|
+
return function(id) {
|
45
|
+
if (id.match(/^\d+$/)) {
|
46
|
+
return $sce.trustAsResourceUrl('https://player.vimeo.com/video/' + id);
|
47
|
+
}
|
48
|
+
};
|
49
|
+
}
|
50
|
+
]);
|
51
|
+
|
52
|
+
page.controller('CmsCtrl', [
|
53
|
+
'$scope', function($scope) {
|
54
|
+
$scope.prefix = cmsType() + '[content_object]';
|
55
|
+
return $scope.preview = {};
|
56
|
+
}
|
57
|
+
]);
|
58
|
+
|
59
|
+
page.directive('cmsNode', function() {
|
60
|
+
return {
|
61
|
+
restrict: 'A',
|
62
|
+
scope: true,
|
63
|
+
controller: [
|
64
|
+
'$scope', '$compile', function($scope, $compile) {
|
65
|
+
$scope.$compile = $compile;
|
66
|
+
$scope.preview = {};
|
67
|
+
return $scope.dragControlListeners = {
|
68
|
+
itemMoved: function(event) {
|
69
|
+
return alert('moved');
|
70
|
+
},
|
71
|
+
orderChanged: function(event) {
|
72
|
+
return alert('changed');
|
73
|
+
}
|
74
|
+
};
|
75
|
+
}
|
76
|
+
],
|
77
|
+
link: function($scope, element, attrs, controller) {
|
78
|
+
var appendNode, prefixName, topLevelArray;
|
79
|
+
prefixName = $(element).data('cmsNode');
|
80
|
+
if (element.hasClass('cms-array-node')) {
|
81
|
+
prefixName = findElementIndex(element.get(0));
|
82
|
+
$scope.$on('renumber', function(event, args) {
|
83
|
+
prefixName = findElementIndex(element.get(0));
|
84
|
+
return $scope.prefix = $scope.$parent.prefix + '[' + prefixName + ']';
|
85
|
+
});
|
86
|
+
}
|
87
|
+
$scope.$parent.$watch('prefix', function(prefix) {
|
88
|
+
return $scope.prefix = prefix + '[' + prefixName + ']';
|
89
|
+
});
|
90
|
+
if ($(element).hasClass('cms-array')) {
|
91
|
+
topLevelArray = $(element).parent().closest('.cms-array').size() === 0;
|
92
|
+
appendNode = function(source) {
|
93
|
+
var newEl;
|
94
|
+
newEl = angular.element(source);
|
95
|
+
element.append(newEl);
|
96
|
+
$scope.$compile(newEl)($scope);
|
97
|
+
$('a', newEl).click(function(e) {
|
98
|
+
return e.preventDefault();
|
99
|
+
});
|
100
|
+
$(newEl).click();
|
101
|
+
if (topLevelArray) {
|
102
|
+
return scrollTo(newEl);
|
103
|
+
}
|
104
|
+
};
|
105
|
+
$scope.$on('append', function(event, args) {
|
106
|
+
if (!event.defaultPrevented) {
|
107
|
+
$.get(args.href, function(data) {
|
108
|
+
return appendNode(data);
|
109
|
+
});
|
110
|
+
return event.preventDefault();
|
111
|
+
}
|
112
|
+
});
|
113
|
+
if (topLevelArray) {
|
114
|
+
$('ol.edit-buttons li a.button').unbind('click').bind('click', function() {
|
115
|
+
$scope.$broadcast('append', {
|
116
|
+
href: $(this).attr('href')
|
117
|
+
});
|
118
|
+
return false;
|
119
|
+
});
|
120
|
+
}
|
121
|
+
}
|
122
|
+
return $scope.edit = function() {
|
123
|
+
var $delete, $draft, $editor, $element, $move, $sidebarButtons, $sidebarFields, domNode, parentScope, template;
|
124
|
+
$element = $(element);
|
125
|
+
$editor = $('#edit-node-fields');
|
126
|
+
$sidebarFields = $('<ol>');
|
127
|
+
$sidebarButtons = $('#edit-node fieldset.actions ol');
|
128
|
+
$sidebarButtons.find('li.button-field').remove();
|
129
|
+
$element.find('> .cms-fields > span.li').each(function() {
|
130
|
+
var li;
|
131
|
+
li = $('<li>').addClass($(this).attr('class')).html($(this).html());
|
132
|
+
if (li.hasClass('button-field')) {
|
133
|
+
return $sidebarButtons.prepend(li);
|
134
|
+
} else {
|
135
|
+
return $sidebarFields.append(li);
|
136
|
+
}
|
137
|
+
});
|
138
|
+
|
139
|
+
$editor.empty().append($sidebarFields);
|
140
|
+
|
141
|
+
$editor.find(':file').each(function() {
|
142
|
+
var $input = $(this);
|
143
|
+
var $next = $($input.siblings('input'));
|
144
|
+
$input.attr('name', null).val('');
|
145
|
+
|
146
|
+
$input.on('change', function(event) {
|
147
|
+
var formData = new FormData(),
|
148
|
+
fileData = event.target.files[0];
|
149
|
+
formData.append('file', fileData);
|
150
|
+
|
151
|
+
$.ajax({
|
152
|
+
url: '/atomic_cms/media',
|
153
|
+
type: 'POST',
|
154
|
+
dataType: 'text',
|
155
|
+
data: formData,
|
156
|
+
contentType: false,
|
157
|
+
processData: false,
|
158
|
+
success: function (data) {
|
159
|
+
var parsed = JSON.parse(data);
|
160
|
+
$next.val(parsed.url);
|
161
|
+
$next.change();
|
162
|
+
}
|
163
|
+
});
|
164
|
+
});
|
165
|
+
});
|
166
|
+
|
167
|
+
$editor.find('.add-children-sublist-item').each(function() {
|
168
|
+
var $input = $(this);
|
169
|
+
$input.attr('name', null).val('');
|
170
|
+
$input.click(function(e) {
|
171
|
+
e.preventDefault();
|
172
|
+
var component = $(this).siblings('.children-sublist').val();
|
173
|
+
if (component !== ''){
|
174
|
+
$scope.$broadcast('append', {
|
175
|
+
href: component
|
176
|
+
});
|
177
|
+
}
|
178
|
+
});
|
179
|
+
});
|
180
|
+
|
181
|
+
$editor.find(':input').each(function() {
|
182
|
+
//guard clause for handling alternatly handled inputs
|
183
|
+
if($(this).prop('type') === 'file') { return; }
|
184
|
+
if($(this).hasClass('children-sublist')) { return; }
|
185
|
+
|
186
|
+
var $input = $(this);
|
187
|
+
var fieldName = $input.attr('name').replace($scope.prefix, '').replace(/\[|\]/g, '');
|
188
|
+
|
189
|
+
$input.attr('name', null).val($scope.preview[fieldName]);
|
190
|
+
|
191
|
+
$input.on('keyup change', function() {
|
192
|
+
$scope.$apply(function() {
|
193
|
+
$scope.preview[fieldName] = $input.val();
|
194
|
+
});
|
195
|
+
});
|
196
|
+
});
|
197
|
+
|
198
|
+
$sidebarButtons.find('li.button-field a').unbind('click').click(function() {
|
199
|
+
if ($(this).hasClass('emit')) {
|
200
|
+
$scope.$emit('append', {
|
201
|
+
href: $(this).attr('href')
|
202
|
+
});
|
203
|
+
} else {
|
204
|
+
$scope.$broadcast('append', {
|
205
|
+
href: $(this).attr('href')
|
206
|
+
});
|
207
|
+
}
|
208
|
+
return false;
|
209
|
+
});
|
210
|
+
$draft = $('#draft-panel');
|
211
|
+
$draft.find('[data-cms-node]').removeClass('active');
|
212
|
+
$draft.add(element).addClass('active');
|
213
|
+
template = $element.find('> input[name*=template]').val();
|
214
|
+
$('#edit-node legend span').html('Edit ' + (template.replace(/([A-Z]+)/g, ' $1')));
|
215
|
+
positionEditBox($element);
|
216
|
+
$editor.find(':input').first().focus();
|
217
|
+
$delete = $('#edit-node li.delete').hide();
|
218
|
+
$move = $('#edit-node li.move').hide();
|
219
|
+
parentScope = $scope.$parent;
|
220
|
+
if (element.hasClass('cms-array-node')) {
|
221
|
+
$move.show();
|
222
|
+
$delete.show();
|
223
|
+
$delete.find('a.button').unbind('click').click(function() {
|
224
|
+
$('#done-edit-node').click();
|
225
|
+
element.remove();
|
226
|
+
$scope.$destroy();
|
227
|
+
return parentScope.$broadcast('renumber');
|
228
|
+
});
|
229
|
+
domNode = element.get(0);
|
230
|
+
$move.find('a#move-node-up').unbind('click').click(function() {
|
231
|
+
if (domNode.previousSibling) {
|
232
|
+
domNode.parentNode.insertBefore(domNode, domNode.previousSibling);
|
233
|
+
positionEditBox(domNode);
|
234
|
+
scrollTo(domNode);
|
235
|
+
parentScope.$broadcast('renumber');
|
236
|
+
}
|
237
|
+
return false;
|
238
|
+
});
|
239
|
+
$move.find('a#move-node-down').unbind('click').click(function() {
|
240
|
+
if (domNode.nextSibling) {
|
241
|
+
domNode.parentNode.insertBefore(domNode.nextSibling, domNode);
|
242
|
+
positionEditBox(domNode);
|
243
|
+
scrollTo(domNode);
|
244
|
+
parentScope.$broadcast('renumber');
|
245
|
+
}
|
246
|
+
return false;
|
247
|
+
});
|
248
|
+
}
|
249
|
+
return false;
|
250
|
+
};
|
251
|
+
}
|
252
|
+
};
|
253
|
+
});
|
254
|
+
|
255
|
+
page.directive('cmsField', function() {
|
256
|
+
return {
|
257
|
+
restrict: 'C',
|
258
|
+
scope: false,
|
259
|
+
link: function($scope, element, attrs) {
|
260
|
+
var $element, fieldName;
|
261
|
+
$element = $(element);
|
262
|
+
fieldName = $element.attr('name');
|
263
|
+
$scope.preview[fieldName] = $element.val();
|
264
|
+
return $scope.$watch('prefix', function(prefix) {
|
265
|
+
return $element.attr('name', prefix + '[' + fieldName + ']');
|
266
|
+
});
|
267
|
+
}
|
268
|
+
};
|
269
|
+
});
|
270
|
+
|
271
|
+
$(document).ready(function() {
|
272
|
+
$('#done-edit-node').click(function() {
|
273
|
+
var $draft = $('#draft-panel');
|
274
|
+
|
275
|
+
$draft.removeClass('active');
|
276
|
+
$draft.find('[data-cms-node]').removeClass('active');
|
277
|
+
|
278
|
+
$('#edit-node').hide();
|
279
|
+
return false;
|
280
|
+
});
|
281
|
+
return $('.preview a').click(function(e) {
|
282
|
+
return e.preventDefault();
|
283
|
+
});
|
284
|
+
});
|
285
|
+
|
286
|
+
}).call(this);
|
@@ -0,0 +1,135 @@
|
|
1
|
+
@mixin component_cms_preview {
|
2
|
+
#component_preview {
|
3
|
+
@content;
|
4
|
+
}
|
5
|
+
}
|
6
|
+
|
7
|
+
#component_preview {
|
8
|
+
a.button.append-inline, a.button.append-block {
|
9
|
+
opacity: 0.5;
|
10
|
+
|
11
|
+
&:hover {
|
12
|
+
opacity: 1;
|
13
|
+
}
|
14
|
+
}
|
15
|
+
|
16
|
+
a.button.append-block {
|
17
|
+
@include outer-container;
|
18
|
+
display: block;
|
19
|
+
}
|
20
|
+
|
21
|
+
.cms-fields {
|
22
|
+
display: none;
|
23
|
+
}
|
24
|
+
}
|
25
|
+
|
26
|
+
#wrapper #active_admin_content #main_content_wrapper #main_content {
|
27
|
+
form#edit-page, form.edit-atomic-content {
|
28
|
+
div.buttons {
|
29
|
+
@include clearfix;
|
30
|
+
margin: 0 0 20px;
|
31
|
+
|
32
|
+
ol.edit-buttons {
|
33
|
+
@include clearfix;
|
34
|
+
float: left;
|
35
|
+
width: 75%;
|
36
|
+
|
37
|
+
li {
|
38
|
+
float: left;
|
39
|
+
font-size: 12px;
|
40
|
+
margin: 0 10px 10px 0;
|
41
|
+
|
42
|
+
a.button {
|
43
|
+
@include linear-gradient(to bottom, #ffffff, #f1f1f1, $fallback: #f8f8f8);
|
44
|
+
@include shadow(1px, 1px, 3px, rgba(138, 138, 138, 0.22));
|
45
|
+
border-color: #dcdcdc;
|
46
|
+
color: #666666;
|
47
|
+
font-weight: normal;
|
48
|
+
line-height: 20px;
|
49
|
+
padding-left: 35px;
|
50
|
+
position: relative;
|
51
|
+
text-shadow: none;
|
52
|
+
|
53
|
+
&::after {
|
54
|
+
@include retina-image("icon_add_component", 16px 15px, "png", null, "@2x", true);
|
55
|
+
background-position: left center;
|
56
|
+
background-repeat: no-repeat;
|
57
|
+
content: '';
|
58
|
+
height: 30px;
|
59
|
+
position: absolute;
|
60
|
+
left: 10px;
|
61
|
+
top: 0;
|
62
|
+
width: 16px;
|
63
|
+
}
|
64
|
+
}
|
65
|
+
}
|
66
|
+
}
|
67
|
+
|
68
|
+
fieldset.actions {
|
69
|
+
float: right;
|
70
|
+
margin: 0;
|
71
|
+
padding: 0;
|
72
|
+
}
|
73
|
+
}
|
74
|
+
}
|
75
|
+
|
76
|
+
#draft-panel.active {
|
77
|
+
[data-cms-node] {
|
78
|
+
h1, h2, h3, h4, h5, h6, p, li, img, a.button, iframe {
|
79
|
+
opacity: 0.35;
|
80
|
+
}
|
81
|
+
|
82
|
+
li li {
|
83
|
+
opacity: 1;
|
84
|
+
}
|
85
|
+
|
86
|
+
&.active {
|
87
|
+
h1, h2, h3, h4, h5, h6, p, li, img, a.button, iframe {
|
88
|
+
opacity: 1;
|
89
|
+
}
|
90
|
+
|
91
|
+
[data-cms-node] {
|
92
|
+
h1, h2, h3, h4, h5, h6, p, li, img, a.button, iframe {
|
93
|
+
opacity: 0.35;
|
94
|
+
}
|
95
|
+
}
|
96
|
+
}
|
97
|
+
}
|
98
|
+
}
|
99
|
+
}
|
100
|
+
|
101
|
+
#edit-node-column {
|
102
|
+
position: relative;
|
103
|
+
}
|
104
|
+
|
105
|
+
#edit-node {
|
106
|
+
display: none;
|
107
|
+
position: absolute;
|
108
|
+
left: 0;
|
109
|
+
top: 0;
|
110
|
+
width: 100%;
|
111
|
+
|
112
|
+
li {
|
113
|
+
margin: 0 10px 10px 0;
|
114
|
+
}
|
115
|
+
|
116
|
+
li.delete {
|
117
|
+
a.button {
|
118
|
+
background-color: #d44040;
|
119
|
+
border-color: #cc2525;
|
120
|
+
color: #ffffff;
|
121
|
+
}
|
122
|
+
}
|
123
|
+
}
|
124
|
+
|
125
|
+
#edit-node-fields {
|
126
|
+
input[type=file] {
|
127
|
+
width: calc(80% - 22px);
|
128
|
+
font-size: 0.95em;
|
129
|
+
font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif;
|
130
|
+
padding: 8px 10px 7px;
|
131
|
+
}
|
132
|
+
label.filler {
|
133
|
+
color: transparent;
|
134
|
+
}
|
135
|
+
}
|
@@ -0,0 +1,18 @@
|
|
1
|
+
module AtomicCms
|
2
|
+
class MediaController < ApplicationController
|
3
|
+
def create
|
4
|
+
asset = MediaScrubber.new(file: media_params)
|
5
|
+
if asset.save
|
6
|
+
render json: { url: asset.url }.to_json, status: :created
|
7
|
+
else
|
8
|
+
render json: {}.to_json, status: :unprocessable_entity
|
9
|
+
end
|
10
|
+
end
|
11
|
+
|
12
|
+
private
|
13
|
+
|
14
|
+
def media_params
|
15
|
+
params.require(:file)
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
@@ -0,0 +1,28 @@
|
|
1
|
+
class MediaScrubber
|
2
|
+
attr_accessor :original, :filtered
|
3
|
+
|
4
|
+
def initialize(args)
|
5
|
+
@original = args.fetch(:file, nil)
|
6
|
+
@filtered = infer_media_type
|
7
|
+
end
|
8
|
+
|
9
|
+
def infer_media_type
|
10
|
+
return nil unless original.respond_to?(:content_type)
|
11
|
+
AtomicCms::Image.new(file: original) if original.content_type.match(/image/)
|
12
|
+
end
|
13
|
+
|
14
|
+
def valid?
|
15
|
+
return false unless filtered
|
16
|
+
filtered.valid?
|
17
|
+
end
|
18
|
+
|
19
|
+
def save
|
20
|
+
return false unless valid?
|
21
|
+
filtered.save
|
22
|
+
end
|
23
|
+
|
24
|
+
def url
|
25
|
+
return nil unless filtered
|
26
|
+
filtered.file.url
|
27
|
+
end
|
28
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
module ComponentHelper
|
2
|
+
def add_option(option, output = nil)
|
3
|
+
return unless option
|
4
|
+
return output if output
|
5
|
+
option
|
6
|
+
end
|
7
|
+
|
8
|
+
def markdown(text)
|
9
|
+
return unless text
|
10
|
+
Redcarpet::Markdown.new(Redcarpet::Render::HTML).render(text).html_safe
|
11
|
+
end
|
12
|
+
|
13
|
+
def markdown_help_url
|
14
|
+
"http://nestacms.com/docs/creating-content/markdown-cheat-sheet"
|
15
|
+
end
|
16
|
+
|
17
|
+
def render_children(children)
|
18
|
+
return children unless children.present? && children.is_a?(Array)
|
19
|
+
children.map(&:render).reduce(:+)
|
20
|
+
end
|
21
|
+
end
|
@@ -0,0 +1,12 @@
|
|
1
|
+
module AtomicCms
|
2
|
+
class Media < ActiveRecord::Base
|
3
|
+
self.inheritance_column = "media_type"
|
4
|
+
|
5
|
+
has_attached_file :file
|
6
|
+
do_not_validate_attachment_file_type :file
|
7
|
+
|
8
|
+
def self.available_types
|
9
|
+
descendants.map { |desc| desc.name.demodulize }
|
10
|
+
end
|
11
|
+
end
|
12
|
+
end
|
@@ -0,0 +1 @@
|
|
1
|
+
input.cms-field type="hidden" name="template_name" value="#{value}"
|
data/atomic_cms.gemspec
ADDED
@@ -0,0 +1,30 @@
|
|
1
|
+
Gem::Specification.new do |s|
|
2
|
+
s.name = 'atomic_cms'
|
3
|
+
s.version = '0.2.2'
|
4
|
+
s.date = '2015-06-19'
|
5
|
+
s.summary = 'Atomic CMS'
|
6
|
+
s.description = 'Live CMS powered by atomic assets.'
|
7
|
+
s.authors = ['Don Humphreys']
|
8
|
+
s.email = 'dhumphreys88@gmail.com'
|
9
|
+
s.files = `git ls-files`.split(/\n/)
|
10
|
+
s.test_files = Dir['spec/**/*']
|
11
|
+
# s.homepage = 'http://rubygems.org/gems/atomic_cms'
|
12
|
+
# s.license = 'MIT'
|
13
|
+
|
14
|
+
s.add_dependency 'rails', '~> 4.2'
|
15
|
+
s.add_dependency 'activeadmin', '1.0.0.pre2'
|
16
|
+
s.add_dependency 'atomic_assets', '~> 0.1.0'
|
17
|
+
s.add_dependency 'jquery-rails', '~> 4.0', '>= 4.0.3'
|
18
|
+
s.add_dependency 'redcarpet', '~> 3.3'
|
19
|
+
s.add_dependency 'slim-rails', '~> 3.0'
|
20
|
+
s.add_dependency 'paperclip', '~> 4.3'
|
21
|
+
|
22
|
+
s.add_development_dependency 'rspec-core', '~> 3.3'
|
23
|
+
s.add_development_dependency 'rspec-expectations', '~> 3.3'
|
24
|
+
s.add_development_dependency 'rspec-mocks', '~> 3.3'
|
25
|
+
s.add_development_dependency 'rspec-support', '~> 3.3'
|
26
|
+
s.add_development_dependency 'rspec-rails'
|
27
|
+
s.add_development_dependency 'factory_girl_rails'
|
28
|
+
s.add_development_dependency 'shoulda-matchers'
|
29
|
+
s.add_development_dependency 'sqlite3'
|
30
|
+
end
|
data/bin/rails
ADDED
@@ -0,0 +1,12 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
# This command will automatically be run when you run "rails" with Rails 4 gems installed from the root of your application.
|
3
|
+
|
4
|
+
ENGINE_ROOT = File.expand_path('../..', __FILE__)
|
5
|
+
ENGINE_PATH = File.expand_path('../../lib/atomic_cms/engine', __FILE__)
|
6
|
+
|
7
|
+
# Set up gems listed in the Gemfile.
|
8
|
+
ENV['BUNDLE_GEMFILE'] ||= File.expand_path('../../Gemfile', __FILE__)
|
9
|
+
require 'bundler/setup' if File.exist?(ENV['BUNDLE_GEMFILE'])
|
10
|
+
|
11
|
+
require 'rails/all'
|
12
|
+
require 'rails/engine/commands'
|
data/config/routes.rb
ADDED