项目论坛丢失了的编辑功能

贴吧的置顶锁定功能,目前只针对管理员开放
贴吧列表搜索功能重构
增加1/2帖子显示数目
取出楼主,防止输入帖子id让回复作为主贴显示
首页取新帖子
帖子下载内容随意删除功能
This commit is contained in:
yanxd 2013-12-11 08:52:55 +08:00
parent 23785999f1
commit 0bc2b8f2b3
13 changed files with 228 additions and 150 deletions

View File

@ -2,9 +2,13 @@
class ForumsController < ApplicationController class ForumsController < ApplicationController
# GET /forums # GET /forums
# GET /forums.json # GET /forums.json
before_filter :find_forum_if_available
before_filter :authenticate_user_edit, :only => [:edit, :update] before_filter :authenticate_user_edit, :only => [:edit, :update]
before_filter :authenticate_user_destroy, :only => [:destroy] before_filter :authenticate_user_destroy, :only => [:destroy]
helper :sort
include SortHelper
PageLimit = 20 PageLimit = 20
def index def index
@ -26,15 +30,33 @@ class ForumsController < ApplicationController
# GET /forums/1 # GET /forums/1
# GET /forums/1.json # GET /forums/1.json
def show def show
@memo = Memo.new sort_init 'updated_at', 'desc'
@offset, @limit = api_offset_and_limit({:limit => 10}) sort_update 'created_at' => "#{Memo.table_name}.created_at",
@forum = Forum.find(params[:id]) 'replies' => "#{Memo.table_name}.replies_count",
@memos_all = @forum.topics 'updated_at' => "COALESCE (last_replies_memos.created_at, #{Memo.table_name}.created_at)"
@topic_count = @memos_all.count
@topic_pages = Paginator.new @topic_count, @limit, params['page'] @memo = Memo.new(:forum => @forum)
@topic_count = @forum.topics.count
@topic_pages = Paginator.new @topic_count, per_page_option, params['page']
@memos = @forum.topics.
reorder("#{Memo.table_name}.sticky DESC").
includes(:last_reply).
limit(@topic_pages.per_page).
offset(@topic_pages.offset).
order(sort_clause).
preload(:author, {:last_reply => :author}).
all
# @offset, @limit = api_offset_and_limit({:limit => 10})
# @forum = Forum.find(params[:id])
# @memos_all = @forum.topics
# @topic_count = @memos_all.count
# @topic_pages = Paginator.new @topic_count, @limit, params['page']
@offset ||= @topic_pages.offset # @offset ||= @topic_pages.offset
@memos = @memos_all.offset(@offset).limit(@limit).all # @memos = @memos_all.offset(@offset).limit(@limit).all
respond_to do |format| respond_to do |format|
format.html { format.html {
render :layout => 'base_forums' render :layout => 'base_forums'
@ -144,20 +166,20 @@ class ForumsController < ApplicationController
private private
def find_forum def find_forum_if_available
@forum = Forum.find(params[:id]) @forum = Forum.find(params[:id]) if params[:id]
rescue ActiveRecord::RecordNotFound rescue ActiveRecord::RecordNotFound
render_404 render_404
nil nil
end end
def authenticate_user_edit def authenticate_user_edit
find_forum find_forum_if_available
render_403 unless @forum.editable_by? User.current render_403 unless @forum.editable_by? User.current
end end
def authenticate_user_destroy def authenticate_user_destroy
find_forum find_forum_if_available
render_403 unless @forum.destroyable_by? User.current render_403 unless @forum.destroyable_by? User.current
end end
end end

View File

@ -52,15 +52,22 @@ class MemosController < ApplicationController
end end
end end
REPLIES_PER_PAGE = 20 unless const_defined?(:REPLIES_PER_PAGE)
def show def show
pre_count = 20 pre_count = REPLIES_PER_PAGE
@current_count = pre_count * (params['page'].to_i - 1) if params['page'].to_i > 0
@offset, @limit = api_offset_and_limit({:limit => pre_count}) @memo = @memo.root # 取出楼主防止输入帖子id让回复作为主贴显示
@replies_all = @memo.replies
@reply_count = @replies_all.count page = params[:page]
@reply_pages = Paginator.new @reply_count, @limit, params['page'] @reply_count = @memo.children.count
@offset ||= @reply_pages.offset @reply_pages = Paginator.new @reply_count, pre_count, page
@replies = @replies_all.offset(@offset).limit(@limit).all @replies = @memo.children.
includes(:author, :attachments).
reorder("#{Memo.table_name}.created_at ASC").
limit(@reply_pages.per_page).
offset(@reply_pages.offset).
all
@mome_new = Memo.new @mome_new = Memo.new
@ -76,12 +83,15 @@ class MemosController < ApplicationController
end end
def edit def edit
@replying = true
end end
def update def update
respond_to do |format| respond_to do |format|
if(@memo.update_attribute(:subject, params[:memo][:subject]) && if( @memo.update_attribute(:subject, params[:memo][:subject]) &&
@memo.update_attribute(:content, params[:memo][:content])) @memo.update_attribute(:content, params[:memo][:content]) &&
@memo.update_attribute(:sticky, params[:memo][:sticky]) &&
@memo.update_attribute(:lock, params[:memo][:lock]))
@memo.save_attachments(params[:attachments] || (params[:memo] && params[:memo][:uploads])) @memo.save_attachments(params[:attachments] || (params[:memo] && params[:memo][:uploads]))
format.html {redirect_to back_memo_url, notice: "#{l :label_memo_create_succ}"} format.html {redirect_to back_memo_url, notice: "#{l :label_memo_create_succ}"}
else else

View File

@ -6,7 +6,7 @@ class Memo < ActiveRecord::Base
validates_presence_of :author_id, :forum_id, :subject validates_presence_of :author_id, :forum_id, :subject
validates :content, presence: true validates :content, presence: true
validates_length_of :subject, maximum: 50 validates_length_of :subject, maximum: 50
validates_length_of :content, maximum: 2048 validates_length_of :content, maximum: 3072
validate :cannot_reply_to_locked_topic, :on => :create validate :cannot_reply_to_locked_topic, :on => :create
acts_as_tree :counter_cache => :replies_count, :order => "#{Memo.table_name}.created_at ASC" acts_as_tree :counter_cache => :replies_count, :order => "#{Memo.table_name}.created_at ASC"
@ -50,7 +50,7 @@ class Memo < ActiveRecord::Base
# } # }
def cannot_reply_to_locked_topic def cannot_reply_to_locked_topic
errors.add :base, 'Topic is locked' if root.locked? && self != root errors.add :base, l(:label_memo_locked) if root.locked? && self != root
end end
# def update_memos_forum # def update_memos_forum
@ -69,7 +69,7 @@ class Memo < ActiveRecord::Base
end end
def sticky=(arg) def sticky=(arg)
write_attribute :sticky, (arg == true || arg.to_s == '1' ? 1 : 0) write_attribute :sticky, (arg == true || arg.to_s == 'true' ? true : false)
end end
def sticky? def sticky?

View File

@ -9,7 +9,7 @@
<td> <td>
<table width="630px" border="0"> <table width="630px" border="0">
<tr> <tr>
<td valign="top" width="500px"><%= link_to h(topic.subject), forum_memo_path(@forum, topic) %></td> <td valign="top" width="500px" class="<%= topic.sticky ? 'sticky' : '' %> <%= topic.locked? ? 'locked' : '' %>"><%= link_to h(topic.subject), forum_memo_path(@forum, topic) %></td>
<td align="right" rowspan="3"> <td align="right" rowspan="3">
<table class="borad-count"> <table class="borad-count">
<tr> <tr>

View File

@ -1,4 +1,5 @@
<!-- <h1>New memo</h1> --> <!-- <h1>New memo</h1> -->
<% @replying ||= false %>
<h3><%=l(:label_memo_edit)%></h3> <h3><%=l(:label_memo_edit)%></h3>
<%= labelled_form_for(@memo, :url => forum_memo_path(@memo.forum_id, @memo)) do |f| %> <%= labelled_form_for(@memo, :url => forum_memo_path(@memo.forum_id, @memo)) do |f| %>
<% if @memo.errors.any? %> <% if @memo.errors.any? %>
@ -12,7 +13,17 @@
</div> </div>
<% end %> <% end %>
<div class="actions"> <div class="actions">
<p><%= f.text_field :subject, :required => true %></p> <p><%= f.text_field :subject, :required => true, :size => 96 %></p>
<p>
<% unless @replying %>
<% if @memo.safe_attribute? 'sticky' %>
<%= f.check_box :sticky %> <%= label_tag 'memo_sticky', l(:label_board_sticky) %>
<% end %>
<% if @memo.safe_attribute? 'lock' %>
<%= f.check_box :lock %> <%= label_tag 'memo_locked', l(:label_board_locked) %>
<% end %>
<% end %>
</p>
<p><%= f.text_area :content, :required => true, :size => 80, id: 'editor01' %></p> <p><%= f.text_area :content, :required => true, :size => 80, id: 'editor01' %></p>
<script type="text/javascript">var ckeditor=CKEDITOR.replace('editor01');</script> <script type="text/javascript">var ckeditor=CKEDITOR.replace('editor01');</script>
<br/> <br/>

View File

@ -1,71 +1,3 @@
<style type="text/css">
/** {
-webkit-box-sizing: border-box;
-moz-box-sizing: border-box;
-box-sizing: border-box;
}*/
.lz {
position:relative;
min-height: 200px;
margin: 10px 2px;
border-radius: 5px;
box-shadow: 1px 1px 6px #97EBF4;
border: 1px solid #F1F1F1;
}
.lz-left{
float: left;
margin: 2%;
padding: 0;
}
.memo-section{
width: auto;
margin-left: 15%;
padding-top: 1%;
border-left: 2px dotted #EEE;
}
.memo-title{
margin: 1em 0;
padding-left: 1%;
padding-bottom: 1%;
font-weight: bold;
border-bottom: 1px dashed rgb(204, 204, 204);
}
.memo-content{
padding: 1%;
margin: 1%;
margin-bottom: 40px;
background-color: #F6F6F6;
}
.memo-timestamp{
position: absolute;
bottom: 0px;
right: 0;
margin: 20px;
}
.replies{
overflow:hidden;
max-width: 100%;
float: right;
/*max-width: 90%;*/
}
.reply-box{
float: right;
width: 640px;
padding: 3%;
/*border: 2px solid #C6F3F9;*/
border-top: 2px double #C6F3F9;
/*border-radius: 10px;*/
}
.comments img {
overflow:hidden;
/*width: 100%;*/
max-width: 500px;
height: auto !important;
width:expression(this.width > 500 ? "500px" : this.width+"px");
}
</style>
<!-- < %= forum_breadcrum%> -->
<div class="lz"> <div class="lz">
<div class="lz-left"> <div class="lz-left">
<div class=""><%= link_to image_tag(url_to_avatar(@memo.author), :class => "avatar"), user_path(@memo.author) %></div> <div class=""><%= link_to image_tag(url_to_avatar(@memo.author), :class => "avatar"), user_path(@memo.author) %></div>
@ -95,7 +27,7 @@
) if @memo.destroyable_by?(User.current) %> ) if @memo.destroyable_by?(User.current) %>
</div> </div>
<div class="memo-title"><%= label_tag l(:field_subject) %>: <%=h @memo.subject %></div> <div class="memo-title <%= @memo.sticky ? 'sticky' : '' %> <%= @memo.locked? ? 'locked' : '' %>"><%= label_tag l(:field_subject) %>: <%=h @memo.subject %></div>
<div class="memo-content"> <div class="memo-content">
<!-- < %= textilizable(@memo, :content) %> --> <!-- < %= textilizable(@memo, :content) %> -->
<%= raw @memo.content %> <%= raw @memo.content %>
@ -149,7 +81,7 @@
<!-- <div class="wiki">< %=h reply.content.html_safe %></div> --> <!-- <div class="wiki">< %=h reply.content.html_safe %></div> -->
<p> <p>
<% if reply.attachments.any?%> <% if reply.attachments.any?%>
<% options = {:author => true, :deletable => true} %> <% options = {:author => true, :deletable => false} %>
<%= render :partial => 'attachments/links', :locals => {:attachments => reply.attachments, :options => options} %> <%= render :partial => 'attachments/links', :locals => {:attachments => reply.attachments, :options => options} %>
<% end %> <% end %>
</p> </p>

View File

@ -90,6 +90,28 @@
</style> </style>
<div class="lz"> <div class="lz">
<div class="contextual">
<%= watcher_link(@topic, User.current) %>
<%= link_to(
l(:button_quote),
{:action => 'quote', :id => @topic},
:remote => true,
:method => 'get',
:class => 'icon icon-comment',
:remote => true) if !@topic.locked? && authorize_for('messages', 'reply') %>
<%= link_to(
l(:button_edit),
{:action => 'edit', :id => @topic},
:class => 'icon icon-edit'
) if @message.editable_by?(User.current) %>
<%= link_to(
l(:button_delete),
{:action => 'destroy', :id => @topic},
:method => :post,
:data => {:confirm => l(:text_are_you_sure)},
:class => 'icon icon-del'
) if @message.destroyable_by?(User.current) %>
</div>
<div class="lz-left"> <div class="lz-left">
<div class=""><%= link_to image_tag(url_to_avatar(@topic.author), :class => "avatar"), user_path(@topic.author) %></div> <div class=""><%= link_to image_tag(url_to_avatar(@topic.author), :class => "avatar"), user_path(@topic.author) %></div>
<p class=""><%=link_to @topic.author, user_path(@topic.author) %></p> <p class=""><%=link_to @topic.author, user_path(@topic.author) %></p>

View File

@ -1,52 +1,3 @@
<style type='text/css'>
.tools a:link{
color: #116699;
text-decoration:none;
width:100px;
padding:3px 5px 0px 5px;
}
.tools a:visited{
color: #116699;
text-decoration:none;
padding:3px 5px 0px 5px;
width:100px;
}
.tools a:hover{
color:white;
padding:3px 3px 0px 20px;
width:88px;
text-decoration:none;
background-color:#539D26;
}
.tools a:active{
color:white;
padding:3px 3px 0px 20px;
width:88px;
text-decoration:none;
background-color:#BD06B4;
}
.tools ul{
list-style-type: none;
margin: 0px 0px 0px 10% ;
padding: 0;
}
.tools li{
background: url("/images/sidebar/tool_tag_alpha.png") 10px 30% no-repeat transparent;
color: #3e3e3e;
font-weight: 400;
line-height: 1.5em;
margin: 0px 0px 10px;
padding: 0px 0px 0px 30px;
font-size: 1.0em;
/*border-bottom: 1px solid #CCC;*/
}
.tools li:last-child{
border: none;
}
</style>
<div class="font_title_left"> <div class="font_title_left">
<%= l(:label_project_tool)%> <%= l(:label_project_tool)%>
</div> </div>

View File

@ -782,6 +782,9 @@ en:
label_board_locked: Locked label_board_locked: Locked
label_board_sticky: Sticky label_board_sticky: Sticky
label_topic_plural: Topics label_topic_plural: Topics
field_sticky: ''
field_locked: ''
field_lock: ''
label_message_plural: Messages label_message_plural: Messages
label_message_last: Last message label_message_last: Last message
label_message_new: New message label_message_new: New message
@ -1577,6 +1580,7 @@ en:
label_forum: Forum label_forum: Forum
label_tags_forum_description: Forum description label_tags_forum_description: Forum description
label_tags_forum: Call forum label_tags_forum: Call forum
label_memo_locked: 'Topic is locked'

View File

@ -792,6 +792,9 @@ zh:
label_board_plural: 讨论区 label_board_plural: 讨论区
label_board_locked: 锁定 label_board_locked: 锁定
label_board_sticky: 置顶 label_board_sticky: 置顶
field_sticky: ''
field_locked: ''
field_lock: ''
label_topic_plural: 主题 label_topic_plural: 主题
label_message_plural: 帖子 label_message_plural: 帖子
label_message_last: 最新的帖子 label_message_last: 最新的帖子
@ -1743,3 +1746,4 @@ zh:
label_tags_forum_description: 贴吧描述 label_tags_forum_description: 贴吧描述
label_tags_forum: 贴吧名称 label_tags_forum: 贴吧名称
label_project_module_forums: 公共贴吧 label_project_module_forums: 公共贴吧
label_memo_locked: 帖子已被锁定

View File

@ -18,12 +18,10 @@
RedmineApp::Application.routes.draw do RedmineApp::Application.routes.draw do
resources :forums do resources :forums do
collection do collection do
get 'search_forum' match 'search_forum', :via => [:get, :post]
post 'search_forum'
end end
member do member do
get 'search_memo' match 'search_memo', :via => [:get, :post]
post 'search_memo'
end end
resources :memos do resources :memos do
collection do collection do

BIN
public/images/zding.gif Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

View File

@ -134,4 +134,128 @@ input[class='nyan-clean-gray']:active, .nyan-clean-gray:active {
#share_label { #share_label {
line-height: 1.4em line-height: 1.4em
}
.tools a:link{
color: #116699;
text-decoration:none;
width:100px;
padding:3px 5px 0px 5px;
}
.tools a:visited{
color: #116699;
text-decoration:none;
padding:3px 5px 0px 5px;
width:100px;
}
.tools a:hover{
color:white;
padding:3px 3px 0px 20px;
width:88px;
text-decoration:none;
background-color:#539D26;
}
.tools a:active{
color:white;
padding:3px 3px 0px 20px;
width:88px;
text-decoration:none;
background-color:#BD06B4;
}
.tools ul{
list-style-type: none;
margin: 0px 0px 0px 10% ;
padding: 0;
}
.tools li{
background: url("/images/sidebar/tool_tag_alpha.png") 10px 30% no-repeat transparent;
color: #3e3e3e;
font-weight: 400;
line-height: 1.5em;
margin: 0px 0px 10px;
padding: 0px 0px 0px 30px;
font-size: 1.0em;
/*border-bottom: 1px solid #CCC;*/
}
.tools li:last-child{
border: none;
}
/** {
-webkit-box-sizing: border-box;
-moz-box-sizing: border-box;
-box-sizing: border-box;
}*/
.lz {
position:relative;
min-height: 200px;
margin: 10px 2px;
border-radius: 5px;
box-shadow: 1px 1px 6px #97EBF4;
border: 1px solid #F1F1F1;
}
.lz-left{
float: left;
margin: 2%;
padding: 0;
}
.memo-section{
width: auto;
margin-left: 15%;
padding-top: 1%;
border-left: 2px dotted #EEE;
}
.memo-title{
margin: 1em 0;
padding-left: 1%;
padding-bottom: 1%;
font-weight: bold;
border-bottom: 1px dashed rgb(204, 204, 204);
}
.memo-content{
padding: 1%;
margin: 1%;
margin-bottom: 40px;
background-color: #F8F8F8;
border-radius: 3px;
}
.memo-timestamp{
position: absolute;
bottom: 0px;
right: 0;
margin: 20px;
}
.replies{
overflow:hidden;
max-width: 100%;
float: right;
/*max-width: 90%;*/
}
.reply-box{
float: right;
width: 640px;
padding: 3%;
/*border: 2px solid #C6F3F9;*/
border-top: 2px double #C6F3F9;
/*border-radius: 10px;*/
}
.comments img {
overflow:hidden;
/*width: 100%;*/
max-width: 500px;
height: auto !important;
width:expression(this.width > 500 ? "500px" : this.width+"px");
}
table.content-text-list tbody tr td.sticky, div.memo-section .sticky{
background: url(../images/zding.gif) no-repeat 0 1px; padding-left: 35px;
/*background: url(../images/2uparrow.png) no-repeat 0 1px; padding-left: 20px;*/
font-weight: bold;
margin-left: 5px;
}
table.content-text-list tbody tr td.locked, div.memo-section .locked{
background: url(../images/locked.png) no-repeat 0 1px;
padding-left: 20px;
margin-left: 5px;
} }