kopia lustrzana https://github.com/wagtail/wagtail
Fix merge conflict remnants
rodzic
a30d3e87fd
commit
8dd8f59a72
|
@ -1,3 +1,3 @@
|
|||
<symbol id="clipboard-list" viewBox="0 0 384 512">
|
||||
<path d="M336 64h-80c0-35.3-28.7-64-64-64s-64 28.7-64 64H48C21.5 64 0 85.5 0 112v352c0 26.5 21.5 48 48 48h288c26.5 0 48-21.5 48-48V112c0-26.5-21.5-48-48-48zM96 424c-13.3 0-24-10.7-24-24s10.7-24 24-24 24 10.7 24 24-10.7 24-24 24zm0-96c-13.3 0-24-10.7-24-24s10.7-24 24-24 24 10.7 24 24-10.7 24-24 24zm0-96c-13.3 0-24-10.7-24-24s10.7-24 24-24 24 10.7 24 24-10.7 24-24 24zm96-192c13.3 0 24 10.7 24 24s-10.7 24-24 24-24-10.7-24-24 10.7-24 24-24zm128 368c0 4.4-3.6 8-8 8H168c-4.4 0-8-3.6-8-8v-16c0-4.4 3.6-8 8-8h144c4.4 0 8 3.6 8 8v16zm0-96c0 4.4-3.6 8-8 8H168c-4.4 0-8-3.6-8-8v-16c0-4.4 3.6-8 8-8h144c4.4 0 8 3.6 8 8v16zm0-96c0 4.4-3.6 8-8 8H168c-4.4 0-8-3.6-8-8v-16c0-4.4 3.6-8 8-8h144c4.4 0 8 3.6 8 8v16z"></path>
|
||||
</svg>
|
||||
</symbol>
|
||||
|
|
|
@ -1,397 +0,0 @@
|
|||
import json
|
||||
import warnings
|
||||
from functools import total_ordering
|
||||
|
||||
from django import forms
|
||||
from django.conf import settings
|
||||
from django.forms import widgets
|
||||
from django.forms.utils import flatatt
|
||||
from django.template.loader import render_to_string
|
||||
from django.urls import reverse
|
||||
from django.utils.formats import get_format
|
||||
from django.utils.functional import cached_property
|
||||
from django.utils.html import format_html
|
||||
from django.utils.translation import gettext_lazy as _
|
||||
from taggit.forms import TagWidget
|
||||
from taggit.models import Tag
|
||||
|
||||
from wagtail.admin.datetimepicker import to_datetimepicker_format
|
||||
from wagtail.admin.staticfiles import versioned_static
|
||||
from wagtail.core import hooks
|
||||
from wagtail.core.models import Page
|
||||
from wagtail.core.utils import accepts_kwarg
|
||||
from wagtail.utils.deprecation import RemovedInWagtail212Warning
|
||||
from wagtail.utils.widgets import WidgetWithScript
|
||||
|
||||
DEFAULT_DATE_FORMAT = '%Y-%m-%d'
|
||||
DEFAULT_DATETIME_FORMAT = '%Y-%m-%d %H:%M'
|
||||
DEFAULT_TIME_FORMAT = '%H:%M'
|
||||
|
||||
|
||||
class AdminAutoHeightTextInput(widgets.Textarea):
|
||||
template_name = 'wagtailadmin/widgets/auto_height_text_input.html'
|
||||
|
||||
def __init__(self, attrs=None):
|
||||
# Use more appropriate rows default, given autoheight will alter this anyway
|
||||
default_attrs = {'rows': '1'}
|
||||
if attrs:
|
||||
default_attrs.update(attrs)
|
||||
|
||||
super().__init__(default_attrs)
|
||||
|
||||
|
||||
class AdminDateInput(widgets.DateInput):
|
||||
template_name = 'wagtailadmin/widgets/date_input.html'
|
||||
|
||||
def __init__(self, attrs=None, format=None):
|
||||
default_attrs = {'autocomplete': 'off'}
|
||||
fmt = format
|
||||
if attrs:
|
||||
default_attrs.update(attrs)
|
||||
if fmt is None:
|
||||
fmt = getattr(settings, 'WAGTAIL_DATE_FORMAT', DEFAULT_DATE_FORMAT)
|
||||
self.js_format = to_datetimepicker_format(fmt)
|
||||
super().__init__(attrs=default_attrs, format=fmt)
|
||||
|
||||
def get_context(self, name, value, attrs):
|
||||
context = super().get_context(name, value, attrs)
|
||||
|
||||
config = {
|
||||
'dayOfWeekStart': get_format('FIRST_DAY_OF_WEEK'),
|
||||
'format': self.js_format,
|
||||
}
|
||||
context['widget']['config_json'] = json.dumps(config)
|
||||
|
||||
return context
|
||||
|
||||
@property
|
||||
def media(self):
|
||||
return forms.Media(js=[
|
||||
versioned_static('wagtailadmin/js/date-time-chooser.js'),
|
||||
])
|
||||
|
||||
|
||||
class AdminTimeInput(widgets.TimeInput):
|
||||
template_name = 'wagtailadmin/widgets/time_input.html'
|
||||
|
||||
def __init__(self, attrs=None, format=None):
|
||||
default_attrs = {'autocomplete': 'off'}
|
||||
if attrs:
|
||||
default_attrs.update(attrs)
|
||||
fmt = format
|
||||
if fmt is None:
|
||||
fmt = getattr(settings, 'WAGTAIL_TIME_FORMAT', DEFAULT_TIME_FORMAT)
|
||||
self.js_format = to_datetimepicker_format(fmt)
|
||||
super().__init__(attrs=default_attrs, format=fmt)
|
||||
|
||||
def get_context(self, name, value, attrs):
|
||||
context = super().get_context(name, value, attrs)
|
||||
|
||||
config = {
|
||||
'format': self.js_format,
|
||||
'formatTime': self.js_format
|
||||
}
|
||||
context['widget']['config_json'] = json.dumps(config)
|
||||
|
||||
return context
|
||||
|
||||
@property
|
||||
def media(self):
|
||||
return forms.Media(js=[
|
||||
versioned_static('wagtailadmin/js/date-time-chooser.js'),
|
||||
])
|
||||
|
||||
|
||||
class AdminDateTimeInput(widgets.DateTimeInput):
|
||||
template_name = 'wagtailadmin/widgets/datetime_input.html'
|
||||
|
||||
def __init__(self, attrs=None, format=None, time_format=None):
|
||||
default_attrs = {'autocomplete': 'off'}
|
||||
fmt = format
|
||||
if attrs:
|
||||
default_attrs.update(attrs)
|
||||
if fmt is None:
|
||||
fmt = getattr(settings, 'WAGTAIL_DATETIME_FORMAT', DEFAULT_DATETIME_FORMAT)
|
||||
time_fmt = time_format
|
||||
if time_fmt is None:
|
||||
time_fmt = getattr(settings, 'WAGTAIL_TIME_FORMAT', DEFAULT_TIME_FORMAT)
|
||||
self.js_format = to_datetimepicker_format(fmt)
|
||||
self.js_time_format = to_datetimepicker_format(time_fmt)
|
||||
super().__init__(attrs=default_attrs, format=fmt)
|
||||
|
||||
def get_context(self, name, value, attrs):
|
||||
context = super().get_context(name, value, attrs)
|
||||
|
||||
config = {
|
||||
'dayOfWeekStart': get_format('FIRST_DAY_OF_WEEK'),
|
||||
'format': self.js_format,
|
||||
'formatTime': self.js_time_format
|
||||
}
|
||||
context['widget']['config_json'] = json.dumps(config)
|
||||
|
||||
return context
|
||||
|
||||
@property
|
||||
def media(self):
|
||||
return forms.Media(js=[
|
||||
versioned_static('wagtailadmin/js/date-time-chooser.js'),
|
||||
])
|
||||
|
||||
|
||||
class AdminTagWidget(TagWidget):
|
||||
template_name = 'wagtailadmin/widgets/tag_widget.html'
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
self.tag_model = kwargs.pop('tag_model', Tag)
|
||||
# free_tagging = None means defer to the tag model's setting
|
||||
self.free_tagging = kwargs.pop('free_tagging', None)
|
||||
super().__init__(*args, **kwargs)
|
||||
|
||||
def get_context(self, name, value, attrs):
|
||||
context = super().get_context(name, value, attrs)
|
||||
|
||||
if self.tag_model == Tag:
|
||||
autocomplete_url = reverse('wagtailadmin_tag_autocomplete')
|
||||
else:
|
||||
autocomplete_url = reverse(
|
||||
'wagtailadmin_tag_model_autocomplete',
|
||||
args=(self.tag_model._meta.app_label, self.tag_model._meta.model_name)
|
||||
)
|
||||
|
||||
if self.free_tagging is None:
|
||||
free_tagging = getattr(self.tag_model, 'free_tagging', True)
|
||||
else:
|
||||
free_tagging = self.free_tagging
|
||||
|
||||
context['widget']['autocomplete_url'] = autocomplete_url
|
||||
context['widget']['options_json'] = json.dumps({
|
||||
'allowSpaces': getattr(settings, 'TAG_SPACES_ALLOWED', True),
|
||||
'tagLimit': getattr(settings, 'TAG_LIMIT', None),
|
||||
'autocompleteOnly': not free_tagging,
|
||||
})
|
||||
|
||||
return context
|
||||
|
||||
|
||||
class AdminChooser(WidgetWithScript, widgets.Input):
|
||||
input_type = 'hidden'
|
||||
choose_one_text = _("Choose an item")
|
||||
choose_another_text = _("Choose another item")
|
||||
clear_choice_text = _("Clear choice")
|
||||
link_to_chosen_text = _("Edit this item")
|
||||
show_edit_link = True
|
||||
|
||||
# when looping over form fields, this one should appear in visible_fields, not hidden_fields
|
||||
# despite the underlying input being type="hidden"
|
||||
is_hidden = False
|
||||
|
||||
def get_instance(self, model_class, value):
|
||||
# helper method for cleanly turning 'value' into an instance object
|
||||
if value is None:
|
||||
return None
|
||||
|
||||
try:
|
||||
return model_class.objects.get(pk=value)
|
||||
except model_class.DoesNotExist:
|
||||
return None
|
||||
|
||||
def get_instance_and_id(self, model_class, value):
|
||||
if value is None:
|
||||
return (None, None)
|
||||
elif isinstance(value, model_class):
|
||||
return (value, value.pk)
|
||||
else:
|
||||
try:
|
||||
return (model_class.objects.get(pk=value), value)
|
||||
except model_class.DoesNotExist:
|
||||
return (None, None)
|
||||
|
||||
def value_from_datadict(self, data, files, name):
|
||||
# treat the empty string as None
|
||||
result = super().value_from_datadict(data, files, name)
|
||||
if result == '':
|
||||
return None
|
||||
else:
|
||||
return result
|
||||
|
||||
def __init__(self, **kwargs):
|
||||
# allow choose_one_text / choose_another_text to be overridden per-instance
|
||||
if 'choose_one_text' in kwargs:
|
||||
self.choose_one_text = kwargs.pop('choose_one_text')
|
||||
if 'choose_another_text' in kwargs:
|
||||
self.choose_another_text = kwargs.pop('choose_another_text')
|
||||
if 'clear_choice_text' in kwargs:
|
||||
self.clear_choice_text = kwargs.pop('clear_choice_text')
|
||||
if 'link_to_chosen_text' in kwargs:
|
||||
self.link_to_chosen_text = kwargs.pop('link_to_chosen_text')
|
||||
if 'show_edit_link' in kwargs:
|
||||
self.show_edit_link = kwargs.pop('show_edit_link')
|
||||
super().__init__(**kwargs)
|
||||
|
||||
|
||||
class AdminPageChooser(AdminChooser):
|
||||
choose_one_text = _('Choose a page')
|
||||
choose_another_text = _('Choose another page')
|
||||
link_to_chosen_text = _('Edit this page')
|
||||
|
||||
def __init__(self, target_models=None, can_choose_root=False, user_perms=None, **kwargs):
|
||||
super().__init__(**kwargs)
|
||||
|
||||
if target_models:
|
||||
model_names = [model._meta.verbose_name.title() for model in target_models if model is not Page]
|
||||
if len(model_names) == 1:
|
||||
self.choose_one_text += ' (' + model_names[0] + ')'
|
||||
|
||||
self.user_perms = user_perms
|
||||
self.target_models = list(target_models or [Page])
|
||||
self.can_choose_root = can_choose_root
|
||||
|
||||
def _get_lowest_common_page_class(self):
|
||||
"""
|
||||
Return a Page class that is an ancestor for all Page classes in
|
||||
``target_models``, and is also a concrete Page class itself.
|
||||
"""
|
||||
if len(self.target_models) == 1:
|
||||
# Shortcut for a single page type
|
||||
return self.target_models[0]
|
||||
else:
|
||||
return Page
|
||||
|
||||
def render_html(self, name, value, attrs):
|
||||
model_class = self._get_lowest_common_page_class()
|
||||
|
||||
instance, value = self.get_instance_and_id(model_class, value)
|
||||
|
||||
original_field_html = super().render_html(name, value, attrs)
|
||||
|
||||
return render_to_string("wagtailadmin/widgets/page_chooser.html", {
|
||||
'widget': self,
|
||||
'original_field_html': original_field_html,
|
||||
'attrs': attrs,
|
||||
'value': value,
|
||||
'page': instance,
|
||||
})
|
||||
|
||||
def render_js_init(self, id_, name, value):
|
||||
if isinstance(value, Page):
|
||||
page = value
|
||||
else:
|
||||
# Value is an ID look up object
|
||||
model_class = self._get_lowest_common_page_class()
|
||||
page = self.get_instance(model_class, value)
|
||||
|
||||
parent = page.get_parent() if page else None
|
||||
|
||||
return "createPageChooser({id}, {model_names}, {parent}, {can_choose_root}, {user_perms});".format(
|
||||
id=json.dumps(id_),
|
||||
model_names=json.dumps([
|
||||
'{app}.{model}'.format(
|
||||
app=model._meta.app_label,
|
||||
model=model._meta.model_name)
|
||||
for model in self.target_models
|
||||
]),
|
||||
parent=json.dumps(parent.id if parent else None),
|
||||
can_choose_root=('true' if self.can_choose_root else 'false'),
|
||||
user_perms=json.dumps(self.user_perms),
|
||||
)
|
||||
|
||||
@property
|
||||
def media(self):
|
||||
return forms.Media(js=[
|
||||
versioned_static('wagtailadmin/js/page-chooser-modal.js'),
|
||||
versioned_static('wagtailadmin/js/page-chooser.js'),
|
||||
])
|
||||
|
||||
|
||||
@total_ordering
|
||||
class Button:
|
||||
show = True
|
||||
|
||||
def __init__(self, label, url, classes=set(), attrs={}, priority=1000):
|
||||
self.label = label
|
||||
self.url = url
|
||||
self.classes = classes
|
||||
self.attrs = attrs.copy()
|
||||
self.priority = priority
|
||||
|
||||
def render(self):
|
||||
attrs = {'href': self.url, 'class': ' '.join(sorted(self.classes))}
|
||||
attrs.update(self.attrs)
|
||||
return format_html('<a{}>{}</a>', flatatt(attrs), self.label)
|
||||
|
||||
def __str__(self):
|
||||
return self.render()
|
||||
|
||||
def __repr__(self):
|
||||
return '<Button: {}>'.format(self.label)
|
||||
|
||||
def __lt__(self, other):
|
||||
if not isinstance(other, Button):
|
||||
return NotImplemented
|
||||
return (self.priority, self.label) < (other.priority, other.label)
|
||||
|
||||
def __eq__(self, other):
|
||||
if not isinstance(other, Button):
|
||||
return NotImplemented
|
||||
return (self.label == other.label
|
||||
and self.url == other.url
|
||||
and self.classes == other.classes
|
||||
and self.attrs == other.attrs
|
||||
and self.priority == other.priority)
|
||||
|
||||
|
||||
class PageListingButton(Button):
|
||||
def __init__(self, label, url, classes=set(), **kwargs):
|
||||
classes = {'button', 'button-small', 'button-secondary'} | set(classes)
|
||||
super().__init__(label, url, classes=classes, **kwargs)
|
||||
|
||||
|
||||
class BaseDropdownMenuButton(Button):
|
||||
def __init__(self, *args, **kwargs):
|
||||
super().__init__(*args, url=None, **kwargs)
|
||||
|
||||
@cached_property
|
||||
def dropdown_buttons(self):
|
||||
raise NotImplementedError
|
||||
|
||||
def render(self):
|
||||
return render_to_string(self.template_name, {
|
||||
'buttons': self.dropdown_buttons,
|
||||
'label': self.label,
|
||||
'title': self.attrs.get('title'),
|
||||
'is_parent': self.is_parent})
|
||||
|
||||
|
||||
class ButtonWithDropdownFromHook(BaseDropdownMenuButton):
|
||||
template_name = 'wagtailadmin/pages/listing/_button_with_dropdown.html'
|
||||
|
||||
def __init__(self, label, hook_name, page, page_perms, is_parent, next_url=None, **kwargs):
|
||||
self.hook_name = hook_name
|
||||
self.page = page
|
||||
self.page_perms = page_perms
|
||||
self.is_parent = is_parent
|
||||
self.next_url = next_url
|
||||
|
||||
super().__init__(label, **kwargs)
|
||||
|
||||
@property
|
||||
def show(self):
|
||||
return bool(self.dropdown_buttons)
|
||||
|
||||
@cached_property
|
||||
def dropdown_buttons(self):
|
||||
button_hooks = hooks.get_hooks(self.hook_name)
|
||||
|
||||
buttons = []
|
||||
for hook in button_hooks:
|
||||
if accepts_kwarg(hook, 'next_url'):
|
||||
buttons.extend(hook(self.page, self.page_perms, self.is_parent, self.next_url))
|
||||
else:
|
||||
warnings.warn(
|
||||
'%s hooks will require an additional kwarg `next_url` in a future release. Please update your hook function to accept `next_url`.' % self.hook_name,
|
||||
RemovedInWagtail212Warning
|
||||
)
|
||||
buttons.extend(hook(self.page, self.page_perms, self.is_parent))
|
||||
|
||||
buttons.sort()
|
||||
return buttons
|
|
@ -1,5 +1,4 @@
|
|||
import itertools
|
||||
|
||||
import warnings
|
||||
from functools import total_ordering
|
||||
|
||||
from django.forms.utils import flatatt
|
||||
|
@ -8,6 +7,8 @@ from django.utils.functional import cached_property
|
|||
from django.utils.html import format_html
|
||||
|
||||
from wagtail.core import hooks
|
||||
from wagtail.core.utils import accepts_kwarg
|
||||
from wagtail.utils.deprecation import RemovedInWagtail212Warning
|
||||
|
||||
|
||||
@total_ordering
|
||||
|
@ -87,6 +88,17 @@ class ButtonWithDropdownFromHook(BaseDropdownMenuButton):
|
|||
@cached_property
|
||||
def dropdown_buttons(self):
|
||||
button_hooks = hooks.get_hooks(self.hook_name)
|
||||
return sorted(itertools.chain.from_iterable(
|
||||
hook(self.page, self.page_perms, self.is_parent)
|
||||
for hook in button_hooks))
|
||||
|
||||
buttons = []
|
||||
for hook in button_hooks:
|
||||
if accepts_kwarg(hook, 'next_url'):
|
||||
buttons.extend(hook(self.page, self.page_perms, self.is_parent, self.next_url))
|
||||
else:
|
||||
warnings.warn(
|
||||
'%s hooks will require an additional kwarg `next_url` in a future release. Please update your hook function to accept `next_url`.' % self.hook_name,
|
||||
RemovedInWagtail212Warning
|
||||
)
|
||||
buttons.extend(hook(self.page, self.page_perms, self.is_parent))
|
||||
|
||||
buttons.sort()
|
||||
return buttons
|
||||
|
|
|
@ -790,7 +790,6 @@
|
|||
</style>
|
||||
|
||||
<ul class="unlist">
|
||||
<<<<<<< HEAD
|
||||
<li>{% icon 'wagtail-icon' %} wagtail</li>
|
||||
<li>{% icon 'wagtail-inverse' %} wagtail-inverse</li>
|
||||
<li>{% icon 'cogs' %} cogs</li>
|
||||
|
|
Ładowanie…
Reference in New Issue