mirror of https://github.com/halo-dev/halo
complate theme system
parent
cfb261eb4f
commit
fe1204f441
|
@ -5,9 +5,7 @@ import lombok.Data;
|
|||
import java.io.Serializable;
|
||||
|
||||
/**
|
||||
* <pre>
|
||||
* 主题信息
|
||||
* </pre>
|
||||
* Theme DTO
|
||||
*
|
||||
* @author : RYAN0UP
|
||||
* @date : 2018/1/3
|
||||
|
@ -18,17 +16,22 @@ public class Theme implements Serializable {
|
|||
private static final long serialVersionUID = 1L;
|
||||
|
||||
/**
|
||||
* 主题名称
|
||||
* theme name
|
||||
*/
|
||||
private String themeName;
|
||||
|
||||
/**
|
||||
* 是否支持设置
|
||||
* is support setting options
|
||||
*/
|
||||
private boolean hasOptions;
|
||||
|
||||
/**
|
||||
* 是否支持更新
|
||||
* is support update
|
||||
*/
|
||||
private boolean hasUpdate;
|
||||
|
||||
/**
|
||||
* is internal theme
|
||||
*/
|
||||
private boolean isInternal;
|
||||
}
|
||||
|
|
|
@ -1,6 +1,9 @@
|
|||
package cc.ryanc.halo.utils;
|
||||
|
||||
import cc.ryanc.halo.model.support.HaloConst;
|
||||
import cc.ryanc.halo.model.support.Theme;
|
||||
import cc.ryanc.halo.web.controller.core.BaseContentController;
|
||||
import cn.hutool.core.text.StrBuilder;
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.util.ResourceUtils;
|
||||
|
@ -27,8 +30,8 @@ public class ThemeUtils {
|
|||
public static List<Theme> getThemes() {
|
||||
final List<Theme> themes = new ArrayList<>();
|
||||
try {
|
||||
themes.addAll(getThemesByPath(getInternalThemesPath()));
|
||||
themes.addAll(getThemesByPath(getUsersThemesPath()));
|
||||
themes.addAll(getThemesByPath(getInternalThemesPath(), true));
|
||||
themes.addAll(getThemesByPath(getUsersThemesPath(), false));
|
||||
} catch (Exception e) {
|
||||
log.error("Themes scan failed", e);
|
||||
}
|
||||
|
@ -41,7 +44,7 @@ public class ThemeUtils {
|
|||
* @param file file
|
||||
* @return List<Theme>
|
||||
*/
|
||||
private static List<Theme> getThemesByPath(File themesPath) {
|
||||
private static List<Theme> getThemesByPath(File themesPath, boolean isInternal) {
|
||||
final List<Theme> themes = new ArrayList<>();
|
||||
try {
|
||||
final File[] files = themesPath.listFiles();
|
||||
|
@ -67,6 +70,7 @@ public class ThemeUtils {
|
|||
} else {
|
||||
theme.setHasUpdate(false);
|
||||
}
|
||||
theme.setInternal(isInternal);
|
||||
themes.add(theme);
|
||||
}
|
||||
}
|
||||
|
@ -78,7 +82,7 @@ public class ThemeUtils {
|
|||
}
|
||||
|
||||
/**
|
||||
* Get internal themes
|
||||
* Get internal themes path
|
||||
*
|
||||
* @return File
|
||||
* @throws FileNotFoundException FileNotFoundException
|
||||
|
@ -88,7 +92,7 @@ public class ThemeUtils {
|
|||
}
|
||||
|
||||
/**
|
||||
* Get user's themes
|
||||
* Get user's themes path
|
||||
*
|
||||
* @return File
|
||||
*/
|
||||
|
@ -96,6 +100,20 @@ public class ThemeUtils {
|
|||
return new File(System.getProperties().getProperty("user.home"), "halo/templates/themes");
|
||||
}
|
||||
|
||||
/**
|
||||
* Get themes path by theme name
|
||||
*
|
||||
* @param themeName themeName
|
||||
* @return File
|
||||
*/
|
||||
public static File getThemesPath(String themeName) throws FileNotFoundException {
|
||||
if (isInternal(themeName)) {
|
||||
return getInternalThemesPath();
|
||||
} else {
|
||||
return getUsersThemesPath();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get theme templates
|
||||
*
|
||||
|
@ -105,7 +123,7 @@ public class ThemeUtils {
|
|||
public static List<String> getTplName(String theme) {
|
||||
final List<String> templates = new ArrayList<>();
|
||||
try {
|
||||
final File themesPath = new File(getUsersThemesPath(), "templates/themes/" + theme);
|
||||
final File themesPath = new File(getThemesPath(theme), theme);
|
||||
final File modulePath = new File(themesPath.getAbsolutePath(), "module");
|
||||
final File[] baseFiles = themesPath.listFiles();
|
||||
final File[] moduleFiles = modulePath.listFiles();
|
||||
|
@ -134,9 +152,9 @@ public class ThemeUtils {
|
|||
*
|
||||
* @return List
|
||||
*/
|
||||
public static List<String> getCustomTpl(String theme) {
|
||||
public static List<String> getCustomTpl(String theme) throws FileNotFoundException {
|
||||
final List<String> templates = new ArrayList<>();
|
||||
final File themePath = new File(getUsersThemesPath(), "templates/themes/" + theme);
|
||||
final File themePath = new File(getThemesPath(theme), theme);
|
||||
final File[] themeFiles = themePath.listFiles();
|
||||
if (null != themeFiles && themeFiles.length > 0) {
|
||||
for (File file : themeFiles) {
|
||||
|
@ -148,4 +166,41 @@ public class ThemeUtils {
|
|||
}
|
||||
return templates;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Judging whether template exists under the specified theme
|
||||
*
|
||||
* @param template template
|
||||
* @return boolean
|
||||
*/
|
||||
public static boolean isTemplateExist(String template) throws FileNotFoundException {
|
||||
boolean result = false;
|
||||
StrBuilder templatePath = new StrBuilder(BaseContentController.THEME);
|
||||
templatePath.append("/");
|
||||
templatePath.append(template);
|
||||
File file = new File(getThemesPath(BaseContentController.THEME), templatePath.toString());
|
||||
if (file.exists()) {
|
||||
result = true;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Judging whether the theme is a internal theme or not
|
||||
*
|
||||
* @param themeName themeName
|
||||
* @return boolean
|
||||
*/
|
||||
public static boolean isInternal(String themeName) {
|
||||
boolean result = false;
|
||||
List<Theme> themes = HaloConst.THEMES;
|
||||
for (Theme theme : themes) {
|
||||
if (theme.getThemeName().equals(themeName) && theme.isInternal()) {
|
||||
result = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -129,7 +129,7 @@ public class ThemeController extends BaseController {
|
|||
@GetMapping(value = "/remove")
|
||||
public String removeTheme(@RequestParam("themeName") String themeName) {
|
||||
try {
|
||||
final File themePath = new File(ThemeUtils.getUsersThemesPath(), themeName);
|
||||
final File themePath = new File(ThemeUtils.getThemesPath(themeName), themeName);
|
||||
FileUtil.del(themePath);
|
||||
} catch (Exception e) {
|
||||
log.error("Delete theme failed: {}", e.getMessage());
|
||||
|
@ -244,7 +244,7 @@ public class ThemeController extends BaseController {
|
|||
public String getTplContent(@RequestParam("tplName") String tplName) {
|
||||
String tplContent = "";
|
||||
try {
|
||||
final StrBuilder themePath = new StrBuilder(ThemeUtils.getUsersThemesPath().getAbsolutePath());
|
||||
final StrBuilder themePath = new StrBuilder(ThemeUtils.getThemesPath(BaseContentController.THEME).getAbsolutePath());
|
||||
themePath.append(BaseContentController.THEME);
|
||||
themePath.append("/");
|
||||
themePath.append(tplName);
|
||||
|
@ -272,7 +272,7 @@ public class ThemeController extends BaseController {
|
|||
return new JsonResult(0, localeMessage("code.admin.theme.edit.no-content"));
|
||||
}
|
||||
try {
|
||||
final StrBuilder themePath = new StrBuilder(ThemeUtils.getUsersThemesPath().getAbsolutePath());
|
||||
final StrBuilder themePath = new StrBuilder(ThemeUtils.getThemesPath(BaseContentController.THEME).getAbsolutePath());
|
||||
themePath.append(BaseContentController.THEME);
|
||||
themePath.append("/");
|
||||
themePath.append(tplName);
|
||||
|
|
|
@ -3,6 +3,7 @@ package cc.ryanc.halo.web.controller.core;
|
|||
import cc.ryanc.halo.logging.Logger;
|
||||
import cc.ryanc.halo.model.entity.User;
|
||||
import cc.ryanc.halo.model.support.HaloConst;
|
||||
import cc.ryanc.halo.utils.ThemeUtils;
|
||||
import cn.hutool.core.text.StrBuilder;
|
||||
import org.springframework.boot.web.servlet.error.ErrorController;
|
||||
import org.springframework.stereotype.Controller;
|
||||
|
@ -11,6 +12,7 @@ import org.springframework.web.bind.annotation.GetMapping;
|
|||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpSession;
|
||||
import java.io.FileNotFoundException;
|
||||
|
||||
/**
|
||||
* <pre>
|
||||
|
@ -92,7 +94,10 @@ public class CommonController implements ErrorController {
|
|||
* @return String
|
||||
*/
|
||||
@GetMapping(value = "/404")
|
||||
public String contentNotFround() {
|
||||
public String contentNotFround() throws FileNotFoundException {
|
||||
if(ThemeUtils.isTemplateExist("404.ftl")){
|
||||
return "common/error/404";
|
||||
}
|
||||
StrBuilder path = new StrBuilder("themes/");
|
||||
path.append(BaseContentController.THEME);
|
||||
path.append("/404");
|
||||
|
@ -105,7 +110,10 @@ public class CommonController implements ErrorController {
|
|||
* @return template path:
|
||||
*/
|
||||
@GetMapping(value = "/500")
|
||||
public String contentInternalError() {
|
||||
public String contentInternalError() throws FileNotFoundException {
|
||||
if(ThemeUtils.isTemplateExist("500.ftl")){
|
||||
return "common/error/404";
|
||||
}
|
||||
StrBuilder path = new StrBuilder("themes/");
|
||||
path.append(BaseContentController.THEME);
|
||||
path.append("/500");
|
||||
|
|
|
@ -2,6 +2,7 @@ package cc.ryanc.halo.web.controller.core;
|
|||
|
||||
import cc.ryanc.halo.model.entity.*;
|
||||
import cc.ryanc.halo.model.enums.CommentStatus;
|
||||
import cc.ryanc.halo.model.enums.PostStatus;
|
||||
import cc.ryanc.halo.model.support.JsonResult;
|
||||
import cc.ryanc.halo.service.*;
|
||||
import cc.ryanc.halo.utils.MarkdownUtils;
|
||||
|
@ -133,9 +134,9 @@ public class InstallController {
|
|||
"欢迎使用Halo进行创作,删除这篇文章后赶紧开始吧。");
|
||||
post.setFormatContent(MarkdownUtils.renderMarkdown(post.getOriginalContent()));
|
||||
post.setSummary("欢迎使用Halo进行创作,删除这篇文章后赶紧开始吧。");
|
||||
post.setStatus(0);
|
||||
post.setStatus(PostStatus.PUBLISHED);
|
||||
post.setUrl("hello-halo");
|
||||
post.setDisallowComment(1);
|
||||
post.setDisallowComment(true);
|
||||
post.setThumbnail("/static/halo-frontend/images/thumbnail/thumbnail-" + RandomUtil.randomInt(1, 11) + ".jpg");
|
||||
postService.create(post);
|
||||
|
||||
|
|
|
@ -1,52 +1 @@
|
|||
<#compress>
|
||||
<!DOCTYPE html>
|
||||
<html lang="zh">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=Edge,chrome=1">
|
||||
<meta name="renderer" content="webkit">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1, user-scalable=no">
|
||||
<title>404 Not Found</title>
|
||||
<link href="//cdnjs.loli.net/ajax/libs/font-awesome/4.7.0/css/font-awesome.min.css" rel="stylesheet">
|
||||
<link href="//cdnjs.loli.net/ajax/libs/animate.css/3.7.0/animate.min.css" rel="stylesheet">
|
||||
<style type="text/css" rel="stylesheet">
|
||||
body{margin:0}*{box-sizing:border-box}h1,h2{margin:0}a{color:#fff;text-decoration:none}body,html{font-family:-apple-system,system-ui,BlinkMacSystemFont,Segoe UI,Roboto,Helvetica Neue,Arial,sans-serif}.fullscreen{background-position:50% 50%;background-size:cover}.fullscreen,.fullscreen .backColor{position:absolute;top:0;left:0;width:100%;height:100%}.fullscreen .backColor{background-color:rgba(0,0,0,.1)}.infos{display:flex;text-align:center;align-items:center;justify-content:center}.infos,.main-content{position:absolute;top:0;left:0;width:100%;height:100%;color:#fff}.main-content{background: #833ab4;background: -webkit-linear-gradient(to right, #833ab4, #fd1d1d, #fcb045);background: linear-gradient(to right, #833ab4, #fd1d1d, #fcb045);}.errorPage{position:relative;width:100vw;height:100vh}.infos-h1{margin:0;font-size:5em;line-height:1}.infos-h1 h1{font-weight:200}.footer{position:absolute;right:1rem;bottom:1rem;left:1rem;z-index:9999;font-size:14px}.infos-h2{font-size:24px}.infos-h2 a:hover{color:#7a8d85}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div class="container">
|
||||
<div class="errorPage">
|
||||
<div class="main-content ">
|
||||
<div class="fullscreen">
|
||||
<div class="backColor"></div>
|
||||
</div>
|
||||
<div class="infos">
|
||||
<div class="infos-main">
|
||||
<div class="infos-h1"><h1>404</h1></div>
|
||||
<div class="infos-h2">
|
||||
<a href="javascript:window.history.back()" title="返回上一页">
|
||||
<i class="fa fa-chevron-left"></i>
|
||||
</a>
|
||||
<a href="/" title="返回到主页">
|
||||
<i class="fa fa-home"></i>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="footer">
|
||||
<span>Copyright © 2018</span>
|
||||
<a href="${options.blog_url!}">${options.blog_title!'Halo'}</a>
|
||||
<span style="float: right">
|
||||
Background image from <a href="https://cn.bing.com/" target="_blank">Bing</a>.
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</body>
|
||||
<script src="//cdnjs.loli.net/ajax/libs/jquery/3.2.1/jquery.min.js"></script>
|
||||
<script>
|
||||
eval(function(p,a,c,k,e,r){e=function(c){return(c<a?'':e(parseInt(c/a)))+((c=c%a)>35?String.fromCharCode(c+29):c.toString(36))};if(!''.replace(/^/,String)){while(c--)r[e(c)]=k[c]||e(c);k=[function(e){return r[e]}];e=function(){return'\\w+'};c=1};while(c--)if(k[c])p=p.replace(new RegExp('\\b'+e(c)+'\\b','g'),k[c]);return p}('$.o(\'m://q.8.n/?1=4%y%z%B.5.9%d.e%f%g%h%i%j%k\',l(b){6 a=b.p[0].1;6 c=$(\'.r\');c.t("u-v","1(4://s.w.5.x"+a+")");c.2(\'3 A\');$(\'.7-C\').2(\'3 D\');$(\'.7-E\').2(\'3 F\')});',42,42,'|url|addClass|animated|http|bing|var|infos|afeld|com||||2FHPImageArchive|aspx|3Fformat|3Djs|26idx|3D0|26n|3D1|function|https|me|get|images|jsonp|fullscreen||css|background|image|cn|net|3A|2F|fadeIn|2Fcn|h1|shake|h2|fadeInDown'.split('|'),0,{}))
|
||||
</script>
|
||||
</html>
|
||||
</#compress>
|
||||
404 Not Found
|
||||
|
|
|
@ -1,52 +1 @@
|
|||
<#compress>
|
||||
<!DOCTYPE html>
|
||||
<html lang="zh">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=Edge,chrome=1">
|
||||
<meta name="renderer" content="webkit">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1, user-scalable=no">
|
||||
<title>500 Error Page</title>
|
||||
<link href="//cdnjs.loli.net/ajax/libs/font-awesome/4.7.0/css/font-awesome.min.css" rel="stylesheet">
|
||||
<link href="//cdnjs.loli.net/ajax/libs/animate.css/3.7.0/animate.min.css" rel="stylesheet">
|
||||
<style type="text/css" rel="stylesheet">
|
||||
body{margin:0}*{box-sizing:border-box}h1,h2{margin:0}a{color:#fff;text-decoration:none}body,html{font-family:-apple-system,system-ui,BlinkMacSystemFont,Segoe UI,Roboto,Helvetica Neue,Arial,sans-serif}.fullscreen{background-position:50% 50%;background-size:cover}.fullscreen,.fullscreen .backColor{position:absolute;top:0;left:0;width:100%;height:100%}.fullscreen .backColor{background-color:rgba(0,0,0,.1)}.infos{display:flex;text-align:center;align-items:center;justify-content:center}.infos,.main-content{position:absolute;top:0;left:0;width:100%;height:100%;color:#fff}.main-content{background: #833ab4;background: -webkit-linear-gradient(to right, #833ab4, #fd1d1d, #fcb045);background: linear-gradient(to right, #833ab4, #fd1d1d, #fcb045);}.errorPage{position:relative;width:100vw;height:100vh}.infos-h1{margin:0;font-size:5em;line-height:1}.infos-h1 h1{font-weight:200}.footer{position:absolute;right:1rem;bottom:1rem;left:1rem;z-index:9999;font-size:14px}.infos-h2{font-size:24px}.infos-h2 a:hover{color:#7a8d85}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div class="container">
|
||||
<div class="errorPage">
|
||||
<div class="main-content ">
|
||||
<div class="fullscreen">
|
||||
<div class="backColor"></div>
|
||||
</div>
|
||||
<div class="infos">
|
||||
<div class="infos-main">
|
||||
<div class="infos-h1"><h1>500</h1></div>
|
||||
<div class="infos-h2">
|
||||
<a href="javascript:window.history.back()" title="返回上一页">
|
||||
<i class="fa fa-chevron-left"></i>
|
||||
</a>
|
||||
<a href="/" title="返回到主页">
|
||||
<i class="fa fa-home"></i>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="footer">
|
||||
<span>Copyright © 2018</span>
|
||||
<a href="${options.blog_title!}">${options.blog_title!'Halo'}</a>
|
||||
<span style="float: right">
|
||||
Background image from <a href="https://cn.bing.com/" target="_blank">Bing</a>.
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</body>
|
||||
<script src="//cdnjs.loli.net/ajax/libs/jquery/3.2.1/jquery.min.js"></script>
|
||||
<script>
|
||||
eval(function(p,a,c,k,e,r){e=function(c){return(c<a?'':e(parseInt(c/a)))+((c=c%a)>35?String.fromCharCode(c+29):c.toString(36))};if(!''.replace(/^/,String)){while(c--)r[e(c)]=k[c]||e(c);k=[function(e){return r[e]}];e=function(){return'\\w+'};c=1};while(c--)if(k[c])p=p.replace(new RegExp('\\b'+e(c)+'\\b','g'),k[c]);return p}('$.o(\'m://q.8.n/?1=4%y%z%B.5.9%d.e%f%g%h%i%j%k\',l(b){6 a=b.p[0].1;6 c=$(\'.r\');c.t("u-v","1(4://s.w.5.x"+a+")");c.2(\'3 A\');$(\'.7-C\').2(\'3 D\');$(\'.7-E\').2(\'3 F\')});',42,42,'|url|addClass|animated|http|bing|var|infos|afeld|com||||2FHPImageArchive|aspx|3Fformat|3Djs|26idx|3D0|26n|3D1|function|https|me|get|images|jsonp|fullscreen||css|background|image|cn|net|3A|2F|fadeIn|2Fcn|h1|shake|h2|fadeInDown'.split('|'),0,{}))
|
||||
</script>
|
||||
</html>
|
||||
</#compress>
|
||||
500 Internal Error
|
||||
|
|
Loading…
Reference in New Issue