burp_cms 1.3.33 → 1.4.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 +4 -4
- data/README.markdown +1 -1
- data/app/assets/javascripts/burp/cms_helper.js +0 -52
- data/app/assets/packages/burp/editing.js +2 -0
- data/app/assets/packages/burp/editing/js/content-decorator.js +86 -114
- data/app/assets/packages/burp/editing/js/disableJavascript.js +49 -0
- data/app/assets/packages/burp/editing/js/jquery.html2markdown.js +6 -2
- data/app/assets/packages/burp/editing/js/main.js +215 -132
- data/app/assets/packages/burp/editing/js/markdown-fix.js +19 -3
- data/app/assets/packages/burp/editing/js/snippets.js +59 -0
- data/app/controllers/burp/files_controller.rb +3 -2
- data/app/lib/burp/util.rb +15 -4
- data/lib/burp/engine.rb +1 -1
- data/lib/burp/version.rb +1 -1
- data/lib/tasks/burp_tasks.rake +1 -1
- metadata +7 -5
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 564123161aa7b130c03532e1a5fb5035034aa38c
|
4
|
+
data.tar.gz: d79287f16ca452d61eb030245a8fc297516e949b
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: bb0d67f9ae6ca1c42de01bfd85782bf44035aaeddb6d783e534c7c3d0860ed421edd96b19f6ee5401f4acfa9ab0f1937fa702bcdc226877aebcdab53e6b5462e
|
7
|
+
data.tar.gz: d3b0fb6a094a7595ecd2a7f5954ad6cb8c4789ebedc490fab09aea7dd1c6a36424e0b7384c614cb13df872874aa36936937fb04018f003cf424b7d94cdf7fc43
|
data/README.markdown
CHANGED
@@ -59,7 +59,7 @@ To use snippets on pages not cought by the CatchAllController. The or part is to
|
|
59
59
|
|
60
60
|
before_filter :load_cms_page
|
61
61
|
def load_cms_page
|
62
|
-
@cms_page = Burp.find_page(request.path) || Burp::Page.new(:
|
62
|
+
@cms_page = Burp.find_page(request.path) || Burp::Page.new(:id => request.path)
|
63
63
|
end
|
64
64
|
|
65
65
|
## Title
|
@@ -1,52 +0,0 @@
|
|
1
|
-
(function(window,jQuery) {
|
2
|
-
|
3
|
-
var $ = jQuery;
|
4
|
-
|
5
|
-
window.snippets = function() {
|
6
|
-
|
7
|
-
var snippets = {names:[],snippets:{}};
|
8
|
-
|
9
|
-
var snippetComments = $("*:not(iframe)").contents().filter(function() {
|
10
|
-
try {
|
11
|
-
return this.nodeType === 8 && this.data.match(/snippet data-type=\"start\"/);
|
12
|
-
} catch (e) {
|
13
|
-
// Yay for not being allow to look at dom elements with external content, aka iframes
|
14
|
-
return false;
|
15
|
-
}
|
16
|
-
});
|
17
|
-
|
18
|
-
snippetComments.map(function() {
|
19
|
-
|
20
|
-
var name = this.data.match(/data-name=\"(.*?)\"/)[1];
|
21
|
-
var pageId = this.data.match(/data-page-id=\"(.*?)\"/)[1];
|
22
|
-
|
23
|
-
snippets.names.push(name);
|
24
|
-
|
25
|
-
snippets.snippets[name] = {
|
26
|
-
pageId:pageId,
|
27
|
-
comment:this,
|
28
|
-
elements:function() {
|
29
|
-
|
30
|
-
var snippetElements = [];
|
31
|
-
var element = this.comment;
|
32
|
-
while(element.nextSibling) {
|
33
|
-
element = element.nextSibling;
|
34
|
-
if(element.nodeType === 8 && element.data.match(/snippet data-type=\"end\"/)) {
|
35
|
-
break;
|
36
|
-
}
|
37
|
-
snippetElements.push(element);
|
38
|
-
}
|
39
|
-
|
40
|
-
return $(snippetElements);
|
41
|
-
},
|
42
|
-
update:function(newElements) {
|
43
|
-
this.elements().remove();
|
44
|
-
$(newElements).insertAfter(this.comment);
|
45
|
-
}
|
46
|
-
};
|
47
|
-
});
|
48
|
-
|
49
|
-
return snippets;
|
50
|
-
};
|
51
|
-
|
52
|
-
}(window,jQuery));
|
@@ -14,6 +14,8 @@
|
|
14
14
|
//= require ./editing/dep/CodeMirror-2.3/mode/htmlmixed/htmlmixed.js
|
15
15
|
//= require ./editing/dep/CodeMirror-2.3/mode/xml/xml.js
|
16
16
|
//= require ./editing/dep/CodeMirror-2.3/mode/markdown/markdown.js
|
17
|
+
//= require ./editing/js/disableJavascript.js
|
18
|
+
//= require ./editing/js/snippets.js
|
17
19
|
//= require ./editing/js/main.js
|
18
20
|
|
19
21
|
|
@@ -1,22 +1,23 @@
|
|
1
1
|
/*global
|
2
|
-
|
2
|
+
markdown2Html snippets
|
3
3
|
*/
|
4
4
|
(function($) {
|
5
5
|
|
6
6
|
var javascript_warning_has_been_shown = false;
|
7
7
|
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
8
|
+
function ContentDecorator(snippetName, options) {
|
9
|
+
this.snippetName = snippetName;
|
10
|
+
this.callbacks = {
|
11
|
+
remove: function(element) {
|
12
|
+
console.debug("remove", element);
|
13
|
+
},
|
14
|
+
insertBefore: function(beforeElement, element) {
|
15
|
+
console.debug('insertBefore', beforeElement, element);
|
16
|
+
},
|
17
|
+
append: function(snippetName, element) {
|
18
|
+
console.debug('append', snippetName, element);
|
19
|
+
}
|
20
|
+
};
|
20
21
|
|
21
22
|
if (typeof(options) === 'object') {
|
22
23
|
this.onUpdate = options['update'];
|
@@ -59,7 +60,8 @@
|
|
59
60
|
var bodyOffset = $('body').offset();
|
60
61
|
var bodyPosition = $('body').css('position');
|
61
62
|
|
62
|
-
|
63
|
+
var snippetElements = snippets().snippets[contentEditor.snippetName].elements();
|
64
|
+
$(snippetElements).filter('h1, h2, h3, h4, h5, p, img, blockquote, ul, ol').each(function() {
|
63
65
|
|
64
66
|
var position = $(this).offset();
|
65
67
|
var size = {width:$(this).outerWidth(),height:$(this).outerHeight()};
|
@@ -144,7 +146,7 @@
|
|
144
146
|
var img = createCallback(ui.draggable[0], className);
|
145
147
|
|
146
148
|
initializeMovable(contentEditor, img, function(element, positionClass) {
|
147
|
-
$(element).removeClass('left center right');
|
149
|
+
$(element).removeClass('left center right ui-droppable movable ui-draggable');
|
148
150
|
$(element).addClass(positionClass);
|
149
151
|
return element;
|
150
152
|
});
|
@@ -157,10 +159,13 @@
|
|
157
159
|
}
|
158
160
|
|
159
161
|
if($(this).parent().is(".bottom-dropbox")) {
|
160
|
-
|
162
|
+
snippets().snippets[contentEditor.snippetName].append(img);
|
163
|
+
contentEditor.callbacks.append(contentEditor.snippetName, img);
|
161
164
|
} else if(img !== markdown) {
|
162
165
|
$(img).insertBefore(markdown);
|
166
|
+
contentEditor.callbacks.insertBefore($(markdown), img);
|
163
167
|
}
|
168
|
+
|
164
169
|
clearDropBoxes();
|
165
170
|
}
|
166
171
|
|
@@ -184,14 +189,6 @@
|
|
184
189
|
}
|
185
190
|
}
|
186
191
|
|
187
|
-
function removeDraggable( element ) {
|
188
|
-
element.find( ".movable" ).draggable( "destroy" );
|
189
|
-
}
|
190
|
-
|
191
|
-
function removeRemoveZone() {
|
192
|
-
$('.remove-zone').removeClass('remove-zone').droppable( "destroy" );
|
193
|
-
}
|
194
|
-
|
195
192
|
$.extend(ContentDecorator.prototype, {
|
196
193
|
|
197
194
|
init: function() {
|
@@ -199,112 +196,86 @@
|
|
199
196
|
$(this.element).find("> .movable").each(function() {
|
200
197
|
$(this).removeClass('movable');
|
201
198
|
initializeMovable(contentEditor, this, function(element, positionClass) {
|
202
|
-
$(element).removeClass('left center right');
|
199
|
+
$(element).removeClass('left center right ui-droppable movable ui-draggable');
|
203
200
|
$(element).addClass(positionClass);
|
204
201
|
return element;
|
205
202
|
});
|
206
203
|
});
|
207
204
|
},
|
208
205
|
|
209
|
-
|
210
|
-
|
211
|
-
removeDraggable(this.element);
|
212
|
-
removeRemoveZone();
|
206
|
+
setSnippetName: function(snippetName) {
|
207
|
+
this.snippetName = snippetName;
|
213
208
|
},
|
214
209
|
|
215
|
-
|
216
|
-
|
217
|
-
var html = this.element.clone();
|
218
|
-
html.find('script[type="text/dont-run-javascript"]').each(function() {
|
219
|
-
$(this).attr("type",'text/javascript');
|
220
|
-
});
|
221
|
-
|
222
|
-
return html.find('.movable').removeClass('ui-draggable ui-droppable').end().html();
|
223
|
-
},
|
224
|
-
|
225
|
-
getMarkdown: function() {
|
226
|
-
return this.markdown;
|
210
|
+
setCallbacks: function(callbacks) {
|
211
|
+
this.callbacks = callbacks;
|
227
212
|
},
|
228
213
|
|
229
|
-
|
230
|
-
|
231
|
-
|
232
|
-
|
233
|
-
|
234
|
-
|
235
|
-
|
236
|
-
|
237
|
-
|
238
|
-
|
239
|
-
|
240
|
-
|
241
|
-
|
242
|
-
|
243
|
-
|
244
|
-
|
245
|
-
|
246
|
-
|
247
|
-
|
248
|
-
|
249
|
-
|
250
|
-
|
251
|
-
|
252
|
-
|
253
|
-
|
254
|
-
|
255
|
-
|
256
|
-
|
257
|
-
|
258
|
-
|
259
|
-
|
260
|
-
|
261
|
-
|
262
|
-
|
263
|
-
|
264
|
-
|
265
|
-
|
266
|
-
|
267
|
-
|
268
|
-
|
269
|
-
|
270
|
-
|
271
|
-
|
272
|
-
|
273
|
-
|
274
|
-
|
275
|
-
|
276
|
-
|
277
|
-
|
278
|
-
|
279
|
-
|
280
|
-
|
281
|
-
|
282
|
-
|
283
|
-
|
284
|
-
|
285
|
-
|
286
|
-
|
287
|
-
this.element.html("");
|
288
|
-
this.element.append(tempElement.children());
|
289
|
-
|
290
|
-
setTimeout(function() {
|
291
|
-
initializeMovable(_this, _this.element.find('> img'), function(element, positionClass) {
|
292
|
-
$(element).removeClass('left center right');
|
293
|
-
$(element).addClass(positionClass);
|
294
|
-
return element;
|
295
|
-
});
|
296
|
-
},10);
|
297
|
-
},
|
214
|
+
// updateContent: function() {
|
215
|
+
// var html = window.markdown2Html(this.markdown);
|
216
|
+
//
|
217
|
+
// if(this.lastHtml === html) {
|
218
|
+
// return;
|
219
|
+
// }
|
220
|
+
// this.lastHtml = html;
|
221
|
+
//
|
222
|
+
// var children = $(html);
|
223
|
+
//
|
224
|
+
// // Fix script escaping of text in script elements
|
225
|
+
// children.each(function() {
|
226
|
+
// if($(this).is("script")) {
|
227
|
+
// $(this).text(unescapeJavascript($(this).text()));
|
228
|
+
// $(this).attr('type','text/dont-run-javascript');
|
229
|
+
// } else {
|
230
|
+
// $(this).find('script').each(function() {
|
231
|
+
// $(this).text(unescapeJavascript($(this).text()));
|
232
|
+
// $(this).attr('type','text/dont-run-javascript');
|
233
|
+
// });
|
234
|
+
// }
|
235
|
+
// });
|
236
|
+
//
|
237
|
+
// var tempElement = $('<div></div>');
|
238
|
+
// tempElement.append(children);
|
239
|
+
//
|
240
|
+
// if(tempElement.find("script").length > 0 && !javascript_warning_has_been_shown) {
|
241
|
+
// $.gritter.add({
|
242
|
+
// title: 'WARNING!',
|
243
|
+
// text: ' Javascript found! The javascript will not be previewed but it will be saved.<br><br>Save and reload to test the javascript.',
|
244
|
+
// time: 20000
|
245
|
+
// });
|
246
|
+
//
|
247
|
+
// javascript_warning_has_been_shown = true;
|
248
|
+
// }
|
249
|
+
//
|
250
|
+
// // Fixes so that we don't reload images on each update
|
251
|
+
// var _this = this;
|
252
|
+
// tempElement.find('img').each(function() {
|
253
|
+
// var element = _this.element.find('img[src="'+$(this).attr('src')+'"]');
|
254
|
+
// if(element.length === 1) {
|
255
|
+
// if(element[0].outerHTML === this.outerHTML) {
|
256
|
+
// $(this).replaceWith(element);
|
257
|
+
// }
|
258
|
+
// }
|
259
|
+
// });
|
260
|
+
//
|
261
|
+
// this.element.html("");
|
262
|
+
// this.element.append(tempElement.children());
|
263
|
+
//
|
264
|
+
// setTimeout(function() {
|
265
|
+
// initializeMovable(_this, _this.element.find('> img'), function(element, positionClass) {
|
266
|
+
// $(element).removeClass('left center right');
|
267
|
+
// $(element).addClass(positionClass);
|
268
|
+
// return element;
|
269
|
+
// });
|
270
|
+
// },10);
|
271
|
+
// },
|
298
272
|
|
299
273
|
makeDroppable: function(elements, createCallback) {
|
300
274
|
initializeMovable(this, elements, createCallback);
|
301
275
|
},
|
302
276
|
|
303
|
-
removeDroppable: function(elements) {
|
304
|
-
$(elements).draggable( 'destroy' );
|
305
|
-
},
|
306
|
-
|
307
277
|
addRemoveZone: function(element) {
|
278
|
+
var contentEditor = this;
|
308
279
|
$(element).addClass('remove-zone');
|
309
280
|
$(element).droppable({
|
310
281
|
hoverClass: 'remove-hover',
|
@@ -313,6 +284,7 @@
|
|
313
284
|
if(ui.draggable.parents("#gallery").length === 0) {
|
314
285
|
setTimeout(function() {
|
315
286
|
// jquery-ui breaks if we remove the element during the callback
|
287
|
+
contentEditor.callbacks.remove(ui.draggable);
|
316
288
|
ui.draggable.remove();
|
317
289
|
},0);
|
318
290
|
ui.draggable.data("removed",true);
|
@@ -0,0 +1,49 @@
|
|
1
|
+
/*global
|
2
|
+
|
3
|
+
*/
|
4
|
+
|
5
|
+
(function(window) {
|
6
|
+
|
7
|
+
if(typeof(window.burp) == "undefined") {
|
8
|
+
window.burp = {};
|
9
|
+
}
|
10
|
+
|
11
|
+
function unescapeJavascript(script) {
|
12
|
+
return script.replace(/"/g,'"').replace(/'/g,"'").replace(/</g,"<").replace(/>/g,"<");
|
13
|
+
}
|
14
|
+
|
15
|
+
var javascript_warning_has_been_shown = false;
|
16
|
+
|
17
|
+
function warnAboutJavascript() {
|
18
|
+
if(!javascript_warning_has_been_shown) {
|
19
|
+
$.gritter.add({
|
20
|
+
title: 'WARNING!',
|
21
|
+
text: ' Javascript found! The javascript will not be previewed but it will be saved.<br><br>Save and reload to test the javascript.',
|
22
|
+
time: 20000
|
23
|
+
});
|
24
|
+
|
25
|
+
javascript_warning_has_been_shown = true;
|
26
|
+
}
|
27
|
+
}
|
28
|
+
|
29
|
+
function disableScriptElements(elements) {
|
30
|
+
$(elements).each(function() {
|
31
|
+
if($(this).is("script")) {
|
32
|
+
$(this).text(unescapeJavascript($(this).text()));
|
33
|
+
$(this).attr('type','text/dont-run-javascript');
|
34
|
+
warnAboutJavascript();
|
35
|
+
} else {
|
36
|
+
$(this).find('script').each(function() {
|
37
|
+
$(this).text(unescapeJavascript($(this).text()));
|
38
|
+
$(this).attr('type','text/dont-run-javascript');
|
39
|
+
warnAboutJavascript();
|
40
|
+
});
|
41
|
+
}
|
42
|
+
});
|
43
|
+
|
44
|
+
return elements;
|
45
|
+
}
|
46
|
+
|
47
|
+
window.burp.disableScriptElements = disableScriptElements;
|
48
|
+
|
49
|
+
}(window));
|
@@ -101,7 +101,7 @@ function Html2Markdown(value) {
|
|
101
101
|
|
102
102
|
dom.find('> blockquote').each(function() {
|
103
103
|
if(!shouldSkip(this)) {
|
104
|
-
$(this).replaceWith("> "+$.trim($(this).html()).replace(/\n{2,20}/g,"\n\n").replace(/\n/g,'\n> ').replace(/> \n/g,">\n"));
|
104
|
+
$(this).replaceWith("> "+$.trim($(this).html()).replace(/\n{2,20}/g,"\n\n").replace(/\n/g,'\n> ').replace(/> \n/g,">\n") + "\n\n");
|
105
105
|
}
|
106
106
|
});
|
107
107
|
|
@@ -134,5 +134,9 @@ function Html2Markdown(value) {
|
|
134
134
|
});
|
135
135
|
});
|
136
136
|
|
137
|
-
|
137
|
+
dom.find("> img").each(function() {
|
138
|
+
$(this).replaceWith($("<div></div>").append($(this).clone()).html() + "\n");
|
139
|
+
});
|
140
|
+
|
141
|
+
return $.trim(dom.html().replace(/^>/mg,'>').replace(/^</mg,'<').replace(/\n{2,20}/g,"\n\n"));
|
138
142
|
}
|
@@ -1,5 +1,5 @@
|
|
1
1
|
/*global
|
2
|
-
snippets CodeMirror ContentDecorator qq Html2Markdown
|
2
|
+
snippets CodeMirror ContentDecorator qq Html2Markdown markdown2Html burp
|
3
3
|
*/
|
4
4
|
|
5
5
|
$(function() {
|
@@ -12,76 +12,66 @@ $(function() {
|
|
12
12
|
var contentDecorator;
|
13
13
|
var editor;
|
14
14
|
|
15
|
-
function
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
$(snippet.elements()).each(function() {
|
21
|
-
if($(this).is("script")) {
|
22
|
-
$(this).attr("type",'text/dont-run-javascript');
|
23
|
-
} else {
|
24
|
-
$(this).find("script").each(function() {
|
25
|
-
$(this).attr("type",'text/dont-run-javascript');
|
26
|
-
});
|
27
|
-
}
|
28
|
-
});
|
29
|
-
|
30
|
-
snippet.update($('<div data-snippet-name="'+name+'" class="snippet-wrapper snippet-'+name+'"></div>').append($(snippet.elements())));
|
31
|
-
});
|
15
|
+
function getPathFor(snippetName) {
|
16
|
+
var path = window.burp_path || snippets().snippets[snippetName].pageId || window.location.pathname;
|
17
|
+
if(path === "/") {
|
18
|
+
path = "/$root";
|
19
|
+
}
|
32
20
|
|
33
|
-
|
34
|
-
$('.burp-remove, .remove-on-save').remove();
|
35
|
-
$('.burp-unwrap').each(function() {$(this).replaceWith(this.children);});
|
21
|
+
return path;
|
36
22
|
}
|
37
23
|
|
38
|
-
|
39
|
-
container.find("p").each(function() {
|
40
|
-
if($(this).children().length === $(this).find('img').length) {
|
41
|
-
$(this).children().unwrap();
|
42
|
-
}
|
43
|
-
});
|
44
|
-
}
|
24
|
+
var snippetCache = {};
|
45
25
|
|
46
|
-
function
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
26
|
+
function getHTMLForSnippet(_snippetName, callback) {
|
27
|
+
var path = getPathFor(snippetName);
|
28
|
+
|
29
|
+
var cacheKey = path + _snippetName;
|
30
|
+
if(snippetCache[cacheKey]) {
|
31
|
+
setTimeout(function() {
|
32
|
+
callback(snippetCache[cacheKey]);
|
33
|
+
}, 0);
|
34
|
+
} else {
|
35
|
+
$.ajax("/burp/pages/"+path,{
|
36
|
+
cache:false,
|
37
|
+
dataType:'json',
|
38
|
+
success:function(data) {
|
39
|
+
data = data || {snippets:{}};
|
40
|
+
snippetCache[cacheKey] = data.snippets[snippetName];
|
41
|
+
callback(snippetCache[cacheKey]);
|
42
|
+
}
|
43
|
+
});
|
51
44
|
}
|
52
45
|
}
|
53
46
|
|
54
|
-
|
55
|
-
|
56
|
-
var element = snippets().snippets[snippetName].elements().clone();
|
57
|
-
element.find('.markdown').each(function() {
|
58
|
-
$(this).removeClass('markdown');
|
59
|
-
if($(this).attr('class') === "") {
|
60
|
-
$(this).removeAttr('class');
|
61
|
-
}
|
62
|
-
});
|
63
|
-
|
64
|
-
element.find('script[type="text/dont-run-javascript"]').each(function() {
|
65
|
-
$(this).attr("type",'text/javascript');
|
66
|
-
});
|
67
|
-
|
68
|
-
element.find('img.movable').each(function() {
|
69
|
-
$(this).removeClass('movable ui-draggable ui-droppable');
|
70
|
-
});
|
71
|
-
|
72
|
-
editor.setValue(Html2Markdown(element.children()));
|
73
|
-
}
|
47
|
+
var snippetEditorState = {};
|
74
48
|
|
75
|
-
function loadSnippet() {
|
76
|
-
var path =
|
77
|
-
|
78
|
-
|
49
|
+
function loadSnippet(snippetName, callback) {
|
50
|
+
var path = getPathFor(snippetName);
|
51
|
+
|
52
|
+
if(typeof(callback) === "undefined") {
|
53
|
+
callback = function() {};
|
79
54
|
}
|
80
55
|
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
56
|
+
if(snippetEditorState[snippetName]) {
|
57
|
+
callback(snippetEditorState[snippetName]);
|
58
|
+
} else {
|
59
|
+
getHTMLForSnippet(snippetName, function(html) {
|
60
|
+
|
61
|
+
var element = $("<div>" + html + "</div>");
|
62
|
+
|
63
|
+
element.find('script[type="text/dont-run-javascript"]').each(function() {
|
64
|
+
$(this).attr("type",'text/javascript');
|
65
|
+
});
|
66
|
+
|
67
|
+
element.find('img.movable').each(function() {
|
68
|
+
$(this).removeClass('movable ui-draggable ui-droppable');
|
69
|
+
});
|
70
|
+
|
71
|
+
snippetEditorState[snippetName] = Html2Markdown(element.children());
|
72
|
+
callback(snippetEditorState[snippetName]);
|
73
|
+
});
|
74
|
+
}
|
85
75
|
}
|
86
76
|
|
87
77
|
function loadFiles() {
|
@@ -119,18 +109,56 @@ $(function() {
|
|
119
109
|
}
|
120
110
|
|
121
111
|
function selectSnippet(_snippetName) {
|
112
|
+
|
113
|
+
snippetName = _snippetName;
|
114
|
+
loadSnippet(snippetName, function(snippet) {
|
115
|
+
editor.setValue(snippet);
|
116
|
+
editor.refresh();
|
117
|
+
});
|
122
118
|
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
|
119
|
+
contentDecorator.setSnippetName(snippetName);
|
120
|
+
}
|
121
|
+
|
122
|
+
function removeIDs(elements) {
|
127
123
|
|
128
|
-
|
129
|
-
|
130
|
-
|
131
|
-
|
132
|
-
$('
|
124
|
+
$(elements).each(function() {
|
125
|
+
$(this).removeAttr("eid");
|
126
|
+
});
|
127
|
+
|
128
|
+
$(elements).find('*').each(function() {
|
129
|
+
$(this).removeAttr("eid");
|
130
|
+
});
|
133
131
|
|
132
|
+
return elements;
|
133
|
+
}
|
134
|
+
|
135
|
+
function addIDs(snippetName, elements) {
|
136
|
+
|
137
|
+
var count = 0;
|
138
|
+
|
139
|
+
$(elements).each(function() {
|
140
|
+
$(this).attr("eid", snippetName + "-" + String(count++));
|
141
|
+
});
|
142
|
+
|
143
|
+
$(elements).find('*').each(function() {
|
144
|
+
$(this).attr("eid", snippetName + "-" +String(count++));
|
145
|
+
});
|
146
|
+
|
147
|
+
return elements;
|
148
|
+
}
|
149
|
+
|
150
|
+
var domSnippetState = {};
|
151
|
+
|
152
|
+
function updateSnippetWithMarkdown(snippetName, markdown) {
|
153
|
+
var html = markdown2Html(markdown);
|
154
|
+
var elements = burp.disableScriptElements($(html));
|
155
|
+
elements = addIDs(snippetName, elements);
|
156
|
+
domSnippetState[snippetName] = elements.clone();
|
157
|
+
snippets().snippets[snippetName].update(elements);
|
158
|
+
|
159
|
+
contentDecorator.makeDroppable(elements, function(element, positionClass) {
|
160
|
+
return $("<img src='" + $(element).attr('src') + "' class='" + positionClass + "' />");
|
161
|
+
});
|
134
162
|
}
|
135
163
|
|
136
164
|
function addEditor() {
|
@@ -144,8 +172,9 @@ $(function() {
|
|
144
172
|
matchBrackets: true,
|
145
173
|
lineWrapping: true,
|
146
174
|
theme: "default",
|
147
|
-
onChange:function(editor,changes) {
|
148
|
-
|
175
|
+
onChange:function(editor, changes) {
|
176
|
+
snippetEditorState[snippetName] = editor.getValue();
|
177
|
+
updateSnippetWithMarkdown(snippetName, snippetEditorState[snippetName]);
|
149
178
|
}
|
150
179
|
});
|
151
180
|
|
@@ -169,22 +198,16 @@ $(function() {
|
|
169
198
|
editor.replaceRange(content,editor.getCursor(true),editor.getCursor(false));
|
170
199
|
});
|
171
200
|
|
172
|
-
contentDecorator.addRemoveZone('#gallery');
|
173
|
-
|
174
|
-
// update(editor.getValue());
|
175
201
|
loadFiles();
|
176
202
|
|
177
203
|
$.adminDock.title('');
|
178
204
|
$.adminDock.footer.addButton({ icon: 'picture', text: "Pictures", showModule: $('#gallery') });
|
179
205
|
$.adminDock.footer.addButton({ icon: 'edit', text: "Edit text", showModule: $('#myContentEditor'), show: function() {
|
180
|
-
loadHTML();
|
181
206
|
editor.refresh();
|
182
207
|
} });
|
183
208
|
|
184
209
|
|
185
210
|
$(document).on('image-drop-done.burp', function() {
|
186
|
-
loadHTML();
|
187
|
-
editor.refresh();
|
188
211
|
});
|
189
212
|
|
190
213
|
var snippet_names = [];
|
@@ -202,13 +225,10 @@ $(function() {
|
|
202
225
|
'default': snippet_names[0],
|
203
226
|
change: function(option) {
|
204
227
|
|
205
|
-
|
206
228
|
selectSnippet(option);
|
207
|
-
loadSnippet()
|
208
|
-
|
209
|
-
|
210
|
-
contentDecorator.makeDroppable('#gallery img', function(element, positionClass) {
|
211
|
-
return $("<img src='" + $(element).attr('src') + "' class='" + positionClass + "' />");
|
229
|
+
loadSnippet(snippetName, function(snippet) {
|
230
|
+
editor.setValue(snippet);
|
231
|
+
editor.refresh();
|
212
232
|
});
|
213
233
|
|
214
234
|
console.debug("Switching to " + option);
|
@@ -242,38 +262,44 @@ $(function() {
|
|
242
262
|
}});
|
243
263
|
|
244
264
|
$.adminDock.footer.addButton({ icon: 'undo', text: 'Discard', secondary: true, click:function() {
|
245
|
-
|
246
|
-
|
247
|
-
|
248
|
-
|
265
|
+
|
266
|
+
var oldSnippetEditorState = snippetEditorState;
|
267
|
+
snippetEditorState = {};
|
268
|
+
|
269
|
+
$.each(oldSnippetEditorState, function(snippetName, editorState) {
|
270
|
+
loadSnippet(snippetName, function(snippet) {
|
271
|
+
updateSnippetWithMarkdown(snippetName, snippet);
|
272
|
+
});
|
273
|
+
});
|
274
|
+
|
275
|
+
loadSnippet(snippetName, function(snippet) {
|
276
|
+
editor.setValue(snippet);
|
277
|
+
editor.refresh();
|
278
|
+
});
|
249
279
|
}});
|
250
280
|
|
251
281
|
$.adminDock.footer.addButton({ icon: 'save', text: 'Save', secondary: true, click:function() {
|
252
282
|
|
253
|
-
var path =
|
254
|
-
|
255
|
-
path = "/$root";
|
256
|
-
}
|
283
|
+
var path = getPathFor(snippetName);
|
284
|
+
snippetCache = {};
|
257
285
|
|
258
286
|
$.ajax("/burp/pages/"+path,{
|
259
|
-
cache:false,
|
260
|
-
dataType:'json',
|
261
|
-
success:function(data) {
|
287
|
+
cache: false,
|
288
|
+
dataType: 'json',
|
289
|
+
success: function(data) {
|
262
290
|
|
263
291
|
data = data || {snippets:{}};
|
264
292
|
|
265
|
-
|
266
|
-
|
293
|
+
$.each(snippetEditorState, function(snippetName, snippetState) {
|
294
|
+
data.snippets[snippetName] = markdown2Html(snippetEditorState[snippetName]);
|
295
|
+
});
|
296
|
+
|
267
297
|
$.ajax("/burp/pages/"+path,{
|
268
298
|
type:"post",
|
269
299
|
data:{page:data,'_method':"put"},
|
270
300
|
dataType:'json',
|
271
301
|
success:function() {
|
272
|
-
|
273
|
-
originalValue = contentDecorator.getMarkdown();
|
274
|
-
originalHtml = contentDecorator.getHtml();
|
275
|
-
|
276
|
-
alert("The page was saved!");
|
302
|
+
alert("The page has been saved!");
|
277
303
|
}
|
278
304
|
});
|
279
305
|
}
|
@@ -287,24 +313,6 @@ $(function() {
|
|
287
313
|
|
288
314
|
var initDone = false;
|
289
315
|
|
290
|
-
function init() {
|
291
|
-
if(!initDone) {
|
292
|
-
initDone = true;
|
293
|
-
|
294
|
-
wrapContent();
|
295
|
-
selectSnippet(snippets().names.sort(function(a, b) { return a.toLowerCase() > b.toLowerCase(); })[0]);
|
296
|
-
addEditor();
|
297
|
-
|
298
|
-
loadSnippet();
|
299
|
-
|
300
|
-
$('#gallery').trigger('refresh');
|
301
|
-
setTimeout(function() { $('#gallery').trigger('refresh'); },300);
|
302
|
-
setTimeout(function() { $('#gallery').trigger('refresh'); },600);
|
303
|
-
setTimeout(function() { $('#gallery').trigger('refresh'); },1200);
|
304
|
-
setTimeout(function() { $('#gallery').trigger('refresh'); },5000);
|
305
|
-
}
|
306
|
-
}
|
307
|
-
|
308
316
|
function trigger_http_basic_auth(callback) {
|
309
317
|
if(initDone) {
|
310
318
|
callback();
|
@@ -313,21 +321,96 @@ $(function() {
|
|
313
321
|
}
|
314
322
|
}
|
315
323
|
|
316
|
-
|
317
|
-
|
318
|
-
|
319
|
-
|
320
|
-
|
321
|
-
|
322
|
-
|
324
|
+
function init(callback) {
|
325
|
+
trigger_http_basic_auth(function() {
|
326
|
+
if(!initDone) {
|
327
|
+
initDone = true;
|
328
|
+
|
329
|
+
contentDecorator = new ContentDecorator("");
|
330
|
+
contentDecorator.setCallbacks({
|
331
|
+
remove: function(element) {
|
332
|
+
var eid = element.attr('eid');
|
333
|
+
var snippetName = eid.split(/-/)[0];
|
334
|
+
|
335
|
+
var cssSelector = '[eid="'+ eid +'"]';
|
336
|
+
|
337
|
+
var root = $('<div></div>');
|
338
|
+
root.append(domSnippetState[snippetName]);
|
339
|
+
root.find(cssSelector).remove();
|
340
|
+
domSnippetState[snippetName] = root.children();
|
341
|
+
|
342
|
+
snippetEditorState[snippetName] = Html2Markdown(removeIDs(domSnippetState[snippetName]));
|
343
|
+
loadSnippet(snippetName, function(snippet) {
|
344
|
+
editor.setValue(snippet);
|
345
|
+
editor.refresh();
|
346
|
+
});
|
347
|
+
},
|
348
|
+
insertBefore: function(beforeElement, element) {
|
349
|
+
$(element).removeClass('ui-droppable movable ui-draggable');
|
350
|
+
|
351
|
+
var eid = beforeElement.attr('eid');
|
352
|
+
var snippetName = eid.split(/-/)[0];
|
353
|
+
|
354
|
+
var cssSelector = '[eid="'+ eid +'"]';
|
355
|
+
|
356
|
+
var root = $('<div></div>');
|
357
|
+
root.append(domSnippetState[snippetName]);
|
358
|
+
element.insertBefore(root.find(cssSelector));
|
359
|
+
domSnippetState[snippetName] = root.children();
|
360
|
+
|
361
|
+
snippetEditorState[snippetName] = Html2Markdown(removeIDs(domSnippetState[snippetName]));
|
362
|
+
loadSnippet(snippetName, function(snippet) {
|
363
|
+
editor.setValue(snippet);
|
364
|
+
editor.refresh();
|
365
|
+
});
|
366
|
+
},
|
367
|
+
append: function(snippetName, element) {
|
368
|
+
$(element).removeClass('ui-droppable movable ui-draggable');
|
369
|
+
|
370
|
+
domSnippetState[snippetName] = $('<div></div>').append(domSnippetState[snippetName]).append(element).children();
|
371
|
+
|
372
|
+
snippetEditorState[snippetName] = Html2Markdown(removeIDs(domSnippetState[snippetName]));
|
373
|
+
loadSnippet(snippetName, function(snippet) {
|
374
|
+
editor.setValue(snippet);
|
375
|
+
editor.refresh();
|
376
|
+
});
|
377
|
+
}
|
378
|
+
});
|
379
|
+
|
380
|
+
selectSnippet(snippets().names.sort(function(a, b) { return a.toLowerCase() > b.toLowerCase(); })[0]);
|
381
|
+
addEditor();
|
323
382
|
|
324
|
-
|
325
|
-
|
326
|
-
|
327
|
-
|
328
|
-
|
383
|
+
contentDecorator.addRemoveZone('#gallery');
|
384
|
+
|
385
|
+
loadSnippet(snippetName, function(snippet) {
|
386
|
+
editor.setValue(snippet);
|
387
|
+
editor.refresh();
|
329
388
|
});
|
389
|
+
|
390
|
+
$('#gallery').trigger('refresh');
|
391
|
+
setTimeout(function() { $('#gallery').trigger('refresh'); },300);
|
392
|
+
setTimeout(function() { $('#gallery').trigger('refresh'); },600);
|
393
|
+
setTimeout(function() { $('#gallery').trigger('refresh'); },1200);
|
394
|
+
setTimeout(function() { $('#gallery').trigger('refresh'); },5000);
|
330
395
|
}
|
396
|
+
|
397
|
+
callback();
|
398
|
+
});
|
399
|
+
}
|
400
|
+
|
401
|
+
function isCtrlOrAltEscape(event) {
|
402
|
+
return (event.altKey === true || event.ctrlKey === true ) && event.keyCode === 27;
|
403
|
+
}
|
404
|
+
|
405
|
+
function isCtrlAltSpace(event) {
|
406
|
+
return event.altKey === true && event.ctrlKey === true && event.keyCode === 32;
|
407
|
+
}
|
408
|
+
|
409
|
+
$(window).keydown(function(event) {
|
410
|
+
if (isCtrlOrAltEscape(event) || isCtrlAltSpace(event)) {
|
411
|
+
init(function() {
|
412
|
+
$.adminDock.toggle();
|
413
|
+
});
|
331
414
|
}
|
332
415
|
});
|
333
416
|
|
@@ -4,6 +4,12 @@
|
|
4
4
|
|
5
5
|
(function() {
|
6
6
|
|
7
|
+
marked.setOptions({
|
8
|
+
gfm: true,
|
9
|
+
pedantic: false,
|
10
|
+
sanitize: false
|
11
|
+
});
|
12
|
+
|
7
13
|
function includeForMarkdown(element) {
|
8
14
|
// Include text
|
9
15
|
if(element.nodeType === 3) {
|
@@ -20,7 +26,7 @@
|
|
20
26
|
$(nodes).each(function(index, element) {
|
21
27
|
var last = newArray.length-1;
|
22
28
|
if(includeForMarkdown(element)) {
|
23
|
-
var data = $("<div></div>").append(element).html();
|
29
|
+
var data = (element.nodeType === 3) ? element.data : $("<div></div>").append(element).html();
|
24
30
|
|
25
31
|
if(typeof(newArray[last]) === 'string') {
|
26
32
|
newArray[last] = newArray[last] + data;
|
@@ -34,6 +40,16 @@
|
|
34
40
|
return newArray;
|
35
41
|
}
|
36
42
|
|
43
|
+
function unwrapImagesFromParagraphs(container) {
|
44
|
+
container.find("p").each(function() {
|
45
|
+
if($(this).children().length === $(this).find('img').length) {
|
46
|
+
$(this).children().unwrap();
|
47
|
+
}
|
48
|
+
});
|
49
|
+
|
50
|
+
return container;
|
51
|
+
}
|
52
|
+
|
37
53
|
function toHtml(markdown) {
|
38
54
|
|
39
55
|
var elements = [];
|
@@ -45,8 +61,8 @@
|
|
45
61
|
elements.push(value);
|
46
62
|
}
|
47
63
|
});
|
48
|
-
|
49
|
-
return $("<div></div>").append(elements).html();
|
64
|
+
|
65
|
+
return unwrapImagesFromParagraphs($("<div></div>").append(elements)).html();
|
50
66
|
}
|
51
67
|
|
52
68
|
window.markdown2Html = toHtml;
|
@@ -0,0 +1,59 @@
|
|
1
|
+
(function(window,jQuery) {
|
2
|
+
|
3
|
+
var $ = jQuery;
|
4
|
+
|
5
|
+
window.snippets = function() {
|
6
|
+
|
7
|
+
var snippets = {names:[],snippets:{}};
|
8
|
+
|
9
|
+
var snippetComments = $("*:not(iframe)").contents().filter(function() {
|
10
|
+
try {
|
11
|
+
return this.nodeType === 8 && this.data.match(/snippet data-type=\"start\"/);
|
12
|
+
} catch (e) {
|
13
|
+
// Yay for not being allow to look at dom elements with external content, aka iframes
|
14
|
+
return false;
|
15
|
+
}
|
16
|
+
});
|
17
|
+
|
18
|
+
snippetComments.map(function() {
|
19
|
+
|
20
|
+
var name = this.data.match(/data-name=\"(.*?)\"/)[1];
|
21
|
+
var pageId = this.data.match(/data-page-id=\"(.*?)\"/)[1];
|
22
|
+
|
23
|
+
snippets.names.push(name);
|
24
|
+
|
25
|
+
snippets.snippets[name] = {
|
26
|
+
pageId:pageId,
|
27
|
+
comment:this,
|
28
|
+
elements:function() {
|
29
|
+
|
30
|
+
var snippetElements = [];
|
31
|
+
var element = this.comment;
|
32
|
+
while(element.nextSibling) {
|
33
|
+
element = element.nextSibling;
|
34
|
+
if(element.nodeType === 8 && element.data.match(/snippet data-type=\"end\"/)) {
|
35
|
+
break;
|
36
|
+
}
|
37
|
+
snippetElements.push(element);
|
38
|
+
}
|
39
|
+
|
40
|
+
return $(snippetElements);
|
41
|
+
},
|
42
|
+
update:function(newElements) {
|
43
|
+
this.elements().remove();
|
44
|
+
$(newElements).insertAfter(this.comment);
|
45
|
+
},
|
46
|
+
prepend:function(newElements) {
|
47
|
+
$(newElements).insertAfter(this.comment);
|
48
|
+
},
|
49
|
+
append:function(newElements) {
|
50
|
+
$(newElements).insertAfter(this.elements().last());
|
51
|
+
}
|
52
|
+
|
53
|
+
};
|
54
|
+
});
|
55
|
+
|
56
|
+
return snippets;
|
57
|
+
};
|
58
|
+
|
59
|
+
}(window,jQuery));
|
@@ -25,12 +25,13 @@ module Burp
|
|
25
25
|
if File.expand_path(file_path) != file_path
|
26
26
|
render :text => "403, Forbiden!", :status => 403, :content_type => "text/plain"
|
27
27
|
else
|
28
|
-
File.unlink(file_path)
|
28
|
+
File.unlink(file_path)
|
29
|
+
Util.remove_all_versions_of_image(file_path)
|
29
30
|
end
|
30
31
|
|
31
32
|
Util.commit("Burp: removed a file")
|
32
33
|
|
33
|
-
redirect_to files_path
|
34
|
+
redirect_to files_path, notice: "#{File.basename(file_path)} has been removed."
|
34
35
|
end
|
35
36
|
|
36
37
|
def show
|
data/app/lib/burp/util.rb
CHANGED
@@ -5,21 +5,27 @@ require 'RMagick'
|
|
5
5
|
module Burp
|
6
6
|
module Util
|
7
7
|
|
8
|
+
SIZES = {:small => [200,300],:medium => [600,900], :large => [1000,1500]}
|
9
|
+
|
8
10
|
def self.commit(message = "auto commit", options = {})
|
9
11
|
options[:path] ||= Burp.content_directory
|
10
12
|
raise "missing git repo in burp cms directory" if `cd #{options[:path]}; git st 2>&1`.match(/Not a git repository/)
|
11
13
|
`cd #{options[:path]}; git add .; git commit -a -m "Burp: #{message}"`
|
12
14
|
end
|
13
15
|
|
16
|
+
def self.remove_all_versions_of_image(file_path)
|
17
|
+
SIZES.each_pair do |key,value|
|
18
|
+
target_path = "#{upload_directory_path}#{key.to_s}/#{File.basename(file_path)}"
|
19
|
+
File.unlink(target_path) if File.exist?(target_path)
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
14
23
|
def self.create_smaller_images(file_path)
|
15
24
|
|
16
|
-
upload_directory_path = "#{Burp.content_directory}uploads/"
|
17
|
-
|
18
|
-
sizes = {:small => [200,300],:medium => [600,900], :large => [1000,1500]}
|
19
25
|
image = Magick::ImageList.new(file_path).first
|
20
26
|
image.auto_orient!
|
21
27
|
|
22
|
-
|
28
|
+
SIZES.each_pair do |key,value|
|
23
29
|
|
24
30
|
FileUtils.mkdir_p("#{upload_directory_path}#{key.to_s}")
|
25
31
|
target_path = "#{upload_directory_path}#{key.to_s}/#{File.basename(file_path)}"
|
@@ -35,6 +41,11 @@ module Burp
|
|
35
41
|
image.destroy!
|
36
42
|
end
|
37
43
|
|
44
|
+
private
|
45
|
+
|
46
|
+
def self.upload_directory_path
|
47
|
+
"#{Burp.content_directory}uploads/"
|
48
|
+
end
|
38
49
|
|
39
50
|
|
40
51
|
end
|
data/lib/burp/engine.rb
CHANGED
@@ -12,7 +12,7 @@ module Burp
|
|
12
12
|
# Enabling assets precompiling under rails 3.1
|
13
13
|
if Rails.version >= '3.1'
|
14
14
|
initializer :assets do |config|
|
15
|
-
Rails.application.config.assets.precompile += %w( burp/editing.css burp/editing.js burp/
|
15
|
+
Rails.application.config.assets.precompile += %w( burp/editing.css burp/editing.js burp/snippets.js)
|
16
16
|
end
|
17
17
|
end
|
18
18
|
|
data/lib/burp/version.rb
CHANGED
data/lib/tasks/burp_tasks.rake
CHANGED
@@ -56,7 +56,7 @@ namespace :burp do
|
|
56
56
|
end
|
57
57
|
|
58
58
|
BurpRakeHelper.write('/app/assets/javascripts/burp.js') do |file|
|
59
|
-
file.write("// Includes burp related javascript.\n//\n//= require 'burp/editing'\n//= require 'burp/
|
59
|
+
file.write("// Includes burp related javascript.\n//\n//= require 'burp/editing'\n//= require 'burp/snippets'")
|
60
60
|
end
|
61
61
|
|
62
62
|
BurpRakeHelper.write("/app/assets/stylesheets/burp.css") do |file|
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: burp_cms
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.
|
4
|
+
version: 1.4.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Darwin
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2014-05-11 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: jquery-rails
|
@@ -200,6 +200,8 @@ extra_rdoc_files:
|
|
200
200
|
- LICENSE.txt
|
201
201
|
- README.markdown
|
202
202
|
files:
|
203
|
+
- LICENSE.txt
|
204
|
+
- README.markdown
|
203
205
|
- Rakefile
|
204
206
|
- app/assets/images/burp/add-group-to-menu-1.png
|
205
207
|
- app/assets/images/burp/add-group-to-menu-2.png
|
@@ -326,10 +328,12 @@ files:
|
|
326
328
|
- app/assets/packages/burp/editing/dep/FontAwesome/less/font-awesome.less
|
327
329
|
- app/assets/packages/burp/editing/js/admin-dock.js
|
328
330
|
- app/assets/packages/burp/editing/js/content-decorator.js
|
331
|
+
- app/assets/packages/burp/editing/js/disableJavascript.js
|
329
332
|
- app/assets/packages/burp/editing/js/jquery.html2markdown.js
|
330
333
|
- app/assets/packages/burp/editing/js/main.js
|
331
334
|
- app/assets/packages/burp/editing/js/markdown-fix.js
|
332
335
|
- app/assets/packages/burp/editing/js/marked.js
|
336
|
+
- app/assets/packages/burp/editing/js/snippets.js
|
333
337
|
- app/assets/packages/gritter/README.markdown
|
334
338
|
- app/assets/packages/gritter/css/jquery.gritter.less
|
335
339
|
- app/assets/packages/gritter/gritter.js
|
@@ -427,8 +431,6 @@ files:
|
|
427
431
|
- lib/burp/version.rb
|
428
432
|
- lib/burp_cms.rb
|
429
433
|
- lib/tasks/burp_tasks.rake
|
430
|
-
- LICENSE.txt
|
431
|
-
- README.markdown
|
432
434
|
homepage: http://github.com/bjornblomqvist/burp
|
433
435
|
licenses:
|
434
436
|
- LGPL3
|
@@ -449,7 +451,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
449
451
|
version: '0'
|
450
452
|
requirements: []
|
451
453
|
rubyforge_project:
|
452
|
-
rubygems_version: 2.
|
454
|
+
rubygems_version: 2.2.2
|
453
455
|
signing_key:
|
454
456
|
specification_version: 4
|
455
457
|
summary: A CMS that tries hard to not get in your way!
|