commit
5d09976a82
49 changed files with 1898 additions and 0 deletions
@ -0,0 +1,39 @@ |
|||
# Django project |
|||
/media/ |
|||
/static/ |
|||
*.sqlite3 |
|||
|
|||
# Python and others |
|||
__pycache__ |
|||
*.pyc |
|||
.DS_Store |
|||
*.swp |
|||
/venv/ |
|||
/tmp/ |
|||
/.vagrant/ |
|||
/Vagrantfile.local |
|||
node_modules/ |
|||
/npm-debug.log |
|||
/.idea/ |
|||
.vscode |
|||
coverage |
|||
.python-version |
|||
|
|||
# Distribution / packaging |
|||
.Python |
|||
env/ |
|||
build/ |
|||
develop-eggs/ |
|||
dist/ |
|||
downloads/ |
|||
eggs/ |
|||
.eggs/ |
|||
lib/ |
|||
lib64/ |
|||
parts/ |
|||
sdist/ |
|||
var/ |
|||
wheels/ |
|||
*.egg-info/ |
|||
.installed.cfg |
|||
*.egg |
@ -0,0 +1,60 @@ |
|||
# Use an official Python runtime based on Debian 10 "buster" as a parent image. |
|||
FROM python:3.8.1-slim-buster |
|||
|
|||
# Add user that will be used in the container. |
|||
RUN useradd wagtail |
|||
|
|||
# Port used by this container to serve HTTP. |
|||
EXPOSE 8000 |
|||
|
|||
# Set environment variables. |
|||
# 1. Force Python stdout and stderr streams to be unbuffered. |
|||
# 2. Set PORT variable that is used by Gunicorn. This should match "EXPOSE" |
|||
# command. |
|||
ENV PYTHONUNBUFFERED=1 \ |
|||
PORT=8000 |
|||
|
|||
# Install system packages required by Wagtail and Django. |
|||
RUN apt-get update --yes --quiet && apt-get install --yes --quiet --no-install-recommends \ |
|||
build-essential \ |
|||
libpq-dev \ |
|||
libmariadbclient-dev \ |
|||
libjpeg62-turbo-dev \ |
|||
zlib1g-dev \ |
|||
libwebp-dev \ |
|||
&& rm -rf /var/lib/apt/lists/* |
|||
|
|||
# Install the application server. |
|||
RUN pip install "gunicorn==20.0.4" |
|||
|
|||
# Install the project requirements. |
|||
COPY requirements.txt / |
|||
RUN pip install -r /requirements.txt |
|||
|
|||
# Use /app folder as a directory where the source code is stored. |
|||
WORKDIR /app |
|||
|
|||
# Set this directory to be owned by the "wagtail" user. This Wagtail project |
|||
# uses SQLite, the folder needs to be owned by the user that |
|||
# will be writing to the database file. |
|||
RUN chown wagtail:wagtail /app |
|||
|
|||
# Copy the source code of the project into the container. |
|||
COPY --chown=wagtail:wagtail . . |
|||
|
|||
# Use user "wagtail" to run the build commands below and the server itself. |
|||
USER wagtail |
|||
|
|||
# Collect static files. |
|||
RUN python manage.py collectstatic --noinput --clear |
|||
|
|||
# Runtime command that executes when "docker run" is called, it does the |
|||
# following: |
|||
# 1. Migrate the database. |
|||
# 2. Start the application server. |
|||
# WARNING: |
|||
# Migrating database at the same time as starting the server IS NOT THE BEST |
|||
# PRACTICE. The database should be migrated manually or using the release |
|||
# phase facilities of your hosting platform. This is used only so the |
|||
# Wagtail instance can be started with a simple "docker run" command. |
|||
CMD set -xe; python manage.py migrate --noinput; gunicorn hvezdarna.wsgi:application |
Binary file not shown.
Binary file not shown.
Binary file not shown.
@ -0,0 +1,22 @@ |
|||
# -*- coding: utf-8 -*- |
|||
from django.db import migrations, models |
|||
|
|||
|
|||
class Migration(migrations.Migration): |
|||
|
|||
dependencies = [ |
|||
('wagtailcore', '0040_page_draft_title'), |
|||
] |
|||
|
|||
operations = [ |
|||
migrations.CreateModel( |
|||
name='HomePage', |
|||
fields=[ |
|||
('page_ptr', models.OneToOneField(on_delete=models.CASCADE, parent_link=True, auto_created=True, primary_key=True, serialize=False, to='wagtailcore.Page')), |
|||
], |
|||
options={ |
|||
'abstract': False, |
|||
}, |
|||
bases=('wagtailcore.page',), |
|||
), |
|||
] |
@ -0,0 +1,58 @@ |
|||
# -*- coding: utf-8 -*- |
|||
from django.db import migrations |
|||
|
|||
|
|||
def create_homepage(apps, schema_editor): |
|||
# Get models |
|||
ContentType = apps.get_model('contenttypes.ContentType') |
|||
Page = apps.get_model('wagtailcore.Page') |
|||
Site = apps.get_model('wagtailcore.Site') |
|||
HomePage = apps.get_model('home.HomePage') |
|||
|
|||
# Delete the default homepage |
|||
# If migration is run multiple times, it may have already been deleted |
|||
Page.objects.filter(id=2).delete() |
|||
|
|||
# Create content type for homepage model |
|||
homepage_content_type, __ = ContentType.objects.get_or_create( |
|||
model='homepage', app_label='home') |
|||
|
|||
# Create a new homepage |
|||
homepage = HomePage.objects.create( |
|||
title="Home", |
|||
draft_title="Home", |
|||
slug='home', |
|||
content_type=homepage_content_type, |
|||
path='00010001', |
|||
depth=2, |
|||
numchild=0, |
|||
url_path='/home/', |
|||
) |
|||
|
|||
# Create a site with the new homepage set as the root |
|||
Site.objects.create( |
|||
hostname='localhost', root_page=homepage, is_default_site=True) |
|||
|
|||
|
|||
def remove_homepage(apps, schema_editor): |
|||
# Get models |
|||
ContentType = apps.get_model('contenttypes.ContentType') |
|||
HomePage = apps.get_model('home.HomePage') |
|||
|
|||
# Delete the default homepage |
|||
# Page and Site objects CASCADE |
|||
HomePage.objects.filter(slug='home', depth=2).delete() |
|||
|
|||
# Delete content type for homepage model |
|||
ContentType.objects.filter(model='homepage', app_label='home').delete() |
|||
|
|||
|
|||
class Migration(migrations.Migration): |
|||
|
|||
dependencies = [ |
|||
('home', '0001_initial'), |
|||
] |
|||
|
|||
operations = [ |
|||
migrations.RunPython(create_homepage, remove_homepage), |
|||
] |
@ -0,0 +1,56 @@ |
|||
# Generated by Django 3.1.4 on 2021-03-19 09:46 |
|||
|
|||
from django.db import migrations, models |
|||
import django.db.models.deletion |
|||
import modelcluster.fields |
|||
import wagtail.core.fields |
|||
|
|||
|
|||
class Migration(migrations.Migration): |
|||
|
|||
dependencies = [ |
|||
('wagtailimages', '0022_uploadedimage'), |
|||
('home', '0002_create_homepage'), |
|||
] |
|||
|
|||
operations = [ |
|||
migrations.AddField( |
|||
model_name='homepage', |
|||
name='address', |
|||
field=models.CharField(blank=True, default='', max_length=255, verbose_name='Adresa'), |
|||
), |
|||
migrations.AddField( |
|||
model_name='homepage', |
|||
name='body', |
|||
field=wagtail.core.fields.RichTextField(blank=True), |
|||
), |
|||
migrations.AddField( |
|||
model_name='homepage', |
|||
name='email', |
|||
field=models.EmailField(blank=True, max_length=64, null=True, verbose_name='E-mail'), |
|||
), |
|||
migrations.AddField( |
|||
model_name='homepage', |
|||
name='map_link', |
|||
field=models.URLField(blank=True, default='', max_length=128, verbose_name='Odkaz na mapu'), |
|||
), |
|||
migrations.AddField( |
|||
model_name='homepage', |
|||
name='mobile', |
|||
field=models.CharField(blank=True, default='', max_length=24, verbose_name='Mobil'), |
|||
), |
|||
migrations.CreateModel( |
|||
name='CarouselImage', |
|||
fields=[ |
|||
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), |
|||
('sort_order', models.IntegerField(blank=True, editable=False, null=True)), |
|||
('caption', models.CharField(blank=True, max_length=250)), |
|||
('image', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='+', to='wagtailimages.image')), |
|||
('page', modelcluster.fields.ParentalKey(on_delete=django.db.models.deletion.CASCADE, related_name='carousel_images', to='home.homepage')), |
|||
], |
|||
options={ |
|||
'ordering': ['sort_order'], |
|||
'abstract': False, |
|||
}, |
|||
), |
|||
] |
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@ -0,0 +1,51 @@ |
|||
from django.db import models |
|||
|
|||
from modelcluster.fields import ParentalKey |
|||
|
|||
from wagtail.core.models import Page, Orderable |
|||
from wagtail.core.fields import RichTextField |
|||
from wagtail.admin.edit_handlers import FieldPanel, InlinePanel |
|||
from wagtail.images.edit_handlers import ImageChooserPanel |
|||
from wagtail.search import index |
|||
from wagtail.api import APIField |
|||
|
|||
|
|||
class HomePage(Page): |
|||
body = RichTextField(blank=True) |
|||
address = models.CharField(max_length=255, verbose_name="Adresa", blank=True, default='') |
|||
mobile = models.CharField(max_length=24, verbose_name="Mobil", blank=True, default='') |
|||
email = models.EmailField(max_length=64, verbose_name="E-mail", blank=True, null=True) |
|||
map_link = models.URLField(max_length=128, verbose_name="Odkaz na mapu", blank=True, default='') |
|||
|
|||
content_panels = Page.content_panels + [ |
|||
FieldPanel('body', classname="full"), |
|||
FieldPanel('address'), |
|||
FieldPanel('mobile'), |
|||
FieldPanel('email'), |
|||
FieldPanel('map_link'), |
|||
InlinePanel('carousel_images', label="Obrázky"), |
|||
] |
|||
|
|||
search_fields = Page.search_fields + [ |
|||
index.SearchField('body'), |
|||
] |
|||
|
|||
api_fields = [ |
|||
APIField('carousel_images'), |
|||
] |
|||
|
|||
|
|||
class CarouselImage(Orderable): |
|||
page = ParentalKey(HomePage, on_delete=models.CASCADE, related_name='carousel_images') |
|||
image = models.ForeignKey('wagtailimages.Image', on_delete=models.CASCADE, related_name='+') |
|||
caption = models.CharField(blank=True, max_length=250) |
|||
|
|||
panels = [ |
|||
ImageChooserPanel('image'), |
|||
FieldPanel('caption'), |
|||
] |
|||
|
|||
api_fields = [ |
|||
APIField("image"), |
|||
APIField('caption'), |
|||
] |
@ -0,0 +1,204 @@ |
|||
html { |
|||
box-sizing: border-box; |
|||
} |
|||
|
|||
*, |
|||
*:before, |
|||
*:after { |
|||
box-sizing: inherit; |
|||
} |
|||
|
|||
body { |
|||
max-width: 960px; |
|||
min-height: 100vh; |
|||
margin: 0 auto; |
|||
padding: 0 15px; |
|||
color: #231f20; |
|||
font-family: 'Helvetica Neue', 'Segoe UI', Arial, sans-serif; |
|||
line-height: 1.25; |
|||
} |
|||
|
|||
a { |
|||
background-color: transparent; |
|||
color: #308282; |
|||
text-decoration: underline; |
|||
} |
|||
|
|||
a:hover { |
|||
color: #ea1b10; |
|||
} |
|||
|
|||
h1, |
|||
h2, |
|||
h3, |
|||
h4, |
|||
h5, |
|||
p, |
|||
ul { |
|||
padding: 0; |
|||
margin: 0; |
|||
font-weight: 400; |
|||
} |
|||
|
|||
main { |
|||
display: block; /* For IE11 support */ |
|||
} |
|||
|
|||
svg:not(:root) { |
|||
overflow: hidden; |
|||
} |
|||
|
|||
.header { |
|||
display: flex; |
|||
justify-content: space-between; |
|||
align-items: center; |
|||
padding-top: 20px; |
|||
padding-bottom: 10px; |
|||
border-bottom: 1px solid #e6e6e6; |
|||
} |
|||
|
|||
.logo { |
|||
width: 150px; |
|||
margin-right: 20px; |
|||
} |
|||
|
|||
.logo a { |
|||
display: block; |
|||
} |
|||
|
|||
.figure-logo { |
|||
max-width: 150px; |
|||
max-height: 55.1px; |
|||
} |
|||
|
|||
.release-notes { |
|||
font-size: 14px; |
|||
} |
|||
|
|||
.main { |
|||
padding: 40px 0; |
|||
margin: 0 auto; |
|||
text-align: center; |
|||
} |
|||
|
|||
.figure-space { |
|||
max-width: 265px; |
|||
} |
|||
|
|||
@-webkit-keyframes pos { |
|||
0%, 100% { |
|||
-webkit-transform: rotate(-6deg); |
|||
transform: rotate(-6deg); |
|||
} |
|||
50% { |
|||
-webkit-transform: rotate(6deg); |
|||
transform: rotate(6deg); |
|||
} |
|||
} |
|||
|
|||
@keyframes pos { |
|||
0%, 100% { |
|||
-webkit-transform: rotate(-6deg); |
|||
transform: rotate(-6deg); |
|||
} |
|||
50% { |
|||
-webkit-transform: rotate(6deg); |
|||
transform: rotate(6deg); |
|||
} |
|||
} |
|||
|
|||
.egg { |
|||
fill: #43b1b0; |
|||
-webkit-animation: pos 3s ease infinite; |
|||
animation: pos 3s ease infinite; |
|||
-webkit-transform: translateY(50px); |
|||
transform: translateY(50px); |
|||
-webkit-transform-origin: 50% 80%; |
|||
transform-origin: 50% 80%; |
|||
} |
|||
|
|||
.main-text { |
|||
max-width: 400px; |
|||
margin: 5px auto; |
|||
} |
|||
|
|||
.main-text h1 { |
|||
font-size: 22px; |
|||
} |
|||
|
|||
.main-text p { |
|||
margin: 15px auto 0; |
|||
} |
|||
|
|||
.footer { |
|||
display: flex; |
|||
flex-wrap: wrap; |
|||
justify-content: space-between; |
|||
border-top: 1px solid #e6e6e6; |
|||
padding: 10px; |
|||
} |
|||
|
|||
.option { |
|||
display: block; |
|||
padding: 10px 10px 10px 34px; |
|||
position: relative; |
|||
text-decoration: none; |
|||
} |
|||
|
|||
.option svg { |
|||
width: 24px; |
|||
height: 24px; |
|||
fill: gray; |
|||
border: 1px solid #d9d9d9; |
|||
padding: 5px; |
|||
border-radius: 100%; |
|||
top: 10px; |
|||
left: 0; |
|||
position: absolute; |
|||
} |
|||
|
|||
.option h4 { |
|||
font-size: 19px; |
|||
text-decoration: underline; |
|||
} |
|||
|
|||
.option p { |
|||
padding-top: 3px; |
|||
color: #231f20; |
|||
font-size: 15px; |
|||
font-weight: 300; |
|||
} |
|||
|
|||
@media (max-width: 996px) { |
|||
body { |
|||
max-width: 780px; |
|||
} |
|||
} |
|||
|
|||
@media (max-width: 767px) { |
|||
.option { |
|||
flex: 0 0 50%; |
|||
} |
|||
} |
|||
|
|||
@media (max-width: 599px) { |
|||
.main { |
|||
padding: 20px 0; |
|||
} |
|||
|
|||
.figure-space { |
|||
max-width: 200px; |
|||
} |
|||
|
|||
.footer { |
|||
display: block; |
|||
width: 300px; |
|||
margin: 0 auto; |
|||
} |
|||
} |
|||
|
|||
@media (max-width: 360px) { |
|||
.header-link { |
|||
max-width: 100px; |
|||
} |
|||
} |
@ -0,0 +1,52 @@ |
|||
{% extends "base.html" %} |
|||
|
|||
{% block extra_css %} |
|||
|
|||
{% endblock extra_css %} |
|||
|
|||
{% block content %} |
|||
<muj-kolotoc/> |
|||
{% endblock content %} |
|||
|
|||
|
|||
{% block extra_js %} |
|||
|
|||
<script> |
|||
$,getJSON("/api/v2/pages/3/?type=home.HomePage&fields=carousel_images") |
|||
.done(function(){ |
|||
console.log(data); |
|||
let images = []; |
|||
for (let index = 0; index < data.carousel_images.length; index++) { |
|||
const element = data.carousel_images[index]; |
|||
console.log(item.caption); |
|||
console.log(item.image.meta.download_url); |
|||
images.push({ |
|||
src: item.image.meta.download_url, |
|||
title: item.caption |
|||
},) |
|||
} |
|||
}) |
|||
.fail(function(){ |
|||
alert("Chyba při dotazu do Api") |
|||
}); |
|||
let images = [ |
|||
{ |
|||
src: "/img/image_01.jpg", |
|||
title: "Obrázek 1" |
|||
}, |
|||
{ |
|||
src: "/img/image_02.jpg", |
|||
title: "Obrázek 2" |
|||
}, |
|||
{ |
|||
src: "/img/image_03.jpg", |
|||
title: "Obrázek 3" |
|||
} |
|||
]; |
|||
|
|||
let kolotoc = document.querySelector("muj-kolotoc"); |
|||
kolotoc.images = images; |
|||
|
|||
</script> |
|||
|
|||
{% endblock %} |
@ -0,0 +1 @@ |
|||
{% load i18n wagtailcore_tags %} |
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@ -0,0 +1,15 @@ |
|||
from wagtail.api.v2.views import PagesAPIViewSet |
|||
from wagtail.api.v2.router import WagtailAPIRouter |
|||
from wagtail.images.api.v2.views import ImagesAPIViewSet |
|||
from wagtail.documents.api.v2.views import DocumentsAPIViewSet |
|||
|
|||
# Create the router. "wagtailapi" is the URL namespace |
|||
api_router = WagtailAPIRouter('wagtailapi') |
|||
|
|||
# Add the three endpoints using the "register_endpoint" method. |
|||
# The first parameter is the name of the endpoint (eg. pages, images). This |
|||
# is used in the URL of the endpoint |
|||
# The second parameter is the endpoint class that handles the requests |
|||
api_router.register_endpoint('pages', PagesAPIViewSet) |
|||
api_router.register_endpoint('images', ImagesAPIViewSet) |
|||
api_router.register_endpoint('documents', DocumentsAPIViewSet) |
Binary file not shown.
Binary file not shown.
Binary file not shown.
@ -0,0 +1,163 @@ |
|||
""" |
|||
Django settings for hvezdarna project. |
|||
|
|||
Generated by 'django-admin startproject' using Django 3.1.4. |
|||
|
|||
For more information on this file, see |
|||
https://docs.djangoproject.com/en/3.1/topics/settings/ |
|||
|
|||
For the full list of settings and their values, see |
|||
https://docs.djangoproject.com/en/3.1/ref/settings/ |
|||
""" |
|||
|
|||
# Build paths inside the project like this: os.path.join(BASE_DIR, ...) |
|||
import os |
|||
|
|||
PROJECT_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) |
|||
BASE_DIR = os.path.dirname(PROJECT_DIR) |
|||
|
|||
|
|||
# Quick-start development settings - unsuitable for production |
|||
# See https://docs.djangoproject.com/en/3.1/howto/deployment/checklist/ |
|||
|
|||
|
|||
# Application definition |
|||
|
|||
INSTALLED_APPS = [ |
|||
'home', |
|||
'search', |
|||
|
|||
'wagtail.contrib.forms', |
|||
'wagtail.contrib.redirects', |
|||
'wagtail.embeds', |
|||
'wagtail.sites', |
|||
'wagtail.users', |
|||
'wagtail.snippets', |
|||
'wagtail.documents', |
|||
'wagtail.images', |
|||
'wagtail.search', |
|||
'wagtail.admin', |
|||
'wagtail.core', |
|||
'rest_framework', |
|||
'wagtail.api.v2', |
|||
'modelcluster', |
|||
'taggit', |
|||
|
|||
'django.contrib.admin', |
|||
'django.contrib.auth', |
|||
'django.contrib.contenttypes', |
|||
'django.contrib.sessions', |
|||
'django.contrib.messages', |
|||
'django.contrib.staticfiles', |
|||
] |
|||
|
|||
MIDDLEWARE = [ |
|||
'django.contrib.sessions.middleware.SessionMiddleware', |
|||
'django.middleware.common.CommonMiddleware', |
|||
'django.middleware.csrf.CsrfViewMiddleware', |
|||
'django.contrib.auth.middleware.AuthenticationMiddleware', |
|||
'django.contrib.messages.middleware.MessageMiddleware', |
|||
'django.middleware.clickjacking.XFrameOptionsMiddleware', |
|||
'django.middleware.security.SecurityMiddleware', |
|||
|
|||
'wagtail.contrib.redirects.middleware.RedirectMiddleware', |
|||
] |
|||
|
|||
ROOT_URLCONF = 'hvezdarna.urls' |
|||
|
|||
TEMPLATES = [ |
|||
{ |
|||
'BACKEND': 'django.template.backends.django.DjangoTemplates', |
|||
'DIRS': [ |
|||
os.path.join(PROJECT_DIR, 'templates'), |
|||
], |
|||
'APP_DIRS': True, |
|||
'OPTIONS': { |
|||
'context_processors': [ |
|||
'django.template.context_processors.debug', |
|||
'django.template.context_processors.request', |
|||
'django.contrib.auth.context_processors.auth', |
|||
'django.contrib.messages.context_processors.messages', |
|||
], |
|||
}, |
|||
}, |
|||
] |
|||
|
|||
WSGI_APPLICATION = 'hvezdarna.wsgi.application' |
|||
|
|||
|
|||
# Database |
|||
# https://docs.djangoproject.com/en/3.1/ref/settings/#databases |
|||
|
|||
DATABASES = { |
|||
'default': { |
|||
'ENGINE': 'django.db.backends.sqlite3', |
|||
'NAME': os.path.join(BASE_DIR, 'db.sqlite3'), |
|||
} |
|||
} |
|||
|
|||
|
|||
# Password validation |
|||
# https://docs.djangoproject.com/en/3.1/ref/settings/#auth-password-validators |
|||
|
|||
AUTH_PASSWORD_VALIDATORS = [ |
|||
{ |
|||
'NAME': 'django.contrib.auth.password_validation.UserAttributeSimilarityValidator', |
|||
}, |
|||
{ |
|||
'NAME': 'django.contrib.auth.password_validation.MinimumLengthValidator', |
|||
}, |
|||
{ |
|||
'NAME': 'django.contrib.auth.password_validation.CommonPasswordValidator', |
|||
}, |
|||
{ |
|||
'NAME': 'django.contrib.auth.password_validation.NumericPasswordValidator', |
|||
}, |
|||
] |
|||
|
|||
|
|||
# Internationalization |
|||
# https://docs.djangoproject.com/en/3.1/topics/i18n/ |
|||
|
|||
LANGUAGE_CODE = 'en-us' |
|||
|
|||
TIME_ZONE = 'UTC' |
|||
|
|||
USE_I18N = True |
|||
|
|||
USE_L10N = True |
|||
|
|||
USE_TZ = True |
|||
|
|||
|
|||
# Static files (CSS, JavaScript, Images) |
|||
# https://docs.djangoproject.com/en/3.1/howto/static-files/ |
|||
|
|||
STATICFILES_FINDERS = [ |
|||
'django.contrib.staticfiles.finders.FileSystemFinder', |
|||
'django.contrib.staticfiles.finders.AppDirectoriesFinder', |
|||
] |
|||
|
|||
STATICFILES_DIRS = [ |
|||
os.path.join(PROJECT_DIR, 'static'), |
|||
] |
|||
|
|||
# ManifestStaticFilesStorage is recommended in production, to prevent outdated |
|||
# JavaScript / CSS assets being served from cache (e.g. after a Wagtail upgrade). |
|||
# See https://docs.djangoproject.com/en/3.1/ref/contrib/staticfiles/#manifeststaticfilesstorage |
|||
STATICFILES_STORAGE = 'django.contrib.staticfiles.storage.ManifestStaticFilesStorage' |
|||
|
|||
STATIC_ROOT = os.path.join(BASE_DIR, 'static') |
|||
STATIC_URL = '/static/' |
|||
|
|||
MEDIA_ROOT = os.path.join(BASE_DIR, 'media') |
|||
MEDIA_URL = '/media/' |
|||
|
|||
|
|||
# Wagtail settings |
|||
|
|||
WAGTAIL_SITE_NAME = "hvezdarna" |
|||
|
|||
# Base URL to use when referring to full URLs within the Wagtail admin backend - |
|||
# e.g. in notification emails. Don't include '/admin' or a trailing slash |
|||
BASE_URL = 'http://example.com' |
@ -0,0 +1,18 @@ |
|||
from .base import * |
|||
|
|||
# SECURITY WARNING: don't run with debug turned on in production! |
|||
DEBUG = True |
|||
|
|||
# SECURITY WARNING: keep the secret key used in production secret! |
|||
SECRET_KEY = '!m!d%l_th%$@(50+p@=r0m$^cf$(a%*5c214-4p-4tcy=#e=d#' |
|||
|
|||
# SECURITY WARNING: define the correct hosts in production! |
|||
ALLOWED_HOSTS = ['*'] |
|||
|
|||
EMAIL_BACKEND = 'django.core.mail.backends.console.EmailBackend' |
|||
|
|||
|
|||
try: |
|||
from .local import * |
|||
except ImportError: |
|||
pass |
@ -0,0 +1,8 @@ |
|||
from .base import * |
|||
|
|||
DEBUG = False |
|||
|
|||
try: |
|||
from .local import * |
|||
except ImportError: |
|||
pass |
@ -0,0 +1,939 @@ |
|||
/******/ (function(modules) { // webpackBootstrap
|
|||
/******/ // The module cache
|
|||
/******/ var installedModules = {}; |
|||
/******/ |
|||
/******/ // The require function
|
|||
/******/ function __webpack_require__(moduleId) { |
|||
/******/ |
|||
/******/ // Check if module is in cache
|
|||
/******/ if(installedModules[moduleId]) { |
|||
/******/ return installedModules[moduleId].exports; |
|||
/******/ } |
|||
/******/ // Create a new module (and put it into the cache)
|
|||
/******/ var module = installedModules[moduleId] = { |
|||
/******/ i: moduleId, |
|||
/******/ l: false, |
|||
/******/ exports: {} |
|||
/******/ }; |
|||
/******/ |
|||
/******/ // Execute the module function
|
|||
/******/ modules[moduleId].call(module.exports, module, module.exports, __webpack_require__); |
|||
/******/ |
|||
/******/ // Flag the module as loaded
|
|||
/******/ module.l = true; |
|||
/******/ |
|||
/******/ // Return the exports of the module
|
|||
/******/ return module.exports; |
|||
/******/ } |
|||
/******/ |
|||
/******/ |
|||
/******/ // expose the modules object (__webpack_modules__)
|
|||
/******/ __webpack_require__.m = modules; |
|||
/******/ |
|||
/******/ // expose the module cache
|
|||
/******/ __webpack_require__.c = installedModules; |
|||
/******/ |
|||
/******/ // define getter function for harmony exports
|
|||
/******/ __webpack_require__.d = function(exports, name, getter) { |
|||
/******/ if(!__webpack_require__.o(exports, name)) { |
|||
/******/ Object.defineProperty(exports, name, { enumerable: true, get: getter }); |
|||
/******/ } |
|||
/******/ }; |
|||
/******/ |
|||
/******/ // define __esModule on exports
|
|||
/******/ __webpack_require__.r = function(exports) { |
|||
/******/ if(typeof Symbol !== 'undefined' && Symbol.toStringTag) { |
|||
/******/ Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' }); |
|||
/******/ } |
|||
/******/ Object.defineProperty(exports, '__esModule', { value: true }); |
|||
/******/ }; |
|||
/******/ |
|||
/******/ // create a fake namespace object
|
|||
/******/ // mode & 1: value is a module id, require it
|
|||
/******/ // mode & 2: merge all properties of value into the ns
|
|||
/******/ // mode & 4: return value when already ns object
|
|||
/******/ // mode & 8|1: behave like require
|
|||
/******/ __webpack_require__.t = function(value, mode) { |
|||
/******/ if(mode & 1) value = __webpack_require__(value); |
|||
/******/ if(mode & 8) return value; |
|||
/******/ if((mode & 4) && typeof value === 'object' && value && value.__esModule) return value; |
|||
/******/ var ns = Object.create(null); |
|||
/******/ __webpack_require__.r(ns); |
|||
/******/ Object.defineProperty(ns, 'default', { enumerable: true, value: value }); |
|||
/******/ if(mode & 2 && typeof value != 'string') for(var key in value) __webpack_require__.d(ns, key, function(key) { return value[key]; }.bind(null, key)); |
|||
/******/ return ns; |
|||
/******/ }; |
|||
/******/ |
|||
/******/ // getDefaultExport function for compatibility with non-harmony modules
|
|||
/******/ __webpack_require__.n = function(module) { |
|||
/******/ var getter = module && module.__esModule ? |
|||
/******/ function getDefault() { return module['default']; } : |
|||
/******/ function getModuleExports() { return module; }; |
|||
/******/ __webpack_require__.d(getter, 'a', getter); |
|||
/******/ return getter; |
|||
/******/ }; |
|||
/******/ |
|||
/******/ // Object.prototype.hasOwnProperty.call
|
|||
/******/ __webpack_require__.o = function(object, property) { return Object.prototype.hasOwnProperty.call(object, property); }; |
|||
/******/ |
|||
/******/ // __webpack_public_path__
|
|||
/******/ __webpack_require__.p = ""; |
|||
/******/ |
|||
/******/ |
|||
/******/ // Load entry module and return exports
|
|||
/******/ return __webpack_require__(__webpack_require__.s = "5a74"); |
|||
/******/ }) |
|||
/************************************************************************/ |
|||
/******/ ({ |
|||
|
|||
/***/ "24fb": |
|||
/***/ (function(module, exports, __webpack_require__) { |
|||
|
|||
"use strict"; |
|||
|
|||
|
|||
/* |
|||
MIT License http://www.opensource.org/licenses/mit-license.php
|
|||
Author Tobias Koppers @sokra |
|||
*/ |
|||
// css base code, injected by the css-loader
|
|||
// eslint-disable-next-line func-names
|
|||
module.exports = function (useSourceMap) { |
|||
var list = []; // return the list of modules as css string
|
|||
|
|||
list.toString = function toString() { |
|||
return this.map(function (item) { |
|||
var content = cssWithMappingToString(item, useSourceMap); |
|||
|
|||
if (item[2]) { |
|||
return "@media ".concat(item[2], " {").concat(content, "}"); |
|||
} |
|||
|
|||
return content; |
|||
}).join(''); |
|||
}; // import a list of modules into the list
|
|||
// eslint-disable-next-line func-names
|
|||
|
|||
|
|||
list.i = function (modules, mediaQuery, dedupe) { |
|||
if (typeof modules === 'string') { |
|||
// eslint-disable-next-line no-param-reassign
|
|||
modules = [[null, modules, '']]; |
|||
} |
|||
|
|||
var alreadyImportedModules = {}; |
|||
|
|||
if (dedupe) { |
|||
for (var i = 0; i < this.length; i++) { |
|||
// eslint-disable-next-line prefer-destructuring
|
|||
var id = this[i][0]; |
|||
|
|||
if (id != null) { |
|||
alreadyImportedModules[id] = true; |
|||
} |
|||
} |
|||
} |
|||
|
|||
for (var _i = 0; _i < modules.length; _i++) { |
|||
var item = [].concat(modules[_i]); |
|||
|
|||
if (dedupe && alreadyImportedModules[item[0]]) { |
|||
// eslint-disable-next-line no-continue
|
|||
continue; |
|||
} |
|||
|
|||
if (mediaQuery) { |
|||
if (!item[2]) { |
|||
item[2] = mediaQuery; |
|||
} else { |
|||
item[2] = "".concat(mediaQuery, " and ").concat(item[2]); |
|||
} |
|||
} |
|||
|
|||
list.push(item); |
|||
} |
|||
}; |
|||
|
|||
return list; |
|||
}; |
|||
|
|||
function cssWithMappingToString(item, useSourceMap) { |
|||
var content = item[1] || ''; // eslint-disable-next-line prefer-destructuring
|
|||
|
|||
var cssMapping = item[3]; |
|||
|
|||
if (!cssMapping) { |
|||
return content; |
|||
} |
|||
|
|||
if (useSourceMap && typeof btoa === 'function') { |
|||
var sourceMapping = toComment(cssMapping); |
|||
var sourceURLs = cssMapping.sources.map(function (source) { |
|||
return "/*# sourceURL=".concat(cssMapping.sourceRoot || '').concat(source, " */"); |
|||
}); |
|||
return [content].concat(sourceURLs).concat([sourceMapping]).join('\n'); |
|||
} |
|||
|
|||
return [content].join('\n'); |
|||
} // Adapted from convert-source-map (MIT)
|
|||
|
|||
|
|||
function toComment(sourceMap) { |
|||
// eslint-disable-next-line no-undef
|
|||
var base64 = btoa(unescape(encodeURIComponent(JSON.stringify(sourceMap)))); |
|||
var data = "sourceMappingURL=data:application/json;charset=utf-8;base64,".concat(base64); |
|||
return "/*# ".concat(data, " */"); |
|||
} |
|||
|
|||
/***/ }), |
|||
|
|||
/***/ "35d6": |
|||
/***/ (function(module, __webpack_exports__, __webpack_require__) { |
|||
|
|||
"use strict"; |
|||
// ESM COMPAT FLAG
|
|||
__webpack_require__.r(__webpack_exports__); |
|||
|
|||
// EXPORTS
|
|||
__webpack_require__.d(__webpack_exports__, "default", function() { return /* binding */ addStylesToShadowDOM; }); |
|||
|
|||
// CONCATENATED MODULE: ./node_modules/vue-style-loader/lib/listToStyles.js
|
|||
/** |
|||
* Translates the list format produced by css-loader into something |
|||
* easier to manipulate. |
|||
*/ |
|||
function listToStyles (parentId, list) { |
|||
var styles = [] |
|||
var newStyles = {} |
|||
for (var i = 0; i < list.length; i++) { |
|||
var item = list[i] |
|||
var id = item[0] |
|||
var css = item[1] |
|||
var media = item[2] |
|||
var sourceMap = item[3] |
|||
var part = { |
|||
id: parentId + ':' + i, |
|||
css: css, |
|||
media: media, |
|||
sourceMap: sourceMap |
|||
} |
|||
if (!newStyles[id]) { |
|||
styles.push(newStyles[id] = { id: id, parts: [part] }) |
|||
} else { |
|||
newStyles[id].parts.push(part) |
|||
} |
|||
} |
|||
return styles |
|||
} |
|||
|
|||
// CONCATENATED MODULE: ./node_modules/vue-style-loader/lib/addStylesShadow.js
|
|||
|
|||
|
|||
function addStylesToShadowDOM (parentId, list, shadowRoot) { |
|||
var styles = listToStyles(parentId, list) |
|||
addStyles(styles, shadowRoot) |
|||
} |
|||
|
|||
/* |
|||
type StyleObject = { |
|||
id: number; |
|||
parts: Array<StyleObjectPart> |
|||
} |
|||
|
|||
type StyleObjectPart = { |
|||
css: string; |
|||
media: string; |
|||
sourceMap: ?string |
|||
} |
|||
*/ |
|||
|
|||
function addStyles (styles /* Array<StyleObject> */, shadowRoot) { |
|||
const injectedStyles = |
|||
shadowRoot._injectedStyles || |
|||
(shadowRoot._injectedStyles = {}) |
|||
for (var i = 0; i < styles.length; i++) { |
|||
var item = styles[i] |
|||
var style = injectedStyles[item.id] |
|||
if (!style) { |
|||
for (var j = 0; j < item.parts.length; j++) { |
|||
addStyle(item.parts[j], shadowRoot) |
|||
} |
|||
injectedStyles[item.id] = true |
|||
} |
|||
} |
|||
} |
|||
|
|||
function createStyleElement (shadowRoot) { |
|||
var styleElement = document.createElement('style') |
|||
styleElement.type = 'text/css' |
|||
shadowRoot.appendChild(styleElement) |
|||
return styleElement |
|||
} |
|||
|
|||
function addStyle (obj /* StyleObjectPart */, shadowRoot) { |
|||
var styleElement = createStyleElement(shadowRoot) |
|||
var css = obj.css |
|||
var media = obj.media |
|||
var sourceMap = obj.sourceMap |
|||
|
|||
if (media) { |
|||
styleElement.setAttribute('media', media) |
|||
} |
|||
|
|||
if (sourceMap) { |
|||
// https://developer.chrome.com/devtools/docs/javascript-debugging
|
|||
// this makes source maps inside style tags work properly in Chrome
|
|||
css += '\n/*# sourceURL=' + sourceMap.sources[0] + ' */' |
|||
// http://stackoverflow.com/a/26603875
|
|||
css += '\n/*# sourceMappingURL=data:application/json;base64,' + btoa(unescape(encodeURIComponent(JSON.stringify(sourceMap)))) + ' */' |
|||
} |
|||
|
|||
if (styleElement.styleSheet) { |
|||
styleElement.styleSheet.cssText = css |
|||
} else { |
|||
while (styleElement.firstChild) { |
|||
styleElement.removeChild(styleElement.firstChild) |
|||
} |
|||
styleElement.appendChild(document.createTextNode(css)) |
|||
} |
|||
} |
|||
|
|||
|
|||
/***/ }), |
|||
|
|||
/***/ "4933": |
|||
/***/ (function(module, __webpack_exports__, __webpack_require__) { |
|||
|
|||
"use strict"; |
|||
__webpack_require__.r(__webpack_exports__); |
|||
/* harmony import */ var _node_modules_vue_style_loader_index_js_ref_6_oneOf_1_0_node_modules_css_loader_dist_cjs_js_ref_6_oneOf_1_1_node_modules_vue_loader_lib_loaders_stylePostLoader_js_node_modules_postcss_loader_src_index_js_ref_6_oneOf_1_2_node_modules_postcss_loader_src_index_js_ref_6_oneOf_1_3_node_modules_cache_loader_dist_cjs_js_ref_0_0_node_modules_vue_loader_lib_index_js_vue_loader_options_Kolotoc_vue_vue_type_style_index_0_lang_css_shadow__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__("4f39"); |
|||
/* harmony import */ var _node_modules_vue_style_loader_index_js_ref_6_oneOf_1_0_node_modules_css_loader_dist_cjs_js_ref_6_oneOf_1_1_node_modules_vue_loader_lib_loaders_stylePostLoader_js_node_modules_postcss_loader_src_index_js_ref_6_oneOf_1_2_node_modules_postcss_loader_src_index_js_ref_6_oneOf_1_3_node_modules_cache_loader_dist_cjs_js_ref_0_0_node_modules_vue_loader_lib_index_js_vue_loader_options_Kolotoc_vue_vue_type_style_index_0_lang_css_shadow__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(_node_modules_vue_style_loader_index_js_ref_6_oneOf_1_0_node_modules_css_loader_dist_cjs_js_ref_6_oneOf_1_1_node_modules_vue_loader_lib_loaders_stylePostLoader_js_node_modules_postcss_loader_src_index_js_ref_6_oneOf_1_2_node_modules_postcss_loader_src_index_js_ref_6_oneOf_1_3_node_modules_cache_loader_dist_cjs_js_ref_0_0_node_modules_vue_loader_lib_index_js_vue_loader_options_Kolotoc_vue_vue_type_style_index_0_lang_css_shadow__WEBPACK_IMPORTED_MODULE_0__); |
|||
/* harmony reexport (unknown) */ for(var __WEBPACK_IMPORT_KEY__ in _node_modules_vue_style_loader_index_js_ref_6_oneOf_1_0_node_modules_css_loader_dist_cjs_js_ref_6_oneOf_1_1_node_modules_vue_loader_lib_loaders_stylePostLoader_js_node_modules_postcss_loader_src_index_js_ref_6_oneOf_1_2_node_modules_postcss_loader_src_index_js_ref_6_oneOf_1_3_node_modules_cache_loader_dist_cjs_js_ref_0_0_node_modules_vue_loader_lib_index_js_vue_loader_options_Kolotoc_vue_vue_type_style_index_0_lang_css_shadow__WEBPACK_IMPORTED_MODULE_0__) if(["default"].indexOf(__WEBPACK_IMPORT_KEY__) < 0) (function(key) { __webpack_require__.d(__webpack_exports__, key, function() { return _node_modules_vue_style_loader_index_js_ref_6_oneOf_1_0_node_modules_css_loader_dist_cjs_js_ref_6_oneOf_1_1_node_modules_vue_loader_lib_loaders_stylePostLoader_js_node_modules_postcss_loader_src_index_js_ref_6_oneOf_1_2_node_modules_postcss_loader_src_index_js_ref_6_oneOf_1_3_node_modules_cache_loader_dist_cjs_js_ref_0_0_node_modules_vue_loader_lib_index_js_vue_loader_options_Kolotoc_vue_vue_type_style_index_0_lang_css_shadow__WEBPACK_IMPORTED_MODULE_0__[key]; }) }(__WEBPACK_IMPORT_KEY__)); |
|||
|
|||
|
|||
/***/ }), |
|||
|
|||
/***/ "4f39": |
|||
/***/ (function(module, exports, __webpack_require__) { |
|||
|
|||
// style-loader: Adds some css to the DOM by adding a <style> tag
|
|||
|
|||
// load the styles
|
|||
var content = __webpack_require__("baf5"); |
|||
if(typeof content === 'string') content = [[module.i, content, '']]; |
|||
if(content.locals) module.exports = content.locals; |
|||
// add CSS to Shadow Root
|
|||
var add = __webpack_require__("35d6").default |
|||
module.exports.__inject__ = function (shadowRoot) { |
|||
add("4e3af268", content, shadowRoot) |
|||
}; |
|||
|
|||
/***/ }), |
|||
|
|||
/***/ "5a74": |
|||
/***/ (function(module, __webpack_exports__, __webpack_require__) { |
|||
|
|||
"use strict"; |
|||
// ESM COMPAT FLAG
|
|||
__webpack_require__.r(__webpack_exports__); |
|||
|
|||
// CONCATENATED MODULE: ./node_modules/@vue/cli-service/lib/commands/build/setPublicPath.js
|
|||
// This file is imported into lib/wc client bundles.
|
|||
|
|||
if (typeof window !== 'undefined') { |
|||
var currentScript = window.document.currentScript |
|||
if (Object({"NODE_ENV":"production","BASE_URL":"/"}).NEED_CURRENTSCRIPT_POLYFILL) { |
|||
var getCurrentScript = __webpack_require__("8875") |
|||
currentScript = getCurrentScript() |
|||
|
|||
// for backward compatibility, because previously we directly included the polyfill
|
|||
if (!('currentScript' in document)) { |
|||
Object.defineProperty(document, 'currentScript', { get: getCurrentScript }) |
|||
} |
|||
} |
|||
|
|||
var src = currentScript && currentScript.src.match(/(.+\/)[^/]+\.js(\?.*)?$/) |
|||
if (src) { |
|||
__webpack_require__.p = src[1] // eslint-disable-line
|
|||
} |
|||
} |
|||
|
|||
// Indicate to webpack that this file can be concatenated
|
|||
/* harmony default export */ var setPublicPath = (null); |
|||
|
|||
// EXTERNAL MODULE: external "Vue"
|
|||
var external_Vue_ = __webpack_require__("8bbf"); |
|||
var external_Vue_default = /*#__PURE__*/__webpack_require__.n(external_Vue_); |
|||
|
|||
// CONCATENATED MODULE: ./node_modules/@vue/web-component-wrapper/dist/vue-wc-wrapper.js
|
|||
const camelizeRE = /-(\w)/g; |
|||
const camelize = str => { |
|||
return str.replace(camelizeRE, (_, c) => c ? c.toUpperCase() : '') |
|||
}; |
|||
|
|||
const hyphenateRE = /\B([A-Z])/g; |
|||
const hyphenate = str => { |
|||
return str.replace(hyphenateRE, '-$1').toLowerCase() |
|||
}; |
|||
|
|||
function getInitialProps (propsList) { |
|||
const res = {}; |
|||
propsList.forEach(key => { |
|||
res[key] = undefined; |
|||
}); |
|||
return res |
|||
} |
|||
|
|||
function injectHook (options, key, hook) { |
|||
options[key] = [].concat(options[key] || []); |
|||
options[key].unshift(hook); |
|||
} |
|||
|
|||
function callHooks (vm, hook) { |
|||
if (vm) { |
|||
const hooks = vm.$options[hook] || []; |
|||
hooks.forEach(hook => { |
|||
hook.call(vm); |
|||
}); |
|||
} |
|||
} |
|||
|
|||
function createCustomEvent (name, args) { |
|||
return new CustomEvent(name, { |
|||
bubbles: false, |
|||
cancelable: false, |
|||
detail: args |
|||
}) |
|||
} |
|||
|
|||
const isBoolean = val => /function Boolean/.test(String(val)); |
|||
const isNumber = val => /function Number/.test(String(val)); |
|||
|
|||
function convertAttributeValue (value, name, { type } = {}) { |
|||
if (isBoolean(type)) { |
|||
if (value === 'true' || value === 'false') { |
|||
return value === 'true' |
|||
} |
|||
if (value === '' || value === name || value != null) { |
|||
return true |
|||
} |
|||
return value |
|||
} else if (isNumber(type)) { |
|||
const parsed = parseFloat(value, 10); |
|||
return isNaN(parsed) ? value : parsed |
|||
} else { |
|||
return value |
|||
} |
|||
} |
|||
|
|||
function toVNodes (h, children) { |
|||
const res = []; |
|||
for (let i = 0, l = children.length; i < l; i++) { |
|||
res.push(toVNode(h, children[i])); |
|||
} |
|||
return res |
|||
} |
|||
|
|||
function toVNode (h, node) { |
|||
if (node.nodeType === 3) { |
|||
return node.data.trim() ? node.data : null |
|||
} else if (node.nodeType === 1) { |
|||
const data = { |
|||
attrs: getAttributes(node), |
|||
domProps: { |
|||
innerHTML: node.innerHTML |
|||
} |
|||
}; |
|||
if (data.attrs.slot) { |
|||
data.slot = data.attrs.slot; |
|||
delete data.attrs.slot; |
|||
} |
|||
return h(node.tagName, data) |
|||
} else { |
|||
return null |
|||
} |
|||
} |
|||
|
|||
function getAttributes (node) { |
|||
const res = {}; |
|||
for (let i = 0, l = node.attributes.length; i < l; i++) { |
|||
const attr = node.attributes[i]; |
|||
res[attr.nodeName] = attr.nodeValue; |
|||
} |
|||
return res |
|||
} |
|||
|
|||
function wrap (Vue, Component) { |
|||
const isAsync = typeof Component === 'function' && !Component.cid; |
|||
let isInitialized = false; |
|||
let hyphenatedPropsList; |
|||
let camelizedPropsList; |
|||
let camelizedPropsMap; |
|||
|
|||
function initialize (Component) { |
|||
if (isInitialized) return |
|||
|
|||
const options = typeof Component === 'function' |
|||
? Component.options |
|||
: Component; |
|||
|
|||
// extract props info
|
|||
const propsList = Array.isArray(options.props) |
|||
? options.props |
|||
: Object.keys(options.props || {}); |
|||
hyphenatedPropsList = propsList.map(hyphenate); |
|||
camelizedPropsList = propsList.map(camelize); |
|||
const originalPropsAsObject = Array.isArray(options.props) ? {} : options.props || {}; |
|||
camelizedPropsMap = camelizedPropsList.reduce((map, key, i) => { |
|||
map[key] = originalPropsAsObject[propsList[i]]; |
|||
return map |
|||
}, {}); |
|||
|
|||
// proxy $emit to native DOM events
|
|||
injectHook(options, 'beforeCreate', function () { |
|||
const emit = this.$emit; |
|||
this.$emit = (name, ...args) => { |
|||
this.$root.$options.customElement.dispatchEvent(createCustomEvent(name, args)); |
|||
return emit.call(this, name, ...args) |
|||
}; |
|||
}); |
|||
|
|||
injectHook(options, 'created', function () { |
|||
// sync default props values to wrapper on created
|
|||
camelizedPropsList.forEach(key => { |
|||
this.$root.props[key] = this[key]; |
|||
}); |
|||
}); |
|||
|
|||
// proxy props as Element properties
|
|||
camelizedPropsList.forEach(key => { |
|||
Object.defineProperty(CustomElement.prototype, key, { |
|||
get () { |
|||
return this._wrapper.props[key] |
|||
}, |
|||
set (newVal) { |
|||
this._wrapper.props[key] = newVal; |
|||
}, |
|||
enumerable: false, |
|||
configurable: true |
|||
}); |
|||
}); |
|||
|
|||
isInitialized = true; |
|||
} |
|||
|
|||
function syncAttribute (el, key) { |
|||
const camelized = camelize(key); |
|||
const value = el.hasAttribute(key) ? el.getAttribute(key) : undefined; |
|||
el._wrapper.props[camelized] = convertAttributeValue( |
|||
value, |
|||
key, |
|||
camelizedPropsMap[camelized] |
|||
); |
|||
} |
|||
|
|||
class CustomElement extends HTMLElement { |
|||
constructor () { |
|||
const self = super(); |
|||
self.attachShadow({ mode: 'open' }); |
|||
|
|||
const wrapper = self._wrapper = new Vue({ |
|||
name: 'shadow-root', |
|||
customElement: self, |
|||
shadowRoot: self.shadowRoot, |
|||
data () { |
|||
return { |
|||
props: {}, |
|||
slotChildren: [] |
|||
} |
|||
}, |
|||
render (h) { |
|||
return h(Component, { |
|||
ref: 'inner', |
|||
props: this.props |
|||
}, this.slotChildren) |
|||
} |
|||
}); |
|||
|
|||
// Use MutationObserver to react to future attribute & slot content change
|
|||
const observer = new MutationObserver(mutations => { |
|||
let hasChildrenChange = false; |
|||
for (let i = 0; i < mutations.length; i++) { |
|||
const m = mutations[i]; |
|||
if (isInitialized && m.type === 'attributes' && m.target === self) { |
|||
syncAttribute(self, m.attributeName); |
|||
} else { |
|||
hasChildrenChange = true; |
|||
} |
|||
} |
|||
if (hasChildrenChange) { |
|||
wrapper.slotChildren = Object.freeze(toVNodes( |
|||
wrapper.$createElement, |
|||
self.childNodes |
|||
)); |
|||
} |
|||
}); |
|||
observer.observe(self, { |
|||
childList: true, |
|||
subtree: true, |
|||
characterData: true, |
|||
attributes: true |
|||
}); |
|||
} |
|||
|
|||
get vueComponent () { |
|||
return this._wrapper.$refs.inner |
|||
} |
|||
|
|||
connectedCallback () { |
|||
const wrapper = this._wrapper; |
|||
if (!wrapper._isMounted) { |
|||
// initialize attributes
|
|||
const syncInitialAttributes = () => { |
|||
wrapper.props = getInitialProps(camelizedPropsList); |
|||
hyphenatedPropsList.forEach(key => { |
|||
syncAttribute(this, key); |
|||
}); |
|||
}; |
|||
|
|||
if (isInitialized) { |
|||
syncInitialAttributes(); |
|||
} else { |
|||
// async & unresolved
|
|||
Component().then(resolved => { |
|||
if (resolved.__esModule || resolved[Symbol.toStringTag] === 'Module') { |
|||
resolved = resolved.default; |
|||
} |
|||
initialize(resolved); |
|||
syncInitialAttributes(); |
|||
}); |
|||
} |
|||
// initialize children
|
|||
wrapper.slotChildren = Object.freeze(toVNodes( |
|||
wrapper.$createElement, |
|||
this.childNodes |
|||
)); |
|||
wrapper.$mount(); |
|||
this.shadowRoot.appendChild(wrapper.$el); |
|||
} else { |
|||
callHooks(this.vueComponent, 'activated'); |
|||
} |
|||
} |
|||
|
|||
disconnectedCallback () { |
|||
callHooks(this.vueComponent, 'deactivated'); |
|||
} |
|||
} |
|||
|
|||
if (!isAsync) { |
|||
initialize(Component); |
|||
} |
|||
|
|||
return CustomElement |
|||
} |
|||
|
|||
/* harmony default export */ var vue_wc_wrapper = (wrap); |
|||
|
|||
// EXTERNAL MODULE: ./node_modules/css-loader/dist/runtime/api.js
|
|||
var api = __webpack_require__("24fb"); |
|||
|
|||
// EXTERNAL MODULE: ./node_modules/vue-style-loader/lib/addStylesShadow.js + 1 modules
|
|||
var addStylesShadow = __webpack_require__("35d6"); |
|||
|
|||
// CONCATENATED MODULE: ./node_modules/vue-loader/lib/runtime/componentNormalizer.js
|
|||
/* globals __VUE_SSR_CONTEXT__ */ |
|||
|
|||
// IMPORTANT: Do NOT use ES2015 features in this file (except for modules).
|
|||
// This module is a runtime utility for cleaner component module output and will
|
|||
// be included in the final webpack user bundle.
|
|||
|
|||
function normalizeComponent ( |
|||
scriptExports, |
|||
render, |
|||
staticRenderFns, |
|||
functionalTemplate, |
|||
injectStyles, |
|||
scopeId, |
|||
moduleIdentifier, /* server only */ |
|||
shadowMode /* vue-cli only */ |
|||
) { |
|||
// Vue.extend constructor export interop
|
|||
var options = typeof scriptExports === 'function' |
|||
? scriptExports.options |
|||
: scriptExports |
|||
|
|||
// render functions
|
|||
if (render) { |
|||
options.render = render |
|||
options.staticRenderFns = staticRenderFns |
|||
options._compiled = true |
|||
} |
|||
|
|||
// functional template
|
|||
if (functionalTemplate) { |
|||
options.functional = true |
|||
} |
|||
|
|||
// scopedId
|
|||
if (scopeId) { |
|||
options._scopeId = 'data-v-' + scopeId |
|||
} |
|||
|
|||
var hook |
|||
if (moduleIdentifier) { // server build
|
|||
hook = function (context) { |
|||
// 2.3 injection
|
|||
context = |
|||
context || // cached call
|
|||
(this.$vnode && this.$vnode.ssrContext) || // stateful
|
|||
(this.parent && this.parent.$vnode && this.parent.$vnode.ssrContext) // functional
|
|||
// 2.2 with runInNewContext: true
|
|||
if (!context && typeof __VUE_SSR_CONTEXT__ !== 'undefined') { |
|||
context = __VUE_SSR_CONTEXT__ |
|||
} |
|||
// inject component styles
|
|||
if (injectStyles) { |
|||
injectStyles.call(this, context) |
|||
} |
|||
// register component module identifier for async chunk inferrence
|
|||
if (context && context._registeredComponents) { |
|||
context._registeredComponents.add(moduleIdentifier) |
|||
} |
|||
} |
|||
// used by ssr in case component is cached and beforeCreate
|
|||
// never gets called
|
|||
options._ssrRegister = hook |
|||
} else if (injectStyles) { |
|||
hook = shadowMode |
|||
? function () { |
|||
injectStyles.call( |
|||
this, |
|||
(options.functional ? this.parent : this).$root.$options.shadowRoot |
|||
) |
|||
} |
|||
: injectStyles |
|||
} |
|||
|
|||
if (hook) { |
|||
if (options.functional) { |
|||
// for template-only hot-reload because in that case the render fn doesn't
|
|||
// go through the normalizer
|
|||
options._injectStyles = hook |
|||
// register for functional component in vue file
|
|||
var originalRender = options.render |
|||
options.render = function renderWithStyleInjection (h, context) { |
|||
hook.call(context) |
|||
return originalRender(h, context) |
|||
} |
|||
} else { |
|||
// inject component registration as beforeCreate hook
|
|||
var existing = options.beforeCreate |
|||
options.beforeCreate = existing |
|||
? [].concat(existing, hook) |
|||
: [hook] |
|||
} |
|||
} |
|||
|
|||
return { |
|||
exports: scriptExports, |
|||
options: options |
|||
} |
|||
} |
|||
|
|||
// CONCATENATED MODULE: ./node_modules/cache-loader/dist/cjs.js?{"cacheDirectory":"node_modules/.cache/vue-loader","cacheIdentifier":"f51886d8-vue-loader-template"}!./node_modules/vue-loader/lib/loaders/templateLoader.js??vue-loader-options!./node_modules/cache-loader/dist/cjs.js??ref--0-0!./node_modules/vue-loader/lib??vue-loader-options!./src/components/Kolotoc.vue?vue&type=template&id=7f6b8457&shadow
|
|||
var render = function () {var _vm=this;var _h=_vm.$createElement;var _c=_vm._self._c||_h;return _c('div',[_c('div',[_c('button',{on:{"click":function($event){_vm.index -= 1}}},[_vm._v("<")]),_c('button',{on:{"click":function($event){_vm.index += 1}}},[_vm._v(">")]),_c('div',[_vm._v(" "+_vm._s(_vm.images[_vm.index].src)),_c('br'),_vm._v(" "+_vm._s(_vm.images[_vm.index].title)+" ")]),_vm._l((_vm.images),function(img,i){return _c('button',{key:i,class:{active: i == _vm.index},attrs:{"title":img.title},on:{"click":function($event){_vm.index = i}}})})],2)])} |
|||
var staticRenderFns = [] |
|||
|
|||
|
|||
// CONCATENATED MODULE: ./src/components/Kolotoc.vue?vue&type=template&id=7f6b8457&shadow
|
|||
|
|||
// CONCATENATED MODULE: ./node_modules/cache-loader/dist/cjs.js??ref--12-0!./node_modules/thread-loader/dist/cjs.js!./node_modules/babel-loader/lib!./node_modules/cache-loader/dist/cjs.js??ref--0-0!./node_modules/vue-loader/lib??vue-loader-options!./src/components/Kolotoc.vue?vue&type=script&lang=js&shadow
|
|||
//
|
|||
//
|
|||
//
|
|||
//
|
|||
//
|
|||
//
|
|||
//
|
|||
//
|
|||
//
|
|||
//
|
|||
//
|
|||
//
|
|||
//
|
|||
//
|
|||
/* harmony default export */ var Kolotocvue_type_script_lang_js_shadow = ({ |
|||
props: { |
|||
images: { |
|||
default: function _default() { |
|||
return []; |
|||
} |
|||
} |
|||
}, |
|||
data: function data() { |
|||
return { |
|||
index: 0 |
|||
}; |
|||
}, |
|||
watch: { |
|||
index: function index(value) { |
|||
var total = this.images.length - 1; |
|||
|
|||
if (value < 0) { |
|||
this.index = total; |
|||
} else if (value > total) { |
|||
this.index = 0; |
|||
} |
|||
} |
|||
} |
|||
}); |
|||
// CONCATENATED MODULE: ./src/components/Kolotoc.vue?vue&type=script&lang=js&shadow
|
|||
/* harmony default export */ var components_Kolotocvue_type_script_lang_js_shadow = (Kolotocvue_type_script_lang_js_shadow); |
|||
// CONCATENATED MODULE: ./src/components/Kolotoc.vue?shadow
|
|||
|
|||
|
|||
|
|||
function injectStyles (context) { |
|||
|
|||
var style0 = __webpack_require__("4933") |
|||
if (style0.__inject__) style0.__inject__(context) |
|||
|
|||
} |
|||
|
|||
/* normalize component */ |
|||
|
|||
var component = normalizeComponent( |
|||
components_Kolotocvue_type_script_lang_js_shadow, |
|||
render, |
|||
staticRenderFns, |
|||
false, |
|||
injectStyles, |
|||
null, |
|||
null |
|||
,true |
|||
) |
|||
|
|||
/* harmony default export */ var Kolotocshadow = (component.exports); |
|||
// CONCATENATED MODULE: ./node_modules/@vue/cli-service/lib/commands/build/entry-wc.js
|
|||
|
|||
|
|||
|
|||
|
|||
// runtime shared by every component chunk
|
|||
|
|||
|
|||
|
|||
|
|||
|
|||
window.customElements.define('muj-kolotoc', vue_wc_wrapper(external_Vue_default.a, Kolotocshadow)) |
|||
|
|||
/***/ }), |
|||
|
|||
/***/ "8875": |
|||
/***/ (function(module, exports, __webpack_require__) { |
|||
|
|||
var __WEBPACK_AMD_DEFINE_FACTORY__, __WEBPACK_AMD_DEFINE_ARRAY__, __WEBPACK_AMD_DEFINE_RESULT__;// addapted from the document.currentScript polyfill by Adam Miller
|
|||
// MIT license
|
|||
// source: https://github.com/amiller-gh/currentScript-polyfill
|
|||
|
|||
// added support for Firefox https://bugzilla.mozilla.org/show_bug.cgi?id=1620505
|
|||
|
|||
(function (root, factory) { |
|||
if (true) { |
|||
!(__WEBPACK_AMD_DEFINE_ARRAY__ = [], __WEBPACK_AMD_DEFINE_FACTORY__ = (factory), |
|||
__WEBPACK_AMD_DEFINE_RESULT__ = (typeof __WEBPACK_AMD_DEFINE_FACTORY__ === 'function' ? |
|||
(__WEBPACK_AMD_DEFINE_FACTORY__.apply(exports, __WEBPACK_AMD_DEFINE_ARRAY__)) : __WEBPACK_AMD_DEFINE_FACTORY__), |
|||
__WEBPACK_AMD_DEFINE_RESULT__ !== undefined && (module.exports = __WEBPACK_AMD_DEFINE_RESULT__)); |
|||
} else {} |
|||
}(typeof self !== 'undefined' ? self : this, function () { |
|||
function getCurrentScript () { |
|||
var descriptor = Object.getOwnPropertyDescriptor(document, 'currentScript') |
|||
// for chrome
|
|||
if (!descriptor && 'currentScript' in document && document.currentScript) { |
|||
return document.currentScript |
|||
} |
|||
|
|||
// for other browsers with native support for currentScript
|
|||
if (descriptor && descriptor.get !== getCurrentScript && document.currentScript) { |
|||
return document.currentScript |
|||
} |
|||
|
|||
// IE 8-10 support script readyState
|
|||
// IE 11+ & Firefox support stack trace
|
|||
try { |
|||
throw new Error(); |
|||
} |
|||
catch (err) { |
|||
// Find the second match for the "at" string to get file src url from stack.
|
|||
var ieStackRegExp = /.*at [^(]*\((.*):(.+):(.+)\)$/ig, |
|||
ffStackRegExp = /@([^@]*):(\d+):(\d+)\s*$/ig, |
|||
stackDetails = ieStackRegExp.exec(err.stack) || ffStackRegExp.exec(err.stack), |
|||
scriptLocation = (stackDetails && stackDetails[1]) || false, |
|||
line = (stackDetails && stackDetails[2]) || false, |
|||
currentLocation = document.location.href.replace(document.location.hash, ''), |
|||
pageSource, |
|||
inlineScriptSourceRegExp, |
|||
inlineScriptSource, |
|||
scripts = document.getElementsByTagName('script'); // Live NodeList collection
|
|||
|
|||
if (scriptLocation === currentLocation) { |
|||
pageSource = document.documentElement.outerHTML; |
|||
inlineScriptSourceRegExp = new RegExp('(?:[^\\n]+?\\n){0,' + (line - 2) + '}[^<]*<script>([\\d\\D]*?)<\\/script>[\\d\\D]*', 'i'); |
|||
inlineScriptSource = pageSource.replace(inlineScriptSourceRegExp, '$1').trim(); |
|||
} |
|||
|
|||
for (var i = 0; i < scripts.length; i++) { |
|||
// If ready state is interactive, return the script tag
|
|||
if (scripts[i].readyState === 'interactive') { |
|||
return scripts[i]; |
|||
} |
|||
|
|||
// If src matches, return the script tag
|
|||
if (scripts[i].src === scriptLocation) { |
|||
return scripts[i]; |
|||
} |
|||
|
|||
// If inline source matches, return the script tag
|
|||
if ( |
|||
scriptLocation === currentLocation && |
|||
scripts[i].innerHTML && |
|||
scripts[i].innerHTML.trim() === inlineScriptSource |
|||
) { |
|||
return scripts[i]; |
|||
} |
|||
} |
|||
|
|||
// If no match, return null
|
|||
return null; |
|||
} |
|||
}; |
|||
|
|||
return getCurrentScript |
|||
})); |
|||
|
|||
|
|||
/***/ }), |
|||
|
|||
/***/ "8bbf": |
|||
/***/ (function(module, exports) { |
|||
|
|||
module.exports = Vue; |
|||
|
|||
/***/ }), |
|||
|
|||
/***/ "baf5": |
|||
/***/ (function(module, exports, __webpack_require__) { |
|||
|
|||
// Imports
|
|||
var ___CSS_LOADER_API_IMPORT___ = __webpack_require__("24fb"); |
|||
exports = ___CSS_LOADER_API_IMPORT___(false); |
|||
// Module
|
|||
exports.push([module.i, ".active{background-color:green}", ""]); |
|||
// Exports
|
|||
module.exports = exports; |
|||
|
|||
|
|||
/***/ }) |
|||
|
|||
/******/ }); |
|||
//# sourceMappingURL=muj-kolotoc.js.map
|
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@ -0,0 +1,9 @@ |
|||
{% extends "base.html" %} |
|||
|
|||
{% block body_class %}template-404{% endblock %} |
|||
|
|||
{% block content %} |
|||
<h1>Page not found</h1> |
|||
|
|||
<h2>Sorry, this page could not be found.</h2> |
|||
{% endblock %} |
@ -0,0 +1,13 @@ |
|||
<!DOCTYPE html> |
|||
<html class="no-js"> |
|||
<head> |
|||
<meta charset="utf-8" /> |
|||
<title>Internal server error</title> |
|||
<meta name="viewport" content="width=device-width, initial-scale=1" /> |
|||
</head> |
|||
<body> |
|||
<h1>Internal server error</h1> |
|||
|
|||
<h2>Sorry, there seems to be an error. Please try again soon.</h2> |
|||
</body> |
|||
</html> |
@ -0,0 +1,43 @@ |
|||
{% load static wagtailuserbar %} |
|||
|
|||
<!DOCTYPE html> |
|||
<html class="no-js" lang="en"> |
|||
<head> |
|||
<meta charset="utf-8" /> |
|||
<title> |
|||
{% block title %} |
|||
{% if self.seo_title %}{{ self.seo_title }}{% else %}{{ self.title }}{% endif %} |
|||
{% endblock %} |
|||
{% block title_suffix %} |
|||
{% with self.get_site.site_name as site_name %} |
|||
{% if site_name %}- {{ site_name }}{% endif %} |
|||
{% endwith %} |
|||
{% endblock %} |
|||
</title> |
|||
<meta name="description" content="" /> |
|||
<meta name="viewport" content="width=device-width, initial-scale=1" /> |
|||
|
|||
{# Global stylesheets #} |
|||
<link rel="stylesheet" type="text/css" href="{% static 'css/hvezdarna.css' %}"> |
|||
|
|||
{% block extra_css %} |
|||
halooo |
|||
{% endblock %} |
|||
</head> |
|||
|
|||
<body class="{% block body_class %}{% endblock %}"> |
|||
{% wagtailuserbar %}W |
|||
|
|||
{% block content %}{% endblock %} |
|||
|
|||
{# Global javascript #} |
|||
<script src="https://www.jsdelivr.com/package/npm/jquery"></script> |
|||
<script src="https://cdn.jsdelivr.net/npm/vue@2.6.12"></script> |
|||
<script type="text/javascript" src="{% static 'js/muj-kolotoc.min.js' %}"></script> |
|||
<script type="text/javascript" src="{% static 'js/hvezdarna.js' %}"></script> |
|||
|
|||
{% block extra_js %} |
|||
{# Override this in templates to add extra javascript #} |
|||
{% endblock %} |
|||
</body> |
|||
</html> |
@ -0,0 +1,43 @@ |
|||
from django.conf import settings |
|||
from django.urls import include, path |
|||
from django.contrib import admin |
|||
|
|||
from wagtail.admin import urls as wagtailadmin_urls |
|||
from wagtail.core import urls as wagtail_urls |
|||
from wagtail.documents import urls as wagtaildocs_urls |
|||
|
|||
from search import views as search_views |
|||
|
|||
|
|||
from .api import api_router |
|||
|
|||
urlpatterns = [ |
|||
path('api/v2/', api_router.urls), |
|||
path('django-admin/', admin.site.urls), |
|||
|
|||
path('admin/', include(wagtailadmin_urls)), |
|||
path('documents/', include(wagtaildocs_urls)), |
|||
|
|||
path('search/', search_views.search, name='search'), |
|||
|
|||
] |
|||
|
|||
|
|||
if settings.DEBUG: |
|||
from django.conf.urls.static import static |
|||
from django.contrib.staticfiles.urls import staticfiles_urlpatterns |
|||
|
|||
# Serve static and media files from development server |
|||
urlpatterns += staticfiles_urlpatterns() |
|||
urlpatterns += static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT) |
|||
|
|||
urlpatterns = urlpatterns + [ |
|||
# For anything not caught by a more specific rule above, hand over to |
|||
# Wagtail's page serving mechanism. This should be the last pattern in |
|||
# the list: |
|||
path("", include(wagtail_urls)), |
|||
|
|||
# Alternatively, if you want Wagtail pages to be served from a subpath |
|||
# of your site, rather than the site root: |
|||
# path("pages/", include(wagtail_urls)), |
|||
] |
@ -0,0 +1,16 @@ |
|||
""" |
|||
WSGI config for hvezdarna project. |
|||
|
|||
It exposes the WSGI callable as a module-level variable named ``application``. |
|||
|
|||
For more information on this file, see |
|||
https://docs.djangoproject.com/en/3.1/howto/deployment/wsgi/ |
|||
""" |
|||
|
|||
import os |
|||
|
|||
from django.core.wsgi import get_wsgi_application |
|||
|
|||
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "hvezdarna.settings.dev") |
|||
|
|||
application = get_wsgi_application() |
@ -0,0 +1,10 @@ |
|||
#!/usr/bin/env python |
|||
import os |
|||
import sys |
|||
|
|||
if __name__ == "__main__": |
|||
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "hvezdarna.settings.dev") |
|||
|
|||
from django.core.management import execute_from_command_line |
|||
|
|||
execute_from_command_line(sys.argv) |
@ -0,0 +1,2 @@ |
|||
Django>=3.1,<3.2 |
|||
wagtail>=2.11,<2.12 |
Binary file not shown.
Binary file not shown.
@ -0,0 +1,38 @@ |
|||
{% extends "base.html" %} |
|||
{% load static wagtailcore_tags %} |
|||
|
|||
{% block body_class %}template-searchresults{% endblock %} |
|||
|
|||
{% block title %}Search{% endblock %} |
|||
|
|||
{% block content %} |
|||
<h1>Search</h1> |
|||
|
|||
<form action="{% url 'search' %}" method="get"> |
|||
<input type="text" name="query"{% if search_query %} value="{{ search_query }}"{% endif %}> |
|||
<input type="submit" value="Search" class="button"> |
|||
</form> |
|||
|
|||
{% if search_results %} |
|||
<ul> |
|||
{% for result in search_results %} |
|||
<li> |
|||
<h4><a href="{% pageurl result %}">{{ result }}</a></h4> |
|||
{% if result.search_description %} |
|||
{{ result.search_description }} |
|||
{% endif %} |
|||
</li> |
|||
{% endfor %} |
|||
</ul> |
|||
|
|||
{% if search_results.has_previous %} |
|||
<a href="{% url 'search' %}?query={{ search_query|urlencode }}&page={{ search_results.previous_page_number }}">Previous</a> |
|||
{% endif %} |
|||
|
|||
{% if search_results.has_next %} |
|||
<a href="{% url 'search' %}?query={{ search_query|urlencode }}&page={{ search_results.next_page_number }}">Next</a> |
|||
{% endif %} |
|||
{% elif search_query %} |
|||
No results found |
|||
{% endif %} |
|||
{% endblock %} |
@ -0,0 +1,34 @@ |
|||
from django.core.paginator import EmptyPage, PageNotAnInteger, Paginator |
|||
from django.template.response import TemplateResponse |
|||
|
|||
from wagtail.core.models import Page |
|||
from wagtail.search.models import Query |
|||
|
|||
|
|||
def search(request): |
|||
search_query = request.GET.get('query', None) |
|||
page = request.GET.get('page', 1) |
|||
|
|||
# Search |
|||
if search_query: |
|||
search_results = Page.objects.live().search(search_query) |
|||
query = Query.get(search_query) |
|||
|
|||
# Record hit |
|||
query.add_hit() |
|||
else: |
|||
search_results = Page.objects.none() |
|||
|
|||
# Pagination |
|||
paginator = Paginator(search_results, 10) |
|||
try: |
|||
search_results = paginator.page(page) |
|||
except PageNotAnInteger: |
|||
search_results = paginator.page(1) |
|||
except EmptyPage: |
|||
search_results = paginator.page(paginator.num_pages) |
|||
|
|||
return TemplateResponse(request, 'search/search.html', { |
|||
'search_query': search_query, |
|||
'search_results': search_results, |
|||
}) |
Loading…
Reference in new issue