👽 1.支持归档信息根据年份和月份或年份归档,2.初步防御xss

pull/1/head
RYAN0UP_ 2018-04-26 11:43:26 +08:00
parent 602059fb2a
commit d7d0d991db
14 changed files with 537 additions and 187 deletions

12
pom.xml
View File

@ -120,6 +120,18 @@
<artifactId>commons-lang3</artifactId>
<version>${commons-lang3.version}</version>
</dependency>
<dependency>
<groupId>org.jsoup</groupId>
<artifactId>jsoup</artifactId>
<version>1.9.2</version>
</dependency>
<dependency>
<groupId>com.google.guava</groupId>
<artifactId>guava</artifactId>
<version>18.0</version>
</dependency>
</dependencies>
<build>

View File

@ -1,9 +1,13 @@
package cc.ryanc.halo.config;
import cc.ryanc.halo.security.XssFilter;
import cc.ryanc.halo.web.interceptor.InstallInterceptor;
import cc.ryanc.halo.web.interceptor.LoginInterceptor;
import com.google.common.collect.Maps;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.web.servlet.FilterRegistrationBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.PropertySource;
@ -12,6 +16,8 @@ import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
import java.util.Map;
/**
* @author : RYAN0UP
* @date : 2018/1/2
@ -63,4 +69,21 @@ public class MvcConfiguration implements WebMvcConfigurer {
registry.addResourceHandler("/upload/**")
.addResourceLocations("classpath:/upload/");
}
/**
* xss
*/
@Bean
public FilterRegistrationBean xssFilterRegistrationBean() {
FilterRegistrationBean filterRegistrationBean = new FilterRegistrationBean();
filterRegistrationBean.setFilter(new XssFilter());
filterRegistrationBean.setOrder(1);
filterRegistrationBean.setEnabled(true);
filterRegistrationBean.addUrlPatterns("/*");
Map<String, String> initParameters = Maps.newHashMap();
initParameters.put("excludes", "/static/*,/upload/*");
initParameters.put("isIncludeRichText", "true");
filterRegistrationBean.setInitParameters(initParameters);
return filterRegistrationBean;
}
}

View File

@ -90,12 +90,19 @@ public interface PostRepository extends JpaRepository<Post,Long>{
List<Post> findByPostDateBeforeAndPostStatusOrderByPostDateAsc(Date postDate,Integer postStatus);
/**
*
*
*
* @return list
*/
@Query(value = "select year(post_date) as year,month(post_date) as month,count(*) as count from halo_post where post_status=0 group by year(post_date),month(post_date)",nativeQuery = true)
List<Object[]> findPostGroupByDate();
@Query(value = "select year(post_date) as year,month(post_date) as month,count(*) as count from halo_post where post_status=0 group by year(post_date),month(post_date) order by year desc,month desc",nativeQuery = true)
List<Object[]> findPostGroupByYearAndMonth();
/**
*
* @return
*/
@Query(value = "select year(post_date) as year,count(*) as count from halo_post where post_status=0 group by year(post_date) order by year desc",nativeQuery = true)
List<Object[]> findPostGroupByYear();
/**
*
@ -107,6 +114,15 @@ public interface PostRepository extends JpaRepository<Post,Long>{
@Query(value = "select *,year(post_date) as year,month(post_date) as month from halo_post where post_status=0 and year(post_date)=:year and month(post_date)=:month order by post_date",nativeQuery = true)
List<Post> findPostByYearAndMonth(@Param("year") String year,@Param("month") String month);
/**
*
*
* @param year year
* @return list
*/
@Query(value = "select *,year(post_date) as year from halo_post where post_status=0 and year(post_date)=:year order by post_date",nativeQuery = true)
List<Post> findPostByYear(@Param("year") String year);
/**
*
*

View File

@ -0,0 +1,32 @@
package cc.ryanc.halo.security;
import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;
import org.jsoup.safety.Whitelist;
/**
* @author : RYAN0UP
* @version : 1.0
* @date : 2018/4/25
*/
public class JsoupUtil {
/**
* 使basicWithImages
* 便a,b,blockquote,br,cite,code,dd,dl,dt,em,i,li,ol,p,pre,q,small,span,
* strike,strong,sub,sup,u,ul,img
* ahref,imgsrc,align,alt,height,width,title
*/
private static final Whitelist whitelist = Whitelist.basicWithImages();
/** 配置过滤化参数,不对代码进行格式化 */
private static final Document.OutputSettings outputSettings = new Document.OutputSettings().prettyPrint(false);
static {
// 富文本编辑时一些样式是使用style来进行实现的
// 比如红色字体 style="color:red;"
// 所以需要给所有标签添加style属性
whitelist.addAttributes(":all", "style");
}
public static String clean(String content) {
return Jsoup.clean(content, "", whitelist, outputSettings);
}
}

View File

@ -0,0 +1,86 @@
package cc.ryanc.halo.security;
import javax.servlet.*;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.BooleanUtils;
import org.apache.commons.lang3.StringUtils;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
/**
* @author : RYAN0UP
* @version : 1.0
* @date : 2018/4/25
*/
@Slf4j
public class XssFilter implements Filter {
private static boolean IS_INCLUDE_RICH_TEXT = false;
public List<String> excludes = new ArrayList<>();
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain filterChain) throws IOException,ServletException {
if(log.isDebugEnabled()){
log.debug("xss filter is open");
}
HttpServletRequest req = (HttpServletRequest) request;
HttpServletResponse resp = (HttpServletResponse) response;
if(handleExcludeURL(req, resp)){
filterChain.doFilter(request, response);
return;
}
XssHttpServletRequestWrapper xssRequest = new XssHttpServletRequestWrapper((HttpServletRequest) request,IS_INCLUDE_RICH_TEXT);
filterChain.doFilter(xssRequest, response);
}
private boolean handleExcludeURL(HttpServletRequest request, HttpServletResponse response) {
if (excludes == null || excludes.isEmpty()) {
return false;
}
String url = request.getServletPath();
for (String pattern : excludes) {
Pattern p = Pattern.compile("^" + pattern);
Matcher m = p.matcher(url);
if (m.find()) {
return true;
}
}
return false;
}
@Override
public void init(FilterConfig filterConfig) throws ServletException {
if(log.isDebugEnabled()){
log.debug("xss filter init~~~~~~~~~~~~");
}
String isIncludeRichText = filterConfig.getInitParameter("isIncludeRichText");
if(StringUtils.isNotBlank(isIncludeRichText)){
IS_INCLUDE_RICH_TEXT = BooleanUtils.toBoolean(isIncludeRichText);
}
String temp = filterConfig.getInitParameter("excludes");
if (temp != null) {
String[] url = temp.split(",");
for (int i = 0; url != null && i < url.length; i++) {
excludes.add(url[i]);
}
}
}
@Override
public void destroy() {}
}

View File

@ -0,0 +1,88 @@
package cc.ryanc.halo.security;
import org.apache.commons.lang3.StringUtils;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletRequestWrapper;
/**
* @author : RYAN0UP
* @version : 1.0
* @date : 2018/4/25
*/
public class XssHttpServletRequestWrapper extends HttpServletRequestWrapper {
HttpServletRequest orgRequest = null;
private boolean isIncludeRichText = false;
public XssHttpServletRequestWrapper(HttpServletRequest request, boolean isIncludeRichText) {
super(request);
orgRequest = request;
this.isIncludeRichText = isIncludeRichText;
}
/**
* getParameterxss<br/>
* super.getParameterValues(name)<br/>
* getParameterNames,getParameterValuesgetParameterMap
*/
@Override
public String getParameter(String name) {
if(("content".equals(name) || name.endsWith("WithHtml")) && !isIncludeRichText){
return super.getParameter(name);
}
name = JsoupUtil.clean(name);
String value = super.getParameter(name);
if (StringUtils.isNotBlank(value)) {
value = JsoupUtil.clean(value);
}
return value;
}
@Override
public String[] getParameterValues(String name) {
String[] arr = super.getParameterValues(name);
if(arr != null){
for (int i=0;i<arr.length;i++) {
arr[i] = JsoupUtil.clean(arr[i]);
}
}
return arr;
}
/**
* getHeaderxss<br/>
* super.getHeaders(name)<br/>
* getHeaderNames
*/
@Override
public String getHeader(String name) {
name = JsoupUtil.clean(name);
String value = super.getHeader(name);
if (StringUtils.isNotBlank(value)) {
value = JsoupUtil.clean(value);
}
return value;
}
/**
* request
*
* @return
*/
public HttpServletRequest getOrgRequest() {
return orgRequest;
}
/**
* request
*
* @return
*/
public static HttpServletRequest getOrgRequest(HttpServletRequest req) {
if (req instanceof XssHttpServletRequestWrapper) {
return ((XssHttpServletRequestWrapper) req).getOrgRequest();
}
return req;
}
}

View File

@ -139,11 +139,18 @@ public interface PostService {
List<Post> findByPostDateBefore(Date postDate);
/**
*
*
*
* @return List
*/
List<Archive> findPostGroupByPostDate();
List<Archive> findPostGroupByYearAndMonth();
/**
*
*
* @return list
*/
List<Archive> findPostGroupByYear();
/**
*
@ -162,7 +169,15 @@ public interface PostService {
* @param pageable pageable
* @return page
*/
Page<Post> findPostByYearAndMonth(@Param("year") String year, @Param("month") String month, Pageable pageable);
Page<Post> findPostByYearAndMonth(String year,String month, Pageable pageable);
/**
*
*
* @param year year
* @return list
*/
List<Post> findPostByYear(String year);
/**
* rss

View File

@ -205,13 +205,13 @@ public class PostServiceImpl implements PostService {
/**
*
*
*
* @return List
*/
@Override
public List<Archive> findPostGroupByPostDate() {
List<Object[]> objects = postRepository.findPostGroupByDate();
public List<Archive> findPostGroupByYearAndMonth() {
List<Object[]> objects = postRepository.findPostGroupByYearAndMonth();
List<Archive> archives = new ArrayList<>();
Archive archive = null;
for(Object[] obj : objects){
@ -225,6 +225,26 @@ public class PostServiceImpl implements PostService {
return archives;
}
/**
*
*
* @return list
*/
@Override
public List<Archive> findPostGroupByYear() {
List<Object[]> objects = postRepository.findPostGroupByYear();
List<Archive> archives = new ArrayList<>();
Archive archive = null;
for(Object[] obj : objects){
archive = new Archive();
archive.setYear(obj[0].toString());
archive.setCount(obj[1].toString());
archive.setPosts(this.findPostByYear(obj[0].toString()));
archives.add(archive);
}
return archives;
}
/**
*
*
@ -237,6 +257,17 @@ public class PostServiceImpl implements PostService {
return postRepository.findPostByYearAndMonth(year,month);
}
/**
*
*
* @param year year
* @return list
*/
@Override
public List<Post> findPostByYear(String year) {
return postRepository.findPostByYear(year);
}
/**
*
* @param year year year

View File

@ -113,7 +113,7 @@ public class IndexController extends BaseController{
model.addAttribute("menus",menus);
//归档数据,包含[year,month,count,List<Post>]
List<Archive> archives = postService.findPostGroupByPostDate();
List<Archive> archives = postService.findPostGroupByYearAndMonth();
model.addAttribute("archives",archives);
//设置选项
@ -186,7 +186,7 @@ public class IndexController extends BaseController{
model.addAttribute("categories",categories);
//归档数据,包含[year,month,count,List<Post>]
List<Archive> archives = postService.findPostGroupByPostDate();
List<Archive> archives = postService.findPostGroupByYearAndMonth();
//菜单列表
List<Menu> menus = menuService.findAllMenus();
@ -287,7 +287,7 @@ public class IndexController extends BaseController{
model.addAttribute("categories",categories);
//归档数据,包含[year,month,count,List<Post>]
List<Archive> archives = postService.findPostGroupByPostDate();
List<Archive> archives = postService.findPostGroupByYearAndMonth();
model.addAttribute("archives",archives);
//设置选项
@ -322,7 +322,7 @@ public class IndexController extends BaseController{
model.addAttribute("menus",menus);
//归档数据,包含[year,month,count,List<Post>]
List<Archive> archives = postService.findPostGroupByPostDate();
List<Archive> archives = postService.findPostGroupByYearAndMonth();
model.addAttribute("archives",archives);
@ -379,9 +379,13 @@ public class IndexController extends BaseController{
model.addAttribute("is_archives",true);
//包含[List<Post>,year,month,count]
List<Archive> archives = postService.findPostGroupByPostDate();
List<Archive> archives = postService.findPostGroupByYearAndMonth();
model.addAttribute("archives",archives);
//包含[List<Post>,year,count]
List<Archive> archivesLess = postService.findPostGroupByYear();
model.addAttribute("archivesLess",archivesLess);
//用户信息
User user = userService.findUser();
model.addAttribute("user",user);
@ -439,7 +443,7 @@ public class IndexController extends BaseController{
model.addAttribute("menus",menus);
//归档数据,包含[year,month,count,List<Post>]
List<Archive> archives = postService.findPostGroupByPostDate();
List<Archive> archives = postService.findPostGroupByYearAndMonth();
model.addAttribute("archives",archives);
//是否是归档页,用于判断输出链接

View File

@ -131,7 +131,11 @@
</div>
<div class="box-body">
<div>
<img src="/static/images/thumbnail.png" class="img-responsive img-thumbnail" id="selectImg" onclick="openAttach('selectImg')" style="cursor: pointer;">
<#if post??>
<img src="${post.postThumbnail?default("/static/images/thumbnail.png")}" class="img-responsive img-thumbnail" id="selectImg" onclick="openAttach('selectImg')" style="cursor: pointer;">
<#else >
<img src="/static/images/thumbnail.png" class="img-responsive img-thumbnail" id="selectImg" onclick="openAttach('selectImg')" style="cursor: pointer;">
</#if>
</div>
</div>
</div>

View File

@ -37,7 +37,7 @@
<a href="#pages" data-toggle="tab">自定义页面</a>
</li>
</ul>
<div class="tab-content">
<div class="tab-content" style="padding: 0;">
<div class="tab-pane active" id="internal">
<div class="box-body table-responsive">
<table class="table table-bordered table-hover">
@ -79,36 +79,37 @@
</div>
<div class="tab-pane" id="pages">
<div class="box-body table-responsive">
<table class="table table-bordered table-hover">
<thead>
<tr>
<th>标题</th>
<th>路径</th>
<th>日期</th>
<th>操作</th>
</tr>
</thead>
<tbody>
<tr>
<td>友情链接</td>
<td>/link</td>
<th>日期</th>
<td>
<a href="/links" class="btn btn-info btn-sm " target="_blank">预览</a>
<a href="/admin/page/links" class="btn btn-primary btn-sm ">配置</a>
</td>
</tr>
<tr>
<td>关于页面</td>
<td>/about</td>
<th>日期</th>
<td>
<a href="#" class="btn btn-info btn-sm " target="_blank">预览</a>
<a href="/admin/page/about" class="btn btn-primary btn-sm ">配置</a>
</td>
</tr>
</tbody>
</table>
开发中...
<#--<table class="table table-bordered table-hover">-->
<#--<thead>-->
<#--<tr>-->
<#--<th>标题</th>-->
<#--<th>路径</th>-->
<#--<th>日期</th>-->
<#--<th>操作</th>-->
<#--</tr>-->
<#--</thead>-->
<#--<tbody>-->
<#--<tr>-->
<#--<td>友情链接</td>-->
<#--<td>/link</td>-->
<#--<th>日期</th>-->
<#--<td>-->
<#--<a href="/links" class="btn btn-info btn-xs " target="_blank">预览</a>-->
<#--<a href="/admin/page/links" class="btn btn-primary btn-xs ">配置</a>-->
<#--</td>-->
<#--</tr>-->
<#--<tr>-->
<#--<td>关于页面</td>-->
<#--<td>/about</td>-->
<#--<th>日期</th>-->
<#--<td>-->
<#--<a href="#" class="btn btn-info btn-xs " target="_blank">预览</a>-->
<#--<a href="/admin/page/about" class="btn btn-primary btn-xs ">配置</a>-->
<#--</td>-->
<#--</tr>-->
<#--</tbody>-->
<#--</table>-->
</div>
</div>
</div>

View File

@ -57,53 +57,59 @@
</tr>
</thead>
<tbody>
<#list posts.content as post>
<#if posts.content?size gt 0>
<#list posts.content as post>
<tr>
<td>${post.postTitle}</td>
<td>
<#if post.categories?size gt 0>
<#list post.categories as cate>
<label>${cate.cateName}</label>
</#list>
<#else >
<label>无分类</label>
</#if>
</td>
<td>
<#if post.tags?size gt 0>
<#list post.tags as tag>
<label>${tag.tagName}</label>
</#list>
<#else >
<label>无标签</label>
</#if>
</td>
<td>
<#if post.getComments()??>
${post.getComments()?size}
</#if>
</td>
<td>${post.postDate?if_exists?string("yyyy-MM-dd HH:mm")}</td>
<td>
<#switch post.postStatus>
<#case 0>
<a href="/archives/${post.postUrl}" class="btn btn-primary btn-xs " target="_blank">查看</a>
<a href="/admin/posts/edit?postId=${post.postId}" class="btn btn-info btn-xs ">修改</a>
<button class="btn btn-danger btn-xs " onclick="modelShow('/admin/posts/throw?postId=${post.postId}','确定移到回收站?')">丢弃</button>
<#break >
<#case 1>
<a href="/admin/posts/view?postId=${post.postId}" class="btn btn-primary btn-xs " target="_blank">预览</a>
<a href="/admin/posts/edit?postId=${post.postId}" class="btn btn-info btn-xs ">修改</a>
<button class="btn btn-danger btn-xs " onclick="modelShow('/admin/posts/revert?postId=${post.postId}&status=1','确定发布该文章?')">发布</button>
<#break >
<#case 2>
<a href="/admin/posts/revert?postId=${post.postId}&status=2" class="btn btn-primary btn-xs ">还原</a>
<button class="btn btn-danger btn-xs " onclick="modelShow('/admin/posts/remove?postId=${post.postId}','确定永久删除?(不可逆)')">永久删除</button>
<#break >
</#switch>
</td>
</tr>
</#list>
<#else>
<tr>
<td>${post.postTitle}</td>
<td>
<#if post.categories?size gt 0>
<#list post.categories as cate>
${cate.cateName}
</#list>
<#else >
无分类
</#if>
</td>
<td>
<#if post.tags?size gt 0>
<#list post.tags as tag>
${tag.tagName}
</#list>
<#else >
无标签
</#if>
</td>
<td>
<#if post.getComments()??>
${post.getComments()?size}
</#if>
</td>
<td>${post.postDate?if_exists?string("yyyy-MM-dd HH:mm")}</td>
<td>
<#switch post.postStatus>
<#case 0>
<a href="/archives/${post.postUrl}" class="btn btn-primary btn-xs " target="_blank">查看</a>
<a href="/admin/posts/edit?postId=${post.postId}" class="btn btn-info btn-xs ">修改</a>
<button class="btn btn-danger btn-xs " onclick="modelShow('/admin/posts/throw?postId=${post.postId}','确定移到回收站?')">丢弃</button>
<#break >
<#case 1>
<a href="/admin/posts/view?postId=${post.postId}" class="btn btn-primary btn-xs " target="_blank">预览</a>
<a href="/admin/posts/edit?postId=${post.postId}" class="btn btn-info btn-xs ">修改</a>
<button class="btn btn-danger btn-xs " onclick="modelShow('/admin/posts/revert?postId=${post.postId}&status=1','确定发布该文章?')">发布</button>
<#break >
<#case 2>
<a href="/admin/posts/revert?postId=${post.postId}&status=2" class="btn btn-primary btn-xs ">还原</a>
<button class="btn btn-danger btn-xs " onclick="modelShow('/admin/posts/remove?postId=${post.postId}','确定永久删除?(不可逆)')">永久删除</button>
<#break >
</#switch>
</td>
<th colspan="6" style="text-align: center">暂无文章</th>
</tr>
</#list>
</#if>
</tbody>
</table>
</div>

View File

@ -10,61 +10,131 @@
<div class="content-wrapper">
<link rel="stylesheet" href="/static/plugins/toast/css/jquery.toast.min.css">
<style>
.tag-cloud .label{
padding: .3em .9em .45em;
font-size: 100%;
font-weight: 400;
.tags {
zoom: 1;
margin: 0;
padding: 0;
}
.tag-cloud{
margin-bottom: 11px;
margin-right: 3px;
display: inline-block;
.tags:before, .tags:after {
content: '';
display: table;
}
.tags:after {
clear: both;
}
.tags li {
position: relative;
float: left;
margin: 0 0 8px 12px;
list-style: none;
}
.bg-color-1{
background-color: #3c8dbc;
.tags li:active {
margin-top: 1px;
margin-bottom: 7px;
}
.bg-color-2{
background-color: #00a65a;
.tags li:after {
content: '';
z-index: 2;
position: absolute;
top: 10px;
right: -2px;
width: 5px;
height: 6px;
opacity: .95;
background: #eb6b22;
border-radius: 3px 0 0 3px;
-webkit-box-shadow: inset 1px 0 #99400e;
box-shadow: inset 1px 0 #99400e;
}
.bg-color-3{
background-color: #001f3f;
.tags a, .tags span {
display: block;
-webkit-box-sizing: border-box;
-moz-box-sizing: border-box;
box-sizing: border-box;
}
.bg-color-4{
background-color: #39cccc;
.tags a {
height: 26px;
line-height: 23px;
padding: 0 9px 0 8px;
font-size: 12px;
color: #555;
text-decoration: none;
text-shadow: 0 1px white;
background: #fafafa;
border-width: 1px 0 1px 1px;
border-style: solid;
border-color: #dadada #d2d2d2 #c5c5c5;
border-radius: 3px 0 0 3px;
background-image: -webkit-linear-gradient(top, #fcfcfc, #f0f0f0);
background-image: -moz-linear-gradient(top, #fcfcfc, #f0f0f0);
background-image: -o-linear-gradient(top, #fcfcfc, #f0f0f0);
background-image: linear-gradient(to bottom, #fcfcfc, #f0f0f0);
-webkit-box-shadow: inset 0 0 0 1px rgba(255, 255, 255, 0.7), 0 1px 2px rgba(0, 0, 0, 0.05);
box-shadow: inset 0 0 0 1px rgba(255, 255, 255, 0.7), 0 1px 2px rgba(0, 0, 0, 0.05);
}
.bg-color-5{
background-color: #3d9970;
.tags a:hover span {
padding: 0 7px 0 6px;
max-width: 40px;
-webkit-box-shadow: inset 0 0 0 1px rgba(255, 255, 255, 0.15), 1px 1px 2px rgba(0, 0, 0, 0.2);
box-shadow: inset 0 0 0 1px rgba(255, 255, 255, 0.15), 1px 1px 2px rgba(0, 0, 0, 0.2);
}
.bg-color-6{
background-color: #01ff70;
.tags span {
position: absolute;
top: 1px;
left: 100%;
z-index: 2;
overflow: hidden;
max-width: 0;
height: 24px;
line-height: 21px;
padding: 0 0 0 2px;
color: white;
text-shadow: 0 -1px rgba(0, 0, 0, 0.3);
background: #eb6b22;
border: 1px solid;
border-color: #d15813 #c85412 #bf5011;
border-radius: 0 2px 2px 0;
opacity: .95;
background-image: -webkit-linear-gradient(top, #ed7b39, #df5e14);
background-image: -moz-linear-gradient(top, #ed7b39, #df5e14);
background-image: -o-linear-gradient(top, #ed7b39, #df5e14);
background-image: linear-gradient(to bottom, #ed7b39, #df5e14);
-webkit-transition: 0.3s ease-out;
-moz-transition: 0.3s ease-out;
-o-transition: 0.3s ease-out;
transition: 0.3s ease-out;
-webkit-transition-property: padding, max-width;
-moz-transition-property: padding, max-width;
-o-transition-property: padding, max-width;
transition-property: padding, max-width;
}
.bg-color-7{
background-color: #ff851b;
.green li:after {
background: #65bb34;
-webkit-box-shadow: inset 1px 0 #3a6b1e;
box-shadow: inset 1px 0 #3a6b1e;
}
.bg-color-8{
background-color: #f012be;
.green span {
background: #65bb34;
border-color: #549b2b #4f9329 #4b8b27;
background-image: -webkit-linear-gradient(top, #71ca3f, #5aa72e);
background-image: -moz-linear-gradient(top, #71ca3f, #5aa72e);
background-image: -o-linear-gradient(top, #71ca3f, #5aa72e);
background-image: linear-gradient(to bottom, #71ca3f, #5aa72e);
}
.bg-color-9{
background-color: #605ca8;
.blue li:after {
background: #56a3d5;
-webkit-box-shadow: inset 1px 0 #276f9e;
box-shadow: inset 1px 0 #276f9e;
}
.bg-color-10{
background-color: #d81b60;
}
.bg-color-11{
background-color: #dd4b39;
}
.bg-color-12{
background-color: #f39c12;
}
.bg-color-13{
background-color: #00c0ef;
}
.bg-color-14{
background-color: #0073b7;
}
.bg-color-15{
background-color: #111111;
.blue span {
background: #56a3d5;
border-color: #3591cd #318cc7 #2f86be;
background-image: -webkit-linear-gradient(top, #6aaeda, #4298d0);
background-image: -moz-linear-gradient(top, #6aaeda, #4298d0);
background-image: -o-linear-gradient(top, #6aaeda, #4298d0);
background-image: linear-gradient(to bottom, #6aaeda, #4298d0);
}
</style>
<section class="content-header">
@ -106,7 +176,7 @@
<div class="box-footer">
<button type="submit" class="btn btn-primary btn-sm ">确定${statusName}</button>
<#if updateTag.posts?size = 0>
<button type="submit" class="btn btn-danger btn-sm pull-right">删除</button>
<a data-pjax="true" href="/admin/tag/remove?tagId=${updateTag.tagId}" class="btn btn-danger btn-sm pull-right">删除</a>
</#if>
</div>
</form>
@ -137,54 +207,16 @@
<h3 class="box-title">所有标签</h3>
</div>
<div class="box-body table-responsive">
<#--<table class="table table-hover">-->
<#--<thead>-->
<#--<tr>-->
<#--<th>名称</th>-->
<#--<th>路径</th>-->
<#--<th>总数</th>-->
<#--<th>操作</th>-->
<#--</tr>-->
<#--</thead>-->
<#--<tbody>-->
<#--<#list tags as tag>-->
<#--<tr>-->
<#--<td>${tag.tagName}</td>-->
<#--<td>${tag.tagUrl}</td>-->
<#--<td>2</td>-->
<#--<td>-->
<#--<#if updateTag ?? && tag.tagId==updateTag.tagId>-->
<#--<a class="btn btn-primary btn-xs " href="#" disabled>正在修改</a>-->
<#--<#else >-->
<#--<a data-pjax="true" class="btn btn-primary btn-xs " href="/admin/tag/edit?tagId=${tag.tagId}">修改</a>-->
<#--</#if>-->
<#--<button class="btn btn-danger btn-xs " onclick="modelShow('/admin/tag/remove?tagId=${tag.tagId}')">删除</button>-->
<#--</td>-->
<#--</tr>-->
<#--</#list>-->
<#--</tbody>-->
<#--</table>-->
<#list tags as tag>
<div class="tag-cloud">
<a class="tag-link" data-pjax="true" href="/admin/tag/edit?tagId=${tag.tagId}">
<span class="label">${tag.tagName}( ${tag.posts?size} )</span>
</a>
</div>
</#list>
<script>
var randomNum;
var tagLabel = $('.tag-link');
<#--for(var i = 0; i < ${tags?size}; i++) {-->
<#--randomNum = Math.floor(Math. random() * 15 + 1);-->
<#--tagLabel.children('.label').addClass("bg-color-"+randomNum);-->
<#--tagLabel = tagLabel.next();-->
<#--}-->
$(".label").each(function () {
randomNum = Math.floor(Math. random() * 15 + 1);
$(this).addClass("bg-color-"+randomNum);
});
</script>
<ul class="tags blue">
<#list tags as tag>
<li>
<a data-pjax="true" href="/admin/tag/edit?tagId=${tag.tagId}">
${tag.tagName}
<span>${tag.posts?size}</span>
</a>
</li>
</#list>
</ul>
</div>
</div>
</div>

View File

@ -7,10 +7,10 @@
<div class="content">
<div class="archive animated fadeInDown">
<ul class="list-with-title">
<#list archives as archive>
<div class="listing-title">${archive.year}.${archive.month}</div>
<#list archivesLess as archive>
<div class="listing-title">${archive.year}</div>
<ul class="listing">
<#list archive.posts as post>
<#list archive.posts?sort_by("postDate")?reverse as post>
<div class="listing-item">
<div class="listing-post">
<a href="/archives/${post.postUrl}" title="${post.postTitle}">${post.postTitle}</a>