1
0
mirror of https://github.com/haiwen/seahub.git synced 2025-09-18 00:00:00 +00:00

[group discuss] resigned it

This commit is contained in:
llj
2013-03-12 21:48:47 +08:00
parent 428147333f
commit e3064a3176
15 changed files with 491 additions and 342 deletions

View File

@@ -6,27 +6,22 @@
{% block nav_group_class %}class="cur"{% endblock %}
{% block title_panel %}
<div class="tabnav">
<div class="grp-profile fright">
{% grp_avatar group.props.id 24 %}<span class="name">{{ group.group_name }}</span>
</div>
<ul class="tabnav-tabs">
<li class="tabnav-tab"><a href="{% url 'group_info' group.id %}">{% trans "Libraries" %}</a></li>
<li class="tabnav-tab tabnav-tab-cur">{% trans "Discussions" %}</li>
<li class="tabnav-tab tabnav-tab-cur">{% trans "Discussion" %}</li>
<li class="tabnav-tab"><a href="{% url 'group_wiki' group.id %}">{% trans "Wiki" %}</a></li>
{% if is_staff %}
<li class="tabnav-tab"><a href="{% url 'group_manage' group.id %}">{% trans "Admin" %}</a></li>
{% endif %}
</ul>
<div class="fright">
{% grp_avatar group.props.id 24 %} <span style="font-size: 16px; font-weight:bold; margin: 0 6px;">{{ group.group_name }}</span>
</div>
</div>
{% endblock %}
{% block left_panel %}
<div class="info-item">
<div class="info-item-top ovhd">
<h3 class="fleft">{% trans "Members" %}</h3>
@@ -71,30 +66,38 @@
<div class="w100 ovhd">
<div class="pic fleft">{% avatar request.user.username 48 %}</div>
<form id="group-message-form" action="" method="post" class="fright">
<textarea name="message" id="message">{{ form.data.message }}</textarea><br />
<textarea name="message" id="message" placeholder="{% trans "Add a discussion..." %}">{{ form.data.message }}</textarea><br />
{% for error in form.message.errors %}
<p class="error">{{ error|escape }}</p>
{% endfor %}
<input type="submit" value="{% trans "Submit" %}" class="submit" />
<button type="submit" class="submit hide">{% trans "Submit" %}</button>
<button type="button" class="cancel hide">{% trans "Cancel" %}</button>
<span class="say"></span>
</form>
</div>
{% if group_msgs %}
{% if group_msgs %}
<ul class="msg-list">
{% for msg in group_msgs %}
{% if msgs_more and forloop.counter0 > per_show %}
<li class="msg w100 ovhd msg-hide hide">
{% else %}
<li class="msg w100 ovhd">
{% endif %}
<div class="pic fleft">
<a href="{{ SITE_ROOT }}profile/{{ msg.from_email }}/">{% avatar msg.from_email 48 %}</a>
<a href="{% url 'user_profile' msg.from_email %}">{% avatar msg.from_email 48 %}</a>
</div>
<div class="txt fright">
<div class="msg-hd">
<span class="time">{{ msg.timestamp|translate_seahub_time }}</span>
<a href="{{ SITE_ROOT }}profile/{{ msg.from_email }}/" title="{{ msg.from_email }}">{{ msg.from_email|email2nickname }}</a>
</div>
<div class="msg-bd">
<p>
<div class="msg-main">
<div class="msg-hd w100 ovhd">
{% if is_staff or msg.from_email == request.user.username %}
<span class="msg-del op fright vh" data-url="{% url 'group_message_remove' group.id msg.id %}">{% trans "Delete" %}</span>
{% endif %}
<a href="{% url 'user_profile' msg.from_email %}" title="{{ msg.from_email }}" class="author">{{ msg.from_email|email2nickname }}</a>
<span class="time">{{ msg.timestamp|translate_seahub_time }}</span>
</div>
<p class="msg-con">
{% if msg.attachment.src == 'recommend' %}
<!-- recommend -->
<span class="recommend">{% trans "Recommended" %}
{% if msg.attachment.attach_type == 'file' %}
<a href="{% url 'repo_view_file' msg.attachment.repo_id %}?p={{ msg.attachment.path|urlencode }}" target="_blank">
@@ -106,43 +109,67 @@
{% endif %}
{% if msg.attachment.src == 'filecomment' %}
<!-- file comment -->
<span class="recommend">{% trans "File " %}<a href="{% url 'repo_view_file' msg.attachment.repo_id %}?p={{ msg.attachment.path|urlencode }}&comment_open=true" target="_blank"> {{ msg.attachment.name }}</a> {% trans "has a new comment:"%}</span>
{% endif %}
{{ msg.message|seahub_urlize|find_at|linebreaksbr }}
</p>
<button class="reply op" data="{% url 'msg_reply' msg.id %}">
{% if msg.reply_cnt == 0 %}
<span class="reply-cnt"></span>{% trans 'Reply' %}
{% else %}
{% blocktrans count counter=msg.reply_cnt %}
<span class="reply-cnt">{{ counter }}</span> Reply
{% plural %}
<span class="reply-cnt">{{ counter }}</span> Replies
{% endblocktrans %}
{% endif %}
</button>
<button class="replyclose op hide">{% trans "Hide" %}</button>
{% if is_staff or msg.from_email == request.user.username %}
<button class="msg-delete op" data="{% url 'group_message_remove' group.id msg.id %}">{% trans "Delete" %}</button>
<span class="say"></span>
</div>
<div class="msg-op">
<div class="reply-cnt-op{% if msg.reply_cnt < 4 %} hide{% endif %}" data-rstatus="hide">
<span class="reply-cnt" data-url="{% url 'msg_reply' msg.id %}">{% blocktrans with amount=msg.reply_cnt %}{{ amount }} replies{% endblocktrans %}</span>
<span class="hide-reply hide">{% trans "Hide replies" %}</span>
</div>
{% if msg.reply_cnt == 0 %}
<ul class="reply-list hide"></ul>
{% else %}
<ul class="reply-list">
{% for r in msg.replies %}
<li class="reply w100 ovhd">
<a href="{% url 'user_profile' r.from_email %}" class="pic fleft">{% avatar r.from_email 28 %}</a>
<div class="txt fright">
<a href="{% url 'user_profile' r.from_email %}">{{ r.from_email|email2nickname }}</a>
<span class="time">{{ r.timestamp|translate_seahub_time }}</span>
<span class="reply-at op vh" data="{{ r.from_email|email2nickname }}">{% trans 'Reply' %}</span>
<p class="reply-con">{{ r.message|seahub_urlize|find_at }}</p>
</div>
</li>
{% endfor %}
</ul>
{% endif %}
<div class="reply-bd"></div>
<textarea placeholder="{% trans "Add a reply..." %}" name="message" class="reply-input"></textarea>
<p class="error hide">{% trans "It can not be blank and should be no more than 150 characters." %}</p>
<button type="button" class="reply-submit hide" data-url="{% url 'msg_reply' msg.id %}">{% trans "Submit" %}</button>
<button type="button" class="reply-cancel hide">{% trans "Cancel" %}</button>
</div>
</div>
</li>
{% endfor %}
</ul>
{% endif %}
{% endif %}
<div id="paginator">
{% if msgs_more %}
<button id="msgs-more" class="big-more-btn">{% trans "More" %}</button>
{% endif %}
{% if pages_show|length > 1 %}
<div id="paginator"{% if msgs_more %} class="hide"{% endif %}>
{% if current_page != 1 %}
<a href="{{ SITE_ROOT }}group/{{ group.id}}/?page={{ prev_page }}&per_page={{ per_page }}">{% trans "Previous" %}</a>
<a href="?page={{ prev_page }}" class="prev">{% trans "Previous" %}</a>
{% endif %}
{% for p in pages_show %}
{% if p == current_page %}
<span class="cur">{{ p }}</span>
{% else %}
<a href="?page={{ p }}" class="pg">{{ p }}</a>
{% endif %}
{% endfor %}
{% if page_next %}
<a href="{{ SITE_ROOT }}group/{{ group.id }}/?page={{ next_page }}&per_page={{ per_page }}">{% trans "Next"%}</a>
<a href="?page={{ next_page }}" class="next">{% trans "Next"%}</a>
{% endif %}
</div>
{% endif %}
{% if group_msgs|length > 5 %}
<a href="#group-reply" id="msg-upward" class="hide">{% trans "↑Top" %}</a>
@@ -155,6 +182,15 @@
{% block extra_script %}
{% include 'snippets/user_profile_js.html' %}
<script type="text/javascript">
{% if msgs_more %}
$('#msgs-more').click(function() {
$('.msg-hide:lt({{per_show}})').removeClass('msg-hide hide');
if ($('.msg-hide').length == 0) {
$(this).hide();
$('#paginator').removeClass('hide');
}
});
{% endif %}
{% if group_msgs|length > 5 %}
$(window).scroll(function() {
var up_icon = $('#msg-upward');
@@ -177,36 +213,36 @@ $(window).scroll(function() {
});
{% endif %}
addAtAutocomplete('#message', '#group-message-form', {{ group.id }}, "{% url 'group_attention' %}", {'border':'1px solid #ddd', 'width':'600px', 'height': '80px', 'word-wrap':'break-word', 'overflow-y':'auto', 'line-height': '1.5em'}); // remember to add unit (px or em) to line-height, as js in ie will take 1.5 as 1.5, not 1.5em
addAtAutocomplete('#message', '#group-message-form', {{ group.id }}, "{% url 'group_attention' %}", {'border':'1px solid #ddd', 'width':'550px', 'height': '75px', 'padding':'3px 5px', 'overflow-y':'auto', 'line-height': '1.5em'}); // remember to add unit (px or em) to line-height, as js in ie will take 1.5 as 1.5, not 1.5em
$("table tr:gt(0)").hover(
function() {
$(this).find('.op-icon').css('cursor', 'pointer').removeClass('vh');
},
function() {
$(this).find('.op-icon').addClass('vh');
}
);
$('#message').focus(function() {
$(this).height(75);
$('#group-message-form').find('.submit, .cancel').removeClass('hide');
});
$('#group-message-form .cancel').click(function() {
$(this).addClass('hide');
$('#group-message-form .submit').addClass('hide');
$('#message').val('').height(25);
});
{% include 'group/msg_js.html' %}
{% include 'group/msg_reply_js.html' %}
var contact_list = [], contact_email;
{% for contact in contacts %}
contact_email = '{{ contact.contact_email }}';
contact_list.push({value:contact_email, label:contact_email});
{% endfor %}
$('.msg-delete').click(function() {
var url = $(this).attr('data');
$('.msg-del').click(function() {
var url = $(this).data('url');
var msg = $(this).parents('.msg');
var del_confirm = '<div class="msg-del-confirm hide"><p>{% trans "Really want to delete this message?" %}</p><button class="msg-del-yes">{% trans "Yes" %}</button><button class="msg-del-no">{% trans "No" %}</button></div>';
$(this).parent().append(del_confirm).css('position', 'relative');
del_confirm = $(this).parent().find('.msg-del-confirm');
del_confirm.css({'left':$(this).position().left - 15, 'top':$(this).position().top - del_confirm.outerHeight()}).removeClass('hide');
del_confirm.children('.msg-del-yes').click(function() {
del_confirm.remove();
var cfm;
if (msg.find('.msg-del-confirm').length > 0) {
cfm = msg.find('.msg-del-confirm');
} else {
cfm = '<div class="msg-del-confirm hide"><p>{% trans "Really want to delete this message?" %}</p><button class="yes">{% trans "Yes" %}</button><button class="no">{% trans "No" %}</button></div>';
var msg_main = msg.find('.msg-main');
var msg_hd = msg.find('.msg-hd');
cfm = msg_main.append(cfm).children(':last');
cfm.css({'right':msg_main.css('padding-right'), 'top':msg_hd.position().top + msg_hd.height()});
}
cfm.removeClass('hide');
cfm.children('.yes').click(function() {
cfm.addClass('hide');
$.ajax({
url: url,
dataType:'json',
@@ -218,22 +254,14 @@ $('.msg-delete').click(function() {
feedback('{% trans "Failed to delete: " %}' + data['err_msg'], 'error');
}
},
error: function(jqXHR, textStatus, errorThrown) {
feedback(textStatus + '{% trans ", failed to delete." %}', 'error');
error: function() {
feedback('{% trans "Failed." %}', 'error');
}
});
});
del_confirm.children('.msg-del-no').click(function() {
del_confirm.remove();
cfm.children('.no').click(function() {
cfm.addClass('hide');
});
});
{% url 'group_members' group.id as member_add_url %}
{% with post_url=member_add_url %}
{% include 'group/grpmember_add_js.html' %}
{% endwith %}
</script>
{% endblock %}

View File

@@ -7,20 +7,18 @@
{% block title_panel %}
<div class="tabnav">
<div class="grp-profile fright">
{% grp_avatar group.props.id 24 %}<span class="name">{{ group.group_name }}</span>
</div>
<ul class="tabnav-tabs">
<li class="tabnav-tab tabnav-tab-cur">{% trans "Libraries" %}</li>
<li class="tabnav-tab"><a href="{% url 'group_discus' group.id %}">{% trans "Discussions" %}</a></li>
<li class="tabnav-tab"><a href="{% url 'group_discuss' group.id %}">{% trans "Discussion" %}</a></li>
<li class="tabnav-tab"><a href="{% url 'group_wiki' group.id %}">{% trans "Wiki" %}</a></li>
{% if is_staff %}
<li class="tabnav-tab"><a href="{% url 'group_manage' group.id %}">{% trans "Admin" %}</a></li>
{% endif %}
</ul>
<div class="fright">
{% grp_avatar group.props.id 24 %} <span style="font-size: 16px; font-weight:bold; margin: 0 6px;">{{ group.group_name }}</span>
</div>
</div>
{% endblock %}

View File

@@ -8,7 +8,7 @@
<div class="tabnav">
<ul class="tabnav-tabs">
<li class="tabnav-tab"><a href="{% url 'group_info' group.id %}">{% trans "Libraries" %}</a></li>
<li class="tabnav-tab"><a href="{% url 'group_discus' group.id %}">{% trans "Discussions" %}</a></li>
<li class="tabnav-tab"><a href="{% url 'group_discuss' group.id %}">{% trans "Discussion" %}</a></li>
<li class="tabnav-tab"><a href="{% url 'group_wiki' group.id %}">{% trans "Wiki" %}</a></li>
<li class="tabnav-tab tabnav-tab-cur">{% trans "Admin" %}</li>
</ul>

View File

@@ -1,17 +1,14 @@
{% load seahub_tags avatar_tags i18n %}
{% load url from future %}
<ul class="reply-list">
{% for reply in replies %}
<li class="w100 ovhd">
<a href="{% url 'user_profile' reply.from_email %}" class="pic fleft">{% avatar reply.from_email 28 %}</a>
{% for r in replies %}
<li class="reply w100 ovhd">
<a href="{% url 'user_profile' r.from_email %}" class="pic fleft">{% avatar r.from_email 28 %}</a>
<div class="txt fright">
<a href="{% url 'user_profile' reply.from_email %}">{{ reply.from_email|email2nickname }}</a> : {{ reply.message|seahub_urlize|find_at }} --
<button class="reply-at op" data="{{ reply.from_email|email2nickname }}">{% trans 'Reply' %}</button>
<a href="{% url 'user_profile' r.from_email %}">{{ r.from_email|email2nickname }}</a>
<span class="time">{{ r.timestamp|translate_seahub_time }}</span>
<span class="reply-at op vh" data="{{ r.from_email|email2nickname }}">{% trans 'Reply' %}</span>
<p class="reply-con">{{ r.message|seahub_urlize|find_at }}</p>
</div>
</li>
{% endfor %}
</ul>
<input type="text" name="message" class="reply-input" />
<button class="submit">{% trans 'Reply' %}</button>
<p class="error hide">{% trans 'It can not be blank and should be no more than 150 characters.' %}</p>

View File

@@ -1,9 +0,0 @@
{% load seahub_tags avatar_tags i18n %}
{% load url from future %}
<li class="w100 ovhd">
<a href="{% url 'user_profile' reply.from_email %}" class="pic fleft">{% avatar reply.from_email 28 %}</a>
<div class="txt fright">
<a href="{% url 'user_profile' reply.from_email %}">{{ reply.from_email|email2nickname }}</a> : {{ reply.message|seahub_urlize|find_at }} -- <button class="reply-at op" data="{{ reply.from_email|email2nickname }}">{% trans 'Reply' %}</button>
</div>
</li>

View File

@@ -11,7 +11,7 @@
<div class="tabnav">
<ul class="tabnav-tabs">
<li class="tabnav-tab"><a href="{% url 'group_info' group.id %}">{% trans "Libraries" %}</a></li>
<li class="tabnav-tab"><a href="{% url 'group_discus' group.id %}">{% trans "Discussions" %}</a></li>
<li class="tabnav-tab"><a href="{% url 'group_discuss' group.id %}">{% trans "Discussion" %}</a></li>
<li class="tabnav-tab tabnav-tab-cur">{% trans "Wiki" %}</li>
{% if is_staff %}
<li class="tabnav-tab"><a href="{% url 'group_manage' group.id %}">{% trans "Admin" %}</a></li>

View File

@@ -0,0 +1,143 @@
{% load i18n %}
$('.msg-main, .reply').hover(
function(){
$(this).find('.op').removeClass('vh');
},
function(){
$(this).find('.op').addClass('vh');
}
);
$('.msg .op').hover(
function() {
$(this).css({'text-decoration':'underline'});
},
function() {
$(this).css({'text-decoration':'none'});
}
);
$('.reply-cnt-op').hover(
function() {
$(this).children().css({'text-decoration':'underline'});
},
function() {
$(this).children().css({'text-decoration':'none'});
}
).click(function() {
var cnt_op = $(this);
var r_cnt = cnt_op.children('.reply-cnt');
var url = r_cnt.data('url');
var h_r = cnt_op.children('.hide-reply');
var p = cnt_op.parent();
var r_list = p.find('.reply-list');
if (cnt_op.data('rstatus') == 'hide') {
$.ajax({
url: url,
dataType: 'json',
cache: true,
success: function(data) {
r_list.html(data['html']);
r_cnt.addClass('hide');
h_r.removeClass('hide')
cnt_op.data('rstatus', 'show').data('cnt', data['r_num']);
p.find('.reply').hover(
function() {
$(this).find('.op').removeClass('vh');
},
function(){
$(this).find('.op').addClass('vh');
}
);
p.find('.reply-at').hover(
function() {
$(this).css({'text-decoration':'underline'});
},
function() {
$(this).css({'text-decoration':'none'});
}
).click(replyAt);
}
});
} else {
h_r.addClass('hide');
r_cnt.removeClass('hide');
r_list.children(':lt(' + parseInt(cnt_op.data('cnt')-1) + ')').each(function(index) {
$(this).remove();
});
cnt_op.data('rstatus', 'hide');
}
});
$('.reply-input').focus(function() {
$(this).height(50);
$(this).parent().find('.reply-submit, .reply-cancel').removeClass('hide');
});
$('.reply-cancel').click(function() {
var p = $(this).parent();
p.find('.reply-submit, .reply-cancel, .error').addClass('hide');
p.find('.reply-input').val('').height(20);
});
function replyAt() {
var r = $(this).parents('.msg-op');
var r_input = r.find('.reply-input');
r_input.height(50).val('@' + $(this).attr('data') + ' ');
r.find('.reply-submit, .reply-cancel').removeClass('hide');
setCaretPos(r_input[0], r_input.val().length);
r_input.focus();
}
$('.reply-at').click(replyAt);
$('.reply-submit').click(function() {
var p = $(this).parent();
var r_input = p.find('.reply-input');
var r = $.trim(r_input.val());
var err = p.find('.error');
if (!r || r.length > 150) {
err.removeClass('hide');
return false;
}
err.addClass('hide');
var sm = $(this);
var url = sm.data('url');
var r_list = p.find('.reply-list');
disable(sm);
$.ajax({
type: "POST",
url: url,
dataType: 'json',
cache: false,
contentType: 'application/json; charset=utf-8',
beforeSend: prepareCSRFToken,
data: "message=" + r,
success: function(data) {
r_list.html(data['html']).removeClass('hide');
if (data['r_num'] > 3) {
var r_cnt = p.find('.reply-cnt');
r_cnt.html(r_cnt.html().replace(/\d+/, data['r_num']));
p.find('.reply-cnt-op').removeClass('hide');
}
enable(sm);
r_input.val('').height(20);
p.find('.reply-submit, .reply-cancel').addClass('hide');
p.find('.reply').hover(
function(){
$(this).find('.op').removeClass('vh');
},
function(){
$(this).find('.op').addClass('vh');
}
);
p.find('.reply-at').hover(
function() {
$(this).css({'text-decoration':'underline'});
},
function() {
$(this).css({'text-decoration':'none'});
}
).click(replyAt);
},
error:function() {
err.html('{% trans "Failed." %}').removeClass('hide');
enable(sm);
}
});
});

View File

@@ -1,78 +0,0 @@
{% load i18n %}
$('.reply, .replyclose, .msg-delete').hover(
function() {
$(this).css('color', '#f93');
},
function() {
$(this).css('color', '#4b4');
}
);
$('.reply').click(function() {
var myself = $(this),
msg_reply_url = $(this).attr('data'),
msg_bd = $(this).parent(),
reply_cnt = msg_bd.find('.reply-cnt'),
reply_bd = msg_bd.children('.reply-bd');
function afterBdShow() {
myself.addClass('hide');
myself.next().removeClass('hide'); // show 'replyclose'
var reply_input = msg_bd.find('.reply-input'),
error = msg_bd.find('.error');
function replyatHandler() {
reply_input.val('@' + $(this).attr('data') + ' ');
var pos = reply_input.val().length;
setCaretPos(reply_input[0], pos);
reply_input.focus();
}
msg_bd.find('.reply-at').click(replyatHandler);
msg_bd.find('.submit').click(function() {
var self = $(this);
self.attr('disabled', 'disabled');
var reply = $.trim(reply_input.val());
if (reply && reply.length <= 150) {
$.ajax({
type: "POST",
url: msg_reply_url,
dataType: 'json',
cache: false,
contentType: 'application/json; charset=utf-8',
beforeSend: prepareCSRFToken,
data: "message=" + reply,
success: function(data) {
msg_bd.find('.reply-list').append(data['html']).removeClass('hide');
reply_input.val('');
error.attr('class', 'error hide');
reply_cnt.html((parseInt(reply_cnt.html()) + 1 || 1) + ' ');
msg_bd.find('.reply-at').click(replyatHandler);
self.removeAttr('disabled');
}
});
} else {
error.removeClass('hide');
self.removeAttr('disabled');
}
});
}
if ($.trim(reply_cnt.html()) == '') {
reply_bd.html('<ul class="reply-list hide"></ul><input type="text" name="message" class="reply-input" /> <button class="submit">{% trans "Reply" %}</button><p class="error hide">{% trans "It cannot be blank and should be no more than 150 characters." %}</p>').attr('class', 'reply-bd');
afterBdShow();
} else {
reply_bd.html('<img src="{{MEDIA_URL}}img/loading-icon.gif" alt="{% trans "loading ..." %}" />');
$.ajax({
url: msg_reply_url,
dataType: 'json',
success: function(data) {
reply_bd.html(data['html']).attr('class', 'reply-bd');
afterBdShow();
}
});
}
});
$('.replyclose').click(function() {
$(this).parents('.msg-bd').find('.reply-bd').addClass('hide');
$(this).addClass('hide');
$(this).prev().removeClass('hide'); // show 'reply'
});

View File

@@ -11,43 +11,59 @@
<a href="{% url 'user_profile' msg.from_email %}">{% avatar msg.from_email 48 %}</a>
</div>
<div class="txt fright">
<div class="msg-main">
<div class="msg-hd">
<a href="{% url 'user_profile' msg.from_email %}" title="{{msg.from_email}}" class="author">{{ msg.from_email|email2nickname }}</a>
<span class="time">{{ msg.timestamp|translate_seahub_time }}</span>
<a href="{% url 'user_profile' msg.from_email %}">{{ msg.from_email|email2nickname }}</a>
<span class="group">{% trans "Group: " %}<a href="{% url 'group_info' msg.group_id %}">{{ msg.group_name }}</a></span>
</div>
<div class="msg-bd">
<p>
{% if msg.attachment %}
<span class="recommend">{% trans 'Recommended' %}
<p class="msg-con">
{% if msg.attachment.src == 'recommend' %}
<span class="recommend">{% trans "Recommended" %}
{% if msg.attachment.attach_type == 'file' %}
<a href="{% url 'repo_view_file' msg.attachment.repo_id %}?p={{ msg.attachment.path }}" target="_blank">
<a href="{% url 'repo_view_file' msg.attachment.repo_id %}?p={{ msg.attachment.path|urlencode }}" target="_blank">
{% else %}
<a href="{% url 'repo' msg.attachment.repo_id %}?p={{ msg.attachment.path }}" target="_blank">
<a href="{% url 'repo' msg.attachment.repo_id %}?p={{ msg.attachment.path|urlencode }}" target="_blank">
{% endif %}
{{ msg.attachment.name }}</a> :
</span>
{% endif %}
{% if msg.attachment.src == 'filecomment' %}
<span class="recommend">{% trans "File " %}<a href="{% url 'repo_view_file' msg.attachment.repo_id %}?p={{ msg.attachment.path|urlencode }}&comment_open=true" target="_blank"> {{ msg.attachment.name }}</a> {% trans "has a new comment:"%}</span>
{% endif %}
{{ msg.message|seahub_urlize|find_at|linebreaksbr }}
</p>
<button class="reply op hide" data="{% url 'msg_reply' msg.id %}"><span class="reply-cnt">{{ msg.reply_cnt }} </span>{% trans 'Reply' %}</a>
<button class="replyclose op">{% trans 'Hide' %}</button>
<div class="reply-bd">
<ul class="reply-list">
{% for reply in msg.reply_list %}
<li class="w100 ovhd">
<a href="{% url 'user_profile' reply.from_email %}" class="pic fleft">{% avatar reply.from_email 28 %}</a>
<div class="txt fright">
<a href="{% url 'user_profile' reply.from_email %}">{{ reply.from_email|email2nickname }}</a> : {{ reply.message|seahub_urlize|find_at }} --
<button class="reply-at op" data="{{ reply.from_email|email2nickname }}">{% trans 'Reply' %}</button>
</div>
</li>
{% endfor %}
</ul>
<input type="text" name="message" class="reply-input" />
<button class="submit">{% trans 'Reply' %}</button>
<p class="error hide">输入不能为空且应少于150个字符。{% trans "It can't be blank and should be no more than 150 characters." %}</p>
</p>
<span class="say"></span>
</div>
<div class="msg-op">
<div class="reply-cnt-op{% if msg.reply_cnt < 4 %} hide{% endif %}" data-rstatus="hide">
<span class="reply-cnt" data-url="{% url 'msg_reply' msg.id %}">{% blocktrans with amount=msg.reply_cnt %}{{ amount }} replies{% endblocktrans %}</span>
<span class="hide-reply hide">{% trans "Hide replies" %}</span>
</div>
{% if msg.reply_cnt == 0 %}
<ul class="reply-list hide"></ul>
{% else %}
<ul class="reply-list">
{% for r in msg.replies %}
<li class="reply w100 ovhd">
<a href="{% url 'user_profile' r.from_email %}" class="pic fleft">{% avatar r.from_email 28 %}</a>
<div class="txt fright">
<a href="{% url 'user_profile' r.from_email %}">{{ r.from_email|email2nickname }}</a>
<span class="time">{{ r.timestamp|translate_seahub_time }}</span>
<span class="reply-at op vh" data="{{ r.from_email|email2nickname }}">{% trans 'Reply' %}</span>
<p class="reply-con">{{ r.message|seahub_urlize|find_at }}</p>
</div>
</li>
{% endfor %}
</ul>
{% endif %}
<textarea placeholder="{% trans "Add a reply..." %}" name="message" class="reply-input"></textarea>
<p class="error hide">{% trans "It can not be blank and should be no more than 150 characters." %}</p>
<button type="button" class="reply-submit hide" data-url="{% url 'msg_reply' msg.id %}">{% trans "Submit" %}</button>
<button type="button" class="reply-cancel hide">{% trans "Cancel" %}</button>
</div>
</div>
</li>
@@ -60,7 +76,6 @@
{% block extra_script %}
<script type="text/javascript">
{% include 'group/msg_reply_js.html' %}
{% include 'group/new_msg_reply_js.html' %}
{% include 'group/msg_js.html' %}
</script>
{% endblock %}

View File

@@ -1,40 +0,0 @@
$('.reply-at').click(function() {
var reply_input = $(this).parent().parent().parent().next();
reply_input.val('@' + $(this).attr('data') + ' ');
var pos = reply_input.val().length;
setCaretPos(reply_input[0], pos);
reply_input.focus();
});
$('.reply-bd .submit').click(function() {
var msg_bd = $(this).parent().parent(),
msg_reply_url = msg_bd.find('.reply').attr('data'),
reply_cnt = msg_bd.find('.reply-cnt'),
reply_input = $(this).prev(),
reply = $.trim(reply_input.val()),
error = $(this).next();
if (reply && reply.length <= 150) {
$.ajax({
type: "POST",
url: msg_reply_url,
dataType: 'json',
cache: false,
contentType: 'application/json; charset=utf-8',
beforeSend: prepareCSRFToken,
data: "message=" + reply,
success: function(data) {
msg_bd.find('.reply-list').append(data['html']);
reply_input.val('');
error.attr('class', 'error hide');
reply_cnt.html(parseInt(reply_cnt.html()) + 1 + ' ');
msg_bd.find('.reply-at').click(function() {
reply_input.val('@' + $(this).attr('data') + ' ');
var pos = reply_input.val().length;
setCaretPos(reply_input[0], pos);
reply_input.focus();
});
}
});
} else {
error.removeClass('hide');
}
});

View File

@@ -3,12 +3,12 @@ from django.conf.urls.defaults import *
from views import group_info, group_member_operations, group_add_admin, \
group_manage, msg_reply, msg_reply_new, group_recommend, \
create_group_repo, group_joinrequest, attention, group_message_remove, \
group_remove_admin, group_discus, group_wiki, group_wiki_create, \
group_remove_admin, group_discuss, group_wiki, group_wiki_create, \
group_wiki_page_new, group_wiki_page_edit
urlpatterns = patterns('',
url(r'^(?P<group_id>\d+)/$', group_info, name='group_info'),
url(r'^(?P<group_id>\d+)/discus/$', group_discus, name='group_discus'),
url(r'^(?P<group_id>\d+)/discuss/$', group_discuss, name='group_discuss'),
url(r'^(?P<group_id>\d+)/wiki/$', group_wiki, name='group_wiki'),
url(r'^(?P<group_id>\d+)/wiki/(?P<page_name>[^/]+)/$', group_wiki, name='group_wiki'),
url(r'^(?P<group_id>\d+)/wiki_create/$', group_wiki_create, name='group_wiki_create'),

View File

@@ -296,17 +296,17 @@ def msg_reply(request, msg_id):
content_type = 'application/json; charset=utf-8'
if request.is_ajax():
ctx = {}
try:
group_msg = GroupMessage.objects.get(id=msg_id)
except GroupMessage.DoesNotExist:
return HttpResponseBadRequest(content_type=content_type)
if request.method == 'POST':
form = MessageReplyForm(request.POST)
# TODO: invalid form
if form.is_valid():
msg = form.cleaned_data['message']
try:
group_msg = GroupMessage.objects.get(id=msg_id)
except GroupMessage.DoesNotExist:
return HttpResponseBadRequest(content_type=content_type)
msg_reply = MessageReply()
msg_reply.reply_to = group_msg
msg_reply.from_email = request.user.username
@@ -318,22 +318,23 @@ def msg_reply(request, msg_id):
grpmsg_reply_added.send(sender=MessageReply,
msg_id=msg_id,
from_email=request.user.username)
ctx['reply'] = msg_reply
html = render_to_string("group/group_reply_new.html", ctx)
replies = MessageReply.objects.filter(reply_to=group_msg)
r_num = len(replies)
if r_num < 4:
ctx['replies'] = replies
else:
ctx['replies'] = replies[r_num - 3:]
html = render_to_string("group/group_reply_list.html", ctx)
serialized_data = json.dumps({"r_num": r_num, "html": html})
return HttpResponse(serialized_data, content_type=content_type)
else:
try:
msg = GroupMessage.objects.get(id=msg_id)
except GroupMessage.DoesNotExist:
raise HttpResponse(status=400)
replies = MessageReply.objects.filter(reply_to=msg)
replies = MessageReply.objects.filter(reply_to=group_msg)
r_num = len(replies)
ctx['replies'] = replies
html = render_to_string("group/group_reply_list.html", ctx)
serialized_data = json.dumps({"html": html})
return HttpResponse(serialized_data, content_type=content_type)
serialized_data = json.dumps({"r_num": r_num, "html": html})
return HttpResponse(serialized_data, content_type=content_type)
else:
return HttpResponseBadRequest(content_type=content_type)
@@ -372,7 +373,7 @@ def msg_reply_new(request):
# get message replies
reply_list = MessageReply.objects.filter(reply_to=m)
m.reply_list = reply_list
m.replies = reply_list
m.reply_cnt = reply_list.count()
group_msgs.append(m)
@@ -912,7 +913,7 @@ def attention(request):
@login_required
def group_discus(request, group_id):
def group_discuss(request, group_id):
if request.method == 'POST':
form = MessageForm(request.POST)
@@ -929,7 +930,7 @@ def group_discus(request, group_id):
from_email=request.user.username)
# Always return an HttpResponseRedirect after successfully dealing
# with POST data.
return HttpResponseRedirect(reverse('group_info', args=[group_id]))
return HttpResponseRedirect(reverse('group_discuss', args=[group_id]))
else:
form = MessageForm()
@@ -978,21 +979,16 @@ def group_discus(request, group_id):
# Make sure page request is an int. If not, deliver first page.
try:
current_page = int(request.GET.get('page', '1'))
per_page= int(request.GET.get('per_page', '15'))
except ValueError:
current_page = 1
per_page = 15
per_page = 45
msgs_plus_one = GroupMessage.objects.filter(
group_msgs = GroupMessage.objects.filter(
group_id=group_id).order_by(
'-timestamp')[per_page*(current_page-1) : per_page*current_page+1]
'-timestamp')[per_page*(current_page-1) : per_page*current_page]
if len(msgs_plus_one) == per_page + 1:
page_next = True
else:
page_next = False
group_msgs = list(group_msgs) # Force evaluate queryset to fix some database error for mysql
group_msgs = msgs_plus_one[:per_page]
attachments = MessageAttachment.objects.filter(group_message__in=group_msgs)
msg_replies = MessageReply.objects.filter(reply_to__in=group_msgs)
@@ -1000,6 +996,11 @@ def group_discus(request, group_id):
for msg in group_msgs:
msg.reply_cnt = reply_to_list.count(msg.id)
msg.replies = []
for r in msg_replies:
if msg.id == r.reply_to_id:
msg.replies.append(r)
msg.replies = msg.replies[-3:]
for att in attachments:
if msg.id == att.group_message_id:
@@ -1020,9 +1021,32 @@ def group_discus(request, group_id):
att.name = os.path.basename(path)
msg.attachment = att
contacts = Contact.objects.filter(user_email=request.user.username)
per_show = 15
if current_page == 1 and len(group_msgs) > per_show:
msgs_more = True
else:
msgs_more = False
return render_to_response("group/group_discus.html", {
msg_total_num = GroupMessage.objects.filter(group_id=group_id).count()
total_page = msg_total_num/per_page
if msg_total_num % per_page > 0:
total_page += 1
page_next = True if current_page < total_page else False
# get page numbers shown in the web page
first_page = 1
if total_page <= 10:
last_page = total_page
else:
if current_page < 6:
last_page = 10
else:
first_page = current_page - 5
last_page = current_page + 4 if current_page + 4 < total_page else total_page
pages_show = range(first_page, last_page + 1)
return render_to_response("group/group_discuss.html", {
"managers": managers,
"common_members": common_members,
"members": members,
@@ -1031,12 +1055,13 @@ def group_discus(request, group_id):
"is_staff": is_staff,
"group_msgs": group_msgs,
"form": form,
'per_show': per_show,
'msgs_more': msgs_more,
'current_page': current_page,
'prev_page': current_page-1,
'next_page': current_page+1,
'per_page': per_page,
'page_next': page_next,
'contacts': contacts,
'pages_show': pages_show,
'group_members_default_display': GROUP_MEMBERS_DEFAULT_DISPLAY,
}, context_instance=RequestContext(request));

View File

@@ -38,12 +38,14 @@ textarea {
border: 1px solid #ddd;
overflow: auto; /* rm default vertical scrollbar in ie */
resize: vertical; /* for drag */
outline:0;
}
input {
height:22px;
/*line-height:22px;*/
border: 1px solid #ddd;
margin:3px 0;
outline:0;
}
input,
button {
@@ -171,6 +173,14 @@ p {
color:#803;
word-wrap:break-word;
}
.big-more-btn {
padding:.5em 0;
color:#777;
}
.big-more-btn:hover {
color:#000;
background:#dfdfdf;
}
.no-deco,
.no-deco:hover {
text-decoration:none;
@@ -207,7 +217,25 @@ input.btn-disabled:hover {/*for input*/
background-color:#f5f5f5;
background-position:3px -206px;
}
#paginator { margin:10px; }
#paginator {
text-align:center;
margin:10px 0;
font-size:14px;
}
#paginator .pg {
font-weight:normal;
margin:0 3px;
}
#paginator .prev {
margin-right:30px;
}
#paginator .prev,
#paginator .next {
text-decoration:underline;
}
#paginator .next {
margin-left:30px;
}
.tri-bg { /*triangle bg, <span>*/
display:inline-block;
font-size:0;
@@ -1368,6 +1396,18 @@ textarea:-moz-placeholder {/* for FF */
-webkit-box-shadow: 0 2px 4px rgba(0,0,0,0.2);
-moz-box-shadow: 0 2px 4px rgba(0,0,0,0.2);
}
.grp-profile {
margin-top:2px;
}
.grp-profile .name {
font-size:16px;
font-weight:bold;
margin:0 6px;
}
.grp-profile .avatar,
.grp-profile .name {
vertical-align:middle;
}
.group-basic-info .txt {
width:145px;
word-wrap:break-word;
@@ -1408,49 +1448,69 @@ textarea:-moz-placeholder {/* for FF */
}
#group-reply,
.new-reply-msg-list {
width:602px;
width:640px;
margin-top:10px;
}
.new-reply-msg-list {
margin-top:0;
}
.msg-num {
font-size:12px;
color:#333;
}
#message {
width: 600px;
height: 80px;
margin-top: 4px;
#group-message-form {
padding:6px;
border:1px solid #c4c4c4;
border-radius:5px;
background:#f9f9f9;
position:relative;
}
#message {
width:538px;
margin-top:0;
width:550px;
padding:3px 5px;
height:25px;
vertical-align:top;
}
#group-reply .submit {
margin-top:3px;
}
.msg-list {
margin-top: 10px;
}
.msg-list button.op {
color: #4b4;
.say {
position:absolute;
width:10px;
height:21px;
background:transparent url('../img/say.png') no-repeat scroll left top;
left:-10px;
top:13px;
}
.msg {
word-wrap: break-word;
padding: 10px 0 5px;
min-height: 48px;
_min-height: 48px;
margin:15px 0 20px;
}
.msg .txt {
width:540px;
width:576px;
}
.msg-hd {
padding:2px 3px;
background:#fafafa;
margin-bottom:2px;
.msg a {
font-weight: normal;
}
.msg-main {
position:relative;
padding:16px;
background:#fff;
border:1px solid #ccc;
border-top-left-radius:3px;
border-top-right-radius:3px;
}
.msg-main .say {
background-image:url('../img/say_white.png');
}
.msg-hd .author {
font-weight:bold;
}
.msg .time {
font-size:11px;
color:#999;
margin-left:5px;
}
.msg .op {
font-size:11px;
color:#999;
cursor:pointer;
margin-left:5px;
}
.msg-hd .time,
.msg-hd .group,
.comment-hd .time {
color: #808080;
@@ -1458,41 +1518,49 @@ textarea:-moz-placeholder {/* for FF */
.msg-hd .group {
margin-left:30px;
}
.msg-bd a {
font-weight: normal;
.msg-con {
margin-bottom:0;
}
.msg-bd .op {
padding:0;
background:none;
border:none;
.msg-op {
padding:10px 16px;
background:#f8f8f8;
border:1px solid #d5d5d5;
border-top:0;
border-bottom-left-radius:3px;
border-bottom-right-radius:3px;
}
.msg-bd .recommend,
.msg-bd .at,
.comment-bd .at {
.reply-cnt-op {
font-weight:bold;
cursor:pointer;
margin-bottom:10px;
}
.msg .recommend,
.msg .at {
color:#808;
}
.reply-list {
.reply {
color:#444;
font-size:12px;
width:90%;
line-height:1.2;
margin-bottom:15px;
}
.reply-list li {
margin:5px 0;
}
.reply-list .txt {
.reply .txt {
width: 93%;
}
.reply-con {
margin:0;
}
.reply-input {
width:82%;
padding:0 1px;
width:530px;
padding:5px;
height:20px;
vertical-align:top;
}
.reply-at {
font-size:12px;
*height:18px;
*vertical-align:middle;
}
.reply-at:hover {
color:#f93;
#group-message-form .submit,
#group-message-form .cancel,
.reply-submit,
.reply-cancel {
margin-top:6px;
margin-right:2px;
}
.msg-del-confirm {
position:absolute;
@@ -1500,8 +1568,6 @@ textarea:-moz-placeholder {/* for FF */
background:#fff;
border:1px solid #ddd;
box-shadow: 0 2px 4px rgba(0,0,0,.2);
-moz-box-shadow: -1px 1px 1px rgba(0,0,0,.2);
-webkit-box-shadow: 0 2px 4px rgba(0,0,0,.2);
}
.msg-del-confirm button {
margin-right:8px;
@@ -1513,6 +1579,10 @@ textarea:-moz-placeholder {/* for FF */
#msg-upward:hover {
text-decoration:none;
}
#msgs-more {
width:576px;
margin-left:64px;
}
/*file upload*/
#upload-file-form {
margin-top:10px;
@@ -2008,4 +2078,4 @@ textarea:-moz-placeholder {/* for FF */
.search-results-item .content {
clear: left;
margin: 0 0 0 40px;
}
}

BIN
media/img/say.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 476 B

BIN
media/img/say_white.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 416 B