mirror of
https://github.com/DarrenOfficial/dpaste.git
synced 2024-11-15 08:02:54 +11:00
Right-To-Left Support
This commit is contained in:
parent
3bfb153b74
commit
0f5fbd28f4
10 changed files with 99 additions and 17 deletions
|
@ -46,6 +46,26 @@ if (wordwrapCheckbox && snippetDiv) {
|
|||
wordwrapCheckbox.onchange = toggleWordwrap;
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// Right-To-Left
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
const rtlCheckbox = document.getElementById('id_rtl');
|
||||
const snippetArea = document.getElementById('id_content');
|
||||
|
||||
function toggleRTL() {
|
||||
if (rtlCheckbox.checked) {
|
||||
snippetArea.dir = 'rtl';
|
||||
} else {
|
||||
snippetArea.dir = '';
|
||||
}
|
||||
}
|
||||
|
||||
if (rtlCheckbox && snippetArea) {
|
||||
toggleRTL();
|
||||
rtlCheckbox.onchange = toggleRTL;
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// Line Highlighting
|
||||
// -----------------------------------------------------------------------------
|
||||
|
|
|
@ -8,7 +8,14 @@
|
|||
.snippet-form {
|
||||
background-color: $bgColor;
|
||||
|
||||
label { display: none; }
|
||||
label {
|
||||
display: none;
|
||||
font-size: 13px;
|
||||
}
|
||||
|
||||
.options-rtl label {
|
||||
display: inline;
|
||||
}
|
||||
|
||||
select {
|
||||
-moz-appearance: none;
|
||||
|
|
|
@ -20,24 +20,37 @@ def get_expire_values(expires):
|
|||
else:
|
||||
expire_type = Snippet.EXPIRE_TIME
|
||||
expires = expires and expires or config.EXPIRE_DEFAULT
|
||||
expires = datetime.datetime.now() + datetime.timedelta(seconds=int(expires))
|
||||
expires = datetime.datetime.now() + datetime.timedelta(
|
||||
seconds=int(expires)
|
||||
)
|
||||
return expires, expire_type
|
||||
|
||||
|
||||
class SnippetForm(forms.ModelForm):
|
||||
content = forms.CharField(
|
||||
label=_('Content'),
|
||||
widget=forms.Textarea(attrs={'placeholder': _('Awesome code goes here...')}),
|
||||
widget=forms.Textarea(
|
||||
attrs={'placeholder': _('Awesome code goes here...')}
|
||||
),
|
||||
max_length=config.MAX_CONTENT_LENGTH,
|
||||
strip=False,
|
||||
)
|
||||
|
||||
lexer = forms.ChoiceField(
|
||||
label=_('Lexer'), initial=LEXER_DEFAULT, choices=LEXER_CHOICES
|
||||
label=_('Lexer'),
|
||||
initial=LEXER_DEFAULT,
|
||||
choices=LEXER_CHOICES
|
||||
)
|
||||
|
||||
expires = forms.ChoiceField(
|
||||
label=_('Expires'), choices=config.EXPIRE_CHOICES, initial=config.EXPIRE_DEFAULT
|
||||
label=_('Expires'),
|
||||
choices=config.EXPIRE_CHOICES,
|
||||
initial=config.EXPIRE_DEFAULT,
|
||||
)
|
||||
|
||||
rtl = forms.BooleanField(
|
||||
label=_('Right to Left'),
|
||||
required=False
|
||||
)
|
||||
|
||||
# Honeypot field
|
||||
|
@ -49,7 +62,7 @@ class SnippetForm(forms.ModelForm):
|
|||
|
||||
class Meta:
|
||||
model = Snippet
|
||||
fields = ('content', 'lexer')
|
||||
fields = ('content', 'lexer', 'rtl')
|
||||
|
||||
def __init__(self, request, *args, **kwargs):
|
||||
super(SnippetForm, self).__init__(*args, **kwargs)
|
||||
|
|
|
@ -34,13 +34,14 @@ class Highlighter(object):
|
|||
return l[1]
|
||||
return fallback
|
||||
|
||||
def render(self, code_string, lexer_name, **kwargs):
|
||||
def render(self, code_string, lexer_name, direction=None, **kwargs):
|
||||
highlighted_string = self.highlight(code_string, lexer_name=lexer_name)
|
||||
context = {
|
||||
'highlighted': highlighted_string,
|
||||
'highlighted_splitted': highlighted_string.splitlines(),
|
||||
'lexer_name': lexer_name,
|
||||
'lexer_display_name': self.get_lexer_display_name(lexer_name),
|
||||
'direction': direction,
|
||||
}
|
||||
context.update(kwargs)
|
||||
return render_to_string(self.template_name, context)
|
||||
|
@ -76,7 +77,9 @@ class MarkdownHighlighter(PlainTextHighlighter):
|
|||
|
||||
return mark_safe(
|
||||
misaka.html(
|
||||
code_string, extensions=self.extensions, render_flags=self.render_flags
|
||||
code_string,
|
||||
extensions=self.extensions,
|
||||
render_flags=self.render_flags
|
||||
)
|
||||
)
|
||||
|
||||
|
|
18
dpaste/migrations/0007_snippet_rtl.py
Normal file
18
dpaste/migrations/0007_snippet_rtl.py
Normal file
|
@ -0,0 +1,18 @@
|
|||
# Generated by Django 2.1.1 on 2018-12-19 13:39
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('dpaste', '0006_auto_20180622_1051'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AddField(
|
||||
model_name='snippet',
|
||||
name='rtl',
|
||||
field=models.BooleanField(default=False, verbose_name='Right-to-left'),
|
||||
),
|
||||
]
|
|
@ -22,7 +22,10 @@ def generate_secret_id(length):
|
|||
)
|
||||
|
||||
secret_id = ''.join(
|
||||
[R.choice(config.SLUG_CHOICES) for i in range(length or config.SLUG_LENGTH)]
|
||||
[
|
||||
R.choice(config.SLUG_CHOICES)
|
||||
for i in range(length or config.SLUG_LENGTH)
|
||||
]
|
||||
)
|
||||
|
||||
# Check if this slug already exists, if not, return this new slug
|
||||
|
@ -51,13 +54,16 @@ class Snippet(models.Model):
|
|||
_('Secret ID'), max_length=255, blank=True, null=True, unique=True
|
||||
)
|
||||
content = models.TextField(_('Content'))
|
||||
lexer = models.CharField(_('Lexer'), max_length=30, default=highlight.LEXER_DEFAULT)
|
||||
lexer = models.CharField(
|
||||
_('Lexer'), max_length=30, default=highlight.LEXER_DEFAULT
|
||||
)
|
||||
published = models.DateTimeField(_('Published'), auto_now_add=True)
|
||||
expire_type = models.PositiveSmallIntegerField(
|
||||
_('Expire Type'), choices=EXPIRE_CHOICES, default=EXPIRE_CHOICES[0][0]
|
||||
)
|
||||
expires = models.DateTimeField(_('Expires'), blank=True, null=True)
|
||||
view_count = models.PositiveIntegerField(_('View count'), default=0)
|
||||
rtl = models.BooleanField(_('Right-to-left'), default=False)
|
||||
parent = models.ForeignKey(
|
||||
'self',
|
||||
null=True,
|
||||
|
@ -80,11 +86,17 @@ class Snippet(models.Model):
|
|||
super(Snippet, self).save(*args, **kwargs)
|
||||
|
||||
def get_absolute_url(self):
|
||||
return reverse('snippet_details', kwargs={'snippet_id': self.secret_id})
|
||||
return reverse(
|
||||
'snippet_details', kwargs={'snippet_id': self.secret_id}
|
||||
)
|
||||
|
||||
def highlight(self):
|
||||
HighlighterClass = highlight.get_highlighter_class(self.lexer)
|
||||
return HighlighterClass().render(self.content, self.lexer)
|
||||
return HighlighterClass().render(
|
||||
code_string=self.content,
|
||||
lexer_name=self.lexer,
|
||||
direction='rtl' if self.rtl else 'ltr',
|
||||
)
|
||||
|
||||
@property
|
||||
def lexer_name(self):
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
<div class="snippet-text">
|
||||
<article>
|
||||
<article dir="{{ direction }}">
|
||||
<div>{{ highlighted }}</div>
|
||||
</article>
|
||||
</div>
|
|
@ -18,6 +18,14 @@
|
|||
{{ form.expires }}
|
||||
</p>
|
||||
|
||||
<p class="options-rtl">
|
||||
{{ form.rtl }}
|
||||
<label for="{{ form.rtl.auto_id }}">
|
||||
{% trans "Right-to-Left" %}
|
||||
<small>[beta]</small>
|
||||
</label>
|
||||
</p>
|
||||
|
||||
<p class="action">
|
||||
<button class="btn" type="submit">
|
||||
{% trans "Paste Snippet" %}
|
||||
|
|
|
@ -39,7 +39,6 @@ class SnippetView(FormView):
|
|||
"""
|
||||
Create a new snippet.
|
||||
"""
|
||||
|
||||
form_class = SnippetForm
|
||||
template_name = 'dpaste/new.html'
|
||||
|
||||
|
@ -100,7 +99,11 @@ class SnippetDetailView(SnippetView, DetailView):
|
|||
|
||||
def get_initial(self):
|
||||
snippet = self.get_object()
|
||||
return {'content': snippet.content, 'lexer': snippet.lexer}
|
||||
return {
|
||||
'content': snippet.content,
|
||||
'lexer': snippet.lexer,
|
||||
'rtl': snippet.rtl,
|
||||
}
|
||||
|
||||
def form_valid(self, form):
|
||||
snippet = form.save(parent=self.get_object())
|
||||
|
|
|
@ -7,11 +7,9 @@
|
|||
"postinstall": "npm run build",
|
||||
"start": "npm run build && pipenv run ./manage.py runserver",
|
||||
"docs": "pipenv run sphinx-build -c docs docs docs/_build/html",
|
||||
|
||||
"build-css": "node-sass --output-style compressed -o build client/scss/dpaste.scss ",
|
||||
"build-js": "uglifyjs --compress=\"drop_console=true,ecma=6\" --mangle=\"toplevel\" --output=build/dpaste.js client/js/dpaste.js",
|
||||
"build": "npm run build-css && npm run build-js",
|
||||
|
||||
"watch-css": "npm run build && node-sass --source-map true -o build/ --watch client/scss/dpaste.scss",
|
||||
"watch-docs": "pipenv run sphinx-autobuild -c docs docs docs/_build/html"
|
||||
},
|
||||
|
|
Loading…
Reference in a new issue