Raw view improvements, copy snippet button, hide edit panel. #120

This commit is contained in:
Martin Mahner 2019-05-27 09:55:39 +02:00
parent 2666c90400
commit 8825ef0930
9 changed files with 97 additions and 8 deletions

View file

@ -1,6 +1,14 @@
Changelog Changelog
========= =========
(development)
-------------
- "Edit Snippet" panel is now hidden by default to remove visual noise.
- Added a dedicated "Copy Snippet" button to copy the content to the clipboard.
- Added "View Raw" option to optionally render the 'raw' snippet content with a
template rather served as plain text. This was added to hinder abuse.
3.1 (2019-05-16) 3.1 (2019-05-16)
---------------- ----------------

View file

@ -102,12 +102,43 @@ lines.forEach(function(el) {
// Copy URL to Clipboard // Copy URL to Clipboard
// ----------------------------------------------------------------------------- // -----------------------------------------------------------------------------
const clipboardLink = document.getElementById('copyToClipboard'); const clipboardLink = document.getElementById('copyToClipboard');
const copyToClipboardField = document.getElementById('copyToClipboardField'); const clipboardField = document.getElementById('copyToClipboardField');
if (clipboardLink && copyToClipboardField) { if (clipboardLink && clipboardField) {
clipboardLink.onclick = function(e) { clipboardLink.onclick = function(e) {
e.preventDefault(); e.preventDefault();
copyToClipboardField.select(); clipboardField.select();
document.execCommand('Copy'); document.execCommand('Copy');
}; };
} }
// -----------------------------------------------------------------------------
// Copy Snippet content to Clipboard
// -----------------------------------------------------------------------------
const snippetClipboardLink = document.getElementById('copySnippetToClipboard');
const snippetClipboardField = document.getElementById('copySnippetSource');
const snippetClipboardConfirm = document.getElementById('copy');
if (snippetClipboardLink && snippetClipboardField) {
snippetClipboardLink.onclick = function(e) {
e.preventDefault();
snippetClipboardField.select();
document.execCommand('Copy');
snippetClipboardConfirm.style.maxHeight = '80px';
window.scrollTo(0, 0);
};
}
const editSnippetLink = document.getElementById('editSnippet');
const editSnippetForm = document.getElementById('edit');
if (editSnippetLink && editSnippetForm) {
editSnippetLink.onclick = function(e) {
e.preventDefault();
editSnippetForm.style.display = 'block';
window.scrollTo(
editSnippetForm.getBoundingClientRect().x,
editSnippetForm.getBoundingClientRect().y
);
};
}

View file

@ -5,6 +5,11 @@
line-height: 17px; line-height: 17px;
} }
// Edit panel in details view, not shown by default.
#edit {
display: none;
}
.snippet-form { .snippet-form {
background-color: $bgColor; background-color: $bgColor;

View file

@ -133,3 +133,10 @@ ul#snippetOptions {
font-size: 14px; font-size: 14px;
font-weight: $baseFontDemiBold; font-weight: $baseFontDemiBold;
} }
// Textarea that holds the unaltered snippet content to be copied to clipboard
#copySnippetSource {
width: 0;
position: absolute;
left: -9999px;
}

View file

@ -77,6 +77,10 @@ class dpasteAppConfig(AppConfig):
# Disable "view Raw" mode. # Disable "view Raw" mode.
RAW_MODE_ENABLED = True RAW_MODE_ENABLED = True
# If enabled, the "raw View" mode will display the snippet content as
# plain text rather rendered in a template.
RAW_MODE_PLAIN_TEXT = True
# Lexers which have wordwrap enabled by default # Lexers which have wordwrap enabled by default
LEXER_WORDWRAP = ('rst',) LEXER_WORDWRAP = ('rst',)

View file

@ -36,6 +36,9 @@
{% if raw_mode and snippet.expire_type != 3 %} {% if raw_mode and snippet.expire_type != 3 %}
<li><a href="{% url "snippet_details_raw" snippet.secret_id %}">{% trans "View Raw" %}</a></li> <li><a href="{% url "snippet_details_raw" snippet.secret_id %}">{% trans "View Raw" %}</a></li>
{% endif %} {% endif %}
<textarea id="copySnippetSource">{{ snippet.content }}</textarea>
<li><a href="#copy" id="copySnippetToClipboard">{% trans "Copy Snippet" %}</a></li>
<li><a href="#edit" id="editSnippet">{% trans "Edit Snippet" %}</a></li>
{% if snippet.lexer != 'text' %} {% if snippet.lexer != 'text' %}
<li> <li>
<label for="wordwrap"> <label for="wordwrap">
@ -45,6 +48,12 @@
{% endif %} {% endif %}
</ul> </ul>
<div id="copy" class="confirm-modal">
<form method="POST" action="">
{% trans "Snippet content copied to clipboard." %}
</form>
</div>
<div id="delete" class="confirm-modal"> <div id="delete" class="confirm-modal">
<form method="POST" action=""> <form method="POST" action="">
{% csrf_token %} {% csrf_token %}
@ -77,9 +86,11 @@
{{ snippet.highlight }} {{ snippet.highlight }}
<header class="sub"> <div id="edit">
<h2>{% trans "Edit this Snippet" %}</h2> <header class="sub">
</header> <h2>{% trans "Edit this Snippet" %}</h2>
</header>
{% include "dpaste/includes/form.html" %} {% include "dpaste/includes/form.html" %}
</div>
{% endblock %} {% endblock %}

View file

@ -37,3 +37,4 @@
{{ form.content }} {{ form.content }}
</p> </p>
</form> </form>

View file

@ -0,0 +1,13 @@
<!DOCTYPE html>
<html>
<head>
<title>{{ snippet.secret_id }}</title>
<meta name="viewport" content="width=device-width, initial-scale=1.0"/>
<meta name="robots" content="noindex, nofollow"/>
</head>
<body>
<pre>{{ object.content }}</pre>
</body>
</html>

View file

@ -152,6 +152,8 @@ class SnippetRawView(SnippetDetailView):
Display the raw content of a snippet Display the raw content of a snippet
""" """
template_name = 'dpaste/raw.html'
def dispatch(self, request, *args, **kwargs): def dispatch(self, request, *args, **kwargs):
if not config.RAW_MODE_ENABLED: if not config.RAW_MODE_ENABLED:
return HttpResponseForbidden( return HttpResponseForbidden(
@ -161,13 +163,20 @@ class SnippetRawView(SnippetDetailView):
) )
return super(SnippetRawView, self).dispatch(request, *args, **kwargs) return super(SnippetRawView, self).dispatch(request, *args, **kwargs)
def render_to_response(self, context, **response_kwargs): def render_plain_text(self, context, **response_kwargs):
snippet = self.get_object() snippet = self.get_object()
response = HttpResponse(snippet.content) response = HttpResponse(snippet.content)
response['Content-Type'] = 'text/plain;charset=UTF-8' response['Content-Type'] = 'text/plain;charset=UTF-8'
response['X-Content-Type-Options'] = 'nosniff' response['X-Content-Type-Options'] = 'nosniff'
return response return response
def render_to_response(self, context, **response_kwargs):
if config.RAW_MODE_PLAIN_TEXT:
return self.render_plain_text(config, **response_kwargs)
return super(SnippetRawView, self).render_to_response(
context, **response_kwargs
)
class SnippetHistory(TemplateView): class SnippetHistory(TemplateView):
""" """