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:
@@ -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;
|
||||
}
|
||||
|
@@ -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;
|
||||
}
|
||||
|
@@ -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 %}
|
||||
|
@@ -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 %}
|
||||
|
||||
|
@@ -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 %}
|
||||
|
||||
|
@@ -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>
|
||||
|
@@ -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();
|
||||
}
|
||||
});
|
||||
|
Reference in New Issue
Block a user