mirror of
https://github.com/DMOJ/online-judge.git
synced 2024-11-25 16:32:37 +08:00
Use different default ace theme depending on site theme
This commit is contained in:
parent
861fcaaf26
commit
e00396fc2a
@ -76,6 +76,8 @@
|
|||||||
editor = ace.edit(div),
|
editor = ace.edit(div),
|
||||||
mode = widget.getAttribute('data-mode'),
|
mode = widget.getAttribute('data-mode'),
|
||||||
theme = widget.getAttribute('data-theme'),
|
theme = widget.getAttribute('data-theme'),
|
||||||
|
default_light_theme = widget.getAttribute('data-default-light-theme'),
|
||||||
|
default_dark_theme = widget.getAttribute('data-default-dark-theme'),
|
||||||
wordwrap = widget.getAttribute('data-wordwrap'),
|
wordwrap = widget.getAttribute('data-wordwrap'),
|
||||||
toolbar = prev(widget),
|
toolbar = prev(widget),
|
||||||
main_block = toolbar.parentNode;
|
main_block = toolbar.parentNode;
|
||||||
@ -98,6 +100,21 @@
|
|||||||
}
|
}
|
||||||
if (theme) {
|
if (theme) {
|
||||||
editor.setTheme("ace/theme/" + theme);
|
editor.setTheme("ace/theme/" + theme);
|
||||||
|
} else {
|
||||||
|
if (window.matchMedia) {
|
||||||
|
const setEditorTheme = function (is_dark) {
|
||||||
|
if (is_dark) {
|
||||||
|
editor.setTheme("ace/theme/" + default_dark_theme);
|
||||||
|
} else {
|
||||||
|
editor.setTheme("ace/theme/" + default_light_theme);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
setEditorTheme(window.matchMedia('(prefers-color-scheme: dark)').matches);
|
||||||
|
window.matchMedia('(prefers-color-scheme: dark)').addEventListener('change', function(ev) {
|
||||||
|
setEditorTheme(ev.matches);
|
||||||
|
})
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if (wordwrap == "true") {
|
if (wordwrap == "true") {
|
||||||
editor.getSession().setUseWrapMode(true);
|
editor.getSession().setUseWrapMode(true);
|
||||||
|
@ -42,6 +42,8 @@ class AceWidget(forms.Textarea):
|
|||||||
ace_attrs['data-mode'] = self.mode
|
ace_attrs['data-mode'] = self.mode
|
||||||
if self.theme:
|
if self.theme:
|
||||||
ace_attrs['data-theme'] = self.theme
|
ace_attrs['data-theme'] = self.theme
|
||||||
|
ace_attrs['data-default-light-theme'] = settings.ACE_DEFAULT_LIGHT_THEME
|
||||||
|
ace_attrs['data-default-dark-theme'] = settings.ACE_DEFAULT_DARK_THEME
|
||||||
if self.wordwrap:
|
if self.wordwrap:
|
||||||
ace_attrs['data-wordwrap'] = 'true'
|
ace_attrs['data-wordwrap'] = 'true'
|
||||||
|
|
||||||
|
@ -106,6 +106,11 @@ DMOJ_THEME_CSS = {
|
|||||||
'light': 'style.css',
|
'light': 'style.css',
|
||||||
'dark': 'dark/style.css',
|
'dark': 'dark/style.css',
|
||||||
}
|
}
|
||||||
|
# At the bare minimum, dark and light ace themes must be declared
|
||||||
|
DMOJ_THEME_DEFAULT_ACE_THEME = {
|
||||||
|
'light': 'github',
|
||||||
|
'dark': 'twilight',
|
||||||
|
}
|
||||||
DMOJ_SELECT2_THEME = 'dmoj'
|
DMOJ_SELECT2_THEME = 'dmoj'
|
||||||
|
|
||||||
MARKDOWN_STYLES = {}
|
MARKDOWN_STYLES = {}
|
||||||
@ -601,3 +606,7 @@ except IOError:
|
|||||||
|
|
||||||
# Check settings are consistent
|
# Check settings are consistent
|
||||||
assert DMOJ_PROBLEM_MIN_USER_POINTS_VOTE >= DMOJ_PROBLEM_MIN_PROBLEM_POINTS
|
assert DMOJ_PROBLEM_MIN_USER_POINTS_VOTE >= DMOJ_PROBLEM_MIN_PROBLEM_POINTS
|
||||||
|
|
||||||
|
# Compute these values after local_settings.py is loaded
|
||||||
|
ACE_DEFAULT_LIGHT_THEME = DMOJ_THEME_DEFAULT_ACE_THEME['light']
|
||||||
|
ACE_DEFAULT_DARK_THEME = DMOJ_THEME_DEFAULT_ACE_THEME['dark']
|
||||||
|
@ -308,7 +308,9 @@ class ContestAdmin(NoBatchDeleteMixin, VersionAdmin):
|
|||||||
if 'problem_label_script' in form.base_fields:
|
if 'problem_label_script' in form.base_fields:
|
||||||
# form.base_fields['problem_label_script'] does not exist when the user has only view permission
|
# form.base_fields['problem_label_script'] does not exist when the user has only view permission
|
||||||
# on the model.
|
# on the model.
|
||||||
form.base_fields['problem_label_script'].widget = AceWidget('lua', request.profile.ace_theme)
|
form.base_fields['problem_label_script'].widget = AceWidget(
|
||||||
|
mode='lua', theme=request.profile.resolved_ace_theme,
|
||||||
|
)
|
||||||
|
|
||||||
perms = ('edit_own_contest', 'edit_all_contest')
|
perms = ('edit_own_contest', 'edit_all_contest')
|
||||||
form.base_fields['curators'].queryset = Profile.objects.filter(
|
form.base_fields['curators'].queryset = Profile.objects.filter(
|
||||||
|
@ -126,5 +126,7 @@ class ProfileAdmin(NoBatchDeleteMixin, VersionAdmin):
|
|||||||
form = super(ProfileAdmin, self).get_form(request, obj, **kwargs)
|
form = super(ProfileAdmin, self).get_form(request, obj, **kwargs)
|
||||||
if 'user_script' in form.base_fields:
|
if 'user_script' in form.base_fields:
|
||||||
# form.base_fields['user_script'] does not exist when the user has only view permission on the model.
|
# form.base_fields['user_script'] does not exist when the user has only view permission on the model.
|
||||||
form.base_fields['user_script'].widget = AceWidget('javascript', request.profile.ace_theme)
|
form.base_fields['user_script'].widget = AceWidget(
|
||||||
|
mode='javascript', theme=request.profile.resolved_ace_theme,
|
||||||
|
)
|
||||||
return form
|
return form
|
||||||
|
@ -27,7 +27,9 @@ class LanguageAdmin(VersionAdmin):
|
|||||||
def get_form(self, request, obj=None, **kwargs):
|
def get_form(self, request, obj=None, **kwargs):
|
||||||
form = super(LanguageAdmin, self).get_form(request, obj, **kwargs)
|
form = super(LanguageAdmin, self).get_form(request, obj, **kwargs)
|
||||||
if obj is not None:
|
if obj is not None:
|
||||||
form.base_fields['template'].widget = AceWidget(obj.ace, request.profile.ace_theme)
|
form.base_fields['template'].widget = AceWidget(
|
||||||
|
mode=obj.ace, theme=request.profile.resolved_ace_theme,
|
||||||
|
)
|
||||||
return form
|
return form
|
||||||
|
|
||||||
|
|
||||||
|
@ -107,8 +107,9 @@ class SubmissionSourceInline(admin.StackedInline):
|
|||||||
extra = 0
|
extra = 0
|
||||||
|
|
||||||
def get_formset(self, request, obj=None, **kwargs):
|
def get_formset(self, request, obj=None, **kwargs):
|
||||||
kwargs.setdefault('widgets', {})['source'] = AceWidget(mode=obj and obj.language.ace,
|
kwargs.setdefault('widgets', {})['source'] = AceWidget(
|
||||||
theme=request.profile.ace_theme)
|
mode=obj and obj.language.ace, theme=request.profile.resolved_ace_theme,
|
||||||
|
)
|
||||||
return super().get_formset(request, obj, **kwargs)
|
return super().get_formset(request, obj, **kwargs)
|
||||||
|
|
||||||
|
|
||||||
|
@ -92,7 +92,7 @@ class ProfileForm(ModelForm):
|
|||||||
)
|
)
|
||||||
if not self.fields['organizations'].queryset:
|
if not self.fields['organizations'].queryset:
|
||||||
self.fields.pop('organizations')
|
self.fields.pop('organizations')
|
||||||
self.fields['user_script'].widget = AceWidget(theme=user.profile.ace_theme, mode='javascript')
|
self.fields['user_script'].widget = AceWidget(mode='javascript', theme=user.profile.resolved_ace_theme)
|
||||||
|
|
||||||
|
|
||||||
class DownloadDataForm(Form):
|
class DownloadDataForm(Form):
|
||||||
|
29
judge/migrations/0138_dark_ace_theme.py
Normal file
29
judge/migrations/0138_dark_ace_theme.py
Normal file
@ -0,0 +1,29 @@
|
|||||||
|
# Generated by Django 3.2.16 on 2023-02-08 01:11
|
||||||
|
|
||||||
|
from django.db import migrations, models
|
||||||
|
|
||||||
|
|
||||||
|
def github_to_auto(apps, schema_editor):
|
||||||
|
Profile = apps.get_model('judge', 'Profile')
|
||||||
|
Profile.objects.filter(ace_theme='github').update(ace_theme='auto')
|
||||||
|
|
||||||
|
|
||||||
|
def auto_to_github(apps, schema_editor):
|
||||||
|
Profile = apps.get_model('judge', 'Profile')
|
||||||
|
Profile.objects.filter(ace_theme='auto').update(ace_theme='github')
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
('judge', '0137_profile_site_theme'),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.AlterField(
|
||||||
|
model_name='profile',
|
||||||
|
name='ace_theme',
|
||||||
|
field=models.CharField(choices=[('auto', 'Follow theme default'), ('ambiance', 'Ambiance'), ('chaos', 'Chaos'), ('chrome', 'Chrome'), ('clouds', 'Clouds'), ('clouds_midnight', 'Clouds Midnight'), ('cobalt', 'Cobalt'), ('crimson_editor', 'Crimson Editor'), ('dawn', 'Dawn'), ('dreamweaver', 'Dreamweaver'), ('eclipse', 'Eclipse'), ('github', 'Github'), ('idle_fingers', 'Idle Fingers'), ('katzenmilch', 'Katzenmilch'), ('kr_theme', 'KR Theme'), ('kuroir', 'Kuroir'), ('merbivore', 'Merbivore'), ('merbivore_soft', 'Merbivore Soft'), ('mono_industrial', 'Mono Industrial'), ('monokai', 'Monokai'), ('pastel_on_dark', 'Pastel on Dark'), ('solarized_dark', 'Solarized Dark'), ('solarized_light', 'Solarized Light'), ('terminal', 'Terminal'), ('textmate', 'Textmate'), ('tomorrow', 'Tomorrow'), ('tomorrow_night', 'Tomorrow Night'), ('tomorrow_night_blue', 'Tomorrow Night Blue'), ('tomorrow_night_bright', 'Tomorrow Night Bright'), ('tomorrow_night_eighties', 'Tomorrow Night Eighties'), ('twilight', 'Twilight'), ('vibrant_ink', 'Vibrant Ink'), ('xcode', 'XCode')], default='auto', max_length=30, verbose_name='Ace theme'),
|
||||||
|
),
|
||||||
|
migrations.RunPython(github_to_auto, auto_to_github, atomic=True),
|
||||||
|
]
|
@ -21,6 +21,7 @@ TIMEZONE = make_timezones()
|
|||||||
del make_timezones
|
del make_timezones
|
||||||
|
|
||||||
ACE_THEMES = (
|
ACE_THEMES = (
|
||||||
|
('auto', _('Follow theme default')),
|
||||||
('ambiance', 'Ambiance'),
|
('ambiance', 'Ambiance'),
|
||||||
('chaos', 'Chaos'),
|
('chaos', 'Chaos'),
|
||||||
('chrome', 'Chrome'),
|
('chrome', 'Chrome'),
|
||||||
|
@ -154,7 +154,7 @@ class Profile(models.Model):
|
|||||||
points = models.FloatField(default=0, db_index=True)
|
points = models.FloatField(default=0, db_index=True)
|
||||||
performance_points = models.FloatField(default=0, db_index=True)
|
performance_points = models.FloatField(default=0, db_index=True)
|
||||||
problem_count = models.IntegerField(default=0, db_index=True)
|
problem_count = models.IntegerField(default=0, db_index=True)
|
||||||
ace_theme = models.CharField(max_length=30, verbose_name=_('Ace theme'), choices=ACE_THEMES, default='github')
|
ace_theme = models.CharField(max_length=30, verbose_name=_('Ace theme'), choices=ACE_THEMES, default='auto')
|
||||||
site_theme = models.CharField(max_length=10, verbose_name=_('site theme'), choices=SITE_THEMES, default='auto')
|
site_theme = models.CharField(max_length=10, verbose_name=_('site theme'), choices=SITE_THEMES, default='auto')
|
||||||
last_access = models.DateTimeField(verbose_name=_('last access time'), default=now)
|
last_access = models.DateTimeField(verbose_name=_('last access time'), default=now)
|
||||||
ip = models.GenericIPAddressField(verbose_name=_('last IP'), blank=True, null=True)
|
ip = models.GenericIPAddressField(verbose_name=_('last IP'), blank=True, null=True)
|
||||||
@ -226,6 +226,15 @@ class Profile(models.Model):
|
|||||||
def has_any_solves(self):
|
def has_any_solves(self):
|
||||||
return self.submission_set.filter(result='AC', case_points__gte=F('case_total')).exists()
|
return self.submission_set.filter(result='AC', case_points__gte=F('case_total')).exists()
|
||||||
|
|
||||||
|
@cached_property
|
||||||
|
def resolved_ace_theme(self):
|
||||||
|
if self.ace_theme != 'auto':
|
||||||
|
return self.ace_theme
|
||||||
|
if self.site_theme != 'auto':
|
||||||
|
return settings.DMOJ_THEME_DEFAULT_ACE_THEME.get(self.site_theme)
|
||||||
|
# This must be resolved client-side using prefers-color-scheme.
|
||||||
|
return None
|
||||||
|
|
||||||
_pp_table = [pow(settings.DMOJ_PP_STEP, i) for i in range(settings.DMOJ_PP_ENTRIES)]
|
_pp_table = [pow(settings.DMOJ_PP_STEP, i) for i in range(settings.DMOJ_PP_ENTRIES)]
|
||||||
|
|
||||||
def calculate_points(self, table=_pp_table):
|
def calculate_points(self, table=_pp_table):
|
||||||
|
@ -691,7 +691,7 @@ class ProblemSubmit(LoginRequiredMixin, ProblemMixin, TitleMixin, SingleObjectFo
|
|||||||
form_data = getattr(form, 'cleaned_data', form.initial)
|
form_data = getattr(form, 'cleaned_data', form.initial)
|
||||||
if 'language' in form_data:
|
if 'language' in form_data:
|
||||||
form.fields['source'].widget.mode = form_data['language'].ace
|
form.fields['source'].widget.mode = form_data['language'].ace
|
||||||
form.fields['source'].widget.theme = self.request.profile.ace_theme
|
form.fields['source'].widget.theme = self.request.profile.resolved_ace_theme
|
||||||
|
|
||||||
return form
|
return form
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user