Revert "Completely remove Pagedown" and "Switch all Pagedown editors to Martor"

This reverts commits:
- 2035e606f3
- ce1196f74f

Since they do not interact well with dark mode.
This commit is contained in:
Tudor Brindus 2023-12-25 12:16:07 -05:00 committed by Tudor Brindus
parent 6baf5c3149
commit c126f07fe7
34 changed files with 494 additions and 71 deletions

View File

@ -18,6 +18,9 @@ per-file-ignores =
./judge/management/commands/runmoss.py:F403,F405 ./judge/management/commands/runmoss.py:F403,F405
# E501: line too long, ignore in migrations # E501: line too long, ignore in migrations
./judge/migrations/*.py:E501 ./judge/migrations/*.py:E501
# E303: too many blank lines
# PyCharm likes to have double lines between class/def in an if statement.
./judge/widgets/pagedown.py:E303
exclude = exclude =
# belongs to the user # belongs to the user
./dmoj/local_settings.py, ./dmoj/local_settings.py,

4
.gitmodules vendored
View File

@ -1,3 +1,7 @@
[submodule "resources/pagedown"]
path = resources/pagedown
url = https://github.com/DMOJ/dmoj-pagedown.git
branch = master
[submodule "resources/libs"] [submodule "resources/libs"]
path = resources/libs path = resources/libs
url = https://github.com/DMOJ/site-assets.git url = https://github.com/DMOJ/site-assets.git

View File

@ -269,6 +269,7 @@ INSTALLED_APPS += (
'social_django', 'social_django',
'compressor', 'compressor',
'django_ace', 'django_ace',
'pagedown',
'sortedm2m', 'sortedm2m',
'statici18n', 'statici18n',
'impersonate', 'impersonate',

View File

@ -20,7 +20,7 @@ from reversion.models import Revision, Version
from judge.dblock import LockModel from judge.dblock import LockModel
from judge.models import Comment, CommentLock from judge.models import Comment, CommentLock
from judge.widgets import MartorWidget from judge.widgets import HeavyPreviewPageDownWidget
class CommentForm(ModelForm): class CommentForm(ModelForm):
@ -31,7 +31,9 @@ class CommentForm(ModelForm):
'parent': forms.HiddenInput(), 'parent': forms.HiddenInput(),
} }
widgets['body'] = MartorWidget(attrs={'data-markdownfy-url': reverse_lazy('comment_preview')}) if HeavyPreviewPageDownWidget is not None:
widgets['body'] = HeavyPreviewPageDownWidget(preview=reverse_lazy('comment_preview'),
preview_timeout=1000, hide_preview_button=True)
def __init__(self, request, *args, **kwargs): def __init__(self, request, *args, **kwargs):
self.request = request self.request = request

View File

@ -20,7 +20,7 @@ from judge.models import Contest, Language, Organization, Problem, ProblemPoints
WebAuthnCredential WebAuthnCredential
from judge.utils.mail import validate_email_domain from judge.utils.mail import validate_email_domain
from judge.utils.subscription import newsletter_id from judge.utils.subscription import newsletter_id
from judge.widgets import MartorWidget, Select2MultipleWidget, Select2Widget from judge.widgets import HeavyPreviewPageDownWidget, Select2MultipleWidget, Select2Widget
TOTP_CODE_LENGTH = 6 TOTP_CODE_LENGTH = 6
@ -63,7 +63,11 @@ class ProfileForm(ModelForm):
fields.append('math_engine') fields.append('math_engine')
widgets['math_engine'] = Select2Widget(attrs={'style': 'width:200px'}) widgets['math_engine'] = Select2Widget(attrs={'style': 'width:200px'})
widgets['about'] = MartorWidget(attrs={'data-markdownfy-url': reverse_lazy('profile_preview')}) if HeavyPreviewPageDownWidget is not None:
widgets['about'] = HeavyPreviewPageDownWidget(
preview=reverse_lazy('profile_preview'),
attrs={'style': 'max-width:700px;min-width:700px;width:700px'},
)
def clean_about(self): def clean_about(self):
if 'about' in self.changed_data and not self.instance.has_any_solves: if 'about' in self.changed_data and not self.instance.has_any_solves:
@ -169,7 +173,8 @@ class EditOrganizationForm(ModelForm):
model = Organization model = Organization
fields = ['about', 'logo_override_image', 'admins'] fields = ['about', 'logo_override_image', 'admins']
widgets = {'admins': Select2MultipleWidget(attrs={'style': 'width: 200px'})} widgets = {'admins': Select2MultipleWidget(attrs={'style': 'width: 200px'})}
widgets['about'] = MartorWidget(attrs={'data-markdownfy-url': reverse_lazy('organization_preview')}) if HeavyPreviewPageDownWidget is not None:
widgets['about'] = HeavyPreviewPageDownWidget(preview=reverse_lazy('organization_preview'))
class CustomAuthenticationForm(AuthenticationForm): class CustomAuthenticationForm(AuthenticationForm):

View File

@ -7,7 +7,6 @@ from django.forms.models import ModelForm
from django.http import Http404, HttpResponse, HttpResponseBadRequest, HttpResponseForbidden, HttpResponseNotFound, \ from django.http import Http404, HttpResponse, HttpResponseBadRequest, HttpResponseForbidden, HttpResponseNotFound, \
HttpResponseRedirect HttpResponseRedirect
from django.shortcuts import get_object_or_404 from django.shortcuts import get_object_or_404
from django.urls import reverse_lazy
from django.utils.translation import gettext as _ from django.utils.translation import gettext as _
from django.views.decorators.http import require_POST from django.views.decorators.http import require_POST
from django.views.generic import DetailView, UpdateView from django.views.generic import DetailView, UpdateView
@ -17,7 +16,7 @@ from reversion.models import Version
from judge.dblock import LockModel from judge.dblock import LockModel
from judge.models import Comment, CommentVote from judge.models import Comment, CommentVote
from judge.utils.views import TitleMixin from judge.utils.views import TitleMixin
from judge.widgets import MartorWidget from judge.widgets import MathJaxPagedownWidget
__all__ = ['upvote_comment', 'downvote_comment', 'CommentEditAjax', 'CommentContent', __all__ = ['upvote_comment', 'downvote_comment', 'CommentEditAjax', 'CommentContent',
'CommentEdit'] 'CommentEdit']
@ -123,14 +122,8 @@ class CommentEditForm(ModelForm):
class Meta: class Meta:
model = Comment model = Comment
fields = ['body'] fields = ['body']
widgets = { if MathJaxPagedownWidget is not None:
'body': MartorWidget( widgets = {'body': MathJaxPagedownWidget(attrs={'id': 'id-edit-comment-body'})}
attrs={
'id': 'id_edit',
'data-markdownfy-url': reverse_lazy('comment_preview'),
},
),
}
class CommentEditAjax(LoginRequiredMixin, CommentMixin, UpdateView): class CommentEditAjax(LoginRequiredMixin, CommentMixin, UpdateView):

View File

@ -22,9 +22,11 @@ from judge.utils.diggpaginator import DiggPaginator
from judge.utils.tickets import filter_visible_tickets, own_ticket_filter from judge.utils.tickets import filter_visible_tickets, own_ticket_filter
from judge.utils.views import SingleObjectFormView, TitleMixin, paginate_query_context from judge.utils.views import SingleObjectFormView, TitleMixin, paginate_query_context
from judge.views.problem import ProblemMixin from judge.views.problem import ProblemMixin
from judge.widgets import MartorWidget from judge.widgets import HeavyPreviewPageDownWidget
ticket_widget = MartorWidget(attrs={'data-markdownfy-url': reverse_lazy('ticket_preview')}) ticket_widget = (forms.Textarea() if HeavyPreviewPageDownWidget is None else
HeavyPreviewPageDownWidget(preview=reverse_lazy('ticket_preview'),
preview_timeout=1000, hide_preview_button=True))
class TicketForm(forms.Form): class TicketForm(forms.Form):

View File

@ -6,9 +6,9 @@ from urllib.parse import urljoin
from django.conf import settings from django.conf import settings
from django.contrib.auth.decorators import login_required from django.contrib.auth.decorators import login_required
from django.core.files.storage import default_storage from django.core.files.storage import default_storage
from django.http import HttpResponse, HttpResponseBadRequest, HttpResponseForbidden, HttpResponseNotFound, \ from django.http import HttpResponse, HttpResponseBadRequest, HttpResponseForbidden, HttpResponseRedirect
HttpResponseRedirect
from django.views.decorators.http import require_POST from django.views.decorators.http import require_POST
from martor.api import imgur_uploader
from judge.models import Submission from judge.models import Submission
@ -51,11 +51,12 @@ def django_uploader(image):
@login_required @login_required
def martor_image_uploader(request): def martor_image_uploader(request):
if not request.user.is_staff:
return HttpResponseNotFound()
if request.method != 'POST' or not request.is_ajax() or 'markdown-image-upload' not in request.FILES: if request.method != 'POST' or not request.is_ajax() or 'markdown-image-upload' not in request.FILES:
return HttpResponseBadRequest('Invalid request') return HttpResponseBadRequest('Invalid request')
image = request.FILES['markdown-image-upload'] image = request.FILES['markdown-image-upload']
data = django_uploader(image) if request.user.is_staff:
data = django_uploader(image)
else:
data = imgur_uploader(image)
return HttpResponse(data, content_type='application/json') return HttpResponse(data, content_type='application/json')

View File

@ -1,4 +1,5 @@
from judge.widgets.checkbox import CheckboxSelectMultipleWithSelectAll from judge.widgets.checkbox import CheckboxSelectMultipleWithSelectAll
from judge.widgets.martor import * from judge.widgets.martor import *
from judge.widgets.mixins import CompressorWidgetMixin from judge.widgets.mixins import CompressorWidgetMixin
from judge.widgets.pagedown import *
from judge.widgets.select2 import * from judge.widgets.select2 import *

View File

@ -12,8 +12,6 @@ class MartorWidget(OldMartorWidget):
class AdminMartorWidget(OldAdminMartorWidget): class AdminMartorWidget(OldAdminMartorWidget):
UPLOADS_ENABLED = True
class Media: class Media:
css = MartorWidget.Media.css css = MartorWidget.Media.css
js = ['admin/js/jquery.init.js', 'martor-mathjax.js'] js = ['admin/js/jquery.init.js', 'martor-mathjax.js']

67
judge/widgets/pagedown.py Normal file
View File

@ -0,0 +1,67 @@
from django.forms.utils import flatatt
from django.template.loader import get_template
from django.utils.encoding import force_str
from django.utils.html import conditional_escape
from judge.widgets.mixins import CompressorWidgetMixin
__all__ = ['PagedownWidget', 'MathJaxPagedownWidget', 'HeavyPreviewPageDownWidget']
try:
from pagedown.widgets import PagedownWidget as OldPagedownWidget
except ImportError:
PagedownWidget = None
MathJaxPagedownWidget = None
HeavyPreviewPageDownWidget = None
else:
class PagedownWidget(CompressorWidgetMixin, OldPagedownWidget):
# The goal here is to compress all the pagedown JS into one file.
# We do not want any further compress down the chain, because
# 1. we'll create multiple large JS files to download.
# 2. this is not a problem here because all the pagedown JS files will be used together.
compress_js = True
def __init__(self, *args, **kwargs):
kwargs.setdefault('css', ())
super(PagedownWidget, self).__init__(*args, **kwargs)
class MathJaxPagedownWidget(PagedownWidget):
class Media:
js = [
'mathjax_config.js',
'https://cdnjs.cloudflare.com/ajax/libs/mathjax/3.2.0/es5/tex-chtml.min.js',
'pagedown_math.js',
]
class HeavyPreviewPageDownWidget(PagedownWidget):
def __init__(self, *args, **kwargs):
kwargs.setdefault('template', 'pagedown.html')
self.preview_url = kwargs.pop('preview')
self.preview_timeout = kwargs.pop('preview_timeout', None)
self.hide_preview_button = kwargs.pop('hide_preview_button', False)
super(HeavyPreviewPageDownWidget, self).__init__(*args, **kwargs)
def render(self, name, value, attrs=None, renderer=None):
if value is None:
value = ''
final_attrs = self.build_attrs(attrs, {'name': name})
if 'class' not in final_attrs:
final_attrs['class'] = ''
final_attrs['class'] += ' wmd-input'
return get_template(self.template).render(self.get_template_context(final_attrs, value))
def get_template_context(self, attrs, value):
return {
'attrs': flatatt(attrs),
'body': conditional_escape(force_str(value)),
'id': attrs['id'],
'show_preview': self.show_preview,
'preview_url': self.preview_url,
'preview_timeout': self.preview_timeout,
'extra_classes': 'dmmd-no-button' if self.hide_preview_button else None,
}
class Media:
js = ['dmmd-preview.js']

View File

@ -1,6 +1,7 @@
Django>=3.2,<4 Django>=3.2,<4
django_compressor>=3 django_compressor>=3
django-mptt>=0.13 django-mptt>=0.13
django-pagedown<2
django-registration-redux>=2.10 django-registration-redux>=2.10
django-reversion>=3.0.5,<4 django-reversion>=3.0.5,<4
django-social-share django-social-share

View File

@ -0,0 +1,10 @@
.wmd-wrapper {
padding-right: 15px !important;
}
.wmd-preview {
margin-top: 15px;
padding: 15px;
word-break: break-word;
}

View File

@ -60,10 +60,6 @@ a {
box-sizing: border-box; box-sizing: border-box;
} }
.comment-edit-form {
min-width: 60em;
}
.comment-post-wrapper { .comment-post-wrapper {
padding-bottom: 5px; padding-bottom: 5px;

99
resources/dmmd-preview.js Normal file
View File

@ -0,0 +1,99 @@
$(function () {
window.register_dmmd_preview = function ($preview) {
var $form = $preview.parents('form').first();
var $update = $preview.find('.dmmd-preview-update');
var $content = $preview.find('.dmmd-preview-content');
var preview_url = $preview.attr('data-preview-url');
var $textarea = $('#' + $preview.attr('data-textarea-id'));
// Submit the form if Ctrl+Enter is pressed in pagedown textarea.
$textarea.keydown(function (ev) {
// Ctrl+Enter pressed (metaKey used to support command key on mac).
if ((ev.metaKey || ev.ctrlKey) && ev.which == 13) {
$form.submit();
}
});
$update.click(function () {
var text = $textarea.val();
if (text) {
$preview.addClass('dmmd-preview-stale');
$.post(preview_url, {
content: text,
csrfmiddlewaretoken: $.cookie('csrftoken')
}, function (result) {
$content.html(result);
$preview.addClass('dmmd-preview-has-content').removeClass('dmmd-preview-stale');
var $jax = $content.find('.require-mathjax-support');
if ($jax.length) {
if (!('MathJax' in window)) {
$.ajax({
type: 'GET',
url: $jax.attr('data-config'),
dataType: 'script',
cache: true,
success: function () {
$.ajax({
type: 'GET',
url: 'https://cdnjs.cloudflare.com/ajax/libs/mathjax/3.2.0/es5/tex-chtml.min.js',
dataType: 'script',
cache: true,
success: function () {
MathJax.typesetPromise([$content[0]]).then(function () {
$content.find('.tex-image').hide();
$content.find('.tex-text').show();
});
}
});
}
});
} else {
MathJax.typesetPromise([$content[0]]).then(function () {
$content.find('.tex-image').hide();
$content.find('.tex-text').show();
});
}
}
});
} else {
$content.empty();
$preview.removeClass('dmmd-preview-has-content').removeClass('dmmd-preview-stale');
}
}).click();
var timeout = $preview.attr('data-timeout');
var last_event = null;
var last_text = $textarea.val();
if (timeout) {
$textarea.on('keyup paste', function () {
var text = $textarea.val();
if (last_text == text) return;
last_text = text;
$preview.addClass('dmmd-preview-stale');
if (last_event)
clearTimeout(last_event);
last_event = setTimeout(function () {
$update.click();
last_event = null;
}, timeout);
});
}
};
$('.dmmd-preview').each(function () {
register_dmmd_preview($(this));
});
if ('django' in window && 'jQuery' in window.django)
django.jQuery(document).on('formset:added', function(event, $row) {
var $preview = $row.find('.dmmd-preview');
if ($preview.length) {
var id = $row.attr('id');
id = id.substr(id.lastIndexOf('-') + 1);
$preview.attr('data-textarea-id', $preview.attr('data-textarea-id').replace('__prefix__', id));
register_dmmd_preview($preview);
}
});
});

View File

@ -0,0 +1,43 @@
@import "vars";
div.dmmd-preview {
padding: 0;
}
div.dmmd-preview-update {
background: $color_primary25;
color: $color_primary75;
text-align: center;
cursor: pointer;
border-radius: 4px;
height: 2em;
line-height: 2em;
}
div.dmmd-preview-content {
padding: 0 7px;
}
div.dmmd-preview.dmmd-preview-has-content div.dmmd-preview-update {
border-radius: 4px 4px 0 0;
}
div.dmmd-preview-has-content div.dmmd-preview-content {
padding-bottom: 7px;
}
div.dmmd-no-button div.dmmd-preview-update {
display: none;
}
div.dmmd-no-button div.dmmd-preview-content {
padding-bottom: 0;
}
div.dmmd-no-button:not(.dmmd-preview-has-content) {
display: none;
}
div.dmmd-preview-stale {
background: repeating-linear-gradient(-45deg, $color_primary0, $color_primary0 10px, $color_primary5 10px, $color_primary5 20px);
}

View File

@ -2,8 +2,6 @@
form .martor-preview { form .martor-preview {
@include content-description; @include content-description;
min-height: 400px;
ul li { ul li {
list-style: unset !important; list-style: unset !important;
@ -23,7 +21,7 @@ form .martor-preview {
} }
.section-martor { .section-martor {
div[data-tab^="editor-tab-"] { div[data-tab="editor-tab-description"] {
padding: 0; padding: 0;
} }
@ -35,12 +33,6 @@ form .martor-preview {
font-size: 0.8rem; font-size: 0.8rem;
} }
.martor-toolbar {
flex: 0 1 auto !important;
overflow-x: auto;
overflow-y: hidden;
}
.martor-field { .martor-field {
height: 400px; height: 400px;
} }

View File

@ -35,7 +35,7 @@
} }
.centered-form { .centered-form {
max-width: 800px; max-width: 700px;
margin: auto; margin: auto;
.submit-bar { .submit-bar {

1
resources/pagedown Submodule

@ -0,0 +1 @@
Subproject commit 6e5eac43883a314d1e0dbc5e70069798859eacbc

View File

@ -0,0 +1,125 @@
@import "vars";
.wmd-panel {
margin: 0;
width: 100%;
min-width: 0;
}
.wmd-button-bar {
width: 100%;
background-color: Silver;
}
.wmd-input {
height: 300px;
width: 100%;
max-width: 100%;
background: $color_primary0;
border: 1px solid $color_primary50;
font-family: Consolas, "Liberation Mono", Monaco, "Courier New", monospace !important;
}
.wmd-preview {
background: none;
word-break: break-word;
}
.wmd-button-row {
margin: 5px;
padding: 0;
line-height: 0;
}
.wmd-spacer {
width: 15px;
height: 20px;
display: inline-block;
list-style: none;
}
.wmd-button {
width: 20px;
height: 20px;
padding-left: 2px;
padding-right: 3px;
display: inline-block;
list-style: none;
cursor: pointer;
}
.wmd-button > span {
@include vars-img;
background: url($path_to_root + '/pagedown/wmd-buttons.png') no-repeat 0 0;
width: 20px;
height: 20px;
display: inline-block;
}
.wmd-prompt-background {
background-color: Black;
}
.wmd-prompt-dialog {
border: 1px solid $color_primary25;
background-color: $color_primary5;
}
.wmd-prompt-dialog > div {
font-size: 0.8em;
font-family: arial, helvetica, sans-serif;
}
.wmd-prompt-dialog > form > input[type="text"] {
border: 1px solid $color_primary25;
color: $color_primary100;
}
.wmd-prompt-dialog > form > input[type="button"] {
border: 1px solid $color_primary50;
font-family: trebuchet MS, helvetica, sans-serif;
font-size: 0.8em;
font-weight: bold;
}
.wmd-wrapper {
padding-right: 0 !important;
}
.wmd-preview {
margin-top: 15px;
padding: 7px;
background: $color_primary0;
line-height: 1.5em;
font-size: 1em;
border: 1px solid $color_primary50;
border-radius: 5px;
box-sizing: border-box;
}
.wmd-preview:empty {
display: none;
}
.wmd-preview h1, .wmd-preview h2, .wmd-preview h3, .wmd-preview h4, .wmd-preview h5, .wmd-preview h6 {
font-weight: bold !important;
margin-left: 0 !important;
}
.wmd-preview:not(.dmmd-preview) h1 {
font-size: 1.6em !important;
margin: 0 !important;
padding: 0 !important;
}
.wmd-preview:not(.dmmd-preview) h2 {
font-size: 1.4em !important
}
.wmd-preview:not(.dmmd-preview) h3 {
font-size: 1em !important
}
.wmd-preview:not(.dmmd-preview) h4, .wmd-preview:not(.dmmd-preview) h5, .wmd-preview:not(.dmmd-preview) h6 {
font-size: .9em !important
}

View File

@ -0,0 +1,19 @@
function mathjax_pagedown($) {
if ('MathJax' in window) {
$.each(window.editors, function (id, editor) {
var preview = $('div.wmd-preview#' + id + '_wmd_preview')[0];
if (preview) {
editor.hooks.chain('onPreviewRefresh', function () {
MathJax.typeset([preview]);
});
MathJax.typeset([preview]);
}
});
}
}
window.mathjax_pagedown = mathjax_pagedown;
$(window).on('load', function () {
(mathjax_pagedown)('$' in window ? $ : django.jQuery);
});

View File

@ -14,6 +14,8 @@
@import "widgets"; @import "widgets";
@import "featherlight"; @import "featherlight";
@import "comments"; @import "comments";
@import "pagedown-widget";
@import "dmmd-preview";
@import "submission"; @import "submission";
@import "contest"; @import "contest";
@import "misc"; @import "misc";

View File

@ -3,7 +3,7 @@
form#ticket-form { form#ticket-form {
display: block; display: block;
margin: 0 auto; margin: 0 auto;
max-width: 800px; max-width: 750px;
padding-top: 1em; padding-top: 1em;
#id_title { #id_title {
@ -72,7 +72,7 @@ div.ticket-title {
display: flex; display: flex;
flex-direction: row; flex-direction: row;
flex-wrap: wrap-reverse; flex-wrap: wrap-reverse;
max-width: 1200px; max-width: 1000px;
} }
.ticket-sidebar { .ticket-sidebar {

View File

@ -6,6 +6,18 @@
line-height: unset !important; line-height: unset !important;
} }
.wmd-wrapper {
padding-top: 2em;
}
.wmd-wrapper ul.wmd-button-row {
margin-left: 0;
}
.wmd-input {
width: 100% !important;
}
#content .content-description h1, #content .content-description h1,
#content .content-description h2, #content .content-description h2,
#content .content-description h3, #content .content-description h3,
@ -53,3 +65,8 @@ select#id_tags.django-select2 {
max-width: unset; max-width: unset;
} }
} }
.dmmd-preview-update {
position: sticky;
top: 38px;
}

View File

@ -48,4 +48,5 @@
{% if REQUIRE_JAX %} {% if REQUIRE_JAX %}
{% include "mathjax-load.html" %} {% include "mathjax-load.html" %}
{% endif %} {% endif %}
{% include "comments/math.html" %}
{% endblock %} {% endblock %}

View File

@ -1,4 +1,4 @@
<div class="comment-submit comment-edit-form"> <div class="comment-submit">
<form id="comment-edit" action="{{ request.get_full_path() }}" method="post"> <form id="comment-edit" action="{{ request.get_full_path() }}" method="post">
<span style="display: none" class="comment-id">{{ comment.id }}</span> <span style="display: none" class="comment-id">{{ comment.id }}</span>
<span style="display: none" class="read-back">{{ url('comment_content', comment.id) }}</span> <span style="display: none" class="read-back">{{ url('comment_content', comment.id) }}</span>

View File

@ -0,0 +1,3 @@
{% compress js, inline %}
<script src="{{ static('pagedown_math.js') }}"></script>
{% endcompress %}

View File

@ -2,40 +2,25 @@
{% compress js %} {% compress js %}
{{ comment_form.media.js }} {{ comment_form.media.js }}
<script type="text/javascript"> <script type="text/javascript">
function rename_martor_widget(widget, old_name, new_name) {
function rename_data(data_name, prefix) {
widget.find('[data-' + data_name + '=' + prefix + old_name + ']')
.data(data_name, prefix + new_name)
.attr('data-' + data_name, prefix + new_name);
}
function rename_id(prefix) {
widget.find('#' + prefix + old_name).prop('id', prefix + new_name);
}
function rename_class(prefix) {
widget.find('.' + prefix + old_name).removeClass(prefix + old_name).addClass(prefix + new_name);
}
rename_data('tab', 'editor-tab-');
rename_data('tab', 'preview-tab-');
rename_data('field-name', '');
rename_id('id_');
rename_id('martor-');
rename_class('martor-field-');
rename_class('main-martor-');
widget.find('.main-martor').martor();
}
$(document).ready(function () { $(document).ready(function () {
window.reply_comment = function (parent) { window.reply_comment = function (parent) {
var $comment_reply = $('#comment-' + parent + '-reply'); var $comment_reply = $('#comment-' + parent + '-reply');
var reply_id = 'reply-' + parent; var reply_id = 'reply-' + parent;
var new_id = 'id' + parent + '_body';
if ($comment_reply.find('#' + reply_id).length == 0) { if ($comment_reply.find('#' + reply_id).length == 0) {
var $reply_form = $('#new-comment').clone(false).prop('id', reply_id); var $reply_form = $('#new-comment').clone(true).prop('id', reply_id);
$reply_form.find('h3').html('{{ _('Replying to comment') }}'); $reply_form.find('h3').html('{{ _('Replying to comment') }}');
$reply_form.prepend('<a class="close">x</a>'); $reply_form.prepend('<a class="close">x</a>');
$reply_form.appendTo($comment_reply);
$reply_form.find('form.comment-submit-form input#id_parent').val(parent); $reply_form.find('form.comment-submit-form input#id_parent').val(parent);
rename_martor_widget($reply_form, 'body', reply_id); $reply_form.find('div#id_body-wmd-wrapper').prop('id', new_id + '-wmd-wrapper');
ace.edit('martor-' + reply_id).setValue(''); $reply_form.find('div#id_body_wmd_button_bar').empty().prop('id', new_id + '_wmd_button_bar');
$reply_form.find('textarea.wmd-input').val('').prop('id', new_id);
$reply_form.find('div#id_body-preview').attr('data-textarea-id', new_id).prop('id', new_id + '-preview');
$reply_form.appendTo($comment_reply);
register_dmmd_preview($reply_form.find('div#' + new_id + '-preview'));
if ('DjangoPagedown' in window) {
window.DjangoPagedown.createEditor($reply_form.find('textarea.wmd-input').get(0));
}
} }
$comment_reply.fadeIn(); $comment_reply.fadeIn();
@ -163,8 +148,19 @@
$comments.find('a.edit-link').featherlight({ $comments.find('a.edit-link').featherlight({
afterOpen: function () { afterOpen: function () {
var $widget = $('.featherlight #comment-form-body'); if ('DjangoPagedown' in window) {
rename_martor_widget($widget, 'body', 'edit'); var $wmd = $('.featherlight .wmd-input');
if ($wmd.length) {
window.DjangoPagedown.createEditor($wmd.get(0));
if ('MathJax' in window) {
var preview = $('.featherlight div.wmd-preview')[0];
window.editors[$wmd.attr('id')].hooks.chain('onPreviewRefresh', function () {
MathJax.typesetPromise([preview]);
});
MathJax.typesetPromise([preview]);
}
}
}
$('#comment-edit').submit(function (event) { $('#comment-edit').submit(function (event) {
event.preventDefault(); event.preventDefault();
var id = $('#comment-edit').find('.comment-id').text(); var id = $('#comment-edit').find('.comment-id').text();
@ -190,6 +186,14 @@
}); });
}); });
}, },
beforeClose: function () {
if ('DjangoPagedown' in window) {
var $wmd = $('.featherlight .wmd-input');
if ($wmd.length) {
window.DjangoPagedown.destroyEditor($wmd.get(0));
}
}
},
variant: 'featherlight-edit' variant: 'featherlight-edit'
}); });

View File

@ -244,3 +244,8 @@
{% endblock %} {% endblock %}
{% block description_end %}{% endblock %} {% block description_end %}{% endblock %}
{% block bodyend %}
{{ super() }}
{% include "comments/math.html" %}
{% endblock %}

14
templates/pagedown.html Normal file
View File

@ -0,0 +1,14 @@
<div id="{{ id|safe }}-wmd-wrapper" class="wmd-wrapper">
<div class="wmd-panel">
<div id="{{ id|safe }}_wmd_button_bar"></div>
<textarea{{ attrs|safe }}>{{ body }}</textarea>
</div>
{% if show_preview %}
<div id="{{ id|safe }}-preview" data-preview-url="{{ preview_url }}" data-textarea-id="{{ id }}"
data-timeout="{{ preview_timeout or '' }}" class="wmd-panel wmd-preview dmmd-preview {{ extra_classes }}">
<div class="dmmd-preview-update"><i class="fa fa-refresh"></i> {{ _('Update preview') }}</div>
<div class="dmmd-preview-content content-description"></div>
</div>
{% endif %}
</div>

View File

@ -0,0 +1,9 @@
<div class="wmd-wrapper" id="{{ id }}-wmd-wrapper">
<div class="wmd-panel">
<div id="{{ id|safe }}_wmd_button_bar"></div>
<textarea{{ attrs|safe }}>{{ body }}</textarea>
</div>
{% if show_preview %}
<div id="{{ id|safe }}_wmd_preview" class="wmd-panel wmd-preview content-description"></div>
{% endif %}
</div>

View File

@ -46,4 +46,5 @@
{% if REQUIRE_JAX %} {% if REQUIRE_JAX %}
{% include "mathjax-load.html" %} {% include "mathjax-load.html" %}
{% endif %} {% endif %}
{% include "comments/math.html" %}
{% endblock %} {% endblock %}

View File

@ -346,3 +346,8 @@
{% include "comments/list.html" %} {% include "comments/list.html" %}
{% endif %} {% endif %}
{% endblock %} {% endblock %}
{% block bodyend %}
{{ super() }}
{% include "comments/math.html" %}
{% endblock %}

View File

@ -42,8 +42,7 @@
#edit-form { #edit-form {
border: unset; border: unset;
background: unset; background: unset;
display: block; max-width: 700px;
padding-bottom: 30px;
} }
.settings { .settings {