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

[file view] add 'discussion'

This commit is contained in:
llj
2016-05-24 17:53:29 +08:00
parent fe999b7559
commit f67865ea62
7 changed files with 304 additions and 60 deletions

View File

@@ -17,15 +17,9 @@
#shared-file-view-hd {
margin-top:4px;
}
#file-op {
padding:0;
border:0;
}
#file-op .avatar,
#file-op .name,
#file-op .time,
#file-op span {
#file-op .avatar {
vertical-align:middle;
border-radius:1000px;
}
#file-op .time {
color:#666;
@@ -34,9 +28,6 @@
#file-op .file-diff {
font-size:100%;
}
#file-op .contributors {
margin-left:8px;
}
#file-view {
padding:30px 0 15px;
background:#f4f4f4;
@@ -73,9 +64,6 @@
.file-path {
margin: 0 0 9px;
}
#file-op .avatar {
border-radius:1000px;
}
.history-file-path {
margin:.5em 0 0;
}

View File

@@ -886,7 +886,7 @@ textarea:-moz-placeholder {/* for FF */
}
/**** right side panel ****/
.right-side-panel {
background:#f8f8f8;
background: #fff;
width:400px;
position:fixed;
right:-400px;
@@ -901,6 +901,7 @@ textarea:-moz-placeholder {/* for FF */
transition: all 0.3s ease;
}
.right-side-panel-hd {
background:#f8f8f8;
padding:10px;
border-bottom:1px solid #c9c9c9;
}
@@ -910,7 +911,6 @@ textarea:-moz-placeholder {/* for FF */
}
.right-side-panel-con {
overflow-y: auto;
background: #fff;
}
/**** messages ****/
.messages {
@@ -1979,7 +1979,6 @@ button.sf-dropdown-toggle:focus {
text-align:right;
margin-bottom:4px;
}
.file-op button,
#file-op button,
.repo-op .op-btn {
*margin-left:5px;/* for ie 7*/
@@ -2440,10 +2439,6 @@ button.sf-dropdown-toggle:focus {
}
/* file view online, file edit */
.file-op {
color:#444;
text-align:right;
}
#shared-link,
#shared-upload-link,
#shared-link-text,
@@ -2461,22 +2456,6 @@ button.sf-dropdown-toggle:focus {
#gen-upload-link-btn {
margin-top: 0.5em;
}
.file-op {
margin-top:0.8em;
}
.file-op a {
font-weight:normal;
margin-left:2px;
}
.file-op button {
color:#444;
}
.file-op [class^='icon-'],
.file-op [class^='sf-icon-'] {
font-size:1em;
margin-right:3px;
color:#666;
}
#text-diff-output {
padding:3px;
background:#dedede;
@@ -2484,13 +2463,7 @@ button.sf-dropdown-toggle:focus {
-moz-border-radius:3px;
margin-top:12px;
}
#file-op {
padding:8px 10px;
background:#fff;
text-align:right;
border:1px solid #ccc;
}
#file-op button,
#file-op .op-btn,
#file-op .sf-btn-link {
padding:2px 8px;
}

View File

@@ -1,5 +1,5 @@
{% extends 'base.html' %}
{% load seahub_tags avatar_tags i18n %}
{% load seahub_tags avatar_tags i18n staticfiles %}
{% load url from future %}
{% block sub_title %}{{filename}} - {% endblock %}
@@ -39,31 +39,32 @@
</div>
<div id="file">
<div id="file-op">
<div id="file-op" class="ovhd">
<div class="commit fleft">
{% avatar latest_contributor 24 %} <a href="{% url 'user_profile' latest_contributor %}" class="name">{{ latest_contributor|email2nickname }}</a>
<span class="time">{{ last_modified|translate_seahub_time}}</span>
{% avatar latest_contributor 24 %} <a href="{% url 'user_profile' latest_contributor %}" class="name vam">{{ latest_contributor|email2nickname }}</a>
<span class="time vam">{{ last_modified|translate_seahub_time}}</span>
{% block update_detail %}
{% if last_commit_id %}
<span>{% trans "updated this file"%}.</span>
<span class="vam">{% trans "updated this file"%}.</span>
{% endif %}
{% endblock %}
</div>
<div class="fright">
{% if can_lock_unlock_file %}
{% if not file_locked %}
<button id="lock-file">{% trans "Lock" %}</button>
<button id="unlock-file" class="hide">{% trans "Unlock" %}</button>
<button id="lock-file" class="op-btn">{% trans "Lock" %}</button>
<button id="unlock-file" class="op-btn hide">{% trans "Unlock" %}</button>
{% elif locked_by_me %}
<button id="unlock-file">{% trans "Unlock" %}</button>
<button id="lock-file" class="hide">{% trans "Lock" %}</button>
<button id="unlock-file" class="op-btn">{% trans "Unlock" %}</button>
<button id="lock-file" class="op-btn hide">{% trans "Lock" %}</button>
{% endif %}
{% endif %}
{% if not repo.encrypted %}
{% if request.user.permissions.can_generate_shared_link %}
<button id="share" data-link="{{ file_shared_link }}" data-token="{{ fileshare.token }}">{% trans "Share" %}</button>
<button id="share" class="op-btn" data-link="{{ file_shared_link }}" data-token="{{ fileshare.token }}">{% trans "Share" %}</button>
{% endif %}
{% endif %}
@@ -77,6 +78,11 @@
{% endif %}
<a class="sf-btn-link" href="?dl=1" id="download">{% trans "Download"%}</a>
<button id="discuss" class="op-btn">{% trans "Discuss" %}</button>
</div>
<div id="file-discussions" class="right-side-panel"></div>
</div>
<div id="file-view">
@@ -100,9 +106,53 @@
</ul>
</div>
<script type="text/template" id="discussion-panel-tmpl">
<div class="right-side-panel-hd file-discussions-hd ovhd">
<a href="#" title="{% trans "Close" %}" aria-label="{% trans "Close" %}" class="sf-popover-close js-close sf2-icon-x1 op-icon fleft"></a>
<h3 class="alc">{% trans "Discussions" %}</h3>
</div>
<div class="right-side-panel-con file-discussions-con">
<div class="loading-icon loading-tip"></div>
<ul class="file-discussion-list hide"></ul>
<p class="no-discussion-tip hide">{% trans "No discussion yet." %}</p>
<p class="error hide"></p>
</div>
<div class="right-side-panel-footer file-discussions-footer">
<form action="" method="post" class="msg-form">
<img src="{% avatar_url request.user 64 %}" alt="" width="32" class="avatar-circle fleft" />
<div class="msg-body">
<textarea name="message" placeholder="{% trans "Add a discussion..." %}" class="msg-input"></textarea>
<p class="error hide"></p>
<button type="submit" class="submit msg-submit">{% trans "Submit" %}</button>
</div>
</form>
</div>
</script>
<script type="text/template" id="discussion-tmpl">
<li class="msg ovhd">
<img src="<%= avatar_url %>" alt="" width="32" class="avatar-circle fleft" />
<div class="msg-body">
<div class="ovhd">
<a class="msg-username ellipsis" title="<%- user_name %>" href="<%= user_profile_url %>"><%- user_name %></a>
<span class="msg-time" title="<%- time %>"><%- time_from_now %></span>
<div class="msg-ops fright vh">
<a class="msg-op sf2-icon-reply op-icon js-reply-msg" title="{% trans "Reply" %}" aria-label="{% trans "Reply" %}" href="#" data-username="<%- user_name %>"></a>
<% if (can_delete_msg) { %>
<a class="msg-op sf2-icon-delete op-icon js-del-msg" title="{% trans "Delete" %}" aria-label="{% trans "Delete" %}" href="#" data-id="<%= id %>"></a>
<% } %>
</div>
</div>
<div class="msg-content"><%= content_marked %></div>
</div>
</li>
</script>
{% endblock %}
{% block extra_script %}
<script type="text/javascript" src="{% static "scripts/lib/underscore.js" %}"></script>
<script type="text/javascript" src="{% static "scripts/lib/moment-with-locales.js" %}"></script>
<script type="text/javascript" src="{% static "scripts/lib/marked.min.js" %}"></script>
{% if highlight_keyword %}
<script type="text/javascript" src="{{ MEDIA_URL }}js/findAndReplaceDOMText.js"></script>
{% endif %}
@@ -243,5 +293,238 @@ $(window).load(function() {
}
});
{% endif %}
// file discussion
var fileDiscussions = {
$el: $('#file-discussions'),
tmpl: _.template($('#discussion-panel-tmpl').html()),
init: function() {
var _this = this;
// events
this.$el.on('click', '.js-close', function() {
_this.hide();
return false;
});
this.$el.on('mouseenter', '.msg', function() {
$(this).addClass('hl').find('.msg-ops').removeClass('vh');
});
this.$el.on('mouseleave', '.msg', function() {
$(this).removeClass('hl').find('.msg-ops').addClass('vh');
});
this.$el.on('click', '.js-reply-msg', function() {
_this.replyTo($(this).attr('data-username'));
return false;
});
this.$el.on('click', '.js-del-msg', function() {
_this.delOne({
id: $(this).attr('data-id'),
$el: $(this).closest('.msg')
});
return false;
});
this.$el.on('submit', '.msg-form', function() {
_this.formSubmit();
return false;
});
},
render: function () {
this.$el.html($(this.tmpl()));
this.$listContainer = $('.file-discussion-list', this.$el);
this.$emptyTip = $('.no-discussion-tip', this.$el);
this.$loadingTip = $('.loading-tip', this.$el);
this.$conError = $('.file-discussions-con .error', this.$el);
this.$msgInput = $('[name="message"]', this.$el);
},
collectionUrl: '{% url "api2-file-comments" repo.id %}?p='
+ e('{{path|escapejs}}') + '&avatar_size=64',
show: function() {
this.render();
this.$el.css({'right': 0});
this.setConHeight();
this.getContent();
},
hide: function() {
this.$el.css({'right': '-400px'});
this.$el.empty();
},
getContent: function() {
var _this = this;
$.ajax({
url: this.collectionUrl,
type: 'GET',
cache: false,
dataType: 'json',
success: function(data) {
var comments = data.comments;
if (comments.length > 0) {
$(comments).each(function(index, item) {
_this.addOne(item);
});
_this.$listContainer.show();
} else {
_this.$emptyTip.show();
}
},
error: function(xhr) {
var err_msg;
if (xhr.responseText) {
err_msg = $.parseJSON(xhr.responseText).error_msg;
} else {
err_msg = "{% trans "Failed. Please check the network." %}";
}
_this.$conError.html(err_msg).show();
},
complete: function() {
_this.$loadingTip.hide();
}
});
},
formSubmit: function() {
var _this = this;
var $formError = $('.msg-form .error', this.$el);
var $submitBtn = $('[type="submit"]', this.$el)
var msg = $.trim(this.$msgInput.val());
if (!msg) {
return false;
}
$formError.hide();
disable($submitBtn);
$.ajax({
url: this.collectionUrl,
type: 'POST',
cache: false,
dataType: 'json',
beforeSend: prepareCSRFToken,
data: {'comment': msg},
success: function(data) {
_this.$msgInput.val('');
_this.addOne(data);
if (_this.$emptyTip.is(':visible')) {
_this.$emptyTip.hide();
_this.$listContainer.show();
}
},
error: function(xhr) {
var err_msg;
if (xhr.responseText) {
err_msg = $.parseJSON(xhr.responseText).error_msg;
} else {
err_msg = "{% trans "Failed. Please check the network." %}";
}
$formError.html(err_msg).show();
},
complete: function() {
enable($submitBtn);
}
});
},
itemTmpl: _.template($('#discussion-tmpl').html()),
addOne: function(obj) {
var can_delete_msg = false;
if ('{{is_repo_owner}}' == 'True' ||
obj.user_email == '{{request.user|escapejs}}') {
can_delete_msg = true;
}
var user_profile_url = '{{SITE_ROOT}}profile/' + encodeURIComponent(obj.user_email) + '/';
var m = moment(obj.created_at);
var data = $.extend({}, obj, {
'content_marked': marked(obj.comment, {
breaks: true,
sanitize: true
}),
'time': m.format('LLLL'),
'time_from_now': this.util_getRelativeTimeStr(m),
'can_delete_msg': can_delete_msg,
'user_profile_url': user_profile_url
});
var $item = $(this.itemTmpl(data));
this.$listContainer.append($item);
},
setConHeight: function() {
$('.file-discussions-con', this.$el).css({
'max-height': $(window).height()
- $('.file-discussions-hd', this.$el).outerHeight(true)
- $('.file-discussions-footer', this.$el).outerHeight(true)
});
},
replyTo: function(to_user) {
var str = "@" + to_user + " ";
var $input = this.$msgInput.val(str);
setCaretPos($input[0], str.length);
$input.focus();
},
// delete a comment
delOne: function(item) { // item: {id:, $el:}
var _this = this;
$.ajax({
url: '{{SITE_ROOT}}api2/repos/{{repo.id}}/file/comments/' + item.id + '/',
type: 'delete',
cache: false,
beforeSend: prepareCSRFToken,
success: function() {
item.$el.remove();
if ($('.msg', _this.$el).length == 0) {
_this.$emptyTip.show();
_this.$listContainer.hide();
}
},
error: function(xhr) {
var err_msg;
if (xhr.responseText) {
err_msg = $.parseJSON(xhr.responseText).error_msg;
} else {
err_msg = "{% trans "Failed. Please check the network." %}";
}
feedback(err_msg, 'error');
}
});
},
util_getRelativeTimeStr: function(m) {
var now = new Date();
if (m - now > 0) {
return "{% trans "Just now" %}";
} else {
return m.fromNow();
}
}
};
// init
fileDiscussions.init();
$('#discuss').click(function() {
fileDiscussions.show();
});
$(document).keydown(function(e) {
// ESCAPE key pressed
if (e.which == 27) {
fileDiscussions.hide();
}
});
$(window).resize(function() {
fileDiscussions.setConHeight();
});
</script>
{% endblock %}

View File

@@ -4,7 +4,7 @@
{% block update_detail %}
{% if last_commit_id %}
<span>{% trans "updated this file"%}, <a class="file-diff" href="{% url 'text_diff' repo.id %}?p={{path|urlencode}}&commit={{last_commit_id}}&file_enc={{file_enc}}">{% trans "Detail"%}</a>.</span>
<span class="vam">{% trans "updated this file"%}, <a class="file-diff" href="{% url 'text_diff' repo.id %}?p={{path|urlencode}}&commit={{last_commit_id}}&file_enc={{file_enc}}">{% trans "Detail"%}</a>.</span>
{% endif %}
{% endblock %}

View File

@@ -13,7 +13,7 @@
{% block update_detail %}
{% if last_commit_id %}
<span>{% trans "updated this file"%}, <a class="file-diff" href="{% url 'text_diff' repo.id %}?p={{path|urlencode}}&commit={{last_commit_id}}&file_enc={{file_enc}}">{% trans "Detail"%}</a>.</span>
<span class="vam">{% trans "updated this file"%}, <a class="file-diff" href="{% url 'text_diff' repo.id %}?p={{path|urlencode}}&commit={{last_commit_id}}&file_enc={{file_enc}}">{% trans "Detail"%}</a>.</span>
{% endif %}
{% endblock %}

View File

@@ -19,7 +19,7 @@
</div>
<div id="file">
<div id="file-op">
<div id="file-op" class="ovhd">
<p class="history-file-path fleft">
{% block file_path %}
{% trans "Current Path: "%}
@@ -29,7 +29,7 @@
{% endblock %}
</p>
<a class="sf-btn-link" href="{% url 'download_file' repo.id obj_id%}?file_name={{ file_name|urlencode }}&p={{path|urlencode}}" id="download">{% trans "Download"%}</a>
<a class="sf-btn-link fright" href="{% url 'download_file' repo.id obj_id%}?file_name={{ file_name|urlencode }}&p={{path|urlencode}}" id="download">{% trans "Download"%}</a>
</div>
{% include 'snippets/file_content_html.html' %}
</div>

View File

@@ -29,7 +29,7 @@ define([
var _this = this;
$(document).keydown(function(e) {
// ESCAPE key pressed
if (e.keyCode == 27) {
if (e.which == 27) {
_this.hide();
}
});