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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 856bc5368305ee60069da52c8e123618a8b0a041
4
- data.tar.gz: b5e3cb1676752eaf84f2f8d57dd03207b7450273
3
+ metadata.gz: 564123161aa7b130c03532e1a5fb5035034aa38c
4
+ data.tar.gz: d79287f16ca452d61eb030245a8fc297516e949b
5
5
  SHA512:
6
- metadata.gz: 2a9cc0ab5483fdd788e983ad2d78b1683b2003fdccf57fa19cfb65e6c71da5e73e4b18a4739f02052b811168f4b81339f6ace1c6209aced0c23d3ec93d1e2961
7
- data.tar.gz: f9cb1b2ae76aaefee5511675f276bb53e1c802731564597d19316f394b26acac7428568dbbd3f86adfa084f16803be591b0b6062022d21068db295cd2e3dcc9c
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(:snippets => [], :title => "", :id => request.path)
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
- marked markdown2Html
2
+ markdown2Html snippets
3
3
  */
4
4
  (function($) {
5
5
 
6
6
  var javascript_warning_has_been_shown = false;
7
7
 
8
- marked.setOptions({
9
- gfm: true,
10
- pedantic: false,
11
- sanitize: false
12
- });
13
-
14
- function unescapeJavascript(script) {
15
- return script.replace(/&quot;/g,'"').replace(/&#39;/g,"'").replace(/&lt;/g,"<").replace(/&gt;/g,"<");
16
- }
17
-
18
- function ContentDecorator(element, options) {
19
- this.element = $(element);
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
- contentEditor.element.find('> h1,> h2,> h3,> h4,> h5,> p,> img,> blockquote,> ul,> ol').each(function() {
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
- $(contentEditor.element).append(img);
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
- cleanup: function() {
211
- removeDraggable(this.element);
212
- removeRemoveZone();
206
+ setSnippetName: function(snippetName) {
207
+ this.snippetName = snippetName;
213
208
  },
214
209
 
215
- getHtml: function() {
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
- setMarkdown: function(markdown) {
230
- if (this.markdown !== markdown) {
231
- this.markdown = markdown;
232
- this.updateContent();
233
-
234
- if (this.onUpdate) {
235
- this.onUpdate();
236
- }
237
- }
238
- },
239
-
240
- updateContent: function() {
241
- var html = window.markdown2Html(this.markdown);
242
-
243
- if(this.lastHtml === html) {
244
- return;
245
- }
246
- this.lastHtml = html;
247
-
248
- var children = $(html);
249
-
250
- // Fix script escaping of text in script elements
251
- children.each(function() {
252
- if($(this).is("script")) {
253
- $(this).text(unescapeJavascript($(this).text()));
254
- $(this).attr('type','text/dont-run-javascript');
255
- } else {
256
- $(this).find('script').each(function() {
257
- $(this).text(unescapeJavascript($(this).text()));
258
- $(this).attr('type','text/dont-run-javascript');
259
- });
260
- }
261
- });
262
-
263
- var tempElement = $('<div></div>');
264
- tempElement.append(children);
265
-
266
- if(tempElement.find("script").length > 0 && !javascript_warning_has_been_shown) {
267
- $.gritter.add({
268
- title: 'WARNING!',
269
- text: ' Javascript found! The javascript will not be previewed but it will be saved.<br><br>Save and reload to test the javascript.',
270
- time: 20000
271
- });
272
-
273
- javascript_warning_has_been_shown = true;
274
- }
275
-
276
- // Fixes so that we don't reload images on each update
277
- var _this = this;
278
- tempElement.find('img').each(function() {
279
- var element = _this.element.find('img[src="'+$(this).attr('src')+'"]');
280
- if(element.length === 1) {
281
- if(element[0].outerHTML === this.outerHTML) {
282
- $(this).replaceWith(element);
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(/&quot;/g,'"').replace(/&#39;/g,"'").replace(/&lt;/g,"<").replace(/&gt;/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
- return dom.html().replace(/^&gt;/mg,'>').replace(/^&lt;/mg,'<').replace(/\n{2,20}/g,"\n\n");
137
+ dom.find("> img").each(function() {
138
+ $(this).replaceWith($("<div></div>").append($(this).clone()).html() + "\n");
139
+ });
140
+
141
+ return $.trim(dom.html().replace(/^&gt;/mg,'>').replace(/^&lt;/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 wrapContent() {
16
- $.each(snippets().snippets,function(name,snippet) {
17
- console.debug(name,snippet);
18
-
19
- // Fix so that we dont run javascript again
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
- // Remove unwanted stuff
34
- $('.burp-remove, .remove-on-save').remove();
35
- $('.burp-unwrap').each(function() {$(this).replaceWith(this.children);});
21
+ return path;
36
22
  }
37
23
 
38
- function cleanup(container) {
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 update(value) {
47
- if(value !== lastValue) {
48
- lastValue = value;
49
- contentDecorator.setMarkdown(value);
50
- cleanup($('.snippet-'+snippetName));
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
- function loadHTML() {
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 = window.burp_path || window.location.pathname;
77
- if(path === "/") {
78
- path = "/$root";
49
+ function loadSnippet(snippetName, callback) {
50
+ var path = getPathFor(snippetName);
51
+
52
+ if(typeof(callback) === "undefined") {
53
+ callback = function() {};
79
54
  }
80
55
 
81
- loadHTML();
82
- editor.clearHistory();
83
- update(editor.getValue());
84
- originalValue = editor.getValue();
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
- if(contentDecorator) {
124
- contentDecorator.cleanup();
125
- contentDecorator.removeDroppable($('#gallery img'));
126
- }
119
+ contentDecorator.setSnippetName(snippetName);
120
+ }
121
+
122
+ function removeIDs(elements) {
127
123
 
128
- snippetName = _snippetName;
129
- originalHtml = $('.snippet-'+snippetName).html();
130
- contentDecorator = new ContentDecorator('.snippet-'+snippetName);
131
- contentDecorator.addRemoveZone('#gallery');
132
- $('#code').val(originalHtml);
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
- update(editor.getValue());
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
- $('#gallery img').removeClass('movable');
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
- // We set this as it holds all the images as when we started
246
- $('.snippet-'+snippetName).html(originalHtml);
247
- contentDecorator.init();
248
- editor.setValue(originalValue);
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 = window.burp_path || snippets().snippets[snippetName].pageId || window.location.pathname;
254
- if(path === "/") {
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
- data.snippets[snippetName] = contentDecorator.getHtml();
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
- var start_time;
317
-
318
- $(window).keydown(function(event) {
319
- if (
320
- ((event.altKey === true || event.ctrlKey === true ) && event.keyCode === 27) ||
321
- (event.altKey === true && event.ctrlKey === true && event.keyCode === 32)
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
- if(!start_time || start_time.getTime() + 1000 < new Date().getTime()) {
325
- trigger_http_basic_auth(function() {
326
- init();
327
- $.adminDock.toggle();
328
- start_time = null;
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
- sizes.each_pair do |key,value|
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/cms_helper.js)
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
@@ -1,3 +1,3 @@
1
1
  module Burp
2
- VERSION = "1.3.33"
2
+ VERSION = "1.4.0"
3
3
  end
@@ -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/cms_helper'")
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.3.33
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: 2013-11-28 00:00:00.000000000 Z
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.0.6
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!