Commit f465958d authored by Liang Ding's avatar Liang Ding

Merge pull request #325 from b3log/0.6.5

0.6.5
parents 5163832f 50a5336f
......@@ -5,6 +5,21 @@
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
</head>
<body>
<h2>Release 0.6.5 - Nov 1, 2013</h2>
<ul>
<li><a href="https://github.com/b3log/b3log-solo/issues/282">282 找回密码问题</a>&nbsp;<span style='background: #fc2929 !important;color:#FFFFFF !important;padding: 1px 4px;'>bug</span></li>
<li><a href="https://github.com/b3log/b3log-solo/issues/283">283 社区同步评论</a>&nbsp;<span style='background: #fc2929 !important;color:#FFFFFF !important;padding: 1px 4px;'>bug</span></li>
<li><a href="https://github.com/b3log/b3log-solo/issues/288">288 IoC 容器冲突</a>&nbsp;<span style='background: #fc2929 !important;color:#FFFFFF !important;padding: 1px 4px;'>bug</span></li>
<li><a href="https://github.com/b3log/b3log-solo/issues/294">294 发布文章时允许评论开关问题</a>&nbsp;<span style='background: #fc2929 !important;color:#FFFFFF !important;padding: 1px 4px;'>bug</span></li>
<li><a href="https://github.com/b3log/b3log-solo/issues/296">296 数据恢复接口被过滤器跳过</a>&nbsp;<span style='background: #fc2929 !important;color:#FFFFFF !important;padding: 1px 4px;'>bug</span></li>
<li><a href="https://github.com/b3log/b3log-solo/issues/302">302 更新已发布文章问题</a>&nbsp;<span style='background: #fc2929 !important;color:#FFFFFF !important;padding: 1px 4px;'>bug</span></li>
<li><a href="https://github.com/b3log/b3log-solo/issues/295">295 未初始化时启动日志报错</a>&nbsp;<span style='background: #84b6eb !important;color:#FFFFFF !important;padding: 1px 4px;'>enhancement</span></li>
<li><a href="https://github.com/b3log/b3log-solo/issues/299">299 评论信息填充优化</a>&nbsp;<span style='background: #84b6eb !important;color:#FFFFFF !important;padding: 1px 4px;'>enhancement</span></li>
<li><a href="https://github.com/b3log/b3log-solo/issues/316">316 评论开关页面显示</a>&nbsp;<span style='background: #84b6eb !important;color:#FFFFFF !important;padding: 1px 4px;'>enhancement</span></li>
<li><a href="https://github.com/b3log/b3log-solo/issues/317">317 自动保存文章时间间隔</a>&nbsp;<span style='background: #84b6eb !important;color:#FFFFFF !important;padding: 1px 4px;'>enhancement</span></li>
<li><a href="https://github.com/b3log/b3log-solo/issues/318">318 去缓存</a>&nbsp;<span style='background: #84b6eb !important;color:#FFFFFF !important;padding: 1px 4px;'>enhancement</span></li>
<li><a href="https://github.com/b3log/b3log-solo/issues/320">320 加入登录状态模版变量</a>&nbsp;<span style='background: #84b6eb !important;color:#FFFFFF !important;padding: 1px 4px;'>enhancement</span></li>
</ul>
<h2>Release 0.6.1 - Aug 25, 2013</h2>
<ul>
<li><a href="https://github.com/b3log/b3log-solo/issues/200">200 找回密码</a>&nbsp;<span style='background: #02e10c !important;color:#FFFFFF !important;padding: 1px 4px;'>feature</span></li>
......
<?xml version="1.0" encoding="UTF-8"?>
<!--
Description: B3log Solo core.
Version: 2.0.1.4, Aug 20, 2013
Version: 2.0.1.5, Oct 29, 2013
Author: Liang Ding
-->
<project xmlns="http://maven.apache.org/POM/4.0.0"
......@@ -17,7 +17,7 @@
<parent>
<groupId>org.b3log</groupId>
<artifactId>solo</artifactId>
<version>0.6.1</version>
<version>0.6.5</version>
</parent>
<dependencies>
......
......@@ -35,8 +35,6 @@ import org.b3log.latke.servlet.AbstractServletListener;
import org.b3log.latke.util.Requests;
import org.b3log.latke.util.Stopwatchs;
import org.b3log.latke.util.Strings;
import org.b3log.latke.util.freemarker.Templates;
import org.b3log.solo.event.cache.RemoveCacheListener;
import org.b3log.solo.event.comment.ArticleCommentReplyNotifier;
import org.b3log.solo.event.comment.PageCommentReplyNotifier;
import org.b3log.solo.event.ping.AddArticleGoogleBlogSearchPinger;
......@@ -59,7 +57,7 @@ import org.json.JSONObject;
* B3log Solo servlet listener.
*
* @author <a href="http://88250.b3log.org">Liang Ding</a>
* @version 1.1.0.1, Aug 20, 2013
* @version 1.1.0.2, Oct 27, 2013
* @since 0.3.1
*/
public final class SoloServletListener extends AbstractServletListener {
......@@ -67,7 +65,7 @@ public final class SoloServletListener extends AbstractServletListener {
/**
* B3log Solo version.
*/
public static final String VERSION = "0.6.1";
public static final String VERSION = "0.6.5";
/**
* Logger.
......@@ -121,8 +119,6 @@ public final class SoloServletListener extends AbstractServletListener {
final Transaction transaction = preferenceRepository.beginTransaction();
// Cache will be cleared manaully if necessary, see loadPreference.
transaction.clearQueryCache(false);
try {
loadPreference();
......@@ -137,7 +133,9 @@ public final class SoloServletListener extends AbstractServletListener {
registerEventProcessor();
PluginManager.getInstance().load();
final PluginManager pluginManager = beanManager.getReference(PluginManager.class);
pluginManager.load();
LOGGER.info("Initialized the context");
......@@ -162,6 +160,9 @@ public final class SoloServletListener extends AbstractServletListener {
@Override
public void requestInitialized(final ServletRequestEvent servletRequestEvent) {
final HttpServletRequest httpServletRequest = (HttpServletRequest) servletRequestEvent.getServletRequest();
Requests.log(httpServletRequest, Level.DEBUG, LOGGER);
final String requestURI = httpServletRequest.getRequestURI();
Stopwatchs.start("Request Initialized[requestURI=" + requestURI + "]");
......@@ -199,12 +200,6 @@ public final class SoloServletListener extends AbstractServletListener {
*
* <p>
* Loads preference from repository, loads skins from skin directory then sets it into preference if the skins changed.
* Puts preference into cache and persists it to repository finally.
* </p>
*
* <p>
* <b>Note</b>: Do NOT use method {@link org.b3log.solo.service.PreferenceQueryService#getPreference() } to load it, caused by the
* method may retrieve it from cache.
* </p>
*/
private void loadPreference() {
......@@ -225,10 +220,6 @@ public final class SoloServletListener extends AbstractServletListener {
final PreferenceMgmtService preferenceMgmtService = beanManager.getReference(PreferenceMgmtService.class);
preferenceMgmtService.loadSkins(preference);
final boolean pageCacheEnabled = preference.getBoolean(Preference.PAGE_CACHE_ENABLED);
Templates.enableCache(pageCacheEnabled);
} catch (final Exception e) {
LOGGER.log(Level.ERROR, e.getMessage(), e);
......@@ -246,7 +237,7 @@ public final class SoloServletListener extends AbstractServletListener {
LOGGER.log(Level.INFO, "Registering event processors....");
try {
final EventManager eventManager = EventManager.getInstance();
final EventManager eventManager = beanManager.getReference(EventManager.class);
// Comment
eventManager.registerListener(new ArticleCommentReplyNotifier());
......@@ -261,8 +252,6 @@ public final class SoloServletListener extends AbstractServletListener {
eventManager.registerListener(new ArticleSender());
eventManager.registerListener(new ArticleUpdater());
eventManager.registerListener(new CommentSender());
// Cache
eventManager.registerListener(new RemoveCacheListener());
} catch (final Exception e) {
LOGGER.log(Level.ERROR, "Register event processors error", e);
throw new IllegalStateException(e);
......
......@@ -51,7 +51,6 @@ import org.b3log.solo.service.PreferenceQueryService;
import org.b3log.solo.service.StatisticMgmtService;
import org.b3log.solo.util.Comments;
import org.b3log.solo.util.QueryResults;
import org.b3log.solo.util.TimeZones;
import org.json.JSONObject;
......@@ -59,7 +58,7 @@ import org.json.JSONObject;
* Comment receiver (from B3log Symphony).
*
* @author <a href="http://88250.b3log.org">Liang Ding</a>
* @version 1.0.0.7, Jul 10, 2013
* @version 1.0.0.8, Aug 29, 2013
* @since 0.5.5
*/
@RequestProcessor
......@@ -79,6 +78,7 @@ public class CommentReceiver {
/**
* Comment repository.
*/
@Inject
private static CommentRepository commentRepository;
/**
......@@ -112,7 +112,8 @@ public class CommentReceiver {
/**
* Event manager.
*/
private static EventManager eventManager = EventManager.getInstance();
@Inject
private static EventManager eventManager;
/**
* Statistic management service.
......@@ -218,8 +219,7 @@ public class CommentReceiver {
comment.put(Comment.COMMENT_EMAIL, commentEmail);
comment.put(Comment.COMMENT_URL, commentURL);
comment.put(Comment.COMMENT_CONTENT, commentContent);
final String timeZoneId = preference.getString(Preference.TIME_ZONE_ID);
final Date date = TimeZones.getTime(timeZoneId);
final Date date = new Date();
comment.put(Comment.COMMENT_DATE, date);
ret.put(Comment.COMMENT_DATE, DateFormatUtils.format(date, "yyyy-MM-dd hh:mm:ss"));
......
/*
* Copyright (c) 2009, 2010, 2011, 2012, 2013, B3log Team
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.b3log.solo.event.cache;
import org.b3log.latke.cache.PageCaches;
import org.b3log.latke.event.AbstractEventListener;
import org.b3log.latke.event.Event;
import org.b3log.latke.event.EventException;
import org.b3log.latke.ioc.LatkeBeanManager;
import org.b3log.latke.ioc.Lifecycle;
import org.b3log.latke.logging.Level;
import org.b3log.latke.logging.Logger;
import org.b3log.latke.service.ServiceException;
import org.b3log.solo.service.StatisticMgmtService;
/**
* This listener is responsible for handling remove cache event.
*
* <p>
* Flush the statistic to repository.
* </p>
*
* @author <a href="http://88250.b3log.org">Liang Ding</a>
* @version 1.0.0.1, Nov 28, 2011
* @since 0.3.1
*/
public final class RemoveCacheListener extends AbstractEventListener<Void> {
/**
* Logger.
*/
private static final Logger LOGGER = Logger.getLogger(RemoveCacheListener.class.getName());
@Override
public void action(final Event<Void> event) throws EventException {
LOGGER.log(Level.DEBUG, "Processing an event[type={0} in listener[className={2}]",
new Object[] {event.getType(), RemoveCacheListener.class.getName()});
final LatkeBeanManager beanManager = Lifecycle.getBeanManager();
final StatisticMgmtService statisticMgmtService = beanManager.getReference(StatisticMgmtService.class);
try {
statisticMgmtService.flushStatistic();
} catch (final ServiceException e) {
LOGGER.log(Level.ERROR, "Flushes statistic to repository failed", e);
}
}
/**
* Gets the event type {@linkplain PageCaches#REMOVE_CACHE}.
*
* @return event type
*/
@Override
public String getEventType() {
return PageCaches.REMOVE_CACHE;
}
}
......@@ -58,7 +58,6 @@ public final class PluginRefresher extends AbstractEventListener<List<AbstractPl
final Transaction transaction = pluginRepository.beginTransaction();
transaction.clearQueryCache(false);
try {
final PluginMgmtService pluginMgmtService = beanManager.getReference(PluginMgmtService.class);
......
......@@ -103,11 +103,11 @@ public final class ArticleSender extends AbstractEventListener<JSONObject> {
throw new EventException("Not found preference");
}
if (Latkes.getServePath().contains("localhost")) {
LOGGER.log(Level.INFO, "Blog Solo runs on local server, so should not send this article[id={0}, title={1}] to Rhythm",
new Object[] {originalArticle.getString(Keys.OBJECT_ID), originalArticle.getString(Article.ARTICLE_TITLE)});
return;
}
// if (Latkes.getServePath().contains("localhost")) {
// LOGGER.log(Level.INFO, "Blog Solo runs on local server, so should not send this article[id={0}, title={1}] to Rhythm",
// new Object[] {originalArticle.getString(Keys.OBJECT_ID), originalArticle.getString(Article.ARTICLE_TITLE)});
// return;
// }
final HTTPRequest httpRequest = new HTTPRequest();
......
......@@ -102,11 +102,11 @@ public final class ArticleUpdater extends AbstractEventListener<JSONObject> {
throw new EventException("Not found preference");
}
if (Latkes.getServePath().contains("localhost")) {
LOGGER.log(Level.INFO, "Blog Solo runs on local server, so should not send this article[id={0}, title={1}] to Rhythm",
new Object[] {originalArticle.getString(Keys.OBJECT_ID), originalArticle.getString(Article.ARTICLE_TITLE)});
return;
}
// if (Latkes.getServePath().contains("localhost")) {
// LOGGER.log(Level.INFO, "Blog Solo runs on local server, so should not send this article[id={0}, title={1}] to Rhythm",
// new Object[] {originalArticle.getString(Keys.OBJECT_ID), originalArticle.getString(Article.ARTICLE_TITLE)});
// return;
// }
final HTTPRequest httpRequest = new HTTPRequest();
......
......@@ -31,20 +31,19 @@ import org.b3log.latke.ioc.LatkeBeanManager;
import org.b3log.latke.ioc.Lifecycle;
import org.b3log.latke.logging.Level;
import org.b3log.latke.logging.Logger;
import org.b3log.latke.service.ServiceException;
import org.b3log.latke.servlet.DispatcherServlet;
import org.b3log.latke.servlet.HTTPRequestContext;
import org.b3log.latke.servlet.HTTPRequestDispatcher;
import org.b3log.latke.servlet.HTTPRequestMethod;
import org.b3log.latke.servlet.HttpControl;
import org.b3log.latke.servlet.renderer.HTTP500Renderer;
import org.b3log.solo.service.InitService;
import org.b3log.solo.service.PreferenceQueryService;
import org.json.JSONObject;
/**
* Checks initialization filter.
*
* @author <a href="http://88250.b3log.org">Liang Ding</a>
* @version 1.0.1.0, Jun 28, 2013
* @version 1.0.1.1, Sep 10, 2013
* @since 0.3.1
*/
public final class InitCheckFilter implements Filter {
......@@ -74,8 +73,8 @@ public final class InitCheckFilter implements Filter {
LOGGER.log(Level.TRACE, "Request[URI={0}]", requestURI);
if (requestURI.startsWith("/latke/remote")) {
// If requests Latke Remote APIs, skips this filter
if (requestURI.startsWith(Latkes.getContextPath() + "/latke/remote")) {
chain.doFilter(request, response);
return;
......@@ -84,7 +83,6 @@ public final class InitCheckFilter implements Filter {
final LatkeBeanManager beanManager = Lifecycle.getBeanManager();
final InitService initService = beanManager.getReference(InitService.class);
try {
if (initService.isInited()) {
chain.doFilter(request, response);
......@@ -98,13 +96,7 @@ public final class InitCheckFilter implements Filter {
return;
}
final PreferenceQueryService preferenceQueryService = beanManager.getReference(PreferenceQueryService.class);
LOGGER.debug("Try to get preference to confirm whether the preference exixts");
final JSONObject preference = preferenceQueryService.getPreference();
if (null == preference) {
LOGGER.log(Level.WARN, "B3log Solo has not been initialized, so redirects to /init");
LOGGER.log(Level.INFO, "B3log Solo has not been initialized, so redirects to /init");
final HTTPRequestContext context = new HTTPRequestContext();
......@@ -114,14 +106,15 @@ public final class InitCheckFilter implements Filter {
request.setAttribute(Keys.HttpRequest.REQUEST_URI, Latkes.getContextPath() + "/init");
request.setAttribute(Keys.HttpRequest.REQUEST_METHOD, HTTPRequestMethod.GET.name());
HTTPRequestDispatcher.dispatch(context);
} else {
// XXX: Wrong state of SoloServletListener.isInited()
chain.doFilter(request, response);
}
} catch (final ServiceException e) {
((HttpServletResponse) response).sendError(HttpServletResponse.SC_NOT_FOUND);
final HttpControl httpControl = new HttpControl(DispatcherServlet.SYS_HANDLER.iterator(), context);
try {
httpControl.nextHandler();
} catch (final Exception e) {
context.setRenderer(new HTTP500Renderer(e));
}
DispatcherServlet.result(context);
}
@Override
......
/*
* Copyright (c) 2009, 2010, 2011, 2012, 2013, B3log Team
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.b3log.solo.filter;
import java.io.IOException;
import java.io.PrintWriter;
import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.apache.commons.lang.time.DateFormatUtils;
import org.b3log.latke.Keys;
import org.b3log.latke.Latkes;
import org.b3log.latke.cache.PageCaches;
import org.b3log.latke.ioc.LatkeBeanManager;
import org.b3log.latke.ioc.Lifecycle;
import org.b3log.latke.logging.Level;
import org.b3log.latke.logging.Logger;
import org.b3log.latke.repository.RepositoryException;
import org.b3log.latke.service.LangPropsService;
import org.b3log.latke.service.LangPropsServiceImpl;
import org.b3log.latke.service.ServiceException;
import org.b3log.latke.util.StaticResources;
import org.b3log.latke.util.Strings;
import org.b3log.solo.model.Article;
import org.b3log.solo.model.Common;
import org.b3log.solo.model.PageTypes;
import org.b3log.solo.processor.util.TopBars;
import org.b3log.solo.repository.ArticleRepository;
import org.b3log.solo.repository.impl.ArticleRepositoryImpl;
import org.b3log.solo.service.ArticleQueryService;
import org.b3log.solo.service.StatisticMgmtService;
import org.json.JSONException;
import org.json.JSONObject;
/**
* Page cache filter.
*
* @author <a href="http://88250.b3log.org">Liang Ding</a>
* @version 1.0.1.1, Jan 8, 2013
* @since 0.3.1
*/
public final class PageCacheFilter implements Filter {
/**
* Logger.
*/
private static final Logger LOGGER = Logger.getLogger(PageCacheFilter.class.getName());
@Override
public void init(final FilterConfig filterConfig) throws ServletException {}
/**
* Try to write response from cache.
*
* @param request the specified request
* @param response the specified response
* @param chain filter chain
* @throws IOException io exception
* @throws ServletException servlet exception
*/
@Override
public void doFilter(final ServletRequest request, final ServletResponse response, final FilterChain chain)
throws IOException, ServletException {
final long startTimeMillis = System.currentTimeMillis();
request.setAttribute(Keys.HttpRequest.START_TIME_MILLIS, startTimeMillis);
final HttpServletRequest httpServletRequest = (HttpServletRequest) request;
final String requestURI = httpServletRequest.getRequestURI();
LOGGER.log(Level.DEBUG, "Request URI[{0}]", requestURI);
if (StaticResources.isStatic(httpServletRequest)) {
final String path = httpServletRequest.getServletPath() + httpServletRequest.getPathInfo();
LOGGER.log(Level.TRACE, "Requests a static resource, forwards to servlet[path={0}]", path);
request.getRequestDispatcher(path).forward(request, response);
return;
}
if (!Latkes.isPageCacheEnabled()) {
LOGGER.log(Level.TRACE, "Page cache is disabled");
chain.doFilter(request, response);
return;
}
final String skinDirName = (String) httpServletRequest.getAttribute(Keys.TEMAPLTE_DIR_NAME);
if ("mobile".equals(skinDirName)) {
// Mobile request, bypasses page caching
chain.doFilter(request, response);
return;
}
String pageCacheKey;
final String queryString = httpServletRequest.getQueryString();
pageCacheKey = (String) request.getAttribute(Keys.PAGE_CACHE_KEY);
if (Strings.isEmptyOrNull(pageCacheKey)) {
pageCacheKey = PageCaches.getPageCacheKey(requestURI, queryString);
request.setAttribute(Keys.PAGE_CACHE_KEY, pageCacheKey);
}
final JSONObject cachedPageContentObject = PageCaches.get(pageCacheKey, httpServletRequest, (HttpServletResponse) response);
if (null == cachedPageContentObject) {
LOGGER.log(Level.DEBUG, "Page cache miss for request URI[{0}]", requestURI);
chain.doFilter(request, response);
return;
}
final String cachedType = cachedPageContentObject.optString(PageCaches.CACHED_TYPE);
final LatkeBeanManager beanManager = Lifecycle.getBeanManager();
final ArticleQueryService articleQueryService = beanManager.getReference(ArticleQueryService.class);
final LangPropsService langPropsService = beanManager.getReference(LangPropsServiceImpl.class);
try {
// If cached an article that has view password, dispatches the password form
if (langPropsService.get(PageTypes.ARTICLE.getLangeLabel()).equals(cachedType)
&& cachedPageContentObject.has(PageCaches.CACHED_PWD)) {
JSONObject article = new JSONObject();
final String articleId = cachedPageContentObject.optString(PageCaches.CACHED_OID);
article.put(Keys.OBJECT_ID, articleId);
article.put(Article.ARTICLE_VIEW_PWD, cachedPageContentObject.optString(PageCaches.CACHED_PWD));
if (articleQueryService.needViewPwd(httpServletRequest, article)) {
final ArticleRepository articleRepository = beanManager.getReference(ArticleRepositoryImpl.class);
article = articleRepository.get(articleId); // Loads the article entity
final HttpServletResponse httpServletResponse = (HttpServletResponse) response;
try {
httpServletResponse.sendRedirect(
Latkes.getServePath() + "/console/article-pwd?articleId=" + article.optString(Keys.OBJECT_ID));
return;
} catch (final Exception e) {
httpServletResponse.sendError(HttpServletResponse.SC_NOT_FOUND);
return;
}
}
}
} catch (final Exception e) {
LOGGER.log(Level.ERROR, e.getMessage(), e);
chain.doFilter(request, response);
}
try {
LOGGER.log(Level.TRACE, "Writes resposne for page[pageCacheKey={0}] from cache", pageCacheKey);
response.setContentType("text/html");
response.setCharacterEncoding("UTF-8");
final PrintWriter writer = response.getWriter();
String cachedPageContent = cachedPageContentObject.getString(PageCaches.CACHED_CONTENT);
final TopBars topbars = beanManager.getReference(TopBars.class);
final String topBarHTML = topbars.getTopBarHTML((HttpServletRequest) request, (HttpServletResponse) response);
cachedPageContent = cachedPageContent.replace(Common.TOP_BAR_REPLACEMENT_FLAG, topBarHTML);
final String cachedTitle = cachedPageContentObject.getString(PageCaches.CACHED_TITLE);
LOGGER.log(Level.TRACE, "Cached value[key={0}, type={1}, title={2}]", new Object[] {pageCacheKey, cachedType, cachedTitle});
final StatisticMgmtService statisticMgmtService = beanManager.getReference(StatisticMgmtService.class);
statisticMgmtService.incBlogViewCount((HttpServletRequest) request, (HttpServletResponse) response);
final long endimeMillis = System.currentTimeMillis();
final String dateString = DateFormatUtils.format(endimeMillis, "yyyy/MM/dd HH:mm:ss");
final String msg = String.format("<!-- Cached by B3log Solo(%1$d ms), %2$s -->", endimeMillis - startTimeMillis, dateString);
LOGGER.debug(msg);
cachedPageContent += Strings.LINE_SEPARATOR + msg;
writer.write(cachedPageContent);
writer.flush();
writer.close();
} catch (final JSONException e) {
LOGGER.log(Level.ERROR, e.getMessage(), e);
chain.doFilter(request, response);
} catch (final RepositoryException e) {
LOGGER.log(Level.ERROR, e.getMessage(), e);
chain.doFilter(request, response);
} catch (final ServiceException e) {
LOGGER.log(Level.ERROR, e.getMessage(), e);
chain.doFilter(request, response);
}
}
@Override
public void destroy() {}
}
......@@ -33,9 +33,11 @@ import org.b3log.latke.ioc.Lifecycle;
import org.b3log.latke.logging.Level;
import org.b3log.latke.logging.Logger;
import org.b3log.latke.repository.RepositoryException;
import org.b3log.latke.servlet.DispatcherServlet;
import org.b3log.latke.servlet.HTTPRequestContext;
import org.b3log.latke.servlet.HTTPRequestDispatcher;
import org.b3log.latke.servlet.HTTPRequestMethod;
import org.b3log.latke.servlet.HttpControl;
import org.b3log.latke.servlet.renderer.HTTP500Renderer;
import org.b3log.solo.model.Article;
import org.b3log.solo.model.Page;
import org.b3log.solo.repository.ArticleRepository;
......@@ -102,7 +104,6 @@ public final class PermalinkFilter implements Filter {
final LatkeBeanManager beanManager = Lifecycle.getBeanManager();
try {
final ArticleRepository articleRepository = beanManager.getReference(ArticleRepositoryImpl.class);
article = articleRepository.getByPermalink(permalink);
......@@ -173,7 +174,15 @@ public final class PermalinkFilter implements Filter {
request.setAttribute(Keys.HttpRequest.REQUEST_METHOD, HTTPRequestMethod.GET.name());
HTTPRequestDispatcher.dispatch(context);
final HttpControl httpControl = new HttpControl(DispatcherServlet.SYS_HANDLER.iterator(), context);
try {
httpControl.nextHandler();
} catch (final Exception e) {
context.setRenderer(new HTTP500Renderer(e));
}
DispatcherServlet.result(context);
}
@Override
......
/*
* Copyright (c) 2009, 2010, 2011, 2012, 2013, B3log Team
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.b3log.solo.model;
/**
* This class defines all cache model relevant keys.
*
* @author <a href="http://88250.b3log.org">Liang Ding</a>
* @version 1.0.0.2, Dec 27, 2010
*/
public final class Cache {
/**
* Cache.
*/
public static final String CACHE = "cache";
/**
* Cached count.
*/
public static final String CACHE_CACHED_COUNT = "cacheCachedCount";
/**
* Cache hit count.
*/
public static final String CACHE_HIT_COUNT = "cacheHitCount";
/**
* Cache hit bytes.
*/
public static final String CACHE_HIT_BYTES = "cacheHitBytes";
/**
* Cached bytes.
*/
public static final String CACHE_CACHED_BYTES = "cacheCachedBytes";
/**
* Cache miss count.
*/
public static final String CACHE_MISS_COUNT = "cacheMissCount";
/**
* Private default constructor.
*/
private Cache() {}
}
......@@ -221,11 +221,6 @@ public final class Common {
*/
public static final String POST_TO_COMMUNITY = "postToCommunity";
/**
* Key of page cached count.
*/
public static final String PAGE_CACHED_CNT = "pageCachedCnt";
/**
* Key of mini postfix.
*/
......@@ -269,12 +264,7 @@ public final class Common {
/**
* Key of top bar replacement flag.
*/
public static final String TOP_BAR_REPLACEMENT_FLAG_KEY = "topBarReplacement";
/**
* Top bar replacement flag.
*/
public static final String TOP_BAR_REPLACEMENT_FLAG = "#B3logSolo#topBarReplacement#B3logSolo#";
public static final String TOP_BAR = "topBarReplacement";
/**
* Key of unused tags.
......
......@@ -17,8 +17,6 @@ package org.b3log.solo.model;
import org.b3log.latke.Keys;
import org.b3log.latke.Latkes;
import org.b3log.latke.RuntimeEnv;
import org.b3log.latke.logging.Level;
import org.b3log.latke.logging.Logger;
import org.json.JSONArray;
......@@ -149,11 +147,6 @@ public final class Preference {
*/
public static final String KEY_OF_SOLO = "keyOfSolo";
/**
* Key of page cache enabled.
*/
public static final String PAGE_CACHE_ENABLED = "pageCacheEnabled";
/**
* Key of allow visit draft via permalink.
*/
......@@ -345,11 +338,6 @@ public final class Preference {
*/
public static final String DEFAULT_SIGNS;
/**
* Default page cache enabled.
*/
public static final boolean DEFAULT_PAGE_CACHE_ENABLED;
/**
* Default allow visit draft via permalink.
*/
......@@ -422,12 +410,6 @@ public final class Preference {
"Your comment on post[<a href='${postLink}'>" + "${postTitle}</a>] received an reply: <p>${replier}"
+ ": <span><a href='${replyURL}'>${replyContent}</a></span></p>");
DEFAULT_REPLY_NOTIFICATION_TEMPLATE = replyNotificationTemplate.toString();
if (RuntimeEnv.BAE == Latkes.getRuntimeEnv()) {
DEFAULT_PAGE_CACHE_ENABLED = false; // https://github.com/b3log/b3log-solo/issues/73
} else {
DEFAULT_PAGE_CACHE_ENABLED = true;
}
} catch (final Exception e) {
LOGGER.log(Level.ERROR, "Creates sign error!", e);
throw new IllegalStateException(e);
......
/*
* Copyright (c) 2009, 2010, 2011, 2012, 2013, B3log Team
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.b3log.solo.plugin.cache;
import org.b3log.solo.model.Common;
import java.util.ArrayList;
import java.util.List;
import javax.inject.Inject;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.b3log.latke.Keys;
import org.b3log.latke.Latkes;
import org.b3log.latke.model.Pagination;
import org.b3log.solo.model.Page;
import org.b3log.latke.cache.PageCaches;
import org.b3log.latke.logging.Level;
import org.b3log.latke.logging.Logger;
import org.b3log.latke.servlet.HTTPRequestContext;
import org.b3log.latke.servlet.HTTPRequestMethod;
import org.b3log.latke.servlet.annotation.RequestProcessing;
import org.b3log.latke.servlet.annotation.RequestProcessor;
import org.b3log.latke.servlet.renderer.JSONRenderer;
import org.b3log.solo.model.Preference;
import org.b3log.latke.util.Paginator;
import org.b3log.latke.util.Requests;
import org.b3log.solo.service.PreferenceMgmtService;
import org.b3log.solo.service.PreferenceQueryService;
import org.b3log.solo.service.UserQueryService;
import org.b3log.solo.util.QueryResults;
import org.json.JSONObject;
/**
* Admin cache service.
*
* @author <a href="http://88250.b3log.org">Liang Ding</a>
* @version 1.0.0.7, May 16, 2012
* @since 0.3.1
*/
@RequestProcessor
public class AdminCacheService {
/**
* Logger.
*/
private static final Logger LOGGER = Logger.getLogger(AdminCacheService.class.getName());
/**
* User query service.
*/
@Inject
private UserQueryService userQueryService;
/**
* Preference query service.
*/
@Inject
private PreferenceQueryService preferenceQueryService;
/**
* Preference management service.
*/
@Inject
private PreferenceMgmtService preferenceMgmtService;
/**
* Gets page cache status with the specified http servlet request and http
* servlet response.
*
* <p>
* Renders the response with a json object, for example,
* <pre>
* {
* "pageCacheEnabled": boolean,
* "pageCachedCnt": int
* }
* </pre>
* </p>
*
* @param context the specified http request context
* @param request the specified http servlet request
* @param response the specified http servlet response
* @throws Exception
*/
@RequestProcessing(value = "/console/plugins/admin-cache/status/", method = HTTPRequestMethod.GET)
public void getPageCache(final HTTPRequestContext context, final HttpServletRequest request, final HttpServletResponse response)
throws Exception {
if (!userQueryService.isAdminLoggedIn(request)) {
response.sendError(HttpServletResponse.SC_FORBIDDEN);
return;
}
final JSONRenderer renderer = new JSONRenderer();
context.setRenderer(renderer);
final JSONObject ret = new JSONObject();
renderer.setJSONObject(ret);
LOGGER.log(Level.INFO, "Cache status[cachedBytes={0}, cachedCount={1}]",
new Object[] {PageCaches.getCache().getCachedBytes(), PageCaches.getCache().getCachedCount()});
try {
final JSONObject preference = preferenceQueryService.getPreference();
final boolean pageCacheEnabled = preference.getBoolean(Preference.PAGE_CACHE_ENABLED);
ret.put(Preference.PAGE_CACHE_ENABLED, pageCacheEnabled);
ret.put(Common.PAGE_CACHED_CNT, PageCaches.getKeys().size());
ret.put(Keys.STATUS_CODE, true);
} catch (final Exception e) {
LOGGER.log(Level.ERROR, e.getMessage(), e);
final JSONObject jsonObject = QueryResults.defaultResult();
renderer.setJSONObject(jsonObject);
jsonObject.put(Keys.MSG, "Admin Cache plugin exception: " + e.getMessage());
}
}
/**
* Gets page cache list by the specified request json object.
*
* <p>
* The request URI contains the pagination arguments. For example, the
* request URI is /console/admin-cache/pages/1/10/20, means the
* current page is 1, the page size is 10, and the window size is 20.
* </p>
*
* <p>
* Renders the response with a json object, for example,
* <pre>
* {
* "sc": boolean,
* "pagination": {
* "paginationPageCount": 100,
* "paginationPageNums": [1, 2, 3, 4, 5]
* },
* "pages": [{
* "link": "",
* "cachedType": "",
* "cachedTitle": "",
* }, ....]
* }
* </pre>
* </p>
*
* @param request the specified http servlet request
* @param response the specified http servlet response
* @param context the specified http request context
* @throws Exception exception
*/
@RequestProcessing(value = "/console/plugins/admin-cache/pages/*/*/*"/* Requests.PAGINATION_PATH_PATTERN */,
method = HTTPRequestMethod.GET)
public void getPages(final HttpServletRequest request, final HttpServletResponse response, final HTTPRequestContext context)
throws Exception {
if (!userQueryService.isLoggedIn(request, response)) {
response.sendError(HttpServletResponse.SC_FORBIDDEN);
return;
}
final JSONRenderer renderer = new JSONRenderer();
context.setRenderer(renderer);
final JSONObject ret = new JSONObject();
renderer.setJSONObject(ret);
try {
final String requestURI = request.getRequestURI();
final String path = requestURI.substring("/console/plugins/admin-cache/pages/".length());
final JSONObject requestJSONObject = Requests.buildPaginationRequest(path);
final int currentPageNum = requestJSONObject.getInt(Pagination.PAGINATION_CURRENT_PAGE_NUM);
final int pageSize = requestJSONObject.getInt(Pagination.PAGINATION_PAGE_SIZE);
final int windowSize = requestJSONObject.getInt(Pagination.PAGINATION_WINDOW_SIZE);
List<String> keys = new ArrayList<String>(PageCaches.getKeys());
// Paginates
final int pageCount = (int) Math.ceil((double) keys.size() / (double) pageSize);
final JSONObject pagination = new JSONObject();
ret.put(Pagination.PAGINATION, pagination);
final List<Integer> pageNums = Paginator.paginate(currentPageNum, pageSize, pageCount, windowSize);
pagination.put(Pagination.PAGINATION_PAGE_COUNT, pageCount);
pagination.put(Pagination.PAGINATION_PAGE_NUMS, pageNums);
final int start = pageSize * (currentPageNum - 1);
int end = start + pageSize;
end = end > keys.size() ? keys.size() : end;
keys = keys.subList(start, end);
// Retrives cached pages
final List<JSONObject> pages = new ArrayList<JSONObject>();
for (final String key : keys) {
LOGGER.log(Level.DEBUG, "Cached page[key={0}]", key);
JSONObject cachedPage = PageCaches.get(key);
if (null != cachedPage) {
// Do a copy for properties removing and retrieving
cachedPage = new JSONObject(cachedPage, JSONObject.getNames(cachedPage));
cachedPage.remove(PageCaches.CACHED_CONTENT);
pages.add(cachedPage);
}
}
ret.put(Page.PAGES, pages);
ret.put(Keys.STATUS_CODE, true);
} catch (final Exception e) {
LOGGER.log(Level.ERROR, e.getMessage(), e);
final JSONObject jsonObject = QueryResults.defaultResult();
renderer.setJSONObject(jsonObject);
jsonObject.put(Keys.MSG, "Admin Cache plugin exception: " + e.getMessage());
}
}
/**
* Sets page cache states.
*
* <p>
* Renders the response with a json object, for example,
* <pre>
* {
* "sc": boolean,
* "msg": ""
* }
* </pre>
* </p>
*
* @param request the specified http servlet request
* @param response the specified http servlet response
* @param context the specified http request context
* @throws Exception exception
*/
@RequestProcessing(value = "/console/plugins/admin-cache/enable/*", method = HTTPRequestMethod.PUT)
public void setPageCache(final HttpServletRequest request, final HttpServletResponse response, final HTTPRequestContext context)
throws Exception {
if (!userQueryService.isAdminLoggedIn(request)) {
response.sendError(HttpServletResponse.SC_FORBIDDEN);
return;
}
final JSONRenderer renderer = new JSONRenderer();
context.setRenderer(renderer);
final JSONObject ret = new JSONObject();
renderer.setJSONObject(ret);
try {
final String path = request.getRequestURI().substring(
(Latkes.getContextPath() + "/console/plugins/admin-cache/enable/").length());
final boolean pageCacheEnabled = "true".equals(path) ? true : false;
final JSONObject preference = preferenceQueryService.getPreference();
preference.put(Preference.PAGE_CACHE_ENABLED, pageCacheEnabled);
preferenceMgmtService.updatePreference(preference);
ret.put(Keys.STATUS_CODE, true);
} catch (final Exception e) {
LOGGER.log(Level.ERROR, "Sets page cache error: {0}", e.getMessage());
final JSONObject jsonObject = QueryResults.defaultResult();
renderer.setJSONObject(jsonObject);
jsonObject.put(Keys.MSG, "Admin Cache plugin exception: " + e.getMessage());
}
}
}
......@@ -28,7 +28,6 @@ import org.apache.commons.lang.StringUtils;
import org.apache.commons.lang.time.DateFormatUtils;
import org.b3log.latke.Keys;
import org.b3log.latke.Latkes;
import org.b3log.latke.cache.PageCaches;
import org.b3log.latke.logging.Level;
import org.b3log.latke.logging.Logger;
import org.b3log.latke.model.Pagination;
......@@ -43,6 +42,7 @@ import org.b3log.latke.servlet.annotation.RequestProcessor;
import org.b3log.latke.servlet.renderer.JSONRenderer;
import org.b3log.latke.servlet.renderer.TextHTMLRenderer;
import org.b3log.latke.servlet.renderer.freemarker.AbstractFreeMarkerRenderer;
import org.b3log.latke.servlet.renderer.freemarker.FreeMarkerRenderer;
import org.b3log.latke.util.Dates;
import org.b3log.latke.util.Locales;
import org.b3log.latke.util.Paginator;
......@@ -52,7 +52,6 @@ import org.b3log.latke.util.Strings;
import org.b3log.solo.SoloServletListener;
import org.b3log.solo.model.*;
import org.b3log.solo.processor.renderer.ConsoleRenderer;
import org.b3log.solo.processor.renderer.FrontRenderer;
import org.b3log.solo.processor.util.Filler;
import org.b3log.solo.service.*;
import org.b3log.solo.util.Skins;
......@@ -67,7 +66,7 @@ import org.jsoup.Jsoup;
* Article processor.
*
* @author <a href="http://88250.b3log.org">Liang Ding</a>
* @version 1.1.2.11, Jul 11, 2013
* @version 1.1.2.13, Oct 26, 2013
* @since 0.3.1
*/
@RequestProcessor
......@@ -647,7 +646,7 @@ public class ArticleProcessor {
@RequestProcessing(value = "/authors/**", method = HTTPRequestMethod.GET)
public void showAuthorArticles(final HTTPRequestContext context, final HttpServletRequest request, final HttpServletResponse response)
throws IOException, JSONException {
final AbstractFreeMarkerRenderer renderer = new FrontRenderer();
final AbstractFreeMarkerRenderer renderer = new FreeMarkerRenderer();
context.setRenderer(renderer);
......@@ -693,16 +692,6 @@ public class ArticleProcessor {
}
final JSONObject author = result.getJSONObject(User.USER);
final Map<String, String> langs = langPropsService.getAll(Latkes.getLocale());
request.setAttribute(PageCaches.CACHED_TYPE, langs.get(PageTypes.AUTHOR_ARTICLES.getLangeLabel()));
request.setAttribute(PageCaches.CACHED_OID, "No id");
request.setAttribute(PageCaches.CACHED_TITLE,
langs.get(PageTypes.AUTHOR_ARTICLES.getLangeLabel()) + " [" + langs.get("pageNumLabel") + "=" + currentPageNum + ", "
+ langs.get("authorLabel") + "=" + author.getString(User.USER_NAME) + "]");
request.setAttribute(PageCaches.CACHED_LINK, requestURI);
final String authorEmail = author.getString(User.USER_EMAIL);
final List<JSONObject> articles = articleQueryService.getArticlesByAuthorEmail(authorEmail, currentPageNum, pageSize);
......@@ -731,8 +720,7 @@ public class ArticleProcessor {
final Map<String, Object> dataModel = renderer.getDataModel();
prepareShowAuthorArticles(pageNums, dataModel, pageCount, currentPageNum, articles, author);
dataModel.put(Keys.PAGE_TYPE, PageTypes.AUTHOR_ARTICLES);
filler.fillBlogHeader(request, dataModel, preference);
filler.fillBlogHeader(request, response, dataModel, preference);
filler.fillBlogFooter(request, dataModel, preference);
filler.fillSide(request, dataModel, preference);
Skins.fillLangs(preference.optString(Preference.LOCALE_STRING), (String) request.getAttribute(Keys.TEMAPLTE_DIR_NAME), dataModel);
......@@ -757,7 +745,7 @@ public class ArticleProcessor {
@RequestProcessing(value = "/archives/**", method = HTTPRequestMethod.GET)
public void showArchiveArticles(final HTTPRequestContext context,
final HttpServletRequest request, final HttpServletResponse response) {
final AbstractFreeMarkerRenderer renderer = new FrontRenderer();
final AbstractFreeMarkerRenderer renderer = new FreeMarkerRenderer();
context.setRenderer(renderer);
......@@ -825,20 +813,10 @@ public class ArticleProcessor {
Skins.fillLangs(preference.optString(Preference.LOCALE_STRING), (String) request.getAttribute(Keys.TEMAPLTE_DIR_NAME), dataModel);
final String cachedTitle = prepareShowArchiveArticles(preference, dataModel, articles, currentPageNum, pageCount,
archiveDateString, archiveDate);
dataModel.put(Keys.PAGE_TYPE, PageTypes.DATE_ARTICLES);
filler.fillBlogHeader(request, dataModel, preference);
prepareShowArchiveArticles(preference, dataModel, articles, currentPageNum, pageCount, archiveDateString, archiveDate);
filler.fillBlogHeader(request, response, dataModel, preference);
filler.fillBlogFooter(request, dataModel, preference);
filler.fillSide(request, dataModel, preference);
final Map<String, String> langs = langPropsService.getAll(Latkes.getLocale());
request.setAttribute(PageCaches.CACHED_TYPE, langs.get(PageTypes.DATE_ARTICLES.getLangeLabel()));
request.setAttribute(PageCaches.CACHED_OID, archiveDateId);
request.setAttribute(PageCaches.CACHED_TITLE, cachedTitle + " [" + langs.get("pageNumLabel") + "=" + currentPageNum + "]");
request.setAttribute(PageCaches.CACHED_LINK, requestURI);
} catch (final Exception e) {
LOGGER.log(Level.ERROR, e.getMessage(), e);
......@@ -895,7 +873,7 @@ public class ArticleProcessor {
final String articleId = article.optString(Keys.OBJECT_ID);
LOGGER.log(Level.DEBUG, "Article[id={0}]", articleId);
final AbstractFreeMarkerRenderer renderer = new FrontRenderer();
final AbstractFreeMarkerRenderer renderer = new FreeMarkerRenderer();
context.setRenderer(renderer);
renderer.setTemplateName("article.ftl");
......@@ -917,12 +895,6 @@ public class ArticleProcessor {
final Map<String, String> langs = langPropsService.getAll(Latkes.getLocale());
request.setAttribute(PageCaches.CACHED_TYPE, langs.get(PageTypes.ARTICLE.getLangeLabel()));
request.setAttribute(PageCaches.CACHED_OID, articleId);
request.setAttribute(PageCaches.CACHED_TITLE, article.getString(Article.ARTICLE_TITLE));
request.setAttribute(PageCaches.CACHED_LINK, article.getString(Article.ARTICLE_PERMALINK));
request.setAttribute(PageCaches.CACHED_PWD, article.optString(Article.ARTICLE_VIEW_PWD));
// For <meta name="description" content="${article.articleAbstract}"/>
final String metaDescription = Jsoup.parse(article.optString(Article.ARTICLE_ABSTRACT)).text();
......@@ -947,9 +919,7 @@ public class ArticleProcessor {
prepareShowArticle(preference, dataModel, article);
dataModel.put(Keys.PAGE_TYPE, PageTypes.ARTICLE);
filler.fillBlogHeader(request, dataModel, preference);
filler.fillBlogHeader(request, response, dataModel, preference);
filler.fillBlogFooter(request, dataModel, preference);
filler.fillSide(request, dataModel, preference);
Skins.fillLangs(preference.optString(Preference.LOCALE_STRING), (String) request.getAttribute(Keys.TEMAPLTE_DIR_NAME), dataModel);
......@@ -1272,7 +1242,7 @@ public class ArticleProcessor {
*/
private void prepareShowArticle(final JSONObject preference, final Map<String, Object> dataModel, final JSONObject article)
throws Exception {
article.put(Common.COMMENTABLE, article.getBoolean(Article.ARTICLE_COMMENTABLE));
article.put(Common.COMMENTABLE, preference.getBoolean(Preference.COMMENTABLE) && article.getBoolean(Article.ARTICLE_COMMENTABLE));
article.put(Common.PERMALINK, article.getString(Article.ARTICLE_PERMALINK));
dataModel.put(Article.ARTICLE, article);
final String articleId = article.getString(Keys.OBJECT_ID);
......
/*
* Copyright (c) 2009, 2010, 2011, 2012, 2013, B3log Team
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.b3log.solo.processor;
import java.io.IOException;
import javax.inject.Inject;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.b3log.latke.cache.PageCaches;
import org.b3log.latke.logging.Level;
import org.b3log.latke.logging.Logger;
import org.b3log.latke.servlet.HTTPRequestContext;
import org.b3log.latke.servlet.HTTPRequestMethod;
import org.b3log.latke.servlet.annotation.RequestProcessing;
import org.b3log.latke.servlet.annotation.RequestProcessor;
import org.b3log.latke.servlet.renderer.DoNothingRenderer;
import org.b3log.latke.util.Requests;
import org.b3log.latke.util.Strings;
import org.b3log.solo.model.Common;
import org.b3log.solo.service.UserMgmtService;
import org.b3log.solo.service.UserQueryService;
import org.json.JSONObject;
/**
* Cache processor.
*
* @author <a href="http://88250.b3log.org">Liang Ding</a>
* @version 1.1.0.2, Aug 9, 2012
* @since 0.3.1
*/
@RequestProcessor
public class CacheProcessor {
/**
* Logger.
*/
private static final Logger LOGGER = Logger.getLogger(CacheProcessor.class.getName());
/**
* User query service.
*/
@Inject
private UserQueryService userQueryService;
/**
* User management service.
*/
@Inject
private UserMgmtService userMgmtService;
/**
* Clears cache with the specified context.
*
* @param context the specified context
* @param request the specified HTTP servlet request
* @param response the specified HTTP servlet response
* @throws IOException io exception
*/
@RequestProcessing(value = "/clear-cache.do", method = HTTPRequestMethod.POST)
public void clearCache(final HTTPRequestContext context, final HttpServletRequest request, final HttpServletResponse response)
throws IOException {
userMgmtService.tryLogInWithCookie(request, response);
if (!userQueryService.isAdminLoggedIn(request)) {
response.sendError(HttpServletResponse.SC_FORBIDDEN);
return;
}
try {
final JSONObject requestJSONObject = Requests.parseRequestJSONObject(request, response);
final String all = requestJSONObject.optString("all");
if (Strings.isEmptyOrNull(all)) { // Just clears single page cache
final String uri = requestJSONObject.optString(Common.URI);
clearPageCache(uri);
} else { // Clears all page caches
clearAllPageCache();
}
context.setRenderer(new DoNothingRenderer());
} catch (final Exception e) {
LOGGER.log(Level.ERROR, e.getMessage(), e);
}
}
/**
* Clears a page cache specified by the given URI.
*
* @param uri the specified URI
*/
private void clearPageCache(final String uri) {
final String pageCacheKey = PageCaches.getPageCacheKey(uri, null);
LOGGER.log(Level.INFO, "Clears page cache[pageCacheKey={0}]", pageCacheKey);
PageCaches.remove(pageCacheKey);
}
/**
* Clears all page cache.
*/
private void clearAllPageCache() {
PageCaches.removeAll();
}
}
......@@ -25,6 +25,7 @@ import javax.servlet.http.HttpSession;
import org.b3log.latke.Keys;
import org.b3log.latke.logging.Level;
import org.b3log.latke.logging.Logger;
import org.b3log.latke.model.User;
import org.b3log.latke.service.LangPropsService;
import org.b3log.latke.servlet.HTTPRequestContext;
import org.b3log.latke.servlet.HTTPRequestMethod;
......@@ -33,6 +34,7 @@ import org.b3log.latke.servlet.annotation.RequestProcessor;
import org.b3log.latke.servlet.renderer.JSONRenderer;
import org.b3log.latke.util.Requests;
import org.b3log.solo.model.Article;
import org.b3log.solo.model.Comment;
import org.b3log.solo.model.Common;
import org.b3log.solo.model.Page;
import org.b3log.solo.service.CommentMgmtService;
......@@ -45,7 +47,7 @@ import org.json.JSONObject;
*
* @author <a href="http://88250.b3log.org">Liang Ding</a>
* @author ArmstrongCN
* @version 1.1.0.11, Jan 30, 2013
* @version 1.1.0.12, Oct 26, 2013
* @since 0.3.1
*/
@RequestProcessor
......@@ -113,6 +115,8 @@ public class CommentProcessor {
requestJSONObject.put(Common.TYPE, Page.PAGE);
fillCommenter(requestJSONObject, httpServletRequest);
final JSONObject jsonObject = commentMgmtService.checkAddCommentRequest(requestJSONObject);
final JSONRenderer renderer = new JSONRenderer();
......@@ -196,7 +200,7 @@ public class CommentProcessor {
* @throws ServletException servlet exception
* @throws IOException io exception
*/
@RequestProcessing(value = { "/add-article-comment.do"}, method = HTTPRequestMethod.POST)
@RequestProcessing(value = "/add-article-comment.do", method = HTTPRequestMethod.POST)
public void addArticleComment(final HTTPRequestContext context) throws ServletException, IOException {
final HttpServletRequest httpServletRequest = context.getRequest();
final HttpServletResponse httpServletResponse = context.getResponse();
......@@ -205,6 +209,8 @@ public class CommentProcessor {
requestJSONObject.put(Common.TYPE, Article.ARTICLE);
fillCommenter(requestJSONObject, httpServletRequest);
final JSONObject jsonObject = commentMgmtService.checkAddCommentRequest(requestJSONObject);
final JSONRenderer renderer = new JSONRenderer();
......@@ -255,4 +261,22 @@ public class CommentProcessor {
jsonObject.put(Keys.MSG, langPropsService.get("addFailLabel"));
}
}
/**
* Fills commenter info if logged in.
*
* @param requestJSONObject the specified request json object
* @param httpServletRequest the specified HTTP servlet request
*/
private void fillCommenter(final JSONObject requestJSONObject, final HttpServletRequest httpServletRequest) {
final JSONObject currentUser = userQueryService.getCurrentUser(httpServletRequest);
if (null == currentUser) {
return;
}
requestJSONObject.put(Comment.COMMENT_NAME, currentUser.optString(User.USER_NAME));
requestJSONObject.put(Comment.COMMENT_EMAIL, currentUser.optString(User.USER_EMAIL));
requestJSONObject.put(Comment.COMMENT_URL, currentUser.optString(User.USER_URL));
}
}
......@@ -108,7 +108,7 @@ public class ErrorProcessor {
dataModel.putAll(langs);
final JSONObject preference = preferenceQueryService.getPreference();
filler.fillBlogHeader(request, dataModel, preference);
filler.fillBlogHeader(request, response, dataModel, preference);
filler.fillBlogFooter(request, dataModel, preference);
dataModel.put(Common.LOGIN_URL, userService.createLoginURL(Common.ADMIN_INDEX_URI));
......
......@@ -59,7 +59,6 @@ import org.b3log.solo.repository.TagRepository;
import org.b3log.solo.service.ArticleQueryService;
import org.b3log.solo.service.PreferenceQueryService;
import org.b3log.solo.service.UserQueryService;
import org.b3log.solo.util.TimeZones;
import org.json.JSONArray;
import org.json.JSONObject;
......@@ -137,7 +136,7 @@ public class FeedProcessor {
feed.setTitle(StringEscapeUtils.escapeXml(blogTitle));
feed.setSubtitle(StringEscapeUtils.escapeXml(blogSubtitle));
feed.setUpdated(TimeZones.getTime(preference.getString(Preference.TIME_ZONE_ID)));
feed.setUpdated(new Date());
feed.setAuthor(StringEscapeUtils.escapeXml(blogTitle));
feed.setLink(Latkes.getServePath() + "/blog-articles-feed.do");
feed.setId(Latkes.getServePath() + "/");
......@@ -263,7 +262,7 @@ public class FeedProcessor {
feed.setTitle(StringEscapeUtils.escapeXml(blogTitle));
feed.setSubtitle(StringEscapeUtils.escapeXml(blogSubtitle));
feed.setUpdated(TimeZones.getTime(preference.getString(Preference.TIME_ZONE_ID)));
feed.setUpdated(new Date());
feed.setAuthor(StringEscapeUtils.escapeXml(blogTitle));
feed.setLink(Latkes.getServePath() + "/tag-articles-feed.do");
feed.setId(Latkes.getServePath() + "/");
......@@ -375,7 +374,7 @@ public class FeedProcessor {
final int outputCnt = preference.getInt(Preference.FEED_OUTPUT_CNT);
channel.setTitle(StringEscapeUtils.escapeXml(blogTitle));
channel.setLastBuildDate(TimeZones.getTime(preference.getString(Preference.TIME_ZONE_ID)));
channel.setLastBuildDate(new Date());
channel.setLink(Latkes.getServePath());
channel.setAtomLink(Latkes.getServePath() + "/blog-articles-rss.do");
channel.setGenerator("B3log Solo, ver " + SoloServletListener.VERSION);
......@@ -508,7 +507,7 @@ public class FeedProcessor {
final int outputCnt = preference.getInt(Preference.FEED_OUTPUT_CNT);
channel.setTitle(StringEscapeUtils.escapeXml(blogTitle));
channel.setLastBuildDate(TimeZones.getTime(preference.getString(Preference.TIME_ZONE_ID)));
channel.setLastBuildDate(new Date());
channel.setLink(Latkes.getServePath());
channel.setAtomLink(Latkes.getServePath() + "/tag-articles-rss.do");
channel.setGenerator("B3log Solo, ver " + SoloServletListener.VERSION);
......
......@@ -26,7 +26,6 @@ import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.apache.commons.lang.StringUtils;
import org.b3log.latke.Keys;
import org.b3log.latke.cache.PageCaches;
import org.b3log.latke.logging.Level;
import org.b3log.latke.logging.Logger;
import org.b3log.latke.model.Pagination;
......@@ -38,13 +37,12 @@ import org.b3log.latke.servlet.URIPatternMode;
import org.b3log.latke.servlet.annotation.RequestProcessing;
import org.b3log.latke.servlet.annotation.RequestProcessor;
import org.b3log.latke.servlet.renderer.freemarker.AbstractFreeMarkerRenderer;
import org.b3log.latke.servlet.renderer.freemarker.FreeMarkerRenderer;
import org.b3log.latke.util.Locales;
import org.b3log.latke.util.Requests;
import org.b3log.solo.model.Common;
import org.b3log.solo.model.PageTypes;
import org.b3log.solo.model.Preference;
import org.b3log.solo.processor.renderer.ConsoleRenderer;
import org.b3log.solo.processor.renderer.FrontRenderer;
import org.b3log.solo.processor.util.Filler;
import org.b3log.solo.service.PreferenceQueryService;
import org.b3log.solo.util.Skins;
......@@ -56,7 +54,7 @@ import org.json.JSONObject;
*
* @author <a href="http://88250.b3log.org">Liang Ding</a>
* @author <a href="mailto:385321165@qq.com">DASHU</a>
* @version 1.1.1.3, Jul 11, 2013
* @version 1.1.1.4, Sep 11, 2013
* @since 0.3.1
*/
@RequestProcessor
......@@ -94,7 +92,7 @@ public class IndexProcessor {
*/
@RequestProcessing(value = { "/\\d*", ""}, uriPatternsMode = URIPatternMode.REGEX, method = HTTPRequestMethod.GET)
public void showIndex(final HTTPRequestContext context, final HttpServletRequest request, final HttpServletResponse response) {
final AbstractFreeMarkerRenderer renderer = new FrontRenderer();
final AbstractFreeMarkerRenderer renderer = new FreeMarkerRenderer();
context.setRenderer(renderer);
......@@ -109,18 +107,10 @@ public class IndexProcessor {
Skins.fillLangs(preference.optString(Preference.LOCALE_STRING), (String) request.getAttribute(Keys.TEMAPLTE_DIR_NAME), dataModel);
request.setAttribute(PageCaches.CACHED_OID, "No id");
request.setAttribute(PageCaches.CACHED_TITLE,
langPropsService.get(PageTypes.INDEX.getLangeLabel()) + " [" + langPropsService.get("pageNumLabel") + "=" + currentPageNum
+ "]");
request.setAttribute(PageCaches.CACHED_TYPE, langPropsService.get(PageTypes.INDEX.getLangeLabel()));
request.setAttribute(PageCaches.CACHED_LINK, requestURI);
filler.fillIndexArticles(request, dataModel, currentPageNum, preference);
dataModel.put(Keys.PAGE_TYPE, PageTypes.INDEX);
filler.fillSide(request, dataModel, preference);
filler.fillBlogHeader(request, dataModel, preference);
filler.fillBlogHeader(request, response, dataModel, preference);
filler.fillBlogFooter(request, dataModel, preference);
dataModel.put(Pagination.PAGINATION_CURRENT_PAGE_NUM, currentPageNum);
......@@ -171,13 +161,6 @@ public class IndexProcessor {
filler.fillBlogFooter(request, dataModel, preference);
Keys.fillRuntime(dataModel);
filler.fillMinified(dataModel);
dataModel.put(Keys.PAGE_TYPE, PageTypes.KILL_BROWSER);
request.setAttribute(PageCaches.CACHED_OID, "No id");
request.setAttribute(PageCaches.CACHED_TITLE, "Kill Browser Page");
request.setAttribute(PageCaches.CACHED_TYPE, langs.get(PageTypes.KILL_BROWSER.getLangeLabel()));
request.setAttribute(PageCaches.CACHED_LINK, request.getRequestURI());
} catch (final ServiceException e) {
LOGGER.log(Level.ERROR, e.getMessage(), e);
......@@ -234,7 +217,7 @@ public class IndexProcessor {
* can not convert to an number
*/
private static int getCurrentPageNum(final String requestURI) {
final String pageNumString = StringUtils.substringAfter(requestURI, "/");
final String pageNumString = StringUtils.substringAfterLast(requestURI, "/");
return Requests.getCurrentPageNum(pageNumString);
}
......@@ -272,8 +255,6 @@ public class IndexProcessor {
final String pageContent = stringWriter.toString();
context.getRequest().setAttribute(PageCaches.CACHED_CONTENT, pageContent);
writer.write(pageContent);
writer.flush();
writer.close();
......
......@@ -68,7 +68,7 @@ import java.util.Map;
* @author <a href="http://88250.b3log.org">Liang Ding</a>
* @author <a href="mailto:LLY219@gmail.com">Liyuan Li</a>
* @author <a href="mailto:dongxu.wang@acm.org">Dongxu Wang</a>
* @version 1.1.1.5, Jul 4, 2013
* @version 1.1.1.6, Oct 26, 2013
* @since 0.3.1
*/
@RequestProcessor
......@@ -162,23 +162,26 @@ public class LoginProcessor {
return;
}
renderPage(context, "login.ftl", destinationURL, request);
}
/**
* Logins.
* <p/>
* <p> Renders the response with a json object, for example,
*
* <p>
* Renders the response with a json object, for example,
* <pre>
* {
* "isLoggedIn": boolean,
* "msg": "" // optional, exists if isLoggedIn equals to false
* }
* </pre> </p>
* </pre>
* </p>
*
* @param context the specified context
*/
@RequestProcessing(value = { "/login"}, method = HTTPRequestMethod.POST)
@RequestProcessing(value = "/login", method = HTTPRequestMethod.POST)
public void login(final HTTPRequestContext context) {
final HttpServletRequest request = context.getRequest();
......@@ -242,7 +245,7 @@ public class LoginProcessor {
* @param context the specified context
* @throws IOException io exception
*/
@RequestProcessing(value = { "/logout"}, method = HTTPRequestMethod.GET)
@RequestProcessing(value = "/logout", method = HTTPRequestMethod.GET)
public void logout(final HTTPRequestContext context) throws IOException {
final HttpServletRequest httpServletRequest = context.getRequest();
......@@ -277,19 +280,21 @@ public class LoginProcessor {
}
/**
* reset forgotten password.
* <p/>
* <p> Renders the response with a json object, for example,
* Resets forgotten password.
*
* <p>
* Renders the response with a json object, for example,
* <pre>
* {
* "isLoggedIn": boolean,
* "msg": "" // optional, exists if isLoggedIn equals to false
* }
* </pre> </p>
* </pre>
* </p>
*
* @param context the specified context
*/
@RequestProcessing(value = { "/forgot"}, method = HTTPRequestMethod.POST)
@RequestProcessing(value = "/forgot", method = HTTPRequestMethod.POST)
public void forgot(final HTTPRequestContext context) {
final HttpServletRequest request = context.getRequest();
......@@ -329,19 +334,21 @@ public class LoginProcessor {
}
/**
* reset forgotten password.
* <p/>
* <p> Renders the response with a json object, for example,
* Resets forgotten password.
*
* <p>
* Renders the response with a json object, for example,
* <pre>
* {
* "isLoggedIn": boolean,
* "msg": "" // optional, exists if isLoggedIn equals to false
* }
* </pre> </p>
* </pre>
* </p>
*
* @param context the specified context
*/
@RequestProcessing(value = { "/reset"}, method = HTTPRequestMethod.POST)
@RequestProcessing(value = "/reset", method = HTTPRequestMethod.POST)
public void reset(final HTTPRequestContext context) {
final HttpServletRequest request = context.getRequest();
final JSONRenderer renderer = new JSONRenderer();
......@@ -381,7 +388,7 @@ public class LoginProcessor {
}
/**
* Send the password resetting URL with a random token.
* Sends the password resetting URL with a random token.
*
* @param userEmail the given email
* @param jsonObject return code and message object
......@@ -394,7 +401,6 @@ public class LoginProcessor {
ServiceException, IOException, RepositoryException {
final JSONObject preference = preferenceQueryService.getPreference();
final String token = new Randoms().nextStringWithMD5();
final String blogTitle = preference.getString(Preference.BLOG_TITLE);
final String adminEmail = preference.getString(Preference.ADMIN_EMAIL);
final String mailSubject = langPropsService.get("resetPwdMailSubject");
final String mailBody = langPropsService.get("resetPwdMailBody") + " " + Latkes.getServePath() + "/forgot?token=" + token
......@@ -423,7 +429,7 @@ public class LoginProcessor {
jsonObject.put("to", Latkes.getServePath() + "/login?from=forgot");
jsonObject.put(Keys.MSG, langPropsService.get("resetPwdSuccessSend"));
LOGGER.log(Level.DEBUG, "Sending a mail[mailSubject={0}, mailBody=[{1}] to [{2}]", new Object[] {mailSubject, mailBody, userEmail});
LOGGER.log(Level.DEBUG, "Sent a mail[mailSubject={0}, mailBody=[{1}] to [{2}]", new Object[] {mailSubject, mailBody, userEmail});
}
/**
......@@ -436,8 +442,8 @@ public class LoginProcessor {
* @throws JSONException the JSONException
* @throws ServiceException the ServiceException
*/
private void renderPage(final HTTPRequestContext context, final String pageTemplate, final String destinationURL, final HttpServletRequest request) throws JSONException,
ServiceException {
private void renderPage(final HTTPRequestContext context, final String pageTemplate, final String destinationURL,
final HttpServletRequest request) throws JSONException, ServiceException {
final AbstractFreeMarkerRenderer renderer = new ConsoleRenderer();
renderer.setTemplateName(pageTemplate);
......
......@@ -24,7 +24,6 @@ import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.b3log.latke.Keys;
import org.b3log.latke.Latkes;
import org.b3log.latke.cache.PageCaches;
import org.b3log.latke.logging.Level;
import org.b3log.latke.logging.Logger;
import org.b3log.latke.service.LangPropsService;
......@@ -33,12 +32,11 @@ import org.b3log.latke.servlet.HTTPRequestMethod;
import org.b3log.latke.servlet.annotation.RequestProcessing;
import org.b3log.latke.servlet.annotation.RequestProcessor;
import org.b3log.latke.servlet.renderer.freemarker.AbstractFreeMarkerRenderer;
import org.b3log.latke.servlet.renderer.freemarker.FreeMarkerRenderer;
import org.b3log.latke.util.Stopwatchs;
import org.b3log.solo.model.Common;
import org.b3log.solo.model.Page;
import org.b3log.solo.model.PageTypes;
import org.b3log.solo.model.Preference;
import org.b3log.solo.processor.renderer.FrontRenderer;
import org.b3log.solo.processor.util.Filler;
import org.b3log.solo.service.CommentQueryService;
import org.b3log.solo.service.PreferenceQueryService;
......@@ -51,7 +49,7 @@ import org.json.JSONObject;
* Page processor.
*
* @author <a href="http://88250.b3log.org">Liang Ding</a>
* @version 1.1.0.2, Apr 29, 2012
* @version 1.1.0.3, Oct 14, 2013
* @since 0.3.1
*/
@RequestProcessor
......@@ -93,7 +91,7 @@ public class PageProcessor {
*/
@RequestProcessing(value = "/page", method = HTTPRequestMethod.GET)
public void showPage(final HTTPRequestContext context) {
final AbstractFreeMarkerRenderer renderer = new FrontRenderer();
final AbstractFreeMarkerRenderer renderer = new FreeMarkerRenderer();
context.setRenderer(renderer);
......@@ -115,8 +113,6 @@ public class PageProcessor {
final Map<String, String> langs = langPropsService.getAll(Latkes.getLocale());
request.setAttribute(PageCaches.CACHED_TYPE, langs.get(PageTypes.PAGE.getLangeLabel()));
// See PermalinkFiler#dispatchToArticleOrPageProcessor()
final JSONObject page = (JSONObject) request.getAttribute(Page.PAGE);
......@@ -127,11 +123,7 @@ public class PageProcessor {
final String pageId = page.getString(Keys.OBJECT_ID);
request.setAttribute(PageCaches.CACHED_OID, pageId);
request.setAttribute(PageCaches.CACHED_TITLE, page.getString(Page.PAGE_TITLE));
request.setAttribute(PageCaches.CACHED_LINK, page.getString(Page.PAGE_PERMALINK));
page.put(Common.COMMENTABLE, page.getBoolean(Page.PAGE_COMMENTABLE));
page.put(Common.COMMENTABLE, preference.getBoolean(Preference.COMMENTABLE) && page.getBoolean(Page.PAGE_COMMENTABLE));
page.put(Common.PERMALINK, page.getString(Page.PAGE_PERMALINK));
dataModel.put(Page.PAGE, page);
final List<JSONObject> comments = commentQueryService.getComments(pageId);
......@@ -149,9 +141,8 @@ public class PageProcessor {
Stopwatchs.end();
}
dataModel.put(Keys.PAGE_TYPE, PageTypes.PAGE);
filler.fillSide(request, dataModel, preference);
filler.fillBlogHeader(request, dataModel, preference);
filler.fillBlogHeader(request, response, dataModel, preference);
filler.fillBlogFooter(request, dataModel, preference);
} catch (final Exception e) {
LOGGER.log(Level.ERROR, e.getMessage(), e);
......
......@@ -25,7 +25,6 @@ import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.b3log.latke.Keys;
import org.b3log.latke.Latkes;
import org.b3log.latke.cache.PageCaches;
import org.b3log.latke.ioc.LatkeBeanManager;
import org.b3log.latke.logging.Level;
import org.b3log.latke.logging.Logger;
......@@ -33,6 +32,7 @@ import org.b3log.latke.mail.MailService;
import org.b3log.latke.mail.MailService.Message;
import org.b3log.latke.mail.MailServiceFactory;
import org.b3log.latke.repository.*;
import org.b3log.latke.repository.annotation.Transactional;
import org.b3log.latke.servlet.HTTPRequestContext;
import org.b3log.latke.servlet.HTTPRequestMethod;
import org.b3log.latke.servlet.annotation.RequestProcessing;
......@@ -69,7 +69,7 @@ import org.json.JSONObject;
* <p>See AuthFilter filter configurations in web.xml for authentication.</p>
*
* @author <a href="http://88250.b3log.org">Liang Ding</a>
* @version 1.1.0.8, Dec 25, 2012
* @version 1.1.0.10, Oct 26, 2013
* @since 0.3.1
*/
@RequestProcessor
......@@ -209,8 +209,6 @@ public class RepairProcessor {
context.setRenderer(renderer);
try {
PageCaches.removeAll(); // Clears all first
final JSONObject statistic = statisticQueryService.getStatistic();
if (statistic.has(Statistic.STATISTIC_BLOG_COMMENT_COUNT) && statistic.has(Statistic.STATISTIC_BLOG_ARTICLE_COUNT)) {
......@@ -278,13 +276,12 @@ public class RepairProcessor {
* @param context the specified context
*/
@RequestProcessing(value = "/fix/tag-article-counter-repair.do", method = HTTPRequestMethod.GET)
@Transactional
public void repairTagArticleCounter(final HTTPRequestContext context) {
final TextHTMLRenderer renderer = new TextHTMLRenderer();
context.setRenderer(renderer);
final Transaction transaction = tagRepository.beginTransaction();
try {
final JSONObject result = tagRepository.get(new Query());
final JSONArray tagArray = result.getJSONArray(Keys.RESULTS);
......@@ -301,9 +298,14 @@ public class RepairProcessor {
final JSONObject tagArticle = tagArticles.getJSONObject(i);
final String articleId = tagArticle.getString(Article.ARTICLE + "_" + Keys.OBJECT_ID);
final JSONObject article = articleRepository.get(articleId);
final boolean isPublished = article.getBoolean(Article.ARTICLE_IS_PUBLISHED);
if (isPublished) {
if (null == article) {
tagArticleRepository.remove(tagArticle.optString(Keys.OBJECT_ID));
continue;
}
if (article.getBoolean(Article.ARTICLE_IS_PUBLISHED)) {
publishedTagRefCnt++;
}
}
......@@ -317,14 +319,8 @@ public class RepairProcessor {
new Object[] {tag.getString(Tag.TAG_TITLE), tagRefCnt, publishedTagRefCnt});
}
transaction.commit();
renderer.setContent("Repair sucessfully!");
} catch (final Exception e) {
if (transaction.isActive()) {
transaction.rollback();
}
LOGGER.log(Level.ERROR, e.getMessage(), e);
renderer.setContent("Repairs failed, error msg[" + e.getMessage() + "]");
}
......@@ -347,7 +343,7 @@ public class RepairProcessor {
htmlBuilder.append("<html><head><title>WARNING!</title>");
htmlBuilder.append("<script type='text/javascript'");
htmlBuilder.append("src='http://ajax.googleapis.com/ajax/libs/jquery/1.4.3/jquery.min.js'");
htmlBuilder.append("src='").append(Latkes.getStaticServer()).append("/js/lib/jquery/jquery.min.js'");
htmlBuilder.append("></script></head><body>");
htmlBuilder.append("<button id='ok' onclick='removeData()'>");
htmlBuilder.append("Continue to delete ALL DATA</button></body>");
......@@ -378,8 +374,6 @@ public class RepairProcessor {
public void removeAllDataPOST(final HTTPRequestContext context) {
LOGGER.info("Removing all data....");
PageCaches.removeAll();
boolean succeed = false;
try {
......
......@@ -141,13 +141,9 @@ public class SitemapProcessor {
final Query query = new Query().setCurrentPageNum(1).setFilter(new PropertyFilter(Article.ARTICLE_IS_PUBLISHED, FilterOperator.EQUAL, true)).addSort(
Article.ARTICLE_CREATE_DATE, SortDirection.DESCENDING);
// Closes cache avoid Java heap space out of memory while caching query results
articleRepository.setCacheEnabled(false);
// XXX: maybe out of memory
final JSONObject articleResult = articleRepository.get(query);
articleRepository.setCacheEnabled(true); // Restores cache
final JSONArray articles = articleResult.getJSONArray(Keys.RESULTS);
for (int i = 0; i < articles.length(); i++) {
......
......@@ -17,9 +17,7 @@ package org.b3log.solo.processor;
import javax.inject.Inject;
import org.b3log.latke.logging.Level;
import org.b3log.latke.logging.Logger;
import org.b3log.latke.service.ServiceException;
import org.b3log.latke.servlet.HTTPRequestContext;
import org.b3log.latke.servlet.HTTPRequestMethod;
import org.b3log.latke.servlet.annotation.RequestProcessing;
......@@ -40,7 +38,7 @@ import org.b3log.solo.service.StatisticMgmtService;
* <p>
*
* @author <a href="http://88250.b3log.org">Liang Ding</a>
* @version 1.0.1.9, Mar 6, 2013
* @version 1.0.2.0, Oct 12, 2013
* @since 0.4.0
*/
@RequestProcessor
......@@ -68,22 +66,4 @@ public class StatProcessor {
statisticMgmtService.removeExpiredOnlineVisitor();
}
/**
* Increments Blog/Articles view counter.
*
* @param context the specified context
*/
@RequestProcessing(value = "/console/stat/viewcnt", method = HTTPRequestMethod.GET)
public void viewCounter(final HTTPRequestContext context) {
LOGGER.log(Level.INFO, "Sync statistic from memcache to repository");
context.setRenderer(new DoNothingRenderer());
try {
statisticMgmtService.flushStatistic();
} catch (final ServiceException e) {
LOGGER.log(Level.ERROR, "Flushes statistic to repository failed", e);
}
}
}
......@@ -27,7 +27,6 @@ import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.b3log.latke.Keys;
import org.b3log.latke.Latkes;
import org.b3log.latke.cache.PageCaches;
import org.b3log.latke.logging.Level;
import org.b3log.latke.logging.Logger;
import org.b3log.latke.model.Pagination;
......@@ -38,15 +37,14 @@ import org.b3log.latke.servlet.HTTPRequestMethod;
import org.b3log.latke.servlet.annotation.RequestProcessing;
import org.b3log.latke.servlet.annotation.RequestProcessor;
import org.b3log.latke.servlet.renderer.freemarker.AbstractFreeMarkerRenderer;
import org.b3log.latke.servlet.renderer.freemarker.FreeMarkerRenderer;
import org.b3log.latke.util.Paginator;
import org.b3log.latke.util.Requests;
import org.b3log.latke.util.Strings;
import org.b3log.solo.model.Article;
import org.b3log.solo.model.Common;
import org.b3log.solo.model.PageTypes;
import org.b3log.solo.model.Preference;
import org.b3log.solo.model.Tag;
import org.b3log.solo.processor.renderer.FrontRenderer;
import org.b3log.solo.processor.util.Filler;
import org.b3log.solo.service.ArticleQueryService;
import org.b3log.solo.service.PreferenceQueryService;
......@@ -62,7 +60,7 @@ import org.json.JSONObject;
* Tag processor.
*
* @author <a href="http://88250.b3log.org">Liang Ding</a>
* @version 1.1.1.1, Jul 11, 2013
* @version 1.1.1.2, Oct 29, 2013
* @since 0.3.1
*/
@RequestProcessor
......@@ -117,7 +115,7 @@ public class TagProcessor {
*/
@RequestProcessing(value = "/tags/**", method = HTTPRequestMethod.GET)
public void showTagArticles(final HTTPRequestContext context) throws IOException {
final AbstractFreeMarkerRenderer renderer = new FrontRenderer();
final AbstractFreeMarkerRenderer renderer = new FreeMarkerRenderer();
context.setRenderer(renderer);
......@@ -162,16 +160,6 @@ public class TagProcessor {
final int pageSize = preference.getInt(Preference.ARTICLE_LIST_DISPLAY_COUNT);
final int windowSize = preference.getInt(Preference.ARTICLE_LIST_PAGINATION_WINDOW_SIZE);
request.setAttribute(PageCaches.CACHED_OID, tagId);
final Map<String, String> langs = langPropsService.getAll(Latkes.getLocale());
request.setAttribute(PageCaches.CACHED_TITLE,
langs.get(PageTypes.TAG_ARTICLES.getLangeLabel()) + " [" + langs.get("pageNumLabel") + "=" + currentPageNum + ", "
+ langs.get("tagLabel") + "=" + tagTitle + "]");
request.setAttribute(PageCaches.CACHED_TYPE, langs.get(PageTypes.TAG_ARTICLES.getLangeLabel()));
request.setAttribute(PageCaches.CACHED_LINK, requestURI);
final List<JSONObject> articles = articleQueryService.getArticlesByTag(tagId, currentPageNum, pageSize);
if (articles.isEmpty()) {
......@@ -210,9 +198,8 @@ public class TagProcessor {
dataModel.put(Keys.OBJECT_ID, tagId);
dataModel.put(Tag.TAG, tag);
dataModel.put(Keys.PAGE_TYPE, PageTypes.TAG_ARTICLES);
filler.fillSide(request, dataModel, preference);
filler.fillBlogHeader(request, dataModel, preference);
filler.fillBlogHeader(request, response, dataModel, preference);
filler.fillBlogFooter(request, dataModel, preference);
} catch (final ServiceException e) {
LOGGER.log(Level.ERROR, e.getMessage(), e);
......@@ -262,69 +249,12 @@ public class TagProcessor {
dataModel.put(Pagination.PAGINATION_PAGE_NUMS, pageNums);
}
/**
* Shows tags with the specified context.
*
* @param context the specified context
*/
@RequestProcessing(value = { "/tags.html"}, method = HTTPRequestMethod.GET)
public void showTags(final HTTPRequestContext context) {
final AbstractFreeMarkerRenderer renderer = new FrontRenderer();
context.setRenderer(renderer);
renderer.setTemplateName("tags.ftl");
final Map<String, Object> dataModel = renderer.getDataModel();
final HttpServletRequest request = context.getRequest();
final HttpServletResponse response = context.getResponse();
try {
final JSONObject preference = preferenceQueryService.getPreference();
if (null == preference) {
response.sendError(HttpServletResponse.SC_NOT_FOUND);
return;
}
Skins.fillLangs(preference.optString(Preference.LOCALE_STRING), (String) request.getAttribute(Keys.TEMAPLTE_DIR_NAME), dataModel);
request.setAttribute(PageCaches.CACHED_OID, "No id");
final Map<String, String> langs = langPropsService.getAll(Latkes.getLocale());
request.setAttribute(PageCaches.CACHED_TITLE, langs.get(PageTypes.TAGS.getLangeLabel()));
request.setAttribute(PageCaches.CACHED_TYPE, langs.get(PageTypes.TAGS.getLangeLabel()));
request.setAttribute(PageCaches.CACHED_LINK, "/tags.html");
final List<JSONObject> tags = tagQueryService.getTags();
tagQueryService.removeForUnpublishedArticles(tags);
Collections.sort(tags, Comparators.TAG_REF_CNT_COMPARATOR);
dataModel.put(Tag.TAGS, tags);
dataModel.put(Keys.PAGE_TYPE, PageTypes.TAGS);
filler.fillSide(request, dataModel, preference);
filler.fillBlogHeader(request, dataModel, preference);
filler.fillBlogFooter(request, dataModel, preference);
} catch (final Exception e) {
LOGGER.log(Level.ERROR, e.getMessage(), e);
try {
response.sendError(HttpServletResponse.SC_NOT_FOUND);
} catch (final IOException ex) {
LOGGER.error(ex.getMessage());
}
}
}
/**
* Gets the request page number from the specified request URI and tag title.
*
* @param requestURI the specified request URI
* @param tagTitle the specified tag title
* @return page number, returns {@code -1} if the specified request URI
* can not convert to an number
* @return page number, returns {@code -1} if the specified request URI can not convert to an number
*/
private static int getCurrentPageNum(final String requestURI, final String tagTitle) {
if (Strings.isEmptyOrNull(tagTitle)) {
......
......@@ -17,19 +17,15 @@ package org.b3log.solo.processor;
import java.io.IOException;
import java.sql.Connection;
import java.sql.Statement;
import javax.inject.Inject;
import org.b3log.latke.Keys;
import org.b3log.latke.Latkes;
import org.b3log.latke.RuntimeEnv;
import org.b3log.latke.logging.Level;
import org.b3log.latke.logging.Logger;
import org.b3log.latke.mail.MailService;
import org.b3log.latke.mail.MailServiceFactory;
import org.b3log.latke.model.User;
import org.b3log.latke.repository.*;
import org.b3log.latke.repository.jdbc.util.Connections;
import org.b3log.latke.service.LangPropsService;
import org.b3log.latke.service.ServiceException;
import org.b3log.latke.servlet.HTTPRequestContext;
......@@ -37,7 +33,6 @@ import org.b3log.latke.servlet.HTTPRequestMethod;
import org.b3log.latke.servlet.annotation.RequestProcessing;
import org.b3log.latke.servlet.annotation.RequestProcessor;
import org.b3log.latke.servlet.renderer.TextHTMLRenderer;
import org.b3log.latke.util.Strings;
import org.b3log.solo.SoloServletListener;
import org.b3log.solo.model.*;
import org.b3log.solo.repository.*;
......@@ -52,7 +47,7 @@ import org.json.JSONObject;
*
* @author <a href="http://88250.b3log.org">Liang Ding</a>
* @author <a href="mailto:dongxu.wang@acm.org">Dongxu Wang</a>
* @version 1.1.1.10, Aug 20, 2013
* @version 1.1.1.11, Oct 27, 2013
* @since 0.3.1
*/
@RequestProcessor
......@@ -111,7 +106,7 @@ public class UpgradeProcessor {
/**
* Old version.
*/
private static final String FROM_VER = "0.6.0";
private static final String FROM_VER = "0.6.1";
/**
* New version.
......@@ -177,26 +172,11 @@ public class UpgradeProcessor {
private void upgrade() throws Exception {
LOGGER.log(Level.INFO, "Upgrading from version [{0}] to version [{1}]....", FROM_VER, TO_VER);
articleRepository.setCacheEnabled(false);
Transaction transaction = null;
try {
transaction = userRepository.beginTransaction();
final RuntimeEnv runtimeEnv = Latkes.getRuntimeEnv();
if (RuntimeEnv.LOCAL == runtimeEnv || RuntimeEnv.BAE == runtimeEnv) {
final Connection connection = Connections.getConnection();
final Statement statement = connection.createStatement();
final String tablePrefix = Latkes.getLocalProperty("jdbc.tablePrefix");
final String tableName = Strings.isEmptyOrNull(tablePrefix) ? "preference" : tablePrefix + "_preference";
statement.execute("ALTER TABLE " + tableName + " DROP COLUMN blogHost");
connection.commit();
}
// Upgrades preference model
final JSONObject preference = preferenceRepository.get(Preference.PREFERENCE);
......@@ -213,8 +193,6 @@ public class UpgradeProcessor {
LOGGER.log(Level.ERROR, "Upgrade failed!", e);
throw new Exception("Upgrade failed from version [" + FROM_VER + "] to version [" + TO_VER + ']');
} finally {
articleRepository.setCacheEnabled(true);
}
LOGGER.log(Level.INFO, "Upgraded from version [{0}] to version [{1}] successfully :-)", FROM_VER, TO_VER);
......
......@@ -24,7 +24,6 @@ import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.apache.commons.lang.StringUtils;
import org.b3log.latke.Keys;
import org.b3log.latke.cache.PageCaches;
import org.b3log.latke.logging.Level;
import org.b3log.latke.logging.Logger;
import org.b3log.latke.service.LangPropsService;
......@@ -33,11 +32,10 @@ import org.b3log.latke.servlet.HTTPRequestMethod;
import org.b3log.latke.servlet.annotation.RequestProcessing;
import org.b3log.latke.servlet.annotation.RequestProcessor;
import org.b3log.latke.servlet.renderer.freemarker.AbstractFreeMarkerRenderer;
import org.b3log.latke.servlet.renderer.freemarker.FreeMarkerRenderer;
import org.b3log.latke.util.Locales;
import org.b3log.latke.util.freemarker.Templates;
import org.b3log.solo.model.PageTypes;
import org.b3log.solo.model.Preference;
import org.b3log.solo.processor.renderer.FrontRenderer;
import org.b3log.solo.processor.util.Filler;
import org.b3log.solo.service.PreferenceQueryService;
import org.b3log.solo.util.Skins;
......@@ -102,7 +100,7 @@ public class UserTemplateProcessor {
templateName = StringUtils.substringBefore(templateName, ".") + ".ftl";
LOGGER.log(Level.DEBUG, "Shows page[requestURI={0}, templateName={1}]", new Object[] {requestURI, templateName});
final AbstractFreeMarkerRenderer renderer = new FrontRenderer();
final AbstractFreeMarkerRenderer renderer = new FreeMarkerRenderer();
context.setRenderer(renderer);
renderer.setTemplateName(templateName);
......@@ -127,16 +125,10 @@ public class UserTemplateProcessor {
dataModel.putAll(langs);
final JSONObject preference = preferenceQueryService.getPreference();
dataModel.put(Keys.PAGE_TYPE, PageTypes.USER_TEMPLATE);
filler.fillBlogHeader(request, dataModel, preference);
filler.fillUserTemplate(template, dataModel, preference);
filler.fillBlogHeader(request, response, dataModel, preference);
filler.fillUserTemplate(request, template, dataModel, preference);
filler.fillBlogFooter(request, dataModel, preference);
Skins.fillLangs(preference.optString(Preference.LOCALE_STRING), (String) request.getAttribute(Keys.TEMAPLTE_DIR_NAME), dataModel);
request.setAttribute(PageCaches.CACHED_OID, "No id");
request.setAttribute(PageCaches.CACHED_TITLE, requestURI);
request.setAttribute(PageCaches.CACHED_TYPE, langs.get(PageTypes.USER_TEMPLATE.getLangeLabel()));
request.setAttribute(PageCaches.CACHED_LINK, requestURI);
} catch (final Exception e) {
LOGGER.log(Level.ERROR, e.getMessage(), e);
......
......@@ -95,7 +95,8 @@ public class AdminConsole {
/**
* Event manager.
*/
private EventManager eventManager = EventManager.getInstance();
@Inject
private EventManager eventManager;
/**
* Shows administrator index with the specified context.
......
......@@ -671,7 +671,7 @@ public class ArticleConsole {
renderer.setJSONObject(ret);
} catch (final ServiceException e) {
LOGGER.log(Level.ERROR, e.getMessage(), e);
LOGGER.log(Level.ERROR, e.getMessage());
final JSONObject jsonObject = QueryResults.defaultResult();
......
/*
* Copyright (c) 2009, 2010, 2011, 2012, 2013, B3log Team
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.b3log.solo.processor.renderer;
import java.io.PrintWriter;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.b3log.latke.Keys;
import org.b3log.latke.cache.PageCaches;
import org.b3log.latke.ioc.LatkeBeanManager;
import org.b3log.latke.ioc.Lifecycle;
import org.b3log.latke.logging.Level;
import org.b3log.latke.logging.Logger;
import org.b3log.latke.servlet.HTTPRequestContext;
import org.b3log.latke.servlet.renderer.freemarker.CacheFreeMarkerRenderer;
import org.b3log.solo.model.Common;
import org.b3log.solo.processor.util.TopBars;
import org.b3log.solo.service.StatisticMgmtService;
/**
* <a href="http://freemarker.org">FreeMarker</a> HTTP response
* renderer.
*
* @author <a href="http://88250.b3log.org">Liang Ding</a>
* @version 1.0.0.7, Jul 16, 2012
* @since 0.3.1
*/
public final class FrontRenderer extends CacheFreeMarkerRenderer {
/**
* Logger.
*/
private static final Logger LOGGER = Logger.getLogger(FrontRenderer.class.getName());
/**
* {@inheritDoc}
*
* <p>
* Puts the top bar replacement flag into data model.
* </p>
*/
@Override
protected void beforeRender(final HTTPRequestContext context) throws Exception {
LOGGER.log(Level.TRACE, "Before render....");
getDataModel().put(Common.TOP_BAR_REPLACEMENT_FLAG_KEY, Common.TOP_BAR_REPLACEMENT_FLAG);
}
@Override
protected void doRender(final String html, final HttpServletRequest request, final HttpServletResponse response)
throws Exception {
LOGGER.log(Level.TRACE, "Do render....");
response.setContentType("text/html");
response.setCharacterEncoding("UTF-8");
PrintWriter writer;
try {
writer = response.getWriter();
} catch (final Exception e) {
writer = new PrintWriter(response.getOutputStream());
}
if (response.isCommitted()) { // response has been sent redirect
writer.flush();
writer.close();
return;
}
final String pageContent = (String) request.getAttribute(PageCaches.CACHED_CONTENT);
String output = html;
final LatkeBeanManager beanManager = Lifecycle.getBeanManager();
if (null != pageContent) {
final TopBars topbars = beanManager.getReference(TopBars.class);
// Adds the top bar HTML content for output
final String topBarHTML = topbars.getTopBarHTML(request, response);
output = html.replace(Common.TOP_BAR_REPLACEMENT_FLAG, topBarHTML);
}
final StatisticMgmtService statisticMgmtService = beanManager.getReference(StatisticMgmtService.class);
// Inc blog view count
try {
statisticMgmtService.incBlogViewCount(request, response);
} catch (final Exception e) {
LOGGER.log(Level.WARN, "Incs blog view count failed", e);
}
// Write out
writer.write(output);
writer.flush();
writer.close();
}
/**
* {@inheritDoc}
*
* <p>
* Skips page caching if requested by mobile device.
* </p>
*/
@Override
protected void afterRender(final HTTPRequestContext context) throws Exception {
LOGGER.log(Level.TRACE, "After render....");
final HttpServletRequest request = context.getRequest();
if ("mobile".equals((String) request.getAttribute(Keys.TEMAPLTE_DIR_NAME))) {
// Skips page caching if requested by mobile device
return;
}
super.afterRender(context);
}
}
......@@ -19,11 +19,13 @@ package org.b3log.solo.processor.util;
import freemarker.template.Template;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import javax.inject.Inject;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.apache.commons.lang.StringEscapeUtils;
import org.apache.commons.lang.time.DateFormatUtils;
import org.b3log.latke.Keys;
......@@ -56,6 +58,7 @@ import org.b3log.solo.service.StatisticQueryService;
import org.b3log.solo.service.TagQueryService;
import org.b3log.solo.service.UserQueryService;
import org.b3log.solo.util.Thumbnails;
import org.b3log.solo.util.comparator.Comparators;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
......@@ -65,7 +68,7 @@ import org.json.JSONObject;
* Filler utilities.
*
* @author <a href="http://88250.b3log.org">Liang Ding</a>
* @version 1.0.6.7, Jul 11, 2013
* @version 1.0.6.9, Oct 29, 2013
* @since 0.3.1
*/
@Service
......@@ -76,6 +79,12 @@ public class Filler {
*/
private static final Logger LOGGER = Logger.getLogger(Filler.class.getName());
/**
* Topbar utilities.
*/
@Inject
private TopBars topBars;
/**
* Article repository.
*/
......@@ -153,6 +162,12 @@ public class Filler {
@Inject
private FillTagArticles fillTagArticles;
/**
* Event manager.
*/
@Inject
private EventManager eventManager;
/**
* Fills articles in index.ftl.
*
......@@ -272,6 +287,34 @@ public class Filler {
Stopwatchs.end();
}
/**
* Fills tags.
*
* @param dataModel data model
* @throws ServiceException service exception
*/
public void fillTags(final Map<String, Object> dataModel) throws ServiceException {
Stopwatchs.start("Fill Tags");
try {
final List<JSONObject> tags = tagQueryService.getTags();
tagQueryService.removeForUnpublishedArticles(tags);
Collections.sort(tags, Comparators.TAG_REF_CNT_COMPARATOR);
dataModel.put(Tag.TAGS, tags);
} catch (final JSONException e) {
LOGGER.log(Level.ERROR, "Fills tags failed", e);
throw new ServiceException(e);
} catch (final RepositoryException e) {
LOGGER.log(Level.ERROR, "Fills tagss failed", e);
throw new ServiceException(e);
} finally {
Stopwatchs.end();
}
Stopwatchs.end();
}
/**
* Fills most used tags.
*
......@@ -526,7 +569,7 @@ public class Filler {
data.setViewName("footer.ftl");
data.setDataModel(dataModel);
EventManager.getInstance().fireEventSynchronously(new Event<ViewLoadEventData>(Keys.FREEMARKER_ACTION, data));
eventManager.fireEventSynchronously(new Event<ViewLoadEventData>(Keys.FREEMARKER_ACTION, data));
if (Strings.isEmptyOrNull((String) dataModel.get(Plugin.PLUGINS))) {
// There is no plugin for this template, fill ${plugins} with blank.
dataModel.put(Plugin.PLUGINS, "");
......@@ -546,15 +589,21 @@ public class Filler {
* Fills header.ftl.
*
* @param request the specified HTTP servlet request
* @param response the specified HTTP servlet response
* @param dataModel data model
* @param preference the specified preference
* @throws ServiceException service exception
*/
public void fillBlogHeader(final HttpServletRequest request, final Map<String, Object> dataModel, final JSONObject preference)
public void fillBlogHeader(final HttpServletRequest request, final HttpServletResponse response,
final Map<String, Object> dataModel, final JSONObject preference)
throws ServiceException {
Stopwatchs.start("Fill Header");
try {
LOGGER.debug("Filling header....");
final String topBarHTML = topBars.getTopBarHTML(request, response);
dataModel.put(Common.TOP_BAR, topBarHTML);
dataModel.put(Preference.ARTICLE_LIST_DISPLAY_COUNT, preference.getInt(Preference.ARTICLE_LIST_DISPLAY_COUNT));
dataModel.put(Preference.ARTICLE_LIST_PAGINATION_WINDOW_SIZE, preference.getInt(Preference.ARTICLE_LIST_PAGINATION_WINDOW_SIZE));
dataModel.put(Preference.LOCALE_STRING, preference.getString(Preference.LOCALE_STRING));
......@@ -564,6 +613,7 @@ public class Filler {
dataModel.put(Preference.META_KEYWORDS, preference.getString(Preference.META_KEYWORDS));
dataModel.put(Preference.META_DESCRIPTION, preference.getString(Preference.META_DESCRIPTION));
dataModel.put(Common.YEAR, String.valueOf(Calendar.getInstance().get(Calendar.YEAR)));
dataModel.put(Common.IS_LOGGED_IN, null != userQueryService.getCurrentUser(request));
final String noticeBoard = preference.getString(Preference.NOTICE_BOARD);
......@@ -686,13 +736,14 @@ public class Filler {
/**
* Fills the specified template.
*
* @param request the specified HTTP servlet request
* @param template the specified template
* @param dataModel data model
* @param preference the specified preference
* @throws ServiceException service exception
*/
public void fillUserTemplate(final Template template, final Map<String, Object> dataModel, final JSONObject preference)
throws ServiceException {
public void fillUserTemplate(final HttpServletRequest request, final Template template,
final Map<String, Object> dataModel, final JSONObject preference) throws ServiceException {
Stopwatchs.start("Fill User Template[name=" + template.getName() + "]");
try {
LOGGER.log(Level.DEBUG, "Filling user template[name{0}]", template.getName());
......@@ -701,6 +752,10 @@ public class Filler {
fillLinks(dataModel);
}
if (Templates.hasExpression(template, "<#list tags as tag>")) {
fillTags(dataModel);
}
if (Templates.hasExpression(template, "<#list recentComments as comment>")) {
fillRecentComments(dataModel, preference);
}
......@@ -721,6 +776,10 @@ public class Filler {
fillArchiveDates(dataModel, preference);
}
if (Templates.hasExpression(template, "<#include \"side.ftl\"/>")) {
fillSide(request, dataModel, preference);
}
final String noticeBoard = preference.getString(Preference.NOTICE_BOARD);
dataModel.put(Preference.NOTICE_BOARD, noticeBoard);
......@@ -783,10 +842,11 @@ public class Filler {
}
/**
* Sets some extra properties into the specified article with the specified
* author and preference, performs content and abstract editor processing.
* Sets some extra properties into the specified article with the specified author and preference, performs content and abstract editor
* processing.
*
* <p> Article ext properties:
* <p>
* Article ext properties:
* <pre>
* {
* ....,
......@@ -828,10 +888,10 @@ public class Filler {
}
/**
* Sets some extra properties into the specified article with the specified
* preference, performs content and abstract editor processing.
* Sets some extra properties into the specified article with the specified preference, performs content and abstract editor processing.
*
* <p> Article ext properties:
* <p>
* Article ext properties:
* <pre>
* {
* ....,
......@@ -872,14 +932,14 @@ public class Filler {
}
/**
* Sets some extra properties into the specified article with the specified
* author and preference.
* Sets some extra properties into the specified article with the specified author and preference.
*
* <p> The batch version of method
* {@linkplain #setArticleExProperties(org.json.JSONObject, org.json.JSONObject)}.
* <p>
* The batch version of method {@linkplain #setArticleExProperties(org.json.JSONObject, org.json.JSONObject)}.
* </p>
*
* <p> Article ext properties:
* <p>
* Article ext properties:
* <pre>
* {
* ....,
......@@ -903,14 +963,14 @@ public class Filler {
}
/**
* Sets some extra properties into the specified article with the specified
* preference.
* Sets some extra properties into the specified article with the specified preference.
*
* <p> The batch version of method
* {@linkplain #setArticleExProperties(org.json.JSONObject, org.json.JSONObject)}.
* <p>
* The batch version of method {@linkplain #setArticleExProperties(org.json.JSONObject, org.json.JSONObject)}.
* </p>
*
* <p> Article ext properties:
* <p>
* Article ext properties:
* <pre>
* {
* ....,
......
......@@ -136,8 +136,6 @@ public class TopBars {
topBarModel.put(Common.IS_ADMIN, Role.ADMIN_ROLE.equals(currentUser.getString(User.USER_ROLE)));
topBarModel.put(Common.IS_VISITOR, Role.VISITOR_ROLE.equals(currentUser.getString(User.USER_ROLE)));
topBarModel.put("clearAllCacheLabel", langPropsService.get("clearAllCacheLabel"));
topBarModel.put("clearCacheLabel", langPropsService.get("clearCacheLabel"));
topBarModel.put("adminLabel", langPropsService.get("adminLabel"));
topBarModel.put("logoutLabel", langPropsService.get("logoutLabel"));
......
......@@ -39,7 +39,7 @@ import org.json.JSONObject;
* @since 0.3.1
*/
@Repository
public final class ArchiveDateArticleRepositoryImpl extends AbstractRepository implements ArchiveDateArticleRepository {
public class ArchiveDateArticleRepositoryImpl extends AbstractRepository implements ArchiveDateArticleRepository {
/**
* Public constructor.
......
......@@ -45,7 +45,7 @@ import org.json.JSONObject;
* @since 0.3.1
*/
@Repository
public final class ArchiveDateRepositoryImpl extends AbstractRepository implements ArchiveDateRepository {
public class ArchiveDateRepositoryImpl extends AbstractRepository implements ArchiveDateRepository {
/**
* Logger.
......
......@@ -46,7 +46,7 @@ import org.json.JSONObject;
* @since 0.3.1
*/
@Repository
public final class ArticleRepositoryImpl extends AbstractRepository implements ArticleRepository {
public class ArticleRepositoryImpl extends AbstractRepository implements ArticleRepository {
/**
* Logger.
......
......@@ -16,12 +16,10 @@
package org.b3log.solo.repository.impl;
import java.io.Serializable;
import java.util.Iterator;
import java.util.List;
import javax.inject.Inject;
import org.b3log.latke.Keys;
import org.b3log.latke.cache.Cache;
import org.b3log.latke.logging.Level;
import org.b3log.latke.logging.Logger;
import org.b3log.latke.repository.AbstractRepository;
......@@ -48,7 +46,7 @@ import org.json.JSONObject;
* @since 0.3.1
*/
@Repository
public final class CommentRepositoryImpl extends AbstractRepository implements CommentRepository {
public class CommentRepositoryImpl extends AbstractRepository implements CommentRepository {
/**
* Logger.
......@@ -68,11 +66,6 @@ public final class CommentRepositoryImpl extends AbstractRepository implements C
super(Comment.COMMENT);
}
/**
* Recent comments query results cache key.
*/
public static final String RECENT_CMTS_CACHE_KEY = "recentCMTs";
@Override
public int removeComments(final String onId) throws RepositoryException {
final List<JSONObject> comments = getComments(onId, 1, Integer.MAX_VALUE);
......@@ -104,15 +97,6 @@ public final class CommentRepositoryImpl extends AbstractRepository implements C
@Override
@SuppressWarnings("unchecked")
public List<JSONObject> getRecentComments(final int num) throws RepositoryException {
if (isCacheEnabled()) {
final Cache<String, Serializable> cache = getCache();
final Object ret = cache.get(RECENT_CMTS_CACHE_KEY);
if (null != ret) {
return (List<JSONObject>) ret;
}
}
final Query query = new Query().addSort(Keys.OBJECT_ID, SortDirection.DESCENDING).setCurrentPageNum(1).setPageSize(num).setPageCount(
1);
......@@ -126,12 +110,6 @@ public final class CommentRepositoryImpl extends AbstractRepository implements C
// Removes unpublished article related comments
removeForUnpublishedArticles(ret);
if (isCacheEnabled()) {
final Cache<String, Serializable> cache = getCache();
cache.put(RECENT_CMTS_CACHE_KEY, (Serializable) ret);
}
return ret;
}
......
......@@ -38,7 +38,7 @@ import org.json.JSONObject;
* @since 0.3.1
*/
@Repository
public final class LinkRepositoryImpl extends AbstractRepository implements LinkRepository {
public class LinkRepositoryImpl extends AbstractRepository implements LinkRepository {
/**
* Public constructor.
......
......@@ -30,7 +30,7 @@ import org.b3log.solo.repository.OptionRepository;
* @since 0.6.0
*/
@Repository
public final class OptionRepositoryImpl extends AbstractRepository implements OptionRepository {
public class OptionRepositoryImpl extends AbstractRepository implements OptionRepository {
/**
* Public constructor.
......
......@@ -40,7 +40,7 @@ import org.json.JSONObject;
* @since 0.3.1
*/
@Repository
public final class PageRepositoryImpl extends AbstractRepository implements PageRepository {
public class PageRepositoryImpl extends AbstractRepository implements PageRepository {
/**
* Public constructor.
......
......@@ -30,7 +30,7 @@ import org.b3log.solo.repository.PluginRepository;
* @since 0.3.1
*/
@Repository
public final class PluginRepositoryImpl extends AbstractRepository implements PluginRepository {
public class PluginRepositoryImpl extends AbstractRepository implements PluginRepository {
/**
* Public constructor.
......
......@@ -32,7 +32,7 @@ import org.json.JSONObject;
* @since 0.3.1
*/
@Repository
public final class PreferenceRepositoryImpl extends AbstractRepository implements PreferenceRepository {
public class PreferenceRepositoryImpl extends AbstractRepository implements PreferenceRepository {
/**
* Public constructor.
......
......@@ -16,14 +16,10 @@
package org.b3log.solo.repository.impl;
import org.b3log.latke.Latkes;
import org.b3log.latke.repository.AbstractRepository;
import org.b3log.latke.repository.RepositoryException;
import org.b3log.latke.repository.annotation.Repository;
import org.b3log.solo.model.Statistic;
import org.b3log.solo.repository.StatisticRepository;
import org.b3log.solo.service.StatisticMgmtService;
import org.json.JSONObject;
/**
......@@ -34,7 +30,7 @@ import org.json.JSONObject;
* @since 0.3.1
*/
@Repository
public final class StatisticRepositoryImpl extends AbstractRepository implements StatisticRepository {
public class StatisticRepositoryImpl extends AbstractRepository implements StatisticRepository {
/**
* Public constructor.
......@@ -42,13 +38,4 @@ public final class StatisticRepositoryImpl extends AbstractRepository implements
public StatisticRepositoryImpl() {
super(Statistic.STATISTIC);
}
@Override
public void update(final String id, final JSONObject jsonObject) throws RepositoryException {
super.update(id, jsonObject);
if (Latkes.isDataCacheEnabled()) {
getCache().put(StatisticMgmtService.REPOSITORY_CACHE_KEY_PREFIX + Statistic.STATISTIC, jsonObject);
}
}
}
......@@ -41,7 +41,7 @@ import org.json.JSONObject;
* @since 0.3.1
*/
@Repository
public final class TagArticleRepositoryImpl extends AbstractRepository implements TagArticleRepository {
public class TagArticleRepositoryImpl extends AbstractRepository implements TagArticleRepository {
/**
* Public constructor.
......
......@@ -43,7 +43,7 @@ import org.json.JSONObject;
* @since 0.3.1
*/
@Repository
public final class TagRepositoryImpl extends AbstractRepository implements TagRepository {
public class TagRepositoryImpl extends AbstractRepository implements TagRepository {
/**
* Public constructor.
......
......@@ -38,7 +38,7 @@ import org.json.JSONObject;
* @since 0.3.1
*/
@Repository
public final class UserRepositoryImpl extends AbstractRepository implements UserRepository {
public class UserRepositoryImpl extends AbstractRepository implements UserRepository {
/**
* Public constructor.
......
......@@ -49,7 +49,6 @@ import org.b3log.solo.repository.TagArticleRepository;
import org.b3log.solo.repository.TagRepository;
import org.b3log.solo.repository.UserRepository;
import org.b3log.solo.util.Comments;
import org.b3log.solo.util.TimeZones;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
......@@ -59,7 +58,7 @@ import org.json.JSONObject;
* Article management service.
*
* @author <a href="http://88250.b3log.org">Liang Ding</a>
* @version 1.0.1.5, Jan 30, 2013
* @version 1.0.1.6, Oct 26, 2013
* @since 0.3.5
*/
@Service
......@@ -133,7 +132,8 @@ public class ArticleMgmtService {
/**
* Event manager.
*/
private EventManager eventManager = EventManager.getInstance();
@Inject
private EventManager eventManager;
/**
* Language service.
......@@ -293,8 +293,7 @@ public class ArticleMgmtService {
// Set date
article.put(ARTICLE_UPDATE_DATE, oldArticle.get(ARTICLE_UPDATE_DATE));
final JSONObject preference = preferenceQueryService.getPreference();
final String timeZoneId = preference.getString(Preference.TIME_ZONE_ID);
final Date date = TimeZones.getTime(timeZoneId);
final Date date = new Date();
// The article to update has no sign
if (!article.has(Article.ARTICLE_SIGN_ID)) {
......@@ -437,18 +436,12 @@ public class ArticleMgmtService {
transaction.commit();
return ret;
} catch (final ServiceException e) {
if (transaction.isActive()) {
transaction.rollback();
}
throw e;
} catch (final Exception e) {
if (transaction.isActive()) {
transaction.rollback();
}
throw new ServiceException(e);
throw new ServiceException(e.getMessage());
}
}
......@@ -478,8 +471,7 @@ public class ArticleMgmtService {
article.put(Article.ARTICLE_VIEW_COUNT, 0);
// Step 3: Set create/updat date
final JSONObject preference = preferenceQueryService.getPreference();
final String timeZoneId = preference.optString(Preference.TIME_ZONE_ID);
final Date date = TimeZones.getTime(timeZoneId);
final Date date = new Date();
if (!article.has(Article.ARTICLE_CREATE_DATE)) {
article.put(Article.ARTICLE_CREATE_DATE, date);
......@@ -610,7 +602,6 @@ public class ArticleMgmtService {
throws ServiceException {
final Transaction transaction = articleRepository.beginTransaction();
transaction.clearQueryCache(false);
try {
final List<JSONObject> randomArticles = articleRepository.getRandomly(updateCnt);
......@@ -1151,7 +1142,6 @@ public class ArticleMgmtService {
throw new ServiceException(langPropsService.get("duplicatedPermalinkLabel"));
}
// TODO: SBC case
return ret.replaceAll(" ", "-");
}
......@@ -1190,7 +1180,6 @@ public class ArticleMgmtService {
}
}
// TODO: SBC case
return ret.replaceAll(" ", "-");
}
......
......@@ -47,7 +47,6 @@ import org.b3log.solo.repository.CommentRepository;
import org.b3log.solo.repository.PageRepository;
import org.b3log.solo.util.Comments;
import org.b3log.solo.util.Thumbnails;
import org.b3log.solo.util.TimeZones;
import org.json.JSONException;
import org.json.JSONObject;
......@@ -106,7 +105,8 @@ public class CommentMgmtService {
/**
* Event manager.
*/
private static EventManager eventManager = EventManager.getInstance();
@Inject
private static EventManager eventManager;
/**
* Default user thumbnail.
......@@ -401,8 +401,7 @@ public class CommentMgmtService {
comment.put(Comment.COMMENT_URL, commentURL);
comment.put(Comment.COMMENT_CONTENT, commentContent);
final JSONObject preference = preferenceQueryService.getPreference();
final String timeZoneId = preference.getString(Preference.TIME_ZONE_ID);
final Date date = TimeZones.getTime(timeZoneId);
final Date date = new Date();
comment.put(Comment.COMMENT_DATE, date);
ret.put(Comment.COMMENT_DATE, DateFormatUtils.format(date, "yyyy-MM-dd hh:mm:ss"));
......@@ -521,8 +520,7 @@ public class CommentMgmtService {
comment.put(Comment.COMMENT_ORIGINAL_COMMENT_ID, requestJSONObject.optString(Comment.COMMENT_ORIGINAL_COMMENT_ID));
comment.put(Comment.COMMENT_ORIGINAL_COMMENT_NAME, requestJSONObject.optString(Comment.COMMENT_ORIGINAL_COMMENT_NAME));
final JSONObject preference = preferenceQueryService.getPreference();
final String timeZoneId = preference.getString(Preference.TIME_ZONE_ID);
final Date date = TimeZones.getTime(timeZoneId);
final Date date = new Date();
comment.put(Comment.COMMENT_DATE, date);
ret.put(Comment.COMMENT_DATE, DateFormatUtils.format(date, "yyyy-MM-dd hh:mm:ss"));
......
......@@ -33,6 +33,7 @@ import org.b3log.latke.logging.Level;
import org.b3log.latke.logging.Logger;
import org.b3log.latke.model.Role;
import org.b3log.latke.model.User;
import org.b3log.latke.plugin.PluginManager;
import org.b3log.latke.repository.RepositoryException;
import org.b3log.latke.repository.Transaction;
import org.b3log.latke.repository.jdbc.util.JdbcRepositories;
......@@ -142,6 +143,12 @@ public class InitService {
@Inject
private LangPropsService langPropsService;
/**
* Plugin manager.
*/
@Inject
private PluginManager pluginManager;
/**
* Determines Solo had been initialized.
*
......@@ -252,6 +259,8 @@ public class InitService {
LOGGER.log(Level.ERROR, "Hello World error?!", e);
}
pluginManager.load();
}
/**
......@@ -274,7 +283,7 @@ public class InitService {
article.put(Article.ARTICLE_SIGN_ID, "1");
article.put(Article.ARTICLE_COMMENT_COUNT, 1);
article.put(Article.ARTICLE_VIEW_COUNT, 0);
final Date date = TimeZones.getTime(INIT_TIME_ZONE_ID);
final Date date = new Date();
article.put(Article.ARTICLE_CREATE_DATE, date);
article.put(Article.ARTICLE_UPDATE_DATE, date);
......@@ -552,7 +561,6 @@ public class InitService {
ret.put(ENABLE_ARTICLE_UPDATE_HINT, Default.DEFAULT_ENABLE_ARTICLE_UPDATE_HINT);
ret.put(SIGNS, Default.DEFAULT_SIGNS);
ret.put(TIME_ZONE_ID, Default.DEFAULT_TIME_ZONE);
ret.put(PAGE_CACHE_ENABLED, Default.DEFAULT_PAGE_CACHE_ENABLED);
ret.put(ALLOW_VISIT_DRAFT_VIA_PERMALINK, Default.DEFAULT_ALLOW_VISIT_DRAFT_VIA_PERMALINK);
ret.put(COMMENTABLE, Default.DEFAULT_COMMENTABLE);
ret.put(VERSION, SoloServletListener.VERSION);
......@@ -598,12 +606,6 @@ public class InitService {
TimeZones.setTimeZone(INIT_TIME_ZONE_ID);
if (Default.DEFAULT_PAGE_CACHE_ENABLED) {
Latkes.enablePageCache();
} else {
Latkes.disablePageCache();
}
ret.put(Keys.OBJECT_ID, PREFERENCE);
preferenceRepository.add(ret);
......@@ -701,4 +703,13 @@ public class InitService {
public void setLangPropsService(final LangPropsService langPropsService) {
this.langPropsService = langPropsService;
}
/**
* Sets the plugin manager with the specified plugin manager.
*
* @param pluginManager the specified plugin manager
*/
public void setPluginManager(final PluginManager pluginManager) {
this.pluginManager = pluginManager;
}
}
......@@ -160,7 +160,6 @@ public class PageMgmtService {
}
}
// TODO: SBC case
newPage.put(Page.PAGE_PERMALINK, permalink.replaceAll(" ", "-"));
if (!oldPage.getString(Page.PAGE_PERMALINK).equals(permalink)) { // The permalink has been updated
......@@ -274,7 +273,6 @@ public class PageMgmtService {
}
}
// TODO: SBC case
page.put(Page.PAGE_PERMALINK, permalink.replaceAll(" ", "-"));
// Editor type
......
......@@ -19,6 +19,7 @@ package org.b3log.solo.service;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import javax.inject.Inject;
import org.b3log.latke.Latkes;
import org.b3log.latke.logging.Level;
import org.b3log.latke.logging.Logger;
import org.b3log.latke.repository.RepositoryException;
......@@ -32,7 +33,7 @@ import org.b3log.solo.repository.PageRepository;
* Permalink query service.
*
* @author <a href="http://88250.b3log.org">Liang Ding</a>
* @version 1.0.0.0, Jun 21, 2013
* @version 1.0.0.1, Oct 26, 2013
* @since 0.6.1
*/
@Service
......@@ -65,7 +66,7 @@ public class PermalinkQueryService {
"/login", "/logout", "/forgot", "/get-article-content", "/admin-index.do", "/admin-article.do", "/admin-article-list.do",
"/admin-link-list.do", "/admin-preference.do", "/admin-file-list.do", "/admin-page-list.do", "/admin-others.do",
"/admin-draft-list.do", "/admin-user-list.do", "/admin-plugin-list.do", "/admin-main.do", "/admin-about.do", "/admin-label",
"/admin-about.do", "/rm-all-data.do", "/init", "/clear-cache.do", "/register.html"
"/admin-about.do", "/rm-all-data.do", "/init", "/register.html"
};
/**
......@@ -148,8 +149,7 @@ public class PermalinkQueryService {
* @param permalink the specified user-defined permalink
* @return {@code true} if invalid, returns {@code false} otherwise
*/
private static boolean invalidUserDefinedPermalinkFormat(
final String permalink) {
private static boolean invalidUserDefinedPermalinkFormat(final String permalink) {
if (Strings.isEmptyOrNull(permalink)) {
return true;
}
......@@ -159,8 +159,7 @@ public class PermalinkQueryService {
}
if (Strings.isNumeric(permalink.substring(1))) {
// See issue 120 (http://code.google.com/p/b3log-solo/issues/detail?id=120#c4)
// for more details
// See issue 120 (http://code.google.com/p/b3log-solo/issues/detail?id=120#c4) for more details
return true;
}
......@@ -176,9 +175,7 @@ public class PermalinkQueryService {
}
}
// FIXME: URL format check
return false;
return !Strings.isURL(Latkes.getServer() + permalink);
}
/**
......
......@@ -66,6 +66,18 @@ public class PluginMgmtService {
@Inject
private LangPropsService langPropsService;
/**
* Initialization service.
*/
@Inject
private InitService initService;
/**
* Plugin manager.
*/
@Inject
private PluginManager pluginManager;
/**
* Updates datastore plugin descriptions with the specified plugins.
*
......@@ -73,13 +85,14 @@ public class PluginMgmtService {
* @throws Exception exception
*/
public void refresh(final List<AbstractPlugin> plugins) throws Exception {
if (!initService.isInited()) {
return;
}
final JSONObject result = pluginRepository.get(new Query());
final JSONArray pluginArray = result.getJSONArray(Keys.RESULTS);
final List<JSONObject> persistedPlugins = CollectionUtils.jsonArrayToList(pluginArray);
// Disables plugin repository cache to avoid remove all cache
pluginRepository.setCacheEnabled(false);
try {
// Reads plugin status from datastore and clear plugin datastore
for (final JSONObject oldPluginDesc : persistedPlugins) {
......@@ -115,8 +128,6 @@ public class PluginMgmtService {
} catch (final Exception e) {
LOGGER.log(Level.ERROR, "Refresh plugins failed", e);
}
pluginRepository.setCacheEnabled(true);
}
/**
......@@ -156,7 +167,6 @@ public class PluginMgmtService {
public JSONObject setPluginStatus(final String pluginId, final String status) {
final Map<String, String> langs = langPropsService.getAll(Latkes.getLocale());
final PluginManager pluginManager = PluginManager.getInstance();
final List<AbstractPlugin> plugins = pluginManager.getPlugins();
final JSONObject ret = new JSONObject();
......@@ -210,7 +220,6 @@ public class PluginMgmtService {
final Map<String, String> langs = langPropsService.getAll(Latkes.getLocale());
final PluginManager pluginManager = PluginManager.getInstance();
final List<AbstractPlugin> plugins = pluginManager.getPlugins();
final JSONObject ret = new JSONObject();
......
......@@ -55,6 +55,12 @@ public class PluginQueryService {
@Inject
private PluginRepository pluginRepository;
/**
* Plugin manager.
*/
@Inject
private PluginManager pluginManager;
/**
* Gets plugins by the specified request json object.
*
......@@ -94,7 +100,7 @@ public class PluginQueryService {
final int windowSize = requestJSONObject.getInt(Pagination.PAGINATION_WINDOW_SIZE);
final List<JSONObject> pluginJSONObjects = new ArrayList<JSONObject>();
final List<AbstractPlugin> plugins = PluginManager.getInstance().getPlugins();
final List<AbstractPlugin> plugins = pluginManager.getPlugins();
for (final AbstractPlugin plugin : plugins) {
final JSONObject jsonObject = plugin.toJSONObject();
......@@ -126,7 +132,7 @@ public class PluginQueryService {
}
/**
* get the setting(json formatter) of the plugin(from database not cache which does not contains it) by the specified pluginoId.
* get the setting(json formatter) of the plugin by the specified pluginoId.
*
* @param pluginId the specified pluginId
* @return the {@link AbstractPlugin}
......
......@@ -27,8 +27,6 @@ import java.util.Locale;
import java.util.Set;
import javax.inject.Inject;
import org.b3log.latke.Latkes;
import org.b3log.latke.RuntimeEnv;
import org.b3log.latke.cache.PageCaches;
import org.b3log.latke.logging.Level;
import org.b3log.latke.logging.Logger;
import org.b3log.latke.repository.RepositoryException;
......@@ -82,12 +80,10 @@ public class PreferenceMgmtService {
private LangPropsService langPropsService;
/**
* Loads skins for the specified preference and initializes templates
* loading.
* Loads skins for the specified preference and initializes templates loading.
*
* <p>
* If the skins directory has been changed, persists the change into
* preference.
* If the skins directory has been changed, persists the change into preference.
* </p>
*
* @param preference the specified preference
......@@ -109,6 +105,7 @@ public class PreferenceMgmtService {
if (null == name) {
LOGGER.log(Level.WARN, "The directory[{0}] does not contain any skin, ignored it", dirName);
continue;
}
......@@ -130,15 +127,13 @@ public class PreferenceMgmtService {
LOGGER.log(Level.ERROR, "Can not find skin[dirName=ease]");
throw new IllegalStateException(
"Can not find default skin[dirName=ease], please redeploy your B3log Solo and make sure "
+ "contains this default skin!");
"Can not find default skin[dirName=ease], please redeploy your B3log Solo and make sure contains this default skin!");
}
preference.put(SKIN_DIR_NAME, "ease");
preference.put(SKIN_NAME, "ease");
updatePreference(preference);
PageCaches.removeAll(); // Clears cache manually.
}
final String skinsString = skinArray.toString();
......@@ -147,20 +142,6 @@ public class PreferenceMgmtService {
LOGGER.log(Level.INFO, "The skins directory has been changed, persists " + "the change into preference");
preference.put(SKINS, skinsString);
updatePreference(preference);
PageCaches.removeAll(); // Clears cache manually.
}
boolean prefsPageCacheEnabled = preference.getBoolean(Preference.PAGE_CACHE_ENABLED);
if (!Latkes.isPageCacheEnabled() && prefsPageCacheEnabled) {
preference.put(Preference.PAGE_CACHE_ENABLED, false);
}
prefsPageCacheEnabled = preference.getBoolean(Preference.PAGE_CACHE_ENABLED);
if (prefsPageCacheEnabled) {
Latkes.enablePageCache();
} else {
Latkes.disablePageCache();
}
setDirectoryForTemplateLoading(preference.getString(SKIN_DIR_NAME));
......@@ -177,11 +158,9 @@ public class PreferenceMgmtService {
}
/**
* Updates the reply notification template with the specified reply
* notification template.
* Updates the reply notification template with the specified reply notification template.
*
* @param replyNotificationTemplate the specified reply notification
* template
* @param replyNotificationTemplate the specified reply notification template
* @throws ServiceException service exception
*/
public void updateReplyNotificationTemplate(final JSONObject replyNotificationTemplate) throws ServiceException {
......@@ -218,8 +197,6 @@ public class PreferenceMgmtService {
}
}
// TODO: checks preference
final Transaction transaction = preferenceRepository.beginTransaction();
try {
......@@ -244,7 +221,6 @@ public class PreferenceMgmtService {
final String skinPath = webRootPath + Skin.SKINS + "/" + skinDirName;
LOGGER.log(Level.DEBUG, "Skin path[{0}]", skinPath);
Templates.CACHE.clear();
preference.put(Skin.SKINS, skinArray.toString());
......@@ -259,26 +235,6 @@ public class PreferenceMgmtService {
preference.put(ADMIN_EMAIL, adminEmail);
if (!preference.has(PAGE_CACHE_ENABLED)) {
preference.put(PAGE_CACHE_ENABLED, oldPreference.getBoolean(PAGE_CACHE_ENABLED));
} else {
if (RuntimeEnv.BAE == Latkes.getRuntimeEnv()) {
// XXX: Ignores user's setting, uses default
// https://github.com/b3log/b3log-solo/issues/73
preference.put(PAGE_CACHE_ENABLED, Default.DEFAULT_PAGE_CACHE_ENABLED);
}
}
final String maxPageCntStr = Latkes.getMaxPageCacheCnt();
if (Integer.valueOf(maxPageCntStr) <= 0) {
preference.put(PAGE_CACHE_ENABLED, false);
}
final boolean pageCacheEnabled = preference.getBoolean(Preference.PAGE_CACHE_ENABLED);
Templates.enableCache(pageCacheEnabled);
final String version = oldPreference.optString(VERSION);
if (!Strings.isEmptyOrNull(version)) {
......@@ -295,12 +251,6 @@ public class PreferenceMgmtService {
transaction.commit();
Templates.MAIN_CFG.setDirectoryForTemplateLoading(new File(skinPath));
if (preference.getBoolean(PAGE_CACHE_ENABLED)) {
Latkes.enablePageCache();
} else {
Latkes.disablePageCache();
}
} catch (final JSONException e) {
if (transaction.isActive()) {
transaction.rollback();
......
......@@ -16,18 +16,12 @@
package org.b3log.solo.service;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
import javax.inject.Inject;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.b3log.latke.Latkes;
import org.b3log.latke.cache.PageCaches;
import org.b3log.latke.logging.Level;
import org.b3log.latke.logging.Logger;
import org.b3log.latke.repository.RepositoryException;
......@@ -35,10 +29,7 @@ import org.b3log.latke.repository.Transaction;
import org.b3log.latke.service.LangPropsService;
import org.b3log.latke.service.ServiceException;
import org.b3log.latke.service.annotation.Service;
import org.b3log.latke.util.CollectionUtils;
import org.b3log.latke.util.Requests;
import org.b3log.solo.model.Article;
import org.b3log.solo.model.PageTypes;
import org.json.JSONObject;
import org.b3log.solo.model.Statistic;
import org.b3log.solo.repository.ArticleRepository;
......@@ -71,11 +62,6 @@ public class StatisticMgmtService {
@Inject
private StatisticRepository statisticRepository;
/**
* Flush size.
*/
private static final int FLUSH_SIZE = 30;
/**
* Language service.
*/
......@@ -88,11 +74,6 @@ public class StatisticMgmtService {
@Inject
private ArticleRepository articleRepository;
/**
* Repository cache prefix, refers to GAERepository#CACHE_KEY_PREFIX.
*/
public static final String REPOSITORY_CACHE_KEY_PREFIX = "repository";
/**
* Online visitor cache.
*
......@@ -147,7 +128,6 @@ public class StatisticMgmtService {
++blogViewCnt;
statistic.put(Statistic.STATISTIC_BLOG_VIEW_COUNT, blogViewCnt);
if (!Latkes.isDataCacheEnabled()) {
final Transaction transaction = statisticRepository.beginTransaction();
try {
......@@ -161,10 +141,6 @@ public class StatisticMgmtService {
LOGGER.log(Level.ERROR, "Updates blog view count failed", e);
}
} else {
// Repository cache prefix, Refers to GAERepository#CACHE_KEY_PREFIX
statisticRepository.getCache().putAsync(REPOSITORY_CACHE_KEY_PREFIX + Statistic.STATISTIC, statistic);
}
LOGGER.log(Level.DEBUG, "Inced blog view count[statistic={0}]", statistic);
}
......@@ -373,98 +349,6 @@ public class StatisticMgmtService {
LOGGER.log(Level.DEBUG, "Current online visitor count [{0}]", ONLINE_VISITORS.size());
}
/**
* Flushes the statistic to repository.
*
* @throws ServiceException
*/
public void flushStatistic() throws ServiceException {
if (!Latkes.isDataCacheEnabled()) {
return;
}
final JSONObject statistic = (JSONObject) statisticRepository.getCache().get(REPOSITORY_CACHE_KEY_PREFIX + Statistic.STATISTIC);
if (null == statistic) {
LOGGER.log(Level.INFO, "Not found statistic in cache, ignores sync");
return;
}
final Transaction transaction = statisticRepository.beginTransaction();
transaction.clearQueryCache(false);
try {
statisticRepository.getCache().remove(REPOSITORY_CACHE_KEY_PREFIX + Statistic.STATISTIC);
// For blog view counter
statisticRepository.update(Statistic.STATISTIC, statistic);
// For article view counter
final Set<String> keys = PageCaches.getKeys();
final List<String> keyList = new ArrayList<String>(keys);
final int size = keys.size() > FLUSH_SIZE ? FLUSH_SIZE : keys.size(); // Flush FLUSH_SIZE articles at most
final List<Integer> idx = CollectionUtils.getRandomIntegers(0, keys.size(), size);
final Set<String> cachedPageKeys = new HashSet<String>();
for (final Integer i : idx) {
cachedPageKeys.add(keyList.get(i));
}
for (final String cachedPageKey : cachedPageKeys) {
final JSONObject cachedPage = PageCaches.get(cachedPageKey);
if (null == cachedPage) {
continue;
}
final Map<String, String> langs = langPropsService.getAll(Latkes.getLocale());
if (!cachedPage.optString(PageCaches.CACHED_TYPE).equals(langs.get(PageTypes.ARTICLE.getLangeLabel()))) { // Cached is not an article page
continue;
}
final int hitCount = cachedPage.optInt(PageCaches.CACHED_HIT_COUNT);
final String articleId = cachedPage.optString(PageCaches.CACHED_OID);
final JSONObject article = articleRepository.get(articleId);
if (null == article) {
continue;
}
LOGGER.log(Level.DEBUG, "Updating article[id={0}, title={1}] view count",
new Object[] {articleId, cachedPage.optString(PageCaches.CACHED_TITLE)});
final int oldViewCount = article.optInt(Article.ARTICLE_VIEW_COUNT);
final int viewCount = oldViewCount + hitCount;
article.put(Article.ARTICLE_VIEW_COUNT, viewCount);
article.put(Article.ARTICLE_RANDOM_DOUBLE, Math.random()); // Updates random value
articleRepository.update(articleId, article);
cachedPage.put(PageCaches.CACHED_HIT_COUNT, 0);
LOGGER.log(Level.DEBUG, "Updating article[id={0}, title={1}] view count from [{2}] to [{3}]",
new Object[] {articleId, article.optString(Article.ARTICLE_TITLE), oldViewCount, viewCount});
}
transaction.commit();
LOGGER.log(Level.INFO, "Synchronized statistic from cache to repository[statistic={0}]", statistic);
} catch (final RepositoryException e) {
if (transaction.isActive()) {
transaction.rollback();
}
LOGGER.log(Level.ERROR, "Updates statistic failed", e);
}
}
/**
* Updates the statistic with the specified statistic.
*
......
......@@ -16,7 +16,6 @@
package org.b3log.solo.util;
import java.util.Date;
import java.util.TimeZone;
import org.b3log.latke.util.freemarker.Templates;
......@@ -25,28 +24,10 @@ import org.b3log.latke.util.freemarker.Templates;
* Time zone utilities.
*
* @author <a href="http://88250.b3log.org">Liang Ding</a>
* @version 1.0.0.4, Jan 18, 2013
* @version 1.0.0.5, Oct 30, 2013
*/
public final class TimeZones {
/**
* Gets the current date with the specified time zone id.
*
* @param timeZoneId the specified time zone id
* @return date
*/
public static Date getTime(final String timeZoneId) {
final TimeZone timeZone = TimeZone.getTimeZone(timeZoneId);
final TimeZone defaultTimeZone = TimeZone.getDefault();
TimeZone.setDefault(timeZone);
final Date ret = new Date();
TimeZone.setDefault(defaultTimeZone);
return ret;
}
/**
* Sets time zone by the specified time zone id.
*
......
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://java.sun.com/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/beans_1_0.xsd">
</beans>
......@@ -17,10 +17,12 @@ package org.b3log.solo;
import com.google.appengine.tools.development.testing.LocalDatastoreServiceTestConfig;
import com.google.appengine.tools.development.testing.LocalServiceTestHelper;
import java.util.Collection;
import java.util.Locale;
import org.b3log.latke.Latkes;
import org.b3log.latke.service.LangPropsService;
import org.b3log.latke.service.LangPropsServiceImpl;
import org.b3log.latke.ioc.LatkeBeanManager;
import org.b3log.latke.ioc.Lifecycle;
import org.b3log.latke.ioc.config.Discoverer;
import org.b3log.solo.repository.ArchiveDateArticleRepository;
import org.b3log.solo.repository.ArchiveDateRepository;
import org.b3log.solo.repository.ArticleRepository;
......@@ -55,7 +57,7 @@ import org.testng.annotations.BeforeClass;
* Abstract test case.
*
* @author <a href="http://88250.b3log.org">Liang Ding</a>
* @version 1.0.0.7, Jul 8, 2013
* @version 1.0.0.8, Oct 14, 2013
* @see #beforeClass()
* @see #afterClass()
*/
......@@ -68,184 +70,9 @@ public abstract class AbstractTestCase {
new LocalServiceTestHelper(new LocalDatastoreServiceTestConfig());
/**
* User repository.
* Bean manager.
*/
private UserRepository userRepository;
/**
* Link repository.
*/
private LinkRepository linkRepository;
/**
* Article repository.
*/
private ArticleRepository articleRepository;
/**
* Tag repository.
*/
private TagRepository tagRepository;
/**
* Tag-Article repository.
*/
private TagArticleRepository tagArticleRepository;
/**
* Page repository.
*/
private PageRepository pageRepository;
/**
* Comment repository.
*/
private CommentRepository commentRepository;
/**
* Archive date repository.
*/
private ArchiveDateRepository archiveDateRepository;
/**
* Archive date article repository.
*/
private ArchiveDateArticleRepository archiveDateArticleRepository;
/**
* Plugin repository.
*/
private PluginRepository pluginRepository;
/**
* Preference repository.
*/
private PreferenceRepository preferenceRepository;
/**
* Statistic repository.
*/
private StatisticRepository statisticRepository;
/**
* Option repository.
*/
private OptionRepository optionRepository;
/**
* Language service.
*/
private LangPropsService langPropsService;
/**
* Plugin management service.
*/
private PluginMgmtService pluginMgmtService;
/**
* Initialization service.
*/
private InitService initService;
/**
* User management service.
*/
private UserMgmtService userMgmtService;
/**
* User query service.
*/
private UserQueryService userQueryService;
/**
* Article management service.
*/
private ArticleMgmtService articleMgmtService;
/**
* Article query service.
*/
private ArticleQueryService articleQueryService;
/**
* Page management service.
*/
private PageMgmtService pageMgmtService;
/**
* Page query service.
*/
private PageQueryService pageQueryService;
/**
* Link management service.
*/
private LinkMgmtService linkMgmtService;
/**
* Link query service.
*/
private LinkQueryService linkQueryService;
/**
* Preference management service.
*/
private PreferenceMgmtService preferenceMgmtService;
/**
* Preference query service.
*/
private PreferenceQueryService preferenceQueryService;
/**
* Tag query service.
*/
private TagQueryService tagQueryService;
/**
* Tag management service.
*/
private TagMgmtService tagMgmtService;
/**
* Comment query service.
*/
private CommentQueryService commentQueryService;
/**
* Comment management service.
*/
private CommentMgmtService commentMgmtService;
/**
* Archive date query service.
*/
private ArchiveDateQueryService archiveDateQueryService;
/**
* Option management service.
*/
private OptionMgmtService optionMgmtService;
/**
* Option query service.
*/
private OptionQueryService optionQueryService;
/**
* Permalink query service.
*/
private PermalinkQueryService permalinkQueryService;
/**
* Statistic management service.
*/
private StatisticMgmtService statisticMgmtService;
/**
* Statistic query service.
*/
private StatisticQueryService statisticQueryService;
private LatkeBeanManager beanManager;
/**
* Before class.
......@@ -255,149 +82,19 @@ public abstract class AbstractTestCase {
* <li>Initializes Latke runtime</li>
* <li>Instantiates repositories</li>
* </ol>
* @throws Exception exception
*/
@BeforeClass
public void beforeClass() {
public void beforeClass() throws Exception {
localServiceTestHelper.setUp();
Latkes.initRuntimeEnv();
Latkes.setLocale(Locale.SIMPLIFIED_CHINESE);
// Repositories
userRepository = new UserRepositoryImpl();
linkRepository = new LinkRepositoryImpl();
articleRepository = new ArticleRepositoryImpl();
tagArticleRepository = new TagArticleRepositoryImpl();
tagRepository = new TagRepositoryImpl();
((TagRepositoryImpl)tagRepository).setTagArticleRepository(tagArticleRepository);
pageRepository = new PageRepositoryImpl();
commentRepository = new CommentRepositoryImpl();
((CommentRepositoryImpl)commentRepository).setArticleRepository(articleRepository);
archiveDateRepository = new ArchiveDateRepositoryImpl();
archiveDateArticleRepository = new ArchiveDateArticleRepositoryImpl();
pluginRepository = new PluginRepositoryImpl();
preferenceRepository = new PreferenceRepositoryImpl();
statisticRepository = new StatisticRepositoryImpl();
optionRepository = new OptionRepositoryImpl();
// Services
langPropsService = new LangPropsServiceImpl();
pluginMgmtService = new PluginMgmtService();
pluginMgmtService.setPluginRepository(pluginRepository);
pluginMgmtService.setLangPropsService(langPropsService);
preferenceQueryService = new PreferenceQueryService();
preferenceQueryService.setPreferenceRepository(preferenceRepository);
initService = new InitService();
initService.setArchiveDateArticleRepository(archiveDateArticleRepository);
initService.setArchiveDateRepository(archiveDateRepository);
initService.setUserRepository(userRepository);
initService.setArticleRepository(articleRepository);
initService.setPreferenceRepository(preferenceRepository);
initService.setStatisticRepository(statisticRepository);
initService.setTagArticleRepository(tagArticleRepository);
initService.setTagRepository(tagRepository);
initService.setCommentRepository(commentRepository);
initService.setLangPropsService(langPropsService);
userMgmtService = new UserMgmtService();
userMgmtService.setUserRepository(userRepository);
userMgmtService.setLangPropsService(langPropsService);
userQueryService = new UserQueryService();
userQueryService.setUserMgmtService(userMgmtService);
userQueryService.setUserRepository(userRepository);
permalinkQueryService = new PermalinkQueryService();
permalinkQueryService.setArticleRepository(articleRepository);
permalinkQueryService.setPageRepository(pageRepository);
statisticMgmtService = new StatisticMgmtService();
statisticMgmtService.setStatisticRepository(statisticRepository);
statisticMgmtService.setLangPropsService(langPropsService);
statisticQueryService = new StatisticQueryService();
statisticQueryService.setStatisticRepository(statisticRepository);
tagQueryService = new TagQueryService();
tagQueryService.setTagRepository(tagRepository);
tagMgmtService = new TagMgmtService();
tagMgmtService.setTagQueryService(tagQueryService);
tagMgmtService.setTagRepository(tagRepository);
articleQueryService = new ArticleQueryService();
articleQueryService.setArchiveDateArticleRepository(archiveDateArticleRepository);
articleQueryService.setArticleRepository(articleRepository);
articleQueryService.setUserRepository(userRepository);
articleQueryService.setPreferenceQueryService(preferenceQueryService);
articleQueryService.setStatisticQueryService(statisticQueryService);
articleQueryService.setTagArticleRepository(tagArticleRepository);
articleQueryService.setTagRepository(tagRepository);
articleMgmtService = new ArticleMgmtService();
articleMgmtService.setArchiveDateArticleRepository(archiveDateArticleRepository);
articleMgmtService.setArchiveDateRepository(archiveDateRepository);
articleMgmtService.setArticleRepository(articleRepository);
articleMgmtService.setPermalinkQueryService(permalinkQueryService);
articleMgmtService.setArticleQueryService(articleQueryService);
articleMgmtService.setUserRepository(userRepository);
articleMgmtService.setArticleQueryService(articleQueryService);
articleMgmtService.setPreferenceQueryService(preferenceQueryService);
articleMgmtService.setStatisticMgmtService(statisticMgmtService);
articleMgmtService.setStatisticQueryService(statisticQueryService);
articleMgmtService.setTagArticleRepository(tagArticleRepository);
articleMgmtService.setTagRepository(tagRepository);
articleMgmtService.setTagMgmtService(tagMgmtService);
articleMgmtService.setCommentRepository(commentRepository);
articleMgmtService.setLangPropsService(langPropsService);
pageMgmtService = new PageMgmtService();
pageMgmtService.setPermalinkQueryService(permalinkQueryService);
pageMgmtService.setPageRepository(pageRepository);
pageMgmtService.setPreferenceQueryService(preferenceQueryService);
pageMgmtService.setStatisticQueryService(statisticQueryService);
pageMgmtService.setStatisticMgmtService(statisticMgmtService);
pageMgmtService.setCommentRepository(commentRepository);
pageMgmtService.setLangPropsService(langPropsService);
pageQueryService = new PageQueryService();
pageQueryService.setPageRepository(pageRepository);
linkMgmtService = new LinkMgmtService();
linkMgmtService.setLinkRepository(linkRepository);
linkQueryService = new LinkQueryService();
linkQueryService.setLinkRepository(linkRepository);
preferenceMgmtService = new PreferenceMgmtService();
preferenceMgmtService.setPreferenceRepository(preferenceRepository);
preferenceMgmtService.setLangPropsService(langPropsService);
commentQueryService = new CommentQueryService();
commentQueryService.setArticleRepository(articleRepository);
commentQueryService.setPageRepository(pageRepository);
commentQueryService.setCommentRepository(commentRepository);
commentMgmtService = new CommentMgmtService();
commentMgmtService.setArticleRepository(articleRepository);
commentMgmtService.setArticleMgmtService(articleMgmtService);
commentMgmtService.setPageRepository(pageRepository);
commentMgmtService.setPreferenceQueryService(preferenceQueryService);
commentMgmtService.setStatisticMgmtService(statisticMgmtService);
commentMgmtService.setCommentRepository(commentRepository);
commentMgmtService.setLangPropsService(langPropsService);
archiveDateQueryService = new ArchiveDateQueryService();
archiveDateQueryService.setArchiveDateRepository(archiveDateRepository);
optionMgmtService = new OptionMgmtService();
optionMgmtService.setOptionRepository(optionRepository);
optionQueryService = new OptionQueryService();
optionQueryService.setOptionRepository(optionRepository);
final Collection<Class<?>> classes = Discoverer.discover("org.b3log.solo");
Lifecycle.startApplication(classes);
beanManager = Lifecycle.getBeanManager();
}
/**
......@@ -421,7 +118,7 @@ public abstract class AbstractTestCase {
* @return user repository
*/
public UserRepository getUserRepository() {
return userRepository;
return beanManager.getReference(UserRepositoryImpl.class);
}
/**
......@@ -430,7 +127,7 @@ public abstract class AbstractTestCase {
* @return link repository
*/
public LinkRepository getLinkRepository() {
return linkRepository;
return beanManager.getReference(LinkRepositoryImpl.class);
}
/**
......@@ -439,7 +136,7 @@ public abstract class AbstractTestCase {
* @return article repository
*/
public ArticleRepository getArticleRepository() {
return articleRepository;
return beanManager.getReference(ArticleRepositoryImpl.class);
}
/**
......@@ -448,7 +145,7 @@ public abstract class AbstractTestCase {
* @return tag repository
*/
public TagRepository getTagRepository() {
return tagRepository;
return beanManager.getReference(TagRepositoryImpl.class);
}
/**
......@@ -457,7 +154,7 @@ public abstract class AbstractTestCase {
* @return tag-article repository
*/
public TagArticleRepository getTagArticleRepository() {
return tagArticleRepository;
return beanManager.getReference(TagArticleRepositoryImpl.class);
}
/**
......@@ -466,7 +163,7 @@ public abstract class AbstractTestCase {
* @return page repository
*/
public PageRepository getPageRepository() {
return pageRepository;
return beanManager.getReference(PageRepositoryImpl.class);
}
/**
......@@ -475,7 +172,7 @@ public abstract class AbstractTestCase {
* @return comment repository
*/
public CommentRepository getCommentRepository() {
return commentRepository;
return beanManager.getReference(CommentRepositoryImpl.class);
}
/**
......@@ -484,7 +181,7 @@ public abstract class AbstractTestCase {
* @return archive date repository
*/
public ArchiveDateRepository getArchiveDateRepository() {
return archiveDateRepository;
return beanManager.getReference(ArchiveDateRepositoryImpl.class);
}
/**
......@@ -493,7 +190,7 @@ public abstract class AbstractTestCase {
* @return archive date article repository
*/
public ArchiveDateArticleRepository getArchiveDateArticleRepository() {
return archiveDateArticleRepository;
return beanManager.getReference(ArchiveDateArticleRepositoryImpl.class);
}
/**
......@@ -502,7 +199,7 @@ public abstract class AbstractTestCase {
* @return plugin repository
*/
public PluginRepository getPluginRepository() {
return pluginRepository;
return beanManager.getReference(PluginRepositoryImpl.class);
}
/**
......@@ -511,7 +208,7 @@ public abstract class AbstractTestCase {
* @return preference repository
*/
public PreferenceRepository getPreferenceRepository() {
return preferenceRepository;
return beanManager.getReference(PreferenceRepositoryImpl.class);
}
/**
......@@ -520,7 +217,7 @@ public abstract class AbstractTestCase {
* @return statistic repository
*/
public StatisticRepository getStatisticRepository() {
return statisticRepository;
return beanManager.getReference(StatisticRepositoryImpl.class);
}
/**
......@@ -529,7 +226,7 @@ public abstract class AbstractTestCase {
* @return option repository
*/
public OptionRepository getOptionRepository() {
return optionRepository;
return beanManager.getReference(OptionRepositoryImpl.class);
}
/**
......@@ -538,7 +235,7 @@ public abstract class AbstractTestCase {
* @return initialization service
*/
public InitService getInitService() {
return initService;
return beanManager.getReference(InitService.class);
}
/**
......@@ -547,7 +244,7 @@ public abstract class AbstractTestCase {
* @return user management service
*/
public UserMgmtService getUserMgmtService() {
return userMgmtService;
return beanManager.getReference(UserMgmtService.class);
}
/**
......@@ -556,7 +253,7 @@ public abstract class AbstractTestCase {
* @return user query service
*/
public UserQueryService getUserQueryService() {
return userQueryService;
return beanManager.getReference(UserQueryService.class);
}
/**
......@@ -565,7 +262,7 @@ public abstract class AbstractTestCase {
* @return article management service
*/
public ArticleMgmtService getArticleMgmtService() {
return articleMgmtService;
return beanManager.getReference(ArticleMgmtService.class);
}
/**
......@@ -574,7 +271,7 @@ public abstract class AbstractTestCase {
* @return article query service
*/
public ArticleQueryService getArticleQueryService() {
return articleQueryService;
return beanManager.getReference(ArticleQueryService.class);
}
/**
......@@ -583,7 +280,7 @@ public abstract class AbstractTestCase {
* @return page management service
*/
public PageMgmtService getPageMgmtService() {
return pageMgmtService;
return beanManager.getReference(PageMgmtService.class);
}
/**
......@@ -592,7 +289,7 @@ public abstract class AbstractTestCase {
* @return page query service
*/
public PageQueryService getPageQueryService() {
return pageQueryService;
return beanManager.getReference(PageQueryService.class);
}
/**
......@@ -601,7 +298,7 @@ public abstract class AbstractTestCase {
* @return link management service
*/
public LinkMgmtService getLinkMgmtService() {
return linkMgmtService;
return beanManager.getReference(LinkMgmtService.class);
}
/**
......@@ -610,7 +307,7 @@ public abstract class AbstractTestCase {
* @return link query service
*/
public LinkQueryService getLinkQueryService() {
return linkQueryService;
return beanManager.getReference(LinkQueryService.class);
}
/**
......@@ -619,7 +316,7 @@ public abstract class AbstractTestCase {
* @return preference management service
*/
public PreferenceMgmtService getPreferenceMgmtService() {
return preferenceMgmtService;
return beanManager.getReference(PreferenceMgmtService.class);
}
/**
......@@ -628,7 +325,7 @@ public abstract class AbstractTestCase {
* @return preference query service
*/
public PreferenceQueryService getPreferenceQueryService() {
return preferenceQueryService;
return beanManager.getReference(PreferenceQueryService.class);
}
/**
......@@ -637,7 +334,7 @@ public abstract class AbstractTestCase {
* @return tag query service
*/
public TagQueryService getTagQueryService() {
return tagQueryService;
return beanManager.getReference(TagQueryService.class);
}
/**
......@@ -646,7 +343,7 @@ public abstract class AbstractTestCase {
* @return tag management service
*/
public TagMgmtService getTagMgmtService() {
return tagMgmtService;
return beanManager.getReference(TagMgmtService.class);
}
/**
......@@ -655,7 +352,7 @@ public abstract class AbstractTestCase {
* @return comment query service
*/
public CommentQueryService getCommentQueryService() {
return commentQueryService;
return beanManager.getReference(CommentQueryService.class);
}
/**
......@@ -664,7 +361,7 @@ public abstract class AbstractTestCase {
* @return comment management service
*/
public CommentMgmtService getCommentMgmtService() {
return commentMgmtService;
return beanManager.getReference(CommentMgmtService.class);
}
/**
......@@ -673,7 +370,7 @@ public abstract class AbstractTestCase {
* @return archive date query service
*/
public ArchiveDateQueryService getArchiveDateQueryService() {
return archiveDateQueryService;
return beanManager.getReference(ArchiveDateQueryService.class);
}
/**
......@@ -682,7 +379,7 @@ public abstract class AbstractTestCase {
* @return option management service
*/
public OptionMgmtService getOptionMgmtService() {
return optionMgmtService;
return beanManager.getReference(OptionMgmtService.class);
}
/**
......@@ -691,6 +388,6 @@ public abstract class AbstractTestCase {
* @return option query service
*/
public OptionQueryService getOptionQueryService() {
return optionQueryService;
return beanManager.getReference(OptionQueryService.class);
}
}
......@@ -41,27 +41,21 @@ public class ArchiveDateArticleRepositoryImplTestCase extends AbstractTestCase {
*/
@Test
public void add() throws Exception {
final ArchiveDateArticleRepository archiveDateArticleRepository =
getArchiveDateArticleRepository();
final ArchiveDateArticleRepository archiveDateArticleRepository = getArchiveDateArticleRepository();
final JSONObject archiveDateArticle = new JSONObject();
archiveDateArticle.put(ArchiveDate.ARCHIVE_DATE + "_"
+ Keys.OBJECT_ID, "archiveDateId");
archiveDateArticle.put(Article.ARTICLE + "_"
+ Keys.OBJECT_ID, "articleId");
archiveDateArticle.put(ArchiveDate.ARCHIVE_DATE + "_" + Keys.OBJECT_ID, "archiveDateId");
archiveDateArticle.put(Article.ARTICLE + "_" + Keys.OBJECT_ID, "articleId");
final Transaction transaction = archiveDateArticleRepository.
beginTransaction();
final Transaction transaction = archiveDateArticleRepository.beginTransaction();
archiveDateArticleRepository.add(archiveDateArticle);
transaction.commit();
final JSONObject found =
archiveDateArticleRepository.getByArticleId("articleId");
final JSONObject found = archiveDateArticleRepository.getByArticleId("articleId");
Assert.assertNotNull(found);
final JSONObject notFound =
archiveDateArticleRepository.getByArticleId("not found");
final JSONObject notFound = archiveDateArticleRepository.getByArticleId("not found");
Assert.assertNull(notFound);
}
......
......@@ -51,9 +51,5 @@ cache=GAE
# userService=GAE
userService=LOCAL
#### Cache ####
cache.maxPageCnt=128
cache.maxDataCnt=128
#### Static resource version ####
staticResourceVersion=201206280945
\ No newline at end of file
<?xml version="1.0" encoding="UTF-8"?>
<!--
Description: B3log Solo parent POM.
Version: 2.0.3.2, Aug 20, 2013
Version: 2.0.3.3, Oct 29, 2013
Author: Liang Ding
-->
<project xmlns="http://maven.apache.org/POM/4.0.0"
......@@ -11,7 +11,7 @@
<groupId>org.b3log</groupId>
<artifactId>solo</artifactId>
<packaging>pom</packaging>
<version>0.6.1</version>
<version>0.6.5</version>
<name>B3log Solo</name>
<url>https://github.com/b3log/b3log-solo</url>
<description>
......
<?xml version="1.0" encoding="UTF-8"?>
<!--
Description: B3log Solo BAE POM.
Version: 1.0.1.5, Aug 24, 2013
Version: 1.0.1.6, Oct 29, 2013
Author: Liang Ding
-->
<project xmlns="http://maven.apache.org/POM/4.0.0"
......@@ -19,7 +19,7 @@
<parent>
<groupId>org.b3log</groupId>
<artifactId>solo-war</artifactId>
<version>0.6.1</version>
<version>0.6.5</version>
</parent>
<properties>
......
......@@ -16,7 +16,7 @@
#
# Description: B3log Latke configurations. Configures the section "Server" carefully.
# Version: 1.0.1.1, Aug 24, 2013
# Version: 1.0.1.2, Oct 31, 2013
# Author: Liang Ding
#
......@@ -41,8 +41,8 @@ scanPath=org.b3log.solo
runtimeEnv=BAE
#### Runtime Mode ####
#runtimeMode=DEVELOPMENT
runtimeMode=PRODUCTION
runtimeMode=DEVELOPMENT
#runtimeMode=PRODUCTION
#### Cache Implementation ####
# Note: If the runtime environment is LOCAL, the cache will be 'LOCAL' always
......@@ -52,9 +52,5 @@ cache=BAE
#### User Service Implementation ####
userService=LOCAL
#### Cache ####
cache.maxPageCnt=0
cache.maxDataCnt=0
#### Static resource version ####
staticResourceVersion=201308241630
\ No newline at end of file
staticResourceVersion=201310311200
\ No newline at end of file
......@@ -15,12 +15,12 @@
#
#
# Description: B3log Solo logging configurations.
# Version: 1.0.0.0, Aug 24, 2013
# Description: B3log Solo logging configurations for BAE.
# Version: 1.0.0.2, Oct 29, 2013
# Author: Liang Ding
#
log4j.rootLogger=INFO, stdout, bae
log4j.rootLogger=WARN, stdout, bae
log4j.appender.stdout=org.apache.log4j.ConsoleAppender
log4j.appender.stdout.Target=System.out
......@@ -31,7 +31,8 @@ log4j.appender.bae=com.baidu.bae.api.baelog.BaeAppender
log4j.appender.bae.layout=org.apache.log4j.PatternLayout
log4j.appender.bae.layout.ConversionPattern=[%-5p]-[%d{yyyy-MM-dd HH:mm:ss}]-[%c:%L]: %m%n
log4j.logger.org.b3log.solo=DEBUG
log4j.logger.org.b3log.solo=WARN
log4j.logger.org.b3log.latke=INFO
log4j.logger.org.b3log.latke=ERROR
log4j.logger.org.b3log.latke.util.freemarker.Templates=ERROR
<?xml version="1.0" encoding="UTF-8"?>
<!--
Description: B3log Solo GAE POM.
Version: 2.0.2.3, Aug 20, 2013
Version: 2.0.2.4, Oct 29, 2013
Author: Liang Ding
-->
<project xmlns="http://maven.apache.org/POM/4.0.0"
......@@ -19,7 +19,7 @@
<parent>
<groupId>org.b3log</groupId>
<artifactId>solo-war</artifactId>
<version>0.6.1</version>
<version>0.6.5</version>
</parent>
<properties>
......
......@@ -16,7 +16,7 @@
#
# Description: B3log Latke configurations. Configures the section "Server" carefully.
# Version: 1.0.0.9, Aug 24, 2013
# Version: 1.0.1.0, Oct 31, 2013
# Author: Liang Ding
#
......@@ -41,8 +41,8 @@ scanPath=org.b3log.solo
runtimeEnv=GAE
#### Runtime Mode ####
#runtimeMode=DEVELOPMENT
runtimeMode=PRODUCTION
runtimeMode=DEVELOPMENT
#runtimeMode=PRODUCTION
#### Cache Implementation ####
# Note: If the runtime environment is LOCAL, the cache will be 'LOCAL' always
......@@ -51,9 +51,5 @@ cache=GAE
#### User Service Implementation ####
userService=LOCAL
#### Cache ####
cache.maxPageCnt=1024000
cache.maxDataCnt=1024000
#### Static resource version ####
staticResourceVersion=201308241630
\ No newline at end of file
staticResourceVersion=201310311200
\ No newline at end of file
......@@ -19,7 +19,7 @@
# <system-properties>
# <property name="java.util.logging.config.file" value="WEB-INF/classes/logging.properties"/>
# </system-properties>
# Version: 1.0.2.1, Jun 4, 2013
# Version: 1.0.2.2, Oct 29, 2013
# Author: Liang Ding
#
......@@ -27,14 +27,10 @@ handlers=java.util.logging.ConsoleHandler
org.b3log.solo.level=INFO
org.b3log.latke.level=WARNING
org.b3log.latke.level=SEVERE
org.b3log.latke.util.freemarker.Templates.level=SEVERE
org.b3log.latke.cache.level=WARNING
org.b3log.latke.repository.jdbc.level=WARNING
com.google.level=WARNING
com.sun.level=WARNING
freemarker.level=WARNING
org.apache.level=WARNING
# c3p0
com.mchange.level=WARNING
<?xml version="1.0" encoding="UTF-8"?>
<!--
Description: B3log Solo (H2) standard Servlet container POM.
Version: 1.0.0.2, Aug 20, 2013
Version: 1.0.0.3, Oct 29, 2013
Author: Liang Ding
-->
<project xmlns="http://maven.apache.org/POM/4.0.0"
......@@ -19,7 +19,7 @@
<parent>
<groupId>org.b3log</groupId>
<artifactId>solo-war</artifactId>
<version>0.6.1</version>
<version>0.6.5</version>
</parent>
<properties>
......
......@@ -16,7 +16,7 @@
#
# Description: B3log Latke configurations. Configures the section "Server" carefully.
# Version: 1.0.0.9, Aug 24, 2013
# Version: 1.0.1.0, Oct 31, 2013
# Author: Liang Ding
#
......@@ -41,8 +41,8 @@ scanPath=org.b3log.solo
runtimeEnv=LOCAL
#### Runtime Mode ####
#runtimeMode=DEVELOPMENT
runtimeMode=PRODUCTION
#runtimeMode=PRODUCTION
runtimeMode=DEVELOPMENT
#### Cache Implementation ####
# Note: If the runtime environment is LOCAL, the cache will be 'LOCAL' always
......@@ -51,9 +51,5 @@ cache=LOCAL
#### User Service Implementation ####
userService=LOCAL
#### Cache ####
cache.maxPageCnt=128
cache.maxDataCnt=128
#### Static resource version ####
staticResourceVersion=201308241630
\ No newline at end of file
staticResourceVersion=201310311200
\ No newline at end of file
......@@ -42,5 +42,5 @@ jdbc.maxConnCnt=10
jdbc.transactionIsolation=READ_COMMITTED
# The specific table name prefix
jdbc.tablePrefix=
jdbc.tablePrefix=b3_solo
<?xml version="1.0" encoding="UTF-8"?>
<!--
Description: B3log Solo (MySQL) standard Servlet container POM.
Version: 1.0.1.3, Aug 20, 2013
Version: 1.0.1.4, Oct 29, 2013
Author: Liang Ding
-->
<project xmlns="http://maven.apache.org/POM/4.0.0"
......@@ -19,7 +19,7 @@
<parent>
<groupId>org.b3log</groupId>
<artifactId>solo-war</artifactId>
<version>0.6.1</version>
<version>0.6.5</version>
</parent>
<properties>
......
......@@ -16,7 +16,7 @@
#
# Description: B3log Latke configurations. Configures the section "Server" carefully.
# Version: 1.0.0.9, Aug 24, 2013
# Version: 1.0.1.0, Oct 31, 2013
# Author: Liang Ding
#
......@@ -41,8 +41,8 @@ scanPath=org.b3log.solo
runtimeEnv=LOCAL
#### Runtime Mode ####
#runtimeMode=DEVELOPMENT
runtimeMode=PRODUCTION
runtimeMode=DEVELOPMENT
#runtimeMode=PRODUCTION
#### Cache Implementation ####
# Note: If the runtime environment is LOCAL, the cache will be 'LOCAL' always
......@@ -51,9 +51,5 @@ cache=LOCAL
#### User Service Implementation ####
userService=LOCAL
#### Cache ####
cache.maxPageCnt=128
cache.maxDataCnt=128
#### Static resource version ####
staticResourceVersion=201308241630
\ No newline at end of file
staticResourceVersion=201310311200
\ No newline at end of file
<?xml version="1.0" encoding="UTF-8"?>
<!--
Description: B3log Solo WAR POM.
Version: 2.0.1.7, Aug 20, 2013
Version: 2.0.1.8, Oct 29, 2013
Author: Liang Ding
-->
<project xmlns="http://maven.apache.org/POM/4.0.0"
......@@ -19,7 +19,7 @@
<parent>
<groupId>org.b3log</groupId>
<artifactId>solo</artifactId>
<version>0.6.1</version>
<version>0.6.5</version>
</parent>
<modules>
......@@ -62,8 +62,13 @@
<artifactId>maven-jetty-plugin</artifactId>
<version>6.1.22</version>
<configuration>
<connectors>
<connector implementation="org.mortbay.jetty.nio.SelectChannelConnector">
<port>8080</port>
</connector>
</connectors>
<stopKey>stop</stopKey>
<stopPort>4500</stopPort>
<stopPort>4502</stopPort>
<webAppSourceDirectory>../src/main/webapp</webAppSourceDirectory>
<classesDirectory>${basedir}/target/${project.build.finalName}/WEB-INF/classes</classesDirectory>
<contextPath>/</contextPath>
......
......@@ -231,8 +231,6 @@ tagsLabel=Tags
importedLabel=Imported
captcha1Label=Captcha:
captchaLabel=Captcha
clearAllCacheLabel=Clear all cache
clearCacheLabel=Clear cache
indexLabel=Index
nextArticle1Label=Next:
previousArticle1Label=Previous:
......
......@@ -231,8 +231,6 @@ tagsLabel=\u6807\u7b7e
importedLabel=\u5df2\u5bfc\u5165
captcha1Label=\u9a8c\u8bc1\u7801\uff1a
captchaLabel=\u9a8c\u8bc1\u7801
clearAllCacheLabel=\u6e05\u9664\u6240\u6709\u9875\u9762\u7f13\u5b58
clearCacheLabel=\u6e05\u9664\u672c\u9875\u7f13\u5b58
indexLabel=\u9996\u9875
nextArticle1Label=\u65b0\u4e00\u7bc7\uff1a
previousArticle1Label=\u65e7\u4e00\u7bc7\uff1a
......
......@@ -16,18 +16,19 @@
#
# Description: B3log Solo logging configurations.
# Version: 1.0.0.0, Jun 19, 2013
# Version: 1.0.0.2, Oct 29, 2013
# Author: Liang Ding
#
log4j.rootLogger=INFO, stdout
log4j.rootLogger=WARN, stdout
log4j.appender.stdout=org.apache.log4j.ConsoleAppender
log4j.appender.stdout.Target=System.out
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
log4j.appender.stdout.layout.ConversionPattern=[%-5p]-[%d{yyyy-MM-dd HH:mm:ss}]-[%c:%L]: %m%n
log4j.logger.org.b3log.solo=DEBUG
log4j.logger.org.b3log.solo=WARN
log4j.logger.org.b3log.latke=DEBUG
log4j.logger.org.b3log.latke=ERROR
log4j.logger.org.b3log.latke.util.freemarker.Templates=ERROR
......@@ -5,6 +5,21 @@
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
</head>
<body>
<h2>Release 0.6.5 - Nov 1, 2013</h2>
<ul>
<li><a href="https://github.com/b3log/b3log-solo/issues/282">282 找回密码问题</a>&nbsp;<span style='background: #fc2929 !important;color:#FFFFFF !important;padding: 1px 4px;'>bug</span></li>
<li><a href="https://github.com/b3log/b3log-solo/issues/283">283 社区同步评论</a>&nbsp;<span style='background: #fc2929 !important;color:#FFFFFF !important;padding: 1px 4px;'>bug</span></li>
<li><a href="https://github.com/b3log/b3log-solo/issues/288">288 IoC 容器冲突</a>&nbsp;<span style='background: #fc2929 !important;color:#FFFFFF !important;padding: 1px 4px;'>bug</span></li>
<li><a href="https://github.com/b3log/b3log-solo/issues/294">294 发布文章时允许评论开关问题</a>&nbsp;<span style='background: #fc2929 !important;color:#FFFFFF !important;padding: 1px 4px;'>bug</span></li>
<li><a href="https://github.com/b3log/b3log-solo/issues/296">296 数据恢复接口被过滤器跳过</a>&nbsp;<span style='background: #fc2929 !important;color:#FFFFFF !important;padding: 1px 4px;'>bug</span></li>
<li><a href="https://github.com/b3log/b3log-solo/issues/302">302 更新已发布文章问题</a>&nbsp;<span style='background: #fc2929 !important;color:#FFFFFF !important;padding: 1px 4px;'>bug</span></li>
<li><a href="https://github.com/b3log/b3log-solo/issues/295">295 未初始化时启动日志报错</a>&nbsp;<span style='background: #84b6eb !important;color:#FFFFFF !important;padding: 1px 4px;'>enhancement</span></li>
<li><a href="https://github.com/b3log/b3log-solo/issues/299">299 评论信息填充优化</a>&nbsp;<span style='background: #84b6eb !important;color:#FFFFFF !important;padding: 1px 4px;'>enhancement</span></li>
<li><a href="https://github.com/b3log/b3log-solo/issues/316">316 评论开关页面显示</a>&nbsp;<span style='background: #84b6eb !important;color:#FFFFFF !important;padding: 1px 4px;'>enhancement</span></li>
<li><a href="https://github.com/b3log/b3log-solo/issues/317">317 自动保存文章时间间隔</a>&nbsp;<span style='background: #84b6eb !important;color:#FFFFFF !important;padding: 1px 4px;'>enhancement</span></li>
<li><a href="https://github.com/b3log/b3log-solo/issues/318">318 去缓存</a>&nbsp;<span style='background: #84b6eb !important;color:#FFFFFF !important;padding: 1px 4px;'>enhancement</span></li>
<li><a href="https://github.com/b3log/b3log-solo/issues/320">320 加入登录状态模版变量</a>&nbsp;<span style='background: #84b6eb !important;color:#FFFFFF !important;padding: 1px 4px;'>enhancement</span></li>
</ul>
<h2>Release 0.6.1 - Aug 25, 2013</h2>
<ul>
<li><a href="https://github.com/b3log/b3log-solo/issues/200">200 找回密码</a>&nbsp;<span style='background: #02e10c !important;color:#FFFFFF !important;padding: 1px 4px;'>feature</span></li>
......
......@@ -20,12 +20,12 @@
Description: Web deployment descriptor on GAE. See
http://code.google.com/intl/en/appengine/docs/java/config/appconfig.html
for more details.
Version: 1.0.4.3, Aug 24, 2013
Version: 1.0.4.4, Oct 31, 2013
Author: Liang Ding
-->
<appengine-web-app xmlns="http://appengine.google.com/ns/1.0">
<application>solo-demo</application>
<version>061</version>
<version>065</version>
<sessions-enabled>true</sessions-enabled>
......
......@@ -31,12 +31,6 @@
<schedule>every 5 minutes</schedule>
</cron>
<cron>
<url>/console/stat/viewcnt</url>
<description>Async Blog/Article counter</description>
<schedule>every 30 minutes</schedule>
</cron>
<cron>
<url>/console/stat/onlineVisitorRefresh</url>
<description>Online Visitor Refresher</description>
......
......@@ -18,7 +18,7 @@
-->
<!--
Description: B3log Solo web deployment descriptor.
Version: 1.0.5.0, Jan 25, 2013
Version: 1.0.5.1, Sep 27, 2013
Author: Liang Ding
-->
<web-app version="2.5" xmlns="http://java.sun.com/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd">
......@@ -65,14 +65,6 @@
<url-pattern>/rm-all-data.do</url-pattern>
<url-pattern>/fix/*</url-pattern>
</filter-mapping>
<filter>
<filter-name>PageCacheFilter</filter-name>
<filter-class>org.b3log.solo.filter.PageCacheFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>PageCacheFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
<filter>
<filter-name>PermalinkFilter</filter-name>
<filter-class>org.b3log.solo.filter.PermalinkFilter</filter-class>
......@@ -97,12 +89,12 @@
</session-config>
<servlet>
<servlet-name>HTTPRequestDispatcher</servlet-name>
<servlet-class>org.b3log.latke.servlet.HTTPRequestDispatcher</servlet-class>
<servlet-name>DispatcherServlet</servlet-name>
<servlet-class>org.b3log.latke.servlet.DispatcherServlet</servlet-class>
<load-on-startup>2</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>HTTPRequestDispatcher</servlet-name>
<servlet-name>DispatcherServlet</servlet-name>
<url-pattern>/*</url-pattern>
</servlet-mapping>
......
......@@ -3,7 +3,7 @@
<head>
<meta charset="utf-8" />
<title>${articleViewPwdLabel}</title>
<meta name="keywords" content="GAE 博客,GAE blog,b3log" />
<meta name="keywords" content="Java 博客,GAE blog,b3log" />
<meta name="description" content="An open source blog based on GAE Java,GAE Java 开源博客" />
<meta name="owner" content="B3log Team" />
<meta name="author" content="B3log Team" />
......
......@@ -18,7 +18,7 @@
* 403, 404, 500, article-pwd, init, login and kill-browser page style.
*
* @author <a href="mailto:LLY219@gmail.com">Liyuan Li</a>
* @version 1.0.1.5, May 30, 2013
* @version 1.0.1.6, Sep 12, 2013
*/
html {
height: 100%;
......@@ -269,6 +269,10 @@ button:active {
width: 470px;
}
#init .form {
padding: 10px 20px;
}
#init input,
.register input {
margin: 5px 0;
......@@ -280,7 +284,7 @@ button:active {
}
#sys p {
height: 166px;
height: 206px;
}
#sys {
......
html{height:100%;overflow:hidden}html,body{margin:0;padding:0}body{background-color:#f3f1e5;color:#333;font-family:\5fae\8f6f\96c5\9ed1;font-size:small;height:100%}h2{background-color:#ececec;background-image:linear-gradient(#f9f9f9,#ececec);background-repeat:repeat-x;border-radius:4px 4px 0 0;font-size:16px;margin:0;padding:10px 20px;text-shadow:0 -1px 0 rgba(255,255,255,0.5)}input{border:1px solid #ccc;border-radius:3px 3px 3px 3px;box-shadow:0 1px 2px rgba(0,0,0,0.075) inset;font-size:13px;margin:15px 0;padding:7px 8px;transition:all .15s ease-in 0s;vertical-align:middle;width:410px;font-family:\5fae\8f6f\96c5\9ed1;font-size:small}input:focus{box-shadow:0 1px 2px rgba(0,0,0,0.075) inset,0 0 5px rgbargba(200,200,200,0.9);border:1px solid #e6e5d9}.form{padding:20px}label{font-size:13px}button{position:relative;display:inline-block;font-size:13px;font-weight:700;color:#333;text-shadow:0 1px 0 rgba(255,255,255,0.9);white-space:nowrap;background-color:#eaeaea;background-image:linear-gradient(#fafafa,#eaeaea);background-repeat:repeat-x;border-radius:3px;border:1px solid #ddd;border-bottom-color:#c5c5c5;box-shadow:0 1px 3px rgba(0,0,0,0.075);vertical-align:baseline;cursor:pointer;-webkit-touch-callout:none;-webkit-user-select:none;-khtml-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;-webkit-appearance:none;outline:0;padding:7px 15px;margin-top:10px}button:hover,button:active{color:#fff;text-decoration:none;text-shadow:0 -1px 0 rgba(0,0,0,0.25);background-color:#3072b3;background-image:linear-gradient(#599bcd,#3072b3);background-repeat:repeat-x}.clear{background-color:transparent;border:0;clear:both;display:block;font-size:0;height:0;line-height:0;overflow:hidden}.none{display:none}.main .icon{position:absolute;right:0;top:0;width:16px;height:16px}.solo{color:orangered;font-weight:bold}.logo{float:left;padding:162px 12px 0;width:153px}.wrapper{height:auto;min-height:100%;position:relative}.wrap{border-top:5px solid #e6e5d9;min-height:400px}.content{background:url("../images/zz.jpg") repeat-x scroll center bottom white;border-color:#e6e5d9;border-style:solid solid none;border-width:1px;margin:0 auto;position:relative;width:700px;top:60px}.main{border-left:1px solid #e6e5d9;float:right;font-size:15px;margin:24px 0;padding:12px 24px;width:470px;height:338px}.main a{text-decoration:none}.main li{margin:6px 0 6px 16px}.footerWrapper{background-color:#fff;border-top:1px solid #e6e5d9;bottom:0;padding:12px 0;position:absolute;text-align:center;width:100%}.footerWrapper a{text-decoration:none}.article-pwd>div,.article-pwd>form{margin:0 20px}.article-pwd>div{margin-bottom:10px;max-height:264px;overflow:auto;word-wrap:break-word}.img-403,.img-500{box-shadow:0 0 5px #e6e5d9;margin:20px 0 0 45px;padding:5px}.a-403,.a-500{margin:20px 50px 0 0;text-align:right}.a-403{margin:10px 75px 0 0}.img-500{margin:20px 0 0 25px}.a-500{margin:25px 35px 0 0}.kill img{position:absolute;right:40px;top:200px}.kill ul{margin-bottom:50px}.kill p{margin:12px 20px}.kill span{margin-left:20px}#init{position:absolute;top:81px;width:470px}#init input,.register input{margin:5px 0;padding:5px 8px}.register{height:400px}#sys p{height:166px}#sys{padding:0 20px}#initButton{margin-right:10px}#tip{color:#21759b;font-weight:bold;margin-left:10px}
\ No newline at end of file
html{height:100%;overflow:hidden}html,body{margin:0;padding:0}body{background-color:#f3f1e5;color:#333;font-family:\5fae\8f6f\96c5\9ed1;font-size:small;height:100%}h2{background-color:#ececec;background-image:linear-gradient(#f9f9f9,#ececec);background-repeat:repeat-x;border-radius:4px 4px 0 0;font-size:16px;margin:0;padding:10px 20px;text-shadow:0 -1px 0 rgba(255,255,255,0.5)}input{border:1px solid #ccc;border-radius:3px 3px 3px 3px;box-shadow:0 1px 2px rgba(0,0,0,0.075) inset;font-size:13px;margin:15px 0;padding:7px 8px;transition:all .15s ease-in 0s;vertical-align:middle;width:410px;font-family:\5fae\8f6f\96c5\9ed1;font-size:small}input:focus{box-shadow:0 1px 2px rgba(0,0,0,0.075) inset,0 0 5px rgbargba(200,200,200,0.9);border:1px solid #e6e5d9}.form{padding:20px}label{font-size:13px}button{position:relative;display:inline-block;font-size:13px;font-weight:700;color:#333;text-shadow:0 1px 0 rgba(255,255,255,0.9);white-space:nowrap;background-color:#eaeaea;background-image:linear-gradient(#fafafa,#eaeaea);background-repeat:repeat-x;border-radius:3px;border:1px solid #ddd;border-bottom-color:#c5c5c5;box-shadow:0 1px 3px rgba(0,0,0,0.075);vertical-align:baseline;cursor:pointer;-webkit-touch-callout:none;-webkit-user-select:none;-khtml-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;-webkit-appearance:none;outline:0;padding:7px 15px;margin-top:10px}button:hover,button:active{color:#fff;text-decoration:none;text-shadow:0 -1px 0 rgba(0,0,0,0.25);background-color:#3072b3;background-image:linear-gradient(#599bcd,#3072b3);background-repeat:repeat-x}.clear{background-color:transparent;border:0;clear:both;display:block;font-size:0;height:0;line-height:0;overflow:hidden}.none{display:none}.main .icon{position:absolute;right:0;top:0;width:16px;height:16px}.solo{color:orangered;font-weight:bold}.logo{float:left;padding:162px 12px 0;width:153px}.wrapper{height:auto;min-height:100%;position:relative}.wrap{border-top:5px solid #e6e5d9;min-height:400px}.content{background:url("../images/zz.jpg") repeat-x scroll center bottom white;border-color:#e6e5d9;border-style:solid solid none;border-width:1px;margin:0 auto;position:relative;width:700px;top:60px}.main{border-left:1px solid #e6e5d9;float:right;font-size:15px;margin:24px 0;padding:12px 24px;width:470px;height:338px}.main a{text-decoration:none}.main li{margin:6px 0 6px 16px}.footerWrapper{background-color:#fff;border-top:1px solid #e6e5d9;bottom:0;padding:12px 0;position:absolute;text-align:center;width:100%}.footerWrapper a{text-decoration:none}.article-pwd>div,.article-pwd>form{margin:0 20px}.article-pwd>div{margin-bottom:10px;max-height:264px;overflow:auto;word-wrap:break-word}.img-403,.img-500{box-shadow:0 0 5px #e6e5d9;margin:20px 0 0 45px;padding:5px}.a-403,.a-500{margin:20px 50px 0 0;text-align:right}.a-403{margin:10px 75px 0 0}.img-500{margin:20px 0 0 25px}.a-500{margin:25px 35px 0 0}.kill img{position:absolute;right:40px;top:200px}.kill ul{margin-bottom:50px}.kill p{margin:12px 20px}.kill span{margin-left:20px}#init{position:absolute;top:81px;width:470px}#init .form{padding:10px 20px}#init input,.register input{margin:5px 0;padding:5px 8px}.register{height:400px}#sys p{height:206px}#sys{padding:0 20px}#initButton{margin-right:10px}#tip{color:#21759b;font-weight:bold;margin-left:10px}
\ No newline at end of file
......@@ -22,6 +22,7 @@
html {
height: 100%;
overflow: hidden;
}
body {
......@@ -30,6 +31,7 @@
font-family: \5fae\8f6f\96c5\9ed1;
font-size: small;
height: 100%;
overflow: hidden;
}
.wrapper {
......@@ -106,6 +108,7 @@
${initIntroLabel}
<button onclick='initSys();' id="initButton">${initLabel}</button>
<button onclick='returnTo();'>${previousStepLabel}</button>
<span id="tipInit"></span>
<span class="clear"></span>
</div>
</div>
......@@ -154,7 +157,7 @@
var getUserInfo = function() {
if (validate()) {
$("#init").animate({
"top": -190
"top": -178
});
$("#user").animate({
......@@ -202,15 +205,15 @@
if (confirm("${confirmInitLabel}")) {
$(window).unbind();
$("#tip").html("<img src='${staticServePath}/images/loading.gif'/> loading...")
$("#tipInit").html("<img src='${staticServePath}/images/loading.gif'/> loading...");
$.ajax({
url: "${contextPath}/init",
type: "POST",
data: JSON.stringify(requestJSONObject),
success: function(result, textStatus) {
if (!result.sc) {
$("#tip").text(result.msg);
;
$("#tipInit").text(result.msg);
return;
}
......
......@@ -18,7 +18,7 @@
*
* @author <a href="mailto:LLY219@gmail.com">Liyuan Li</a>
* @author <a href="mailto:DL88250@gmail.com">Liang Ding</a>
* @version 1.0.3.3, Jun 4, 2013
* @version 1.0.3.3, Sep 30, 2013
*/
admin.article = {
// 当发文章,取消发布,更新文章时设置为 false。不需在离开编辑器时进行提示。
......@@ -456,11 +456,7 @@ admin.article = {
return;
}
if (admin.article.status.id) {
if (admin.article.status.isArticle) {
admin.article.status.isArticle = false;
admin.article.setStatus();
admin.article.unPublish(true);
} else {
if (!admin.article.status.isArticle) {
admin.article.update(false, true);
}
} else {
......
......@@ -875,7 +875,7 @@ $.extend(TablePaginate.prototype, {
*
* @author <a href="mailto:LLY219@gmail.com">Liyuan Li</a>
* @author <a href="mailto:DL88250@gmail.com">Liang Ding</a>
* @version 1.0.3.3, Jun 4, 2013
* @version 1.0.3.3, Sep 30, 2013
*/
admin.article = {
// 当发文章,取消发布,更新文章时设置为 false。不需在离开编辑器时进行提示。
......@@ -1313,11 +1313,7 @@ admin.article = {
return;
}
if (admin.article.status.id) {
if (admin.article.status.isArticle) {
admin.article.status.isArticle = false;
admin.article.setStatus();
admin.article.unPublish(true);
} else {
if (!admin.article.status.isArticle) {
admin.article.update(false, true);
}
} else {
......@@ -3542,7 +3538,7 @@ admin.userList = {
} else if (!/^((([a-z]|\d|[!#\$%&'\*\+\-\/=\?\^_`{\|}~]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])+(\.([a-z]|\d|[!#\$%&'\*\+\-\/=\?\^_`{\|}~]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])+)*)|((\x22)((((\x20|\x09)*(\x0d\x0a))?(\x20|\x09)+)?(([\x01-\x08\x0b\x0c\x0e-\x1f\x7f]|\x21|[\x23-\x5b]|[\x5d-\x7e]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(\\([\x01-\x09\x0b\x0c\x0d-\x7f]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF]))))*(((\x20|\x09)*(\x0d\x0a))?(\x20|\x09)+)?(\x22)))@((([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])*([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])))\.)+(([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])*([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])))\.?$/i.test($("#userEmail" + status).val())) {
$("#tipMsg").text(Label.mailInvalidLabel);
$("#userEmail" + status).focus();
} else if ($("#userPassword" + status).val().replace(/\s/g, "") === "") {
} else if ($("#userPassword" + status).val() === "") {
$("#tipMsg").text(Label.passwordEmptyLabel);
$("#userPassword" + status).focus();
} else {
......
This source diff could not be displayed because it is too large. You can view the blob instead.
......@@ -338,7 +338,7 @@ admin.userList = {
} else if (!/^((([a-z]|\d|[!#\$%&'\*\+\-\/=\?\^_`{\|}~]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])+(\.([a-z]|\d|[!#\$%&'\*\+\-\/=\?\^_`{\|}~]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])+)*)|((\x22)((((\x20|\x09)*(\x0d\x0a))?(\x20|\x09)+)?(([\x01-\x08\x0b\x0c\x0e-\x1f\x7f]|\x21|[\x23-\x5b]|[\x5d-\x7e]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(\\([\x01-\x09\x0b\x0c\x0d-\x7f]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF]))))*(((\x20|\x09)*(\x0d\x0a))?(\x20|\x09)+)?(\x22)))@((([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])*([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])))\.)+(([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])*([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])))\.?$/i.test($("#userEmail" + status).val())) {
$("#tipMsg").text(Label.mailInvalidLabel);
$("#userEmail" + status).focus();
} else if ($("#userPassword" + status).val().replace(/\s/g, "") === "") {
} else if ($("#userPassword" + status).val() === "") {
$("#tipMsg").text(Label.passwordEmptyLabel);
$("#userPassword" + status).focus();
} else {
......
......@@ -155,28 +155,6 @@ var Util = {
Util.killIE();
Util.setTopBar();
},
/**
* @description topbar 清除缓存按钮事件
*/
clearCache: function(all) {
var data = '';
if (all === "all") {
data = '{"all": "all", "URI": ""}';
} else {
data = '{"all": "all", "URI": "' + window.location.pathname + '"}';
}
$.ajax({
type: "POST",
url: latkeConfig.servePath + "/clear-cache.do",
cache: false,
contentType: "application/json",
data: data,
success: function(result) {
window.location.reload();
}
});
},
/**
* @description 替换侧边栏表情为图片
* @param {Dom} comments 评论内容元素
......
......@@ -13,4 +13,4 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
var Util={error:function(){$("#tipMsg").text("Error: "+arguments[0]+" File: "+arguments[1]+"\nLine: "+arguments[2]+" please report this issue on https://github.com/b3log/b3log-solo/issues/new");$("#loadMsg").text("")},killIE:function(){var addKillPanel=function(){if(Cookie.readCookie("showKill")===""){var left=($(window).width()-701)/2,top=($(window).height()-420)/2;$("body").append("<div style='display: block; height: 100%; width: 100%; position: fixed; background-color: rgb(0, 0, 0); opacity: 0.6; top: 0px;z-index:11'></div><iframe style='left:"+left+"px;z-index:20;top: "+top+"px; position: fixed; border: 0px none; width: 701px; height: 420px;' src='"+latkeConfig.servePath+"/kill-browser.html'></iframe>")}};if($.browser.msie){if($.browser.version==="6.0"||$.browser.version==="7.0"){addKillPanel();return}if(window.external&&window.external.twGetRunPath){var path=external.twGetRunPath();if(path&&path.toLowerCase().indexOf("360se")>-1&&window.location.href.indexOf("admin-index")>-1){addKillPanel();return}}}},replaceEmString:function(str){var commentSplited=str.split("[em");if(commentSplited.length===1){return str}str=commentSplited[0];for(var j=1;j<commentSplited.length;j++){var key=commentSplited[j].substr(0,2);str+="<img src='"+latkeConfig.staticServePath+"/skins/"+Label.skinDirName+"/images/emotions/em"+key+".png' alt='"+Label["em"+key+"Label"]+"' title='"+Label["em"+key+"Label"]+"'/>"+commentSplited[j].substr(3)}return str},proessURL:function(url){if(!/^\w+:\/\//.test(url)){url="http://"+url}return url},switchMobile:function(skin){Cookie.createCookie("btouch_switch_toggle",skin,365);setTimeout(function(){location.reload()},1250)},setTopBar:function(){var $top=$("#top");if($top.length===1){var $showTop=$("#showTop");$showTop.click(function(){$top.slideDown();$showTop.hide()});$("#hideTop").click(function(){$top.slideUp();$showTop.show()})}},goTop:function(){var acceleration=acceleration||0.1;var y=$(window).scrollTop();var speed=1+acceleration;window.scrollTo(0,Math.floor(y/speed));if(y>0){var invokeFunction="Util.goTop("+acceleration+")";window.setTimeout(invokeFunction,16)}},goBottom:function(bottom){if(!bottom){bottom=0}window.scrollTo(0,$("body").height()-$(window).height()-bottom)},init:function(){Util.killIE();Util.setTopBar()},clearCache:function(all){var data="";if(all==="all"){data='{"all": "all", "URI": ""}'}else{data='{"all": "all", "URI": "'+window.location.pathname+'"}'}$.ajax({type:"POST",url:latkeConfig.servePath+"/clear-cache.do",cache:false,contentType:"application/json",data:data,success:function(result){window.location.reload()}})},replaceSideEm:function(comments){for(var i=0;i<comments.length;i++){var $comment=$(comments[i]);$comment.html(Util.replaceEmString($comment.html()))}},buildTags:function(id){id=id||"tags";var classes=["tags1","tags2","tags3","tags4","tags5"],bList=$("#"+id+" b").get();var max=parseInt($("#"+id+" b").last().text());var distance=Math.ceil(max/classes.length);for(var i=0;i<bList.length;i++){var num=parseInt(bList[i].innerHTML);for(var j=0;j<classes.length;j++){if(num>j*distance&&num<=(j+1)*distance){bList[i].parentNode.className=classes[j];break}}}$("#"+id).html($("#"+id+" li").get().sort(function(a,b){var valA=$(a).find("span").text().toLowerCase();var valB=$(b).find("span").text().toLowerCase();return valA.localeCompare(valB)}))},toDate:function(time,format){var dateTime=new Date(time);var o={"M+":dateTime.getMonth()+1,"d+":dateTime.getDate(),"H+":dateTime.getHours(),"m+":dateTime.getMinutes(),"s+":dateTime.getSeconds(),"q+":Math.floor((dateTime.getMonth()+3)/3),S:dateTime.getMilliseconds()};if(/(y+)/.test(format)){format=format.replace(RegExp.$1,(dateTime.getFullYear()+"").substr(4-RegExp.$1.length))}for(var k in o){if(new RegExp("("+k+")").test(format)){format=format.replace(RegExp.$1,RegExp.$1.length==1?o[k]:("00"+o[k]).substr((""+o[k]).length))}}return format},getWinHeight:function(){if(window.innerHeight){return window.innerHeight}if(document.compatMode==="CSS1Compat"){return window.document.documentElement.clientHeight}return window.document.body.clientHeight}};if(!Cookie){var Cookie={readCookie:function(name){var nameEQ=name+"=";var ca=document.cookie.split(";");for(var i=0;i<ca.length;i++){var c=ca[i];while(c.charAt(0)==" "){c=c.substring(1,c.length)}if(c.indexOf(nameEQ)==0){return decodeURIComponent(c.substring(nameEQ.length,c.length))}}return""},eraseCookie:function(name){this.createCookie(name,"",-1)},createCookie:function(name,value,days){var expires="";if(days){var date=new Date();date.setTime(date.getTime()+(days*24*60*60*1000));expires="; expires="+date.toGMTString()}document.cookie=name+"="+encodeURIComponent(value)+expires+"; path=/"}}};
\ No newline at end of file
var Util={error:function(){$("#tipMsg").text("Error: "+arguments[0]+" File: "+arguments[1]+"\nLine: "+arguments[2]+" please report this issue on https://github.com/b3log/b3log-solo/issues/new");$("#loadMsg").text("")},killIE:function(){var addKillPanel=function(){if(Cookie.readCookie("showKill")===""){var left=($(window).width()-701)/2,top=($(window).height()-420)/2;$("body").append("<div style='display: block; height: 100%; width: 100%; position: fixed; background-color: rgb(0, 0, 0); opacity: 0.6; top: 0px;z-index:11'></div><iframe style='left:"+left+"px;z-index:20;top: "+top+"px; position: fixed; border: 0px none; width: 701px; height: 420px;' src='"+latkeConfig.servePath+"/kill-browser.html'></iframe>")}};if($.browser.msie){if($.browser.version==="6.0"||$.browser.version==="7.0"){addKillPanel();return}if(window.external&&window.external.twGetRunPath){var path=external.twGetRunPath();if(path&&path.toLowerCase().indexOf("360se")>-1&&window.location.href.indexOf("admin-index")>-1){addKillPanel();return}}}},replaceEmString:function(str){var commentSplited=str.split("[em");if(commentSplited.length===1){return str}str=commentSplited[0];for(var j=1;j<commentSplited.length;j++){var key=commentSplited[j].substr(0,2);str+="<img src='"+latkeConfig.staticServePath+"/skins/"+Label.skinDirName+"/images/emotions/em"+key+".png' alt='"+Label["em"+key+"Label"]+"' title='"+Label["em"+key+"Label"]+"'/>"+commentSplited[j].substr(3)}return str},proessURL:function(url){if(!/^\w+:\/\//.test(url)){url="http://"+url}return url},switchMobile:function(skin){Cookie.createCookie("btouch_switch_toggle",skin,365);setTimeout(function(){location.reload()},1250)},setTopBar:function(){var $top=$("#top");if($top.length===1){var $showTop=$("#showTop");$showTop.click(function(){$top.slideDown();$showTop.hide()});$("#hideTop").click(function(){$top.slideUp();$showTop.show()})}},goTop:function(){var acceleration=acceleration||0.1;var y=$(window).scrollTop();var speed=1+acceleration;window.scrollTo(0,Math.floor(y/speed));if(y>0){var invokeFunction="Util.goTop("+acceleration+")";window.setTimeout(invokeFunction,16)}},goBottom:function(bottom){if(!bottom){bottom=0}window.scrollTo(0,$("body").height()-$(window).height()-bottom)},init:function(){Util.killIE();Util.setTopBar()},replaceSideEm:function(comments){for(var i=0;i<comments.length;i++){var $comment=$(comments[i]);$comment.html(Util.replaceEmString($comment.html()))}},buildTags:function(id){id=id||"tags";var classes=["tags1","tags2","tags3","tags4","tags5"],bList=$("#"+id+" b").get();var max=parseInt($("#"+id+" b").last().text());var distance=Math.ceil(max/classes.length);for(var i=0;i<bList.length;i++){var num=parseInt(bList[i].innerHTML);for(var j=0;j<classes.length;j++){if(num>j*distance&&num<=(j+1)*distance){bList[i].parentNode.className=classes[j];break}}}$("#"+id).html($("#"+id+" li").get().sort(function(a,b){var valA=$(a).find("span").text().toLowerCase();var valB=$(b).find("span").text().toLowerCase();return valA.localeCompare(valB)}))},toDate:function(time,format){var dateTime=new Date(time);var o={"M+":dateTime.getMonth()+1,"d+":dateTime.getDate(),"H+":dateTime.getHours(),"m+":dateTime.getMinutes(),"s+":dateTime.getSeconds(),"q+":Math.floor((dateTime.getMonth()+3)/3),S:dateTime.getMilliseconds()};if(/(y+)/.test(format)){format=format.replace(RegExp.$1,(dateTime.getFullYear()+"").substr(4-RegExp.$1.length))}for(var k in o){if(new RegExp("("+k+")").test(format)){format=format.replace(RegExp.$1,RegExp.$1.length==1?o[k]:("00"+o[k]).substr((""+o[k]).length))}}return format},getWinHeight:function(){if(window.innerHeight){return window.innerHeight}if(document.compatMode==="CSS1Compat"){return window.document.documentElement.clientHeight}return window.document.body.clientHeight}};if(!Cookie){var Cookie={readCookie:function(name){var nameEQ=name+"=";var ca=document.cookie.split(";");for(var i=0;i<ca.length;i++){var c=ca[i];while(c.charAt(0)==" "){c=c.substring(1,c.length)}if(c.indexOf(nameEQ)==0){return decodeURIComponent(c.substring(nameEQ.length,c.length))}}return""},eraseCookie:function(name){this.createCookie(name,"",-1)},createCookie:function(name,value,days){var expires="";if(days){var date=new Date();date.setTime(date.getTime()+(days*24*60*60*1000));expires="; expires="+date.toGMTString()}document.cookie=name+"="+encodeURIComponent(value)+expires+"; path=/"}}};
\ No newline at end of file
......@@ -18,32 +18,30 @@
*
* @author <a href="mailto:LLY219@gmail.com">Liyuan Li</a>
* @author <a href="mailto:DL88250@gmail.com">Liang Ding</a>
* @version 1.0.3.3, Feb 20, 2013
* @version 1.0.3.5, Oct 26, 2013
*/
var Page = function (tips) {
var Page = function(tips) {
this.currentCommentId = "";
this.tips = tips;
};
$.extend(Page.prototype, {
/*
* @description 评论时点击表情,在评论内容中插入相关代码
* @param {String} name 用于区别回复评论还是对文章的评论
*/
insertEmotions: function (name) {
insertEmotions: function(name) {
var _it = this;
if (name === undefined) {
name = "";
}
$("#emotions" + name + " span").click(function () {
$("#emotions" + name + " span").click(function() {
var $comment = $("#comment" + name);
var endPosition = _it._getCursorEndPosition($comment[0]);
var key = "[" + this.className + "]",
textValue = $comment[0].value;
textValue = textValue.substring(0, endPosition) + key + textValue.substring(endPosition, textValue.length);
$("#comment" + name).val(textValue);
if ($.browser.msie) {
endPosition -= textValue.split('\n').length - 1;
var oR = $comment[0].createTextRange();
......@@ -55,13 +53,12 @@ $.extend(Page.prototype, {
}
});
},
/**
* @description 获取当前光标最后位置
* @param {Dom} textarea 评论框对象
* @returns {Num} 光标位置
*/
_getCursorEndPosition: function (textarea) {
_getCursorEndPosition: function(textarea) {
textarea.focus();
if (textarea.setSelectionRange) { // W3C
return textarea.selectionEnd;
......@@ -71,20 +68,31 @@ $.extend(Page.prototype, {
oR = document.body.createTextRange();
oR.moveToElementText(textarea);
oS.getBookmark();
for (i = 0; oR.compareEndPoints('StartToStart', oS) < 0 && oS.moveStart("character", -1) !== 0; i ++) {
for (i = 0; oR.compareEndPoints('StartToStart', oS) < 0 && oS.moveStart("character", -1) !== 0; i++) {
if (textarea.value.charAt(i) == '\n') {
i ++;
i++;
}
}
return i;
}
},
/*
* @description 评论校验
* @param {String} state 用于区别回复评论还是对文章的评论
*/
validateComment: function (state) {
validateComment: function(state) {
if ($("#admin").data("login")) {
var commenterContent = $("#comment" + state).val().replace(/(^\s*)|(\s*$)/g, "");
if (2 > commenterContent.length || commenterContent.length > 500) {
$("#commentErrorTip" + state).html(this.tips.commentContentCannotEmptyLabel);
$("#comment" + state).focus();
} else {
return true;
}
$("#commentErrorTip" + state).show();
return false;
}
var commentName = $("#commentName" + state).val().replace(/(^\s*)|(\s*$)/g, ""),
commenterContent = $("#comment" + state).val().replace(/(^\s*)|(\s*$)/g, "");
if (2 > commentName.length || commentName.length > 20) {
......@@ -93,13 +101,13 @@ $.extend(Page.prototype, {
} else if ($("#commentEmail" + state).val().replace(/\s/g, "") === "") {
$("#commentErrorTip" + state).html(this.tips.mailCannotEmptyLabel);
$("#commentEmail" + state).focus();
} else if(!/^((([a-z]|\d|[!#\$%&'\*\+\-\/=\?\^_`{\|}~]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])+(\.([a-z]|\d|[!#\$%&'\*\+\-\/=\?\^_`{\|}~]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])+)*)|((\x22)((((\x20|\x09)*(\x0d\x0a))?(\x20|\x09)+)?(([\x01-\x08\x0b\x0c\x0e-\x1f\x7f]|\x21|[\x23-\x5b]|[\x5d-\x7e]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(\\([\x01-\x09\x0b\x0c\x0d-\x7f]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF]))))*(((\x20|\x09)*(\x0d\x0a))?(\x20|\x09)+)?(\x22)))@((([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])*([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])))\.)+(([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])*([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])))\.?$/i.test($("#commentEmail" + state).val())) {
} else if (!/^((([a-z]|\d|[!#\$%&'\*\+\-\/=\?\^_`{\|}~]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])+(\.([a-z]|\d|[!#\$%&'\*\+\-\/=\?\^_`{\|}~]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])+)*)|((\x22)((((\x20|\x09)*(\x0d\x0a))?(\x20|\x09)+)?(([\x01-\x08\x0b\x0c\x0e-\x1f\x7f]|\x21|[\x23-\x5b]|[\x5d-\x7e]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(\\([\x01-\x09\x0b\x0c\x0d-\x7f]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF]))))*(((\x20|\x09)*(\x0d\x0a))?(\x20|\x09)+)?(\x22)))@((([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])*([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])))\.)+(([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])*([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])))\.?$/i.test($("#commentEmail" + state).val())) {
$("#commentErrorTip" + state).html(this.tips.mailInvalidLabel);
$("#commentEmail" + state).focus();
} else if (2 > commenterContent.length || commenterContent.length > 500) {
$("#commentErrorTip" + state).html(this.tips.commentContentCannotEmptyLabel);
$("#comment" + state).focus();
} else if (!$("#admin").data("login") && $("#commentValidate" + state).val().replace(/\s/g, "") === "") {
} else if ($("#commentValidate" + state).val().replace(/\s/g, "") === "") {
$("#commentErrorTip" + state).html(this.tips.captchaCannotEmptyLabel);
$("#commentValidate" + state).focus();
} else {
......@@ -108,24 +116,22 @@ $.extend(Page.prototype, {
$("#commentErrorTip" + state).show();
return false;
},
/*
* @description 把评论中的标识替换为图片
* @param {Dom} selector
*/
replaceCommentsEm: function (selector) {
replaceCommentsEm: function(selector) {
var $commentContents = $(selector);
for (var i = 0; i < $commentContents.length; i++) {
var str = $commentContents[i].innerHTML;
$commentContents[i].innerHTML = Util.replaceEmString(str);
}
},
/*
* @description 初始化 SyantaxHighlighter
* @param {Array} languages 需要加载的语言
*/
_initSyntaxHighlighter: function (languages) {
_initSyntaxHighlighter: function(languages) {
// load brush js
for (var i = 0; i < languages.length; i++) {
switch (languages[i]) {
......@@ -264,12 +270,11 @@ $.extend(Page.prototype, {
SyntaxHighlighter.config.stripBrs = true;
SyntaxHighlighter.all();
},
/*
* @description 加载 SyntaxHighlighter
* @param {String} SHTheme SyntaxHighLighter 样式
*/
_loadSyntaxHighlighter: function (SHTheme) {
_loadSyntaxHighlighter: function(SHTheme) {
var cssName = SHTheme ? SHTheme : "shCoreEclipse",
that = this;
// load css
......@@ -289,10 +294,9 @@ $.extend(Page.prototype, {
// get brush settings
var languages = [],
isScrip = false;
$(".article-body pre").each(function () {
$(".article-body pre").each(function() {
var name = this.className.split(";")[0];
var language = name.substr(7, name.length - 1);
if (this.className.indexOf("html-script: true") > -1 &&
(language !== "xml" && language !== "xhtml" &&
language !== "xslt" && language != "html")) {
......@@ -301,7 +305,6 @@ $.extend(Page.prototype, {
languages.push(language);
});
// when html-script is true, need shBrushXml.js
if (isScrip) {
$.ajax({
......@@ -318,17 +321,15 @@ $.extend(Page.prototype, {
}
});
},
/*
* @description 解析语法高亮
* @param {Obj} obj 语法高亮配置参数
* @param {Obj} obj.SHTheme 语法高亮 SyntaxHighLighter 样式
*/
parseLanguage: function (obj) {
parseLanguage: function(obj) {
var isPrettify = false,
isSH = false;
$(".article-body pre").each(function () {
$(".article-body pre").each(function() {
if (this.className.indexOf("brush") > -1) {
isSH = true;
}
......@@ -337,8 +338,6 @@ $.extend(Page.prototype, {
isPrettify = true;
}
});
if (isSH) {
this._loadSyntaxHighlighter(obj ? (obj.SHTheme ? obj.SHTheme : undefined) : undefined);
}
......@@ -362,56 +361,39 @@ $.extend(Page.prototype, {
});
}
},
/*
* @description 文章/自定义页面加载
* @param {Obj} obj 配置设定
* @param {Obj} obj.language 代码高亮配置
*/
load: function (obj) {
load: function(obj) {
var that = this;
// if login, remove captcha
if ($("#admin").data("login")) {
$("#commentValidate").parent().parent().hide();
}
// emotions
that.insertEmotions();
// language
that.parseLanguage(obj ? (obj.language ? obj.language : undefined) : undefined);
// submit comment
$("#commentValidate").keypress(function (event) {
$("#commentValidate").keypress(function(event) {
if (event.keyCode === 13) {
that.submitComment();
}
});
$("#comment").keypress(function (event) {
$("#comment").keypress(function(event) {
if (event.keyCode === 13 && event.ctrlKey) {
that.submitComment();
}
});
// captcha
$("#captcha").click(function () {
$("#captcha").click(function() {
$(this).attr("src", latkeConfig.servePath + "/captcha.do?code=" + Math.random());
});
// cookie
var $top = $("#top #admin");
if ($top.length === 1) {
if ($top.find("a").length > 3) {
Cookie.createCookie("commentName", $top.find("span").text(), 365);
Cookie.createCookie("commentURL", window.location.host, 365);
}
}
if (!$("#admin").data("login")) {
$("#commentEmail").val(Cookie.readCookie("commentEmail"));
$("#commentURL").val(Cookie.readCookie("commentURL"));
$("#commentName").val(Cookie.readCookie("commentName"));
}
// if no JSON, add it.
try {
JSON
......@@ -420,18 +402,17 @@ $.extend(Page.prototype, {
}
},
/*
* @description 加载随机文章
* @param {String} headTitle 随机文章标题
*/
loadRandomArticles: function (headTitle) {
loadRandomArticles: function(headTitle) {
var randomArticles1Label = this.tips.randomArticles1Label;
// getRandomArticles
$.ajax({
url: latkeConfig.servePath + "/get-random-articles.do",
type: "POST",
success: function(result, textStatus){
success: function(result, textStatus) {
var randomArticles = result.randomArticles;
if (!randomArticles || 0 === randomArticles.length) {
$("#randomArticles").remove();
......@@ -443,7 +424,7 @@ $.extend(Page.prototype, {
var article = randomArticles[i];
var title = article.articleTitle;
var randomArticleLiHtml = "<li>" + "<a rel='nofollow' title='" + title + "' href='" + latkeConfig.servePath +
article.articlePermalink +"'>" + title + "</a></li>";
article.articlePermalink + "'>" + title + "</a></li>";
listHtml += randomArticleLiHtml;
}
......@@ -453,17 +434,16 @@ $.extend(Page.prototype, {
}
});
},
/*
* @description 加载相关文章
* @param {String} id 文章 id
* @param {String} headTitle 相关文章标题
*/
loadRelevantArticles: function (id, headTitle) {
loadRelevantArticles: function(id, headTitle) {
$.ajax({
url: latkeConfig.servePath + "/article/id/" + id + "/relevant/articles",
type: "GET",
success: function(data, textStatus){
success: function(data, textStatus) {
var articles = data.relevantArticles;
if (!articles || 0 === articles.length) {
$("#relevantArticles").remove();
......@@ -484,18 +464,17 @@ $.extend(Page.prototype, {
+ listHtml + "</ul>";
$("#relevantArticles").append(relevantArticleListHtml);
},
error: function () {
error: function() {
$("#relevantArticles").remove();
}
});
},
/*
* @description 加载站外相关文章
* @param {String} tags 文章 tags
* @param {String} headTitle 站外相关文章标题
*/
loadExternalRelevantArticles: function (tags, headTitle) {
loadExternalRelevantArticles: function(tags, headTitle) {
var tips = this.tips;
try {
$.ajax({
......@@ -503,11 +482,11 @@ $.extend(Page.prototype, {
+ "&blogHost=" + tips.blogHost + "&paginationPageSize=" + tips.externalRelevantArticlesDisplayCount,
type: "GET",
cache: true,
dataType:"jsonp",
error: function(){
dataType: "jsonp",
error: function() {
$("#externalRelevantArticles").remove();
},
success: function(data, textStatus){
success: function(data, textStatus) {
var articles = data.articles;
if (!articles || 0 === articles.length) {
$("#externalRelevantArticles").remove();
......@@ -534,13 +513,12 @@ $.extend(Page.prototype, {
// 忽略相关文章加载异常:load script error
}
},
/*
* @description 提交评论
* @param {String} commentId 回复评论时的评论 id
* @param {String} state 区分回复文章还是回复评论的标识
*/
submitComment: function (commentId, state) {
submitComment: function(commentId, state) {
if (!state) {
state = '';
}
......@@ -554,8 +532,13 @@ $.extend(Page.prototype, {
if (this.validateComment(state)) {
$("#submitCommentButton" + state).attr("disabled", "disabled");
$("#commentErrorTip" + state).show().html(this.tips.loadingLabel);
var requestJSONObject = {
"oId": tips.oId,
"commentContent": $("#comment" + state).val().replace(/(^\s*)|(\s*$)/g, "")
};
if (!$("#admin").data("login")) {
requestJSONObject = {
"oId": tips.oId,
"commentContent": $("#comment" + state).val().replace(/(^\s*)|(\s*$)/g, ""),
"commentEmail": $("#commentEmail" + state).val(),
......@@ -563,64 +546,72 @@ $.extend(Page.prototype, {
"commentName": $("#commentName" + state).val().replace(/(^\s*)|(\s*$)/g, ""),
"captcha": $("#commentValidate" + state).val()
};
Cookie.createCookie("commentName", requestJSONObject.commentName, 365);
Cookie.createCookie("commentEmail", requestJSONObject.commentEmail, 365);
Cookie.createCookie("commentURL", $("#commentURL" + state).val().replace(/(^\s*)|(\s*$)/g, ""), 365);
}
if (state === "Reply") {
requestJSONObject.commentOriginalCommentId = commentId;
}
$.ajax({
type: "POST",
url: latkeConfig.servePath + "/add-" + type + "-comment.do",
cache: false,
contentType: "application/json",
data: JSON.stringify(requestJSONObject),
success: function(result){
success: function(result) {
if (!result.sc) {
$("#commentErrorTip" + state).html(result.msg);
$("#commentValidate" + state).val("").focus();
$("#comment" + state).val("").focus();
$("#submitCommentButton" + state).removeAttr("disabled");
if (!$("#admin").data("login")) {
$("#captcha" + state).attr("src", latkeConfig.servePath + "/captcha.do?code=" + Math.random());
}
return;
}
result.replyNameHTML = "";
if (!$("#admin").data("login")) {
$("#captcha" + state).attr("src", latkeConfig.servePath + "/captcha.do?code=" + Math.random());
if ($("#commentURL" + state).val().replace(/\s/g, "") === "") {
result.replyNameHTML = '<a>' + $("#commentName" + state).val() + '</a>';
} else {
result.replyNameHTML = '<a href="' + Util.proessURL($("#commentURL" + state).val()) +
'" target="_blank">' + $("#commentName" + state).val() + '</a>';
}
result.userName = $("#commentName" + state).val();
} else {
result.replyNameHTML = '<a href="' + window.location.host +
'" target="_blank">' + $("#adminName").text() + '</a>';
result.userName = $("#adminName").text();
}
that.addCommentAjax(addComment(result, state), state);
$("#submitCommentButton" + state).removeAttr("disabled");
$("#captcha" + state).attr("src", latkeConfig.servePath + "/captcha.do?code=" + Math.random());
}
});
Cookie.createCookie("commentName", requestJSONObject.commentName, 365);
Cookie.createCookie("commentEmail", requestJSONObject.commentEmail, 365);
Cookie.createCookie("commentURL", $("#commentURL" + state).val().replace(/(^\s*)|(\s*$)/g, ""), 365);
}
},
/*
* @description 添加回复评论表单
* @param {String} id 被回复的评论 id
* @param {String} commentFormHTML 评论表单HTML
* @param {String} endHTML 判断该表单使用 table 还是 div 标签,然后进行构造
*/
addReplyForm: function (id, commentFormHTML, endHTML) {
addReplyForm: function(id, commentFormHTML, endHTML) {
var that = this;
if (id === this.currentCommentId) {
if (Cookie.readCookie("commentName") === "") {
if ($("#commentNameReply").val() === "") {
$("#commentNameReply").focus();
} else if ($("#commentEmailReply").val() === "") {
$("#commentEmailReply").focus();
} else {
$("#commentReply").focus();
}
return;
} else {
}
$("#replyForm").remove();
endHTML = endHTML ? endHTML : "";
if (endHTML === "</div>") {
......@@ -630,67 +621,57 @@ $.extend(Page.prototype, {
}
// change id, bind event and set value
$("#replyForm input, #replyForm textarea").each(function () {
$("#replyForm input, #replyForm textarea").each(function() {
this.id = this.id + "Reply";
});
$("#commentNameReply").val(Cookie.readCookie("commentName"));
$("#commentEmailReply").val(Cookie.readCookie("commentEmail"));
var $label = $("#replyForm #commentURLLabel");
if ($label.length === 1) {
$label.attr("id", "commentURLLabelReply");
}
$("#commentURLReply").val(Cookie.readCookie("commentURL"));
$("#replyForm #emotions").attr("id", "emotionsReply");
this.insertEmotions("Reply");
$("#commentReply").unbind().keypress(function (event) {
$("#commentReply").unbind().keypress(function(event) {
if (event.keyCode === 13 && event.ctrlKey) {
that.submitComment(id, 'Reply');
event.preventDefault();
}
});
$("#commentValidateReply").unbind().keypress(function (event) {
$("#commentValidateReply").unbind().keypress(function(event) {
if (event.keyCode === 13) {
that.submitComment(id, 'Reply');
event.preventDefault();
}
});
$("#replyForm #captcha").attr("id", "captchaReply").
attr("src", latkeConfig.servePath + "/captcha.do?" + new Date().getTime()).click(function () {
attr("src", latkeConfig.servePath + "/captcha.do?" + new Date().getTime()).click(function() {
$(this).attr("src", latkeConfig.servePath + "/captcha.do?code=" + Math.random());
});
$("#replyForm #commentErrorTip").attr("id", "commentErrorTipReply").html("").hide();
$("#replyForm #submitCommentButton").attr("id", "submitCommentButtonReply");
$("#replyForm #submitCommentButtonReply").unbind("click").removeAttr("onclick").click(function () {
$("#replyForm #submitCommentButtonReply").unbind("click").removeAttr("onclick").click(function() {
that.submitComment(id, 'Reply');
});
if (Cookie.readCookie("commentName") === "") {
if ($("#commentNameReply").val() === "") {
$("#commentNameReply").focus();
} else if ($("#commentEmailReply").val() === "") {
$("#commentEmailReply").focus();
} else {
$("#commentReply").focus();
}
}
this.currentCommentId = id;
},
/*
* @description 隐藏回复评论的浮出层
* @parma {String} id 被回复的评论 id
*/
hideComment: function (id) {
hideComment: function(id) {
$("#commentRef" + id).hide();
},
/*
* @description 显示回复评论的浮出层
* @parma {Dom} it 触发事件的 dom
......@@ -698,12 +679,12 @@ $.extend(Page.prototype, {
* @param {Int} top 位置相对浮出层的高度
* @param {String} [parentTag] it 如果嵌入在 position 为 relative 的元素 A 中时,需取到 A 元素
*/
showComment: function (it, id, top, parentTag) {
showComment: function(it, id, top, parentTag) {
var positionTop = parseInt($(it).position().top);
if (parentTag) {
positionTop = parseInt($(it).parents(parentTag).position().top);
}
if ( $("#commentRef" + id).length > 0) {
if ($("#commentRef" + id).length > 0) {
// 此处重复设置 top 是由于评论为异步,原有回复评论的显示位置应往下移动
$("#commentRef" + id).show().css("top", (positionTop + top) + "px");
} else {
......@@ -714,13 +695,12 @@ $.extend(Page.prototype, {
$("#commentRef" + id).css("top", (positionTop + top) + "px");
}
},
/*
* @description 回复不刷新,将回复内容异步添加到评论列表中
* @parma {String} commentHTML 回复内容 HTML
* @param {String} state 用于区分评论文章还是回复评论
*/
addCommentAjax: function (commentHTML, state) {
addCommentAjax: function(commentHTML, state) {
if ($("#comments").children().length > 0) {
$($("#comments").children()[0]).before(commentHTML);
} else {
......
......@@ -13,4 +13,4 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
var Page=function(tips){this.currentCommentId="";this.tips=tips};$.extend(Page.prototype,{insertEmotions:function(name){var _it=this;if(name===undefined){name=""}$("#emotions"+name+" span").click(function(){var $comment=$("#comment"+name);var endPosition=_it._getCursorEndPosition($comment[0]);var key="["+this.className+"]",textValue=$comment[0].value;textValue=textValue.substring(0,endPosition)+key+textValue.substring(endPosition,textValue.length);$("#comment"+name).val(textValue);if($.browser.msie){endPosition-=textValue.split("\n").length-1;var oR=$comment[0].createTextRange();oR.collapse(true);oR.moveStart("character",endPosition+6);oR.select()}else{$comment[0].setSelectionRange(endPosition+6,endPosition+6)}})},_getCursorEndPosition:function(textarea){textarea.focus();if(textarea.setSelectionRange){return textarea.selectionEnd}else{if(document.selection){var i=0,oS=document.selection.createRange(),oR=document.body.createTextRange();oR.moveToElementText(textarea);oS.getBookmark();for(i=0;oR.compareEndPoints("StartToStart",oS)<0&&oS.moveStart("character",-1)!==0;i++){if(textarea.value.charAt(i)=="\n"){i++}}return i}}},validateComment:function(state){var commentName=$("#commentName"+state).val().replace(/(^\s*)|(\s*$)/g,""),commenterContent=$("#comment"+state).val().replace(/(^\s*)|(\s*$)/g,"");if(2>commentName.length||commentName.length>20){$("#commentErrorTip"+state).html(this.tips.nameTooLongLabel);$("#commentName"+state).focus()}else{if($("#commentEmail"+state).val().replace(/\s/g,"")===""){$("#commentErrorTip"+state).html(this.tips.mailCannotEmptyLabel);$("#commentEmail"+state).focus()}else{if(!/^((([a-z]|\d|[!#\$%&'\*\+\-\/=\?\^_`{\|}~]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])+(\.([a-z]|\d|[!#\$%&'\*\+\-\/=\?\^_`{\|}~]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])+)*)|((\x22)((((\x20|\x09)*(\x0d\x0a))?(\x20|\x09)+)?(([\x01-\x08\x0b\x0c\x0e-\x1f\x7f]|\x21|[\x23-\x5b]|[\x5d-\x7e]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(\\([\x01-\x09\x0b\x0c\x0d-\x7f]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF]))))*(((\x20|\x09)*(\x0d\x0a))?(\x20|\x09)+)?(\x22)))@((([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])*([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])))\.)+(([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])*([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])))\.?$/i.test($("#commentEmail"+state).val())){$("#commentErrorTip"+state).html(this.tips.mailInvalidLabel);$("#commentEmail"+state).focus()}else{if(2>commenterContent.length||commenterContent.length>500){$("#commentErrorTip"+state).html(this.tips.commentContentCannotEmptyLabel);$("#comment"+state).focus()}else{if(!$("#admin").data("login")&&$("#commentValidate"+state).val().replace(/\s/g,"")===""){$("#commentErrorTip"+state).html(this.tips.captchaCannotEmptyLabel);$("#commentValidate"+state).focus()}else{return true}}}}}$("#commentErrorTip"+state).show();return false},replaceCommentsEm:function(selector){var $commentContents=$(selector);for(var i=0;i<$commentContents.length;i++){var str=$commentContents[i].innerHTML;$commentContents[i].innerHTML=Util.replaceEmString(str)}},_initSyntaxHighlighter:function(languages){for(var i=0;i<languages.length;i++){switch(languages[i]){case"groovy":languages[i]="groovy "+latkeConfig.staticServePath+"/js/lib/SyntaxHighlighter/scripts/shBrushGroovy.js";break;case"java":languages[i]="java "+latkeConfig.staticServePath+"/js/lib/SyntaxHighlighter/scripts/shBrushJava.js";break;case"php":languages[i]="php "+latkeConfig.staticServePath+"/js/lib/SyntaxHighlighter/scripts/shBrushPhp.js";break;case"scala":languages[i]="scala "+latkeConfig.staticServePath+"/js/lib/SyntaxHighlighter/scripts/shBrushScala.js";break;case"sql":languages[i]="sql "+latkeConfig.staticServePath+"/js/lib/SyntaxHighlighter/scripts/shBrushSql.js";break;case"applescript":languages[i]="applescript "+latkeConfig.staticServePath+"/js/lib/SyntaxHighlighter/scripts/shBrushAppleScript.js";break;case"as3":case"actionscript3":languages[i]="actionscript3 as3 "+latkeConfig.staticServePath+"/js/lib/SyntaxHighlighter/scripts/shBrushAS3.js";break;case"bash":case"shell":languages[i]="bash shell "+latkeConfig.staticServePath+"/js/lib/SyntaxHighlighter/scripts/shBrushBash.js";break;case"coldfusion":case"cf":languages[i]="coldfusion cf "+latkeConfig.staticServePath+"/js/lib/SyntaxHighlighter/scripts/shBrushColdFusion.js";break;case"c#":case"c-sharp":case"csharp":languages[i]="c# c-sharp csharp "+latkeConfig.staticServePath+"/js/lib/SyntaxHighlighter/scripts/shBrushCSharp.js";break;case"cpp":case"c":languages[i]="cpp c "+latkeConfig.staticServePath+"/js/lib/SyntaxHighlighter/scripts/shBrushCpp.js";break;case"css":languages[i]="css "+latkeConfig.staticServePath+"/js/lib/SyntaxHighlighter/scripts/shBrushCss.js";break;case"delphi":case"pascal":languages[i]="delphi pascal "+latkeConfig.staticServePath+"/js/lib/SyntaxHighlighter/scripts/shBrushDelphi.js";break;case"diff":case"patch":case"pas":languages[i]="diff patch pas "+latkeConfig.staticServePath+"/js/lib/SyntaxHighlighter/scripts/shBrushDiff.js";break;case"erl":case"erlang":languages[i]="erl erlang "+latkeConfig.staticServePath+"/js/lib/SyntaxHighlighter/scripts/shBrushErlang.js";break;case"js":case"jscript":case"javascript":languages[i]="js jscript javascript "+latkeConfig.staticServePath+"/js/lib/SyntaxHighlighter/scripts/shBrushJScript.js";break;case"jfx":case"javafx":languages[i]="jfx javafx "+latkeConfig.staticServePath+"/js/lib/SyntaxHighlighter/scripts/shBrushJavaFX.js";break;case"perl":case"pl":languages[i]="perl pl "+latkeConfig.staticServePath+"/js/lib/SyntaxHighlighter/scripts/shBrushPerl.js";break;case"plain":case"text":languages[i]="text plain "+latkeConfig.staticServePath+"/js/lib/SyntaxHighlighter/scripts/shBrushPlain.js";break;case"ps":case"powershell":languages[i]="ps powershell "+latkeConfig.staticServePath+"/js/lib/SyntaxHighlighter/scripts/shBrushPowerShell.js";break;case"py":case"python":languages[i]="py python "+latkeConfig.staticServePath+"/js/lib/SyntaxHighlighter/scripts/shBrushPython.js";break;case"rails":case"ror":case"ruby":case"rb":languages[i]="ruby rails ror rb "+latkeConfig.staticServePath+"/js/lib/SyntaxHighlighter/scripts/shBrushRuby.js";break;case"sass":case"scss":languages[i]="sass scss "+latkeConfig.staticServePath+"/js/lib/SyntaxHighlighter/scripts/shBrushSass.js";break;case"vb":case"vbnet":languages[i]="vb vbnet "+latkeConfig.staticServePath+"/js/lib/SyntaxHighlighter/scripts/shBrushVb.js";break;case"xml":case"xhtml":case"xslt":case"html":languages[i]="xml xhtml xslt html "+latkeConfig.staticServePath+"/js/lib/SyntaxHighlighter/scripts/shBrushXml.js";break;default:break}}SyntaxHighlighter.autoloader.apply(null,languages);SyntaxHighlighter.config.stripBrs=true;SyntaxHighlighter.all()},_loadSyntaxHighlighter:function(SHTheme){var cssName=SHTheme?SHTheme:"shCoreEclipse",that=this;if(document.createStyleSheet){document.createStyleSheet(latkeConfig.staticServePath+"/js/lib/SyntaxHighlighter/styles/"+cssName+".css")}else{$("head").append($("<link rel='stylesheet' href='"+latkeConfig.staticServePath+"/js/lib/SyntaxHighlighter/styles/"+cssName+".css' type='text/css' charset='utf-8' />"))}$.ajax({url:latkeConfig.staticServePath+"/js/lib/SyntaxHighlighter/scripts/shCore.js",dataType:"script",cache:true,success:function(){var languages=[],isScrip=false;$(".article-body pre").each(function(){var name=this.className.split(";")[0];var language=name.substr(7,name.length-1);if(this.className.indexOf("html-script: true")>-1&&(language!=="xml"&&language!=="xhtml"&&language!=="xslt"&&language!="html")){isScrip=true}languages.push(language)});if(isScrip){$.ajax({url:latkeConfig.staticServePath+"/js/lib/SyntaxHighlighter/scripts/shBrushXml.js",dataType:"script",cache:true,success:function(){that._initSyntaxHighlighter(languages)}})}else{that._initSyntaxHighlighter(languages)}}})},parseLanguage:function(obj){var isPrettify=false,isSH=false;$(".article-body pre").each(function(){if(this.className.indexOf("brush")>-1){isSH=true}if(this.className.indexOf("prettyprint")>-1){isPrettify=true}});if(isSH){this._loadSyntaxHighlighter(obj?(obj.SHTheme?obj.SHTheme:undefined):undefined)}if(isPrettify){if(document.createStyleSheet){document.createStyleSheet(latkeConfig.staticServePath+"/js/lib/google-code-prettify/prettify.css")}else{$("head").append($("<link rel='stylesheet' href='"+latkeConfig.staticServePath+"/js/lib/google-code-prettify/prettify.css'>"))}$.ajax({url:latkeConfig.staticServePath+"/js/lib/google-code-prettify/prettify.js",dataType:"script",cache:true,success:function(){prettyPrint()}})}},load:function(obj){var that=this;if($("#admin").data("login")){$("#commentValidate").parent().parent().hide()}that.insertEmotions();that.parseLanguage(obj?(obj.language?obj.language:undefined):undefined);$("#commentValidate").keypress(function(event){if(event.keyCode===13){that.submitComment()}});$("#comment").keypress(function(event){if(event.keyCode===13&&event.ctrlKey){that.submitComment()}});$("#captcha").click(function(){$(this).attr("src",latkeConfig.servePath+"/captcha.do?code="+Math.random())});var $top=$("#top #admin");if($top.length===1){if($top.find("a").length>3){Cookie.createCookie("commentName",$top.find("span").text(),365);Cookie.createCookie("commentURL",window.location.host,365)}}$("#commentEmail").val(Cookie.readCookie("commentEmail"));$("#commentURL").val(Cookie.readCookie("commentURL"));$("#commentName").val(Cookie.readCookie("commentName"));try{JSON}catch(e){document.write('<script src="'+latkeConfig.staticServePath+'/js/lib/json2.js"><\/script>')}},loadRandomArticles:function(headTitle){var randomArticles1Label=this.tips.randomArticles1Label;$.ajax({url:latkeConfig.servePath+"/get-random-articles.do",type:"POST",success:function(result,textStatus){var randomArticles=result.randomArticles;if(!randomArticles||0===randomArticles.length){$("#randomArticles").remove();return}var listHtml="";for(var i=0;i<randomArticles.length;i++){var article=randomArticles[i];var title=article.articleTitle;var randomArticleLiHtml="<li><a rel='nofollow' title='"+title+"' href='"+latkeConfig.servePath+article.articlePermalink+"'>"+title+"</a></li>";listHtml+=randomArticleLiHtml}var titleHTML=headTitle?headTitle:"<h4>"+randomArticles1Label+"</h4>";var randomArticleListHtml=titleHTML+"<ul class='marginLeft12'>"+listHtml+"</ul>";$("#randomArticles").append(randomArticleListHtml)}})},loadRelevantArticles:function(id,headTitle){$.ajax({url:latkeConfig.servePath+"/article/id/"+id+"/relevant/articles",type:"GET",success:function(data,textStatus){var articles=data.relevantArticles;if(!articles||0===articles.length){$("#relevantArticles").remove();return}var listHtml="";for(var i=0;i<articles.length;i++){var article=articles[i];var title=article.articleTitle;var articleLiHtml="<li><a rel='nofollow' title='"+title+"' href='"+latkeConfig.servePath+article.articlePermalink+"'>"+title+"</a></li>";listHtml+=articleLiHtml}var relevantArticleListHtml=headTitle+"<ul class='marginLeft12'>"+listHtml+"</ul>";$("#relevantArticles").append(relevantArticleListHtml)},error:function(){$("#relevantArticles").remove()}})},loadExternalRelevantArticles:function(tags,headTitle){var tips=this.tips;try{$.ajax({url:"http://rhythm.b3log.org:80/get-articles-by-tags.do?tags="+tags+"&blogHost="+tips.blogHost+"&paginationPageSize="+tips.externalRelevantArticlesDisplayCount,type:"GET",cache:true,dataType:"jsonp",error:function(){$("#externalRelevantArticles").remove()},success:function(data,textStatus){var articles=data.articles;if(!articles||0===articles.length){$("#externalRelevantArticles").remove();return}var listHtml="";for(var i=0;i<articles.length;i++){var article=articles[i];var title=article.articleTitle;var articleLiHtml="<li><a rel='nofollow' title='"+title+"' target='_blank' href='"+article.articlePermalink+"'>"+title+"</a></li>";listHtml+=articleLiHtml}var titleHTML=headTitle?headTitle:"<h4>"+tips.externalRelevantArticles1Label+"</h4>";var randomArticleListHtml=titleHTML+"<ul class='marginLeft12'>"+listHtml+"</ul>";$("#externalRelevantArticles").append(randomArticleListHtml)}})}catch(e){}},submitComment:function(commentId,state){if(!state){state=""}var that=this,tips=this.tips,type="article";if(tips.externalRelevantArticlesDisplayCount===undefined){type="page"}if(this.validateComment(state)){$("#submitCommentButton"+state).attr("disabled","disabled");$("#commentErrorTip"+state).show().html(this.tips.loadingLabel);var requestJSONObject={oId:tips.oId,commentContent:$("#comment"+state).val().replace(/(^\s*)|(\s*$)/g,""),commentEmail:$("#commentEmail"+state).val(),commentURL:Util.proessURL($("#commentURL"+state).val().replace(/(^\s*)|(\s*$)/g,"")),commentName:$("#commentName"+state).val().replace(/(^\s*)|(\s*$)/g,""),captcha:$("#commentValidate"+state).val()};if(state==="Reply"){requestJSONObject.commentOriginalCommentId=commentId}$.ajax({type:"POST",url:latkeConfig.servePath+"/add-"+type+"-comment.do",cache:false,contentType:"application/json",data:JSON.stringify(requestJSONObject),success:function(result){if(!result.sc){$("#commentErrorTip"+state).html(result.msg);$("#commentValidate"+state).val("").focus();$("#submitCommentButton"+state).removeAttr("disabled");$("#captcha"+state).attr("src",latkeConfig.servePath+"/captcha.do?code="+Math.random());return}result.replyNameHTML="";if($("#commentURL"+state).val().replace(/\s/g,"")===""){result.replyNameHTML="<a>"+$("#commentName"+state).val()+"</a>"}else{result.replyNameHTML='<a href="'+Util.proessURL($("#commentURL"+state).val())+'" target="_blank">'+$("#commentName"+state).val()+"</a>"}that.addCommentAjax(addComment(result,state),state);$("#submitCommentButton"+state).removeAttr("disabled");$("#captcha"+state).attr("src",latkeConfig.servePath+"/captcha.do?code="+Math.random())}});Cookie.createCookie("commentName",requestJSONObject.commentName,365);Cookie.createCookie("commentEmail",requestJSONObject.commentEmail,365);Cookie.createCookie("commentURL",$("#commentURL"+state).val().replace(/(^\s*)|(\s*$)/g,""),365)}},addReplyForm:function(id,commentFormHTML,endHTML){var that=this;if(id===this.currentCommentId){if(Cookie.readCookie("commentName")===""){$("#commentNameReply").focus()}else{$("#commentReply").focus()}return}else{$("#replyForm").remove();endHTML=endHTML?endHTML:"";if(endHTML==="</div>"){$("#"+id).append(commentFormHTML+$("#commentForm").html()+endHTML)}else{$("#"+id).append(commentFormHTML+$("#commentForm").html()+"</table>"+endHTML)}$("#replyForm input, #replyForm textarea").each(function(){this.id=this.id+"Reply"});$("#commentNameReply").val(Cookie.readCookie("commentName"));$("#commentEmailReply").val(Cookie.readCookie("commentEmail"));var $label=$("#replyForm #commentURLLabel");if($label.length===1){$label.attr("id","commentURLLabelReply")}$("#commentURLReply").val(Cookie.readCookie("commentURL"));$("#replyForm #emotions").attr("id","emotionsReply");this.insertEmotions("Reply");$("#commentReply").unbind().keypress(function(event){if(event.keyCode===13&&event.ctrlKey){that.submitComment(id,"Reply");event.preventDefault()}});$("#commentValidateReply").unbind().keypress(function(event){if(event.keyCode===13){that.submitComment(id,"Reply");event.preventDefault()}});$("#replyForm #captcha").attr("id","captchaReply").attr("src",latkeConfig.servePath+"/captcha.do?"+new Date().getTime()).click(function(){$(this).attr("src",latkeConfig.servePath+"/captcha.do?code="+Math.random())});$("#replyForm #commentErrorTip").attr("id","commentErrorTipReply").html("").hide();$("#replyForm #submitCommentButton").attr("id","submitCommentButtonReply");$("#replyForm #submitCommentButtonReply").unbind("click").removeAttr("onclick").click(function(){that.submitComment(id,"Reply")});if(Cookie.readCookie("commentName")===""){$("#commentNameReply").focus()}else{$("#commentReply").focus()}}this.currentCommentId=id},hideComment:function(id){$("#commentRef"+id).hide()},showComment:function(it,id,top,parentTag){var positionTop=parseInt($(it).position().top);if(parentTag){positionTop=parseInt($(it).parents(parentTag).position().top)}if($("#commentRef"+id).length>0){$("#commentRef"+id).show().css("top",(positionTop+top)+"px")}else{var $refComment=$("#"+id).clone();$refComment.addClass("comment-body-ref").attr("id","commentRef"+id);$refComment.find("#replyForm").remove();$("#comments").append($refComment);$("#commentRef"+id).css("top",(positionTop+top)+"px")}},addCommentAjax:function(commentHTML,state){if($("#comments").children().length>0){$($("#comments").children()[0]).before(commentHTML)}else{$("#comments").html(commentHTML)}if(state===""){$("#commentErrorTip").html("").hide();$("#comment").val("");$("#commentValidate").val("");$("#captcha").attr("src",latkeConfig.servePath+"/captcha.do?code="+Math.random())}else{$("#replyForm").remove()}window.location.hash="#comments"}});
\ No newline at end of file
var Page=function(tips){this.currentCommentId="";this.tips=tips};$.extend(Page.prototype,{insertEmotions:function(name){var _it=this;if(name===undefined){name=""}$("#emotions"+name+" span").click(function(){var $comment=$("#comment"+name);var endPosition=_it._getCursorEndPosition($comment[0]);var key="["+this.className+"]",textValue=$comment[0].value;textValue=textValue.substring(0,endPosition)+key+textValue.substring(endPosition,textValue.length);$("#comment"+name).val(textValue);if($.browser.msie){endPosition-=textValue.split("\n").length-1;var oR=$comment[0].createTextRange();oR.collapse(true);oR.moveStart("character",endPosition+6);oR.select()}else{$comment[0].setSelectionRange(endPosition+6,endPosition+6)}})},_getCursorEndPosition:function(textarea){textarea.focus();if(textarea.setSelectionRange){return textarea.selectionEnd}else{if(document.selection){var i=0,oS=document.selection.createRange(),oR=document.body.createTextRange();oR.moveToElementText(textarea);oS.getBookmark();for(i=0;oR.compareEndPoints("StartToStart",oS)<0&&oS.moveStart("character",-1)!==0;i++){if(textarea.value.charAt(i)=="\n"){i++}}return i}}},validateComment:function(state){if($("#admin").data("login")){var commenterContent=$("#comment"+state).val().replace(/(^\s*)|(\s*$)/g,"");if(2>commenterContent.length||commenterContent.length>500){$("#commentErrorTip"+state).html(this.tips.commentContentCannotEmptyLabel);$("#comment"+state).focus()}else{return true}$("#commentErrorTip"+state).show();return false}var commentName=$("#commentName"+state).val().replace(/(^\s*)|(\s*$)/g,""),commenterContent=$("#comment"+state).val().replace(/(^\s*)|(\s*$)/g,"");if(2>commentName.length||commentName.length>20){$("#commentErrorTip"+state).html(this.tips.nameTooLongLabel);$("#commentName"+state).focus()}else{if($("#commentEmail"+state).val().replace(/\s/g,"")===""){$("#commentErrorTip"+state).html(this.tips.mailCannotEmptyLabel);$("#commentEmail"+state).focus()}else{if(!/^((([a-z]|\d|[!#\$%&'\*\+\-\/=\?\^_`{\|}~]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])+(\.([a-z]|\d|[!#\$%&'\*\+\-\/=\?\^_`{\|}~]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])+)*)|((\x22)((((\x20|\x09)*(\x0d\x0a))?(\x20|\x09)+)?(([\x01-\x08\x0b\x0c\x0e-\x1f\x7f]|\x21|[\x23-\x5b]|[\x5d-\x7e]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(\\([\x01-\x09\x0b\x0c\x0d-\x7f]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF]))))*(((\x20|\x09)*(\x0d\x0a))?(\x20|\x09)+)?(\x22)))@((([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])*([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])))\.)+(([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])*([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])))\.?$/i.test($("#commentEmail"+state).val())){$("#commentErrorTip"+state).html(this.tips.mailInvalidLabel);$("#commentEmail"+state).focus()}else{if(2>commenterContent.length||commenterContent.length>500){$("#commentErrorTip"+state).html(this.tips.commentContentCannotEmptyLabel);$("#comment"+state).focus()}else{if($("#commentValidate"+state).val().replace(/\s/g,"")===""){$("#commentErrorTip"+state).html(this.tips.captchaCannotEmptyLabel);$("#commentValidate"+state).focus()}else{return true}}}}}$("#commentErrorTip"+state).show();return false},replaceCommentsEm:function(selector){var $commentContents=$(selector);for(var i=0;i<$commentContents.length;i++){var str=$commentContents[i].innerHTML;$commentContents[i].innerHTML=Util.replaceEmString(str)}},_initSyntaxHighlighter:function(languages){for(var i=0;i<languages.length;i++){switch(languages[i]){case"groovy":languages[i]="groovy "+latkeConfig.staticServePath+"/js/lib/SyntaxHighlighter/scripts/shBrushGroovy.js";break;case"java":languages[i]="java "+latkeConfig.staticServePath+"/js/lib/SyntaxHighlighter/scripts/shBrushJava.js";break;case"php":languages[i]="php "+latkeConfig.staticServePath+"/js/lib/SyntaxHighlighter/scripts/shBrushPhp.js";break;case"scala":languages[i]="scala "+latkeConfig.staticServePath+"/js/lib/SyntaxHighlighter/scripts/shBrushScala.js";break;case"sql":languages[i]="sql "+latkeConfig.staticServePath+"/js/lib/SyntaxHighlighter/scripts/shBrushSql.js";break;case"applescript":languages[i]="applescript "+latkeConfig.staticServePath+"/js/lib/SyntaxHighlighter/scripts/shBrushAppleScript.js";break;case"as3":case"actionscript3":languages[i]="actionscript3 as3 "+latkeConfig.staticServePath+"/js/lib/SyntaxHighlighter/scripts/shBrushAS3.js";break;case"bash":case"shell":languages[i]="bash shell "+latkeConfig.staticServePath+"/js/lib/SyntaxHighlighter/scripts/shBrushBash.js";break;case"coldfusion":case"cf":languages[i]="coldfusion cf "+latkeConfig.staticServePath+"/js/lib/SyntaxHighlighter/scripts/shBrushColdFusion.js";break;case"c#":case"c-sharp":case"csharp":languages[i]="c# c-sharp csharp "+latkeConfig.staticServePath+"/js/lib/SyntaxHighlighter/scripts/shBrushCSharp.js";break;case"cpp":case"c":languages[i]="cpp c "+latkeConfig.staticServePath+"/js/lib/SyntaxHighlighter/scripts/shBrushCpp.js";break;case"css":languages[i]="css "+latkeConfig.staticServePath+"/js/lib/SyntaxHighlighter/scripts/shBrushCss.js";break;case"delphi":case"pascal":languages[i]="delphi pascal "+latkeConfig.staticServePath+"/js/lib/SyntaxHighlighter/scripts/shBrushDelphi.js";break;case"diff":case"patch":case"pas":languages[i]="diff patch pas "+latkeConfig.staticServePath+"/js/lib/SyntaxHighlighter/scripts/shBrushDiff.js";break;case"erl":case"erlang":languages[i]="erl erlang "+latkeConfig.staticServePath+"/js/lib/SyntaxHighlighter/scripts/shBrushErlang.js";break;case"js":case"jscript":case"javascript":languages[i]="js jscript javascript "+latkeConfig.staticServePath+"/js/lib/SyntaxHighlighter/scripts/shBrushJScript.js";break;case"jfx":case"javafx":languages[i]="jfx javafx "+latkeConfig.staticServePath+"/js/lib/SyntaxHighlighter/scripts/shBrushJavaFX.js";break;case"perl":case"pl":languages[i]="perl pl "+latkeConfig.staticServePath+"/js/lib/SyntaxHighlighter/scripts/shBrushPerl.js";break;case"plain":case"text":languages[i]="text plain "+latkeConfig.staticServePath+"/js/lib/SyntaxHighlighter/scripts/shBrushPlain.js";break;case"ps":case"powershell":languages[i]="ps powershell "+latkeConfig.staticServePath+"/js/lib/SyntaxHighlighter/scripts/shBrushPowerShell.js";break;case"py":case"python":languages[i]="py python "+latkeConfig.staticServePath+"/js/lib/SyntaxHighlighter/scripts/shBrushPython.js";break;case"rails":case"ror":case"ruby":case"rb":languages[i]="ruby rails ror rb "+latkeConfig.staticServePath+"/js/lib/SyntaxHighlighter/scripts/shBrushRuby.js";break;case"sass":case"scss":languages[i]="sass scss "+latkeConfig.staticServePath+"/js/lib/SyntaxHighlighter/scripts/shBrushSass.js";break;case"vb":case"vbnet":languages[i]="vb vbnet "+latkeConfig.staticServePath+"/js/lib/SyntaxHighlighter/scripts/shBrushVb.js";break;case"xml":case"xhtml":case"xslt":case"html":languages[i]="xml xhtml xslt html "+latkeConfig.staticServePath+"/js/lib/SyntaxHighlighter/scripts/shBrushXml.js";break;default:break}}SyntaxHighlighter.autoloader.apply(null,languages);SyntaxHighlighter.config.stripBrs=true;SyntaxHighlighter.all()},_loadSyntaxHighlighter:function(SHTheme){var cssName=SHTheme?SHTheme:"shCoreEclipse",that=this;if(document.createStyleSheet){document.createStyleSheet(latkeConfig.staticServePath+"/js/lib/SyntaxHighlighter/styles/"+cssName+".css")}else{$("head").append($("<link rel='stylesheet' href='"+latkeConfig.staticServePath+"/js/lib/SyntaxHighlighter/styles/"+cssName+".css' type='text/css' charset='utf-8' />"))}$.ajax({url:latkeConfig.staticServePath+"/js/lib/SyntaxHighlighter/scripts/shCore.js",dataType:"script",cache:true,success:function(){var languages=[],isScrip=false;$(".article-body pre").each(function(){var name=this.className.split(";")[0];var language=name.substr(7,name.length-1);if(this.className.indexOf("html-script: true")>-1&&(language!=="xml"&&language!=="xhtml"&&language!=="xslt"&&language!="html")){isScrip=true}languages.push(language)});if(isScrip){$.ajax({url:latkeConfig.staticServePath+"/js/lib/SyntaxHighlighter/scripts/shBrushXml.js",dataType:"script",cache:true,success:function(){that._initSyntaxHighlighter(languages)}})}else{that._initSyntaxHighlighter(languages)}}})},parseLanguage:function(obj){var isPrettify=false,isSH=false;$(".article-body pre").each(function(){if(this.className.indexOf("brush")>-1){isSH=true}if(this.className.indexOf("prettyprint")>-1){isPrettify=true}});if(isSH){this._loadSyntaxHighlighter(obj?(obj.SHTheme?obj.SHTheme:undefined):undefined)}if(isPrettify){if(document.createStyleSheet){document.createStyleSheet(latkeConfig.staticServePath+"/js/lib/google-code-prettify/prettify.css")}else{$("head").append($("<link rel='stylesheet' href='"+latkeConfig.staticServePath+"/js/lib/google-code-prettify/prettify.css'>"))}$.ajax({url:latkeConfig.staticServePath+"/js/lib/google-code-prettify/prettify.js",dataType:"script",cache:true,success:function(){prettyPrint()}})}},load:function(obj){var that=this;that.insertEmotions();that.parseLanguage(obj?(obj.language?obj.language:undefined):undefined);$("#commentValidate").keypress(function(event){if(event.keyCode===13){that.submitComment()}});$("#comment").keypress(function(event){if(event.keyCode===13&&event.ctrlKey){that.submitComment()}});$("#captcha").click(function(){$(this).attr("src",latkeConfig.servePath+"/captcha.do?code="+Math.random())});if(!$("#admin").data("login")){$("#commentEmail").val(Cookie.readCookie("commentEmail"));$("#commentURL").val(Cookie.readCookie("commentURL"));$("#commentName").val(Cookie.readCookie("commentName"))}try{JSON}catch(e){document.write('<script src="'+latkeConfig.staticServePath+'/js/lib/json2.js"><\/script>')}},loadRandomArticles:function(headTitle){var randomArticles1Label=this.tips.randomArticles1Label;$.ajax({url:latkeConfig.servePath+"/get-random-articles.do",type:"POST",success:function(result,textStatus){var randomArticles=result.randomArticles;if(!randomArticles||0===randomArticles.length){$("#randomArticles").remove();return}var listHtml="";for(var i=0;i<randomArticles.length;i++){var article=randomArticles[i];var title=article.articleTitle;var randomArticleLiHtml="<li><a rel='nofollow' title='"+title+"' href='"+latkeConfig.servePath+article.articlePermalink+"'>"+title+"</a></li>";listHtml+=randomArticleLiHtml}var titleHTML=headTitle?headTitle:"<h4>"+randomArticles1Label+"</h4>";var randomArticleListHtml=titleHTML+"<ul class='marginLeft12'>"+listHtml+"</ul>";$("#randomArticles").append(randomArticleListHtml)}})},loadRelevantArticles:function(id,headTitle){$.ajax({url:latkeConfig.servePath+"/article/id/"+id+"/relevant/articles",type:"GET",success:function(data,textStatus){var articles=data.relevantArticles;if(!articles||0===articles.length){$("#relevantArticles").remove();return}var listHtml="";for(var i=0;i<articles.length;i++){var article=articles[i];var title=article.articleTitle;var articleLiHtml="<li><a rel='nofollow' title='"+title+"' href='"+latkeConfig.servePath+article.articlePermalink+"'>"+title+"</a></li>";listHtml+=articleLiHtml}var relevantArticleListHtml=headTitle+"<ul class='marginLeft12'>"+listHtml+"</ul>";$("#relevantArticles").append(relevantArticleListHtml)},error:function(){$("#relevantArticles").remove()}})},loadExternalRelevantArticles:function(tags,headTitle){var tips=this.tips;try{$.ajax({url:"http://rhythm.b3log.org:80/get-articles-by-tags.do?tags="+tags+"&blogHost="+tips.blogHost+"&paginationPageSize="+tips.externalRelevantArticlesDisplayCount,type:"GET",cache:true,dataType:"jsonp",error:function(){$("#externalRelevantArticles").remove()},success:function(data,textStatus){var articles=data.articles;if(!articles||0===articles.length){$("#externalRelevantArticles").remove();return}var listHtml="";for(var i=0;i<articles.length;i++){var article=articles[i];var title=article.articleTitle;var articleLiHtml="<li><a rel='nofollow' title='"+title+"' target='_blank' href='"+article.articlePermalink+"'>"+title+"</a></li>";listHtml+=articleLiHtml}var titleHTML=headTitle?headTitle:"<h4>"+tips.externalRelevantArticles1Label+"</h4>";var randomArticleListHtml=titleHTML+"<ul class='marginLeft12'>"+listHtml+"</ul>";$("#externalRelevantArticles").append(randomArticleListHtml)}})}catch(e){}},submitComment:function(commentId,state){if(!state){state=""}var that=this,tips=this.tips,type="article";if(tips.externalRelevantArticlesDisplayCount===undefined){type="page"}if(this.validateComment(state)){$("#submitCommentButton"+state).attr("disabled","disabled");$("#commentErrorTip"+state).show().html(this.tips.loadingLabel);var requestJSONObject={oId:tips.oId,commentContent:$("#comment"+state).val().replace(/(^\s*)|(\s*$)/g,"")};if(!$("#admin").data("login")){requestJSONObject={oId:tips.oId,commentContent:$("#comment"+state).val().replace(/(^\s*)|(\s*$)/g,""),commentEmail:$("#commentEmail"+state).val(),commentURL:Util.proessURL($("#commentURL"+state).val().replace(/(^\s*)|(\s*$)/g,"")),commentName:$("#commentName"+state).val().replace(/(^\s*)|(\s*$)/g,""),captcha:$("#commentValidate"+state).val()};Cookie.createCookie("commentName",requestJSONObject.commentName,365);Cookie.createCookie("commentEmail",requestJSONObject.commentEmail,365);Cookie.createCookie("commentURL",$("#commentURL"+state).val().replace(/(^\s*)|(\s*$)/g,""),365)}if(state==="Reply"){requestJSONObject.commentOriginalCommentId=commentId}$.ajax({type:"POST",url:latkeConfig.servePath+"/add-"+type+"-comment.do",cache:false,contentType:"application/json",data:JSON.stringify(requestJSONObject),success:function(result){if(!result.sc){$("#commentErrorTip"+state).html(result.msg);$("#comment"+state).val("").focus();$("#submitCommentButton"+state).removeAttr("disabled");if(!$("#admin").data("login")){$("#captcha"+state).attr("src",latkeConfig.servePath+"/captcha.do?code="+Math.random())}return}result.replyNameHTML="";if(!$("#admin").data("login")){$("#captcha"+state).attr("src",latkeConfig.servePath+"/captcha.do?code="+Math.random());if($("#commentURL"+state).val().replace(/\s/g,"")===""){result.replyNameHTML="<a>"+$("#commentName"+state).val()+"</a>"}else{result.replyNameHTML='<a href="'+Util.proessURL($("#commentURL"+state).val())+'" target="_blank">'+$("#commentName"+state).val()+"</a>"}result.userName=$("#commentName"+state).val()}else{result.replyNameHTML='<a href="'+window.location.host+'" target="_blank">'+$("#adminName").text()+"</a>";result.userName=$("#adminName").text()}that.addCommentAjax(addComment(result,state),state);$("#submitCommentButton"+state).removeAttr("disabled")}})}},addReplyForm:function(id,commentFormHTML,endHTML){var that=this;if(id===this.currentCommentId){if($("#commentNameReply").val()===""){$("#commentNameReply").focus()}else{if($("#commentEmailReply").val()===""){$("#commentEmailReply").focus()}else{$("#commentReply").focus()}}return}$("#replyForm").remove();endHTML=endHTML?endHTML:"";if(endHTML==="</div>"){$("#"+id).append(commentFormHTML+$("#commentForm").html()+endHTML)}else{$("#"+id).append(commentFormHTML+$("#commentForm").html()+"</table>"+endHTML)}$("#replyForm input, #replyForm textarea").each(function(){this.id=this.id+"Reply"});$("#commentNameReply").val(Cookie.readCookie("commentName"));$("#commentEmailReply").val(Cookie.readCookie("commentEmail"));var $label=$("#replyForm #commentURLLabel");if($label.length===1){$label.attr("id","commentURLLabelReply")}$("#commentURLReply").val(Cookie.readCookie("commentURL"));$("#replyForm #emotions").attr("id","emotionsReply");this.insertEmotions("Reply");$("#commentReply").unbind().keypress(function(event){if(event.keyCode===13&&event.ctrlKey){that.submitComment(id,"Reply");event.preventDefault()}});$("#commentValidateReply").unbind().keypress(function(event){if(event.keyCode===13){that.submitComment(id,"Reply");event.preventDefault()}});$("#replyForm #captcha").attr("id","captchaReply").attr("src",latkeConfig.servePath+"/captcha.do?"+new Date().getTime()).click(function(){$(this).attr("src",latkeConfig.servePath+"/captcha.do?code="+Math.random())});$("#replyForm #commentErrorTip").attr("id","commentErrorTipReply").html("").hide();$("#replyForm #submitCommentButton").attr("id","submitCommentButtonReply");$("#replyForm #submitCommentButtonReply").unbind("click").removeAttr("onclick").click(function(){that.submitComment(id,"Reply")});if($("#commentNameReply").val()===""){$("#commentNameReply").focus()}else{if($("#commentEmailReply").val()===""){$("#commentEmailReply").focus()}else{$("#commentReply").focus()}}this.currentCommentId=id},hideComment:function(id){$("#commentRef"+id).hide()},showComment:function(it,id,top,parentTag){var positionTop=parseInt($(it).position().top);if(parentTag){positionTop=parseInt($(it).parents(parentTag).position().top)}if($("#commentRef"+id).length>0){$("#commentRef"+id).show().css("top",(positionTop+top)+"px")}else{var $refComment=$("#"+id).clone();$refComment.addClass("comment-body-ref").attr("id","commentRef"+id);$refComment.find("#replyForm").remove();$("#comments").append($refComment);$("#commentRef"+id).css("top",(positionTop+top)+"px")}},addCommentAjax:function(commentHTML,state){if($("#comments").children().length>0){$($("#comments").children()[0]).before(commentHTML)}else{$("#comments").html(commentHTML)}if(state===""){$("#commentErrorTip").html("").hide();$("#comment").val("");$("#commentValidate").val("");$("#captcha").attr("src",latkeConfig.servePath+"/captcha.do?code="+Math.random())}else{$("#replyForm").remove()}window.location.hash="#comments"}});
\ No newline at end of file
......@@ -3,7 +3,7 @@
<head>
<meta charset="utf-8" />
<title>${blogTitle}</title>
<meta name="keywords" content="GAE 博客,blog,b3log,kill IE6" />
<meta name="keywords" content="Java 博客,blog,b3log,kill IE6" />
<meta name="description" content="An open source blog based on GAE Java,GAE Java 开源博客,Let's kill IE6" />
<meta name="owner" content="B3log Team" />
<meta name="author" content="B3log Team" />
......
......@@ -3,7 +3,7 @@
<head>
<meta charset="utf-8" />
<title>${welcomeToSoloLabel} B3log Solo!</title>
<meta name="keywords" content="GAE 博客,GAE blog,b3log" />
<meta name="keywords" content="Java 博客,GAE blog,b3log" />
<meta name="description" content="An open source blog based on GAE Java,GAE Java 开源博客" />
<meta name="owner" content="B3log Team" />
<meta name="author" content="B3log Team" />
......@@ -84,7 +84,7 @@
return;
}
if ($("#userPassword").val().replace(/\s/g, "") === "") {
if ($("#userPassword").val() === "") {
$("#tip").text("${passwordEmptyLabel}");
$("#userPassword").focus();
return;
......
#
# Copyright (c) 2009, 2010, 2011, B3log Team
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
#
# Description: Language configurations(en_US) of plugin admin-cache.
# Version: 1.0.0.3, Jun 25, 2011
# Author: Liyuan Li
# Author: Liang Ding
#
cacheMgmtLabel=Cache
typeLabel=Type
hitCountLabel=Hit Count
pageCacheStatus1Label=Page Cache Status:
pageCachedCnt1Label=Cached Page Count:
cachedCount1Label=Cached Count:
hitCount1Label=Hit Count:
cachedBytes1Label=Cached Bytes:
hitBytes1Label=Hit Bytes:
missCount1Label=Miss Count:
\ No newline at end of file
#
# Copyright (c) 2009, 2010, 2011, B3log Team
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
#
# Description: Language configurations(zh_CN) of plugin admin-cache.
# Version: 1.0.0.4, Jun 26, 2011
# Author: Liyuan Li
# Author: Liang Ding
#
cacheMgmtLabel=\u7f13\u5b58\u7ba1\u7406
typeLabel=\u7c7b\u578b
hitCountLabel=\u547d\u4e2d\u6b21\u6570
pageCacheStatus1Label=\u9875\u9762\u7f13\u5b58\u72b6\u6001\uff1a
pageCachedCnt1Label=\u5df2\u7f13\u5b58\u9875\u9762\u6570\uff1a
cachedCount1Label=\u5f53\u524d\u7f13\u5b58\u6570\uff1a
hitCount1Label=\u547d\u4e2d\u6b21\u6570\uff1a
cachedBytes1Label=\u5df2\u7f13\u5b58\u5b57\u8282\uff1a
hitBytes1Label=\u5df2\u547d\u4e2d\u5b57\u8282\uff1a
missCount1Label=\u4e22\u5931\u6b21\u6570\uff1a
\ No newline at end of file
<style type="text/css">
#cacheContent {
line-height: 28px;
padding: 12px;
}
</style>
<div id="cachePlugin">
<div id="cacheContent"></div>
<div id="cacheTable"></div>
<div id="cachePagination" class="margin12 right"></div>
<div class="clear"></div>
</div>
<script type="text/javascript">
plugins["cache-list"] = {
tablePagination: new TablePaginate("cache"),
getList: function (pageNum) {
var that = this;
$("#loadMsg").text("${loadingLabel}");
$.ajax({
url: latkeConfig.servePath + "/console/plugins/admin-cache/pages/" + pageNum + "/" + Label.PAGE_SIZE + "/" + Label.WINDOW_SIZE,
type: "GET",
cache: false,
success: function(result, textStatus){
if (!result.sc) {
$("#tipMsg").text(result.msg);
return;
}
var caches = result.pages;
var cacheData = caches;
for (var i = 0; i < caches.length; i++) {
cacheData[i].cachedTitle = "<a href='" + caches[i].cachedLink + "' target='_blank'>"
+ caches[i].cachedTitle + "</a>";
cacheData[i].cachedTime = $.bowknot.getDate(cacheData[i].cachedTime, 1);
}
that.tablePagination.updateTablePagination(cacheData, pageNum, result.pagination);
$("#loadMsg").text("");
}
});
},
changeStatus: function (it) {
$("#loadMsg").text("${loadingLabel}");
var $it = $(it);
var flag = "true";
if ($it.text() === "${enabledLabel}") {
flag = "false";
}
$.ajax({
url: latkeConfig.servePath + "/console/plugins/admin-cache/enable/" + flag,
type: "PUT",
cache: false,
success: function(result, textStatus){
if (!result.sc) {
$("#tipMsg").text(result.msg);
return;
}
if ($it.text() === "${enabledLabel}") {
$it.text("${disabledLabel}");
} else {
$it.text("${enabledLabel}");
}
$("#tipMsg").text("${updateSuccLabel}");
$("#loadMsg").text("");
}
});
},
getCache: function () {
$("#loadMsg").text("${loadingLabel}");
$.ajax({
url: latkeConfig.servePath + "/console/plugins/admin-cache/status/",
type: "GET",
cache: false,
success: function(result, textStatus){
if (!result.sc) {
$("#tipMsg").text(result.msg);
return;
}
var pageCacheStatusLabel = "${disabledLabel}";
if (result.pageCacheEnabled) {
pageCacheStatusLabel = "${enabledLabel}";
}
var cacheHTML = "${pageCacheStatus1Label}&nbsp;<button onclick=\"window.plugins['cache-list'].changeStatus(this);\">"
+ pageCacheStatusLabel
+ "</button>&nbsp;&nbsp;${pageCachedCnt1Label}<span class='f-blue'>" + result.pageCachedCnt;
$("#cacheContent").html(cacheHTML);
$("#loadMsg").text("");
}
});
},
init: function (page) {
this.tablePagination.buildTable([{
style: "padding-left: 6px;",
text: "${typeLabel}",
index: "cachedType",
width: 220
}, {
style: "padding-left: 6px;",
text: "${titleLabel}",
index: "cachedTitle",
minWidth: 300
}, {
style: "padding-left: 6px;",
text: "${hitCountLabel}",
index: "cachedHitCount",
width: 120
}, {
style: "padding-left: 6px;",
text: "${sizeLabel}(Byte)",
index: "cachedBtypesLength",
width: 120
}, {
style: "padding-left: 6px;",
text: "${createDateLabel}",
index: "cachedTime",
width: 160
}]);
this.tablePagination.initPagination();
this.getList(page);
this.getCache();
},
refresh: function (page) {
this.getList(page);
this.getCache();
}
};
/*
* 添加插件
*/
admin.plugin.add({
"id": "cache-list",
"text": "${cacheMgmtLabel}",
"path": "/tools",
"index": 6,
"content": $("#cachePlugin").html()
});
// 移除现有内容
$("#cachePlugin").remove();
</script>
\ No newline at end of file
#
# Copyright (c) 2009, 2010, 2011, B3log Team
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
#
# Description: Description of plugin admin-cache.
# Version: 1.0.1.0, May 16, 2012
# Author: Liang Ding
#
rendererId=admin-index.ftl
author=<a href="http://88250.b3log.org">88250</a> & <a href="http://vanessa.b3log.org">Vanessa</a>
name=Admin Cache
version=0.1.2
types=ADMIN
classesDirPath=/WEB-INF/classes/
# TODO: libDirPath=/WEB-INF/lib/
pluginClass=
eventListenerClasses=
\ No newline at end of file
......@@ -3,7 +3,7 @@
<head>
<meta charset="utf-8" />
<title>${blogTitle}</title>
<meta name="keywords" content="GAE 博客,blog,b3log,kill IE6" />
<meta name="keywords" content="Java 博客,blog,b3log,kill IE6" />
<meta name="description" content="An open source blog based on GAE Java,GAE Java 开源博客,用户注册" />
<meta name="owner" content="B3log Team" />
<meta name="author" content="B3log Team" />
......@@ -75,7 +75,7 @@
} else if (2 > userName.length || userName.length > 20) {
$("#tip").text("${nameTooLongLabel}");
$("#userName").focus();
} else if ($("#userPassword").val().replace(/\s/g, "") === "") {
} else if ($("#userPassword").val() === "") {
$("#tip").text("${passwordEmptyLabel}");
$("#userPassword").focus();
} else if ($("#userPassword").val() !== $("#userPasswordConfirm").val()) {
......
<!DOCTYPE html>
<html>
<head>
<head>
<meta charset="utf-8"/>
<title>${forgotLabel} B3log Solo!</title>
<meta name="keywords" content="GAE 博客,GAE blog,b3log"/>
<meta name="keywords" content="Java 博客,GAE blog,b3log"/>
<meta name="description" content="An open source blog based on GAE Java,GAE Java 开源博客"/>
<meta name="owner" content="B3log Team"/>
<meta name="author" content="B3log Team"/>
......@@ -15,9 +15,9 @@
<link type="text/css" rel="stylesheet"
href="${staticServePath}/css/default-init${miniPostfix}.css?${staticResourceVersion}" charset="utf-8"/>
<link rel="icon" type="image/png" href="${staticServePath}/favicon.png"/>
</head>
<body>
<div class="wrapper">
</head>
<body>
<div class="wrapper">
<div class="wrap">
<div class="content">
<div class="logo">
......@@ -68,13 +68,13 @@
ver ${version}
</div>
</div>
</div>
<script type="text/javascript" src="${staticServePath}/js/lib/jquery/jquery.min.js" charset="utf-8"></script>
<script type="text/javascript">
(function () {
</div>
<script type="text/javascript" src="${staticServePath}/js/lib/jquery/jquery.min.js" charset="utf-8"></script>
<script type="text/javascript">
(function() {
$("#emailOrPassword").focus();
$("#emailOrPassword").keypress(function (event) {
$("#emailOrPassword").keypress(function(event) {
if (13 === event.keyCode) { // Enter pressed
$('#sendBtn').click();
}
......@@ -88,35 +88,37 @@
}
})();
var reset = function(){
//TODO verify the password
var reset = function() {
if ($("#emailOrPassword").val() === "") {
$("#tip").text("${passwordEmptyLabel}");
$("#emailOrPassword").focus();
return;
}
var requestJSONObject = {
"newPwd": $("#emailOrPassword").val(),
"userEmail":$("#userEmailHidden").val()
"userEmail": $("#userEmailHidden").val()
};
$("#tip").html("<img src='${staticServePath}/images/loading.gif'/> loading...")
$("#tip").html("<img src='${staticServePath}/images/loading.gif'/> loading...");
$.ajax({
url: "${servePath}/reset",
type: "POST",
contentType: "application/json",
data: JSON.stringify(requestJSONObject),
error: function () {
error: function() {
// alert("reset password error!");
},
success: function (data, textStatus) {
// $("#tip").text(data.msg);
success: function(data, textStatus) {
if (data.succeed) {
window.location.href = data.to;
} else {
$("#tip").text(data.msg);
}
}
});
};
var forgot = function () {
var forgot = function() {
if (!/^((([a-z]|\d|[!#\$%&'\*\+\-\/=\?\^_`{\|}~]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])+(\.([a-z]|\d|[!#\$%&'\*\+\-\/=\?\^_`{\|}~]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])+)*)|((\x22)((((\x20|\x09)*(\x0d\x0a))?(\x20|\x09)+)?(([\x01-\x08\x0b\x0c\x0e-\x1f\x7f]|\x21|[\x23-\x5b]|[\x5d-\x7e]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(\\([\x01-\x09\x0b\x0c\x0d-\x7f]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF]))))*(((\x20|\x09)*(\x0d\x0a))?(\x20|\x09)+)?(\x22)))@((([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])*([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])))\.)+(([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])*([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])))\.?$/i.test($("#emailOrPassword" + status).val())) {
$("#tip").text("${mailInvalidLabel}");
$("#emailOrPassword").focus();
......@@ -133,17 +135,18 @@
type: "POST",
contentType: "application/json",
data: JSON.stringify(requestJSONObject),
error: function () {
error: function() {
// alert("reset password error!");
},
success: function (data, textStatus) {
// $("#tip").text(data.msg);
success: function(data, textStatus) {
if (data.succeed) {
window.location.href = data.to;
} else {
$("#tip").text(data.msg);
}
}
});
};
</script>
</body>
</script>
</body>
</html>
......@@ -47,8 +47,6 @@
"updatedLabel": "${updatedLabel}",
"contentLabel": "${contentLabel}",
"abstractLabel": "${abstractLabel}",
"clearAllCacheLabel": "${clearAllCacheLabel}",
"clearCacheLabel": "${clearCacheLabel}",
"adminLabel": "${adminLabel}",
"logoutLabel": "${logoutLabel}",
"skinDirName": "${skinDirName}",
......
......@@ -39,8 +39,6 @@ linkLabel=Friend Links
indexLabel=Home
sumLabel=
pageLabel=Page
clearAllCacheLabel=Clear all cache
clearCacheLabel=Clear cache
adminLabel=Admin
logoutLabel=Logout
loginLabel=Login
......
......@@ -41,8 +41,6 @@ linkLabel=\u53cb\u60c5\u94fe\u63a5
indexLabel=\u9996\u9875
sumLabel=\u5171
pageLabel=\u9875
clearAllCacheLabel=\u6e05\u9664\u6240\u6709\u9875\u9762\u7f13\u5b58
clearCacheLabel=\u6e05\u9664\u672c\u9875\u7f13\u5b58
adminLabel=\u7ba1\u7406
logoutLabel=\u767b\u51fa
loginLabel=\u767b\u5f55
......
......@@ -34,6 +34,7 @@
<div class="form">
<table id="commentForm">
<tbody>
<#if !isLoggedIn>
<tr>
<td colspan="2">
<input type="text" class="normalInput" id="commentName"/>
......@@ -52,6 +53,7 @@
<label for="commentURL">${commentURLLabel}</label>
</td>
</tr>
</#if>
<tr>
<td id="emotions" colspan="2">
<span class="em00" title="${em00Label}"></span>
......@@ -76,12 +78,14 @@
<textarea rows="10" cols="96" id="comment"></textarea>
</td>
</tr>
<#if !isLoggedIn>
<tr>
<td colspan="2">
<input type="text" class="normalInput" id="commentValidate"/>
<img id="captcha" alt="validate" src="${servePath}/captcha.do" />
</td>
</tr>
</#if>
<tr>
<td>
<span class="ft-gray" id="commentErrorTip"></span>
......@@ -118,37 +122,41 @@
"externalRelevantArticles1Label": "${externalRelevantArticlesLabel}"
});
var addComment = function (result, state) {
var addComment = function(result, state) {
var commentHTML = '<div id="' + result.oId + '"><img class="comment-header" \
title="' + $("#commentName" + state).val() + '" alt="' + $("#commentName" + state).val() +
'" src="' + result.commentThumbnailURL + '"/><div class="comment-panel"><div class="left">' + result.replyNameHTML;
title="' + result.userName + '" alt="' + result.userName +
'" src="' + result.commentThumbnailURL
+ '"/><div class="comment-panel"><div class="left">' + result.replyNameHTML;
if (state !== "") {
var commentOriginalCommentName = $("#" + page.currentCommentId + " .comment-panel>.left a").first().text();
commentHTML += '&nbsp;@&nbsp;<a href="${servePath}' + result.commentSharpURL.split("#")[0] + '#' + page.currentCommentId + '"'
var commentOriginalCommentName = $("#" + page.currentCommentId
+ " .comment-panel>.left a").first().text();
commentHTML += '&nbsp;@&nbsp;<a href="${servePath}'
+ result.commentSharpURL.split("#")[0] + '#' + page.currentCommentId + '"'
+ 'onmouseover="page.showComment(this, \'' + page.currentCommentId + '\', 20);"'
+ 'onmouseout="page.hideComment(\'' + page.currentCommentId + '\')">' + commentOriginalCommentName + '</a>';
+ 'onmouseout="page.hideComment(\'' + page.currentCommentId + '\')">'
+ commentOriginalCommentName + '</a>';
}
commentHTML += '</div><div class="right ft-gray">' + result.commentDate.substring(2, 16)
+ '&nbsp;<a rel="nofollow" href="javascript:replyTo(\'' + result.oId
+ '\');">${replyLabel}</a></div><span class="clear"></span><div class="article-body">' +
Util.replaceEmString($("#comment" + state).val().replace(/</g, "&lt;").replace(/>/g, "&gt;").replace(/\n/g,"<br/>"))
Util.replaceEmString($("#comment" + state).val().replace(/</g, "&lt;").replace(/>/g, "&gt;").replace(/\n/g, "<br/>"))
+ '</div></div><span class="clear"></span></div>';
return commentHTML;
}
};
var replyTo = function (id) {
var replyTo = function(id) {
var commentFormHTML = "<table class='form' id='replyForm'>";
page.addReplyForm(id, commentFormHTML);
$("#replyForm label").each(function () {
$("#replyForm label").each(function() {
$this = $(this);
$this.attr("for", $this.attr("for") + "Reply");
});
};
$(document).ready(function () {
$(document).ready(function() {
page.load();
ease.scrollToCmt();
// emotions
......
......@@ -16,12 +16,12 @@
#
# Description: ease skin.
# Version: 1.0.0.5, Apr 26, 2013
# Version: 1.0.0.6, Oct 29, 2013
# Author: Liyuan Li
# Author: Liang Ding
#
name=ease
version=1.0.4
forSolo=0.6.1
forSolo=0.6.5
memo=\u56de\u5f52\u606c\u9759
......@@ -34,7 +34,7 @@
</div>
<ul id="head-pages">
<li><a href="${servePath}/admin-index.do#main"><img src="${staticServePath}/skins/${skinDirName}/images/icon-pool/Home.png" alt=""/>Admin</a></li>
<li id="admin" data-login="${isLoggedIn?string}"><a href="${servePath}/admin-index.do#main"><img src="${staticServePath}/skins/${skinDirName}/images/icon-pool/Home.png" alt=""/>Admin</a></li>
<#list pageNavigations as page>
<li><a href="${page.pagePermalink}" target="${page.pageOpenTarget}"><img src="${staticServePath}/skins/${skinDirName}/images/icon-pool/Apps.png" alt=""/>${page.pageTitle}</a></li>
</#list>
......
......@@ -164,8 +164,6 @@ tagsLabel=Tags
importedLabel=Imported
captcha1Label=Captcha:
captchaLabel=Captcha
clearAllCacheLabel=Clear all cache
clearCacheLabel=Clear cache
indexLabel=Index
nextArticle1Label=Next:
previousArticle1Label=Previous:
......
......@@ -170,8 +170,6 @@ tagsLabel=\u6807\u7b7e
importedLabel=\u5df2\u5bfc\u5165
captcha1Label=\u9a8c\u8bc1\u7801\uff1a
captchaLabel=\u9a8c\u8bc1\u7801
clearAllCacheLabel=\u6e05\u9664\u6240\u6709\u9875\u9762\u7f13\u5b58
clearCacheLabel=\u6e05\u9664\u672c\u9875\u7f13\u5b58
indexLabel=\u9996\u9875
nextArticle1Label=\u65b0\u4e00\u7bc7\uff1a
previousArticle1Label=\u65e7\u4e00\u7bc7\uff1a
......
......@@ -48,6 +48,7 @@
</div>
<div id="commentForm">
<h3 id="respond">${postCommentsLabel}</h3>
<#if !isLoggedIn>
<p>
<input type="text" id="commentName" size="22" tabindex="1"/>
<label for="author">${commentNameLabel} *</label>
......@@ -62,17 +63,18 @@
<input type="text" id="commentURL" size="22" tabindex="3" />
<label for="url">${commentURLLabel}</label>
</p>
</#if>
<p>
<span id="commentErrorTip" style="display:none;"></span>
</p>
<p><textarea id="comment" tabindex="4"></textarea></p>
<#if !isLoggedIn>
<p>
<input type="text" id="commentValidate" tabindex="5" />
<label for="url">${captchaLabel}</label>
<img id="captcha" alt="validate" src="${servePath}/captcha.do" />
</p>
</#if>
<p>
<input class="reply-button" id="submitCommentButton" type="submit" onclick="page.submitComment();" value="${submmitCommentLabel}" tabindex="6" />
<div id="loading" style="display:none">
......@@ -88,7 +90,7 @@
<#macro comment_script oId>
<script type="text/javascript" src="${staticServePath}/js/page${miniPostfix}.js?${staticResourceVersion}" charset="utf-8"></script>
<script type="text/javascript">
Page.prototype.submitComment = function (commentId, state) {
Page.prototype.submitComment = function(commentId, state) {
if (!state) {
state = '';
}
......@@ -100,9 +102,14 @@
if (this.validateComment(state)) {
$("#submitCommentButton" + state).attr("disabled", "disabled");
$("#commentErrorTip" + state).html(this.tips.loadingLabel);
$("#commentErrorTip" + state).show().html(this.tips.loadingLabel);
var requestJSONObject = {
"oId": tips.oId,
"commentContent": $("#comment" + state).val().replace(/(^\s*)|(\s*$)/g, "")
};
if (!$("#admin").data("login")) {
requestJSONObject = {
"oId": tips.oId,
"commentContent": $("#comment" + state).val().replace(/(^\s*)|(\s*$)/g, ""),
"commentEmail": $("#commentEmail" + state).val(),
......@@ -110,19 +117,21 @@
"commentName": $("#commentName" + state).val().replace(/(^\s*)|(\s*$)/g, ""),
"captcha": $("#commentValidate" + state).val()
};
Cookie.createCookie("commentName", requestJSONObject.commentName, 365);
Cookie.createCookie("commentEmail", requestJSONObject.commentEmail, 365);
Cookie.createCookie("commentURL", $("#commentURL" + state).val().replace(/(^\s*)|(\s*$)/g, ""), 365);
}
if (state === "Reply") {
requestJSONObject.commentOriginalCommentId = commentId;
}
$wpt("#loading").fadeIn(400);
$.ajax({
type: "POST",
url: "/add-" + type + "-comment.do",
url: latkeConfig.servePath + "/add-" + type + "-comment.do",
cache: false,
contentType: "application/json",
data: JSON.stringify(requestJSONObject),
success: function(result){
success: function(result) {
$("#submitCommentButton" + state).removeAttr("disabled");
if (!result.sc) {
......@@ -143,17 +152,13 @@
}, // end success
error: function() {
} //end error
});
Cookie.createCookie("commentName", requestJSONObject.commentName, 365);
Cookie.createCookie("commentEmail", requestJSONObject.commentEmail, 365);
Cookie.createCookie("commentURL", $("#commentURL" + state).val().replace(/(^\s*)|(\s*$)/g, ""), 365);
}
};
var replyTo = function (id) {
var replyTo = function(id) {
var commentFormHTML = "<div id='replyForm'>";
page.addReplyForm(id, commentFormHTML, "</div>");
};
......@@ -172,7 +177,7 @@
"externalRelevantArticles1Label": "${externalRelevantArticles1Label}"
});
(function () {
(function() {
page.load();
// emotions
page.replaceCommentsEm("#commentlist .combody");
......
......@@ -16,11 +16,11 @@
#
# Description: Mobile skin.
# Version: 1.0.0.7, Apr 26, 2013
# Version: 1.0.0.8, Oct 29, 2013
# Author: Liang Ding
#
name=Mobile
version=0.1.5
forSolo=0.6.1
forSolo=0.6.5
memo=\u8bf7\u4e0d\u8981\u4ece\u90e8\u7f72\u76ee\u5f55\u4e2d\u5220\u9664\u8be5\u76ae\u80a4\uff0c\u5426\u5219\u79fb\u52a8\u8bbe\u5907\u8bbf\u95ee\u65f6\u535a\u5ba2\u5c06\u4e0d\u53ef\u7528\u3002
......@@ -69,15 +69,7 @@
<span class="left">&nbsp;${onlineVisitor1Label}${onlineVisitorCnt}</span>
<span class="right" id="admin" data-login="${isLoggedIn?string}">
<#if isLoggedIn>
<span>${userName}</span>
<#if isAdmin>
<a href="javascript:Util.clearCache('all');">
${clearAllCacheLabel}
</a>
<a href="javascript:Util.clearCache();">
${clearCacheLabel}
</a>
</#if>
<span id="adminName">${userName}</span>
<#if !isVisitor>
<a href="${contextPath}/admin-index.do#main" title="${adminLabel}">
${adminLabel}
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment