Skip to content

Commit 423c6ba

Browse files
committed
Implemented live post content preview without saving
1 parent 22837de commit 423c6ba

10 files changed

Lines changed: 130 additions & 25 deletions

File tree

README.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,10 @@ SpringBlog is powered by many powerful frameworks and third-party projects:
2525

2626
## Changelog
2727

28+
#### 2018-01-29
29+
30+
* Implemented live post content preview without saving
31+
2832
#### 2017-12-25
2933

3034
* Added chart filters into admin dashboard using [Date Range Picker](http://www.daterangepicker.com)

build.gradle

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ apply plugin: 'org.springframework.boot'
66
sourceCompatibility = 1.8
77
targetCompatibility = 1.8
88

9-
version = '2.8.1'
9+
version = '2.8.2'
1010

1111
repositories {
1212
mavenCentral()

src/main/java/com/raysmond/blog/admin/controllers/PostController.java

Lines changed: 19 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,30 +1,34 @@
11
package com.raysmond.blog.admin.controllers;
22

33
import com.raysmond.blog.forms.PostForm;
4+
import com.raysmond.blog.forms.PostPreviewForm;
45
import com.raysmond.blog.models.Post;
56
import com.raysmond.blog.models.Tag;
67
import com.raysmond.blog.models.User;
8+
import com.raysmond.blog.models.dto.PostPreviewDTO;
79
import com.raysmond.blog.models.support.*;
810
import com.raysmond.blog.repositories.PostRepository;
911
import com.raysmond.blog.repositories.UserRepository;
1012
import com.raysmond.blog.services.AppSetting;
1113
import com.raysmond.blog.services.PostService;
1214
import com.raysmond.blog.services.TagService;
15+
import com.raysmond.blog.support.web.FlexmarkMarkdownService;
16+
import com.raysmond.blog.support.web.MarkdownService;
1317
import com.raysmond.blog.utils.DTOUtil;
1418
import com.raysmond.blog.utils.PaginatorUtil;
1519
import org.hibernate.Hibernate;
1620
import org.springframework.beans.factory.annotation.Autowired;
1721
import org.springframework.data.domain.Page;
1822
import org.springframework.data.domain.PageRequest;
1923
import org.springframework.data.domain.Sort;
24+
import org.springframework.http.MediaType;
2025
import org.springframework.stereotype.Controller;
2126
import org.springframework.ui.Model;
2227
import org.springframework.validation.Errors;
2328
import org.springframework.validation.FieldError;
2429
import org.springframework.validation.ObjectError;
25-
import org.springframework.web.bind.annotation.PathVariable;
26-
import org.springframework.web.bind.annotation.RequestMapping;
27-
import org.springframework.web.bind.annotation.RequestParam;
30+
import org.springframework.web.bind.annotation.*;
31+
2832
import javax.validation.Valid;
2933
import java.security.Principal;
3034
import java.util.*;
@@ -47,6 +51,9 @@ public class PostController {
4751
@Autowired
4852
private UserRepository userRepository;
4953

54+
@Autowired
55+
private MarkdownService markdownService;
56+
5057
private static final int PAGE_SIZE = 20;
5158

5259
@RequestMapping(value = "")
@@ -164,7 +171,16 @@ public String update(@PathVariable Long postId, @Valid PostForm postForm, Errors
164171
}
165172
}
166173

174+
@RequestMapping(value = "/preview", method = {PUT, POST}, produces = MediaType.APPLICATION_JSON_VALUE)
175+
public @ResponseBody
176+
PostPreviewDTO preview(@RequestBody @Valid PostPreviewForm postPreviewForm, Errors errors, Model model) throws Exception {
167177

178+
if (errors.hasErrors()) {
179+
throw new Exception("Error occurred!");
180+
}
181+
182+
return new PostPreviewDTO(markdownService.renderToHtml(postPreviewForm.getContent()));
183+
}
168184

169185

170186
}
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
package com.raysmond.blog.forms;
2+
3+
import lombok.Data;
4+
import org.hibernate.validator.constraints.NotEmpty;
5+
6+
/**
7+
* Created by bvn13 on 28.01.2018.
8+
*/
9+
@Data
10+
public class PostPreviewForm {
11+
12+
@NotEmpty
13+
private String content;
14+
15+
}
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
package com.raysmond.blog.models.dto;
2+
3+
import lombok.AllArgsConstructor;
4+
import lombok.Data;
5+
6+
/**
7+
* Created by bvn13 on 28.01.2018.
8+
*/
9+
@Data
10+
@AllArgsConstructor
11+
public class PostPreviewDTO {
12+
13+
private String content;
14+
15+
}

src/main/java/com/raysmond/blog/support/web/ViewHelper.java

Lines changed: 15 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -27,21 +27,21 @@ public class ViewHelper {
2727

2828
private static Logger logger = LoggerFactory.getLogger(ViewHelper.class);
2929

30-
private static DateFormatSymbols ruDateFormatSymbolsFull = new DateFormatSymbols(){
31-
@Override
32-
public String[] getMonths() {
33-
return new String[]{"январь", "февраль", "март", "апрель", "май", "июнь", "июль", "август", "сентябрь", "октябрь", "ноябрь", "декабрь"};
34-
}
35-
};
36-
private static DateFormatSymbols ruDateFormatSymbolsShort = new DateFormatSymbols(){
37-
@Override
38-
public String[] getMonths() {
39-
return new String[]{"янв", "фев", "мар", "апр", "май", "июн", "июл", "авг", "сен", "окт", "ноя", "дек"};
40-
}
41-
};
42-
43-
private static final SimpleDateFormat DATE_FORMAT = new SimpleDateFormat("MMMM dd, yyyy", ViewHelper.ruDateFormatSymbolsFull);
44-
private static final SimpleDateFormat DATE_FORMAT_MONTH_DAY = new SimpleDateFormat("MMM dd", ViewHelper.ruDateFormatSymbolsShort);
30+
// private static DateFormatSymbols ruDateFormatSymbolsFull = new DateFormatSymbols(){
31+
// @Override
32+
// public String[] getMonths() {
33+
// return new String[]{"январь", "февраль", "март", "апрель", "май", "июнь", "июль", "август", "сентябрь", "октябрь", "ноябрь", "декабрь"};
34+
// }
35+
// };
36+
// private static DateFormatSymbols ruDateFormatSymbolsShort = new DateFormatSymbols(){
37+
// @Override
38+
// public String[] getMonths() {
39+
// return new String[]{"янв", "фев", "мар", "апр", "май", "июн", "июл", "авг", "сен", "окт", "ноя", "дек"};
40+
// }
41+
// };
42+
43+
private static final SimpleDateFormat DATE_FORMAT = new SimpleDateFormat("MMMM dd, yyyy"); //, ViewHelper.ruDateFormatSymbolsFull);
44+
private static final SimpleDateFormat DATE_FORMAT_MONTH_DAY = new SimpleDateFormat("MMM dd"); //, ViewHelper.ruDateFormatSymbolsShort);
4545

4646
private AppSetting appSetting;
4747

src/main/resources/resources/css/admin/admin.css

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -50,4 +50,17 @@ td.operations a{
5050
.mt-10 { margin-top:10px; }
5151
.mt-15 { margin-top:15px; }
5252
.mt-17 { margin-top:17px; }
53-
.mt-30 { margin-top:30px; }
53+
.mt-30 { margin-top:30px; }
54+
55+
56+
.loading {
57+
display: block; /*for the img inside your div */
58+
margin-left: auto;
59+
margin-right: auto;
60+
}
61+
62+
.loading-error {
63+
display: block; /*for the img inside your div */
64+
margin-left: auto;
65+
margin-right: auto;
66+
}
Lines changed: 1 addition & 0 deletions
Loading
42.7 KB
Loading

src/main/resources/templates/admin/posts/edit.jade

Lines changed: 46 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -24,20 +24,23 @@ block content
2424

2525
.item-row
2626
ul#pages-tabs.nav.nav-tabs.nav-justified
27-
li#tab-page-announce.active(role="presentation")
27+
li#tab-page-announce(role="presentation")
2828
a#btn-page-announce(href="#") Announce
29-
li#tab-page-content(role="presentation")
29+
li#tab-page-content.active(role="presentation")
3030
a#btn-page-content(href="#") Content
31+
li#tab-page-preview(role="presentation")
32+
a#btn-page-preview(href="#") Preview
33+
3134

3235
div#pages
3336

34-
div#page-announce
37+
div#page-announce(style="display:none")
3538

3639
.item-row
3740
textarea.form-control#announcement(name="announcement")
3841
= postForm.getAnnouncement()
3942

40-
div#page-content(style="display:none")
43+
div#page-content
4144

4245
.item-row
4346
textarea.form-control#content(name="content", style="display:none;")
@@ -111,6 +114,12 @@ block content
111114
else
112115
option(value="#{ogLocale.getId()}") #{ogLocale.getName()}
113116

117+
div#page-preview(style="display:none")
118+
119+
.item-row
120+
div#content-preview
121+
img#loading.loading.borderless(src="/images/loading.gif")
122+
114123

115124
.item-row
116125
hr
@@ -137,8 +146,9 @@ block content
137146
$(document).ready(function () {
138147
// page Announcement
139148
$("#btn-page-announce").click(function () {
140-
$("#page-announce").show();
149+
$("#page-preview").hide();
141150
$("#page-content").hide();
151+
$("#page-announce").show();
142152
$("#pages-tabs li").each(function () {
143153
$(this).removeClass("active");
144154
});
@@ -147,10 +157,41 @@ block content
147157
//page Content
148158
$("#btn-page-content").click(function () {
149159
$("#page-announce").hide();
160+
$("#page-preview").hide();
150161
$("#page-content").show();
151162
$("#pages-tabs li").each(function () {
152163
$(this).removeClass("active");
153164
});
154165
$("#tab-page-content").addClass("active");
155166
});
167+
//page Preview
168+
$("#btn-page-preview").click(function () {
169+
$("#page-announce").hide();
170+
$("#page-content").hide();
171+
$("#page-preview").show();
172+
$("#pages-tabs li").each(function () {
173+
$(this).removeClass("active");
174+
});
175+
$("#tab-page-preview").addClass("active");
176+
177+
$("#content-preview").html("<img class='loading borderless' src='/images/loading.gif'/>");
178+
var token = $("input[name='_csrf']").val();
179+
var header = "X-CSRF-TOKEN";
180+
$(document).ajaxSend(function (e, xhr, options) {
181+
xhr.setRequestHeader(header, token);
182+
});
183+
$.ajax({
184+
type: 'post',
185+
contentType: 'application/json',
186+
url: '/admin/posts/preview',
187+
data: JSON.stringify({
188+
content: editor.getValue()
189+
})
190+
}).done(function(data) {
191+
$("#content-preview").html(data.content);
192+
}).fail(function() {
193+
$("#content-preview").html("<img class='loading-error borderless' src='/images/icon_error.svg'/>");
194+
});
195+
196+
});
156197
});

0 commit comments

Comments
 (0)