burp_cms 1.3.33 → 1.4.0

Sign up to get free protection for your applications and to get access to all the features.
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!